summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--CREDITS17
-rw-r--r--Documentation/ABI/testing/debugfs-pktcdvd20
-rw-r--r--Documentation/ABI/testing/sysfs-class-pktcdvd72
-rw-r--r--Documentation/CodingStyle144
-rw-r--r--Documentation/DocBook/Makefile4
-rw-r--r--Documentation/DocBook/genericirq.tmpl4
-rw-r--r--Documentation/DocBook/libata.tmpl2
-rw-r--r--Documentation/HOWTO1
-rw-r--r--Documentation/SubmitChecklist10
-rw-r--r--Documentation/SubmittingPatches6
-rw-r--r--Documentation/accounting/getdelays.c64
-rw-r--r--Documentation/arm/Samsung-S3C24XX/Overview.txt30
-rw-r--r--Documentation/block/biodoc.txt7
-rw-r--r--Documentation/cachetlb.txt28
-rw-r--r--Documentation/cdrom/packet-writing.txt35
-rw-r--r--Documentation/cpu-freq/core.txt2
-rw-r--r--Documentation/crypto/api-intro.txt4
-rw-r--r--Documentation/driver-model/devres.txt268
-rw-r--r--Documentation/dvb/cards.txt4
-rw-r--r--Documentation/fault-injection/failcmd.sh4
-rw-r--r--Documentation/fault-injection/failmodule.sh31
-rw-r--r--Documentation/fault-injection/fault-injection.txt225
-rw-r--r--Documentation/feature-removal-schedule.txt170
-rw-r--r--Documentation/filesystems/9p.txt20
-rw-r--r--Documentation/filesystems/Locking8
-rw-r--r--Documentation/filesystems/bfs.txt2
-rw-r--r--Documentation/filesystems/fuse.txt4
-rw-r--r--Documentation/filesystems/ntfs.txt2
-rw-r--r--Documentation/filesystems/ocfs2.txt3
-rw-r--r--Documentation/hwmon/f71805f56
-rw-r--r--Documentation/hwmon/it8715
-rw-r--r--Documentation/hwmon/k8temp2
-rw-r--r--Documentation/hwmon/pc8742738
-rw-r--r--Documentation/hwmon/sysfs-interface4
-rw-r--r--Documentation/hwmon/w83627ehf2
-rw-r--r--Documentation/hwmon/w83791d2
-rw-r--r--Documentation/hwmon/w83793106
-rw-r--r--Documentation/i2c/busses/i2c-amd81112
-rw-r--r--Documentation/i2c/busses/i2c-i8015
-rw-r--r--Documentation/i2c/busses/i2c-nforce26
-rw-r--r--Documentation/i386/boot.txt3
-rw-r--r--Documentation/ibm-acpi.txt151
-rw-r--r--Documentation/ioctl-number.txt2
-rw-r--r--Documentation/ioctl/ioctl-decoding.txt24
-rw-r--r--Documentation/kbuild/kconfig-language.txt8
-rw-r--r--Documentation/kdump/kdump.txt249
-rw-r--r--Documentation/kernel-parameters.txt21
-rw-r--r--Documentation/networking/dccp.txt6
-rw-r--r--Documentation/pci.txt702
-rw-r--r--Documentation/powerpc/booting-without-of.txt19
-rw-r--r--Documentation/powerpc/mpc52xx-device-tree-bindings.txt10
-rw-r--r--Documentation/s390/Debugging390.txt2
-rw-r--r--Documentation/s390/driver-model.txt7
-rw-r--r--Documentation/scsi/aacraid.txt66
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt60
-rw-r--r--Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl4
-rw-r--r--Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl41
-rw-r--r--Documentation/sound/alsa/hda_codec.txt10
-rw-r--r--Documentation/sound/alsa/soc/DAI.txt56
-rw-r--r--Documentation/sound/alsa/soc/clocking.txt51
-rw-r--r--Documentation/sound/alsa/soc/codec.txt197
-rw-r--r--Documentation/sound/alsa/soc/dapm.txt297
-rw-r--r--Documentation/sound/alsa/soc/machine.txt113
-rw-r--r--Documentation/sound/alsa/soc/overview.txt83
-rw-r--r--Documentation/sound/alsa/soc/platform.txt58
-rw-r--r--Documentation/sound/alsa/soc/pops_clicks.txt52
-rw-r--r--Documentation/spi/pxa2xx16
-rw-r--r--Documentation/sysrq.txt66
-rw-r--r--Documentation/tty.txt111
-rw-r--r--Documentation/usb/CREDITS2
-rw-r--r--Documentation/usb/acm.txt4
-rw-r--r--Documentation/usb/proc_usb_info.txt21
-rw-r--r--Documentation/usb/usbmon.txt152
-rw-r--r--Documentation/video-output.txt34
-rw-r--r--Documentation/video4linux/CARDLIST.cx882
-rw-r--r--Documentation/video4linux/CARDLIST.saa71347
-rw-r--r--Documentation/video4linux/cafe_ccic54
-rw-r--r--Documentation/video4linux/zr36120.txt162
-rw-r--r--Documentation/x86_64/boot-options.txt4
-rw-r--r--MAINTAINERS408
-rw-r--r--Makefile67
-rw-r--r--README4
-rw-r--r--arch/alpha/Kconfig8
-rw-r--r--arch/alpha/kernel/osf_sys.c8
-rw-r--r--arch/alpha/kernel/pci.c4
-rw-r--r--arch/alpha/kernel/process.c1
-rw-r--r--arch/arm/Kconfig50
-rw-r--r--arch/arm/common/sharpsl_pm.c2
-rw-r--r--arch/arm/configs/at91sam9260ek_defconfig1
-rw-r--r--arch/arm/configs/at91sam9261ek_defconfig1
-rw-r--r--arch/arm/configs/ep93xx_defconfig123
-rw-r--r--arch/arm/configs/iop13xx_defconfig99
-rw-r--r--arch/arm/configs/iop32x_defconfig213
-rw-r--r--arch/arm/configs/iop33x_defconfig110
-rw-r--r--arch/arm/configs/ixp2000_defconfig114
-rw-r--r--arch/arm/configs/ixp23xx_defconfig136
-rw-r--r--arch/arm/configs/lpd270_defconfig103
-rw-r--r--arch/arm/configs/onearm_defconfig126
-rw-r--r--arch/arm/kernel/Makefile1
-rw-r--r--arch/arm/kernel/calls.S37
-rw-r--r--arch/arm/kernel/ecard.c2
-rw-r--r--arch/arm/kernel/entry-armv.S12
-rw-r--r--arch/arm/kernel/head.S26
-rw-r--r--arch/arm/kernel/setup.c4
-rw-r--r--arch/arm/kernel/sys_arm.c13
-rw-r--r--arch/arm/kernel/time.c13
-rw-r--r--arch/arm/kernel/traps.c1
-rw-r--r--arch/arm/mach-at91rm9200/at91rm9200_devices.c2
-rw-r--r--arch/arm/mach-at91rm9200/at91sam9260.c3
-rw-r--r--arch/arm/mach-at91rm9200/at91sam9260_devices.c1
-rw-r--r--arch/arm/mach-at91rm9200/at91sam9261.c3
-rw-r--r--arch/arm/mach-at91rm9200/board-sam9260ek.c1
-rw-r--r--arch/arm/mach-at91rm9200/gpio.c39
-rw-r--r--arch/arm/mach-ep93xx/core.c4
-rw-r--r--arch/arm/mach-imx/Makefile2
-rw-r--r--arch/arm/mach-imx/cpufreq.c299
-rw-r--r--arch/arm/mach-iop13xx/io.c19
-rw-r--r--arch/arm/mach-iop13xx/iq81340mc.c6
-rw-r--r--arch/arm/mach-iop13xx/iq81340sc.c6
-rw-r--r--arch/arm/mach-iop13xx/irq.c22
-rw-r--r--arch/arm/mach-iop13xx/setup.c2
-rw-r--r--arch/arm/mach-netx/time.c42
-rw-r--r--arch/arm/mach-omap1/Kconfig1
-rw-r--r--arch/arm/mach-omap1/board-osk.c1
-rw-r--r--arch/arm/mach-omap2/board-apollon.c1
-rw-r--r--arch/arm/mach-omap2/gpmc.c21
-rw-r--r--arch/arm/mach-pnx4008/Makefile2
-rw-r--r--arch/arm/mach-pnx4008/i2c.c167
-rw-r--r--arch/arm/mach-pxa/Kconfig16
-rw-r--r--arch/arm/mach-pxa/corgi_pm.c2
-rw-r--r--arch/arm/mach-pxa/generic.c4
-rw-r--r--arch/arm/mach-pxa/sharpsl_pm.c2
-rw-r--r--arch/arm/mach-pxa/spitz_pm.c2
-rw-r--r--arch/arm/mach-pxa/time.c45
-rw-r--r--arch/arm/mach-pxa/trizeps4.c5
-rw-r--r--arch/arm/mach-realview/core.c13
-rw-r--r--arch/arm/mach-realview/core.h1
-rw-r--r--arch/arm/mach-realview/realview_eb.c1
-rw-r--r--arch/arm/mach-s3c2410/Kconfig25
-rw-r--r--arch/arm/mach-s3c2410/cpu.c1
-rw-r--r--arch/arm/mach-s3c2410/devs.c1
-rw-r--r--arch/arm/mach-s3c2410/dma.c6
-rw-r--r--arch/arm/mach-s3c2410/gpio.c12
-rw-r--r--arch/arm/mach-s3c2410/irq.h2
-rw-r--r--arch/arm/mach-s3c2410/mach-anubis.c1
-rw-r--r--arch/arm/mach-s3c2410/mach-bast.c1
-rw-r--r--arch/arm/mach-s3c2410/mach-h1940.c3
-rw-r--r--arch/arm/mach-s3c2410/mach-n30.c3
-rw-r--r--arch/arm/mach-s3c2410/mach-nexcoder.c1
-rw-r--r--arch/arm/mach-s3c2410/mach-osiris.c1
-rw-r--r--arch/arm/mach-s3c2410/mach-otom.c1
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2410.c1
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2413.c1
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2440.c1
-rw-r--r--arch/arm/mach-s3c2410/mach-vr1000.c2
-rw-r--r--arch/arm/mach-s3c2410/mach-vstms.c1
-rw-r--r--arch/arm/mach-s3c2410/pm-simtec.c1
-rw-r--r--arch/arm/mach-s3c2410/pm.c8
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-clock.c5
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-dma.c9
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-pm.c8
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.c3
-rw-r--r--arch/arm/mach-s3c2410/s3c2412-clock.c11
-rw-r--r--arch/arm/mach-s3c2410/s3c2412-dma.c7
-rw-r--r--arch/arm/mach-s3c2410/s3c2412.c2
-rw-r--r--arch/arm/mach-s3c2410/s3c2440-clock.c24
-rw-r--r--arch/arm/mach-s3c2410/s3c2440-dma.c3
-rw-r--r--arch/arm/mach-s3c2410/s3c2440.c9
-rw-r--r--arch/arm/mach-s3c2410/s3c2440.h18
-rw-r--r--arch/arm/mach-s3c2410/s3c2442-clock.c22
-rw-r--r--arch/arm/mach-s3c2410/s3c2442.c20
-rw-r--r--arch/arm/mach-s3c2410/s3c244x.c3
-rw-r--r--arch/arm/mach-s3c2410/usb-simtec.h3
-rw-r--r--arch/arm/mach-sa1100/jornada720.c229
-rw-r--r--arch/arm/mach-versatile/core.c14
-rw-r--r--arch/arm/mm/consistent.c2
-rw-r--r--arch/arm/mm/copypage-v4mc.c8
-rw-r--r--arch/arm/mm/copypage-v6.c10
-rw-r--r--arch/arm/mm/copypage-xscale.c8
-rw-r--r--arch/arm/mm/fault-armv.c2
-rw-r--r--arch/arm/mm/flush.c41
-rw-r--r--arch/arm/mm/init.c11
-rw-r--r--arch/arm/mm/ioremap.c105
-rw-r--r--arch/arm/mm/mmu.c28
-rw-r--r--arch/arm/mm/pgd.c2
-rw-r--r--arch/arm/mm/proc-arm1020.S4
-rw-r--r--arch/arm/mm/proc-arm1020e.S4
-rw-r--r--arch/arm/mm/proc-arm1022.S6
-rw-r--r--arch/arm/mm/proc-arm1026.S6
-rw-r--r--arch/arm/mm/proc-arm6_7.S10
-rw-r--r--arch/arm/mm/proc-arm720.S6
-rw-r--r--arch/arm/mm/proc-arm920.S6
-rw-r--r--arch/arm/mm/proc-arm922.S6
-rw-r--r--arch/arm/mm/proc-arm925.S6
-rw-r--r--arch/arm/mm/proc-arm926.S8
-rw-r--r--arch/arm/mm/proc-sa110.S6
-rw-r--r--arch/arm/mm/proc-sa1100.S6
-rw-r--r--arch/arm/mm/proc-syms.c2
-rw-r--r--arch/arm/mm/proc-v6.S39
-rw-r--r--arch/arm/mm/proc-xsc3.S8
-rw-r--r--arch/arm/mm/proc-xscale.S8
-rw-r--r--arch/arm/plat-omap/Kconfig2
-rw-r--r--arch/arm/tools/mach-types25
-rw-r--r--arch/arm/vfp/entry.S1
-rw-r--r--arch/arm/vfp/vfp.h4
-rw-r--r--arch/arm/vfp/vfphw.S26
-rw-r--r--arch/arm/vfp/vfpmodule.c71
-rw-r--r--arch/arm26/Kconfig8
-rw-r--r--arch/arm26/kernel/ecard.c2
-rw-r--r--arch/arm26/kernel/irq.c2
-rw-r--r--arch/avr32/Kconfig8
-rw-r--r--arch/avr32/boards/atstk1000/Makefile2
-rw-r--r--arch/avr32/boards/atstk1000/atstk1002.c129
-rw-r--r--arch/avr32/boards/atstk1000/spi.c27
-rw-r--r--arch/avr32/configs/atstk1002_defconfig39
-rw-r--r--arch/avr32/kernel/avr32_ksyms.c3
-rw-r--r--arch/avr32/kernel/cpu.c1
-rw-r--r--arch/avr32/kernel/irq.c1
-rw-r--r--arch/avr32/kernel/process.c7
-rw-r--r--arch/avr32/kernel/setup.c28
-rw-r--r--arch/avr32/lib/delay.c2
-rw-r--r--arch/avr32/lib/libgcc.h33
-rw-r--r--arch/avr32/lib/longlong.h98
-rw-r--r--arch/avr32/mach-at32ap/Makefile2
-rw-r--r--arch/avr32/mach-at32ap/at32ap7000.c236
-rw-r--r--arch/avr32/mach-at32ap/extint.c34
-rw-r--r--arch/avr32/mach-at32ap/intc.c4
-rw-r--r--arch/avr32/mach-at32ap/pio.c322
-rw-r--r--arch/avr32/mach-at32ap/sm.c289
-rw-r--r--arch/avr32/mm/cache.c32
-rw-r--r--arch/cris/Kconfig8
-rw-r--r--arch/cris/arch-v10/drivers/axisflashmap.c2
-rw-r--r--arch/cris/arch-v10/drivers/gpio.c2
-rw-r--r--arch/cris/arch-v32/drivers/axisflashmap.c2
-rw-r--r--arch/cris/arch-v32/drivers/gpio.c2
-rw-r--r--arch/cris/arch-v32/drivers/sync_serial.c8
-rw-r--r--arch/cris/arch-v32/kernel/signal.c2
-rw-r--r--arch/cris/arch-v32/kernel/smp.c2
-rw-r--r--arch/cris/kernel/profile.c2
-rw-r--r--arch/frv/Kconfig8
-rw-r--r--arch/frv/kernel/pm.c6
-rw-r--r--arch/frv/mm/elf-fdpic.c4
-rw-r--r--arch/h8300/Kconfig8
-rw-r--r--arch/h8300/kernel/ints.c2
-rw-r--r--arch/h8300/platform/h8s/ints.c2
-rw-r--r--arch/i386/Kconfig47
-rw-r--r--arch/i386/Kconfig.cpu8
-rw-r--r--arch/i386/boot/compressed/.gitignore1
-rw-r--r--arch/i386/boot/compressed/head.S2
-rw-r--r--arch/i386/boot/compressed/relocs.c2
-rw-r--r--arch/i386/defconfig41
-rw-r--r--arch/i386/kernel/acpi/boot.c259
-rw-r--r--arch/i386/kernel/acpi/cstate.c10
-rw-r--r--arch/i386/kernel/acpi/earlyquirk.c4
-rw-r--r--arch/i386/kernel/apm.c8
-rw-r--r--arch/i386/kernel/cpu/common.c15
-rw-r--r--arch/i386/kernel/cpu/cpufreq/Kconfig6
-rw-r--r--arch/i386/kernel/cpu/cpufreq/Makefile2
-rw-r--r--arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c810
-rw-r--r--arch/i386/kernel/cpu/cpufreq/gx-suspmod.c4
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c135
-rw-r--r--arch/i386/kernel/cpu/cpufreq/p4-clockmod.c47
-rw-r--r--arch/i386/kernel/cpu/cpufreq/sc520_freq.c7
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c15
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-lib.c32
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-lib.h1
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-smi.c3
-rw-r--r--arch/i386/kernel/cpuid.c4
-rw-r--r--arch/i386/kernel/e820.c2
-rw-r--r--arch/i386/kernel/efi.c89
-rw-r--r--arch/i386/kernel/entry.S36
-rw-r--r--arch/i386/kernel/hpet.c5
-rw-r--r--arch/i386/kernel/io_apic.c53
-rw-r--r--arch/i386/kernel/microcode.c8
-rw-r--r--arch/i386/kernel/module.c4
-rw-r--r--arch/i386/kernel/mpparse.c12
-rw-r--r--arch/i386/kernel/msr.c6
-rw-r--r--arch/i386/kernel/nmi.c16
-rw-r--r--arch/i386/kernel/paravirt.c9
-rw-r--r--arch/i386/kernel/process.c7
-rw-r--r--arch/i386/kernel/ptrace.c21
-rw-r--r--arch/i386/kernel/quirks.c33
-rw-r--r--arch/i386/kernel/setup.c6
-rw-r--r--arch/i386/kernel/smpboot.c27
-rw-r--r--arch/i386/kernel/srat.c84
-rw-r--r--arch/i386/kernel/sysenter.c65
-rw-r--r--arch/i386/kernel/trampoline.S5
-rw-r--r--arch/i386/kernel/traps.c124
-rw-r--r--arch/i386/kernel/tsc.c2
-rw-r--r--arch/i386/kernel/vmlinux.lds.S3
-rw-r--r--arch/i386/mach-default/setup.c2
-rw-r--r--arch/i386/mach-es7000/es7000.h9
-rw-r--r--arch/i386/mach-es7000/es7000plat.c53
-rw-r--r--arch/i386/mach-generic/bigsmp.c2
-rw-r--r--arch/i386/mach-generic/default.c2
-rw-r--r--arch/i386/mach-generic/es7000.c2
-rw-r--r--arch/i386/mach-generic/summit.c2
-rw-r--r--arch/i386/mach-visws/setup.c3
-rw-r--r--arch/i386/mach-voyager/voyager_smp.c6
-rw-r--r--arch/i386/mm/discontig.c28
-rw-r--r--arch/i386/mm/init.c14
-rw-r--r--arch/i386/mm/pageattr.c2
-rw-r--r--arch/i386/pci/fixup.c13
-rw-r--r--arch/i386/pci/mmconfig.c30
-rw-r--r--arch/ia64/Kconfig17
-rw-r--r--arch/ia64/hp/common/hwsw_iommu.c4
-rw-r--r--arch/ia64/hp/sim/simserial.c2
-rw-r--r--arch/ia64/ia32/sys_ia32.c4
-rw-r--r--arch/ia64/kernel/Makefile1
-rw-r--r--arch/ia64/kernel/acpi.c206
-rw-r--r--arch/ia64/kernel/cpufreq/acpi-cpufreq.c4
-rw-r--r--arch/ia64/kernel/crash.c40
-rw-r--r--arch/ia64/kernel/crash_dump.c49
-rw-r--r--arch/ia64/kernel/efi.c2
-rw-r--r--arch/ia64/kernel/entry.S2
-rw-r--r--arch/ia64/kernel/iosapic.c5
-rw-r--r--arch/ia64/kernel/irq.c3
-rw-r--r--arch/ia64/kernel/jprobes.S3
-rw-r--r--arch/ia64/kernel/kprobes.c226
-rw-r--r--arch/ia64/kernel/machine_kexec.c22
-rw-r--r--arch/ia64/kernel/mca.c2
-rw-r--r--arch/ia64/kernel/msi_ia64.c19
-rw-r--r--arch/ia64/kernel/perfmon.c10
-rw-r--r--arch/ia64/kernel/process.c26
-rw-r--r--arch/ia64/kernel/ptrace.c14
-rw-r--r--arch/ia64/kernel/salinfo.c6
-rw-r--r--arch/ia64/kernel/setup.c64
-rw-r--r--arch/ia64/kernel/smp.c8
-rw-r--r--arch/ia64/kernel/traps.c50
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S1
-rw-r--r--arch/ia64/mm/contig.c83
-rw-r--r--arch/ia64/mm/discontig.c46
-rw-r--r--arch/ia64/mm/init.c48
-rw-r--r--arch/ia64/sn/kernel/huberror.c16
-rw-r--r--arch/ia64/sn/kernel/io_acpi_init.c317
-rw-r--r--arch/ia64/sn/kernel/io_common.c90
-rw-r--r--arch/ia64/sn/kernel/io_init.c54
-rw-r--r--arch/ia64/sn/kernel/iomv.c5
-rw-r--r--arch/ia64/sn/kernel/msi_sn.c20
-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/xpc_channel.c15
-rw-r--r--arch/ia64/sn/kernel/xpc_main.c64
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_provider.c6
-rw-r--r--arch/m32r/Kconfig8
-rw-r--r--arch/m32r/boot/compressed/m32r_sio.c7
-rw-r--r--arch/m32r/kernel/entry.S67
-rw-r--r--arch/m32r/kernel/io_opsput.c71
-rw-r--r--arch/m32r/kernel/setup_opsput.c17
-rw-r--r--arch/m32r/kernel/smpboot.c2
-rw-r--r--arch/m32r/mm/fault.c4
-rw-r--r--arch/m68k/Kconfig8
-rw-r--r--arch/m68k/atari/stdma.c2
-rw-r--r--arch/m68k/kernel/sun3-head.S10
-rw-r--r--arch/m68k/kernel/vmlinux-sun3.lds2
-rw-r--r--arch/m68k/mm/kmap.c2
-rw-r--r--arch/m68k/mm/memory.c4
-rw-r--r--arch/m68k/mm/sun3mmu.c7
-rw-r--r--arch/m68knommu/Kconfig8
-rw-r--r--arch/m68knommu/kernel/time.c5
-rw-r--r--arch/m68knommu/kernel/vmlinux.lds.S10
-rw-r--r--arch/m68knommu/platform/5206/config.c2
-rw-r--r--arch/m68knommu/platform/5206e/config.c2
-rw-r--r--arch/m68knommu/platform/520x/config.c3
-rw-r--r--arch/m68knommu/platform/523x/config.c2
-rw-r--r--arch/m68knommu/platform/5249/config.c3
-rw-r--r--arch/m68knommu/platform/5272/config.c2
-rw-r--r--arch/m68knommu/platform/527x/config.c2
-rw-r--r--arch/m68knommu/platform/528x/config.c2
-rw-r--r--arch/m68knommu/platform/5307/config.c2
-rw-r--r--arch/m68knommu/platform/5307/pit.c2
-rw-r--r--arch/m68knommu/platform/5307/timers.c5
-rw-r--r--arch/m68knommu/platform/532x/config.c2
-rw-r--r--arch/m68knommu/platform/5407/config.c2
-rw-r--r--arch/m68knommu/platform/68328/config.c2
-rw-r--r--arch/mips/Kconfig184
-rw-r--r--arch/mips/Kconfig.debug8
-rw-r--r--arch/mips/Makefile17
-rw-r--r--arch/mips/arc/identify.c2
-rw-r--r--arch/mips/arc/memory.c18
-rw-r--r--arch/mips/au1000/common/irq.c8
-rw-r--r--arch/mips/au1000/common/pci.c26
-rw-r--r--arch/mips/au1000/common/prom.c3
-rw-r--r--arch/mips/au1000/common/setup.c19
-rw-r--r--arch/mips/au1000/pb1100/board_setup.c93
-rw-r--r--arch/mips/au1000/pb1200/irqmap.c32
-rw-r--r--arch/mips/basler/excite/excite_irq.c6
-rw-r--r--arch/mips/cobalt/irq.c2
-rw-r--r--arch/mips/cobalt/setup.c3
-rw-r--r--arch/mips/configs/atlas_defconfig2
-rw-r--r--arch/mips/configs/bigsur_defconfig2
-rw-r--r--arch/mips/configs/capcella_defconfig2
-rw-r--r--arch/mips/configs/cobalt_defconfig2
-rw-r--r--arch/mips/configs/db1000_defconfig2
-rw-r--r--arch/mips/configs/db1100_defconfig2
-rw-r--r--arch/mips/configs/db1200_defconfig2
-rw-r--r--arch/mips/configs/db1500_defconfig2
-rw-r--r--arch/mips/configs/db1550_defconfig2
-rw-r--r--arch/mips/configs/ddb5477_defconfig2
-rw-r--r--arch/mips/configs/decstation_defconfig2
-rw-r--r--arch/mips/configs/e55_defconfig2
-rw-r--r--arch/mips/configs/emma2rh_defconfig2
-rw-r--r--arch/mips/configs/ev64120_defconfig2
-rw-r--r--arch/mips/configs/excite_defconfig2
-rw-r--r--arch/mips/configs/ip22_defconfig2
-rw-r--r--arch/mips/configs/ip27_defconfig2
-rw-r--r--arch/mips/configs/ip32_defconfig2
-rw-r--r--arch/mips/configs/jaguar-atx_defconfig2
-rw-r--r--arch/mips/configs/jazz_defconfig2
-rw-r--r--arch/mips/configs/jmr3927_defconfig2
-rw-r--r--arch/mips/configs/lasat200_defconfig2
-rw-r--r--arch/mips/configs/malta_defconfig82
-rw-r--r--arch/mips/configs/mipssim_defconfig2
-rw-r--r--arch/mips/configs/mpc30x_defconfig2
-rw-r--r--arch/mips/configs/ocelot_3_defconfig2
-rw-r--r--arch/mips/configs/ocelot_c_defconfig2
-rw-r--r--arch/mips/configs/ocelot_defconfig2
-rw-r--r--arch/mips/configs/ocelot_g_defconfig2
-rw-r--r--arch/mips/configs/pb1100_defconfig2
-rw-r--r--arch/mips/configs/pb1500_defconfig2
-rw-r--r--arch/mips/configs/pb1550_defconfig2
-rw-r--r--arch/mips/configs/pnx8550-jbs_defconfig2
-rw-r--r--arch/mips/configs/pnx8550-stb810_defconfig1229
-rw-r--r--arch/mips/configs/pnx8550-v2pci_defconfig2
-rw-r--r--arch/mips/configs/qemu_defconfig2
-rw-r--r--arch/mips/configs/rbhma4500_defconfig2
-rw-r--r--arch/mips/configs/rm200_defconfig2
-rw-r--r--arch/mips/configs/sb1250-swarm_defconfig2
-rw-r--r--arch/mips/configs/sead_defconfig2
-rw-r--r--arch/mips/configs/tb0226_defconfig2
-rw-r--r--arch/mips/configs/tb0229_defconfig2
-rw-r--r--arch/mips/configs/tb0287_defconfig2
-rw-r--r--arch/mips/configs/workpad_defconfig2
-rw-r--r--arch/mips/configs/wrppmc_defconfig2
-rw-r--r--arch/mips/configs/yosemite_defconfig2
-rw-r--r--arch/mips/ddb5xxx/common/prom.c3
-rw-r--r--arch/mips/ddb5xxx/ddb5477/irq.c9
-rw-r--r--arch/mips/ddb5xxx/ddb5477/irq_5477.c2
-rw-r--r--arch/mips/dec/Makefile1
-rw-r--r--arch/mips/dec/ioasic-irq.c4
-rw-r--r--arch/mips/dec/kn02-irq.c2
-rw-r--r--arch/mips/dec/prom/identify.c3
-rw-r--r--arch/mips/dec/prom/memory.c17
-rw-r--r--arch/mips/dec/setup.c14
-rw-r--r--arch/mips/dec/tc.c95
-rw-r--r--arch/mips/defconfig2
-rw-r--r--arch/mips/emma2rh/common/irq_emma2rh.c2
-rw-r--r--arch/mips/emma2rh/markeins/irq.c2
-rw-r--r--arch/mips/emma2rh/markeins/irq_markeins.c4
-rw-r--r--arch/mips/gt64120/ev64120/irq.c2
-rw-r--r--arch/mips/gt64120/ev64120/setup.c3
-rw-r--r--arch/mips/gt64120/momenco_ocelot/dbg_io.c4
-rw-r--r--arch/mips/gt64120/momenco_ocelot/irq.c4
-rw-r--r--arch/mips/gt64120/momenco_ocelot/prom.c3
-rw-r--r--arch/mips/gt64120/wrppmc/irq.c2
-rw-r--r--arch/mips/gt64120/wrppmc/setup.c3
-rw-r--r--arch/mips/jazz/irq.c2
-rw-r--r--arch/mips/jmr3927/common/prom.c3
-rw-r--r--arch/mips/jmr3927/rbhma3100/irq.c2
-rw-r--r--arch/mips/jmr3927/rbhma3100/setup.c2
-rw-r--r--arch/mips/kernel/Makefile2
-rw-r--r--arch/mips/kernel/apm.c604
-rw-r--r--arch/mips/kernel/asm-offsets.c4
-rw-r--r--arch/mips/kernel/cpu-probe.c2
-rw-r--r--arch/mips/kernel/gdb-stub.c6
-rw-r--r--arch/mips/kernel/head.S27
-rw-r--r--arch/mips/kernel/i8259.c24
-rw-r--r--arch/mips/kernel/irixelf.c333
-rw-r--r--arch/mips/kernel/irq-msc01.c4
-rw-r--r--arch/mips/kernel/irq-mv6434x.c14
-rw-r--r--arch/mips/kernel/irq-rm7000.c13
-rw-r--r--arch/mips/kernel/irq-rm9000.c24
-rw-r--r--arch/mips/kernel/irq_cpu.c21
-rw-r--r--arch/mips/kernel/kspd.c2
-rw-r--r--arch/mips/kernel/linux32.c44
-rw-r--r--arch/mips/kernel/mips-mt.c9
-rw-r--r--arch/mips/kernel/mips_ksyms.c2
-rw-r--r--arch/mips/kernel/proc.c8
-rw-r--r--arch/mips/kernel/process.c6
-rw-r--r--arch/mips/kernel/r4k_fpu.S19
-rw-r--r--arch/mips/kernel/reset.c2
-rw-r--r--arch/mips/kernel/rtlx.c10
-rw-r--r--arch/mips/kernel/scall64-n32.S6
-rw-r--r--arch/mips/kernel/scall64-o32.S2
-rw-r--r--arch/mips/kernel/setup.c47
-rw-r--r--arch/mips/kernel/signal.c6
-rw-r--r--arch/mips/kernel/signal_n32.c4
-rw-r--r--arch/mips/kernel/smp-mt.c9
-rw-r--r--arch/mips/kernel/smp.c2
-rw-r--r--arch/mips/kernel/smtc.c119
-rw-r--r--arch/mips/kernel/sysirix.c14
-rw-r--r--arch/mips/kernel/time.c2
-rw-r--r--arch/mips/kernel/vmlinux.lds.S2
-rw-r--r--arch/mips/kernel/vpe.c47
-rw-r--r--arch/mips/lasat/interrupt.c2
-rw-r--r--arch/mips/lasat/prom.c3
-rw-r--r--arch/mips/lasat/sysctl.c23
-rw-r--r--arch/mips/lib-32/Makefile2
-rw-r--r--arch/mips/lib-64/Makefile2
-rw-r--r--arch/mips/lib-64/memset.S142
-rw-r--r--arch/mips/lib/Makefile2
-rw-r--r--arch/mips/lib/csum_partial.S735
-rw-r--r--arch/mips/lib/csum_partial_copy.c49
-rw-r--r--arch/mips/lib/memset.S (renamed from arch/mips/lib-32/memset.S)35
-rw-r--r--arch/mips/lib/uncached.c4
-rw-r--r--arch/mips/mips-boards/atlas/atlas_int.c9
-rw-r--r--arch/mips/mips-boards/generic/memory.c18
-rw-r--r--arch/mips/mips-boards/generic/time.c9
-rw-r--r--arch/mips/mips-boards/malta/Makefile1
-rw-r--r--arch/mips/mips-boards/malta/malta_int.c7
-rw-r--r--arch/mips/mips-boards/malta/malta_mtd.c63
-rw-r--r--arch/mips/mips-boards/malta/malta_setup.c39
-rw-r--r--arch/mips/mips-boards/sead/sead_int.c6
-rw-r--r--arch/mips/mips-boards/sim/sim_int.c6
-rw-r--r--arch/mips/mips-boards/sim/sim_mem.c16
-rw-r--r--arch/mips/mips-boards/sim/sim_setup.c2
-rw-r--r--arch/mips/mm/cache.c1
-rw-r--r--arch/mips/mm/init.c89
-rw-r--r--arch/mips/mm/ioremap.c96
-rw-r--r--arch/mips/mm/pg-r4k.c9
-rw-r--r--arch/mips/mm/tlb-r4k.c1
-rw-r--r--arch/mips/momentum/jaguar_atx/Makefile2
-rw-r--r--arch/mips/momentum/jaguar_atx/irq.c4
-rw-r--r--arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h6
-rw-r--r--arch/mips/momentum/jaguar_atx/platform.c235
-rw-r--r--arch/mips/momentum/jaguar_atx/prom.c58
-rw-r--r--arch/mips/momentum/ocelot_3/irq.c2
-rw-r--r--arch/mips/momentum/ocelot_3/prom.c3
-rw-r--r--arch/mips/momentum/ocelot_c/cpci-irq.c2
-rw-r--r--arch/mips/momentum/ocelot_c/dbg_io.c4
-rw-r--r--arch/mips/momentum/ocelot_c/irq.c2
-rw-r--r--arch/mips/momentum/ocelot_c/prom.c3
-rw-r--r--arch/mips/momentum/ocelot_c/uart-irq.c2
-rw-r--r--arch/mips/momentum/ocelot_g/dbg_io.c4
-rw-r--r--arch/mips/momentum/ocelot_g/irq.c4
-rw-r--r--arch/mips/momentum/ocelot_g/prom.c7
-rw-r--r--arch/mips/momentum/ocelot_g/setup.c4
-rw-r--r--arch/mips/oprofile/Kconfig2
-rw-r--r--arch/mips/pci/Makefile2
-rw-r--r--arch/mips/pci/fixup-pnx8550.c4
-rw-r--r--arch/mips/pci/fixup-vr4133.c16
-rw-r--r--arch/mips/pci/ops-pnx8550.c2
-rw-r--r--arch/mips/philips/pnx8550/common/int.c2
-rw-r--r--arch/mips/philips/pnx8550/common/prom.c23
-rw-r--r--arch/mips/philips/pnx8550/common/time.c45
-rw-r--r--arch/mips/philips/pnx8550/jbs/irqmap.c8
-rw-r--r--arch/mips/philips/pnx8550/stb810/Makefile4
-rw-r--r--arch/mips/philips/pnx8550/stb810/board_setup.c49
-rw-r--r--arch/mips/philips/pnx8550/stb810/irqmap.c23
-rw-r--r--arch/mips/philips/pnx8550/stb810/prom_init.c49
-rw-r--r--arch/mips/pmc-sierra/yosemite/dbg_io.c2
-rw-r--r--arch/mips/pmc-sierra/yosemite/irq.c6
-rw-r--r--arch/mips/pmc-sierra/yosemite/prom.c3
-rw-r--r--arch/mips/pmc-sierra/yosemite/setup.c2
-rw-r--r--arch/mips/qemu/q-mem.c3
-rw-r--r--arch/mips/sgi-ip22/ip22-eisa.c4
-rw-r--r--arch/mips/sgi-ip22/ip22-int.c13
-rw-r--r--arch/mips/sgi-ip22/ip22-mc.c3
-rw-r--r--arch/mips/sgi-ip27/ip27-irq.c2
-rw-r--r--arch/mips/sgi-ip27/ip27-memory.c3
-rw-r--r--arch/mips/sgi-ip27/ip27-timer.c2
-rw-r--r--arch/mips/sgi-ip32/ip32-irq.c10
-rw-r--r--arch/mips/sgi-ip32/ip32-memory.c3
-rw-r--r--arch/mips/sibyte/bcm1480/irq.c2
-rw-r--r--arch/mips/sibyte/cfe/setup.c3
-rw-r--r--arch/mips/sibyte/sb1250/irq.c2
-rw-r--r--arch/mips/sibyte/sb1250/prom.c3
-rw-r--r--arch/mips/sni/irq.c2
-rw-r--r--arch/mips/sni/sniprom.c3
-rw-r--r--arch/mips/tx4927/common/tx4927_irq.c4
-rw-r--r--arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c39
-rw-r--r--arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c3
-rw-r--r--arch/mips/tx4938/common/irq.c4
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/irq.c2
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/prom.c3
-rw-r--r--arch/mips/vr41xx/Kconfig5
-rw-r--r--arch/mips/vr41xx/common/icu.c31
-rw-r--r--arch/mips/vr41xx/common/init.c3
-rw-r--r--arch/mips/vr41xx/common/irq.c30
-rw-r--r--arch/mips/vr41xx/nec-cmbvr4133/irq.c60
-rw-r--r--arch/parisc/Kconfig8
-rw-r--r--arch/parisc/hpux/sys_hpux.c4
-rw-r--r--arch/parisc/kernel/smp.c2
-rw-r--r--arch/parisc/kernel/unwind.c2
-rw-r--r--arch/parisc/mm/ioremap.c111
-rw-r--r--arch/powerpc/Kconfig78
-rw-r--r--arch/powerpc/Kconfig.debug18
-rw-r--r--arch/powerpc/boot/Makefile4
-rw-r--r--arch/powerpc/boot/dts/lite5200.dts10
-rw-r--r--arch/powerpc/boot/dts/lite5200b.dts10
-rw-r--r--arch/powerpc/boot/dts/mpc8272ads.dts55
-rw-r--r--arch/powerpc/boot/dts/mpc8323emds.dts345
-rw-r--r--arch/powerpc/boot/dts/mpc8560ads.dts10
-rw-r--r--arch/powerpc/boot/dts/mpc866ads.dts162
-rw-r--r--arch/powerpc/boot/dts/mpc885ads.dts185
-rw-r--r--arch/powerpc/configs/cell_defconfig356
-rw-r--r--arch/powerpc/configs/celleb_defconfig1408
-rw-r--r--arch/powerpc/configs/chrp32_defconfig161
-rw-r--r--arch/powerpc/configs/g5_defconfig237
-rw-r--r--arch/powerpc/configs/iseries_defconfig132
-rw-r--r--arch/powerpc/configs/linkstation_defconfig111
-rw-r--r--arch/powerpc/configs/lite5200_defconfig39
-rw-r--r--arch/powerpc/configs/maple_defconfig91
-rw-r--r--arch/powerpc/configs/mpc7448_hpc2_defconfig175
-rw-r--r--arch/powerpc/configs/mpc8272_ads_defconfig848
-rw-r--r--arch/powerpc/configs/mpc832xemds_defconfig1083
-rw-r--r--arch/powerpc/configs/mpc834x_itx_defconfig188
-rw-r--r--arch/powerpc/configs/mpc834x_mds_defconfig96
-rw-r--r--arch/powerpc/configs/mpc8360emds_defconfig104
-rw-r--r--arch/powerpc/configs/mpc8540_ads_defconfig89
-rw-r--r--arch/powerpc/configs/mpc8560_ads_defconfig96
-rw-r--r--arch/powerpc/configs/mpc85xx_cds_defconfig96
-rw-r--r--arch/powerpc/configs/mpc8641_hpcn_defconfig98
-rw-r--r--arch/powerpc/configs/mpc866_ads_defconfig829
-rw-r--r--arch/powerpc/configs/mpc885_ads_defconfig827
-rw-r--r--arch/powerpc/configs/pasemi_defconfig1722
-rw-r--r--arch/powerpc/configs/pmac32_defconfig202
-rw-r--r--arch/powerpc/configs/ppc64_defconfig250
-rw-r--r--arch/powerpc/configs/ps3_defconfig274
-rw-r--r--arch/powerpc/configs/pseries_defconfig224
-rw-r--r--arch/powerpc/kernel/Makefile2
-rw-r--r--arch/powerpc/kernel/asm-offsets.c3
-rw-r--r--arch/powerpc/kernel/cpu_setup_pa6t.S44
-rw-r--r--arch/powerpc/kernel/cputable.c26
-rw-r--r--arch/powerpc/kernel/entry_64.S72
-rw-r--r--arch/powerpc/kernel/head_32.S12
-rw-r--r--arch/powerpc/kernel/head_64.S2
-rw-r--r--arch/powerpc/kernel/iomap.c20
-rw-r--r--arch/powerpc/kernel/irq.c8
-rw-r--r--arch/powerpc/kernel/kprobes.c8
-rw-r--r--arch/powerpc/kernel/lparcfg.c11
-rw-r--r--arch/powerpc/kernel/misc_64.S40
-rw-r--r--arch/powerpc/kernel/module_32.c30
-rw-r--r--arch/powerpc/kernel/module_64.c23
-rw-r--r--arch/powerpc/kernel/nvram_64.c4
-rw-r--r--arch/powerpc/kernel/of_device.c4
-rw-r--r--arch/powerpc/kernel/of_platform.c3
-rw-r--r--arch/powerpc/kernel/pci_32.c141
-rw-r--r--arch/powerpc/kernel/pci_64.c48
-rw-r--r--arch/powerpc/kernel/pmc.c37
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c3
-rw-r--r--arch/powerpc/kernel/proc_ppc64.c6
-rw-r--r--arch/powerpc/kernel/prom.c73
-rw-r--r--arch/powerpc/kernel/prom_init.c2
-rw-r--r--arch/powerpc/kernel/prom_parse.c15
-rw-r--r--arch/powerpc/kernel/ptrace.c24
-rw-r--r--arch/powerpc/kernel/rtas.c35
-rw-r--r--arch/powerpc/kernel/rtas_flash.c16
-rw-r--r--arch/powerpc/kernel/setup_32.c1
-rw-r--r--arch/powerpc/kernel/signal_32.c16
-rw-r--r--arch/powerpc/kernel/smp.c2
-rw-r--r--arch/powerpc/kernel/sysfs.c157
-rw-r--r--arch/powerpc/kernel/traps.c165
-rw-r--r--arch/powerpc/kernel/udbg.c4
-rw-r--r--arch/powerpc/kernel/udbg_16550.c24
-rw-r--r--arch/powerpc/kernel/vdso.c105
-rw-r--r--arch/powerpc/kernel/vio.c6
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S6
-rw-r--r--arch/powerpc/lib/Makefile4
-rw-r--r--arch/powerpc/lib/dma-noncoherent.c (renamed from arch/ppc/kernel/dma-mapping.c)24
-rw-r--r--arch/powerpc/lib/rheap.c6
-rw-r--r--arch/powerpc/mm/hugetlbpage.c11
-rw-r--r--arch/powerpc/mm/imalloc.c6
-rw-r--r--arch/powerpc/mm/mem.c24
-rw-r--r--arch/powerpc/mm/numa.c65
-rw-r--r--arch/powerpc/mm/pgtable_32.c5
-rw-r--r--arch/powerpc/oprofile/common.c2
-rw-r--r--arch/powerpc/oprofile/op_model_7450.c10
-rw-r--r--arch/powerpc/oprofile/op_model_fsl_booke.c81
-rw-r--r--arch/powerpc/oprofile/op_model_power4.c10
-rw-r--r--arch/powerpc/oprofile/op_model_rs64.c10
-rw-r--r--arch/powerpc/platforms/4xx/Kconfig2
-rw-r--r--arch/powerpc/platforms/52xx/Makefile1
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c9
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_common.c7
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pci.c412
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx.c2
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx_ads.c2
-rw-r--r--arch/powerpc/platforms/82xx/pq2ads.h5
-rw-r--r--arch/powerpc/platforms/83xx/misc.c29
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.c5
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_itx.c2
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_sys.c2
-rw-r--r--arch/powerpc/platforms/83xx/mpc8360e_pb.c5
-rw-r--r--arch/powerpc/platforms/86xx/Kconfig1
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_smp.c1
-rw-r--r--arch/powerpc/platforms/8xx/Kconfig300
-rw-r--r--arch/powerpc/platforms/8xx/Makefile6
-rw-r--r--arch/powerpc/platforms/8xx/m8xx_setup.c303
-rw-r--r--arch/powerpc/platforms/8xx/mpc86xads.h95
-rw-r--r--arch/powerpc/platforms/8xx/mpc86xads_setup.c301
-rw-r--r--arch/powerpc/platforms/8xx/mpc885ads.h95
-rw-r--r--arch/powerpc/platforms/8xx/mpc885ads_setup.c387
-rw-r--r--arch/powerpc/platforms/Makefile5
-rw-r--r--arch/powerpc/platforms/cell/Makefile7
-rw-r--r--arch/powerpc/platforms/cell/cbe_thermal.c2
-rw-r--r--arch/powerpc/platforms/cell/io-workarounds.c2
-rw-r--r--arch/powerpc/platforms/cell/iommu.c5
-rw-r--r--arch/powerpc/platforms/cell/pmu.c5
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c3
-rw-r--r--arch/powerpc/platforms/cell/spu_manage.c420
-rw-r--r--arch/powerpc/platforms/cell/spu_priv1_mmio.c411
-rw-r--r--arch/powerpc/platforms/cell/spufs/coredump.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/syscalls.c2
-rw-r--r--arch/powerpc/platforms/celleb/Makefile9
-rw-r--r--arch/powerpc/platforms/celleb/beat.c163
-rw-r--r--arch/powerpc/platforms/celleb/beat.h40
-rw-r--r--arch/powerpc/platforms/celleb/beat_syscall.h160
-rw-r--r--arch/powerpc/platforms/celleb/beat_wrapper.h220
-rw-r--r--arch/powerpc/platforms/celleb/htab.c311
-rw-r--r--arch/powerpc/platforms/celleb/hvCall.S287
-rw-r--r--arch/powerpc/platforms/celleb/interrupt.c274
-rw-r--r--arch/powerpc/platforms/celleb/interrupt.h33
-rw-r--r--arch/powerpc/platforms/celleb/iommu.c104
-rw-r--r--arch/powerpc/platforms/celleb/pci.c481
-rw-r--r--arch/powerpc/platforms/celleb/pci.h35
-rw-r--r--arch/powerpc/platforms/celleb/scc.h145
-rw-r--r--arch/powerpc/platforms/celleb/scc_epci.c409
-rw-r--r--arch/powerpc/platforms/celleb/scc_sio.c101
-rw-r--r--arch/powerpc/platforms/celleb/scc_uhc.c94
-rw-r--r--arch/powerpc/platforms/celleb/setup.c191
-rw-r--r--arch/powerpc/platforms/celleb/smp.c124
-rw-r--r--arch/powerpc/platforms/celleb/spu_priv1.c208
-rw-r--r--arch/powerpc/platforms/celleb/udbg_beat.c97
-rw-r--r--arch/powerpc/platforms/chrp/setup.c4
-rw-r--r--arch/powerpc/platforms/embedded6xx/Kconfig11
-rw-r--r--arch/powerpc/platforms/iseries/Kconfig2
-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/proc.c11
-rw-r--r--arch/powerpc/platforms/iseries/setup.c3
-rw-r--r--arch/powerpc/platforms/iseries/viopath.c4
-rw-r--r--arch/powerpc/platforms/maple/pci.c23
-rw-r--r--arch/powerpc/platforms/maple/setup.c16
-rw-r--r--arch/powerpc/platforms/pasemi/Kconfig10
-rw-r--r--arch/powerpc/platforms/pasemi/Makefile3
-rw-r--r--arch/powerpc/platforms/pasemi/idle.c88
-rw-r--r--arch/powerpc/platforms/pasemi/iommu.c281
-rw-r--r--arch/powerpc/platforms/pasemi/pasemi.h12
-rw-r--r--arch/powerpc/platforms/pasemi/pci.c13
-rw-r--r--arch/powerpc/platforms/pasemi/powersave.S80
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c106
-rw-r--r--arch/powerpc/platforms/powermac/smp.c1
-rw-r--r--arch/powerpc/platforms/ps3/Kconfig11
-rw-r--r--arch/powerpc/platforms/ps3/Makefile4
-rw-r--r--arch/powerpc/platforms/ps3/htab.c1
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c446
-rw-r--r--arch/powerpc/platforms/ps3/mm.c1
-rw-r--r--arch/powerpc/platforms/ps3/os-area.c22
-rw-r--r--arch/powerpc/platforms/ps3/platform.h151
-rw-r--r--arch/powerpc/platforms/ps3/repository.c220
-rw-r--r--arch/powerpc/platforms/ps3/setup.c19
-rw-r--r--arch/powerpc/platforms/ps3/smp.c3
-rw-r--r--arch/powerpc/platforms/ps3/spu.c20
-rw-r--r--arch/powerpc/platforms/ps3/system-bus.c (renamed from drivers/ps3/system-bus.c)36
-rw-r--r--arch/powerpc/platforms/pseries/Makefile2
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c20
-rw-r--r--arch/powerpc/platforms/pseries/eeh_cache.c2
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c16
-rw-r--r--arch/powerpc/platforms/pseries/firmware.c1
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c275
-rw-r--r--arch/powerpc/platforms/pseries/hvCall.S9
-rw-r--r--arch/powerpc/platforms/pseries/hvCall_inst.c6
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c3
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c55
-rw-r--r--arch/powerpc/platforms/pseries/pci.c2
-rw-r--r--arch/powerpc/platforms/pseries/scanlog.c2
-rw-r--r--arch/powerpc/platforms/pseries/setup.c30
-rw-r--r--arch/powerpc/platforms/pseries/smp.c200
-rw-r--r--arch/powerpc/platforms/pseries/xics.c5
-rw-r--r--arch/powerpc/sysdev/Makefile7
-rw-r--r--arch/powerpc/sysdev/commproc.c398
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.c154
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.h2
-rw-r--r--arch/powerpc/sysdev/dcr.S39
-rw-r--r--arch/powerpc/sysdev/fsl_soc.c274
-rw-r--r--arch/powerpc/sysdev/grackle.c2
-rw-r--r--arch/powerpc/sysdev/ipic.c17
-rw-r--r--arch/powerpc/sysdev/micropatch.c743
-rw-r--r--arch/powerpc/sysdev/mmio_nvram.c40
-rw-r--r--arch/powerpc/sysdev/mpc8xx_pic.c197
-rw-r--r--arch/powerpc/sysdev/mpc8xx_pic.h12
-rw-r--r--arch/powerpc/sysdev/mpic.c68
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_ic.c46
-rw-r--r--arch/powerpc/sysdev/rom.c1
-rw-r--r--arch/powerpc/xmon/ppc-opc.c7
-rw-r--r--arch/powerpc/xmon/spu-dis.c2
-rw-r--r--arch/powerpc/xmon/spu-opc.c4
-rw-r--r--arch/powerpc/xmon/xmon.c10
-rw-r--r--arch/ppc/8260_io/fcc_enet.c4
-rw-r--r--arch/ppc/8xx_io/cs4218_tdm.c15
-rw-r--r--arch/ppc/Kconfig26
-rw-r--r--arch/ppc/boot/simple/Makefile4
-rw-r--r--arch/ppc/boot/simple/misc.c15
-rw-r--r--arch/ppc/configs/gemini_defconfig618
-rw-r--r--arch/ppc/kernel/Makefile1
-rw-r--r--arch/ppc/kernel/head.S18
-rw-r--r--arch/ppc/kernel/pci.c41
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c1
-rw-r--r--arch/ppc/kernel/traps.c64
-rw-r--r--arch/ppc/lib/rheap.c3
-rw-r--r--arch/ppc/mm/pgtable.c5
-rw-r--r--arch/ppc/platforms/4xx/Kconfig2
-rw-r--r--arch/ppc/platforms/Makefile1
-rw-r--r--arch/ppc/platforms/ev64360.c3
-rw-r--r--arch/ppc/platforms/gemini.h165
-rw-r--r--arch/ppc/platforms/gemini_pci.c41
-rw-r--r--arch/ppc/platforms/gemini_prom.S90
-rw-r--r--arch/ppc/platforms/gemini_serial.h40
-rw-r--r--arch/ppc/platforms/gemini_setup.c577
-rw-r--r--arch/ppc/platforms/mpc866ads_setup.c2
-rw-r--r--arch/ppc/syslib/Makefile1
-rw-r--r--arch/ppc/syslib/m8260_pci_erratum9.c3
-rw-r--r--arch/ppc/syslib/m8xx_setup.c2
-rw-r--r--arch/ppc/syslib/ppc85xx_rio.c2
-rw-r--r--arch/ppc/xmon/ppc-opc.c7
-rw-r--r--arch/ppc/xmon/start.c5
-rw-r--r--arch/s390/Kconfig51
-rw-r--r--arch/s390/appldata/appldata_base.c2
-rw-r--r--arch/s390/appldata/appldata_mem.c2
-rw-r--r--arch/s390/appldata/appldata_net_sum.c2
-rw-r--r--arch/s390/crypto/Kconfig60
-rw-r--r--arch/s390/crypto/Makefile3
-rw-r--r--arch/s390/crypto/aes_s390.c47
-rw-r--r--arch/s390/crypto/crypt_s390.h281
-rw-r--r--arch/s390/crypto/crypt_s390_query.c129
-rw-r--r--arch/s390/crypto/des_check_key.c6
-rw-r--r--arch/s390/crypto/des_s390.c8
-rw-r--r--arch/s390/crypto/prng.c213
-rw-r--r--arch/s390/crypto/sha1_s390.c83
-rw-r--r--arch/s390/crypto/sha256_s390.c11
-rw-r--r--arch/s390/defconfig63
-rw-r--r--arch/s390/hypfs/Makefile2
-rw-r--r--arch/s390/hypfs/hypfs.h9
-rw-r--r--arch/s390/hypfs/hypfs_diag.c4
-rw-r--r--arch/s390/hypfs/hypfs_diag.h16
-rw-r--r--arch/s390/hypfs/hypfs_vm.c231
-rw-r--r--arch/s390/hypfs/inode.c35
-rw-r--r--arch/s390/kernel/Makefile4
-rw-r--r--arch/s390/kernel/base.S150
-rw-r--r--arch/s390/kernel/binfmt_elf32.c2
-rw-r--r--arch/s390/kernel/compat_exec_domain.c5
-rw-r--r--arch/s390/kernel/compat_linux.c24
-rw-r--r--arch/s390/kernel/compat_linux.h31
-rw-r--r--arch/s390/kernel/compat_signal.c8
-rw-r--r--arch/s390/kernel/cpcmd.c14
-rw-r--r--arch/s390/kernel/crash.c1
-rw-r--r--arch/s390/kernel/debug.c30
-rw-r--r--arch/s390/kernel/early.c306
-rw-r--r--arch/s390/kernel/ebcdic.c1
-rw-r--r--arch/s390/kernel/head31.S184
-rw-r--r--arch/s390/kernel/head64.S183
-rw-r--r--arch/s390/kernel/ipl.c159
-rw-r--r--arch/s390/kernel/irq.c15
-rw-r--r--arch/s390/kernel/kprobes.c32
-rw-r--r--arch/s390/kernel/machine_kexec.c1
-rw-r--r--arch/s390/kernel/module.c5
-rw-r--r--arch/s390/kernel/process.c4
-rw-r--r--arch/s390/kernel/profile.c20
-rw-r--r--arch/s390/kernel/ptrace.c46
-rw-r--r--arch/s390/kernel/reipl.S6
-rw-r--r--arch/s390/kernel/reipl64.S5
-rw-r--r--arch/s390/kernel/reset.S48
-rw-r--r--arch/s390/kernel/s390_ext.c10
-rw-r--r--arch/s390/kernel/setup.c212
-rw-r--r--arch/s390/kernel/signal.c2
-rw-r--r--arch/s390/kernel/smp.c37
-rw-r--r--arch/s390/kernel/stacktrace.c10
-rw-r--r--arch/s390/kernel/time.c1185
-rw-r--r--arch/s390/kernel/traps.c24
-rw-r--r--arch/s390/kernel/vmlinux.lds.S13
-rw-r--r--arch/s390/kernel/vtime.c10
-rw-r--r--arch/s390/lib/Makefile2
-rw-r--r--arch/s390/lib/delay.c48
-rw-r--r--arch/s390/lib/qrnnd.S77
-rw-r--r--arch/s390/lib/uaccess.h23
-rw-r--r--arch/s390/lib/uaccess_mvcos.c78
-rw-r--r--arch/s390/lib/uaccess_pt.c337
-rw-r--r--arch/s390/lib/uaccess_std.c26
-rw-r--r--arch/s390/math-emu/Makefile2
-rw-r--r--arch/s390/math-emu/math.c2
-rw-r--r--arch/s390/math-emu/qrnnd.S77
-rw-r--r--arch/s390/mm/Makefile2
-rw-r--r--arch/s390/mm/cmm.c4
-rw-r--r--arch/s390/mm/extmem.c168
-rw-r--r--arch/s390/mm/fault.c93
-rw-r--r--arch/s390/mm/init.c188
-rw-r--r--arch/s390/mm/ioremap.c84
-rw-r--r--arch/s390/mm/vmem.c382
-rw-r--r--arch/sh/Kconfig29
-rw-r--r--arch/sh/Kconfig.debug3
-rw-r--r--arch/sh/Makefile7
-rw-r--r--arch/sh/boards/hp6xx/hp6xx_apm.c68
-rw-r--r--arch/sh/boards/landisk/irq.c4
-rw-r--r--arch/sh/boards/se/7206/irq.c16
-rw-r--r--arch/sh/boards/se/7619/Makefile2
-rw-r--r--arch/sh/boards/se/7619/io.c102
-rw-r--r--arch/sh/boards/se/7619/setup.c21
-rw-r--r--arch/sh/boot/Makefile40
-rw-r--r--arch/sh/boot/compressed/Makefile6
-rw-r--r--arch/sh/boot/compressed/head.S3
-rw-r--r--arch/sh/boot/compressed/misc.c3
-rw-r--r--arch/sh/configs/landisk_defconfig85
-rw-r--r--arch/sh/configs/se7206_defconfig142
-rw-r--r--arch/sh/configs/se7619_defconfig744
-rw-r--r--arch/sh/drivers/push-switch.c13
-rw-r--r--arch/sh/kernel/Makefile1
-rw-r--r--arch/sh/kernel/apm.c538
-rw-r--r--arch/sh/kernel/cpu/Makefile1
-rw-r--r--arch/sh/kernel/cpu/sh2/entry.S32
-rw-r--r--arch/sh/kernel/cpu/sh2/setup-sh7619.c41
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7206.c62
-rw-r--r--arch/sh/kernel/cpu/sh4/Makefile9
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c9
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7750.c31
-rw-r--r--arch/sh/kernel/cpu/sh4/sq.c7
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile19
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh73180.c (renamed from arch/sh/kernel/cpu/sh4/clock-sh73180.c)0
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7343.c99
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7770.c (renamed from arch/sh/kernel/cpu/sh4/clock-sh7770.c)0
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7780.c (renamed from arch/sh/kernel/cpu/sh4/clock-sh7780.c)0
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh73180.c (renamed from arch/sh/kernel/cpu/sh4/setup-sh73180.c)0
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7343.c (renamed from arch/sh/kernel/cpu/sh4/setup-sh7343.c)0
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7722.c80
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7770.c (renamed from arch/sh/kernel/cpu/sh4/setup-sh7770.c)0
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7780.c (renamed from arch/sh/kernel/cpu/sh4/setup-sh7780.c)0
-rw-r--r--arch/sh/kernel/early_printk.c20
-rw-r--r--arch/sh/kernel/entry-common.S15
-rw-r--r--arch/sh/kernel/head.S3
-rw-r--r--arch/sh/kernel/process.c15
-rw-r--r--arch/sh/kernel/setup.c41
-rw-r--r--arch/sh/kernel/sh_ksyms.c15
-rw-r--r--arch/sh/kernel/signal.c2
-rw-r--r--arch/sh/kernel/sys_sh.c8
-rw-r--r--arch/sh/kernel/traps.c35
-rw-r--r--arch/sh/kernel/vmlinux.lds.S2
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall.c58
-rw-r--r--arch/sh/mm/Kconfig12
-rw-r--r--arch/sh/mm/cache-sh4.c2
-rw-r--r--arch/sh/mm/init.c2
-rw-r--r--arch/sh/mm/ioremap.c90
-rw-r--r--arch/sh/oprofile/op_model_sh7750.c2
-rw-r--r--arch/sh64/Kconfig8
-rw-r--r--arch/sh64/mm/ioremap.c100
-rw-r--r--arch/sparc/Kconfig8
-rw-r--r--arch/sparc/defconfig711
-rw-r--r--arch/sparc/kernel/ioport.c11
-rw-r--r--arch/sparc/kernel/irq.c4
-rw-r--r--arch/sparc/kernel/of_device.c3
-rw-r--r--arch/sparc/kernel/process.c1
-rw-r--r--arch/sparc/kernel/ptrace.c5
-rw-r--r--arch/sparc/kernel/smp.c8
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c8
-rw-r--r--arch/sparc/kernel/sun4d_irq.c9
-rw-r--r--arch/sparc/kernel/sun4d_smp.c2
-rw-r--r--arch/sparc/kernel/sys_sunos.c6
-rw-r--r--arch/sparc/kernel/time.c5
-rw-r--r--arch/sparc/lib/Makefile4
-rw-r--r--arch/sparc/lib/atomic32.c39
-rw-r--r--arch/sparc/lib/bitops.S109
-rw-r--r--arch/sparc/mm/io-unit.c8
-rw-r--r--arch/sparc64/Kconfig16
-rw-r--r--arch/sparc64/Kconfig.debug4
-rw-r--r--arch/sparc64/defconfig82
-rw-r--r--arch/sparc64/kernel/Makefile1
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c4
-rw-r--r--arch/sparc64/kernel/chmc.c3
-rw-r--r--arch/sparc64/kernel/entry.S27
-rw-r--r--arch/sparc64/kernel/head.S15
-rw-r--r--arch/sparc64/kernel/irq.c24
-rw-r--r--arch/sparc64/kernel/isa.c32
-rw-r--r--arch/sparc64/kernel/kprobes.c91
-rw-r--r--arch/sparc64/kernel/of_device.c10
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c16
-rw-r--r--arch/sparc64/kernel/ptrace.c5
-rw-r--r--arch/sparc64/kernel/rtrap.S23
-rw-r--r--arch/sparc64/kernel/smp.c9
-rw-r--r--arch/sparc64/kernel/stacktrace.c41
-rw-r--r--arch/sparc64/kernel/sun4v_ivec.S20
-rw-r--r--arch/sparc64/kernel/sun4v_tlb_miss.S4
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c8
-rw-r--r--arch/sparc64/kernel/traps.c30
-rw-r--r--arch/sparc64/kernel/unaligned.c44
-rw-r--r--arch/sparc64/kernel/visemul.c6
-rw-r--r--arch/sparc64/mm/init.c147
-rw-r--r--arch/sparc64/mm/ultra.S8
-rw-r--r--arch/sparc64/solaris/fs.c4
-rw-r--r--arch/sparc64/solaris/ioctl.c6
-rw-r--r--arch/sparc64/solaris/misc.c6
-rw-r--r--arch/sparc64/solaris/socksys.c14
-rw-r--r--arch/sparc64/solaris/timod.c10
-rw-r--r--arch/um/Kconfig5
-rw-r--r--arch/um/Kconfig.i38658
-rw-r--r--arch/um/drivers/line.c2
-rw-r--r--arch/um/drivers/net_kern.c18
-rw-r--r--arch/um/include/line.h2
-rw-r--r--arch/um/include/net_kern.h2
-rw-r--r--arch/um/kernel/exec.c7
-rw-r--r--arch/um/sys-i386/Makefile2
-rw-r--r--arch/um/sys-i386/bug.c20
-rw-r--r--arch/um/sys-i386/ldt.c4
-rw-r--r--arch/um/sys-i386/signal.c3
-rw-r--r--arch/um/sys-x86_64/Makefile2
-rw-r--r--arch/um/sys-x86_64/bug.c20
-rw-r--r--arch/um/sys-x86_64/signal.c5
-rw-r--r--arch/v850/Kconfig36
-rw-r--r--arch/x86_64/Kconfig15
-rw-r--r--arch/x86_64/Makefile2
-rw-r--r--arch/x86_64/defconfig41
-rw-r--r--arch/x86_64/ia32/ia32_aout.c12
-rw-r--r--arch/x86_64/ia32/ia32_binfmt.c49
-rw-r--r--arch/x86_64/ia32/syscall32.c70
-rw-r--r--arch/x86_64/kernel/cpufreq/Kconfig7
-rw-r--r--arch/x86_64/kernel/cpufreq/Makefile2
-rw-r--r--arch/x86_64/kernel/early-quirks.c9
-rw-r--r--arch/x86_64/kernel/entry.S33
-rw-r--r--arch/x86_64/kernel/genapic.c4
-rw-r--r--arch/x86_64/kernel/io_apic.c141
-rw-r--r--arch/x86_64/kernel/module.c5
-rw-r--r--arch/x86_64/kernel/mpparse.c2
-rw-r--r--arch/x86_64/kernel/nmi.c11
-rw-r--r--arch/x86_64/kernel/pci-calgary.c22
-rw-r--r--arch/x86_64/kernel/pci-swiotlb.c2
-rw-r--r--arch/x86_64/kernel/process.c6
-rw-r--r--arch/x86_64/kernel/time.c43
-rw-r--r--arch/x86_64/kernel/traps.c122
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S5
-rw-r--r--arch/x86_64/kernel/vsyscall.c3
-rw-r--r--arch/x86_64/mm/srat.c48
-rw-r--r--arch/x86_64/pci/mmconfig.c29
-rw-r--r--arch/xtensa/Kconfig29
-rw-r--r--arch/xtensa/Makefile25
-rw-r--r--arch/xtensa/boot/boot-elf/bootstrap.S3
-rw-r--r--arch/xtensa/boot/boot-redboot/bootstrap.S37
-rw-r--r--arch/xtensa/configs/iss_defconfig6
-rw-r--r--arch/xtensa/kernel/Makefile2
-rw-r--r--arch/xtensa/kernel/align.S42
-rw-r--r--arch/xtensa/kernel/asm-offsets.c5
-rw-r--r--arch/xtensa/kernel/coprocessor.S2
-rw-r--r--arch/xtensa/kernel/entry.S256
-rw-r--r--arch/xtensa/kernel/head.S53
-rw-r--r--arch/xtensa/kernel/irq.c107
-rw-r--r--arch/xtensa/kernel/pci-dma.c44
-rw-r--r--arch/xtensa/kernel/process.c108
-rw-r--r--arch/xtensa/kernel/ptrace.c28
-rw-r--r--arch/xtensa/kernel/setup.c41
-rw-r--r--arch/xtensa/kernel/signal.c28
-rw-r--r--arch/xtensa/kernel/syscall.c95
-rw-r--r--arch/xtensa/kernel/syscalls.c288
-rw-r--r--arch/xtensa/kernel/syscalls.h247
-rw-r--r--arch/xtensa/kernel/time.c8
-rw-r--r--arch/xtensa/kernel/traps.c56
-rw-r--r--arch/xtensa/kernel/vectors.S12
-rw-r--r--arch/xtensa/kernel/vmlinux.lds.S26
-rw-r--r--arch/xtensa/lib/checksum.S3
-rw-r--r--arch/xtensa/lib/memcopy.S2
-rw-r--r--arch/xtensa/lib/memset.S2
-rw-r--r--arch/xtensa/lib/strncpy_user.S2
-rw-r--r--arch/xtensa/lib/strnlen_user.S2
-rw-r--r--arch/xtensa/lib/usercopy.S2
-rw-r--r--arch/xtensa/mm/fault.c10
-rw-r--r--arch/xtensa/mm/init.c6
-rw-r--r--arch/xtensa/mm/misc.S265
-rw-r--r--arch/xtensa/mm/tlb.c445
-rw-r--r--arch/xtensa/platform-iss/console.c8
-rw-r--r--arch/xtensa/platform-iss/network.c2
-rw-r--r--block/as-iosched.c15
-rw-r--r--block/cfq-iosched.c46
-rw-r--r--block/elevator.c37
-rw-r--r--block/genhd.c31
-rw-r--r--block/ioctl.c6
-rw-r--r--block/ll_rw_blk.c157
-rw-r--r--block/scsi_ioctl.c16
-rw-r--r--crypto/Kconfig72
-rw-r--r--crypto/Makefile3
-rw-r--r--crypto/algapi.c15
-rw-r--r--crypto/api.c80
-rw-r--r--crypto/blkcipher.c10
-rw-r--r--crypto/camellia.c1801
-rw-r--r--crypto/cbc.c9
-rw-r--r--crypto/cipher.c447
-rw-r--r--crypto/compress.c5
-rw-r--r--crypto/digest.c24
-rw-r--r--crypto/ecb.c9
-rw-r--r--crypto/fcrypt.c423
-rw-r--r--crypto/hash.c5
-rw-r--r--crypto/hmac.c9
-rw-r--r--crypto/internal.h27
-rw-r--r--crypto/lrw.c11
-rw-r--r--crypto/pcbc.c349
-rw-r--r--crypto/sha512.c2
-rw-r--r--crypto/tcrypt.c73
-rw-r--r--crypto/tcrypt.h538
-rw-r--r--crypto/xcbc.c60
-rw-r--r--drivers/Kconfig4
-rw-r--r--drivers/Makefile4
-rw-r--r--drivers/acorn/block/fd1772.c4
-rw-r--r--drivers/acorn/char/i2c.c2
-rw-r--r--drivers/acpi/Kconfig43
-rw-r--r--drivers/acpi/Makefile5
-rw-r--r--drivers/acpi/ac.c9
-rw-r--r--drivers/acpi/acpi_memhotplug.c5
-rw-r--r--drivers/acpi/asus_acpi.c73
-rw-r--r--drivers/acpi/battery.c35
-rw-r--r--drivers/acpi/bay.c490
-rw-r--r--drivers/acpi/blacklist.c29
-rw-r--r--drivers/acpi/bus.c47
-rw-r--r--drivers/acpi/button.c225
-rw-r--r--drivers/acpi/container.c11
-rw-r--r--drivers/acpi/debug.c62
-rw-r--r--drivers/acpi/dispatcher/dsfield.c32
-rw-r--r--drivers/acpi/dispatcher/dsinit.c25
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c55
-rw-r--r--drivers/acpi/dispatcher/dsmthdat.c2
-rw-r--r--drivers/acpi/dispatcher/dsobject.c78
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c6
-rw-r--r--drivers/acpi/dispatcher/dsutils.c2
-rw-r--r--drivers/acpi/dispatcher/dswexec.c12
-rw-r--r--drivers/acpi/dispatcher/dswload.c19
-rw-r--r--drivers/acpi/dispatcher/dswscope.c2
-rw-r--r--drivers/acpi/dispatcher/dswstate.c2
-rw-r--r--drivers/acpi/dock.c169
-rw-r--r--drivers/acpi/ec.c363
-rw-r--r--drivers/acpi/events/evevent.c17
-rw-r--r--drivers/acpi/events/evgpe.c91
-rw-r--r--drivers/acpi/events/evgpeblk.c64
-rw-r--r--drivers/acpi/events/evmisc.c202
-rw-r--r--drivers/acpi/events/evregion.c17
-rw-r--r--drivers/acpi/events/evrgnini.c168
-rw-r--r--drivers/acpi/events/evsci.c14
-rw-r--r--drivers/acpi/events/evxface.c8
-rw-r--r--drivers/acpi/events/evxfevnt.c27
-rw-r--r--drivers/acpi/events/evxfregn.c2
-rw-r--r--drivers/acpi/executer/exconfig.c235
-rw-r--r--drivers/acpi/executer/exconvrt.c2
-rw-r--r--drivers/acpi/executer/excreate.c21
-rw-r--r--drivers/acpi/executer/exdump.c29
-rw-r--r--drivers/acpi/executer/exfield.c2
-rw-r--r--drivers/acpi/executer/exfldio.c7
-rw-r--r--drivers/acpi/executer/exmisc.c2
-rw-r--r--drivers/acpi/executer/exmutex.c92
-rw-r--r--drivers/acpi/executer/exnames.c2
-rw-r--r--drivers/acpi/executer/exoparg1.c4
-rw-r--r--drivers/acpi/executer/exoparg2.c2
-rw-r--r--drivers/acpi/executer/exoparg3.c2
-rw-r--r--drivers/acpi/executer/exoparg6.c2
-rw-r--r--drivers/acpi/executer/exprep.c2
-rw-r--r--drivers/acpi/executer/exregion.c16
-rw-r--r--drivers/acpi/executer/exresnte.c2
-rw-r--r--drivers/acpi/executer/exresolv.c10
-rw-r--r--drivers/acpi/executer/exresop.c12
-rw-r--r--drivers/acpi/executer/exstore.c2
-rw-r--r--drivers/acpi/executer/exstoren.c2
-rw-r--r--drivers/acpi/executer/exstorob.c2
-rw-r--r--drivers/acpi/executer/exsystem.c110
-rw-r--r--drivers/acpi/executer/exutils.c106
-rw-r--r--drivers/acpi/fan.c17
-rw-r--r--drivers/acpi/glue.c121
-rw-r--r--drivers/acpi/hardware/hwacpi.c56
-rw-r--r--drivers/acpi/hardware/hwgpe.c15
-rw-r--r--drivers/acpi/hardware/hwregs.c98
-rw-r--r--drivers/acpi/hardware/hwsleep.c81
-rw-r--r--drivers/acpi/hardware/hwtimer.c9
-rw-r--r--drivers/acpi/hotkey.c5
-rw-r--r--drivers/acpi/i2c_ec.c8
-rw-r--r--drivers/acpi/ibm_acpi.c1042
-rw-r--r--drivers/acpi/motherboard.c191
-rw-r--r--drivers/acpi/namespace/nsaccess.c36
-rw-r--r--drivers/acpi/namespace/nsalloc.c14
-rw-r--r--drivers/acpi/namespace/nsdump.c13
-rw-r--r--drivers/acpi/namespace/nsdumpdv.c2
-rw-r--r--drivers/acpi/namespace/nseval.c13
-rw-r--r--drivers/acpi/namespace/nsinit.c9
-rw-r--r--drivers/acpi/namespace/nsload.c160
-rw-r--r--drivers/acpi/namespace/nsnames.c2
-rw-r--r--drivers/acpi/namespace/nsobject.c2
-rw-r--r--drivers/acpi/namespace/nsparse.c52
-rw-r--r--drivers/acpi/namespace/nssearch.c9
-rw-r--r--drivers/acpi/namespace/nsutils.c9
-rw-r--r--drivers/acpi/namespace/nswalk.c65
-rw-r--r--drivers/acpi/namespace/nsxfeval.c13
-rw-r--r--drivers/acpi/namespace/nsxfname.c47
-rw-r--r--drivers/acpi/namespace/nsxfobj.c46
-rw-r--r--drivers/acpi/numa.c79
-rw-r--r--drivers/acpi/osl.c102
-rw-r--r--drivers/acpi/parser/psargs.c2
-rw-r--r--drivers/acpi/parser/psloop.c1408
-rw-r--r--drivers/acpi/parser/psopcode.c2
-rw-r--r--drivers/acpi/parser/psparse.c7
-rw-r--r--drivers/acpi/parser/psscope.c2
-rw-r--r--drivers/acpi/parser/pstree.c2
-rw-r--r--drivers/acpi/parser/psutils.c2
-rw-r--r--drivers/acpi/parser/pswalk.c2
-rw-r--r--drivers/acpi/parser/psxface.c116
-rw-r--r--drivers/acpi/pci_bind.c16
-rw-r--r--drivers/acpi/pci_irq.c9
-rw-r--r--drivers/acpi/pci_link.c18
-rw-r--r--drivers/acpi/pci_root.c54
-rw-r--r--drivers/acpi/power.c9
-rw-r--r--drivers/acpi/processor_core.c209
-rw-r--r--drivers/acpi/processor_idle.c78
-rw-r--r--drivers/acpi/processor_perflib.c45
-rw-r--r--drivers/acpi/processor_thermal.c6
-rw-r--r--drivers/acpi/processor_throttling.c10
-rw-r--r--drivers/acpi/resources/rsaddr.c2
-rw-r--r--drivers/acpi/resources/rscalc.c2
-rw-r--r--drivers/acpi/resources/rscreate.c2
-rw-r--r--drivers/acpi/resources/rsdump.c2
-rw-r--r--drivers/acpi/resources/rsinfo.c2
-rw-r--r--drivers/acpi/resources/rsio.c2
-rw-r--r--drivers/acpi/resources/rsirq.c2
-rw-r--r--drivers/acpi/resources/rslist.c2
-rw-r--r--drivers/acpi/resources/rsmemory.c2
-rw-r--r--drivers/acpi/resources/rsmisc.c2
-rw-r--r--drivers/acpi/resources/rsutils.c2
-rw-r--r--drivers/acpi/resources/rsxface.c2
-rw-r--r--drivers/acpi/sbs.c27
-rw-r--r--drivers/acpi/scan.c1268
-rw-r--r--drivers/acpi/sleep/proc.c36
-rw-r--r--drivers/acpi/sleep/wakeup.c6
-rw-r--r--drivers/acpi/system.c39
-rw-r--r--drivers/acpi/tables.c508
-rw-r--r--drivers/acpi/tables/Makefile3
-rw-r--r--drivers/acpi/tables/tbconvrt.c622
-rw-r--r--drivers/acpi/tables/tbfadt.c434
-rw-r--r--drivers/acpi/tables/tbfind.c126
-rw-r--r--drivers/acpi/tables/tbget.c471
-rw-r--r--drivers/acpi/tables/tbgetall.c311
-rw-r--r--drivers/acpi/tables/tbinstal.c664
-rw-r--r--drivers/acpi/tables/tbrsdt.c307
-rw-r--r--drivers/acpi/tables/tbutils.c513
-rw-r--r--drivers/acpi/tables/tbxface.c641
-rw-r--r--drivers/acpi/tables/tbxfroot.c552
-rw-r--r--drivers/acpi/thermal.c41
-rw-r--r--drivers/acpi/toshiba_acpi.c86
-rw-r--r--drivers/acpi/utilities/utalloc.c11
-rw-r--r--drivers/acpi/utilities/utcache.c10
-rw-r--r--drivers/acpi/utilities/utcopy.c11
-rw-r--r--drivers/acpi/utilities/utdebug.c8
-rw-r--r--drivers/acpi/utilities/utdelete.c16
-rw-r--r--drivers/acpi/utilities/uteval.c2
-rw-r--r--drivers/acpi/utilities/utglobal.c199
-rw-r--r--drivers/acpi/utilities/utinit.c114
-rw-r--r--drivers/acpi/utilities/utmath.c2
-rw-r--r--drivers/acpi/utilities/utmisc.c102
-rw-r--r--drivers/acpi/utilities/utmutex.c18
-rw-r--r--drivers/acpi/utilities/utobject.c2
-rw-r--r--drivers/acpi/utilities/utresrc.c2
-rw-r--r--drivers/acpi/utilities/utstate.c2
-rw-r--r--drivers/acpi/utilities/utxface.c29
-rw-r--r--drivers/acpi/utils.c10
-rw-r--r--drivers/acpi/video.c278
-rw-r--r--drivers/ata/Kconfig49
-rw-r--r--drivers/ata/Makefile3
-rw-r--r--drivers/ata/ahci.c347
-rw-r--r--drivers/ata/ata_generic.c14
-rw-r--r--drivers/ata/ata_piix.c76
-rw-r--r--drivers/ata/libata-core.c622
-rw-r--r--drivers/ata/libata-eh.c13
-rw-r--r--drivers/ata/libata-scsi.c400
-rw-r--r--drivers/ata/libata-sff.c666
-rw-r--r--drivers/ata/libata.h4
-rw-r--r--drivers/ata/pata_ali.c32
-rw-r--r--drivers/ata/pata_amd.c36
-rw-r--r--drivers/ata/pata_artop.c12
-rw-r--r--drivers/ata/pata_atiixp.c17
-rw-r--r--drivers/ata/pata_cmd64x.c41
-rw-r--r--drivers/ata/pata_cs5520.c41
-rw-r--r--drivers/ata/pata_cs5530.c44
-rw-r--r--drivers/ata/pata_cs5535.c6
-rw-r--r--drivers/ata/pata_cypress.c6
-rw-r--r--drivers/ata/pata_efar.c6
-rw-r--r--drivers/ata/pata_hpt366.c26
-rw-r--r--drivers/ata/pata_hpt37x.c67
-rw-r--r--drivers/ata/pata_hpt3x2n.c32
-rw-r--r--drivers/ata/pata_hpt3x3.c8
-rw-r--r--drivers/ata/pata_isapnp.c21
-rw-r--r--drivers/ata/pata_it8213.c354
-rw-r--r--drivers/ata/pata_it821x.c62
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c55
-rw-r--r--drivers/ata/pata_jmicron.c26
-rw-r--r--drivers/ata/pata_legacy.c168
-rw-r--r--drivers/ata/pata_marvell.c12
-rw-r--r--drivers/ata/pata_mpc52xx.c538
-rw-r--r--drivers/ata/pata_mpiix.c113
-rw-r--r--drivers/ata/pata_netcell.c6
-rw-r--r--drivers/ata/pata_ns87410.c6
-rw-r--r--drivers/ata/pata_oldpiix.c24
-rw-r--r--drivers/ata/pata_opti.c24
-rw-r--r--drivers/ata/pata_optidma.c40
-rw-r--r--drivers/ata/pata_pcmcia.c27
-rw-r--r--drivers/ata/pata_pdc2027x.c122
-rw-r--r--drivers/ata/pata_pdc202xx_old.c41
-rw-r--r--drivers/ata/pata_platform.c70
-rw-r--r--drivers/ata/pata_qdi.c54
-rw-r--r--drivers/ata/pata_radisys.c6
-rw-r--r--drivers/ata/pata_rz1000.c14
-rw-r--r--drivers/ata/pata_sc1200.c6
-rw-r--r--drivers/ata/pata_serverworks.c31
-rw-r--r--drivers/ata/pata_sil680.c10
-rw-r--r--drivers/ata/pata_sis.c70
-rw-r--r--drivers/ata/pata_sl82c105.c10
-rw-r--r--drivers/ata/pata_triflex.c6
-rw-r--r--drivers/ata/pata_via.c37
-rw-r--r--drivers/ata/pata_winbond.c51
-rw-r--r--drivers/ata/pdc_adma.c120
-rw-r--r--drivers/ata/sata_inic162x.c781
-rw-r--r--drivers/ata/sata_mv.c205
-rw-r--r--drivers/ata/sata_nv.c651
-rw-r--r--drivers/ata/sata_promise.c379
-rw-r--r--drivers/ata/sata_qstor.c138
-rw-r--r--drivers/ata/sata_sil.c99
-rw-r--r--drivers/ata/sata_sil24.c178
-rw-r--r--drivers/ata/sata_sis.c161
-rw-r--r--drivers/ata/sata_svw.c153
-rw-r--r--drivers/ata/sata_sx4.c207
-rw-r--r--drivers/ata/sata_uli.c69
-rw-r--r--drivers/ata/sata_via.c206
-rw-r--r--drivers/ata/sata_vsc.c111
-rw-r--r--drivers/atm/.gitignore2
-rw-r--r--drivers/atm/Kconfig5
-rw-r--r--drivers/atm/ambassador.c17
-rw-r--r--drivers/atm/eni.c4
-rw-r--r--drivers/atm/fore200e.c166
-rw-r--r--drivers/atm/he.c2
-rw-r--r--drivers/atm/horizon.c2
-rw-r--r--drivers/atm/lanai.c2
-rw-r--r--drivers/atm/nicstar.c4
-rw-r--r--drivers/atm/zatm.c4
-rw-r--r--drivers/base/Kconfig12
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/base.h1
-rw-r--r--drivers/base/class.c23
-rw-r--r--drivers/base/core.c205
-rw-r--r--drivers/base/dd.c24
-rw-r--r--drivers/base/devres.c644
-rw-r--r--drivers/base/dma-mapping.c218
-rw-r--r--drivers/base/dmapool.c61
-rw-r--r--drivers/base/firmware_class.c3
-rw-r--r--drivers/base/platform.c15
-rw-r--r--drivers/block/Kconfig21
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/acsi_slm.c4
-rw-r--r--drivers/block/aoe/aoecmd.c13
-rw-r--r--drivers/block/cciss.c33
-rw-r--r--drivers/block/cpqarray.c10
-rw-r--r--drivers/block/loop.c4
-rw-r--r--drivers/block/nbd.c2
-rw-r--r--drivers/block/pktcdvd.c596
-rw-r--r--drivers/block/swim_iop.c578
-rw-r--r--drivers/block/viodasd.c6
-rw-r--r--drivers/bluetooth/hci_usb.c8
-rw-r--r--drivers/cdrom/cdrom.c19
-rw-r--r--drivers/cdrom/cm206.c2
-rw-r--r--drivers/cdrom/viocd.c4
-rw-r--r--drivers/char/Kconfig30
-rw-r--r--drivers/char/Makefile4
-rw-r--r--drivers/char/agp/Kconfig4
-rw-r--r--drivers/char/agp/agp.h4
-rw-r--r--drivers/char/agp/amd-k7-agp.c5
-rw-r--r--drivers/char/agp/amd64-agp.c9
-rw-r--r--drivers/char/agp/ati-agp.c36
-rw-r--r--drivers/char/agp/generic.c36
-rw-r--r--drivers/char/agp/intel-agp.c181
-rw-r--r--drivers/char/agp/sgi-agp.c9
-rw-r--r--drivers/char/agp/via-agp.c21
-rw-r--r--drivers/char/amiserial.c6
-rw-r--r--drivers/char/apm-emulation.c (renamed from arch/arm/kernel/apm.c)10
-rw-r--r--drivers/char/consolemap.c2
-rw-r--r--drivers/char/cs5535_gpio.c4
-rw-r--r--drivers/char/cyclades.c7769
-rw-r--r--drivers/char/drm/drm.h33
-rw-r--r--drivers/char/drm/drmP.h66
-rw-r--r--drivers/char/drm/drm_bufs.c29
-rw-r--r--drivers/char/drm/drm_core.h8
-rw-r--r--drivers/char/drm/drm_drawable.c294
-rw-r--r--drivers/char/drm/drm_drv.c14
-rw-r--r--drivers/char/drm/drm_ioc32.c56
-rw-r--r--drivers/char/drm/drm_irq.c155
-rw-r--r--drivers/char/drm/drm_lock.c13
-rw-r--r--drivers/char/drm/drm_memory.c94
-rw-r--r--drivers/char/drm/drm_memory.h20
-rw-r--r--drivers/char/drm/drm_memory_debug.h70
-rw-r--r--drivers/char/drm/drm_mm.c183
-rw-r--r--drivers/char/drm/drm_pciids.h4
-rw-r--r--drivers/char/drm/drm_proc.c4
-rw-r--r--drivers/char/drm/drm_sman.c3
-rw-r--r--drivers/char/drm/drm_stub.c14
-rw-r--r--drivers/char/drm/drm_sysfs.c8
-rw-r--r--drivers/char/drm/drm_vm.c32
-rw-r--r--drivers/char/drm/i810_dma.c34
-rw-r--r--drivers/char/drm/i810_drv.h2
-rw-r--r--drivers/char/drm/i830_dma.c32
-rw-r--r--drivers/char/drm/i830_drv.h2
-rw-r--r--drivers/char/drm/i915_dma.c2
-rw-r--r--drivers/char/drm/i915_drm.h19
-rw-r--r--drivers/char/drm/i915_drv.c4
-rw-r--r--drivers/char/drm/i915_drv.h22
-rw-r--r--drivers/char/drm/i915_ioc32.c12
-rw-r--r--drivers/char/drm/i915_irq.c344
-rw-r--r--drivers/char/drm/mga_ioc32.c8
-rw-r--r--drivers/char/drm/r128_drm.h3
-rw-r--r--drivers/char/drm/r128_drv.h3
-rw-r--r--drivers/char/drm/r128_ioc32.c10
-rw-r--r--drivers/char/drm/r128_state.c3
-rw-r--r--drivers/char/drm/r300_cmdbuf.c32
-rw-r--r--drivers/char/drm/radeon_drv.h15
-rw-r--r--drivers/char/drm/radeon_ioc32.c20
-rw-r--r--drivers/char/drm/radeon_irq.c4
-rw-r--r--drivers/char/drm/radeon_mem.c4
-rw-r--r--drivers/char/drm/radeon_state.c13
-rw-r--r--drivers/char/drm/savage_bci.c4
-rw-r--r--drivers/char/drm/via_dma.c9
-rw-r--r--drivers/char/drm/via_dmablit.c2
-rw-r--r--drivers/char/drm/via_drv.h11
-rw-r--r--drivers/char/drm/via_irq.c16
-rw-r--r--drivers/char/drm/via_map.c3
-rw-r--r--drivers/char/drm/via_verifier.c50
-rw-r--r--drivers/char/drm/via_verifier.h1
-rw-r--r--drivers/char/dsp56k.c6
-rw-r--r--drivers/char/dtlk.c4
-rw-r--r--drivers/char/epca.c16
-rw-r--r--drivers/char/esp.c2
-rw-r--r--drivers/char/generic_serial.c4
-rw-r--r--drivers/char/hvc_beat.c134
-rw-r--r--drivers/char/hvcs.c6
-rw-r--r--drivers/char/hvsi.c2
-rw-r--r--drivers/char/hw_random/amd-rng.c2
-rw-r--r--drivers/char/hw_random/geode-rng.c2
-rw-r--r--drivers/char/hw_random/intel-rng.c34
-rw-r--r--drivers/char/hw_random/ixp4xx-rng.c2
-rw-r--r--drivers/char/hw_random/via-rng.c2
-rw-r--r--drivers/char/ip2/i2ellis.h4
-rw-r--r--drivers/char/ip2/ip2main.c12
-rw-r--r--drivers/char/ipmi/ipmi_bt_sm.c4
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c6
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c15
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c6
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c150
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c29
-rw-r--r--drivers/char/isicom.c399
-rw-r--r--drivers/char/istallion.c1164
-rw-r--r--drivers/char/lcd.c2
-rw-r--r--drivers/char/lp.c6
-rw-r--r--drivers/char/mem.c20
-rw-r--r--drivers/char/moxa.c18
-rw-r--r--drivers/char/mxser.c33
-rw-r--r--drivers/char/mxser_new.c2813
-rw-r--r--drivers/char/mxser_new.h450
-rw-r--r--drivers/char/n_r3964.c41
-rw-r--r--drivers/char/n_tty.c3
-rw-r--r--drivers/char/nsc_gpio.c4
-rw-r--r--drivers/char/pcmcia/synclink_cs.c4
-rw-r--r--drivers/char/ppdev.c4
-rw-r--r--drivers/char/pty.c10
-rw-r--r--drivers/char/random.c4
-rw-r--r--drivers/char/raw.c2
-rw-r--r--drivers/char/rio/riocmd.c2
-rw-r--r--drivers/char/riscom8.c4
-rw-r--r--drivers/char/rocket.c10
-rw-r--r--drivers/char/rtc.c43
-rw-r--r--drivers/char/ser_a2232.c2
-rw-r--r--drivers/char/serial167.c2
-rw-r--r--drivers/char/sonypi.c2
-rw-r--r--drivers/char/specialix.c9
-rw-r--r--drivers/char/stallion.c2148
-rw-r--r--drivers/char/sx.c2236
-rw-r--r--drivers/char/sx.h1
-rw-r--r--drivers/char/synclink.c6
-rw-r--r--drivers/char/synclink_gt.c6
-rw-r--r--drivers/char/synclinkmp.c10
-rw-r--r--drivers/char/sysrq.c57
-rw-r--r--drivers/char/tb0219.c4
-rw-r--r--drivers/char/tipar.c4
-rw-r--r--drivers/char/tlclk.c45
-rw-r--r--drivers/char/tpm/tpm_bios.c8
-rw-r--r--drivers/char/tty_io.c404
-rw-r--r--drivers/char/tty_ioctl.c264
-rw-r--r--drivers/char/vc_screen.c6
-rw-r--r--drivers/char/viocons.c17
-rw-r--r--drivers/char/viotape.c15
-rw-r--r--drivers/char/vme_scc.c2
-rw-r--r--drivers/char/vr41xx_giu.c118
-rw-r--r--drivers/char/vt.c2
-rw-r--r--drivers/char/vt_ioctl.c10
-rw-r--r--drivers/char/watchdog/at91rm9200_wdt.c6
-rw-r--r--drivers/char/watchdog/booke_wdt.c20
-rw-r--r--drivers/char/watchdog/machzwd.c2
-rw-r--r--drivers/char/watchdog/mpcore_wdt.c2
-rw-r--r--drivers/char/watchdog/omap_wdt.c2
-rw-r--r--drivers/char/watchdog/pcwd_usb.c5
-rw-r--r--drivers/char/watchdog/rm9k_wdt.c44
-rw-r--r--drivers/clocksource/acpi_pm.c42
-rw-r--r--drivers/connector/cn_proc.c11
-rw-r--r--drivers/connector/cn_queue.c5
-rw-r--r--drivers/connector/connector.c17
-rw-r--r--drivers/cpufreq/cpufreq.c172
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c33
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c33
-rw-r--r--drivers/cpufreq/cpufreq_performance.c9
-rw-r--r--drivers/cpufreq/cpufreq_powersave.c9
-rw-r--r--drivers/cpufreq/cpufreq_stats.c15
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c11
-rw-r--r--drivers/cpufreq/freq_table.c28
-rw-r--r--drivers/crypto/Kconfig4
-rw-r--r--drivers/crypto/geode-aes.c2
-rw-r--r--drivers/fc4/fc.c10
-rw-r--r--drivers/firmware/efivars.c29
-rw-r--r--drivers/firmware/pcdp.c2
-rw-r--r--drivers/hid/Kconfig40
-rw-r--r--drivers/hid/Makefile8
-rw-r--r--drivers/hid/hid-core.c998
-rw-r--r--drivers/hid/hid-debug.c (renamed from drivers/usb/input/hid-debug.h)35
-rw-r--r--drivers/hid/hid-input.c (renamed from drivers/usb/input/hid-input.c)236
-rw-r--r--drivers/hwmon/Kconfig56
-rw-r--r--drivers/hwmon/Makefile3
-rw-r--r--drivers/hwmon/ams/Makefile8
-rw-r--r--drivers/hwmon/ams/ams-core.c265
-rw-r--r--drivers/hwmon/ams/ams-i2c.c299
-rw-r--r--drivers/hwmon/ams/ams-input.c160
-rw-r--r--drivers/hwmon/ams/ams-pmu.c207
-rw-r--r--drivers/hwmon/ams/ams.h72
-rw-r--r--drivers/hwmon/f71805f.c569
-rw-r--r--drivers/hwmon/hdaps.c68
-rw-r--r--drivers/hwmon/hwmon-vid.c6
-rw-r--r--drivers/hwmon/it87.c202
-rw-r--r--drivers/hwmon/k8temp.c4
-rw-r--r--drivers/hwmon/pc87360.c2
-rw-r--r--drivers/hwmon/pc87427.c627
-rw-r--r--drivers/hwmon/w83627ehf.c2
-rw-r--r--drivers/hwmon/w83792d.c2
-rw-r--r--drivers/hwmon/w83793.c1702
-rw-r--r--drivers/i2c/algos/Kconfig11
-rw-r--r--drivers/i2c/algos/Makefile1
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c8
-rw-r--r--drivers/i2c/algos/i2c-algo-ite.c806
-rw-r--r--drivers/i2c/algos/i2c-algo-ite.h117
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c7
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c8
-rw-r--r--drivers/i2c/algos/i2c-algo-sgi.c8
-rw-r--r--drivers/i2c/busses/Kconfig40
-rw-r--r--drivers/i2c/busses/Makefile4
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c2
-rw-r--r--drivers/i2c/busses/i2c-at91.c325
-rw-r--r--drivers/i2c/busses/i2c-elektor.c2
-rw-r--r--drivers/i2c/busses/i2c-hydra.c2
-rw-r--r--drivers/i2c/busses/i2c-i801.c16
-rw-r--r--drivers/i2c/busses/i2c-i810.c6
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c9
-rw-r--r--drivers/i2c/busses/i2c-ite.c278
-rw-r--r--drivers/i2c/busses/i2c-ixp2000.c2
-rw-r--r--drivers/i2c/busses/i2c-ixp4xx.c2
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c4
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c89
-rw-r--r--drivers/i2c/busses/i2c-omap.c4
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c2
-rw-r--r--drivers/i2c/busses/i2c-parport.c2
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c2
-rw-r--r--drivers/i2c/busses/i2c-pnx.c703
-rw-r--r--drivers/i2c/busses/i2c-prosavage.c2
-rw-r--r--drivers/i2c/busses/i2c-savage4.c2
-rw-r--r--drivers/i2c/busses/i2c-versatile.c153
-rw-r--r--drivers/i2c/busses/i2c-via.c2
-rw-r--r--drivers/i2c/busses/i2c-voodoo3.c6
-rw-r--r--drivers/i2c/busses/scx200_i2c.c2
-rw-r--r--drivers/i2c/chips/ds1337.c8
-rw-r--r--drivers/i2c/chips/isp1301_omap.c2
-rw-r--r--drivers/i2c/chips/m41t00.c1
-rw-r--r--drivers/i2c/chips/tps65010.c21
-rw-r--r--drivers/i2c/i2c-core.c95
-rw-r--r--drivers/i2c/i2c-dev.c48
-rw-r--r--drivers/ide/Kconfig26
-rw-r--r--drivers/ide/Makefile1
-rw-r--r--drivers/ide/ide-acpi.c697
-rw-r--r--drivers/ide/ide-cd.c7
-rw-r--r--drivers/ide/ide-floppy.c2
-rw-r--r--drivers/ide/ide-pnp.c5
-rw-r--r--drivers/ide/ide-probe.c7
-rw-r--r--drivers/ide/ide-tape.c8
-rw-r--r--drivers/ide/ide.c47
-rw-r--r--drivers/ide/pci/Makefile4
-rw-r--r--drivers/ide/pci/aec62xx.c2
-rw-r--r--drivers/ide/pci/alim15x3.c18
-rw-r--r--drivers/ide/pci/amd74xx.c2
-rw-r--r--drivers/ide/pci/atiixp.c61
-rw-r--r--drivers/ide/pci/cmd64x.c2
-rw-r--r--drivers/ide/pci/cs5520.c2
-rw-r--r--drivers/ide/pci/cs5530.c2
-rw-r--r--drivers/ide/pci/cy82c693.c2
-rw-r--r--drivers/ide/pci/delkin_cb.c140
-rw-r--r--drivers/ide/pci/generic.c37
-rw-r--r--drivers/ide/pci/hpt34x.c2
-rw-r--r--drivers/ide/pci/hpt366.c2197
-rw-r--r--drivers/ide/pci/it8213.c362
-rw-r--r--drivers/ide/pci/jmicron.c17
-rw-r--r--drivers/ide/pci/ns87415.c2
-rw-r--r--drivers/ide/pci/opti621.c2
-rw-r--r--drivers/ide/pci/pdc202xx_new.c541
-rw-r--r--drivers/ide/pci/pdc202xx_old.c29
-rw-r--r--drivers/ide/pci/piix.c99
-rw-r--r--drivers/ide/pci/rz1000.c2
-rw-r--r--drivers/ide/pci/sc1200.c2
-rw-r--r--drivers/ide/pci/serverworks.c2
-rw-r--r--drivers/ide/pci/sgiioc4.c3
-rw-r--r--drivers/ide/pci/siimage.c2
-rw-r--r--drivers/ide/pci/sis5513.c5
-rw-r--r--drivers/ide/pci/sl82c105.c33
-rw-r--r--drivers/ide/pci/slc90e66.c75
-rw-r--r--drivers/ide/pci/tc86c001.c309
-rw-r--r--drivers/ide/pci/triflex.c2
-rw-r--r--drivers/ide/pci/trm290.c2
-rw-r--r--drivers/ide/pci/via82cxxx.c143
-rw-r--r--drivers/ide/setup-pci.c11
-rw-r--r--drivers/ieee1394/.gitignore1
-rw-r--r--drivers/ieee1394/Kconfig21
-rw-r--r--drivers/ieee1394/Makefile10
-rw-r--r--drivers/ieee1394/csr1212.c15
-rw-r--r--drivers/ieee1394/dv1394.c46
-rw-r--r--drivers/ieee1394/hosts.c13
-rw-r--r--drivers/ieee1394/hosts.h7
-rw-r--r--drivers/ieee1394/ieee1394_core.c23
-rw-r--r--drivers/ieee1394/ieee1394_core.h2
-rw-r--r--drivers/ieee1394/nodemgr.c63
-rw-r--r--drivers/ieee1394/nodemgr.h3
-rw-r--r--drivers/ieee1394/ohci1394.c17
-rw-r--r--drivers/ieee1394/oui.db7048
-rw-r--r--drivers/ieee1394/oui2c.sh22
-rw-r--r--drivers/ieee1394/pcilynx.c2
-rw-r--r--drivers/ieee1394/raw1394.c48
-rw-r--r--drivers/ieee1394/sbp2.c108
-rw-r--r--drivers/ieee1394/video1394.c8
-rw-r--r--drivers/infiniband/core/Makefile6
-rw-r--r--drivers/infiniband/core/addr.c3
-rw-r--r--drivers/infiniband/core/cm.c4
-rw-r--r--drivers/infiniband/core/cma.c431
-rw-r--r--drivers/infiniband/core/fmr_pool.c12
-rw-r--r--drivers/infiniband/core/mad.c101
-rw-r--r--drivers/infiniband/core/mad_priv.h6
-rw-r--r--drivers/infiniband/core/ucma.c885
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c2
-rw-r--r--drivers/infiniband/core/uverbs_main.c6
-rw-r--r--drivers/infiniband/core/uverbs_marshall.c5
-rw-r--r--drivers/infiniband/core/uverbs_mem.c12
-rw-r--r--drivers/infiniband/hw/amso1100/c2_cq.c2
-rw-r--r--drivers/infiniband/hw/amso1100/c2_qp.c13
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h29
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c70
-rw-r--r--drivers/infiniband/hw/ehca/ehca_hca.c8
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c5
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h12
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c16
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c82
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_uverbs.c395
-rw-r--r--drivers/infiniband/hw/ipath/Makefile1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_dma.c189
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c9
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c10
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6120.c8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_keys.c8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mr.c7
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sysfs.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_uc.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c10
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c113
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c7
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c30
-rw-r--r--drivers/infiniband/hw/mthca/mthca_srq.c4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c75
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c36
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c11
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c4
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h2
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c34
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c129
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c110
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h5
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/keyboard/amikbd.c2
-rw-r--r--drivers/input/keyboard/hilkbd.c5
-rw-r--r--drivers/input/keyboard/sunkbd.c2
-rw-r--r--drivers/input/serio/i8042-sparcio.h6
-rw-r--r--drivers/input/serio/serio.c6
-rw-r--r--drivers/input/touchscreen/Kconfig2
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c2
-rw-r--r--drivers/isdn/act2000/act2000_isa.c2
-rw-r--r--drivers/isdn/act2000/module.c3
-rw-r--r--drivers/isdn/capi/capi.c13
-rw-r--r--drivers/isdn/capi/capidrv.c11
-rw-r--r--drivers/isdn/divert/divert_procfs.c2
-rw-r--r--drivers/isdn/divert/isdn_divert.c6
-rw-r--r--drivers/isdn/gigaset/Kconfig1
-rw-r--r--drivers/isdn/gigaset/asyncdata.c5
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c118
-rw-r--r--drivers/isdn/gigaset/common.c98
-rw-r--r--drivers/isdn/gigaset/gigaset.h4
-rw-r--r--drivers/isdn/gigaset/interface.c4
-rw-r--r--drivers/isdn/gigaset/isocdata.c5
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c3
-rw-r--r--drivers/isdn/hardware/avm/b1.c10
-rw-r--r--drivers/isdn/hardware/avm/t1isa.c1
-rw-r--r--drivers/isdn/hardware/eicon/debug.c4
-rw-r--r--drivers/isdn/hardware/eicon/di.c8
-rw-r--r--drivers/isdn/hardware/eicon/divasmain.c2
-rw-r--r--drivers/isdn/hardware/eicon/io.c2
-rw-r--r--drivers/isdn/hardware/eicon/istream.c4
-rw-r--r--drivers/isdn/hardware/eicon/platform.h8
-rw-r--r--drivers/isdn/hisax/Kconfig18
-rw-r--r--drivers/isdn/hisax/avma1_cs.c3
-rw-r--r--drivers/isdn/hisax/config.c21
-rw-r--r--drivers/isdn/hisax/diva.c4
-rw-r--r--drivers/isdn/hisax/elsa_cs.c3
-rw-r--r--drivers/isdn/hisax/fsm.c4
-rw-r--r--drivers/isdn/hisax/hfc4s8s_l1.c3
-rw-r--r--drivers/isdn/hisax/hfc_pci.c10
-rw-r--r--drivers/isdn/hisax/hfc_usb.c3
-rw-r--r--drivers/isdn/hisax/hisax.h6
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.c4
-rw-r--r--drivers/isdn/hisax/hisax_isac.c2
-rw-r--r--drivers/isdn/hisax/isdnhdlc.c25
-rw-r--r--drivers/isdn/hisax/isdnhdlc.h2
-rw-r--r--drivers/isdn/hisax/sedlbauer.c4
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c3
-rw-r--r--drivers/isdn/hisax/st5481_b.c3
-rw-r--r--drivers/isdn/hisax/st5481_d.c4
-rw-r--r--drivers/isdn/hisax/st5481_init.c4
-rw-r--r--drivers/isdn/hisax/teles_cs.c3
-rw-r--r--drivers/isdn/hysdn/hycapi.c3
-rw-r--r--drivers/isdn/hysdn/hysdn_boot.c3
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c3
-rw-r--r--drivers/isdn/hysdn/hysdn_net.c3
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c2
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c9
-rw-r--r--drivers/isdn/i4l/isdn_audio.c6
-rw-r--r--drivers/isdn/i4l/isdn_bsdcomp.c4
-rw-r--r--drivers/isdn/i4l/isdn_common.c15
-rw-r--r--drivers/isdn/i4l/isdn_net.c8
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c24
-rw-r--r--drivers/isdn/i4l/isdn_tty.c2
-rw-r--r--drivers/isdn/i4l/isdn_v110.c3
-rw-r--r--drivers/isdn/icn/icn.c3
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c3
-rw-r--r--drivers/isdn/pcbit/drv.c9
-rw-r--r--drivers/isdn/pcbit/layer2.c5
-rw-r--r--drivers/isdn/sc/init.c9
-rw-r--r--drivers/kvm/Kconfig37
-rw-r--r--drivers/kvm/Makefile10
-rw-r--r--drivers/kvm/kvm.h630
-rw-r--r--drivers/kvm/kvm_main.c2137
-rw-r--r--drivers/kvm/kvm_svm.h44
-rw-r--r--drivers/kvm/kvm_vmx.h14
-rw-r--r--drivers/kvm/mmu.c1454
-rw-r--r--drivers/kvm/paging_tmpl.h484
-rw-r--r--drivers/kvm/segment_descriptor.h17
-rw-r--r--drivers/kvm/svm.c1721
-rw-r--r--drivers/kvm/svm.h315
-rw-r--r--drivers/kvm/vmx.c2061
-rw-r--r--drivers/kvm/vmx.h296
-rw-r--r--drivers/kvm/x86_emulate.c1415
-rw-r--r--drivers/kvm/x86_emulate.h185
-rw-r--r--drivers/leds/Kconfig22
-rw-r--r--drivers/leds/leds-s3c24xx.c2
-rw-r--r--drivers/macintosh/Kconfig2
-rw-r--r--drivers/macintosh/adb.c2
-rw-r--r--drivers/macintosh/apm_emu.c2
-rw-r--r--drivers/macintosh/rack-meter.c6
-rw-r--r--drivers/macintosh/smu.c2
-rw-r--r--drivers/macintosh/via-pmu-backlight.c2
-rw-r--r--drivers/macintosh/via-pmu.c1
-rw-r--r--drivers/macintosh/via-pmu68k.c2
-rw-r--r--drivers/macintosh/windfarm_core.c6
-rw-r--r--drivers/md/Kconfig1
-rw-r--r--drivers/md/bitmap.c42
-rw-r--r--drivers/md/dm-bio-list.h14
-rw-r--r--drivers/md/dm-crypt.c4
-rw-r--r--drivers/md/dm-emc.c10
-rw-r--r--drivers/md/dm-hw-handler.h2
-rw-r--r--drivers/md/dm-io.c15
-rw-r--r--drivers/md/dm-ioctl.c16
-rw-r--r--drivers/md/dm-linear.c4
-rw-r--r--drivers/md/dm-log.c24
-rw-r--r--drivers/md/dm-log.h10
-rw-r--r--drivers/md/dm-mpath.c52
-rw-r--r--drivers/md/dm-mpath.h4
-rw-r--r--drivers/md/dm-path-selector.h12
-rw-r--r--drivers/md/dm-raid1.c25
-rw-r--r--drivers/md/dm-round-robin.c12
-rw-r--r--drivers/md/dm-snap.c33
-rw-r--r--drivers/md/dm-stripe.c2
-rw-r--r--drivers/md/dm-zero.c2
-rw-r--r--drivers/md/dm.c155
-rw-r--r--drivers/md/dm.h19
-rw-r--r--drivers/md/faulty.c2
-rw-r--r--drivers/md/md.c74
-rw-r--r--drivers/md/raid1.c23
-rw-r--r--drivers/md/raid10.c17
-rw-r--r--drivers/md/raid5.c406
-rw-r--r--drivers/media/Kconfig2
-rw-r--r--drivers/media/common/ir-functions.c1
-rw-r--r--drivers/media/common/ir-keymaps.c56
-rw-r--r--drivers/media/common/saa7146_i2c.c16
-rw-r--r--drivers/media/dvb/b2c2/Kconfig1
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c10
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig2
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c2
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c11
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.h2
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c13
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c4
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig14
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--drivers/media/dvb/dvb-usb/a800.c36
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c271
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h5
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c40
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c200
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c113
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mc.c26
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c22
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.c24
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h14
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c37
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.c22
-rw-r--r--drivers/media/dvb/dvb-usb/nova-t-usb2.c38
-rw-r--r--drivers/media/dvb/dvb-usb/ttusb2.c270
-rw-r--r--drivers/media/dvb/dvb-usb/ttusb2.h70
-rw-r--r--drivers/media/dvb/dvb-usb/umt-010.c24
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.c20
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c40
-rw-r--r--drivers/media/dvb/frontends/Kconfig24
-rw-r--r--drivers/media/dvb/frontends/Makefile3
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c7
-rw-r--r--drivers/media/dvb/frontends/dib7000m.c1191
-rw-r--r--drivers/media/dvb/frontends/dib7000m.h51
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c1019
-rw-r--r--drivers/media/dvb/frontends/dib7000p.h46
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.h13
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c67
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h7
-rw-r--r--drivers/media/dvb/frontends/lg_h06xf.h64
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c257
-rw-r--r--drivers/media/dvb/frontends/lgdt330x_priv.h15
-rw-r--r--drivers/media/dvb/frontends/lgh06xf.c134
-rw-r--r--drivers/media/dvb/frontends/lgh06xf.h35
-rw-r--r--drivers/media/dvb/frontends/or51132.c176
-rw-r--r--drivers/media/dvb/frontends/or51211.c124
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c10
-rw-r--r--drivers/media/dvb/frontends/tda1004x.h5
-rw-r--r--drivers/media/dvb/frontends/tda8083.c30
-rw-r--r--drivers/media/dvb/frontends/tda826x.c12
-rw-r--r--drivers/media/dvb/frontends/tua6100.c3
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c8
-rw-r--r--drivers/media/dvb/ttpci/Kconfig1
-rw-r--r--drivers/media/dvb/ttpci/av7110.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c25
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c26
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c334
-rw-r--r--drivers/media/dvb/ttpci/budget.c2
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c11
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusbdecfe.c4
-rw-r--r--drivers/media/video/Kconfig31
-rw-r--r--drivers/media/video/Makefile6
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c6
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c6
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c101
-rw-r--r--drivers/media/video/cafe_ccic-regs.h160
-rw-r--r--drivers/media/video/cafe_ccic.c2228
-rw-r--r--drivers/media/video/compat_ioctl32.c2
-rw-r--r--drivers/media/video/cpia2/cpia2_usb.c4
-rw-r--r--drivers/media/video/cx2341x.c21
-rw-r--r--drivers/media/video/cx25840/cx25840-vbi.c9
-rw-r--r--drivers/media/video/cx88/Kconfig1
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c179
-rw-r--r--drivers/media/video/cx88/cx88-cards.c88
-rw-r--r--drivers/media/video/cx88/cx88-core.c37
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c333
-rw-r--r--drivers/media/video/cx88/cx88-input.c77
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c348
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c15
-rw-r--r--drivers/media/video/cx88/cx88-video.c32
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.c2
-rw-r--r--drivers/media/video/cx88/cx88.h49
-rw-r--r--drivers/media/video/dabusb.c4
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c4
-rw-r--r--drivers/media/video/ir-kbd-i2c.c46
-rw-r--r--drivers/media/video/ks0127.c8
-rw-r--r--drivers/media/video/meye.c4
-rw-r--r--drivers/media/video/msp3400-driver.c8
-rw-r--r--drivers/media/video/msp3400-kthreads.c11
-rw-r--r--drivers/media/video/mxb.c8
-rw-r--r--drivers/media/video/ov7670.c1333
-rw-r--r--drivers/media/video/planb.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c16
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c26
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c81
-rw-r--r--drivers/media/video/saa7115.c18
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c63
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c236
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c11
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c222
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c1
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c76
-rw-r--r--drivers/media/video/saa7134/saa7134.h8
-rw-r--r--drivers/media/video/stv680.c21
-rw-r--r--drivers/media/video/tda9887.c6
-rw-r--r--drivers/media/video/tuner-core.c8
-rw-r--r--drivers/media/video/tuner-simple.c4
-rw-r--r--drivers/media/video/tuner-types.c15
-rw-r--r--drivers/media/video/tveeprom.c11
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c9
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.h14
-rw-r--r--drivers/media/video/usbvideo/usbvideo.c2
-rw-r--r--drivers/media/video/usbvision/Kconfig12
-rw-r--r--drivers/media/video/usbvision/Makefile5
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.c156
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c2535
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c552
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c2088
-rw-r--r--drivers/media/video/usbvision/usbvision.h531
-rw-r--r--drivers/media/video/v4l1-compat.c18
-rw-r--r--drivers/media/video/v4l2-common.c92
-rw-r--r--drivers/media/video/video-buf.c3
-rw-r--r--drivers/media/video/videocodec.c2
-rw-r--r--drivers/media/video/videodev.c175
-rw-r--r--drivers/media/video/vino.c2
-rw-r--r--drivers/media/video/vivi.c31
-rw-r--r--drivers/media/video/w9966.c2
-rw-r--r--drivers/media/video/w9968cf.c24
-rw-r--r--drivers/media/video/zc0301/zc0301_sensor.h1
-rw-r--r--drivers/media/video/zoran_card.c2
-rw-r--r--drivers/media/video/zoran_device.c3
-rw-r--r--drivers/media/video/zoran_procfs.c4
-rw-r--r--drivers/media/video/zr36120.c2079
-rw-r--r--drivers/media/video/zr36120.h279
-rw-r--r--drivers/media/video/zr36120_i2c.c132
-rw-r--r--drivers/media/video/zr36120_mem.c78
-rw-r--r--drivers/media/video/zr36120_mem.h3
-rw-r--r--drivers/message/fusion/mptbase.c3
-rw-r--r--drivers/message/fusion/mptbase.h10
-rw-r--r--drivers/message/fusion/mptctl.c5
-rw-r--r--drivers/message/fusion/mptctl.h2
-rw-r--r--drivers/message/fusion/mptfc.c3
-rw-r--r--drivers/message/fusion/mptlan.c4
-rw-r--r--drivers/message/fusion/mptlan.h2
-rw-r--r--drivers/message/fusion/mptsas.c38
-rw-r--r--drivers/message/fusion/mptscsih.c19
-rw-r--r--drivers/message/fusion/mptscsih.h2
-rw-r--r--drivers/message/fusion/mptspi.c3
-rw-r--r--drivers/message/i2o/core.h4
-rw-r--r--drivers/message/i2o/driver.c2
-rw-r--r--drivers/message/i2o/exec-osm.c4
-rw-r--r--drivers/message/i2o/i2o_config.c4
-rw-r--r--drivers/misc/Kconfig21
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/asus-laptop.c1165
-rw-r--r--drivers/misc/lkdtm.c4
-rw-r--r--drivers/misc/msi-laptop.c3
-rw-r--r--drivers/misc/tifm_7xx1.c402
-rw-r--r--drivers/misc/tifm_core.c65
-rw-r--r--drivers/mmc/Kconfig2
-rw-r--r--drivers/mmc/at91_mci.c360
-rw-r--r--drivers/mmc/au1xmmc.c15
-rw-r--r--drivers/mmc/imxmmc.c7
-rw-r--r--drivers/mmc/mmc.c182
-rw-r--r--drivers/mmc/mmc_block.c15
-rw-r--r--drivers/mmc/mmc_queue.c6
-rw-r--r--drivers/mmc/mmc_sysfs.c2
-rw-r--r--drivers/mmc/mmci.c19
-rw-r--r--drivers/mmc/omap.c27
-rw-r--r--drivers/mmc/pxamci.c16
-rw-r--r--drivers/mmc/sdhci.c95
-rw-r--r--drivers/mmc/sdhci.h2
-rw-r--r--drivers/mmc/tifm_sd.c492
-rw-r--r--drivers/mmc/wbsd.c102
-rw-r--r--drivers/mmc/wbsd.h1
-rw-r--r--drivers/mtd/Kconfig15
-rw-r--r--drivers/mtd/Makefile15
-rw-r--r--drivers/mtd/afs.c3
-rw-r--r--drivers/mtd/chips/amd_flash.c3
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c5
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c11
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0020.c3
-rw-r--r--drivers/mtd/chips/gen_probe.c5
-rw-r--r--drivers/mtd/chips/jedec.c3
-rw-r--r--drivers/mtd/chips/jedec_probe.c17
-rw-r--r--drivers/mtd/chips/map_absent.c4
-rw-r--r--drivers/mtd/chips/map_ram.c4
-rw-r--r--drivers/mtd/chips/map_rom.c4
-rw-r--r--drivers/mtd/chips/sharp.c7
-rw-r--r--drivers/mtd/cmdlinepart.c5
-rw-r--r--drivers/mtd/devices/block2mtd.c3
-rw-r--r--drivers/mtd/devices/m25p80.c4
-rw-r--r--drivers/mtd/devices/ms02-nv.c18
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c6
-rw-r--r--drivers/mtd/devices/phram.c4
-rw-r--r--drivers/mtd/devices/slram.c7
-rw-r--r--drivers/mtd/ftl.c7
-rw-r--r--drivers/mtd/inftlcore.c12
-rw-r--r--drivers/mtd/maps/Kconfig71
-rw-r--r--drivers/mtd/maps/Makefile4
-rw-r--r--drivers/mtd/maps/amd76xrom.c34
-rw-r--r--drivers/mtd/maps/bast-flash.c2
-rw-r--r--drivers/mtd/maps/ceiva.c3
-rw-r--r--drivers/mtd/maps/ck804xrom.c356
-rw-r--r--drivers/mtd/maps/cstm_mips_ixx.c283
-rw-r--r--drivers/mtd/maps/esb2rom.c450
-rw-r--r--drivers/mtd/maps/integrator-flash.c4
-rw-r--r--drivers/mtd/maps/nettel.c5
-rw-r--r--drivers/mtd/maps/omap_nor.c4
-rw-r--r--drivers/mtd/maps/pcmciamtd.c3
-rw-r--r--drivers/mtd/maps/physmap.c5
-rw-r--r--drivers/mtd/maps/physmap_of.c255
-rw-r--r--drivers/mtd/maps/plat-ram.c3
-rw-r--r--drivers/mtd/maps/sa1100-flash.c4
-rw-r--r--drivers/mtd/maps/tqm834x.c8
-rw-r--r--drivers/mtd/maps/tqm8xxl.c3
-rw-r--r--drivers/mtd/mtd_blkdevs.c19
-rw-r--r--drivers/mtd/mtdblock.c10
-rw-r--r--drivers/mtd/mtdblock_ro.c7
-rw-r--r--drivers/mtd/mtdchar.c23
-rw-r--r--drivers/mtd/mtdconcat.c43
-rw-r--r--drivers/mtd/mtdcore.c93
-rw-r--r--drivers/mtd/mtdpart.c8
-rw-r--r--drivers/mtd/nand/Kconfig16
-rw-r--r--drivers/mtd/nand/Makefile5
-rw-r--r--drivers/mtd/nand/at91_nand.c223
-rw-r--r--drivers/mtd/nand/cafe.c771
-rw-r--r--drivers/mtd/nand/cafe_ecc.c1381
-rw-r--r--drivers/mtd/nand/cs553x_nand.c4
-rw-r--r--drivers/mtd/nand/diskonchip.c3
-rw-r--r--drivers/mtd/nand/nand_base.c133
-rw-r--r--drivers/mtd/nand/nand_bbt.c11
-rw-r--r--drivers/mtd/nand/nand_ecc.c4
-rw-r--r--drivers/mtd/nand/nandsim.c243
-rw-r--r--drivers/mtd/nand/ndfc.c2
-rw-r--r--drivers/mtd/nand/rtc_from4.c46
-rw-r--r--drivers/mtd/nand/s3c2410.c2
-rw-r--r--drivers/mtd/nftlcore.c12
-rw-r--r--drivers/mtd/onenand/generic.c5
-rw-r--r--drivers/mtd/onenand/onenand_base.c374
-rw-r--r--drivers/mtd/onenand/onenand_bbt.c14
-rw-r--r--drivers/mtd/redboot.c30
-rw-r--r--drivers/mtd/rfd_ftl.c5
-rw-r--r--drivers/mtd/ssfdc.c7
-rw-r--r--drivers/net/3c503.c3
-rw-r--r--drivers/net/3c59x.c3
-rw-r--r--drivers/net/7990.c2
-rw-r--r--drivers/net/8139cp.c13
-rw-r--r--drivers/net/8139too.c5
-rw-r--r--drivers/net/82596.c7
-rw-r--r--drivers/net/Kconfig116
-rw-r--r--drivers/net/Makefile7
-rw-r--r--drivers/net/Space.c15
-rw-r--r--drivers/net/ac3200.c3
-rw-r--r--drivers/net/amd8111e.c3
-rw-r--r--drivers/net/apne.c3
-rw-r--r--drivers/net/appletalk/ipddp.c2
-rw-r--r--drivers/net/arm/at91_ether.c2
-rw-r--r--drivers/net/arm/ep93xx_eth.c4
-rw-r--r--drivers/net/arm/etherh.c2
-rw-r--r--drivers/net/atl1/Makefile2
-rw-r--r--drivers/net/atl1/atl1.h283
-rw-r--r--drivers/net/atl1/atl1_ethtool.c508
-rw-r--r--drivers/net/atl1/atl1_hw.c718
-rw-r--r--drivers/net/atl1/atl1_hw.h951
-rw-r--r--drivers/net/atl1/atl1_main.c2468
-rw-r--r--drivers/net/atl1/atl1_param.c206
-rw-r--r--drivers/net/b44.c66
-rw-r--r--drivers/net/b44.h10
-rw-r--r--drivers/net/bmac.c20
-rw-r--r--drivers/net/bnx2.c128
-rw-r--r--drivers/net/bnx2.h6
-rw-r--r--drivers/net/bonding/bond_alb.c4
-rw-r--r--drivers/net/bonding/bond_main.c27
-rw-r--r--drivers/net/bonding/bond_sysfs.c302
-rw-r--r--drivers/net/bonding/bonding.h14
-rw-r--r--drivers/net/bsd_comp.c2
-rw-r--r--drivers/net/chelsio/common.h2
-rw-r--r--drivers/net/chelsio/cpl5_cmd.h18
-rw-r--r--drivers/net/chelsio/cxgb2.c172
-rw-r--r--drivers/net/chelsio/elmer0.h40
-rw-r--r--drivers/net/chelsio/espi.c44
-rw-r--r--drivers/net/chelsio/fpga_defs.h6
-rw-r--r--drivers/net/chelsio/gmac.h11
-rw-r--r--drivers/net/chelsio/ixf1010.c100
-rw-r--r--drivers/net/chelsio/mv88e1xxx.c27
-rw-r--r--drivers/net/chelsio/my3126.c21
-rw-r--r--drivers/net/chelsio/pm3393.c91
-rw-r--r--drivers/net/chelsio/sge.c375
-rw-r--r--drivers/net/chelsio/sge.h4
-rw-r--r--drivers/net/chelsio/subr.c89
-rw-r--r--drivers/net/chelsio/tp.c62
-rw-r--r--drivers/net/chelsio/vsc7326.c139
-rw-r--r--drivers/net/chelsio/vsc7326_reg.h139
-rw-r--r--drivers/net/chelsio/vsc8244.c41
-rw-r--r--drivers/net/cxgb3/Makefile8
-rw-r--r--drivers/net/cxgb3/adapter.h279
-rw-r--r--drivers/net/cxgb3/ael1002.c251
-rw-r--r--drivers/net/cxgb3/common.h729
-rw-r--r--drivers/net/cxgb3/cxgb3_ctl_defs.h164
-rw-r--r--drivers/net/cxgb3/cxgb3_defs.h99
-rw-r--r--drivers/net/cxgb3/cxgb3_ioctl.h185
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c2519
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c1222
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.h193
-rw-r--r--drivers/net/cxgb3/firmware_exports.h177
-rw-r--r--drivers/net/cxgb3/l2t.c450
-rw-r--r--drivers/net/cxgb3/l2t.h143
-rw-r--r--drivers/net/cxgb3/mc5.c473
-rw-r--r--drivers/net/cxgb3/regs.h2195
-rw-r--r--drivers/net/cxgb3/sge.c2681
-rw-r--r--drivers/net/cxgb3/sge_defs.h251
-rw-r--r--drivers/net/cxgb3/t3_cpl.h1444
-rw-r--r--drivers/net/cxgb3/t3_hw.c3375
-rw-r--r--drivers/net/cxgb3/t3cdev.h73
-rw-r--r--drivers/net/cxgb3/version.h39
-rw-r--r--drivers/net/cxgb3/vsc8211.c228
-rw-r--r--drivers/net/cxgb3/xgmac.c409
-rw-r--r--drivers/net/declance.c164
-rw-r--r--drivers/net/defxx.c928
-rw-r--r--drivers/net/defxx.h58
-rw-r--r--drivers/net/e100.c10
-rw-r--r--drivers/net/e1000/e1000.h7
-rw-r--r--drivers/net/e1000/e1000_ethtool.c9
-rw-r--r--drivers/net/e1000/e1000_hw.c296
-rw-r--r--drivers/net/e1000/e1000_hw.h310
-rw-r--r--drivers/net/e1000/e1000_main.c465
-rw-r--r--drivers/net/e1000/e1000_osdep.h4
-rw-r--r--drivers/net/e1000/e1000_param.c19
-rw-r--r--drivers/net/e2100.c3
-rw-r--r--drivers/net/ehea/ehea.h2
-rw-r--r--drivers/net/ehea/ehea_main.c87
-rw-r--r--drivers/net/ehea/ehea_phyp.c10
-rw-r--r--drivers/net/es3210.c2
-rw-r--r--drivers/net/forcedeth.c1469
-rw-r--r--drivers/net/fs_enet/fs_enet.h1
-rw-r--r--drivers/net/fs_enet/mac-fec.c13
-rw-r--r--drivers/net/fs_enet/mac-scc.c6
-rw-r--r--drivers/net/gianfar_ethtool.c2
-rw-r--r--drivers/net/hamradio/6pack.c9
-rw-r--r--drivers/net/hamradio/Kconfig6
-rw-r--r--drivers/net/hamradio/baycom_epp.c10
-rw-r--r--drivers/net/hamradio/bpqether.c9
-rw-r--r--drivers/net/hamradio/dmascc.c10
-rw-r--r--drivers/net/hamradio/hdlcdrv.c16
-rw-r--r--drivers/net/hamradio/mkiss.c9
-rw-r--r--drivers/net/hamradio/scc.c9
-rw-r--r--drivers/net/hamradio/yam.c9
-rw-r--r--drivers/net/hp100.c2
-rw-r--r--drivers/net/hplance.c14
-rw-r--r--drivers/net/ibm_emac/ibm_emac_phy.c4
-rw-r--r--drivers/net/ifb.c4
-rw-r--r--drivers/net/irda/donauboe.c2
-rw-r--r--drivers/net/irda/irda-usb.c47
-rw-r--r--drivers/net/irda/irda-usb.h1
-rw-r--r--drivers/net/irda/irport.c2
-rw-r--r--drivers/net/irda/irtty-sir.c4
-rw-r--r--drivers/net/irda/stir4200.c2
-rw-r--r--drivers/net/irda/vlsi_ir.c16
-rw-r--r--drivers/net/irda/vlsi_ir.h33
-rw-r--r--drivers/net/iseries_veth.c11
-rw-r--r--drivers/net/ixgb/ixgb.h3
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c7
-rw-r--r--drivers/net/ixgb/ixgb_hw.c3
-rw-r--r--drivers/net/ixgb/ixgb_main.c63
-rw-r--r--drivers/net/loopback.c4
-rw-r--r--drivers/net/lp486e.c4
-rw-r--r--drivers/net/macb.c69
-rw-r--r--drivers/net/macb.h14
-rw-r--r--drivers/net/mace.c16
-rw-r--r--drivers/net/macmace.c18
-rw-r--r--drivers/net/macsonic.c7
-rw-r--r--drivers/net/mv643xx_eth.c12
-rw-r--r--drivers/net/myri10ge/myri10ge.c684
-rw-r--r--drivers/net/netxen/netxen_nic.h179
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c123
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c342
-rw-r--r--drivers/net/netxen/netxen_nic_hw.h74
-rw-r--r--drivers/net/netxen/netxen_nic_init.c539
-rw-r--r--drivers/net/netxen/netxen_nic_ioctl.h77
-rw-r--r--drivers/net/netxen/netxen_nic_isr.c7
-rw-r--r--drivers/net/netxen/netxen_nic_main.c91
-rw-r--r--drivers/net/netxen/netxen_nic_niu.c106
-rw-r--r--drivers/net/oaknet.c666
-rw-r--r--drivers/net/pasemi_mac.c1019
-rw-r--r--drivers/net/pasemi_mac.h460
-rw-r--r--drivers/net/pcmcia/3c574_cs.c1
-rw-r--r--drivers/net/pcmcia/3c589_cs.c8
-rw-r--r--drivers/net/pcmcia/com20020_cs.c1
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c2
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c1
-rw-r--r--drivers/net/phy/fixed.c2
-rw-r--r--drivers/net/phy/phy.c3
-rw-r--r--drivers/net/phy/phy_device.c2
-rw-r--r--drivers/net/ppp_deflate.c4
-rw-r--r--drivers/net/ppp_mppe.c2
-rwxr-xr-x[-rw-r--r--]drivers/net/qla3xxx.c401
-rwxr-xr-x[-rw-r--r--]drivers/net/qla3xxx.h88
-rw-r--r--drivers/net/r8169.c10
-rw-r--r--drivers/net/s2io-regs.h7
-rw-r--r--drivers/net/s2io.c1183
-rw-r--r--drivers/net/s2io.h227
-rw-r--r--drivers/net/sc92031.c1620
-rw-r--r--drivers/net/sis190.c2
-rw-r--r--drivers/net/sk_mca.c1216
-rw-r--r--drivers/net/sk_mca.h170
-rw-r--r--drivers/net/skfp/can.c83
-rw-r--r--drivers/net/skfp/drvfbi.c24
-rw-r--r--drivers/net/skfp/fplustm.c4
-rw-r--r--drivers/net/skfp/smt.c10
-rw-r--r--drivers/net/skge.c244
-rw-r--r--drivers/net/skge.h2
-rw-r--r--drivers/net/sky2.c555
-rw-r--r--drivers/net/sky2.h85
-rw-r--r--drivers/net/slip.c11
-rw-r--r--drivers/net/smc-mca.c3
-rw-r--r--drivers/net/smc-ultra.c3
-rw-r--r--drivers/net/smc-ultra32.c3
-rw-r--r--drivers/net/smc911x.c30
-rw-r--r--drivers/net/smc91x.c2
-rw-r--r--drivers/net/smc91x.h90
-rw-r--r--drivers/net/spider_net.c317
-rw-r--r--drivers/net/spider_net.h20
-rw-r--r--drivers/net/spider_net_ethtool.c4
-rw-r--r--drivers/net/sungem.c3
-rw-r--r--drivers/net/sungem_phy.c179
-rw-r--r--drivers/net/sungem_phy.h7
-rw-r--r--drivers/net/tg3.c89
-rw-r--r--drivers/net/tg3.h5
-rw-r--r--drivers/net/ucc_geth.c126
-rw-r--r--drivers/net/ucc_geth_phy.c136
-rw-r--r--drivers/net/via-velocity.c20
-rw-r--r--drivers/net/wan/Kconfig29
-rw-r--r--drivers/net/wan/Makefile1
-rw-r--r--drivers/net/wan/cosa.c4
-rw-r--r--drivers/net/wan/hdlc.c3
-rw-r--r--drivers/net/wan/hostess_sv11.c2
-rw-r--r--drivers/net/wan/pc300_drv.c2
-rw-r--r--drivers/net/wan/pc300_tty.c2
-rw-r--r--drivers/net/wan/pc300too.c565
-rw-r--r--drivers/net/wan/x25_asy.c8
-rw-r--r--drivers/net/wan/z85230.c14
-rw-r--r--drivers/net/wd.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h7
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.c11
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c47
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.h16
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_download.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c4
-rw-r--r--drivers/net/wireless/ipw2100.c4
-rw-r--r--drivers/net/wireless/ipw2200.c4
-rw-r--r--drivers/net/wireless/netwave_cs.c1
-rw-r--r--drivers/net/wireless/orinoco.c6
-rw-r--r--drivers/net/wireless/orinoco_cs.c2
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c13
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.h4
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c3
-rw-r--r--drivers/net/wireless/ray_cs.c1
-rw-r--r--drivers/net/wireless/spectrum_cs.c2
-rw-r--r--drivers/net/wireless/strip.c2
-rw-r--r--drivers/net/wireless/wavelan_cs.c2
-rw-r--r--drivers/net/wireless/wl3501_cs.c1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c128
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h158
-rw-r--r--drivers/net/wireless/zd1211rw/zd_def.h2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.h1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c96
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_types.h71
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c132
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h6
-rw-r--r--drivers/oprofile/buffer_sync.c8
-rw-r--r--drivers/parisc/iosapic.c2
-rw-r--r--drivers/parport/Kconfig6
-rw-r--r--drivers/pci/Kconfig2
-rw-r--r--drivers/pci/hotplug/Kconfig12
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c12
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c3
-rw-r--r--drivers/pci/hotplug/cpqphp_nvram.c8
-rw-r--r--drivers/pci/hotplug/pciehp.h194
-rw-r--r--drivers/pci/hotplug/pciehp_core.c292
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c223
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c827
-rw-r--r--drivers/pci/hotplug/rpaphp_slot.c47
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c155
-rw-r--r--drivers/pci/hotplug/shpchp.h240
-rw-r--r--drivers/pci/hotplug/shpchp_core.c120
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c41
-rw-r--r--drivers/pci/hotplug/shpchp_hpc.c406
-rw-r--r--drivers/pci/htirq.c9
-rw-r--r--drivers/pci/msi.c325
-rw-r--r--drivers/pci/pci-driver.c22
-rw-r--r--drivers/pci/pci.c411
-rw-r--r--drivers/pci/pci.h14
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c2
-rw-r--r--drivers/pci/pcie/portdrv_pci.c2
-rw-r--r--drivers/pci/probe.c80
-rw-r--r--drivers/pci/proc.c8
-rw-r--r--drivers/pci/quirks.c367
-rw-r--r--drivers/pci/search.c94
-rw-r--r--drivers/pci/setup-bus.c2
-rw-r--r--drivers/pci/setup-res.c19
-rw-r--r--drivers/pcmcia/at91_cf.c2
-rw-r--r--drivers/pcmcia/cs.c34
-rw-r--r--drivers/pcmcia/cs_internal.h4
-rw-r--r--drivers/pcmcia/ds.c14
-rw-r--r--drivers/pcmcia/i82092.c2
-rw-r--r--drivers/pcmcia/i82365.c2
-rw-r--r--drivers/pcmcia/m32r_pcc.c2
-rw-r--r--drivers/pcmcia/omap_cf.c2
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c7
-rw-r--r--drivers/pcmcia/pcmcia_resource.c1
-rw-r--r--drivers/pcmcia/pd6729.c2
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c56
-rw-r--r--drivers/pcmcia/soc_common.c6
-rw-r--r--drivers/pcmcia/socket_sysfs.c104
-rw-r--r--drivers/pcmcia/tcic.c2
-rw-r--r--drivers/pcmcia/yenta_socket.c2
-rw-r--r--drivers/pnp/isapnp/core.c22
-rw-r--r--drivers/pnp/isapnp/proc.c2
-rw-r--r--drivers/pnp/pnpacpi/Kconfig4
-rw-r--r--drivers/pnp/pnpacpi/core.c6
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c22
-rw-r--r--drivers/pnp/pnpbios/core.c16
-rw-r--r--drivers/pnp/pnpbios/proc.c8
-rw-r--r--drivers/pnp/pnpbios/rsparser.c16
-rw-r--r--drivers/pnp/system.c52
-rw-r--r--drivers/ps3/Makefile2
-rw-r--r--drivers/ps3/vuart.c965
-rw-r--r--drivers/ps3/vuart.h58
-rw-r--r--drivers/rtc/Kconfig2
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/rtc-at91rm9200.c (renamed from drivers/rtc/rtc-at91.c)7
-rw-r--r--drivers/rtc/rtc-dev.c4
-rw-r--r--drivers/rtc/rtc-ds1672.c2
-rw-r--r--drivers/rtc/rtc-lib.c81
-rw-r--r--drivers/rtc/rtc-omap.c3
-rw-r--r--drivers/rtc/rtc-pcf8563.c46
-rw-r--r--drivers/rtc/rtc-proc.c4
-rw-r--r--drivers/rtc/rtc-rs5c372.c537
-rw-r--r--drivers/rtc/rtc-s3c.c6
-rw-r--r--drivers/rtc/rtc-sa1100.c4
-rw-r--r--drivers/rtc/rtc-sh.c251
-rw-r--r--drivers/rtc/rtc-sysfs.c4
-rw-r--r--drivers/rtc/rtc-x1205.c10
-rw-r--r--drivers/s390/Kconfig8
-rw-r--r--drivers/s390/Makefile2
-rw-r--r--drivers/s390/block/dasd.c41
-rw-r--r--drivers/s390/block/dasd_3990_erp.c28
-rw-r--r--drivers/s390/block/dasd_devmap.c55
-rw-r--r--drivers/s390/block/dasd_diag.c8
-rw-r--r--drivers/s390/block/dasd_eckd.c95
-rw-r--r--drivers/s390/block/dasd_eer.c24
-rw-r--r--drivers/s390/block/dasd_erp.c80
-rw-r--r--drivers/s390/block/dasd_fba.c4
-rw-r--r--drivers/s390/block/dasd_genhd.c2
-rw-r--r--drivers/s390/block/dasd_int.h5
-rw-r--r--drivers/s390/block/dasd_ioctl.c2
-rw-r--r--drivers/s390/block/dasd_proc.c8
-rw-r--r--drivers/s390/block/dcssblk.c6
-rw-r--r--drivers/s390/char/Makefile4
-rw-r--r--drivers/s390/char/con3215.c4
-rw-r--r--drivers/s390/char/con3270.c3
-rw-r--r--drivers/s390/char/ctrlchar.c9
-rw-r--r--drivers/s390/char/defkeymap.c2
-rw-r--r--drivers/s390/char/fs3270.c20
-rw-r--r--drivers/s390/char/keyboard.c4
-rw-r--r--drivers/s390/char/monreader.c218
-rw-r--r--drivers/s390/char/monwriter.c6
-rw-r--r--drivers/s390/char/raw3270.c4
-rw-r--r--drivers/s390/char/sclp.c93
-rw-r--r--drivers/s390/char/sclp.h18
-rw-r--r--drivers/s390/char/sclp_con.c2
-rw-r--r--drivers/s390/char/sclp_cpi.c6
-rw-r--r--drivers/s390/char/sclp_info.c57
-rw-r--r--drivers/s390/char/sclp_rw.c2
-rw-r--r--drivers/s390/char/sclp_tty.c4
-rw-r--r--drivers/s390/char/sclp_vt220.c4
-rw-r--r--drivers/s390/char/tape.h25
-rw-r--r--drivers/s390/char/tape_34xx.c23
-rw-r--r--drivers/s390/char/tape_3590.c486
-rw-r--r--drivers/s390/char/tape_3590.h53
-rw-r--r--drivers/s390/char/tape_block.c18
-rw-r--r--drivers/s390/char/tape_char.c35
-rw-r--r--drivers/s390/char/tape_core.c83
-rw-r--r--drivers/s390/char/tty3270.c15
-rw-r--r--drivers/s390/char/vmcp.c2
-rw-r--r--drivers/s390/char/vmlogrdr.c284
-rw-r--r--drivers/s390/cio/blacklist.c10
-rw-r--r--drivers/s390/cio/ccwgroup.c6
-rw-r--r--drivers/s390/cio/chsc.c298
-rw-r--r--drivers/s390/cio/chsc.h11
-rw-r--r--drivers/s390/cio/cio.c125
-rw-r--r--drivers/s390/cio/cio.h6
-rw-r--r--drivers/s390/cio/cmf.c4
-rw-r--r--drivers/s390/cio/css.c81
-rw-r--r--drivers/s390/cio/css.h11
-rw-r--r--drivers/s390/cio/device.c454
-rw-r--r--drivers/s390/cio/device.h8
-rw-r--r--drivers/s390/cio/device_fsm.c66
-rw-r--r--drivers/s390/cio/device_ops.c30
-rw-r--r--drivers/s390/cio/device_status.c8
-rw-r--r--drivers/s390/cio/qdio.c322
-rw-r--r--drivers/s390/cio/qdio.h28
-rw-r--r--drivers/s390/crypto/ap_bus.c35
-rw-r--r--drivers/s390/crypto/zcrypt_api.c20
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c4
-rw-r--r--drivers/s390/crypto/zcrypt_pcica.c12
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c5
-rw-r--r--drivers/s390/net/Kconfig10
-rw-r--r--drivers/s390/net/Makefile1
-rw-r--r--drivers/s390/net/claw.c16
-rw-r--r--drivers/s390/net/ctcmain.c14
-rw-r--r--drivers/s390/net/cu3088.c2
-rw-r--r--drivers/s390/net/iucv.c2540
-rw-r--r--drivers/s390/net/iucv.h849
-rw-r--r--drivers/s390/net/lcs.c6
-rw-r--r--drivers/s390/net/netiucv.c1318
-rw-r--r--drivers/s390/net/qeth.h2
-rw-r--r--drivers/s390/net/qeth_eddp.c28
-rw-r--r--drivers/s390/net/qeth_main.c309
-rw-r--r--drivers/s390/net/qeth_sys.c30
-rw-r--r--drivers/s390/net/smsgiucv.c147
-rw-r--r--drivers/s390/s390mach.c37
-rw-r--r--drivers/s390/s390mach.h3
-rw-r--r--drivers/s390/scsi/zfcp_aux.c27
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c44
-rw-r--r--drivers/s390/scsi/zfcp_erp.c7
-rw-r--r--drivers/s390/scsi/zfcp_ext.h4
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c2
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c38
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c18
-rw-r--r--drivers/s390/sysinfo.c63
-rw-r--r--drivers/sbus/char/bpp.c4
-rw-r--r--drivers/sbus/char/cpwatchdog.c2
-rw-r--r--drivers/sbus/char/display7seg.c2
-rw-r--r--drivers/sbus/char/openprom.c2
-rw-r--r--drivers/sbus/char/vfc_dev.c4
-rw-r--r--drivers/scsi/3w-xxxx.c60
-rw-r--r--drivers/scsi/3w-xxxx.h2
-rw-r--r--drivers/scsi/Kconfig4
-rw-r--r--drivers/scsi/NCR53C9x.c8
-rw-r--r--drivers/scsi/NCR53C9x.h2
-rw-r--r--drivers/scsi/aacraid/aachba.c2
-rw-r--r--drivers/scsi/aacraid/comminit.c2
-rw-r--r--drivers/scsi/aacraid/linit.c20
-rw-r--r--drivers/scsi/advansys.c3
-rw-r--r--drivers/scsi/aha1542.c2
-rw-r--r--drivers/scsi/aic7xxx_old.c2
-rw-r--r--drivers/scsi/blz1230.c3
-rw-r--r--drivers/scsi/blz2060.c2
-rw-r--r--drivers/scsi/cyberstorm.c2
-rw-r--r--drivers/scsi/cyberstormII.c2
-rw-r--r--drivers/scsi/dc395x.c2
-rw-r--r--drivers/scsi/dec_esp.c355
-rw-r--r--drivers/scsi/dpt_i2o.c10
-rw-r--r--drivers/scsi/fastlane.c2
-rw-r--r--drivers/scsi/ibmvscsi/Makefile2
-rw-r--r--drivers/scsi/initio.c2
-rw-r--r--drivers/scsi/ipr.c3
-rw-r--r--drivers/scsi/iscsi_tcp.c14
-rw-r--r--drivers/scsi/jazz_esp.c2
-rw-r--r--drivers/scsi/libiscsi.c44
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c6
-rw-r--r--drivers/scsi/mac_esp.c2
-rw-r--r--drivers/scsi/mca_53c9x.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c6
-rw-r--r--drivers/scsi/oktagon_esp.c2
-rw-r--r--drivers/scsi/osst.c10
-rw-r--r--drivers/scsi/osst.h68
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c1
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c3
-rw-r--r--drivers/scsi/pluto.c2
-rw-r--r--drivers/scsi/qla1280.c6
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c24
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c76
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c15
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c12
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c59
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h1
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h1
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c18
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c4
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c35
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c64
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h2
-rw-r--r--drivers/scsi/scsi_lib.c4
-rw-r--r--drivers/scsi/scsi_scan.c39
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c2
-rw-r--r--drivers/scsi/scsi_transport_spi.c2
-rw-r--r--drivers/scsi/sd.c22
-rw-r--r--drivers/scsi/seagate.c5
-rw-r--r--drivers/scsi/sr.c2
-rw-r--r--drivers/scsi/sr_ioctl.c2
-rw-r--r--drivers/scsi/sr_vendor.c4
-rw-r--r--drivers/scsi/st.c21
-rw-r--r--drivers/scsi/sun3_NCR5380.c10
-rw-r--r--drivers/scsi/sun3_scsi.c2
-rw-r--r--drivers/scsi/sun3_scsi.h2
-rw-r--r--drivers/scsi/sun3_scsi_vme.c2
-rw-r--r--drivers/scsi/sun3x_esp.c2
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.c2
-rw-r--r--drivers/serial/21285.c4
-rw-r--r--drivers/serial/68328serial.c2
-rw-r--r--drivers/serial/68360serial.c2
-rw-r--r--drivers/serial/8250.c6
-rw-r--r--drivers/serial/8250_pci.c24
-rw-r--r--drivers/serial/Kconfig57
-rw-r--r--drivers/serial/amba-pl010.c6
-rw-r--r--drivers/serial/amba-pl011.c6
-rw-r--r--drivers/serial/atmel_serial.c9
-rw-r--r--drivers/serial/atmel_serial.h2
-rw-r--r--drivers/serial/clps711x.c4
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c15
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.h3
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.h3
-rw-r--r--drivers/serial/crisv10.c8
-rw-r--r--drivers/serial/crisv10.h4
-rw-r--r--drivers/serial/dz.c4
-rw-r--r--drivers/serial/icom.c6
-rw-r--r--drivers/serial/imx.c4
-rw-r--r--drivers/serial/ioc3_serial.c4
-rw-r--r--drivers/serial/ioc4_serial.c6
-rw-r--r--drivers/serial/ip22zilog.c4
-rw-r--r--drivers/serial/jsm/jsm_tty.c10
-rw-r--r--drivers/serial/m32r_sio.c2
-rw-r--r--drivers/serial/mcfserial.c2
-rw-r--r--drivers/serial/mpc52xx_uart.c6
-rw-r--r--drivers/serial/mpsc.c4
-rw-r--r--drivers/serial/mux.c4
-rw-r--r--drivers/serial/netx-serial.c4
-rw-r--r--drivers/serial/pmac_zilog.c10
-rw-r--r--drivers/serial/pmac_zilog.h2
-rw-r--r--drivers/serial/pxa.c4
-rw-r--r--drivers/serial/s3c2410.c4
-rw-r--r--drivers/serial/sa1100.c4
-rw-r--r--drivers/serial/serial_core.c21
-rw-r--r--drivers/serial/serial_lh7a40x.c4
-rw-r--r--drivers/serial/serial_txx9.c4
-rw-r--r--drivers/serial/sh-sci.c26
-rw-r--r--drivers/serial/sh-sci.h19
-rw-r--r--drivers/serial/sn_console.c4
-rw-r--r--drivers/serial/sunhv.c4
-rw-r--r--drivers/serial/sunsab.c15
-rw-r--r--drivers/serial/sunsu.c14
-rw-r--r--drivers/serial/sunzilog.c18
-rw-r--r--drivers/serial/uartlite.c14
-rw-r--r--drivers/serial/v850e_uart.c4
-rw-r--r--drivers/serial/vr41xx_siu.c4
-rw-r--r--drivers/spi/pxa2xx_spi.c738
-rw-r--r--drivers/spi/spi.c23
-rw-r--r--drivers/spi/spi_mpc83xx.c2
-rw-r--r--drivers/spi/spi_s3c24xx.c30
-rw-r--r--drivers/spi/spi_s3c24xx_gpio.c3
-rw-r--r--drivers/tc/Makefile2
-rw-r--r--drivers/tc/tc-driver.c110
-rw-r--r--drivers/tc/tc.c339
-rw-r--r--drivers/tc/zs.c2
-rw-r--r--drivers/telephony/ixj.c10
-rw-r--r--drivers/usb/atm/speedtch.c2
-rw-r--r--drivers/usb/class/cdc-acm.c4
-rw-r--r--drivers/usb/class/usblp.c63
-rw-r--r--drivers/usb/core/Kconfig29
-rw-r--r--drivers/usb/core/buffer.c36
-rw-r--r--drivers/usb/core/devices.c22
-rw-r--r--drivers/usb/core/devio.c31
-rw-r--r--drivers/usb/core/driver.c39
-rw-r--r--drivers/usb/core/endpoint.c2
-rw-r--r--drivers/usb/core/file.c13
-rw-r--r--drivers/usb/core/generic.c28
-rw-r--r--drivers/usb/core/hcd.c137
-rw-r--r--drivers/usb/core/hcd.h6
-rw-r--r--drivers/usb/core/hub.c71
-rw-r--r--drivers/usb/core/inode.c4
-rw-r--r--drivers/usb/core/message.c6
-rw-r--r--drivers/usb/core/sysfs.c98
-rw-r--r--drivers/usb/core/urb.c21
-rw-r--r--drivers/usb/core/usb.c96
-rw-r--r--drivers/usb/gadget/at91_udc.c259
-rw-r--r--drivers/usb/gadget/at91_udc.h8
-rw-r--r--drivers/usb/gadget/config.c2
-rw-r--r--drivers/usb/gadget/dummy_hcd.c7
-rw-r--r--drivers/usb/gadget/epautoconf.c2
-rw-r--r--drivers/usb/gadget/ether.c148
-rw-r--r--drivers/usb/gadget/file_storage.c51
-rw-r--r--drivers/usb/gadget/gadget_chips.h8
-rw-r--r--drivers/usb/gadget/gmidi.c14
-rw-r--r--drivers/usb/gadget/goku_udc.c14
-rw-r--r--drivers/usb/gadget/inode.c240
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.c13
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.h2
-rw-r--r--drivers/usb/gadget/net2280.c13
-rw-r--r--drivers/usb/gadget/omap_udc.c260
-rw-r--r--drivers/usb/gadget/omap_udc.h3
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c9
-rw-r--r--drivers/usb/gadget/serial.c10
-rw-r--r--drivers/usb/gadget/usbstring.c2
-rw-r--r--drivers/usb/gadget/zero.c2
-rw-r--r--drivers/usb/host/Kconfig38
-rw-r--r--drivers/usb/host/ehci-dbg.c24
-rw-r--r--drivers/usb/host/ehci-fsl.c8
-rw-r--r--drivers/usb/host/ehci-hcd.c127
-rw-r--r--drivers/usb/host/ehci-hub.c324
-rw-r--r--drivers/usb/host/ehci-pci.c38
-rw-r--r--drivers/usb/host/ehci-ps3.c193
-rw-r--r--drivers/usb/host/ehci-q.c16
-rw-r--r--drivers/usb/host/ehci-sched.c22
-rw-r--r--drivers/usb/host/ehci.h46
-rw-r--r--drivers/usb/host/hc_crisv10.c2
-rw-r--r--drivers/usb/host/ohci-at91.c26
-rw-r--r--drivers/usb/host/ohci-au1xxx.c20
-rw-r--r--drivers/usb/host/ohci-dbg.c8
-rw-r--r--drivers/usb/host/ohci-ep93xx.c16
-rw-r--r--drivers/usb/host/ohci-hcd.c238
-rw-r--r--drivers/usb/host/ohci-hub.c21
-rw-r--r--drivers/usb/host/ohci-lh7a404.c24
-rw-r--r--drivers/usb/host/ohci-mem.c10
-rw-r--r--drivers/usb/host/ohci-omap.c23
-rw-r--r--drivers/usb/host/ohci-pci.c225
-rw-r--r--drivers/usb/host/ohci-pnx4008.c16
-rw-r--r--drivers/usb/host/ohci-pnx8550.c242
-rw-r--r--drivers/usb/host/ohci-ppc-of.c232
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c26
-rw-r--r--drivers/usb/host/ohci-ps3.c196
-rw-r--r--drivers/usb/host/ohci-pxa27x.c26
-rw-r--r--drivers/usb/host/ohci-q.c103
-rw-r--r--drivers/usb/host/ohci-s3c2410.c16
-rw-r--r--drivers/usb/host/ohci-sa1111.c24
-rw-r--r--drivers/usb/host/ohci.h247
-rw-r--r--drivers/usb/host/u132-hcd.c92
-rw-r--r--drivers/usb/host/uhci-debug.c71
-rw-r--r--drivers/usb/host/uhci-hcd.c84
-rw-r--r--drivers/usb/host/uhci-hcd.h8
-rw-r--r--drivers/usb/host/uhci-hub.c14
-rw-r--r--drivers/usb/host/uhci-q.c258
-rw-r--r--drivers/usb/image/mdc800.c4
-rw-r--r--drivers/usb/input/Kconfig46
-rw-r--r--drivers/usb/input/Makefile7
-rw-r--r--drivers/usb/input/gtco.c1104
-rw-r--r--drivers/usb/input/hid-core.c1497
-rw-r--r--drivers/usb/input/hid-ff.c12
-rw-r--r--drivers/usb/input/hid-lgff.c11
-rw-r--r--drivers/usb/input/hid-pidff.c58
-rw-r--r--drivers/usb/input/hid-plff.c129
-rw-r--r--drivers/usb/input/hid-tmff.c5
-rw-r--r--drivers/usb/input/hid-zpff.c7
-rw-r--r--drivers/usb/input/hiddev.c37
-rw-r--r--drivers/usb/input/usbhid.h87
-rw-r--r--drivers/usb/input/usbtouchscreen.c98
-rw-r--r--drivers/usb/input/wacom_sys.c4
-rw-r--r--drivers/usb/input/wacom_wac.c26
-rw-r--r--drivers/usb/misc/appledisplay.c2
-rw-r--r--drivers/usb/misc/auerswald.c10
-rw-r--r--drivers/usb/misc/ftdi-elan.c592
-rw-r--r--drivers/usb/misc/idmouse.c10
-rw-r--r--drivers/usb/misc/phidgetservo.c1
-rw-r--r--drivers/usb/misc/rio500.c54
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c2
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c12
-rw-r--r--drivers/usb/misc/trancevibrator.c2
-rw-r--r--drivers/usb/misc/uss720.c2
-rw-r--r--drivers/usb/mon/Makefile2
-rw-r--r--drivers/usb/mon/mon_bin.c1172
-rw-r--r--drivers/usb/mon/mon_dma.c39
-rw-r--r--drivers/usb/mon/mon_main.c97
-rw-r--r--drivers/usb/mon/mon_text.c67
-rw-r--r--drivers/usb/mon/usb_mon.h30
-rw-r--r--drivers/usb/net/Kconfig6
-rw-r--r--drivers/usb/net/asix.c22
-rw-r--r--drivers/usb/net/cdc_ether.c60
-rw-r--r--drivers/usb/net/gl620a.c180
-rw-r--r--drivers/usb/net/kaweth.c37
-rw-r--r--drivers/usb/net/pegasus.h4
-rw-r--r--drivers/usb/net/rndis_host.c106
-rw-r--r--drivers/usb/net/rtl8150.c9
-rw-r--r--drivers/usb/serial/aircable.c21
-rw-r--r--drivers/usb/serial/airprime.c4
-rw-r--r--drivers/usb/serial/ark3116.c6
-rw-r--r--drivers/usb/serial/belkin_sa.c5
-rw-r--r--drivers/usb/serial/bus.c45
-rw-r--r--drivers/usb/serial/console.c2
-rw-r--r--drivers/usb/serial/cp2101.c14
-rw-r--r--drivers/usb/serial/cyberjack.c3
-rw-r--r--drivers/usb/serial/cypress_m8.c30
-rw-r--r--drivers/usb/serial/digi_acceleport.c12
-rw-r--r--drivers/usb/serial/empeg.c5
-rw-r--r--drivers/usb/serial/ftdi_sio.c7
-rw-r--r--drivers/usb/serial/ftdi_sio.h6
-rw-r--r--drivers/usb/serial/funsoft.c28
-rw-r--r--drivers/usb/serial/garmin_gps.c1
-rw-r--r--drivers/usb/serial/generic.c35
-rw-r--r--drivers/usb/serial/hp4x.c1
-rw-r--r--drivers/usb/serial/io_edgeport.c425
-rw-r--r--drivers/usb/serial/io_edgeport.h6
-rw-r--r--drivers/usb/serial/io_tables.h61
-rw-r--r--drivers/usb/serial/io_ti.c10
-rw-r--r--drivers/usb/serial/io_usbvend.h5
-rw-r--r--drivers/usb/serial/ipaq.c3
-rw-r--r--drivers/usb/serial/ipw.c1
-rw-r--r--drivers/usb/serial/ir-usb.c5
-rw-r--r--drivers/usb/serial/keyspan.c51
-rw-r--r--drivers/usb/serial/keyspan.h9
-rw-r--r--drivers/usb/serial/keyspan_pda.c5
-rw-r--r--drivers/usb/serial/kl5kusb105.c75
-rw-r--r--drivers/usb/serial/kobil_sct.c15
-rw-r--r--drivers/usb/serial/mct_u232.c5
-rw-r--r--drivers/usb/serial/mos7720.c20
-rw-r--r--drivers/usb/serial/mos7840.c26
-rw-r--r--drivers/usb/serial/navman.c1
-rw-r--r--drivers/usb/serial/omninet.c1
-rw-r--r--drivers/usb/serial/option.c14
-rw-r--r--drivers/usb/serial/pl2303.c7
-rw-r--r--drivers/usb/serial/safe_serial.c1
-rw-r--r--drivers/usb/serial/sierra.c31
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c8
-rw-r--r--drivers/usb/serial/usb-serial.c104
-rw-r--r--drivers/usb/serial/visor.c10
-rw-r--r--drivers/usb/serial/visor.h1
-rw-r--r--drivers/usb/serial/whiteheat.c12
-rw-r--r--drivers/usb/storage/onetouch.c1
-rw-r--r--drivers/usb/storage/scsiglue.c31
-rw-r--r--drivers/usb/storage/sddr09.c2
-rw-r--r--drivers/usb/storage/unusual_devs.h61
-rw-r--r--drivers/usb/storage/usb.c23
-rw-r--r--drivers/video/Kconfig22
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/S3triofb.c7
-rw-r--r--drivers/video/amba-clcd.c2
-rw-r--r--drivers/video/amifb.c16
-rw-r--r--drivers/video/arcfb.c2
-rw-r--r--drivers/video/atafb.c13
-rw-r--r--drivers/video/aty/aty128fb.c7
-rw-r--r--drivers/video/aty/atyfb.h9
-rw-r--r--drivers/video/aty/atyfb_base.c199
-rw-r--r--drivers/video/aty/mach64_ct.c47
-rw-r--r--drivers/video/aty/radeon_backlight.c2
-rw-r--r--drivers/video/aty/radeon_i2c.c8
-rw-r--r--drivers/video/aty/radeon_monitor.c3
-rw-r--r--drivers/video/au1100fb.h2
-rw-r--r--drivers/video/backlight/backlight.c102
-rw-r--r--drivers/video/backlight/corgi_bl.c6
-rw-r--r--drivers/video/backlight/hp680_bl.c6
-rw-r--r--drivers/video/backlight/lcd.c80
-rw-r--r--drivers/video/backlight/locomolcd.c6
-rw-r--r--drivers/video/bw2.c18
-rw-r--r--drivers/video/cfbimgblt.c8
-rw-r--r--drivers/video/cg14.c28
-rw-r--r--drivers/video/cg3.c22
-rw-r--r--drivers/video/cg6.c33
-rw-r--r--drivers/video/cirrusfb.c15
-rw-r--r--drivers/video/console/softcursor.c26
-rw-r--r--drivers/video/console/sticon.c2
-rw-r--r--drivers/video/console/vgacon.c30
-rw-r--r--drivers/video/cyberfb.c4
-rw-r--r--drivers/video/epson1355fb.c4
-rw-r--r--drivers/video/fbcmap.c55
-rw-r--r--drivers/video/fbcvt.c2
-rw-r--r--drivers/video/fbmem.c22
-rw-r--r--drivers/video/fbmon.c2
-rw-r--r--drivers/video/ffb.c21
-rw-r--r--drivers/video/fm2fb.c1
-rw-r--r--drivers/video/geode/Kconfig20
-rw-r--r--drivers/video/geode/display_gx.c23
-rw-r--r--drivers/video/geode/display_gx.h7
-rw-r--r--drivers/video/geode/gxfb_core.c53
-rw-r--r--drivers/video/geode/video_gx.c107
-rw-r--r--drivers/video/geode/video_gx.h25
-rw-r--r--drivers/video/gxt4500.c774
-rw-r--r--drivers/video/hpfb.c2
-rw-r--r--drivers/video/i810/i810-i2c.c10
-rw-r--r--drivers/video/igafb.c6
-rw-r--r--drivers/video/intelfb/intelfb_i2c.c4
-rw-r--r--drivers/video/intelfb/intelfbdrv.c3
-rw-r--r--drivers/video/leo.c29
-rw-r--r--drivers/video/macfb.c20
-rw-r--r--drivers/video/matrox/i2c-matroxfb.c4
-rw-r--r--drivers/video/matrox/matroxfb_base.c2
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c2
-rw-r--r--drivers/video/mbx/mbxdebugfs.c188
-rw-r--r--drivers/video/mbx/mbxfb.c359
-rw-r--r--drivers/video/mbx/reg_bits.h114
-rw-r--r--drivers/video/mbx/regs.h2
-rw-r--r--drivers/video/modedb.c6
-rw-r--r--drivers/video/neofb.c2
-rw-r--r--drivers/video/nvidia/nv_accel.c35
-rw-r--r--drivers/video/nvidia/nv_backlight.c2
-rw-r--r--drivers/video/nvidia/nv_i2c.c13
-rw-r--r--drivers/video/nvidia/nv_local.h11
-rw-r--r--drivers/video/nvidia/nv_of.c3
-rw-r--r--drivers/video/nvidia/nv_proto.h1
-rw-r--r--drivers/video/offb.c3
-rw-r--r--drivers/video/output.c129
-rw-r--r--drivers/video/p9100.c25
-rw-r--r--drivers/video/platinumfb.c3
-rw-r--r--drivers/video/pmag-ba-fb.c95
-rw-r--r--drivers/video/pmagb-b-fb.c100
-rw-r--r--drivers/video/pvr2fb.c18
-rw-r--r--drivers/video/pxafb.c40
-rw-r--r--drivers/video/retz3fb.c4
-rw-r--r--drivers/video/riva/fbdev.c68
-rw-r--r--drivers/video/riva/riva_hw.c10
-rw-r--r--drivers/video/riva/riva_hw.h17
-rw-r--r--drivers/video/riva/rivafb-i2c.c6
-rw-r--r--drivers/video/s3c2410fb.c213
-rw-r--r--drivers/video/sa1100fb.c6
-rw-r--r--drivers/video/savage/savagefb-i2c.c9
-rw-r--r--drivers/video/sis/init301.c7
-rw-r--r--drivers/video/sstfb.c335
-rw-r--r--drivers/video/stifb.c3
-rw-r--r--drivers/video/tcx.c33
-rw-r--r--drivers/video/tgafb.c58
-rw-r--r--drivers/video/tridentfb.c22
-rw-r--r--drivers/video/vesafb.c24
-rw-r--r--drivers/video/vga16fb.c28
-rw-r--r--drivers/video/virgefb.c17
-rw-r--r--drivers/w1/slaves/Kconfig4
-rw-r--r--drivers/zorro/proc.c2
-rw-r--r--fs/9p/error.c1
-rw-r--r--fs/9p/fid.c69
-rw-r--r--fs/9p/fid.h5
-rw-r--r--fs/9p/mux.c4
-rw-r--r--fs/9p/v9fs.c11
-rw-r--r--fs/9p/vfs_addr.c2
-rw-r--r--fs/9p/vfs_dir.c4
-rw-r--r--fs/9p/vfs_file.c53
-rw-r--r--fs/9p/vfs_inode.c205
-rw-r--r--fs/Kconfig20
-rw-r--r--fs/Makefile3
-rw-r--r--fs/adfs/dir.c2
-rw-r--r--fs/adfs/dir_f.c2
-rw-r--r--fs/affs/dir.c4
-rw-r--r--fs/afs/dir.c4
-rw-r--r--fs/afs/mntpt.c10
-rw-r--r--fs/aio.c29
-rw-r--r--fs/autofs/root.c4
-rw-r--r--fs/autofs4/autofs_i.h3
-rw-r--r--fs/autofs4/inode.c2
-rw-r--r--fs/autofs4/root.c16
-rw-r--r--fs/bad_inode.c330
-rw-r--r--fs/befs/btree.c2
-rw-r--r--fs/befs/debug.c6
-rw-r--r--fs/befs/linuxvfs.c4
-rw-r--r--fs/bfs/dir.c2
-rw-r--r--fs/bfs/inode.c4
-rw-r--r--fs/binfmt_aout.c8
-rw-r--r--fs/binfmt_elf.c65
-rw-r--r--fs/binfmt_elf_fdpic.c19
-rw-r--r--fs/binfmt_flat.c33
-rw-r--r--fs/binfmt_misc.c12
-rw-r--r--fs/bio.c2
-rw-r--r--fs/block_dev.c403
-rw-r--r--fs/buffer.c60
-rw-r--r--fs/cifs/CHANGES9
-rw-r--r--fs/cifs/cifs_debug.c4
-rw-r--r--fs/cifs/cifsencrypt.c4
-rw-r--r--fs/cifs/cifsfs.c12
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifspdu.h8
-rw-r--r--fs/cifs/cifssmb.c2
-rw-r--r--fs/cifs/fcntl.c4
-rw-r--r--fs/cifs/file.c154
-rw-r--r--fs/cifs/misc.c8
-rw-r--r--fs/cifs/readdir.c38
-rw-r--r--fs/cifs/sess.c13
-rw-r--r--fs/cifs/smbdes.c10
-rw-r--r--fs/coda/dir.c8
-rw-r--r--fs/coda/file.c14
-rw-r--r--fs/coda/inode.c2
-rw-r--r--fs/compat.c22
-rw-r--r--fs/compat_ioctl.c2
-rw-r--r--fs/configfs/dir.c10
-rw-r--r--fs/configfs/file.c21
-rw-r--r--fs/cramfs/inode.c2
-rw-r--r--fs/debugfs/inode.c39
-rw-r--r--fs/direct-io.c323
-rw-r--r--fs/dlm/Kconfig18
-rw-r--r--fs/dlm/config.c154
-rw-r--r--fs/dlm/config.h17
-rw-r--r--fs/dlm/dlm_internal.h20
-rw-r--r--fs/dlm/lock.c87
-rw-r--r--fs/dlm/lockspace.c10
-rw-r--r--fs/dlm/lowcomms-sctp.c151
-rw-r--r--fs/dlm/lowcomms-tcp.c386
-rw-r--r--fs/dlm/midcomms.c4
-rw-r--r--fs/dlm/rcom.c85
-rw-r--r--fs/dlm/recover.c8
-rw-r--r--fs/dlm/recoverd.c22
-rw-r--r--fs/dlm/user.c9
-rw-r--r--fs/dlm/util.c4
-rw-r--r--fs/dnotify.c4
-rw-r--r--fs/dquot.c18
-rw-r--r--fs/ecryptfs/crypto.c4
-rw-r--r--fs/ecryptfs/dentry.c3
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h17
-rw-r--r--fs/ecryptfs/file.c15
-rw-r--r--fs/ecryptfs/inode.c79
-rw-r--r--fs/ecryptfs/main.c5
-rw-r--r--fs/ecryptfs/mmap.c16
-rw-r--r--fs/efs/dir.c2
-rw-r--r--fs/eventpoll.c4
-rw-r--r--fs/exec.c17
-rw-r--r--fs/ext2/dir.c2
-rw-r--r--fs/ext2/ioctl.c2
-rw-r--r--fs/ext2/super.c6
-rw-r--r--fs/ext3/dir.c8
-rw-r--r--fs/ext3/file.c2
-rw-r--r--fs/ext3/ioctl.c2
-rw-r--r--fs/ext3/namei.c4
-rw-r--r--fs/ext3/super.c6
-rw-r--r--fs/ext4/dir.c8
-rw-r--r--fs/ext4/file.c2
-rw-r--r--fs/ext4/inode.c2
-rw-r--r--fs/ext4/ioctl.c2
-rw-r--r--fs/ext4/namei.c4
-rw-r--r--fs/fat/dir.c6
-rw-r--r--fs/fat/file.c2
-rw-r--r--fs/fcntl.c7
-rw-r--r--fs/file.c255
-rw-r--r--fs/file_table.c10
-rw-r--r--fs/freevxfs/vxfs_lookup.c2
-rw-r--r--fs/fs-writeback.c13
-rw-r--r--fs/fuse/control.c6
-rw-r--r--fs/fuse/dir.c2
-rw-r--r--fs/fuse/file.c22
-rw-r--r--fs/gfs2/Kconfig49
-rw-r--r--fs/gfs2/bmap.c10
-rw-r--r--fs/gfs2/dir.c25
-rw-r--r--fs/gfs2/dir.h21
-rw-r--r--fs/gfs2/eattr.c8
-rw-r--r--fs/gfs2/glock.c316
-rw-r--r--fs/gfs2/glock.h11
-rw-r--r--fs/gfs2/glops.c136
-rw-r--r--fs/gfs2/incore.h18
-rw-r--r--fs/gfs2/inode.c61
-rw-r--r--fs/gfs2/lm.c8
-rw-r--r--fs/gfs2/locking/dlm/lock_dlm.h2
-rw-r--r--fs/gfs2/locking/dlm/main.c6
-rw-r--r--fs/gfs2/locking/dlm/mount.c6
-rw-r--r--fs/gfs2/locking/dlm/sysfs.c13
-rw-r--r--fs/gfs2/lops.c14
-rw-r--r--fs/gfs2/ops_address.c134
-rw-r--r--fs/gfs2/ops_dentry.c16
-rw-r--r--fs/gfs2/ops_export.c15
-rw-r--r--fs/gfs2/ops_file.c58
-rw-r--r--fs/gfs2/ops_fstype.c4
-rw-r--r--fs/gfs2/ops_inode.c55
-rw-r--r--fs/gfs2/ops_super.c11
-rw-r--r--fs/gfs2/ops_vm.c24
-rw-r--r--fs/gfs2/super.c16
-rw-r--r--fs/gfs2/sys.c10
-rw-r--r--fs/hfs/dir.c2
-rw-r--r--fs/hfs/inode.c2
-rw-r--r--fs/hfsplus/dir.c2
-rw-r--r--fs/hfsplus/inode.c2
-rw-r--r--fs/hostfs/hostfs.h2
-rw-r--r--fs/hostfs/hostfs_kern.c8
-rw-r--r--fs/hostfs/hostfs_user.c4
-rw-r--r--fs/hpfs/dir.c4
-rw-r--r--fs/hpfs/file.c2
-rw-r--r--fs/hppfs/hppfs_kern.c12
-rw-r--r--fs/hugetlbfs/inode.c13
-rw-r--r--fs/inode.c45
-rw-r--r--fs/inotify_user.c6
-rw-r--r--fs/ioctl.c14
-rw-r--r--fs/isofs/compress.c2
-rw-r--r--fs/isofs/dir.c5
-rw-r--r--fs/jbd/commit.c8
-rw-r--r--fs/jbd/transaction.c2
-rw-r--r--fs/jffs/inode-v23.c10
-rw-r--r--fs/jffs/intrep.c14
-rw-r--r--fs/jffs/jffs_fm.c3
-rw-r--r--fs/jffs2/debug.c4
-rw-r--r--fs/jffs2/debug.h1
-rw-r--r--fs/jffs2/dir.c6
-rw-r--r--fs/jffs2/fs.c3
-rw-r--r--fs/jffs2/gc.c2
-rw-r--r--fs/jffs2/nodelist.h10
-rw-r--r--fs/jffs2/readinode.c3
-rw-r--r--fs/jffs2/scan.c6
-rw-r--r--fs/jffs2/summary.c6
-rw-r--r--fs/jffs2/super.c7
-rw-r--r--fs/jffs2/symlink.c2
-rw-r--r--fs/jffs2/wbuf.c21
-rw-r--r--fs/jffs2/xattr.c5
-rw-r--r--fs/jfs/inode.c6
-rw-r--r--fs/jfs/jfs_debug.h5
-rw-r--r--fs/jfs/jfs_dmap.c16
-rw-r--r--fs/jfs/jfs_dtree.c6
-rw-r--r--fs/jfs/jfs_filsys.h42
-rw-r--r--fs/jfs/jfs_imap.c18
-rw-r--r--fs/jfs/jfs_incore.h29
-rw-r--r--fs/jfs/jfs_lock.h2
-rw-r--r--fs/jfs/jfs_metapage.c17
-rw-r--r--fs/jfs/jfs_txnmgr.c2
-rw-r--r--fs/jfs/jfs_xtree.c15
-rw-r--r--fs/jfs/namei.c48
-rw-r--r--fs/libfs.c14
-rw-r--r--fs/lockd/clntlock.c16
-rw-r--r--fs/lockd/clntproc.c41
-rw-r--r--fs/lockd/svclock.c20
-rw-r--r--fs/lockd/svcshare.c2
-rw-r--r--fs/lockd/svcsubs.c2
-rw-r--r--fs/lockd/xdr.c8
-rw-r--r--fs/lockd/xdr4.c8
-rw-r--r--fs/locks.c32
-rw-r--r--fs/minix/dir.c2
-rw-r--r--fs/namei.c15
-rw-r--r--fs/namespace.c118
-rw-r--r--fs/ncpfs/dir.c8
-rw-r--r--fs/ncpfs/file.c4
-rw-r--r--fs/ncpfs/inode.c38
-rw-r--r--fs/ncpfs/ioctl.c8
-rw-r--r--fs/ncpfs/mmap.c4
-rw-r--r--fs/nfs/dir.c20
-rw-r--r--fs/nfs/direct.c10
-rw-r--r--fs/nfs/file.c35
-rw-r--r--fs/nfs/getroot.c2
-rw-r--r--fs/nfs/idmap.c2
-rw-r--r--fs/nfs/inode.c103
-rw-r--r--fs/nfs/nfs3proc.c2
-rw-r--r--fs/nfs/nfs4proc.c2
-rw-r--r--fs/nfs/proc.c2
-rw-r--r--fs/nfs/symlink.c4
-rw-r--r--fs/nfs/write.c4
-rw-r--r--fs/nfsd/export.c34
-rw-r--r--fs/nfsd/lockd.c2
-rw-r--r--fs/nfsd/nfs2acl.c8
-rw-r--r--fs/nfsd/nfs3acl.c8
-rw-r--r--fs/nfsd/nfs3xdr.c9
-rw-r--r--fs/nfsd/nfs4proc.c625
-rw-r--r--fs/nfsd/nfs4recover.c2
-rw-r--r--fs/nfsd/nfs4state.c99
-rw-r--r--fs/nfsd/nfs4xdr.c19
-rw-r--r--fs/nfsd/nfscache.c3
-rw-r--r--fs/nfsd/nfsctl.c2
-rw-r--r--fs/nfsd/nfsfh.c20
-rw-r--r--fs/nfsd/nfssvc.c8
-rw-r--r--fs/nfsd/nfsxdr.c5
-rw-r--r--fs/nfsd/vfs.c84
-rw-r--r--fs/ntfs/ChangeLog7
-rw-r--r--fs/ntfs/Makefile2
-rw-r--r--fs/ntfs/aops.c4
-rw-r--r--fs/ntfs/dir.c51
-rw-r--r--fs/ntfs/file.c2
-rw-r--r--fs/ntfs/inode.c69
-rw-r--r--fs/ntfs/inode.h6
-rw-r--r--fs/ntfs/super.c7
-rw-r--r--fs/ocfs2/alloc.c2
-rw-r--r--fs/ocfs2/aops.c28
-rw-r--r--fs/ocfs2/cluster/heartbeat.c179
-rw-r--r--fs/ocfs2/cluster/nodemanager.c198
-rw-r--r--fs/ocfs2/cluster/nodemanager.h17
-rw-r--r--fs/ocfs2/cluster/tcp.c197
-rw-r--r--fs/ocfs2/cluster/tcp.h14
-rw-r--r--fs/ocfs2/cluster/tcp_internal.h25
-rw-r--r--fs/ocfs2/dir.c2
-rw-r--r--fs/ocfs2/dlm/dlmast.c14
-rw-r--r--fs/ocfs2/dlm/dlmcommon.h130
-rw-r--r--fs/ocfs2/dlm/dlmconvert.c40
-rw-r--r--fs/ocfs2/dlm/dlmdebug.c30
-rw-r--r--fs/ocfs2/dlm/dlmdomain.c257
-rw-r--r--fs/ocfs2/dlm/dlmfs.c4
-rw-r--r--fs/ocfs2/dlm/dlmlock.c11
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c581
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c188
-rw-r--r--fs/ocfs2/dlm/dlmthread.c200
-rw-r--r--fs/ocfs2/dlm/dlmunlock.c15
-rw-r--r--fs/ocfs2/dlmglue.c89
-rw-r--r--fs/ocfs2/export.c5
-rw-r--r--fs/ocfs2/file.c55
-rw-r--r--fs/ocfs2/heartbeat.c9
-rw-r--r--fs/ocfs2/inode.c14
-rw-r--r--fs/ocfs2/journal.c46
-rw-r--r--fs/ocfs2/journal.h9
-rw-r--r--fs/ocfs2/localalloc.c2
-rw-r--r--fs/ocfs2/mmap.c6
-rw-r--r--fs/ocfs2/namei.c77
-rw-r--r--fs/ocfs2/ocfs2.h5
-rw-r--r--fs/ocfs2/ocfs2_fs.h57
-rw-r--r--fs/ocfs2/slot_map.c2
-rw-r--r--fs/ocfs2/suballoc.c6
-rw-r--r--fs/ocfs2/super.c96
-rw-r--r--fs/ocfs2/symlink.c3
-rw-r--r--fs/ocfs2/vote.c15
-rw-r--r--fs/open.c30
-rw-r--r--fs/openpromfs/inode.c2
-rw-r--r--fs/partitions/Kconfig2
-rw-r--r--fs/partitions/check.c27
-rw-r--r--fs/pipe.c43
-rw-r--r--fs/pnode.c2
-rw-r--r--fs/pnode.h2
-rw-r--r--fs/proc/array.c18
-rw-r--r--fs/proc/base.c175
-rw-r--r--fs/proc/generic.c10
-rw-r--r--fs/proc/nommu.c4
-rw-r--r--fs/proc/proc_misc.c11
-rw-r--r--fs/proc/task_mmu.c8
-rw-r--r--fs/proc/task_nommu.c4
-rw-r--r--fs/qnx4/dir.c2
-rw-r--r--fs/ramfs/file-mmu.c4
-rw-r--r--fs/ramfs/file-nommu.c6
-rw-r--r--fs/read_write.c22
-rw-r--r--fs/readdir.c2
-rw-r--r--fs/reiserfs/bitmap.c2
-rw-r--r--fs/reiserfs/dir.c4
-rw-r--r--fs/reiserfs/file.c24
-rw-r--r--fs/reiserfs/fix_node.c6
-rw-r--r--fs/reiserfs/inode.c14
-rw-r--r--fs/reiserfs/ioctl.c2
-rw-r--r--fs/reiserfs/namei.c6
-rw-r--r--fs/reiserfs/procfs.c2
-rw-r--r--fs/reiserfs/stree.c44
-rw-r--r--fs/reiserfs/super.c2
-rw-r--r--fs/reiserfs/tail_conversion.c4
-rw-r--r--fs/reiserfs/xattr.c10
-rw-r--r--fs/reiserfs/xattr_acl.c2
-rw-r--r--fs/romfs/inode.c2
-rw-r--r--fs/select.c10
-rw-r--r--fs/seq_file.c2
-rw-r--r--fs/smbfs/cache.c2
-rw-r--r--fs/smbfs/dir.c6
-rw-r--r--fs/smbfs/file.c14
-rw-r--r--fs/smbfs/inode.c5
-rw-r--r--fs/smbfs/proc.c16
-rw-r--r--fs/smbfs/smbiod.c5
-rw-r--r--fs/smbfs/sock.c4
-rw-r--r--fs/splice.c26
-rw-r--r--fs/stack.c38
-rw-r--r--fs/stat.c2
-rw-r--r--fs/super.c6
-rw-r--r--fs/sync.c4
-rw-r--r--fs/sysfs/bin.c20
-rw-r--r--fs/sysfs/dir.c224
-rw-r--r--fs/sysfs/file.c98
-rw-r--r--fs/sysfs/group.c2
-rw-r--r--fs/sysfs/inode.c36
-rw-r--r--fs/sysfs/mount.c11
-rw-r--r--fs/sysfs/symlink.c1
-rw-r--r--fs/sysfs/sysfs.h21
-rw-r--r--fs/sysv/dir.c2
-rw-r--r--fs/sysv/super.c3
-rw-r--r--fs/sysv/sysv.h3
-rw-r--r--fs/udf/dir.c4
-rw-r--r--fs/udf/file.c2
-rw-r--r--fs/ufs/balloc.c67
-rw-r--r--fs/ufs/dir.c23
-rw-r--r--fs/ufs/inode.c53
-rw-r--r--fs/ufs/super.c5
-rw-r--r--fs/ufs/truncate.c4
-rw-r--r--fs/xattr.c8
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c6
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c28
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c10
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.c2
-rw-r--r--fs/xfs/xfs_dfrag.c4
-rw-r--r--include/acpi/acconfig.h15
-rw-r--r--include/acpi/acdebug.h8
-rw-r--r--include/acpi/acdisasm.h22
-rw-r--r--include/acpi/acdispat.h4
-rw-r--r--include/acpi/acevents.h2
-rw-r--r--include/acpi/acexcep.h10
-rw-r--r--include/acpi/acglobal.h117
-rw-r--r--include/acpi/achware.h6
-rw-r--r--include/acpi/acinterp.h14
-rw-r--r--include/acpi/aclocal.h77
-rw-r--r--include/acpi/acmacros.h71
-rw-r--r--include/acpi/acnames.h2
-rw-r--r--include/acpi/acnamesp.h21
-rw-r--r--include/acpi/acobject.h19
-rw-r--r--include/acpi/acopcode.h4
-rw-r--r--include/acpi/acoutput.h2
-rw-r--r--include/acpi/acparser.h2
-rw-r--r--include/acpi/acpi.h2
-rw-r--r--include/acpi/acpi_bus.h23
-rw-r--r--include/acpi/acpi_drivers.h15
-rw-r--r--include/acpi/acpiosxf.h8
-rw-r--r--include/acpi/acpixf.h35
-rw-r--r--include/acpi/acresrc.h2
-rw-r--r--include/acpi/acstruct.h5
-rw-r--r--include/acpi/actables.h106
-rw-r--r--include/acpi/actbl.h333
-rw-r--r--include/acpi/actbl1.h568
-rw-r--r--include/acpi/actbl2.h49
-rw-r--r--include/acpi/actbl71.h134
-rw-r--r--include/acpi/actypes.h106
-rw-r--r--include/acpi/acutils.h8
-rw-r--r--include/acpi/amlcode.h4
-rw-r--r--include/acpi/amlresrc.h2
-rw-r--r--include/acpi/platform/acenv.h2
-rw-r--r--include/acpi/platform/acgcc.h2
-rw-r--r--include/acpi/platform/aclinux.h2
-rw-r--r--include/asm-alpha/cacheflush.h1
-rw-r--r--include/asm-alpha/dma-mapping.h20
-rw-r--r--include/asm-alpha/io.h9
-rw-r--r--include/asm-alpha/pci.h2
-rw-r--r--include/asm-alpha/posix_types.h2
-rw-r--r--include/asm-alpha/termbits.h13
-rw-r--r--include/asm-alpha/unistd.h11
-rw-r--r--include/asm-arm/apm.h64
-rw-r--r--include/asm-arm/arch-at91rm9200/at91_ecc.h8
-rw-r--r--include/asm-arm/arch-at91rm9200/at91_pmc.h2
-rw-r--r--include/asm-arm/arch-at91rm9200/at91_rstc.h2
-rw-r--r--include/asm-arm/arch-at91rm9200/at91_rtc.h16
-rw-r--r--include/asm-arm/arch-at91rm9200/at91rm9200.h2
-rw-r--r--include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h2
-rw-r--r--include/asm-arm/arch-at91rm9200/at91sam9261_matrix.h6
-rw-r--r--include/asm-arm/arch-at91rm9200/at91sam926x_mc.h16
-rw-r--r--include/asm-arm/arch-ep93xx/irqs.h6
-rw-r--r--include/asm-arm/arch-imx/imx-regs.h10
-rw-r--r--include/asm-arm/arch-iop13xx/io.h3
-rw-r--r--include/asm-arm/arch-iop13xx/iq81340.h5
-rw-r--r--include/asm-arm/arch-iop32x/iop32x.h2
-rw-r--r--include/asm-arm/arch-ixp23xx/memory.h16
-rw-r--r--include/asm-arm/arch-ixp4xx/io.h3
-rw-r--r--include/asm-arm/arch-pnx4008/i2c.h67
-rw-r--r--include/asm-arm/arch-pxa/pxa-regs.h3
-rw-r--r--include/asm-arm/arch-pxa/pxa2xx_spi.h5
-rw-r--r--include/asm-arm/arch-s3c2410/anubis-cpld.h2
-rw-r--r--include/asm-arm/arch-s3c2410/anubis-irq.h2
-rw-r--r--include/asm-arm/arch-s3c2410/anubis-map.h2
-rw-r--r--include/asm-arm/arch-s3c2410/audio.h2
-rw-r--r--include/asm-arm/arch-s3c2410/bast-cpld.h4
-rw-r--r--include/asm-arm/arch-s3c2410/bast-irq.h4
-rw-r--r--include/asm-arm/arch-s3c2410/bast-map.h4
-rw-r--r--include/asm-arm/arch-s3c2410/bast-pmu.h2
-rw-r--r--include/asm-arm/arch-s3c2410/dma.h2
-rw-r--r--include/asm-arm/arch-s3c2410/entry-macro.S2
-rw-r--r--include/asm-arm/arch-s3c2410/fb.h3
-rw-r--r--include/asm-arm/arch-s3c2410/h1940-latch.h4
-rw-r--r--include/asm-arm/arch-s3c2410/hardware.h8
-rw-r--r--include/asm-arm/arch-s3c2410/iic.h2
-rw-r--r--include/asm-arm/arch-s3c2410/irqs.h3
-rw-r--r--include/asm-arm/arch-s3c2410/leds-gpio.h2
-rw-r--r--include/asm-arm/arch-s3c2410/map.h30
-rw-r--r--include/asm-arm/arch-s3c2410/nand.h4
-rw-r--r--include/asm-arm/arch-s3c2410/osiris-cpld.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-gpio.h4
-rw-r--r--include/asm-arm/arch-s3c2410/regs-mem.h14
-rw-r--r--include/asm-arm/arch-s3c2410/regs-serial.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-udc.h7
-rw-r--r--include/asm-arm/arch-s3c2410/system.h4
-rw-r--r--include/asm-arm/arch-s3c2410/timex.h4
-rw-r--r--include/asm-arm/arch-s3c2410/uncompress.h5
-rw-r--r--include/asm-arm/arch-s3c2410/usb-control.h4
-rw-r--r--include/asm-arm/arch-s3c2410/vr1000-cpld.h4
-rw-r--r--include/asm-arm/arch-s3c2410/vr1000-irq.h4
-rw-r--r--include/asm-arm/arch-s3c2410/vr1000-map.h4
-rw-r--r--include/asm-arm/cacheflush.h14
-rw-r--r--include/asm-arm/cpu-multi32.h7
-rw-r--r--include/asm-arm/cpu-single.h4
-rw-r--r--include/asm-arm/elf.h1
-rw-r--r--include/asm-arm/flat.h4
-rw-r--r--include/asm-arm/fpstate.h3
-rw-r--r--include/asm-arm/hardware/iop3xx.h6
-rw-r--r--include/asm-arm/io.h5
-rw-r--r--include/asm-arm/irq.h5
-rw-r--r--include/asm-arm/pgtable.h11
-rw-r--r--include/asm-arm/processor.h16
-rw-r--r--include/asm-arm/system.h52
-rw-r--r--include/asm-arm/termbits.h12
-rw-r--r--include/asm-arm/thread_info.h2
-rw-r--r--include/asm-arm/unistd.h25
-rw-r--r--include/asm-arm26/cacheflush.h1
-rw-r--r--include/asm-arm26/termbits.h12
-rw-r--r--include/asm-avr32/arch-at32ap/at32ap7000.h35
-rw-r--r--include/asm-avr32/arch-at32ap/board.h3
-rw-r--r--include/asm-avr32/arch-at32ap/gpio.h27
-rw-r--r--include/asm-avr32/arch-at32ap/irq.h14
-rw-r--r--include/asm-avr32/arch-at32ap/portmux.h22
-rw-r--r--include/asm-avr32/cacheflush.h1
-rw-r--r--include/asm-avr32/checksum.h2
-rw-r--r--include/asm-avr32/dma-mapping.h20
-rw-r--r--include/asm-avr32/gpio.h6
-rw-r--r--include/asm-avr32/irq.h8
-rw-r--r--include/asm-avr32/pgalloc.h2
-rw-r--r--include/asm-avr32/posix_types.h2
-rw-r--r--include/asm-avr32/termbits.h11
-rw-r--r--include/asm-avr32/uaccess.h6
-rw-r--r--include/asm-cris/cacheflush.h1
-rw-r--r--include/asm-cris/io.h5
-rw-r--r--include/asm-cris/termbits.h11
-rw-r--r--include/asm-frv/Kbuild6
-rw-r--r--include/asm-frv/bitops.h44
-rw-r--r--include/asm-frv/cacheflush.h1
-rw-r--r--include/asm-frv/page.h4
-rw-r--r--include/asm-frv/ptrace.h4
-rw-r--r--include/asm-frv/termbits.h11
-rw-r--r--include/asm-frv/termios.h2
-rw-r--r--include/asm-frv/thread_info.h2
-rw-r--r--include/asm-generic/bug.h18
-rw-r--r--include/asm-generic/libata-portmap.h4
-rw-r--r--include/asm-generic/page.h38
-rw-r--r--include/asm-generic/termios.h4
-rw-r--r--include/asm-generic/vmlinux.lds.h34
-rw-r--r--include/asm-h8300/cacheflush.h1
-rw-r--r--include/asm-h8300/termbits.h11
-rw-r--r--include/asm-i386/acpi.h50
-rw-r--r--include/asm-i386/boot.h3
-rw-r--r--include/asm-i386/bug.h28
-rw-r--r--include/asm-i386/cacheflush.h1
-rw-r--r--include/asm-i386/e820.h2
-rw-r--r--include/asm-i386/elf.h51
-rw-r--r--include/asm-i386/fixmap.h2
-rw-r--r--include/asm-i386/ide.h4
-rw-r--r--include/asm-i386/io.h6
-rw-r--r--include/asm-i386/mach-es7000/mach_mpparse.h17
-rw-r--r--include/asm-i386/msr.h5
-rw-r--r--include/asm-i386/page.h2
-rw-r--r--include/asm-i386/processor.h1
-rw-r--r--include/asm-i386/termbits.h11
-rw-r--r--include/asm-i386/thread_info.h2
-rw-r--r--include/asm-i386/topology.h1
-rw-r--r--include/asm-i386/unwind.h91
-rw-r--r--include/asm-ia64/acpi.h10
-rw-r--r--include/asm-ia64/break.h4
-rw-r--r--include/asm-ia64/cacheflush.h1
-rw-r--r--include/asm-ia64/checksum.h6
-rw-r--r--include/asm-ia64/dma.h2
-rw-r--r--include/asm-ia64/esi.h1
-rw-r--r--include/asm-ia64/kprobes.h1
-rw-r--r--include/asm-ia64/machvec.h3
-rw-r--r--include/asm-ia64/meminit.h3
-rw-r--r--include/asm-ia64/pci.h9
-rw-r--r--include/asm-ia64/pgalloc.h3
-rw-r--r--include/asm-ia64/posix_types.h2
-rw-r--r--include/asm-ia64/scatterlist.h3
-rw-r--r--include/asm-ia64/sn/acpi.h3
-rw-r--r--include/asm-ia64/sn/pcibr_provider.h2
-rw-r--r--include/asm-ia64/sn/pcidev.h8
-rw-r--r--include/asm-ia64/sn/xpc.h2
-rw-r--r--include/asm-ia64/swiotlb.h9
-rw-r--r--include/asm-ia64/termbits.h11
-rw-r--r--include/asm-ia64/thread_info.h6
-rw-r--r--include/asm-ia64/topology.h1
-rw-r--r--include/asm-ia64/unistd.h4
-rw-r--r--include/asm-m32r/cacheflush.h3
-rw-r--r--include/asm-m32r/ide.h3
-rw-r--r--include/asm-m32r/m32102.h7
-rw-r--r--include/asm-m32r/ptrace.h28
-rw-r--r--include/asm-m32r/sigcontext.h13
-rw-r--r--include/asm-m32r/termbits.h11
-rw-r--r--include/asm-m68k/cacheflush.h2
-rw-r--r--include/asm-m68k/sun3-head.h1
-rw-r--r--include/asm-m68k/sun3ints.h1
-rw-r--r--include/asm-m68k/swim_iop.h221
-rw-r--r--include/asm-m68k/termbits.h11
-rw-r--r--include/asm-m68k/uaccess.h1
-rw-r--r--include/asm-m68knommu/bitops.h1
-rw-r--r--include/asm-m68knommu/cacheflush.h1
-rw-r--r--include/asm-mips/bootinfo.h5
-rw-r--r--include/asm-mips/cacheflush.h2
-rw-r--r--include/asm-mips/checksum.h34
-rw-r--r--include/asm-mips/compat.h1
-rw-r--r--include/asm-mips/ddb5xxx/ddb5477.h41
-rw-r--r--include/asm-mips/dec/interrupts.h3
-rw-r--r--include/asm-mips/dec/system.h3
-rw-r--r--include/asm-mips/dec/tc.h41
-rw-r--r--include/asm-mips/dec/tcinfo.h47
-rw-r--r--include/asm-mips/dec/tcmodule.h39
-rw-r--r--include/asm-mips/dma.h1
-rw-r--r--include/asm-mips/emma2rh/emma2rh.h5
-rw-r--r--include/asm-mips/emma2rh/markeins.h1
-rw-r--r--include/asm-mips/hazards.h2
-rw-r--r--include/asm-mips/i8259.h3
-rw-r--r--include/asm-mips/io.h10
-rw-r--r--include/asm-mips/irq.h8
-rw-r--r--include/asm-mips/irq_cpu.h6
-rw-r--r--include/asm-mips/irqflags.h22
-rw-r--r--include/asm-mips/mach-au1x00/au1000.h1
-rw-r--r--include/asm-mips/mach-cobalt/cobalt.h4
-rw-r--r--include/asm-mips/mach-emma2rh/irq.h2
-rw-r--r--include/asm-mips/mach-generic/irq.h32
-rw-r--r--include/asm-mips/mach-ip27/irq.h2
-rw-r--r--include/asm-mips/mach-ip27/topology.h1
-rw-r--r--include/asm-mips/mach-mips/irq.h2
-rw-r--r--include/asm-mips/mach-rm/cpu-feature-overrides.h (renamed from include/asm-mips/mach-rm200/cpu-feature-overrides.h)0
-rw-r--r--include/asm-mips/mach-rm/mc146818rtc.h (renamed from include/asm-mips/mach-rm200/mc146818rtc.h)0
-rw-r--r--include/asm-mips/mach-rm/timex.h (renamed from include/asm-mips/mach-rm200/timex.h)0
-rw-r--r--include/asm-mips/mach-vr41xx/irq.h11
-rw-r--r--include/asm-mips/mips-boards/atlasint.h4
-rw-r--r--include/asm-mips/mips-boards/maltaint.h4
-rw-r--r--include/asm-mips/mips-boards/prom.h1
-rw-r--r--include/asm-mips/mips-boards/seadint.h4
-rw-r--r--include/asm-mips/mips-boards/simint.h3
-rw-r--r--include/asm-mips/mipsmtregs.h2
-rw-r--r--include/asm-mips/page.h41
-rw-r--r--include/asm-mips/pci.h6
-rw-r--r--include/asm-mips/pgtable.h10
-rw-r--r--include/asm-mips/ptrace.h8
-rw-r--r--include/asm-mips/rtlx.h3
-rw-r--r--include/asm-mips/sections.h2
-rw-r--r--include/asm-mips/sgi/ip22.h13
-rw-r--r--include/asm-mips/smtc_ipi.h3
-rw-r--r--include/asm-mips/sn/arch.h1
-rw-r--r--include/asm-mips/sn/klconfig.h2
-rw-r--r--include/asm-mips/system.h9
-rw-r--r--include/asm-mips/termbits.h11
-rw-r--r--include/asm-mips/thread_info.h2
-rw-r--r--include/asm-mips/uaccess.h3
-rw-r--r--include/asm-mips/vr41xx/cmbvr4133.h5
-rw-r--r--include/asm-mips/war.h2
-rw-r--r--include/asm-parisc/cacheflush.h4
-rw-r--r--include/asm-parisc/io.h9
-rw-r--r--include/asm-parisc/termbits.h11
-rw-r--r--include/asm-powerpc/Kbuild2
-rw-r--r--include/asm-powerpc/atomic.h8
-rw-r--r--include/asm-powerpc/bitops.h21
-rw-r--r--include/asm-powerpc/bug.h105
-rw-r--r--include/asm-powerpc/cacheflush.h1
-rw-r--r--include/asm-powerpc/cputable.h27
-rw-r--r--include/asm-powerpc/dcr-native.h37
-rw-r--r--include/asm-powerpc/dcr.h3
-rw-r--r--include/asm-powerpc/dma-mapping.h12
-rw-r--r--include/asm-powerpc/elf.h2
-rw-r--r--include/asm-powerpc/firmware.h10
-rw-r--r--include/asm-powerpc/fs_pd.h49
-rw-r--r--include/asm-powerpc/hvcall.h3
-rw-r--r--include/asm-powerpc/hw_irq.h19
-rw-r--r--include/asm-powerpc/io.h6
-rw-r--r--include/asm-powerpc/iommu.h1
-rw-r--r--include/asm-powerpc/ipic.h2
-rw-r--r--include/asm-powerpc/irq.h3
-rw-r--r--include/asm-powerpc/kprobes.h7
-rw-r--r--include/asm-powerpc/libata-portmap.h12
-rw-r--r--include/asm-powerpc/mmu.h1
-rw-r--r--include/asm-powerpc/module.h2
-rw-r--r--include/asm-powerpc/mpc52xx.h3
-rw-r--r--include/asm-powerpc/mpc8260.h24
-rw-r--r--include/asm-powerpc/mpc8xx.h28
-rw-r--r--include/asm-powerpc/mpic.h24
-rw-r--r--include/asm-powerpc/oprofile_impl.h89
-rw-r--r--include/asm-powerpc/page_32.h10
-rw-r--r--include/asm-powerpc/pci-bridge.h6
-rw-r--r--include/asm-powerpc/pci.h33
-rw-r--r--include/asm-powerpc/posix_types.h2
-rw-r--r--include/asm-powerpc/ps3.h225
-rw-r--r--include/asm-powerpc/reg.h16
-rw-r--r--include/asm-powerpc/rtas.h3
-rw-r--r--include/asm-powerpc/smp.h1
-rw-r--r--include/asm-powerpc/spu.h15
-rw-r--r--include/asm-powerpc/spu_priv1.h2
-rw-r--r--include/asm-powerpc/sstep.h1
-rw-r--r--include/asm-powerpc/termbits.h13
-rw-r--r--include/asm-powerpc/thread_info.h2
-rw-r--r--include/asm-powerpc/time.h2
-rw-r--r--include/asm-powerpc/topology.h1
-rw-r--r--include/asm-powerpc/udbg.h2
-rw-r--r--include/asm-ppc/commproc.h1
-rw-r--r--include/asm-ppc/ibm4xx.h1
-rw-r--r--include/asm-ppc/io.h2
-rw-r--r--include/asm-ppc/m48t35.h77
-rw-r--r--include/asm-ppc/pci-bridge.h8
-rw-r--r--include/asm-ppc/pci.h23
-rw-r--r--include/asm-ppc/reg_booke.h34
-rw-r--r--include/asm-ppc/serial.h2
-rw-r--r--include/asm-s390/cacheflush.h1
-rw-r--r--include/asm-s390/compat.h28
-rw-r--r--include/asm-s390/dasd.h2
-rw-r--r--include/asm-s390/etr.h219
-rw-r--r--include/asm-s390/futex.h4
-rw-r--r--include/asm-s390/hardirq.h2
-rw-r--r--include/asm-s390/io.h4
-rw-r--r--include/asm-s390/kdebug.h3
-rw-r--r--include/asm-s390/lowcore.h6
-rw-r--r--include/asm-s390/mmu_context.h50
-rw-r--r--include/asm-s390/page.h22
-rw-r--r--include/asm-s390/pgalloc.h88
-rw-r--r--include/asm-s390/pgtable.h163
-rw-r--r--include/asm-s390/posix_types.h2
-rw-r--r--include/asm-s390/processor.h27
-rw-r--r--include/asm-s390/ptrace.h11
-rw-r--r--include/asm-s390/qdio.h1
-rw-r--r--include/asm-s390/reset.h2
-rw-r--r--include/asm-s390/sclp.h39
-rw-r--r--include/asm-s390/sections.h2
-rw-r--r--include/asm-s390/setup.h23
-rw-r--r--include/asm-s390/sfp-util.h (renamed from arch/s390/math-emu/sfp-util.h)6
-rw-r--r--include/asm-s390/smp.h6
-rw-r--r--include/asm-s390/system.h4
-rw-r--r--include/asm-s390/tape390.h72
-rw-r--r--include/asm-s390/termbits.h11
-rw-r--r--include/asm-s390/timer.h3
-rw-r--r--include/asm-s390/timex.h50
-rw-r--r--include/asm-s390/tlbflush.h9
-rw-r--r--include/asm-s390/uaccess.h2
-rw-r--r--include/asm-sh/apm.h46
-rw-r--r--include/asm-sh/atomic-irq.h71
-rw-r--r--include/asm-sh/atomic-llsc.h107
-rw-r--r--include/asm-sh/atomic.h153
-rw-r--r--include/asm-sh/bug.h53
-rw-r--r--include/asm-sh/bugs.h12
-rw-r--r--include/asm-sh/checksum.h69
-rw-r--r--include/asm-sh/cpu-sh2/cacheflush.h2
-rw-r--r--include/asm-sh/cpu-sh3/cacheflush.h3
-rw-r--r--include/asm-sh/cpu-sh4/cache.h2
-rw-r--r--include/asm-sh/cpu-sh4/cacheflush.h1
-rw-r--r--include/asm-sh/cpu-sh4/freq.h2
-rw-r--r--include/asm-sh/dma-mapping.h10
-rw-r--r--include/asm-sh/irq.h5
-rw-r--r--include/asm-sh/pgtable.h47
-rw-r--r--include/asm-sh/processor.h8
-rw-r--r--include/asm-sh/push-switch.h3
-rw-r--r--include/asm-sh/termbits.h11
-rw-r--r--include/asm-sh/thread_info.h2
-rw-r--r--include/asm-sh64/cacheflush.h2
-rw-r--r--include/asm-sh64/pgalloc.h2
-rw-r--r--include/asm-sparc/bitops.h100
-rw-r--r--include/asm-sparc/cacheflush.h1
-rw-r--r--include/asm-sparc/checksum.h2
-rw-r--r--include/asm-sparc/of_device.h2
-rw-r--r--include/asm-sparc/termbits.h12
-rw-r--r--include/asm-sparc64/cacheflush.h1
-rw-r--r--include/asm-sparc64/dma.h6
-rw-r--r--include/asm-sparc64/hw_irq.h2
-rw-r--r--include/asm-sparc64/irqflags.h89
-rw-r--r--include/asm-sparc64/kprobes.h11
-rw-r--r--include/asm-sparc64/of_device.h2
-rw-r--r--include/asm-sparc64/percpu.h10
-rw-r--r--include/asm-sparc64/rwsem.h32
-rw-r--r--include/asm-sparc64/system.h49
-rw-r--r--include/asm-sparc64/termbits.h12
-rw-r--r--include/asm-sparc64/ttable.h45
-rw-r--r--include/asm-um/bug.h4
-rw-r--r--include/asm-um/pgtable.h9
-rw-r--r--include/asm-v850/cacheflush.h1
-rw-r--r--include/asm-v850/termbits.h11
-rw-r--r--include/asm-x86_64/acpi.h50
-rw-r--r--include/asm-x86_64/bitops.h34
-rw-r--r--include/asm-x86_64/bug.h44
-rw-r--r--include/asm-x86_64/cacheflush.h1
-rw-r--r--include/asm-x86_64/dma-mapping.h3
-rw-r--r--include/asm-x86_64/io.h6
-rw-r--r--include/asm-x86_64/ioctls.h4
-rw-r--r--include/asm-x86_64/msr.h4
-rw-r--r--include/asm-x86_64/proto.h1
-rw-r--r--include/asm-x86_64/swiotlb.h8
-rw-r--r--include/asm-x86_64/termbits.h27
-rw-r--r--include/asm-x86_64/termios.h6
-rw-r--r--include/asm-x86_64/thread_info.h2
-rw-r--r--include/asm-x86_64/topology.h1
-rw-r--r--include/asm-x86_64/uaccess.h2
-rw-r--r--include/asm-x86_64/unwind.h96
-rw-r--r--include/asm-xtensa/asmmacro.h153
-rw-r--r--include/asm-xtensa/bug.h25
-rw-r--r--include/asm-xtensa/byteorder.h5
-rw-r--r--include/asm-xtensa/cache.h20
-rw-r--r--include/asm-xtensa/cacheasm.h177
-rw-r--r--include/asm-xtensa/cacheflush.h4
-rw-r--r--include/asm-xtensa/checksum.h2
-rw-r--r--include/asm-xtensa/coprocessor.h13
-rw-r--r--include/asm-xtensa/dma.h5
-rw-r--r--include/asm-xtensa/elf.h9
-rw-r--r--include/asm-xtensa/fcntl.h98
-rw-r--r--include/asm-xtensa/fixmap.h252
-rw-r--r--include/asm-xtensa/io.h64
-rw-r--r--include/asm-xtensa/irq.h8
-rw-r--r--include/asm-xtensa/irq_regs.h1
-rw-r--r--include/asm-xtensa/mmu_context.h269
-rw-r--r--include/asm-xtensa/page.h10
-rw-r--r--include/asm-xtensa/param.h2
-rw-r--r--include/asm-xtensa/pgtable.h41
-rw-r--r--include/asm-xtensa/platform-iss/hardware.h10
-rw-r--r--include/asm-xtensa/platform-iss/simcall.h62
-rw-r--r--include/asm-xtensa/posix_types.h4
-rw-r--r--include/asm-xtensa/processor.h24
-rw-r--r--include/asm-xtensa/ptrace.h2
-rw-r--r--include/asm-xtensa/regs.h138
-rw-r--r--include/asm-xtensa/sembuf.h2
-rw-r--r--include/asm-xtensa/shmbuf.h21
-rw-r--r--include/asm-xtensa/stat.h112
-rw-r--r--include/asm-xtensa/syscall.h20
-rw-r--r--include/asm-xtensa/system.h2
-rw-r--r--include/asm-xtensa/termbits.h11
-rw-r--r--include/asm-xtensa/timex.h17
-rw-r--r--include/asm-xtensa/tlbflush.h42
-rw-r--r--include/asm-xtensa/uaccess.h1
-rw-r--r--include/asm-xtensa/unistd.h798
-rw-r--r--include/asm-xtensa/variant-fsf/core.h359
-rw-r--r--include/asm-xtensa/variant-fsf/tie.h22
-rw-r--r--include/asm-xtensa/xtensa/cacheasm.h708
-rw-r--r--include/asm-xtensa/xtensa/cacheattrasm.h432
-rw-r--r--include/asm-xtensa/xtensa/config-linux_be/core.h1270
-rw-r--r--include/asm-xtensa/xtensa/config-linux_be/defs.h270
-rw-r--r--include/asm-xtensa/xtensa/config-linux_be/specreg.h99
-rw-r--r--include/asm-xtensa/xtensa/config-linux_be/system.h198
-rw-r--r--include/asm-xtensa/xtensa/config-linux_be/tie.h275
-rw-r--r--include/asm-xtensa/xtensa/coreasm.h526
-rw-r--r--include/asm-xtensa/xtensa/corebits.h77
-rw-r--r--include/asm-xtensa/xtensa/hal.h822
-rw-r--r--include/asm-xtensa/xtensa/simcall.h130
-rw-r--r--include/asm-xtensa/xtensa/xt2000-uart.h155
-rw-r--r--include/asm-xtensa/xtensa/xt2000.h408
-rw-r--r--include/asm-xtensa/xtensa/xtboard.h120
-rw-r--r--include/crypto/algapi.h24
-rw-r--r--include/linux/Kbuild12
-rw-r--r--include/linux/acpi.h340
-rw-r--r--include/linux/aio.h1
-rw-r--r--include/linux/apm-emulation.h (renamed from include/asm-mips/apm.h)8
-rw-r--r--include/linux/ata.h13
-rw-r--r--include/linux/atmarp.h2
-rw-r--r--include/linux/backlight.h2
-rw-r--r--include/linux/bio.h1
-rw-r--r--include/linux/bitops.h6
-rw-r--r--include/linux/bitrev.h15
-rw-r--r--include/linux/blkdev.h19
-rw-r--r--include/linux/bug.h47
-rw-r--r--include/linux/cdev.h4
-rw-r--r--include/linux/clocksource.h2
-rw-r--r--include/linux/coda_linux.h2
-rw-r--r--include/linux/compiler.h2
-rw-r--r--include/linux/configfs.h25
-rw-r--r--include/linux/connector.h2
-rw-r--r--include/linux/cpufreq.h3
-rw-r--r--include/linux/cpuset.h24
-rw-r--r--include/linux/crc32.h4
-rw-r--r--include/linux/crypto.h148
-rw-r--r--include/linux/dccp.h26
-rw-r--r--include/linux/debug_locks.h2
-rw-r--r--include/linux/device-mapper.h7
-rw-r--r--include/linux/device.h52
-rw-r--r--include/linux/dm-ioctl.h9
-rw-r--r--include/linux/dma-mapping.h29
-rw-r--r--include/linux/dmapool.h7
-rw-r--r--include/linux/efi.h2
-rw-r--r--include/linux/eisa.h10
-rw-r--r--include/linux/elevator.h3
-rw-r--r--include/linux/fault-inject.h84
-rw-r--r--include/linux/fb.h8
-rw-r--r--include/linux/file.h20
-rw-r--r--include/linux/freezer.h13
-rw-r--r--include/linux/fs.h31
-rw-r--r--include/linux/fs_stack.h31
-rw-r--r--include/linux/fsl_devices.h1
-rw-r--r--include/linux/fsnotify.h2
-rw-r--r--include/linux/futex.h2
-rw-r--r--include/linux/gameport.h2
-rw-r--r--include/linux/generic_serial.h2
-rw-r--r--include/linux/genhd.h4
-rw-r--r--include/linux/gfp.h2
-rw-r--r--include/linux/hdreg.h8
-rw-r--r--include/linux/hid-debug.h45
-rw-r--r--include/linux/hid.h (renamed from drivers/usb/input/hid.h)99
-rw-r--r--include/linux/highmem.h9
-rw-r--r--include/linux/i2c-algo-bit.h5
-rw-r--r--include/linux/i2c-algo-ite.h72
-rw-r--r--include/linux/i2c-algo-pca.h1
-rw-r--r--include/linux/i2c-algo-pcf.h3
-rw-r--r--include/linux/i2c-algo-sgi.h1
-rw-r--r--include/linux/i2c-id.h22
-rw-r--r--include/linux/i2c-pnx.h43
-rw-r--r--include/linux/i2c.h75
-rw-r--r--include/linux/i2o-dev.h5
-rw-r--r--include/linux/ide.h32
-rw-r--r--include/linux/if_addr.h6
-rw-r--r--include/linux/if_fddi.h2
-rw-r--r--include/linux/if_link.h6
-rw-r--r--include/linux/if_packet.h10
-rw-r--r--include/linux/if_tunnel.h2
-rw-r--r--include/linux/init.h1
-rw-r--r--include/linux/init_task.h17
-rw-r--r--include/linux/input.h15
-rw-r--r--include/linux/interrupt.h9
-rw-r--r--include/linux/io.h21
-rw-r--r--include/linux/ioport.h23
-rw-r--r--include/linux/irq.h4
-rw-r--r--include/linux/isdn.h8
-rw-r--r--include/linux/istallion.h36
-rw-r--r--include/linux/kernel.h16
-rw-r--r--include/linux/kobject.h15
-rw-r--r--include/linux/kvm.h240
-rw-r--r--include/linux/libata.h141
-rw-r--r--include/linux/list.h10
-rw-r--r--include/linux/lockd/bind.h2
-rw-r--r--include/linux/lockd/lockd.h4
-rw-r--r--include/linux/lockd/sm_inter.h2
-rw-r--r--include/linux/lockd/xdr.h8
-rw-r--r--include/linux/lockdep.h16
-rw-r--r--include/linux/log2.h168
-rw-r--r--include/linux/magic.h1
-rw-r--r--include/linux/mm.h7
-rw-r--r--include/linux/mmc/card.h3
-rw-r--r--include/linux/mmc/host.h10
-rw-r--r--include/linux/mmc/mmc.h3
-rw-r--r--include/linux/mmc/protocol.h13
-rw-r--r--include/linux/mmzone.h8
-rw-r--r--include/linux/mnt_namespace.h42
-rw-r--r--include/linux/module.h10
-rw-r--r--include/linux/mount.h5
-rw-r--r--include/linux/msi.h5
-rw-r--r--include/linux/mtd/blktrans.h3
-rw-r--r--include/linux/mtd/mtd.h24
-rw-r--r--include/linux/mtd/nand.h15
-rw-r--r--include/linux/mtd/onenand.h8
-rw-r--r--include/linux/mtd/onenand_regs.h1
-rw-r--r--include/linux/mtio.h146
-rw-r--r--include/linux/mutex.h4
-rw-r--r--include/linux/n_r3964.h2
-rw-r--r--include/linux/namei.h5
-rw-r--r--include/linux/namespace.h42
-rw-r--r--include/linux/ncp_mount.h2
-rw-r--r--include/linux/net.h4
-rw-r--r--include/linux/netdevice.h19
-rw-r--r--include/linux/netfilter/Kbuild1
-rw-r--r--include/linux/netfilter/nf_conntrack_sane.h21
-rw-r--r--include/linux/netfilter/nf_conntrack_tcp.h6
-rw-r--r--include/linux/netfilter/xt_TCPMSS.h10
-rw-r--r--include/linux/netfilter_arp/arp_tables.h1
-rw-r--r--include/linux/netfilter_bridge.h1
-rw-r--r--include/linux/netfilter_ipv4.h2
-rw-r--r--include/linux/netfilter_ipv4/ip_nat.h1
-rw-r--r--include/linux/netfilter_ipv4/ip_tables.h24
-rw-r--r--include/linux/netfilter_ipv4/ipt_TCPMSS.h7
-rw-r--r--include/linux/netfilter_ipv6.h2
-rw-r--r--include/linux/netfilter_ipv6/ip6_tables.h35
-rw-r--r--include/linux/netfilter_ipv6/ip6t_mh.h15
-rw-r--r--include/linux/nfs_fs.h1
-rw-r--r--include/linux/nfsd/nfsd.h8
-rw-r--r--include/linux/nfsd/nfsfh.h15
-rw-r--r--include/linux/nfsd/state.h1
-rw-r--r--include/linux/nfsd/xdr.h4
-rw-r--r--include/linux/nfsd/xdr3.h8
-rw-r--r--include/linux/nfsd/xdr4.h40
-rw-r--r--include/linux/nsproxy.h6
-rw-r--r--include/linux/page-flags.h8
-rw-r--r--include/linux/pagemap.h2
-rw-r--r--include/linux/pci.h65
-rw-r--r--include/linux/pci_ids.h29
-rw-r--r--include/linux/pci_regs.h19
-rw-r--r--include/linux/pfkeyv2.h4
-rw-r--r--include/linux/pid.h5
-rw-r--r--include/linux/pid_namespace.h45
-rw-r--r--include/linux/pipe_fs_i.h5
-rw-r--r--include/linux/pktcdvd.h25
-rw-r--r--include/linux/platform_device.h2
-rw-r--r--include/linux/profile.h1
-rw-r--r--include/linux/pspace.h23
-rw-r--r--include/linux/qic117.h290
-rw-r--r--include/linux/raid/bitmap.h1
-rw-r--r--include/linux/raid/md.h2
-rw-r--r--include/linux/raid/raid5.h3
-rw-r--r--include/linux/reciprocal_div.h32
-rw-r--r--include/linux/reiserfs_fs.h44
-rw-r--r--include/linux/reiserfs_fs_i.h2
-rw-r--r--include/linux/rmap.h2
-rw-r--r--include/linux/rtc.h1
-rw-r--r--include/linux/rtmutex.h4
-rw-r--r--include/linux/rtnetlink.h2
-rw-r--r--include/linux/sched.h31
-rw-r--r--include/linux/sctp.h10
-rw-r--r--include/linux/seqlock.h7
-rw-r--r--include/linux/serial_core.h8
-rw-r--r--include/linux/serio.h5
-rw-r--r--include/linux/slab.h306
-rw-r--r--include/linux/slab_def.h100
-rw-r--r--include/linux/smb_fs_sb.h2
-rw-r--r--include/linux/socket.h4
-rw-r--r--include/linux/spi/spi.h2
-rw-r--r--include/linux/stallion.h52
-rw-r--r--include/linux/sunrpc/sched.h1
-rw-r--r--include/linux/sunrpc/svc.h5
-rw-r--r--include/linux/sunrpc/svcsock.h2
-rw-r--r--include/linux/swap.h2
-rw-r--r--include/linux/sysctl.h10
-rw-r--r--include/linux/sysdev.h12
-rw-r--r--include/linux/sysfs.h24
-rw-r--r--include/linux/sysrq.h22
-rw-r--r--include/linux/task_io_accounting.h37
-rw-r--r--include/linux/task_io_accounting_ops.h47
-rw-r--r--include/linux/taskstats.h28
-rw-r--r--include/linux/tc.h141
-rw-r--r--include/linux/tcp.h2
-rw-r--r--include/linux/tfrc.h8
-rw-r--r--include/linux/tifm.h35
-rw-r--r--include/linux/timer.h10
-rw-r--r--include/linux/topology.h5
-rw-r--r--include/linux/tty.h20
-rw-r--r--include/linux/tty_driver.h12
-rw-r--r--include/linux/tty_ldisc.h4
-rw-r--r--include/linux/ufs_fs.h1
-rw-r--r--include/linux/unwind.h63
-rw-r--r--include/linux/usb.h39
-rw-r--r--include/linux/usb/Kbuild5
-rw-r--r--include/linux/usb/ch9.h (renamed from include/linux/usb_ch9.h)1
-rw-r--r--include/linux/usb/serial.h7
-rw-r--r--include/linux/usb_gadgetfs.h2
-rw-r--r--include/linux/video_output.h42
-rw-r--r--include/linux/videodev2.h10
-rw-r--r--include/linux/vmstat.h11
-rw-r--r--include/linux/wanrouter.h8
-rw-r--r--include/linux/workqueue.h36
-rw-r--r--include/linux/xfrm.h21
-rw-r--r--include/media/cx2341x.h2
-rw-r--r--include/media/ir-common.h2
-rw-r--r--include/media/saa7146.h20
-rw-r--r--include/media/tuner-types.h4
-rw-r--r--include/media/tuner.h1
-rw-r--r--include/media/tveeprom.h2
-rw-r--r--include/media/v4l2-common.h7
-rw-r--r--include/media/v4l2-dev.h14
-rw-r--r--include/net/ax25.h48
-rw-r--r--include/net/bluetooth/hci.h4
-rw-r--r--include/net/ieee80211.h2
-rw-r--r--include/net/inet6_connection_sock.h2
-rw-r--r--include/net/inet_connection_sock.h3
-rw-r--r--include/net/inet_hashtables.h10
-rw-r--r--include/net/ip.h5
-rw-r--r--include/net/ip6_checksum.h2
-rw-r--r--include/net/ip6_fib.h4
-rw-r--r--include/net/irda/ircomm_tty.h2
-rw-r--r--include/net/iucv/af_iucv.h106
-rw-r--r--include/net/iucv/iucv.h415
-rw-r--r--include/net/neighbour.h18
-rw-r--r--include/net/netfilter/nf_conntrack.h2
-rw-r--r--include/net/netfilter/nf_conntrack_compat.h11
-rw-r--r--include/net/netfilter/nf_nat.h1
-rw-r--r--include/net/rose.h6
-rw-r--r--include/net/route.h5
-rw-r--r--include/net/sctp/sctp.h4
-rw-r--r--include/net/sctp/sm.h1
-rw-r--r--include/net/sctp/structs.h18
-rw-r--r--include/net/sctp/ulpevent.h2
-rw-r--r--include/net/sctp/user.h30
-rw-r--r--include/net/tcp.h12
-rw-r--r--include/net/x25.h19
-rw-r--r--include/net/xfrm.h47
-rw-r--r--include/pcmcia/ss.h2
-rw-r--r--include/rdma/ib_marshall.h5
-rw-r--r--include/rdma/ib_user_mad.h2
-rw-r--r--include/rdma/ib_verbs.h271
-rw-r--r--include/rdma/rdma_cm.h62
-rw-r--r--include/rdma/rdma_cm_ib.h3
-rw-r--r--include/rdma/rdma_user_cm.h206
-rw-r--r--include/scsi/iscsi_proto.h46
-rw-r--r--include/sound/ac97_codec.h4
-rw-r--r--include/sound/ad1848.h2
-rw-r--r--include/sound/ak4114.h3
-rw-r--r--include/sound/ak4117.h2
-rw-r--r--include/sound/ak4xxx-adda.h6
-rw-r--r--include/sound/control.h5
-rw-r--r--include/sound/core.h80
-rw-r--r--include/sound/emu10k1.h418
-rw-r--r--include/sound/pcm.h4
-rw-r--r--include/sound/pcm_oss.h1
-rw-r--r--include/sound/pt2258.h37
-rw-r--r--include/sound/sb16_csp.h14
-rw-r--r--include/sound/snd_wavefront.h2
-rw-r--r--include/sound/soc-dapm.h286
-rw-r--r--include/sound/soc.h461
-rw-r--r--include/sound/typedefs.h173
-rw-r--r--include/sound/version.h4
-rw-r--r--include/sound/vx_core.h2
-rw-r--r--include/sound/ymfpci.h11
-rw-r--r--include/video/mbxfb.h31
-rw-r--r--include/video/pm3fb.h24
-rw-r--r--include/video/sstfb.h13
-rw-r--r--init/Kconfig21
-rw-r--r--init/initramfs.c6
-rw-r--r--init/main.c21
-rw-r--r--init/version.c6
-rw-r--r--ipc/mqueue.c16
-rw-r--r--ipc/msgutil.c4
-rw-r--r--ipc/shm.c18
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/acct.c26
-rw-r--r--kernel/auditfilter.c4
-rw-r--r--kernel/auditsc.c6
-rw-r--r--kernel/cpu.c8
-rw-r--r--kernel/cpuset.c106
-rw-r--r--kernel/exit.c104
-rw-r--r--kernel/fork.c85
-rw-r--r--kernel/futex.c10
-rw-r--r--kernel/irq/chip.c33
-rw-r--r--kernel/irq/manage.c89
-rw-r--r--kernel/irq/proc.c3
-rw-r--r--kernel/irq/spurious.c2
-rw-r--r--kernel/kallsyms.c16
-rw-r--r--kernel/kmod.c2
-rw-r--r--kernel/kprobes.c20
-rw-r--r--kernel/lockdep.c207
-rw-r--r--kernel/module.c127
-rw-r--r--kernel/mutex.c9
-rw-r--r--kernel/nsproxy.c38
-rw-r--r--kernel/params.c34
-rw-r--r--kernel/pid.c75
-rw-r--r--kernel/power/Kconfig35
-rw-r--r--kernel/power/disk.c8
-rw-r--r--kernel/power/main.c2
-rw-r--r--kernel/power/process.c21
-rw-r--r--kernel/power/swap.c9
-rw-r--r--kernel/power/user.c7
-rw-r--r--kernel/printk.c2
-rw-r--r--kernel/profile.c17
-rw-r--r--kernel/rcutorture.c3
-rw-r--r--kernel/relay.c25
-rw-r--r--kernel/resource.c62
-rw-r--r--kernel/sched.c538
-rw-r--r--kernel/signal.c17
-rw-r--r--kernel/sys.c38
-rw-r--r--kernel/sysctl.c390
-rw-r--r--kernel/time/clocksource.c8
-rw-r--r--kernel/timer.c169
-rw-r--r--kernel/tsacct.c9
-rw-r--r--kernel/unwind.c1305
-rw-r--r--kernel/workqueue.c45
-rw-r--r--lib/Kconfig9
-rw-r--r--lib/Kconfig.debug102
-rw-r--r--lib/Makefile10
-rw-r--r--lib/bitrev.c58
-rw-r--r--lib/bug.c163
-rw-r--r--lib/crc32.c28
-rw-r--r--lib/fault-inject.c306
-rw-r--r--lib/iomap.c299
-rw-r--r--lib/ioremap.c1
-rw-r--r--lib/kobject.c73
-rw-r--r--lib/kobject_uevent.c44
-rw-r--r--lib/kref.c7
-rw-r--r--lib/reciprocal_div.c9
-rw-r--r--lib/swiotlb.c290
-rw-r--r--mm/bounce.c4
-rw-r--r--mm/fadvise.c2
-rw-r--r--mm/filemap.c31
-rw-r--r--mm/filemap_xip.c8
-rw-r--r--mm/fremap.c2
-rw-r--r--mm/hugetlb.c10
-rw-r--r--mm/memory.c59
-rw-r--r--mm/memory_hotplug.c6
-rw-r--r--mm/mempolicy.c6
-rw-r--r--mm/mincore.c183
-rw-r--r--mm/mmap.c89
-rw-r--r--mm/mremap.c1
-rw-r--r--mm/nommu.c12
-rw-r--r--mm/oom_kill.c21
-rw-r--r--mm/page-writeback.c147
-rw-r--r--mm/page_alloc.c137
-rw-r--r--mm/readahead.c4
-rw-r--r--mm/rmap.c36
-rw-r--r--mm/shmem.c27
-rw-r--r--mm/slab.c119
-rw-r--r--mm/slob.c27
-rw-r--r--mm/swapfile.c12
-rw-r--r--mm/tiny-shmem.c4
-rw-r--r--mm/truncate.c49
-rw-r--r--mm/vmscan.c47
-rw-r--r--net/Kconfig1
-rw-r--r--net/Makefile1
-rw-r--r--net/atm/common.c3
-rw-r--r--net/atm/proc.c2
-rw-r--r--net/ax25/af_ax25.c4
-rw-r--r--net/ax25/ax25_addr.c36
-rw-r--r--net/ax25/ax25_iface.c103
-rw-r--r--net/ax25/ax25_route.c2
-rw-r--r--net/bluetooth/cmtp/capi.c39
-rw-r--r--net/bluetooth/hci_sock.c4
-rw-r--r--net/bluetooth/hci_sysfs.c7
-rw-r--r--net/bluetooth/hidp/hidp.h2
-rw-r--r--net/bluetooth/hidp/sock.c2
-rw-r--r--net/bluetooth/l2cap.c10
-rw-r--r--net/bluetooth/rfcomm/sock.c9
-rw-r--r--net/bluetooth/rfcomm/tty.c26
-rw-r--r--net/bridge/br_if.c2
-rw-r--r--net/bridge/br_netfilter.c217
-rw-r--r--net/bridge/br_netlink.c14
-rw-r--r--net/bridge/br_sysfs_br.c234
-rw-r--r--net/bridge/br_sysfs_if.c2
-rw-r--r--net/bridge/netfilter/ebt_ip.c1
-rw-r--r--net/bridge/netfilter/ebt_log.c1
-rw-r--r--net/bridge/netfilter/ebtables.c3
-rw-r--r--net/core/dev.c19
-rw-r--r--net/core/dst.c9
-rw-r--r--net/core/fib_rules.c14
-rw-r--r--net/core/flow.c26
-rw-r--r--net/core/neighbour.c40
-rw-r--r--net/core/net-sysfs.c175
-rw-r--r--net/core/netpoll.c53
-rw-r--r--net/core/pktgen.c156
-rw-r--r--net/core/rtnetlink.c23
-rw-r--r--net/core/skbuff.c2
-rw-r--r--net/dccp/ackvec.c4
-rw-r--r--net/dccp/ccid.h10
-rw-r--r--net/dccp/ccids/ccid2.c12
-rw-r--r--net/dccp/ccids/ccid3.c520
-rw-r--r--net/dccp/ccids/ccid3.h46
-rw-r--r--net/dccp/ccids/lib/packet_history.c219
-rw-r--r--net/dccp/ccids/lib/packet_history.h128
-rw-r--r--net/dccp/ccids/lib/tfrc.h23
-rw-r--r--net/dccp/ccids/lib/tfrc_equation.c28
-rw-r--r--net/dccp/dccp.h3
-rw-r--r--net/dccp/feat.c6
-rw-r--r--net/dccp/input.c47
-rw-r--r--net/dccp/ipv4.c28
-rw-r--r--net/dccp/ipv6.c26
-rw-r--r--net/dccp/minisocks.c2
-rw-r--r--net/dccp/options.c5
-rw-r--r--net/dccp/output.c43
-rw-r--r--net/dccp/proto.c10
-rw-r--r--net/dccp/timer.c14
-rw-r--r--net/decnet/dn_dev.c31
-rw-r--r--net/decnet/dn_table.c11
-rw-r--r--net/decnet/sysctl_net_decnet.c6
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_assoc.c6
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c8
-rw-r--r--net/ipv4/af_inet.c4
-rw-r--r--net/ipv4/datagram.c2
-rw-r--r--net/ipv4/devinet.c23
-rw-r--r--net/ipv4/fib_semantics.c14
-rw-r--r--net/ipv4/fib_trie.c34
-rw-r--r--net/ipv4/igmp.c2
-rw-r--r--net/ipv4/inet_diag.c19
-rw-r--r--net/ipv4/inet_hashtables.c2
-rw-r--r--net/ipv4/inet_timewait_sock.c4
-rw-r--r--net/ipv4/ip_fragment.c2
-rw-r--r--net/ipv4/ip_gre.c3
-rw-r--r--net/ipv4/ip_output.c17
-rw-r--r--net/ipv4/ipip.c3
-rw-r--r--net/ipv4/ipvs/ip_vs_sync.c17
-rw-r--r--net/ipv4/netfilter.c7
-rw-r--r--net/ipv4/netfilter/Kconfig32
-rw-r--r--net/ipv4/netfilter/Makefile21
-rw-r--r--net/ipv4/netfilter/arp_tables.c5
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c4
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_tcp.c40
-rw-r--r--net/ipv4/netfilter/ip_conntrack_sip.c10
-rw-r--r--net/ipv4/netfilter/ip_nat_core.c12
-rw-r--r--net/ipv4/netfilter/ip_nat_helper.c2
-rw-r--r--net/ipv4/netfilter/ip_nat_proto_tcp.c5
-rw-r--r--net/ipv4/netfilter/ip_nat_proto_udp.c5
-rw-r--r--net/ipv4/netfilter/ip_nat_rule.c32
-rw-r--r--net/ipv4/netfilter/ip_tables.c227
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c25
-rw-r--r--net/ipv4/netfilter/ipt_ECN.c13
-rw-r--r--net/ipv4/netfilter/ipt_LOG.c16
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c14
-rw-r--r--net/ipv4/netfilter/ipt_NETMAP.c8
-rw-r--r--net/ipv4/netfilter/ipt_REDIRECT.c8
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c12
-rw-r--r--net/ipv4/netfilter/ipt_SAME.c8
-rw-r--r--net/ipv4/netfilter/ipt_TCPMSS.c207
-rw-r--r--net/ipv4/netfilter/ipt_TOS.c11
-rw-r--r--net/ipv4/netfilter/ipt_TTL.c11
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c18
-rw-r--r--net/ipv4/netfilter/ipt_addrtype.c9
-rw-r--r--net/ipv4/netfilter/ipt_ah.c10
-rw-r--r--net/ipv4/netfilter/ipt_ecn.c10
-rw-r--r--net/ipv4/netfilter/ipt_iprange.c10
-rw-r--r--net/ipv4/netfilter/ipt_owner.c9
-rw-r--r--net/ipv4/netfilter/ipt_recent.c14
-rw-r--r--net/ipv4/netfilter/ipt_tos.c10
-rw-r--r--net/ipv4/netfilter/ipt_ttl.c11
-rw-r--r--net/ipv4/netfilter/iptable_filter.c2
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c2
-rw-r--r--net/ipv4/netfilter/iptable_raw.c2
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c12
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c2
-rw-r--r--net/ipv4/netfilter/nf_nat_pptp.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_tcp.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_udp.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_rule.c8
-rw-r--r--net/ipv4/netfilter/nf_nat_standalone.c8
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/route.c11
-rw-r--r--net/ipv4/sysctl_net_ipv4.c16
-rw-r--r--net/ipv4/tcp.c12
-rw-r--r--net/ipv4/tcp_input.c120
-rw-r--r--net/ipv4/tcp_ipv4.c23
-rw-r--r--net/ipv4/tcp_output.c9
-rw-r--r--net/ipv4/tcp_probe.c2
-rw-r--r--net/ipv4/udp.c15
-rw-r--r--net/ipv4/xfrm4_mode_tunnel.c57
-rw-r--r--net/ipv4/xfrm4_policy.c51
-rw-r--r--net/ipv4/xfrm4_state.c1
-rw-r--r--net/ipv6/addrconf.c87
-rw-r--r--net/ipv6/af_inet6.c2
-rw-r--r--net/ipv6/datagram.c2
-rw-r--r--net/ipv6/inet6_connection_sock.c3
-rw-r--r--net/ipv6/inet6_hashtables.c4
-rw-r--r--net/ipv6/ip6_output.c17
-rw-r--r--net/ipv6/ip6_tunnel.c3
-rw-r--r--net/ipv6/ipv6_sockglue.c23
-rw-r--r--net/ipv6/mcast.c8
-rw-r--r--net/ipv6/mip6.c26
-rw-r--r--net/ipv6/ndisc.c16
-rw-r--r--net/ipv6/netfilter/Kconfig13
-rw-r--r--net/ipv6/netfilter/Makefile1
-rw-r--r--net/ipv6/netfilter/ip6_tables.c17
-rw-r--r--net/ipv6/netfilter/ip6t_HL.c17
-rw-r--r--net/ipv6/netfilter/ip6t_LOG.c15
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c10
-rw-r--r--net/ipv6/netfilter/ip6t_ah.c8
-rw-r--r--net/ipv6/netfilter/ip6t_eui64.c8
-rw-r--r--net/ipv6/netfilter/ip6t_frag.c8
-rw-r--r--net/ipv6/netfilter/ip6t_hbh.c1
-rw-r--r--net/ipv6/netfilter/ip6t_hl.c11
-rw-r--r--net/ipv6/netfilter/ip6t_ipv6header.c8
-rw-r--r--net/ipv6/netfilter/ip6t_mh.c108
-rw-r--r--net/ipv6/netfilter/ip6t_owner.c8
-rw-r--r--net/ipv6/netfilter/ip6t_rt.c8
-rw-r--r--net/ipv6/netfilter/ip6table_filter.c21
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c21
-rw-r--r--net/ipv6/netfilter/ip6table_raw.c19
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c2
-rw-r--r--net/ipv6/raw.c15
-rw-r--r--net/ipv6/route.c36
-rw-r--r--net/ipv6/sit.c3
-rw-r--r--net/ipv6/tcp_ipv6.c2
-rw-r--r--net/ipv6/udp.c2
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c42
-rw-r--r--net/ipv6/xfrm6_policy.c46
-rw-r--r--net/ipv6/xfrm6_state.c1
-rw-r--r--net/ipx/af_ipx.c24
-rw-r--r--net/irda/ircomm/ircomm_tty_ioctl.c2
-rw-r--r--net/irda/irias_object.c40
-rw-r--r--net/irda/irlan/irlan_common.c23
-rw-r--r--net/iucv/Kconfig15
-rw-r--r--net/iucv/Makefile6
-rw-r--r--net/iucv/af_iucv.c1077
-rw-r--r--net/iucv/iucv.c1619
-rw-r--r--net/key/af_key.c422
-rw-r--r--net/netfilter/Kconfig70
-rw-r--r--net/netfilter/Makefile2
-rw-r--r--net/netfilter/nf_conntrack_netbios_ns.c1
-rw-r--r--net/netfilter/nf_conntrack_netlink.c4
-rw-r--r--net/netfilter/nf_conntrack_pptp.c2
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c40
-rw-r--r--net/netfilter/nf_conntrack_sane.c242
-rw-r--r--net/netfilter/nf_conntrack_sip.c10
-rw-r--r--net/netfilter/xt_CLASSIFY.c4
-rw-r--r--net/netfilter/xt_CONNMARK.c19
-rw-r--r--net/netfilter/xt_CONNSECMARK.c20
-rw-r--r--net/netfilter/xt_MARK.c8
-rw-r--r--net/netfilter/xt_SECMARK.c4
-rw-r--r--net/netfilter/xt_TCPMSS.c296
-rw-r--r--net/netfilter/xt_connbytes.c43
-rw-r--r--net/netfilter/xt_connmark.c7
-rw-r--r--net/netfilter/xt_conntrack.c8
-rw-r--r--net/netfilter/xt_hashlimit.c3
-rw-r--r--net/netfilter/xt_helper.c8
-rw-r--r--net/netfilter/xt_physdev.c12
-rw-r--r--net/netfilter/xt_state.c7
-rw-r--r--net/netlabel/netlabel_cipso_v4.c43
-rw-r--r--net/netlink/af_netlink.c5
-rw-r--r--net/netrom/af_netrom.c15
-rw-r--r--net/netrom/nr_dev.c24
-rw-r--r--net/netrom/nr_route.c19
-rw-r--r--net/packet/af_packet.c125
-rw-r--r--net/rose/af_rose.c18
-rw-r--r--net/rose/rose_dev.c22
-rw-r--r--net/rose/rose_loopback.c5
-rw-r--r--net/rose/rose_route.c47
-rw-r--r--net/sched/act_ipt.c10
-rw-r--r--net/sched/sch_cbq.c21
-rw-r--r--net/sched/sch_generic.c2
-rw-r--r--net/sched/sch_htb.c51
-rw-r--r--net/sched/sch_prio.c15
-rw-r--r--net/sched/sch_sfq.c2
-rw-r--r--net/sctp/associola.c1
-rw-r--r--net/sctp/ipv6.c38
-rw-r--r--net/sctp/protocol.c76
-rw-r--r--net/sctp/sm_make_chunk.c34
-rw-r--r--net/sctp/sm_sideeffect.c8
-rw-r--r--net/sctp/sm_statefuns.c76
-rw-r--r--net/sctp/sm_statetable.c2
-rw-r--r--net/sctp/socket.c152
-rw-r--r--net/sctp/ulpevent.c24
-rw-r--r--net/socket.c43
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c2
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_mech.c2
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c11
-rw-r--r--net/sunrpc/cache.c41
-rw-r--r--net/sunrpc/clnt.c8
-rw-r--r--net/sunrpc/rpc_pipe.c8
-rw-r--r--net/sunrpc/sched.c3
-rw-r--r--net/sunrpc/svc.c38
-rw-r--r--net/sunrpc/svcauth_unix.c5
-rw-r--r--net/sunrpc/svcsock.c66
-rw-r--r--net/tipc/config.c2
-rw-r--r--net/unix/garbage.c2
-rw-r--r--net/wanrouter/wanmain.c17
-rw-r--r--net/x25/Makefile2
-rw-r--r--net/x25/af_x25.c34
-rw-r--r--net/x25/sysctl_net_x25.c8
-rw-r--r--net/x25/x25_dev.c14
-rw-r--r--net/x25/x25_facilities.c12
-rw-r--r--net/x25/x25_forward.c163
-rw-r--r--net/x25/x25_proc.c98
-rw-r--r--net/x25/x25_route.c3
-rw-r--r--net/xfrm/Kconfig26
-rw-r--r--net/xfrm/xfrm_algo.c20
-rw-r--r--net/xfrm/xfrm_policy.c247
-rw-r--r--net/xfrm/xfrm_state.c184
-rw-r--r--net/xfrm/xfrm_user.c246
-rw-r--r--scripts/Kbuild.include85
-rw-r--r--scripts/Makefile.headersinst2
-rw-r--r--scripts/gen_initramfs_list.sh43
-rw-r--r--scripts/kallsyms.c2
-rw-r--r--scripts/kconfig/conf.c2
-rw-r--r--scripts/kconfig/confdata.c37
-rw-r--r--scripts/kconfig/gconf.c35
-rw-r--r--scripts/kconfig/gconf.glade4
-rw-r--r--scripts/kconfig/lkc.h2
-rw-r--r--scripts/kconfig/lkc_proto.h3
-rw-r--r--scripts/kconfig/mconf.c21
-rw-r--r--scripts/kconfig/qconf.cc18
-rw-r--r--scripts/kconfig/qconf.h3
-rw-r--r--scripts/kconfig/symbol.c3
-rw-r--r--scripts/kconfig/zconf.tab.c_shipped2
-rw-r--r--scripts/kconfig/zconf.y2
-rwxr-xr-xscripts/kernel-doc17
-rwxr-xr-xscripts/makelst34
-rw-r--r--scripts/mod/modpost.c28
-rw-r--r--security/keys/key.c33
-rw-r--r--security/selinux/hooks.c33
-rw-r--r--security/selinux/include/xfrm.h9
-rw-r--r--security/selinux/selinuxfs.c8
-rw-r--r--security/selinux/ss/context.h23
-rw-r--r--security/selinux/ss/mls.c30
-rw-r--r--security/selinux/ss/mls.h20
-rw-r--r--security/selinux/ss/services.c16
-rw-r--r--sound/Kconfig10
-rw-r--r--sound/Makefile5
-rw-r--r--sound/ac97_bus.c (renamed from sound/pci/ac97/ac97_bus.c)4
-rw-r--r--sound/aoa/aoa.h2
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-onyx.c11
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-onyx.h1
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-tas.c1
-rw-r--r--sound/aoa/core/snd-aoa-alsa.c5
-rw-r--r--sound/aoa/core/snd-aoa-alsa.h2
-rw-r--r--sound/aoa/core/snd-aoa-core.c4
-rw-r--r--sound/aoa/fabrics/Kconfig2
-rw-r--r--sound/aoa/fabrics/snd-aoa-fabric-layout.c13
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-core.c22
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-pcm.c407
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus.h6
-rw-r--r--sound/arm/aaci.h2
-rw-r--r--sound/core/control.c44
-rw-r--r--sound/core/control_compat.c5
-rw-r--r--sound/core/device.c24
-rw-r--r--sound/core/hwdep.c19
-rw-r--r--sound/core/info.c2
-rw-r--r--sound/core/init.c40
-rw-r--r--sound/core/memalloc.c10
-rw-r--r--sound/core/misc.c28
-rw-r--r--sound/core/oss/mixer_oss.c2
-rw-r--r--sound/core/oss/pcm_oss.c52
-rw-r--r--sound/core/pcm.c54
-rw-r--r--sound/core/pcm_lib.c13
-rw-r--r--sound/core/pcm_memory.c23
-rw-r--r--sound/core/pcm_native.c2
-rw-r--r--sound/core/rawmidi.c33
-rw-r--r--sound/core/seq/seq_clientmgr.c14
-rw-r--r--sound/core/seq/seq_device.c25
-rw-r--r--sound/core/seq/seq_memory.c2
-rw-r--r--sound/core/seq/seq_ports.c51
-rw-r--r--sound/core/seq/seq_virmidi.c4
-rw-r--r--sound/core/sgbuf.c2
-rw-r--r--sound/core/sound.c17
-rw-r--r--sound/core/sound_oss.c4
-rw-r--r--sound/core/timer.c80
-rw-r--r--sound/drivers/Kconfig17
-rw-r--r--sound/drivers/Makefile2
-rw-r--r--sound/drivers/dummy.c2
-rw-r--r--sound/drivers/portman2x4.c876
-rw-r--r--sound/drivers/serial-u16550.c221
-rw-r--r--sound/drivers/vx/vx_mixer.c2
-rw-r--r--sound/i2c/Makefile1
-rw-r--r--sound/i2c/other/Makefile4
-rw-r--r--sound/i2c/other/ak4114.c29
-rw-r--r--sound/i2c/other/ak4117.c2
-rw-r--r--sound/i2c/other/ak4xxx-adda.c110
-rw-r--r--sound/i2c/other/pt2258.c233
-rw-r--r--sound/isa/Kconfig2
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c10
-rw-r--r--sound/isa/ad1848/ad1848_lib.c6
-rw-r--r--sound/isa/gus/gus_main.c6
-rw-r--r--sound/isa/gus/gus_mem.c7
-rw-r--r--sound/isa/opl3sa2.c4
-rw-r--r--sound/isa/sb/sb16_csp.c61
-rw-r--r--sound/isa/sb/sb_common.c2
-rw-r--r--sound/isa/wavefront/wavefront.c1
-rw-r--r--sound/isa/wavefront/wavefront_fx.c812
-rw-r--r--sound/isa/wavefront/wavefront_synth.c2
-rw-r--r--sound/isa/wavefront/yss225.c2739
-rw-r--r--sound/oss/ad1848.c2
-rw-r--r--sound/oss/cs4232.c2
-rw-r--r--sound/oss/dmasound/dmasound_core.c4
-rw-r--r--sound/oss/dmasound/tas3001c.c14
-rw-r--r--sound/oss/dmasound/tas3004.c15
-rw-r--r--sound/oss/emu10k1/audio.c6
-rw-r--r--sound/oss/emu10k1/cardmi.c2
-rw-r--r--sound/oss/emu10k1/cardmo.c2
-rw-r--r--sound/oss/emu10k1/midi.c10
-rw-r--r--sound/oss/emu10k1/mixer.c2
-rw-r--r--sound/oss/hal2.c2
-rw-r--r--sound/oss/mpu401.c2
-rw-r--r--sound/oss/msnd_pinnacle.c4
-rw-r--r--sound/oss/opl3.c2
-rw-r--r--sound/oss/sb_common.c2
-rw-r--r--sound/oss/sb_midi.c4
-rw-r--r--sound/oss/sb_mixer.c2
-rw-r--r--sound/oss/soundcard.c8
-rw-r--r--sound/oss/v_midi.c2
-rw-r--r--sound/oss/waveartist.c2
-rw-r--r--sound/pci/Kconfig30
-rw-r--r--sound/pci/ac97/Makefile2
-rw-r--r--sound/pci/ac97/ac97_codec.c74
-rw-r--r--sound/pci/ac97/ac97_patch.c554
-rw-r--r--sound/pci/ac97/ac97_patch.h1
-rw-r--r--sound/pci/ac97/ak4531_codec.c6
-rw-r--r--sound/pci/ad1889.c4
-rw-r--r--sound/pci/ali5451/ali5451.c5
-rw-r--r--sound/pci/als300.c12
-rw-r--r--sound/pci/atiixp.c33
-rw-r--r--sound/pci/atiixp_modem.c4
-rw-r--r--sound/pci/au88x0/au88x0.c2
-rw-r--r--sound/pci/azt3328.c5
-rw-r--r--sound/pci/bt87x.c4
-rw-r--r--sound/pci/ca0106/ca0106.h2
-rw-r--r--sound/pci/ca0106/ca0106_main.c58
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c50
-rw-r--r--sound/pci/cmipci.c5
-rw-r--r--sound/pci/cs4281.c4
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c2
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c2
-rw-r--r--sound/pci/echoaudio/darla20.c1
-rw-r--r--sound/pci/echoaudio/darla24.c1
-rw-r--r--sound/pci/echoaudio/echo3g.c1
-rw-r--r--sound/pci/echoaudio/echo3g_dsp.c2
-rw-r--r--sound/pci/echoaudio/echoaudio.c24
-rw-r--r--sound/pci/echoaudio/gina20.c1
-rw-r--r--sound/pci/echoaudio/gina24.c1
-rw-r--r--sound/pci/echoaudio/indigo.c1
-rw-r--r--sound/pci/echoaudio/indigodj.c1
-rw-r--r--sound/pci/echoaudio/indigoio.c1
-rw-r--r--sound/pci/echoaudio/layla20.c1
-rw-r--r--sound/pci/echoaudio/layla24.c1
-rw-r--r--sound/pci/echoaudio/mia.c1
-rw-r--r--sound/pci/echoaudio/midi.c6
-rw-r--r--sound/pci/echoaudio/mona.c1
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c621
-rw-r--r--sound/pci/emu10k1/emu10k1x.c15
-rw-r--r--sound/pci/emu10k1/emufx.c204
-rw-r--r--sound/pci/emu10k1/emumixer.c745
-rw-r--r--sound/pci/emu10k1/emupcm.c147
-rw-r--r--sound/pci/emu10k1/emuproc.c34
-rw-r--r--sound/pci/emu10k1/io.c104
-rw-r--r--sound/pci/emu10k1/p16v.c14
-rw-r--r--sound/pci/emu10k1/p17v.h47
-rw-r--r--sound/pci/emu10k1/voice.c2
-rw-r--r--sound/pci/ens1370.c156
-rw-r--r--sound/pci/es1938.c6
-rw-r--r--sound/pci/es1968.c8
-rw-r--r--sound/pci/fm801.c4
-rw-r--r--sound/pci/hda/Makefile11
-rw-r--r--sound/pci/hda/hda_codec.c71
-rw-r--r--sound/pci/hda/hda_generic.c5
-rw-r--r--sound/pci/hda/hda_intel.c50
-rw-r--r--sound/pci/hda/hda_local.h12
-rw-r--r--sound/pci/hda/hda_patch.h6
-rw-r--r--sound/pci/hda/hda_proc.c53
-rw-r--r--sound/pci/hda/patch_analog.c163
-rw-r--r--sound/pci/hda/patch_cmedia.c24
-rw-r--r--sound/pci/hda/patch_conexant.c1311
-rw-r--r--sound/pci/hda/patch_realtek.c2365
-rw-r--r--sound/pci/hda/patch_si3054.c3
-rw-r--r--sound/pci/hda/patch_sigmatel.c692
-rw-r--r--sound/pci/hda/patch_via.c1396
-rw-r--r--sound/pci/ice1712/Makefile2
-rw-r--r--sound/pci/ice1712/amp.c4
-rw-r--r--sound/pci/ice1712/amp.h2
-rw-r--r--sound/pci/ice1712/aureon.c186
-rw-r--r--sound/pci/ice1712/aureon.h6
-rw-r--r--sound/pci/ice1712/delta.c34
-rw-r--r--sound/pci/ice1712/delta.h2
-rw-r--r--sound/pci/ice1712/ews.c24
-rw-r--r--sound/pci/ice1712/ews.h2
-rw-r--r--sound/pci/ice1712/hoontech.c7
-rw-r--r--sound/pci/ice1712/hoontech.h2
-rw-r--r--sound/pci/ice1712/ice1712.c76
-rw-r--r--sound/pci/ice1712/ice1712.h18
-rw-r--r--sound/pci/ice1712/ice1724.c80
-rw-r--r--sound/pci/ice1712/juli.c36
-rw-r--r--sound/pci/ice1712/juli.h2
-rw-r--r--sound/pci/ice1712/phase.c76
-rw-r--r--sound/pci/ice1712/phase.h2
-rw-r--r--sound/pci/ice1712/pontis.c42
-rw-r--r--sound/pci/ice1712/pontis.h2
-rw-r--r--sound/pci/ice1712/prodigy192.c40
-rw-r--r--sound/pci/ice1712/prodigy192.h2
-rw-r--r--sound/pci/ice1712/revo.c372
-rw-r--r--sound/pci/ice1712/revo.h13
-rw-r--r--sound/pci/ice1712/vt1720_mobo.c59
-rw-r--r--sound/pci/ice1712/vt1720_mobo.h2
-rw-r--r--sound/pci/ice1712/wtm.c542
-rw-r--r--sound/pci/ice1712/wtm.h20
-rw-r--r--sound/pci/intel8x0.c212
-rw-r--r--sound/pci/intel8x0m.c124
-rw-r--r--sound/pci/korg1212/korg1212.c47
-rw-r--r--sound/pci/maestro3.c377
-rw-r--r--sound/pci/mixart/mixart.c5
-rw-r--r--sound/pci/mixart/mixart_mixer.c4
-rw-r--r--sound/pci/nm256/nm256.c58
-rw-r--r--sound/pci/pcxhr/pcxhr.c2
-rw-r--r--sound/pci/pcxhr/pcxhr_mixer.c6
-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.c47
-rw-r--r--sound/pci/rme9652/hdspm.c1245
-rw-r--r--sound/pci/rme9652/rme9652.c7
-rw-r--r--sound/pci/sonicvibes.c5
-rw-r--r--sound/pci/trident/trident_main.c10
-rw-r--r--sound/pci/via82xx.c136
-rw-r--r--sound/pci/via82xx_modem.c4
-rw-r--r--sound/pci/vx222/vx222.c8
-rw-r--r--sound/pci/vx222/vx222_ops.c2
-rw-r--r--sound/pci/ymfpci/ymfpci.c5
-rw-r--r--sound/pci/ymfpci/ymfpci_image.h6
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c210
-rw-r--r--sound/pcmcia/vx/vxp_mixer.c2
-rw-r--r--sound/pcmcia/vx/vxpocket.c2
-rw-r--r--sound/soc/Kconfig32
-rw-r--r--sound/soc/Makefile4
-rw-r--r--sound/soc/at91/Kconfig32
-rw-r--r--sound/soc/at91/Makefile11
-rw-r--r--sound/soc/at91/at91-i2s.c720
-rw-r--r--sound/soc/at91/at91-i2s.h27
-rw-r--r--sound/soc/at91/at91-pcm.c432
-rw-r--r--sound/soc/at91/at91-pcm.h72
-rw-r--r--sound/soc/at91/eti_b1_wm8731.c375
-rw-r--r--sound/soc/codecs/Kconfig15
-rw-r--r--sound/soc/codecs/Makefile9
-rw-r--r--sound/soc/codecs/ac97.c156
-rw-r--r--sound/soc/codecs/ac97.h18
-rw-r--r--sound/soc/codecs/wm8731.c758
-rw-r--r--sound/soc/codecs/wm8731.h44
-rw-r--r--sound/soc/codecs/wm8750.c1049
-rw-r--r--sound/soc/codecs/wm8750.h67
-rw-r--r--sound/soc/codecs/wm9712.c771
-rw-r--r--sound/soc/codecs/wm9712.h14
-rw-r--r--sound/soc/pxa/Kconfig60
-rw-r--r--sound/soc/pxa/Makefile20
-rw-r--r--sound/soc/pxa/corgi.c383
-rw-r--r--sound/soc/pxa/poodle.c352
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c431
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.h22
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c318
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.h20
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c372
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.h34
-rw-r--r--sound/soc/pxa/spitz.c394
-rw-r--r--sound/soc/pxa/tosa.c289
-rw-r--r--sound/soc/soc-core.c1587
-rw-r--r--sound/soc/soc-dapm.c1323
-rw-r--r--sound/sound_firmware.c2
-rw-r--r--sound/sparc/cs4231.c26
-rw-r--r--sound/sparc/dbri.c2
-rw-r--r--sound/usb/usbaudio.c202
-rw-r--r--sound/usb/usbaudio.h1
-rw-r--r--sound/usb/usbmixer.c2
-rw-r--r--sound/usb/usbquirks.h32
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c2
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c2
4487 files changed, 225590 insertions, 103337 deletions
diff --git a/.gitignore b/.gitignore
index 9eb4b771149..060a71d41ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,6 @@ patches-*
# quilt's files
patches
series
+
+# cscope files
+cscope.*
diff --git a/CREDITS b/CREDITS
index d0880082c19..ae08e4c10ed 100644
--- a/CREDITS
+++ b/CREDITS
@@ -516,9 +516,10 @@ S: Orlando, Florida
S: USA
N: Lennert Buytenhek
-E: buytenh@gnu.org
-D: Rewrite of the ethernet bridging code
-S: Ravenhorst 58B
+E: kernel@wantstofly.org
+D: Original (2.4) rewrite of the ethernet bridging code
+D: Various ARM bits and pieces
+S: Ravenhorst 58
S: 2317 AK Leiden
S: The Netherlands
@@ -1808,6 +1809,14 @@ S: Kruislaan 419
S: 1098 VA Amsterdam
S: The Netherlands
+N: Jiri Kosina
+E: jikos@jikos.cz
+E: jkosina@suse.cz
+D: Generic HID layer - original code split, fixes
+D: Various ACPI fixes, keeping correct battery state through suspend
+D: various lockdep annotations, autofs and other random bugfixes
+S: Prague, Czech Republic
+
N: Gene Kozin
E: 74604.152@compuserve.com
W: http://www.sangoma.com
@@ -3270,7 +3279,7 @@ S: Sevilla 41005
S: Spain
N: Linus Torvalds
-E: torvalds@osdl.org
+E: torvalds@linux-foundation.org
D: Original kernel hacker
S: 12725 SW Millikan Way, Suite 400
S: Beaverton, Oregon 97005
diff --git a/Documentation/ABI/testing/debugfs-pktcdvd b/Documentation/ABI/testing/debugfs-pktcdvd
new file mode 100644
index 00000000000..03dbd883cc4
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-pktcdvd
@@ -0,0 +1,20 @@
+What: /debug/pktcdvd/pktcdvd[0-7]
+Date: Oct. 2006
+KernelVersion: 2.6.19
+Contact: Thomas Maier <balagi@justmail.de>
+Description:
+
+debugfs interface
+-----------------
+
+The pktcdvd module (packet writing driver) creates
+these files in debugfs:
+
+/debug/pktcdvd/pktcdvd[0-7]/
+ info (0444) Lots of human readable driver
+ statistics and infos. Multiple lines!
+
+Example:
+-------
+
+cat /debug/pktcdvd/pktcdvd0/info
diff --git a/Documentation/ABI/testing/sysfs-class-pktcdvd b/Documentation/ABI/testing/sysfs-class-pktcdvd
new file mode 100644
index 00000000000..c4c55edc9a5
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-pktcdvd
@@ -0,0 +1,72 @@
+What: /sys/class/pktcdvd/
+Date: Oct. 2006
+KernelVersion: 2.6.19
+Contact: Thomas Maier <balagi@justmail.de>
+Description:
+
+sysfs interface
+---------------
+
+The pktcdvd module (packet writing driver) creates
+these files in the sysfs:
+(<devid> is in format major:minor )
+
+/sys/class/pktcdvd/
+ add (0200) Write a block device id (major:minor)
+ to create a new pktcdvd device and map
+ it to the block device.
+
+ remove (0200) Write the pktcdvd device id (major:minor)
+ to it to remove the pktcdvd device.
+
+ device_map (0444) Shows the device mapping in format:
+ pktcdvd[0-7] <pktdevid> <blkdevid>
+
+/sys/class/pktcdvd/pktcdvd[0-7]/
+ dev (0444) Device id
+ uevent (0200) To send an uevent.
+
+/sys/class/pktcdvd/pktcdvd[0-7]/stat/
+ packets_started (0444) Number of started packets.
+ packets_finished (0444) Number of finished packets.
+
+ kb_written (0444) kBytes written.
+ kb_read (0444) kBytes read.
+ kb_read_gather (0444) kBytes read to fill write packets.
+
+ reset (0200) Write any value to it to reset
+ pktcdvd device statistic values, like
+ bytes read/written.
+
+/sys/class/pktcdvd/pktcdvd[0-7]/write_queue/
+ size (0444) Contains the size of the bio write
+ queue.
+
+ congestion_off (0644) If bio write queue size is below
+ this mark, accept new bio requests
+ from the block layer.
+
+ congestion_on (0644) If bio write queue size is higher
+ as this mark, do no longer accept
+ bio write requests from the block
+ layer and wait till the pktcdvd
+ device has processed enough bio's
+ so that bio write queue size is
+ below congestion off mark.
+ A value of <= 0 disables congestion
+ control.
+
+
+Example:
+--------
+To use the pktcdvd sysfs interface directly, you can do:
+
+# create a new pktcdvd device mapped to /dev/hdc
+echo "22:0" >/sys/class/pktcdvd/add
+cat /sys/class/pktcdvd/device_map
+# assuming device pktcdvd0 was created, look at stat's
+cat /sys/class/pktcdvd/pktcdvd0/stat/kb_written
+# print the device id of the mapped block device
+fgrep pktcdvd0 /sys/class/pktcdvd/device_map
+# remove device, using pktcdvd0 device id 253:0
+echo "253:0" >/sys/class/pktcdvd/remove
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index 29c18966b05..9069189e78e 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -35,12 +35,37 @@ In short, 8-char indents make things easier to read, and have the added
benefit of warning you when you're nesting your functions too deep.
Heed that warning.
+The preferred way to ease multiple indentation levels in a switch statement is
+to align the "switch" and its subordinate "case" labels in the same column
+instead of "double-indenting" the "case" labels. E.g.:
+
+ switch (suffix) {
+ case 'G':
+ case 'g':
+ mem <<= 30;
+ break;
+ case 'M':
+ case 'm':
+ mem <<= 20;
+ break;
+ case 'K':
+ case 'k':
+ mem <<= 10;
+ /* fall through */
+ default:
+ break;
+ }
+
+
Don't put multiple statements on a single line unless you have
something to hide:
if (condition) do_this;
do_something_everytime;
+Don't put multiple assignments on a single line either. Kernel coding style
+is super simple. Avoid tricky expressions.
+
Outside of comments, documentation and except in Kconfig, spaces are never
used for indentation, and the above example is deliberately broken.
@@ -69,7 +94,7 @@ void fun(int a, int b, int c)
next_statement;
}
- Chapter 3: Placing Braces
+ Chapter 3: Placing Braces and Spaces
The other issue that always comes up in C styling is the placement of
braces. Unlike the indent size, there are few technical reasons to
@@ -81,6 +106,20 @@ brace last on the line, and put the closing brace first, thusly:
we do y
}
+This applies to all non-function statement blocks (if, switch, for,
+while, do). E.g.:
+
+ switch (action) {
+ case KOBJ_ADD:
+ return "add";
+ case KOBJ_REMOVE:
+ return "remove";
+ case KOBJ_CHANGE:
+ return "change";
+ default:
+ return NULL;
+ }
+
However, there is one special case, namely functions: they have the
opening brace at the beginning of the next line, thus:
@@ -121,6 +160,49 @@ supply of new-lines on your screen is not a renewable resource (think
25-line terminal screens here), you have more empty lines to put
comments on.
+ 3.1: Spaces
+
+Linux kernel style for use of spaces depends (mostly) on
+function-versus-keyword usage. Use a space after (most) keywords. The
+notable exceptions are sizeof, typeof, alignof, and __attribute__, which look
+somewhat like functions (and are usually used with parentheses in Linux,
+although they are not required in the language, as in: "sizeof info" after
+"struct fileinfo info;" is declared).
+
+So use a space after these keywords:
+ if, switch, case, for, do, while
+but not with sizeof, typeof, alignof, or __attribute__. E.g.,
+ s = sizeof(struct file);
+
+Do not add spaces around (inside) parenthesized expressions. This example is
+*bad*:
+
+ s = sizeof( struct file );
+
+When declaring pointer data or a function that returns a pointer type, the
+preferred use of '*' is adjacent to the data name or function name and not
+adjacent to the type name. Examples:
+
+ char *linux_banner;
+ unsigned long long memparse(char *ptr, char **retptr);
+ char *match_strdup(substring_t *s);
+
+Use one space around (on each side of) most binary and ternary operators,
+such as any of these:
+
+ = + - < > * / % | & ^ <= >= == != ? :
+
+but no space after unary operators:
+ & * + - ~ ! sizeof typeof alignof __attribute__ defined
+
+no space before the postfix increment & decrement unary operators:
+ ++ --
+
+no space after the prefix increment & decrement unary operators:
+ ++ --
+
+and no space around the '.' and "->" structure member operators.
+
Chapter 4: Naming
@@ -152,7 +234,7 @@ variable that is used to hold a temporary value.
If you are afraid to mix up your local variable names, you have another
problem, which is called the function-growth-hormone-imbalance syndrome.
-See next chapter.
+See chapter 6 (Functions).
Chapter 5: Typedefs
@@ -258,6 +340,20 @@ generally easily keep track of about 7 different things, anything more
and it gets confused. You know you're brilliant, but maybe you'd like
to understand what you did 2 weeks from now.
+In source files, separate functions with one blank line. If the function is
+exported, the EXPORT* macro for it should follow immediately after the closing
+function brace line. E.g.:
+
+int system_is_up(void)
+{
+ return system_state == SYSTEM_RUNNING;
+}
+EXPORT_SYMBOL(system_is_up);
+
+In function prototypes, include parameter names with their data types.
+Although this is not required by the C language, it is preferred in Linux
+because it is a simple way to add valuable information for the reader.
+
Chapter 7: Centralized exiting of functions
@@ -306,16 +402,36 @@ time to explain badly written code.
Generally, you want your comments to tell WHAT your code does, not HOW.
Also, try to avoid putting comments inside a function body: if the
function is so complex that you need to separately comment parts of it,
-you should probably go back to chapter 5 for a while. You can make
+you should probably go back to chapter 6 for a while. You can make
small comments to note or warn about something particularly clever (or
ugly), but try to avoid excess. Instead, put the comments at the head
of the function, telling people what it does, and possibly WHY it does
it.
-When commenting the kernel API functions, please use the kerneldoc format.
+When commenting the kernel API functions, please use the kernel-doc format.
See the files Documentation/kernel-doc-nano-HOWTO.txt and scripts/kernel-doc
for details.
+Linux style for comments is the C89 "/* ... */" style.
+Don't use C99-style "// ..." comments.
+
+The preferred style for long (multi-line) comments is:
+
+ /*
+ * This is the preferred style for multi-line
+ * comments in the Linux kernel source code.
+ * Please use it consistently.
+ *
+ * Description: A column of asterisks on the left side,
+ * with beginning and ending almost-blank lines.
+ */
+
+It's also important to comment data, whether they are basic types or derived
+types. To this end, use just one data declaration per line (no commas for
+multiple data declarations). This leaves you room for a small comment on each
+item, explaining its use.
+
+
Chapter 9: You've made a mess of it
That's OK, we all do. You've probably been told by your long-time Unix
@@ -566,6 +682,24 @@ result. Typical examples would be functions that return pointers; they use
NULL or the ERR_PTR mechanism to report failure.
+ Chapter 17: Don't re-invent the kernel macros
+
+The header file include/linux/kernel.h contains a number of macros that
+you should use, rather than explicitly coding some variant of them yourself.
+For example, if you need to calculate the length of an array, take advantage
+of the macro
+
+ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+Similarly, if you need to calculate the size of some structure member, use
+
+ #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+
+There are also min() and max() macros that do strict type checking if you
+need them. Feel free to peruse that header file to see what else is already
+defined that you shouldn't reproduce in your code.
+
+
Appendix I: References
@@ -591,4 +725,4 @@ Kernel CodingStyle, by greg@kroah.com at OLS 2002:
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
--
-Last updated on 30 April 2006.
+Last updated on 2006-December-06.
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 36526a1e76d..867608ab3ca 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -53,8 +53,8 @@ installmandocs: mandocs
###
#External programs used
-KERNELDOC = scripts/kernel-doc
-DOCPROC = scripts/basic/docproc
+KERNELDOC = $(srctree)/scripts/kernel-doc
+DOCPROC = $(objtree)/scripts/basic/docproc
XMLTOFLAGS = -m $(srctree)/Documentation/DocBook/stylesheet.xsl
#XMLTOFLAGS += --skip-validation
diff --git a/Documentation/DocBook/genericirq.tmpl b/Documentation/DocBook/genericirq.tmpl
index 0f4a4b6321e..4215f69ce7e 100644
--- a/Documentation/DocBook/genericirq.tmpl
+++ b/Documentation/DocBook/genericirq.tmpl
@@ -303,10 +303,10 @@ desc->status |= running;
do {
if (desc->status &amp; masked)
desc->chip->enable();
- desc-status &amp;= ~pending;
+ desc->status &amp;= ~pending;
handle_IRQ_event(desc->action);
} while (status &amp; pending);
-desc-status &amp;= ~running;
+desc->status &amp;= ~running;
desc->chip->end();
</programlisting>
</para>
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index 07a635590b3..e2e24b4778d 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -883,7 +883,7 @@ and other resources, etc.
</chapter>
<chapter id="ataExceptions">
- <title>ATA errors &amp; exceptions</title>
+ <title>ATA errors and exceptions</title>
<para>
This chapter tries to identify what error/exception conditions exist
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 8d51c148f72..48123dba5e6 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -30,6 +30,7 @@ are not a good substitute for a solid C education and/or years of
experience, the following books are good for, if anything, reference:
- "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
- "Practical C Programming" by Steve Oualline [O'Reilly]
+ - "C: A Reference Manual" by Harbison and Steele [Prentice Hall]
The kernel is written using GNU C and the GNU toolchain. While it
adheres to the ISO C89 standard, it uses a number of extensions that are
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist
index 7ac61f60037..bfbb2718a27 100644
--- a/Documentation/SubmitChecklist
+++ b/Documentation/SubmitChecklist
@@ -66,3 +66,13 @@ kernel patches.
See Documentation/ABI/README for more information.
20: Check that it all passes `make headers_check'.
+
+21: Has been checked with injection of at least slab and page-allocation
+ fauilures. See Documentation/fault-injection/.
+
+ If the new code is substantial, addition of subsystem-specific fault
+ injection might be appropriate.
+
+22: Newly-added code has been compiled with `gcc -W'. This will generate
+ lots of noise, but is good for finding bugs like "warning: comparison
+ between signed and unsigned".
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 302d148c2e1..b0d0043f7c4 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -134,9 +134,9 @@ Do not send more than 15 patches at once to the vger mailing lists!!!
Linus Torvalds is the final arbiter of all changes accepted into the
-Linux kernel. His e-mail address is <torvalds@osdl.org>. He gets
-a lot of e-mail, so typically you should do your best to -avoid- sending
-him e-mail.
+Linux kernel. His e-mail address is <torvalds@linux-foundation.org>.
+He gets a lot of e-mail, so typically you should do your best to -avoid-
+sending him e-mail.
Patches which are bug fixes, are "obvious" changes, or similarly
require little discussion should be sent or CC'd to Linus. Patches
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index bf2b0e2f87e..e9126e794ed 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -7,6 +7,8 @@
* Copyright (C) Balbir Singh, IBM Corp. 2006
* Copyright (c) Jay Lan, SGI. 2006
*
+ * Compile with
+ * gcc -I/usr/src/linux/include getdelays.c -o getdelays
*/
#include <stdio.h>
@@ -35,13 +37,20 @@
#define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN))
#define NLA_PAYLOAD(len) (len - NLA_HDRLEN)
-#define err(code, fmt, arg...) do { printf(fmt, ##arg); exit(code); } while (0)
-int done = 0;
-int rcvbufsz=0;
-
- char name[100];
-int dbg=0, print_delays=0;
+#define err(code, fmt, arg...) \
+ do { \
+ fprintf(stderr, fmt, ##arg); \
+ exit(code); \
+ } while (0)
+
+int done;
+int rcvbufsz;
+char name[100];
+int dbg;
+int print_delays;
+int print_io_accounting;
__u64 stime, utime;
+
#define PRINTF(fmt, arg...) { \
if (dbg) { \
printf(fmt, ##arg); \
@@ -78,8 +87,9 @@ static int create_nl_socket(int protocol)
if (rcvbufsz)
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
&rcvbufsz, sizeof(rcvbufsz)) < 0) {
- printf("Unable to set socket rcv buf size to %d\n",
- rcvbufsz);
+ fprintf(stderr, "Unable to set socket rcv buf size "
+ "to %d\n",
+ rcvbufsz);
return -1;
}
@@ -186,6 +196,15 @@ void print_delayacct(struct taskstats *t)
"count", "delay total", t->swapin_count, t->swapin_delay_total);
}
+void print_ioacct(struct taskstats *t)
+{
+ printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n",
+ t->ac_comm,
+ (unsigned long long)t->read_bytes,
+ (unsigned long long)t->write_bytes,
+ (unsigned long long)t->cancelled_write_bytes);
+}
+
int main(int argc, char *argv[])
{
int c, rc, rep_len, aggr_len, len2, cmd_type;
@@ -208,7 +227,7 @@ int main(int argc, char *argv[])
struct msgtemplate msg;
while (1) {
- c = getopt(argc, argv, "dw:r:m:t:p:v:l");
+ c = getopt(argc, argv, "diw:r:m:t:p:v:l");
if (c < 0)
break;
@@ -217,6 +236,10 @@ int main(int argc, char *argv[])
printf("print delayacct stats ON\n");
print_delays = 1;
break;
+ case 'i':
+ printf("printing IO accounting\n");
+ print_io_accounting = 1;
+ break;
case 'w':
strncpy(logfile, optarg, MAX_FILENAME);
printf("write to file %s\n", logfile);
@@ -238,14 +261,12 @@ int main(int argc, char *argv[])
if (!tid)
err(1, "Invalid tgid\n");
cmd_type = TASKSTATS_CMD_ATTR_TGID;
- print_delays = 1;
break;
case 'p':
tid = atoi(optarg);
if (!tid)
err(1, "Invalid pid\n");
cmd_type = TASKSTATS_CMD_ATTR_PID;
- print_delays = 1;
break;
case 'v':
printf("debug on\n");
@@ -277,7 +298,7 @@ int main(int argc, char *argv[])
mypid = getpid();
id = get_family_id(nl_sd);
if (!id) {
- printf("Error getting family id, errno %d", errno);
+ fprintf(stderr, "Error getting family id, errno %d\n", errno);
goto err;
}
PRINTF("family id %d\n", id);
@@ -288,7 +309,7 @@ int main(int argc, char *argv[])
&cpumask, strlen(cpumask) + 1);
PRINTF("Sent register cpumask, retval %d\n", rc);
if (rc < 0) {
- printf("error sending register cpumask\n");
+ fprintf(stderr, "error sending register cpumask\n");
goto err;
}
}
@@ -298,7 +319,7 @@ int main(int argc, char *argv[])
cmd_type, &tid, sizeof(__u32));
PRINTF("Sent pid/tgid, retval %d\n", rc);
if (rc < 0) {
- printf("error sending tid/tgid cmd\n");
+ fprintf(stderr, "error sending tid/tgid cmd\n");
goto done;
}
}
@@ -310,13 +331,15 @@ int main(int argc, char *argv[])
PRINTF("received %d bytes\n", rep_len);
if (rep_len < 0) {
- printf("nonfatal reply error: errno %d\n", errno);
+ fprintf(stderr, "nonfatal reply error: errno %d\n",
+ errno);
continue;
}
if (msg.n.nlmsg_type == NLMSG_ERROR ||
!NLMSG_OK((&msg.n), rep_len)) {
struct nlmsgerr *err = NLMSG_DATA(&msg);
- printf("fatal reply error, errno %d\n", err->error);
+ fprintf(stderr, "fatal reply error, errno %d\n",
+ err->error);
goto done;
}
@@ -356,6 +379,8 @@ int main(int argc, char *argv[])
count++;
if (print_delays)
print_delayacct((struct taskstats *) NLA_DATA(na));
+ if (print_io_accounting)
+ print_ioacct((struct taskstats *) NLA_DATA(na));
if (fd) {
if (write(fd, NLA_DATA(na), na->nla_len) < 0) {
err(1,"write error\n");
@@ -365,7 +390,9 @@ int main(int argc, char *argv[])
goto done;
break;
default:
- printf("Unknown nested nla_type %d\n", na->nla_type);
+ fprintf(stderr, "Unknown nested"
+ " nla_type %d\n",
+ na->nla_type);
break;
}
len2 += NLA_ALIGN(na->nla_len);
@@ -374,7 +401,8 @@ int main(int argc, char *argv[])
break;
default:
- printf("Unknown nla_type %d\n", na->nla_type);
+ fprintf(stderr, "Unknown nla_type %d\n",
+ na->nla_type);
break;
}
na = (struct nlattr *) (GENLMSG_DATA(&msg) + len);
diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt
index dda7ecdde87..28d014714ab 100644
--- a/Documentation/arm/Samsung-S3C24XX/Overview.txt
+++ b/Documentation/arm/Samsung-S3C24XX/Overview.txt
@@ -76,6 +76,15 @@ Machines
A S3C2410 based PDA from Acer. There is a Wiki page at
http://handhelds.org/moin/moin.cgi/AcerN30Documentation .
+ AML M5900
+
+ American Microsystems' M5900
+
+ Nex Vision Nexcoder
+ Nex Vision Otom
+
+ Two machines by Nex Vision
+
Adding New Machines
-------------------
@@ -115,6 +124,10 @@ RTC
Support for the onboard RTC unit, including alarm function.
+ This has recently been upgraded to use the new RTC core,
+ and the module has been renamed to rtc-s3c to fit in with
+ the new rtc naming scheme.
+
Watchdog
--------
@@ -128,7 +141,7 @@ NAND
The current kernels now have support for the s3c2410 NAND
controller. If there are any problems the latest linux-mtd
- CVS can be found from http://www.linux-mtd.infradead.org/
+ code can be found from http://www.linux-mtd.infradead.org/
Serial
@@ -168,6 +181,21 @@ Suspend to RAM
See Suspend.txt for more information.
+SPI
+---
+
+ SPI drivers are available for both the in-built hardware
+ (although there is no DMA support yet) and a generic
+ GPIO based solution.
+
+
+LEDs
+----
+
+ There is support for GPIO based LEDs via a platform driver
+ in the LED subsystem.
+
+
Platform Data
-------------
diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
index c6c9a9c10d7..3adaace328a 100644
--- a/Documentation/block/biodoc.txt
+++ b/Documentation/block/biodoc.txt
@@ -946,6 +946,13 @@ elevator_merged_fn called when a request in the scheduler has been
scheduler for example, to reposition the request
if its sorting order has changed.
+elevator_allow_merge_fn called whenever the block layer determines
+ that a bio can be merged into an existing
+ request safely. The io scheduler may still
+ want to stop a merge at this point if it
+ results in some sort of conflict internally,
+ this hook allows it to do that.
+
elevator_dispatch_fn fills the dispatch queue with ready requests.
I/O schedulers are free to postpone requests by
not filling the dispatch queue unless @force
diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt
index 53245c429f7..debf6813934 100644
--- a/Documentation/cachetlb.txt
+++ b/Documentation/cachetlb.txt
@@ -179,10 +179,21 @@ Here are the routines, one by one:
lines associated with 'mm'.
This interface is used to handle whole address space
- page table operations such as what happens during
- fork, exit, and exec.
+ page table operations such as what happens during exit and exec.
+
+2) void flush_cache_dup_mm(struct mm_struct *mm)
+
+ This interface flushes an entire user address space from
+ the caches. That is, after running, there will be no cache
+ lines associated with 'mm'.
+
+ This interface is used to handle whole address space
+ page table operations such as what happens during fork.
+
+ This option is separate from flush_cache_mm to allow some
+ optimizations for VIPT caches.
-2) void flush_cache_range(struct vm_area_struct *vma,
+3) void flush_cache_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
Here we are flushing a specific range of (user) virtual
@@ -199,7 +210,7 @@ Here are the routines, one by one:
call flush_cache_page (see below) for each entry which may be
modified.
-3) void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
+4) void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
This time we need to remove a PAGE_SIZE sized range
from the cache. The 'vma' is the backing structure used by
@@ -220,7 +231,7 @@ Here are the routines, one by one:
This is used primarily during fault processing.
-4) void flush_cache_kmaps(void)
+5) void flush_cache_kmaps(void)
This routine need only be implemented if the platform utilizes
highmem. It will be called right before all of the kmaps
@@ -232,7 +243,7 @@ Here are the routines, one by one:
This routing should be implemented in asm/highmem.h
-5) void flush_cache_vmap(unsigned long start, unsigned long end)
+6) void flush_cache_vmap(unsigned long start, unsigned long end)
void flush_cache_vunmap(unsigned long start, unsigned long end)
Here in these two interfaces we are flushing a specific range
@@ -362,14 +373,15 @@ maps this page at its virtual address.
likely that you will need to flush the instruction cache
for copy_to_user_page().
- void flush_anon_page(struct page *page, unsigned long vmaddr)
+ void flush_anon_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vmaddr)
When the kernel needs to access the contents of an anonymous
page, it calls this function (currently only
get_user_pages()). Note: flush_dcache_page() deliberately
doesn't work for an anonymous page. The default
implementation is a nop (and should remain so for all coherent
architectures). For incoherent architectures, it should flush
- the cache of the page at vmaddr in the current user process.
+ the cache of the page at vmaddr.
void flush_kernel_dcache_page(struct page *page)
When the kernel needs to modify a user page is has obtained
diff --git a/Documentation/cdrom/packet-writing.txt b/Documentation/cdrom/packet-writing.txt
index 3d44c561fe6..7715d2247c4 100644
--- a/Documentation/cdrom/packet-writing.txt
+++ b/Documentation/cdrom/packet-writing.txt
@@ -90,6 +90,41 @@ Notes
to create an ext2 filesystem on the disc.
+Using the pktcdvd sysfs interface
+---------------------------------
+
+Since Linux 2.6.19, the pktcdvd module has a sysfs interface
+and can be controlled by it. For example the "pktcdvd" tool uses
+this interface. (see http://people.freenet.de/BalaGi#pktcdvd )
+
+"pktcdvd" works similar to "pktsetup", e.g.:
+
+ # pktcdvd -a dev_name /dev/hdc
+ # mkudffs /dev/pktcdvd/dev_name
+ # mount -t udf -o rw,noatime /dev/pktcdvd/dev_name /dvdram
+ # cp files /dvdram
+ # umount /dvdram
+ # pktcdvd -r dev_name
+
+
+For a description of the sysfs interface look into the file:
+
+ Documentation/ABI/testing/sysfs-block-pktcdvd
+
+
+Using the pktcdvd debugfs interface
+-----------------------------------
+
+To read pktcdvd device infos in human readable form, do:
+
+ # cat /debug/pktcdvd/pktcdvd[0-7]/info
+
+For a description of the debugfs interface look into the file:
+
+ Documentation/ABI/testing/debugfs-pktcdvd
+
+
+
Links
-----
diff --git a/Documentation/cpu-freq/core.txt b/Documentation/cpu-freq/core.txt
index 29b3f9ffc66..ce0666e5103 100644
--- a/Documentation/cpu-freq/core.txt
+++ b/Documentation/cpu-freq/core.txt
@@ -24,7 +24,7 @@ Contents:
1. General Information
=======================
-The CPUFreq core code is located in linux/kernel/cpufreq.c. This
+The CPUFreq core code is located in drivers/cpufreq/cpufreq.c. This
cpufreq code offers a standardized interface for the CPUFreq
architecture drivers (those pieces of code that do actual
frequency transitions), as well as to "notifiers". These are device
diff --git a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt
index 5a03a2801d6..e41a79aa71c 100644
--- a/Documentation/crypto/api-intro.txt
+++ b/Documentation/crypto/api-intro.txt
@@ -193,6 +193,7 @@ Original developers of the crypto algorithms:
Kartikey Mahendra Bhatt (CAST6)
Jon Oberheide (ARC4)
Jouni Malinen (Michael MIC)
+ NTT(Nippon Telegraph and Telephone Corporation) (Camellia)
SHA1 algorithm contributors:
Jean-Francois Dive
@@ -246,6 +247,9 @@ Tiger algorithm contributors:
VIA PadLock contributors:
Michal Ludvig
+Camellia algorithm contributors:
+ NTT(Nippon Telegraph and Telephone Corporation) (Camellia)
+
Generic scatterwalk code by Adam J. Richter <adam@yggdrasil.com>
Please send any credits updates or corrections to:
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
new file mode 100644
index 00000000000..5163b85308f
--- /dev/null
+++ b/Documentation/driver-model/devres.txt
@@ -0,0 +1,268 @@
+Devres - Managed Device Resource
+================================
+
+Tejun Heo <teheo@suse.de>
+
+First draft 10 January 2007
+
+
+1. Intro : Huh? Devres?
+2. Devres : Devres in a nutshell
+3. Devres Group : Group devres'es and release them together
+4. Details : Life time rules, calling context, ...
+5. Overhead : How much do we have to pay for this?
+6. List of managed interfaces : Currently implemented managed interfaces
+
+
+ 1. Intro
+ --------
+
+devres came up while trying to convert libata to use iomap. Each
+iomapped address should be kept and unmapped on driver detach. For
+example, a plain SFF ATA controller (that is, good old PCI IDE) in
+native mode makes use of 5 PCI BARs and all of them should be
+maintained.
+
+As with many other device drivers, libata low level drivers have
+sufficient bugs in ->remove and ->probe failure path. Well, yes,
+that's probably because libata low level driver developers are lazy
+bunch, but aren't all low level driver developers? After spending a
+day fiddling with braindamaged hardware with no document or
+braindamaged document, if it's finally working, well, it's working.
+
+For one reason or another, low level drivers don't receive as much
+attention or testing as core code, and bugs on driver detach or
+initilaization failure doesn't happen often enough to be noticeable.
+Init failure path is worse because it's much less travelled while
+needs to handle multiple entry points.
+
+So, many low level drivers end up leaking resources on driver detach
+and having half broken failure path implementation in ->probe() which
+would leak resources or even cause oops when failure occurs. iomap
+adds more to this mix. So do msi and msix.
+
+
+ 2. Devres
+ ---------
+
+devres is basically linked list of arbitrarily sized memory areas
+associated with a struct device. Each devres entry is associated with
+a release function. A devres can be released in several ways. No
+matter what, all devres entries are released on driver detach. On
+release, the associated release function is invoked and then the
+devres entry is freed.
+
+Managed interface is created for resources commonly used by device
+drivers using devres. For example, coherent DMA memory is acquired
+using dma_alloc_coherent(). The managed version is called
+dmam_alloc_coherent(). It is identical to dma_alloc_coherent() except
+for the DMA memory allocated using it is managed and will be
+automatically released on driver detach. Implementation looks like
+the following.
+
+ struct dma_devres {
+ size_t size;
+ void *vaddr;
+ dma_addr_t dma_handle;
+ };
+
+ static void dmam_coherent_release(struct device *dev, void *res)
+ {
+ struct dma_devres *this = res;
+
+ dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle);
+ }
+
+ dmam_alloc_coherent(dev, size, dma_handle, gfp)
+ {
+ struct dma_devres *dr;
+ void *vaddr;
+
+ dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp);
+ ...
+
+ /* alloc DMA memory as usual */
+ vaddr = dma_alloc_coherent(...);
+ ...
+
+ /* record size, vaddr, dma_handle in dr */
+ dr->vaddr = vaddr;
+ ...
+
+ devres_add(dev, dr);
+
+ return vaddr;
+ }
+
+If a driver uses dmam_alloc_coherent(), the area is guaranteed to be
+freed whether initialization fails half-way or the device gets
+detached. If most resources are acquired using managed interface, a
+driver can have much simpler init and exit code. Init path basically
+looks like the following.
+
+ my_init_one()
+ {
+ struct mydev *d;
+
+ d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
+
+ d->ring = dmam_alloc_coherent(...);
+ if (!d->ring)
+ return -ENOMEM;
+
+ if (check something)
+ return -EINVAL;
+ ...
+
+ return register_to_upper_layer(d);
+ }
+
+And exit path,
+
+ my_remove_one()
+ {
+ unregister_from_upper_layer(d);
+ shutdown_my_hardware();
+ }
+
+As shown above, low level drivers can be simplified a lot by using
+devres. Complexity is shifted from less maintained low level drivers
+to better maintained higher layer. Also, as init failure path is
+shared with exit path, both can get more testing.
+
+
+ 3. Devres group
+ ---------------
+
+Devres entries can be grouped using devres group. When a group is
+released, all contained normal devres entries and properly nested
+groups are released. One usage is to rollback series of acquired
+resources on failure. For example,
+
+ if (!devres_open_group(dev, NULL, GFP_KERNEL))
+ return -ENOMEM;
+
+ acquire A;
+ if (failed)
+ goto err;
+
+ acquire B;
+ if (failed)
+ goto err;
+ ...
+
+ devres_remove_group(dev, NULL);
+ return 0;
+
+ err:
+ devres_release_group(dev, NULL);
+ return err_code;
+
+As resource acquision failure usually means probe failure, constructs
+like above are usually useful in midlayer driver (e.g. libata core
+layer) where interface function shouldn't have side effect on failure.
+For LLDs, just returning error code suffices in most cases.
+
+Each group is identified by void *id. It can either be explicitly
+specified by @id argument to devres_open_group() or automatically
+created by passing NULL as @id as in the above example. In both
+cases, devres_open_group() returns the group's id. The returned id
+can be passed to other devres functions to select the target group.
+If NULL is given to those functions, the latest open group is
+selected.
+
+For example, you can do something like the following.
+
+ int my_midlayer_create_something()
+ {
+ if (!devres_open_group(dev, my_midlayer_create_something, GFP_KERNEL))
+ return -ENOMEM;
+
+ ...
+
+ devres_close_group(dev, my_midlayer_something);
+ return 0;
+ }
+
+ void my_midlayer_destroy_something()
+ {
+ devres_release_group(dev, my_midlayer_create_soemthing);
+ }
+
+
+ 4. Details
+ ----------
+
+Lifetime of a devres entry begins on devres allocation and finishes
+when it is released or destroyed (removed and freed) - no reference
+counting.
+
+devres core guarantees atomicity to all basic devres operations and
+has support for single-instance devres types (atomic
+lookup-and-add-if-not-found). Other than that, synchronizing
+concurrent accesses to allocated devres data is caller's
+responsibility. This is usually non-issue because bus ops and
+resource allocations already do the job.
+
+For an example of single-instance devres type, read pcim_iomap_table()
+in lib/iomap.c.
+
+All devres interface functions can be called without context if the
+right gfp mask is given.
+
+
+ 5. Overhead
+ -----------
+
+Each devres bookkeeping info is allocated together with requested data
+area. With debug option turned off, bookkeeping info occupies 16
+bytes on 32bit machines and 24 bytes on 64bit (three pointers rounded
+up to ull alignment). If singly linked list is used, it can be
+reduced to two pointers (8 bytes on 32bit, 16 bytes on 64bit).
+
+Each devres group occupies 8 pointers. It can be reduced to 6 if
+singly linked list is used.
+
+Memory space overhead on ahci controller with two ports is between 300
+and 400 bytes on 32bit machine after naive conversion (we can
+certainly invest a bit more effort into libata core layer).
+
+
+ 6. List of managed interfaces
+ -----------------------------
+
+IO region
+ devm_request_region()
+ devm_request_mem_region()
+ devm_release_region()
+ devm_release_mem_region()
+
+IRQ
+ devm_request_irq()
+ devm_free_irq()
+
+DMA
+ dmam_alloc_coherent()
+ dmam_free_coherent()
+ dmam_alloc_noncoherent()
+ dmam_free_noncoherent()
+ dmam_declare_coherent_memory()
+ dmam_pool_create()
+ dmam_pool_destroy()
+
+PCI
+ pcim_enable_device() : after success, all PCI ops become managed
+ pcim_pin_device() : keep PCI device enabled after release
+
+IOMAP
+ devm_ioport_map()
+ devm_ioport_unmap()
+ devm_ioremap()
+ devm_ioremap_nocache()
+ devm_iounmap()
+ pcim_iomap()
+ pcim_iounmap()
+ pcim_iomap_table() : array of mapped addresses indexed by BAR
+ pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
diff --git a/Documentation/dvb/cards.txt b/Documentation/dvb/cards.txt
index ca58e339d85..cc09187a5db 100644
--- a/Documentation/dvb/cards.txt
+++ b/Documentation/dvb/cards.txt
@@ -22,10 +22,10 @@ o Frontends drivers:
- ves1x93 : Alps BSRV2 (ves1893 demodulator) and dbox2 (ves1993)
- cx24110 : Conexant HM1221/HM1811 (cx24110 or cx24106 demod, cx24108 PLL)
- grundig_29504-491 : Grundig 29504-491 (Philips TDA8083 demodulator), tsa5522 PLL
- - mt312 : Zarlink mt312 or Mitel vp310 demodulator, sl1935 or tsa5059 PLL
+ - mt312 : Zarlink mt312 or Mitel vp310 demodulator, sl1935 or tsa5059 PLLi, Technisat Sky2Pc with bios Rev. 2.3
- stv0299 : Alps BSRU6 (tsa5059 PLL), LG TDQB-S00x (tsa5059 PLL),
LG TDQF-S001F (sl1935 PLL), Philips SU1278 (tua6100 PLL),
- Philips SU1278SH (tsa5059 PLL), Samsung TBMU24112IMB
+ Philips SU1278SH (tsa5059 PLL), Samsung TBMU24112IMB, Technisat Sky2Pc with bios Rev. 2.6
DVB-C:
- ves1820 : various (ves1820 demodulator, sp5659c or spXXXX PLL)
- at76c651 : Atmel AT76c651(B) with DAT7021 PLL
diff --git a/Documentation/fault-injection/failcmd.sh b/Documentation/fault-injection/failcmd.sh
new file mode 100644
index 00000000000..63177aba810
--- /dev/null
+++ b/Documentation/fault-injection/failcmd.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+echo 1 > /proc/self/make-it-fail
+exec $*
diff --git a/Documentation/fault-injection/failmodule.sh b/Documentation/fault-injection/failmodule.sh
new file mode 100644
index 00000000000..474a8b971f9
--- /dev/null
+++ b/Documentation/fault-injection/failmodule.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+#
+# Usage: failmodule <failname> <modulename> [stacktrace-depth]
+#
+# <failname>: "failslab", "fail_alloc_page", or "fail_make_request"
+#
+# <modulename>: module name that you want to inject faults.
+#
+# [stacktrace-depth]: the maximum number of stacktrace walking allowed
+#
+
+STACKTRACE_DEPTH=5
+if [ $# -gt 2 ]; then
+ STACKTRACE_DEPTH=$3
+fi
+
+if [ ! -d /debug/$1 ]; then
+ echo "Fault-injection $1 does not exist" >&2
+ exit 1
+fi
+if [ ! -d /sys/module/$2 ]; then
+ echo "Module $2 does not exist" >&2
+ exit 1
+fi
+
+# Disable any fault injection
+echo 0 > /debug/$1/stacktrace-depth
+
+echo `cat /sys/module/$2/sections/.text` > /debug/$1/require-start
+echo `cat /sys/module/$2/sections/.exit.text` > /debug/$1/require-end
+echo $STACKTRACE_DEPTH > /debug/$1/stacktrace-depth
diff --git a/Documentation/fault-injection/fault-injection.txt b/Documentation/fault-injection/fault-injection.txt
new file mode 100644
index 00000000000..b7ca560b934
--- /dev/null
+++ b/Documentation/fault-injection/fault-injection.txt
@@ -0,0 +1,225 @@
+Fault injection capabilities infrastructure
+===========================================
+
+See also drivers/md/faulty.c and "every_nth" module option for scsi_debug.
+
+
+Available fault injection capabilities
+--------------------------------------
+
+o failslab
+
+ injects slab allocation failures. (kmalloc(), kmem_cache_alloc(), ...)
+
+o fail_page_alloc
+
+ injects page allocation failures. (alloc_pages(), get_free_pages(), ...)
+
+o fail_make_request
+
+ injects disk IO errors on devices permitted by setting
+ /sys/block/<device>/make-it-fail or
+ /sys/block/<device>/<partition>/make-it-fail. (generic_make_request())
+
+Configure fault-injection capabilities behavior
+-----------------------------------------------
+
+o debugfs entries
+
+fault-inject-debugfs kernel module provides some debugfs entries for runtime
+configuration of fault-injection capabilities.
+
+- /debug/fail*/probability:
+
+ likelihood of failure injection, in percent.
+ Format: <percent>
+
+ Note that one-failure-per-hundred is a very high error rate
+ for some testcases. Consider setting probability=100 and configure
+ /debug/fail*/interval for such testcases.
+
+- /debug/fail*/interval:
+
+ specifies the interval between failures, for calls to
+ should_fail() that pass all the other tests.
+
+ Note that if you enable this, by setting interval>1, you will
+ probably want to set probability=100.
+
+- /debug/fail*/times:
+
+ specifies how many times failures may happen at most.
+ A value of -1 means "no limit".
+
+- /debug/fail*/space:
+
+ specifies an initial resource "budget", decremented by "size"
+ on each call to should_fail(,size). Failure injection is
+ suppressed until "space" reaches zero.
+
+- /debug/fail*/verbose
+
+ Format: { 0 | 1 | 2 }
+ specifies the verbosity of the messages when failure is
+ injected. '0' means no messages; '1' will print only a single
+ log line per failure; '2' will print a call trace too -- useful
+ to debug the problems revealed by fault injection.
+
+- /debug/fail*/task-filter:
+
+ Format: { 'Y' | 'N' }
+ A value of 'N' disables filtering by process (default).
+ Any positive value limits failures to only processes indicated by
+ /proc/<pid>/make-it-fail==1.
+
+- /debug/fail*/require-start:
+- /debug/fail*/require-end:
+- /debug/fail*/reject-start:
+- /debug/fail*/reject-end:
+
+ specifies the range of virtual addresses tested during
+ stacktrace walking. Failure is injected only if some caller
+ in the walked stacktrace lies within the required range, and
+ none lies within the rejected range.
+ Default required range is [0,ULONG_MAX) (whole of virtual address space).
+ Default rejected range is [0,0).
+
+- /debug/fail*/stacktrace-depth:
+
+ specifies the maximum stacktrace depth walked during search
+ for a caller within [require-start,require-end) OR
+ [reject-start,reject-end).
+
+- /debug/fail_page_alloc/ignore-gfp-highmem:
+
+ Format: { 'Y' | 'N' }
+ default is 'N', setting it to 'Y' won't inject failures into
+ highmem/user allocations.
+
+- /debug/failslab/ignore-gfp-wait:
+- /debug/fail_page_alloc/ignore-gfp-wait:
+
+ Format: { 'Y' | 'N' }
+ default is 'N', setting it to 'Y' will inject failures
+ only into non-sleep allocations (GFP_ATOMIC allocations).
+
+o Boot option
+
+In order to inject faults while debugfs is not available (early boot time),
+use the boot option:
+
+ failslab=
+ fail_page_alloc=
+ fail_make_request=<interval>,<probability>,<space>,<times>
+
+How to add new fault injection capability
+-----------------------------------------
+
+o #include <linux/fault-inject.h>
+
+o define the fault attributes
+
+ DECLARE_FAULT_INJECTION(name);
+
+ Please see the definition of struct fault_attr in fault-inject.h
+ for details.
+
+o provide a way to configure fault attributes
+
+- boot option
+
+ If you need to enable the fault injection capability from boot time, you can
+ provide boot option to configure it. There is a helper function for it:
+
+ setup_fault_attr(attr, str);
+
+- debugfs entries
+
+ failslab, fail_page_alloc, and fail_make_request use this way.
+ Helper functions:
+
+ init_fault_attr_entries(entries, attr, name);
+ void cleanup_fault_attr_entries(entries);
+
+- module parameters
+
+ If the scope of the fault injection capability is limited to a
+ single kernel module, it is better to provide module parameters to
+ configure the fault attributes.
+
+o add a hook to insert failures
+
+ Upon should_fail() returning true, client code should inject a failure.
+
+ should_fail(attr, size);
+
+Application Examples
+--------------------
+
+o inject slab allocation failures into module init/cleanup code
+
+------------------------------------------------------------------------------
+#!/bin/bash
+
+FAILCMD=Documentation/fault-injection/failcmd.sh
+BLACKLIST="root_plug evbug"
+
+FAILNAME=failslab
+echo Y > /debug/$FAILNAME/task-filter
+echo 10 > /debug/$FAILNAME/probability
+echo 100 > /debug/$FAILNAME/interval
+echo -1 > /debug/$FAILNAME/times
+echo 2 > /debug/$FAILNAME/verbose
+echo 1 > /debug/$FAILNAME/ignore-gfp-wait
+
+blacklist()
+{
+ echo $BLACKLIST | grep $1 > /dev/null 2>&1
+}
+
+oops()
+{
+ dmesg | grep BUG > /dev/null 2>&1
+}
+
+find /lib/modules/`uname -r` -name '*.ko' -exec basename {} .ko \; |
+ while read i
+ do
+ oops && exit 1
+
+ if ! blacklist $i
+ then
+ echo inserting $i...
+ bash $FAILCMD modprobe $i
+ fi
+ done
+
+lsmod | awk '{ if ($3 == 0) { print $1 } }' |
+ while read i
+ do
+ oops && exit 1
+
+ if ! blacklist $i
+ then
+ echo removing $i...
+ bash $FAILCMD modprobe -r $i
+ fi
+ done
+
+------------------------------------------------------------------------------
+
+o inject slab allocation failures only for a specific module
+
+------------------------------------------------------------------------------
+#!/bin/bash
+
+FAILMOD=Documentation/fault-injection/failmodule.sh
+
+echo injecting errors into the module $1...
+
+modprobe $1
+bash $FAILMOD failslab $1 10
+echo 25 > /debug/failslab/probability
+
+------------------------------------------------------------------------------
+
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 46f2a559b27..fa844fd7bde 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -50,22 +50,6 @@ Who: Dan Dennedy <dan@dennedy.org>, Stefan Richter <stefanr@s5r6.in-berlin.de>
---------------------------
-What: ieee1394 core's unused exports (CONFIG_IEEE1394_EXPORT_FULL_API)
-When: January 2007
-Why: There are no projects known to use these exported symbols, except
- dfg1394 (uses one symbol whose functionality is core-internal now).
-Who: Stefan Richter <stefanr@s5r6.in-berlin.de>
-
----------------------------
-
-What: ieee1394's *_oui sysfs attributes (CONFIG_IEEE1394_OUI_DB)
-When: January 2007
-Files: drivers/ieee1394/: oui.db, oui2c.sh
-Why: big size, little value
-Who: Stefan Richter <stefanr@s5r6.in-berlin.de>
-
----------------------------
-
What: Video4Linux API 1 ioctls and video_decoder.h from Video devices.
When: December 2006
Why: V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
@@ -151,15 +135,6 @@ Who: Thomas Gleixner <tglx@linutronix.de>
---------------------------
-What: I2C interface of the it87 driver
-When: January 2007
-Why: The ISA interface is faster and should be always available. The I2C
- probing is also known to cause trouble in at least one case (see
- bug #5889.)
-Who: Jean Delvare <khali@linux-fr.org>
-
----------------------------
-
What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
(temporary transition config option provided until then)
The transition config option will also be removed at the same time.
@@ -195,18 +170,6 @@ Who: Greg Kroah-Hartman <gregkh@suse.de>
---------------------------
-What: find_trylock_page
-When: January 2007
-Why: The interface no longer has any callers left in the kernel. It
- is an odd interface (compared with other find_*_page functions), in
- that it does not take a refcount to the page, only the page lock.
- It should be replaced with find_get_page or find_lock_page if possible.
- This feature removal can be reevaluated if users of the interface
- cannot cleanly use something else.
-Who: Nick Piggin <npiggin@suse.de>
-
----------------------------
-
What: Interrupt only SA_* flags
When: Januar 2007
Why: The interrupt related SA_* flags are replaced by IRQF_* to move them
@@ -216,33 +179,6 @@ Who: Thomas Gleixner <tglx@linutronix.de>
---------------------------
-What: i2c-ite and i2c-algo-ite drivers
-When: September 2006
-Why: These drivers never compiled since they were added to the kernel
- tree 5 years ago. This feature removal can be reevaluated if
- someone shows interest in the drivers, fixes them and takes over
- maintenance.
- http://marc.theaimsgroup.com/?l=linux-mips&m=115040510817448
-Who: Jean Delvare <khali@linux-fr.org>
-
----------------------------
-
-What: Bridge netfilter deferred IPv4/IPv6 output hook calling
-When: January 2007
-Why: The deferred output hooks are a layering violation causing unusual
- and broken behaviour on bridge devices. Examples of things they
- break include QoS classifation using the MARK or CLASSIFY targets,
- the IPsec policy match and connection tracking with VLANs on a
- bridge. Their only use is to enable bridge output port filtering
- within iptables with the physdev match, which can also be done by
- combining iptables and ebtables using netfilter marks. Until it
- will get removed the hook deferral is disabled by default and is
- only enabled when needed.
-
-Who: Patrick McHardy <kaber@trash.net>
-
----------------------------
-
What: PHYSDEVPATH, PHYSDEVBUS, PHYSDEVDRIVER in the uevent environment
When: October 2008
Why: The stacking of class devices makes these values misleading and
@@ -262,6 +198,23 @@ Who: Jean Delvare <khali@linux-fr.org>
---------------------------
+What: i2c_adapter.dev
+ i2c_adapter.list
+When: July 2007
+Why: Superfluous, given i2c_adapter.class_dev:
+ * The "dev" was a stand-in for the physical device node that legacy
+ drivers would not have; but now it's almost always present. Any
+ remaining legacy drivers must upgrade (they now trigger warnings).
+ * The "list" duplicates class device children.
+ The delay in removing this is so upgraded lm_sensors and libsensors
+ can get deployed. (Removal causes minor changes in the sysfs layout,
+ notably the location of the adapter type name and parenting the i2c
+ client hardware directly from their controller.)
+Who: Jean Delvare <khali@linux-fr.org>,
+ David Brownell <dbrownell@users.sourceforge.net>
+
+---------------------------
+
What: IPv4 only connection tracking/NAT/helpers
When: 2.6.22
Why: The new layer 3 independant connection tracking replaces the old
@@ -270,3 +223,92 @@ Why: The new layer 3 independant connection tracking replaces the old
Who: Patrick McHardy <kaber@trash.net>
---------------------------
+
+What: ACPI hooks (X86_SPEEDSTEP_CENTRINO_ACPI) in speedstep-centrino driver
+When: December 2006
+Why: Speedstep-centrino driver with ACPI hooks and acpi-cpufreq driver are
+ functionally very much similar. They talk to ACPI in same way. Only
+ difference between them is the way they do frequency transitions.
+ One uses MSRs and the other one uses IO ports. Functionaliy of
+ speedstep_centrino with ACPI hooks is now merged into acpi-cpufreq.
+ That means one common driver will support all Intel Enhanced Speedstep
+ capable CPUs. That means less confusion over name of
+ speedstep-centrino driver (with that driver supposed to be used on
+ non-centrino platforms). That means less duplication of code and
+ less maintenance effort and no possibility of these two drivers
+ going out of sync.
+ Current users of speedstep_centrino with ACPI hooks are requested to
+ switch over to acpi-cpufreq driver. speedstep-centrino will continue
+ to work using older non-ACPI static table based scheme even after this
+ date.
+
+Who: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+
+---------------------------
+
+<<<<<<< test:Documentation/feature-removal-schedule.txt
+What: ACPI hotkey driver (CONFIG_ACPI_HOTKEY)
+When: 2.6.21
+Why: hotkey.c was an attempt to consolidate multiple drivers that use
+ ACPI to implement hotkeys. However, hotkeys are not documented
+ in the ACPI specification, so the drivers used undocumented
+ vendor-specific hooks and turned out to be more different than
+ the same.
+
+ Further, the keys and the features supplied by each platform
+ are different, so there will always be a need for
+ platform-specific drivers.
+
+ So the new plan is to delete hotkey.c and instead, work on the
+ platform specific drivers to try to make them look the same
+ to the user when they supply the same features.
+
+ hotkey.c has always depended on CONFIG_EXPERIMENTAL
+
+Who: Len Brown <len.brown@intel.com>
+
+---------------------------
+
+What: /sys/firmware/acpi/namespace
+When: 2.6.21
+Why: The ACPI namespace is effectively the symbol list for
+ the BIOS. The device names are completely arbitrary
+ and have no place being exposed to user-space.
+
+ For those interested in the BIOS ACPI namespace,
+ the BIOS can be extracted and disassembled with acpidump
+ and iasl as documented in the pmtools package here:
+ http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/utils
+Who: Len Brown <len.brown@intel.com>
+
+---------------------------
+
+What: ACPI procfs interface
+When: July 2007
+Why: After ACPI sysfs conversion, ACPI attributes will be duplicated
+ in sysfs and the ACPI procfs interface should be removed.
+Who: Zhang Rui <rui.zhang@intel.com>
+
+---------------------------
+
+What: /proc/acpi/button
+When: August 2007
+Why: /proc/acpi/button has been replaced by events to the input layer
+ since 2.6.20.
+Who: Len Brown <len.brown@intel.com>
+
+---------------------------
+
+What: JFFS (version 1)
+When: 2.6.21
+Why: Unmaintained for years, superceded by JFFS2 for years.
+Who: Jeff Garzik <jeff@garzik.org>
+
+---------------------------
+
+What: sk98lin network driver
+When: July 2007
+Why: In kernel tree version of driver is unmaintained. Sk98lin driver
+ replaced by the skge driver.
+Who: Stephen Hemminger <shemminger@osdl.org>
+
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt
index 43b89c214d2..4d075a4558f 100644
--- a/Documentation/filesystems/9p.txt
+++ b/Documentation/filesystems/9p.txt
@@ -73,8 +73,22 @@ OPTIONS
RESOURCES
=========
-The Linux version of the 9p server is now maintained under the npfs project
-on sourceforge (http://sourceforge.net/projects/npfs).
+Our current recommendation is to use Inferno (http://www.vitanuova.com/inferno)
+as the 9p server. You can start a 9p server under Inferno by issuing the
+following command:
+ ; styxlisten -A tcp!*!564 export '#U*'
+
+The -A specifies an unauthenticated export. The 564 is the port # (you may
+have to choose a higher port number if running as a normal user). The '#U*'
+specifies exporting the root of the Linux name space. You may specify a
+subset of the namespace by extending the path: '#U*'/tmp would just export
+/tmp. For more information, see the Inferno manual pages covering styxlisten
+and export.
+
+A Linux version of the 9p server is now maintained under the npfs project
+on sourceforge (http://sourceforge.net/projects/npfs). There is also a
+more stable single-threaded version of the server (named spfs) available from
+the same CVS repository.
There are user and developer mailing lists available through the v9fs project
on sourceforge (http://sourceforge.net/projects/v9fs).
@@ -96,5 +110,5 @@ STATUS
The 2.6 kernel support is working on PPC and x86.
-PLEASE USE THE SOURCEFORGE BUG-TRACKER TO REPORT PROBLEMS.
+PLEASE USE THE KERNEL BUGZILLA TO REPORT PROBLEMS. (http://bugzilla.kernel.org)
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 790ef6fbe49..28bfea75bcf 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -171,6 +171,7 @@ prototypes:
int (*releasepage) (struct page *, int);
int (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
loff_t offset, unsigned long nr_segs);
+ int (*launder_page) (struct page *);
locking rules:
All except set_page_dirty may block
@@ -188,6 +189,7 @@ bmap: yes
invalidatepage: no yes
releasepage: no yes
direct_IO: no
+launder_page: no yes
->prepare_write(), ->commit_write(), ->sync_page() and ->readpage()
may be called from the request handler (/dev/loop).
@@ -281,6 +283,12 @@ buffers from the page in preparation for freeing it. It returns zero to
indicate that the buffers are (or may be) freeable. If ->releasepage is zero,
the kernel assumes that the fs has no private interest in the buffers.
+ ->launder_page() may be called prior to releasing a page if
+it is still found to be dirty. It returns zero if the page was successfully
+cleaned, or an error value if not. Note that in order to prevent the page
+getting mapped back in and redirtied, it needs to be kept locked
+across the entire operation.
+
Note: currently almost all instances of address_space methods are
using BKL for internal serialization and that's one of the worst sources
of contention. Normally they are calling library functions (in fs/buffer.c)
diff --git a/Documentation/filesystems/bfs.txt b/Documentation/filesystems/bfs.txt
index d2841e0bcf0..ea825e178e7 100644
--- a/Documentation/filesystems/bfs.txt
+++ b/Documentation/filesystems/bfs.txt
@@ -54,4 +54,4 @@ The first 4 bytes should be 0x1badface.
If you have any patches, questions or suggestions regarding this BFS
implementation please contact the author:
-Tigran A. Aivazian <tigran@veritas.com>
+Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
diff --git a/Documentation/filesystems/fuse.txt b/Documentation/filesystems/fuse.txt
index 345392c4cae..397a41adb4c 100644
--- a/Documentation/filesystems/fuse.txt
+++ b/Documentation/filesystems/fuse.txt
@@ -94,8 +94,8 @@ Mount options
filesystem is free to implement it's access policy or leave it to
the underlying file access mechanism (e.g. in case of network
filesystems). This option enables permission checking, restricting
- access based on file mode. This is option is usually useful
- together with the 'allow_other' mount option.
+ access based on file mode. It is usually useful together with the
+ 'allow_other' mount option.
'allow_other'
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
index 13ba649bda7..81779068b09 100644
--- a/Documentation/filesystems/ntfs.txt
+++ b/Documentation/filesystems/ntfs.txt
@@ -457,6 +457,8 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
+2.1.28:
+ - Fix a deadlock.
2.1.27:
- Implement page migration support so the kernel can move memory used
by NTFS files and directories around for management purposes.
diff --git a/Documentation/filesystems/ocfs2.txt b/Documentation/filesystems/ocfs2.txt
index af6defd10cb..8ccf0c1b58e 100644
--- a/Documentation/filesystems/ocfs2.txt
+++ b/Documentation/filesystems/ocfs2.txt
@@ -54,3 +54,6 @@ errors=panic Panic and halt the machine if an error occurs.
intr (*) Allow signals to interrupt cluster operations.
nointr Do not allow signals to interrupt cluster
operations.
+atime_quantum=60(*) OCFS2 will not update atime unless this number
+ of seconds has passed since the last update.
+ Set to zero to always update atime.
diff --git a/Documentation/hwmon/f71805f b/Documentation/hwmon/f71805f
index 2ca69df669c..bfd0f154959 100644
--- a/Documentation/hwmon/f71805f
+++ b/Documentation/hwmon/f71805f
@@ -6,6 +6,10 @@ Supported chips:
Prefix: 'f71805f'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Provided by Fintek on request
+ * Fintek F71872F/FG
+ Prefix: 'f71872f'
+ Addresses scanned: none, address read from Super I/O config space
+ Datasheet: Provided by Fintek on request
Author: Jean Delvare <khali@linux-fr.org>
@@ -13,8 +17,8 @@ Thanks to Denis Kieft from Barracuda Networks for the donation of a
test system (custom Jetway K8M8MS motherboard, with CPU and RAM) and
for providing initial documentation.
-Thanks to Kris Chen from Fintek for answering technical questions and
-providing additional documentation.
+Thanks to Kris Chen and Aaron Huang from Fintek for answering technical
+questions and providing additional documentation.
Thanks to Chris Lin from Jetway for providing wiring schematics and
answering technical questions.
@@ -28,8 +32,11 @@ capabilities. It can monitor up to 9 voltages (counting its own power
source), 3 fans and 3 temperature sensors.
This chip also has fan controlling features, using either DC or PWM, in
-three different modes (one manual, two automatic). The driver doesn't
-support these features yet.
+three different modes (one manual, two automatic).
+
+The Fintek F71872F/FG Super I/O chip is almost the same, with two
+additional internal voltages monitored (VSB and battery). It also features
+6 VID inputs. The VID inputs are not yet supported by this driver.
The driver assumes that no more than one chip is present, which seems
reasonable.
@@ -42,7 +49,8 @@ Voltages are sampled by an 8-bit ADC with a LSB of 8 mV. The supported
range is thus from 0 to 2.040 V. Voltage values outside of this range
need external resistors. An exception is in0, which is used to monitor
the chip's own power source (+3.3V), and is divided internally by a
-factor 2.
+factor 2. For the F71872F/FG, in9 (VSB) and in10 (battery) are also
+divided internally by a factor 2.
The two LSB of the voltage limit registers are not used (always 0), so
you can only set the limits in steps of 32 mV (before scaling).
@@ -61,9 +69,12 @@ in5 VIN5 +12V 200K 20K 11.00 1.05 V
in6 VIN6 VCC1.5V 10K - 1.00 1.50 V
in7 VIN7 VCORE 10K - 1.00 ~1.40 V (1)
in8 VIN8 VSB5V 200K 47K 1.00 0.95 V
+in10 VSB VSB3.3V int. int. 2.00 1.65 V (3)
+in9 VBAT VBATTERY int. int. 2.00 1.50 V (3)
(1) Depends on your hardware setup.
(2) Obviously not correct, swapping R1 and R2 would make more sense.
+(3) F71872F/FG only.
These values can be used as hints at best, as motherboard manufacturers
are free to use a completely different setup. As a matter of fact, the
@@ -103,3 +114,38 @@ sensor. Each channel can be used for connecting either a thermal diode
or a thermistor. The driver reports the currently selected mode, but
doesn't allow changing it. In theory, the BIOS should have configured
everything properly.
+
+
+Fan Control
+-----------
+
+Both PWM (pulse-width modulation) and DC fan speed control methods are
+supported. The right one to use depends on external circuitry on the
+motherboard, so the driver assumes that the BIOS set the method
+properly. The driver will report the method, but won't let you change
+it.
+
+When the PWM method is used, you can select the operating frequency,
+from 187.5 kHz (default) to 31 Hz. The best frequency depends on the
+fan model. As a rule of thumb, lower frequencies seem to give better
+control, but may generate annoying high-pitch noise. Fintek recommends
+not going below 1 kHz, as the fan tachometers get confused by lower
+frequencies as well.
+
+When the DC method is used, Fintek recommends not going below 5 V, which
+corresponds to a pwm value of 106 for the driver. The driver doesn't
+enforce this limit though.
+
+Three different fan control modes are supported:
+
+* Manual mode
+ You ask for a specific PWM duty cycle or DC voltage.
+
+* Fan speed mode
+ You ask for a specific fan speed. This mode assumes that pwm1
+ corresponds to fan1, pwm2 to fan2 and pwm3 to fan3.
+
+* Temperature mode
+ You define 3 temperature/fan speed trip points, and the fan speed is
+ adjusted depending on the measured temperature, using interpolation.
+ This mode is not yet supported by the driver.
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87
index e783fd62e30..74a80992d23 100644
--- a/Documentation/hwmon/it87
+++ b/Documentation/hwmon/it87
@@ -9,8 +9,7 @@ Supported chips:
http://www.ite.com.tw/
* IT8712F
Prefix: 'it8712'
- Addresses scanned: I2C 0x2d
- from Super I/O config space (8 I/O ports)
+ Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Publicly available at the ITE website
http://www.ite.com.tw/
* IT8716F
@@ -53,6 +52,18 @@ Module Parameters
misconfigured by BIOS - PWM values would be inverted. This option tries
to fix this. Please contact your BIOS manufacturer and ask him for fix.
+
+Hardware Interfaces
+-------------------
+
+All the chips suported by this driver are LPC Super-I/O chips, accessed
+through the LPC bus (ISA-like I/O ports). The IT8712F additionally has an
+SMBus interface to the hardware monitoring functions. This driver no
+longer supports this interface though, as it is slower and less reliable
+than the ISA access, and was only available on a small number of
+motherboard models.
+
+
Description
-----------
diff --git a/Documentation/hwmon/k8temp b/Documentation/hwmon/k8temp
index 30d123b8d92..0005c716614 100644
--- a/Documentation/hwmon/k8temp
+++ b/Documentation/hwmon/k8temp
@@ -8,7 +8,7 @@ Supported chips:
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>
+Contact: Rudolf Marek <r.marek@assembler.cz>
Description
-----------
diff --git a/Documentation/hwmon/pc87427 b/Documentation/hwmon/pc87427
new file mode 100644
index 00000000000..9a0708f9f49
--- /dev/null
+++ b/Documentation/hwmon/pc87427
@@ -0,0 +1,38 @@
+Kernel driver pc87427
+=====================
+
+Supported chips:
+ * National Semiconductor PC87427
+ Prefix: 'pc87427'
+ Addresses scanned: none, address read from Super I/O config space
+ Datasheet: http://www.winbond.com.tw/E-WINBONDHTM/partner/apc_007.html
+
+Author: Jean Delvare <khali@linux-fr.org>
+
+Thanks to Amir Habibi at Candelis for setting up a test system, and to
+Michael Kress for testing several iterations of this driver.
+
+
+Description
+-----------
+
+The National Semiconductor Super I/O chip includes complete hardware
+monitoring capabilities. It can monitor up to 18 voltages, 8 fans and
+6 temperature sensors. Only the fans are supported at the moment.
+
+This chip also has fan controlling features, which are not yet supported
+by this driver either.
+
+The driver assumes that no more than one chip is present, which seems
+reasonable.
+
+
+Fan Monitoring
+--------------
+
+Fan rotation speeds are reported as 14-bit values from a gated clock
+signal. Speeds down to 83 RPM can be measured.
+
+An alarm is triggered if the rotation speed drops below a programmable
+limit. Another alarm is triggered if the speed is too low to to be measured
+(including stalled or missing fan).
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index d1d390aaf62..efef3b962cd 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -208,12 +208,14 @@ temp[1-*]_auto_point[1-*]_temp_hyst
****************
temp[1-*]_type Sensor type selection.
- Integers 1 to 4 or thermistor Beta value (typically 3435)
+ Integers 1 to 6 or thermistor Beta value (typically 3435)
RW
1: PII/Celeron Diode
2: 3904 transistor
3: thermal diode
4: thermistor (default/unknown Beta)
+ 5: AMD AMDSI
+ 6: Intel PECI
Not all types are supported by all chips
temp[1-*]_max Temperature max value.
diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
index caa610a297e..8a15a740875 100644
--- a/Documentation/hwmon/w83627ehf
+++ b/Documentation/hwmon/w83627ehf
@@ -10,7 +10,7 @@ Supported chips:
Authors:
Jean Delvare <khali@linux-fr.org>
Yuan Mu (Winbond)
- Rudolf Marek <r.marek@sh.cvut.cz>
+ Rudolf Marek <r.marek@assembler.cz>
Description
-----------
diff --git a/Documentation/hwmon/w83791d b/Documentation/hwmon/w83791d
index 19b2ed739fa..db9881df88a 100644
--- a/Documentation/hwmon/w83791d
+++ b/Documentation/hwmon/w83791d
@@ -18,7 +18,7 @@ Credits:
and Mark Studebaker <mdsxyz123@yahoo.com>
w83792d.c:
Chunhao Huang <DZShen@Winbond.com.tw>,
- Rudolf Marek <r.marek@sh.cvut.cz>
+ Rudolf Marek <r.marek@assembler.cz>
Additional contributors:
Sven Anders <anders@anduras.de>
diff --git a/Documentation/hwmon/w83793 b/Documentation/hwmon/w83793
new file mode 100644
index 00000000000..51171a83165
--- /dev/null
+++ b/Documentation/hwmon/w83793
@@ -0,0 +1,106 @@
+Kernel driver w83793
+====================
+
+Supported chips:
+ * Winbond W83793G/W83793R
+ Prefix: 'w83793'
+ Addresses scanned: I2C 0x2c - 0x2f
+ Datasheet: Still not published
+
+Authors:
+ Yuan Mu (Winbond Electronics)
+ Rudolf Marek <r.marek@assembler.cz>
+
+
+Module parameters
+-----------------
+
+* reset int
+ (default 0)
+ This parameter is not recommended, it will lose motherboard specific
+ settings. Use 'reset=1' to reset the chip when loading this module.
+
+* force_subclients=bus,caddr,saddr1,saddr2
+ This is used to force the i2c addresses for subclients of
+ a certain chip. Typical usage is `force_subclients=0,0x2f,0x4a,0x4b'
+ to force the subclients of chip 0x2f on bus 0 to i2c addresses
+ 0x4a and 0x4b.
+
+
+Description
+-----------
+
+This driver implements support for Winbond W83793G/W83793R chips.
+
+* Exported features
+ This driver exports 10 voltage sensors, up to 12 fan tachometer inputs,
+ 6 remote temperatures, up to 8 sets of PWM fan controls, SmartFan
+ (automatic fan speed control) on all temperature/PWM combinations, 2
+ sets of 6-pin CPU VID input.
+
+* Sensor resolutions
+ If your motherboard maker used the reference design, the resolution of
+ voltage0-2 is 2mV, resolution of voltage3/4/5 is 16mV, 8mV for voltage6,
+ 24mV for voltage7/8. Temp1-4 have a 0.25 degree Celsius resolution,
+ temp5-6 have a 1 degree Celsiis resolution.
+
+* Temperature sensor types
+ Temp1-4 have 2 possible types. It can be read from (and written to)
+ temp[1-4]_type.
+ - If the value is 3, it starts monitoring using a remote termal diode
+ (default).
+ - If the value is 6, it starts monitoring using the temperature sensor
+ in Intel CPU and get result by PECI.
+ Temp5-6 can be connected to external thermistors (value of
+ temp[5-6]_type is 4).
+
+* Alarm mechanism
+ For voltage sensors, an alarm triggers if the measured value is below
+ the low voltage limit or over the high voltage limit.
+ For temperature sensors, an alarm triggers if the measured value goes
+ above the high temperature limit, and wears off only after the measured
+ value drops below the hysteresis value.
+ For fan sensors, an alarm triggers if the measured value is below the
+ low speed limit.
+
+* SmartFan/PWM control
+ If you want to set a pwm fan to manual mode, you just need to make sure it
+ is not controlled by any temp channel, for example, you want to set fan1
+ to manual mode, you need to check the value of temp[1-6]_fan_map, make
+ sure bit 0 is cleared in the 6 values. And then set the pwm1 value to
+ control the fan.
+
+ Each temperature channel can control all the 8 PWM outputs (by setting the
+ corresponding bit in tempX_fan_map), you can set the temperature channel
+ mode using temp[1-6]_pwm_enable, 2 is Thermal Cruise mode and 3
+ is the SmartFanII mode. Temperature channels will try to speed up or
+ slow down all controlled fans, this means one fan can receive different
+ PWM value requests from different temperature channels, but the chip
+ will always pick the safest (max) PWM value for each fan.
+
+ In Thermal Cruise mode, the chip attempts to keep the temperature at a
+ predefined value, within a tolerance margin. So if tempX_input >
+ thermal_cruiseX + toleranceX, the chip will increase the PWM value,
+ if tempX_input < thermal_cruiseX - toleranceX, the chip will decrease
+ the PWM value. If the temperature is within the tolerance range, the PWM
+ value is left unchanged.
+
+ SmartFanII works differently, you have to define up to 7 PWM, temperature
+ trip points, defining a PWM/temperature curve which the chip will follow.
+ While not fundamentally different from the Thermal Cruise mode, the
+ implementation is quite different, giving you a finer-grained control.
+
+* Chassis
+ If the case open alarm triggers, it will stay in this state unless cleared
+ by any write to the sysfs file "chassis".
+
+* VID and VRM
+ The VRM version is detected automatically, don't modify the it unless you
+ *do* know the cpu VRM version and it's not properly detected.
+
+
+Notes
+-----
+
+ Only Fan1-5 and PWM1-3 are guaranteed to always exist, other fan inputs and
+ PWM outputs may or may not exist depending on the chip pin configuration.
diff --git a/Documentation/i2c/busses/i2c-amd8111 b/Documentation/i2c/busses/i2c-amd8111
index db294ee7455..460dd6635fd 100644
--- a/Documentation/i2c/busses/i2c-amd8111
+++ b/Documentation/i2c/busses/i2c-amd8111
@@ -5,7 +5,7 @@ Supported adapters:
Datasheets:
AMD datasheet not yet available, but almost everything can be found
- in publically available ACPI 2.0 specification, which the adapter
+ in the publicly available ACPI 2.0 specification, which the adapter
follows.
Author: Vojtech Pavlik <vojtech@suse.cz>
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
index e46c2345824..3db69a086c4 100644
--- a/Documentation/i2c/busses/i2c-i801
+++ b/Documentation/i2c/busses/i2c-i801
@@ -9,7 +9,10 @@ Supported adapters:
* Intel 82801EB/ER (ICH5) (HW PEC supported, 32 byte buffer not supported)
* Intel 6300ESB
* Intel 82801FB/FR/FW/FRW (ICH6)
- * Intel ICH7
+ * Intel 82801G (ICH7)
+ * Intel 631xESB/632xESB (ESB2)
+ * Intel 82801H (ICH8)
+ * Intel ICH9
Datasheets: Publicly available at the Intel website
Authors:
diff --git a/Documentation/i2c/busses/i2c-nforce2 b/Documentation/i2c/busses/i2c-nforce2
index cd49c428a3a..7f61fbc03f7 100644
--- a/Documentation/i2c/busses/i2c-nforce2
+++ b/Documentation/i2c/busses/i2c-nforce2
@@ -10,11 +10,11 @@ Supported adapters:
* nForce4 MCP51 10de:0264
* nForce4 MCP55 10de:0368
-Datasheet: not publically available, but seems to be similar to the
+Datasheet: not publicly available, but seems to be similar to the
AMD-8111 SMBus 2.0 adapter.
Authors:
- Hans-Frieder Vogt <hfvogt@arcor.de>,
+ Hans-Frieder Vogt <hfvogt@gmx.net>,
Thomas Leibold <thomas@plx.com>,
Patrick Dreker <patrick@dreker.de>
@@ -38,7 +38,7 @@ Notes
-----
The SMBus adapter in the nForce2 chipset seems to be very similar to the
-SMBus 2.0 adapter in the AMD-8111 southbridge. However, I could only get
+SMBus 2.0 adapter in the AMD-8111 south bridge. However, I could only get
the driver to work with direct I/O access, which is different to the EC
interface of the AMD-8111. Tested on Asus A7N8X. The ACPI DSDT table of the
Asus A7N8X lists two SMBuses, both of which are supported by this driver.
diff --git a/Documentation/i386/boot.txt b/Documentation/i386/boot.txt
index 9575de300a6..38fe1f03fb1 100644
--- a/Documentation/i386/boot.txt
+++ b/Documentation/i386/boot.txt
@@ -2,7 +2,7 @@
----------------------------
H. Peter Anvin <hpa@zytor.com>
- Last update 2006-11-17
+ Last update 2007-01-26
On the i386 platform, the Linux kernel uses a rather complicated boot
convention. This has evolved partially due to historical aspects, as
@@ -186,6 +186,7 @@ filled out, however:
7 GRuB
8 U-BOOT
9 Xen
+ A Gujin
Please contact <hpa@zytor.com> if you need a bootloader ID
value assigned.
diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt
index e50595bfd8e..0132d363feb 100644
--- a/Documentation/ibm-acpi.txt
+++ b/Documentation/ibm-acpi.txt
@@ -398,25 +398,67 @@ Temperature sensors -- /proc/acpi/ibm/thermal
Most ThinkPads include six or more separate temperature sensors but
only expose the CPU temperature through the standard ACPI methods.
-This feature shows readings from up to eight different sensors. Some
-readings may not be valid, e.g. may show large negative values. For
-example, on the X40, a typical output may be:
+This feature shows readings from up to eight different sensors on older
+ThinkPads, and it has experimental support for up to sixteen different
+sensors on newer ThinkPads. Readings from sensors that are not available
+return -128.
+No commands can be written to this file.
+
+EXPERIMENTAL: The 16-sensors 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. When EXPERIMENTAL
+mode is enabled, reading the first 8 sensors on newer ThinkPads will
+also use an new experimental thermal sensor access mode.
+
+For example, on the X40, a typical output may be:
temperatures: 42 42 45 41 36 -128 33 -128
-Thomas Gruber took his R51 apart and traced all six active sensors in
-his laptop (the location of sensors may vary on other models):
+EXPERIMENTAL: On the T43/p, a typical output may be:
+temperatures: 48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128
+
+The mapping of thermal sensors to physical locations varies depending on
+system-board model (and thus, on ThinkPad model).
+
+http://thinkwiki.org/wiki/Thermal_Sensors is a public wiki page that
+tries to track down these locations for various models.
+
+Most (newer?) models seem to follow this pattern:
1: CPU
-2: Mini PCI Module
-3: HDD
+2: (depends on model)
+3: (depends on model)
4: GPU
-5: Battery
-6: N/A
-7: Battery
-8: N/A
+5: Main battery: main sensor
+6: Bay battery: main sensor
+7: Main battery: secondary sensor
+8: Bay battery: secondary sensor
+9-15: (depends on model)
+
+For the R51 (source: Thomas Gruber):
+2: Mini-PCI
+3: Internal HDD
+
+For the T43, T43/p (source: Shmidoax/Thinkwiki.org)
+http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_T43.2C_T43p
+2: System board, left side (near PCMCIA slot), reported as HDAPS temp
+3: PCMCIA slot
+9: MCH (northbridge) to DRAM Bus
+10: ICH (southbridge), under Mini-PCI card, under touchpad
+11: Power regulator, underside of system board, below F2 key
+
+The A31 has a very atypical layout for the thermal sensors
+(source: Milos Popovic, http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_A31)
+1: CPU
+2: Main Battery: main sensor
+3: Power Converter
+4: Bay Battery: main sensor
+5: MCH (northbridge)
+6: PCMCIA/ambient
+7: Main Battery: secondary sensor
+8: Bay Battery: secondary sensor
-No commands can be written to this file.
EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump
------------------------------------------------------------------------
@@ -529,27 +571,57 @@ 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 attempts to show the current fan speed. The speed is read
-directly from the hardware registers of the embedded controller. This
-is known to work on later R, T and X series ThinkPads but may show a
-bogus value on other models.
+This feature attempts to show the current fan speed, control mode and
+other fan data that might be available. The speed is read directly
+from the hardware registers of the embedded controller. This is known
+to work on later R, T and X series ThinkPads but may show a bogus
+value on other models.
+
+Most ThinkPad fans work in "levels". Level 0 stops the fan. The higher
+the level, the higher the fan speed, although adjacent levels often map
+to the same fan speed. 7 is the highest level, where the fan reaches
+the maximum recommended speed. Level "auto" means the EC changes the
+fan level according to some internal algorithm, usually based on
+readings from the thermal sensors. Level "disengaged" means the EC
+disables the speed-locked closed-loop fan control, and drives the fan as
+fast as it can go, which might exceed hardware limits, so use this level
+with caution.
+
+The fan usually ramps up or down slowly from one speed to another,
+and it is normal for the EC to take several seconds to react to fan
+commands.
The fan may be enabled or disabled with the following commands:
echo enable >/proc/acpi/ibm/fan
echo disable >/proc/acpi/ibm/fan
+Placing a fan on level 0 is the same as disabling it. Enabling a fan
+will try to place it in a safe level if it is too slow or disabled.
+
WARNING WARNING WARNING: do not leave the fan disabled unless you are
-monitoring the temperature sensor readings and you are ready to enable
-it if necessary to avoid overheating.
+monitoring all of the temperature sensor readings and you are ready to
+enable it if necessary to avoid overheating.
-The fan only runs if it's enabled *and* the various temperature
-sensors which control it read high enough. On the X40, this seems to
-depend on the CPU and HDD temperatures. Specifically, the fan is
-turned on when either the CPU temperature climbs to 56 degrees or the
-HDD temperature climbs to 46 degrees. The fan is turned off when the
-CPU temperature drops to 49 degrees and the HDD temperature drops to
-41 degrees. These thresholds cannot currently be controlled.
+An enabled fan in level "auto" may stop spinning if the EC decides the
+ThinkPad is cool enough and doesn't need the extra airflow. This is
+normal, and the EC will spin the fan up if the varios thermal readings
+rise too much.
+
+On the X40, this seems to depend on the CPU and HDD temperatures.
+Specifically, the fan is turned on when either the CPU temperature
+climbs to 56 degrees or the HDD temperature climbs to 46 degrees. The
+fan is turned off when the CPU temperature drops to 49 degrees and the
+HDD temperature drops to 41 degrees. These thresholds cannot
+currently be controlled.
+
+The fan level can be controlled with the command:
+
+ echo 'level <level>' > /proc/acpi/ibm/thermal
+
+Where <level> is an integer from 0 to 7, or one of the words "auto"
+or "disengaged" (without the quotes). Not all ThinkPads support the
+"auto" and "disengaged" levels.
On the X31 and X40 (and ONLY on those models), the fan speed can be
controlled to a certain degree. Once the fan is running, it can be
@@ -562,12 +634,9 @@ about 3700 to about 7350. Values outside this range either do not have
any effect or the fan speed eventually settles somewhere in that
range. The fan cannot be stopped or started with this command.
-On the 570, temperature readings are not available through this
-feature and the fan control works a little differently. The fan speed
-is reported in levels from 0 (off) to 7 (max) and can be controlled
-with the following command:
-
- echo 'level <level>' > /proc/acpi/ibm/thermal
+The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
+certain conditions are met. It will override any fan programming done
+through ibm-acpi.
EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
---------------------------------------
@@ -601,6 +670,26 @@ example:
modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable
+The ibm-acpi kernel driver can be programmed to revert the fan level
+to a safe setting if userspace does not issue one of the fan commands:
+"enable", "disable", "level" or "watchdog" within a configurable
+ammount of time. To do this, use the "watchdog" command.
+
+ echo 'watchdog <interval>' > /proc/acpi/ibm/fan
+
+Interval is the ammount of time in seconds to wait for one of the
+above mentioned fan commands before reseting the fan level to a safe
+one. If set to zero, the watchdog is disabled (default). When the
+watchdog timer runs out, it does the exact equivalent of the "enable"
+fan command.
+
+Note that the watchdog timer stops after it enables the fan. It will
+be rearmed again automatically (using the same interval) when one of
+the above mentioned fan commands is received. The fan watchdog is,
+therefore, not suitable to protect against fan mode changes made
+through means other than the "enable", "disable", and "level" fan
+commands.
+
Example Configuration
---------------------
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index edc04d74ae2..5a8bd5bd88e 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -191,3 +191,5 @@ Code Seq# Include File Comments
<mailto:aherrman@de.ibm.com>
0xF3 00-3F video/sisfb.h sisfb (in development)
<mailto:thomas@winischhofer.net>
+0xF4 00-1F video/mbxfb.h mbxfb
+ <mailto:raph@8d.com>
diff --git a/Documentation/ioctl/ioctl-decoding.txt b/Documentation/ioctl/ioctl-decoding.txt
new file mode 100644
index 00000000000..bfdf7f3ee4f
--- /dev/null
+++ b/Documentation/ioctl/ioctl-decoding.txt
@@ -0,0 +1,24 @@
+To decode a hex IOCTL code:
+
+Most architecures use this generic format, but check
+include/ARCH/ioctl.h for specifics, e.g. powerpc
+uses 3 bits to encode read/write and 13 bits for size.
+
+ bits meaning
+ 31-30 00 - no parameters: uses _IO macro
+ 10 - read: _IOR
+ 01 - write: _IOW
+ 11 - read/write: _IOWR
+
+ 29-16 size of arguments
+
+ 15-8 ascii character supposedly
+ unique to each driver
+
+ 7-0 function #
+
+
+ So for example 0x82187201 is a read with arg length of 0x218,
+character 'r' function 1. Grepping the source reveals this is:
+
+#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
index 125093c3ef7..536d5bfbdb8 100644
--- a/Documentation/kbuild/kconfig-language.txt
+++ b/Documentation/kbuild/kconfig-language.txt
@@ -29,7 +29,7 @@ them. A single configuration option is defined like this:
config MODVERSIONS
bool "Set version information on all module symbols"
- depends MODULES
+ depends on MODULES
help
Usually, modules have to be recompiled whenever you switch to a new
kernel. ...
@@ -163,7 +163,7 @@ The position of a menu entry in the tree is determined in two ways. First
it can be specified explicitly:
menu "Network device support"
- depends NET
+ depends on NET
config NETDEVICES
...
@@ -188,10 +188,10 @@ config MODULES
config MODVERSIONS
bool "Set version information on all module symbols"
- depends MODULES
+ depends on MODULES
comment "module support disabled"
- depends !MODULES
+ depends on !MODULES
MODVERSIONS directly depends on MODULES, this means it's only visible if
MODULES is different from 'n'. The comment on the other hand is always
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
index 99f2d4d4bf7..07330681834 100644
--- a/Documentation/kdump/kdump.txt
+++ b/Documentation/kdump/kdump.txt
@@ -17,7 +17,7 @@ You can use common Linux commands, such as cp and scp, to copy the
memory image to a dump file on the local disk, or across the network to
a remote system.
-Kdump and kexec are currently supported on the x86, x86_64, and ppc64
+Kdump and kexec are currently supported on the x86, x86_64, ppc64 and ia64
architectures.
When the system kernel boots, it reserves a small section of memory for
@@ -54,59 +54,69 @@ memory," in two ways:
Setup and Installation
======================
-Install kexec-tools and the Kdump patch
----------------------------------------
+Install kexec-tools
+-------------------
1) Login as the root user.
2) Download the kexec-tools user-space package from the following URL:
- http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz
+http://www.kernel.org/pub/linux/kernel/people/horms/kexec-tools/kexec-tools-testing.tar.gz
-3) Unpack the tarball with the tar command, as follows:
-
- tar xvpzf kexec-tools-1.101.tar.gz
-
-4) Download the latest consolidated Kdump patch from the following URL:
+This is a symlink to the latest version, which at the time of writing is
+20061214, the only release of kexec-tools-testing so far. As other versions
+are made released, the older onese will remain available at
+http://www.kernel.org/pub/linux/kernel/people/horms/kexec-tools/
- http://lse.sourceforge.net/kdump/
+Note: Latest kexec-tools-testing git tree is available at
- (This location is being used until all the user-space Kdump patches
- are integrated with the kexec-tools package.)
+git://git.kernel.org/pub/scm/linux/kernel/git/horms/kexec-tools-testing.git
+or
+http://www.kernel.org/git/?p=linux/kernel/git/horms/kexec-tools-testing.git;a=summary
-5) Change to the kexec-tools-1.101 directory, as follows:
+3) Unpack the tarball with the tar command, as follows:
- cd kexec-tools-1.101
+ tar xvpzf kexec-tools-testing.tar.gz
-6) Apply the consolidated patch to the kexec-tools-1.101 source tree
- with the patch command, as follows. (Modify the path to the downloaded
- patch as necessary.)
+4) Change to the kexec-tools directory, as follows:
- patch -p1 < /path-to-kdump-patch/kexec-tools-1.101-kdump.patch
+ cd kexec-tools-testing-VERSION
-7) Configure the package, as follows:
+5) Configure the package, as follows:
./configure
-8) Compile the package, as follows:
+6) Compile the package, as follows:
make
-9) Install the package, as follows:
+7) Install the package, as follows:
make install
-Download and build the system and dump-capture kernels
-------------------------------------------------------
+Build the system and dump-capture kernels
+-----------------------------------------
+There are two possible methods of using Kdump.
+
+1) Build a separate custom dump-capture kernel for capturing the
+ kernel core dump.
-Download the mainline (vanilla) kernel source code (2.6.13-rc1 or newer)
-from http://www.kernel.org. Two kernels must be built: a system kernel
-and a dump-capture kernel. Use the following steps to configure these
-kernels with the necessary kexec and Kdump features:
+2) Or use the system kernel binary itself as dump-capture kernel and there is
+ no need to build a separate dump-capture kernel. This is possible
+ only with the architecutres which support a relocatable kernel. As
+ of today i386 and ia64 architectures support relocatable kernel.
-System kernel
--------------
+Building a relocatable kernel is advantageous from the point of view that
+one does not have to build a second kernel for capturing the dump. But
+at the same time one might want to build a custom dump capture kernel
+suitable to his needs.
+
+Following are the configuration setting required for system and
+dump-capture kernels for enabling kdump support.
+
+System kernel config options
+----------------------------
1) Enable "kexec system call" in "Processor type and features."
@@ -132,88 +142,182 @@ System kernel
analysis tools require a vmlinux with debug symbols in order to read
and analyze a dump file.
-4) Make and install the kernel and its modules. Update the boot loader
- (such as grub, yaboot, or lilo) configuration files as necessary.
+Dump-capture kernel config options (Arch Independent)
+-----------------------------------------------------
-5) Boot the system kernel with the boot parameter "crashkernel=Y@X",
- where Y specifies how much memory to reserve for the dump-capture kernel
- and X specifies the beginning of this reserved memory. For example,
- "crashkernel=64M@16M" tells the system kernel to reserve 64 MB of memory
- starting at physical address 0x01000000 for the dump-capture kernel.
-
- On x86 and x86_64, use "crashkernel=64M@16M".
-
- On ppc64, use "crashkernel=128M@32M".
+1) Enable "kernel crash dumps" support under "Processor type and
+ features":
+ CONFIG_CRASH_DUMP=y
-The dump-capture kernel
------------------------
+2) Enable "/proc/vmcore support" under "Filesystems" -> "Pseudo filesystems".
-1) Under "General setup," append "-kdump" to the current string in
- "Local version."
+ CONFIG_PROC_VMCORE=y
+ (CONFIG_PROC_VMCORE is set by default when CONFIG_CRASH_DUMP is selected.)
-2) On x86, enable high memory support under "Processor type and
+Dump-capture kernel config options (Arch Dependent, i386)
+--------------------------------------------------------
+1) On x86, enable high memory support under "Processor type and
features":
CONFIG_HIGHMEM64G=y
or
CONFIG_HIGHMEM4G
-3) On x86 and x86_64, disable symmetric multi-processing support
+2) On x86 and x86_64, disable symmetric multi-processing support
under "Processor type and features":
CONFIG_SMP=n
+
(If CONFIG_SMP=y, then specify maxcpus=1 on the kernel command line
when loading the dump-capture kernel, see section "Load the Dump-capture
Kernel".)
-4) On ppc64, disable NUMA support and enable EMBEDDED support:
+3) If one wants to build and use a relocatable kernel,
+ Enable "Build a relocatable kernel" support under "Processor type and
+ features"
- CONFIG_NUMA=n
- CONFIG_EMBEDDED=y
- CONFIG_EEH=N for the dump-capture kernel
+ CONFIG_RELOCATABLE=y
-5) Enable "kernel crash dumps" support under "Processor type and
- features":
+4) Use a suitable value for "Physical address where the kernel is
+ loaded" (under "Processor type and features"). This only appears when
+ "kernel crash dumps" is enabled. A suitable value depends upon
+ whether kernel is relocatable or not.
+
+ If you are using a relocatable kernel use CONFIG_PHYSICAL_START=0x100000
+ This will compile the kernel for physical address 1MB, but given the fact
+ kernel is relocatable, it can be run from any physical address hence
+ kexec boot loader will load it in memory region reserved for dump-capture
+ kernel.
+
+ Otherwise it should be the start of memory region reserved for
+ second kernel using boot parameter "crashkernel=Y@X". Here X is
+ start of memory region reserved for dump-capture kernel.
+ Generally X is 16MB (0x1000000). So you can set
+ CONFIG_PHYSICAL_START=0x1000000
+
+5) Make and install the kernel and its modules. DO NOT add this kernel
+ to the boot loader configuration files.
- CONFIG_CRASH_DUMP=y
+Dump-capture kernel config options (Arch Dependent, x86_64)
+----------------------------------------------------------
+1) On x86 and x86_64, disable symmetric multi-processing support
+ under "Processor type and features":
-6) Use a suitable value for "Physical address where the kernel is
+ CONFIG_SMP=n
+
+ (If CONFIG_SMP=y, then specify maxcpus=1 on the kernel command line
+ when loading the dump-capture kernel, see section "Load the Dump-capture
+ Kernel".)
+
+2) Use a suitable value for "Physical address where the kernel is
loaded" (under "Processor type and features"). This only appears when
"kernel crash dumps" is enabled. By default this value is 0x1000000
(16MB). It should be the same as X in the "crashkernel=Y@X" boot
- parameter discussed above.
+ parameter.
- On x86 and x86_64, use "CONFIG_PHYSICAL_START=0x1000000".
+ For x86_64, normally "CONFIG_PHYSICAL_START=0x1000000".
- On ppc64 the value is automatically set at 32MB when
- CONFIG_CRASH_DUMP is set.
+3) Make and install the kernel and its modules. DO NOT add this kernel
+ to the boot loader configuration files.
-6) Optionally enable "/proc/vmcore support" under "Filesystems" ->
- "Pseudo filesystems".
+Dump-capture kernel config options (Arch Dependent, ppc64)
+----------------------------------------------------------
- CONFIG_PROC_VMCORE=y
- (CONFIG_PROC_VMCORE is set by default when CONFIG_CRASH_DUMP is selected.)
-
-7) Make and install the kernel and its modules. DO NOT add this kernel
+- Make and install the kernel and its modules. DO NOT add this kernel
to the boot loader configuration files.
+Dump-capture kernel config options (Arch Dependent, ia64)
+----------------------------------------------------------
+
+- No specific options are required to create a dump-capture kernel
+ for ia64, other than those specified in the arch idependent section
+ above. This means that it is possible to use the system kernel
+ as a dump-capture kernel if desired.
+
+ The crashkernel region can be automatically placed by the system
+ kernel at run time. This is done by specifying the base address as 0,
+ or omitting it all together.
+
+ crashkernel=256M@0
+ or
+ crashkernel=256M
+
+ If the start address is specified, note that the start address of the
+ kernel will be aligned to 64Mb, so if the start address is not then
+ any space below the alignment point will be wasted.
+
+
+Boot into System Kernel
+=======================
+
+1) Make and install the kernel and its modules. Update the boot loader
+ (such as grub, yaboot, or lilo) configuration files as necessary.
+
+2) Boot the system kernel with the boot parameter "crashkernel=Y@X",
+ where Y specifies how much memory to reserve for the dump-capture kernel
+ and X specifies the beginning of this reserved memory. For example,
+ "crashkernel=64M@16M" tells the system kernel to reserve 64 MB of memory
+ starting at physical address 0x01000000 (16MB) for the dump-capture kernel.
+
+ On x86 and x86_64, use "crashkernel=64M@16M".
+
+ On ppc64, use "crashkernel=128M@32M".
+
+ On ia64, 256M@256M is a generous value that typically works.
+ The region may be automatically placed on ia64, see the
+ dump-capture kernel config option notes above.
Load the Dump-capture Kernel
============================
-After booting to the system kernel, load the dump-capture kernel using
-the following command:
+After booting to the system kernel, dump-capture kernel needs to be
+loaded.
+
+Based on the architecture and type of image (relocatable or not), one
+can choose to load the uncompressed vmlinux or compressed bzImage/vmlinuz
+of dump-capture kernel. Following is the summary.
+
+For i386:
+ - Use vmlinux if kernel is not relocatable.
+ - Use bzImage/vmlinuz if kernel is relocatable.
+For x86_64:
+ - Use vmlinux
+For ppc64:
+ - Use vmlinux
+For ia64:
+ - Use vmlinux or vmlinuz.gz
+
- kexec -p <dump-capture-kernel> \
+If you are using a uncompressed vmlinux image then use following command
+to load dump-capture kernel.
+
+ kexec -p <dump-capture-kernel-vmlinux-image> \
--initrd=<initrd-for-dump-capture-kernel> --args-linux \
- --append="root=<root-dev> init 1 irqpoll"
+ --append="root=<root-dev> <arch-specific-options>"
+If you are using a compressed bzImage/vmlinuz, then use following command
+to load dump-capture kernel.
-Notes on loading the dump-capture kernel:
+ kexec -p <dump-capture-kernel-bzImage> \
+ --initrd=<initrd-for-dump-capture-kernel> \
+ --append="root=<root-dev> <arch-specific-options>"
+
+Please note, that --args-linux does not need to be specified for ia64.
+It is planned to make this a no-op on that architecture, but for now
+it should be omitted
+
+Following are the arch specific command line options to be used while
+loading dump-capture kernel.
-* <dump-capture-kernel> must be a vmlinux image (that is, an
- uncompressed ELF image). bzImage does not work at this time.
+For i386, x86_64 and ia64:
+ "init 1 irqpoll maxcpus=1"
+
+For ppc64:
+ "init 1 maxcpus=1 noirqdistrib"
+
+
+Notes on loading the dump-capture kernel:
* By default, the ELF headers are stored in ELF64 format to support
systems with more than 4GB memory. The --elf32-core-headers option can
@@ -231,6 +335,9 @@ Notes on loading the dump-capture kernel:
* "init 1" boots the dump-capture kernel into single-user mode without
networking. If you want networking, use "init 3."
+* We generally don' have to bring up a SMP kernel just to capture the
+ dump. Hence generally it is useful either to build a UP dump-capture
+ kernel or specify maxcpus=1 option while loading dump-capture kernel.
Kernel Panic
============
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index b79bcdf1631..25d29851710 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -548,6 +548,13 @@ and is between 256 and 4096 characters. It is defined in the file
eurwdt= [HW,WDT] Eurotech CPU-1220/1410 onboard watchdog.
Format: <io>[,<irq>]
+ failslab=
+ fail_page_alloc=
+ fail_make_request=[KNL]
+ General fault injection mechanism.
+ Format: <interval>,<probability>,<space>,<times>
+ See also /Documentation/fault-injection/.
+
fd_mcs= [HW,SCSI]
See header of drivers/scsi/fd_mcs.c.
@@ -1649,6 +1656,12 @@ and is between 256 and 4096 characters. It is defined in the file
sym53c416= [HW,SCSI]
See header of drivers/scsi/sym53c416.c.
+ sysrq_always_enabled
+ [KNL]
+ Ignore sysrq setting - this boot parameter will
+ neutralize any effect of /proc/sys/kernel/sysrq.
+ Useful for debugging.
+
t128= [HW,SCSI]
See header of drivers/scsi/t128.c.
@@ -1701,6 +1714,14 @@ and is between 256 and 4096 characters. It is defined in the file
uart6850= [HW,OSS]
Format: <io>,<irq>
+ uhci-hcd.ignore_oc=
+ [USB] Ignore overcurrent events (default N).
+ Some badly-designed motherboards generate lots of
+ bogus events, for ports that aren't wired to
+ anything. Set this parameter to avoid log spamming.
+ Note that genuine overcurrent events won't be
+ reported either.
+
usbhid.mousepoll=
[USBHID] The interval which mice are to be polled at.
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt
index dda15886bcb..387482e46c4 100644
--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -19,7 +19,8 @@ for real time and multimedia traffic.
It has a base protocol and pluggable congestion control IDs (CCIDs).
-It is at experimental RFC status and the homepage for DCCP as a protocol is at:
+It is at proposed standard RFC status and the homepage for DCCP as a protocol
+is at:
http://www.read.cs.ucla.edu/dccp/
Missing features
@@ -34,9 +35,6 @@ The known bugs are at:
Socket options
==============
-DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for
-calculations.
-
DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
service codes (RFC 4340, sec. 8.1.2); if this socket option is not set,
the socket will fall back to 0 (which means that no meaningful service code
diff --git a/Documentation/pci.txt b/Documentation/pci.txt
index 2b395e47896..fd5028eca13 100644
--- a/Documentation/pci.txt
+++ b/Documentation/pci.txt
@@ -1,142 +1,231 @@
- How To Write Linux PCI Drivers
- by Martin Mares <mj@ucw.cz> on 07-Feb-2000
+ How To Write Linux PCI Drivers
+
+ by Martin Mares <mj@ucw.cz> on 07-Feb-2000
+ updated by Grant Grundler <grundler@parisc-linux.org> on 23-Dec-2006
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The world of PCI is vast and it's full of (mostly unpleasant) surprises.
-Different PCI devices have different requirements and different bugs --
-because of this, the PCI support layer in Linux kernel is not as trivial
-as one would wish. This short pamphlet tries to help all potential driver
-authors find their way through the deep forests of PCI handling.
+The world of PCI is vast and full of (mostly unpleasant) surprises.
+Since each CPU architecture implements different chip-sets and PCI devices
+have different requirements (erm, "features"), the result is the PCI support
+in the Linux kernel is not as trivial as one would wish. This short paper
+tries to introduce all potential driver authors to Linux APIs for
+PCI device drivers.
+
+A more complete resource is the third edition of "Linux Device Drivers"
+by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman.
+LDD3 is available for free (under Creative Commons License) from:
+
+ http://lwn.net/Kernel/LDD3/
+
+However, keep in mind that all documents are subject to "bit rot".
+Refer to the source code if things are not working as described here.
+
+Please send questions/comments/patches about Linux PCI API to the
+"Linux PCI" <linux-pci@atrey.karlin.mff.cuni.cz> mailing list.
+
0. Structure of PCI drivers
~~~~~~~~~~~~~~~~~~~~~~~~~~~
-There exist two kinds of PCI drivers: new-style ones (which leave most of
-probing for devices to the PCI layer and support online insertion and removal
-of devices [thus supporting PCI, hot-pluggable PCI and CardBus in a single
-driver]) and old-style ones which just do all the probing themselves. Unless
-you have a very good reason to do so, please don't use the old way of probing
-in any new code. After the driver finds the devices it wishes to operate
-on (either the old or the new way), it needs to perform the following steps:
+PCI drivers "discover" PCI devices in a system via pci_register_driver().
+Actually, it's the other way around. When the PCI generic code discovers
+a new device, the driver with a matching "description" will be notified.
+Details on this below.
+
+pci_register_driver() leaves most of the probing for devices to
+the PCI layer and supports online insertion/removal of devices [thus
+supporting hot-pluggable PCI, CardBus, and Express-Card in a single driver].
+pci_register_driver() call requires passing in a table of function
+pointers and thus dictates the high level structure of a driver.
+
+Once the driver knows about a PCI device and takes ownership, the
+driver generally needs to perform the following initialization:
Enable the device
- Access device configuration space
- Discover resources (addresses and IRQ numbers) provided by the device
- Allocate these resources
- Communicate with the device
+ Request MMIO/IOP resources
+ Set the DMA mask size (for both coherent and streaming DMA)
+ Allocate and initialize shared control data (pci_allocate_coherent())
+ Access device configuration space (if needed)
+ Register IRQ handler (request_irq())
+ Initialize non-PCI (i.e. LAN/SCSI/etc parts of the chip)
+ Enable DMA/processing engines
+
+When done using the device, and perhaps the module needs to be unloaded,
+the driver needs to take the follow steps:
+ Disable the device from generating IRQs
+ Release the IRQ (free_irq())
+ Stop all DMA activity
+ Release DMA buffers (both streaming and coherent)
+ Unregister from other subsystems (e.g. scsi or netdev)
+ Release MMIO/IOP resources
Disable the device
-Most of these topics are covered by the following sections, for the rest
-look at <linux/pci.h>, it's hopefully well commented.
+Most of these topics are covered in the following sections.
+For the rest look at LDD3 or <linux/pci.h> .
If the PCI subsystem is not configured (CONFIG_PCI is not set), most of
-the functions described below are defined as inline functions either completely
-empty or just returning an appropriate error codes to avoid lots of ifdefs
-in the drivers.
+the PCI functions described below are defined as inline functions either
+completely empty or just returning an appropriate error codes to avoid
+lots of ifdefs in the drivers.
+
-1. New-style drivers
-~~~~~~~~~~~~~~~~~~~~
-The new-style drivers just call pci_register_driver during their initialization
-with a pointer to a structure describing the driver (struct pci_driver) which
-contains:
+1. pci_register_driver() call
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- name Name of the driver
+PCI device drivers call pci_register_driver() during their
+initialization with a pointer to a structure describing the driver
+(struct pci_driver):
+
+ field name Description
+ ---------- ------------------------------------------------------
id_table Pointer to table of device ID's the driver is
interested in. Most drivers should export this
table using MODULE_DEVICE_TABLE(pci,...).
- probe Pointer to a probing function which gets called (during
- execution of pci_register_driver for already existing
- devices or later if a new device gets inserted) for all
- PCI devices which match the ID table and are not handled
- by the other drivers yet. This function gets passed a
- pointer to the pci_dev structure representing the device
- and also which entry in the ID table did the device
- match. It returns zero when the driver has accepted the
- device or an error code (negative number) otherwise.
- This function always gets called from process context,
- so it can sleep.
- remove Pointer to a function which gets called whenever a
- device being handled by this driver is removed (either
- during deregistration of the driver or when it's
- manually pulled out of a hot-pluggable slot). This
- function always gets called from process context, so it
- can sleep.
- save_state Save a device's state before it's suspend.
+
+ probe This probing function gets called (during execution
+ of pci_register_driver() for already existing
+ devices or later if a new device gets inserted) for
+ all PCI devices which match the ID table and are not
+ "owned" by the other drivers yet. This function gets
+ passed a "struct pci_dev *" for each device whose
+ entry in the ID table matches the device. The probe
+ function returns zero when the driver chooses to
+ take "ownership" of the device or an error code
+ (negative number) otherwise.
+ The probe function always gets called from process
+ context, so it can sleep.
+
+ remove The remove() function gets called whenever a device
+ being handled by this driver is removed (either during
+ deregistration of the driver or when it's manually
+ pulled out of a hot-pluggable slot).
+ The remove function always gets called from process
+ context, so it can sleep.
+
suspend Put device into low power state.
+ suspend_late Put device into low power state.
+
+ resume_early Wake device from low power state.
resume Wake device from low power state.
+
+ (Please see Documentation/power/pci.txt for descriptions
+ of PCI Power Management and the related functions.)
+
enable_wake Enable device to generate wake events from a low power
state.
- (Please see Documentation/power/pci.txt for descriptions
- of PCI Power Management and the related functions)
+ shutdown Hook into reboot_notifier_list (kernel/sys.c).
+ Intended to stop any idling DMA operations.
+ Useful for enabling wake-on-lan (NIC) or changing
+ the power state of a device before reboot.
+ e.g. drivers/net/e100.c.
+
+ err_handler See Documentation/pci-error-recovery.txt
+
+ multithread_probe Enable multi-threaded probe/scan. Driver must
+ provide its own locking/syncronization for init
+ operations if this is enabled.
+
-The ID table is an array of struct pci_device_id ending with a all-zero entry.
-Each entry consists of:
+The ID table is an array of struct pci_device_id entries ending with an
+all-zero entry. Each entry consists of:
+
+ vendor,device Vendor and device ID to match (or PCI_ANY_ID)
- vendor, device Vendor and device ID to match (or PCI_ANY_ID)
subvendor, Subsystem vendor and device ID to match (or PCI_ANY_ID)
- subdevice
- class, Device class to match. The class_mask tells which bits
- class_mask of the class are honored during the comparison.
+ subdevice,
+
+ class Device class, subclass, and "interface" to match.
+ See Appendix D of the PCI Local Bus Spec or
+ include/linux/pci_ids.h for a full list of classes.
+ Most drivers do not need to specify class/class_mask
+ as vendor/device is normally sufficient.
+
+ class_mask limit which sub-fields of the class field are compared.
+ See drivers/scsi/sym53c8xx_2/ for example of usage.
+
driver_data Data private to the driver.
+ Most drivers don't need to use driver_data field.
+ Best practice is to use driver_data as an index
+ into a static list of equivalent device types,
+ instead of using it as a pointer.
-Most drivers don't need to use the driver_data field. Best practice
-for use of driver_data is to use it as an index into a static list of
-equivalent device types, not to use it as a pointer.
-Have a table entry {PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID}
-to have probe() called for every PCI device known to the system.
+Most drivers only need PCI_DEVICE() or PCI_DEVICE_CLASS() to set up
+a pci_device_id table.
-New PCI IDs may be added to a device driver at runtime by writing
-to the file /sys/bus/pci/drivers/{driver}/new_id. When added, the
-driver will probe for all devices it can support.
+New PCI IDs may be added to a device driver pci_ids table at runtime
+as shown below:
echo "vendor device subvendor subdevice class class_mask driver_data" > \
- /sys/bus/pci/drivers/{driver}/new_id
-where all fields are passed in as hexadecimal values (no leading 0x).
-Users need pass only as many fields as necessary; vendor, device,
-subvendor, and subdevice fields default to PCI_ANY_ID (FFFFFFFF),
-class and classmask fields default to 0, and driver_data defaults to
-0UL. Device drivers must initialize use_driver_data in the dynids struct
-in their pci_driver struct prior to calling pci_register_driver in order
-for the driver_data field to get passed to the driver. Otherwise, only a
-0 is passed in that field.
+/sys/bus/pci/drivers/{driver}/new_id
+
+All fields are passed in as hexadecimal values (no leading 0x).
+Users need pass only as many fields as necessary:
+ o vendor, device, subvendor, and subdevice fields default
+ to PCI_ANY_ID (FFFFFFFF),
+ o class and classmask fields default to 0
+ o driver_data defaults to 0UL.
+
+Once added, the driver probe routine will be invoked for any unclaimed
+PCI devices listed in its (newly updated) pci_ids list.
When the driver exits, it just calls pci_unregister_driver() and the PCI layer
automatically calls the remove hook for all devices handled by the driver.
+
+1.1 "Attributes" for driver functions/data
+
Please mark the initialization and cleanup functions where appropriate
(the corresponding macros are defined in <linux/init.h>):
__init Initialization code. Thrown away after the driver
initializes.
__exit Exit code. Ignored for non-modular drivers.
- __devinit Device initialization code. Identical to __init if
- the kernel is not compiled with CONFIG_HOTPLUG, normal
- function otherwise.
+
+
+ __devinit Device initialization code.
+ Identical to __init if the kernel is not compiled
+ with CONFIG_HOTPLUG, normal function otherwise.
__devexit The same for __exit.
-Tips:
- The module_init()/module_exit() functions (and all initialization
- functions called only from these) should be marked __init/exit.
- The struct pci_driver shouldn't be marked with any of these tags.
- The ID table array should be marked __devinitdata.
- The probe() and remove() functions (and all initialization
- functions called only from these) should be marked __devinit/exit.
- If you are sure the driver is not a hotplug driver then use only
- __init/exit __initdata/exitdata.
+Tips on when/where to use the above attributes:
+ o The module_init()/module_exit() functions (and all
+ initialization functions called _only_ from these)
+ should be marked __init/__exit.
- Pointers to functions marked as __devexit must be created using
- __devexit_p(function_name). That will generate the function
- name or NULL if the __devexit function will be discarded.
+ o Do not mark the struct pci_driver.
+ o The ID table array should be marked __devinitdata.
-2. How to find PCI devices manually (the old style)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-PCI drivers not using the pci_register_driver() interface search
-for PCI devices manually using the following constructs:
+ o The probe() and remove() functions should be marked __devinit
+ and __devexit respectively. All initialization functions
+ exclusively called by the probe() routine, can be marked __devinit.
+ Ditto for remove() and __devexit.
+
+ o If mydriver_probe() is marked with __devinit(), then all address
+ references to mydriver_probe must use __devexit_p(mydriver_probe)
+ (in the struct pci_driver declaration for example).
+ __devexit_p() will generate the function name _or_ NULL if the
+ function will be discarded. For an example, see drivers/net/tg3.c.
+
+ o Do NOT mark a function if you are not sure which mark to use.
+ Better to not mark the function than mark the function wrong.
+
+
+
+2. How to find PCI devices manually
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+PCI drivers should have a really good reason for not using the
+pci_register_driver() interface to search for PCI devices.
+The main reason PCI devices are controlled by multiple drivers
+is because one PCI device implements several different HW services.
+E.g. combined serial/parallel port/floppy controller.
+
+A manual search may be performed using the following constructs:
Searching by vendor and device ID:
@@ -150,87 +239,311 @@ Searching by class ID (iterate in a similar way):
Searching by both vendor/device and subsystem vendor/device ID:
- pci_get_subsys(VENDOR_ID, DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev).
+ pci_get_subsys(VENDOR_ID,DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev).
- You can use the constant PCI_ANY_ID as a wildcard replacement for
+You can use the constant PCI_ANY_ID as a wildcard replacement for
VENDOR_ID or DEVICE_ID. This allows searching for any device from a
specific vendor, for example.
- These functions are hotplug-safe. They increment the reference count on
+These functions are hotplug-safe. They increment the reference count on
the pci_dev that they return. You must eventually (possibly at module unload)
decrement the reference count on these devices by calling pci_dev_put().
-3. Enabling and disabling devices
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Before you do anything with the device you've found, you need to enable
-it by calling pci_enable_device() which enables I/O and memory regions of
-the device, allocates an IRQ if necessary, assigns missing resources if
-needed and wakes up the device if it was in suspended state. Please note
-that this function can fail.
- If you want to use the device in bus mastering mode, call pci_set_master()
-which enables the bus master bit in PCI_COMMAND register and also fixes
-the latency timer value if it's set to something bogus by the BIOS.
+3. Device Initialization Steps
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As noted in the introduction, most PCI drivers need the following steps
+for device initialization:
- If you want to use the PCI Memory-Write-Invalidate transaction,
+ Enable the device
+ Request MMIO/IOP resources
+ Set the DMA mask size (for both coherent and streaming DMA)
+ Allocate and initialize shared control data (pci_allocate_coherent())
+ Access device configuration space (if needed)
+ Register IRQ handler (request_irq())
+ Initialize non-PCI (i.e. LAN/SCSI/etc parts of the chip)
+ Enable DMA/processing engines.
+
+The driver can access PCI config space registers at any time.
+(Well, almost. When running BIST, config space can go away...but
+that will just result in a PCI Bus Master Abort and config reads
+will return garbage).
+
+
+3.1 Enable the PCI device
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Before touching any device registers, the driver needs to enable
+the PCI device by calling pci_enable_device(). This will:
+ o wake up the device if it was in suspended state,
+ o allocate I/O and memory regions of the device (if BIOS did not),
+ o allocate an IRQ (if BIOS did not).
+
+NOTE: pci_enable_device() can fail! Check the return value.
+NOTE2: Also see pci_enable_device_bars() below. Drivers can
+ attempt to enable only a subset of BARs they need.
+
+[ OS BUG: we don't check resource allocations before enabling those
+ resources. The sequence would make more sense if we called
+ pci_request_resources() before calling pci_enable_device().
+ Currently, the device drivers can't detect the bug when when two
+ devices have been allocated the same range. This is not a common
+ problem and unlikely to get fixed soon.
+
+ This has been discussed before but not changed as of 2.6.19:
+ http://lkml.org/lkml/2006/3/2/194
+]
+
+pci_set_master() will enable DMA by setting the bus master bit
+in the PCI_COMMAND register. It also fixes the latency timer value if
+it's set to something bogus by the BIOS.
+
+If the PCI device can use the PCI Memory-Write-Invalidate transaction,
call pci_set_mwi(). This enables the PCI_COMMAND bit for Mem-Wr-Inval
and also ensures that the cache line size register is set correctly.
-Make sure to check the return value of pci_set_mwi(), not all architectures
-may support Memory-Write-Invalidate.
+Check the return value of pci_set_mwi() as not all architectures
+or chip-sets may support Memory-Write-Invalidate.
+
+
+3.2 Request MMIO/IOP resources
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Memory (MMIO), and I/O port addresses should NOT be read directly
+from the PCI device config space. Use the values in the pci_dev structure
+as the PCI "bus address" might have been remapped to a "host physical"
+address by the arch/chip-set specific kernel support.
- If your driver decides to stop using the device (e.g., there was an
-error while setting it up or the driver module is being unloaded), it
-should call pci_disable_device() to deallocate any IRQ resources, disable
-PCI bus-mastering, etc. You should not do anything with the device after
+See Documentation/IO-mapping.txt for how to access device registers
+or device memory.
+
+The device driver needs to call pci_request_region() to verify
+no other device is already using the same address resource.
+Conversely, drivers should call pci_release_region() AFTER
calling pci_disable_device().
+The idea is to prevent two devices colliding on the same address range.
+
+[ See OS BUG comment above. Currently (2.6.19), The driver can only
+ determine MMIO and IO Port resource availability _after_ calling
+ pci_enable_device(). ]
+
+Generic flavors of pci_request_region() are request_mem_region()
+(for MMIO ranges) and request_region() (for IO Port ranges).
+Use these for address resources that are not described by "normal" PCI
+BARs.
+
+Also see pci_request_selected_regions() below.
+
+
+3.3 Set the DMA mask size
+~~~~~~~~~~~~~~~~~~~~~~~~~
+[ If anything below doesn't make sense, please refer to
+ Documentation/DMA-API.txt. This section is just a reminder that
+ drivers need to indicate DMA capabilities of the device and is not
+ an authoritative source for DMA interfaces. ]
+
+While all drivers should explicitly indicate the DMA capability
+(e.g. 32 or 64 bit) of the PCI bus master, devices with more than
+32-bit bus master capability for streaming data need the driver
+to "register" this capability by calling pci_set_dma_mask() with
+appropriate parameters. In general this allows more efficient DMA
+on systems where System RAM exists above 4G _physical_ address.
+
+Drivers for all PCI-X and PCIe compliant devices must call
+pci_set_dma_mask() as they are 64-bit DMA devices.
+
+Similarly, drivers must also "register" this capability if the device
+can directly address "consistent memory" in System RAM above 4G physical
+address by calling pci_set_consistent_dma_mask().
+Again, this includes drivers for all PCI-X and PCIe compliant devices.
+Many 64-bit "PCI" devices (before PCI-X) and some PCI-X devices are
+64-bit DMA capable for payload ("streaming") data but not control
+("consistent") data.
+
+
+3.4 Setup shared control data
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Once the DMA masks are set, the driver can allocate "consistent" (a.k.a. shared)
+memory. See Documentation/DMA-API.txt for a full description of
+the DMA APIs. This section is just a reminder that it needs to be done
+before enabling DMA on the device.
+
+
+3.5 Initialize device registers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Some drivers will need specific "capability" fields programmed
+or other "vendor specific" register initialized or reset.
+E.g. clearing pending interrupts.
+
+
+3.6 Register IRQ handler
+~~~~~~~~~~~~~~~~~~~~~~~~
+While calling request_irq() is the the last step described here,
+this is often just another intermediate step to initialize a device.
+This step can often be deferred until the device is opened for use.
+
+All interrupt handlers for IRQ lines should be registered with IRQF_SHARED
+and use the devid to map IRQs to devices (remember that all PCI IRQ lines
+can be shared).
+
+request_irq() will associate an interrupt handler and device handle
+with an interrupt number. Historically interrupt numbers represent
+IRQ lines which run from the PCI device to the Interrupt controller.
+With MSI and MSI-X (more below) the interrupt number is a CPU "vector".
+
+request_irq() also enables the interrupt. Make sure the device is
+quiesced and does not have any interrupts pending before registering
+the interrupt handler.
+
+MSI and MSI-X are PCI capabilities. Both are "Message Signaled Interrupts"
+which deliver interrupts to the CPU via a DMA write to a Local APIC.
+The fundamental difference between MSI and MSI-X is how multiple
+"vectors" get allocated. MSI requires contiguous blocks of vectors
+while MSI-X can allocate several individual ones.
+
+MSI capability can be enabled by calling pci_enable_msi() or
+pci_enable_msix() before calling request_irq(). This causes
+the PCI support to program CPU vector data into the PCI device
+capability registers.
+
+If your PCI device supports both, try to enable MSI-X first.
+Only one can be enabled at a time. Many architectures, chip-sets,
+or BIOSes do NOT support MSI or MSI-X and the call to pci_enable_msi/msix
+will fail. This is important to note since many drivers have
+two (or more) interrupt handlers: one for MSI/MSI-X and another for IRQs.
+They choose which handler to register with request_irq() based on the
+return value from pci_enable_msi/msix().
+
+There are (at least) two really good reasons for using MSI:
+1) MSI is an exclusive interrupt vector by definition.
+ This means the interrupt handler doesn't have to verify
+ its device caused the interrupt.
+
+2) MSI avoids DMA/IRQ race conditions. DMA to host memory is guaranteed
+ to be visible to the host CPU(s) when the MSI is delivered. This
+ is important for both data coherency and avoiding stale control data.
+ This guarantee allows the driver to omit MMIO reads to flush
+ the DMA stream.
+
+See drivers/infiniband/hw/mthca/ or drivers/net/tg3.c for examples
+of MSI/MSI-X usage.
+
+
+
+4. PCI device shutdown
+~~~~~~~~~~~~~~~~~~~~~~~
+
+When a PCI device driver is being unloaded, most of the following
+steps need to be performed:
+
+ Disable the device from generating IRQs
+ Release the IRQ (free_irq())
+ Stop all DMA activity
+ Release DMA buffers (both streaming and consistent)
+ Unregister from other subsystems (e.g. scsi or netdev)
+ Disable device from responding to MMIO/IO Port addresses
+ Release MMIO/IO Port resource(s)
+
+
+4.1 Stop IRQs on the device
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+How to do this is chip/device specific. If it's not done, it opens
+the possibility of a "screaming interrupt" if (and only if)
+the IRQ is shared with another device.
+
+When the shared IRQ handler is "unhooked", the remaining devices
+using the same IRQ line will still need the IRQ enabled. Thus if the
+"unhooked" device asserts IRQ line, the system will respond assuming
+it was one of the remaining devices asserted the IRQ line. Since none
+of the other devices will handle the IRQ, the system will "hang" until
+it decides the IRQ isn't going to get handled and masks the IRQ (100,000
+iterations later). Once the shared IRQ is masked, the remaining devices
+will stop functioning properly. Not a nice situation.
+
+This is another reason to use MSI or MSI-X if it's available.
+MSI and MSI-X are defined to be exclusive interrupts and thus
+are not susceptible to the "screaming interrupt" problem.
+
+
+4.2 Release the IRQ
+~~~~~~~~~~~~~~~~~~~
+Once the device is quiesced (no more IRQs), one can call free_irq().
+This function will return control once any pending IRQs are handled,
+"unhook" the drivers IRQ handler from that IRQ, and finally release
+the IRQ if no one else is using it.
+
+
+4.3 Stop all DMA activity
+~~~~~~~~~~~~~~~~~~~~~~~~~
+It's extremely important to stop all DMA operations BEFORE attempting
+to deallocate DMA control data. Failure to do so can result in memory
+corruption, hangs, and on some chip-sets a hard crash.
-4. How to access PCI config space
+Stopping DMA after stopping the IRQs can avoid races where the
+IRQ handler might restart DMA engines.
+
+While this step sounds obvious and trivial, several "mature" drivers
+didn't get this step right in the past.
+
+
+4.4 Release DMA buffers
+~~~~~~~~~~~~~~~~~~~~~~~
+Once DMA is stopped, clean up streaming DMA first.
+I.e. unmap data buffers and return buffers to "upstream"
+owners if there is one.
+
+Then clean up "consistent" buffers which contain the control data.
+
+See Documentation/DMA-API.txt for details on unmapping interfaces.
+
+
+4.5 Unregister from other subsystems
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Most low level PCI device drivers support some other subsystem
+like USB, ALSA, SCSI, NetDev, Infiniband, etc. Make sure your
+driver isn't losing resources from that other subsystem.
+If this happens, typically the symptom is an Oops (panic) when
+the subsystem attempts to call into a driver that has been unloaded.
+
+
+4.6 Disable Device from responding to MMIO/IO Port addresses
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+io_unmap() MMIO or IO Port resources and then call pci_disable_device().
+This is the symmetric opposite of pci_enable_device().
+Do not access device registers after calling pci_disable_device().
+
+
+4.7 Release MMIO/IO Port Resource(s)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Call pci_release_region() to mark the MMIO or IO Port range as available.
+Failure to do so usually results in the inability to reload the driver.
+
+
+
+5. How to access PCI config space
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- You can use pci_(read|write)_config_(byte|word|dword) to access the config
+
+You can use pci_(read|write)_config_(byte|word|dword) to access the config
space of a device represented by struct pci_dev *. All these functions return 0
when successful or an error code (PCIBIOS_...) which can be translated to a text
string by pcibios_strerror. Most drivers expect that accesses to valid PCI
devices don't fail.
- If you don't have a struct pci_dev available, you can call
+If you don't have a struct pci_dev available, you can call
pci_bus_(read|write)_config_(byte|word|dword) to access a given device
and function on that bus.
- If you access fields in the standard portion of the config header, please
+If you access fields in the standard portion of the config header, please
use symbolic names of locations and bits declared in <linux/pci.h>.
- If you need to access Extended PCI Capability registers, just call
+If you need to access Extended PCI Capability registers, just call
pci_find_capability() for the particular capability and it will find the
corresponding register block for you.
-5. Addresses and interrupts
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Memory and port addresses and interrupt numbers should NOT be read from the
-config space. You should use the values in the pci_dev structure as they might
-have been remapped by the kernel.
-
- See Documentation/IO-mapping.txt for how to access device memory.
-
- The device driver needs to call pci_request_region() to make sure
-no other device is already using the same resource. The driver is expected
-to determine MMIO and IO Port resource availability _before_ calling
-pci_enable_device(). Conversely, drivers should call pci_release_region()
-_after_ calling pci_disable_device(). The idea is to prevent two devices
-colliding on the same address range.
-
-Generic flavors of pci_request_region() are request_mem_region()
-(for MMIO ranges) and request_region() (for IO Port ranges).
-Use these for address resources that are not described by "normal" PCI
-interfaces (e.g. BAR).
-
- All interrupt handlers should be registered with IRQF_SHARED and use the devid
-to map IRQs to devices (remember that all PCI interrupts are shared).
-
6. Other interesting functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
pci_find_slot() Find pci_dev corresponding to given bus and
slot numbers.
pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3)
@@ -247,11 +560,12 @@ pci_set_mwi() Enable Memory-Write-Invalidate transactions.
pci_clear_mwi() Disable Memory-Write-Invalidate transactions.
+
7. Miscellaneous hints
~~~~~~~~~~~~~~~~~~~~~~
-When displaying PCI slot names to the user (for example when a driver wants
-to tell the user what card has it found), please use pci_name(pci_dev)
-for this purpose.
+
+When displaying PCI device names to the user (for example when a driver wants
+to tell the user what card has it found), please use pci_name(pci_dev).
Always refer to the PCI devices by a pointer to the pci_dev structure.
All PCI layer functions use this identification and it's the only
@@ -259,31 +573,113 @@ reasonable one. Don't use bus/slot/function numbers except for very
special purposes -- on systems with multiple primary buses their semantics
can be pretty complex.
-If you're going to use PCI bus mastering DMA, take a look at
-Documentation/DMA-mapping.txt.
-
Don't try to turn on Fast Back to Back writes in your driver. All devices
on the bus need to be capable of doing it, so this is something which needs
to be handled by platform and generic code, not individual drivers.
+
8. Vendor and device identifications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-For the future, let's avoid adding device ids to include/linux/pci_ids.h.
-PCI_VENDOR_ID_xxx for vendors, and a hex constant for device ids.
+One is not not required to add new device ids to include/linux/pci_ids.h.
+Please add PCI_VENDOR_ID_xxx for vendors and a hex constant for device ids.
+
+PCI_VENDOR_ID_xxx constants are re-used. The device ids are arbitrary
+hex numbers (vendor controlled) and normally used only in a single
+location, the pci_device_id table.
+
+Please DO submit new vendor/device ids to pciids.sourceforge.net project.
+
-Rationale: PCI_VENDOR_ID_xxx constants are re-used, but device ids are not.
- Further, device ids are arbitrary hex numbers, normally used only in a
- single location, the pci_device_id table.
9. Obsolete functions
~~~~~~~~~~~~~~~~~~~~~
+
There are several functions which you might come across when trying to
port an old driver to the new PCI interface. They are no longer present
in the kernel as they aren't compatible with hotplug or PCI domains or
having sane locking.
-pci_find_device() Superseded by pci_get_device()
-pci_find_subsys() Superseded by pci_get_subsys()
-pci_find_slot() Superseded by pci_get_slot()
+pci_find_device() Superseded by pci_get_device()
+pci_find_subsys() Superseded by pci_get_subsys()
+pci_find_slot() Superseded by pci_get_slot()
+
+
+The alternative is the traditional PCI device driver that walks PCI
+device lists. This is still possible but discouraged.
+
+
+
+10. pci_enable_device_bars() and Legacy I/O Port space
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Large servers may not be able to provide I/O port resources to all PCI
+devices. I/O Port space is only 64KB on Intel Architecture[1] and is
+likely also fragmented since the I/O base register of PCI-to-PCI
+bridge will usually be aligned to a 4KB boundary[2]. On such systems,
+pci_enable_device() and pci_request_region() will fail when
+attempting to enable I/O Port regions that don't have I/O Port
+resources assigned.
+
+Fortunately, many PCI devices which request I/O Port resources also
+provide access to the same registers via MMIO BARs. These devices can
+be handled without using I/O port space and the drivers typically
+offer a CONFIG_ option to only use MMIO regions
+(e.g. CONFIG_TULIP_MMIO). PCI devices typically provide I/O port
+interface for legacy OSes and will work when I/O port resources are not
+assigned. The "PCI Local Bus Specification Revision 3.0" discusses
+this on p.44, "IMPLEMENTATION NOTE".
+
+If your PCI device driver doesn't need I/O port resources assigned to
+I/O Port BARs, you should use pci_enable_device_bars() instead of
+pci_enable_device() in order not to enable I/O port regions for the
+corresponding devices. In addition, you should use
+pci_request_selected_regions() and pci_release_selected_regions()
+instead of pci_request_regions()/pci_release_regions() in order not to
+request/release I/O port regions for the corresponding devices.
+
+[1] Some systems support 64KB I/O port space per PCI segment.
+[2] Some PCI-to-PCI bridges support optional 1KB aligned I/O base.
+
+
+
+11. MMIO Space and "Write Posting"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Converting a driver from using I/O Port space to using MMIO space
+often requires some additional changes. Specifically, "write posting"
+needs to be handled. Many drivers (e.g. tg3, acenic, sym53c8xx_2)
+already do this. I/O Port space guarantees write transactions reach the PCI
+device before the CPU can continue. Writes to MMIO space allow the CPU
+to continue before the transaction reaches the PCI device. HW weenies
+call this "Write Posting" because the write completion is "posted" to
+the CPU before the transaction has reached its destination.
+
+Thus, timing sensitive code should add readl() where the CPU is
+expected to wait before doing other work. The classic "bit banging"
+sequence works fine for I/O Port space:
+
+ for (i = 8; --i; val >>= 1) {
+ outb(val & 1, ioport_reg); /* write bit */
+ udelay(10);
+ }
+
+The same sequence for MMIO space should be:
+
+ for (i = 8; --i; val >>= 1) {
+ writeb(val & 1, mmio_reg); /* write bit */
+ readb(safe_mmio_reg); /* flush posted write */
+ udelay(10);
+ }
+
+It is important that "safe_mmio_reg" not have any side effects that
+interferes with the correct operation of the device.
+
+Another case to watch out for is when resetting a PCI device. Use PCI
+Configuration space reads to flush the writel(). This will gracefully
+handle the PCI master abort on all platforms if the PCI device is
+expected to not respond to a readl(). Most x86 platforms will allow
+MMIO reads to master abort (a.k.a. "Soft Fail") and return garbage
+(e.g. ~0). But many RISC platforms will crash (a.k.a."Hard Fail").
+
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index b3bd36668db..33994271cb3 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1703,29 +1703,32 @@ platforms are moved over to use the flattened-device-tree model.
Required properties:
- device_type : has to be "rom"
- - compatible : Should specify what this ROM device is compatible with
- (i.e. "onenand"). Currently, this is most likely to be "direct-mapped"
- (which corresponds to the MTD physmap mapping driver).
- - regs : Offset and length of the register set (or memory mapping) for
+ - compatible : Should specify what this flash device is compatible with.
+ Currently, this is most likely to be "direct-mapped" (which
+ corresponds to the MTD physmap mapping driver).
+ - reg : Offset and length of the register set (or memory mapping) for
the device.
+ - bank-width : Width of the flash data bus in bytes. Required
+ for the NOR flashes (compatible == "direct-mapped" and others) ONLY.
Recommended properties :
- - bank-width : Width of the flash data bus in bytes. Required
- for the NOR flashes (compatible == "direct-mapped" and others) ONLY.
- partitions : Several pairs of 32-bit values where the first value is
partition's offset from the start of the device and the second one is
partition size in bytes with LSB used to signify a read only
- partititon (so, the parition size should always be an even number).
+ partition (so, the parition size should always be an even number).
- partition-names : The list of concatenated zero terminated strings
representing the partition names.
+ - probe-type : The type of probe which should be done for the chip
+ (JEDEC vs CFI actually). Valid ONLY for NOR flashes.
Example:
flash@ff000000 {
device_type = "rom";
compatible = "direct-mapped";
- regs = <ff000000 01000000>;
+ probe-type = "CFI";
+ reg = <ff000000 01000000>;
bank-width = <4>;
partitions = <00000000 00f80000
00f80000 00080001>;
diff --git a/Documentation/powerpc/mpc52xx-device-tree-bindings.txt b/Documentation/powerpc/mpc52xx-device-tree-bindings.txt
index d077d764f82..69f016f02bb 100644
--- a/Documentation/powerpc/mpc52xx-device-tree-bindings.txt
+++ b/Documentation/powerpc/mpc52xx-device-tree-bindings.txt
@@ -4,6 +4,12 @@ MPC52xx Device Tree Bindings
(c) 2006 Secret Lab Technologies Ltd
Grant Likely <grant.likely at secretlab.ca>
+********** DRAFT ***********
+* WARNING: Do not depend on the stability of these bindings just yet.
+* The MPC5200 device tree conventions are still in flux
+* Keep an eye on the linuxppc-dev mailing list for more details
+********** DRAFT ***********
+
I - Introduction
================
Boards supported by the arch/powerpc architecture require device tree be
@@ -157,8 +163,8 @@ rtc@<addr> rtc *-rtc Real time clock
mscan@<addr> mscan *-mscan CAN bus controller
pci@<addr> pci *-pci PCI bridge
serial@<addr> serial *-psc-uart PSC in serial mode
-i2s@<addr> i2s *-psc-i2s PSC in i2s mode
-ac97@<addr> ac97 *-psc-ac97 PSC in ac97 mode
+i2s@<addr> sound *-psc-i2s PSC in i2s mode
+ac97@<addr> sound *-psc-ac97 PSC in ac97 mode
spi@<addr> spi *-psc-spi PSC in spi mode
irda@<addr> irda *-psc-irda PSC in IrDA mode
spi@<addr> spi *-spi MPC52xx spi device
diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt
index 3f9ddbc23b2..0993969609c 100644
--- a/Documentation/s390/Debugging390.txt
+++ b/Documentation/s390/Debugging390.txt
@@ -480,7 +480,7 @@ r2 argument 0 / return value 0 call-clobbered
r3 argument 1 / return value 1 (if long long) call-clobbered
r4 argument 2 call-clobbered
r5 argument 3 call-clobbered
-r6 argument 5 saved
+r6 argument 4 saved
r7 pointer-to arguments 5 to ... saved
r8 this & that saved
r9 this & that saved
diff --git a/Documentation/s390/driver-model.txt b/Documentation/s390/driver-model.txt
index 77bf450ec39..e938c442277 100644
--- a/Documentation/s390/driver-model.txt
+++ b/Documentation/s390/driver-model.txt
@@ -18,11 +18,18 @@ devices/
- 0.0.0002/
- 0.1.0000/0.1.1234/
...
+ - defunct/
In this example, device 0815 is accessed via subchannel 0 in subchannel set 0,
device 4711 via subchannel 1 in subchannel set 0, and subchannel 2 is a non-I/O
subchannel. Device 1234 is accessed via subchannel 0 in subchannel set 1.
+The subchannel named 'defunct' does not represent any real subchannel on the
+system; it is a pseudo subchannel where disconnnected ccw devices are moved to
+if they are displaced by another ccw device becoming operational on their
+former subchannel. The ccw devices will be moved again to a proper subchannel
+if they become operational again on that subchannel.
+
You should address a ccw device via its bus id (e.g. 0.0.4711); the device can
be found under bus/ccw/devices/.
diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt
index 3367130e64f..dc8e44fc650 100644
--- a/Documentation/scsi/aacraid.txt
+++ b/Documentation/scsi/aacraid.txt
@@ -11,43 +11,42 @@ the original).
Supported Cards/Chipsets
-------------------------
PCI ID (pci.ids) OEM Product
- 9005:0283:9005:0283 Adaptec Catapult (3210S with arc firmware)
- 9005:0284:9005:0284 Adaptec Tomcat (3410S with arc firmware)
9005:0285:9005:0285 Adaptec 2200S (Vulcan)
9005:0285:9005:0286 Adaptec 2120S (Crusader)
9005:0285:9005:0287 Adaptec 2200S (Vulcan-2m)
9005:0285:9005:0288 Adaptec 3230S (Harrier)
9005:0285:9005:0289 Adaptec 3240S (Tornado)
9005:0285:9005:028a Adaptec 2020ZCR (Skyhawk)
- 9005:0285:9005:028b Adaptec 2025ZCR (Terminator)
+ 9005:0285:9005:028b Adaptec 2025ZCR (Terminator)
9005:0286:9005:028c Adaptec 2230S (Lancer)
9005:0286:9005:028c Adaptec 2230SLP (Lancer)
9005:0286:9005:028d Adaptec 2130S (Lancer)
9005:0285:9005:028e Adaptec 2020SA (Skyhawk)
- 9005:0285:9005:028f Adaptec 2025SA (Terminator)
+ 9005:0285:9005:028f Adaptec 2025SA (Terminator)
9005:0285:9005:0290 Adaptec 2410SA (Jaguar)
- 9005:0285:103c:3227 Adaptec 2610SA (Bearcat HP release)
- 9005:0285:9005:0293 Adaptec 21610SA (Corsair-16)
+ 9005:0285:103c:3227 Adaptec 2610SA (Bearcat HP release)
+ 9005:0285:9005:0293 Adaptec 21610SA (Corsair-16)
9005:0285:9005:0296 Adaptec 2240S (SabreExpress)
9005:0285:9005:0292 Adaptec 2810SA (Corsair-8)
- 9005:0285:9005:0294 Adaptec Prowler
- 9005:0285:9005:0297 Adaptec 4005SAS (AvonPark)
- 9005:0285:9005:0298 Adaptec 4000SAS (BlackBird)
+ 9005:0285:9005:0297 Adaptec 4005 (AvonPark)
+ 9005:0285:9005:0298 Adaptec 4000 (BlackBird)
9005:0285:9005:0299 Adaptec 4800SAS (Marauder-X)
9005:0285:9005:029a Adaptec 4805SAS (Marauder-E)
9005:0286:9005:029b Adaptec 2820SA (Intruder)
9005:0286:9005:029c Adaptec 2620SA (Intruder)
9005:0286:9005:029d Adaptec 2420SA (Intruder HP release)
- 9005:0286:9005:02a2 Adaptec 3800SAS (Hurricane44)
- 9005:0286:9005:02a7 Adaptec 3805SAS (Hurricane80)
- 9005:0286:9005:02a8 Adaptec 3400SAS (Hurricane40)
- 9005:0286:9005:02ac Adaptec 1800SAS (Typhoon44)
- 9005:0286:9005:02b3 Adaptec 2400SAS (Hurricane40lm)
- 9005:0285:9005:02b5 Adaptec ASR5800 (Voodoo44)
- 9005:0285:9005:02b6 Adaptec ASR5805 (Voodoo80)
- 9005:0285:9005:02b7 Adaptec ASR5808 (Voodoo08)
+ 9005:0286:9005:02ac Adaptec 1800 (Typhoon44)
+ 9005:0285:9005:02b5 Adaptec 5445 (Voodoo44)
+ 9005:0285:9005:02b6 Adaptec 5805 (Voodoo80)
+ 9005:0285:9005:02b7 Adaptec 5085 (Voodoo08)
+ 9005:0285:9005:02bb Adaptec 3405 (Marauder40LP)
+ 9005:0285:9005:02bc Adaptec 3805 (Marauder80LP)
+ 9005:0285:9005:02c7 Adaptec 3085 (Marauder08ELP)
+ 9005:0285:9005:02bd Adaptec 31205 (Marauder120)
+ 9005:0285:9005:02be Adaptec 31605 (Marauder160)
+ 9005:0285:9005:02c3 Adaptec 51205 (Voodoo120)
+ 9005:0285:9005:02c4 Adaptec 51605 (Voodoo160)
1011:0046:9005:0364 Adaptec 5400S (Mustang)
- 1011:0046:9005:0365 Adaptec 5400S (Mustang)
9005:0287:9005:0800 Adaptec Themisto (Jupiter)
9005:0200:9005:0200 Adaptec Themisto (Jupiter)
9005:0286:9005:0800 Adaptec Callisto (Jupiter)
@@ -68,21 +67,32 @@ Supported Cards/Chipsets
9005:0285:17aa:0287 Legend S230 (Vulcan)
9005:0285:9005:0290 IBM ServeRAID 7t (Jaguar)
9005:0285:1014:02F2 IBM ServeRAID 8i (AvonPark)
- 9005:0285:1014:0312 IBM ServeRAID 8i (AvonParkLite)
9005:0286:1014:9540 IBM ServeRAID 8k/8k-l4 (AuroraLite)
9005:0286:1014:9580 IBM ServeRAID 8k/8k-l8 (Aurora)
- 9005:0286:1014:034d IBM ServeRAID 8s (Hurricane)
- 9005:0286:9005:029e ICP ICP9024R0 (Lancer)
- 9005:0286:9005:029f ICP ICP9014R0 (Lancer)
+ 9005:0285:1014:034d IBM ServeRAID 8s (Marauder-E)
+ 9005:0286:9005:029e ICP ICP9024RO (Lancer)
+ 9005:0286:9005:029f ICP ICP9014RO (Lancer)
9005:0286:9005:02a0 ICP ICP9047MA (Lancer)
9005:0286:9005:02a1 ICP ICP9087MA (Lancer)
- 9005:0286:9005:02a3 ICP ICP5445AU (Hurricane44)
- 9005:0286:9005:02a4 ICP ICP9085LI (Marauder-X)
- 9005:0286:9005:02a5 ICP ICP5085BR (Marauder-E)
+ 9005:0285:9005:02a4 ICP ICP9085LI (Marauder-X)
+ 9005:0285:9005:02a5 ICP ICP5085BR (Marauder-E)
9005:0286:9005:02a6 ICP ICP9067MA (Intruder-6)
- 9005:0286:9005:02a9 ICP ICP5085AU (Hurricane80)
- 9005:0286:9005:02aa ICP ICP5045AU (Hurricane40)
- 9005:0286:9005:02b4 ICP ICP5045AL (Hurricane40lm)
+ 9005:0285:9005:02b2 ICP (Voodoo 8 internal 8 external)
+ 9005:0285:9005:02b8 ICP ICP5445SL (Voodoo44)
+ 9005:0285:9005:02b9 ICP ICP5085SL (Voodoo80)
+ 9005:0285:9005:02ba ICP ICP5805SL (Voodoo08)
+ 9005:0285:9005:02bf ICP ICP5045BL (Marauder40LP)
+ 9005:0285:9005:02c0 ICP ICP5085BL (Marauder80LP)
+ 9005:0285:9005:02c8 ICP ICP5805BL (Marauder08ELP)
+ 9005:0285:9005:02c1 ICP ICP5125BR (Marauder120)
+ 9005:0285:9005:02c2 ICP ICP5165BR (Marauder160)
+ 9005:0285:9005:02c5 ICP ICP5125SL (Voodoo120)
+ 9005:0285:9005:02c6 ICP ICP5165SL (Voodoo160)
+ 9005:0286:9005:02ab (Typhoon40)
+ 9005:0286:9005:02ad (Aurora ARK)
+ 9005:0286:9005:02ae (Aurora Lite ARK)
+ 9005:0285:9005:02b0 (Sunrise Lake ARK)
+ 9005:0285:9005:02b1 Adaptec (Voodoo 8 internal 8 external)
People
-------------------------
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 9fef210ab50..c30ff1bb2d1 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -242,6 +242,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
ac97_clock - AC'97 clock (default = 48000)
ac97_quirk - AC'97 workaround for strange hardware
See "AC97 Quirk Option" section below.
+ ac97_codec - Workaround to specify which AC'97 codec
+ instead of probing. If this works for you
+ file a bug with your `lspci -vn` output.
+ -2 -- Force probing.
+ -1 -- Default behavior.
+ 0-2 -- Use the specified codec.
spdif_aclink - S/PDIF transfer over AC-link (default = 1)
This module supports one card and autoprobe.
@@ -779,6 +785,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
asus-dig ASUS with SPDIF out
asus-dig2 ASUS with SPDIF out (using GPIO2)
uniwill 3-jack
+ fujitsu Fujitsu Laptops (Pi1536)
F1734 2-jack
lg LG laptop (m1 express dual)
lg-lw LG LW20/LW25 laptop
@@ -800,14 +807,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
ALC262
fujitsu Fujitsu Laptop
hp-bpc HP xw4400/6400/8400/9400 laptops
+ hp-bpc-d7000 HP BPC D7000
benq Benq ED8
+ hippo Hippo (ATI) with jack detection, Sony UX-90s
+ hippo_1 Hippo (Benq) with jack detection
basic fixed pin assignment w/o SPDIF
auto auto-config reading BIOS (default)
ALC882/885
3stack-dig 3-jack with SPDIF I/O
- 6stck-dig 6-jack digital with SPDIF I/O
+ 6stack-dig 6-jack digital with SPDIF I/O
arima Arima W820Di1
+ macpro MacPro support
auto auto-config reading BIOS (default)
ALC883/888
@@ -817,6 +828,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
6stack-dig-demo 6-jack digital for Intel demo board
acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
+ medion Medion Laptops
+ targa-dig Targa/MSI
+ targa-2ch-dig Targs/MSI with 2-channel
+ laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
auto auto-config reading BIOS (default)
ALC861/660
@@ -825,6 +840,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
6stack-dig 6-jack with SPDIF I/O
3stack-660 3-jack (for ALC660)
uniwill-m31 Uniwill M31 laptop
+ toshiba Toshiba laptop support
+ asus Asus laptop support
+ asus-laptop ASUS F2/F3 laptops
+ auto auto-config reading BIOS (default)
+
+ ALC861VD/660VD
+ 3stack 3-jack
+ 3stack-dig 3-jack with SPDIF OUT
+ 6stack-dig 6-jack with SPDIF OUT
+ 3stack-660 3-jack (for ALC660VD)
auto auto-config reading BIOS (default)
CMI9880
@@ -845,6 +870,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
3stack 3-stack, shared surrounds
laptop 2-channel only (FSC V2060, Samsung M50)
laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J)
+ ultra 2-channel with EAPD (Samsung Ultra tablet PC)
AD1988
6stack 6-jack
@@ -854,12 +880,31 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
laptop 3-jack with hp-jack automute
laptop-dig ditto with SPDIF
auto auto-config reading BIOS (default)
+
+ Conexant 5045
+ laptop Laptop config
+ test for testing/debugging purpose, almost all controls
+ can be adjusted. Appearing only when compiled with
+ $CONFIG_SND_DEBUG=y
+
+ Conexant 5047
+ laptop Basic Laptop config
+ laptop-hp Laptop config for some HP models (subdevice 30A5)
+ laptop-eapd Laptop config with EAPD support
+ test for testing/debugging purpose, almost all controls
+ can be adjusted. Appearing only when compiled with
+ $CONFIG_SND_DEBUG=y
STAC9200/9205/9220/9221/9254
ref Reference board
3stack D945 3stack
5stack D945 5stack + SPDIF
+ STAC9202/9250/9251
+ ref Reference board, base config
+ m2-2 Some Gateway MX series laptops
+ m6 Some Gateway NX series laptops
+
STAC9227/9228/9229/927x
ref Reference board
3stack D965 3stack
@@ -974,6 +1019,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards.
* MidiMan M Audio Revolution 5.1
* MidiMan M Audio Revolution 7.1
+ * MidiMan M Audio Audiophile 192
* AMP Ltd AUDIO2000
* TerraTec Aureon 5.1 Sky
* TerraTec Aureon 7.1 Space
@@ -993,7 +1039,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
model - Use the given board model, one of the following:
revo51, revo71, amp2000, prodigy71, prodigy71lt,
- prodigy192, aureon51, aureon71, universe,
+ prodigy192, aureon51, aureon71, universe, ap192,
k8x800, phase22, phase28, ms300, av710
This module supports multiple cards and autoprobe.
@@ -1049,6 +1095,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
buggy_semaphore - Enable workaround for hardwares with buggy
semaphores (e.g. on some ASUS laptops)
(default off)
+ spdif_aclink - Use S/PDIF over AC-link instead of direct connection
+ from the controller chip
+ (0 = off, 1 = on, -1 = default)
This module supports one chip and autoprobe.
@@ -1371,6 +1420,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
This module supports multiple cards.
+ Module snd-portman2x4
+ ---------------------
+
+ Module for Midiman Portman 2x4 parallel port MIDI interface
+
+ This module supports multiple cards.
+
Module snd-powermac (on ppc only)
---------------------------------
diff --git a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl
index 1f3ae3e32d6..c4d2e3507af 100644
--- a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl
+++ b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl
@@ -36,7 +36,7 @@
</bookinfo>
<chapter><title>Management of Cards and Devices</title>
- <sect1><title>Card Managment</title>
+ <sect1><title>Card Management</title>
!Esound/core/init.c
</sect1>
<sect1><title>Device Components</title>
@@ -59,7 +59,7 @@
<sect1><title>PCM Format Helpers</title>
!Esound/core/pcm_misc.c
</sect1>
- <sect1><title>PCM Memory Managment</title>
+ <sect1><title>PCM Memory Management</title>
!Esound/core/pcm_memory.c
</sect1>
</chapter>
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
index 077fbe25ebf..74d3a35b59b 100644
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -927,7 +927,7 @@
<informalexample>
<programlisting>
<![CDATA[
- struct mychip *chip = (struct mychip *)card->private_data;
+ struct mychip *chip = card->private_data;
]]>
</programlisting>
</informalexample>
@@ -1095,7 +1095,7 @@
/* release the irq */
if (chip->irq >= 0)
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, chip);
/* release the i/o ports & memory */
pci_release_regions(chip->pci);
/* disable the PCI entry */
@@ -1148,7 +1148,7 @@
}
chip->port = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_mychip_interrupt,
- IRQF_DISABLED|IRQF_SHARED, "My Chip", chip)) {
+ IRQF_SHARED, "My Chip", chip)) {
printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
snd_mychip_free(chip);
return -EBUSY;
@@ -1360,8 +1360,7 @@
<informalexample>
<programlisting>
<![CDATA[
- static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+ static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
{
struct mychip *chip = dev_id;
....
@@ -1387,7 +1386,7 @@
<programlisting>
<![CDATA[
if (chip->irq >= 0)
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, chip);
]]>
</programlisting>
</informalexample>
@@ -2127,7 +2126,7 @@
accessible via <constant>substream-&gt;runtime</constant>.
This runtime pointer holds the various information; it holds
the copy of hw_params and sw_params configurations, the buffer
- pointers, mmap records, spinlocks, etc. Almost everyhing you
+ pointers, mmap records, spinlocks, etc. Almost everything you
need for controlling the PCM can be found there.
</para>
@@ -2340,7 +2339,7 @@ struct _snd_pcm_runtime {
<para>
When the PCM substreams can be synchronized (typically,
- synchorinized start/stop of a playback and a capture streams),
+ synchronized start/stop of a playback and a capture streams),
you can give <constant>SNDRV_PCM_INFO_SYNC_START</constant>,
too. In this case, you'll need to check the linked-list of
PCM substreams in the trigger callback. This will be
@@ -3062,8 +3061,7 @@ struct _snd_pcm_runtime {
<title>Interrupt Handler Case #1</title>
<programlisting>
<![CDATA[
- static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+ static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
{
struct mychip *chip = dev_id;
spin_lock(&chip->lock);
@@ -3106,8 +3104,7 @@ struct _snd_pcm_runtime {
<title>Interrupt Handler Case #2</title>
<programlisting>
<![CDATA[
- static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+ static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
{
struct mychip *chip = dev_id;
spin_lock(&chip->lock);
@@ -3247,7 +3244,7 @@ struct _snd_pcm_runtime {
You can even define your own constraint rules.
For example, let's suppose my_chip can manage a substream of 1 channel
if and only if the format is S16_LE, otherwise it supports any format
- specified in the <structname>snd_pcm_hardware</structname> stucture (or in any
+ specified in the <structname>snd_pcm_hardware</structname> structure (or in any
other constraint_list). You can build a rule like this:
<example>
@@ -3691,16 +3688,6 @@ struct _snd_pcm_runtime {
</para>
<para>
- Here, the chip instance is retrieved via
- <function>snd_kcontrol_chip()</function> macro. This macro
- just accesses to kcontrol-&gt;private_data. The
- kcontrol-&gt;private_data field is
- given as the argument of <function>snd_ctl_new()</function>
- (see the later subsection
- <link linkend="control-interface-constructor"><citetitle>Constructor</citetitle></link>).
- </para>
-
- <para>
The <structfield>value</structfield> field is depending on
the type of control as well as on info callback. For example,
the sb driver uses this field to store the register offset,
@@ -3780,7 +3767,7 @@ struct _snd_pcm_runtime {
<para>
Like <structfield>get</structfield> callback,
when the control has more than one elements,
- all elemehts must be evaluated in this callback, too.
+ all elements must be evaluated in this callback, too.
</para>
</section>
@@ -5541,12 +5528,12 @@ struct _snd_pcm_runtime {
#ifdef CONFIG_PM
static int snd_my_suspend(struct pci_dev *pci, pm_message_t state)
{
- .... /* do things for suspsend */
+ .... /* do things for suspend */
return 0;
}
static int snd_my_resume(struct pci_dev *pci)
{
- .... /* do things for suspsend */
+ .... /* do things for suspend */
return 0;
}
#endif
@@ -6111,7 +6098,7 @@ struct _snd_pcm_runtime {
<!-- ****************************************************** -->
<!-- Acknowledgments -->
<!-- ****************************************************** -->
- <chapter id="acknowledments">
+ <chapter id="acknowledgments">
<title>Acknowledgments</title>
<para>
I would like to thank Phil Kerr for his help for improvement and
diff --git a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt
index 0be57ed8130..4eaae2a4553 100644
--- a/Documentation/sound/alsa/hda_codec.txt
+++ b/Documentation/sound/alsa/hda_codec.txt
@@ -277,11 +277,11 @@ Helper Functions
snd_hda_get_codec_name() stores the codec name on the given string.
snd_hda_check_board_config() can be used to obtain the configuration
-information matching with the device. Define the table with struct
-hda_board_config entries (zero-terminated), and pass it to the
-function. The function checks the modelname given as a module
-parameter, and PCI subsystem IDs. If the matching entry is found, it
-returns the config field value.
+information matching with the device. Define the model string table
+and the table with struct snd_pci_quirk entries (zero-terminated),
+and pass it to the function. The function checks the modelname given
+as a module parameter, and PCI subsystem IDs. If the matching entry
+is found, it returns the config field value.
snd_hda_add_new_ctls() can be used to create and add control entries.
Pass the zero-terminated array of struct snd_kcontrol_new. The same array
diff --git a/Documentation/sound/alsa/soc/DAI.txt b/Documentation/sound/alsa/soc/DAI.txt
new file mode 100644
index 00000000000..58cbfd01ea8
--- /dev/null
+++ b/Documentation/sound/alsa/soc/DAI.txt
@@ -0,0 +1,56 @@
+ASoC currently supports the three main Digital Audio Interfaces (DAI) found on
+SoC controllers and portable audio CODECS today, namely AC97, I2S and PCM.
+
+
+AC97
+====
+
+ AC97 is a five wire interface commonly found on many PC sound cards. It is
+now also popular in many portable devices. This DAI has a reset line and time
+multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines.
+The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the
+frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
+frame is 21uS long and is divided into 13 time slots.
+
+The AC97 specification can be found at :-
+http://www.intel.com/design/chipsets/audio/ac97_r23.pdf
+
+
+I2S
+===
+
+ I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and
+Rx lines are used for audio transmision, whilst the bit clock (BCLK) and
+left/right clock (LRC) synchronise the link. I2S is flexible in that either the
+controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock
+usually varies depending on the sample rate and the master system clock
+(SYSCLK). LRCLK is the same as the sample rate. A few devices support separate
+ADC and DAC LRCLK's, this allows for similtanious capture and playback at
+different sample rates.
+
+I2S has several different operating modes:-
+
+ o I2S - MSB is transmitted on the falling edge of the first BCLK after LRC
+ transition.
+
+ o Left Justified - MSB is transmitted on transition of LRC.
+
+ o Right Justified - MSB is transmitted sample size BCLK's before LRC
+ transition.
+
+PCM
+===
+
+PCM is another 4 wire interface, very similar to I2S, that can support a more
+flexible protocol. It has bit clock (BCLK) and sync (SYNC) lines that are used
+to synchronise the link whilst the Tx and Rx lines are used to transmit and
+receive the audio data. Bit clock usually varies depending on sample rate
+whilst sync runs at the sample rate. PCM also supports Time Division
+Multiplexing (TDM) in that several devices can use the bus similtaniuosly (This
+is sometimes referred to as network mode).
+
+Common PCM operating modes:-
+
+ o Mode A - MSB is transmitted on falling edge of first BCLK after FRAME/SYNC.
+
+ o Mode B - MSB is transmitted on rising edge of FRAME/SYNC.
diff --git a/Documentation/sound/alsa/soc/clocking.txt b/Documentation/sound/alsa/soc/clocking.txt
new file mode 100644
index 00000000000..e93960d53a1
--- /dev/null
+++ b/Documentation/sound/alsa/soc/clocking.txt
@@ -0,0 +1,51 @@
+Audio Clocking
+==============
+
+This text describes the audio clocking terms in ASoC and digital audio in
+general. Note: Audio clocking can be complex !
+
+
+Master Clock
+------------
+
+Every audio subsystem is driven by a master clock (sometimes refered to as MCLK
+or SYSCLK). This audio master clock can be derived from a number of sources
+(e.g. crystal, PLL, CPU clock) and is responsible for producing the correct
+audio playback and capture sample rates.
+
+Some master clocks (e.g. PLL's and CPU based clocks) are configuarble in that
+their speed can be altered by software (depending on the system use and to save
+power). Other master clocks are fixed at at set frequency (i.e. crystals).
+
+
+DAI Clocks
+----------
+The Digital Audio Interface is usually driven by a Bit Clock (often referred to
+as BCLK). This clock is used to drive the digital audio data across the link
+between the codec and CPU.
+
+The DAI also has a frame clock to signal the start of each audio frame. This
+clock is sometimes referred to as LRC (left right clock) or FRAME. This clock
+runs at exactly the sample rate (LRC = Rate).
+
+Bit Clock can be generated as follows:-
+
+BCLK = MCLK / x
+
+ or
+
+BCLK = LRC * x
+
+ or
+
+BCLK = LRC * Channels * Word Size
+
+This relationship depends on the codec or SoC CPU in particular. In general
+it's best to configure BCLK to the lowest possible speed (depending on your
+rate, number of channels and wordsize) to save on power.
+
+It's also desireable to use the codec (if possible) to drive (or master) the
+audio clocks as it's usually gives more accurate sample rates than the CPU.
+
+
+
diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt
new file mode 100644
index 00000000000..48983c75aad
--- /dev/null
+++ b/Documentation/sound/alsa/soc/codec.txt
@@ -0,0 +1,197 @@
+ASoC Codec Driver
+=================
+
+The codec driver is generic and hardware independent code that configures the
+codec to provide audio capture and playback. It should contain no code that is
+specific to the target platform or machine. All platform and machine specific
+code should be added to the platform and machine drivers respectively.
+
+Each codec driver *must* provide the following features:-
+
+ 1) Codec DAI and PCM configuration
+ 2) Codec control IO - using I2C, 3 Wire(SPI) or both API's
+ 3) Mixers and audio controls
+ 4) Codec audio operations
+
+Optionally, codec drivers can also provide:-
+
+ 5) DAPM description.
+ 6) DAPM event handler.
+ 7) DAC Digital mute control.
+
+It's probably best to use this guide in conjuction with the existing codec
+driver code in sound/soc/codecs/
+
+ASoC Codec driver breakdown
+===========================
+
+1 - Codec DAI and PCM configuration
+-----------------------------------
+Each codec driver must have a struct snd_soc_codec_dai to define it's DAI and
+PCM's capablities and operations. This struct is exported so that it can be
+registered with the core by your machine driver.
+
+e.g.
+
+struct snd_soc_codec_dai wm8731_dai = {
+ .name = "WM8731",
+ /* playback capabilities */
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8731_RATES,
+ .formats = WM8731_FORMATS,},
+ /* capture capabilities */
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8731_RATES,
+ .formats = WM8731_FORMATS,},
+ /* pcm operations - see section 4 below */
+ .ops = {
+ .prepare = wm8731_pcm_prepare,
+ .hw_params = wm8731_hw_params,
+ .shutdown = wm8731_shutdown,
+ },
+ /* DAI operations - see DAI.txt */
+ .dai_ops = {
+ .digital_mute = wm8731_mute,
+ .set_sysclk = wm8731_set_dai_sysclk,
+ .set_fmt = wm8731_set_dai_fmt,
+ }
+};
+EXPORT_SYMBOL_GPL(wm8731_dai);
+
+
+2 - Codec control IO
+--------------------
+The codec can ususally be controlled via an I2C or SPI style interface (AC97
+combines control with data in the DAI). The codec drivers will have to provide
+functions to read and write the codec registers along with supplying a register
+cache:-
+
+ /* IO control data and register cache */
+ void *control_data; /* codec control (i2c/3wire) data */
+ void *reg_cache;
+
+Codec read/write should do any data formatting and call the hardware read write
+below to perform the IO. These functions are called by the core and alsa when
+performing DAPM or changing the mixer:-
+
+ unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+ int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+
+Codec hardware IO functions - usually points to either the I2C, SPI or AC97
+read/write:-
+
+ hw_write_t hw_write;
+ hw_read_t hw_read;
+
+
+3 - Mixers and audio controls
+-----------------------------
+All the codec mixers and audio controls can be defined using the convenience
+macros defined in soc.h.
+
+ #define SOC_SINGLE(xname, reg, shift, mask, invert)
+
+Defines a single control as follows:-
+
+ xname = Control name e.g. "Playback Volume"
+ reg = codec register
+ shift = control bit(s) offset in register
+ mask = control bit size(s) e.g. mask of 7 = 3 bits
+ invert = the control is inverted
+
+Other macros include:-
+
+ #define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert)
+
+A stereo control
+
+ #define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert)
+
+A stereo control spanning 2 registers
+
+ #define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts)
+
+Defines an single enumerated control as follows:-
+
+ xreg = register
+ xshift = control bit(s) offset in register
+ xmask = control bit(s) size
+ xtexts = pointer to array of strings that describe each setting
+
+ #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts)
+
+Defines a stereo enumerated control
+
+
+4 - Codec Audio Operations
+--------------------------
+The codec driver also supports the following alsa operations:-
+
+/* SoC audio ops */
+struct snd_soc_ops {
+ int (*startup)(struct snd_pcm_substream *);
+ void (*shutdown)(struct snd_pcm_substream *);
+ int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
+ int (*hw_free)(struct snd_pcm_substream *);
+ int (*prepare)(struct snd_pcm_substream *);
+};
+
+Please refer to the alsa driver PCM documentation for details.
+http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
+
+
+5 - DAPM description.
+---------------------
+The Dynamic Audio Power Management description describes the codec's power
+components, their relationships and registers to the ASoC core. Please read
+dapm.txt for details of building the description.
+
+Please also see the examples in other codec drivers.
+
+
+6 - DAPM event handler
+----------------------
+This function is a callback that handles codec domain PM calls and system
+domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep
+when not in use.
+
+Power states:-
+
+ SNDRV_CTL_POWER_D0: /* full On */
+ /* vref/mid, clk and osc on, active */
+
+ SNDRV_CTL_POWER_D1: /* partial On */
+ SNDRV_CTL_POWER_D2: /* partial On */
+
+ SNDRV_CTL_POWER_D3hot: /* Off, with power */
+ /* everything off except vref/vmid, inactive */
+
+ SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */
+
+
+7 - Codec DAC digital mute control.
+------------------------------------
+Most codecs have a digital mute before the DAC's that can be used to minimise
+any system noise. The mute stops any digital data from entering the DAC.
+
+A callback can be created that is called by the core for each codec DAI when the
+mute is applied or freed.
+
+i.e.
+
+static int wm8974_mute(struct snd_soc_codec *codec,
+ struct snd_soc_codec_dai *dai, int mute)
+{
+ u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf;
+ if(mute)
+ wm8974_write(codec, WM8974_DAC, mute_reg | 0x40);
+ else
+ wm8974_write(codec, WM8974_DAC, mute_reg);
+ return 0;
+}
diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt
new file mode 100644
index 00000000000..c11877f5b4a
--- /dev/null
+++ b/Documentation/sound/alsa/soc/dapm.txt
@@ -0,0 +1,297 @@
+Dynamic Audio Power Management for Portable Devices
+===================================================
+
+1. Description
+==============
+
+Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices
+to use the minimum amount of power within the audio subsystem at all times. It
+is independent of other kernel PM and as such, can easily co-exist with the
+other PM systems.
+
+DAPM is also completely transparent to all user space applications as all power
+switching is done within the ASoC core. No code changes or recompiling are
+required for user space applications. DAPM makes power switching descisions based
+upon any audio stream (capture/playback) activity and audio mixer settings
+within the device.
+
+DAPM spans the whole machine. It covers power control within the entire audio
+subsystem, this includes internal codec power blocks and machine level power
+systems.
+
+There are 4 power domains within DAPM
+
+ 1. Codec domain - VREF, VMID (core codec and audio power)
+ Usually controlled at codec probe/remove and suspend/resume, although
+ can be set at stream time if power is not needed for sidetone, etc.
+
+ 2. Platform/Machine domain - physically connected inputs and outputs
+ Is platform/machine and user action specific, is configured by the
+ machine driver and responds to asynchronous events e.g when HP
+ are inserted
+
+ 3. Path domain - audio susbsystem signal paths
+ Automatically set when mixer and mux settings are changed by the user.
+ e.g. alsamixer, amixer.
+
+ 4. Stream domain - DAC's and ADC's.
+ Enabled and disabled when stream playback/capture is started and
+ stopped respectively. e.g. aplay, arecord.
+
+All DAPM power switching descisons are made automatically by consulting an audio
+routing map of the whole machine. This map is specific to each machine and
+consists of the interconnections between every audio component (including
+internal codec components). All audio components that effect power are called
+widgets hereafter.
+
+
+2. DAPM Widgets
+===============
+
+Audio DAPM widgets fall into a number of types:-
+
+ o Mixer - Mixes several analog signals into a single analog signal.
+ o Mux - An analog switch that outputs only 1 of it's inputs.
+ o PGA - A programmable gain amplifier or attenuation widget.
+ o ADC - Analog to Digital Converter
+ o DAC - Digital to Analog Converter
+ o Switch - An analog switch
+ o Input - A codec input pin
+ o Output - A codec output pin
+ o Headphone - Headphone (and optional Jack)
+ o Mic - Mic (and optional Jack)
+ o Line - Line Input/Output (and optional Jack)
+ o Speaker - Speaker
+ o Pre - Special PRE widget (exec before all others)
+ o Post - Special POST widget (exec after all others)
+
+(Widgets are defined in include/sound/soc-dapm.h)
+
+Widgets are usually added in the codec driver and the machine driver. There are
+convience macros defined in soc-dapm.h that can be used to quickly build a
+list of widgets of the codecs and machines DAPM widgets.
+
+Most widgets have a name, register, shift and invert. Some widgets have extra
+parameters for stream name and kcontrols.
+
+
+2.1 Stream Domain Widgets
+-------------------------
+
+Stream Widgets relate to the stream power domain and only consist of ADC's
+(analog to digital converters) and DAC's (digital to analog converters).
+
+Stream widgets have the following format:-
+
+SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert),
+
+NOTE: the stream name must match the corresponding stream name in your codecs
+snd_soc_codec_dai.
+
+e.g. stream widgets for HiFi playback and capture
+
+SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1),
+SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1),
+
+
+2.2 Path Domain Widgets
+-----------------------
+
+Path domain widgets have a ability to control or effect the audio signal or
+audio paths within the audio subsystem. They have the following form:-
+
+SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls)
+
+Any widget kcontrols can be set using the controls and num_controls members.
+
+e.g. Mixer widget (the kcontrols are declared first)
+
+/* Output Mixer */
+static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
+};
+
+SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls,
+ ARRAY_SIZE(wm8731_output_mixer_controls)),
+
+
+2.3 Platform/Machine domain Widgets
+-----------------------------------
+
+Machine widgets are different from codec widgets in that they don't have a
+codec register bit associated with them. A machine widget is assigned to each
+machine audio component (non codec) that can be independently powered. e.g.
+
+ o Speaker Amp
+ o Microphone Bias
+ o Jack connectors
+
+A machine widget can have an optional call back.
+
+e.g. Jack connector widget for an external Mic that enables Mic Bias
+when the Mic is inserted:-
+
+static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event)
+{
+ if(SND_SOC_DAPM_EVENT_ON(event))
+ set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
+ else
+ reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS);
+
+ return 0;
+}
+
+SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
+
+
+2.4 Codec Domain
+----------------
+
+The Codec power domain has no widgets and is handled by the codecs DAPM event
+handler. This handler is called when the codec powerstate is changed wrt to any
+stream event or by kernel PM events.
+
+
+2.5 Virtual Widgets
+-------------------
+
+Sometimes widgets exist in the codec or machine audio map that don't have any
+corresponding register bit for power control. In this case it's necessary to
+create a virtual widget - a widget with no control bits e.g.
+
+SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0),
+
+This can be used to merge to signal paths together in software.
+
+After all the widgets have been defined, they can then be added to the DAPM
+subsystem individually with a call to snd_soc_dapm_new_control().
+
+
+3. Codec Widget Interconnections
+================================
+
+Widgets are connected to each other within the codec and machine by audio
+paths (called interconnections). Each interconnection must be defined in order
+to create a map of all audio paths between widgets.
+This is easiest with a diagram of the codec (and schematic of the machine audio
+system), as it requires joining widgets together via their audio signal paths.
+
+i.e. from the WM8731 codec's output mixer (wm8731.c)
+
+The WM8731 output mixer has 3 inputs (sources)
+
+ 1. Line Bypass Input
+ 2. DAC (HiFi playback)
+ 3. Mic Sidetone Input
+
+Each input in this example has a kcontrol associated with it (defined in example
+above) and is connected to the output mixer via it's kcontrol name. We can now
+connect the destination widget (wrt audio signal) with it's source widgets.
+
+ /* output mixer */
+ {"Output Mixer", "Line Bypass Switch", "Line Input"},
+ {"Output Mixer", "HiFi Playback Switch", "DAC"},
+ {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
+
+So we have :-
+
+ Destination Widget <=== Path Name <=== Source Widget
+
+Or:-
+
+ Sink, Path, Source
+
+Or :-
+
+ "Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch".
+
+When there is no path name connecting widgets (e.g. a direct connection) we
+pass NULL for the path name.
+
+Interconnections are created with a call to:-
+
+snd_soc_dapm_connect_input(codec, sink, path, source);
+
+Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and
+interconnections have been registered with the core. This causes the core to
+scan the codec and machine so that the internal DAPM state matches the
+physical state of the machine.
+
+
+3.1 Machine Widget Interconnections
+-----------------------------------
+Machine widget interconnections are created in the same way as codec ones and
+directly connect the codec pins to machine level widgets.
+
+e.g. connects the speaker out codec pins to the internal speaker.
+
+ /* ext speaker connected to codec pins LOUT2, ROUT2 */
+ {"Ext Spk", NULL , "ROUT2"},
+ {"Ext Spk", NULL , "LOUT2"},
+
+This allows the DAPM to power on and off pins that are connected (and in use)
+and pins that are NC respectively.
+
+
+4 Endpoint Widgets
+===================
+An endpoint is a start or end point (widget) of an audio signal within the
+machine and includes the codec. e.g.
+
+ o Headphone Jack
+ o Internal Speaker
+ o Internal Mic
+ o Mic Jack
+ o Codec Pins
+
+When a codec pin is NC it can be marked as not used with a call to
+
+snd_soc_dapm_set_endpoint(codec, "Widget Name", 0);
+
+The last argument is 0 for inactive and 1 for active. This way the pin and its
+input widget will never be powered up and consume power.
+
+This also applies to machine widgets. e.g. if a headphone is connected to a
+jack then the jack can be marked active. If the headphone is removed, then
+the headphone jack can be marked inactive.
+
+
+5 DAPM Widget Events
+====================
+
+Some widgets can register their interest with the DAPM core in PM events.
+e.g. A Speaker with an amplifier registers a widget so the amplifier can be
+powered only when the spk is in use.
+
+/* turn speaker amplifier on/off depending on use */
+static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+ else
+ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+
+ return 0;
+}
+
+/* corgi machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets =
+ SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event);
+
+Please see soc-dapm.h for all other widgets that support events.
+
+
+5.1 Event types
+---------------
+
+The following event types are supported by event widgets.
+
+/* dapm event types */
+#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
+#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
+#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
+#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
+#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
+#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt
new file mode 100644
index 00000000000..72bd222f2a2
--- /dev/null
+++ b/Documentation/sound/alsa/soc/machine.txt
@@ -0,0 +1,113 @@
+ASoC Machine Driver
+===================
+
+The ASoC machine (or board) driver is the code that glues together the platform
+and codec drivers.
+
+The machine driver can contain codec and platform specific code. It registers
+the audio subsystem with the kernel as a platform device and is represented by
+the following struct:-
+
+/* SoC machine */
+struct snd_soc_machine {
+ char *name;
+
+ int (*probe)(struct platform_device *pdev);
+ int (*remove)(struct platform_device *pdev);
+
+ /* the pre and post PM functions are used to do any PM work before and
+ * after the codec and DAI's do any PM work. */
+ int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
+ int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
+ int (*resume_pre)(struct platform_device *pdev);
+ int (*resume_post)(struct platform_device *pdev);
+
+ /* machine stream operations */
+ struct snd_soc_ops *ops;
+
+ /* CPU <--> Codec DAI links */
+ struct snd_soc_dai_link *dai_link;
+ int num_links;
+};
+
+probe()/remove()
+----------------
+probe/remove are optional. Do any machine specific probe here.
+
+
+suspend()/resume()
+------------------
+The machine driver has pre and post versions of suspend and resume to take care
+of any machine audio tasks that have to be done before or after the codec, DAI's
+and DMA is suspended and resumed. Optional.
+
+
+Machine operations
+------------------
+The machine specific audio operations can be set here. Again this is optional.
+
+
+Machine DAI Configuration
+-------------------------
+The machine DAI configuration glues all the codec and CPU DAI's together. It can
+also be used to set up the DAI system clock and for any machine related DAI
+initialisation e.g. the machine audio map can be connected to the codec audio
+map, unconnnected codec pins can be set as such. Please see corgi.c, spitz.c
+for examples.
+
+struct snd_soc_dai_link is used to set up each DAI in your machine. e.g.
+
+/* corgi digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link corgi_dai = {
+ .name = "WM8731",
+ .stream_name = "WM8731",
+ .cpu_dai = &pxa_i2s_dai,
+ .codec_dai = &wm8731_dai,
+ .init = corgi_wm8731_init,
+ .ops = &corgi_ops,
+};
+
+struct snd_soc_machine then sets up the machine with it's DAI's. e.g.
+
+/* corgi audio machine driver */
+static struct snd_soc_machine snd_soc_machine_corgi = {
+ .name = "Corgi",
+ .dai_link = &corgi_dai,
+ .num_links = 1,
+};
+
+
+Machine Audio Subsystem
+-----------------------
+
+The machine soc device glues the platform, machine and codec driver together.
+Private data can also be set here. e.g.
+
+/* corgi audio private data */
+static struct wm8731_setup_data corgi_wm8731_setup = {
+ .i2c_address = 0x1b,
+};
+
+/* corgi audio subsystem */
+static struct snd_soc_device corgi_snd_devdata = {
+ .machine = &snd_soc_machine_corgi,
+ .platform = &pxa2xx_soc_platform,
+ .codec_dev = &soc_codec_dev_wm8731,
+ .codec_data = &corgi_wm8731_setup,
+};
+
+
+Machine Power Map
+-----------------
+
+The machine driver can optionally extend the codec power map and to become an
+audio power map of the audio subsystem. This allows for automatic power up/down
+of speaker/HP amplifiers, etc. Codec pins can be connected to the machines jack
+sockets in the machine init function. See soc/pxa/spitz.c and dapm.txt for
+details.
+
+
+Machine Controls
+----------------
+
+Machine specific audio mixer controls can be added in the dai init function. \ No newline at end of file
diff --git a/Documentation/sound/alsa/soc/overview.txt b/Documentation/sound/alsa/soc/overview.txt
new file mode 100644
index 00000000000..753c5cc5984
--- /dev/null
+++ b/Documentation/sound/alsa/soc/overview.txt
@@ -0,0 +1,83 @@
+ALSA SoC Layer
+==============
+
+The overall project goal of the ALSA System on Chip (ASoC) layer is to provide
+better ALSA support for embedded system on chip procesors (e.g. pxa2xx, au1x00,
+iMX, etc) and portable audio codecs. Currently there is some support in the
+kernel for SoC audio, however it has some limitations:-
+
+ * Currently, codec drivers are often tightly coupled to the underlying SoC
+ cpu. This is not ideal and leads to code duplication i.e. Linux now has 4
+ different wm8731 drivers for 4 different SoC platforms.
+
+ * There is no standard method to signal user initiated audio events.
+ e.g. Headphone/Mic insertion, Headphone/Mic detection after an insertion
+ event. These are quite common events on portable devices and ofter require
+ machine specific code to re route audio, enable amps etc after such an event.
+
+ * Current drivers tend to power up the entire codec when playing
+ (or recording) audio. This is fine for a PC, but tends to waste a lot of
+ power on portable devices. There is also no support for saving power via
+ changing codec oversampling rates, bias currents, etc.
+
+
+ASoC Design
+===========
+
+The ASoC layer is designed to address these issues and provide the following
+features :-
+
+ * Codec independence. Allows reuse of codec drivers on other platforms
+ and machines.
+
+ * Easy I2S/PCM audio interface setup between codec and SoC. Each SoC interface
+ and codec registers it's audio interface capabilities with the core and are
+ subsequently matched and configured when the application hw params are known.
+
+ * Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to
+ it's minimum power state at all times. This includes powering up/down
+ internal power blocks depending on the internal codec audio routing and any
+ active streams.
+
+ * Pop and click reduction. Pops and clicks can be reduced by powering the
+ codec up/down in the correct sequence (including using digital mute). ASoC
+ signals the codec when to change power states.
+
+ * Machine specific controls: Allow machines to add controls to the sound card
+ e.g. volume control for speaker amp.
+
+To achieve all this, ASoC basically splits an embedded audio system into 3
+components :-
+
+ * Codec driver: The codec driver is platform independent and contains audio
+ controls, audio interface capabilities, codec dapm definition and codec IO
+ functions.
+
+ * Platform driver: The platform driver contains the audio dma engine and audio
+ interface drivers (e.g. I2S, AC97, PCM) for that platform.
+
+ * Machine driver: The machine driver handles any machine specific controls and
+ audio events. i.e. turing on an amp at start of playback.
+
+
+Documentation
+=============
+
+The documentation is spilt into the following sections:-
+
+overview.txt: This file.
+
+codec.txt: Codec driver internals.
+
+DAI.txt: Description of Digital Audio Interface standards and how to configure
+a DAI within your codec and CPU DAI drivers.
+
+dapm.txt: Dynamic Audio Power Management
+
+platform.txt: Platform audio DMA and DAI.
+
+machine.txt: Machine driver internals.
+
+pop_clicks.txt: How to minimise audio artifacts.
+
+clocking.txt: ASoC clocking for best power performance. \ No newline at end of file
diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt
new file mode 100644
index 00000000000..e95b16d5a53
--- /dev/null
+++ b/Documentation/sound/alsa/soc/platform.txt
@@ -0,0 +1,58 @@
+ASoC Platform Driver
+====================
+
+An ASoC platform driver can be divided into audio DMA and SoC DAI configuration
+and control. The platform drivers only target the SoC CPU and must have no board
+specific code.
+
+Audio DMA
+=========
+
+The platform DMA driver optionally supports the following alsa operations:-
+
+/* SoC audio ops */
+struct snd_soc_ops {
+ int (*startup)(struct snd_pcm_substream *);
+ void (*shutdown)(struct snd_pcm_substream *);
+ int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
+ int (*hw_free)(struct snd_pcm_substream *);
+ int (*prepare)(struct snd_pcm_substream *);
+ int (*trigger)(struct snd_pcm_substream *, int);
+};
+
+The platform driver exports it's DMA functionailty via struct snd_soc_platform:-
+
+struct snd_soc_platform {
+ char *name;
+
+ int (*probe)(struct platform_device *pdev);
+ int (*remove)(struct platform_device *pdev);
+ int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
+ int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
+
+ /* pcm creation and destruction */
+ int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *);
+ void (*pcm_free)(struct snd_pcm *);
+
+ /* platform stream ops */
+ struct snd_pcm_ops *pcm_ops;
+};
+
+Please refer to the alsa driver documentation for details of audio DMA.
+http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
+
+An example DMA driver is soc/pxa/pxa2xx-pcm.c
+
+
+SoC DAI Drivers
+===============
+
+Each SoC DAI driver must provide the following features:-
+
+ 1) Digital audio interface (DAI) description
+ 2) Digital audio interface configuration
+ 3) PCM's description
+ 4) Sysclk configuration
+ 5) Suspend and resume (optional)
+
+Please see codec.txt for a description of items 1 - 4.
diff --git a/Documentation/sound/alsa/soc/pops_clicks.txt b/Documentation/sound/alsa/soc/pops_clicks.txt
new file mode 100644
index 00000000000..2cf7ee5b3d7
--- /dev/null
+++ b/Documentation/sound/alsa/soc/pops_clicks.txt
@@ -0,0 +1,52 @@
+Audio Pops and Clicks
+=====================
+
+Pops and clicks are unwanted audio artifacts caused by the powering up and down
+of components within the audio subsystem. This is noticable on PC's when an
+audio module is either loaded or unloaded (at module load time the sound card is
+powered up and causes a popping noise on the speakers).
+
+Pops and clicks can be more frequent on portable systems with DAPM. This is
+because the components within the subsystem are being dynamically powered
+depending on the audio usage and this can subsequently cause a small pop or
+click every time a component power state is changed.
+
+
+Minimising Playback Pops and Clicks
+===================================
+
+Playback pops in portable audio subsystems cannot be completely eliminated atm,
+however future audio codec hardware will have better pop and click supression.
+Pops can be reduced within playback by powering the audio components in a
+specific order. This order is different for startup and shutdown and follows
+some basic rules:-
+
+ Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute
+
+ Shutdown Order :- Digital Mute --> Output PGA --> Mixers --> DAC
+
+This assumes that the codec PCM output path from the DAC is via a mixer and then
+a PGA (programmable gain amplifier) before being output to the speakers.
+
+
+Minimising Capture Pops and Clicks
+==================================
+
+Capture artifacts are somewhat easier to get rid as we can delay activating the
+ADC until all the pops have occured. This follows similar power rules to
+playback in that components are powered in a sequence depending upon stream
+startup or shutdown.
+
+ Startup Order - Input PGA --> Mixers --> ADC
+
+ Shutdown Order - ADC --> Mixers --> Input PGA
+
+
+Zipper Noise
+============
+An unwanted zipper noise can occur within the audio playback or capture stream
+when a volume control is changed near its maximum gain value. The zipper noise
+is heard when the gain increase or decrease changes the mean audio signal
+amplitude too quickly. It can be minimised by enabling the zero cross setting
+for each volume control. The ZC forces the gain change to occur when the signal
+crosses the zero amplitude line.
diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx
index a1e0ee20f59..f9717fe9bd8 100644
--- a/Documentation/spi/pxa2xx
+++ b/Documentation/spi/pxa2xx
@@ -102,7 +102,7 @@ struct pxa2xx_spi_chip {
u8 tx_threshold;
u8 rx_threshold;
u8 dma_burst_size;
- u32 timeout_microsecs;
+ u32 timeout;
u8 enable_loopback;
void (*cs_control)(u32 command);
};
@@ -121,7 +121,7 @@ the PXA2xx "Developer Manual" sections on the DMA controller and SSP Controllers
to determine the correct value. An SSP configured for byte-wide transfers would
use a value of 8.
-The "pxa2xx_spi_chip.timeout_microsecs" fields is used to efficiently handle
+The "pxa2xx_spi_chip.timeout" 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 that the PXA2xx SSP 1 does not support trailing byte
@@ -162,18 +162,18 @@ static void cs8405a_cs_control(u32 command)
}
static struct pxa2xx_spi_chip cs8415a_chip_info = {
- .tx_threshold = 12, /* SSP hardward FIFO threshold */
- .rx_threshold = 4, /* SSP hardward FIFO threshold */
+ .tx_threshold = 8, /* SSP hardward FIFO threshold */
+ .rx_threshold = 8, /* SSP hardward FIFO threshold */
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
- .timeout_microsecs = 64, /* Wait at least 64usec to handle trailing */
+ .timeout = 235, /* See Intel documentation */
.cs_control = cs8415a_cs_control, /* Use external chip select */
};
static struct pxa2xx_spi_chip cs8405a_chip_info = {
- .tx_threshold = 12, /* SSP hardward FIFO threshold */
- .rx_threshold = 4, /* SSP hardward FIFO threshold */
+ .tx_threshold = 8, /* SSP hardward FIFO threshold */
+ .rx_threshold = 8, /* SSP hardward FIFO threshold */
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
- .timeout_microsecs = 64, /* Wait at least 64usec to handle trailing */
+ .timeout = 235, /* See Intel documentation */
.cs_control = cs8405a_cs_control, /* Use external chip select */
};
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index e0188a23fd5..61613166981 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -1,6 +1,6 @@
Linux Magic System Request Key Hacks
-Documentation for sysrq.c version 1.15
-Last update: $Date: 2001/01/28 10:15:59 $
+Documentation for sysrq.c
+Last update: 2007-JAN-06
* What is the magic SysRq key?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -35,7 +35,7 @@ You can set the value in the file by the following command:
Note that the value of /proc/sys/kernel/sysrq influences only the invocation
via a keyboard. Invocation of any operation via /proc/sysrq-trigger is always
-allowed.
+allowed (by a user with admin privileges).
* How do I use the magic SysRq key?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -58,7 +58,7 @@ On PowerPC - Press 'ALT - Print Screen (or F13) - <command key>,
On other - If you know of the key combos for other architectures, please
let me know so I can add them to this section.
-On all - write a character to /proc/sysrq-trigger. eg:
+On all - write a character to /proc/sysrq-trigger. e.g.:
echo t > /proc/sysrq-trigger
@@ -74,6 +74,8 @@ On all - write a character to /proc/sysrq-trigger. eg:
'c' - Will perform a kexec reboot in order to take a crashdump.
+'d' - Shows all locks that are held.
+
'o' - Will shut your system off (if configured and supported).
's' - Will attempt to sync all mounted filesystems.
@@ -87,38 +89,43 @@ On all - write a character to /proc/sysrq-trigger. eg:
'm' - Will dump current memory info to your console.
+'n' - Used to make RT tasks nice-able
+
'v' - Dumps Voyager SMP processor info to your console.
+'w' - Dumps tasks that are in uninterruptable (blocked) state.
+
+'x' - Used by xmon interface on ppc/powerpc platforms.
+
'0'-'9' - Sets the console log level, controlling which kernel messages
will be printed to your console. ('0', for example would make
it so that only emergency messages like PANICs or OOPSes would
make it to your console.)
-'f' - Will call oom_kill to kill a memory hog process
+'f' - Will call oom_kill to kill a memory hog process.
'e' - Send a SIGTERM to all processes, except for init.
-'i' - Send a SIGKILL to all processes, except for init.
+'g' - Used by kgdb on ppc platforms.
-'l' - Send a SIGKILL to all processes, INCLUDING init. (Your system
- will be non-functional after this.)
+'i' - Send a SIGKILL to all processes, except for init.
-'h' - Will display help ( actually any other key than those listed
+'h' - Will display help (actually any other key than those listed
above will display help. but 'h' is easy to remember :-)
* Okay, so what can I use them for?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Well, un'R'aw is very handy when your X server or a svgalib program crashes.
-sa'K' (Secure Access Key) is useful when you want to be sure there are no
-trojan program is running at console and which could grab your password
-when you would try to login. It will kill all programs on given console
-and thus letting you make sure that the login prompt you see is actually
+sa'K' (Secure Access Key) is useful when you want to be sure there is no
+trojan program running at console which could grab your password
+when you would try to login. It will kill all programs on given console,
+thus letting you make sure that the login prompt you see is actually
the one from init, not some trojan program.
IMPORTANT: In its true form it is not a true SAK like the one in a :IMPORTANT
IMPORTANT: c2 compliant system, and it should not be mistaken as :IMPORTANT
IMPORTANT: such. :IMPORTANT
- It seems other find it useful as (System Attention Key) which is
+ It seems others find it useful as (System Attention Key) which is
useful when you want to exit a program that will not let you switch consoles.
(For example, X or a svgalib program.)
@@ -139,8 +146,8 @@ OK or Done message...)
Again, the unmount (remount read-only) hasn't taken place until you see the
"OK" and "Done" message appear on the screen.
-The loglevel'0'-'9' is useful when your console is being flooded with
-kernel messages you do not want to see. Setting '0' will prevent all but
+The loglevels '0'-'9' are useful when your console is being flooded with
+kernel messages you do not want to see. Selecting '0' will prevent all but
the most urgent kernel messages from reaching your console. (They will
still be logged if syslogd/klogd are alive, though.)
@@ -152,7 +159,7 @@ processes.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
That happens to me, also. I've found that tapping shift, alt, and control
on both sides of the keyboard, and hitting an invalid sysrq sequence again
-will fix the problem. (ie, something like alt-sysrq-z). Switching to another
+will fix the problem. (i.e., something like alt-sysrq-z). Switching to another
virtual console (ALT+Fn) and then back again should also help.
* I hit SysRq, but nothing seems to happen, what's wrong?
@@ -174,11 +181,11 @@ handler function you will use, B) a help_msg string, that will print when SysRQ
prints help, and C) an action_msg string, that will print right before your
handler is called. Your handler must conform to the prototype in 'sysrq.h'.
-After the sysrq_key_op is created, you can call the macro
-register_sysrq_key(int key, struct sysrq_key_op *op_p) that is defined in
-sysrq.h, this will register the operation pointed to by 'op_p' at table
-key 'key', if that slot in the table is blank. At module unload time, you must
-call the macro unregister_sysrq_key(int key, struct sysrq_key_op *op_p), which
+After the sysrq_key_op is created, you can call the kernel function
+register_sysrq_key(int key, struct sysrq_key_op *op_p); this will
+register the operation pointed to by 'op_p' at table key 'key',
+if that slot in the table is blank. At module unload time, you must call
+the function unregister_sysrq_key(int key, struct sysrq_key_op *op_p), which
will remove the key op pointed to by 'op_p' from the key 'key', if and only if
it is currently registered in that slot. This is in case the slot has been
overwritten since you registered it.
@@ -186,15 +193,12 @@ overwritten since you registered it.
The Magic SysRQ system works by registering key operations against a key op
lookup table, which is defined in 'drivers/char/sysrq.c'. This key table has
a number of operations registered into it at compile time, but is mutable,
-and 4 functions are exported for interface to it: __sysrq_lock_table,
-__sysrq_unlock_table, __sysrq_get_key_op, and __sysrq_put_key_op. The
-functions __sysrq_swap_key_ops and __sysrq_swap_key_ops_nolock are defined
-in the header itself, and the REGISTER and UNREGISTER macros are built from
-these. More complex (and dangerous!) manipulations of the table are possible
-using these functions, but you must be careful to always lock the table before
-you read or write from it, and to unlock it again when you are done. (And of
-course, to never ever leave an invalid pointer in the table). Null pointers in
-the table are always safe :)
+and 2 functions are exported for interface to it:
+ register_sysrq_key and unregister_sysrq_key.
+Of course, never ever leave an invalid pointer in the table. I.e., when
+your module that called register_sysrq_key() exits, it must call
+unregister_sysrq_key() to clean up the sysrq key table entry that it used.
+Null pointers in the table are always safe. :)
If for some reason you feel the need to call the handle_sysrq function from
within a function called by handle_sysrq, you must be aware that you are in
diff --git a/Documentation/tty.txt b/Documentation/tty.txt
index dab56604745..5f799e612e0 100644
--- a/Documentation/tty.txt
+++ b/Documentation/tty.txt
@@ -39,28 +39,37 @@ Line Discipline Methods
TTY side interfaces:
+open() - Called when the line discipline is attached to
+ the terminal. No other call into the line
+ discipline for this tty will occur until it
+ completes successfully. Can sleep.
+
close() - This is called on a terminal when the line
discipline is being unplugged. At the point of
execution no further users will enter the
ldisc code for this tty. Can sleep.
-open() - Called when the line discipline is attached to
- the terminal. No other call into the line
- discipline for this tty will occur until it
- completes successfully. Can sleep.
+hangup() - Called when the tty line is hung up.
+ The line discipline should cease I/O to the tty.
+ No further calls into the ldisc code will occur.
+ Can sleep.
write() - A process is writing data through the line
discipline. Multiple write calls are serialized
by the tty layer for the ldisc. May sleep.
-flush_buffer() - May be called at any point between open and close.
+flush_buffer() - (optional) May be called at any point between
+ open and close, and instructs the line discipline
+ to empty its input buffer.
-chars_in_buffer() - Report the number of bytes in the buffer.
+chars_in_buffer() - (optional) Report the number of bytes in the input
+ buffer.
-set_termios() - Called on termios structure changes. The caller
- passes the old termios data and the current data
- is in the tty. Called under the termios semaphore so
- allowed to sleep. Serialized against itself only.
+set_termios() - (optional) Called on termios structure changes.
+ The caller passes the old termios data and the
+ current data is in the tty. Called under the
+ termios semaphore so allowed to sleep. Serialized
+ against itself only.
read() - Move data from the line discipline to the user.
Multiple read calls may occur in parallel and the
@@ -92,6 +101,88 @@ write_wakeup() - May be called at any point between open and close.
this function. In such a situation defer it.
+Driver Access
+
+Line discipline methods can call the following methods of the underlying
+hardware driver through the function pointers within the tty->driver
+structure:
+
+write() Write a block of characters to the tty device.
+ Returns the number of characters accepted.
+
+put_char() Queues a character for writing to the tty device.
+ If there is no room in the queue, the character is
+ ignored.
+
+flush_chars() (Optional) If defined, must be called after
+ queueing characters with put_char() in order to
+ start transmission.
+
+write_room() Returns the numbers of characters the tty driver
+ will accept for queueing to be written.
+
+ioctl() Invoke device specific ioctl.
+ Expects data pointers to refer to userspace.
+ Returns ENOIOCTLCMD for unrecognized ioctl numbers.
+
+set_termios() Notify the tty driver that the device's termios
+ settings have changed. New settings are in
+ tty->termios. Previous settings should be passed in
+ the "old" argument.
+
+throttle() Notify the tty driver that input buffers for the
+ line discipline are close to full, and it should
+ somehow signal that no more characters should be
+ sent to the tty.
+
+unthrottle() Notify the tty driver that characters can now be
+ sent to the tty without fear of overrunning the
+ input buffers of the line disciplines.
+
+stop() Ask the tty driver to stop outputting characters
+ to the tty device.
+
+start() Ask the tty driver to resume sending characters
+ to the tty device.
+
+hangup() Ask the tty driver to hang up the tty device.
+
+break_ctl() (Optional) Ask the tty driver to turn on or off
+ BREAK status on the RS-232 port. If state is -1,
+ then the BREAK status should be turned on; if
+ state is 0, then BREAK should be turned off.
+ If this routine is not implemented, use ioctls
+ TIOCSBRK / TIOCCBRK instead.
+
+wait_until_sent() Waits until the device has written out all of the
+ characters in its transmitter FIFO.
+
+send_xchar() Send a high-priority XON/XOFF character to the device.
+
+
+Flags
+
+Line discipline methods have access to tty->flags field containing the
+following interesting flags:
+
+TTY_THROTTLED Driver input is throttled. The ldisc should call
+ tty->driver->unthrottle() in order to resume
+ reception when it is ready to process more data.
+
+TTY_DO_WRITE_WAKEUP If set, causes the driver to call the ldisc's
+ write_wakeup() method in order to resume
+ transmission when it can accept more data
+ to transmit.
+
+TTY_IO_ERROR If set, causes all subsequent userspace read/write
+ calls on the tty to fail, returning -EIO.
+
+TTY_OTHER_CLOSED Device is a pty and the other side has closed.
+
+TTY_NO_WRITE_SPLIT Prevent driver from splitting up writes into
+ smaller chunks.
+
+
Locking
Callers to the line discipline functions from the tty layer are required to
diff --git a/Documentation/usb/CREDITS b/Documentation/usb/CREDITS
index 01e7f857ef3..27a721635f9 100644
--- a/Documentation/usb/CREDITS
+++ b/Documentation/usb/CREDITS
@@ -21,7 +21,7 @@ difficult to maintain, add yourself with a patch if desired.
Bill Ryder <bryder@sgi.com>
Thomas Sailer <sailer@ife.ee.ethz.ch>
Gregory P. Smith <greg@electricrain.com>
- Linus Torvalds <torvalds@osdl.org>
+ Linus Torvalds <torvalds@linux-foundation.org>
Roman Weissgaerber <weissg@vienna.at>
<Kazuki.Yasumatsu@fujixerox.co.jp>
diff --git a/Documentation/usb/acm.txt b/Documentation/usb/acm.txt
index 737d6104c3f..17f5c2e1a57 100644
--- a/Documentation/usb/acm.txt
+++ b/Documentation/usb/acm.txt
@@ -46,6 +46,10 @@ Abstract Control Model (USB CDC ACM) specification.
3Com USR ISDN Pro TA
+ Some cell phones also connect via USB. I know the following phones work:
+
+ SonyEricsson K800i
+
Unfortunately many modems and most ISDN TAs use proprietary interfaces and
thus won't work with this drivers. Check for ACM compliance before buying.
diff --git a/Documentation/usb/proc_usb_info.txt b/Documentation/usb/proc_usb_info.txt
index 22c5331260c..077e9032d0c 100644
--- a/Documentation/usb/proc_usb_info.txt
+++ b/Documentation/usb/proc_usb_info.txt
@@ -213,15 +213,16 @@ C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
Interface descriptor info (can be multiple per Config):
-I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
-| | | | | | | |__Driver name
-| | | | | | | or "(none)"
-| | | | | | |__InterfaceProtocol
-| | | | | |__InterfaceSubClass
-| | | | |__InterfaceClass
-| | | |__NumberOfEndpoints
-| | |__AlternateSettingNumber
-| |__InterfaceNumber
+I:* If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
+| | | | | | | | |__Driver name
+| | | | | | | | or "(none)"
+| | | | | | | |__InterfaceProtocol
+| | | | | | |__InterfaceSubClass
+| | | | | |__InterfaceClass
+| | | | |__NumberOfEndpoints
+| | | |__AlternateSettingNumber
+| | |__InterfaceNumber
+| |__ "*" indicates the active altsetting (others are " ")
|__Interface info tag
A given interface may have one or more "alternate" settings.
@@ -277,7 +278,7 @@ of the USB devices on a system's root hub. (See more below
on how to do this.)
The Interface lines can be used to determine what driver is
-being used for each device.
+being used for each device, and which altsetting it activated.
The Configuration lines could be used to list maximum power
(in milliamps) that a system's USB devices are using.
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
index e65ec828d7a..0f6808abd61 100644
--- a/Documentation/usb/usbmon.txt
+++ b/Documentation/usb/usbmon.txt
@@ -77,7 +77,7 @@ that the file size is not excessive for your favourite editor.
The '1t' type data consists of a stream of events, such as URB submission,
URB callback, submission error. Every event is a text line, which consists
-of whitespace separated words. The number of position of words may depend
+of whitespace separated words. The number or position of words may depend
on the event type, but there is a set of words, common for all types.
Here is the list of words, from left to right:
@@ -170,4 +170,152 @@ dd65f0e8 4128379808 C Bo:005:02 0 31 >
* Raw binary format and API
-TBD
+The overall architecture of the API is about the same as the one above,
+only the events are delivered in binary format. Each event is sent in
+the following structure (its name is made up, so that we can refer to it):
+
+struct usbmon_packet {
+ u64 id; /* 0: URB ID - from submission to callback */
+ unsigned char type; /* 8: Same as text; extensible. */
+ unsigned char xfer_type; /* ISO (0), Intr, Control, Bulk (3) */
+ unsigned char epnum; /* Endpoint number and transfer direction */
+ unsigned char devnum; /* Device address */
+ u16 busnum; /* 12: Bus number */
+ char flag_setup; /* 14: Same as text */
+ char flag_data; /* 15: Same as text; Binary zero is OK. */
+ s64 ts_sec; /* 16: gettimeofday */
+ s32 ts_usec; /* 24: gettimeofday */
+ int status; /* 28: */
+ unsigned int length; /* 32: Length of data (submitted or actual) */
+ unsigned int len_cap; /* 36: Delivered length */
+ unsigned char setup[8]; /* 40: Only for Control 'S' */
+}; /* 48 bytes total */
+
+These events can be received from a character device by reading with read(2),
+with an ioctl(2), or by accessing the buffer with mmap.
+
+The character device is usually called /dev/usbmonN, where N is the USB bus
+number. Number zero (/dev/usbmon0) is special and means "all buses".
+However, this feature is not implemented yet. Note that specific naming
+policy is set by your Linux distribution.
+
+If you create /dev/usbmon0 by hand, make sure that it is owned by root
+and has mode 0600. Otherwise, unpriviledged users will be able to snoop
+keyboard traffic.
+
+The following ioctl calls are available, with MON_IOC_MAGIC 0x92:
+
+ MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1)
+
+This call returns the length of data in the next event. Note that majority of
+events contain no data, so if this call returns zero, it does not mean that
+no events are available.
+
+ MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+
+The argument is a pointer to the following structure:
+
+struct mon_bin_stats {
+ u32 queued;
+ u32 dropped;
+};
+
+The member "queued" refers to the number of events currently queued in the
+buffer (and not to the number of events processed since the last reset).
+
+The member "dropped" is the number of events lost since the last call
+to MON_IOCG_STATS.
+
+ MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4)
+
+This call sets the buffer size. The argument is the size in bytes.
+The size may be rounded down to the next chunk (or page). If the requested
+size is out of [unspecified] bounds for this kernel, the call fails with
+-EINVAL.
+
+ MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5)
+
+This call returns the current size of the buffer in bytes.
+
+ MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg)
+
+This call waits for events to arrive if none were in the kernel buffer,
+then returns the first event. Its argument is a pointer to the following
+structure:
+
+struct mon_get_arg {
+ struct usbmon_packet *hdr;
+ void *data;
+ size_t alloc; /* Length of data (can be zero) */
+};
+
+Before the call, hdr, data, and alloc should be filled. Upon return, the area
+pointed by hdr contains the next event structure, and the data buffer contains
+the data, if any. The event is removed from the kernel buffer.
+
+ MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)
+
+This ioctl is primarily used when the application accesses the buffer
+with mmap(2). Its argument is a pointer to the following structure:
+
+struct mon_mfetch_arg {
+ uint32_t *offvec; /* Vector of events fetched */
+ uint32_t nfetch; /* Number of events to fetch (out: fetched) */
+ uint32_t nflush; /* Number of events to flush */
+};
+
+The ioctl operates in 3 stages.
+
+First, it removes and discards up to nflush events from the kernel buffer.
+The actual number of events discarded is returned in nflush.
+
+Second, it waits for an event to be present in the buffer, unless the pseudo-
+device is open with O_NONBLOCK.
+
+Third, it extracts up to nfetch offsets into the mmap buffer, and stores
+them into the offvec. The actual number of event offsets is stored into
+the nfetch.
+
+ MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8)
+
+This call removes a number of events from the kernel buffer. Its argument
+is the number of events to remove. If the buffer contains fewer events
+than requested, all events present are removed, and no error is reported.
+This works when no events are available too.
+
+ FIONBIO
+
+The ioctl FIONBIO may be implemented in the future, if there's a need.
+
+In addition to ioctl(2) and read(2), the special file of binary API can
+be polled with select(2) and poll(2). But lseek(2) does not work.
+
+* Memory-mapped access of the kernel buffer for the binary API
+
+The basic idea is simple:
+
+To prepare, map the buffer by getting the current size, then using mmap(2).
+Then, execute a loop similar to the one written in pseudo-code below:
+
+ struct mon_mfetch_arg fetch;
+ struct usbmon_packet *hdr;
+ int nflush = 0;
+ for (;;) {
+ fetch.offvec = vec; // Has N 32-bit words
+ fetch.nfetch = N; // Or less than N
+ fetch.nflush = nflush;
+ ioctl(fd, MON_IOCX_MFETCH, &fetch); // Process errors, too
+ nflush = fetch.nfetch; // This many packets to flush when done
+ for (i = 0; i < nflush; i++) {
+ hdr = (struct ubsmon_packet *) &mmap_area[vec[i]];
+ if (hdr->type == '@') // Filler packet
+ continue;
+ caddr_t data = &mmap_area[vec[i]] + 64;
+ process_packet(hdr, data);
+ }
+ }
+
+Thus, the main idea is to execute only one ioctl per N events.
+
+Although the buffer is circular, the returned headers and data do not cross
+the end of the buffer, so the above pseudo-code does not need any gathering.
diff --git a/Documentation/video-output.txt b/Documentation/video-output.txt
new file mode 100644
index 00000000000..e517011be4f
--- /dev/null
+++ b/Documentation/video-output.txt
@@ -0,0 +1,34 @@
+
+ Video Output Switcher Control
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 2006 luming.yu@intel.com
+
+The output sysfs class driver provides an abstract video output layer that
+can be used to hook platform specific methods to enable/disable video output
+device through common sysfs interface. For example, on my IBM ThinkPad T42
+laptop, The ACPI video driver registered its output devices and read/write
+method for 'state' with output sysfs class. The user interface under sysfs is:
+
+linux:/sys/class/video_output # tree .
+.
+|-- CRT0
+| |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+| |-- state
+| |-- subsystem -> ../../../class/video_output
+| `-- uevent
+|-- DVI0
+| |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+| |-- state
+| |-- subsystem -> ../../../class/video_output
+| `-- uevent
+|-- LCD0
+| |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+| |-- state
+| |-- subsystem -> ../../../class/video_output
+| `-- uevent
+`-- TV0
+ |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+ |-- state
+ |-- subsystem -> ../../../class/video_output
+ `-- uevent
+
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 8755b3e7b09..62e32b49cec 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -43,7 +43,7 @@
42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025,1822:0019]
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]
+ 45 -> KWorld HardwareMpegTV XPert [17de:0840,1421:0305]
46 -> DViCO FusionHDTV DVB-T Hybrid [18ac:db40,18ac:db44]
47 -> pcHDTV HD5500 HDTV [7063:5500]
48 -> Kworld MCE 200 Deluxe [17de:0841]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 53ce6a39083..f6201cc37ec 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -76,7 +76,7 @@
75 -> AVerMedia AVerTVHD MCE A180 [1461:1044]
76 -> SKNet MonsterTV Mobile [1131:4ee9]
77 -> Pinnacle PCTV 40i/50i/110i (saa7133) [11bd:002e]
- 78 -> ASUSTeK P7131 Dual [1043:4862]
+ 78 -> ASUSTeK P7131 Dual [1043:4862,1043:4876]
79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
80 -> ASUS Digimatrix TV [1043:0210]
81 -> Philips Tiger reference design [1131:2018]
@@ -99,3 +99,8 @@
98 -> Proteus Pro 2309 [0919:2003]
99 -> AVerMedia TV Hybrid A16AR [1461:2c00]
100 -> Asus Europa2 OEM [1043:4860]
+101 -> Pinnacle PCTV 310i [11bd:002f]
+102 -> Avermedia AVerTV Studio 507 [1461:9715]
+103 -> Compro Videomate DVB-T200A
+104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid [0070:6701]
+105 -> Terratec Cinergy HT PCMCIA [153b:1172]
diff --git a/Documentation/video4linux/cafe_ccic b/Documentation/video4linux/cafe_ccic
new file mode 100644
index 00000000000..88821022a5d
--- /dev/null
+++ b/Documentation/video4linux/cafe_ccic
@@ -0,0 +1,54 @@
+"cafe_ccic" is a driver for the Marvell 88ALP01 "cafe" CMOS camera
+controller. This is the controller found in first-generation OLPC systems,
+and this driver was written with support from the OLPC project.
+
+Current status: the core driver works. It can generate data in YUV422,
+RGB565, and RGB444 formats. (Anybody looking at the code will see RGB32 as
+well, but that is a debugging aid which will be removed shortly). VGA and
+QVGA modes work; CIF is there but the colors remain funky. Only the OV7670
+sensor is known to work with this controller at this time.
+
+To try it out: either of these commands will work:
+
+ mplayer tv:// -tv driver=v4l2:width=640:height=480 -nosound
+ mplayer tv:// -tv driver=v4l2:width=640:height=480:outfmt=bgr16 -nosound
+
+The "xawtv" utility also works; gqcam does not, for unknown reasons.
+
+There are a few load-time options, most of which can be changed after
+loading via sysfs as well:
+
+ - alloc_bufs_at_load: Normally, the driver will not allocate any DMA
+ buffers until the time comes to transfer data. If this option is set,
+ then worst-case-sized buffers will be allocated at module load time.
+ This option nails down the memory for the life of the module, but
+ perhaps decreases the chances of an allocation failure later on.
+
+ - dma_buf_size: The size of DMA buffers to allocate. Note that this
+ option is only consulted for load-time allocation; when buffers are
+ allocated at run time, they will be sized appropriately for the current
+ camera settings.
+
+ - n_dma_bufs: The controller can cycle through either two or three DMA
+ buffers. Normally, the driver tries to use three buffers; on faster
+ systems, however, it will work well with only two.
+
+ - min_buffers: The minimum number of streaming I/O buffers that the driver
+ will consent to work with. Default is one, but, on slower systems,
+ better behavior with mplayer can be achieved by setting to a higher
+ value (like six).
+
+ - max_buffers: The maximum number of streaming I/O buffers; default is
+ ten. That number was carefully picked out of a hat and should not be
+ assumed to actually mean much of anything.
+
+ - flip: If this boolean parameter is set, the sensor will be instructed to
+ invert the video image. Whether it makes sense is determined by how
+ your particular camera is mounted.
+
+Work is ongoing with this driver, stay tuned.
+
+jon
+
+Jonathan Corbet
+corbet@lwn.net
diff --git a/Documentation/video4linux/zr36120.txt b/Documentation/video4linux/zr36120.txt
deleted file mode 100644
index 1a1c2d03a5c..00000000000
--- a/Documentation/video4linux/zr36120.txt
+++ /dev/null
@@ -1,162 +0,0 @@
-Driver for Trust Computer Products Framegrabber, version 0.6.1
------- --- ----- -------- -------- ------------ ------- - - -
-
-- ZORAN ------------------------------------------------------
- Author: Pauline Middelink <middelin@polyware.nl>
- Date: 18 September 1999
-Version: 0.6.1
-
-- Description ------------------------------------------------
-
-Video4Linux compatible driver for an unknown brand framegrabber
-(Sold in the Netherlands by TRUST Computer Products) and various
-other zoran zr36120 based framegrabbers.
-
-The card contains a ZR36120 Multimedia PCI Interface and a Philips
-SAA7110 Onechip Frontend videodecoder. There is also an DSP of
-which I have forgotten the number, since i will never get that thing
-to work without specs from the vendor itself.
-
-The SAA711x are capable of processing 6 different video inputs,
-CVBS1..6 and Y1+C1, Y2+C2, Y3+C3. All in 50/60Hz, NTSC, PAL or
-SECAM and delivering a YUV datastream. On my card the input
-'CVBS-0' corresponds to channel CVBS2 and 'S-Video' to Y2+C2.
-
-I have some reports of other cards working with the mentioned
-chip sets. For a list of other working cards please have a look
-at the cards named in the tvcards struct in the beginning of
-zr36120.c
-
-After some testing, I discovered that the carddesigner messed up
-on the I2C interface. The Zoran chip includes 2 lines SDA and SCL
-which (s)he connected reversely. So we have to clock on the SDA
-and r/w data on the SCL pin. Life is fun... Each cardtype now has
-a bit which signifies if you have a card with the same deficiency.
-
-Oh, for the completeness of this story I must mention that my
-card delivers the VSYNC pulse of the SAA chip to GIRQ1, not
-GIRQ0 as some other cards have. This is also incorporated in
-the driver be clearing/setting the 'useirq1' bit in the tvcard
-description.
-
-Another problems of continuous capturing data with a Zoran chip
-is something nasty inside the chip. It effectively halves the
-fps we ought to get... Here is the scenario: capturing frames
-to memory is done in the so-called snapshot mode. In this mode
-the Zoran stops after capturing a frame worth of data and wait
-till the application set GRAB bit to indicate readiness for the
-next frame. After detecting a set bit, the chip neatly waits
-till the start of a frame, captures it and it goes back to off.
-Smart ppl will notice the problem here. Its the waiting on the
-_next_ frame each time we set the GRAB bit... Oh well, 12,5 fps
-is still plenty fast for me.
--- update 28/7/1999 --
-Don't believe a word I just said... Proof is the output
-of `streamer -t 300 -r 25 -f avi15 -o /dev/null`
- ++--+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
- +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
- +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
- +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
- +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
- +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
- +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
- +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
- +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
- +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
- +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
- +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+-
- syncer: done
- writer: done
-(note the /dev/null is prudent here, my system is not able to
- grab /and/ write 25 fps to a file... gifts welcome :) )
-The technical reasoning follows: The zoran completed the last
-frame, the VSYNC goes low, and GRAB is cleared. The interrupt
-routine starts to work since its VSYNC driven, and again
-activates the GRAB bit. A few ms later the VSYNC (re-)rises and
-the zoran starts to work on a new and freshly broadcasted frame....
-
-For pointers I used the specs of both chips. Below are the URLs:
- http://www.zoran.com/ftp/download/devices/pci/ZR36120/36120data.pdf
- http://www-us.semiconductor.philips.com/acrobat/datasheets/SAA_7110_A_1.pdf
-Some alternatives for the Philips SAA 7110 datasheet are:
- http://www.datasheetcatalog.com/datasheets_pdf/S/A/A/7/SAA7110.shtml
- http://www.datasheetarchive.com/search.php?search=SAA7110&sType=part
-
-The documentation has very little on absolute numbers or timings
-needed for the various modes/resolutions, but there are other
-programs you can borrow those from.
-
------- Install --------------------------------------------
-Read the file called TODO. Note its long list of limitations.
-
-Build a kernel with VIDEO4LINUX enabled. Activate the
-BT848 driver; we need this because we have need for the
-other modules (i2c and videodev) it enables.
-
-To install this software, extract it into a suitable directory.
-Examine the makefile and change anything you don't like. Type "make".
-
-After making the modules check if you have the much needed
-/dev/video devices. If not, execute the following 4 lines:
- mknod /dev/video c 81 0
- mknod /dev/video1 c 81 1
- mknod /dev/video2 c 81 2
- mknod /dev/video3 c 81 3
- mknod /dev/video4 c 81 4
-
-After making/checking the devices do:
- modprobe i2c
- modprobe videodev
- modprobe saa7110 (optional)
- modprobe saa7111 (optional)
- modprobe tuner (optional)
- insmod zoran cardtype=<n>
-
-<n> is the cardtype of the card you have. The cardnumber can
-be found in the source of zr36120. Look for tvcards. If your
-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!)
- Don't forget to set video_input to the number of inputs
- you defined in the video_mux part of the tvcard definition.
- 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
-video4linux compatible tool
-
------- Application ----------------------------------------
-
-This device works with all Video4Linux compatible applications,
-given the limitations in the TODO file.
-
------- API ------------------------------------------------
-
-This uses the V4L interface as of kernel release 2.1.116, and in
-fact has not been tested on any lower version. There are a couple
-of minor differences due to the fact that the amount of data returned
-with each frame varies, and no doubt there are discrepancies due to my
-misunderstanding of the API. I intend to convert this driver to the
-new V4L2 API when it has stabilized more.
-
------- Current state --------------------------------------
-
-The driver is capable of overlaying a video image in screen, and
-even capable of grabbing frames. It uses the BIGPHYSAREA patch
-to allocate lots of large memory blocks when tis patch is
-found in the kernel, but it doesn't need it.
-The consequence is that, when loading the driver as a module,
-the module may tell you it's out of memory, but 'free' says
-otherwise. The reason is simple; the modules wants its memory
-contiguous, not fragmented, and after a long uptime there
-probably isn't a fragment of memory large enough...
-
-The driver uses a double buffering scheme, which should really
-be an n-way buffer, depending on the size of allocated framebuffer
-and the requested grab-size/format.
-This current version also fixes a dead-lock situation during irq
-time, which really, really froze my system... :)
-
-Good luck.
- Pauline
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index dbdcaf68e3e..5c86ed6f044 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -52,6 +52,10 @@ APICs
apicmaintimer. Useful when your PIT timer is totally
broken.
+ disable_8254_timer / enable_8254_timer
+ Enable interrupt 0 timer routing over the 8254 in addition to over
+ the IO-APIC. The kernel tries to set a sensible default.
+
Early Console
syntax: earlyprintk=vga
diff --git a/MAINTAINERS b/MAINTAINERS
index 89ef018cc4b..a6c1ebd18d0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -207,16 +207,45 @@ S: Supported
ACPI
P: Len Brown
M: len.brown@intel.com
+M: lenb@kernel.org
L: linux-acpi@vger.kernel.org
W: http://acpi.sourceforge.net/
T: git kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
-S: Maintained
+S: Supported
+
+ACPI BATTERY DRIVERS
+P: Vladimir P. Lebedev
+M: vladimir.p.lebedev@intel.com
+L: linux-acpi@vger.kernel.org
+W: http://acpi.sourceforge.net/
+S: Supported
+
+ACPI EC DRIVER
+P: Alexey Starikovskiy
+M: alexey.y.starikovskiy@linux.intel.com
+L: linux-acpi@vger.kernel.org
+W: http://acpi.sourceforge.net/
+S: Supported
+
+ACPI FAN DRIVER
+P: Konstantin A. Karasyov
+M: konstantin.a.karasyov@intel.com
+L: linux-acpi@vger.kernel.org
+W: http://acpi.sourceforge.net/
+S: Supported
ACPI PCI HOTPLUG DRIVER
P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com
L: pcihpd-discuss@lists.sourceforge.net
-S: Maintained
+S: Supported
+
+ACPI THERMAL DRIVER
+P: Konstantin A. Karasyov
+M: konstantin.a.karasyov@intel.com
+L: linux-acpi@vger.kernel.org
+W: http://acpi.sourceforge.net/
+S: Supported
AD1816 SOUND DRIVER
P: Thorsten Knabe
@@ -277,7 +306,7 @@ S: Maintained
ALI1563 I2C DRIVER
P: Rudolf Marek
-M: r.marek@sh.cvut.cz
+M: r.marek@assembler.cz
L: i2c@lm-sensors.org
S: Maintained
@@ -296,6 +325,13 @@ L: info-linux@geode.amd.com
W: http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
S: Supported
+AMS (Apple Motion Sensor) DRIVER
+P: Stelian Pop
+M: stelian@popies.net
+P: Michael Hanselmann
+M: linux-kernel@hansmi.ch
+S: Supported
+
AMSO1100 RNIC DRIVER
P: Tom Tucker
M: tom@opengridcomputing.com
@@ -348,6 +384,24 @@ P: Ian Molton
M: spyro@f2s.com
S: Maintained
+ARM/ADI ROADRUNNER MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
+ARM/ADS SPHERE MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
+ARM/AJECO 1ARM MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
ARM/ATMEL AT91RM9200 ARM ARCHITECTURE
P: Andrew Victor
M: andrew@sanpeople.com
@@ -355,17 +409,103 @@ L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://maxim.org.za/at91_26.html
S: Maintained
+ARM/CIRRUS LOGIC EP93XX ARM ARCHITECTURE
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
+ARM/CIRRUS LOGIC EDB9315A MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
ARM/CORGI MACHINE SUPPORT
P: Richard Purdie
M: rpurdie@rpsys.net
S: Maintained
+ARM/GLOMATION GESBC9312SX MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
ARM/HP JORNADA 7XX MACHINE SUPPORT
P: Kristoffer Ericson
M: kristoffer_e1@hotmail.com
W: www.jlime.com
S: Maintained
+ARM/INTEL IOP32X ARM ARCHITECTURE
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+P: Dan Williams
+M: dan.j.williams@intel.com
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Supported
+
+ARM/INTEL IOP33X ARM ARCHITECTURE
+P: Dan Williams
+M: dan.j.williams@intel.com
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Supported
+
+ARM/INTEL IOP13XX ARM ARCHITECTURE
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+P: Dan Williams
+M: dan.j.williams@intel.com
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Supported
+
+ARM/INTEL IQ81342EX MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+P: Dan Williams
+M: dan.j.williams@intel.com
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Supported
+
+ARM/INTEL IXP2000 ARM ARCHITECTURE
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
+ARM/INTEL IXDP2850 MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
+ARM/INTEL IXP23XX ARM ARCHITECTURE
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
+ARM/INTEL XSC3 (MANZANO) ARM CORE
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+P: Dan Williams
+M: dan.j.williams@intel.com
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Supported
+
+ARM/IP FABRICS DOUBLE ESPRESSO MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
+ARM/LOGICPD PXA270 MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
ARM/TOSA MACHINE SUPPORT
P: Dirk Opfer
M: dirk@opfer-online.de
@@ -384,6 +524,12 @@ L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.arm.linux.org.uk/
S: Maintained
+ARM/RADISYS ENP2611 MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
ARM/SHARK MACHINE SUPPORT
P: Alexander Schulz
M: alex@shark-linux.de
@@ -399,31 +545,51 @@ S: Maintained
ARM/S3C2410 ARM ARCHITECTURE
P: Ben Dooks
-M: ben-s3c2410@fluff.org
+M: ben-linux@fluff.org
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.fluff.org/ben/linux/
S: Maintained
ARM/S3C2440 ARM ARCHITECTURE
P: Ben Dooks
-M: ben-s3c2440@fluff.org
+M: ben-linux@fluff.org
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
W: http://www.fluff.org/ben/linux/
S: Maintained
+ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
+ARM/THECUS N2100 MACHINE SUPPORT
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
ARPD SUPPORT
P: Jonathan Layes
L: netdev@vger.kernel.org
S: Maintained
ASUS ACPI EXTRAS DRIVER
+P: Corentin Chary
+M: corentincj@iksaif.net
P: Karol Kozimor
M: sziwan@users.sourceforge.net
-P: Julien Lerouge
-M: julien.lerouge@free.fr
L: acpi4asus-user@lists.sourceforge.net
W: http://sourceforge.net/projects/acpi4asus
-W: http://julien.lerouge.free.fr
+W: http://xf.iksaif.net/acpi4asus
+S: Maintained
+
+ASUS LAPTOP EXTRAS DRIVER
+P: Corentin Chary
+M: corentincj@iksaif.net
+L: acpi4asus-user@lists.sourceforge.net
+W: http://sourceforge.net/projects/acpi4asus
+W: http://xf.iksaif.net/acpi4asus
S: Maintained
ATA OVER ETHERNET DRIVER
@@ -432,6 +598,16 @@ M: ecashin@coraid.com
W: http://www.coraid.com/support/linux
S: Supported
+ATL1 ETHERNET DRIVER
+P: Jay Cliburn
+M: jcliburn@gmail.com
+P: Chris Snook
+M: csnook@redhat.com
+L: atl1-devel@lists.sourceforge.net
+W: http://sourceforge.net/projects/atl1
+W: http://atl1.sourceforge.net
+S: Maintained
+
ATM
P: Chas Williams
M: chas@cmf.nrl.navy.mil
@@ -440,8 +616,6 @@ W: http://linux-atm.sourceforge.net
S: Maintained
ATMEL MACB ETHERNET DRIVER
-P: Atmel AVR32 Support Team
-M: avr32@atmel.com
P: Haavard Skinnemoen
M: hskinnemoen@atmel.com
S: Supported
@@ -462,8 +636,6 @@ T: git kernel.org:/pub/scm/linux/kernel/git/dwmw2/audit-2.6.git
S: Maintained
AVR32 ARCHITECTURE
-P: Atmel AVR32 Support Team
-M: avr32@atmel.com
P: Haavard Skinnemoen
M: hskinnemoen@atmel.com
W: http://www.atmel.com/products/AVR32/
@@ -472,8 +644,6 @@ W: http://avrfreaks.net/
S: Supported
AVR32/AT32AP MACHINE SUPPORT
-P: Atmel AVR32 Support Team
-M: avr32@atmel.com
P: Haavard Skinnemoen
M: hskinnemoen@atmel.com
S: Supported
@@ -681,12 +851,24 @@ M: joel.becker@oracle.com
L: linux-kernel@vger.kernel.org
S: Supported
+CIRRUS LOGIC EP93XX ETHERNET DRIVER
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: netdev@vger.kernel.org
+S: Maintained
+
CIRRUS LOGIC GENERIC FBDEV DRIVER
P: Jeff Garzik
M: jgarzik@pobox.com
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Odd Fixes
+CIRRUS LOGIC EP93XX OHCI USB HOST DRIVER
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: linux-usb-devel@lists.sourceforge.net
+S: Maintained
+
CIRRUS LOGIC CS4280/CS461x SOUNDDRIVER
P: Cirrus Logic Corporation (kernel 2.2 driver)
M: Cirrus Logic Corporation, Thomas Woller <twoller@crystal.cirrus.com>
@@ -740,7 +922,7 @@ P: Dave Jones
M: davej@codemonkey.org.uk
L: cpufreq@lists.linux.org.uk
W: http://www.codemonkey.org.uk/projects/cpufreq/
-T: git kernel.org/pub/scm/linux/kernel/davej/cpufreq.git
+T: git kernel.org/pub/scm/linux/kernel/git/davej/cpufreq.git
S: Maintained
CPUID/MSR DRIVER
@@ -791,7 +973,7 @@ S: Maintained
CYBLAFB FRAMEBUFFER DRIVER
P: Knut Petersen
M: Knut_Petersen@t-online.de
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
CYCLADES 2X SYNC CARD DRIVER
@@ -932,22 +1114,19 @@ S: Supported
DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
P: Tobias Ringstrom
M: tori@unhappy.mine.nu
-L: linux-kernel@vger.kernel.org
+L: netdev@vger.kernel.org
S: Maintained
DOCBOOK FOR DOCUMENTATION
-P: Martin Waitz
-M: tali@admingilde.org
P: Randy Dunlap
M: rdunlap@xenotime.net
-T: git http://tali.admingilde.org/git/linux-docbook.git
S: Maintained
DOCKING STATION DRIVER
P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com
L: linux-acpi@vger.kernel.org
-S: Maintained
+S: Supported
DOUBLETALK DRIVER
P: James R. Van Zandt
@@ -970,9 +1149,9 @@ T: git kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git
S: Maintained
DSCC4 DRIVER
-P: François Romieu
-M: romieu@cogenit.fr
-M: romieu@ensta.fr
+P: Francois Romieu
+M: romieu@fr.zoreil.com
+L: netdev@vger.kernel.org
S: Maintained
DVB SUBSYSTEM AND DRIVERS
@@ -1087,7 +1266,7 @@ S: Maintained
ETHERNET BRIDGE
P: Stephen Hemminger
-M: shemminger@osdl.org
+M: shemminger@linux-foundation.org
L: bridge@osdl.org
W: http://bridge.sourceforge.net/
S: Maintained
@@ -1128,7 +1307,7 @@ S: Supported
FRAMEBUFFER LAYER
P: Antonino Daplas
M: adaplas@pol.net
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
W: http://linux-fbdev.sourceforge.net/
S: Maintained
@@ -1270,6 +1449,12 @@ L: linux-nvidia@lists.surfsouth.com
W: http://drama.obuda.kando.hu/~fero/cgi-bin/hgafb.shtml
S: Maintained
+HID CORE LAYER
+P: Jiri Kosina
+M: jkosina@suse.cz
+L: linux-input@atrey.karlin.mff.cuni.cz
+S: Maintained
+
HIGH-SPEED SCC DRIVER FOR AX.25
P: Klaus Kudielka
M: klaus.kudielka@ieee.org
@@ -1390,6 +1575,15 @@ W: http://www.ia64-linux.org/
T: git kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
S: Maintained
+IBM ACPI EXTRAS DRIVER
+P: Henrique de Moraes Holschuh
+M: ibm-acpi@hmh.eng.br
+L: ibm-acpi-devel@lists.sourceforge.net
+W: http://ibm-acpi.sourceforge.net
+W: http://thinkwiki.org/wiki/Ibm-acpi
+T: git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
+S: Maintained
+
SN-IA64 (Itanium) SUB-PLATFORM
P: Jes Sorensen
M: jes@sgi.com
@@ -1416,19 +1610,17 @@ M: ipslinux@adaptec.com
W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html
S: Supported
-IDE DRIVER [GENERAL]
+IDE SUBSYSTEM
P: Bartlomiej Zolnierkiewicz
-M: B.Zolnierkiewicz@elka.pw.edu.pl
-L: linux-kernel@vger.kernel.org
+M: bzolnier@gmail.com
L: linux-ide@vger.kernel.org
-T: git kernel.org:/pub/scm/linux/kernel/git/bart/ide-2.6.git
+T: quilt kernel.org/pub/linux/kernel/people/bart/pata-2.6/
S: Maintained
IDE/ATAPI CDROM DRIVER
-P: Jens Axboe
-M: axboe@kernel.dk
-L: linux-kernel@vger.kernel.org
-W: http://www.kernel.dk
+P: Alan Cox
+M: alan@lxorguk.ukuu.org.uk
+L: linux-ide@vger.kernel.org
S: Maintained
IDE/ATAPI FLOPPY DRIVERS
@@ -1479,7 +1671,7 @@ S: Maintained
IMS TWINTURBO FRAMEBUFFER DRIVER
P: Paul Mundt
M: lethal@chaoticdreams.org
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
INFINIBAND SUBSYSTEM
@@ -1504,21 +1696,23 @@ T: git kernel.org:/pub/scm/linux/kernel/git/dtor/input.git
S: Maintained
INOTIFY
-P: John McCutchan and Robert Love
-M: ttb@tentacle.dhs.org and rml@novell.com
+P: John McCutchan
+M: ttb@tentacle.dhs.org
+P: Robert Love
+M: rml@novell.com
L: linux-kernel@vger.kernel.org
S: Maintained
INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
P: Sylvain Meyer
M: sylvain.meyer@worldonline.fr
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
INTEL 810/815 FRAMEBUFFER DRIVER
P: Antonino Daplas
M: adaplas@pol.net
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT
@@ -1542,6 +1736,12 @@ P: Deepak Saxena
M: dsaxena@plexity.net
S: Maintained
+INTEL IXP2000 ETHERNET DRIVER
+P: Lennert Buytenhek
+M: kernel@wantstofly.org
+L: netdev@vger.kernel.org
+S: Maintained
+
INTEL PRO/100 ETHERNET SUPPORT
P: John Ronciak
M: john.ronciak@intel.com
@@ -1739,11 +1939,17 @@ S: Maintained
KERNEL NFSD
P: Neil Brown
-M: neilb@cse.unsw.edu.au
+M: neilb@suse.de
L: nfs@lists.sourceforge.net
W: http://nfs.sourceforge.net/
-W: http://www.cse.unsw.edu.au/~neilb/patches/linux-devel/
-S: Maintained
+S: Supported
+
+KERNEL VIRTUAL MACHINE (KVM)
+P: Avi Kivity
+M: avi@qumranet.com
+L: kvm-devel@lists.sourceforge.net
+W: kvm.sourceforge.net
+S: Supported
KEXEC
P: Eric Biederman
@@ -1903,9 +2109,9 @@ S: Maintained
LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
P: Eric Moore
-M: Eric.Moore@lsil.com
-M: support@lsil.com
-L: mpt_linux_developer@lsil.com
+M: Eric.Moore@lsi.com
+M: support@lsi.com
+L: mpt_linux_developer@lsi.com
L: linux-scsi@vger.kernel.org
W: http://www.lsilogic.com/support
S: Supported
@@ -1964,7 +2170,7 @@ S: Odd Fixes for 2.4; Maintained for 2.6.
MATROX FRAMEBUFFER DRIVER
P: Petr Vandrovec
M: vandrove@vc.cvut.cz
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
MEGARAID SCSI DRIVERS
@@ -2025,6 +2231,12 @@ M: rubini@ipvvis.unipv.it
L: linux-kernel@vger.kernel.org
S: Maintained
+MOXA SMARTIO/INDUSTIO SERIAL CARD (MXSER 2.0)
+P: Jiri Slaby
+M: jirislaby@gmail.com
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
MSI LAPTOP SUPPORT
P: Lennart Poettering
M: mzxreary@0pointer.de
@@ -2050,6 +2262,12 @@ P: Andrew Veliath
M: andrewtv@usa.net
S: Maintained
+MULTITECH MULTIPORT CARD (ISICOM)
+P: Jiri Slaby
+M: jirislaby@gmail.com
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
NATSEMI ETHERNET DRIVER (DP8381x)
P: Tim Hockin
M: thockin@hockin.org
@@ -2069,7 +2287,7 @@ S: Maintained
NETEM NETWORK EMULATOR
P: Stephen Hemminger
-M: shemminger@osdl.org
+M: shemminger@linux-foundation.org
L: netem@osdl.org
S: Maintained
@@ -2082,7 +2300,7 @@ P: Jozsef Kadlecsik
P: Patrick McHardy
M: kaber@trash.net
L: netfilter-devel@lists.netfilter.org
-L: netfilter@lists.netfilter.org
+L: netfilter@lists.netfilter.org (subscribers-only)
L: coreteam@netfilter.org
W: http://www.netfilter.org/
W: http://www.iptables.org/
@@ -2143,7 +2361,7 @@ S: Maintained
NETWORKING [WIRELESS]
P: John W. Linville
M: linville@tuxdriver.com
-L: netdev@vger.kernel.org
+L: linux-wireless@vger.kernel.org
T: git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6.git
S: Maintained
@@ -2210,7 +2428,7 @@ S: Maintained
NVIDIA (rivafb and nvidiafb) FRAMEBUFFER DRIVER
P: Antonino Daplas
M: adaplas@pol.net
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
OPENCORES I2C BUS DRIVER
@@ -2277,6 +2495,12 @@ L: orinoco-devel@lists.sourceforge.net
W: http://www.nongnu.org/orinoco/
S: Maintained
+PA SEMI ETHERNET DRIVER
+P: Olof Johansson
+M: olof@lixom.net
+L: netdev@vger.kernel.org
+S: Maintained
+
PARALLEL PORT SUPPORT
P: Phil Blundell
M: philb@gnu.org
@@ -2356,7 +2580,7 @@ PCIE HOTPLUG DRIVER
P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com
L: pcihpd-discuss@lists.sourceforge.net
-S: Maintained
+S: Supported
PCMCIA SUBSYSTEM
P: Linux PCMCIA Team
@@ -2414,6 +2638,12 @@ P: Adam Belay
M: ambx1@neo.rr.com
S: Maintained
+PNXxxxx I2C DRIVER
+P: Vitaly Wool
+M: vitalywool@gmail.com
+L: i2c@lm-sensors.org
+S: Maintained
+
PPP PROTOCOL DRIVERS AND COMPRESSORS
P: Paul Mackerras
M: paulus@samba.org
@@ -2440,7 +2670,7 @@ S: Supported
PRISM54 WIRELESS DRIVER
P: Prism54 Development Team
-M: prism54-private@prism54.org
+M: developers@islsm.org
L: netdev@vger.kernel.org
W: http://prism54.org
S: Maintained
@@ -2451,6 +2681,12 @@ M: promise@pnd-pc.demon.co.uk
W: http://www.pnd-pc.demon.co.uk/promise/
S: Maintained
+PROMISE SATA TX2/TX4 CONTROLLER LIBATA DRIVER
+P: Mikael Pettersson
+M: mikpe@it.uu.se
+L: linux-ide@vger.kernel.org
+S: Maintained
+
PS3 PLATFORM SUPPORT
P: Geoff Levand
M: geoffrey.levand@am.sony.com
@@ -2494,13 +2730,13 @@ S: Maintained
RADEON FRAMEBUFFER DISPLAY DRIVER
P: Benjamin Herrenschmidt
M: benh@kernel.crashing.org
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
RAGE128 FRAMEBUFFER DISPLAY DRIVER
P: Paul Mackerras
M: paulus@samba.org
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
@@ -2542,7 +2778,7 @@ S: Maintained
REAL TIME CLOCK (RTC) SUBSYSTEM
P: Alessandro Zummo
M: a.zummo@towertech.it
-L: linux-kernel@vger.kernel.org
+L: rtc-linux@googlegroups.com
S: Maintained
REISERFS FILE SYSTEM
@@ -2570,7 +2806,7 @@ S: Orphan
S3 SAVAGE FRAMEBUFFER DRIVER
P: Antonino Daplas
M: adaplas@pol.net
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
S390
@@ -2579,7 +2815,7 @@ M: schwidefsky@de.ibm.com
P: Heiko Carstens
M: heiko.carstens@de.ibm.com
M: linux390@de.ibm.com
-L: linux-390@vm.marist.edu
+L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
@@ -2587,7 +2823,7 @@ S390 NETWORK DRIVERS
P: Frank Pavlic
M: fpavlic@de.ibm.com
M: linux390@de.ibm.com
-L: linux-390@vm.marist.edu
+L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
@@ -2595,7 +2831,7 @@ S390 ZFCP DRIVER
P: Swen Schillig
M: swen@vnet.ibm.com
M: linux390@de.ibm.com
-L: linux-390@vm.marist.edu
+L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
@@ -2773,9 +3009,9 @@ SOFTWARE RAID (Multiple Disks) SUPPORT
P: Ingo Molnar
M: mingo@redhat.com
P: Neil Brown
-M: neilb@cse.unsw.edu.au
+M: neilb@suse.de
L: linux-raid@vger.kernel.org
-S: Maintained
+S: Supported
SOFTWARE SUSPEND:
P: Pavel Machek
@@ -2801,6 +3037,12 @@ M: perex@suse.cz
L: alsa-devel@alsa-project.org
S: Maintained
+SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT
+P: Liam Girdwood
+M: liam.girdwood@wolfsonmicro.com
+L: alsa-devel@alsa-project.org
+S: Supported
+
SPI SUBSYSTEM
P: David Brownell
M: dbrownell@users.sourceforge.net
@@ -2850,7 +3092,7 @@ SHPC HOTPLUG DRIVER
P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com
L: pcihpd-discuss@lists.sourceforge.net
-S: Maintained
+S: Supported
SECURE DIGITAL HOST CONTROLLER INTERFACE DRIVER
P: Pierre Ossman
@@ -2861,7 +3103,7 @@ S: Maintained
SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
P: Stephen Hemminger
-M: shemminger@osdl.org
+M: shemminger@linux-foundation.org
L: netdev@vger.kernel.org
S: Maintained
@@ -3051,6 +3293,11 @@ L: vtun@office.satix.net
W: http://vtun.sourceforge.net/tun
S: Maintained
+TURBOCHANNEL SUBSYSTEM
+P: Maciej W. Rozycki
+M: macro@linux-mips.org
+S: Maintained
+
U14-34F SCSI DRIVER
P: Dario Ballabio
M: ballabio_dario@emc.com
@@ -3096,7 +3343,7 @@ USB EHCI DRIVER
P: David Brownell
M: dbrownell@users.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
-S: Maintained
+S: Odd Fixes
USB ET61X[12]51 DRIVER
P: Luca Risolia
@@ -3114,9 +3361,8 @@ W: http://www.linux-usb.org/gadget
S: Maintained
USB HID/HIDBP DRIVERS
-P: Vojtech Pavlik
-M: vojtech@suse.cz
-L: linux-usb-users@lists.sourceforge.net
+P: Jiri Kosina
+M: jkosina@suse.cz
L: linux-usb-devel@lists.sourceforge.net
S: Maintained
@@ -3149,11 +3395,11 @@ S: Maintained
W: http://www.one-eyed-alien.net/~mdharm/linux-usb/
USB OHCI DRIVER
-P: Roman Weissgaerber
-M: weissg@vienna.at
+P: David Brownell
+M: dbrownell@users.sourceforge.net
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
-S: Maintained
+S: Odd Fixes
USB OPTION-CARD DRIVER
P: Matthias Urlichs
@@ -3356,6 +3602,12 @@ M: khali@linux-fr.org
L: i2c@lm-sensors.org
S: Maintained
+VIA VELOCITY NETWORK DRIVER
+P: Francois Romieu
+M: romieu@fr.zoreil.com
+L: netdev@vger.kernel.org
+S: Maintained
+
UCLINUX (AND M68KNOMMU)
P: Greg Ungerer
M: gerg@uclinux.org
@@ -3376,6 +3628,12 @@ M: ysato@users.sourceforge.jp
W: http://uclinux-h8.sourceforge.jp/
S: Supported
+UFS FILESYSTEM
+P: Evgeniy Dushistov
+M: dushistov@mail.ru
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
USB DIAMOND RIO500 DRIVER
P: Cesar Miquel
M: miquel@df.uba.ar
@@ -3415,10 +3673,16 @@ M: bezaur@gmail.com
L: lm-sensors@lm-sensors.org
S: Maintained
+W83793 HARDWARE MONITORING DRIVER
+P: Rudolf Marek
+M: r.marek@assembler.cz
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
W83L51xD SD/MMC CARD INTERFACE DRIVER
P: Pierre Ossman
M: drzeus-wbsd@drzeus.cx
-L: wbsd-devel@list.drzeus.cx
+L: linux-kernel@vger.kernel.org
W: http://projects.drzeus.cx/wbsd
S: Maintained
diff --git a/Makefile b/Makefile
index aef96259051..cdeda68cf2a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
VERSION = 2
PATCHLEVEL = 6
-SUBLEVEL = 19
+SUBLEVEL = 20
EXTRAVERSION =
-NAME=Avast! A bilge rat!
+NAME = Homicidal Dwarf Hamster
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
@@ -10,8 +10,11 @@ NAME=Avast! A bilge rat!
# Comments in this file are targeted only to the developer, do not
# expect to learn how to build the kernel reading this file.
-# Do not print "Entering directory ..."
-MAKEFLAGS += --no-print-directory
+# Do not:
+# o use make's built-in rules and variables
+# (this increases performance and avoid hard-to-debug behavour);
+# o print "Entering directory ...";
+MAKEFLAGS += -rR --no-print-directory
# We are using a recursive build, so we need to do a little thinking
# to get the ordering right.
@@ -271,12 +274,8 @@ export quiet Q KBUILD_VERBOSE
# Look for make include files relative to root of kernel src
MAKEFLAGS += --include-dir=$(srctree)
-# We need some generic definitions
-include $(srctree)/scripts/Kbuild.include
-
-# Do not use make's built-in rules and variables
-# This increases performance and avoid hard-to-debug behavour
-MAKEFLAGS += -rR
+# We need some generic definitions.
+include $(srctree)/scripts/Kbuild.include
# Make variables (CC, etc...)
@@ -497,11 +496,6 @@ else
CFLAGS += -fomit-frame-pointer
endif
-ifdef CONFIG_UNWIND_INFO
-CFLAGS += -fasynchronous-unwind-tables
-LDFLAGS_vmlinux += --eh-frame-hdr
-endif
-
ifdef CONFIG_DEBUG_INFO
CFLAGS += -g
endif
@@ -782,7 +776,7 @@ $(vmlinux-dirs): prepare scripts
# $(EXTRAVERSION) eg, -rc6
# $(localver-full)
# $(localver)
-# localversion* (all localversion* files)
+# localversion* (files without backups, containing '~')
# $(CONFIG_LOCALVERSION) (from kernel config setting)
# $(localver-auto) (only if CONFIG_LOCALVERSION_AUTO is set)
# ./scripts/setlocalversion (SCM tag, if one exists)
@@ -793,17 +787,12 @@ $(vmlinux-dirs): prepare scripts
# moment, only git is supported but other SCMs can edit the script
# scripts/setlocalversion and add the appropriate checks as needed.
-nullstring :=
-space := $(nullstring) # end of line
+pattern = ".*/localversion[^~]*"
+string = $(shell cat /dev/null \
+ `find $(objtree) $(srctree) -maxdepth 1 -regex $(pattern) | sort`)
-___localver = $(objtree)/localversion* $(srctree)/localversion*
-__localver = $(sort $(wildcard $(___localver)))
-# skip backup files (containing '~')
-_localver = $(foreach f, $(__localver), $(if $(findstring ~, $(f)),,$(f)))
-
-localver = $(subst $(space),, \
- $(shell cat /dev/null $(_localver)) \
- $(patsubst "%",%,$(CONFIG_LOCALVERSION)))
+localver = $(subst $(space),, $(string) \
+ $(patsubst "%",%,$(CONFIG_LOCALVERSION)))
# If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called
# and if the SCM is know a tag from the SCM is appended.
@@ -1101,9 +1090,9 @@ boards := $(notdir $(boards))
help:
@echo 'Cleaning targets:'
- @echo ' clean - remove most generated files but keep the config and'
+ @echo ' clean - Remove most generated files but keep the config and'
@echo ' enough build support to build external modules'
- @echo ' mrproper - remove all generated files + config + various backup files'
+ @echo ' mrproper - Remove all generated files + config + various backup files'
@echo ' distclean - mrproper + remove editor backup and patch files'
@echo ''
@echo 'Configuration targets:'
@@ -1122,15 +1111,15 @@ help:
@echo ' cscope - Generate cscope index'
@echo ' kernelrelease - Output the release version string'
@echo ' kernelversion - Output the version stored in Makefile'
- @if [ -r include/asm-$(ARCH)/Kbuild ]; then \
+ @if [ -r $(srctree)/include/asm-$(ARCH)/Kbuild ]; then \
echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
+ echo ' (default: $(INSTALL_HDR_PATH))'; \
fi
- @echo ' (default: $(INSTALL_HDR_PATH))'
@echo ''
@echo 'Static analysers'
@echo ' checkstack - Generate a list of stack hogs'
@echo ' namespacecheck - Name space analysis on compiled kernel'
- @if [ -r include/asm-$(ARCH)/Kbuild ]; then \
+ @if [ -r $(srctree)/include/asm-$(ARCH)/Kbuild ]; then \
echo ' headers_check - Sanity check on exported headers'; \
fi
@echo ''
@@ -1391,12 +1380,18 @@ 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).
+# UML needs a little special treatment here. It wants to use the host
+# toolchain, so needs $(SUBARCH) passed to checkstack.pl. Everyone
+# else wants $(ARCH), including people doing cross-builds, which means
+# that $(SUBARCH) doesn't work here.
+ifeq ($(ARCH), um)
+CHECKSTACK_ARCH := $(SUBARCH)
+else
+CHECKSTACK_ARCH := $(ARCH)
+endif
checkstack:
$(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \
- $(PERL) $(src)/scripts/checkstack.pl $(SUBARCH)
+ $(PERL) $(src)/scripts/checkstack.pl $(CHECKSTACK_ARCH)
kernelrelease:
$(if $(wildcard include/config/kernel.release), $(Q)echo $(KERNELRELEASE), \
@@ -1484,6 +1479,8 @@ endif # skip-makefile
PHONY += FORCE
FORCE:
+# Cancel implicit rules on top Makefile, `-rR' will apply to sub-makes.
+Makefile: ;
# Declare the contents of the .PHONY variable as phony. We keep that
# information in a variable se we can use it in if_changed and friends.
diff --git a/README b/README
index c0556152302..46a66c6e76d 100644
--- a/README
+++ b/README
@@ -278,8 +278,8 @@ IF SOMETHING GOES WRONG:
the file MAINTAINERS to see if there is a particular person associated
with the part of the kernel that you are having trouble with. If there
isn't anyone listed there, then the second best thing is to mail
- them to me (torvalds@osdl.org), and possibly to any other relevant
- mailing-list or to the newsgroup.
+ them to me (torvalds@linux-foundation.org), and possibly to any other
+ relevant mailing-list or to the newsgroup.
- In all bug-reports, *please* tell what kernel you are talking about,
how to duplicate the problem, and what your setup is (use your common
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 7e55ea66c6d..84caf50725b 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -25,6 +25,14 @@ config RWSEM_XCHGADD_ALGORITHM
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index ad617365199..be133f1f75a 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -277,7 +277,7 @@ osf_fstatfs(unsigned long fd, struct osf_statfs __user *buffer, unsigned long bu
retval = -EBADF;
file = fget(fd);
if (file) {
- retval = do_osf_statfs(file->f_dentry, buffer, bufsiz);
+ retval = do_osf_statfs(file->f_path.dentry, buffer, bufsiz);
fput(file);
}
return retval;
@@ -979,7 +979,7 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
long timeout;
int ret = -EINVAL;
struct fdtable *fdt;
- int max_fdset;
+ int max_fds;
timeout = MAX_SCHEDULE_TIMEOUT;
if (tvp) {
@@ -1003,9 +1003,9 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
rcu_read_lock();
fdt = files_fdtable(current->files);
- max_fdset = fdt->max_fdset;
+ max_fds = fdt->max_fds;
rcu_read_unlock();
- if (n < 0 || n > max_fdset)
+ if (n < 0 || n > max_fds)
goto out_nofds;
/*
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 3c10b9a1ddf..ab642a4f08d 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -575,3 +575,7 @@ void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
EXPORT_SYMBOL(pci_iomap);
EXPORT_SYMBOL(pci_iounmap);
+
+/* FIXME: Some boxes have multiple ISA bridges! */
+struct pci_dev *isa_bridge;
+EXPORT_SYMBOL(isa_bridge);
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 3370e6faeae..c1518639069 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -47,6 +47,7 @@
* Power off function, if any
*/
void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
void
cpu_idle(void)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8c05d4321ae..1523046e092 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -9,6 +9,7 @@ config ARM
bool
default y
select RTC_LIB
+ select SYS_SUPPORTS_APM_EMULATION
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
@@ -17,6 +18,9 @@ config ARM
Europe. There is an ARM Linux project with a web page at
<http://www.arm.linux.org.uk/>.
+config SYS_SUPPORTS_APM_EMULATION
+ bool
+
config GENERIC_TIME
bool
default n
@@ -74,6 +78,14 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_HWEIGHT
bool
default y
@@ -732,7 +744,7 @@ config XIP_PHYS_ADDR
endmenu
-if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP)
+if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX )
menu "CPU Frequency scaling"
@@ -759,6 +771,15 @@ config CPU_FREQ_INTEGRATOR
If in doubt, say Y.
+config CPU_FREQ_IMX
+ tristate "CPUfreq driver for i.MX CPUs"
+ depends on ARCH_IMX && CPU_FREQ
+ default n
+ help
+ This enables the CPUfreq driver for i.MX CPUs.
+
+ If in doubt, say N.
+
endmenu
endif
@@ -839,31 +860,6 @@ menu "Power management options"
source "kernel/power/Kconfig"
-config APM
- tristate "Advanced Power Management Emulation"
- ---help---
- APM is a BIOS specification for saving power using several different
- techniques. This is mostly useful for battery powered laptops with
- APM compliant BIOSes. If you say Y here, the system time will be
- reset after a RESUME operation, the /proc/apm device will provide
- battery status information, and user-space programs will receive
- notification of APM "events" (e.g. battery status change).
-
- In order to use APM, you will need supporting software. For location
- and more information, read <file:Documentation/pm.txt> and the
- Battery Powered Linux mini-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- This driver does not spin down disk drives (see the hdparm(8)
- manpage ("man 8 hdparm") for that), and it doesn't turn off
- VESA-compliant "green" monitors.
-
- Generally, if you don't have a battery in your machine, there isn't
- much point in using this driver and you should say N. If you get
- random kernel OOPSes or reboots that don't seem to be related to
- anything, try disabling/enabling this option (or disabling/enabling
- APM in your BIOS).
-
endmenu
source "net/Kconfig"
@@ -937,6 +933,8 @@ source "drivers/video/Kconfig"
source "sound/Kconfig"
+source "drivers/hid/Kconfig"
+
source "drivers/usb/Kconfig"
source "drivers/mmc/Kconfig"
diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c
index b3599743093..a3b450f8ef1 100644
--- a/arch/arm/common/sharpsl_pm.c
+++ b/arch/arm/common/sharpsl_pm.c
@@ -27,7 +27,7 @@
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/irq.h>
-#include <asm/apm.h>
+#include <asm/apm-emulation.h>
#include <asm/arch/pm.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/sharpsl.h>
diff --git a/arch/arm/configs/at91sam9260ek_defconfig b/arch/arm/configs/at91sam9260ek_defconfig
index 79049206dfa..46b0c734aeb 100644
--- a/arch/arm/configs/at91sam9260ek_defconfig
+++ b/arch/arm/configs/at91sam9260ek_defconfig
@@ -923,7 +923,6 @@ CONFIG_FORCED_INLINING=y
# CONFIG_HEADERS_CHECK 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
diff --git a/arch/arm/configs/at91sam9261ek_defconfig b/arch/arm/configs/at91sam9261ek_defconfig
index 784ad7c0186..fcd8fa091e9 100644
--- a/arch/arm/configs/at91sam9261ek_defconfig
+++ b/arch/arm/configs/at91sam9261ek_defconfig
@@ -1079,7 +1079,6 @@ CONFIG_FORCED_INLINING=y
# CONFIG_HEADERS_CHECK 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
diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig
index f8a66b72ad5..24a701ab33e 100644
--- a/arch/arm/configs/ep93xx_defconfig
+++ b/arch/arm/configs/ep93xx_defconfig
@@ -1,14 +1,18 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1-git9
-# Sat Jul 15 15:08:10 2006
+# Linux kernel version: 2.6.20-rc1
+# Sat Dec 16 06:05:24 2006
#
CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
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_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_VECTORS_BASE=0xffff0000
@@ -28,18 +32,22 @@ 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
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
-CONFIG_UID16=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -48,12 +56,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,7 +79,10 @@ 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
@@ -103,7 +114,9 @@ CONFIG_ARCH_EP93XX=y
# 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_IOP13XX is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_IXP23XX is not set
@@ -127,6 +140,7 @@ CONFIG_CRUNCH=y
#
CONFIG_MACH_ADSSPHERE=y
CONFIG_MACH_EDB9302=y
+CONFIG_MACH_EDB9302A=y
CONFIG_MACH_EDB9312=y
CONFIG_MACH_EDB9315=y
CONFIG_MACH_EDB9315A=y
@@ -138,12 +152,14 @@ CONFIG_MACH_TS72XX=y
#
CONFIG_CPU_32=y
CONFIG_CPU_ARM920T=y
-CONFIG_CPU_32v4=y
+CONFIG_CPU_32v4T=y
CONFIG_CPU_ABRT_EV4T=y
CONFIG_CPU_CACHE_V4WT=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
#
# Processor Features
@@ -230,6 +246,7 @@ 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 is not set
@@ -250,13 +267,29 @@ CONFIG_SYN_COOKIES=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_IPV6 is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+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 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 is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -283,7 +316,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
@@ -330,7 +362,7 @@ CONFIG_MTD_REDBOOT_PARTS=y
CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_AFS_PARTS is not set
#
@@ -342,6 +374,7 @@ CONFIG_MTD_BLOCK=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
@@ -430,7 +463,7 @@ CONFIG_MTD_NAND_IDS=y
#
# 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_NBD=y
# CONFIG_BLK_DEV_UB is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
@@ -442,6 +475,8 @@ CONFIG_MTD_NAND_IDS=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
# CONFIG_SCSI_PROC_FS is not set
#
@@ -460,23 +495,29 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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_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
@@ -513,6 +554,7 @@ CONFIG_NETDEVICES=y
#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
+CONFIG_EP93XX_ETH=y
# CONFIG_SMC91X is not set
# CONFIG_DM9000 is not set
@@ -607,17 +649,12 @@ CONFIG_EP93XX_WATCHDOG=y
# CONFIG_NVRAM 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
@@ -645,7 +682,7 @@ CONFIG_I2C_ALGOBIT=y
#
# CONFIG_SENSORS_DS1337 is not set
# CONFIG_SENSORS_DS1374 is not set
-# CONFIG_SENSORS_EEPROM is not set
+CONFIG_SENSORS_EEPROM=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
@@ -664,6 +701,7 @@ CONFIG_I2C_DEBUG_CHIP=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -697,12 +735,15 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
@@ -711,6 +752,7 @@ CONFIG_HWMON=y
#
# Misc devices
#
+# CONFIG_TIFM_CORE is not set
#
# LED devices
@@ -729,7 +771,6 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -742,6 +783,7 @@ CONFIG_VIDEO_V4L2=y
#
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -763,6 +805,7 @@ CONFIG_USB_DEBUG=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
CONFIG_USB_DYNAMIC_MINORS=y
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -797,12 +840,12 @@ 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
#
# USB Input Devices
#
-# CONFIG_USB_HID is not set
#
# USB HID Boot Protocol drivers
@@ -821,6 +864,7 @@ CONFIG_USB_STORAGE=y
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
CONFIG_USB_RTL8150=y
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
# CONFIG_USB_MON is not set
@@ -834,8 +878,8 @@ CONFIG_USB_RTL8150=y
CONFIG_USB_SERIAL=y
CONFIG_USB_SERIAL_CONSOLE=y
# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
# CONFIG_USB_SERIAL_AIRPRIME is not set
-# CONFIG_USB_SERIAL_ANYDATA is not set
# CONFIG_USB_SERIAL_ARK3116 is not set
# CONFIG_USB_SERIAL_BELKIN is not set
# CONFIG_USB_SERIAL_WHITEHEAT is not set
@@ -857,6 +901,8 @@ CONFIG_USB_SERIAL_CONSOLE=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_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
# CONFIG_USB_SERIAL_NAVMAN is not set
CONFIG_USB_SERIAL_PL2303=y
# CONFIG_USB_SERIAL_HP4X is not set
@@ -867,12 +913,14 @@ CONFIG_USB_SERIAL_PL2303=y
# CONFIG_USB_SERIAL_XIRCOM is not set
# CONFIG_USB_SERIAL_OPTION is not set
# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG 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
@@ -880,11 +928,12 @@ CONFIG_USB_SERIAL_PL2303=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_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_TEST is not set
#
@@ -908,6 +957,7 @@ CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
#
# RTC interfaces
@@ -921,7 +971,7 @@ CONFIG_RTC_INTF_DEV=y
# RTC drivers
#
# CONFIG_RTC_DRV_X1205 is not set
-# CONFIG_RTC_DRV_DS1307 is not set
+CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_DS1553 is not set
# CONFIG_RTC_DRV_ISL1208 is not set
# CONFIG_RTC_DRV_DS1672 is not set
@@ -943,12 +993,14 @@ CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG 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
@@ -980,8 +1032,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
# Pseudo filesystems
#
CONFIG_PROC_FS=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
@@ -1102,6 +1156,11 @@ CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -1110,8 +1169,11 @@ CONFIG_NLS_ISO8859_1=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1128,10 +1190,9 @@ CONFIG_DEBUG_MUTEXES=y
# 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_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_DEBUG_USER=y
@@ -1151,12 +1212,9 @@ CONFIG_DEBUG_LL=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -1164,3 +1222,4 @@ CONFIG_LIBCRC32C=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/iop13xx_defconfig b/arch/arm/configs/iop13xx_defconfig
index f6e46193fd2..43c4a37e924 100644
--- a/arch/arm/configs/iop13xx_defconfig
+++ b/arch/arm/configs/iop13xx_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19
-# Fri Dec 1 10:51:01 2006
+# Linux kernel version: 2.6.20-rc1-git5
+# Tue Dec 19 21:38:01 2006
#
CONFIG_ARM=y
# CONFIG_GENERIC_TIME is not set
@@ -11,6 +11,8 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_VECTORS_BASE=0xffff0000
@@ -39,6 +41,7 @@ CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -77,7 +80,9 @@ 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
@@ -154,11 +159,13 @@ CONFIG_IO_36=y
CONFIG_ARM_THUMB=y
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_IWMMXT is not set
#
# Bus support
#
CONFIG_PCI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -259,9 +266,23 @@ 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_TCP_MD5SIG is not set
+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 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 is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -433,7 +454,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# 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_NBD=y
# CONFIG_BLK_DEV_SX8 is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=2
@@ -448,6 +469,7 @@ CONFIG_BLK_DEV_INITRD=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
@@ -467,6 +489,7 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
#
# SCSI Transports
@@ -510,6 +533,7 @@ CONFIG_SCSI_SAS_ATTRS=y
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
#
# Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -605,6 +629,7 @@ CONFIG_E1000_NAPI=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -711,10 +736,6 @@ CONFIG_HW_RANDOM=y
# 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
@@ -820,6 +841,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
@@ -830,6 +852,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
@@ -883,6 +906,11 @@ CONFIG_DUMMY_CONSOLE=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -970,6 +998,7 @@ CONFIG_RAMFS=y
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
+CONFIG_ECRYPT_FS=y
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
@@ -1092,6 +1121,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -1103,28 +1137,68 @@ CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DEBUG_BUGVERBOSE=y
-# CONFIG_DEBUG_FS is not set
CONFIG_FRAME_POINTER=y
-# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_USER=y
#
# Security options
#
-# CONFIG_KEYS is not set
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_WP512=y
+CONFIG_CRYPTO_TGR192=y
+CONFIG_CRYPTO_GF128MUL=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_LRW=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_TWOFISH_COMMON=y
+CONFIG_CRYPTO_SERPENT=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_CAST5=y
+CONFIG_CRYPTO_CAST6=y
+CONFIG_CRYPTO_TEA=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_KHAZAD=y
+CONFIG_CRYPTO_ANUBIS=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=y
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -1132,3 +1206,4 @@ CONFIG_LIBCRC32C=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/iop32x_defconfig b/arch/arm/configs/iop32x_defconfig
index b275c53728e..7909a555706 100644
--- a/arch/arm/configs/iop32x_defconfig
+++ b/arch/arm/configs/iop32x_defconfig
@@ -1,15 +1,18 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc7
-# Tue Sep 19 00:30:18 2006
+# Linux kernel version: 2.6.20-rc1-git5
+# Tue Dec 19 21:37:52 2006
#
CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
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_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_VECTORS_BASE=0xffff0000
@@ -29,18 +32,22 @@ 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_SYSCTL=y
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
-CONFIG_UID16=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -49,12 +56,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
@@ -72,7 +79,10 @@ 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
@@ -106,6 +116,7 @@ CONFIG_DEFAULT_IOSCHED="cfq"
# CONFIG_ARCH_IMX is not set
CONFIG_ARCH_IOP32X=y
# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_IXP23XX is not set
@@ -141,17 +152,22 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
#
# Processor Features
#
# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_IWMMXT is not set
CONFIG_XSCALE_PMU=y
#
# Bus support
#
CONFIG_PCI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
#
@@ -225,6 +241,7 @@ 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
@@ -246,13 +263,29 @@ CONFIG_IP_PNP_BOOTP=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_IPV6 is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+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 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 is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -279,7 +312,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
@@ -338,6 +370,7 @@ CONFIG_MTD_BLOCK=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
@@ -419,9 +452,11 @@ 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_NBD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
# 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
@@ -440,6 +475,8 @@ CONFIG_BLK_DEV_INITRD=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -458,14 +495,16 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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
@@ -478,26 +517,84 @@ CONFIG_CHR_DEV_SG=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
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP 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=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_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_MARVELL 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)
@@ -512,6 +609,7 @@ CONFIG_MD_RAID1=y
# CONFIG_MD_MULTIPATH is not set
# CONFIG_MD_FAULTY 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
@@ -612,6 +710,7 @@ CONFIG_R8169=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)
@@ -620,6 +719,7 @@ CONFIG_R8169=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -654,6 +754,7 @@ CONFIG_R8169=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -725,10 +826,6 @@ CONFIG_HW_RANDOM=y
# 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
@@ -736,7 +833,6 @@ CONFIG_HW_RANDOM=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -801,6 +897,7 @@ CONFIG_I2C_IOP3XX=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -834,15 +931,18 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 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
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
@@ -851,6 +951,8 @@ CONFIG_HWMON=y
#
# Misc devices
#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
#
# LED devices
@@ -869,12 +971,12 @@ CONFIG_HWMON=y
# 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
@@ -895,6 +997,11 @@ CONFIG_DUMMY_CONSOLE=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -909,6 +1016,7 @@ CONFIG_USB=y
# CONFIG_USB_DEVICEFS is not set
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -946,6 +1054,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
#
@@ -984,6 +1093,7 @@ CONFIG_USB_STORAGE=y
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
CONFIG_USB_MON=y
@@ -1001,6 +1111,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
@@ -1008,12 +1119,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
#
# USB DSL modem support
@@ -1045,6 +1157,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
@@ -1056,6 +1169,7 @@ CONFIG_XFS_FS=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 is not set
# CONFIG_ROMFS_FS is not set
@@ -1084,8 +1198,10 @@ CONFIG_DNOTIFY=y
# Pseudo filesystems
#
CONFIG_PROC_FS=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
@@ -1095,6 +1211,7 @@ CONFIG_RAMFS=y
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
+CONFIG_ECRYPT_FS=y
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
@@ -1129,7 +1246,7 @@ 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_NFSD_TCP=y
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
@@ -1172,6 +1289,11 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -1180,8 +1302,11 @@ CONFIG_MSDOS_PARTITION=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1197,10 +1322,9 @@ CONFIG_DETECT_SOFTLOCKUP=y
# 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_DEBUG_LIST 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
@@ -1211,13 +1335,48 @@ CONFIG_DEBUG_LL=y
#
# Security options
#
-# CONFIG_KEYS is not set
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_WP512=y
+CONFIG_CRYPTO_TGR192=y
+CONFIG_CRYPTO_GF128MUL=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_LRW=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_TWOFISH_COMMON=y
+CONFIG_CRYPTO_SERPENT=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_CAST5=y
+CONFIG_CRYPTO_CAST6=y
+CONFIG_CRYPTO_TEA=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_KHAZAD=y
+CONFIG_CRYPTO_ANUBIS=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_TEST is not set
#
# Hardware crypto devices
@@ -1226,10 +1385,12 @@ CONFIG_DEBUG_LL=y
#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
+CONFIG_LIBCRC32C=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/iop33x_defconfig b/arch/arm/configs/iop33x_defconfig
index 848e3ace906..fa271bce8ff 100644
--- a/arch/arm/configs/iop33x_defconfig
+++ b/arch/arm/configs/iop33x_defconfig
@@ -1,15 +1,18 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc7
-# Tue Sep 19 00:30:42 2006
+# Linux kernel version: 2.6.20-rc1
+# Sat Dec 16 06:05:34 2006
#
CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
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_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_VECTORS_BASE=0xffff0000
@@ -29,18 +32,22 @@ 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_SYSCTL=y
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
-CONFIG_UID16=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -49,12 +56,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
@@ -72,7 +79,10 @@ 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
@@ -106,6 +116,7 @@ CONFIG_DEFAULT_IOSCHED="cfq"
# CONFIG_ARCH_IMX is not set
# CONFIG_ARCH_IOP32X is not set
CONFIG_ARCH_IOP33X=y
+# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_IXP23XX is not set
@@ -139,17 +150,22 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
#
# Processor Features
#
# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_IWMMXT is not set
CONFIG_XSCALE_PMU=y
#
# Bus support
#
CONFIG_PCI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
#
@@ -223,6 +239,7 @@ 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
@@ -244,13 +261,29 @@ CONFIG_IP_PNP_BOOTP=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_IPV6 is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+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 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 is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -277,7 +310,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
@@ -336,6 +368,7 @@ CONFIG_MTD_BLOCK=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
@@ -423,7 +456,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
# 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_NBD=y
# CONFIG_BLK_DEV_SX8 is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
@@ -443,6 +476,8 @@ CONFIG_BLK_DEV_INITRD=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -461,14 +496,16 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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
@@ -481,26 +518,34 @@ CONFIG_CHR_DEV_SG=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
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -515,6 +560,7 @@ CONFIG_MD_RAID1=y
# CONFIG_MD_MULTIPATH is not set
# CONFIG_MD_FAULTY 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
@@ -580,6 +626,7 @@ CONFIG_E1000_NAPI=y
# CONFIG_SK98LIN is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -588,6 +635,7 @@ CONFIG_E1000_NAPI=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -622,6 +670,7 @@ CONFIG_E1000_NAPI=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -693,10 +742,6 @@ CONFIG_HW_RANDOM=y
# 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
@@ -704,7 +749,6 @@ CONFIG_HW_RANDOM=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -769,6 +813,7 @@ CONFIG_I2C_IOP3XX=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -802,15 +847,18 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 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
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
@@ -819,6 +867,8 @@ CONFIG_HWMON=y
#
# Misc devices
#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
#
# LED devices
@@ -837,7 +887,6 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -863,6 +912,11 @@ CONFIG_DUMMY_CONSOLE=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -900,6 +954,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
@@ -911,6 +966,7 @@ CONFIG_XFS_FS=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 is not set
# CONFIG_ROMFS_FS is not set
@@ -939,8 +995,10 @@ CONFIG_DNOTIFY=y
# Pseudo filesystems
#
CONFIG_PROC_FS=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
@@ -1019,6 +1077,11 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -1027,8 +1090,11 @@ CONFIG_MSDOS_PARTITION=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1044,10 +1110,9 @@ CONFIG_DETECT_SOFTLOCKUP=y
# 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_DEBUG_LIST 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
@@ -1067,10 +1132,6 @@ CONFIG_DEBUG_LL=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
@@ -1078,3 +1139,4 @@ CONFIG_DEBUG_LL=y
# CONFIG_CRC32 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/ixp2000_defconfig b/arch/arm/configs/ixp2000_defconfig
index bbd2dcf91e5..f8f9793b526 100644
--- a/arch/arm/configs/ixp2000_defconfig
+++ b/arch/arm/configs/ixp2000_defconfig
@@ -1,14 +1,18 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Sun Jul 9 15:28:50 2006
+# Linux kernel version: 2.6.20-rc1
+# Sat Dec 16 06:05:39 2006
#
CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
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_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_VECTORS_BASE=0xffff0000
@@ -28,17 +32,22 @@ 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_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
-CONFIG_UID16=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -47,12 +56,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
@@ -70,7 +79,10 @@ 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
@@ -102,7 +114,9 @@ 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_IOP13XX is not set
# CONFIG_ARCH_IXP4XX is not set
CONFIG_ARCH_IXP2000=y
# CONFIG_ARCH_IXP23XX is not set
@@ -143,24 +157,28 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
#
# Processor Features
#
# CONFIG_ARM_THUMB is not set
CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_IWMMXT is not set
CONFIG_XSCALE_PMU=y
#
# Bus support
#
CONFIG_PCI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
#
# PCCARD (PCMCIA/CardBus) support
#
-# CONFIG_PCCARD is not set
#
# Kernel Features
@@ -228,6 +246,7 @@ 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 is not set
@@ -248,13 +267,29 @@ CONFIG_SYN_COOKIES=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_IPV6 is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+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 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 is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -281,7 +316,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
@@ -308,7 +342,6 @@ CONFIG_TCP_CONG_BIC=y
#
CONFIG_STANDALONE=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_FW_LOADER is not set
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_SYS_HYPERVISOR is not set
@@ -340,6 +373,7 @@ CONFIG_MTD_BLOCK=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
@@ -422,11 +456,12 @@ CONFIG_MTD_IXP2000=y
# 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_NBD=y
# 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_RAM_BLOCKSIZE=1024
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -436,6 +471,12 @@ CONFIG_BLK_DEV_INITRD=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)
@@ -501,8 +542,8 @@ CONFIG_NET_PCI=y
# CONFIG_FORCEDETH is not set
CONFIG_CS89x0=y
# CONFIG_DGRS is not set
-CONFIG_EEPRO100=y
-# CONFIG_E100 is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
# CONFIG_FEALNX is not set
# CONFIG_NATSEMI is not set
# CONFIG_NE2K_PCI is not set
@@ -532,6 +573,7 @@ CONFIG_ENP2611_MSF_NET=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)
@@ -540,6 +582,7 @@ CONFIG_ENP2611_MSF_NET=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -555,7 +598,6 @@ CONFIG_ENP2611_MSF_NET=y
# Wan interfaces
#
CONFIG_WAN=y
-# CONFIG_DSCC4 is not set
# CONFIG_LANMEDIA is not set
CONFIG_HDLC=y
CONFIG_HDLC_RAW=y
@@ -571,6 +613,7 @@ CONFIG_HDLC_PPP=y
# CONFIG_WANXL is not set
# CONFIG_PC300 is not set
# CONFIG_FARSYNC is not set
+# CONFIG_DSCC4 is not set
CONFIG_DLCI=y
CONFIG_DLCI_COUNT=24
CONFIG_DLCI_MAX=8
@@ -592,6 +635,7 @@ CONFIG_DLCI_MAX=8
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -673,10 +717,6 @@ CONFIG_IXP2000_WATCHDOG=y
# 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
@@ -684,7 +724,6 @@ CONFIG_IXP2000_WATCHDOG=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -749,6 +788,7 @@ CONFIG_SENSORS_EEPROM=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -782,15 +822,18 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 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
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
@@ -799,6 +842,8 @@ CONFIG_HWMON=y
#
# Misc devices
#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
#
# LED devices
@@ -817,7 +862,6 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -829,6 +873,7 @@ CONFIG_VIDEO_V4L2=y
#
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -836,6 +881,11 @@ CONFIG_VIDEO_V4L2=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -875,6 +925,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
@@ -882,6 +933,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
@@ -910,8 +962,10 @@ CONFIG_DNOTIFY=y
# Pseudo filesystems
#
CONFIG_PROC_FS=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
@@ -961,7 +1015,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
@@ -994,6 +1047,11 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -1002,8 +1060,11 @@ CONFIG_MSDOS_PARTITION=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1019,10 +1080,9 @@ CONFIG_DEBUG_MUTEXES=y
# 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_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_DEBUG_USER=y
@@ -1042,12 +1102,9 @@ CONFIG_DEBUG_LL=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -1055,3 +1112,4 @@ CONFIG_CRC32=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/ixp23xx_defconfig b/arch/arm/configs/ixp23xx_defconfig
index 06deefaec1d..27cf022dd80 100644
--- a/arch/arm/configs/ixp23xx_defconfig
+++ b/arch/arm/configs/ixp23xx_defconfig
@@ -1,14 +1,18 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Sun Jul 9 14:13:35 2006
+# Linux kernel version: 2.6.20-rc1
+# Sat Dec 16 06:05:45 2006
#
CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
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_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_VECTORS_BASE=0xffff0000
@@ -28,17 +32,22 @@ 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_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
-CONFIG_UID16=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -47,12 +56,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
@@ -70,7 +79,10 @@ 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
@@ -102,7 +114,9 @@ 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_IOP13XX is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_IXP2000 is not set
CONFIG_ARCH_IXP23XX=y
@@ -137,6 +151,8 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
CONFIG_IO_36=y
#
@@ -144,11 +160,15 @@ CONFIG_IO_36=y
#
# CONFIG_ARM_THUMB is not set
CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_IWMMXT is not set
#
# Bus support
#
CONFIG_PCI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
#
@@ -222,6 +242,7 @@ 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 is not set
@@ -242,13 +263,29 @@ CONFIG_SYN_COOKIES=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_IPV6 is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+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 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 is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -275,7 +312,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
@@ -334,6 +370,7 @@ CONFIG_MTD_BLOCK=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
@@ -418,12 +455,13 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
# 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_NBD=y
# 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
@@ -432,6 +470,7 @@ CONFIG_BLK_DEV_INITRD=y
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
CONFIG_BLK_DEV_IDE=y
#
@@ -455,7 +494,6 @@ CONFIG_BLK_DEV_IDEPCI=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_SL82C105 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
# CONFIG_IDEDMA_PCI_AUTO is not set
@@ -469,6 +507,7 @@ CONFIG_BLK_DEV_IDEDMA_PCI=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
@@ -477,6 +516,7 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_PDC202XX_NEW is not set
# CONFIG_BLK_DEV_SVWKS is not set
CONFIG_BLK_DEV_SIIMAGE=y
+# CONFIG_BLK_DEV_SL82C105 is not set
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
@@ -491,6 +531,8 @@ CONFIG_BLK_DEV_IDEDMA=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -509,14 +551,16 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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
@@ -529,26 +573,34 @@ 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
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -649,6 +701,7 @@ CONFIG_E1000_NAPI=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)
@@ -657,6 +710,7 @@ CONFIG_E1000_NAPI=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -672,7 +726,6 @@ CONFIG_E1000_NAPI=y
# Wan interfaces
#
CONFIG_WAN=y
-# CONFIG_DSCC4 is not set
# CONFIG_LANMEDIA is not set
CONFIG_HDLC=y
CONFIG_HDLC_RAW=y
@@ -688,6 +741,7 @@ CONFIG_HDLC_PPP=y
# CONFIG_WANXL is not set
# CONFIG_PC300 is not set
# CONFIG_FARSYNC is not set
+# CONFIG_DSCC4 is not set
CONFIG_DLCI=y
CONFIG_DLCI_COUNT=24
CONFIG_DLCI_MAX=8
@@ -710,6 +764,7 @@ CONFIG_DLCI_MAX=8
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -795,10 +850,6 @@ CONFIG_WATCHDOG=y
# 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
@@ -806,7 +857,6 @@ CONFIG_WATCHDOG=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -870,6 +920,7 @@ CONFIG_SENSORS_EEPROM=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -903,15 +954,18 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 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
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
@@ -920,6 +974,8 @@ CONFIG_HWMON=y
#
# Misc devices
#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
#
# LED devices
@@ -938,7 +994,6 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -951,6 +1006,7 @@ CONFIG_VIDEO_V4L2=y
#
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -958,6 +1014,11 @@ CONFIG_VIDEO_V4L2=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -972,6 +1033,7 @@ CONFIG_USB=y
# CONFIG_USB_DEVICEFS is not set
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -1012,6 +1074,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
#
@@ -1050,6 +1113,7 @@ CONFIG_USB_STORAGE=y
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
CONFIG_USB_MON=y
@@ -1067,19 +1131,21 @@ 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
+# CONFIG_USB_TRANCEVIBRATOR is not set
#
# USB DSL modem support
@@ -1113,6 +1179,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
@@ -1120,6 +1187,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
@@ -1150,8 +1218,10 @@ CONFIG_FAT_DEFAULT_CODEPAGE=437
# Pseudo filesystems
#
CONFIG_PROC_FS=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
@@ -1201,7 +1271,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
@@ -1273,6 +1342,11 @@ CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -1281,8 +1355,11 @@ CONFIG_NLS_CODEPAGE_437=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1298,10 +1375,9 @@ CONFIG_DEBUG_MUTEXES=y
# 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_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_DEBUG_USER=y
@@ -1321,12 +1397,9 @@ CONFIG_DEBUG_LL=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -1334,3 +1407,4 @@ CONFIG_CRC32=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/lpd270_defconfig b/arch/arm/configs/lpd270_defconfig
index e146189ab54..a3bf5833b87 100644
--- a/arch/arm/configs/lpd270_defconfig
+++ b/arch/arm/configs/lpd270_defconfig
@@ -1,14 +1,18 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Sun Jul 9 14:15:23 2006
+# Linux kernel version: 2.6.20-rc1
+# Sat Dec 16 06:05:51 2006
#
CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
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_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ARCH_MTD_XIP=y
@@ -29,16 +33,21 @@ 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_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
-CONFIG_UID16=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -47,12 +56,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
@@ -69,7 +78,10 @@ CONFIG_MODULES=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
@@ -101,7 +113,9 @@ 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_IOP13XX is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_IXP23XX is not set
@@ -125,7 +139,6 @@ CONFIG_MACH_LOGICPD_PXA270=y
# CONFIG_PXA_SHARPSL is not set
# CONFIG_MACH_TRIZEPS4 is not set
CONFIG_PXA27x=y
-CONFIG_IWMMXT=y
#
# Processor Type
@@ -136,11 +149,15 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
#
# Processor Features
#
# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_IWMMXT=y
CONFIG_XSCALE_PMU=y
#
@@ -217,6 +234,7 @@ CONFIG_NET=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
@@ -237,13 +255,29 @@ CONFIG_IP_PNP_BOOTP=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_IPV6 is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+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 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 is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -270,7 +304,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
@@ -329,6 +362,7 @@ CONFIG_MTD_BLOCK=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
@@ -410,7 +444,7 @@ CONFIG_MTD_CFI_UTIL=y
#
# 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_NBD=y
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
@@ -447,6 +481,12 @@ CONFIG_BLK_DEV_IDEDISK=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)
@@ -526,6 +566,7 @@ CONFIG_SMC91X=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -548,6 +589,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 is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
@@ -600,17 +642,12 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_NVRAM 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
@@ -626,6 +663,7 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -634,11 +672,14 @@ CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_VT1211 is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
#
+# CONFIG_TIFM_CORE is not set
#
# LED devices
@@ -657,7 +698,6 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -679,6 +719,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_S1D13XXX is not set
CONFIG_FB_PXA=y
# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_MBX is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -725,7 +766,6 @@ CONFIG_SND_VERBOSE_PROCFS=y
# Generic devices
#
CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_AC97_BUS=y
# CONFIG_SND_DUMMY is not set
# CONFIG_SND_MTPAV is not set
# CONFIG_SND_SERIAL_U16550 is not set
@@ -741,6 +781,12 @@ CONFIG_SND_PXA2XX_AC97=y
# Open Sound System
#
# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+
+#
+# HID Devices
+#
+CONFIG_HID=y
#
# USB support
@@ -777,10 +823,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
@@ -811,6 +859,7 @@ CONFIG_FAT_DEFAULT_CODEPAGE=437
# Pseudo filesystems
#
CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
# CONFIG_TMPFS is not set
# CONFIG_HUGETLB_PAGE is not set
@@ -860,7 +909,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
@@ -917,6 +965,11 @@ CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -925,8 +978,11 @@ CONFIG_NLS_ISO8859_1=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -942,10 +998,9 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_FS is not set
# 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_DEBUG_USER=y
@@ -965,12 +1020,9 @@ CONFIG_DEBUG_LL=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -978,3 +1030,4 @@ CONFIG_CRC32=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/configs/onearm_defconfig b/arch/arm/configs/onearm_defconfig
index 0498ebd7d5d..650a248613e 100644
--- a/arch/arm/configs/onearm_defconfig
+++ b/arch/arm/configs/onearm_defconfig
@@ -1,14 +1,18 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Sun Jul 9 14:16:20 2006
+# Linux kernel version: 2.6.20-rc1
+# Sat Dec 16 06:05:18 2006
#
CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
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_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_VECTORS_BASE=0xffff0000
@@ -28,16 +32,21 @@ 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 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_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
-CONFIG_UID16=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -46,12 +55,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
@@ -69,7 +78,10 @@ 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
@@ -101,7 +113,9 @@ CONFIG_ARCH_AT91=y
# 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_IOP13XX is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_IXP23XX is not set
@@ -118,10 +132,6 @@ CONFIG_ARCH_AT91=y
#
# Atmel AT91 System-on-Chip
#
-
-#
-# Atmel AT91 Processors
-#
CONFIG_ARCH_AT91RM9200=y
# CONFIG_ARCH_AT91SAM9260 is not set
# CONFIG_ARCH_AT91SAM9261 is not set
@@ -140,6 +150,10 @@ CONFIG_MACH_ONEARM=y
# CONFIG_MACH_KAFA is not set
#
+# AT91 Board Options
+#
+
+#
# AT91 Feature Selections
#
CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
@@ -149,12 +163,14 @@ CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
#
CONFIG_CPU_32=y
CONFIG_CPU_ARM920T=y
-CONFIG_CPU_32v4=y
+CONFIG_CPU_32v4T=y
CONFIG_CPU_ABRT_EV4T=y
CONFIG_CPU_CACHE_V4WT=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
#
# Processor Features
@@ -251,6 +267,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
@@ -271,13 +288,29 @@ CONFIG_IP_PNP_BOOTP=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_IPV6 is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+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 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 is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -304,7 +337,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
@@ -360,6 +392,7 @@ CONFIG_MTD_BLOCK=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
@@ -438,11 +471,12 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=0
#
# 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_NBD=y
# 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
@@ -457,6 +491,12 @@ CONFIG_BLK_DEV_INITRD=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)
@@ -541,6 +581,7 @@ CONFIG_ARM_AT91_ETHER=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -619,10 +660,6 @@ CONFIG_AT91RM9200_WATCHDOG=y
# CONFIG_R3964 is not set
#
-# Ftape, the floppy tape device driver
-#
-
-#
# PCMCIA character devices
#
# CONFIG_SYNCLINK_CS is not set
@@ -634,7 +671,6 @@ CONFIG_AT91RM9200_WATCHDOG=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -652,6 +688,7 @@ CONFIG_I2C_CHARDEV=y
#
# I2C Hardware Bus support
#
+# CONFIG_I2C_AT91 is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_STUB is not set
@@ -681,6 +718,7 @@ CONFIG_I2C_CHARDEV=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -714,12 +752,15 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
@@ -728,6 +769,7 @@ CONFIG_HWMON=y
#
# Misc devices
#
+# CONFIG_TIFM_CORE is not set
#
# LED devices
@@ -746,7 +788,6 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -759,6 +800,7 @@ CONFIG_VIDEO_V4L2=y
#
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -766,6 +808,11 @@ CONFIG_VIDEO_V4L2=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -780,6 +827,7 @@ CONFIG_USB_DEBUG=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -804,7 +852,6 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
#
# may also be needed; see USB_STORAGE Help for more information
#
-# CONFIG_USB_STORAGE is not set
# CONFIG_USB_LIBUSUAL is not set
#
@@ -842,6 +889,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
CONFIG_USB_MON=y
@@ -859,18 +907,20 @@ 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_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_TEST is not set
#
@@ -897,6 +947,7 @@ CONFIG_USB_AT91=y
# CONFIG_USB_GADGETFS is not set
# CONFIG_USB_FILE_STORAGE is not set
# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
#
# MMC/SD Card support
@@ -904,7 +955,8 @@ CONFIG_USB_AT91=y
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
CONFIG_MMC_BLOCK=y
-CONFIG_MMC_AT91RM9200=y
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_TIFM_SD is not set
#
# Real Time Clock
@@ -919,10 +971,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=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
@@ -951,8 +1005,10 @@ CONFIG_DNOTIFY=y
# Pseudo filesystems
#
CONFIG_PROC_FS=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
@@ -995,7 +1051,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
@@ -1013,6 +1068,11 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -1021,8 +1081,11 @@ 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1038,10 +1101,9 @@ CONFIG_DETECT_SOFTLOCKUP=y
# 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_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_DEBUG_USER=y
@@ -1061,15 +1123,13 @@ CONFIG_DEBUG_LL=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
+CONFIG_BITREVERSE=y
# 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
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index ab06a86e85d..1b935fb94b8 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -10,7 +10,6 @@ obj-y := compat.o entry-armv.o entry-common.o irq.o \
process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \
time.o traps.o
-obj-$(CONFIG_APM) += apm.o
obj-$(CONFIG_ISA_DMA_API) += dma.o
obj-$(CONFIG_ARCH_ACORN) += ecard.o
obj-$(CONFIG_FIQ) += fiq.o
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 3173924a9b6..f7598cbc7ec 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -110,7 +110,7 @@
CALL(sys_ni_syscall) /* was sys_profil */
CALL(sys_statfs)
/* 100 */ CALL(sys_fstatfs)
- CALL(sys_ni_syscall)
+ CALL(sys_ni_syscall) /* sys_ioperm */
CALL(OBSOLETE(ABI(sys_socketcall, sys_oabi_socketcall)))
CALL(sys_syslog)
CALL(sys_setitimer)
@@ -132,7 +132,7 @@
/* 120 */ CALL(sys_clone_wrapper)
CALL(sys_setdomainname)
CALL(sys_newuname)
- CALL(sys_ni_syscall)
+ CALL(sys_ni_syscall) /* modify_ldt */
CALL(sys_adjtimex)
/* 125 */ CALL(sys_mprotect)
CALL(sys_sigprocmask)
@@ -146,7 +146,7 @@
CALL(sys_bdflush)
/* 135 */ CALL(sys_sysfs)
CALL(sys_personality)
- CALL(sys_ni_syscall) /* CALL(_sys_afs_syscall) */
+ CALL(sys_ni_syscall) /* reserved for afs_syscall */
CALL(sys_setfsuid16)
CALL(sys_setfsgid16)
/* 140 */ CALL(sys_llseek)
@@ -175,7 +175,7 @@
CALL(sys_arm_mremap)
CALL(sys_setresuid16)
/* 165 */ CALL(sys_getresuid16)
- CALL(sys_ni_syscall)
+ CALL(sys_ni_syscall) /* vm86 */
CALL(sys_ni_syscall) /* was sys_query_module */
CALL(sys_poll)
CALL(sys_nfsservctl)
@@ -197,8 +197,8 @@
/* 185 */ CALL(sys_capset)
CALL(sys_sigaltstack_wrapper)
CALL(sys_sendfile)
- CALL(sys_ni_syscall)
- CALL(sys_ni_syscall)
+ CALL(sys_ni_syscall) /* getpmsg */
+ CALL(sys_ni_syscall) /* putpmsg */
/* 190 */ CALL(sys_vfork_wrapper)
CALL(sys_getrlimit)
CALL(sys_mmap2)
@@ -331,6 +331,31 @@
CALL(sys_mbind)
/* 320 */ CALL(sys_get_mempolicy)
CALL(sys_set_mempolicy)
+ CALL(sys_openat)
+ CALL(sys_mkdirat)
+ CALL(sys_mknodat)
+/* 325 */ CALL(sys_fchownat)
+ CALL(sys_futimesat)
+ CALL(sys_fstatat64)
+ CALL(sys_unlinkat)
+ CALL(sys_renameat)
+/* 330 */ CALL(sys_linkat)
+ CALL(sys_symlinkat)
+ CALL(sys_readlinkat)
+ CALL(sys_fchmodat)
+ CALL(sys_faccessat)
+/* 335 */ CALL(sys_ni_syscall) /* eventually pselect6 */
+ CALL(sys_ni_syscall) /* eventually ppoll */
+ CALL(sys_unshare)
+ CALL(sys_set_robust_list)
+ CALL(sys_get_robust_list)
+/* 340 */ CALL(sys_splice)
+ CALL(sys_arm_sync_file_range)
+ CALL(sys_tee)
+ CALL(sys_vmsplice)
+ CALL(sys_move_pages)
+/* 345 */ CALL(sys_getcpu)
+ CALL(sys_ni_syscall) /* eventually epoll_pwait */
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index a786f769035..71257e3d513 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -353,7 +353,7 @@ int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
}
if (c_id(&excd) == 0x80) { /* loader */
if (!ec->loader) {
- ec->loader = (loader_t)kmalloc(c_len(&excd),
+ ec->loader = kmalloc(c_len(&excd),
GFP_KERNEL);
if (ec->loader)
ecard_readbytes(ec->loader, ec,
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 2db42b18f53..8517c3c3eb3 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -436,7 +436,7 @@ __und_usr:
usr_entry
tst r3, #PSR_T_BIT @ Thumb mode?
- bne fpundefinstr @ ignore FP
+ bne __und_usr_unknown @ ignore FP
sub r4, r2, #4
@
@@ -448,7 +448,7 @@ __und_usr:
@
1: ldrt r0, [r4]
adr r9, ret_from_exception
- adr lr, fpundefinstr
+ adr lr, __und_usr_unknown
@
@ fallthrough to call_fpe
@
@@ -476,7 +476,9 @@ __und_usr:
* Emulators may wish to make use of the following registers:
* r0 = instruction opcode.
* r2 = PC+4
+ * r9 = normal "successful" return address
* r10 = this threads thread_info structure.
+ * lr = unrecognised instruction return address
*/
call_fpe:
tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27
@@ -545,10 +547,12 @@ do_fpe:
.data
ENTRY(fp_enter)
- .word fpundefinstr
+ .word no_fp
.text
-fpundefinstr:
+no_fp: mov pc, lr
+
+__und_usr_unknown:
mov r0, sp
adr lr, ret_from_exception
b do_undefinstr
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index bda0748ffb0..cf495a3084b 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -22,30 +22,35 @@
#include <asm/thread_info.h>
#include <asm/system.h>
-#define KERNEL_RAM_ADDR (PAGE_OFFSET + TEXT_OFFSET)
+#if (PHYS_OFFSET & 0x001fffff)
+#error "PHYS_OFFSET must be at an even 2MiB boundary!"
+#endif
+
+#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
+#define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)
/*
* swapper_pg_dir is the virtual address of the initial page table.
- * We place the page tables 16K below KERNEL_RAM_ADDR. Therefore, we must
- * make sure that KERNEL_RAM_ADDR is correctly set. Currently, we expect
+ * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must
+ * make sure that KERNEL_RAM_VADDR is correctly set. Currently, we expect
* the least significant 16 bits to be 0x8000, but we could probably
- * relax this restriction to KERNEL_RAM_ADDR >= PAGE_OFFSET + 0x4000.
+ * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000.
*/
-#if (KERNEL_RAM_ADDR & 0xffff) != 0x8000
-#error KERNEL_RAM_ADDR must start at 0xXXXX8000
+#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
+#error KERNEL_RAM_VADDR must start at 0xXXXX8000
#endif
.globl swapper_pg_dir
- .equ swapper_pg_dir, KERNEL_RAM_ADDR - 0x4000
+ .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000
.macro pgtbl, rd
- ldr \rd, =(__virt_to_phys(KERNEL_RAM_ADDR - 0x4000))
+ ldr \rd, =(KERNEL_RAM_PADDR - 0x4000)
.endm
#ifdef CONFIG_XIP_KERNEL
#define TEXTADDR XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR)
#else
-#define TEXTADDR KERNEL_RAM_ADDR
+#define TEXTADDR KERNEL_RAM_VADDR
#endif
/*
@@ -250,7 +255,8 @@ __create_page_tables:
* Then map first 1MB of ram in case it contains our boot params.
*/
add r0, r4, #PAGE_OFFSET >> 18
- orr r6, r7, #PHYS_OFFSET
+ orr r6, r7, #(PHYS_OFFSET & 0xff000000)
+ orr r6, r6, #(PHYS_OFFSET & 0x00e00000)
str r6, [r0]
#ifdef CONFIG_XIP_KERNEL
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 238dd9b6db8..bbab134cd82 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -354,9 +354,6 @@ static void __init setup_processor(void)
#ifndef CONFIG_ARM_THUMB
elf_hwcap &= ~HWCAP_THUMB;
#endif
-#ifndef CONFIG_VFP
- elf_hwcap &= ~HWCAP_VFP;
-#endif
cpu_proc_init();
}
@@ -858,6 +855,7 @@ static const char *hwcap_str[] = {
"edsp",
"java",
"iwmmxt",
+ "crunch",
NULL
};
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index 00c18d35913..3d4fcbc1627 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -328,3 +328,16 @@ asmlinkage long sys_arm_fadvise64_64(int fd, int advice,
{
return sys_fadvise64_64(fd, offset, len, advice);
}
+
+/*
+ * Yet more syscall fsckage - we can't fit sys_sync_file_range's
+ * arguments into the available registers with EABI. So, let's
+ * create an ARM specific syscall for this which has _sane_
+ * arguments. (This incidentally also has an ABI-independent
+ * argument layout.)
+ */
+asmlinkage long sys_arm_sync_file_range(int fd, unsigned int flags,
+ loff_t offset, loff_t nbytes)
+{
+ return sys_sync_file_range(fd, offset, nbytes, flags);
+}
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 6ff5e3ff6cb..3c8cdcfe8d4 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -29,6 +29,8 @@
#include <linux/timer.h>
#include <linux/irq.h>
+#include <linux/mc146818rtc.h>
+
#include <asm/leds.h>
#include <asm/thread_info.h>
#include <asm/mach/time.h>
@@ -85,6 +87,17 @@ unsigned long long __attribute__((weak)) sched_clock(void)
return (unsigned long long)jiffies * (1000000000 / HZ);
}
+/*
+ * An implementation of printk_clock() independent from
+ * sched_clock(). This avoids non-bootable kernels when
+ * printk_clock is enabled.
+ */
+unsigned long long printk_clock(void)
+{
+ return (unsigned long long)(jiffies - INITIAL_JIFFIES) *
+ (1000000000 / HZ);
+}
+
static unsigned long next_rtc_update;
/*
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 042a12982e9..908915675ed 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -27,6 +27,7 @@
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/traps.h>
+#include <asm/io.h>
#include "ptrace.h"
#include "signal.h"
diff --git a/arch/arm/mach-at91rm9200/at91rm9200_devices.c b/arch/arm/mach-at91rm9200/at91rm9200_devices.c
index 4641b99db0e..57fac7203fe 100644
--- a/arch/arm/mach-at91rm9200/at91rm9200_devices.c
+++ b/arch/arm/mach-at91rm9200/at91rm9200_devices.c
@@ -272,7 +272,7 @@ void __init at91_add_device_cf(struct at91_cf_data *data)
at91_set_A_periph(AT91_PIN_PC12, 0); /* NCS6/CFCE2 */
/* nWAIT is _not_ a default setting */
- at91_set_A_periph(AT91_PIN_PC6, 1); /* nWAIT */
+ at91_set_A_periph(AT91_PIN_PC6, 1); /* nWAIT */
cf_data = *data;
platform_device_register(&at91rm9200_cf_device);
diff --git a/arch/arm/mach-at91rm9200/at91sam9260.c b/arch/arm/mach-at91rm9200/at91sam9260.c
index 203f073a53e..b14871adc30 100644
--- a/arch/arm/mach-at91rm9200/at91sam9260.c
+++ b/arch/arm/mach-at91rm9200/at91sam9260.c
@@ -16,6 +16,7 @@
#include <asm/mach/map.h>
#include <asm/arch/at91sam9260.h>
#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_rstc.h>
#include "generic.h"
#include "clock.h"
@@ -212,7 +213,7 @@ static struct at91_gpio_bank at91sam9260_gpio[] = {
static void at91sam9260_reset(void)
{
-#warning "Implement CPU reset"
+ at91_sys_write(AT91_RSTC_CR, (0xA5 << 24) | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
}
diff --git a/arch/arm/mach-at91rm9200/at91sam9260_devices.c b/arch/arm/mach-at91rm9200/at91sam9260_devices.c
index a6c596dc451..f42d3a40ec3 100644
--- a/arch/arm/mach-at91rm9200/at91sam9260_devices.c
+++ b/arch/arm/mach-at91rm9200/at91sam9260_devices.c
@@ -18,6 +18,7 @@
#include <asm/arch/gpio.h>
#include <asm/arch/at91sam9260.h>
#include <asm/arch/at91sam926x_mc.h>
+#include <asm/arch/at91sam9260_matrix.h>
#include "generic.h"
diff --git a/arch/arm/mach-at91rm9200/at91sam9261.c b/arch/arm/mach-at91rm9200/at91sam9261.c
index 5a82f35da2e..d242bb885c6 100644
--- a/arch/arm/mach-at91rm9200/at91sam9261.c
+++ b/arch/arm/mach-at91rm9200/at91sam9261.c
@@ -16,6 +16,7 @@
#include <asm/mach/map.h>
#include <asm/arch/at91sam9261.h>
#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_rstc.h>
#include "generic.h"
#include "clock.h"
@@ -207,7 +208,7 @@ static struct at91_gpio_bank at91sam9261_gpio[] = {
static void at91sam9261_reset(void)
{
-#warning "Implement CPU reset"
+ at91_sys_write(AT91_RSTC_CR, (0xA5 << 24) | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
}
diff --git a/arch/arm/mach-at91rm9200/board-sam9260ek.c b/arch/arm/mach-at91rm9200/board-sam9260ek.c
index ffca9bdec37..da5d58ac870 100644
--- a/arch/arm/mach-at91rm9200/board-sam9260ek.c
+++ b/arch/arm/mach-at91rm9200/board-sam9260ek.c
@@ -119,6 +119,7 @@ static struct spi_board_info ek_spi_devices[] = {
* MACB Ethernet device
*/
static struct __initdata eth_platform_data ek_macb_data = {
+ .phy_irq_pin = AT91_PIN_PA7,
.is_rmii = 1,
};
diff --git a/arch/arm/mach-at91rm9200/gpio.c b/arch/arm/mach-at91rm9200/gpio.c
index 3f188508c39..af22659c8a2 100644
--- a/arch/arm/mach-at91rm9200/gpio.c
+++ b/arch/arm/mach-at91rm9200/gpio.c
@@ -20,7 +20,6 @@
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/arch/at91_pio.h>
-#include <asm/arch/at91_pmc.h>
#include <asm/arch/gpio.h>
#include "generic.h"
@@ -224,17 +223,17 @@ static u32 backups[MAX_GPIO_BANKS];
static int gpio_irq_set_wake(unsigned pin, unsigned state)
{
unsigned mask = pin_to_mask(pin);
+ unsigned bank = (pin - PIN_BASE) / 32;
- pin -= PIN_BASE;
- pin /= 32;
-
- if (unlikely(pin >= MAX_GPIO_BANKS))
+ if (unlikely(bank >= MAX_GPIO_BANKS))
return -EINVAL;
if (state)
- wakeups[pin] |= mask;
+ wakeups[bank] |= mask;
else
- wakeups[pin] &= ~mask;
+ wakeups[bank] &= ~mask;
+
+ set_irq_wake(gpio[bank].id, state);
return 0;
}
@@ -246,29 +245,15 @@ void at91_gpio_suspend(void)
for (i = 0; i < gpio_banks; i++) {
u32 pio = gpio[i].offset;
- /*
- * Note: drivers should have disabled GPIO interrupts that
- * aren't supposed to be wakeup sources.
- * But that is not much good on ARM..... disable_irq() does
- * not update the hardware immediately, so the hardware mask
- * (IMR) has the wrong value (not current, too much is
- * permitted).
- *
- * Our workaround is to disable all non-wakeup IRQs ...
- * which is exactly what correct drivers asked for in the
- * first place!
- */
backups[i] = at91_sys_read(pio + PIO_IMR);
at91_sys_write(pio + PIO_IDR, backups[i]);
at91_sys_write(pio + PIO_IER, wakeups[i]);
- if (!wakeups[i]) {
- disable_irq_wake(gpio[i].id);
- at91_sys_write(AT91_PMC_PCDR, 1 << gpio[i].id);
- } else {
- enable_irq_wake(gpio[i].id);
+ if (!wakeups[i])
+ clk_disable(gpio[i].clock);
+ else {
#ifdef CONFIG_PM_DEBUG
- printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", "ABCD"[i], wakeups[i]);
+ printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]);
#endif
}
}
@@ -281,9 +266,11 @@ void at91_gpio_resume(void)
for (i = 0; i < gpio_banks; i++) {
u32 pio = gpio[i].offset;
+ if (!wakeups[i])
+ clk_enable(gpio[i].clock);
+
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);
}
}
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index d649b39711d..6b26346191c 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -477,4 +477,8 @@ void __init ep93xx_init_devices(void)
platform_device_register(&ep93xx_rtc_device);
platform_device_register(&ep93xx_ohci_device);
+
+#ifdef CONFIG_CRUNCH
+ elf_hwcap |= HWCAP_CRUNCH;
+#endif
}
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 0b27d79f2ef..02272aa36e9 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -9,6 +9,8 @@
obj-y += irq.o time.o dma.o generic.o
+obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o
+
# Specific board support
obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o
diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c
new file mode 100644
index 00000000000..4f66e90db74
--- /dev/null
+++ b/arch/arm/mach-imx/cpufreq.c
@@ -0,0 +1,299 @@
+/*
+ * cpu.c: clock scaling for the iMX
+ *
+ * Copyright (C) 2000 2001, The Delft University of Technology
+ * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
+ * Copyright (C) 2006 Inky Lung <ilung@cwlinux.com>
+ * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
+ *
+ * Based on SA1100 version written by:
+ * - Johan Pouwelse (J.A.Pouwelse@its.tudelft.nl): initial version
+ * - Erik Mouw (J.A.K.Mouw@its.tudelft.nl):
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <asm/system.h>
+
+#include <asm/hardware.h>
+
+#include "generic.h"
+
+#ifndef __val2mfld
+#define __val2mfld(mask,val) (((mask)&~((mask)<<1))*(val)&(mask))
+#endif
+#ifndef __mfld2val
+#define __mfld2val(mask,val) (((val)&(mask))/((mask)&~((mask)<<1)))
+#endif
+
+#define CR_920T_CLOCK_MODE 0xC0000000
+#define CR_920T_FASTBUS_MODE 0x00000000
+#define CR_920T_ASYNC_MODE 0xC0000000
+
+static u32 mpctl0_at_boot;
+
+static void imx_set_async_mode(void)
+{
+ adjust_cr(CR_920T_CLOCK_MODE, CR_920T_ASYNC_MODE);
+}
+
+static void imx_set_fastbus_mode(void)
+{
+ adjust_cr(CR_920T_CLOCK_MODE, CR_920T_FASTBUS_MODE);
+}
+
+static void imx_set_mpctl0(u32 mpctl0)
+{
+ unsigned long flags;
+
+ if (mpctl0 == 0) {
+ local_irq_save(flags);
+ CSCR &= ~CSCR_MPEN;
+ local_irq_restore(flags);
+ return;
+ }
+
+ local_irq_save(flags);
+ MPCTL0 = mpctl0;
+ CSCR |= CSCR_MPEN;
+ local_irq_restore(flags);
+}
+
+/**
+ * imx_compute_mpctl - compute new PLL parameters
+ * @new_mpctl: pointer to location assigned by new PLL control register value
+ * @cur_mpctl: current PLL control register parameters
+ * @freq: required frequency in Hz
+ * @relation: is one of %CPUFREQ_RELATION_L (supremum)
+ * and %CPUFREQ_RELATION_H (infimum)
+ */
+long imx_compute_mpctl(u32 *new_mpctl, u32 cur_mpctl, unsigned long freq, int relation)
+{
+ u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512);
+ u32 mfi;
+ u32 mfn;
+ u32 mfd;
+ u32 pd;
+ unsigned long long ll;
+ long l;
+ long quot;
+
+ /* Fdppl=2*Fref*(MFI+MFN/(MFD+1))/(PD+1) */
+ /* PD=<0,15>, MFD=<1,1023>, MFI=<5,15> MFN=<0,1022> */
+
+ if (cur_mpctl) {
+ mfd = ((cur_mpctl >> 16) & 0x3ff) + 1;
+ pd = ((cur_mpctl >> 26) & 0xf) + 1;
+ } else {
+ pd=2; mfd=313;
+ }
+
+ /* pd=2; mfd=313; mfi=8; mfn=183; */
+ /* (MFI+MFN/(MFD)) = Fdppl / (2*Fref) * (PD); */
+
+ quot = (f_ref + (1 << 9)) >> 10;
+ l = (freq * pd + quot) / (2 * quot);
+ mfi = l >> 10;
+ mfn = ((l & ((1 << 10) - 1)) * mfd + (1 << 9)) >> 10;
+
+ mfd -= 1;
+ pd -= 1;
+
+ *new_mpctl = ((mfi & 0xf) << 10) | (mfn & 0x3ff) | ((mfd & 0x3ff) << 16)
+ | ((pd & 0xf) << 26);
+
+ ll = 2 * (unsigned long long)f_ref * ( (mfi<<16) + (mfn<<16) / (mfd+1) );
+ quot = (pd+1) * (1<<16);
+ ll += quot / 2;
+ do_div(ll, quot);
+ freq = ll;
+
+ pr_debug(KERN_DEBUG "imx: new PLL parameters pd=%d mfd=%d mfi=%d mfn=%d, freq=%ld\n",
+ pd, mfd, mfi, mfn, freq);
+
+ return freq;
+}
+
+
+static int imx_verify_speed(struct cpufreq_policy *policy)
+{
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
+
+ return 0;
+}
+
+static unsigned int imx_get_speed(unsigned int cpu)
+{
+ unsigned int freq;
+ unsigned int cr;
+ unsigned int cscr;
+ unsigned int bclk_div;
+
+ if (cpu)
+ return 0;
+
+ cscr = CSCR;
+ bclk_div = __mfld2val(CSCR_BCLK_DIV, cscr) + 1;
+ cr = get_cr();
+
+ if((cr & CR_920T_CLOCK_MODE) == CR_920T_FASTBUS_MODE) {
+ freq = imx_get_system_clk();
+ freq = (freq + bclk_div/2) / bclk_div;
+ } else {
+ freq = imx_get_mcu_clk();
+ if (cscr & CSCR_MPU_PRESC)
+ freq /= 2;
+ }
+
+ freq = (freq + 500) / 1000;
+
+ return freq;
+}
+
+static int imx_set_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_freqs freqs;
+ u32 mpctl0 = 0;
+ u32 cscr;
+ unsigned long flags;
+ long freq;
+ long sysclk;
+ unsigned int bclk_div = 1;
+
+ /*
+ * Some governors do not respects CPU and policy lower limits
+ * which leads to bad things (division by zero etc), ensure
+ * that such things do not happen.
+ */
+ if(target_freq < policy->cpuinfo.min_freq)
+ target_freq = policy->cpuinfo.min_freq;
+
+ if(target_freq < policy->min)
+ target_freq = policy->min;
+
+ freq = target_freq * 1000;
+
+ pr_debug(KERN_DEBUG "imx: requested frequency %ld Hz, mpctl0 at boot 0x%08x\n",
+ freq, mpctl0_at_boot);
+
+ sysclk = imx_get_system_clk();
+
+ if (freq > sysclk + 1000000) {
+ freq = imx_compute_mpctl(&mpctl0, mpctl0_at_boot, freq, relation);
+ if (freq < 0) {
+ printk(KERN_WARNING "imx: target frequency %ld Hz cannot be set\n", freq);
+ return -EINVAL;
+ }
+ } else {
+ if(freq + 1000 < sysclk) {
+ if (relation == CPUFREQ_RELATION_L)
+ bclk_div = (sysclk - 1000) / freq;
+ else
+ bclk_div = (sysclk + freq + 1000) / freq;
+
+ if(bclk_div > 16)
+ bclk_div = 16;
+ }
+ freq = (sysclk + bclk_div / 2) / bclk_div;
+ }
+
+ freqs.old = imx_get_speed(0);
+ freqs.new = (freq + 500) / 1000;
+ freqs.cpu = 0;
+ freqs.flags = 0;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ local_irq_save(flags);
+
+ imx_set_fastbus_mode();
+
+ imx_set_mpctl0(mpctl0);
+
+ cscr = CSCR;
+ cscr &= ~CSCR_BCLK_DIV;
+ cscr |= __val2mfld(CSCR_BCLK_DIV, bclk_div - 1);
+ CSCR = cscr;
+
+ if(mpctl0) {
+ CSCR |= CSCR_MPLL_RESTART;
+
+ /* Wait until MPLL is stablized */
+ while( CSCR & CSCR_MPLL_RESTART );
+
+ imx_set_async_mode();
+ }
+
+ local_irq_restore(flags);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ pr_debug(KERN_INFO "imx: set frequency %ld Hz, running from %s\n",
+ freq, mpctl0? "MPLL": "SPLL");
+
+ return 0;
+}
+
+static int __init imx_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+ printk(KERN_INFO "i.MX cpu freq change driver v1.0\n");
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->cur = policy->min = policy->max = imx_get_speed(0);
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+ policy->cpuinfo.min_freq = 8000;
+ policy->cpuinfo.max_freq = 200000;
+ /* Manual states, that PLL stabilizes in two CLK32 periods */
+ policy->cpuinfo.transition_latency = 4 * 1000000000LL / CLK32;
+ return 0;
+}
+
+static struct cpufreq_driver imx_driver = {
+ .flags = CPUFREQ_STICKY,
+ .verify = imx_verify_speed,
+ .target = imx_set_target,
+ .get = imx_get_speed,
+ .init = imx_cpufreq_driver_init,
+ .name = "imx",
+};
+
+static int __init imx_cpufreq_init(void)
+{
+
+ mpctl0_at_boot = 0;
+
+ if((CSCR & CSCR_MPEN) &&
+ ((get_cr() & CR_920T_CLOCK_MODE) != CR_920T_FASTBUS_MODE))
+ mpctl0_at_boot = MPCTL0;
+
+ return cpufreq_register_driver(&imx_driver);
+}
+
+arch_initcall(imx_cpufreq_init);
+
diff --git a/arch/arm/mach-iop13xx/io.c b/arch/arm/mach-iop13xx/io.c
index fbf9f88e46e..e79a1b62600 100644
--- a/arch/arm/mach-iop13xx/io.c
+++ b/arch/arm/mach-iop13xx/io.c
@@ -21,6 +21,25 @@
#include <asm/hardware.h>
#include <asm/io.h>
+void * __iomem __iop13xx_io(unsigned long io_addr)
+{
+ void __iomem * io_virt;
+
+ switch (io_addr) {
+ case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
+ io_virt = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(io_addr);
+ break;
+ case IOP13XX_PCIX_LOWER_IO_PA ... IOP13XX_PCIX_UPPER_IO_PA:
+ io_virt = (void *) IOP13XX_PCIX_IO_PHYS_TO_VIRT(io_addr);
+ break;
+ default:
+ BUG();
+ }
+
+ return io_virt;
+}
+EXPORT_SYMBOL(__iop13xx_io);
+
void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
unsigned long flags)
{
diff --git a/arch/arm/mach-iop13xx/iq81340mc.c b/arch/arm/mach-iop13xx/iq81340mc.c
index ee595786cd2..2a1bbfe9896 100644
--- a/arch/arm/mach-iop13xx/iq81340mc.c
+++ b/arch/arm/mach-iop13xx/iq81340mc.c
@@ -88,11 +88,11 @@ static struct sys_timer iq81340mc_timer = {
MACHINE_START(IQ81340MC, "Intel IQ81340MC")
/* Maintainer: Dan Williams <dan.j.williams@intel.com> */
- .phys_io = PHYS_IO,
- .io_pg_offst = IO_PG_OFFSET,
+ .phys_io = IOP13XX_PMMR_PHYS_MEM_BASE,
+ .io_pg_offst = (IOP13XX_PMMR_VIRT_MEM_BASE >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
.map_io = iop13xx_map_io,
.init_irq = iop13xx_init_irq,
.timer = &iq81340mc_timer,
- .boot_params = BOOT_PARAM_OFFSET,
.init_machine = iq81340mc_init,
MACHINE_END
diff --git a/arch/arm/mach-iop13xx/iq81340sc.c b/arch/arm/mach-iop13xx/iq81340sc.c
index 6677e14b61b..5ad2b62c9bf 100644
--- a/arch/arm/mach-iop13xx/iq81340sc.c
+++ b/arch/arm/mach-iop13xx/iq81340sc.c
@@ -90,11 +90,11 @@ static struct sys_timer iq81340sc_timer = {
MACHINE_START(IQ81340SC, "Intel IQ81340SC")
/* Maintainer: Dan Williams <dan.j.williams@intel.com> */
- .phys_io = PHYS_IO,
- .io_pg_offst = IO_PG_OFFSET,
+ .phys_io = IOP13XX_PMMR_PHYS_MEM_BASE,
+ .io_pg_offst = (IOP13XX_PMMR_VIRT_MEM_BASE >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
.map_io = iop13xx_map_io,
.init_irq = iop13xx_init_irq,
.timer = &iq81340sc_timer,
- .boot_params = BOOT_PARAM_OFFSET,
.init_machine = iq81340sc_init,
MACHINE_END
diff --git a/arch/arm/mach-iop13xx/irq.c b/arch/arm/mach-iop13xx/irq.c
index c4d9c8c5579..dbbc07c38b1 100644
--- a/arch/arm/mach-iop13xx/irq.c
+++ b/arch/arm/mach-iop13xx/irq.c
@@ -222,25 +222,29 @@ iop13xx_irq_unmask3(unsigned int irq)
iop13xx_cp6_restore(cp_flags);
}
-static struct irqchip iop13xx_irqchip0 = {
+static struct irq_chip iop13xx_irqchip1 = {
+ .name = "IOP13xx-1",
.ack = iop13xx_irq_mask0,
.mask = iop13xx_irq_mask0,
.unmask = iop13xx_irq_unmask0,
};
-static struct irqchip iop13xx_irqchip1 = {
+static struct irq_chip iop13xx_irqchip2 = {
+ .name = "IOP13xx-2",
.ack = iop13xx_irq_mask1,
.mask = iop13xx_irq_mask1,
.unmask = iop13xx_irq_unmask1,
};
-static struct irqchip iop13xx_irqchip2 = {
+static struct irq_chip iop13xx_irqchip3 = {
+ .name = "IOP13xx-3",
.ack = iop13xx_irq_mask2,
.mask = iop13xx_irq_mask2,
.unmask = iop13xx_irq_unmask2,
};
-static struct irqchip iop13xx_irqchip3 = {
+static struct irq_chip iop13xx_irqchip4 = {
+ .name = "IOP13xx-4",
.ack = iop13xx_irq_mask3,
.mask = iop13xx_irq_mask3,
.unmask = iop13xx_irq_unmask3,
@@ -270,15 +274,15 @@ void __init iop13xx_init_irq(void)
for(i = 0; i < NR_IOP13XX_IRQS; i++) {
if (i < 32)
- set_irq_chip(i, &iop13xx_irqchip0);
- else if (i < 64)
set_irq_chip(i, &iop13xx_irqchip1);
- else if (i < 96)
+ else if (i < 64)
set_irq_chip(i, &iop13xx_irqchip2);
- else
+ else if (i < 96)
set_irq_chip(i, &iop13xx_irqchip3);
+ else
+ set_irq_chip(i, &iop13xx_irqchip4);
- set_irq_handler(i, do_level_IRQ);
+ set_irq_handler(i, handle_level_irq);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
}
diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c
index 3756d2ccb1a..5fbeb28d04b 100644
--- a/arch/arm/mach-iop13xx/setup.c
+++ b/arch/arm/mach-iop13xx/setup.c
@@ -337,7 +337,7 @@ void __init iop13xx_platform_init(void)
#ifdef CONFIG_MTD_PHYSMAP
iq8134x_flash_resource.end = iq8134x_flash_resource.start +
- iq8134x_probe_flash_size();
+ iq8134x_probe_flash_size() - 1;
if (iq8134x_flash_resource.end > iq8134x_flash_resource.start)
iop13xx_devices[plat_idx++] = &iq8134x_flash;
else
diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c
index 0993336c0b5..5773b55ef4a 100644
--- a/arch/arm/mach-netx/time.c
+++ b/arch/arm/mach-netx/time.c
@@ -19,6 +19,8 @@
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clocksource.h>
#include <asm/hardware.h>
#include <asm/io.h>
@@ -26,15 +28,6 @@
#include <asm/arch/netx-regs.h>
/*
- * Returns number of us since last clock interrupt. Note that interrupts
- * will have been disabled by do_gettimeoffset()
- */
-static unsigned long netx_gettimeoffset(void)
-{
- return readl(NETX_GPIO_COUNTER_CURRENT(0)) / 100;
-}
-
-/*
* IRQ handler for the timer
*/
static irqreturn_t
@@ -43,6 +36,7 @@ netx_timer_interrupt(int irq, void *dev_id)
write_seqlock(&xtime_lock);
timer_tick();
+
write_sequnlock(&xtime_lock);
/* acknowledge interrupt */
@@ -51,13 +45,26 @@ netx_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-
static struct irqaction netx_timer_irq = {
.name = "NetX Timer Tick",
.flags = IRQF_DISABLED | IRQF_TIMER,
.handler = netx_timer_interrupt,
};
+cycle_t netx_get_cycles(void)
+{
+ return readl(NETX_GPIO_COUNTER_CURRENT(1));
+}
+
+static struct clocksource clocksource_netx = {
+ .name = "netx_timer",
+ .rating = 200,
+ .read = netx_get_cycles,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 20,
+ .is_continuous = 1,
+};
+
/*
* Set up timer interrupt
*/
@@ -80,9 +87,20 @@ static void __init netx_timer_init(void)
NETX_GPIO_COUNTER_CTRL(0));
setup_irq(NETX_IRQ_TIMER0, &netx_timer_irq);
+
+ /* Setup timer one for clocksource */
+ writel(0, NETX_GPIO_COUNTER_CTRL(1));
+ writel(0, NETX_GPIO_COUNTER_CURRENT(1));
+ writel(0xFFFFFFFF, NETX_GPIO_COUNTER_MAX(1));
+
+ writel(NETX_GPIO_COUNTER_CTRL_RUN,
+ NETX_GPIO_COUNTER_CTRL(1));
+
+ clocksource_netx.mult =
+ clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_netx.shift);
+ clocksource_register(&clocksource_netx);
}
struct sys_timer netx_timer = {
- .init = netx_timer_init,
- .offset = netx_gettimeoffset,
+ .init = netx_timer_init,
};
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index d135568dc9e..8781aaeb576 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -43,6 +43,7 @@ config MACH_OMAP_H3
config MACH_OMAP_OSK
bool "TI OSK Support"
depends on ARCH_OMAP1 && ARCH_OMAP16XX
+ select TPS65010
help
TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
if you have such a board.
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 3a622801d7b..7d0cf7af88c 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -30,6 +30,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
index 03d6905ba49..878ff9181d0 100644
--- a/arch/arm/mach-omap2/board-apollon.c
+++ b/arch/arm/mach-omap2/board-apollon.c
@@ -22,6 +22,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/onenand.h>
+#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index f4f04d87df3..d8f57824423 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -17,6 +17,7 @@
#include <linux/spinlock.h>
#include <asm/io.h>
+#include <asm/mach-types.h>
#include <asm/arch/gpmc.h>
#undef DEBUG
@@ -338,19 +339,13 @@ 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;
+ /* never allocate the first page, to facilitate bug detection;
+ * even if we didn't boot from ROM.
+ */
+ boot_rom_space = BOOT_ROM_SPACE;
+ /* In apollon the CS0 is mapped as 0x0000 0000 */
+ if (machine_is_omap_apollon())
+ boot_rom_space = 0;
gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space;
gpmc_mem_root.end = GPMC_MEM_END;
diff --git a/arch/arm/mach-pnx4008/Makefile b/arch/arm/mach-pnx4008/Makefile
index b457ca0a431..777564c90a1 100644
--- a/arch/arm/mach-pnx4008/Makefile
+++ b/arch/arm/mach-pnx4008/Makefile
@@ -2,7 +2,7 @@
# Makefile for the linux kernel.
#
-obj-y := core.o irq.o time.o clock.o gpio.o serial.o dma.o
+obj-y := core.o irq.o time.o clock.o gpio.o serial.o dma.o i2c.o
obj-m :=
obj-n :=
obj- :=
diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c
new file mode 100644
index 00000000000..6f308827c4f
--- /dev/null
+++ b/arch/arm/mach-pnx4008/i2c.c
@@ -0,0 +1,167 @@
+/*
+ * I2C initialization for PNX4008.
+ *
+ * Author: Vitaly Wool <vitalywool@gmail.com>
+ *
+ * 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/i2c.h>
+#include <linux/i2c-pnx.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <asm/arch/platform.h>
+#include <asm/arch/i2c.h>
+
+static int set_clock_run(struct platform_device *pdev)
+{
+ struct clk *clk;
+ char name[10];
+ int retval = 0;
+
+ snprintf(name, 10, "i2c%d_ck", pdev->id);
+ clk = clk_get(&pdev->dev, name);
+ if (!IS_ERR(clk)) {
+ clk_set_rate(clk, 1);
+ clk_put(clk);
+ } else
+ retval = -ENOENT;
+
+ return retval;
+}
+
+static int set_clock_stop(struct platform_device *pdev)
+{
+ struct clk *clk;
+ char name[10];
+ int retval = 0;
+
+ snprintf(name, 10, "i2c%d_ck", pdev->id);
+ clk = clk_get(&pdev->dev, name);
+ if (!IS_ERR(clk)) {
+ clk_set_rate(clk, 0);
+ clk_put(clk);
+ } else
+ retval = -ENOENT;
+
+ return retval;
+}
+
+static int i2c_pnx_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int retval = 0;
+#ifdef CONFIG_PM
+ retval = set_clock_run(pdev);
+#endif
+ return retval;
+}
+
+static int i2c_pnx_resume(struct platform_device *pdev)
+{
+ int retval = 0;
+#ifdef CONFIG_PM
+ retval = set_clock_run(pdev);
+#endif
+ return retval;
+}
+
+static u32 calculate_input_freq(struct platform_device *pdev)
+{
+ return HCLK_MHZ;
+}
+
+
+static struct i2c_pnx_algo_data pnx_algo_data0 = {
+ .base = PNX4008_I2C1_BASE,
+ .irq = I2C_1_INT,
+};
+
+static struct i2c_pnx_algo_data pnx_algo_data1 = {
+ .base = PNX4008_I2C2_BASE,
+ .irq = I2C_2_INT,
+};
+
+static struct i2c_pnx_algo_data pnx_algo_data2 = {
+ .base = (PNX4008_USB_CONFIG_BASE + 0x300),
+ .irq = USB_I2C_INT,
+};
+
+static struct i2c_adapter pnx_adapter0 = {
+ .name = I2C_CHIP_NAME "0",
+ .algo_data = &pnx_algo_data0,
+};
+static struct i2c_adapter pnx_adapter1 = {
+ .name = I2C_CHIP_NAME "1",
+ .algo_data = &pnx_algo_data1,
+};
+
+static struct i2c_adapter pnx_adapter2 = {
+ .name = "USB-I2C",
+ .algo_data = &pnx_algo_data2,
+};
+
+static struct i2c_pnx_data i2c0_data = {
+ .suspend = i2c_pnx_suspend,
+ .resume = i2c_pnx_resume,
+ .calculate_input_freq = calculate_input_freq,
+ .set_clock_run = set_clock_run,
+ .set_clock_stop = set_clock_stop,
+ .adapter = &pnx_adapter0,
+};
+
+static struct i2c_pnx_data i2c1_data = {
+ .suspend = i2c_pnx_suspend,
+ .resume = i2c_pnx_resume,
+ .calculate_input_freq = calculate_input_freq,
+ .set_clock_run = set_clock_run,
+ .set_clock_stop = set_clock_stop,
+ .adapter = &pnx_adapter1,
+};
+
+static struct i2c_pnx_data i2c2_data = {
+ .suspend = i2c_pnx_suspend,
+ .resume = i2c_pnx_resume,
+ .calculate_input_freq = calculate_input_freq,
+ .set_clock_run = set_clock_run,
+ .set_clock_stop = set_clock_stop,
+ .adapter = &pnx_adapter2,
+};
+
+static struct platform_device i2c0_device = {
+ .name = "pnx-i2c",
+ .id = 0,
+ .dev = {
+ .platform_data = &i2c0_data,
+ },
+};
+
+static struct platform_device i2c1_device = {
+ .name = "pnx-i2c",
+ .id = 1,
+ .dev = {
+ .platform_data = &i2c1_data,
+ },
+};
+
+static struct platform_device i2c2_device = {
+ .name = "pnx-i2c",
+ .id = 2,
+ .dev = {
+ .platform_data = &i2c2_data,
+ },
+};
+
+static struct platform_device *devices[] __initdata = {
+ &i2c0_device,
+ &i2c1_device,
+ &i2c2_device,
+};
+
+void __init pnx4008_register_i2c_devices(void)
+{
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+}
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 9e3d0bdcba0..5c0a10041cd 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -75,28 +75,28 @@ endmenu
config MACH_POODLE
bool "Enable Sharp SL-5600 (Poodle) Support"
- depends PXA_SHARPSL_25x
+ depends on PXA_SHARPSL_25x
select SHARP_LOCOMO
select PXA_SSP
config MACH_CORGI
bool "Enable Sharp SL-C700 (Corgi) Support"
- depends PXA_SHARPSL_25x
+ depends on PXA_SHARPSL_25x
select PXA_SHARP_C7xx
config MACH_SHEPHERD
bool "Enable Sharp SL-C750 (Shepherd) Support"
- depends PXA_SHARPSL_25x
+ depends on PXA_SHARPSL_25x
select PXA_SHARP_C7xx
config MACH_HUSKY
bool "Enable Sharp SL-C760 (Husky) Support"
- depends PXA_SHARPSL_25x
+ depends on PXA_SHARPSL_25x
select PXA_SHARP_C7xx
config MACH_AKITA
bool "Enable Sharp SL-1000 (Akita) Support"
- depends PXA_SHARPSL_27x
+ depends on PXA_SHARPSL_27x
select PXA_SHARP_Cxx00
select MACH_SPITZ
select I2C
@@ -104,17 +104,17 @@ config MACH_AKITA
config MACH_SPITZ
bool "Enable Sharp Zaurus SL-3000 (Spitz) Support"
- depends PXA_SHARPSL_27x
+ depends on PXA_SHARPSL_27x
select PXA_SHARP_Cxx00
config MACH_BORZOI
bool "Enable Sharp Zaurus SL-3100 (Borzoi) Support"
- depends PXA_SHARPSL_27x
+ depends on PXA_SHARPSL_27x
select PXA_SHARP_Cxx00
config MACH_TOSA
bool "Enable Sharp SL-6000x (Tosa) Support"
- depends PXA_SHARPSL_25x
+ depends on PXA_SHARPSL_25x
config PXA25x
bool
diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c
index 4c3de4008a4..165017de8d0 100644
--- a/arch/arm/mach-pxa/corgi_pm.c
+++ b/arch/arm/mach-pxa/corgi_pm.c
@@ -16,7 +16,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <asm/apm.h>
+#include <asm/apm-emulation.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/hardware.h>
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 6ae605857ca..9de1278d234 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -76,7 +76,9 @@ unsigned long long sched_clock(void)
/*
* 96-bit math to perform tick * NSEC_PER_SEC / CLOCK_TICK_RATE for
* any value of CLOCK_TICK_RATE. Max value is in the 80 thousand
- * years range which is nice, but with higher computation cost.
+ * years range and truncation to unsigned long long limits it to
+ * sched_clock's max range of ~584 years. This is nice but with
+ * higher computation cost.
*/
{
union {
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
index db6e8f56a75..b1d8cfca245 100644
--- a/arch/arm/mach-pxa/sharpsl_pm.c
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
@@ -23,7 +23,7 @@
#include <asm/hardware.h>
#include <asm/mach-types.h>
-#include <asm/apm.h>
+#include <asm/apm-emulation.h>
#include <asm/arch/pm.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/sharpsl.h>
diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c
index 40be833079c..b97d543d936 100644
--- a/arch/arm/mach-pxa/spitz_pm.c
+++ b/arch/arm/mach-pxa/spitz_pm.c
@@ -16,7 +16,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <asm/apm.h>
+#include <asm/apm-emulation.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/hardware.h>
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index b9146686102..ee2beb40041 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -18,6 +18,7 @@
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/sched.h>
+#include <linux/clocksource.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -48,27 +49,6 @@ static int pxa_set_rtc(void)
return 0;
}
-/* IRQs are disabled before entering here from do_gettimeofday() */
-static unsigned long pxa_gettimeoffset (void)
-{
- long ticks_to_match, elapsed, usec;
-
- /* Get ticks before next timer match */
- ticks_to_match = OSMR0 - OSCR;
-
- /* We need elapsed ticks since last match */
- elapsed = LATCH - ticks_to_match;
-
- /* don't get fooled by the workaround in pxa_timer_interrupt() */
- if (elapsed <= 0)
- return 0;
-
- /* Now convert them to usec */
- usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
-
- return usec;
-}
-
#ifdef CONFIG_NO_IDLE_HZ
static unsigned long initial_match;
static int match_posponed;
@@ -121,6 +101,20 @@ static struct irqaction pxa_timer_irq = {
.handler = pxa_timer_interrupt,
};
+static cycle_t pxa_get_cycles(void)
+{
+ return OSCR;
+}
+
+static struct clocksource clocksource_pxa = {
+ .name = "pxa_timer",
+ .rating = 200,
+ .read = pxa_get_cycles,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 20,
+ .is_continuous = 1,
+};
+
static void __init pxa_timer_init(void)
{
struct timespec tv;
@@ -139,6 +133,14 @@ static void __init pxa_timer_init(void)
OIER = OIER_E0; /* enable match on timer 0 to cause interrupts */
OSMR0 = OSCR + LATCH; /* set initial match */
local_irq_restore(flags);
+
+ /*
+ * OSCR runs continuously on PXA and is not written to,
+ * so we can use it as clock source directly.
+ */
+ clocksource_pxa.mult =
+ clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_pxa.shift);
+ clocksource_register(&clocksource_pxa);
}
#ifdef CONFIG_NO_IDLE_HZ
@@ -211,7 +213,6 @@ struct sys_timer pxa_timer = {
.init = pxa_timer_init,
.suspend = pxa_timer_suspend,
.resume = pxa_timer_resume,
- .offset = pxa_gettimeoffset,
#ifdef CONFIG_NO_IDLE_HZ
.dyn_tick = &pxa_dyn_tick,
#endif
diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
index c1827d021ba..119c64b7223 100644
--- a/arch/arm/mach-pxa/trizeps4.c
+++ b/arch/arm/mach-pxa/trizeps4.c
@@ -393,10 +393,6 @@ static struct pxafb_mach_info sharp_lcd = {
.pxafb_backlight_power = board_backlight_power,
};
-static void __init trizeps4_fixup(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi)
-{
-}
-
static void __init trizeps4_init(void)
{
platform_add_devices(trizeps4_devices, ARRAY_SIZE(trizeps4_devices));
@@ -469,7 +465,6 @@ MACHINE_START(TRIZEPS4, "Keith und Koep Trizeps IV module")
.phys_io = 0x40000000,
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
.boot_params = TRIZEPS4_SDRAM_BASE + 0x100,
- .fixup = trizeps4_fixup,
.init_machine = trizeps4_init,
.map_io = trizeps4_map_io,
.init_irq = pxa_init_irq,
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 68c67053f47..84d3fe76e94 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -141,6 +141,19 @@ struct platform_device realview_smc91x_device = {
.resource = realview_smc91x_resources,
};
+static struct resource realview_i2c_resource = {
+ .start = REALVIEW_I2C_BASE,
+ .end = REALVIEW_I2C_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+struct platform_device realview_i2c_device = {
+ .name = "versatile-i2c",
+ .id = -1,
+ .num_resources = 1,
+ .resource = &realview_i2c_resource,
+};
+
#define REALVIEW_SYSMCI (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_MCI_OFFSET)
static unsigned int realview_mmc_status(struct device *dev)
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index 93e86d9f439..2b53420f9c1 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -108,6 +108,7 @@ static struct amba_device name##_device = { \
extern struct platform_device realview_flash_device;
extern struct platform_device realview_smc91x_device;
+extern struct platform_device realview_i2c_device;
extern struct mmc_platform_data realview_mmc0_plat_data;
extern struct mmc_platform_data realview_mmc1_plat_data;
extern struct clk realview_clcd_clk;
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 84a959530fb..9741b4d3c9c 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -155,6 +155,7 @@ static void __init realview_eb_init(void)
platform_device_register(&realview_flash_device);
platform_device_register(&realview_smc91x_device);
+ platform_device_register(&realview_i2c_device);
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 9f46bf330bc..eb4ec411312 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -5,6 +5,7 @@ menu "S3C24XX Implementations"
config MACH_AML_M5900
bool "AML M5900 Series"
select CPU_S3C2410
+ select PM_SIMTEC if PM
help
Say Y here if you are using the American Microsystems M5900 Series
<http://www.amltd.com>
@@ -12,6 +13,7 @@ config MACH_AML_M5900
config MACH_ANUBIS
bool "Simtec Electronics ANUBIS"
select CPU_S3C2440
+ select PM_SIMTEC if PM
help
Say Y here if you are using the Simtec Electronics ANUBIS
development system
@@ -19,6 +21,7 @@ config MACH_ANUBIS
config MACH_OSIRIS
bool "Simtec IM2440D20 (OSIRIS) module"
select CPU_S3C2440
+ select PM_SIMTEC if PM
help
Say Y here if you are using the Simtec IM2440D20 module, also
known as the Osiris.
@@ -26,6 +29,7 @@ config MACH_OSIRIS
config ARCH_BAST
bool "Simtec Electronics BAST (EB2410ITX)"
select CPU_S3C2410
+ select PM_SIMTEC if PM
select ISA
help
Say Y here if you are using the Simtec Electronics EB2410ITX
@@ -43,14 +47,13 @@ config BAST_PC104_IRQ
config PM_H1940
bool
- depends on PM
help
Internal node for H1940 and related PM
config ARCH_H1940
bool "IPAQ H1940"
select CPU_S3C2410
- select PM_H1940
+ select PM_H1940 if PM
help
Say Y here if you are using the HP IPAQ H1940
@@ -112,6 +115,7 @@ config MACH_SMDK2413
config MACH_VR1000
bool "Thorcom VR1000"
+ select PM_SIMTEC if PM
select CPU_S3C2410
help
Say Y here if you are using the Thorcom VR1000 board.
@@ -122,7 +126,7 @@ config MACH_VR1000
config MACH_RX3715
bool "HP iPAQ rx3715"
select CPU_S3C2440
- select PM_H1940
+ select PM_H1940 if PM
help
Say Y here if you are using the HP iPAQ rx3715.
@@ -156,7 +160,6 @@ config S3C2410_CLOCK
config S3C2410_PM
bool
- depends on CONFIG_PM
help
Power Management code common to S3C2410 and better
@@ -171,7 +174,7 @@ config CPU_S3C2410
bool
depends on ARCH_S3C2410
select S3C2410_CLOCK
- select S3C2410_PM
+ select S3C2410_PM if PM
help
Support for S3C2410 and S3C2410A family from the S3C24XX line
of Samsung Mobile CPUs.
@@ -186,14 +189,13 @@ config CPU_S3C2412_ONLY
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
+ select S3C2412_PM if PM
help
Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
@@ -207,7 +209,7 @@ config CPU_S3C2440
bool
depends on ARCH_S3C2410
select S3C2410_CLOCK
- select S3C2410_PM
+ select S3C2410_PM if PM
select CPU_S3C244X
help
Support for S3C2440 Samsung Mobile CPU based systems.
@@ -216,7 +218,7 @@ config CPU_S3C2442
bool
depends on ARCH_S3C2420
select S3C2410_CLOCK
- select S3C2410_PM
+ select S3C2410_PM if PM
select CPU_S3C244X
help
Support for S3C2442 Samsung Mobile CPU based systems.
@@ -300,8 +302,9 @@ config S3C2410_PM_CHECK_CHUNKSIZE
config PM_SIMTEC
bool
- depends on PM && (ARCH_BAST || MACH_VR1000 || MACH_AML_M5900)
- default y
+ help
+ Common power management code for systems that are
+ compatible with the Simtec style of power management
config S3C2410_LOWLEVEL_UART_PORT
int "S3C2410 UART to use for low-level messages"
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
index 9d4899eddf1..ae1f5bb63f7 100644
--- a/arch/arm/mach-s3c2410/cpu.c
+++ b/arch/arm/mach-s3c2410/cpu.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <asm/hardware.h>
diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c
index cae35ff76f3..faccde2092d 100644
--- a/arch/arm/mach-s3c2410/devs.c
+++ b/arch/arm/mach-s3c2410/devs.c
@@ -17,6 +17,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
index 01abb0ace23..fa860e716b4 100644
--- a/arch/arm/mach-s3c2410/dma.c
+++ b/arch/arm/mach-s3c2410/dma.c
@@ -1,6 +1,6 @@
/* linux/arch/arm/mach-s3c2410/dma.c
*
- * (c) 2003-2005,2006 Simtec Electronics
+ * Copyright (c) 2003-2005,2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 DMA core
@@ -1053,11 +1053,11 @@ int s3c2410_dma_config(dmach_t channel,
if (chan == NULL)
return -EINVAL;
- printk("Initial dcon is %08x\n", dcon);
+ pr_debug("%s: Initial dcon is %08x\n", __FUNCTION__, dcon);
dcon |= chan->dcon & dma_sel.dcon_mask;
- printk("New dcon is %08x\n", dcon);
+ pr_debug("%s: New dcon is %08x\n", __FUNCTION__, dcon);
switch (xferunit) {
case 1:
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
index ba346546150..f6fb215bb48 100644
--- a/arch/arm/mach-s3c2410/gpio.c
+++ b/arch/arm/mach-s3c2410/gpio.c
@@ -57,6 +57,7 @@ void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
case S3C2410_GPIO_SFN2:
case S3C2410_GPIO_SFN3:
if (pin < S3C2410_GPIO_BANKB) {
+ function -= 1;
function &= 1;
function <<= S3C2410_GPIO_OFFSET(pin);
} else {
@@ -83,15 +84,18 @@ EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
unsigned int s3c2410_gpio_getcfg(unsigned int pin)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
- unsigned long mask;
+ unsigned long val = __raw_readl(base);
if (pin < S3C2410_GPIO_BANKB) {
- mask = 1 << S3C2410_GPIO_OFFSET(pin);
+ val >>= S3C2410_GPIO_OFFSET(pin);
+ val &= 1;
+ val += 1;
} else {
- mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
+ val >>= S3C2410_GPIO_OFFSET(pin)*2;
+ val &= 3;
}
- return __raw_readl(base) & mask;
+ return val | S3C2410_GPIO_INPUT;
}
EXPORT_SYMBOL(s3c2410_gpio_getcfg);
diff --git a/arch/arm/mach-s3c2410/irq.h b/arch/arm/mach-s3c2410/irq.h
index 3686a008224..e5913da3b91 100644
--- a/arch/arm/mach-s3c2410/irq.h
+++ b/arch/arm/mach-s3c2410/irq.h
@@ -8,8 +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:
*/
#define irqdbf(x...)
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c
index e94cdcd9659..0fad0c2fe07 100644
--- a/arch/arm/mach-s3c2410/mach-anubis.c
+++ b/arch/arm/mach-s3c2410/mach-anubis.c
@@ -15,6 +15,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 2968fb235f9..b8b76757ec5 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -16,6 +16,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/dm9000.h>
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index f5b98099a5d..15b625eae49 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -17,6 +17,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
@@ -37,8 +38,6 @@
#include <asm/arch/h1940-latch.h>
#include <asm/arch/fb.h>
-#include <linux/serial_core.h>
-
#include "clock.h"
#include "devs.h"
#include "cpu.h"
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 116ac316996..0411e9adb54 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -20,6 +20,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/kthread.h>
@@ -37,8 +38,6 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/iic.h>
-#include <linux/serial_core.h>
-
#include "s3c2410.h"
#include "clock.h"
#include "devs.h"
diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2410/mach-nexcoder.c
index 065a1d4e860..d6dfdad8c90 100644
--- a/arch/arm/mach-s3c2410/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2410/mach-nexcoder.c
@@ -19,6 +19,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/string.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/mtd/map.h>
diff --git a/arch/arm/mach-s3c2410/mach-osiris.c b/arch/arm/mach-s3c2410/mach-osiris.c
index a4ab144e729..37b40850c9b 100644
--- a/arch/arm/mach-s3c2410/mach-osiris.c
+++ b/arch/arm/mach-s3c2410/mach-osiris.c
@@ -16,6 +16,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/device.h>
+#include <linux/serial_core.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
index c71673fd995..2c738b375e4 100644
--- a/arch/arm/mach-s3c2410/mach-otom.c
+++ b/arch/arm/mach-s3c2410/mach-otom.c
@@ -15,6 +15,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
index b3b0171d505..01c0c986d82 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -35,6 +35,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-s3c2410/mach-smdk2413.c b/arch/arm/mach-s3c2410/mach-smdk2413.c
index 3a4ca7f6f7b..4f89abd7a6d 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2413.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2413.c
@@ -17,6 +17,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c
index e2205ff1b0e..2b61f4ed1da 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2440.c
@@ -19,6 +19,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index e2eda3937ab..a382fc09511 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -352,7 +352,7 @@ static struct platform_device vr1000_led2 = {
static struct platform_device vr1000_led3 = {
.name = "s3c24xx_led",
- .id = 1,
+ .id = 3,
.dev = {
.platform_data = &vr1000_led3_pdata,
},
diff --git a/arch/arm/mach-s3c2410/mach-vstms.c b/arch/arm/mach-s3c2410/mach-vstms.c
index ea554e7c006..0360e1055bc 100644
--- a/arch/arm/mach-s3c2410/mach-vstms.c
+++ b/arch/arm/mach-s3c2410/mach-vstms.c
@@ -15,6 +15,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/mach-s3c2410/pm-simtec.c
index 42cd05e298f..619133eb716 100644
--- a/arch/arm/mach-s3c2410/pm-simtec.c
+++ b/arch/arm/mach-s3c2410/pm-simtec.c
@@ -27,7 +27,6 @@
#include <asm/io.h>
#include <asm/arch/map.h>
-#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-mem.h>
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
index b49a0b3b72b..ebf294dd31d 100644
--- a/arch/arm/mach-s3c2410/pm.c
+++ b/arch/arm/mach-s3c2410/pm.c
@@ -34,6 +34,7 @@
#include <linux/crc32.h>
#include <linux/ioport.h>
#include <linux/delay.h>
+#include <linux/serial_core.h>
#include <asm/cacheflush.h>
#include <asm/hardware.h>
@@ -450,15 +451,14 @@ static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
irqstate = s3c_irqwake_eintmask & (1L<<irqoffs);
pinstate = s3c2410_gpio_getcfg(pin);
- pinstate >>= S3C2410_GPIO_OFFSET(pin)*2;
if (!irqstate) {
- if (pinstate == 0x02)
+ if (pinstate == S3C2410_GPIO_IRQ)
DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin);
} else {
- if (pinstate == 0x02) {
+ if (pinstate == S3C2410_GPIO_IRQ) {
DBG("Disabling IRQ %d (pin %d)\n", irq, pin);
- s3c2410_gpio_cfgpin(pin, 0x00);
+ s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT);
}
}
}
diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c
index 00abe199a08..992cc6af230 100644
--- a/arch/arm/mach-s3c2410/s3c2410-clock.c
+++ b/arch/arm/mach-s3c2410/s3c2410-clock.c
@@ -30,13 +30,18 @@
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/delay.h>
+#include <linux/serial_core.h>
+
+#include <asm/mach/map.h>
#include <asm/hardware.h>
#include <asm/io.h>
+#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
+#include "s3c2410.h"
#include "clock.h"
#include "cpu.h"
diff --git a/arch/arm/mach-s3c2410/s3c2410-dma.c b/arch/arm/mach-s3c2410/s3c2410-dma.c
index 51e5098b32e..e67ba3911f1 100644
--- a/arch/arm/mach-s3c2410/s3c2410-dma.c
+++ b/arch/arm/mach-s3c2410/s3c2410-dma.c
@@ -1,6 +1,6 @@
/* linux/arch/arm/mach-s3c2410/s3c2410-dma.c
*
- * (c) 2006 Simtec Electronics
+ * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 DMA selection
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sysdev.h>
+#include <linux/serial_core.h>
#include <asm/dma.h>
#include <asm/arch/dma.h>
@@ -131,6 +132,7 @@ static int s3c2410_dma_add(struct sys_device *sysdev)
return s3c24xx_dma_init_map(&s3c2410_dma_sel);
}
+#if defined(CONFIG_CPU_S3C2410)
static struct sysdev_driver s3c2410_dma_driver = {
.add = s3c2410_dma_add,
};
@@ -141,9 +143,10 @@ static int __init s3c2410_dma_init(void)
}
arch_initcall(s3c2410_dma_init);
+#endif
+#if defined(CONFIG_CPU_S3C2442)
/* S3C2442 DMA contains the same selection table as the S3C2410 */
-
static struct sysdev_driver s3c2442_dma_driver = {
.add = s3c2410_dma_add,
};
@@ -154,5 +157,5 @@ static int __init s3c2442_dma_init(void)
}
arch_initcall(s3c2442_dma_init);
-
+#endif
diff --git a/arch/arm/mach-s3c2410/s3c2410-pm.c b/arch/arm/mach-s3c2410/s3c2410-pm.c
index 77c6814c0f0..8bb6e5e21f5 100644
--- a/arch/arm/mach-s3c2410/s3c2410-pm.c
+++ b/arch/arm/mach-s3c2410/s3c2410-pm.c
@@ -87,7 +87,7 @@ static void s3c2410_pm_prepare(void)
}
-int s3c2410_pm_resume(struct sys_device *dev)
+static int s3c2410_pm_resume(struct sys_device *dev)
{
unsigned long tmp;
@@ -111,6 +111,7 @@ static int s3c2410_pm_add(struct sys_device *dev)
return 0;
}
+#if defined(CONFIG_CPU_S3C2410)
static struct sysdev_driver s3c2410_pm_driver = {
.add = s3c2410_pm_add,
.resume = s3c2410_pm_resume,
@@ -124,7 +125,9 @@ static int __init s3c2410_pm_drvinit(void)
}
arch_initcall(s3c2410_pm_drvinit);
+#endif
+#if defined(CONFIG_CPU_S3C2440)
static struct sysdev_driver s3c2440_pm_driver = {
.add = s3c2410_pm_add,
.resume = s3c2410_pm_resume,
@@ -136,7 +139,9 @@ static int __init s3c2440_pm_drvinit(void)
}
arch_initcall(s3c2440_pm_drvinit);
+#endif
+#if defined(CONFIG_CPU_S3C2442)
static struct sysdev_driver s3c2442_pm_driver = {
.add = s3c2410_pm_add,
.resume = s3c2410_pm_resume,
@@ -148,3 +153,4 @@ static int __init s3c2442_pm_drvinit(void)
}
arch_initcall(s3c2442_pm_drvinit);
+#endif
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
index 183e4033ce6..4cdc0d70c19 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -17,6 +17,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/sysdev.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
@@ -38,11 +39,9 @@
/* Initial IO mappings */
static struct map_desc s3c2410_iodesc[] __initdata = {
- IODESC_ENT(USBHOST),
IODESC_ENT(CLKPWR),
IODESC_ENT(LCD),
IODESC_ENT(TIMER),
- IODESC_ENT(ADC),
IODESC_ENT(WATCHDOG),
};
diff --git a/arch/arm/mach-s3c2410/s3c2412-clock.c b/arch/arm/mach-s3c2410/s3c2412-clock.c
index c95ed3e1858..8f94ad83901 100644
--- a/arch/arm/mach-s3c2410/s3c2412-clock.c
+++ b/arch/arm/mach-s3c2410/s3c2412-clock.c
@@ -30,13 +30,18 @@
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/delay.h>
+#include <linux/serial_core.h>
+
+#include <asm/mach/map.h>
#include <asm/hardware.h>
#include <asm/io.h>
+#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
+#include "s3c2412.h"
#include "clock.h"
#include "cpu.h"
@@ -49,7 +54,7 @@
* set the correct muxing at initialisation
*/
-int s3c2412_clkcon_enable(struct clk *clk, int enable)
+static int s3c2412_clkcon_enable(struct clk *clk, int enable)
{
unsigned int clocks = clk->ctrlbit;
unsigned long clkcon;
@@ -556,7 +561,7 @@ struct clk_init {
struct clk *src_1;
};
-struct clk_init clks_src[] __initdata = {
+static struct clk_init clks_src[] __initdata = {
{
.clk = &clk_usysclk,
.bit = S3C2412_CLKSRC_USBCLK_HCLK,
@@ -619,7 +624,7 @@ static void __init s3c2412_clk_initparents(void)
/* clocks to add straight away */
-struct clk *clks[] __initdata = {
+static struct clk *clks[] __initdata = {
&clk_ext,
&clk_usb_bus,
&clk_erefclk,
diff --git a/arch/arm/mach-s3c2410/s3c2412-dma.c b/arch/arm/mach-s3c2410/s3c2412-dma.c
index 171f3706d36..138f726ac6b 100644
--- a/arch/arm/mach-s3c2410/s3c2412-dma.c
+++ b/arch/arm/mach-s3c2410/s3c2412-dma.c
@@ -1,6 +1,6 @@
/* linux/arch/arm/mach-s3c2410/s3c2412-dma.c
*
- * (c) 2006 Simtec Electronics
+ * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2412 DMA selection
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sysdev.h>
+#include <linux/serial_core.h>
#include <asm/dma.h>
#include <asm/arch/dma.h>
@@ -132,8 +133,8 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
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);
+ writel(map->channels[0] | S3C2412_DMAREQSEL_HW,
+ chan->regs + S3C2412_DMA_DMAREQSEL);
}
static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = {
diff --git a/arch/arm/mach-s3c2410/s3c2412.c b/arch/arm/mach-s3c2410/s3c2412.c
index e76431c4146..2f651a811ec 100644
--- a/arch/arm/mach-s3c2410/s3c2412.c
+++ b/arch/arm/mach-s3c2410/s3c2412.c
@@ -17,6 +17,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/sysdev.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
@@ -60,7 +61,6 @@ static struct map_desc s3c2412_iodesc[] __initdata = {
IODESC_ENT(CLKPWR),
IODESC_ENT(LCD),
IODESC_ENT(TIMER),
- IODESC_ENT(ADC),
IODESC_ENT(WATCHDOG),
};
diff --git a/arch/arm/mach-s3c2410/s3c2440-clock.c b/arch/arm/mach-s3c2410/s3c2440-clock.c
index 15796864d01..ba13c1d079d 100644
--- a/arch/arm/mach-s3c2410/s3c2440-clock.c
+++ b/arch/arm/mach-s3c2410/s3c2440-clock.c
@@ -113,18 +113,18 @@ static int s3c2440_clk_add(struct sys_device *sysdev)
{
unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
unsigned long clkdivn;
- struct clk *clk_h;
- struct clk *clk_p;
- struct clk *clk_upll;
+ struct clk *clock_h;
+ struct clk *clock_p;
+ struct clk *clock_upll;
printk("S3C2440: Clock Support, DVS %s\n",
(camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
- clk_p = clk_get(NULL, "pclk");
- clk_h = clk_get(NULL, "hclk");
- clk_upll = clk_get(NULL, "upll");
+ clock_p = clk_get(NULL, "pclk");
+ clock_h = clk_get(NULL, "hclk");
+ clock_upll = clk_get(NULL, "upll");
- if (IS_ERR(clk_p) || IS_ERR(clk_h) || IS_ERR(clk_upll)) {
+ if (IS_ERR(clock_p) || IS_ERR(clock_h) || IS_ERR(clock_upll)) {
printk(KERN_ERR "S3C2440: Failed to get parent clocks\n");
return -EINVAL;
}
@@ -132,8 +132,8 @@ static int s3c2440_clk_add(struct sys_device *sysdev)
/* check rate of UPLL, and if it is near 96MHz, then change
* to using half the UPLL rate for the system */
- if (clk_get_rate(clk_upll) > (94 * MHZ)) {
- clk_usb_bus.rate = clk_get_rate(clk_upll) / 2;
+ if (clk_get_rate(clock_upll) > (94 * MHZ)) {
+ clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
mutex_lock(&clocks_mutex);
@@ -144,9 +144,9 @@ static int s3c2440_clk_add(struct sys_device *sysdev)
mutex_unlock(&clocks_mutex);
}
- s3c2440_clk_cam.parent = clk_h;
- s3c2440_clk_ac97.parent = clk_p;
- s3c2440_clk_cam_upll.parent = clk_upll;
+ s3c2440_clk_cam.parent = clock_h;
+ s3c2440_clk_ac97.parent = clock_p;
+ s3c2440_clk_cam_upll.parent = clock_upll;
s3c24xx_register_clock(&s3c2440_clk_ac97);
s3c24xx_register_clock(&s3c2440_clk_cam);
diff --git a/arch/arm/mach-s3c2410/s3c2440-dma.c b/arch/arm/mach-s3c2410/s3c2440-dma.c
index 11e109c84a1..47b861b9443 100644
--- a/arch/arm/mach-s3c2410/s3c2440-dma.c
+++ b/arch/arm/mach-s3c2410/s3c2440-dma.c
@@ -1,6 +1,6 @@
/* linux/arch/arm/mach-s3c2410/s3c2440-dma.c
*
- * (c) 2006 Simtec Electronics
+ * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2440 DMA selection
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sysdev.h>
+#include <linux/serial_core.h>
#include <asm/dma.h>
#include <asm/arch/dma.h>
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c
index 0ab50f44f31..344eb27cca4 100644
--- a/arch/arm/mach-s3c2410/s3c2440.c
+++ b/arch/arm/mach-s3c2410/s3c2440.c
@@ -17,6 +17,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/serial_core.h>
#include <linux/sysdev.h>
#include <linux/clk.h>
@@ -28,17 +29,9 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-serial.h>
-#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-gpioj.h>
-#include <asm/arch/regs-dsc.h>
-
#include "s3c2440.h"
-#include "clock.h"
#include "devs.h"
#include "cpu.h"
-#include "pm.h"
static struct sys_device s3c2440_sysdev = {
.cls = &s3c2440_sysclass,
diff --git a/arch/arm/mach-s3c2410/s3c2440.h b/arch/arm/mach-s3c2410/s3c2440.h
index 29cb6df65a4..dcd316076c5 100644
--- a/arch/arm/mach-s3c2410/s3c2440.h
+++ b/arch/arm/mach-s3c2410/s3c2440.h
@@ -8,28 +8,10 @@
* 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:
- * 24-Aug-2004 BJD Start of S3C2440 CPU support
- * 04-Nov-2004 BJD Added s3c2440_init_uarts()
- * 04-Jan-2005 BJD Moved uart init to cpu code
- * 10-Jan-2005 BJD Moved 2440 specific init here
- * 14-Jan-2005 BJD Split the clock initialisation code
*/
#ifdef CONFIG_CPU_S3C2440
-
extern int s3c2440_init(void);
-
-extern void s3c2440_map_io(struct map_desc *mach_desc, int size);
-
-extern void s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no);
-
-extern void s3c2440_init_clocks(int xtal);
-
#else
-#define s3c2440_init_clocks NULL
-#define s3c2440_init_uarts NULL
-#define s3c2440_map_io NULL
#define s3c2440_init NULL
#endif
diff --git a/arch/arm/mach-s3c2410/s3c2442-clock.c b/arch/arm/mach-s3c2410/s3c2442-clock.c
index d9f54b5cab7..4e292ca7c9b 100644
--- a/arch/arm/mach-s3c2410/s3c2442-clock.c
+++ b/arch/arm/mach-s3c2410/s3c2442-clock.c
@@ -117,18 +117,18 @@ static int s3c2442_clk_add(struct sys_device *sysdev)
{
unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
unsigned long clkdivn;
- struct clk *clk_h;
- struct clk *clk_p;
- struct clk *clk_upll;
+ struct clk *clock_h;
+ struct clk *clock_p;
+ struct clk *clock_upll;
printk("S3C2442: Clock Support, DVS %s\n",
(camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
- clk_p = clk_get(NULL, "pclk");
- clk_h = clk_get(NULL, "hclk");
- clk_upll = clk_get(NULL, "upll");
+ clock_p = clk_get(NULL, "pclk");
+ clock_h = clk_get(NULL, "hclk");
+ clock_upll = clk_get(NULL, "upll");
- if (IS_ERR(clk_p) || IS_ERR(clk_h) || IS_ERR(clk_upll)) {
+ if (IS_ERR(clock_p) || IS_ERR(clock_h) || IS_ERR(clock_upll)) {
printk(KERN_ERR "S3C2442: Failed to get parent clocks\n");
return -EINVAL;
}
@@ -136,8 +136,8 @@ static int s3c2442_clk_add(struct sys_device *sysdev)
/* check rate of UPLL, and if it is near 96MHz, then change
* to using half the UPLL rate for the system */
- if (clk_get_rate(clk_upll) > (94 * MHZ)) {
- clk_usb_bus.rate = clk_get_rate(clk_upll) / 2;
+ if (clk_get_rate(clock_upll) > (94 * MHZ)) {
+ clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
mutex_lock(&clocks_mutex);
@@ -148,8 +148,8 @@ static int s3c2442_clk_add(struct sys_device *sysdev)
mutex_unlock(&clocks_mutex);
}
- s3c2442_clk_cam.parent = clk_h;
- s3c2442_clk_cam_upll.parent = clk_upll;
+ s3c2442_clk_cam.parent = clock_h;
+ s3c2442_clk_cam_upll.parent = clock_upll;
s3c24xx_register_clock(&s3c2442_clk_cam);
s3c24xx_register_clock(&s3c2442_clk_cam_upll);
diff --git a/arch/arm/mach-s3c2410/s3c2442.c b/arch/arm/mach-s3c2410/s3c2442.c
index 581667efd13..428732ee68c 100644
--- a/arch/arm/mach-s3c2410/s3c2442.c
+++ b/arch/arm/mach-s3c2410/s3c2442.c
@@ -16,29 +16,11 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
-#include <linux/platform_device.h>
+#include <linux/serial_core.h>
#include <linux/sysdev.h>
-#include <linux/clk.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-serial.h>
-#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-gpioj.h>
-#include <asm/arch/regs-dsc.h>
#include "s3c2442.h"
-#include "clock.h"
-#include "devs.h"
#include "cpu.h"
-#include "pm.h"
static struct sys_device s3c2442_sysdev = {
.cls = &s3c2442_sysclass,
diff --git a/arch/arm/mach-s3c2410/s3c244x.c b/arch/arm/mach-s3c2410/s3c244x.c
index 9a2258270de..23c7494ad10 100644
--- a/arch/arm/mach-s3c2410/s3c244x.c
+++ b/arch/arm/mach-s3c2410/s3c244x.c
@@ -16,6 +16,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/sysdev.h>
#include <linux/clk.h>
@@ -47,8 +48,6 @@ static struct map_desc s3c244x_iodesc[] __initdata = {
IODESC_ENT(TIMER),
IODESC_ENT(WATCHDOG),
IODESC_ENT(LCD),
- IODESC_ENT(ADC),
- IODESC_ENT(USBHOST),
};
/* uart initialisation */
diff --git a/arch/arm/mach-s3c2410/usb-simtec.h b/arch/arm/mach-s3c2410/usb-simtec.h
index d8aa6127ded..03842ede9e7 100644
--- a/arch/arm/mach-s3c2410/usb-simtec.h
+++ b/arch/arm/mach-s3c2410/usb-simtec.h
@@ -10,9 +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:
- * 20-Aug-2004 BJD Created
*/
extern int usb_simtec_init(void);
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index 17f5a43acdb..54ecdaa373d 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -1,5 +1,15 @@
/*
* linux/arch/arm/mach-sa1100/jornada720.c
+ *
+ * HP Jornada720 init code
+ *
+ * Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
+ * Copyright (C) 2005 Michael Gernoth <michael@gernoth.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.
+ *
*/
#include <linux/init.h>
@@ -10,13 +20,13 @@
#include <linux/ioport.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <video/s1d13xxxfb.h>
#include <asm/hardware.h>
#include <asm/hardware/sa1111.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/setup.h>
-
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
@@ -24,13 +34,170 @@
#include "generic.h"
+/*
+ * HP Documentation referred in this file:
+ * http://www.jlime.com/downloads/development/docs/jornada7xx/jornada720.txt
+ */
+
+/* line 110 of HP's doc */
+#define TUCR_VAL 0x20000400
+
+/* memory space (line 52 of HP's doc) */
+#define SA1111REGSTART 0x40000000
+#define SA1111REGLEN 0x00001fff
+#define EPSONREGSTART 0x48000000
+#define EPSONREGLEN 0x00100000
+#define EPSONFBSTART 0x48200000
+/* 512kB framebuffer */
+#define EPSONFBLEN 512*1024
+
+static struct s1d13xxxfb_regval s1d13xxxfb_initregs[] = {
+ /* line 344 of HP's doc */
+ {0x0001,0x00}, // Miscellaneous Register
+ {0x01FC,0x00}, // Display Mode Register
+ {0x0004,0x00}, // General IO Pins Configuration Register 0
+ {0x0005,0x00}, // General IO Pins Configuration Register 1
+ {0x0008,0x00}, // General IO Pins Control Register 0
+ {0x0009,0x00}, // General IO Pins Control Register 1
+ {0x0010,0x01}, // Memory Clock Configuration Register
+ {0x0014,0x11}, // LCD Pixel Clock Configuration Register
+ {0x0018,0x01}, // CRT/TV Pixel Clock Configuration Register
+ {0x001C,0x01}, // MediaPlug Clock Configuration Register
+ {0x001E,0x01}, // CPU To Memory Wait State Select Register
+ {0x0020,0x00}, // Memory Configuration Register
+ {0x0021,0x45}, // DRAM Refresh Rate Register
+ {0x002A,0x01}, // DRAM Timings Control Register 0
+ {0x002B,0x03}, // DRAM Timings Control Register 1
+ {0x0030,0x1c}, // Panel Type Register
+ {0x0031,0x00}, // MOD Rate Register
+ {0x0032,0x4F}, // LCD Horizontal Display Width Register
+ {0x0034,0x07}, // LCD Horizontal Non-Display Period Register
+ {0x0035,0x01}, // TFT FPLINE Start Position Register
+ {0x0036,0x0B}, // TFT FPLINE Pulse Width Register
+ {0x0038,0xEF}, // LCD Vertical Display Height Register 0
+ {0x0039,0x00}, // LCD Vertical Display Height Register 1
+ {0x003A,0x13}, // LCD Vertical Non-Display Period Register
+ {0x003B,0x0B}, // TFT FPFRAME Start Position Register
+ {0x003C,0x01}, // TFT FPFRAME Pulse Width Register
+ {0x0040,0x05}, // LCD Display Mode Register (2:4bpp,3:8bpp,5:16bpp)
+ {0x0041,0x00}, // LCD Miscellaneous Register
+ {0x0042,0x00}, // LCD Display Start Address Register 0
+ {0x0043,0x00}, // LCD Display Start Address Register 1
+ {0x0044,0x00}, // LCD Display Start Address Register 2
+ {0x0046,0x80}, // LCD Memory Address Offset Register 0
+ {0x0047,0x02}, // LCD Memory Address Offset Register 1
+ {0x0048,0x00}, // LCD Pixel Panning Register
+ {0x004A,0x00}, // LCD Display FIFO High Threshold Control Register
+ {0x004B,0x00}, // LCD Display FIFO Low Threshold Control Register
+ {0x0050,0x4F}, // CRT/TV Horizontal Display Width Register
+ {0x0052,0x13}, // CRT/TV Horizontal Non-Display Period Register
+ {0x0053,0x01}, // CRT/TV HRTC Start Position Register
+ {0x0054,0x0B}, // CRT/TV HRTC Pulse Width Register
+ {0x0056,0xDF}, // CRT/TV Vertical Display Height Register 0
+ {0x0057,0x01}, // CRT/TV Vertical Display Height Register 1
+ {0x0058,0x2B}, // CRT/TV Vertical Non-Display Period Register
+ {0x0059,0x09}, // CRT/TV VRTC Start Position Register
+ {0x005A,0x01}, // CRT/TV VRTC Pulse Width Register
+ {0x005B,0x10}, // TV Output Control Register
+ {0x0060,0x03}, // CRT/TV Display Mode Register (2:4bpp,3:8bpp,5:16bpp)
+ {0x0062,0x00}, // CRT/TV Display Start Address Register 0
+ {0x0063,0x00}, // CRT/TV Display Start Address Register 1
+ {0x0064,0x00}, // CRT/TV Display Start Address Register 2
+ {0x0066,0x40}, // CRT/TV Memory Address Offset Register 0
+ {0x0067,0x01}, // CRT/TV Memory Address Offset Register 1
+ {0x0068,0x00}, // CRT/TV Pixel Panning Register
+ {0x006A,0x00}, // CRT/TV Display FIFO High Threshold Control Register
+ {0x006B,0x00}, // CRT/TV Display FIFO Low Threshold Control Register
+ {0x0070,0x00}, // LCD Ink/Cursor Control Register
+ {0x0071,0x01}, // LCD Ink/Cursor Start Address Register
+ {0x0072,0x00}, // LCD Cursor X Position Register 0
+ {0x0073,0x00}, // LCD Cursor X Position Register 1
+ {0x0074,0x00}, // LCD Cursor Y Position Register 0
+ {0x0075,0x00}, // LCD Cursor Y Position Register 1
+ {0x0076,0x00}, // LCD Ink/Cursor Blue Color 0 Register
+ {0x0077,0x00}, // LCD Ink/Cursor Green Color 0 Register
+ {0x0078,0x00}, // LCD Ink/Cursor Red Color 0 Register
+ {0x007A,0x1F}, // LCD Ink/Cursor Blue Color 1 Register
+ {0x007B,0x3F}, // LCD Ink/Cursor Green Color 1 Register
+ {0x007C,0x1F}, // LCD Ink/Cursor Red Color 1 Register
+ {0x007E,0x00}, // LCD Ink/Cursor FIFO Threshold Register
+ {0x0080,0x00}, // CRT/TV Ink/Cursor Control Register
+ {0x0081,0x01}, // CRT/TV Ink/Cursor Start Address Register
+ {0x0082,0x00}, // CRT/TV Cursor X Position Register 0
+ {0x0083,0x00}, // CRT/TV Cursor X Position Register 1
+ {0x0084,0x00}, // CRT/TV Cursor Y Position Register 0
+ {0x0085,0x00}, // CRT/TV Cursor Y Position Register 1
+ {0x0086,0x00}, // CRT/TV Ink/Cursor Blue Color 0 Register
+ {0x0087,0x00}, // CRT/TV Ink/Cursor Green Color 0 Register
+ {0x0088,0x00}, // CRT/TV Ink/Cursor Red Color 0 Register
+ {0x008A,0x1F}, // CRT/TV Ink/Cursor Blue Color 1 Register
+ {0x008B,0x3F}, // CRT/TV Ink/Cursor Green Color 1 Register
+ {0x008C,0x1F}, // CRT/TV Ink/Cursor Red Color 1 Register
+ {0x008E,0x00}, // CRT/TV Ink/Cursor FIFO Threshold Register
+ {0x0100,0x00}, // BitBlt Control Register 0
+ {0x0101,0x00}, // BitBlt Control Register 1
+ {0x0102,0x00}, // BitBlt ROP Code/Color Expansion Register
+ {0x0103,0x00}, // BitBlt Operation Register
+ {0x0104,0x00}, // BitBlt Source Start Address Register 0
+ {0x0105,0x00}, // BitBlt Source Start Address Register 1
+ {0x0106,0x00}, // BitBlt Source Start Address Register 2
+ {0x0108,0x00}, // BitBlt Destination Start Address Register 0
+ {0x0109,0x00}, // BitBlt Destination Start Address Register 1
+ {0x010A,0x00}, // BitBlt Destination Start Address Register 2
+ {0x010C,0x00}, // BitBlt Memory Address Offset Register 0
+ {0x010D,0x00}, // BitBlt Memory Address Offset Register 1
+ {0x0110,0x00}, // BitBlt Width Register 0
+ {0x0111,0x00}, // BitBlt Width Register 1
+ {0x0112,0x00}, // BitBlt Height Register 0
+ {0x0113,0x00}, // BitBlt Height Register 1
+ {0x0114,0x00}, // BitBlt Background Color Register 0
+ {0x0115,0x00}, // BitBlt Background Color Register 1
+ {0x0118,0x00}, // BitBlt Foreground Color Register 0
+ {0x0119,0x00}, // BitBlt Foreground Color Register 1
+ {0x01E0,0x00}, // Look-Up Table Mode Register
+ {0x01E2,0x00}, // Look-Up Table Address Register
+ /* not sure, wouldn't like to mess with the driver */
+ {0x01E4,0x00}, // Look-Up Table Data Register
+ /* jornada doc says 0x00, but I trust the driver */
+ {0x01F0,0x10}, // Power Save Configuration Register
+ {0x01F1,0x00}, // Power Save Status Register
+ {0x01F4,0x00}, // CPU-to-Memory Access Watchdog Timer Register
+ {0x01FC,0x01}, // Display Mode Register(0x01:LCD, 0x02:CRT, 0x03:LCD&CRT)
+};
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+ .initregs = s1d13xxxfb_initregs,
+ .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
+ .platform_init_video = NULL
+};
-#define JORTUCR_VAL 0x20000400
+static struct resource s1d13xxxfb_resources[] = {
+ [0] = {
+ .start = EPSONFBSTART,
+ .end = EPSONFBSTART + EPSONFBLEN,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = EPSONREGSTART,
+ .end = EPSONREGSTART + EPSONREGLEN,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device s1d13xxxfb_device = {
+ .name = S1D_DEVICENAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &s1d13xxxfb_data,
+ },
+ .num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
+ .resource = s1d13xxxfb_resources,
+};
static struct resource sa1111_resources[] = {
[0] = {
- .start = 0x40000000,
- .end = 0x40001fff,
+ .start = SA1111REGSTART,
+ .end = SA1111REGSTART + SA1111REGLEN,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -53,18 +220,32 @@ static struct platform_device sa1111_device = {
.resource = sa1111_resources,
};
+static struct platform_device jornada720_mcu_device = {
+ .name = "jornada720_mcu",
+ .id = -1,
+};
+
static struct platform_device *devices[] __initdata = {
&sa1111_device,
+ &jornada720_mcu_device,
+ &s1d13xxxfb_device,
};
+/* a stub for now, we theoretically cannot suspend without a flashboard */
+int pm_suspend(suspend_state_t state)
+{
+ return -1;
+}
+
static int __init jornada720_init(void)
{
int ret = -ENODEV;
if (machine_is_jornada720()) {
GPDR |= GPIO_GPIO20;
- TUCR = JORTUCR_VAL; /* set the oscillator out to the SA-1101 */
-
+ /* oscillator setup (line 116 of HP's doc) */
+ TUCR = TUCR_VAL;
+ /* resetting SA1111 (line 118 of HP's doc) */
GPSR = GPIO_GPIO20;
udelay(1);
GPCR = GPIO_GPIO20;
@@ -72,10 +253,6 @@ static int __init jornada720_init(void)
GPSR = GPIO_GPIO20;
udelay(20);
- /* LDD4 is speaker, LDD3 is microphone */
- PPSR &= ~(PPC_LDD3 | PPC_LDD4);
- PPDR |= PPC_LDD3 | PPC_LDD4;
-
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
return ret;
@@ -85,19 +262,19 @@ arch_initcall(jornada720_init);
static struct map_desc jornada720_io_desc[] __initdata = {
{ /* Epson registers */
- .virtual = 0xf0000000,
- .pfn = __phys_to_pfn(0x48000000),
- .length = 0x00100000,
+ .virtual = 0xf0000000,
+ .pfn = __phys_to_pfn(EPSONREGSTART),
+ .length = EPSONREGLEN,
.type = MT_DEVICE
}, { /* Epson frame buffer */
- .virtual = 0xf1000000,
- .pfn = __phys_to_pfn(0x48200000),
- .length = 0x00100000,
+ .virtual = 0xf1000000,
+ .pfn = __phys_to_pfn(EPSONFBSTART),
+ .length = EPSONFBLEN,
.type = MT_DEVICE
}, { /* SA-1111 */
- .virtual = 0xf4000000,
- .pfn = __phys_to_pfn(0x40000000),
- .length = 0x00100000,
+ .virtual = 0xf4000000,
+ .pfn = __phys_to_pfn(SA1111REGSTART),
+ .length = SA1111REGLEN,
.type = MT_DEVICE
}
};
@@ -106,7 +283,7 @@ static void __init jornada720_map_io(void)
{
sa1100_map_io();
iotable_init(jornada720_io_desc, ARRAY_SIZE(jornada720_io_desc));
-
+
sa1100_register_uart(0, 3);
sa1100_register_uart(1, 1);
}
@@ -116,7 +293,7 @@ static struct mtd_partition jornada720_partitions[] = {
.name = "JORNADA720 boot firmware",
.size = 0x00040000,
.offset = 0,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
.name = "JORNADA720 kernel",
.size = 0x000c0000,
@@ -139,7 +316,7 @@ static struct mtd_partition jornada720_partitions[] = {
.offset = 0x00540000,
}, {
.name = "JORNADA720 usr local",
- .size = 0, /* will expand to the end of the flash */
+ .size = 0, /* will expand to the end of the flash */
.offset = 0x00d00000,
}
};
@@ -147,10 +324,12 @@ static struct mtd_partition jornada720_partitions[] = {
static void jornada720_set_vpp(int vpp)
{
if (vpp)
- PPSR |= 0x80;
+ /* enabling flash write (line 470 of HP's doc) */
+ PPSR |= PPC_LDD7;
else
- PPSR &= ~0x80;
- PPDR |= 0x80;
+ /* disabling flash write (line 470 of HP's doc) */
+ PPSR &= ~PPC_LDD7;
+ PPDR |= PPC_LDD7;
}
static struct flash_platform_data jornada720_flash_data = {
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 57196947559..bf71507c76f 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -325,6 +325,19 @@ static struct platform_device smc91x_device = {
.resource = smc91x_resources,
};
+static struct resource versatile_i2c_resource = {
+ .start = VERSATILE_I2C_BASE,
+ .end = VERSATILE_I2C_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device versatile_i2c_device = {
+ .name = "versatile-i2c",
+ .id = -1,
+ .num_resources = 1,
+ .resource = &versatile_i2c_resource,
+};
+
#define VERSATILE_SYSMCI (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_MCI_OFFSET)
unsigned int mmc_status(struct device *dev)
@@ -775,6 +788,7 @@ void __init versatile_init(void)
clk_register(&versatile_clcd_clk);
platform_device_register(&versatile_flash_device);
+ platform_device_register(&versatile_i2c_device);
platform_device_register(&smc91x_device);
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
index b797217e82b..6a9c362fef5 100644
--- a/arch/arm/mm/consistent.c
+++ b/arch/arm/mm/consistent.c
@@ -238,7 +238,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
* x86 does not mark the pages reserved...
*/
SetPageReserved(page);
- set_pte(pte, mk_pte(page, prot));
+ set_pte_ext(pte, mk_pte(page, prot), 0);
page++;
pte++;
off++;
diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c
index df1645e14b4..ded0e96d069 100644
--- a/arch/arm/mm/copypage-v4mc.c
+++ b/arch/arm/mm/copypage-v4mc.c
@@ -19,6 +19,7 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
#include "mm.h"
@@ -69,9 +70,14 @@ mc_copy_user_page(void *from, void *to)
void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
{
+ struct page *page = virt_to_page(kfrom);
+
+ if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
+ __flush_dcache_page(page_mapping(page), page);
+
spin_lock(&minicache_lock);
- set_pte(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot));
+ set_pte_ext(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot), 0);
flush_tlb_kernel_page(0xffff8000);
mc_copy_user_page((void *)0xffff8000, kto);
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
index 3d0d3a963d2..3adb79257f4 100644
--- a/arch/arm/mm/copypage-v6.c
+++ b/arch/arm/mm/copypage-v6.c
@@ -53,6 +53,10 @@ static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned lo
{
unsigned int offset = CACHE_COLOUR(vaddr);
unsigned long from, to;
+ struct page *page = virt_to_page(kfrom);
+
+ if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
+ __flush_dcache_page(page_mapping(page), page);
/*
* Discard data in the kernel mapping for the new page.
@@ -70,8 +74,8 @@ static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned lo
*/
spin_lock(&v6_lock);
- set_pte(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, PAGE_KERNEL));
- set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, PAGE_KERNEL));
+ set_pte_ext(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, PAGE_KERNEL), 0);
+ set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, PAGE_KERNEL), 0);
from = from_address + (offset << PAGE_SHIFT);
to = to_address + (offset << PAGE_SHIFT);
@@ -110,7 +114,7 @@ static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
*/
spin_lock(&v6_lock);
- set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, PAGE_KERNEL));
+ set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, PAGE_KERNEL), 0);
flush_tlb_kernel_page(to);
clear_page((void *)to);
diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c
index 84ebe0aa379..2e455f82a4d 100644
--- a/arch/arm/mm/copypage-xscale.c
+++ b/arch/arm/mm/copypage-xscale.c
@@ -19,6 +19,7 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
#include "mm.h"
@@ -91,9 +92,14 @@ mc_copy_user_page(void *from, void *to)
void xscale_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
{
+ struct page *page = virt_to_page(kfrom);
+
+ if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
+ __flush_dcache_page(page_mapping(page), page);
+
spin_lock(&minicache_lock);
- set_pte(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot));
+ set_pte_ext(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot), 0);
flush_tlb_kernel_page(COPYPAGE_MINICACHE);
mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto);
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index 7fc1b35a674..cf95c5d0ce4 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -61,7 +61,7 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address)
if (pte_present(entry) && pte_val(entry) & shared_pte_mask) {
flush_cache_page(vma, address, pte_pfn(entry));
pte_val(entry) &= ~shared_pte_mask;
- set_pte(pte, entry);
+ set_pte_at(vma->vm_mm, address, pte, entry);
flush_tlb_page(vma, address);
ret = 1;
}
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 454205b789d..9df507d36e0 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -26,7 +26,7 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
const int zero = 0;
- set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL));
+ set_pte_ext(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL), 0);
flush_tlb_kernel_page(to);
asm( "mcrr p15, 0, %1, %0, c14\n"
@@ -202,3 +202,42 @@ void flush_dcache_page(struct page *page)
}
}
EXPORT_SYMBOL(flush_dcache_page);
+
+/*
+ * Flush an anonymous page so that users of get_user_pages()
+ * can safely access the data. The expected sequence is:
+ *
+ * get_user_pages()
+ * -> flush_anon_page
+ * memcpy() to/from page
+ * if written to page, flush_dcache_page()
+ */
+void __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
+{
+ unsigned long pfn;
+
+ /* VIPT non-aliasing caches need do nothing */
+ if (cache_is_vipt_nonaliasing())
+ return;
+
+ /*
+ * Write back and invalidate userspace mapping.
+ */
+ pfn = page_to_pfn(page);
+ if (cache_is_vivt()) {
+ flush_cache_page(vma, vmaddr, pfn);
+ } else {
+ /*
+ * For aliasing VIPT, we can flush an alias of the
+ * userspace address only.
+ */
+ flush_pfn_alias(pfn, vmaddr);
+ }
+
+ /*
+ * Invalidate kernel mapping. No data should be contained
+ * in this mapping of the page. FIXME: this is overkill
+ * since we actually ask for a write-back and invalidate.
+ */
+ __cpuc_flush_dcache_page(page_address(page));
+}
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index b5814b4b6f3..7760193e74c 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -52,15 +52,18 @@ void show_mem(void)
printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
for_each_online_node(node) {
+ pg_data_t *n = NODE_DATA(node);
+ struct page *map = n->node_mem_map - n->node_start_pfn;
+
for_each_nodebank (i,mi,node) {
unsigned int pfn1, pfn2;
struct page *page, *end;
- pfn1 = mi->bank[i].start >> PAGE_SHIFT;
- pfn2 = (mi->bank[i].size + mi->bank[i].start) >> PAGE_SHIFT;
+ pfn1 = __phys_to_pfn(mi->bank[i].start);
+ pfn2 = __phys_to_pfn(mi->bank[i].size + mi->bank[i].start);
- page = NODE_MEM_MAP(node) + pfn1;
- end = NODE_MEM_MAP(node) + pfn2;
+ page = map + pfn1;
+ end = map + pfn2;
do {
total++;
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 46544059279..0ac615c0f79 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -38,89 +38,71 @@
*/
#define VM_ARM_SECTION_MAPPING 0x80000000
-static inline void
-remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, pgprot_t pgprot)
+static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end,
+ unsigned long phys_addr, pgprot_t prot)
{
- unsigned long end;
+ pte_t *pte;
+
+ pte = pte_alloc_kernel(pmd, addr);
+ if (!pte)
+ return -ENOMEM;
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- BUG_ON(address >= end);
do {
if (!pte_none(*pte))
goto bad;
- set_pte(pte, pfn_pte(phys_addr >> PAGE_SHIFT, pgprot));
- address += PAGE_SIZE;
+ set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot), 0);
phys_addr += PAGE_SIZE;
- pte++;
- } while (address && (address < end));
- return;
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+ return 0;
bad:
- printk("remap_area_pte: page already exists\n");
+ printk(KERN_CRIT "remap_area_pte: page already exists\n");
BUG();
}
-static inline int
-remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
+static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr,
+ unsigned long end, unsigned long phys_addr,
+ pgprot_t prot)
{
- unsigned long end;
- pgprot_t pgprot;
-
- address &= ~PGDIR_MASK;
- end = address + size;
-
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
+ unsigned long next;
+ pmd_t *pmd;
+ int ret = 0;
- phys_addr -= address;
- BUG_ON(address >= end);
+ pmd = pmd_alloc(&init_mm, pgd, addr);
+ if (!pmd)
+ return -ENOMEM;
- pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags);
do {
- pte_t * pte = pte_alloc_kernel(pmd, address);
- if (!pte)
- return -ENOMEM;
- remap_area_pte(pte, address, end - address, address + phys_addr, pgprot);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
+ next = pmd_addr_end(addr, end);
+ ret = remap_area_pte(pmd, addr, next, phys_addr, prot);
+ if (ret)
+ return ret;
+ phys_addr += next - addr;
+ } while (pmd++, addr = next, addr != end);
+ return ret;
}
-static int
-remap_area_pages(unsigned long start, unsigned long pfn,
- unsigned long size, unsigned long flags)
+static int remap_area_pages(unsigned long start, unsigned long pfn,
+ unsigned long size, unsigned long flags)
{
- unsigned long address = start;
- unsigned long end = start + size;
+ unsigned long addr = start;
+ unsigned long next, end = start + size;
unsigned long phys_addr = __pfn_to_phys(pfn);
+ pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
+ L_PTE_DIRTY | L_PTE_WRITE | flags);
+ pgd_t *pgd;
int err = 0;
- pgd_t * dir;
- phys_addr -= address;
- dir = pgd_offset(&init_mm, address);
- BUG_ON(address >= end);
+ BUG_ON(addr >= end);
+ pgd = pgd_offset_k(addr);
do {
- pmd_t *pmd = pmd_alloc(&init_mm, dir, address);
- if (!pmd) {
- err = -ENOMEM;
- break;
- }
- if (remap_area_pmd(pmd, address, end - address,
- phys_addr + address, flags)) {
- err = -ENOMEM;
+ next = pgd_addr_end(addr, end);
+ err = remap_area_pmd(pgd, addr, next, phys_addr, prot);
+ if (err)
break;
- }
-
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
+ phys_addr += next - addr;
+ } while (pgd++, addr = next, addr != end);
return err;
}
@@ -310,13 +292,16 @@ __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK))
return NULL;
+ size = PAGE_ALIGN(size);
+
area = get_vm_area(size, VM_IOREMAP);
if (!area)
return NULL;
addr = (unsigned long)area->addr;
#ifndef CONFIG_SMP
- if ((((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) ||
+ if (DOMAIN_IO == 0 &&
+ (((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) ||
cpu_is_xsc3()) &&
!((__pfn_to_phys(pfn) | size | addr) & ~SUPERSECTION_MASK)) {
area->flags |= VM_ARM_SECTION_MAPPING;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index b7f194af20b..655c8376f0b 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -154,6 +154,26 @@ static int __init noalign_setup(char *__unused)
}
__setup("noalign", noalign_setup);
+#ifndef CONFIG_SMP
+void adjust_cr(unsigned long mask, unsigned long set)
+{
+ unsigned long flags;
+
+ mask &= ~CR_A;
+
+ set &= mask;
+
+ local_irq_save(flags);
+
+ cr_no_alignment = (cr_no_alignment & ~mask) | set;
+ cr_alignment = (cr_alignment & ~mask) | set;
+
+ set_cr((get_cr() & ~mask) | set);
+
+ local_irq_restore(flags);
+}
+#endif
+
struct mem_types {
unsigned int prot_pte;
unsigned int prot_l1;
@@ -294,12 +314,6 @@ static void __init build_mem_type_table(void)
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
@@ -408,7 +422,7 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg
}
ptep = pte_offset_kernel(pmdp, virt);
- set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
+ set_pte_ext(ptep, pfn_pte(phys >> PAGE_SHIFT, prot), 0);
}
/*
diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c
index 20c1b0df75f..50b9aed6000 100644
--- a/arch/arm/mm/pgd.c
+++ b/arch/arm/mm/pgd.c
@@ -57,7 +57,7 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
init_pmd = pmd_offset(init_pgd, 0);
init_pte = pte_offset_map_nested(init_pmd, 0);
- set_pte(new_pte, *init_pte);
+ set_pte_ext(new_pte, *init_pte, 0);
pte_unmap_nested(init_pte);
pte_unmap(new_pte);
}
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
index 289b8e6f504..700c04d6996 100644
--- a/arch/arm/mm/proc-arm1020.S
+++ b/arch/arm/mm/proc-arm1020.S
@@ -397,7 +397,7 @@ ENTRY(cpu_arm1020_switch_mm)
* Set a PTE and flush it out
*/
.align 5
-ENTRY(cpu_arm1020_set_pte)
+ENTRY(cpu_arm1020_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -477,7 +477,7 @@ arm1020_processor_functions:
.word cpu_arm1020_do_idle
.word cpu_arm1020_dcache_clean_area
.word cpu_arm1020_switch_mm
- .word cpu_arm1020_set_pte
+ .word cpu_arm1020_set_pte_ext
.size arm1020_processor_functions, . - arm1020_processor_functions
.section ".rodata"
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
index bed9db6ba58..1cc206ab5ea 100644
--- a/arch/arm/mm/proc-arm1020e.S
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -381,7 +381,7 @@ ENTRY(cpu_arm1020e_switch_mm)
* Set a PTE and flush it out
*/
.align 5
-ENTRY(cpu_arm1020e_set_pte)
+ENTRY(cpu_arm1020e_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -458,7 +458,7 @@ arm1020e_processor_functions:
.word cpu_arm1020e_do_idle
.word cpu_arm1020e_dcache_clean_area
.word cpu_arm1020e_switch_mm
- .word cpu_arm1020e_set_pte
+ .word cpu_arm1020e_set_pte_ext
.size arm1020e_processor_functions, . - arm1020e_processor_functions
.section ".rodata"
diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S
index d2a7c1b9cab..aff0ea08e2f 100644
--- a/arch/arm/mm/proc-arm1022.S
+++ b/arch/arm/mm/proc-arm1022.S
@@ -358,12 +358,12 @@ ENTRY(cpu_arm1022_switch_mm)
mov pc, lr
/*
- * cpu_arm1022_set_pte(ptep, pte)
+ * cpu_arm1022_set_pte_ext(ptep, pte, ext)
*
* Set a PTE and flush it out
*/
.align 5
-ENTRY(cpu_arm1022_set_pte)
+ENTRY(cpu_arm1022_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -441,7 +441,7 @@ arm1022_processor_functions:
.word cpu_arm1022_do_idle
.word cpu_arm1022_dcache_clean_area
.word cpu_arm1022_switch_mm
- .word cpu_arm1022_set_pte
+ .word cpu_arm1022_set_pte_ext
.size arm1022_processor_functions, . - arm1022_processor_functions
.section ".rodata"
diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S
index 3247ce5c017..65e43a10908 100644
--- a/arch/arm/mm/proc-arm1026.S
+++ b/arch/arm/mm/proc-arm1026.S
@@ -347,12 +347,12 @@ ENTRY(cpu_arm1026_switch_mm)
mov pc, lr
/*
- * cpu_arm1026_set_pte(ptep, pte)
+ * cpu_arm1026_set_pte_ext(ptep, pte, ext)
*
* Set a PTE and flush it out
*/
.align 5
-ENTRY(cpu_arm1026_set_pte)
+ENTRY(cpu_arm1026_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -436,7 +436,7 @@ arm1026_processor_functions:
.word cpu_arm1026_do_idle
.word cpu_arm1026_dcache_clean_area
.word cpu_arm1026_switch_mm
- .word cpu_arm1026_set_pte
+ .word cpu_arm1026_set_pte_ext
.size arm1026_processor_functions, . - arm1026_processor_functions
.section .rodata
diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S
index ce4f9eef763..123a7dc7a43 100644
--- a/arch/arm/mm/proc-arm6_7.S
+++ b/arch/arm/mm/proc-arm6_7.S
@@ -209,14 +209,14 @@ ENTRY(cpu_arm7_switch_mm)
mov pc, lr
/*
- * Function: arm6_7_set_pte(pte_t *ptep, pte_t pte)
+ * Function: arm6_7_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext)
* Params : r0 = Address to set
* : r1 = value to set
* Purpose : Set a PTE and flush it out of any WB cache
*/
.align 5
-ENTRY(cpu_arm6_set_pte)
-ENTRY(cpu_arm7_set_pte)
+ENTRY(cpu_arm6_set_pte_ext)
+ENTRY(cpu_arm7_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -299,7 +299,7 @@ ENTRY(arm6_processor_functions)
.word cpu_arm6_do_idle
.word cpu_arm6_dcache_clean_area
.word cpu_arm6_switch_mm
- .word cpu_arm6_set_pte
+ .word cpu_arm6_set_pte_ext
.size arm6_processor_functions, . - arm6_processor_functions
/*
@@ -315,7 +315,7 @@ ENTRY(arm7_processor_functions)
.word cpu_arm7_do_idle
.word cpu_arm7_dcache_clean_area
.word cpu_arm7_switch_mm
- .word cpu_arm7_set_pte
+ .word cpu_arm7_set_pte_ext
.size arm7_processor_functions, . - arm7_processor_functions
.section ".rodata"
diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S
index c04c194da78..dc763be4336 100644
--- a/arch/arm/mm/proc-arm720.S
+++ b/arch/arm/mm/proc-arm720.S
@@ -88,13 +88,13 @@ ENTRY(cpu_arm720_switch_mm)
mov pc, lr
/*
- * Function: arm720_set_pte(pte_t *ptep, pte_t pte)
+ * Function: arm720_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext)
* Params : r0 = Address to set
* : r1 = value to set
* Purpose : Set a PTE and flush it out of any WB cache
*/
.align 5
-ENTRY(cpu_arm720_set_pte)
+ENTRY(cpu_arm720_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -204,7 +204,7 @@ ENTRY(arm720_processor_functions)
.word cpu_arm720_do_idle
.word cpu_arm720_dcache_clean_area
.word cpu_arm720_switch_mm
- .word cpu_arm720_set_pte
+ .word cpu_arm720_set_pte_ext
.size arm720_processor_functions, . - arm720_processor_functions
.section ".rodata"
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index 65cbb2851bf..75c945ed6c4 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -344,12 +344,12 @@ ENTRY(cpu_arm920_switch_mm)
mov pc, lr
/*
- * cpu_arm920_set_pte(ptep, pte)
+ * cpu_arm920_set_pte(ptep, pte, ext)
*
* Set a PTE and flush it out
*/
.align 5
-ENTRY(cpu_arm920_set_pte)
+ENTRY(cpu_arm920_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -423,7 +423,7 @@ arm920_processor_functions:
.word cpu_arm920_do_idle
.word cpu_arm920_dcache_clean_area
.word cpu_arm920_switch_mm
- .word cpu_arm920_set_pte
+ .word cpu_arm920_set_pte_ext
.size arm920_processor_functions, . - arm920_processor_functions
.section ".rodata"
diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S
index 52761b70d73..ffb751b877f 100644
--- a/arch/arm/mm/proc-arm922.S
+++ b/arch/arm/mm/proc-arm922.S
@@ -348,12 +348,12 @@ ENTRY(cpu_arm922_switch_mm)
mov pc, lr
/*
- * cpu_arm922_set_pte(ptep, pte)
+ * cpu_arm922_set_pte_ext(ptep, pte, ext)
*
* Set a PTE and flush it out
*/
.align 5
-ENTRY(cpu_arm922_set_pte)
+ENTRY(cpu_arm922_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -427,7 +427,7 @@ arm922_processor_functions:
.word cpu_arm922_do_idle
.word cpu_arm922_dcache_clean_area
.word cpu_arm922_switch_mm
- .word cpu_arm922_set_pte
+ .word cpu_arm922_set_pte_ext
.size arm922_processor_functions, . - arm922_processor_functions
.section ".rodata"
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S
index 5b74339d158..44c2c997819 100644
--- a/arch/arm/mm/proc-arm925.S
+++ b/arch/arm/mm/proc-arm925.S
@@ -391,12 +391,12 @@ ENTRY(cpu_arm925_switch_mm)
mov pc, lr
/*
- * cpu_arm925_set_pte(ptep, pte)
+ * cpu_arm925_set_pte_ext(ptep, pte, ext)
*
* Set a PTE and flush it out
*/
.align 5
-ENTRY(cpu_arm925_set_pte)
+ENTRY(cpu_arm925_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -490,7 +490,7 @@ arm925_processor_functions:
.word cpu_arm925_do_idle
.word cpu_arm925_dcache_clean_area
.word cpu_arm925_switch_mm
- .word cpu_arm925_set_pte
+ .word cpu_arm925_set_pte_ext
.size arm925_processor_functions, . - arm925_processor_functions
.section ".rodata"
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 8628ed29a95..5b80b6bdd0c 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -348,12 +348,12 @@ ENTRY(cpu_arm926_switch_mm)
mov pc, lr
/*
- * cpu_arm926_set_pte(ptep, pte)
+ * cpu_arm926_set_pte_ext(ptep, pte, ext)
*
* Set a PTE and flush it out
*/
.align 5
-ENTRY(cpu_arm926_set_pte)
+ENTRY(cpu_arm926_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -439,7 +439,7 @@ arm926_processor_functions:
.word cpu_arm926_do_idle
.word cpu_arm926_dcache_clean_area
.word cpu_arm926_switch_mm
- .word cpu_arm926_set_pte
+ .word cpu_arm926_set_pte_ext
.size arm926_processor_functions, . - arm926_processor_functions
.section ".rodata"
@@ -480,7 +480,7 @@ __arm926_proc_info:
b __arm926_setup
.long cpu_arch_name
.long cpu_elf_name
- .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_VFP|HWCAP_EDSP|HWCAP_JAVA
+ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA
.long cpu_arm926_name
.long arm926_processor_functions
.long v4wbi_tlb_fns
diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S
index cd7d865c9d1..6e226e12989 100644
--- a/arch/arm/mm/proc-sa110.S
+++ b/arch/arm/mm/proc-sa110.S
@@ -146,12 +146,12 @@ ENTRY(cpu_sa110_switch_mm)
#endif
/*
- * cpu_sa110_set_pte(ptep, pte)
+ * cpu_sa110_set_pte_ext(ptep, pte, ext)
*
* Set a PTE and flush it out
*/
.align 5
-ENTRY(cpu_sa110_set_pte)
+ENTRY(cpu_sa110_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -222,7 +222,7 @@ ENTRY(sa110_processor_functions)
.word cpu_sa110_do_idle
.word cpu_sa110_dcache_clean_area
.word cpu_sa110_switch_mm
- .word cpu_sa110_set_pte
+ .word cpu_sa110_set_pte_ext
.size sa110_processor_functions, . - sa110_processor_functions
.section ".rodata"
diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S
index b776653cc31..9afb11d089f 100644
--- a/arch/arm/mm/proc-sa1100.S
+++ b/arch/arm/mm/proc-sa1100.S
@@ -159,12 +159,12 @@ ENTRY(cpu_sa1100_switch_mm)
#endif
/*
- * cpu_sa1100_set_pte(ptep, pte)
+ * cpu_sa1100_set_pte_ext(ptep, pte, ext)
*
* Set a PTE and flush it out
*/
.align 5
-ENTRY(cpu_sa1100_set_pte)
+ENTRY(cpu_sa1100_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
@@ -237,7 +237,7 @@ ENTRY(sa1100_processor_functions)
.word cpu_sa1100_do_idle
.word cpu_sa1100_dcache_clean_area
.word cpu_sa1100_switch_mm
- .word cpu_sa1100_set_pte
+ .word cpu_sa1100_set_pte_ext
.size sa1100_processor_functions, . - sa1100_processor_functions
.section ".rodata"
diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c
index ab143557e68..9f396b4fa0b 100644
--- a/arch/arm/mm/proc-syms.c
+++ b/arch/arm/mm/proc-syms.c
@@ -17,7 +17,7 @@
#ifndef MULTI_CPU
EXPORT_SYMBOL(cpu_dcache_clean_area);
-EXPORT_SYMBOL(cpu_set_pte);
+EXPORT_SYMBOL(cpu_set_pte_ext);
#else
EXPORT_SYMBOL(processor);
#endif
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index b440c8a1d34..7b1843befb9 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -103,13 +103,14 @@ ENTRY(cpu_v6_switch_mm)
mov pc, lr
/*
- * cpu_v6_set_pte(ptep, pte)
+ * cpu_v6_set_pte_ext(ptep, pte, ext)
*
* Set a level 2 translation table entry.
*
* - ptep - pointer to level 2 translation table entry
* (hardware version is stored at -1024 bytes)
* - pte - PTE value to store
+ * - ext - value for extended PTE bits
*
* Permissions:
* YUWD APX AP1 AP0 SVC User
@@ -121,33 +122,34 @@ ENTRY(cpu_v6_switch_mm)
* 11x0 0 1 0 r/w r/o
* 1111 0 1 1 r/w r/w
*/
-ENTRY(cpu_v6_set_pte)
+ENTRY(cpu_v6_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
- bic r2, r1, #0x000003f0
- bic r2, r2, #0x00000003
- orr r2, r2, #PTE_EXT_AP0 | 2
+ bic r3, r1, #0x000003f0
+ bic r3, r3, #0x00000003
+ orr r3, r3, r2
+ orr r3, r3, #PTE_EXT_AP0 | 2
tst r1, #L_PTE_WRITE
tstne r1, #L_PTE_DIRTY
- orreq r2, r2, #PTE_EXT_APX
+ orreq r3, r3, #PTE_EXT_APX
tst r1, #L_PTE_USER
- orrne r2, r2, #PTE_EXT_AP1
- tstne r2, #PTE_EXT_APX
- bicne r2, r2, #PTE_EXT_APX | PTE_EXT_AP0
+ orrne r3, r3, #PTE_EXT_AP1
+ tstne r3, #PTE_EXT_APX
+ bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0
tst r1, #L_PTE_YOUNG
- biceq r2, r2, #PTE_EXT_APX | PTE_EXT_AP_MASK
+ biceq r3, r3, #PTE_EXT_APX | PTE_EXT_AP_MASK
tst r1, #L_PTE_EXEC
- orreq r2, r2, #PTE_EXT_XN
+ orreq r3, r3, #PTE_EXT_XN
tst r1, #L_PTE_PRESENT
- moveq r2, #0
+ moveq r3, #0
- str r2, [r0]
+ str r3, [r0]
mcr p15, 0, r0, c7, c10, 1 @ flush_pte
#endif
mov pc, lr
@@ -156,7 +158,7 @@ ENTRY(cpu_v6_set_pte)
cpu_v6_name:
- .asciz "Some Random V6 Processor"
+ .asciz "ARMv6-compatible processor"
.align
.section ".text.init", #alloc, #execinstr
@@ -207,11 +209,6 @@ __v6_setup:
#endif
mcr p15, 0, r4, c2, c0, 1 @ load TTB1
#endif /* CONFIG_MMU */
-#ifdef CONFIG_VFP
- mrc p15, 0, r0, c1, c0, 2
- orr r0, r0, #(0xf << 20)
- mcr p15, 0, r0, c1, c0, 2 @ Enable full access to VFP
-#endif
adr r5, v6_crval
ldmia r5, {r5, r6}
mrc p15, 0, r0, c1, c0, 0 @ read control register
@@ -238,7 +235,7 @@ ENTRY(v6_processor_functions)
.word cpu_v6_do_idle
.word cpu_v6_dcache_clean_area
.word cpu_v6_switch_mm
- .word cpu_v6_set_pte
+ .word cpu_v6_set_pte_ext
.size v6_processor_functions, . - v6_processor_functions
.type cpu_arch_name, #object
@@ -273,7 +270,7 @@ __v6_proc_info:
b __v6_setup
.long cpu_arch_name
.long cpu_elf_name
- .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_VFP|HWCAP_EDSP|HWCAP_JAVA
+ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA
.long cpu_v6_name
.long v6_processor_functions
.long v6wbi_tlb_fns
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index 1ef564d0957..94a58455f34 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -2,7 +2,7 @@
* linux/arch/arm/mm/proc-xsc3.S
*
* Original Author: Matthew Gilbert
- * Current Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ * Current Maintainer: Lennert Buytenhek <buytenh@wantstofly.org>
*
* Copyright 2004 (C) Intel Corp.
* Copyright 2005 (c) MontaVista Software, Inc.
@@ -357,13 +357,13 @@ ENTRY(cpu_xsc3_switch_mm)
cpwait_ret lr, ip
/*
- * cpu_xsc3_set_pte(ptep, pte)
+ * cpu_xsc3_set_pte_ext(ptep, pte, ext)
*
* Set a PTE and flush it out
*
*/
.align 5
-ENTRY(cpu_xsc3_set_pte)
+ENTRY(cpu_xsc3_set_pte_ext)
str r1, [r0], #-2048 @ linux version
bic r2, r1, #0xff0 @ Keep C, B bits
@@ -457,7 +457,7 @@ ENTRY(xsc3_processor_functions)
.word cpu_xsc3_do_idle
.word cpu_xsc3_dcache_clean_area
.word cpu_xsc3_switch_mm
- .word cpu_xsc3_set_pte
+ .word cpu_xsc3_set_pte_ext
.size xsc3_processor_functions, . - xsc3_processor_functions
.section ".rodata"
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index cc1004b3e51..d29fe927ee9 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -421,14 +421,14 @@ ENTRY(cpu_xscale_switch_mm)
cpwait_ret lr, ip
/*
- * cpu_xscale_set_pte(ptep, pte)
+ * cpu_xscale_set_pte_ext(ptep, pte, ext)
*
* Set a PTE and flush it out
*
* Errata 40: must set memory to write-through for user read-only pages.
*/
.align 5
-ENTRY(cpu_xscale_set_pte)
+ENTRY(cpu_xscale_set_pte_ext)
str r1, [r0], #-2048 @ linux version
bic r2, r1, #0xff0
@@ -529,7 +529,7 @@ ENTRY(xscale_processor_functions)
.word cpu_xscale_do_idle
.word cpu_xscale_dcache_clean_area
.word cpu_xscale_switch_mm
- .word cpu_xscale_set_pte
+ .word cpu_xscale_set_pte_ext
.size xscale_processor_functions, . - xscale_processor_functions
.section ".rodata"
@@ -708,7 +708,7 @@ __8032x_proc_info:
.type __8033x_proc_info,#object
__8033x_proc_info:
.long 0x69054010
- .long 0xffffff30
+ .long 0xfffffd30
.long PMD_TYPE_SECT | \
PMD_SECT_BUFFERABLE | \
PMD_SECT_CACHEABLE | \
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index ec752e16d61..f2dc363de66 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -113,7 +113,7 @@ endchoice
config OMAP_SERIAL_WAKE
bool "Enable wake-up events for serial ports"
- depends OMAP_MUX
+ depends on OMAP_MUX
default y
help
Select this option if you want to have your system wake up
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 8bcb838e544..bd78058b717 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -12,7 +12,7 @@
#
# http://www.arm.linux.org.uk/developer/machines/?action=new
#
-# Last update: Thu Dec 7 17:19:20 2006
+# Last update: Tue Jan 16 16:52:56 2007
#
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
#
@@ -1219,3 +1219,26 @@ zevio_1020 MACH_ZEVIO_1020 ZEVIO_1020 1207
hitrack MACH_HITRACK HITRACK 1208
syme1 MACH_SYME1 SYME1 1209
syhl1 MACH_SYHL1 SYHL1 1210
+empca400 MACH_EMPCA400 EMPCA400 1211
+em7210 MACH_EM7210 EM7210 1212
+htchermes MACH_HTCHERMES HTCHERMES 1213
+eti_c1 MACH_ETI_C1 ETI_C1 1214
+mach_dep2410 MACH_MACH_DEP2410 MACH_DEP2410 1215
+ac100 MACH_AC100 AC100 1216
+sneetch MACH_SNEETCH SNEETCH 1217
+studentmate MACH_STUDENTMATE STUDENTMATE 1218
+zir2410 MACH_ZIR2410 ZIR2410 1219
+zir2413 MACH_ZIR2413 ZIR2413 1220
+dlonip3 MACH_DLONIP3 DLONIP3 1221
+instream MACH_INSTREAM INSTREAM 1222
+ambarella MACH_AMBARELLA AMBARELLA 1223
+nevis MACH_NEVIS NEVIS 1224
+htc_trinity MACH_HTC_TRINITY HTC_TRINITY 1225
+ql202b MACH_QL202B QL202B 1226
+vpac270 MACH_VPAC270 VPAC270 1227
+rd129 MACH_RD129 RD129 1228
+htcwizard MACH_HTCWIZARD HTCWIZARD 1229
+xscale_treo680 MACH_XSCALE_TREO680 XSCALE_TREO680 1230
+tecon_tmezon MACH_TECON_TMEZON TECON_TMEZON 1231
+zylonite MACH_ZYLONITE ZYLONITE 1233
+gene1270 MACH_GENE1270 GENE1270 1234
diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
index 7b595547c1c..ca2a5ad19ea 100644
--- a/arch/arm/vfp/entry.S
+++ b/arch/arm/vfp/entry.S
@@ -25,6 +25,7 @@
do_vfp:
enable_irq
ldr r4, .LCvfp
+ ldr r11, [r10, #TI_CPU] @ CPU number
add r10, r10, #TI_VFPSTATE @ r10 = workspace
ldr pc, [r4] @ call VFP entry point
diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
index f2797896e6d..54a2ad6d9ca 100644
--- a/arch/arm/vfp/vfp.h
+++ b/arch/arm/vfp/vfp.h
@@ -370,3 +370,7 @@ struct op {
u32 (* const fn)(int dd, int dn, int dm, u32 fpscr);
u32 flags;
};
+
+#ifdef CONFIG_SMP
+extern void vfp_save_state(void *location, u32 fpexc);
+#endif
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index e51e6679c40..d4b7b229631 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -65,6 +65,7 @@
@ r2 = faulted PC+4
@ r9 = successful return
@ r10 = vfp_state union
+@ r11 = CPU number
@ lr = failure return
.globl vfp_support_entry
@@ -79,7 +80,7 @@ vfp_support_entry:
DBGSTR1 "enable %x", r10
ldr r3, last_VFP_context_address
orr r1, r1, #FPEXC_ENABLE @ user FPEXC has the enable bit set
- ldr r4, [r3] @ last_VFP_context pointer
+ ldr r4, [r3, r11, lsl #2] @ last_VFP_context pointer
bic r5, r1, #FPEXC_EXCEPTION @ make sure exceptions are disabled
cmp r4, r10
beq check_for_exception @ we are returning to the same
@@ -91,7 +92,9 @@ vfp_support_entry:
@ exceptions, so we can get at the
@ rest of it
+#ifndef CONFIG_SMP
@ Save out the current registers to the old thread state
+ @ No need for SMP since this is not done lazily
DBGSTR1 "save old state %p", r4
cmp r4, #0
@@ -105,10 +108,11 @@ vfp_support_entry:
stmia r4, {r1, r5, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2
@ and point r4 at the word at the
@ start of the register dump
+#endif
no_old_VFP_process:
DBGSTR1 "load state %p", r10
- str r10, [r3] @ update the last_VFP_context pointer
+ str r10, [r3, r11, lsl #2] @ update the last_VFP_context pointer
@ Load the saved state back into the VFP
VFPFLDMIA r10 @ reload the working registers while
@ FPEXC is in a safe state
@@ -162,6 +166,24 @@ process_exception:
@ required. If not, the user code will
@ retry the faulted instruction
+#ifdef CONFIG_SMP
+ .globl vfp_save_state
+ .type vfp_save_state, %function
+vfp_save_state:
+ @ Save the current VFP state
+ @ r0 - save location
+ @ r1 - FPEXC
+ DBGSTR1 "save VFP state %p", r0
+ VFPFMRX r2, FPSCR @ current status
+ VFPFMRX r3, FPINST @ FPINST (always there, rev0 onwards)
+ tst r1, #FPEXC_FPV2 @ is there an FPINST2 to read?
+ VFPFMRX r12, FPINST2, NE @ FPINST2 if needed - avoids reading
+ @ nonexistant reg on rev0
+ VFPFSTMIA r0 @ save the working registers
+ stmia r0, {r1, r2, r3, r12} @ save FPEXC, FPSCR, FPINST, FPINST2
+ mov pc, lr
+#endif
+
last_VFP_context_address:
.word last_VFP_context
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index f08eafbddcc..f1e5951dc72 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -28,7 +28,7 @@ void vfp_testing_entry(void);
void vfp_support_entry(void);
void (*vfp_vector)(void) = vfp_testing_entry;
-union vfp_state *last_VFP_context;
+union vfp_state *last_VFP_context[NR_CPUS];
/*
* Dual-use variable.
@@ -41,13 +41,35 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
{
struct thread_info *thread = v;
union vfp_state *vfp;
+ __u32 cpu = thread->cpu;
if (likely(cmd == THREAD_NOTIFY_SWITCH)) {
+ u32 fpexc = fmrx(FPEXC);
+
+#ifdef CONFIG_SMP
+ /*
+ * On SMP, if VFP is enabled, save the old state in
+ * case the thread migrates to a different CPU. The
+ * restoring is done lazily.
+ */
+ if ((fpexc & FPEXC_ENABLE) && last_VFP_context[cpu]) {
+ vfp_save_state(last_VFP_context[cpu], fpexc);
+ last_VFP_context[cpu]->hard.cpu = cpu;
+ }
+ /*
+ * Thread migration, just force the reloading of the
+ * state on the new CPU in case the VFP registers
+ * contain stale data.
+ */
+ if (thread->vfpstate.hard.cpu != cpu)
+ last_VFP_context[cpu] = NULL;
+#endif
+
/*
* Always disable VFP so we can lazily save/restore the
* old state.
*/
- fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+ fmxr(FPEXC, fpexc & ~FPEXC_ENABLE);
return NOTIFY_DONE;
}
@@ -68,8 +90,8 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
}
/* flush and release case: Per-thread VFP cleanup. */
- if (last_VFP_context == vfp)
- last_VFP_context = NULL;
+ if (last_VFP_context[cpu] == vfp)
+ last_VFP_context[cpu] = NULL;
return NOTIFY_DONE;
}
@@ -263,13 +285,36 @@ void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
if (exceptions)
vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
}
-
+
+static void vfp_enable(void *unused)
+{
+ u32 access = get_copro_access();
+
+ /*
+ * Enable full access to VFP (cp10 and cp11)
+ */
+ set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
+}
+
+#include <linux/smp.h>
+
/*
* VFP support code initialisation.
*/
static int __init vfp_init(void)
{
unsigned int vfpsid;
+ unsigned int cpu_arch = cpu_architecture();
+ u32 access = 0;
+
+ if (cpu_arch >= CPU_ARCH_ARMv6) {
+ access = get_copro_access();
+
+ /*
+ * Enable full access to VFP (cp10 and cp11)
+ */
+ set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
+ }
/*
* First check that there is a VFP that we can use.
@@ -277,13 +322,22 @@ static int __init vfp_init(void)
* we just need to read the VFPSID register.
*/
vfpsid = fmrx(FPSID);
+ barrier();
printk(KERN_INFO "VFP support v0.3: ");
if (VFP_arch) {
printk("not present\n");
+
+ /*
+ * Restore the copro access register.
+ */
+ if (cpu_arch >= CPU_ARCH_ARMv6)
+ set_copro_access(access);
} else if (vfpsid & FPSID_NODOUBLE) {
printk("no double precision support\n");
} else {
+ smp_call_function(vfp_enable, NULL, 1, 1);
+
VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */
printk("implementor %02x architecture %d part %02x variant %x rev %x\n",
(vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT,
@@ -291,9 +345,16 @@ static int __init vfp_init(void)
(vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT,
(vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT,
(vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT);
+
vfp_vector = vfp_support_entry;
thread_register_notifier(&vfp_notifier_block);
+
+ /*
+ * We detected VFP, and the support code is
+ * in place; report VFP support to userspace.
+ */
+ elf_hwcap |= HWCAP_VFP;
}
return 0;
}
diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig
index c14fe918bc4..74eba8b5a8c 100644
--- a/arch/arm26/Kconfig
+++ b/arch/arm26/Kconfig
@@ -41,6 +41,14 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_HWEIGHT
bool
default y
diff --git a/arch/arm26/kernel/ecard.c b/arch/arm26/kernel/ecard.c
index 43dd41be71f..9dbc17247c6 100644
--- a/arch/arm26/kernel/ecard.c
+++ b/arch/arm26/kernel/ecard.c
@@ -215,7 +215,7 @@ int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
}
if (c_id(&excd) == 0x80) { /* loader */
if (!ec->loader) {
- ec->loader = (loader_t)kmalloc(c_len(&excd),
+ ec->loader = kmalloc(c_len(&excd),
GFP_KERNEL);
if (ec->loader)
ecard_readbytes(ec->loader, ec,
diff --git a/arch/arm26/kernel/irq.c b/arch/arm26/kernel/irq.c
index d87d68b77d6..d53382c83bf 100644
--- a/arch/arm26/kernel/irq.c
+++ b/arch/arm26/kernel/irq.c
@@ -545,7 +545,7 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_
(irq_flags & IRQF_SHARED && !dev_id))
return -EINVAL;
- action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ action = kmalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index 5f1694eea84..bb059a4e1df 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -45,6 +45,14 @@ config GENERIC_TIME
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_BUST_SPINLOCK
bool
diff --git a/arch/avr32/boards/atstk1000/Makefile b/arch/avr32/boards/atstk1000/Makefile
index df949948053..8e0992201bb 100644
--- a/arch/avr32/boards/atstk1000/Makefile
+++ b/arch/avr32/boards/atstk1000/Makefile
@@ -1,2 +1,2 @@
-obj-y += setup.o spi.o flash.o
+obj-y += setup.o flash.o
obj-$(CONFIG_BOARD_ATSTK1002) += atstk1002.o
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index cced73c5811..d47e39f0e97 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -7,38 +7,149 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/etherdevice.h>
#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/arch/at32ap7000.h>
#include <asm/arch/board.h>
#include <asm/arch/init.h>
+#include <asm/arch/portmux.h>
-struct eth_platform_data __initdata eth0_data = {
- .valid = 1,
- .mii_phy_addr = 0x10,
- .is_rmii = 0,
- .hw_addr = { 0x6a, 0x87, 0x71, 0x14, 0xcd, 0xcb },
+
+#define SW2_DEFAULT /* MMCI and UART_A available */
+
+struct eth_addr {
+ u8 addr[6];
};
+static struct eth_addr __initdata hw_addr[2];
+
+static struct eth_platform_data __initdata eth_data[2];
extern struct lcdc_platform_data atstk1000_fb0_data;
+static struct spi_board_info spi_board_info[] __initdata = {
+ {
+ .modalias = "ltv350qv",
+ .controller_data = (void *)GPIO_PIN_PA(4),
+ .max_speed_hz = 16000000,
+ .bus_num = 0,
+ .chip_select = 1,
+ },
+};
+
+/*
+ * The next two functions should go away as the boot loader is
+ * supposed to initialize the macb address registers with a valid
+ * ethernet address. But we need to keep it around for a while until
+ * we can be reasonably sure the boot loader does this.
+ *
+ * The phy_id is ignored as the driver will probe for it.
+ */
+static int __init parse_tag_ethernet(struct tag *tag)
+{
+ int i;
+
+ i = tag->u.ethernet.mac_index;
+ if (i < ARRAY_SIZE(hw_addr))
+ memcpy(hw_addr[i].addr, tag->u.ethernet.hw_address,
+ sizeof(hw_addr[i].addr));
+
+ return 0;
+}
+__tagtable(ATAG_ETHERNET, parse_tag_ethernet);
+
+static void __init set_hw_addr(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ const u8 *addr;
+ void __iomem *regs;
+ struct clk *pclk;
+
+ if (!res)
+ return;
+ if (pdev->id >= ARRAY_SIZE(hw_addr))
+ return;
+
+ addr = hw_addr[pdev->id].addr;
+ if (!is_valid_ether_addr(addr))
+ return;
+
+ /*
+ * Since this is board-specific code, we'll cheat and use the
+ * physical address directly as we happen to know that it's
+ * the same as the virtual address.
+ */
+ regs = (void __iomem __force *)res->start;
+ pclk = clk_get(&pdev->dev, "pclk");
+ if (!pclk)
+ return;
+
+ clk_enable(pclk);
+ __raw_writel((addr[3] << 24) | (addr[2] << 16)
+ | (addr[1] << 8) | addr[0], regs + 0x98);
+ __raw_writel((addr[5] << 8) | addr[4], regs + 0x9c);
+ clk_disable(pclk);
+ clk_put(pclk);
+}
+
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 */
+#ifdef SW2_DEFAULT
+ at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */
+#else
+ at32_map_usart(0, 1); /* USART 0/B: /dev/ttyS1, IRDA */
+#endif
+ /* USART 2/unused: expansion connector */
+ at32_map_usart(3, 2); /* USART 3/C: /dev/ttyS2, DB9 */
at32_setup_serial_console(0);
}
static int __init atstk1002_init(void)
{
+ /*
+ * ATSTK1000 uses 32-bit SDRAM interface. Reserve the
+ * SDRAM-specific pins so that nobody messes with them.
+ */
+ at32_reserve_pin(GPIO_PIN_PE(0)); /* DATA[16] */
+ at32_reserve_pin(GPIO_PIN_PE(1)); /* DATA[17] */
+ at32_reserve_pin(GPIO_PIN_PE(2)); /* DATA[18] */
+ at32_reserve_pin(GPIO_PIN_PE(3)); /* DATA[19] */
+ at32_reserve_pin(GPIO_PIN_PE(4)); /* DATA[20] */
+ at32_reserve_pin(GPIO_PIN_PE(5)); /* DATA[21] */
+ at32_reserve_pin(GPIO_PIN_PE(6)); /* DATA[22] */
+ at32_reserve_pin(GPIO_PIN_PE(7)); /* DATA[23] */
+ at32_reserve_pin(GPIO_PIN_PE(8)); /* DATA[24] */
+ at32_reserve_pin(GPIO_PIN_PE(9)); /* DATA[25] */
+ at32_reserve_pin(GPIO_PIN_PE(10)); /* DATA[26] */
+ at32_reserve_pin(GPIO_PIN_PE(11)); /* DATA[27] */
+ at32_reserve_pin(GPIO_PIN_PE(12)); /* DATA[28] */
+ at32_reserve_pin(GPIO_PIN_PE(13)); /* DATA[29] */
+ at32_reserve_pin(GPIO_PIN_PE(14)); /* DATA[30] */
+ at32_reserve_pin(GPIO_PIN_PE(15)); /* DATA[31] */
+ at32_reserve_pin(GPIO_PIN_PE(26)); /* SDCS */
+
at32_add_system_devices();
+#ifdef SW2_DEFAULT
at32_add_device_usart(0);
+#else
at32_add_device_usart(1);
+#endif
at32_add_device_usart(2);
- at32_add_device_eth(0, &eth0_data);
+ set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
+
+ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
at32_add_device_spi(0);
at32_add_device_lcdc(0, &atstk1000_fb0_data);
diff --git a/arch/avr32/boards/atstk1000/spi.c b/arch/avr32/boards/atstk1000/spi.c
deleted file mode 100644
index 567726c82c6..00000000000
--- a/arch/avr32/boards/atstk1000/spi.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * ATSTK1000 SPI devices
- *
- * Copyright (C) 2005 Atmel Norway
- *
- * 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/device.h>
-#include <linux/spi/spi.h>
-
-static struct spi_board_info spi_board_info[] __initdata = {
- {
- .modalias = "ltv350qv",
- .max_speed_hz = 16000000,
- .bus_num = 0,
- .chip_select = 1,
- },
-};
-
-static int board_init_spi(void)
-{
- spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
- return 0;
-}
-arch_initcall(board_init_spi);
diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig
index ae92a14ef9a..77dace9d54b 100644
--- a/arch/avr32/configs/atstk1002_defconfig
+++ b/arch/avr32/configs/atstk1002_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc2
-# Fri Oct 20 11:52:37 2006
+# Linux kernel version: 2.6.20-rc6
+# Fri Jan 26 13:12:59 2007
#
CONFIG_AVR32=y
CONFIG_GENERIC_HARDIRQS=y
@@ -9,6 +9,8 @@ CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -36,6 +38,7 @@ CONFIG_TASK_DELAY_ACCT=y
# CONFIG_UTS_NS is not set
CONFIG_AUDIT=y
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
CONFIG_RELAY=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -75,7 +78,9 @@ CONFIG_MODULE_UNLOAD=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
@@ -125,6 +130,7 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_OWNERSHIP_TRACE is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_CMDLINE=""
@@ -182,6 +188,7 @@ CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -260,6 +267,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
@@ -355,7 +363,6 @@ CONFIG_BLK_DEV_INITRD=y
#
# Misc devices
#
-# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
#
@@ -405,11 +412,14 @@ CONFIG_TUN=m
#
# 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_MACB=y
#
# Ethernet (1000 Mbit)
@@ -505,10 +515,6 @@ CONFIG_UNIX98_PTYS=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
#
@@ -621,6 +627,10 @@ CONFIG_UNIX98_PTYS=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=m
@@ -683,7 +693,6 @@ CONFIG_CONFIGFS_FS=m
# 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
@@ -763,6 +772,11 @@ CONFIG_NLS_ISO8859_1=m
CONFIG_NLS_UTF8=m
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Kernel hacking
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
@@ -770,6 +784,8 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -785,13 +801,10 @@ CONFIG_DETECT_SOFTLOCKUP=y
# 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_HEADERS_CHECK is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_KPROBES is not set
@@ -809,6 +822,7 @@ CONFIG_FORCED_INLINING=y
#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=m
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -817,3 +831,4 @@ CONFIG_AUDIT_GENERIC=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/avr32/kernel/avr32_ksyms.c b/arch/avr32/kernel/avr32_ksyms.c
index 372e3f8b241..80f55f8dbf1 100644
--- a/arch/avr32/kernel/avr32_ksyms.c
+++ b/arch/avr32/kernel/avr32_ksyms.c
@@ -7,12 +7,12 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <asm/checksum.h>
#include <asm/uaccess.h>
-#include <asm/delay.h>
/*
* GCC functions
@@ -29,6 +29,7 @@ EXPORT_SYMBOL(__avr32_asr64);
*/
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(clear_page);
/*
* Userspace access stuff.
diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c
index 342452ba204..2e72fd2699d 100644
--- a/arch/avr32/kernel/cpu.c
+++ b/arch/avr32/kernel/cpu.c
@@ -9,6 +9,7 @@
#include <linux/sysdev.h>
#include <linux/seq_file.h>
#include <linux/cpu.h>
+#include <linux/module.h>
#include <linux/percpu.h>
#include <linux/param.h>
#include <linux/errno.h>
diff --git a/arch/avr32/kernel/irq.c b/arch/avr32/kernel/irq.c
index 856f3548e66..fd311248c14 100644
--- a/arch/avr32/kernel/irq.c
+++ b/arch/avr32/kernel/irq.c
@@ -57,6 +57,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%3d: ", i);
for_each_online_cpu(cpu)
seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]);
+ seq_printf(p, " %8s", irq_desc[i].chip->name ? : "-");
seq_printf(p, " %s", action->name);
for (action = action->next; action; action = action->next)
seq_printf(p, ", %s", action->name);
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 317dc50945f..0b4325946a4 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -38,6 +38,13 @@ void cpu_idle(void)
void machine_halt(void)
{
+ /*
+ * Enter Stop mode. The 32 kHz oscillator will keep running so
+ * the RTC will keep the time properly and the system will
+ * boot quickly.
+ */
+ asm volatile("sleep 3\n\t"
+ "sub pc, -2");
}
void machine_power_off(void)
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index ea2d1ffee47..c6734aefb55 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/root_dev.h>
#include <linux/cpu.h>
+#include <linux/kernel.h>
#include <asm/sections.h>
#include <asm/processor.h>
@@ -174,8 +175,7 @@ static int __init parse_tag_mem_range(struct tag *tag,
* Copy the data so the bootmem init code doesn't need to care
* about it.
*/
- if (mem_range_next_free >=
- (sizeof(mem_range_cache) / sizeof(mem_range_cache[0])))
+ if (mem_range_next_free >= ARRAY_SIZE(mem_range_cache))
panic("Physical memory map too complex!\n");
new = &mem_range_cache[mem_range_next_free++];
@@ -229,30 +229,6 @@ static int __init parse_tag_rsvd_mem(struct tag *tag)
}
__tagtable(ATAG_RSVD_MEM, parse_tag_rsvd_mem);
-static int __init parse_tag_ethernet(struct tag *tag)
-{
-#if 0
- const struct platform_device *pdev;
-
- /*
- * We really need a bus type that supports "classes"...this
- * will do for now (until we must handle other kinds of
- * ethernet controllers)
- */
- pdev = platform_get_device("macb", tag->u.ethernet.mac_index);
- if (pdev && pdev->dev.platform_data) {
- struct eth_platform_data *data = pdev->dev.platform_data;
-
- data->valid = 1;
- data->mii_phy_addr = tag->u.ethernet.mii_phy_addr;
- memcpy(data->hw_addr, tag->u.ethernet.hw_address,
- sizeof(data->hw_addr));
- }
-#endif
- return 0;
-}
-__tagtable(ATAG_ETHERNET, parse_tag_ethernet);
-
/*
* Scan the tag table for this tag, and call its parse function. The
* tag table is built by the linker from all the __tagtable
diff --git a/arch/avr32/lib/delay.c b/arch/avr32/lib/delay.c
index 462c8307b68..b3bc0b56e2c 100644
--- a/arch/avr32/lib/delay.c
+++ b/arch/avr32/lib/delay.c
@@ -12,9 +12,9 @@
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/param.h>
#include <linux/types.h>
-#include <asm/delay.h>
#include <asm/processor.h>
#include <asm/sysreg.h>
diff --git a/arch/avr32/lib/libgcc.h b/arch/avr32/lib/libgcc.h
deleted file mode 100644
index 5a091b5e361..00000000000
--- a/arch/avr32/lib/libgcc.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Definitions for various functions 'borrowed' from gcc-3.4.3 */
-
-#define BITS_PER_UNIT 8
-
-typedef int QItype __attribute__ ((mode (QI)));
-typedef unsigned int UQItype __attribute__ ((mode (QI)));
-typedef int HItype __attribute__ ((mode (HI)));
-typedef unsigned int UHItype __attribute__ ((mode (HI)));
-typedef int SItype __attribute__ ((mode (SI)));
-typedef unsigned int USItype __attribute__ ((mode (SI)));
-typedef int DItype __attribute__ ((mode (DI)));
-typedef unsigned int UDItype __attribute__ ((mode (DI)));
-typedef float SFtype __attribute__ ((mode (SF)));
-typedef float DFtype __attribute__ ((mode (DF)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-#define W_TYPE_SIZE (4 * BITS_PER_UNIT)
-#define Wtype SItype
-#define UWtype USItype
-#define HWtype SItype
-#define UHWtype USItype
-#define DWtype DItype
-#define UDWtype UDItype
-#define __NW(a,b) __ ## a ## si ## b
-#define __NDW(a,b) __ ## a ## di ## b
-
-struct DWstruct {Wtype high, low;};
-
-typedef union
-{
- struct DWstruct s;
- DWtype ll;
-} DWunion;
diff --git a/arch/avr32/lib/longlong.h b/arch/avr32/lib/longlong.h
deleted file mode 100644
index cd5e369ac43..00000000000
--- a/arch/avr32/lib/longlong.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
- Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000
- Free Software Foundation, Inc.
-
- This definition file is free software; you can redistribute 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 definition file 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. */
-
-/* Borrowed from gcc-3.4.3 */
-
-#define __BITS4 (W_TYPE_SIZE / 4)
-#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 count_leading_zeros(count, x) ((count) = __builtin_clz(x))
-
-#define __udiv_qrnnd_c(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 udiv_qrnnd __udiv_qrnnd_c
-
-#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) \
- do { \
- UWtype __x0, __x1, __x2, __x3; \
- UHWtype __ul, __vl, __uh, __vh; \
- \
- __ul = __ll_lowpart (u); \
- __uh = __ll_highpart (u); \
- __vl = __ll_lowpart (v); \
- __vh = __ll_highpart (v); \
- \
- __x0 = (UWtype) __ul * __vl; \
- __x1 = (UWtype) __ul * __vh; \
- __x2 = (UWtype) __uh * __vl; \
- __x3 = (UWtype) __uh * __vh; \
- \
- __x1 += __ll_highpart (__x0);/* this can't give carry */ \
- __x1 += __x2; /* but this indeed can */ \
- if (__x1 < __x2) /* did we get it? */ \
- __x3 += __ll_B; /* yes, add it in the proper pos. */ \
- \
- (w1) = __x3 + __ll_highpart (__x1); \
- (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \
- } while (0)
diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
index f62eb691551..b21bea9af8b 100644
--- a/arch/avr32/mach-at32ap/Makefile
+++ b/arch/avr32/mach-at32ap/Makefile
@@ -1,2 +1,2 @@
-obj-y += at32ap.o clock.o pio.o intc.o extint.o hsmc.o
+obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
index 7ff6ad8bab5..c1e477ec757 100644
--- a/arch/avr32/mach-at32ap/at32ap7000.c
+++ b/arch/avr32/mach-at32ap/at32ap7000.c
@@ -11,6 +11,7 @@
#include <asm/io.h>
+#include <asm/arch/at32ap7000.h>
#include <asm/arch/board.h>
#include <asm/arch/portmux.h>
#include <asm/arch/sm.h>
@@ -57,6 +58,9 @@ static struct platform_device _name##_id##_device = { \
.num_resources = ARRAY_SIZE(_name##_id##_resource), \
}
+#define select_peripheral(pin, periph, flags) \
+ at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
+
#define DEV_CLK(_name, devname, bus, _index) \
static struct clk devname##_##_name = { \
.name = #_name, \
@@ -67,18 +71,6 @@ static struct clk devname##_##_name = { \
.index = _index, \
}
-enum {
- PIOA,
- PIOB,
- PIOC,
- PIOD,
-};
-
-enum {
- FUNC_A,
- FUNC_B,
-};
-
unsigned long at32ap7000_osc_rates[3] = {
[0] = 32768,
/* FIXME: these are ATSTK1002-specific */
@@ -504,9 +496,16 @@ static struct resource pio3_resource[] = {
DEFINE_DEV(pio, 3);
DEV_CLK(mck, pio3, pba, 13);
+static struct resource pio4_resource[] = {
+ PBMEM(0xffe03800),
+ IRQ(17),
+};
+DEFINE_DEV(pio, 4);
+DEV_CLK(mck, pio4, pba, 14);
+
void __init at32_add_system_devices(void)
{
- system_manager.eim_first_irq = NR_INTERNAL_IRQS;
+ system_manager.eim_first_irq = EIM_IRQ_BASE;
platform_device_register(&at32_sm_device);
platform_device_register(&at32_intc0_device);
@@ -517,6 +516,7 @@ void __init at32_add_system_devices(void)
platform_device_register(&pio1_device);
platform_device_register(&pio2_device);
platform_device_register(&pio3_device);
+ platform_device_register(&pio4_device);
}
/* --------------------------------------------------------------------
@@ -529,7 +529,7 @@ static struct atmel_uart_data atmel_usart0_data = {
};
static struct resource atmel_usart0_resource[] = {
PBMEM(0xffe00c00),
- IRQ(7),
+ IRQ(6),
};
DEFINE_DEV_DATA(atmel_usart, 0);
DEV_CLK(usart, atmel_usart0, pba, 4);
@@ -569,29 +569,29 @@ DEV_CLK(usart, atmel_usart3, pba, 6);
static inline void configure_usart0_pins(void)
{
- portmux_set_func(PIOA, 8, FUNC_B); /* RXD */
- portmux_set_func(PIOA, 9, FUNC_B); /* TXD */
+ select_peripheral(PA(8), PERIPH_B, 0); /* RXD */
+ select_peripheral(PA(9), PERIPH_B, 0); /* TXD */
}
static inline void configure_usart1_pins(void)
{
- portmux_set_func(PIOA, 17, FUNC_A); /* RXD */
- portmux_set_func(PIOA, 18, FUNC_A); /* TXD */
+ select_peripheral(PA(17), PERIPH_A, 0); /* RXD */
+ select_peripheral(PA(18), PERIPH_A, 0); /* TXD */
}
static inline void configure_usart2_pins(void)
{
- portmux_set_func(PIOB, 26, FUNC_B); /* RXD */
- portmux_set_func(PIOB, 27, FUNC_B); /* TXD */
+ select_peripheral(PB(26), PERIPH_B, 0); /* RXD */
+ select_peripheral(PB(27), PERIPH_B, 0); /* TXD */
}
static inline void configure_usart3_pins(void)
{
- portmux_set_func(PIOB, 18, FUNC_B); /* RXD */
- portmux_set_func(PIOB, 17, FUNC_B); /* TXD */
+ select_peripheral(PB(18), PERIPH_B, 0); /* RXD */
+ select_peripheral(PB(17), PERIPH_B, 0); /* TXD */
}
-static struct platform_device *at32_usarts[4];
+static struct platform_device *__initdata at32_usarts[4];
void __init at32_map_usart(unsigned int hw_id, unsigned int line)
{
@@ -654,6 +654,15 @@ DEFINE_DEV_DATA(macb, 0);
DEV_CLK(hclk, macb0, hsb, 8);
DEV_CLK(pclk, macb0, pbb, 6);
+static struct eth_platform_data macb1_data;
+static struct resource macb1_resource[] = {
+ PBMEM(0xfff01c00),
+ IRQ(26),
+};
+DEFINE_DEV_DATA(macb, 1);
+DEV_CLK(hclk, macb1, hsb, 9);
+DEV_CLK(pclk, macb1, pbb, 7);
+
struct platform_device *__init
at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
{
@@ -663,27 +672,54 @@ at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
case 0:
pdev = &macb0_device;
- portmux_set_func(PIOC, 3, FUNC_A); /* TXD0 */
- portmux_set_func(PIOC, 4, FUNC_A); /* TXD1 */
- portmux_set_func(PIOC, 7, FUNC_A); /* TXEN */
- portmux_set_func(PIOC, 8, FUNC_A); /* TXCK */
- portmux_set_func(PIOC, 9, FUNC_A); /* RXD0 */
- portmux_set_func(PIOC, 10, FUNC_A); /* RXD1 */
- portmux_set_func(PIOC, 13, FUNC_A); /* RXER */
- portmux_set_func(PIOC, 15, FUNC_A); /* RXDV */
- portmux_set_func(PIOC, 16, FUNC_A); /* MDC */
- portmux_set_func(PIOC, 17, FUNC_A); /* MDIO */
+ select_peripheral(PC(3), PERIPH_A, 0); /* TXD0 */
+ select_peripheral(PC(4), PERIPH_A, 0); /* TXD1 */
+ select_peripheral(PC(7), PERIPH_A, 0); /* TXEN */
+ select_peripheral(PC(8), PERIPH_A, 0); /* TXCK */
+ select_peripheral(PC(9), PERIPH_A, 0); /* RXD0 */
+ select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
+ select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
+ select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
+ select_peripheral(PC(16), PERIPH_A, 0); /* MDC */
+ select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
if (!data->is_rmii) {
- portmux_set_func(PIOC, 0, FUNC_A); /* COL */
- portmux_set_func(PIOC, 1, FUNC_A); /* CRS */
- portmux_set_func(PIOC, 2, FUNC_A); /* TXER */
- portmux_set_func(PIOC, 5, FUNC_A); /* TXD2 */
- portmux_set_func(PIOC, 6, FUNC_A); /* TXD3 */
- portmux_set_func(PIOC, 11, FUNC_A); /* RXD2 */
- portmux_set_func(PIOC, 12, FUNC_A); /* RXD3 */
- portmux_set_func(PIOC, 14, FUNC_A); /* RXCK */
- portmux_set_func(PIOC, 18, FUNC_A); /* SPD */
+ select_peripheral(PC(0), PERIPH_A, 0); /* COL */
+ select_peripheral(PC(1), PERIPH_A, 0); /* CRS */
+ select_peripheral(PC(2), PERIPH_A, 0); /* TXER */
+ select_peripheral(PC(5), PERIPH_A, 0); /* TXD2 */
+ select_peripheral(PC(6), PERIPH_A, 0); /* TXD3 */
+ select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
+ select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
+ select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
+ select_peripheral(PC(18), PERIPH_A, 0); /* SPD */
+ }
+ break;
+
+ case 1:
+ pdev = &macb1_device;
+
+ select_peripheral(PD(13), PERIPH_B, 0); /* TXD0 */
+ select_peripheral(PD(14), PERIPH_B, 0); /* TXD1 */
+ select_peripheral(PD(11), PERIPH_B, 0); /* TXEN */
+ select_peripheral(PD(12), PERIPH_B, 0); /* TXCK */
+ select_peripheral(PD(10), PERIPH_B, 0); /* RXD0 */
+ select_peripheral(PD(6), PERIPH_B, 0); /* RXD1 */
+ select_peripheral(PD(5), PERIPH_B, 0); /* RXER */
+ select_peripheral(PD(4), PERIPH_B, 0); /* RXDV */
+ select_peripheral(PD(3), PERIPH_B, 0); /* MDC */
+ select_peripheral(PD(2), PERIPH_B, 0); /* MDIO */
+
+ if (!data->is_rmii) {
+ select_peripheral(PC(19), PERIPH_B, 0); /* COL */
+ select_peripheral(PC(23), PERIPH_B, 0); /* CRS */
+ select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
+ select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
+ select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
+ select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
+ select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
+ select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
+ select_peripheral(PD(15), PERIPH_B, 0); /* SPD */
}
break;
@@ -700,12 +736,19 @@ at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
/* --------------------------------------------------------------------
* SPI
* -------------------------------------------------------------------- */
-static struct resource spi0_resource[] = {
+static struct resource atmel_spi0_resource[] = {
PBMEM(0xffe00000),
IRQ(3),
};
-DEFINE_DEV(spi, 0);
-DEV_CLK(mck, spi0, pba, 0);
+DEFINE_DEV(atmel_spi, 0);
+DEV_CLK(spi_clk, atmel_spi0, pba, 0);
+
+static struct resource atmel_spi1_resource[] = {
+ PBMEM(0xffe00400),
+ IRQ(4),
+};
+DEFINE_DEV(atmel_spi, 1);
+DEV_CLK(spi_clk, atmel_spi1, pba, 1);
struct platform_device *__init at32_add_device_spi(unsigned int id)
{
@@ -713,13 +756,33 @@ struct platform_device *__init at32_add_device_spi(unsigned int id)
switch (id) {
case 0:
- pdev = &spi0_device;
- portmux_set_func(PIOA, 0, FUNC_A); /* MISO */
- portmux_set_func(PIOA, 1, FUNC_A); /* MOSI */
- portmux_set_func(PIOA, 2, FUNC_A); /* SCK */
- portmux_set_func(PIOA, 3, FUNC_A); /* NPCS0 */
- portmux_set_func(PIOA, 4, FUNC_A); /* NPCS1 */
- portmux_set_func(PIOA, 5, FUNC_A); /* NPCS2 */
+ pdev = &atmel_spi0_device;
+ select_peripheral(PA(0), PERIPH_A, 0); /* MISO */
+ select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */
+ select_peripheral(PA(2), PERIPH_A, 0); /* SCK */
+
+ /* NPCS[2:0] */
+ at32_select_gpio(GPIO_PIN_PA(3),
+ AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+ at32_select_gpio(GPIO_PIN_PA(4),
+ AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+ at32_select_gpio(GPIO_PIN_PA(5),
+ AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+ break;
+
+ case 1:
+ pdev = &atmel_spi1_device;
+ select_peripheral(PB(0), PERIPH_B, 0); /* MISO */
+ select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */
+ select_peripheral(PB(5), PERIPH_B, 0); /* SCK */
+
+ /* NPCS[2:0] */
+ at32_select_gpio(GPIO_PIN_PB(2),
+ AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+ at32_select_gpio(GPIO_PIN_PB(3),
+ AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+ at32_select_gpio(GPIO_PIN_PB(4),
+ AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
break;
default:
@@ -762,37 +825,37 @@ at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data)
switch (id) {
case 0:
pdev = &lcdc0_device;
- portmux_set_func(PIOC, 19, FUNC_A); /* CC */
- portmux_set_func(PIOC, 20, FUNC_A); /* HSYNC */
- portmux_set_func(PIOC, 21, FUNC_A); /* PCLK */
- portmux_set_func(PIOC, 22, FUNC_A); /* VSYNC */
- portmux_set_func(PIOC, 23, FUNC_A); /* DVAL */
- portmux_set_func(PIOC, 24, FUNC_A); /* MODE */
- portmux_set_func(PIOC, 25, FUNC_A); /* PWR */
- portmux_set_func(PIOC, 26, FUNC_A); /* DATA0 */
- portmux_set_func(PIOC, 27, FUNC_A); /* DATA1 */
- portmux_set_func(PIOC, 28, FUNC_A); /* DATA2 */
- portmux_set_func(PIOC, 29, FUNC_A); /* DATA3 */
- portmux_set_func(PIOC, 30, FUNC_A); /* DATA4 */
- portmux_set_func(PIOC, 31, FUNC_A); /* DATA5 */
- portmux_set_func(PIOD, 0, FUNC_A); /* DATA6 */
- portmux_set_func(PIOD, 1, FUNC_A); /* DATA7 */
- portmux_set_func(PIOD, 2, FUNC_A); /* DATA8 */
- portmux_set_func(PIOD, 3, FUNC_A); /* DATA9 */
- portmux_set_func(PIOD, 4, FUNC_A); /* DATA10 */
- portmux_set_func(PIOD, 5, FUNC_A); /* DATA11 */
- portmux_set_func(PIOD, 6, FUNC_A); /* DATA12 */
- portmux_set_func(PIOD, 7, FUNC_A); /* DATA13 */
- portmux_set_func(PIOD, 8, FUNC_A); /* DATA14 */
- portmux_set_func(PIOD, 9, FUNC_A); /* DATA15 */
- portmux_set_func(PIOD, 10, FUNC_A); /* DATA16 */
- portmux_set_func(PIOD, 11, FUNC_A); /* DATA17 */
- portmux_set_func(PIOD, 12, FUNC_A); /* DATA18 */
- portmux_set_func(PIOD, 13, FUNC_A); /* DATA19 */
- portmux_set_func(PIOD, 14, FUNC_A); /* DATA20 */
- portmux_set_func(PIOD, 15, FUNC_A); /* DATA21 */
- portmux_set_func(PIOD, 16, FUNC_A); /* DATA22 */
- portmux_set_func(PIOD, 17, FUNC_A); /* DATA23 */
+ select_peripheral(PC(19), PERIPH_A, 0); /* CC */
+ select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */
+ select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */
+ select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */
+ select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */
+ select_peripheral(PC(24), PERIPH_A, 0); /* MODE */
+ select_peripheral(PC(25), PERIPH_A, 0); /* PWR */
+ select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */
+ select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */
+ select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */
+ select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */
+ select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */
+ select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */
+ select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */
+ select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */
+ select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */
+ select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */
+ select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */
+ select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */
+ select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */
+ select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */
+ select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */
+ select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */
+ select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
+ select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
+ select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
+ select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
+ select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
+ select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
+ select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
+ select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
clk_set_parent(&lcdc0_pixclk, &pll0);
clk_set_rate(&lcdc0_pixclk, clk_get_rate(&pll0));
@@ -832,13 +895,17 @@ struct clk *at32_clock_list[] = {
&pio1_mck,
&pio2_mck,
&pio3_mck,
+ &pio4_mck,
&atmel_usart0_usart,
&atmel_usart1_usart,
&atmel_usart2_usart,
&atmel_usart3_usart,
&macb0_hclk,
&macb0_pclk,
- &spi0_mck,
+ &macb1_hclk,
+ &macb1_pclk,
+ &atmel_spi0_spi_clk,
+ &atmel_spi1_spi_clk,
&lcdc0_hclk,
&lcdc0_pixclk,
};
@@ -850,6 +917,7 @@ void __init at32_portmux_init(void)
at32_init_pio(&pio1_device);
at32_init_pio(&pio2_device);
at32_init_pio(&pio3_device);
+ at32_init_pio(&pio4_device);
}
void __init at32_clock_init(void)
diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c
index 4dff1f98890..4a60eccfebd 100644
--- a/arch/avr32/mach-at32ap/extint.c
+++ b/arch/avr32/mach-at32ap/extint.c
@@ -49,13 +49,17 @@ static void eim_unmask_irq(unsigned int irq)
static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
{
struct at32_sm *sm = get_irq_chip_data(irq);
+ struct irq_desc *desc;
unsigned int i = irq - sm->eim_first_irq;
u32 mode, edge, level;
unsigned long flags;
int ret = 0;
flow_type &= IRQ_TYPE_SENSE_MASK;
+ if (flow_type == IRQ_TYPE_NONE)
+ flow_type = IRQ_TYPE_LEVEL_LOW;
+ desc = &irq_desc[irq];
spin_lock_irqsave(&sm->lock, flags);
mode = sm_readl(sm, EIM_MODE);
@@ -84,9 +88,16 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
break;
}
- sm_writel(sm, EIM_MODE, mode);
- sm_writel(sm, EIM_EDGE, edge);
- sm_writel(sm, EIM_LEVEL, level);
+ if (ret == 0) {
+ sm_writel(sm, EIM_MODE, mode);
+ sm_writel(sm, EIM_EDGE, edge);
+ sm_writel(sm, EIM_LEVEL, level);
+
+ if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+ flow_type |= IRQ_LEVEL;
+ desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+ desc->status |= flow_type;
+ }
spin_unlock_irqrestore(&sm->lock, flags);
@@ -109,8 +120,6 @@ static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
unsigned long status, pending;
unsigned int i, ext_irq;
- spin_lock(&sm->lock);
-
status = sm_readl(sm, EIM_ISR);
pending = status & sm_readl(sm, EIM_IMR);
@@ -120,10 +129,11 @@ 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);
+ if (ext_desc->status & IRQ_LEVEL)
+ handle_level_irq(ext_irq, ext_desc);
+ else
+ handle_edge_irq(ext_irq, ext_desc);
}
-
- spin_unlock(&sm->lock);
}
static int __init eim_init(void)
@@ -148,10 +158,16 @@ static int __init eim_init(void)
pattern = sm_readl(sm, EIM_MODE);
nr_irqs = fls(pattern);
+ /* Trigger on falling edge unless overridden by driver */
+ sm_writel(sm, EIM_MODE, 0UL);
+ sm_writel(sm, EIM_EDGE, 0UL);
+
sm->eim_chip = &eim_chip;
for (i = 0; i < nr_irqs; i++) {
- set_irq_chip(sm->eim_first_irq + i, &eim_chip);
+ /* NOTE the handler we set here is ignored by the demux */
+ set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip,
+ handle_level_irq);
set_irq_chip_data(sm->eim_first_irq + i, sm);
}
diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c
index eb87a18ad7b..dd5c009cf22 100644
--- a/arch/avr32/mach-at32ap/intc.c
+++ b/arch/avr32/mach-at32ap/intc.c
@@ -136,3 +136,7 @@ fail:
panic("Interrupt controller initialization failed!\n");
}
+unsigned long intc_get_pending(int group)
+{
+ return intc_readl(&intc0, INTREQ0 + 4 * group);
+}
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index d3aabfca859..9ba5654cde1 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -12,7 +12,9 @@
#include <linux/debugfs.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/portmux.h>
@@ -25,43 +27,328 @@ struct pio_device {
void __iomem *regs;
const struct platform_device *pdev;
struct clk *clk;
- u32 alloc_mask;
- char name[32];
+ u32 pinmux_mask;
+ u32 gpio_mask;
+ char name[8];
};
static struct pio_device pio_dev[MAX_NR_PIO_DEVICES];
-void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
- unsigned int function_id)
+static struct pio_device *gpio_to_pio(unsigned int gpio)
{
struct pio_device *pio;
- u32 mask = 1 << pin_id;
+ unsigned int index;
- BUG_ON(portmux_id >= MAX_NR_PIO_DEVICES);
+ index = gpio >> 5;
+ if (index >= MAX_NR_PIO_DEVICES)
+ return NULL;
+ pio = &pio_dev[index];
+ if (!pio->regs)
+ return NULL;
- pio = &pio_dev[portmux_id];
+ return pio;
+}
+
+/* Pin multiplexing API */
+
+void __init at32_select_periph(unsigned int pin, unsigned int periph,
+ unsigned long flags)
+{
+ struct pio_device *pio;
+ unsigned int pin_index = pin & 0x1f;
+ u32 mask = 1 << pin_index;
+
+ pio = gpio_to_pio(pin);
+ if (unlikely(!pio)) {
+ printk("pio: invalid pin %u\n", pin);
+ goto fail;
+ }
- if (function_id)
+ if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+ printk("%s: pin %u is busy\n", pio->name, pin_index);
+ goto fail;
+ }
+
+ pio_writel(pio, PUER, mask);
+ if (periph)
pio_writel(pio, BSR, mask);
else
pio_writel(pio, ASR, mask);
+
pio_writel(pio, PDR, mask);
+ if (!(flags & AT32_GPIOF_PULLUP))
+ pio_writel(pio, PUDR, mask);
+
+ /* gpio_request NOT allowed */
+ set_bit(pin_index, &pio->gpio_mask);
+
+ return;
+
+fail:
+ dump_stack();
+}
+
+void __init at32_select_gpio(unsigned int pin, unsigned long flags)
+{
+ struct pio_device *pio;
+ unsigned int pin_index = pin & 0x1f;
+ u32 mask = 1 << pin_index;
+
+ pio = gpio_to_pio(pin);
+ if (unlikely(!pio)) {
+ printk("pio: invalid pin %u\n", pin);
+ goto fail;
+ }
+
+ if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+ printk("%s: pin %u is busy\n", pio->name, pin_index);
+ goto fail;
+ }
+
+ if (flags & AT32_GPIOF_OUTPUT) {
+ if (flags & AT32_GPIOF_HIGH)
+ pio_writel(pio, SODR, mask);
+ else
+ pio_writel(pio, CODR, mask);
+ pio_writel(pio, PUDR, mask);
+ pio_writel(pio, OER, mask);
+ } else {
+ if (flags & AT32_GPIOF_PULLUP)
+ pio_writel(pio, PUER, mask);
+ else
+ pio_writel(pio, PUDR, mask);
+ if (flags & AT32_GPIOF_DEGLITCH)
+ pio_writel(pio, IFER, mask);
+ else
+ pio_writel(pio, IFDR, mask);
+ pio_writel(pio, ODR, mask);
+ }
+
+ pio_writel(pio, PER, mask);
+
+ /* gpio_request now allowed */
+ clear_bit(pin_index, &pio->gpio_mask);
+
+ return;
+
+fail:
+ dump_stack();
+}
+
+/* Reserve a pin, preventing anyone else from changing its configuration. */
+void __init at32_reserve_pin(unsigned int pin)
+{
+ struct pio_device *pio;
+ unsigned int pin_index = pin & 0x1f;
+
+ pio = gpio_to_pio(pin);
+ if (unlikely(!pio)) {
+ printk("pio: invalid pin %u\n", pin);
+ goto fail;
+ }
+
+ if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+ printk("%s: pin %u is busy\n", pio->name, pin_index);
+ goto fail;
+ }
+
+ return;
+
+fail:
+ dump_stack();
}
+/*--------------------------------------------------------------------------*/
+
+/* GPIO API */
+
+int gpio_request(unsigned int gpio, const char *label)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ if (!pio)
+ return -ENODEV;
+
+ pin = gpio & 0x1f;
+ if (test_and_set_bit(pin, &pio->gpio_mask))
+ return -EBUSY;
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned int gpio)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ if (!pio) {
+ printk(KERN_ERR
+ "gpio: attempted to free invalid pin %u\n", gpio);
+ return;
+ }
+
+ pin = gpio & 0x1f;
+ if (!test_and_clear_bit(pin, &pio->gpio_mask))
+ printk(KERN_ERR "gpio: freeing free or non-gpio pin %s-%u\n",
+ pio->name, pin);
+}
+EXPORT_SYMBOL(gpio_free);
+
+int gpio_direction_input(unsigned int gpio)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ if (!pio)
+ return -ENODEV;
+
+ pin = gpio & 0x1f;
+ pio_writel(pio, ODR, 1 << pin);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned int gpio)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ if (!pio)
+ return -ENODEV;
+
+ pin = gpio & 0x1f;
+ pio_writel(pio, OER, 1 << pin);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+int gpio_get_value(unsigned int gpio)
+{
+ struct pio_device *pio = &pio_dev[gpio >> 5];
+
+ return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1;
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+void gpio_set_value(unsigned int gpio, int value)
+{
+ struct pio_device *pio = &pio_dev[gpio >> 5];
+ u32 mask;
+
+ mask = 1 << (gpio & 0x1f);
+ if (value)
+ pio_writel(pio, SODR, mask);
+ else
+ pio_writel(pio, CODR, mask);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+/*--------------------------------------------------------------------------*/
+
+/* GPIO IRQ support */
+
+static void gpio_irq_mask(unsigned irq)
+{
+ unsigned gpio = irq_to_gpio(irq);
+ struct pio_device *pio = &pio_dev[gpio >> 5];
+
+ pio_writel(pio, IDR, 1 << (gpio & 0x1f));
+}
+
+static void gpio_irq_unmask(unsigned irq)
+{
+ unsigned gpio = irq_to_gpio(irq);
+ struct pio_device *pio = &pio_dev[gpio >> 5];
+
+ pio_writel(pio, IER, 1 << (gpio & 0x1f));
+}
+
+static int gpio_irq_type(unsigned irq, unsigned type)
+{
+ if (type != IRQ_TYPE_EDGE_BOTH && type != IRQ_TYPE_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct irq_chip gpio_irqchip = {
+ .name = "gpio",
+ .mask = gpio_irq_mask,
+ .unmask = gpio_irq_unmask,
+ .set_type = gpio_irq_type,
+};
+
+static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct pio_device *pio = get_irq_chip_data(irq);
+ unsigned gpio_irq;
+
+ gpio_irq = (unsigned) get_irq_data(irq);
+ for (;;) {
+ u32 isr;
+ struct irq_desc *d;
+
+ /* ack pending GPIO interrupts */
+ isr = pio_readl(pio, ISR) & pio_readl(pio, IMR);
+ if (!isr)
+ break;
+ do {
+ int i;
+
+ i = ffs(isr) - 1;
+ isr &= ~(1 << i);
+
+ i += gpio_irq;
+ d = &irq_desc[i];
+
+ d->handle_irq(i, d);
+ } while (isr);
+ }
+}
+
+static void __init
+gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq)
+{
+ unsigned i;
+
+ set_irq_chip_data(irq, pio);
+ set_irq_data(irq, (void *) gpio_irq);
+
+ for (i = 0; i < 32; i++, gpio_irq++) {
+ set_irq_chip_data(gpio_irq, pio);
+ set_irq_chip_and_handler(gpio_irq, &gpio_irqchip,
+ handle_simple_irq);
+ }
+
+ set_irq_chained_handler(irq, gpio_irq_handler);
+}
+
+/*--------------------------------------------------------------------------*/
+
static int __init pio_probe(struct platform_device *pdev)
{
struct pio_device *pio = NULL;
+ int irq = platform_get_irq(pdev, 0);
+ int gpio_irq_base = GPIO_IRQ_BASE + pdev->id * 32;
BUG_ON(pdev->id >= MAX_NR_PIO_DEVICES);
pio = &pio_dev[pdev->id];
BUG_ON(!pio->regs);
- /* TODO: Interrupts */
+ gpio_irq_setup(pio, irq, gpio_irq_base);
platform_set_drvdata(pdev, pio);
- printk(KERN_INFO "%s: Atmel Port Multiplexer at 0x%p (irq %d)\n",
- pio->name, pio->regs, platform_get_irq(pdev, 0));
+ printk(KERN_DEBUG "%s: base 0x%p, irq %d chains %d..%d\n",
+ pio->name, pio->regs, irq, gpio_irq_base, gpio_irq_base + 31);
return 0;
}
@@ -77,7 +364,7 @@ static int __init pio_init(void)
{
return platform_driver_register(&pio_driver);
}
-subsys_initcall(pio_init);
+postcore_initcall(pio_init);
void __init at32_init_pio(struct platform_device *pdev)
{
@@ -113,6 +400,13 @@ void __init at32_init_pio(struct platform_device *pdev)
pio->pdev = pdev;
pio->regs = ioremap(regs->start, regs->end - regs->start + 1);
- pio_writel(pio, ODR, ~0UL);
- pio_writel(pio, PER, ~0UL);
+ /*
+ * request_gpio() is only valid for pins that have been
+ * explicitly configured as GPIO and not previously requested
+ */
+ pio->gpio_mask = ~0UL;
+
+ /* start with irqs disabled and acked */
+ pio_writel(pio, IDR, ~0UL);
+ (void) pio_readl(pio, ISR);
}
diff --git a/arch/avr32/mach-at32ap/sm.c b/arch/avr32/mach-at32ap/sm.c
deleted file mode 100644
index 03306eb0345..00000000000
--- a/arch/avr32/mach-at32ap/sm.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * System Manager driver for AT32AP CPUs
- *
- * Copyright (C) 2006 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/spinlock.h>
-
-#include <asm/intc.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include <asm/arch/sm.h>
-
-#include "sm.h"
-
-#define SM_EIM_IRQ_RESOURCE 1
-#define SM_PM_IRQ_RESOURCE 2
-#define SM_RTC_IRQ_RESOURCE 3
-
-#define to_eim(irqc) container_of(irqc, struct at32_sm, irqc)
-
-struct at32_sm system_manager;
-
-int __init at32_sm_init(void)
-{
- struct resource *regs;
- struct at32_sm *sm = &system_manager;
- int ret = -ENXIO;
-
- regs = platform_get_resource(&at32_sm_device, IORESOURCE_MEM, 0);
- if (!regs)
- goto fail;
-
- spin_lock_init(&sm->lock);
- sm->pdev = &at32_sm_device;
-
- ret = -ENOMEM;
- sm->regs = ioremap(regs->start, regs->end - regs->start + 1);
- if (!sm->regs)
- goto fail;
-
- return 0;
-
-fail:
- printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret);
- return ret;
-}
-
-/*
- * External Interrupt Module (EIM).
- *
- * EIM gets level- or edge-triggered interrupts of either polarity
- * from the outside and converts it to active-high level-triggered
- * interrupts that the internal interrupt controller can handle. EIM
- * also provides masking/unmasking of interrupts, as well as
- * acknowledging of edge-triggered interrupts.
- */
-
-static irqreturn_t spurious_eim_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
-{
- printk(KERN_WARNING "Spurious EIM interrupt %d\n", irq);
- disable_irq(irq);
- return IRQ_NONE;
-}
-
-static struct irqaction eim_spurious_action = {
- .handler = spurious_eim_interrupt,
-};
-
-static irqreturn_t eim_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct irq_controller * irqc = dev_id;
- struct at32_sm *sm = to_eim(irqc);
- unsigned long pending;
-
- /*
- * No need to disable interrupts globally. The interrupt
- * level relevant to this group must be masked all the time,
- * so we know that this particular EIM instance will not be
- * re-entered.
- */
- spin_lock(&sm->lock);
-
- pending = intc_get_pending(sm->irqc.irq_group);
- if (unlikely(!pending)) {
- printk(KERN_ERR "EIM (group %u): No interrupts pending!\n",
- sm->irqc.irq_group);
- goto unlock;
- }
-
- do {
- struct irqaction *action;
- unsigned int i;
-
- i = fls(pending) - 1;
- pending &= ~(1 << i);
- action = sm->action[i];
-
- /* Acknowledge the interrupt */
- sm_writel(sm, EIM_ICR, 1 << i);
-
- spin_unlock(&sm->lock);
-
- if (action->flags & SA_INTERRUPT)
- local_irq_disable();
- action->handler(sm->irqc.first_irq + i, action->dev_id, regs);
- local_irq_enable();
- spin_lock(&sm->lock);
- if (action->flags & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(sm->irqc.first_irq + i);
- } while (pending);
-
-unlock:
- spin_unlock(&sm->lock);
- return IRQ_HANDLED;
-}
-
-static void eim_mask(struct irq_controller *irqc, unsigned int irq)
-{
- struct at32_sm *sm = to_eim(irqc);
- unsigned int i;
-
- i = irq - sm->irqc.first_irq;
- sm_writel(sm, EIM_IDR, 1 << i);
-}
-
-static void eim_unmask(struct irq_controller *irqc, unsigned int irq)
-{
- struct at32_sm *sm = to_eim(irqc);
- unsigned int i;
-
- i = irq - sm->irqc.first_irq;
- sm_writel(sm, EIM_IER, 1 << i);
-}
-
-static int eim_setup(struct irq_controller *irqc, unsigned int irq,
- struct irqaction *action)
-{
- struct at32_sm *sm = to_eim(irqc);
- sm->action[irq - sm->irqc.first_irq] = action;
- /* Acknowledge earlier interrupts */
- sm_writel(sm, EIM_ICR, (1<<(irq - sm->irqc.first_irq)));
- eim_unmask(irqc, irq);
- return 0;
-}
-
-static void eim_free(struct irq_controller *irqc, unsigned int irq,
- void *dev)
-{
- struct at32_sm *sm = to_eim(irqc);
- eim_mask(irqc, irq);
- sm->action[irq - sm->irqc.first_irq] = &eim_spurious_action;
-}
-
-static int eim_set_type(struct irq_controller *irqc, unsigned int irq,
- unsigned int type)
-{
- struct at32_sm *sm = to_eim(irqc);
- unsigned long flags;
- u32 value, pattern;
-
- spin_lock_irqsave(&sm->lock, flags);
-
- pattern = 1 << (irq - sm->irqc.first_irq);
-
- value = sm_readl(sm, EIM_MODE);
- if (type & IRQ_TYPE_LEVEL)
- value |= pattern;
- else
- value &= ~pattern;
- sm_writel(sm, EIM_MODE, value);
- value = sm_readl(sm, EIM_EDGE);
- if (type & IRQ_EDGE_RISING)
- value |= pattern;
- else
- value &= ~pattern;
- sm_writel(sm, EIM_EDGE, value);
- value = sm_readl(sm, EIM_LEVEL);
- if (type & IRQ_LEVEL_HIGH)
- value |= pattern;
- else
- value &= ~pattern;
- sm_writel(sm, EIM_LEVEL, value);
-
- spin_unlock_irqrestore(&sm->lock, flags);
-
- return 0;
-}
-
-static unsigned int eim_get_type(struct irq_controller *irqc,
- unsigned int irq)
-{
- struct at32_sm *sm = to_eim(irqc);
- unsigned long flags;
- unsigned int type = 0;
- u32 mode, edge, level, pattern;
-
- pattern = 1 << (irq - sm->irqc.first_irq);
-
- spin_lock_irqsave(&sm->lock, flags);
- mode = sm_readl(sm, EIM_MODE);
- edge = sm_readl(sm, EIM_EDGE);
- level = sm_readl(sm, EIM_LEVEL);
- spin_unlock_irqrestore(&sm->lock, flags);
-
- if (mode & pattern)
- type |= IRQ_TYPE_LEVEL;
- if (edge & pattern)
- type |= IRQ_EDGE_RISING;
- if (level & pattern)
- type |= IRQ_LEVEL_HIGH;
-
- return type;
-}
-
-static struct irq_controller_class eim_irq_class = {
- .typename = "EIM",
- .handle = eim_handle_irq,
- .setup = eim_setup,
- .free = eim_free,
- .mask = eim_mask,
- .unmask = eim_unmask,
- .set_type = eim_set_type,
- .get_type = eim_get_type,
-};
-
-static int __init eim_init(void)
-{
- struct at32_sm *sm = &system_manager;
- unsigned int i;
- u32 pattern;
- int ret;
-
- /*
- * The EIM is really the same module as SM, so register
- * mapping, etc. has been taken care of already.
- */
-
- /*
- * Find out how many interrupt lines that are actually
- * implemented in hardware.
- */
- sm_writel(sm, EIM_IDR, ~0UL);
- sm_writel(sm, EIM_MODE, ~0UL);
- pattern = sm_readl(sm, EIM_MODE);
- sm->irqc.nr_irqs = fls(pattern);
-
- ret = -ENOMEM;
- sm->action = kmalloc(sizeof(*sm->action) * sm->irqc.nr_irqs,
- GFP_KERNEL);
- if (!sm->action)
- goto out;
-
- for (i = 0; i < sm->irqc.nr_irqs; i++)
- sm->action[i] = &eim_spurious_action;
-
- spin_lock_init(&sm->lock);
- sm->irqc.irq_group = sm->pdev->resource[SM_EIM_IRQ_RESOURCE].start;
- sm->irqc.class = &eim_irq_class;
-
- ret = intc_register_controller(&sm->irqc);
- if (ret < 0)
- goto out_free_actions;
-
- printk("EIM: External Interrupt Module at 0x%p, IRQ group %u\n",
- sm->regs, sm->irqc.irq_group);
- printk("EIM: Handling %u external IRQs, starting with IRQ%u\n",
- sm->irqc.nr_irqs, sm->irqc.first_irq);
-
- return 0;
-
-out_free_actions:
- kfree(sm->action);
-out:
- return ret;
-}
-arch_initcall(eim_init);
diff --git a/arch/avr32/mm/cache.c b/arch/avr32/mm/cache.c
index 450515b245a..fb13f72e9a0 100644
--- a/arch/avr32/mm/cache.c
+++ b/arch/avr32/mm/cache.c
@@ -22,18 +22,34 @@
void invalidate_dcache_region(void *start, size_t size)
{
- unsigned long v, begin, end, linesz;
+ unsigned long v, begin, end, linesz, mask;
+ int flush = 0;
linesz = boot_cpu_data.dcache.linesz;
+ mask = linesz - 1;
+
+ /* when first and/or last cachelines are shared, flush them
+ * instead of invalidating ... never discard valid data!
+ */
+ begin = (unsigned long)start;
+ end = begin + size - 1;
+
+ if (begin & mask) {
+ flush_dcache_line(start);
+ begin += linesz;
+ flush = 1;
+ }
+ if ((end & mask) != mask) {
+ flush_dcache_line((void *)end);
+ end -= linesz;
+ flush = 1;
+ }
- //printk("invalidate dcache: %p + %u\n", start, size);
-
- /* You asked for it, you got it */
- begin = (unsigned long)start & ~(linesz - 1);
- end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1);
-
- for (v = begin; v < end; v += linesz)
+ /* remaining cachelines only need invalidation */
+ for (v = begin; v <= end; v += linesz)
invalidate_dcache_line((void *)v);
+ if (flush)
+ flush_write_buffer();
}
void clean_dcache_region(void *start, size_t size)
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index 6a1238a29d6..3474309e049 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -16,6 +16,14 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
diff --git a/arch/cris/arch-v10/drivers/axisflashmap.c b/arch/cris/arch-v10/drivers/axisflashmap.c
index 4fa81abab0c..ffade19a14e 100644
--- a/arch/cris/arch-v10/drivers/axisflashmap.c
+++ b/arch/cris/arch-v10/drivers/axisflashmap.c
@@ -516,7 +516,7 @@ static int __init init_axis_flash(void)
#else
struct mtd_info *mtd_ram;
- mtd_ram = (struct mtd_info *)kmalloc(sizeof(struct mtd_info),
+ mtd_ram = kmalloc(sizeof(struct mtd_info),
GFP_KERNEL);
if (!mtd_ram) {
panic("axisflashmap couldn't allocate memory for "
diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c
index fcba6632ed7..9aba18b931d 100644
--- a/arch/cris/arch-v10/drivers/gpio.c
+++ b/arch/cris/arch-v10/drivers/gpio.c
@@ -440,7 +440,7 @@ gpio_open(struct inode *inode, struct file *filp)
if (p > GPIO_MINOR_LAST)
return -EINVAL;
- priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private),
+ priv = kmalloc(sizeof(struct gpio_private),
GFP_KERNEL);
if (!priv)
diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c
index 41952320e00..5180d45412f 100644
--- a/arch/cris/arch-v32/drivers/axisflashmap.c
+++ b/arch/cris/arch-v32/drivers/axisflashmap.c
@@ -427,7 +427,7 @@ static int __init init_axis_flash(void)
#else
struct mtd_info *mtd_ram;
- mtd_ram = (struct mtd_info *)kmalloc(sizeof(struct mtd_info),
+ mtd_ram = kmalloc(sizeof(struct mtd_info),
GFP_KERNEL);
if (!mtd_ram) {
panic("axisflashmap couldn't allocate memory for "
diff --git a/arch/cris/arch-v32/drivers/gpio.c b/arch/cris/arch-v32/drivers/gpio.c
index c3f876b4da6..08d36f0955c 100644
--- a/arch/cris/arch-v32/drivers/gpio.c
+++ b/arch/cris/arch-v32/drivers/gpio.c
@@ -423,7 +423,7 @@ gpio_open(struct inode *inode, struct file *filp)
if (p > GPIO_MINOR_LAST)
return -EINVAL;
- priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private),
+ priv = kmalloc(sizeof(struct gpio_private),
GFP_KERNEL);
if (!priv)
diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c
index e067806b220..424eb0eb1cd 100644
--- a/arch/cris/arch-v32/drivers/sync_serial.c
+++ b/arch/cris/arch-v32/drivers/sync_serial.c
@@ -504,7 +504,7 @@ static int sync_serial_release(struct inode *inode, struct file *file)
static unsigned int sync_serial_poll(struct file *file, poll_table *wait)
{
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
unsigned int mask = 0;
sync_port* port;
DEBUGPOLL( static unsigned int prev_mask = 0; );
@@ -531,7 +531,7 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int return_val = 0;
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
sync_port* port;
reg_sser_rw_tr_cfg tr_cfg;
reg_sser_rw_rec_cfg rec_cfg;
@@ -789,7 +789,7 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file,
static ssize_t sync_serial_write(struct file * file, const char * buf,
size_t count, loff_t *ppos)
{
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
DECLARE_WAITQUEUE(wait, current);
sync_port *port;
unsigned long c, c1;
@@ -919,7 +919,7 @@ static ssize_t sync_serial_write(struct file * file, const char * buf,
static ssize_t sync_serial_read(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
int avail;
sync_port *port;
unsigned char* start;
diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c
index 99e59b3eacf..7cd6ac80340 100644
--- a/arch/cris/arch-v32/kernel/signal.c
+++ b/arch/cris/arch-v32/kernel/signal.c
@@ -686,7 +686,7 @@ keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
int __init
cris_init_signal(void)
{
- u16* data = (u16*)kmalloc(PAGE_SIZE, GFP_KERNEL);
+ u16* data = kmalloc(PAGE_SIZE, GFP_KERNEL);
/* This is movu.w __NR_sigreturn, r9; break 13; */
data[0] = 0x9c5f;
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c
index 2d0023f2d49..77e655f2656 100644
--- a/arch/cris/arch-v32/kernel/smp.c
+++ b/arch/cris/arch-v32/kernel/smp.c
@@ -195,7 +195,7 @@ int setup_profiling_timer(unsigned int multiplier)
*/
unsigned long cache_decay_ticks = 1;
-int __devinit __cpu_up(unsigned int cpu)
+int __cpuinit __cpu_up(unsigned int cpu)
{
smp_boot_one_cpu(cpu);
return cpu_online(cpu) ? 0 : -ENOSYS;
diff --git a/arch/cris/kernel/profile.c b/arch/cris/kernel/profile.c
index 69c52189f04..f60ab785f23 100644
--- a/arch/cris/kernel/profile.c
+++ b/arch/cris/kernel/profile.c
@@ -59,7 +59,7 @@ static int
__init init_cris_profile(void)
{
struct proc_dir_entry *entry;
- sample_buffer = (char*)kmalloc(SAMPLE_BUFFER_SIZE, GFP_KERNEL);
+ sample_buffer = kmalloc(SAMPLE_BUFFER_SIZE, GFP_KERNEL);
sample_buffer_pos = sample_buffer;
entry = create_proc_entry("system_profile", S_IWUSR | S_IRUGO, NULL);
if (entry) {
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index cf1c446e003..7561d7b72e7 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -41,6 +41,14 @@ config TIME_LOW_RES
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default y
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default y
+
mainmenu "Fujitsu FR-V Kernel Configuration"
source "init/Kconfig"
diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c
index c1d9fc8f1a8..ee677ced7b6 100644
--- a/arch/frv/kernel/pm.c
+++ b/arch/frv/kernel/pm.c
@@ -223,7 +223,7 @@ static int cmode_procctl(ctl_table *ctl, int write, struct file *filp,
static int cmode_sysctl(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
if (oldval && oldlenp) {
size_t oldlen;
@@ -326,7 +326,7 @@ static int p0_procctl(ctl_table *ctl, int write, struct file *filp,
static int p0_sysctl(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
if (oldval && oldlenp) {
size_t oldlen;
@@ -370,7 +370,7 @@ static int cm_procctl(ctl_table *ctl, int write, struct file *filp,
static int cm_sysctl(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
if (oldval && oldlenp) {
size_t oldlen;
diff --git a/arch/frv/mm/elf-fdpic.c b/arch/frv/mm/elf-fdpic.c
index f5a653033fe..9477ccce070 100644
--- a/arch/frv/mm/elf-fdpic.c
+++ b/arch/frv/mm/elf-fdpic.c
@@ -110,14 +110,14 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
#if 0
printk("[area] l=%lx (ENOMEM) f='%s'\n",
- len, filp ? filp->f_dentry->d_name.name : "");
+ len, filp ? filp->f_path.dentry->d_name.name : "");
#endif
return -ENOMEM;
success:
#if 0
printk("[area] l=%lx ad=%lx f='%s'\n",
- len, addr, filp ? filp->f_dentry->d_name.name : "");
+ len, addr, filp ? filp->f_path.dentry->d_name.name : "");
#endif
return addr;
} /* end arch_get_unmapped_area() */
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index cabf0bfffc5..34a84bc4baf 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -29,6 +29,14 @@ config RWSEM_XCHGADD_ALGORITHM
bool
default n
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
diff --git a/arch/h8300/kernel/ints.c b/arch/h8300/kernel/ints.c
index 1bfc77e391d..587ef7f4fcc 100644
--- a/arch/h8300/kernel/ints.c
+++ b/arch/h8300/kernel/ints.c
@@ -141,7 +141,7 @@ int request_irq(unsigned int irq,
return -EBUSY;
if (use_kmalloc)
- irq_handle = (irq_handler_t *)kmalloc(sizeof(irq_handler_t), GFP_ATOMIC);
+ irq_handle = kmalloc(sizeof(irq_handler_t), GFP_ATOMIC);
else {
/* use bootmem allocater */
irq_handle = (irq_handler_t *)alloc_bootmem(sizeof(irq_handler_t));
diff --git a/arch/h8300/platform/h8s/ints.c b/arch/h8300/platform/h8s/ints.c
index 270440de461..567f681ddfe 100644
--- a/arch/h8300/platform/h8s/ints.c
+++ b/arch/h8300/platform/h8s/ints.c
@@ -176,7 +176,7 @@ int request_irq(unsigned int irq,
}
if (use_kmalloc)
- irq_handle = (irq_handler_t *)kmalloc(sizeof(irq_handler_t), GFP_ATOMIC);
+ irq_handle = kmalloc(sizeof(irq_handler_t), GFP_ATOMIC);
else {
/* use bootmem allocater */
irq_handle = (irq_handler_t *)alloc_bootmem(sizeof(irq_handler_t));
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index ea70359b02d..0dfee812811 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -49,6 +49,11 @@ config GENERIC_IOMAP
bool
default y
+config GENERIC_BUG
+ bool
+ default y
+ depends on BUG
+
config GENERIC_HWEIGHT
bool
default y
@@ -185,6 +190,7 @@ endchoice
config PARAVIRT
bool "Paravirtualization support (EXPERIMENTAL)"
depends on EXPERIMENTAL
+ depends on !(X86_VISWS || X86_VOYAGER)
help
Paravirtualization is a way of running multiple instances of
Linux on the same machine, under a hypervisor. This option
@@ -771,6 +777,47 @@ config CRASH_DUMP
PHYSICAL_START.
For more details see Documentation/kdump/kdump.txt
+config PHYSICAL_START
+ hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
+ default "0x100000"
+ help
+ This gives the physical address where the kernel is loaded.
+
+ If kernel is a not relocatable (CONFIG_RELOCATABLE=n) then
+ bzImage will decompress itself to above physical address and
+ run from there. Otherwise, bzImage will run from the address where
+ it has been loaded by the boot loader and will ignore above physical
+ address.
+
+ In normal kdump cases one does not have to set/change this option
+ as now bzImage can be compiled as a completely relocatable image
+ (CONFIG_RELOCATABLE=y) and be used to load and run from a different
+ address. This option is mainly useful for the folks who don't want
+ to use a bzImage for capturing the crash dump and want to use a
+ vmlinux instead. vmlinux is not relocatable hence a kernel needs
+ to be specifically compiled to run from a specific memory area
+ (normally a reserved region) and this option comes handy.
+
+ So if you are using bzImage for capturing the crash dump, leave
+ the value here unchanged to 0x100000 and set CONFIG_RELOCATABLE=y.
+ Otherwise if you plan to use vmlinux for capturing the crash dump
+ change this value to start of the reserved region (Typically 16MB
+ 0x1000000). In other words, it can be set based on the "X" value as
+ specified in the "crashkernel=YM@XM" command line boot parameter
+ passed to the panic-ed kernel. Typically this parameter is set as
+ crashkernel=64M@16M. Please take a look at
+ Documentation/kdump/kdump.txt for more details about crash dumps.
+
+ Usage of bzImage for capturing the crash dump is recommended as
+ one does not have to build two kernels. Same kernel can be used
+ as production kernel and capture kernel. Above option should have
+ gone away after relocatable bzImage support is introduced. But it
+ is present because there are users out there who continue to use
+ vmlinux for dump capture. This option should go away down the
+ line.
+
+ Don't change this unless you know what you are doing.
+
config RELOCATABLE
bool "Build a relocatable kernel(EXPERIMENTAL)"
depends on EXPERIMENTAL
diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu
index 821fd269ca5..2aecfba4ac4 100644
--- a/arch/i386/Kconfig.cpu
+++ b/arch/i386/Kconfig.cpu
@@ -248,6 +248,14 @@ config RWSEM_XCHGADD_ALGORITHM
depends on !M386
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_CALIBRATE_DELAY
bool
default y
diff --git a/arch/i386/boot/compressed/.gitignore b/arch/i386/boot/compressed/.gitignore
new file mode 100644
index 00000000000..be0ed065249
--- /dev/null
+++ b/arch/i386/boot/compressed/.gitignore
@@ -0,0 +1 @@
+relocs
diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S
index f395a4bb38b..3517a32aaf4 100644
--- a/arch/i386/boot/compressed/head.S
+++ b/arch/i386/boot/compressed/head.S
@@ -28,7 +28,7 @@
#include <asm/page.h>
#include <asm/boot.h>
-.section ".text.head"
+.section ".text.head","ax",@progbits
.globl startup_32
startup_32:
diff --git a/arch/i386/boot/compressed/relocs.c b/arch/i386/boot/compressed/relocs.c
index 468da89153c..881951ca03e 100644
--- a/arch/i386/boot/compressed/relocs.c
+++ b/arch/i386/boot/compressed/relocs.c
@@ -43,6 +43,8 @@ static int is_safe_abs_reloc(const char* sym_name)
/* Match found */
return 1;
}
+ if (strncmp(sym_name, "__crc_", 6) == 0)
+ return 1;
return 0;
}
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 65891f11ace..bb0c376b62b 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.19-git7
-# Wed Dec 6 23:50:49 2006
+# Linux kernel version: 2.6.20-rc3
+# Fri Jan 5 11:54:46 2007
#
CONFIG_X86_32=y
CONFIG_GENERIC_TIME=y
@@ -12,6 +12,7 @@ CONFIG_X86=y
CONFIG_MMU=y
CONFIG_GENERIC_ISA_DMA=y
CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_DMI=y
@@ -141,6 +142,8 @@ CONFIG_X86_CMPXCHG=y
CONFIG_X86_XADD=y
CONFIG_X86_L1_CACHE_SHIFT=7
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
@@ -203,6 +206,7 @@ CONFIG_MTRR=y
CONFIG_SECCOMP=y
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
# CONFIG_KEXEC is not set
@@ -462,7 +466,8 @@ CONFIG_FW_LOADER=y
#
# Plug and Play support
#
-# CONFIG_PNP is not set
+CONFIG_PNP=y
+CONFIG_PNPACPI=y
#
# Block devices
@@ -563,6 +568,7 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
# CONFIG_SCSI_PROC_FS is not set
@@ -583,6 +589,7 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
#
# SCSI Transports
@@ -642,6 +649,7 @@ CONFIG_AIC79XX_DEBUG_MASK=0
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
#
# Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -1082,10 +1090,7 @@ CONFIG_SOUND=y
# Open Sound System
#
CONFIG_SOUND_PRIME=y
-CONFIG_OSS_OBSOLETE_DRIVER=y
# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_EMU10K1 is not set
-# CONFIG_SOUND_FUSION is not set
# CONFIG_SOUND_ES1371 is not set
CONFIG_SOUND_ICH=y
# CONFIG_SOUND_TRIDENT is not set
@@ -1095,6 +1100,11 @@ CONFIG_SOUND_ICH=y
# CONFIG_SOUND_OSS is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1158,7 +1168,6 @@ CONFIG_USB_STORAGE=y
# 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 is not set
@@ -1279,6 +1288,11 @@ CONFIG_USB_MON=y
#
#
+# Virtualization
+#
+# CONFIG_KVM is not set
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1444,6 +1458,11 @@ CONFIG_NLS_ISO8859_15=y
CONFIG_NLS_UTF8=y
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Instrumentation Support
#
CONFIG_PROFILING=y
@@ -1458,6 +1477,8 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_UNUSED_SYMBOLS=y
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1476,14 +1497,10 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_HIGHMEM 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_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
@@ -1509,12 +1526,14 @@ CONFIG_DOUBLEFAULT=y
#
# Library routines
#
+CONFIG_BITREVERSE=y
# 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
+CONFIG_IOMAP_COPY=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_PENDING_IRQ=y
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index c8f96cff07c..e94aff6888c 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -66,7 +66,7 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return
#define BAD_MADT_ENTRY(entry, end) ( \
(!entry) || (unsigned long)entry + sizeof(*entry) > end || \
- ((acpi_table_entry_header *)entry)->length < sizeof(*entry))
+ ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
#define PREFIX "ACPI: "
@@ -79,7 +79,7 @@ int acpi_ioapic;
int acpi_strict;
EXPORT_SYMBOL(acpi_strict);
-acpi_interrupt_flags acpi_sci_flags __initdata;
+u8 acpi_sci_flags __initdata;
int acpi_sci_override_gsi __initdata;
int acpi_skip_timer_override __initdata;
int acpi_use_timer_override __initdata;
@@ -92,11 +92,6 @@ static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
#warning ACPI uses CMPXCHG, i486 and later hardware
#endif
-#define MAX_MADT_ENTRIES 256
-u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] =
- {[0 ... MAX_MADT_ENTRIES - 1] = 0xff };
-EXPORT_SYMBOL(x86_acpiid_to_apicid);
-
/* --------------------------------------------------------------------------
Boot-time Configuration
-------------------------------------------------------------------------- */
@@ -166,30 +161,26 @@ char *__acpi_map_table(unsigned long phys, unsigned long size)
#ifdef CONFIG_PCI_MMCONFIG
/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
-struct acpi_table_mcfg_config *pci_mmcfg_config;
+struct acpi_mcfg_allocation *pci_mmcfg_config;
int pci_mmcfg_config_num;
-int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
+int __init acpi_parse_mcfg(struct acpi_table_header *header)
{
struct acpi_table_mcfg *mcfg;
unsigned long i;
int config_size;
- if (!phys_addr || !size)
+ if (!header)
return -EINVAL;
- mcfg = (struct acpi_table_mcfg *)__acpi_map_table(phys_addr, size);
- if (!mcfg) {
- printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
- return -ENODEV;
- }
+ mcfg = (struct acpi_table_mcfg *)header;
/* how many config structures do we have */
pci_mmcfg_config_num = 0;
- i = size - sizeof(struct acpi_table_mcfg);
- while (i >= sizeof(struct acpi_table_mcfg_config)) {
+ i = header->length - sizeof(struct acpi_table_mcfg);
+ while (i >= sizeof(struct acpi_mcfg_allocation)) {
++pci_mmcfg_config_num;
- i -= sizeof(struct acpi_table_mcfg_config);
+ i -= sizeof(struct acpi_mcfg_allocation);
};
if (pci_mmcfg_config_num == 0) {
printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
@@ -204,9 +195,9 @@ int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
return -ENOMEM;
}
- memcpy(pci_mmcfg_config, &mcfg->config, config_size);
+ memcpy(pci_mmcfg_config, &mcfg[1], config_size);
for (i = 0; i < pci_mmcfg_config_num; ++i) {
- if (mcfg->config[i].base_reserved) {
+ if (pci_mmcfg_config[i].address > 0xFFFFFFFF) {
printk(KERN_ERR PREFIX
"MMCONFIG not in low 4GB of memory\n");
kfree(pci_mmcfg_config);
@@ -220,24 +211,24 @@ int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
#endif /* CONFIG_PCI_MMCONFIG */
#ifdef CONFIG_X86_LOCAL_APIC
-static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_madt(struct acpi_table_header *table)
{
struct acpi_table_madt *madt = NULL;
- if (!phys_addr || !size || !cpu_has_apic)
+ if (!cpu_has_apic)
return -EINVAL;
- madt = (struct acpi_table_madt *)__acpi_map_table(phys_addr, size);
+ madt = (struct acpi_table_madt *)table;
if (!madt) {
printk(KERN_WARNING PREFIX "Unable to map MADT\n");
return -ENODEV;
}
- if (madt->lapic_address) {
- acpi_lapic_addr = (u64) madt->lapic_address;
+ if (madt->address) {
+ acpi_lapic_addr = (u64) madt->address;
printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n",
- madt->lapic_address);
+ madt->address);
}
acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id);
@@ -246,21 +237,17 @@ static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
}
static int __init
-acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end)
{
- struct acpi_table_lapic *processor = NULL;
+ struct acpi_madt_local_apic *processor = NULL;
- processor = (struct acpi_table_lapic *)header;
+ processor = (struct acpi_madt_local_apic *)header;
if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
acpi_table_print_madt_entry(header);
- /* Record local apic id only when enabled */
- if (processor->flags.enabled)
- x86_acpiid_to_apicid[processor->acpi_id] = processor->id;
-
/*
* We need to register disabled CPU as well to permit
* counting disabled CPUs. This allows us to size
@@ -269,18 +256,18 @@ acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end)
* when we use CPU hotplug.
*/
mp_register_lapic(processor->id, /* APIC ID */
- processor->flags.enabled); /* Enabled? */
+ processor->lapic_flags & ACPI_MADT_ENABLED); /* Enabled? */
return 0;
}
static int __init
-acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header,
+acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
const unsigned long end)
{
- struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL;
+ struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL;
- lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr *)header;
+ lapic_addr_ovr = (struct acpi_madt_local_apic_override *)header;
if (BAD_MADT_ENTRY(lapic_addr_ovr, end))
return -EINVAL;
@@ -291,11 +278,11 @@ acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header,
}
static int __init
-acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
{
- struct acpi_table_lapic_nmi *lapic_nmi = NULL;
+ struct acpi_madt_local_apic_nmi *lapic_nmi = NULL;
- lapic_nmi = (struct acpi_table_lapic_nmi *)header;
+ lapic_nmi = (struct acpi_madt_local_apic_nmi *)header;
if (BAD_MADT_ENTRY(lapic_nmi, end))
return -EINVAL;
@@ -313,11 +300,11 @@ acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end)
#ifdef CONFIG_X86_IO_APIC
static int __init
-acpi_parse_ioapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
{
- struct acpi_table_ioapic *ioapic = NULL;
+ struct acpi_madt_io_apic *ioapic = NULL;
- ioapic = (struct acpi_table_ioapic *)header;
+ ioapic = (struct acpi_madt_io_apic *)header;
if (BAD_MADT_ENTRY(ioapic, end))
return -EINVAL;
@@ -333,7 +320,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 __init acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
{
if (trigger == 0) /* compatible SCI trigger is level */
trigger = 3;
@@ -342,11 +329,11 @@ static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
polarity = 3;
/* Command-line over-ride via acpi_sci= */
- if (acpi_sci_flags.trigger)
- trigger = acpi_sci_flags.trigger;
+ if (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)
+ trigger = (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
- if (acpi_sci_flags.polarity)
- polarity = acpi_sci_flags.polarity;
+ if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK)
+ polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
/*
* mp_config_acpi_legacy_irqs() already setup IRQs < 16
@@ -357,51 +344,52 @@ static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
/*
* stash over-ride to indicate we've been here
- * and for later update of acpi_fadt
+ * and for later update of acpi_gbl_FADT
*/
acpi_sci_override_gsi = gsi;
return;
}
static int __init
-acpi_parse_int_src_ovr(acpi_table_entry_header * header,
+acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
const unsigned long end)
{
- struct acpi_table_int_src_ovr *intsrc = NULL;
+ struct acpi_madt_interrupt_override *intsrc = NULL;
- intsrc = (struct acpi_table_int_src_ovr *)header;
+ intsrc = (struct acpi_madt_interrupt_override *)header;
if (BAD_MADT_ENTRY(intsrc, end))
return -EINVAL;
acpi_table_print_madt_entry(header);
- if (intsrc->bus_irq == acpi_fadt.sci_int) {
+ if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) {
acpi_sci_ioapic_setup(intsrc->global_irq,
- intsrc->flags.polarity,
- intsrc->flags.trigger);
+ intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
+ (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
return 0;
}
if (acpi_skip_timer_override &&
- intsrc->bus_irq == 0 && intsrc->global_irq == 2) {
+ intsrc->source_irq == 0 && intsrc->global_irq == 2) {
printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
return 0;
}
- mp_override_legacy_irq(intsrc->bus_irq,
- intsrc->flags.polarity,
- intsrc->flags.trigger, intsrc->global_irq);
+ mp_override_legacy_irq(intsrc->source_irq,
+ intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
+ (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2,
+ intsrc->global_irq);
return 0;
}
static int __init
-acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end)
{
- struct acpi_table_nmi_src *nmi_src = NULL;
+ struct acpi_madt_nmi_source *nmi_src = NULL;
- nmi_src = (struct acpi_table_nmi_src *)header;
+ nmi_src = (struct acpi_madt_nmi_source *)header;
if (BAD_MADT_ENTRY(nmi_src, end))
return -EINVAL;
@@ -417,7 +405,7 @@ acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end)
/*
* acpi_pic_sci_set_trigger()
- *
+ *
* use ELCR to set PIC-mode trigger type for SCI
*
* If a PIC-mode SCI is not recognized or gives spurious IRQ7's
@@ -511,7 +499,7 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
- struct acpi_table_lapic *lapic;
+ struct acpi_madt_local_apic *lapic;
cpumask_t tmp_map, new_map;
u8 physid;
int cpu;
@@ -529,10 +517,10 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
return -EINVAL;
}
- lapic = (struct acpi_table_lapic *)obj->buffer.pointer;
+ lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer;
- if ((lapic->header.type != ACPI_MADT_LAPIC) ||
- (!lapic->flags.enabled)) {
+ if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC ||
+ !(lapic->lapic_flags & ACPI_MADT_ENABLED)) {
kfree(buffer.pointer);
return -EINVAL;
}
@@ -544,7 +532,7 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
buffer.pointer = NULL;
tmp_map = cpu_present_map;
- mp_register_lapic(physid, lapic->flags.enabled);
+ mp_register_lapic(physid, lapic->lapic_flags & ACPI_MADT_ENABLED);
/*
* If mp_register_lapic successfully generates a new logical cpu
@@ -566,14 +554,6 @@ EXPORT_SYMBOL(acpi_map_lsapic);
int acpi_unmap_lsapic(int cpu)
{
- int i;
-
- for_each_possible_cpu(i) {
- if (x86_acpiid_to_apicid[i] == x86_cpu_to_apicid[cpu]) {
- x86_acpiid_to_apicid[i] = -1;
- break;
- }
- }
x86_cpu_to_apicid[cpu] = -1;
cpu_clear(cpu, cpu_present_map);
num_processors--;
@@ -619,42 +599,36 @@ acpi_scan_rsdp(unsigned long start, unsigned long length)
return 0;
}
-static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_sbf(struct acpi_table_header *table)
{
- struct acpi_table_sbf *sb;
-
- if (!phys_addr || !size)
- return -EINVAL;
+ struct acpi_table_boot *sb;
- sb = (struct acpi_table_sbf *)__acpi_map_table(phys_addr, size);
+ sb = (struct acpi_table_boot *)table;
if (!sb) {
printk(KERN_WARNING PREFIX "Unable to map SBF\n");
return -ENODEV;
}
- sbf_port = sb->sbf_cmos; /* Save CMOS port */
+ sbf_port = sb->cmos_index; /* Save CMOS port */
return 0;
}
#ifdef CONFIG_HPET_TIMER
-static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
+static int __init acpi_parse_hpet(struct acpi_table_header *table)
{
struct acpi_table_hpet *hpet_tbl;
struct resource *hpet_res;
resource_size_t res_start;
- if (!phys || !size)
- return -EINVAL;
-
- hpet_tbl = (struct acpi_table_hpet *)__acpi_map_table(phys, size);
+ hpet_tbl = (struct acpi_table_hpet *)table;
if (!hpet_tbl) {
printk(KERN_WARNING PREFIX "Unable to map HPET\n");
return -ENODEV;
}
- if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) {
+ if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
printk(KERN_WARNING PREFIX "HPET timers must be located in "
"memory.\n");
return -1;
@@ -667,29 +641,28 @@ static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
hpet_res->name = (void *)&hpet_res[1];
hpet_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE,
- "HPET %u", hpet_tbl->number);
+ "HPET %u", hpet_tbl->sequence);
hpet_res->end = (1 * 1024) - 1;
}
-#ifdef CONFIG_X86_64
- vxtime.hpet_address = hpet_tbl->addr.addrl |
- ((long)hpet_tbl->addr.addrh << 32);
+#ifdef CONFIG_X86_64
+ vxtime.hpet_address = hpet_tbl->address.address;
printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
- hpet_tbl->id, vxtime.hpet_address);
+ hpet_tbl->id, vxtime.hpet_address);
res_start = vxtime.hpet_address;
-#else /* X86 */
+#else /* X86 */
{
extern unsigned long hpet_address;
- hpet_address = hpet_tbl->addr.addrl;
+ hpet_address = hpet_tbl->address.address;
printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
- hpet_tbl->id, hpet_address);
+ hpet_tbl->id, hpet_address);
res_start = hpet_address;
}
-#endif /* X86 */
+#endif /* X86 */
if (hpet_res) {
hpet_res->start = res_start;
@@ -707,42 +680,28 @@ static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
extern u32 pmtmr_ioport;
#endif
-static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
+static int __init acpi_parse_fadt(struct acpi_table_header *table)
{
- struct fadt_descriptor *fadt = NULL;
-
- fadt = (struct fadt_descriptor *)__acpi_map_table(phys, size);
- if (!fadt) {
- printk(KERN_WARNING PREFIX "Unable to map FADT\n");
- return 0;
- }
- /* initialize sci_int early for INT_SRC_OVR MADT parsing */
- acpi_fadt.sci_int = fadt->sci_int;
-
- /* initialize rev and apic_phys_dest_mode for x86_64 genapic */
- acpi_fadt.revision = fadt->revision;
- acpi_fadt.force_apic_physical_destination_mode =
- fadt->force_apic_physical_destination_mode;
#ifdef CONFIG_X86_PM_TIMER
/* detect the location of the ACPI PM Timer */
- if (fadt->revision >= FADT2_REVISION_ID) {
+ if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
/* FADT rev. 2 */
- if (fadt->xpm_tmr_blk.address_space_id !=
+ if (acpi_gbl_FADT.xpm_timer_block.space_id !=
ACPI_ADR_SPACE_SYSTEM_IO)
return 0;
- pmtmr_ioport = fadt->xpm_tmr_blk.address;
+ pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
/*
* "X" fields are optional extensions to the original V1.0
* fields, so we must selectively expand V1.0 fields if the
* corresponding X field is zero.
*/
if (!pmtmr_ioport)
- pmtmr_ioport = fadt->V1_pm_tmr_blk;
+ pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
} else {
/* FADT rev. 1 */
- pmtmr_ioport = fadt->V1_pm_tmr_blk;
+ pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
}
if (pmtmr_ioport)
printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
@@ -784,13 +743,13 @@ static int __init acpi_parse_madt_lapic_entries(void)
if (!cpu_has_apic)
return -ENODEV;
- /*
+ /*
* Note that the LAPIC address is obtained from the MADT (32-bit value)
* and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
*/
count =
- acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR,
+ acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
acpi_parse_lapic_addr_ovr, 0);
if (count < 0) {
printk(KERN_ERR PREFIX
@@ -800,7 +759,7 @@ static int __init acpi_parse_madt_lapic_entries(void)
mp_register_lapic_address(acpi_lapic_addr);
- count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic,
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC, acpi_parse_lapic,
MAX_APICS);
if (!count) {
printk(KERN_ERR PREFIX "No LAPIC entries present\n");
@@ -813,7 +772,7 @@ static int __init acpi_parse_madt_lapic_entries(void)
}
count =
- acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0);
+ acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0);
if (count < 0) {
printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
/* TBD: Cleanup to allow fallback to MPS */
@@ -842,7 +801,7 @@ static int __init acpi_parse_madt_ioapic_entries(void)
return -ENODEV;
}
- if (!cpu_has_apic)
+ if (!cpu_has_apic)
return -ENODEV;
/*
@@ -855,7 +814,7 @@ static int __init acpi_parse_madt_ioapic_entries(void)
}
count =
- acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic,
+ acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic,
MAX_IO_APICS);
if (!count) {
printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
@@ -866,7 +825,7 @@ static int __init acpi_parse_madt_ioapic_entries(void)
}
count =
- acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr,
+ acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr,
NR_IRQ_VECTORS);
if (count < 0) {
printk(KERN_ERR PREFIX
@@ -880,13 +839,13 @@ 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_gbl_FADT.sci_interrupt, 0, 0);
/* Fill in identity legacy mapings where no override */
mp_config_acpi_legacy_irqs();
count =
- acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src,
+ acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src,
NR_IRQ_VECTORS);
if (count < 0) {
printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
@@ -908,7 +867,7 @@ static void __init acpi_process_madt(void)
#ifdef CONFIG_X86_LOCAL_APIC
int count, error;
- count = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
+ count = acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt);
if (count >= 1) {
/*
@@ -1195,7 +1154,7 @@ int __init acpi_boot_table_init(void)
if (acpi_disabled && !acpi_ht)
return 1;
- /*
+ /*
* Initialize the ACPI boot-time table parser.
*/
error = acpi_table_init();
@@ -1204,7 +1163,7 @@ int __init acpi_boot_table_init(void)
return error;
}
- acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
+ acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
/*
* blacklist may disable ACPI entirely
@@ -1232,19 +1191,19 @@ int __init acpi_boot_init(void)
if (acpi_disabled && !acpi_ht)
return 1;
- acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
+ acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
/*
* set sci_int and PM timer address
*/
- acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
+ acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt);
/*
* Process the Multiple APIC Description Table (MADT), if present
*/
acpi_process_madt();
- acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
+ acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
return 0;
}
@@ -1315,15 +1274,41 @@ static int __init setup_acpi_sci(char *s)
if (!s)
return -EINVAL;
if (!strcmp(s, "edge"))
- acpi_sci_flags.trigger = 1;
+ acpi_sci_flags = ACPI_MADT_TRIGGER_EDGE |
+ (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
else if (!strcmp(s, "level"))
- acpi_sci_flags.trigger = 3;
+ acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL |
+ (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
else if (!strcmp(s, "high"))
- acpi_sci_flags.polarity = 1;
+ acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH |
+ (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
else if (!strcmp(s, "low"))
- acpi_sci_flags.polarity = 3;
+ acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW |
+ (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
else
return -EINVAL;
return 0;
}
early_param("acpi_sci", setup_acpi_sci);
+
+int __acpi_acquire_global_lock(unsigned int *lock)
+{
+ unsigned int old, new, val;
+ do {
+ old = *lock;
+ new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
+ val = cmpxchg(lock, old, new);
+ } while (unlikely (val != old));
+ return (new < 3) ? -1 : 0;
+}
+
+int __acpi_release_global_lock(unsigned int *lock)
+{
+ unsigned int old, new, val;
+ do {
+ old = *lock;
+ new = old & ~0x3;
+ val = cmpxchg(lock, old, new);
+ } while (unlikely (val != old));
+ return old & 0x1;
+}
diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/i386/kernel/acpi/cstate.c
index 12e937c1ce4..2d39f55d29a 100644
--- a/arch/i386/kernel/acpi/cstate.c
+++ b/arch/i386/kernel/acpi/cstate.c
@@ -47,13 +47,13 @@ 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 cstate_entry {
struct {
unsigned int eax;
unsigned int ecx;
} states[ACPI_PROCESSOR_MAX_POWER];
};
-static struct cstate_entry_s *cpu_cstate_entry; /* per CPU ptr */
+static struct cstate_entry *cpu_cstate_entry; /* per CPU ptr */
static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
@@ -71,7 +71,7 @@ static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
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 cstate_entry *percpu_entry;
struct cpuinfo_x86 *c = cpu_data + cpu;
cpumask_t saved_mask;
@@ -136,7 +136,7 @@ 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;
+ struct cstate_entry *percpu_entry;
percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
mwait_idle_with_hints(percpu_entry->states[cx->index].eax,
@@ -150,7 +150,7 @@ static int __init ffh_cstate_init(void)
if (c->x86_vendor != X86_VENDOR_INTEL)
return -1;
- cpu_cstate_entry = alloc_percpu(struct cstate_entry_s);
+ cpu_cstate_entry = alloc_percpu(struct cstate_entry);
return 0;
}
diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c
index 4b60af7f91d..bf86f7662d8 100644
--- a/arch/i386/kernel/acpi/earlyquirk.c
+++ b/arch/i386/kernel/acpi/earlyquirk.c
@@ -16,7 +16,7 @@
static int nvidia_hpet_detected __initdata;
-static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
+static int __init nvidia_hpet_check(struct acpi_table_header *header)
{
nvidia_hpet_detected = 1;
return 0;
@@ -30,7 +30,7 @@ static int __init check_bridge(int vendor, int device)
is enabled. */
if (!acpi_use_timer_override && vendor == PCI_VENDOR_ID_NVIDIA) {
nvidia_hpet_detected = 0;
- acpi_table_parse(ACPI_HPET, nvidia_hpet_check);
+ acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check);
if (nvidia_hpet_detected == 0) {
acpi_skip_timer_override = 1;
printk(KERN_INFO "Nvidia board "
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index a97847da9ed..19901692754 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -785,7 +785,11 @@ static int apm_do_idle(void)
polling = !!(current_thread_info()->status & TS_POLLING);
if (polling) {
current_thread_info()->status &= ~TS_POLLING;
- smp_mb__after_clear_bit();
+ /*
+ * TS_POLLING-cleared state must be visible before we
+ * test NEED_RESCHED:
+ */
+ smp_mb();
}
if (!need_resched()) {
idled = 1;
@@ -1604,7 +1608,7 @@ static int do_open(struct inode * inode, struct file * filp)
{
struct apm_user * as;
- as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
+ as = kmalloc(sizeof(*as), GFP_KERNEL);
if (as == NULL) {
printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
sizeof(*as));
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 1b34c56f812..8a8bbdaaf38 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -54,7 +54,7 @@ static struct cpu_dev __cpuinitdata default_cpu = {
.c_init = default_init,
.c_vendor = "Unknown",
};
-static struct cpu_dev * this_cpu = &default_cpu;
+static struct cpu_dev * this_cpu __cpuinitdata = &default_cpu;
static int __init cachesize_setup(char *str)
{
@@ -710,11 +710,8 @@ __cpuinit int init_gdt(int cpu, struct task_struct *idle)
return 1;
}
-/* Common CPU init for both boot and secondary CPUs */
-static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
+void __cpuinit cpu_set_gdt(int cpu)
{
- struct tss_struct * t = &per_cpu(init_tss, cpu);
- struct thread_struct *thread = &curr->thread;
struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
/* Reinit these anyway, even if they've already been done (on
@@ -722,6 +719,13 @@ static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
the real ones). */
load_gdt(cpu_gdt_descr);
set_kernel_gs();
+}
+
+/* Common CPU init for both boot and secondary CPUs */
+static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
+{
+ struct tss_struct * t = &per_cpu(init_tss, cpu);
+ struct thread_struct *thread = &curr->thread;
if (cpu_test_and_set(cpu, cpu_initialized)) {
printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
@@ -807,6 +811,7 @@ void __cpuinit cpu_init(void)
local_irq_enable();
}
+ cpu_set_gdt(cpu);
_cpu_init(cpu, curr);
}
diff --git a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig
index ccc1edff5c9..5299c5bf445 100644
--- a/arch/i386/kernel/cpu/cpufreq/Kconfig
+++ b/arch/i386/kernel/cpu/cpufreq/Kconfig
@@ -17,6 +17,7 @@ config X86_ACPI_CPUFREQ
help
This driver adds a CPUFreq driver which utilizes the ACPI
Processor Performance States.
+ This driver also supports Intel Enhanced Speedstep.
For details, take a look at <file:Documentation/cpu-freq/>.
@@ -121,11 +122,14 @@ config X86_SPEEDSTEP_CENTRINO
If in doubt, say N.
config X86_SPEEDSTEP_CENTRINO_ACPI
- bool "Use ACPI tables to decode valid frequency/voltage pairs"
+ bool "Use ACPI tables to decode valid frequency/voltage (deprecated)"
depends on X86_SPEEDSTEP_CENTRINO && ACPI_PROCESSOR
depends on !(X86_SPEEDSTEP_CENTRINO = y && ACPI_PROCESSOR = m)
default y
help
+ This is deprecated and this functionality is now merged into
+ acpi_cpufreq (X86_ACPI_CPUFREQ). Use that driver instead of
+ speedstep_centrino.
Use primarily the information provided in the BIOS ACPI tables
to determine valid CPU frequency and voltage pairings. It is
required for the driver to work on non-Banias CPUs.
diff --git a/arch/i386/kernel/cpu/cpufreq/Makefile b/arch/i386/kernel/cpu/cpufreq/Makefile
index 2e894f1c891..8de3abe322a 100644
--- a/arch/i386/kernel/cpu/cpufreq/Makefile
+++ b/arch/i386/kernel/cpu/cpufreq/Makefile
@@ -7,9 +7,9 @@ obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o
obj-$(CONFIG_X86_LONGRUN) += longrun.o
obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o
obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o
-obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o
obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o
obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o
+obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
index 57c880bf0bd..10baa3501ed 100644
--- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -1,9 +1,10 @@
/*
- * acpi-cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.3 $)
+ * acpi-cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.4 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
* Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -27,202 +28,370 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
#include <linux/cpufreq.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
#include <linux/compiler.h>
-#include <linux/sched.h> /* current */
#include <linux/dmi.h>
-#include <asm/io.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
#include <linux/acpi.h>
#include <acpi/processor.h>
+#include <asm/io.h>
+#include <asm/msr.h>
+#include <asm/processor.h>
+#include <asm/cpufeature.h>
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
MODULE_DESCRIPTION("ACPI Processor P-States Driver");
MODULE_LICENSE("GPL");
+enum {
+ UNDEFINED_CAPABLE = 0,
+ SYSTEM_INTEL_MSR_CAPABLE,
+ SYSTEM_IO_CAPABLE,
+};
+
+#define INTEL_MSR_RANGE (0xffff)
+#define CPUID_6_ECX_APERFMPERF_CAPABILITY (0x1)
-struct cpufreq_acpi_io {
- struct acpi_processor_performance *acpi_data;
- struct cpufreq_frequency_table *freq_table;
- unsigned int resume;
+struct acpi_cpufreq_data {
+ struct acpi_processor_performance *acpi_data;
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int max_freq;
+ unsigned int resume;
+ unsigned int cpu_feature;
};
-static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS];
-static struct acpi_processor_performance *acpi_perf_data[NR_CPUS];
+static struct acpi_cpufreq_data *drv_data[NR_CPUS];
+static struct acpi_processor_performance *acpi_perf_data[NR_CPUS];
static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
-static int
-acpi_processor_write_port(
- u16 port,
- u8 bit_width,
- u32 value)
+static int check_est_cpu(unsigned int cpuid)
{
- if (bit_width <= 8) {
- outb(value, port);
- } else if (bit_width <= 16) {
- outw(value, port);
- } else if (bit_width <= 32) {
- outl(value, port);
- } else {
- return -ENODEV;
+ struct cpuinfo_x86 *cpu = &cpu_data[cpuid];
+
+ if (cpu->x86_vendor != X86_VENDOR_INTEL ||
+ !cpu_has(cpu, X86_FEATURE_EST))
+ return 0;
+
+ return 1;
+}
+
+static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
+{
+ struct acpi_processor_performance *perf;
+ int i;
+
+ perf = data->acpi_data;
+
+ for (i=0; i<perf->state_count; i++) {
+ if (value == perf->states[i].status)
+ return data->freq_table[i].frequency;
}
return 0;
}
-static int
-acpi_processor_read_port(
- u16 port,
- u8 bit_width,
- u32 *ret)
+static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
{
- *ret = 0;
- if (bit_width <= 8) {
- *ret = inb(port);
- } else if (bit_width <= 16) {
- *ret = inw(port);
- } else if (bit_width <= 32) {
- *ret = inl(port);
- } else {
- return -ENODEV;
+ int i;
+ struct acpi_processor_performance *perf;
+
+ msr &= INTEL_MSR_RANGE;
+ perf = data->acpi_data;
+
+ for (i=0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ if (msr == perf->states[data->freq_table[i].index].status)
+ return data->freq_table[i].frequency;
}
- return 0;
+ return data->freq_table[0].frequency;
}
-static int
-acpi_processor_set_performance (
- struct cpufreq_acpi_io *data,
- unsigned int cpu,
- int state)
+static unsigned extract_freq(u32 val, struct acpi_cpufreq_data *data)
{
- u16 port = 0;
- u8 bit_width = 0;
- int i = 0;
- int ret = 0;
- u32 value = 0;
- int retval;
- struct acpi_processor_performance *perf;
-
- dprintk("acpi_processor_set_performance\n");
-
- retval = 0;
- perf = data->acpi_data;
- if (state == perf->state) {
- if (unlikely(data->resume)) {
- dprintk("Called after resume, resetting to P%d\n", state);
- data->resume = 0;
- } else {
- dprintk("Already at target state (P%d)\n", state);
- return (retval);
- }
+ switch (data->cpu_feature) {
+ case SYSTEM_INTEL_MSR_CAPABLE:
+ return extract_msr(val, data);
+ case SYSTEM_IO_CAPABLE:
+ return extract_io(val, data);
+ default:
+ return 0;
}
+}
+
+struct msr_addr {
+ u32 reg;
+};
- dprintk("Transitioning from P%d to P%d\n", perf->state, state);
+struct io_addr {
+ u16 port;
+ u8 bit_width;
+};
- /*
- * First we write the target state's 'control' value to the
- * control_register.
- */
+typedef union {
+ struct msr_addr msr;
+ struct io_addr io;
+} drv_addr_union;
- port = perf->control_register.address;
- bit_width = perf->control_register.bit_width;
- value = (u32) perf->states[state].control;
+struct drv_cmd {
+ unsigned int type;
+ cpumask_t mask;
+ drv_addr_union addr;
+ u32 val;
+};
- dprintk("Writing 0x%08x to port 0x%04x\n", value, port);
+static void do_drv_read(struct drv_cmd *cmd)
+{
+ u32 h;
+
+ switch (cmd->type) {
+ case SYSTEM_INTEL_MSR_CAPABLE:
+ rdmsr(cmd->addr.msr.reg, cmd->val, h);
+ break;
+ case SYSTEM_IO_CAPABLE:
+ acpi_os_read_port((acpi_io_address)cmd->addr.io.port,
+ &cmd->val,
+ (u32)cmd->addr.io.bit_width);
+ break;
+ default:
+ break;
+ }
+}
- ret = acpi_processor_write_port(port, bit_width, value);
- if (ret) {
- dprintk("Invalid port width 0x%04x\n", bit_width);
- return (ret);
+static void do_drv_write(struct drv_cmd *cmd)
+{
+ u32 h = 0;
+
+ switch (cmd->type) {
+ case SYSTEM_INTEL_MSR_CAPABLE:
+ wrmsr(cmd->addr.msr.reg, cmd->val, h);
+ break;
+ case SYSTEM_IO_CAPABLE:
+ acpi_os_write_port((acpi_io_address)cmd->addr.io.port,
+ cmd->val,
+ (u32)cmd->addr.io.bit_width);
+ break;
+ default:
+ break;
}
+}
+static void drv_read(struct drv_cmd *cmd)
+{
+ cpumask_t saved_mask = current->cpus_allowed;
+ cmd->val = 0;
+
+ set_cpus_allowed(current, cmd->mask);
+ do_drv_read(cmd);
+ set_cpus_allowed(current, saved_mask);
+}
+
+static void drv_write(struct drv_cmd *cmd)
+{
+ cpumask_t saved_mask = current->cpus_allowed;
+ unsigned int i;
+
+ for_each_cpu_mask(i, cmd->mask) {
+ set_cpus_allowed(current, cpumask_of_cpu(i));
+ do_drv_write(cmd);
+ }
+
+ set_cpus_allowed(current, saved_mask);
+ return;
+}
+
+static u32 get_cur_val(cpumask_t mask)
+{
+ struct acpi_processor_performance *perf;
+ struct drv_cmd cmd;
+
+ if (unlikely(cpus_empty(mask)))
+ return 0;
+
+ switch (drv_data[first_cpu(mask)]->cpu_feature) {
+ case SYSTEM_INTEL_MSR_CAPABLE:
+ cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
+ cmd.addr.msr.reg = MSR_IA32_PERF_STATUS;
+ break;
+ case SYSTEM_IO_CAPABLE:
+ cmd.type = SYSTEM_IO_CAPABLE;
+ perf = drv_data[first_cpu(mask)]->acpi_data;
+ cmd.addr.io.port = perf->control_register.address;
+ cmd.addr.io.bit_width = perf->control_register.bit_width;
+ break;
+ default:
+ return 0;
+ }
+
+ cmd.mask = mask;
+
+ drv_read(&cmd);
+
+ dprintk("get_cur_val = %u\n", cmd.val);
+
+ return cmd.val;
+}
+
+/*
+ * Return the measured active (C0) frequency on this CPU since last call
+ * to this function.
+ * Input: cpu number
+ * Return: Average CPU frequency in terms of max frequency (zero on error)
+ *
+ * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance
+ * over a period of time, while CPU is in C0 state.
+ * IA32_MPERF counts at the rate of max advertised frequency
+ * IA32_APERF counts at the rate of actual CPU frequency
+ * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and
+ * no meaning should be associated with absolute values of these MSRs.
+ */
+static unsigned int get_measured_perf(unsigned int cpu)
+{
+ union {
+ struct {
+ u32 lo;
+ u32 hi;
+ } split;
+ u64 whole;
+ } aperf_cur, mperf_cur;
+
+ cpumask_t saved_mask;
+ unsigned int perf_percent;
+ unsigned int retval;
+
+ saved_mask = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
+ if (get_cpu() != cpu) {
+ /* We were not able to run on requested processor */
+ put_cpu();
+ return 0;
+ }
+
+ rdmsr(MSR_IA32_APERF, aperf_cur.split.lo, aperf_cur.split.hi);
+ rdmsr(MSR_IA32_MPERF, mperf_cur.split.lo, mperf_cur.split.hi);
+
+ wrmsr(MSR_IA32_APERF, 0,0);
+ wrmsr(MSR_IA32_MPERF, 0,0);
+
+#ifdef __i386__
/*
- * Assume the write went through when acpi_pstate_strict is not used.
- * As read status_register is an expensive operation and there
- * are no specific error cases where an IO port write will fail.
+ * We dont want to do 64 bit divide with 32 bit kernel
+ * Get an approximate value. Return failure in case we cannot get
+ * an approximate value.
*/
- if (acpi_pstate_strict) {
- /* Then we read the 'status_register' and compare the value
- * with the target state's 'status' to make sure the
- * transition was successful.
- * Note that we'll poll for up to 1ms (100 cycles of 10us)
- * before giving up.
- */
-
- port = perf->status_register.address;
- bit_width = perf->status_register.bit_width;
-
- dprintk("Looking for 0x%08x from port 0x%04x\n",
- (u32) perf->states[state].status, port);
-
- for (i = 0; i < 100; i++) {
- ret = acpi_processor_read_port(port, bit_width, &value);
- if (ret) {
- dprintk("Invalid port width 0x%04x\n", bit_width);
- return (ret);
- }
- if (value == (u32) perf->states[state].status)
- break;
- udelay(10);
- }
- } else {
- value = (u32) perf->states[state].status;
+ if (unlikely(aperf_cur.split.hi || mperf_cur.split.hi)) {
+ int shift_count;
+ u32 h;
+
+ h = max_t(u32, aperf_cur.split.hi, mperf_cur.split.hi);
+ shift_count = fls(h);
+
+ aperf_cur.whole >>= shift_count;
+ mperf_cur.whole >>= shift_count;
+ }
+
+ if (((unsigned long)(-1) / 100) < aperf_cur.split.lo) {
+ int shift_count = 7;
+ aperf_cur.split.lo >>= shift_count;
+ mperf_cur.split.lo >>= shift_count;
+ }
+
+ if (aperf_cur.split.lo && mperf_cur.split.lo)
+ perf_percent = (aperf_cur.split.lo * 100) / mperf_cur.split.lo;
+ else
+ perf_percent = 0;
+
+#else
+ if (unlikely(((unsigned long)(-1) / 100) < aperf_cur.whole)) {
+ int shift_count = 7;
+ aperf_cur.whole >>= shift_count;
+ mperf_cur.whole >>= shift_count;
}
- if (unlikely(value != (u32) perf->states[state].status)) {
- printk(KERN_WARNING "acpi-cpufreq: Transition failed\n");
- retval = -ENODEV;
- return (retval);
+ if (aperf_cur.whole && mperf_cur.whole)
+ perf_percent = (aperf_cur.whole * 100) / mperf_cur.whole;
+ else
+ perf_percent = 0;
+
+#endif
+
+ retval = drv_data[cpu]->max_freq * perf_percent / 100;
+
+ put_cpu();
+ set_cpus_allowed(current, saved_mask);
+
+ dprintk("cpu %d: performance percent %d\n", cpu, perf_percent);
+ return retval;
+}
+
+static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
+{
+ struct acpi_cpufreq_data *data = drv_data[cpu];
+ unsigned int freq;
+
+ dprintk("get_cur_freq_on_cpu (%d)\n", cpu);
+
+ if (unlikely(data == NULL ||
+ data->acpi_data == NULL || data->freq_table == NULL)) {
+ return 0;
}
- dprintk("Transition successful after %d microseconds\n", i * 10);
+ freq = extract_freq(get_cur_val(cpumask_of_cpu(cpu)), data);
+ dprintk("cur freq = %u\n", freq);
- perf->state = state;
- return (retval);
+ return freq;
}
+static unsigned int check_freqs(cpumask_t mask, unsigned int freq,
+ struct acpi_cpufreq_data *data)
+{
+ unsigned int cur_freq;
+ unsigned int i;
+
+ for (i=0; i<100; i++) {
+ cur_freq = extract_freq(get_cur_val(mask), data);
+ if (cur_freq == freq)
+ return 1;
+ udelay(10);
+ }
+ return 0;
+}
-static int
-acpi_cpufreq_target (
- struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation)
+static int acpi_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
{
- struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
struct acpi_processor_performance *perf;
struct cpufreq_freqs freqs;
cpumask_t online_policy_cpus;
- cpumask_t saved_mask;
- cpumask_t set_mask;
- cpumask_t covered_cpus;
- unsigned int cur_state = 0;
- unsigned int next_state = 0;
- unsigned int result = 0;
- unsigned int j;
- unsigned int tmp;
+ struct drv_cmd cmd;
+ unsigned int msr;
+ unsigned int next_state = 0; /* Index into freq_table */
+ unsigned int next_perf_state = 0; /* Index into perf table */
+ unsigned int i;
+ int result = 0;
- dprintk("acpi_cpufreq_setpolicy\n");
+ dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
- result = cpufreq_frequency_table_target(policy,
- data->freq_table,
- target_freq,
- relation,
- &next_state);
- if (unlikely(result))
- return (result);
+ if (unlikely(data == NULL ||
+ data->acpi_data == NULL || data->freq_table == NULL)) {
+ return -ENODEV;
+ }
perf = data->acpi_data;
- cur_state = perf->state;
- freqs.old = data->freq_table[cur_state].frequency;
- freqs.new = data->freq_table[next_state].frequency;
+ result = cpufreq_frequency_table_target(policy,
+ data->freq_table,
+ target_freq,
+ relation, &next_state);
+ if (unlikely(result))
+ return -ENODEV;
#ifdef CONFIG_HOTPLUG_CPU
/* cpufreq holds the hotplug lock, so we are safe from here on */
@@ -231,106 +400,85 @@ acpi_cpufreq_target (
online_policy_cpus = policy->cpus;
#endif
- for_each_cpu_mask(j, online_policy_cpus) {
- freqs.cpu = j;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ next_perf_state = data->freq_table[next_state].index;
+ if (perf->state == next_perf_state) {
+ if (unlikely(data->resume)) {
+ dprintk("Called after resume, resetting to P%d\n",
+ next_perf_state);
+ data->resume = 0;
+ } else {
+ dprintk("Already at target state (P%d)\n",
+ next_perf_state);
+ return 0;
+ }
}
- /*
- * We need to call driver->target() on all or any CPU in
- * policy->cpus, depending on policy->shared_type.
- */
- saved_mask = current->cpus_allowed;
- cpus_clear(covered_cpus);
- for_each_cpu_mask(j, online_policy_cpus) {
- /*
- * Support for SMP systems.
- * Make sure we are running on CPU that wants to change freq
- */
- cpus_clear(set_mask);
- if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
- cpus_or(set_mask, set_mask, online_policy_cpus);
- else
- cpu_set(j, set_mask);
-
- set_cpus_allowed(current, set_mask);
- if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) {
- dprintk("couldn't limit to CPUs in this domain\n");
- result = -EAGAIN;
- break;
- }
+ switch (data->cpu_feature) {
+ case SYSTEM_INTEL_MSR_CAPABLE:
+ cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
+ cmd.addr.msr.reg = MSR_IA32_PERF_CTL;
+ msr =
+ (u32) perf->states[next_perf_state].
+ control & INTEL_MSR_RANGE;
+ cmd.val = get_cur_val(online_policy_cpus);
+ cmd.val = (cmd.val & ~INTEL_MSR_RANGE) | msr;
+ break;
+ case SYSTEM_IO_CAPABLE:
+ cmd.type = SYSTEM_IO_CAPABLE;
+ cmd.addr.io.port = perf->control_register.address;
+ cmd.addr.io.bit_width = perf->control_register.bit_width;
+ cmd.val = (u32) perf->states[next_perf_state].control;
+ break;
+ default:
+ return -ENODEV;
+ }
- result = acpi_processor_set_performance (data, j, next_state);
- if (result) {
- result = -EAGAIN;
- break;
- }
+ cpus_clear(cmd.mask);
- if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
- break;
-
- cpu_set(j, covered_cpus);
- }
+ if (policy->shared_type != CPUFREQ_SHARED_TYPE_ANY)
+ cmd.mask = online_policy_cpus;
+ else
+ cpu_set(policy->cpu, cmd.mask);
- for_each_cpu_mask(j, online_policy_cpus) {
- freqs.cpu = j;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ freqs.old = perf->states[perf->state].core_frequency * 1000;
+ freqs.new = data->freq_table[next_state].frequency;
+ for_each_cpu_mask(i, cmd.mask) {
+ freqs.cpu = i;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
- if (unlikely(result)) {
- /*
- * We have failed halfway through the frequency change.
- * We have sent callbacks to online_policy_cpus and
- * acpi_processor_set_performance() has been called on
- * coverd_cpus. Best effort undo..
- */
-
- if (!cpus_empty(covered_cpus)) {
- for_each_cpu_mask(j, covered_cpus) {
- policy->cpu = j;
- acpi_processor_set_performance (data,
- j,
- cur_state);
- }
- }
+ drv_write(&cmd);
- tmp = freqs.new;
- freqs.new = freqs.old;
- freqs.old = tmp;
- for_each_cpu_mask(j, online_policy_cpus) {
- freqs.cpu = j;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ if (acpi_pstate_strict) {
+ if (!check_freqs(cmd.mask, freqs.new, data)) {
+ dprintk("acpi_cpufreq_target failed (%d)\n",
+ policy->cpu);
+ return -EAGAIN;
}
}
- set_cpus_allowed(current, saved_mask);
- return (result);
-}
+ for_each_cpu_mask(i, cmd.mask) {
+ freqs.cpu = i;
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+ perf->state = next_perf_state;
+ return result;
+}
-static int
-acpi_cpufreq_verify (
- struct cpufreq_policy *policy)
+static int acpi_cpufreq_verify(struct cpufreq_policy *policy)
{
- unsigned int result = 0;
- struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
dprintk("acpi_cpufreq_verify\n");
- result = cpufreq_frequency_table_verify(policy,
- data->freq_table);
-
- return (result);
+ return cpufreq_frequency_table_verify(policy, data->freq_table);
}
-
static unsigned long
-acpi_cpufreq_guess_freq (
- struct cpufreq_acpi_io *data,
- unsigned int cpu)
+acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu)
{
- struct acpi_processor_performance *perf = data->acpi_data;
+ struct acpi_processor_performance *perf = data->acpi_data;
if (cpu_khz) {
/* search the closest match to cpu_khz */
@@ -338,16 +486,16 @@ acpi_cpufreq_guess_freq (
unsigned long freq;
unsigned long freqn = perf->states[0].core_frequency * 1000;
- for (i = 0; i < (perf->state_count - 1); i++) {
+ for (i=0; i<(perf->state_count-1); i++) {
freq = freqn;
freqn = perf->states[i+1].core_frequency * 1000;
if ((2 * cpu_khz) > (freqn + freq)) {
perf->state = i;
- return (freq);
+ return freq;
}
}
- perf->state = perf->state_count - 1;
- return (freqn);
+ perf->state = perf->state_count-1;
+ return freqn;
} else {
/* assume CPU is at P0... */
perf->state = 0;
@@ -355,7 +503,6 @@ acpi_cpufreq_guess_freq (
}
}
-
/*
* acpi_cpufreq_early_init - initialize ACPI P-States library
*
@@ -364,30 +511,34 @@ acpi_cpufreq_guess_freq (
* do _PDC and _PSD and find out the processor dependency for the
* actual init that will happen later...
*/
-static int acpi_cpufreq_early_init_acpi(void)
+static int acpi_cpufreq_early_init(void)
{
- struct acpi_processor_performance *data;
- unsigned int i, j;
+ struct acpi_processor_performance *data;
+ cpumask_t covered;
+ unsigned int i, j;
dprintk("acpi_cpufreq_early_init\n");
for_each_possible_cpu(i) {
- data = kzalloc(sizeof(struct acpi_processor_performance),
- GFP_KERNEL);
+ data = kzalloc(sizeof(struct acpi_processor_performance),
+ GFP_KERNEL);
if (!data) {
- for_each_possible_cpu(j) {
+ for_each_cpu_mask(j, covered) {
kfree(acpi_perf_data[j]);
acpi_perf_data[j] = NULL;
}
- return (-ENOMEM);
+ return -ENOMEM;
}
acpi_perf_data[i] = data;
+ cpu_set(i, covered);
}
/* Do initialization in ACPI core */
- return acpi_processor_preregister_performance(acpi_perf_data);
+ acpi_processor_preregister_performance(acpi_perf_data);
+ return 0;
}
+#ifdef CONFIG_SMP
/*
* Some BIOSes do SW_ANY coordination internally, either set it up in hw
* or do it in BIOS firmware and won't inform about it to OS. If not
@@ -414,39 +565,42 @@ static struct dmi_system_id sw_any_bug_dmi_table[] = {
},
{ }
};
+#endif
-static int
-acpi_cpufreq_cpu_init (
- struct cpufreq_policy *policy)
+static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- unsigned int i;
- unsigned int cpu = policy->cpu;
- struct cpufreq_acpi_io *data;
- unsigned int result = 0;
+ unsigned int i;
+ unsigned int valid_states = 0;
+ unsigned int cpu = policy->cpu;
+ struct acpi_cpufreq_data *data;
+ unsigned int result = 0;
struct cpuinfo_x86 *c = &cpu_data[policy->cpu];
- struct acpi_processor_performance *perf;
+ struct acpi_processor_performance *perf;
dprintk("acpi_cpufreq_cpu_init\n");
if (!acpi_perf_data[cpu])
- return (-ENODEV);
+ return -ENODEV;
- data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
+ data = kzalloc(sizeof(struct acpi_cpufreq_data), GFP_KERNEL);
if (!data)
- return (-ENOMEM);
+ return -ENOMEM;
data->acpi_data = acpi_perf_data[cpu];
- acpi_io_data[cpu] = data;
+ drv_data[cpu] = data;
- result = acpi_processor_register_performance(data->acpi_data, cpu);
+ if (cpu_has(c, X86_FEATURE_CONSTANT_TSC))
+ acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
+ result = acpi_processor_register_performance(data->acpi_data, cpu);
if (result)
goto err_free;
perf = data->acpi_data;
policy->shared_type = perf->shared_type;
+
/*
- * Will let policy->cpus know about dependency only when software
+ * Will let policy->cpus know about dependency only when software
* coordination is required.
*/
if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL ||
@@ -462,10 +616,6 @@ acpi_cpufreq_cpu_init (
}
#endif
- if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
- acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
- }
-
/* capability check */
if (perf->state_count <= 1) {
dprintk("No P-States\n");
@@ -473,17 +623,33 @@ acpi_cpufreq_cpu_init (
goto err_unreg;
}
- if ((perf->control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) ||
- (perf->status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
- dprintk("Unsupported address space [%d, %d]\n",
- (u32) (perf->control_register.space_id),
- (u32) (perf->status_register.space_id));
+ if (perf->control_register.space_id != perf->status_register.space_id) {
result = -ENODEV;
goto err_unreg;
}
- /* alloc freq_table */
- data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (perf->state_count + 1), GFP_KERNEL);
+ switch (perf->control_register.space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ dprintk("SYSTEM IO addr space\n");
+ data->cpu_feature = SYSTEM_IO_CAPABLE;
+ break;
+ case ACPI_ADR_SPACE_FIXED_HARDWARE:
+ dprintk("HARDWARE addr space\n");
+ if (!check_est_cpu(cpu)) {
+ result = -ENODEV;
+ goto err_unreg;
+ }
+ data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE;
+ break;
+ default:
+ dprintk("Unknown addr space %d\n",
+ (u32) (perf->control_register.space_id));
+ result = -ENODEV;
+ goto err_unreg;
+ }
+
+ data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) *
+ (perf->state_count+1), GFP_KERNEL);
if (!data->freq_table) {
result = -ENOMEM;
goto err_unreg;
@@ -492,129 +658,141 @@ acpi_cpufreq_cpu_init (
/* detect transition latency */
policy->cpuinfo.transition_latency = 0;
for (i=0; i<perf->state_count; i++) {
- if ((perf->states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency)
- policy->cpuinfo.transition_latency = perf->states[i].transition_latency * 1000;
+ if ((perf->states[i].transition_latency * 1000) >
+ policy->cpuinfo.transition_latency)
+ policy->cpuinfo.transition_latency =
+ perf->states[i].transition_latency * 1000;
}
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
- /* The current speed is unknown and not detectable by ACPI... */
- policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu);
-
+ data->max_freq = perf->states[0].core_frequency * 1000;
/* table init */
- for (i=0; i<=perf->state_count; i++)
- {
- data->freq_table[i].index = i;
- if (i<perf->state_count)
- data->freq_table[i].frequency = perf->states[i].core_frequency * 1000;
- else
- data->freq_table[i].frequency = CPUFREQ_TABLE_END;
+ for (i=0; i<perf->state_count; i++) {
+ if (i>0 && perf->states[i].core_frequency ==
+ perf->states[i-1].core_frequency)
+ continue;
+
+ data->freq_table[valid_states].index = i;
+ data->freq_table[valid_states].frequency =
+ perf->states[i].core_frequency * 1000;
+ valid_states++;
}
+ data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END;
+ perf->state = 0;
result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
- if (result) {
+ if (result)
goto err_freqfree;
+
+ switch (perf->control_register.space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ /* Current speed is unknown and not detectable by IO port */
+ policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu);
+ break;
+ case ACPI_ADR_SPACE_FIXED_HARDWARE:
+ acpi_cpufreq_driver.get = get_cur_freq_on_cpu;
+ policy->cur = get_cur_freq_on_cpu(cpu);
+ break;
+ default:
+ break;
}
/* notify BIOS that we exist */
acpi_processor_notify_smm(THIS_MODULE);
- printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management activated.\n",
- cpu);
+ /* Check for APERF/MPERF support in hardware */
+ if (c->x86_vendor == X86_VENDOR_INTEL && c->cpuid_level >= 6) {
+ unsigned int ecx;
+ ecx = cpuid_ecx(6);
+ if (ecx & CPUID_6_ECX_APERFMPERF_CAPABILITY)
+ acpi_cpufreq_driver.getavg = get_measured_perf;
+ }
+
+ dprintk("CPU%u - ACPI performance management activated.\n", cpu);
for (i = 0; i < perf->state_count; i++)
dprintk(" %cP%d: %d MHz, %d mW, %d uS\n",
- (i == perf->state?'*':' '), i,
+ (i == perf->state ? '*' : ' '), i,
(u32) perf->states[i].core_frequency,
(u32) perf->states[i].power,
(u32) perf->states[i].transition_latency);
cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
-
+
/*
* the first call to ->target() should result in us actually
* writing something to the appropriate registers.
*/
data->resume = 1;
-
- return (result);
- err_freqfree:
+ return result;
+
+err_freqfree:
kfree(data->freq_table);
- err_unreg:
+err_unreg:
acpi_processor_unregister_performance(perf, cpu);
- err_free:
+err_free:
kfree(data);
- acpi_io_data[cpu] = NULL;
+ drv_data[cpu] = NULL;
- return (result);
+ return result;
}
-
-static int
-acpi_cpufreq_cpu_exit (
- struct cpufreq_policy *policy)
+static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{
- struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
-
+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
dprintk("acpi_cpufreq_cpu_exit\n");
if (data) {
cpufreq_frequency_table_put_attr(policy->cpu);
- acpi_io_data[policy->cpu] = NULL;
- acpi_processor_unregister_performance(data->acpi_data, policy->cpu);
+ drv_data[policy->cpu] = NULL;
+ acpi_processor_unregister_performance(data->acpi_data,
+ policy->cpu);
kfree(data);
}
- return (0);
+ return 0;
}
-static int
-acpi_cpufreq_resume (
- struct cpufreq_policy *policy)
+static int acpi_cpufreq_resume(struct cpufreq_policy *policy)
{
- struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
-
+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
dprintk("acpi_cpufreq_resume\n");
data->resume = 1;
- return (0);
+ return 0;
}
-
-static struct freq_attr* acpi_cpufreq_attr[] = {
+static struct freq_attr *acpi_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
static struct cpufreq_driver acpi_cpufreq_driver = {
- .verify = acpi_cpufreq_verify,
- .target = acpi_cpufreq_target,
- .init = acpi_cpufreq_cpu_init,
- .exit = acpi_cpufreq_cpu_exit,
- .resume = acpi_cpufreq_resume,
- .name = "acpi-cpufreq",
- .owner = THIS_MODULE,
- .attr = acpi_cpufreq_attr,
+ .verify = acpi_cpufreq_verify,
+ .target = acpi_cpufreq_target,
+ .init = acpi_cpufreq_cpu_init,
+ .exit = acpi_cpufreq_cpu_exit,
+ .resume = acpi_cpufreq_resume,
+ .name = "acpi-cpufreq",
+ .owner = THIS_MODULE,
+ .attr = acpi_cpufreq_attr,
};
-
-static int __init
-acpi_cpufreq_init (void)
+static int __init acpi_cpufreq_init(void)
{
dprintk("acpi_cpufreq_init\n");
- acpi_cpufreq_early_init_acpi();
+ acpi_cpufreq_early_init();
return cpufreq_register_driver(&acpi_cpufreq_driver);
}
-
-static void __exit
-acpi_cpufreq_exit (void)
+static void __exit acpi_cpufreq_exit(void)
{
- unsigned int i;
+ unsigned int i;
dprintk("acpi_cpufreq_exit\n");
cpufreq_unregister_driver(&acpi_cpufreq_driver);
@@ -627,7 +805,9 @@ acpi_cpufreq_exit (void)
}
module_param(acpi_pstate_strict, uint, 0644);
-MODULE_PARM_DESC(acpi_pstate_strict, "value 0 or non-zero. non-zero -> strict ACPI checks are performed during frequency changes.");
+MODULE_PARM_DESC(acpi_pstate_strict,
+ "value 0 or non-zero. non-zero -> strict ACPI checks are "
+ "performed during frequency changes.");
late_initcall(acpi_cpufreq_init);
module_exit(acpi_cpufreq_exit);
diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
index 92afa3bc84f..6667e9cceb9 100644
--- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
@@ -447,7 +447,6 @@ static int __init cpufreq_gx_init(void)
int ret;
struct gxfreq_params *params;
struct pci_dev *gx_pci;
- u32 class_rev;
/* Test if we have the right hardware */
if ((gx_pci = gx_detect_chipset()) == NULL)
@@ -472,8 +471,7 @@ static int __init cpufreq_gx_init(void)
pci_read_config_byte(params->cs55x0, PCI_PMER2, &(params->pci_pmer2));
pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration));
pci_read_config_byte(params->cs55x0, PCI_MODOFF, &(params->off_duration));
- pci_read_config_dword(params->cs55x0, PCI_CLASS_REVISION, &class_rev);
- params->pci_rev = class_rev && 0xff;
+ pci_read_config_byte(params->cs55x0, PCI_REVISION_ID, &params->pci_rev);
if ((ret = cpufreq_register_driver(&gx_suspmod_driver))) {
kfree(params);
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index 7233abe5d69..a3db9332d65 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -52,6 +52,10 @@
#define CPU_EZRA_T 4
#define CPU_NEHEMIAH 5
+/* Flags */
+#define USE_ACPI_C3 (1 << 1)
+#define USE_NORTHBRIDGE (1 << 2)
+
static int cpu_model;
static unsigned int numscales=16;
static unsigned int fsb;
@@ -68,7 +72,7 @@ static unsigned int minmult, maxmult;
static int can_scale_voltage;
static struct acpi_processor *pr = NULL;
static struct acpi_processor_cx *cx = NULL;
-static int port22_en;
+static u8 longhaul_flags;
/* Module parameters */
static int scale_voltage;
@@ -80,7 +84,6 @@ static int ignore_latency;
/* Clock ratios multiplied by 10 */
static int clock_ratio[32];
static int eblcr_table[32];
-static unsigned int highest_speed, lowest_speed; /* kHz */
static int longhaul_version;
static struct cpufreq_frequency_table *longhaul_table;
@@ -178,7 +181,7 @@ 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);
- if (port22_en) {
+ if (!cx_address) {
ACPI_FLUSH_CPU_CACHE();
/* Invoke C1 */
halt();
@@ -187,9 +190,8 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
/* Invoke C3 */
inb(cx_address);
/* Dummy op - must do something useless after P_LVL3 read */
- t = inl(acpi_fadt.xpm_tmr_blk.address);
+ t = inl(acpi_gbl_FADT.xpm_timer_block.address);
}
-
/* Disable bus ratio bit */
local_irq_disable();
longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
@@ -243,15 +245,13 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
outb(0xFF,0xA1); /* Overkill */
outb(0xFE,0x21); /* TMR0 only */
- if (pr->flags.bm_control) {
- /* Disable bus master arbitration */
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
- ACPI_MTX_DO_NOT_LOCK);
- } else if (port22_en) {
+ if (longhaul_flags & USE_NORTHBRIDGE) {
/* Disable AGP and PCI arbiters */
outb(3, 0x22);
+ } else if ((pr != NULL) && pr->flags.bm_control) {
+ /* Disable bus master arbitration */
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
}
-
switch (longhaul_version) {
/*
@@ -278,22 +278,23 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
* to work in practice.
*/
case TYPE_POWERSAVER:
- /* Don't allow wakeup */
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
- ACPI_MTX_DO_NOT_LOCK);
- do_powersaver(cx->address, clock_ratio_index);
+ if (longhaul_flags & USE_ACPI_C3) {
+ /* Don't allow wakeup */
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
+ do_powersaver(cx->address, clock_ratio_index);
+ } else {
+ do_powersaver(0, clock_ratio_index);
+ }
break;
}
- if (pr->flags.bm_control) {
- /* Enable bus master arbitration */
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
- ACPI_MTX_DO_NOT_LOCK);
- } else if (port22_en) {
+ if (longhaul_flags & USE_NORTHBRIDGE) {
/* Enable arbiters */
outb(0, 0x22);
+ } else if ((pr != NULL) && pr->flags.bm_control) {
+ /* Enable bus master arbitration */
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
}
-
outb(pic2_mask,0xA1); /* restore mask */
outb(pic1_mask,0x21);
@@ -314,12 +315,12 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
#define ROUNDING 0xf
-static int _guess(int guess)
+static int _guess(int guess, int mult)
{
int target;
- target = ((maxmult/10)*guess);
- if (maxmult%10 != 0)
+ target = ((mult/10)*guess);
+ if (mult%10 != 0)
target += (guess/2);
target += ROUNDING/2;
target &= ~ROUNDING;
@@ -327,17 +328,17 @@ static int _guess(int guess)
}
-static int guess_fsb(void)
+static int guess_fsb(int mult)
{
int speed = (cpu_khz/1000);
int i;
- int speeds[3] = { 66, 100, 133 };
+ int speeds[] = { 66, 100, 133, 200 };
speed += ROUNDING/2;
speed &= ~ROUNDING;
- for (i=0; i<3; i++) {
- if (_guess(speeds[i]) == speed)
+ for (i=0; i<4; i++) {
+ if (_guess(speeds[i], mult) == speed)
return speeds[i];
}
return 0;
@@ -354,9 +355,7 @@ static int __init longhaul_get_ranges(void)
130, 150, 160, 140, -1, 155, -1, 145 };
unsigned int j, k = 0;
union msr_longhaul longhaul;
- unsigned long lo, hi;
- unsigned int eblcr_fsb_table_v1[] = { 66, 133, 100, -1 };
- unsigned int eblcr_fsb_table_v2[] = { 133, 100, -1, 66 };
+ int mult = 0;
switch (longhaul_version) {
case TYPE_LONGHAUL_V1:
@@ -364,30 +363,18 @@ static int __init longhaul_get_ranges(void)
/* Ugh, Longhaul v1 didn't have the min/max MSRs.
Assume min=3.0x & max = whatever we booted at. */
minmult = 30;
- maxmult = longhaul_get_cpu_mult();
- rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
- invalue = (lo & (1<<18|1<<19)) >>18;
- if (cpu_model==CPU_SAMUEL || cpu_model==CPU_SAMUEL2)
- fsb = eblcr_fsb_table_v1[invalue];
- else
- fsb = guess_fsb();
+ maxmult = mult = longhaul_get_cpu_mult();
break;
case TYPE_POWERSAVER:
/* Ezra-T */
if (cpu_model==CPU_EZRA_T) {
+ minmult = 30;
rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
invalue = longhaul.bits.MaxMHzBR;
if (longhaul.bits.MaxMHzBR4)
invalue += 16;
- maxmult=ezra_t_multipliers[invalue];
-
- invalue = longhaul.bits.MinMHzBR;
- if (longhaul.bits.MinMHzBR4 == 1)
- minmult = 30;
- else
- minmult = ezra_t_multipliers[invalue];
- fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
+ maxmult = mult = ezra_t_multipliers[invalue];
break;
}
@@ -407,21 +394,16 @@ static int __init longhaul_get_ranges(void)
* But it works, so we don't grumble.
*/
minmult=40;
- maxmult=longhaul_get_cpu_mult();
-
- /* Starting with the 1.2GHz parts, theres a 200MHz bus. */
- if ((cpu_khz/1000) > 1200)
- fsb = 200;
- else
- fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
+ maxmult = mult = longhaul_get_cpu_mult();
break;
}
}
+ fsb = guess_fsb(mult);
dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n",
minmult/10, minmult%10, maxmult/10, maxmult%10);
- if (fsb == -1) {
+ if (fsb == 0) {
printk (KERN_INFO PFX "Invalid (reserved) FSB!\n");
return -EINVAL;
}
@@ -429,7 +411,7 @@ static int __init longhaul_get_ranges(void)
highest_speed = calc_speed(maxmult);
lowest_speed = calc_speed(minmult);
dprintk ("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb,
- print_speed(lowest_speed/1000),
+ print_speed(lowest_speed/1000),
print_speed(highest_speed/1000));
if (lowest_speed == highest_speed) {
@@ -513,7 +495,7 @@ static void __init longhaul_setup_voltagescaling(void)
maxvid.mV/1000, maxvid.mV%1000,
minvid.mV/1000, minvid.mV%1000,
numvscales);
-
+
j = 0;
while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
speed = longhaul_table[j].frequency;
@@ -583,6 +565,10 @@ static int enable_arbiter_disable(void)
if (dev == NULL) {
reg = 0x76;
dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_862X_0, NULL);
+ /* Find CN400 V-Link host bridge */
+ if (dev == NULL)
+ dev = pci_find_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);
+
}
if (dev != NULL) {
/* Enable access to port 0x22 */
@@ -687,27 +673,32 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
/* Find ACPI data for processor */
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
&longhaul_walk_callback, NULL, (void *)&pr);
- if (pr == NULL)
- goto err_acpi;
- if (longhaul_version == TYPE_POWERSAVER) {
- /* Check ACPI support for C3 state */
+ /* Check ACPI support for C3 state */
+ if ((pr != NULL) && (longhaul_version == TYPE_POWERSAVER)) {
cx = &pr->power.states[ACPI_STATE_C3];
if (cx->address > 0 &&
(cx->latency <= 1000 || ignore_latency != 0) ) {
+ longhaul_flags |= USE_ACPI_C3;
goto print_support_type;
}
}
+ /* Check if northbridge is friendly */
+ if (enable_arbiter_disable()) {
+ longhaul_flags |= USE_NORTHBRIDGE;
+ goto print_support_type;
+ }
+
+ /* No ACPI C3 or we can't use it */
/* Check ACPI support for bus master arbiter disable */
- if (!pr->flags.bm_control) {
- if (enable_arbiter_disable()) {
- port22_en = 1;
- } else {
- goto err_acpi;
- }
+ if ((pr == NULL) || !(pr->flags.bm_control)) {
+ printk(KERN_ERR PFX
+ "No ACPI support. Unsupported northbridge.\n");
+ return -ENODEV;
}
+
print_support_type:
- if (!port22_en) {
+ if (!(longhaul_flags & USE_NORTHBRIDGE)) {
printk (KERN_INFO PFX "Using ACPI support.\n");
} else {
printk (KERN_INFO PFX "Using northbridge support.\n");
@@ -732,10 +723,6 @@ print_support_type:
cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu);
return 0;
-
-err_acpi:
- printk(KERN_ERR PFX "No ACPI support. No VT8601 or VT8623 northbridge. Aborting.\n");
- return -ENODEV;
}
static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy)
@@ -770,8 +757,8 @@ static int __init longhaul_init(void)
#ifdef CONFIG_SMP
if (num_online_cpus() > 1) {
- return -ENODEV;
printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n");
+ return -ENODEV;
}
#endif
#ifdef CONFIG_X86_IO_APIC
@@ -783,8 +770,10 @@ static int __init longhaul_init(void)
switch (c->x86_model) {
case 6 ... 9:
return cpufreq_register_driver(&longhaul_driver);
+ case 10:
+ printk(KERN_ERR PFX "Use acpi-cpufreq driver for VIA C7\n");
default:
- printk (KERN_INFO PFX "Unknown VIA CPU. Contact davej@codemonkey.org.uk\n");
+ ;;
}
return -ENODEV;
diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
index 304d2eaa4a1..4786fedca6e 100644
--- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
@@ -51,7 +51,6 @@ enum {
static int has_N44_O17_errata[NR_CPUS];
-static int has_N60_errata[NR_CPUS];
static unsigned int stock_freq;
static struct cpufreq_driver p4clockmod_driver;
static unsigned int cpufreq_p4_get(unsigned int cpu);
@@ -163,29 +162,27 @@ static int cpufreq_p4_verify(struct cpufreq_policy *policy)
static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
{
- if ((c->x86 == 0x06) && (c->x86_model == 0x09)) {
- /* Pentium M (Banias) */
- printk(KERN_WARNING PFX "Warning: Pentium M detected. "
- "The speedstep_centrino module offers voltage scaling"
- " in addition of frequency scaling. You should use "
- "that instead of p4-clockmod, if possible.\n");
- return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
- }
-
- if ((c->x86 == 0x06) && (c->x86_model == 0x0D)) {
- /* Pentium M (Dothan) */
- printk(KERN_WARNING PFX "Warning: Pentium M detected. "
- "The speedstep_centrino module offers voltage scaling"
- " in addition of frequency scaling. You should use "
- "that instead of p4-clockmod, if possible.\n");
- /* on P-4s, the TSC runs with constant frequency independent whether
- * throttling is active or not. */
- p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
- return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
+ if (c->x86 == 0x06) {
+ if (cpu_has(c, X86_FEATURE_EST))
+ printk(KERN_WARNING PFX "Warning: EST-capable CPU detected. "
+ "The acpi-cpufreq module offers voltage scaling"
+ " in addition of frequency scaling. You should use "
+ "that instead of p4-clockmod, if possible.\n");
+ switch (c->x86_model) {
+ case 0x0E: /* Core */
+ case 0x0F: /* Core Duo */
+ p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
+ return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PCORE);
+ case 0x0D: /* Pentium M (Dothan) */
+ p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
+ /* fall through */
+ case 0x09: /* Pentium M (Banias) */
+ return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
+ }
}
if (c->x86 != 0xF) {
- printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to <linux@brodo.de>\n");
+ printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to <cpufreq@lists.linux.org.uk>\n");
return 0;
}
@@ -226,12 +223,6 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
case 0x0f12:
has_N44_O17_errata[policy->cpu] = 1;
dprintk("has errata -- disabling low frequencies\n");
- break;
-
- case 0x0f29:
- has_N60_errata[policy->cpu] = 1;
- dprintk("has errata -- disabling frequencies lower than 2ghz\n");
- break;
}
/* get max frequency */
@@ -243,8 +234,6 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
for (i=1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) {
if ((i<2) && (has_N44_O17_errata[policy->cpu]))
p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID;
- else if (has_N60_errata[policy->cpu] && ((stock_freq * i)/8) < 2000000)
- p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID;
else
p4clockmod_table[i].frequency = (stock_freq * i)/8;
}
diff --git a/arch/i386/kernel/cpu/cpufreq/sc520_freq.c b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c
index ef457d50f4a..b8fb4b521c6 100644
--- a/arch/i386/kernel/cpu/cpufreq/sc520_freq.c
+++ b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c
@@ -153,6 +153,7 @@ static struct cpufreq_driver sc520_freq_driver = {
static int __init sc520_freq_init(void)
{
struct cpuinfo_x86 *c = cpu_data;
+ int err;
/* Test if we have the right hardware */
if(c->x86_vendor != X86_VENDOR_AMD ||
@@ -166,7 +167,11 @@ static int __init sc520_freq_init(void)
return -ENOMEM;
}
- return cpufreq_register_driver(&sc520_freq_driver);
+ err = cpufreq_register_driver(&sc520_freq_driver);
+ if (err)
+ iounmap(cpuctl);
+
+ return err;
}
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
index e8993baf3d1..f43b987f952 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -36,6 +36,7 @@
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg)
+#define INTEL_MSR_RANGE (0xffff)
struct cpu_id
{
@@ -379,6 +380,7 @@ static int centrino_cpu_early_init_acpi(void)
}
+#ifdef CONFIG_SMP
/*
* Some BIOSes do SW_ANY coordination internally, either set it up in hw
* or do it in BIOS firmware and won't inform about it to OS. If not
@@ -392,7 +394,6 @@ static int sw_any_bug_found(struct dmi_system_id *d)
return 0;
}
-
static struct dmi_system_id sw_any_bug_dmi_table[] = {
{
.callback = sw_any_bug_found,
@@ -405,7 +406,7 @@ static struct dmi_system_id sw_any_bug_dmi_table[] = {
},
{ }
};
-
+#endif
/*
* centrino_cpu_init_acpi - register with ACPI P-States library
@@ -463,8 +464,9 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
}
for (i=0; i<p->state_count; i++) {
- if (p->states[i].control != p->states[i].status) {
- dprintk("Different control (%llu) and status values (%llu)\n",
+ if ((p->states[i].control & INTEL_MSR_RANGE) !=
+ (p->states[i].status & INTEL_MSR_RANGE)) {
+ dprintk("Different MSR bits in control (%llu) and status (%llu)\n",
p->states[i].control, p->states[i].status);
result = -EINVAL;
goto err_unreg;
@@ -500,7 +502,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
}
for (i=0; i<p->state_count; i++) {
- centrino_model[cpu]->op_points[i].index = p->states[i].control;
+ centrino_model[cpu]->op_points[i].index = p->states[i].control & INTEL_MSR_RANGE;
centrino_model[cpu]->op_points[i].frequency = p->states[i].core_frequency * 1000;
dprintk("adding state %i with frequency %u and control value %04x\n",
i, centrino_model[cpu]->op_points[i].frequency, centrino_model[cpu]->op_points[i].index);
@@ -531,6 +533,9 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
/* notify BIOS that we exist */
acpi_processor_notify_smm(THIS_MODULE);
+ printk("speedstep-centrino with X86_SPEEDSTEP_CENTRINO_ACPI "
+ "config is deprecated.\n "
+ "Use X86_ACPI_CPUFREQ (acpi-cpufreq) instead.\n" );
return 0;
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
index 4f46cac155c..d59277c0091 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
@@ -123,6 +123,36 @@ static unsigned int pentiumM_get_frequency(void)
return (msr_tmp * 100 * 1000);
}
+static unsigned int pentium_core_get_frequency(void)
+{
+ u32 fsb = 0;
+ u32 msr_lo, msr_tmp;
+
+ rdmsr(MSR_FSB_FREQ, msr_lo, msr_tmp);
+ /* see table B-2 of 25366920.pdf */
+ switch (msr_lo & 0x07) {
+ case 5:
+ fsb = 100000;
+ break;
+ case 1:
+ fsb = 133333;
+ break;
+ case 3:
+ fsb = 166667;
+ break;
+ default:
+ printk(KERN_ERR "PCORE - MSR_FSB_FREQ undefined value");
+ }
+
+ rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
+ dprintk("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
+
+ msr_tmp = (msr_lo >> 22) & 0x1f;
+ dprintk("bits 22-26 are 0x%x, speed is %u\n", msr_tmp, (msr_tmp * fsb));
+
+ return (msr_tmp * fsb);
+}
+
static unsigned int pentium4_get_frequency(void)
{
@@ -174,6 +204,8 @@ static unsigned int pentium4_get_frequency(void)
unsigned int speedstep_get_processor_frequency(unsigned int processor)
{
switch (processor) {
+ case SPEEDSTEP_PROCESSOR_PCORE:
+ return pentium_core_get_frequency();
case SPEEDSTEP_PROCESSOR_PM:
return pentiumM_get_frequency();
case SPEEDSTEP_PROCESSOR_P4D:
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h
index b735429c50b..b11bcc608ca 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h
@@ -22,6 +22,7 @@
* the speedstep_get_processor_frequency() call. */
#define SPEEDSTEP_PROCESSOR_PM 0xFFFFFF03 /* Pentium M */
#define SPEEDSTEP_PROCESSOR_P4D 0xFFFFFF04 /* desktop P4 */
+#define SPEEDSTEP_PROCESSOR_PCORE 0xFFFFFF05 /* Core */
/* speedstep states -- only two of them */
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
index c28333d5364..ff0d8980611 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
@@ -360,9 +360,6 @@ static int __init speedstep_init(void)
case SPEEDSTEP_PROCESSOR_PIII_C:
case SPEEDSTEP_PROCESSOR_PIII_C_EARLY:
break;
- case SPEEDSTEP_PROCESSOR_P4M:
- printk(KERN_INFO "speedstep-smi: you're trying to use this cpufreq driver on a Pentium 4-based CPU. Most likely it will not work.\n");
- break;
default:
speedstep_processor = 0;
}
diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c
index db6dd20c358..51130b39cd2 100644
--- a/arch/i386/kernel/cpuid.c
+++ b/arch/i386/kernel/cpuid.c
@@ -116,7 +116,7 @@ static ssize_t cpuid_read(struct file *file, char __user *buf,
char __user *tmp = buf;
u32 data[4];
u32 reg = *ppos;
- int cpu = iminor(file->f_dentry->d_inode);
+ int cpu = iminor(file->f_path.dentry->d_inode);
if (count % 16)
return -EINVAL; /* Invalid chunk size */
@@ -134,7 +134,7 @@ static ssize_t cpuid_read(struct file *file, char __user *buf,
static int cpuid_open(struct inode *inode, struct file *file)
{
- unsigned int cpu = iminor(file->f_dentry->d_inode);
+ unsigned int cpu = iminor(file->f_path.dentry->d_inode);
struct cpuinfo_x86 *c = &(cpu_data)[cpu];
if (cpu >= NR_CPUS || !cpu_online(cpu))
diff --git a/arch/i386/kernel/e820.c b/arch/i386/kernel/e820.c
index 2f7d0a92fd7..f391abcf7da 100644
--- a/arch/i386/kernel/e820.c
+++ b/arch/i386/kernel/e820.c
@@ -668,7 +668,7 @@ void __init register_bootmem_low_pages(unsigned long max_low_pfn)
}
}
-void __init register_memory(void)
+void __init e820_register_memory(void)
{
unsigned long gapstart, gapsize, round;
unsigned long long last;
diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c
index b92c7f0a358..8f9c624ace6 100644
--- a/arch/i386/kernel/efi.c
+++ b/arch/i386/kernel/efi.c
@@ -473,6 +473,70 @@ static inline void __init check_range_for_systab(efi_memory_desc_t *md)
}
/*
+ * Wrap all the virtual calls in a way that forces the parameters on the stack.
+ */
+
+#define efi_call_virt(f, args...) \
+ ((efi_##f##_t __attribute__((regparm(0)))*)efi.systab->runtime->f)(args)
+
+static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+ return efi_call_virt(get_time, tm, tc);
+}
+
+static efi_status_t virt_efi_set_time (efi_time_t *tm)
+{
+ return efi_call_virt(set_time, tm);
+}
+
+static efi_status_t virt_efi_get_wakeup_time (efi_bool_t *enabled,
+ efi_bool_t *pending,
+ efi_time_t *tm)
+{
+ return efi_call_virt(get_wakeup_time, enabled, pending, tm);
+}
+
+static efi_status_t virt_efi_set_wakeup_time (efi_bool_t enabled,
+ efi_time_t *tm)
+{
+ return efi_call_virt(set_wakeup_time, enabled, tm);
+}
+
+static efi_status_t virt_efi_get_variable (efi_char16_t *name,
+ efi_guid_t *vendor, u32 *attr,
+ unsigned long *data_size, void *data)
+{
+ return efi_call_virt(get_variable, name, vendor, attr, data_size, data);
+}
+
+static efi_status_t virt_efi_get_next_variable (unsigned long *name_size,
+ efi_char16_t *name,
+ efi_guid_t *vendor)
+{
+ return efi_call_virt(get_next_variable, name_size, name, vendor);
+}
+
+static efi_status_t virt_efi_set_variable (efi_char16_t *name,
+ efi_guid_t *vendor,
+ unsigned long attr,
+ unsigned long data_size, void *data)
+{
+ return efi_call_virt(set_variable, name, vendor, attr, data_size, data);
+}
+
+static efi_status_t virt_efi_get_next_high_mono_count (u32 *count)
+{
+ return efi_call_virt(get_next_high_mono_count, count);
+}
+
+static void virt_efi_reset_system (int reset_type, efi_status_t status,
+ unsigned long data_size,
+ efi_char16_t *data)
+{
+ efi_call_virt(reset_system, reset_type, status, data_size, data);
+}
+
+/*
* This function will switch the EFI runtime services to virtual mode.
* Essentially, look through the EFI memmap and map every region that
* has the runtime attribute bit set in its memory descriptor and update
@@ -525,22 +589,15 @@ void __init efi_enter_virtual_mode(void)
* pointers in the runtime service table to the new virtual addresses.
*/
- efi.get_time = (efi_get_time_t *) efi.systab->runtime->get_time;
- efi.set_time = (efi_set_time_t *) efi.systab->runtime->set_time;
- efi.get_wakeup_time = (efi_get_wakeup_time_t *)
- efi.systab->runtime->get_wakeup_time;
- efi.set_wakeup_time = (efi_set_wakeup_time_t *)
- efi.systab->runtime->set_wakeup_time;
- efi.get_variable = (efi_get_variable_t *)
- efi.systab->runtime->get_variable;
- efi.get_next_variable = (efi_get_next_variable_t *)
- efi.systab->runtime->get_next_variable;
- efi.set_variable = (efi_set_variable_t *)
- efi.systab->runtime->set_variable;
- efi.get_next_high_mono_count = (efi_get_next_high_mono_count_t *)
- efi.systab->runtime->get_next_high_mono_count;
- efi.reset_system = (efi_reset_system_t *)
- efi.systab->runtime->reset_system;
+ efi.get_time = virt_efi_get_time;
+ efi.set_time = virt_efi_set_time;
+ efi.get_wakeup_time = virt_efi_get_wakeup_time;
+ efi.set_wakeup_time = virt_efi_set_wakeup_time;
+ efi.get_variable = virt_efi_get_variable;
+ efi.get_next_variable = virt_efi_get_next_variable;
+ efi.set_variable = virt_efi_set_variable;
+ efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
+ efi.reset_system = virt_efi_reset_system;
}
void __init
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index de34b7fed3c..5e47683fc63 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -302,12 +302,16 @@ sysenter_past_esp:
pushl $(__USER_CS)
CFI_ADJUST_CFA_OFFSET 4
/*CFI_REL_OFFSET cs, 0*/
+#ifndef CONFIG_COMPAT_VDSO
/*
* Push current_thread_info()->sysenter_return to the stack.
* A tiny bit of offset fixup is necessary - 4*4 means the 4 words
* pushed above; +8 corresponds to copy_thread's esp0 setting.
*/
pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
+#else
+ pushl $SYSENTER_RETURN
+#endif
CFI_ADJUST_CFA_OFFSET 4
CFI_REL_OFFSET eip, 0
@@ -979,38 +983,6 @@ ENTRY(spurious_interrupt_bug)
jmp error_code
CFI_ENDPROC
-#ifdef CONFIG_STACK_UNWIND
-ENTRY(arch_unwind_init_running)
- CFI_STARTPROC
- movl 4(%esp), %edx
- movl (%esp), %ecx
- leal 4(%esp), %eax
- movl %ebx, PT_EBX(%edx)
- xorl %ebx, %ebx
- movl %ebx, PT_ECX(%edx)
- movl %ebx, PT_EDX(%edx)
- movl %esi, PT_ESI(%edx)
- movl %edi, PT_EDI(%edx)
- movl %ebp, PT_EBP(%edx)
- movl %ebx, PT_EAX(%edx)
- movl $__USER_DS, PT_DS(%edx)
- movl $__USER_DS, PT_ES(%edx)
- movl $0, PT_GS(%edx)
- movl %ebx, PT_ORIG_EAX(%edx)
- movl %ecx, PT_EIP(%edx)
- movl 12(%esp), %ecx
- movl $__KERNEL_CS, PT_CS(%edx)
- movl %ebx, PT_EFLAGS(%edx)
- movl %eax, PT_OLDESP(%edx)
- movl 8(%esp), %eax
- movl %ecx, 8(%esp)
- movl PT_EBX(%edx), %ebx
- movl $__KERNEL_DS, PT_OLDSS(%edx)
- jmpl *%eax
- CFI_ENDPROC
-ENDPROC(arch_unwind_init_running)
-#endif
-
ENTRY(kernel_thread_helper)
pushl $0 # fake return address for unwinder
CFI_STARTPROC
diff --git a/arch/i386/kernel/hpet.c b/arch/i386/kernel/hpet.c
index 45a8685bb60..0b29d41322a 100644
--- a/arch/i386/kernel/hpet.c
+++ b/arch/i386/kernel/hpet.c
@@ -12,7 +12,7 @@
/* FSEC = 10^-15 NSEC = 10^-9 */
#define FSEC_PER_NSEC 1000000
-static void *hpet_ptr;
+static void __iomem *hpet_ptr;
static cycle_t read_hpet(void)
{
@@ -40,8 +40,7 @@ static int __init init_hpet_clocksource(void)
return -ENODEV;
/* calculate the hpet address: */
- hpet_base =
- (void __iomem*)ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
+ hpet_base = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
hpet_ptr = hpet_base + HPET_COUNTER;
/* calculate the frequency: */
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index e21dcde0790..ba8d302a0b7 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -126,7 +126,7 @@ static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned i
*/
static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
{
- volatile struct io_apic *io_apic = io_apic_base(apic);
+ volatile struct io_apic __iomem *io_apic = io_apic_base(apic);
if (sis_apic_bug)
writel(reg, &io_apic->index);
writel(value, &io_apic->data);
@@ -1227,26 +1227,32 @@ static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }
static int __assign_irq_vector(int irq)
{
- static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
- int vector;
+ static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0;
+ int vector, offset, i;
BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
if (irq_vector[irq] > 0)
return irq_vector[irq];
- current_vector += 8;
- if (current_vector == SYSCALL_VECTOR)
- current_vector += 8;
-
- if (current_vector >= FIRST_SYSTEM_VECTOR) {
- offset++;
- if (!(offset % 8))
- return -ENOSPC;
- current_vector = FIRST_DEVICE_VECTOR + offset;
- }
-
vector = current_vector;
+ offset = current_offset;
+next:
+ vector += 8;
+ if (vector >= FIRST_SYSTEM_VECTOR) {
+ offset = (offset + 1) % 8;
+ vector = FIRST_DEVICE_VECTOR + offset;
+ }
+ if (vector == current_vector)
+ return -ENOSPC;
+ if (vector == SYSCALL_VECTOR)
+ goto next;
+ for (i = 0; i < NR_IRQ_VECTORS; i++)
+ if (irq_vector[i] == vector)
+ goto next;
+
+ current_vector = vector;
+ current_offset = offset;
irq_vector[irq] = vector;
return vector;
@@ -2485,7 +2491,7 @@ device_initcall(ioapic_init_sysfs);
int create_irq(void)
{
/* Allocate an unused irq */
- int irq, new, vector;
+ int irq, new, vector = 0;
unsigned long flags;
irq = -ENOSPC;
@@ -2600,25 +2606,32 @@ static struct irq_chip msi_chip = {
.retrigger = ioapic_retrigger_irq,
};
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
{
struct msi_msg msg;
- int ret;
+ int irq, ret;
+ irq = create_irq();
+ if (irq < 0)
+ return irq;
+
+ set_irq_msi(irq, desc);
ret = msi_compose_msg(dev, irq, &msg);
- if (ret < 0)
+ if (ret < 0) {
+ destroy_irq(irq);
return ret;
+ }
write_msi_msg(irq, &msg);
set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq,
"edge");
- return 0;
+ return irq;
}
void arch_teardown_msi_irq(unsigned int irq)
{
- return;
+ destroy_irq(irq);
}
#endif /* CONFIG_PCI_MSI */
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index 972346604f9..c8fa13721bc 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -1,7 +1,7 @@
/*
* Intel CPU Microcode Update Driver for Linux
*
- * Copyright (C) 2000-2004 Tigran Aivazian
+ * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
* 2006 Shaohua Li <shaohua.li@intel.com>
*
* This driver allows to upgrade microcode on Intel processors
@@ -92,7 +92,7 @@
#include <asm/processor.h>
MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
-MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
MODULE_LICENSE("GPL");
#define MICROCODE_VERSION "1.14a"
@@ -722,7 +722,7 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
return NOTIFY_OK;
}
-static struct notifier_block mc_cpu_notifier = {
+static struct notifier_block __cpuinitdata mc_cpu_notifier = {
.notifier_call = mc_cpu_callback,
};
@@ -752,7 +752,7 @@ static int __init microcode_init (void)
register_hotcpu_notifier(&mc_cpu_notifier);
printk(KERN_INFO
- "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n");
+ "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
return 0;
}
diff --git a/arch/i386/kernel/module.c b/arch/i386/kernel/module.c
index d7d9c8b23f7..3db0a5442eb 100644
--- a/arch/i386/kernel/module.c
+++ b/arch/i386/kernel/module.c
@@ -21,6 +21,7 @@
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/bug.h>
#if 0
#define DEBUGP printk
@@ -141,10 +142,11 @@ int module_finalize(const Elf_Ehdr *hdr,
apply_paravirt(pseg, pseg + para->sh_size);
}
- return 0;
+ return module_bug_finalize(hdr, sechdrs, me);
}
void module_arch_cleanup(struct module *mod)
{
alternatives_smp_module_del(mod);
+ module_bug_cleanup(mod);
}
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index 2ce67228dff..4f5983c9866 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -36,7 +36,7 @@
/* Have we found an MP table */
int smp_found_config;
-unsigned int __initdata maxcpus = NR_CPUS;
+unsigned int __cpuinitdata maxcpus = NR_CPUS;
/*
* Various Linux-internal data structures created from the
@@ -102,9 +102,9 @@ static int __init mpf_checksum(unsigned char *mp, int len)
*/
static int mpc_record;
-static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata;
+static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __cpuinitdata;
-static void __devinit MP_processor_info (struct mpc_config_processor *m)
+static void __cpuinit MP_processor_info (struct mpc_config_processor *m)
{
int ver, apicid;
physid_mask_t phys_cpu;
@@ -822,7 +822,7 @@ void __init mp_register_lapic_address(u64 address)
Dprintk("Boot CPU = %d\n", boot_cpu_physical_apicid);
}
-void __devinit mp_register_lapic (u8 id, u8 enabled)
+void __cpuinit mp_register_lapic (u8 id, u8 enabled)
{
struct mpc_config_processor processor;
int boot_cpu = 0;
@@ -1057,7 +1057,7 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
static int gsi_to_irq[MAX_GSI_NUM];
/* Don't set up the ACPI SCI because it's already set up */
- if (acpi_fadt.sci_int == gsi)
+ if (acpi_gbl_FADT.sci_interrupt == gsi)
return gsi;
ioapic = mp_find_ioapic(gsi);
@@ -1114,7 +1114,7 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
/*
* Don't assign IRQ used by ACPI SCI
*/
- if (gsi == acpi_fadt.sci_int)
+ if (gsi == acpi_gbl_FADT.sci_interrupt)
gsi = pci_irq++;
gsi_to_irq[irq] = gsi;
} else {
diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
index 1d1a56cae34..4a472a17d1c 100644
--- a/arch/i386/kernel/msr.c
+++ b/arch/i386/kernel/msr.c
@@ -172,7 +172,7 @@ static ssize_t msr_read(struct file *file, char __user * buf,
u32 __user *tmp = (u32 __user *) buf;
u32 data[2];
u32 reg = *ppos;
- int cpu = iminor(file->f_dentry->d_inode);
+ int cpu = iminor(file->f_path.dentry->d_inode);
int err;
if (count % 8)
@@ -196,7 +196,7 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
const u32 __user *tmp = (const u32 __user *)buf;
u32 data[2];
u32 reg = *ppos;
- int cpu = iminor(file->f_dentry->d_inode);
+ int cpu = iminor(file->f_path.dentry->d_inode);
int err;
if (count % 8)
@@ -216,7 +216,7 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
static int msr_open(struct inode *inode, struct file *file)
{
- unsigned int cpu = iminor(file->f_dentry->d_inode);
+ unsigned int cpu = iminor(file->f_path.dentry->d_inode);
struct cpuinfo_x86 *c = &(cpu_data)[cpu];
if (cpu >= NR_CPUS || !cpu_online(cpu))
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index f5bc7e1be80..1a6f8bb8881 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -195,6 +195,8 @@ static __cpuinit inline int nmi_known_cpu(void)
return 0;
}
+static int endflag __initdata = 0;
+
#ifdef CONFIG_SMP
/* The performance counters used by NMI_LOCAL_APIC don't trigger when
* the CPU is idle. To make sure the NMI watchdog really ticks on all
@@ -202,7 +204,6 @@ static __cpuinit inline int nmi_known_cpu(void)
*/
static __init void nmi_cpu_busy(void *data)
{
- volatile int *endflag = data;
local_irq_enable_in_hardirq();
/* Intentionally don't use cpu_relax here. This is
to make sure that the performance counter really ticks,
@@ -210,14 +211,13 @@ static __init void nmi_cpu_busy(void *data)
pause instruction. On a real HT machine this is fine because
all other CPUs are busy with "useless" delay loops and don't
care if they get somewhat less cycles. */
- while (*endflag == 0)
- barrier();
+ while (endflag == 0)
+ mb();
}
#endif
static int __init check_nmi_watchdog(void)
{
- volatile int endflag = 0;
unsigned int *prev_nmi_count;
int cpu;
@@ -310,13 +310,7 @@ static int __init setup_nmi_watchdog(char *str)
if ((nmi >= NMI_INVALID) || (nmi < NMI_NONE))
return 0;
- /*
- * If any other x86 CPU has a local APIC, then
- * please test the NMI stuff there and send me the
- * missing bits. Right now Intel P6/P4 and AMD K7 only.
- */
- if ((nmi == NMI_LOCAL_APIC) && (nmi_known_cpu() == 0))
- return 0; /* no lapic support */
+
nmi_watchdog = nmi;
return 1;
}
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c
index 3dceab5828f..e55fd05da0f 100644
--- a/arch/i386/kernel/paravirt.c
+++ b/arch/i386/kernel/paravirt.c
@@ -566,4 +566,11 @@ struct paravirt_ops paravirt_ops = {
.irq_enable_sysexit = native_irq_enable_sysexit,
.iret = native_iret,
};
-EXPORT_SYMBOL(paravirt_ops);
+
+/*
+ * NOTE: CONFIG_PARAVIRT is experimental and the paravirt_ops
+ * semantics are subject to change. Hence we only do this
+ * internal-only export of this, until it gets sorted out and
+ * all lowlevel CPU ops used by modules are separately exported.
+ */
+EXPORT_SYMBOL_GPL(paravirt_ops);
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 99308510a17..c641056233a 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -102,7 +102,12 @@ void default_idle(void)
{
if (!hlt_counter && boot_cpu_data.hlt_works_ok) {
current_thread_info()->status &= ~TS_POLLING;
- smp_mb__after_clear_bit();
+ /*
+ * TS_POLLING-cleared state must be visible before we
+ * test NEED_RESCHED:
+ */
+ smp_mb();
+
local_irq_disable();
if (!need_resched())
safe_halt(); /* enables interrupts racelessly */
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index f3f94ac5736..af8aabe8580 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -45,7 +45,7 @@
/*
* Offset of eflags on child stack..
*/
-#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
+#define EFL_OFFSET offsetof(struct pt_regs, eflags)
static inline struct pt_regs *get_child_regs(struct task_struct *task)
{
@@ -54,24 +54,24 @@ static inline struct pt_regs *get_child_regs(struct task_struct *task)
}
/*
- * this routine will get a word off of the processes privileged stack.
- * the offset is how far from the base addr as stored in the TSS.
- * this routine assumes that all the privileged stacks are in our
+ * This routine will get a word off of the processes privileged stack.
+ * the offset is bytes into the pt_regs structure on the stack.
+ * This routine assumes that all the privileged stacks are in our
* data space.
*/
static inline int get_stack_long(struct task_struct *task, int offset)
{
unsigned char *stack;
- stack = (unsigned char *)task->thread.esp0;
+ stack = (unsigned char *)task->thread.esp0 - sizeof(struct pt_regs);
stack += offset;
return (*((int *)stack));
}
/*
- * this routine will put a word on the processes privileged stack.
- * the offset is how far from the base addr as stored in the TSS.
- * this routine assumes that all the privileged stacks are in our
+ * This routine will put a word on the processes privileged stack.
+ * the offset is bytes into the pt_regs structure on the stack.
+ * This routine assumes that all the privileged stacks are in our
* data space.
*/
static inline int put_stack_long(struct task_struct *task, int offset,
@@ -79,7 +79,7 @@ static inline int put_stack_long(struct task_struct *task, int offset,
{
unsigned char * stack;
- stack = (unsigned char *) task->thread.esp0;
+ stack = (unsigned char *)task->thread.esp0 - sizeof(struct pt_regs);
stack += offset;
*(unsigned long *) stack = data;
return 0;
@@ -114,7 +114,7 @@ static int putreg(struct task_struct *child,
}
if (regno > ES*4)
regno -= 1*4;
- put_stack_long(child, regno - sizeof(struct pt_regs), value);
+ put_stack_long(child, regno, value);
return 0;
}
@@ -137,7 +137,6 @@ static unsigned long getreg(struct task_struct *child,
default:
if (regno > ES*4)
regno -= 1*4;
- regno = regno - sizeof(struct pt_regs);
retval &= get_stack_long(child, regno);
}
return retval;
diff --git a/arch/i386/kernel/quirks.c b/arch/i386/kernel/quirks.c
index a01320a7b63..34874c398b4 100644
--- a/arch/i386/kernel/quirks.c
+++ b/arch/i386/kernel/quirks.c
@@ -10,13 +10,38 @@
#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
static void __devinit verify_quirk_intel_irqbalance(struct pci_dev *dev)
{
+ u8 config, rev;
+ u32 word;
+
+ /* BIOS may enable hardware IRQ balancing for
+ * E7520/E7320/E7525(revision ID 0x9 and below)
+ * based platforms.
+ * For those platforms, make sure that the genapic is set to 'flat'
+ */
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
+ if (rev > 0x9)
+ return;
+
+ /* enable access to config space*/
+ pci_read_config_byte(dev, 0xf4, &config);
+ pci_write_config_byte(dev, 0xf4, config|0x2);
+
+ /* read xTPR register */
+ raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word);
+
+ if (!(word & (1 << 13))) {
#ifdef CONFIG_X86_64
- if (genapic != &apic_flat)
- panic("APIC mode must be flat on this system\n");
+ if (genapic != &apic_flat)
+ panic("APIC mode must be flat on this system\n");
#elif defined(CONFIG_X86_GENERICARCH)
- if (genapic != &apic_default)
- panic("APIC mode must be default(flat) on this system. Use apic=default\n");
+ if (genapic != &apic_default)
+ panic("APIC mode must be default(flat) on this system. Use apic=default\n");
#endif
+ }
+
+ /* put back the original value for config space*/
+ if (!(config & 0x2))
+ pci_write_config_byte(dev, 0xf4, config);
}
void __init quirk_intel_irqbalance(void)
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 79df6e612db..4b31ad70c1a 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -77,7 +77,7 @@ extern struct resource code_resource;
extern struct resource data_resource;
/* cpu data as detected by the assembly code in head.S */
-struct cpuinfo_x86 new_cpu_data __initdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
+struct cpuinfo_x86 new_cpu_data __cpuinitdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
/* common cpu data for all cpus */
struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
EXPORT_SYMBOL(boot_cpu_data);
@@ -495,7 +495,7 @@ static void set_mca_bus(int x) { }
#endif
/* Overridden in paravirt.c if CONFIG_PARAVIRT */
-char * __attribute__((weak)) memory_setup(void)
+char * __init __attribute__((weak)) memory_setup(void)
{
return machine_specific_memory_setup();
}
@@ -639,7 +639,7 @@ void __init setup_arch(char **cmdline_p)
get_smp_config();
#endif
- register_memory();
+ e820_register_memory();
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 4bf0e3c83b8..8c6c8c52b95 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -69,9 +69,7 @@ static int __devinitdata smp_b_stepping;
/* Number of siblings per CPU package */
int smp_num_siblings = 1;
-#ifdef CONFIG_X86_HT
EXPORT_SYMBOL(smp_num_siblings);
-#endif
/* Last level cache ID of each logical CPU */
int cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID};
@@ -161,7 +159,7 @@ void __init smp_alloc_memory(void)
* a given CPU
*/
-static void __devinit smp_store_cpu_info(int id)
+static void __cpuinit smp_store_cpu_info(int id)
{
struct cpuinfo_x86 *c = cpu_data + id;
@@ -229,7 +227,7 @@ static struct {
atomic_t count_start;
atomic_t count_stop;
unsigned long long values[NR_CPUS];
-} tsc __initdata = {
+} tsc __cpuinitdata = {
.start_flag = ATOMIC_INIT(0),
.count_start = ATOMIC_INIT(0),
.count_stop = ATOMIC_INIT(0),
@@ -334,7 +332,7 @@ static void __init synchronize_tsc_bp(void)
printk("passed.\n");
}
-static void __init synchronize_tsc_ap(void)
+static void __cpuinit synchronize_tsc_ap(void)
{
int i;
@@ -366,7 +364,7 @@ extern void calibrate_delay(void);
static atomic_t init_deasserted;
-static void __devinit smp_callin(void)
+static void __cpuinit smp_callin(void)
{
int cpuid, phys_id;
unsigned long timeout;
@@ -540,7 +538,7 @@ set_cpu_sibling_map(int cpu)
/*
* Activate a secondary processor.
*/
-static void __devinit start_secondary(void *unused)
+static void __cpuinit start_secondary(void *unused)
{
/*
* Don't put *anything* before secondary_cpu_init(), SMP
@@ -598,6 +596,12 @@ static void __devinit start_secondary(void *unused)
void __devinit initialize_secondary(void)
{
/*
+ * switch to the per CPU GDT we already set up
+ * in do_boot_cpu()
+ */
+ cpu_set_gdt(current_thread_info()->cpu);
+
+ /*
* We don't actually need to load the full TSS,
* basically just the stack pointer and the eip.
*/
@@ -933,7 +937,7 @@ static inline struct task_struct * alloc_idle_task(int cpu)
#define alloc_idle_task(cpu) fork_idle(cpu)
#endif
-static int __devinit do_boot_cpu(int apicid, int cpu)
+static int __cpuinit do_boot_cpu(int apicid, int cpu)
/*
* NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
* (ie clustered apic addressing mode), this is a LOGICAL apic ID.
@@ -974,9 +978,6 @@ static int __devinit do_boot_cpu(int apicid, int cpu)
/* Stack for startup_32 can be just as for start_secondary onwards */
stack_start.esp = (void *) idle->thread.esp;
- start_pda = cpu_pda(cpu);
- cpu_gdt_descr = per_cpu(cpu_gdt_descr, cpu);
-
irq_ctx_init(cpu);
x86_cpu_to_apicid[cpu] = apicid;
@@ -1118,7 +1119,7 @@ static int __cpuinit __smp_prepare_cpu(int cpu)
/* init low mem mapping */
clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
- KERNEL_PGD_PTRS);
+ min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
flush_tlb_all();
schedule_work(&info.task);
wait_for_completion(&done);
@@ -1434,7 +1435,7 @@ void __cpu_die(unsigned int cpu)
}
#endif /* CONFIG_HOTPLUG_CPU */
-int __devinit __cpu_up(unsigned int cpu)
+int __cpuinit __cpu_up(unsigned int cpu)
{
#ifdef CONFIG_HOTPLUG_CPU
int ret=0;
diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c
index f7e735c077c..2a8713ec0f9 100644
--- a/arch/i386/kernel/srat.c
+++ b/arch/i386/kernel/srat.c
@@ -62,19 +62,19 @@ extern void * boot_ioremap(unsigned long, unsigned long);
/* Identify CPU proximity domains */
static void __init parse_cpu_affinity_structure(char *p)
{
- struct acpi_table_processor_affinity *cpu_affinity =
- (struct acpi_table_processor_affinity *) p;
+ struct acpi_srat_cpu_affinity *cpu_affinity =
+ (struct acpi_srat_cpu_affinity *) p;
- if (!cpu_affinity->flags.enabled)
+ if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0)
return; /* empty entry */
/* mark this node as "seen" in node bitmap */
- BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain);
+ BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain_lo);
- apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain;
+ apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain_lo;
printk("CPU 0x%02X in proximity domain 0x%02X\n",
- cpu_affinity->apic_id, cpu_affinity->proximity_domain);
+ cpu_affinity->apic_id, cpu_affinity->proximity_domain_lo);
}
/*
@@ -84,28 +84,27 @@ static void __init parse_cpu_affinity_structure(char *p)
static void __init parse_memory_affinity_structure (char *sratp)
{
unsigned long long paddr, size;
- unsigned long start_pfn, end_pfn;
+ unsigned long start_pfn, end_pfn;
u8 pxm;
struct node_memory_chunk_s *p, *q, *pend;
- struct acpi_table_memory_affinity *memory_affinity =
- (struct acpi_table_memory_affinity *) sratp;
+ struct acpi_srat_mem_affinity *memory_affinity =
+ (struct acpi_srat_mem_affinity *) sratp;
- if (!memory_affinity->flags.enabled)
+ if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0)
return; /* empty entry */
+ pxm = memory_affinity->proximity_domain & 0xff;
+
/* mark this node as "seen" in node bitmap */
- BMAP_SET(pxm_bitmap, memory_affinity->proximity_domain);
+ BMAP_SET(pxm_bitmap, pxm);
/* calculate info for memory chunk structure */
- paddr = memory_affinity->base_addr_hi;
- paddr = (paddr << 32) | memory_affinity->base_addr_lo;
- size = memory_affinity->length_hi;
- size = (size << 32) | memory_affinity->length_lo;
-
+ paddr = memory_affinity->base_address;
+ size = memory_affinity->length;
+
start_pfn = paddr >> PAGE_SHIFT;
end_pfn = (paddr + size) >> PAGE_SHIFT;
-
- pxm = memory_affinity->proximity_domain;
+
if (num_memory_chunks >= MAXCHUNKS) {
printk("Too many mem chunks in SRAT. Ignoring %lld MBytes at %llx\n",
@@ -132,8 +131,8 @@ static void __init parse_memory_affinity_structure (char *sratp)
printk("Memory range 0x%lX to 0x%lX (type 0x%X) in proximity domain 0x%02X %s\n",
start_pfn, end_pfn,
memory_affinity->memory_type,
- memory_affinity->proximity_domain,
- (memory_affinity->flags.hot_pluggable ?
+ pxm,
+ ((memory_affinity->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ?
"enabled and removable" : "enabled" ) );
}
@@ -185,10 +184,10 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
num_memory_chunks = 0;
while (p < end) {
switch (*p) {
- case ACPI_SRAT_PROCESSOR_AFFINITY:
+ case ACPI_SRAT_TYPE_CPU_AFFINITY:
parse_cpu_affinity_structure(p);
break;
- case ACPI_SRAT_MEMORY_AFFINITY:
+ case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
parse_memory_affinity_structure(p);
break;
default:
@@ -262,31 +261,30 @@ out_fail:
return 0;
}
+struct acpi_static_rsdt {
+ struct acpi_table_rsdt table;
+ u32 padding[7]; /* Allow for 7 more table entries */
+};
+
int __init get_memcfg_from_srat(void)
{
struct acpi_table_header *header = NULL;
struct acpi_table_rsdp *rsdp = NULL;
struct acpi_table_rsdt *rsdt = NULL;
- struct acpi_pointer *rsdp_address = NULL;
- struct acpi_table_rsdt saved_rsdt;
+ acpi_native_uint rsdp_address = 0;
+ struct acpi_static_rsdt saved_rsdt;
int tables = 0;
int i = 0;
- if (ACPI_FAILURE(acpi_find_root_pointer(ACPI_PHYSICAL_ADDRESSING,
- rsdp_address))) {
+ rsdp_address = acpi_find_rsdp();
+ if (!rsdp_address) {
printk("%s: System description tables not found\n",
__FUNCTION__);
goto out_err;
}
- if (rsdp_address->pointer_type == ACPI_PHYSICAL_POINTER) {
- printk("%s: assigning address to rsdp\n", __FUNCTION__);
- rsdp = (struct acpi_table_rsdp *)
- (u32)rsdp_address->pointer.physical;
- } else {
- printk("%s: rsdp_address is not a physical pointer\n", __FUNCTION__);
- goto out_err;
- }
+ printk("%s: assigning address to rsdp\n", __FUNCTION__);
+ rsdp = (struct acpi_table_rsdp *)(u32)rsdp_address;
if (!rsdp) {
printk("%s: Didn't find ACPI root!\n", __FUNCTION__);
goto out_err;
@@ -295,13 +293,13 @@ int __init get_memcfg_from_srat(void)
printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision,
rsdp->oem_id);
- if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) {
+ if (strncmp(rsdp->signature, ACPI_SIG_RSDP,strlen(ACPI_SIG_RSDP))) {
printk(KERN_WARNING "%s: RSDP table signature incorrect\n", __FUNCTION__);
goto out_err;
}
rsdt = (struct acpi_table_rsdt *)
- boot_ioremap(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt));
+ boot_ioremap(rsdp->rsdt_physical_address, sizeof(struct acpi_table_rsdt));
if (!rsdt) {
printk(KERN_WARNING
@@ -310,9 +308,9 @@ int __init get_memcfg_from_srat(void)
goto out_err;
}
- header = & rsdt->header;
+ header = &rsdt->header;
- if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) {
+ if (strncmp(header->signature, ACPI_SIG_RSDT, strlen(ACPI_SIG_RSDT))) {
printk(KERN_WARNING "ACPI: RSDT signature incorrect\n");
goto out_err;
}
@@ -330,9 +328,9 @@ int __init get_memcfg_from_srat(void)
memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt));
- if (saved_rsdt.header.length > sizeof(saved_rsdt)) {
+ if (saved_rsdt.table.header.length > sizeof(saved_rsdt)) {
printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n",
- saved_rsdt.header.length);
+ saved_rsdt.table.header.length);
goto out_err;
}
@@ -341,15 +339,15 @@ int __init get_memcfg_from_srat(void)
for (i = 0; i < tables; i++) {
/* Map in header, then map in full table length. */
header = (struct acpi_table_header *)
- boot_ioremap(saved_rsdt.entry[i], sizeof(struct acpi_table_header));
+ boot_ioremap(saved_rsdt.table.table_offset_entry[i], sizeof(struct acpi_table_header));
if (!header)
break;
header = (struct acpi_table_header *)
- boot_ioremap(saved_rsdt.entry[i], header->length);
+ boot_ioremap(saved_rsdt.table.table_offset_entry[i], header->length);
if (!header)
break;
- if (strncmp((char *) &header->signature, "SRAT", 4))
+ if (strncmp((char *) &header->signature, ACPI_SIG_SRAT, 4))
continue;
/* we've found the srat table. don't need to look at any more tables */
diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c
index 7de9117b5a3..bc882a2b1db 100644
--- a/arch/i386/kernel/sysenter.c
+++ b/arch/i386/kernel/sysenter.c
@@ -70,20 +70,16 @@ void enable_sep_cpu(void)
*/
extern const char vsyscall_int80_start, vsyscall_int80_end;
extern const char vsyscall_sysenter_start, vsyscall_sysenter_end;
-static void *syscall_page;
+static struct page *syscall_pages[1];
int __init sysenter_setup(void)
{
- syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+ void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+ syscall_pages[0] = virt_to_page(syscall_page);
#ifdef CONFIG_COMPAT_VDSO
__set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY);
printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));
-#else
- /*
- * In the non-compat case the ELF coredumping code needs the fixmap:
- */
- __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_KERNEL_RO);
#endif
if (!boot_cpu_has(X86_FEATURE_SEP)) {
@@ -100,31 +96,13 @@ int __init sysenter_setup(void)
return 0;
}
-static struct page *syscall_nopage(struct vm_area_struct *vma,
- unsigned long adr, int *type)
-{
- struct page *p = virt_to_page(adr - vma->vm_start + syscall_page);
- get_page(p);
- return p;
-}
-
-/* Prevent VMA merging */
-static void syscall_vma_close(struct vm_area_struct *vma)
-{
-}
-
-static struct vm_operations_struct syscall_vm_ops = {
- .close = syscall_vma_close,
- .nopage = syscall_nopage,
-};
-
+#ifndef CONFIG_COMPAT_VDSO
/* Defined in vsyscall-sysenter.S */
extern void SYSENTER_RETURN;
/* Setup a VMA at program startup for the vsyscall page */
int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
{
- struct vm_area_struct *vma;
struct mm_struct *mm = current->mm;
unsigned long addr;
int ret;
@@ -136,31 +114,25 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
goto up_fail;
}
- vma = kmem_cache_zalloc(vm_area_cachep, GFP_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);
+ /*
+ * MAYWRITE to allow gdb to COW and set breakpoints
+ *
+ * Make sure the vDSO gets into every core dump.
+ * Dumping its contents makes post-mortem fully interpretable later
+ * without matching up the same kernel and hardware config to see
+ * what PC values meant.
+ */
+ ret = install_special_mapping(mm, addr, PAGE_SIZE,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+ VM_ALWAYSDUMP,
+ syscall_pages);
+ if (ret)
goto up_fail;
- }
current->mm->context.vdso = (void *)addr;
current_thread_info()->sysenter_return =
(void *)VDSO_SYM(&SYSENTER_RETURN);
- mm->total_vm++;
up_fail:
up_write(&mm->mmap_sem);
return ret;
@@ -187,3 +159,4 @@ int in_gate_area_no_task(unsigned long addr)
{
return 0;
}
+#endif
diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S
index fcce0e61b0e..2f1814c5cfd 100644
--- a/arch/i386/kernel/trampoline.S
+++ b/arch/i386/kernel/trampoline.S
@@ -38,6 +38,11 @@
.data
+/* We can free up trampoline after bootup if cpu hotplug is not supported. */
+#ifndef CONFIG_HOTPLUG_CPU
+.section ".init.data","aw",@progbits
+#endif
+
.code16
ENTRY(trampoline_data)
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 68de48e498c..0efad8aeb41 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -30,6 +30,7 @@
#include <linux/unwind.h>
#include <linux/uaccess.h>
#include <linux/nmi.h>
+#include <linux/bug.h>
#ifdef CONFIG_EISA
#include <linux/ioport.h>
@@ -93,11 +94,6 @@ asmlinkage void spurious_interrupt_bug(void);
asmlinkage void machine_check(void);
int kstack_depth_to_print = 24;
-#ifdef CONFIG_STACK_UNWIND
-static int call_trace = 1;
-#else
-#define call_trace (-1)
-#endif
ATOMIC_NOTIFIER_HEAD(i386die_chain);
int register_die_notifier(struct notifier_block *nb)
@@ -151,33 +147,6 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,
return ebp;
}
-struct ops_and_data {
- struct stacktrace_ops *ops;
- void *data;
-};
-
-static asmlinkage int
-dump_trace_unwind(struct unwind_frame_info *info, void *data)
-{
- struct ops_and_data *oad = (struct ops_and_data *)data;
- int n = 0;
- unsigned long sp = UNW_SP(info);
-
- if (arch_unw_user_mode(info))
- return -1;
- while (unwind(info) == 0 && UNW_PC(info)) {
- n++;
- oad->ops->address(oad->data, UNW_PC(info));
- if (arch_unw_user_mode(info))
- break;
- if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1))
- && sp > UNW_SP(info))
- break;
- sp = UNW_SP(info);
- }
- return n;
-}
-
#define MSG(msg) ops->warning(data, msg)
void dump_trace(struct task_struct *task, struct pt_regs *regs,
@@ -189,41 +158,6 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
if (!task)
task = current;
- if (call_trace >= 0) {
- int unw_ret = 0;
- struct unwind_frame_info info;
- struct ops_and_data oad = { .ops = ops, .data = data };
-
- if (regs) {
- if (unwind_init_frame_info(&info, task, regs) == 0)
- unw_ret = dump_trace_unwind(&info, &oad);
- } else if (task == current)
- unw_ret = unwind_init_running(&info, dump_trace_unwind,
- &oad);
- else {
- if (unwind_init_blocked(&info, task) == 0)
- unw_ret = dump_trace_unwind(&info, &oad);
- }
- if (unw_ret > 0) {
- if (call_trace == 1 && !arch_unw_user_mode(&info)) {
- ops->warning_symbol(data,
- "DWARF2 unwinder stuck at %s",
- UNW_PC(&info));
- if (UNW_SP(&info) >= PAGE_OFFSET) {
- MSG("Leftover inexact backtrace:");
- stack = (void *)UNW_SP(&info);
- if (!stack)
- return;
- ebp = UNW_FP(&info);
- } else
- MSG("Full inexact backtrace again:");
- } else if (call_trace >= 1)
- return;
- else
- MSG("Full inexact backtrace again:");
- } else
- MSG("Inexact backtrace:");
- }
if (!stack) {
unsigned long dummy;
stack = &dummy;
@@ -420,43 +354,22 @@ void show_registers(struct pt_regs *regs)
printk("\n");
}
-static void handle_BUG(struct pt_regs *regs)
+int is_valid_bugaddr(unsigned long eip)
{
- unsigned long eip = regs->eip;
unsigned short ud2;
if (eip < PAGE_OFFSET)
- return;
+ return 0;
if (probe_kernel_address((unsigned short *)eip, ud2))
- return;
- if (ud2 != 0x0b0f)
- return;
-
- printk(KERN_EMERG "------------[ cut here ]------------\n");
-
-#ifdef CONFIG_DEBUG_BUGVERBOSE
- do {
- unsigned short line;
- char *file;
- char c;
-
- if (probe_kernel_address((unsigned short *)(eip + 2), line))
- break;
- if (probe_kernel_address((char **)(eip + 4), file) ||
- (unsigned long)file < PAGE_OFFSET ||
- probe_kernel_address(file, c))
- file = "<bad filename>";
+ return 0;
- printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line);
- return;
- } while (0);
-#endif
- printk(KERN_EMERG "Kernel BUG at [verbose debug info unavailable]\n");
+ return ud2 == 0x0b0f;
}
-/* This is gone through when something in the kernel
- * has done something bad and is about to be terminated.
-*/
+/*
+ * This is gone through when something in the kernel has done something bad and
+ * is about to be terminated.
+ */
void die(const char * str, struct pt_regs * regs, long err)
{
static struct {
@@ -488,7 +401,8 @@ void die(const char * str, struct pt_regs * regs, long err)
unsigned long esp;
unsigned short ss;
- handle_BUG(regs);
+ report_bug(regs->eip);
+
printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
#ifdef CONFIG_PREEMPT
printk(KERN_EMERG "PREEMPT ");
@@ -1277,19 +1191,3 @@ static int __init kstack_setup(char *s)
return 1;
}
__setup("kstack=", kstack_setup);
-
-#ifdef CONFIG_STACK_UNWIND
-static int __init call_trace_setup(char *s)
-{
- if (strcmp(s, "old") == 0)
- call_trace = -1;
- else if (strcmp(s, "both") == 0)
- call_trace = 0;
- else if (strcmp(s, "newfallback") == 0)
- call_trace = 1;
- else if (strcmp(s, "new") == 2)
- call_trace = 2;
- return 1;
-}
-__setup("call_trace=", call_trace_setup);
-#endif
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
index 1bbe45dca7a..2cfc7b09b92 100644
--- a/arch/i386/kernel/tsc.c
+++ b/arch/i386/kernel/tsc.c
@@ -24,7 +24,7 @@
*/
unsigned int tsc_khz;
-int tsc_disable __cpuinitdata = 0;
+int tsc_disable;
#ifdef CONFIG_X86_TSC
static int __init tsc_setup(char *str)
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 56e6ad5cb04..a53c8b1854b 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -26,6 +26,7 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(phys_startup_32)
jiffies = jiffies_64;
+_proxy_pda = 0;
PHDRS {
text PT_LOAD FLAGS(5); /* R_E */
@@ -57,6 +58,8 @@ SECTIONS
RODATA
+ BUG_TABLE
+
. = ALIGN(4);
.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
__tracedata_start = .;
diff --git a/arch/i386/mach-default/setup.c b/arch/i386/mach-default/setup.c
index c511705c386..cc2f519b2f7 100644
--- a/arch/i386/mach-default/setup.c
+++ b/arch/i386/mach-default/setup.c
@@ -102,7 +102,7 @@ void __init time_init_hook(void)
* along the MCA bus. Use this to hook into that chain if you will need
* it.
**/
-void __init mca_nmi_hook(void)
+void mca_nmi_hook(void)
{
/* If I recall correctly, there's a whole bunch of other things that
* we can do to check for NMI problems, but that's all I know about
diff --git a/arch/i386/mach-es7000/es7000.h b/arch/i386/mach-es7000/es7000.h
index 80566ca4a80..c8d5aa132fa 100644
--- a/arch/i386/mach-es7000/es7000.h
+++ b/arch/i386/mach-es7000/es7000.h
@@ -84,15 +84,6 @@ struct es7000_oem_table {
};
#ifdef CONFIG_ACPI
-struct acpi_table_sdt {
- unsigned long pa;
- unsigned long count;
- struct {
- unsigned long pa;
- enum acpi_table_id id;
- unsigned long size;
- } entry[50];
-};
struct oem_table {
struct acpi_table_header Header;
diff --git a/arch/i386/mach-es7000/es7000plat.c b/arch/i386/mach-es7000/es7000plat.c
index 3d0fc853516..9be6ceabf04 100644
--- a/arch/i386/mach-es7000/es7000plat.c
+++ b/arch/i386/mach-es7000/es7000plat.c
@@ -160,51 +160,14 @@ parse_unisys_oem (char *oemptr)
int __init
find_unisys_acpi_oem_table(unsigned long *oem_addr)
{
- struct acpi_table_rsdp *rsdp = NULL;
- unsigned long rsdp_phys = 0;
- struct acpi_table_header *header = NULL;
- int i;
- struct acpi_table_sdt sdt;
-
- rsdp_phys = acpi_find_rsdp();
- rsdp = __va(rsdp_phys);
- if (rsdp->rsdt_address) {
- struct acpi_table_rsdt *mapped_rsdt = NULL;
- sdt.pa = rsdp->rsdt_address;
-
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt.pa, sizeof(struct acpi_table_header));
- if (!header)
- return -ENODEV;
-
- sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 3;
- mapped_rsdt = (struct acpi_table_rsdt *)
- __acpi_map_table(sdt.pa, header->length);
- if (!mapped_rsdt)
- return -ENODEV;
-
- header = &mapped_rsdt->header;
-
- for (i = 0; i < sdt.count; i++)
- sdt.entry[i].pa = (unsigned long) mapped_rsdt->entry[i];
- };
- for (i = 0; i < sdt.count; i++) {
-
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt.entry[i].pa,
- sizeof(struct acpi_table_header));
- if (!header)
- continue;
- if (!strncmp((char *) &header->signature, "OEM1", 4)) {
- if (!strncmp((char *) &header->oem_id, "UNISYS", 6)) {
- void *addr;
- struct oem_table *t;
- acpi_table_print(header, sdt.entry[i].pa);
- t = (struct oem_table *) __acpi_map_table(sdt.entry[i].pa, header->length);
- addr = (void *) __acpi_map_table(t->OEMTableAddr, t->OEMTableSize);
- *oem_addr = (unsigned long) addr;
- return 0;
- }
+ struct acpi_table_header *header = NULL;
+ int i = 0;
+ while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) {
+ if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
+ struct oem_table *t = (struct oem_table *)header;
+ *oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr,
+ t->OEMTableSize);
+ return 0;
}
}
return -1;
diff --git a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c
index 33d9f93557b..8a210fa915b 100644
--- a/arch/i386/mach-generic/bigsmp.c
+++ b/arch/i386/mach-generic/bigsmp.c
@@ -45,7 +45,7 @@ static struct dmi_system_id __initdata bigsmp_dmi_table[] = {
};
-static __init int probe_bigsmp(void)
+static int probe_bigsmp(void)
{
if (def_to_bigsmp)
dmi_bigsmp = 1;
diff --git a/arch/i386/mach-generic/default.c b/arch/i386/mach-generic/default.c
index 96c19821e47..8685208d851 100644
--- a/arch/i386/mach-generic/default.c
+++ b/arch/i386/mach-generic/default.c
@@ -18,7 +18,7 @@
#include <asm/mach-default/mach_mpparse.h>
/* should be called last. */
-static __init int probe_default(void)
+static int probe_default(void)
{
return 1;
}
diff --git a/arch/i386/mach-generic/es7000.c b/arch/i386/mach-generic/es7000.c
index aa144d82334..b8963a5a3b2 100644
--- a/arch/i386/mach-generic/es7000.c
+++ b/arch/i386/mach-generic/es7000.c
@@ -19,7 +19,7 @@
#include <asm/mach-es7000/mach_mpparse.h>
#include <asm/mach-es7000/mach_wakecpu.h>
-static __init int probe_es7000(void)
+static int probe_es7000(void)
{
/* probed later in mptable/ACPI hooks */
return 0;
diff --git a/arch/i386/mach-generic/summit.c b/arch/i386/mach-generic/summit.c
index f7e5d66648d..74883ccb8f7 100644
--- a/arch/i386/mach-generic/summit.c
+++ b/arch/i386/mach-generic/summit.c
@@ -18,7 +18,7 @@
#include <asm/mach-summit/mach_ipi.h>
#include <asm/mach-summit/mach_mpparse.h>
-static __init int probe_summit(void)
+static int probe_summit(void)
{
/* probed later in mptable/ACPI hooks */
return 0;
diff --git a/arch/i386/mach-visws/setup.c b/arch/i386/mach-visws/setup.c
index 885c7cbfd47..233ee20907b 100644
--- a/arch/i386/mach-visws/setup.c
+++ b/arch/i386/mach-visws/setup.c
@@ -6,6 +6,7 @@
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
#include <asm/fixmap.h>
#include <asm/arch_hooks.h>
@@ -142,6 +143,8 @@ void __init time_init_hook(void)
unsigned long sgivwfb_mem_phys;
unsigned long sgivwfb_mem_size;
+EXPORT_SYMBOL(sgivwfb_mem_phys);
+EXPORT_SYMBOL(sgivwfb_mem_size);
long long mem_size __initdata = 0;
diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
index 55428e656a3..74aeedf277f 100644
--- a/arch/i386/mach-voyager/voyager_smp.c
+++ b/arch/i386/mach-voyager/voyager_smp.c
@@ -773,6 +773,12 @@ initialize_secondary(void)
#endif
/*
+ * switch to the per CPU GDT we already set up
+ * in do_boot_cpu()
+ */
+ cpu_set_gdt(current_thread_info()->cpu);
+
+ /*
* We don't actually need to load the full TSS,
* basically just the stack pointer and the eip.
*/
diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
index 103b76e56a9..e0c390d6ceb 100644
--- a/arch/i386/mm/discontig.c
+++ b/arch/i386/mm/discontig.c
@@ -405,3 +405,31 @@ void __init set_highmem_pages_init(int bad_ppro)
totalram_pages += totalhigh_pages;
#endif
}
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+int paddr_to_nid(u64 addr)
+{
+ int nid;
+ unsigned long pfn = PFN_DOWN(addr);
+
+ for_each_node(nid)
+ if (node_start_pfn[nid] <= pfn &&
+ pfn < node_end_pfn[nid])
+ return nid;
+
+ return -1;
+}
+
+/*
+ * This function is used to ask node id BEFORE memmap and mem_section's
+ * initialization (pfn_to_nid() can't be used yet).
+ * If _PXM is not defined on ACPI's DSDT, node id must be found by this.
+ */
+int memory_add_physaddr_to_nid(u64 addr)
+{
+ int nid = paddr_to_nid(addr);
+ return (nid >= 0) ? nid : 0;
+}
+
+EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
+#endif
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 84697dfc734..c5c5ea700cc 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -283,7 +283,7 @@ void __init add_one_highpage_init(struct page *page, int pfn, int bad_ppro)
SetPageReserved(page);
}
-static int add_one_highpage_hotplug(struct page *page, unsigned long pfn)
+static int __meminit add_one_highpage_hotplug(struct page *page, unsigned long pfn)
{
free_new_highpage(page);
totalram_pages++;
@@ -300,7 +300,7 @@ static int add_one_highpage_hotplug(struct page *page, unsigned long pfn)
* has been added dynamically that would be
* onlined here is in HIGHMEM
*/
-void online_page(struct page *page)
+void __meminit online_page(struct page *page)
{
ClearPageReserved(page);
add_one_highpage_hotplug(page, page_to_pfn(page));
@@ -673,16 +673,10 @@ void __init mem_init(void)
#endif
}
-/*
- * this is for the non-NUMA, single node SMP system case.
- * Specifically, in the case of x86, we will always add
- * memory to the highmem for now.
- */
#ifdef CONFIG_MEMORY_HOTPLUG
-#ifndef CONFIG_NEED_MULTIPLE_NODES
int arch_add_memory(int nid, u64 start, u64 size)
{
- struct pglist_data *pgdata = &contig_page_data;
+ struct pglist_data *pgdata = NODE_DATA(nid);
struct zone *zone = pgdata->node_zones + ZONE_HIGHMEM;
unsigned long start_pfn = start >> PAGE_SHIFT;
unsigned long nr_pages = size >> PAGE_SHIFT;
@@ -694,7 +688,7 @@ int remove_memory(u64 start, u64 size)
{
return -EINVAL;
}
-#endif
+EXPORT_SYMBOL_GPL(remove_memory);
#endif
struct kmem_cache *pgd_cache;
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c
index ad91528bdc1..e223b1d4981 100644
--- a/arch/i386/mm/pageattr.c
+++ b/arch/i386/mm/pageattr.c
@@ -224,7 +224,7 @@ void global_flush_tlb(void)
list_replace_init(&df_list, &l);
spin_unlock_irq(&cpa_lock);
if (!cpu_has_clflush)
- flush_map(0);
+ flush_map(NULL);
list_for_each_entry_safe(pg, next, &l, lru) {
if (cpu_has_clflush)
flush_map(page_address(pg));
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
index cde1170b01a..8053b17ab64 100644
--- a/arch/i386/pci/fixup.c
+++ b/arch/i386/pci/fixup.c
@@ -115,7 +115,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci
#define VIA_8363_KL133_REVISION_ID 0x81
#define VIA_8363_KM133_REVISION_ID 0x84
-static void __devinit pci_fixup_via_northbridge_bug(struct pci_dev *d)
+static void pci_fixup_via_northbridge_bug(struct pci_dev *d)
{
u8 v;
u8 revision;
@@ -151,6 +151,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug);
/*
* For some reasons Intel decided that certain parts of their
@@ -181,7 +185,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_
* issue another HALT within 80 ns of the initial HALT, the failure condition
* is avoided.
*/
-static void __init pci_fixup_nforce2(struct pci_dev *dev)
+static void pci_fixup_nforce2(struct pci_dev *dev)
{
u32 val;
@@ -204,6 +208,7 @@ static void __init pci_fixup_nforce2(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2);
/* Max PCI Express root ports */
#define MAX_PCIEROOT 6
@@ -419,7 +424,7 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_TI, 0x8032,
* Prevent the BIOS trapping accesses to the Cyrix CS5530A video device
* configuration space.
*/
-static void __devinit pci_early_fixup_cyrix_5530(struct pci_dev *dev)
+static void pci_early_fixup_cyrix_5530(struct pci_dev *dev)
{
u8 r;
/* clear 'F4 Video Configuration Trap' bit */
@@ -429,3 +434,5 @@ static void __devinit pci_early_fixup_cyrix_5530(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY,
pci_early_fixup_cyrix_5530);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY,
+ pci_early_fixup_cyrix_5530);
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index c6b6d9bbc45..5700220dcf5 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -26,6 +26,7 @@
/* The base address of the last MMCONFIG device accessed */
static u32 mmcfg_last_accessed_device;
+static int mmcfg_last_accessed_cpu;
static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32);
@@ -35,7 +36,7 @@ static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32);
static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
{
int cfg_num = -1;
- struct acpi_table_mcfg_config *cfg;
+ struct acpi_mcfg_allocation *cfg;
if (seg == 0 && bus < MAX_CHECK_BUS &&
test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots))
@@ -47,11 +48,11 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
break;
}
cfg = &pci_mmcfg_config[cfg_num];
- if (cfg->pci_segment_group_number != seg)
+ if (cfg->pci_segment != seg)
continue;
if ((cfg->start_bus_number <= bus) &&
(cfg->end_bus_number >= bus))
- return cfg->base_address;
+ return cfg->address;
}
/* Handle more broken MCFG tables on Asus etc.
@@ -59,9 +60,9 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
this applies to all busses. */
cfg = &pci_mmcfg_config[0];
if (pci_mmcfg_config_num == 1 &&
- cfg->pci_segment_group_number == 0 &&
+ cfg->pci_segment == 0 &&
(cfg->start_bus_number | cfg->end_bus_number) == 0)
- return cfg->base_address;
+ return cfg->address;
/* Fall back to type 0 */
return 0;
@@ -73,8 +74,11 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
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) {
+ int cpu = smp_processor_id();
+ if (dev_base != mmcfg_last_accessed_device ||
+ cpu != mmcfg_last_accessed_cpu) {
mmcfg_last_accessed_device = dev_base;
+ mmcfg_last_accessed_cpu = cpu;
set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
}
}
@@ -121,7 +125,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
unsigned long flags;
u32 base;
- if ((bus > 255) || (devfn > 255) || (reg > 4095))
+ if ((bus > 255) || (devfn > 255) || (reg > 4095))
return -EINVAL;
base = get_base_addr(seg, bus, devfn);
@@ -195,19 +199,19 @@ void __init pci_mmcfg_init(int type)
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return;
- acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+ acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
if ((pci_mmcfg_config_num == 0) ||
(pci_mmcfg_config == NULL) ||
- (pci_mmcfg_config[0].base_address == 0))
+ (pci_mmcfg_config[0].address == 0))
return;
/* Only do this check when type 1 works. If it doesn't work
assume we run on a Mac and always use MCFG */
- if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address,
- pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
+ if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].address,
+ pci_mmcfg_config[0].address + MMCONFIG_APER_MIN,
E820_RESERVED)) {
- printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
- pci_mmcfg_config[0].base_address);
+ printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n",
+ (unsigned long)pci_mmcfg_config[0].address);
printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
return;
}
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 75d839715b2..f1d2899e9a6 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -11,6 +11,8 @@ menu "Processor type and features"
config IA64
bool
+ select PCI if (!IA64_HP_SIM)
+ select ACPI if (!IA64_HP_SIM)
default y
help
The Itanium Processor Family is Intel's 64-bit successor to
@@ -28,12 +30,19 @@ config MMU
config SWIOTLB
bool
- default y
config RWSEM_XCHGADD_ALGORITHM
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
@@ -76,10 +85,9 @@ choice
config IA64_GENERIC
bool "generic"
- select ACPI
- select PCI
select NUMA
select ACPI_NUMA
+ select SWIOTLB
help
This selects the system type of your hardware. A "generic" kernel
will run on any supported IA-64 system. However, if you configure
@@ -96,6 +104,7 @@ config IA64_GENERIC
config IA64_DIG
bool "DIG-compliant"
+ select SWIOTLB
config IA64_HP_ZX1
bool "HP-zx1/sx1000"
@@ -105,6 +114,7 @@ config IA64_HP_ZX1
config IA64_HP_ZX1_SWIOTLB
bool "HP-zx1/sx1000 with software I/O TLB"
+ select SWIOTLB
help
Build a kernel that runs on HP zx1 and sx1000 systems even when they
have broken PCI devices which cannot DMA to full 32 bits. Apart
@@ -123,6 +133,7 @@ config IA64_SGI_SN2
config IA64_HP_SIM
bool "Ski-simulator"
+ select SWIOTLB
endchoice
diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c
index a5a5637507b..2153bcacbe6 100644
--- a/arch/ia64/hp/common/hwsw_iommu.c
+++ b/arch/ia64/hp/common/hwsw_iommu.c
@@ -192,3 +192,7 @@ EXPORT_SYMBOL(hwsw_unmap_sg);
EXPORT_SYMBOL(hwsw_dma_supported);
EXPORT_SYMBOL(hwsw_alloc_coherent);
EXPORT_SYMBOL(hwsw_free_coherent);
+EXPORT_SYMBOL(hwsw_sync_single_for_cpu);
+EXPORT_SYMBOL(hwsw_sync_single_for_device);
+EXPORT_SYMBOL(hwsw_sync_sg_for_cpu);
+EXPORT_SYMBOL(hwsw_sync_sg_for_device);
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index 1f16ebb9a80..324ea7565e2 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -488,7 +488,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
unsigned int cflag = tty->termios->c_cflag;
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index a4a6e1463af..957681c39ad 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -235,7 +235,7 @@ mmap_subpage (struct file *file, unsigned long start, unsigned long end, int pro
if (!(flags & MAP_ANONYMOUS)) {
/* read the file contents */
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (!inode->i_fop || !file->f_op->read
|| ((*file->f_op->read)(file, (char __user *) start, end - start, &off) < 0))
{
@@ -837,7 +837,7 @@ emulate_mmap (struct file *file, unsigned long start, unsigned long len, int pro
if (!is_congruent) {
/* read the file contents */
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (!inode->i_fop || !file->f_op->read
|| ((*file->f_op->read)(file, (char __user *) pstart, pend - pstart, &poff)
< 0))
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 8ae384eb535..098ee605bf5 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
obj-$(CONFIG_AUDIT) += audit.o
obj-$(CONFIG_PCI_MSI) += msi_ia64.o
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 73ef4a85b86..9197d7b361b 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -55,7 +55,7 @@
#define BAD_MADT_ENTRY(entry, end) ( \
(!entry) || (unsigned long)entry + sizeof(*entry) > end || \
- ((acpi_table_entry_header *)entry)->length < sizeof(*entry))
+ ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
#define PREFIX "ACPI: "
@@ -67,16 +67,11 @@ EXPORT_SYMBOL(pm_power_off);
unsigned int acpi_cpei_override;
unsigned int acpi_cpei_phys_cpuid;
-#define MAX_SAPICS 256
-u16 ia64_acpiid_to_sapicid[MAX_SAPICS] = {[0 ... MAX_SAPICS - 1] = -1 };
-
-EXPORT_SYMBOL(ia64_acpiid_to_sapicid);
-
const char *acpi_get_sysname(void)
{
#ifdef CONFIG_IA64_GENERIC
unsigned long rsdp_phys;
- struct acpi20_table_rsdp *rsdp;
+ struct acpi_table_rsdp *rsdp;
struct acpi_table_xsdt *xsdt;
struct acpi_table_header *hdr;
@@ -87,16 +82,16 @@ const char *acpi_get_sysname(void)
return "dig";
}
- rsdp = (struct acpi20_table_rsdp *)__va(rsdp_phys);
- if (strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) {
+ rsdp = (struct acpi_table_rsdp *)__va(rsdp_phys);
+ if (strncmp(rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)) {
printk(KERN_ERR
"ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n");
return "dig";
}
- xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_address);
+ xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_physical_address);
hdr = &xsdt->header;
- if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) {
+ if (strncmp(hdr->signature, ACPI_SIG_XSDT, sizeof(ACPI_SIG_XSDT) - 1)) {
printk(KERN_ERR
"ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n");
return "dig";
@@ -169,12 +164,12 @@ struct acpi_table_madt *acpi_madt __initdata;
static u8 has_8259;
static int __init
-acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header,
+acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
const unsigned long end)
{
- struct acpi_table_lapic_addr_ovr *lapic;
+ struct acpi_madt_local_apic_override *lapic;
- lapic = (struct acpi_table_lapic_addr_ovr *)header;
+ lapic = (struct acpi_madt_local_apic_override *)header;
if (BAD_MADT_ENTRY(lapic, end))
return -EINVAL;
@@ -187,22 +182,19 @@ acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header,
}
static int __init
-acpi_parse_lsapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lsapic(struct acpi_subtable_header * header, const unsigned long end)
{
- struct acpi_table_lsapic *lsapic;
+ struct acpi_madt_local_sapic *lsapic;
- lsapic = (struct acpi_table_lsapic *)header;
+ lsapic = (struct acpi_madt_local_sapic *)header;
- if (BAD_MADT_ENTRY(lsapic, end))
- return -EINVAL;
+ /*Skip BAD_MADT_ENTRY check, as lsapic size could vary */
- if (lsapic->flags.enabled) {
+ if (lsapic->lapic_flags & ACPI_MADT_ENABLED) {
#ifdef CONFIG_SMP
smp_boot_data.cpu_phys_id[available_cpus] =
(lsapic->id << 8) | lsapic->eid;
#endif
- ia64_acpiid_to_sapicid[lsapic->acpi_id] =
- (lsapic->id << 8) | lsapic->eid;
++available_cpus;
}
@@ -211,11 +203,11 @@ acpi_parse_lsapic(acpi_table_entry_header * header, const unsigned long end)
}
static int __init
-acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
{
- struct acpi_table_lapic_nmi *lacpi_nmi;
+ struct acpi_madt_local_apic_nmi *lacpi_nmi;
- lacpi_nmi = (struct acpi_table_lapic_nmi *)header;
+ lacpi_nmi = (struct acpi_madt_local_apic_nmi *)header;
if (BAD_MADT_ENTRY(lacpi_nmi, end))
return -EINVAL;
@@ -225,11 +217,11 @@ acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end)
}
static int __init
-acpi_parse_iosapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_iosapic(struct acpi_subtable_header * header, const unsigned long end)
{
- struct acpi_table_iosapic *iosapic;
+ struct acpi_madt_io_sapic *iosapic;
- iosapic = (struct acpi_table_iosapic *)header;
+ iosapic = (struct acpi_madt_io_sapic *)header;
if (BAD_MADT_ENTRY(iosapic, end))
return -EINVAL;
@@ -240,13 +232,13 @@ acpi_parse_iosapic(acpi_table_entry_header * header, const unsigned long end)
static unsigned int __initdata acpi_madt_rev;
static int __init
-acpi_parse_plat_int_src(acpi_table_entry_header * header,
+acpi_parse_plat_int_src(struct acpi_subtable_header * header,
const unsigned long end)
{
- struct acpi_table_plat_int_src *plintsrc;
+ struct acpi_madt_interrupt_source *plintsrc;
int vector;
- plintsrc = (struct acpi_table_plat_int_src *)header;
+ plintsrc = (struct acpi_madt_interrupt_source *)header;
if (BAD_MADT_ENTRY(plintsrc, end))
return -EINVAL;
@@ -257,19 +249,19 @@ acpi_parse_plat_int_src(acpi_table_entry_header * header,
*/
vector = iosapic_register_platform_intr(plintsrc->type,
plintsrc->global_irq,
- plintsrc->iosapic_vector,
+ plintsrc->io_sapic_vector,
plintsrc->eid,
plintsrc->id,
- (plintsrc->flags.polarity ==
- 1) ? IOSAPIC_POL_HIGH :
- IOSAPIC_POL_LOW,
- (plintsrc->flags.trigger ==
- 1) ? IOSAPIC_EDGE :
- IOSAPIC_LEVEL);
+ ((plintsrc->inti_flags & ACPI_MADT_POLARITY_MASK) ==
+ ACPI_MADT_POLARITY_ACTIVE_HIGH) ?
+ IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
+ ((plintsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) ==
+ ACPI_MADT_TRIGGER_EDGE) ?
+ IOSAPIC_EDGE : IOSAPIC_LEVEL);
platform_intr_list[plintsrc->type] = vector;
if (acpi_madt_rev > 1) {
- acpi_cpei_override = plintsrc->plint_flags.cpei_override_flag;
+ acpi_cpei_override = plintsrc->flags & ACPI_MADT_CPEI_OVERRIDE;
}
/*
@@ -324,30 +316,32 @@ unsigned int get_cpei_target_cpu(void)
}
static int __init
-acpi_parse_int_src_ovr(acpi_table_entry_header * header,
+acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
const unsigned long end)
{
- struct acpi_table_int_src_ovr *p;
+ struct acpi_madt_interrupt_override *p;
- p = (struct acpi_table_int_src_ovr *)header;
+ p = (struct acpi_madt_interrupt_override *)header;
if (BAD_MADT_ENTRY(p, end))
return -EINVAL;
- iosapic_override_isa_irq(p->bus_irq, p->global_irq,
- (p->flags.polarity ==
- 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
- (p->flags.trigger ==
- 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
+ iosapic_override_isa_irq(p->source_irq, p->global_irq,
+ ((p->inti_flags & ACPI_MADT_POLARITY_MASK) ==
+ ACPI_MADT_POLARITY_ACTIVE_HIGH) ?
+ IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
+ ((p->inti_flags & ACPI_MADT_TRIGGER_MASK) ==
+ ACPI_MADT_TRIGGER_EDGE) ?
+ IOSAPIC_EDGE : IOSAPIC_LEVEL);
return 0;
}
static int __init
-acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end)
{
- struct acpi_table_nmi_src *nmi_src;
+ struct acpi_madt_nmi_source *nmi_src;
- nmi_src = (struct acpi_table_nmi_src *)header;
+ nmi_src = (struct acpi_madt_nmi_source *)header;
if (BAD_MADT_ENTRY(nmi_src, end))
return -EINVAL;
@@ -371,12 +365,12 @@ static void __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
}
}
-static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_madt(struct acpi_table_header *table)
{
- if (!phys_addr || !size)
+ if (!table)
return -EINVAL;
- acpi_madt = (struct acpi_table_madt *)__va(phys_addr);
+ acpi_madt = (struct acpi_table_madt *)table;
acpi_madt_rev = acpi_madt->header.revision;
@@ -384,14 +378,14 @@ static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
#ifdef CONFIG_ITANIUM
has_8259 = 1; /* Firmware on old Itanium systems is broken */
#else
- has_8259 = acpi_madt->flags.pcat_compat;
+ has_8259 = acpi_madt->flags & ACPI_MADT_PCAT_COMPAT;
#endif
iosapic_system_init(has_8259);
/* Get base address of IPI Message Block */
- if (acpi_madt->lapic_address)
- ipi_base_addr = ioremap(acpi_madt->lapic_address, 0);
+ if (acpi_madt->address)
+ ipi_base_addr = ioremap(acpi_madt->address, 0);
printk(KERN_INFO PREFIX "Local APIC address %p\n", ipi_base_addr);
@@ -413,23 +407,24 @@ static u32 __devinitdata pxm_flag[PXM_FLAG_LEN];
#define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag))
static struct acpi_table_slit __initdata *slit_table;
-static int get_processor_proximity_domain(struct acpi_table_processor_affinity *pa)
+static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
{
int pxm;
- pxm = pa->proximity_domain;
+ pxm = pa->proximity_domain_lo;
if (ia64_platform_is("sn2"))
- pxm += pa->reserved[0] << 8;
+ pxm += pa->proximity_domain_hi[0] << 8;
return pxm;
}
-static int get_memory_proximity_domain(struct acpi_table_memory_affinity *ma)
+static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
{
int pxm;
pxm = ma->proximity_domain;
- if (ia64_platform_is("sn2"))
- pxm += ma->reserved1[0] << 8;
+ if (!ia64_platform_is("sn2"))
+ pxm &= 0xff;
+
return pxm;
}
@@ -442,7 +437,7 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
u32 len;
len = sizeof(struct acpi_table_header) + 8
- + slit->localities * slit->localities;
+ + slit->locality_count * slit->locality_count;
if (slit->header.length != len) {
printk(KERN_ERR
"ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n",
@@ -454,11 +449,11 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
}
void __init
-acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
+acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
{
int pxm;
- if (!pa->flags.enabled)
+ if (!(pa->flags & ACPI_SRAT_CPU_ENABLED))
return;
pxm = get_processor_proximity_domain(pa);
@@ -467,14 +462,14 @@ acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
pxm_bit_set(pxm);
node_cpuid[srat_num_cpus].phys_id =
- (pa->apic_id << 8) | (pa->lsapic_eid);
+ (pa->apic_id << 8) | (pa->local_sapic_eid);
/* nid should be overridden as logical node id later */
node_cpuid[srat_num_cpus].nid = pxm;
srat_num_cpus++;
}
void __init
-acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
+acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
{
unsigned long paddr, size;
int pxm;
@@ -483,13 +478,11 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
pxm = get_memory_proximity_domain(ma);
/* fill node memory chunk structure */
- paddr = ma->base_addr_hi;
- paddr = (paddr << 32) | ma->base_addr_lo;
- size = ma->length_hi;
- size = (size << 32) | ma->length_lo;
+ paddr = ma->base_address;
+ size = ma->length;
/* Ignore disabled entries */
- if (!ma->flags.enabled)
+ if (!(ma->flags & ACPI_SRAT_MEM_ENABLED))
return;
/* record this node in proximity bitmap */
@@ -560,16 +553,16 @@ void __init acpi_numa_arch_fixup(void)
if (!slit_table)
return;
memset(numa_slit, -1, sizeof(numa_slit));
- for (i = 0; i < slit_table->localities; i++) {
+ for (i = 0; i < slit_table->locality_count; i++) {
if (!pxm_bit_test(i))
continue;
node_from = pxm_to_node(i);
- for (j = 0; j < slit_table->localities; j++) {
+ for (j = 0; j < slit_table->locality_count; j++) {
if (!pxm_bit_test(j))
continue;
node_to = pxm_to_node(j);
node_distance(node_from, node_to) =
- slit_table->entry[i * slit_table->localities + j];
+ slit_table->entry[i * slit_table->locality_count + j];
}
}
@@ -590,6 +583,9 @@ void __init acpi_numa_arch_fixup(void)
*/
int acpi_register_gsi(u32 gsi, int triggering, int polarity)
{
+ if (acpi_irq_model == ACPI_IRQ_MODEL_PLATFORM)
+ return gsi;
+
if (has_8259 && gsi < 16)
return isa_irq_to_vector(gsi);
@@ -606,26 +602,29 @@ EXPORT_SYMBOL(acpi_register_gsi);
void acpi_unregister_gsi(u32 gsi)
{
+ if (acpi_irq_model == ACPI_IRQ_MODEL_PLATFORM)
+ return;
+
iosapic_unregister_intr(gsi);
}
EXPORT_SYMBOL(acpi_unregister_gsi);
-static int __init acpi_parse_fadt(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_fadt(struct acpi_table_header *table)
{
struct acpi_table_header *fadt_header;
- struct fadt_descriptor *fadt;
+ struct acpi_table_fadt *fadt;
- if (!phys_addr || !size)
+ if (!table)
return -EINVAL;
- fadt_header = (struct acpi_table_header *)__va(phys_addr);
+ fadt_header = (struct acpi_table_header *)table;
if (fadt_header->revision != 3)
return -ENODEV; /* Only deal with ACPI 2.0 FADT */
- fadt = (struct fadt_descriptor *)fadt_header;
+ fadt = (struct acpi_table_fadt *)fadt_header;
- acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
+ acpi_register_gsi(fadt->sci_interrupt, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
return 0;
}
@@ -652,7 +651,7 @@ int __init acpi_boot_init(void)
* information -- the successor to MPS tables.
*/
- if (acpi_table_parse(ACPI_APIC, acpi_parse_madt) < 1) {
+ if (acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt) < 1) {
printk(KERN_ERR PREFIX "Can't find MADT\n");
goto skip_madt;
}
@@ -660,40 +659,40 @@ int __init acpi_boot_init(void)
/* Local APIC */
if (acpi_table_parse_madt
- (ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0) < 0)
+ (ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, acpi_parse_lapic_addr_ovr, 0) < 0)
printk(KERN_ERR PREFIX
"Error parsing LAPIC address override entry\n");
- if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic, NR_CPUS)
+ if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC, acpi_parse_lsapic, NR_CPUS)
< 1)
printk(KERN_ERR PREFIX
"Error parsing MADT - no LAPIC entries\n");
- if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0)
+ if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0)
< 0)
printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
/* I/O APIC */
if (acpi_table_parse_madt
- (ACPI_MADT_IOSAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1)
+ (ACPI_MADT_TYPE_IO_SAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1)
printk(KERN_ERR PREFIX
"Error parsing MADT - no IOSAPIC entries\n");
/* System-Level Interrupt Routing */
if (acpi_table_parse_madt
- (ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src,
+ (ACPI_MADT_TYPE_INTERRUPT_SOURCE, acpi_parse_plat_int_src,
ACPI_MAX_PLATFORM_INTERRUPTS) < 0)
printk(KERN_ERR PREFIX
"Error parsing platform interrupt source entry\n");
if (acpi_table_parse_madt
- (ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, 0) < 0)
+ (ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr, 0) < 0)
printk(KERN_ERR PREFIX
"Error parsing interrupt source overrides entry\n");
- if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, 0) < 0)
+ if (acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src, 0) < 0)
printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
skip_madt:
@@ -703,7 +702,7 @@ int __init acpi_boot_init(void)
* gets interrupts such as power and sleep buttons. If it's not
* on a Legacy interrupt, it needs to be setup.
*/
- if (acpi_table_parse(ACPI_FADT, acpi_parse_fadt) < 1)
+ if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt) < 1)
printk(KERN_ERR PREFIX "Can't find FADT\n");
#ifdef CONFIG_SMP
@@ -836,7 +835,7 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
- struct acpi_table_lsapic *lsapic;
+ struct acpi_madt_local_sapic *lsapic;
cpumask_t tmp_map;
long physid;
int cpu;
@@ -848,16 +847,16 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
return -EINVAL;
obj = buffer.pointer;
- if (obj->type != ACPI_TYPE_BUFFER ||
- obj->buffer.length < sizeof(*lsapic)) {
+ if (obj->type != ACPI_TYPE_BUFFER)
+ {
kfree(buffer.pointer);
return -EINVAL;
}
- lsapic = (struct acpi_table_lsapic *)obj->buffer.pointer;
+ lsapic = (struct acpi_madt_local_sapic *)obj->buffer.pointer;
- if ((lsapic->header.type != ACPI_MADT_LSAPIC) ||
- (!lsapic->flags.enabled)) {
+ if ((lsapic->header.type != ACPI_MADT_TYPE_LOCAL_SAPIC) ||
+ (!lsapic->lapic_flags & ACPI_MADT_ENABLED)) {
kfree(buffer.pointer);
return -EINVAL;
}
@@ -877,7 +876,6 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
cpu_set(cpu, cpu_present_map);
ia64_cpu_to_sapicid[cpu] = physid;
- ia64_acpiid_to_sapicid[lsapic->acpi_id] = ia64_cpu_to_sapicid[cpu];
*pcpu = cpu;
return (0);
@@ -887,14 +885,6 @@ EXPORT_SYMBOL(acpi_map_lsapic);
int acpi_unmap_lsapic(int cpu)
{
- int i;
-
- for (i = 0; i < MAX_SAPICS; i++) {
- if (ia64_acpiid_to_sapicid[i] == ia64_cpu_to_sapicid[cpu]) {
- ia64_acpiid_to_sapicid[i] = -1;
- break;
- }
- }
ia64_cpu_to_sapicid[cpu] = -1;
cpu_clear(cpu, cpu_present_map);
@@ -914,7 +904,7 @@ acpi_map_iosapic(acpi_handle handle, u32 depth, void *context, void **ret)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
- struct acpi_table_iosapic *iosapic;
+ struct acpi_madt_io_sapic *iosapic;
unsigned int gsi_base;
int pxm, node;
@@ -932,9 +922,9 @@ acpi_map_iosapic(acpi_handle handle, u32 depth, void *context, void **ret)
return AE_OK;
}
- iosapic = (struct acpi_table_iosapic *)obj->buffer.pointer;
+ iosapic = (struct acpi_madt_io_sapic *)obj->buffer.pointer;
- if (iosapic->header.type != ACPI_MADT_IOSAPIC) {
+ if (iosapic->header.type != ACPI_MADT_TYPE_IO_SAPIC) {
kfree(buffer.pointer);
return AE_OK;
}
diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
index 088f130197a..15c08d52f09 100644
--- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
+++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
@@ -276,12 +276,10 @@ acpi_cpufreq_cpu_init (
dprintk("acpi_cpufreq_cpu_init\n");
- data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
+ data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
if (!data)
return (-ENOMEM);
- memset(data, 0, sizeof(struct cpufreq_acpi_io));
-
acpi_io_data[cpu] = data;
result = acpi_processor_register_performance(&data->acpi_data, cpu);
diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c
index 0aabedf95da..37bb16f07fc 100644
--- a/arch/ia64/kernel/crash.c
+++ b/arch/ia64/kernel/crash.c
@@ -19,29 +19,11 @@
#include <asm/kdebug.h>
#include <asm/mca.h>
-#include <asm/uaccess.h>
int kdump_status[NR_CPUS];
atomic_t kdump_cpu_freezed;
atomic_t kdump_in_progress;
int kdump_on_init = 1;
-ssize_t
-copy_oldmem_page(unsigned long pfn, char *buf,
- size_t csize, unsigned long offset, int userbuf)
-{
- void *vaddr;
-
- if (!csize)
- return 0;
- vaddr = __va(pfn<<PAGE_SHIFT);
- if (userbuf) {
- if (copy_to_user(buf, (vaddr + offset), csize)) {
- return -EFAULT;
- }
- } else
- memcpy(buf, (vaddr + offset), csize);
- return csize;
-}
static inline Elf64_Word
*append_elf_note(Elf64_Word *buf, char *name, unsigned type, void *data,
@@ -70,7 +52,7 @@ extern void ia64_dump_cpu_regs(void *);
static DEFINE_PER_CPU(struct elf_prstatus, elf_prstatus);
void
-crash_save_this_cpu()
+crash_save_this_cpu(void)
{
void *buf;
unsigned long cfm, sof, sol;
@@ -97,6 +79,7 @@ crash_save_this_cpu()
final_note(buf);
}
+#ifdef CONFIG_SMP
static int
kdump_wait_cpu_freeze(void)
{
@@ -109,6 +92,7 @@ kdump_wait_cpu_freeze(void)
}
return 1;
}
+#endif
void
machine_crash_shutdown(struct pt_regs *pt)
@@ -134,6 +118,11 @@ machine_crash_shutdown(struct pt_regs *pt)
static void
machine_kdump_on_init(void)
{
+ if (!ia64_kimage) {
+ printk(KERN_NOTICE "machine_kdump_on_init(): "
+ "kdump not configured\n");
+ return;
+ }
local_irq_disable();
kexec_disable_iosapic();
machine_kexec(ia64_kimage);
@@ -150,11 +139,12 @@ kdump_cpu_freeze(struct unw_frame_info *info, void *arg)
atomic_inc(&kdump_cpu_freezed);
kdump_status[cpuid] = 1;
mb();
- if (cpuid == 0) {
- for (;;)
- cpu_relax();
- } else
+#ifdef CONFIG_HOTPLUG_CPU
+ if (cpuid != 0)
ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]);
+#endif
+ for (;;)
+ cpu_relax();
}
static int
@@ -225,14 +215,10 @@ static ctl_table sys_table[] = {
static int
machine_crash_setup(void)
{
- char *from = strstr(saved_command_line, "elfcorehdr=");
static struct notifier_block kdump_init_notifier_nb = {
.notifier_call = kdump_init_notifier,
};
int ret;
- if (from)
- elfcorehdr_addr = memparse(from+11, &from);
- saved_max_pfn = (unsigned long)-1;
if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0)
return ret;
#ifdef CONFIG_SYSCTL
diff --git a/arch/ia64/kernel/crash_dump.c b/arch/ia64/kernel/crash_dump.c
new file mode 100644
index 00000000000..da60e90eeeb
--- /dev/null
+++ b/arch/ia64/kernel/crash_dump.c
@@ -0,0 +1,49 @@
+/*
+ * kernel/crash_dump.c - Memory preserving reboot related code.
+ *
+ * Created by: Simon Horman <horms@verge.net.au>
+ * Original code moved from kernel/crash.c
+ * Original code comment copied from the i386 version of this file
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+
+#include <asm/page.h>
+#include <asm/uaccess.h>
+
+/**
+ * copy_oldmem_page - copy one page from "oldmem"
+ * @pfn: page frame number to be copied
+ * @buf: target memory address for the copy; this can be in kernel address
+ * space or user address space (see @userbuf)
+ * @csize: number of bytes to copy
+ * @offset: offset in bytes into the page (based on pfn) to begin the copy
+ * @userbuf: if set, @buf is in user address space, use copy_to_user(),
+ * otherwise @buf is in kernel address space, use memcpy().
+ *
+ * Copy a page from "oldmem". For this page, there is no pte mapped
+ * in the current kernel. We stitch up a pte, similar to kmap_atomic.
+ *
+ * Calling copy_to_user() in atomic context is not desirable. Hence first
+ * copying the data to a pre-allocated kernel page and then copying to user
+ * space in non-atomic context.
+ */
+ssize_t
+copy_oldmem_page(unsigned long pfn, char *buf,
+ size_t csize, unsigned long offset, int userbuf)
+{
+ void *vaddr;
+
+ if (!csize)
+ return 0;
+ vaddr = __va(pfn<<PAGE_SHIFT);
+ if (userbuf) {
+ if (copy_to_user(buf, (vaddr + offset), csize)) {
+ return -EFAULT;
+ }
+ } else
+ memcpy(buf, (vaddr + offset), csize);
+ return csize;
+}
+
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index 0b25a7d4e1e..6c03928544c 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -380,7 +380,7 @@ efi_get_pal_addr (void)
#endif
return __va(md->phys_addr);
}
- printk(KERN_WARNING "%s: no PAL-code memory-descriptor found",
+ printk(KERN_WARNING "%s: no PAL-code memory-descriptor found\n",
__FUNCTION__);
return NULL;
}
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 15234ed3a34..e7873eeae44 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1610,5 +1610,7 @@ sys_call_table:
data8 sys_sync_file_range // 1300
data8 sys_tee
data8 sys_vmsplice
+ data8 sys_ni_syscall // reserved for move_pages
+ data8 sys_getcpu
.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 0fc5fb7865c..d6aab40c641 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -925,6 +925,11 @@ iosapic_unregister_intr (unsigned int gsi)
/* Clear the interrupt controller descriptor */
idesc->chip = &no_irq_type;
+#ifdef CONFIG_SMP
+ /* Clear affinity */
+ cpus_setall(idesc->affinity);
+#endif
+
/* Clear the interrupt information */
memset(&iosapic_intr_info[vector], 0,
sizeof(struct iosapic_intr_info));
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index 54d55e4d64f..ce49c85c928 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -122,6 +122,9 @@ static void migrate_irqs(void)
for (irq=0; irq < NR_IRQS; irq++) {
desc = irq_desc + irq;
+ if (desc->status == IRQ_DISABLED)
+ continue;
+
/*
* No handling for now.
* TBD: Implement a disable function so we can now
diff --git a/arch/ia64/kernel/jprobes.S b/arch/ia64/kernel/jprobes.S
index 5cd6226f44f..621630256c4 100644
--- a/arch/ia64/kernel/jprobes.S
+++ b/arch/ia64/kernel/jprobes.S
@@ -45,13 +45,14 @@
* to the correct location.
*/
#include <asm/asmmacro.h>
+#include <asm-ia64/break.h>
/*
* void jprobe_break(void)
*/
.section .kprobes.text, "ax"
ENTRY(jprobe_break)
- break.m 0x80300
+ break.m __IA64_BREAK_JPROBE
END(jprobe_break)
/*
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 76e778951e2..6cb56dd4056 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -88,6 +88,7 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
{
p->ainsn.inst_flag = 0;
p->ainsn.target_br_reg = 0;
+ p->ainsn.slot = slot;
/* Check for Break instruction
* Bits 37:40 Major opcode to be zero
@@ -129,48 +130,6 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
/*
* In this function we check to see if the instruction
- * on which we are inserting kprobe is supported.
- * Returns 0 if supported
- * Returns -EINVAL if unsupported
- */
-static int __kprobes unsupported_inst(uint template, uint slot,
- uint major_opcode,
- unsigned long kprobe_inst,
- unsigned long addr)
-{
- if (bundle_encoding[template][slot] == I) {
- switch (major_opcode) {
- case 0x0: //I_UNIT_MISC_OPCODE:
- /*
- * Check for Integer speculation instruction
- * - Bit 33-35 to be equal to 0x1
- */
- if (((kprobe_inst >> 33) & 0x7) == 1) {
- printk(KERN_WARNING
- "Kprobes on speculation inst at <0x%lx> not supported\n",
- addr);
- return -EINVAL;
- }
-
- /*
- * IP relative mov instruction
- * - Bit 27-35 to be equal to 0x30
- */
- if (((kprobe_inst >> 27) & 0x1FF) == 0x30) {
- printk(KERN_WARNING
- "Kprobes on \"mov r1=ip\" at <0x%lx> not supported\n",
- addr);
- return -EINVAL;
-
- }
- }
- }
- return 0;
-}
-
-
-/*
- * In this function we check to see if the instruction
* (qp) cmpx.crel.ctype p1,p2=r2,r3
* on which we are inserting kprobe is cmp instruction
* with ctype as unc.
@@ -206,26 +165,136 @@ out:
}
/*
+ * In this function we check to see if the instruction
+ * on which we are inserting kprobe is supported.
+ * Returns qp value if supported
+ * Returns -EINVAL if unsupported
+ */
+static int __kprobes unsupported_inst(uint template, uint slot,
+ uint major_opcode,
+ unsigned long kprobe_inst,
+ unsigned long addr)
+{
+ int qp;
+
+ qp = kprobe_inst & 0x3f;
+ if (is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst)) {
+ if (slot == 1 && qp) {
+ printk(KERN_WARNING "Kprobes on cmp unc"
+ "instruction on slot 1 at <0x%lx>"
+ "is not supported\n", addr);
+ return -EINVAL;
+
+ }
+ qp = 0;
+ }
+ else if (bundle_encoding[template][slot] == I) {
+ if (major_opcode == 0) {
+ /*
+ * Check for Integer speculation instruction
+ * - Bit 33-35 to be equal to 0x1
+ */
+ if (((kprobe_inst >> 33) & 0x7) == 1) {
+ printk(KERN_WARNING
+ "Kprobes on speculation inst at <0x%lx> not supported\n",
+ addr);
+ return -EINVAL;
+ }
+ /*
+ * IP relative mov instruction
+ * - Bit 27-35 to be equal to 0x30
+ */
+ if (((kprobe_inst >> 27) & 0x1FF) == 0x30) {
+ printk(KERN_WARNING
+ "Kprobes on \"mov r1=ip\" at <0x%lx> not supported\n",
+ addr);
+ return -EINVAL;
+
+ }
+ }
+ else if ((major_opcode == 5) && !(kprobe_inst & (0xFUl << 33)) &&
+ (kprobe_inst & (0x1UL << 12))) {
+ /* test bit instructions, tbit,tnat,tf
+ * bit 33-36 to be equal to 0
+ * bit 12 to be equal to 1
+ */
+ if (slot == 1 && qp) {
+ printk(KERN_WARNING "Kprobes on test bit"
+ "instruction on slot at <0x%lx>"
+ "is not supported\n", addr);
+ return -EINVAL;
+ }
+ qp = 0;
+ }
+ }
+ else if (bundle_encoding[template][slot] == B) {
+ if (major_opcode == 7) {
+ /* IP-Relative Predict major code is 7 */
+ printk(KERN_WARNING "Kprobes on IP-Relative"
+ "Predict is not supported\n");
+ return -EINVAL;
+ }
+ else if (major_opcode == 2) {
+ /* Indirect Predict, major code is 2
+ * bit 27-32 to be equal to 10 or 11
+ */
+ int x6=(kprobe_inst >> 27) & 0x3F;
+ if ((x6 == 0x10) || (x6 == 0x11)) {
+ printk(KERN_WARNING "Kprobes on"
+ "Indirect Predict is not supported\n");
+ return -EINVAL;
+ }
+ }
+ }
+ /* kernel does not use float instruction, here for safety kprobe
+ * will judge whether it is fcmp/flass/float approximation instruction
+ */
+ else if (unlikely(bundle_encoding[template][slot] == F)) {
+ if ((major_opcode == 4 || major_opcode == 5) &&
+ (kprobe_inst & (0x1 << 12))) {
+ /* fcmp/fclass unc instruction */
+ if (slot == 1 && qp) {
+ printk(KERN_WARNING "Kprobes on fcmp/fclass "
+ "instruction on slot at <0x%lx> "
+ "is not supported\n", addr);
+ return -EINVAL;
+
+ }
+ qp = 0;
+ }
+ if ((major_opcode == 0 || major_opcode == 1) &&
+ (kprobe_inst & (0x1UL << 33))) {
+ /* float Approximation instruction */
+ if (slot == 1 && qp) {
+ printk(KERN_WARNING "Kprobes on float Approx "
+ "instr at <0x%lx> is not supported\n",
+ addr);
+ return -EINVAL;
+ }
+ qp = 0;
+ }
+ }
+ return qp;
+}
+
+/*
* In this function we override the bundle with
* the break instruction at the given slot.
*/
static void __kprobes prepare_break_inst(uint template, uint slot,
uint major_opcode,
unsigned long kprobe_inst,
- struct kprobe *p)
+ struct kprobe *p,
+ int qp)
{
unsigned long break_inst = BREAK_INST;
bundle_t *bundle = &p->opcode.bundle;
/*
* Copy the original kprobe_inst qualifying predicate(qp)
- * to the break instruction iff !is_cmp_ctype_unc_inst
- * because for cmp instruction with ctype equal to unc,
- * which is a special instruction always needs to be
- * executed regradless of qp
+ * to the break instruction
*/
- if (!is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst))
- break_inst |= (0x3f & kprobe_inst);
+ break_inst |= qp;
switch (slot) {
case 0:
@@ -296,12 +365,6 @@ static int __kprobes valid_kprobe_addr(int template, int slot,
return -EINVAL;
}
- if (slot == 1 && bundle_encoding[template][1] != L) {
- printk(KERN_WARNING "Inserting kprobes on slot #1 "
- "is not supported\n");
- return -EINVAL;
- }
-
return 0;
}
@@ -427,6 +490,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
unsigned long kprobe_inst=0;
unsigned int slot = addr & 0xf, template, major_opcode = 0;
bundle_t *bundle;
+ int qp;
bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle;
template = bundle->quad0.template;
@@ -441,9 +505,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
/* 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, addr))
- return -EINVAL;
-
+ qp = unsupported_inst(template, slot, major_opcode, kprobe_inst, addr);
+ if (qp < 0)
+ return -EINVAL;
p->ainsn.insn = get_insn_slot();
if (!p->ainsn.insn)
@@ -451,30 +515,56 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t));
memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t));
- prepare_break_inst(template, slot, major_opcode, kprobe_inst, p);
+ prepare_break_inst(template, slot, major_opcode, kprobe_inst, p, qp);
return 0;
}
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
- unsigned long addr = (unsigned long)p->addr;
- unsigned long arm_addr = addr & ~0xFULL;
+ unsigned long arm_addr;
+ bundle_t *src, *dest;
+
+ arm_addr = ((unsigned long)p->addr) & ~0xFUL;
+ dest = &((kprobe_opcode_t *)arm_addr)->bundle;
+ src = &p->opcode.bundle;
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));
+ switch (p->ainsn.slot) {
+ case 0:
+ dest->quad0.slot0 = src->quad0.slot0;
+ break;
+ case 1:
+ dest->quad1.slot1_p1 = src->quad1.slot1_p1;
+ break;
+ case 2:
+ dest->quad1.slot2 = src->quad1.slot2;
+ break;
+ }
flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
}
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
- unsigned long addr = (unsigned long)p->addr;
- unsigned long arm_addr = addr & ~0xFULL;
+ unsigned long arm_addr;
+ bundle_t *src, *dest;
+ arm_addr = ((unsigned long)p->addr) & ~0xFUL;
+ dest = &((kprobe_opcode_t *)arm_addr)->bundle;
/* p->ainsn.insn contains the original unaltered kprobe_opcode_t */
- memcpy((char *) arm_addr, (char *) p->ainsn.insn,
- sizeof(kprobe_opcode_t));
+ src = &p->ainsn.insn->bundle;
+ switch (p->ainsn.slot) {
+ case 0:
+ dest->quad0.slot0 = src->quad0.slot0;
+ break;
+ case 1:
+ dest->quad1.slot1_p1 = src->quad1.slot1_p1;
+ break;
+ case 2:
+ dest->quad1.slot2 = src->quad1.slot2;
+ break;
+ }
flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
}
@@ -807,7 +897,9 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
switch(val) {
case DIE_BREAK:
/* err is break number from ia64_bad_break() */
- if (args->err == 0x80200 || args->err == 0x80300 || args->err == 0)
+ if ((args->err >> 12) == (__IA64_BREAK_KPROBE >> 12)
+ || args->err == __IA64_BREAK_JPROBE
+ || args->err == 0)
if (pre_kprobes_handler(args))
ret = NOTIFY_STOP;
break;
diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c
index 468233fa2ce..4f0f3b8c1ee 100644
--- a/arch/ia64/kernel/machine_kexec.c
+++ b/arch/ia64/kernel/machine_kexec.c
@@ -14,13 +14,17 @@
#include <linux/kexec.h>
#include <linux/cpu.h>
#include <linux/irq.h>
+#include <linux/efi.h>
#include <asm/mmu_context.h>
#include <asm/setup.h>
#include <asm/delay.h>
#include <asm/meminit.h>
-typedef void (*relocate_new_kernel_t)(unsigned long, unsigned long,
- struct ia64_boot_param *, unsigned long);
+typedef NORET_TYPE void (*relocate_new_kernel_t)(
+ unsigned long indirection_page,
+ unsigned long start_address,
+ struct ia64_boot_param *boot_param,
+ unsigned long pal_addr) ATTRIB_NORET;
struct kimage *ia64_kimage;
@@ -65,22 +69,10 @@ void machine_kexec_cleanup(struct kimage *image)
{
}
-void machine_shutdown(void)
-{
- int cpu;
-
- for_each_online_cpu(cpu) {
- if (cpu != smp_processor_id())
- cpu_down(cpu);
- }
- kexec_disable_iosapic();
-}
-
/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now.
*/
-extern void *efi_get_pal_addr(void);
static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
{
struct kimage *image = arg;
@@ -90,6 +82,7 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
unsigned long vector;
int ii;
+ BUG_ON(!image);
if (image->type == KEXEC_TYPE_CRASH) {
crash_save_this_cpu();
current->thread.ksp = (__u64)info->sw - 16;
@@ -128,6 +121,7 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
void machine_kexec(struct kimage *image)
{
+ BUG_ON(!image);
unw_init_running(ia64_machine_kexec, image);
for(;;);
}
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 87c1c4f4287..a76add3e76a 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -1239,7 +1239,7 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
} else {
/* Dump buffered message to console */
ia64_mlogbuf_finish(1);
-#ifdef CONFIG_CRASH_DUMP
+#ifdef CONFIG_KEXEC
atomic_set(&kdump_in_progress, 1);
monarch_cpu = -1;
#endif
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index 822e59a1b82..0d05450c91c 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -64,12 +64,17 @@ static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
}
#endif /* CONFIG_SMP */
-int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
{
struct msi_msg msg;
unsigned long dest_phys_id;
- unsigned int vector;
+ unsigned int irq, vector;
+ irq = create_irq();
+ if (irq < 0)
+ return irq;
+
+ set_irq_msi(irq, desc);
dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
vector = irq;
@@ -89,12 +94,12 @@ int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
write_msi_msg(irq, &msg);
set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
- return 0;
+ return irq;
}
void ia64_teardown_msi_irq(unsigned int irq)
{
- return; /* no-op */
+ destroy_irq(irq);
}
static void ia64_ack_msi_irq(unsigned int irq)
@@ -126,12 +131,12 @@ static struct irq_chip ia64_msi_chip = {
};
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
{
if (platform_setup_msi_irq)
- return platform_setup_msi_irq(irq, pdev);
+ return platform_setup_msi_irq(pdev, desc);
- return ia64_setup_msi_irq(irq, pdev);
+ return ia64_setup_msi_irq(pdev, desc);
}
void arch_teardown_msi_irq(unsigned int irq)
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index dbb28164b19..aa94f60fa8e 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2188,13 +2188,13 @@ pfm_alloc_fd(struct file **cfile)
/*
* allocate a new dcache entry
*/
- file->f_dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
- if (!file->f_dentry) goto out;
+ file->f_path.dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
+ if (!file->f_path.dentry) goto out;
- file->f_dentry->d_op = &pfmfs_dentry_operations;
+ file->f_path.dentry->d_op = &pfmfs_dentry_operations;
- d_add(file->f_dentry, inode);
- file->f_vfsmnt = mntget(pfmfs_mnt);
+ d_add(file->f_path.dentry, inode);
+ file->f_path.mnt = mntget(pfmfs_mnt);
file->f_mapping = inode->i_mapping;
file->f_op = &pfm_file_ops;
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 51922b98086..ae96d417699 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -34,6 +34,7 @@
#include <asm/ia32.h>
#include <asm/irq.h>
#include <asm/kdebug.h>
+#include <asm/kexec.h>
#include <asm/pgalloc.h>
#include <asm/processor.h>
#include <asm/sal.h>
@@ -268,10 +269,16 @@ cpu_idle (void)
/* endless idle loop with no priority at all */
while (1) {
- if (can_do_pal_halt)
+ if (can_do_pal_halt) {
current_thread_info()->status &= ~TS_POLLING;
- else
+ /*
+ * TS_POLLING-cleared state must be visible before we
+ * test NEED_RESCHED:
+ */
+ smp_mb();
+ } else {
current_thread_info()->status |= TS_POLLING;
+ }
if (!need_resched()) {
void (*idle)(void);
@@ -797,6 +804,21 @@ cpu_halt (void)
ia64_pal_halt(min_power_state);
}
+void machine_shutdown(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+ int cpu;
+
+ for_each_online_cpu(cpu) {
+ if (cpu != smp_processor_id())
+ cpu_down(cpu);
+ }
+#endif
+#ifdef CONFIG_KEXEC
+ kexec_disable_iosapic();
+#endif
+}
+
void
machine_restart (char *restart_cmd)
{
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index aa705e46b97..3f8918782e0 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -607,7 +607,7 @@ find_thread_for_addr (struct task_struct *child, unsigned long addr)
*/
list_for_each_safe(this, next, &current->children) {
p = list_entry(this, struct task_struct, sibling);
- if (p->mm != mm)
+ if (p->tgid != child->tgid)
continue;
if (thread_matches(p, addr)) {
child = p;
@@ -1405,6 +1405,7 @@ ptrace_disable (struct task_struct *child)
struct ia64_psr *child_psr = ia64_psr(task_pt_regs(child));
/* make sure the single step/taken-branch trap bits are not set: */
+ clear_tsk_thread_flag(child, TIF_SINGLESTEP);
child_psr->ss = 0;
child_psr->tb = 0;
}
@@ -1525,6 +1526,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
* Make sure the single step/taken-branch trap bits
* are not set:
*/
+ clear_tsk_thread_flag(child, TIF_SINGLESTEP);
ia64_psr(pt)->ss = 0;
ia64_psr(pt)->tb = 0;
@@ -1556,6 +1558,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
goto out_tsk;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ set_tsk_thread_flag(child, TIF_SINGLESTEP);
if (request == PTRACE_SINGLESTEP) {
ia64_psr(pt)->ss = 1;
} else {
@@ -1595,13 +1598,9 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
}
-void
+static void
syscall_trace (void)
{
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
- if (!(current->ptrace & PT_PTRACED))
- return;
/*
* The 0x80 provides a way for the tracing parent to
* distinguish between a syscall stop and SIGTRAP delivery.
@@ -1664,7 +1663,8 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
audit_syscall_exit(success, result);
}
- if (test_thread_flag(TIF_SYSCALL_TRACE)
+ if ((test_thread_flag(TIF_SYSCALL_TRACE)
+ || test_thread_flag(TIF_SINGLESTEP))
&& (current->ptrace & PT_PTRACED))
syscall_trace();
}
diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
index fd607ca51a8..e375a2f0f2c 100644
--- a/arch/ia64/kernel/salinfo.c
+++ b/arch/ia64/kernel/salinfo.c
@@ -302,7 +302,7 @@ salinfo_event_open(struct inode *inode, struct file *file)
static ssize_t
salinfo_event_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct proc_dir_entry *entry = PDE(inode);
struct salinfo_data *data = entry->data;
char cmd[32];
@@ -464,7 +464,7 @@ retry:
static ssize_t
salinfo_log_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct proc_dir_entry *entry = PDE(inode);
struct salinfo_data *data = entry->data;
u8 *buf;
@@ -525,7 +525,7 @@ salinfo_log_clear(struct salinfo_data *data, int cpu)
static ssize_t
salinfo_log_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct proc_dir_entry *entry = PDE(inode);
struct salinfo_data *data = entry->data;
char cmd[32];
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 14e1200376a..83c2629e1c4 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -256,7 +256,7 @@ reserve_memory (void)
#ifdef CONFIG_KEXEC
/* crashkernel=size@offset specifies the size to reserve for a crash
- * kernel.(offset is ingored for keep compatibility with other archs)
+ * kernel. If offset is 0, then it is determined automatically.
* By reserving this memory we guarantee that linux never set's it
* up as a DMA target.Useful for holding code to do something
* appropriate after a kernel panic.
@@ -266,10 +266,16 @@ reserve_memory (void)
unsigned long base, size;
if (from) {
size = memparse(from + 12, &from);
+ if (*from == '@')
+ base = memparse(from+1, &from);
+ else
+ base = 0;
if (size) {
- sort_regions(rsvd_region, n);
- base = kdump_find_rsvd_region(size,
- rsvd_region, n);
+ if (!base) {
+ sort_regions(rsvd_region, n);
+ base = kdump_find_rsvd_region(size,
+ rsvd_region, n);
+ }
if (base != ~0UL) {
rsvd_region[n].start =
(unsigned long)__va(base);
@@ -434,6 +440,21 @@ static __init int setup_nomca(char *s)
}
early_param("nomca", setup_nomca);
+#ifdef CONFIG_PROC_VMCORE
+/* elfcorehdr= specifies the location of elf core header
+ * stored by the crashed kernel.
+ */
+static int __init parse_elfcorehdr(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ elfcorehdr_addr = memparse(arg, &arg);
+ return 0;
+}
+early_param("elfcorehdr", parse_elfcorehdr);
+#endif /* CONFIG_PROC_VMCORE */
+
void __init
setup_arch (char **cmdline_p)
{
@@ -548,34 +569,31 @@ show_cpuinfo (struct seq_file *m, void *v)
{ 1UL << 1, "spontaneous deferral"},
{ 1UL << 2, "16-byte atomic ops" }
};
- char features[128], *cp, sep;
+ char features[128], *cp, *sep;
struct cpuinfo_ia64 *c = v;
unsigned long mask;
unsigned long proc_freq;
- int i;
+ int i, size;
mask = c->features;
/* build the feature string: */
- memcpy(features, " standard", 10);
+ memcpy(features, "standard", 9);
cp = features;
- sep = 0;
- for (i = 0; i < (int) ARRAY_SIZE(feature_bits); ++i) {
+ size = sizeof(features);
+ sep = "";
+ for (i = 0; i < ARRAY_SIZE(feature_bits) && size > 1; ++i) {
if (mask & feature_bits[i].mask) {
- if (sep)
- *cp++ = sep;
- sep = ',';
- *cp++ = ' ';
- strcpy(cp, feature_bits[i].feature_name);
- cp += strlen(feature_bits[i].feature_name);
+ cp += snprintf(cp, size, "%s%s", sep,
+ feature_bits[i].feature_name),
+ sep = ", ";
mask &= ~feature_bits[i].mask;
+ size = sizeof(features) - (cp - features);
}
}
- if (mask) {
- /* print unknown features as a hex value: */
- if (sep)
- *cp++ = sep;
- sprintf(cp, " 0x%lx", mask);
+ if (mask && size > 1) {
+ /* print unknown features as a hex value */
+ snprintf(cp, size, "%s0x%lx", sep, mask);
}
proc_freq = cpufreq_quick_get(cpunum);
@@ -591,7 +609,7 @@ show_cpuinfo (struct seq_file *m, void *v)
"model name : %s\n"
"revision : %u\n"
"archrev : %u\n"
- "features :%s\n" /* don't change this---it _is_ right! */
+ "features : %s\n"
"cpu number : %lu\n"
"cpu regs : %u\n"
"cpu MHz : %lu.%06lu\n"
@@ -653,6 +671,7 @@ get_model_name(__u8 family, __u8 model)
{
char brand[128];
+ memcpy(brand, "Unknown", 8);
if (ia64_pal_get_brand_info(brand)) {
if (family == 0x7)
memcpy(brand, "Merced", 7);
@@ -660,8 +679,7 @@ get_model_name(__u8 family, __u8 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);
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index b1b9aa4364b..55ddd809b02 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -157,7 +157,7 @@ handle_IPI (int irq, void *dev_id)
case IPI_CPU_STOP:
stop_this_cpu();
break;
-#ifdef CONFIG_CRASH_DUMP
+#ifdef CONFIG_KEXEC
case IPI_KDUMP_CPU_STOP:
unw_init_running(kdump_cpu_freeze, NULL);
break;
@@ -219,15 +219,15 @@ send_IPI_self (int op)
send_IPI_single(smp_processor_id(), op);
}
-#ifdef CONFIG_CRASH_DUMP
+#ifdef CONFIG_KEXEC
void
-kdump_smp_send_stop()
+kdump_smp_send_stop(void)
{
send_IPI_allbutself(IPI_KDUMP_CPU_STOP);
}
void
-kdump_smp_send_init()
+kdump_smp_send_init(void)
{
unsigned int cpu, self_cpu;
self_cpu = smp_processor_id();
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index fffa9e0826b..ab684747036 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -307,6 +307,15 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long
return ret.status;
}
+struct fpu_swa_msg {
+ unsigned long count;
+ unsigned long time;
+};
+static DEFINE_PER_CPU(struct fpu_swa_msg, cpulast);
+DECLARE_PER_CPU(struct fpu_swa_msg, cpulast);
+static struct fpu_swa_msg last __cacheline_aligned;
+
+
/*
* Handle floating-point assist faults and traps.
*/
@@ -316,8 +325,6 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
long exception, bundle[2];
unsigned long fault_ip;
struct siginfo siginfo;
- static int fpu_swa_count = 0;
- static unsigned long last_time;
fault_ip = regs->cr_iip;
if (!fp_fault && (ia64_psr(regs)->ri == 0))
@@ -325,14 +332,37 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
if (copy_from_user(bundle, (void __user *) fault_ip, sizeof(bundle)))
return -1;
- if (jiffies - last_time > 5*HZ)
- fpu_swa_count = 0;
- if ((fpu_swa_count < 4) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) {
- last_time = jiffies;
- ++fpu_swa_count;
- printk(KERN_WARNING
- "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n",
- current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr);
+ if (!(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) {
+ unsigned long count, current_jiffies = jiffies;
+ struct fpu_swa_msg *cp = &__get_cpu_var(cpulast);
+
+ if (unlikely(current_jiffies > cp->time))
+ cp->count = 0;
+ if (unlikely(cp->count < 5)) {
+ cp->count++;
+ cp->time = current_jiffies + 5 * HZ;
+
+ /* minimize races by grabbing a copy of count BEFORE checking last.time. */
+ count = last.count;
+ barrier();
+
+ /*
+ * Lower 4 bits are used as a count. Upper bits are a sequence
+ * number that is updated when count is reset. The cmpxchg will
+ * fail is seqno has changed. This minimizes mutiple cpus
+ * reseting the count.
+ */
+ if (current_jiffies > last.time)
+ (void) cmpxchg_acq(&last.count, count, 16 + (count & ~15));
+
+ /* used fetchadd to atomically update the count */
+ if ((last.count & 15) < 5 && (ia64_fetchadd(1, &last.count, acq) & 15) < 5) {
+ last.time = current_jiffies + 5 * HZ;
+ printk(KERN_WARNING
+ "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n",
+ current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr);
+ }
+ }
}
exception = fp_emulate(fp_fault, bundle, &regs->cr_ipsr, &regs->ar_fpsr, &isr, &regs->pr,
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index d6083a0936f..8f3d0066f44 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -157,6 +157,7 @@ SECTIONS
}
#endif
+ . = ALIGN(8);
__con_initcall_start = .;
.con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET)
{ *(.con_initcall.init) }
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index 82deaa3a7c4..63e6d49c581 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -30,47 +30,69 @@ static unsigned long max_gap;
#endif
/**
- * show_mem - display a memory statistics summary
+ * show_mem - give short summary of memory stats
*
- * Just walks the pages in the system and describes where they're allocated.
+ * Shows a simple page count of reserved and used pages in the system.
+ * For discontig machines, it does this on a per-pgdat basis.
*/
-void
-show_mem (void)
+void show_mem(void)
{
- int i, total = 0, reserved = 0;
- int shared = 0, cached = 0;
+ int i, total_reserved = 0;
+ int total_shared = 0, total_cached = 0;
+ unsigned long total_present = 0;
+ pg_data_t *pgdat;
printk(KERN_INFO "Mem-info:\n");
show_free_areas();
-
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)) {
+ 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;
+
+ pgdat_resize_lock(pgdat, &flags);
+ present = pgdat->node_present_pages;
+ for(i = 0; i < pgdat->node_spanned_pages; i++) {
+ struct page *page;
+ if (pfn_valid(pgdat->node_start_pfn + i))
+ page = pfn_to_page(pgdat->node_start_pfn + i);
+ else {
#ifdef CONFIG_VIRTUAL_MEM_MAP
- if (max_gap < LARGE_GAP)
- continue;
- i = vmemmap_find_next_valid_pfn(0, i) - 1;
+ if (max_gap < LARGE_GAP)
+ continue;
#endif
- continue;
+ i = vmemmap_find_next_valid_pfn(pgdat->node_id,
+ i) - 1;
+ continue;
+ }
+ if (PageReserved(page))
+ reserved++;
+ else if (PageSwapCache(page))
+ cached++;
+ else if (page_count(page))
+ shared += page_count(page)-1;
}
- total++;
- if (PageReserved(mem_map+i))
- reserved++;
- else if (PageSwapCache(mem_map+i))
- cached++;
- else if (page_count(mem_map + i))
- shared += page_count(mem_map + i) - 1;
+ pgdat_resize_unlock(pgdat, &flags);
+ total_present += present;
+ total_reserved += reserved;
+ total_cached += cached;
+ total_shared += shared;
+ printk(KERN_INFO "Node %4d: RAM: %11ld, rsvd: %8d, "
+ "shrd: %10d, swpd: %10d\n", pgdat->node_id,
+ present, reserved, shared, cached);
}
- 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",
+ 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());
}
+
/* physical address where the bootmem map is located */
unsigned long bootmap_start;
@@ -174,6 +196,12 @@ find_memory (void)
reserve_bootmem(bootmap_start, bootmap_size);
find_initrd();
+
+#ifdef CONFIG_CRASH_DUMP
+ /* If we are doing a crash dump, we still need to know the real mem
+ * size before original memory map is reset. */
+ saved_max_pfn = max_pfn;
+#endif
}
#ifdef CONFIG_SMP
@@ -226,7 +254,6 @@ void __init
paging_init (void)
{
unsigned long max_dma;
- unsigned long nid = 0;
unsigned long max_zone_pfns[MAX_NR_ZONES];
num_physpages = 0;
@@ -238,7 +265,7 @@ paging_init (void)
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
#ifdef CONFIG_VIRTUAL_MEM_MAP
- efi_memmap_walk(register_active_ranges, &nid);
+ efi_memmap_walk(register_active_ranges, NULL);
efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
if (max_gap < LARGE_GAP) {
vmem_map = (struct page *) 0;
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 96722cb1b49..6eae596c509 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -412,37 +412,6 @@ static void __init memory_less_nodes(void)
return;
}
-#ifdef CONFIG_SPARSEMEM
-/**
- * register_sparse_mem - notify SPARSEMEM that this memory range exists.
- * @start: physical start of range
- * @end: physical end of range
- * @arg: unused
- *
- * Simply calls SPARSEMEM to register memory section(s).
- */
-static int __init register_sparse_mem(unsigned long start, unsigned long end,
- void *arg)
-{
- int nid;
-
- start = __pa(start) >> PAGE_SHIFT;
- end = __pa(end) >> PAGE_SHIFT;
- nid = early_pfn_to_nid(start);
- memory_present(nid, start, end);
-
- return 0;
-}
-
-static void __init arch_sparse_init(void)
-{
- efi_memmap_walk(register_sparse_mem, NULL);
- sparse_init();
-}
-#else
-#define arch_sparse_init() do {} while (0)
-#endif
-
/**
* find_memory - walk the EFI memory map and setup the bootmem allocator
*
@@ -473,6 +442,9 @@ void __init find_memory(void)
node_clear(node, memory_less_mask);
mem_data[node].min_pfn = ~0UL;
}
+
+ efi_memmap_walk(register_active_ranges, NULL);
+
/*
* Initialize the boot memory maps in reverse order since that's
* what the bootmem allocator expects
@@ -506,6 +478,12 @@ void __init find_memory(void)
max_pfn = max_low_pfn;
find_initrd();
+
+#ifdef CONFIG_CRASH_DUMP
+ /* If we are doing a crash dump, we still need to know the real mem
+ * size before original memory map is reset. */
+ saved_max_pfn = max_pfn;
+#endif
}
#ifdef CONFIG_SMP
@@ -654,7 +632,6 @@ 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 +=
@@ -686,10 +663,11 @@ void __init paging_init(void)
max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
- arch_sparse_init();
-
efi_memmap_walk(filter_rsvd_memory, count_node_pages);
+ sparse_memory_present_with_active_regions(MAX_NUMNODES);
+ sparse_init();
+
#ifdef CONFIG_VIRTUAL_MEM_MAP
vmalloc_end -= PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) *
sizeof(struct page));
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 56dc2024220..faaca21a371 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -19,6 +19,7 @@
#include <linux/swap.h>
#include <linux/proc_fs.h>
#include <linux/bitops.h>
+#include <linux/kexec.h>
#include <asm/a.out.h>
#include <asm/dma.h>
@@ -128,6 +129,25 @@ lazy_mmu_prot_update (pte_t pte)
set_bit(PG_arch_1, &page->flags); /* mark page as clean */
}
+/*
+ * Since DMA is i-cache coherent, any (complete) pages that were written via
+ * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
+ * flush them when they get mapped into an executable vm-area.
+ */
+void
+dma_mark_clean(void *addr, size_t size)
+{
+ unsigned long pg_addr, end;
+
+ pg_addr = PAGE_ALIGN((unsigned long) addr);
+ end = (unsigned long) addr + size;
+ while (pg_addr + PAGE_SIZE <= end) {
+ struct page *page = virt_to_page(pg_addr);
+ set_bit(PG_arch_1, &page->flags);
+ pg_addr += PAGE_SIZE;
+ }
+}
+
inline void
ia64_set_rbs_bot (void)
{
@@ -543,7 +563,8 @@ virtual_memmap_init (u64 start, u64 end, void *arg)
if (map_start < map_end)
memmap_init_zone((unsigned long)(map_end - map_start),
- args->nid, args->zone, page_to_pfn(map_start));
+ args->nid, args->zone, page_to_pfn(map_start),
+ MEMMAP_EARLY);
return 0;
}
@@ -552,7 +573,7 @@ memmap_init (unsigned long size, int nid, unsigned long zone,
unsigned long start_pfn)
{
if (!vmem_map)
- memmap_init_zone(size, nid, zone, start_pfn);
+ memmap_init_zone(size, nid, zone, start_pfn, MEMMAP_EARLY);
else {
struct page *start;
struct memmap_init_callback_data args;
@@ -594,18 +615,27 @@ find_largest_hole (u64 start, u64 end, void *arg)
return 0;
}
+#endif /* CONFIG_VIRTUAL_MEM_MAP */
+
int __init
-register_active_ranges(u64 start, u64 end, void *nid)
+register_active_ranges(u64 start, u64 end, void *arg)
{
- BUG_ON(nid == NULL);
- BUG_ON(*(unsigned long *)nid >= MAX_NUMNODES);
+ int nid = paddr_to_nid(__pa(start));
+
+ if (nid < 0)
+ nid = 0;
+#ifdef CONFIG_KEXEC
+ if (start > crashk_res.start && start < crashk_res.end)
+ start = crashk_res.end;
+ if (end > crashk_res.start && end < crashk_res.end)
+ end = crashk_res.start;
+#endif
- add_active_range(*(unsigned long *)nid,
- __pa(start) >> PAGE_SHIFT,
- __pa(end) >> PAGE_SHIFT);
+ if (start < end)
+ add_active_range(nid, __pa(start) >> PAGE_SHIFT,
+ __pa(end) >> PAGE_SHIFT);
return 0;
}
-#endif /* CONFIG_VIRTUAL_MEM_MAP */
static int __init
count_reserved_pages (u64 start, u64 end, void *arg)
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
index abca6bd7962..fcf7f93c4b6 100644
--- a/arch/ia64/sn/kernel/huberror.c
+++ b/arch/ia64/sn/kernel/huberror.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1992 - 1997, 2000,2002-2005 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000,2002-2007 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/types.h>
@@ -38,12 +38,20 @@ static irqreturn_t hub_eint_handler(int irq, void *arg)
(u64) nasid, 0, 0, 0, 0, 0, 0);
if ((int)ret_stuff.v0)
- panic("hubii_eint_handler(): Fatal TIO Error");
+ panic("%s: Fatal %s Error", __FUNCTION__,
+ ((nasid & 1) ? "TIO" : "HUBII"));
if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
(void)hubiio_crb_error_handler(hubdev_info);
- } else
- bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
+ } else
+ if (nasid & 1) { /* TIO errors */
+ SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
+ (u64) nasid, 0, 0, 0, 0, 0, 0);
+
+ if ((int)ret_stuff.v0)
+ panic("%s: Fatal TIO Error", __FUNCTION__);
+ } else
+ bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
return IRQ_HANDLED;
}
diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c
index 99d7f278612..8c331ca6e5c 100644
--- a/arch/ia64/sn/kernel/io_acpi_init.c
+++ b/arch/ia64/sn/kernel/io_acpi_init.c
@@ -13,6 +13,7 @@
#include <asm/sn/sn_sal.h>
#include "xtalk/hubdev.h"
#include <linux/acpi.h>
+#include <acpi/acnamesp.h>
/*
@@ -31,6 +32,12 @@ struct acpi_vendor_uuid sn_uuid = {
0xa2, 0x7c, 0x08, 0x00, 0x69, 0x13, 0xea, 0x51 },
};
+struct sn_pcidev_match {
+ u8 bus;
+ unsigned int devfn;
+ acpi_handle handle;
+};
+
/*
* Perform the early IO init in PROM.
*/
@@ -119,9 +126,11 @@ sn_get_bussoft_ptr(struct pci_bus *bus)
status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
&sn_uuid, &buffer);
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR "get_acpi_pcibus_ptr: "
- "get_acpi_bussoft_info() failed: %d\n",
- status);
+ printk(KERN_ERR "%s: "
+ "acpi_get_vendor_resource() failed (0x%x) for: ",
+ __FUNCTION__, status);
+ acpi_ns_print_node_pathname(handle, NULL);
+ printk("\n");
return NULL;
}
resource = buffer.pointer;
@@ -130,8 +139,8 @@ sn_get_bussoft_ptr(struct pci_bus *bus)
if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
sizeof(struct pcibus_bussoft *)) {
printk(KERN_ERR
- "get_acpi_bussoft_ptr: Invalid vendor data "
- "length %d\n", vendor->byte_length);
+ "%s: Invalid vendor data length %d\n",
+ __FUNCTION__, vendor->byte_length);
kfree(buffer.pointer);
return NULL;
}
@@ -143,34 +152,254 @@ sn_get_bussoft_ptr(struct pci_bus *bus)
}
/*
- * sn_acpi_bus_fixup
+ * sn_extract_device_info - Extract the pcidev_info and the sn_irq_info
+ * pointers from the vendor resource using the
+ * provided acpi handle, and copy the structures
+ * into the argument buffers.
*/
-void
-sn_acpi_bus_fixup(struct pci_bus *bus)
+static int
+sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info,
+ struct sn_irq_info **sn_irq_info)
{
- struct pci_dev *pci_dev = NULL;
- struct pcibus_bussoft *prom_bussoft_ptr;
- extern void sn_common_bus_fixup(struct pci_bus *,
- struct pcibus_bussoft *);
+ u64 addr;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct sn_irq_info *irq_info, *irq_info_prom;
+ struct pcidev_info *pcidev_ptr, *pcidev_prom_ptr;
+ struct acpi_resource *resource;
+ int ret = 0;
+ acpi_status status;
+ struct acpi_resource_vendor_typed *vendor;
- if (!bus->parent) { /* If root bus */
- prom_bussoft_ptr = sn_get_bussoft_ptr(bus);
- if (prom_bussoft_ptr == NULL) {
+ /*
+ * The pointer to this device's pcidev_info structure in
+ * the PROM, is in the vendor resource.
+ */
+ status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
+ &sn_uuid, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR
+ "%s: acpi_get_vendor_resource() failed (0x%x) for: ",
+ __FUNCTION__, status);
+ acpi_ns_print_node_pathname(handle, NULL);
+ printk("\n");
+ return 1;
+ }
+
+ resource = buffer.pointer;
+ vendor = &resource->data.vendor_typed;
+ if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
+ sizeof(struct pci_devdev_info *)) {
+ printk(KERN_ERR
+ "%s: Invalid vendor data length: %d for: ",
+ __FUNCTION__, vendor->byte_length);
+ acpi_ns_print_node_pathname(handle, NULL);
+ printk("\n");
+ ret = 1;
+ goto exit;
+ }
+
+ pcidev_ptr = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
+ if (!pcidev_ptr)
+ panic("%s: Unable to alloc memory for pcidev_info", __FUNCTION__);
+
+ memcpy(&addr, vendor->byte_data, sizeof(struct pcidev_info *));
+ pcidev_prom_ptr = __va(addr);
+ memcpy(pcidev_ptr, pcidev_prom_ptr, sizeof(struct pcidev_info));
+
+ /* Get the IRQ info */
+ irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
+ if (!irq_info)
+ panic("%s: Unable to alloc memory for sn_irq_info", __FUNCTION__);
+
+ if (pcidev_ptr->pdi_sn_irq_info) {
+ irq_info_prom = __va(pcidev_ptr->pdi_sn_irq_info);
+ memcpy(irq_info, irq_info_prom, sizeof(struct sn_irq_info));
+ }
+
+ *pcidev_info = pcidev_ptr;
+ *sn_irq_info = irq_info;
+
+exit:
+ kfree(buffer.pointer);
+ return ret;
+}
+
+static unsigned int
+get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle)
+{
+ unsigned long adr;
+ acpi_handle child;
+ unsigned int devfn;
+ int function;
+ acpi_handle parent;
+ int slot;
+ acpi_status status;
+
+ /*
+ * Do an upward search to find the root bus device, and
+ * obtain the host devfn from the previous child device.
+ */
+ child = device_handle;
+ while (child) {
+ status = acpi_get_parent(child, &parent);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR "%s: acpi_get_parent() failed "
+ "(0x%x) for: ", __FUNCTION__, status);
+ acpi_ns_print_node_pathname(child, NULL);
+ printk("\n");
+ panic("%s: Unable to find host devfn\n", __FUNCTION__);
+ }
+ if (parent == rootbus_handle)
+ break;
+ child = parent;
+ }
+ if (!child) {
+ printk(KERN_ERR "%s: Unable to find root bus for: ",
+ __FUNCTION__);
+ acpi_ns_print_node_pathname(device_handle, NULL);
+ printk("\n");
+ BUG();
+ }
+
+ status = acpi_evaluate_integer(child, METHOD_NAME__ADR, NULL, &adr);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR "%s: Unable to get _ADR (0x%x) for: ",
+ __FUNCTION__, status);
+ acpi_ns_print_node_pathname(child, NULL);
+ printk("\n");
+ panic("%s: Unable to find host devfn\n", __FUNCTION__);
+ }
+
+ slot = (adr >> 16) & 0xffff;
+ function = adr & 0xffff;
+ devfn = PCI_DEVFN(slot, function);
+ return devfn;
+}
+
+/*
+ * find_matching_device - Callback routine to find the ACPI device
+ * that matches up with our pci_dev device.
+ * Matching is done on bus number and devfn.
+ * To find the bus number for a particular
+ * ACPI device, we must look at the _BBN method
+ * of its parent.
+ */
+static acpi_status
+find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ unsigned long bbn = -1;
+ unsigned long adr;
+ acpi_handle parent = NULL;
+ acpi_status status;
+ unsigned int devfn;
+ int function;
+ int slot;
+ struct sn_pcidev_match *info = context;
+
+ status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
+ &adr);
+ if (ACPI_SUCCESS(status)) {
+ status = acpi_get_parent(handle, &parent);
+ if (ACPI_FAILURE(status)) {
printk(KERN_ERR
- "sn_pci_fixup_bus: 0x%04x:0x%02x Unable to "
- "obtain prom_bussoft_ptr\n",
- pci_domain_nr(bus), bus->number);
- return;
+ "%s: acpi_get_parent() failed (0x%x) for: ",
+ __FUNCTION__, status);
+ acpi_ns_print_node_pathname(handle, NULL);
+ printk("\n");
+ return AE_OK;
+ }
+ status = acpi_evaluate_integer(parent, METHOD_NAME__BBN,
+ NULL, &bbn);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR
+ "%s: Failed to find _BBN in parent of: ",
+ __FUNCTION__);
+ acpi_ns_print_node_pathname(handle, NULL);
+ printk("\n");
+ return AE_OK;
+ }
+
+ slot = (adr >> 16) & 0xffff;
+ function = adr & 0xffff;
+ devfn = PCI_DEVFN(slot, function);
+ if ((info->devfn == devfn) && (info->bus == bbn)) {
+ /* We have a match! */
+ info->handle = handle;
+ return 1;
}
- sn_common_bus_fixup(bus, prom_bussoft_ptr);
}
- list_for_each_entry(pci_dev, &bus->devices, bus_list) {
- sn_pci_fixup_slot(pci_dev);
+ return AE_OK;
+}
+
+/*
+ * sn_acpi_get_pcidev_info - Search ACPI namespace for the acpi
+ * device matching the specified pci_dev,
+ * and return the pcidev info and irq info.
+ */
+int
+sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info,
+ struct sn_irq_info **sn_irq_info)
+{
+ unsigned int host_devfn;
+ struct sn_pcidev_match pcidev_match;
+ acpi_handle rootbus_handle;
+ unsigned long segment;
+ acpi_status status;
+
+ rootbus_handle = PCI_CONTROLLER(dev)->acpi_handle;
+ status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL,
+ &segment);
+ if (ACPI_SUCCESS(status)) {
+ if (segment != pci_domain_nr(dev)) {
+ printk(KERN_ERR
+ "%s: Segment number mismatch, 0x%lx vs 0x%x for: ",
+ __FUNCTION__, segment, pci_domain_nr(dev));
+ acpi_ns_print_node_pathname(rootbus_handle, NULL);
+ printk("\n");
+ return 1;
+ }
+ } else {
+ printk(KERN_ERR "%s: Unable to get __SEG from: ",
+ __FUNCTION__);
+ acpi_ns_print_node_pathname(rootbus_handle, NULL);
+ printk("\n");
+ return 1;
}
+
+ /*
+ * We want to search all devices in this segment/domain
+ * of the ACPI namespace for the matching ACPI device,
+ * which holds the pcidev_info pointer in its vendor resource.
+ */
+ pcidev_match.bus = dev->bus->number;
+ pcidev_match.devfn = dev->devfn;
+ pcidev_match.handle = NULL;
+
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, rootbus_handle, ACPI_UINT32_MAX,
+ find_matching_device, &pcidev_match, NULL);
+
+ if (!pcidev_match.handle) {
+ printk(KERN_ERR
+ "%s: Could not find matching ACPI device for %s.\n",
+ __FUNCTION__, pci_name(dev));
+ return 1;
+ }
+
+ if (sn_extract_device_info(pcidev_match.handle, pcidev_info, sn_irq_info))
+ return 1;
+
+ /* Build up the pcidev_info.pdi_slot_host_handle */
+ host_devfn = get_host_devfn(pcidev_match.handle, rootbus_handle);
+ (*pcidev_info)->pdi_slot_host_handle =
+ ((unsigned long) pci_domain_nr(dev) << 40) |
+ /* bus == 0 */
+ host_devfn;
+ return 0;
}
/*
- * sn_acpi_slot_fixup - Perform any SN specific slot fixup.
+ * sn_acpi_slot_fixup - Obtain the pcidev_info and sn_irq_info.
+ * Perform any SN specific slot fixup.
* At present there does not appear to be
* any generic way to handle a ROM image
* that has been shadowed by the PROM, so
@@ -179,11 +408,18 @@ sn_acpi_bus_fixup(struct pci_bus *bus)
*/
void
-sn_acpi_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
+sn_acpi_slot_fixup(struct pci_dev *dev)
{
void __iomem *addr;
+ struct pcidev_info *pcidev_info = NULL;
+ struct sn_irq_info *sn_irq_info = NULL;
size_t size;
+ if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) {
+ panic("%s: Failure obtaining pcidev_info for %s\n",
+ __FUNCTION__, pci_name(dev));
+ }
+
if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) {
/*
* A valid ROM image exists and has been shadowed by the
@@ -200,8 +436,11 @@ sn_acpi_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
(unsigned long) addr + size;
dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY;
}
+ sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
}
+EXPORT_SYMBOL(sn_acpi_slot_fixup);
+
static struct acpi_driver acpi_sn_hubdev_driver = {
.name = "SGI HUBDEV Driver",
.ids = "SGIHUB,SGITIO",
@@ -212,6 +451,33 @@ static struct acpi_driver acpi_sn_hubdev_driver = {
/*
+ * sn_acpi_bus_fixup - Perform SN specific setup of software structs
+ * (pcibus_bussoft, pcidev_info) and hardware
+ * registers, for the specified bus and devices under it.
+ */
+void
+sn_acpi_bus_fixup(struct pci_bus *bus)
+{
+ struct pci_dev *pci_dev = NULL;
+ struct pcibus_bussoft *prom_bussoft_ptr;
+
+ if (!bus->parent) { /* If root bus */
+ prom_bussoft_ptr = sn_get_bussoft_ptr(bus);
+ if (prom_bussoft_ptr == NULL) {
+ printk(KERN_ERR
+ "%s: 0x%04x:0x%02x Unable to "
+ "obtain prom_bussoft_ptr\n",
+ __FUNCTION__, pci_domain_nr(bus), bus->number);
+ return;
+ }
+ sn_common_bus_fixup(bus, prom_bussoft_ptr);
+ }
+ list_for_each_entry(pci_dev, &bus->devices, bus_list) {
+ sn_acpi_slot_fixup(pci_dev);
+ }
+}
+
+/*
* sn_io_acpi_init - PROM has ACPI support for IO, defining at a minimum the
* nodes and root buses in the DSDT. As a result, bus scanning
* will be initiated by the Linux ACPI code.
@@ -223,6 +489,9 @@ sn_io_acpi_init(void)
u64 result;
s64 status;
+ /* SN Altix does not follow the IOSAPIC IRQ routing model */
+ acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
+
acpi_bus_register_driver(&acpi_sn_hubdev_driver);
status = sal_ioif_init(&result);
if (status || result)
diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c
index d4dd8f4b6b8..d48bcd83253 100644
--- a/arch/ia64/sn/kernel/io_common.c
+++ b/arch/ia64/sn/kernel/io_common.c
@@ -26,14 +26,10 @@
#include <linux/acpi.h>
#include <asm/sn/sn2/sn_hwperf.h>
#include <asm/sn/acpi.h>
+#include "acpi/acglobal.h"
extern void sn_init_cpei_timer(void);
extern void register_sn_procfs(void);
-extern void sn_acpi_bus_fixup(struct pci_bus *);
-extern void sn_bus_fixup(struct pci_bus *);
-extern void sn_acpi_slot_fixup(struct pci_dev *, struct pcidev_info *);
-extern void sn_more_slot_fixup(struct pci_dev *, struct pcidev_info *);
-extern void sn_legacy_pci_window_fixup(struct pci_controller *, u64, u64);
extern void sn_io_acpi_init(void);
extern void sn_io_init(void);
@@ -48,6 +44,9 @@ struct sysdata_el {
int sn_ioif_inited; /* SN I/O infrastructure initialized? */
+int sn_acpi_rev; /* SN ACPI revision */
+EXPORT_SYMBOL_GPL(sn_acpi_rev);
+
struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */
/*
@@ -99,25 +98,6 @@ sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num,
}
/*
- * Retrieve the pci device information given the bus and device|function number.
- */
-static inline u64
-sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
- u64 sn_irq_info)
-{
- struct ia64_sal_retval ret_stuff;
- ret_stuff.status = 0;
- ret_stuff.v0 = 0;
-
- SAL_CALL_NOLOCK(ret_stuff,
- (u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
- (u64) segment, (u64) bus_number, (u64) devfn,
- (u64) pci_dev,
- sn_irq_info, 0, 0);
- return ret_stuff.v0;
-}
-
-/*
* sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified
* device.
*/
@@ -249,50 +229,25 @@ void sn_pci_unfixup_slot(struct pci_dev *dev)
}
/*
- * sn_pci_fixup_slot() - This routine sets up a slot's resources consistent
- * with the Linux PCI abstraction layer. Resources
- * acquired from our PCI provider include PIO maps
- * to BAR space and interrupt objects.
+ * sn_pci_fixup_slot()
*/
-void sn_pci_fixup_slot(struct pci_dev *dev)
+void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *pcidev_info,
+ struct sn_irq_info *sn_irq_info)
{
int segment = pci_domain_nr(dev->bus);
- int status = 0;
struct pcibus_bussoft *bs;
- struct pci_bus *host_pci_bus;
- struct pci_dev *host_pci_dev;
- struct pcidev_info *pcidev_info;
- struct sn_irq_info *sn_irq_info;
- unsigned int bus_no, devfn;
+ struct pci_bus *host_pci_bus;
+ struct pci_dev *host_pci_dev;
+ unsigned int bus_no, devfn;
pci_dev_get(dev); /* for the sysdata pointer */
- pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
- if (!pcidev_info)
- BUG(); /* Cannot afford to run out of memory */
-
- sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
- if (!sn_irq_info)
- BUG(); /* Cannot afford to run out of memory */
-
- /* Call to retrieve pci device information needed by kernel. */
- status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number,
- dev->devfn,
- (u64) __pa(pcidev_info),
- (u64) __pa(sn_irq_info));
- if (status)
- BUG(); /* Cannot get platform pci device information */
/* Add pcidev_info to list in pci_controller.platform_data */
list_add_tail(&pcidev_info->pdi_list,
&(SN_PLATFORM_DATA(dev->bus)->pcidev_info));
-
- if (SN_ACPI_BASE_SUPPORT())
- sn_acpi_slot_fixup(dev, pcidev_info);
- else
- sn_more_slot_fixup(dev, pcidev_info);
/*
* Using the PROMs values for the PCI host bus, get the Linux
- * PCI host_pci_dev struct and set up host bus linkages
+ * PCI host_pci_dev struct and set up host bus linkages
*/
bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff;
@@ -489,11 +444,6 @@ void sn_generate_path(struct pci_bus *pci_bus, char *address)
sprintf(address, "%s^%d", address, geo_slot(geoid));
}
-/*
- * sn_pci_fixup_bus() - Perform SN specific setup of software structs
- * (pcibus_bussoft, pcidev_info) and hardware
- * registers, for the specified bus and devices under it.
- */
void __devinit
sn_pci_fixup_bus(struct pci_bus *bus)
{
@@ -519,6 +469,15 @@ sn_io_early_init(void)
if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM())
return 0;
+ /* we set the acpi revision to that of the DSDT table OEM rev. */
+ {
+ struct acpi_table_header *header = NULL;
+
+ acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header);
+ BUG_ON(header == NULL);
+ sn_acpi_rev = header->oem_revision;
+ }
+
/*
* prime sn_pci_provider[]. Individial provider init routines will
* override their respective default entries.
@@ -544,8 +503,12 @@ sn_io_early_init(void)
register_sn_procfs();
#endif
- printk(KERN_INFO "ACPI DSDT OEM Rev 0x%x\n",
- acpi_gbl_DSDT->oem_revision);
+ {
+ struct acpi_table_header *header;
+ (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header);
+ printk(KERN_INFO "ACPI DSDT OEM Rev 0x%x\n",
+ header->oem_revision);
+ }
if (SN_ACPI_BASE_SUPPORT())
sn_io_acpi_init();
else
@@ -605,7 +568,6 @@ sn_io_late_init(void)
fs_initcall(sn_io_late_init);
-EXPORT_SYMBOL(sn_pci_fixup_slot);
EXPORT_SYMBOL(sn_pci_unfixup_slot);
EXPORT_SYMBOL(sn_bus_store_sysdata);
EXPORT_SYMBOL(sn_bus_free_sysdata);
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 9ad843e0383..600be3ebae0 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -56,6 +56,25 @@ static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
return ret_stuff.v0;
}
+/*
+ * Retrieve the pci device information given the bus and device|function number.
+ */
+static inline u64
+sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
+ u64 sn_irq_info)
+{
+ struct ia64_sal_retval ret_stuff;
+ ret_stuff.status = 0;
+ ret_stuff.v0 = 0;
+
+ SAL_CALL_NOLOCK(ret_stuff,
+ (u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
+ (u64) segment, (u64) bus_number, (u64) devfn,
+ (u64) pci_dev,
+ sn_irq_info, 0, 0);
+ return ret_stuff.v0;
+}
+
/*
* sn_fixup_ionodes() - This routine initializes the HUB data structure for
@@ -172,18 +191,40 @@ sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
}
/*
- * sn_more_slot_fixup() - We are not running with an ACPI capable PROM,
+ * sn_io_slot_fixup() - We are not running with an ACPI capable PROM,
* and need to convert the pci_dev->resource
* 'start' and 'end' addresses to mapped addresses,
* and setup the pci_controller->window array entries.
*/
void
-sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
+sn_io_slot_fixup(struct pci_dev *dev)
{
unsigned int count = 0;
int idx;
s64 pci_addrs[PCI_ROM_RESOURCE + 1];
unsigned long addr, end, size, start;
+ struct pcidev_info *pcidev_info;
+ struct sn_irq_info *sn_irq_info;
+ int status;
+
+ pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
+ if (!pcidev_info)
+ panic("%s: Unable to alloc memory for pcidev_info", __FUNCTION__);
+
+ sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
+ if (!sn_irq_info)
+ panic("%s: Unable to alloc memory for sn_irq_info", __FUNCTION__);
+
+ /* Call to retrieve pci device information needed by kernel. */
+ status = sal_get_pcidev_info((u64) pci_domain_nr(dev),
+ (u64) dev->bus->number,
+ dev->devfn,
+ (u64) __pa(pcidev_info),
+ (u64) __pa(sn_irq_info));
+
+ if (status)
+ BUG(); /* Cannot get platform pci device information */
+
/* Copy over PIO Mapped Addresses */
for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
@@ -219,8 +260,12 @@ sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
*/
if (count > 0)
sn_pci_window_fixup(dev, count, pci_addrs);
+
+ sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
}
+EXPORT_SYMBOL(sn_io_slot_fixup);
+
/*
* sn_pci_controller_fixup() - This routine sets up a bus's resources
* consistent with the Linux PCI abstraction layer.
@@ -272,9 +317,6 @@ sn_bus_fixup(struct pci_bus *bus)
{
struct pci_dev *pci_dev = NULL;
struct pcibus_bussoft *prom_bussoft_ptr;
- extern void sn_common_bus_fixup(struct pci_bus *,
- struct pcibus_bussoft *);
-
if (!bus->parent) { /* If root bus */
prom_bussoft_ptr = PCI_CONTROLLER(bus)->platform_data;
@@ -291,7 +333,7 @@ sn_bus_fixup(struct pci_bus *bus)
prom_bussoft_ptr->bs_legacy_mem);
}
list_for_each_entry(pci_dev, &bus->devices, bus_list) {
- sn_pci_fixup_slot(pci_dev);
+ sn_io_slot_fixup(pci_dev);
}
}
diff --git a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c
index 4aa4f301d56..ab7e2fd4079 100644
--- a/arch/ia64/sn/kernel/iomv.c
+++ b/arch/ia64/sn/kernel/iomv.c
@@ -1,4 +1,4 @@
-/*
+/*
* 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.
@@ -26,9 +26,10 @@
* @port: port to convert
*
* Legacy in/out instructions are converted to ld/st instructions
- * on IA64. This routine will convert a port number into a valid
+ * on IA64. This routine will convert a port number into a valid
* SN i/o address. Used by sn_in*() and sn_out*().
*/
+
void *sn_io_addr(unsigned long port)
{
if (!IS_RUNNING_ON_SIMULATOR()) {
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c
index b3a435fd70f..ea3dc38d73f 100644
--- a/arch/ia64/sn/kernel/msi_sn.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -59,13 +59,12 @@ void sn_teardown_msi_irq(unsigned int irq)
sn_intr_free(nasid, widget, sn_irq_info);
sn_msi_info[irq].sn_irq_info = NULL;
- return;
+ destroy_irq(irq);
}
-int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
{
struct msi_msg msg;
- struct msi_desc *entry;
int widget;
int status;
nasid_t nasid;
@@ -73,8 +72,8 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
struct sn_irq_info *sn_irq_info;
struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+ int irq;
- entry = get_irq_data(irq);
if (!entry->msi_attrib.is_64)
return -EINVAL;
@@ -84,6 +83,11 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
if (provider == NULL || provider->dma_map_consistent == NULL)
return -EINVAL;
+ irq = create_irq();
+ if (irq < 0)
+ return irq;
+
+ set_irq_msi(irq, entry);
/*
* Set up the vector plumbing. Let the prom (via sn_intr_alloc)
* decide which cpu to direct this msi at by default.
@@ -95,12 +99,15 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
SWIN_WIDGETNUM(bussoft->bs_base);
sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
- if (! sn_irq_info)
+ if (! sn_irq_info) {
+ destroy_irq(irq);
return -ENOMEM;
+ }
status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
if (status) {
kfree(sn_irq_info);
+ destroy_irq(irq);
return -ENOMEM;
}
@@ -121,6 +128,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
if (! bus_addr) {
sn_intr_free(nasid, widget, sn_irq_info);
kfree(sn_irq_info);
+ destroy_irq(irq);
return -ENOMEM;
}
@@ -139,7 +147,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
write_msi_msg(irq, &msg);
set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
- return 0;
+ return irq;
}
#ifdef CONFIG_SMP
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index a934ad06942..8571e52c2ef 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -580,7 +580,7 @@ void __cpuinit sn_cpu_init(void)
int slice;
int cnode;
int i;
- static int wars_have_been_checked;
+ static int wars_have_been_checked, set_cpu0_number;
cpuid = smp_processor_id();
if (cpuid == 0 && IS_MEDUSA()) {
@@ -605,8 +605,16 @@ void __cpuinit sn_cpu_init(void)
/*
* Don't check status. The SAL call is not supported on all PROMs
* but a failure is harmless.
+ * Architechtuallly, cpu_init is always called twice on cpu 0. We
+ * should set cpu_number on cpu 0 once.
*/
- (void) ia64_sn_set_cpu_number(cpuid);
+ if (cpuid == 0) {
+ if (!set_cpu0_number) {
+ (void) ia64_sn_set_cpu_number(cpuid);
+ set_cpu0_number = 1;
+ }
+ } else
+ (void) ia64_sn_set_cpu_number(cpuid);
/*
* The boot cpu makes this call again after platform initialization is
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
index 462ea178f49..33367996d72 100644
--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
@@ -189,7 +189,7 @@ static void print_pci_topology(struct seq_file *s)
int e;
for (sz = PAGE_SIZE; sz < 16 * PAGE_SIZE; sz += PAGE_SIZE) {
- if (!(p = (char *)kmalloc(sz, GFP_KERNEL)))
+ if (!(p = kmalloc(sz, GFP_KERNEL)))
break;
e = ia64_sn_ioif_get_pci_topology(__pa(p), sz);
if (e == SALRET_OK)
diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c
index 1f3540826e6..c08db9c2375 100644
--- a/arch/ia64/sn/kernel/xpc_channel.c
+++ b/arch/ia64/sn/kernel/xpc_channel.c
@@ -632,7 +632,7 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags)
ch->number, ch->partid);
spin_unlock_irqrestore(&ch->lock, *irq_flags);
- xpc_create_kthreads(ch, 1);
+ xpc_create_kthreads(ch, 1, 0);
spin_lock_irqsave(&ch->lock, *irq_flags);
}
@@ -754,12 +754,12 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags)
/* make sure all activity has settled down first */
- if (atomic_read(&ch->references) > 0 ||
- ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
- !(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE))) {
+ if (atomic_read(&ch->kthreads_assigned) > 0 ||
+ atomic_read(&ch->references) > 0) {
return;
}
- DBUG_ON(atomic_read(&ch->kthreads_assigned) != 0);
+ DBUG_ON((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
+ !(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE));
if (part->act_state == XPC_P_DEACTIVATING) {
/* can't proceed until the other side disengages from us */
@@ -1651,6 +1651,11 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch,
/* wake all idle kthreads so they can exit */
if (atomic_read(&ch->kthreads_idle) > 0) {
wake_up_all(&ch->idle_wq);
+
+ } else if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
+ !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
+ /* start a kthread that will do the xpcDisconnecting callout */
+ xpc_create_kthreads(ch, 1, 1);
}
/* wake those waiting to allocate an entry from the local msg queue */
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c
index fa96dfc0e1a..7a387d23736 100644
--- a/arch/ia64/sn/kernel/xpc_main.c
+++ b/arch/ia64/sn/kernel/xpc_main.c
@@ -681,7 +681,7 @@ xpc_activate_kthreads(struct xpc_channel *ch, int needed)
dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n",
needed, ch->partid, ch->number);
- xpc_create_kthreads(ch, needed);
+ xpc_create_kthreads(ch, needed, 0);
}
@@ -775,26 +775,28 @@ xpc_daemonize_kthread(void *args)
xpc_kthread_waitmsgs(part, ch);
}
- if (atomic_dec_return(&ch->kthreads_assigned) == 0) {
- spin_lock_irqsave(&ch->lock, irq_flags);
- if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
- !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
- ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
- spin_unlock_irqrestore(&ch->lock, irq_flags);
+ /* let registerer know that connection is disconnecting */
- xpc_disconnect_callout(ch, xpcDisconnecting);
-
- spin_lock_irqsave(&ch->lock, irq_flags);
- ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
- }
+ spin_lock_irqsave(&ch->lock, irq_flags);
+ if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
+ !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
+ ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+ xpc_disconnect_callout(ch, xpcDisconnecting);
+
+ spin_lock_irqsave(&ch->lock, irq_flags);
+ ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
+ }
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+ if (atomic_dec_return(&ch->kthreads_assigned) == 0) {
if (atomic_dec_return(&part->nchannels_engaged) == 0) {
xpc_mark_partition_disengaged(part);
xpc_IPI_send_disengage(part);
}
}
-
xpc_msgqueue_deref(ch);
dev_dbg(xpc_chan, "kthread exiting, partid=%d, channel=%d\n",
@@ -818,7 +820,8 @@ xpc_daemonize_kthread(void *args)
* partition.
*/
void
-xpc_create_kthreads(struct xpc_channel *ch, int needed)
+xpc_create_kthreads(struct xpc_channel *ch, int needed,
+ int ignore_disconnecting)
{
unsigned long irq_flags;
pid_t pid;
@@ -833,16 +836,38 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed)
* kthread. That kthread is responsible for doing the
* counterpart to the following before it exits.
*/
+ if (ignore_disconnecting) {
+ if (!atomic_inc_not_zero(&ch->kthreads_assigned)) {
+ /* kthreads assigned had gone to zero */
+ BUG_ON(!(ch->flags &
+ XPC_C_DISCONNECTINGCALLOUT_MADE));
+ break;
+ }
+
+ } else if (ch->flags & XPC_C_DISCONNECTING) {
+ break;
+
+ } else if (atomic_inc_return(&ch->kthreads_assigned) == 1) {
+ if (atomic_inc_return(&part->nchannels_engaged) == 1)
+ xpc_mark_partition_engaged(part);
+ }
(void) xpc_part_ref(part);
xpc_msgqueue_ref(ch);
- if (atomic_inc_return(&ch->kthreads_assigned) == 1 &&
- atomic_inc_return(&part->nchannels_engaged) == 1) {
- xpc_mark_partition_engaged(part);
- }
pid = kernel_thread(xpc_daemonize_kthread, (void *) args, 0);
if (pid < 0) {
/* the fork failed */
+
+ /*
+ * NOTE: if (ignore_disconnecting &&
+ * !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) is true,
+ * then we'll deadlock if all other kthreads assigned
+ * to this channel are blocked in the channel's
+ * registerer, because the only thing that will unblock
+ * them is the xpcDisconnecting callout that this
+ * failed kernel_thread would have made.
+ */
+
if (atomic_dec_return(&ch->kthreads_assigned) == 0 &&
atomic_dec_return(&part->nchannels_engaged) == 0) {
xpc_mark_partition_disengaged(part);
@@ -857,9 +882,6 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed)
* Flag this as an error only if we have an
* insufficient #of kthreads for the channel
* to function.
- *
- * No xpc_msgqueue_ref() is needed here since
- * the channel mgr is doing this.
*/
spin_lock_irqsave(&ch->lock, irq_flags);
XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources,
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index 6846dc9b432..04a8256017e 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -20,7 +20,8 @@
#include "xtalk/hubdev.h"
int
-sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp)
+sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp,
+ char **ssdt)
{
struct ia64_sal_retval ret_stuff;
u64 busnum;
@@ -32,7 +33,8 @@ sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp)
segment = soft->pbi_buscommon.bs_persist_segment;
busnum = soft->pbi_buscommon.bs_persist_busnum;
SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, segment,
- busnum, (u64) device, (u64) resp, 0, 0, 0);
+ busnum, (u64) device, (u64) resp, (u64)ia64_tpa(ssdt),
+ 0, 0);
return (int)ret_stuff.v0;
}
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index 41fd490af3b..f383dab973f 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -214,6 +214,14 @@ config RWSEM_XCHGADD_ALGORITHM
bool
default n
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
diff --git a/arch/m32r/boot/compressed/m32r_sio.c b/arch/m32r/boot/compressed/m32r_sio.c
index bce8af5e3bb..ee3c8be12fa 100644
--- a/arch/m32r/boot/compressed/m32r_sio.c
+++ b/arch/m32r/boot/compressed/m32r_sio.c
@@ -2,6 +2,7 @@
* arch/m32r/boot/compressed/m32r_sio.c
*
* 2003-02-12: Takeo Takahashi
+ * 2006-11-30: OPSPUT support by Kazuhiro Inaoka
*
*/
@@ -16,7 +17,7 @@ static int puts(const char *s)
return 0;
}
-#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT)
+#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT)
#include <asm/m32r.h>
#include <asm/io.h>
@@ -31,7 +32,11 @@ static int puts(const char *s)
#define BOOT_SIO0TXB (volatile unsigned short *)(0x02c00000 + 0x2000c)
#else
#undef PLD_BASE
+#if defined(CONFIG_PLAT_OPSPUT)
+#define PLD_BASE 0x1cc00000
+#else
#define PLD_BASE 0xa4c00000
+#endif
#define BOOT_SIO0STS PLD_ESIO0STS
#define BOOT_SIO0TXB PLD_ESIO0TXB
#endif
diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S
index ac6d840b382..a2c472c0549 100644
--- a/arch/m32r/kernel/entry.S
+++ b/arch/m32r/kernel/entry.S
@@ -23,35 +23,35 @@
* updated in fork.c:copy_thread, signal.c:do_signal,
* ptrace.c and ptrace.h
*
- * M32Rx/M32R2 M32R
- * @(sp) - r4 ditto
- * @(0x04,sp) - r5 ditto
- * @(0x08,sp) - r6 ditto
- * @(0x0c,sp) - *pt_regs ditto
- * @(0x10,sp) - r0 ditto
- * @(0x14,sp) - r1 ditto
- * @(0x18,sp) - r2 ditto
- * @(0x1c,sp) - r3 ditto
- * @(0x20,sp) - r7 ditto
- * @(0x24,sp) - r8 ditto
- * @(0x28,sp) - r9 ditto
- * @(0x2c,sp) - r10 ditto
- * @(0x30,sp) - r11 ditto
- * @(0x34,sp) - r12 ditto
- * @(0x38,sp) - syscall_nr ditto
- * @(0x3c,sp) - acc0h @(0x3c,sp) - acch
- * @(0x40,sp) - acc0l @(0x40,sp) - accl
- * @(0x44,sp) - acc1h @(0x44,sp) - dummy_acc1h
- * @(0x48,sp) - acc1l @(0x48,sp) - dummy_acc1l
- * @(0x4c,sp) - psw ditto
- * @(0x50,sp) - bpc ditto
- * @(0x54,sp) - bbpsw ditto
- * @(0x58,sp) - bbpc ditto
- * @(0x5c,sp) - spu (cr3) ditto
- * @(0x60,sp) - fp (r13) ditto
- * @(0x64,sp) - lr (r14) ditto
- * @(0x68,sp) - spi (cr2) ditto
- * @(0x6c,sp) - orig_r0 ditto
+ * M32R/M32Rx/M32R2
+ * @(sp) - r4
+ * @(0x04,sp) - r5
+ * @(0x08,sp) - r6
+ * @(0x0c,sp) - *pt_regs
+ * @(0x10,sp) - r0
+ * @(0x14,sp) - r1
+ * @(0x18,sp) - r2
+ * @(0x1c,sp) - r3
+ * @(0x20,sp) - r7
+ * @(0x24,sp) - r8
+ * @(0x28,sp) - r9
+ * @(0x2c,sp) - r10
+ * @(0x30,sp) - r11
+ * @(0x34,sp) - r12
+ * @(0x38,sp) - syscall_nr
+ * @(0x3c,sp) - acc0h
+ * @(0x40,sp) - acc0l
+ * @(0x44,sp) - acc1h ; ISA_DSP_LEVEL2 only
+ * @(0x48,sp) - acc1l ; ISA_DSP_LEVEL2 only
+ * @(0x4c,sp) - psw
+ * @(0x50,sp) - bpc
+ * @(0x54,sp) - bbpsw
+ * @(0x58,sp) - bbpc
+ * @(0x5c,sp) - spu (cr3)
+ * @(0x60,sp) - fp (r13)
+ * @(0x64,sp) - lr (r14)
+ * @(0x68,sp) - spi (cr2)
+ * @(0x6c,sp) - orig_r0
*/
#include <linux/linkage.h>
@@ -95,17 +95,10 @@
#define R11(reg) @(0x30,reg)
#define R12(reg) @(0x34,reg)
#define SYSCALL_NR(reg) @(0x38,reg)
-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
#define ACC0H(reg) @(0x3C,reg)
#define ACC0L(reg) @(0x40,reg)
#define ACC1H(reg) @(0x44,reg)
#define ACC1L(reg) @(0x48,reg)
-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
-#define ACCH(reg) @(0x3C,reg)
-#define ACCL(reg) @(0x40,reg)
-#else
-#error unknown isa configuration
-#endif
#define PSW(reg) @(0x4C,reg)
#define BPC(reg) @(0x50,reg)
#define BBPSW(reg) @(0x54,reg)
@@ -603,8 +596,6 @@ ENTRY(ace_handler)
beqz r1, inst
oprand:
ld r2, @(low(MDEVA_offset),r2) ; set address
- srli r2, #12
- slli r2, #12
srli r1, #1
bra 1f
inst:
diff --git a/arch/m32r/kernel/io_opsput.c b/arch/m32r/kernel/io_opsput.c
index da6c5f5c1f8..3cbb1f717e5 100644
--- a/arch/m32r/kernel/io_opsput.c
+++ b/arch/m32r/kernel/io_opsput.c
@@ -30,14 +30,34 @@ extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int);
extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */
-#define PORT2ADDR(port) _port2addr(port)
-#define PORT2ADDR_USB(port) _port2addr_usb(port)
+#define PORT2ADDR(port) _port2addr(port)
+#define PORT2ADDR_USB(port) _port2addr_usb(port)
static inline void *_port2addr(unsigned long port)
{
return (void *)(port | NONCACHE_OFFSET);
}
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+static inline void *__port2addr_ata(unsigned long port)
+{
+ static int dummy_reg;
+
+ switch (port) {
+ case 0x1f0: return (void *)(0x0c002000 | NONCACHE_OFFSET);
+ case 0x1f1: return (void *)(0x0c012800 | NONCACHE_OFFSET);
+ case 0x1f2: return (void *)(0x0c012002 | NONCACHE_OFFSET);
+ case 0x1f3: return (void *)(0x0c012802 | NONCACHE_OFFSET);
+ case 0x1f4: return (void *)(0x0c012004 | NONCACHE_OFFSET);
+ case 0x1f5: return (void *)(0x0c012804 | NONCACHE_OFFSET);
+ case 0x1f6: return (void *)(0x0c012006 | NONCACHE_OFFSET);
+ case 0x1f7: return (void *)(0x0c012806 | NONCACHE_OFFSET);
+ case 0x3f6: return (void *)(0x0c01200e | NONCACHE_OFFSET);
+ default: return (void *)&dummy_reg;
+ }
+}
+#endif
+
/*
* OPSPUT-LAN is located in the extended bus space
* from 0x10000000 to 0x13ffffff on physical address.
@@ -97,6 +117,12 @@ unsigned char _inb(unsigned long port)
{
if (port >= LAN_IOSTART && port < LAN_IOEND)
return _ne_inb(PORT2ADDR_NE(port));
+
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ return *(volatile unsigned char *)__port2addr_ata(port);
+ }
+#endif
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
unsigned char b;
@@ -112,6 +138,11 @@ unsigned short _inw(unsigned long port)
{
if (port >= LAN_IOSTART && port < LAN_IOEND)
return _ne_inw(PORT2ADDR_NE(port));
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ return *(volatile unsigned short *)__port2addr_ata(port);
+ }
+#endif
#if defined(CONFIG_USB)
else if(port >= 0x340 && port < 0x3a0)
return *(volatile unsigned short *)PORT2ADDR_USB(port);
@@ -164,6 +195,11 @@ void _outb(unsigned char b, unsigned long port)
if (port >= LAN_IOSTART && port < LAN_IOEND)
_ne_outb(b, PORT2ADDR_NE(port));
else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ *(volatile unsigned char *)__port2addr_ata(port) = b;
+ } else
+#endif
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
@@ -177,6 +213,11 @@ void _outw(unsigned short w, unsigned long port)
if (port >= LAN_IOSTART && port < LAN_IOEND)
_ne_outw(w, PORT2ADDR_NE(port));
else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ *(volatile unsigned short *)__port2addr_ata(port) = w;
+ } else
+#endif
#if defined(CONFIG_USB)
if(port >= 0x340 && port < 0x3a0)
*(volatile unsigned short *)PORT2ADDR_USB(port) = w;
@@ -222,6 +263,14 @@ void _insb(unsigned int port, void *addr, unsigned long count)
{
if (port >= LAN_IOSTART && port < LAN_IOEND)
_ne_insb(PORT2ADDR_NE(port), addr, count);
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ unsigned char *buf = addr;
+ unsigned char *portp = __port2addr_ata(port);
+ while (count--)
+ *buf++ = *(volatile unsigned char *)portp;
+ }
+#endif
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char),
@@ -254,6 +303,12 @@ void _insw(unsigned int port, void *addr, unsigned long count)
pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short),
count, 1);
#endif
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ portp = __port2addr_ata(port);
+ while (count--)
+ *buf++ = *(volatile unsigned short *)portp;
+#endif
} else {
portp = PORT2ADDR(port);
while (count--)
@@ -280,6 +335,12 @@ void _outsb(unsigned int port, const void *addr, unsigned long count)
portp = PORT2ADDR_NE(port);
while (count--)
_ne_outb(*buf++, portp);
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ portp = __port2addr_ata(port);
+ while (count--)
+ *(volatile unsigned char *)portp = *buf++;
+#endif
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char),
@@ -305,6 +366,12 @@ void _outsw(unsigned int port, const void *addr, unsigned long count)
portp = PORT2ADDR_NE(port);
while (count--)
*(volatile unsigned short *)portp = *buf++;
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ portp = __port2addr_ata(port);
+ while (count--)
+ *(volatile unsigned short *)portp = *buf++;
+#endif
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short),
diff --git a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c
index 61d3b01cbe0..62d6b71de45 100644
--- a/arch/m32r/kernel/setup_opsput.c
+++ b/arch/m32r/kernel/setup_opsput.c
@@ -218,13 +218,13 @@ static void shutdown_opsput_lanpld_irq(unsigned int irq)
static struct hw_interrupt_type opsput_lanpld_irq_type =
{
- "OPSPUT-PLD-LAN-IRQ",
- startup_opsput_lanpld_irq,
- shutdown_opsput_lanpld_irq,
- enable_opsput_lanpld_irq,
- disable_opsput_lanpld_irq,
- mask_and_ack_opsput_lanpld,
- end_opsput_lanpld_irq
+ .typename = "OPSPUT-PLD-LAN-IRQ",
+ .startup = startup_opsput_lanpld_irq,
+ .shutdown = shutdown_opsput_lanpld_irq,
+ .enable = enable_opsput_lanpld_irq,
+ .disable = disable_opsput_lanpld_irq,
+ .ack = mask_and_ack_opsput_lanpld,
+ .end = end_opsput_lanpld_irq
};
/*
@@ -374,7 +374,6 @@ void __init init_IRQ(void)
disable_opsput_pld_irq(PLD_IRQ_SIO0_SND);
#endif /* CONFIG_SERIAL_M32R_PLDSIO */
-#if defined(CONFIG_M32R_CFC)
/* INT#1: CFC IREQ on PLD */
irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
irq_desc[PLD_IRQ_CFIREQ].chip = &opsput_pld_irq_type;
@@ -398,8 +397,6 @@ void __init init_IRQ(void)
irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */
pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */
disable_opsput_pld_irq(PLD_IRQ_CFC_EJECT);
-#endif /* CONFIG_M32R_CFC */
-
/*
* INT0# is used for LAN, DIO
diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c
index fa786560949..48d376f47e1 100644
--- a/arch/m32r/kernel/smpboot.c
+++ b/arch/m32r/kernel/smpboot.c
@@ -351,7 +351,7 @@ static void __init do_boot_cpu(int phys_id)
}
}
-int __devinit __cpu_up(unsigned int cpu_id)
+int __cpuinit __cpu_up(unsigned int cpu_id)
{
int timeout;
diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c
index 8d5f551b575..9b9feb0f161 100644
--- a/arch/m32r/mm/fault.c
+++ b/arch/m32r/mm/fault.c
@@ -173,7 +173,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
-#if 0
+
if (error_code & ACE_USERMODE) {
/*
* accessing the stack below "spu" is always a bug.
@@ -184,7 +184,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
if (address + 4 < regs->spu)
goto bad_area;
}
-#endif
+
if (expand_stack(vma, address))
goto bad_area;
/*
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 7bc14461a6a..70a577c89c7 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -17,6 +17,14 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_HWEIGHT
bool
default y
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
index d64b5804e98..d01deb46ebb 100644
--- a/arch/m68k/atari/stdma.c
+++ b/arch/m68k/atari/stdma.c
@@ -174,7 +174,7 @@ int stdma_islocked(void)
void __init stdma_init(void)
{
stdma_isr = NULL;
- request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW,
+ request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW | SA_SHIRQ,
"ST-DMA: floppy/ACSI/IDE/Falcon-SCSI", stdma_int);
}
diff --git a/arch/m68k/kernel/sun3-head.S b/arch/m68k/kernel/sun3-head.S
index bffd69a4a1a..4b5f050204e 100644
--- a/arch/m68k/kernel/sun3-head.S
+++ b/arch/m68k/kernel/sun3-head.S
@@ -67,16 +67,6 @@ ENTRY(_start)
1: lea init_task,%curptr | get initial thread...
lea init_thread_union+THREAD_SIZE,%sp | ...and its stack.
-/* copy bootinfo records from the loader to _end */
- lea _end, %a1
- lea BI_START, %a0
- /* number of longs to copy */
- movel %a0@, %d0
-1: addl #4, %a0
- movel %a0@, %a1@
- addl #4, %a1
- dbf %d0, 1b
-
/* Point MSP at an invalid page to trap if it's used. --m */
movl #(PAGESIZE),%d0
movc %d0,%msp
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index 2550b4ae273..8c7eccbfc98 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -8,7 +8,7 @@ ENTRY(_start)
jiffies = jiffies_64 + 4;
SECTIONS
{
- . = 0xE004000;
+ . = 0xE002000;
_text = .; /* Text and read-only data */
.text : {
*(.head)
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index b54ef1726c5..46b7d6035aa 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -59,7 +59,7 @@ static struct vm_struct *get_io_area(unsigned long size)
unsigned long addr;
struct vm_struct **p, *tmp, *area;
- area = (struct vm_struct *)kmalloc(sizeof(*area), GFP_KERNEL);
+ area = kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return NULL;
addr = KMAP_START;
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index 0f88812822b..13c0b4ad01e 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -299,7 +299,7 @@ void cache_clear (unsigned long paddr, int len)
mach_l2_flush(0);
#endif
}
-EXPORT_SYMBOL(cache_clear); /* probably can be unexported */
+EXPORT_SYMBOL(cache_clear);
/*
@@ -352,7 +352,7 @@ void cache_push (unsigned long paddr, int len)
mach_l2_flush(1);
#endif
}
-EXPORT_SYMBOL(cache_push); /* probably can be unexported */
+EXPORT_SYMBOL(cache_push);
#ifndef CONFIG_SINGLE_MEMORY_CHUNK
int mm_end_of_chunk (unsigned long addr, int len)
diff --git a/arch/m68k/mm/sun3mmu.c b/arch/m68k/mm/sun3mmu.c
index ac6640ade0b..6a6513aa1ce 100644
--- a/arch/m68k/mm/sun3mmu.c
+++ b/arch/m68k/mm/sun3mmu.c
@@ -49,7 +49,6 @@ void __init paging_init(void)
unsigned long zones_size[MAX_NR_ZONES] = { 0, };
unsigned long size;
-
#ifdef TEST_VERIFY_AREA
wp_works_ok = 0;
#endif
@@ -94,7 +93,11 @@ void __init paging_init(void)
/* memory sizing is a hack stolen from motorola.c.. hope it works for us */
zones_size[ZONE_DMA] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
- free_area_init(zones_size);
+ /* I really wish I knew why the following change made things better... -- Sam */
+/* free_area_init(zones_size); */
+ free_area_init_node(0, NODE_DATA(0), zones_size,
+ (__pa(PAGE_OFFSET) >> PAGE_SHIFT) + 1, NULL);
+
}
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index aa70dde5422..25993c2a8fb 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -25,6 +25,14 @@ config RWSEM_XCHGADD_ALGORITHM
bool
default n
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c
index 9226264abf1..11ea217ed5c 100644
--- a/arch/m68knommu/kernel/time.c
+++ b/arch/m68knommu/kernel/time.c
@@ -23,6 +23,7 @@
#include <asm/machdep.h>
#include <asm/io.h>
+#include <asm/irq_regs.h>
#define TICK_SIZE (tick_nsec / 1000)
@@ -38,7 +39,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;
@@ -51,7 +52,7 @@ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
if (current->pid)
profile_tick(CPU_PROFILING);
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index 2b2a10da64a..bfade20a9e5 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -87,6 +87,16 @@ SECTIONS {
*(__ksymtab_gpl)
__stop___ksymtab_gpl = .;
+ /* Kernel symbol table: Normal unused symbols */
+ __start___ksymtab_unused = .;
+ *(__ksymtab_unused)
+ __stop___ksymtab_unused = .;
+
+ /* Kernel symbol table: GPL-only unused symbols */
+ __start___ksymtab_unused_gpl = .;
+ *(__ksymtab_unused_gpl)
+ __stop___ksymtab_unused_gpl = .;
+
/* Kernel symbol table: GPL-future symbols */
__start___ksymtab_gpl_future = .;
*(__ksymtab_gpl_future)
diff --git a/arch/m68knommu/platform/5206/config.c b/arch/m68knommu/platform/5206/config.c
index 34657f85e70..3343830aad1 100644
--- a/arch/m68knommu/platform/5206/config.c
+++ b/arch/m68knommu/platform/5206/config.c
@@ -26,7 +26,7 @@
/***************************************************************************/
void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
unsigned long coldfire_timer_offset(void);
void coldfire_trap_init(void);
void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c
index 48e4d626650..0f67320b403 100644
--- a/arch/m68knommu/platform/5206e/config.c
+++ b/arch/m68knommu/platform/5206e/config.c
@@ -25,7 +25,7 @@
/***************************************************************************/
void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
unsigned long coldfire_timer_offset(void);
void coldfire_trap_init(void);
void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/520x/config.c b/arch/m68knommu/platform/520x/config.c
index 823f561f35b..58b2878deb6 100644
--- a/arch/m68knommu/platform/520x/config.c
+++ b/arch/m68knommu/platform/520x/config.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/param.h>
+#include <linux/interrupt.h>
#include <asm/machdep.h>
#include <asm/dma.h>
@@ -27,7 +28,7 @@ unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
/***************************************************************************/
void coldfire_pit_tick(void);
-void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_pit_init(irq_handler_t handler);
unsigned long coldfire_pit_offset(void);
void coldfire_trap_init(void);
void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/523x/config.c b/arch/m68knommu/platform/523x/config.c
index 85de817e9ec..9b054e6caee 100644
--- a/arch/m68knommu/platform/523x/config.c
+++ b/arch/m68knommu/platform/523x/config.c
@@ -27,7 +27,7 @@
/***************************************************************************/
void coldfire_pit_tick(void);
-void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_pit_init(irq_handler_t handler);
unsigned long coldfire_pit_offset(void);
void coldfire_trap_init(void);
void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5249/config.c b/arch/m68knommu/platform/5249/config.c
index 9d19d5bdb8a..d6706079d64 100644
--- a/arch/m68knommu/platform/5249/config.c
+++ b/arch/m68knommu/platform/5249/config.c
@@ -12,6 +12,7 @@
#include <linux/sched.h>
#include <linux/param.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/traps.h>
@@ -24,7 +25,7 @@
/***************************************************************************/
void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
unsigned long coldfire_timer_offset(void);
void coldfire_trap_init(void);
void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c
index d500e27eda5..6b437cc9777 100644
--- a/arch/m68knommu/platform/5272/config.c
+++ b/arch/m68knommu/platform/5272/config.c
@@ -26,7 +26,7 @@
/***************************************************************************/
void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
unsigned long coldfire_timer_offset(void);
void coldfire_trap_init(void);
void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/527x/config.c b/arch/m68knommu/platform/527x/config.c
index bbae5159745..28e7d964eef 100644
--- a/arch/m68knommu/platform/527x/config.c
+++ b/arch/m68knommu/platform/527x/config.c
@@ -27,7 +27,7 @@
/***************************************************************************/
void coldfire_pit_tick(void);
-void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_pit_init(irq_handler_t handler);
unsigned long coldfire_pit_offset(void);
void coldfire_trap_init(void);
void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/528x/config.c b/arch/m68knommu/platform/528x/config.c
index 18dad904614..805b4f74ff1 100644
--- a/arch/m68knommu/platform/528x/config.c
+++ b/arch/m68knommu/platform/528x/config.c
@@ -27,7 +27,7 @@
/***************************************************************************/
void coldfire_pit_tick(void);
-void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_pit_init(irq_handler_t handler);
unsigned long coldfire_pit_offset(void);
void coldfire_trap_init(void);
void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5307/config.c b/arch/m68knommu/platform/5307/config.c
index 8074ac56f47..e04b84deb57 100644
--- a/arch/m68knommu/platform/5307/config.c
+++ b/arch/m68knommu/platform/5307/config.c
@@ -27,7 +27,7 @@
/***************************************************************************/
void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
unsigned long coldfire_timer_offset(void);
void coldfire_trap_init(void);
void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5307/pit.c b/arch/m68knommu/platform/5307/pit.c
index 9dc5688f71b..aa15beeb36c 100644
--- a/arch/m68knommu/platform/5307/pit.c
+++ b/arch/m68knommu/platform/5307/pit.c
@@ -43,7 +43,7 @@ void coldfire_pit_tick(void)
/***************************************************************************/
-void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *))
+void coldfire_pit_init(irq_handler_t handler)
{
volatile unsigned char *icrp;
volatile unsigned long *imrp;
diff --git a/arch/m68knommu/platform/5307/timers.c b/arch/m68knommu/platform/5307/timers.c
index e5668af1978..87b112b363a 100644
--- a/arch/m68knommu/platform/5307/timers.c
+++ b/arch/m68knommu/platform/5307/timers.c
@@ -62,7 +62,7 @@ void coldfire_tick(void)
/***************************************************************************/
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *))
+void coldfire_timer_init(irq_handler_t handler)
{
__raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
__raw_writetrr(((MCF_BUSCLK / 16) / HZ), TA(MCFTIMER_TRR));
@@ -111,12 +111,13 @@ unsigned long coldfire_timer_offset(void)
/*
* Use the other timer to provide high accuracy profiling info.
*/
-void coldfire_profile_tick(int irq, void *dummy, struct pt_regs *regs)
+irqreturn_t coldfire_profile_tick(int irq, void *dummy)
{
/* Reset ColdFire timer2 */
__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));
if (current->pid)
profile_tick(CPU_PROFILING, regs);
+ return IRQ_HANDLED;
}
/***************************************************************************/
diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c
index c7d6ad51382..664c3a12b0c 100644
--- a/arch/m68knommu/platform/532x/config.c
+++ b/arch/m68knommu/platform/532x/config.c
@@ -35,7 +35,7 @@
/***************************************************************************/
void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
unsigned long coldfire_timer_offset(void);
void coldfire_trap_init(void);
void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/5407/config.c b/arch/m68knommu/platform/5407/config.c
index 5aad2645f0f..036f6287624 100644
--- a/arch/m68knommu/platform/5407/config.c
+++ b/arch/m68knommu/platform/5407/config.c
@@ -26,7 +26,7 @@
/***************************************************************************/
void coldfire_tick(void);
-void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void coldfire_timer_init(irq_handler_t handler);
unsigned long coldfire_timer_offset(void);
void coldfire_trap_init(void);
void coldfire_reset(void);
diff --git a/arch/m68knommu/platform/68328/config.c b/arch/m68knommu/platform/68328/config.c
index 26ffeba2864..e5c537d14df 100644
--- a/arch/m68knommu/platform/68328/config.c
+++ b/arch/m68knommu/platform/68328/config.c
@@ -34,7 +34,7 @@
/***************************************************************************/
-void m68328_timer_init(irqreturn_t (*timer_routine) (int, void *, struct pt_regs *));
+void m68328_timer_init(irq_handler_t timer_routine);
void m68328_timer_tick(void);
unsigned long m68328_timer_gettimeoffset(void);
void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index d8af858fe3f..9d839a9c4b1 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -165,6 +165,7 @@ config MIPS_COBALT
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
select SYS_SUPPORTS_LITTLE_ENDIAN
+ select GENERIC_HARDIRQS_NO__DO_IRQ
config MACH_DECSTATION
bool "DECstations"
@@ -225,6 +226,7 @@ config MACH_JAZZ
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
select SYS_SUPPORTS_100HZ
+ select GENERIC_HARDIRQS_NO__DO_IRQ
help
This a family of machines based on the MIPS R4030 chipset which was
used by several vendors to build RISC/os and Windows NT workstations.
@@ -459,6 +461,11 @@ config PNX8550_JBS
select PNX8550
select SYS_SUPPORTS_LITTLE_ENDIAN
+config PNX8550_STB810
+ bool "Support for Philips PNX8550 based STB810 board"
+ select PNX8550
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
config DDB5477
bool "NEC DDB Vrc-5477"
select DDB5XXX_COMMON
@@ -482,6 +489,7 @@ config MACH_VR41XX
select SYS_HAS_CPU_VR41XX
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+ select GENERIC_HARDIRQS_NO__DO_IRQ
config PMC_YOSEMITE
bool "PMC-Sierra Yosemite eval board"
@@ -515,6 +523,7 @@ config QEMU
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_LITTLE_ENDIAN
select ARCH_SPARSEMEM_ENABLE
+ select GENERIC_HARDIRQS_NO__DO_IRQ
help
Qemu is a software emulator which among other architectures also
can simulate a MIPS32 4Kc system. This patch adds support for the
@@ -566,6 +575,7 @@ config SGI_IP27
select DMA_IP27
select EARLY_PRINTK
select HW_HAS_PCI
+ select NR_CPUS_DEFAULT_64
select PCI_DOMAINS
select SYS_HAS_CPU_R10000
select SYS_SUPPORTS_64BIT_KERNEL
@@ -603,6 +613,7 @@ config SIBYTE_BIGSUR
bool "Sibyte BCM91480B-BigSur"
select BOOT_ELF32
select DMA_COHERENT
+ select NR_CPUS_DEFAULT_4
select PCI_DOMAINS
select SIBYTE_BCM1x80
select SWAP_IO_SPACE
@@ -614,6 +625,7 @@ config SIBYTE_SWARM
bool "Sibyte BCM91250A-SWARM"
select BOOT_ELF32
select DMA_COHERENT
+ select NR_CPUS_DEFAULT_2
select SIBYTE_SB1250
select SWAP_IO_SPACE
select SYS_HAS_CPU_SB1
@@ -626,6 +638,7 @@ config SIBYTE_SENTOSA
depends on EXPERIMENTAL
select BOOT_ELF32
select DMA_COHERENT
+ select NR_CPUS_DEFAULT_2
select SIBYTE_SB1250
select SWAP_IO_SPACE
select SYS_HAS_CPU_SB1
@@ -659,6 +672,7 @@ config SIBYTE_PTSWARM
depends on EXPERIMENTAL
select BOOT_ELF32
select DMA_COHERENT
+ select NR_CPUS_DEFAULT_2
select SIBYTE_SB1250
select SWAP_IO_SPACE
select SYS_HAS_CPU_SB1
@@ -671,6 +685,7 @@ config SIBYTE_LITTLESUR
depends on EXPERIMENTAL
select BOOT_ELF32
select DMA_COHERENT
+ select NR_CPUS_DEFAULT_2
select SIBYTE_SB1250
select SWAP_IO_SPACE
select SYS_HAS_CPU_SB1
@@ -701,8 +716,8 @@ config SIBYTE_CRHONE
select SYS_SUPPORTS_HIGHMEM
select SYS_SUPPORTS_LITTLE_ENDIAN
-config SNI_RM200_PCI
- bool "SNI RM200 PCI"
+config SNI_RM
+ bool "SNI RM200/300/400"
select ARC if CPU_LITTLE_ENDIAN
select ARC32 if CPU_LITTLE_ENDIAN
select ARCH_MAY_HAVE_PC_FDC
@@ -725,8 +740,8 @@ config SNI_RM200_PCI
select SYS_SUPPORTS_HIGHMEM
select SYS_SUPPORTS_LITTLE_ENDIAN
help
- The SNI RM200 PCI was a MIPS-based platform manufactured by Siemens
- Nixdorf Informationssysteme (SNI), parent company of Pyramid
+ The SNI RM200/300/400 are MIPS-based machines manufactured by
+ Siemens Nixdorf Informationssysteme (SNI), parent company of Pyramid
Technology and now in turn merged with Fujitsu. Say Y here to
support this machine type.
@@ -754,6 +769,7 @@ config TOSHIBA_RBTX4927
select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_BIG_ENDIAN
select TOSHIBA_BOARDS
+ select GENERIC_HARDIRQS_NO__DO_IRQ
help
This Toshiba board is based on the TX4927 processor. Say Y here to
support this machine type
@@ -773,29 +789,13 @@ config TOSHIBA_RBTX4938
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_BIG_ENDIAN
select TOSHIBA_BOARDS
+ select GENERIC_HARDIRQS_NO__DO_IRQ
help
This Toshiba board is based on the TX4938 processor. Say Y here to
support this machine type
endchoice
-config KEXEC
- bool "Kexec system call (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- help
- kexec is a system call that implements the ability to shutdown your
- current kernel, and to start another kernel. It is like a reboot
- but it is indepedent of the system firmware. And like a reboot
- you can start any kernel with it, not just Linux.
-
- The name comes from the similiarity to the exec system call.
-
- It is an ongoing process to be certain the hardware in a machine
- is properly shutdown, so do not be surprised if this code does not
- initially work for you. It may help to enable device hotplugging
- support. As of this writing the exact hardware interface is
- strongly in flux, so no good recommendation can be made.
-
source "arch/mips/ddb5xxx/Kconfig"
source "arch/mips/gt64120/ev64120/Kconfig"
source "arch/mips/jazz/Kconfig"
@@ -819,6 +819,14 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
@@ -926,6 +934,9 @@ config CPU_LITTLE_ENDIAN
endchoice
+config SYS_SUPPORTS_APM_EMULATION
+ bool
+
config SYS_SUPPORTS_BIG_ENDIAN
bool
@@ -993,6 +1004,7 @@ config SOC_AU1X00
bool
select SYS_HAS_CPU_MIPS32_R1
select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_APM_EMULATION
config PNX8550
bool
@@ -1062,16 +1074,16 @@ config HAVE_STD_PC_SERIAL_PORT
config ARC_CONSOLE
bool "ARC console support"
- depends on SGI_IP22 || SNI_RM200_PCI
+ depends on SGI_IP22 || SNI_RM
config ARC_MEMORY
bool
- depends on MACH_JAZZ || SNI_RM200_PCI || SGI_IP32
+ depends on MACH_JAZZ || SNI_RM || SGI_IP32
default y
config ARC_PROMLIB
bool
- depends on MACH_JAZZ || SNI_RM200_PCI || SGI_IP22 || SGI_IP32
+ depends on MACH_JAZZ || SNI_RM || SGI_IP22 || SGI_IP32
default y
config ARC64
@@ -1522,6 +1534,8 @@ config MIPS_MT_SMTC
select CPU_MIPSR2_IRQ_VI
select CPU_MIPSR2_SRS
select MIPS_MT
+ select NR_CPUS_DEFAULT_2
+ select NR_CPUS_DEFAULT_8
select SMP
select SYS_SUPPORTS_SMP
help
@@ -1549,6 +1563,20 @@ config MIPS_MT_FPAFF
depends on MIPS_MT
default y
+config MIPS_MT_SMTC_INSTANT_REPLAY
+ bool "Low-latency Dispatch of Deferred SMTC IPIs"
+ depends on MIPS_MT_SMTC
+ default y
+ help
+ SMTC pseudo-interrupts between TCs are deferred and queued
+ if the target TC is interrupt-inhibited (IXMT). In the first
+ SMTC prototypes, these queued IPIs were serviced on return
+ to user mode, or on entry into the kernel idle loop. The
+ INSTANT_REPLAY option dispatches them as part of local_irq_restore()
+ processing, which adds runtime overhead (hence the option to turn
+ it off), but ensures that IPIs are handled promptly even under
+ heavy I/O interrupt load.
+
config MIPS_VPE_LOADER_TOM
bool "Load VPE program into memory hidden from linux"
depends on MIPS_VPE_LOADER
@@ -1723,13 +1751,34 @@ config SMP
config SYS_SUPPORTS_SMP
bool
+config NR_CPUS_DEFAULT_2
+ bool
+
+config NR_CPUS_DEFAULT_4
+ bool
+
+config NR_CPUS_DEFAULT_8
+ bool
+
+config NR_CPUS_DEFAULT_16
+ bool
+
+config NR_CPUS_DEFAULT_32
+ bool
+
+config NR_CPUS_DEFAULT_64
+ bool
+
config NR_CPUS
int "Maximum number of CPUs (2-64)"
range 2 64
depends on SMP
- default "64" if SGI_IP27
- default "2"
- default "8" if MIPS_MT_SMTC
+ default "2" if NR_CPUS_DEFAULT_2
+ default "4" if NR_CPUS_DEFAULT_4
+ default "8" if NR_CPUS_DEFAULT_8
+ default "16" if NR_CPUS_DEFAULT_16
+ default "32" if NR_CPUS_DEFAULT_32
+ default "64" if NR_CPUS_DEFAULT_64
help
This allows you to specify the maximum number of CPUs which this
kernel will support. The maximum supported value is 32 for 32-bit
@@ -1826,6 +1875,40 @@ config MIPS_INSANE_LARGE
This will result in additional memory usage, so it is not
recommended for normal users.
+config KEXEC
+ bool "Kexec system call (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ kexec is a system call that implements the ability to shutdown your
+ current kernel, and to start another kernel. It is like a reboot
+ but it is indepedent of the system firmware. And like a reboot
+ you can start any kernel with it, not just Linux.
+
+ The name comes from the similiarity to the exec system call.
+
+ It is an ongoing process to be certain the hardware in a machine
+ is properly shutdown, so do not be surprised if this code does not
+ initially work for you. It may help to enable device hotplugging
+ support. As of this writing the exact hardware interface is
+ strongly in flux, so no good recommendation can be made.
+
+config SECCOMP
+ bool "Enable seccomp to safely compute untrusted bytecode"
+ depends on PROC_FS && BROKEN
+ default y
+ help
+ This kernel feature is useful for number crunching applications
+ that may need to compute untrusted bytecode during their
+ execution. By using pipes or other transports made available to
+ the process as file descriptors supporting the read/write
+ syscalls, it's possible to isolate those applications in
+ their own address space using seccomp. Once seccomp is
+ enabled via /proc/<pid>/seccomp, it cannot be disabled
+ and the task is only allowed to execute a few safe syscalls
+ defined by each seccomp mode.
+
+ If unsure, say Y. Only embedded should say N here.
+
endmenu
config RWSEM_GENERIC_SPINLOCK
@@ -1992,52 +2075,11 @@ config BINFMT_ELF32
bool
default y if MIPS32_O32 || MIPS32_N32
-config SECCOMP
- bool "Enable seccomp to safely compute untrusted bytecode"
- depends on PROC_FS && BROKEN
- default y
- help
- This kernel feature is useful for number crunching applications
- that may need to compute untrusted bytecode during their
- execution. By using pipes or other transports made available to
- the process as file descriptors supporting the read/write
- syscalls, it's possible to isolate those applications in
- their own address space using seccomp. Once seccomp is
- enabled via /proc/<pid>/seccomp, it cannot be disabled
- and the task is only allowed to execute a few safe syscalls
- defined by each seccomp mode.
+endmenu
- If unsure, say Y. Only embedded should say N here.
+menu "Power management options"
-config PM
- bool "Power Management support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && SOC_AU1X00
-
-config APM
- tristate "Advanced Power Management Emulation"
- depends on PM
- ---help---
- APM is a BIOS specification for saving power using several different
- techniques. This is mostly useful for battery powered systems with
- APM compliant BIOSes. If you say Y here, the system time will be
- reset after a RESUME operation, the /proc/apm device will provide
- battery status information, and user-space programs will receive
- notification of APM "events" (e.g. battery status change).
-
- In order to use APM, you will need supporting software. For location
- and more information, read <file:Documentation/pm.txt> and the
- Battery Powered Linux mini-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- This driver does not spin down disk drives (see the hdparm(8)
- manpage ("man 8 hdparm") for that), and it doesn't turn off
- VESA-compliant "green" monitors.
-
- Generally, if you don't have a battery in your machine, there isn't
- much point in using this driver and you should say N. If you get
- random kernel OOPSes or reboots that don't seem to be related to
- anything, try disabling/enabling this option (or disabling/enabling
- APM in your BIOS).
+source "kernel/power/Kconfig"
endmenu
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index 5d6afb52d90..9351f1c04a9 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -22,10 +22,10 @@ config CMDLINE
string "Default kernel command string"
default ""
help
- On some platforms, there is currently no way for the boot loader to
- pass arguments to the kernel. For these platforms, you can supply
- some command-line options at build time by entering them here. In
- other cases you can specify kernel args so that you don't have
+ On some platforms, there is currently no way for the boot loader to
+ pass arguments to the kernel. For these platforms, you can supply
+ some command-line options at build time by entering them here. In
+ other cases you can specify kernel args so that you don't have
to set them up in board prom initialization routines.
config DEBUG_STACK_USAGE
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 641aa30b363..c68b5d3e5d1 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -463,6 +463,11 @@ libs-$(CONFIG_PNX8550_JBS) += arch/mips/philips/pnx8550/jbs/
#cflags-$(CONFIG_PNX8550_JBS) += -Iinclude/asm-mips/mach-pnx8550
load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000
+# Philips PNX8550 STB810 board
+#
+libs-$(CONFIG_PNX8550_STB810) += arch/mips/philips/pnx8550/stb810/
+load-$(CONFIG_PNX8550_STB810) += 0xffffffff80060000
+
# NEC EMMA2RH boards
#
core-$(CONFIG_EMMA2RH) += arch/mips/emma2rh/common/
@@ -569,11 +574,11 @@ libs-$(CONFIG_SIBYTE_BIGSUR) += arch/mips/sibyte/swarm/
load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000
#
-# SNI RM200 PCI
+# SNI RM
#
-core-$(CONFIG_SNI_RM200_PCI) += arch/mips/sni/
-cflags-$(CONFIG_SNI_RM200_PCI) += -Iinclude/asm-mips/mach-rm200
-load-$(CONFIG_SNI_RM200_PCI) += 0xffffffff80600000
+core-$(CONFIG_SNI_RM) += arch/mips/sni/
+cflags-$(CONFIG_SNI_RM) += -Iinclude/asm-mips/mach-rm
+load-$(CONFIG_SNI_RM) += 0xffffffff80600000
#
# Toshiba JMR-TX3927 board
@@ -618,7 +623,7 @@ LDFLAGS += -m $(ld-emul)
ifdef CONFIG_MIPS
CHECKFLAGS += $(shell $(CC) $(CFLAGS) -dM -E -xc /dev/null | \
- egrep -vw '__GNUC_(MAJOR|MINOR|PATCHLEVEL)__' | \
+ egrep -vw '__GNUC_(|MINOR_|PATCHLEVEL_)_' | \
sed -e 's/^\#define /-D/' -e "s/ /='/" -e "s/$$/'/")
ifdef CONFIG_64BIT
CHECKFLAGS += -m64
@@ -695,7 +700,7 @@ ifdef CONFIG_QEMU
all: vmlinux.bin
endif
-ifdef CONFIG_SNI_RM200_PCI
+ifdef CONFIG_SNI_RM
all: vmlinux.ecoff
endif
diff --git a/arch/mips/arc/identify.c b/arch/mips/arc/identify.c
index 3ba7c47f9f2..4b907369b0f 100644
--- a/arch/mips/arc/identify.c
+++ b/arch/mips/arc/identify.c
@@ -77,7 +77,7 @@ static struct smatch * __init string_to_mach(const char *s)
{
int i;
- for (i = 0; i < (sizeof(mach_table) / sizeof (mach_table[0])); i++) {
+ for (i = 0; i < ARRAY_SIZE(mach_table); i++) {
if (!strcmp(s, mach_table[i].arcname))
return &mach_table[i];
}
diff --git a/arch/mips/arc/memory.c b/arch/mips/arc/memory.c
index 8a9ef58cc39..456cb81a32d 100644
--- a/arch/mips/arc/memory.c
+++ b/arch/mips/arc/memory.c
@@ -141,30 +141,20 @@ void __init prom_meminit(void)
}
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- unsigned long freed = 0;
unsigned long addr;
int i;
if (prom_flags & PROM_FLAG_DONT_FREE_TEMP)
- return 0;
+ return;
for (i = 0; i < boot_mem_map.nr_map; i++) {
if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
continue;
addr = boot_mem_map.map[i].addr;
- while (addr < boot_mem_map.map[i].addr
- + boot_mem_map.map[i].size) {
- ClearPageReserved(virt_to_page(__va(addr)));
- init_page_count(virt_to_page(__va(addr)));
- free_page((unsigned long)__va(addr));
- addr += PAGE_SIZE;
- freed += PAGE_SIZE;
- }
+ free_init_pages("prom memory",
+ addr, addr + boot_mem_map.map[i].size);
}
- printk(KERN_INFO "Freeing prom memory: %ldkb freed\n", freed >> 10);
-
- return freed;
}
diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
index 9cf7b671583..ea6e99fbe2f 100644
--- a/arch/mips/au1000/common/irq.c
+++ b/arch/mips/au1000/common/irq.c
@@ -233,7 +233,7 @@ void restore_local_and_enable(int controller, unsigned long mask)
static struct irq_chip rise_edge_irq_type = {
- .typename = "Au1000 Rise Edge",
+ .name = "Au1000 Rise Edge",
.ack = mask_and_ack_rise_edge_irq,
.mask = local_disable_irq,
.mask_ack = mask_and_ack_rise_edge_irq,
@@ -242,7 +242,7 @@ static struct irq_chip rise_edge_irq_type = {
};
static struct irq_chip fall_edge_irq_type = {
- .typename = "Au1000 Fall Edge",
+ .name = "Au1000 Fall Edge",
.ack = mask_and_ack_fall_edge_irq,
.mask = local_disable_irq,
.mask_ack = mask_and_ack_fall_edge_irq,
@@ -251,7 +251,7 @@ static struct irq_chip fall_edge_irq_type = {
};
static struct irq_chip either_edge_irq_type = {
- .typename = "Au1000 Rise or Fall Edge",
+ .name = "Au1000 Rise or Fall Edge",
.ack = mask_and_ack_either_edge_irq,
.mask = local_disable_irq,
.mask_ack = mask_and_ack_either_edge_irq,
@@ -260,7 +260,7 @@ static struct irq_chip either_edge_irq_type = {
};
static struct irq_chip level_irq_type = {
- .typename = "Au1000 Level",
+ .name = "Au1000 Level",
.ack = mask_and_ack_level_irq,
.mask = local_disable_irq,
.mask_ack = mask_and_ack_level_irq,
diff --git a/arch/mips/au1000/common/pci.c b/arch/mips/au1000/common/pci.c
index da591f67489..6c25e6c09f7 100644
--- a/arch/mips/au1000/common/pci.c
+++ b/arch/mips/au1000/common/pci.c
@@ -39,15 +39,15 @@
/* TBD */
static struct resource pci_io_resource = {
- .start = PCI_IO_START,
- .end = PCI_IO_END,
+ .start = (resource_size_t)PCI_IO_START,
+ .end = (resource_size_t)PCI_IO_END,
.name = "PCI IO space",
.flags = IORESOURCE_IO
};
static struct resource pci_mem_resource = {
- .start = PCI_MEM_START,
- .end = PCI_MEM_END,
+ .start = (resource_size_t)PCI_MEM_START,
+ .end = (resource_size_t)PCI_MEM_END,
.name = "PCI memory space",
.flags = IORESOURCE_MEM
};
@@ -76,13 +76,17 @@ static int __init au1x_pci_setup(void)
}
#ifdef CONFIG_DMA_NONCOHERENT
- /*
- * Set the NC bit in controller for Au1500 pre-AC silicon
- */
- u32 prid = read_c0_prid();
- if ( (prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) {
- au_writel( 1<<16 | au_readl(Au1500_PCI_CFG), Au1500_PCI_CFG);
- printk("Non-coherent PCI accesses enabled\n");
+ {
+ /*
+ * Set the NC bit in controller for Au1500 pre-AC silicon
+ */
+ u32 prid = read_c0_prid();
+
+ if ((prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) {
+ au_writel((1 << 16) | au_readl(Au1500_PCI_CFG),
+ Au1500_PCI_CFG);
+ printk("Non-coherent PCI accesses enabled\n");
+ }
}
#endif
diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/au1000/common/prom.c
index 6fce60af005..a8637cdb5b4 100644
--- a/arch/mips/au1000/common/prom.c
+++ b/arch/mips/au1000/common/prom.c
@@ -149,9 +149,8 @@ int get_ethernet_addr(char *ethernet_addr)
return 0;
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
EXPORT_SYMBOL(prom_getcmdline);
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index 919172db560..13fe187f35d 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -141,17 +141,20 @@ void __init plat_mem_setup(void)
/* This routine should be valid for all Au1x based boards */
phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size)
{
- u32 start, end;
-
/* Don't fixup 36 bit addresses */
- if ((phys_addr >> 32) != 0) return phys_addr;
+ if ((phys_addr >> 32) != 0)
+ return phys_addr;
#ifdef CONFIG_PCI
- start = (u32)Au1500_PCI_MEM_START;
- end = (u32)Au1500_PCI_MEM_END;
- /* check for pci memory window */
- if ((phys_addr >= start) && ((phys_addr + size) < end)) {
- return (phys_t)((phys_addr - start) + Au1500_PCI_MEM_START);
+ {
+ u32 start, end;
+
+ start = (u32)Au1500_PCI_MEM_START;
+ end = (u32)Au1500_PCI_MEM_END;
+ /* check for pci memory window */
+ if ((phys_addr >= start) && ((phys_addr + size) < end))
+ return (phys_t)
+ ((phys_addr - start) + Au1500_PCI_MEM_START);
}
#endif
diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c
index 2d1533f116c..6bc1f8e1b60 100644
--- a/arch/mips/au1000/pb1100/board_setup.c
+++ b/arch/mips/au1000/pb1100/board_setup.c
@@ -47,8 +47,7 @@ void board_reset (void)
void __init board_setup(void)
{
- u32 pin_func;
- u32 sys_freqctrl, sys_clksrc;
+ volatile void __iomem * base = (volatile void __iomem *) 0xac000000UL;
// set AUX clock to 12MHz * 8 = 96 MHz
au_writel(8, SYS_AUXPLL);
@@ -56,58 +55,62 @@ void __init board_setup(void)
udelay(100);
#ifdef CONFIG_USB_OHCI
- // configure pins GPIO[14:9] as GPIO
- pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80);
-
- /* zero and disable FREQ2 */
- sys_freqctrl = au_readl(SYS_FREQCTRL0);
- sys_freqctrl &= ~0xFFF00000;
- au_writel(sys_freqctrl, SYS_FREQCTRL0);
-
- /* zero and disable USBH/USBD/IrDA clock */
- sys_clksrc = au_readl(SYS_CLKSRC);
- sys_clksrc &= ~0x0000001F;
- au_writel(sys_clksrc, SYS_CLKSRC);
-
- sys_freqctrl = au_readl(SYS_FREQCTRL0);
- sys_freqctrl &= ~0xFFF00000;
-
- sys_clksrc = au_readl(SYS_CLKSRC);
- sys_clksrc &= ~0x0000001F;
-
- // FREQ2 = aux/2 = 48 MHz
- sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
- au_writel(sys_freqctrl, SYS_FREQCTRL0);
-
- /*
- * Route 48MHz FREQ2 into USBH/USBD/IrDA
- */
- sys_clksrc |= ((4<<2) | (0<<1) | 0 );
- au_writel(sys_clksrc, SYS_CLKSRC);
-
- /* setup the static bus controller */
- au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */
- au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
- au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
-
- // get USB Functionality pin state (device vs host drive pins)
- pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
- // 2nd USB port is USB host
- pin_func |= 0x8000;
- au_writel(pin_func, SYS_PINFUNC);
+ {
+ u32 pin_func, sys_freqctrl, sys_clksrc;
+
+ // configure pins GPIO[14:9] as GPIO
+ pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80);
+
+ /* zero and disable FREQ2 */
+ sys_freqctrl = au_readl(SYS_FREQCTRL0);
+ sys_freqctrl &= ~0xFFF00000;
+ au_writel(sys_freqctrl, SYS_FREQCTRL0);
+
+ /* zero and disable USBH/USBD/IrDA clock */
+ sys_clksrc = au_readl(SYS_CLKSRC);
+ sys_clksrc &= ~0x0000001F;
+ au_writel(sys_clksrc, SYS_CLKSRC);
+
+ sys_freqctrl = au_readl(SYS_FREQCTRL0);
+ sys_freqctrl &= ~0xFFF00000;
+
+ sys_clksrc = au_readl(SYS_CLKSRC);
+ sys_clksrc &= ~0x0000001F;
+
+ // FREQ2 = aux/2 = 48 MHz
+ sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
+ au_writel(sys_freqctrl, SYS_FREQCTRL0);
+
+ /*
+ * Route 48MHz FREQ2 into USBH/USBD/IrDA
+ */
+ sys_clksrc |= ((4<<2) | (0<<1) | 0 );
+ au_writel(sys_clksrc, SYS_CLKSRC);
+
+ /* setup the static bus controller */
+ au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */
+ au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
+ au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
+
+ // get USB Functionality pin state (device vs host drive pins)
+ pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
+ // 2nd USB port is USB host
+ pin_func |= 0x8000;
+ au_writel(pin_func, SYS_PINFUNC);
+ }
#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);
// Enable the RTC if not already enabled
- if (!(readb(0xac000028) & 0x20)) {
- writeb(readb(0xac000028) | 0x20, 0xac000028);
+ if (!(readb(base + 0x28) & 0x20)) {
+ writeb(readb(base + 0x28) | 0x20, base + 0x28);
au_sync();
}
// Put the clock in BCD mode
- if (readb(0xac00002C) & 0x4) { /* reg B */
- writeb(readb(0xac00002c) & ~0x4, 0xac00002c);
+ if (readb(base + 0x2C) & 0x4) { /* reg B */
+ writeb(readb(base + 0x2c) & ~0x4, base + 0x2c);
au_sync();
}
}
diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c
index 91983ba407c..b73b2d18bf5 100644
--- a/arch/mips/au1000/pb1200/irqmap.c
+++ b/arch/mips/au1000/pb1200/irqmap.c
@@ -137,33 +137,20 @@ static void pb1200_shutdown_irq( unsigned int irq_nr )
return;
}
-static inline void pb1200_mask_and_ack_irq(unsigned int irq_nr)
-{
- pb1200_disable_irq( irq_nr );
-}
-
-static void pb1200_end_irq(unsigned int irq_nr)
-{
- if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
- pb1200_enable_irq(irq_nr);
- }
-}
-
static struct irq_chip external_irq_type =
{
#ifdef CONFIG_MIPS_PB1200
- "Pb1200 Ext",
+ .name = "Pb1200 Ext",
#endif
#ifdef CONFIG_MIPS_DB1200
- "Db1200 Ext",
+ .name = "Db1200 Ext",
#endif
- pb1200_startup_irq,
- pb1200_shutdown_irq,
- pb1200_enable_irq,
- pb1200_disable_irq,
- pb1200_mask_and_ack_irq,
- pb1200_end_irq,
- NULL
+ .startup = pb1200_startup_irq,
+ .shutdown = pb1200_shutdown_irq,
+ .ack = pb1200_disable_irq,
+ .mask = pb1200_disable_irq,
+ .mask_ack = pb1200_disable_irq,
+ .unmask = pb1200_enable_irq,
};
void _board_init_irq(void)
@@ -172,7 +159,8 @@ void _board_init_irq(void)
for (irq_nr = PB1200_INT_BEGIN; irq_nr <= PB1200_INT_END; irq_nr++)
{
- irq_desc[irq_nr].chip = &external_irq_type;
+ set_irq_chip_and_handler(irq_nr, &external_irq_type,
+ handle_level_irq);
pb1200_disable_irq(irq_nr);
}
diff --git a/arch/mips/basler/excite/excite_irq.c b/arch/mips/basler/excite/excite_irq.c
index 2e2061a286c..1ecab635042 100644
--- a/arch/mips/basler/excite/excite_irq.c
+++ b/arch/mips/basler/excite/excite_irq.c
@@ -47,9 +47,9 @@ extern asmlinkage void excite_handle_int(void);
*/
void __init arch_init_irq(void)
{
- mips_cpu_irq_init(0);
- rm7k_cpu_irq_init(8);
- rm9k_cpu_irq_init(12);
+ mips_cpu_irq_init();
+ rm7k_cpu_irq_init();
+ rm9k_cpu_irq_init();
#ifdef CONFIG_KGDB
excite_kgdb_init();
diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c
index 4c46f0e7378..fe93b846923 100644
--- a/arch/mips/cobalt/irq.c
+++ b/arch/mips/cobalt/irq.c
@@ -104,7 +104,7 @@ void __init arch_init_irq(void)
GT_WRITE(GT_INTRMASK_OFS, 0);
init_i8259_irqs(); /* 0 ... 15 */
- mips_cpu_irq_init(COBALT_CPU_IRQ); /* 16 ... 23 */
+ mips_cpu_irq_init(); /* 16 ... 23 */
/*
* Mask all cpu interrupts
diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
index e8f0f20b852..a4b69b543bd 100644
--- a/arch/mips/cobalt/setup.c
+++ b/arch/mips/cobalt/setup.c
@@ -204,8 +204,7 @@ void __init prom_init(void)
add_memory_region(0x0, memsz, BOOT_MEM_RAM);
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
/* Nothing to do! */
- return 0;
}
diff --git a/arch/mips/configs/atlas_defconfig b/arch/mips/configs/atlas_defconfig
index 35931bedc3d..ac189168752 100644
--- a/arch/mips/configs/atlas_defconfig
+++ b/arch/mips/configs/atlas_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_ATLAS=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig
index ba3bf733d27..9554257c6f3 100644
--- a/arch/mips/configs/bigsur_defconfig
+++ b/arch/mips/configs/bigsur_defconfig
@@ -57,7 +57,7 @@ CONFIG_SIBYTE_BIGSUR=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig
index e5358121d2d..49590d44371 100644
--- a/arch/mips/configs/capcella_defconfig
+++ b/arch/mips/configs/capcella_defconfig
@@ -59,7 +59,7 @@ CONFIG_MACH_VR41XX=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig
index adf1e8c98c6..0607fc23908 100644
--- a/arch/mips/configs/cobalt_defconfig
+++ b/arch/mips/configs/cobalt_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_COBALT=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig
index 4fd29ffdfb8..1a57b337548 100644
--- a/arch/mips/configs/db1000_defconfig
+++ b/arch/mips/configs/db1000_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_DB1000=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig
index 025b960ba99..0055ec41f20 100644
--- a/arch/mips/configs/db1100_defconfig
+++ b/arch/mips/configs/db1100_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_DB1100=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig
index 80c9dd98f89..c41823b81be 100644
--- a/arch/mips/configs/db1200_defconfig
+++ b/arch/mips/configs/db1200_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_DB1200=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig
index 6caa90b0e17..7d6d9218788 100644
--- a/arch/mips/configs/db1500_defconfig
+++ b/arch/mips/configs/db1500_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_DB1500=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig
index c6cae86c6ab..c681c91763a 100644
--- a/arch/mips/configs/db1550_defconfig
+++ b/arch/mips/configs/db1550_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_DB1550=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/ddb5477_defconfig b/arch/mips/configs/ddb5477_defconfig
index 72f24001c99..dd4bb008021 100644
--- a/arch/mips/configs/ddb5477_defconfig
+++ b/arch/mips/configs/ddb5477_defconfig
@@ -59,7 +59,7 @@ CONFIG_DDB5477=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig
index fe1387eb83c..8a31ce4be12 100644
--- a/arch/mips/configs/decstation_defconfig
+++ b/arch/mips/configs/decstation_defconfig
@@ -59,7 +59,7 @@ CONFIG_MACH_DECSTATION=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig
index 6133c28beb8..6fa4f914f6e 100644
--- a/arch/mips/configs/e55_defconfig
+++ b/arch/mips/configs/e55_defconfig
@@ -59,7 +59,7 @@ CONFIG_MACH_VR41XX=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/emma2rh_defconfig b/arch/mips/configs/emma2rh_defconfig
index a484b7d396f..4c9d0405a5d 100644
--- a/arch/mips/configs/emma2rh_defconfig
+++ b/arch/mips/configs/emma2rh_defconfig
@@ -59,7 +59,7 @@ CONFIG_MARKEINS=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/ev64120_defconfig b/arch/mips/configs/ev64120_defconfig
index 21bfcdebf8f..d5b49735683 100644
--- a/arch/mips/configs/ev64120_defconfig
+++ b/arch/mips/configs/ev64120_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_EV64120=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/excite_defconfig b/arch/mips/configs/excite_defconfig
index 1a5b06cfb4d..697140c6562 100644
--- a/arch/mips/configs/excite_defconfig
+++ b/arch/mips/configs/excite_defconfig
@@ -60,7 +60,7 @@ CONFIG_BASLER_EXCITE=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig
index 21d53e0c9ee..f9812d1e457 100644
--- a/arch/mips/configs/ip22_defconfig
+++ b/arch/mips/configs/ip22_defconfig
@@ -59,7 +59,7 @@ CONFIG_SGI_IP22=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig
index e3e94c7e5ee..96090f28373 100644
--- a/arch/mips/configs/ip27_defconfig
+++ b/arch/mips/configs/ip27_defconfig
@@ -59,7 +59,7 @@ CONFIG_SGI_IP27=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig
index b4ab2bea972..61e069a0f1a 100644
--- a/arch/mips/configs/ip32_defconfig
+++ b/arch/mips/configs/ip32_defconfig
@@ -59,7 +59,7 @@ CONFIG_SGI_IP32=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig
index 9d4d17ace12..88966666f4c 100644
--- a/arch/mips/configs/jaguar-atx_defconfig
+++ b/arch/mips/configs/jaguar-atx_defconfig
@@ -59,7 +59,7 @@ CONFIG_MOMENCO_JAGUAR_ATX=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig
index 382083ebea0..835764d834f 100644
--- a/arch/mips/configs/jazz_defconfig
+++ b/arch/mips/configs/jazz_defconfig
@@ -57,7 +57,7 @@ CONFIG_MACH_JAZZ=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig
index d03746667a9..50fd9557e64 100644
--- a/arch/mips/configs/jmr3927_defconfig
+++ b/arch/mips/configs/jmr3927_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS=y
# 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_SNI_RM is not set
CONFIG_TOSHIBA_JMR3927=y
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/lasat200_defconfig b/arch/mips/configs/lasat200_defconfig
index 1db8249b4c0..05f539f84f5 100644
--- a/arch/mips/configs/lasat200_defconfig
+++ b/arch/mips/configs/lasat200_defconfig
@@ -59,7 +59,7 @@ CONFIG_LASAT=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
index 101e80347dc..96e941084c0 100644
--- a/arch/mips/configs/malta_defconfig
+++ b/arch/mips/configs/malta_defconfig
@@ -57,7 +57,7 @@ CONFIG_MIPS_MALTA=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
@@ -644,7 +644,85 @@ CONFIG_CONNECTOR=m
#
# Memory Technology Devices (MTD)
#
-# CONFIG_MTD is not set
+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=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+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=0x0
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=0
+# 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 is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
#
# Parallel port support
diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig
index a3cbd23bf21..03efcfd0503 100644
--- a/arch/mips/configs/mipssim_defconfig
+++ b/arch/mips/configs/mipssim_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_SIM=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig
index 6570b47426c..e4221aafbc4 100644
--- a/arch/mips/configs/mpc30x_defconfig
+++ b/arch/mips/configs/mpc30x_defconfig
@@ -59,7 +59,7 @@ CONFIG_MACH_VR41XX=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig
index 440d65f93a9..32b1afdd1c2 100644
--- a/arch/mips/configs/ocelot_3_defconfig
+++ b/arch/mips/configs/ocelot_3_defconfig
@@ -59,7 +59,7 @@ CONFIG_MOMENCO_OCELOT_3=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig
index c2c7ae77da3..ebe75c1c71a 100644
--- a/arch/mips/configs/ocelot_c_defconfig
+++ b/arch/mips/configs/ocelot_c_defconfig
@@ -59,7 +59,7 @@ CONFIG_MOMENCO_OCELOT_C=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/ocelot_defconfig b/arch/mips/configs/ocelot_defconfig
index 67efe270e0c..5a9603c1290 100644
--- a/arch/mips/configs/ocelot_defconfig
+++ b/arch/mips/configs/ocelot_defconfig
@@ -59,7 +59,7 @@ CONFIG_MOMENCO_OCELOT=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/ocelot_g_defconfig
index a10f34de5f7..46a942c253c 100644
--- a/arch/mips/configs/ocelot_g_defconfig
+++ b/arch/mips/configs/ocelot_g_defconfig
@@ -59,7 +59,7 @@ CONFIG_MOMENCO_OCELOT_G=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig
index 9e672f63a0a..7d3c688181d 100644
--- a/arch/mips/configs/pb1100_defconfig
+++ b/arch/mips/configs/pb1100_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_PB1100=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig
index d0c0f4af1bf..a77805af081 100644
--- a/arch/mips/configs/pb1500_defconfig
+++ b/arch/mips/configs/pb1500_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_PB1500=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig
index 3db7427d1b5..8318d74d6ad 100644
--- a/arch/mips/configs/pb1550_defconfig
+++ b/arch/mips/configs/pb1550_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_PB1550=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig
index 280a8001eac..fcb8fea3052 100644
--- a/arch/mips/configs/pnx8550-jbs_defconfig
+++ b/arch/mips/configs/pnx8550-jbs_defconfig
@@ -57,7 +57,7 @@ CONFIG_PNX8550_JBS=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/pnx8550-stb810_defconfig b/arch/mips/configs/pnx8550-stb810_defconfig
new file mode 100644
index 00000000000..f38a2c12303
--- /dev/null
+++ b/arch/mips/configs/pnx8550-stb810_defconfig
@@ -0,0 +1,1229 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19
+# Thu Dec 7 16:35: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_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_PNX8550_STB810=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 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_KEXEC 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
+# 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
+
+#
+# CPU selection
+#
+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
+# 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 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_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_CPU_HAS_PREFETCH=y
+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_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=y
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+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"
+
+#
+# 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=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=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_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 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=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_HW_HAS_PCI=y
+CONFIG_PCI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
+# CONFIG_PCI_DEBUG is not set
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# 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 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_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"
+# CONFIG_TCP_MD5SIG 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 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_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=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
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE 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_IDECD=m
+# 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 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=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_IDEDMA_AUTO is not set
+# 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 is not set
+CONFIG_SCSI_CONSTANTS=y
+# 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=m
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_ISCSI_TCP=m
+# 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
+
+#
+# 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_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
+#
+# 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 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
+# CONFIG_NETXEN_NIC 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
+# 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 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=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
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_PNX8XXX is not set
+# 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_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# 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_VGA_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=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_MULTITHREAD_PROBE 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
+
+#
+# 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_MII 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_TRANCEVIBRATOR 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 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
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# 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_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 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_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 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=m
+# 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=m
+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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 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_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=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+CONFIG_DEBUG_SLAB=y
+# CONFIG_DEBUG_SLAB_LEAK 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_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=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp"
+# 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 is not set
+# CONFIG_SECURITY is not set
+
+#
+# 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
+CONFIG_CRYPTO_MD5=m
+# 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 is not set
+# 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=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_PLIST=y
diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig
index 64b9fbf44a6..5bc3248e50e 100644
--- a/arch/mips/configs/pnx8550-v2pci_defconfig
+++ b/arch/mips/configs/pnx8550-v2pci_defconfig
@@ -57,7 +57,7 @@ CONFIG_PNX8550_V2PCI=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/qemu_defconfig b/arch/mips/configs/qemu_defconfig
index 9b0dab822bd..aa61f0f030a 100644
--- a/arch/mips/configs/qemu_defconfig
+++ b/arch/mips/configs/qemu_defconfig
@@ -59,7 +59,7 @@ CONFIG_QEMU=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig
index dd029603602..f9e8f41d17f 100644
--- a/arch/mips/configs/rbhma4500_defconfig
+++ b/arch/mips/configs/rbhma4500_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
CONFIG_TOSHIBA_RBTX4938=y
diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig
index d8a498d64d6..496aa67b9f8 100644
--- a/arch/mips/configs/rm200_defconfig
+++ b/arch/mips/configs/rm200_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS=y
# CONFIG_SIBYTE_LITTLESUR is not set
# CONFIG_SIBYTE_CRHINE is not set
# CONFIG_SIBYTE_CRHONE is not set
-CONFIG_SNI_RM200_PCI=y
+CONFIG_SNI_RM=y
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig
index 805a4fe450f..e33c17200b3 100644
--- a/arch/mips/configs/sb1250-swarm_defconfig
+++ b/arch/mips/configs/sb1250-swarm_defconfig
@@ -59,7 +59,7 @@ CONFIG_SIBYTE_SWARM=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/sead_defconfig b/arch/mips/configs/sead_defconfig
index 6fcb656d8d8..83fb932f9d4 100644
--- a/arch/mips/configs/sead_defconfig
+++ b/arch/mips/configs/sead_defconfig
@@ -59,7 +59,7 @@ CONFIG_MIPS_SEAD=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig
index dc312f19ada..e9d4eae45bf 100644
--- a/arch/mips/configs/tb0226_defconfig
+++ b/arch/mips/configs/tb0226_defconfig
@@ -59,7 +59,7 @@ CONFIG_MACH_VR41XX=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig
index 85615d99b01..c19597fb0c3 100644
--- a/arch/mips/configs/tb0229_defconfig
+++ b/arch/mips/configs/tb0229_defconfig
@@ -59,7 +59,7 @@ CONFIG_MACH_VR41XX=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig
index f7e8194809a..97d94f96990 100644
--- a/arch/mips/configs/tb0287_defconfig
+++ b/arch/mips/configs/tb0287_defconfig
@@ -57,7 +57,7 @@ CONFIG_MACH_VR41XX=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig
index 863f6a7cadf..553734a47b6 100644
--- a/arch/mips/configs/workpad_defconfig
+++ b/arch/mips/configs/workpad_defconfig
@@ -59,7 +59,7 @@ CONFIG_MACH_VR41XX=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig
index c10267d61cc..d3dfb702bb7 100644
--- a/arch/mips/configs/wrppmc_defconfig
+++ b/arch/mips/configs/wrppmc_defconfig
@@ -59,7 +59,7 @@ CONFIG_WR_PPMC=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig
index 4d3c1329f3c..b9f74d6745e 100644
--- a/arch/mips/configs/yosemite_defconfig
+++ b/arch/mips/configs/yosemite_defconfig
@@ -59,7 +59,7 @@ CONFIG_PMC_YOSEMITE=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/ddb5xxx/common/prom.c b/arch/mips/ddb5xxx/common/prom.c
index efef0f57ce1..54a857b5e3b 100644
--- a/arch/mips/ddb5xxx/common/prom.c
+++ b/arch/mips/ddb5xxx/common/prom.c
@@ -59,9 +59,8 @@ void __init prom_init(void)
#endif
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
#if defined(CONFIG_DDB5477)
diff --git a/arch/mips/ddb5xxx/ddb5477/irq.c b/arch/mips/ddb5xxx/ddb5477/irq.c
index a8bd2e66705..2b23234a5b9 100644
--- a/arch/mips/ddb5xxx/ddb5477/irq.c
+++ b/arch/mips/ddb5xxx/ddb5477/irq.c
@@ -17,6 +17,7 @@
#include <linux/ptrace.h>
#include <asm/i8259.h>
+#include <asm/irq_cpu.h>
#include <asm/system.h>
#include <asm/mipsregs.h>
#include <asm/debug.h>
@@ -73,7 +74,6 @@ set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger)
}
extern void vrc5477_irq_init(u32 base);
-extern void mips_cpu_irq_init(u32 base);
static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
void __init arch_init_irq(void)
@@ -125,7 +125,7 @@ void __init arch_init_irq(void)
/* init all controllers */
init_i8259_irqs();
- mips_cpu_irq_init(CPU_IRQ_BASE);
+ mips_cpu_irq_init();
vrc5477_irq_init(VRC5477_IRQ_BASE);
@@ -146,8 +146,7 @@ u8 i8259_interrupt_ack(void)
irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE);
ddb_out32(DDB_PCIINIT10, reg);
- /* i8259.c set the base vector to be 0x0 */
- return irq + I8259_IRQ_BASE;
+ return irq;
}
/*
* the first level int-handler will jump here if it is a vrc5477 irq
@@ -177,7 +176,7 @@ static void vrc5477_irq_dispatch(void)
/* check for i8259 interrupts */
if (intStatus & (1 << VRC5477_I8259_CASCADE)) {
int i8259_irq = i8259_interrupt_ack();
- do_IRQ(I8259_IRQ_BASE + i8259_irq);
+ do_IRQ(i8259_irq);
return;
}
}
diff --git a/arch/mips/ddb5xxx/ddb5477/irq_5477.c b/arch/mips/ddb5xxx/ddb5477/irq_5477.c
index 96249aa5df5..98c3b15eb36 100644
--- a/arch/mips/ddb5xxx/ddb5477/irq_5477.c
+++ b/arch/mips/ddb5xxx/ddb5477/irq_5477.c
@@ -82,7 +82,7 @@ vrc5477_irq_end(unsigned int irq)
}
struct irq_chip vrc5477_irq_controller = {
- .typename = "vrc5477_irq",
+ .name = "vrc5477_irq",
.ack = vrc5477_irq_ack,
.mask = vrc5477_irq_disable,
.mask_ack = vrc5477_irq_ack,
diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile
index ed181fdc3ac..8b790c2900d 100644
--- a/arch/mips/dec/Makefile
+++ b/arch/mips/dec/Makefile
@@ -6,6 +6,7 @@ obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn01-berr.o \
kn02-irq.o kn02xa-berr.o reset.o setup.o time.o
obj-$(CONFIG_PROM_CONSOLE) += promcon.o
+obj-$(CONFIG_TC) += tc.o
obj-$(CONFIG_CPU_HAS_WB) += wbflush.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/dec/ioasic-irq.c b/arch/mips/dec/ioasic-irq.c
index 4c7cb4048d3..3acb133668d 100644
--- a/arch/mips/dec/ioasic-irq.c
+++ b/arch/mips/dec/ioasic-irq.c
@@ -62,7 +62,7 @@ static inline void end_ioasic_irq(unsigned int irq)
}
static struct irq_chip ioasic_irq_type = {
- .typename = "IO-ASIC",
+ .name = "IO-ASIC",
.ack = ack_ioasic_irq,
.mask = mask_ioasic_irq,
.mask_ack = ack_ioasic_irq,
@@ -84,7 +84,7 @@ static inline void end_ioasic_dma_irq(unsigned int irq)
}
static struct irq_chip ioasic_dma_irq_type = {
- .typename = "IO-ASIC-DMA",
+ .name = "IO-ASIC-DMA",
.ack = ack_ioasic_dma_irq,
.mask = mask_ioasic_dma_irq,
.mask_ack = ack_ioasic_dma_irq,
diff --git a/arch/mips/dec/kn02-irq.c b/arch/mips/dec/kn02-irq.c
index 916e46b8ccd..02439dc0ba8 100644
--- a/arch/mips/dec/kn02-irq.c
+++ b/arch/mips/dec/kn02-irq.c
@@ -58,7 +58,7 @@ static void ack_kn02_irq(unsigned int irq)
}
static struct irq_chip kn02_irq_type = {
- .typename = "KN02-CSR",
+ .name = "KN02-CSR",
.ack = ack_kn02_irq,
.mask = mask_kn02_irq,
.mask_ack = ack_kn02_irq,
diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c
index 81d5e878ddc..c4e3c1ea0d4 100644
--- a/arch/mips/dec/prom/identify.c
+++ b/arch/mips/dec/prom/identify.c
@@ -88,6 +88,7 @@ static inline void prom_init_kn02(void)
{
dec_kn_slot_base = KN02_SLOT_BASE;
dec_kn_slot_size = KN02_SLOT_SIZE;
+ dec_tc_bus = 1;
dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN02_RTC);
}
@@ -96,6 +97,7 @@ static inline void prom_init_kn02xa(void)
{
dec_kn_slot_base = KN02XA_SLOT_BASE;
dec_kn_slot_size = IOASIC_SLOT_SIZE;
+ dec_tc_bus = 1;
ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL);
dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY);
@@ -105,6 +107,7 @@ static inline void prom_init_kn03(void)
{
dec_kn_slot_base = KN03_SLOT_BASE;
dec_kn_slot_size = IOASIC_SLOT_SIZE;
+ dec_tc_bus = 1;
ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL);
dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY);
diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c
index 3027ce78279..5a557e268f7 100644
--- a/arch/mips/dec/prom/memory.c
+++ b/arch/mips/dec/prom/memory.c
@@ -92,9 +92,9 @@ void __init prom_meminit(u32 magic)
rex_setup_memory_region();
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- unsigned long addr, end;
+ unsigned long end;
/*
* Free everything below the kernel itself but leave
@@ -114,16 +114,5 @@ unsigned long __init prom_free_prom_memory(void)
#endif
end = __pa(&_text);
- addr = PAGE_SIZE;
- while (addr < end) {
- ClearPageReserved(virt_to_page(__va(addr)));
- init_page_count(virt_to_page(__va(addr)));
- free_page((unsigned long)__va(addr));
- addr += PAGE_SIZE;
- }
-
- printk("Freeing unused PROM memory: %ldk freed\n",
- (end - PAGE_SIZE) >> 10);
-
- return end - PAGE_SIZE;
+ free_init_pages("unused PROM memory", PAGE_SIZE, end);
}
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
index d34032ac492..b8a5e75ba0a 100644
--- a/arch/mips/dec/setup.c
+++ b/arch/mips/dec/setup.c
@@ -53,6 +53,8 @@ unsigned long dec_kn_slot_base, dec_kn_slot_size;
EXPORT_SYMBOL(dec_kn_slot_base);
EXPORT_SYMBOL(dec_kn_slot_size);
+int dec_tc_bus;
+
spinlock_t ioasic_ssr_lock;
volatile u32 *ioasic_base;
@@ -234,7 +236,7 @@ static void __init dec_init_kn01(void)
memcpy(&cpu_mask_nr_tbl, &kn01_cpu_mask_nr_tbl,
sizeof(kn01_cpu_mask_nr_tbl));
- mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+ mips_cpu_irq_init();
} /* dec_init_kn01 */
@@ -309,7 +311,7 @@ static void __init dec_init_kn230(void)
memcpy(&cpu_mask_nr_tbl, &kn230_cpu_mask_nr_tbl,
sizeof(kn230_cpu_mask_nr_tbl));
- mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+ mips_cpu_irq_init();
} /* dec_init_kn230 */
@@ -403,7 +405,7 @@ static void __init dec_init_kn02(void)
memcpy(&asic_mask_nr_tbl, &kn02_asic_mask_nr_tbl,
sizeof(kn02_asic_mask_nr_tbl));
- mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+ mips_cpu_irq_init();
init_kn02_irqs(KN02_IRQ_BASE);
} /* dec_init_kn02 */
@@ -504,7 +506,7 @@ static void __init dec_init_kn02ba(void)
memcpy(&asic_mask_nr_tbl, &kn02ba_asic_mask_nr_tbl,
sizeof(kn02ba_asic_mask_nr_tbl));
- mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+ mips_cpu_irq_init();
init_ioasic_irqs(IO_IRQ_BASE);
} /* dec_init_kn02ba */
@@ -601,7 +603,7 @@ static void __init dec_init_kn02ca(void)
memcpy(&asic_mask_nr_tbl, &kn02ca_asic_mask_nr_tbl,
sizeof(kn02ca_asic_mask_nr_tbl));
- mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+ mips_cpu_irq_init();
init_ioasic_irqs(IO_IRQ_BASE);
} /* dec_init_kn02ca */
@@ -702,7 +704,7 @@ static void __init dec_init_kn03(void)
memcpy(&asic_mask_nr_tbl, &kn03_asic_mask_nr_tbl,
sizeof(kn03_asic_mask_nr_tbl));
- mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+ mips_cpu_irq_init();
init_ioasic_irqs(IO_IRQ_BASE);
} /* dec_init_kn03 */
diff --git a/arch/mips/dec/tc.c b/arch/mips/dec/tc.c
new file mode 100644
index 00000000000..732027c7983
--- /dev/null
+++ b/arch/mips/dec/tc.c
@@ -0,0 +1,95 @@
+/*
+ * TURBOchannel architecture calls.
+ *
+ * Copyright (c) Harald Koerfgen, 1998
+ * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki
+ * Copyright (c) 2005 James Simmons
+ *
+ * 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/compiler.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/tc.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <asm/paccess.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/prom.h>
+#include <asm/dec/system.h>
+
+/*
+ * Protected read byte from TURBOchannel slot space.
+ */
+int tc_preadb(u8 *valp, void __iomem *addr)
+{
+ return get_dbe(*valp, (u8 *)addr);
+}
+
+/*
+ * Get TURBOchannel bus information as specified by the spec, plus
+ * the slot space base address and the number of slots.
+ */
+int __init tc_bus_get_info(struct tc_bus *tbus)
+{
+ if (!dec_tc_bus)
+ return -ENXIO;
+
+ memcpy(&tbus->info, rex_gettcinfo(), sizeof(tbus->info));
+ tbus->slot_base = CPHYSADDR((long)rex_slot_address(0));
+
+ switch (mips_machtype) {
+ case MACH_DS5000_200:
+ tbus->num_tcslots = 7;
+ break;
+ case MACH_DS5000_2X0:
+ case MACH_DS5900:
+ tbus->ext_slot_base = 0x20000000;
+ tbus->ext_slot_size = 0x20000000;
+ /* fall through */
+ case MACH_DS5000_1XX:
+ tbus->num_tcslots = 3;
+ break;
+ case MACH_DS5000_XX:
+ tbus->num_tcslots = 2;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Get the IRQ for the specified slot.
+ */
+void __init tc_device_get_irq(struct tc_dev *tdev)
+{
+ switch (tdev->slot) {
+ case 0:
+ tdev->interrupt = dec_interrupt[DEC_IRQ_TC0];
+ break;
+ case 1:
+ tdev->interrupt = dec_interrupt[DEC_IRQ_TC1];
+ break;
+ case 2:
+ tdev->interrupt = dec_interrupt[DEC_IRQ_TC2];
+ break;
+ /*
+ * Yuck! DS5000/200 onboard devices
+ */
+ case 5:
+ tdev->interrupt = dec_interrupt[DEC_IRQ_TC5];
+ break;
+ case 6:
+ tdev->interrupt = dec_interrupt[DEC_IRQ_TC6];
+ break;
+ default:
+ tdev->interrupt = -1;
+ break;
+ }
+}
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index 21d53e0c9ee..f9812d1e457 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -59,7 +59,7 @@ CONFIG_SGI_IP22=y
# 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_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
diff --git a/arch/mips/emma2rh/common/irq_emma2rh.c b/arch/mips/emma2rh/common/irq_emma2rh.c
index 8d880f0b06e..96df37b7775 100644
--- a/arch/mips/emma2rh/common/irq_emma2rh.c
+++ b/arch/mips/emma2rh/common/irq_emma2rh.c
@@ -57,7 +57,7 @@ static void emma2rh_irq_disable(unsigned int irq)
}
struct irq_chip emma2rh_irq_controller = {
- .typename = "emma2rh_irq",
+ .name = "emma2rh_irq",
.ack = emma2rh_irq_disable,
.mask = emma2rh_irq_disable,
.mask_ack = emma2rh_irq_disable,
diff --git a/arch/mips/emma2rh/markeins/irq.c b/arch/mips/emma2rh/markeins/irq.c
index c93369cb411..3299b6dfe76 100644
--- a/arch/mips/emma2rh/markeins/irq.c
+++ b/arch/mips/emma2rh/markeins/irq.c
@@ -106,7 +106,7 @@ void __init arch_init_irq(void)
emma2rh_irq_init(EMMA2RH_IRQ_BASE);
emma2rh_sw_irq_init(EMMA2RH_SW_IRQ_BASE);
emma2rh_gpio_irq_init(EMMA2RH_GPIO_IRQ_BASE);
- mips_cpu_irq_init(CPU_IRQ_BASE);
+ mips_cpu_irq_init();
/* setup cascade interrupts */
setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE, &irq_cascade);
diff --git a/arch/mips/emma2rh/markeins/irq_markeins.c b/arch/mips/emma2rh/markeins/irq_markeins.c
index 2116d9be5fa..fba5c156f47 100644
--- a/arch/mips/emma2rh/markeins/irq_markeins.c
+++ b/arch/mips/emma2rh/markeins/irq_markeins.c
@@ -49,7 +49,7 @@ static void emma2rh_sw_irq_disable(unsigned int irq)
}
struct irq_chip emma2rh_sw_irq_controller = {
- .typename = "emma2rh_sw_irq",
+ .name = "emma2rh_sw_irq",
.ack = emma2rh_sw_irq_disable,
.mask = emma2rh_sw_irq_disable,
.mask_ack = emma2rh_sw_irq_disable,
@@ -115,7 +115,7 @@ static void emma2rh_gpio_irq_end(unsigned int irq)
}
struct irq_chip emma2rh_gpio_irq_controller = {
- .typename = "emma2rh_gpio_irq",
+ .name = "emma2rh_gpio_irq",
.ack = emma2rh_gpio_irq_ack,
.mask = emma2rh_gpio_irq_disable,
.mask_ack = emma2rh_gpio_irq_ack,
diff --git a/arch/mips/gt64120/ev64120/irq.c b/arch/mips/gt64120/ev64120/irq.c
index b3e5796c81d..04572b9c964 100644
--- a/arch/mips/gt64120/ev64120/irq.c
+++ b/arch/mips/gt64120/ev64120/irq.c
@@ -88,7 +88,7 @@ static void end_ev64120_irq(unsigned int irq)
}
static struct irq_chip ev64120_irq_type = {
- .typename = "EV64120",
+ .name = "EV64120",
.ack = disable_ev64120_irq,
.mask = disable_ev64120_irq,
.mask_ack = disable_ev64120_irq,
diff --git a/arch/mips/gt64120/ev64120/setup.c b/arch/mips/gt64120/ev64120/setup.c
index 99c8d42212e..477848c22a2 100644
--- a/arch/mips/gt64120/ev64120/setup.c
+++ b/arch/mips/gt64120/ev64120/setup.c
@@ -59,9 +59,8 @@ extern void galileo_machine_power_off(void);
*/
extern struct pci_ops galileo_pci_ops;
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
/*
diff --git a/arch/mips/gt64120/momenco_ocelot/dbg_io.c b/arch/mips/gt64120/momenco_ocelot/dbg_io.c
index 2128684584f..32d6fb4ee67 100644
--- a/arch/mips/gt64120/momenco_ocelot/dbg_io.c
+++ b/arch/mips/gt64120/momenco_ocelot/dbg_io.c
@@ -1,6 +1,4 @@
-#ifdef CONFIG_KGDB
-
#include <asm/serial.h> /* For the serial port location and base baud */
/* --- CONFIG --- */
@@ -121,5 +119,3 @@ int putDebugChar(uint8 byte)
UART16550_WRITE(OFS_SEND_BUFFER, byte);
return 1;
}
-
-#endif
diff --git a/arch/mips/gt64120/momenco_ocelot/irq.c b/arch/mips/gt64120/momenco_ocelot/irq.c
index d9294401ccb..2585d9dbda3 100644
--- a/arch/mips/gt64120/momenco_ocelot/irq.c
+++ b/arch/mips/gt64120/momenco_ocelot/irq.c
@@ -90,6 +90,6 @@ void __init arch_init_irq(void)
clear_c0_status(ST0_IM);
local_irq_disable();
- mips_cpu_irq_init(0);
- rm7k_cpu_irq_init(8);
+ mips_cpu_irq_init();
+ rm7k_cpu_irq_init();
}
diff --git a/arch/mips/gt64120/momenco_ocelot/prom.c b/arch/mips/gt64120/momenco_ocelot/prom.c
index 8677b6d3ada..78f393b2afd 100644
--- a/arch/mips/gt64120/momenco_ocelot/prom.c
+++ b/arch/mips/gt64120/momenco_ocelot/prom.c
@@ -67,7 +67,6 @@ void __init prom_init(void)
add_memory_region(0, 64 << 20, BOOT_MEM_RAM);
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
diff --git a/arch/mips/gt64120/wrppmc/irq.c b/arch/mips/gt64120/wrppmc/irq.c
index eedfc24e1ea..d3d96591780 100644
--- a/arch/mips/gt64120/wrppmc/irq.c
+++ b/arch/mips/gt64120/wrppmc/irq.c
@@ -63,7 +63,7 @@ void gt64120_init_pic(void)
void __init arch_init_irq(void)
{
/* IRQ 0 - 7 are for MIPS common irq_cpu controller */
- mips_cpu_irq_init(0);
+ mips_cpu_irq_init();
gt64120_init_pic();
}
diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/gt64120/wrppmc/setup.c
index 429afc400cb..121188d5ec4 100644
--- a/arch/mips/gt64120/wrppmc/setup.c
+++ b/arch/mips/gt64120/wrppmc/setup.c
@@ -93,9 +93,8 @@ void __init wrppmc_early_printk(const char *fmt, ...)
}
#endif /* WRPPMC_EARLY_DEBUG */
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
#ifdef CONFIG_SERIAL_8250
diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c
index f8d417b5c2b..295892e4ce5 100644
--- a/arch/mips/jazz/irq.c
+++ b/arch/mips/jazz/irq.c
@@ -40,7 +40,7 @@ void disable_r4030_irq(unsigned int irq)
}
static struct irq_chip r4030_irq_type = {
- .typename = "R4030",
+ .name = "R4030",
.ack = disable_r4030_irq,
.mask = disable_r4030_irq,
.mask_ack = disable_r4030_irq,
diff --git a/arch/mips/jmr3927/common/prom.c b/arch/mips/jmr3927/common/prom.c
index 5d5838f41d2..aa481b774c4 100644
--- a/arch/mips/jmr3927/common/prom.c
+++ b/arch/mips/jmr3927/common/prom.c
@@ -75,7 +75,6 @@ void __init prom_init_cmdline(void)
*cp = '\0';
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c
index 3da49c5aaf4..7d2c203cb40 100644
--- a/arch/mips/jmr3927/rbhma3100/irq.c
+++ b/arch/mips/jmr3927/rbhma3100/irq.c
@@ -439,7 +439,7 @@ void __init arch_init_irq(void)
}
static struct irq_chip jmr3927_irq_controller = {
- .typename = "jmr3927_irq",
+ .name = "jmr3927_irq",
.ack = jmr3927_irq_ack,
.mask = jmr3927_irq_disable,
.mask_ack = jmr3927_irq_ack,
diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c
index 138f25efe38..7ca3d6d07b3 100644
--- a/arch/mips/jmr3927/rbhma3100/setup.c
+++ b/arch/mips/jmr3927/rbhma3100/setup.c
@@ -434,7 +434,7 @@ void __init tx3927_setup(void)
/* DMA */
tx3927_dmaptr->mcr = 0;
- for (i = 0; i < sizeof(tx3927_dmaptr->ch) / sizeof(tx3927_dmaptr->ch[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(tx3927_dmaptr->ch); i++) {
/* reset channel */
tx3927_dmaptr->ch[i].ccr = TX3927_DMA_CCR_CHRST;
tx3927_dmaptr->ch[i].ccr = 0;
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index bbbb8d7cb89..1bf2c844891 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -14,8 +14,6 @@ binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
-obj-$(CONFIG_APM) += apm.o
-
obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o
obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o
obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o
diff --git a/arch/mips/kernel/apm.c b/arch/mips/kernel/apm.c
deleted file mode 100644
index 528e731049c..00000000000
--- a/arch/mips/kernel/apm.c
+++ /dev/null
@@ -1,604 +0,0 @@
-/*
- * bios-less APM driver for MIPS Linux
- * 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/capability.h>
-#include <linux/sched.h>
-#include <linux/pm.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-
-#include <asm/apm.h> /* apm_power_info */
-#include <asm/system.h>
-
-/*
- * The apm_bios device is one of the misc char devices.
- * This is its minor number.
- */
-#define APM_MINOR_DEV 134
-
-/*
- * See Documentation/Config.help for the configuration options.
- *
- * Various options can be changed at boot time as follows:
- * (We allow underscores for compatibility with the modules code)
- * apm=on/off enable/disable APM
- */
-
-/*
- * 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 int apm_disabled;
-static int mips_apm_active;
-
-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;
-
-
-static const char driver_version[] = "1.13"; /* no spaces */
-
-
-
-/*
- * Compatibility cruft until the IPAQ people move over to the new
- * interface.
- */
-static void __apm_get_power_status(struct apm_power_info *info)
-{
-}
-
-/*
- * This allows machines to provide their own "apm get power status" function.
- */
-void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status;
-EXPORT_SYMBOL(apm_get_power_status);
-
-
-/*
- * 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);
-}
-
-static void apm_suspend(void)
-{
- struct apm_user *as;
- int 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);
-}
-
-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, unsigned int cmd, unsigned 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 = (struct apm_user *)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_get_info(char *buf, char **start, off_t fpos, int length)
-{
- struct apm_power_info info;
- char *units;
- int ret;
-
- info.ac_line_status = 0xff;
- info.battery_status = 0xff;
- info.battery_flag = 0xff;
- info.battery_life = -1;
- info.time = -1;
- info.units = -1;
-
- if (apm_get_power_status)
- apm_get_power_status(&info);
-
- switch (info.units) {
- default: units = "?"; break;
- case 0: units = "min"; break;
- case 1: units = "sec"; break;
- }
-
- ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
- driver_version, APM_32_BIT_SUPPORT,
- info.ac_line_status, info.battery_status,
- info.battery_flag, info.battery_life,
- info.time, units);
-
- return ret;
-}
-#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) || !mips_apm_active);
-
- if (!mips_apm_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;
-
- if (apm_disabled) {
- printk(KERN_NOTICE "apm: disabled on user request.\n");
- return -ENODEV;
- }
-
- mips_apm_active = 1;
-
- ret = kernel_thread(kapmd, NULL, CLONE_KERNEL);
- if (ret < 0) {
- mips_apm_active = 0;
- return ret;
- }
-
-#ifdef CONFIG_PROC_FS
- create_proc_info_entry("apm", 0, NULL, apm_get_info);
-#endif
-
- ret = misc_register(&apm_device);
- if (ret != 0) {
- remove_proc_entry("apm", NULL);
-
- mips_apm_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);
-
- mips_apm_active = 0;
- wake_up(&kapmd_wait);
- wait_for_completion(&kapmd_exit);
-}
-
-module_init(apm_init);
-module_exit(apm_exit);
-
-MODULE_AUTHOR("Stephen Rothwell");
-MODULE_DESCRIPTION("Advanced Power Management");
-MODULE_LICENSE("GPL");
-
-#ifndef MODULE
-static int __init apm_setup(char *str)
-{
- while ((str != NULL) && (*str != '\0')) {
- if (strncmp(str, "off", 3) == 0)
- apm_disabled = 1;
- if (strncmp(str, "on", 2) == 0)
- apm_disabled = 0;
- str = strchr(str, ',');
- if (str != NULL)
- str += strspn(str, ", \t");
- }
- return 1;
-}
-
-__setup("apm=", apm_setup);
-#endif
-
-/**
- * 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)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&kapmd_queue_lock, flags);
- queue_add_event(&kapmd_queue, event);
- spin_unlock_irqrestore(&kapmd_queue_lock, flags);
-
- wake_up_interruptible(&kapmd_wait);
-}
-EXPORT_SYMBOL(apm_queue_event);
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index ff88b06f89d..ea7df4b8da3 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -234,10 +234,6 @@ void output_mm_defines(void)
constant("#define _PMD_SHIFT ", PMD_SHIFT);
constant("#define _PGDIR_SHIFT ", PGDIR_SHIFT);
linefeed;
- constant("#define _PGD_ORDER ", PGD_ORDER);
- constant("#define _PMD_ORDER ", PMD_ORDER);
- constant("#define _PTE_ORDER ", PTE_ORDER);
- linefeed;
constant("#define _PTRS_PER_PGD ", PTRS_PER_PGD);
constant("#define _PTRS_PER_PMD ", PTRS_PER_PMD);
constant("#define _PTRS_PER_PTE ", PTRS_PER_PTE);
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 442839e9578..f59ef271d24 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -565,7 +565,7 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
if (config3 & MIPS_CONF3_VEIC)
c->options |= MIPS_CPU_VEIC;
if (config3 & MIPS_CONF3_MT)
- c->ases |= MIPS_ASE_MIPSMT;
+ c->ases |= MIPS_ASE_MIPSMT;
return config3 & MIPS_CONF_M;
}
diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c
index 719d26968cb..7bc88204926 100644
--- a/arch/mips/kernel/gdb-stub.c
+++ b/arch/mips/kernel/gdb-stub.c
@@ -505,13 +505,13 @@ void show_gdbregs(struct gdb_regs * regs)
*/
printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
regs->reg0, regs->reg1, regs->reg2, regs->reg3,
- regs->reg4, regs->reg5, regs->reg6, regs->reg7);
+ regs->reg4, regs->reg5, regs->reg6, regs->reg7);
printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
regs->reg8, regs->reg9, regs->reg10, regs->reg11,
- regs->reg12, regs->reg13, regs->reg14, regs->reg15);
+ regs->reg12, regs->reg13, regs->reg14, regs->reg15);
printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
regs->reg16, regs->reg17, regs->reg18, regs->reg19,
- regs->reg20, regs->reg21, regs->reg22, regs->reg23);
+ regs->reg20, regs->reg21, regs->reg22, regs->reg23);
printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
regs->reg24, regs->reg25, regs->reg26, regs->reg27,
regs->reg28, regs->reg29, regs->reg30, regs->reg31);
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index a2e095adaa3..6f57ca44291 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -138,7 +138,7 @@
EXPORT(stext) # used for profiling
EXPORT(_stext)
-#if defined(CONFIG_QEMU) || defined(CONFIG_MIPS_SIM)
+#ifdef CONFIG_MIPS_SIM
/*
* Give us a fighting chance of running if execution beings at the
* kernel load address. This is needed because this platform does
@@ -231,28 +231,3 @@ NESTED(smp_bootstrap, 16, sp)
#endif /* CONFIG_SMP */
__FINIT
-
- .comm kernelsp, NR_CPUS * 8, 8
- .comm pgd_current, NR_CPUS * 8, 8
-
- .comm fw_arg0, SZREG, SZREG # firmware arguments
- .comm fw_arg1, SZREG, SZREG
- .comm fw_arg2, SZREG, SZREG
- .comm fw_arg3, SZREG, SZREG
-
- .macro page name, order
- .comm \name, (_PAGE_SIZE << \order), (_PAGE_SIZE << \order)
- .endm
-
- /*
- * On 64-bit we've got three-level pagetables with a slightly
- * different layout ...
- */
- page swapper_pg_dir, _PGD_ORDER
-#ifdef CONFIG_64BIT
-#if defined(CONFIG_MODULES) && !defined(CONFIG_BUILD_ELF64)
- page module_pg_dir, _PGD_ORDER
-#endif
- page invalid_pmd_table, _PMD_ORDER
-#endif
- page invalid_pte_table, _PTE_ORDER
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
index b59a676c6d0..b33ba6cd7f5 100644
--- a/arch/mips/kernel/i8259.c
+++ b/arch/mips/kernel/i8259.c
@@ -54,9 +54,11 @@ static unsigned int cached_irq_mask = 0xffff;
void disable_8259A_irq(unsigned int irq)
{
- unsigned int mask = 1 << irq;
+ unsigned int mask;
unsigned long flags;
+ irq -= I8259A_IRQ_BASE;
+ mask = 1 << irq;
spin_lock_irqsave(&i8259A_lock, flags);
cached_irq_mask |= mask;
if (irq & 8)
@@ -68,9 +70,11 @@ void disable_8259A_irq(unsigned int irq)
void enable_8259A_irq(unsigned int irq)
{
- unsigned int mask = ~(1 << irq);
+ unsigned int mask;
unsigned long flags;
+ irq -= I8259A_IRQ_BASE;
+ mask = ~(1 << irq);
spin_lock_irqsave(&i8259A_lock, flags);
cached_irq_mask &= mask;
if (irq & 8)
@@ -82,10 +86,12 @@ void enable_8259A_irq(unsigned int irq)
int i8259A_irq_pending(unsigned int irq)
{
- unsigned int mask = 1 << irq;
+ unsigned int mask;
unsigned long flags;
int ret;
+ irq -= I8259A_IRQ_BASE;
+ mask = 1 << irq;
spin_lock_irqsave(&i8259A_lock, flags);
if (irq < 8)
ret = inb(PIC_MASTER_CMD) & mask;
@@ -134,9 +140,11 @@ static inline int i8259A_irq_real(unsigned int irq)
*/
void mask_and_ack_8259A(unsigned int irq)
{
- unsigned int irqmask = 1 << irq;
+ unsigned int irqmask;
unsigned long flags;
+ irq -= I8259A_IRQ_BASE;
+ irqmask = 1 << irq;
spin_lock_irqsave(&i8259A_lock, flags);
/*
* Lightweight spurious IRQ detection. We do not want
@@ -169,8 +177,8 @@ handle_real_irq:
outb(0x60+irq,PIC_MASTER_CMD); /* 'Specific EOI to master */
}
#ifdef CONFIG_MIPS_MT_SMTC
- if (irq_hwmask[irq] & ST0_IM)
- set_c0_status(irq_hwmask[irq] & ST0_IM);
+ if (irq_hwmask[irq] & ST0_IM)
+ set_c0_status(irq_hwmask[irq] & ST0_IM);
#endif /* CONFIG_MIPS_MT_SMTC */
spin_unlock_irqrestore(&i8259A_lock, flags);
return;
@@ -322,8 +330,8 @@ void __init init_i8259_irqs (void)
init_8259A(0);
- for (i = 0; i < 16; i++)
+ for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++)
set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq);
- setup_irq(PIC_CASCADE_IR, &irq2);
+ setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);
}
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index 1bbefbf4337..3cc25c05d36 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -10,6 +10,8 @@
* Copyright (C) 1996 - 2004 David S. Miller <dm@engr.sgi.com>
* Copyright (C) 2004 - 2005 Steven J. Hill <sjhill@realitydiluted.com>
*/
+#undef DEBUG
+
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/stat.h>
@@ -40,8 +42,6 @@
#include <linux/elf.h>
-#undef DEBUG
-
static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs);
static int load_irix_library(struct file *);
static int irix_core_dump(long signr, struct pt_regs * regs,
@@ -52,72 +52,102 @@ static struct linux_binfmt irix_format = {
irix_core_dump, PAGE_SIZE
};
-#ifdef DEBUG
/* Debugging routines. */
static char *get_elf_p_type(Elf32_Word p_type)
{
- int i = (int) p_type;
-
- switch(i) {
- case PT_NULL: return("PT_NULL"); break;
- case PT_LOAD: return("PT_LOAD"); break;
- case PT_DYNAMIC: return("PT_DYNAMIC"); break;
- case PT_INTERP: return("PT_INTERP"); break;
- case PT_NOTE: return("PT_NOTE"); break;
- case PT_SHLIB: return("PT_SHLIB"); break;
- case PT_PHDR: return("PT_PHDR"); break;
- case PT_LOPROC: return("PT_LOPROC/REGINFO"); break;
- case PT_HIPROC: return("PT_HIPROC"); break;
- default: return("PT_BOGUS"); break;
+#ifdef DEBUG
+ switch (p_type) {
+ case PT_NULL:
+ return "PT_NULL";
+ break;
+
+ case PT_LOAD:
+ return "PT_LOAD";
+ break;
+
+ case PT_DYNAMIC:
+ return "PT_DYNAMIC";
+ break;
+
+ case PT_INTERP:
+ return "PT_INTERP";
+ break;
+
+ case PT_NOTE:
+ return "PT_NOTE";
+ break;
+
+ case PT_SHLIB:
+ return "PT_SHLIB";
+ break;
+
+ case PT_PHDR:
+ return "PT_PHDR";
+ break;
+
+ case PT_LOPROC:
+ return "PT_LOPROC/REGINFO";
+ break;
+
+ case PT_HIPROC:
+ return "PT_HIPROC";
+ break;
+
+ default:
+ return "PT_BOGUS";
+ break;
}
+#endif
}
static void print_elfhdr(struct elfhdr *ehp)
{
int i;
- printk("ELFHDR: e_ident<");
- for(i = 0; i < (EI_NIDENT - 1); i++) printk("%x ", ehp->e_ident[i]);
- printk("%x>\n", ehp->e_ident[i]);
- printk(" e_type[%04x] e_machine[%04x] e_version[%08lx]\n",
- (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine,
- (unsigned long) ehp->e_version);
- printk(" e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] "
- "e_flags[%08lx]\n",
- (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff,
- (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags);
- printk(" e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n",
- (unsigned short) ehp->e_ehsize, (unsigned short) ehp->e_phentsize,
- (unsigned short) ehp->e_phnum);
- printk(" e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n",
- (unsigned short) ehp->e_shentsize, (unsigned short) ehp->e_shnum,
- (unsigned short) ehp->e_shstrndx);
+ pr_debug("ELFHDR: e_ident<");
+ for (i = 0; i < (EI_NIDENT - 1); i++)
+ pr_debug("%x ", ehp->e_ident[i]);
+ pr_debug("%x>\n", ehp->e_ident[i]);
+ pr_debug(" e_type[%04x] e_machine[%04x] e_version[%08lx]\n",
+ (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine,
+ (unsigned long) ehp->e_version);
+ pr_debug(" e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] "
+ "e_flags[%08lx]\n",
+ (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff,
+ (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags);
+ pr_debug(" e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n",
+ (unsigned short) ehp->e_ehsize,
+ (unsigned short) ehp->e_phentsize,
+ (unsigned short) ehp->e_phnum);
+ pr_debug(" e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n",
+ (unsigned short) ehp->e_shentsize,
+ (unsigned short) ehp->e_shnum,
+ (unsigned short) ehp->e_shstrndx);
}
static void print_phdr(int i, struct elf_phdr *ep)
{
- printk("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] "
- "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type),
- (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr,
- (unsigned long) ep->p_paddr);
- printk(" p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] "
- "p_align[%08lx]\n", (unsigned long) ep->p_filesz,
- (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags,
- (unsigned long) ep->p_align);
+ pr_debug("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] "
+ "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type),
+ (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr,
+ (unsigned long) ep->p_paddr);
+ pr_debug(" p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] "
+ "p_align[%08lx]\n", (unsigned long) ep->p_filesz,
+ (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags,
+ (unsigned long) ep->p_align);
}
static void dump_phdrs(struct elf_phdr *ep, int pnum)
{
int i;
- for(i = 0; i < pnum; i++, ep++) {
- if((ep->p_type == PT_LOAD) ||
- (ep->p_type == PT_INTERP) ||
- (ep->p_type == PT_PHDR))
+ for (i = 0; i < pnum; i++, ep++) {
+ if ((ep->p_type == PT_LOAD) ||
+ (ep->p_type == PT_INTERP) ||
+ (ep->p_type == PT_PHDR))
print_phdr(i, ep);
}
}
-#endif /* DEBUG */
static void set_brk(unsigned long start, unsigned long end)
{
@@ -156,11 +186,10 @@ static unsigned long * create_irix_tables(char * p, int argc, int envc,
elf_addr_t *envp;
elf_addr_t *sp, *csp;
-#ifdef DEBUG
- printk("create_irix_tables: p[%p] argc[%d] envc[%d] "
- "load_addr[%08x] interp_load_addr[%08x]\n",
- p, argc, envc, load_addr, interp_load_addr);
-#endif
+ pr_debug("create_irix_tables: p[%p] argc[%d] envc[%d] "
+ "load_addr[%08x] interp_load_addr[%08x]\n",
+ p, argc, envc, load_addr, interp_load_addr);
+
sp = (elf_addr_t *) (~15UL & (unsigned long) p);
csp = sp;
csp -= exec ? DLINFO_ITEMS*2 : 2;
@@ -181,7 +210,7 @@ static unsigned long * create_irix_tables(char * p, int argc, int envc,
sp -= 2;
NEW_AUX_ENT(0, AT_NULL, 0);
- if(exec) {
+ if (exec) {
sp -= 11*2;
NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
@@ -245,9 +274,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
last_bss = 0;
error = load_addr = 0;
-#ifdef DEBUG
print_elfhdr(interp_elf_ex);
-#endif
/* First of all, some simple consistency checks */
if ((interp_elf_ex->e_type != ET_EXEC &&
@@ -258,7 +285,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
}
/* Now read in all of the header information */
- if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) {
+ if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) {
printk("IRIX interp header bigger than a page (%d)\n",
(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum));
return 0xffffffff;
@@ -267,15 +294,15 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
elf_phdata = kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
GFP_KERNEL);
- if(!elf_phdata) {
- printk("Cannot kmalloc phdata for IRIX interp.\n");
- return 0xffffffff;
+ if (!elf_phdata) {
+ printk("Cannot kmalloc phdata for IRIX interp.\n");
+ return 0xffffffff;
}
/* If the size of this structure has changed, then punt, since
* we will be doing the wrong thing.
*/
- if(interp_elf_ex->e_phentsize != 32) {
+ if (interp_elf_ex->e_phentsize != 32) {
printk("IRIX interp e_phentsize == %d != 32 ",
interp_elf_ex->e_phentsize);
kfree(elf_phdata);
@@ -286,61 +313,71 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
(char *) elf_phdata,
sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
-#ifdef DEBUG
dump_phdrs(elf_phdata, interp_elf_ex->e_phnum);
-#endif
eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
- if(eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
- int elf_prot = 0;
- unsigned long vaddr = 0;
- if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
- if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
- if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- elf_type |= MAP_FIXED;
- vaddr = eppnt->p_vaddr;
-
- pr_debug("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ",
- interpreter, vaddr,
- (unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)),
- (unsigned long) elf_prot, (unsigned long) elf_type,
- (unsigned long) (eppnt->p_offset & 0xfffff000));
- down_write(&current->mm->mmap_sem);
- error = do_mmap(interpreter, vaddr,
- eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
- elf_prot, elf_type,
- eppnt->p_offset & 0xfffff000);
- up_write(&current->mm->mmap_sem);
-
- if(error < 0 && error > -1024) {
- printk("Aieee IRIX interp mmap error=%d\n", error);
- break; /* Real error */
- }
- pr_debug("error=%08lx ", (unsigned long) error);
- if(!load_addr && interp_elf_ex->e_type == ET_DYN) {
- load_addr = error;
- pr_debug("load_addr = error ");
- }
-
- /* Find the end of the file mapping for this phdr, and keep
- * track of the largest address we see for this.
- */
- k = eppnt->p_vaddr + eppnt->p_filesz;
- if(k > elf_bss) elf_bss = k;
-
- /* Do the same thing for the memory mapping - between
- * elf_bss and last_bss is the bss section.
- */
- k = eppnt->p_memsz + eppnt->p_vaddr;
- if(k > last_bss) last_bss = k;
- pr_debug("\n");
- }
+ for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
+ if (eppnt->p_type == PT_LOAD) {
+ int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+ int elf_prot = 0;
+ unsigned long vaddr = 0;
+ if (eppnt->p_flags & PF_R)
+ elf_prot = PROT_READ;
+ if (eppnt->p_flags & PF_W)
+ elf_prot |= PROT_WRITE;
+ if (eppnt->p_flags & PF_X)
+ elf_prot |= PROT_EXEC;
+ elf_type |= MAP_FIXED;
+ vaddr = eppnt->p_vaddr;
+
+ pr_debug("INTERP do_mmap"
+ "(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ",
+ interpreter, vaddr,
+ (unsigned long)
+ (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)),
+ (unsigned long)
+ elf_prot, (unsigned long) elf_type,
+ (unsigned long)
+ (eppnt->p_offset & 0xfffff000));
+
+ down_write(&current->mm->mmap_sem);
+ error = do_mmap(interpreter, vaddr,
+ eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
+ elf_prot, elf_type,
+ eppnt->p_offset & 0xfffff000);
+ up_write(&current->mm->mmap_sem);
+
+ if (error < 0 && error > -1024) {
+ printk("Aieee IRIX interp mmap error=%d\n",
+ error);
+ break; /* Real error */
+ }
+ pr_debug("error=%08lx ", (unsigned long) error);
+ if (!load_addr && interp_elf_ex->e_type == ET_DYN) {
+ load_addr = error;
+ pr_debug("load_addr = error ");
+ }
+
+ /*
+ * Find the end of the file mapping for this phdr, and
+ * keep track of the largest address we see for this.
+ */
+ k = eppnt->p_vaddr + eppnt->p_filesz;
+ if (k > elf_bss)
+ elf_bss = k;
+
+ /* Do the same thing for the memory mapping - between
+ * elf_bss and last_bss is the bss section.
+ */
+ k = eppnt->p_memsz + eppnt->p_vaddr;
+ if (k > last_bss)
+ last_bss = k;
+ pr_debug("\n");
+ }
}
/* Now use mmap to map the library into memory. */
- if(error < 0 && error > -1024) {
+ if (error < 0 && error > -1024) {
pr_debug("got error %d\n", error);
kfree(elf_phdata);
return 0xffffffff;
@@ -377,7 +414,7 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm)
return -ENOEXEC;
/* First of all, some simple consistency checks */
- if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) ||
+ if ((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) ||
!bprm->file->f_op->mmap) {
return -ENOEXEC;
}
@@ -388,7 +425,7 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm)
* XXX all registers as 64bits on cpu's capable of this at
* XXX exception time plus frob the XTLB exception vector.
*/
- if((ehp->e_flags & EF_MIPS_ABI2))
+ if ((ehp->e_flags & EF_MIPS_ABI2))
return -ENOEXEC;
return 0;
@@ -410,7 +447,7 @@ static inline int look_for_irix_interpreter(char **name,
struct file *file = NULL;
*name = NULL;
- for(i = 0; i < pnum; i++, epp++) {
+ for (i = 0; i < pnum; i++, epp++) {
if (epp->p_type != PT_INTERP)
continue;
@@ -467,8 +504,8 @@ static inline void map_executable(struct file *fp, struct elf_phdr *epp, int pnu
unsigned int tmp;
int i, prot;
- for(i = 0; i < pnum; i++, epp++) {
- if(epp->p_type != PT_LOAD)
+ for (i = 0; i < pnum; i++, epp++) {
+ if (epp->p_type != PT_LOAD)
continue;
/* Map it. */
@@ -483,23 +520,23 @@ static inline void map_executable(struct file *fp, struct elf_phdr *epp, int pnu
up_write(&current->mm->mmap_sem);
/* Fixup location tracking vars. */
- if((epp->p_vaddr & 0xfffff000) < *estack)
+ if ((epp->p_vaddr & 0xfffff000) < *estack)
*estack = (epp->p_vaddr & 0xfffff000);
- if(!*laddr)
+ if (!*laddr)
*laddr = epp->p_vaddr - epp->p_offset;
- if(epp->p_vaddr < *scode)
+ if (epp->p_vaddr < *scode)
*scode = epp->p_vaddr;
tmp = epp->p_vaddr + epp->p_filesz;
- if(tmp > *ebss)
+ if (tmp > *ebss)
*ebss = tmp;
- if((epp->p_flags & PF_X) && *ecode < tmp)
+ if ((epp->p_flags & PF_X) && *ecode < tmp)
*ecode = tmp;
- if(*edata < tmp)
+ if (*edata < tmp)
*edata = tmp;
tmp = epp->p_vaddr + epp->p_memsz;
- if(tmp > *ebrk)
+ if (tmp > *ebrk)
*ebrk = tmp;
}
@@ -513,12 +550,12 @@ static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp,
int i;
*eentry = 0xffffffff;
- for(i = 0; i < pnum; i++, epp++) {
- if(epp->p_type != PT_INTERP)
+ for (i = 0; i < pnum; i++, epp++) {
+ if (epp->p_type != PT_INTERP)
continue;
/* We should have fielded this error elsewhere... */
- if(*eentry != 0xffffffff)
+ if (*eentry != 0xffffffff)
return -1;
set_fs(old_fs);
@@ -604,9 +641,7 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (elf_ex.e_shnum > 20)
goto out;
-#ifdef DEBUG
print_elfhdr(&elf_ex);
-#endif
/* Now read in all of the header information */
size = elf_ex.e_phentsize * elf_ex.e_phnum;
@@ -622,13 +657,11 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (retval < 0)
goto out_free_ph;
-#ifdef DEBUG
dump_phdrs(elf_phdata, elf_ex.e_phnum);
-#endif
/* Set some things for later. */
- for(i = 0; i < elf_ex.e_phnum; i++) {
- switch(elf_phdata[i].p_type) {
+ for (i = 0; i < elf_ex.e_phnum; i++) {
+ switch (elf_phdata[i].p_type) {
case PT_INTERP:
has_interp = 1;
elf_ihdr = &elf_phdata[i];
@@ -667,7 +700,7 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (elf_interpreter) {
retval = verify_irix_interpreter(&interp_elf_ex);
- if(retval)
+ if (retval)
goto out_free_interp;
}
@@ -706,12 +739,12 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
&load_addr, &start_code, &elf_bss, &end_code,
&end_data, &elf_brk);
- if(elf_interpreter) {
+ if (elf_interpreter) {
retval = map_interpreter(elf_phdata, &interp_elf_ex,
interpreter, &interp_load_addr,
elf_ex.e_phnum, old_fs, &elf_entry);
kfree(elf_interpreter);
- if(retval) {
+ if (retval) {
set_fs(old_fs);
printk("Unable to load IRIX ELF interpreter\n");
send_sig(SIGSEGV, current, 0);
@@ -809,12 +842,12 @@ static int load_irix_library(struct file *file)
return -ENOEXEC;
/* First of all, some simple consistency checks. */
- if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
+ if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
!file->f_op->mmap)
return -ENOEXEC;
/* Now read in all of the header information. */
- if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
+ if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
return -ENOEXEC;
elf_phdata = kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
@@ -825,15 +858,15 @@ static int load_irix_library(struct file *file)
sizeof(struct elf_phdr) * elf_ex.e_phnum);
j = 0;
- for(i=0; i<elf_ex.e_phnum; i++)
- if((elf_phdata + i)->p_type == PT_LOAD) j++;
+ for (i=0; i<elf_ex.e_phnum; i++)
+ if ((elf_phdata + i)->p_type == PT_LOAD) j++;
- if(j != 1) {
+ if (j != 1) {
kfree(elf_phdata);
return -ENOEXEC;
}
- while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
+ while (elf_phdata->p_type != PT_LOAD) elf_phdata++;
/* Now use mmap to map the library into memory. */
down_write(&current->mm->mmap_sem);
@@ -889,9 +922,7 @@ unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt)
return -EFAULT;
}
-#ifdef DEBUG
dump_phdrs(user_phdrp, cnt);
-#endif
for (i = 0; i < cnt; i++, hp++) {
if (__get_user(type, &hp->p_type))
@@ -905,14 +936,14 @@ unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt)
filp = fget(fd);
if (!filp)
return -EACCES;
- if(!filp->f_op) {
+ if (!filp->f_op) {
printk("irix_mapelf: Bogon filp!\n");
fput(filp);
return -EACCES;
}
hp = user_phdrp;
- for(i = 0; i < cnt; i++, hp++) {
+ for (i = 0; i < cnt; i++, hp++) {
int prot;
retval = __get_user(vaddr, &hp->p_vaddr);
@@ -1015,8 +1046,6 @@ static int notesize(struct memelfnote *en)
return sz;
}
-/* #define DEBUG */
-
#define DUMP_WRITE(addr, nr) \
if (!dump_write(file, (addr), (nr))) \
goto end_coredump;
@@ -1093,9 +1122,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
segs++;
}
-#ifdef DEBUG
- printk("irix_core_dump: %d segs taking %d bytes\n", segs, size);
-#endif
+ pr_debug("irix_core_dump: %d segs taking %d bytes\n", segs, size);
/* Set up header. */
memcpy(elf.e_ident, ELFMAG, SELFMAG);
@@ -1145,7 +1172,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
psinfo.pr_pid = prstatus.pr_pid = current->pid;
psinfo.pr_ppid = prstatus.pr_ppid = current->parent->pid;
psinfo.pr_pgrp = prstatus.pr_pgrp = process_group(current);
- psinfo.pr_sid = prstatus.pr_sid = current->signal->session;
+ psinfo.pr_sid = prstatus.pr_sid = process_session(current);
if (current->pid == current->tgid) {
/*
* This is the record for the group leader. Add in the
@@ -1221,7 +1248,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
struct elf_phdr phdr;
int sz = 0;
- for(i = 0; i < numnote; i++)
+ for (i = 0; i < numnote; i++)
sz += notesize(&notes[i]);
phdr.p_type = PT_NOTE;
@@ -1241,7 +1268,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
dataoff = offset = roundup(offset, PAGE_SIZE);
/* Write program headers for segments dump. */
- for(vma = current->mm->mmap, i = 0;
+ for (vma = current->mm->mmap, i = 0;
i < segs && vma != NULL; vma = vma->vm_next) {
struct elf_phdr phdr;
size_t sz;
@@ -1267,7 +1294,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
DUMP_WRITE(&phdr, sizeof(phdr));
}
- for(i = 0; i < numnote; i++)
+ for (i = 0; i < numnote; i++)
if (!writenote(&notes[i], file))
goto end_coredump;
@@ -1275,7 +1302,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
DUMP_SEEK(dataoff);
- for(i = 0, vma = current->mm->mmap;
+ for (i = 0, vma = current->mm->mmap;
i < segs && vma != NULL;
vma = vma->vm_next) {
unsigned long addr = vma->vm_start;
@@ -1284,9 +1311,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
if (!maydump(vma))
continue;
i++;
-#ifdef DEBUG
- printk("elf_core_dump: writing %08lx %lx\n", addr, len);
-#endif
+ pr_debug("elf_core_dump: writing %08lx %lx\n", addr, len);
DUMP_WRITE((void __user *)addr, len);
}
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
index bcaad669608..2967537221e 100644
--- a/arch/mips/kernel/irq-msc01.c
+++ b/arch/mips/kernel/irq-msc01.c
@@ -112,7 +112,7 @@ msc_bind_eic_interrupt (unsigned int irq, unsigned int set)
}
struct irq_chip msc_levelirq_type = {
- .typename = "SOC-it-Level",
+ .name = "SOC-it-Level",
.ack = level_mask_and_ack_msc_irq,
.mask = mask_msc_irq,
.mask_ack = level_mask_and_ack_msc_irq,
@@ -122,7 +122,7 @@ struct irq_chip msc_levelirq_type = {
};
struct irq_chip msc_edgeirq_type = {
- .typename = "SOC-it-Edge",
+ .name = "SOC-it-Edge",
.ack = edge_mask_and_ack_msc_irq,
.mask = mask_msc_irq,
.mask_ack = edge_mask_and_ack_msc_irq,
diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c
index efbd219845b..3dd561832e4 100644
--- a/arch/mips/kernel/irq-mv6434x.c
+++ b/arch/mips/kernel/irq-mv6434x.c
@@ -23,13 +23,13 @@ static unsigned int irq_base;
static inline int ls1bit32(unsigned int x)
{
- int b = 31, s;
+ int b = 31, s;
- s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
- s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s;
- s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s;
- s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s;
- s = 1; if (x << 1 == 0) s = 0; b -= s;
+ s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
+ s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s;
+ s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s;
+ s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s;
+ s = 1; if (x << 1 == 0) s = 0; b -= s;
return b;
}
@@ -92,7 +92,7 @@ void ll_mv64340_irq(void)
}
struct irq_chip mv64340_irq_type = {
- .typename = "MV-64340",
+ .name = "MV-64340",
.ack = mask_mv64340_irq,
.mask = mask_mv64340_irq,
.mask_ack = mask_mv64340_irq,
diff --git a/arch/mips/kernel/irq-rm7000.c b/arch/mips/kernel/irq-rm7000.c
index 123324ba8c1..25073288348 100644
--- a/arch/mips/kernel/irq-rm7000.c
+++ b/arch/mips/kernel/irq-rm7000.c
@@ -17,28 +17,27 @@
#include <asm/mipsregs.h>
#include <asm/system.h>
-static int irq_base;
-
static inline void unmask_rm7k_irq(unsigned int irq)
{
- set_c0_intcontrol(0x100 << (irq - irq_base));
+ set_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE));
}
static inline void mask_rm7k_irq(unsigned int irq)
{
- clear_c0_intcontrol(0x100 << (irq - irq_base));
+ clear_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE));
}
static struct irq_chip rm7k_irq_controller = {
- .typename = "RM7000",
+ .name = "RM7000",
.ack = mask_rm7k_irq,
.mask = mask_rm7k_irq,
.mask_ack = mask_rm7k_irq,
.unmask = unmask_rm7k_irq,
};
-void __init rm7k_cpu_irq_init(int base)
+void __init rm7k_cpu_irq_init(void)
{
+ int base = RM7K_CPU_IRQ_BASE;
int i;
clear_c0_intcontrol(0x00000f00); /* Mask all */
@@ -46,6 +45,4 @@ void __init rm7k_cpu_irq_init(int base)
for (i = base; i < base + 4; i++)
set_irq_chip_and_handler(i, &rm7k_irq_controller,
handle_level_irq);
-
- irq_base = base;
}
diff --git a/arch/mips/kernel/irq-rm9000.c b/arch/mips/kernel/irq-rm9000.c
index 0e6f4c5349d..ae83d2df6f3 100644
--- a/arch/mips/kernel/irq-rm9000.c
+++ b/arch/mips/kernel/irq-rm9000.c
@@ -18,16 +18,14 @@
#include <asm/mipsregs.h>
#include <asm/system.h>
-static int irq_base;
-
static inline void unmask_rm9k_irq(unsigned int irq)
{
- set_c0_intcontrol(0x1000 << (irq - irq_base));
+ set_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE));
}
static inline void mask_rm9k_irq(unsigned int irq)
{
- clear_c0_intcontrol(0x1000 << (irq - irq_base));
+ clear_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE));
}
static inline void rm9k_cpu_irq_enable(unsigned int irq)
@@ -39,15 +37,6 @@ static inline void rm9k_cpu_irq_enable(unsigned int irq)
local_irq_restore(flags);
}
-static void rm9k_cpu_irq_disable(unsigned int irq)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- mask_rm9k_irq(irq);
- local_irq_restore(flags);
-}
-
/*
* Performance counter interrupts are global on all processors.
*/
@@ -81,7 +70,7 @@ static void rm9k_perfcounter_irq_shutdown(unsigned int irq)
}
static struct irq_chip rm9k_irq_controller = {
- .typename = "RM9000",
+ .name = "RM9000",
.ack = mask_rm9k_irq,
.mask = mask_rm9k_irq,
.mask_ack = mask_rm9k_irq,
@@ -89,7 +78,7 @@ static struct irq_chip rm9k_irq_controller = {
};
static struct irq_chip rm9k_perfcounter_irq = {
- .typename = "RM9000",
+ .name = "RM9000",
.startup = rm9k_perfcounter_irq_startup,
.shutdown = rm9k_perfcounter_irq_shutdown,
.ack = mask_rm9k_irq,
@@ -102,8 +91,9 @@ unsigned int rm9000_perfcount_irq;
EXPORT_SYMBOL(rm9000_perfcount_irq);
-void __init rm9k_cpu_irq_init(int base)
+void __init rm9k_cpu_irq_init(void)
{
+ int base = RM9K_CPU_IRQ_BASE;
int i;
clear_c0_intcontrol(0x0000f000); /* Mask all */
@@ -115,6 +105,4 @@ void __init rm9k_cpu_irq_init(int base)
rm9000_perfcount_irq = base + 1;
set_irq_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq,
handle_level_irq);
-
- irq_base = base;
}
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
index fcc86b96ccf..7b66e03b589 100644
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -25,7 +25,7 @@
* Don't even think about using this on SMP. You have been warned.
*
* This file exports one global function:
- * void mips_cpu_irq_init(int irq_base);
+ * void mips_cpu_irq_init(void);
*/
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -36,22 +36,20 @@
#include <asm/mipsmtregs.h>
#include <asm/system.h>
-static int mips_cpu_irq_base;
-
static inline void unmask_mips_irq(unsigned int irq)
{
- set_c0_status(0x100 << (irq - mips_cpu_irq_base));
+ set_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE));
irq_enable_hazard();
}
static inline void mask_mips_irq(unsigned int irq)
{
- clear_c0_status(0x100 << (irq - mips_cpu_irq_base));
+ clear_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE));
irq_disable_hazard();
}
static struct irq_chip mips_cpu_irq_controller = {
- .typename = "MIPS",
+ .name = "MIPS",
.ack = mask_mips_irq,
.mask = mask_mips_irq,
.mask_ack = mask_mips_irq,
@@ -70,7 +68,7 @@ static unsigned int mips_mt_cpu_irq_startup(unsigned int irq)
{
unsigned int vpflags = dvpe();
- clear_c0_cause(0x100 << (irq - mips_cpu_irq_base));
+ clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE));
evpe(vpflags);
unmask_mips_mt_irq(irq);
@@ -84,13 +82,13 @@ static unsigned int mips_mt_cpu_irq_startup(unsigned int irq)
static void mips_mt_cpu_irq_ack(unsigned int irq)
{
unsigned int vpflags = dvpe();
- clear_c0_cause(0x100 << (irq - mips_cpu_irq_base));
+ clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE));
evpe(vpflags);
mask_mips_mt_irq(irq);
}
static struct irq_chip mips_mt_cpu_irq_controller = {
- .typename = "MIPS",
+ .name = "MIPS",
.startup = mips_mt_cpu_irq_startup,
.ack = mips_mt_cpu_irq_ack,
.mask = mask_mips_mt_irq,
@@ -99,8 +97,9 @@ static struct irq_chip mips_mt_cpu_irq_controller = {
.eoi = unmask_mips_mt_irq,
};
-void __init mips_cpu_irq_init(int irq_base)
+void __init mips_cpu_irq_init(void)
{
+ int irq_base = MIPS_CPU_IRQ_BASE;
int i;
/* Mask interrupts. */
@@ -118,6 +117,4 @@ void __init mips_cpu_irq_init(int irq_base)
for (i = irq_base + 2; i < irq_base + 8; i++)
set_irq_chip_and_handler(i, &mips_cpu_irq_controller,
handle_level_irq);
-
- mips_cpu_irq_base = irq_base;
}
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
index 2c82412b9ef..5929f883e46 100644
--- a/arch/mips/kernel/kspd.c
+++ b/arch/mips/kernel/kspd.c
@@ -301,7 +301,7 @@ static void sp_cleanup(void)
for (;;) {
unsigned long set;
i = j * __NFDBITS;
- if (i >= fdt->max_fdset || i >= fdt->max_fds)
+ if (i >= fdt->max_fds)
break;
set = fdt->open_fds->fds_bits[j++];
while (set) {
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index b061c9aa630..0b8ce59429a 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -194,15 +194,15 @@ sysn32_waitid(int which, compat_pid_t pid,
}
struct sysinfo32 {
- s32 uptime;
- u32 loads[3];
- u32 totalram;
- u32 freeram;
- u32 sharedram;
- u32 bufferram;
- u32 totalswap;
- u32 freeswap;
- u16 procs;
+ s32 uptime;
+ u32 loads[3];
+ u32 totalram;
+ u32 freeram;
+ u32 sharedram;
+ u32 bufferram;
+ u32 totalswap;
+ u32 freeswap;
+ u16 procs;
u32 totalhigh;
u32 freehigh;
u32 mem_unit;
@@ -440,14 +440,26 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
}
#ifdef CONFIG_MIPS32_N32
-asmlinkage long sysn32_semctl(int semid, int semnum, int cmd, union semun arg)
+asmlinkage long sysn32_semctl(int semid, int semnum, int cmd, u32 arg)
{
/* compat_sys_semctl expects a pointer to union semun */
u32 __user *uptr = compat_alloc_user_space(sizeof(u32));
- if (put_user(ptr_to_compat(arg.__pad), uptr))
+ if (put_user(arg, uptr))
return -EFAULT;
return compat_sys_semctl(semid, semnum, cmd, uptr);
}
+
+asmlinkage long sysn32_msgsnd(int msqid, u32 msgp, unsigned msgsz, int msgflg)
+{
+ return compat_sys_msgsnd(msqid, msgsz, msgflg, compat_ptr(msgp));
+}
+
+asmlinkage long sysn32_msgrcv(int msqid, u32 msgp, size_t msgsz, int msgtyp,
+ int msgflg)
+{
+ return compat_sys_msgrcv(msqid, msgsz, msgtyp, msgflg, IPC_64,
+ compat_ptr(msgp));
+}
#endif
struct sysctl_args32
@@ -546,7 +558,7 @@ extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf);
asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32)
{
int err;
- struct ustat tmp;
+ struct ustat tmp;
struct ustat32 tmp32;
mm_segment_t old_fs = get_fs();
@@ -557,11 +569,11 @@ asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32)
if (err)
goto out;
- memset(&tmp32,0,sizeof(struct ustat32));
- tmp32.f_tfree = tmp.f_tfree;
- tmp32.f_tinode = tmp.f_tinode;
+ memset(&tmp32,0,sizeof(struct ustat32));
+ tmp32.f_tfree = tmp.f_tfree;
+ tmp32.f_tinode = tmp.f_tinode;
- err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0;
+ err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0;
out:
return err;
diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c
index c1373a6e668..a32f6797353 100644
--- a/arch/mips/kernel/mips-mt.c
+++ b/arch/mips/kernel/mips-mt.c
@@ -96,6 +96,10 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
goto out_unlock;
}
+ retval = security_task_setscheduler(p, 0, NULL);
+ if (retval)
+ goto out_unlock;
+
/* Record new user-specified CPU set for future reference */
p->thread.user_cpus_allowed = new_mask;
@@ -141,8 +145,9 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
p = find_process_by_pid(pid);
if (!p)
goto out_unlock;
-
- retval = 0;
+ retval = security_task_getscheduler(p);
+ if (retval)
+ goto out_unlock;
cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map);
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index f44a01357ad..2ef857c3ee5 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -46,5 +46,7 @@ EXPORT_SYMBOL(__strnlen_user_nocheck_asm);
EXPORT_SYMBOL(__strnlen_user_asm);
EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+EXPORT_SYMBOL(__csum_partial_copy_user);
EXPORT_SYMBOL(invalid_pte_table);
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 4ed37ba1973..5ddc2e9deec 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -31,13 +31,13 @@ static const char *cpu_name[] = {
[CPU_R4000PC] = "R4000PC",
[CPU_R4000SC] = "R4000SC",
[CPU_R4000MC] = "R4000MC",
- [CPU_R4200] = "R4200",
+ [CPU_R4200] = "R4200",
[CPU_R4400PC] = "R4400PC",
[CPU_R4400SC] = "R4400SC",
[CPU_R4400MC] = "R4400MC",
[CPU_R4600] = "R4600",
[CPU_R6000] = "R6000",
- [CPU_R6000A] = "R6000A",
+ [CPU_R6000A] = "R6000A",
[CPU_R8000] = "R8000",
[CPU_R10000] = "R10000",
[CPU_R12000] = "R12000",
@@ -46,14 +46,14 @@ static const char *cpu_name[] = {
[CPU_R4650] = "R4650",
[CPU_R4700] = "R4700",
[CPU_R5000] = "R5000",
- [CPU_R5000A] = "R5000A",
+ [CPU_R5000A] = "R5000A",
[CPU_R4640] = "R4640",
[CPU_NEVADA] = "Nevada",
[CPU_RM7000] = "RM7000",
[CPU_RM9000] = "RM9000",
[CPU_R5432] = "R5432",
[CPU_4KC] = "MIPS 4Kc",
- [CPU_5KC] = "MIPS 5Kc",
+ [CPU_5KC] = "MIPS 5Kc",
[CPU_R4310] = "R4310",
[CPU_SB1] = "SiByte SB1",
[CPU_SB1A] = "SiByte SB1A",
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index ec8209f3a0c..04e5b38d327 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -41,10 +41,6 @@
#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);
-#endif /* CONFIG_MIPS_MT_SMTC */
/*
* The idle thread. There's no useful work to be done, so just try to conserve
@@ -57,6 +53,8 @@ ATTRIB_NORET void cpu_idle(void)
while (1) {
while (!need_resched()) {
#ifdef CONFIG_MIPS_MT_SMTC
+ extern void smtc_idle_loop_hook(void);
+
smtc_idle_loop_hook();
#endif /* CONFIG_MIPS_MT_SMTC */
if (cpu_wait)
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
index 880fa6e841e..59c1577ecbb 100644
--- a/arch/mips/kernel/r4k_fpu.S
+++ b/arch/mips/kernel/r4k_fpu.S
@@ -114,6 +114,14 @@ LEAF(_save_fp_context32)
*/
LEAF(_restore_fp_context)
EX lw t0, SC_FPC_CSR(a0)
+
+ /* Fail if the CSR has exceptions pending */
+ srl t1, t0, 5
+ and t1, t0
+ andi t1, 0x1f << 7
+ bnez t1, fault
+ nop
+
#ifdef CONFIG_64BIT
EX ldc1 $f1, SC_FPREGS+8(a0)
EX ldc1 $f3, SC_FPREGS+24(a0)
@@ -157,6 +165,14 @@ LEAF(_restore_fp_context)
LEAF(_restore_fp_context32)
/* Restore an o32 sigcontext. */
EX lw t0, SC32_FPC_CSR(a0)
+
+ /* Fail if the CSR has exceptions pending */
+ srl t1, t0, 5
+ and t1, t0
+ andi t1, 0x1f << 7
+ bnez t1, fault
+ nop
+
EX ldc1 $f0, SC32_FPREGS+0(a0)
EX ldc1 $f2, SC32_FPREGS+16(a0)
EX ldc1 $f4, SC32_FPREGS+32(a0)
@@ -177,9 +193,10 @@ LEAF(_restore_fp_context32)
jr ra
li v0, 0 # success
END(_restore_fp_context32)
- .set reorder
#endif
+ .set reorder
+
.type fault@function
.ent fault
fault: li v0, -EFAULT # failure
diff --git a/arch/mips/kernel/reset.c b/arch/mips/kernel/reset.c
index 621037db229..060563a712b 100644
--- a/arch/mips/kernel/reset.c
+++ b/arch/mips/kernel/reset.c
@@ -23,6 +23,8 @@ void (*_machine_restart)(char *command);
void (*_machine_halt)(void);
void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
+
void machine_restart(char *command)
{
if (_machine_restart)
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index 8c8c8324f77..8610f4a925e 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -63,7 +63,7 @@ extern void *vpe_get_shared(int index);
static void rtlx_dispatch(void)
{
- do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ);
+ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ);
}
@@ -415,7 +415,7 @@ static unsigned int file_poll(struct file *file, poll_table * wait)
int minor;
unsigned int mask = 0;
- minor = iminor(file->f_dentry->d_inode);
+ minor = iminor(file->f_path.dentry->d_inode);
poll_wait(file, &channel_wqs[minor].rt_queue, wait);
poll_wait(file, &channel_wqs[minor].lx_queue, wait);
@@ -437,7 +437,7 @@ static unsigned int file_poll(struct file *file, poll_table * wait)
static ssize_t file_read(struct file *file, char __user * buffer, size_t count,
loff_t * ppos)
{
- int minor = iminor(file->f_dentry->d_inode);
+ int minor = iminor(file->f_path.dentry->d_inode);
/* data available? */
if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1)) {
@@ -454,7 +454,7 @@ static ssize_t file_write(struct file *file, const char __user * buffer,
struct rtlx_channel *rt;
DECLARE_WAITQUEUE(wait, current);
- minor = iminor(file->f_dentry->d_inode);
+ minor = iminor(file->f_path.dentry->d_inode);
rt = &rtlx->channel[minor];
/* any space left... */
@@ -491,7 +491,7 @@ static struct irqaction rtlx_irq = {
.name = "RTLX",
};
-static int rtlx_irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ;
+static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ;
static char register_chrdev_failed[] __initdata =
KERN_ERR "rtlx_module_init: unable to register device\n";
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 34567d81f94..39add2341aa 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -187,8 +187,8 @@ EXPORT(sysn32_call_table)
PTR sysn32_semctl
PTR sys_shmdt /* 6065 */
PTR sys_msgget
- PTR compat_sys_msgsnd
- PTR compat_sys_msgrcv
+ PTR sysn32_msgsnd
+ PTR sysn32_msgrcv
PTR compat_sys_msgctl
PTR compat_sys_fcntl /* 6070 */
PTR sys_flock
@@ -384,7 +384,7 @@ EXPORT(sysn32_call_table)
PTR sys_readlinkat
PTR sys_fchmodat
PTR sys_faccessat
- PTR sys_pselect6
+ PTR compat_sys_pselect6
PTR sys_ppoll /* 6265 */
PTR sys_unshare
PTR sys_splice
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index e91379c1be1..c58b8e0105e 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -506,7 +506,7 @@ sys_call_table:
PTR sys_readlinkat
PTR sys_fchmodat
PTR sys_faccessat /* 4300 */
- PTR sys_pselect6
+ PTR compat_sys_pselect6
PTR sys_ppoll
PTR sys_unshare
PTR sys_splice
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 89440a0d852..d2e01e7167b 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -271,8 +271,7 @@ static void __init bootmem_init(void)
static void __init bootmem_init(void)
{
unsigned long reserved_end;
- unsigned long highest = 0;
- unsigned long mapstart = -1UL;
+ unsigned long mapstart = ~0UL;
unsigned long bootmap_size;
int i;
@@ -284,6 +283,13 @@ static void __init bootmem_init(void)
reserved_end = max(init_initrd(), PFN_UP(__pa_symbol(&_end)));
/*
+ * max_low_pfn is not a number of pages. The number of pages
+ * of the system is given by 'max_low_pfn - min_low_pfn'.
+ */
+ min_low_pfn = ~0UL;
+ max_low_pfn = 0;
+
+ /*
* Find the highest page frame number we have available.
*/
for (i = 0; i < boot_mem_map.nr_map; i++) {
@@ -296,8 +302,10 @@ static void __init bootmem_init(void)
end = PFN_DOWN(boot_mem_map.map[i].addr
+ boot_mem_map.map[i].size);
- if (end > highest)
- highest = end;
+ if (end > max_low_pfn)
+ max_low_pfn = end;
+ if (start < min_low_pfn)
+ min_low_pfn = start;
if (end <= reserved_end)
continue;
if (start >= mapstart)
@@ -305,22 +313,36 @@ static void __init bootmem_init(void)
mapstart = max(reserved_end, start);
}
+ if (min_low_pfn >= max_low_pfn)
+ panic("Incorrect memory mapping !!!");
+ if (min_low_pfn > ARCH_PFN_OFFSET) {
+ printk(KERN_INFO
+ "Wasting %lu bytes for tracking %lu unused pages\n",
+ (min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page),
+ min_low_pfn - ARCH_PFN_OFFSET);
+ } else if (min_low_pfn < ARCH_PFN_OFFSET) {
+ printk(KERN_INFO
+ "%lu free pages won't be used\n",
+ ARCH_PFN_OFFSET - min_low_pfn);
+ }
+ min_low_pfn = ARCH_PFN_OFFSET;
+
/*
* Determine low and high memory ranges
*/
- if (highest > PFN_DOWN(HIGHMEM_START)) {
+ if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) {
#ifdef CONFIG_HIGHMEM
highstart_pfn = PFN_DOWN(HIGHMEM_START);
- highend_pfn = highest;
+ highend_pfn = max_low_pfn;
#endif
- highest = PFN_DOWN(HIGHMEM_START);
+ max_low_pfn = PFN_DOWN(HIGHMEM_START);
}
/*
* Initialize the boot-time allocator with low memory only.
*/
- bootmap_size = init_bootmem(mapstart, highest);
-
+ bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
+ min_low_pfn, max_low_pfn);
/*
* Register fully available low RAM pages with the bootmem allocator.
*/
@@ -507,9 +529,9 @@ void __init setup_arch(char **cmdline_p)
#if defined(CONFIG_VT)
#if defined(CONFIG_VGA_CONSOLE)
- conswitchp = &vga_con;
+ conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
- conswitchp = &dummy_con;
+ conswitchp = &dummy_con;
#endif
#endif
@@ -541,3 +563,6 @@ int __init dsp_disable(char *s)
}
__setup("nodsp", dsp_disable);
+
+unsigned long kernelsp[NR_CPUS];
+unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index b9d358e0521..9a44053cd9f 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -89,7 +89,7 @@ _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
spin_lock_irq(&current->sighand->siglock);
current->saved_sigmask = current->blocked;
current->blocked = newset;
- recalc_sigpending();
+ recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
current->state = TASK_INTERRUPTIBLE;
@@ -124,7 +124,7 @@ asmlinkage int sys_sigaction(int sig, const struct sigaction __user *act,
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
- return -EFAULT;
+ return -EFAULT;
err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler);
err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
@@ -304,7 +304,7 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
current->comm, current->pid,
frame, regs->cp0_epc, frame->regs[31]);
#endif
- return 0;
+ return 0;
give_sigsegv:
force_sigsegv(signr, current);
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index a67c18555ed..b28646b3cea 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -105,7 +105,7 @@ _sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
spin_lock_irq(&current->sighand->siglock);
current->saved_sigmask = current->blocked;
current->blocked = newset;
- recalc_sigpending();
+ recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
current->state = TASK_INTERRUPTIBLE;
@@ -184,7 +184,7 @@ int setup_rt_frame_n32(struct k_sigaction * ka,
/* Create the ucontext. */
err |= __put_user(0, &frame->rs_uc.uc_flags);
err |= __put_user(0, &frame->rs_uc.uc_link);
- sp = (int) (long) current->sas_ss_sp;
+ sp = (int) (long) current->sas_ss_sp;
err |= __put_user(sp,
&frame->rs_uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->regs[29]),
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index 1ee689c0e0c..64b62bdfb4f 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -35,7 +35,6 @@
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
#include <asm/mips_mt.h>
-#include <asm/mips-boards/maltaint.h> /* This is f*cking wrong */
#define MIPS_CPU_IPI_RESCHED_IRQ 0
#define MIPS_CPU_IPI_CALL_IRQ 1
@@ -108,12 +107,12 @@ void __init sanitize_tlb_entries(void)
static void ipi_resched_dispatch(void)
{
- do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
+ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
}
static void ipi_call_dispatch(void)
{
- do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ);
+ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
}
static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
@@ -270,8 +269,8 @@ void __init plat_prepare_cpus(unsigned int max_cpus)
set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
}
- cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
- cpu_ipi_call_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ;
+ cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
+ cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
setup_irq(cpu_ipi_resched_irq, &irq_resched);
setup_irq(cpu_ipi_call_irq, &irq_call);
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index f2a8701e414..0555fc554f6 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -271,7 +271,7 @@ void __devinit smp_prepare_boot_cpu(void)
* and keep control until "cpu_online(cpu)" is set. Note: cpu is
* physical, not logical.
*/
-int __devinit __cpu_up(unsigned int cpu)
+int __cpuinit __cpu_up(unsigned int cpu)
{
struct task_struct *idle;
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 802febed7df..9251ea82493 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -4,6 +4,7 @@
#include <linux/sched.h>
#include <linux/cpumask.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
#include <asm/cpu.h>
#include <asm/processor.h>
@@ -25,16 +26,6 @@
* This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set.
*/
-/*
- * MIPSCPU_INT_BASE is identically defined in both
- * asm-mips/mips-boards/maltaint.h and asm-mips/mips-boards/simint.h,
- * but as yet there's no properly organized include structure that
- * will ensure that the right *int.h file will be included for a
- * given platform build.
- */
-
-#define MIPSCPU_INT_BASE 16
-
#define MIPS_CPU_IPI_IRQ 1
#define LOCK_MT_PRA() \
@@ -76,15 +67,15 @@ unsigned int ipi_timer_latch[NR_CPUS];
#define IPIBUF_PER_CPU 4
-struct smtc_ipi_q IPIQ[NR_CPUS];
-struct smtc_ipi_q freeIPIq;
+static struct smtc_ipi_q IPIQ[NR_CPUS];
+static struct smtc_ipi_q freeIPIq;
/* Forward declarations */
void ipi_decode(struct smtc_ipi *);
-void post_direct_ipi(int cpu, struct smtc_ipi *pipi);
-void setup_cross_vpe_interrupts(void);
+static void post_direct_ipi(int cpu, struct smtc_ipi *pipi);
+static void setup_cross_vpe_interrupts(void);
void init_smtc_stats(void);
/* Global SMTC Status */
@@ -199,7 +190,7 @@ void __init sanitize_tlb_entries(void)
* Configure shared TLB - VPC configuration bit must be set by caller
*/
-void smtc_configure_tlb(void)
+static void smtc_configure_tlb(void)
{
int i,tlbsiz,vpes;
unsigned long mvpconf0;
@@ -261,6 +252,7 @@ void smtc_configure_tlb(void)
}
}
write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_STLB);
+ ehb();
/*
* Setup kernel data structures to use software total,
@@ -269,9 +261,12 @@ void smtc_configure_tlb(void)
* of their initialization in smtc_cpu_setup().
*/
- tlbsiz = tlbsiz & 0x3f; /* MIPS32 limits TLB indices to 64 */
- cpu_data[0].tlbsize = tlbsiz;
+ /* MIPS32 limits TLB indices to 64 */
+ if (tlbsiz > 64)
+ tlbsiz = 64;
+ cpu_data[0].tlbsize = current_cpu_data.tlbsize = tlbsiz;
smtc_status |= SMTC_TLB_SHARED;
+ local_flush_tlb_all();
printk("TLB of %d entry pairs shared by %d VPEs\n",
tlbsiz, vpes);
@@ -643,7 +638,7 @@ int setup_irq_smtc(unsigned int irq, struct irqaction * new,
* the VPE.
*/
-void smtc_ipi_qdump(void)
+static void smtc_ipi_qdump(void)
{
int i;
@@ -681,28 +676,6 @@ static __inline__ int atomic_postincrement(unsigned int *pv)
return result;
}
-/* No longer used in IPI dispatch, but retained for future recycling */
-
-static __inline__ int atomic_postclear(unsigned int *pv)
-{
- unsigned long result;
-
- unsigned long temp;
-
- __asm__ __volatile__(
- "1: ll %0, %2 \n"
- " or %1, $0, $0 \n"
- " sc %1, %2 \n"
- " beqz %1, 1b \n"
- " sync \n"
- : "=&r" (result), "=&r" (temp), "=m" (*pv)
- : "m" (*pv)
- : "memory");
-
- return result;
-}
-
-
void smtc_send_ipi(int cpu, int type, unsigned int action)
{
int tcstatus;
@@ -776,7 +749,7 @@ void smtc_send_ipi(int cpu, int type, unsigned int action)
/*
* Send IPI message to Halted TC, TargTC/TargVPE already having been set
*/
-void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
+static void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
{
struct pt_regs *kstack;
unsigned long tcstatus;
@@ -916,7 +889,7 @@ void smtc_timer_broadcast(int vpe)
* interrupts.
*/
-static int cpu_ipi_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_IRQ;
+static int cpu_ipi_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_IRQ;
static irqreturn_t ipi_interrupt(int irq, void *dev_idm)
{
@@ -995,7 +968,7 @@ static void ipi_irq_dispatch(void)
static struct irqaction irq_ipi;
-void setup_cross_vpe_interrupts(void)
+static void setup_cross_vpe_interrupts(void)
{
if (!cpu_has_vint)
panic("SMTC Kernel requires Vectored Interupt support");
@@ -1016,6 +989,35 @@ void setup_cross_vpe_interrupts(void)
* SMTC-specific hacks invoked from elsewhere in the kernel.
*/
+void smtc_ipi_replay(void)
+{
+ /*
+ * To the extent that we've ever turned interrupts off,
+ * we may have accumulated deferred IPIs. This is subtle.
+ * If we use the smtc_ipi_qdepth() macro, we'll get an
+ * exact number - but we'll also disable interrupts
+ * and create a window of failure where a new IPI gets
+ * queued after we test the depth but before we re-enable
+ * interrupts. So long as IXMT never gets set, however,
+ * we should be OK: If we pick up something and dispatch
+ * it here, that's great. If we see nothing, but concurrent
+ * with this operation, another TC sends us an IPI, IXMT
+ * is clear, and we'll handle it as a real pseudo-interrupt
+ * and not a pseudo-pseudo interrupt.
+ */
+ if (IPIQ[smp_processor_id()].depth > 0) {
+ struct smtc_ipi *pipi;
+ extern void self_ipi(struct smtc_ipi *);
+
+ while ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()]))) {
+ self_ipi(pipi);
+ smtc_cpu_stats[smp_processor_id()].selfipis++;
+ }
+ }
+}
+
+EXPORT_SYMBOL(smtc_ipi_replay);
+
void smtc_idle_loop_hook(void)
{
#ifdef SMTC_IDLE_HOOK_DEBUG
@@ -1112,29 +1114,14 @@ void smtc_idle_loop_hook(void)
if (pdb_msg != &id_ho_db_msg[0])
printk("CPU%d: %s", smp_processor_id(), id_ho_db_msg);
#endif /* SMTC_IDLE_HOOK_DEBUG */
+
/*
- * To the extent that we've ever turned interrupts off,
- * we may have accumulated deferred IPIs. This is subtle.
- * If we use the smtc_ipi_qdepth() macro, we'll get an
- * exact number - but we'll also disable interrupts
- * and create a window of failure where a new IPI gets
- * queued after we test the depth but before we re-enable
- * interrupts. So long as IXMT never gets set, however,
- * we should be OK: If we pick up something and dispatch
- * it here, that's great. If we see nothing, but concurrent
- * with this operation, another TC sends us an IPI, IXMT
- * is clear, and we'll handle it as a real pseudo-interrupt
- * and not a pseudo-pseudo interrupt.
+ * Replay any accumulated deferred IPIs. If "Instant Replay"
+ * is in use, there should never be any.
*/
- if (IPIQ[smp_processor_id()].depth > 0) {
- struct smtc_ipi *pipi;
- extern void self_ipi(struct smtc_ipi *);
-
- if ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()])) != NULL) {
- self_ipi(pipi);
- smtc_cpu_stats[smp_processor_id()].selfipis++;
- }
- }
+#ifndef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY
+ smtc_ipi_replay();
+#endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */
}
void smtc_soft_dump(void)
@@ -1172,7 +1159,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
* It would be nice to be able to use a spinlock here,
* but this is invoked from within TLB flush routines
* that protect themselves with DVPE, so if a lock is
- * held by another TC, it'll never be freed.
+ * held by another TC, it'll never be freed.
*
* DVPE/DMT must not be done with interrupts enabled,
* so even so most callers will already have disabled
@@ -1277,7 +1264,7 @@ void smtc_flush_tlb_asid(unsigned long asid)
* Support for single-threading cache flush operations.
*/
-int halt_state_save[NR_CPUS];
+static int halt_state_save[NR_CPUS];
/*
* To really, really be sure that nothing is being done
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 93c74fefff7..93a148486f8 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -669,7 +669,7 @@ asmlinkage int irix_mount(char __user *dev_name, char __user *dir_name,
struct irix_statfs {
short f_type;
- long f_bsize, f_frsize, f_blocks, f_bfree, f_files, f_ffree;
+ long f_bsize, f_frsize, f_blocks, f_bfree, f_files, f_ffree;
char f_fname[6], f_fpack[6];
};
@@ -732,7 +732,7 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs __user *buf)
goto out;
}
- error = vfs_statfs(file->f_dentry, &kbuf);
+ error = vfs_statfs(file->f_path.dentry, &kbuf);
if (error)
goto out_f;
@@ -959,7 +959,7 @@ static inline loff_t llseek(struct file *file, loff_t offset, int origin)
fn = default_llseek;
if (file->f_op && file->f_op->llseek)
- fn = file->f_op->llseek;
+ fn = file->f_op->llseek;
lock_kernel();
retval = fn(file, offset, origin);
unlock_kernel();
@@ -1041,7 +1041,7 @@ asmlinkage unsigned long irix_mmap32(unsigned long addr, size_t len, int prot,
unsigned long old_pos;
long max_size = offset + len;
- if (max_size > file->f_dentry->d_inode->i_size) {
+ if (max_size > file->f_path.dentry->d_inode->i_size) {
old_pos = sys_lseek (fd, max_size - 1, 0);
sys_write (fd, (void __user *) "", 1);
sys_lseek (fd, old_pos, 0);
@@ -1406,7 +1406,7 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs __user *buf)
error = -EBADF;
goto out;
}
- error = vfs_statfs(file->f_dentry, &kbuf);
+ error = vfs_statfs(file->f_path.dentry, &kbuf);
if (error)
goto out_f;
@@ -1526,7 +1526,7 @@ asmlinkage int irix_mmap64(struct pt_regs *regs)
unsigned long old_pos;
long max_size = off2 + len;
- if (max_size > file->f_dentry->d_inode->i_size) {
+ if (max_size > file->f_path.dentry->d_inode->i_size) {
old_pos = sys_lseek (fd, max_size - 1, 0);
sys_write (fd, (void __user *) "", 1);
sys_lseek (fd, old_pos, 0);
@@ -1658,7 +1658,7 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs __user *buf)
error = -EBADF;
goto out;
}
- error = vfs_statfs(file->f_dentry, &kbuf);
+ error = vfs_statfs(file->f_path.dentry, &kbuf);
if (error)
goto out_f;
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 11aab6d6bfe..8aa544f73a5 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -94,10 +94,8 @@ static void c0_timer_ack(void)
{
unsigned int count;
-#ifndef CONFIG_SOC_PNX8550 /* pnx8550 resets to zero */
/* Ack this timer interrupt and set the next one. */
expirelo += cycles_per_jiffy;
-#endif
write_c0_compare(expirelo);
/* Check to see if we have missed any timer interrupts. */
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 79f0317d84a..cecff24cc97 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -112,6 +112,7 @@ SECTIONS
/* .exit.text is discarded at runtime, not link time, to deal with
references from .rodata */
.exit.text : { *(.exit.text) }
+ .exit.data : { *(.exit.data) }
. = ALIGN(_PAGE_SIZE);
__initramfs_start = .;
.init.ramfs : { *(.init.ramfs) }
@@ -139,7 +140,6 @@ SECTIONS
/* Sections to be discarded */
/DISCARD/ : {
- *(.exit.data)
*(.exitcall.exit)
/* ABI crap starts here */
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index 51ddd216689..459624969c9 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -139,13 +139,16 @@ struct tc {
struct list_head list;
};
-struct vpecontrol_ {
+struct {
/* Virtual processing elements */
struct list_head vpe_list;
/* Thread contexts */
struct list_head tc_list;
-} vpecontrol;
+} vpecontrol = {
+ .vpe_list = LIST_HEAD_INIT(vpecontrol.vpe_list),
+ .tc_list = LIST_HEAD_INIT(vpecontrol.tc_list)
+};
static void release_progmem(void *ptr);
/* static __attribute_used__ void dump_vpe(struct vpe * v); */
@@ -519,7 +522,7 @@ static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
};
static char *rstrs[] = {
- [R_MIPS_NONE] = "MIPS_NONE",
+ [R_MIPS_NONE] = "MIPS_NONE",
[R_MIPS_32] = "MIPS_32",
[R_MIPS_26] = "MIPS_26",
[R_MIPS_HI16] = "MIPS_HI16",
@@ -692,7 +695,7 @@ static void dump_tclist(void)
}
/* We are prepared so configure and start the VPE... */
-int vpe_run(struct vpe * v)
+static int vpe_run(struct vpe * v)
{
struct vpe_notifications *n;
unsigned long val, dmt_flag;
@@ -710,16 +713,16 @@ int vpe_run(struct vpe * v)
dvpe();
if (!list_empty(&v->tc)) {
- if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
- printk(KERN_WARNING "VPE loader: TC %d is already in use.\n",
- t->index);
- return -ENOEXEC;
- }
- } else {
- printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n",
- v->minor);
- return -ENOEXEC;
- }
+ if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
+ printk(KERN_WARNING "VPE loader: TC %d is already in use.\n",
+ t->index);
+ return -ENOEXEC;
+ }
+ } else {
+ printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n",
+ v->minor);
+ return -ENOEXEC;
+ }
/* Put MVPE's into 'configuration state' */
set_c0_mvpcontrol(MVPCONTROL_VPC);
@@ -772,14 +775,14 @@ int vpe_run(struct vpe * v)
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));
+ /* 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);
+ /* enable this VPE */
+ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
/* clear out any left overs from a previous program */
write_vpe_c0_status(0);
@@ -829,7 +832,7 @@ static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
* contents of the program (p)buffer performing relocatations/etc, free's it
* when finished.
*/
-int vpe_elfload(struct vpe * v)
+static int vpe_elfload(struct vpe * v)
{
Elf_Ehdr *hdr;
Elf_Shdr *sechdrs;
@@ -1179,7 +1182,7 @@ static ssize_t vpe_write(struct file *file, const char __user * buffer,
size_t ret = count;
struct vpe *v;
- minor = iminor(file->f_dentry->d_inode);
+ minor = iminor(file->f_path.dentry->d_inode);
if ((v = get_vpe(minor)) == NULL)
return -ENODEV;
@@ -1388,8 +1391,6 @@ static int __init vpe_module_init(void)
/* dump_mtregs(); */
- INIT_LIST_HEAD(&vpecontrol.vpe_list);
- INIT_LIST_HEAD(&vpecontrol.tc_list);
val = read_c0_mvpconf0();
for (i = 0; i < ((val & MVPCONF0_PTC) + 1); i++) {
diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c
index 2affa5ff171..9a622b9a105 100644
--- a/arch/mips/lasat/interrupt.c
+++ b/arch/mips/lasat/interrupt.c
@@ -45,7 +45,7 @@ void enable_lasat_irq(unsigned int irq_nr)
}
static struct irq_chip lasat_irq_type = {
- .typename = "Lasat",
+ .name = "Lasat",
.ack = disable_lasat_irq,
.mask = disable_lasat_irq,
.mask_ack = disable_lasat_irq,
diff --git a/arch/mips/lasat/prom.c b/arch/mips/lasat/prom.c
index 88c7ab871ec..d47692f73a2 100644
--- a/arch/mips/lasat/prom.c
+++ b/arch/mips/lasat/prom.c
@@ -132,9 +132,8 @@ void __init prom_init(void)
add_memory_region(0, lasat_board_info.li_memsize, BOOT_MEM_RAM);
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
const char *get_system_type(void)
diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c
index 6dd7ae1b7c2..12878359f2c 100644
--- a/arch/mips/lasat/sysctl.c
+++ b/arch/mips/lasat/sysctl.c
@@ -40,12 +40,12 @@ static DEFINE_MUTEX(lasat_info_mutex);
/* Strategy function to write EEPROM after changing string entry */
int sysctl_lasatstring(ctl_table *table, int *name, int nlen,
void *oldval, size_t *oldlenp,
- void *newval, size_t newlen, void **context)
+ void *newval, size_t newlen)
{
int r;
mutex_lock(&lasat_info_mutex);
r = sysctl_string(table, name,
- nlen, oldval, oldlenp, newval, newlen, context);
+ nlen, oldval, oldlenp, newval, newlen);
if (r < 0) {
mutex_unlock(&lasat_info_mutex);
return r;
@@ -119,11 +119,11 @@ int proc_dolasatrtc(ctl_table *table, int write, struct file *filp,
/* Sysctl for setting the IP addresses */
int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
void *oldval, size_t *oldlenp,
- void *newval, size_t newlen, void **context)
+ void *newval, size_t newlen)
{
int r;
mutex_lock(&lasat_info_mutex);
- r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+ r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
if (r < 0) {
mutex_unlock(&lasat_info_mutex);
return r;
@@ -139,14 +139,14 @@ int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
/* Same for RTC */
int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen,
void *oldval, size_t *oldlenp,
- void *newval, size_t newlen, void **context)
+ void *newval, size_t newlen)
{
int r;
mutex_lock(&lasat_info_mutex);
rtctmp = ds1603_read();
if (rtctmp < 0)
rtctmp = 0;
- r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+ r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
if (r < 0) {
mutex_unlock(&lasat_info_mutex);
return r;
@@ -251,13 +251,12 @@ int proc_lasat_ip(ctl_table *table, int write, struct file *filp,
static int sysctl_lasat_eeprom_value(ctl_table *table, int *name, int nlen,
void *oldval, size_t *oldlenp,
- void *newval, size_t newlen,
- void **context)
+ void *newval, size_t newlen)
{
int r;
mutex_lock(&lasat_info_mutex);
- r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+ r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
if (r < 0) {
mutex_unlock(&lasat_info_mutex);
return r;
@@ -286,11 +285,11 @@ int proc_lasat_eeprom_value(ctl_table *table, int write, struct file *filp,
mutex_unlock(&lasat_info_mutex);
return r;
}
- if (filp && filp->f_dentry)
+ if (filp && filp->f_path.dentry)
{
- if (!strcmp(filp->f_dentry->d_name.name, "prid"))
+ if (!strcmp(filp->f_path.dentry->d_name.name, "prid"))
lasat_board_info.li_eeprom_info.prid = lasat_board_info.li_prid;
- if (!strcmp(filp->f_dentry->d_name.name, "debugaccess"))
+ if (!strcmp(filp->f_path.dentry->d_name.name, "debugaccess"))
lasat_board_info.li_eeprom_info.debugaccess = lasat_board_info.li_debugaccess;
}
lasat_write_eeprom_info();
diff --git a/arch/mips/lib-32/Makefile b/arch/mips/lib-32/Makefile
index dcd4d2ed2ac..2036cf5e685 100644
--- a/arch/mips/lib-32/Makefile
+++ b/arch/mips/lib-32/Makefile
@@ -2,7 +2,7 @@
# Makefile for MIPS-specific library files..
#
-lib-y += memset.o watch.o
+lib-y += watch.o
obj-$(CONFIG_CPU_MIPS32) += dump_tlb.o
obj-$(CONFIG_CPU_MIPS64) += dump_tlb.o
diff --git a/arch/mips/lib-64/Makefile b/arch/mips/lib-64/Makefile
index dcd4d2ed2ac..2036cf5e685 100644
--- a/arch/mips/lib-64/Makefile
+++ b/arch/mips/lib-64/Makefile
@@ -2,7 +2,7 @@
# Makefile for MIPS-specific library files..
#
-lib-y += memset.o watch.o
+lib-y += watch.o
obj-$(CONFIG_CPU_MIPS32) += dump_tlb.o
obj-$(CONFIG_CPU_MIPS64) += dump_tlb.o
diff --git a/arch/mips/lib-64/memset.S b/arch/mips/lib-64/memset.S
deleted file mode 100644
index e2c42c85113..00000000000
--- a/arch/mips/lib-64/memset.S
+++ /dev/null
@@ -1,142 +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) 1998, 1999, 2000 by Ralf Baechle
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#include <asm/asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/regdef.h>
-
-#define EX(insn,reg,addr,handler) \
-9: insn reg, addr; \
- .section __ex_table,"a"; \
- PTR 9b, handler; \
- .previous
-
- .macro f_fill64 dst, offset, val, fixup
- EX(LONG_S, \val, (\offset + 0 * LONGSIZE)(\dst), \fixup)
- EX(LONG_S, \val, (\offset + 1 * LONGSIZE)(\dst), \fixup)
- EX(LONG_S, \val, (\offset + 2 * LONGSIZE)(\dst), \fixup)
- EX(LONG_S, \val, (\offset + 3 * LONGSIZE)(\dst), \fixup)
- EX(LONG_S, \val, (\offset + 4 * LONGSIZE)(\dst), \fixup)
- EX(LONG_S, \val, (\offset + 5 * LONGSIZE)(\dst), \fixup)
- EX(LONG_S, \val, (\offset + 6 * LONGSIZE)(\dst), \fixup)
- EX(LONG_S, \val, (\offset + 7 * LONGSIZE)(\dst), \fixup)
- .endm
-
-/*
- * memset(void *s, int c, size_t n)
- *
- * a0: start of area to clear
- * a1: char to fill with
- * a2: size of area to clear
- */
- .set noreorder
- .align 5
-LEAF(memset)
- beqz a1, 1f
- move v0, a0 /* result */
-
- andi a1, 0xff /* spread fillword */
- dsll t1, a1, 8
- or a1, t1
- dsll t1, a1, 16
- or a1, t1
- dsll t1, a1, 32
- or a1, t1
-1:
-
-FEXPORT(__bzero)
- sltiu t0, a2, LONGSIZE /* very small region? */
- bnez t0, small_memset
- andi t0, a0, LONGMASK /* aligned? */
-
- beqz t0, 1f
- PTR_SUBU t0, LONGSIZE /* alignment in bytes */
-
-#ifdef __MIPSEB__
- EX(sdl, a1, (a0), first_fixup) /* make dword aligned */
-#endif
-#ifdef __MIPSEL__
- EX(sdr, a1, (a0), first_fixup) /* make dword aligned */
-#endif
- PTR_SUBU a0, t0 /* long align ptr */
- PTR_ADDU a2, t0 /* correct size */
-
-1: ori t1, a2, 0x3f /* # of full blocks */
- xori t1, 0x3f
- beqz t1, memset_partial /* no block to fill */
- andi t0, a2, 0x38
-
- PTR_ADDU t1, a0 /* end address */
- .set reorder
-1: PTR_ADDIU a0, 64
- f_fill64 a0, -64, a1, fwd_fixup
- bne t1, a0, 1b
- .set noreorder
-
-memset_partial:
- PTR_LA t1, 2f /* where to start */
- .set noat
- dsrl AT, t0, 1
- PTR_SUBU t1, AT
- .set noat
- jr t1
- PTR_ADDU a0, t0 /* dest ptr */
-
- .set push
- .set noreorder
- .set nomacro
- f_fill64 a0, -64, a1, partial_fixup /* ... but first do longs ... */
-2: .set pop
- andi a2, LONGMASK /* At most one long to go */
-
- beqz a2, 1f
- PTR_ADDU a0, a2 /* What's left */
-#ifdef __MIPSEB__
- EX(sdr, a1, -1(a0), last_fixup)
-#endif
-#ifdef __MIPSEL__
- EX(sdl, a1, -1(a0), last_fixup)
-#endif
-1: jr ra
- move a2, zero
-
-small_memset:
- beqz a2, 2f
- PTR_ADDU t1, a0, a2
-
-1: PTR_ADDIU a0, 1 /* fill bytewise */
- bne t1, a0, 1b
- sb a1, -1(a0)
-
-2: jr ra /* done */
- move a2, zero
- END(memset)
-
-first_fixup:
- jr ra
- nop
-
-fwd_fixup:
- PTR_L t0, TI_TASK($28)
- LONG_L t0, THREAD_BUADDR(t0)
- andi a2, 0x3f
- LONG_ADDU a2, t1
- jr ra
- LONG_SUBU a2, t0
-
-partial_fixup:
- PTR_L t0, TI_TASK($28)
- LONG_L t0, THREAD_BUADDR(t0)
- andi a2, LONGMASK
- LONG_ADDU a2, t1
- jr ra
- LONG_SUBU a2, t0
-
-last_fixup:
- jr ra
- andi v1, a2, LONGMASK
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 888b61ea12f..5ad501b30b4 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -2,7 +2,7 @@
# Makefile for MIPS-specific library files..
#
-lib-y += csum_partial.o csum_partial_copy.o memcpy.o promlib.o \
+lib-y += csum_partial.o memcpy.o memset.o promlib.o \
strlen_user.o strncpy_user.o strnlen_user.o uncached.o
obj-y += iomap.o
diff --git a/arch/mips/lib/csum_partial.S b/arch/mips/lib/csum_partial.S
index 15611d9df7a..c0a77fe038b 100644
--- a/arch/mips/lib/csum_partial.S
+++ b/arch/mips/lib/csum_partial.S
@@ -8,47 +8,72 @@
* Copyright (C) 1998, 1999 Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
+#include <linux/errno.h>
#include <asm/asm.h>
+#include <asm/asm-offsets.h>
#include <asm/regdef.h>
#ifdef CONFIG_64BIT
-#define T0 ta0
-#define T1 ta1
-#define T2 ta2
-#define T3 ta3
-#define T4 t0
-#define T7 t3
-#else
-#define T0 t0
-#define T1 t1
-#define T2 t2
-#define T3 t3
-#define T4 t4
-#define T7 t7
+/*
+ * As we are sharing code base with the mips32 tree (which use the o32 ABI
+ * register definitions). We need to redefine the register definitions from
+ * the n64 ABI register naming to the o32 ABI register naming.
+ */
+#undef t0
+#undef t1
+#undef t2
+#undef t3
+#define t0 $8
+#define t1 $9
+#define t2 $10
+#define t3 $11
+#define t4 $12
+#define t5 $13
+#define t6 $14
+#define t7 $15
+
+#define USE_DOUBLE
#endif
+#ifdef USE_DOUBLE
+
+#define LOAD ld
+#define ADD daddu
+#define NBYTES 8
+
+#else
+
+#define LOAD lw
+#define ADD addu
+#define NBYTES 4
+
+#endif /* USE_DOUBLE */
+
+#define UNIT(unit) ((unit)*NBYTES)
+
#define ADDC(sum,reg) \
- addu sum, reg; \
+ ADD sum, reg; \
sltu v1, sum, reg; \
- addu sum, v1
+ ADD sum, v1
-#define CSUM_BIGCHUNK(src, offset, sum, _t0, _t1, _t2, _t3) \
- lw _t0, (offset + 0x00)(src); \
- lw _t1, (offset + 0x04)(src); \
- lw _t2, (offset + 0x08)(src); \
- lw _t3, (offset + 0x0c)(src); \
+#define CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3) \
+ LOAD _t0, (offset + UNIT(0))(src); \
+ LOAD _t1, (offset + UNIT(1))(src); \
+ LOAD _t2, (offset + UNIT(2))(src); \
+ LOAD _t3, (offset + UNIT(3))(src); \
ADDC(sum, _t0); \
ADDC(sum, _t1); \
ADDC(sum, _t2); \
- ADDC(sum, _t3); \
- lw _t0, (offset + 0x10)(src); \
- lw _t1, (offset + 0x14)(src); \
- lw _t2, (offset + 0x18)(src); \
- lw _t3, (offset + 0x1c)(src); \
- ADDC(sum, _t0); \
- ADDC(sum, _t1); \
- ADDC(sum, _t2); \
- ADDC(sum, _t3); \
+ ADDC(sum, _t3)
+
+#ifdef USE_DOUBLE
+#define CSUM_BIGCHUNK(src, offset, sum, _t0, _t1, _t2, _t3) \
+ CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3)
+#else
+#define CSUM_BIGCHUNK(src, offset, sum, _t0, _t1, _t2, _t3) \
+ CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3); \
+ CSUM_BIGCHUNK1(src, offset + 0x10, sum, _t0, _t1, _t2, _t3)
+#endif
/*
* a0: source address
@@ -61,86 +86,27 @@
.text
.set noreorder
-
-/* unknown src alignment and < 8 bytes to go */
-small_csumcpy:
- move a1, T2
-
- andi T0, a1, 4
- beqz T0, 1f
- andi T0, a1, 2
-
- /* Still a full word to go */
- ulw T1, (src)
- PTR_ADDIU src, 4
- ADDC(sum, T1)
-
-1: move T1, zero
- beqz T0, 1f
- andi T0, a1, 1
-
- /* Still a halfword to go */
- ulhu T1, (src)
- PTR_ADDIU src, 2
-
-1: beqz T0, 1f
- sll T1, T1, 16
-
- lbu T2, (src)
- nop
-
-#ifdef __MIPSEB__
- sll T2, T2, 8
-#endif
- or T1, T2
-
-1: ADDC(sum, T1)
-
- /* fold checksum */
- sll v1, sum, 16
- addu sum, v1
- sltu v1, sum, v1
- srl sum, sum, 16
- addu sum, v1
-
- /* odd buffer alignment? */
- beqz T7, 1f
- nop
- sll v1, sum, 8
- srl sum, sum, 8
- or sum, v1
- andi sum, 0xffff
-1:
- .set reorder
- /* Add the passed partial csum. */
- ADDC(sum, a2)
- jr ra
- .set noreorder
-
-/* ------------------------------------------------------------------------- */
-
.align 5
LEAF(csum_partial)
move sum, zero
- move T7, zero
+ move t7, zero
sltiu t8, a1, 0x8
bnez t8, small_csumcpy /* < 8 bytes to copy */
- move T2, a1
+ move t2, a1
- beqz a1, out
- andi T7, src, 0x1 /* odd buffer? */
+ andi t7, src, 0x1 /* odd buffer? */
hword_align:
- beqz T7, word_align
+ beqz t7, word_align
andi t8, src, 0x2
- lbu T0, (src)
+ lbu t0, (src)
LONG_SUBU a1, a1, 0x1
#ifdef __MIPSEL__
- sll T0, T0, 8
+ sll t0, t0, 8
#endif
- ADDC(sum, T0)
+ ADDC(sum, t0)
PTR_ADDU src, src, 0x1
andi t8, src, 0x2
@@ -148,9 +114,9 @@ word_align:
beqz t8, dword_align
sltiu t8, a1, 56
- lhu T0, (src)
+ lhu t0, (src)
LONG_SUBU a1, a1, 0x2
- ADDC(sum, T0)
+ ADDC(sum, t0)
sltiu t8, a1, 56
PTR_ADDU src, src, 0x2
@@ -162,9 +128,9 @@ dword_align:
beqz t8, qword_align
andi t8, src, 0x8
- lw T0, 0x00(src)
+ lw t0, 0x00(src)
LONG_SUBU a1, a1, 0x4
- ADDC(sum, T0)
+ ADDC(sum, t0)
PTR_ADDU src, src, 0x4
andi t8, src, 0x8
@@ -172,11 +138,17 @@ qword_align:
beqz t8, oword_align
andi t8, src, 0x10
- lw T0, 0x00(src)
- lw T1, 0x04(src)
+#ifdef USE_DOUBLE
+ ld t0, 0x00(src)
LONG_SUBU a1, a1, 0x8
- ADDC(sum, T0)
- ADDC(sum, T1)
+ ADDC(sum, t0)
+#else
+ lw t0, 0x00(src)
+ lw t1, 0x04(src)
+ LONG_SUBU a1, a1, 0x8
+ ADDC(sum, t0)
+ ADDC(sum, t1)
+#endif
PTR_ADDU src, src, 0x8
andi t8, src, 0x10
@@ -184,75 +156,560 @@ oword_align:
beqz t8, begin_movement
LONG_SRL t8, a1, 0x7
- lw T3, 0x08(src)
- lw T4, 0x0c(src)
- lw T0, 0x00(src)
- lw T1, 0x04(src)
- ADDC(sum, T3)
- ADDC(sum, T4)
- ADDC(sum, T0)
- ADDC(sum, T1)
+#ifdef USE_DOUBLE
+ ld t0, 0x00(src)
+ ld t1, 0x08(src)
+ ADDC(sum, t0)
+ ADDC(sum, t1)
+#else
+ CSUM_BIGCHUNK1(src, 0x00, sum, t0, t1, t3, t4)
+#endif
LONG_SUBU a1, a1, 0x10
PTR_ADDU src, src, 0x10
LONG_SRL t8, a1, 0x7
begin_movement:
beqz t8, 1f
- andi T2, a1, 0x40
+ andi t2, a1, 0x40
move_128bytes:
- CSUM_BIGCHUNK(src, 0x00, sum, T0, T1, T3, T4)
- CSUM_BIGCHUNK(src, 0x20, sum, T0, T1, T3, T4)
- CSUM_BIGCHUNK(src, 0x40, sum, T0, T1, T3, T4)
- CSUM_BIGCHUNK(src, 0x60, sum, T0, T1, T3, T4)
+ CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4)
+ CSUM_BIGCHUNK(src, 0x20, sum, t0, t1, t3, t4)
+ CSUM_BIGCHUNK(src, 0x40, sum, t0, t1, t3, t4)
+ CSUM_BIGCHUNK(src, 0x60, sum, t0, t1, t3, t4)
LONG_SUBU t8, t8, 0x01
bnez t8, move_128bytes
PTR_ADDU src, src, 0x80
1:
- beqz T2, 1f
- andi T2, a1, 0x20
+ beqz t2, 1f
+ andi t2, a1, 0x20
move_64bytes:
- CSUM_BIGCHUNK(src, 0x00, sum, T0, T1, T3, T4)
- CSUM_BIGCHUNK(src, 0x20, sum, T0, T1, T3, T4)
+ CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4)
+ CSUM_BIGCHUNK(src, 0x20, sum, t0, t1, t3, t4)
PTR_ADDU src, src, 0x40
1:
- beqz T2, do_end_words
+ beqz t2, do_end_words
andi t8, a1, 0x1c
move_32bytes:
- CSUM_BIGCHUNK(src, 0x00, sum, T0, T1, T3, T4)
+ CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4)
andi t8, a1, 0x1c
PTR_ADDU src, src, 0x20
do_end_words:
- beqz t8, maybe_end_cruft
- LONG_SRL t8, t8, 0x2
+ beqz t8, small_csumcpy
+ andi t2, a1, 0x3
+ LONG_SRL t8, t8, 0x2
end_words:
- lw T0, (src)
+ lw t0, (src)
LONG_SUBU t8, t8, 0x1
- ADDC(sum, T0)
+ ADDC(sum, t0)
bnez t8, end_words
PTR_ADDU src, src, 0x4
-maybe_end_cruft:
- andi T2, a1, 0x3
+/* unknown src alignment and < 8 bytes to go */
+small_csumcpy:
+ move a1, t2
-small_memcpy:
- j small_csumcpy; move a1, T2 /* XXX ??? */
- beqz t2, out
- move a1, T2
+ andi t0, a1, 4
+ beqz t0, 1f
+ andi t0, a1, 2
-end_bytes:
- lb T0, (src)
- LONG_SUBU a1, a1, 0x1
- bnez a2, end_bytes
- PTR_ADDU src, src, 0x1
+ /* Still a full word to go */
+ ulw t1, (src)
+ PTR_ADDIU src, 4
+ ADDC(sum, t1)
+
+1: move t1, zero
+ beqz t0, 1f
+ andi t0, a1, 1
+
+ /* Still a halfword to go */
+ ulhu t1, (src)
+ PTR_ADDIU src, 2
-out:
+1: beqz t0, 1f
+ sll t1, t1, 16
+
+ lbu t2, (src)
+ nop
+
+#ifdef __MIPSEB__
+ sll t2, t2, 8
+#endif
+ or t1, t2
+
+1: ADDC(sum, t1)
+
+ /* fold checksum */
+#ifdef USE_DOUBLE
+ dsll32 v1, sum, 0
+ daddu sum, v1
+ sltu v1, sum, v1
+ dsra32 sum, sum, 0
+ addu sum, v1
+#endif
+ sll v1, sum, 16
+ addu sum, v1
+ sltu v1, sum, v1
+ srl sum, sum, 16
+ addu sum, v1
+
+ /* odd buffer alignment? */
+ beqz t7, 1f
+ nop
+ sll v1, sum, 8
+ srl sum, sum, 8
+ or sum, v1
+ andi sum, 0xffff
+1:
+ .set reorder
+ /* Add the passed partial csum. */
+ ADDC(sum, a2)
jr ra
- move v0, sum
+ .set noreorder
END(csum_partial)
+
+
+/*
+ * checksum and copy routines based on memcpy.S
+ *
+ * csum_partial_copy_nocheck(src, dst, len, sum)
+ * __csum_partial_copy_user(src, dst, len, sum, errp)
+ *
+ * See "Spec" in memcpy.S for details. Unlike __copy_user, all
+ * function in this file use the standard calling convention.
+ */
+
+#define src a0
+#define dst a1
+#define len a2
+#define psum a3
+#define sum v0
+#define odd t8
+#define errptr t9
+
+/*
+ * The exception handler for loads requires that:
+ * 1- AT contain the address of the byte just past the end of the source
+ * of the copy,
+ * 2- src_entry <= src < AT, and
+ * 3- (dst - src) == (dst_entry - src_entry),
+ * The _entry suffix denotes values when __copy_user was called.
+ *
+ * (1) is set up up by __csum_partial_copy_from_user and maintained by
+ * not writing AT in __csum_partial_copy
+ * (2) is met by incrementing src by the number of bytes copied
+ * (3) is met by not doing loads between a pair of increments of dst and src
+ *
+ * The exception handlers for stores stores -EFAULT to errptr and return.
+ * These handlers do not need to overwrite any data.
+ */
+
+#define EXC(inst_reg,addr,handler) \
+9: inst_reg, addr; \
+ .section __ex_table,"a"; \
+ PTR 9b, handler; \
+ .previous
+
+#ifdef USE_DOUBLE
+
+#define LOAD ld
+#define LOADL ldl
+#define LOADR ldr
+#define STOREL sdl
+#define STORER sdr
+#define STORE sd
+#define ADD daddu
+#define SUB dsubu
+#define SRL dsrl
+#define SLL dsll
+#define SLLV dsllv
+#define SRLV dsrlv
+#define NBYTES 8
+#define LOG_NBYTES 3
+
+#else
+
+#define LOAD lw
+#define LOADL lwl
+#define LOADR lwr
+#define STOREL swl
+#define STORER swr
+#define STORE sw
+#define ADD addu
+#define SUB subu
+#define SRL srl
+#define SLL sll
+#define SLLV sllv
+#define SRLV srlv
+#define NBYTES 4
+#define LOG_NBYTES 2
+
+#endif /* USE_DOUBLE */
+
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+#define LDFIRST LOADR
+#define LDREST LOADL
+#define STFIRST STORER
+#define STREST STOREL
+#define SHIFT_DISCARD SLLV
+#define SHIFT_DISCARD_REVERT SRLV
+#else
+#define LDFIRST LOADL
+#define LDREST LOADR
+#define STFIRST STOREL
+#define STREST STORER
+#define SHIFT_DISCARD SRLV
+#define SHIFT_DISCARD_REVERT SLLV
+#endif
+
+#define FIRST(unit) ((unit)*NBYTES)
+#define REST(unit) (FIRST(unit)+NBYTES-1)
+
+#define ADDRMASK (NBYTES-1)
+
+ .set noat
+
+LEAF(__csum_partial_copy_user)
+ PTR_ADDU AT, src, len /* See (1) above. */
+#ifdef CONFIG_64BIT
+ move errptr, a4
+#else
+ lw errptr, 16(sp)
+#endif
+FEXPORT(csum_partial_copy_nocheck)
+ move sum, zero
+ move odd, zero
+ /*
+ * Note: dst & src may be unaligned, len may be 0
+ * Temps
+ */
+ /*
+ * The "issue break"s below are very approximate.
+ * Issue delays for dcache fills will perturb the schedule, as will
+ * load queue full replay traps, etc.
+ *
+ * If len < NBYTES use byte operations.
+ */
+ sltu t2, len, NBYTES
+ and t1, dst, ADDRMASK
+ bnez t2, copy_bytes_checklen
+ and t0, src, ADDRMASK
+ andi odd, dst, 0x1 /* odd buffer? */
+ bnez t1, dst_unaligned
+ nop
+ bnez t0, src_unaligned_dst_aligned
+ /*
+ * use delay slot for fall-through
+ * src and dst are aligned; need to compute rem
+ */
+both_aligned:
+ SRL t0, len, LOG_NBYTES+3 # +3 for 8 units/iter
+ beqz t0, cleanup_both_aligned # len < 8*NBYTES
+ nop
+ SUB len, 8*NBYTES # subtract here for bgez loop
+ .align 4
+1:
+EXC( LOAD t0, UNIT(0)(src), l_exc)
+EXC( LOAD t1, UNIT(1)(src), l_exc_copy)
+EXC( LOAD t2, UNIT(2)(src), l_exc_copy)
+EXC( LOAD t3, UNIT(3)(src), l_exc_copy)
+EXC( LOAD t4, UNIT(4)(src), l_exc_copy)
+EXC( LOAD t5, UNIT(5)(src), l_exc_copy)
+EXC( LOAD t6, UNIT(6)(src), l_exc_copy)
+EXC( LOAD t7, UNIT(7)(src), l_exc_copy)
+ SUB len, len, 8*NBYTES
+ ADD src, src, 8*NBYTES
+EXC( STORE t0, UNIT(0)(dst), s_exc)
+ ADDC(sum, t0)
+EXC( STORE t1, UNIT(1)(dst), s_exc)
+ ADDC(sum, t1)
+EXC( STORE t2, UNIT(2)(dst), s_exc)
+ ADDC(sum, t2)
+EXC( STORE t3, UNIT(3)(dst), s_exc)
+ ADDC(sum, t3)
+EXC( STORE t4, UNIT(4)(dst), s_exc)
+ ADDC(sum, t4)
+EXC( STORE t5, UNIT(5)(dst), s_exc)
+ ADDC(sum, t5)
+EXC( STORE t6, UNIT(6)(dst), s_exc)
+ ADDC(sum, t6)
+EXC( STORE t7, UNIT(7)(dst), s_exc)
+ ADDC(sum, t7)
+ bgez len, 1b
+ ADD dst, dst, 8*NBYTES
+ ADD len, 8*NBYTES # revert len (see above)
+
+ /*
+ * len == the number of bytes left to copy < 8*NBYTES
+ */
+cleanup_both_aligned:
+#define rem t7
+ beqz len, done
+ sltu t0, len, 4*NBYTES
+ bnez t0, less_than_4units
+ and rem, len, (NBYTES-1) # rem = len % NBYTES
+ /*
+ * len >= 4*NBYTES
+ */
+EXC( LOAD t0, UNIT(0)(src), l_exc)
+EXC( LOAD t1, UNIT(1)(src), l_exc_copy)
+EXC( LOAD t2, UNIT(2)(src), l_exc_copy)
+EXC( LOAD t3, UNIT(3)(src), l_exc_copy)
+ SUB len, len, 4*NBYTES
+ ADD src, src, 4*NBYTES
+EXC( STORE t0, UNIT(0)(dst), s_exc)
+ ADDC(sum, t0)
+EXC( STORE t1, UNIT(1)(dst), s_exc)
+ ADDC(sum, t1)
+EXC( STORE t2, UNIT(2)(dst), s_exc)
+ ADDC(sum, t2)
+EXC( STORE t3, UNIT(3)(dst), s_exc)
+ ADDC(sum, t3)
+ beqz len, done
+ ADD dst, dst, 4*NBYTES
+less_than_4units:
+ /*
+ * rem = len % NBYTES
+ */
+ beq rem, len, copy_bytes
+ nop
+1:
+EXC( LOAD t0, 0(src), l_exc)
+ ADD src, src, NBYTES
+ SUB len, len, NBYTES
+EXC( STORE t0, 0(dst), s_exc)
+ ADDC(sum, t0)
+ bne rem, len, 1b
+ ADD dst, dst, NBYTES
+
+ /*
+ * src and dst are aligned, need to copy rem bytes (rem < NBYTES)
+ * A loop would do only a byte at a time with possible branch
+ * mispredicts. Can't do an explicit LOAD dst,mask,or,STORE
+ * because can't assume read-access to dst. Instead, use
+ * STREST dst, which doesn't require read access to dst.
+ *
+ * This code should perform better than a simple loop on modern,
+ * wide-issue mips processors because the code has fewer branches and
+ * more instruction-level parallelism.
+ */
+#define bits t2
+ beqz len, done
+ ADD t1, dst, len # t1 is just past last byte of dst
+ li bits, 8*NBYTES
+ SLL rem, len, 3 # rem = number of bits to keep
+EXC( LOAD t0, 0(src), l_exc)
+ SUB bits, bits, rem # bits = number of bits to discard
+ SHIFT_DISCARD t0, t0, bits
+EXC( STREST t0, -1(t1), s_exc)
+ SHIFT_DISCARD_REVERT t0, t0, bits
+ .set reorder
+ ADDC(sum, t0)
+ b done
+ .set noreorder
+dst_unaligned:
+ /*
+ * dst is unaligned
+ * t0 = src & ADDRMASK
+ * t1 = dst & ADDRMASK; T1 > 0
+ * len >= NBYTES
+ *
+ * Copy enough bytes to align dst
+ * Set match = (src and dst have same alignment)
+ */
+#define match rem
+EXC( LDFIRST t3, FIRST(0)(src), l_exc)
+ ADD t2, zero, NBYTES
+EXC( LDREST t3, REST(0)(src), l_exc_copy)
+ SUB t2, t2, t1 # t2 = number of bytes copied
+ xor match, t0, t1
+EXC( STFIRST t3, FIRST(0)(dst), s_exc)
+ SLL t4, t1, 3 # t4 = number of bits to discard
+ SHIFT_DISCARD t3, t3, t4
+ /* no SHIFT_DISCARD_REVERT to handle odd buffer properly */
+ ADDC(sum, t3)
+ beq len, t2, done
+ SUB len, len, t2
+ ADD dst, dst, t2
+ beqz match, both_aligned
+ ADD src, src, t2
+
+src_unaligned_dst_aligned:
+ SRL t0, len, LOG_NBYTES+2 # +2 for 4 units/iter
+ beqz t0, cleanup_src_unaligned
+ and rem, len, (4*NBYTES-1) # rem = len % 4*NBYTES
+1:
+/*
+ * Avoid consecutive LD*'s to the same register since some mips
+ * implementations can't issue them in the same cycle.
+ * It's OK to load FIRST(N+1) before REST(N) because the two addresses
+ * are to the same unit (unless src is aligned, but it's not).
+ */
+EXC( LDFIRST t0, FIRST(0)(src), l_exc)
+EXC( LDFIRST t1, FIRST(1)(src), l_exc_copy)
+ SUB len, len, 4*NBYTES
+EXC( LDREST t0, REST(0)(src), l_exc_copy)
+EXC( LDREST t1, REST(1)(src), l_exc_copy)
+EXC( LDFIRST t2, FIRST(2)(src), l_exc_copy)
+EXC( LDFIRST t3, FIRST(3)(src), l_exc_copy)
+EXC( LDREST t2, REST(2)(src), l_exc_copy)
+EXC( LDREST t3, REST(3)(src), l_exc_copy)
+ ADD src, src, 4*NBYTES
+#ifdef CONFIG_CPU_SB1
+ nop # improves slotting
+#endif
+EXC( STORE t0, UNIT(0)(dst), s_exc)
+ ADDC(sum, t0)
+EXC( STORE t1, UNIT(1)(dst), s_exc)
+ ADDC(sum, t1)
+EXC( STORE t2, UNIT(2)(dst), s_exc)
+ ADDC(sum, t2)
+EXC( STORE t3, UNIT(3)(dst), s_exc)
+ ADDC(sum, t3)
+ bne len, rem, 1b
+ ADD dst, dst, 4*NBYTES
+
+cleanup_src_unaligned:
+ beqz len, done
+ and rem, len, NBYTES-1 # rem = len % NBYTES
+ beq rem, len, copy_bytes
+ nop
+1:
+EXC( LDFIRST t0, FIRST(0)(src), l_exc)
+EXC( LDREST t0, REST(0)(src), l_exc_copy)
+ ADD src, src, NBYTES
+ SUB len, len, NBYTES
+EXC( STORE t0, 0(dst), s_exc)
+ ADDC(sum, t0)
+ bne len, rem, 1b
+ ADD dst, dst, NBYTES
+
+copy_bytes_checklen:
+ beqz len, done
+ nop
+copy_bytes:
+ /* 0 < len < NBYTES */
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+#define SHIFT_START 0
+#define SHIFT_INC 8
+#else
+#define SHIFT_START 8*(NBYTES-1)
+#define SHIFT_INC -8
+#endif
+ move t2, zero # partial word
+ li t3, SHIFT_START # shift
+/* use l_exc_copy here to return correct sum on fault */
+#define COPY_BYTE(N) \
+EXC( lbu t0, N(src), l_exc_copy); \
+ SUB len, len, 1; \
+EXC( sb t0, N(dst), s_exc); \
+ SLLV t0, t0, t3; \
+ addu t3, SHIFT_INC; \
+ beqz len, copy_bytes_done; \
+ or t2, t0
+
+ COPY_BYTE(0)
+ COPY_BYTE(1)
+#ifdef USE_DOUBLE
+ COPY_BYTE(2)
+ COPY_BYTE(3)
+ COPY_BYTE(4)
+ COPY_BYTE(5)
+#endif
+EXC( lbu t0, NBYTES-2(src), l_exc_copy)
+ SUB len, len, 1
+EXC( sb t0, NBYTES-2(dst), s_exc)
+ SLLV t0, t0, t3
+ or t2, t0
+copy_bytes_done:
+ ADDC(sum, t2)
+done:
+ /* fold checksum */
+#ifdef USE_DOUBLE
+ dsll32 v1, sum, 0
+ daddu sum, v1
+ sltu v1, sum, v1
+ dsra32 sum, sum, 0
+ addu sum, v1
+#endif
+ sll v1, sum, 16
+ addu sum, v1
+ sltu v1, sum, v1
+ srl sum, sum, 16
+ addu sum, v1
+
+ /* odd buffer alignment? */
+ beqz odd, 1f
+ nop
+ sll v1, sum, 8
+ srl sum, sum, 8
+ or sum, v1
+ andi sum, 0xffff
+1:
+ .set reorder
+ ADDC(sum, psum)
+ jr ra
+ .set noreorder
+
+l_exc_copy:
+ /*
+ * Copy bytes from src until faulting load address (or until a
+ * lb faults)
+ *
+ * When reached by a faulting LDFIRST/LDREST, THREAD_BUADDR($28)
+ * may be more than a byte beyond the last address.
+ * Hence, the lb below may get an exception.
+ *
+ * Assumes src < THREAD_BUADDR($28)
+ */
+ LOAD t0, TI_TASK($28)
+ li t2, SHIFT_START
+ LOAD t0, THREAD_BUADDR(t0)
+1:
+EXC( lbu t1, 0(src), l_exc)
+ ADD src, src, 1
+ sb t1, 0(dst) # can't fault -- we're copy_from_user
+ SLLV t1, t1, t2
+ addu t2, SHIFT_INC
+ ADDC(sum, t1)
+ bne src, t0, 1b
+ ADD dst, dst, 1
+l_exc:
+ LOAD t0, TI_TASK($28)
+ nop
+ LOAD t0, THREAD_BUADDR(t0) # t0 is just past last good address
+ nop
+ SUB len, AT, t0 # len number of uncopied bytes
+ /*
+ * Here's where we rely on src and dst being incremented in tandem,
+ * See (3) above.
+ * dst += (fault addr - src) to put dst at first byte to clear
+ */
+ ADD dst, t0 # compute start address in a1
+ SUB dst, src
+ /*
+ * Clear len bytes starting at dst. Can't call __bzero because it
+ * might modify len. An inefficient loop for these rare times...
+ */
+ beqz len, done
+ SUB src, len, 1
+1: sb zero, 0(dst)
+ ADD dst, dst, 1
+ bnez src, 1b
+ SUB src, src, 1
+ li v1, -EFAULT
+ b done
+ sw v1, (errptr)
+
+s_exc:
+ li v0, -1 /* invalid checksum */
+ li v1, -EFAULT
+ jr ra
+ sw v1, (errptr)
+ END(__csum_partial_copy_user)
diff --git a/arch/mips/lib/csum_partial_copy.c b/arch/mips/lib/csum_partial_copy.c
deleted file mode 100644
index 1720f2ceeea..00000000000
--- a/arch/mips/lib/csum_partial_copy.c
+++ /dev/null
@@ -1,49 +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) 1994, 1995 Waldorf Electronics GmbH
- * Copyright (C) 1998, 1999 Ralf Baechle
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/byteorder.h>
-#include <asm/string.h>
-#include <asm/uaccess.h>
-#include <net/checksum.h>
-
-/*
- * copy while checksumming, otherwise like csum_partial
- */
-__wsum csum_partial_copy_nocheck(const void *src,
- void *dst, int len, __wsum sum)
-{
- /*
- * It's 2:30 am and I don't feel like doing it real ...
- * This is lots slower than the real thing (tm)
- */
- sum = csum_partial(src, len, sum);
- memcpy(dst, src, len);
-
- return sum;
-}
-
-/*
- * Copy from userspace and compute checksum. If we catch an exception
- * then zero the rest of the buffer.
- */
-__wsum csum_partial_copy_from_user (const void __user *src,
- void *dst, int len, __wsum sum, int *err_ptr)
-{
- int missing;
-
- might_sleep();
- missing = copy_from_user(dst, src, len);
- if (missing) {
- memset(dst + len - missing, 0, missing);
- *err_ptr = -EFAULT;
- }
-
- return csum_partial(dst, len, sum);
-}
diff --git a/arch/mips/lib-32/memset.S b/arch/mips/lib/memset.S
index 1981485bd48..3f8b8b3d0b2 100644
--- a/arch/mips/lib-32/memset.S
+++ b/arch/mips/lib/memset.S
@@ -10,6 +10,14 @@
#include <asm/asm-offsets.h>
#include <asm/regdef.h>
+#if LONGSIZE == 4
+#define LONG_S_L swl
+#define LONG_S_R swr
+#else
+#define LONG_S_L sdl
+#define LONG_S_R sdr
+#endif
+
#define EX(insn,reg,addr,handler) \
9: insn reg, addr; \
.section __ex_table,"a"; \
@@ -25,6 +33,7 @@
EX(LONG_S, \val, (\offset + 5 * LONGSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 6 * LONGSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 7 * LONGSIZE)(\dst), \fixup)
+#if LONGSIZE == 4
EX(LONG_S, \val, (\offset + 8 * LONGSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 9 * LONGSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 10 * LONGSIZE)(\dst), \fixup)
@@ -33,6 +42,7 @@
EX(LONG_S, \val, (\offset + 13 * LONGSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 14 * LONGSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 15 * LONGSIZE)(\dst), \fixup)
+#endif
.endm
/*
@@ -49,9 +59,13 @@ LEAF(memset)
move v0, a0 /* result */
andi a1, 0xff /* spread fillword */
- sll t1, a1, 8
+ LONG_SLL t1, a1, 8
or a1, t1
- sll t1, a1, 16
+ LONG_SLL t1, a1, 16
+#if LONGSIZE == 8
+ or a1, t1
+ LONG_SLL t1, a1, 32
+#endif
or a1, t1
1:
@@ -64,10 +78,10 @@ FEXPORT(__bzero)
PTR_SUBU t0, LONGSIZE /* alignment in bytes */
#ifdef __MIPSEB__
- EX(swl, a1, (a0), first_fixup) /* make word aligned */
+ EX(LONG_S_L, a1, (a0), first_fixup) /* make word/dword aligned */
#endif
#ifdef __MIPSEL__
- EX(swr, a1, (a0), first_fixup) /* make word aligned */
+ EX(LONG_S_R, a1, (a0), first_fixup) /* make word/dword aligned */
#endif
PTR_SUBU a0, t0 /* long align ptr */
PTR_ADDU a2, t0 /* correct size */
@@ -75,7 +89,7 @@ FEXPORT(__bzero)
1: ori t1, a2, 0x3f /* # of full blocks */
xori t1, 0x3f
beqz t1, memset_partial /* no block to fill */
- andi t0, a2, 0x3c
+ andi t0, a2, 0x40-LONGSIZE
PTR_ADDU t1, a0 /* end address */
.set reorder
@@ -86,7 +100,14 @@ FEXPORT(__bzero)
memset_partial:
PTR_LA t1, 2f /* where to start */
+#if LONGSIZE == 4
PTR_SUBU t1, t0
+#else
+ .set noat
+ LONG_SRL AT, t0, 1
+ PTR_SUBU t1, AT
+ .set noat
+#endif
jr t1
PTR_ADDU a0, t0 /* dest ptr */
@@ -100,10 +121,10 @@ memset_partial:
beqz a2, 1f
PTR_ADDU a0, a2 /* What's left */
#ifdef __MIPSEB__
- EX(swr, a1, -1(a0), last_fixup)
+ EX(LONG_S_R, a1, -1(a0), last_fixup)
#endif
#ifdef __MIPSEL__
- EX(swl, a1, -1(a0), last_fixup)
+ EX(LONG_S_L, a1, -1(a0), last_fixup)
#endif
1: jr ra
move a2, zero
diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c
index 98ce89f8068..2388f7f3ffd 100644
--- a/arch/mips/lib/uncached.c
+++ b/arch/mips/lib/uncached.c
@@ -44,20 +44,24 @@ unsigned long __init run_uncached(void *func)
if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
usp = CKSEG1ADDR(sp);
+#ifdef CONFIG_64BIT
else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
(long long)sp < (long long)PHYS_TO_XKPHYS(8LL, 0))
usp = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
XKPHYS_TO_PHYS((long long)sp));
+#endif
else {
BUG();
usp = sp;
}
if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
ufunc = CKSEG1ADDR(lfunc);
+#ifdef CONFIG_64BIT
else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
(long long)lfunc < (long long)PHYS_TO_XKPHYS(8LL, 0))
ufunc = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
XKPHYS_TO_PHYS((long long)lfunc));
+#endif
else {
BUG();
ufunc = lfunc;
diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c
index 43dba6ce660..dfa0acbd7fc 100644
--- a/arch/mips/mips-boards/atlas/atlas_int.c
+++ b/arch/mips/mips-boards/atlas/atlas_int.c
@@ -32,6 +32,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <linux/kernel.h>
#include <asm/gdb-stub.h>
#include <asm/io.h>
@@ -69,7 +70,7 @@ static void end_atlas_irq(unsigned int irq)
}
static struct irq_chip atlas_irq_type = {
- .typename = "Atlas",
+ .name = "Atlas",
.ack = disable_atlas_irq,
.mask = disable_atlas_irq,
.mask_ack = disable_atlas_irq,
@@ -220,7 +221,7 @@ 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);
+int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap);
msc_irqmap_t __initdata msc_eicirqmap[] = {
{MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0},
@@ -231,14 +232,14 @@ msc_irqmap_t __initdata msc_eicirqmap[] = {
{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);
+int __initdata msc_nr_eicirqs = ARRAY_SIZE(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);
+ mips_cpu_irq_init();
switch(mips_revision_corid) {
case MIPS_REVISION_CORID_CORE_MSC:
diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c
index eeed944e0f8..ebf0e16c5a0 100644
--- a/arch/mips/mips-boards/generic/memory.c
+++ b/arch/mips/mips-boards/generic/memory.c
@@ -166,9 +166,8 @@ void __init prom_meminit(void)
}
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- unsigned long freed = 0;
unsigned long addr;
int i;
@@ -176,17 +175,8 @@ unsigned long __init prom_free_prom_memory(void)
if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
continue;
- addr = PAGE_ALIGN(boot_mem_map.map[i].addr);
- while (addr < boot_mem_map.map[i].addr
- + boot_mem_map.map[i].size) {
- ClearPageReserved(virt_to_page(__va(addr)));
- init_page_count(virt_to_page(__va(addr)));
- free_page((unsigned long)__va(addr));
- addr += PAGE_SIZE;
- freed += PAGE_SIZE;
- }
+ addr = boot_mem_map.map[i].addr;
+ free_init_pages("prom memory",
+ addr, addr + boot_mem_map.map[i].size);
}
- printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
-
- return freed;
}
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index e4604c73f02..a3c3a1d462b 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -47,6 +47,9 @@
#ifdef CONFIG_MIPS_MALTA
#include <asm/mips-boards/maltaint.h>
#endif
+#ifdef CONFIG_MIPS_SEAD
+#include <asm/mips-boards/seadint.h>
+#endif
unsigned long cpu_khz;
@@ -263,11 +266,13 @@ void __init mips_time_init(void)
void __init plat_timer_setup(struct irqaction *irq)
{
+#ifdef MSC01E_INT_BASE
if (cpu_has_veic) {
set_vi_handler (MSC01E_INT_CPUCTR, mips_timer_dispatch);
mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
- }
- else {
+ } else
+#endif
+ {
if (cpu_has_vint)
set_vi_handler (MIPSCPU_INT_CPUCTR, mips_timer_dispatch);
mips_cpu_timer_irq = MIPSCPU_INT_BASE + MIPSCPU_INT_CPUCTR;
diff --git a/arch/mips/mips-boards/malta/Makefile b/arch/mips/mips-boards/malta/Makefile
index 77ee5c6d33c..cb7f349b051 100644
--- a/arch/mips/mips-boards/malta/Makefile
+++ b/arch/mips/mips-boards/malta/Makefile
@@ -20,4 +20,5 @@
#
obj-y := malta_int.o malta_setup.o
+obj-$(CONFIG_MTD) += malta_mtd.o
obj-$(CONFIG_SMP) += malta_smp.o
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index 90ad5bf3e2f..3c206bb1716 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <linux/kernel.h>
#include <linux/random.h>
#include <asm/i8259.h>
@@ -289,7 +290,7 @@ 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_t);
+int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap);
msc_irqmap_t __initdata msc_eicirqmap[] = {
{MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0},
@@ -303,14 +304,14 @@ msc_irqmap_t __initdata msc_eicirqmap[] = {
{MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0}
};
-int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t);
+int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
void __init arch_init_irq(void)
{
init_i8259_irqs();
if (!cpu_has_veic)
- mips_cpu_irq_init (MIPSCPU_INT_BASE);
+ mips_cpu_irq_init();
switch(mips_revision_corid) {
case MIPS_REVISION_CORID_CORE_MSC:
diff --git a/arch/mips/mips-boards/malta/malta_mtd.c b/arch/mips/mips-boards/malta/malta_mtd.c
new file mode 100644
index 00000000000..8ad9bdf25dc
--- /dev/null
+++ b/arch/mips/mips-boards/malta/malta_mtd.c
@@ -0,0 +1,63 @@
+/*
+ * 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) 2006 MIPS Technologies, Inc.
+ * written by Ralf Baechle <ralf@linux-mips.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <mtd/mtd-abi.h>
+
+static struct mtd_partition malta_mtd_partitions[] = {
+ {
+ .name = "YAMON",
+ .offset = 0x0,
+ .size = 0x100000,
+ .mask_flags = MTD_WRITEABLE
+ }, {
+ .name = "User FS",
+ .offset = 0x100000,
+ .size = 0x2e0000
+ }, {
+ .name = "Board Config",
+ .offset = 0x3e0000,
+ .size = 0x020000,
+ .mask_flags = MTD_WRITEABLE
+ }
+};
+
+static struct physmap_flash_data malta_flash_data = {
+ .width = 4,
+ .nr_parts = ARRAY_SIZE(malta_mtd_partitions),
+ .parts = malta_mtd_partitions
+};
+
+static struct resource malta_flash_resource = {
+ .start = 0x1e000000,
+ .end = 0x1e3fffff,
+ .flags = IORESOURCE_MEM
+};
+
+static struct platform_device malta_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &malta_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &malta_flash_resource,
+};
+
+static int __init malta_mtd_init(void)
+{
+ platform_device_register(&malta_flash);
+
+ return 0;
+}
+
+module_init(malta_mtd_init)
diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c
index 282f3e52eea..56ea76679cd 100644
--- a/arch/mips/mips-boards/malta/malta_setup.c
+++ b/arch/mips/mips-boards/malta/malta_setup.c
@@ -21,13 +21,6 @@
#include <linux/pci.h>
#include <linux/screen_info.h>
-#ifdef CONFIG_MTD
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#endif
-
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
@@ -58,30 +51,6 @@ struct resource standard_io_resources[] = {
{ .name = "dma2", .start = 0xc0, .end = 0xdf, .flags = IORESOURCE_BUSY },
};
-#ifdef CONFIG_MTD
-static struct mtd_partition malta_mtd_partitions[] = {
- {
- .name = "YAMON",
- .offset = 0x0,
- .size = 0x100000,
- .mask_flags = MTD_WRITEABLE
- },
- {
- .name = "User FS",
- .offset = 0x100000,
- .size = 0x2e0000
- },
- {
- .name = "Board Config",
- .offset = 0x3e0000,
- .size = 0x020000,
- .mask_flags = MTD_WRITEABLE
- }
-};
-
-#define number_partitions (sizeof(malta_mtd_partitions)/sizeof(struct mtd_partition))
-#endif
-
const char *get_system_type(void)
{
return "MIPS Malta";
@@ -211,14 +180,6 @@ void __init plat_mem_setup(void)
#endif
#endif
-#ifdef CONFIG_MTD
- /*
- * Support for MTD on Malta. Use the generic physmap driver
- */
- physmap_configure(0x1e000000, 0x400000, 4, NULL);
- physmap_set_partitions(malta_mtd_partitions, number_partitions);
-#endif
-
mips_reboot_setup();
board_time_init = mips_time_init;
diff --git a/arch/mips/mips-boards/sead/sead_int.c b/arch/mips/mips-boards/sead/sead_int.c
index f445fcddfdf..c4b9de3a7f2 100644
--- a/arch/mips/mips-boards/sead/sead_int.c
+++ b/arch/mips/mips-boards/sead/sead_int.c
@@ -21,7 +21,7 @@
* Sead board.
*/
#include <linux/init.h>
-#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
@@ -108,10 +108,10 @@ asmlinkage void plat_irq_dispatch(void)
if (irq >= 0)
do_IRQ(MIPSCPU_INT_BASE + irq);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
void __init arch_init_irq(void)
{
- mips_cpu_irq_init(MIPSCPU_INT_BASE);
+ mips_cpu_irq_init();
}
diff --git a/arch/mips/mips-boards/sim/sim_int.c b/arch/mips/mips-boards/sim/sim_int.c
index 2ce449dce6f..15ac0655c1f 100644
--- a/arch/mips/mips-boards/sim/sim_int.c
+++ b/arch/mips/mips-boards/sim/sim_int.c
@@ -21,9 +21,7 @@
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <asm/mips-boards/simint.h>
-
-
-extern void mips_cpu_irq_init(int);
+#include <asm/irq_cpu.h>
static inline int clz(unsigned long x)
{
@@ -86,5 +84,5 @@ asmlinkage void plat_irq_dispatch(void)
void __init arch_init_irq(void)
{
- mips_cpu_irq_init(MIPSCPU_INT_BASE);
+ mips_cpu_irq_init();
}
diff --git a/arch/mips/mips-boards/sim/sim_mem.c b/arch/mips/mips-boards/sim/sim_mem.c
index f7ce7698332..46bc16f8b15 100644
--- a/arch/mips/mips-boards/sim/sim_mem.c
+++ b/arch/mips/mips-boards/sim/sim_mem.c
@@ -99,10 +99,9 @@ void __init prom_meminit(void)
}
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
int i;
- unsigned long freed = 0;
unsigned long addr;
for (i = 0; i < boot_mem_map.nr_map; i++) {
@@ -110,16 +109,7 @@ unsigned long __init prom_free_prom_memory(void)
continue;
addr = boot_mem_map.map[i].addr;
- while (addr < boot_mem_map.map[i].addr
- + boot_mem_map.map[i].size) {
- ClearPageReserved(virt_to_page(__va(addr)));
- init_page_count(virt_to_page(__va(addr)));
- free_page((unsigned long)__va(addr));
- addr += PAGE_SIZE;
- freed += PAGE_SIZE;
- }
+ free_init_pages("prom memory",
+ addr, addr + boot_mem_map.map[i].size);
}
- printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
-
- return freed;
}
diff --git a/arch/mips/mips-boards/sim/sim_setup.c b/arch/mips/mips-boards/sim/sim_setup.c
index 2659c1c3b78..ea2066c3a1f 100644
--- a/arch/mips/mips-boards/sim/sim_setup.c
+++ b/arch/mips/mips-boards/sim/sim_setup.c
@@ -57,7 +57,7 @@ void __init plat_mem_setup(void)
board_time_init = sim_time_init;
prom_printf("Linux started...\n");
-#ifdef CONFIG_MT_SMP
+#ifdef CONFIG_MIPS_MT_SMP
sanitize_tlb_entries();
#endif
}
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index caf807ded51..1f954a238a6 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -32,6 +32,7 @@ void (*local_flush_data_cache_page)(void * addr);
void (*flush_data_cache_page)(unsigned long addr);
void (*flush_icache_all)(void);
+EXPORT_SYMBOL_GPL(local_flush_data_cache_page);
EXPORT_SYMBOL(flush_data_cache_page);
#ifdef CONFIG_DMA_NONCOHERENT
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 9e29ba9205f..125a4a85ec0 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -203,6 +203,31 @@ static inline void kunmap_coherent(struct page *page)
preempt_check_resched();
}
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma)
+{
+ void *vfrom, *vto;
+
+ vto = kmap_atomic(to, KM_USER1);
+ if (cpu_has_dc_aliases) {
+ vfrom = kmap_coherent(from, vaddr);
+ copy_page(vto, vfrom);
+ kunmap_coherent(from);
+ } else {
+ vfrom = kmap_atomic(from, KM_USER0);
+ copy_page(vto, vfrom);
+ kunmap_atomic(vfrom, KM_USER0);
+ }
+ if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) ||
+ pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
+ flush_data_cache_page((unsigned long)vto);
+ kunmap_atomic(vto, KM_USER1);
+ /* Make sure this page is cleared on other CPU's too before using it */
+ smp_wmb();
+}
+
+EXPORT_SYMBOL(copy_user_highpage);
+
void copy_to_user_page(struct vm_area_struct *vma,
struct page *page, unsigned long vaddr, void *dst, const void *src,
unsigned long len)
@@ -316,7 +341,6 @@ static int __init page_is_ram(unsigned long pagenr)
void __init paging_init(void)
{
unsigned long zones_size[MAX_NR_ZONES] = { 0, };
- unsigned long max_dma, high, low;
#ifndef CONFIG_FLATMEM
unsigned long zholes_size[MAX_NR_ZONES] = { 0, };
unsigned long i, j, pfn;
@@ -329,28 +353,27 @@ void __init paging_init(void)
#endif
kmap_coherent_init();
- max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
- low = max_low_pfn;
- high = highend_pfn;
-
#ifdef CONFIG_ISA
- if (low < max_dma)
- zones_size[ZONE_DMA] = low;
- else {
- zones_size[ZONE_DMA] = max_dma;
- zones_size[ZONE_NORMAL] = low - max_dma;
- }
-#else
- zones_size[ZONE_DMA] = low;
+ if (max_low_pfn >= MAX_DMA_PFN)
+ if (min_low_pfn >= MAX_DMA_PFN) {
+ zones_size[ZONE_DMA] = 0;
+ zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
+ } else {
+ zones_size[ZONE_DMA] = MAX_DMA_PFN - min_low_pfn;
+ zones_size[ZONE_NORMAL] = max_low_pfn - MAX_DMA_PFN;
+ }
+ else
#endif
+ zones_size[ZONE_DMA] = max_low_pfn - min_low_pfn;
+
#ifdef CONFIG_HIGHMEM
- if (cpu_has_dc_aliases) {
- printk(KERN_WARNING "This processor doesn't support highmem.");
- if (high - low)
- printk(" %ldk highmem ignored", high - low);
- printk("\n");
- } else
- zones_size[ZONE_HIGHMEM] = high - low;
+ zones_size[ZONE_HIGHMEM] = highend_pfn - highstart_pfn;
+
+ if (cpu_has_dc_aliases && zones_size[ZONE_HIGHMEM]) {
+ printk(KERN_WARNING "This processor doesn't support highmem."
+ " %ldk highmem ignored\n", zones_size[ZONE_HIGHMEM]);
+ zones_size[ZONE_HIGHMEM] = 0;
+ }
#endif
#ifdef CONFIG_FLATMEM
@@ -443,7 +466,7 @@ void __init mem_init(void)
}
#endif /* !CONFIG_NEED_MULTIPLE_NODES */
-static void free_init_pages(char *what, unsigned long begin, unsigned long end)
+void free_init_pages(const char *what, unsigned long begin, unsigned long end)
{
unsigned long pfn;
@@ -469,17 +492,25 @@ void free_initrd_mem(unsigned long start, unsigned long end)
}
#endif
-extern unsigned long prom_free_prom_memory(void);
-
void free_initmem(void)
{
- unsigned long freed;
-
- freed = prom_free_prom_memory();
- if (freed)
- printk(KERN_INFO "Freeing firmware memory: %ldk freed\n",freed);
-
+ prom_free_prom_memory();
free_init_pages("unused kernel memory",
__pa_symbol(&__init_begin),
__pa_symbol(&__init_end));
}
+
+unsigned long pgd_current[NR_CPUS];
+/*
+ * On 64-bit we've got three-level pagetables with a slightly
+ * different layout ...
+ */
+#define __page_aligned(order) __attribute__((__aligned__(PAGE_SIZE<<order)))
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned(PGD_ORDER);
+#ifdef CONFIG_64BIT
+#ifdef MODULE_START
+pgd_t module_pg_dir[PTRS_PER_PGD] __page_aligned(PGD_ORDER);
+#endif
+pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned(PMD_ORDER);
+#endif
+pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned(PTE_ORDER);
diff --git a/arch/mips/mm/ioremap.c b/arch/mips/mm/ioremap.c
index cea7d0ea36e..fc2c96f0a1f 100644
--- a/arch/mips/mm/ioremap.c
+++ b/arch/mips/mm/ioremap.c
@@ -6,98 +6,13 @@
* (C) Copyright 1995 1996 Linus Torvalds
* (C) Copyright 2001, 2002 Ralf Baechle
*/
+#include <linux/mm.h>
#include <linux/module.h>
#include <asm/addrspace.h>
#include <asm/byteorder.h>
#include <linux/vmalloc.h>
-#include <asm/cacheflush.h>
-#include <asm/io.h>
-#include <asm/tlbflush.h>
-
-static inline void remap_area_pte(pte_t * pte, unsigned long address,
- phys_t size, phys_t phys_addr, unsigned long flags)
-{
- phys_t end;
- unsigned long pfn;
- pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE
- | __WRITEABLE | 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,
- phys_t size, phys_t phys_addr, unsigned long flags)
-{
- phys_t 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, phys_t phys_addr,
- phys_t 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 {
- 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, flags))
- break;
- error = 0;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
- flush_tlb_all();
- return error;
-}
+#include <linux/io.h>
/*
* Generic mapping function (not visible outside):
@@ -121,6 +36,7 @@ void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
unsigned long offset;
phys_t last_addr;
void * addr;
+ pgprot_t pgprot;
phys_addr = fixup_bigphys_addr(phys_addr, size);
@@ -152,6 +68,9 @@ void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
return NULL;
}
+ pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE
+ | __WRITEABLE | flags);
+
/*
* Mappings have to be page-aligned
*/
@@ -166,7 +85,8 @@ void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
if (!area)
return NULL;
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)) {
vunmap(addr);
return NULL;
}
diff --git a/arch/mips/mm/pg-r4k.c b/arch/mips/mm/pg-r4k.c
index d41fc5885e8..dc795be6280 100644
--- a/arch/mips/mm/pg-r4k.c
+++ b/arch/mips/mm/pg-r4k.c
@@ -243,11 +243,10 @@ static void __init __build_store_reg(int reg)
static inline void build_store_reg(int reg)
{
- if (cpu_has_prefetch)
- if (reg)
- build_dst_pref(pref_offset_copy);
- else
- build_dst_pref(pref_offset_clear);
+ int pref_off = cpu_has_prefetch ?
+ (reg ? pref_offset_copy : pref_offset_clear) : 0;
+ if (pref_off)
+ build_dst_pref(pref_off);
else if (cpu_has_cache_cdex_s)
build_cdex_s();
else if (cpu_has_cache_cdex_p)
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 2e0e21ef433..65160d4984d 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -106,7 +106,6 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
ENTER_CRITICAL(flags);
size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
size = (size + 1) >> 1;
- local_irq_save(flags);
if (size <= current_cpu_data.tlbsize/2) {
int oldpid = read_c0_entryhi();
int newpid = cpu_asid(cpu, mm);
diff --git a/arch/mips/momentum/jaguar_atx/Makefile b/arch/mips/momentum/jaguar_atx/Makefile
index 67372f3f965..2e8cebd49bc 100644
--- a/arch/mips/momentum/jaguar_atx/Makefile
+++ b/arch/mips/momentum/jaguar_atx/Makefile
@@ -6,7 +6,7 @@
# unless it's something special (ie not a .c file).
#
-obj-y += irq.o prom.o reset.o setup.o
+obj-y += irq.o platform.o prom.o reset.o setup.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o
obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
diff --git a/arch/mips/momentum/jaguar_atx/irq.c b/arch/mips/momentum/jaguar_atx/irq.c
index 2efb25aa1ae..f2b432585df 100644
--- a/arch/mips/momentum/jaguar_atx/irq.c
+++ b/arch/mips/momentum/jaguar_atx/irq.c
@@ -82,8 +82,8 @@ void __init arch_init_irq(void)
*/
clear_c0_status(ST0_IM);
- mips_cpu_irq_init(0);
- rm7k_cpu_irq_init(8);
+ mips_cpu_irq_init();
+ rm7k_cpu_irq_init();
/* set up the cascading interrupts */
setup_irq(8, &cascade_mv64340);
diff --git a/arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h b/arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h
index 6978654c712..022f6974b76 100644
--- a/arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h
+++ b/arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h
@@ -46,7 +46,9 @@
extern unsigned long ja_fpga_base;
-#define JAGUAR_FPGA_WRITE(x,y) writeb(x, ja_fpga_base + JAGUAR_ATX_REG_##y)
-#define JAGUAR_FPGA_READ(x) readb(ja_fpga_base + JAGUAR_ATX_REG_##x)
+#define __FPGA_REG_TO_ADDR(reg) \
+ ((void *) ja_fpga_base + JAGUAR_ATX_REG_##reg)
+#define JAGUAR_FPGA_WRITE(x, reg) writeb(x, __FPGA_REG_TO_ADDR(reg))
+#define JAGUAR_FPGA_READ(reg) readb(__FPGA_REG_TO_ADDR(reg))
#endif
diff --git a/arch/mips/momentum/jaguar_atx/platform.c b/arch/mips/momentum/jaguar_atx/platform.c
new file mode 100644
index 00000000000..035ea5137c7
--- /dev/null
+++ b/arch/mips/momentum/jaguar_atx/platform.c
@@ -0,0 +1,235 @@
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/ioport.h>
+#include <linux/mv643xx.h>
+#include <linux/platform_device.h>
+
+#include "jaguar_atx_fpga.h"
+
+#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)
+
+static struct resource mv643xx_eth_shared_resources[] = {
+ [0] = {
+ .name = "ethernet shared base",
+ .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS,
+ .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS +
+ MV643XX_ETH_SHARED_REGS_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device mv643xx_eth_shared_device = {
+ .name = MV643XX_ETH_SHARED_NAME,
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources),
+ .resource = mv643xx_eth_shared_resources,
+};
+
+#define MV_SRAM_BASE 0xfe000000UL
+#define MV_SRAM_SIZE (256 * 1024)
+
+#define MV_SRAM_RXRING_SIZE (MV_SRAM_SIZE / 4)
+#define MV_SRAM_TXRING_SIZE (MV_SRAM_SIZE / 4)
+
+#define MV_SRAM_BASE_ETH0 MV_SRAM_BASE
+#define MV_SRAM_BASE_ETH1 (MV_SRAM_BASE + (MV_SRAM_SIZE / 2))
+
+#define MV64x60_IRQ_ETH_0 48
+#define MV64x60_IRQ_ETH_1 49
+#define MV64x60_IRQ_ETH_2 50
+
+#ifdef CONFIG_MV643XX_ETH_0
+
+static struct resource mv64x60_eth0_resources[] = {
+ [0] = {
+ .name = "eth0 irq",
+ .start = MV64x60_IRQ_ETH_0,
+ .end = MV64x60_IRQ_ETH_0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static char eth0_mac_addr[ETH_ALEN];
+
+static struct mv643xx_eth_platform_data eth0_pd = {
+ .mac_addr = eth0_mac_addr,
+
+ .tx_sram_addr = MV_SRAM_BASE_ETH0,
+ .tx_sram_size = MV_SRAM_TXRING_SIZE,
+ .tx_queue_size = MV_SRAM_TXRING_SIZE / 16,
+
+ .rx_sram_addr = MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE,
+ .rx_sram_size = MV_SRAM_RXRING_SIZE,
+ .rx_queue_size = MV_SRAM_RXRING_SIZE / 16,
+};
+
+static struct platform_device eth0_device = {
+ .name = MV643XX_ETH_NAME,
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mv64x60_eth0_resources),
+ .resource = mv64x60_eth0_resources,
+ .dev = {
+ .platform_data = &eth0_pd,
+ },
+};
+#endif /* CONFIG_MV643XX_ETH_0 */
+
+#ifdef CONFIG_MV643XX_ETH_1
+
+static struct resource mv64x60_eth1_resources[] = {
+ [0] = {
+ .name = "eth1 irq",
+ .start = MV64x60_IRQ_ETH_1,
+ .end = MV64x60_IRQ_ETH_1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static char eth1_mac_addr[ETH_ALEN];
+
+static struct mv643xx_eth_platform_data eth1_pd = {
+ .mac_addr = eth1_mac_addr,
+
+ .tx_sram_addr = MV_SRAM_BASE_ETH1,
+ .tx_sram_size = MV_SRAM_TXRING_SIZE,
+ .tx_queue_size = MV_SRAM_TXRING_SIZE / 16,
+
+ .rx_sram_addr = MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE,
+ .rx_sram_size = MV_SRAM_RXRING_SIZE,
+ .rx_queue_size = MV_SRAM_RXRING_SIZE / 16,
+};
+
+static struct platform_device eth1_device = {
+ .name = MV643XX_ETH_NAME,
+ .id = 1,
+ .num_resources = ARRAY_SIZE(mv64x60_eth1_resources),
+ .resource = mv64x60_eth1_resources,
+ .dev = {
+ .platform_data = &eth1_pd,
+ },
+};
+#endif /* CONFIG_MV643XX_ETH_1 */
+
+#ifdef CONFIG_MV643XX_ETH_2
+
+static struct resource mv64x60_eth2_resources[] = {
+ [0] = {
+ .name = "eth2 irq",
+ .start = MV64x60_IRQ_ETH_2,
+ .end = MV64x60_IRQ_ETH_2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static char eth2_mac_addr[ETH_ALEN];
+
+static struct mv643xx_eth_platform_data eth2_pd = {
+ .mac_addr = eth2_mac_addr,
+};
+
+static struct platform_device eth2_device = {
+ .name = MV643XX_ETH_NAME,
+ .id = 1,
+ .num_resources = ARRAY_SIZE(mv64x60_eth2_resources),
+ .resource = mv64x60_eth2_resources,
+ .dev = {
+ .platform_data = &eth2_pd,
+ },
+};
+#endif /* CONFIG_MV643XX_ETH_2 */
+
+static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
+ &mv643xx_eth_shared_device,
+#ifdef CONFIG_MV643XX_ETH_0
+ &eth0_device,
+#endif
+#ifdef CONFIG_MV643XX_ETH_1
+ &eth1_device,
+#endif
+#ifdef CONFIG_MV643XX_ETH_2
+ &eth2_device,
+#endif
+};
+
+static u8 __init exchange_bit(u8 val, u8 cs)
+{
+ /* place the data */
+ JAGUAR_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
+ udelay(1);
+
+ /* turn the clock on */
+ JAGUAR_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
+ udelay(1);
+
+ /* turn the clock off and read-strobe */
+ JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
+
+ /* return the data */
+ return (JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1;
+}
+
+static void __init get_mac(char dest[6])
+{
+ u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ int i,j;
+
+ for (i = 0; i < 12; i++)
+ exchange_bit(read_opcode[i], 1);
+
+ for (j = 0; j < 6; j++) {
+ dest[j] = 0;
+ for (i = 0; i < 8; i++) {
+ dest[j] <<= 1;
+ dest[j] |= exchange_bit(0, 1);
+ }
+ }
+
+ /* turn off CS */
+ exchange_bit(0,0);
+}
+
+/*
+ * Copy and increment ethernet MAC address by a small value.
+ *
+ * This is useful for systems where the only one MAC address is stored in
+ * non-volatile memory for multiple ports.
+ */
+static inline void eth_mac_add(unsigned char *dst, unsigned char *src,
+ unsigned int add)
+{
+ int i;
+
+ BUG_ON(add >= 256);
+
+ for (i = ETH_ALEN; i >= 0; i--) {
+ dst[i] = src[i] + add;
+ add = dst[i] < src[i]; /* compute carry */
+ }
+
+ WARN_ON(add);
+}
+
+static int __init mv643xx_eth_add_pds(void)
+{
+ unsigned char mac[ETH_ALEN];
+ int ret;
+
+ get_mac(mac);
+#ifdef CONFIG_MV643XX_ETH_0
+ eth_mac_add(eth1_mac_addr, mac, 0);
+#endif
+#ifdef CONFIG_MV643XX_ETH_1
+ eth_mac_add(eth1_mac_addr, mac, 1);
+#endif
+#ifdef CONFIG_MV643XX_ETH_2
+ eth_mac_add(eth2_mac_addr, mac, 2);
+#endif
+ ret = platform_add_devices(mv643xx_eth_pd_devs,
+ ARRAY_SIZE(mv643xx_eth_pd_devs));
+
+ return ret;
+}
+
+device_initcall(mv643xx_eth_add_pds);
+
+#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */
diff --git a/arch/mips/momentum/jaguar_atx/prom.c b/arch/mips/momentum/jaguar_atx/prom.c
index 3d271292929..5dd154ee58f 100644
--- a/arch/mips/momentum/jaguar_atx/prom.c
+++ b/arch/mips/momentum/jaguar_atx/prom.c
@@ -39,56 +39,6 @@ const char *get_system_type(void)
return "Momentum Jaguar-ATX";
}
-#ifdef CONFIG_MV643XX_ETH
-extern unsigned char prom_mac_addr_base[6];
-
-static void burn_clocks(void)
-{
- int i;
-
- /* this loop should burn at least 1us -- this should be plenty */
- for (i = 0; i < 0x10000; i++)
- ;
-}
-
-static u8 exchange_bit(u8 val, u8 cs)
-{
- /* place the data */
- JAGUAR_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
- burn_clocks();
-
- /* turn the clock on */
- JAGUAR_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
- burn_clocks();
-
- /* turn the clock off and read-strobe */
- JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
-
- /* return the data */
- return ((JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
-}
-
-void get_mac(char dest[6])
-{
- u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- int i,j;
-
- for (i = 0; i < 12; i++)
- exchange_bit(read_opcode[i], 1);
-
- for (j = 0; j < 6; j++) {
- dest[j] = 0;
- for (i = 0; i < 8; i++) {
- dest[j] <<= 1;
- dest[j] |= exchange_bit(0, 1);
- }
- }
-
- /* turn off CS */
- exchange_bit(0,0);
-}
-#endif
-
#ifdef CONFIG_64BIT
unsigned long signext(unsigned long addr)
@@ -228,16 +178,10 @@ void __init prom_init(void)
#endif /* CONFIG_64BIT */
mips_machgroup = MACH_GROUP_MOMENCO;
mips_machtype = MACH_MOMENCO_JAGUAR_ATX;
-
-#ifdef CONFIG_MV643XX_ETH
- /* get the base MAC address for on-board ethernet ports */
- get_mac(prom_mac_addr_base);
-#endif
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
diff --git a/arch/mips/momentum/ocelot_3/irq.c b/arch/mips/momentum/ocelot_3/irq.c
index cea0e5deb80..3862d1d1add 100644
--- a/arch/mips/momentum/ocelot_3/irq.c
+++ b/arch/mips/momentum/ocelot_3/irq.c
@@ -65,7 +65,7 @@ void __init arch_init_irq(void)
*/
clear_c0_status(ST0_IM | ST0_BEV);
- rm7k_cpu_irq_init(8);
+ rm7k_cpu_irq_init();
/* set up the cascading interrupts */
setup_irq(8, &cascade_mv64340); /* unmask intControl IM8, IRQ 9 */
diff --git a/arch/mips/momentum/ocelot_3/prom.c b/arch/mips/momentum/ocelot_3/prom.c
index 6ce9b7fdb82..8e02df63578 100644
--- a/arch/mips/momentum/ocelot_3/prom.c
+++ b/arch/mips/momentum/ocelot_3/prom.c
@@ -180,9 +180,8 @@ void __init prom_init(void)
#endif
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
diff --git a/arch/mips/momentum/ocelot_c/cpci-irq.c b/arch/mips/momentum/ocelot_c/cpci-irq.c
index bb11fef0847..186a140fd2a 100644
--- a/arch/mips/momentum/ocelot_c/cpci-irq.c
+++ b/arch/mips/momentum/ocelot_c/cpci-irq.c
@@ -84,7 +84,7 @@ void ll_cpci_irq(void)
}
struct irq_chip cpci_irq_type = {
- .typename = "CPCI/FPGA",
+ .name = "CPCI/FPGA",
.ack = mask_cpci_irq,
.mask = mask_cpci_irq,
.mask_ack = mask_cpci_irq,
diff --git a/arch/mips/momentum/ocelot_c/dbg_io.c b/arch/mips/momentum/ocelot_c/dbg_io.c
index 2128684584f..32d6fb4ee67 100644
--- a/arch/mips/momentum/ocelot_c/dbg_io.c
+++ b/arch/mips/momentum/ocelot_c/dbg_io.c
@@ -1,6 +1,4 @@
-#ifdef CONFIG_KGDB
-
#include <asm/serial.h> /* For the serial port location and base baud */
/* --- CONFIG --- */
@@ -121,5 +119,3 @@ int putDebugChar(uint8 byte)
UART16550_WRITE(OFS_SEND_BUFFER, byte);
return 1;
}
-
-#endif
diff --git a/arch/mips/momentum/ocelot_c/irq.c b/arch/mips/momentum/ocelot_c/irq.c
index ea65223a6d2..40472f7944d 100644
--- a/arch/mips/momentum/ocelot_c/irq.c
+++ b/arch/mips/momentum/ocelot_c/irq.c
@@ -94,7 +94,7 @@ void __init arch_init_irq(void)
*/
clear_c0_status(ST0_IM);
- mips_cpu_irq_init(0);
+ mips_cpu_irq_init();
/* set up the cascading interrupts */
setup_irq(3, &cascade_fpga);
diff --git a/arch/mips/momentum/ocelot_c/prom.c b/arch/mips/momentum/ocelot_c/prom.c
index d0b77e101d7..b689ceea8cf 100644
--- a/arch/mips/momentum/ocelot_c/prom.c
+++ b/arch/mips/momentum/ocelot_c/prom.c
@@ -178,7 +178,6 @@ void __init prom_init(void)
#endif
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
diff --git a/arch/mips/momentum/ocelot_c/uart-irq.c b/arch/mips/momentum/ocelot_c/uart-irq.c
index a7a80c0da56..de1a31ee52f 100644
--- a/arch/mips/momentum/ocelot_c/uart-irq.c
+++ b/arch/mips/momentum/ocelot_c/uart-irq.c
@@ -77,7 +77,7 @@ void ll_uart_irq(void)
}
struct irq_chip uart_irq_type = {
- .typename = "UART/FPGA",
+ .name = "UART/FPGA",
.ack = mask_uart_irq,
.mask = mask_uart_irq,
.mask_ack = mask_uart_irq,
diff --git a/arch/mips/momentum/ocelot_g/dbg_io.c b/arch/mips/momentum/ocelot_g/dbg_io.c
index 2128684584f..32d6fb4ee67 100644
--- a/arch/mips/momentum/ocelot_g/dbg_io.c
+++ b/arch/mips/momentum/ocelot_g/dbg_io.c
@@ -1,6 +1,4 @@
-#ifdef CONFIG_KGDB
-
#include <asm/serial.h> /* For the serial port location and base baud */
/* --- CONFIG --- */
@@ -121,5 +119,3 @@ int putDebugChar(uint8 byte)
UART16550_WRITE(OFS_SEND_BUFFER, byte);
return 1;
}
-
-#endif
diff --git a/arch/mips/momentum/ocelot_g/irq.c b/arch/mips/momentum/ocelot_g/irq.c
index da46524e87c..273541fe708 100644
--- a/arch/mips/momentum/ocelot_g/irq.c
+++ b/arch/mips/momentum/ocelot_g/irq.c
@@ -94,8 +94,8 @@ void __init arch_init_irq(void)
clear_c0_status(ST0_IM);
local_irq_disable();
- mips_cpu_irq_init(0);
- rm7k_cpu_irq_init(8);
+ mips_cpu_irq_init();
+ rm7k_cpu_irq_init();
gt64240_irq_init();
}
diff --git a/arch/mips/momentum/ocelot_g/prom.c b/arch/mips/momentum/ocelot_g/prom.c
index 6509a9c9863..836d0830720 100644
--- a/arch/mips/momentum/ocelot_g/prom.c
+++ b/arch/mips/momentum/ocelot_g/prom.c
@@ -28,7 +28,7 @@ struct callvectors* debug_vectors;
extern unsigned long marvell_base;
extern unsigned long bus_clock;
-#ifdef CONFIG_GALILLEO_GT64240_ETH
+#ifdef CONFIG_GALILEO_GT64240_ETH
extern unsigned char prom_mac_addr_base[6];
#endif
@@ -61,7 +61,7 @@ void __init prom_init(void)
mips_machgroup = MACH_GROUP_MOMENCO;
mips_machtype = MACH_MOMENCO_OCELOT_G;
-#ifdef CONFIG_GALILLEO_GT64240_ETH
+#ifdef CONFIG_GALILEO_GT64240_ETH
/* get the base MAC address for on-board ethernet ports */
memcpy(prom_mac_addr_base, (void*)0xfc807cf2, 6);
#endif
@@ -79,7 +79,6 @@ void __init prom_init(void)
}
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
diff --git a/arch/mips/momentum/ocelot_g/setup.c b/arch/mips/momentum/ocelot_g/setup.c
index d288f7b0184..9db638a7982 100644
--- a/arch/mips/momentum/ocelot_g/setup.c
+++ b/arch/mips/momentum/ocelot_g/setup.c
@@ -64,7 +64,7 @@
#include "ocelot_pld.h"
-#ifdef CONFIG_GALILLEO_GT64240_ETH
+#ifdef CONFIG_GALILEO_GT64240_ETH
extern unsigned char prom_mac_addr_base[6];
#endif
@@ -185,7 +185,7 @@ void __init plat_mem_setup(void)
/* do handoff reconfiguration */
PMON_v2_setup();
-#ifdef CONFIG_GALILLEO_GT64240_ETH
+#ifdef CONFIG_GALILEO_GT64240_ETH
/* get the mac addr */
memcpy(prom_mac_addr_base, (void*)0xfc807cf2, 6);
#endif
diff --git a/arch/mips/oprofile/Kconfig b/arch/mips/oprofile/Kconfig
index 55feaf79859..ca395ef06d4 100644
--- a/arch/mips/oprofile/Kconfig
+++ b/arch/mips/oprofile/Kconfig
@@ -11,7 +11,7 @@ config PROFILING
config OPROFILE
tristate "OProfile system profiling (EXPERIMENTAL)"
- depends on PROFILING && EXPERIMENTAL
+ depends on PROFILING && !!MIPS_MT_SMTC && EXPERIMENTAL
help
OProfile is a profiling system capable of profiling the
whole system, include the kernel, kernel modules, libraries,
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 70cb55b89df..82b20c28bef 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -43,7 +43,7 @@ obj-$(CONFIG_SGI_IP32) += fixup-ip32.o ops-mace.o pci-ip32.o
obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o
obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o
obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o
-obj-$(CONFIG_SNI_RM200_PCI) += fixup-sni.o ops-sni.o
+obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o
obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o
obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o
obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o
diff --git a/arch/mips/pci/fixup-pnx8550.c b/arch/mips/pci/fixup-pnx8550.c
index 4256b3b30b7..50546dab668 100644
--- a/arch/mips/pci/fixup-pnx8550.c
+++ b/arch/mips/pci/fixup-pnx8550.c
@@ -33,7 +33,7 @@
#define DBG(x...)
#endif
-extern char irq_tab_jbs[][5];
+extern char pnx8550_irq_tab[][5];
void __init pcibios_fixup_resources(struct pci_dev *dev)
{
@@ -47,7 +47,7 @@ void __init pcibios_fixup(void)
int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
- return irq_tab_jbs[slot][pin];
+ return pnx8550_irq_tab[slot][pin];
}
/* Do platform specific device initialization at pci_enable_device() time */
diff --git a/arch/mips/pci/fixup-vr4133.c b/arch/mips/pci/fixup-vr4133.c
index 597b89764ba..a8d9d22b13d 100644
--- a/arch/mips/pci/fixup-vr4133.c
+++ b/arch/mips/pci/fixup-vr4133.c
@@ -17,8 +17,10 @@
*/
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/kernel.h>
#include <asm/io.h>
+#include <asm/i8259.h>
#include <asm/vr41xx/cmbvr4133.h>
extern int vr4133_rockhopper;
@@ -142,7 +144,7 @@ int rockhopper_get_irq(struct pci_dev *dev, u8 pin, u8 slot)
if (bus == NULL)
return -1;
- for (i = 0; i < sizeof (int_map) / sizeof (int_map[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(int_map); i++) {
if (int_map[i].bus == bus->number && int_map[i].slot == slot) {
int line;
for (line = 0; line < 4; line++)
@@ -160,17 +162,7 @@ int rockhopper_get_irq(struct pci_dev *dev, u8 pin, u8 slot)
#ifdef CONFIG_ROCKHOPPER
void i8259_init(void)
{
- outb(0x11, 0x20); /* Master ICW1 */
- outb(I8259_IRQ_BASE, 0x21); /* Master ICW2 */
- outb(0x04, 0x21); /* Master ICW3 */
- outb(0x01, 0x21); /* Master ICW4 */
- outb(0xff, 0x21); /* Master IMW */
-
- outb(0x11, 0xa0); /* Slave ICW1 */
- outb(I8259_IRQ_BASE + 8, 0xa1); /* Slave ICW2 */
- outb(0x02, 0xa1); /* Slave ICW3 */
- outb(0x01, 0xa1); /* Slave ICW4 */
- outb(0xff, 0xa1); /* Slave IMW */
+ init_i8259_irqs();
outb(0x00, 0x4d0);
outb(0x02, 0x4d1); /* USB IRQ9 is level */
diff --git a/arch/mips/pci/ops-pnx8550.c b/arch/mips/pci/ops-pnx8550.c
index 454b65cc335..f556b7a8dcc 100644
--- a/arch/mips/pci/ops-pnx8550.c
+++ b/arch/mips/pci/ops-pnx8550.c
@@ -202,7 +202,7 @@ write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val)
break;
}
- err = config_access(PCI_CMD_CONFIG_READ, bus, devfn, where, ~(1 << (where & 3)), &data);
+ err = config_access(PCI_CMD_CONFIG_WRITE, bus, devfn, where, ~(1 << (where & 3)), &data);
return err;
}
diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c
index 2c36c108c4d..d48665ebd33 100644
--- a/arch/mips/philips/pnx8550/common/int.c
+++ b/arch/mips/philips/pnx8550/common/int.c
@@ -159,7 +159,7 @@ int pnx8550_set_gic_priority(int irq, int priority)
}
static struct irq_chip level_irq_type = {
- .typename = "PNX Level IRQ",
+ .name = "PNX Level IRQ",
.ack = mask_irq,
.mask = mask_irq,
.mask_ack = mask_irq,
diff --git a/arch/mips/philips/pnx8550/common/prom.c b/arch/mips/philips/pnx8550/common/prom.c
index f8952c1359c..8aeed6c2b8c 100644
--- a/arch/mips/philips/pnx8550/common/prom.c
+++ b/arch/mips/philips/pnx8550/common/prom.c
@@ -35,23 +35,15 @@ char * prom_getcmdline(void)
return &(arcs_cmdline[0]);
}
-void prom_init_cmdline(void)
+void __init prom_init_cmdline(void)
{
- char *cp;
- int actr;
-
- actr = 1; /* Always ignore argv[0] */
+ int i;
- cp = &(arcs_cmdline[0]);
- while(actr < prom_argc) {
- strcpy(cp, prom_argv[actr]);
- cp += strlen(prom_argv[actr]);
- *cp++ = ' ';
- actr++;
+ arcs_cmdline[0] = '\0';
+ for (i = 0; i < prom_argc; i++) {
+ strcat(arcs_cmdline, prom_argv[i]);
+ strcat(arcs_cmdline, " ");
}
- if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
- --cp;
- *cp = '\0';
}
char *prom_getenv(char *envname)
@@ -114,9 +106,8 @@ int get_ethernet_addr(char *ethernet_addr)
return 0;
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
extern int pnx8550_console_port;
diff --git a/arch/mips/philips/pnx8550/common/time.c b/arch/mips/philips/pnx8550/common/time.c
index 65c440e8480..68def3880a1 100644
--- a/arch/mips/philips/pnx8550/common/time.c
+++ b/arch/mips/philips/pnx8550/common/time.c
@@ -33,7 +33,17 @@
#include <int.h>
#include <cm.h>
-extern unsigned int mips_hpt_frequency;
+static unsigned long cpj;
+
+static cycle_t hpt_read(void)
+{
+ return read_c0_count2();
+}
+
+static void timer_ack(void)
+{
+ write_c0_compare(cpj);
+}
/*
* pnx8550_time_init() - it does the following things:
@@ -68,27 +78,48 @@ void pnx8550_time_init(void)
* HZ timer interrupts per second.
*/
mips_hpt_frequency = 27UL * ((1000000UL * n)/(m * pow2p));
+ cpj = (mips_hpt_frequency + HZ / 2) / HZ;
+ write_c0_count(0);
+ timer_ack();
+
+ /* Setup Timer 2 */
+ write_c0_count2(0);
+ write_c0_compare2(0xffffffff);
+
+ clocksource_mips.read = hpt_read;
+ mips_timer_ack = timer_ack;
+}
+
+static irqreturn_t monotonic_interrupt(int irq, void *dev_id)
+{
+ /* Timer 2 clear interrupt */
+ write_c0_compare2(-1);
+ return IRQ_HANDLED;
}
+static struct irqaction monotonic_irqaction = {
+ .handler = monotonic_interrupt,
+ .flags = IRQF_DISABLED,
+ .name = "Monotonic timer",
+};
+
void __init plat_timer_setup(struct irqaction *irq)
{
int configPR;
setup_irq(PNX8550_INT_TIMER1, irq);
+ setup_irq(PNX8550_INT_TIMER2, &monotonic_irqaction);
- /* Start timer1 */
+ /* Timer 1 start */
configPR = read_c0_config7();
configPR &= ~0x00000008;
write_c0_config7(configPR);
- /* Timer 2 stop */
+ /* Timer 2 start */
configPR = read_c0_config7();
- configPR |= 0x00000010;
+ configPR &= ~0x00000010;
write_c0_config7(configPR);
- write_c0_count2(0);
- write_c0_compare2(0xffffffff);
-
/* Timer 3 stop */
configPR = read_c0_config7();
configPR |= 0x00000020;
diff --git a/arch/mips/philips/pnx8550/jbs/irqmap.c b/arch/mips/philips/pnx8550/jbs/irqmap.c
index f78e0423dc9..98c3429e6e5 100644
--- a/arch/mips/philips/pnx8550/jbs/irqmap.c
+++ b/arch/mips/philips/pnx8550/jbs/irqmap.c
@@ -28,9 +28,9 @@
#include <linux/init.h>
#include <int.h>
-char irq_tab_jbs[][5] __initdata = {
- [8] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
- [9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
- [17] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
+char pnx8550_irq_tab[][5] __initdata = {
+ [8] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
+ [9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
+ [17] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
};
diff --git a/arch/mips/philips/pnx8550/stb810/Makefile b/arch/mips/philips/pnx8550/stb810/Makefile
new file mode 100644
index 00000000000..f14b592af39
--- /dev/null
+++ b/arch/mips/philips/pnx8550/stb810/Makefile
@@ -0,0 +1,4 @@
+
+# Makefile for the Philips STB810 Board.
+
+lib-y := prom_init.o board_setup.o irqmap.o
diff --git a/arch/mips/philips/pnx8550/stb810/board_setup.c b/arch/mips/philips/pnx8550/stb810/board_setup.c
new file mode 100644
index 00000000000..345d71e53cf
--- /dev/null
+++ b/arch/mips/philips/pnx8550/stb810/board_setup.c
@@ -0,0 +1,49 @@
+/*
+ * STB810 specific board startup routines.
+ *
+ * Based on the arch/mips/philips/pnx8550/jbs/board_setup.c
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * Copyright 2005 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/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/mc146818rtc.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/pgtable.h>
+
+#include <glb.h>
+
+void __init board_setup(void)
+{
+ unsigned long config0, configpr;
+
+ config0 = read_c0_config();
+
+ /* clear all three cache coherency fields */
+ config0 &= ~(0x7 | (7<<25) | (7<<28));
+ config0 |= (CONF_CM_DEFAULT | (CONF_CM_DEFAULT<<25) |
+ (CONF_CM_DEFAULT<<28));
+ write_c0_config(config0);
+
+ configpr = read_c0_config7();
+ configpr |= (1<<19); /* enable tlb */
+ write_c0_config7(configpr);
+}
diff --git a/arch/mips/philips/pnx8550/stb810/irqmap.c b/arch/mips/philips/pnx8550/stb810/irqmap.c
new file mode 100644
index 00000000000..5ee11e19975
--- /dev/null
+++ b/arch/mips/philips/pnx8550/stb810/irqmap.c
@@ -0,0 +1,23 @@
+/*
+ * Philips STB810 board irqmap.
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * Copyright 2005 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/init.h>
+#include <int.h>
+
+char pnx8550_irq_tab[][5] __initdata = {
+ [8] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
+ [9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
+ [10] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
+};
+
diff --git a/arch/mips/philips/pnx8550/stb810/prom_init.c b/arch/mips/philips/pnx8550/stb810/prom_init.c
new file mode 100644
index 00000000000..ea5b4e0fb47
--- /dev/null
+++ b/arch/mips/philips/pnx8550/stb810/prom_init.c
@@ -0,0 +1,49 @@
+/*
+ * STB810 specific prom routines
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * Copyright 2005 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/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>
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+extern void __init prom_init_cmdline(void);
+extern char *prom_getenv(char *envname);
+
+const char *get_system_type(void)
+{
+ return "Philips PNX8550/STB810";
+}
+
+void __init prom_init(void)
+{
+ unsigned long memsize;
+
+ prom_argc = (int) fw_arg0;
+ prom_argv = (char **) fw_arg1;
+ prom_envp = (char **) fw_arg2;
+
+ prom_init_cmdline();
+
+ mips_machgroup = MACH_GROUP_PHILIPS;
+ mips_machtype = MACH_PHILIPS_STB810;
+
+ memsize = 0x08000000; /* Trimedia uses memory above */
+ add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
diff --git a/arch/mips/pmc-sierra/yosemite/dbg_io.c b/arch/mips/pmc-sierra/yosemite/dbg_io.c
index 0f659c9106a..6362c702e38 100644
--- a/arch/mips/pmc-sierra/yosemite/dbg_io.c
+++ b/arch/mips/pmc-sierra/yosemite/dbg_io.c
@@ -93,7 +93,7 @@
* Functions to READ and WRITE to serial port 1
*/
#define SERIAL_READ_1(ofs) (*((volatile unsigned char*) \
- (TITAN_SERIAL_BASE_1 + ofs)
+ (TITAN_SERIAL_BASE_1 + ofs)))
#define SERIAL_WRITE_1(ofs, val) ((*((volatile unsigned char*) \
(TITAN_SERIAL_BASE_1 + ofs))) = val)
diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c
index adb048527e7..428d1f45a28 100644
--- a/arch/mips/pmc-sierra/yosemite/irq.c
+++ b/arch/mips/pmc-sierra/yosemite/irq.c
@@ -148,9 +148,9 @@ void __init arch_init_irq(void)
{
clear_c0_status(ST0_IM);
- mips_cpu_irq_init(0);
- rm7k_cpu_irq_init(8);
- rm9k_cpu_irq_init(12);
+ mips_cpu_irq_init();
+ rm7k_cpu_irq_init();
+ rm9k_cpu_irq_init();
#ifdef CONFIG_KGDB
/* At this point, initialize the second serial port */
diff --git a/arch/mips/pmc-sierra/yosemite/prom.c b/arch/mips/pmc-sierra/yosemite/prom.c
index 9fe4973377c..1e1685e415a 100644
--- a/arch/mips/pmc-sierra/yosemite/prom.c
+++ b/arch/mips/pmc-sierra/yosemite/prom.c
@@ -132,9 +132,8 @@ void __init prom_init(void)
prom_grab_secondary();
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c
index 1b9b0d396d3..6a6e15e4000 100644
--- a/arch/mips/pmc-sierra/yosemite/setup.c
+++ b/arch/mips/pmc-sierra/yosemite/setup.c
@@ -171,6 +171,7 @@ static void __init py_map_ocd(void)
static void __init py_uart_setup(void)
{
+#ifdef CONFIG_SERIAL_8250
struct uart_port up;
/*
@@ -188,6 +189,7 @@ static void __init py_uart_setup(void)
if (early_serial_setup(&up))
printk(KERN_ERR "Early serial init of port 0 failed\n");
+#endif /* CONFIG_SERIAL_8250 */
}
static void __init py_rtc_setup(void)
diff --git a/arch/mips/qemu/q-mem.c b/arch/mips/qemu/q-mem.c
index d174fac4303..dae39b59de1 100644
--- a/arch/mips/qemu/q-mem.c
+++ b/arch/mips/qemu/q-mem.c
@@ -1,6 +1,5 @@
#include <linux/init.h>
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0UL;
}
diff --git a/arch/mips/sgi-ip22/ip22-eisa.c b/arch/mips/sgi-ip22/ip22-eisa.c
index a1a9af6da7b..6b6e97b90c6 100644
--- a/arch/mips/sgi-ip22/ip22-eisa.c
+++ b/arch/mips/sgi-ip22/ip22-eisa.c
@@ -139,7 +139,7 @@ static void end_eisa1_irq(unsigned int irq)
}
static struct irq_chip ip22_eisa1_irq_type = {
- .typename = "IP22 EISA",
+ .name = "IP22 EISA",
.startup = startup_eisa1_irq,
.ack = mask_and_ack_eisa1_irq,
.mask = disable_eisa1_irq,
@@ -194,7 +194,7 @@ static void end_eisa2_irq(unsigned int irq)
}
static struct irq_chip ip22_eisa2_irq_type = {
- .typename = "IP22 EISA",
+ .name = "IP22 EISA",
.startup = startup_eisa2_irq,
.ack = mask_and_ack_eisa2_irq,
.mask = disable_eisa2_irq,
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index c44f8be0644..b454924aeb5 100644
--- a/arch/mips/sgi-ip22/ip22-int.c
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -19,6 +19,7 @@
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
+#include <asm/irq_cpu.h>
#include <asm/sgi/ioc.h>
#include <asm/sgi/hpc3.h>
@@ -52,7 +53,7 @@ static void disable_local0_irq(unsigned int irq)
}
static struct irq_chip ip22_local0_irq_type = {
- .typename = "IP22 local 0",
+ .name = "IP22 local 0",
.ack = disable_local0_irq,
.mask = disable_local0_irq,
.mask_ack = disable_local0_irq,
@@ -73,7 +74,7 @@ void disable_local1_irq(unsigned int irq)
}
static struct irq_chip ip22_local1_irq_type = {
- .typename = "IP22 local 1",
+ .name = "IP22 local 1",
.ack = disable_local1_irq,
.mask = disable_local1_irq,
.mask_ack = disable_local1_irq,
@@ -94,7 +95,7 @@ void disable_local2_irq(unsigned int irq)
}
static struct irq_chip ip22_local2_irq_type = {
- .typename = "IP22 local 2",
+ .name = "IP22 local 2",
.ack = disable_local2_irq,
.mask = disable_local2_irq,
.mask_ack = disable_local2_irq,
@@ -115,7 +116,7 @@ void disable_local3_irq(unsigned int irq)
}
static struct irq_chip ip22_local3_irq_type = {
- .typename = "IP22 local 3",
+ .name = "IP22 local 3",
.ack = disable_local3_irq,
.mask = disable_local3_irq,
.mask_ack = disable_local3_irq,
@@ -253,8 +254,6 @@ asmlinkage void plat_irq_dispatch(void)
indy_8254timer_irq();
}
-extern void mips_cpu_irq_init(unsigned int irq_base);
-
void __init arch_init_irq(void)
{
int i;
@@ -316,7 +315,7 @@ void __init arch_init_irq(void)
sgint->cmeimask1 = 0;
/* init CPU irqs */
- mips_cpu_irq_init(SGINT_CPU);
+ mips_cpu_irq_init();
for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) {
struct irq_chip *handler;
diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c
index b58bd522262..ddb6506d834 100644
--- a/arch/mips/sgi-ip22/ip22-mc.c
+++ b/arch/mips/sgi-ip22/ip22-mc.c
@@ -202,7 +202,6 @@ void __init sgimc_init(void)
}
void __init prom_meminit(void) {}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 319f8803ef6..60ade7690e0 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -333,7 +333,7 @@ static inline void disable_bridge_irq(unsigned int irq)
}
static struct irq_chip bridge_irq_type = {
- .typename = "bridge",
+ .name = "bridge",
.startup = startup_bridge_irq,
.shutdown = shutdown_bridge_irq,
.ack = disable_bridge_irq,
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index 16e5682b01f..0e3d535e9f4 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -498,10 +498,9 @@ void __init prom_meminit(void)
}
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
/* We got nothing to free here ... */
- return 0;
}
extern void pagetable_init(void);
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index c20e9899b34..9ce513629b1 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -181,7 +181,7 @@ static void disable_rt_irq(unsigned int irq)
}
static struct irq_chip rt_irq_type = {
- .typename = "SN HUB RT timer",
+ .name = "SN HUB RT timer",
.ack = disable_rt_irq,
.mask = disable_rt_irq,
.mask_ack = disable_rt_irq,
diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c
index ae063864c02..8c450d9e869 100644
--- a/arch/mips/sgi-ip32/ip32-irq.c
+++ b/arch/mips/sgi-ip32/ip32-irq.c
@@ -144,7 +144,7 @@ static void end_cpu_irq(unsigned int irq)
}
static struct irq_chip ip32_cpu_interrupt = {
- .typename = "IP32 CPU",
+ .name = "IP32 CPU",
.ack = disable_cpu_irq,
.mask = disable_cpu_irq,
.mask_ack = disable_cpu_irq,
@@ -193,7 +193,7 @@ static void end_crime_irq(unsigned int irq)
}
static struct irq_chip ip32_crime_interrupt = {
- .typename = "IP32 CRIME",
+ .name = "IP32 CRIME",
.ack = mask_and_ack_crime_irq,
.mask = disable_crime_irq,
.mask_ack = mask_and_ack_crime_irq,
@@ -234,7 +234,7 @@ static void end_macepci_irq(unsigned int irq)
}
static struct irq_chip ip32_macepci_interrupt = {
- .typename = "IP32 MACE PCI",
+ .name = "IP32 MACE PCI",
.ack = disable_macepci_irq,
.mask = disable_macepci_irq,
.mask_ack = disable_macepci_irq,
@@ -347,7 +347,7 @@ static void end_maceisa_irq(unsigned irq)
}
static struct irq_chip ip32_maceisa_interrupt = {
- .typename = "IP32 MACE ISA",
+ .name = "IP32 MACE ISA",
.ack = mask_and_ack_maceisa_irq,
.mask = disable_maceisa_irq,
.mask_ack = mask_and_ack_maceisa_irq,
@@ -379,7 +379,7 @@ static void end_mace_irq(unsigned int irq)
}
static struct irq_chip ip32_mace_interrupt = {
- .typename = "IP32 MACE",
+ .name = "IP32 MACE",
.ack = disable_mace_irq,
.mask = disable_mace_irq,
.mask_ack = disable_mace_irq,
diff --git a/arch/mips/sgi-ip32/ip32-memory.c b/arch/mips/sgi-ip32/ip32-memory.c
index d37d40a3cda..849d392a001 100644
--- a/arch/mips/sgi-ip32/ip32-memory.c
+++ b/arch/mips/sgi-ip32/ip32-memory.c
@@ -43,7 +43,6 @@ void __init prom_meminit (void)
}
-unsigned long __init prom_free_prom_memory (void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
index 2e8f6b2e242..1dc5d05d896 100644
--- a/arch/mips/sibyte/bcm1480/irq.c
+++ b/arch/mips/sibyte/bcm1480/irq.c
@@ -82,7 +82,7 @@ extern char sb1250_duart_present[];
#endif
static struct irq_chip bcm1480_irq_type = {
- .typename = "BCM1480-IMR",
+ .name = "BCM1480-IMR",
.ack = ack_bcm1480_irq,
.mask = disable_bcm1480_irq,
.mask_ack = ack_bcm1480_irq,
diff --git a/arch/mips/sibyte/cfe/setup.c b/arch/mips/sibyte/cfe/setup.c
index 6e8952da6e2..9e6099e6962 100644
--- a/arch/mips/sibyte/cfe/setup.c
+++ b/arch/mips/sibyte/cfe/setup.c
@@ -343,10 +343,9 @@ void __init prom_init(void)
prom_meminit();
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
/* Not sure what I'm supposed to do here. Nothing, I think */
- return 0;
}
void prom_putchar(char c)
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
index 82ce7533053..148239446e6 100644
--- a/arch/mips/sibyte/sb1250/irq.c
+++ b/arch/mips/sibyte/sb1250/irq.c
@@ -67,7 +67,7 @@ extern char sb1250_duart_present[];
#endif
static struct irq_chip sb1250_irq_type = {
- .typename = "SB1250-IMR",
+ .name = "SB1250-IMR",
.ack = ack_sb1250_irq,
.mask = disable_sb1250_irq,
.mask_ack = ack_sb1250_irq,
diff --git a/arch/mips/sibyte/sb1250/prom.c b/arch/mips/sibyte/sb1250/prom.c
index 3c33a4517bc..257c4e67435 100644
--- a/arch/mips/sibyte/sb1250/prom.c
+++ b/arch/mips/sibyte/sb1250/prom.c
@@ -87,10 +87,9 @@ void __init prom_init(void)
prom_meminit();
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
/* Not sure what I'm supposed to do here. Nothing, I think */
- return 0;
}
void prom_putchar(char c)
diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c
index 8511bcc6d99..039e8e54050 100644
--- a/arch/mips/sni/irq.c
+++ b/arch/mips/sni/irq.c
@@ -37,7 +37,7 @@ static void end_pciasic_irq(unsigned int irq)
}
static struct irq_chip pciasic_irq_type = {
- .typename = "ASIC-PCI",
+ .name = "ASIC-PCI",
.ack = disable_pciasic_irq,
.mask = disable_pciasic_irq,
.mask_ack = disable_pciasic_irq,
diff --git a/arch/mips/sni/sniprom.c b/arch/mips/sni/sniprom.c
index d1d0f1f493b..1213d166f22 100644
--- a/arch/mips/sni/sniprom.c
+++ b/arch/mips/sni/sniprom.c
@@ -67,9 +67,8 @@ void prom_printf(char *fmt, ...)
va_end(args);
}
-unsigned long prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
/*
diff --git a/arch/mips/tx4927/common/tx4927_irq.c b/arch/mips/tx4927/common/tx4927_irq.c
index ed4a19adf36..e7f3e5b84dc 100644
--- a/arch/mips/tx4927/common/tx4927_irq.c
+++ b/arch/mips/tx4927/common/tx4927_irq.c
@@ -120,7 +120,7 @@ static void tx4927_irq_pic_disable(unsigned int irq);
#define TX4927_CP0_NAME "TX4927-CP0"
static struct irq_chip tx4927_irq_cp0_type = {
- .typename = TX4927_CP0_NAME,
+ .name = TX4927_CP0_NAME,
.ack = tx4927_irq_cp0_disable,
.mask = tx4927_irq_cp0_disable,
.mask_ack = tx4927_irq_cp0_disable,
@@ -129,7 +129,7 @@ static struct irq_chip tx4927_irq_cp0_type = {
#define TX4927_PIC_NAME "TX4927-PIC"
static struct irq_chip tx4927_irq_pic_type = {
- .typename = TX4927_PIC_NAME,
+ .name = TX4927_PIC_NAME,
.ack = tx4927_irq_pic_disable,
.mask = tx4927_irq_pic_disable,
.mask_ack = tx4927_irq_pic_disable,
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
index 5a5ea6c0b9f..dcce88f403c 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
@@ -158,7 +158,6 @@ JP7 is not bus master -- do NOT use -- only 4 pci bus master's allowed -- SouthB
#define TOSHIBA_RBTX4927_IRQ_ISA_ENABLE ( 1 << 23 )
#define TOSHIBA_RBTX4927_IRQ_ISA_DISABLE ( 1 << 24 )
#define TOSHIBA_RBTX4927_IRQ_ISA_MASK ( 1 << 25 )
-#define TOSHIBA_RBTX4927_IRQ_ISA_ENDIRQ ( 1 << 26 )
#define TOSHIBA_RBTX4927_SETUP_ALL 0xffffffff
#endif
@@ -175,7 +174,6 @@ static const u32 toshiba_rbtx4927_irq_debug_flag =
// | TOSHIBA_RBTX4927_IRQ_ISA_ENABLE
// | TOSHIBA_RBTX4927_IRQ_ISA_DISABLE
// | TOSHIBA_RBTX4927_IRQ_ISA_MASK
-// | TOSHIBA_RBTX4927_IRQ_ISA_ENDIRQ
);
#endif
@@ -226,12 +224,11 @@ static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq);
static void toshiba_rbtx4927_irq_isa_enable(unsigned int irq);
static void toshiba_rbtx4927_irq_isa_disable(unsigned int irq);
static void toshiba_rbtx4927_irq_isa_mask_and_ack(unsigned int irq);
-static void toshiba_rbtx4927_irq_isa_end(unsigned int irq);
#endif
#define TOSHIBA_RBTX4927_IOC_NAME "RBTX4927-IOC"
static struct irq_chip toshiba_rbtx4927_irq_ioc_type = {
- .typename = TOSHIBA_RBTX4927_IOC_NAME,
+ .name = TOSHIBA_RBTX4927_IOC_NAME,
.ack = toshiba_rbtx4927_irq_ioc_disable,
.mask = toshiba_rbtx4927_irq_ioc_disable,
.mask_ack = toshiba_rbtx4927_irq_ioc_disable,
@@ -244,12 +241,11 @@ static struct irq_chip toshiba_rbtx4927_irq_ioc_type = {
#ifdef CONFIG_TOSHIBA_FPCIB0
#define TOSHIBA_RBTX4927_ISA_NAME "RBTX4927-ISA"
static struct irq_chip toshiba_rbtx4927_irq_isa_type = {
- .typename = TOSHIBA_RBTX4927_ISA_NAME,
+ .name = TOSHIBA_RBTX4927_ISA_NAME,
.ack = toshiba_rbtx4927_irq_isa_mask_and_ack,
.mask = toshiba_rbtx4927_irq_isa_disable,
.mask_ack = toshiba_rbtx4927_irq_isa_mask_and_ack,
.unmask = toshiba_rbtx4927_irq_isa_enable,
- .end = toshiba_rbtx4927_irq_isa_end,
};
#endif
@@ -402,7 +398,8 @@ static void __init toshiba_rbtx4927_irq_isa_init(void)
for (i = TOSHIBA_RBTX4927_IRQ_ISA_BEG;
i <= TOSHIBA_RBTX4927_IRQ_ISA_END; i++)
- set_irq_chip(i, &toshiba_rbtx4927_irq_isa_type);
+ set_irq_chip_and_handler(i, &toshiba_rbtx4927_irq_isa_type,
+ handle_level_irq);
setup_irq(TOSHIBA_RBTX4927_IRQ_NEST_ISA_ON_IOC,
&toshiba_rbtx4927_irq_isa_master);
@@ -470,26 +467,6 @@ static void toshiba_rbtx4927_irq_isa_mask_and_ack(unsigned int irq)
#endif
-#ifdef CONFIG_TOSHIBA_FPCIB0
-static void toshiba_rbtx4927_irq_isa_end(unsigned int irq)
-{
- TOSHIBA_RBTX4927_IRQ_DPRINTK(TOSHIBA_RBTX4927_IRQ_ISA_ENDIRQ,
- "irq=%d\n", irq);
-
- if (irq < TOSHIBA_RBTX4927_IRQ_ISA_BEG
- || irq > TOSHIBA_RBTX4927_IRQ_ISA_END) {
- TOSHIBA_RBTX4927_IRQ_DPRINTK(TOSHIBA_RBTX4927_IRQ_EROR,
- "bad irq=%d\n", irq);
- panic("\n");
- }
-
- if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
- toshiba_rbtx4927_irq_isa_enable(irq);
- }
-}
-#endif
-
-
void __init arch_init_irq(void)
{
extern void tx4927_irq_init(void);
@@ -513,13 +490,13 @@ void toshiba_rbtx4927_irq_dump(char *key)
{
u32 i, j = 0;
for (i = 0; i < NR_IRQS; i++) {
- if (strcmp(irq_desc[i].chip->typename, "none")
+ if (strcmp(irq_desc[i].chip->name, "none")
== 0)
continue;
if ((i >= 1)
- && (irq_desc[i - 1].chip->typename ==
- irq_desc[i].chip->typename)) {
+ && (irq_desc[i - 1].chip->name ==
+ irq_desc[i].chip->name)) {
j++;
} else {
j = 0;
@@ -533,7 +510,7 @@ void toshiba_rbtx4927_irq_dump(char *key)
(u32) (irq_desc[i].action ? irq_desc[i].
action->handler : 0),
irq_desc[i].depth,
- irq_desc[i].chip->typename, j);
+ irq_desc[i].chip->name, j);
}
}
#endif
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
index efe50562f0c..9a3a5babd1f 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
@@ -80,9 +80,8 @@ void __init prom_init(void)
add_memory_region(0, msize << 20, BOOT_MEM_RAM);
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
const char *get_system_type(void)
diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c
index a347b424d91..3a2dbfc2501 100644
--- a/arch/mips/tx4938/common/irq.c
+++ b/arch/mips/tx4938/common/irq.c
@@ -49,7 +49,7 @@ static void tx4938_irq_pic_disable(unsigned int irq);
#define TX4938_CP0_NAME "TX4938-CP0"
static struct irq_chip tx4938_irq_cp0_type = {
- .typename = TX4938_CP0_NAME,
+ .name = TX4938_CP0_NAME,
.ack = tx4938_irq_cp0_disable,
.mask = tx4938_irq_cp0_disable,
.mask_ack = tx4938_irq_cp0_disable,
@@ -58,7 +58,7 @@ static struct irq_chip tx4938_irq_cp0_type = {
#define TX4938_PIC_NAME "TX4938-PIC"
static struct irq_chip tx4938_irq_pic_type = {
- .typename = TX4938_PIC_NAME,
+ .name = TX4938_PIC_NAME,
.ack = tx4938_irq_pic_disable,
.mask = tx4938_irq_pic_disable,
.mask_ack = tx4938_irq_pic_disable,
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
index b6f363d0801..2e96dbb248b 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
@@ -92,7 +92,7 @@ static void toshiba_rbtx4938_irq_ioc_disable(unsigned int irq);
#define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC"
static struct irq_chip toshiba_rbtx4938_irq_ioc_type = {
- .typename = TOSHIBA_RBTX4938_IOC_NAME,
+ .name = TOSHIBA_RBTX4938_IOC_NAME,
.ack = toshiba_rbtx4938_irq_ioc_disable,
.mask = toshiba_rbtx4938_irq_ioc_disable,
.mask_ack = toshiba_rbtx4938_irq_ioc_disable,
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/prom.c b/arch/mips/tx4938/toshiba_rbtx4938/prom.c
index e44daf30a7c..7dc6a0aae21 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/prom.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/prom.c
@@ -56,9 +56,8 @@ void __init prom_init(void)
return;
}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
{
- return 0;
}
void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
diff --git a/arch/mips/vr41xx/Kconfig b/arch/mips/vr41xx/Kconfig
index c8dfd8092ca..92f41f6f934 100644
--- a/arch/mips/vr41xx/Kconfig
+++ b/arch/mips/vr41xx/Kconfig
@@ -6,7 +6,6 @@ config CASIO_E55
select ISA
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
- select GENERIC_HARDIRQS_NO__DO_IRQ
config IBM_WORKPAD
bool "Support for IBM WorkPad z50"
@@ -16,7 +15,6 @@ config IBM_WORKPAD
select ISA
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
- select GENERIC_HARDIRQS_NO__DO_IRQ
config NEC_CMBVR4133
bool "Support for NEC CMB-VR4133"
@@ -41,7 +39,6 @@ config TANBAC_TB022X
select IRQ_CPU
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
- select GENERIC_HARDIRQS_NO__DO_IRQ
help
The TANBAC VR4131 multichip module(TB0225) and
the TANBAC VR4131DIMM(TB0229) are MIPS-based platforms
@@ -74,7 +71,6 @@ config VICTOR_MPC30X
select IRQ_CPU
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
- select GENERIC_HARDIRQS_NO__DO_IRQ
config ZAO_CAPCELLA
bool "Support for ZAO Networks Capcella"
@@ -84,7 +80,6 @@ config ZAO_CAPCELLA
select IRQ_CPU
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
- select GENERIC_HARDIRQS_NO__DO_IRQ
config PCI_VR41XX
bool "Add PCI control unit support of NEC VR4100 series"
diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c
index c075261976c..adabc6bad44 100644
--- a/arch/mips/vr41xx/common/icu.c
+++ b/arch/mips/vr41xx/common/icu.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2001-2002 MontaVista Software Inc.
* Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- * Copyright (C) 2003-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2006 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -68,6 +68,7 @@ static unsigned char sysint2_assign[16] = {
#define MPIUINTREG 0x0e
#define MAIUINTREG 0x10
#define MKIUINTREG 0x12
+#define MMACINTREG 0x12
#define MGIUINTLREG 0x14
#define MDSIUINTREG 0x16
#define NMIREG 0x18
@@ -241,6 +242,30 @@ void vr41xx_disable_kiuint(uint16_t mask)
EXPORT_SYMBOL(vr41xx_disable_kiuint);
+void vr41xx_enable_macint(uint16_t mask)
+{
+ struct irq_desc *desc = irq_desc + ETHERNET_IRQ;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ icu1_set(MMACINTREG, mask);
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(vr41xx_enable_macint);
+
+void vr41xx_disable_macint(uint16_t mask)
+{
+ struct irq_desc *desc = irq_desc + ETHERNET_IRQ;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ icu1_clear(MMACINTREG, mask);
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(vr41xx_disable_macint);
+
void vr41xx_enable_dsiuint(uint16_t mask)
{
struct irq_desc *desc = irq_desc + DSIU_IRQ;
@@ -428,7 +453,7 @@ static void enable_sysint1_irq(unsigned int irq)
}
static struct irq_chip sysint1_irq_type = {
- .typename = "SYSINT1",
+ .name = "SYSINT1",
.ack = disable_sysint1_irq,
.mask = disable_sysint1_irq,
.mask_ack = disable_sysint1_irq,
@@ -446,7 +471,7 @@ static void enable_sysint2_irq(unsigned int irq)
}
static struct irq_chip sysint2_irq_type = {
- .typename = "SYSINT2",
+ .name = "SYSINT2",
.ack = disable_sysint2_irq,
.mask = disable_sysint2_irq,
.mask_ack = disable_sysint2_irq,
diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c
index a2e285c1d4d..4f97e0ba9e2 100644
--- a/arch/mips/vr41xx/common/init.c
+++ b/arch/mips/vr41xx/common/init.c
@@ -81,7 +81,6 @@ void __init prom_init(void)
}
}
-unsigned long __init prom_free_prom_memory (void)
+void __init prom_free_prom_memory(void)
{
- return 0UL;
}
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
index 397ba94cd7e..cba36a247e3 100644
--- a/arch/mips/vr41xx/common/irq.c
+++ b/arch/mips/vr41xx/common/irq.c
@@ -1,7 +1,7 @@
/*
* Interrupt handing routines for NEC VR4100 series.
*
- * Copyright (C) 2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2005-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -73,13 +73,19 @@ static void irq_dispatch(unsigned int irq)
if (cascade->get_irq != NULL) {
unsigned int source_irq = irq;
desc = irq_desc + source_irq;
- desc->chip->ack(source_irq);
+ if (desc->chip->mask_ack)
+ desc->chip->mask_ack(source_irq);
+ else {
+ desc->chip->mask(source_irq);
+ desc->chip->ack(source_irq);
+ }
irq = cascade->get_irq(irq);
if (irq < 0)
atomic_inc(&irq_err_count);
else
irq_dispatch(irq);
- desc->chip->end(source_irq);
+ if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
+ desc->chip->unmask(source_irq);
} else
do_IRQ(irq);
}
@@ -89,27 +95,27 @@ asmlinkage void plat_irq_dispatch(void)
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
if (pending & CAUSEF_IP7)
- do_IRQ(7);
+ do_IRQ(TIMER_IRQ);
else if (pending & 0x7800) {
if (pending & CAUSEF_IP3)
- irq_dispatch(3);
+ irq_dispatch(INT1_IRQ);
else if (pending & CAUSEF_IP4)
- irq_dispatch(4);
+ irq_dispatch(INT2_IRQ);
else if (pending & CAUSEF_IP5)
- irq_dispatch(5);
+ irq_dispatch(INT3_IRQ);
else if (pending & CAUSEF_IP6)
- irq_dispatch(6);
+ irq_dispatch(INT4_IRQ);
} else if (pending & CAUSEF_IP2)
- irq_dispatch(2);
+ irq_dispatch(INT0_IRQ);
else if (pending & CAUSEF_IP0)
- do_IRQ(0);
+ do_IRQ(MIPS_SOFTINT0_IRQ);
else if (pending & CAUSEF_IP1)
- do_IRQ(1);
+ do_IRQ(MIPS_SOFTINT1_IRQ);
else
spurious_interrupt();
}
void __init arch_init_irq(void)
{
- mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
+ mips_cpu_irq_init();
}
diff --git a/arch/mips/vr41xx/nec-cmbvr4133/irq.c b/arch/mips/vr41xx/nec-cmbvr4133/irq.c
index a039bb7251f..7d2d076b0f5 100644
--- a/arch/mips/vr41xx/nec-cmbvr4133/irq.c
+++ b/arch/mips/vr41xx/nec-cmbvr4133/irq.c
@@ -21,67 +21,16 @@
#include <linux/interrupt.h>
#include <asm/io.h>
+#include <asm/i8259.h>
#include <asm/vr41xx/cmbvr4133.h>
-extern void enable_8259A_irq(unsigned int irq);
-extern void disable_8259A_irq(unsigned int irq);
-extern void mask_and_ack_8259A(unsigned int irq);
-extern void init_8259A(int hoge);
-
extern int vr4133_rockhopper;
-static void enable_i8259_irq(unsigned int irq)
-{
- enable_8259A_irq(irq - I8259_IRQ_BASE);
-}
-
-static void disable_i8259_irq(unsigned int irq)
-{
- disable_8259A_irq(irq - I8259_IRQ_BASE);
-}
-
-static void ack_i8259_irq(unsigned int irq)
-{
- mask_and_ack_8259A(irq - I8259_IRQ_BASE);
-}
-
-static void end_i8259_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- enable_8259A_irq(irq - I8259_IRQ_BASE);
-}
-
-static struct irq_chip i8259_irq_type = {
- .typename = "XT-PIC",
- .ack = ack_i8259_irq,
- .mask = disable_i8259_irq,
- .mask_ack = ack_i8259_irq,
- .unmask = enable_i8259_irq,
- .end = end_i8259_irq,
-};
-
static int i8259_get_irq_number(int irq)
{
- unsigned long isr;
-
- isr = inb(0x20);
- irq = ffz(~isr);
- if (irq == 2) {
- isr = inb(0xa0);
- irq = 8 + ffz(~isr);
- }
-
- if (irq < 0 || irq > 15)
- return -EINVAL;
-
- return I8259_IRQ_BASE + irq;
+ return i8259_irq();
}
-static struct irqaction i8259_slave_cascade = {
- .handler = &no_action,
- .name = "cascade",
-};
-
void __init rockhopper_init_irq(void)
{
int i;
@@ -91,11 +40,6 @@ void __init rockhopper_init_irq(void)
return;
}
- for (i = I8259_IRQ_BASE; i <= I8259_IRQ_LAST; i++)
- set_irq_chip(i, &i8259_irq_type);
-
- setup_irq(I8259_SLAVE_IRQ, &i8259_slave_cascade);
-
vr41xx_set_irq_trigger(CMBVR41XX_INTC_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH);
vr41xx_set_irq_level(CMBVR41XX_INTC_PIN, LEVEL_HIGH);
vr41xx_cascade_irq(CMBVR41XX_INTC_IRQ, i8259_get_irq_number);
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index d2101237442..0f9ff618c6d 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -25,6 +25,14 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
diff --git a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c
index 2e2dc4f2c85..04c2ff44439 100644
--- a/arch/parisc/hpux/sys_hpux.c
+++ b/arch/parisc/hpux/sys_hpux.c
@@ -237,7 +237,7 @@ asmlinkage long hpux_fstatfs(unsigned int fd, struct hpux_statfs __user * buf)
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs_hpux(file->f_dentry, &tmp);
+ error = vfs_statfs_hpux(file->f_path.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
@@ -475,7 +475,7 @@ int hpux_sysfs(int opcode, unsigned long arg1, unsigned long arg2)
printk(KERN_DEBUG "len of arg1 = %d\n", len);
if (len == 0)
return 0;
- fsname = (char *) kmalloc(len, GFP_KERNEL);
+ fsname = kmalloc(len, GFP_KERNEL);
if ( !fsname ) {
printk(KERN_DEBUG "failed to kmalloc fsname\n");
return 0;
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 4a23a97b06c..12cc019307a 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -608,7 +608,7 @@ void smp_cpus_done(unsigned int cpu_max)
}
-int __devinit __cpu_up(unsigned int cpu)
+int __cpuinit __cpu_up(unsigned int cpu)
{
if (cpu != 0 && cpu < parisc_max_cpus)
smp_boot_one_cpu(cpu);
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c
index 920bdbf8404..c10ab47d81f 100644
--- a/arch/parisc/kernel/unwind.c
+++ b/arch/parisc/kernel/unwind.c
@@ -343,7 +343,7 @@ void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct
struct pt_regs *r = &t->thread.regs;
struct pt_regs *r2;
- r2 = (struct pt_regs *)kmalloc(sizeof(struct pt_regs), GFP_KERNEL);
+ r2 = kmalloc(sizeof(struct pt_regs), GFP_KERNEL);
if (!r2)
return;
*r2 = *r;
diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c
index 47a1d2ac941..44b42c7f639 100644
--- a/arch/parisc/mm/ioremap.c
+++ b/arch/parisc/mm/ioremap.c
@@ -9,110 +9,8 @@
#include <linux/vmalloc.h>
#include <linux/errno.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/pgalloc.h>
-#include <asm/tlbflush.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, pfn;
- pgprot_t pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY |
- _PAGE_ACCESSED | flags);
-
- address &= ~PMD_MASK;
-
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
-
- BUG_ON(address >= end);
-
- pfn = phys_addr >> PAGE_SHIFT;
- do {
- BUG_ON(!pte_none(*pte));
-
- 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;
-
- BUG_ON(address >= end);
-
- phys_addr -= address;
- 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)
-{
- pgd_t *dir;
- int error = 0;
- unsigned long end = address + size;
-
- BUG_ON(address >= end);
-
- phys_addr -= address;
- dir = pgd_offset_k(address);
-
- flush_cache_all();
-
- 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, 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):
@@ -131,6 +29,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;
#ifdef CONFIG_EISA
unsigned long end = phys_addr + size - 1;
@@ -164,6 +63,9 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
}
}
+ pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY |
+ _PAGE_ACCESSED | flags);
+
/*
* Mappings have to be page-aligned
*/
@@ -179,7 +81,8 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
return NULL;
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)) {
vfree(addr);
return NULL;
}
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 291c95ac4b3..f08e80a0bf0 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -41,6 +41,14 @@ config RWSEM_XCHGADD_ALGORITHM
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default y
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default y if 64BIT
+
config GENERIC_HWEIGHT
bool
default y
@@ -99,6 +107,11 @@ config AUDIT_ARCH
bool
default y
+config GENERIC_BUG
+ bool
+ default y
+ depends on BUG
+
config DEFAULT_UIMAGE
bool
help
@@ -160,6 +173,11 @@ config PPC_86xx
help
The Freescale E600 SoCs have 74xx cores.
+config PPC_8xx
+ bool "Freescale 8xx"
+ select FSL_SOC
+ select 8xx
+
config 40x
bool "AMCC 40x"
select PPC_DCR_NATIVE
@@ -168,8 +186,6 @@ config 44x
bool "AMCC 44x"
select PPC_DCR_NATIVE
-config 8xx
- bool "Freescale 8xx"
config E200
bool "Freescale e200"
@@ -198,6 +214,10 @@ config 6xx
bool
# this is temp to handle compat with arch=ppc
+config 8xx
+ bool
+
+# this is temp to handle compat with arch=ppc
config 83xx
bool
@@ -416,6 +436,21 @@ config PPC_MPC52xx
bool
default n
+config PPC_MPC5200
+ bool
+ select PPC_MPC52xx
+ default n
+
+config PPC_MPC5200_BUGFIX
+ bool "MPC5200 (L25R) bugfix support"
+ depends on PPC_MPC5200
+ default n
+ help
+ Enable workarounds for original MPC5200 errata. This is not required
+ for MPC5200B based boards.
+
+ It is safe to say 'Y' here
+
config PPC_EFIKA
bool "bPlan Efika 5k2. MPC5200B based computer"
depends on PPC_MULTIPLATFORM && PPC32
@@ -423,12 +458,12 @@ config PPC_EFIKA
select RTAS_PROC
select PPC_MPC52xx
select PPC_NATIVE
- default y
+ default n
config PPC_LITE5200
bool "Freescale Lite5200 Eval Board"
depends on PPC_MULTIPLATFORM && PPC32
- select PPC_MPC52xx
+ select PPC_MPC5200
default n
config PPC_PMAC
@@ -458,7 +493,7 @@ config PPC_PREP
select PPC_INDIRECT_PCI
select PPC_UDBG_16550
select PPC_NATIVE
- default y
+ default n
config PPC_MAPLE
depends on PPC_MULTIPLATFORM && PPC64
@@ -470,6 +505,9 @@ config PPC_MAPLE
select PPC_UDBG_16550
select PPC_970_NAP
select PPC_NATIVE
+ select PPC_RTAS
+ select MMIO_NVRAM
+ select ATA_NONSTANDARD if ATA
default n
help
This option enables support for the Maple 970FX Evaluation Board.
@@ -511,12 +549,30 @@ config PPC_IBM_CELL_BLADE
select UDBG_RTAS_CONSOLE
config PPC_PS3
- bool "Sony PS3"
+ bool "Sony PS3 (incomplete)"
depends on PPC_MULTIPLATFORM && PPC64
select PPC_CELL
+ select USB_ARCH_HAS_OHCI
+ select USB_OHCI_LITTLE_ENDIAN
+ select USB_OHCI_BIG_ENDIAN_MMIO
+ select USB_ARCH_HAS_EHCI
+ select USB_EHCI_BIG_ENDIAN_MMIO
help
This option enables support for the Sony PS3 game console
and other platforms using the PS3 hypervisor.
+ Support for this platform is not yet complete, so
+ enabling this will not result in a bootable kernel on a
+ PS3 system.
+
+config PPC_CELLEB
+ bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
+ depends on PPC_MULTIPLATFORM && PPC64
+ select PPC_CELL
+ select PPC_OF_PLATFORM_PCI
+ select HAS_TXX9_SERIAL
+ select PPC_UDBG_BEAT
+ select USB_OHCI_BIG_ENDIAN_MMIO
+ select USB_EHCI_BIG_ENDIAN_MMIO
config PPC_NATIVE
bool
@@ -531,6 +587,11 @@ config UDBG_RTAS_CONSOLE
depends on PPC_RTAS
default n
+config PPC_UDBG_BEAT
+ bool "BEAT based debug console"
+ depends on PPC_CELLEB
+ default n
+
config XICS
depends on PPC_PSERIES
bool
@@ -684,6 +745,7 @@ source arch/powerpc/platforms/86xx/Kconfig
source arch/powerpc/platforms/8xx/Kconfig
source arch/powerpc/platforms/cell/Kconfig
source arch/powerpc/platforms/ps3/Kconfig
+source arch/powerpc/platforms/pasemi/Kconfig
menu "Kernel options"
@@ -706,7 +768,7 @@ config FORCE_MAX_ZONEORDER
config MATH_EMULATION
bool "Math emulation"
- depends on 4xx || 8xx || E200 || E500
+ depends on 4xx || 8xx || E200 || PPC_MPC832x || E500
---help---
Some PowerPC chips designed for embedded applications do not have
a floating-point unit and therefore do not implement the
@@ -1164,7 +1226,7 @@ source "arch/powerpc/oprofile/Kconfig"
config KPROBES
bool "Kprobes (EXPERIMENTAL)"
- depends on PPC64 && KALLSYMS && EXPERIMENTAL && MODULES
+ depends on !BOOKE && !4xx && 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/Kconfig.debug b/arch/powerpc/Kconfig.debug
index f0e51edde02..d39d13327e6 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -4,14 +4,14 @@ source "lib/Kconfig.debug"
config DEBUG_STACKOVERFLOW
bool "Check for stack overflows"
- depends on DEBUG_KERNEL && PPC64
+ 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 && PPC64
+ 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.
@@ -185,6 +185,20 @@ config PPC_EARLY_DEBUG_ISERIES
Select this to enable early debugging for legacy iSeries. You need
to hit "Ctrl-x Ctrl-x" to see the messages on the console.
+config PPC_EARLY_DEBUG_PAS_REALMODE
+ bool "PA Semi real mode"
+ depends on PPC_PASEMI
+ help
+ Select this to enable early debugging for PA Semi.
+ Output will be on UART0.
+
+config PPC_EARLY_DEBUG_BEAT
+ bool "Beat HV Console"
+ depends on PPC_CELLEB
+ select PPC_UDBG_BEAT
+ help
+ Select this to enable early debugging for Celleb with Beat.
+
endchoice
endmenu
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 343dbcfdf08..dc779407de1 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -152,6 +152,9 @@ $(obj)/zImage.initrd.miboot: vmlinux $(wrapperbits)
$(obj)/zImage.ps3: vmlinux
$(STRIP) -s -R .comment $< -o $@
+$(obj)/zImage.initrd.ps3: vmlinux
+ @echo " WARNING zImage.initrd.ps3 not supported (yet)"
+
$(obj)/uImage: vmlinux $(wrapperbits)
$(call cmd,wrap,uboot)
@@ -159,6 +162,7 @@ image-$(CONFIG_PPC_PSERIES) += zImage.pseries
image-$(CONFIG_PPC_MAPLE) += zImage.pseries
image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
image-$(CONFIG_PPC_PS3) += zImage.ps3
+image-$(CONFIG_PPC_CELLEB) += zImage.pseries
image-$(CONFIG_PPC_CHRP) += zImage.chrp
image-$(CONFIG_PPC_EFIKA) += zImage.chrp
image-$(CONFIG_PPC_PMAC) += zImage.pmac
diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts
index 8bc0d259796..186870704ad 100644
--- a/arch/powerpc/boot/dts/lite5200.dts
+++ b/arch/powerpc/boot/dts/lite5200.dts
@@ -10,6 +10,12 @@
* option) any later version.
*/
+/*
+ * WARNING: Do not depend on this tree layout remaining static just yet.
+ * The MPC5200 device tree conventions are still in flux
+ * Keep an eye on the linuxppc-dev mailing list for more details
+ */
+
/ {
model = "Lite5200";
compatible = "lite5200\0lite52xx\0mpc5200\0mpc52xx";
@@ -238,7 +244,7 @@
// PSC3 in CODEC mode example
i2s@2400 { // PSC3
- device_type = "i2s";
+ device_type = "sound";
compatible = "mpc5200-psc-i2s\0mpc52xx-psc-i2s";
reg = <2400 100>;
interrupts = <2 3 0>;
@@ -265,7 +271,7 @@
// PSC6 in AC97 mode example
ac97@2c00 { // PSC6
- device_type = "ac97";
+ device_type = "sound";
compatible = "mpc5200-psc-ac97\0mpc52xx-psc-ac97";
reg = <2c00 100>;
interrupts = <2 4 0>;
diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts
index 81cb76418a7..5bb2760d7c3 100644
--- a/arch/powerpc/boot/dts/lite5200b.dts
+++ b/arch/powerpc/boot/dts/lite5200b.dts
@@ -10,6 +10,12 @@
* option) any later version.
*/
+/*
+ * WARNING: Do not depend on this tree layout remaining static just yet.
+ * The MPC5200 device tree conventions are still in flux
+ * Keep an eye on the linuxppc-dev mailing list for more details
+ */
+
/ {
model = "Lite5200b";
compatible = "lite5200b\0lite52xx\0mpc5200b\0mpc52xx";
@@ -243,7 +249,7 @@
// PSC3 in CODEC mode example
i2s@2400 { // PSC3
- device_type = "i2s";
+ device_type = "sound";
compatible = "mpc5200b-psc-i2s\0mpc52xx-psc-i2s";
reg = <2400 100>;
interrupts = <2 3 0>;
@@ -270,7 +276,7 @@
// PSC6 in AC97 mode example
ac97@2c00 { // PSC6
- device_type = "ac97";
+ device_type = "sound";
compatible = "mpc5200b-psc-ac97\0mpc52xx-psc-ac97";
reg = <2c00 100>;
interrupts = <2 4 0>;
diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
index 34efdd028c4..26b44f7513d 100644
--- a/arch/powerpc/boot/dts/mpc8272ads.dts
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -53,13 +53,20 @@
reg = <00000000 4000000 f4500000 00000020>;
};
+ chosen {
+ name = "chosen";
+ linux,platform = <0>;
+ interrupt-controller = <10c00>;
+ linux,phandle = <400>;
+ };
+
soc8272@f0000000 {
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
device_type = "soc";
- ranges = < 0 0 2 00000000 f0000000 00053000>;
- reg = <f0000000 0>;
+ ranges = <00000000 f0000000 00053000>;
+ reg = <f0000000 10000>;
mdio@0 {
device_type = "mdio";
@@ -71,7 +78,7 @@
ethernet-phy@0 {
linux,phandle = <2452000>;
interrupt-parent = <10c00>;
- interrupts = <19 1>;
+ interrupts = <17 4>;
reg = <0>;
bitbang = [ 12 12 13 02 02 01 ];
device_type = "ethernet-phy";
@@ -79,7 +86,7 @@
ethernet-phy@1 {
linux,phandle = <2452001>;
interrupt-parent = <10c00>;
- interrupts = <19 1>;
+ interrupts = <17 4>;
bitbang = [ 12 12 13 02 02 01 ];
reg = <3>;
device_type = "ethernet-phy";
@@ -90,7 +97,7 @@
#address-cells = <1>;
#size-cells = <0>;
device_type = "network";
- device-id = <2>;
+ device-id = <1>;
compatible = "fs_enet";
model = "FCC";
reg = <11300 20 8400 100 11380 30>;
@@ -104,7 +111,7 @@
ethernet@25000 {
device_type = "network";
- device-id = <3>;
+ device-id = <2>;
compatible = "fs_enet";
model = "FCC";
reg = <11320 20 8500 100 113b0 30>;
@@ -123,8 +130,8 @@
#interrupt-cells = <2>;
device_type = "cpm";
model = "CPM2";
- ranges = <00000000 00000000 3ffff>;
- reg = <10d80 3280>;
+ ranges = <00000000 00000000 20000>;
+ reg = <0 20000>;
command-proc = <119c0>;
brg-frequency = <17D7840>;
cpm_clk = <BEBC200>;
@@ -133,7 +140,7 @@
device_type = "serial";
compatible = "cpm_uart";
model = "SCC";
- device-id = <2>;
+ device-id = <1>;
reg = <11a00 20 8000 100>;
current-speed = <1c200>;
interrupts = <28 2>;
@@ -147,7 +154,7 @@
device_type = "serial";
compatible = "cpm_uart";
model = "SCC";
- device-id = <5>;
+ device-id = <4>;
reg = <11a60 20 8300 100>;
current-speed = <1c200>;
interrupts = <2b 2>;
@@ -181,24 +188,24 @@
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
+ b000 0 0 1 f8200000 40 8
+ b000 0 0 2 f8200000 41 8
+ b000 0 0 3 f8200000 42 8
+ b000 0 0 4 f8200000 43 8
/* 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
+ b800 0 0 1 f8200000 43 8
+ b800 0 0 2 f8200000 40 8
+ b800 0 0 3 f8200000 41 8
+ b800 0 0 4 f8200000 42 8
/* 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>;
+ c000 0 0 1 f8200000 42 8
+ c000 0 0 2 f8200000 43 8
+ c000 0 0 3 f8200000 40 8
+ c000 0 0 4 f8200000 41 8>;
interrupt-parent = <10c00>;
- interrupts = <14 3>;
+ interrupts = <14 8>;
bus-range = <0 0>;
ranges = <02000000 0 80000000 80000000 0 40000000
01000000 0 00000000 f6000000 0 02000000>;
@@ -210,7 +217,7 @@
model = "SEC2";
compatible = "talitos";
reg = <30000 10000>;
- interrupts = <b 0>;
+ interrupts = <b 2>;
interrupt-parent = <10c00>;
num-channels = <4>;
channel-fifo-len = <18>;
diff --git a/arch/powerpc/boot/dts/mpc8323emds.dts b/arch/powerpc/boot/dts/mpc8323emds.dts
new file mode 100644
index 00000000000..fa7ef24d205
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8323emds.dts
@@ -0,0 +1,345 @@
+/*
+ * MPC8323E 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.
+ */
+
+/ {
+ model = "MPC8323EMDS";
+ compatible = "MPC83xx";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ linux,phandle = <100>;
+
+ cpus {
+ #cpus = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ linux,phandle = <200>;
+
+ PowerPC,8323@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;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ linux,phandle = <300>;
+ reg = <00000000 08000000>;
+ };
+
+ bcsr@f8000000 {
+ device_type = "board-control";
+ reg = <f8000000 8000>;
+ };
+
+ soc8323@e0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ ranges = <0 e0000000 00100000>;
+ reg = <e0000000 00000200>;
+ bus-frequency = <7DE2900>;
+
+ 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;
+ };
+
+ serial@4500 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4500 100>;
+ clock-frequency = <0>;
+ interrupts = <9 8>;
+ interrupt-parent = <700>;
+ };
+
+ serial@4600 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4600 100>;
+ clock-frequency = <0>;
+ interrupts = <a 8>;
+ interrupt-parent = <700>;
+ };
+
+ crypto@30000 {
+ device_type = "crypto";
+ model = "SEC2";
+ compatible = "talitos";
+ reg = <30000 7000>;
+ interrupts = <b 8>;
+ interrupt-parent = <700>;
+ /* Rev. 2.2 */
+ num-channels = <1>;
+ channel-fifo-len = <18>;
+ exec-units-mask = <0000004c>;
+ descriptor-types-mask = <0122003f>;
+ };
+
+ 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 90000000 0 10000000
+ 42000000 0 80000000 80000000 0 10000000
+ 01000000 0 00000000 d0000000 0 00100000>;
+ clock-frequency = <0>;
+ #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@03 {
+ linux,phandle = <140003>;
+ pio-map = <
+ /* port pin dir open_drain assignment has_irq */
+ 3 4 3 0 2 0 /* MDIO */
+ 3 5 1 0 2 0 /* MDC */
+ 0 d 2 0 1 0 /* RX_CLK (CLK9) */
+ 3 18 2 0 1 0 /* TX_CLK (CLK10) */
+ 1 1 1 0 1 0 /* TxD1 */
+ 1 0 1 0 1 0 /* TxD0 */
+ 1 1 1 0 1 0 /* TxD1 */
+ 1 2 1 0 1 0 /* TxD2 */
+ 1 3 1 0 1 0 /* TxD3 */
+ 1 4 2 0 1 0 /* RxD0 */
+ 1 5 2 0 1 0 /* RxD1 */
+ 1 6 2 0 1 0 /* RxD2 */
+ 1 7 2 0 1 0 /* RxD3 */
+ 1 8 2 0 1 0 /* RX_ER */
+ 1 9 1 0 1 0 /* TX_ER */
+ 1 a 2 0 1 0 /* RX_DV */
+ 1 b 2 0 1 0 /* COL */
+ 1 c 1 0 1 0 /* TX_EN */
+ 1 d 2 0 1 0>;/* CRS */
+ };
+ ucc_pin@04 {
+ linux,phandle = <140004>;
+ pio-map = <
+ /* port pin dir open_drain assignment has_irq */
+ 3 1f 2 0 1 0 /* RX_CLK (CLK7) */
+ 3 6 2 0 1 0 /* TX_CLK (CLK8) */
+ 1 12 1 0 1 0 /* TxD0 */
+ 1 13 1 0 1 0 /* TxD1 */
+ 1 14 1 0 1 0 /* TxD2 */
+ 1 15 1 0 1 0 /* TxD3 */
+ 1 16 2 0 1 0 /* RxD0 */
+ 1 17 2 0 1 0 /* RxD1 */
+ 1 18 2 0 1 0 /* RxD2 */
+ 1 19 2 0 1 0 /* RxD3 */
+ 1 1a 2 0 1 0 /* RX_ER */
+ 1 1b 1 0 1 0 /* TX_ER */
+ 1 1c 2 0 1 0 /* RX_DV */
+ 1 1d 2 0 1 0 /* COL */
+ 1 1e 1 0 1 0 /* TX_EN */
+ 1 1f 2 0 1 0>;/* CRS */
+ };
+ };
+ };
+
+ 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 = <BCD3D80>;
+
+ muram@10000 {
+ device_type = "muram";
+ ranges = <0 00010000 00004000>;
+
+ data-only@0 {
+ reg = <0 4000>;
+ };
+ };
+
+ 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@2200 {
+ device_type = "network";
+ compatible = "ucc_geth";
+ model = "UCC";
+ device-id = <3>;
+ reg = <2200 200>;
+ interrupts = <22>;
+ interrupt-parent = <80>;
+ mac-address = [ 00 04 9f 00 23 23 ];
+ rx-clock = <19>;
+ tx-clock = <1a>;
+ phy-handle = <212003>;
+ pio-handle = <140003>;
+ };
+
+ ucc@3200 {
+ device_type = "network";
+ compatible = "ucc_geth";
+ model = "UCC";
+ device-id = <4>;
+ reg = <3000 200>;
+ interrupts = <23>;
+ interrupt-parent = <80>;
+ mac-address = [ 00 11 22 33 44 55 ];
+ rx-clock = <17>;
+ tx-clock = <18>;
+ phy-handle = <212004>;
+ pio-handle = <140004>;
+ };
+
+ mdio@2320 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2320 18>;
+ device_type = "mdio";
+ compatible = "ucc_geth_phy";
+
+ ethernet-phy@03 {
+ linux,phandle = <212003>;
+ interrupt-parent = <700>;
+ interrupts = <11 2>;
+ reg = <3>;
+ device_type = "ethernet-phy";
+ interface = <3>; //ENET_100_MII
+ };
+ ethernet-phy@04 {
+ linux,phandle = <212004>;
+ interrupt-parent = <700>;
+ interrupts = <12 2>;
+ reg = <4>;
+ device_type = "ethernet-phy";
+ interface = <3>;
+ };
+ };
+
+ 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
index 2b168486aeb..119bd5d3a83 100644
--- a/arch/powerpc/boot/dts/mpc8560ads.dts
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -200,7 +200,7 @@
a800 0 0 4 40000 31 1>;
interrupt-parent = <40000>;
- interrupts = <42 0>;
+ interrupts = <8 0>;
bus-range = <0 0>;
ranges = <02000000 0 80000000 80000000 0 20000000
01000000 0 00000000 e2000000 0 01000000>;
@@ -250,7 +250,7 @@
rx-clock = <1>;
tx-clock = <1>;
current-speed = <1c200>;
- interrupts = <64 1>;
+ interrupts = <28 8>;
interrupt-parent = <90c00>;
};
@@ -264,7 +264,7 @@
rx-clock = <2>;
tx-clock = <2>;
current-speed = <1c200>;
- interrupts = <65 1>;
+ interrupts = <29 8>;
interrupt-parent = <90c00>;
};
@@ -278,7 +278,7 @@
clock-setup = <ff00ffff 250000>;
rx-clock = <15>;
tx-clock = <16>;
- interrupts = <5d 1>;
+ interrupts = <21 8>;
interrupt-parent = <90c00>;
phy-handle = <2452002>;
};
@@ -293,7 +293,7 @@
clock-setup = <ffff00ff 3700>;
rx-clock = <17>;
tx-clock = <18>;
- interrupts = <5e 1>;
+ interrupts = <22 8>;
interrupt-parent = <90c00>;
phy-handle = <2452003>;
};
diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts
new file mode 100644
index 00000000000..5d4005239b8
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc866ads.dts
@@ -0,0 +1,162 @@
+/*
+ * MPC866 ADS Device Tree Source
+ *
+ * Copyright 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.
+ */
+
+
+/ {
+ model = "MPC866ADS";
+ compatible = "mpc8xx";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ linux,phandle = <100>;
+
+ cpus {
+ #cpus = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ linux,phandle = <200>;
+
+ PowerPC,866@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <20>; // 32 bytes
+ i-cache-line-size = <20>; // 32 bytes
+ d-cache-size = <2000>; // L1, 8K
+ i-cache-size = <4000>; // L1, 16K
+ timebase-frequency = <0>;
+ bus-frequency = <0>;
+ clock-frequency = <0>;
+ 32-bit;
+ interrupts = <f 2>; // decrementer interrupt
+ interrupt-parent = <ff000000>;
+ linux,phandle = <201>;
+ linux,boot-cpu;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ linux,phandle = <300>;
+ reg = <00000000 800000>;
+ };
+
+ soc866@ff000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ ranges = <0 ff000000 00100000>;
+ reg = <ff000000 00000200>;
+ bus-frequency = <0>;
+ mdio@e80 {
+ device_type = "mdio";
+ compatible = "fs_enet";
+ reg = <e80 8>;
+ linux,phandle = <e80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ethernet-phy@f {
+ linux,phandle = <e800f>;
+ reg = <f>;
+ device_type = "ethernet-phy";
+ };
+ };
+
+ fec@e00 {
+ device_type = "network";
+ compatible = "fs_enet";
+ model = "FEC";
+ device-id = <1>;
+ reg = <e00 188>;
+ mac-address = [ 00 00 0C 00 01 FD ];
+ interrupts = <3 1>;
+ interrupt-parent = <ff000000>;
+ phy-handle = <e800f>;
+ };
+
+ pic@ff000000 {
+ linux,phandle = <ff000000>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0 24>;
+ built-in;
+ device_type = "mpc8xx-pic";
+ compatible = "CPM";
+ };
+
+ cpm@ff000000 {
+ linux,phandle = <ff000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "cpm";
+ model = "CPM";
+ ranges = <0 0 4000>;
+ reg = <860 f0>;
+ command-proc = <9c0>;
+ brg-frequency = <0>;
+ interrupts = <0 2>; // cpm error interrupt
+ interrupt-parent = <930>;
+
+ pic@930 {
+ linux,phandle = <930>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <5 2 0 2>;
+ interrupt-parent = <ff000000>;
+ reg = <930 20>;
+ built-in;
+ device_type = "cpm-pic";
+ compatible = "CPM";
+ };
+
+ smc@a80 {
+ device_type = "serial";
+ compatible = "cpm_uart";
+ model = "SMC";
+ device-id = <1>;
+ reg = <a80 10 3e80 40>;
+ clock-setup = <00ffffff 0>;
+ rx-clock = <1>;
+ tx-clock = <1>;
+ current-speed = <0>;
+ interrupts = <4 3>;
+ interrupt-parent = <930>;
+ };
+
+ smc@a90 {
+ device_type = "serial";
+ compatible = "cpm_uart";
+ model = "SMC";
+ device-id = <2>;
+ reg = <a90 20 3f80 40>;
+ clock-setup = <ff00ffff 90000>;
+ rx-clock = <2>;
+ tx-clock = <2>;
+ current-speed = <0>;
+ interrupts = <3 3>;
+ interrupt-parent = <930>;
+ };
+
+ scc@a00 {
+ device_type = "network";
+ compatible = "fs_enet";
+ model = "SCC";
+ device-id = <1>;
+ reg = <a00 18 3c00 80>;
+ mac-address = [ 00 00 0C 00 03 FD ];
+ interrupts = <1e 3>;
+ interrupt-parent = <930>;
+ };
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
new file mode 100644
index 00000000000..cf1a19f962c
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -0,0 +1,185 @@
+/*
+ * MPC885 ADS Device Tree Source
+ *
+ * Copyright 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.
+ */
+
+
+/ {
+ model = "MPC885ADS";
+ compatible = "mpc8xx";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ linux,phandle = <100>;
+
+ cpus {
+ #cpus = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ linux,phandle = <200>;
+
+ PowerPC,885@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <20>; // 32 bytes
+ i-cache-line-size = <20>; // 32 bytes
+ d-cache-size = <2000>; // L1, 8K
+ i-cache-size = <2000>; // L1, 8K
+ timebase-frequency = <0>;
+ bus-frequency = <0>;
+ clock-frequency = <0>;
+ 32-bit;
+ interrupts = <f 2>; // decrementer interrupt
+ interrupt-parent = <ff000000>;
+ linux,phandle = <201>;
+ linux,boot-cpu;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ linux,phandle = <300>;
+ reg = <00000000 800000>;
+ };
+
+ soc885@ff000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ ranges = <0 ff000000 00100000>;
+ reg = <ff000000 00000200>;
+ bus-frequency = <0>;
+ mdio@e80 {
+ device_type = "mdio";
+ compatible = "fs_enet";
+ reg = <e80 8>;
+ linux,phandle = <e80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ethernet-phy@0 {
+ linux,phandle = <e8000>;
+ reg = <0>;
+ device_type = "ethernet-phy";
+ };
+ ethernet-phy@1 {
+ linux,phandle = <e8001>;
+ reg = <1>;
+ device_type = "ethernet-phy";
+ };
+ ethernet-phy@2 {
+ linux,phandle = <e8002>;
+ reg = <2>;
+ device_type = "ethernet-phy";
+ };
+ };
+
+ fec@e00 {
+ device_type = "network";
+ compatible = "fs_enet";
+ model = "FEC";
+ device-id = <1>;
+ reg = <e00 188>;
+ mac-address = [ 00 00 0C 00 01 FD ];
+ interrupts = <3 1>;
+ interrupt-parent = <ff000000>;
+ phy-handle = <e8000>;
+ };
+
+ fec@1e00 {
+ device_type = "network";
+ compatible = "fs_enet";
+ model = "FEC";
+ device-id = <2>;
+ reg = <1e00 188>;
+ mac-address = [ 00 00 0C 00 02 FD ];
+ interrupts = <7 1>;
+ interrupt-parent = <ff000000>;
+ phy-handle = <e8001>;
+ };
+
+ pic@ff000000 {
+ linux,phandle = <ff000000>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0 24>;
+ built-in;
+ device_type = "mpc8xx-pic";
+ compatible = "CPM";
+ };
+
+ cpm@ff000000 {
+ linux,phandle = <ff000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "cpm";
+ model = "CPM";
+ ranges = <0 0 4000>;
+ reg = <860 f0>;
+ command-proc = <9c0>;
+ brg-frequency = <0>;
+ interrupts = <0 2>; // cpm error interrupt
+ interrupt-parent = <930>;
+
+ pic@930 {
+ linux,phandle = <930>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <5 2 0 2>;
+ interrupt-parent = <ff000000>;
+ reg = <930 20>;
+ built-in;
+ device_type = "cpm-pic";
+ compatible = "CPM";
+ };
+
+ smc@a80 {
+ device_type = "serial";
+ compatible = "cpm_uart";
+ model = "SMC";
+ device-id = <1>;
+ reg = <a80 10 3e80 40>;
+ clock-setup = <00ffffff 0>;
+ rx-clock = <1>;
+ tx-clock = <1>;
+ current-speed = <0>;
+ interrupts = <4 3>;
+ interrupt-parent = <930>;
+ };
+
+ smc@a90 {
+ device_type = "serial";
+ compatible = "cpm_uart";
+ model = "SMC";
+ device-id = <2>;
+ reg = <a90 20 3f80 40>;
+ clock-setup = <ff00ffff 90000>;
+ rx-clock = <2>;
+ tx-clock = <2>;
+ current-speed = <0>;
+ interrupts = <3 3>;
+ interrupt-parent = <930>;
+ };
+
+ scc@a40 {
+ device_type = "network";
+ compatible = "fs_enet";
+ model = "SCC";
+ device-id = <3>;
+ reg = <a40 18 3e00 80>;
+ mac-address = [ 00 00 0C 00 03 FD ];
+ interrupts = <1c 3>;
+ interrupt-parent = <930>;
+ phy-handle = <e8002>;
+ };
+ };
+ };
+};
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index a98c982c73a..e956548da00 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.19-rc6
-# Wed Nov 22 15:33:04 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:12:56 2007
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -10,6 +10,8 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -23,6 +25,7 @@ CONFIG_PPC_OF=y
CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
@@ -66,6 +69,7 @@ CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_CPUSETS=y
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -128,14 +132,16 @@ CONFIG_PPC_MULTIPLATFORM=y
# CONFIG_APUS is not set
# CONFIG_PPC_PSERIES is not set
# CONFIG_PPC_ISERIES is not set
+# CONFIG_PPC_MPC52xx 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
-CONFIG_UDBG_RTAS_CONSOLE=y
CONFIG_PPC_PS3=y
+CONFIG_PPC_NATIVE=y
+CONFIG_UDBG_RTAS_CONSOLE=y
# CONFIG_U3_DART is not set
CONFIG_PPC_RTAS=y
# CONFIG_RTAS_ERROR_LOGGING is not set
@@ -177,12 +183,14 @@ CONFIG_CBE_CPUFREQ=m
CONFIG_PS3_HTAB_SIZE=20
# CONFIG_PS3_DYNAMIC_DMA is not set
CONFIG_PS3_USE_LPAR_ADDR=y
+CONFIG_PS3_VUART=y
#
# Kernel options
#
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -270,7 +278,10 @@ 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_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 is not set
# CONFIG_IP_MROUTE is not set
@@ -289,6 +300,7 @@ CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
#
# IP: Virtual Server Configuration
@@ -317,31 +329,67 @@ CONFIG_NETFILTER=y
#
# Core Netfilter Configuration
#
-# CONFIG_NETFILTER_NETLINK is not set
-# CONFIG_NETFILTER_XTABLES is not set
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=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_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
#
# 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=y
-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
+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_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_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=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 is not set
+# CONFIG_IP6_NF_IPTABLES is not set
#
# DCCP Configuration (EXPERIMENTAL)
@@ -373,6 +421,7 @@ CONFIG_IP_NF_QUEUE=m
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
#
# Network testing
@@ -428,6 +477,7 @@ 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=131072
@@ -457,6 +507,7 @@ 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 is not set
# CONFIG_IDE_TASK_IOCTL is not set
#
@@ -468,7 +519,6 @@ CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
@@ -492,6 +542,7 @@ CONFIG_BLK_DEV_AEC62XX=y
# CONFIG_BLK_DEV_PDC202XX_NEW is not set
# CONFIG_BLK_DEV_SVWKS is not set
CONFIG_BLK_DEV_SIIMAGE=y
+# CONFIG_BLK_DEV_SL82C105 is not set
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
@@ -505,8 +556,74 @@ CONFIG_IDEDMA_AUTO=y
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
+CONFIG_SCSI=m
+# CONFIG_SCSI_TGT is not set
# 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
+# CONFIG_SCSI_SCAN_ASYNC 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_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_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_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_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
#
# Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -538,6 +655,9 @@ CONFIG_DM_MULTIPATH=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
@@ -552,6 +672,7 @@ CONFIG_DM_MULTIPATH=m
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -559,7 +680,7 @@ CONFIG_DM_MULTIPATH=m
#
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
-CONFIG_BONDING=y
+CONFIG_BONDING=m
# CONFIG_EQUALIZER is not set
CONFIG_TUN=y
@@ -604,11 +725,11 @@ CONFIG_E1000_NAPI=y
# CONFIG_R8169 is not set
# CONFIG_SIS190 is not set
CONFIG_SKGE=m
-# CONFIG_SKY2 is not set
+CONFIG_SKY2=m
# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
+CONFIG_TIGON3=y
# CONFIG_BNX2 is not set
-CONFIG_SPIDER_NET=m
+CONFIG_SPIDER_NET=y
# CONFIG_QLA3XXX is not set
#
@@ -618,6 +739,7 @@ CONFIG_SPIDER_NET=m
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -637,6 +759,7 @@ CONFIG_SPIDER_NET=m
# 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
@@ -703,6 +826,7 @@ CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_DIGIEPCA is not set
# CONFIG_MOXA_INTELLIO is not set
# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_MOXA_SMARTIO_NEW is not set
# CONFIG_ISI is not set
# CONFIG_SYNCLINK is not set
# CONFIG_SYNCLINKMP is not set
@@ -756,16 +880,17 @@ CONFIG_WATCHDOG_RTAS=y
#
# CONFIG_PCIPCWATCHDOG is not set
# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
# CONFIG_HW_RANDOM is not set
CONFIG_GEN_RTC=y
# CONFIG_GEN_RTC_X is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -855,12 +980,14 @@ CONFIG_I2C_ALGOBIT=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
+# CONFIG_FB_IBM_GXT4500 is not set
#
# Console display driver support
@@ -875,18 +1002,145 @@ CONFIG_DUMMY_CONSOLE=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=m
+
+#
# 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
+CONFIG_USB=m
+# 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_MULTITHREAD_PROBE is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+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
+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=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
+
+#
+# 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_MII 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_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
@@ -912,7 +1166,7 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
# InfiniBand support
#
-CONFIG_INFINIBAND=y
+CONFIG_INFINIBAND=m
CONFIG_INFINIBAND_USER_MAD=m
CONFIG_INFINIBAND_USER_ACCESS=m
CONFIG_INFINIBAND_ADDR_TRANS=y
@@ -922,6 +1176,8 @@ CONFIG_INFINIBAND_MTHCA_DEBUG=y
CONFIG_INFINIBAND_IPOIB=m
CONFIG_INFINIBAND_IPOIB_DEBUG=y
CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y
+# CONFIG_INFINIBAND_SRP is not set
+# CONFIG_INFINIBAND_ISER is not set
#
# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
@@ -946,6 +1202,10 @@ CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1028,23 +1288,18 @@ CONFIG_RAMFS=y
#
# Network File Systems
#
-CONFIG_NFS_FS=m
+CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=m
-CONFIG_NFSD_V2_ACL=y
-CONFIG_NFSD_V3=y
-CONFIG_NFSD_V3_ACL=y
-# CONFIG_NFSD_V4 is not set
-CONFIG_NFSD_TCP=y
-CONFIG_LOCKD=m
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=m
-CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_ACL_SUPPORT=y
CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
+CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
@@ -1120,8 +1375,14 @@ CONFIG_NLS_ISO8859_15=m
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -1130,7 +1391,10 @@ 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
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -1146,6 +1410,8 @@ CONFIG_OPROFILE=y
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=15
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1159,12 +1425,11 @@ CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_SPINLOCK_SLEEP=y
# 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_FORCED_INLINING is not set
-# CONFIG_HEADERS_CHECK is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
@@ -1191,6 +1456,7 @@ CONFIG_CRYPTO_BLKCIPHER=m
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=m
@@ -1199,8 +1465,10 @@ CONFIG_CRYPTO_SHA1=m
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_LRW is not set
CONFIG_CRYPTO_DES=m
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/powerpc/configs/celleb_defconfig b/arch/powerpc/configs/celleb_defconfig
new file mode 100644
index 00000000000..a1fe97197ea
--- /dev/null
+++ b/arch/powerpc/configs/celleb_defconfig
@@ -0,0 +1,1408 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc4
+# Thu Jan 11 20:55:33 2007
+#
+CONFIG_PPC64=y
+CONFIG_64BIT=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+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_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+# CONFIG_POWER4_ONLY is not set
+CONFIG_POWER3=y
+CONFIG_POWER4=y
+CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_OF_PLATFORM_PCI=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_VIRT_CPU_ACCOUNTING=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=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 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_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=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=y
+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 is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# 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=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_APUS is not set
+# CONFIG_PPC_PSERIES is not set
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_PPC_MPC52xx 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 is not set
+# CONFIG_PPC_IBM_CELL_BLADE is not set
+# CONFIG_PPC_PS3 is not set
+CONFIG_PPC_CELLEB=y
+CONFIG_PPC_UDBG_BEAT=y
+# CONFIG_U3_DART is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+# CONFIG_MPIC is not set
+
+#
+# Cell Broadband Engine options
+#
+CONFIG_SPU_FS=y
+CONFIG_SPU_BASE=y
+# CONFIG_CBE_RAS is not set
+
+#
+# Kernel options
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# 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_PREEMPT_BKL=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_FORCE_MAX_ZONEORDER=13
+# CONFIG_IOMMU_VMERGE is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=4
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_NEED_MULTIPLE_NODES=y
+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_ARCH_MEMORY_PROBE=y
+CONFIG_NODES_SPAN_OTHER_NODES=y
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_SCHED_SMT 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
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_INDIRECT_PCI is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_KERNEL_START=0xc000000000000000
+
+#
+# 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 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_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"
+# CONFIG_TCP_MD5SIG is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+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_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES 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_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_QUEUE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP6_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 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_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_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=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=131072
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE 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=y
+CONFIG_BLK_DEV_IDECD=m
+# 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=y
+# 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=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 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_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_SL82C105 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_CELLEB=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# 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=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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_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_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_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_DEBUG is not set
+# CONFIG_SCSI_SRP 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
+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=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_EMC 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
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_WINDFARM 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_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 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_SPIDER_NET=y
+# 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
+# CONFIG_NETXEN_NIC 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
+# 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=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 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=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_MOXA_SMARTIO_NEW is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
+# 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
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_TXX9=y
+CONFIG_HAS_TXX9_SERIAL=y
+CONFIG_SERIAL_TXX9_CONSOLE=y
+# CONFIG_SERIAL_TXX9_STDSERIAL is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_BEAT=y
+
+#
+# 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
+
+#
+# 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 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
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# 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_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
+
+#
+# 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_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 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
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# 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_MULTITHREAD_PROBE is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+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_EHCI_BIG_ENDIAN_MMIO=y
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+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=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
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# 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_MII 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_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR 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
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XIP=y
+CONFIG_FS_XIP=y
+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
+# CONFIG_REISERFS_FS is not set
+# 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
+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=y
+# CONFIG_ZISOFS is not set
+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=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=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=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 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=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=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+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 is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+# CONFIG_KPROBES 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_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=15
+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=y
+# 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_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
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUGGER=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+CONFIG_XMON_DISASSEMBLY=y
+CONFIG_IRQSTACKS=y
+# CONFIG_BOOTX_TEXT is not set
+CONFIG_PPC_EARLY_DEBUG=y
+# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
+# CONFIG_PPC_EARLY_DEBUG_G5 is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set
+# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
+# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+CONFIG_PPC_EARLY_DEBUG_BEAT=y
+
+#
+# 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=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_LRW is not set
+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=m
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/chrp32_defconfig b/arch/powerpc/configs/chrp32_defconfig
index fee72f8a2fb..029c9a0e730 100644
--- a/arch/powerpc/configs/chrp32_defconfig
+++ b/arch/powerpc/configs/chrp32_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:22:54 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:12:58 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -21,13 +22,14 @@ 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_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
# Processor support
#
CONFIG_CLASSIC32=y
-# CONFIG_PPC_52xx is not set
# CONFIG_PPC_82xx is not set
# CONFIG_PPC_83xx is not set
# CONFIG_PPC_85xx is not set
@@ -38,6 +40,8 @@ CONFIG_CLASSIC32=y
# CONFIG_E200 is not set
CONFIG_6xx=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
@@ -59,18 +63,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_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
# CONFIG_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=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=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -79,12 +87,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
@@ -103,6 +111,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
@@ -124,13 +133,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_CHRP=y
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_EFIKA is not set
+# CONFIG_PPC_LITE5200 is not set
# CONFIG_PPC_PMAC is not set
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
+CONFIG_PPC_NATIVE=y
# CONFIG_UDBG_RTAS_CONSOLE is not set
CONFIG_PPC_RTAS=y
# CONFIG_RTAS_ERROR_LOGGING is not set
@@ -138,6 +150,8 @@ CONFIG_RTAS_PROC=y
# CONFIG_MMIO_NVRAM is not set
CONFIG_PPC_MPC106=y
# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
# CONFIG_CPU_FREQ is not set
# CONFIG_TAU is not set
# CONFIG_WANT_EARLY_SERIAL is not set
@@ -149,6 +163,7 @@ CONFIG_MPIC=y
CONFIG_HIGHMEM=y
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -161,6 +176,7 @@ CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
# CONFIG_KEXEC is not set
CONFIG_IRQ_ALL_CPUS=y
CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -243,10 +259,13 @@ CONFIG_SYN_COOKIES=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
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
#
# IP: Virtual Server Configuration
@@ -263,24 +282,29 @@ CONFIG_NETFILTER=y
# Core Netfilter Configuration
#
# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NF_CONNTRACK_ENABLED=m
+CONFIG_NF_CONNTRACK_SUPPORT=y
+# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set
+CONFIG_NF_CONNTRACK=m
+# CONFIG_NF_CT_ACCT is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=m
+# CONFIG_NF_CONNTRACK_H323 is not set
+CONFIG_NF_CONNTRACK_IRC=m
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
# CONFIG_NETFILTER_XTABLES is not set
#
# IP: Netfilter Configuration
#
-CONFIG_IP_NF_CONNTRACK=m
-# 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=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_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
# CONFIG_IP_NF_QUEUE is not set
#
@@ -306,7 +330,6 @@ CONFIG_IP_NF_AMANDA=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
@@ -381,6 +404,12 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
@@ -407,7 +436,6 @@ CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_SL82C105=y
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
@@ -422,6 +450,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
@@ -430,6 +459,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
# 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_SL82C105=y
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
CONFIG_BLK_DEV_VIA82CXXX=y
@@ -445,6 +475,8 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -464,14 +496,16 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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
@@ -487,12 +521,13 @@ 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_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_ATA is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
@@ -506,17 +541,18 @@ CONFIG_SCSI_SPI_ATTRS=y
# 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=y
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
CONFIG_SCSI_SYM53C8XX_MMIO=y
-# 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_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_DC395x is not set
@@ -525,6 +561,12 @@ CONFIG_SCSI_SYM53C8XX_MMIO=y
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Old CD-ROM drivers (not SCSI, not IDE)
@@ -557,6 +599,7 @@ CONFIG_SCSI_SYM53C8XX_MMIO=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -607,6 +650,7 @@ CONFIG_DE4X5=y
# CONFIG_NET_ISA 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_AC3200 is not set
@@ -655,6 +699,7 @@ CONFIG_MV643XX_ETH=y
# CONFIG_MV643XX_ETH_0 is not set
# CONFIG_MV643XX_ETH_1 is not set
# CONFIG_MV643XX_ETH_2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -663,6 +708,7 @@ CONFIG_MV643XX_ETH=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -690,6 +736,7 @@ CONFIG_PPP_BSDCOMP=m
CONFIG_PPP_MPPE=m
CONFIG_PPPOE=m
# CONFIG_SLIP is not set
+CONFIG_SLHC=m
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
@@ -710,6 +757,7 @@ CONFIG_PPPOE=m
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -732,6 +780,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
@@ -778,12 +827,14 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
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
+CONFIG_BRIQ_PANEL=m
# CONFIG_HVC_RTAS is not set
#
@@ -802,10 +853,6 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -814,7 +861,6 @@ CONFIG_GEN_RTC=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -881,6 +927,7 @@ CONFIG_I2C_ALGOBIT=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -889,14 +936,9 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_HWMON_VID is not set
#
-# Misc devices
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -909,6 +951,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
CONFIG_FB=y
+CONFIG_FB_DDC=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
@@ -949,6 +992,7 @@ CONFIG_FB_3DFX=y
# CONFIG_FB_3DFX_ACCEL is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -979,6 +1023,11 @@ CONFIG_LOGO_LINUX_CLUT224=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -993,6 +1042,7 @@ CONFIG_USB=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -1034,13 +1084,13 @@ CONFIG_USB_STORAGE=m
# 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 is not set
@@ -1070,6 +1120,7 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
CONFIG_USB_MON=y
@@ -1087,6 +1138,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
@@ -1094,12 +1146,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
#
@@ -1157,6 +1210,10 @@ CONFIG_USB_MON=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1166,6 +1223,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
@@ -1173,6 +1231,7 @@ CONFIG_FS_MBCACHE=y
# 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
@@ -1207,8 +1266,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_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -1308,17 +1369,22 @@ CONFIG_NLS_ISO8859_1=m
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=m
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=m
CONFIG_ZLIB_DEFLATE=m
-CONFIG_TEXTSEARCH=y
-CONFIG_TEXTSEARCH_KMP=m
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -1329,8 +1395,11 @@ 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=15
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1345,14 +1414,16 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_HIGHMEM 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_DEBUG_LIST is not set
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_DEBUGGER=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
+CONFIG_XMON_DISASSEMBLY=y
# CONFIG_BDI_SWITCH is not set
# CONFIG_BOOTX_TEXT is not set
# CONFIG_PPC_EARLY_DEBUG is not set
@@ -1367,7 +1438,11 @@ CONFIG_XMON_DEFAULT=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_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
@@ -1376,6 +1451,10 @@ CONFIG_CRYPTO_SHA1=m
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_LRW is not set
# CONFIG_CRYPTO_DES is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 92d0a9dd0b8..7724847f702 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:22:55 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:15:04 2007
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -10,6 +10,8 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -22,6 +24,8 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_PPC_OF=y
# CONFIG_PPC_UDBG_16550 is not set
CONFIG_GENERIC_TBSYNC=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
@@ -30,6 +34,9 @@ CONFIG_GENERIC_TBSYNC=y
CONFIG_POWER4_ONLY=y
CONFIG_POWER4=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+# CONFIG_PPC_OF_PLATFORM_PCI is not set
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_VIRT_CPU_ACCOUNTING=y
@@ -51,18 +58,22 @@ 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
# CONFIG_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=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=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -71,12 +82,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 +106,7 @@ CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
#
@@ -114,23 +126,28 @@ 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_MPC52xx is not set
CONFIG_PPC_PMAC=y
CONFIG_PPC_PMAC64=y
# 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_PPC_IBM_CELL_BLADE is not set
-# CONFIG_UDBG_RTAS_CONSOLE is not set
+# CONFIG_PPC_PS3 is not set
+CONFIG_PPC_NATIVE=y
CONFIG_U3_DART=y
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
CONFIG_MPIC_BROKEN_U3=y
# CONFIG_PPC_MPC106 is not set
CONFIG_PPC_970_NAP=y
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=y
# CONFIG_CPU_FREQ_DEBUG is not set
@@ -152,6 +169,7 @@ CONFIG_MPIC=y
#
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -171,6 +189,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
@@ -225,6 +244,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_NET_KEY=m
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -243,10 +263,13 @@ 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=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_TCP_MD5SIG is not set
#
# IP: Virtual Server Configuration
@@ -263,24 +286,29 @@ CONFIG_NETFILTER=y
# Core Netfilter Configuration
#
# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NF_CONNTRACK_ENABLED=m
+CONFIG_NF_CONNTRACK_SUPPORT=y
+# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set
+CONFIG_NF_CONNTRACK=m
+# CONFIG_NF_CT_ACCT is not set
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=m
+# CONFIG_NF_CONNTRACK_H323 is not set
+CONFIG_NF_CONNTRACK_IRC=m
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+CONFIG_NF_CONNTRACK_TFTP=m
# 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=y
-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 is not set
-# CONFIG_IP_NF_H323 is not set
-# CONFIG_IP_NF_SIP is not set
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
CONFIG_IP_NF_QUEUE=m
#
@@ -307,7 +335,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
@@ -382,6 +409,12 @@ CONFIG_CDROM_PKTCDVD_BUFFERS=8
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
@@ -408,7 +441,6 @@ CONFIG_BLK_DEV_IDEPCI=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_SL82C105 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
@@ -423,6 +455,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
@@ -431,6 +464,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
# 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_SL82C105 is not set
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
@@ -448,6 +482,8 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -467,14 +503,16 @@ CONFIG_CHR_DEV_SG=y
CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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
@@ -487,26 +525,12 @@ 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_ARCMSR is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-CONFIG_ATA=y
-# CONFIG_SATA_AHCI is not set
-CONFIG_SATA_SVW=y
-# CONFIG_SCSI_ATA_PIIX 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_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
@@ -515,14 +539,71 @@ CONFIG_SATA_SVW=y
# 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
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_SATA_AHCI is not set
+CONFIG_SATA_SVW=y
+# 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_MARVELL 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)
@@ -537,6 +618,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
@@ -591,11 +673,13 @@ CONFIG_IEEE1394_RAWIO=y
CONFIG_ADB_PMU=y
# CONFIG_ADB_PMU_LED is not set
CONFIG_PMAC_SMU=y
+CONFIG_MAC_EMUMOUSEBTN=y
CONFIG_THERM_PM72=y
CONFIG_WINDFARM=y
CONFIG_WINDFARM_PM81=y
CONFIG_WINDFARM_PM91=y
CONFIG_WINDFARM_PM112=y
+# CONFIG_PMAC_RACKMETER is not set
#
# Network device support
@@ -652,7 +736,7 @@ CONFIG_E1000=y
# CONFIG_SK98LIN 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)
@@ -661,6 +745,7 @@ CONFIG_TIGON3=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -691,6 +776,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 is not set
@@ -711,6 +797,7 @@ CONFIG_PPPOE=m
# Input device support
#
CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=y
#
# Userland interfaces
@@ -733,6 +820,7 @@ CONFIG_INPUT_KEYBOARD=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 is not set
# CONFIG_MOUSE_SERIAL is not set
@@ -789,13 +877,7 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
CONFIG_AGP=m
-# CONFIG_AGP_SIS is not set
-# CONFIG_AGP_VIA is not set
CONFIG_AGP_UNINORTH=m
# CONFIG_DRM is not set
CONFIG_RAW_DRIVER=y
@@ -806,7 +888,6 @@ CONFIG_MAX_RAW_DEVS=256
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -871,6 +952,7 @@ CONFIG_I2C_POWERMAC=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -879,14 +961,9 @@ CONFIG_I2C_POWERMAC=y
# CONFIG_HWMON_VID is not set
#
-# Misc devices
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -899,6 +976,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
CONFIG_FB=y
+CONFIG_FB_DDC=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
@@ -930,6 +1008,7 @@ CONFIG_FB_RADEON_I2C=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -1080,6 +1159,11 @@ CONFIG_SND_USB_AUDIO=m
# CONFIG_SOUND_PRIME is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1094,6 +1178,7 @@ CONFIG_USB=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -1135,18 +1220,19 @@ CONFIG_USB_STORAGE_SDDR55=y
CONFIG_USB_STORAGE_JUMPSHOT=y
# 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=y
CONFIG_HID_PID=y
CONFIG_LOGITECH_FF=y
CONFIG_THRUSTMASTER_FF=y
+# CONFIG_ZEROPLUS_FF is not set
CONFIG_USB_HIDDEV=y
# CONFIG_USB_AIPTEK is not set
# CONFIG_USB_WACOM is not set
@@ -1174,12 +1260,14 @@ CONFIG_USB_CATC=m
CONFIG_USB_KAWETH=m
CONFIG_USB_PEGASUS=m
CONFIG_USB_RTL8150=m
+# CONFIG_USB_USBNET_MII is not set
CONFIG_USB_USBNET=m
# CONFIG_USB_NET_AX8817X is not set
CONFIG_USB_NET_CDCETHER=m
# CONFIG_USB_NET_GL620A is not set
# CONFIG_USB_NET_NET1080 is not set
# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
# CONFIG_USB_NET_RNDIS_HOST is not set
# CONFIG_USB_NET_CDC_SUBSET is not set
# CONFIG_USB_NET_ZAURUS is not set
@@ -1194,6 +1282,7 @@ CONFIG_USB_MON=y
#
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 is not set
CONFIG_USB_SERIAL_BELKIN=m
@@ -1228,6 +1317,8 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
CONFIG_USB_SERIAL_KLSI=m
CONFIG_USB_SERIAL_KOBIL_SCT=m
CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_USB_SERIAL_MOS7720 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
@@ -1239,6 +1330,7 @@ CONFIG_USB_SERIAL_CYBERJACK=m
CONFIG_USB_SERIAL_XIRCOM=m
# CONFIG_USB_SERIAL_OPTION is not set
CONFIG_USB_SERIAL_OMNINET=m
+# CONFIG_USB_SERIAL_DEBUG is not set
CONFIG_USB_EZUSB=y
#
@@ -1246,6 +1338,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
@@ -1253,12 +1346,13 @@ 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=m
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_TEST is not set
#
@@ -1316,6 +1410,10 @@ CONFIG_USB_APPLEDISPLAY=m
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1328,6 +1426,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
@@ -1344,6 +1443,7 @@ CONFIG_XFS_FS=m
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 is not set
# CONFIG_ROMFS_FS is not set
@@ -1380,8 +1480,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
@@ -1505,17 +1607,22 @@ CONFIG_NLS_ISO8859_15=y
CONFIG_NLS_UTF8=y
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=m
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=m
-CONFIG_TEXTSEARCH=y
-CONFIG_TEXTSEARCH_KMP=m
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -1528,8 +1635,11 @@ CONFIG_OPROFILE=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_FS=y
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=17
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1543,9 +1653,10 @@ CONFIG_DEBUG_MUTEXES=y
# 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_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_DEBUG_STACKOVERFLOW is not set
@@ -1565,7 +1676,12 @@ CONFIG_BOOTX_TEXT=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
@@ -1574,9 +1690,14 @@ CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
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/iseries_defconfig b/arch/powerpc/configs/iseries_defconfig
index b5005506c2f..5fc87448704 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.19-rc1
-# Fri Oct 6 13:25:04 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:16:44 2007
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -10,6 +10,8 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -23,6 +25,7 @@ CONFIG_PPC_OF=y
# CONFIG_PPC_UDBG_16550 is not set
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
@@ -32,6 +35,9 @@ CONFIG_AUDIT_ARCH=y
CONFIG_POWER3=y
CONFIG_POWER4=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+# CONFIG_PPC_OF_PLATFORM_PCI is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_VIRT_CPU_ACCOUNTING=y
@@ -63,12 +69,13 @@ CONFIG_AUDITSYSCALL=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=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_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -125,18 +132,22 @@ CONFIG_PPC_MULTIPLATFORM=y
# CONFIG_APUS is not set
# CONFIG_PPC_PSERIES is not set
CONFIG_PPC_ISERIES=y
+# CONFIG_PPC_MPC52xx is not set
# 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_PPC_IBM_CELL_BLADE is not set
+# CONFIG_PPC_PS3 is not set
# CONFIG_U3_DART is not set
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
CONFIG_IBMVIO=y
# CONFIG_PPC_MPC106 is not set
# CONFIG_PPC_970_NAP is not set
+CONFIG_PPC_INDIRECT_IO=y
+CONFIG_GENERIC_IOMAP=y
# CONFIG_CPU_FREQ is not set
# CONFIG_WANT_EARLY_SERIAL is not set
# CONFIG_MPIC is not set
@@ -146,6 +157,7 @@ CONFIG_IBMVIO=y
#
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -178,6 +190,7 @@ CONFIG_RESOURCES_64BIT=y
# CONFIG_PPC_64K_PAGES is not set
# CONFIG_SCHED_SMT 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
@@ -192,7 +205,6 @@ 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
#
@@ -245,6 +257,7 @@ CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
#
# IP: Virtual Server Configuration
@@ -261,21 +274,37 @@ CONFIG_NETFILTER=y
# Core Netfilter Configuration
#
# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NF_CONNTRACK_ENABLED=m
+CONFIG_NF_CONNTRACK_SUPPORT=y
+# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set
+CONFIG_NF_CONNTRACK=m
+# CONFIG_NF_CT_ACCT is not set
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=m
+# CONFIG_NF_CONNTRACK_H323 is not set
+CONFIG_NF_CONNTRACK_IRC=m
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+CONFIG_NF_CONNTRACK_TFTP=m
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
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
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 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_HELPER is not set
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
CONFIG_NETFILTER_XT_MATCH_MAC=m
@@ -286,27 +315,17 @@ 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_STATE is not set
# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT 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=y
-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 is not set
-# CONFIG_IP_NF_H323 is not set
-# CONFIG_IP_NF_SIP is not set
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_IPRANGE=m
@@ -317,23 +336,25 @@ CONFIG_IP_NF_MATCH_ECN=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_NF_NAT=m
+CONFIG_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_NF_NAT_SNMP_BASIC is not set
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_SIP is not set
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_TOS=m
CONFIG_IP_NF_TARGET_ECN=m
@@ -440,6 +461,12 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -449,6 +476,7 @@ CONFIG_BLK_DEV_INITRD=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
@@ -469,6 +497,7 @@ CONFIG_CHR_DEV_SG=y
CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
#
# SCSI Transports
@@ -515,6 +544,7 @@ CONFIG_SCSI_IBMVSCSI=m
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
#
# Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -562,6 +592,7 @@ CONFIG_DM_ZERO=m
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -647,6 +678,7 @@ CONFIG_E1000=m
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -765,10 +797,6 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
CONFIG_RAW_DRIVER=y
@@ -779,7 +807,6 @@ CONFIG_MAX_RAW_DEVS=256
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -795,6 +822,7 @@ CONFIG_MAX_RAW_DEVS=256
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -803,11 +831,6 @@ CONFIG_MAX_RAW_DEVS=256
# CONFIG_HWMON_VID is not set
#
-# Misc devices
-#
-# CONFIG_TIFM_CORE is not set
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
@@ -822,6 +845,7 @@ CONFIG_MAX_RAW_DEVS=256
#
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -830,6 +854,11 @@ CONFIG_FIRMWARE_EDID=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+# CONFIG_HID is not set
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -892,6 +921,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -904,6 +937,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
@@ -937,6 +971,7 @@ CONFIG_DNOTIFY=y
CONFIG_AUTOFS_FS=m
# CONFIG_AUTOFS4_FS is not set
# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
#
# CD-ROM/DVD Filesystems
@@ -1024,7 +1059,6 @@ 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
@@ -1080,6 +1114,8 @@ CONFIG_NLS_ISO8859_1=y
# Distributed Lock Manager
#
CONFIG_DLM=m
+CONFIG_DLM_TCP=y
+# CONFIG_DLM_SCTP is not set
# CONFIG_DLM_DEBUG is not set
#
@@ -1094,6 +1130,7 @@ CONFIG_VIOPATH=y
#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=m
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -1105,6 +1142,7 @@ CONFIG_TEXTSEARCH_KMP=m
CONFIG_TEXTSEARCH_BM=m
CONFIG_TEXTSEARCH_FSM=m
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -1119,6 +1157,8 @@ CONFIG_PLIST=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=17
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1132,8 +1172,8 @@ 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_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_FORCED_INLINING is not set
@@ -1142,6 +1182,7 @@ CONFIG_DEBUG_STACKOVERFLOW=y
CONFIG_DEBUG_STACK_USAGE=y
# CONFIG_DEBUGGER is not set
CONFIG_IRQSTACKS=y
+# CONFIG_BOOTX_TEXT is not set
# CONFIG_PPC_EARLY_DEBUG is not set
#
@@ -1155,10 +1196,11 @@ CONFIG_IRQSTACKS=y
#
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
@@ -1167,8 +1209,10 @@ CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_TGR192=m
+# CONFIG_CRYPTO_GF128MUL is not set
CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
diff --git a/arch/powerpc/configs/linkstation_defconfig b/arch/powerpc/configs/linkstation_defconfig
index 23fd210eb56..405c1c90821 100644
--- a/arch/powerpc/configs/linkstation_defconfig
+++ b/arch/powerpc/configs/linkstation_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc4
-# Wed Nov 15 20:36:30 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:17:58 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -22,13 +23,13 @@ CONFIG_PPC_OF=y
CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
# Processor support
#
CONFIG_CLASSIC32=y
-# CONFIG_PPC_52xx is not set
# CONFIG_PPC_82xx is not set
# CONFIG_PPC_83xx is not set
# CONFIG_PPC_85xx is not set
@@ -69,12 +70,13 @@ CONFIG_POSIX_MQUEUE=y
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=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_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -130,6 +132,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_PPC_MULTIPLATFORM is not set
CONFIG_EMBEDDED6xx=y
# CONFIG_APUS is not set
+# CONFIG_PPC_MPC52xx is not set
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_RTAS is not set
@@ -166,7 +169,6 @@ CONFIG_LINKSTATION=y
# CONFIG_TQM8260 is not set
# CONFIG_ADS8272 is not set
# CONFIG_PQ2FADS is not set
-# CONFIG_LITE5200 is not set
# CONFIG_EV64360 is not set
CONFIG_PPC_GEN550=y
CONFIG_MPC10X_BRIDGE=y
@@ -181,6 +183,7 @@ CONFIG_MPIC=y
# CONFIG_HIGHMEM is not set
CONFIG_HZ_100=y
# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=100
CONFIG_PREEMPT_NONE=y
@@ -217,7 +220,6 @@ CONFIG_FSL_SOC=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
#
@@ -286,6 +288,7 @@ CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
#
# IP: Virtual Server Configuration
@@ -302,18 +305,35 @@ CONFIG_NETFILTER=y
# Core Netfilter Configuration
#
# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NF_CONNTRACK_ENABLED=m
+CONFIG_NF_CONNTRACK_SUPPORT=y
+# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set
+CONFIG_NF_CONNTRACK=m
+# CONFIG_NF_CT_ACCT is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=m
+# CONFIG_NF_CONNTRACK_H323 is not set
+CONFIG_NF_CONNTRACK_IRC=m
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NETFILTER_XTABLES=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
CONFIG_NETFILTER_XT_TARGET_MARK=m
# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
CONFIG_NETFILTER_XT_MATCH_ESP=m
-# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
CONFIG_NETFILTER_XT_MATCH_MAC=m
@@ -324,27 +344,17 @@ CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
# CONFIG_NETFILTER_XT_MATCH_REALM is not set
# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
-CONFIG_NETFILTER_XT_MATCH_STATE=m
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
# CONFIG_NETFILTER_XT_MATCH_STRING is not set
# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
#
# IP: Netfilter Configuration
#
-CONFIG_IP_NF_CONNTRACK=m
-# 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=m
-# CONFIG_IP_NF_NETBIOS_NS is not set
-CONFIG_IP_NF_TFTP=m
-# CONFIG_IP_NF_AMANDA is not set
-# CONFIG_IP_NF_PPTP is not set
-# CONFIG_IP_NF_H323 is not set
-# CONFIG_IP_NF_SIP is not set
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
# CONFIG_IP_NF_QUEUE is not set
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_IPRANGE=m
@@ -355,22 +365,25 @@ CONFIG_IP_NF_MATCH_IPRANGE=m
# CONFIG_IP_NF_MATCH_TTL is not set
# CONFIG_IP_NF_MATCH_OWNER is not set
# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
-# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
# CONFIG_IP_NF_TARGET_LOG is not set
# CONFIG_IP_NF_TARGET_ULOG is not set
# CONFIG_IP_NF_TARGET_TCPMSS is not set
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_NF_NAT=m
+CONFIG_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 is not set
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_SIP is not set
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_TOS=m
CONFIG_IP_NF_TARGET_ECN=m
@@ -580,6 +593,7 @@ CONFIG_BLK_DEV_INITRD=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
@@ -599,6 +613,7 @@ CONFIG_CHR_DEV_SG=y
CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
#
# SCSI Transports
@@ -646,6 +661,7 @@ CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
#
# Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -683,6 +699,7 @@ CONFIG_ATA=y
# CONFIG_PATA_IT821X is not set
# CONFIG_PATA_JMICRON is not set
# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
# CONFIG_PATA_MPIIX is not set
# CONFIG_PATA_OLDPIIX is not set
# CONFIG_PATA_NETCELL is not set
@@ -726,6 +743,7 @@ CONFIG_PATA_SIL680=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -777,6 +795,7 @@ CONFIG_R8169=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -899,6 +918,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
@@ -921,10 +941,6 @@ CONFIG_HW_RANDOM=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -1032,6 +1048,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
@@ -1042,6 +1059,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
@@ -1063,6 +1081,7 @@ CONFIG_HWMON=y
#
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
#
# Console display driver support
@@ -1077,6 +1096,11 @@ CONFIG_DUMMY_CONSOLE=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1091,6 +1115,7 @@ CONFIG_USB=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -1170,6 +1195,7 @@ CONFIG_USB_STORAGE=m
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
CONFIG_USB_MON=y
@@ -1218,6 +1244,7 @@ CONFIG_USB_SERIAL_FTDI_SIO=y
# CONFIG_USB_SERIAL_XIRCOM is not set
# CONFIG_USB_SERIAL_OPTION is not set
# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
#
# USB Miscellaneous drivers
@@ -1324,6 +1351,10 @@ CONFIG_RTC_DRV_RS5C372=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1398,7 +1429,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
@@ -1488,8 +1518,14 @@ CONFIG_NLS_ISO8859_1=m
CONFIG_NLS_UTF8=m
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -1497,6 +1533,7 @@ CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=m
CONFIG_ZLIB_DEFLATE=m
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -1511,6 +1548,8 @@ CONFIG_OPROFILE=m
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1524,12 +1563,11 @@ 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_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_FORCED_INLINING=y
-# CONFIG_HEADERS_CHECK is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_DEBUGGER is not set
# CONFIG_BDI_SWITCH is not set
@@ -1551,6 +1589,7 @@ CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
@@ -1559,8 +1598,10 @@ CONFIG_CRYPTO_SHA1=m
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
diff --git a/arch/powerpc/configs/lite5200_defconfig b/arch/powerpc/configs/lite5200_defconfig
index ee7655776d4..8cbd87ded6b 100644
--- a/arch/powerpc/configs/lite5200_defconfig
+++ b/arch/powerpc/configs/lite5200_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc6
-# Mon Nov 27 11:08:20 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:18:18 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -22,13 +23,13 @@ CONFIG_PPC_OF=y
# CONFIG_PPC_UDBG_16550 is not set
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
# Processor support
#
CONFIG_CLASSIC32=y
-# CONFIG_PPC_52xx is not set
# CONFIG_PPC_82xx is not set
# CONFIG_PPC_83xx is not set
# CONFIG_PPC_85xx is not set
@@ -68,6 +69,7 @@ CONFIG_SYSVIPC=y
# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -151,6 +153,7 @@ CONFIG_PPC_LITE5200=y
# CONFIG_HIGHMEM is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -259,6 +262,7 @@ CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -374,6 +378,7 @@ CONFIG_BLK_DEV_INITRD=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
# CONFIG_SCSI_PROC_FS is not set
@@ -393,6 +398,7 @@ CONFIG_SCSI=y
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
#
# SCSI Transports
@@ -440,6 +446,7 @@ CONFIG_SCSI=y
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
#
# Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -477,7 +484,7 @@ CONFIG_ATA=y
# CONFIG_PATA_IT821X is not set
# CONFIG_PATA_JMICRON is not set
# CONFIG_PATA_TRIFLEX is not set
-CONFIG_PATA_MPC52xx=y
+# CONFIG_PATA_MARVELL is not set
# CONFIG_PATA_MPIIX is not set
# CONFIG_PATA_OLDPIIX is not set
# CONFIG_PATA_NETCELL is not set
@@ -494,6 +501,7 @@ CONFIG_PATA_MPC52xx=y
# CONFIG_PATA_SIS is not set
# CONFIG_PATA_VIA is not set
# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
#
# Multi-device support (RAID and LVM)
@@ -521,6 +529,7 @@ CONFIG_PATA_MPC52xx=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -572,6 +581,7 @@ CONFIG_NETDEVICES=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -632,6 +642,7 @@ CONFIG_NETDEVICES=y
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_MPC52xx=y
@@ -657,10 +668,6 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -707,6 +714,7 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -777,6 +785,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -873,6 +885,11 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
# CONFIG_CRC_CCITT is not set
@@ -880,6 +897,7 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_CRC32 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -893,6 +911,8 @@ CONFIG_PRINTK_TIME=y
CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -906,12 +926,11 @@ 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_BUGVERBOSE 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_HEADERS_CHECK is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_DEBUGGER is not set
# CONFIG_BDI_SWITCH is not set
diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig
index ae96a5b2f00..de97f2f0ae9 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
-# Mon Oct 9 11:59:34 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:19:02 2007
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -10,6 +10,8 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -23,6 +25,7 @@ CONFIG_PPC_OF=y
CONFIG_PPC_UDBG_16550=y
CONFIG_GENERIC_TBSYNC=y
CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
@@ -31,6 +34,9 @@ CONFIG_AUDIT_ARCH=y
CONFIG_POWER4_ONLY=y
CONFIG_POWER4=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+# CONFIG_PPC_OF_PLATFORM_PCI is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_VIRT_CPU_ACCOUNTING=y
@@ -61,12 +67,13 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=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_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -123,18 +130,27 @@ CONFIG_PPC_MULTIPLATFORM=y
# CONFIG_APUS is not set
# CONFIG_PPC_PSERIES is not set
# CONFIG_PPC_ISERIES is not set
+# CONFIG_PPC_MPC52xx 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_PPC_PS3 is not set
+CONFIG_PPC_NATIVE=y
+CONFIG_UDBG_RTAS_CONSOLE=y
CONFIG_U3_DART=y
-# CONFIG_PPC_RTAS is not set
+CONFIG_PPC_RTAS=y
+# CONFIG_RTAS_ERROR_LOGGING is not set
+CONFIG_RTAS_PROC=y
+# CONFIG_RTAS_FLASH is not set
# CONFIG_MMIO_NVRAM is not set
CONFIG_MPIC_BROKEN_U3=y
# CONFIG_PPC_MPC106 is not set
CONFIG_PPC_970_NAP=y
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
# CONFIG_CPU_FREQ is not set
# CONFIG_WANT_EARLY_SERIAL is not set
CONFIG_MPIC=y
@@ -144,6 +160,7 @@ CONFIG_MPIC=y
#
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -190,7 +207,6 @@ 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
#
@@ -246,6 +262,7 @@ CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -346,6 +363,12 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
@@ -371,7 +394,6 @@ CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
@@ -395,6 +417,7 @@ CONFIG_BLK_DEV_AMD74XX=y
# 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_SL82C105 is not set
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
@@ -439,6 +462,7 @@ CONFIG_IDEDMA_AUTO=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -523,6 +547,7 @@ CONFIG_TIGON3=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -618,6 +643,8 @@ CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_RTAS=y
#
# IPMI
@@ -634,10 +661,6 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -647,7 +670,6 @@ CONFIG_GEN_RTC=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -711,6 +733,7 @@ CONFIG_I2C_AMD8111=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -719,15 +742,9 @@ CONFIG_I2C_AMD8111=y
# CONFIG_HWMON_VID 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
@@ -740,6 +757,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
#
# Console display driver support
@@ -754,6 +772,11 @@ CONFIG_DUMMY_CONSOLE=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -768,6 +791,7 @@ CONFIG_USB=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -803,7 +827,6 @@ CONFIG_USB_UHCI_HCD=y
# 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 is not set
@@ -819,7 +842,6 @@ 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
@@ -833,6 +855,7 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_KAWETH is not set
CONFIG_USB_PEGASUS=y
# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
CONFIG_USB_MON=y
@@ -881,6 +904,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_MOS7720 is not set
# CONFIG_USB_SERIAL_MOS7840 is not set
# CONFIG_USB_SERIAL_NAVMAN is not set
# CONFIG_USB_SERIAL_PL2303 is not set
@@ -892,6 +916,7 @@ CONFIG_USB_SERIAL_TI=m
# CONFIG_USB_SERIAL_XIRCOM is not set
# CONFIG_USB_SERIAL_OPTION is not set
# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
CONFIG_USB_EZUSB=y
#
@@ -913,6 +938,7 @@ CONFIG_USB_EZUSB=y
# 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
#
@@ -970,6 +996,10 @@ CONFIG_USB_EZUSB=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -978,12 +1008,14 @@ CONFIG_EXT2_FS_XIP=y
CONFIG_FS_XIP=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
# CONFIG_REISERFS_FS is not set
# 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
@@ -1133,14 +1165,21 @@ CONFIG_NLS_DEFAULT="utf-8"
CONFIG_NLS_UTF8=y
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=y
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -1155,6 +1194,8 @@ CONFIG_PLIST=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=17
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1169,8 +1210,8 @@ CONFIG_DEBUG_SLAB=y
CONFIG_DEBUG_SPINLOCK_SLEEP=y
# 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_FORCED_INLINING is not set
@@ -1180,6 +1221,7 @@ CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUGGER=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
+CONFIG_XMON_DISASSEMBLY=y
# CONFIG_IRQSTACKS is not set
CONFIG_BOOTX_TEXT=y
# CONFIG_PPC_EARLY_DEBUG is not set
@@ -1195,9 +1237,10 @@ CONFIG_BOOTX_TEXT=y
#
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_BLKCIPHER=m
-CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
@@ -1206,8 +1249,10 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
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 d1811e75451..fdf09eabe6e 100644
--- a/arch/powerpc/configs/mpc7448_hpc2_defconfig
+++ b/arch/powerpc/configs/mpc7448_hpc2_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:26:55 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:20:53 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -21,13 +22,14 @@ 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_GENERIC_BUG=y
CONFIG_DEFAULT_UIMAGE=y
#
# Processor support
#
CONFIG_CLASSIC32=y
-# CONFIG_PPC_52xx is not set
# CONFIG_PPC_82xx is not set
# CONFIG_PPC_83xx is not set
# CONFIG_PPC_85xx is not set
@@ -38,6 +40,8 @@ CONFIG_CLASSIC32=y
# CONFIG_E200 is not set
CONFIG_6xx=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
@@ -58,16 +62,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_TASKSTATS is not set
-CONFIG_SYSCTL=y
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=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=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
@@ -75,12 +83,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
@@ -93,6 +101,7 @@ CONFIG_BASE_SMALL=0
#
# Block layer
#
+CONFIG_BLOCK=y
CONFIG_LBD=y
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -114,19 +123,19 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# Platform support
#
# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_PPC_ISERIES is not set
CONFIG_EMBEDDED6xx=y
# CONFIG_APUS is not set
+# CONFIG_PPC_MPC52xx 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_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
# CONFIG_PPC_MPC106 is not set
# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
# CONFIG_CPU_FREQ is not set
# CONFIG_TAU is not set
-# CONFIG_PPC_TODC is not set
# CONFIG_KATANA is not set
# CONFIG_WILLOW is not set
# CONFIG_CPCI690 is not set
@@ -141,6 +150,7 @@ CONFIG_EMBEDDED6xx=y
# CONFIG_PRPMC750 is not set
# CONFIG_PRPMC800 is not set
# CONFIG_SANDPOINT is not set
+# CONFIG_LINKSTATION is not set
CONFIG_MPC7448HPC2=y
# CONFIG_RADSTONE_PPC7D is not set
# CONFIG_PAL4 is not set
@@ -152,7 +162,6 @@ CONFIG_MPC7448HPC2=y
# CONFIG_TQM8260 is not set
# CONFIG_ADS8272 is not set
# CONFIG_PQ2FADS is not set
-# CONFIG_LITE5200 is not set
# CONFIG_EV64360 is not set
CONFIG_TSI108_BRIDGE=y
# CONFIG_WANT_EARLY_SERIAL is not set
@@ -164,6 +173,7 @@ CONFIG_MPIC=y
# CONFIG_HIGHMEM is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -173,6 +183,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -237,6 +248,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -258,10 +270,13 @@ CONFIG_SYN_COOKIES=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_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -291,7 +306,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
@@ -362,6 +376,12 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -371,6 +391,8 @@ CONFIG_BLK_DEV_INITRD=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -389,14 +411,16 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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
@@ -409,27 +433,13 @@ 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_ATA=y
-# CONFIG_SATA_AHCI is not set
-# CONFIG_SATA_SVW is not set
-# CONFIG_SCSI_ATA_PIIX 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_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
@@ -438,15 +448,73 @@ CONFIG_SATA_MV=y
# 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
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP 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=y
+# 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_MARVELL 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
+# CONFIG_PATA_PLATFORM is not set
#
# Multi-device support (RAID and LVM)
@@ -474,6 +542,7 @@ CONFIG_SATA_MV=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -505,6 +574,7 @@ CONFIG_PHYLIB=y
# CONFIG_CICADA_PHY is not set
# CONFIG_VITESSE_PHY is not set
# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
# CONFIG_FIXED_PHY is not set
#
@@ -563,6 +633,8 @@ CONFIG_8139TOO=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+CONFIG_TSI108_ETH=y
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -571,6 +643,7 @@ CONFIG_8139TOO=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -610,6 +683,7 @@ CONFIG_8139TOO=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -654,6 +728,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
@@ -677,10 +752,6 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -689,7 +760,6 @@ CONFIG_GEN_RTC=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -705,6 +775,7 @@ CONFIG_GEN_RTC=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -713,17 +784,14 @@ CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 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
@@ -735,6 +803,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -743,6 +812,11 @@ CONFIG_FIRMWARE_EDID=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -805,6 +879,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -814,6 +892,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
@@ -821,6 +900,7 @@ CONFIG_FS_MBCACHE=y
# 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
@@ -850,8 +930,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_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -921,13 +1003,20 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -938,12 +1027,14 @@ CONFIG_PLIST=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_DEBUG_FS is not set
-# CONFIG_UNWIND_INFO is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_BOOTX_TEXT is not set
# CONFIG_PPC_EARLY_DEBUG is not set
@@ -957,7 +1048,3 @@ CONFIG_LOG_BUF_SHIFT=14
# Cryptographic options
#
# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
diff --git a/arch/powerpc/configs/mpc8272_ads_defconfig b/arch/powerpc/configs/mpc8272_ads_defconfig
new file mode 100644
index 00000000000..2af45025082
--- /dev/null
+++ b/arch/powerpc/configs/mpc8272_ads_defconfig
@@ -0,0 +1,848 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17-rc5
+# Fri Jul 14 20:36:35 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_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 is not set
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+CONFIG_PPC_82xx=y
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx 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_PPC_FPU=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+
+#
+# Code maturity level options
+#
+# CONFIG_EXPERIMENTAL is not set
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="powerpc8272"
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=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_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+# 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"
+CONFIG_PQ2ADS=y
+CONFIG_8260=y
+CONFIG_8272=y
+CONFIG_CPM2=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_EMBEDDEDBOOT=y
+
+#
+# Platform support
+#
+CONFIG_ADS8272=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_PC_KEYBOARD is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_PPC_I8259 is not set
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP 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_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_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_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+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_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL 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 is not set
+# CONFIG_IP_NF_QUEUE 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
+
+#
+# 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 is not set
+# CONFIG_DEBUG_DRIVER 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_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_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=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_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC 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
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI 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
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM 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=y
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+CONFIG_DAVICOM_PHY=y
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_FS_ENET=y
+# CONFIG_FS_ENET_HAS_SCC is not set
+CONFIG_FS_ENET_HAS_FCC=y
+
+#
+# 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=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_SLIP 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
+
+#
+# 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=y
+# 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_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
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+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_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 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+CONFIG_SERIAL_CPM_SCC4=y
+# CONFIG_SERIAL_CPM_SMC1 is not set
+# CONFIG_SERIAL_CPM_SMC2 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_NVRAM 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_AGP is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# 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 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_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=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED 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
+#
+
+#
+# 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=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# 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=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_HFSPLUS_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=y
+# 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_SMB_FS=y
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_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=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 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=y
+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=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
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ 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_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP 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_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=y
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+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
+#
diff --git a/arch/powerpc/configs/mpc832xemds_defconfig b/arch/powerpc/configs/mpc832xemds_defconfig
new file mode 100644
index 00000000000..e1b36de6b38
--- /dev/null
+++ b/arch/powerpc/configs/mpc832xemds_defconfig
@@ -0,0 +1,1083 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc5
+# Tue Jan 30 14:27:25 2007
+#
+# 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_ARCH_HAS_ILOG2_U32=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_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_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 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_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+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_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_SYSFS_DEPRECATED=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=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 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
+
+#
+# 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 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"
+CONFIG_QUICC_ENGINE=y
+CONFIG_PPC_GEN550=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+CONFIG_MPC832x_MDS=y
+# CONFIG_MPC834x_SYS is not set
+# CONFIG_MPC834x_ITX is not set
+# CONFIG_MPC8360E_PB is not set
+CONFIG_PPC_MPC832x=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_300 is not set
+# 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_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=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
+
+#
+# Bus options
+#
+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
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# 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 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_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"
+# CONFIG_TCP_MD5SIG 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 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_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 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=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=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
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+# 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 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 is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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_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_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
+# CONFIG_SCSI_SRP 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
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_WINDFARM 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_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 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
+# 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
+# CONFIG_NETXEN_NIC 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
+# 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 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=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
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+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_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_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
+# CONFIG_AGP is not set
+# 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_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_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
+
+#
+# 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_W1 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
+# 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_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 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
+# CONFIG_SENSORS_W83793 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# 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
+#
+
+#
+# Virtualization
+#
+
+#
+# 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_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_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
+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_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=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 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 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=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=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
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# QE Options
+#
+CONFIG_UCC_SLOW=y
+CONFIG_UCC_FAST=y
+CONFIG_UCC=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
+
+#
+# Instrumentation 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE 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
+#
+# 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_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC 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_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW 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
+#
diff --git a/arch/powerpc/configs/mpc834x_itx_defconfig b/arch/powerpc/configs/mpc834x_itx_defconfig
index 0561b73a918..7902806429f 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
-# Mon Sep 25 19:41:14 2006
+# Linux kernel version: 2.6.20-rc5
+# Fri Jan 26 00:19:02 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -22,13 +23,13 @@ CONFIG_PPC_OF=y
CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=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
@@ -40,6 +41,8 @@ CONFIG_PPC_83xx=y
CONFIG_6xx=y
CONFIG_83xx=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_SMP is not set
@@ -59,16 +62,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_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
@@ -98,6 +105,7 @@ CONFIG_MODULE_UNLOAD=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -120,8 +128,10 @@ CONFIG_PPC_GEN550=y
#
# Platform support
#
+# CONFIG_MPC832x_MDS is not set
# CONFIG_MPC834x_SYS is not set
CONFIG_MPC834x_ITX=y
+# CONFIG_MPC8360E_PB is not set
CONFIG_MPC834x=y
# CONFIG_MPIC is not set
@@ -131,6 +141,7 @@ CONFIG_MPC834x=y
# CONFIG_HIGHMEM is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -140,6 +151,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -206,6 +218,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
@@ -227,10 +240,13 @@ CONFIG_SYN_COOKIES=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_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -307,6 +323,7 @@ CONFIG_MTD=y
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
+# CONFIG_MTD_BLKDEVS is not set
# CONFIG_MTD_BLOCK is not set
# CONFIG_MTD_BLOCK_RO is not set
# CONFIG_FTL is not set
@@ -349,6 +366,7 @@ CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_PHYSMAP_START=0xfe000000
CONFIG_MTD_PHYSMAP_LEN=0x1000000
CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PHYSMAP_OF is not set
# CONFIG_MTD_PLATRAM is not set
#
@@ -373,6 +391,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# NAND Flash Device Drivers
#
# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_NAND_CAFE is not set
#
# OneNAND Flash Device Drivers
@@ -411,9 +430,16 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
# CONFIG_BLK_DEV_IDE is not set
# CONFIG_BLK_DEV_HD_ONLY is not set
# CONFIG_BLK_DEV_HD is not set
@@ -423,6 +449,8 @@ CONFIG_IDE=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -441,14 +469,16 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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
@@ -461,27 +491,13 @@ 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_MEGARAID_SAS 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_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_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
@@ -490,15 +506,73 @@ CONFIG_SATA_SIL=y
# 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
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP 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=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_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_MARVELL 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
+# CONFIG_PATA_PLATFORM is not set
#
# Multi-device support (RAID and LVM)
@@ -535,6 +609,7 @@ CONFIG_MD_RAID1=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -566,6 +641,7 @@ CONFIG_PHYLIB=y
CONFIG_CICADA_PHY=y
# CONFIG_VITESSE_PHY is not set
# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
# CONFIG_FIXED_PHY is not set
#
@@ -622,6 +698,7 @@ CONFIG_E100=y
# CONFIG_BNX2 is not set
CONFIG_GIANFAR=y
CONFIG_GFAR_NAPI=y
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -630,6 +707,7 @@ CONFIG_GFAR_NAPI=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -669,6 +747,7 @@ CONFIG_GFAR_NAPI=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -713,6 +792,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
@@ -753,10 +833,6 @@ CONFIG_HW_RANDOM=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -765,7 +841,6 @@ CONFIG_HW_RANDOM=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -842,6 +917,7 @@ CONFIG_SPI_MPC83xx=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -876,29 +952,27 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 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
+# CONFIG_SENSORS_W83793 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
#
-# Misc devices
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -911,6 +985,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -919,6 +994,11 @@ CONFIG_FIRMWARE_EDID=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -972,6 +1052,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
#
@@ -1010,6 +1091,7 @@ CONFIG_USB_STORAGE=y
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
CONFIG_USB_MON=y
@@ -1027,6 +1109,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
@@ -1034,12 +1117,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
#
@@ -1067,6 +1151,7 @@ CONFIG_USB_ETH_RNDIS=y
# CONFIG_USB_GADGETFS is not set
# CONFIG_USB_FILE_STORAGE is not set
# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
#
# MMC/SD Card support
@@ -1102,6 +1187,7 @@ CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
#
# RTC interfaces
@@ -1145,6 +1231,10 @@ CONFIG_NET_DMA=y
CONFIG_INTEL_IOATDMA=y
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1154,6 +1244,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
@@ -1161,6 +1252,7 @@ CONFIG_FS_MBCACHE=y
# 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
@@ -1190,8 +1282,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_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -1206,7 +1300,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
@@ -1249,6 +1342,10 @@ CONFIG_PARTITION_ADVANCED=y
# 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
@@ -1262,13 +1359,20 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -1279,8 +1383,11 @@ CONFIG_PLIST=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1294,9 +1401,10 @@ 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_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_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_DEBUGGER is not set
@@ -1316,8 +1424,10 @@ CONFIG_FORCED_INLINING=y
#
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
-# CONFIG_CRYPTO_MANAGER is not set
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
@@ -1326,8 +1436,10 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
# CONFIG_CRYPTO_ECB is not set
-# CONFIG_CRYPTO_CBC is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/powerpc/configs/mpc834x_mds_defconfig b/arch/powerpc/configs/mpc834x_mds_defconfig
index 9eefab96789..9eaed3a3698 100644
--- a/arch/powerpc/configs/mpc834x_mds_defconfig
+++ b/arch/powerpc/configs/mpc834x_mds_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:28:54 2006
+# Linux kernel version: 2.6.20-rc5
+# Fri Jan 26 00:19:27 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -21,13 +22,14 @@ 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_GENERIC_BUG=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
@@ -39,6 +41,8 @@ CONFIG_PPC_83xx=y
CONFIG_6xx=y
CONFIG_83xx=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_SMP is not set
@@ -58,28 +62,32 @@ 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 is not set
+CONFIG_SYSFS_DEPRECATED=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=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
@@ -97,6 +105,7 @@ CONFIG_MODULE_UNLOAD=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -119,8 +128,10 @@ CONFIG_PPC_GEN550=y
#
# Platform support
#
+# CONFIG_MPC832x_MDS is not set
CONFIG_MPC834x_SYS=y
# CONFIG_MPC834x_ITX is not set
+# CONFIG_MPC8360E_PB is not set
CONFIG_MPC834x=y
# CONFIG_MPIC is not set
@@ -130,6 +141,7 @@ CONFIG_MPC834x=y
# CONFIG_HIGHMEM is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -139,6 +151,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -204,6 +217,7 @@ CONFIG_PACKET=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
@@ -225,10 +239,13 @@ CONFIG_SYN_COOKIES=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_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -258,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
@@ -329,6 +345,12 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -338,6 +360,12 @@ CONFIG_BLK_DEV_INITRD=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)
@@ -362,6 +390,7 @@ CONFIG_BLK_DEV_INITRD=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -393,6 +422,7 @@ CONFIG_MARVELL_PHY=y
# CONFIG_CICADA_PHY is not set
# CONFIG_VITESSE_PHY is not set
# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
# CONFIG_FIXED_PHY is not set
#
@@ -449,6 +479,7 @@ CONFIG_E100=y
# CONFIG_BNX2 is not set
CONFIG_GIANFAR=y
# CONFIG_GFAR_NAPI is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -457,6 +488,7 @@ CONFIG_GIANFAR=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -495,6 +527,7 @@ CONFIG_GIANFAR=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -539,6 +572,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
@@ -575,10 +609,6 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -587,7 +617,6 @@ CONFIG_GEN_RTC=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -653,6 +682,7 @@ CONFIG_I2C_MPC=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -686,29 +716,27 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 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
+# CONFIG_SENSORS_W83793 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
#
-# Misc devices
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -720,6 +748,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -728,6 +757,11 @@ CONFIG_FIRMWARE_EDID=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -790,6 +824,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -799,6 +837,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
@@ -806,6 +845,7 @@ CONFIG_FS_MBCACHE=y
# 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
@@ -835,8 +875,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_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -905,13 +947,20 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -922,11 +971,14 @@ CONFIG_PLIST=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_BOOTX_TEXT is not set
# CONFIG_SERIAL_TEXT_DEBUG is not set
# CONFIG_PPC_EARLY_DEBUG is not set
@@ -941,7 +993,11 @@ 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_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
@@ -950,6 +1006,10 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/powerpc/configs/mpc8360emds_defconfig b/arch/powerpc/configs/mpc8360emds_defconfig
index c0703415d60..bbe38ccc3d8 100644
--- a/arch/powerpc/configs/mpc8360emds_defconfig
+++ b/arch/powerpc/configs/mpc8360emds_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18
-# Thu Sep 21 18:14:27 2006
+# Linux kernel version: 2.6.20-rc5
+# Fri Jan 26 00:19:45 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -22,13 +23,13 @@ CONFIG_PPC_OF=y
CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=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
@@ -40,6 +41,8 @@ CONFIG_PPC_83xx=y
CONFIG_6xx=y
CONFIG_83xx=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_SMP is not set
@@ -59,16 +62,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_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
# CONFIG_KALLSYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
@@ -98,6 +105,7 @@ CONFIG_MODULE_UNLOAD=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -121,6 +129,7 @@ CONFIG_PPC_GEN550=y
#
# Platform support
#
+# CONFIG_MPC832x_MDS is not set
# CONFIG_MPC834x_SYS is not set
# CONFIG_MPC834x_ITX is not set
CONFIG_MPC8360E_PB=y
@@ -133,6 +142,7 @@ CONFIG_PPC_MPC836x=y
# CONFIG_HIGHMEM is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -142,6 +152,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -207,6 +218,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
@@ -228,10 +240,13 @@ CONFIG_SYN_COOKIES=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_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -331,6 +346,12 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -340,6 +361,8 @@ CONFIG_BLK_DEV_INITRD=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -358,14 +381,16 @@ CONFIG_SCSI_PROC_FS=y
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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
@@ -378,11 +403,12 @@ CONFIG_SCSI_PROC_FS=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_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
@@ -392,15 +418,22 @@ CONFIG_SCSI_PROC_FS=y
# 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
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -428,6 +461,7 @@ CONFIG_SCSI_PROC_FS=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -488,6 +522,7 @@ CONFIG_UCC_GETH=y
# CONFIG_UGETH_MAGIC_PACKET is not set
# CONFIG_UGETH_FILTERING is not set
# CONFIG_UGETH_TX_ON_DEMOND is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -496,6 +531,7 @@ CONFIG_UCC_GETH=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -535,6 +571,7 @@ CONFIG_UCC_GETH=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -579,6 +616,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
@@ -615,10 +653,6 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -627,7 +661,6 @@ CONFIG_GEN_RTC=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -693,6 +726,7 @@ CONFIG_I2C_MPC=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -726,29 +760,27 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 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
+# CONFIG_SENSORS_W83793 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
#
-# Misc devices
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -760,6 +792,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -768,6 +801,11 @@ CONFIG_FIRMWARE_EDID=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -830,6 +868,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -839,6 +881,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
@@ -846,6 +889,7 @@ CONFIG_FS_MBCACHE=y
# 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
@@ -875,8 +919,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_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -945,20 +991,27 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# QE Options
#
-# CONFIG_UCC_SLOW is not set
+CONFIG_UCC_SLOW=y
CONFIG_UCC_FAST=y
CONFIG_UCC=y
#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -969,11 +1022,14 @@ CONFIG_PLIST=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_BOOTX_TEXT is not set
# CONFIG_SERIAL_TEXT_DEBUG is not set
# CONFIG_PPC_EARLY_DEBUG is not set
@@ -988,7 +1044,11 @@ 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_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
@@ -997,6 +1057,10 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/powerpc/configs/mpc8540_ads_defconfig b/arch/powerpc/configs/mpc8540_ads_defconfig
index 67e7d0b5793..17120c47230 100644
--- a/arch/powerpc/configs/mpc8540_ads_defconfig
+++ b/arch/powerpc/configs/mpc8540_ads_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:29:23 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:25:24 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -21,13 +22,14 @@ 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_GENERIC_BUG=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 is not set
CONFIG_PPC_85xx=y
@@ -38,6 +40,8 @@ CONFIG_PPC_85xx=y
# CONFIG_E200 is not set
CONFIG_85xx=y
CONFIG_E500=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
CONFIG_BOOKE=y
CONFIG_FSL_BOOKE=y
# CONFIG_PHYS_64BIT is not set
@@ -58,16 +62,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_TASKSTATS is not set
-CONFIG_SYSCTL=y
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=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=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -76,12 +84,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
@@ -94,6 +102,7 @@ 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
@@ -116,6 +125,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# Platform support
#
CONFIG_MPC8540_ADS=y
+# CONFIG_MPC8560_ADS is not set
# CONFIG_MPC85xx_CDS is not set
CONFIG_MPC8540=y
CONFIG_PPC_INDIRECT_PCI_BE=y
@@ -127,6 +137,7 @@ CONFIG_MPIC=y
# CONFIG_HIGHMEM is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -137,6 +148,7 @@ CONFIG_BINFMT_MISC=y
CONFIG_MATH_EMULATION=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -199,6 +211,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -220,10 +233,13 @@ CONFIG_SYN_COOKIES=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_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -253,7 +269,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
@@ -320,6 +335,11 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -329,6 +349,12 @@ CONFIG_BLK_DEV_INITRD=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)
@@ -351,6 +377,7 @@ CONFIG_BLK_DEV_INITRD=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -377,6 +404,7 @@ CONFIG_PHYLIB=y
# CONFIG_CICADA_PHY is not set
# CONFIG_VITESSE_PHY is not set
# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
# CONFIG_FIXED_PHY is not set
#
@@ -429,6 +457,7 @@ CONFIG_GFAR_NAPI=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -472,6 +501,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
@@ -493,17 +523,12 @@ CONFIG_GEN_RTC=y
# CONFIG_GEN_RTC_X 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
@@ -519,6 +544,7 @@ CONFIG_GEN_RTC=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -527,17 +553,14 @@ CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 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
@@ -549,6 +572,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -557,6 +581,11 @@ CONFIG_FIRMWARE_EDID=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
# CONFIG_USB_ARCH_HAS_HCD is not set
@@ -617,6 +646,10 @@ CONFIG_FIRMWARE_EDID=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -626,6 +659,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
@@ -633,6 +667,7 @@ CONFIG_FS_MBCACHE=y
# 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
@@ -662,8 +697,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_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -729,13 +766,20 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -746,8 +790,11 @@ CONFIG_PLIST=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -761,10 +808,10 @@ CONFIG_DEBUG_MUTEXES=y
# 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_UNWIND_INFO is not set
+# CONFIG_DEBUG_LIST is not set
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_DEBUGGER is not set
@@ -782,7 +829,3 @@ CONFIG_FORCED_INLINING=y
# Cryptographic options
#
# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
diff --git a/arch/powerpc/configs/mpc8560_ads_defconfig b/arch/powerpc/configs/mpc8560_ads_defconfig
index ddc2a7b07ba..ecaa267a853 100644
--- a/arch/powerpc/configs/mpc8560_ads_defconfig
+++ b/arch/powerpc/configs/mpc8560_ads_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc4
-# Fri Aug 11 16:45:05 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:25:53 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -21,13 +22,14 @@ 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_GENERIC_BUG=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 is not set
CONFIG_PPC_85xx=y
@@ -38,6 +40,8 @@ CONFIG_PPC_85xx=y
# CONFIG_E200 is not set
CONFIG_85xx=y
CONFIG_E500=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
CONFIG_BOOKE=y
CONFIG_FSL_BOOKE=y
# CONFIG_PHYS_64BIT is not set
@@ -58,16 +62,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_TASKSTATS is not set
-CONFIG_SYSCTL=y
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=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=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -76,12 +84,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
@@ -94,6 +102,7 @@ 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
@@ -110,7 +119,6 @@ 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
@@ -122,6 +130,7 @@ CONFIG_MPC8560_ADS=y
# CONFIG_MPC85xx_CDS is not set
CONFIG_MPC8560=y
CONFIG_PPC_INDIRECT_PCI_BE=y
+CONFIG_MPIC=y
#
# Kernel options
@@ -129,6 +138,7 @@ CONFIG_PPC_INDIRECT_PCI_BE=y
# CONFIG_HIGHMEM is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -140,6 +150,7 @@ CONFIG_BINFMT_MISC=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
# CONFIG_PC_KEYBOARD is not set
CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -152,13 +163,13 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# 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
#
+# CONFIG_MPIC_WEIRD is not set
# CONFIG_PPC_I8259 is not set
CONFIG_PPC_INDIRECT_PCI=y
CONFIG_FSL_SOC=y
@@ -205,6 +216,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
@@ -226,10 +238,13 @@ CONFIG_SYN_COOKIES=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_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -259,7 +274,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
@@ -331,6 +345,12 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -340,6 +360,12 @@ CONFIG_BLK_DEV_INITRD=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)
@@ -364,6 +390,7 @@ CONFIG_BLK_DEV_INITRD=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -395,6 +422,7 @@ CONFIG_DAVICOM_PHY=y
# CONFIG_CICADA_PHY is not set
# CONFIG_VITESSE_PHY is not set
# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
# CONFIG_FIXED_PHY is not set
#
@@ -437,6 +465,7 @@ CONFIG_E1000_NAPI=y
# CONFIG_BNX2 is not set
CONFIG_GIANFAR=y
CONFIG_GFAR_NAPI=y
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -445,6 +474,7 @@ CONFIG_GFAR_NAPI=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -483,6 +513,7 @@ CONFIG_GFAR_NAPI=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -522,6 +553,7 @@ CONFIG_INPUT=y
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_CPM=y
@@ -536,7 +568,6 @@ CONFIG_SERIAL_CPM_SCC2=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_BRIQ_PANEL is not set
#
# IPMI
@@ -554,10 +585,6 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -566,7 +593,6 @@ CONFIG_GEN_RTC=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -582,6 +608,7 @@ CONFIG_GEN_RTC=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -590,17 +617,14 @@ CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 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
@@ -612,6 +636,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -620,6 +645,11 @@ CONFIG_FIRMWARE_EDID=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -682,6 +712,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -691,6 +725,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
@@ -698,6 +733,7 @@ CONFIG_FS_MBCACHE=y
# 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
@@ -727,8 +763,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_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -794,13 +832,20 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -811,8 +856,11 @@ CONFIG_PLIST=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -826,10 +874,10 @@ CONFIG_DEBUG_MUTEXES=y
# 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_UNWIND_INFO is not set
+# CONFIG_DEBUG_LIST is not set
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_DEBUGGER is not set
@@ -848,7 +896,3 @@ CONFIG_FORCED_INLINING=y
# Cryptographic options
#
# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
diff --git a/arch/powerpc/configs/mpc85xx_cds_defconfig b/arch/powerpc/configs/mpc85xx_cds_defconfig
index 72edf9f6682..1f61bce33e3 100644
--- a/arch/powerpc/configs/mpc85xx_cds_defconfig
+++ b/arch/powerpc/configs/mpc85xx_cds_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:29:49 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:26:46 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -21,13 +22,14 @@ 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_GENERIC_BUG=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 is not set
CONFIG_PPC_85xx=y
@@ -38,6 +40,8 @@ CONFIG_PPC_85xx=y
# CONFIG_E200 is not set
CONFIG_85xx=y
CONFIG_E500=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
CONFIG_BOOKE=y
CONFIG_FSL_BOOKE=y
# CONFIG_PHYS_64BIT is not set
@@ -58,16 +62,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_TASKSTATS is not set
-CONFIG_SYSCTL=y
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=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=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -76,12 +84,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
@@ -94,6 +102,7 @@ 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
@@ -116,6 +125,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# Platform support
#
# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8560_ADS is not set
CONFIG_MPC85xx_CDS=y
CONFIG_MPC8540=y
CONFIG_PPC_INDIRECT_PCI_BE=y
@@ -127,6 +137,7 @@ CONFIG_MPIC=y
# CONFIG_HIGHMEM is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -137,6 +148,7 @@ CONFIG_BINFMT_MISC=y
CONFIG_MATH_EMULATION=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -202,6 +214,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -223,10 +236,13 @@ CONFIG_SYN_COOKIES=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_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -256,7 +272,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
@@ -328,9 +343,16 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
CONFIG_BLK_DEV_IDE=y
#
@@ -353,7 +375,6 @@ CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
# CONFIG_IDEDMA_PCI_AUTO is not set
@@ -367,6 +388,7 @@ CONFIG_BLK_DEV_IDEDMA_PCI=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
@@ -375,6 +397,7 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y
# 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_SL82C105 is not set
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
CONFIG_BLK_DEV_VIA82CXXX=y
@@ -389,6 +412,12 @@ CONFIG_BLK_DEV_IDEDMA=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)
@@ -413,6 +442,7 @@ CONFIG_BLK_DEV_IDEDMA=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -444,6 +474,7 @@ CONFIG_PHYLIB=y
# CONFIG_CICADA_PHY is not set
# CONFIG_VITESSE_PHY is not set
# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
# CONFIG_FIXED_PHY is not set
#
@@ -483,6 +514,7 @@ CONFIG_E1000_NAPI=y
# CONFIG_BNX2 is not set
CONFIG_GIANFAR=y
CONFIG_GFAR_NAPI=y
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -491,6 +523,7 @@ CONFIG_GFAR_NAPI=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -529,6 +562,7 @@ CONFIG_GFAR_NAPI=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -573,6 +607,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
@@ -596,10 +631,6 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -608,7 +639,6 @@ CONFIG_GEN_RTC=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -624,6 +654,7 @@ CONFIG_GEN_RTC=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -632,17 +663,14 @@ CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 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
@@ -654,6 +682,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -662,6 +691,11 @@ CONFIG_FIRMWARE_EDID=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -724,6 +758,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -733,6 +771,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
@@ -740,6 +779,7 @@ CONFIG_FS_MBCACHE=y
# 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
@@ -769,8 +809,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_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -836,13 +878,20 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -853,8 +902,11 @@ CONFIG_PLIST=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -868,10 +920,10 @@ CONFIG_DEBUG_MUTEXES=y
# 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_UNWIND_INFO is not set
+# CONFIG_DEBUG_LIST is not set
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_DEBUGGER is not set
@@ -889,7 +941,3 @@ CONFIG_FORCED_INLINING=y
# Cryptographic options
#
# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
diff --git a/arch/powerpc/configs/mpc8641_hpcn_defconfig b/arch/powerpc/configs/mpc8641_hpcn_defconfig
index 92a527fccf8..53fcd6932f5 100644
--- a/arch/powerpc/configs/mpc8641_hpcn_defconfig
+++ b/arch/powerpc/configs/mpc8641_hpcn_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:30:15 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:27:14 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -21,13 +22,14 @@ 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_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
# 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 is not set
@@ -38,6 +40,8 @@ CONFIG_PPC_86xx=y
# CONFIG_E200 is not set
CONFIG_6xx=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
@@ -62,15 +66,18 @@ CONFIG_LOCALVERSION=""
# 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
# CONFIG_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=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=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
@@ -79,15 +86,15 @@ CONFIG_PRINTK=y
CONFIG_BUG=y
# CONFIG_ELF_CORE is not set
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
-# CONFIG_SLAB is not set
+CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-CONFIG_SLOB=y
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -97,6 +104,7 @@ CONFIG_SLOB=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -129,6 +137,7 @@ CONFIG_MPC8641=y
CONFIG_HIGHMEM=y
# CONFIG_HZ_100 is not set
# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
CONFIG_HZ_1000=y
CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
@@ -140,6 +149,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
# CONFIG_IRQ_ALL_CPUS is not set
CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -206,6 +216,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
@@ -226,21 +237,29 @@ CONFIG_IP_PNP_RARP=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_TCP_MD5SIG is not set
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_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -267,7 +286,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
@@ -339,6 +357,12 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -348,6 +372,12 @@ CONFIG_BLK_DEV_INITRD=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)
@@ -372,6 +402,7 @@ CONFIG_BLK_DEV_INITRD=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -403,6 +434,7 @@ CONFIG_PHYLIB=y
# CONFIG_CICADA_PHY is not set
CONFIG_VITESSE_PHY=y
# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
# CONFIG_FIXED_PHY is not set
#
@@ -440,6 +472,7 @@ CONFIG_MII=y
# CONFIG_BNX2 is not set
CONFIG_GIANFAR=y
# CONFIG_GFAR_NAPI is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -448,6 +481,7 @@ CONFIG_GIANFAR=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -486,6 +520,7 @@ CONFIG_GIANFAR=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -542,6 +577,7 @@ CONFIG_SERIAL_8250_RSA=y
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
@@ -563,10 +599,6 @@ CONFIG_UNIX98_PTYS=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -575,7 +607,6 @@ CONFIG_UNIX98_PTYS=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -640,6 +671,7 @@ CONFIG_SENSORS_EEPROM=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -648,14 +680,9 @@ CONFIG_SENSORS_EEPROM=y
# CONFIG_HWMON_VID is not set
#
-# Misc devices
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -667,6 +694,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
#
# Console display driver support
@@ -682,6 +710,11 @@ CONFIG_DUMMY_CONSOLE=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -744,6 +777,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -753,6 +790,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
@@ -760,6 +798,7 @@ CONFIG_FS_MBCACHE=y
# 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
@@ -788,8 +827,10 @@ CONFIG_FS_MBCACHE=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
@@ -904,13 +945,20 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -921,12 +969,16 @@ CONFIG_PLIST=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_FS is not set
+# CONFIG_HEADERS_CHECK 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
@@ -936,10 +988,10 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_HIGHMEM 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_UNWIND_INFO is not set
+# CONFIG_DEBUG_LIST is not set
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_DEBUGGER is not set
@@ -957,7 +1009,3 @@ CONFIG_FORCED_INLINING=y
# Cryptographic options
#
# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
diff --git a/arch/powerpc/configs/mpc866_ads_defconfig b/arch/powerpc/configs/mpc866_ads_defconfig
new file mode 100644
index 00000000000..539d9e3d366
--- /dev/null
+++ b/arch/powerpc/configs/mpc866_ads_defconfig
@@ -0,0 +1,829 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-rc6
+# Fri Nov 24 21:13:55 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_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
+
+#
+# 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 is not set
+# CONFIG_PPC_86xx is not set
+CONFIG_PPC_8xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_8xx=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_NOT_COHERENT_CACHE=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 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 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
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# 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"
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_EMBEDDEDBOOT=y
+# CONFIG_MPIC is not set
+
+#
+# Platform support
+#
+CONFIG_CPM1=y
+# CONFIG_MPC8XXFADS is not set
+CONFIG_MPC86XADS=y
+# CONFIG_MPC885ADS is not set
+
+#
+# MPC8xx CPM Options
+#
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+CONFIG_8xx_CPU6=y
+CONFIG_NO_UCODE_PATCH=y
+# CONFIG_USB_SOF_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+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_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=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_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_QSPAN is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# 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 is not set
+# 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_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"
+# 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 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=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
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE 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
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM 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
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# 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=y
+CONFIG_FIXED_MII_10_FDX=y
+CONFIG_FIXED_MII_100_FDX=y
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_FEC_8XX is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_HAS_SCC=y
+CONFIG_FS_ENET_HAS_FEC=y
+
+#
+# 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=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_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_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_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_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# 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=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 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_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
+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_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_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=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=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 is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+
+#
+# Instrumentation 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_FS is not set
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
diff --git a/arch/powerpc/configs/mpc885_ads_defconfig b/arch/powerpc/configs/mpc885_ads_defconfig
new file mode 100644
index 00000000000..e2c17d8da4f
--- /dev/null
+++ b/arch/powerpc/configs/mpc885_ads_defconfig
@@ -0,0 +1,827 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-rc4
+# Fri Nov 10 21:30:40 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_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
+
+#
+# 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 is not set
+# CONFIG_PPC_86xx is not set
+CONFIG_PPC_8xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_8xx=y
+CONFIG_NOT_COHERENT_CACHE=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 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 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
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# 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"
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_EMBEDDEDBOOT=y
+# CONFIG_MPIC is not set
+
+#
+# Platform support
+#
+CONFIG_CPM1=y
+# CONFIG_MPC8XXFADS is not set
+# CONFIG_MPC86XADS is not set
+CONFIG_MPC885ADS=y
+
+#
+# MPC8xx CPM Options
+#
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+# CONFIG_8xx_CPU6 is not set
+CONFIG_NO_UCODE_PATCH=y
+# CONFIG_USB_SOF_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+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_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=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_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_QSPAN is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# 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 is not set
+# 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_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"
+# 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 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=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
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE 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
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM 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
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+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=y
+CONFIG_FIXED_MII_10_FDX=y
+# CONFIG_FIXED_MII_100_FDX is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_FEC_8XX is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_HAS_SCC=y
+CONFIG_FS_ENET_HAS_FEC=y
+
+#
+# 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=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_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_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_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_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# 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=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 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_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
+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_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_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=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=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 is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+
+#
+# Instrumentation 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_FS is not set
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
diff --git a/arch/powerpc/configs/pasemi_defconfig b/arch/powerpc/configs/pasemi_defconfig
new file mode 100644
index 00000000000..97a57e99666
--- /dev/null
+++ b/arch/powerpc/configs/pasemi_defconfig
@@ -0,0 +1,1722 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc6
+# Thu Feb 1 22:54:15 2007
+#
+CONFIG_PPC64=y
+CONFIG_64BIT=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=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=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+CONFIG_POWER4_ONLY=y
+CONFIG_POWER4=y
+CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+# CONFIG_PPC_OF_PLATFORM_PCI is not set
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+# CONFIG_VIRT_CPU_ACCOUNTING is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=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 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_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=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=y
+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 is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_STOP_MACHINE=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE 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"
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_APUS is not set
+CONFIG_PPC_PSERIES=y
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_MAPLE is not set
+CONFIG_PPC_PASEMI=y
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_IBM_CELL_BLADE is not set
+# CONFIG_PPC_PS3 is not set
+CONFIG_PPC_NATIVE=y
+# CONFIG_UDBG_RTAS_CONSOLE is not set
+CONFIG_XICS=y
+# CONFIG_U3_DART is not set
+CONFIG_PPC_RTAS=y
+CONFIG_RTAS_ERROR_LOGGING=y
+CONFIG_RTAS_PROC=y
+# CONFIG_RTAS_FLASH is not set
+# CONFIG_MMIO_NVRAM is not set
+CONFIG_IBMVIO=y
+# CONFIG_IBMEBUS is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+CONFIG_MPIC=y
+
+#
+# PA Semi PWRficient options
+#
+CONFIG_PPC_PASEMI_IOMMU=y
+
+#
+# Kernel options
+#
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_FORCE_MAX_ZONEORDER=13
+CONFIG_IOMMU_VMERGE=y
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+# CONFIG_PPC_SPLPAR is not set
+CONFIG_EEH=y
+# CONFIG_SCANLOG is not set
+# CONFIG_LPARCFG is not set
+# CONFIG_NUMA is not set
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=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=y
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_SCHED_SMT is not set
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+CONFIG_PPC_I8259=y
+# CONFIG_PPC_INDIRECT_PCI is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_DEBUG=y
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+# CONFIG_YENTA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_KERNEL_START=0xc000000000000000
+
+#
+# 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=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=y
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+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_TCP_MD5SIG 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 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_FW_LOADER=y
+# 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=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+# CONFIG_MTD_PARTITIONS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=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 is not set
+# CONFIG_MTD_JEDECPROBE 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_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_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+CONFIG_MTD_SLRAM=y
+CONFIG_MTD_PHRAM=y
+# 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
+# CONFIG_MTD_NAND_CAFE 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_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=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=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE 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=y
+# 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=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# 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
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# 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=y
+CONFIG_CHR_DEV_OSST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC 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=y
+CONFIG_SCSI_3W_9XXX=y
+# 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_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_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_IBMVSCSI 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
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_FDOMAIN 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=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+CONFIG_SATA_SVW=y
+# CONFIG_ATA_PIIX is not set
+CONFIG_SATA_MV=y
+# 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=y
+CONFIG_SATA_SIL24=y
+# 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=y
+# 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_MARVELL 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_PCMCIA 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 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=y
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+# CONFIG_IEEE1394_OUI_DB is not set
+# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
+# CONFIG_IEEE1394_EXPORT_FULL_API is not set
+
+#
+# Device Drivers
+#
+CONFIG_IEEE1394_PCILYNX=y
+CONFIG_IEEE1394_OHCI1394=y
+
+#
+# Protocol Drivers
+#
+# CONFIG_IEEE1394_VIDEO1394 is not set
+CONFIG_IEEE1394_SBP2=y
+# CONFIG_IEEE1394_ETH1394 is not set
+# CONFIG_IEEE1394_DV1394 is not set
+CONFIG_IEEE1394_RAWIO=y
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# 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_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_IBMVETH=y
+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=y
+# 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_VIA_RHINE 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_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=y
+# 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
+# CONFIG_NETXEN_NIC 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=y
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+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=y
+# CONFIG_MOUSE_PS2 is not set
+# 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
+
+#
+# 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=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+# CONFIG_SERIAL_8250_CS is not set
+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_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_ICOM is not set
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=4
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_CONSOLE=y
+CONFIG_HVC_RTAS=y
+# CONFIG_HVCS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AGP is not set
+# 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=y
+CONFIG_MAX_RAW_DEVS=256
+# CONFIG_HANGCHECK_TIMER 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=y
+CONFIG_I2C_ALGOPCF=y
+CONFIG_I2C_ALGOPCA=y
+
+#
+# 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
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+CONFIG_SENSORS_EEPROM=y
+# 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=y
+# 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_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=y
+# 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
+# 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=y
+# CONFIG_SENSORS_LM87 is not set
+CONFIG_SENSORS_LM90=y
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 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
+# CONFIG_SENSORS_W83793 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+CONFIG_FB_DDC=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_MACMODES=y
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_VGA16=y
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_NVIDIA=y
+CONFIG_FB_NVIDIA_I2C=y
+CONFIG_FB_RIVA=y
+CONFIG_FB_RIVA_I2C=y
+# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=y
+CONFIG_FB_MATROX_MAVEN=y
+CONFIG_FB_MATROX_MULTIHEAD=y
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG 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_TRIDENT is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_VGACON_SOFT_SCROLLBACK=y
+CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+CONFIG_SND_SEQUENCER=y
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_SEQUENCER_OSS=y
+# 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
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X 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_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X 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_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_RIPTIDE 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 is not set
+
+#
+# ALSA PowerMac devices
+#
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_USX2Y=y
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_PDAUDIOCF is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# 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=y
+CONFIG_USB_SL811_HCD=y
+# CONFIG_USB_SL811_CS 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=y
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV 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_MII 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_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR 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_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_X1205 is not set
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# 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 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=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
+# CONFIG_INOTIFY is not set
+# 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
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# 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 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=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+CONFIG_CONFIGFS_FS=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_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 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=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=y
+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=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 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 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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
+
+#
+# Instrumentation Support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+# CONFIG_KPROBES 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=17
+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=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUGGER=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+CONFIG_XMON_DISASSEMBLY=y
+# CONFIG_IRQSTACKS is not set
+CONFIG_BOOTX_TEXT=y
+# CONFIG_PPC_EARLY_DEBUG 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=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+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_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW 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
+#
diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig
index 765c8bb90dd..f611df480fd 100644
--- a/arch/powerpc/configs/pmac32_defconfig
+++ b/arch/powerpc/configs/pmac32_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:30:23 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:28:56 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -10,6 +10,7 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -21,13 +22,14 @@ 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_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
# Processor support
#
CONFIG_CLASSIC32=y
-# CONFIG_PPC_52xx is not set
# CONFIG_PPC_82xx is not set
# CONFIG_PPC_83xx is not set
# CONFIG_PPC_85xx is not set
@@ -38,6 +40,8 @@ CONFIG_CLASSIC32=y
# CONFIG_E200 is not set
CONFIG_6xx=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
@@ -58,17 +62,21 @@ 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_SYSCTL=y
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=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=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -77,12 +85,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
@@ -100,6 +108,7 @@ CONFIG_KMOD=y
#
# Block layer
#
+CONFIG_BLOCK=y
CONFIG_LBD=y
# CONFIG_BLK_DEV_IO_TRACE is not set
CONFIG_LSF=y
@@ -121,18 +130,22 @@ 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_CHRP is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_EFIKA is not set
+# CONFIG_PPC_LITE5200 is not set
CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
-# CONFIG_UDBG_RTAS_CONSOLE is not set
+CONFIG_PPC_NATIVE=y
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
CONFIG_PPC_MPC106=y
# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=y
# CONFIG_CPU_FREQ_DEBUG is not set
@@ -157,6 +170,7 @@ CONFIG_MPIC=y
# CONFIG_HIGHMEM is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -167,6 +181,7 @@ CONFIG_BINFMT_MISC=m
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
# CONFIG_KEXEC is not set
CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -181,6 +196,8 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_PM=y
# CONFIG_PM_LEGACY is not set
CONFIG_PM_DEBUG=y
+# CONFIG_DISABLE_CONSOLE_SUSPEND is not set
+CONFIG_PM_SYSFS_DEPRECATED=y
CONFIG_SOFTWARE_SUSPEND=y
CONFIG_PM_STD_PARTITION=""
CONFIG_SECCOMP=y
@@ -254,6 +271,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -272,10 +290,13 @@ CONFIG_INET_ESP=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=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_TCP_MD5SIG is not set
#
# IP: Virtual Server Configuration
@@ -292,14 +313,33 @@ CONFIG_NETFILTER=y
# Core Netfilter Configuration
#
# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NF_CONNTRACK_ENABLED=m
+CONFIG_NF_CONNTRACK_SUPPORT=y
+# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set
+CONFIG_NF_CONNTRACK=m
+# CONFIG_NF_CT_ACCT is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=m
+# CONFIG_NF_CONNTRACK_H323 is not set
+CONFIG_NF_CONNTRACK_IRC=m
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NETFILTER_XTABLES=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=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_NFLOG=m
CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
CONFIG_NETFILTER_XT_MATCH_COMMENT=m
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
@@ -312,61 +352,49 @@ 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_STATE is not set
# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
#
# IP: Netfilter Configuration
#
-CONFIG_IP_NF_CONNTRACK=m
-# 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=m
-CONFIG_IP_NF_NETBIOS_NS=m
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_AMANDA=m
-CONFIG_IP_NF_PPTP=m
-CONFIG_IP_NF_H323=m
-# CONFIG_IP_NF_SIP is not set
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
# CONFIG_IP_NF_QUEUE is not set
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_DSCP=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_NF_NAT=m
+CONFIG_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_NF_NAT_SNMP_BASIC is not set
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_SIP is not set
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_RAW=m
CONFIG_IP_NF_ARPTABLES=m
@@ -384,8 +412,11 @@ CONFIG_IP_DCCP_ACKVEC=y
# DCCP CCIDs Configuration (EXPERIMENTAL)
#
CONFIG_IP_DCCP_CCID2=m
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
CONFIG_IP_DCCP_CCID3=m
CONFIG_IP_DCCP_TFRC_LIB=m
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_CCID3_RTO=100
#
# DCCP Kernel Hacking
@@ -410,7 +441,6 @@ CONFIG_IP_DCCP_TFRC_LIB=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
@@ -567,6 +597,12 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
@@ -594,7 +630,6 @@ CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_SL82C105=y
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
@@ -609,6 +644,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
@@ -617,6 +653,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
CONFIG_BLK_DEV_PDC202XX_NEW=y
# CONFIG_BLK_DEV_SVWKS is not set
# CONFIG_BLK_DEV_SIIMAGE is not set
+CONFIG_BLK_DEV_SL82C105=y
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
@@ -634,6 +671,8 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
#
@@ -653,14 +692,16 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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_LIBSAS is not set
#
# SCSI low-level drivers
@@ -678,11 +719,12 @@ CONFIG_AIC7XXX_DEBUG_MASK=0
CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
CONFIG_SCSI_AIC7XXX_OLD=m
# 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_ATA is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
@@ -692,14 +734,15 @@ CONFIG_SCSI_AIC7XXX_OLD=m
# 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_MMIO=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
@@ -709,6 +752,7 @@ CONFIG_SCSI_MESH=y
CONFIG_SCSI_MESH_SYNC_RATE=5
CONFIG_SCSI_MESH_RESET_DELAY_MS=4000
CONFIG_SCSI_MAC53C94=y
+# CONFIG_SCSI_SRP is not set
#
# PCMCIA SCSI adapter support
@@ -720,6 +764,11 @@ CONFIG_SCSI_MAC53C94=y
# CONFIG_PCMCIA_SYM53C500 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
@@ -732,6 +781,7 @@ CONFIG_MD_RAID10=m
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
@@ -798,6 +848,7 @@ CONFIG_THERM_WINDTUNNEL=m
CONFIG_THERM_ADT746X=m
# CONFIG_WINDFARM is not set
# CONFIG_ANSLCD is not set
+CONFIG_PMAC_RACKMETER=m
#
# Network device support
@@ -838,6 +889,7 @@ CONFIG_SUNGEM=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
@@ -874,6 +926,7 @@ CONFIG_PCNET32=y
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
# CONFIG_MV643XX_ETH is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -882,6 +935,7 @@ CONFIG_PCNET32=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -957,6 +1011,7 @@ CONFIG_PPP_BSDCOMP=m
# CONFIG_PPP_MPPE is not set
# CONFIG_PPPOE is not set
# CONFIG_SLIP is not set
+CONFIG_SLHC=y
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
@@ -977,6 +1032,7 @@ CONFIG_PPP_BSDCOMP=m
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -999,6 +1055,7 @@ CONFIG_INPUT_KEYBOARD=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 is not set
# CONFIG_MOUSE_SERIAL is not set
@@ -1039,6 +1096,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=m
CONFIG_SERIAL_PMACZILOG=m
# CONFIG_SERIAL_JSM is not set
@@ -1062,13 +1120,7 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
CONFIG_AGP=m
-# CONFIG_AGP_SIS is not set
-# CONFIG_AGP_VIA is not set
CONFIG_AGP_UNINORTH=m
CONFIG_DRM=m
# CONFIG_DRM_TDFX is not set
@@ -1091,7 +1143,6 @@ CONFIG_DRM_RADEON=m
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -1167,14 +1218,9 @@ CONFIG_I2C_POWERMAC=y
# CONFIG_HWMON_VID is not set
#
-# Misc devices
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -1187,6 +1233,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
@@ -1235,6 +1282,7 @@ CONFIG_FB_3DFX=y
# CONFIG_FB_3DFX_ACCEL is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_IBM_GXT4500 is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -1393,6 +1441,11 @@ CONFIG_SND_USB_AUDIO=m
# CONFIG_SOUND_PRIME is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1408,6 +1461,7 @@ CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
CONFIG_USB_DYNAMIC_MINORS=y
# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -1448,13 +1502,13 @@ CONFIG_USB_STORAGE=m
# 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=y
-CONFIG_USB_HIDINPUT=y
CONFIG_USB_HIDINPUT_POWERBOOK=y
# CONFIG_HID_FF is not set
# CONFIG_USB_HIDDEV is not set
@@ -1484,12 +1538,14 @@ CONFIG_USB_APPLETOUCH=y
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET_MII=m
CONFIG_USB_USBNET=m
CONFIG_USB_NET_AX8817X=m
CONFIG_USB_NET_CDCETHER=m
# CONFIG_USB_NET_GL620A is not set
CONFIG_USB_NET_NET1080=m
# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
# CONFIG_USB_NET_RNDIS_HOST is not set
# CONFIG_USB_NET_CDC_SUBSET is not set
CONFIG_USB_NET_ZAURUS=m
@@ -1504,6 +1560,7 @@ CONFIG_USB_MON=y
#
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
@@ -1538,6 +1595,8 @@ 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_MOS7720 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
@@ -1548,6 +1607,7 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
# CONFIG_USB_SERIAL_XIRCOM is not set
# CONFIG_USB_SERIAL_OPTION is not set
# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
CONFIG_USB_EZUSB=y
#
@@ -1555,6 +1615,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
@@ -1562,12 +1623,13 @@ 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=m
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_TEST is not set
#
@@ -1630,6 +1692,10 @@ CONFIG_LEDS_TRIGGER_IDE_DISK=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1639,6 +1705,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
@@ -1646,6 +1713,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
@@ -1682,8 +1750,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_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -1802,8 +1872,14 @@ CONFIG_NLS_ISO8859_1=m
CONFIG_NLS_UTF8=m
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=y
CONFIG_CRC16=y
CONFIG_CRC32=y
@@ -1815,6 +1891,7 @@ CONFIG_TEXTSEARCH_KMP=m
CONFIG_TEXTSEARCH_BM=m
CONFIG_TEXTSEARCH_FSM=m
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -1826,8 +1903,11 @@ CONFIG_OPROFILE=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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1841,14 +1921,16 @@ 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_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_FORCED_INLINING is not set
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_DEBUGGER=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
+CONFIG_XMON_DISASSEMBLY=y
# CONFIG_BDI_SWITCH is not set
CONFIG_BOOTX_TEXT=y
# CONFIG_PPC_EARLY_DEBUG is not set
@@ -1863,7 +1945,12 @@ CONFIG_BOOTX_TEXT=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
@@ -1872,9 +1959,14 @@ CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_TGR192=m
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
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/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index 1c009651f92..debac66e825 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:45:11 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:28:58 2007
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -10,6 +10,8 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -22,6 +24,8 @@ 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_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
@@ -31,6 +35,10 @@ CONFIG_GENERIC_TBSYNC=y
CONFIG_POWER3=y
CONFIG_POWER4=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+CONFIG_PPC_DCR_MMIO=y
+CONFIG_PPC_DCR=y
+CONFIG_PPC_OF_PLATFORM_PCI=y
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_VIRT_CPU_ACCOUNTING=y
@@ -52,19 +60,24 @@ 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=y
CONFIG_TASK_DELAY_ACCT=y
-CONFIG_SYSCTL=y
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_CPUSETS=y
+CONFIG_SYSFS_DEPRECATED=y
CONFIG_RELAY=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_TASK_XACCT is not set
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -73,12 +86,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 +110,7 @@ CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
CONFIG_BLK_DEV_IO_TRACE=y
#
@@ -116,16 +130,20 @@ 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=y
+CONFIG_PPC_ISERIES=y
+# CONFIG_PPC_MPC52xx is not set
CONFIG_PPC_PMAC=y
CONFIG_PPC_PMAC64=y
CONFIG_PPC_MAPLE=y
+# CONFIG_PPC_PASEMI is not set
CONFIG_PPC_CELL=y
CONFIG_PPC_CELL_NATIVE=y
CONFIG_PPC_IBM_CELL_BLADE=y
+# CONFIG_PPC_PS3 is not set
+CONFIG_PPC_NATIVE=y
CONFIG_UDBG_RTAS_CONSOLE=y
CONFIG_XICS=y
CONFIG_U3_DART=y
@@ -139,6 +157,8 @@ CONFIG_IBMVIO=y
# CONFIG_IBMEBUS is not set
# CONFIG_PPC_MPC106 is not set
CONFIG_PPC_970_NAP=y
+CONFIG_PPC_INDIRECT_IO=y
+CONFIG_GENERIC_IOMAP=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=y
# CONFIG_CPU_FREQ_DEBUG is not set
@@ -160,14 +180,16 @@ CONFIG_MPIC=y
#
CONFIG_SPU_FS=m
CONFIG_SPU_BASE=y
-CONFIG_SPUFS_MMAP=y
CONFIG_CBE_RAS=y
+CONFIG_CBE_THERM=m
+CONFIG_CBE_CPUFREQ=m
#
# Kernel options
#
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -192,6 +214,7 @@ CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
# CONFIG_FLATMEM_MANUAL is not set
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -201,6 +224,7 @@ 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_RESOURCES_64BIT=y
CONFIG_ARCH_MEMORY_PROBE=y
@@ -254,6 +278,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_NET_KEY=m
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -272,10 +297,13 @@ 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=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_TCP_MD5SIG is not set
#
# IP: Virtual Server Configuration
@@ -294,25 +322,31 @@ CONFIG_NETFILTER=y
CONFIG_NETFILTER_NETLINK=y
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK_ENABLED=m
+CONFIG_NF_CONNTRACK_SUPPORT=y
+# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CT_ACCT=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_GRE=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
# 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=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 is not set
-# CONFIG_IP_NF_H323 is not set
-CONFIG_IP_NF_SIP=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
CONFIG_IP_NF_QUEUE=m
#
@@ -339,7 +373,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
@@ -412,6 +445,12 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
@@ -438,7 +477,6 @@ CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_SL82C105=y
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
@@ -453,6 +491,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
@@ -461,6 +500,7 @@ CONFIG_BLK_DEV_AMD74XX=y
# 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_SL82C105=y
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
@@ -478,6 +518,8 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
#
@@ -497,14 +539,16 @@ CONFIG_CHR_DEV_SG=y
CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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
@@ -517,26 +561,12 @@ CONFIG_SCSI_ISCSI_ATTRS=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_ATA=y
-# CONFIG_SATA_AHCI is not set
-CONFIG_SATA_SVW=y
-# CONFIG_SCSI_ATA_PIIX 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_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
@@ -546,6 +576,7 @@ CONFIG_SATA_SVW=y
CONFIG_SCSI_IBMVSCSI=y
# 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
@@ -556,10 +587,66 @@ CONFIG_SCSI_IPR_TRACE=y
CONFIG_SCSI_IPR_DUMP=y
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
CONFIG_SCSI_LPFC=m
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
CONFIG_SCSI_DEBUG=m
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_SATA_AHCI is not set
+CONFIG_SATA_SVW=y
+# 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_MARVELL 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)
@@ -575,6 +662,7 @@ CONFIG_MD_RAID5_RESHAPE=y
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
@@ -630,11 +718,13 @@ CONFIG_IEEE1394_RAWIO=y
CONFIG_ADB_PMU=y
# CONFIG_ADB_PMU_LED is not set
CONFIG_PMAC_SMU=y
+# CONFIG_MAC_EMUMOUSEBTN is not set
CONFIG_THERM_PM72=y
CONFIG_WINDFARM=y
CONFIG_WINDFARM_PM81=y
CONFIG_WINDFARM_PM91=y
CONFIG_WINDFARM_PM112=y
+# CONFIG_PMAC_RACKMETER is not set
#
# Network device support
@@ -675,6 +765,7 @@ CONFIG_VORTEX=y
CONFIG_IBMVETH=m
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
@@ -713,7 +804,7 @@ CONFIG_E1000=y
CONFIG_TIGON3=y
# CONFIG_BNX2 is not set
CONFIG_SPIDER_NET=m
-# CONFIG_MV643XX_ETH is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -723,6 +814,7 @@ CONFIG_IXGB=m
# CONFIG_IXGB_NAPI is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -741,6 +833,7 @@ CONFIG_IBMOL=y
# Wan interfaces
#
# CONFIG_WAN is not set
+CONFIG_ISERIES_VETH=m
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
CONFIG_PPP=m
@@ -753,6 +846,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
@@ -775,6 +869,7 @@ CONFIG_NET_POLL_CONTROLLER=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -797,6 +892,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
@@ -850,6 +946,7 @@ CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
CONFIG_HVC_DRIVER=y
CONFIG_HVC_CONSOLE=y
+CONFIG_HVC_ISERIES=y
CONFIG_HVC_RTAS=y
CONFIG_HVCS=m
@@ -868,10 +965,6 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
CONFIG_RAW_DRIVER=y
@@ -882,7 +975,6 @@ CONFIG_MAX_RAW_DEVS=256
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -947,6 +1039,7 @@ CONFIG_I2C_POWERMAC=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -955,14 +1048,9 @@ CONFIG_I2C_POWERMAC=y
# CONFIG_HWMON_VID is not set
#
-# Misc devices
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -975,6 +1063,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
CONFIG_FB=y
+CONFIG_FB_DDC=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
@@ -1011,6 +1100,7 @@ CONFIG_FB_RADEON_I2C=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_TRIDENT is not set
+CONFIG_FB_IBM_GXT4500=y
# CONFIG_FB_VIRTUAL is not set
#
@@ -1159,6 +1249,11 @@ CONFIG_SND_AOA_SOUNDBUS_I2S=m
# CONFIG_SOUND_PRIME is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1173,6 +1268,7 @@ CONFIG_USB=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -1214,13 +1310,13 @@ CONFIG_USB_STORAGE=m
# 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
@@ -1250,6 +1346,7 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
# CONFIG_USB_MON is not set
@@ -1267,6 +1364,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
@@ -1274,12 +1372,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=m
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_TEST is not set
#
@@ -1318,6 +1417,7 @@ CONFIG_INFINIBAND=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
@@ -1347,6 +1447,10 @@ CONFIG_INFINIBAND_ISER=m
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1359,6 +1463,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
@@ -1379,6 +1484,7 @@ CONFIG_XFS_FS=m
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 is not set
# CONFIG_ROMFS_FS is not set
@@ -1414,8 +1520,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
@@ -1540,8 +1648,23 @@ CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=m
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# iSeries device drivers
+#
+# CONFIG_VIOCONS is not set
+CONFIG_VIODASD=y
+CONFIG_VIOCD=m
+CONFIG_VIOTAPE=m
+CONFIG_VIOPATH=y
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=m
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -1551,6 +1674,7 @@ CONFIG_ZLIB_DEFLATE=m
CONFIG_TEXTSEARCH=y
CONFIG_TEXTSEARCH_KMP=m
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -1563,8 +1687,11 @@ CONFIG_OPROFILE=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_FS=y
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=17
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1578,16 +1705,19 @@ CONFIG_DEBUG_MUTEXES=y
# 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_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_DEBUG_STACKOVERFLOW=y
CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_HCALL_STATS is not set
CONFIG_DEBUGGER=y
CONFIG_XMON=y
# CONFIG_XMON_DEFAULT is not set
+CONFIG_XMON_DISASSEMBLY=y
CONFIG_IRQSTACKS=y
CONFIG_BOOTX_TEXT=y
# CONFIG_PPC_EARLY_DEBUG is not set
@@ -1602,7 +1732,12 @@ CONFIG_BOOTX_TEXT=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
@@ -1611,9 +1746,14 @@ CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_TGR192=m
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
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/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index f2d888e014a..ec644b34a08 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc6
-# Tue Nov 21 19:38:53 2006
+# Linux kernel version: 2.6.20-rc6
+# Thu Jan 25 13:35:34 2007
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -10,6 +10,8 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -23,6 +25,7 @@ CONFIG_PPC_OF=y
# CONFIG_PPC_UDBG_16550 is not set
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
@@ -64,12 +67,13 @@ CONFIG_SYSVIPC=y
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
# CONFIG_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=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_SYSCTL_SYSCALL is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
@@ -126,6 +130,7 @@ CONFIG_PPC_MULTIPLATFORM=y
# CONFIG_APUS is not set
# CONFIG_PPC_PSERIES is not set
# CONFIG_PPC_ISERIES is not set
+# CONFIG_PPC_MPC52xx is not set
# CONFIG_PPC_PMAC is not set
# CONFIG_PPC_MAPLE is not set
# CONFIG_PPC_PASEMI is not set
@@ -155,14 +160,16 @@ CONFIG_SPU_BASE=y
# PS3 Platform Options
#
CONFIG_PS3_HTAB_SIZE=20
-CONFIG_PS3_DYNAMIC_DMA=y
+# CONFIG_PS3_DYNAMIC_DMA is not set
CONFIG_PS3_USE_LPAR_ADDR=y
+CONFIG_PS3_VUART=y
#
# Kernel options
#
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -200,7 +207,7 @@ CONFIG_PPC_64K_PAGES=y
# CONFIG_SCHED_SMT is not set
CONFIG_PROC_DEVICETREE=y
CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="root=/dev/nfs rw ip=dhcp"
+CONFIG_CMDLINE="root=/dev/sda1 ip=dhcp"
# CONFIG_PM is not set
# CONFIG_SECCOMP is not set
CONFIG_ISA_DMA_API=y
@@ -233,7 +240,8 @@ 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_NET_KEY is not set
CONFIG_INET=y
@@ -260,6 +268,7 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -345,6 +354,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# 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_UB is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
@@ -365,16 +375,18 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
# SCSI support type (disk, tape, CD-ROM)
#
-# CONFIG_BLK_DEV_SD is not set
+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_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
@@ -384,6 +396,7 @@ CONFIG_SCSI_PROC_FS=y
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
#
# SCSI Transports
@@ -426,6 +439,7 @@ CONFIG_SCSI_PROC_FS=y
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -445,6 +459,7 @@ CONFIG_NETDEVICES=y
# Ethernet (10 or 100Mbit)
#
# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=y
#
# Ethernet (1000 Mbit)
@@ -493,10 +508,13 @@ CONFIG_INPUT=y
#
# Userland interfaces
#
-# CONFIG_INPUT_MOUSEDEV is not set
+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=y
+# CONFIG_INPUT_EVDEV is not set
# CONFIG_INPUT_EVBUG is not set
#
@@ -548,10 +566,6 @@ CONFIG_GEN_RTC=y
# CONFIG_GEN_RTC_X 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
# CONFIG_HANGCHECK_TIMER is not set
@@ -591,12 +605,14 @@ CONFIG_GEN_RTC=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_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
#
# Console display driver support
@@ -611,17 +627,149 @@ CONFIG_DUMMY_CONSOLE=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=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=y
+
+#
+# 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 is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# 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_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV 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_MII=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+CONFIG_USB_NET_MCS7830=y
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS 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_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+
+#
+# USB DSL modem support
+#
+
+#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
@@ -671,11 +819,21 @@ CONFIG_DUMMY_CONSOLE=y
#
#
+# Virtualization
+#
+
+#
# File systems
#
# CONFIG_EXT2_FS 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_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
@@ -695,14 +853,20 @@ CONFIG_DNOTIFY=y
#
# CD-ROM/DVD Filesystems
#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
#
# DOS/FAT/NT Filesystems
#
+CONFIG_FAT_FS=y
# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
# CONFIG_NTFS_FS is not set
#
@@ -768,16 +932,62 @@ CONFIG_MSDOS_PARTITION=y
#
# Native Language Support
#
-# CONFIG_NLS is not set
+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 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 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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
-# CONFIG_CRC32 is not set
+CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -792,27 +1002,29 @@ CONFIG_PLIST=y
CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=17
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_SLAB=y
+# CONFIG_DEBUG_SLAB_LEAK is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
CONFIG_DEBUG_SPINLOCK=y
-# CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_RWSEMS is not set
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_RWSEMS=y
CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_FS is not set
# CONFIG_DEBUG_VM is not set
CONFIG_DEBUG_LIST=y
CONFIG_FORCED_INLINING=y
-# CONFIG_HEADERS_CHECK is not set
# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_DEBUG_STACKOVERFLOW is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_STACK_USAGE is not set
# CONFIG_DEBUGGER is not set
CONFIG_IRQSTACKS=y
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index d2833c1a1f3..1c794fe718f 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:45:12 2006
+# Linux kernel version: 2.6.20-rc5
+# Mon Jan 22 22:31:27 2007
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -10,6 +10,8 @@ CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_IRQ_PER_CPU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -22,6 +24,8 @@ 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_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
#
@@ -31,6 +35,9 @@ CONFIG_PPC_UDBG_16550=y
CONFIG_POWER3=y
CONFIG_POWER4=y
CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+# CONFIG_PPC_OF_PLATFORM_PCI is not set
CONFIG_ALTIVEC=y
CONFIG_PPC_STD_MMU=y
CONFIG_VIRT_CPU_ACCOUNTING=y
@@ -52,19 +59,22 @@ 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
CONFIG_IKCONFIG_PROC=y
CONFIG_CPUSETS=y
+CONFIG_SYSFS_DEPRECATED=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=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -73,12 +83,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 +107,7 @@ CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
#
@@ -116,15 +127,19 @@ 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=y
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_PPC_MPC52xx is not set
# 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_PPC_IBM_CELL_BLADE is not set
+# CONFIG_PPC_PS3 is not set
+CONFIG_PPC_NATIVE=y
# CONFIG_UDBG_RTAS_CONSOLE is not set
CONFIG_XICS=y
# CONFIG_U3_DART is not set
@@ -137,6 +152,8 @@ CONFIG_IBMVIO=y
CONFIG_IBMEBUS=y
# CONFIG_PPC_MPC106 is not set
# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
# CONFIG_CPU_FREQ is not set
# CONFIG_WANT_EARLY_SERIAL is not set
CONFIG_MPIC=y
@@ -146,6 +163,7 @@ CONFIG_MPIC=y
#
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
@@ -170,6 +188,7 @@ CONFIG_NODES_SHIFT=4
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
# CONFIG_FLATMEM_MANUAL is not set
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -183,7 +202,6 @@ CONFIG_SPARSEMEM_EXTREME=y
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
@@ -235,6 +253,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_NET_KEY=m
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -253,10 +272,13 @@ 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=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_TCP_MD5SIG is not set
#
# IP: Virtual Server Configuration
@@ -275,25 +297,30 @@ CONFIG_NETFILTER=y
CONFIG_NETFILTER_NETLINK=y
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK_ENABLED=m
+CONFIG_NF_CONNTRACK_SUPPORT=y
+# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set
+CONFIG_NF_CONNTRACK=m
+# CONFIG_NF_CT_ACCT is not set
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=m
+# CONFIG_NF_CONNTRACK_H323 is not set
+CONFIG_NF_CONNTRACK_IRC=m
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
# 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=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 is not set
-# CONFIG_IP_NF_H323 is not set
-# CONFIG_IP_NF_SIP is not set
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
CONFIG_IP_NF_QUEUE=m
#
@@ -320,7 +347,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
@@ -402,6 +428,12 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
@@ -428,7 +460,6 @@ CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_SL82C105=y
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
@@ -443,6 +474,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
@@ -451,6 +483,7 @@ CONFIG_BLK_DEV_AMD74XX=y
# 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_SL82C105=y
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
@@ -465,6 +498,8 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
#
@@ -484,14 +519,16 @@ CONFIG_CHR_DEV_SG=y
CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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=m
+# CONFIG_SCSI_SAS_LIBSAS is not set
#
# SCSI low-level drivers
@@ -504,10 +541,11 @@ CONFIG_SCSI_SAS_ATTRS=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_ATA=y
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
@@ -520,6 +558,7 @@ CONFIG_SCSI_IBMVSCSI=y
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_IMM 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
@@ -530,10 +569,66 @@ CONFIG_SCSI_IPR_TRACE=y
CONFIG_SCSI_IPR_DUMP=y
# CONFIG_SCSI_QLOGIC_1280 is not set
CONFIG_SCSI_QLA_FC=m
+# CONFIG_SCSI_QLA_ISCSI is not set
CONFIG_SCSI_LPFC=m
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP 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_MARVELL 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)
@@ -548,6 +643,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
@@ -576,6 +672,7 @@ CONFIG_DM_MULTIPATH_EMC=m
#
# Macintosh device drivers
#
+# CONFIG_MAC_EMUMOUSEBTN is not set
# CONFIG_WINDFARM is not set
#
@@ -617,6 +714,7 @@ CONFIG_VORTEX=y
CONFIG_IBMVETH=y
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
@@ -655,17 +753,19 @@ 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)
#
# CONFIG_CHELSIO_T1 is not set
+CONFIG_EHEA=m
CONFIG_IXGB=m
# CONFIG_IXGB_NAPI is not set
CONFIG_S2IO=m
# CONFIG_S2IO_NAPI is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -697,6 +797,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
@@ -719,6 +820,7 @@ CONFIG_NET_POLL_CONTROLLER=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -741,6 +843,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
@@ -815,10 +918,6 @@ CONFIG_GEN_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
CONFIG_RAW_DRIVER=y
@@ -829,7 +928,6 @@ CONFIG_MAX_RAW_DEVS=1024
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -894,6 +992,7 @@ CONFIG_I2C_ALGOBIT=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -902,14 +1001,9 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_HWMON_VID is not set
#
-# Misc devices
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -922,6 +1016,7 @@ CONFIG_VIDEO_V4L2=y
#
CONFIG_FIRMWARE_EDID=y
CONFIG_FB=y
+CONFIG_FB_DDC=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
@@ -957,6 +1052,7 @@ CONFIG_FB_RADEON_I2C=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_TRIDENT is not set
+CONFIG_FB_IBM_GXT4500=y
# CONFIG_FB_VIRTUAL is not set
#
@@ -989,6 +1085,11 @@ CONFIG_LCD_DEVICE=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1003,6 +1104,7 @@ CONFIG_USB=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -1043,13 +1145,13 @@ 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
#
# 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
@@ -1079,6 +1181,7 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
CONFIG_USB_MON=y
@@ -1097,6 +1200,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
@@ -1104,12 +1208,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
#
@@ -1148,6 +1253,9 @@ CONFIG_INFINIBAND_USER_ACCESS=m
CONFIG_INFINIBAND_ADDR_TRANS=y
CONFIG_INFINIBAND_MTHCA=m
CONFIG_INFINIBAND_MTHCA_DEBUG=y
+CONFIG_INFINIBAND_EHCA=m
+CONFIG_INFINIBAND_EHCA_SCALING=y
+# CONFIG_INFINIBAND_AMSO1100 is not set
CONFIG_INFINIBAND_IPOIB=m
CONFIG_INFINIBAND_IPOIB_DEBUG=y
# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
@@ -1177,6 +1285,10 @@ CONFIG_INFINIBAND_SRP=m
#
#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1189,6 +1301,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
@@ -1209,6 +1322,7 @@ CONFIG_XFS_FS=m
CONFIG_XFS_SECURITY=y
CONFIG_XFS_POSIX_ACL=y
# CONFIG_XFS_RT is not set
+# CONFIG_GFS2_FS is not set
CONFIG_OCFS2_FS=m
CONFIG_OCFS2_DEBUG_MASKLOG=y
# CONFIG_MINIX_FS is not set
@@ -1246,8 +1360,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
@@ -1357,17 +1473,22 @@ CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=m
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=m
-CONFIG_TEXTSEARCH=y
-CONFIG_TEXTSEARCH_KMP=m
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
#
# Instrumentation Support
@@ -1380,8 +1501,11 @@ CONFIG_KPROBES=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_FS=y
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=17
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1395,16 +1519,20 @@ 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_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_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_LKDTM is not set
CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_HCALL_STATS=y
CONFIG_DEBUGGER=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
+CONFIG_XMON_DISASSEMBLY=y
CONFIG_IRQSTACKS=y
# CONFIG_BOOTX_TEXT is not set
# CONFIG_PPC_EARLY_DEBUG is not set
@@ -1419,7 +1547,12 @@ CONFIG_IRQSTACKS=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
@@ -1428,9 +1561,14 @@ CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_TGR192=m
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
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/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 4fe53d08ab8..8120d428ebf 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -17,6 +17,7 @@ obj-y += vdso32/
obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
signal_64.o ptrace32.o \
paca.o cpu_setup_ppc970.o \
+ cpu_setup_pa6t.o \
firmware.o sysfs.o nvram_64.o
obj-$(CONFIG_PPC64) += vdso64/
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
@@ -77,6 +78,7 @@ endif
ifeq ($(CONFIG_PPC_ISERIES),y)
extra-y += lparmap.s
+$(obj)/head_64.o: $(obj)/lparmap.s
AFLAGS_head_64.o += -I$(obj)
endif
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index e96521530d2..030d300cd71 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -303,5 +303,8 @@ int main(void)
DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
DEFINE(CLOCK_REALTIME_RES, TICK_NSEC);
+#ifdef CONFIG_BUG
+ DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry));
+#endif
return 0;
}
diff --git a/arch/powerpc/kernel/cpu_setup_pa6t.S b/arch/powerpc/kernel/cpu_setup_pa6t.S
new file mode 100644
index 00000000000..4047be25c4d
--- /dev/null
+++ b/arch/powerpc/kernel/cpu_setup_pa6t.S
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.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 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 <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/cache.h>
+
+/* Right now, restore and setup are the same thing */
+_GLOBAL(__restore_cpu_pa6t)
+_GLOBAL(__setup_cpu_pa6t)
+ /* Do nothing if not running in HV mode */
+ mfmsr r0
+ rldicl. r0,r0,4,63
+ beqlr
+
+ mfspr r0,SPRN_HID5
+ ori r0,r0,0x30
+ mtspr SPRN_HID5,r0
+
+ mfspr r0,SPRN_LPCR
+ ori r0,r0,0x7000
+ mtspr SPRN_LPCR,r0
+
+ blr
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 9d1614c3ce6..dd17dffbf05 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -43,6 +43,8 @@ extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec);
#ifdef CONFIG_PPC64
extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_ppc970MP(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_pa6t(unsigned long offset, struct cpu_spec* spec);
+extern void __restore_cpu_pa6t(unsigned long offset, struct cpu_spec* spec);
extern void __restore_cpu_ppc970(void);
#endif /* CONFIG_PPC64 */
@@ -86,6 +88,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power3",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "power3",
@@ -99,6 +102,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power3",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "power3",
@@ -112,6 +116,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "rs64",
@@ -125,6 +130,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "rs64",
@@ -138,6 +144,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "rs64",
@@ -151,6 +158,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
.platform = "rs64",
@@ -164,6 +172,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power4",
.oprofile_type = PPC_OPROFILE_POWER4,
.platform = "power4",
@@ -177,6 +186,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power4",
.oprofile_type = PPC_OPROFILE_POWER4,
.platform = "power4",
@@ -191,6 +201,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_ppc970,
.cpu_restore = __restore_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970",
@@ -207,6 +218,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_ppc970,
.cpu_restore = __restore_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970",
@@ -239,6 +251,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970",
.oprofile_type = PPC_OPROFILE_POWER4,
@@ -253,6 +266,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power5",
.oprofile_type = PPC_OPROFILE_POWER4,
/* SIHV / SIPR bits are implemented on POWER4+ (GQ)
@@ -271,6 +285,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power5+",
.oprofile_type = PPC_OPROFILE_POWER4,
.oprofile_mmcra_sihv = MMCRA_SIHV,
@@ -321,6 +336,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power6",
.oprofile_type = PPC_OPROFILE_POWER4,
.oprofile_mmcra_sihv = POWER6_MMCRA_SIHV,
@@ -340,6 +356,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/cell-be",
.oprofile_type = PPC_OPROFILE_CELL,
.platform = "ppc-cell-be",
@@ -353,6 +370,9 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 64,
.dcache_bsize = 64,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_PA6T,
+ .cpu_setup = __setup_cpu_pa6t,
+ .cpu_restore = __restore_cpu_pa6t,
.platform = "pa6t",
},
{ /* default match */
@@ -364,6 +384,7 @@ static struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_IBM,
.platform = "power4",
}
#endif /* CONFIG_PPC64 */
@@ -833,7 +854,7 @@ static struct cpu_spec cpu_specs[] = {
.pvr_mask = 0x7fff0000,
.pvr_value = 0x00840000,
.cpu_name = "e300c2",
- .cpu_features = CPU_FTRS_E300,
+ .cpu_features = CPU_FTRS_E300C2,
.cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
.icache_bsize = 32,
.dcache_bsize = 32,
@@ -1136,8 +1157,7 @@ static struct cpu_spec cpu_specs[] = {
.pvr_mask = 0xff000fff,
.pvr_value = 0x53000890,
.cpu_name = "440SPe Rev. A",
- .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
- CPU_FTR_USE_TB,
+ .cpu_features = CPU_FTRS_44X,
.cpu_user_features = COMMON_USER_BOOKE,
.icache_bsize = 32,
.dcache_bsize = 32,
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 1a3d4de197d..2b66d53dcc5 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -28,6 +28,7 @@
#include <asm/asm-offsets.h>
#include <asm/cputable.h>
#include <asm/firmware.h>
+#include <asm/bug.h>
/*
* System calls.
@@ -171,13 +172,18 @@ syscall_error_cont:
stdcx. r0,0,r1 /* to clear the reservation */
andi. r6,r8,MSR_PR
ld r4,_LINK(r1)
+ /*
+ * Clear RI before restoring r13. If we are returning to
+ * userspace and we take an exception after restoring r13,
+ * we end up corrupting the userspace r13 value.
+ */
+ li r12,MSR_RI
+ andc r11,r10,r12
+ mtmsrd r11,1 /* clear MSR.RI */
beq- 1f
ACCOUNT_CPU_USER_EXIT(r11, r12)
ld r13,GPR13(r1) /* only restore r13 if returning to usermode */
1: ld r2,GPR2(r1)
- li r12,MSR_RI
- andc r11,r10,r12
- mtmsrd r11,1 /* clear MSR.RI */
ld r1,GPR1(r1)
mtlr r4
mtcr r5
@@ -487,42 +493,44 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif
stb r5,PACASOFTIRQEN(r13)
+ /* extract EE bit and use it to restore paca->hard_enabled */
ld r3,_MSR(r1)
+ rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */
+ stb r4,PACAHARDIRQEN(r13)
+
+ ld r4,_CTR(r1)
+ ld r0,_LINK(r1)
+ mtctr r4
+ mtlr r0
+ ld r4,_XER(r1)
+ mtspr SPRN_XER,r4
+
+ REST_8GPRS(5, r1)
+
andi. r0,r3,MSR_RI
beq- unrecov_restore
- /* extract EE bit and use it to restore paca->hard_enabled */
- rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */
- stb r4,PACAHARDIRQEN(r13)
+ stdcx. r0,0,r1 /* to clear the reservation */
- andi. r0,r3,MSR_PR
+ /*
+ * Clear RI before restoring r13. If we are returning to
+ * userspace and we take an exception after restoring r13,
+ * we end up corrupting the userspace r13 value.
+ */
+ mfmsr r4
+ andc r4,r4,r0 /* r0 contains MSR_RI here */
+ mtmsrd r4,1
/*
* r13 is our per cpu area, only restore it if we are returning to
* userspace
*/
+ andi. r0,r3,MSR_PR
beq 1f
- ACCOUNT_CPU_USER_EXIT(r3, r4)
+ ACCOUNT_CPU_USER_EXIT(r2, r4)
REST_GPR(13, r1)
1:
- ld r3,_CTR(r1)
- ld r0,_LINK(r1)
- mtctr r3
- mtlr r0
- ld r3,_XER(r1)
- mtspr SPRN_XER,r3
-
- REST_8GPRS(5, r1)
-
- stdcx. r0,0,r1 /* to clear the reservation */
-
- mfmsr r0
- li r2, MSR_RI
- andc r0,r0,r2
- mtmsrd r0,1
-
- ld r0,_MSR(r1)
- mtspr SPRN_SRR1,r0
+ mtspr SPRN_SRR1,r3
ld r2,_CCR(r1)
mtcrf 0xFF,r2
@@ -634,19 +642,15 @@ _GLOBAL(enter_rtas)
li r0,0
mtcr r0
+#ifdef CONFIG_BUG
/* There is no way it is acceptable to get here with interrupts enabled,
* check it with the asm equivalent of WARN_ON
*/
lbz r0,PACASOFTIRQEN(r13)
1: tdnei r0,0
-.section __bug_table,"a"
- .llong 1b,__LINE__ + 0x1000000, 1f, 2f
-.previous
-.section .rodata,"a"
-1: .asciz __FILE__
-2: .asciz "enter_rtas"
-.previous
-
+ EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING
+#endif
+
/* Hard-disable interrupts */
mfmsr r6
rldicl r7,r6,48,1
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index d88e182e40b..c897203198b 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -344,12 +344,7 @@ i##n: \
/* System reset */
/* core99 pmac starts the seconary here by changing the vector, and
putting it back to what it was (unknown_exception) when done. */
-#if defined(CONFIG_GEMINI) && defined(CONFIG_SMP)
- . = 0x100
- b __secondary_start_gemini
-#else
EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)
-#endif
/* Machine check */
/*
@@ -437,6 +432,13 @@ Alignment:
/* Floating-point unavailable */
. = 0x800
FPUnavailable:
+BEGIN_FTR_SECTION
+/*
+ * Certain Freescale cores don't have a FPU and treat fp instructions
+ * as a FP Unavailable exception. Redirect to illegal/emulation handling.
+ */
+ b ProgramCheck
+END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)
EXCEPTION_PROLOG
bne load_up_fpu /* if from user, just load it up */
addi r3,r1,STACK_FRAME_OVERHEAD
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 71b1fe58e9e..97cedcd6c9b 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -613,7 +613,7 @@ system_call_pSeries:
/*** pSeries interrupt support ***/
/* moved from 0xf00 */
- MASKABLE_EXCEPTION_PSERIES(., performance_monitor)
+ STD_EXCEPTION_PSERIES(., performance_monitor)
/*
* An interrupt came in while soft-disabled; clear EE in SRR1,
diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c
index c6811337105..601ef79a591 100644
--- a/arch/powerpc/kernel/iomap.c
+++ b/arch/powerpc/kernel/iomap.c
@@ -12,23 +12,23 @@
* Here comes the ppc64 implementation of the IOMAP
* interfaces.
*/
-unsigned int fastcall ioread8(void __iomem *addr)
+unsigned int ioread8(void __iomem *addr)
{
return readb(addr);
}
-unsigned int fastcall ioread16(void __iomem *addr)
+unsigned int ioread16(void __iomem *addr)
{
return readw(addr);
}
-unsigned int fastcall ioread16be(void __iomem *addr)
+unsigned int ioread16be(void __iomem *addr)
{
return in_be16(addr);
}
-unsigned int fastcall ioread32(void __iomem *addr)
+unsigned int ioread32(void __iomem *addr)
{
return readl(addr);
}
-unsigned int fastcall ioread32be(void __iomem *addr)
+unsigned int ioread32be(void __iomem *addr)
{
return in_be32(addr);
}
@@ -38,23 +38,23 @@ EXPORT_SYMBOL(ioread16be);
EXPORT_SYMBOL(ioread32);
EXPORT_SYMBOL(ioread32be);
-void fastcall iowrite8(u8 val, void __iomem *addr)
+void iowrite8(u8 val, void __iomem *addr)
{
writeb(val, addr);
}
-void fastcall iowrite16(u16 val, void __iomem *addr)
+void iowrite16(u16 val, void __iomem *addr)
{
writew(val, addr);
}
-void fastcall iowrite16be(u16 val, void __iomem *addr)
+void iowrite16be(u16 val, void __iomem *addr)
{
out_be16(addr, val);
}
-void fastcall iowrite32(u32 val, void __iomem *addr)
+void iowrite32(u32 val, void __iomem *addr)
{
writel(val, addr);
}
-void fastcall iowrite32be(u32 val, void __iomem *addr)
+void iowrite32be(u32 val, void __iomem *addr)
{
out_be32(addr, val);
}
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 0bd8c766583..919fbf56849 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -281,10 +281,10 @@ void do_IRQ(struct pt_regs *regs)
/*
* Every platform is required to implement ppc_md.get_irq.
- * This function will either return an irq number or -1 to
+ * This function will either return an irq number or NO_IRQ to
* indicate there are no more pending.
- * The value -2 is for buggy hardware and means that this IRQ
- * has already been handled. -- Tom
+ * The value NO_IRQ_IGNORE is for buggy hardware and means that this
+ * IRQ has already been handled. -- Tom
*/
irq = ppc_md.get_irq();
@@ -604,6 +604,8 @@ unsigned int irq_create_mapping(struct irq_host *host,
*/
virq = irq_find_mapping(host, hwirq);
if (virq != IRQ_NONE) {
+ if (host->ops->remap)
+ host->ops->remap(host, virq, hwirq);
pr_debug("irq: -> existing mapping on virq %d\n", virq);
return virq;
}
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index 4657563f881..dd2886f97e9 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -46,8 +46,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
if ((unsigned long)p->addr & 0x03) {
printk("Attempt to register kprobe at an unaligned address\n");
ret = -EINVAL;
- } else if (IS_MTMSRD(insn) || IS_RFID(insn)) {
- printk("Cannot register a kprobe on rfid or mtmsrd\n");
+ } else if (IS_MTMSRD(insn) || IS_RFID(insn) || IS_RFI(insn)) {
+ printk("Cannot register a kprobe on rfi/rfid or mtmsr[d]\n");
ret = -EINVAL;
}
@@ -483,8 +483,12 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs));
/* setup return addr to the jprobe handler routine */
+#ifdef CONFIG_PPC64
regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry);
regs->gpr[2] = (unsigned long)(((func_descr_t *)jp->entry)->toc);
+#else
+ regs->nip = (unsigned long)jp->entry;
+#endif
return 1;
}
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 41c05dcd68f..0de5a08cf9b 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -439,6 +439,10 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf,
ssize_t retval = -ENOMEM;
+ if (!firmware_has_feature(FW_FEATURE_SPLPAR) ||
+ firmware_has_feature(FW_FEATURE_ISERIES))
+ return -EINVAL;
+
kbuf = kmalloc(count, GFP_KERNEL);
if (!kbuf)
goto out;
@@ -517,7 +521,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
static ssize_t lparcfg_write(struct file *file, const char __user * buf,
size_t count, loff_t * off)
{
- return count;
+ return -EINVAL;
}
#endif /* CONFIG_PPC_PSERIES */
@@ -570,6 +574,7 @@ static int lparcfg_open(struct inode *inode, struct file *file)
struct file_operations lparcfg_fops = {
.owner = THIS_MODULE,
.read = seq_read,
+ .write = lparcfg_write,
.open = lparcfg_open,
.release = single_release,
};
@@ -581,10 +586,8 @@ int __init lparcfg_init(void)
/* Allow writing if we have FW_FEATURE_SPLPAR */
if (firmware_has_feature(FW_FEATURE_SPLPAR) &&
- !firmware_has_feature(FW_FEATURE_ISERIES)) {
- lparcfg_fops.write = lparcfg_write;
+ !firmware_has_feature(FW_FEATURE_ISERIES))
mode |= S_IWUSR;
- }
ent = create_proc_entry("ppc64/lparcfg", mode, NULL);
if (ent) {
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 21fd2c662a9..519861da042 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -311,6 +311,46 @@ _GLOBAL(real_writeb)
blr
#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
+#ifdef CONFIG_PPC_PASEMI
+
+/* No support in all binutils for these yet, so use defines */
+#define LBZCIX(RT,RA,RB) .long (0x7c0006aa|(RT<<21)|(RA<<16)|(RB << 11))
+#define STBCIX(RS,RA,RB) .long (0x7c0007aa|(RS<<21)|(RA<<16)|(RB << 11))
+
+
+_GLOBAL(real_205_readb)
+ mfmsr r7
+ ori r0,r7,MSR_DR
+ xori r0,r0,MSR_DR
+ sync
+ mtmsrd r0
+ sync
+ isync
+ LBZCIX(r3,0,r3)
+ isync
+ mtmsrd r7
+ sync
+ isync
+ blr
+
+_GLOBAL(real_205_writeb)
+ mfmsr r7
+ ori r0,r7,MSR_DR
+ xori r0,r0,MSR_DR
+ sync
+ mtmsrd r0
+ sync
+ isync
+ STBCIX(r3,0,r4)
+ isync
+ mtmsrd r7
+ sync
+ isync
+ blr
+
+#endif /* CONFIG_PPC_PASEMI */
+
+
#ifdef CONFIG_CPU_FREQ_PMAC64
/*
* SCOM access functions for 970 (FX only for now)
diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c
index e2c3c6a85f3..07a89a39863 100644
--- a/arch/powerpc/kernel/module_32.c
+++ b/arch/powerpc/kernel/module_32.c
@@ -23,6 +23,7 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/cache.h>
+#include <linux/bug.h>
#include "setup.h"
@@ -223,7 +224,12 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
/* Low half of the symbol */
*(uint16_t *)location = value;
break;
-
+
+ case R_PPC_ADDR16_HI:
+ /* Higher half of the symbol */
+ *(uint16_t *)location = (value >> 16);
+ break;
+
case R_PPC_ADDR16_HA:
/* Sign-adjusted lower 16 bits: PPC ELF ABI says:
(((x >> 16) + ((x & 0x8000) ? 1 : 0))) & 0xFFFF.
@@ -290,23 +296,11 @@ int module_finalize(const Elf_Ehdr *hdr,
struct module *me)
{
const Elf_Shdr *sect;
+ int err;
- me->arch.bug_table = NULL;
- me->arch.num_bugs = 0;
-
- /* Find the __bug_table section, if present */
- sect = find_section(hdr, sechdrs, "__bug_table");
- if (sect != NULL) {
- me->arch.bug_table = (void *) sect->sh_addr;
- me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
- }
-
- /*
- * Strictly speaking this should have a spinlock to protect against
- * traversals, but since we only traverse on BUG()s, a spinlock
- * could potentially lead to deadlock and thus be counter-productive.
- */
- list_add(&me->arch.bug_list, &module_bug_list);
+ err = module_bug_finalize(hdr, sechdrs, me);
+ if (err) /* never true, currently */
+ return err;
/* Apply feature fixups */
sect = find_section(hdr, sechdrs, "__ftr_fixup");
@@ -320,7 +314,7 @@ int module_finalize(const Elf_Ehdr *hdr,
void module_arch_cleanup(struct module *mod)
{
- list_del(&mod->arch.bug_list);
+ module_bug_cleanup(mod);
}
struct bug_entry *module_find_bug(unsigned long bugaddr)
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
index 8dd1f0aae5d..75c7c4f1928 100644
--- a/arch/powerpc/kernel/module_64.c
+++ b/arch/powerpc/kernel/module_64.c
@@ -20,6 +20,7 @@
#include <linux/moduleloader.h>
#include <linux/err.h>
#include <linux/vmalloc.h>
+#include <linux/bug.h>
#include <asm/module.h>
#include <asm/uaccess.h>
#include <asm/firmware.h>
@@ -439,23 +440,11 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs, struct module *me)
{
const Elf_Shdr *sect;
+ int err;
- me->arch.bug_table = NULL;
- me->arch.num_bugs = 0;
-
- /* Find the __bug_table section, if present */
- sect = find_section(hdr, sechdrs, "__bug_table");
- if (sect != NULL) {
- me->arch.bug_table = (void *) sect->sh_addr;
- me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
- }
-
- /*
- * Strictly speaking this should have a spinlock to protect against
- * traversals, but since we only traverse on BUG()s, a spinlock
- * could potentially lead to deadlock and thus be counter-productive.
- */
- list_add(&me->arch.bug_list, &module_bug_list);
+ err = module_bug_finalize(hdr, sechdrs, me);
+ if (err)
+ return err;
/* Apply feature fixups */
sect = find_section(hdr, sechdrs, "__ftr_fixup");
@@ -475,7 +464,7 @@ int module_finalize(const Elf_Ehdr *hdr,
void module_arch_cleanup(struct module *mod)
{
- list_del(&mod->arch.bug_list);
+ module_bug_cleanup(mod);
}
struct bug_entry *module_find_bug(unsigned long bugaddr)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 6960f090991..869cebbba96 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -505,7 +505,7 @@ static int nvram_scan_partitions(void)
return -ENODEV;
total_size = ppc_md.nvram_size();
- header = (char *) kmalloc(NVRAM_HEADER_LEN, GFP_KERNEL);
+ header = kmalloc(NVRAM_HEADER_LEN, GFP_KERNEL);
if (!header) {
printk(KERN_ERR "nvram_scan_partitions: Failed kmalloc\n");
return -ENOMEM;
@@ -574,7 +574,7 @@ static int __init nvram_init(void)
}
/* initialize our anchor for the nvram partition list */
- nvram_part = (struct nvram_partition *) kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
+ nvram_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
if (!nvram_part) {
printk(KERN_ERR "nvram_init: Failed kmalloc\n");
return -ENOMEM;
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index 8a06724e029..e921514e655 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -109,9 +109,7 @@ int of_device_register(struct of_device *ofdev)
if (rc)
return rc;
- device_create_file(&ofdev->dev, &dev_attr_devspec);
-
- return 0;
+ return device_create_file(&ofdev->dev, &dev_attr_devspec);
}
void of_device_unregister(struct of_device *ofdev)
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index b3189d0161b..b7345176b39 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -50,6 +50,7 @@ static struct of_device_id of_default_bus_ids[] = {
{ .type = "plb5", },
{ .type = "plb4", },
{ .type = "opb", },
+ { .type = "ebc", },
{},
};
@@ -169,7 +170,7 @@ static void of_platform_make_bus_id(struct of_device *dev)
char *name = dev->dev.bus_id;
const u32 *reg;
u64 addr;
- long magic;
+ int magic;
/*
* If it's a DCR based device, use 'd' for native DCRs
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index 2f54cd81dea..d8ef2e10050 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -670,7 +670,7 @@ pcibios_make_OF_bus_map(void)
struct pci_controller* hose;
struct property *map_prop;
- pci_to_OF_bus_map = (u8*)kmalloc(pci_bus_count, GFP_KERNEL);
+ pci_to_OF_bus_map = kmalloc(pci_bus_count, GFP_KERNEL);
if (!pci_to_OF_bus_map) {
printk(KERN_ERR "Can't allocate OF bus map !\n");
return;
@@ -736,25 +736,46 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
return NULL;
}
-static int
-scan_OF_pci_childs_iterator(struct device_node* node, void* data)
+static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
+ unsigned int devfn)
{
- const unsigned int *reg;
- u8* fdata = (u8*)data;
-
- reg = get_property(node, "reg", NULL);
- if (reg && ((reg[0] >> 8) & 0xff) == fdata[1]
- && ((reg[0] >> 16) & 0xff) == fdata[0])
- return 1;
- return 0;
+ struct device_node *np = NULL;
+ const u32 *reg;
+ unsigned int psize;
+
+ while ((np = of_get_next_child(parent, np)) != NULL) {
+ reg = get_property(np, "reg", &psize);
+ if (reg == NULL || psize < 4)
+ continue;
+ if (((reg[0] >> 8) & 0xff) == devfn)
+ return np;
+ }
+ return NULL;
}
-static struct device_node*
-scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
+
+static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus)
{
- u8 filter_data[2] = {bus, dev_fn};
+ struct device_node *parent, *np;
+
+ /* Are we a root bus ? */
+ if (bus->self == NULL || bus->parent == NULL) {
+ struct pci_controller *hose = pci_bus_to_hose(bus->number);
+ if (hose == NULL)
+ return NULL;
+ return of_node_get(hose->arch_data);
+ }
- return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data);
+ /* not a root bus, we need to get our parent */
+ parent = scan_OF_for_pci_bus(bus->parent);
+ if (parent == NULL)
+ return NULL;
+
+ /* now iterate for children for a match */
+ np = scan_OF_for_pci_dev(parent, bus->self->devfn);
+ of_node_put(parent);
+
+ return np;
}
/*
@@ -763,43 +784,25 @@ scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
struct device_node *
pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
{
- struct pci_controller *hose;
- struct device_node *node;
- int busnr;
+ struct device_node *parent, *np;
if (!have_of)
return NULL;
-
- /* Lookup the hose */
- busnr = bus->number;
- hose = pci_bus_to_hose(busnr);
- if (!hose)
- return NULL;
- /* Check it has an OF node associated */
- node = (struct device_node *) hose->arch_data;
- if (!node)
+ DBG("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn);
+ parent = scan_OF_for_pci_bus(bus);
+ if (parent == NULL)
return NULL;
-
- /* Fixup bus number according to what OF think it is. */
-#ifdef CONFIG_PPC_PMAC
- /* The G5 need a special case here. Basically, we don't remap all
- * busses on it so we don't create the pci-OF-map. However, we do
- * remap the AGP bus and so have to deal with it. A future better
- * fix has to be done by making the remapping per-host and always
- * filling the pci_to_OF map. --BenH
+ DBG(" parent is %s\n", parent ? parent->full_name : "<NULL>");
+ np = scan_OF_for_pci_dev(parent, devfn);
+ of_node_put(parent);
+ DBG(" result is %s\n", np ? np->full_name : "<NULL>");
+
+ /* XXX most callers don't release the returned node
+ * mostly because ppc64 doesn't increase the refcount,
+ * we need to fix that.
*/
- if (machine_is(powermac) && busnr >= 0xf0)
- busnr -= 0xf0;
- else
-#endif
- if (pci_to_OF_bus_map)
- busnr = pci_to_OF_bus_map[busnr];
- if (busnr == 0xff)
- return NULL;
-
- /* Now, lookup childs of the hose */
- return scan_OF_childs_for_device(node->child, busnr, devfn);
+ return np;
}
EXPORT_SYMBOL(pci_busdev_to_OF_node);
@@ -1447,7 +1450,6 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
return -1;
}
pci_dev->irq = virq;
- pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq);
return 0;
}
@@ -1544,7 +1546,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
- unsigned long *offset,
+ resource_size_t *offset,
enum pci_mmap_state mmap_state)
{
struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
@@ -1556,7 +1558,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
/* If memory, add on the PCI bridge address offset */
if (mmap_state == pci_mmap_mem) {
+#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
*offset += hose->pci_mem_offset;
+#endif
res_bit = IORESOURCE_MEM;
} else {
io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE;
@@ -1624,9 +1628,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
else
prot |= _PAGE_GUARDED;
- printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev),
- (unsigned long long)rp->start, prot);
-
return __pgprot(prot);
}
@@ -1695,7 +1696,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state,
int write_combine)
{
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
struct resource *rp;
int ret;
@@ -1808,22 +1809,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
resource_size_t *start, resource_size_t *end)
{
struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
- unsigned long offset = 0;
+ resource_size_t offset = 0;
if (hose == NULL)
return;
if (rsrc->flags & IORESOURCE_IO)
- offset = (void __iomem *)_IO_BASE - hose->io_base_virt
- + hose->io_base_phys;
+ offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+
+ /* We pass a fully fixed up address to userland for MMIO instead of
+ * a BAR value because X is lame and expects to be able to use that
+ * to pass to /dev/mem !
+ *
+ * That means that we'll have potentially 64 bits values where some
+ * userland apps only expect 32 (like X itself since it thinks only
+ * Sparc has 64 bits MMIO) but if we don't do that, we break it on
+ * 32 bits CHRPs :-(
+ *
+ * Hopefully, the sysfs insterface is immune to that gunk. Once X
+ * has been fixed (and the fix spread enough), we can re-enable the
+ * 2 lines below and pass down a BAR value to userland. In that case
+ * we'll also have to re-enable the matching code in
+ * __pci_mmap_make_offset().
+ *
+ * BenH.
+ */
+#if 0
+ else if (rsrc->flags & IORESOURCE_MEM)
+ offset = hose->pci_mem_offset;
+#endif
- *start = rsrc->start + offset;
- *end = rsrc->end + offset;
+ *start = rsrc->start - offset;
+ *end = rsrc->end - offset;
}
-void __init
-pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
- int flags, char *name)
+void __init pci_init_resource(struct resource *res, resource_size_t start,
+ resource_size_t end, int flags, char *name)
{
res->start = start;
res->end = end;
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 6fa9a0a5c8d..7e97d71a5f8 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -360,6 +360,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
DBG(" class: 0x%x\n", dev->class);
dev->current_state = 4; /* unknown power state */
+ dev->error_state = pci_channel_io_normal;
if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
/* a PCI-PCI bridge */
@@ -380,8 +381,6 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
pci_device_add(dev, bus);
- /* XXX pci_scan_msi_device(dev); */
-
return dev;
}
EXPORT_SYMBOL(of_create_pci_dev);
@@ -682,7 +681,7 @@ int pci_proc_domain(struct pci_bus *bus)
* Returns negative error code on failure, zero on success.
*/
static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
- unsigned long *offset,
+ resource_size_t *offset,
enum pci_mmap_state mmap_state)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
@@ -694,7 +693,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
/* If memory, add on the PCI bridge address offset */
if (mmap_state == pci_mmap_mem) {
+#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
*offset += hose->pci_mem_offset;
+#endif
res_bit = IORESOURCE_MEM;
} else {
io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
@@ -762,9 +763,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
else
prot |= _PAGE_GUARDED;
- printk(KERN_DEBUG "PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
- prot);
-
return __pgprot(prot);
}
@@ -832,7 +830,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
struct resource *rp;
int ret;
@@ -1325,7 +1323,6 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
DBG(" -> mapped to linux irq %d\n", virq);
pci_dev->irq = virq;
- pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq);
return 0;
}
@@ -1333,20 +1330,41 @@ EXPORT_SYMBOL(pci_read_irq_line);
void pci_resource_to_user(const struct pci_dev *dev, int bar,
const struct resource *rsrc,
- u64 *start, u64 *end)
+ resource_size_t *start, resource_size_t *end)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
- unsigned long offset = 0;
+ resource_size_t offset = 0;
if (hose == NULL)
return;
if (rsrc->flags & IORESOURCE_IO)
- offset = pci_io_base - (unsigned long)hose->io_base_virt +
- hose->io_base_phys;
+ offset = (unsigned long)hose->io_base_virt - pci_io_base;
+
+ /* We pass a fully fixed up address to userland for MMIO instead of
+ * a BAR value because X is lame and expects to be able to use that
+ * to pass to /dev/mem !
+ *
+ * That means that we'll have potentially 64 bits values where some
+ * userland apps only expect 32 (like X itself since it thinks only
+ * Sparc has 64 bits MMIO) but if we don't do that, we break it on
+ * 32 bits CHRPs :-(
+ *
+ * Hopefully, the sysfs insterface is immune to that gunk. Once X
+ * has been fixed (and the fix spread enough), we can re-enable the
+ * 2 lines below and pass down a BAR value to userland. In that case
+ * we'll also have to re-enable the matching code in
+ * __pci_mmap_make_offset().
+ *
+ * BenH.
+ */
+#if 0
+ else if (rsrc->flags & IORESOURCE_MEM)
+ offset = hose->pci_mem_offset;
+#endif
- *start = rsrc->start + offset;
- *end = rsrc->end + offset;
+ *start = rsrc->start - offset;
+ *end = rsrc->end - offset;
}
struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
@@ -1409,7 +1427,7 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
for (ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {
bus = pci_bus_b(ln);
- if (in_bus >= bus->number && in_bus < (bus->number + bus->subordinate))
+ if (in_bus >= bus->number && in_bus <= bus->subordinate)
break;
bus = NULL;
}
diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c
index 3d8f6f44641..24d7b7c99bb 100644
--- a/arch/powerpc/kernel/pmc.c
+++ b/arch/powerpc/kernel/pmc.c
@@ -17,40 +17,25 @@
#include <linux/module.h>
#include <asm/processor.h>
+#include <asm/cputable.h>
#include <asm/pmc.h>
-#if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200)
-static void dummy_perf(struct pt_regs *regs)
-{
- unsigned int pmgc0 = mfpmr(PMRN_PMGC0);
-
- pmgc0 &= ~PMGC0_PMIE;
- mtpmr(PMRN_PMGC0, pmgc0);
-}
-#elif defined(CONFIG_PPC64) || defined(CONFIG_6xx)
-
-#ifndef MMCR0_PMAO
-#define MMCR0_PMAO 0
+#ifndef MMCR0_PMA0
+#define MMCR0_PMA0 0
#endif
-/* Ensure exceptions are disabled */
static void dummy_perf(struct pt_regs *regs)
{
- unsigned int mmcr0 = mfspr(SPRN_MMCR0);
-
- mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO);
- mtspr(SPRN_MMCR0, mmcr0);
-}
+#if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200)
+ mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE);
+#elif defined(CONFIG_PPC64) || defined(CONFIG_6xx)
+ if (cur_cpu_spec->pmc_type == PPC_PMC_IBM)
+ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~(MMCR0_PMXE|MMCR0_PMA0));
#else
-/* Ensure exceptions are disabled */
-static void dummy_perf(struct pt_regs *regs)
-{
- unsigned int mmcr0 = mfspr(SPRN_MMCR0);
-
- mmcr0 &= ~(MMCR0_PMXE);
- mtspr(SPRN_MMCR0, mmcr0);
-}
+ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMXE);
#endif
+}
+
static DEFINE_SPINLOCK(pmc_owner_lock);
static void *pmc_owner_caller; /* mostly for debugging */
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 9179f0739ea..ecee596d28f 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -44,6 +44,7 @@
#include <asm/btext.h>
#include <asm/div64.h>
#include <asm/signal.h>
+#include <asm/dcr.h>
#ifdef CONFIG_8xx
#include <asm/commproc.h>
@@ -208,7 +209,7 @@ EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */
extern long *intercept_table;
EXPORT_SYMBOL(intercept_table);
#endif /* CONFIG_PPC_STD_MMU_32 */
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_DCR_NATIVE
EXPORT_SYMBOL(__mtdcr);
EXPORT_SYMBOL(__mfdcr);
#endif
diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c
index f598cb51953..dd7001cacf7 100644
--- a/arch/powerpc/kernel/proc_ppc64.c
+++ b/arch/powerpc/kernel/proc_ppc64.c
@@ -83,7 +83,7 @@ __initcall(proc_ppc64_init);
static loff_t page_map_seek( struct file *file, loff_t off, int whence)
{
loff_t new;
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
switch(whence) {
case 0:
@@ -106,13 +106,13 @@ static loff_t page_map_seek( struct file *file, loff_t off, int whence)
static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
return simple_read_from_buffer(buf, nbytes, ppos, dp->data, dp->size);
}
static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
if ((vma->vm_end - vma->vm_start) > dp->size)
return -EINVAL;
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index c18dbe77fdc..3be52d693ec 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -804,6 +804,56 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
return of_read_ulong(p, s);
}
+#ifdef CONFIG_PPC_PSERIES
+/*
+ * Interpret the ibm,dynamic-memory property in the
+ * /ibm,dynamic-reconfiguration-memory node.
+ * This contains a list of memory blocks along with NUMA affinity
+ * information.
+ */
+static int __init early_init_dt_scan_drconf_memory(unsigned long node)
+{
+ cell_t *dm, *ls;
+ unsigned long l, n;
+ unsigned long base, size, lmb_size, flags;
+
+ ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
+ if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
+ return 0;
+ lmb_size = dt_mem_next_cell(dt_root_size_cells, &ls);
+
+ dm = (cell_t *)of_get_flat_dt_prop(node, "ibm,dynamic-memory", &l);
+ if (dm == NULL || l < sizeof(cell_t))
+ return 0;
+
+ n = *dm++; /* number of entries */
+ if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
+ return 0;
+
+ for (; n != 0; --n) {
+ base = dt_mem_next_cell(dt_root_addr_cells, &dm);
+ flags = dm[3];
+ /* skip DRC index, pad, assoc. list index, flags */
+ dm += 4;
+ /* skip this block if the reserved bit is set in flags (0x80)
+ or if the block is not assigned to this partition (0x8) */
+ if ((flags & 0x80) || !(flags & 0x8))
+ continue;
+ size = lmb_size;
+ if (iommu_is_off) {
+ if (base >= 0x80000000ul)
+ continue;
+ if ((base + size) > 0x80000000ul)
+ size = 0x80000000ul - base;
+ }
+ lmb_add(base, size);
+ }
+ lmb_dump_all();
+ return 0;
+}
+#else
+#define early_init_dt_scan_drconf_memory(node) 0
+#endif /* CONFIG_PPC_PSERIES */
static int __init early_init_dt_scan_memory(unsigned long node,
const char *uname, int depth, void *data)
@@ -812,6 +862,11 @@ static int __init early_init_dt_scan_memory(unsigned long node,
cell_t *reg, *endp;
unsigned long l;
+ /* Look for the ibm,dynamic-reconfiguration-memory node */
+ if (depth == 1 &&
+ strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0)
+ return early_init_dt_scan_drconf_memory(node);
+
/* We are scanning "memory" nodes only */
if (type == NULL) {
/*
@@ -1166,8 +1221,7 @@ struct device_node *of_find_node_by_name(struct device_node *from,
if (np->name != NULL && strcasecmp(np->name, name) == 0
&& of_node_get(np))
break;
- if (from)
- of_node_put(from);
+ of_node_put(from);
read_unlock(&devtree_lock);
return np;
}
@@ -1195,8 +1249,7 @@ struct device_node *of_find_node_by_type(struct device_node *from,
if (np->type != 0 && strcasecmp(np->type, type) == 0
&& of_node_get(np))
break;
- if (from)
- of_node_put(from);
+ of_node_put(from);
read_unlock(&devtree_lock);
return np;
}
@@ -1230,8 +1283,7 @@ struct device_node *of_find_compatible_node(struct device_node *from,
if (device_is_compatible(np, compatible) && of_node_get(np))
break;
}
- if (from)
- of_node_put(from);
+ of_node_put(from);
read_unlock(&devtree_lock);
return np;
}
@@ -1274,8 +1326,7 @@ struct device_node *of_find_node_by_phandle(phandle handle)
for (np = allnodes; np != 0; np = np->allnext)
if (np->linux_phandle == handle)
break;
- if (np)
- of_node_get(np);
+ of_node_get(np);
read_unlock(&devtree_lock);
return np;
}
@@ -1298,8 +1349,7 @@ struct device_node *of_find_all_nodes(struct device_node *prev)
for (; np != 0; np = np->allnext)
if (of_node_get(np))
break;
- if (prev)
- of_node_put(prev);
+ of_node_put(prev);
read_unlock(&devtree_lock);
return np;
}
@@ -1344,8 +1394,7 @@ struct device_node *of_get_next_child(const struct device_node *node,
for (; next != 0; next = next->sibling)
if (of_node_get(next))
break;
- if (prev)
- of_node_put(prev);
+ of_node_put(prev);
read_unlock(&devtree_lock);
return next;
}
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 46cf32670dd..520ef42f642 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -679,7 +679,7 @@ static unsigned char ibm_architecture_vec[] = {
/* option vector 5: PAPR/OF options */
3 - 2, /* length */
0, /* don't ignore, don't halt */
- OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
+ OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY,
};
/* Old method - ELF header with PT_NOTE sections */
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index 0dfbe1cd28e..12c51e4ad2b 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -920,9 +920,20 @@ static int of_irq_map_oldworld(struct device_node *device, int index,
/*
* Old machines just have a list of interrupt numbers
- * and no interrupt-controller nodes.
+ * and no interrupt-controller nodes. We also have dodgy
+ * cases where the APPL,interrupts property is completely
+ * missing behind pci-pci bridges and we have to get it
+ * from the parent (the bridge itself, as apple just wired
+ * everything together on these)
*/
- ints = get_property(device, "AAPL,interrupts", &intlen);
+ while (device) {
+ ints = get_property(device, "AAPL,interrupts", &intlen);
+ if (ints != NULL)
+ break;
+ device = device->parent;
+ if (device && strcmp(device->type, "pci") != 0)
+ break;
+ }
if (ints == NULL)
return -EINVAL;
intlen /= sizeof(u32);
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 975102a020d..cc44c7b975a 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -532,16 +532,22 @@ void do_syscall_trace_enter(struct pt_regs *regs)
&& (current->ptrace & PT_PTRACED))
do_syscall_trace();
- if (unlikely(current->audit_context))
- audit_syscall_entry(
-#ifdef CONFIG_PPC32
- AUDIT_ARCH_PPC,
-#else
- test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64,
+ if (unlikely(current->audit_context)) {
+#ifdef CONFIG_PPC64
+ if (!test_thread_flag(TIF_32BIT))
+ audit_syscall_entry(AUDIT_ARCH_PPC64,
+ regs->gpr[0],
+ regs->gpr[3], regs->gpr[4],
+ regs->gpr[5], regs->gpr[6]);
+ else
#endif
- regs->gpr[0],
- regs->gpr[3], regs->gpr[4],
- regs->gpr[5], regs->gpr[6]);
+ audit_syscall_entry(AUDIT_ARCH_PPC,
+ regs->gpr[0],
+ regs->gpr[3] & 0xffffffff,
+ regs->gpr[4] & 0xffffffff,
+ regs->gpr[5] & 0xffffffff,
+ regs->gpr[6] & 0xffffffff);
+ }
}
void do_syscall_trace_leave(struct pt_regs *regs)
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 387ed0d9ad6..76b5d7ebdcc 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -303,6 +303,12 @@ int rtas_token(const char *service)
}
EXPORT_SYMBOL(rtas_token);
+int rtas_service_present(const char *service)
+{
+ return rtas_token(service) != RTAS_UNKNOWN_SERVICE;
+}
+EXPORT_SYMBOL(rtas_service_present);
+
#ifdef CONFIG_RTAS_ERROR_LOGGING
/*
* Return the firmware-specified size of the error log buffer
@@ -810,32 +816,6 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
return 0;
}
-#ifdef CONFIG_HOTPLUG_CPU
-/* This version can't take the spinlock, because it never returns */
-static struct rtas_args rtas_stop_self_args = {
- /* The token is initialized for real in setup_system() */
- .token = RTAS_UNKNOWN_SERVICE,
- .nargs = 0,
- .nret = 1,
- .rets = &rtas_stop_self_args.args[0],
-};
-
-void rtas_stop_self(void)
-{
- struct rtas_args *rtas_args = &rtas_stop_self_args;
-
- local_irq_disable();
-
- BUG_ON(rtas_args->token == RTAS_UNKNOWN_SERVICE);
-
- printk("cpu %u (hwid %u) Ready to die...\n",
- smp_processor_id(), hard_smp_processor_id());
- enter_rtas(__pa(rtas_args));
-
- panic("Alas, I survived.\n");
-}
-#endif
-
/*
* Call early during boot, before mem init or bootmem, to retrieve the RTAS
* informations from the device-tree and allocate the RMO buffer for userland
@@ -880,9 +860,6 @@ void __init rtas_initialize(void)
#endif
rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region);
-#ifdef CONFIG_HOTPLUG_CPU
- rtas_stop_self_args.token = rtas_token("stop-self");
-#endif /* CONFIG_HOTPLUG_CPU */
#ifdef CONFIG_RTAS_ERROR_LOGGING
rtas_last_error_token = rtas_token("rtas-last-error");
#endif
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c
index 7d0f13fecc0..0c4fcd34bfe 100644
--- a/arch/powerpc/kernel/rtas_flash.c
+++ b/arch/powerpc/kernel/rtas_flash.c
@@ -193,7 +193,7 @@ static void free_flash_list(struct flash_block_list *f)
static int rtas_flash_release(struct inode *inode, struct file *file)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_update_flash_t *uf;
uf = (struct rtas_update_flash_t *) dp->data;
@@ -255,7 +255,7 @@ static void get_flash_status_msg(int status, char *buf)
static ssize_t rtas_flash_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_update_flash_t *uf;
char msg[RTAS_MSG_MAXLEN];
int msglen;
@@ -299,7 +299,7 @@ void rtas_block_ctor(void *ptr, struct kmem_cache *cache, unsigned long flags)
static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,
size_t count, loff_t *off)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_update_flash_t *uf;
char *p;
int next_free;
@@ -391,7 +391,7 @@ static void manage_flash(struct rtas_manage_flash_t *args_buf)
static ssize_t manage_flash_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_manage_flash_t *args_buf;
char msg[RTAS_MSG_MAXLEN];
int msglen;
@@ -421,7 +421,7 @@ static ssize_t manage_flash_read(struct file *file, char __user *buf,
static ssize_t manage_flash_write(struct file *file, const char __user *buf,
size_t count, loff_t *off)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_manage_flash_t *args_buf;
const char reject_str[] = "0";
const char commit_str[] = "1";
@@ -492,7 +492,7 @@ static int get_validate_flash_msg(struct rtas_validate_flash_t *args_buf,
static ssize_t validate_flash_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_validate_flash_t *args_buf;
char msg[RTAS_MSG_MAXLEN];
int msglen;
@@ -520,7 +520,7 @@ static ssize_t validate_flash_read(struct file *file, char __user *buf,
static ssize_t validate_flash_write(struct file *file, const char __user *buf,
size_t count, loff_t *off)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_validate_flash_t *args_buf;
int rc;
@@ -569,7 +569,7 @@ done:
static int validate_flash_release(struct inode *inode, struct file *file)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_validate_flash_t *args_buf;
args_buf = (struct rtas_validate_flash_t *) dp->data;
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 61c65d19ef0..6a19fa40dce 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -65,6 +65,7 @@ int have_of = 1;
#ifdef CONFIG_VGA_CONSOLE
unsigned long vgacon_remap_base;
+EXPORT_SYMBOL(vgacon_remap_base);
#endif
/*
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index e4ebe1a6228..6b405a3f43f 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -835,11 +835,21 @@ long sys_swapcontext(struct ucontext __user *old_ctx,
return -EINVAL;
if (old_ctx != NULL) {
+ struct mcontext __user *mctx;
+
+ /*
+ * old_ctx might not be 16-byte aligned, in which
+ * case old_ctx->uc_mcontext won't be either.
+ * Because we have the old_ctx->uc_pad2 field
+ * before old_ctx->uc_mcontext, we need to round down
+ * from &old_ctx->uc_mcontext to a 16-byte boundary.
+ */
+ mctx = (struct mcontext __user *)
+ ((unsigned long) &old_ctx->uc_mcontext & ~0xfUL);
if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
- || save_user_regs(regs, &old_ctx->uc_mcontext, 0)
+ || save_user_regs(regs, mctx, 0)
|| put_sigset_t(&old_ctx->uc_sigmask, &current->blocked)
- || __put_user(to_user_ptr(&old_ctx->uc_mcontext),
- &old_ctx->uc_regs))
+ || __put_user(to_user_ptr(mctx), &old_ctx->uc_regs))
return -EFAULT;
}
if (new_ctx == NULL)
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 9b28c238b6c..0e8beca460a 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -468,7 +468,7 @@ static int __devinit cpu_enable(unsigned int cpu)
return -ENOSYS;
}
-int __devinit __cpu_up(unsigned int cpu)
+int __cpuinit __cpu_up(unsigned int cpu)
{
int c;
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 63ed265b7f0..d57818aea08 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -169,6 +169,11 @@ static ssize_t __attribute_used__ \
return count; \
}
+
+/* Let's define all possible registers, we'll only hook up the ones
+ * that are implemented on the current processor
+ */
+
SYSFS_PMCSETUP(mmcr0, SPRN_MMCR0);
SYSFS_PMCSETUP(mmcr1, SPRN_MMCR1);
SYSFS_PMCSETUP(mmcra, SPRN_MMCRA);
@@ -181,56 +186,98 @@ SYSFS_PMCSETUP(pmc6, SPRN_PMC6);
SYSFS_PMCSETUP(pmc7, SPRN_PMC7);
SYSFS_PMCSETUP(pmc8, SPRN_PMC8);
SYSFS_PMCSETUP(purr, SPRN_PURR);
+SYSFS_PMCSETUP(spurr, SPRN_SPURR);
+SYSFS_PMCSETUP(dscr, SPRN_DSCR);
+
+SYSFS_PMCSETUP(pa6t_pmc0, PA6T_SPRN_PMC0);
+SYSFS_PMCSETUP(pa6t_pmc1, PA6T_SPRN_PMC1);
+SYSFS_PMCSETUP(pa6t_pmc2, PA6T_SPRN_PMC2);
+SYSFS_PMCSETUP(pa6t_pmc3, PA6T_SPRN_PMC3);
+SYSFS_PMCSETUP(pa6t_pmc4, PA6T_SPRN_PMC4);
+SYSFS_PMCSETUP(pa6t_pmc5, PA6T_SPRN_PMC5);
+
-static SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0);
-static SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1);
static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
-static SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1);
-static SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2);
-static SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3);
-static SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4);
-static SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5);
-static SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6);
-static SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7);
-static SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8);
-static SYSDEV_ATTR(purr, 0600, show_purr, NULL);
+static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
+static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
+static SYSDEV_ATTR(purr, 0600, show_purr, store_purr);
+
+static struct sysdev_attribute ibm_common_attrs[] = {
+ _SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
+ _SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
+};
+
+static struct sysdev_attribute ibm_pmc_attrs[] = {
+ _SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1),
+ _SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2),
+ _SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3),
+ _SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4),
+ _SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5),
+ _SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6),
+ _SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7),
+ _SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8),
+};
+
+static struct sysdev_attribute pa6t_attrs[] = {
+ _SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
+ _SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
+ _SYSDEV_ATTR(pmc0, 0600, show_pa6t_pmc0, store_pa6t_pmc0),
+ _SYSDEV_ATTR(pmc1, 0600, show_pa6t_pmc1, store_pa6t_pmc1),
+ _SYSDEV_ATTR(pmc2, 0600, show_pa6t_pmc2, store_pa6t_pmc2),
+ _SYSDEV_ATTR(pmc3, 0600, show_pa6t_pmc3, store_pa6t_pmc3),
+ _SYSDEV_ATTR(pmc4, 0600, show_pa6t_pmc4, store_pa6t_pmc4),
+ _SYSDEV_ATTR(pmc5, 0600, show_pa6t_pmc5, store_pa6t_pmc5),
+};
+
static void register_cpu_online(unsigned int cpu)
{
struct cpu *c = &per_cpu(cpu_devices, cpu);
struct sys_device *s = &c->sysdev;
+ struct sysdev_attribute *attrs, *pmc_attrs;
+ int i, nattrs;
if (!firmware_has_feature(FW_FEATURE_ISERIES) &&
cpu_has_feature(CPU_FTR_SMT))
sysdev_create_file(s, &attr_smt_snooze_delay);
/* PMC stuff */
+ switch (cur_cpu_spec->pmc_type) {
+ case PPC_PMC_IBM:
+ attrs = ibm_common_attrs;
+ nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute);
+ pmc_attrs = ibm_pmc_attrs;
+ break;
+ case PPC_PMC_PA6T:
+ /* PA Semi starts counting at PMC0 */
+ attrs = pa6t_attrs;
+ nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute);
+ pmc_attrs = NULL;
+ break;
+ default:
+ attrs = NULL;
+ nattrs = 0;
+ pmc_attrs = NULL;
+ }
- sysdev_create_file(s, &attr_mmcr0);
- sysdev_create_file(s, &attr_mmcr1);
+ for (i = 0; i < nattrs; i++)
+ sysdev_create_file(s, &attrs[i]);
+
+ if (pmc_attrs)
+ for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
+ sysdev_create_file(s, &pmc_attrs[i]);
if (cpu_has_feature(CPU_FTR_MMCRA))
sysdev_create_file(s, &attr_mmcra);
- if (cur_cpu_spec->num_pmcs >= 1)
- sysdev_create_file(s, &attr_pmc1);
- if (cur_cpu_spec->num_pmcs >= 2)
- sysdev_create_file(s, &attr_pmc2);
- if (cur_cpu_spec->num_pmcs >= 3)
- sysdev_create_file(s, &attr_pmc3);
- if (cur_cpu_spec->num_pmcs >= 4)
- sysdev_create_file(s, &attr_pmc4);
- if (cur_cpu_spec->num_pmcs >= 5)
- sysdev_create_file(s, &attr_pmc5);
- if (cur_cpu_spec->num_pmcs >= 6)
- sysdev_create_file(s, &attr_pmc6);
- if (cur_cpu_spec->num_pmcs >= 7)
- sysdev_create_file(s, &attr_pmc7);
- if (cur_cpu_spec->num_pmcs >= 8)
- sysdev_create_file(s, &attr_pmc8);
-
if (cpu_has_feature(CPU_FTR_PURR))
sysdev_create_file(s, &attr_purr);
+
+ if (cpu_has_feature(CPU_FTR_SPURR))
+ sysdev_create_file(s, &attr_spurr);
+
+ if (cpu_has_feature(CPU_FTR_DSCR))
+ sysdev_create_file(s, &attr_dscr);
}
#ifdef CONFIG_HOTPLUG_CPU
@@ -238,6 +285,8 @@ static void unregister_cpu_online(unsigned int cpu)
{
struct cpu *c = &per_cpu(cpu_devices, cpu);
struct sys_device *s = &c->sysdev;
+ struct sysdev_attribute *attrs, *pmc_attrs;
+ int i, nattrs;
BUG_ON(!c->hotpluggable);
@@ -246,32 +295,42 @@ static void unregister_cpu_online(unsigned int cpu)
sysdev_remove_file(s, &attr_smt_snooze_delay);
/* PMC stuff */
+ switch (cur_cpu_spec->pmc_type) {
+ case PPC_PMC_IBM:
+ attrs = ibm_common_attrs;
+ nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute);
+ pmc_attrs = ibm_pmc_attrs;
+ break;
+ case PPC_PMC_PA6T:
+ /* PA Semi starts counting at PMC0 */
+ attrs = pa6t_attrs;
+ nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute);
+ pmc_attrs = NULL;
+ break;
+ default:
+ attrs = NULL;
+ nattrs = 0;
+ pmc_attrs = NULL;
+ }
+
+ for (i = 0; i < nattrs; i++)
+ sysdev_remove_file(s, &attrs[i]);
- sysdev_remove_file(s, &attr_mmcr0);
- sysdev_remove_file(s, &attr_mmcr1);
+ if (pmc_attrs)
+ for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
+ sysdev_remove_file(s, &pmc_attrs[i]);
if (cpu_has_feature(CPU_FTR_MMCRA))
sysdev_remove_file(s, &attr_mmcra);
- if (cur_cpu_spec->num_pmcs >= 1)
- sysdev_remove_file(s, &attr_pmc1);
- if (cur_cpu_spec->num_pmcs >= 2)
- sysdev_remove_file(s, &attr_pmc2);
- if (cur_cpu_spec->num_pmcs >= 3)
- sysdev_remove_file(s, &attr_pmc3);
- if (cur_cpu_spec->num_pmcs >= 4)
- sysdev_remove_file(s, &attr_pmc4);
- if (cur_cpu_spec->num_pmcs >= 5)
- sysdev_remove_file(s, &attr_pmc5);
- if (cur_cpu_spec->num_pmcs >= 6)
- sysdev_remove_file(s, &attr_pmc6);
- if (cur_cpu_spec->num_pmcs >= 7)
- sysdev_remove_file(s, &attr_pmc7);
- if (cur_cpu_spec->num_pmcs >= 8)
- sysdev_remove_file(s, &attr_pmc8);
-
if (cpu_has_feature(CPU_FTR_PURR))
sysdev_remove_file(s, &attr_purr);
+
+ if (cpu_has_feature(CPU_FTR_SPURR))
+ sysdev_remove_file(s, &attr_spurr);
+
+ if (cpu_has_feature(CPU_FTR_DSCR))
+ sysdev_remove_file(s, &attr_dscr);
}
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 0d4e203fa7a..dcc6f159fd9 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -32,6 +32,7 @@
#include <linux/kprobes.h>
#include <linux/kexec.h>
#include <linux/backlight.h>
+#include <linux/bug.h>
#include <asm/kdebug.h>
#include <asm/pgtable.h>
@@ -173,7 +174,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);
@@ -534,34 +535,40 @@ static void emulate_single_step(struct pt_regs *regs)
}
}
-static void parse_fpe(struct pt_regs *regs)
+static inline int __parse_fpscr(unsigned long fpscr)
{
- int code = 0;
- unsigned long fpscr;
-
- flush_fp_to_thread(current);
-
- fpscr = current->thread.fpscr.val;
+ int ret = 0;
/* Invalid operation */
if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX))
- code = FPE_FLTINV;
+ ret = FPE_FLTINV;
/* Overflow */
else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX))
- code = FPE_FLTOVF;
+ ret = FPE_FLTOVF;
/* Underflow */
else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX))
- code = FPE_FLTUND;
+ ret = FPE_FLTUND;
/* Divide by zero */
else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX))
- code = FPE_FLTDIV;
+ ret = FPE_FLTDIV;
/* Inexact result */
else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX))
- code = FPE_FLTRES;
+ ret = FPE_FLTRES;
+
+ return ret;
+}
+
+static void parse_fpe(struct pt_regs *regs)
+{
+ int code = 0;
+
+ flush_fp_to_thread(current);
+
+ code = __parse_fpscr(current->thread.fpscr.val);
_exception(SIGFPE, regs, code, regs->nip);
}
@@ -727,54 +734,9 @@ static int emulate_instruction(struct pt_regs *regs)
return -EINVAL;
}
-/*
- * Look through the list of trap instructions that are used for BUG(),
- * BUG_ON() and WARN_ON() and see if we hit one. At this point we know
- * that the exception was caused by a trap instruction of some kind.
- * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0
- * otherwise.
- */
-extern struct bug_entry __start___bug_table[], __stop___bug_table[];
-
-#ifndef CONFIG_MODULES
-#define module_find_bug(x) NULL
-#endif
-
-struct bug_entry *find_bug(unsigned long bugaddr)
-{
- struct bug_entry *bug;
-
- for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
- if (bugaddr == bug->bug_addr)
- return bug;
- return module_find_bug(bugaddr);
-}
-
-static int check_bug_trap(struct pt_regs *regs)
+int is_valid_bugaddr(unsigned long addr)
{
- struct bug_entry *bug;
- unsigned long addr;
-
- if (regs->msr & MSR_PR)
- return 0; /* not in kernel */
- addr = regs->nip; /* address of trap instruction */
- if (addr < PAGE_OFFSET)
- return 0;
- bug = find_bug(regs->nip);
- if (bug == NULL)
- return 0;
- if (bug->line & BUG_WARNING_TRAP) {
- /* this is a WARN_ON rather than BUG/BUG_ON */
- printk(KERN_ERR "Badness in %s at %s:%ld\n",
- bug->function, bug->file,
- bug->line & ~BUG_WARNING_TRAP);
- dump_stack();
- return 1;
- }
- printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
- bug->function, bug->file, bug->line);
-
- return 0;
+ return is_kernel_addr(addr);
}
void __kprobes program_check_exception(struct pt_regs *regs)
@@ -782,19 +744,8 @@ void __kprobes program_check_exception(struct pt_regs *regs)
unsigned int reason = get_reason(regs);
extern int do_mathemu(struct pt_regs *regs);
-#ifdef CONFIG_MATH_EMULATION
- /* (reason & REASON_ILLEGAL) would be the obvious thing here,
- * but there seems to be a hardware bug on the 405GP (RevD)
- * that means ESR is sometimes set incorrectly - either to
- * ESR_DST (!?) or 0. In the process of chasing this with the
- * hardware people - not sure if it can happen on any illegal
- * instruction or only on FP instructions, whether there is a
- * pattern to occurences etc. -dgibson 31/Mar/2003 */
- if (!(reason & REASON_TRAP) && do_mathemu(regs) == 0) {
- emulate_single_step(regs);
- return;
- }
-#endif /* CONFIG_MATH_EMULATION */
+ /* We can now get here via a FP Unavailable exception if the core
+ * has no FPU, in that case the reason flags will be 0 */
if (reason & REASON_FP) {
/* IEEE FP exception */
@@ -808,7 +759,9 @@ void __kprobes program_check_exception(struct pt_regs *regs)
return;
if (debugger_bpt(regs))
return;
- if (check_bug_trap(regs)) {
+
+ if (!(regs->msr & MSR_PR) && /* not user-mode */
+ report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) {
regs->nip += 4;
return;
}
@@ -818,6 +771,31 @@ void __kprobes program_check_exception(struct pt_regs *regs)
local_irq_enable();
+#ifdef CONFIG_MATH_EMULATION
+ /* (reason & REASON_ILLEGAL) would be the obvious thing here,
+ * but there seems to be a hardware bug on the 405GP (RevD)
+ * that means ESR is sometimes set incorrectly - either to
+ * ESR_DST (!?) or 0. In the process of chasing this with the
+ * hardware people - not sure if it can happen on any illegal
+ * instruction or only on FP instructions, whether there is a
+ * pattern to occurences etc. -dgibson 31/Mar/2003 */
+ switch (do_mathemu(regs)) {
+ case 0:
+ emulate_single_step(regs);
+ return;
+ case 1: {
+ int code = 0;
+ code = __parse_fpscr(current->thread.fpscr.val);
+ _exception(SIGFPE, regs, code, regs->nip);
+ return;
+ }
+ case -EFAULT:
+ _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
+ return;
+ }
+ /* fall through on any other errors */
+#endif /* CONFIG_MATH_EMULATION */
+
/* Try to emulate it if we should. */
if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) {
switch (emulate_instruction(regs)) {
@@ -931,18 +909,39 @@ void SoftwareEmulation(struct pt_regs *regs)
#ifdef CONFIG_MATH_EMULATION
errcode = do_mathemu(regs);
+
+ switch (errcode) {
+ case 0:
+ emulate_single_step(regs);
+ return;
+ case 1: {
+ int code = 0;
+ code = __parse_fpscr(current->thread.fpscr.val);
+ _exception(SIGFPE, regs, code, regs->nip);
+ return;
+ }
+ case -EFAULT:
+ _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
+ return;
+ default:
+ _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
+ return;
+ }
+
#else
errcode = Soft_emulate_8xx(regs);
-#endif
- if (errcode) {
- if (errcode > 0)
- _exception(SIGFPE, regs, 0, 0);
- else if (errcode == -EFAULT)
- _exception(SIGSEGV, regs, 0, 0);
- else
- _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
- } else
+ switch (errcode) {
+ case 0:
emulate_single_step(regs);
+ return;
+ case 1:
+ _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
+ return;
+ case -EFAULT:
+ _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
+ return;
+ }
+#endif
}
#endif /* CONFIG_8xx */
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 5730906b23d..8f5afdbad0d 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -45,6 +45,10 @@ void __init udbg_early_init(void)
#elif defined(CONFIG_PPC_EARLY_DEBUG_ISERIES)
/* For iSeries - hit Ctrl-x Ctrl-x to see the output */
udbg_init_iseries();
+#elif defined(CONFIG_PPC_EARLY_DEBUG_BEAT)
+ udbg_init_debug_beat();
+#elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE)
+ udbg_init_pas_realmode();
#endif
}
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index 2d17f2b8eda..e738f93b42f 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -14,6 +14,8 @@
extern u8 real_readb(volatile u8 __iomem *addr);
extern void real_writeb(u8 data, volatile u8 __iomem *addr);
+extern u8 real_205_readb(volatile u8 __iomem *addr);
+extern void real_205_writeb(u8 data, volatile u8 __iomem *addr);
struct NS16550 {
/* this struct must be packed */
@@ -167,3 +169,25 @@ void __init udbg_init_maple_realmode(void)
udbg_getc_poll = NULL;
}
#endif /* CONFIG_PPC_MAPLE */
+
+#ifdef CONFIG_PPC_PASEMI
+void udbg_pas_real_putc(char c)
+{
+ if (udbg_comport) {
+ while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
+ /* wait for idle */;
+ real_205_writeb(c, &udbg_comport->thr); eieio();
+ if (c == '\n')
+ udbg_pas_real_putc('\r');
+ }
+}
+
+void udbg_init_pas_realmode(void)
+{
+ udbg_comport = (volatile struct NS16550 __iomem *)0xfcff03f8;
+
+ udbg_putc = udbg_pas_real_putc;
+ udbg_getc = NULL;
+ udbg_getc_poll = NULL;
+}
+#endif /* CONFIG_PPC_MAPLE */
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index a4b28c73bba..50149ec6efa 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -49,9 +49,13 @@
/* Max supported size for symbol names */
#define MAX_SYMNAME 64
+#define VDSO32_MAXPAGES (((0x3000 + PAGE_MASK) >> PAGE_SHIFT) + 2)
+#define VDSO64_MAXPAGES (((0x3000 + PAGE_MASK) >> PAGE_SHIFT) + 2)
+
extern char vdso32_start, vdso32_end;
static void *vdso32_kbase = &vdso32_start;
unsigned int vdso32_pages;
+static struct page *vdso32_pagelist[VDSO32_MAXPAGES];
unsigned long vdso32_sigtramp;
unsigned long vdso32_rt_sigtramp;
@@ -59,6 +63,7 @@ unsigned long vdso32_rt_sigtramp;
extern char vdso64_start, vdso64_end;
static void *vdso64_kbase = &vdso64_start;
unsigned int vdso64_pages;
+static struct page *vdso64_pagelist[VDSO64_MAXPAGES];
unsigned long vdso64_rt_sigtramp;
#endif /* CONFIG_PPC64 */
@@ -165,55 +170,6 @@ static void dump_vdso_pages(struct vm_area_struct * vma)
#endif /* DEBUG */
/*
- * Keep a dummy vma_close for now, it will prevent VMA merging.
- */
-static void vdso_vma_close(struct vm_area_struct * vma)
-{
-}
-
-/*
- * Our nopage() function, maps in the actual vDSO kernel pages, they will
- * be mapped read-only by do_no_page(), and eventually COW'ed, either
- * right away for an initial write access, or by do_wp_page().
- */
-static struct page * vdso_vma_nopage(struct vm_area_struct * vma,
- unsigned long address, int *type)
-{
- unsigned long offset = address - vma->vm_start;
- struct page *pg;
-#ifdef CONFIG_PPC64
- void *vbase = (vma->vm_mm->task_size > TASK_SIZE_USER32) ?
- vdso64_kbase : vdso32_kbase;
-#else
- void *vbase = vdso32_kbase;
-#endif
-
- DBG("vdso_vma_nopage(current: %s, address: %016lx, off: %lx)\n",
- current->comm, address, offset);
-
- if (address < vma->vm_start || address > vma->vm_end)
- return NOPAGE_SIGBUS;
-
- /*
- * Last page is systemcfg.
- */
- if ((vma->vm_end - address) <= PAGE_SIZE)
- pg = virt_to_page(vdso_data);
- else
- pg = virt_to_page(vbase + offset);
-
- get_page(pg);
- DBG(" ->page count: %d\n", page_count(pg));
-
- return pg;
-}
-
-static struct vm_operations_struct vdso_vmops = {
- .close = vdso_vma_close,
- .nopage = vdso_vma_nopage,
-};
-
-/*
* This is called from binfmt_elf, we create the special vma for the
* vDSO and insert it into the mm struct tree
*/
@@ -221,20 +177,23 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
int executable_stack)
{
struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
+ struct page **vdso_pagelist;
unsigned long vdso_pages;
unsigned long vdso_base;
int rc;
#ifdef CONFIG_PPC64
if (test_thread_flag(TIF_32BIT)) {
+ vdso_pagelist = vdso32_pagelist;
vdso_pages = vdso32_pages;
vdso_base = VDSO32_MBASE;
} else {
+ vdso_pagelist = vdso64_pagelist;
vdso_pages = vdso64_pages;
vdso_base = VDSO64_MBASE;
}
#else
+ vdso_pagelist = vdso32_pagelist;
vdso_pages = vdso32_pages;
vdso_base = VDSO32_MBASE;
#endif
@@ -262,17 +221,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
goto fail_mmapsem;
}
-
- /* Allocate a VMA structure and fill it up */
- vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
- if (vma == NULL) {
- rc = -ENOMEM;
- goto fail_mmapsem;
- }
- vma->vm_mm = mm;
- vma->vm_start = vdso_base;
- vma->vm_end = vma->vm_start + (vdso_pages << PAGE_SHIFT);
-
/*
* our vma flags don't have VM_WRITE so by default, the process isn't
* allowed to write those pages.
@@ -282,25 +230,26 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
* and your nice userland gettimeofday will be totally dead.
* It's fine to use that for setting breakpoints in the vDSO code
* pages though
+ *
+ * Make sure the vDSO gets into every core dump.
+ * Dumping its contents makes post-mortem fully interpretable later
+ * without matching up the same kernel and hardware config to see
+ * what PC values meant.
*/
- vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC;
- vma->vm_flags |= mm->def_flags;
- vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
- vma->vm_ops = &vdso_vmops;
-
- /* Insert new VMA */
- rc = insert_vm_struct(mm, vma);
+ rc = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+ VM_ALWAYSDUMP,
+ vdso_pagelist);
if (rc)
- goto fail_vma;
+ goto fail_mmapsem;
- /* Put vDSO base into mm struct and account for memory usage */
+ /* Put vDSO base into mm struct */
current->mm->context.vdso_base = vdso_base;
- mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+
up_write(&mm->mmap_sem);
return 0;
- fail_vma:
- kmem_cache_free(vm_area_cachep, vma);
fail_mmapsem:
up_write(&mm->mmap_sem);
return rc;
@@ -771,18 +720,26 @@ void __init vdso_init(void)
}
/* Make sure pages are in the correct state */
+ BUG_ON(vdso32_pages + 2 > VDSO32_MAXPAGES);
for (i = 0; i < vdso32_pages; i++) {
struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
ClearPageReserved(pg);
get_page(pg);
-
+ vdso32_pagelist[i] = pg;
}
+ vdso32_pagelist[i++] = virt_to_page(vdso_data);
+ vdso32_pagelist[i] = NULL;
+
#ifdef CONFIG_PPC64
+ BUG_ON(vdso64_pages + 2 > VDSO64_MAXPAGES);
for (i = 0; i < vdso64_pages; i++) {
struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE);
ClearPageReserved(pg);
get_page(pg);
+ vdso64_pagelist[i] = pg;
}
+ vdso64_pagelist[i++] = virt_to_page(vdso_data);
+ vdso64_pagelist[i] = NULL;
#endif /* CONFIG_PPC64 */
get_page(virt_to_page(vdso_data));
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index a80f8f1d2e5..2968ffeafdb 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -199,10 +199,8 @@ EXPORT_SYMBOL(vio_unregister_driver);
/* vio_dev refcount hit 0 */
static void __devinit vio_dev_release(struct device *dev)
{
- if (dev->archdata.of_node) {
- /* XXX should free TCE table */
- of_node_put(dev->archdata.of_node);
- }
+ /* XXX should free TCE table */
+ of_node_put(dev->archdata.of_node);
kfree(to_vio_dev(dev));
}
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 04b98671a06..04b8e71bf5b 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -62,11 +62,7 @@ SECTIONS
__stop___ex_table = .;
}
- __bug_table : {
- __start___bug_table = .;
- *(__bug_table)
- __stop___bug_table = .;
- }
+ BUG_TABLE
/*
* Init sections discarded at runtime
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index a0360ae10d0..4b1ba49fbd9 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -16,13 +16,15 @@ obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \
strcase.o
obj-$(CONFIG_QUICC_ENGINE) += rheap.o
obj-$(CONFIG_XMON) += sstep.o
+obj-$(CONFIG_KPROBES) += sstep.o
+obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.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_8xx) += rheap.o
obj-$(CONFIG_CPM2) += rheap.o
endif
diff --git a/arch/ppc/kernel/dma-mapping.c b/arch/powerpc/lib/dma-noncoherent.c
index 10fec736396..48f3d13a3de 100644
--- a/arch/ppc/kernel/dma-mapping.c
+++ b/arch/powerpc/lib/dma-noncoherent.c
@@ -22,37 +22,13 @@
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
-#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/swap.h>
-#include <linux/stddef.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bootmem.h>
#include <linux/highmem.h>
#include <linux/dma-mapping.h>
-#include <linux/hardirq.h>
-
-#include <asm/pgalloc.h>
-#include <asm/prom.h>
-#include <asm/io.h>
-#include <asm/mmu_context.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/uaccess.h>
-#include <asm/smp.h>
-#include <asm/machdep.h>
-
-int map_page(unsigned long va, phys_addr_t pa, int flags);
#include <asm/tlbflush.h>
diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c
index 57bf991ccd6..6c5c5dd183e 100644
--- a/arch/powerpc/lib/rheap.c
+++ b/arch/powerpc/lib/rheap.c
@@ -14,6 +14,7 @@
*/
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -85,7 +86,8 @@ static int grow(rh_info_t * info, int max_blocks)
info->flags &= ~RHIF_STATIC_BLOCK;
/* add all new blocks to the free list */
- for (i = 0, blk = block + info->max_blocks; i < new_blocks; i++, blk++)
+ blk = block + info->max_blocks - new_blocks;
+ for (i = 0; i < new_blocks; i++, blk++)
list_add(&blk->list, &info->empty_list);
return 0;
@@ -670,7 +672,7 @@ void rh_dump(rh_info_t * info)
int maxnr;
int i, nr;
- maxnr = sizeof(st) / sizeof(st[0]);
+ maxnr = ARRAY_SIZE(st);
printk(KERN_INFO
"info @0x%p (%d slots empty / %d max)\n",
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 89c836d5480..8c77c791f87 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -744,7 +744,8 @@ static int htlb_check_hinted_area(unsigned long addr, unsigned long len)
struct vm_area_struct *vma;
vma = find_vma(current->mm, addr);
- if (!vma || ((addr + len) <= vma->vm_start))
+ if (TASK_SIZE - len >= addr &&
+ (!vma || ((addr + len) <= vma->vm_start)))
return 0;
return -ENOMEM;
@@ -815,6 +816,8 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
return -EINVAL;
if (len & ~HPAGE_MASK)
return -EINVAL;
+ if (len > TASK_SIZE)
+ return -ENOMEM;
if (!cpu_has_feature(CPU_FTR_16M_PAGE))
return -EINVAL;
@@ -823,9 +826,6 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
BUG_ON((addr + len) < addr);
if (test_thread_flag(TIF_32BIT)) {
- /* Paranoia, caller should have dealt with this */
- BUG_ON((addr + len) > 0x100000000UL);
-
curareas = current->mm->context.low_htlb_areas;
/* First see if we can use the hint address */
@@ -1014,7 +1014,6 @@ repeat:
/* Primary is full, try the secondary */
if (unlikely(slot == -1)) {
- new_pte |= _PAGE_F_SECOND;
hpte_group = ((~hash & htab_hash_mask) *
HPTES_PER_GROUP) & ~0x7UL;
slot = ppc_md.hpte_insert(hpte_group, va, pa, rflags,
@@ -1033,7 +1032,7 @@ repeat:
if (unlikely(slot == -2))
panic("hash_huge_page: pte_insert failed\n");
- new_pte |= (slot << 12) & _PAGE_F_GIX;
+ new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX);
}
/*
diff --git a/arch/powerpc/mm/imalloc.c b/arch/powerpc/mm/imalloc.c
index add8c1a9af6..c831815c31f 100644
--- a/arch/powerpc/mm/imalloc.c
+++ b/arch/powerpc/mm/imalloc.c
@@ -138,7 +138,7 @@ static struct vm_struct * split_im_region(unsigned long v_addr,
struct vm_struct *vm2 = NULL;
struct vm_struct *new_vm = NULL;
- vm1 = (struct vm_struct *) kmalloc(sizeof(*vm1), GFP_KERNEL);
+ vm1 = kmalloc(sizeof(*vm1), GFP_KERNEL);
if (vm1 == NULL) {
printk(KERN_ERR "%s() out of memory\n", __FUNCTION__);
return NULL;
@@ -172,7 +172,7 @@ static struct vm_struct * split_im_region(unsigned long v_addr,
* uppermost remainder, and use existing parent one for the
* lower remainder of parent range
*/
- vm2 = (struct vm_struct *) kmalloc(sizeof(*vm2), GFP_KERNEL);
+ vm2 = kmalloc(sizeof(*vm2), GFP_KERNEL);
if (vm2 == NULL) {
printk(KERN_ERR "%s() out of memory\n", __FUNCTION__);
kfree(vm1);
@@ -206,7 +206,7 @@ static struct vm_struct * __add_new_im_area(unsigned long req_addr,
break;
}
- area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
+ area = kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return NULL;
area->flags = 0;
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index d1c0758c561..77b4637097e 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -61,10 +61,6 @@ unsigned long memory_limit;
extern void hash_preload(struct mm_struct *mm, unsigned long ea,
unsigned long access, unsigned long trap);
-/*
- * This is called by /dev/mem to know if a given address has to
- * be mapped non-cacheable or not
- */
int page_is_ram(unsigned long pfn)
{
unsigned long paddr = (pfn << PAGE_SHIFT);
@@ -490,19 +486,19 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
!cpu_has_feature(CPU_FTR_NOEXECUTE) &&
pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);
+#ifdef CONFIG_8xx
+ /* On 8xx, cache control instructions (particularly
+ * "dcbst" from flush_dcache_icache) fault as write
+ * operation if there is an unpopulated TLB entry
+ * for the address in question. To workaround that,
+ * we invalidate the TLB here, thus avoiding dcbst
+ * misbehaviour.
+ */
+ _tlbie(address);
+#endif
if (!PageReserved(page)
&& !test_bit(PG_arch_1, &page->flags)) {
if (vma->vm_mm == current->active_mm) {
-#ifdef CONFIG_8xx
- /* On 8xx, cache control instructions (particularly
- * "dcbst" from flush_dcache_icache) fault as write
- * operation if there is an unpopulated TLB entry
- * for the address in question. To workaround that,
- * we invalidate the TLB here, thus avoiding dcbst
- * misbehaviour.
- */
- _tlbie(address);
-#endif
__flush_dcache_icache((void *) address);
} else
flush_dcache_icache_page(page);
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 9da01dc8cfd..262790910ff 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -295,6 +295,63 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
return lmb_end_of_DRAM() - start;
}
+/*
+ * Extract NUMA information from the ibm,dynamic-reconfiguration-memory
+ * node. This assumes n_mem_{addr,size}_cells have been set.
+ */
+static void __init parse_drconf_memory(struct device_node *memory)
+{
+ const unsigned int *lm, *dm, *aa;
+ unsigned int ls, ld, la;
+ unsigned int n, aam, aalen;
+ unsigned long lmb_size, size;
+ int nid, default_nid = 0;
+ unsigned int start, ai, flags;
+
+ lm = get_property(memory, "ibm,lmb-size", &ls);
+ dm = get_property(memory, "ibm,dynamic-memory", &ld);
+ aa = get_property(memory, "ibm,associativity-lookup-arrays", &la);
+ if (!lm || !dm || !aa ||
+ ls < sizeof(unsigned int) || ld < sizeof(unsigned int) ||
+ la < 2 * sizeof(unsigned int))
+ return;
+
+ lmb_size = read_n_cells(n_mem_size_cells, &lm);
+ n = *dm++; /* number of LMBs */
+ aam = *aa++; /* number of associativity lists */
+ aalen = *aa++; /* length of each associativity list */
+ if (ld < (n * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int) ||
+ la < (aam * aalen + 2) * sizeof(unsigned int))
+ return;
+
+ for (; n != 0; --n) {
+ start = read_n_cells(n_mem_addr_cells, &dm);
+ ai = dm[2];
+ flags = dm[3];
+ dm += 4;
+ /* 0x80 == reserved, 0x8 = assigned to us */
+ if ((flags & 0x80) || !(flags & 0x8))
+ continue;
+ nid = default_nid;
+ /* flags & 0x40 means associativity index is invalid */
+ if (min_common_depth > 0 && min_common_depth <= aalen &&
+ (flags & 0x40) == 0 && ai < aam) {
+ /* this is like of_node_to_nid_single */
+ nid = aa[ai * aalen + min_common_depth - 1];
+ if (nid == 0xffff || nid >= MAX_NUMNODES)
+ nid = default_nid;
+ }
+ node_set_online(nid);
+
+ size = numa_enforce_memory_limit(start, lmb_size);
+ if (!size)
+ continue;
+
+ add_active_range(nid, start >> PAGE_SHIFT,
+ (start >> PAGE_SHIFT) + (size >> PAGE_SHIFT));
+ }
+}
+
static int __init parse_numa_properties(void)
{
struct device_node *cpu = NULL;
@@ -385,6 +442,14 @@ new_range:
goto new_range;
}
+ /*
+ * Now do the same thing for each LMB listed in the ibm,dynamic-memory
+ * property in the ibm,dynamic-reconfiguration-memory node.
+ */
+ memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+ if (memory)
+ parse_drconf_memory(memory);
+
return 0;
}
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 1891dbeeb8e..bd02272bcb0 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -294,11 +294,8 @@ void __init mapin_ram(void)
}
}
-/* is x a power of 2? */
-#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
-
/* is x a power of 4? */
-#define is_power_of_4(x) ((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1))
+#define is_power_of_4(x) is_power_of_2(x) && (ffs(x) & 1))
/*
* Set up a mapping for a block of I/O.
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index b6d82390b6a..fbd62eacfdf 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -149,6 +149,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
#ifdef CONFIG_PPC64
#ifdef CONFIG_PPC_CELL_NATIVE
case PPC_OPROFILE_CELL:
+ if (firmware_has_feature(FW_FEATURE_LPAR))
+ return -ENODEV;
model = &op_model_cell;
break;
#endif
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
index f481c0ed5e6..5d1bbaf35cc 100644
--- a/arch/powerpc/oprofile/op_model_7450.c
+++ b/arch/powerpc/oprofile/op_model_7450.c
@@ -137,9 +137,9 @@ static void fsl7450_start(struct op_counter_config *ctr)
for (i = 0; i < NUM_CTRS; ++i) {
if (ctr[i].enabled)
- ctr_write(i, reset_value[i]);
+ classic_ctr_write(i, reset_value[i]);
else
- ctr_write(i, 0);
+ classic_ctr_write(i, 0);
}
/* Clear the freeze bit, and enable the interrupt.
@@ -179,13 +179,13 @@ static void fsl7450_handle_interrupt(struct pt_regs *regs,
is_kernel = is_kernel_addr(pc);
for (i = 0; i < NUM_CTRS; ++i) {
- val = ctr_read(i);
+ val = classic_ctr_read(i);
if (val < 0) {
if (oprofile_running && ctr[i].enabled) {
oprofile_add_ext_sample(pc, regs, i, is_kernel);
- ctr_write(i, reset_value[i]);
+ classic_ctr_write(i, reset_value[i]);
} else {
- ctr_write(i, 0);
+ classic_ctr_write(i, 0);
}
}
}
diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c
index 0b3c31f5209..2267eb8c661 100644
--- a/arch/powerpc/oprofile/op_model_fsl_booke.c
+++ b/arch/powerpc/oprofile/op_model_fsl_booke.c
@@ -32,6 +32,87 @@ static unsigned long reset_value[OP_MAX_COUNTER];
static int num_counters;
static int oprofile_running;
+static inline u32 get_pmlca(int ctr)
+{
+ u32 pmlca;
+
+ switch (ctr) {
+ case 0:
+ pmlca = mfpmr(PMRN_PMLCA0);
+ break;
+ case 1:
+ pmlca = mfpmr(PMRN_PMLCA1);
+ break;
+ case 2:
+ pmlca = mfpmr(PMRN_PMLCA2);
+ break;
+ case 3:
+ pmlca = mfpmr(PMRN_PMLCA3);
+ break;
+ default:
+ panic("Bad ctr number\n");
+ }
+
+ return pmlca;
+}
+
+static inline void set_pmlca(int ctr, u32 pmlca)
+{
+ switch (ctr) {
+ case 0:
+ mtpmr(PMRN_PMLCA0, pmlca);
+ break;
+ case 1:
+ mtpmr(PMRN_PMLCA1, pmlca);
+ break;
+ case 2:
+ mtpmr(PMRN_PMLCA2, pmlca);
+ break;
+ case 3:
+ mtpmr(PMRN_PMLCA3, pmlca);
+ break;
+ default:
+ panic("Bad ctr number\n");
+ }
+}
+
+static inline unsigned int ctr_read(unsigned int i)
+{
+ switch(i) {
+ case 0:
+ return mfpmr(PMRN_PMC0);
+ case 1:
+ return mfpmr(PMRN_PMC1);
+ case 2:
+ return mfpmr(PMRN_PMC2);
+ case 3:
+ return mfpmr(PMRN_PMC3);
+ default:
+ return 0;
+ }
+}
+
+static inline void ctr_write(unsigned int i, unsigned int val)
+{
+ switch(i) {
+ case 0:
+ mtpmr(PMRN_PMC0, val);
+ break;
+ case 1:
+ mtpmr(PMRN_PMC1, val);
+ break;
+ case 2:
+ mtpmr(PMRN_PMC2, val);
+ break;
+ case 3:
+ mtpmr(PMRN_PMC3, val);
+ break;
+ default:
+ break;
+ }
+}
+
+
static void init_pmc_stop(int ctr)
{
u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU |
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index 356709d515b..fe597a154d4 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -121,9 +121,9 @@ static void power4_start(struct op_counter_config *ctr)
for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
if (ctr[i].enabled) {
- ctr_write(i, reset_value[i]);
+ classic_ctr_write(i, reset_value[i]);
} else {
- ctr_write(i, 0);
+ classic_ctr_write(i, 0);
}
}
@@ -254,13 +254,13 @@ static void power4_handle_interrupt(struct pt_regs *regs,
mtmsrd(mfmsr() | MSR_PMM);
for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
- val = ctr_read(i);
+ val = classic_ctr_read(i);
if (val < 0) {
if (oprofile_running && ctr[i].enabled) {
oprofile_add_ext_sample(pc, regs, i, is_kernel);
- ctr_write(i, reset_value[i]);
+ classic_ctr_write(i, reset_value[i]);
} else {
- ctr_write(i, 0);
+ classic_ctr_write(i, 0);
}
}
}
diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c
index 19c5ee089bc..c731acbfb2a 100644
--- a/arch/powerpc/oprofile/op_model_rs64.c
+++ b/arch/powerpc/oprofile/op_model_rs64.c
@@ -137,10 +137,10 @@ static void rs64_start(struct op_counter_config *ctr)
for (i = 0; i < num_counters; ++i) {
if (ctr[i].enabled) {
- ctr_write(i, reset_value[i]);
+ classic_ctr_write(i, reset_value[i]);
ctrl_write(i, ctr[i].event);
} else {
- ctr_write(i, 0);
+ classic_ctr_write(i, 0);
}
}
@@ -186,13 +186,13 @@ static void rs64_handle_interrupt(struct pt_regs *regs,
mtmsrd(mfmsr() | MSR_PMM);
for (i = 0; i < num_counters; ++i) {
- val = ctr_read(i);
+ val = classic_ctr_read(i);
if (val < 0) {
if (ctr[i].enabled) {
oprofile_add_ext_sample(pc, regs, i, is_kernel);
- ctr_write(i, reset_value[i]);
+ classic_ctr_write(i, reset_value[i]);
} else {
- ctr_write(i, 0);
+ classic_ctr_write(i, 0);
}
}
}
diff --git a/arch/powerpc/platforms/4xx/Kconfig b/arch/powerpc/platforms/4xx/Kconfig
index ed39d6a3d22..2f2a13ed766 100644
--- a/arch/powerpc/platforms/4xx/Kconfig
+++ b/arch/powerpc/platforms/4xx/Kconfig
@@ -179,7 +179,7 @@ config BIOS_FIXUP
# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
config 403GCX
bool
- depends OAK
+ depends on OAK
default y
config 405EP
diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile
index a46184a0c75..795b713ec9e 100644
--- a/arch/powerpc/platforms/52xx/Makefile
+++ b/arch/powerpc/platforms/52xx/Makefile
@@ -3,6 +3,7 @@
#
ifeq ($(CONFIG_PPC_MERGE),y)
obj-y += mpc52xx_pic.o mpc52xx_common.o
+obj-$(CONFIG_PCI) += mpc52xx_pci.o
endif
obj-$(CONFIG_PPC_EFIKA) += efika-setup.o efika-pci.o
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index a375c15b431..cdb16bfa6ca 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -40,8 +40,6 @@
#include <asm/prom.h>
#include <asm/udbg.h>
#include <sysdev/fsl_soc.h>
-#include <asm/qe.h>
-#include <asm/qe_ic.h>
#include <asm/of_platform.h>
#include <asm/mpc52xx.h>
@@ -109,6 +107,12 @@ static void __init lite52xx_setup_arch(void)
mpc52xx_setup_cpu(); /* Generic */
lite52xx_setup_cpu(); /* Platorm specific */
+#ifdef CONFIG_PCI
+ np = of_find_node_by_type(np, "pci");
+ if (np)
+ mpc52xx_add_bridge(np);
+#endif
+
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
ROOT_DEV = Root_RAM0;
@@ -155,6 +159,7 @@ define_machine(lite52xx) {
.name = "lite52xx",
.probe = lite52xx_probe,
.setup_arch = lite52xx_setup_arch,
+ .init = mpc52xx_declare_of_platform_devices,
.init_IRQ = mpc52xx_init_irq,
.get_irq = mpc52xx_get_irq,
.show_cpuinfo = lite52xx_show_cpuinfo,
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c
index 8331ff45777..cc40889074b 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -116,11 +116,12 @@ unmap_regs:
if (xlb) iounmap(xlb);
}
-static int __init
+void __init
mpc52xx_declare_of_platform_devices(void)
{
/* Find every child of the SOC node and add it to of_platform */
- return of_platform_bus_probe(NULL, NULL, NULL);
+ if (of_platform_bus_probe(NULL, NULL, NULL))
+ printk(KERN_ERR __FILE__ ": "
+ "Error while probing of_platform bus\n");
}
-device_initcall(mpc52xx_declare_of_platform_devices);
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
new file mode 100644
index 00000000000..faf161bdbc1
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -0,0 +1,412 @@
+/*
+ * PCI code for the Freescale MPC52xx embedded CPU.
+ *
+ * Copyright (C) 2006 Secret Lab Technologies Ltd.
+ * Grant Likely <grant.likely@secretlab.ca>
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.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.
+ */
+
+#undef DEBUG
+
+#include <asm/pci.h>
+#include <asm/mpc52xx.h>
+#include <asm/delay.h>
+#include <asm/machdep.h>
+#include <linux/kernel.h>
+
+
+/* ======================================================================== */
+/* PCI windows config */
+/* ======================================================================== */
+
+#define MPC52xx_PCI_TARGET_IO 0xf0000000
+#define MPC52xx_PCI_TARGET_MEM 0x00000000
+
+
+/* ======================================================================== */
+/* Structures mapping & Defines for PCI Unit */
+/* ======================================================================== */
+
+#define MPC52xx_PCI_GSCR_BM 0x40000000
+#define MPC52xx_PCI_GSCR_PE 0x20000000
+#define MPC52xx_PCI_GSCR_SE 0x10000000
+#define MPC52xx_PCI_GSCR_XLB2PCI_MASK 0x07000000
+#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT 24
+#define MPC52xx_PCI_GSCR_IPG2PCI_MASK 0x00070000
+#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT 16
+#define MPC52xx_PCI_GSCR_BME 0x00004000
+#define MPC52xx_PCI_GSCR_PEE 0x00002000
+#define MPC52xx_PCI_GSCR_SEE 0x00001000
+#define MPC52xx_PCI_GSCR_PR 0x00000001
+
+
+#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size) \
+ ( ( (proc_ad) & 0xff000000 ) | \
+ ( (((size) - 1) >> 8) & 0x00ff0000 ) | \
+ ( ((pci_ad) >> 16) & 0x0000ff00 ) )
+
+#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2) (((win0) << 24) | \
+ ((win1) << 16) | \
+ ((win2) << 8))
+
+#define MPC52xx_PCI_IWCR_DISABLE 0x0
+#define MPC52xx_PCI_IWCR_ENABLE 0x1
+#define MPC52xx_PCI_IWCR_READ 0x0
+#define MPC52xx_PCI_IWCR_READ_LINE 0x2
+#define MPC52xx_PCI_IWCR_READ_MULTI 0x4
+#define MPC52xx_PCI_IWCR_MEM 0x0
+#define MPC52xx_PCI_IWCR_IO 0x8
+
+#define MPC52xx_PCI_TCR_P 0x01000000
+#define MPC52xx_PCI_TCR_LD 0x00010000
+
+#define MPC52xx_PCI_TBATR_DISABLE 0x0
+#define MPC52xx_PCI_TBATR_ENABLE 0x1
+
+struct mpc52xx_pci {
+ u32 idr; /* PCI + 0x00 */
+ u32 scr; /* PCI + 0x04 */
+ u32 ccrir; /* PCI + 0x08 */
+ u32 cr1; /* PCI + 0x0C */
+ u32 bar0; /* PCI + 0x10 */
+ u32 bar1; /* PCI + 0x14 */
+ u8 reserved1[16]; /* PCI + 0x18 */
+ u32 ccpr; /* PCI + 0x28 */
+ u32 sid; /* PCI + 0x2C */
+ u32 erbar; /* PCI + 0x30 */
+ u32 cpr; /* PCI + 0x34 */
+ u8 reserved2[4]; /* PCI + 0x38 */
+ u32 cr2; /* PCI + 0x3C */
+ u8 reserved3[32]; /* PCI + 0x40 */
+ u32 gscr; /* PCI + 0x60 */
+ u32 tbatr0; /* PCI + 0x64 */
+ u32 tbatr1; /* PCI + 0x68 */
+ u32 tcr; /* PCI + 0x6C */
+ u32 iw0btar; /* PCI + 0x70 */
+ u32 iw1btar; /* PCI + 0x74 */
+ u32 iw2btar; /* PCI + 0x78 */
+ u8 reserved4[4]; /* PCI + 0x7C */
+ u32 iwcr; /* PCI + 0x80 */
+ u32 icr; /* PCI + 0x84 */
+ u32 isr; /* PCI + 0x88 */
+ u32 arb; /* PCI + 0x8C */
+ u8 reserved5[104]; /* PCI + 0x90 */
+ u32 car; /* PCI + 0xF8 */
+ u8 reserved6[4]; /* PCI + 0xFC */
+};
+
+
+/* ======================================================================== */
+/* PCI configuration acess */
+/* ======================================================================== */
+
+static int
+mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 *val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ u32 value;
+
+ if (ppc_md.pci_exclude_device)
+ if (ppc_md.pci_exclude_device(bus->number, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ out_be32(hose->cfg_addr,
+ (1 << 31) |
+ ((bus->number - hose->bus_offset) << 16) |
+ (devfn << 8) |
+ (offset & 0xfc));
+ mb();
+
+#if defined(CONFIG_PPC_MPC5200_BUGFIX)
+ if (bus->number != hose->bus_offset) {
+ /* workaround for the bug 435 of the MPC5200 (L25R);
+ * Don't do 32 bits config access during type-1 cycles */
+ switch (len) {
+ case 1:
+ value = in_8(((u8 __iomem *)hose->cfg_data) +
+ (offset & 3));
+ break;
+ case 2:
+ value = in_le16(((u16 __iomem *)hose->cfg_data) +
+ ((offset>>1) & 1));
+ break;
+
+ default:
+ value = in_le16((u16 __iomem *)hose->cfg_data) |
+ (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
+ break;
+ }
+ }
+ else
+#endif
+ {
+ value = in_le32(hose->cfg_data);
+
+ if (len != 4) {
+ value >>= ((offset & 0x3) << 3);
+ value &= 0xffffffff >> (32 - (len << 3));
+ }
+ }
+
+ *val = value;
+
+ out_be32(hose->cfg_addr, 0);
+ mb();
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ u32 value, mask;
+
+ if (ppc_md.pci_exclude_device)
+ if (ppc_md.pci_exclude_device(bus->number, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ out_be32(hose->cfg_addr,
+ (1 << 31) |
+ ((bus->number - hose->bus_offset) << 16) |
+ (devfn << 8) |
+ (offset & 0xfc));
+ mb();
+
+#if defined(CONFIG_PPC_MPC5200_BUGFIX)
+ if (bus->number != hose->bus_offset) {
+ /* workaround for the bug 435 of the MPC5200 (L25R);
+ * Don't do 32 bits config access during type-1 cycles */
+ switch (len) {
+ case 1:
+ out_8(((u8 __iomem *)hose->cfg_data) +
+ (offset & 3), val);
+ break;
+ case 2:
+ out_le16(((u16 __iomem *)hose->cfg_data) +
+ ((offset>>1) & 1), val);
+ break;
+
+ default:
+ out_le16((u16 __iomem *)hose->cfg_data,
+ (u16)val);
+ out_le16(((u16 __iomem *)hose->cfg_data) + 1,
+ (u16)(val>>16));
+ break;
+ }
+ }
+ else
+#endif
+ {
+ if (len != 4) {
+ value = in_le32(hose->cfg_data);
+
+ offset = (offset & 0x3) << 3;
+ mask = (0xffffffff >> (32 - (len << 3)));
+ mask <<= offset;
+
+ value &= ~mask;
+ val = value | ((val << offset) & mask);
+ }
+
+ out_le32(hose->cfg_data, val);
+ }
+ mb();
+
+ out_be32(hose->cfg_addr, 0);
+ mb();
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops mpc52xx_pci_ops = {
+ .read = mpc52xx_pci_read_config,
+ .write = mpc52xx_pci_write_config
+};
+
+
+/* ======================================================================== */
+/* PCI setup */
+/* ======================================================================== */
+
+static void __init
+mpc52xx_pci_setup(struct pci_controller *hose,
+ struct mpc52xx_pci __iomem *pci_regs)
+{
+ struct resource *res;
+ u32 tmp;
+ int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0;
+
+ pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs);
+
+ /* pci_process_bridge_OF_ranges() found all our addresses for us;
+ * now store them in the right places */
+ hose->cfg_addr = &pci_regs->car;
+ hose->cfg_data = hose->io_base_virt;
+
+ /* Control regs */
+ tmp = in_be32(&pci_regs->scr);
+ tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ out_be32(&pci_regs->scr, tmp);
+
+ /* Memory windows */
+ res = &hose->mem_resources[0];
+ if (res->flags) {
+ pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n",
+ res->start, res->end, res->flags);
+ out_be32(&pci_regs->iw0btar,
+ MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
+ res->end - res->start + 1));
+ iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
+ if (res->flags & IORESOURCE_PREFETCH)
+ iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI;
+ else
+ iwcr0 |= MPC52xx_PCI_IWCR_READ;
+ }
+
+ res = &hose->mem_resources[1];
+ if (res->flags) {
+ pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n",
+ res->start, res->end, res->flags);
+ out_be32(&pci_regs->iw1btar,
+ MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
+ res->end - res->start + 1));
+ iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
+ if (res->flags & IORESOURCE_PREFETCH)
+ iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI;
+ else
+ iwcr1 |= MPC52xx_PCI_IWCR_READ;
+ }
+
+ /* IO resources */
+ res = &hose->io_resource;
+ if (!res) {
+ printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__);
+ return;
+ }
+ pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} "
+ ".io_base_phys=0x%p\n",
+ res->start, res->end, res->flags, (void*)hose->io_base_phys);
+ out_be32(&pci_regs->iw2btar,
+ MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
+ res->start,
+ res->end - res->start + 1));
+ iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO;
+
+ /* Set all the IWCR fields at once; they're in the same reg */
+ out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2));
+
+ out_be32(&pci_regs->tbatr0,
+ MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
+ out_be32(&pci_regs->tbatr1,
+ MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
+
+ out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
+
+ tmp = in_be32(&pci_regs->gscr);
+#if 0
+ /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
+ /* Not necessary and can be a bad thing if for example the bootloader
+ is displaying a splash screen or ... Just left here for
+ documentation purpose if anyone need it */
+ out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
+ udelay(50);
+#endif
+
+ /* Make sure the PCI bridge is out of reset */
+ out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
+}
+
+static void
+mpc52xx_pci_fixup_resources(struct pci_dev *dev)
+{
+ int i;
+
+ pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n",
+ dev->vendor, dev->device);
+
+ /* We don't rely on boot loader for PCI and resets all
+ devices */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ struct resource *res = &dev->resource[i];
+ if (res->end > res->start) { /* Only valid resources */
+ res->end -= res->start;
+ res->start = 0;
+ res->flags |= IORESOURCE_UNSET;
+ }
+ }
+
+ /* The PCI Host bridge of MPC52xx has a prefetch memory resource
+ fixed to 1Gb. Doesn't fit in the resource system so we remove it */
+ if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
+ ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
+ || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
+ struct resource *res = &dev->resource[1];
+ res->start = res->end = res->flags = 0;
+ }
+}
+
+int __init
+mpc52xx_add_bridge(struct device_node *node)
+{
+ int len;
+ struct mpc52xx_pci __iomem *pci_regs;
+ struct pci_controller *hose;
+ const int *bus_range;
+ struct resource rsrc;
+
+ pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name);
+
+ pci_assign_all_buses = 1;
+
+ if (of_address_to_resource(node, 0, &rsrc) != 0) {
+ printk(KERN_ERR "Can't get %s resources\n", node->full_name);
+ return -EINVAL;
+ }
+
+ bus_range = get_property(node, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n",
+ node->full_name);
+ bus_range = NULL;
+ }
+
+ /* There are some PCI quirks on the 52xx, register the hook to
+ * fix them. */
+ ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
+
+ /* Alloc and initialize the pci controller. Values in the device
+ * tree are needed to configure the 52xx PCI controller. Rather
+ * than parse the tree here, let pci_process_bridge_OF_ranges()
+ * do it for us and extract the values after the fact */
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return -ENOMEM;
+
+ hose->arch_data = node;
+ 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->ops = &mpc52xx_pci_ops;
+
+ pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
+ if (!pci_regs)
+ return -ENOMEM;
+
+ pci_process_bridge_OF_ranges(hose, node, 1);
+
+ /* Finish setting up PCI using values obtained by
+ * pci_proces_bridge_OF_ranges */
+ mpc52xx_pci_setup(hose, pci_regs);
+
+ return 0;
+}
diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c
index 0f5b30dc60d..74e7892cdfc 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx.c
@@ -50,7 +50,7 @@
#include <sysdev/fsl_soc.h>
#include <sysdev/cpm2_pic.h>
-#include "pq2ads_pd.h"
+#include "pq2ads.h"
static int __init get_freq(char *name, unsigned long *val)
{
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
index ea880f1f0dc..7334c1a15b9 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
@@ -51,7 +51,7 @@
#include <sysdev/fsl_soc.h>
#include <../sysdev/cpm2_pic.h>
-#include "pq2ads_pd.h"
+#include "pq2ads.h"
#ifdef CONFIG_PCI
static uint pci_clk_frq;
diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h
index fb2f92bcd77..5b5cca6c8c8 100644
--- a/arch/powerpc/platforms/82xx/pq2ads.h
+++ b/arch/powerpc/platforms/82xx/pq2ads.h
@@ -22,6 +22,7 @@
#ifndef __MACH_ADS8260_DEFS
#define __MACH_ADS8260_DEFS
+#include <linux/seq_file.h>
#include <asm/ppcboot.h>
/* For our show_cpuinfo hooks. */
@@ -46,12 +47,12 @@
#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 */
+#define BCSR3_FETH2_RST ((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_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)
diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/platforms/83xx/misc.c
index f0c6df61faa..f01806c940e 100644
--- a/arch/powerpc/platforms/83xx/misc.c
+++ b/arch/powerpc/platforms/83xx/misc.c
@@ -18,23 +18,36 @@
#include "mpc83xx.h"
+static __be32 __iomem *restart_reg_base;
+
+static int __init mpc83xx_restart_init(void)
+{
+ /* map reset restart_reg_baseister space */
+ restart_reg_base = ioremap(get_immrbase() + 0x900, 0xff);
+
+ return 0;
+}
+
+arch_initcall(mpc83xx_restart_init);
+
void mpc83xx_restart(char *cmd)
{
#define RST_OFFSET 0x00000900
#define RST_PROT_REG 0x00000018
#define RST_CTRL_REG 0x0000001c
- __be32 __iomem *reg;
-
- /* map reset register space */
- reg = ioremap(get_immrbase() + 0x900, 0xff);
local_irq_disable();
- /* enable software reset "RSTE" */
- out_be32(reg + (RST_PROT_REG >> 2), 0x52535445);
+ if (restart_reg_base) {
+ /* enable software reset "RSTE" */
+ out_be32(restart_reg_base + (RST_PROT_REG >> 2), 0x52535445);
+
+ /* set software hard reset */
+ out_be32(restart_reg_base + (RST_CTRL_REG >> 2), 0x2);
+ } else {
+ printk (KERN_EMERG "Error: Restart registers not mapped, spinning!\n");
+ }
- /* set software hard reset */
- out_be32(reg + (RST_CTRL_REG >> 2), 0x2);
for (;;) ;
}
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
index f58c9780b66..3ecb55f8a6e 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -25,6 +25,7 @@
#include <linux/initrd.h>
#include <asm/of_device.h>
+#include <asm/of_platform.h>
#include <asm/system.h>
#include <asm/atomic.h>
#include <asm/time.h>
@@ -103,7 +104,7 @@ static void __init mpc832x_sys_setup_arch(void)
#ifdef CONFIG_QUICC_ENGINE
qe_reset();
- if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
+ if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
par_io_init(np);
of_node_put(np);
@@ -153,7 +154,7 @@ static int __init mpc832x_declare_of_platform_devices(void)
}
device_initcall(mpc832x_declare_of_platform_devices);
-void __init mpc832x_sys_init_IRQ(void)
+static void __init mpc832x_sys_init_IRQ(void)
{
struct device_node *np;
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c
index 314c42ac604..2446dea9407 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c
@@ -81,7 +81,7 @@ static void __init mpc834x_itx_setup_arch(void)
#endif
}
-void __init mpc834x_itx_init_IRQ(void)
+static void __init mpc834x_itx_init_IRQ(void)
{
struct device_node *np;
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_sys.c
index 80b735a414d..f30393f0b83 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_sys.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_sys.c
@@ -79,7 +79,7 @@ static void __init mpc834x_sys_setup_arch(void)
#endif
}
-void __init mpc834x_sys_init_IRQ(void)
+static void __init mpc834x_sys_init_IRQ(void)
{
struct device_node *np;
diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
index 7bfd47ad723..ccce2f9f283 100644
--- a/arch/powerpc/platforms/83xx/mpc8360e_pb.c
+++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
@@ -31,6 +31,7 @@
#include <linux/initrd.h>
#include <asm/of_device.h>
+#include <asm/of_platform.h>
#include <asm/system.h>
#include <asm/atomic.h>
#include <asm/time.h>
@@ -108,7 +109,7 @@ static void __init mpc8360_sys_setup_arch(void)
#ifdef CONFIG_QUICC_ENGINE
qe_reset();
- if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
+ if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
par_io_init(np);
of_node_put(np);
@@ -158,7 +159,7 @@ static int __init mpc8360_declare_of_platform_devices(void)
}
device_initcall(mpc8360_declare_of_platform_devices);
-void __init mpc8360_sys_init_IRQ(void)
+static void __init mpc8360_sys_init_IRQ(void)
{
struct device_node *np;
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index d1ecc0f9ab5..0c70944d0e3 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -8,6 +8,7 @@ choice
config MPC8641_HPCN
bool "Freescale MPC8641 HPCN"
select PPC_I8259
+ select DEFAULT_UIMAGE
help
This option enables support for the MPC8641 HPCN board.
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
index bb7fb41933a..7ef0c685479 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
@@ -65,7 +65,6 @@ smp_86xx_kick_cpu(int nr)
pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr);
local_irq_save(flags);
- local_irq_disable();
/* Save reset vector */
save_vector = *vector;
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index c8c0ba3cf8e..beea6834bb7 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -1,105 +1,16 @@
+menu "Platform support"
+ depends on PPC_8xx
+
config FADS
bool
+config CPM1
+ bool
+
choice
prompt "8xx Machine Type"
depends on 8xx
- default RPXLITE
-
-config RPXLITE
- bool "RPX-Lite"
- ---help---
- Single-board computers based around the PowerPC MPC8xx chips and
- intended for embedded applications. The following types are
- supported:
-
- RPX-Lite:
- Embedded Planet RPX Lite. PC104 form-factor SBC based on the MPC823.
-
- RPX-Classic:
- Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on
- the MPC 860
-
- BSE-IP:
- Bright Star Engineering ip-Engine.
-
- TQM823L:
- TQM850L:
- TQM855L:
- TQM860L:
- MPC8xx based family of mini modules, half credit card size,
- up to 64 MB of RAM, 8 MB Flash, (Fast) Ethernet, 2 x serial ports,
- 2 x CAN bus interface, ...
- Manufacturer: TQ Components, www.tq-group.de
- Date of Release: October (?) 1999
- End of Life: not yet :-)
- URL:
- - module: <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>
- - starter kit: <http://www.denx.de/PDF/STK8xxLHWM201.pdf>
- - images: <http://www.denx.de/embedded-ppc-en.html>
-
- FPS850L:
- FingerPrint Sensor System (based on TQM850L)
- Manufacturer: IKENDI AG, <http://www.ikendi.com/>
- Date of Release: November 1999
- End of life: end 2000 ?
- URL: see TQM850L
-
- IVMS8:
- MPC860 based board used in the "Integrated Voice Mail System",
- Small Version (8 voice channels)
- Manufacturer: Speech Design, <http://www.speech-design.de/>
- Date of Release: December 2000 (?)
- End of life: -
- URL: <http://www.speech-design.de/>
-
- IVML24:
- MPC860 based board used in the "Integrated Voice Mail System",
- Large Version (24 voice channels)
- Manufacturer: Speech Design, <http://www.speech-design.de/>
- Date of Release: March 2001 (?)
- End of life: -
- URL: <http://www.speech-design.de/>
-
- HERMES:
- Hermes-Pro ISDN/LAN router with integrated 8 x hub
- Manufacturer: Multidata Gesellschaft fur Datentechnik und Informatik
- <http://www.multidata.de/>
- Date of Release: 2000 (?)
- End of life: -
- URL: <http://www.multidata.de/english/products/hpro.htm>
-
- IP860:
- VMEBus IP (Industry Pack) carrier board with MPC860
- Manufacturer: MicroSys GmbH, <http://www.microsys.de/>
- Date of Release: ?
- End of life: -
- URL: <http://www.microsys.de/html/ip860.html>
-
- PCU_E:
- PCU = Peripheral Controller Unit, Extended
- Manufacturer: Siemens AG, ICN (Information and Communication Networks)
- <http://www.siemens.de/page/1,3771,224315-1-999_2_226207-0,00.html>
- Date of Release: April 2001
- End of life: August 2001
- URL: n. a.
-
-config RPXCLASSIC
- bool "RPX-Classic"
- help
- The RPX-Classic is a single-board computer based on the Motorola
- MPC860. It features 16MB of DRAM and a variable amount of flash,
- I2C EEPROM, thermal monitoring, a PCMCIA slot, a DIP switch and two
- LEDs. Variants with Ethernet ports exist. Say Y here to support it
- directly.
-
-config BSEIP
- bool "BSE-IP"
- help
- Say Y here to support the Bright Star Engineering ipEngine SBC.
- This is a credit-card-sized device featuring a MPC823 processor,
- 26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video
- controller, and two RS232 ports.
+ default MPC885ADS
config MPC8XXFADS
bool "FADS"
@@ -107,110 +18,58 @@ config MPC8XXFADS
config MPC86XADS
bool "MPC86XADS"
+ select CPM1
help
MPC86x Application Development System by Freescale Semiconductor.
The MPC86xADS is meant to serve as a platform for s/w and h/w
development around the MPC86X processor families.
- select FADS
config MPC885ADS
bool "MPC885ADS"
+ select CPM1
help
Freescale Semiconductor MPC885 Application Development System (ADS).
Also known as DUET.
The MPC885ADS is meant to serve as a platform for s/w and h/w
development around the MPC885 processor family.
-config TQM823L
- bool "TQM823L"
- help
- Say Y here to support the TQM823L, one of an MPC8xx-based family of
- mini SBCs (half credit-card size) from TQ Components first released
- in late 1999. Technical references are at
- <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
- <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
- <http://www.denx.de/embedded-ppc-en.html>.
-
-config TQM850L
- bool "TQM850L"
- help
- Say Y here to support the TQM850L, one of an MPC8xx-based family of
- mini SBCs (half credit-card size) from TQ Components first released
- in late 1999. Technical references are at
- <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
- <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
- <http://www.denx.de/embedded-ppc-en.html>.
-
-config TQM855L
- bool "TQM855L"
- help
- Say Y here to support the TQM855L, one of an MPC8xx-based family of
- mini SBCs (half credit-card size) from TQ Components first released
- in late 1999. Technical references are at
- <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
- <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
- <http://www.denx.de/embedded-ppc-en.html>.
-
-config TQM860L
- bool "TQM860L"
- help
- Say Y here to support the TQM860L, one of an MPC8xx-based family of
- mini SBCs (half credit-card size) from TQ Components first released
- in late 1999. Technical references are at
- <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
- <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
- <http://www.denx.de/embedded-ppc-en.html>.
-
-config FPS850L
- bool "FPS850L"
-
-config IVMS8
- bool "IVMS8"
- help
- Say Y here to support the Integrated Voice-Mail Small 8-channel SBC
- from Speech Design, released March 2001. The manufacturer's website
- is at <http://www.speech-design.de/>.
-
-config IVML24
- bool "IVML24"
- help
- Say Y here to support the Integrated Voice-Mail Large 24-channel SBC
- from Speech Design, released March 2001. The manufacturer's website
- is at <http://www.speech-design.de/>.
-
-config HERMES_PRO
- bool "HERMES"
-
-config IP860
- bool "IP860"
-
-config LWMON
- bool "LWMON"
-
-config PCU_E
- bool "PCU_E"
-
-config CCM
- bool "CCM"
-
-config LANTEC
- bool "LANTEC"
+endchoice
-config MBX
- bool "MBX"
- help
- MBX is a line of Motorola single-board computer based around the
- MPC821 and MPC860 processors, and intended for embedded-controller
- applications. Say Y here to support these boards directly.
+menu "Freescale Ethernet driver platform-specific options"
+ depends on (FS_ENET && MPC885ADS)
+
+ config MPC8xx_SECOND_ETH
+ bool "Second Ethernet channel"
+ depends on MPC885ADS
+ default y
+ help
+ This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
+ The latter will use SCC1, for 885ADS you can select it below.
+
+ choice
+ prompt "Second Ethernet channel"
+ depends on MPC8xx_SECOND_ETH
+ default MPC8xx_SECOND_ETH_FEC2
+
+ config MPC8xx_SECOND_ETH_FEC2
+ bool "FEC2"
+ depends on MPC885ADS
+ help
+ Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
+ (often 2-nd UART) will not work if this is enabled.
+
+ config MPC8xx_SECOND_ETH_SCC3
+ bool "SCC3"
+ depends on MPC885ADS
+ help
+ Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
+ (often 1-nd UART) will not work if this is enabled.
+
+ endchoice
-config WINCEPT
- bool "WinCept"
- help
- The Wincept 100/110 is a Motorola single-board computer based on the
- MPC821 PowerPC, introduced in 1998 and designed to be used in
- thin-client machines. Say Y to support it directly.
+endmenu
-endchoice
+endmenu
#
# MPC8xx Communication options
@@ -219,79 +78,6 @@ endchoice
menu "MPC8xx CPM Options"
depends on 8xx
-config SCC_ENET
- bool "CPM SCC Ethernet"
- depends on NET_ETHERNET
- help
- Enable Ethernet support via the Motorola MPC8xx serial
- communications controller.
-
-choice
- prompt "SCC used for Ethernet"
- depends on SCC_ENET
- default SCC1_ENET
-
-config SCC1_ENET
- bool "SCC1"
- help
- Use MPC8xx serial communications controller 1 to drive Ethernet
- (default).
-
-config SCC2_ENET
- bool "SCC2"
- help
- Use MPC8xx serial communications controller 2 to drive Ethernet.
-
-config SCC3_ENET
- bool "SCC3"
- help
- Use MPC8xx serial communications controller 3 to drive Ethernet.
-
-endchoice
-
-config FEC_ENET
- bool "860T FEC Ethernet"
- depends on NET_ETHERNET
- help
- Enable Ethernet support via the Fast Ethernet Controller (FCC) on
- the Motorola MPC8260.
-
-config USE_MDIO
- bool "Use MDIO for PHY configuration"
- depends on FEC_ENET
- help
- On some boards the hardware configuration of the ethernet PHY can be
- used without any software interaction over the MDIO interface, so
- all MII code can be omitted. Say N here if unsure or if you don't
- need link status reports.
-
-config FEC_AM79C874
- bool "Support AMD79C874 PHY"
- depends on USE_MDIO
-
-config FEC_LXT970
- bool "Support LXT970 PHY"
- depends on USE_MDIO
-
-config FEC_LXT971
- bool "Support LXT971 PHY"
- depends on USE_MDIO
-
-config FEC_QS6612
- bool "Support QS6612 PHY"
- depends on USE_MDIO
-
-config ENET_BIG_BUFFERS
- bool "Use Big CPM Ethernet Buffers"
- depends on SCC_ENET || FEC_ENET
- help
- Allocate large buffers for MPC8xx Ethernet. Increases throughput
- and decreases the likelihood of dropped packets, but costs memory.
-
-config HTDMSOUND
- bool "Embedded Planet HIOX Audio"
- depends on SOUND=y
-
# This doesn't really belong here, but it is convenient to ask
# 8xx specific questions.
comment "Generic MPC8xx Options"
diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile
new file mode 100644
index 00000000000..5e2dae3afd2
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the PowerPC 8xx linux kernel.
+#
+obj-$(CONFIG_PPC_8xx) += m8xx_setup.o
+obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o
+obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
new file mode 100644
index 00000000000..9ed7125f015
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
+ * Further modified for generic 8xx by Dan.
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/initrd.h>
+#include <linux/ioport.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+
+#include <asm/mmu.h>
+#include <asm/reg.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include <asm/machdep.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+#include <asm/prom.h>
+#include <asm/fs_pd.h>
+#include <mm/mmu_decl.h>
+
+#include "sysdev/mpc8xx_pic.h"
+
+void m8xx_calibrate_decr(void);
+extern void m8xx_wdt_handler_install(bd_t *bp);
+extern int cpm_pic_init(void);
+extern int cpm_get_irq(void);
+
+/* A place holder for time base interrupts, if they are ever enabled. */
+irqreturn_t timebase_interrupt(int irq, void * dev)
+{
+ printk ("timebase_interrupt()\n");
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction tbint_irqaction = {
+ .handler = timebase_interrupt,
+ .mask = CPU_MASK_NONE,
+ .name = "tbint",
+};
+
+/* per-board overridable init_internal_rtc() function. */
+void __init __attribute__ ((weak))
+init_internal_rtc(void)
+{
+ sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit);
+
+ /* Disable the RTC one second and alarm interrupts. */
+ clrbits16(&sys_tmr->sit_rtcsc, (RTCSC_SIE | RTCSC_ALE));
+
+ /* Enable the RTC */
+ setbits16(&sys_tmr->sit_rtcsc, (RTCSC_RTF | RTCSC_RTE));
+ immr_unmap(sys_tmr);
+}
+
+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;
+}
+
+/* The decrementer counts at the system (internal) clock frequency divided by
+ * sixteen, or external oscillator divided by four. We force the processor
+ * to use system clock divided by sixteen.
+ */
+void __init mpc8xx_calibrate_decr(void)
+{
+ struct device_node *cpu;
+ cark8xx_t *clk_r1;
+ car8xx_t *clk_r2;
+ sitk8xx_t *sys_tmr1;
+ sit8xx_t *sys_tmr2;
+ int irq, virq;
+
+ clk_r1 = (cark8xx_t *) immr_map(im_clkrstk);
+
+ /* Unlock the SCCR. */
+ out_be32(&clk_r1->cark_sccrk, ~KAPWR_KEY);
+ out_be32(&clk_r1->cark_sccrk, KAPWR_KEY);
+ immr_unmap(clk_r1);
+
+ /* Force all 8xx processors to use divide by 16 processor clock. */
+ clk_r2 = (car8xx_t *) immr_map(im_clkrst);
+ setbits32(&clk_r2->car_sccr, 0x02000000);
+ immr_unmap(clk_r2);
+
+ /* Processor frequency is MHz.
+ */
+ ppc_tb_freq = 50000000;
+ if (!get_freq("bus-frequency", &ppc_tb_freq)) {
+ printk(KERN_ERR "WARNING: Estimating decrementer frequency "
+ "(not found)\n");
+ }
+ ppc_tb_freq /= 16;
+ ppc_proc_freq = 50000000;
+ if (!get_freq("clock-frequency", &ppc_proc_freq))
+ printk(KERN_ERR "WARNING: Estimating processor frequency"
+ "(not found)\n");
+
+ printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq);
+
+ /* Perform some more timer/timebase initialization. This used
+ * to be done elsewhere, but other changes caused it to get
+ * called more than once....that is a bad thing.
+ *
+ * First, unlock all of the registers we are going to modify.
+ * To protect them from corruption during power down, registers
+ * that are maintained by keep alive power are "locked". To
+ * modify these registers we have to write the key value to
+ * the key location associated with the register.
+ * Some boards power up with these unlocked, while others
+ * are locked. Writing anything (including the unlock code?)
+ * to the unlocked registers will lock them again. So, here
+ * we guarantee the registers are locked, then we unlock them
+ * for our use.
+ */
+ sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk);
+ out_be32(&sys_tmr1->sitk_tbscrk, ~KAPWR_KEY);
+ out_be32(&sys_tmr1->sitk_rtcsck, ~KAPWR_KEY);
+ out_be32(&sys_tmr1->sitk_tbk, ~KAPWR_KEY);
+ out_be32(&sys_tmr1->sitk_tbscrk, KAPWR_KEY);
+ out_be32(&sys_tmr1->sitk_rtcsck, KAPWR_KEY);
+ out_be32(&sys_tmr1->sitk_tbk, KAPWR_KEY);
+ immr_unmap(sys_tmr1);
+
+ init_internal_rtc();
+
+ /* Enabling the decrementer also enables the timebase interrupts
+ * (or from the other point of view, to get decrementer interrupts
+ * we have to enable the timebase). The decrementer interrupt
+ * is wired into the vector table, nothing to do here for that.
+ */
+ cpu = of_find_node_by_type(NULL, "cpu");
+ virq= irq_of_parse_and_map(cpu, 0);
+ irq = irq_map[virq].hwirq;
+
+ sys_tmr2 = (sit8xx_t *) immr_map(im_sit);
+ out_be16(&sys_tmr2->sit_tbscr, ((1 << (7 - (irq/2))) << 8) |
+ (TBSCR_TBF | TBSCR_TBE));
+ immr_unmap(sys_tmr2);
+
+ if (setup_irq(virq, &tbint_irqaction))
+ panic("Could not allocate timer IRQ!");
+
+#ifdef CONFIG_8xx_WDT
+ /* Install watchdog timer handler early because it might be
+ * already enabled by the bootloader
+ */
+ m8xx_wdt_handler_install(binfo);
+#endif
+}
+
+/* The RTC on the MPC8xx is an internal register.
+ * We want to protect this during power down, so we need to unlock,
+ * modify, and re-lock.
+ */
+
+int mpc8xx_set_rtc_time(struct rtc_time *tm)
+{
+ sitk8xx_t *sys_tmr1;
+ sit8xx_t *sys_tmr2;
+ int time;
+
+ sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk);
+ sys_tmr2 = (sit8xx_t *) immr_map(im_sit);
+ time = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ out_be32(&sys_tmr1->sitk_rtck, KAPWR_KEY);
+ out_be32(&sys_tmr2->sit_rtc, time);
+ out_be32(&sys_tmr1->sitk_rtck, ~KAPWR_KEY);
+
+ immr_unmap(sys_tmr2);
+ immr_unmap(sys_tmr1);
+ return 0;
+}
+
+void mpc8xx_get_rtc_time(struct rtc_time *tm)
+{
+ unsigned long data;
+ sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit);
+
+ /* Get time from the RTC. */
+ data = in_be32(&sys_tmr->sit_rtc);
+ to_tm(data, tm);
+ tm->tm_year -= 1900;
+ tm->tm_mon -= 1;
+ immr_unmap(sys_tmr);
+ return;
+}
+
+void mpc8xx_restart(char *cmd)
+{
+ __volatile__ unsigned char dummy;
+ car8xx_t * clk_r = (car8xx_t *) immr_map(im_clkrst);
+
+
+ local_irq_disable();
+
+ setbits32(&clk_r->car_plprcr, 0x00000080);
+ /* Clear the ME bit in MSR to cause checkstop on machine check
+ */
+ mtmsr(mfmsr() & ~0x1000);
+
+ dummy = in_8(&clk_r->res[0]);
+ printk("Restart failed\n");
+ while(1);
+}
+
+void mpc8xx_show_cpuinfo(struct seq_file *m)
+{
+ struct device_node *root;
+ uint memsize = total_memory;
+ const char *model = "";
+
+ seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+
+ root = of_find_node_by_path("/");
+ if (root)
+ model = get_property(root, "model", NULL);
+ seq_printf(m, "Machine\t\t: %s\n", model);
+ of_node_put(root);
+
+ seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+}
+
+static void cpm_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ int cascade_irq;
+
+ if ((cascade_irq = cpm_get_irq()) >= 0) {
+ struct irq_desc *cdesc = irq_desc + cascade_irq;
+
+ generic_handle_irq(cascade_irq);
+ cdesc->chip->eoi(cascade_irq);
+ }
+ desc->chip->eoi(irq);
+}
+
+/* Initialize the internal interrupt controller. The number of
+ * interrupts supported can vary with the processor type, and the
+ * 82xx family can have up to 64.
+ * External interrupts can be either edge or level triggered, and
+ * need to be initialized by the appropriate driver.
+ */
+void __init m8xx_pic_init(void)
+{
+ int irq;
+
+ if (mpc8xx_pic_init()) {
+ printk(KERN_ERR "Failed interrupt 8xx controller initialization\n");
+ return;
+ }
+
+ irq = cpm_pic_init();
+ if (irq != NO_IRQ)
+ set_irq_chained_handler(irq, cpm_cascade);
+}
diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h
new file mode 100644
index 00000000000..b5d19dd0619
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc86xads.h
@@ -0,0 +1,95 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Freescale MPC86xADS board.
+ * Copied from the FADS stuff.
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 2005 (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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_MPC86XADS_H__
+#define __ASM_MPC86XADS_H__
+
+#include <asm/ppcboot.h>
+#include <sysdev/fsl_soc.h>
+
+/* U-Boot maps BCSR to 0xff080000 */
+#define BCSR_ADDR ((uint)0xff080000)
+#define BCSR_SIZE ((uint)32)
+#define BCSR0 ((uint)(BCSR_ADDR + 0x00))
+#define BCSR1 ((uint)(BCSR_ADDR + 0x04))
+#define BCSR2 ((uint)(BCSR_ADDR + 0x08))
+#define BCSR3 ((uint)(BCSR_ADDR + 0x0c))
+#define BCSR4 ((uint)(BCSR_ADDR + 0x10))
+
+#define CFG_PHYDEV_ADDR ((uint)0xff0a0000)
+#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300))
+
+#define IMAP_ADDR (get_immrbase())
+#define IMAP_SIZE ((uint)(64 * 1024))
+
+#define MPC8xx_CPM_OFFSET (0x9c0)
+#define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET)
+#define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver
+
+#define PCMCIA_MEM_ADDR (uint)0xff020000)
+#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
+
+/* Bits of interest in the BCSRs.
+ */
+#define BCSR1_ETHEN ((uint)0x20000000)
+#define BCSR1_IRDAEN ((uint)0x10000000)
+#define BCSR1_RS232EN_1 ((uint)0x01000000)
+#define BCSR1_PCCEN ((uint)0x00800000)
+#define BCSR1_PCCVCC0 ((uint)0x00400000)
+#define BCSR1_PCCVPP0 ((uint)0x00200000)
+#define BCSR1_PCCVPP1 ((uint)0x00100000)
+#define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1)
+#define BCSR1_RS232EN_2 ((uint)0x00040000)
+#define BCSR1_PCCVCC1 ((uint)0x00010000)
+#define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1)
+
+#define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/
+#define BCSR4_USB_LO_SPD ((uint)0x04000000)
+#define BCSR4_USB_VCC ((uint)0x02000000)
+#define BCSR4_USB_FULL_SPD ((uint)0x00040000)
+#define BCSR4_USB_EN ((uint)0x00020000)
+
+#define BCSR5_MII2_EN 0x40
+#define BCSR5_MII2_RST 0x20
+#define BCSR5_T1_RST 0x10
+#define BCSR5_ATM155_RST 0x08
+#define BCSR5_ATM25_RST 0x04
+#define BCSR5_MII1_EN 0x02
+#define BCSR5_MII1_RST 0x01
+
+/* Interrupt level assignments */
+#define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */
+#define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */
+#define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */
+
+/* We don't use the 8259 */
+#define NR_8259_INTS 0
+
+/* CPM Ethernet through SCC1 */
+#define PA_ENET_RXD ((ushort)0x0001)
+#define PA_ENET_TXD ((ushort)0x0002)
+#define PA_ENET_TCLK ((ushort)0x0100)
+#define PA_ENET_RCLK ((ushort)0x0200)
+#define PB_ENET_TENA ((uint)0x00001000)
+#define PC_ENET_CLSN ((ushort)0x0010)
+#define PC_ENET_RENA ((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK1) and RCLK (CLK2) to
+ * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x000000ff)
+#define SICR_ENET_CLKRT ((uint)0x0000002c)
+
+#endif /* __ASM_MPC86XADS_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
new file mode 100644
index 00000000000..ef52ce701b0
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
@@ -0,0 +1,301 @@
+/*arch/ppc/platforms/mpc86xads-setup.c
+ *
+ * Platform setup for the Freescale mpc86xads board
+ *
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright 2005 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/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/root_dev.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/fs_uart_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/fs_pd.h>
+#include <asm/prom.h>
+
+extern void cpm_reset(void);
+extern void mpc8xx_show_cpuinfo(struct seq_file*);
+extern void mpc8xx_restart(char *cmd);
+extern void mpc8xx_calibrate_decr(void);
+extern int mpc8xx_set_rtc_time(struct rtc_time *tm);
+extern void mpc8xx_get_rtc_time(struct rtc_time *tm);
+extern void m8xx_pic_init(void);
+extern unsigned int mpc8xx_get_irq(void);
+
+static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
+static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
+static void init_scc1_ioports(struct fs_platform_info* ptr);
+
+void __init mpc86xads_board_setup(void)
+{
+ cpm8xx_t *cp;
+ unsigned int *bcsr_io;
+ u8 tmpval8;
+
+ bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+ cp = (cpm8xx_t *)immr_map(im_cpm);
+
+ if (bcsr_io == NULL) {
+ printk(KERN_CRIT "Could not remap BCSR\n");
+ return;
+ }
+#ifdef CONFIG_SERIAL_CPM_SMC1
+ clrbits32(bcsr_io, BCSR1_RS232EN_1);
+ clrbits32(&cp->cp_simode, 0xe0000000 >> 17); /* brg1 */
+ tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX);
+ out_8(&(cp->cp_smc[0].smc_smcm), tmpval8);
+ clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN);
+#else
+ setbits32(bcsr_io,BCSR1_RS232EN_1);
+ out_be16(&cp->cp_smc[0].smc_smcmr, 0);
+ out_8(&cp->cp_smc[0].smc_smce, 0);
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+ clrbits32(bcsr_io,BCSR1_RS232EN_2);
+ clrbits32(&cp->cp_simode, 0xe0000000 >> 1);
+ setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */
+ tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX);
+ out_8(&(cp->cp_smc[1].smc_smcm), tmpval8);
+ clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN);
+
+ init_smc2_uart_ioports(0);
+#else
+ setbits32(bcsr_io,BCSR1_RS232EN_2);
+ out_be16(&cp->cp_smc[1].smc_smcmr, 0);
+ out_8(&cp->cp_smc[1].smc_smce, 0);
+#endif
+ immr_unmap(cp);
+ iounmap(bcsr_io);
+}
+
+
+static void init_fec1_ioports(struct fs_platform_info* ptr)
+{
+ iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport);
+
+ /* configure FEC1 pins */
+
+ setbits16(&io_port->iop_pdpar, 0x1fff);
+ setbits16(&io_port->iop_pddir, 0x1fff);
+
+ immr_unmap(io_port);
+}
+
+void init_fec_ioports(struct fs_platform_info *fpi)
+{
+ int fec_no = fs_get_fec_index(fpi->fs_no);
+
+ switch (fec_no) {
+ case 0:
+ init_fec1_ioports(fpi);
+ break;
+ default:
+ printk(KERN_ERR "init_fec_ioports: invalid FEC number\n");
+ return;
+ }
+}
+
+static void init_scc1_ioports(struct fs_platform_info* fpi)
+{
+ unsigned *bcsr_io;
+ iop8xx_t *io_port;
+ cpm8xx_t *cp;
+
+ bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE);
+ io_port = (iop8xx_t *)immr_map(im_ioport);
+ cp = (cpm8xx_t *)immr_map(im_cpm);
+
+ if (bcsr_io == NULL) {
+ printk(KERN_CRIT "Could not remap BCSR\n");
+ return;
+ }
+
+ /* Configure port A pins for Txd and Rxd.
+ */
+ setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD);
+ clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD);
+ clrbits16(&io_port->iop_paodr, PA_ENET_TXD);
+
+ /* Configure port C pins to enable CLSN and RENA.
+ */
+ clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
+ clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
+ setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
+
+ /* Configure port A for TCLK and RCLK.
+ */
+ setbits16(&io_port->iop_papar, PA_ENET_TCLK | PA_ENET_RCLK);
+ clrbits16(&io_port->iop_padir, PA_ENET_TCLK | PA_ENET_RCLK);
+ clrbits32(&cp->cp_pbpar, PB_ENET_TENA);
+ clrbits32(&cp->cp_pbdir, PB_ENET_TENA);
+
+ /* Configure Serial Interface clock routing.
+ * First, clear all SCC bits to zero, then set the ones we want.
+ */
+ clrbits32(&cp->cp_sicr, SICR_ENET_MASK);
+ setbits32(&cp->cp_sicr, SICR_ENET_CLKRT);
+
+ /* In the original SCC enet driver the following code is placed at
+ the end of the initialization */
+ setbits32(&cp->cp_pbpar, PB_ENET_TENA);
+ setbits32(&cp->cp_pbdir, PB_ENET_TENA);
+
+ clrbits32(bcsr_io+1, BCSR1_ETHEN);
+ iounmap(bcsr_io);
+ immr_unmap(cp);
+ immr_unmap(io_port);
+}
+
+void init_scc_ioports(struct fs_platform_info *fpi)
+{
+ int scc_no = fs_get_scc_index(fpi->fs_no);
+
+ switch (scc_no) {
+ case 0:
+ init_scc1_ioports(fpi);
+ break;
+ default:
+ printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
+ return;
+ }
+}
+
+
+
+static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr)
+{
+ unsigned *bcsr_io;
+ cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
+
+ setbits32(&cp->cp_pbpar, 0x000000c0);
+ clrbits32(&cp->cp_pbdir, 0x000000c0);
+ clrbits16(&cp->cp_pbodr, 0x00c0);
+ immr_unmap(cp);
+
+ bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+ if (bcsr_io == NULL) {
+ printk(KERN_CRIT "Could not remap BCSR1\n");
+ return;
+ }
+ clrbits32(bcsr_io,BCSR1_RS232EN_1);
+ iounmap(bcsr_io);
+}
+
+static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi)
+{
+ unsigned *bcsr_io;
+ cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
+
+ setbits32(&cp->cp_pbpar, 0x00000c00);
+ clrbits32(&cp->cp_pbdir, 0x00000c00);
+ clrbits16(&cp->cp_pbodr, 0x0c00);
+ immr_unmap(cp);
+
+ bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+ if (bcsr_io == NULL) {
+ printk(KERN_CRIT "Could not remap BCSR1\n");
+ return;
+ }
+ clrbits32(bcsr_io,BCSR1_RS232EN_2);
+ iounmap(bcsr_io);
+}
+
+void init_smc_ioports(struct fs_uart_platform_info *data)
+{
+ int smc_no = fs_uart_id_fsid2smc(data->fs_no);
+
+ switch (smc_no) {
+ case 0:
+ init_smc1_uart_ioports(data);
+ data->brg = data->clk_rx;
+ break;
+ case 1:
+ init_smc2_uart_ioports(data);
+ data->brg = data->clk_rx;
+ break;
+ default:
+ printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
+ return;
+ }
+}
+
+int platform_device_skip(char *model, int id)
+{
+ return 0;
+}
+
+static void __init mpc86xads_setup_arch(void)
+{
+ struct device_node *cpu;
+
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (cpu != 0) {
+ const unsigned int *fp;
+
+ fp = get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+ loops_per_jiffy = 50000000 / HZ;
+ of_node_put(cpu);
+ }
+
+ cpm_reset();
+
+ mpc86xads_board_setup();
+
+ ROOT_DEV = Root_NFS;
+}
+
+static int __init mpc86xads_probe(void)
+{
+ char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
+ "model", NULL);
+ if (model == NULL)
+ return 0;
+ if (strcmp(model, "MPC866ADS"))
+ return 0;
+
+ return 1;
+}
+
+define_machine(mpc86x_ads) {
+ .name = "MPC86x ADS",
+ .probe = mpc86xads_probe,
+ .setup_arch = mpc86xads_setup_arch,
+ .init_IRQ = m8xx_pic_init,
+ .show_cpuinfo = mpc8xx_show_cpuinfo,
+ .get_irq = mpc8xx_get_irq,
+ .restart = mpc8xx_restart,
+ .calibrate_decr = mpc8xx_calibrate_decr,
+ .set_rtc_time = mpc8xx_set_rtc_time,
+ .get_rtc_time = mpc8xx_get_rtc_time,
+};
diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h
new file mode 100644
index 00000000000..30cbebfe84c
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc885ads.h
@@ -0,0 +1,95 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Freescale MPC885ADS board.
+ * Copied from the FADS stuff.
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 2005 (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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_MPC885ADS_H__
+#define __ASM_MPC885ADS_H__
+
+#include <asm/ppcboot.h>
+#include <sysdev/fsl_soc.h>
+
+/* U-Boot maps BCSR to 0xff080000 */
+#define BCSR_ADDR ((uint)0xff080000)
+#define BCSR_SIZE ((uint)32)
+#define BCSR0 ((uint)(BCSR_ADDR + 0x00))
+#define BCSR1 ((uint)(BCSR_ADDR + 0x04))
+#define BCSR2 ((uint)(BCSR_ADDR + 0x08))
+#define BCSR3 ((uint)(BCSR_ADDR + 0x0c))
+#define BCSR4 ((uint)(BCSR_ADDR + 0x10))
+
+#define CFG_PHYDEV_ADDR ((uint)0xff0a0000)
+#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300))
+
+#define IMAP_ADDR (get_immrbase())
+#define IMAP_SIZE ((uint)(64 * 1024))
+
+#define MPC8xx_CPM_OFFSET (0x9c0)
+#define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET)
+#define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver
+
+#define PCMCIA_MEM_ADDR (uint)0xff020000)
+#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
+
+/* Bits of interest in the BCSRs.
+ */
+#define BCSR1_ETHEN ((uint)0x20000000)
+#define BCSR1_IRDAEN ((uint)0x10000000)
+#define BCSR1_RS232EN_1 ((uint)0x01000000)
+#define BCSR1_PCCEN ((uint)0x00800000)
+#define BCSR1_PCCVCC0 ((uint)0x00400000)
+#define BCSR1_PCCVPP0 ((uint)0x00200000)
+#define BCSR1_PCCVPP1 ((uint)0x00100000)
+#define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1)
+#define BCSR1_RS232EN_2 ((uint)0x00040000)
+#define BCSR1_PCCVCC1 ((uint)0x00010000)
+#define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1)
+
+#define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/
+#define BCSR4_USB_LO_SPD ((uint)0x04000000)
+#define BCSR4_USB_VCC ((uint)0x02000000)
+#define BCSR4_USB_FULL_SPD ((uint)0x00040000)
+#define BCSR4_USB_EN ((uint)0x00020000)
+
+#define BCSR5_MII2_EN 0x40
+#define BCSR5_MII2_RST 0x20
+#define BCSR5_T1_RST 0x10
+#define BCSR5_ATM155_RST 0x08
+#define BCSR5_ATM25_RST 0x04
+#define BCSR5_MII1_EN 0x02
+#define BCSR5_MII1_RST 0x01
+
+/* Interrupt level assignments */
+#define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */
+#define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */
+#define SIU_INT_FEC2 SIU_LEVEL3 /* FEC2 interrupt */
+#define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */
+
+/* We don't use the 8259 */
+#define NR_8259_INTS 0
+
+/* CPM Ethernet through SCC3 */
+#define PA_ENET_RXD ((ushort)0x0040)
+#define PA_ENET_TXD ((ushort)0x0080)
+#define PE_ENET_TCLK ((uint)0x00004000)
+#define PE_ENET_RCLK ((uint)0x00008000)
+#define PE_ENET_TENA ((uint)0x00000010)
+#define PC_ENET_CLSN ((ushort)0x0400)
+#define PC_ENET_RENA ((ushort)0x0800)
+
+/* Control bits in the SICR to route TCLK (CLK5) and RCLK (CLK6) to
+ * SCC3. Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero */
+#define SICR_ENET_MASK ((uint)0x00ff0000)
+#define SICR_ENET_CLKRT ((uint)0x002c0000)
+
+#endif /* __ASM_MPC885ADS_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
new file mode 100644
index 00000000000..c5fefdf66c0
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -0,0 +1,387 @@
+/*arch/ppc/platforms/mpc885ads-setup.c
+ *
+ * Platform setup for the Freescale mpc885ads board
+ *
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright 2005 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/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/root_dev.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/fs_uart_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/fs_pd.h>
+#include <asm/prom.h>
+
+extern void cpm_reset(void);
+extern void mpc8xx_show_cpuinfo(struct seq_file*);
+extern void mpc8xx_restart(char *cmd);
+extern void mpc8xx_calibrate_decr(void);
+extern int mpc8xx_set_rtc_time(struct rtc_time *tm);
+extern void mpc8xx_get_rtc_time(struct rtc_time *tm);
+extern void m8xx_pic_init(void);
+extern unsigned int mpc8xx_get_irq(void);
+
+static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
+static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
+static void init_scc3_ioports(struct fs_platform_info* ptr);
+
+void __init mpc885ads_board_setup(void)
+{
+ cpm8xx_t *cp;
+ unsigned int *bcsr_io;
+ u8 tmpval8;
+
+#ifdef CONFIG_FS_ENET
+ iop8xx_t *io_port;
+#endif
+
+ bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+ cp = (cpm8xx_t *)immr_map(im_cpm);
+
+ if (bcsr_io == NULL) {
+ printk(KERN_CRIT "Could not remap BCSR\n");
+ return;
+ }
+#ifdef CONFIG_SERIAL_CPM_SMC1
+ clrbits32(bcsr_io, BCSR1_RS232EN_1);
+ clrbits32(&cp->cp_simode, 0xe0000000 >> 17); /* brg1 */
+ tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX);
+ out_8(&(cp->cp_smc[0].smc_smcm), tmpval8);
+ clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); /* brg1 */
+#else
+ setbits32(bcsr_io,BCSR1_RS232EN_1);
+ out_be16(&cp->cp_smc[0].smc_smcmr, 0);
+ out_8(&cp->cp_smc[0].smc_smce, 0);
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+ clrbits32(bcsr_io,BCSR1_RS232EN_2);
+ clrbits32(&cp->cp_simode, 0xe0000000 >> 1);
+ setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */
+ tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX);
+ out_8(&(cp->cp_smc[1].smc_smcm), tmpval8);
+ clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN);
+
+ init_smc2_uart_ioports(0);
+#else
+ setbits32(bcsr_io,BCSR1_RS232EN_2);
+ out_be16(&cp->cp_smc[1].smc_smcmr, 0);
+ out_8(&cp->cp_smc[1].smc_smce, 0);
+#endif
+ immr_unmap(cp);
+ iounmap(bcsr_io);
+
+#ifdef CONFIG_FS_ENET
+ /* use MDC for MII (common) */
+ io_port = (iop8xx_t*)immr_map(im_ioport);
+ setbits16(&io_port->iop_pdpar, 0x0080);
+ clrbits16(&io_port->iop_pddir, 0x0080);
+
+ bcsr_io = ioremap(BCSR5, sizeof(unsigned long));
+ clrbits32(bcsr_io,BCSR5_MII1_EN);
+ clrbits32(bcsr_io,BCSR5_MII1_RST);
+#ifndef CONFIG_FC_ENET_HAS_SCC
+ clrbits32(bcsr_io,BCSR5_MII2_EN);
+ clrbits32(bcsr_io,BCSR5_MII2_RST);
+
+#endif
+ iounmap(bcsr_io);
+ immr_unmap(io_port);
+
+#endif
+}
+
+
+static void init_fec1_ioports(struct fs_platform_info* ptr)
+{
+ cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
+ iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport);
+
+ /* configure FEC1 pins */
+ setbits16(&io_port->iop_papar, 0xf830);
+ setbits16(&io_port->iop_padir, 0x0830);
+ clrbits16(&io_port->iop_padir, 0xf000);
+
+ setbits32(&cp->cp_pbpar, 0x00001001);
+ clrbits32(&cp->cp_pbdir, 0x00001001);
+
+ setbits16(&io_port->iop_pcpar, 0x000c);
+ clrbits16(&io_port->iop_pcdir, 0x000c);
+
+ setbits32(&cp->cp_pepar, 0x00000003);
+ setbits32(&cp->cp_pedir, 0x00000003);
+ clrbits32(&cp->cp_peso, 0x00000003);
+ clrbits32(&cp->cp_cptr, 0x00000100);
+
+ immr_unmap(io_port);
+ immr_unmap(cp);
+}
+
+
+static void init_fec2_ioports(struct fs_platform_info* ptr)
+{
+ cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
+ iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport);
+
+ /* configure FEC2 pins */
+ setbits32(&cp->cp_pepar, 0x0003fffc);
+ setbits32(&cp->cp_pedir, 0x0003fffc);
+ clrbits32(&cp->cp_peso, 0x000087fc);
+ setbits32(&cp->cp_peso, 0x00037800);
+ clrbits32(&cp->cp_cptr, 0x00000080);
+
+ immr_unmap(io_port);
+ immr_unmap(cp);
+}
+
+void init_fec_ioports(struct fs_platform_info *fpi)
+{
+ int fec_no = fs_get_fec_index(fpi->fs_no);
+
+ switch (fec_no) {
+ case 0:
+ init_fec1_ioports(fpi);
+ break;
+ case 1:
+ init_fec2_ioports(fpi);
+ break;
+ default:
+ printk(KERN_ERR "init_fec_ioports: invalid FEC number\n");
+ return;
+ }
+}
+
+static void init_scc3_ioports(struct fs_platform_info* fpi)
+{
+ unsigned *bcsr_io;
+ iop8xx_t *io_port;
+ cpm8xx_t *cp;
+
+ bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE);
+ io_port = (iop8xx_t *)immr_map(im_ioport);
+ cp = (cpm8xx_t *)immr_map(im_cpm);
+
+ if (bcsr_io == NULL) {
+ printk(KERN_CRIT "Could not remap BCSR\n");
+ return;
+ }
+
+ /* Enable the PHY.
+ */
+ clrbits32(bcsr_io+4, BCSR4_ETH10_RST);
+ udelay(1000);
+ setbits32(bcsr_io+4, BCSR4_ETH10_RST);
+ /* Configure port A pins for Txd and Rxd.
+ */
+ setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD);
+ clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD);
+
+ /* Configure port C pins to enable CLSN and RENA.
+ */
+ clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
+ clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
+ setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
+
+ /* Configure port E for TCLK and RCLK.
+ */
+ setbits32(&cp->cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK);
+ clrbits32(&cp->cp_pepar, PE_ENET_TENA);
+ clrbits32(&cp->cp_pedir,
+ PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA);
+ clrbits32(&cp->cp_peso, PE_ENET_TCLK | PE_ENET_RCLK);
+ setbits32(&cp->cp_peso, PE_ENET_TENA);
+
+ /* Configure Serial Interface clock routing.
+ * First, clear all SCC bits to zero, then set the ones we want.
+ */
+ clrbits32(&cp->cp_sicr, SICR_ENET_MASK);
+ setbits32(&cp->cp_sicr, SICR_ENET_CLKRT);
+
+ /* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used.
+ */
+ clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN);
+ /* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex mode
+ * by H/W setting after reset. SCC ethernet controller support only half duplex.
+ * This discrepancy of modes causes a lot of carrier lost errors.
+ */
+
+ /* In the original SCC enet driver the following code is placed at
+ the end of the initialization */
+ setbits32(&cp->cp_pepar, PE_ENET_TENA);
+ clrbits32(&cp->cp_pedir, PE_ENET_TENA);
+ setbits32(&cp->cp_peso, PE_ENET_TENA);
+
+ setbits32(bcsr_io+4, BCSR1_ETHEN);
+ iounmap(bcsr_io);
+ immr_unmap(io_port);
+ immr_unmap(cp);
+}
+
+void init_scc_ioports(struct fs_platform_info *fpi)
+{
+ int scc_no = fs_get_scc_index(fpi->fs_no);
+
+ switch (scc_no) {
+ case 2:
+ init_scc3_ioports(fpi);
+ break;
+ default:
+ printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
+ return;
+ }
+}
+
+
+
+static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr)
+{
+ unsigned *bcsr_io;
+ cpm8xx_t *cp;
+
+ cp = (cpm8xx_t *)immr_map(im_cpm);
+ setbits32(&cp->cp_pepar, 0x000000c0);
+ clrbits32(&cp->cp_pedir, 0x000000c0);
+ clrbits32(&cp->cp_peso, 0x00000040);
+ setbits32(&cp->cp_peso, 0x00000080);
+ immr_unmap(cp);
+
+ bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+ if (bcsr_io == NULL) {
+ printk(KERN_CRIT "Could not remap BCSR1\n");
+ return;
+ }
+ clrbits32(bcsr_io,BCSR1_RS232EN_1);
+ iounmap(bcsr_io);
+}
+
+static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi)
+{
+ unsigned *bcsr_io;
+ cpm8xx_t *cp;
+
+ cp = (cpm8xx_t *)immr_map(im_cpm);
+ setbits32(&cp->cp_pepar, 0x00000c00);
+ clrbits32(&cp->cp_pedir, 0x00000c00);
+ clrbits32(&cp->cp_peso, 0x00000400);
+ setbits32(&cp->cp_peso, 0x00000800);
+ immr_unmap(cp);
+
+ bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+ if (bcsr_io == NULL) {
+ printk(KERN_CRIT "Could not remap BCSR1\n");
+ return;
+ }
+ clrbits32(bcsr_io,BCSR1_RS232EN_2);
+ iounmap(bcsr_io);
+}
+
+void init_smc_ioports(struct fs_uart_platform_info *data)
+{
+ int smc_no = fs_uart_id_fsid2smc(data->fs_no);
+
+ switch (smc_no) {
+ case 0:
+ init_smc1_uart_ioports(data);
+ data->brg = data->clk_rx;
+ break;
+ case 1:
+ init_smc2_uart_ioports(data);
+ data->brg = data->clk_rx;
+ break;
+ default:
+ printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
+ return;
+ }
+}
+
+int platform_device_skip(char *model, int id)
+{
+#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
+ const char *dev = "FEC";
+ int n = 2;
+#else
+ const char *dev = "SCC";
+ int n = 3;
+#endif
+
+ if (!strcmp(model, dev) && n == id)
+ return 1;
+
+ return 0;
+}
+
+static void __init mpc885ads_setup_arch(void)
+{
+ struct device_node *cpu;
+
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (cpu != 0) {
+ const unsigned int *fp;
+
+ fp = get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+ loops_per_jiffy = 50000000 / HZ;
+ of_node_put(cpu);
+ }
+
+ cpm_reset();
+
+ mpc885ads_board_setup();
+
+ ROOT_DEV = Root_NFS;
+}
+
+static int __init mpc885ads_probe(void)
+{
+ char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
+ "model", NULL);
+ if (model == NULL)
+ return 0;
+ if (strcmp(model, "MPC885ADS"))
+ return 0;
+
+ return 1;
+}
+
+define_machine(mpc885_ads) {
+ .name = "MPC885 ADS",
+ .probe = mpc885ads_probe,
+ .setup_arch = mpc885ads_setup_arch,
+ .init_IRQ = m8xx_pic_init,
+ .show_cpuinfo = mpc8xx_show_cpuinfo,
+ .get_irq = mpc8xx_get_irq,
+ .restart = mpc8xx_restart,
+ .calibrate_decr = mpc8xx_calibrate_decr,
+ .set_rtc_time = mpc8xx_set_rtc_time,
+ .get_rtc_time = mpc8xx_get_rtc_time,
+};
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index 44d95eaf22e..65e612315b9 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -5,9 +5,11 @@ ifeq ($(CONFIG_PPC64),y)
obj-$(CONFIG_PPC_PMAC) += powermac/
endif
endif
+obj-$(CONFIG_PPC_MPC52xx) += 52xx/
obj-$(CONFIG_PPC_CHRP) += chrp/
obj-$(CONFIG_4xx) += 4xx/
-obj-$(CONFIG_PPC_MPC52xx) += 52xx/
+obj-$(CONFIG_PPC_8xx) += 8xx/
+obj-$(CONFIG_PPC_82xx) += 82xx/
obj-$(CONFIG_PPC_83xx) += 83xx/
obj-$(CONFIG_PPC_85xx) += 85xx/
obj-$(CONFIG_PPC_86xx) += 86xx/
@@ -17,4 +19,5 @@ obj-$(CONFIG_PPC_MAPLE) += maple/
obj-$(CONFIG_PPC_PASEMI) += pasemi/
obj-$(CONFIG_PPC_CELL) += cell/
obj-$(CONFIG_PPC_PS3) += ps3/
+obj-$(CONFIG_PPC_CELLEB) += celleb/
obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index f90e8337796..869af89df6f 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -14,7 +14,12 @@ endif
spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o
spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o
+spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o
+spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o
+
obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \
spu_coredump.o \
$(spufs-modular-m) \
- $(spu-priv1-y) spufs/
+ $(spu-priv1-y) \
+ $(spu-manage-y) \
+ spufs/
diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c
index 616a0a3fd0e..70e0d968d30 100644
--- a/arch/powerpc/platforms/cell/cbe_thermal.c
+++ b/arch/powerpc/platforms/cell/cbe_thermal.c
@@ -115,6 +115,7 @@ static struct sysdev_attribute attr_spu_temperature = {
static struct attribute *spu_attributes[] = {
&attr_spu_temperature.attr,
+ NULL,
};
static struct attribute_group spu_attribute_group = {
@@ -135,6 +136,7 @@ static struct sysdev_attribute attr_ppe_temperature1 = {
static struct attribute *ppe_attributes[] = {
&attr_ppe_temperature0.attr,
&attr_ppe_temperature1.attr,
+ NULL,
};
static struct attribute_group ppe_attribute_group = {
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c
index 580d4259591..7c73128305e 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.c
+++ b/arch/powerpc/platforms/cell/io-workarounds.c
@@ -37,7 +37,7 @@
*/
#define SPIDER_DISABLE_PREFETCH
-#define MAX_SPIDERS 2
+#define MAX_SPIDERS 3
static struct spider_pci_bus {
void __iomem *regs;
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index b43466ba809..67d617b60a2 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -149,7 +149,8 @@ static int cbe_nr_iommus;
static void invalidate_tce_cache(struct cbe_iommu *iommu, unsigned long *pte,
long n_ptes)
{
- unsigned long *reg, val;
+ unsigned long __iomem *reg;
+ unsigned long val;
long n;
reg = iommu->xlate_regs + IOC_IOPT_CacheInvd;
@@ -592,7 +593,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off
/* Init base fields */
i = cbe_nr_iommus++;
iommu = &iommus[i];
- iommu->stab = 0;
+ iommu->stab = NULL;
iommu->nid = nid;
snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i);
INIT_LIST_HEAD(&iommu->windows);
diff --git a/arch/powerpc/platforms/cell/pmu.c b/arch/powerpc/platforms/cell/pmu.c
index 99c612025e8..d04ae1671e6 100644
--- a/arch/powerpc/platforms/cell/pmu.c
+++ b/arch/powerpc/platforms/cell/pmu.c
@@ -382,11 +382,14 @@ static irqreturn_t cbe_pm_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-int __init cbe_init_pm_irq(void)
+static int __init cbe_init_pm_irq(void)
{
unsigned int irq;
int rc, node;
+ if (!machine_is(cell))
+ return 0;
+
for_each_node(node) {
irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI |
(node << IIC_IRQ_NODE_SHIFT));
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index bd7bffc3ddd..c43999a10de 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -170,9 +170,11 @@ int
spu_irq_class_0_bottom(struct spu *spu)
{
unsigned long stat, mask;
+ unsigned long flags;
spu->class_0_pending = 0;
+ spin_lock_irqsave(&spu->register_lock, flags);
mask = spu_int_mask_get(spu, 0);
stat = spu_int_stat_get(spu, 0);
@@ -188,6 +190,7 @@ spu_irq_class_0_bottom(struct spu *spu)
__spu_trap_error(spu);
spu_int_stat_clear(spu, 0, stat);
+ spin_unlock_irqrestore(&spu->register_lock, flags);
return (stat & 0x7) ? -EIO : 0;
}
diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c
new file mode 100644
index 00000000000..d8b39fe39cd
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_manage.c
@@ -0,0 +1,420 @@
+/*
+ * spu management operations for of based platforms
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ * Copyright 2006 Sony Corp.
+ * (C) Copyright 2007 TOSHIBA 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
+#include <asm/firmware.h>
+#include <asm/prom.h>
+
+#include "interrupt.h"
+
+struct device_node *spu_devnode(struct spu *spu)
+{
+ return spu->devnode;
+}
+
+EXPORT_SYMBOL_GPL(spu_devnode);
+
+static u64 __init find_spu_unit_number(struct device_node *spe)
+{
+ const unsigned int *prop;
+ int proplen;
+ prop = get_property(spe, "unit-id", &proplen);
+ if (proplen == 4)
+ return (u64)*prop;
+
+ prop = get_property(spe, "reg", &proplen);
+ if (proplen == 4)
+ return (u64)*prop;
+
+ return 0;
+}
+
+static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
+ const char *prop)
+{
+ const struct address_prop {
+ unsigned long address;
+ unsigned int len;
+ } __attribute__((packed)) *p;
+ int proplen;
+
+ unsigned long start_pfn, nr_pages;
+ struct pglist_data *pgdata;
+ struct zone *zone;
+ int ret;
+
+ p = get_property(spe, prop, &proplen);
+ WARN_ON(proplen != sizeof (*p));
+
+ start_pfn = p->address >> PAGE_SHIFT;
+ nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ pgdata = NODE_DATA(spu->node);
+ zone = pgdata->node_zones;
+
+ ret = __add_pages(zone, start_pfn, nr_pages);
+
+ return ret;
+}
+
+static void __iomem * __init map_spe_prop(struct spu *spu,
+ struct device_node *n, const char *name)
+{
+ const struct address_prop {
+ unsigned long address;
+ unsigned int len;
+ } __attribute__((packed)) *prop;
+
+ const void *p;
+ int proplen;
+ void __iomem *ret = NULL;
+ int err = 0;
+
+ p = get_property(n, name, &proplen);
+ if (proplen != sizeof (struct address_prop))
+ return NULL;
+
+ prop = p;
+
+ err = cell_spuprop_present(spu, n, name);
+ if (err && (err != -EEXIST))
+ goto out;
+
+ ret = ioremap(prop->address, prop->len);
+
+ out:
+ return ret;
+}
+
+static void spu_unmap(struct spu *spu)
+{
+ if (!firmware_has_feature(FW_FEATURE_LPAR))
+ iounmap(spu->priv1);
+ iounmap(spu->priv2);
+ iounmap(spu->problem);
+ iounmap((__force u8 __iomem *)spu->local_store);
+}
+
+static int __init spu_map_interrupts_old(struct spu *spu,
+ struct device_node *np)
+{
+ unsigned int isrc;
+ const u32 *tmp;
+ int nid;
+
+ /* Get the interrupt source unit from the device-tree */
+ tmp = get_property(np, "isrc", NULL);
+ if (!tmp)
+ return -ENODEV;
+ isrc = tmp[0];
+
+ tmp = get_property(np->parent->parent, "node-id", NULL);
+ if (!tmp) {
+ printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__);
+ nid = spu->node;
+ } else
+ nid = tmp[0];
+
+ /* Add the node number */
+ isrc |= nid << IIC_IRQ_NODE_SHIFT;
+
+ /* Now map interrupts of all 3 classes */
+ 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_old(struct spu *spu)
+{
+ struct device_node *node = spu->devnode;
+ const char *prop;
+ int ret;
+
+ ret = -ENODEV;
+ spu->name = get_property(node, "name", NULL);
+ if (!spu->name)
+ goto out;
+
+ prop = get_property(node, "local-store", NULL);
+ if (!prop)
+ goto out;
+ spu->local_store_phys = *(unsigned long *)prop;
+
+ /* we use local store as ram, not io memory */
+ spu->local_store = (void __force *)
+ map_spe_prop(spu, node, "local-store");
+ if (!spu->local_store)
+ goto out;
+
+ prop = get_property(node, "problem", NULL);
+ if (!prop)
+ goto out_unmap;
+ spu->problem_phys = *(unsigned long *)prop;
+
+ spu->problem = map_spe_prop(spu, node, "problem");
+ if (!spu->problem)
+ goto out_unmap;
+
+ spu->priv2 = map_spe_prop(spu, node, "priv2");
+ if (!spu->priv2)
+ goto out_unmap;
+
+ if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+ spu->priv1 = map_spe_prop(spu, node, "priv1");
+ if (!spu->priv1)
+ goto out_unmap;
+ }
+
+ ret = 0;
+ goto out;
+
+out_unmap:
+ spu_unmap(spu);
+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) {
+ pr_debug("spu_new: failed to get irq %d\n", i);
+ goto err;
+ }
+ ret = -EINVAL;
+ pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0],
+ oirq.controller->full_name);
+ spu->irqs[i] = irq_create_of_mapping(oirq.controller,
+ oirq.specifier, oirq.size);
+ if (spu->irqs[i] == NO_IRQ) {
+ pr_debug("spu_new: failed to map it !\n");
+ 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 spu *spu, int nr,
+ void __iomem** virt, unsigned long *phys)
+{
+ struct device_node *np = spu->devnode;
+ unsigned long start_pfn, nr_pages;
+ struct pglist_data *pgdata;
+ struct zone *zone;
+ struct resource resource = { };
+ unsigned long len;
+ int ret;
+
+ ret = of_address_to_resource(np, nr, &resource);
+ if (ret)
+ goto out;
+
+ if (phys)
+ *phys = resource.start;
+ len = resource.end - resource.start + 1;
+ *virt = ioremap(resource.start, len);
+ if (!*virt)
+ ret = -EINVAL;
+
+ start_pfn = resource.start >> PAGE_SHIFT;
+ nr_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ pgdata = NODE_DATA(spu->node);
+ zone = pgdata->node_zones;
+
+ ret = __add_pages(zone, start_pfn, nr_pages);
+
+out:
+ return ret;
+}
+
+static int __init spu_map_device(struct spu *spu)
+{
+ struct device_node *np = spu->devnode;
+ int ret = -ENODEV;
+
+ spu->name = get_property(np, "name", NULL);
+ if (!spu->name)
+ goto out;
+
+ ret = spu_map_resource(spu, 0, (void __iomem**)&spu->local_store,
+ &spu->local_store_phys);
+ if (ret) {
+ pr_debug("spu_new: failed to map %s resource 0\n",
+ np->full_name);
+ goto out;
+ }
+ ret = spu_map_resource(spu, 1, (void __iomem**)&spu->problem,
+ &spu->problem_phys);
+ if (ret) {
+ pr_debug("spu_new: failed to map %s resource 1\n",
+ np->full_name);
+ goto out_unmap;
+ }
+ ret = spu_map_resource(spu, 2, (void __iomem**)&spu->priv2, NULL);
+ if (ret) {
+ pr_debug("spu_new: failed to map %s resource 2\n",
+ np->full_name);
+ goto out_unmap;
+ }
+ if (!firmware_has_feature(FW_FEATURE_LPAR))
+ ret = spu_map_resource(spu, 3,
+ (void __iomem**)&spu->priv1, NULL);
+ if (ret) {
+ pr_debug("spu_new: failed to map %s resource 3\n",
+ np->full_name);
+ goto out_unmap;
+ }
+ pr_debug("spu_new: %s maps:\n", np->full_name);
+ pr_debug(" local store : 0x%016lx -> 0x%p\n",
+ spu->local_store_phys, spu->local_store);
+ pr_debug(" problem state : 0x%016lx -> 0x%p\n",
+ spu->problem_phys, spu->problem);
+ pr_debug(" priv2 : 0x%p\n", spu->priv2);
+ pr_debug(" priv1 : 0x%p\n", spu->priv1);
+
+ return 0;
+
+out_unmap:
+ spu_unmap(spu);
+out:
+ pr_debug("failed to map spe %s: %d\n", spu->name, ret);
+ return ret;
+}
+
+static int __init of_enumerate_spus(int (*fn)(void *data))
+{
+ int ret;
+ struct device_node *node;
+
+ ret = -ENODEV;
+ for (node = of_find_node_by_type(NULL, "spe");
+ node; node = of_find_node_by_type(node, "spe")) {
+ ret = fn(node);
+ if (ret) {
+ printk(KERN_WARNING "%s: Error initializing %s\n",
+ __FUNCTION__, node->name);
+ break;
+ }
+ }
+ return ret;
+}
+
+static int __init of_create_spu(struct spu *spu, void *data)
+{
+ int ret;
+ struct device_node *spe = (struct device_node *)data;
+ static int legacy_map = 0, legacy_irq = 0;
+
+ spu->devnode = of_node_get(spe);
+ spu->spe_id = find_spu_unit_number(spe);
+
+ spu->node = of_node_to_nid(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");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ret = spu_map_device(spu);
+ if (ret) {
+ if (!legacy_map) {
+ legacy_map = 1;
+ printk(KERN_WARNING "%s: Legacy device tree found, "
+ "trying to map old style\n", __FUNCTION__);
+ }
+ ret = spu_map_device_old(spu);
+ if (ret) {
+ printk(KERN_ERR "Unable to map %s\n",
+ spu->name);
+ goto out;
+ }
+ }
+
+ ret = spu_map_interrupts(spu, spe);
+ if (ret) {
+ if (!legacy_irq) {
+ legacy_irq = 1;
+ printk(KERN_WARNING "%s: Legacy device tree found, "
+ "trying old style irq\n", __FUNCTION__);
+ }
+ ret = spu_map_interrupts_old(spu, spe);
+ if (ret) {
+ printk(KERN_ERR "%s: could not map interrupts",
+ spu->name);
+ goto out_unmap;
+ }
+ }
+
+ pr_debug("Using SPE %s %p %p %p %p %d\n", spu->name,
+ spu->local_store, spu->problem, spu->priv1,
+ spu->priv2, spu->number);
+ goto out;
+
+out_unmap:
+ spu_unmap(spu);
+out:
+ return ret;
+}
+
+static int of_destroy_spu(struct spu *spu)
+{
+ spu_unmap(spu);
+ of_node_put(spu->devnode);
+ return 0;
+}
+
+const struct spu_management_ops spu_management_of_ops = {
+ .enumerate_spus = of_enumerate_spus,
+ .create_spu = of_create_spu,
+ .destroy_spu = of_destroy_spu,
+};
diff --git a/arch/powerpc/platforms/cell/spu_priv1_mmio.c b/arch/powerpc/platforms/cell/spu_priv1_mmio.c
index a5de0430c56..67fa7247b80 100644
--- a/arch/powerpc/platforms/cell/spu_priv1_mmio.c
+++ b/arch/powerpc/platforms/cell/spu_priv1_mmio.c
@@ -37,479 +37,112 @@
#include "interrupt.h"
#include "spu_priv1_mmio.h"
-struct spu_pdata {
- int nid;
- struct device_node *devnode;
- struct spu_priv1 __iomem *priv1;
-};
-
-static struct spu_pdata *spu_get_pdata(struct spu *spu)
-{
- BUG_ON(!spu->pdata);
- return spu->pdata;
-}
-
-struct device_node *spu_devnode(struct spu *spu)
-{
- return spu_get_pdata(spu)->devnode;
-}
-
-EXPORT_SYMBOL_GPL(spu_devnode);
-
-static int __init find_spu_node_id(struct device_node *spe)
-{
- const unsigned int *id;
- struct device_node *cpu;
- cpu = spe->parent->parent;
- id = get_property(cpu, "node-id", NULL);
- return id ? *id : 0;
-}
-
-static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
- const char *prop)
-{
- static DEFINE_MUTEX(add_spumem_mutex);
-
- const struct address_prop {
- unsigned long address;
- unsigned int len;
- } __attribute__((packed)) *p;
- int proplen;
-
- unsigned long start_pfn, nr_pages;
- struct pglist_data *pgdata;
- struct zone *zone;
- int ret;
-
- p = get_property(spe, prop, &proplen);
- WARN_ON(proplen != sizeof (*p));
-
- start_pfn = p->address >> PAGE_SHIFT;
- nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
- pgdata = NODE_DATA(spu_get_pdata(spu)->nid);
- zone = pgdata->node_zones;
-
- /* XXX rethink locking here */
- mutex_lock(&add_spumem_mutex);
- ret = __add_pages(zone, start_pfn, nr_pages);
- mutex_unlock(&add_spumem_mutex);
-
- return ret;
-}
-
-static void __iomem * __init map_spe_prop(struct spu *spu,
- struct device_node *n, const char *name)
-{
- const struct address_prop {
- unsigned long address;
- unsigned int len;
- } __attribute__((packed)) *prop;
-
- const void *p;
- int proplen;
- void __iomem *ret = NULL;
- int err = 0;
-
- p = get_property(n, name, &proplen);
- if (proplen != sizeof (struct address_prop))
- return NULL;
-
- prop = p;
-
- err = cell_spuprop_present(spu, n, name);
- if (err && (err != -EEXIST))
- goto out;
-
- ret = ioremap(prop->address, prop->len);
-
- out:
- return ret;
-}
-
-static void spu_unmap(struct spu *spu)
-{
- iounmap(spu->priv2);
- iounmap(spu_get_pdata(spu)->priv1);
- iounmap(spu->problem);
- iounmap((__force u8 __iomem *)spu->local_store);
-}
-
-static int __init spu_map_interrupts_old(struct spu *spu,
- struct device_node *np)
-{
- unsigned int isrc;
- const u32 *tmp;
-
- /* Get the interrupt source unit from the device-tree */
- tmp = get_property(np, "isrc", NULL);
- if (!tmp)
- return -ENODEV;
- isrc = tmp[0];
-
- /* Add the node number */
- isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
-
- /* Now map interrupts of all 3 classes */
- 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_old(struct spu *spu, struct device_node *node)
-{
- const char *prop;
- int ret;
-
- ret = -ENODEV;
- spu->name = get_property(node, "name", NULL);
- if (!spu->name)
- goto out;
-
- prop = get_property(node, "local-store", NULL);
- if (!prop)
- goto out;
- spu->local_store_phys = *(unsigned long *)prop;
-
- /* we use local store as ram, not io memory */
- spu->local_store = (void __force *)
- map_spe_prop(spu, node, "local-store");
- if (!spu->local_store)
- goto out;
-
- prop = get_property(node, "problem", NULL);
- if (!prop)
- goto out_unmap;
- spu->problem_phys = *(unsigned long *)prop;
-
- spu->problem= map_spe_prop(spu, node, "problem");
- if (!spu->problem)
- goto out_unmap;
-
- spu_get_pdata(spu)->priv1= map_spe_prop(spu, node, "priv1");
-
- spu->priv2= map_spe_prop(spu, node, "priv2");
- if (!spu->priv2)
- goto out_unmap;
- ret = 0;
- goto out;
-
-out_unmap:
- spu_unmap(spu);
-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) {
- pr_debug("spu_new: failed to get irq %d\n", i);
- goto err;
- }
- ret = -EINVAL;
- pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0],
- oirq.controller->full_name);
- spu->irqs[i] = irq_create_of_mapping(oirq.controller,
- oirq.specifier, oirq.size);
- if (spu->irqs[i] == NO_IRQ) {
- pr_debug("spu_new: failed to map it !\n");
- 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, nr, &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) {
- pr_debug("spu_new: failed to map %s resource 0\n",
- node->full_name);
- goto out;
- }
- ret = spu_map_resource(node, 1, (void __iomem**)&spu->problem,
- &spu->problem_phys);
- if (ret) {
- pr_debug("spu_new: failed to map %s resource 1\n",
- node->full_name);
- goto out_unmap;
- }
- ret = spu_map_resource(node, 2, (void __iomem**)&spu->priv2,
- NULL);
- if (ret) {
- pr_debug("spu_new: failed to map %s resource 2\n",
- node->full_name);
- goto out_unmap;
- }
- if (!firmware_has_feature(FW_FEATURE_LPAR))
- ret = spu_map_resource(node, 3,
- (void __iomem**)&spu_get_pdata(spu)->priv1, NULL);
- if (ret) {
- pr_debug("spu_new: failed to map %s resource 3\n",
- node->full_name);
- goto out_unmap;
- }
- pr_debug("spu_new: %s maps:\n", node->full_name);
- pr_debug(" local store : 0x%016lx -> 0x%p\n",
- spu->local_store_phys, spu->local_store);
- pr_debug(" problem state : 0x%016lx -> 0x%p\n",
- spu->problem_phys, spu->problem);
- pr_debug(" priv2 : 0x%p\n", spu->priv2);
- pr_debug(" priv1 : 0x%p\n",
- spu_get_pdata(spu)->priv1);
-
- return 0;
-
-out_unmap:
- spu_unmap(spu);
-out:
- pr_debug("failed to map spe %s: %d\n", spu->name, ret);
- return ret;
-}
-
-static int __init of_enumerate_spus(int (*fn)(void *data))
-{
- int ret;
- struct device_node *node;
-
- ret = -ENODEV;
- for (node = of_find_node_by_type(NULL, "spe");
- node; node = of_find_node_by_type(node, "spe")) {
- ret = fn(node);
- if (ret) {
- printk(KERN_WARNING "%s: Error initializing %s\n",
- __FUNCTION__, node->name);
- break;
- }
- }
- return ret;
-}
-
-static int __init of_create_spu(struct spu *spu, void *data)
-{
- int ret;
- struct device_node *spe = (struct device_node *)data;
-
- spu->pdata = kzalloc(sizeof(struct spu_pdata),
- GFP_KERNEL);
- if (!spu->pdata) {
- ret = -ENOMEM;
- goto out;
- }
-
- 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");
- ret = -ENODEV;
- goto out_free;
- }
-
- spu_get_pdata(spu)->nid = of_node_to_nid(spe);
- if (spu_get_pdata(spu)->nid == -1)
- spu_get_pdata(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;
-
- spu_get_pdata(spu)->devnode = of_node_get(spe);
-
- pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n", spu->name,
- spu->local_store, spu->problem, spu_get_pdata(spu)->priv1,
- spu->priv2, spu->number);
- goto out;
-
-out_unmap:
- spu_unmap(spu);
-out_free:
- kfree(spu->pdata);
- spu->pdata = NULL;
-out:
- return ret;
-}
-
-static int of_destroy_spu(struct spu *spu)
-{
- spu_unmap(spu);
- of_node_put(spu_get_pdata(spu)->devnode);
- kfree(spu->pdata);
- spu->pdata = NULL;
- return 0;
-}
-
-const struct spu_management_ops spu_management_of_ops = {
- .enumerate_spus = of_enumerate_spus,
- .create_spu = of_create_spu,
- .destroy_spu = of_destroy_spu,
-};
-
static void int_mask_and(struct spu *spu, int class, u64 mask)
{
u64 old_mask;
- old_mask = in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]);
- out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class],
- old_mask & mask);
+ old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+ out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask);
}
static void int_mask_or(struct spu *spu, int class, u64 mask)
{
u64 old_mask;
- old_mask = in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]);
- out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class],
- old_mask | mask);
+ old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
+ out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask);
}
static void int_mask_set(struct spu *spu, int class, u64 mask)
{
- out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class], mask);
+ out_be64(&spu->priv1->int_mask_RW[class], mask);
}
static u64 int_mask_get(struct spu *spu, int class)
{
- return in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]);
+ return in_be64(&spu->priv1->int_mask_RW[class]);
}
static void int_stat_clear(struct spu *spu, int class, u64 stat)
{
- out_be64(&spu_get_pdata(spu)->priv1->int_stat_RW[class], stat);
+ out_be64(&spu->priv1->int_stat_RW[class], stat);
}
static u64 int_stat_get(struct spu *spu, int class)
{
- return in_be64(&spu_get_pdata(spu)->priv1->int_stat_RW[class]);
+ return in_be64(&spu->priv1->int_stat_RW[class]);
}
static void cpu_affinity_set(struct spu *spu, int cpu)
{
u64 target = iic_get_target_id(cpu);
u64 route = target << 48 | target << 32 | target << 16;
- out_be64(&spu_get_pdata(spu)->priv1->int_route_RW, route);
+ out_be64(&spu->priv1->int_route_RW, route);
}
static u64 mfc_dar_get(struct spu *spu)
{
- return in_be64(&spu_get_pdata(spu)->priv1->mfc_dar_RW);
+ return in_be64(&spu->priv1->mfc_dar_RW);
}
static u64 mfc_dsisr_get(struct spu *spu)
{
- return in_be64(&spu_get_pdata(spu)->priv1->mfc_dsisr_RW);
+ return in_be64(&spu->priv1->mfc_dsisr_RW);
}
static void mfc_dsisr_set(struct spu *spu, u64 dsisr)
{
- out_be64(&spu_get_pdata(spu)->priv1->mfc_dsisr_RW, dsisr);
+ out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
}
static void mfc_sdr_setup(struct spu *spu)
{
- out_be64(&spu_get_pdata(spu)->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
+ out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
}
static void mfc_sr1_set(struct spu *spu, u64 sr1)
{
- out_be64(&spu_get_pdata(spu)->priv1->mfc_sr1_RW, sr1);
+ out_be64(&spu->priv1->mfc_sr1_RW, sr1);
}
static u64 mfc_sr1_get(struct spu *spu)
{
- return in_be64(&spu_get_pdata(spu)->priv1->mfc_sr1_RW);
+ return in_be64(&spu->priv1->mfc_sr1_RW);
}
static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
{
- out_be64(&spu_get_pdata(spu)->priv1->mfc_tclass_id_RW, tclass_id);
+ out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id);
}
static u64 mfc_tclass_id_get(struct spu *spu)
{
- return in_be64(&spu_get_pdata(spu)->priv1->mfc_tclass_id_RW);
+ return in_be64(&spu->priv1->mfc_tclass_id_RW);
}
static void tlb_invalidate(struct spu *spu)
{
- out_be64(&spu_get_pdata(spu)->priv1->tlb_invalidate_entry_W, 0ul);
+ out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul);
}
static void resource_allocation_groupID_set(struct spu *spu, u64 id)
{
- out_be64(&spu_get_pdata(spu)->priv1->resource_allocation_groupID_RW,
- id);
+ out_be64(&spu->priv1->resource_allocation_groupID_RW, id);
}
static u64 resource_allocation_groupID_get(struct spu *spu)
{
- return in_be64(
- &spu_get_pdata(spu)->priv1->resource_allocation_groupID_RW);
+ return in_be64(&spu->priv1->resource_allocation_groupID_RW);
}
static void resource_allocation_enable_set(struct spu *spu, u64 enable)
{
- out_be64(&spu_get_pdata(spu)->priv1->resource_allocation_enable_RW,
- enable);
+ out_be64(&spu->priv1->resource_allocation_enable_RW, enable);
}
static u64 resource_allocation_enable_get(struct spu *spu)
{
- return in_be64(
- &spu_get_pdata(spu)->priv1->resource_allocation_enable_RW);
+ return in_be64(&spu->priv1->resource_allocation_enable_RW);
}
const struct spu_priv1_ops spu_priv1_mmio_ops =
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 26945c491f6..725e1956115 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -147,7 +147,7 @@ static int spufs_arch_notes_size(void)
struct fdtable *fdt = files_fdtable(current->files);
int size = 0, fd;
- for (fd = 0; fd < fdt->max_fdset && fd < fdt->max_fds; fd++) {
+ for (fd = 0; fd < fdt->max_fds; fd++) {
if (FD_ISSET(fd, fdt->open_fds)) {
struct file *file = fcheck(fd);
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index e3af9112c02..738b9244382 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -205,7 +205,7 @@ static int spufs_dir_close(struct inode *inode, struct file *file)
struct dentry *dir;
int ret;
- dir = file->f_dentry;
+ dir = file->f_path.dentry;
parent = dir->d_parent->d_inode;
ctx = SPUFS_I(dir->d_inode)->i_ctx;
@@ -363,7 +363,7 @@ static int spufs_gang_close(struct inode *inode, struct file *file)
struct dentry *dir;
int ret;
- dir = file->f_dentry;
+ dir = file->f_path.dentry;
parent = dir->d_parent->d_inode;
ret = spufs_rmgang(parent, dir);
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
index a6d1ae4dc2a..8e37bdf4dfd 100644
--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -46,7 +46,7 @@ static long do_spu_run(struct file *filp,
if (filp->f_op != &spufs_context_fops)
goto out;
- i = SPUFS_I(filp->f_dentry->d_inode);
+ i = SPUFS_I(filp->f_path.dentry->d_inode);
ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
if (put_user(npc, unpc))
diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile
new file mode 100644
index 00000000000..3baf658ac54
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/Makefile
@@ -0,0 +1,9 @@
+obj-y += interrupt.o iommu.o setup.o \
+ htab.o beat.o pci.o \
+ scc_epci.o hvCall.o
+
+obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o
+obj-$(CONFIG_USB) += scc_uhc.o
+obj-$(CONFIG_HAS_TXX9_SERIAL) += scc_sio.o
+obj-$(CONFIG_SPU_BASE) += spu_priv1.o
diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/celleb/beat.c
new file mode 100644
index 00000000000..99341ce8a69
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat.c
@@ -0,0 +1,163 @@
+/*
+ * Simple routines for Celleb/Beat
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/rtc.h>
+
+#include <asm/hvconsole.h>
+#include <asm/time.h>
+
+#include "beat_wrapper.h"
+#include "beat.h"
+
+void beat_restart(char *cmd)
+{
+ beat_shutdown_logical_partition(1);
+}
+
+void beat_power_off(void)
+{
+ beat_shutdown_logical_partition(0);
+}
+
+u64 beat_halt_code = 0x1000000000000000UL;
+
+void beat_halt(void)
+{
+ beat_shutdown_logical_partition(beat_halt_code);
+}
+
+int beat_set_rtc_time(struct rtc_time *rtc_time)
+{
+ u64 tim;
+ tim = mktime(rtc_time->tm_year+1900,
+ rtc_time->tm_mon+1, rtc_time->tm_mday,
+ rtc_time->tm_hour, rtc_time->tm_min, rtc_time->tm_sec);
+ if (beat_rtc_write(tim))
+ return -1;
+ return 0;
+}
+
+void beat_get_rtc_time(struct rtc_time *rtc_time)
+{
+ u64 tim;
+
+ if (beat_rtc_read(&tim))
+ tim = 0;
+ to_tm(tim, rtc_time);
+ rtc_time->tm_year -= 1900;
+ rtc_time->tm_mon -= 1;
+}
+
+#define BEAT_NVRAM_SIZE 4096
+
+ssize_t beat_nvram_read(char *buf, size_t count, loff_t *index)
+{
+ unsigned int i;
+ unsigned long len;
+ char *p = buf;
+
+ if (*index >= BEAT_NVRAM_SIZE)
+ return -ENODEV;
+ i = *index;
+ if (i + count > BEAT_NVRAM_SIZE)
+ count = BEAT_NVRAM_SIZE - i;
+
+ for (; count != 0; count -= len) {
+ len = count;
+ if (len > BEAT_NVRW_CNT)
+ len = BEAT_NVRW_CNT;
+ if (beat_eeprom_read(i, len, p)) {
+ return -EIO;
+ }
+
+ p += len;
+ i += len;
+ }
+ *index = i;
+ return p - buf;
+}
+
+ssize_t beat_nvram_write(char *buf, size_t count, loff_t *index)
+{
+ unsigned int i;
+ unsigned long len;
+ char *p = buf;
+
+ if (*index >= BEAT_NVRAM_SIZE)
+ return -ENODEV;
+ i = *index;
+ if (i + count > BEAT_NVRAM_SIZE)
+ count = BEAT_NVRAM_SIZE - i;
+
+ for (; count != 0; count -= len) {
+ len = count;
+ if (len > BEAT_NVRW_CNT)
+ len = BEAT_NVRW_CNT;
+ if (beat_eeprom_write(i, len, p)) {
+ return -EIO;
+ }
+
+ p += len;
+ i += len;
+ }
+ *index = i;
+ return p - buf;
+}
+
+ssize_t beat_nvram_get_size(void)
+{
+ return BEAT_NVRAM_SIZE;
+}
+
+int beat_set_xdabr(unsigned long dabr)
+{
+ if (beat_set_dabr(dabr, DABRX_KERNEL | DABRX_USER))
+ return -1;
+ return 0;
+}
+
+int64_t beat_get_term_char(u64 vterm, u64 *len, u64 *t1, u64 *t2)
+{
+ u64 db[2];
+ s64 ret;
+
+ ret = beat_get_characters_from_console(vterm, len, (u8*)db);
+ if (ret == 0) {
+ *t1 = db[0];
+ *t2 = db[1];
+ }
+ return ret;
+}
+
+int64_t beat_put_term_char(u64 vterm, u64 len, u64 t1, u64 t2)
+{
+ u64 db[2];
+
+ db[0] = t1;
+ db[1] = t2;
+ return beat_put_characters_to_console(vterm, len, (u8*)db);
+}
+
+EXPORT_SYMBOL(beat_get_term_char);
+EXPORT_SYMBOL(beat_put_term_char);
+EXPORT_SYMBOL(beat_halt_code);
diff --git a/arch/powerpc/platforms/celleb/beat.h b/arch/powerpc/platforms/celleb/beat.h
new file mode 100644
index 00000000000..2b16bf3bee8
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat.h
@@ -0,0 +1,40 @@
+/*
+ * Guest OS Interfaces.
+ *
+ * (C) Copyright 2006 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CELLEB_BEAT_H
+#define _CELLEB_BEAT_H
+
+#define DABRX_KERNEL (1UL<<1)
+#define DABRX_USER (1UL<<0)
+
+int64_t beat_get_term_char(uint64_t,uint64_t*,uint64_t*,uint64_t*);
+int64_t beat_put_term_char(uint64_t,uint64_t,uint64_t,uint64_t);
+int64_t beat_repository_encode(int, const char *, uint64_t[4]);
+void beat_restart(char *);
+void beat_power_off(void);
+void beat_halt(void);
+int beat_set_rtc_time(struct rtc_time *);
+void beat_get_rtc_time(struct rtc_time *);
+ssize_t beat_nvram_get_size(void);
+ssize_t beat_nvram_read(char *, size_t, loff_t *);
+ssize_t beat_nvram_write(char *, size_t, loff_t *);
+int beat_set_xdabr(unsigned long);
+
+#endif /* _CELLEB_BEAT_H */
diff --git a/arch/powerpc/platforms/celleb/beat_syscall.h b/arch/powerpc/platforms/celleb/beat_syscall.h
new file mode 100644
index 00000000000..14e16974773
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat_syscall.h
@@ -0,0 +1,160 @@
+/*
+ * Beat hypervisor call numbers
+ *
+ * (C) Copyright 2004-2007 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef BEAT_BEAT_syscall_H
+#define BEAT_BEAT_syscall_H
+
+#ifdef __ASSEMBLY__
+#define __BEAT_ADD_VENDOR_ID(__x, __v) ((__v)<<60|(__x))
+#else
+#define __BEAT_ADD_VENDOR_ID(__x, __v) ((u64)(__v)<<60|(__x))
+#endif
+#define HV_allocate_memory __BEAT_ADD_VENDOR_ID(0, 0)
+#define HV_construct_virtual_address_space __BEAT_ADD_VENDOR_ID(2, 0)
+#define HV_destruct_virtual_address_space __BEAT_ADD_VENDOR_ID(10, 0)
+#define HV_get_virtual_address_space_id_of_ppe __BEAT_ADD_VENDOR_ID(4, 0)
+#define HV_query_logical_partition_address_region_info \
+ __BEAT_ADD_VENDOR_ID(6, 0)
+#define HV_release_memory __BEAT_ADD_VENDOR_ID(13, 0)
+#define HV_select_virtual_address_space __BEAT_ADD_VENDOR_ID(7, 0)
+#define HV_load_range_registers __BEAT_ADD_VENDOR_ID(68, 0)
+#define HV_set_ppe_l2cache_rmt_entry __BEAT_ADD_VENDOR_ID(70, 0)
+#define HV_set_ppe_tlb_rmt_entry __BEAT_ADD_VENDOR_ID(71, 0)
+#define HV_set_spe_tlb_rmt_entry __BEAT_ADD_VENDOR_ID(72, 0)
+#define HV_get_io_address_translation_fault_info __BEAT_ADD_VENDOR_ID(14, 0)
+#define HV_get_iopte __BEAT_ADD_VENDOR_ID(16, 0)
+#define HV_preload_iopt_cache __BEAT_ADD_VENDOR_ID(17, 0)
+#define HV_put_iopte __BEAT_ADD_VENDOR_ID(15, 0)
+#define HV_connect_event_ports __BEAT_ADD_VENDOR_ID(21, 0)
+#define HV_construct_event_receive_port __BEAT_ADD_VENDOR_ID(18, 0)
+#define HV_destruct_event_receive_port __BEAT_ADD_VENDOR_ID(19, 0)
+#define HV_destruct_event_send_port __BEAT_ADD_VENDOR_ID(22, 0)
+#define HV_get_state_of_event_send_port __BEAT_ADD_VENDOR_ID(25, 0)
+#define HV_request_to_connect_event_ports __BEAT_ADD_VENDOR_ID(20, 0)
+#define HV_send_event_externally __BEAT_ADD_VENDOR_ID(23, 0)
+#define HV_send_event_locally __BEAT_ADD_VENDOR_ID(24, 0)
+#define HV_construct_and_connect_irq_plug __BEAT_ADD_VENDOR_ID(28, 0)
+#define HV_destruct_irq_plug __BEAT_ADD_VENDOR_ID(29, 0)
+#define HV_detect_pending_interrupts __BEAT_ADD_VENDOR_ID(26, 0)
+#define HV_end_of_interrupt __BEAT_ADD_VENDOR_ID(27, 0)
+#define HV_assign_control_signal_notification_port __BEAT_ADD_VENDOR_ID(45, 0)
+#define HV_end_of_control_signal_processing __BEAT_ADD_VENDOR_ID(48, 0)
+#define HV_get_control_signal __BEAT_ADD_VENDOR_ID(46, 0)
+#define HV_set_irq_mask_for_spe __BEAT_ADD_VENDOR_ID(61, 0)
+#define HV_shutdown_logical_partition __BEAT_ADD_VENDOR_ID(44, 0)
+#define HV_connect_message_ports __BEAT_ADD_VENDOR_ID(35, 0)
+#define HV_destruct_message_port __BEAT_ADD_VENDOR_ID(36, 0)
+#define HV_receive_message __BEAT_ADD_VENDOR_ID(37, 0)
+#define HV_get_message_port_info __BEAT_ADD_VENDOR_ID(34, 0)
+#define HV_request_to_connect_message_ports __BEAT_ADD_VENDOR_ID(33, 0)
+#define HV_send_message __BEAT_ADD_VENDOR_ID(32, 0)
+#define HV_get_logical_ppe_id __BEAT_ADD_VENDOR_ID(69, 0)
+#define HV_pause __BEAT_ADD_VENDOR_ID(9, 0)
+#define HV_destruct_shared_memory_handle __BEAT_ADD_VENDOR_ID(51, 0)
+#define HV_get_shared_memory_info __BEAT_ADD_VENDOR_ID(52, 0)
+#define HV_permit_sharing_memory __BEAT_ADD_VENDOR_ID(50, 0)
+#define HV_request_to_attach_shared_memory __BEAT_ADD_VENDOR_ID(49, 0)
+#define HV_enable_logical_spe_execution __BEAT_ADD_VENDOR_ID(55, 0)
+#define HV_construct_logical_spe __BEAT_ADD_VENDOR_ID(53, 0)
+#define HV_disable_logical_spe_execution __BEAT_ADD_VENDOR_ID(56, 0)
+#define HV_destruct_logical_spe __BEAT_ADD_VENDOR_ID(54, 0)
+#define HV_sense_spe_execution_status __BEAT_ADD_VENDOR_ID(58, 0)
+#define HV_insert_htab_entry __BEAT_ADD_VENDOR_ID(101, 0)
+#define HV_read_htab_entries __BEAT_ADD_VENDOR_ID(95, 0)
+#define HV_write_htab_entry __BEAT_ADD_VENDOR_ID(94, 0)
+#define HV_assign_io_address_translation_fault_port \
+ __BEAT_ADD_VENDOR_ID(100, 0)
+#define HV_set_interrupt_mask __BEAT_ADD_VENDOR_ID(73, 0)
+#define HV_get_logical_partition_id __BEAT_ADD_VENDOR_ID(74, 0)
+#define HV_create_repository_node2 __BEAT_ADD_VENDOR_ID(90, 0)
+#define HV_create_repository_node __BEAT_ADD_VENDOR_ID(90, 0) /* alias */
+#define HV_get_repository_node_value2 __BEAT_ADD_VENDOR_ID(91, 0)
+#define HV_get_repository_node_value __BEAT_ADD_VENDOR_ID(91, 0) /* alias */
+#define HV_modify_repository_node_value2 __BEAT_ADD_VENDOR_ID(92, 0)
+#define HV_modify_repository_node_value __BEAT_ADD_VENDOR_ID(92, 0) /* alias */
+#define HV_remove_repository_node2 __BEAT_ADD_VENDOR_ID(93, 0)
+#define HV_remove_repository_node __BEAT_ADD_VENDOR_ID(93, 0) /* alias */
+#define HV_cancel_shared_memory __BEAT_ADD_VENDOR_ID(104, 0)
+#define HV_clear_interrupt_status_of_spe __BEAT_ADD_VENDOR_ID(206, 0)
+#define HV_construct_spe_irq_outlet __BEAT_ADD_VENDOR_ID(80, 0)
+#define HV_destruct_spe_irq_outlet __BEAT_ADD_VENDOR_ID(81, 0)
+#define HV_disconnect_ipspc_service __BEAT_ADD_VENDOR_ID(88, 0)
+#define HV_execute_ipspc_command __BEAT_ADD_VENDOR_ID(86, 0)
+#define HV_get_interrupt_status_of_spe __BEAT_ADD_VENDOR_ID(205, 0)
+#define HV_get_spe_privileged_state_1_registers __BEAT_ADD_VENDOR_ID(208, 0)
+#define HV_permit_use_of_ipspc_service __BEAT_ADD_VENDOR_ID(85, 0)
+#define HV_reinitialize_logical_spe __BEAT_ADD_VENDOR_ID(82, 0)
+#define HV_request_ipspc_service __BEAT_ADD_VENDOR_ID(84, 0)
+#define HV_stop_ipspc_command __BEAT_ADD_VENDOR_ID(87, 0)
+#define HV_set_spe_privileged_state_1_registers __BEAT_ADD_VENDOR_ID(204, 0)
+#define HV_get_status_of_ipspc_service __BEAT_ADD_VENDOR_ID(203, 0)
+#define HV_put_characters_to_console __BEAT_ADD_VENDOR_ID(0x101, 1)
+#define HV_get_characters_from_console __BEAT_ADD_VENDOR_ID(0x102, 1)
+#define HV_get_base_clock __BEAT_ADD_VENDOR_ID(0x111, 1)
+#define HV_set_base_clock __BEAT_ADD_VENDOR_ID(0x112, 1)
+#define HV_get_frame_cycle __BEAT_ADD_VENDOR_ID(0x114, 1)
+#define HV_disable_console __BEAT_ADD_VENDOR_ID(0x115, 1)
+#define HV_disable_all_console __BEAT_ADD_VENDOR_ID(0x116, 1)
+#define HV_oneshot_timer __BEAT_ADD_VENDOR_ID(0x117, 1)
+#define HV_set_dabr __BEAT_ADD_VENDOR_ID(0x118, 1)
+#define HV_get_dabr __BEAT_ADD_VENDOR_ID(0x119, 1)
+#define HV_start_hv_stats __BEAT_ADD_VENDOR_ID(0x21c, 1)
+#define HV_stop_hv_stats __BEAT_ADD_VENDOR_ID(0x21d, 1)
+#define HV_get_hv_stats __BEAT_ADD_VENDOR_ID(0x21e, 1)
+#define HV_get_hv_error_stats __BEAT_ADD_VENDOR_ID(0x221, 1)
+#define HV_get_stats __BEAT_ADD_VENDOR_ID(0x224, 1)
+#define HV_get_heap_stats __BEAT_ADD_VENDOR_ID(0x225, 1)
+#define HV_get_memory_stats __BEAT_ADD_VENDOR_ID(0x227, 1)
+#define HV_get_memory_detail __BEAT_ADD_VENDOR_ID(0x228, 1)
+#define HV_set_priority_of_irq_outlet __BEAT_ADD_VENDOR_ID(0x122, 1)
+#define HV_get_physical_spe_by_reservation_id __BEAT_ADD_VENDOR_ID(0x128, 1)
+#define HV_get_spe_context __BEAT_ADD_VENDOR_ID(0x129, 1)
+#define HV_set_spe_context __BEAT_ADD_VENDOR_ID(0x12a, 1)
+#define HV_downcount_of_interrupt __BEAT_ADD_VENDOR_ID(0x12e, 1)
+#define HV_peek_spe_context __BEAT_ADD_VENDOR_ID(0x12f, 1)
+#define HV_read_bpa_register __BEAT_ADD_VENDOR_ID(0x131, 1)
+#define HV_write_bpa_register __BEAT_ADD_VENDOR_ID(0x132, 1)
+#define HV_map_context_table_of_spe __BEAT_ADD_VENDOR_ID(0x137, 1)
+#define HV_get_slb_for_logical_spe __BEAT_ADD_VENDOR_ID(0x138, 1)
+#define HV_set_slb_for_logical_spe __BEAT_ADD_VENDOR_ID(0x139, 1)
+#define HV_init_pm __BEAT_ADD_VENDOR_ID(0x150, 1)
+#define HV_set_pm_signal __BEAT_ADD_VENDOR_ID(0x151, 1)
+#define HV_get_pm_signal __BEAT_ADD_VENDOR_ID(0x152, 1)
+#define HV_set_pm_config __BEAT_ADD_VENDOR_ID(0x153, 1)
+#define HV_get_pm_config __BEAT_ADD_VENDOR_ID(0x154, 1)
+#define HV_get_inner_trace_data __BEAT_ADD_VENDOR_ID(0x155, 1)
+#define HV_set_ext_trace_buffer __BEAT_ADD_VENDOR_ID(0x156, 1)
+#define HV_get_ext_trace_buffer __BEAT_ADD_VENDOR_ID(0x157, 1)
+#define HV_set_pm_interrupt __BEAT_ADD_VENDOR_ID(0x158, 1)
+#define HV_get_pm_interrupt __BEAT_ADD_VENDOR_ID(0x159, 1)
+#define HV_kick_pm __BEAT_ADD_VENDOR_ID(0x160, 1)
+#define HV_construct_pm_context __BEAT_ADD_VENDOR_ID(0x164, 1)
+#define HV_destruct_pm_context __BEAT_ADD_VENDOR_ID(0x165, 1)
+#define HV_be_slow __BEAT_ADD_VENDOR_ID(0x170, 1)
+#define HV_assign_ipspc_server_connection_status_notification_port \
+ __BEAT_ADD_VENDOR_ID(0x173, 1)
+#define HV_get_raid_of_physical_spe __BEAT_ADD_VENDOR_ID(0x174, 1)
+#define HV_set_physical_spe_to_rag __BEAT_ADD_VENDOR_ID(0x175, 1)
+#define HV_release_physical_spe_from_rag __BEAT_ADD_VENDOR_ID(0x176, 1)
+#define HV_rtc_read __BEAT_ADD_VENDOR_ID(0x190, 1)
+#define HV_rtc_write __BEAT_ADD_VENDOR_ID(0x191, 1)
+#define HV_eeprom_read __BEAT_ADD_VENDOR_ID(0x192, 1)
+#define HV_eeprom_write __BEAT_ADD_VENDOR_ID(0x193, 1)
+#endif
diff --git a/arch/powerpc/platforms/celleb/beat_wrapper.h b/arch/powerpc/platforms/celleb/beat_wrapper.h
new file mode 100644
index 00000000000..76ea0a6a901
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat_wrapper.h
@@ -0,0 +1,220 @@
+/*
+ * Beat hypervisor call I/F
+ *
+ * (C) Copyright 2007 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/platforms/pseries/plpar_wrapper.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.
+ *
+ * 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.
+ */
+#ifndef BEAT_HCALL
+#include "beat_syscall.h"
+
+/* defined in hvCall.S */
+extern s64 beat_hcall_norets(u64 opcode, ...);
+extern s64 beat_hcall_norets8(u64 opcode, u64 arg1, u64 arg2, u64 arg3,
+ u64 arg4, u64 arg5, u64 arg6, u64 arg7, u64 arg8);
+extern s64 beat_hcall1(u64 opcode, u64 retbuf[1], ...);
+extern s64 beat_hcall2(u64 opcode, u64 retbuf[2], ...);
+extern s64 beat_hcall3(u64 opcode, u64 retbuf[3], ...);
+extern s64 beat_hcall4(u64 opcode, u64 retbuf[4], ...);
+extern s64 beat_hcall5(u64 opcode, u64 retbuf[5], ...);
+extern s64 beat_hcall6(u64 opcode, u64 retbuf[6], ...);
+
+static inline s64 beat_downcount_of_interrupt(u64 plug_id)
+{
+ return beat_hcall_norets(HV_downcount_of_interrupt, plug_id);
+}
+
+static inline s64 beat_set_interrupt_mask(u64 index,
+ u64 val0, u64 val1, u64 val2, u64 val3)
+{
+ return beat_hcall_norets(HV_set_interrupt_mask, index,
+ val0, val1, val2, val3);
+}
+
+static inline s64 beat_destruct_irq_plug(u64 plug_id)
+{
+ return beat_hcall_norets(HV_destruct_irq_plug, plug_id);
+}
+
+static inline s64 beat_construct_and_connect_irq_plug(u64 plug_id,
+ u64 outlet_id)
+{
+ return beat_hcall_norets(HV_construct_and_connect_irq_plug, plug_id,
+ outlet_id);
+}
+
+static inline s64 beat_detect_pending_interrupts(u64 index, u64 *retbuf)
+{
+ return beat_hcall4(HV_detect_pending_interrupts, retbuf, index);
+}
+
+static inline s64 beat_pause(u64 style)
+{
+ return beat_hcall_norets(HV_pause, style);
+}
+
+static inline s64 beat_read_htab_entries(u64 htab_id, u64 index, u64 *retbuf)
+{
+ return beat_hcall5(HV_read_htab_entries, retbuf, htab_id, index);
+}
+
+static inline s64 beat_insert_htab_entry(u64 htab_id, u64 group,
+ u64 bitmask, u64 hpte_v, u64 hpte_r, u64 *slot)
+{
+ u64 dummy[3];
+ s64 ret;
+
+ ret = beat_hcall3(HV_insert_htab_entry, dummy, htab_id, group,
+ bitmask, hpte_v, hpte_r);
+ *slot = dummy[0];
+ return ret;
+}
+
+static inline s64 beat_write_htab_entry(u64 htab_id, u64 slot,
+ u64 hpte_v, u64 hpte_r, u64 mask_v, u64 mask_r,
+ u64 *ret_v, u64 *ret_r)
+{
+ u64 dummy[2];
+ s64 ret;
+
+ ret = beat_hcall2(HV_write_htab_entry, dummy, htab_id, slot,
+ hpte_v, hpte_r, mask_v, mask_r);
+ *ret_v = dummy[0];
+ *ret_r = dummy[1];
+ return ret;
+}
+
+static inline void beat_shutdown_logical_partition(u64 code)
+{
+ (void)beat_hcall_norets(HV_shutdown_logical_partition, code);
+}
+
+static inline s64 beat_rtc_write(u64 time_from_epoch)
+{
+ return beat_hcall_norets(HV_rtc_write, time_from_epoch);
+}
+
+static inline s64 beat_rtc_read(u64 *time_from_epoch)
+{
+ u64 dummy[1];
+ s64 ret;
+
+ ret = beat_hcall1(HV_rtc_read, dummy);
+ *time_from_epoch = dummy[0];
+ return ret;
+}
+
+#define BEAT_NVRW_CNT (sizeof(u64) * 6)
+
+static inline s64 beat_eeprom_write(u64 index, u64 length, u8 *buffer)
+{
+ u64 b[6];
+
+ if (length > BEAT_NVRW_CNT)
+ return -1;
+ memcpy(b, buffer, sizeof(b));
+ return beat_hcall_norets8(HV_eeprom_write, index, length,
+ b[0], b[1], b[2], b[3], b[4], b[5]);
+}
+
+static inline s64 beat_eeprom_read(u64 index, u64 length, u8 *buffer)
+{
+ u64 b[6];
+ s64 ret;
+
+ if (length > BEAT_NVRW_CNT)
+ return -1;
+ ret = beat_hcall6(HV_eeprom_read, b, index, length);
+ memcpy(buffer, b, length);
+ return ret;
+}
+
+static inline s64 beat_set_dabr(u64 value, u64 style)
+{
+ return beat_hcall_norets(HV_set_dabr, value, style);
+}
+
+static inline s64 beat_get_characters_from_console(u64 termno, u64 *len,
+ u8 *buffer)
+{
+ u64 dummy[3];
+ s64 ret;
+
+ ret = beat_hcall3(HV_get_characters_from_console, dummy, termno, len);
+ *len = dummy[0];
+ memcpy(buffer, dummy + 1, *len);
+ return ret;
+}
+
+static inline s64 beat_put_characters_to_console(u64 termno, u64 len,
+ u8 *buffer)
+{
+ u64 b[2];
+
+ memcpy(b, buffer, len);
+ return beat_hcall_norets(HV_put_characters_to_console, termno, len, b[0], b[1]);
+}
+
+static inline s64 beat_get_spe_privileged_state_1_registers(
+ u64 id, u64 offsetof, u64 *value)
+{
+ u64 dummy[1];
+ s64 ret;
+
+ ret = beat_hcall1(HV_get_spe_privileged_state_1_registers, dummy, id,
+ offsetof);
+ *value = dummy[0];
+ return ret;
+}
+
+static inline s64 beat_set_irq_mask_for_spe(u64 id, u64 class, u64 mask)
+{
+ return beat_hcall_norets(HV_set_irq_mask_for_spe, id, class, mask);
+}
+
+static inline s64 beat_clear_interrupt_status_of_spe(u64 id, u64 class,
+ u64 mask)
+{
+ return beat_hcall_norets(HV_clear_interrupt_status_of_spe,
+ id, class, mask);
+}
+
+static inline s64 beat_set_spe_privileged_state_1_registers(
+ u64 id, u64 offsetof, u64 value)
+{
+ return beat_hcall_norets(HV_set_spe_privileged_state_1_registers,
+ id, offsetof, value);
+}
+
+static inline s64 beat_get_interrupt_status_of_spe(u64 id, u64 class, u64 *val)
+{
+ u64 dummy[1];
+ s64 ret;
+
+ ret = beat_hcall1(HV_get_interrupt_status_of_spe, dummy, id, class);
+ *val = dummy[0];
+ return ret;
+}
+
+static inline s64 beat_put_iopte(u64 ioas_id, u64 io_addr, u64 real_addr,
+ u64 ioid, u64 flags)
+{
+ return beat_hcall_norets(HV_put_iopte, ioas_id, io_addr, real_addr,
+ ioid, flags);
+}
+
+#endif
diff --git a/arch/powerpc/platforms/celleb/htab.c b/arch/powerpc/platforms/celleb/htab.c
new file mode 100644
index 00000000000..ffa7c2c2030
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/htab.c
@@ -0,0 +1,311 @@
+/*
+ * "Cell Reference Set" HTAB support.
+ *
+ * (C) Copyright 2006-2007 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/platforms/pseries/lpar.c:
+ * Copyright (C) 2001 Todd Inglett, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG_LOW
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/udbg.h>
+
+#include "beat_wrapper.h"
+
+#ifdef DEBUG_LOW
+#define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0)
+#else
+#define DBG_LOW(fmt...) do { } while(0)
+#endif
+
+static DEFINE_SPINLOCK(beat_htab_lock);
+
+static inline unsigned int beat_read_mask(unsigned hpte_group)
+{
+ unsigned long hpte_v[5];
+ unsigned long rmask = 0;
+
+ beat_read_htab_entries(0, hpte_group + 0, hpte_v);
+ if (!(hpte_v[0] & HPTE_V_BOLTED))
+ rmask |= 0x8000;
+ if (!(hpte_v[1] & HPTE_V_BOLTED))
+ rmask |= 0x4000;
+ if (!(hpte_v[2] & HPTE_V_BOLTED))
+ rmask |= 0x2000;
+ if (!(hpte_v[3] & HPTE_V_BOLTED))
+ rmask |= 0x1000;
+ beat_read_htab_entries(0, hpte_group + 4, hpte_v);
+ if (!(hpte_v[0] & HPTE_V_BOLTED))
+ rmask |= 0x0800;
+ if (!(hpte_v[1] & HPTE_V_BOLTED))
+ rmask |= 0x0400;
+ if (!(hpte_v[2] & HPTE_V_BOLTED))
+ rmask |= 0x0200;
+ if (!(hpte_v[3] & HPTE_V_BOLTED))
+ rmask |= 0x0100;
+ hpte_group = ~hpte_group & (htab_hash_mask * HPTES_PER_GROUP);
+ beat_read_htab_entries(0, hpte_group + 0, hpte_v);
+ if (!(hpte_v[0] & HPTE_V_BOLTED))
+ rmask |= 0x80;
+ if (!(hpte_v[1] & HPTE_V_BOLTED))
+ rmask |= 0x40;
+ if (!(hpte_v[2] & HPTE_V_BOLTED))
+ rmask |= 0x20;
+ if (!(hpte_v[3] & HPTE_V_BOLTED))
+ rmask |= 0x10;
+ beat_read_htab_entries(0, hpte_group + 4, hpte_v);
+ if (!(hpte_v[0] & HPTE_V_BOLTED))
+ rmask |= 0x08;
+ if (!(hpte_v[1] & HPTE_V_BOLTED))
+ rmask |= 0x04;
+ if (!(hpte_v[2] & HPTE_V_BOLTED))
+ rmask |= 0x02;
+ if (!(hpte_v[3] & HPTE_V_BOLTED))
+ rmask |= 0x01;
+ return rmask;
+}
+
+static long beat_lpar_hpte_insert(unsigned long hpte_group,
+ unsigned long va, unsigned long pa,
+ unsigned long rflags, unsigned long vflags,
+ int psize)
+{
+ unsigned long lpar_rc;
+ unsigned long slot;
+ unsigned long hpte_v, hpte_r;
+ unsigned long flags;
+
+ /* same as iseries */
+ if (vflags & HPTE_V_SECONDARY)
+ return -1;
+
+ if (!(vflags & HPTE_V_BOLTED))
+ DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, "
+ "rflags=%lx, vflags=%lx, psize=%d)\n",
+ hpte_group, va, pa, rflags, vflags, psize);
+
+ hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID;
+ hpte_r = hpte_encode_r(pa, psize) | rflags;
+
+ if (!(vflags & HPTE_V_BOLTED))
+ DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
+
+ if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
+ hpte_r &= ~_PAGE_COHERENT;
+
+ spin_lock_irqsave(&beat_htab_lock, flags);
+ if ((lpar_rc = beat_read_mask(hpte_group)) == 0) {
+ if (!(vflags & HPTE_V_BOLTED))
+ DBG_LOW(" full\n");
+ spin_unlock_irqrestore(&beat_htab_lock, flags);
+ return -1;
+ }
+
+ lpar_rc = beat_insert_htab_entry(0, hpte_group, lpar_rc << 48,
+ hpte_v, hpte_r, &slot);
+ spin_unlock_irqrestore(&beat_htab_lock, flags);
+
+ /*
+ * Since we try and ioremap PHBs we don't own, the pte insert
+ * will fail. However we must catch the failure in hash_page
+ * or we will loop forever, so return -2 in this case.
+ */
+ if (unlikely(lpar_rc != 0)) {
+ if (!(vflags & HPTE_V_BOLTED))
+ DBG_LOW(" lpar err %lx\n", lpar_rc);
+ return -2;
+ }
+ if (!(vflags & HPTE_V_BOLTED))
+ DBG_LOW(" -> slot: %lx\n", slot);
+
+ /* We have to pass down the secondary bucket bit here as well */
+ return (slot ^ hpte_group) & 15;
+}
+
+static long beat_lpar_hpte_remove(unsigned long hpte_group)
+{
+ DBG_LOW("hpte_remove(group=%lx)\n", hpte_group);
+ return -1;
+}
+
+static unsigned long beat_lpar_hpte_getword0(unsigned long slot)
+{
+ unsigned long dword0, dword[5];
+ unsigned long lpar_rc;
+
+ lpar_rc = beat_read_htab_entries(0, slot & ~3UL, dword);
+
+ dword0 = dword[slot&3];
+
+ BUG_ON(lpar_rc != 0);
+
+ return dword0;
+}
+
+static void beat_lpar_hptab_clear(void)
+{
+ unsigned long size_bytes = 1UL << ppc64_pft_size;
+ unsigned long hpte_count = size_bytes >> 4;
+ int i;
+ unsigned long dummy0, dummy1;
+
+ /* TODO: Use bulk call */
+ for (i = 0; i < hpte_count; i++)
+ beat_write_htab_entry(0, i, 0, 0, -1UL, -1UL, &dummy0, &dummy1);
+}
+
+/*
+ * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and
+ * the low 3 bits of flags happen to line up. So no transform is needed.
+ * We can probably optimize here and assume the high bits of newpp are
+ * already zero. For now I am paranoid.
+ */
+static long beat_lpar_hpte_updatepp(unsigned long slot,
+ unsigned long newpp,
+ unsigned long va,
+ int psize, int local)
+{
+ unsigned long lpar_rc;
+ unsigned long dummy0, dummy1, want_v;
+ unsigned long flags;
+
+ want_v = hpte_encode_v(va, psize);
+
+ DBG_LOW(" update: "
+ "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ",
+ want_v & HPTE_V_AVPN, slot, psize, newpp);
+
+ spin_lock_irqsave(&beat_htab_lock, flags);
+ dummy0 = beat_lpar_hpte_getword0(slot);
+ if ((dummy0 & ~0x7FUL) != (want_v & ~0x7FUL)) {
+ DBG_LOW("not found !\n");
+ spin_unlock_irqrestore(&beat_htab_lock, flags);
+ return -1;
+ }
+
+ lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7, &dummy0,
+ &dummy1);
+ spin_unlock_irqrestore(&beat_htab_lock, flags);
+ if (lpar_rc != 0 || dummy0 == 0) {
+ DBG_LOW("not found !\n");
+ return -1;
+ }
+
+ DBG_LOW("ok %lx %lx\n", dummy0, dummy1);
+
+ BUG_ON(lpar_rc != 0);
+
+ return 0;
+}
+
+static long beat_lpar_hpte_find(unsigned long va, int psize)
+{
+ unsigned long hash;
+ unsigned long i, j;
+ long slot;
+ unsigned long want_v, hpte_v;
+
+ hash = hpt_hash(va, mmu_psize_defs[psize].shift);
+ want_v = hpte_encode_v(va, psize);
+
+ for (j = 0; j < 2; j++) {
+ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ for (i = 0; i < HPTES_PER_GROUP; i++) {
+ hpte_v = beat_lpar_hpte_getword0(slot);
+
+ if (HPTE_V_COMPARE(hpte_v, want_v)
+ && (hpte_v & HPTE_V_VALID)
+ && (!!(hpte_v & HPTE_V_SECONDARY) == j)) {
+ /* HPTE matches */
+ if (j)
+ slot = -slot;
+ return slot;
+ }
+ ++slot;
+ }
+ hash = ~hash;
+ }
+
+ return -1;
+}
+
+static void beat_lpar_hpte_updateboltedpp(unsigned long newpp,
+ unsigned long ea,
+ int psize)
+{
+ unsigned long lpar_rc, slot, vsid, va, dummy0, dummy1;
+ unsigned long flags;
+
+ vsid = get_kernel_vsid(ea);
+ va = (vsid << 28) | (ea & 0x0fffffff);
+
+ spin_lock_irqsave(&beat_htab_lock, flags);
+ slot = beat_lpar_hpte_find(va, psize);
+ BUG_ON(slot == -1);
+
+ lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7,
+ &dummy0, &dummy1);
+ spin_unlock_irqrestore(&beat_htab_lock, flags);
+
+ BUG_ON(lpar_rc != 0);
+}
+
+static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
+ int psize, int local)
+{
+ unsigned long want_v;
+ unsigned long lpar_rc;
+ unsigned long dummy1, dummy2;
+ unsigned long flags;
+
+ DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n",
+ slot, va, psize, local);
+ want_v = hpte_encode_v(va, psize);
+
+ spin_lock_irqsave(&beat_htab_lock, flags);
+ dummy1 = beat_lpar_hpte_getword0(slot);
+
+ if ((dummy1 & ~0x7FUL) != (want_v & ~0x7FUL)) {
+ DBG_LOW("not found !\n");
+ spin_unlock_irqrestore(&beat_htab_lock, flags);
+ return;
+ }
+
+ lpar_rc = beat_write_htab_entry(0, slot, 0, 0, HPTE_V_VALID, 0,
+ &dummy1, &dummy2);
+ spin_unlock_irqrestore(&beat_htab_lock, flags);
+
+ BUG_ON(lpar_rc != 0);
+}
+
+void __init hpte_init_beat(void)
+{
+ ppc_md.hpte_invalidate = beat_lpar_hpte_invalidate;
+ ppc_md.hpte_updatepp = beat_lpar_hpte_updatepp;
+ ppc_md.hpte_updateboltedpp = beat_lpar_hpte_updateboltedpp;
+ ppc_md.hpte_insert = beat_lpar_hpte_insert;
+ ppc_md.hpte_remove = beat_lpar_hpte_remove;
+ ppc_md.hpte_clear_all = beat_lpar_hptab_clear;
+}
diff --git a/arch/powerpc/platforms/celleb/hvCall.S b/arch/powerpc/platforms/celleb/hvCall.S
new file mode 100644
index 00000000000..74c81744894
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/hvCall.S
@@ -0,0 +1,287 @@
+/*
+ * Beat hypervisor call I/F
+ *
+ * (C) Copyright 2007 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/platforms/pseries/hvCall.S.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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 <asm/ppc_asm.h>
+
+#define STK_PARM(i) (48 + ((i)-3)*8)
+
+/* Not implemented on Beat, now */
+#define HCALL_INST_PRECALL
+#define HCALL_INST_POSTCALL
+
+ .text
+
+#define HVSC .long 0x44000022
+
+/* Note: takes only 7 input parameters at maximum */
+_GLOBAL(beat_hcall_norets)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+ HCALL_INST_PRECALL
+
+ mr r11,r3
+ mr r3,r4
+ mr r4,r5
+ mr r5,r6
+ mr r6,r7
+ mr r7,r8
+ mr r8,r9
+
+ HVSC /* invoke the hypervisor */
+
+ HCALL_INST_POSTCALL
+
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+
+ blr /* return r3 = status */
+
+/* Note: takes 8 input parameters at maximum */
+_GLOBAL(beat_hcall_norets8)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+ HCALL_INST_PRECALL
+
+ mr r11,r3
+ mr r3,r4
+ mr r4,r5
+ mr r5,r6
+ mr r6,r7
+ mr r7,r8
+ mr r8,r9
+ ld r10,STK_PARM(r10)(r1)
+
+ HVSC /* invoke the hypervisor */
+
+ HCALL_INST_POSTCALL
+
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+
+ blr /* return r3 = status */
+
+/* Note: takes only 6 input parameters, 1 output parameters at maximum */
+_GLOBAL(beat_hcall1)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+ HCALL_INST_PRECALL
+
+ std r4,STK_PARM(r4)(r1) /* save ret buffer */
+
+ mr r11,r3
+ mr r3,r5
+ mr r4,r6
+ mr r5,r7
+ mr r6,r8
+ mr r7,r9
+ mr r8,r10
+
+ HVSC /* invoke the hypervisor */
+
+ HCALL_INST_POSTCALL
+
+ ld r12,STK_PARM(r4)(r1)
+ std r4, 0(r12)
+
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+
+ blr /* return r3 = status */
+
+/* Note: takes only 6 input parameters, 2 output parameters at maximum */
+_GLOBAL(beat_hcall2)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+ HCALL_INST_PRECALL
+
+ std r4,STK_PARM(r4)(r1) /* save ret buffer */
+
+ mr r11,r3
+ mr r3,r5
+ mr r4,r6
+ mr r5,r7
+ mr r6,r8
+ mr r7,r9
+ mr r8,r10
+
+ HVSC /* invoke the hypervisor */
+
+ HCALL_INST_POSTCALL
+
+ ld r12,STK_PARM(r4)(r1)
+ std r4, 0(r12)
+ std r5, 8(r12)
+
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+
+ blr /* return r3 = status */
+
+/* Note: takes only 6 input parameters, 3 output parameters at maximum */
+_GLOBAL(beat_hcall3)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+ HCALL_INST_PRECALL
+
+ std r4,STK_PARM(r4)(r1) /* save ret buffer */
+
+ mr r11,r3
+ mr r3,r5
+ mr r4,r6
+ mr r5,r7
+ mr r6,r8
+ mr r7,r9
+ mr r8,r10
+
+ HVSC /* invoke the hypervisor */
+
+ HCALL_INST_POSTCALL
+
+ ld r12,STK_PARM(r4)(r1)
+ std r4, 0(r12)
+ std r5, 8(r12)
+ std r6, 16(r12)
+
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+
+ blr /* return r3 = status */
+
+/* Note: takes only 6 input parameters, 4 output parameters at maximum */
+_GLOBAL(beat_hcall4)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+ HCALL_INST_PRECALL
+
+ std r4,STK_PARM(r4)(r1) /* save ret buffer */
+
+ mr r11,r3
+ mr r3,r5
+ mr r4,r6
+ mr r5,r7
+ mr r6,r8
+ mr r7,r9
+ mr r8,r10
+
+ HVSC /* invoke the hypervisor */
+
+ HCALL_INST_POSTCALL
+
+ ld r12,STK_PARM(r4)(r1)
+ std r4, 0(r12)
+ std r5, 8(r12)
+ std r6, 16(r12)
+ std r7, 24(r12)
+
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+
+ blr /* return r3 = status */
+
+/* Note: takes only 6 input parameters, 5 output parameters at maximum */
+_GLOBAL(beat_hcall5)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+ HCALL_INST_PRECALL
+
+ std r4,STK_PARM(r4)(r1) /* save ret buffer */
+
+ mr r11,r3
+ mr r3,r5
+ mr r4,r6
+ mr r5,r7
+ mr r6,r8
+ mr r7,r9
+ mr r8,r10
+
+ HVSC /* invoke the hypervisor */
+
+ HCALL_INST_POSTCALL
+
+ ld r12,STK_PARM(r4)(r1)
+ std r4, 0(r12)
+ std r5, 8(r12)
+ std r6, 16(r12)
+ std r7, 24(r12)
+ std r8, 32(r12)
+
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+
+ blr /* return r3 = status */
+
+/* Note: takes only 6 input parameters, 6 output parameters at maximum */
+_GLOBAL(beat_hcall6)
+ HMT_MEDIUM
+
+ mfcr r0
+ stw r0,8(r1)
+
+ HCALL_INST_PRECALL
+
+ std r4,STK_PARM(r4)(r1) /* save ret buffer */
+
+ mr r11,r3
+ mr r3,r5
+ mr r4,r6
+ mr r5,r7
+ mr r6,r8
+ mr r7,r9
+ mr r8,r10
+
+ HVSC /* invoke the hypervisor */
+
+ HCALL_INST_POSTCALL
+
+ ld r12,STK_PARM(r4)(r1)
+ std r4, 0(r12)
+ std r5, 8(r12)
+ std r6, 16(r12)
+ std r7, 24(r12)
+ std r8, 32(r12)
+ std r9, 40(r12)
+
+ lwz r0,8(r1)
+ mtcrf 0xff,r0
+
+ blr /* return r3 = status */
diff --git a/arch/powerpc/platforms/celleb/interrupt.c b/arch/powerpc/platforms/celleb/interrupt.c
new file mode 100644
index 00000000000..98e6665681d
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/interrupt.c
@@ -0,0 +1,274 @@
+/*
+ * Celleb/Beat Interrupt controller
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/percpu.h>
+#include <linux/types.h>
+
+#include <asm/machdep.h>
+
+#include "interrupt.h"
+#include "beat_wrapper.h"
+
+#define MAX_IRQS NR_IRQS
+static DEFINE_SPINLOCK(beatic_irq_mask_lock);
+static uint64_t beatic_irq_mask_enable[(MAX_IRQS+255)/64];
+static uint64_t beatic_irq_mask_ack[(MAX_IRQS+255)/64];
+
+static struct irq_host *beatic_host = NULL;
+
+/*
+ * In this implementation, "virq" == "IRQ plug number",
+ * "(irq_hw_number_t)hwirq" == "IRQ outlet number".
+ */
+
+/* assumption: locked */
+static inline void beatic_update_irq_mask(unsigned int irq_plug)
+{
+ int off;
+ unsigned long masks[4];
+
+ off = (irq_plug / 256) * 4;
+ masks[0] = beatic_irq_mask_enable[off + 0]
+ & beatic_irq_mask_ack[off + 0];
+ masks[1] = beatic_irq_mask_enable[off + 1]
+ & beatic_irq_mask_ack[off + 1];
+ masks[2] = beatic_irq_mask_enable[off + 2]
+ & beatic_irq_mask_ack[off + 2];
+ masks[3] = beatic_irq_mask_enable[off + 3]
+ & beatic_irq_mask_ack[off + 3];
+ if (beat_set_interrupt_mask(irq_plug&~255UL,
+ masks[0], masks[1], masks[2], masks[3]) != 0)
+ panic("Failed to set mask IRQ!");
+}
+
+static void beatic_mask_irq(unsigned int irq_plug)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&beatic_irq_mask_lock, flags);
+ beatic_irq_mask_enable[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
+ beatic_update_irq_mask(irq_plug);
+ spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
+}
+
+static void beatic_unmask_irq(unsigned int irq_plug)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&beatic_irq_mask_lock, flags);
+ beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
+ beatic_update_irq_mask(irq_plug);
+ spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
+}
+
+static void beatic_ack_irq(unsigned int irq_plug)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&beatic_irq_mask_lock, flags);
+ beatic_irq_mask_ack[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
+ beatic_update_irq_mask(irq_plug);
+ spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
+}
+
+static void beatic_end_irq(unsigned int irq_plug)
+{
+ s64 err;
+ unsigned long flags;
+
+ if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) {
+ if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */
+ panic("Failed to downcount IRQ! Error = %16lx", err);
+
+ printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug);
+ }
+ spin_lock_irqsave(&beatic_irq_mask_lock, flags);
+ beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
+ beatic_update_irq_mask(irq_plug);
+ spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
+}
+
+static struct irq_chip beatic_pic = {
+ .typename = " CELL-BEAT ",
+ .unmask = beatic_unmask_irq,
+ .mask = beatic_mask_irq,
+ .eoi = beatic_end_irq,
+};
+
+/*
+ * Dispose binding hardware IRQ number (hw) and Virtuql IRQ number (virq),
+ * update flags.
+ *
+ * Note that the number (virq) is already assigned at upper layer.
+ */
+static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq)
+{
+ beat_destruct_irq_plug(virq);
+}
+
+/*
+ * Create or update binding hardware IRQ number (hw) and Virtuql
+ * IRQ number (virq). This is called only once for a given mapping.
+ *
+ * Note that the number (virq) is already assigned at upper layer.
+ */
+static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct irq_desc *desc = get_irq_desc(virq);
+ int64_t err;
+
+ if ((err = beat_construct_and_connect_irq_plug(virq, hw)) < 0)
+ return -EIO;
+
+ desc->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(virq, &beatic_pic, handle_fasteoi_irq);
+ return 0;
+}
+
+/*
+ * Update binding hardware IRQ number (hw) and Virtuql
+ * IRQ number (virq). This is called only once for a given mapping.
+ */
+static void beatic_pic_host_remap(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ beat_construct_and_connect_irq_plug(virq, hw);
+}
+
+/*
+ * Translate device-tree interrupt spec to irq_hw_number_t style (ulong),
+ * to pass away to irq_create_mapping().
+ *
+ * Called from irq_create_of_mapping() only.
+ * Note: We have only 1 entry to translate.
+ */
+static int beatic_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)
+{
+ u64 *intspec2 = (u64 *)intspec;
+
+ *out_hwirq = *intspec2;
+ *out_flags |= IRQ_TYPE_LEVEL_LOW;
+ return 0;
+}
+
+static struct irq_host_ops beatic_pic_host_ops = {
+ .map = beatic_pic_host_map,
+ .remap = beatic_pic_host_remap,
+ .unmap = beatic_pic_host_unmap,
+ .xlate = beatic_pic_host_xlate,
+};
+
+/*
+ * Get an IRQ number
+ * Note: returns VIRQ
+ */
+static inline unsigned int beatic_get_irq_plug(void)
+{
+ int i;
+ uint64_t pending[4], ub;
+
+ for (i = 0; i < MAX_IRQS; i += 256) {
+ beat_detect_pending_interrupts(i, pending);
+ __asm__ ("cntlzd %0,%1":"=r"(ub):
+ "r"(pending[0] & beatic_irq_mask_enable[i/64+0]
+ & beatic_irq_mask_ack[i/64+0]));
+ if (ub != 64)
+ return i + ub + 0;
+ __asm__ ("cntlzd %0,%1":"=r"(ub):
+ "r"(pending[1] & beatic_irq_mask_enable[i/64+1]
+ & beatic_irq_mask_ack[i/64+1]));
+ if (ub != 64)
+ return i + ub + 64;
+ __asm__ ("cntlzd %0,%1":"=r"(ub):
+ "r"(pending[2] & beatic_irq_mask_enable[i/64+2]
+ & beatic_irq_mask_ack[i/64+2]));
+ if (ub != 64)
+ return i + ub + 128;
+ __asm__ ("cntlzd %0,%1":"=r"(ub):
+ "r"(pending[3] & beatic_irq_mask_enable[i/64+3]
+ & beatic_irq_mask_ack[i/64+3]));
+ if (ub != 64)
+ return i + ub + 192;
+ }
+
+ return NO_IRQ;
+}
+unsigned int beatic_get_irq(void)
+{
+ unsigned int ret;
+
+ ret = beatic_get_irq_plug();
+ if (ret != NO_IRQ)
+ beatic_ack_irq(ret);
+ return ret;
+}
+
+/*
+ */
+void __init beatic_init_IRQ(void)
+{
+ int i;
+
+ memset(beatic_irq_mask_enable, 0, sizeof(beatic_irq_mask_enable));
+ memset(beatic_irq_mask_ack, 255, sizeof(beatic_irq_mask_ack));
+ for (i = 0; i < MAX_IRQS; i += 256)
+ beat_set_interrupt_mask(i, 0L, 0L, 0L, 0L);
+
+ /* Set out get_irq function */
+ ppc_md.get_irq = beatic_get_irq;
+
+ /* Allocate an irq host */
+ beatic_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0,
+ &beatic_pic_host_ops,
+ 0);
+ BUG_ON(beatic_host == NULL);
+ irq_set_default_host(beatic_host);
+}
+
+#ifdef CONFIG_SMP
+
+/* Nullified to compile with SMP mode */
+void beatic_setup_cpu(int cpu)
+{
+}
+
+void beatic_cause_IPI(int cpu, int mesg)
+{
+}
+
+void beatic_request_IPIs(void)
+{
+}
+#endif /* CONFIG_SMP */
+
+void beatic_deinit_IRQ(void)
+{
+ int i;
+
+ for (i = 1; i < NR_IRQS; i++)
+ beat_destruct_irq_plug(i);
+}
diff --git a/arch/powerpc/platforms/celleb/interrupt.h b/arch/powerpc/platforms/celleb/interrupt.h
new file mode 100644
index 00000000000..b470fd0051f
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/interrupt.h
@@ -0,0 +1,33 @@
+/*
+ * Celleb/Beat Interrupt controller
+ *
+ * (C) Copyright 2006 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef ASM_BEAT_PIC_H
+#define ASM_BEAT_PIC_H
+#ifdef __KERNEL__
+
+extern void beatic_init_IRQ(void);
+extern unsigned int beatic_get_irq(void);
+extern void beatic_cause_IPI(int cpu, int mesg);
+extern void beatic_request_IPIs(void);
+extern void beatic_setup_cpu(int);
+extern void beatic_deinit_IRQ(void);
+
+#endif
+#endif /* ASM_BEAT_PIC_H */
diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/celleb/iommu.c
new file mode 100644
index 00000000000..f63b94c6535
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/iommu.c
@@ -0,0 +1,104 @@
+/*
+ * Support for IOMMU on Celleb platform.
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+
+#include <asm/of_platform.h>
+
+#include "beat_wrapper.h"
+
+#define DMA_FLAGS 0xf800000000000000UL /* r/w permitted, coherency required,
+ strongest order */
+
+static int __init find_dma_window(u64 *io_space_id, u64 *ioid,
+ u64 *base, u64 *size, u64 *io_page_size)
+{
+ struct device_node *dn;
+ const unsigned long *dma_window;
+
+ for_each_node_by_type(dn, "ioif") {
+ dma_window = get_property(dn, "toshiba,dma-window", NULL);
+ if (dma_window) {
+ *io_space_id = (dma_window[0] >> 32) & 0xffffffffUL;
+ *ioid = dma_window[0] & 0x7ffUL;
+ *base = dma_window[1];
+ *size = dma_window[2];
+ *io_page_size = 1 << dma_window[3];
+ of_node_put(dn);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void __init celleb_init_direct_mapping(void)
+{
+ u64 lpar_addr, io_addr;
+ u64 io_space_id, ioid, dma_base, dma_size, io_page_size;
+
+ if (!find_dma_window(&io_space_id, &ioid, &dma_base, &dma_size,
+ &io_page_size)) {
+ pr_info("No dma window found !\n");
+ return;
+ }
+
+ for (lpar_addr = 0; lpar_addr < dma_size; lpar_addr += io_page_size) {
+ io_addr = lpar_addr + dma_base;
+ (void)beat_put_iopte(io_space_id, io_addr, lpar_addr,
+ ioid, DMA_FLAGS);
+ }
+
+ dma_direct_offset = dma_base;
+}
+
+static int celleb_of_bus_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+
+ /* We are only intereted in device addition */
+ if (action != BUS_NOTIFY_ADD_DEVICE)
+ return 0;
+
+ dev->archdata.dma_ops = pci_dma_ops;
+
+ return 0;
+}
+
+static struct notifier_block celleb_of_bus_notifier = {
+ .notifier_call = celleb_of_bus_notify
+};
+
+static int __init celleb_init_iommu(void)
+{
+ if (!machine_is(celleb))
+ return -ENODEV;
+
+ celleb_init_direct_mapping();
+ pci_dma_ops = &dma_direct_ops;
+ bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier);
+
+ return 0;
+}
+
+arch_initcall(celleb_init_iommu);
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c
new file mode 100644
index 00000000000..98de836dfed
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/pci.c
@@ -0,0 +1,481 @@
+/*
+ * Support for PCI on Celleb platform.
+ *
+ * (C) Copyright 2006-2007 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/kernel/rtas_pci.c:
+ * Copyright (C) 2001 Dave Engebretsen, IBM Corporation
+ * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/threads.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/pci_regs.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+#include "pci.h"
+#include "interrupt.h"
+
+#define MAX_PCI_DEVICES 32
+#define MAX_PCI_FUNCTIONS 8
+#define MAX_PCI_BASE_ADDRS 3 /* use 64 bit address */
+
+/* definition for fake pci configuration area for GbE, .... ,and etc. */
+
+struct celleb_pci_resource {
+ struct resource r[MAX_PCI_BASE_ADDRS];
+};
+
+struct celleb_pci_private {
+ unsigned char *fake_config[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS];
+ struct celleb_pci_resource *res[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS];
+};
+
+static inline u8 celleb_fake_config_readb(void *addr)
+{
+ u8 *p = addr;
+ return *p;
+}
+
+static inline u16 celleb_fake_config_readw(void *addr)
+{
+ __le16 *p = addr;
+ return le16_to_cpu(*p);
+}
+
+static inline u32 celleb_fake_config_readl(void *addr)
+{
+ __le32 *p = addr;
+ return le32_to_cpu(*p);
+}
+
+static inline void celleb_fake_config_writeb(u32 val, void *addr)
+{
+ u8 *p = addr;
+ *p = val;
+}
+
+static inline void celleb_fake_config_writew(u32 val, void *addr)
+{
+ __le16 val16;
+ __le16 *p = addr;
+ val16 = cpu_to_le16(val);
+ *p = val16;
+}
+
+static inline void celleb_fake_config_writel(u32 val, void *addr)
+{
+ __le32 val32;
+ __le32 *p = addr;
+ val32 = cpu_to_le32(val);
+ *p = val32;
+}
+
+static unsigned char *get_fake_config_start(struct pci_controller *hose,
+ int devno, int fn)
+{
+ struct celleb_pci_private *private = hose->private_data;
+
+ if (private == NULL)
+ return NULL;
+
+ return private->fake_config[devno][fn];
+}
+
+static struct celleb_pci_resource *get_resource_start(
+ struct pci_controller *hose,
+ int devno, int fn)
+{
+ struct celleb_pci_private *private = hose->private_data;
+
+ if (private == NULL)
+ return NULL;
+
+ return private->res[devno][fn];
+}
+
+
+static void celleb_config_read_fake(unsigned char *config, int where,
+ int size, u32 *val)
+{
+ char *p = config + where;
+
+ switch (size) {
+ case 1:
+ *val = celleb_fake_config_readb(p);
+ break;
+ case 2:
+ *val = celleb_fake_config_readw(p);
+ break;
+ case 4:
+ *val = celleb_fake_config_readl(p);
+ break;
+ }
+
+ return;
+}
+
+static void celleb_config_write_fake(unsigned char *config, int where,
+ int size, u32 val)
+{
+ char *p = config + where;
+
+ switch (size) {
+ case 1:
+ celleb_fake_config_writeb(val, p);
+ break;
+ case 2:
+ celleb_fake_config_writew(val, p);
+ break;
+ case 4:
+ celleb_fake_config_writel(val, p);
+ break;
+ }
+ return;
+}
+
+static int celleb_fake_pci_read_config(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 *val)
+{
+ char *config;
+ struct device_node *node;
+ struct pci_controller *hose;
+ unsigned int devno = devfn >> 3;
+ unsigned int fn = devfn & 0x7;
+
+ /* allignment check */
+ BUG_ON(where % size);
+
+ pr_debug(" fake read: bus=0x%x, ", bus->number);
+ node = (struct device_node *)bus->sysdata;
+ hose = pci_find_hose_for_OF_device(node);
+ config = get_fake_config_start(hose, devno, fn);
+
+ pr_debug("devno=0x%x, where=0x%x, size=0x%x, ", devno, where, size);
+ if (!config) {
+ pr_debug("failed\n");
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ celleb_config_read_fake(config, where, size, val);
+ pr_debug("val=0x%x\n", *val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int celleb_fake_pci_write_config(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 val)
+{
+ char *config;
+ struct device_node *node;
+ struct pci_controller *hose;
+ struct celleb_pci_resource *res;
+ unsigned int devno = devfn >> 3;
+ unsigned int fn = devfn & 0x7;
+
+ /* allignment check */
+ BUG_ON(where % size);
+
+ node = (struct device_node *)bus->sysdata;
+ hose = pci_find_hose_for_OF_device(node);
+ config = get_fake_config_start(hose, devno, fn);
+
+ if (!config)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (val == ~0) {
+ int i = (where - PCI_BASE_ADDRESS_0) >> 3;
+
+ switch (where) {
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_2:
+ if (size != 4)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ res = get_resource_start(hose, devno, fn);
+ if (!res)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ celleb_config_write_fake(config, where, size,
+ (res->r[i].end - res->r[i].start));
+ return PCIBIOS_SUCCESSFUL;
+ case PCI_BASE_ADDRESS_1:
+ case PCI_BASE_ADDRESS_3:
+ case PCI_BASE_ADDRESS_4:
+ case PCI_BASE_ADDRESS_5:
+ break;
+ default:
+ break;
+ }
+ }
+
+ celleb_config_write_fake(config, where, size, val);
+ pr_debug(" fake write: where=%x, size=%d, val=%x\n",
+ where, size, val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops celleb_fake_pci_ops = {
+ celleb_fake_pci_read_config,
+ celleb_fake_pci_write_config
+};
+
+static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose,
+ unsigned int devno, unsigned int fn,
+ unsigned int num_base_addr)
+{
+ u32 val;
+ unsigned char *config;
+ struct celleb_pci_resource *res;
+
+ config = get_fake_config_start(hose, devno, fn);
+ res = get_resource_start(hose, devno, fn);
+
+ if (!config || !res)
+ return;
+
+ switch (num_base_addr) {
+ case 3:
+ val = (res->r[2].start & 0xfffffff0)
+ | PCI_BASE_ADDRESS_MEM_TYPE_64;
+ celleb_config_write_fake(config, PCI_BASE_ADDRESS_4, 4, val);
+ val = res->r[2].start >> 32;
+ celleb_config_write_fake(config, PCI_BASE_ADDRESS_5, 4, val);
+ /* FALLTHROUGH */
+ case 2:
+ val = (res->r[1].start & 0xfffffff0)
+ | PCI_BASE_ADDRESS_MEM_TYPE_64;
+ celleb_config_write_fake(config, PCI_BASE_ADDRESS_2, 4, val);
+ val = res->r[1].start >> 32;
+ celleb_config_write_fake(config, PCI_BASE_ADDRESS_3, 4, val);
+ /* FALLTHROUGH */
+ case 1:
+ val = (res->r[0].start & 0xfffffff0)
+ | PCI_BASE_ADDRESS_MEM_TYPE_64;
+ celleb_config_write_fake(config, PCI_BASE_ADDRESS_0, 4, val);
+ val = res->r[0].start >> 32;
+ celleb_config_write_fake(config, PCI_BASE_ADDRESS_1, 4, val);
+ break;
+ }
+
+ val = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ celleb_config_write_fake(config, PCI_COMMAND, 2, val);
+}
+
+static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
+ struct pci_controller *hose)
+{
+ unsigned int rlen;
+ int num_base_addr = 0;
+ u32 val;
+ const u32 *wi0, *wi1, *wi2, *wi3, *wi4;
+ unsigned int devno, fn;
+ struct celleb_pci_private *private = hose->private_data;
+ unsigned char **config = NULL;
+ struct celleb_pci_resource **res = NULL;
+ const char *name;
+ const unsigned long *li;
+ int size, result;
+
+ if (private == NULL) {
+ printk(KERN_ERR "PCI: "
+ "memory space for pci controller is not assigned\n");
+ goto error;
+ }
+
+ name = get_property(node, "model", &rlen);
+ if (!name) {
+ printk(KERN_ERR "PCI: model property not found.\n");
+ goto error;
+ }
+
+ wi4 = get_property(node, "reg", &rlen);
+ if (wi4 == NULL)
+ goto error;
+
+ devno = ((wi4[0] >> 8) & 0xff) >> 3;
+ fn = (wi4[0] >> 8) & 0x7;
+
+ pr_debug("PCI: celleb_setup_fake_pci() %s devno=%x fn=%x\n", name,
+ devno, fn);
+
+ size = 256;
+ config = &private->fake_config[devno][fn];
+ if (mem_init_done)
+ *config = kzalloc(size, GFP_KERNEL);
+ else
+ *config = alloc_bootmem(size);
+ if (*config == NULL) {
+ printk(KERN_ERR "PCI: "
+ "not enough memory for fake configuration space\n");
+ goto error;
+ }
+ pr_debug("PCI: fake config area assigned 0x%016lx\n",
+ (unsigned long)*config);
+
+ size = sizeof(struct celleb_pci_resource);
+ res = &private->res[devno][fn];
+ if (mem_init_done)
+ *res = kzalloc(size, GFP_KERNEL);
+ else
+ *res = alloc_bootmem(size);
+ if (*res == NULL) {
+ printk(KERN_ERR
+ "PCI: not enough memory for resource data space\n");
+ goto error;
+ }
+ pr_debug("PCI: res assigned 0x%016lx\n", (unsigned long)*res);
+
+ wi0 = get_property(node, "device-id", NULL);
+ wi1 = get_property(node, "vendor-id", NULL);
+ wi2 = get_property(node, "class-code", NULL);
+ wi3 = get_property(node, "revision-id", NULL);
+
+ celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff);
+ celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff);
+ pr_debug("class-code = 0x%08x\n", wi2[0]);
+
+ celleb_config_write_fake(*config, PCI_CLASS_PROG, 1, wi2[0] & 0xff);
+ celleb_config_write_fake(*config, PCI_CLASS_DEVICE, 2,
+ (wi2[0] >> 8) & 0xffff);
+ celleb_config_write_fake(*config, PCI_REVISION_ID, 1, wi3[0]);
+
+ while (num_base_addr < MAX_PCI_BASE_ADDRS) {
+ result = of_address_to_resource(node,
+ num_base_addr, &(*res)->r[num_base_addr]);
+ if (result)
+ break;
+ num_base_addr++;
+ }
+
+ celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr);
+
+ li = get_property(node, "interrupts", &rlen);
+ val = li[0];
+ celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1);
+ celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val);
+
+#ifdef DEBUG
+ pr_debug("PCI: %s irq=%ld\n", name, li[0]);
+ for (i = 0; i < 6; i++) {
+ celleb_config_read_fake(*config,
+ PCI_BASE_ADDRESS_0 + 0x4 * i, 4,
+ &val);
+ pr_debug("PCI: %s fn=%d base_address_%d=0x%x\n",
+ name, fn, i, val);
+ }
+#endif
+
+ celleb_config_write_fake(*config, PCI_HEADER_TYPE, 1,
+ PCI_HEADER_TYPE_NORMAL);
+
+ return 0;
+
+error:
+ if (mem_init_done) {
+ if (config && *config)
+ kfree(*config);
+ if (res && *res)
+ kfree(*res);
+
+ } else {
+ if (config && *config) {
+ size = 256;
+ free_bootmem((unsigned long)(*config), size);
+ }
+ if (res && *res) {
+ size = sizeof(struct celleb_pci_resource);
+ free_bootmem((unsigned long)(*res), size);
+ }
+ }
+
+ return 1;
+}
+
+static int __devinit phb_set_bus_ranges(struct device_node *dev,
+ struct pci_controller *phb)
+{
+ const int *bus_range;
+ unsigned int len;
+
+ bus_range = get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int))
+ return 1;
+
+ phb->first_busno = bus_range[0];
+ phb->last_busno = bus_range[1];
+
+ return 0;
+}
+
+static void __devinit celleb_alloc_private_mem(struct pci_controller *hose)
+{
+ if (mem_init_done)
+ hose->private_data =
+ kzalloc(sizeof(struct celleb_pci_private), GFP_KERNEL);
+ else
+ hose->private_data =
+ alloc_bootmem(sizeof(struct celleb_pci_private));
+}
+
+int __devinit celleb_setup_phb(struct pci_controller *phb)
+{
+ const char *name;
+ struct device_node *dev = phb->arch_data;
+ struct device_node *node;
+ unsigned int rlen;
+
+ name = get_property(dev, "name", &rlen);
+ if (!name)
+ return 1;
+
+ pr_debug("PCI: celleb_setup_phb() %s\n", name);
+ phb_set_bus_ranges(dev, phb);
+
+ if (strcmp(name, "epci") == 0) {
+ phb->ops = &celleb_epci_ops;
+ return celleb_setup_epci(dev, phb);
+
+ } else if (strcmp(name, "pci-pseudo") == 0) {
+ phb->ops = &celleb_fake_pci_ops;
+ celleb_alloc_private_mem(phb);
+ for (node = of_get_next_child(dev, NULL);
+ node != NULL; node = of_get_next_child(dev, node))
+ celleb_setup_fake_pci_device(node, phb);
+
+ } else
+ return 1;
+
+ return 0;
+}
+
+int celleb_pci_probe_mode(struct pci_bus *bus)
+{
+ return PCI_PROBE_DEVTREE;
+}
diff --git a/arch/powerpc/platforms/celleb/pci.h b/arch/powerpc/platforms/celleb/pci.h
new file mode 100644
index 00000000000..5340e348e29
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/pci.h
@@ -0,0 +1,35 @@
+/*
+ * pci prototypes for Celleb platform
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CELLEB_PCI_H
+#define _CELLEB_PCI_H
+
+#include <linux/pci.h>
+
+#include <asm/pci-bridge.h>
+#include <asm/prom.h>
+
+extern int celleb_setup_phb(struct pci_controller *);
+extern int celleb_pci_probe_mode(struct pci_bus *);
+
+extern struct pci_ops celleb_epci_ops;
+extern int celleb_setup_epci(struct device_node *, struct pci_controller *);
+
+#endif /* _CELLEB_PCI_H */
diff --git a/arch/powerpc/platforms/celleb/scc.h b/arch/powerpc/platforms/celleb/scc.h
new file mode 100644
index 00000000000..e9ce8a7c188
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc.h
@@ -0,0 +1,145 @@
+/*
+ * SCC (Super Companion Chip) definitions
+ *
+ * (C) Copyright 2004-2006 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CELLEB_SCC_H
+#define _CELLEB_SCC_H
+
+#define PCI_VENDOR_ID_TOSHIBA_2 0x102f
+#define PCI_DEVICE_ID_TOSHIBA_SCC_PCIEXC_BRIDGE 0x01b0
+#define PCI_DEVICE_ID_TOSHIBA_SCC_EPCI_BRIDGE 0x01b1
+#define PCI_DEVICE_ID_TOSHIBA_SCC_BRIDGE 0x01b2
+#define PCI_DEVICE_ID_TOSHIBA_SCC_GBE 0x01b3
+#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4
+#define PCI_DEVICE_ID_TOSHIBA_SCC_USB2 0x01b5
+#define PCI_DEVICE_ID_TOSHIBA_SCC_USB 0x01b6
+#define PCI_DEVICE_ID_TOSHIBA_SCC_ENCDEC 0x01b7
+
+#define SCC_EPCI_REG 0x0000d000
+
+/* EPCI registers */
+#define SCC_EPCI_CNF10_REG 0x010
+#define SCC_EPCI_CNF14_REG 0x014
+#define SCC_EPCI_CNF18_REG 0x018
+#define SCC_EPCI_PVBAT 0x100
+#define SCC_EPCI_VPMBAT 0x104
+#define SCC_EPCI_VPIBAT 0x108
+#define SCC_EPCI_VCSR 0x110
+#define SCC_EPCI_VIENAB 0x114
+#define SCC_EPCI_VISTAT 0x118
+#define SCC_EPCI_VRDCOUNT 0x124
+#define SCC_EPCI_BAM0 0x12c
+#define SCC_EPCI_BAM1 0x134
+#define SCC_EPCI_BAM2 0x13c
+#define SCC_EPCI_IADR 0x164
+#define SCC_EPCI_CLKRST 0x800
+#define SCC_EPCI_INTSET 0x804
+#define SCC_EPCI_STATUS 0x808
+#define SCC_EPCI_ABTSET 0x80c
+#define SCC_EPCI_WATRP 0x810
+#define SCC_EPCI_DUMMYRADR 0x814
+#define SCC_EPCI_SWRESP 0x818
+#define SCC_EPCI_CNTOPT 0x81c
+#define SCC_EPCI_ECMODE 0xf00
+#define SCC_EPCI_IOM_AC_NUM 5
+#define SCC_EPCI_IOM_ACTE(n) (0xf10 + (n) * 4)
+#define SCC_EPCI_IOT_AC_NUM 4
+#define SCC_EPCI_IOT_ACTE(n) (0xf30 + (n) * 4)
+#define SCC_EPCI_MAEA 0xf50
+#define SCC_EPCI_MAEC 0xf54
+#define SCC_EPCI_CKCTRL 0xff0
+
+/* bits for SCC_EPCI_VCSR */
+#define SCC_EPCI_VCSR_FRE 0x00020000
+#define SCC_EPCI_VCSR_FWE 0x00010000
+#define SCC_EPCI_VCSR_DR 0x00000400
+#define SCC_EPCI_VCSR_SR 0x00000008
+#define SCC_EPCI_VCSR_AT 0x00000004
+
+/* bits for SCC_EPCI_VIENAB/SCC_EPCI_VISTAT */
+#define SCC_EPCI_VISTAT_PMPE 0x00000008
+#define SCC_EPCI_VISTAT_PMFE 0x00000004
+#define SCC_EPCI_VISTAT_PRA 0x00000002
+#define SCC_EPCI_VISTAT_PRD 0x00000001
+#define SCC_EPCI_VISTAT_ALL 0x0000000f
+
+#define SCC_EPCI_VIENAB_PMPEE 0x00000008
+#define SCC_EPCI_VIENAB_PMFEE 0x00000004
+#define SCC_EPCI_VIENAB_PRA 0x00000002
+#define SCC_EPCI_VIENAB_PRD 0x00000001
+#define SCC_EPCI_VIENAB_ALL 0x0000000f
+
+/* bits for SCC_EPCI_CLKRST */
+#define SCC_EPCI_CLKRST_CKS_MASK 0x00030000
+#define SCC_EPCI_CLKRST_CKS_2 0x00000000
+#define SCC_EPCI_CLKRST_CKS_4 0x00010000
+#define SCC_EPCI_CLKRST_CKS_8 0x00020000
+#define SCC_EPCI_CLKRST_PCICRST 0x00000400
+#define SCC_EPCI_CLKRST_BC 0x00000200
+#define SCC_EPCI_CLKRST_PCIRST 0x00000100
+#define SCC_EPCI_CLKRST_PCKEN 0x00000001
+
+/* bits for SCC_EPCI_INTSET/SCC_EPCI_STATUS */
+#define SCC_EPCI_INT_2M 0x01000000
+#define SCC_EPCI_INT_RERR 0x00200000
+#define SCC_EPCI_INT_SERR 0x00100000
+#define SCC_EPCI_INT_PRTER 0x00080000
+#define SCC_EPCI_INT_SER 0x00040000
+#define SCC_EPCI_INT_PER 0x00020000
+#define SCC_EPCI_INT_PAI 0x00010000
+#define SCC_EPCI_INT_1M 0x00000100
+#define SCC_EPCI_INT_PME 0x00000010
+#define SCC_EPCI_INT_INTD 0x00000008
+#define SCC_EPCI_INT_INTC 0x00000004
+#define SCC_EPCI_INT_INTB 0x00000002
+#define SCC_EPCI_INT_INTA 0x00000001
+#define SCC_EPCI_INT_DEVINT 0x0000000f
+#define SCC_EPCI_INT_ALL 0x003f001f
+#define SCC_EPCI_INT_ALLERR 0x003f0000
+
+/* bits for SCC_EPCI_CKCTRL */
+#define SCC_EPCI_CKCTRL_CRST0 0x00010000
+#define SCC_EPCI_CKCTRL_CRST1 0x00020000
+#define SCC_EPCI_CKCTRL_OCLKEN 0x00000100
+#define SCC_EPCI_CKCTRL_LCLKEN 0x00000001
+
+#define SCC_EPCI_IDSEL_AD_TO_SLOT(ad) ((ad) - 10)
+#define SCC_EPCI_MAX_DEVNU SCC_EPCI_IDSEL_AD_TO_SLOT(32)
+
+/* bits for SCC_EPCI_CNTOPT */
+#define SCC_EPCI_CNTOPT_O2PMB 0x00000002
+
+/* UHC registers */
+#define SCC_UHC_CKRCTRL 0xff0
+#define SCC_UHC_ECMODE 0xf00
+
+/* bits for SCC_UHC_CKRCTRL */
+#define SCC_UHC_F48MCKLEN 0x00000001
+#define SCC_UHC_P_SUSPEND 0x00000002
+#define SCC_UHC_PHY_SUSPEND_SEL 0x00000004
+#define SCC_UHC_HCLKEN 0x00000100
+#define SCC_UHC_USBEN 0x00010000
+#define SCC_UHC_USBCEN 0x00020000
+#define SCC_UHC_PHYEN 0x00040000
+
+/* bits for SCC_UHC_ECMODE */
+#define SCC_UHC_ECMODE_BY_BYTE 0x00000555
+#define SCC_UHC_ECMODE_BY_WORD 0x00000aaa
+
+#endif /* _CELLEB_SCC_H */
diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c
new file mode 100644
index 00000000000..c11b39c3776
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc_epci.c
@@ -0,0 +1,409 @@
+/*
+ * Support for SCC external PCI
+ *
+ * (C) Copyright 2004-2007 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/threads.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/pci_regs.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+#include "scc.h"
+#include "pci.h"
+#include "interrupt.h"
+
+#define MAX_PCI_DEVICES 32
+#define MAX_PCI_FUNCTIONS 8
+
+#define iob() __asm__ __volatile__("eieio; sync":::"memory")
+
+
+#if 0 /* test code for epci dummy read */
+static void celleb_epci_dummy_read(struct pci_dev *dev)
+{
+ void __iomem *epci_base;
+ struct device_node *node;
+ struct pci_controller *hose;
+ u32 val;
+
+ node = (struct device_node *)dev->bus->sysdata;
+ hose = pci_find_hose_for_OF_device(node);
+
+ if (!hose)
+ return;
+
+ epci_base = hose->cfg_addr;
+
+ val = in_be32(epci_base + SCC_EPCI_WATRP);
+ iosync();
+
+ return;
+}
+#endif
+
+static inline void clear_and_disable_master_abort_interrupt(
+ struct pci_controller *hose)
+{
+ void __iomem *addr;
+ addr = hose->cfg_addr + PCI_COMMAND;
+ out_be32(addr, in_be32(addr) | (PCI_STATUS_REC_MASTER_ABORT << 16));
+}
+
+static int celleb_epci_check_abort(struct pci_controller *hose,
+ void __iomem *addr)
+{
+ void __iomem *reg, *epci_base;
+ u32 val;
+
+ iob();
+ epci_base = hose->cfg_addr;
+
+ reg = epci_base + PCI_COMMAND;
+ val = in_be32(reg);
+
+ if (val & (PCI_STATUS_REC_MASTER_ABORT << 16)) {
+ out_be32(reg,
+ (val & 0xffff) | (PCI_STATUS_REC_MASTER_ABORT << 16));
+
+ /* clear PCI Controller error, FRE, PMFE */
+ reg = epci_base + SCC_EPCI_STATUS;
+ out_be32(reg, SCC_EPCI_INT_PAI);
+
+ reg = epci_base + SCC_EPCI_VCSR;
+ val = in_be32(reg) & 0xffff;
+ val |= SCC_EPCI_VCSR_FRE;
+ out_be32(reg, val);
+
+ reg = epci_base + SCC_EPCI_VISTAT;
+ out_be32(reg, SCC_EPCI_VISTAT_PMFE);
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static void __iomem *celleb_epci_make_config_addr(struct pci_controller *hose,
+ unsigned int devfn, int where)
+{
+ void __iomem *addr;
+ struct pci_bus *bus = hose->bus;
+
+ if (bus->self)
+ addr = hose->cfg_data +
+ (((bus->number & 0xff) << 16)
+ | ((devfn & 0xff) << 8)
+ | (where & 0xff)
+ | 0x01000000);
+ else
+ addr = hose->cfg_data +
+ (((devfn & 0xff) << 8) | (where & 0xff));
+
+ pr_debug("EPCI: config_addr = 0x%p\n", addr);
+
+ return addr;
+}
+
+static int celleb_epci_read_config(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 * val)
+{
+ void __iomem *addr;
+ struct device_node *node;
+ struct pci_controller *hose;
+
+ /* allignment check */
+ BUG_ON(where % size);
+
+ node = (struct device_node *)bus->sysdata;
+ hose = pci_find_hose_for_OF_device(node);
+
+ if (!hose->cfg_data)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (bus->number == hose->first_busno && devfn == 0) {
+ /* EPCI controller self */
+
+ addr = hose->cfg_addr + where;
+
+ switch (size) {
+ case 1:
+ *val = in_8(addr);
+ break;
+ case 2:
+ *val = in_be16(addr);
+ break;
+ case 4:
+ *val = in_be32(addr);
+ break;
+ default:
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ } else {
+
+ clear_and_disable_master_abort_interrupt(hose);
+ addr = celleb_epci_make_config_addr(hose, devfn, where);
+
+ switch (size) {
+ case 1:
+ *val = in_8(addr);
+ break;
+ case 2:
+ *val = in_le16(addr);
+ break;
+ case 4:
+ *val = in_le32(addr);
+ break;
+ default:
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ }
+
+ pr_debug("EPCI: "
+ "addr=0x%lx, devfn=0x%x, where=0x%x, size=0x%x, val=0x%x\n",
+ addr, devfn, where, size, *val);
+
+ return celleb_epci_check_abort(hose, NULL);
+}
+
+static int celleb_epci_write_config(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 val)
+{
+ void __iomem *addr;
+ struct device_node *node;
+ struct pci_controller *hose;
+
+ /* allignment check */
+ BUG_ON(where % size);
+
+ node = (struct device_node *)bus->sysdata;
+ hose = pci_find_hose_for_OF_device(node);
+
+ if (!hose->cfg_data)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (bus->number == hose->first_busno && devfn == 0) {
+ /* EPCI controller self */
+
+ addr = hose->cfg_addr + where;
+
+ switch (size) {
+ case 1:
+ out_8(addr, val);
+ break;
+ case 2:
+ out_be16(addr, val);
+ break;
+ case 4:
+ out_be32(addr, val);
+ break;
+ default:
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ } else {
+
+ clear_and_disable_master_abort_interrupt(hose);
+ addr = celleb_epci_make_config_addr(hose, devfn, where);
+
+ switch (size) {
+ case 1:
+ out_8(addr, val);
+ break;
+ case 2:
+ out_le16(addr, val);
+ break;
+ case 4:
+ out_le32(addr, val);
+ break;
+ default:
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ }
+
+ return celleb_epci_check_abort(hose, addr);
+}
+
+struct pci_ops celleb_epci_ops = {
+ celleb_epci_read_config,
+ celleb_epci_write_config,
+};
+
+/* to be moved in FW */
+static int __devinit celleb_epci_init(struct pci_controller *hose)
+{
+ u32 val;
+ void __iomem *reg, *epci_base;
+ int hwres = 0;
+
+ epci_base = hose->cfg_addr;
+
+ /* PCI core reset(Internal bus and PCI clock) */
+ reg = epci_base + SCC_EPCI_CKCTRL;
+ val = in_be32(reg);
+ if (val == 0x00030101)
+ hwres = 1;
+ else {
+ val &= ~(SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1);
+ out_be32(reg, val);
+
+ /* set PCI core clock */
+ val = in_be32(reg);
+ val |= (SCC_EPCI_CKCTRL_OCLKEN | SCC_EPCI_CKCTRL_LCLKEN);
+ out_be32(reg, val);
+
+ /* release PCI core reset (internal bus) */
+ val = in_be32(reg);
+ val |= SCC_EPCI_CKCTRL_CRST0;
+ out_be32(reg, val);
+
+ /* set PCI clock select */
+ reg = epci_base + SCC_EPCI_CLKRST;
+ val = in_be32(reg);
+ val &= ~SCC_EPCI_CLKRST_CKS_MASK;
+ val |= SCC_EPCI_CLKRST_CKS_2;
+ out_be32(reg, val);
+
+ /* set arbiter */
+ reg = epci_base + SCC_EPCI_ABTSET;
+ out_be32(reg, 0x0f1f001f); /* temporary value */
+
+ /* buffer on */
+ reg = epci_base + SCC_EPCI_CLKRST;
+ val = in_be32(reg);
+ val |= SCC_EPCI_CLKRST_BC;
+ out_be32(reg, val);
+
+ /* PCI clock enable */
+ val = in_be32(reg);
+ val |= SCC_EPCI_CLKRST_PCKEN;
+ out_be32(reg, val);
+
+ /* release PCI core reset (all) */
+ reg = epci_base + SCC_EPCI_CKCTRL;
+ val = in_be32(reg);
+ val |= (SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1);
+ out_be32(reg, val);
+
+ /* set base translation registers. (already set by Beat) */
+
+ /* set base address masks. (already set by Beat) */
+ }
+
+ /* release interrupt masks and clear all interrupts */
+ reg = epci_base + SCC_EPCI_INTSET;
+ out_be32(reg, 0x013f011f); /* all interrupts enable */
+ reg = epci_base + SCC_EPCI_VIENAB;
+ val = SCC_EPCI_VIENAB_PMPEE | SCC_EPCI_VIENAB_PMFEE;
+ out_be32(reg, val);
+ reg = epci_base + SCC_EPCI_STATUS;
+ out_be32(reg, 0xffffffff);
+ reg = epci_base + SCC_EPCI_VISTAT;
+ out_be32(reg, 0xffffffff);
+
+ /* disable PCI->IB address translation */
+ reg = epci_base + SCC_EPCI_VCSR;
+ val = in_be32(reg);
+ val &= ~(SCC_EPCI_VCSR_DR | SCC_EPCI_VCSR_AT);
+ out_be32(reg, val);
+
+ /* set base addresses. (no need to set?) */
+
+ /* memory space, bus master enable */
+ reg = epci_base + PCI_COMMAND;
+ val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ out_be32(reg, val);
+
+ /* endian mode setup */
+ reg = epci_base + SCC_EPCI_ECMODE;
+ val = 0x00550155;
+ out_be32(reg, val);
+
+ /* set control option */
+ reg = epci_base + SCC_EPCI_CNTOPT;
+ val = in_be32(reg);
+ val |= SCC_EPCI_CNTOPT_O2PMB;
+ out_be32(reg, val);
+
+ /* XXX: temporay: set registers for address conversion setup */
+ reg = epci_base + SCC_EPCI_CNF10_REG;
+ out_be32(reg, 0x80000008);
+ reg = epci_base + SCC_EPCI_CNF14_REG;
+ out_be32(reg, 0x40000008);
+
+ reg = epci_base + SCC_EPCI_BAM0;
+ out_be32(reg, 0x80000000);
+ reg = epci_base + SCC_EPCI_BAM1;
+ out_be32(reg, 0xe0000000);
+
+ reg = epci_base + SCC_EPCI_PVBAT;
+ out_be32(reg, 0x80000000);
+
+ if (!hwres) {
+ /* release external PCI reset */
+ reg = epci_base + SCC_EPCI_CLKRST;
+ val = in_be32(reg);
+ val |= SCC_EPCI_CLKRST_PCIRST;
+ out_be32(reg, val);
+ }
+
+ return 0;
+}
+
+int __devinit celleb_setup_epci(struct device_node *node,
+ struct pci_controller *hose)
+{
+ struct resource r;
+
+ pr_debug("PCI: celleb_setup_epci()\n");
+
+ if (of_address_to_resource(node, 0, &r))
+ goto error;
+ hose->cfg_addr = ioremap(r.start, (r.end - r.start + 1));
+ if (!hose->cfg_addr)
+ goto error;
+ pr_debug("EPCI: cfg_addr map 0x%016lx->0x%016lx + 0x%016lx\n",
+ r.start, (unsigned long)hose->cfg_addr,
+ (r.end - r.start + 1));
+
+ if (of_address_to_resource(node, 2, &r))
+ goto error;
+ hose->cfg_data = ioremap(r.start, (r.end - r.start + 1));
+ if (!hose->cfg_data)
+ goto error;
+ pr_debug("EPCI: cfg_data map 0x%016lx->0x%016lx + 0x%016lx\n",
+ r.start, (unsigned long)hose->cfg_data,
+ (r.end - r.start + 1));
+
+ celleb_epci_init(hose);
+
+ return 0;
+
+error:
+ return 1;
+}
diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/celleb/scc_sio.c
new file mode 100644
index 00000000000..bcd25f54d98
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc_sio.c
@@ -0,0 +1,101 @@
+/*
+ * setup serial port in SCC
+ *
+ * (C) Copyright 2006 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+
+/* sio irq0=0xb00010022 irq0=0xb00010023 irq2=0xb00010024
+ mmio=0xfff000-0x1000,0xff2000-0x1000 */
+static int txx9_serial_bitmap = 0;
+
+static struct {
+ uint32_t offset;
+ uint32_t index;
+} txx9_scc_tab[3] = {
+ { 0x300, 0 }, /* 0xFFF300 */
+ { 0x400, 0 }, /* 0xFFF400 */
+ { 0x800, 1 } /* 0xFF2800 */
+};
+
+static int txx9_serial_init(void)
+{
+ extern int early_serial_txx9_setup(struct uart_port *port);
+ struct device_node *node;
+ int i;
+ struct uart_port req;
+ struct of_irq irq;
+ struct resource res;
+
+ node = of_find_node_by_path("/ioif1/sio");
+ if (!node)
+ return 0;
+
+ for(i = 0; i < sizeof(txx9_scc_tab)/sizeof(txx9_scc_tab[0]); i++) {
+ if (!(txx9_serial_bitmap & (1<<i)))
+ continue;
+
+ if (of_irq_map_one(node, i, &irq))
+ continue;
+ if (of_address_to_resource(node, txx9_scc_tab[i].index, &res))
+ continue;
+
+ memset(&req, 0, sizeof(req));
+ req.line = i;
+ req.iotype = UPIO_MEM;
+ req.mapbase = res.start + txx9_scc_tab[i].offset;
+#ifdef CONFIG_SERIAL_TXX9_CONSOLE
+ req.membase = ioremap(req.mapbase, 0x24);
+#endif
+ req.irq = irq_create_of_mapping(irq.controller,
+ irq.specifier, irq.size);
+ req.flags |= UPF_IOREMAP | UPF_BUGGY_UART /*HAVE_CTS_LINE*/;
+ req.uartclk = 83300000;
+ early_serial_txx9_setup(&req);
+ }
+
+ of_node_put(node);
+ return 0;
+}
+
+static int txx9_serial_config(char *ptr)
+{
+ int i;
+
+ for (;;) {
+ switch(get_option(&ptr, &i)) {
+ default:
+ return 0;
+ case 2:
+ txx9_serial_bitmap |= 1 << i;
+ break;
+ case 1:
+ txx9_serial_bitmap |= 1 << i;
+ return 0;
+ }
+ }
+}
+__setup("txx9_serial=", txx9_serial_config);
+
+console_initcall(txx9_serial_init);
diff --git a/arch/powerpc/platforms/celleb/scc_uhc.c b/arch/powerpc/platforms/celleb/scc_uhc.c
new file mode 100644
index 00000000000..a7c548bde2e
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc_uhc.c
@@ -0,0 +1,94 @@
+/*
+ * SCC (Super Companion Chip) UHC setup
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+
+#include "scc.h"
+
+#define UHC_RESET_WAIT_MAX 10000
+
+static inline int uhc_clkctrl_ready(u32 val)
+{
+ const u32 mask = SCC_UHC_USBCEN | SCC_UHC_USBCEN;
+ return((val & mask) == mask);
+}
+
+/*
+ * UHC(usb host controler) enable function.
+ * affect to both of OHCI and EHCI core module.
+ */
+static void enable_scc_uhc(struct pci_dev *dev)
+{
+ void __iomem *uhc_base;
+ u32 __iomem *uhc_clkctrl;
+ u32 __iomem *uhc_ecmode;
+ u32 val = 0;
+ int i;
+
+ if (!machine_is(celleb))
+ return;
+
+ uhc_base = ioremap(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
+ if (!uhc_base) {
+ printk(KERN_ERR "failed to map UHC register base.\n");
+ return;
+ }
+ uhc_clkctrl = uhc_base + SCC_UHC_CKRCTRL;
+ uhc_ecmode = uhc_base + SCC_UHC_ECMODE;
+
+ /* setup for normal mode */
+ val |= SCC_UHC_F48MCKLEN;
+ out_be32(uhc_clkctrl, val);
+ val |= SCC_UHC_PHY_SUSPEND_SEL;
+ out_be32(uhc_clkctrl, val);
+ udelay(10);
+ val |= SCC_UHC_PHYEN;
+ out_be32(uhc_clkctrl, val);
+ udelay(50);
+
+ /* disable reset */
+ val |= SCC_UHC_HCLKEN;
+ out_be32(uhc_clkctrl, val);
+ val |= (SCC_UHC_USBCEN | SCC_UHC_USBEN);
+ out_be32(uhc_clkctrl, val);
+ i = 0;
+ while (!uhc_clkctrl_ready(in_be32(uhc_clkctrl))) {
+ udelay(10);
+ if (i++ > UHC_RESET_WAIT_MAX) {
+ printk(KERN_ERR "Failed to disable UHC reset %x\n",
+ in_be32(uhc_clkctrl));
+ break;
+ }
+ }
+
+ /* Endian Conversion Mode for Master ALL area */
+ out_be32(uhc_ecmode, SCC_UHC_ECMODE_BY_BYTE);
+
+ iounmap(uhc_base);
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
+ PCI_DEVICE_ID_TOSHIBA_SCC_USB, enable_scc_uhc);
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c
new file mode 100644
index 00000000000..1de63acfda8
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/setup.c
@@ -0,0 +1,191 @@
+/*
+ * Celleb setup code
+ *
+ * (C) Copyright 2006-2007 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/platforms/cell/setup.c:
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * Modified by PPC64 Team, IBM Corp
+ * Modified by Cell Team, IBM Deutschland Entwicklung 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG
+
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/console.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/kexec.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/cputable.h>
+#include <asm/irq.h>
+#include <asm/spu_priv1.h>
+#include <asm/firmware.h>
+#include <asm/of_platform.h>
+
+#include "interrupt.h"
+#include "beat_wrapper.h"
+#include "beat.h"
+#include "pci.h"
+
+static char celleb_machine_type[128] = "Celleb";
+
+static void celleb_show_cpuinfo(struct seq_file *m)
+{
+ struct device_node *root;
+ const char *model = "";
+
+ root = of_find_node_by_path("/");
+ if (root)
+ model = get_property(root, "model", NULL);
+ /* using "CHRP" is to trick anaconda into installing FCx into Celleb */
+ seq_printf(m, "machine\t\t: %s %s\n", celleb_machine_type, model);
+ of_node_put(root);
+}
+
+static int celleb_machine_type_hack(char *ptr)
+{
+ strncpy(celleb_machine_type, ptr, sizeof(celleb_machine_type));
+ celleb_machine_type[sizeof(celleb_machine_type)-1] = 0;
+ return 0;
+}
+
+__setup("celleb_machine_type_hack", celleb_machine_type_hack);
+
+static void celleb_progress(char *s, unsigned short hex)
+{
+ printk("*** %04x : %s\n", hex, s ? s : "");
+}
+
+static void __init celleb_setup_arch(void)
+{
+#ifdef CONFIG_SPU_BASE
+ spu_priv1_ops = &spu_priv1_beat_ops;
+ spu_management_ops = &spu_management_of_ops;
+#endif
+
+#ifdef CONFIG_SMP
+ smp_init_celleb();
+#endif
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000;
+
+ if (ROOT_DEV == 0) {
+ printk("No ramdisk, default root is /dev/hda2\n");
+ ROOT_DEV = Root_HDA2;
+ }
+
+#ifdef CONFIG_DUMMY_CONSOLE
+ conswitchp = &dummy_con;
+#endif
+}
+
+static void beat_power_save(void)
+{
+ beat_pause(0);
+}
+
+static int __init celleb_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ if (!of_flat_dt_is_compatible(root, "Beat"))
+ return 0;
+
+ powerpc_firmware_features |= FW_FEATURE_CELLEB_POSSIBLE;
+ hpte_init_beat();
+ return 1;
+}
+
+/*
+ * Cell has no legacy IO; anything calling this function has to
+ * fail or bad things will happen
+ */
+static int celleb_check_legacy_ioport(unsigned int baseport)
+{
+ return -ENODEV;
+}
+
+static void celleb_kexec_cpu_down(int crash, int secondary)
+{
+ beatic_deinit_IRQ();
+}
+
+static struct of_device_id celleb_bus_ids[] = {
+ { .type = "scc", },
+ { .type = "ioif", }, /* old style */
+ {},
+};
+
+static int __init celleb_publish_devices(void)
+{
+ if (!machine_is(celleb))
+ return 0;
+
+ /* Publish OF platform devices for southbridge IOs */
+ of_platform_bus_probe(NULL, celleb_bus_ids, NULL);
+
+ return 0;
+}
+device_initcall(celleb_publish_devices);
+
+define_machine(celleb) {
+ .name = "Cell Reference Set",
+ .probe = celleb_probe,
+ .setup_arch = celleb_setup_arch,
+ .show_cpuinfo = celleb_show_cpuinfo,
+ .restart = beat_restart,
+ .power_off = beat_power_off,
+ .halt = beat_halt,
+ .get_rtc_time = beat_get_rtc_time,
+ .set_rtc_time = beat_set_rtc_time,
+ .calibrate_decr = generic_calibrate_decr,
+ .check_legacy_ioport = celleb_check_legacy_ioport,
+ .progress = celleb_progress,
+ .power_save = beat_power_save,
+ .nvram_size = beat_nvram_get_size,
+ .nvram_read = beat_nvram_read,
+ .nvram_write = beat_nvram_write,
+ .set_dabr = beat_set_xdabr,
+ .init_IRQ = beatic_init_IRQ,
+ .get_irq = beatic_get_irq,
+ .pci_probe_mode = celleb_pci_probe_mode,
+ .pci_setup_phb = celleb_setup_phb,
+#ifdef CONFIG_KEXEC
+ .kexec_cpu_down = celleb_kexec_cpu_down,
+ .machine_kexec = default_machine_kexec,
+ .machine_kexec_prepare = default_machine_kexec_prepare,
+ .machine_crash_shutdown = default_machine_crash_shutdown,
+#endif
+};
diff --git a/arch/powerpc/platforms/celleb/smp.c b/arch/powerpc/platforms/celleb/smp.c
new file mode 100644
index 00000000000..a7631250aeb
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/smp.c
@@ -0,0 +1,124 @@
+/*
+ * SMP support for Celleb platform. (Incomplete)
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/platforms/cell/smp.c:
+ * Dave Engebretsen, Peter Bergner, and
+ * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
+ * Plus various changes from other IBM teams...
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/threads.h>
+#include <linux/cpu.h>
+
+#include <asm/irq.h>
+#include <asm/smp.h>
+#include <asm/machdep.h>
+#include <asm/udbg.h>
+
+#include "interrupt.h"
+
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+/*
+ * The primary thread of each non-boot processor is recorded here before
+ * smp init.
+ */
+/* static cpumask_t of_spin_map; */
+
+/**
+ * smp_startup_cpu() - start the given cpu
+ *
+ * At boot time, there is nothing to do for primary threads which were
+ * started from Open Firmware. For anything else, call RTAS with the
+ * appropriate start location.
+ *
+ * Returns:
+ * 0 - failure
+ * 1 - success
+ */
+static inline int __devinit smp_startup_cpu(unsigned int lcpu)
+{
+ return 0;
+}
+
+static void smp_beatic_message_pass(int target, int msg)
+{
+ unsigned int i;
+
+ if (target < NR_CPUS) {
+ beatic_cause_IPI(target, msg);
+ } else {
+ for_each_online_cpu(i) {
+ if (target == MSG_ALL_BUT_SELF
+ && i == smp_processor_id())
+ continue;
+ beatic_cause_IPI(i, msg);
+ }
+ }
+}
+
+static int __init smp_beatic_probe(void)
+{
+ return cpus_weight(cpu_possible_map);
+}
+
+static void __devinit smp_beatic_setup_cpu(int cpu)
+{
+ beatic_setup_cpu(cpu);
+}
+
+static void __devinit smp_celleb_kick_cpu(int nr)
+{
+ BUG_ON(nr < 0 || nr >= NR_CPUS);
+
+ if (!smp_startup_cpu(nr))
+ return;
+}
+
+static int smp_celleb_cpu_bootable(unsigned int nr)
+{
+ return 1;
+}
+static struct smp_ops_t bpa_beatic_smp_ops = {
+ .message_pass = smp_beatic_message_pass,
+ .probe = smp_beatic_probe,
+ .kick_cpu = smp_celleb_kick_cpu,
+ .setup_cpu = smp_beatic_setup_cpu,
+ .cpu_bootable = smp_celleb_cpu_bootable,
+};
+
+/* This is called very early */
+void __init smp_init_celleb(void)
+{
+ DBG(" -> smp_init_celleb()\n");
+
+ smp_ops = &bpa_beatic_smp_ops;
+
+ DBG(" <- smp_init_celleb()\n");
+}
diff --git a/arch/powerpc/platforms/celleb/spu_priv1.c b/arch/powerpc/platforms/celleb/spu_priv1.c
new file mode 100644
index 00000000000..2bf6700f747
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/spu_priv1.c
@@ -0,0 +1,208 @@
+/*
+ * spu hypervisor abstraction for Beat
+ *
+ * (C) Copyright 2006-2007 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+
+#include <asm/types.h>
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
+
+#include "beat_wrapper.h"
+
+static inline void _int_mask_set(struct spu *spu, int class, u64 mask)
+{
+ spu->shadow_int_mask_RW[class] = mask;
+ beat_set_irq_mask_for_spe(spu->spe_id, class, mask);
+}
+
+static inline u64 _int_mask_get(struct spu *spu, int class)
+{
+ return spu->shadow_int_mask_RW[class];
+}
+
+static void int_mask_set(struct spu *spu, int class, u64 mask)
+{
+ _int_mask_set(spu, class, mask);
+}
+
+static u64 int_mask_get(struct spu *spu, int class)
+{
+ return _int_mask_get(spu, class);
+}
+
+static void int_mask_and(struct spu *spu, int class, u64 mask)
+{
+ u64 old_mask;
+ old_mask = _int_mask_get(spu, class);
+ _int_mask_set(spu, class, old_mask & mask);
+}
+
+static void int_mask_or(struct spu *spu, int class, u64 mask)
+{
+ u64 old_mask;
+ old_mask = _int_mask_get(spu, class);
+ _int_mask_set(spu, class, old_mask | mask);
+}
+
+static void int_stat_clear(struct spu *spu, int class, u64 stat)
+{
+ beat_clear_interrupt_status_of_spe(spu->spe_id, class, stat);
+}
+
+static u64 int_stat_get(struct spu *spu, int class)
+{
+ u64 int_stat;
+ beat_get_interrupt_status_of_spe(spu->spe_id, class, &int_stat);
+ return int_stat;
+}
+
+static void cpu_affinity_set(struct spu *spu, int cpu)
+{
+ return;
+}
+
+static u64 mfc_dar_get(struct spu *spu)
+{
+ u64 dar;
+ beat_get_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, mfc_dar_RW), &dar);
+ return dar;
+}
+
+static u64 mfc_dsisr_get(struct spu *spu)
+{
+ u64 dsisr;
+ beat_get_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, mfc_dsisr_RW), &dsisr);
+ return dsisr;
+}
+
+static void mfc_dsisr_set(struct spu *spu, u64 dsisr)
+{
+ beat_set_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, mfc_dsisr_RW), dsisr);
+}
+
+static void mfc_sdr_setup(struct spu *spu)
+{
+ return;
+}
+
+static void mfc_sr1_set(struct spu *spu, u64 sr1)
+{
+ beat_set_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, mfc_sr1_RW), sr1);
+}
+
+static u64 mfc_sr1_get(struct spu *spu)
+{
+ u64 sr1;
+ beat_get_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, mfc_sr1_RW), &sr1);
+ return sr1;
+}
+
+static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
+{
+ beat_set_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, mfc_tclass_id_RW), tclass_id);
+}
+
+static u64 mfc_tclass_id_get(struct spu *spu)
+{
+ u64 tclass_id;
+ beat_get_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, mfc_tclass_id_RW), &tclass_id);
+ return tclass_id;
+}
+
+static void tlb_invalidate(struct spu *spu)
+{
+ beat_set_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, tlb_invalidate_entry_W), 0ul);
+}
+
+static void resource_allocation_groupID_set(struct spu *spu, u64 id)
+{
+ beat_set_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, resource_allocation_groupID_RW),
+ id);
+}
+
+static u64 resource_allocation_groupID_get(struct spu *spu)
+{
+ u64 id;
+ beat_get_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, resource_allocation_groupID_RW),
+ &id);
+ return id;
+}
+
+static void resource_allocation_enable_set(struct spu *spu, u64 enable)
+{
+ beat_set_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, resource_allocation_enable_RW),
+ enable);
+}
+
+static u64 resource_allocation_enable_get(struct spu *spu)
+{
+ u64 enable;
+ beat_get_spe_privileged_state_1_registers(
+ spu->spe_id,
+ offsetof(struct spu_priv1, resource_allocation_enable_RW),
+ &enable);
+ return enable;
+}
+
+const struct spu_priv1_ops spu_priv1_beat_ops =
+{
+ .int_mask_and = int_mask_and,
+ .int_mask_or = int_mask_or,
+ .int_mask_set = int_mask_set,
+ .int_mask_get = int_mask_get,
+ .int_stat_clear = int_stat_clear,
+ .int_stat_get = int_stat_get,
+ .cpu_affinity_set = cpu_affinity_set,
+ .mfc_dar_get = mfc_dar_get,
+ .mfc_dsisr_get = mfc_dsisr_get,
+ .mfc_dsisr_set = mfc_dsisr_set,
+ .mfc_sdr_setup = mfc_sdr_setup,
+ .mfc_sr1_set = mfc_sr1_set,
+ .mfc_sr1_get = mfc_sr1_get,
+ .mfc_tclass_id_set = mfc_tclass_id_set,
+ .mfc_tclass_id_get = mfc_tclass_id_get,
+ .tlb_invalidate = tlb_invalidate,
+ .resource_allocation_groupID_set = resource_allocation_groupID_set,
+ .resource_allocation_groupID_get = resource_allocation_groupID_get,
+ .resource_allocation_enable_set = resource_allocation_enable_set,
+ .resource_allocation_enable_get = resource_allocation_enable_get,
+};
diff --git a/arch/powerpc/platforms/celleb/udbg_beat.c b/arch/powerpc/platforms/celleb/udbg_beat.c
new file mode 100644
index 00000000000..d888c4674c6
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/udbg_beat.c
@@ -0,0 +1,97 @@
+/*
+ * udbg function for Beat
+ *
+ * (C) Copyright 2006 TOSHIBA 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+
+#include "beat.h"
+
+#define celleb_vtermno 0
+
+static void udbg_putc_beat(char c)
+{
+ unsigned long rc;
+
+ if (c == '\n')
+ udbg_putc_beat('\r');
+
+ rc = beat_put_term_char(celleb_vtermno, 1, (uint64_t)c << 56, 0);
+}
+
+/* Buffered chars getc */
+static long inbuflen;
+static long inbuf[2]; /* must be 2 longs */
+
+static int udbg_getc_poll_beat(void)
+{
+ /* The interface is tricky because it may return up to 16 chars.
+ * We save them statically for future calls to udbg_getc().
+ */
+ char ch, *buf = (char *)inbuf;
+ int i;
+ long rc;
+ if (inbuflen == 0) {
+ /* get some more chars. */
+ inbuflen = 0;
+ rc = beat_get_term_char(celleb_vtermno, &inbuflen, inbuf+0, inbuf+1);
+ if (rc != 0)
+ inbuflen = 0; /* otherwise inbuflen is garbage */
+ }
+ if (inbuflen <= 0 || inbuflen > 16) {
+ /* Catch error case as well as other oddities (corruption) */
+ inbuflen = 0;
+ return -1;
+ }
+ ch = buf[0];
+ for (i = 1; i < inbuflen; i++) /* shuffle them down. */
+ buf[i-1] = buf[i];
+ inbuflen--;
+ return ch;
+}
+
+static int udbg_getc_beat(void)
+{
+ int ch;
+ for (;;) {
+ ch = udbg_getc_poll_beat();
+ if (ch == -1) {
+ /* This shouldn't be needed...but... */
+ volatile unsigned long delay;
+ for (delay=0; delay < 2000000; delay++)
+ ;
+ } else {
+ return ch;
+ }
+ }
+}
+
+/* call this from early_init() for a working debug console on
+ * vterm capable LPAR machines
+ */
+void __init udbg_init_debug_beat(void)
+{
+ udbg_putc = udbg_putc_beat;
+ udbg_getc = udbg_getc_beat;
+ udbg_getc_poll = udbg_getc_poll_beat;
+}
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index e1f51d45598..117c9a0055b 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -75,7 +75,7 @@ extern irqreturn_t xmon_irq(int, void *);
extern unsigned long loops_per_jiffy;
/* To be replaced by RTAS when available */
-static unsigned int *briq_SPOR;
+static unsigned int __iomem *briq_SPOR;
#ifdef CONFIG_SMP
extern struct smp_ops_t chrp_smp_ops;
@@ -267,7 +267,7 @@ void __init chrp_setup_arch(void)
} else if (machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0) {
_chrp_type = _CHRP_briq;
/* Map the SPOR register on briq and change the restart hook */
- briq_SPOR = (unsigned int *)ioremap(0xff0000e8, 4);
+ briq_SPOR = ioremap(0xff0000e8, 4);
ppc_md.restart = briq_restart;
} else {
/* Let's assume it is an IBM chrp if all else fails */
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index ddbe398fbd4..886c522d78e 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -35,7 +35,7 @@ config HDPU
Select HDPU if configuring a Sky Computers Compute Blade.
config HDPU_FEATURES
- depends HDPU
+ depends on HDPU
tristate "HDPU-Features"
help
Select to enable HDPU enhanced features.
@@ -104,15 +104,6 @@ config RADSTONE_PPC7D
config PAL4
bool "SBS-Palomar4"
-config GEMINI
- bool "Synergy-Gemini"
- select PPC_INDIRECT_PCI
- depends on BROKEN
- help
- Select Gemini if configuring for a Synergy Microsystems' Gemini
- series Single Board Computer. More information is available at:
- <http://www.synergymicro.com/PressRel/97_10_15.html>.
-
config EST8260
bool "EST8260"
---help---
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
index 887b68804e6..54e6b3b6f26 100644
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -31,5 +31,5 @@ endmenu
config VIOPATH
bool
- depends on VIOCONS || VIODASD || VIOCD || VIOTAPE || VETH
+ depends on VIOCONS || VIODASD || VIOCD || VIOTAPE || ISERIES_VETH
default y
diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c
index e3e929e1b46..c1f4502a3c6 100644
--- a/arch/powerpc/platforms/iseries/lpevents.c
+++ b/arch/powerpc/platforms/iseries/lpevents.c
@@ -17,6 +17,7 @@
#include <asm/system.h>
#include <asm/paca.h>
+#include <asm/firmware.h>
#include <asm/iseries/it_lp_queue.h>
#include <asm/iseries/hv_lp_event.h>
#include <asm/iseries/hv_call_event.h>
@@ -318,6 +319,9 @@ static int __init proc_lpevents_init(void)
{
struct proc_dir_entry *e;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return 0;
+
e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL);
if (e)
e->proc_fops = &proc_lpevents_operations;
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c
index b5737d68d6c..1ad0e4aaad1 100644
--- a/arch/powerpc/platforms/iseries/mf.c
+++ b/arch/powerpc/platforms/iseries/mf.c
@@ -38,6 +38,7 @@
#include <asm/uaccess.h>
#include <asm/paca.h>
#include <asm/abs_addr.h>
+#include <asm/firmware.h>
#include <asm/iseries/vio.h>
#include <asm/iseries/mf.h>
#include <asm/iseries/hv_lp_config.h>
@@ -1178,7 +1179,7 @@ static ssize_t proc_mf_change_vmlinux(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
ssize_t rc;
dma_addr_t dma_addr;
char *page;
@@ -1235,6 +1236,9 @@ static int __init mf_proc_init(void)
char name[2];
int i;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return 0;
+
mf_proc_root = proc_mkdir("iSeries/mf", NULL);
if (!mf_proc_root)
return 1;
diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c
index c241413629a..b54e37101e6 100644
--- a/arch/powerpc/platforms/iseries/proc.c
+++ b/arch/powerpc/platforms/iseries/proc.c
@@ -24,6 +24,7 @@
#include <asm/processor.h>
#include <asm/time.h>
#include <asm/lppaca.h>
+#include <asm/firmware.h>
#include <asm/iseries/hv_call_xm.h>
#include "processor_vpd.h"
@@ -31,7 +32,12 @@
static int __init iseries_proc_create(void)
{
- struct proc_dir_entry *e = proc_mkdir("iSeries", 0);
+ struct proc_dir_entry *e;
+
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return 0;
+
+ e = proc_mkdir("iSeries", 0);
if (!e)
return 1;
@@ -106,6 +112,9 @@ static int __init iseries_proc_init(void)
{
struct proc_dir_entry *e;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return 0;
+
e = create_proc_entry("iSeries/titanTod", S_IFREG|S_IRUGO, NULL);
if (e)
e->proc_fops = &proc_titantod_operations;
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index bdf2afbb60c..cce7e309340 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -527,7 +527,8 @@ static void __init iSeries_fixup_klimit(void)
static int __init iSeries_src_init(void)
{
/* clear the progress line */
- ppc_md.progress(" ", 0xffff);
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ ppc_md.progress(" ", 0xffff);
return 0;
}
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
index 84e7ee2c086..a6799ed34a6 100644
--- a/arch/powerpc/platforms/iseries/viopath.c
+++ b/arch/powerpc/platforms/iseries/viopath.c
@@ -42,6 +42,7 @@
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/prom.h>
+#include <asm/firmware.h>
#include <asm/iseries/hv_types.h>
#include <asm/iseries/hv_lp_event.h>
#include <asm/iseries/hv_lp_config.h>
@@ -183,6 +184,9 @@ static int __init vio_proc_init(void)
{
struct proc_dir_entry *e;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return 0;
+
e = create_proc_entry("iSeries/config", 0, NULL);
if (e)
e->proc_fops = &proc_viopath_operations;
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 3a32deda765..73c59904697 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -425,14 +425,6 @@ static void __init setup_u4_pcie(struct pci_controller* hose)
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;
}
@@ -560,13 +552,16 @@ void __init maple_pci_init(void)
return;
}
for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
- if (np->name == NULL)
+ if (!np->type)
continue;
- if (strcmp(np->name, "pci") == 0) {
- if (add_bridge(np) == 0)
- of_node_get(np);
- }
- if (strcmp(np->name, "ht") == 0) {
+ if (strcmp(np->type, "pci") && strcmp(np->type, "ht"))
+ continue;
+ if ((device_is_compatible(np, "u4-pcie") ||
+ device_is_compatible(np, "u3-agp")) &&
+ add_bridge(np) == 0)
+ of_node_get(np);
+
+ if (device_is_compatible(np, "u3-ht")) {
of_node_get(np);
ht = np;
}
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 094989d50ba..82d3f9e28d7 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -60,7 +60,9 @@
#include <asm/of_device.h>
#include <asm/lmb.h>
#include <asm/mpic.h>
+#include <asm/rtas.h>
#include <asm/udbg.h>
+#include <asm/nvram.h>
#include "maple.h"
@@ -166,6 +168,16 @@ struct smp_ops_t maple_smp_ops = {
};
#endif /* CONFIG_SMP */
+static void __init maple_use_rtas_reboot_and_halt_if_present(void)
+{
+ if (rtas_service_present("system-reboot") &&
+ rtas_service_present("power-off")) {
+ ppc_md.restart = rtas_restart;
+ ppc_md.power_off = rtas_power_off;
+ ppc_md.halt = rtas_halt;
+ }
+}
+
void __init maple_setup_arch(void)
{
/* init to some ~sane value until calibrate_delay() runs */
@@ -181,8 +193,11 @@ void __init maple_setup_arch(void)
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
+ maple_use_rtas_reboot_and_halt_if_present();
printk(KERN_DEBUG "Using native/NAP idle loop\n");
+
+ mmio_nvram_init();
}
/*
@@ -242,7 +257,6 @@ static void __init maple_init_IRQ(void)
printk(KERN_DEBUG "OpenPIC addr: %lx, has ISUs: %d\n",
openpic_addr, has_isus);
}
- of_node_put(root);
BUG_ON(openpic_addr == 0);
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig
new file mode 100644
index 00000000000..68dc529dfd2
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/Kconfig
@@ -0,0 +1,10 @@
+menu "PA Semi PWRficient options"
+ depends on PPC_PASEMI
+
+config PPC_PASEMI_IOMMU
+ bool "PA Semi IOMMU support"
+ depends on PPC_PASEMI
+ help
+ IOMMU support for PA6T-1682M
+
+endmenu
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile
index 1be1a993c5f..e657ccae90a 100644
--- a/arch/powerpc/platforms/pasemi/Makefile
+++ b/arch/powerpc/platforms/pasemi/Makefile
@@ -1 +1,2 @@
-obj-y += setup.o pci.o time.o
+obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o
+
diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c
new file mode 100644
index 00000000000..1ca3ff38159
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/idle.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.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 License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/machdep.h>
+#include <asm/reg.h>
+
+#include "pasemi.h"
+
+struct sleep_mode {
+ char *name;
+ void (*entry)(void);
+};
+
+static struct sleep_mode modes[] = {
+ { .name = "spin", .entry = &idle_spin },
+ { .name = "doze", .entry = &idle_doze },
+};
+
+static int current_mode = 0;
+
+static int pasemi_system_reset_exception(struct pt_regs *regs)
+{
+ /* If we were woken up from power savings, we need to return
+ * to the calling function, since nip is not saved across
+ * all modes.
+ */
+
+ if (regs->msr & SRR1_WAKEMASK)
+ regs->nip = regs->link;
+
+ switch (regs->msr & SRR1_WAKEMASK) {
+ case SRR1_WAKEEE:
+ do_IRQ(regs);
+ break;
+ case SRR1_WAKEDEC:
+ timer_interrupt(regs);
+ break;
+ default:
+ /* do system reset */
+ return 0;
+ }
+ /* everything handled */
+ regs->msr |= MSR_RI;
+ return 1;
+}
+
+void __init pasemi_idle_init(void)
+{
+ ppc_md.system_reset_exception = pasemi_system_reset_exception;
+ ppc_md.power_save = modes[current_mode].entry;
+ printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name);
+}
+
+static int __init idle_param(char *p)
+{
+ int i;
+ for (i = 0; i < sizeof(modes)/sizeof(struct sleep_mode); i++) {
+ if (!strcmp(modes[i].name, p)) {
+ current_mode = i;
+ break;
+ }
+ }
+ return 0;
+}
+
+early_param("idle", idle_param);
diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c
new file mode 100644
index 00000000000..459a53b7d24
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/iommu.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2005-2007, PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.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 License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <asm/iommu.h>
+#include <asm/machdep.h>
+#include <asm/abs_addr.h>
+
+
+#define IOBMAP_PAGE_SHIFT 12
+#define IOBMAP_PAGE_SIZE (1 << IOBMAP_PAGE_SHIFT)
+#define IOBMAP_PAGE_MASK (IOBMAP_PAGE_SIZE - 1)
+
+#define IOBMAP_PAGE_FACTOR (PAGE_SHIFT - IOBMAP_PAGE_SHIFT)
+
+#define IOB_BASE 0xe0000000
+#define IOB_SIZE 0x3000
+/* Configuration registers */
+#define IOBCAP_REG 0x10
+#define IOBCOM_REG 0x40
+/* Enable IOB address translation */
+#define IOBCOM_ATEN 0x00000100
+
+/* Address decode configuration register */
+#define IOB_AD_REG 0x53
+/* IOBCOM_AD_REG fields */
+#define IOB_AD_VGPRT 0x00000e00
+#define IOB_AD_VGAEN 0x00000100
+/* Direct mapping settings */
+#define IOB_AD_MPSEL_MASK 0x00000030
+#define IOB_AD_MPSEL_B38 0x00000000
+#define IOB_AD_MPSEL_B40 0x00000010
+#define IOB_AD_MPSEL_B42 0x00000020
+/* Translation window size / enable */
+#define IOB_AD_TRNG_MASK 0x00000003
+#define IOB_AD_TRNG_256M 0x00000000
+#define IOB_AD_TRNG_2G 0x00000001
+#define IOB_AD_TRNG_128G 0x00000003
+
+#define IOB_TABLEBASE_REG 0x55
+
+/* Base of the 64 4-byte L1 registers */
+#define IOB_XLT_L1_REGBASE 0xac0
+
+/* Register to invalidate TLB entries */
+#define IOB_AT_INVAL_TLB_REG 0xb40
+
+/* The top two bits of the level 1 entry contains valid and type flags */
+#define IOBMAP_L1E_V 0x40000000
+#define IOBMAP_L1E_V_B 0x80000000
+
+/* For big page entries, the bottom two bits contains flags */
+#define IOBMAP_L1E_BIG_CACHED 0x00000002
+#define IOBMAP_L1E_BIG_PRIORITY 0x00000001
+
+/* For regular level 2 entries, top 2 bits contain valid and cache flags */
+#define IOBMAP_L2E_V 0x80000000
+#define IOBMAP_L2E_V_CACHED 0xc0000000
+
+static u32 *iob;
+static u32 iob_l1_emptyval;
+static u32 iob_l2_emptyval;
+static u32 *iob_l2_base;
+
+static struct iommu_table iommu_table_iobmap;
+static int iommu_table_iobmap_inited;
+
+static void iobmap_build(struct iommu_table *tbl, long index,
+ long npages, unsigned long uaddr,
+ enum dma_data_direction direction)
+{
+ u32 *ip;
+ u32 rpn;
+ unsigned long bus_addr;
+
+ pr_debug("iobmap: build at: %lx, %lx, addr: %lx\n", index, npages, uaddr);
+
+ bus_addr = (tbl->it_offset + index) << PAGE_SHIFT;
+
+ npages <<= IOBMAP_PAGE_FACTOR;
+ index <<= IOBMAP_PAGE_FACTOR;
+
+ ip = ((u32 *)tbl->it_base) + index;
+
+ while (npages--) {
+ rpn = virt_to_abs(uaddr) >> IOBMAP_PAGE_SHIFT;
+
+ *(ip++) = IOBMAP_L2E_V | rpn;
+ /* invalidate tlb, can be optimized more */
+ out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14);
+
+ uaddr += IOBMAP_PAGE_SIZE;
+ bus_addr += IOBMAP_PAGE_SIZE;
+ }
+}
+
+
+static void iobmap_free(struct iommu_table *tbl, long index,
+ long npages)
+{
+ u32 *ip;
+ unsigned long bus_addr;
+
+ pr_debug("iobmap: free at: %lx, %lx\n", index, npages);
+
+ bus_addr = (tbl->it_offset + index) << PAGE_SHIFT;
+
+ npages <<= IOBMAP_PAGE_FACTOR;
+ index <<= IOBMAP_PAGE_FACTOR;
+
+ ip = ((u32 *)tbl->it_base) + index;
+
+ while (npages--) {
+ *(ip++) = iob_l2_emptyval;
+ /* invalidate tlb, can be optimized more */
+ out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14);
+ bus_addr += IOBMAP_PAGE_SIZE;
+ }
+}
+
+
+static void iommu_table_iobmap_setup(void)
+{
+ pr_debug(" -> %s\n", __func__);
+ iommu_table_iobmap.it_busno = 0;
+ iommu_table_iobmap.it_offset = 0;
+ /* it_size is in number of entries */
+ iommu_table_iobmap.it_size = 0x80000000 >> PAGE_SHIFT;
+
+ /* Initialize the common IOMMU code */
+ iommu_table_iobmap.it_base = (unsigned long)iob_l2_base;
+ iommu_table_iobmap.it_index = 0;
+ /* XXXOJN tune this to avoid IOB cache invals.
+ * Should probably be 8 (64 bytes)
+ */
+ iommu_table_iobmap.it_blocksize = 4;
+ iommu_init_table(&iommu_table_iobmap, 0);
+ pr_debug(" <- %s\n", __func__);
+}
+
+
+
+static void pci_dma_bus_setup_pasemi(struct pci_bus *bus)
+{
+ struct device_node *dn;
+
+ pr_debug("pci_dma_bus_setup, bus %p, bus->self %p\n", bus, bus->self);
+
+ if (!iommu_table_iobmap_inited) {
+ iommu_table_iobmap_inited = 1;
+ iommu_table_iobmap_setup();
+ }
+
+ dn = pci_bus_to_OF_node(bus);
+
+ if (dn)
+ PCI_DN(dn)->iommu_table = &iommu_table_iobmap;
+
+}
+
+
+static void pci_dma_dev_setup_pasemi(struct pci_dev *dev)
+{
+ pr_debug("pci_dma_dev_setup, dev %p (%s)\n", dev, pci_name(dev));
+
+ /* DMA device is untranslated, but all other PCI-e goes through
+ * the IOMMU
+ */
+ if (dev->vendor == 0x1959 && dev->device == 0xa007)
+ dev->dev.archdata.dma_ops = &dma_direct_ops;
+ else
+ dev->dev.archdata.dma_data = &iommu_table_iobmap;
+}
+
+static void pci_dma_bus_setup_null(struct pci_bus *b) { }
+static void pci_dma_dev_setup_null(struct pci_dev *d) { }
+
+int iob_init(struct device_node *dn)
+{
+ unsigned long tmp;
+ u32 regword;
+ int i;
+
+ pr_debug(" -> %s\n", __func__);
+
+ /* Allocate a spare page to map all invalid IOTLB pages. */
+ tmp = lmb_alloc(IOBMAP_PAGE_SIZE, IOBMAP_PAGE_SIZE);
+ if (!tmp)
+ panic("IOBMAP: Cannot allocate spare page!");
+ /* Empty l1 is marked invalid */
+ iob_l1_emptyval = 0;
+ /* Empty l2 is mapped to dummy page */
+ iob_l2_emptyval = IOBMAP_L2E_V | (tmp >> IOBMAP_PAGE_SHIFT);
+
+ iob = ioremap(IOB_BASE, IOB_SIZE);
+ if (!iob)
+ panic("IOBMAP: Cannot map registers!");
+
+ /* setup direct mapping of the L1 entries */
+ for (i = 0; i < 64; i++) {
+ /* Each L1 covers 32MB, i.e. 8K entries = 32K of ram */
+ regword = IOBMAP_L1E_V | (__pa(iob_l2_base + i*0x2000) >> 12);
+ out_le32(iob+IOB_XLT_L1_REGBASE+i, regword);
+ }
+
+ /* set 2GB translation window, based at 0 */
+ regword = in_le32(iob+IOB_AD_REG);
+ regword &= ~IOB_AD_TRNG_MASK;
+ regword |= IOB_AD_TRNG_2G;
+ out_le32(iob+IOB_AD_REG, regword);
+
+ /* Enable translation */
+ regword = in_le32(iob+IOBCOM_REG);
+ regword |= IOBCOM_ATEN;
+ out_le32(iob+IOBCOM_REG, regword);
+
+ pr_debug(" <- %s\n", __func__);
+
+ return 0;
+}
+
+
+/* These are called very early. */
+void iommu_init_early_pasemi(void)
+{
+ int iommu_off;
+
+#ifndef CONFIG_PPC_PASEMI_IOMMU
+ iommu_off = 1;
+#else
+ iommu_off = of_chosen &&
+ get_property(of_chosen, "linux,iommu-off", NULL);
+#endif
+ if (iommu_off) {
+ /* Direct I/O, IOMMU off */
+ ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_null;
+ ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_null;
+ pci_dma_ops = &dma_direct_ops;
+
+ return;
+ }
+
+ iob_init(NULL);
+
+ ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pasemi;
+ ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pasemi;
+ ppc_md.tce_build = iobmap_build;
+ ppc_md.tce_free = iobmap_free;
+ pci_dma_ops = &dma_iommu_ops;
+}
+
+void __init alloc_iobmap_l2(void)
+{
+#ifndef CONFIG_PPC_PASEMI_IOMMU
+ return;
+#endif
+ /* For 2G space, 8x64 pages (2^21 bytes) is max total l2 size */
+ iob_l2_base = (u32 *)abs_to_virt(lmb_alloc_base(1UL<<21, 1UL<<21, 0x80000000));
+
+ printk(KERN_INFO "IOBMAP L2 allocated at: %p\n", iob_l2_base);
+}
diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h
index 51c2a2397ec..2d3927e6edb 100644
--- a/arch/powerpc/platforms/pasemi/pasemi.h
+++ b/arch/powerpc/platforms/pasemi/pasemi.h
@@ -3,5 +3,17 @@
extern unsigned long pas_get_boot_time(void);
extern void pas_pci_init(void);
+extern void __devinit pas_pci_irq_fixup(struct pci_dev *dev);
+extern void __devinit pas_pci_dma_dev_setup(struct pci_dev *dev);
+
+extern void __init alloc_iobmap_l2(void);
+
+extern void __init pasemi_idle_init(void);
+
+/* Power savings modes, implemented in asm */
+extern void idle_spin(void);
+extern void idle_doze(void);
+
+
#endif /* _PASEMI_PASEMI_H */
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
index faa618e0404..7ecb2ba24db 100644
--- a/arch/powerpc/platforms/pasemi/pci.c
+++ b/arch/powerpc/platforms/pasemi/pci.c
@@ -163,6 +163,19 @@ static void __init pas_fixup_phb_resources(void)
}
+void __devinit pas_pci_irq_fixup(struct pci_dev *dev)
+{
+ /* DMA is special, 84 interrupts (128 -> 211), all but 128
+ * need to be mapped by hand here.
+ */
+ if (dev->vendor == 0x1959 && dev->device == 0xa007) {
+ int i;
+ for (i = 129; i < 212; i++)
+ irq_create_mapping(NULL, i);
+ }
+}
+
+
void __init pas_pci_init(void)
{
struct device_node *np, *root;
diff --git a/arch/powerpc/platforms/pasemi/powersave.S b/arch/powerpc/platforms/pasemi/powersave.S
new file mode 100644
index 00000000000..6d0fba6aab1
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/powersave.S
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.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 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 <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+
+/* Power savings opcodes since not all binutils have them at this time */
+#define DOZE .long 0x4c000324
+#define NAP .long 0x4c000364
+#define SLEEP .long 0x4c0003a4
+#define RVW .long 0x4c0003e4
+
+/* Common sequence to do before going to any of the
+ * powersavings modes.
+ */
+
+#define PRE_SLEEP_SEQUENCE \
+ std r3,8(r1); \
+ ptesync ; \
+ ld r3,8(r1); \
+1: cmpd r3,r3; \
+ bne 1b
+
+_doze:
+ PRE_SLEEP_SEQUENCE
+ DOZE
+ b .
+
+
+_GLOBAL(idle_spin)
+ blr
+
+_GLOBAL(idle_doze)
+ LOAD_REG_ADDR(r3, _doze)
+ b sleep_common
+
+/* Add more modes here later */
+
+sleep_common:
+ mflr r0
+ std r0, 16(r1)
+ stdu r1,-64(r1)
+
+ LOAD_REG_IMMEDIATE(r6,MSR_DR|MSR_IR|MSR_ME|MSR_EE)
+ mfmsr r4
+ andc r5,r4,r6
+ mtmsrd r5,0
+
+ mtctr r3
+ bctrl
+
+ mtmsrd r4,0
+
+ addi r1,r1,64
+ ld r0,16(r1)
+ mtlr r0
+ blr
+
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index 89d6e295dbf..449cf1a0829 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 PA Semi, Inc
+ * Copyright (C) 2006-2007 PA Semi, Inc
*
* Authors: Kip Walker, PA Semi
* Olof Johansson, PA Semi
@@ -38,31 +38,46 @@
#include "pasemi.h"
+static void __iomem *reset_reg;
+
static void pas_restart(char *cmd)
{
- printk("restart unimplemented, looping...\n");
- for (;;) ;
+ printk("Restarting...\n");
+ while (1)
+ out_le32(reset_reg, 0x6000000);
}
-static void pas_power_off(void)
+#ifdef CONFIG_SMP
+static DEFINE_SPINLOCK(timebase_lock);
+
+static void __devinit pas_give_timebase(void)
{
- printk("power off unimplemented, looping...\n");
- for (;;) ;
+ unsigned long tb;
+
+ spin_lock(&timebase_lock);
+ mtspr(SPRN_TBCTL, TBCTL_FREEZE);
+ tb = mftb();
+ mtspr(SPRN_TBCTL, TBCTL_UPDATE_LOWER | (tb & 0xffffffff));
+ mtspr(SPRN_TBCTL, TBCTL_UPDATE_UPPER | (tb >> 32));
+ mtspr(SPRN_TBCTL, TBCTL_RESTART);
+ spin_unlock(&timebase_lock);
+ pr_debug("pas_give_timebase: cpu %d gave tb %lx\n",
+ smp_processor_id(), tb);
}
-static void pas_halt(void)
+static void __devinit pas_take_timebase(void)
{
- pas_power_off();
+ pr_debug("pas_take_timebase: cpu %d has tb %lx\n",
+ smp_processor_id(), mftb());
}
-#ifdef CONFIG_SMP
struct smp_ops_t pas_smp_ops = {
.probe = smp_mpic_probe,
.message_pass = smp_mpic_message_pass,
.kick_cpu = smp_generic_kick_cpu,
.setup_cpu = smp_mpic_setup_cpu,
- .give_timebase = smp_generic_give_timebase,
- .take_timebase = smp_generic_take_timebase,
+ .give_timebase = pas_give_timebase,
+ .take_timebase = pas_take_timebase,
};
#endif /* CONFIG_SMP */
@@ -72,9 +87,6 @@ void __init pas_setup_arch(void)
/* Setup SMP callback */
smp_ops = &pas_smp_ops;
#endif
- /* no iommu yet */
- pci_dma_ops = &dma_direct_ops;
-
/* Lookup PCI hosts */
pas_pci_init();
@@ -82,7 +94,11 @@ void __init pas_setup_arch(void)
conswitchp = &dummy_con;
#endif
- printk(KERN_DEBUG "Using default idle loop\n");
+ /* Remap SDC register for doing reset */
+ /* XXXOJN This should maybe come out of the device tree */
+ reset_reg = ioremap(0xfc101100, 4);
+
+ pasemi_idle_init();
}
/* No legacy IO on our parts */
@@ -129,10 +145,10 @@ static __init void pas_init_IRQ(void)
}
openpic_addr = of_read_number(opprop, naddr);
printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
- of_node_put(root);
- mpic = mpic_alloc(mpic_node, openpic_addr, MPIC_PRIMARY, 0, 0,
- " PAS-OPIC ");
+ mpic = mpic_alloc(mpic_node, openpic_addr,
+ MPIC_PRIMARY|MPIC_LARGE_VECTORS,
+ 0, 0, " PAS-OPIC ");
BUG_ON(!mpic);
mpic_assign_isu(mpic, 0, openpic_addr + 0x10000);
@@ -147,6 +163,53 @@ static void __init pas_progress(char *s, unsigned short hex)
}
+static int pas_machine_check_handler(struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+ unsigned long srr0, srr1, dsisr;
+
+ srr0 = regs->nip;
+ srr1 = regs->msr;
+ dsisr = mfspr(SPRN_DSISR);
+ printk(KERN_ERR "Machine Check on CPU %d\n", cpu);
+ printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1);
+ printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar);
+ printk(KERN_ERR "Cause:\n");
+
+ if (srr1 & 0x200000)
+ printk(KERN_ERR "Signalled by SDC\n");
+ if (srr1 & 0x100000) {
+ printk(KERN_ERR "Load/Store detected error:\n");
+ if (dsisr & 0x8000)
+ printk(KERN_ERR "D-cache ECC double-bit error or bus error\n");
+ if (dsisr & 0x4000)
+ printk(KERN_ERR "LSU snoop response error\n");
+ if (dsisr & 0x2000)
+ printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n");
+ if (dsisr & 0x1000)
+ printk(KERN_ERR "Recoverable Duptags\n");
+ if (dsisr & 0x800)
+ printk(KERN_ERR "Recoverable D-cache parity error count overflow\n");
+ if (dsisr & 0x400)
+ printk(KERN_ERR "TLB parity error count overflow\n");
+ }
+ if (srr1 & 0x80000)
+ printk(KERN_ERR "Bus Error\n");
+ if (srr1 & 0x40000)
+ printk(KERN_ERR "I-side SLB multiple hit\n");
+ if (srr1 & 0x20000)
+ printk(KERN_ERR "I-cache parity error hit\n");
+
+ /* SRR1[62] is from MSR[62] if recoverable, so pass that back */
+ return !!(srr1 & 0x2);
+}
+
+static void __init pas_init_early(void)
+{
+ iommu_init_early_pasemi();
+}
+
+
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
@@ -159,6 +222,8 @@ static int __init pas_probe(void)
hpte_init_native();
+ alloc_iobmap_l2();
+
return 1;
}
@@ -166,13 +231,14 @@ define_machine(pas) {
.name = "PA Semi PA6T-1682M",
.probe = pas_probe,
.setup_arch = pas_setup_arch,
+ .init_early = pas_init_early,
.init_IRQ = pas_init_IRQ,
.get_irq = mpic_get_irq,
.restart = pas_restart,
- .power_off = pas_power_off,
- .halt = pas_halt,
.get_boot_time = pas_get_boot_time,
.calibrate_decr = generic_calibrate_decr,
.check_legacy_ioport = pas_check_legacy_ioport,
.progress = pas_progress,
+ .machine_check_exception = pas_machine_check_handler,
+ .pci_irq_fixup = pas_pci_irq_fixup,
};
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index eeb2ae5ffc5..d73fb73802b 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -795,7 +795,6 @@ static void __devinit smp_core99_kick_cpu(int nr)
ppc_md.progress("smp_core99_kick_cpu", 0x346);
local_irq_save(flags);
- local_irq_disable();
/* Save reset vector */
save_vector = *vector;
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 451bfcd5502..de52ec4e9e5 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -40,4 +40,15 @@ config PS3_USE_LPAR_ADDR
If you have any doubt, choose the default y.
+config PS3_VUART
+ depends on PPC_PS3
+ bool "PS3 Virtual UART support"
+ default y
+ help
+ Include support for the PS3 Virtual UART.
+
+ This support is required for several system services
+ including the System Manager and AV Settings. In
+ general, all users will say Y.
+
endmenu
diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile
index 3757cfabc8c..a0048fcf086 100644
--- a/arch/powerpc/platforms/ps3/Makefile
+++ b/arch/powerpc/platforms/ps3/Makefile
@@ -1,4 +1,6 @@
-obj-y += setup.o mm.o smp.o time.o hvcall.o htab.o repository.o
+obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o
obj-y += interrupt.o exports.o os-area.o
+obj-y += system-bus.o
+obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SPU_BASE) += spu.o
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index 8fe1769655a..a4b5a1bc60f 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -23,7 +23,6 @@
#include <asm/machdep.h>
#include <asm/lmb.h>
#include <asm/udbg.h>
-#include <asm/ps3.h>
#include <asm/lv1call.h>
#include "platform.h"
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 056c1e4141b..631c3009561 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -24,7 +24,6 @@
#include <asm/machdep.h>
#include <asm/udbg.h>
-#include <asm/ps3.h>
#include <asm/lv1call.h>
#include "platform.h"
@@ -36,15 +35,148 @@
#endif
/**
+ * struct ps3_bmp - a per cpu irq status and mask bitmap structure
+ * @status: 256 bit status bitmap indexed by plug
+ * @unused_1:
+ * @mask: 256 bit mask bitmap indexed by plug
+ * @unused_2:
+ * @lock:
+ * @ipi_debug_brk_mask:
+ *
+ * The HV mantains per SMT thread mappings of HV outlet to HV plug on
+ * behalf of the guest. These mappings are implemented as 256 bit guest
+ * supplied bitmaps indexed by plug number. The addresses of the bitmaps
+ * are registered with the HV through lv1_configure_irq_state_bitmap().
+ * The HV requires that the 512 bits of status + mask not cross a page
+ * boundary. PS3_BMP_MINALIGN is used to define this minimal 64 byte
+ * alignment.
+ *
+ * The HV supports 256 plugs per thread, assigned as {0..255}, for a total
+ * of 512 plugs supported on a processor. To simplify the logic this
+ * implementation equates HV plug value to Linux virq value, constrains each
+ * interrupt to have a system wide unique plug number, and limits the range
+ * of the plug values to map into the first dword of the bitmaps. This
+ * gives a usable range of plug values of {NUM_ISA_INTERRUPTS..63}. Note
+ * that there is no constraint on how many in this set an individual thread
+ * can acquire.
+ */
+
+#define PS3_BMP_MINALIGN 64
+
+struct ps3_bmp {
+ struct {
+ u64 status;
+ u64 unused_1[3];
+ u64 mask;
+ u64 unused_2[3];
+ };
+ u64 ipi_debug_brk_mask;
+ spinlock_t lock;
+};
+
+/**
+ * struct ps3_private - a per cpu data structure
+ * @bmp: ps3_bmp structure
+ * @node: HV logical_ppe_id
+ * @cpu: HV thread_id
+ */
+
+struct ps3_private {
+ struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
+ u64 node;
+ unsigned int cpu;
+};
+
+static DEFINE_PER_CPU(struct ps3_private, ps3_private);
+
+int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
+ unsigned int *virq)
+{
+ int result;
+ struct ps3_private *pd;
+
+ /* This defines the default interrupt distribution policy. */
+
+ if (cpu == PS3_BINDING_CPU_ANY)
+ cpu = 0;
+
+ pd = &per_cpu(ps3_private, cpu);
+
+ *virq = irq_create_mapping(NULL, outlet);
+
+ if (*virq == NO_IRQ) {
+ pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n",
+ __func__, __LINE__, outlet);
+ result = -ENOMEM;
+ goto fail_create;
+ }
+
+ /* Binds outlet to cpu + virq. */
+
+ result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
+
+ if (result) {
+ pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ result = -EPERM;
+ goto fail_connect;
+ }
+
+ pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
+ outlet, cpu, *virq);
+
+ result = set_irq_chip_data(*virq, pd);
+
+ if (result) {
+ pr_debug("%s:%d: set_irq_chip_data failed\n",
+ __func__, __LINE__);
+ goto fail_set;
+ }
+
+ return result;
+
+fail_set:
+ lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq);
+fail_connect:
+ irq_dispose_mapping(*virq);
+fail_create:
+ return result;
+}
+EXPORT_SYMBOL_GPL(ps3_alloc_irq);
+
+int ps3_free_irq(unsigned int virq)
+{
+ int result;
+ const struct ps3_private *pd = get_irq_chip_data(virq);
+
+ pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
+ pd->node, pd->cpu, virq);
+
+ result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
+
+ if (result)
+ pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+
+ set_irq_chip_data(virq, NULL);
+ irq_dispose_mapping(virq);
+ return result;
+}
+EXPORT_SYMBOL_GPL(ps3_free_irq);
+
+/**
* ps3_alloc_io_irq - Assign a virq to a system bus device.
- * interrupt_id: The device interrupt id read from the system repository.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
+ * @interrupt_id: The device interrupt id read from the system repository.
* @virq: The assigned Linux virq.
*
* An io irq represents a non-virtualized device interrupt. interrupt_id
* coresponds to the interrupt number of the interrupt controller.
*/
-int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq)
+int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+ unsigned int *virq)
{
int result;
unsigned long outlet;
@@ -57,13 +189,12 @@ int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq)
return result;
}
- *virq = irq_create_mapping(NULL, outlet);
-
- pr_debug("%s:%d: interrupt_id %u => outlet %lu, virq %u\n",
- __func__, __LINE__, interrupt_id, outlet, *virq);
+ result = ps3_alloc_irq(cpu, outlet, virq);
+ BUG_ON(result);
- return 0;
+ return result;
}
+EXPORT_SYMBOL_GPL(ps3_alloc_io_irq);
int ps3_free_io_irq(unsigned int virq)
{
@@ -71,17 +202,20 @@ int ps3_free_io_irq(unsigned int virq)
result = lv1_destruct_io_irq_outlet(virq_to_hw(virq));
- if (!result)
+ if (result)
pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
__func__, __LINE__, ps3_result(result));
- irq_dispose_mapping(virq);
+ ps3_free_irq(virq);
return result;
}
+EXPORT_SYMBOL_GPL(ps3_free_io_irq);
/**
* ps3_alloc_event_irq - Allocate a virq for use with a system event.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
* @virq: The assigned Linux virq.
*
* The virq can be used with lv1_connect_interrupt_event_receive_port() to
@@ -89,7 +223,7 @@ int ps3_free_io_irq(unsigned int virq)
* events.
*/
-int ps3_alloc_event_irq(unsigned int *virq)
+int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
{
int result;
unsigned long outlet;
@@ -103,12 +237,10 @@ int ps3_alloc_event_irq(unsigned int *virq)
return result;
}
- *virq = irq_create_mapping(NULL, outlet);
-
- pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__, outlet,
- *virq);
+ result = ps3_alloc_irq(cpu, outlet, virq);
+ BUG_ON(result);
- return 0;
+ return result;
}
int ps3_free_event_irq(unsigned int virq)
@@ -123,7 +255,7 @@ int ps3_free_event_irq(unsigned int virq)
pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
__func__, __LINE__, ps3_result(result));
- irq_dispose_mapping(virq);
+ ps3_free_irq(virq);
pr_debug(" <- %s:%d\n", __func__, __LINE__);
return result;
@@ -136,6 +268,8 @@ int ps3_send_event_locally(unsigned int virq)
/**
* ps3_connect_event_irq - Assign a virq to a system bus device.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
* @did: The HV device identifier read from the system repository.
* @interrupt_id: The device interrupt id read from the system repository.
* @virq: The assigned Linux virq.
@@ -144,12 +278,13 @@ int ps3_send_event_locally(unsigned int virq)
* coresponds to the software interrupt number.
*/
-int ps3_connect_event_irq(const struct ps3_device_id *did,
- unsigned int interrupt_id, unsigned int *virq)
+int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
+ const struct ps3_device_id *did, unsigned int interrupt_id,
+ unsigned int *virq)
{
int result;
- result = ps3_alloc_event_irq(virq);
+ result = ps3_alloc_event_irq(cpu, virq);
if (result)
return result;
@@ -196,6 +331,8 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did,
/**
* ps3_alloc_vuart_irq - Configure the system virtual uart virq.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
* @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap.
* @virq: The assigned Linux virq.
*
@@ -203,13 +340,14 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did,
* freeing the interrupt will return a wrong state error.
*/
-int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq)
+int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
+ unsigned int *virq)
{
int result;
unsigned long outlet;
- unsigned long lpar_addr;
+ u64 lpar_addr;
- BUG_ON(!is_kernel_addr((unsigned long)virt_addr_bmp));
+ BUG_ON(!is_kernel_addr((u64)virt_addr_bmp));
lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp));
@@ -221,12 +359,10 @@ int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq)
return result;
}
- *virq = irq_create_mapping(NULL, outlet);
-
- pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__,
- outlet, *virq);
+ result = ps3_alloc_irq(cpu, outlet, virq);
+ BUG_ON(result);
- return 0;
+ return result;
}
int ps3_free_vuart_irq(unsigned int virq)
@@ -241,21 +377,23 @@ int ps3_free_vuart_irq(unsigned int virq)
return result;
}
- irq_dispose_mapping(virq);
+ ps3_free_irq(virq);
return result;
}
/**
* ps3_alloc_spe_irq - Configure an spe virq.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
* @spe_id: The spe_id returned from lv1_construct_logical_spe().
* @class: The spe interrupt class {0,1,2}.
* @virq: The assigned Linux virq.
*
*/
-int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class,
- unsigned int *virq)
+int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
+ unsigned int class, unsigned int *virq)
{
int result;
unsigned long outlet;
@@ -270,73 +408,24 @@ int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class,
return result;
}
- *virq = irq_create_mapping(NULL, outlet);
-
- pr_debug("%s:%d: spe_id %lu, class %u, outlet %lu, virq %u\n",
- __func__, __LINE__, spe_id, class, outlet, *virq);
+ result = ps3_alloc_irq(cpu, outlet, virq);
+ BUG_ON(result);
- return 0;
+ return result;
}
int ps3_free_spe_irq(unsigned int virq)
{
- irq_dispose_mapping(virq);
+ ps3_free_irq(virq);
return 0;
}
+
#define PS3_INVALID_OUTLET ((irq_hw_number_t)-1)
#define PS3_PLUG_MAX 63
-/**
- * struct bmp - a per cpu irq status and mask bitmap structure
- * @status: 256 bit status bitmap indexed by plug
- * @unused_1:
- * @mask: 256 bit mask bitmap indexed by plug
- * @unused_2:
- * @lock:
- * @ipi_debug_brk_mask:
- *
- * The HV mantains per SMT thread mappings of HV outlet to HV plug on
- * behalf of the guest. These mappings are implemented as 256 bit guest
- * supplied bitmaps indexed by plug number. The address of the bitmaps are
- * registered with the HV through lv1_configure_irq_state_bitmap().
- *
- * The HV supports 256 plugs per thread, assigned as {0..255}, for a total
- * of 512 plugs supported on a processor. To simplify the logic this
- * implementation equates HV plug value to linux virq value, constrains each
- * interrupt to have a system wide unique plug number, and limits the range
- * of the plug values to map into the first dword of the bitmaps. This
- * gives a usable range of plug values of {NUM_ISA_INTERRUPTS..63}. Note
- * that there is no constraint on how many in this set an individual thread
- * can aquire.
- */
-
-struct bmp {
- struct {
- unsigned long status;
- unsigned long unused_1[3];
- unsigned long mask;
- unsigned long unused_2[3];
- } __attribute__ ((packed));
- spinlock_t lock;
- unsigned long ipi_debug_brk_mask;
-};
-
-/**
- * struct private - a per cpu data structure
- * @node: HV node id
- * @cpu: HV thread id
- * @bmp: an HV bmp structure
- */
-
-struct private {
- unsigned long node;
- unsigned int cpu;
- struct bmp bmp;
-};
-
#if defined(DEBUG)
-static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cpu,
+static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,
const char* func, int line)
{
pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n",
@@ -346,14 +435,14 @@ static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cp
}
static void __attribute__ ((unused)) _dump_256_bmp(const char *header,
- const unsigned long *p, unsigned cpu, const char* func, int line)
+ const u64 *p, unsigned cpu, const char* func, int line)
{
pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n",
func, line, header, cpu, p[0], p[1], p[2], p[3]);
}
#define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__)
-static void _dump_bmp(struct private* pd, const char* func, int line)
+static void _dump_bmp(struct ps3_private* pd, const char* func, int line)
{
unsigned long flags;
@@ -364,7 +453,7 @@ static void _dump_bmp(struct private* pd, const char* func, int line)
}
#define dump_mask(_x) _dump_mask(_x, __func__, __LINE__)
-static void __attribute__ ((unused)) _dump_mask(struct private* pd,
+static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd,
const char* func, int line)
{
unsigned long flags;
@@ -374,109 +463,94 @@ static void __attribute__ ((unused)) _dump_mask(struct private* pd,
spin_unlock_irqrestore(&pd->bmp.lock, flags);
}
#else
-static void dump_bmp(struct private* pd) {};
+static void dump_bmp(struct ps3_private* pd) {};
#endif /* defined(DEBUG) */
-static void chip_mask(unsigned int virq)
+static void ps3_chip_mask(unsigned int virq)
{
+ struct ps3_private *pd = get_irq_chip_data(virq);
+ u64 bit = 0x8000000000000000UL >> virq;
+ u64 *p = &pd->bmp.mask;
+ u64 old;
unsigned long flags;
- struct private *pd = get_irq_chip_data(virq);
pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
- BUG_ON(virq < NUM_ISA_INTERRUPTS);
- BUG_ON(virq > PS3_PLUG_MAX);
-
- spin_lock_irqsave(&pd->bmp.lock, flags);
- pd->bmp.mask &= ~(0x8000000000000000UL >> virq);
- spin_unlock_irqrestore(&pd->bmp.lock, flags);
+ local_irq_save(flags);
+ asm volatile(
+ "1: ldarx %0,0,%3\n"
+ "andc %0,%0,%2\n"
+ "stdcx. %0,0,%3\n"
+ "bne- 1b"
+ : "=&r" (old), "+m" (*p)
+ : "r" (bit), "r" (p)
+ : "cc" );
lv1_did_update_interrupt_mask(pd->node, pd->cpu);
+ local_irq_restore(flags);
}
-static void chip_unmask(unsigned int virq)
+static void ps3_chip_unmask(unsigned int virq)
{
+ struct ps3_private *pd = get_irq_chip_data(virq);
+ u64 bit = 0x8000000000000000UL >> virq;
+ u64 *p = &pd->bmp.mask;
+ u64 old;
unsigned long flags;
- struct private *pd = get_irq_chip_data(virq);
pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
- BUG_ON(virq < NUM_ISA_INTERRUPTS);
- BUG_ON(virq > PS3_PLUG_MAX);
-
- spin_lock_irqsave(&pd->bmp.lock, flags);
- pd->bmp.mask |= (0x8000000000000000UL >> virq);
- spin_unlock_irqrestore(&pd->bmp.lock, flags);
+ local_irq_save(flags);
+ asm volatile(
+ "1: ldarx %0,0,%3\n"
+ "or %0,%0,%2\n"
+ "stdcx. %0,0,%3\n"
+ "bne- 1b"
+ : "=&r" (old), "+m" (*p)
+ : "r" (bit), "r" (p)
+ : "cc" );
lv1_did_update_interrupt_mask(pd->node, pd->cpu);
+ local_irq_restore(flags);
}
-static void chip_eoi(unsigned int virq)
+static void ps3_chip_eoi(unsigned int virq)
{
- lv1_end_of_interrupt(virq);
+ const struct ps3_private *pd = get_irq_chip_data(virq);
+ lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq);
}
static struct irq_chip irq_chip = {
.typename = "ps3",
- .mask = chip_mask,
- .unmask = chip_unmask,
- .eoi = chip_eoi,
+ .mask = ps3_chip_mask,
+ .unmask = ps3_chip_unmask,
+ .eoi = ps3_chip_eoi,
};
-static void host_unmap(struct irq_host *h, unsigned int virq)
+static void ps3_host_unmap(struct irq_host *h, unsigned int virq)
{
- int result;
-
- pr_debug("%s:%d: virq %d\n", __func__, __LINE__, virq);
-
- lv1_disconnect_irq_plug(virq);
-
- result = set_irq_chip_data(virq, NULL);
- BUG_ON(result);
+ set_irq_chip_data(virq, NULL);
}
-static DEFINE_PER_CPU(struct private, private);
-
-static int host_map(struct irq_host *h, unsigned int virq,
+static int ps3_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hwirq)
{
- int result;
- unsigned int cpu;
-
- pr_debug(" -> %s:%d\n", __func__, __LINE__);
- pr_debug("%s:%d: hwirq %lu => virq %u\n", __func__, __LINE__, hwirq,
+ pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
virq);
- /* bind this virq to a cpu */
-
- preempt_disable();
- cpu = smp_processor_id();
- result = lv1_connect_irq_plug(virq, hwirq);
- preempt_enable();
-
- if (result) {
- pr_info("%s:%d: lv1_connect_irq_plug failed:"
- " %s\n", __func__, __LINE__, ps3_result(result));
- return -EPERM;
- }
-
- result = set_irq_chip_data(virq, &per_cpu(private, cpu));
- BUG_ON(result);
-
set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq);
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
- return result;
+ return 0;
}
-static struct irq_host_ops host_ops = {
- .map = host_map,
- .unmap = host_unmap,
+static struct irq_host_ops ps3_host_ops = {
+ .map = ps3_host_map,
+ .unmap = ps3_host_unmap,
};
void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
{
- struct private *pd = &per_cpu(private, cpu);
+ struct ps3_private *pd = &per_cpu(ps3_private, cpu);
pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq;
@@ -484,57 +558,32 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
cpu, virq, pd->bmp.ipi_debug_brk_mask);
}
-static int bmp_get_and_clear_status_bit(struct bmp *m)
+unsigned int ps3_get_irq(void)
{
- unsigned long flags;
- unsigned int bit;
- unsigned long x;
-
- spin_lock_irqsave(&m->lock, flags);
+ struct ps3_private *pd = &__get_cpu_var(ps3_private);
+ u64 x = (pd->bmp.status & pd->bmp.mask);
+ unsigned int plug;
/* check for ipi break first to stop this cpu ASAP */
- if (m->status & m->ipi_debug_brk_mask) {
- m->status &= ~m->ipi_debug_brk_mask;
- spin_unlock_irqrestore(&m->lock, flags);
- return __ilog2(m->ipi_debug_brk_mask);
- }
-
- x = (m->status & m->mask);
+ if (x & pd->bmp.ipi_debug_brk_mask)
+ x &= pd->bmp.ipi_debug_brk_mask;
- for (bit = NUM_ISA_INTERRUPTS, x <<= bit; x; bit++, x <<= 1)
- if (x & 0x8000000000000000UL) {
- m->status &= ~(0x8000000000000000UL >> bit);
- spin_unlock_irqrestore(&m->lock, flags);
- return bit;
- }
+ asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x));
+ plug &= 0x3f;
- spin_unlock_irqrestore(&m->lock, flags);
-
- pr_debug("%s:%d: not found\n", __func__, __LINE__);
- return -1;
-}
-
-unsigned int ps3_get_irq(void)
-{
- int plug;
-
- struct private *pd = &__get_cpu_var(private);
-
- plug = bmp_get_and_clear_status_bit(&pd->bmp);
-
- if (plug < 1) {
+ if (unlikely(plug) == NO_IRQ) {
pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__,
pd->cpu);
- dump_bmp(&per_cpu(private, 0));
- dump_bmp(&per_cpu(private, 1));
+ dump_bmp(&per_cpu(ps3_private, 0));
+ dump_bmp(&per_cpu(ps3_private, 1));
return NO_IRQ;
}
#if defined(DEBUG)
- if (plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX) {
- dump_bmp(&per_cpu(private, 0));
- dump_bmp(&per_cpu(private, 1));
+ if (unlikely(plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX)) {
+ dump_bmp(&per_cpu(ps3_private, 0));
+ dump_bmp(&per_cpu(ps3_private, 1));
BUG();
}
#endif
@@ -544,26 +593,27 @@ unsigned int ps3_get_irq(void)
void __init ps3_init_IRQ(void)
{
int result;
- unsigned long node;
unsigned cpu;
struct irq_host *host;
- lv1_get_logical_ppe_id(&node);
-
- host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &host_ops,
+ host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops,
PS3_INVALID_OUTLET);
irq_set_default_host(host);
irq_set_virq_count(PS3_PLUG_MAX + 1);
for_each_possible_cpu(cpu) {
- struct private *pd = &per_cpu(private, cpu);
+ struct ps3_private *pd = &per_cpu(ps3_private, cpu);
- pd->node = node;
- pd->cpu = cpu;
+ lv1_get_logical_ppe_id(&pd->node);
+ pd->cpu = get_hard_smp_processor_id(cpu);
spin_lock_init(&pd->bmp.lock);
- result = lv1_configure_irq_state_bitmap(node, cpu,
- ps3_mm_phys_to_lpar(__pa(&pd->bmp.status)));
+ pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__,
+ __LINE__, pd->node, pd->cpu,
+ ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
+
+ result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu,
+ ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
if (result)
pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:"
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index 49c0d010d49..42354de3f55 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -25,7 +25,6 @@
#include <asm/firmware.h>
#include <asm/lmb.h>
#include <asm/udbg.h>
-#include <asm/ps3.h>
#include <asm/lv1call.h>
#include "platform.h"
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c
index 58358305dc1..5c3da08bc0c 100644
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -22,7 +22,6 @@
#include <linux/io.h>
#include <asm/lmb.h>
-#include <asm/ps3.h>
#include "platform.h"
@@ -59,7 +58,7 @@ struct os_area_header {
u32 ldr_format;
u32 ldr_size;
u32 _reserved_2[6];
-} __attribute__ ((packed));
+};
enum {
PARAM_BOOT_FLAG_GAME_OS = 0,
@@ -67,13 +66,6 @@ enum {
};
enum {
- PARAM_AV_MULTI_OUT_NTSC = 0,
- PARAM_AV_MULTI_OUT_PAL_RGB = 1,
- PARAM_AV_MULTI_OUT_PAL_YCBCR = 2,
- PARAM_AV_MULTI_OUT_SECAM = 3,
-};
-
-enum {
PARAM_CTRL_BUTTON_O_IS_YES = 0,
PARAM_CTRL_BUTTON_X_IS_YES = 1,
};
@@ -114,7 +106,7 @@ struct os_area_params {
u8 dns_primary[4];
u8 dns_secondary[4];
u8 _reserved_5[8];
-} __attribute__ ((packed));
+};
/**
* struct saved_params - Static working copies of data from the 'Other OS' area.
@@ -257,3 +249,13 @@ u64 ps3_os_area_rtc_diff(void)
{
return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL;
}
+
+/**
+ * ps3_os_area_get_av_multi_out - Returns the default video mode.
+ */
+
+enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void)
+{
+ return saved_params.av_multi_out;
+}
+EXPORT_SYMBOL_GPL(ps3_os_area_get_av_multi_out);
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index 23b111bea9d..ca04f03305c 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -22,6 +22,9 @@
#define _PS3_PLATFORM_H
#include <linux/rtc.h>
+#include <scsi/scsi.h>
+
+#include <asm/ps3.h>
/* htab */
@@ -65,4 +68,152 @@ void ps3_spu_set_platform (void);
static inline void ps3_spu_set_platform (void) {}
#endif
+/* repository bus info */
+
+enum ps3_bus_type {
+ PS3_BUS_TYPE_SB = 4,
+ PS3_BUS_TYPE_STORAGE = 5,
+};
+
+enum ps3_dev_type {
+ PS3_DEV_TYPE_STOR_DISK = TYPE_DISK, /* 0 */
+ PS3_DEV_TYPE_SB_GELIC = 3,
+ PS3_DEV_TYPE_SB_USB = 4,
+ PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */
+ PS3_DEV_TYPE_SB_GPIO = 6,
+ PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */
+};
+
+int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
+ u64 *value);
+int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id);
+int ps3_repository_read_bus_type(unsigned int bus_index,
+ enum ps3_bus_type *bus_type);
+int ps3_repository_read_bus_num_dev(unsigned int bus_index,
+ unsigned int *num_dev);
+
+/* repository bus device info */
+
+enum ps3_interrupt_type {
+ PS3_INTERRUPT_TYPE_EVENT_PORT = 2,
+ PS3_INTERRUPT_TYPE_SB_OHCI = 3,
+ PS3_INTERRUPT_TYPE_SB_EHCI = 4,
+ PS3_INTERRUPT_TYPE_OTHER = 5,
+};
+
+enum ps3_reg_type {
+ PS3_REG_TYPE_SB_OHCI = 3,
+ PS3_REG_TYPE_SB_EHCI = 4,
+ PS3_REG_TYPE_SB_GPIO = 5,
+};
+
+int ps3_repository_read_dev_str(unsigned int bus_index,
+ unsigned int dev_index, const char *dev_str, u64 *value);
+int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index,
+ unsigned int *dev_id);
+int ps3_repository_read_dev_type(unsigned int bus_index,
+ unsigned int dev_index, enum ps3_dev_type *dev_type);
+int ps3_repository_read_dev_intr(unsigned int bus_index,
+ unsigned int dev_index, unsigned int intr_index,
+ enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id);
+int ps3_repository_read_dev_reg_type(unsigned int bus_index,
+ unsigned int dev_index, unsigned int reg_index,
+ enum ps3_reg_type *reg_type);
+int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
+ unsigned int dev_index, unsigned int reg_index, u64 *bus_addr,
+ u64 *len);
+int ps3_repository_read_dev_reg(unsigned int bus_index,
+ unsigned int dev_index, unsigned int reg_index,
+ enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len);
+
+/* repository bus enumerators */
+
+struct ps3_repository_device {
+ unsigned int bus_index;
+ unsigned int dev_index;
+ struct ps3_device_id did;
+};
+
+int ps3_repository_find_device(enum ps3_bus_type bus_type,
+ enum ps3_dev_type dev_type,
+ const struct ps3_repository_device *start_dev,
+ struct ps3_repository_device *dev);
+static inline int ps3_repository_find_first_device(
+ enum ps3_bus_type bus_type, enum ps3_dev_type dev_type,
+ struct ps3_repository_device *dev)
+{
+ return ps3_repository_find_device(bus_type, dev_type, NULL, dev);
+}
+int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
+ enum ps3_interrupt_type intr_type, unsigned int *interrupt_id);
+int ps3_repository_find_reg(const struct ps3_repository_device *dev,
+ enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len);
+
+/* repository block device info */
+
+int ps3_repository_read_stor_dev_port(unsigned int bus_index,
+ unsigned int dev_index, u64 *port);
+int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index,
+ unsigned int dev_index, u64 *blk_size);
+int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index,
+ unsigned int dev_index, u64 *num_blocks);
+int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,
+ unsigned int dev_index, unsigned int *num_regions);
+int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,
+ unsigned int dev_index, unsigned int region_index,
+ unsigned int *region_id);
+int ps3_repository_read_stor_dev_region_size(unsigned int bus_index,
+ unsigned int dev_index, unsigned int region_index, u64 *region_size);
+int ps3_repository_read_stor_dev_region_start(unsigned int bus_index,
+ unsigned int dev_index, unsigned int region_index, u64 *region_start);
+int ps3_repository_read_stor_dev_info(unsigned int bus_index,
+ unsigned int dev_index, u64 *port, u64 *blk_size,
+ u64 *num_blocks, unsigned int *num_regions);
+int ps3_repository_read_stor_dev_region(unsigned int bus_index,
+ unsigned int dev_index, unsigned int region_index,
+ unsigned int *region_id, u64 *region_start, u64 *region_size);
+
+/* repository pu and memory info */
+
+int ps3_repository_read_num_pu(unsigned int *num_pu);
+int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id);
+int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base);
+int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size);
+int ps3_repository_read_region_total(u64 *region_total);
+int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
+ u64 *region_total);
+
+/* repository pme info */
+
+int ps3_repository_read_num_be(unsigned int *num_be);
+int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id);
+int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq);
+int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq);
+
+/* repository 'Other OS' area */
+
+int ps3_repository_read_boot_dat_addr(u64 *lpar_addr);
+int ps3_repository_read_boot_dat_size(unsigned int *size);
+int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size);
+
+/* repository spu info */
+
+/**
+ * enum spu_resource_type - Type of spu resource.
+ * @spu_resource_type_shared: Logical spu is shared with other partions.
+ * @spu_resource_type_exclusive: Logical spu is not shared with other partions.
+ *
+ * Returned by ps3_repository_read_spu_resource_id().
+ */
+
+enum ps3_spu_resource_type {
+ PS3_SPU_RESOURCE_TYPE_SHARED = 0,
+ PS3_SPU_RESOURCE_TYPE_EXCLUSIVE = 0x8000000000000000UL,
+};
+
+int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved);
+int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id);
+int ps3_repository_read_spu_resource_id(unsigned int res_index,
+ enum ps3_spu_resource_type* resource_type, unsigned int *resource_id);
+
#endif
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
index 273a0d621bd..ae586a0e5d3 100644
--- a/arch/powerpc/platforms/ps3/repository.c
+++ b/arch/powerpc/platforms/ps3/repository.c
@@ -18,9 +18,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/ps3.h>
#include <asm/lv1call.h>
+#include "platform.h"
+
enum ps3_vendor_id {
PS3_VENDOR_ID_NONE = 0,
PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
@@ -257,7 +258,7 @@ int ps3_repository_read_dev_type(unsigned int bus_index,
int ps3_repository_read_dev_intr(unsigned int bus_index,
unsigned int dev_index, unsigned int intr_index,
- unsigned int *intr_type, unsigned int* interrupt_id)
+ enum ps3_interrupt_type *intr_type, unsigned int* interrupt_id)
{
int result;
u64 v1;
@@ -275,7 +276,8 @@ int ps3_repository_read_dev_intr(unsigned int bus_index,
}
int ps3_repository_read_dev_reg_type(unsigned int bus_index,
- unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type)
+ unsigned int dev_index, unsigned int reg_index,
+ enum ps3_reg_type *reg_type)
{
int result;
u64 v1;
@@ -302,8 +304,8 @@ int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
}
int ps3_repository_read_dev_reg(unsigned int bus_index,
- unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type,
- u64 *bus_addr, u64 *len)
+ unsigned int dev_index, unsigned int reg_index,
+ enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len)
{
int result = ps3_repository_read_dev_reg_type(bus_index, dev_index,
reg_index, reg_type);
@@ -343,7 +345,7 @@ int ps3_repository_dump_resource_info(unsigned int bus_index,
}
for (res_index = 0; res_index < 10; res_index++) {
- enum ps3_region_type reg_type;
+ enum ps3_reg_type reg_type;
u64 bus_addr;
u64 len;
@@ -367,7 +369,55 @@ int ps3_repository_dump_resource_info(unsigned int bus_index,
return result;
}
-static int dump_device_info(unsigned int bus_index, unsigned int num_dev)
+static int dump_stor_dev_info(unsigned int bus_index, unsigned int dev_index)
+{
+ int result = 0;
+ unsigned int num_regions, region_index;
+ u64 port, blk_size, num_blocks;
+
+ pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
+ bus_index, dev_index);
+
+ result = ps3_repository_read_stor_dev_info(bus_index, dev_index, &port,
+ &blk_size, &num_blocks, &num_regions);
+ if (result) {
+ pr_debug("%s:%d ps3_repository_read_stor_dev_info"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ bus_index, dev_index);
+ goto out;
+ }
+
+ pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks "
+ "%lu, num_regions %u\n",
+ __func__, __LINE__, bus_index, dev_index, port,
+ blk_size, num_blocks, num_regions);
+
+ for (region_index = 0; region_index < num_regions; region_index++) {
+ unsigned int region_id;
+ u64 region_start, region_size;
+
+ result = ps3_repository_read_stor_dev_region(bus_index,
+ dev_index, region_index, &region_id, &region_start,
+ &region_size);
+ if (result) {
+ pr_debug("%s:%d ps3_repository_read_stor_dev_region"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ bus_index, dev_index);
+ break;
+ }
+
+ pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n",
+ __func__, __LINE__, bus_index, dev_index, region_id,
+ region_start, region_size);
+ }
+
+out:
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+
+static int dump_device_info(unsigned int bus_index, enum ps3_bus_type bus_type,
+ unsigned int num_dev)
{
int result = 0;
unsigned int dev_index;
@@ -402,6 +452,9 @@ static int dump_device_info(unsigned int bus_index, unsigned int num_dev)
__LINE__, bus_index, dev_index, dev_type, dev_id);
ps3_repository_dump_resource_info(bus_index, dev_index);
+
+ if (bus_type == PS3_BUS_TYPE_STORAGE)
+ dump_stor_dev_info(bus_index, dev_index);
}
pr_debug(" <- %s:%d\n", __func__, __LINE__);
@@ -452,7 +505,7 @@ int ps3_repository_dump_bus_info(void)
__func__, __LINE__, bus_index, bus_type, bus_id,
num_dev);
- dump_device_info(bus_index, num_dev);
+ dump_device_info(bus_index, bus_type, num_dev);
}
pr_debug(" <- %s:%d\n", __func__, __LINE__);
@@ -487,7 +540,8 @@ static int find_device(unsigned int bus_index, unsigned int num_dev,
break;
}
- BUG_ON(dev_index == num_dev);
+ if (dev_index == num_dev)
+ return -1;
pr_debug("%s:%d: found dev_type %u at dev_index %u\n",
__func__, __LINE__, dev_type, dev_index);
@@ -521,7 +575,7 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type,
pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__,
bus_type, dev_type);
- dev->bus_index = UINT_MAX;
+ BUG_ON(start_dev && start_dev->bus_index > 10);
for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10;
bus_index++) {
@@ -532,13 +586,15 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type,
if (result) {
pr_debug("%s:%d read_bus_type failed\n",
__func__, __LINE__);
+ dev->bus_index = UINT_MAX;
return result;
}
if (x == bus_type)
break;
}
- BUG_ON(bus_index == 10);
+ if (bus_index >= 10)
+ return -ENODEV;
pr_debug("%s:%d: found bus_type %u at bus_index %u\n",
__func__, __LINE__, bus_type, bus_index);
@@ -604,7 +660,8 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
}
}
- BUG_ON(res_index == 10);
+ if (res_index == 10)
+ return -ENODEV;
pr_debug("%s:%d: found intr_type %u at res_index %u\n",
__func__, __LINE__, intr_type, res_index);
@@ -612,8 +669,8 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
return result;
}
-int ps3_repository_find_region(const struct ps3_repository_device *dev,
- enum ps3_region_type reg_type, u64 *bus_addr, u64 *len)
+int ps3_repository_find_reg(const struct ps3_repository_device *dev,
+ enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len)
{
int result = 0;
unsigned int res_index;
@@ -623,7 +680,7 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev,
*bus_addr = *len = 0;
for (res_index = 0; res_index < 10; res_index++) {
- enum ps3_region_type t;
+ enum ps3_reg_type t;
u64 a;
u64 l;
@@ -643,7 +700,8 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev,
}
}
- BUG_ON(res_index == 10);
+ if (res_index == 10)
+ return -ENODEV;
pr_debug("%s:%d: found reg_type %u at res_index %u\n",
__func__, __LINE__, reg_type, res_index);
@@ -651,6 +709,136 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev,
return result;
}
+int ps3_repository_read_stor_dev_port(unsigned int bus_index,
+ unsigned int dev_index, u64 *port)
+{
+ return read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("port", 0),
+ 0, port, 0);
+}
+
+int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index,
+ unsigned int dev_index, u64 *blk_size)
+{
+ return read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("blk_size", 0),
+ 0, blk_size, 0);
+}
+
+int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index,
+ unsigned int dev_index, u64 *num_blocks)
+{
+ return read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("n_blocks", 0),
+ 0, num_blocks, 0);
+}
+
+int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,
+ unsigned int dev_index, unsigned int *num_regions)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("n_regs", 0),
+ 0, &v1, 0);
+ *num_regions = v1;
+ return result;
+}
+
+int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,
+ unsigned int dev_index, unsigned int region_index,
+ unsigned int *region_id)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("region", region_index),
+ make_field("id", 0),
+ &v1, 0);
+ *region_id = v1;
+ return result;
+}
+
+int ps3_repository_read_stor_dev_region_size(unsigned int bus_index,
+ unsigned int dev_index, unsigned int region_index, u64 *region_size)
+{
+ return read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("region", region_index),
+ make_field("size", 0),
+ region_size, 0);
+}
+
+int ps3_repository_read_stor_dev_region_start(unsigned int bus_index,
+ unsigned int dev_index, unsigned int region_index, u64 *region_start)
+{
+ return read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("region", region_index),
+ make_field("start", 0),
+ region_start, 0);
+}
+
+int ps3_repository_read_stor_dev_info(unsigned int bus_index,
+ unsigned int dev_index, u64 *port, u64 *blk_size,
+ u64 *num_blocks, unsigned int *num_regions)
+{
+ int result;
+
+ result = ps3_repository_read_stor_dev_port(bus_index, dev_index, port);
+ if (result)
+ return result;
+
+ result = ps3_repository_read_stor_dev_blk_size(bus_index, dev_index,
+ blk_size);
+ if (result)
+ return result;
+
+ result = ps3_repository_read_stor_dev_num_blocks(bus_index, dev_index,
+ num_blocks);
+ if (result)
+ return result;
+
+ result = ps3_repository_read_stor_dev_num_regions(bus_index, dev_index,
+ num_regions);
+ return result;
+}
+
+int ps3_repository_read_stor_dev_region(unsigned int bus_index,
+ unsigned int dev_index, unsigned int region_index,
+ unsigned int *region_id, u64 *region_start, u64 *region_size)
+{
+ int result;
+
+ result = ps3_repository_read_stor_dev_region_id(bus_index, dev_index,
+ region_index, region_id);
+ if (result)
+ return result;
+
+ result = ps3_repository_read_stor_dev_region_start(bus_index, dev_index,
+ region_index, region_start);
+ if (result)
+ return result;
+
+ result = ps3_repository_read_stor_dev_region_size(bus_index, dev_index,
+ region_index, region_size);
+ return result;
+}
+
int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size)
{
return read_node(PS3_LPAR_ID_CURRENT,
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index d8b5cadbe80..e62505e1881 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -41,10 +41,18 @@
#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
#endif
-static void ps3_show_cpuinfo(struct seq_file *m)
+int ps3_get_firmware_version(union ps3_firmware_version *v)
{
- seq_printf(m, "machine\t\t: %s\n", ppc_md.name);
+ int result = lv1_get_version_info(&v->raw);
+
+ if (result) {
+ v->raw = 0;
+ return -1;
+ }
+
+ return result;
}
+EXPORT_SYMBOL_GPL(ps3_get_firmware_version);
static void ps3_power_save(void)
{
@@ -74,8 +82,14 @@ static void ps3_panic(char *str)
static void __init ps3_setup_arch(void)
{
+ union ps3_firmware_version v;
+
DBG(" -> %s:%d\n", __func__, __LINE__);
+ ps3_get_firmware_version(&v);
+ printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", v.major, v.minor,
+ v.rev);
+
ps3_spu_set_platform();
ps3_map_htab();
@@ -156,7 +170,6 @@ define_machine(ps3) {
.name = "PS3",
.probe = ps3_probe,
.setup_arch = ps3_setup_arch,
- .show_cpuinfo = ps3_show_cpuinfo,
.init_IRQ = ps3_init_IRQ,
.panic = ps3_panic,
.get_boot_time = ps3_get_boot_time,
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 11d2080607e..6fb887961a6 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -23,7 +23,6 @@
#include <asm/machdep.h>
#include <asm/udbg.h>
-#include <asm/ps3.h>
#include "platform.h"
@@ -111,7 +110,7 @@ static void __init ps3_smp_setup_cpu(int cpu)
BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
for (i = 0; i < MSG_COUNT; i++) {
- result = ps3_alloc_event_irq(&virqs[i]);
+ result = ps3_alloc_event_irq(cpu, &virqs[i]);
if (result)
continue;
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c
index 644532c3b7c..d1929721b0e 100644
--- a/arch/powerpc/platforms/ps3/spu.c
+++ b/arch/powerpc/platforms/ps3/spu.c
@@ -26,9 +26,10 @@
#include <asm/spu.h>
#include <asm/spu_priv1.h>
-#include <asm/ps3.h>
#include <asm/lv1call.h>
+#include "platform.h"
+
/* spu_management_ops */
/**
@@ -50,7 +51,7 @@ enum spe_type {
*/
struct spe_shadow {
- u8 padding_0000[0x0140];
+ u8 padding_0140[0x0140];
u64 int_status_class0_RW; /* 0x0140 */
u64 int_status_class1_RW; /* 0x0148 */
u64 int_status_class2_RW; /* 0x0150 */
@@ -67,8 +68,7 @@ struct spe_shadow {
u8 padding_0c08[0x0f00-0x0c08];
u64 spe_execution_status; /* 0x0f00 */
u8 padding_0f08[0x1000-0x0f08];
-} __attribute__ ((packed));
-
+};
/**
* enum spe_ex_state - Logical spe execution state.
@@ -268,20 +268,20 @@ static int __init setup_interrupts(struct spu *spu)
{
int result;
- result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 0,
- &spu->irqs[0]);
+ result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+ 0, &spu->irqs[0]);
if (result)
goto fail_alloc_0;
- result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 1,
- &spu->irqs[1]);
+ result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+ 1, &spu->irqs[1]);
if (result)
goto fail_alloc_1;
- result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 2,
- &spu->irqs[2]);
+ result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+ 2, &spu->irqs[2]);
if (result)
goto fail_alloc_2;
diff --git a/drivers/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
index d79f949bcb2..a9f7e4a39a2 100644
--- a/drivers/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -25,10 +25,11 @@
#include <linux/err.h>
#include <asm/udbg.h>
-#include <asm/ps3.h>
#include <asm/lv1call.h>
#include <asm/firmware.h>
+#include "platform.h"
+
#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
static void _dump_mmio_region(const struct ps3_mmio_region* r,
const char* func, int line)
@@ -50,27 +51,29 @@ int ps3_mmio_region_create(struct ps3_mmio_region *r)
if (result) {
pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n",
__func__, __LINE__, ps3_result(result));
- r->lpar_addr = r->len = r->bus_addr = 0;
+ r->lpar_addr = 0;
}
dump_mmio_region(r);
return result;
}
+EXPORT_SYMBOL_GPL(ps3_mmio_region_create);
int ps3_free_mmio_region(struct ps3_mmio_region *r)
{
int result;
result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id,
- r->bus_addr);
+ r->lpar_addr);
if (result)
pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n",
__func__, __LINE__, ps3_result(result));
- r->lpar_addr = r->len = r->bus_addr = 0;
+ r->lpar_addr = 0;
return result;
}
+EXPORT_SYMBOL_GPL(ps3_free_mmio_region);
static int ps3_system_bus_match(struct device *_dev,
struct device_driver *_drv)
@@ -158,7 +161,7 @@ static int ps3_system_bus_remove(struct device *_dev)
}
struct bus_type ps3_system_bus_type = {
- .name = "ps3_system_bus",
+ .name = "ps3_system_bus",
.match = ps3_system_bus_match,
.probe = ps3_system_bus_probe,
.remove = ps3_system_bus_remove,
@@ -271,10 +274,29 @@ static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
enum dma_data_direction direction)
{
+ struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ int i;
+
#if defined(CONFIG_PS3_DYNAMIC_DMA)
BUG_ON("do");
+ return -EPERM;
+#else
+ for (i = 0; i < nents; i++, sg++) {
+ int result = ps3_dma_map(dev->d_region,
+ page_to_phys(sg->page) + sg->offset, sg->length,
+ &sg->dma_address);
+
+ if (result) {
+ pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
+ __func__, __LINE__, result);
+ return -EINVAL;
+ }
+
+ sg->dma_length = sg->length;
+ }
+
+ return nents;
#endif
- return 0;
}
static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
@@ -287,7 +309,7 @@ static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
static int ps3_dma_supported(struct device *_dev, u64 mask)
{
- return 1;
+ return mask >= DMA_32BIT_MASK;
}
static struct dma_mapping_ops ps3_dma_ops = {
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 997243a91be..69590fbf83d 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -10,6 +10,8 @@ obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_SCANLOG) += scanlog.o
obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o
+obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o
+
obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
obj-$(CONFIG_HVCS) += hvcserver.o
obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 3c2d63ebf78..9437f48cc9e 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -337,6 +337,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n",
pdn->eeh_check_count);
dump_stack();
+ msleep(5000);
/* re-read the slot reset state */
if (read_slot_reset_state(pdn, rets) != 0)
@@ -746,6 +747,7 @@ struct eeh_early_enable_info {
/* Enable eeh for the given device node. */
static void *early_enable_eeh(struct device_node *dn, void *data)
{
+ unsigned int rets[3];
struct eeh_early_enable_info *info = data;
int ret;
const char *status = get_property(dn, "status", NULL);
@@ -802,16 +804,14 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
regs[0], info->buid_hi, info->buid_lo,
EEH_ENABLE);
+ enable = 0;
if (ret == 0) {
- eeh_subsystem_enabled = 1;
- pdn->eeh_mode |= EEH_MODE_SUPPORTED;
pdn->eeh_config_addr = regs[0];
/* If the newer, better, ibm,get-config-addr-info is supported,
* then use that instead. */
pdn->eeh_pe_config_addr = 0;
if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
- unsigned int rets[2];
ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets,
pdn->eeh_config_addr,
info->buid_hi, info->buid_lo,
@@ -819,6 +819,20 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
if (ret == 0)
pdn->eeh_pe_config_addr = rets[0];
}
+
+ /* Some older systems (Power4) allow the
+ * ibm,set-eeh-option call to succeed even on nodes
+ * where EEH is not supported. Verify support
+ * explicitly. */
+ ret = read_slot_reset_state(pdn, rets);
+ if ((ret == 0) && (rets[1] == 1))
+ enable = 1;
+ }
+
+ if (enable) {
+ eeh_subsystem_enabled = 1;
+ pdn->eeh_mode |= EEH_MODE_SUPPORTED;
+
#ifdef DEBUG
printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n",
dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr);
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c
index b6b462d3c60..f2bae04424f 100644
--- a/arch/powerpc/platforms/pseries/eeh_cache.c
+++ b/arch/powerpc/platforms/pseries/eeh_cache.c
@@ -153,7 +153,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo,
return piar;
}
}
- piar = (struct pci_io_addr_range *)kmalloc(sizeof(struct pci_io_addr_range), GFP_ATOMIC);
+ piar = kmalloc(sizeof(struct pci_io_addr_range), GFP_ATOMIC);
if (!piar)
return NULL;
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index c2bc9904f1c..a4c0bf84ef2 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -170,14 +170,19 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
static void eeh_report_resume(struct pci_dev *dev, void *userdata)
{
struct pci_driver *driver = dev->driver;
+ struct device_node *dn = pci_device_to_OF_node(dev);
dev->error_state = pci_channel_io_normal;
if (!driver)
return;
- if (!driver->err_handler)
- return;
- if (!driver->err_handler->resume)
+
+ if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
+ PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
+ enable_irq(dev->irq);
+ }
+ if (!driver->err_handler ||
+ !driver->err_handler->resume)
return;
driver->err_handler->resume(dev);
@@ -407,6 +412,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
if (rc)
result = PCI_ERS_RESULT_NEED_RESET;
+ else
+ result = PCI_ERS_RESULT_RECOVERED;
}
/* If any device has a hard failure, then shut off everything. */
@@ -439,7 +446,8 @@ excess_failures:
*/
printk(KERN_ERR
"EEH: PCI device at location=%s driver=%s pci addr=%s \n"
- "has failed %d times and has been permanently disabled. \n"
+ "has failed %d times in the last hour "
+ "and has been permanently disabled. \n"
"Please try reseating this device or replacing it.\n",
location, drv_str, pci_str, frozen_pdn->eeh_freeze_count);
goto perm_error;
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 1c7b2baa5f7..90522e3c9d4 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -59,6 +59,7 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = {
{FW_FEATURE_XDABR, "hcall-xdabr"},
{FW_FEATURE_MULTITCE, "hcall-multi-tce"},
{FW_FEATURE_SPLPAR, "hcall-splpar"},
+ {FW_FEATURE_BULK_REMOVE, "hcall-bulk"},
};
/* Build up the firmware features bitmask using the contents of
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
new file mode 100644
index 00000000000..f460b9cbfd4
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -0,0 +1,275 @@
+/*
+ * pseries CPU Hotplug infrastructure.
+ *
+ * Split out from arch/powerpc/platforms/pseries/setup.c
+ * arch/powerpc/kernel/rtas.c, and arch/powerpc/platforms/pseries/smp.c
+ *
+ * Peter Bergner, IBM March 2001.
+ * Copyright (C) 2001 IBM.
+ * Dave Engebretsen, Peter Bergner, and
+ * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
+ * Plus various changes from other IBM teams...
+ *
+ * Copyright (C) 2006 Michael Ellerman, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/cpu.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/firmware.h>
+#include <asm/machdep.h>
+#include <asm/vdso_datapage.h>
+#include <asm/pSeries_reconfig.h>
+#include "xics.h"
+
+/* This version can't take the spinlock, because it never returns */
+static struct rtas_args rtas_stop_self_args = {
+ .token = RTAS_UNKNOWN_SERVICE,
+ .nargs = 0,
+ .nret = 1,
+ .rets = &rtas_stop_self_args.args[0],
+};
+
+static void rtas_stop_self(void)
+{
+ struct rtas_args *args = &rtas_stop_self_args;
+
+ local_irq_disable();
+
+ BUG_ON(args->token == RTAS_UNKNOWN_SERVICE);
+
+ printk("cpu %u (hwid %u) Ready to die...\n",
+ smp_processor_id(), hard_smp_processor_id());
+ enter_rtas(__pa(args));
+
+ panic("Alas, I survived.\n");
+}
+
+static void pseries_mach_cpu_die(void)
+{
+ local_irq_disable();
+ idle_task_exit();
+ xics_teardown_cpu(0);
+ rtas_stop_self();
+ /* Should never get here... */
+ BUG();
+ for(;;);
+}
+
+static int qcss_tok; /* query-cpu-stopped-state token */
+
+/* Get state of physical CPU.
+ * Return codes:
+ * 0 - The processor is in the RTAS stopped state
+ * 1 - stop-self is in progress
+ * 2 - The processor is not in the RTAS stopped state
+ * -1 - Hardware Error
+ * -2 - Hardware Busy, Try again later.
+ */
+static int query_cpu_stopped(unsigned int pcpu)
+{
+ int cpu_status, status;
+
+ status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu);
+ if (status != 0) {
+ printk(KERN_ERR
+ "RTAS query-cpu-stopped-state failed: %i\n", status);
+ return status;
+ }
+
+ return cpu_status;
+}
+
+static int pseries_cpu_disable(void)
+{
+ int cpu = smp_processor_id();
+
+ cpu_clear(cpu, cpu_online_map);
+ vdso_data->processorCount--;
+
+ /*fix boot_cpuid here*/
+ if (cpu == boot_cpuid)
+ boot_cpuid = any_online_cpu(cpu_online_map);
+
+ /* FIXME: abstract this to not be platform specific later on */
+ xics_migrate_irqs_away();
+ return 0;
+}
+
+static void pseries_cpu_die(unsigned int cpu)
+{
+ int tries;
+ int cpu_status;
+ unsigned int pcpu = get_hard_smp_processor_id(cpu);
+
+ for (tries = 0; tries < 25; tries++) {
+ cpu_status = query_cpu_stopped(pcpu);
+ if (cpu_status == 0 || cpu_status == -1)
+ break;
+ msleep(200);
+ }
+ if (cpu_status != 0) {
+ printk("Querying DEAD? cpu %i (%i) shows %i\n",
+ cpu, pcpu, cpu_status);
+ }
+
+ /* Isolation and deallocation are definatly done by
+ * drslot_chrp_cpu. If they were not they would be
+ * done here. Change isolate state to Isolate and
+ * change allocation-state to Unusable.
+ */
+ paca[cpu].cpu_start = 0;
+}
+
+/*
+ * Update cpu_present_map and paca(s) for a new cpu node. The wrinkle
+ * here is that a cpu device node may represent up to two logical cpus
+ * in the SMT case. We must honor the assumption in other code that
+ * the logical ids for sibling SMT threads x and y are adjacent, such
+ * that x^1 == y and y^1 == x.
+ */
+static int pseries_add_processor(struct device_node *np)
+{
+ unsigned int cpu;
+ cpumask_t candidate_map, tmp = CPU_MASK_NONE;
+ int err = -ENOSPC, len, nthreads, i;
+ const u32 *intserv;
+
+ intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+ if (!intserv)
+ return 0;
+
+ nthreads = len / sizeof(u32);
+ for (i = 0; i < nthreads; i++)
+ cpu_set(i, tmp);
+
+ lock_cpu_hotplug();
+
+ BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
+
+ /* Get a bitmap of unoccupied slots. */
+ cpus_xor(candidate_map, cpu_possible_map, cpu_present_map);
+ if (cpus_empty(candidate_map)) {
+ /* If we get here, it most likely means that NR_CPUS is
+ * less than the partition's max processors setting.
+ */
+ printk(KERN_ERR "Cannot add cpu %s; this system configuration"
+ " supports %d logical cpus.\n", np->full_name,
+ cpus_weight(cpu_possible_map));
+ goto out_unlock;
+ }
+
+ while (!cpus_empty(tmp))
+ if (cpus_subset(tmp, candidate_map))
+ /* Found a range where we can insert the new cpu(s) */
+ break;
+ else
+ cpus_shift_left(tmp, tmp, nthreads);
+
+ if (cpus_empty(tmp)) {
+ printk(KERN_ERR "Unable to find space in cpu_present_map for"
+ " processor %s with %d thread(s)\n", np->name,
+ nthreads);
+ goto out_unlock;
+ }
+
+ for_each_cpu_mask(cpu, tmp) {
+ BUG_ON(cpu_isset(cpu, cpu_present_map));
+ cpu_set(cpu, cpu_present_map);
+ set_hard_smp_processor_id(cpu, *intserv++);
+ }
+ err = 0;
+out_unlock:
+ unlock_cpu_hotplug();
+ return err;
+}
+
+/*
+ * Update the present map for a cpu node which is going away, and set
+ * the hard id in the paca(s) to -1 to be consistent with boot time
+ * convention for non-present cpus.
+ */
+static void pseries_remove_processor(struct device_node *np)
+{
+ unsigned int cpu;
+ int len, nthreads, i;
+ const u32 *intserv;
+
+ intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+ if (!intserv)
+ return;
+
+ nthreads = len / sizeof(u32);
+
+ lock_cpu_hotplug();
+ for (i = 0; i < nthreads; i++) {
+ for_each_present_cpu(cpu) {
+ if (get_hard_smp_processor_id(cpu) != intserv[i])
+ continue;
+ BUG_ON(cpu_online(cpu));
+ cpu_clear(cpu, cpu_present_map);
+ set_hard_smp_processor_id(cpu, -1);
+ break;
+ }
+ if (cpu == NR_CPUS)
+ printk(KERN_WARNING "Could not find cpu to remove "
+ "with physical id 0x%x\n", intserv[i]);
+ }
+ unlock_cpu_hotplug();
+}
+
+static int pseries_smp_notifier(struct notifier_block *nb,
+ unsigned long action, void *node)
+{
+ int err = NOTIFY_OK;
+
+ switch (action) {
+ case PSERIES_RECONFIG_ADD:
+ if (pseries_add_processor(node))
+ err = NOTIFY_BAD;
+ break;
+ case PSERIES_RECONFIG_REMOVE:
+ pseries_remove_processor(node);
+ break;
+ default:
+ err = NOTIFY_DONE;
+ break;
+ }
+ return err;
+}
+
+static struct notifier_block pseries_smp_nb = {
+ .notifier_call = pseries_smp_notifier,
+};
+
+static int __init pseries_cpu_hotplug_init(void)
+{
+ rtas_stop_self_args.token = rtas_token("stop-self");
+ qcss_tok = rtas_token("query-cpu-stopped-state");
+
+ if (rtas_stop_self_args.token == RTAS_UNKNOWN_SERVICE ||
+ qcss_tok == RTAS_UNKNOWN_SERVICE) {
+ printk(KERN_INFO "CPU Hotplug not supported by firmware "
+ "- disabling.\n");
+ return 0;
+ }
+
+ ppc_md.cpu_die = pseries_mach_cpu_die;
+ smp_ops->cpu_disable = pseries_cpu_disable;
+ smp_ops->cpu_die = pseries_cpu_die;
+
+ /* Processors can be added/removed only on LPAR */
+ if (firmware_has_feature(FW_FEATURE_LPAR))
+ pSeries_reconfig_notifier_register(&pseries_smp_nb);
+
+ return 0;
+}
+arch_initcall(pseries_cpu_hotplug_init);
diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S
index c00cfed7af2..5c7e3878989 100644
--- a/arch/powerpc/platforms/pseries/hvCall.S
+++ b/arch/powerpc/platforms/pseries/hvCall.S
@@ -26,7 +26,7 @@
BEGIN_FTR_SECTION; \
mfspr r0,SPRN_PURR; /* get PURR and */ \
std r0,STK_PARM(r6)(r1); /* save for later */ \
-END_FTR_SECTION_IFCLR(CPU_FTR_PURR);
+END_FTR_SECTION_IFSET(CPU_FTR_PURR);
/*
* postcall is performed immediately before function return which
@@ -43,7 +43,7 @@ BEGIN_FTR_SECTION; \
mfspr r8,SPRN_PURR; /* PURR after */ \
ld r6,STK_PARM(r6)(r1); /* PURR before */ \
subf r6,r6,r8; /* delta */ \
-END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
+END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
ld r5,STK_PARM(r5)(r1); /* timebase before */ \
subf r5,r5,r7; /* time delta */ \
\
@@ -66,7 +66,7 @@ BEGIN_FTR_SECTION; \
ld r7,HCALL_STAT_PURR(r4); /* PURR */ \
add r7,r7,r6; \
std r7,HCALL_STAT_PURR(r4); \
-END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
+END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
1:
#else
#define HCALL_INST_PRECALL
@@ -145,6 +145,7 @@ _GLOBAL(plpar_hcall9)
HVSC /* invoke the hypervisor */
+ mr r0,r12
ld r12,STK_PARM(r4)(r1)
std r4, 0(r12)
std r5, 8(r12)
@@ -154,7 +155,7 @@ _GLOBAL(plpar_hcall9)
std r9, 40(r12)
std r10,48(r12)
std r11,56(r12)
- std r12,64(r12)
+ std r0, 64(r12)
HCALL_INST_POSTCALL
diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c
index 446e17d162a..3ddc04925d5 100644
--- a/arch/powerpc/platforms/pseries/hvCall_inst.c
+++ b/arch/powerpc/platforms/pseries/hvCall_inst.c
@@ -34,7 +34,7 @@ DEFINE_PER_CPU(struct hcall_stats[HCALL_STAT_ARRAY_SIZE], hcall_stats);
*/
static void *hc_start(struct seq_file *m, loff_t *pos)
{
- if ((int)*pos < HCALL_STAT_ARRAY_SIZE)
+ if ((int)*pos < (HCALL_STAT_ARRAY_SIZE-1))
return (void *)(unsigned long)(*pos + 1);
return NULL;
@@ -57,7 +57,7 @@ static int hc_show(struct seq_file *m, void *p)
struct hcall_stats *hs = (struct hcall_stats *)m->private;
if (hs[h_num].num_calls) {
- if (!cpu_has_feature(CPU_FTR_PURR))
+ if (cpu_has_feature(CPU_FTR_PURR))
seq_printf(m, "%lu %lu %lu %lu\n", h_num<<2,
hs[h_num].num_calls,
hs[h_num].tb_total,
@@ -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->i_private;
+ seq->private = file->f_path.dentry->d_inode->i_private;
return rc;
}
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 3c95392f4f4..e6653a868b9 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -459,7 +459,8 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
phb->node);
iommu_table_setparms(phb, dn, tbl);
- dev->dev.archdata.dma_data = iommu_init_table(tbl, phb->node);
+ PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node);
+ dev->dev.archdata.dma_data = PCI_DN(dn)->iommu_table;
return;
}
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 721436db3ef..7496005566e 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -502,23 +502,70 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
BUG_ON(lpar_rc != H_SUCCESS);
}
+/* Flag bits for H_BULK_REMOVE */
+#define HBR_REQUEST 0x4000000000000000UL
+#define HBR_RESPONSE 0x8000000000000000UL
+#define HBR_END 0xc000000000000000UL
+#define HBR_AVPN 0x0200000000000000UL
+#define HBR_ANDCOND 0x0100000000000000UL
+
/*
* Take a spinlock around flushes to avoid bouncing the hypervisor tlbie
* lock.
*/
static void pSeries_lpar_flush_hash_range(unsigned long number, int local)
{
- int i;
+ unsigned long i, pix, rc;
unsigned long flags = 0;
struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
+ unsigned long param[9];
+ unsigned long va;
+ unsigned long hash, index, shift, hidx, slot;
+ real_pte_t pte;
+ int psize;
if (lock_tlbie)
spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
- for (i = 0; i < number; i++)
- flush_hash_page(batch->vaddr[i], batch->pte[i],
- batch->psize, local);
+ psize = batch->psize;
+ pix = 0;
+ for (i = 0; i < number; i++) {
+ va = batch->vaddr[i];
+ pte = batch->pte[i];
+ pte_iterate_hashed_subpages(pte, psize, va, index, shift) {
+ hash = hpt_hash(va, shift);
+ hidx = __rpte_to_hidx(pte, index);
+ if (hidx & _PTEIDX_SECONDARY)
+ hash = ~hash;
+ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ slot += hidx & _PTEIDX_GROUP_IX;
+ if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) {
+ pSeries_lpar_hpte_invalidate(slot, va, psize,
+ local);
+ } else {
+ param[pix] = HBR_REQUEST | HBR_AVPN | slot;
+ param[pix+1] = hpte_encode_v(va, psize) &
+ HPTE_V_AVPN;
+ pix += 2;
+ if (pix == 8) {
+ rc = plpar_hcall9(H_BULK_REMOVE, param,
+ param[0], param[1], param[2],
+ param[3], param[4], param[5],
+ param[6], param[7]);
+ BUG_ON(rc != H_SUCCESS);
+ pix = 0;
+ }
+ }
+ } pte_iterate_hashed_end();
+ }
+ if (pix) {
+ param[pix] = HBR_END;
+ rc = plpar_hcall9(H_BULK_REMOVE, param, param[0], param[1],
+ param[2], param[3], param[4], param[5],
+ param[6], param[7]);
+ BUG_ON(rc != H_SUCCESS);
+ }
if (lock_tlbie)
spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags);
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index 715db5c8990..c69bd15ced9 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -77,7 +77,7 @@ void __init pSeries_final_fixup(void)
/*
* Assume the winbond 82c105 is the IDE controller on a
- * p610. We should probably be more careful in case
+ * p610/p615/p630. We should probably be more careful in case
* someone tries to plug in a similar adapter.
*/
static void fixup_winbond_82c105(struct pci_dev* dev)
diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c
index 77a5bb1d9c3..45368a57d7d 100644
--- a/arch/powerpc/platforms/pseries/scanlog.c
+++ b/arch/powerpc/platforms/pseries/scanlog.c
@@ -47,7 +47,7 @@ static struct proc_dir_entry *proc_ppc64_scan_log_dump; /* The proc file */
static ssize_t scanlog_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
struct proc_dir_entry *dp;
unsigned int *data;
int status;
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 0dc2548ca9b..042ecae107a 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -347,21 +347,6 @@ static int __init pSeries_init_panel(void)
}
arch_initcall(pSeries_init_panel);
-#ifdef CONFIG_HOTPLUG_CPU
-static void pSeries_mach_cpu_die(void)
-{
- local_irq_disable();
- idle_task_exit();
- xics_teardown_cpu(0);
- rtas_stop_self();
- /* Should never get here... */
- BUG();
- for(;;);
-}
-#else
-#define pSeries_mach_cpu_die NULL
-#endif
-
static int pseries_set_dabr(unsigned long dabr)
{
return plpar_hcall_norets(H_SET_DABR, dabr);
@@ -437,19 +422,14 @@ static int __init pSeries_probe_hypertas(unsigned long node,
if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
powerpc_firmware_features |= FW_FEATURE_LPAR;
- if (firmware_has_feature(FW_FEATURE_LPAR))
- hpte_init_lpar();
- else
- hpte_init_native();
-
return 1;
}
static int __init pSeries_probe(void)
{
unsigned long root = of_get_flat_dt_root();
- char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
- "device_type", NULL);
+ char *dtype = of_get_flat_dt_prop(root, "device_type", NULL);
+
if (dtype == NULL)
return 0;
if (strcmp(dtype, "chrp"))
@@ -467,6 +447,11 @@ static int __init pSeries_probe(void)
/* Now try to figure out if we are running on LPAR */
of_scan_flat_dt(pSeries_probe_hypertas, NULL);
+ if (firmware_has_feature(FW_FEATURE_LPAR))
+ hpte_init_lpar();
+ else
+ hpte_init_native();
+
DBG("Machine is%s LPAR !\n",
(powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not");
@@ -561,7 +546,6 @@ define_machine(pseries) {
.power_off = rtas_power_off,
.halt = rtas_halt,
.panic = rtas_os_term,
- .cpu_die = pSeries_mach_cpu_die,
.get_boot_time = rtas_get_boot_time,
.get_rtc_time = rtas_get_rtc_time,
.set_rtc_time = rtas_set_rtc_time,
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index c6624b8a0e7..4408518eaeb 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -64,197 +64,6 @@ static cpumask_t of_spin_map;
extern void generic_secondary_smp_init(unsigned long);
-#ifdef CONFIG_HOTPLUG_CPU
-
-/* Get state of physical CPU.
- * Return codes:
- * 0 - The processor is in the RTAS stopped state
- * 1 - stop-self is in progress
- * 2 - The processor is not in the RTAS stopped state
- * -1 - Hardware Error
- * -2 - Hardware Busy, Try again later.
- */
-static int query_cpu_stopped(unsigned int pcpu)
-{
- int cpu_status;
- int status, qcss_tok;
-
- qcss_tok = rtas_token("query-cpu-stopped-state");
- if (qcss_tok == RTAS_UNKNOWN_SERVICE)
- return -1;
- status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu);
- if (status != 0) {
- printk(KERN_ERR
- "RTAS query-cpu-stopped-state failed: %i\n", status);
- return status;
- }
-
- return cpu_status;
-}
-
-static int pSeries_cpu_disable(void)
-{
- int cpu = smp_processor_id();
-
- cpu_clear(cpu, cpu_online_map);
- vdso_data->processorCount--;
-
- /*fix boot_cpuid here*/
- if (cpu == boot_cpuid)
- boot_cpuid = any_online_cpu(cpu_online_map);
-
- /* FIXME: abstract this to not be platform specific later on */
- xics_migrate_irqs_away();
- return 0;
-}
-
-static void pSeries_cpu_die(unsigned int cpu)
-{
- int tries;
- int cpu_status;
- unsigned int pcpu = get_hard_smp_processor_id(cpu);
-
- for (tries = 0; tries < 25; tries++) {
- cpu_status = query_cpu_stopped(pcpu);
- if (cpu_status == 0 || cpu_status == -1)
- break;
- msleep(200);
- }
- if (cpu_status != 0) {
- printk("Querying DEAD? cpu %i (%i) shows %i\n",
- cpu, pcpu, cpu_status);
- }
-
- /* Isolation and deallocation are definatly done by
- * drslot_chrp_cpu. If they were not they would be
- * done here. Change isolate state to Isolate and
- * change allocation-state to Unusable.
- */
- paca[cpu].cpu_start = 0;
-}
-
-/*
- * Update cpu_present_map and paca(s) for a new cpu node. The wrinkle
- * here is that a cpu device node may represent up to two logical cpus
- * in the SMT case. We must honor the assumption in other code that
- * the logical ids for sibling SMT threads x and y are adjacent, such
- * that x^1 == y and y^1 == x.
- */
-static int pSeries_add_processor(struct device_node *np)
-{
- unsigned int cpu;
- cpumask_t candidate_map, tmp = CPU_MASK_NONE;
- int err = -ENOSPC, len, nthreads, i;
- const u32 *intserv;
-
- intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
- if (!intserv)
- return 0;
-
- nthreads = len / sizeof(u32);
- for (i = 0; i < nthreads; i++)
- cpu_set(i, tmp);
-
- lock_cpu_hotplug();
-
- BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
-
- /* Get a bitmap of unoccupied slots. */
- cpus_xor(candidate_map, cpu_possible_map, cpu_present_map);
- if (cpus_empty(candidate_map)) {
- /* If we get here, it most likely means that NR_CPUS is
- * less than the partition's max processors setting.
- */
- printk(KERN_ERR "Cannot add cpu %s; this system configuration"
- " supports %d logical cpus.\n", np->full_name,
- cpus_weight(cpu_possible_map));
- goto out_unlock;
- }
-
- while (!cpus_empty(tmp))
- if (cpus_subset(tmp, candidate_map))
- /* Found a range where we can insert the new cpu(s) */
- break;
- else
- cpus_shift_left(tmp, tmp, nthreads);
-
- if (cpus_empty(tmp)) {
- printk(KERN_ERR "Unable to find space in cpu_present_map for"
- " processor %s with %d thread(s)\n", np->name,
- nthreads);
- goto out_unlock;
- }
-
- for_each_cpu_mask(cpu, tmp) {
- BUG_ON(cpu_isset(cpu, cpu_present_map));
- cpu_set(cpu, cpu_present_map);
- set_hard_smp_processor_id(cpu, *intserv++);
- }
- err = 0;
-out_unlock:
- unlock_cpu_hotplug();
- return err;
-}
-
-/*
- * Update the present map for a cpu node which is going away, and set
- * the hard id in the paca(s) to -1 to be consistent with boot time
- * convention for non-present cpus.
- */
-static void pSeries_remove_processor(struct device_node *np)
-{
- unsigned int cpu;
- int len, nthreads, i;
- const u32 *intserv;
-
- intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
- if (!intserv)
- return;
-
- nthreads = len / sizeof(u32);
-
- lock_cpu_hotplug();
- for (i = 0; i < nthreads; i++) {
- for_each_present_cpu(cpu) {
- if (get_hard_smp_processor_id(cpu) != intserv[i])
- continue;
- BUG_ON(cpu_online(cpu));
- cpu_clear(cpu, cpu_present_map);
- set_hard_smp_processor_id(cpu, -1);
- break;
- }
- if (cpu == NR_CPUS)
- printk(KERN_WARNING "Could not find cpu to remove "
- "with physical id 0x%x\n", intserv[i]);
- }
- unlock_cpu_hotplug();
-}
-
-static int pSeries_smp_notifier(struct notifier_block *nb, unsigned long action, void *node)
-{
- int err = NOTIFY_OK;
-
- switch (action) {
- case PSERIES_RECONFIG_ADD:
- if (pSeries_add_processor(node))
- err = NOTIFY_BAD;
- break;
- case PSERIES_RECONFIG_REMOVE:
- pSeries_remove_processor(node);
- break;
- default:
- err = NOTIFY_DONE;
- break;
- }
- return err;
-}
-
-static struct notifier_block pSeries_smp_nb = {
- .notifier_call = pSeries_smp_notifier,
-};
-
-#endif /* CONFIG_HOTPLUG_CPU */
-
/**
* smp_startup_cpu() - start the given cpu
*
@@ -422,15 +231,6 @@ static void __init smp_init_pseries(void)
DBG(" -> smp_init_pSeries()\n");
-#ifdef CONFIG_HOTPLUG_CPU
- smp_ops->cpu_disable = pSeries_cpu_disable;
- smp_ops->cpu_die = pSeries_cpu_die;
-
- /* Processors can be added/removed only on LPAR */
- if (firmware_has_feature(FW_FEATURE_LPAR))
- pSeries_reconfig_notifier_register(&pSeries_smp_nb);
-#endif
-
/* Mark threads which are still spinning in hold loops. */
if (cpu_has_feature(CPU_FTR_SMT)) {
for_each_present_cpu(i) {
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index b5b2b1103de..81d172d6503 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -224,7 +224,6 @@ static void xics_unmask_irq(unsigned int virq)
static void xics_mask_real_irq(unsigned int irq)
{
int call_status;
- unsigned int server;
if (irq == XICS_IPI)
return;
@@ -236,9 +235,9 @@ static void xics_mask_real_irq(unsigned int irq)
return;
}
- server = get_irq_server(irq);
/* Have to set XIVE to 0xff to be able to remove a slot */
- call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, 0xff);
+ call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq,
+ default_server, 0xff);
if (call_status != 0) {
printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)"
" returned %d\n", irq, call_status);
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 6cc34597a62..85dcdf17841 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -5,13 +5,13 @@ endif
obj-$(CONFIG_MPIC) += mpic.o
obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
obj-$(CONFIG_PPC_MPC106) += grackle.o
-obj-$(CONFIG_PPC_DCR) += dcr.o dcr-low.o
+obj-$(CONFIG_PPC_DCR) += dcr.o
+obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o
obj-$(CONFIG_U3_DART) += dart_iommu.o
obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
-obj-$(CONFIG_MTD) += rom.o
ifeq ($(CONFIG_PPC_MERGE),y)
obj-$(CONFIG_PPC_I8259) += i8259.o
@@ -20,5 +20,8 @@ endif
# Temporary hack until we have migrated to asm-powerpc
ifeq ($(ARCH),powerpc)
+obj-$(CONFIG_MTD) += rom.o
obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o
+obj-$(CONFIG_8xx) += mpc8xx_pic.o commproc.o
+obj-$(CONFIG_UCODE_PATCH) += micropatch.o
endif
diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c
new file mode 100644
index 00000000000..9b4fafd9a84
--- /dev/null
+++ b/arch/powerpc/sysdev/commproc.c
@@ -0,0 +1,398 @@
+/*
+ * General Purpose functions for the global management of the
+ * Communication Processor Module.
+ * Copyright (c) 1997 Dan error_act (dmalek@jlc.net)
+ *
+ * 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.
+ * The amount of space available is platform dependent. On the
+ * MBX, the EPPC software loads additional microcode into the
+ * communication processor, and uses some of the DP ram for this
+ * purpose. Current, the first 512 bytes and the last 256 bytes of
+ * memory are used. Right now I am conservative and only use the
+ * memory that can never be used for microcode. If there are
+ * applications that require more DP ram, we can expand the boundaries
+ * but then we have to be careful of any downloaded microcode.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <asm/mpc8xx.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+#include <asm/rheap.h>
+#include <asm/prom.h>
+
+#include <asm/fs_pd.h>
+
+#define CPM_MAP_SIZE (0x4000)
+
+static void m8xx_cpm_dpinit(void);
+static uint host_buffer; /* One page of host buffer */
+static uint host_end; /* end + 1 */
+cpm8xx_t *cpmp; /* Pointer to comm processor space */
+cpic8xx_t *cpic_reg;
+
+static struct device_node *cpm_pic_node;
+static struct irq_host *cpm_pic_host;
+
+static void cpm_mask_irq(unsigned int irq)
+{
+ unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
+
+ clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
+}
+
+static void cpm_unmask_irq(unsigned int irq)
+{
+ unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
+
+ setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
+}
+
+static void cpm_end_irq(unsigned int irq)
+{
+ unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
+
+ out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec));
+}
+
+static struct irq_chip cpm_pic = {
+ .typename = " CPM PIC ",
+ .mask = cpm_mask_irq,
+ .unmask = cpm_unmask_irq,
+ .eoi = cpm_end_irq,
+};
+
+int cpm_get_irq(void)
+{
+ int cpm_vec;
+
+ /* Get the vector by setting the ACK bit and then reading
+ * the register.
+ */
+ out_be16(&cpic_reg->cpic_civr, 1);
+ cpm_vec = in_be16(&cpic_reg->cpic_civr);
+ cpm_vec >>= 11;
+
+ return irq_linear_revmap(cpm_pic_host, cpm_vec);
+}
+
+static int cpm_pic_host_match(struct irq_host *h, struct device_node *node)
+{
+ return cpm_pic_node == node;
+}
+
+static int cpm_pic_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw);
+
+ get_irq_desc(virq)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq);
+ return 0;
+}
+
+/* The CPM can generate the error interrupt when there is a race condition
+ * between generating and masking interrupts. All we have to do is ACK it
+ * and return. This is a no-op function so we don't need any special
+ * tests in the interrupt handler.
+ */
+static irqreturn_t cpm_error_interrupt(int irq, void *dev)
+{
+ return IRQ_HANDLED;
+}
+
+static struct irqaction cpm_error_irqaction = {
+ .handler = cpm_error_interrupt,
+ .mask = CPU_MASK_NONE,
+ .name = "error",
+};
+
+static struct irq_host_ops cpm_pic_host_ops = {
+ .match = cpm_pic_host_match,
+ .map = cpm_pic_host_map,
+};
+
+unsigned int cpm_pic_init(void)
+{
+ struct device_node *np = NULL;
+ struct resource res;
+ unsigned int sirq = NO_IRQ, hwirq, eirq;
+ int ret;
+
+ pr_debug("cpm_pic_init\n");
+
+ np = of_find_compatible_node(NULL, "cpm-pic", "CPM");
+ if (np == NULL) {
+ printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n");
+ return sirq;
+ }
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ goto end;
+
+ cpic_reg = (void *)ioremap(res.start, res.end - res.start + 1);
+ if (cpic_reg == NULL)
+ goto end;
+
+ sirq = irq_of_parse_and_map(np, 0);
+ if (sirq == NO_IRQ)
+ goto end;
+
+ /* Initialize the CPM interrupt controller. */
+ hwirq = (unsigned int)irq_map[sirq].hwirq;
+ out_be32(&cpic_reg->cpic_cicr,
+ (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
+ ((hwirq/2) << 13) | CICR_HP_MASK);
+
+ out_be32(&cpic_reg->cpic_cimr, 0);
+
+ cpm_pic_node = of_node_get(np);
+
+ cpm_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm_pic_host_ops, 64);
+ if (cpm_pic_host == NULL) {
+ printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
+ sirq = NO_IRQ;
+ goto end;
+ }
+ of_node_put(np);
+
+ /* Install our own error handler. */
+ np = of_find_node_by_type(NULL, "cpm");
+ if (np == NULL) {
+ printk(KERN_ERR "CPM PIC init: can not find cpm node\n");
+ goto end;
+ }
+ eirq= irq_of_parse_and_map(np, 0);
+ if (eirq == NO_IRQ)
+ goto end;
+
+ if (setup_irq(eirq, &cpm_error_irqaction))
+ printk(KERN_ERR "Could not allocate CPM error IRQ!");
+
+ setbits32(&cpic_reg->cpic_cicr, CICR_IEN);
+
+end:
+ of_node_put(np);
+ return sirq;
+}
+
+void cpm_reset(void)
+{
+ cpm8xx_t *commproc;
+ sysconf8xx_t *siu_conf;
+
+ commproc = (cpm8xx_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
+
+#ifdef CONFIG_UCODE_PATCH
+ /* Perform a reset.
+ */
+ out_be16(&commproc->cp_cpcr, CPM_CR_RST | CPM_CR_FLG);
+
+ /* Wait for it.
+ */
+ while (in_be16(&commproc->cp_cpcr) & CPM_CR_FLG);
+
+ cpm_load_patch(commproc);
+#endif
+
+ /* Set SDMA Bus Request priority 5.
+ * On 860T, this also enables FEC priority 6. I am not sure
+ * this is what we realy want for some applications, but the
+ * manual recommends it.
+ * Bit 25, FAM can also be set to use FEC aggressive mode (860T).
+ */
+ siu_conf = (sysconf8xx_t*)immr_map(im_siu_conf);
+ out_be32(&siu_conf->sc_sdcr, 1);
+ immr_unmap(siu_conf);
+
+ /* Reclaim the DP memory for our use. */
+ m8xx_cpm_dpinit();
+
+ /* Tell everyone where the comm processor resides.
+ */
+ cpmp = commproc;
+}
+
+/* We used to do this earlier, but have to postpone as long as possible
+ * to ensure the kernel VM is now running.
+ */
+static void
+alloc_host_memory(void)
+{
+ dma_addr_t physaddr;
+
+ /* Set the host page for allocation.
+ */
+ host_buffer = (uint)dma_alloc_coherent(NULL, PAGE_SIZE, &physaddr,
+ GFP_KERNEL);
+ host_end = host_buffer + PAGE_SIZE;
+}
+
+/* We also own one page of host buffer space for the allocation of
+ * UART "fifos" and the like.
+ */
+uint
+m8xx_cpm_hostalloc(uint size)
+{
+ uint retloc;
+
+ if (host_buffer == 0)
+ alloc_host_memory();
+
+ if ((host_buffer + size) >= host_end)
+ return(0);
+
+ retloc = host_buffer;
+ host_buffer += size;
+
+ return(retloc);
+}
+
+/* Set a baud rate generator. This needs lots of work. There are
+ * four BRGs, any of which can be wired to any channel.
+ * The internal baud rate clock is the system clock divided by 16.
+ * This assumes the baudrate is 16x oversampled by the uart.
+ */
+#define BRG_INT_CLK (get_brgfreq())
+#define BRG_UART_CLK (BRG_INT_CLK/16)
+#define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16)
+
+void
+cpm_setbrg(uint brg, uint rate)
+{
+ volatile uint *bp;
+
+ /* This is good enough to get SMCs running.....
+ */
+ bp = (uint *)&cpmp->cp_brgc1;
+ bp += brg;
+ /* The BRG has a 12-bit counter. For really slow baud rates (or
+ * really fast processors), we may have to further divide by 16.
+ */
+ if (((BRG_UART_CLK / rate) - 1) < 4096)
+ *bp = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN;
+ else
+ *bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
+ CPM_BRG_EN | CPM_BRG_DIV16;
+}
+
+/*
+ * 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;
+
+#define CPM_DPMEM_ALIGNMENT 8
+static u8* dpram_vbase;
+static uint dpram_pbase;
+
+void m8xx_cpm_dpinit(void)
+{
+ spin_lock_init(&cpm_dpmem_lock);
+
+ dpram_vbase = immr_map_size(im_cpm.cp_dpmem, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE);
+ dpram_pbase = (uint)&((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem;
+
+ /* Initialize the info header */
+ rh_init(&cpm_dpmem_info, CPM_DPMEM_ALIGNMENT,
+ 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 are a subset of the available dparm. It varies
+ * with the processor and the microcode patches applied / activated.
+ * But the following should be at least safe.
+ */
+ rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
+}
+
+/*
+ * Allocate the requested size worth of DP memory.
+ * This function returns an offset into the DPRAM area.
+ * Use cpm_dpram_addr() to get the virtual address of the area.
+ */
+uint cpm_dpalloc(uint size, uint align)
+{
+ 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);
+
+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 *)(dpram_vbase + offset);
+}
+EXPORT_SYMBOL(cpm_dpram_addr);
+
+uint cpm_dpram_phys(u8* addr)
+{
+ return (dpram_pbase + (uint)(addr - dpram_vbase));
+}
+EXPORT_SYMBOL(cpm_dpram_addr);
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
index 767ee6651ad..eabfe06fe05 100644
--- a/arch/powerpc/sysdev/cpm2_pic.c
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -36,9 +36,20 @@
#include <asm/mpc8260.h>
#include <asm/io.h>
#include <asm/prom.h>
+#include <asm/fs_pd.h>
#include "cpm2_pic.h"
+/* External IRQS */
+#define CPM2_IRQ_EXT1 19
+#define CPM2_IRQ_EXT7 25
+
+/* Port C IRQS */
+#define CPM2_IRQ_PORTC15 48
+#define CPM2_IRQ_PORTC0 63
+
+static intctl_cpm2_t *cpm2_intctl;
+
static struct device_node *cpm2_pic_node;
static struct irq_host *cpm2_pic_host;
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
@@ -68,68 +79,55 @@ static const u_char irq_to_siubit[] = {
24, 25, 26, 27, 28, 29, 30, 31,
};
-static void cpm2_mask_irq(unsigned int irq_nr)
+static void cpm2_mask_irq(unsigned int virq)
{
int bit, word;
- volatile uint *simr;
-
- irq_nr -= CPM_IRQ_OFFSET;
+ unsigned int irq_nr = virq_to_hw(virq);
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];
+ out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
}
-static void cpm2_unmask_irq(unsigned int irq_nr)
+static void cpm2_unmask_irq(unsigned int virq)
{
int bit, word;
- volatile uint *simr;
-
- irq_nr -= CPM_IRQ_OFFSET;
+ unsigned int irq_nr = virq_to_hw(virq);
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];
+ out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
}
-static void cpm2_mask_and_ack(unsigned int irq_nr)
+static void cpm2_ack(unsigned int virq)
{
int bit, word;
- volatile uint *simr, *sipnr;
-
- irq_nr -= CPM_IRQ_OFFSET;
+ unsigned int irq_nr = virq_to_hw(virq);
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;
+ out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit);
}
-static void cpm2_end_irq(unsigned int irq_nr)
+static void cpm2_end_irq(unsigned int virq)
{
int bit, word;
- volatile uint *simr;
+ unsigned int irq_nr = virq_to_hw(virq);
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];
+ out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
+
/*
* Work around large numbers of spurious IRQs on PowerPC 82xx
* systems.
@@ -138,13 +136,59 @@ static void cpm2_end_irq(unsigned int irq_nr)
}
}
+static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type)
+{
+ unsigned int src = virq_to_hw(virq);
+ struct irq_desc *desc = get_irq_desc(virq);
+ unsigned int vold, vnew, edibit;
+
+ if (flow_type == IRQ_TYPE_NONE)
+ flow_type = IRQ_TYPE_LEVEL_LOW;
+
+ if (flow_type & IRQ_TYPE_EDGE_RISING) {
+ printk(KERN_ERR "CPM2 PIC: sense type 0x%x not supported\n",
+ flow_type);
+ return -EINVAL;
+ }
+
+ desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+ desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
+ if (flow_type & IRQ_TYPE_LEVEL_LOW) {
+ desc->status |= IRQ_LEVEL;
+ desc->handle_irq = handle_level_irq;
+ } else
+ desc->handle_irq = handle_edge_irq;
+
+ /* internal IRQ senses are LEVEL_LOW
+ * EXT IRQ and Port C IRQ senses are programmable
+ */
+ if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7)
+ edibit = (14 - (src - CPM2_IRQ_EXT1));
+ else
+ if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0)
+ edibit = (31 - (src - CPM2_IRQ_PORTC15));
+ else
+ return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL;
+
+ vold = in_be32(&cpm2_intctl->ic_siexr);
+
+ if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING)
+ vnew = vold | (1 << edibit);
+ else
+ vnew = vold & ~(1 << edibit);
+
+ if (vold != vnew)
+ out_be32(&cpm2_intctl->ic_siexr, vnew);
+ return 0;
+}
+
static struct irq_chip cpm2_pic = {
.typename = " CPM2 SIU ",
- .enable = cpm2_unmask_irq,
- .disable = cpm2_mask_irq,
+ .mask = cpm2_mask_irq,
.unmask = cpm2_unmask_irq,
- .mask_ack = cpm2_mask_and_ack,
- .end = cpm2_end_irq,
+ .ack = cpm2_ack,
+ .eoi = cpm2_end_irq,
+ .set_type = cpm2_set_irq_type,
};
unsigned int cpm2_get_irq(void)
@@ -154,17 +198,17 @@ unsigned int cpm2_get_irq(void)
/* For CPM2, read the SIVEC register and shift the bits down
* to get the irq number. */
- bits = cpm2_intctl->ic_sivec;
+ bits = in_be32(&cpm2_intctl->ic_sivec);
irq = bits >> 26;
if (irq == 0)
return(-1);
- return irq+CPM_IRQ_OFFSET;
+ return irq_linear_revmap(cpm2_pic_host, irq);
}
static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node)
{
- return cpm2_pic_node == NULL || cpm2_pic_node == node;
+ return cpm2_pic_node == node;
}
static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
@@ -177,39 +221,21 @@ static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
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]];
+ if (intsize > 1)
+ *out_flags = 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,
};
@@ -217,37 +243,37 @@ void cpm2_pic_init(struct device_node *node)
{
int i;
+ cpm2_intctl = cpm2_map(im_intctl);
+
/* 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;
+ out_be32(&cpm2_intctl->ic_simrh, 0x00000000);
+ out_be32(&cpm2_intctl->ic_simrl, 0x00000000);
wmb();
/* Ack everything */
- cpm2_intctl->ic_sipnrh = 0xffffffff;
- cpm2_intctl->ic_sipnrl = 0xffffffff;
+ out_be32(&cpm2_intctl->ic_sipnrh, 0xffffffff);
+ out_be32(&cpm2_intctl->ic_sipnrl, 0xffffffff);
wmb();
/* Dummy read of the vector */
- i = cpm2_intctl->ic_sivec;
+ i = in_be32(&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;
+ out_be16(&cpm2_intctl->ic_sicr, 0);
+ out_be32(&cpm2_intctl->ic_scprrh, 0x05309770);
+ out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);
/* create a legacy host */
- if (node)
- cpm2_pic_node = of_node_get(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");
diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/cpm2_pic.h
index 2840616529e..30e5828a278 100644
--- a/arch/powerpc/sysdev/cpm2_pic.h
+++ b/arch/powerpc/sysdev/cpm2_pic.h
@@ -1,8 +1,6 @@
#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*);
diff --git a/arch/powerpc/sysdev/dcr.S b/arch/powerpc/sysdev/dcr.S
deleted file mode 100644
index 2078f39e2f1..00000000000
--- a/arch/powerpc/sysdev/dcr.S
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * "Indirect" DCR access
- *
- * Copyright (c) 2004 Eugene Surovegin <ebs@ebshome.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <asm/ppc_asm.h>
-#include <asm/processor.h>
-
-#define DCR_ACCESS_PROLOG(table) \
- rlwinm r3,r3,4,18,27; \
- lis r5,table@h; \
- ori r5,r5,table@l; \
- add r3,r3,r5; \
- mtctr r3; \
- bctr
-
-_GLOBAL(__mfdcr)
- DCR_ACCESS_PROLOG(__mfdcr_table)
-
-_GLOBAL(__mtdcr)
- DCR_ACCESS_PROLOG(__mtdcr_table)
-
-__mfdcr_table:
- mfdcr r3,0; blr
-__mtdcr_table:
- mtdcr 0,r4; blr
-
-dcr = 1
- .rept 1023
- mfdcr r3,dcr; blr
- mtdcr dcr,r4; blr
- dcr = dcr + 1
- .endr
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index ad31e56e892..9f2a9a444bf 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -38,7 +38,8 @@
#include <asm/cpm2.h>
extern void init_fcc_ioports(struct fs_platform_info*);
-extern void init_scc_ioports(struct fs_uart_platform_info*);
+extern void init_fec_ioports(struct fs_platform_info*);
+extern void init_smc_ioports(struct fs_uart_platform_info*);
static phys_addr_t immrbase = -1;
phys_addr_t get_immrbase(void)
@@ -63,7 +64,7 @@ phys_addr_t get_immrbase(void)
EXPORT_SYMBOL(get_immrbase);
-#ifdef CONFIG_CPM2
+#if defined(CONFIG_CPM2) || defined(CONFIG_8xx)
static u32 brgfreq = -1;
@@ -544,6 +545,8 @@ arch_initcall(fsl_usb_of_init);
#ifdef CONFIG_CPM2
+extern void init_scc_ioports(struct fs_uart_platform_info*);
+
static const char fcc_regs[] = "fcc_regs";
static const char fcc_regs_c[] = "fcc_regs_c";
static const char fcc_pram[] = "fcc_pram";
@@ -792,3 +795,270 @@ err:
arch_initcall(cpm_uart_of_init);
#endif /* CONFIG_CPM2 */
+
+#ifdef CONFIG_8xx
+
+extern void init_scc_ioports(struct fs_platform_info*);
+extern int platform_device_skip(char *model, int id);
+
+static int __init fs_enet_mdio_of_init(void)
+{
+ struct device_node *np;
+ unsigned int i;
+ struct platform_device *mdio_dev;
+ struct resource res;
+ int ret;
+
+ for (np = NULL, i = 0;
+ (np = of_find_compatible_node(np, "mdio", "fs_enet")) != NULL;
+ i++) {
+ struct fs_mii_fec_platform_info mdio_data;
+
+ memset(&res, 0, sizeof(res));
+ memset(&mdio_data, 0, sizeof(mdio_data));
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ goto err;
+
+ mdio_dev =
+ platform_device_register_simple("fsl-cpm-fec-mdio",
+ res.start, &res, 1);
+ if (IS_ERR(mdio_dev)) {
+ ret = PTR_ERR(mdio_dev);
+ goto err;
+ }
+
+ mdio_data.mii_speed = ((((ppc_proc_freq + 4999999) / 2500000) / 2) & 0x3F) << 1;
+
+ ret =
+ platform_device_add_data(mdio_dev, &mdio_data,
+ sizeof(struct fs_mii_fec_platform_info));
+ if (ret)
+ goto unreg;
+ }
+ return 0;
+
+unreg:
+ platform_device_unregister(mdio_dev);
+err:
+ return ret;
+}
+
+arch_initcall(fs_enet_mdio_of_init);
+
+static const char *enet_regs = "regs";
+static const char *enet_pram = "pram";
+static const char *enet_irq = "interrupt";
+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 = NULL;
+ 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 = NULL, *mdio = NULL;
+ struct fs_platform_info fs_enet_data;
+ unsigned int *id, *phy_addr;
+ void *mac_addr;
+ phandle *ph;
+ char *model;
+
+ memset(r, 0, sizeof(r));
+ memset(&fs_enet_data, 0, sizeof(fs_enet_data));
+
+ model = (char *)get_property(np, "model", NULL);
+ if (model == NULL) {
+ ret = -ENODEV;
+ goto unreg;
+ }
+
+ id = (u32 *) get_property(np, "device-id", NULL);
+ fs_enet_data.fs_no = *id;
+
+ if (platform_device_skip(model, *id))
+ continue;
+
+ ret = of_address_to_resource(np, 0, &r[0]);
+ if (ret)
+ goto err;
+ r[0].name = enet_regs;
+
+ mac_addr = (void *)get_property(np, "mac-address", NULL);
+ memcpy(fs_enet_data.macaddr, mac_addr, 6);
+
+ ph = (phandle *) get_property(np, "phy-handle", NULL);
+ if (ph != NULL)
+ phy = of_find_node_by_phandle(*ph);
+
+ if (phy != NULL) {
+ phy_addr = (u32 *) get_property(phy, "reg", NULL);
+ fs_enet_data.phy_addr = *phy_addr;
+ fs_enet_data.has_phy = 1;
+
+ 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;
+ }
+ }
+
+ model = (char*)get_property(np, "model", NULL);
+ strcpy(fs_enet_data.fs_type, model);
+
+ if (strstr(model, "FEC")) {
+ r[1].start = r[1].end = irq_of_parse_and_map(np, 0);
+ r[1].flags = IORESOURCE_IRQ;
+ r[1].name = enet_irq;
+
+ fs_enet_dev =
+ platform_device_register_simple("fsl-cpm-fec", i, &r[0], 2);
+
+ if (IS_ERR(fs_enet_dev)) {
+ ret = PTR_ERR(fs_enet_dev);
+ goto err;
+ }
+
+ fs_enet_data.rx_ring = 128;
+ fs_enet_data.tx_ring = 16;
+ fs_enet_data.rx_copybreak = 240;
+ fs_enet_data.use_napi = 1;
+ fs_enet_data.napi_weight = 17;
+
+ snprintf((char*)&bus_id[i], BUS_ID_SIZE, "%x:%02x",
+ (u32)res.start, fs_enet_data.phy_addr);
+ fs_enet_data.bus_id = (char*)&bus_id[i];
+ fs_enet_data.init_ioports = init_fec_ioports;
+ }
+ if (strstr(model, "SCC")) {
+ ret = of_address_to_resource(np, 1, &r[1]);
+ if (ret)
+ goto err;
+ r[1].name = enet_pram;
+
+ r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
+ r[2].flags = IORESOURCE_IRQ;
+ r[2].name = enet_irq;
+
+ fs_enet_dev =
+ platform_device_register_simple("fsl-cpm-scc", i, &r[0], 3);
+
+ if (IS_ERR(fs_enet_dev)) {
+ ret = PTR_ERR(fs_enet_dev);
+ goto err;
+ }
+
+ fs_enet_data.rx_ring = 64;
+ fs_enet_data.tx_ring = 8;
+ fs_enet_data.rx_copybreak = 240;
+ fs_enet_data.use_napi = 1;
+ fs_enet_data.napi_weight = 17;
+
+ snprintf((char*)&bus_id[i], BUS_ID_SIZE, "%s", "fixed@10:1");
+ fs_enet_data.bus_id = (char*)&bus_id[i];
+ fs_enet_data.init_ioports = init_scc_ioports;
+ }
+
+ 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 *smc_regs = "regs";
+static const char *smc_pram = "pram";
+
+static int __init cpm_smc_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;
+ int *id;
+ 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 = smc_regs;
+
+ ret = of_address_to_resource(np, 1, &r[1]);
+ if (ret)
+ goto err;
+ r[1].name = smc_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-smc:uart", i, &r[0], 3);
+
+ if (IS_ERR(cpm_uart_dev)) {
+ ret = PTR_ERR(cpm_uart_dev);
+ goto err;
+ }
+
+ model = (char*)get_property(np, "model", NULL);
+ strcpy(cpm_uart_data.fs_type, model);
+
+ id = (int*)get_property(np, "device-id", NULL);
+ cpm_uart_data.fs_no = *id;
+ 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;
+
+ 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_smc_uart_of_init);
+
+#endif /* CONFIG_8xx */
diff --git a/arch/powerpc/sysdev/grackle.c b/arch/powerpc/sysdev/grackle.c
index b6ec793a23b..42053625f49 100644
--- a/arch/powerpc/sysdev/grackle.c
+++ b/arch/powerpc/sysdev/grackle.c
@@ -56,6 +56,8 @@ static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable)
void __init setup_grackle(struct pci_controller *hose)
{
setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
+ if (machine_is_compatible("PowerMac1,1"))
+ pci_assign_all_buses = 1;
if (machine_is_compatible("AAPL,PowerBook1998"))
grackle_set_loop_snoop(hose, 1);
#if 0 /* Disabled for now, HW problems ??? */
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index 746f78c1537..473c415e9e2 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -557,8 +557,7 @@ static struct irq_host_ops ipic_host_ops = {
.xlate = ipic_host_xlate,
};
-void __init ipic_init(struct device_node *node,
- unsigned int flags)
+struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
{
struct ipic *ipic;
struct resource res;
@@ -566,22 +565,24 @@ void __init ipic_init(struct device_node *node,
ipic = alloc_bootmem(sizeof(struct ipic));
if (ipic == NULL)
- return;
+ return NULL;
memset(ipic, 0, sizeof(struct ipic));
- ipic->of_node = node ? of_node_get(node) : NULL;
+ ipic->of_node = of_node_get(node);
ipic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
NR_IPIC_INTS,
&ipic_host_ops, 0);
if (ipic->irqhost == NULL) {
of_node_put(node);
- return;
+ return NULL;
}
ret = of_address_to_resource(node, 0, &res);
- if (ret)
- return;
+ if (ret) {
+ of_node_put(node);
+ return NULL;
+ }
ipic->regs = ioremap(res.start, res.end - res.start + 1);
@@ -625,6 +626,8 @@ void __init ipic_init(struct device_node *node,
printk ("IPIC (%d IRQ sources) at %p\n", NR_IPIC_INTS,
primary_ipic->regs);
+
+ return ipic;
}
int ipic_set_priority(unsigned int virq, unsigned int priority)
diff --git a/arch/powerpc/sysdev/micropatch.c b/arch/powerpc/sysdev/micropatch.c
new file mode 100644
index 00000000000..712b10a55f8
--- /dev/null
+++ b/arch/powerpc/sysdev/micropatch.c
@@ -0,0 +1,743 @@
+
+/* Microcode patches for the CPM as supplied by Motorola.
+ * This is the one for IIC/SPI. There is a newer one that
+ * also relocates SMC2, but this would require additional changes
+ * to uart.c, so I am holding off on that for a moment.
+ */
+#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 <asm/irq.h>
+#include <asm/mpc8xx.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+
+/*
+ * I2C/SPI relocation patch arrays.
+ */
+
+#ifdef CONFIG_I2C_SPI_UCODE_PATCH
+
+uint patch_2000[] = {
+ 0x7FFFEFD9,
+ 0x3FFD0000,
+ 0x7FFB49F7,
+ 0x7FF90000,
+ 0x5FEFADF7,
+ 0x5F89ADF7,
+ 0x5FEFAFF7,
+ 0x5F89AFF7,
+ 0x3A9CFBC8,
+ 0xE7C0EDF0,
+ 0x77C1E1BB,
+ 0xF4DC7F1D,
+ 0xABAD932F,
+ 0x4E08FDCF,
+ 0x6E0FAFF8,
+ 0x7CCF76CF,
+ 0xFD1FF9CF,
+ 0xABF88DC6,
+ 0xAB5679F7,
+ 0xB0937383,
+ 0xDFCE79F7,
+ 0xB091E6BB,
+ 0xE5BBE74F,
+ 0xB3FA6F0F,
+ 0x6FFB76CE,
+ 0xEE0DF9CF,
+ 0x2BFBEFEF,
+ 0xCFEEF9CF,
+ 0x76CEAD24,
+ 0x90B2DF9A,
+ 0x7FDDD0BF,
+ 0x4BF847FD,
+ 0x7CCF76CE,
+ 0xCFEF7E1F,
+ 0x7F1D7DFD,
+ 0xF0B6EF71,
+ 0x7FC177C1,
+ 0xFBC86079,
+ 0xE722FBC8,
+ 0x5FFFDFFF,
+ 0x5FB2FFFB,
+ 0xFBC8F3C8,
+ 0x94A67F01,
+ 0x7F1D5F39,
+ 0xAFE85F5E,
+ 0xFFDFDF96,
+ 0xCB9FAF7D,
+ 0x5FC1AFED,
+ 0x8C1C5FC1,
+ 0xAFDD5FC3,
+ 0xDF9A7EFD,
+ 0xB0B25FB2,
+ 0xFFFEABAD,
+ 0x5FB2FFFE,
+ 0x5FCE600B,
+ 0xE6BB600B,
+ 0x5FCEDFC6,
+ 0x27FBEFDF,
+ 0x5FC8CFDE,
+ 0x3A9CE7C0,
+ 0xEDF0F3C8,
+ 0x7F0154CD,
+ 0x7F1D2D3D,
+ 0x363A7570,
+ 0x7E0AF1CE,
+ 0x37EF2E68,
+ 0x7FEE10EC,
+ 0xADF8EFDE,
+ 0xCFEAE52F,
+ 0x7D0FE12B,
+ 0xF1CE5F65,
+ 0x7E0A4DF8,
+ 0xCFEA5F72,
+ 0x7D0BEFEE,
+ 0xCFEA5F74,
+ 0xE522EFDE,
+ 0x5F74CFDA,
+ 0x0B627385,
+ 0xDF627E0A,
+ 0x30D8145B,
+ 0xBFFFF3C8,
+ 0x5FFFDFFF,
+ 0xA7F85F5E,
+ 0xBFFE7F7D,
+ 0x10D31450,
+ 0x5F36BFFF,
+ 0xAF785F5E,
+ 0xBFFDA7F8,
+ 0x5F36BFFE,
+ 0x77FD30C0,
+ 0x4E08FDCF,
+ 0xE5FF6E0F,
+ 0xAFF87E1F,
+ 0x7E0FFD1F,
+ 0xF1CF5F1B,
+ 0xABF80D5E,
+ 0x5F5EFFEF,
+ 0x79F730A2,
+ 0xAFDD5F34,
+ 0x47F85F34,
+ 0xAFED7FDD,
+ 0x50B24978,
+ 0x47FD7F1D,
+ 0x7DFD70AD,
+ 0xEF717EC1,
+ 0x6BA47F01,
+ 0x2D267EFD,
+ 0x30DE5F5E,
+ 0xFFFD5F5E,
+ 0xFFEF5F5E,
+ 0xFFDF0CA0,
+ 0xAFED0A9E,
+ 0xAFDD0C3A,
+ 0x5F3AAFBD,
+ 0x7FBDB082,
+ 0x5F8247F8
+};
+
+uint patch_2f00[] = {
+ 0x3E303430,
+ 0x34343737,
+ 0xABF7BF9B,
+ 0x994B4FBD,
+ 0xBD599493,
+ 0x349FFF37,
+ 0xFB9B177D,
+ 0xD9936956,
+ 0xBBFDD697,
+ 0xBDD2FD11,
+ 0x31DB9BB3,
+ 0x63139637,
+ 0x93733693,
+ 0x193137F7,
+ 0x331737AF,
+ 0x7BB9B999,
+ 0xBB197957,
+ 0x7FDFD3D5,
+ 0x73B773F7,
+ 0x37933B99,
+ 0x1D115316,
+ 0x99315315,
+ 0x31694BF4,
+ 0xFBDBD359,
+ 0x31497353,
+ 0x76956D69,
+ 0x7B9D9693,
+ 0x13131979,
+ 0x79376935
+};
+#endif
+
+/*
+ * I2C/SPI/SMC1 relocation patch arrays.
+ */
+
+#ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
+
+uint patch_2000[] = {
+ 0x3fff0000,
+ 0x3ffd0000,
+ 0x3ffb0000,
+ 0x3ff90000,
+ 0x5f13eff8,
+ 0x5eb5eff8,
+ 0x5f88adf7,
+ 0x5fefadf7,
+ 0x3a9cfbc8,
+ 0x77cae1bb,
+ 0xf4de7fad,
+ 0xabae9330,
+ 0x4e08fdcf,
+ 0x6e0faff8,
+ 0x7ccf76cf,
+ 0xfdaff9cf,
+ 0xabf88dc8,
+ 0xab5879f7,
+ 0xb0925d8d,
+ 0xdfd079f7,
+ 0xb090e6bb,
+ 0xe5bbe74f,
+ 0x9e046f0f,
+ 0x6ffb76ce,
+ 0xee0cf9cf,
+ 0x2bfbefef,
+ 0xcfeef9cf,
+ 0x76cead23,
+ 0x90b3df99,
+ 0x7fddd0c1,
+ 0x4bf847fd,
+ 0x7ccf76ce,
+ 0xcfef77ca,
+ 0x7eaf7fad,
+ 0x7dfdf0b7,
+ 0xef7a7fca,
+ 0x77cafbc8,
+ 0x6079e722,
+ 0xfbc85fff,
+ 0xdfff5fb3,
+ 0xfffbfbc8,
+ 0xf3c894a5,
+ 0xe7c9edf9,
+ 0x7f9a7fad,
+ 0x5f36afe8,
+ 0x5f5bffdf,
+ 0xdf95cb9e,
+ 0xaf7d5fc3,
+ 0xafed8c1b,
+ 0x5fc3afdd,
+ 0x5fc5df99,
+ 0x7efdb0b3,
+ 0x5fb3fffe,
+ 0xabae5fb3,
+ 0xfffe5fd0,
+ 0x600be6bb,
+ 0x600b5fd0,
+ 0xdfc827fb,
+ 0xefdf5fca,
+ 0xcfde3a9c,
+ 0xe7c9edf9,
+ 0xf3c87f9e,
+ 0x54ca7fed,
+ 0x2d3a3637,
+ 0x756f7e9a,
+ 0xf1ce37ef,
+ 0x2e677fee,
+ 0x10ebadf8,
+ 0xefdecfea,
+ 0xe52f7d9f,
+ 0xe12bf1ce,
+ 0x5f647e9a,
+ 0x4df8cfea,
+ 0x5f717d9b,
+ 0xefeecfea,
+ 0x5f73e522,
+ 0xefde5f73,
+ 0xcfda0b61,
+ 0x5d8fdf61,
+ 0xe7c9edf9,
+ 0x7e9a30d5,
+ 0x1458bfff,
+ 0xf3c85fff,
+ 0xdfffa7f8,
+ 0x5f5bbffe,
+ 0x7f7d10d0,
+ 0x144d5f33,
+ 0xbfffaf78,
+ 0x5f5bbffd,
+ 0xa7f85f33,
+ 0xbffe77fd,
+ 0x30bd4e08,
+ 0xfdcfe5ff,
+ 0x6e0faff8,
+ 0x7eef7e9f,
+ 0xfdeff1cf,
+ 0x5f17abf8,
+ 0x0d5b5f5b,
+ 0xffef79f7,
+ 0x309eafdd,
+ 0x5f3147f8,
+ 0x5f31afed,
+ 0x7fdd50af,
+ 0x497847fd,
+ 0x7f9e7fed,
+ 0x7dfd70a9,
+ 0xef7e7ece,
+ 0x6ba07f9e,
+ 0x2d227efd,
+ 0x30db5f5b,
+ 0xfffd5f5b,
+ 0xffef5f5b,
+ 0xffdf0c9c,
+ 0xafed0a9a,
+ 0xafdd0c37,
+ 0x5f37afbd,
+ 0x7fbdb081,
+ 0x5f8147f8,
+ 0x3a11e710,
+ 0xedf0ccdd,
+ 0xf3186d0a,
+ 0x7f0e5f06,
+ 0x7fedbb38,
+ 0x3afe7468,
+ 0x7fedf4fc,
+ 0x8ffbb951,
+ 0xb85f77fd,
+ 0xb0df5ddd,
+ 0xdefe7fed,
+ 0x90e1e74d,
+ 0x6f0dcbf7,
+ 0xe7decfed,
+ 0xcb74cfed,
+ 0xcfeddf6d,
+ 0x91714f74,
+ 0x5dd2deef,
+ 0x9e04e7df,
+ 0xefbb6ffb,
+ 0xe7ef7f0e,
+ 0x9e097fed,
+ 0xebdbeffa,
+ 0xeb54affb,
+ 0x7fea90d7,
+ 0x7e0cf0c3,
+ 0xbffff318,
+ 0x5fffdfff,
+ 0xac59efea,
+ 0x7fce1ee5,
+ 0xe2ff5ee1,
+ 0xaffbe2ff,
+ 0x5ee3affb,
+ 0xf9cc7d0f,
+ 0xaef8770f,
+ 0x7d0fb0c6,
+ 0xeffbbfff,
+ 0xcfef5ede,
+ 0x7d0fbfff,
+ 0x5ede4cf8,
+ 0x7fddd0bf,
+ 0x49f847fd,
+ 0x7efdf0bb,
+ 0x7fedfffd,
+ 0x7dfdf0b7,
+ 0xef7e7e1e,
+ 0x5ede7f0e,
+ 0x3a11e710,
+ 0xedf0ccab,
+ 0xfb18ad2e,
+ 0x1ea9bbb8,
+ 0x74283b7e,
+ 0x73c2e4bb,
+ 0x2ada4fb8,
+ 0xdc21e4bb,
+ 0xb2a1ffbf,
+ 0x5e2c43f8,
+ 0xfc87e1bb,
+ 0xe74ffd91,
+ 0x6f0f4fe8,
+ 0xc7ba32e2,
+ 0xf396efeb,
+ 0x600b4f78,
+ 0xe5bb760b,
+ 0x53acaef8,
+ 0x4ef88b0e,
+ 0xcfef9e09,
+ 0xabf8751f,
+ 0xefef5bac,
+ 0x741f4fe8,
+ 0x751e760d,
+ 0x7fdbf081,
+ 0x741cafce,
+ 0xefcc7fce,
+ 0x751e70ac,
+ 0x741ce7bb,
+ 0x3372cfed,
+ 0xafdbefeb,
+ 0xe5bb760b,
+ 0x53f2aef8,
+ 0xafe8e7eb,
+ 0x4bf8771e,
+ 0x7e247fed,
+ 0x4fcbe2cc,
+ 0x7fbc30a9,
+ 0x7b0f7a0f,
+ 0x34d577fd,
+ 0x308b5db7,
+ 0xde553e5f,
+ 0xaf78741f,
+ 0x741f30f0,
+ 0xcfef5e2c,
+ 0x741f3eac,
+ 0xafb8771e,
+ 0x5e677fed,
+ 0x0bd3e2cc,
+ 0x741ccfec,
+ 0xe5ca53cd,
+ 0x6fcb4f74,
+ 0x5dadde4b,
+ 0x2ab63d38,
+ 0x4bb3de30,
+ 0x751f741c,
+ 0x6c42effa,
+ 0xefea7fce,
+ 0x6ffc30be,
+ 0xefec3fca,
+ 0x30b3de2e,
+ 0xadf85d9e,
+ 0xaf7daefd,
+ 0x5d9ede2e,
+ 0x5d9eafdd,
+ 0x761f10ac,
+ 0x1da07efd,
+ 0x30adfffe,
+ 0x4908fb18,
+ 0x5fffdfff,
+ 0xafbb709b,
+ 0x4ef85e67,
+ 0xadf814ad,
+ 0x7a0f70ad,
+ 0xcfef50ad,
+ 0x7a0fde30,
+ 0x5da0afed,
+ 0x3c12780f,
+ 0xefef780f,
+ 0xefef790f,
+ 0xa7f85e0f,
+ 0xffef790f,
+ 0xefef790f,
+ 0x14adde2e,
+ 0x5d9eadfd,
+ 0x5e2dfffb,
+ 0xe79addfd,
+ 0xeff96079,
+ 0x607ae79a,
+ 0xddfceff9,
+ 0x60795dff,
+ 0x607acfef,
+ 0xefefefdf,
+ 0xefbfef7f,
+ 0xeeffedff,
+ 0xebffe7ff,
+ 0xafefafdf,
+ 0xafbfaf7f,
+ 0xaeffadff,
+ 0xabffa7ff,
+ 0x6fef6fdf,
+ 0x6fbf6f7f,
+ 0x6eff6dff,
+ 0x6bff67ff,
+ 0x2fef2fdf,
+ 0x2fbf2f7f,
+ 0x2eff2dff,
+ 0x2bff27ff,
+ 0x4e08fd1f,
+ 0xe5ff6e0f,
+ 0xaff87eef,
+ 0x7e0ffdef,
+ 0xf11f6079,
+ 0xabf8f542,
+ 0x7e0af11c,
+ 0x37cfae3a,
+ 0x7fec90be,
+ 0xadf8efdc,
+ 0xcfeae52f,
+ 0x7d0fe12b,
+ 0xf11c6079,
+ 0x7e0a4df8,
+ 0xcfea5dc4,
+ 0x7d0befec,
+ 0xcfea5dc6,
+ 0xe522efdc,
+ 0x5dc6cfda,
+ 0x4e08fd1f,
+ 0x6e0faff8,
+ 0x7c1f761f,
+ 0xfdeff91f,
+ 0x6079abf8,
+ 0x761cee24,
+ 0xf91f2bfb,
+ 0xefefcfec,
+ 0xf91f6079,
+ 0x761c27fb,
+ 0xefdf5da7,
+ 0xcfdc7fdd,
+ 0xd09c4bf8,
+ 0x47fd7c1f,
+ 0x761ccfcf,
+ 0x7eef7fed,
+ 0x7dfdf093,
+ 0xef7e7f1e,
+ 0x771efb18,
+ 0x6079e722,
+ 0xe6bbe5bb,
+ 0xae0ae5bb,
+ 0x600bae85,
+ 0xe2bbe2bb,
+ 0xe2bbe2bb,
+ 0xaf02e2bb,
+ 0xe2bb2ff9,
+ 0x6079e2bb
+};
+
+uint patch_2f00[] = {
+ 0x30303030,
+ 0x3e3e3434,
+ 0xabbf9b99,
+ 0x4b4fbdbd,
+ 0x59949334,
+ 0x9fff37fb,
+ 0x9b177dd9,
+ 0x936956bb,
+ 0xfbdd697b,
+ 0xdd2fd113,
+ 0x1db9f7bb,
+ 0x36313963,
+ 0x79373369,
+ 0x3193137f,
+ 0x7331737a,
+ 0xf7bb9b99,
+ 0x9bb19795,
+ 0x77fdfd3d,
+ 0x573b773f,
+ 0x737933f7,
+ 0xb991d115,
+ 0x31699315,
+ 0x31531694,
+ 0xbf4fbdbd,
+ 0x35931497,
+ 0x35376956,
+ 0xbd697b9d,
+ 0x96931313,
+ 0x19797937,
+ 0x6935af78,
+ 0xb9b3baa3,
+ 0xb8788683,
+ 0x368f78f7,
+ 0x87778733,
+ 0x3ffffb3b,
+ 0x8e8f78b8,
+ 0x1d118e13,
+ 0xf3ff3f8b,
+ 0x6bd8e173,
+ 0xd1366856,
+ 0x68d1687b,
+ 0x3daf78b8,
+ 0x3a3a3f87,
+ 0x8f81378f,
+ 0xf876f887,
+ 0x77fd8778,
+ 0x737de8d6,
+ 0xbbf8bfff,
+ 0xd8df87f7,
+ 0xfd876f7b,
+ 0x8bfff8bd,
+ 0x8683387d,
+ 0xb873d87b,
+ 0x3b8fd7f8,
+ 0xf7338883,
+ 0xbb8ee1f8,
+ 0xef837377,
+ 0x3337b836,
+ 0x817d11f8,
+ 0x7378b878,
+ 0xd3368b7d,
+ 0xed731b7d,
+ 0x833731f3,
+ 0xf22f3f23
+};
+
+uint patch_2e00[] = {
+ 0x27eeeeee,
+ 0xeeeeeeee,
+ 0xeeeeeeee,
+ 0xeeeeeeee,
+ 0xee4bf4fb,
+ 0xdbd259bb,
+ 0x1979577f,
+ 0xdfd2d573,
+ 0xb773f737,
+ 0x4b4fbdbd,
+ 0x25b9b177,
+ 0xd2d17376,
+ 0x956bbfdd,
+ 0x697bdd2f,
+ 0xff9f79ff,
+ 0xff9ff22f
+};
+#endif
+
+/*
+ * USB SOF patch arrays.
+ */
+
+#ifdef CONFIG_USB_SOF_UCODE_PATCH
+
+uint patch_2000[] = {
+ 0x7fff0000,
+ 0x7ffd0000,
+ 0x7ffb0000,
+ 0x49f7ba5b,
+ 0xba383ffb,
+ 0xf9b8b46d,
+ 0xe5ab4e07,
+ 0xaf77bffe,
+ 0x3f7bbf79,
+ 0xba5bba38,
+ 0xe7676076,
+ 0x60750000
+};
+
+uint patch_2f00[] = {
+ 0x3030304c,
+ 0xcab9e441,
+ 0xa1aaf220
+};
+#endif
+
+void
+cpm_load_patch(cpm8xx_t *cp)
+{
+ volatile uint *dp; /* Dual-ported RAM. */
+ volatile cpm8xx_t *commproc;
+ volatile iic_t *iip;
+ volatile spi_t *spp;
+ volatile smc_uart_t *smp;
+ int i;
+
+ commproc = cp;
+
+#ifdef CONFIG_USB_SOF_UCODE_PATCH
+ commproc->cp_rccr = 0;
+
+ dp = (uint *)(commproc->cp_dpmem);
+ for (i=0; i<(sizeof(patch_2000)/4); i++)
+ *dp++ = patch_2000[i];
+
+ dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
+ for (i=0; i<(sizeof(patch_2f00)/4); i++)
+ *dp++ = patch_2f00[i];
+
+ commproc->cp_rccr = 0x0009;
+
+ printk("USB SOF microcode patch installed\n");
+#endif /* CONFIG_USB_SOF_UCODE_PATCH */
+
+#if defined(CONFIG_I2C_SPI_UCODE_PATCH) || \
+ defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
+
+ commproc->cp_rccr = 0;
+
+ dp = (uint *)(commproc->cp_dpmem);
+ for (i=0; i<(sizeof(patch_2000)/4); i++)
+ *dp++ = patch_2000[i];
+
+ dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
+ for (i=0; i<(sizeof(patch_2f00)/4); i++)
+ *dp++ = patch_2f00[i];
+
+ iip = (iic_t *)&commproc->cp_dparam[PROFF_IIC];
+# define RPBASE 0x0500
+ iip->iic_rpbase = RPBASE;
+
+ /* Put SPI above the IIC, also 32-byte aligned.
+ */
+ i = (RPBASE + sizeof(iic_t) + 31) & ~31;
+ spp = (spi_t *)&commproc->cp_dparam[PROFF_SPI];
+ spp->spi_rpbase = i;
+
+# if defined(CONFIG_I2C_SPI_UCODE_PATCH)
+ commproc->cp_cpmcr1 = 0x802a;
+ commproc->cp_cpmcr2 = 0x8028;
+ commproc->cp_cpmcr3 = 0x802e;
+ commproc->cp_cpmcr4 = 0x802c;
+ commproc->cp_rccr = 1;
+
+ printk("I2C/SPI microcode patch installed.\n");
+# endif /* CONFIG_I2C_SPI_UCODE_PATCH */
+
+# if defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
+
+ dp = (uint *)&(commproc->cp_dpmem[0x0e00]);
+ for (i=0; i<(sizeof(patch_2e00)/4); i++)
+ *dp++ = patch_2e00[i];
+
+ commproc->cp_cpmcr1 = 0x8080;
+ commproc->cp_cpmcr2 = 0x808a;
+ commproc->cp_cpmcr3 = 0x8028;
+ commproc->cp_cpmcr4 = 0x802a;
+ commproc->cp_rccr = 3;
+
+ smp = (smc_uart_t *)&commproc->cp_dparam[PROFF_SMC1];
+ smp->smc_rpbase = 0x1FC0;
+
+ printk("I2C/SPI/SMC1 microcode patch installed.\n");
+# endif /* CONFIG_I2C_SPI_SMC1_UCODE_PATCH) */
+
+#endif /* some variation of the I2C/SPI patch was selected */
+}
+
+/*
+ * Take this entire routine out, since no one calls it and its
+ * logic is suspect.
+ */
+
+#if 0
+void
+verify_patch(volatile immap_t *immr)
+{
+ volatile uint *dp;
+ volatile cpm8xx_t *commproc;
+ int i;
+
+ commproc = (cpm8xx_t *)&immr->im_cpm;
+
+ printk("cp_rccr %x\n", commproc->cp_rccr);
+ commproc->cp_rccr = 0;
+
+ dp = (uint *)(commproc->cp_dpmem);
+ for (i=0; i<(sizeof(patch_2000)/4); i++)
+ if (*dp++ != patch_2000[i]) {
+ printk("patch_2000 bad at %d\n", i);
+ dp--;
+ printk("found 0x%X, wanted 0x%X\n", *dp, patch_2000[i]);
+ break;
+ }
+
+ dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
+ for (i=0; i<(sizeof(patch_2f00)/4); i++)
+ if (*dp++ != patch_2f00[i]) {
+ printk("patch_2f00 bad at %d\n", i);
+ dp--;
+ printk("found 0x%X, wanted 0x%X\n", *dp, patch_2f00[i]);
+ break;
+ }
+
+ commproc->cp_rccr = 0x0009;
+}
+#endif
diff --git a/arch/powerpc/sysdev/mmio_nvram.c b/arch/powerpc/sysdev/mmio_nvram.c
index ff23f5a4d4b..e073e246293 100644
--- a/arch/powerpc/sysdev/mmio_nvram.c
+++ b/arch/powerpc/sysdev/mmio_nvram.c
@@ -80,33 +80,39 @@ static ssize_t mmio_nvram_get_size(void)
int __init mmio_nvram_init(void)
{
struct device_node *nvram_node;
- const unsigned long *buffer;
- int proplen;
unsigned long nvram_addr;
+ struct resource r;
int ret;
- ret = -ENODEV;
nvram_node = of_find_node_by_type(NULL, "nvram");
- if (!nvram_node)
+ if (!nvram_node) {
+ printk(KERN_WARNING "nvram: no node found in device-tree\n");
+ return -ENODEV;
+ }
+
+ ret = of_address_to_resource(nvram_node, 0, &r);
+ if (ret) {
+ printk(KERN_WARNING "nvram: failed to get address (err %d)\n",
+ ret);
goto out;
-
- ret = -EIO;
- buffer = get_property(nvram_node, "reg", &proplen);
- if (proplen != 2*sizeof(unsigned long))
- goto out;
-
- ret = -ENODEV;
- nvram_addr = buffer[0];
- mmio_nvram_len = buffer[1];
- if ( (!mmio_nvram_len) || (!nvram_addr) )
+ }
+ nvram_addr = r.start;
+ mmio_nvram_len = r.end - r.start + 1;
+ if ( (!mmio_nvram_len) || (!nvram_addr) ) {
+ printk(KERN_WARNING "nvram: address or lenght is 0\n");
+ ret = -EIO;
goto out;
+ }
mmio_nvram_start = ioremap(nvram_addr, mmio_nvram_len);
- if (!mmio_nvram_start)
+ if (!mmio_nvram_start) {
+ printk(KERN_WARNING "nvram: failed to ioremap\n");
+ ret = -ENOMEM;
goto out;
+ }
- printk(KERN_INFO "mmio NVRAM, %luk mapped to %p\n",
- mmio_nvram_len >> 10, mmio_nvram_start);
+ printk(KERN_INFO "mmio NVRAM, %luk at 0x%lx mapped to %p\n",
+ mmio_nvram_len >> 10, nvram_addr, mmio_nvram_start);
ppc_md.nvram_read = mmio_nvram_read;
ppc_md.nvram_write = mmio_nvram_write;
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
new file mode 100644
index 00000000000..2fc2bcd79b5
--- /dev/null
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -0,0 +1,197 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <asm/prom.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/8xx_immap.h>
+#include <asm/mpc8xx.h>
+
+#include "mpc8xx_pic.h"
+
+
+#define PIC_VEC_SPURRIOUS 15
+
+extern int cpm_get_irq(struct pt_regs *regs);
+
+static struct device_node *mpc8xx_pic_node;
+static struct irq_host *mpc8xx_pic_host;
+#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
+static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
+static sysconf8xx_t *siu_reg;
+
+int cpm_get_irq(struct pt_regs *regs);
+
+static void mpc8xx_unmask_irq(unsigned int virq)
+{
+ int bit, word;
+ unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+
+ bit = irq_nr & 0x1f;
+ word = irq_nr >> 5;
+
+ ppc_cached_irq_mask[word] |= (1 << (31-bit));
+ out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
+}
+
+static void mpc8xx_mask_irq(unsigned int virq)
+{
+ int bit, word;
+ unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+
+ bit = irq_nr & 0x1f;
+ word = irq_nr >> 5;
+
+ ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
+ out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
+}
+
+static void mpc8xx_ack(unsigned int virq)
+{
+ int bit;
+ unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+
+ bit = irq_nr & 0x1f;
+ out_be32(&siu_reg->sc_sipend, 1 << (31-bit));
+}
+
+static void mpc8xx_end_irq(unsigned int virq)
+{
+ int bit, word;
+ unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+
+ bit = irq_nr & 0x1f;
+ word = irq_nr >> 5;
+
+ ppc_cached_irq_mask[word] |= (1 << (31-bit));
+ out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
+}
+
+static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type)
+{
+ struct irq_desc *desc = get_irq_desc(virq);
+
+ desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+ desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
+ if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+ desc->status |= IRQ_LEVEL;
+
+ if (flow_type & IRQ_TYPE_EDGE_FALLING) {
+ irq_hw_number_t hw = (unsigned int)irq_map[virq].hwirq;
+ unsigned int siel = in_be32(&siu_reg->sc_siel);
+
+ /* only external IRQ senses are programmable */
+ if ((hw & 1) == 0) {
+ siel |= (0x80000000 >> hw);
+ out_be32(&siu_reg->sc_siel, siel);
+ desc->handle_irq = handle_edge_irq;
+ }
+ }
+ return 0;
+}
+
+static struct irq_chip mpc8xx_pic = {
+ .typename = " MPC8XX SIU ",
+ .unmask = mpc8xx_unmask_irq,
+ .mask = mpc8xx_mask_irq,
+ .ack = mpc8xx_ack,
+ .eoi = mpc8xx_end_irq,
+ .set_type = mpc8xx_set_irq_type,
+};
+
+unsigned int mpc8xx_get_irq(void)
+{
+ int irq;
+
+ /* For MPC8xx, read the SIVEC register and shift the bits down
+ * to get the irq number.
+ */
+ irq = in_be32(&siu_reg->sc_sivec) >> 26;
+
+ if (irq == PIC_VEC_SPURRIOUS)
+ irq = NO_IRQ;
+
+ return irq_linear_revmap(mpc8xx_pic_host, irq);
+
+}
+
+static int mpc8xx_pic_host_match(struct irq_host *h, struct device_node *node)
+{
+ return mpc8xx_pic_node == node;
+}
+
+static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw);
+
+ /* Set default irq handle */
+ set_irq_chip_and_handler(virq, &mpc8xx_pic, handle_level_irq);
+ return 0;
+}
+
+
+static int mpc8xx_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 unsigned char map_pic_senses[4] = {
+ IRQ_TYPE_EDGE_RISING,
+ IRQ_TYPE_LEVEL_LOW,
+ IRQ_TYPE_LEVEL_HIGH,
+ IRQ_TYPE_EDGE_FALLING,
+ };
+
+ *out_hwirq = intspec[0];
+ if (intsize > 1 && intspec[1] < 4)
+ *out_flags = map_pic_senses[intspec[1]];
+ else
+ *out_flags = IRQ_TYPE_NONE;
+
+ return 0;
+}
+
+
+static struct irq_host_ops mpc8xx_pic_host_ops = {
+ .match = mpc8xx_pic_host_match,
+ .map = mpc8xx_pic_host_map,
+ .xlate = mpc8xx_pic_host_xlate,
+};
+
+int mpc8xx_pic_init(void)
+{
+ struct resource res;
+ struct device_node *np = NULL;
+ int ret;
+
+ np = of_find_node_by_type(np, "mpc8xx-pic");
+
+ if (np == NULL) {
+ printk(KERN_ERR "Could not find open-pic node\n");
+ return -ENOMEM;
+ }
+
+ mpc8xx_pic_node = of_node_get(np);
+
+ ret = of_address_to_resource(np, 0, &res);
+ of_node_put(np);
+ if (ret)
+ return ret;
+
+ siu_reg = (void *)ioremap(res.start, res.end - res.start + 1);
+ if (siu_reg == NULL)
+ return -EINVAL;
+
+ mpc8xx_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &mpc8xx_pic_host_ops, 64);
+ if (mpc8xx_pic_host == NULL) {
+ printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.h b/arch/powerpc/sysdev/mpc8xx_pic.h
new file mode 100644
index 00000000000..afa2ee6717c
--- /dev/null
+++ b/arch/powerpc/sysdev/mpc8xx_pic.h
@@ -0,0 +1,12 @@
+#ifndef _PPC_KERNEL_MPC8xx_H
+#define _PPC_KERNEL_MPC8xx_H
+
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+extern struct hw_interrupt_type mpc8xx_pic;
+
+int mpc8xx_pic_init(void);
+unsigned int mpc8xx_get_irq(void);
+
+#endif /* _PPC_KERNEL_PPC8xx_H */
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 411480d5c62..aa701cc27ec 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -390,7 +390,7 @@ static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
if (id == PCI_CAP_ID_HT) {
id = readb(devbase + pos + 3);
- if (id == HT_CAPTYPE_IRQ)
+ if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_IRQ)
break;
}
}
@@ -496,13 +496,18 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi)
{
unsigned int src = mpic_irq_to_hw(irq);
+ struct mpic *mpic;
if (irq < NUM_ISA_INTERRUPTS)
return NULL;
+
+ mpic = irq_desc[irq].chip_data;
+
if (is_ipi)
- *is_ipi = (src >= MPIC_VEC_IPI_0 && src <= MPIC_VEC_IPI_3);
+ *is_ipi = (src >= mpic->ipi_vecs[0] &&
+ src <= mpic->ipi_vecs[3]);
- return irq_desc[irq].chip_data;
+ return mpic;
}
/* Convert a cpu mask from logical to physical cpu numbers. */
@@ -540,7 +545,11 @@ static inline void mpic_eoi(struct mpic *mpic)
#ifdef CONFIG_SMP
static irqreturn_t mpic_ipi_action(int irq, void *dev_id)
{
- smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0);
+ struct mpic *mpic;
+
+ mpic = mpic_find(irq, NULL);
+ smp_message_recv(mpic_irq_to_hw(irq) - mpic->ipi_vecs[0]);
+
return IRQ_HANDLED;
}
#endif /* CONFIG_SMP */
@@ -663,7 +672,7 @@ static void mpic_end_ht_irq(unsigned int irq)
static void mpic_unmask_ipi(unsigned int irq)
{
struct mpic *mpic = mpic_from_ipi(irq);
- unsigned int src = mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0;
+ unsigned int src = mpic_irq_to_hw(irq) - mpic->ipi_vecs[0];
DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src);
mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
@@ -807,11 +816,11 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw);
- if (hw == MPIC_VEC_SPURRIOUS)
+ if (hw == mpic->spurious_vec)
return -EINVAL;
#ifdef CONFIG_SMP
- else if (hw >= MPIC_VEC_IPI_0) {
+ else if (hw >= mpic->ipi_vecs[0]) {
WARN_ON(!(mpic->flags & MPIC_PRIMARY));
DBG("mpic: mapping as IPI\n");
@@ -904,6 +913,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
u32 reg;
const char *vers;
int i;
+ int intvec_top;
u64 paddr = phys_addr;
mpic = alloc_bootmem(sizeof(struct mpic));
@@ -912,11 +922,11 @@ struct mpic * __init mpic_alloc(struct device_node *node,
memset(mpic, 0, sizeof(struct mpic));
mpic->name = name;
- mpic->of_node = node ? of_node_get(node) : NULL;
+ mpic->of_node = of_node_get(node);
- mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 256,
+ mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, isu_size,
&mpic_host_ops,
- MPIC_VEC_SPURRIOUS);
+ flags & MPIC_LARGE_VECTORS ? 2048 : 256);
if (mpic->irqhost == NULL) {
of_node_put(node);
return NULL;
@@ -944,6 +954,21 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic->irq_count = irq_count;
mpic->num_sources = 0; /* so far */
+ if (flags & MPIC_LARGE_VECTORS)
+ intvec_top = 2047;
+ else
+ intvec_top = 255;
+
+ mpic->timer_vecs[0] = intvec_top - 8;
+ mpic->timer_vecs[1] = intvec_top - 7;
+ mpic->timer_vecs[2] = intvec_top - 6;
+ mpic->timer_vecs[3] = intvec_top - 5;
+ mpic->ipi_vecs[0] = intvec_top - 4;
+ mpic->ipi_vecs[1] = intvec_top - 3;
+ mpic->ipi_vecs[2] = intvec_top - 2;
+ mpic->ipi_vecs[3] = intvec_top - 1;
+ mpic->spurious_vec = intvec_top;
+
/* Check for "big-endian" in device-tree */
if (node && get_property(node, "big-endian", NULL) != NULL)
mpic->flags |= MPIC_BIG_ENDIAN;
@@ -1084,11 +1109,6 @@ void __init mpic_init(struct mpic *mpic)
int i;
BUG_ON(mpic->num_sources == 0);
- WARN_ON(mpic->num_sources > MPIC_VEC_IPI_0);
-
- /* Sanitize source count */
- if (mpic->num_sources > MPIC_VEC_IPI_0)
- mpic->num_sources = MPIC_VEC_IPI_0;
printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources);
@@ -1104,7 +1124,7 @@ void __init mpic_init(struct mpic *mpic)
i * MPIC_INFO(TIMER_STRIDE) +
MPIC_INFO(TIMER_VECTOR_PRI),
MPIC_VECPRI_MASK |
- (MPIC_VEC_TIMER_0 + i));
+ (mpic->timer_vecs[0] + i));
}
/* Initialize IPIs to our reserved vectors and mark them disabled for now */
@@ -1113,7 +1133,7 @@ void __init mpic_init(struct mpic *mpic)
mpic_ipi_write(i,
MPIC_VECPRI_MASK |
(10 << MPIC_VECPRI_PRIORITY_SHIFT) |
- (MPIC_VEC_IPI_0 + i));
+ (mpic->ipi_vecs[0] + i));
}
/* Initialize interrupt sources */
@@ -1136,8 +1156,8 @@ void __init mpic_init(struct mpic *mpic)
1 << hard_smp_processor_id());
}
- /* Init spurrious vector */
- mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), MPIC_VEC_SPURRIOUS);
+ /* Init spurious vector */
+ mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), mpic->spurious_vec);
/* Disable 8259 passthrough, if supported */
if (!(mpic->flags & MPIC_NO_PTHROU_DIS))
@@ -1184,9 +1204,9 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
spin_lock_irqsave(&mpic_lock, flags);
if (is_ipi) {
- reg = mpic_ipi_read(src - MPIC_VEC_IPI_0) &
+ reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) &
~MPIC_VECPRI_PRIORITY_MASK;
- mpic_ipi_write(src - MPIC_VEC_IPI_0,
+ mpic_ipi_write(src - mpic->ipi_vecs[0],
reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
} else {
reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI))
@@ -1207,7 +1227,7 @@ unsigned int mpic_irq_get_priority(unsigned int irq)
spin_lock_irqsave(&mpic_lock, flags);
if (is_ipi)
- reg = mpic_ipi_read(src = MPIC_VEC_IPI_0);
+ reg = mpic_ipi_read(src = mpic->ipi_vecs[0]);
else
reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
spin_unlock_irqrestore(&mpic_lock, flags);
@@ -1313,7 +1333,7 @@ unsigned int mpic_get_one_irq(struct mpic *mpic)
#ifdef DEBUG_LOW
DBG("%s: get_one_irq(): %d\n", mpic->name, src);
#endif
- if (unlikely(src == MPIC_VEC_SPURRIOUS))
+ if (unlikely(src == mpic->spurious_vec))
return NO_IRQ;
return irq_linear_revmap(mpic->irqhost, src);
}
@@ -1345,7 +1365,7 @@ void mpic_request_ipis(void)
for (i = 0; i < 4; i++) {
unsigned int vipi = irq_create_mapping(mpic->irqhost,
- MPIC_VEC_IPI_0 + i);
+ mpic->ipi_vecs[0] + i);
if (vipi == NO_IRQ) {
printk(KERN_ERR "Failed to map IPI %d\n", i);
break;
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
index 6995f51b948..4d1dcb45963 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
@@ -223,23 +223,15 @@ static void qe_ic_mask_irq(unsigned int virq)
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 */
+ /* Flush the above write before enabling interrupts; otherwise,
+ * spurious interrupts will sometimes happen. To be 100% sure
+ * that the write has reached the device before interrupts are
+ * enabled, the mask register would have to be read back; however,
+ * this is not required for correctness, only to avoid wasting
+ * time on a large number of spurious interrupts. In testing,
+ * a sync reduced the observed spurious interrupts to zero.
+ */
+ mb();
spin_unlock_irqrestore(&qe_ic_lock, flags);
}
@@ -248,7 +240,7 @@ 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,
+ .mask_ack = qe_ic_mask_irq,
};
static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
@@ -331,34 +323,22 @@ unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
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)
+void 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)
+void 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)
@@ -372,7 +352,7 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags)
return;
memset(qe_ic, 0, sizeof(struct qe_ic));
- qe_ic->of_node = node ? of_node_get(node) : NULL;
+ qe_ic->of_node = of_node_get(node);
qe_ic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
NR_QE_IC_INTS, &qe_ic_host_ops, 0);
diff --git a/arch/powerpc/sysdev/rom.c b/arch/powerpc/sysdev/rom.c
index bf5b3f10e6c..c855a3b298a 100644
--- a/arch/powerpc/sysdev/rom.c
+++ b/arch/powerpc/sysdev/rom.c
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <asm/of_device.h>
+#include <asm/of_platform.h>
static int __init powerpc_flash_init(void)
{
diff --git a/arch/powerpc/xmon/ppc-opc.c b/arch/powerpc/xmon/ppc-opc.c
index 5d841f4b353..af3780e52e7 100644
--- a/arch/powerpc/xmon/ppc-opc.c
+++ b/arch/powerpc/xmon/ppc-opc.c
@@ -21,6 +21,7 @@
02110-1301, USA. */
#include <linux/stddef.h>
+#include <linux/kernel.h>
#include "nonstdio.h"
#include "ppc.h"
@@ -4932,8 +4933,7 @@ const struct powerpc_opcode powerpc_opcodes[] = {
};
-const int powerpc_num_opcodes =
- sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
+const int powerpc_num_opcodes = ARRAY_SIZE(powerpc_opcodes);
/* The macro table. This is only used by the assembler. */
@@ -4989,5 +4989,4 @@ const struct powerpc_macro powerpc_macros[] = {
{ "clrlslwi.",4, PPCCOM, "rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" },
};
-const int powerpc_num_macros =
- sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
+const int powerpc_num_macros = ARRAY_SIZE(powerpc_macros);
diff --git a/arch/powerpc/xmon/spu-dis.c b/arch/powerpc/xmon/spu-dis.c
index ee929c641bf..e5f89837c82 100644
--- a/arch/powerpc/xmon/spu-dis.c
+++ b/arch/powerpc/xmon/spu-dis.c
@@ -85,7 +85,7 @@ get_index_for_opcode (unsigned int insn)
if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0)
return index;
- return 0;
+ return NULL;
}
/* Print a Spu instruction. */
diff --git a/arch/powerpc/xmon/spu-opc.c b/arch/powerpc/xmon/spu-opc.c
index efffde9edc6..530df3d6d7b 100644
--- a/arch/powerpc/xmon/spu-opc.c
+++ b/arch/powerpc/xmon/spu-opc.c
@@ -18,6 +18,7 @@
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+#include <linux/kernel.h>
#include "spu.h"
/* This file holds the Spu opcode table */
@@ -40,5 +41,4 @@ const struct spu_opcode spu_opcodes[] = {
#undef APUOPFB
};
-const int spu_num_opcodes =
- sizeof (spu_opcodes) / sizeof (spu_opcodes[0]);
+const int spu_num_opcodes = ARRAY_SIZE(spu_opcodes);
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index a34ed49e035..77540a2f770 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -22,6 +22,7 @@
#include <linux/sysrq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/bug.h>
#include <asm/ptrace.h>
#include <asm/string.h>
@@ -35,7 +36,6 @@
#include <asm/cputable.h>
#include <asm/rtas.h>
#include <asm/sstep.h>
-#include <asm/bug.h>
#include <asm/irq_regs.h>
#include <asm/spu.h>
#include <asm/spu_priv1.h>
@@ -1346,7 +1346,7 @@ static void backtrace(struct pt_regs *excp)
static void print_bug_trap(struct pt_regs *regs)
{
- struct bug_entry *bug;
+ const struct bug_entry *bug;
unsigned long addr;
if (regs->msr & MSR_PR)
@@ -1357,11 +1357,11 @@ static void print_bug_trap(struct pt_regs *regs)
bug = find_bug(regs->nip);
if (bug == NULL)
return;
- if (bug->line & BUG_WARNING_TRAP)
+ if (is_warning_bug(bug))
return;
- printf("kernel BUG in %s at %s:%d!\n",
- bug->function, bug->file, (unsigned int)bug->line);
+ printf("kernel BUG at %s:%u!\n",
+ bug->file, bug->line);
}
void excprint(struct pt_regs *fp)
diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c
index 709952c25f2..06b84c372e5 100644
--- a/arch/ppc/8260_io/fcc_enet.c
+++ b/arch/ppc/8260_io/fcc_enet.c
@@ -1892,10 +1892,10 @@ init_fcc_param(fcc_info_t *fip, struct net_device *dev,
/* Allocate space for the buffer descriptors from regular memory.
* Initialize base addresses for the buffer descriptors.
*/
- cep->rx_bd_base = (cbd_t *)kmalloc(sizeof(cbd_t) * RX_RING_SIZE,
+ cep->rx_bd_base = kmalloc(sizeof(cbd_t) * RX_RING_SIZE,
GFP_KERNEL | GFP_DMA);
ep->fen_genfcc.fcc_rbase = __pa(cep->rx_bd_base);
- cep->tx_bd_base = (cbd_t *)kmalloc(sizeof(cbd_t) * TX_RING_SIZE,
+ cep->tx_bd_base = kmalloc(sizeof(cbd_t) * TX_RING_SIZE,
GFP_KERNEL | GFP_DMA);
ep->fen_genfcc.fcc_tbase = __pa(cep->tx_bd_base);
diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
index 959d31c26cb..684ed04eb8b 100644
--- a/arch/ppc/8xx_io/cs4218_tdm.c
+++ b/arch/ppc/8xx_io/cs4218_tdm.c
@@ -1379,7 +1379,6 @@ static void cs_nosound(unsigned long xx)
}
static DEFINE_TIMER(beep_timer, cs_nosound, 0, 0);
-};
static void cs_mksound(unsigned int hz, unsigned int ticks)
{
@@ -2165,7 +2164,7 @@ static int sq_release(struct inode *inode, struct file *file)
int rc = 0;
if (sq.busy)
- rc = sq_fsync(file, file->f_dentry);
+ rc = sq_fsync(file, file->f_path.dentry);
sound.soft = sound.dsp;
sound.hard = sound.dsp;
sound_silence();
@@ -2218,25 +2217,25 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
return 0;
case SNDCTL_DSP_POST:
case SNDCTL_DSP_SYNC:
- return sq_fsync(file, file->f_dentry);
+ return sq_fsync(file, file->f_path.dentry);
/* ++TeSche: before changing any of these it's
* probably wise to wait until sound playing has
* settled down. */
case SNDCTL_DSP_SPEED:
- sq_fsync(file, file->f_dentry);
+ sq_fsync(file, file->f_path.dentry);
IOCTL_IN(arg, data);
return IOCTL_OUT(arg, sound_set_speed(data));
case SNDCTL_DSP_STEREO:
- sq_fsync(file, file->f_dentry);
+ sq_fsync(file, file->f_path.dentry);
IOCTL_IN(arg, data);
return IOCTL_OUT(arg, sound_set_stereo(data));
case SOUND_PCM_WRITE_CHANNELS:
- sq_fsync(file, file->f_dentry);
+ sq_fsync(file, file->f_path.dentry);
IOCTL_IN(arg, data);
return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
case SNDCTL_DSP_SETFMT:
- sq_fsync(file, file->f_dentry);
+ sq_fsync(file, file->f_path.dentry);
IOCTL_IN(arg, data);
return IOCTL_OUT(arg, sound_set_format(data));
case SNDCTL_DSP_GETFMTS:
@@ -2601,7 +2600,7 @@ int __init tdm8xx_sound_init(void)
/* Initialize beep stuff */
orig_mksound = kd_mksound;
kd_mksound = cs_mksound;
- beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
+ beep_buf = kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
if (beep_buf == NULL)
printk(KERN_WARNING "dmasound: no memory for "
"beep buffer\n");
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index edf71a4ecc9..c22e60619d9 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -19,6 +19,14 @@ config RWSEM_XCHGADD_ALGORITHM
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default y
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_HWEIGHT
bool
default y
@@ -52,6 +60,11 @@ config ARCH_MAY_HAVE_PC_FDC
bool
default y
+config GENERIC_BUG
+ bool
+ default y
+ depends on BUG
+
source "init/Kconfig"
menu "Processor"
@@ -611,7 +624,7 @@ config HDPU
Select HDPU if configuring a Sky Computers Compute Blade.
config HDPU_FEATURES
- depends HDPU
+ depends on HDPU
tristate "HDPU-Features"
help
Select to enable HDPU enhanced features.
@@ -657,15 +670,6 @@ config RADSTONE_PPC7D
config PAL4
bool "SBS-Palomar4"
-config GEMINI
- bool "Synergy-Gemini"
- depends on BROKEN
- select PPC_INDIRECT_PCI
- help
- Select Gemini if configuring for a Synergy Microsystems' Gemini
- series Single Board Computer. More information is available at:
- <http://www.synergymicro.com/PressRel/97_10_15.html>.
-
config EST8260
bool "EST8260"
---help---
@@ -722,7 +726,7 @@ config LITE5200
config LITE5200B
bool "Freescale LITE5200B"
- depends LITE5200
+ depends on LITE5200
help
Support for the LITE5200B dev board for the MPC5200 from Freescale.
This is the new board with 2 PCI slots.
diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
index 28be01b99c4..bcfb6cde70c 100644
--- a/arch/ppc/boot/simple/Makefile
+++ b/arch/ppc/boot/simple/Makefile
@@ -116,10 +116,6 @@ zimageinitrd-$(CONFIG_WALNUT) := zImage.initrd-TREE
extra.o-$(CONFIG_CHESTNUT) := misc-chestnut.o
end-$(CONFIG_CHESTNUT) := chestnut
- zimage-$(CONFIG_GEMINI) := zImage-STRIPELF
-zimageinitrd-$(CONFIG_GEMINI) := zImage.initrd-STRIPELF
- end-$(CONFIG_GEMINI) := gemini
-
extra.o-$(CONFIG_KATANA) := misc-katana.o
end-$(CONFIG_KATANA) := katana
cacheflag-$(CONFIG_KATANA) := -include $(clear_L2_L3)
diff --git a/arch/ppc/boot/simple/misc.c b/arch/ppc/boot/simple/misc.c
index a5df0896369..c3d3305eb5c 100644
--- a/arch/ppc/boot/simple/misc.c
+++ b/arch/ppc/boot/simple/misc.c
@@ -42,14 +42,11 @@
#endif
/* Will / Can the user give input?
- * Val Henson has requested that Gemini doesn't wait for the
- * user to edit the cmdline or not.
*/
#if (defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_VGA_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
- && !defined(CONFIG_GEMINI)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE))
#define INTERACTIVE_CONSOLE 1
#endif
@@ -178,16 +175,6 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
if (keyb_present)
CRT_tstc(); /* Forces keyboard to be initialized */
-#ifdef CONFIG_GEMINI
- /*
- * If cmd_line is empty and cmd_preset is not, copy cmd_preset
- * to cmd_line. This way we can override cmd_preset with the
- * command line from Smon.
- */
-
- if ( (cmd_line[0] == '\0') && (cmd_preset[0] != '\0'))
- memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
-#endif
/* Display standard Linux/PPC boot prompt for kernel args */
puts("\nLinux/PPC load: ");
diff --git a/arch/ppc/configs/gemini_defconfig b/arch/ppc/configs/gemini_defconfig
deleted file mode 100644
index ebcd17b097f..00000000000
--- a/arch/ppc/configs/gemini_defconfig
+++ /dev/null
@@ -1,618 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_EMBEDDED is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-
-#
-# IBM 4xx options
-#
-# CONFIG_8260 is not set
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PPC_STD_MMU=y
-# CONFIG_PPC_MULTIPLATFORM is not set
-# CONFIG_APUS is not set
-# CONFIG_WILLOW_2 is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-CONFIG_GEMINI=y
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-CONFIG_ALTIVEC=y
-CONFIG_TAU=y
-# CONFIG_TAU_INT is not set
-# CONFIG_TAU_AVERAGE is not set
-# CONFIG_CPU_FREQ is not set
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_PPC601_SYNC_FIX is not set
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00800000
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=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=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
-CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID 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_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS 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_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C7xx 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_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_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG 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_INET_ECN 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
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_OAKNET is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_PCI is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices (depends on LLC=y)
-#
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_FAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
-CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=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=y
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_NEC98_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
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 466437f4bcb..6b4f022111e 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -12,7 +12,6 @@ obj-y := entry.o traps.o time.o misc.o \
setup.o \
ppc_htab.o
obj-$(CONFIG_MODULES) += ppc_ksyms.o
-obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_RAPIDIO) += rio.o
obj-$(CONFIG_KGDB) += ppc-stub.o
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 100052aaea9..c7cb9d5f24a 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -310,12 +310,7 @@ i##n: \
/* System reset */
/* core99 pmac starts the seconary here by changing the vector, and
putting it back to what it was (unknown_exception) when done. */
-#if defined(CONFIG_GEMINI) && defined(CONFIG_SMP)
- . = 0x100
- b __secondary_start_gemini
-#else
EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)
-#endif
/* Machine check */
. = 0x200
@@ -897,19 +892,6 @@ fix_mem_constants:
#endif /* CONFIG_APUS */
#ifdef CONFIG_SMP
-#ifdef CONFIG_GEMINI
- .globl __secondary_start_gemini
-__secondary_start_gemini:
- mfspr r4,SPRN_HID0
- ori r4,r4,HID0_ICFI
- li r3,0
- ori r3,r3,HID0_ICE
- andc r4,r4,r3
- mtspr SPRN_HID0,r4
- sync
- b __secondary_start
-#endif /* CONFIG_GEMINI */
-
.globl __secondary_start_pmac_0
__secondary_start_pmac_0:
/* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 63808e01cb0..5e723c4c257 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -879,7 +879,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
- unsigned long *offset,
+ resource_size_t *offset,
enum pci_mmap_state mmap_state)
{
struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
@@ -891,7 +891,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
/* If memory, add on the PCI bridge address offset */
if (mmap_state == pci_mmap_mem) {
+#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
*offset += hose->pci_mem_offset;
+#endif
res_bit = IORESOURCE_MEM;
} else {
io_offset = hose->io_base_virt - ___IO_BASE;
@@ -1030,7 +1032,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state,
int write_combine)
{
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
struct resource *rp;
int ret;
@@ -1132,21 +1134,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
resource_size_t *start, resource_size_t *end)
{
struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
- unsigned long offset = 0;
+ resource_size_t offset = 0;
if (hose == NULL)
return;
if (rsrc->flags & IORESOURCE_IO)
- offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys;
+ offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+
+ /* We pass a fully fixed up address to userland for MMIO instead of
+ * a BAR value because X is lame and expects to be able to use that
+ * to pass to /dev/mem !
+ *
+ * That means that we'll have potentially 64 bits values where some
+ * userland apps only expect 32 (like X itself since it thinks only
+ * Sparc has 64 bits MMIO) but if we don't do that, we break it on
+ * 32 bits CHRPs :-(
+ *
+ * Hopefully, the sysfs insterface is immune to that gunk. Once X
+ * has been fixed (and the fix spread enough), we can re-enable the
+ * 2 lines below and pass down a BAR value to userland. In that case
+ * we'll also have to re-enable the matching code in
+ * __pci_mmap_make_offset().
+ *
+ * BenH.
+ */
+#if 0
+ else if (rsrc->flags & IORESOURCE_MEM)
+ offset = hose->pci_mem_offset;
+#endif
- *start = rsrc->start + offset;
- *end = rsrc->end + offset;
+ *start = rsrc->start - offset;
+ *end = rsrc->end - offset;
}
-void __init
-pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
- int flags, char *name)
+void __init pci_init_resource(struct resource *res, resource_size_t start,
+ resource_size_t end, int flags, char *name)
{
res->start = start;
res->end = end;
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index c8b65ca8a35..1f49503317c 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -43,6 +43,7 @@
#include <asm/div64.h>
#include <asm/xmon.h>
#include <asm/signal.h>
+#include <asm/dcr.h>
#ifdef CONFIG_8xx
#include <asm/commproc.h>
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 2f835b9e95e..810f7aa72e9 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -28,6 +28,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/prctl.h>
+#include <linux/bug.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
@@ -559,64 +560,9 @@ static void emulate_single_step(struct pt_regs *regs)
}
}
-/*
- * Look through the list of trap instructions that are used for BUG(),
- * BUG_ON() and WARN_ON() and see if we hit one. At this point we know
- * that the exception was caused by a trap instruction of some kind.
- * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0
- * otherwise.
- */
-extern struct bug_entry __start___bug_table[], __stop___bug_table[];
-
-#ifndef CONFIG_MODULES
-#define module_find_bug(x) NULL
-#endif
-
-struct bug_entry *find_bug(unsigned long bugaddr)
-{
- struct bug_entry *bug;
-
- for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
- if (bugaddr == bug->bug_addr)
- return bug;
- return module_find_bug(bugaddr);
-}
-
-int check_bug_trap(struct pt_regs *regs)
+int is_valid_bugaddr(unsigned long addr)
{
- struct bug_entry *bug;
- unsigned long addr;
-
- if (regs->msr & MSR_PR)
- return 0; /* not in kernel */
- addr = regs->nip; /* address of trap instruction */
- if (addr < PAGE_OFFSET)
- return 0;
- bug = find_bug(regs->nip);
- if (bug == NULL)
- return 0;
- if (bug->line & BUG_WARNING_TRAP) {
- /* this is a WARN_ON rather than BUG/BUG_ON */
-#ifdef CONFIG_XMON
- xmon_printf(KERN_ERR "Badness in %s at %s:%ld\n",
- bug->function, bug->file,
- bug->line & ~BUG_WARNING_TRAP);
-#endif /* CONFIG_XMON */
- printk(KERN_ERR "Badness in %s at %s:%ld\n",
- bug->function, bug->file,
- bug->line & ~BUG_WARNING_TRAP);
- dump_stack();
- return 1;
- }
-#ifdef CONFIG_XMON
- xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
- bug->function, bug->file, bug->line);
- xmon(regs);
-#endif /* CONFIG_XMON */
- printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
- bug->function, bug->file, bug->line);
-
- return 0;
+ return addr >= PAGE_OFFSET;
}
void program_check_exception(struct pt_regs *regs)
@@ -671,7 +617,9 @@ void program_check_exception(struct pt_regs *regs)
/* trap exception */
if (debugger_bpt(regs))
return;
- if (check_bug_trap(regs)) {
+
+ if (!(regs->msr & MSR_PR) && /* not user-mode */
+ report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) {
regs->nip += 4;
return;
}
diff --git a/arch/ppc/lib/rheap.c b/arch/ppc/lib/rheap.c
index 31e511856dc..d40700795a9 100644
--- a/arch/ppc/lib/rheap.c
+++ b/arch/ppc/lib/rheap.c
@@ -14,6 +14,7 @@
*/
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -654,7 +655,7 @@ void rh_dump(rh_info_t * info)
int maxnr;
int i, nr;
- maxnr = sizeof(st) / sizeof(st[0]);
+ maxnr = ARRAY_SIZE(st);
printk(KERN_INFO
"info @0x%p (%d slots empty / %d max)\n",
diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c
index 354a9408f02..82b06a1ef95 100644
--- a/arch/ppc/mm/pgtable.c
+++ b/arch/ppc/mm/pgtable.c
@@ -313,11 +313,8 @@ void __init mapin_ram(void)
}
}
-/* is x a power of 2? */
-#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
-
/* is x a power of 4? */
-#define is_power_of_4(x) ((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1))
+#define is_power_of_4(x) is_power_of_2(x) && (ffs(x) & 1))
/*
* Set up a mapping for a block of I/O.
diff --git a/arch/ppc/platforms/4xx/Kconfig b/arch/ppc/platforms/4xx/Kconfig
index 293bd489e7d..6980de420e9 100644
--- a/arch/ppc/platforms/4xx/Kconfig
+++ b/arch/ppc/platforms/4xx/Kconfig
@@ -189,7 +189,7 @@ config BIOS_FIXUP
# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
config 403GCX
bool
- depends OAK
+ depends on OAK
default y
config 405EP
diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
index 90c62229442..e17fad47062 100644
--- a/arch/ppc/platforms/Makefile
+++ b/arch/ppc/platforms/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_TQM8260) += tqm8260_setup.o
obj-$(CONFIG_CPCI690) += cpci690.o
obj-$(CONFIG_EV64260) += ev64260.o
obj-$(CONFIG_CHESTNUT) += chestnut.o
-obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o
obj-$(CONFIG_LOPEC) += lopec.o
obj-$(CONFIG_KATANA) += katana.o
obj-$(CONFIG_HDPU) += hdpu.o
diff --git a/arch/ppc/platforms/ev64360.c b/arch/ppc/platforms/ev64360.c
index 90ed375c9b9..f87e06f6bab 100644
--- a/arch/ppc/platforms/ev64360.c
+++ b/arch/ppc/platforms/ev64360.c
@@ -358,13 +358,12 @@ ev64360_setup_mtd(void)
ptbl_entries = 3;
- if ((ptbl = kmalloc(ptbl_entries * sizeof(struct mtd_partition),
+ if ((ptbl = kzalloc(ptbl_entries * sizeof(struct mtd_partition),
GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "Can't alloc MTD partition table\n");
return -ENOMEM;
}
- memset(ptbl, 0, ptbl_entries * sizeof(struct mtd_partition));
ptbl[0].name = "reserved";
ptbl[0].offset = 0;
diff --git a/arch/ppc/platforms/gemini.h b/arch/ppc/platforms/gemini.h
deleted file mode 100644
index 5528fd0a121..00000000000
--- a/arch/ppc/platforms/gemini.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Onboard registers and descriptions for Synergy Microsystems'
- * "Gemini" boards.
- *
- */
-#ifdef __KERNEL__
-#ifndef __PPC_GEMINI_H
-#define __PPC_GEMINI_H
-
-/* Registers */
-
-#define GEMINI_SERIAL_B (0xffeffb00)
-#define GEMINI_SERIAL_A (0xffeffb08)
-#define GEMINI_USWITCH (0xffeffd00)
-#define GEMINI_BREV (0xffeffe00)
-#define GEMINI_BECO (0xffeffe08)
-#define GEMINI_FEAT (0xffeffe10)
-#define GEMINI_BSTAT (0xffeffe18)
-#define GEMINI_CPUSTAT (0xffeffe20)
-#define GEMINI_L2CFG (0xffeffe30)
-#define GEMINI_MEMCFG (0xffeffe38)
-#define GEMINI_FLROM (0xffeffe40)
-#define GEMINI_P0PCI (0xffeffe48)
-#define GEMINI_FLWIN (0xffeffe50)
-#define GEMINI_P0INTMASK (0xffeffe60)
-#define GEMINI_P0INTAP (0xffeffe68)
-#define GEMINI_PCIERR (0xffeffe70)
-#define GEMINI_LEDBASE (0xffeffe80)
-#define GEMINI_RTC (0xffe9fff8)
-#define GEMINI_LEDS 8
-#define GEMINI_SWITCHES 8
-
-
-/* Flash ROM bit definitions */
-#define GEMINI_FLS_WEN (1<<0)
-#define GEMINI_FLS_JMP (1<<6)
-#define GEMINI_FLS_BOOT (1<<7)
-
-/* Memory bit definitions */
-#define GEMINI_MEM_TYPE_MASK 0xc0
-#define GEMINI_MEM_SIZE_MASK 0x38
-#define GEMINI_MEM_BANK_MASK 0x07
-
-/* L2 cache bit definitions */
-#define GEMINI_L2_SIZE_MASK 0xc0
-#define GEMINI_L2_RATIO_MASK 0x03
-
-/* Timebase register bit definitons */
-#define GEMINI_TIMEB0_EN (1<<0)
-#define GEMINI_TIMEB1_EN (1<<1)
-#define GEMINI_TIMEB2_EN (1<<2)
-#define GEMINI_TIMEB3_EN (1<<3)
-
-/* CPU status bit definitions */
-#define GEMINI_CPU_ID_MASK 0x03
-#define GEMINI_CPU_COUNT_MASK 0x0c
-#define GEMINI_CPU0_HALTED (1<<4)
-#define GEMINI_CPU1_HALTED (1<<5)
-#define GEMINI_CPU2_HALTED (1<<6)
-#define GEMINI_CPU3_HALTED (1<<7)
-
-/* Board status bit definitions */
-#define GEMINI_BRD_FAIL (1<<0) /* FAIL led is lit */
-#define GEMINI_BRD_BUS_MASK 0x0c /* PowerPC bus speed */
-
-/* Board family/feature bit descriptions */
-#define GEMINI_FEAT_HAS_FLASH (1<<0)
-#define GEMINI_FEAT_HAS_ETH (1<<1)
-#define GEMINI_FEAT_HAS_SCSI (1<<2)
-#define GEMINI_FEAT_HAS_P0 (1<<3)
-#define GEMINI_FEAT_FAM_MASK 0xf0
-
-/* Mod/ECO bit definitions */
-#define GEMINI_ECO_LEVEL_MASK 0x0f
-#define GEMINI_MOD_MASK 0xf0
-
-/* Type/revision bit definitions */
-#define GEMINI_REV_MASK 0x0f
-#define GEMINI_TYPE_MASK 0xf0
-
-/* User switch definitions */
-#define GEMINI_SWITCH_VERBOSE 1 /* adds "debug" to boot cmd line */
-#define GEMINI_SWITCH_SINGLE_USER 7 /* boots into "single-user" mode */
-
-#define SGS_RTC_CONTROL 0
-#define SGS_RTC_SECONDS 1
-#define SGS_RTC_MINUTES 2
-#define SGS_RTC_HOURS 3
-#define SGS_RTC_DAY 4
-#define SGS_RTC_DAY_OF_MONTH 5
-#define SGS_RTC_MONTH 6
-#define SGS_RTC_YEAR 7
-
-#define SGS_RTC_SET 0x80
-#define SGS_RTC_IS_STOPPED 0x80
-
-#define GRACKLE_CONFIG_ADDR_ADDR (0xfec00000)
-#define GRACKLE_CONFIG_DATA_ADDR (0xfee00000)
-
-#define GEMINI_BOOT_INIT (0xfff00100)
-
-#ifndef __ASSEMBLY__
-
-static inline void grackle_write( unsigned long addr, unsigned long data )
-{
- __asm__ __volatile__(
- " stwbrx %1, 0, %0\n \
- sync\n \
- stwbrx %3, 0, %2\n \
- sync "
- : /* no output */
- : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr),
- "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data));
-}
-
-static inline unsigned long grackle_read( unsigned long addr )
-{
- unsigned long val;
-
- __asm__ __volatile__(
- " stwbrx %1, 0, %2\n \
- sync\n \
- lwbrx %0, 0, %3\n \
- sync "
- : "=r" (val)
- : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR),
- "r" (GRACKLE_CONFIG_DATA_ADDR));
-
- return val;
-}
-
-static inline void gemini_led_on( int led )
-{
- if (led >= 0 && led < GEMINI_LEDS)
- *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1;
-}
-
-static inline void gemini_led_off(int led)
-{
- if (led >= 0 && led < GEMINI_LEDS)
- *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0;
-}
-
-static inline int gemini_led_val(int led)
-{
- int val = 0;
- if (led >= 0 && led < GEMINI_LEDS)
- val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3));
- return (val & 0x1);
-}
-
-/* returns processor id from the board */
-static inline int gemini_processor(void)
-{
- unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT);
- return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK));
-}
-
-
-extern void _gemini_reboot(void);
-extern void gemini_prom_init(void);
-extern void gemini_init_l2(void);
-#endif /* __ASSEMBLY__ */
-#endif
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/gemini_pci.c b/arch/ppc/platforms/gemini_pci.c
deleted file mode 100644
index 95656091ba2..00000000000
--- a/arch/ppc/platforms/gemini_pci.c
+++ /dev/null
@@ -1,41 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/machdep.h>
-#include <platforms/gemini.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pci-bridge.h>
-
-void __init gemini_pcibios_fixup(void)
-{
- int i;
- struct pci_dev *dev = NULL;
-
- for_each_pci_dev(dev) {
- for(i = 0; i < 6; i++) {
- if (dev->resource[i].flags & IORESOURCE_IO) {
- dev->resource[i].start |= (0xfe << 24);
- dev->resource[i].end |= (0xfe << 24);
- }
- }
- }
-}
-
-
-/* The "bootloader" for Synergy boards does none of this for us, so we need to
- lay it all out ourselves... --Dan */
-void __init gemini_find_bridges(void)
-{
- struct pci_controller* hose;
-
- ppc_md.pcibios_fixup = gemini_pcibios_fixup;
-
- hose = pcibios_alloc_controller();
- if (!hose)
- return;
- setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
-}
diff --git a/arch/ppc/platforms/gemini_prom.S b/arch/ppc/platforms/gemini_prom.S
deleted file mode 100644
index e8c84d24f01..00000000000
--- a/arch/ppc/platforms/gemini_prom.S
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Not really prom support code (yet), but sort of anti-prom code. The current
- * bootloader does a number of things it shouldn't and doesn't do things that it
- * should. The stuff in here is mainly a hodge-podge collection of setup code
- * to get the board up and running.
- * ---Dan
- */
-
-#include <asm/reg.h>
-#include <asm/page.h>
-#include <platforms/gemini.h>
-#include <asm/ppc_asm.h>
-
-/*
- * On 750's the MMU is on when Linux is booted, so we need to clear out the
- * bootloader's BAT settings, make sure we're in supervisor state (gotcha!),
- * and turn off the MMU.
- *
- */
-
-_GLOBAL(gemini_prom_init)
-#ifdef CONFIG_SMP
- /* Since the MMU's on, get stuff in rom space that we'll need */
- lis r4,GEMINI_CPUSTAT@h
- ori r4,r4,GEMINI_CPUSTAT@l
- lbz r5,0(r4)
- andi. r5,r5,3
- mr r24,r5 /* cpu # used later on */
-#endif
- mfmsr r4
- li r3,MSR_PR /* ensure supervisor! */
- ori r3,r3,MSR_IR|MSR_DR
- andc r4,r4,r3
- mtmsr r4
- isync
-#if 0
- /* zero out the bats now that the MMU is off */
-prom_no_mmu:
- li r3,0
- mtspr SPRN_IBAT0U,r3
- mtspr SPRN_IBAT0L,r3
- mtspr SPRN_IBAT1U,r3
- mtspr SPRN_IBAT1L,r3
- mtspr SPRN_IBAT2U,r3
- mtspr SPRN_IBAT2L,r3
- mtspr SPRN_IBAT3U,r3
- mtspr SPRN_IBAT3L,r3
-
- mtspr SPRN_DBAT0U,r3
- mtspr SPRN_DBAT0L,r3
- mtspr SPRN_DBAT1U,r3
- mtspr SPRN_DBAT1L,r3
- mtspr SPRN_DBAT2U,r3
- mtspr SPRN_DBAT2L,r3
- mtspr SPRN_DBAT3U,r3
- mtspr SPRN_DBAT3L,r3
-#endif
-
- /* the bootloader (as far as I'm currently aware) doesn't mess with page
- tables, but since we're already here, might as well zap these, too */
- li r4,0
- mtspr SPRN_SDR1,r4
-
- li r4,16
- mtctr r4
- li r3,0
- li r4,0
-3: mtsrin r3,r4
- addi r3,r3,1
- bdnz 3b
-
-#ifdef CONFIG_SMP
- /* The 750 book (and Mot/IBM support) says that this will "assist" snooping
- when in SMP. Not sure yet whether this should stay or leave... */
- mfspr r4,SPRN_HID0
- ori r4,r4,HID0_ABE
- mtspr SPRN_HID0,r4
- sync
-#endif /* CONFIG_SMP */
- blr
-
-/* apparently, SMon doesn't pay attention to HID0[SRST]. Disable the MMU and
- branch to 0xfff00100 */
-_GLOBAL(_gemini_reboot)
- lis r5,GEMINI_BOOT_INIT@h
- ori r5,r5,GEMINI_BOOT_INIT@l
- li r6,MSR_IP
- mtspr SPRN_SRR0,r5
- mtspr SPRN_SRR1,r6
- rfi
diff --git a/arch/ppc/platforms/gemini_serial.h b/arch/ppc/platforms/gemini_serial.h
deleted file mode 100644
index b915eff79fd..00000000000
--- a/arch/ppc/platforms/gemini_serial.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifdef __KERNEL__
-#ifndef __ASMPPC_GEMINI_SERIAL_H
-#define __ASMPPC_GEMINI_SERIAL_H
-
-#include <platforms/gemini.h>
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define RS_TABLE_SIZE 64
-#else
-#define RS_TABLE_SIZE 4
-#endif
-
-/* Rate for the 24.576 Mhz clock for the onboard serial chip */
-#define BASE_BAUD (24576000 / 16)
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
-#endif
-
-#define STD_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \
-
-#ifdef CONFIG_GEMINI_PU32
-#define PU32_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS },
-#else
-#define PU32_SERIAL_PORT_DEFNS
-#endif
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DEFNS \
- PU32_SERIAL_PORT_DEFNS
-
-#endif
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c
deleted file mode 100644
index f48048f362a..00000000000
--- a/arch/ppc/platforms/gemini_setup.c
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- * Copyright (C) 1995 Linus Torvalds
- * Adapted from 'alpha' version by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
- * Synergy Microsystems board support by Dan Cox (dan@synergymicro.com)
- *
- */
-
-#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/time.h>
-#include <linux/kdev_t.h>
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/initrd.h>
-#include <linux/console.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-#include <linux/bcd.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/m48t35.h>
-#include <platforms/gemini.h>
-#include <asm/time.h>
-#include <asm/open_pic.h>
-#include <asm/bootinfo.h>
-#include <asm/machdep.h>
-
-void gemini_find_bridges(void);
-static int gemini_get_clock_speed(void);
-extern void gemini_pcibios_fixup(void);
-
-static char *gemini_board_families[] = {
- "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR"
-};
-static int gemini_board_count = sizeof(gemini_board_families) /
- sizeof(gemini_board_families[0]);
-
-static unsigned int cpu_7xx[16] = {
- 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
-};
-static unsigned int cpu_6xx[16] = {
- 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
-};
-
-/*
- * prom_init is the Gemini version of prom.c:prom_init. We only need
- * the BSS clearing code, so I copied that out of prom.c. This is a
- * lot simpler than hacking prom.c so it will build with Gemini. -VAL
- */
-
-#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset))
-
-unsigned long
-prom_init(void)
-{
- unsigned long offset = reloc_offset();
- unsigned long phys;
- extern char __bss_start, _end;
-
- /* First zero the BSS -- use memset, some arches don't have
- * caches on yet */
- memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start);
-
- /* Default */
- phys = offset + KERNELBASE;
-
- gemini_prom_init();
-
- return phys;
-}
-
-int
-gemini_show_cpuinfo(struct seq_file *m)
-{
- unsigned char reg, rev;
- char *family;
- unsigned int type;
-
- reg = readb(GEMINI_FEAT);
- family = gemini_board_families[((reg>>4) & 0xf)];
- if (((reg>>4) & 0xf) > gemini_board_count)
- printk(KERN_ERR "cpuinfo(): unable to determine board family\n");
-
- reg = readb(GEMINI_BREV);
- type = (reg>>4) & 0xf;
- rev = reg & 0xf;
-
- reg = readb(GEMINI_BECO);
-
- seq_printf(m, "machine\t\t: Gemini %s%d, rev %c, eco %d\n",
- family, type, (rev + 'A'), (reg & 0xf));
-
- seq_printf(m, "board\t\t: Gemini %s", family);
- if (type > 9)
- seq_printf(m, "%c", (type - 10) + 'A');
- else
- seq_printf(m, "%d", type);
-
- seq_printf(m, ", rev %c, eco %d\n", (rev + 'A'), (reg & 0xf));
-
- seq_printf(m, "clock\t\t: %dMhz\n", gemini_get_clock_speed());
-
- return 0;
-}
-
-static u_char gemini_openpic_initsenses[] = {
- 1,
- 1,
- 1,
- 1,
- 0,
- 0,
- 1, /* remainder are level-triggered */
-};
-
-#define GEMINI_MPIC_ADDR (0xfcfc0000)
-#define GEMINI_MPIC_PCI_CFG (0x80005800)
-
-void __init gemini_openpic_init(void)
-{
-
- OpenPIC_Addr = (volatile struct OpenPIC *)
- grackle_read(GEMINI_MPIC_PCI_CFG + 0x10);
- OpenPIC_InitSenses = gemini_openpic_initsenses;
- OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses );
-
- ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE);
-}
-
-
-extern unsigned long loops_per_jiffy;
-extern int root_mountflags;
-extern char cmd_line[];
-
-void
-gemini_heartbeat(void)
-{
- static unsigned long led = GEMINI_LEDBASE+(4*8);
- static char direction = 8;
-
-
- /* We only want to do this on 1 CPU */
- if (smp_processor_id())
- return;
- *(char *)led = 0;
- if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) ||
- (led + direction) < (GEMINI_LEDBASE+(4*8)) )
- direction *= -1;
- led += direction;
- *(char *)led = 0xff;
- ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
-}
-
-void __init gemini_setup_arch(void)
-{
- extern char cmd_line[];
-
-
- loops_per_jiffy = 50000000/HZ;
-
-#ifdef CONFIG_BLK_DEV_INITRD
- /* bootable off CDROM */
- if (initrd_start)
- ROOT_DEV = Root_SR0;
- else
-#endif
- ROOT_DEV = Root_SDA1;
-
- /* nothing but serial consoles... */
- sprintf(cmd_line, "%s console=ttyS0", cmd_line);
-
- printk("Boot arguments: %s\n", cmd_line);
-
- ppc_md.heartbeat = gemini_heartbeat;
- ppc_md.heartbeat_reset = HZ/8;
- ppc_md.heartbeat_count = 1;
-
- /* Lookup PCI hosts */
- gemini_find_bridges();
- /* take special pains to map the MPIC, since it isn't mapped yet */
- gemini_openpic_init();
- /* start the L2 */
- gemini_init_l2();
-}
-
-
-int
-gemini_get_clock_speed(void)
-{
- unsigned long hid1, pvr;
- int clock;
-
- pvr = mfspr(SPRN_PVR);
- hid1 = (mfspr(SPRN_HID1) >> 28) & 0xf;
- if (PVR_VER(pvr) == 8 ||
- PVR_VER(pvr) == 12)
- hid1 = cpu_7xx[hid1];
- else
- hid1 = cpu_6xx[hid1];
-
- switch((readb(GEMINI_BSTAT) & 0xc) >> 2) {
-
- case 0:
- default:
- clock = (hid1*100)/3;
- break;
-
- case 1:
- clock = (hid1*125)/3;
- break;
-
- case 2:
- clock = (hid1*50);
- break;
- }
-
- return clock;
-}
-
-void __init gemini_init_l2(void)
-{
- unsigned char reg, brev, fam, creg;
- unsigned long cache;
- unsigned long pvr;
-
- reg = readb(GEMINI_L2CFG);
- brev = readb(GEMINI_BREV);
- fam = readb(GEMINI_FEAT);
- pvr = mfspr(SPRN_PVR);
-
- switch(PVR_VER(pvr)) {
-
- case 8:
- if (reg & 0xc0)
- cache = (((reg >> 6) & 0x3) << 28);
- else
- cache = 0x3 << 28;
-
-#ifdef CONFIG_SMP
- /* Pre-3.0 processor revs had snooping errata. Leave
- their L2's disabled with SMP. -- Dan */
- if (PVR_CFG(pvr) < 3) {
- printk("Pre-3.0 750; L2 left disabled!\n");
- return;
- }
-#endif /* CONFIG_SMP */
-
- /* Special case: VGM5-B's came before L2 ratios were set on
- the board. Processor speed shouldn't be too high, so
- set L2 ratio to 1:1.5. */
- if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0)
- reg |= 1;
-
- /* determine best cache ratio based upon what the board
- tells us (which sometimes _may_ not be true) and
- the processor speed. */
- else {
- if (gemini_get_clock_speed() > 250)
- reg = 2;
- }
- break;
- case 12:
- {
- static unsigned long l2_size_val = 0;
-
- if (!l2_size_val)
- l2_size_val = _get_L2CR();
- cache = l2_size_val;
- break;
- }
- case 4:
- case 9:
- creg = readb(GEMINI_CPUSTAT);
- if (((creg & 0xc) >> 2) != 1)
- printk("Dual-604 boards don't support the use of L2\n");
- else
- writeb(1, GEMINI_L2CFG);
- return;
- default:
- printk("Unknown processor; L2 left disabled\n");
- return;
- }
-
- cache |= ((1<<reg) << 25);
- cache |= (L2CR_L2RAM_MASK|L2CR_L2CTL|L2CR_L2DO);
- _set_L2CR(0);
- _set_L2CR(cache | L2CR_L2E);
-
-}
-
-void
-gemini_restart(char *cmd)
-{
- local_irq_disable();
- /* make a clean restart, not via the MPIC */
- _gemini_reboot();
- for(;;);
-}
-
-void
-gemini_power_off(void)
-{
- for(;;);
-}
-
-void
-gemini_halt(void)
-{
- gemini_restart(NULL);
-}
-
-void __init gemini_init_IRQ(void)
-{
- /* gemini has no 8259 */
- openpic_init(1, 0, 0, -1);
-}
-
-#define gemini_rtc_read(x) (readb(GEMINI_RTC+(x)))
-#define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x))))
-
-/* ensure that the RTC is up and running */
-long __init gemini_time_init(void)
-{
- unsigned char reg;
-
- reg = gemini_rtc_read(M48T35_RTC_CONTROL);
-
- if ( reg & M48T35_RTC_STOPPED ) {
- printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n");
- gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL);
- gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL);
- }
- return 0;
-}
-
-#undef DEBUG_RTC
-
-unsigned long
-gemini_get_rtc_time(void)
-{
- unsigned int year, mon, day, hour, min, sec;
- unsigned char reg;
-
- reg = gemini_rtc_read(M48T35_RTC_CONTROL);
- gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL);
-#ifdef DEBUG_RTC
- printk("get rtc: reg = %x\n", reg);
-#endif
-
- do {
- sec = gemini_rtc_read(M48T35_RTC_SECONDS);
- min = gemini_rtc_read(M48T35_RTC_MINUTES);
- hour = gemini_rtc_read(M48T35_RTC_HOURS);
- day = gemini_rtc_read(M48T35_RTC_DOM);
- mon = gemini_rtc_read(M48T35_RTC_MONTH);
- year = gemini_rtc_read(M48T35_RTC_YEAR);
- } while( sec != gemini_rtc_read(M48T35_RTC_SECONDS));
-#ifdef DEBUG_RTC
- printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n",
- sec, min, hour, day, mon, year);
-#endif
-
- gemini_rtc_write(reg, M48T35_RTC_CONTROL);
-
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
-
- if ((year += 1900) < 1970)
- year += 100;
-#ifdef DEBUG_RTC
- printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n",
- sec, min, hour, day, mon, year);
-#endif
-
- return mktime( year, mon, day, hour, min, sec );
-}
-
-
-int
-gemini_set_rtc_time( unsigned long now )
-{
- unsigned char reg;
- struct rtc_time tm;
-
- to_tm( now, &tm );
-
- reg = gemini_rtc_read(M48T35_RTC_CONTROL);
-#ifdef DEBUG_RTC
- printk("set rtc: reg = %x\n", reg);
-#endif
-
- gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL);
-#ifdef DEBUG_RTC
- printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
- tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
-#endif
-
- tm.tm_year -= 1900;
- BIN_TO_BCD(tm.tm_sec);
- BIN_TO_BCD(tm.tm_min);
- BIN_TO_BCD(tm.tm_hour);
- BIN_TO_BCD(tm.tm_mon);
- BIN_TO_BCD(tm.tm_mday);
- BIN_TO_BCD(tm.tm_year);
-#ifdef DEBUG_RTC
- printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
- tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
-#endif
-
- gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS);
- gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES);
- gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS);
- gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM);
- gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH);
- gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR);
-
- /* done writing */
- gemini_rtc_write(reg, M48T35_RTC_CONTROL);
-
- return 0;
-}
-
-/* use the RTC to determine the decrementer count */
-void __init gemini_calibrate_decr(void)
-{
- int freq, divisor;
- unsigned char reg;
-
- /* determine processor bus speed */
- reg = readb(GEMINI_BSTAT);
-
- switch(((reg & 0x0c)>>2)&0x3) {
- case 0:
- default:
- freq = 66667;
- break;
- case 1:
- freq = 83000;
- break;
- case 2:
- freq = 100000;
- break;
- }
-
- freq *= 1000;
- divisor = 4;
- tb_ticks_per_jiffy = freq / HZ / divisor;
- tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
-}
-
-unsigned long __init gemini_find_end_of_memory(void)
-{
- unsigned long total;
- unsigned char reg;
-
- reg = readb(GEMINI_MEMCFG);
- total = ((1<<((reg & 0x7) - 1)) *
- (8<<((reg >> 3) & 0x7)));
- total *= (1024*1024);
- return total;
-}
-
-static void __init
-gemini_map_io(void)
-{
- io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
- io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
-}
-
-#ifdef CONFIG_SMP
-static int
-smp_gemini_probe(void)
-{
- int i, nr;
-
- nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2;
- if (nr == 0)
- nr = 4;
-
- if (nr > 1) {
- openpic_request_IPIs();
- for (i = 1; i < nr; ++i)
- smp_hw_index[i] = i;
- }
-
- return nr;
-}
-
-static void
-smp_gemini_kick_cpu(int nr)
-{
- openpic_reset_processor_phys(1 << nr);
- openpic_reset_processor_phys(0);
-}
-
-static void
-smp_gemini_setup_cpu(int cpu_nr)
-{
- if (OpenPIC_Addr)
- do_openpic_setup_cpu();
- if (cpu_nr > 0)
- gemini_init_l2();
-}
-
-static struct smp_ops_t gemini_smp_ops = {
- smp_openpic_message_pass,
- smp_gemini_probe,
- smp_gemini_kick_cpu,
- smp_gemini_setup_cpu,
- .give_timebase = smp_generic_give_timebase,
- .take_timebase = smp_generic_take_timebase,
-};
-#endif /* CONFIG_SMP */
-
-void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
- int i;
-
- /* Restore BATs for now */
- mtspr(SPRN_DBAT3U, 0xf0001fff);
- mtspr(SPRN_DBAT3L, 0xf000002a);
-
- parse_bootinfo(find_bootinfo());
-
- for(i = 0; i < GEMINI_LEDS; i++)
- gemini_led_off(i);
-
- ISA_DMA_THRESHOLD = 0;
- DMA_MODE_READ = 0;
- DMA_MODE_WRITE = 0;
-
-#ifdef CONFIG_BLK_DEV_INITRD
- if ( r4 )
- {
- initrd_start = r4 + KERNELBASE;
- initrd_end = r5 + KERNELBASE;
- }
-#endif
-
- ppc_md.setup_arch = gemini_setup_arch;
- ppc_md.show_cpuinfo = gemini_show_cpuinfo;
- ppc_md.init_IRQ = gemini_init_IRQ;
- ppc_md.get_irq = openpic_get_irq;
- ppc_md.init = NULL;
-
- ppc_md.restart = gemini_restart;
- ppc_md.power_off = gemini_power_off;
- ppc_md.halt = gemini_halt;
-
- ppc_md.time_init = gemini_time_init;
- ppc_md.set_rtc_time = gemini_set_rtc_time;
- ppc_md.get_rtc_time = gemini_get_rtc_time;
- ppc_md.calibrate_decr = gemini_calibrate_decr;
-
- ppc_md.find_end_of_memory = gemini_find_end_of_memory;
- ppc_md.setup_io_mappings = gemini_map_io;
-
- ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup;
-
-#ifdef CONFIG_SMP
- smp_ops = &gemini_smp_ops;
-#endif /* CONFIG_SMP */
-}
diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c
index 8a0c07eb444..5b05d4bd0df 100644
--- a/arch/ppc/platforms/mpc866ads_setup.c
+++ b/arch/ppc/platforms/mpc866ads_setup.c
@@ -369,7 +369,7 @@ int __init mpc866ads_init(void)
ppc_sys_device_setfunc(MPC8xx_CPM_SMC1, PPC_SYS_FUNC_UART);
#endif
-#ifdef CONFIG_SERIAL_CPM_SMC
+#ifdef CONFIG_SERIAL_CPM_SMC2
ppc_sys_device_enable(MPC8xx_CPM_SMC2);
ppc_sys_device_setfunc(MPC8xx_CPM_SMC2, PPC_SYS_FUNC_UART);
#endif
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index dca23f2ef85..d84f0466697 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -45,7 +45,6 @@ obj-$(CONFIG_EBONY) += pci_auto.o todc_time.o
obj-$(CONFIG_EV64260) += todc_time.o pci_auto.o
obj-$(CONFIG_EV64360) += todc_time.o
obj-$(CONFIG_CHESTNUT) += mv64360_pic.o pci_auto.o
-obj-$(CONFIG_GEMINI) += open_pic.o
obj-$(CONFIG_GT64260) += gt64260_pic.o
obj-$(CONFIG_LOPEC) += pci_auto.o todc_time.o
obj-$(CONFIG_HDPU) += pci_auto.o
diff --git a/arch/ppc/syslib/m8260_pci_erratum9.c b/arch/ppc/syslib/m8260_pci_erratum9.c
index 5475709ce07..ebb8c8f8f30 100644
--- a/arch/ppc/syslib/m8260_pci_erratum9.c
+++ b/arch/ppc/syslib/m8260_pci_erratum9.c
@@ -105,7 +105,8 @@ void idma_pci9_init(void)
idma_reg[IDMA_CHAN].idmr = 0; /* mask all IDMA interrupts */
idma_reg[IDMA_CHAN].idsr = 0xff; /* clear all event flags */
- printk("<4>Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n",
+ printk(KERN_WARNING
+ "Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n",
IDMA_CHAN + 1);
return;
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index d8d299bd1a1..01e48d88f22 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -77,7 +77,7 @@ static struct mtd_partition mpc8xxads_partitions[] = {
}
};
-#define mpc8xxads_part_num (sizeof (mpc8xxads_partitions) / sizeof (mpc8xxads_partitions[0]))
+#define mpc8xxads_part_num ARRAY_SIZE(mpc8xxads_partitions)
#endif
diff --git a/arch/ppc/syslib/ppc85xx_rio.c b/arch/ppc/syslib/ppc85xx_rio.c
index 05b0e941508..2b097800cdd 100644
--- a/arch/ppc/syslib/ppc85xx_rio.c
+++ b/arch/ppc/syslib/ppc85xx_rio.c
@@ -59,8 +59,6 @@
#define DBELL_TID(x) (*(u8 *)(x + DOORBELL_TID_OFFSET))
#define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET))
-#define is_power_of_2(x) (((x) & ((x) - 1)) == 0)
-
struct rio_atmu_regs {
u32 rowtar;
u32 pad1;
diff --git a/arch/ppc/xmon/ppc-opc.c b/arch/ppc/xmon/ppc-opc.c
index 533a6c9973d..034313cef6e 100644
--- a/arch/ppc/xmon/ppc-opc.c
+++ b/arch/ppc/xmon/ppc-opc.c
@@ -19,6 +19,7 @@ along with this file; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <linux/posix_types.h>
+#include <linux/kernel.h>
#include "ansidecl.h"
#include "ppc.h"
@@ -2669,8 +2670,7 @@ const struct powerpc_opcode powerpc_opcodes[] = {
};
-const int powerpc_num_opcodes =
- sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
+const int powerpc_num_opcodes = ARRAY_SIZE(powerpc_opcodes);
/* The macro table. This is only used by the assembler. */
@@ -2717,5 +2717,4 @@ const struct powerpc_macro powerpc_macros[] = {
};
-const int powerpc_num_macros =
- sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
+const int powerpc_num_macros = ARRAY_SIZE(powerpc_macros);
diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c
index d74a883e5bd..8f0b953179f 100644
--- a/arch/ppc/xmon/start.c
+++ b/arch/ppc/xmon/start.c
@@ -58,10 +58,7 @@ static struct sysrq_key_op sysrq_xmon_op =
void
xmon_map_scc(void)
{
-#if defined(CONFIG_GEMINI)
- /* should already be mapped by the kernel boot */
- sccd = (volatile unsigned char *) 0xffeffb08;
-#elif defined(CONFIG_405GP)
+#if defined(CONFIG_405GP)
sccd = (volatile unsigned char *)0xef600300;
#elif defined(CONFIG_440EP)
sccd = (volatile unsigned char *) ioremap(PPC440EP_UART0_ADDR, 8);
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 583d9ff0a57..eaed402ad34 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -22,11 +22,15 @@ config RWSEM_XCHGADD_ALGORITHM
bool
default y
-config GENERIC_HWEIGHT
+config ARCH_HAS_ILOG2_U32
bool
- default y
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
-config GENERIC_CALIBRATE_DELAY
+config GENERIC_HWEIGHT
bool
default y
@@ -126,6 +130,31 @@ config AUDIT_ARCH
bool
default y
+config S390_SWITCH_AMODE
+ bool "Switch kernel/user addressing modes"
+ help
+ This option allows to switch the addressing modes of kernel and user
+ space. The kernel parameter switch_amode=on will enable this feature,
+ default is disabled. Enabling this (via kernel parameter) on machines
+ earlier than IBM System z9-109 EC/BC will reduce system performance.
+
+ Note that this option will also be selected by selecting the execute
+ protection option below. Enabling the execute protection via the
+ noexec kernel parameter will also switch the addressing modes,
+ independent of the switch_amode kernel parameter.
+
+
+config S390_EXEC_PROTECT
+ bool "Data execute protection"
+ select S390_SWITCH_AMODE
+ help
+ This option allows to enable a buffer overflow protection for user
+ space programs and it also selects the addressing mode option above.
+ The kernel parameter noexec=on will enable this feature and also
+ switch the addressing modes, default is disabled. Enabling this (via
+ kernel parameter) on machines earlier than IBM System z9-109 EC/BC
+ will reduce system performance.
+
comment "Code generation options"
choice
@@ -233,8 +262,14 @@ 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"
+config HOLES_IN_ZONE
+ def_bool y
+
comment "I/O subsystem configuration"
config MACHCHK_WARNING
@@ -258,14 +293,6 @@ config QDIO
If unsure, say Y.
-config QDIO_PERF_STATS
- bool "Performance statistics in /proc"
- depends on QDIO
- help
- Say Y here to get performance statistics in /proc/qdio_perf
-
- If unsure, say N.
-
config QDIO_DEBUG
bool "Extended debugging information"
depends on QDIO
@@ -401,7 +428,7 @@ config APPLDATA_BASE
config APPLDATA_MEM
tristate "Monitor memory management statistics"
- depends on APPLDATA_BASE
+ depends on APPLDATA_BASE && VM_EVENT_COUNTERS
help
This provides memory management related data to the Linux - VM Monitor
Stream, like paging/swapping rate, memory utilisation, etc.
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index b8c23729026..c9da7d16145 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -81,7 +81,7 @@ static struct ctl_table appldata_dir_table[] = {
/*
* Timer
*/
-DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
+static DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
static atomic_t appldata_expire_count = ATOMIC_INIT(0);
static DEFINE_SPINLOCK(appldata_timer_lock);
diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c
index 8aea3698a77..4ca61578870 100644
--- a/arch/s390/appldata/appldata_mem.c
+++ b/arch/s390/appldata/appldata_mem.c
@@ -36,7 +36,7 @@
* book:
* http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
*/
-struct appldata_mem_data {
+static struct appldata_mem_data {
u64 timestamp;
u32 sync_count_1; /* after VM collected the record data, */
u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
index 075e619bf37..f64b8c867ae 100644
--- a/arch/s390/appldata/appldata_net_sum.c
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -34,7 +34,7 @@
* book:
* http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
*/
-struct appldata_net_sum_data {
+static struct appldata_net_sum_data {
u64 timestamp;
u32 sync_count_1; /* after VM collected the record data, */
u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
diff --git a/arch/s390/crypto/Kconfig b/arch/s390/crypto/Kconfig
new file mode 100644
index 00000000000..99ff9f08e4d
--- /dev/null
+++ b/arch/s390/crypto/Kconfig
@@ -0,0 +1,60 @@
+config CRYPTO_SHA1_S390
+ tristate "SHA1 digest algorithm"
+ depends on S390
+ select CRYPTO_ALGAPI
+ help
+ This is the s390 hardware accelerated implementation of the
+ SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+config CRYPTO_SHA256_S390
+ tristate "SHA256 digest algorithm"
+ depends on S390
+ select CRYPTO_ALGAPI
+ help
+ This is the s390 hardware accelerated implementation of the
+ SHA256 secure hash standard (DFIPS 180-2).
+
+ This version of SHA implements a 256 bit hash with 128 bits of
+ security against collision attacks.
+
+config CRYPTO_DES_S390
+ tristate "DES and Triple DES cipher algorithms"
+ depends on S390
+ select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
+ help
+ This us the s390 hardware accelerated implementation of the
+ DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+config CRYPTO_AES_S390
+ tristate "AES cipher algorithms"
+ depends on S390
+ select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
+ help
+ This is the s390 hardware accelerated implementation of the
+ AES cipher algorithms (FIPS-197). AES uses the Rijndael
+ algorithm.
+
+ Rijndael appears to be consistently a very good performer in
+ both hardware and software across a wide range of computing
+ environments regardless of its use in feedback or non-feedback
+ modes. Its key setup time is excellent, and its key agility is
+ good. Rijndael's very low memory requirements make it very well
+ suited for restricted-space environments, in which it also
+ demonstrates excellent performance. Rijndael's operations are
+ among the easiest to defend against power and timing attacks.
+
+ On s390 the System z9-109 currently only supports the key size
+ of 128 bit.
+
+config S390_PRNG
+ tristate "Pseudo random number generator device driver"
+ depends on S390
+ default "m"
+ help
+ Select this option if you want to use the s390 pseudo random number
+ generator. The PRNG is part of the cryptograhic processor functions
+ and uses triple-DES to generate secure random numbers like the
+ ANSI X9.17 standard. The PRNG is usable via the char device
+ /dev/prandom.
diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile
index bfe2541dc5c..14e552c5cc4 100644
--- a/arch/s390/crypto/Makefile
+++ b/arch/s390/crypto/Makefile
@@ -6,5 +6,4 @@ obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o
obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o
obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o
obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
-
-obj-$(CONFIG_CRYPTO_TEST) += crypt_s390_query.o
+obj-$(CONFIG_S390_PRNG) += prng.o
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
index 15c9eec0292..91636353f6f 100644
--- a/arch/s390/crypto/aes_s390.c
+++ b/arch/s390/crypto/aes_s390.c
@@ -4,7 +4,7 @@
* s390 implementation of the AES Cipher Algorithm.
*
* s390 Version:
- * Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
+ * Copyright IBM Corp. 2005,2007
* Author(s): Jan Glauber (jang@de.ibm.com)
*
* Derived from "crypto/aes.c"
@@ -27,9 +27,11 @@
/* data block size for all key lengths */
#define AES_BLOCK_SIZE 16
-int has_aes_128 = 0;
-int has_aes_192 = 0;
-int has_aes_256 = 0;
+#define AES_KEYLEN_128 1
+#define AES_KEYLEN_192 2
+#define AES_KEYLEN_256 4
+
+static char keylen_flag = 0;
struct s390_aes_ctx {
u8 iv[AES_BLOCK_SIZE];
@@ -47,20 +49,19 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
switch (key_len) {
case 16:
- if (!has_aes_128)
+ if (!(keylen_flag & AES_KEYLEN_128))
goto fail;
break;
case 24:
- if (!has_aes_192)
+ if (!(keylen_flag & AES_KEYLEN_192))
goto fail;
break;
case 32:
- if (!has_aes_256)
+ if (!(keylen_flag & AES_KEYLEN_256))
goto fail;
break;
default:
- /* invalid key length */
goto fail;
break;
}
@@ -322,34 +323,32 @@ static int __init aes_init(void)
int ret;
if (crypt_s390_func_available(KM_AES_128_ENCRYPT))
- has_aes_128 = 1;
+ keylen_flag |= AES_KEYLEN_128;
if (crypt_s390_func_available(KM_AES_192_ENCRYPT))
- has_aes_192 = 1;
+ keylen_flag |= AES_KEYLEN_192;
if (crypt_s390_func_available(KM_AES_256_ENCRYPT))
- has_aes_256 = 1;
+ keylen_flag |= AES_KEYLEN_256;
+
+ if (!keylen_flag)
+ return -EOPNOTSUPP;
- if (!has_aes_128 && !has_aes_192 && !has_aes_256)
- return -ENOSYS;
+ /* z9 109 and z9 BC/EC only support 128 bit key length */
+ if (keylen_flag == AES_KEYLEN_128)
+ printk(KERN_INFO
+ "aes_s390: hardware acceleration only available for"
+ "128 bit keys\n");
ret = crypto_register_alg(&aes_alg);
- if (ret != 0) {
- printk(KERN_INFO "crypt_s390: aes-s390 couldn't be loaded.\n");
+ if (ret)
goto aes_err;
- }
ret = crypto_register_alg(&ecb_aes_alg);
- if (ret != 0) {
- printk(KERN_INFO
- "crypt_s390: ecb-aes-s390 couldn't be loaded.\n");
+ if (ret)
goto ecb_aes_err;
- }
ret = crypto_register_alg(&cbc_aes_alg);
- if (ret != 0) {
- printk(KERN_INFO
- "crypt_s390: cbc-aes-s390 couldn't be loaded.\n");
+ if (ret)
goto cbc_aes_err;
- }
out:
return ret;
diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h
index 2b137089f62..2775d261833 100644
--- a/arch/s390/crypto/crypt_s390.h
+++ b/arch/s390/crypto/crypt_s390.h
@@ -3,8 +3,9 @@
*
* Support for s390 cryptographic instructions.
*
- * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ * Copyright IBM Corp. 2003,2007
+ * Author(s): Thomas Spatzier
+ * Jan Glauber (jan.glauber@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
@@ -32,7 +33,8 @@ enum crypt_s390_operations {
CRYPT_S390_KMAC = 0x0500
};
-/* function codes for KM (CIPHER MESSAGE) instruction
+/*
+ * function codes for KM (CIPHER MESSAGE) instruction
* 0x80 is the decipher modifier bit
*/
enum crypt_s390_km_func {
@@ -51,7 +53,8 @@ enum crypt_s390_km_func {
KM_AES_256_DECRYPT = CRYPT_S390_KM | 0x14 | 0x80,
};
-/* function codes for KMC (CIPHER MESSAGE WITH CHAINING)
+/*
+ * function codes for KMC (CIPHER MESSAGE WITH CHAINING)
* instruction
*/
enum crypt_s390_kmc_func {
@@ -68,9 +71,11 @@ enum crypt_s390_kmc_func {
KMC_AES_192_DECRYPT = CRYPT_S390_KMC | 0x13 | 0x80,
KMC_AES_256_ENCRYPT = CRYPT_S390_KMC | 0x14,
KMC_AES_256_DECRYPT = CRYPT_S390_KMC | 0x14 | 0x80,
+ KMC_PRNG = CRYPT_S390_KMC | 0x43,
};
-/* function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
+/*
+ * function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
* instruction
*/
enum crypt_s390_kimd_func {
@@ -79,7 +84,8 @@ enum crypt_s390_kimd_func {
KIMD_SHA_256 = CRYPT_S390_KIMD | 2,
};
-/* function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
+/*
+ * function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
* instruction
*/
enum crypt_s390_klmd_func {
@@ -88,7 +94,8 @@ enum crypt_s390_klmd_func {
KLMD_SHA_256 = CRYPT_S390_KLMD | 2,
};
-/* function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
+/*
+ * function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
* instruction
*/
enum crypt_s390_kmac_func {
@@ -98,229 +105,219 @@ enum crypt_s390_kmac_func {
KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
};
-/* status word for s390 crypto instructions' QUERY functions */
-struct crypt_s390_query_status {
- u64 high;
- u64 low;
-};
-
-/*
+/**
+ * crypt_s390_km:
+ * @func: the function code passed to KM; see crypt_s390_km_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
* 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
- * @param dest: address of destination memory area
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * for encryption/decryption funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for encryption/decryption funcs
*/
-static inline int
-crypt_s390_km(long func, void* param, u8* dest, const u8* src, long src_len)
+static inline int 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 const u8* __src asm("2") = src;
+ register void *__param asm("1") = param;
+ register const u8 *__src asm("2") = src;
register long __src_len asm("3") = src_len;
- register u8* __dest asm("4") = dest;
+ register u8 *__dest asm("4") = dest;
int ret;
asm volatile(
"0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */
"1: brc 1,0b \n" /* handle partial completion */
- " ahi %0,%h7\n"
- "2: ahi %0,%h8\n"
- "3:\n"
- EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) 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");
+ : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0)
return ret;
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
}
-/*
+/**
+ * crypt_s390_kmc:
+ * @func: the function code passed to KM; see crypt_s390_kmc_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
* Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_kmc_func
- * @param param: address of parameter block; see POP for details on each func
- * @param dest: address of destination memory area
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * for encryption/decryption funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for encryption/decryption funcs
*/
-static inline int
-crypt_s390_kmc(long func, void* param, u8* dest, const u8* src, long src_len)
+static inline int 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 const u8* __src asm("2") = src;
+ register void *__param asm("1") = param;
+ register const u8 *__src asm("2") = src;
register long __src_len asm("3") = src_len;
- register u8* __dest asm("4") = dest;
+ register u8 *__dest asm("4") = dest;
int ret;
asm volatile(
"0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
"1: brc 1,0b \n" /* handle partial completion */
- " ahi %0,%h7\n"
- "2: ahi %0,%h8\n"
- "3:\n"
- EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) 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");
+ : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0)
return ret;
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
}
-/*
+/**
+ * crypt_s390_kimd:
+ * @func: the function code passed to KM; see crypt_s390_kimd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
* Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation
* of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_kimd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * for digest funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
*/
-static inline int
-crypt_s390_kimd(long func, void* param, const u8* src, long src_len)
+static inline int crypt_s390_kimd(long func, void *param,
+ const u8 *src, long src_len)
{
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
- register void* __param asm("1") = param;
- register const u8* __src asm("2") = src;
+ register void *__param asm("1") = param;
+ register const u8 *__src asm("2") = src;
register long __src_len asm("3") = src_len;
int 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)
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len)
- : "d" (__func), "a" (__param), "0" (-EFAULT),
- "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+ : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0)
return ret;
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
}
-/*
+/**
+ * crypt_s390_klmd:
+ * @func: the function code passed to KM; see crypt_s390_klmd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
* Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_klmd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * for digest funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
*/
-static inline int
-crypt_s390_klmd(long func, void* param, const u8* src, long src_len)
+static inline int crypt_s390_klmd(long func, void *param,
+ const u8 *src, long src_len)
{
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
- register void* __param asm("1") = param;
- register const u8* __src asm("2") = src;
+ register void *__param asm("1") = param;
+ register const u8 *__src asm("2") = src;
register long __src_len asm("3") = src_len;
int 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)
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len)
- : "d" (__func), "a" (__param), "0" (-EFAULT),
- "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+ : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0)
return ret;
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
}
-/*
+/**
+ * crypt_s390_kmac:
+ * @func: the function code passed to KM; see crypt_s390_klmd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
* Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation
* of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_klmd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * for digest funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
*/
-static inline int
-crypt_s390_kmac(long func, void* param, const u8* src, long src_len)
+static inline int crypt_s390_kmac(long func, void *param,
+ const u8 *src, long src_len)
{
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
- register void* __param asm("1") = param;
- register const u8* __src asm("2") = src;
+ register void *__param asm("1") = param;
+ register const u8 *__src asm("2") = src;
register long __src_len asm("3") = src_len;
int 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)
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len)
- : "d" (__func), "a" (__param), "0" (-EFAULT),
- "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+ : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0)
return ret;
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
}
/**
+ * crypt_s390_func_available:
+ * @func: the function code of the specific function; 0 if op in general
+ *
* Tests if a specific crypto function is implemented on the machine.
- * @param func: the function code of the specific function; 0 if op in general
- * @return 1 if func available; 0 if func or op in general not available
+ *
+ * Returns 1 if func available; 0 if func or op in general not available
*/
-static inline int
-crypt_s390_func_available(int func)
+static inline int crypt_s390_func_available(int func)
{
+ unsigned char status[16];
int ret;
- struct crypt_s390_query_status status = {
- .high = 0,
- .low = 0
- };
- switch (func & CRYPT_S390_OP_MASK){
- case CRYPT_S390_KM:
- ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
- break;
- case CRYPT_S390_KMC:
- ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
- break;
- case CRYPT_S390_KIMD:
- ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
- break;
- case CRYPT_S390_KLMD:
- ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
- break;
- case CRYPT_S390_KMAC:
- ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
- break;
- default:
- ret = 0;
- return ret;
- }
- if (ret >= 0){
- func &= CRYPT_S390_FUNC_MASK;
- func &= 0x7f; //mask modifier bit
- if (func < 64){
- ret = (status.high >> (64 - func - 1)) & 0x1;
- } else {
- ret = (status.low >> (128 - func - 1)) & 0x1;
- }
- } else {
- ret = 0;
+ switch (func & CRYPT_S390_OP_MASK) {
+ case CRYPT_S390_KM:
+ ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
+ break;
+ case CRYPT_S390_KMC:
+ ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
+ break;
+ case CRYPT_S390_KIMD:
+ ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
+ break;
+ case CRYPT_S390_KLMD:
+ ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
+ break;
+ case CRYPT_S390_KMAC:
+ ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
+ break;
+ default:
+ return 0;
}
- return ret;
+ if (ret < 0)
+ return 0;
+ func &= CRYPT_S390_FUNC_MASK;
+ func &= 0x7f; /* mask modifier bit */
+ return (status[func >> 3] & (0x80 >> (func & 7))) != 0;
}
-#endif // _CRYPTO_ARCH_S390_CRYPT_S390_H
+#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */
diff --git a/arch/s390/crypto/crypt_s390_query.c b/arch/s390/crypto/crypt_s390_query.c
deleted file mode 100644
index 54fb11d7fad..00000000000
--- a/arch/s390/crypto/crypt_s390_query.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Support for s390 cryptographic instructions.
- * Testing module for querying processor crypto capabilities.
- *
- * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@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 of the License, or (at your option)
- * any later version.
- *
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/errno.h>
-#include "crypt_s390.h"
-
-static void query_available_functions(void)
-{
- printk(KERN_INFO "#####################\n");
-
- /* query available KM functions */
- printk(KERN_INFO "KM_QUERY: %d\n",
- crypt_s390_func_available(KM_QUERY));
- printk(KERN_INFO "KM_DEA: %d\n",
- crypt_s390_func_available(KM_DEA_ENCRYPT));
- printk(KERN_INFO "KM_TDEA_128: %d\n",
- crypt_s390_func_available(KM_TDEA_128_ENCRYPT));
- printk(KERN_INFO "KM_TDEA_192: %d\n",
- crypt_s390_func_available(KM_TDEA_192_ENCRYPT));
- printk(KERN_INFO "KM_AES_128: %d\n",
- crypt_s390_func_available(KM_AES_128_ENCRYPT));
- printk(KERN_INFO "KM_AES_192: %d\n",
- crypt_s390_func_available(KM_AES_192_ENCRYPT));
- printk(KERN_INFO "KM_AES_256: %d\n",
- crypt_s390_func_available(KM_AES_256_ENCRYPT));
-
- /* query available KMC functions */
- printk(KERN_INFO "KMC_QUERY: %d\n",
- crypt_s390_func_available(KMC_QUERY));
- printk(KERN_INFO "KMC_DEA: %d\n",
- crypt_s390_func_available(KMC_DEA_ENCRYPT));
- printk(KERN_INFO "KMC_TDEA_128: %d\n",
- crypt_s390_func_available(KMC_TDEA_128_ENCRYPT));
- printk(KERN_INFO "KMC_TDEA_192: %d\n",
- crypt_s390_func_available(KMC_TDEA_192_ENCRYPT));
- printk(KERN_INFO "KMC_AES_128: %d\n",
- crypt_s390_func_available(KMC_AES_128_ENCRYPT));
- printk(KERN_INFO "KMC_AES_192: %d\n",
- crypt_s390_func_available(KMC_AES_192_ENCRYPT));
- printk(KERN_INFO "KMC_AES_256: %d\n",
- crypt_s390_func_available(KMC_AES_256_ENCRYPT));
-
- /* query available KIMD functions */
- printk(KERN_INFO "KIMD_QUERY: %d\n",
- crypt_s390_func_available(KIMD_QUERY));
- printk(KERN_INFO "KIMD_SHA_1: %d\n",
- crypt_s390_func_available(KIMD_SHA_1));
- printk(KERN_INFO "KIMD_SHA_256: %d\n",
- crypt_s390_func_available(KIMD_SHA_256));
-
- /* query available KLMD functions */
- printk(KERN_INFO "KLMD_QUERY: %d\n",
- crypt_s390_func_available(KLMD_QUERY));
- printk(KERN_INFO "KLMD_SHA_1: %d\n",
- crypt_s390_func_available(KLMD_SHA_1));
- printk(KERN_INFO "KLMD_SHA_256: %d\n",
- crypt_s390_func_available(KLMD_SHA_256));
-
- /* query available KMAC functions */
- printk(KERN_INFO "KMAC_QUERY: %d\n",
- crypt_s390_func_available(KMAC_QUERY));
- printk(KERN_INFO "KMAC_DEA: %d\n",
- crypt_s390_func_available(KMAC_DEA));
- printk(KERN_INFO "KMAC_TDEA_128: %d\n",
- crypt_s390_func_available(KMAC_TDEA_128));
- printk(KERN_INFO "KMAC_TDEA_192: %d\n",
- crypt_s390_func_available(KMAC_TDEA_192));
-}
-
-static int init(void)
-{
- struct crypt_s390_query_status status = {
- .high = 0,
- .low = 0
- };
-
- printk(KERN_INFO "crypt_s390: querying available crypto functions\n");
- crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
- printk(KERN_INFO "KM:\t%016llx %016llx\n",
- (unsigned long long) status.high,
- (unsigned long long) status.low);
- status.high = status.low = 0;
- crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
- printk(KERN_INFO "KMC:\t%016llx %016llx\n",
- (unsigned long long) status.high,
- (unsigned long long) status.low);
- status.high = status.low = 0;
- crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
- printk(KERN_INFO "KIMD:\t%016llx %016llx\n",
- (unsigned long long) status.high,
- (unsigned long long) status.low);
- status.high = status.low = 0;
- crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
- printk(KERN_INFO "KLMD:\t%016llx %016llx\n",
- (unsigned long long) status.high,
- (unsigned long long) status.low);
- status.high = status.low = 0;
- crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
- printk(KERN_INFO "KMAC:\t%016llx %016llx\n",
- (unsigned long long) status.high,
- (unsigned long long) status.low);
-
- query_available_functions();
- return -ECANCELED;
-}
-
-static void __exit cleanup(void)
-{
-}
-
-module_init(init);
-module_exit(cleanup);
-
-MODULE_LICENSE("GPL");
diff --git a/arch/s390/crypto/des_check_key.c b/arch/s390/crypto/des_check_key.c
index e3f5c5f238f..5706af26644 100644
--- a/arch/s390/crypto/des_check_key.c
+++ b/arch/s390/crypto/des_check_key.c
@@ -10,8 +10,9 @@
* scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL.
*
* s390 Version:
- * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ * Copyright IBM Corp. 2003
+ * Author(s): Thomas Spatzier
+ * Jan Glauber (jan.glauber@de.ibm.com)
*
* Derived from "crypto/des.c"
* Copyright (c) 1992 Dana L. How.
@@ -30,6 +31,7 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/crypto.h>
+#include "crypto_des.h"
#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o))
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c
index 2aba04852fe..ea22707f435 100644
--- a/arch/s390/crypto/des_s390.c
+++ b/arch/s390/crypto/des_s390.c
@@ -3,9 +3,9 @@
*
* s390 implementation of the DES Cipher Algorithm.
*
- * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
- *
+ * Copyright IBM Corp. 2003,2007
+ * Author(s): Thomas Spatzier
+ * Jan Glauber (jan.glauber@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
@@ -557,7 +557,7 @@ static int init(void)
if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
!crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
!crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
- return -ENOSYS;
+ return -EOPNOTSUPP;
ret = crypto_register_alg(&des_alg);
if (ret)
diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c
new file mode 100644
index 00000000000..8eb3a1aedc2
--- /dev/null
+++ b/arch/s390/crypto/prng.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright IBM Corp. 2006,2007
+ * Author(s): Jan Glauber <jan.glauber@de.ibm.com>
+ * Driver for the s390 pseudo random number generator
+ */
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/random.h>
+#include <asm/debug.h>
+#include <asm/uaccess.h>
+
+#include "crypt_s390.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jan Glauber <jan.glauber@de.ibm.com>");
+MODULE_DESCRIPTION("s390 PRNG interface");
+
+static int prng_chunk_size = 256;
+module_param(prng_chunk_size, int, S_IRUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes");
+
+static int prng_entropy_limit = 4096;
+module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
+MODULE_PARM_DESC(prng_entropy_limit,
+ "PRNG add entropy after that much bytes were produced");
+
+/*
+ * Any one who considers arithmetical methods of producing random digits is,
+ * of course, in a state of sin. -- John von Neumann
+ */
+
+struct s390_prng_data {
+ unsigned long count; /* how many bytes were produced */
+ char *buf;
+};
+
+static struct s390_prng_data *p;
+
+/* copied from libica, use a non-zero initial parameter block */
+static unsigned char parm_block[32] = {
+0x0F,0x2B,0x8E,0x63,0x8C,0x8E,0xD2,0x52,0x64,0xB7,0xA0,0x7B,0x75,0x28,0xB8,0xF4,
+0x75,0x5F,0xD2,0xA6,0x8D,0x97,0x11,0xFF,0x49,0xD8,0x23,0xF3,0x7E,0x21,0xEC,0xA0,
+};
+
+static int prng_open(struct inode *inode, struct file *file)
+{
+ return nonseekable_open(inode, file);
+}
+
+static void prng_add_entropy(void)
+{
+ __u64 entropy[4];
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < 16; i++) {
+ ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy,
+ (char *)entropy, sizeof(entropy));
+ BUG_ON(ret < 0 || ret != sizeof(entropy));
+ memcpy(parm_block, entropy, sizeof(entropy));
+ }
+}
+
+static void prng_seed(int nbytes)
+{
+ char buf[16];
+ int i = 0;
+
+ BUG_ON(nbytes > 16);
+ get_random_bytes(buf, nbytes);
+
+ /* Add the entropy */
+ while (nbytes >= 8) {
+ *((__u64 *)parm_block) ^= *((__u64 *)buf+i*8);
+ prng_add_entropy();
+ i += 8;
+ nbytes -= 8;
+ }
+ prng_add_entropy();
+}
+
+static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
+ loff_t *ppos)
+{
+ int chunk, n;
+ int ret = 0;
+ int tmp;
+
+ /* nbytes can be arbitrary long, we spilt it into chunks */
+ while (nbytes) {
+ /* same as in extract_entropy_user in random.c */
+ if (need_resched()) {
+ if (signal_pending(current)) {
+ if (ret == 0)
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+
+ /*
+ * we lose some random bytes if an attacker issues
+ * reads < 8 bytes, but we don't care
+ */
+ chunk = min_t(int, nbytes, prng_chunk_size);
+
+ /* PRNG only likes multiples of 8 bytes */
+ n = (chunk + 7) & -8;
+
+ if (p->count > prng_entropy_limit)
+ prng_seed(8);
+
+ /* if the CPU supports PRNG stckf is present too */
+ asm volatile(".insn s,0xb27c0000,%0"
+ : "=m" (*((unsigned long long *)p->buf)) : : "cc");
+
+ /*
+ * Beside the STCKF the input for the TDES-EDE is the output
+ * of the last operation. We differ here from X9.17 since we
+ * only store one timestamp into the buffer. Padding the whole
+ * buffer with timestamps does not improve security, since
+ * successive stckf have nearly constant offsets.
+ * If an attacker knows the first timestamp it would be
+ * trivial to guess the additional values. One timestamp
+ * is therefore enough and still guarantees unique input values.
+ *
+ * Note: you can still get strict X9.17 conformity by setting
+ * prng_chunk_size to 8 bytes.
+ */
+ tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n);
+ BUG_ON((tmp < 0) || (tmp != n));
+
+ p->count += n;
+
+ if (copy_to_user(ubuf, p->buf, chunk))
+ return -EFAULT;
+
+ nbytes -= chunk;
+ ret += chunk;
+ ubuf += chunk;
+ }
+ return ret;
+}
+
+static struct file_operations prng_fops = {
+ .owner = THIS_MODULE,
+ .open = &prng_open,
+ .release = NULL,
+ .read = &prng_read,
+};
+
+static struct miscdevice prng_dev = {
+ .name = "prandom",
+ .minor = MISC_DYNAMIC_MINOR,
+ .fops = &prng_fops,
+};
+
+static int __init prng_init(void)
+{
+ int ret;
+
+ /* check if the CPU has a PRNG */
+ if (!crypt_s390_func_available(KMC_PRNG))
+ return -EOPNOTSUPP;
+
+ if (prng_chunk_size < 8)
+ return -EINVAL;
+
+ p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+ p->count = 0;
+
+ p->buf = kmalloc(prng_chunk_size, GFP_KERNEL);
+ if (!p->buf) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ /* initialize the PRNG, add 128 bits of entropy */
+ prng_seed(16);
+
+ ret = misc_register(&prng_dev);
+ if (ret) {
+ printk(KERN_WARNING
+ "Could not register misc device for PRNG.\n");
+ goto out_buf;
+ }
+ return 0;
+
+out_buf:
+ kfree(p->buf);
+out_free:
+ kfree(p);
+ return ret;
+}
+
+static void __exit prng_exit(void)
+{
+ /* wipe me */
+ memset(p->buf, 0, prng_chunk_size);
+ kfree(p->buf);
+ kfree(p);
+
+ misc_deregister(&prng_dev);
+}
+
+module_init(prng_init);
+module_exit(prng_exit);
diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c
index 49ca8690ee3..969639f3197 100644
--- a/arch/s390/crypto/sha1_s390.c
+++ b/arch/s390/crypto/sha1_s390.c
@@ -8,8 +8,9 @@
* implementation written by Steve Reid.
*
* s390 Version:
- * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ * Copyright IBM Corp. 2003,2007
+ * Author(s): Thomas Spatzier
+ * Jan Glauber (jan.glauber@de.ibm.com)
*
* Derived from "crypto/sha1.c"
* Copyright (c) Alan Smithee.
@@ -43,16 +44,14 @@ struct crypt_s390_sha1_ctx {
static void sha1_init(struct crypto_tfm *tfm)
{
struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm);
- static const u32 initstate[5] = {
- 0x67452301,
- 0xEFCDAB89,
- 0x98BADCFE,
- 0x10325476,
- 0xC3D2E1F0
- };
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
ctx->count = 0;
- memcpy(ctx->state, &initstate, sizeof(initstate));
ctx->buf_len = 0;
}
@@ -63,13 +62,13 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
long imd_len;
sctx = crypto_tfm_ctx(tfm);
- sctx->count += len * 8; //message bit length
+ sctx->count += len * 8; /* message bit length */
- //anything in buffer yet? -> must be completed
+ /* anything in buffer yet? -> must be completed */
if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) {
- //complete full block and hash
+ /* complete full block and hash */
memcpy(sctx->buffer + sctx->buf_len, data,
- SHA1_BLOCK_SIZE - sctx->buf_len);
+ SHA1_BLOCK_SIZE - sctx->buf_len);
crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer,
SHA1_BLOCK_SIZE);
data += SHA1_BLOCK_SIZE - sctx->buf_len;
@@ -77,37 +76,36 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
sctx->buf_len = 0;
}
- //rest of data contains full blocks?
+ /* rest of data contains full blocks? */
imd_len = len & ~0x3ful;
- if (imd_len){
+ if (imd_len) {
crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len);
data += imd_len;
len -= imd_len;
}
- //anything left? store in buffer
- if (len){
+ /* anything left? store in buffer */
+ if (len) {
memcpy(sctx->buffer + sctx->buf_len , data, len);
sctx->buf_len += len;
}
}
-static void
-pad_message(struct crypt_s390_sha1_ctx* sctx)
+static void pad_message(struct crypt_s390_sha1_ctx* sctx)
{
int index;
index = sctx->buf_len;
- sctx->buf_len = (sctx->buf_len < 56)?
- SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
- //start pad with 1
+ sctx->buf_len = (sctx->buf_len < 56) ?
+ SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
+ /* start pad with 1 */
sctx->buffer[index] = 0x80;
- //pad with zeros
+ /* pad with zeros */
index++;
memset(sctx->buffer + index, 0x00, sctx->buf_len - index);
- //append length
+ /* append length */
memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count,
- sizeof sctx->count);
+ sizeof sctx->count);
}
/* Add padding and return the message digest. */
@@ -115,47 +113,40 @@ static void sha1_final(struct crypto_tfm *tfm, u8 *out)
{
struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
- //must perform manual padding
+ /* must perform manual padding */
pad_message(sctx);
crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len);
- //copy digest to out
+ /* copy digest to out */
memcpy(out, sctx->state, SHA1_DIGEST_SIZE);
- /* Wipe context */
+ /* wipe context */
memset(sctx, 0, sizeof *sctx);
}
static struct crypto_alg alg = {
.cra_name = "sha1",
- .cra_driver_name = "sha1-s390",
+ .cra_driver_name= "sha1-s390",
.cra_priority = CRYPT_S390_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypt_s390_sha1_ctx),
.cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(alg.cra_list),
+ .cra_list = LIST_HEAD_INIT(alg.cra_list),
.cra_u = { .digest = {
.dia_digestsize = SHA1_DIGEST_SIZE,
- .dia_init = sha1_init,
- .dia_update = sha1_update,
- .dia_final = sha1_final } }
+ .dia_init = sha1_init,
+ .dia_update = sha1_update,
+ .dia_final = sha1_final } }
};
-static int
-init(void)
+static int __init init(void)
{
- int ret = -ENOSYS;
+ if (!crypt_s390_func_available(KIMD_SHA_1))
+ return -EOPNOTSUPP;
- if (crypt_s390_func_available(KIMD_SHA_1)){
- ret = crypto_register_alg(&alg);
- if (ret == 0){
- printk(KERN_INFO "crypt_s390: sha1_s390 loaded.\n");
- }
- }
- return ret;
+ return crypto_register_alg(&alg);
}
-static void __exit
-fini(void)
+static void __exit fini(void)
{
crypto_unregister_alg(&alg);
}
diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c
index 8e4e67503fe..78436c696d3 100644
--- a/arch/s390/crypto/sha256_s390.c
+++ b/arch/s390/crypto/sha256_s390.c
@@ -4,7 +4,7 @@
* s390 implementation of the SHA256 Secure Hash Algorithm.
*
* s390 Version:
- * Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
+ * Copyright IBM Corp. 2005,2007
* Author(s): Jan Glauber (jang@de.ibm.com)
*
* Derived from "crypto/sha256.c"
@@ -143,15 +143,10 @@ static struct crypto_alg alg = {
static int init(void)
{
- int ret;
-
if (!crypt_s390_func_available(KIMD_SHA_256))
- return -ENOSYS;
+ return -EOPNOTSUPP;
- ret = crypto_register_alg(&alg);
- if (ret != 0)
- printk(KERN_INFO "crypt_s390: sha256_s390 couldn't be loaded.");
- return ret;
+ return crypto_register_alg(&alg);
}
static void __exit fini(void)
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 7cd51e73e27..1406400bf3e 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -1,14 +1,15 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc2
-# Wed Oct 18 17:11:10 2006
+# Linux kernel version: 2.6.20-rc1
+# Fri Dec 15 16:52:28 2006
#
CONFIG_MMU=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_TIME=y
CONFIG_S390=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -37,12 +38,13 @@ CONFIG_AUDIT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_CPUSETS is not set
+CONFIG_SYSFS_DEPRECATED=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_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -106,6 +108,8 @@ CONFIG_DEFAULT_MIGRATION_COST=1000000
CONFIG_COMPAT=y
CONFIG_SYSVIPC_COMPAT=y
CONFIG_AUDIT_ARCH=y
+CONFIG_S390_SWITCH_AMODE=y
+CONFIG_S390_EXEC_PROTECT=y
#
# Code generation options
@@ -119,6 +123,7 @@ CONFIG_PACK_STACK=y
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
@@ -128,13 +133,13 @@ CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_RESOURCES_64BIT=y
+CONFIG_HOLES_IN_ZONE=y
#
# I/O subsystem configuration
#
CONFIG_MACHCHK_WARNING=y
CONFIG_QDIO=y
-# CONFIG_QDIO_PERF_STATS is not set
# CONFIG_QDIO_DEBUG is not set
#
@@ -174,6 +179,8 @@ CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_NET_KEY=y
+CONFIG_IUCV=m
+CONFIG_AFIUCV=m
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
@@ -197,6 +204,7 @@ CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
CONFIG_IPV6=y
# CONFIG_IPV6_PRIVACY is not set
# CONFIG_IPV6_ROUTER_PREF is not set
@@ -212,7 +220,6 @@ 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
@@ -247,6 +254,7 @@ CONFIG_IPV6_SIT=y
# QoS and/or fair queueing
#
CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_FIFO=y
CONFIG_NET_SCH_CLK_JIFFIES=y
# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
# CONFIG_NET_SCH_CLK_CPU is not set
@@ -278,6 +286,7 @@ 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=y
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
# CONFIG_NET_EMATCH is not set
@@ -316,6 +325,7 @@ CONFIG_SYS_HYPERVISOR=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
@@ -336,6 +346,7 @@ CONFIG_CHR_DEV_SG=y
CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
#
# SCSI Transports
@@ -424,7 +435,6 @@ CONFIG_TN3270_CONSOLE=y
CONFIG_TN3215=y
CONFIG_TN3215_CONSOLE=y
CONFIG_CCW_CONSOLE=y
-CONFIG_SCLP=y
CONFIG_SCLP_TTY=y
CONFIG_SCLP_CONSOLE=y
CONFIG_SCLP_VT220_TTY=y
@@ -500,7 +510,6 @@ CONFIG_NET_ETHERNET=y
#
CONFIG_LCS=m
CONFIG_CTC=m
-CONFIG_IUCV=m
# CONFIG_NETIUCV is not set
# CONFIG_SMSGIUCV is not set
# CONFIG_CLAW is not set
@@ -547,6 +556,7 @@ CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
#
# CD-ROM/DVD Filesystems
@@ -572,7 +582,7 @@ 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=m
#
# Miscellaneous filesystems
@@ -617,7 +627,6 @@ 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
@@ -647,6 +656,14 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+CONFIG_DLM=m
+CONFIG_DLM_TCP=y
+# CONFIG_DLM_SCTP is not set
+# CONFIG_DLM_DEBUG is not set
+
+#
# Instrumentation Support
#
@@ -664,6 +681,8 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_CHECK=y
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=17
# CONFIG_SCHEDSTATS is not set
@@ -680,13 +699,11 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT 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 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
@@ -700,29 +717,28 @@ CONFIG_HEADERS_CHECK=y
# Cryptographic options
#
CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=m
-CONFIG_CRYPTO_BLKCIPHER=m
-CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA1_S390 is not set
# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA256_S390 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
# CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_DES_S390 is not set
# 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_AES_S390 is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
# CONFIG_CRYPTO_TEA is not set
@@ -737,12 +753,19 @@ CONFIG_CRYPTO_CBC=m
#
# Hardware crypto devices
#
+# CONFIG_CRYPTO_SHA1_S390 is not set
+# CONFIG_CRYPTO_SHA256_S390 is not set
+# CONFIG_CRYPTO_DES_S390 is not set
+# CONFIG_CRYPTO_AES_S390 is not set
+CONFIG_S390_PRNG=m
#
# Library routines
#
+CONFIG_BITREVERSE=m
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=m
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile
index f4b00cd81f7..b08d2abf617 100644
--- a/arch/s390/hypfs/Makefile
+++ b/arch/s390/hypfs/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
-s390_hypfs-objs := inode.o hypfs_diag.o
+s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o
diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h
index f3dbd91965c..aea572009d6 100644
--- a/arch/s390/hypfs/hypfs.h
+++ b/arch/s390/hypfs/hypfs.h
@@ -27,4 +27,13 @@ extern struct dentry *hypfs_create_str(struct super_block *sb,
struct dentry *dir, const char *name,
char *string);
+/* LPAR Hypervisor */
+extern int hypfs_diag_init(void);
+extern void hypfs_diag_exit(void);
+extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
+
+/* VM Hypervisor */
+extern int hypfs_vm_init(void);
+extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root);
+
#endif /* _HYPFS_H_ */
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c
index 443fa377d9f..2782cf9da5b 100644
--- a/arch/s390/hypfs/hypfs_diag.c
+++ b/arch/s390/hypfs/hypfs_diag.c
@@ -379,7 +379,7 @@ static void *diag204_alloc_vbuf(int pages)
static void *diag204_alloc_rbuf(void)
{
diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0);
- if (diag204_buf)
+ if (!diag204_buf)
return ERR_PTR(-ENOMEM);
diag204_buf_pages = 1;
return diag204_buf;
@@ -521,7 +521,7 @@ __init int hypfs_diag_init(void)
}
rc = diag224_get_name_table();
if (rc) {
- diag224_delete_name_table();
+ diag204_free_buffer();
printk(KERN_ERR "hypfs: could not get name table.\n");
}
return rc;
diff --git a/arch/s390/hypfs/hypfs_diag.h b/arch/s390/hypfs/hypfs_diag.h
deleted file mode 100644
index 256b384aebe..00000000000
--- a/arch/s390/hypfs/hypfs_diag.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * arch/s390/hypfs_diag.h
- * Hypervisor filesystem for Linux on s390.
- *
- * Copyright (C) IBM Corp. 2006
- * Author(s): Michael Holzheu <holzheu@de.ibm.com>
- */
-
-#ifndef _HYPFS_DIAG_H_
-#define _HYPFS_DIAG_H_
-
-extern int hypfs_diag_init(void);
-extern void hypfs_diag_exit(void);
-extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
-
-#endif /* _HYPFS_DIAG_H_ */
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c
new file mode 100644
index 00000000000..d01fc8f799f
--- /dev/null
+++ b/arch/s390/hypfs/hypfs_vm.c
@@ -0,0 +1,231 @@
+/*
+ * Hypervisor filesystem for Linux on s390. z/VM implementation.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <asm/ebcdic.h>
+#include "hypfs.h"
+
+#define NAME_LEN 8
+
+static char local_guest[] = " ";
+static char all_guests[] = "* ";
+static char *guest_query;
+
+struct diag2fc_data {
+ __u32 version;
+ __u32 flags;
+ __u64 used_cpu;
+ __u64 el_time;
+ __u64 mem_min_kb;
+ __u64 mem_max_kb;
+ __u64 mem_share_kb;
+ __u64 mem_used_kb;
+ __u32 pcpus;
+ __u32 lcpus;
+ __u32 vcpus;
+ __u32 cpu_min;
+ __u32 cpu_max;
+ __u32 cpu_shares;
+ __u32 cpu_use_samp;
+ __u32 cpu_delay_samp;
+ __u32 page_wait_samp;
+ __u32 idle_samp;
+ __u32 other_samp;
+ __u32 total_samp;
+ char guest_name[NAME_LEN];
+};
+
+struct diag2fc_parm_list {
+ char userid[NAME_LEN];
+ char aci_grp[NAME_LEN];
+ __u64 addr;
+ __u32 size;
+ __u32 fmt;
+};
+
+static int diag2fc(int size, char* query, void *addr)
+{
+ unsigned long residual_cnt;
+ unsigned long rc;
+ struct diag2fc_parm_list parm_list;
+
+ memcpy(parm_list.userid, query, NAME_LEN);
+ ASCEBC(parm_list.userid, NAME_LEN);
+ parm_list.addr = (unsigned long) addr ;
+ parm_list.size = size;
+ parm_list.fmt = 0x02;
+ memset(parm_list.aci_grp, 0x40, NAME_LEN);
+ rc = -1;
+
+ asm volatile(
+ " diag %0,%1,0x2fc\n"
+ "0:\n"
+ EX_TABLE(0b,0b)
+ : "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
+
+ if ((rc != 0 ) && (rc != -2))
+ return rc;
+ else
+ return -residual_cnt;
+}
+
+static struct diag2fc_data *diag2fc_store(char *query, int *count)
+{
+ int size;
+ struct diag2fc_data *data;
+
+ do {
+ size = diag2fc(0, query, NULL);
+ if (size < 0)
+ return ERR_PTR(-EACCES);
+ data = vmalloc(size);
+ if (!data)
+ return ERR_PTR(-ENOMEM);
+ if (diag2fc(size, query, data) == 0)
+ break;
+ vfree(data);
+ } while (1);
+ *count = (size / sizeof(*data));
+
+ return data;
+}
+
+static void diag2fc_free(void *data)
+{
+ vfree(data);
+}
+
+#define ATTRIBUTE(sb, dir, name, member) \
+do { \
+ void *rc; \
+ rc = hypfs_create_u64(sb, dir, name, member); \
+ if (IS_ERR(rc)) \
+ return PTR_ERR(rc); \
+} while(0)
+
+static int hpyfs_vm_create_guest(struct super_block *sb,
+ struct dentry *systems_dir,
+ struct diag2fc_data *data)
+{
+ char guest_name[NAME_LEN + 1] = {};
+ struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
+ int dedicated_flag, capped_value;
+
+ capped_value = (data->flags & 0x00000006) >> 1;
+ dedicated_flag = (data->flags & 0x00000008) >> 3;
+
+ /* guest dir */
+ memcpy(guest_name, data->guest_name, NAME_LEN);
+ EBCASC(guest_name, NAME_LEN);
+ strstrip(guest_name);
+ guest_dir = hypfs_mkdir(sb, systems_dir, guest_name);
+ if (IS_ERR(guest_dir))
+ return PTR_ERR(guest_dir);
+ ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time);
+
+ /* logical cpu information */
+ cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus");
+ if (IS_ERR(cpus_dir))
+ return PTR_ERR(cpus_dir);
+ ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu);
+ ATTRIBUTE(sb, cpus_dir, "capped", capped_value);
+ ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag);
+ ATTRIBUTE(sb, cpus_dir, "count", data->vcpus);
+ ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min);
+ ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max);
+ ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares);
+
+ /* memory information */
+ mem_dir = hypfs_mkdir(sb, guest_dir, "mem");
+ if (IS_ERR(mem_dir))
+ return PTR_ERR(mem_dir);
+ ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb);
+ ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb);
+ ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb);
+ ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb);
+
+ /* samples */
+ samples_dir = hypfs_mkdir(sb, guest_dir, "samples");
+ if (IS_ERR(samples_dir))
+ return PTR_ERR(samples_dir);
+ ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp);
+ ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp);
+ ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp);
+ ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp);
+ ATTRIBUTE(sb, samples_dir, "other", data->other_samp);
+ ATTRIBUTE(sb, samples_dir, "total", data->total_samp);
+ return 0;
+}
+
+int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir, *file;
+ struct diag2fc_data *data;
+ int rc, i, count = 0;
+
+ data = diag2fc_store(guest_query, &count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ /* Hpervisor Info */
+ dir = hypfs_mkdir(sb, root, "hyp");
+ if (IS_ERR(dir)) {
+ rc = PTR_ERR(dir);
+ goto failed;
+ }
+ file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor");
+ if (IS_ERR(file)) {
+ rc = PTR_ERR(file);
+ goto failed;
+ }
+
+ /* physical cpus */
+ dir = hypfs_mkdir(sb, root, "cpus");
+ if (IS_ERR(dir)) {
+ rc = PTR_ERR(dir);
+ goto failed;
+ }
+ file = hypfs_create_u64(sb, dir, "count", data->lcpus);
+ if (IS_ERR(file)) {
+ rc = PTR_ERR(file);
+ goto failed;
+ }
+
+ /* guests */
+ dir = hypfs_mkdir(sb, root, "systems");
+ if (IS_ERR(dir)) {
+ rc = PTR_ERR(dir);
+ goto failed;
+ }
+
+ for (i = 0; i < count; i++) {
+ rc = hpyfs_vm_create_guest(sb, dir, &(data[i]));
+ if (rc)
+ goto failed;
+ }
+ diag2fc_free(data);
+ return 0;
+
+failed:
+ diag2fc_free(data);
+ return rc;
+}
+
+int hypfs_vm_init(void)
+{
+ if (diag2fc(0, all_guests, NULL) > 0)
+ guest_query = all_guests;
+ else if (diag2fc(0, local_guest, NULL) > 0)
+ guest_query = local_guest;
+ else
+ return -EACCES;
+
+ return 0;
+}
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index cd702ae45d6..a4fda7b5364 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <asm/ebcdic.h>
#include "hypfs.h"
-#include "hypfs_diag.h"
#define HYPFS_MAGIC 0x687970 /* ASCII 'hyp' */
#define TMP_SIZE 64 /* size of temporary buffers */
@@ -109,7 +108,7 @@ static void hypfs_drop_inode(struct inode *inode)
static int hypfs_open(struct inode *inode, struct file *filp)
{
- char *data = filp->f_dentry->d_inode->i_private;
+ char *data = filp->f_path.dentry->d_inode->i_private;
struct hypfs_sb_info *fs_info;
if (filp->f_mode & FMODE_WRITE) {
@@ -174,7 +173,7 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
struct hypfs_sb_info *fs_info;
size_t count = iov_length(iov, nr_segs);
- sb = iocb->ki_filp->f_dentry->d_inode->i_sb;
+ sb = iocb->ki_filp->f_path.dentry->d_inode->i_sb;
fs_info = sb->s_fs_info;
/*
* Currently we only allow one update per second for two reasons:
@@ -192,7 +191,10 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
goto out;
}
hypfs_delete_tree(sb->s_root);
- rc = hypfs_diag_create_files(sb, sb->s_root);
+ if (MACHINE_IS_VM)
+ rc = hypfs_vm_create_files(sb, sb->s_root);
+ else
+ rc = hypfs_diag_create_files(sb, sb->s_root);
if (rc) {
printk(KERN_ERR "hypfs: Update failed\n");
hypfs_delete_tree(sb->s_root);
@@ -289,7 +291,10 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
rc = -ENOMEM;
goto err_alloc;
}
- rc = hypfs_diag_create_files(sb, root_dentry);
+ if (MACHINE_IS_VM)
+ rc = hypfs_vm_create_files(sb, root_dentry);
+ else
+ rc = hypfs_diag_create_files(sb, root_dentry);
if (rc)
goto err_tree;
sbi->update_file = hypfs_create_update_file(sb, root_dentry);
@@ -462,11 +467,15 @@ static int __init hypfs_init(void)
{
int rc;
- if (MACHINE_IS_VM)
- return -ENODATA;
- if (hypfs_diag_init()) {
- rc = -ENODATA;
- goto fail_diag;
+ if (MACHINE_IS_VM) {
+ if (hypfs_vm_init())
+ /* no diag 2fc, just exit */
+ return -ENODATA;
+ } else {
+ if (hypfs_diag_init()) {
+ rc = -ENODATA;
+ goto fail_diag;
+ }
}
kset_set_kset_s(&s390_subsys, hypervisor_subsys);
rc = subsystem_register(&s390_subsys);
@@ -480,7 +489,8 @@ static int __init hypfs_init(void)
fail_filesystem:
subsystem_unregister(&s390_subsys);
fail_sysfs:
- hypfs_diag_exit();
+ if (!MACHINE_IS_VM)
+ hypfs_diag_exit();
fail_diag:
printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
return rc;
@@ -488,7 +498,8 @@ fail_diag:
static void __exit hypfs_exit(void)
{
- hypfs_diag_exit();
+ if (!MACHINE_IS_VM)
+ hypfs_diag_exit();
unregister_filesystem(&hypfs_type);
subsystem_unregister(&s390_subsys);
}
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index a81881c9b29..5492d25d7d6 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -4,9 +4,9 @@
EXTRA_AFLAGS := -traditional
-obj-y := bitmap.o traps.o time.o process.o reset.o \
+obj-y := bitmap.o traps.o time.o process.o base.o early.o \
setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
- semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o
+ semaphore.o s390_ext.o debug.o irq.o ipl.o
obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S
new file mode 100644
index 00000000000..dc7e5259770
--- /dev/null
+++ b/arch/s390/kernel/base.S
@@ -0,0 +1,150 @@
+/*
+ * arch/s390/kernel/base.S
+ *
+ * Copyright IBM Corp. 2006,2007
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ * Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <asm/ptrace.h>
+#include <asm/lowcore.h>
+
+#ifdef CONFIG_64BIT
+
+ .globl s390_base_mcck_handler
+s390_base_mcck_handler:
+ basr %r13,0
+0: lg %r15,__LC_PANIC_STACK # load panic stack
+ aghi %r15,-STACK_FRAME_OVERHEAD
+ larl %r1,s390_base_mcck_handler_fn
+ lg %r1,0(%r1)
+ ltgr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+1: la %r1,4095
+ lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
+ lpswe __LC_MCK_OLD_PSW
+
+ .section .bss
+ .globl s390_base_mcck_handler_fn
+s390_base_mcck_handler_fn:
+ .quad 0
+ .previous
+
+ .globl s390_base_ext_handler
+s390_base_ext_handler:
+ stmg %r0,%r15,__LC_SAVE_AREA
+ basr %r13,0
+0: aghi %r15,-STACK_FRAME_OVERHEAD
+ larl %r1,s390_base_ext_handler_fn
+ lg %r1,0(%r1)
+ ltgr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+1: lmg %r0,%r15,__LC_SAVE_AREA
+ ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit
+ lpswe __LC_EXT_OLD_PSW
+
+ .section .bss
+ .globl s390_base_ext_handler_fn
+s390_base_ext_handler_fn:
+ .quad 0
+ .previous
+
+ .globl s390_base_pgm_handler
+s390_base_pgm_handler:
+ stmg %r0,%r15,__LC_SAVE_AREA
+ basr %r13,0
+0: aghi %r15,-STACK_FRAME_OVERHEAD
+ larl %r1,s390_base_pgm_handler_fn
+ lg %r1,0(%r1)
+ ltgr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+ lmg %r0,%r15,__LC_SAVE_AREA
+ lpswe __LC_PGM_OLD_PSW
+1: lpswe disabled_wait_psw-0b(%r13)
+
+ .align 8
+disabled_wait_psw:
+ .quad 0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler
+
+ .section .bss
+ .globl s390_base_pgm_handler_fn
+s390_base_pgm_handler_fn:
+ .quad 0
+ .previous
+
+#else /* CONFIG_64BIT */
+
+ .globl s390_base_mcck_handler
+s390_base_mcck_handler:
+ basr %r13,0
+0: l %r15,__LC_PANIC_STACK # load panic stack
+ ahi %r15,-STACK_FRAME_OVERHEAD
+ l %r1,2f-0b(%r13)
+ l %r1,0(%r1)
+ ltr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA
+ lpsw __LC_MCK_OLD_PSW
+
+2: .long s390_base_mcck_handler_fn
+
+ .section .bss
+ .globl s390_base_mcck_handler_fn
+s390_base_mcck_handler_fn:
+ .long 0
+ .previous
+
+ .globl s390_base_ext_handler
+s390_base_ext_handler:
+ stm %r0,%r15,__LC_SAVE_AREA
+ basr %r13,0
+0: ahi %r15,-STACK_FRAME_OVERHEAD
+ l %r1,2f-0b(%r13)
+ l %r1,0(%r1)
+ ltr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+1: lm %r0,%r15,__LC_SAVE_AREA
+ ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit
+ lpsw __LC_EXT_OLD_PSW
+
+2: .long s390_base_ext_handler_fn
+
+ .section .bss
+ .globl s390_base_ext_handler_fn
+s390_base_ext_handler_fn:
+ .long 0
+ .previous
+
+ .globl s390_base_pgm_handler
+s390_base_pgm_handler:
+ stm %r0,%r15,__LC_SAVE_AREA
+ basr %r13,0
+0: ahi %r15,-STACK_FRAME_OVERHEAD
+ l %r1,2f-0b(%r13)
+ l %r1,0(%r1)
+ ltr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+ lm %r0,%r15,__LC_SAVE_AREA
+ lpsw __LC_PGM_OLD_PSW
+
+1: lpsw disabled_wait_psw-0b(%r13)
+
+2: .long s390_base_pgm_handler_fn
+
+disabled_wait_psw:
+ .align 8
+ .long 0x000a0000,0x00000000 + s390_base_pgm_handler
+
+ .section .bss
+ .globl s390_base_pgm_handler_fn
+s390_base_pgm_handler_fn:
+ .long 0
+ .previous
+
+#endif /* CONFIG_64BIT */
diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c
index 5c46054195c..f1e40ca00d8 100644
--- a/arch/s390/kernel/binfmt_elf32.c
+++ b/arch/s390/kernel/binfmt_elf32.c
@@ -192,7 +192,7 @@ MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
#undef cputime_to_timeval
#define cputime_to_timeval cputime_to_compat_timeval
-static __inline__ void
+static inline void
cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
{
value->tv_usec = cputime % 1000000;
diff --git a/arch/s390/kernel/compat_exec_domain.c b/arch/s390/kernel/compat_exec_domain.c
index 71d27c49356..914d49444f9 100644
--- a/arch/s390/kernel/compat_exec_domain.c
+++ b/arch/s390/kernel/compat_exec_domain.c
@@ -12,10 +12,9 @@
#include <linux/personality.h>
#include <linux/sched.h>
-struct exec_domain s390_exec_domain;
+static struct exec_domain s390_exec_domain;
-static int __init
-s390_init (void)
+static int __init s390_init (void)
{
s390_exec_domain.name = "Linux/s390";
s390_exec_domain.handler = NULL;
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 5b33f823863..666bb6daa14 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -69,6 +69,12 @@
#include "compat_linux.h"
+long psw_user32_bits = (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+ PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
+long psw32_user_bits = (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME |
+ PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
+ PSW32_MASK_PSTATE);
/* For this source file, we want overflow handling. */
@@ -416,7 +422,7 @@ asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
- ret = sys_sysinfo((struct sysinfo __user *) &s);
+ ret = sys_sysinfo((struct sysinfo __force __user *) &s);
set_fs (old_fs);
err = put_user (s.uptime, &info->uptime);
err |= __put_user (s.loads[0], &info->loads[0]);
@@ -445,7 +451,8 @@ asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
- ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t);
+ ret = sys_sched_rr_get_interval(pid,
+ (struct timespec __force __user *) &t);
set_fs (old_fs);
if (put_compat_timespec(&t, interval))
return -EFAULT;
@@ -472,8 +479,8 @@ asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
}
set_fs (KERNEL_DS);
ret = sys_rt_sigprocmask(how,
- set ? (sigset_t __user *) &s : NULL,
- oset ? (sigset_t __user *) &s : NULL,
+ set ? (sigset_t __force __user *) &s : NULL,
+ oset ? (sigset_t __force __user *) &s : NULL,
sigsetsize);
set_fs (old_fs);
if (ret) return ret;
@@ -499,7 +506,7 @@ asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
- ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
+ ret = sys_rt_sigpending((sigset_t __force __user *) &s, sigsetsize);
set_fs (old_fs);
if (!ret) {
switch (_NSIG_WORDS) {
@@ -524,7 +531,7 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
if (copy_siginfo_from_user32(&info, uinfo))
return -EFAULT;
set_fs (KERNEL_DS);
- ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
+ ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *) &info);
set_fs (old_fs);
return ret;
}
@@ -682,7 +689,7 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offse
set_fs(KERNEL_DS);
ret = sys_sendfile(out_fd, in_fd,
- offset ? (off_t __user *) &of : NULL, count);
+ offset ? (off_t __force __user *) &of : NULL, count);
set_fs(old_fs);
if (offset && put_user(of, offset))
@@ -703,7 +710,8 @@ asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
set_fs(KERNEL_DS);
ret = sys_sendfile64(out_fd, in_fd,
- offset ? (loff_t __user *) &lof : NULL, count);
+ offset ? (loff_t __force __user *) &lof : NULL,
+ count);
set_fs(old_fs);
if (offset && put_user(lof, offset))
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 1a18e29668e..e89f8c0c42a 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -115,37 +115,6 @@ typedef struct
__u32 addr;
} _psw_t32 __attribute__ ((aligned(8)));
-#define PSW32_MASK_PER 0x40000000UL
-#define PSW32_MASK_DAT 0x04000000UL
-#define PSW32_MASK_IO 0x02000000UL
-#define PSW32_MASK_EXT 0x01000000UL
-#define PSW32_MASK_KEY 0x00F00000UL
-#define PSW32_MASK_MCHECK 0x00040000UL
-#define PSW32_MASK_WAIT 0x00020000UL
-#define PSW32_MASK_PSTATE 0x00010000UL
-#define PSW32_MASK_ASC 0x0000C000UL
-#define PSW32_MASK_CC 0x00003000UL
-#define PSW32_MASK_PM 0x00000f00UL
-
-#define PSW32_ADDR_AMODE31 0x80000000UL
-#define PSW32_ADDR_INSN 0x7FFFFFFFUL
-
-#define PSW32_BASE_BITS 0x00080000UL
-
-#define PSW32_ASC_PRIMARY 0x00000000UL
-#define PSW32_ASC_ACCREG 0x00004000UL
-#define PSW32_ASC_SECONDARY 0x00008000UL
-#define PSW32_ASC_HOME 0x0000C000UL
-
-#define PSW32_USER_BITS (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \
- PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
- PSW32_MASK_PSTATE)
-
-#define PSW32_MASK_MERGE(CURRENT,NEW) \
- (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
- ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
-
-
typedef struct
{
_psw_t32 psw;
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 861888ab8c1..887a9881d0d 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -275,8 +275,8 @@ sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss,
}
set_fs (KERNEL_DS);
- ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL),
- (stack_t __user *) (uoss ? &koss : NULL),
+ ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL),
+ (stack_t __force __user *) (uoss ? &koss : NULL),
regs->gprs[15]);
set_fs (old_fs);
@@ -298,7 +298,7 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
_s390_regs_common32 regs32;
int err, i;
- regs32.psw.mask = PSW32_MASK_MERGE(PSW32_USER_BITS,
+ regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits,
(__u32)(regs->psw.mask >> 32));
regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
for (i = 0; i < NUM_GPRS; i++)
@@ -401,7 +401,7 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
goto badframe;
set_fs (KERNEL_DS);
- do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]);
+ do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
set_fs (old_fs);
return regs->gprs[2];
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
index a5972f1541f..6c89f30c8e3 100644
--- a/arch/s390/kernel/cpcmd.c
+++ b/arch/s390/kernel/cpcmd.c
@@ -16,6 +16,7 @@
#include <asm/ebcdic.h>
#include <asm/cpcmd.h>
#include <asm/system.h>
+#include <asm/io.h>
static DEFINE_SPINLOCK(cpcmd_lock);
static char cpcmd_buf[241];
@@ -88,13 +89,8 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
int len;
unsigned long flags;
- if ((rlen == 0) || (response == NULL)
- || !((unsigned long)response >> 31)) {
- spin_lock_irqsave(&cpcmd_lock, flags);
- len = __cpcmd(cmd, response, rlen, response_code);
- spin_unlock_irqrestore(&cpcmd_lock, flags);
- }
- else {
+ if ((virt_to_phys(response) != (unsigned long) response) ||
+ (((unsigned long)response + rlen) >> 31)) {
lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
if (!lowbuf) {
printk(KERN_WARNING
@@ -106,6 +102,10 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
spin_unlock_irqrestore(&cpcmd_lock, flags);
memcpy(response, lowbuf, rlen);
kfree(lowbuf);
+ } else {
+ spin_lock_irqsave(&cpcmd_lock, flags);
+ len = __cpcmd(cmd, response, rlen, response_code);
+ spin_unlock_irqrestore(&cpcmd_lock, flags);
}
return len;
}
diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c
index 926cceeae0f..8cc7c9fa64f 100644
--- a/arch/s390/kernel/crash.c
+++ b/arch/s390/kernel/crash.c
@@ -9,6 +9,7 @@
#include <linux/threads.h>
#include <linux/kexec.h>
+#include <linux/reboot.h>
void machine_crash_shutdown(struct pt_regs *regs)
{
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index 43f3d0c7e13..f4b62df02aa 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -120,7 +120,7 @@ struct debug_view debug_hex_ascii_view = {
NULL
};
-struct debug_view debug_level_view = {
+static struct debug_view debug_level_view = {
"level",
&debug_prolog_level_fn,
NULL,
@@ -129,7 +129,7 @@ struct debug_view debug_level_view = {
NULL
};
-struct debug_view debug_pages_view = {
+static struct debug_view debug_pages_view = {
"pages",
&debug_prolog_pages_fn,
NULL,
@@ -138,7 +138,7 @@ struct debug_view debug_pages_view = {
NULL
};
-struct debug_view debug_flush_view = {
+static struct debug_view debug_flush_view = {
"flush",
NULL,
NULL,
@@ -156,14 +156,14 @@ struct debug_view debug_sprintf_view = {
NULL
};
-
+/* used by dump analysis tools to determine version of debug feature */
unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
/* static globals */
static debug_info_t *debug_area_first = NULL;
static debug_info_t *debug_area_last = NULL;
-DECLARE_MUTEX(debug_lock);
+static DECLARE_MUTEX(debug_lock);
static int initialized;
@@ -191,13 +191,13 @@ debug_areas_alloc(int pages_per_area, int nr_areas)
debug_entry_t*** areas;
int i,j;
- areas = (debug_entry_t ***) kmalloc(nr_areas *
+ areas = kmalloc(nr_areas *
sizeof(debug_entry_t**),
GFP_KERNEL);
if (!areas)
goto fail_malloc_areas;
for (i = 0; i < nr_areas; i++) {
- areas[i] = (debug_entry_t**) kmalloc(pages_per_area *
+ areas[i] = kmalloc(pages_per_area *
sizeof(debug_entry_t*),GFP_KERNEL);
if (!areas[i]) {
goto fail_malloc_areas2;
@@ -242,7 +242,7 @@ debug_info_alloc(char *name, int pages_per_area, int nr_areas, int buf_size,
/* alloc everything */
- rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_KERNEL);
+ rc = kmalloc(sizeof(debug_info_t), GFP_KERNEL);
if(!rc)
goto fail_malloc_rc;
rc->active_entries = kcalloc(nr_areas, sizeof(int), GFP_KERNEL);
@@ -603,13 +603,13 @@ debug_open(struct inode *inode, struct file *file)
debug_info_t *debug_info, *debug_info_snapshot;
down(&debug_lock);
- debug_info = file->f_dentry->d_inode->i_private;
+ debug_info = file->f_path.dentry->d_inode->i_private;
/* find debug view */
for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
if (!debug_info->views[i])
continue;
else if (debug_info->debugfs_entries[i] ==
- file->f_dentry) {
+ file->f_path.dentry) {
goto found; /* found view ! */
}
}
@@ -634,7 +634,7 @@ found:
rc = -ENOMEM;
goto out;
}
- p_info = (file_private_info_t *) kmalloc(sizeof(file_private_info_t),
+ p_info = kmalloc(sizeof(file_private_info_t),
GFP_KERNEL);
if(!p_info){
if(debug_info_snapshot)
@@ -905,7 +905,7 @@ static struct ctl_table s390dbf_dir_table[] = {
{ .ctl_name = 0 }
};
-struct ctl_table_header *s390dbf_sysctl_header;
+static struct ctl_table_header *s390dbf_sysctl_header;
void
debug_stop_all(void)
@@ -1300,8 +1300,7 @@ out:
* flushes debug areas
*/
-void
-debug_flush(debug_info_t* id, int area)
+static void debug_flush(debug_info_t* id, int area)
{
unsigned long flags;
int i,j;
@@ -1511,8 +1510,7 @@ out:
/*
* clean up module
*/
-void
-__exit debug_exit(void)
+static void __exit debug_exit(void)
{
debugfs_remove(debug_debugfs_root_entry);
unregister_sysctl_table(s390dbf_sysctl_header);
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
new file mode 100644
index 00000000000..e518dd53eff
--- /dev/null
+++ b/arch/s390/kernel/early.c
@@ -0,0 +1,306 @@
+/*
+ * arch/s390/kernel/early.c
+ *
+ * Copyright IBM Corp. 2007
+ * Author(s): Hongjie Yang <hongjie@us.ibm.com>,
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/pfn.h>
+#include <linux/uaccess.h>
+#include <asm/lowcore.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/cpcmd.h>
+#include <asm/sclp.h>
+
+/*
+ * Create a Kernel NSS if the SAVESYS= parameter is defined
+ */
+#define DEFSYS_CMD_SIZE 96
+#define SAVESYS_CMD_SIZE 32
+
+char kernel_nss_name[NSS_NAME_SIZE + 1];
+
+#ifdef CONFIG_SHARED_KERNEL
+static noinline __init void create_kernel_nss(void)
+{
+ unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
+#ifdef CONFIG_BLK_DEV_INITRD
+ unsigned int sinitrd_pfn, einitrd_pfn;
+#endif
+ int response;
+ char *savesys_ptr;
+ char upper_command_line[COMMAND_LINE_SIZE];
+ char defsys_cmd[DEFSYS_CMD_SIZE];
+ char savesys_cmd[SAVESYS_CMD_SIZE];
+
+ /* Do nothing if we are not running under VM */
+ if (!MACHINE_IS_VM)
+ return;
+
+ /* Convert COMMAND_LINE to upper case */
+ for (i = 0; i < strlen(COMMAND_LINE); i++)
+ upper_command_line[i] = toupper(COMMAND_LINE[i]);
+
+ savesys_ptr = strstr(upper_command_line, "SAVESYS=");
+
+ if (!savesys_ptr)
+ return;
+
+ savesys_ptr += 8; /* Point to the beginning of the NSS name */
+ for (i = 0; i < NSS_NAME_SIZE; i++) {
+ if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
+ break;
+ kernel_nss_name[i] = savesys_ptr[i];
+ }
+
+ stext_pfn = PFN_DOWN(__pa(&_stext));
+ eshared_pfn = PFN_DOWN(__pa(&_eshared));
+ end_pfn = PFN_UP(__pa(&_end));
+ min_size = end_pfn << 2;
+
+ sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
+ kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
+ eshared_pfn, end_pfn);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (INITRD_START && INITRD_SIZE) {
+ sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
+ einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
+ min_size = einitrd_pfn << 2;
+ sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
+ sinitrd_pfn, einitrd_pfn);
+ }
+#endif
+
+ sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size);
+ sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
+ kernel_nss_name, kernel_nss_name);
+
+ __cpcmd(defsys_cmd, NULL, 0, &response);
+
+ if (response != 0)
+ return;
+
+ __cpcmd(savesys_cmd, NULL, 0, &response);
+
+ if (response != strlen(savesys_cmd))
+ return;
+
+ ipl_flags = IPL_NSS_VALID;
+}
+
+#else /* CONFIG_SHARED_KERNEL */
+
+static inline void create_kernel_nss(void) { }
+
+#endif /* CONFIG_SHARED_KERNEL */
+
+/*
+ * Clear bss memory
+ */
+static noinline __init void clear_bss_section(void)
+{
+ memset(__bss_start, 0, _end - __bss_start);
+}
+
+/*
+ * Initialize storage key for kernel pages
+ */
+static noinline __init void init_kernel_storage_key(void)
+{
+ unsigned long end_pfn, init_pfn;
+
+ end_pfn = PFN_UP(__pa(&_end));
+
+ for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
+ page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
+}
+
+static noinline __init void detect_machine_type(void)
+{
+ struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
+
+ asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id));
+
+ /* Running under z/VM ? */
+ if (cpuinfo->cpu_id.version == 0xff)
+ machine_flags |= 1;
+
+ /* Running on a P/390 ? */
+ if (cpuinfo->cpu_id.machine == 0x7490)
+ machine_flags |= 4;
+}
+
+static noinline __init int memory_fast_detect(void)
+{
+
+ unsigned long val0 = 0;
+ unsigned long val1 = 0xc;
+ int ret = -ENOSYS;
+
+ if (ipl_flags & IPL_NSS_VALID)
+ return -ENOSYS;
+
+ asm volatile(
+ " diag %1,%2,0x260\n"
+ "0: lhi %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "+d" (ret), "+d" (val0), "+d" (val1) : : "cc");
+
+ if (ret || val0 != val1)
+ return -ENOSYS;
+
+ memory_chunk[0].size = val0;
+ return 0;
+}
+
+#define ADDR2G (1UL << 31)
+
+static noinline __init unsigned long sclp_memory_detect(void)
+{
+ struct sclp_readinfo_sccb *sccb;
+ unsigned long long memsize;
+
+ sccb = &s390_readinfo_sccb;
+
+ if (sccb->header.response_code != 0x10)
+ return 0;
+
+ if (sccb->rnsize)
+ memsize = sccb->rnsize << 20;
+ else
+ memsize = sccb->rnsize2 << 20;
+ if (sccb->rnmax)
+ memsize *= sccb->rnmax;
+ else
+ memsize *= sccb->rnmax2;
+#ifndef CONFIG_64BIT
+ /*
+ * Can't deal with more than 2G in 31 bit addressing mode, so
+ * limit the value in order to avoid strange side effects.
+ */
+ if (memsize > ADDR2G)
+ memsize = ADDR2G;
+#endif
+ return (unsigned long) memsize;
+}
+
+static inline __init unsigned long __tprot(unsigned long addr)
+{
+ int cc = -1;
+
+ asm volatile(
+ " tprot 0(%1),0\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "+d" (cc) : "a" (addr) : "cc");
+ return (unsigned long)cc;
+}
+
+/* Checking memory in 128KB increments. */
+#define CHUNK_INCR (1UL << 17)
+
+static noinline __init void find_memory_chunks(unsigned long memsize)
+{
+ unsigned long addr = 0, old_addr = 0;
+ unsigned long old_cc = CHUNK_READ_WRITE;
+ unsigned long cc;
+ int chunk = 0;
+
+ while (chunk < MEMORY_CHUNKS) {
+ cc = __tprot(addr);
+ while (cc == old_cc) {
+ addr += CHUNK_INCR;
+ cc = __tprot(addr);
+#ifndef CONFIG_64BIT
+ if (addr == ADDR2G)
+ break;
+#endif
+ }
+
+ if (old_addr != addr &&
+ (old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) {
+ memory_chunk[chunk].addr = old_addr;
+ memory_chunk[chunk].size = addr - old_addr;
+ memory_chunk[chunk].type = old_cc;
+ chunk++;
+ }
+
+ old_addr = addr;
+ old_cc = cc;
+
+#ifndef CONFIG_64BIT
+ if (addr == ADDR2G)
+ break;
+#endif
+ /*
+ * Finish memory detection at the first hole, unless
+ * - we reached the hsa -> skip it.
+ * - we know there must be more.
+ */
+ if (cc == -1UL && !memsize && old_addr != ADDR2G)
+ break;
+ if (memsize && addr >= memsize)
+ break;
+ }
+}
+
+static __init void early_pgm_check_handler(void)
+{
+ unsigned long addr;
+ const struct exception_table_entry *fixup;
+
+ addr = S390_lowcore.program_old_psw.addr;
+ fixup = search_exception_tables(addr & PSW_ADDR_INSN);
+ if (!fixup)
+ disabled_wait(0);
+ S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+}
+
+static noinline __init void setup_lowcore_early(void)
+{
+ psw_t psw;
+
+ psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
+ psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler;
+ S390_lowcore.external_new_psw = psw;
+ psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
+ S390_lowcore.program_new_psw = psw;
+ s390_base_pgm_handler_fn = early_pgm_check_handler;
+}
+
+/*
+ * Save ipl parameters, clear bss memory, initialize storage keys
+ * and create a kernel NSS at startup if the SAVESYS= parm is defined
+ */
+void __init startup_init(void)
+{
+ unsigned long memsize;
+
+ ipl_save_parameters();
+ clear_bss_section();
+ init_kernel_storage_key();
+ lockdep_init();
+ lockdep_off();
+ detect_machine_type();
+ create_kernel_nss();
+ sort_main_extable();
+ setup_lowcore_early();
+ sclp_readinfo_early();
+ memsize = sclp_memory_detect();
+ if (memory_fast_detect() < 0)
+ find_memory_chunks(memsize);
+ lockdep_on();
+}
diff --git a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c
index bb0f973137f..cc0dc609d73 100644
--- a/arch/s390/kernel/ebcdic.c
+++ b/arch/s390/kernel/ebcdic.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <asm/types.h>
+#include <asm/ebcdic.h>
/*
* ASCII (IBM PC 437) -> EBCDIC 037
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S
index 4388b3309e0..453fd3b4ede 100644
--- a/arch/s390/kernel/head31.S
+++ b/arch/s390/kernel/head31.S
@@ -51,166 +51,15 @@ startup_continue:
st %r15,__LC_KERNEL_STACK # set end of kernel stack
ahi %r15,-96
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
-
- l %r14,.Lipl_save_parameters-.LPG1(%r13)
- basr %r14,%r14
#
-# clear bss memory
+# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
+# and create a kernel NSS if the SAVESYS= parm is defined
#
- l %r2,.Lbss_bgn-.LPG1(%r13) # start of bss
- l %r3,.Lbss_end-.LPG1(%r13) # end of bss
- sr %r3,%r2 # length of bss
- sr %r4,%r4
- sr %r5,%r5 # set src,length and pad to zero
- sr %r0,%r0
- mvcle %r2,%r4,0 # clear mem
- jo .-4 # branch back, if not finish
-
- l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
-.Lservicecall:
- stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts
-
- stctl %r0, %r0,.Lcr-.LPG1(%r13) # get cr0
- la %r1,0x200 # set bit 22
- o %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1
- st %r1,.Lcr-.LPG1(%r13)
- lctl %r0, %r0,.Lcr-.LPG1(%r13) # load modified cr0
-
- mvc __LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw
- la %r1, .Lsclph-.LPG1(%r13)
- a %r1,__LC_EXT_NEW_PSW+4 # set handler
- st %r1,__LC_EXT_NEW_PSW+4
-
- l %r4,.Lsccbaddr-.LPG1(%r13) # %r4 is our index for sccb stuff
- lr %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)
- lpsw .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)
-.Lprocsccb:
- lhi %r1,0
- icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
- jnz .Lscnd
- lhi %r1,0x800 # otherwise report 2GB
-.Lscnd:
- lhi %r3,0x800 # limit reported memory size to 2GB
- cr %r1,%r3
- jl .Lno2gb
- lr %r1,%r3
-.Lno2gb:
- xr %r3,%r3 # same logic
- ic %r3,.Lscpa1-.Lsccb(%r4)
- chi %r3,0x00
- jne .Lcompmem
- l %r3,.Lscpa2-.Lsccb(%r4)
-.Lcompmem:
- mr %r2,%r1 # mem in MB on 128-bit
- l %r1,.Lonemb-.LPG1(%r13)
- mr %r2,%r1 # mem size in bytes in %r3
- b .Lfchunk-.LPG1(%r13)
-
- .align 4
-.Lipl_save_parameters:
- .long ipl_save_parameters
-.Linittu:
- .long init_thread_union
-.Lpmask:
- .byte 0
- .align 8
-.Lpcext:.long 0x00080000,0x80000000
-.Lcr:
- .long 0x00 # place holder for cr0
- .align 8
-.Lwaitsclp:
- .long 0x010a0000,0x80000000 + .Lsclph
-.Lrcp:
- .int 0x00120001 # Read SCP forced code
-.Lrcp2:
- .int 0x00020001 # Read SCP code
-.Lonemb:
- .int 0x100000
-.Lfchunk:
+ l %r14,.Lstartup_init-.LPG1(%r13)
+ basr %r14,%r14
-#
-# find memory chunks.
-#
- lr %r9,%r3 # end of mem
- mvc __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13)
- la %r1,1 # test in increments of 128KB
- sll %r1,17
- l %r3,.Lmchunk-.LPG1(%r13) # get pointer to memory_chunk array
- slr %r4,%r4 # set start of chunk to zero
- slr %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
- be .Lsame-.LPG1(%r13)
- b .Lchkmem-.LPG1(%r13)
-.Lsame:
- ar %r5,%r1 # add 128KB to end of chunk
- bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop
-.Lchkmem: # > 2GB or tprot got a program check
- clr %r4,%r5 # chunk size > 0?
- be .Lchkloop-.LPG1(%r13)
- st %r4,0(%r3) # store start address of chunk
- lr %r0,%r5
- slr %r0,%r4
- st %r0,4(%r3) # store size of chunk
- st %r6,8(%r3) # store type of chunk
- la %r3,12(%r3)
- ahi %r10,-1 # update chunk number
-.Lchkloop:
- 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
- xr %r0,%r0
- clr %r0,%r9 # did we detect memory?
- je .Ldonemem # if not, leave
- chi %r10,0 # do we have chunks left?
- je .Ldonemem
- alr %r5,%r1 # add 128KB to end of chunk
- lr %r4,%r5 # potential new chunk
- clr %r5,%r9 # should we go on?
- jl .Lloop
-.Ldonemem:
l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
#
-# find out if we are running under VM
-#
- stidp __LC_CPUID # store cpuid
- tm __LC_CPUID,0xff # running under VM ?
- bno .Lnovm-.LPG1(%r13)
- oi 3(%r12),1 # set VM flag
-.Lnovm:
- lh %r0,__LC_CPUID+4 # get cpu version
- chi %r0,0x7490 # running on a P/390 ?
- bne .Lnop390-.LPG1(%r13)
- oi 3(%r12),4 # set P/390 flag
-.Lnop390:
-
-#
# find out if we have an IEEE fpu
#
mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13)
@@ -285,7 +134,6 @@ startup_continue:
.long 0 # cr15: linkage stack operations
.Lduct: .long 0,0,0,0,0,0,0,0
.long 0,0,0,0,0,0,0,0
-.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem
.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu
.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
@@ -296,7 +144,9 @@ startup_continue:
.Lbss_bgn: .long __bss_start
.Lbss_end: .long _end
.Lparmaddr: .long PARMAREA
-.Lsccbaddr: .long .Lsccb
+.Linittu: .long init_thread_union
+.Lstartup_init:
+ .long startup_init
.globl ipl_schib
ipl_schib:
@@ -312,26 +162,6 @@ ipl_devno:
.word 0
.org 0x12000
-.globl s390_readinfo_sccb
-s390_readinfo_sccb:
-.Lsccb:
- .hword 0x1000 # length, one page
- .byte 0x00,0x00,0x00
- .byte 0x80 # variable response bit set
-.Lsccbr:
- .hword 0x00 # response code
-.Lscpincr1:
- .hword 0x00
-.Lscpa1:
- .byte 0x00
- .fill 89,1,0
-.Lscpa2:
- .int 0x00
-.Lscpincr2:
- .quad 0x00
- .fill 3984,1,0
- .org 0x13000
-
#ifdef CONFIG_SHARED_KERNEL
.org 0x100000
#endif
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index c526279e112..b8fec4e5c5d 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -58,173 +58,15 @@ startup_continue:
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
#
-# clear bss memory
+# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
+# and create a kernel NSS if the SAVESYS= parm is defined
#
- 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
+ brasl %r14,startup_init
# set program check new psw mask
mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
- larl %r1,.Lslowmemdetect # set program check address
- stg %r1,__LC_PGM_NEW_PSW+8
- lghi %r1,0xc
- diag %r0,%r1,0x260 # get memory size of virtual machine
- cgr %r0,%r1 # different? -> old detection routine
- jne .Lslowmemdetect
- aghi %r1,1 # size is one more than end
- larl %r2,memory_chunk
- stg %r1,8(%r2) # store size of chunk
- j .Ldonemem
-
-.Lslowmemdetect:
- l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
-.Lservicecall:
- 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
-
- 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)
-.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)
-.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
-.Lscnd:
- 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)
-
- .align 4
-.Lpmask:
- .byte 0
- .align 8
-.Lcr:
- .quad 0x00 # place holder for cr0
-.Lwaitsclp:
- .quad 0x0102000180000000,.Lsclph
-.Lrcp:
- .int 0x00120001 # Read SCP forced code
-.Lrcp2:
- .int 0x00020001 # Read SCP code
-.Lonemb:
- .int 0x100000
-
-.Lfchunk:
-
-#
-# 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
-.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
-.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)
- ahi %r10,-1 # update chunk number
-.Lchkloop:
- 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
-.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:
-
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
-1:
-
-#
# find out if we have the MVPG instruction
#
la %r1,0f-.LPG1(%r13) # set program check address
@@ -326,25 +168,6 @@ ipl_devno:
.word 0
.org 0x12000
-.globl s390_readinfo_sccb
-s390_readinfo_sccb:
-.Lsccb:
- .hword 0x1000 # length, one page
- .byte 0x00,0x00,0x00
- .byte 0x80 # variable response bit set
-.Lsccbr:
- .hword 0x00 # response code
-.Lscpincr1:
- .hword 0x00
-.Lscpa1:
- .byte 0x00
- .fill 89,1,0
-.Lscpa2:
- .int 0x00
-.Lscpincr2:
- .quad 0x00
- .fill 3984,1,0
- .org 0x13000
#ifdef CONFIG_SHARED_KERNEL
.org 0x100000
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index a36bea1188d..05225953065 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -20,26 +20,27 @@
#include <asm/cio.h>
#include <asm/ebcdic.h>
#include <asm/reset.h>
+#include <asm/sclp.h>
#define IPL_PARM_BLOCK_VERSION 0
-#define LOADPARM_LEN 8
-extern char s390_readinfo_sccb[];
-#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010)
-#define SCCB_LOADPARM (&s390_readinfo_sccb[24])
-#define SCCB_FLAG (s390_readinfo_sccb[91])
+#define SCCB_VALID (s390_readinfo_sccb.header.response_code == 0x10)
+#define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm)
+#define SCCB_FLAG (s390_readinfo_sccb.flags)
enum ipl_type {
IPL_TYPE_NONE = 1,
IPL_TYPE_UNKNOWN = 2,
IPL_TYPE_CCW = 4,
IPL_TYPE_FCP = 8,
+ IPL_TYPE_NSS = 16,
};
#define IPL_NONE_STR "none"
#define IPL_UNKNOWN_STR "unknown"
#define IPL_CCW_STR "ccw"
#define IPL_FCP_STR "fcp"
+#define IPL_NSS_STR "nss"
static char *ipl_type_str(enum ipl_type type)
{
@@ -50,6 +51,8 @@ static char *ipl_type_str(enum ipl_type type)
return IPL_CCW_STR;
case IPL_TYPE_FCP:
return IPL_FCP_STR;
+ case IPL_TYPE_NSS:
+ return IPL_NSS_STR;
case IPL_TYPE_UNKNOWN:
default:
return IPL_UNKNOWN_STR;
@@ -64,6 +67,7 @@ enum ipl_method {
IPL_METHOD_FCP_RO_DIAG,
IPL_METHOD_FCP_RW_DIAG,
IPL_METHOD_FCP_RO_VM,
+ IPL_METHOD_NSS,
};
enum shutdown_action {
@@ -114,11 +118,14 @@ enum diag308_rc {
static int diag308_set_works = 0;
static int reipl_capabilities = IPL_TYPE_UNKNOWN;
+
static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
static enum ipl_method reipl_method = IPL_METHOD_NONE;
static struct ipl_parameter_block *reipl_block_fcp;
static struct ipl_parameter_block *reipl_block_ccw;
+static char reipl_nss_name[NSS_NAME_SIZE + 1];
+
static int dump_capabilities = IPL_TYPE_NONE;
static enum ipl_type dump_type = IPL_TYPE_NONE;
static enum ipl_method dump_method = IPL_METHOD_NONE;
@@ -173,6 +180,24 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
sys_##_prefix##_##_name##_show, \
sys_##_prefix##_##_name##_store);
+#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
+static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
+ char *page) \
+{ \
+ return sprintf(page, _fmt_out, _value); \
+} \
+static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
+ const char *buf, size_t len) \
+{ \
+ if (sscanf(buf, _fmt_in, _value) != 1) \
+ return -EINVAL; \
+ return len; \
+} \
+static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
+ __ATTR(_name,(S_IRUGO | S_IWUSR), \
+ sys_##_prefix##_##_name##_show, \
+ sys_##_prefix##_##_name##_store);
+
static void make_attrs_ro(struct attribute **attrs)
{
while (*attrs) {
@@ -189,6 +214,8 @@ static enum ipl_type ipl_get_type(void)
{
struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
+ if (ipl_flags & IPL_NSS_VALID)
+ return IPL_TYPE_NSS;
if (!(ipl_flags & IPL_DEVNO_VALID))
return IPL_TYPE_UNKNOWN;
if (!(ipl_flags & IPL_PARMBLOCK_VALID))
@@ -324,6 +351,20 @@ static struct attribute_group ipl_ccw_attr_group = {
.attrs = ipl_ccw_attrs,
};
+/* NSS ipl device attributes */
+
+DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
+
+static struct attribute *ipl_nss_attrs[] = {
+ &sys_ipl_type_attr.attr,
+ &sys_ipl_nss_name_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ipl_nss_attr_group = {
+ .attrs = ipl_nss_attrs,
+};
+
/* UNKNOWN ipl device attributes */
static struct attribute *ipl_unknown_attrs[] = {
@@ -432,6 +473,21 @@ static struct attribute_group reipl_ccw_attr_group = {
.attrs = reipl_ccw_attrs,
};
+
+/* NSS reipl device attributes */
+
+DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
+
+static struct attribute *reipl_nss_attrs[] = {
+ &sys_reipl_nss_name_attr.attr,
+ NULL,
+};
+
+static struct attribute_group reipl_nss_attr_group = {
+ .name = IPL_NSS_STR,
+ .attrs = reipl_nss_attrs,
+};
+
/* reipl type */
static int reipl_set_type(enum ipl_type type)
@@ -454,6 +510,9 @@ static int reipl_set_type(enum ipl_type type)
else
reipl_method = IPL_METHOD_FCP_RO_DIAG;
break;
+ case IPL_TYPE_NSS:
+ reipl_method = IPL_METHOD_NSS;
+ break;
default:
reipl_method = IPL_METHOD_NONE;
}
@@ -475,6 +534,8 @@ static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
rc = reipl_set_type(IPL_TYPE_CCW);
else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
rc = reipl_set_type(IPL_TYPE_FCP);
+ else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
+ rc = reipl_set_type(IPL_TYPE_NSS);
return (rc != 0) ? rc : len;
}
@@ -609,42 +670,12 @@ static ssize_t on_panic_store(struct subsystem *subsys, const char *buf,
static struct subsys_attribute on_panic_attr =
__ATTR(on_panic, 0644, on_panic_show, on_panic_store);
-static void print_fcp_block(struct ipl_parameter_block *fcp_block)
-{
- printk(KERN_EMERG "wwpn: %016llx\n",
- (unsigned long long)fcp_block->ipl_info.fcp.wwpn);
- printk(KERN_EMERG "lun: %016llx\n",
- (unsigned long long)fcp_block->ipl_info.fcp.lun);
- printk(KERN_EMERG "bootprog: %lld\n",
- (unsigned long long)fcp_block->ipl_info.fcp.bootprog);
- printk(KERN_EMERG "br_lba: %lld\n",
- (unsigned long long)fcp_block->ipl_info.fcp.br_lba);
- printk(KERN_EMERG "device: %llx\n",
- (unsigned long long)fcp_block->ipl_info.fcp.devno);
- printk(KERN_EMERG "opt: %x\n", fcp_block->ipl_info.fcp.opt);
-}
-
void do_reipl(void)
{
struct ccw_dev_id devid;
static char buf[100];
char loadparm[LOADPARM_LEN + 1];
- switch (reipl_type) {
- case IPL_TYPE_CCW:
- reipl_get_ascii_loadparm(loadparm);
- printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n",
- reipl_block_ccw->ipl_info.ccw.devno);
- printk(KERN_EMERG "loadparm = '%s'\n", loadparm);
- break;
- case IPL_TYPE_FCP:
- printk(KERN_EMERG "reboot on fcp device:\n");
- print_fcp_block(reipl_block_fcp);
- break;
- default:
- break;
- }
-
switch (reipl_method) {
case IPL_METHOD_CCW_CIO:
devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
@@ -654,6 +685,7 @@ void do_reipl(void)
reipl_ccw_dev(&devid);
break;
case IPL_METHOD_CCW_VM:
+ reipl_get_ascii_loadparm(loadparm);
if (strlen(loadparm) == 0)
sprintf(buf, "IPL %X",
reipl_block_ccw->ipl_info.ccw.devno);
@@ -676,6 +708,10 @@ void do_reipl(void)
case IPL_METHOD_FCP_RO_VM:
__cpcmd("IPL", NULL, 0, NULL);
break;
+ case IPL_METHOD_NSS:
+ sprintf(buf, "IPL %s", reipl_nss_name);
+ __cpcmd(buf, NULL, 0, NULL);
+ break;
case IPL_METHOD_NONE:
default:
if (MACHINE_IS_VM)
@@ -683,7 +719,6 @@ void do_reipl(void)
diag308(DIAG308_IPL, NULL);
break;
}
- printk(KERN_EMERG "reboot failed!\n");
signal_processor(smp_processor_id(), sigp_stop_and_store_status);
}
@@ -692,19 +727,6 @@ static void do_dump(void)
struct ccw_dev_id devid;
static char buf[100];
- switch (dump_type) {
- case IPL_TYPE_CCW:
- printk(KERN_EMERG "Automatic dump on ccw device: 0.0.%04x\n",
- dump_block_ccw->ipl_info.ccw.devno);
- break;
- case IPL_TYPE_FCP:
- printk(KERN_EMERG "Automatic dump on fcp device:\n");
- print_fcp_block(dump_block_fcp);
- break;
- default:
- return;
- }
-
switch (dump_method) {
case IPL_METHOD_CCW_CIO:
smp_send_stop();
@@ -776,6 +798,10 @@ static int __init ipl_init(void)
case IPL_TYPE_FCP:
rc = ipl_register_fcp_files();
break;
+ case IPL_TYPE_NSS:
+ rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+ &ipl_nss_attr_group);
+ break;
default:
rc = sysfs_create_group(&ipl_subsys.kset.kobj,
&ipl_unknown_attr_group);
@@ -798,6 +824,20 @@ static void __init reipl_probe(void)
free_page((unsigned long)buffer);
}
+static int __init reipl_nss_init(void)
+{
+ int rc;
+
+ if (!MACHINE_IS_VM)
+ return 0;
+ rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group);
+ if (rc)
+ return rc;
+ strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
+ reipl_capabilities |= IPL_TYPE_NSS;
+ return 0;
+}
+
static int __init reipl_ccw_init(void)
{
int rc;
@@ -880,6 +920,9 @@ static int __init reipl_init(void)
rc = reipl_fcp_init();
if (rc)
return rc;
+ rc = reipl_nss_init();
+ if (rc)
+ return rc;
rc = reipl_set_type(ipl_get_type());
if (rc)
return rc;
@@ -1036,16 +1079,20 @@ static void do_reset_calls(void)
reset->fn();
}
-extern void reset_mcck_handler(void);
+extern __u32 dump_prefix_page;
void s390_reset_system(void)
{
struct _lowcore *lc;
- /* Stack for interrupt/machine check handler */
lc = (struct _lowcore *)(unsigned long) store_prefix();
+
+ /* Stack for interrupt/machine check handler */
lc->panic_stack = S390_lowcore.panic_stack;
+ /* Save prefix page address for dump case */
+ dump_prefix_page = (unsigned long) lc;
+
/* Disable prefixing */
set_prefix(0);
@@ -1053,8 +1100,14 @@ void s390_reset_system(void)
__ctl_clear_bit(0,28);
/* Set new machine check handler */
- S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
+ S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
S390_lowcore.mcck_new_psw.addr =
- PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
+ PSW_ADDR_AMODE | (unsigned long) s390_base_mcck_handler;
+
+ /* Set new program check handler */
+ S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
+ S390_lowcore.program_new_psw.addr =
+ PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
+
do_reset_calls();
}
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index 1eef5091861..8f0cbca3120 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -1,9 +1,9 @@
/*
* arch/s390/kernel/irq.c
*
- * S390 version
- * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2004,2007
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Thomas Spatzier (tspat@de.ibm.com)
*
* This file contains interrupt related functions.
*/
@@ -14,6 +14,8 @@
#include <linux/interrupt.h>
#include <linux/seq_file.h>
#include <linux/cpu.h>
+#include <linux/proc_fs.h>
+#include <linux/profile.h>
/*
* show_interrupts is needed by /proc/interrupts.
@@ -93,5 +95,12 @@ asmlinkage void do_softirq(void)
local_irq_restore(flags);
}
-
EXPORT_SYMBOL(do_softirq);
+
+void init_irq_proc(void)
+{
+ struct proc_dir_entry *root_irq_dir;
+
+ root_irq_dir = proc_mkdir("irq", NULL);
+ create_prof_cpu_mask(root_irq_dir);
+}
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 576368c4f60..a466bab6677 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -155,15 +155,34 @@ void __kprobes get_instruction_type(struct arch_specific_insn *ainsn)
static int __kprobes swap_instruction(void *aref)
{
struct ins_replace_args *args = aref;
+ u32 *addr;
+ u32 instr;
int err = -EFAULT;
+ /*
+ * Text segment is read-only, hence we use stura to bypass dynamic
+ * address translation to exchange the instruction. Since stura
+ * always operates on four bytes, but we only want to exchange two
+ * bytes do some calculations to get things right. In addition we
+ * shall not cross any page boundaries (vmalloc area!) when writing
+ * the new instruction.
+ */
+ addr = (u32 *)ALIGN((unsigned long)args->ptr, 4);
+ if ((unsigned long)args->ptr & 2)
+ instr = ((*addr) & 0xffff0000) | args->new;
+ else
+ instr = ((*addr) & 0x0000ffff) | args->new << 16;
+
asm volatile(
- "0: mvc 0(2,%2),0(%3)\n"
- "1: la %0,0\n"
+ " lra %1,0(%1)\n"
+ "0: stura %2,%1\n"
+ "1: la %0,0\n"
"2:\n"
EX_TABLE(0b,2b)
- : "+d" (err), "=m" (*args->ptr)
- : "a" (args->ptr), "a" (&args->new), "m" (args->new));
+ : "+d" (err)
+ : "a" (addr), "d" (instr)
+ : "memory", "cc");
+
return err;
}
@@ -356,7 +375,7 @@ no_kprobe:
* - When the probed function returns, this probe
* causes the handlers to fire
*/
-void __kprobes kretprobe_trampoline_holder(void)
+void kretprobe_trampoline_holder(void)
{
asm volatile(".global kretprobe_trampoline\n"
"kretprobe_trampoline: bcr 0,0\n");
@@ -365,7 +384,8 @@ void __kprobes kretprobe_trampoline_holder(void)
/*
* Called when the probe at kretprobe trampoline is hit
*/
-int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+static int __kprobes trampoline_probe_handler(struct kprobe *p,
+ struct pt_regs *regs)
{
struct kretprobe_instance *ri = NULL;
struct hlist_head *head, empty_rp;
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index f6d9bcc0f75..52f57af252b 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -11,6 +11,7 @@
#include <linux/mm.h>
#include <linux/kexec.h>
#include <linux/delay.h>
+#include <linux/reboot.h>
#include <asm/cio.h>
#include <asm/setup.h>
#include <asm/pgtable.h>
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index d989ed45a7a..39d1dd75252 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -30,6 +30,7 @@
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/moduleloader.h>
#if 0
#define DEBUGP printk
@@ -58,7 +59,7 @@ void module_free(struct module *mod, void *module_region)
table entries. */
}
-static inline void
+static void
check_rela(Elf_Rela *rela, struct module *me)
{
struct mod_arch_syminfo *info;
@@ -181,7 +182,7 @@ apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex,
return -ENOEXEC;
}
-static inline int
+static int
apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
struct module *me)
{
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 6603fbb41d0..5acfac654f9 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -144,7 +144,7 @@ static void default_idle(void)
trace_hardirqs_on();
/* Wait for external, I/O or machine check interrupt. */
- __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT |
+ __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
PSW_MASK_IO | PSW_MASK_EXT);
}
@@ -190,7 +190,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
struct pt_regs regs;
memset(&regs, 0, sizeof(regs));
- regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
+ regs.psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
regs.gprs[9] = (unsigned long) fn;
regs.gprs[10] = (unsigned long) arg;
diff --git a/arch/s390/kernel/profile.c b/arch/s390/kernel/profile.c
deleted file mode 100644
index b81aa1f569c..00000000000
--- a/arch/s390/kernel/profile.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * arch/s390/kernel/profile.c
- *
- * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
- *
- */
-#include <linux/proc_fs.h>
-#include <linux/profile.h>
-
-static struct proc_dir_entry * root_irq_dir;
-
-void init_irq_proc(void)
-{
- /* create /proc/irq */
- root_irq_dir = proc_mkdir("irq", NULL);
-
- /* create /proc/irq/prof_cpu_mask */
- create_prof_cpu_mask(root_irq_dir);
-}
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 8f36504075e..2a8f0872ea8 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -86,15 +86,13 @@ FixPerRegisters(struct task_struct *task)
per_info->control_regs.bits.storage_alt_space_ctl = 0;
}
-void
-set_single_step(struct task_struct *task)
+static void set_single_step(struct task_struct *task)
{
task->thread.per_info.single_step = 1;
FixPerRegisters(task);
}
-void
-clear_single_step(struct task_struct *task)
+static void clear_single_step(struct task_struct *task)
{
task->thread.per_info.single_step = 0;
FixPerRegisters(task);
@@ -232,9 +230,9 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
*/
if (addr == (addr_t) &dummy->regs.psw.mask &&
#ifdef CONFIG_COMPAT
- data != PSW_MASK_MERGE(PSW_USER32_BITS, data) &&
+ data != PSW_MASK_MERGE(psw_user32_bits, data) &&
#endif
- data != PSW_MASK_MERGE(PSW_USER_BITS, data))
+ data != PSW_MASK_MERGE(psw_user_bits, data))
/* Invalid psw mask. */
return -EINVAL;
#ifndef CONFIG_64BIT
@@ -309,7 +307,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
if (copied != sizeof(tmp))
return -EIO;
- return put_user(tmp, (unsigned long __user *) data);
+ return put_user(tmp, (unsigned long __force __user *) data);
case PTRACE_PEEKUSR:
/* read the word at location addr in the USER area. */
@@ -331,7 +329,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
case PTRACE_PEEKUSR_AREA:
case PTRACE_POKEUSR_AREA:
- if (copy_from_user(&parea, (void __user *) addr,
+ if (copy_from_user(&parea, (void __force __user *) addr,
sizeof(parea)))
return -EFAULT;
addr = parea.kernel_addr;
@@ -341,10 +339,11 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
if (request == PTRACE_PEEKUSR_AREA)
ret = peek_user(child, addr, data);
else {
- addr_t tmp;
- if (get_user (tmp, (addr_t __user *) data))
+ addr_t utmp;
+ if (get_user(utmp,
+ (addr_t __force __user *) data))
return -EFAULT;
- ret = poke_user(child, addr, tmp);
+ ret = poke_user(child, addr, utmp);
}
if (ret)
return ret;
@@ -394,7 +393,7 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
if (addr == (addr_t) &dummy32->regs.psw.mask) {
/* Fake a 31 bit psw mask. */
tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32);
- tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp);
+ tmp = PSW32_MASK_MERGE(psw32_user_bits, tmp);
} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
/* Fake a 31 bit psw address. */
tmp = (__u32) task_pt_regs(child)->psw.addr |
@@ -469,11 +468,11 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
*/
if (addr == (addr_t) &dummy32->regs.psw.mask) {
/* Build a 64 bit psw mask from 31 bit mask. */
- if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp))
+ if (tmp != PSW32_MASK_MERGE(psw32_user_bits, tmp))
/* Invalid psw mask. */
return -EINVAL;
task_pt_regs(child)->psw.mask =
- PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32);
+ PSW_MASK_MERGE(psw_user32_bits, (__u64) tmp << 32);
} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
/* Build a 64 bit psw address from 31 bit address. */
task_pt_regs(child)->psw.addr =
@@ -550,7 +549,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
if (copied != sizeof(tmp))
return -EIO;
- return put_user(tmp, (unsigned int __user *) data);
+ return put_user(tmp, (unsigned int __force __user *) data);
case PTRACE_PEEKUSR:
/* read the word at location addr in the USER area. */
@@ -571,7 +570,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
case PTRACE_PEEKUSR_AREA:
case PTRACE_POKEUSR_AREA:
- if (copy_from_user(&parea, (void __user *) addr,
+ if (copy_from_user(&parea, (void __force __user *) addr,
sizeof(parea)))
return -EFAULT;
addr = parea.kernel_addr;
@@ -581,10 +580,11 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
if (request == PTRACE_PEEKUSR_AREA)
ret = peek_user_emu31(child, addr, data);
else {
- __u32 tmp;
- if (get_user (tmp, (__u32 __user *) data))
+ __u32 utmp;
+ if (get_user(utmp,
+ (__u32 __force __user *) data))
return -EFAULT;
- ret = poke_user_emu31(child, addr, tmp);
+ ret = poke_user_emu31(child, addr, utmp);
}
if (ret)
return ret;
@@ -595,17 +595,19 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
return 0;
case PTRACE_GETEVENTMSG:
return put_user((__u32) child->ptrace_message,
- (unsigned int __user *) data);
+ (unsigned int __force __user *) data);
case PTRACE_GETSIGINFO:
if (child->last_siginfo == NULL)
return -EINVAL;
- return copy_siginfo_to_user32((compat_siginfo_t __user *) data,
+ return copy_siginfo_to_user32((compat_siginfo_t
+ __force __user *) data,
child->last_siginfo);
case PTRACE_SETSIGINFO:
if (child->last_siginfo == NULL)
return -EINVAL;
return copy_siginfo_from_user32(child->last_siginfo,
- (compat_siginfo_t __user *) data);
+ (compat_siginfo_t
+ __force __user *) data);
}
return ptrace_request(child, request, addr, data);
}
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
index f9434d42ce9..c3f4d9b9508 100644
--- a/arch/s390/kernel/reipl.S
+++ b/arch/s390/kernel/reipl.S
@@ -16,7 +16,7 @@ do_reipl_asm: basr %r13,0
stm %r0,%r15,__LC_GPREGS_SAVE_AREA
stctl %c0,%c15,__LC_CREGS_SAVE_AREA
stam %a0,%a15,__LC_AREGS_SAVE_AREA
- stpx __LC_PREFIX_SAVE_AREA
+ mvc __LC_PREFIX_SAVE_AREA(4),dump_prefix_page-.Lpg0(%r13)
stckc .Lclkcmp-.Lpg0(%r13)
mvc __LC_CLOCK_COMP_SAVE_AREA(8),.Lclkcmp-.Lpg0(%r13)
stpt __LC_CPU_TIMER_SAVE_AREA
@@ -79,3 +79,7 @@ do_reipl_asm: basr %r13,0
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
+ .globl dump_prefix_page
+dump_prefix_page:
+ .long 0x00000000
+
diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S
index f18ef260ca2..dbb3eed3886 100644
--- a/arch/s390/kernel/reipl64.S
+++ b/arch/s390/kernel/reipl64.S
@@ -20,7 +20,7 @@ do_reipl_asm: basr %r13,0
stg %r0,__LC_GPREGS_SAVE_AREA-0x1000+8(%r1)
stctg %c0,%c15,__LC_CREGS_SAVE_AREA-0x1000(%r1)
stam %a0,%a15,__LC_AREGS_SAVE_AREA-0x1000(%r1)
- stpx __LC_PREFIX_SAVE_AREA-0x1000(%r1)
+ mvc __LC_PREFIX_SAVE_AREA-0x1000(4,%r1),dump_prefix_page-.Lpg0(%r13)
stfpc __LC_FP_CREG_SAVE_AREA-0x1000(%r1)
stckc .Lclkcmp-.Lpg0(%r13)
mvc __LC_CLOCK_COMP_SAVE_AREA-0x1000(8,%r1),.Lclkcmp-.Lpg0(%r13)
@@ -103,3 +103,6 @@ do_reipl_asm: basr %r13,0
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
+ .globl dump_prefix_page
+dump_prefix_page:
+ .long 0x00000000
diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S
deleted file mode 100644
index be8688c0665..00000000000
--- a/arch/s390/kernel/reset.S
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * arch/s390/kernel/reset.S
- *
- * Copyright (C) IBM Corp. 2006
- * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
- */
-
-#include <asm/ptrace.h>
-#include <asm/lowcore.h>
-
-#ifdef CONFIG_64BIT
-
- .globl reset_mcck_handler
-reset_mcck_handler:
- basr %r13,0
-0: lg %r15,__LC_PANIC_STACK # load panic stack
- aghi %r15,-STACK_FRAME_OVERHEAD
- lg %r1,s390_reset_mcck_handler-0b(%r13)
- ltgr %r1,%r1
- jz 1f
- basr %r14,%r1
-1: la %r1,4095
- lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
- lpswe __LC_MCK_OLD_PSW
-
- .globl s390_reset_mcck_handler
-s390_reset_mcck_handler:
- .quad 0
-
-#else /* CONFIG_64BIT */
-
- .globl reset_mcck_handler
-reset_mcck_handler:
- basr %r13,0
-0: l %r15,__LC_PANIC_STACK # load panic stack
- ahi %r15,-STACK_FRAME_OVERHEAD
- l %r1,s390_reset_mcck_handler-0b(%r13)
- ltr %r1,%r1
- jz 1f
- basr %r14,%r1
-1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA
- lpsw __LC_MCK_OLD_PSW
-
- .globl s390_reset_mcck_handler
-s390_reset_mcck_handler:
- .long 0
-
-#endif /* CONFIG_64BIT */
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
index 4faf96f8a83..acf93dba772 100644
--- a/arch/s390/kernel/s390_ext.c
+++ b/arch/s390/kernel/s390_ext.c
@@ -37,7 +37,7 @@ int register_external_interrupt(__u16 code, ext_int_handler_t handler)
ext_int_info_t *p;
int index;
- p = (ext_int_info_t *) kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
+ p = kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
if (p == NULL)
return -ENOMEM;
p->code = code;
@@ -125,14 +125,12 @@ 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();
+ account_ticks(S390_lowcore.int_clock);
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(code);
- }
+ if (likely(p->code == code))
+ p->handler(code);
}
irq_exit();
set_irq_regs(old_regs);
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index b928fecdc74..03739813d3b 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -38,6 +38,8 @@
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/pfn.h>
+#include <linux/ctype.h>
+#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -49,6 +51,14 @@
#include <asm/page.h>
#include <asm/ptrace.h>
#include <asm/sections.h>
+#include <asm/ebcdic.h>
+#include <asm/compat.h>
+
+long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
+ PSW_MASK_MCHECK | PSW_DEFAULT_KEY);
+long psw_user_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+ PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
/*
* User copy operations.
@@ -64,9 +74,8 @@ unsigned int console_devno = -1;
unsigned int console_irq = -1;
unsigned long machine_flags = 0;
-struct mem_chunk memory_chunk[MEMORY_CHUNKS];
+struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
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;
/*
@@ -118,9 +127,9 @@ void __devinit cpu_init (void)
*/
char vmhalt_cmd[128] = "";
char vmpoff_cmd[128] = "";
-char vmpanic_cmd[128] = "";
+static char vmpanic_cmd[128] = "";
-static inline void strncpy_skip_quote(char *dst, char *src, int n)
+static void strncpy_skip_quote(char *dst, char *src, int n)
{
int sx, dx;
@@ -276,10 +285,6 @@ static void __init conmode_default(void)
}
#ifdef CONFIG_SMP
-extern void machine_restart_smp(char *);
-extern void machine_halt_smp(void);
-extern void machine_power_off_smp(void);
-
void (*_machine_restart)(char *command) = machine_restart_smp;
void (*_machine_halt)(void) = machine_halt_smp;
void (*_machine_power_off)(void) = machine_power_off_smp;
@@ -354,21 +359,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);
@@ -402,6 +392,84 @@ static int __init early_parse_ipldelay(char *p)
}
early_param("ipldelay", early_parse_ipldelay);
+#ifdef CONFIG_S390_SWITCH_AMODE
+unsigned int switch_amode = 0;
+EXPORT_SYMBOL_GPL(switch_amode);
+
+static void set_amode_and_uaccess(unsigned long user_amode,
+ unsigned long user32_amode)
+{
+ psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode |
+ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+ PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
+#ifdef CONFIG_COMPAT
+ psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode |
+ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+ PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
+ psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode |
+ PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
+ PSW32_MASK_PSTATE;
+#endif
+ psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+ PSW_MASK_MCHECK | PSW_DEFAULT_KEY;
+
+ if (MACHINE_HAS_MVCOS) {
+ printk("mvcos available.\n");
+ memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess));
+ } else {
+ printk("mvcos not available.\n");
+ memcpy(&uaccess, &uaccess_pt, sizeof(uaccess));
+ }
+}
+
+/*
+ * Switch kernel/user addressing modes?
+ */
+static int __init early_parse_switch_amode(char *p)
+{
+ switch_amode = 1;
+ return 0;
+}
+early_param("switch_amode", early_parse_switch_amode);
+
+#else /* CONFIG_S390_SWITCH_AMODE */
+static inline void set_amode_and_uaccess(unsigned long user_amode,
+ unsigned long user32_amode)
+{
+}
+#endif /* CONFIG_S390_SWITCH_AMODE */
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+unsigned int s390_noexec = 0;
+EXPORT_SYMBOL_GPL(s390_noexec);
+
+/*
+ * Enable execute protection?
+ */
+static int __init early_parse_noexec(char *p)
+{
+ if (!strncmp(p, "off", 3))
+ return 0;
+ switch_amode = 1;
+ s390_noexec = 1;
+ return 0;
+}
+early_param("noexec", early_parse_noexec);
+#endif /* CONFIG_S390_EXEC_PROTECT */
+
+static void setup_addressing_mode(void)
+{
+ if (s390_noexec) {
+ printk("S390 execute protection active, ");
+ set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY);
+ return;
+ }
+ if (switch_amode) {
+ printk("S390 address spaces switched, ");
+ set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY);
+ }
+}
+
static void __init
setup_lowcore(void)
{
@@ -418,19 +486,21 @@ setup_lowcore(void)
lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
lc->restart_psw.addr =
PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
- lc->external_new_psw.mask = PSW_KERNEL_BITS;
+ if (switch_amode)
+ lc->restart_psw.mask |= PSW_ASC_HOME;
+ lc->external_new_psw.mask = psw_kernel_bits;
lc->external_new_psw.addr =
PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
- lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
+ lc->svc_new_psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
- lc->program_new_psw.mask = PSW_KERNEL_BITS;
+ lc->program_new_psw.mask = psw_kernel_bits;
lc->program_new_psw.addr =
PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
lc->mcck_new_psw.mask =
- PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
+ psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
lc->mcck_new_psw.addr =
PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
- lc->io_new_psw.mask = PSW_KERNEL_BITS;
+ lc->io_new_psw.mask = psw_kernel_bits;
lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
lc->ipl_device = S390_lowcore.ipl_device;
lc->jiffy_timer = -1LL;
@@ -455,7 +525,7 @@ setup_lowcore(void)
static void __init
setup_resources(void)
{
- struct resource *res;
+ struct resource *res, *sub_res;
int i;
code_resource.start = (unsigned long) &_text;
@@ -480,8 +550,38 @@ setup_resources(void)
res->start = memory_chunk[i].addr;
res->end = memory_chunk[i].addr + memory_chunk[i].size - 1;
request_resource(&iomem_resource, res);
- request_resource(res, &code_resource);
- request_resource(res, &data_resource);
+
+ if (code_resource.start >= res->start &&
+ code_resource.start <= res->end &&
+ code_resource.end > res->end) {
+ sub_res = alloc_bootmem_low(sizeof(struct resource));
+ memcpy(sub_res, &code_resource,
+ sizeof(struct resource));
+ sub_res->end = res->end;
+ code_resource.start = res->end + 1;
+ request_resource(res, sub_res);
+ }
+
+ if (code_resource.start >= res->start &&
+ code_resource.start <= res->end &&
+ code_resource.end <= res->end)
+ request_resource(res, &code_resource);
+
+ if (data_resource.start >= res->start &&
+ data_resource.start <= res->end &&
+ data_resource.end > res->end) {
+ sub_res = alloc_bootmem_low(sizeof(struct resource));
+ memcpy(sub_res, &data_resource,
+ sizeof(struct resource));
+ sub_res->end = res->end;
+ data_resource.start = res->end + 1;
+ request_resource(res, sub_res);
+ }
+
+ if (data_resource.start >= res->start &&
+ data_resource.start <= res->end &&
+ data_resource.end <= res->end)
+ request_resource(res, &data_resource);
}
}
@@ -492,7 +592,7 @@ static void __init setup_memory_end(void)
int i;
memory_size = real_size = 0;
- max_phys = VMALLOC_END - VMALLOC_MIN_SIZE;
+ max_phys = VMALLOC_END_INIT - VMALLOC_MIN_SIZE;
memory_end &= PAGE_MASK;
max_mem = memory_end ? min(max_phys, memory_end) : max_phys;
@@ -511,17 +611,13 @@ static void __init setup_memory_end(void)
}
if (!memory_end)
memory_end = memory_size;
- if (real_size > memory_end)
- printk("More memory detected than supported. Unused: %luk\n",
- (real_size - memory_end) >> 10);
}
static void __init
setup_memory(void)
{
unsigned long bootmap_size;
- unsigned long start_pfn, end_pfn, init_pfn;
- unsigned long last_rw_end;
+ unsigned long start_pfn, end_pfn;
int i;
/*
@@ -531,10 +627,6 @@ setup_memory(void)
start_pfn = PFN_UP(__pa(&_end));
end_pfn = max_pfn = PFN_DOWN(memory_end);
- /* Initialize storage key for kernel pages */
- for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++)
- page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
-
#ifdef CONFIG_BLK_DEV_INITRD
/*
* Move the initrd in case the bitmap of the bootmem allocater
@@ -577,39 +669,27 @@ setup_memory(void)
/*
* 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
@@ -680,6 +760,7 @@ setup_arch(char **cmdline_p)
parse_early_param();
setup_memory_end();
+ setup_addressing_mode();
setup_memory();
setup_resources();
setup_lowcore();
@@ -723,6 +804,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
struct cpuinfo_S390 *cpuinfo;
unsigned long n = (unsigned long) v - 1;
+ s390_adjust_jiffies();
preempt_disable();
if (!n) {
seq_printf(m, "vendor_id : IBM/S390\n"
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 4c8a7954ef4..554f9cf7499 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -119,7 +119,7 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
/* Copy a 'clean' PSW mask to the user to avoid leaking
information about whether PER is currently on. */
- user_sregs.regs.psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.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,
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 19090f7d4f5..65b52320d14 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -22,23 +22,23 @@
#include <linux/module.h>
#include <linux/init.h>
-
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/kernel_stat.h>
#include <linux/smp_lock.h>
-
#include <linux/delay.h>
#include <linux/cache.h>
#include <linux/interrupt.h>
#include <linux/cpu.h>
-
+#include <linux/timex.h>
+#include <asm/setup.h>
#include <asm/sigp.h>
#include <asm/pgalloc.h>
#include <asm/irq.h>
#include <asm/s390_ext.h>
#include <asm/cpcmd.h>
#include <asm/tlbflush.h>
+#include <asm/timer.h>
extern volatile int __cpu_logical_map[];
@@ -53,12 +53,6 @@ cpumask_t cpu_possible_map = CPU_MASK_NONE;
static struct task_struct *current_set[NR_CPUS];
-/*
- * Reboot, halt and power_off routines for SMP.
- */
-extern char vmhalt_cmd[];
-extern char vmpoff_cmd[];
-
static void smp_ext_bitcall(int, ec_bit_sig);
static void smp_ext_bitcall_others(ec_bit_sig);
@@ -200,7 +194,7 @@ int smp_call_function_on(void (*func) (void *info), void *info,
}
EXPORT_SYMBOL(smp_call_function_on);
-static inline void do_send_stop(void)
+static void do_send_stop(void)
{
int cpu, rc;
@@ -214,7 +208,7 @@ static inline void do_send_stop(void)
}
}
-static inline void do_store_status(void)
+static void do_store_status(void)
{
int cpu, rc;
@@ -230,7 +224,7 @@ static inline void do_store_status(void)
}
}
-static inline void do_wait_for_stop(void)
+static void do_wait_for_stop(void)
{
int cpu;
@@ -250,7 +244,7 @@ static inline void do_wait_for_stop(void)
void smp_send_stop(void)
{
/* Disable all interrupts/machine checks */
- __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK);
+ __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
/* write magic number to zero page (absolute 0) */
lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
@@ -298,7 +292,7 @@ void machine_power_off_smp(void)
* cpus are handled.
*/
-void do_ext_call_interrupt(__u16 code)
+static void do_ext_call_interrupt(__u16 code)
{
unsigned long bits;
@@ -385,7 +379,7 @@ struct ec_creg_mask_parms {
/*
* callback for setting/clearing control bits
*/
-void smp_ctl_bit_callback(void *info) {
+static void smp_ctl_bit_callback(void *info) {
struct ec_creg_mask_parms *pp = info;
unsigned long cregs[16];
int i;
@@ -458,17 +452,15 @@ __init smp_count_cpus(void)
/*
* Activate a secondary processor.
*/
-extern void init_cpu_timer(void);
-extern void init_cpu_vtimer(void);
-
int __devinit start_secondary(void *cpuvoid)
{
/* Setup the cpu */
cpu_init();
preempt_disable();
- /* init per CPU timer */
+ /* Enable TOD clock interrupts on the secondary cpu. */
init_cpu_timer();
#ifdef CONFIG_VIRT_TIMER
+ /* Enable cpu timer interrupts on the secondary cpu. */
init_cpu_vtimer();
#endif
/* Enable pfault pseudo page faults on this cpu. */
@@ -542,7 +534,7 @@ smp_put_cpu(int cpu)
spin_unlock_irqrestore(&smp_reserve_lock, flags);
}
-static inline int
+static int
cpu_stopped(int cpu)
{
__u32 status;
@@ -794,7 +786,10 @@ static int __init topology_init(void)
int ret;
for_each_possible_cpu(cpu) {
- ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu);
+ struct cpu *c = &per_cpu(cpu_devices, cpu);
+
+ c->hotpluggable = 1;
+ ret = register_cpu(c, cpu);
if (ret)
printk(KERN_WARNING "topology_init: register_cpu %d "
"failed (%d)\n", cpu, ret);
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c
index 0d14a4789bf..2e5c65a1863 100644
--- a/arch/s390/kernel/stacktrace.c
+++ b/arch/s390/kernel/stacktrace.c
@@ -11,11 +11,11 @@
#include <linux/stacktrace.h>
#include <linux/kallsyms.h>
-static inline unsigned long save_context_stack(struct stack_trace *trace,
- unsigned int *skip,
- unsigned long sp,
- unsigned long low,
- unsigned long high)
+static unsigned long save_context_stack(struct stack_trace *trace,
+ unsigned int *skip,
+ unsigned long sp,
+ unsigned long low,
+ unsigned long high)
{
struct stack_frame *sf;
struct pt_regs *regs;
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 6cceed4df73..3b91f27ab20 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -37,11 +37,15 @@
#include <asm/irq.h>
#include <asm/irq_regs.h>
#include <asm/timer.h>
+#include <asm/etr.h>
/* change this if you have some constant time drift */
#define USECS_PER_JIFFY ((unsigned long) 1000000/HZ)
#define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
+/* The value of the TOD clock for 1.1.1970. */
+#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
+
/*
* Create a small time difference between the timer interrupts
* on the different cpus to avoid lock contention.
@@ -51,6 +55,7 @@
#define TICK_SIZE tick
static ext_int_info_t ext_int_info_cc;
+static ext_int_info_t ext_int_etr_cc;
static u64 init_timer_cc;
static u64 jiffies_timer_cc;
static u64 xtime_cc;
@@ -89,29 +94,21 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime)
#define s390_do_profile() do { ; } while(0)
#endif /* CONFIG_PROFILING */
-
/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * Advance the per cpu tick counter up to the time given with the
+ * "time" argument. The per cpu update consists of accounting
+ * the virtual cpu time, calling update_process_times and calling
+ * the profiling hook. If xtime is before time it is advanced as well.
*/
-void account_ticks(void)
+void account_ticks(u64 time)
{
- __u64 tmp;
__u32 ticks;
+ __u64 tmp;
/* Calculate how many ticks have passed. */
- if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) {
- /*
- * We have to program the clock comparator even if
- * no tick has passed. That happens if e.g. an i/o
- * interrupt wakes up an idle processor that has
- * switched off its hz timer.
- */
- tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
- asm volatile ("SCKC %0" : : "m" (tmp));
+ if (time < S390_lowcore.jiffy_timer)
return;
- }
- tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer;
+ tmp = time - S390_lowcore.jiffy_timer;
if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */
ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1;
S390_lowcore.jiffy_timer +=
@@ -124,10 +121,6 @@ void account_ticks(void)
S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
}
- /* set clock comparator for next tick */
- tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
- asm volatile ("SCKC %0" : : "m" (tmp));
-
#ifdef CONFIG_SMP
/*
* Do not rely on the boot cpu to do the calls to do_timer.
@@ -173,7 +166,7 @@ int sysctl_hz_timer = 1;
* Stop the HZ tick on the current CPU.
* Only cpu_idle may call this function.
*/
-static inline void stop_hz_timer(void)
+static void stop_hz_timer(void)
{
unsigned long flags;
unsigned long seq, next;
@@ -210,20 +203,21 @@ static inline void stop_hz_timer(void)
if (timer >= jiffies_timer_cc)
todval = timer;
}
- asm volatile ("SCKC %0" : : "m" (todval));
+ set_clock_comparator(todval);
}
/*
* Start the HZ tick on the current CPU.
* Only cpu_idle may call this function.
*/
-static inline void start_hz_timer(void)
+static void start_hz_timer(void)
{
BUG_ON(!in_interrupt());
if (!cpu_isset(smp_processor_id(), nohz_cpu_mask))
return;
- account_ticks();
+ account_ticks(get_clock());
+ set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
cpu_clear(smp_processor_id(), nohz_cpu_mask);
}
@@ -245,7 +239,7 @@ static struct notifier_block nohz_idle_nb = {
.notifier_call = nohz_idle_notify,
};
-void __init nohz_init(void)
+static void __init nohz_init(void)
{
if (register_idle_notifier(&nohz_idle_nb))
panic("Couldn't register idle notifier");
@@ -254,24 +248,57 @@ void __init nohz_init(void)
#endif
/*
- * Start the clock comparator on the current CPU.
+ * Set up per cpu jiffy timer and set the clock comparator.
+ */
+static void setup_jiffy_timer(void)
+{
+ /* Set up clock comparator to next jiffy. */
+ S390_lowcore.jiffy_timer =
+ jiffies_timer_cc + (jiffies_64 + 1) * CLK_TICKS_PER_JIFFY;
+ set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
+}
+
+/*
+ * Set up lowcore and control register of the current cpu to
+ * enable TOD clock and clock comparator interrupts.
*/
void init_cpu_timer(void)
{
- unsigned long cr0;
- __u64 timer;
+ setup_jiffy_timer();
- timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY;
- S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY;
- timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION;
- asm volatile ("SCKC %0" : : "m" (timer));
- /* allow clock comparator timer interrupt */
- __ctl_store(cr0, 0, 0);
- cr0 |= 0x800;
- __ctl_load(cr0, 0, 0);
+ /* Enable clock comparator timer interrupt. */
+ __ctl_set_bit(0,11);
+
+ /* Always allow ETR external interrupts, even without an ETR. */
+ __ctl_set_bit(0, 4);
}
-extern void vtime_init(void);
+static void clock_comparator_interrupt(__u16 code)
+{
+ /* set clock comparator for next tick */
+ set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
+}
+
+static void etr_reset(void);
+static void etr_init(void);
+static void etr_ext_handler(__u16);
+
+/*
+ * Get the TOD clock running.
+ */
+static u64 __init reset_tod_clock(void)
+{
+ u64 time;
+
+ etr_reset();
+ if (store_clock(&time) == 0)
+ return time;
+ /* TOD clock not running. Set the clock to Unix Epoch. */
+ if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0)
+ panic("TOD clock not operational.");
+
+ return TOD_UNIX_EPOCH;
+}
static cycle_t read_tod_clock(void)
{
@@ -295,48 +322,31 @@ static struct clocksource clocksource_tod = {
*/
void __init time_init(void)
{
- __u64 set_time_cc;
- int cc;
-
- /* kick the TOD clock */
- 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;
- case 1: /* clock in non-set state: FIXME */
- printk("time_init: TOD clock in non-set state\n");
- break;
- case 2: /* clock in error state: FIXME */
- printk("time_init: TOD clock in error state\n");
- break;
- case 3: /* clock in stopped or not-operational state: FIXME */
- printk("time_init: TOD clock stopped/non-operational\n");
- break;
- }
+ init_timer_cc = reset_tod_clock();
+ xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY;
/* set xtime */
- xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
- set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
- (0x3c26700LL*1000000*4096);
- tod_to_timeval(set_time_cc, &xtime);
+ tod_to_timeval(init_timer_cc - TOD_UNIX_EPOCH, &xtime);
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
/* request the clock comparator external interrupt */
- if (register_early_external_interrupt(0x1004, NULL,
+ if (register_early_external_interrupt(0x1004,
+ clock_comparator_interrupt,
&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();
+ /* request the etr external interrupt */
+ if (register_early_external_interrupt(0x1406, etr_ext_handler,
+ &ext_int_etr_cc) != 0)
+ panic("Couldn't request external interrupt 0x1406");
+
+ /* Enable TOD clock interrupts on the boot cpu. */
+ init_cpu_timer();
#ifdef CONFIG_NO_IDLE_HZ
nohz_init();
@@ -345,5 +355,1048 @@ void __init time_init(void)
#ifdef CONFIG_VIRT_TIMER
vtime_init();
#endif
+ etr_init();
+}
+
+/*
+ * External Time Reference (ETR) code.
+ */
+static int etr_port0_online;
+static int etr_port1_online;
+
+static int __init early_parse_etr(char *p)
+{
+ if (strncmp(p, "off", 3) == 0)
+ etr_port0_online = etr_port1_online = 0;
+ else if (strncmp(p, "port0", 5) == 0)
+ etr_port0_online = 1;
+ else if (strncmp(p, "port1", 5) == 0)
+ etr_port1_online = 1;
+ else if (strncmp(p, "on", 2) == 0)
+ etr_port0_online = etr_port1_online = 1;
+ return 0;
+}
+early_param("etr", early_parse_etr);
+
+enum etr_event {
+ ETR_EVENT_PORT0_CHANGE,
+ ETR_EVENT_PORT1_CHANGE,
+ ETR_EVENT_PORT_ALERT,
+ ETR_EVENT_SYNC_CHECK,
+ ETR_EVENT_SWITCH_LOCAL,
+ ETR_EVENT_UPDATE,
+};
+
+enum etr_flags {
+ ETR_FLAG_ENOSYS,
+ ETR_FLAG_EACCES,
+ ETR_FLAG_STEAI,
+};
+
+/*
+ * Valid bit combinations of the eacr register are (x = don't care):
+ * e0 e1 dp p0 p1 ea es sl
+ * 0 0 x 0 0 0 0 0 initial, disabled state
+ * 0 0 x 0 1 1 0 0 port 1 online
+ * 0 0 x 1 0 1 0 0 port 0 online
+ * 0 0 x 1 1 1 0 0 both ports online
+ * 0 1 x 0 1 1 0 0 port 1 online and usable, ETR or PPS mode
+ * 0 1 x 0 1 1 0 1 port 1 online, usable and ETR mode
+ * 0 1 x 0 1 1 1 0 port 1 online, usable, PPS mode, in-sync
+ * 0 1 x 0 1 1 1 1 port 1 online, usable, ETR mode, in-sync
+ * 0 1 x 1 1 1 0 0 both ports online, port 1 usable
+ * 0 1 x 1 1 1 1 0 both ports online, port 1 usable, PPS mode, in-sync
+ * 0 1 x 1 1 1 1 1 both ports online, port 1 usable, ETR mode, in-sync
+ * 1 0 x 1 0 1 0 0 port 0 online and usable, ETR or PPS mode
+ * 1 0 x 1 0 1 0 1 port 0 online, usable and ETR mode
+ * 1 0 x 1 0 1 1 0 port 0 online, usable, PPS mode, in-sync
+ * 1 0 x 1 0 1 1 1 port 0 online, usable, ETR mode, in-sync
+ * 1 0 x 1 1 1 0 0 both ports online, port 0 usable
+ * 1 0 x 1 1 1 1 0 both ports online, port 0 usable, PPS mode, in-sync
+ * 1 0 x 1 1 1 1 1 both ports online, port 0 usable, ETR mode, in-sync
+ * 1 1 x 1 1 1 1 0 both ports online & usable, ETR, in-sync
+ * 1 1 x 1 1 1 1 1 both ports online & usable, ETR, in-sync
+ */
+static struct etr_eacr etr_eacr;
+static u64 etr_tolec; /* time of last eacr update */
+static unsigned long etr_flags;
+static struct etr_aib etr_port0;
+static int etr_port0_uptodate;
+static struct etr_aib etr_port1;
+static int etr_port1_uptodate;
+static unsigned long etr_events;
+static struct timer_list etr_timer;
+static struct tasklet_struct etr_tasklet;
+static DEFINE_PER_CPU(atomic_t, etr_sync_word);
+
+static void etr_timeout(unsigned long dummy);
+static void etr_tasklet_fn(unsigned long dummy);
+
+/*
+ * The etr get_clock function. It will write the current clock value
+ * to the clock pointer and return 0 if the clock is in sync with the
+ * external time source. If the clock mode is local it will return
+ * -ENOSYS and -EAGAIN if the clock is not in sync with the external
+ * reference. This function is what ETR is all about..
+ */
+int get_sync_clock(unsigned long long *clock)
+{
+ atomic_t *sw_ptr;
+ unsigned int sw0, sw1;
+
+ sw_ptr = &get_cpu_var(etr_sync_word);
+ sw0 = atomic_read(sw_ptr);
+ *clock = get_clock();
+ sw1 = atomic_read(sw_ptr);
+ put_cpu_var(etr_sync_sync);
+ if (sw0 == sw1 && (sw0 & 0x80000000U))
+ /* Success: time is in sync. */
+ return 0;
+ if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+ return -ENOSYS;
+ if (test_bit(ETR_FLAG_EACCES, &etr_flags))
+ return -EACCES;
+ return -EAGAIN;
+}
+EXPORT_SYMBOL(get_sync_clock);
+
+/*
+ * Make get_sync_clock return -EAGAIN.
+ */
+static void etr_disable_sync_clock(void *dummy)
+{
+ atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
+ /*
+ * Clear the in-sync bit 2^31. All get_sync_clock calls will
+ * fail until the sync bit is turned back on. In addition
+ * increase the "sequence" counter to avoid the race of an
+ * etr event and the complete recovery against get_sync_clock.
+ */
+ atomic_clear_mask(0x80000000, sw_ptr);
+ atomic_inc(sw_ptr);
+}
+
+/*
+ * Make get_sync_clock return 0 again.
+ * Needs to be called from a context disabled for preemption.
+ */
+static void etr_enable_sync_clock(void)
+{
+ atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
+ atomic_set_mask(0x80000000, sw_ptr);
+}
+
+/*
+ * Reset ETR attachment.
+ */
+static void etr_reset(void)
+{
+ etr_eacr = (struct etr_eacr) {
+ .e0 = 0, .e1 = 0, ._pad0 = 4, .dp = 0,
+ .p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0,
+ .es = 0, .sl = 0 };
+ if (etr_setr(&etr_eacr) == 0)
+ etr_tolec = get_clock();
+ else {
+ set_bit(ETR_FLAG_ENOSYS, &etr_flags);
+ if (etr_port0_online || etr_port1_online) {
+ printk(KERN_WARNING "Running on non ETR capable "
+ "machine, only local mode available.\n");
+ etr_port0_online = etr_port1_online = 0;
+ }
+ }
+}
+
+static void etr_init(void)
+{
+ struct etr_aib aib;
+
+ if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+ return;
+ /* Check if this machine has the steai instruction. */
+ if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0)
+ set_bit(ETR_FLAG_STEAI, &etr_flags);
+ setup_timer(&etr_timer, etr_timeout, 0UL);
+ tasklet_init(&etr_tasklet, etr_tasklet_fn, 0);
+ if (!etr_port0_online && !etr_port1_online)
+ set_bit(ETR_FLAG_EACCES, &etr_flags);
+ if (etr_port0_online) {
+ set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+ tasklet_hi_schedule(&etr_tasklet);
+ }
+ if (etr_port1_online) {
+ set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+ tasklet_hi_schedule(&etr_tasklet);
+ }
+}
+
+/*
+ * Two sorts of ETR machine checks. The architecture reads:
+ * "When a machine-check niterruption occurs and if a switch-to-local or
+ * ETR-sync-check interrupt request is pending but disabled, this pending
+ * disabled interruption request is indicated and is cleared".
+ * Which means that we can get etr_switch_to_local events from the machine
+ * check handler although the interruption condition is disabled. Lovely..
+ */
+
+/*
+ * Switch to local machine check. This is called when the last usable
+ * ETR port goes inactive. After switch to local the clock is not in sync.
+ */
+void etr_switch_to_local(void)
+{
+ if (!etr_eacr.sl)
+ return;
+ etr_disable_sync_clock(NULL);
+ set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events);
+ tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * ETR sync check machine check. This is called when the ETR OTE and the
+ * local clock OTE are farther apart than the ETR sync check tolerance.
+ * After a ETR sync check the clock is not in sync. The machine check
+ * is broadcasted to all cpus at the same time.
+ */
+void etr_sync_check(void)
+{
+ if (!etr_eacr.es)
+ return;
+ etr_disable_sync_clock(NULL);
+ set_bit(ETR_EVENT_SYNC_CHECK, &etr_events);
+ tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * ETR external interrupt. There are two causes:
+ * 1) port state change, check the usability of the port
+ * 2) port alert, one of the ETR-data-validity bits (v1-v2 bits of the
+ * sldr-status word) or ETR-data word 1 (edf1) or ETR-data word 3 (edf3)
+ * or ETR-data word 4 (edf4) has changed.
+ */
+static void etr_ext_handler(__u16 code)
+{
+ struct etr_interruption_parameter *intparm =
+ (struct etr_interruption_parameter *) &S390_lowcore.ext_params;
+
+ if (intparm->pc0)
+ /* ETR port 0 state change. */
+ set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+ if (intparm->pc1)
+ /* ETR port 1 state change. */
+ set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+ if (intparm->eai)
+ /*
+ * ETR port alert on either port 0, 1 or both.
+ * Both ports are not up-to-date now.
+ */
+ set_bit(ETR_EVENT_PORT_ALERT, &etr_events);
+ tasklet_hi_schedule(&etr_tasklet);
+}
+
+static void etr_timeout(unsigned long dummy)
+{
+ set_bit(ETR_EVENT_UPDATE, &etr_events);
+ tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * Check if the etr mode is pss.
+ */
+static inline int etr_mode_is_pps(struct etr_eacr eacr)
+{
+ return eacr.es && !eacr.sl;
+}
+
+/*
+ * Check if the etr mode is etr.
+ */
+static inline int etr_mode_is_etr(struct etr_eacr eacr)
+{
+ return eacr.es && eacr.sl;
+}
+
+/*
+ * Check if the port can be used for TOD synchronization.
+ * For PPS mode the port has to receive OTEs. For ETR mode
+ * the port has to receive OTEs, the ETR stepping bit has to
+ * be zero and the validity bits for data frame 1, 2, and 3
+ * have to be 1.
+ */
+static int etr_port_valid(struct etr_aib *aib, int port)
+{
+ unsigned int psc;
+
+ /* Check that this port is receiving OTEs. */
+ if (aib->tsp == 0)
+ return 0;
+
+ psc = port ? aib->esw.psc1 : aib->esw.psc0;
+ if (psc == etr_lpsc_pps_mode)
+ return 1;
+ if (psc == etr_lpsc_operational_step)
+ return !aib->esw.y && aib->slsw.v1 &&
+ aib->slsw.v2 && aib->slsw.v3;
+ return 0;
+}
+
+/*
+ * Check if two ports are on the same network.
+ */
+static int etr_compare_network(struct etr_aib *aib1, struct etr_aib *aib2)
+{
+ // FIXME: any other fields we have to compare?
+ return aib1->edf1.net_id == aib2->edf1.net_id;
+}
+
+/*
+ * Wrapper for etr_stei that converts physical port states
+ * to logical port states to be consistent with the output
+ * of stetr (see etr_psc vs. etr_lpsc).
+ */
+static void etr_steai_cv(struct etr_aib *aib, unsigned int func)
+{
+ BUG_ON(etr_steai(aib, func) != 0);
+ /* Convert port state to logical port state. */
+ if (aib->esw.psc0 == 1)
+ aib->esw.psc0 = 2;
+ else if (aib->esw.psc0 == 0 && aib->esw.p == 0)
+ aib->esw.psc0 = 1;
+ if (aib->esw.psc1 == 1)
+ aib->esw.psc1 = 2;
+ else if (aib->esw.psc1 == 0 && aib->esw.p == 1)
+ aib->esw.psc1 = 1;
+}
+
+/*
+ * Check if the aib a2 is still connected to the same attachment as
+ * aib a1, the etv values differ by one and a2 is valid.
+ */
+static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p)
+{
+ int state_a1, state_a2;
+
+ /* Paranoia check: e0/e1 should better be the same. */
+ if (a1->esw.eacr.e0 != a2->esw.eacr.e0 ||
+ a1->esw.eacr.e1 != a2->esw.eacr.e1)
+ return 0;
+
+ /* Still connected to the same etr ? */
+ state_a1 = p ? a1->esw.psc1 : a1->esw.psc0;
+ state_a2 = p ? a2->esw.psc1 : a2->esw.psc0;
+ if (state_a1 == etr_lpsc_operational_step) {
+ if (state_a2 != etr_lpsc_operational_step ||
+ a1->edf1.net_id != a2->edf1.net_id ||
+ a1->edf1.etr_id != a2->edf1.etr_id ||
+ a1->edf1.etr_pn != a2->edf1.etr_pn)
+ return 0;
+ } else if (state_a2 != etr_lpsc_pps_mode)
+ return 0;
+
+ /* The ETV value of a2 needs to be ETV of a1 + 1. */
+ if (a1->edf2.etv + 1 != a2->edf2.etv)
+ return 0;
+
+ if (!etr_port_valid(a2, p))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * The time is "clock". xtime is what we think the time is.
+ * Adjust the value by a multiple of jiffies and add the delta to ntp.
+ * "delay" is an approximation how long the synchronization took. If
+ * the time correction is positive, then "delay" is subtracted from
+ * the time difference and only the remaining part is passed to ntp.
+ */
+static void etr_adjust_time(unsigned long long clock, unsigned long long delay)
+{
+ unsigned long long delta, ticks;
+ struct timex adjust;
+
+ /*
+ * We don't have to take the xtime lock because the cpu
+ * executing etr_adjust_time is running disabled in
+ * tasklet context and all other cpus are looping in
+ * etr_sync_cpu_start.
+ */
+ if (clock > xtime_cc) {
+ /* It is later than we thought. */
+ delta = ticks = clock - xtime_cc;
+ delta = ticks = (delta < delay) ? 0 : delta - delay;
+ delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+ init_timer_cc = init_timer_cc + delta;
+ jiffies_timer_cc = jiffies_timer_cc + delta;
+ xtime_cc = xtime_cc + delta;
+ adjust.offset = ticks * (1000000 / HZ);
+ } else {
+ /* It is earlier than we thought. */
+ delta = ticks = xtime_cc - clock;
+ delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+ init_timer_cc = init_timer_cc - delta;
+ jiffies_timer_cc = jiffies_timer_cc - delta;
+ xtime_cc = xtime_cc - delta;
+ adjust.offset = -ticks * (1000000 / HZ);
+ }
+ if (adjust.offset != 0) {
+ printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n",
+ adjust.offset);
+ adjust.modes = ADJ_OFFSET_SINGLESHOT;
+ do_adjtimex(&adjust);
+ }
+}
+
+static void etr_sync_cpu_start(void *dummy)
+{
+ int *in_sync = dummy;
+
+ etr_enable_sync_clock();
+ /*
+ * This looks like a busy wait loop but it isn't. etr_sync_cpus
+ * is called on all other cpus while the TOD clocks is stopped.
+ * __udelay will stop the cpu on an enabled wait psw until the
+ * TOD is running again.
+ */
+ while (*in_sync == 0)
+ __udelay(1);
+ if (*in_sync != 1)
+ /* Didn't work. Clear per-cpu in sync bit again. */
+ etr_disable_sync_clock(NULL);
+ /*
+ * This round of TOD syncing is done. Set the clock comparator
+ * to the next tick and let the processor continue.
+ */
+ setup_jiffy_timer();
+}
+
+static void etr_sync_cpu_end(void *dummy)
+{
+}
+
+/*
+ * Sync the TOD clock using the port refered to by aibp. This port
+ * has to be enabled and the other port has to be disabled. The
+ * last eacr update has to be more than 1.6 seconds in the past.
+ */
+static int etr_sync_clock(struct etr_aib *aib, int port)
+{
+ struct etr_aib *sync_port;
+ unsigned long long clock, delay;
+ int in_sync, follows;
+ int rc;
+
+ /* Check if the current aib is adjacent to the sync port aib. */
+ sync_port = (port == 0) ? &etr_port0 : &etr_port1;
+ follows = etr_aib_follows(sync_port, aib, port);
+ memcpy(sync_port, aib, sizeof(*aib));
+ if (!follows)
+ return -EAGAIN;
+
+ /*
+ * Catch all other cpus and make them wait until we have
+ * successfully synced the clock. smp_call_function will
+ * return after all other cpus are in etr_sync_cpu_start.
+ */
+ in_sync = 0;
+ preempt_disable();
+ smp_call_function(etr_sync_cpu_start,&in_sync,0,0);
+ local_irq_disable();
+ etr_enable_sync_clock();
+
+ /* Set clock to next OTE. */
+ __ctl_set_bit(14, 21);
+ __ctl_set_bit(0, 29);
+ clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32;
+ if (set_clock(clock) == 0) {
+ __udelay(1); /* Wait for the clock to start. */
+ __ctl_clear_bit(0, 29);
+ __ctl_clear_bit(14, 21);
+ etr_stetr(aib);
+ /* Adjust Linux timing variables. */
+ delay = (unsigned long long)
+ (aib->edf2.etv - sync_port->edf2.etv) << 32;
+ etr_adjust_time(clock, delay);
+ setup_jiffy_timer();
+ /* Verify that the clock is properly set. */
+ if (!etr_aib_follows(sync_port, aib, port)) {
+ /* Didn't work. */
+ etr_disable_sync_clock(NULL);
+ in_sync = -EAGAIN;
+ rc = -EAGAIN;
+ } else {
+ in_sync = 1;
+ rc = 0;
+ }
+ } else {
+ /* Could not set the clock ?!? */
+ __ctl_clear_bit(0, 29);
+ __ctl_clear_bit(14, 21);
+ etr_disable_sync_clock(NULL);
+ in_sync = -EAGAIN;
+ rc = -EAGAIN;
+ }
+ local_irq_enable();
+ smp_call_function(etr_sync_cpu_end,NULL,0,0);
+ preempt_enable();
+ return rc;
+}
+
+/*
+ * Handle the immediate effects of the different events.
+ * The port change event is used for online/offline changes.
+ */
+static struct etr_eacr etr_handle_events(struct etr_eacr eacr)
+{
+ if (test_and_clear_bit(ETR_EVENT_SYNC_CHECK, &etr_events))
+ eacr.es = 0;
+ if (test_and_clear_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events))
+ eacr.es = eacr.sl = 0;
+ if (test_and_clear_bit(ETR_EVENT_PORT_ALERT, &etr_events))
+ etr_port0_uptodate = etr_port1_uptodate = 0;
+
+ if (test_and_clear_bit(ETR_EVENT_PORT0_CHANGE, &etr_events)) {
+ if (eacr.e0)
+ /*
+ * Port change of an enabled port. We have to
+ * assume that this can have caused an stepping
+ * port switch.
+ */
+ etr_tolec = get_clock();
+ eacr.p0 = etr_port0_online;
+ if (!eacr.p0)
+ eacr.e0 = 0;
+ etr_port0_uptodate = 0;
+ }
+ if (test_and_clear_bit(ETR_EVENT_PORT1_CHANGE, &etr_events)) {
+ if (eacr.e1)
+ /*
+ * Port change of an enabled port. We have to
+ * assume that this can have caused an stepping
+ * port switch.
+ */
+ etr_tolec = get_clock();
+ eacr.p1 = etr_port1_online;
+ if (!eacr.p1)
+ eacr.e1 = 0;
+ etr_port1_uptodate = 0;
+ }
+ clear_bit(ETR_EVENT_UPDATE, &etr_events);
+ return eacr;
+}
+
+/*
+ * Set up a timer that expires after the etr_tolec + 1.6 seconds if
+ * one of the ports needs an update.
+ */
+static void etr_set_tolec_timeout(unsigned long long now)
+{
+ unsigned long micros;
+
+ if ((!etr_eacr.p0 || etr_port0_uptodate) &&
+ (!etr_eacr.p1 || etr_port1_uptodate))
+ return;
+ micros = (now > etr_tolec) ? ((now - etr_tolec) >> 12) : 0;
+ micros = (micros > 1600000) ? 0 : 1600000 - micros;
+ mod_timer(&etr_timer, jiffies + (micros * HZ) / 1000000 + 1);
+}
+
+/*
+ * Set up a time that expires after 1/2 second.
+ */
+static void etr_set_sync_timeout(void)
+{
+ mod_timer(&etr_timer, jiffies + HZ/2);
+}
+
+/*
+ * Update the aib information for one or both ports.
+ */
+static struct etr_eacr etr_handle_update(struct etr_aib *aib,
+ struct etr_eacr eacr)
+{
+ /* With both ports disabled the aib information is useless. */
+ if (!eacr.e0 && !eacr.e1)
+ return eacr;
+
+ /* Update port0 or port1 with aib stored in etr_tasklet_fn. */
+ if (aib->esw.q == 0) {
+ /* Information for port 0 stored. */
+ if (eacr.p0 && !etr_port0_uptodate) {
+ etr_port0 = *aib;
+ if (etr_port0_online)
+ etr_port0_uptodate = 1;
+ }
+ } else {
+ /* Information for port 1 stored. */
+ if (eacr.p1 && !etr_port1_uptodate) {
+ etr_port1 = *aib;
+ if (etr_port0_online)
+ etr_port1_uptodate = 1;
+ }
+ }
+
+ /*
+ * Do not try to get the alternate port aib if the clock
+ * is not in sync yet.
+ */
+ if (!eacr.es)
+ return eacr;
+
+ /*
+ * If steai is available we can get the information about
+ * the other port immediately. If only stetr is available the
+ * data-port bit toggle has to be used.
+ */
+ if (test_bit(ETR_FLAG_STEAI, &etr_flags)) {
+ if (eacr.p0 && !etr_port0_uptodate) {
+ etr_steai_cv(&etr_port0, ETR_STEAI_PORT_0);
+ etr_port0_uptodate = 1;
+ }
+ if (eacr.p1 && !etr_port1_uptodate) {
+ etr_steai_cv(&etr_port1, ETR_STEAI_PORT_1);
+ etr_port1_uptodate = 1;
+ }
+ } else {
+ /*
+ * One port was updated above, if the other
+ * port is not uptodate toggle dp bit.
+ */
+ if ((eacr.p0 && !etr_port0_uptodate) ||
+ (eacr.p1 && !etr_port1_uptodate))
+ eacr.dp ^= 1;
+ else
+ eacr.dp = 0;
+ }
+ return eacr;
+}
+
+/*
+ * Write new etr control register if it differs from the current one.
+ * Return 1 if etr_tolec has been updated as well.
+ */
+static void etr_update_eacr(struct etr_eacr eacr)
+{
+ int dp_changed;
+
+ if (memcmp(&etr_eacr, &eacr, sizeof(eacr)) == 0)
+ /* No change, return. */
+ return;
+ /*
+ * The disable of an active port of the change of the data port
+ * bit can/will cause a change in the data port.
+ */
+ dp_changed = etr_eacr.e0 > eacr.e0 || etr_eacr.e1 > eacr.e1 ||
+ (etr_eacr.dp ^ eacr.dp) != 0;
+ etr_eacr = eacr;
+ etr_setr(&etr_eacr);
+ if (dp_changed)
+ etr_tolec = get_clock();
+}
+
+/*
+ * ETR tasklet. In this function you'll find the main logic. In
+ * particular this is the only function that calls etr_update_eacr(),
+ * it "controls" the etr control register.
+ */
+static void etr_tasklet_fn(unsigned long dummy)
+{
+ unsigned long long now;
+ struct etr_eacr eacr;
+ struct etr_aib aib;
+ int sync_port;
+
+ /* Create working copy of etr_eacr. */
+ eacr = etr_eacr;
+
+ /* Check for the different events and their immediate effects. */
+ eacr = etr_handle_events(eacr);
+
+ /* Check if ETR is supposed to be active. */
+ eacr.ea = eacr.p0 || eacr.p1;
+ if (!eacr.ea) {
+ /* Both ports offline. Reset everything. */
+ eacr.dp = eacr.es = eacr.sl = 0;
+ on_each_cpu(etr_disable_sync_clock, NULL, 0, 1);
+ del_timer_sync(&etr_timer);
+ etr_update_eacr(eacr);
+ set_bit(ETR_FLAG_EACCES, &etr_flags);
+ return;
+ }
+
+ /* Store aib to get the current ETR status word. */
+ BUG_ON(etr_stetr(&aib) != 0);
+ etr_port0.esw = etr_port1.esw = aib.esw; /* Copy status word. */
+ now = get_clock();
+
+ /*
+ * Update the port information if the last stepping port change
+ * or data port change is older than 1.6 seconds.
+ */
+ if (now >= etr_tolec + (1600000 << 12))
+ eacr = etr_handle_update(&aib, eacr);
+
+ /*
+ * Select ports to enable. The prefered synchronization mode is PPS.
+ * If a port can be enabled depends on a number of things:
+ * 1) The port needs to be online and uptodate. A port is not
+ * disabled just because it is not uptodate, but it is only
+ * enabled if it is uptodate.
+ * 2) The port needs to have the same mode (pps / etr).
+ * 3) The port needs to be usable -> etr_port_valid() == 1
+ * 4) To enable the second port the clock needs to be in sync.
+ * 5) If both ports are useable and are ETR ports, the network id
+ * has to be the same.
+ * The eacr.sl bit is used to indicate etr mode vs. pps mode.
+ */
+ if (eacr.p0 && aib.esw.psc0 == etr_lpsc_pps_mode) {
+ eacr.sl = 0;
+ eacr.e0 = 1;
+ if (!etr_mode_is_pps(etr_eacr))
+ eacr.es = 0;
+ if (!eacr.es || !eacr.p1 || aib.esw.psc1 != etr_lpsc_pps_mode)
+ eacr.e1 = 0;
+ // FIXME: uptodate checks ?
+ else if (etr_port0_uptodate && etr_port1_uptodate)
+ eacr.e1 = 1;
+ sync_port = (etr_port0_uptodate &&
+ etr_port_valid(&etr_port0, 0)) ? 0 : -1;
+ clear_bit(ETR_FLAG_EACCES, &etr_flags);
+ } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_pps_mode) {
+ eacr.sl = 0;
+ eacr.e0 = 0;
+ eacr.e1 = 1;
+ if (!etr_mode_is_pps(etr_eacr))
+ eacr.es = 0;
+ sync_port = (etr_port1_uptodate &&
+ etr_port_valid(&etr_port1, 1)) ? 1 : -1;
+ clear_bit(ETR_FLAG_EACCES, &etr_flags);
+ } else if (eacr.p0 && aib.esw.psc0 == etr_lpsc_operational_step) {
+ eacr.sl = 1;
+ eacr.e0 = 1;
+ if (!etr_mode_is_etr(etr_eacr))
+ eacr.es = 0;
+ if (!eacr.es || !eacr.p1 ||
+ aib.esw.psc1 != etr_lpsc_operational_alt)
+ eacr.e1 = 0;
+ else if (etr_port0_uptodate && etr_port1_uptodate &&
+ etr_compare_network(&etr_port0, &etr_port1))
+ eacr.e1 = 1;
+ sync_port = (etr_port0_uptodate &&
+ etr_port_valid(&etr_port0, 0)) ? 0 : -1;
+ clear_bit(ETR_FLAG_EACCES, &etr_flags);
+ } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_operational_step) {
+ eacr.sl = 1;
+ eacr.e0 = 0;
+ eacr.e1 = 1;
+ if (!etr_mode_is_etr(etr_eacr))
+ eacr.es = 0;
+ sync_port = (etr_port1_uptodate &&
+ etr_port_valid(&etr_port1, 1)) ? 1 : -1;
+ clear_bit(ETR_FLAG_EACCES, &etr_flags);
+ } else {
+ /* Both ports not usable. */
+ eacr.es = eacr.sl = 0;
+ sync_port = -1;
+ set_bit(ETR_FLAG_EACCES, &etr_flags);
+ }
+
+ /*
+ * If the clock is in sync just update the eacr and return.
+ * If there is no valid sync port wait for a port update.
+ */
+ if (eacr.es || sync_port < 0) {
+ etr_update_eacr(eacr);
+ etr_set_tolec_timeout(now);
+ return;
+ }
+
+ /*
+ * Prepare control register for clock syncing
+ * (reset data port bit, set sync check control.
+ */
+ eacr.dp = 0;
+ eacr.es = 1;
+
+ /*
+ * Update eacr and try to synchronize the clock. If the update
+ * of eacr caused a stepping port switch (or if we have to
+ * assume that a stepping port switch has occured) or the
+ * clock syncing failed, reset the sync check control bit
+ * and set up a timer to try again after 0.5 seconds
+ */
+ etr_update_eacr(eacr);
+ if (now < etr_tolec + (1600000 << 12) ||
+ etr_sync_clock(&aib, sync_port) != 0) {
+ /* Sync failed. Try again in 1/2 second. */
+ eacr.es = 0;
+ etr_update_eacr(eacr);
+ etr_set_sync_timeout();
+ } else
+ etr_set_tolec_timeout(now);
+}
+
+/*
+ * Sysfs interface functions
+ */
+static struct sysdev_class etr_sysclass = {
+ set_kset_name("etr")
+};
+
+static struct sys_device etr_port0_dev = {
+ .id = 0,
+ .cls = &etr_sysclass,
+};
+
+static struct sys_device etr_port1_dev = {
+ .id = 1,
+ .cls = &etr_sysclass,
+};
+
+/*
+ * ETR class attributes
+ */
+static ssize_t etr_stepping_port_show(struct sysdev_class *class, char *buf)
+{
+ return sprintf(buf, "%i\n", etr_port0.esw.p);
+}
+
+static SYSDEV_CLASS_ATTR(stepping_port, 0400, etr_stepping_port_show, NULL);
+
+static ssize_t etr_stepping_mode_show(struct sysdev_class *class, char *buf)
+{
+ char *mode_str;
+
+ if (etr_mode_is_pps(etr_eacr))
+ mode_str = "pps";
+ else if (etr_mode_is_etr(etr_eacr))
+ mode_str = "etr";
+ else
+ mode_str = "local";
+ return sprintf(buf, "%s\n", mode_str);
+}
+
+static SYSDEV_CLASS_ATTR(stepping_mode, 0400, etr_stepping_mode_show, NULL);
+
+/*
+ * ETR port attributes
+ */
+static inline struct etr_aib *etr_aib_from_dev(struct sys_device *dev)
+{
+ if (dev == &etr_port0_dev)
+ return etr_port0_online ? &etr_port0 : NULL;
+ else
+ return etr_port1_online ? &etr_port1 : NULL;
+}
+
+static ssize_t etr_online_show(struct sys_device *dev, char *buf)
+{
+ unsigned int online;
+
+ online = (dev == &etr_port0_dev) ? etr_port0_online : etr_port1_online;
+ return sprintf(buf, "%i\n", online);
+}
+
+static ssize_t etr_online_store(struct sys_device *dev,
+ const char *buf, size_t count)
+{
+ unsigned int value;
+
+ value = simple_strtoul(buf, NULL, 0);
+ if (value != 0 && value != 1)
+ return -EINVAL;
+ if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+ return -ENOSYS;
+ if (dev == &etr_port0_dev) {
+ if (etr_port0_online == value)
+ return count; /* Nothing to do. */
+ etr_port0_online = value;
+ set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+ tasklet_hi_schedule(&etr_tasklet);
+ } else {
+ if (etr_port1_online == value)
+ return count; /* Nothing to do. */
+ etr_port1_online = value;
+ set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+ tasklet_hi_schedule(&etr_tasklet);
+ }
+ return count;
+}
+
+static SYSDEV_ATTR(online, 0600, etr_online_show, etr_online_store);
+
+static ssize_t etr_stepping_control_show(struct sys_device *dev, char *buf)
+{
+ return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ?
+ etr_eacr.e0 : etr_eacr.e1);
+}
+
+static SYSDEV_ATTR(stepping_control, 0400, etr_stepping_control_show, NULL);
+
+static ssize_t etr_mode_code_show(struct sys_device *dev, char *buf)
+{
+ if (!etr_port0_online && !etr_port1_online)
+ /* Status word is not uptodate if both ports are offline. */
+ return -ENODATA;
+ return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ?
+ etr_port0.esw.psc0 : etr_port0.esw.psc1);
+}
+
+static SYSDEV_ATTR(state_code, 0400, etr_mode_code_show, NULL);
+
+static ssize_t etr_untuned_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v1)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf1.u);
+}
+
+static SYSDEV_ATTR(untuned, 0400, etr_untuned_show, NULL);
+
+static ssize_t etr_network_id_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v1)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf1.net_id);
+}
+
+static SYSDEV_ATTR(network, 0400, etr_network_id_show, NULL);
+
+static ssize_t etr_id_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v1)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf1.etr_id);
+}
+
+static SYSDEV_ATTR(id, 0400, etr_id_show, NULL);
+
+static ssize_t etr_port_number_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v1)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf1.etr_pn);
+}
+
+static SYSDEV_ATTR(port, 0400, etr_port_number_show, NULL);
+
+static ssize_t etr_coupled_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v3)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf3.c);
+}
+
+static SYSDEV_ATTR(coupled, 0400, etr_coupled_show, NULL);
+
+static ssize_t etr_local_time_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v3)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf3.blto);
+}
+
+static SYSDEV_ATTR(local_time, 0400, etr_local_time_show, NULL);
+
+static ssize_t etr_utc_offset_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v3)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf3.buo);
+}
+
+static SYSDEV_ATTR(utc_offset, 0400, etr_utc_offset_show, NULL);
+
+static struct sysdev_attribute *etr_port_attributes[] = {
+ &attr_online,
+ &attr_stepping_control,
+ &attr_state_code,
+ &attr_untuned,
+ &attr_network,
+ &attr_id,
+ &attr_port,
+ &attr_coupled,
+ &attr_local_time,
+ &attr_utc_offset,
+ NULL
+};
+
+static int __init etr_register_port(struct sys_device *dev)
+{
+ struct sysdev_attribute **attr;
+ int rc;
+
+ rc = sysdev_register(dev);
+ if (rc)
+ goto out;
+ for (attr = etr_port_attributes; *attr; attr++) {
+ rc = sysdev_create_file(dev, *attr);
+ if (rc)
+ goto out_unreg;
+ }
+ return 0;
+out_unreg:
+ for (; attr >= etr_port_attributes; attr--)
+ sysdev_remove_file(dev, *attr);
+ sysdev_unregister(dev);
+out:
+ return rc;
+}
+
+static void __init etr_unregister_port(struct sys_device *dev)
+{
+ struct sysdev_attribute **attr;
+
+ for (attr = etr_port_attributes; *attr; attr++)
+ sysdev_remove_file(dev, *attr);
+ sysdev_unregister(dev);
+}
+
+static int __init etr_init_sysfs(void)
+{
+ int rc;
+
+ rc = sysdev_class_register(&etr_sysclass);
+ if (rc)
+ goto out;
+ rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_port);
+ if (rc)
+ goto out_unreg_class;
+ rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_mode);
+ if (rc)
+ goto out_remove_stepping_port;
+ rc = etr_register_port(&etr_port0_dev);
+ if (rc)
+ goto out_remove_stepping_mode;
+ rc = etr_register_port(&etr_port1_dev);
+ if (rc)
+ goto out_remove_port0;
+ return 0;
+
+out_remove_port0:
+ etr_unregister_port(&etr_port0_dev);
+out_remove_stepping_mode:
+ sysdev_class_remove_file(&etr_sysclass, &attr_stepping_mode);
+out_remove_stepping_port:
+ sysdev_class_remove_file(&etr_sysclass, &attr_stepping_port);
+out_unreg_class:
+ sysdev_class_unregister(&etr_sysclass);
+out:
+ return rc;
}
+device_initcall(etr_init_sysfs);
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 3cbb0dcf1f1..f0e5a320e2e 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -283,7 +283,7 @@ char *task_show_regs(struct task_struct *task, char *buffer)
return buffer;
}
-DEFINE_SPINLOCK(die_lock);
+static DEFINE_SPINLOCK(die_lock);
void die(const char * str, struct pt_regs * regs, long err)
{
@@ -364,8 +364,7 @@ void __kprobes do_single_step(struct pt_regs *regs)
force_sig(SIGTRAP, current);
}
-asmlinkage void
-default_trap_handler(struct pt_regs * regs, long interruption_code)
+static void default_trap_handler(struct pt_regs * regs, long interruption_code)
{
if (regs->psw.mask & PSW_MASK_PSTATE) {
local_irq_enable();
@@ -376,7 +375,7 @@ default_trap_handler(struct pt_regs * regs, long interruption_code)
}
#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+static void name(struct pt_regs * regs, long interruption_code) \
{ \
siginfo_t info; \
info.si_signo = signr; \
@@ -442,7 +441,7 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
"floating point exception", regs, &si);
}
-asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
+static void illegal_op(struct pt_regs * regs, long interruption_code)
{
siginfo_t info;
__u8 opcode[6];
@@ -491,8 +490,15 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
#endif
} else
signal = SIGILL;
- } else
- signal = SIGILL;
+ } else {
+ /*
+ * If we get an illegal op in kernel mode, send it through the
+ * kprobes notifier. If kprobes doesn't pick it up, SIGILL
+ */
+ if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
+ 3, SIGTRAP) != NOTIFY_STOP)
+ signal = SIGILL;
+ }
#ifdef CONFIG_MATHEMU
if (signal == SIGFPE)
@@ -585,7 +591,7 @@ DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
ILL_ILLOPN, get_check_address(regs));
#endif
-asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
+static void data_exception(struct pt_regs * regs, long interruption_code)
{
__u16 __user *location;
int signal = 0;
@@ -675,7 +681,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
}
}
-asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code)
+static void space_switch_exception(struct pt_regs * regs, long int_code)
{
siginfo_t info;
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index fe0f2e97ba7..a4890739252 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -31,18 +31,19 @@ SECTIONS
_etext = .; /* End of text section */
- . = ALIGN(16); /* Exception table */
- __start___ex_table = .;
- __ex_table : { *(__ex_table) }
- __stop___ex_table = .;
-
RODATA
#ifdef CONFIG_SHARED_KERNEL
. = ALIGN(1048576); /* VM shared segments are 1MB aligned */
+#endif
+ . = ALIGN(4096);
_eshared = .; /* End of shareable data */
-#endif
+
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
.data : { /* Data */
*(.data)
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index 21baaf5496d..9d5b02801b4 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -25,7 +25,7 @@
#include <asm/irq_regs.h>
static ext_int_info_t ext_int_info_timer;
-DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
+static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
/*
@@ -524,16 +524,15 @@ EXPORT_SYMBOL(del_virt_timer);
void init_cpu_vtimer(void)
{
struct vtimer_queue *vt_list;
- unsigned long cr0;
/* kick the virtual timer */
S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
- __ctl_store(cr0, 0, 0);
- cr0 |= 0x400;
- __ctl_load(cr0, 0, 0);
+
+ /* enable cpu timer interrupts */
+ __ctl_set_bit(0,10);
vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
INIT_LIST_HEAD(&vt_list->list);
@@ -572,6 +571,7 @@ void __init vtime_init(void)
if (register_idle_notifier(&vtimer_idle_nb))
panic("Couldn't register idle notifier");
+ /* Enable cpu timer interrupts on the boot cpu. */
init_cpu_vtimer();
}
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index b5f94cf3bde..7a44fed21b3 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -4,7 +4,7 @@
EXTRA_AFLAGS := -traditional
-lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
+lib-y += delay.o string.o uaccess_std.o uaccess_pt.o qrnnd.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 027c4742a00..02854449b74 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -1,5 +1,5 @@
/*
- * arch/s390/kernel/delay.c
+ * arch/s390/lib/delay.c
* Precise Delay Loops for S390
*
* S390 version
@@ -13,10 +13,8 @@
#include <linux/sched.h>
#include <linux/delay.h>
-
-#ifdef CONFIG_SMP
-#include <asm/smp.h>
-#endif
+#include <linux/timex.h>
+#include <linux/irqflags.h>
void __delay(unsigned long loops)
{
@@ -31,17 +29,39 @@ void __delay(unsigned long loops)
}
/*
- * Waits for 'usecs' microseconds using the tod clock, giving up the time slice
- * of the virtual PU inbetween to avoid congestion.
+ * Waits for 'usecs' microseconds using the TOD clock comparator.
*/
void __udelay(unsigned long usecs)
{
- uint64_t start_cc;
+ u64 end, time, jiffy_timer = 0;
+ unsigned long flags, cr0, mask, dummy;
+
+ local_irq_save(flags);
+ if (raw_irqs_disabled_flags(flags)) {
+ jiffy_timer = S390_lowcore.jiffy_timer;
+ S390_lowcore.jiffy_timer = -1ULL - (4096 << 12);
+ __ctl_store(cr0, 0, 0);
+ dummy = (cr0 & 0xffff00e0) | 0x00000800;
+ __ctl_load(dummy , 0, 0);
+ mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
+ } else
+ mask = psw_kernel_bits | PSW_MASK_WAIT |
+ PSW_MASK_EXT | PSW_MASK_IO;
+
+ end = get_clock() + ((u64) usecs << 12);
+ do {
+ time = end < S390_lowcore.jiffy_timer ?
+ end : S390_lowcore.jiffy_timer;
+ set_clock_comparator(time);
+ trace_hardirqs_on();
+ __load_psw_mask(mask);
+ local_irq_disable();
+ } while (get_clock() < end);
- if (usecs == 0)
- return;
- start_cc = get_clock();
- do {
- cpu_relax();
- } while (((get_clock() - start_cc)/4096) < usecs);
+ if (raw_irqs_disabled_flags(flags)) {
+ __ctl_load(cr0, 0, 0);
+ S390_lowcore.jiffy_timer = jiffy_timer;
+ }
+ set_clock_comparator(S390_lowcore.jiffy_timer);
+ local_irq_restore(flags);
}
diff --git a/arch/s390/lib/qrnnd.S b/arch/s390/lib/qrnnd.S
new file mode 100644
index 00000000000..eb1df632e74
--- /dev/null
+++ b/arch/s390/lib/qrnnd.S
@@ -0,0 +1,77 @@
+# S/390 __udiv_qrnnd
+
+# r2 : &__r
+# r3 : upper half of 64 bit word n
+# r4 : lower half of 64 bit word n
+# r5 : divisor d
+# the reminder r of the division is to be stored to &__r and
+# the quotient q is to be returned
+
+ .text
+ .globl __udiv_qrnnd
+__udiv_qrnnd:
+ st %r2,24(%r15) # store pointer to reminder for later
+ lr %r0,%r3 # reload n
+ lr %r1,%r4
+ ltr %r2,%r5 # reload and test divisor
+ jp 5f
+ # divisor >= 0x80000000
+ srdl %r0,2 # n/4
+ srl %r2,1 # d/2
+ slr %r1,%r2 # special case if last bit of d is set
+ brc 3,0f # (n/4) div (n/2) can overflow by 1
+ ahi %r0,-1 # trick: subtract n/2, then divide
+0: dr %r0,%r2 # signed division
+ ahi %r1,1 # trick part 2: add 1 to the quotient
+ # now (n >> 2) = (d >> 1) * %r1 + %r0
+ lhi %r3,1
+ nr %r3,%r1 # test last bit of q
+ jz 1f
+ alr %r0,%r2 # add (d>>1) to r
+1: srl %r1,1 # q >>= 1
+ # now (n >> 2) = (d&-2) * %r1 + %r0
+ lhi %r3,1
+ nr %r3,%r5 # test last bit of d
+ jz 2f
+ slr %r0,%r1 # r -= q
+ brc 3,2f # borrow ?
+ alr %r0,%r5 # r += d
+ ahi %r1,-1
+2: # now (n >> 2) = d * %r1 + %r0
+ alr %r1,%r1 # q <<= 1
+ alr %r0,%r0 # r <<= 1
+ brc 12,3f # overflow on r ?
+ slr %r0,%r5 # r -= d
+ ahi %r1,1 # q += 1
+3: lhi %r3,2
+ nr %r3,%r4 # test next to last bit of n
+ jz 4f
+ ahi %r0,1 # r += 1
+4: clr %r0,%r5 # r >= d ?
+ jl 6f
+ slr %r0,%r5 # r -= d
+ ahi %r1,1 # q += 1
+ # now (n >> 1) = d * %r1 + %r0
+ j 6f
+5: # divisor < 0x80000000
+ srdl %r0,1
+ dr %r0,%r2 # signed division
+ # now (n >> 1) = d * %r1 + %r0
+6: alr %r1,%r1 # q <<= 1
+ alr %r0,%r0 # r <<= 1
+ brc 12,7f # overflow on r ?
+ slr %r0,%r5 # r -= d
+ ahi %r1,1 # q += 1
+7: lhi %r3,1
+ nr %r3,%r4 # isolate last bit of n
+ alr %r0,%r3 # r += (n & 1)
+ clr %r0,%r5 # r >= d ?
+ jl 8f
+ slr %r0,%r5 # r -= d
+ ahi %r1,1 # q += 1
+8: # now n = d * %r1 + %r0
+ l %r2,24(%r15)
+ st %r0,0(%r2)
+ lr %r2,%r1
+ br %r14
+ .end __udiv_qrnnd
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
new file mode 100644
index 00000000000..126011df14f
--- /dev/null
+++ b/arch/s390/lib/uaccess.h
@@ -0,0 +1,23 @@
+/*
+ * arch/s390/uaccess.h
+ *
+ * Copyright IBM Corp. 2007
+ *
+ */
+
+#ifndef __ARCH_S390_LIB_UACCESS_H
+#define __ARCH_S390_LIB_UACCESS_H
+
+extern size_t copy_from_user_std(size_t, const void __user *, void *);
+extern size_t copy_to_user_std(size_t, void __user *, const void *);
+extern size_t strnlen_user_std(size_t, const char __user *);
+extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
+extern int futex_atomic_cmpxchg_std(int __user *, int, int);
+extern int futex_atomic_op_std(int, int __user *, int, int *);
+
+extern size_t copy_from_user_pt(size_t, const void __user *, void *);
+extern size_t copy_to_user_pt(size_t, void __user *, const void *);
+extern int futex_atomic_op_pt(int, int __user *, int, int *);
+extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
+
+#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
index f9a23d57eb7..6d8772339d7 100644
--- a/arch/s390/lib/uaccess_mvcos.c
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -12,6 +12,7 @@
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/futex.h>
+#include "uaccess.h"
#ifndef __s390x__
#define AHI "ahi"
@@ -27,10 +28,7 @@
#define SLR "slgr"
#endif
-extern size_t copy_from_user_std(size_t, const void __user *, void *);
-extern size_t copy_to_user_std(size_t, void __user *, const void *);
-
-size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
{
register unsigned long reg0 asm("0") = 0x81UL;
unsigned long tmp1, tmp2;
@@ -69,14 +67,14 @@ size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
return size;
}
-size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
{
if (size <= 256)
return copy_from_user_std(size, ptr, x);
return copy_from_user_mvcos(size, ptr, x);
}
-size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
{
register unsigned long reg0 asm("0") = 0x810000UL;
unsigned long tmp1, tmp2;
@@ -105,14 +103,16 @@ size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
return size;
}
-size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_mvcos_check(size_t size, void __user *ptr,
+ const void *x)
{
if (size <= 256)
return copy_to_user_std(size, ptr, x);
return copy_to_user_mvcos(size, ptr, x);
}
-size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from)
+static size_t copy_in_user_mvcos(size_t size, void __user *to,
+ const void __user *from)
{
register unsigned long reg0 asm("0") = 0x810081UL;
unsigned long tmp1, tmp2;
@@ -134,7 +134,7 @@ size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from)
return size;
}
-size_t clear_user_mvcos(size_t size, void __user *to)
+static size_t clear_user_mvcos(size_t size, void __user *to)
{
register unsigned long reg0 asm("0") = 0x810000UL;
unsigned long tmp1, tmp2;
@@ -162,10 +162,43 @@ size_t clear_user_mvcos(size_t size, void __user *to)
return size;
}
-extern size_t strnlen_user_std(size_t, const char __user *);
-extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_op(int, int __user *, int, int *);
-extern int futex_atomic_cmpxchg(int __user *, int, int);
+static size_t strnlen_user_mvcos(size_t count, const char __user *src)
+{
+ char buf[256];
+ int rc;
+ size_t done, len, len_str;
+
+ done = 0;
+ do {
+ len = min(count - done, (size_t) 256);
+ rc = uaccess.copy_from_user(len, src + done, buf);
+ if (unlikely(rc == len))
+ return 0;
+ len -= rc;
+ len_str = strnlen(buf, len);
+ done += len_str;
+ } while ((len_str == len) && (done < count));
+ return done + 1;
+}
+
+static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
+ char *dst)
+{
+ int rc;
+ size_t done, len, len_str;
+
+ done = 0;
+ do {
+ len = min(count - done, (size_t) 4096);
+ rc = uaccess.copy_from_user(len, src + done, dst);
+ if (unlikely(rc == len))
+ return -EFAULT;
+ len -= rc;
+ len_str = strnlen(dst, len);
+ done += len_str;
+ } while ((len_str == len) && (done < count));
+ return done;
+}
struct uaccess_ops uaccess_mvcos = {
.copy_from_user = copy_from_user_mvcos_check,
@@ -176,6 +209,21 @@ struct uaccess_ops uaccess_mvcos = {
.clear_user = clear_user_mvcos,
.strnlen_user = strnlen_user_std,
.strncpy_from_user = strncpy_from_user_std,
- .futex_atomic_op = futex_atomic_op,
- .futex_atomic_cmpxchg = futex_atomic_cmpxchg,
+ .futex_atomic_op = futex_atomic_op_std,
+ .futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
+};
+
+#ifdef CONFIG_S390_SWITCH_AMODE
+struct uaccess_ops uaccess_mvcos_switch = {
+ .copy_from_user = copy_from_user_mvcos,
+ .copy_from_user_small = copy_from_user_mvcos,
+ .copy_to_user = copy_to_user_mvcos,
+ .copy_to_user_small = copy_to_user_mvcos,
+ .copy_in_user = copy_in_user_mvcos,
+ .clear_user = clear_user_mvcos,
+ .strnlen_user = strnlen_user_mvcos,
+ .strncpy_from_user = strncpy_from_user_mvcos,
+ .futex_atomic_op = futex_atomic_op_pt,
+ .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
};
+#endif
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 8741bdc0929..63181671e3e 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -1,23 +1,28 @@
/*
* arch/s390/lib/uaccess_pt.c
*
- * User access functions based on page table walks.
+ * User access functions based on page table walks for enhanced
+ * system layout without hardware support.
*
* Copyright IBM Corp. 2006
* Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
*/
#include <linux/errno.h>
-#include <asm/uaccess.h>
+#include <linux/hardirq.h>
#include <linux/mm.h>
+#include <asm/uaccess.h>
#include <asm/futex.h>
+#include "uaccess.h"
-static inline int __handle_fault(struct mm_struct *mm, unsigned long address,
- int write_access)
+static int __handle_fault(struct mm_struct *mm, unsigned long address,
+ int write_access)
{
struct vm_area_struct *vma;
int ret = -EFAULT;
+ if (in_atomic())
+ return ret;
down_read(&mm->mmap_sem);
vma = find_vma(mm, address);
if (unlikely(!vma))
@@ -60,8 +65,9 @@ out:
out_of_memory:
up_read(&mm->mmap_sem);
- if (current->pid == 1) {
+ if (is_init(current)) {
yield();
+ down_read(&mm->mmap_sem);
goto survive;
}
printk("VM: killing process %s\n", current->comm);
@@ -75,8 +81,8 @@ out_sigbus:
return ret;
}
-static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
- size_t n, int write_user)
+static size_t __user_copy_pt(unsigned long uaddr, void *kptr,
+ size_t n, int write_user)
{
struct mm_struct *mm = current->mm;
unsigned long offset, pfn, done, size;
@@ -129,6 +135,49 @@ fault:
goto retry;
}
+/*
+ * Do DAT for user address by page table walk, return kernel address.
+ * This function needs to be called with current->mm->page_table_lock held.
+ */
+static unsigned long __dat_user_addr(unsigned long uaddr)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long pfn, ret;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ int rc;
+
+ ret = 0;
+retry:
+ pgd = pgd_offset(mm, uaddr);
+ if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+ goto fault;
+
+ pmd = pmd_offset(pgd, uaddr);
+ if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+ goto fault;
+
+ pte = pte_offset_map(pmd, uaddr);
+ if (!pte || !pte_present(*pte))
+ goto fault;
+
+ pfn = pte_pfn(*pte);
+ if (!pfn_valid(pfn))
+ goto out;
+
+ ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
+out:
+ return ret;
+fault:
+ spin_unlock(&mm->page_table_lock);
+ rc = __handle_fault(mm, uaddr, 0);
+ spin_lock(&mm->page_table_lock);
+ if (rc)
+ goto out;
+ goto retry;
+}
+
size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
{
size_t rc;
@@ -151,3 +200,277 @@ size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
}
return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
}
+
+static size_t clear_user_pt(size_t n, void __user *to)
+{
+ long done, size, ret;
+
+ if (segment_eq(get_fs(), KERNEL_DS)) {
+ memset((void __kernel __force *) to, 0, n);
+ return 0;
+ }
+ done = 0;
+ do {
+ if (n - done > PAGE_SIZE)
+ size = PAGE_SIZE;
+ else
+ size = n - done;
+ ret = __user_copy_pt((unsigned long) to + done,
+ &empty_zero_page, size, 1);
+ done += size;
+ if (ret)
+ return ret + n - done;
+ } while (done < n);
+ return 0;
+}
+
+static size_t strnlen_user_pt(size_t count, const char __user *src)
+{
+ char *addr;
+ unsigned long uaddr = (unsigned long) src;
+ struct mm_struct *mm = current->mm;
+ unsigned long offset, pfn, done, len;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ size_t len_str;
+
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return strnlen((const char __kernel __force *) src, count) + 1;
+ done = 0;
+retry:
+ spin_lock(&mm->page_table_lock);
+ do {
+ pgd = pgd_offset(mm, uaddr);
+ if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+ goto fault;
+
+ pmd = pmd_offset(pgd, uaddr);
+ if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+ goto fault;
+
+ pte = pte_offset_map(pmd, uaddr);
+ if (!pte || !pte_present(*pte))
+ goto fault;
+
+ pfn = pte_pfn(*pte);
+ if (!pfn_valid(pfn)) {
+ done = -1;
+ goto out;
+ }
+
+ offset = uaddr & (PAGE_SIZE-1);
+ addr = (char *)(pfn << PAGE_SHIFT) + offset;
+ len = min(count - done, PAGE_SIZE - offset);
+ len_str = strnlen(addr, len);
+ done += len_str;
+ uaddr += len_str;
+ } while ((len_str == len) && (done < count));
+out:
+ spin_unlock(&mm->page_table_lock);
+ return done + 1;
+fault:
+ spin_unlock(&mm->page_table_lock);
+ if (__handle_fault(mm, uaddr, 0)) {
+ return 0;
+ }
+ goto retry;
+}
+
+static size_t strncpy_from_user_pt(size_t count, const char __user *src,
+ char *dst)
+{
+ size_t n = strnlen_user_pt(count, src);
+
+ if (!n)
+ return -EFAULT;
+ if (n > count)
+ n = count;
+ if (segment_eq(get_fs(), KERNEL_DS)) {
+ memcpy(dst, (const char __kernel __force *) src, n);
+ if (dst[n-1] == '\0')
+ return n-1;
+ else
+ return n;
+ }
+ if (__user_copy_pt((unsigned long) src, dst, n, 0))
+ return -EFAULT;
+ if (dst[n-1] == '\0')
+ return n-1;
+ else
+ return n;
+}
+
+static size_t copy_in_user_pt(size_t n, void __user *to,
+ const void __user *from)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to,
+ uaddr, done, size;
+ unsigned long uaddr_from = (unsigned long) from;
+ unsigned long uaddr_to = (unsigned long) to;
+ pgd_t *pgd_from, *pgd_to;
+ pmd_t *pmd_from, *pmd_to;
+ pte_t *pte_from, *pte_to;
+ int write_user;
+
+ done = 0;
+retry:
+ spin_lock(&mm->page_table_lock);
+ do {
+ pgd_from = pgd_offset(mm, uaddr_from);
+ if (pgd_none(*pgd_from) || unlikely(pgd_bad(*pgd_from))) {
+ uaddr = uaddr_from;
+ write_user = 0;
+ goto fault;
+ }
+ pgd_to = pgd_offset(mm, uaddr_to);
+ if (pgd_none(*pgd_to) || unlikely(pgd_bad(*pgd_to))) {
+ uaddr = uaddr_to;
+ write_user = 1;
+ goto fault;
+ }
+
+ pmd_from = pmd_offset(pgd_from, uaddr_from);
+ if (pmd_none(*pmd_from) || unlikely(pmd_bad(*pmd_from))) {
+ uaddr = uaddr_from;
+ write_user = 0;
+ goto fault;
+ }
+ pmd_to = pmd_offset(pgd_to, uaddr_to);
+ if (pmd_none(*pmd_to) || unlikely(pmd_bad(*pmd_to))) {
+ uaddr = uaddr_to;
+ write_user = 1;
+ goto fault;
+ }
+
+ pte_from = pte_offset_map(pmd_from, uaddr_from);
+ if (!pte_from || !pte_present(*pte_from)) {
+ uaddr = uaddr_from;
+ write_user = 0;
+ goto fault;
+ }
+ pte_to = pte_offset_map(pmd_to, uaddr_to);
+ if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) {
+ uaddr = uaddr_to;
+ write_user = 1;
+ goto fault;
+ }
+
+ pfn_from = pte_pfn(*pte_from);
+ if (!pfn_valid(pfn_from))
+ goto out;
+ pfn_to = pte_pfn(*pte_to);
+ if (!pfn_valid(pfn_to))
+ goto out;
+
+ offset_from = uaddr_from & (PAGE_SIZE-1);
+ offset_to = uaddr_from & (PAGE_SIZE-1);
+ offset_max = max(offset_from, offset_to);
+ size = min(n - done, PAGE_SIZE - offset_max);
+
+ memcpy((void *)(pfn_to << PAGE_SHIFT) + offset_to,
+ (void *)(pfn_from << PAGE_SHIFT) + offset_from, size);
+ done += size;
+ uaddr_from += size;
+ uaddr_to += size;
+ } while (done < n);
+out:
+ spin_unlock(&mm->page_table_lock);
+ return n - done;
+fault:
+ spin_unlock(&mm->page_table_lock);
+ if (__handle_fault(mm, uaddr, write_user))
+ return n - done;
+ goto retry;
+}
+
+#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \
+ asm volatile("0: l %1,0(%6)\n" \
+ "1: " insn \
+ "2: cs %1,%2,0(%6)\n" \
+ "3: jl 1b\n" \
+ " lhi %0,0\n" \
+ "4:\n" \
+ EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b) \
+ : "=d" (ret), "=&d" (oldval), "=&d" (newval), \
+ "=m" (*uaddr) \
+ : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
+ "m" (*uaddr) : "cc" );
+
+int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+{
+ int oldval = 0, newval, ret;
+
+ spin_lock(&current->mm->page_table_lock);
+ uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
+ if (!uaddr) {
+ spin_unlock(&current->mm->page_table_lock);
+ return -EFAULT;
+ }
+ get_page(virt_to_page(uaddr));
+ spin_unlock(&current->mm->page_table_lock);
+ switch (op) {
+ case FUTEX_OP_SET:
+ __futex_atomic_op("lr %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ADD:
+ __futex_atomic_op("lr %2,%1\nar %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_OR:
+ __futex_atomic_op("lr %2,%1\nor %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ANDN:
+ __futex_atomic_op("lr %2,%1\nnr %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_XOR:
+ __futex_atomic_op("lr %2,%1\nxr %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+ put_page(virt_to_page(uaddr));
+ *old = oldval;
+ return ret;
+}
+
+int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+{
+ int ret;
+
+ spin_lock(&current->mm->page_table_lock);
+ uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
+ if (!uaddr) {
+ spin_unlock(&current->mm->page_table_lock);
+ return -EFAULT;
+ }
+ get_page(virt_to_page(uaddr));
+ spin_unlock(&current->mm->page_table_lock);
+ asm volatile(" cs %1,%4,0(%5)\n"
+ "0: lr %0,%1\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
+ : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
+ : "cc", "memory" );
+ put_page(virt_to_page(uaddr));
+ return ret;
+}
+
+struct uaccess_ops uaccess_pt = {
+ .copy_from_user = copy_from_user_pt,
+ .copy_from_user_small = copy_from_user_pt,
+ .copy_to_user = copy_to_user_pt,
+ .copy_to_user_small = copy_to_user_pt,
+ .copy_in_user = copy_in_user_pt,
+ .clear_user = clear_user_pt,
+ .strnlen_user = strnlen_user_pt,
+ .strncpy_from_user = strncpy_from_user_pt,
+ .futex_atomic_op = futex_atomic_op_pt,
+ .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
+};
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index bbaca66fa29..28c4500a58d 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -13,6 +13,7 @@
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <asm/futex.h>
+#include "uaccess.h"
#ifndef __s390x__
#define AHI "ahi"
@@ -28,9 +29,6 @@
#define SLR "slgr"
#endif
-extern size_t copy_from_user_pt(size_t n, const void __user *from, void *to);
-extern size_t copy_to_user_pt(size_t n, void __user *to, const void *from);
-
size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
{
unsigned long tmp1, tmp2;
@@ -72,7 +70,8 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
return size;
}
-size_t copy_from_user_std_check(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_std_check(size_t size, const void __user *ptr,
+ void *x)
{
if (size <= 1024)
return copy_from_user_std(size, ptr, x);
@@ -110,14 +109,16 @@ size_t copy_to_user_std(size_t size, void __user *ptr, const void *x)
return size;
}
-size_t copy_to_user_std_check(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_std_check(size_t size, void __user *ptr,
+ const void *x)
{
if (size <= 1024)
return copy_to_user_std(size, ptr, x);
return copy_to_user_pt(size, ptr, x);
}
-size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
+static size_t copy_in_user_std(size_t size, void __user *to,
+ const void __user *from)
{
unsigned long tmp1;
@@ -148,7 +149,7 @@ size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
return size;
}
-size_t clear_user_std(size_t size, void __user *to)
+static size_t clear_user_std(size_t size, void __user *to)
{
unsigned long tmp1, tmp2;
@@ -254,12 +255,10 @@ size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
"m" (*uaddr) : "cc");
-int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
{
int oldval = 0, newval, ret;
- pagefault_disable();
-
switch (op) {
case FUTEX_OP_SET:
__futex_atomic_op("lr %2,%5\n",
@@ -284,12 +283,11 @@ int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
default:
ret = -ENOSYS;
}
- pagefault_enable();
*old = oldval;
return ret;
}
-int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
{
int ret;
@@ -314,6 +312,6 @@ struct uaccess_ops uaccess_std = {
.clear_user = clear_user_std,
.strnlen_user = strnlen_user_std,
.strncpy_from_user = strncpy_from_user_std,
- .futex_atomic_op = futex_atomic_op,
- .futex_atomic_cmpxchg = futex_atomic_cmpxchg,
+ .futex_atomic_op = futex_atomic_op_std,
+ .futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
};
diff --git a/arch/s390/math-emu/Makefile b/arch/s390/math-emu/Makefile
index c10df144f2a..73b3e72efc4 100644
--- a/arch/s390/math-emu/Makefile
+++ b/arch/s390/math-emu/Makefile
@@ -2,7 +2,7 @@
# Makefile for the FPU instruction emulation.
#
-obj-$(CONFIG_MATHEMU) := math.o qrnnd.o
+obj-$(CONFIG_MATHEMU) := math.o
EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
EXTRA_AFLAGS := -traditional
diff --git a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c
index 6b9aec5a2c1..3ee78ccb617 100644
--- a/arch/s390/math-emu/math.c
+++ b/arch/s390/math-emu/math.c
@@ -15,7 +15,7 @@
#include <asm/uaccess.h>
#include <asm/lowcore.h>
-#include "sfp-util.h"
+#include <asm/sfp-util.h>
#include <math-emu/soft-fp.h>
#include <math-emu/single.h>
#include <math-emu/double.h>
diff --git a/arch/s390/math-emu/qrnnd.S b/arch/s390/math-emu/qrnnd.S
deleted file mode 100644
index b01c2b648e2..00000000000
--- a/arch/s390/math-emu/qrnnd.S
+++ /dev/null
@@ -1,77 +0,0 @@
-# S/390 __udiv_qrnnd
-
-# r2 : &__r
-# r3 : upper half of 64 bit word n
-# r4 : lower half of 64 bit word n
-# r5 : divisor d
-# the reminder r of the division is to be stored to &__r and
-# the quotient q is to be returned
-
- .text
- .globl __udiv_qrnnd
-__udiv_qrnnd:
- st %r2,24(%r15) # store pointer to reminder for later
- lr %r0,%r3 # reload n
- lr %r1,%r4
- ltr %r2,%r5 # reload and test divisor
- jp 5f
- # divisor >= 0x80000000
- srdl %r0,2 # n/4
- srl %r2,1 # d/2
- slr %r1,%r2 # special case if last bit of d is set
- brc 3,0f # (n/4) div (n/2) can overflow by 1
- ahi %r0,-1 # trick: subtract n/2, then divide
-0: dr %r0,%r2 # signed division
- ahi %r1,1 # trick part 2: add 1 to the quotient
- # now (n >> 2) = (d >> 1) * %r1 + %r0
- lhi %r3,1
- nr %r3,%r1 # test last bit of q
- jz 1f
- alr %r0,%r2 # add (d>>1) to r
-1: srl %r1,1 # q >>= 1
- # now (n >> 2) = (d&-2) * %r1 + %r0
- lhi %r3,1
- nr %r3,%r5 # test last bit of d
- jz 2f
- slr %r0,%r1 # r -= q
- brc 3,2f # borrow ?
- alr %r0,%r5 # r += d
- ahi %r1,-1
-2: # now (n >> 2) = d * %r1 + %r0
- alr %r1,%r1 # q <<= 1
- alr %r0,%r0 # r <<= 1
- brc 12,3f # overflow on r ?
- slr %r0,%r5 # r -= d
- ahi %r1,1 # q += 1
-3: lhi %r3,2
- nr %r3,%r4 # test next to last bit of n
- jz 4f
- ahi %r0,1 # r += 1
-4: clr %r0,%r5 # r >= d ?
- jl 6f
- slr %r0,%r5 # r -= d
- ahi %r1,1 # q += 1
- # now (n >> 1) = d * %r1 + %r0
- j 6f
-5: # divisor < 0x80000000
- srdl %r0,1
- dr %r0,%r2 # signed division
- # now (n >> 1) = d * %r1 + %r0
-6: alr %r1,%r1 # q <<= 1
- alr %r0,%r0 # r <<= 1
- brc 12,7f # overflow on r ?
- slr %r0,%r5 # r -= d
- ahi %r1,1 # q += 1
-7: lhi %r3,1
- nr %r3,%r4 # isolate last bit of n
- alr %r0,%r3 # r += (n & 1)
- clr %r0,%r5 # r >= d ?
- jl 8f
- slr %r0,%r5 # r -= d
- ahi %r1,1 # q += 1
-8: # now n = d * %r1 + %r0
- l %r2,24(%r15)
- st %r0,0(%r2)
- lr %r2,%r1
- br %r14
- .end __udiv_qrnnd
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index aa9a42b6e62..8e09db1edbb 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -2,6 +2,6 @@
# Makefile for the linux s390-specific parts of the memory manager.
#
-obj-y := init.o fault.o ioremap.o extmem.o mmap.o
+obj-y := init.o fault.o ioremap.o extmem.o mmap.o vmem.o
obj-$(CONFIG_CMM) += cmm.o
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
index 607f50ead1f..f93a056869b 100644
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -245,7 +245,7 @@ cmm_set_timeout(long nr, long seconds)
cmm_set_timer();
}
-static inline int
+static int
cmm_skip_blanks(char *cp, char **endp)
{
char *str;
@@ -414,7 +414,7 @@ cmm_smsg_target(char *from, char *msg)
}
#endif
-struct ctl_table_header *cmm_sysctl_header;
+static struct ctl_table_header *cmm_sysctl_header;
static int
cmm_init (void)
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index 9e9bc48463a..394980b05e6 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -15,7 +15,9 @@
#include <linux/module.h>
#include <linux/bootmem.h>
#include <linux/ctype.h>
+#include <linux/ioport.h>
#include <asm/page.h>
+#include <asm/pgtable.h>
#include <asm/ebcdic.h>
#include <asm/errno.h>
#include <asm/extmem.h>
@@ -69,6 +71,7 @@ struct qin64 {
struct dcss_segment {
struct list_head list;
char dcss_name[8];
+ char res_name[15];
unsigned long start_addr;
unsigned long end;
atomic_t ref_count;
@@ -76,6 +79,7 @@ struct dcss_segment {
unsigned int vm_segtype;
struct qrange range[6];
int segcnt;
+ struct resource *res;
};
static DEFINE_MUTEX(dcss_lock);
@@ -87,7 +91,7 @@ static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
* Create the 8 bytes, ebcdic VM segment name from
* an ascii name.
*/
-static void inline
+static void
dcss_mkname(char *name, char *dcss_name)
{
int i;
@@ -238,65 +242,6 @@ query_segment_type (struct dcss_segment *seg)
}
/*
- * check if the given segment collides with guest storage.
- * returns 1 if this is the case, 0 if no collision was found
- */
-static int
-segment_overlaps_storage(struct dcss_segment *seg)
-{
- int i;
-
- for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
- if (memory_chunk[i].type != CHUNK_READ_WRITE)
- continue;
- if ((memory_chunk[i].addr >> 20) > (seg->end >> 20))
- continue;
- if (((memory_chunk[i].addr + memory_chunk[i].size - 1) >> 20)
- < (seg->start_addr >> 20))
- continue;
- return 1;
- }
- return 0;
-}
-
-/*
- * check if segment collides with other segments that are currently loaded
- * returns 1 if this is the case, 0 if no collision was found
- */
-static int
-segment_overlaps_others (struct dcss_segment *seg)
-{
- struct list_head *l;
- struct dcss_segment *tmp;
-
- BUG_ON(!mutex_is_locked(&dcss_lock));
- list_for_each(l, &dcss_list) {
- tmp = list_entry(l, struct dcss_segment, list);
- if ((tmp->start_addr >> 20) > (seg->end >> 20))
- continue;
- if ((tmp->end >> 20) < (seg->start_addr >> 20))
- continue;
- if (seg == tmp)
- continue;
- return 1;
- }
- return 0;
-}
-
-/*
- * check if segment exceeds the kernel mapping range (detected or set via mem=)
- * returns 1 if this is the case, 0 if segment fits into the range
- */
-static inline int
-segment_exceeds_range (struct dcss_segment *seg)
-{
- int seg_last_pfn = (seg->end) >> PAGE_SHIFT;
- if (seg_last_pfn > max_pfn)
- return 1;
- return 0;
-}
-
-/*
* get info about a segment
* possible return values:
* -ENOSYS : we are not running on VM
@@ -341,24 +286,49 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
rc = query_segment_type (seg);
if (rc < 0)
goto out_free;
- if (segment_exceeds_range(seg)) {
- PRINT_WARN ("segment_load: not loading segment %s - exceeds"
- " kernel mapping range\n",name);
- rc = -ERANGE;
+
+ rc = add_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+
+ switch (rc) {
+ case 0:
+ break;
+ case -ENOSPC:
+ PRINT_WARN("segment_load: not loading segment %s - overlaps "
+ "storage/segment\n", name);
+ goto out_free;
+ case -ERANGE:
+ PRINT_WARN("segment_load: not loading segment %s - exceeds "
+ "kernel mapping range\n", name);
goto out_free;
- }
- if (segment_overlaps_storage(seg)) {
- PRINT_WARN ("segment_load: not loading segment %s - overlaps"
- " storage\n",name);
- rc = -ENOSPC;
+ default:
+ PRINT_WARN("segment_load: not loading segment %s (rc: %d)\n",
+ name, rc);
goto out_free;
}
- if (segment_overlaps_others(seg)) {
- PRINT_WARN ("segment_load: not loading segment %s - overlaps"
- " other segments\n",name);
+
+ seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+ if (seg->res == NULL) {
+ rc = -ENOMEM;
+ goto out_shared;
+ }
+ seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+ seg->res->start = seg->start_addr;
+ seg->res->end = seg->end;
+ memcpy(&seg->res_name, seg->dcss_name, 8);
+ EBCASC(seg->res_name, 8);
+ seg->res_name[8] = '\0';
+ strncat(seg->res_name, " (DCSS)", 7);
+ seg->res->name = seg->res_name;
+ rc = seg->vm_segtype;
+ if (rc == SEG_TYPE_SC ||
+ ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
+ seg->res->flags |= IORESOURCE_READONLY;
+ if (request_resource(&iomem_resource, seg->res)) {
rc = -EBUSY;
- goto out_free;
+ kfree(seg->res);
+ goto out_shared;
}
+
if (do_nonshared)
dcss_command = DCSS_LOADNSR;
else
@@ -372,12 +342,11 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
rc = dcss_diag_translate_rc (seg->end);
dcss_diag(DCSS_PURGESEG, seg->dcss_name,
&seg->start_addr, &seg->end);
- goto out_free;
+ goto out_resource;
}
seg->do_nonshared = do_nonshared;
atomic_set(&seg->ref_count, 1);
list_add(&seg->list, &dcss_list);
- rc = seg->vm_segtype;
*addr = seg->start_addr;
*end = seg->end;
if (do_nonshared)
@@ -385,12 +354,18 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
"type %s in non-shared mode\n", name,
(void*)seg->start_addr, (void*)seg->end,
segtype_string[seg->vm_segtype]);
- else
+ else {
PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
"type %s in shared mode\n", name,
(void*)seg->start_addr, (void*)seg->end,
segtype_string[seg->vm_segtype]);
+ }
goto out;
+ out_resource:
+ release_resource(seg->res);
+ kfree(seg->res);
+ out_shared:
+ remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
out_free:
kfree(seg);
out:
@@ -455,6 +430,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr,
* -ENOENT : no such segment (segment gone!)
* -EAGAIN : segment is in use by other exploiters, try later
* -EINVAL : no segment with the given name is currently loaded - name invalid
+ * -EBUSY : segment can temporarily not be used (overlaps with dcss)
* 0 : operation succeeded
*/
int
@@ -482,12 +458,24 @@ segment_modify_shared (char *name, int do_nonshared)
rc = -EAGAIN;
goto out_unlock;
}
- dcss_diag(DCSS_PURGESEG, seg->dcss_name,
- &dummy, &dummy);
- if (do_nonshared)
+ release_resource(seg->res);
+ if (do_nonshared) {
dcss_command = DCSS_LOADNSR;
- else
- dcss_command = DCSS_LOADNOLY;
+ seg->res->flags &= ~IORESOURCE_READONLY;
+ } else {
+ dcss_command = DCSS_LOADNOLY;
+ if (seg->vm_segtype == SEG_TYPE_SR ||
+ seg->vm_segtype == SEG_TYPE_ER)
+ seg->res->flags |= IORESOURCE_READONLY;
+ }
+ if (request_resource(&iomem_resource, seg->res)) {
+ PRINT_WARN("segment_modify_shared: could not reload segment %s"
+ " - overlapping resources\n", name);
+ rc = -EBUSY;
+ kfree(seg->res);
+ goto out_del;
+ }
+ dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
diag_cc = dcss_diag(dcss_command, seg->dcss_name,
&seg->start_addr, &seg->end);
if (diag_cc > 1) {
@@ -500,9 +488,9 @@ segment_modify_shared (char *name, int do_nonshared)
rc = 0;
goto out_unlock;
out_del:
+ remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
list_del(&seg->list);
- dcss_diag(DCSS_PURGESEG, seg->dcss_name,
- &dummy, &dummy);
+ dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
kfree(seg);
out_unlock:
mutex_unlock(&dcss_lock);
@@ -530,12 +518,14 @@ segment_unload(char *name)
"please report to linux390@de.ibm.com\n",name);
goto out_unlock;
}
- if (atomic_dec_return(&seg->ref_count) == 0) {
- list_del(&seg->list);
- dcss_diag(DCSS_PURGESEG, seg->dcss_name,
- &dummy, &dummy);
- kfree(seg);
- }
+ if (atomic_dec_return(&seg->ref_count) != 0)
+ goto out_unlock;
+ release_resource(seg->res);
+ kfree(seg->res);
+ remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+ list_del(&seg->list);
+ dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
+ kfree(seg);
out_unlock:
mutex_unlock(&dcss_lock);
}
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index cd85e34d870..9ff143e8774 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -52,7 +52,7 @@ extern int sysctl_userprocess_debug;
extern void die(const char *,struct pt_regs *,long);
#ifdef CONFIG_KPROBES
-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
int register_page_fault_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
@@ -137,7 +137,9 @@ static int __check_access_register(struct pt_regs *regs, int error_code)
/*
* Check which address space the address belongs to.
- * Returns 1 for user space and 0 for kernel space.
+ * May return 1 or 2 for user space and 0 for kernel space.
+ * Returns 2 for user space in primary addressing mode with
+ * CONFIG_S390_EXEC_PROTECT on and kernel parameter noexec=on.
*/
static inline int check_user_space(struct pt_regs *regs, int error_code)
{
@@ -154,7 +156,7 @@ static inline int check_user_space(struct pt_regs *regs, int error_code)
return __check_access_register(regs, error_code);
if (descriptor == 2)
return current->thread.mm_segment.ar4;
- return descriptor != 0;
+ return ((descriptor != 0) ^ (switch_amode)) << s390_noexec;
}
/*
@@ -183,6 +185,77 @@ static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
force_sig_info(SIGSEGV, &si, current);
}
+#ifdef CONFIG_S390_EXEC_PROTECT
+extern long sys_sigreturn(struct pt_regs *regs);
+extern long sys_rt_sigreturn(struct pt_regs *regs);
+extern long sys32_sigreturn(struct pt_regs *regs);
+extern long sys32_rt_sigreturn(struct pt_regs *regs);
+
+static inline void do_sigreturn(struct mm_struct *mm, struct pt_regs *regs,
+ int rt)
+{
+ up_read(&mm->mmap_sem);
+ clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
+#ifdef CONFIG_COMPAT
+ if (test_tsk_thread_flag(current, TIF_31BIT)) {
+ if (rt)
+ sys32_rt_sigreturn(regs);
+ else
+ sys32_sigreturn(regs);
+ return;
+ }
+#endif /* CONFIG_COMPAT */
+ if (rt)
+ sys_rt_sigreturn(regs);
+ else
+ sys_sigreturn(regs);
+ return;
+}
+
+static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
+ unsigned long address, unsigned long error_code)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ u16 *instruction;
+ unsigned long pfn, uaddr = regs->psw.addr;
+
+ spin_lock(&mm->page_table_lock);
+ pgd = pgd_offset(mm, uaddr);
+ if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+ goto out_fault;
+ pmd = pmd_offset(pgd, uaddr);
+ if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+ goto out_fault;
+ pte = pte_offset_map(pmd_offset(pgd_offset(mm, uaddr), uaddr), uaddr);
+ if (!pte || !pte_present(*pte))
+ goto out_fault;
+ pfn = pte_pfn(*pte);
+ if (!pfn_valid(pfn))
+ goto out_fault;
+ spin_unlock(&mm->page_table_lock);
+
+ instruction = (u16 *) ((pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE-1)));
+ if (*instruction == 0x0a77)
+ do_sigreturn(mm, regs, 0);
+ else if (*instruction == 0x0aad)
+ do_sigreturn(mm, regs, 1);
+ else {
+ printk("- XXX - do_exception: task = %s, primary, NO EXEC "
+ "-> SIGSEGV\n", current->comm);
+ up_read(&mm->mmap_sem);
+ current->thread.prot_addr = address;
+ current->thread.trap_no = error_code;
+ do_sigsegv(regs, error_code, SEGV_MAPERR, address);
+ }
+ return 0;
+out_fault:
+ spin_unlock(&mm->page_table_lock);
+ return -EFAULT;
+}
+#endif /* CONFIG_S390_EXEC_PROTECT */
+
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
@@ -260,6 +333,17 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
vma = find_vma(mm, address);
if (!vma)
goto bad_area;
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+ if (unlikely((user_address == 2) && !(vma->vm_flags & VM_EXEC)))
+ if (!signal_return(mm, regs, address, error_code))
+ /*
+ * signal_return() has done an up_read(&mm->mmap_sem)
+ * if it returns 0.
+ */
+ return;
+#endif
+
if (vma->vm_start <= address)
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
@@ -452,8 +536,7 @@ void pfault_fini(void)
: : "a" (&refbk), "m" (refbk) : "cc");
}
-asmlinkage void
-pfault_interrupt(__u16 error_code)
+static void 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 e1881c31b1c..b3e7c45efb6 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -24,7 +24,8 @@
#include <linux/pagemap.h>
#include <linux/bootmem.h>
#include <linux/pfn.h>
-
+#include <linux/poison.h>
+#include <linux/initrd.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -69,6 +70,8 @@ void show_mem(void)
printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
i = max_mapnr;
while (i-- > 0) {
+ if (!pfn_valid(i))
+ continue;
page = pfn_to_page(i);
total++;
if (PageReserved(page))
@@ -84,150 +87,50 @@ void show_mem(void)
printk("%d pages swap cached\n",cached);
}
-extern unsigned long __initdata zholes_size[];
-/*
- * paging_init() sets up the page tables
- */
-
-#ifndef CONFIG_64BIT
-void __init paging_init(void)
+static void __init setup_ro_region(void)
{
- pgd_t * pg_dir;
- pte_t * pg_table;
- pte_t pte;
- int i;
- unsigned long tmp;
- unsigned long pfn = 0;
- 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];
-
- 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);
-
- /* unmap whole virtual address space */
-
- pg_dir = swapper_pg_dir;
-
- for (i = 0; i < PTRS_PER_PGD; i++)
- pmd_clear((pmd_t *) pg_dir++);
-
- /*
- * map whole physical memory to virtual memory (identity mapping)
- */
-
- pg_dir = swapper_pg_dir;
-
- while (pfn < max_low_pfn) {
- /*
- * pg_table is physical at this point
- */
- pg_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
-
- pmd_populate_kernel(&init_mm, (pmd_t *) pg_dir, pg_table);
- pg_dir++;
-
- for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
- if (pfn >= ro_start_pfn && pfn < ro_end_pfn)
- pte = pfn_pte(pfn, __pgprot(_PAGE_RO));
- else
- pte = pfn_pte(pfn, PAGE_KERNEL);
- if (pfn >= max_low_pfn)
- pte_val(pte) = _PAGE_TYPE_EMPTY;
- set_pte(pg_table, pte);
- pfn++;
- }
- }
-
- S390_lowcore.kernel_asce = pgdir_k;
-
- /* enable virtual mapping in kernel mode */
- __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();
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ pte_t new_pte;
+ unsigned long address, end;
+
+ address = ((unsigned long)&_stext) & PAGE_MASK;
+ end = PFN_ALIGN((unsigned long)&_eshared);
+
+ for (; address < end; address += PAGE_SIZE) {
+ pgd = pgd_offset_k(address);
+ pmd = pmd_offset(pgd, address);
+ pte = pte_offset_kernel(pmd, address);
+ new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO));
+ *pte = new_pte;
+ }
}
-#else /* CONFIG_64BIT */
-
+/*
+ * paging_init() sets up the page tables
+ */
void __init paging_init(void)
{
- pgd_t * pg_dir;
- pmd_t * pm_dir;
- pte_t * pt_dir;
- pte_t pte;
- int i,j,k;
- unsigned long pfn = 0;
- unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) |
- _KERN_REGION_TABLE;
+ pgd_t *pg_dir;
+ int i;
+ unsigned long pgdir_k;
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;
-
- 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;
- }
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
- /* Initialize mem_map[]. */
- free_area_init_node(0, &contig_page_data, zones_size,
- __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size);
-
- /*
- * map whole physical memory to virtual memory (identity mapping)
- */
-
- pg_dir = swapper_pg_dir;
-
- for (i = 0 ; i < PTRS_PER_PGD ; i++,pg_dir++) {
+ pg_dir = swapper_pg_dir;
- if (pfn >= max_low_pfn) {
- pgd_clear(pg_dir);
- continue;
- }
-
- pm_dir = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE * 4);
- pgd_populate(&init_mm, pg_dir, pm_dir);
-
- for (j = 0 ; j < PTRS_PER_PMD ; j++,pm_dir++) {
- if (pfn >= max_low_pfn) {
- pmd_clear(pm_dir);
- continue;
- }
-
- pt_dir = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
- pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
-
- for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) {
- if (pfn >= ro_start_pfn && pfn < ro_end_pfn)
- pte = pfn_pte(pfn, __pgprot(_PAGE_RO));
- else
- pte = pfn_pte(pfn, PAGE_KERNEL);
- if (pfn >= max_low_pfn)
- pte_val(pte) = _PAGE_TYPE_EMPTY;
- set_pte(pt_dir, pte);
- pfn++;
- }
- }
- }
+#ifdef CONFIG_64BIT
+ pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE;
+ for (i = 0; i < PTRS_PER_PGD; i++)
+ pgd_clear_kernel(pg_dir + i);
+#else
+ pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
+ for (i = 0; i < PTRS_PER_PGD; i++)
+ pmd_clear_kernel((pmd_t *)(pg_dir + i));
+#endif
+ vmem_map_init();
+ setup_ro_region();
S390_lowcore.kernel_asce = pgdir_k;
@@ -237,9 +140,11 @@ void __init paging_init(void)
__ctl_load(pgdir_k, 13, 13);
__raw_local_irq_ssm(ssm_mask);
- local_flush_tlb();
+ 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);
}
-#endif /* CONFIG_64BIT */
void __init mem_init(void)
{
@@ -267,8 +172,8 @@ void __init mem_init(void)
datasize >>10,
initsize >> 10);
printk("Write protected kernel read-only data: %#lx - %#lx\n",
- (unsigned long)&__start_rodata,
- PFN_ALIGN((unsigned long)&__end_rodata) - 1);
+ (unsigned long)&_stext,
+ PFN_ALIGN((unsigned long)&_eshared) - 1);
}
void free_initmem(void)
@@ -279,6 +184,7 @@ void free_initmem(void)
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
ClearPageReserved(virt_to_page(addr));
init_page_count(virt_to_page(addr));
+ memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
free_page(addr);
totalram_pages++;
}
diff --git a/arch/s390/mm/ioremap.c b/arch/s390/mm/ioremap.c
index 0f6e9ecbefe..3d2100a4e20 100644
--- a/arch/s390/mm/ioremap.c
+++ b/arch/s390/mm/ioremap.c
@@ -15,87 +15,8 @@
#include <linux/vmalloc.h>
#include <linux/mm.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;
-
- 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(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;
-}
-
-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 0;
-}
/*
* Generic mapping function (not visible outside):
@@ -122,7 +43,8 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
if (!area)
return NULL;
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(flags))) {
vfree(addr);
return NULL;
}
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
new file mode 100644
index 00000000000..92a56519002
--- /dev/null
+++ b/arch/s390/mm/vmem.c
@@ -0,0 +1,382 @@
+/*
+ * arch/s390/mm/vmem.c
+ *
+ * Copyright IBM Corp. 2006
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/bootmem.h>
+#include <linux/pfn.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/tlbflush.h>
+
+unsigned long vmalloc_end;
+EXPORT_SYMBOL(vmalloc_end);
+
+static struct page *vmem_map;
+static DEFINE_MUTEX(vmem_mutex);
+
+struct memory_segment {
+ struct list_head list;
+ unsigned long start;
+ unsigned long size;
+};
+
+static LIST_HEAD(mem_segs);
+
+void memmap_init(unsigned long size, int nid, unsigned long zone,
+ unsigned long start_pfn)
+{
+ struct page *start, *end;
+ struct page *map_start, *map_end;
+ int i;
+
+ start = pfn_to_page(start_pfn);
+ end = start + size;
+
+ for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+ unsigned long cstart, cend;
+
+ cstart = PFN_DOWN(memory_chunk[i].addr);
+ cend = cstart + PFN_DOWN(memory_chunk[i].size);
+
+ map_start = mem_map + cstart;
+ map_end = mem_map + cend;
+
+ if (map_start < start)
+ map_start = start;
+ if (map_end > end)
+ map_end = end;
+
+ map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1))
+ / sizeof(struct page);
+ map_end += ((PFN_ALIGN((unsigned long) map_end)
+ - (unsigned long) map_end)
+ / sizeof(struct page));
+
+ if (map_start < map_end)
+ memmap_init_zone((unsigned long)(map_end - map_start),
+ nid, zone, page_to_pfn(map_start),
+ MEMMAP_EARLY);
+ }
+}
+
+static inline void *vmem_alloc_pages(unsigned int order)
+{
+ if (slab_is_available())
+ return (void *)__get_free_pages(GFP_KERNEL, order);
+ return alloc_bootmem_pages((1 << order) * PAGE_SIZE);
+}
+
+static inline pmd_t *vmem_pmd_alloc(void)
+{
+ pmd_t *pmd;
+ int i;
+
+ pmd = vmem_alloc_pages(PMD_ALLOC_ORDER);
+ if (!pmd)
+ return NULL;
+ for (i = 0; i < PTRS_PER_PMD; i++)
+ pmd_clear_kernel(pmd + i);
+ return pmd;
+}
+
+static inline pte_t *vmem_pte_alloc(void)
+{
+ pte_t *pte;
+ pte_t empty_pte;
+ int i;
+
+ pte = vmem_alloc_pages(PTE_ALLOC_ORDER);
+ if (!pte)
+ return NULL;
+ pte_val(empty_pte) = _PAGE_TYPE_EMPTY;
+ for (i = 0; i < PTRS_PER_PTE; i++)
+ pte[i] = empty_pte;
+ return pte;
+}
+
+/*
+ * Add a physical memory range to the 1:1 mapping.
+ */
+static int vmem_add_range(unsigned long start, unsigned long size)
+{
+ unsigned long address;
+ pgd_t *pg_dir;
+ pmd_t *pm_dir;
+ pte_t *pt_dir;
+ pte_t pte;
+ int ret = -ENOMEM;
+
+ for (address = start; address < start + size; address += PAGE_SIZE) {
+ pg_dir = pgd_offset_k(address);
+ if (pgd_none(*pg_dir)) {
+ pm_dir = vmem_pmd_alloc();
+ if (!pm_dir)
+ goto out;
+ pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
+ }
+
+ pm_dir = pmd_offset(pg_dir, address);
+ if (pmd_none(*pm_dir)) {
+ pt_dir = vmem_pte_alloc();
+ if (!pt_dir)
+ goto out;
+ pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+ }
+
+ pt_dir = pte_offset_kernel(pm_dir, address);
+ pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
+ *pt_dir = pte;
+ }
+ ret = 0;
+out:
+ flush_tlb_kernel_range(start, start + size);
+ return ret;
+}
+
+/*
+ * Remove a physical memory range from the 1:1 mapping.
+ * Currently only invalidates page table entries.
+ */
+static void vmem_remove_range(unsigned long start, unsigned long size)
+{
+ unsigned long address;
+ pgd_t *pg_dir;
+ pmd_t *pm_dir;
+ pte_t *pt_dir;
+ pte_t pte;
+
+ pte_val(pte) = _PAGE_TYPE_EMPTY;
+ for (address = start; address < start + size; address += PAGE_SIZE) {
+ pg_dir = pgd_offset_k(address);
+ if (pgd_none(*pg_dir))
+ continue;
+ pm_dir = pmd_offset(pg_dir, address);
+ if (pmd_none(*pm_dir))
+ continue;
+ pt_dir = pte_offset_kernel(pm_dir, address);
+ *pt_dir = pte;
+ }
+ flush_tlb_kernel_range(start, start + size);
+}
+
+/*
+ * Add a backed mem_map array to the virtual mem_map array.
+ */
+static int vmem_add_mem_map(unsigned long start, unsigned long size)
+{
+ unsigned long address, start_addr, end_addr;
+ struct page *map_start, *map_end;
+ pgd_t *pg_dir;
+ pmd_t *pm_dir;
+ pte_t *pt_dir;
+ pte_t pte;
+ int ret = -ENOMEM;
+
+ map_start = vmem_map + PFN_DOWN(start);
+ map_end = vmem_map + PFN_DOWN(start + size);
+
+ start_addr = (unsigned long) map_start & PAGE_MASK;
+ end_addr = PFN_ALIGN((unsigned long) map_end);
+
+ for (address = start_addr; address < end_addr; address += PAGE_SIZE) {
+ pg_dir = pgd_offset_k(address);
+ if (pgd_none(*pg_dir)) {
+ pm_dir = vmem_pmd_alloc();
+ if (!pm_dir)
+ goto out;
+ pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
+ }
+
+ pm_dir = pmd_offset(pg_dir, address);
+ if (pmd_none(*pm_dir)) {
+ pt_dir = vmem_pte_alloc();
+ if (!pt_dir)
+ goto out;
+ pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+ }
+
+ pt_dir = pte_offset_kernel(pm_dir, address);
+ if (pte_none(*pt_dir)) {
+ unsigned long new_page;
+
+ new_page =__pa(vmem_alloc_pages(0));
+ if (!new_page)
+ goto out;
+ pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL);
+ *pt_dir = pte;
+ }
+ }
+ ret = 0;
+out:
+ flush_tlb_kernel_range(start_addr, end_addr);
+ return ret;
+}
+
+static int vmem_add_mem(unsigned long start, unsigned long size)
+{
+ int ret;
+
+ ret = vmem_add_range(start, size);
+ if (ret)
+ return ret;
+ return vmem_add_mem_map(start, size);
+}
+
+/*
+ * Add memory segment to the segment list if it doesn't overlap with
+ * an already present segment.
+ */
+static int insert_memory_segment(struct memory_segment *seg)
+{
+ struct memory_segment *tmp;
+
+ if (PFN_DOWN(seg->start + seg->size) > max_pfn ||
+ seg->start + seg->size < seg->start)
+ return -ERANGE;
+
+ list_for_each_entry(tmp, &mem_segs, list) {
+ if (seg->start >= tmp->start + tmp->size)
+ continue;
+ if (seg->start + seg->size <= tmp->start)
+ continue;
+ return -ENOSPC;
+ }
+ list_add(&seg->list, &mem_segs);
+ return 0;
+}
+
+/*
+ * Remove memory segment from the segment list.
+ */
+static void remove_memory_segment(struct memory_segment *seg)
+{
+ list_del(&seg->list);
+}
+
+static void __remove_shared_memory(struct memory_segment *seg)
+{
+ remove_memory_segment(seg);
+ vmem_remove_range(seg->start, seg->size);
+}
+
+int remove_shared_memory(unsigned long start, unsigned long size)
+{
+ struct memory_segment *seg;
+ int ret;
+
+ mutex_lock(&vmem_mutex);
+
+ ret = -ENOENT;
+ list_for_each_entry(seg, &mem_segs, list) {
+ if (seg->start == start && seg->size == size)
+ break;
+ }
+
+ if (seg->start != start || seg->size != size)
+ goto out;
+
+ ret = 0;
+ __remove_shared_memory(seg);
+ kfree(seg);
+out:
+ mutex_unlock(&vmem_mutex);
+ return ret;
+}
+
+int add_shared_memory(unsigned long start, unsigned long size)
+{
+ struct memory_segment *seg;
+ struct page *page;
+ unsigned long pfn, num_pfn, end_pfn;
+ int ret;
+
+ mutex_lock(&vmem_mutex);
+ ret = -ENOMEM;
+ seg = kzalloc(sizeof(*seg), GFP_KERNEL);
+ if (!seg)
+ goto out;
+ seg->start = start;
+ seg->size = size;
+
+ ret = insert_memory_segment(seg);
+ if (ret)
+ goto out_free;
+
+ ret = vmem_add_mem(start, size);
+ if (ret)
+ goto out_remove;
+
+ pfn = PFN_DOWN(start);
+ num_pfn = PFN_DOWN(size);
+ end_pfn = pfn + num_pfn;
+
+ page = pfn_to_page(pfn);
+ memset(page, 0, num_pfn * sizeof(struct page));
+
+ for (; pfn < end_pfn; pfn++) {
+ page = pfn_to_page(pfn);
+ init_page_count(page);
+ reset_page_mapcount(page);
+ SetPageReserved(page);
+ INIT_LIST_HEAD(&page->lru);
+ }
+ goto out;
+
+out_remove:
+ __remove_shared_memory(seg);
+out_free:
+ kfree(seg);
+out:
+ mutex_unlock(&vmem_mutex);
+ return ret;
+}
+
+/*
+ * map whole physical memory to virtual memory (identity mapping)
+ */
+void __init vmem_map_init(void)
+{
+ unsigned long map_size;
+ int i;
+
+ map_size = ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * sizeof(struct page);
+ vmalloc_end = PFN_ALIGN(VMALLOC_END_INIT) - PFN_ALIGN(map_size);
+ vmem_map = (struct page *) vmalloc_end;
+ NODE_DATA(0)->node_mem_map = vmem_map;
+
+ for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
+ vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
+}
+
+/*
+ * Convert memory chunk array to a memory segment list so there is a single
+ * list that contains both r/w memory and shared memory segments.
+ */
+static int __init vmem_convert_memory_chunk(void)
+{
+ struct memory_segment *seg;
+ int i;
+
+ mutex_lock(&vmem_mutex);
+ for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+ if (!memory_chunk[i].size)
+ continue;
+ seg = kzalloc(sizeof(*seg), GFP_KERNEL);
+ if (!seg)
+ panic("Out of memory...\n");
+ seg->start = memory_chunk[i].addr;
+ seg->size = memory_chunk[i].size;
+ insert_memory_segment(seg);
+ }
+ mutex_unlock(&vmem_mutex);
+ return 0;
+}
+
+core_initcall(vmem_convert_memory_chunk);
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index d83d64af31f..4f3891215b8 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -48,6 +48,9 @@ config GENERIC_IOMAP
config GENERIC_TIME
def_bool n
+config SYS_SUPPORTS_APM_EMULATION
+ bool
+
config ARCH_MAY_HAVE_PC_FDC
bool
@@ -59,6 +62,14 @@ config LOCKDEP_SUPPORT
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
source "init/Kconfig"
menu "System type"
@@ -118,6 +129,7 @@ config SH_7751_SYSTEMH
config SH_HP6XX
bool "HP6XX"
+ select SYS_SUPPORTS_APM_EMULATION
help
Select HP6XX if configuring for a HP jornada HP6xx.
More information (hardware only) at
@@ -471,7 +483,7 @@ config SH_CLK_MD
int "CPU Mode Pin Setting"
depends on CPU_SUBTYPE_SH7619 || CPU_SUBTYPE_SH7206
help
- MD2 - MD0 Setting.
+ MD2 - MD0 pin setting.
menu "CPU Frequency scaling"
@@ -572,18 +584,6 @@ config NR_CPUS
source "kernel/Kconfig.preempt"
-config CPU_HAS_SR_RB
- bool "CPU has SR.RB"
- depends on CPU_SH3 || CPU_SH4
- default y
- help
- This will enable the use of SR.RB register bank usage. Processors
- that are lacking this bit must have another method in place for
- accomplishing what is taken care of by the banked registers.
-
- See <file:Documentation/sh/register-banks.txt> for further
- information on SR.RB and register banking in the kernel in general.
-
config NODES_SHIFT
int
default "1"
@@ -698,9 +698,6 @@ depends on EXPERIMENTAL
source kernel/power/Kconfig
-config APM
- bool "Advanced Power Management Emulation"
- depends on PM
endmenu
source "net/Kconfig"
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index 66a25ef4ef1..87902e0298e 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -31,7 +31,8 @@ config EARLY_SCIF_CONSOLE_PORT
hex "SCIF port for early console"
depends on EARLY_SCIF_CONSOLE
default "0xffe00000" if CPU_SUBTYPE_SH7780
- default "0xfffe9800" if CPU_SUBTYPE_SH72060
+ default "0xfffe9800" if CPU_SUBTYPE_SH7206
+ default "0xf8420000" if CPU_SUBTYPE_SH7619
default "0xffe80000" if CPU_SH4
config EARLY_PRINTK
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index d10bba5e107..c1dbef21263 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -179,7 +179,7 @@ maketools: include/linux/version.h FORCE
all: zImage
-zImage: vmlinux
+zImage uImage uImage.srec vmlinux.srec: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
compressed: zImage
@@ -190,5 +190,8 @@ archclean:
CLEAN_FILES += include/asm-sh/machtypes.h
define archhelp
- @echo ' zImage - Compressed kernel image (arch/sh/boot/zImage)'
+ @echo '* zImage - Compressed kernel image'
+ @echo ' vmlinux.srec - Create an ELF S-record'
+ @echo ' uImage - Create a bootable image for U-Boot'
+ @echo ' uImage.srec - Create an S-record for U-Boot'
endef
diff --git a/arch/sh/boards/hp6xx/hp6xx_apm.c b/arch/sh/boards/hp6xx/hp6xx_apm.c
index d146cdaa0b8..d1c1460c8a0 100644
--- a/arch/sh/boards/hp6xx/hp6xx_apm.c
+++ b/arch/sh/boards/hp6xx/hp6xx_apm.c
@@ -7,12 +7,11 @@
* 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 <linux/apm-emulation.h>
+#include <linux/io.h>
#include <asm/adc.h>
#include <asm/hp6xx.h>
@@ -27,60 +26,41 @@
#define MODNAME "hp6x0_apm"
-static int hp6x0_apm_get_info(char *buf, char **start, off_t fpos, int length)
+static void hp6x0_apm_get_power_status(struct apm_power_info *info)
{
+ int battery, backup, charging, percentage;
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;
+ battery = adc_single(ADC_CHANNEL_BATTERY);
+ backup = adc_single(ADC_CHANNEL_BACKUP);
+ charging = adc_single(ADC_CHANNEL_CHARGE);
percentage = 100 * (battery - HP680_BATTERY_MIN) /
(HP680_BATTERY_MAX - HP680_BATTERY_MIN);
- ac_line_status = (battery > HP680_BATTERY_AC_ON) ?
+ info->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;
+ info->battery_status = APM_BATTERY_STATUS_NOT_PRESENT;
+ info->battery_flag = 0x80;
+ } else if (charging < 8) {
+ info->battery_status = APM_BATTERY_STATUS_CHARGING;
+ info->battery_flag = 0x08;
+ info->ac_line_status = 0xff;
} else if (percentage <= APM_CRITICAL) {
- battery_status = APM_BATTERY_STATUS_CRITICAL;
- battery_flag = 0x04;
+ info->battery_status = APM_BATTERY_STATUS_CRITICAL;
+ info->battery_flag = 0x04;
} else if (percentage <= APM_LOW) {
- battery_status = APM_BATTERY_STATUS_LOW;
- battery_flag = 0x02;
+ info->battery_status = APM_BATTERY_STATUS_LOW;
+ info->battery_flag = 0x02;
} else {
- battery_status = APM_BATTERY_STATUS_HIGH;
- battery_flag = 0x01;
+ info->battery_status = APM_BATTERY_STATUS_HIGH;
+ info->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;
+ info->units = 0;
}
static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev)
@@ -96,14 +76,14 @@ static int __init hp6x0_apm_init(void)
int ret;
ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt,
- IRQF_DISABLED, MODNAME, 0);
+ IRQF_DISABLED, MODNAME, NULL);
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;
+ apm_get_power_status = hp6x0_apm_get_power_status;
return ret;
}
@@ -111,7 +91,7 @@ static int __init hp6x0_apm_init(void)
static void __exit hp6x0_apm_exit(void)
{
free_irq(HP680_BTN_IRQ, 0);
- apm_get_info = 0;
+ apm_get_info = NULL;
}
module_init(hp6x0_apm_init);
diff --git a/arch/sh/boards/landisk/irq.c b/arch/sh/boards/landisk/irq.c
index 8f2e1c68b90..3eba6d086d7 100644
--- a/arch/sh/boards/landisk/irq.c
+++ b/arch/sh/boards/landisk/irq.c
@@ -16,8 +16,8 @@
*/
#include <linux/init.h>
#include <linux/irq.h>
-#include <asm/io.h>
-#include <asm/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
#include <asm/landisk/iodata_landisk.h>
static void enable_landisk_irq(unsigned int irq);
diff --git a/arch/sh/boards/se/7206/irq.c b/arch/sh/boards/se/7206/irq.c
index 3fb0c5f5b23..27da88486f7 100644
--- a/arch/sh/boards/se/7206/irq.c
+++ b/arch/sh/boards/se/7206/irq.c
@@ -10,6 +10,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <asm/se7206.h>
#define INTSTS0 0x31800000
@@ -18,6 +19,13 @@
#define INTMSK1 0x31800006
#define INTSEL 0x31800008
+#define IRQ0_IRQ 64
+#define IRQ1_IRQ 65
+#define IRQ3_IRQ 67
+
+#define INTC_IPR01 0xfffe0818
+#define INTC_ICR1 0xfffe0802
+
static void disable_se7206_irq(unsigned int irq)
{
unsigned short val;
@@ -39,7 +47,7 @@ static void disable_se7206_irq(unsigned int irq)
case IRQ1_IRQ:
msk0 |= 0x000f;
break;
- case IRQ2_IRQ:
+ case IRQ3_IRQ:
msk0 |= 0x0f00;
msk1 |= 0x00ff;
break;
@@ -70,7 +78,7 @@ static void enable_se7206_irq(unsigned int irq)
case IRQ1_IRQ:
msk0 &= ~0x000f;
break;
- case IRQ2_IRQ:
+ case IRQ3_IRQ:
msk0 &= ~0x0f00;
msk1 &= ~0x00ff;
break;
@@ -96,7 +104,7 @@ static void eoi_se7206_irq(unsigned int irq)
case IRQ1_IRQ:
sts0 &= ~0x000f;
break;
- case IRQ2_IRQ:
+ case IRQ3_IRQ:
sts0 &= ~0x0f00;
sts1 &= ~0x00ff;
break;
@@ -106,7 +114,7 @@ static void eoi_se7206_irq(unsigned int irq)
}
static struct irq_chip se7206_irq_chip __read_mostly = {
- .name = "SE7206-FPGA-IRQ",
+ .name = "SE7206-FPGA",
.mask = disable_se7206_irq,
.unmask = enable_se7206_irq,
.mask_ack = disable_se7206_irq,
diff --git a/arch/sh/boards/se/7619/Makefile b/arch/sh/boards/se/7619/Makefile
index 3666eca8a65..d21775c28cd 100644
--- a/arch/sh/boards/se/7619/Makefile
+++ b/arch/sh/boards/se/7619/Makefile
@@ -2,4 +2,4 @@
# Makefile for the 7619 SolutionEngine specific parts of the kernel
#
-obj-y := setup.o io.o
+obj-y := setup.o
diff --git a/arch/sh/boards/se/7619/io.c b/arch/sh/boards/se/7619/io.c
deleted file mode 100644
index 176f1f39cd9..00000000000
--- a/arch/sh/boards/se/7619/io.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *
- * linux/arch/sh/boards/se/7619/io.c
- *
- * Copyright (C) 2006 Yoshinori Sato
- *
- * I/O routine for Hitachi 7619 SolutionEngine.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <asm/se7619.h>
-#include <asm/irq.h>
-
-/* FIXME: M3A-ZAB7 Compact Flash Slot support */
-
-static inline void delay(void)
-{
- ctrl_inw(0xa0000000); /* Uncached ROM area (P2) */
-}
-
-#define badio(name,port) \
- printk("bad I/O operation (%s) for port 0x%lx at 0x%08x\n", \
- #name, (port), (__u32) __builtin_return_address(0))
-
-unsigned char se7619___inb(unsigned long port)
-{
- badio(inb, port);
- return 0;
-}
-
-unsigned char se7619___inb_p(unsigned long port)
-{
- badio(inb_p, port);
- delay();
- return 0;
-}
-
-unsigned short se7619___inw(unsigned long port)
-{
- badio(inw, port);
- return 0;
-}
-
-unsigned int se7619___inl(unsigned long port)
-{
- badio(inl, port);
- return 0;
-}
-
-void se7619___outb(unsigned char value, unsigned long port)
-{
- badio(outb, port);
-}
-
-void se7619___outb_p(unsigned char value, unsigned long port)
-{
- badio(outb_p, port);
- delay();
-}
-
-void se7619___outw(unsigned short value, unsigned long port)
-{
- badio(outw, port);
-}
-
-void se7619___outl(unsigned int value, unsigned long port)
-{
- badio(outl, port);
-}
-
-void se7619___insb(unsigned long port, void *addr, unsigned long count)
-{
- badio(inw, port);
-}
-
-void se7619___insw(unsigned long port, void *addr, unsigned long count)
-{
- badio(inw, port);
-}
-
-void se7619___insl(unsigned long port, void *addr, unsigned long count)
-{
- badio(insl, port);
-}
-
-void se7619___outsb(unsigned long port, const void *addr, unsigned long count)
-{
- badio(insl, port);
-}
-
-void se7619___outsw(unsigned long port, const void *addr, unsigned long count)
-{
- badio(insl, port);
-}
-
-void se7619___outsl(unsigned long port, const void *addr, unsigned long count)
-{
- badio(outsw, port);
-}
diff --git a/arch/sh/boards/se/7619/setup.c b/arch/sh/boards/se/7619/setup.c
index e627b26de0d..52d2c4d5d2f 100644
--- a/arch/sh/boards/se/7619/setup.c
+++ b/arch/sh/boards/se/7619/setup.c
@@ -9,7 +9,6 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <asm/io.h>
-#include <asm/se7619.h>
#include <asm/machvec.h>
/*
@@ -19,25 +18,5 @@
struct sh_machine_vector mv_se __initmv = {
.mv_name = "SolutionEngine",
.mv_nr_irqs = 108,
- .mv_inb = se7619___inb,
- .mv_inw = se7619___inw,
- .mv_inl = se7619___inl,
- .mv_outb = se7619___outb,
- .mv_outw = se7619___outw,
- .mv_outl = se7619___outl,
-
- .mv_inb_p = se7619___inb_p,
- .mv_inw_p = se7619___inw,
- .mv_inl_p = se7619___inl,
- .mv_outb_p = se7619___outb_p,
- .mv_outw_p = se7619___outw,
- .mv_outl_p = se7619___outl,
-
- .mv_insb = se7619___insb,
- .mv_insw = se7619___insw,
- .mv_insl = se7619___insl,
- .mv_outsb = se7619___outsb,
- .mv_outsw = se7619___outsw,
- .mv_outsl = se7619___outsl,
};
ALIAS_MV(se)
diff --git a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile
index 60797b31089..11dc272c618 100644
--- a/arch/sh/boot/Makefile
+++ b/arch/sh/boot/Makefile
@@ -8,13 +8,49 @@
# Copyright (C) 1999 Stuart Menefy
#
-targets := zImage
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
+
+#
+# Assign safe dummy values if these variables are not defined,
+# in order to suppress error message.
+#
+CONFIG_PAGE_OFFSET ?= 0x80000000
+CONFIG_MEMORY_START ?= 0x0c000000
+CONFIG_BOOT_LINK_OFFSET ?= 0x00800000
+CONFIG_ZERO_PAGE_OFFSET ?= 0x00001000
+
+export CONFIG_PAGE_OFFSET CONFIG_MEMORY_START CONFIG_BOOT_LINK_OFFSET \
+ CONFIG_ZERO_PAGE_OFFSET
+
+targets := zImage vmlinux.srec uImage uImage.srec
subdir- := compressed
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
- @echo 'Kernel: $@ is ready'
+ @echo ' Kernel: $@ is ready'
$(obj)/compressed/vmlinux: FORCE
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
+KERNEL_LOAD := $(shell printf "0x%8x" $$[$(CONFIG_PAGE_OFFSET) + \
+ $(CONFIG_MEMORY_START) + \
+ $(CONFIG_ZERO_PAGE_OFFSET)+0x1000])
+
+quiet_cmd_uimage = UIMAGE $@
+ cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A sh -O linux -T kernel \
+ -C gzip -a $(KERNEL_LOAD) -e $(KERNEL_LOAD) \
+ -n 'Linux-$(KERNELRELEASE)' -d $< $@
+
+$(obj)/uImage: $(obj)/zImage FORCE
+ $(call if_changed,uimage)
+ @echo ' Image $@ is ready'
+
+OBJCOPYFLAGS_vmlinux.srec := -I binary -O srec
+$(obj)/vmlinux.srec: $(obj)/compressed/vmlinux
+ $(call if_changed,objcopy)
+
+OBJCOPYFLAGS_uImage.srec := -I binary -O srec
+$(obj)/uImage.srec: $(obj)/uImage
+ $(call if_changed,objcopy)
+
+clean-files += uImage uImage.srec vmlinux.srec
diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile
index e5f44379007..d9512416f88 100644
--- a/arch/sh/boot/compressed/Makefile
+++ b/arch/sh/boot/compressed/Makefile
@@ -15,13 +15,7 @@ endif
#
# IMAGE_OFFSET is the load offset of the compression loader
-# 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%08x" $$[$(CONFIG_PAGE_OFFSET) + \
$(CONFIG_MEMORY_START) + \
$(CONFIG_BOOT_LINK_OFFSET)])
diff --git a/arch/sh/boot/compressed/head.S b/arch/sh/boot/compressed/head.S
index 4c26a192277..a8399b01372 100644
--- a/arch/sh/boot/compressed/head.S
+++ b/arch/sh/boot/compressed/head.S
@@ -8,6 +8,7 @@
.text
#include <linux/linkage.h>
+#include <asm/page.h>
.global startup
startup:
@@ -97,7 +98,7 @@ init_stack_addr:
decompress_kernel_addr:
.long decompress_kernel
kernel_start_addr:
- .long _text+0x1000
+ .long _text+PAGE_SIZE
.align 9
fake_headers_as_bzImage:
diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c
index 35452d85b7f..df65e305acf 100644
--- a/arch/sh/boot/compressed/misc.c
+++ b/arch/sh/boot/compressed/misc.c
@@ -13,6 +13,7 @@
#include <asm/uaccess.h>
#include <asm/addrspace.h>
+#include <asm/page.h>
#ifdef CONFIG_SH_STANDARD_BIOS
#include <asm/sh_bios.h>
#endif
@@ -229,7 +230,7 @@ long* stack_start = &user_stack[STACK_SIZE];
void decompress_kernel(void)
{
output_data = 0;
- output_ptr = P2SEGADDR((unsigned long)&_text+0x1000);
+ output_ptr = P2SEGADDR((unsigned long)&_text+PAGE_SIZE);
free_mem_ptr = (unsigned long)&_end;
free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
diff --git a/arch/sh/configs/landisk_defconfig b/arch/sh/configs/landisk_defconfig
index 238c0f10990..e7f8ddb0ada 100644
--- a/arch/sh/configs/landisk_defconfig
+++ b/arch/sh/configs/landisk_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18
-# Tue Oct 3 11:14:13 2006
+# Linux kernel version: 2.6.19
+# Thu Dec 7 17:13:04 2006
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -10,6 +10,9 @@ CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -33,6 +36,7 @@ CONFIG_SYSVIPC=y
# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -114,6 +118,8 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_SH_LANDISK=y
# CONFIG_SH_TITAN is not set
# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
# CONFIG_SH_UNKNOWN is not set
#
@@ -125,6 +131,12 @@ CONFIG_CPU_SH4=y
# SH-2 Processor Support
#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
#
# SH-3 Processor Support
@@ -160,6 +172,7 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
#
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
#
# SH4AL-DSP Processor Support
@@ -175,6 +188,9 @@ CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x04000000
CONFIG_VSYSCALL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -196,16 +212,21 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# Processor features
#
CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
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_IPR_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
#
# Timer support
#
CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+# CONFIG_NO_IDLE_HZ is not set
CONFIG_SH_PCLK_FREQ=33333333
#
@@ -216,9 +237,7 @@ CONFIG_SH_PCLK_FREQ=33333333
#
# DMA support
#
-CONFIG_SH_DMA=y
-CONFIG_NR_ONCHIP_DMA_CHANNELS=4
-# CONFIG_NR_DMA_CHANNELS_BOOL is not set
+# CONFIG_SH_DMA is not set
#
# Companion Chips
@@ -227,6 +246,11 @@ CONFIG_NR_ONCHIP_DMA_CHANNELS=4
CONFIG_HEARTBEAT=y
#
+# Additional SuperH Device Drivers
+#
+# CONFIG_PUSH_SWITCH is not set
+
+#
# Kernel features
#
# CONFIG_HZ_100 is not set
@@ -340,11 +364,13 @@ CONFIG_IP_PNP=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_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
#
# IP: Virtual Server Configuration
@@ -361,24 +387,12 @@ CONFIG_NETFILTER=y
# Core Netfilter Configuration
#
# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED 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
#
@@ -477,6 +491,12 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
@@ -519,6 +539,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
@@ -542,6 +563,7 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
@@ -561,6 +583,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
#
# SCSI Transports
@@ -602,12 +625,12 @@ CONFIG_SCSI_MULTI_LUN=y
# 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_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_DC395x is not set
@@ -615,6 +638,7 @@ CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
#
# PCMCIA SCSI adapter support
@@ -757,6 +781,7 @@ CONFIG_8139CP=y
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -871,10 +896,6 @@ CONFIG_HW_RANDOM=y
# 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
#
@@ -889,7 +910,6 @@ CONFIG_HW_RANDOM=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -905,6 +925,7 @@ CONFIG_HW_RANDOM=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -917,10 +938,6 @@ CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set
#
-# Misc devices
-#
-
-#
# Multimedia devices
#
CONFIG_VIDEO_DEV=m
@@ -1037,6 +1054,7 @@ CONFIG_USB=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -1106,7 +1124,6 @@ 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
@@ -1121,6 +1138,7 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_KAWETH is not set
CONFIG_USB_PEGASUS=m
CONFIG_USB_RTL8150=m
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
CONFIG_USB_MON=y
@@ -1156,6 +1174,7 @@ CONFIG_USB_SERIAL_FTDI_SIO=m
# 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_MOS7720 is not set
# CONFIG_USB_SERIAL_MOS7840 is not set
# CONFIG_USB_SERIAL_NAVMAN is not set
CONFIG_USB_SERIAL_PL2303=m
@@ -1167,6 +1186,7 @@ CONFIG_USB_SERIAL_PL2303=m
# CONFIG_USB_SERIAL_XIRCOM is not set
# CONFIG_USB_SERIAL_OPTION is not set
# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
#
# USB Miscellaneous drivers
@@ -1188,6 +1208,7 @@ CONFIG_USB_EMI26=m
CONFIG_USB_SISUSBVGA=m
CONFIG_USB_SISUSBVGA_CON=y
# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_TEST is not set
#
@@ -1254,6 +1275,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
@@ -1264,6 +1286,7 @@ CONFIG_REISERFS_FS=y
# 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=y
@@ -1414,6 +1437,7 @@ CONFIG_NLS_CODEPAGE_932=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
@@ -1422,6 +1446,7 @@ CONFIG_ENABLE_MUST_CHECK=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_SH_STANDARD_BIOS=y
# CONFIG_EARLY_SCIF_CONSOLE is not set
# CONFIG_EARLY_PRINTK is not set
@@ -1445,6 +1470,4 @@ CONFIG_SH_STANDARD_BIOS=y
# 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/se7206_defconfig b/arch/sh/configs/se7206_defconfig
index 36cec0b6e7c..87ab9080fd1 100644
--- a/arch/sh/configs/se7206_defconfig
+++ b/arch/sh/configs/se7206_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc4
-# Sun Nov 5 16:20:10 2006
+# Linux kernel version: 2.6.19
+# Wed Dec 6 14:40:15 2006
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -11,6 +11,8 @@ CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
# CONFIG_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -34,24 +36,23 @@ CONFIG_LOCALVERSION=""
# CONFIG_IKCONFIG is not set
# 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_UID16 is not set
# CONFIG_SYSCTL_SYSCALL is not set
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS 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_ELF_CORE is not set
+# CONFIG_BASE_FULL is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
CONFIG_SLAB=y
-CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_TINY_SHMEM=y
-CONFIG_BASE_SMALL=0
+CONFIG_BASE_SMALL=1
# CONFIG_SLOB is not set
#
@@ -160,6 +161,7 @@ CONFIG_CPU_SUBTYPE_SH7206=y
#
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
#
# SH4AL-DSP Processor Support
@@ -172,7 +174,10 @@ CONFIG_CPU_SUBTYPE_SH7206=y
#
CONFIG_PAGE_OFFSET=0x00000000
CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x02000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -194,6 +199,7 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# Processor features
#
# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_CPU_BIG_ENDIAN=y
# CONFIG_SH_FPU is not set
# CONFIG_SH_FPU_EMU is not set
# CONFIG_SH_DSP is not set
@@ -203,6 +209,8 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
#
CONFIG_SH_CMT=y
# CONFIG_SH_MTU2 is not set
+CONFIG_SH_TIMER_IRQ=140
+# CONFIG_NO_IDLE_HZ is not set
CONFIG_SH_PCLK_FREQ=33333333
CONFIG_SH_CLK_MD=6
@@ -222,6 +230,11 @@ CONFIG_SH_CLK_MD=6
# CONFIG_HD6446X_SERIES is not set
#
+# Additional SuperH Device Drivers
+#
+# CONFIG_PUSH_SWITCH is not set
+
+#
# Kernel features
#
CONFIG_HZ_100=y
@@ -279,9 +292,6 @@ CONFIG_NET=y
# 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
@@ -297,9 +307,9 @@ CONFIG_IP_FIB_HASH=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_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 is not set
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
@@ -371,7 +381,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_REDBOOT_PARTS=y
CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
@@ -422,7 +432,7 @@ CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_PHYSMAP_START=0x20000000
-CONFIG_MTD_PHYSMAP_LEN=0x1000000
+CONFIG_MTD_PHYSMAP_LEN=0x01000000
CONFIG_MTD_PHYSMAP_BANKWIDTH=4
# CONFIG_MTD_SOLUTIONENGINE is not set
# CONFIG_MTD_UCLINUX is not set
@@ -468,10 +478,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4
# 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=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# 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
@@ -519,7 +526,50 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
#
# Network device support
#
-# CONFIG_NETDEVICES 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
+
+#
+# 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_SMC91X=y
+
+#
+# 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
@@ -536,7 +586,26 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
#
# Input device support
#
-# CONFIG_INPUT is not set
+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
@@ -564,8 +633,7 @@ 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
+# CONFIG_LEGACY_PTYS is not set
#
# IPMI
@@ -576,7 +644,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM is not set
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -610,12 +678,8 @@ CONFIG_HW_RANDOM=y
#
# Hardware Monitoring support
#
-CONFIG_HWMON=y
+# CONFIG_HWMON is not set
# 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
#
# Multimedia devices
@@ -630,7 +694,7 @@ CONFIG_HWMON=y
#
# Graphics support
#
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB is not set
#
@@ -701,8 +765,7 @@ CONFIG_FIRMWARE_EDID=y
#
# File systems
#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
# CONFIG_EXT4DEV_FS is not set
# CONFIG_REISERFS_FS is not set
@@ -755,7 +818,7 @@ CONFIG_RAMFS=y
# CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set
# CONFIG_JFFS2_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
@@ -793,8 +856,9 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
@@ -819,7 +883,7 @@ CONFIG_LOG_BUF_SHIFT=14
#
# Library routines
#
-CONFIG_CRC_CCITT=y
+# 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/se7619_defconfig b/arch/sh/configs/se7619_defconfig
new file mode 100644
index 00000000000..20ac7f4c53f
--- /dev/null
+++ b/arch/sh/configs/se7619_defconfig
@@ -0,0 +1,744 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19
+# Wed Dec 6 16:35:36 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_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_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 is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT 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=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=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_SLAB=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
+# CONFIG_SLOB is not set
+
+#
+# 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 is not set
+# CONFIG_SH_7206_SOLUTION_ENGINE is not set
+CONFIG_SH_7619_SOLUTION_ENGINE=y
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH2=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+CONFIG_CPU_SUBTYPE_SH7619=y
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 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
+# CONFIG_CPU_SUBTYPE_SH7785 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_PAGE_OFFSET=0x00000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB 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=y
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_SH_FPU is not set
+# CONFIG_SH_FPU_EMU is not set
+# CONFIG_SH_DSP is not set
+
+#
+# Timer support
+#
+CONFIG_SH_CMT=y
+CONFIG_SH_TIMER_IRQ=86
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_SH_PCLK_FREQ=31250000
+CONFIG_SH_CLK_MD=5
+
+#
+# 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
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+# 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
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY 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 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=0x01000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_SOLUTIONENGINE is not set
+# CONFIG_MTD_UCLINUX 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_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE 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
+#
+
+#
+# ISDN subsystem
+#
+
+#
+# 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 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=3
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM 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_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM 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 is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+# 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_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_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+# 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_SYSCTL=y
+# CONFIG_SYSFS 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_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
+
+#
+# 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_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK 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 is not set
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# 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/drivers/push-switch.c b/arch/sh/drivers/push-switch.c
index f2b9157c314..b3d20c0e021 100644
--- a/arch/sh/drivers/push-switch.c
+++ b/arch/sh/drivers/push-switch.c
@@ -14,7 +14,7 @@
#include <asm/push-switch.h>
#define DRV_NAME "push-switch"
-#define DRV_VERSION "0.1.0"
+#define DRV_VERSION "0.1.1"
static ssize_t switch_show(struct device *dev,
struct device_attribute *attr,
@@ -32,10 +32,10 @@ static void switch_timer(unsigned long data)
schedule_work(&psw->work);
}
-static void switch_work_handler(void *data)
+static void switch_work_handler(struct work_struct *work)
{
- struct platform_device *pdev = data;
- struct push_switch *psw = platform_get_drvdata(pdev);
+ struct push_switch *psw = container_of(work, struct push_switch, work);
+ struct platform_device *pdev = psw->pdev;
psw->state = 0;
@@ -76,12 +76,15 @@ static int switch_drv_probe(struct platform_device *pdev)
}
}
- INIT_WORK(&psw->work, switch_work_handler, pdev);
+ INIT_WORK(&psw->work, switch_work_handler);
init_timer(&psw->debounce);
psw->debounce.function = switch_timer;
psw->debounce.data = (unsigned long)psw;
+ /* Workqueue API brain-damage */
+ psw->pdev = pdev;
+
platform_set_drvdata(pdev, psw);
return 0;
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 99c7e5249f7..2f6d2bcb1c9 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -19,6 +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
obj-$(CONFIG_STACKTRACE) += stacktrace.o
diff --git a/arch/sh/kernel/apm.c b/arch/sh/kernel/apm.c
deleted file mode 100644
index 4f66f91b100..00000000000
--- a/arch/sh/kernel/apm.c
+++ /dev/null
@@ -1,538 +0,0 @@
-/*
- * 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/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index 0582e6712b7..d055a3ea6b4 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_CPU_SH2) = sh2/
obj-$(CONFIG_CPU_SH2A) = sh2a/
obj-$(CONFIG_CPU_SH3) = sh3/
obj-$(CONFIG_CPU_SH4) = sh4/
+obj-$(CONFIG_CPU_SH4A) += sh4a/
obj-$(CONFIG_UBC_WAKEUP) += ubc.o
obj-$(CONFIG_SH_ADC) += adc.o
diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S
index 34d51b3745e..d51fa5e9904 100644
--- a/arch/sh/kernel/cpu/sh2/entry.S
+++ b/arch/sh/kernel/cpu/sh2/entry.S
@@ -177,15 +177,21 @@ interrupt_entry:
7: .long do_IRQ
8: .long do_exception_error
-trap_entry:
- add #-0x10,r9
+trap_entry:
+ /* verbose BUG trapa entry check */
+ mov #0x3e,r8
+ cmp/ge r8,r9
+ bf/s 1f
+ add #-0x10,r9
+ add #0x10,r9
+1:
shll2 r9 ! TRA
mov #OFF_TRA,r8
add r15,r8
mov.l r9,@r8
mov r9,r8
#ifdef CONFIG_TRACE_IRQFLAGS
- mov.l 5f, r9
+ mov.l 2f, r9
jsr @r9
nop
#endif
@@ -194,12 +200,8 @@ trap_entry:
nop
.align 2
-1: .long syscall_exit
-2: .long break_point_trap_software
-3: .long NR_syscalls
-4: .long sys_call_table
#ifdef CONFIG_TRACE_IRQFLAGS
-5: .long trace_hardirqs_on
+2: .long trace_hardirqs_on
#endif
#if defined(CONFIG_SH_STANDARD_BIOS)
@@ -264,7 +266,7 @@ ENTRY(address_error_handler)
restore_all:
cli
#ifdef CONFIG_TRACE_IRQFLAGS
- mov.l 3f, r0
+ mov.l 1f, r0
jsr @r0
nop
#endif
@@ -309,20 +311,14 @@ restore_all:
mov.l @r15,r15
rte
nop
-2:
- mov.l 1f,r8
- mov.l 2f,r9
- jmp @r9
- lds r8,pr
- .align 2
+#ifdef CONFIG_TRACE_IRQFLAGS
+1: .long trace_hardirqs_off
+#endif
$current_thread_info:
.long __current_thread_info
$cpu_mode:
.long __cpu_mode
-#ifdef CONFIG_TRACE_IRQFLAGS
-3: .long trace_hardirqs_off
-#endif
! common exception handler
#include "../../entry-common.S"
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index 82c2d905152..79283e6c1d8 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -51,3 +51,44 @@ static int __init sh7619_devices_setup(void)
ARRAY_SIZE(sh7619_devices));
}
__initcall(sh7619_devices_setup);
+
+#define INTC_IPRC 0xf8080000UL
+#define INTC_IPRD 0xf8080002UL
+
+#define CMI0_IRQ 86
+
+#define SCIF0_ERI_IRQ 88
+#define SCIF0_RXI_IRQ 89
+#define SCIF0_BRI_IRQ 90
+#define SCIF0_TXI_IRQ 91
+
+#define SCIF1_ERI_IRQ 92
+#define SCIF1_RXI_IRQ 93
+#define SCIF1_BRI_IRQ 94
+#define SCIF1_TXI_IRQ 95
+
+#define SCIF2_BRI_IRQ 96
+#define SCIF2_ERI_IRQ 97
+#define SCIF2_RXI_IRQ 98
+#define SCIF2_TXI_IRQ 99
+
+static struct ipr_data sh7619_ipr_map[] = {
+ { CMI0_IRQ, INTC_IPRC, 1, 2 },
+ { SCIF0_ERI_IRQ, INTC_IPRD, 3, 3 },
+ { SCIF0_RXI_IRQ, INTC_IPRD, 3, 3 },
+ { SCIF0_BRI_IRQ, INTC_IPRD, 3, 3 },
+ { SCIF0_TXI_IRQ, INTC_IPRD, 3, 3 },
+ { SCIF1_ERI_IRQ, INTC_IPRD, 2, 3 },
+ { SCIF1_RXI_IRQ, INTC_IPRD, 2, 3 },
+ { SCIF1_BRI_IRQ, INTC_IPRD, 2, 3 },
+ { SCIF1_TXI_IRQ, INTC_IPRD, 2, 3 },
+ { SCIF2_ERI_IRQ, INTC_IPRD, 1, 3 },
+ { SCIF2_RXI_IRQ, INTC_IPRD, 1, 3 },
+ { SCIF2_BRI_IRQ, INTC_IPRD, 1, 3 },
+ { SCIF2_TXI_IRQ, INTC_IPRD, 1, 3 },
+};
+
+void __init init_IRQ_ipr(void)
+{
+ make_ipr_irq(sh7619_ipr_map, ARRAY_SIZE(sh7619_ipr_map));
+}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
index cdfeef49e62..4b60fcc7d66 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -17,22 +17,22 @@ static struct plat_sci_port sci_platform_data[] = {
.mapbase = 0xfffe8000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 240, 241, 242, 243},
+ .irqs = { 241, 242, 243, 240},
}, {
.mapbase = 0xfffe8800,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 244, 245, 246, 247},
+ .irqs = { 247, 244, 245, 246},
}, {
.mapbase = 0xfffe9000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 248, 249, 250, 251},
+ .irqs = { 249, 250, 251, 248},
}, {
.mapbase = 0xfffe9800,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 252, 253, 254, 255},
+ .irqs = { 253, 254, 255, 252},
}, {
.flags = 0,
}
@@ -56,3 +56,57 @@ static int __init sh7206_devices_setup(void)
ARRAY_SIZE(sh7206_devices));
}
__initcall(sh7206_devices_setup);
+
+#define INTC_IPR08 0xfffe0c04UL
+#define INTC_IPR09 0xfffe0c06UL
+#define INTC_IPR14 0xfffe0c10UL
+
+#define CMI0_IRQ 140
+
+#define MTU1_TGI1A 164
+
+#define SCIF0_BRI_IRQ 240
+#define SCIF0_ERI_IRQ 241
+#define SCIF0_RXI_IRQ 242
+#define SCIF0_TXI_IRQ 243
+
+#define SCIF1_BRI_IRQ 244
+#define SCIF1_ERI_IRQ 245
+#define SCIF1_RXI_IRQ 246
+#define SCIF1_TXI_IRQ 247
+
+#define SCIF2_BRI_IRQ 248
+#define SCIF2_ERI_IRQ 249
+#define SCIF2_RXI_IRQ 250
+#define SCIF2_TXI_IRQ 251
+
+#define SCIF3_BRI_IRQ 252
+#define SCIF3_ERI_IRQ 253
+#define SCIF3_RXI_IRQ 254
+#define SCIF3_TXI_IRQ 255
+
+static struct ipr_data sh7206_ipr_map[] = {
+ { CMI0_IRQ, INTC_IPR08, 3, 2 },
+ { MTU2_TGI1A, INTC_IPR09, 1, 2 },
+ { SCIF0_ERI_IRQ, INTC_IPR14, 3, 3 },
+ { SCIF0_RXI_IRQ, INTC_IPR14, 3, 3 },
+ { SCIF0_BRI_IRQ, INTC_IPR14, 3, 3 },
+ { SCIF0_TXI_IRQ, INTC_IPR14, 3, 3 },
+ { SCIF1_ERI_IRQ, INTC_IPR14, 2, 3 },
+ { SCIF1_RXI_IRQ, INTC_IPR14, 2, 3 },
+ { SCIF1_BRI_IRQ, INTC_IPR14, 2, 3 },
+ { SCIF1_TXI_IRQ, INTC_IPR14, 2, 3 },
+ { SCIF2_ERI_IRQ, INTC_IPR14, 1, 3 },
+ { SCIF2_RXI_IRQ, INTC_IPR14, 1, 3 },
+ { SCIF2_BRI_IRQ, INTC_IPR14, 1, 3 },
+ { SCIF2_TXI_IRQ, INTC_IPR14, 1, 3 },
+ { SCIF3_ERI_IRQ, INTC_IPR14, 0, 3 },
+ { SCIF3_RXI_IRQ, INTC_IPR14, 0, 3 },
+ { SCIF3_BRI_IRQ, INTC_IPR14, 0, 3 },
+ { SCIF3_TXI_IRQ, INTC_IPR14, 0, 3 },
+};
+
+void __init init_IRQ_ipr(void)
+{
+ make_ipr_irq(sh7206_ipr_map, ARRAY_SIZE(sh7206_ipr_map));
+}
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 6e415baf04b..19ca68c7188 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -12,17 +12,12 @@ obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
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)
+ifndef CONFIG_CPU_SH4A
clock-$(CONFIG_CPU_SH4) := clock-sh4.o
-clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
+endif
# Additional clocks by subtype
clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index afe0f1b1c03..9031a22a2ce 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -119,11 +119,20 @@ int __init detect_cpu_and_cache_system(void)
break;
case 0x3000:
case 0x3003:
+ case 0x3009:
cpu_data->type = CPU_SH7343;
cpu_data->icache.ways = 4;
cpu_data->dcache.ways = 4;
cpu_data->flags |= CPU_HAS_LLSC;
break;
+ case 0x3008:
+ if (prr == 0xa0) {
+ cpu_data->type = CPU_SH7722;
+ 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;
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index bbcb06f18b0..cbac27634c0 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -14,6 +14,36 @@
#include <linux/io.h>
#include <asm/sci.h>
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xffc80000,
+ .end = 0xffc80000 + 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 = 20,
+ .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,
@@ -39,6 +69,7 @@ static struct platform_device sci_device = {
};
static struct platform_device *sh7750_devices[] __initdata = {
+ &rtc_device,
&sci_device,
};
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index 0c9ea38d2ca..d7fff752e56 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -111,8 +111,9 @@ static int __sq_remap(struct sq_mapping *map, unsigned long flags)
vma->phys_addr = map->addr;
- if (remap_area_pages((unsigned long)vma->addr, vma->phys_addr,
- map->size, flags)) {
+ if (ioremap_page_range((unsigned long)vma->addr,
+ (unsigned long)vma->addr + map->size,
+ vma->phys_addr, __pgprot(flags))) {
vunmap(vma->addr);
return -EAGAIN;
}
@@ -176,7 +177,7 @@ unsigned long sq_remap(unsigned long phys, unsigned int size,
map->sq_addr = P4SEG_STORE_QUE + (page << PAGE_SHIFT);
- ret = __sq_remap(map, flags);
+ ret = __sq_remap(map, pgprot_val(PAGE_KERNEL_NOCACHE) | flags);
if (unlikely(ret != 0))
goto out;
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
new file mode 100644
index 00000000000..a8f493f2f21
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -0,0 +1,19 @@
+#
+# Makefile for the Linux/SuperH SH-4 backends.
+#
+
+# CPU subtype setup
+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_SH7722) += setup-sh7722.o
+
+# Primary on-chip clocks (common)
+clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7343.o
+
+obj-y += $(clock-y)
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh73180.c b/arch/sh/kernel/cpu/sh4a/clock-sh73180.c
index 2fa5cb2ae68..2fa5cb2ae68 100644
--- a/arch/sh/kernel/cpu/sh4/clock-sh73180.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh73180.c
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
new file mode 100644
index 00000000000..1707a213f0c
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
@@ -0,0 +1,99 @@
+/*
+ * arch/sh/kernel/cpu/sh4/clock-sh7343.c
+ *
+ * SH7343/SH7722 support for the clock framework
+ *
+ * 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/kernel.h>
+#include <linux/io.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+
+/*
+ * SH7343/SH7722 uses a common set of multipliers and divisors, so this
+ * is quite simple..
+ */
+static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
+
+#define pll_calc() (((ctrl_inl(FRQCR) >> 24) & 0x1f) + 1)
+
+static void master_clk_init(struct clk *clk)
+{
+ clk->parent = clk_get(NULL, "cpu_clk");
+}
+
+static void master_clk_recalc(struct clk *clk)
+{
+ int idx = (ctrl_inl(FRQCR) & 0x000f);
+ clk->rate *= clk->parent->rate * multipliers[idx] / divisors[idx];
+}
+
+static struct clk_ops sh7343_master_clk_ops = {
+ .init = master_clk_init,
+ .recalc = master_clk_recalc,
+};
+
+static void module_clk_init(struct clk *clk)
+{
+ clk->parent = NULL;
+ clk->rate = CONFIG_SH_PCLK_FREQ;
+}
+
+static struct clk_ops sh7343_module_clk_ops = {
+ .init = module_clk_init,
+};
+
+static void bus_clk_init(struct clk *clk)
+{
+ clk->parent = clk_get(NULL, "cpu_clk");
+}
+
+static void bus_clk_recalc(struct clk *clk)
+{
+ int idx = (ctrl_inl(FRQCR) >> 8) & 0x000f;
+ clk->rate = clk->parent->rate * multipliers[idx] / divisors[idx];
+}
+
+static struct clk_ops sh7343_bus_clk_ops = {
+ .init = bus_clk_init,
+ .recalc = bus_clk_recalc,
+};
+
+static void cpu_clk_init(struct clk *clk)
+{
+ clk->parent = clk_get(NULL, "module_clk");
+ clk->flags |= CLK_RATE_PROPAGATES;
+ clk_set_rate(clk, clk_get_rate(clk));
+}
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+ int idx = (ctrl_inl(FRQCR) >> 20) & 0x000f;
+ clk->rate = clk->parent->rate * pll_calc() *
+ multipliers[idx] / divisors[idx];
+}
+
+static struct clk_ops sh7343_cpu_clk_ops = {
+ .init = cpu_clk_init,
+ .recalc = cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7343_clk_ops[] = {
+ &sh7343_master_clk_ops,
+ &sh7343_module_clk_ops,
+ &sh7343_bus_clk_ops,
+ &sh7343_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+ if (idx < ARRAY_SIZE(sh7343_clk_ops))
+ *ops = sh7343_clk_ops[idx];
+}
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh7770.c b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c
index c8694bac647..c8694bac647 100644
--- a/arch/sh/kernel/cpu/sh4/clock-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh7780.c b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
index 9e6a216750c..9e6a216750c 100644
--- a/arch/sh/kernel/cpu/sh4/clock-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh73180.c b/arch/sh/kernel/cpu/sh4a/setup-sh73180.c
index cc9ea1e2e5d..cc9ea1e2e5d 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh73180.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh73180.c
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
index 91d61cf91ba..91d61cf91ba 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
new file mode 100644
index 00000000000..1143fbf65fa
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -0,0 +1,80 @@
+/*
+ * SH7722 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 *sh7722_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7722_devices_setup(void)
+{
+ return platform_add_devices(sh7722_devices,
+ ARRAY_SIZE(sh7722_devices));
+}
+__initcall(sh7722_devices_setup);
+
+static struct ipr_data sh7722_ipr_map[] = {
+ /* IRQ, IPR-idx, shift, prio */
+ { 16, 0, 12, 2 }, /* TMU0 */
+ { 17, 0, 8, 2 }, /* TMU1 */
+ { 80, 6, 12, 3 }, /* SCIF ERI */
+ { 81, 6, 12, 3 }, /* SCIF RXI */
+ { 82, 6, 12, 3 }, /* SCIF BRI */
+ { 83, 6, 12, 3 }, /* SCIF TXI */
+};
+
+static unsigned long ipr_offsets[] = {
+ 0xa4080000, /* 0: IPRA */
+ 0xa4080004, /* 1: IPRB */
+ 0xa4080008, /* 2: IPRC */
+ 0xa408000c, /* 3: IPRD */
+ 0xa4080010, /* 4: IPRE */
+ 0xa4080014, /* 5: IPRF */
+ 0xa4080018, /* 6: IPRG */
+ 0xa408001c, /* 7: IPRH */
+ 0xa4080020, /* 8: IPRI */
+ 0xa4080024, /* 9: IPRJ */
+ 0xa4080028, /* 10: IPRK */
+ 0xa408002c, /* 11: IPRL */
+};
+
+unsigned int map_ipridx_to_addr(int idx)
+{
+ if (unlikely(idx >= ARRAY_SIZE(ipr_offsets)))
+ return 0;
+ return ipr_offsets[idx];
+}
+
+void __init init_IRQ_ipr(void)
+{
+ make_ipr_irq(sh7722_ipr_map, ARRAY_SIZE(sh7722_ipr_map));
+}
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
index 6a04cc5f5ac..6a04cc5f5ac 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
index 9aeaa2ddaa2..9aeaa2ddaa2 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c
index 60340823798..560b91cdd15 100644
--- a/arch/sh/kernel/early_printk.c
+++ b/arch/sh/kernel/early_printk.c
@@ -144,16 +144,16 @@ static struct console *early_console =
;
static int __initdata keep_early;
+static int early_console_initialized;
-int __init setup_early_printk(char *opt)
+int __init setup_early_printk(char *buf)
{
- char *space;
- char buf[256];
+ if (!buf)
+ return 0;
- strlcpy(buf, opt, sizeof(buf));
- space = strchr(buf, ' ');
- if (space)
- *space = 0;
+ if (early_console_initialized)
+ return 0;
+ early_console_initialized = 1;
if (strstr(buf, "keep"))
keep_early = 1;
@@ -175,12 +175,14 @@ int __init setup_early_printk(char *opt)
if (likely(early_console))
register_console(early_console);
- return 1;
+ return 0;
}
-__setup("earlyprintk=", setup_early_printk);
+early_param("earlyprintk", setup_early_printk);
void __init disable_early_printk(void)
{
+ if (!early_console_initialized || !early_console)
+ return;
if (!keep_early) {
printk("disabling early console\n");
unregister_console(early_console);
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index 29136a35d7c..fc279aeb73a 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -79,18 +79,29 @@ debug_kernel_sw:
.align 2
3: .long kgdb_handle_exception
#endif /* CONFIG_SH_KGDB */
-
+#ifdef CONFIG_SH_STANDARD_BIOS
+ bra debug_kernel_fw
+ nop
+#endif
#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
-
.align 2
debug_trap:
#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+ mov r8, r0
+ shlr2 r0
+ cmp/eq #0x3f, r0 ! sh_bios() trap
+ bf 1f
+#ifdef CONFIG_SH_KGDB
+ cmp/eq #0xff, r0 ! XXX: KGDB trap, fix for SH-2.
+ bf 1f
+#endif
mov #OFF_SR, r0
mov.l @(r0,r15), r0 ! get status register
shll r0
shll r0 ! kernel space?
bt/s debug_kernel
+1:
#endif
mov.l @r15, r0 ! Restore R0 value
mov.l 1f, r8
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
index 6aca4bc6ec5..71a3ad7d283 100644
--- a/arch/sh/kernel/head.S
+++ b/arch/sh/kernel/head.S
@@ -33,7 +33,8 @@ ENTRY(empty_zero_page)
.long 0x00360000 /* INITRD_START */
.long 0x000a0000 /* INITRD_SIZE */
.long 0
- .balign PAGE_SIZE,0,PAGE_SIZE
+1:
+ .skip PAGE_SIZE - empty_zero_page - 1b
.text
/*
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index f3e2631be14..486c06e1803 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -470,9 +470,10 @@ unsigned long get_wchan(struct task_struct *p)
*/
pc = thread_saved_pc(p);
if (in_sched_functions(pc)) {
- schedule_frame = ((unsigned long *)(long)p->thread.sp)[1];
- return (unsigned long)((unsigned long *)schedule_frame)[1];
+ schedule_frame = (unsigned long)p->thread.sp;
+ return ((unsigned long *)schedule_frame)[21];
}
+
return pc;
}
@@ -498,6 +499,16 @@ asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5,
{
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ /* Rewind */
regs->pc -= 2;
+
+#ifdef CONFIG_BUG
+ if (__kernel_text_address(instruction_pointer(regs))) {
+ u16 insn = *(u16 *)instruction_pointer(regs);
+ if (insn == TRAPA_BUG_OPCODE)
+ handle_BUG(regs);
+ }
+#endif
+
force_sig(SIGTRAP, current);
}
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index f8dd6b7bfab..225f9ea5cdd 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -84,8 +84,7 @@ unsigned long memory_start, memory_end;
static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
struct sh_machine_vector** mvp,
- unsigned long *mv_io_base,
- int *mv_mmio_enable)
+ unsigned long *mv_io_base)
{
char c = ' ', *to = command_line, *from = COMMAND_LINE;
int len = 0;
@@ -112,23 +111,6 @@ static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_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;
@@ -145,7 +127,6 @@ static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
int ints[3];
get_options(mv_comma+1, ARRAY_SIZE(ints), ints);
*mv_io_base = ints[1];
- *mv_mmio_enable = ints[2];
mv_len = mv_comma - from;
} else {
mv_len = mv_end - from;
@@ -158,6 +139,7 @@ static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
*mvp = get_mv_byname(mv_name);
}
+
c = *(from++);
if (!c)
break;
@@ -177,9 +159,8 @@ static int __init sh_mv_setup(char **cmdline_p)
struct sh_machine_vector *mv = NULL;
char mv_name[MV_NAME_SIZE] = "";
unsigned long mv_io_base = 0;
- int mv_mmio_enable = 0;
- parse_cmdline(cmdline_p, mv_name, &mv, &mv_io_base, &mv_mmio_enable);
+ parse_cmdline(cmdline_p, mv_name, &mv, &mv_io_base);
#ifdef CONFIG_SH_UNKNOWN
if (mv == NULL) {
@@ -258,6 +239,7 @@ void __init setup_arch(char **cmdline_p)
sh_mv_setup(cmdline_p);
+
/*
* Find the highest page frame number we have available
*/
@@ -305,6 +287,7 @@ void __init setup_arch(char **cmdline_p)
PFN_PHYS(pages));
}
+
/*
* Reserve the kernel text and
* Reserve the bootmem bitmap. We do this in two steps (first step
@@ -325,14 +308,18 @@ void __init setup_arch(char **cmdline_p)
ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
if (&__rd_start != &__rd_end) {
LOADER_TYPE = 1;
- INITRD_START = PHYSADDR((unsigned long)&__rd_start) - __MEMORY_START;
- INITRD_SIZE = (unsigned long)&__rd_end - (unsigned long)&__rd_start;
+ INITRD_START = PHYSADDR((unsigned long)&__rd_start) -
+ __MEMORY_START;
+ INITRD_SIZE = (unsigned long)&__rd_end -
+ (unsigned long)&__rd_start;
}
if (LOADER_TYPE && INITRD_START) {
if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
- reserve_bootmem_node(NODE_DATA(0), INITRD_START+__MEMORY_START, INITRD_SIZE);
- initrd_start = INITRD_START + PAGE_OFFSET + __MEMORY_START;
+ reserve_bootmem_node(NODE_DATA(0), INITRD_START +
+ __MEMORY_START, INITRD_SIZE);
+ initrd_start = INITRD_START + PAGE_OFFSET +
+ __MEMORY_START;
initrd_end = initrd_start + INITRD_SIZE;
} else {
printk("initrd extends beyond end of memory "
@@ -404,7 +391,7 @@ static const char *cpu_name[] = {
[CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501",
[CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780",
[CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343",
- [CPU_SH7785] = "SH7785",
+ [CPU_SH7785] = "SH7785", [CPU_SH7722] = "SH7722",
[CPU_SH_NONE] = "Unknown"
};
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
index ceee7914340..e6106239a0f 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -70,13 +70,26 @@ DECLARE_EXPORT(__sdivsi3);
DECLARE_EXPORT(__ashrdi3);
DECLARE_EXPORT(__ashldi3);
DECLARE_EXPORT(__lshrdi3);
-DECLARE_EXPORT(__movstr);
DECLARE_EXPORT(__movstrSI16);
+#if __GNUC__ == 4
+DECLARE_EXPORT(__movmem);
+#else
+DECLARE_EXPORT(__movstr);
+#endif
#ifdef CONFIG_CPU_SH4
+#if __GNUC__ == 4
+DECLARE_EXPORT(__movmem_i4_even);
+DECLARE_EXPORT(__movmem_i4_odd);
+DECLARE_EXPORT(__movmemSI12_i4);
+DECLARE_EXPORT(__sdivsi3_i4i);
+DECLARE_EXPORT(__udiv_qrnnd_16);
+DECLARE_EXPORT(__udivsi3_i4i);
+#else /* GCC 3.x */
DECLARE_EXPORT(__movstr_i4_even);
DECLARE_EXPORT(__movstr_i4_odd);
DECLARE_EXPORT(__movstrSI12_i4);
+#endif /* __GNUC__ == 4 */
#endif
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index bb1c480a59c..379c88bf5d9 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -101,7 +101,7 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
*/
#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
-#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
+#if defined(CONFIG_CPU_SH2)
#define TRAP_NOARG 0xc320 /* Syscall w/no args (NR in R3) */
#else
#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) */
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
index 5083b6ed4b3..e18f183e103 100644
--- a/arch/sh/kernel/sys_sh.c
+++ b/arch/sh/kernel/sys_sh.c
@@ -314,6 +314,12 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
#endif
}
+#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
+#define SYSCALL_ARG3 "trapa #0x23"
+#else
+#define SYSCALL_ARG3 "trapa #0x13"
+#endif
+
/*
* Do a system call from kernel instead of calling sys_execve so we
* end up with proper pt_regs.
@@ -324,7 +330,7 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[])
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)
+ __asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0)
: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
: "memory");
return __sc0;
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 3762d9dc204..ec110157992 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -19,6 +19,7 @@
#include <linux/kallsyms.h>
#include <linux/io.h>
#include <linux/debug_locks.h>
+#include <linux/limits.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -129,6 +130,40 @@ static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
return -EFAULT;
}
+#ifdef CONFIG_BUG
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+static inline void do_bug_verbose(struct pt_regs *regs)
+{
+ struct bug_frame f;
+ long len;
+
+ if (__copy_from_user(&f, (const void __user *)regs->pc,
+ sizeof(struct bug_frame)))
+ return;
+
+ len = __strnlen_user(f.file, PATH_MAX) - 1;
+ if (unlikely(len < 0 || len >= PATH_MAX))
+ f.file = "<bad filename>";
+ len = __strnlen_user(f.func, PATH_MAX) - 1;
+ if (unlikely(len < 0 || len >= PATH_MAX))
+ f.func = "<bad function>";
+
+ printk(KERN_ALERT "kernel BUG in %s() at %s:%d!\n",
+ f.func, f.file, f.line);
+}
+#else
+static inline void do_bug_verbose(struct pt_regs *regs)
+{
+}
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
+#endif /* CONFIG_BUG */
+
+void handle_BUG(struct pt_regs *regs)
+{
+ do_bug_verbose(regs);
+ die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
+}
+
/*
* handle an instruction that does an unaligned memory access by emulating the
* desired behaviour
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 77b4026d568..f34bdcc33a7 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -51,7 +51,7 @@ SECTIONS
}
. = ALIGN(PAGE_SIZE);
- .data.page_aligned : { *(.data.idt) }
+ .data.page_aligned : { *(.data.page_aligned) }
. = ALIGN(32);
__per_cpu_start = .;
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c
index deb46941f31..7b0f66f0331 100644
--- a/arch/sh/kernel/vsyscall/vsyscall.c
+++ b/arch/sh/kernel/vsyscall/vsyscall.c
@@ -37,11 +37,12 @@ __setup("vdso=", vdso_setup);
* of the ELF DSO images included therein.
*/
extern const char vsyscall_trapa_start, vsyscall_trapa_end;
-static void *syscall_page;
+static struct page *syscall_pages[1];
int __init vsyscall_init(void)
{
- syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+ void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+ syscall_pages[0] = virt_to_page(syscall_page);
/*
* XXX: Map this page to a fixmap entry if we get around
@@ -55,37 +56,10 @@ int __init vsyscall_init(void)
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;
@@ -97,30 +71,16 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
goto up_fail;
}
- vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
- if (!vma) {
- ret = -ENOMEM;
+ ret = install_special_mapping(mm, addr, PAGE_SIZE,
+ VM_READ | VM_EXEC |
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC |
+ VM_ALWAYSDUMP,
+ syscall_pages);
+ if (unlikely(ret))
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;
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 4e0362f5038..29f4ee35c6d 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -35,6 +35,9 @@ config CPU_SUBTYPE_ST40
select CPU_SH4
select CPU_HAS_INTC2_IRQ
+config CPU_SHX2
+ bool
+
#
# Processor subtypes
#
@@ -180,6 +183,7 @@ config CPU_SUBTYPE_SH7780
config CPU_SUBTYPE_SH7785
bool "Support SH7785 processor"
select CPU_SH4A
+ select CPU_SHX2
select CPU_HAS_INTC2_IRQ
comment "SH4AL-DSP Processor Support"
@@ -192,6 +196,12 @@ config CPU_SUBTYPE_SH7343
bool "Support SH7343 processor"
select CPU_SH4AL_DSP
+config CPU_SUBTYPE_SH7722
+ bool "Support SH7722 processor"
+ select CPU_SH4AL_DSP
+ select CPU_SHX2
+ select CPU_HAS_IPR_IRQ
+
endmenu
menu "Memory management options"
@@ -250,7 +260,7 @@ config 32BIT
config X2TLB
bool "Enable extended TLB mode"
- depends on CPU_SUBTYPE_SH7785 && MMU && EXPERIMENTAL
+ depends on CPU_SHX2 && MMU && EXPERIMENTAL
help
Selecting this option will enable the extended mode of the SH-X2
TLB. For legacy SH-X behaviour and interoperability, say N. For
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index ae531affccb..c6955157c98 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -107,7 +107,7 @@ void __init p3_cache_init(void)
emit_cache_params();
- if (remap_area_pages(P3SEG, 0, PAGE_SIZE * 4, _PAGE_CACHABLE))
+ if (ioremap_page_range(P3SEG, P3SEG + (PAGE_SIZE * 4), 0, PAGE_KERNEL))
panic("%s failed.", __FUNCTION__);
for (i = 0; i < cpu_data->dcache.n_aliases; i++)
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 59f4cc18235..29bd37b1488 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -77,6 +77,7 @@ void show_mem(void)
printk("%d pages swap cached\n",cached);
}
+#ifdef CONFIG_MMU
static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
{
pgd_t *pgd;
@@ -139,6 +140,7 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
set_pte_phys(address, phys, prot);
}
+#endif /* CONFIG_MMU */
/* References to section boundaries */
diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c
index 11d54c14982..90b494a0cf4 100644
--- a/arch/sh/mm/ioremap.c
+++ b/arch/sh/mm/ioremap.c
@@ -16,97 +16,13 @@
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/pci.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/addrspace.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(pgprot_val(PAGE_KERNEL_NOCACHE) | 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;
-}
-
-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_k(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, flags))
- break;
- error = 0;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
- flush_tlb_all();
- return error;
-}
-
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space. Needed when the kernel wants to access high addresses
@@ -121,6 +37,7 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
{
struct vm_struct * area;
unsigned long offset, last_addr, addr, orig_addr;
+ pgprot_t pgprot;
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1;
@@ -190,8 +107,9 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
}
#endif
+ pgprot = __pgprot(pgprot_val(PAGE_KERNEL_NOCACHE) | flags);
if (likely(size))
- if (remap_area_pages(addr, phys_addr, size, flags)) {
+ if (ioremap_page_range(addr, addr + size, phys_addr, pgprot)) {
vunmap((void *)orig_addr);
return NULL;
}
diff --git a/arch/sh/oprofile/op_model_sh7750.c b/arch/sh/oprofile/op_model_sh7750.c
index c265185b22a..60402eec4b4 100644
--- a/arch/sh/oprofile/op_model_sh7750.c
+++ b/arch/sh/oprofile/op_model_sh7750.c
@@ -142,7 +142,7 @@ static u64 sh7750_read_counter(int counter)
*/
static inline int to_counter(struct file *file)
{
- const unsigned char *name = file->f_dentry->d_parent->d_name.name;
+ const unsigned char *name = file->f_path.dentry->d_parent->d_name.name;
return (int)simple_strtol(name, NULL, 10);
}
diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig
index 58c678e0666..7bc0744b7ab 100644
--- a/arch/sh64/Kconfig
+++ b/arch/sh64/Kconfig
@@ -39,6 +39,14 @@ config RWSEM_XCHGADD_ALGORITHM
config GENERIC_ISA_DMA
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
source init/Kconfig
menu "System type"
diff --git a/arch/sh64/mm/ioremap.c b/arch/sh64/mm/ioremap.c
index 80c56754f51..ff26c02511a 100644
--- a/arch/sh64/mm/ioremap.c
+++ b/arch/sh64/mm/ioremap.c
@@ -18,7 +18,7 @@
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/string.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#include <linux/ioport.h>
@@ -28,96 +28,6 @@
static void shmedia_mapioaddr(unsigned long, unsigned long);
static unsigned long shmedia_ioremap(struct resource *, u32, int);
-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_PRESENT | _PAGE_READ |
- _PAGE_WRITE | _PAGE_DIRTY |
- _PAGE_ACCESSED | _PAGE_SHARED | flags);
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- if (address >= end)
- BUG();
-
- pfn = phys_addr >> PAGE_SHIFT;
-
- pr_debug(" %s: pte %p address %lx size %lx phys_addr %lx\n",
- __FUNCTION__,pte,address,size,phys_addr);
-
- 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_k(address);
- flush_cache_all();
- if (address >= end)
- BUG();
- do {
- pmd_t *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 0;
-}
-
/*
* Generic mapping function (not visible outside):
*/
@@ -136,12 +46,17 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
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;
if (!size || last_addr < phys_addr)
return NULL;
+ pgprot = __pgprot(_PAGE_PRESENT | _PAGE_READ |
+ _PAGE_WRITE | _PAGE_DIRTY |
+ _PAGE_ACCESSED | _PAGE_SHARED | flags);
+
/*
* Mappings have to be page-aligned
*/
@@ -158,7 +73,8 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
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)) {
vunmap(addr);
return NULL;
}
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 92a7c8a636d..d0dec1ea2ee 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -166,6 +166,14 @@ config ARCH_MAY_HAVE_PC_FDC
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config SUN_PM
bool
default y
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index a6985626300..79e54894529 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -1,41 +1,59 @@
#
# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc1
+# Sun Dec 17 14:20:47 2006
#
CONFIG_MMU=y
-CONFIG_UID16=y
CONFIG_HIGHMEM=y
CONFIG_GENERIC_ISA_DMA=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=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_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_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=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_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
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_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE 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
#
# Loadable module support
@@ -43,17 +61,36 @@ CONFIG_IOSCHED_CFQ=y
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
#
-# General setup
+# 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"
+
+#
+# General machine setup
#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
# CONFIG_SMP is not set
+CONFIG_SPARC=y
CONFIG_SPARC32=y
CONFIG_SBUS=y
CONFIG_SBUSCHAR=y
@@ -61,73 +98,170 @@ CONFIG_SERIAL_CONSOLE=y
CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_SUN_PM=y
# CONFIG_SUN4 is not set
CONFIG_PCI=y
-# CONFIG_PCI_LEGACY_PROC is not set
-# CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
+# CONFIG_PCI_DEBUG is not set
CONFIG_SUN_OPENPROMFS=m
+# CONFIG_SPARC_LED is not set
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_MISC=m
CONFIG_SUNOS_EMUL=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
#
-# Parallel port support
+# Networking
#
-# CONFIG_PARPORT is not set
+CONFIG_NET=y
#
-# Generic Driver Options
+# Networking options
#
-# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_NET_KEY=m
+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=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_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"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+# CONFIG_IPV6_ROUTER_PREF is not set
+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_SIT=m
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
#
-# Graphics support
+# DCCP Configuration (EXPERIMENTAL)
#
-# CONFIG_FB is not set
+# CONFIG_IP_DCCP is not set
#
-# Console display driver support
+# SCTP Configuration (EXPERIMENTAL)
#
-# CONFIG_MDA_CONSOLE is not set
-# CONFIG_PROM_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+CONFIG_SCTP_DBG_OBJCNT=y
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
#
-# Memory Technology Devices (MTD)
+# TIPC Configuration (EXPERIMENTAL)
#
-# CONFIG_MTD 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
#
-# Serial drivers
+# QoS and/or fair queueing
#
-# CONFIG_SERIAL_8250 is not set
+# CONFIG_NET_SCHED is not set
#
-# Non-8250 serial port support
+# Network testing
#
-CONFIG_SERIAL_SUNCORE=y
-CONFIG_SERIAL_SUNZILOG=y
-CONFIG_SERIAL_SUNZILOG_CONSOLE=y
-CONFIG_SERIAL_SUNSU=y
-CONFIG_SERIAL_SUNSU_CONSOLE=y
-# CONFIG_SERIAL_SUNSAB is not set
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
#
-# Misc Linux/SPARC drivers
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+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)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
#
-CONFIG_SUN_OPENPROMIO=m
-CONFIG_SUN_MOSTEK_RTC=m
-# CONFIG_SUN_BPP is not set
-# CONFIG_SUN_VIDEOPIX is not set
-# CONFIG_SUN_AURORA is not set
-# CONFIG_TADPOLE_TS102_UCTRL is not set
-# CONFIG_SUN_JSFLASH is not set
-CONFIG_APM_RTC_IS_GMT=y
-CONFIG_RTC=m
#
# Block devices
@@ -137,28 +271,37 @@ CONFIG_RTC=m
# 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_CARMEL 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_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
#
-# ATA/ATAPI/MFM/RLL support
+# Misc devices
#
-# CONFIG_IDE is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
#
-# ISDN subsystem
+# ATA/ATAPI/MFM/RLL support
#
-# CONFIG_ISDN is not set
+# CONFIG_IDE is not set
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -170,6 +313,7 @@ CONFIG_BLK_DEV_SD=y
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
@@ -177,57 +321,58 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
#
-# SCSI Transport Attributes
+# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=m
# 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_ADVANSYS is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC 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_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_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
CONFIG_SCSI_QLOGICPTI=m
-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_QLA6322 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
CONFIG_SCSI_SUNESP=y
+# CONFIG_SCSI_SRP is not set
#
-# Fibre Channel support
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
#
-# CONFIG_FC4 is not set
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -235,85 +380,31 @@ CONFIG_SCSI_SUNESP=y
# CONFIG_MD is not set
#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
+# Fusion MPT device support
#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=m
-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=y
-CONFIG_INET_ESP=y
-CONFIG_INET_IPCOMP=y
-CONFIG_IPV6=m
-CONFIG_IPV6_PRIVACY=y
-CONFIG_INET6_AH=m
-CONFIG_INET6_ESP=m
-CONFIG_INET6_IPCOMP=m
-CONFIG_IPV6_TUNNEL=m
-# CONFIG_NETFILTER is not set
-CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
#
-# SCTP Configuration (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
#
-CONFIG_IP_SCTP=m
-# CONFIG_SCTP_DBG_MSG is not set
-CONFIG_SCTP_DBG_OBJCNT=y
-# CONFIG_SCTP_HMAC_NONE is not set
-# CONFIG_SCTP_HMAC_SHA1 is not set
-CONFIG_SCTP_HMAC_MD5=y
-# 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
-# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_IEEE1394 is not set
#
-# QoS and/or fair queueing
+# I2O device support
#
-# CONFIG_NET_SCHED is not set
+# CONFIG_I2O is not set
#
-# Network testing
+# Network device support
#
-CONFIG_NET_PKTGEN=m
-# 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=m
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
CONFIG_TUN=m
-# CONFIG_ETHERTAP is not set
#
# ARCnet devices
@@ -321,6 +412,11 @@ CONFIG_TUN=m
# CONFIG_ARCNET is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
@@ -330,6 +426,7 @@ CONFIG_HAPPYMEAL=m
CONFIG_SUNBMAC=m
CONFIG_SUNQE=m
# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
#
@@ -350,14 +447,22 @@ CONFIG_SUNQE=m
# 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_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
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -380,17 +485,24 @@ CONFIG_SUNQE=m
# 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
#
-# Unix98 PTY support
+# ISDN subsystem
#
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+# 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
@@ -405,17 +517,6 @@ CONFIG_INPUT_EVDEV=m
CONFIG_INPUT_EVBUG=m
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=m
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=m
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-
-#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
@@ -424,6 +525,7 @@ CONFIG_KEYBOARD_SUNKBD=m
# 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=m
CONFIG_MOUSE_SERIAL=m
@@ -433,29 +535,239 @@ CONFIG_MOUSE_SERIAL=m
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SUNCORE=y
+CONFIG_SERIAL_SUNZILOG=y
+CONFIG_SERIAL_SUNZILOG_CONSOLE=y
+CONFIG_SERIAL_SUNSU=y
+CONFIG_SERIAL_SUNSU_CONSOLE=y
+# CONFIG_SERIAL_SUNSAB is not set
+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=m
+CONFIG_RTC=m
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM 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_PC87427 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP 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=y
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_PROM_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# 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
+#
+
+#
+# Virtualization
+#
+
+#
+# Misc Linux/SPARC drivers
+#
+CONFIG_SUN_OPENPROMIO=m
+CONFIG_SUN_MOSTEK_RTC=m
+# CONFIG_SUN_BPP is not set
+# CONFIG_SUN_VIDEOPIX is not set
+# CONFIG_TADPOLE_TS102_UCTRL is not set
+# CONFIG_SUN_JSFLASH is not set
+
+#
+# Unix98 PTY support
+#
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
# File systems
#
CONFIG_EXT2_FS=y
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_JBD is not set
+# CONFIG_EXT4DEV_FS 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=m
-CONFIG_XFS_RT=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_SECURITY=y
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=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 is not set
#
# CD-ROM/DVD Filesystems
@@ -468,7 +780,8 @@ CONFIG_ISO9660_FS=m
#
# DOS/FAT/NT Filesystems
#
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
# CONFIG_NTFS_FS is not set
#
@@ -476,13 +789,12 @@ CONFIG_ISO9660_FS=m
#
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=y
-# CONFIG_DEVPTS_FS_SECURITY is not set
# CONFIG_TMPFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -512,17 +824,23 @@ CONFIG_NFS_FS=y
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
-# CONFIG_EXPORTFS is not set
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=m
CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS 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
CONFIG_AFS_FS=m
CONFIG_RXRPC=m
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -559,6 +877,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# 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
@@ -575,70 +894,104 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_UTF8 is not set
#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
+# Distributed Lock Manager
#
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
+# CONFIG_DLM is not set
#
-# Watchdog Cards
+# Instrumentation Support
#
-# CONFIG_WATCHDOG is not set
+# 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
-CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO 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_DEBUG_STACK_USAGE 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=y
CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
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
CONFIG_CRYPTO_CAST6=m
+# CONFIG_CRYPTO_TEA is not set
CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_CRC32C=m
# CONFIG_CRYPTO_TEST is not set
#
+# Hardware crypto devices
+#
+
+#
# Library routines
#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 54d51b40460..987ec6782f9 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -153,7 +153,7 @@ void __iomem *of_ioremap(struct resource *res, unsigned long offset,
}
EXPORT_SYMBOL(of_ioremap);
-void of_iounmap(void __iomem *base, unsigned long size)
+void of_iounmap(struct resource *res, void __iomem *base, unsigned long size)
{
iounmap(base);
}
@@ -317,9 +317,8 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
if ((va = __get_free_pages(GFP_KERNEL|__GFP_COMP, order)) == 0)
goto err_nopages;
- if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL)
+ if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL)
goto err_nomem;
- memset((char*)res, 0, sizeof(struct resource));
if (allocate_resource(&_sparc_dvma, res, len_total,
_sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) {
@@ -589,12 +588,11 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba)
return NULL;
}
- if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {
+ if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {
free_pages(va, order);
printk("pci_alloc_consistent: no core\n");
return NULL;
}
- memset((char*)res, 0, sizeof(struct resource));
if (allocate_resource(&_sparc_dvma, res, len_total,
_sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) {
@@ -728,7 +726,8 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
/* IIep is write-through, not flushing. */
for (n = 0; n < nents; n++) {
BUG_ON(page_address(sg->page) == NULL);
- sg->dvma_address = virt_to_phys(page_address(sg->page));
+ sg->dvma_address =
+ virt_to_phys(page_address(sg->page)) + sg->offset;
sg->dvma_length = sg->length;
sg++;
}
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index c8cb211b907..5b4841d067c 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -425,7 +425,7 @@ int request_fast_irq(unsigned int irq,
}
if (action == NULL)
- action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+ action = kmalloc(sizeof(struct irqaction),
GFP_ATOMIC);
if (!action) {
@@ -528,7 +528,7 @@ int request_irq(unsigned int irq,
}
if (action == NULL)
- action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+ action = kmalloc(sizeof(struct irqaction),
GFP_ATOMIC);
if (!action) {
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index 46200c43ffb..dab6169e31c 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -793,10 +793,9 @@ struct of_device* of_platform_device_create(struct device_node *np,
{
struct of_device *dev;
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
- memset(dev, 0, sizeof(*dev));
dev->dev.parent = parent;
dev->dev.bus = bus;
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 89a28cc018c..113bd48a89b 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -54,6 +54,7 @@ void (*pm_idle)(void);
* handler when auxio is not present-- unused for now...
*/
void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
/*
* sysctl - toggle power-off restriction for serial console
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 1baf13ed5c3..003f8eed32f 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -289,7 +289,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
if (request == PTRACE_TRACEME) {
ret = ptrace_traceme();
- pt_succ_return(regs, 0);
+ if (ret < 0)
+ pt_error_return(regs, -ret);
+ else
+ pt_succ_return(regs, 0);
goto out;
}
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index 276f22881d0..6b5f26b0fb7 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -292,8 +292,8 @@ int setup_profiling_timer(unsigned int multiplier)
void __init smp_prepare_cpus(unsigned int max_cpus)
{
- extern void smp4m_boot_cpus(void);
- extern void smp4d_boot_cpus(void);
+ extern void __init smp4m_boot_cpus(void);
+ extern void __init smp4d_boot_cpus(void);
int i, cpuid, extra;
printk("Entering SMP Mode...\n");
@@ -375,8 +375,8 @@ void __init smp_prepare_boot_cpu(void)
int __cpuinit __cpu_up(unsigned int cpu)
{
- extern int smp4m_boot_one_cpu(int);
- extern int smp4d_boot_one_cpu(int);
+ extern int __cpuinit smp4m_boot_one_cpu(int);
+ extern int __cpuinit smp4d_boot_one_cpu(int);
int ret=0;
switch(sparc_cpu_model) {
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 33dadd9f287..d8e008a04e2 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -83,9 +83,6 @@ extern int __divdi3(int, int);
/* Private functions with odd calling conventions. */
extern void ___atomic24_add(void);
extern void ___atomic24_sub(void);
-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);
@@ -125,11 +122,6 @@ EXPORT_SYMBOL(pfn_base);
EXPORT_SYMBOL(___atomic24_add);
EXPORT_SYMBOL(___atomic24_sub);
-/* Bit operations. */
-EXPORT_SYMBOL(___set_bit);
-EXPORT_SYMBOL(___clear_bit);
-EXPORT_SYMBOL(___change_bit);
-
/* Per-CPU information table */
EXPORT_PER_CPU_SYMBOL(__cpu_data);
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index d4f9da8170c..0e27e226e0e 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -327,7 +327,7 @@ int sun4d_request_irq(unsigned int irq,
}
if (action == NULL)
- action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+ action = kmalloc(sizeof(struct irqaction),
GFP_ATOMIC);
if (!action) {
@@ -545,8 +545,11 @@ void __init sun4d_init_sbi_irq(void)
nsbi = 0;
for_each_sbus(sbus)
nsbi++;
- sbus_actions = (struct sbus_action *)kmalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
- memset (sbus_actions, 0, (nsbi * 8 * 4 * sizeof(struct sbus_action)));
+ sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
+ if (!sbus_actions) {
+ prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
+ prom_halt();
+ }
for_each_sbus(sbus) {
#ifdef CONFIG_SMP
extern unsigned char boot_cpu_id;
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index c80ea61e8ba..c69de5d4863 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -164,7 +164,7 @@ void __init smp4d_boot_cpus(void)
local_flush_cache_all();
}
-int smp4d_boot_one_cpu(int i)
+int __cpuinit smp4d_boot_one_cpu(int i)
{
extern unsigned long sun4d_cpu_startup;
unsigned long *entry = &sun4d_cpu_startup;
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 6f3ac548ee6..0bf8c165fc9 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -94,8 +94,8 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
* SunOS is so stupid some times... hmph!
*/
if (file) {
- if (imajor(file->f_dentry->d_inode) == MEM_MAJOR &&
- iminor(file->f_dentry->d_inode) == 5) {
+ if (imajor(file->f_path.dentry->d_inode) == MEM_MAJOR &&
+ iminor(file->f_path.dentry->d_inode) == 5) {
flags |= MAP_ANONYMOUS;
fput(file);
file = NULL;
@@ -655,7 +655,7 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
if (!file)
goto out;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
socket = SOCKET_I(inode);
local.sin_family = AF_INET;
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 6c7aa51b590..2fcce000d87 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -78,7 +78,6 @@ unsigned long profile_pc(struct pt_regs *regs)
extern char __copy_user_begin[], __copy_user_end[];
extern char __atomic_begin[], __atomic_end[];
extern char __bzero_begin[], __bzero_end[];
- extern char __bitops_begin[], __bitops_end[];
unsigned long pc = regs->pc;
@@ -88,9 +87,7 @@ unsigned long profile_pc(struct pt_regs *regs)
(pc >= (unsigned long) __atomic_begin &&
pc < (unsigned long) __atomic_end) ||
(pc >= (unsigned long) __bzero_begin &&
- pc < (unsigned long) __bzero_end) ||
- (pc >= (unsigned long) __bitops_begin &&
- pc < (unsigned long) __bitops_end))
+ pc < (unsigned long) __bzero_end))
pc = regs->u_regs[UREG_RETPC];
return pc;
}
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 5db7e1d8538..9ddc5b9ce3b 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -7,7 +7,7 @@ EXTRA_AFLAGS := -ansi -DST_DIV0=0x02
lib-y := mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \
strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
- copy_user.o locks.o atomic.o atomic32.o bitops.o \
+ copy_user.o locks.o atomic.o \
lshrdi3.o ashldi3.o rwsem.o muldi3.o bitext.o
-obj-y += iomap.o
+obj-y += iomap.o atomic32.o
diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c
index de84f8534ba..53ddcd9d1e6 100644
--- a/arch/sparc/lib/atomic32.c
+++ b/arch/sparc/lib/atomic32.c
@@ -76,3 +76,42 @@ void atomic_set(atomic_t *v, int i)
spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
}
EXPORT_SYMBOL(atomic_set);
+
+unsigned long ___set_bit(unsigned long *addr, unsigned long mask)
+{
+ unsigned long old, flags;
+
+ spin_lock_irqsave(ATOMIC_HASH(addr), flags);
+ old = *addr;
+ *addr = old | mask;
+ spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
+
+ return old & mask;
+}
+EXPORT_SYMBOL(___set_bit);
+
+unsigned long ___clear_bit(unsigned long *addr, unsigned long mask)
+{
+ unsigned long old, flags;
+
+ spin_lock_irqsave(ATOMIC_HASH(addr), flags);
+ old = *addr;
+ *addr = old & ~mask;
+ spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
+
+ return old & mask;
+}
+EXPORT_SYMBOL(___clear_bit);
+
+unsigned long ___change_bit(unsigned long *addr, unsigned long mask)
+{
+ unsigned long old, flags;
+
+ spin_lock_irqsave(ATOMIC_HASH(addr), flags);
+ old = *addr;
+ *addr = old ^ mask;
+ spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
+
+ return old & mask;
+}
+EXPORT_SYMBOL(___change_bit);
diff --git a/arch/sparc/lib/bitops.S b/arch/sparc/lib/bitops.S
deleted file mode 100644
index cb7fb66a40c..00000000000
--- a/arch/sparc/lib/bitops.S
+++ /dev/null
@@ -1,109 +0,0 @@
-/* bitops.S: Low level assembler bit operations.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/ptrace.h>
-#include <asm/psr.h>
-
- .text
- .align 4
-
- .globl __bitops_begin
-__bitops_begin:
-
- /* Take bits in %g2 and set them in word at %g1,
- * return whether bits were set in original value
- * in %g2. %g4 holds value to restore into %o7
- * in delay slot of jmpl return, %g3 + %g5 + %g7 can be
- * used as temporaries and thus is considered clobbered
- * by all callers.
- */
- .globl ___set_bit
-___set_bit:
- rd %psr, %g3
- nop; nop; nop;
- or %g3, PSR_PIL, %g5
- wr %g5, 0x0, %psr
- nop; nop; nop
-#ifdef CONFIG_SMP
- set bitops_spinlock, %g5
-2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
- orcc %g7, 0x0, %g0 ! Did we get it?
- bne 2b ! Nope...
-#endif
- ld [%g1], %g7
- or %g7, %g2, %g5
- and %g7, %g2, %g2
-#ifdef CONFIG_SMP
- st %g5, [%g1]
- set bitops_spinlock, %g5
- stb %g0, [%g5]
-#else
- st %g5, [%g1]
-#endif
- wr %g3, 0x0, %psr
- nop; nop; nop
- jmpl %o7, %g0
- mov %g4, %o7
-
- /* Same as above, but clears the bits from %g2 instead. */
- .globl ___clear_bit
-___clear_bit:
- rd %psr, %g3
- nop; nop; nop
- or %g3, PSR_PIL, %g5
- wr %g5, 0x0, %psr
- nop; nop; nop
-#ifdef CONFIG_SMP
- set bitops_spinlock, %g5
-2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
- orcc %g7, 0x0, %g0 ! Did we get it?
- bne 2b ! Nope...
-#endif
- ld [%g1], %g7
- andn %g7, %g2, %g5
- and %g7, %g2, %g2
-#ifdef CONFIG_SMP
- st %g5, [%g1]
- set bitops_spinlock, %g5
- stb %g0, [%g5]
-#else
- st %g5, [%g1]
-#endif
- wr %g3, 0x0, %psr
- nop; nop; nop
- jmpl %o7, %g0
- mov %g4, %o7
-
- /* Same thing again, but this time toggles the bits from %g2. */
- .globl ___change_bit
-___change_bit:
- rd %psr, %g3
- nop; nop; nop
- or %g3, PSR_PIL, %g5
- wr %g5, 0x0, %psr
- nop; nop; nop
-#ifdef CONFIG_SMP
- set bitops_spinlock, %g5
-2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
- orcc %g7, 0x0, %g0 ! Did we get it?
- bne 2b ! Nope...
-#endif
- ld [%g1], %g7
- xor %g7, %g2, %g5
- and %g7, %g2, %g2
-#ifdef CONFIG_SMP
- st %g5, [%g1]
- set bitops_spinlock, %g5
- stb %g0, [%g5]
-#else
- st %g5, [%g1]
-#endif
- wr %g3, 0x0, %psr
- nop; nop; nop
- jmpl %o7, %g0
- mov %g4, %o7
-
- .globl __bitops_end
-__bitops_end:
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
index 2bb1309003d..4ccda77d08d 100644
--- a/arch/sparc/mm/io-unit.c
+++ b/arch/sparc/mm/io-unit.c
@@ -22,6 +22,7 @@
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/dma.h>
+#include <asm/oplib.h>
/* #define IOUNIT_DEBUG */
#ifdef IOUNIT_DEBUG
@@ -41,9 +42,12 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
struct linux_prom_registers iommu_promregs[PROMREG_MAX];
struct resource r;
- iounit = kmalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
+ iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
+ if (!iounit) {
+ prom_printf("SUN4D: Cannot alloc iounit, halting.\n");
+ prom_halt();
+ }
- memset(iounit, 0, sizeof(*iounit));
iounit->limit[0] = IOUNIT_BMAP1_START;
iounit->limit[1] = IOUNIT_BMAP2_START;
iounit->limit[2] = IOUNIT_BMAPM_START;
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index b627f8dbcaa..d41f66ac7ff 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -26,6 +26,14 @@ config MMU
bool
default y
+config STACKTRACE_SUPPORT
+ bool
+ default y
+
+config LOCKDEP_SUPPORT
+ bool
+ default y
+
config TIME_INTERPOLATION
bool
default y
@@ -34,6 +42,14 @@ config ARCH_MAY_HAVE_PC_FDC
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config AUDIT_ARCH
bool
default y
diff --git a/arch/sparc64/Kconfig.debug b/arch/sparc64/Kconfig.debug
index afe0a7720a2..1f130f3b6c2 100644
--- a/arch/sparc64/Kconfig.debug
+++ b/arch/sparc64/Kconfig.debug
@@ -1,5 +1,9 @@
menu "Kernel hacking"
+config TRACE_IRQFLAGS_SUPPORT
+ bool
+ default y
+
source "lib/Kconfig.debug"
config DEBUG_STACK_USAGE
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 2f4612fa81f..5a9e68b13e6 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,24 +1,29 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc2
-# Tue Oct 17 19:29:20 2006
+# Linux kernel version: 2.6.20-rc2
+# Thu Dec 28 15:09:49 2006
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
CONFIG_64BIT=y
CONFIG_MMU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
CONFIG_TIME_INTERPOLATION=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_AUDIT_ARCH=y
CONFIG_SPARC64_PAGE_SIZE_8KB=y
# CONFIG_SPARC64_PAGE_SIZE_64KB is not set
# CONFIG_SPARC64_PAGE_SIZE_512KB is not set
# CONFIG_SPARC64_PAGE_SIZE_4MB is not set
CONFIG_SECCOMP=y
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
+CONFIG_HZ=100
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -42,13 +47,14 @@ CONFIG_POSIX_MQUEUE=y
# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
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_SYSCALL is not set
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -203,6 +209,7 @@ CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
CONFIG_IPV6=m
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
@@ -219,7 +226,6 @@ 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
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -238,6 +244,8 @@ CONFIG_IP_DCCP_CCID2=m
# CONFIG_IP_DCCP_CCID2_DEBUG is not set
CONFIG_IP_DCCP_CCID3=m
CONFIG_IP_DCCP_TFRC_LIB=m
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_CCID3_RTO=100
#
# DCCP Kernel Hacking
@@ -326,7 +334,7 @@ CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_NBD=m
# CONFIG_BLK_DEV_SX8 is not set
-CONFIG_BLK_DEV_UB=m
+# CONFIG_BLK_DEV_UB is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CDROM_PKTCDVD=m
@@ -405,6 +413,7 @@ CONFIG_IDEDMA_AUTO=y
#
CONFIG_RAID_ATTRS=m
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
@@ -425,6 +434,7 @@ CONFIG_CHR_DEV_SG=m
CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
#
# SCSI Transports
@@ -468,6 +478,7 @@ CONFIG_ISCSI_TCP=m
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_SUNESP is not set
+# CONFIG_SCSI_SRP is not set
#
# Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -598,6 +609,7 @@ CONFIG_BNX2=m
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -724,10 +736,6 @@ CONFIG_RTC=y
# 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
@@ -832,6 +840,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
@@ -842,6 +851,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
@@ -954,7 +964,6 @@ CONFIG_SND_VERBOSE_PROCFS=y
#
CONFIG_SND_MPU401_UART=m
CONFIG_SND_AC97_CODEC=m
-CONFIG_SND_AC97_BUS=m
CONFIG_SND_DUMMY=m
CONFIG_SND_VIRMIDI=m
CONFIG_SND_MTPAV=m
@@ -1037,6 +1046,12 @@ CONFIG_SND_SUN_CS4231=m
# Open Sound System
#
# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+
+#
+# HID Devices
+#
+CONFIG_HID=y
#
# USB support
@@ -1053,6 +1068,7 @@ CONFIG_USB=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -1082,14 +1098,25 @@ CONFIG_USB_UHCI_HCD=m
#
# may also be needed; see USB_STORAGE Help for more information
#
-# CONFIG_USB_STORAGE is not set
+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_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
@@ -1119,6 +1146,7 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
# CONFIG_USB_MON is not set
@@ -1208,6 +1236,10 @@ CONFIG_USB_HIDDEV=y
#
#
+# Virtualization
+#
+
+#
# Misc Linux/SPARC drivers
#
CONFIG_SUN_OPENPROMIO=m
@@ -1364,6 +1396,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Instrumentation Support
#
CONFIG_PROFILING=y
@@ -1373,10 +1410,13 @@ CONFIG_KPROBES=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_PRINTK_TIME=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1387,17 +1427,16 @@ CONFIG_SCHEDSTATS=y
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
# 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_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
@@ -1420,8 +1459,9 @@ CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_MD5=y
@@ -1430,8 +1470,10 @@ CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_GF128MUL=m
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
@@ -1456,6 +1498,7 @@ CONFIG_CRYPTO_TEST=m
#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=m
CONFIG_CRC16=m
CONFIG_CRC32=y
@@ -1463,3 +1506,4 @@ CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index e1eabebaed3..eff0c01d357 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -14,6 +14,7 @@ obj-y := process.o setup.o cpu.o idprom.o \
power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
visemul.o prom.o of_device.o
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
pci_sun4v.o pci_sun4v_asm.o
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index d7caa60a007..f205fc7cbcd 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -209,7 +209,7 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
N_TRSIZE(ex) || N_DRSIZE(ex) ||
- bprm->file->f_dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+ bprm->file->f_path.dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
return -ENOEXEC;
}
@@ -349,7 +349,7 @@ static int load_aout32_library(struct file *file)
int retval;
struct exec ex;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
retval = -ENOEXEC;
error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c
index 259f37e516f..9699abeb990 100644
--- a/arch/sparc64/kernel/chmc.c
+++ b/arch/sparc64/kernel/chmc.c
@@ -341,7 +341,7 @@ static void fetch_decode_regs(struct mctrl_info *mp)
static int init_one_mctrl(struct device_node *dp)
{
- struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL);
+ struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
int portid = of_getintprop_default(dp, "portid", -1);
struct linux_prom64_registers *regs;
void *pval;
@@ -349,7 +349,6 @@ static int init_one_mctrl(struct device_node *dp)
if (!mp)
return -1;
- memset(mp, 0, sizeof(*mp));
if (portid == -1)
goto fail;
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 6f28bec0a9b..c15a3edcb82 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -597,7 +597,12 @@ __spitfire_cee_trap_continue:
1: ba,pt %xcc, etrap_irq
rd %pc, %g7
-2: mov %l4, %o1
+2:
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov %l4, %o1
mov %l5, %o2
call spitfire_access_error
add %sp, PTREGS_OFF, %o0
@@ -824,6 +829,10 @@ do_cheetah_plus_data_parity:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
mov 0x0, %o0
call cheetah_plus_parity_error
add %sp, PTREGS_OFF, %o1
@@ -855,6 +864,10 @@ do_cheetah_plus_insn_parity:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
mov 0x1, %o0
call cheetah_plus_parity_error
add %sp, PTREGS_OFF, %o1
@@ -1183,6 +1196,10 @@ c_fast_ecc:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
mov %l4, %o1
mov %l5, %o2
call cheetah_fecc_handler
@@ -1211,6 +1228,10 @@ c_cee:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
mov %l4, %o1
mov %l5, %o2
call cheetah_cee_handler
@@ -1239,6 +1260,10 @@ c_deferred:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
mov %l4, %o1
mov %l5, %o2
call cheetah_deferred_handler
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index c8e9dc9d68a..baea10a9819 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -78,11 +78,7 @@ sparc_ramdisk_image64:
/* PROM cif handler code address is in %o4. */
sparc64_boot:
-1: rd %pc, %g7
- set 1b, %g1
- cmp %g1, %g7
- be,pn %xcc, sparc64_boot_after_remap
- mov %o4, %l7
+ mov %o4, %l7
/* We need to remap the kernel. Use position independant
* code to remap us to KERNBASE.
@@ -295,7 +291,6 @@ is_sun4v:
add %sp, (192 + 128), %sp
-sparc64_boot_after_remap:
sethi %hi(prom_root_compatible), %g1
or %g1, %lo(prom_root_compatible), %g1
sethi %hi(prom_sun4v_name), %g7
@@ -489,6 +484,14 @@ tlb_fixup_done:
call __bzero
sub %o1, %o0, %o1
+#ifdef CONFIG_LOCKDEP
+ /* We have this call this super early, as even prom_init can grab
+ * spinlocks and thus call into the lockdep code.
+ */
+ call lockdep_init
+ nop
+#endif
+
mov %l6, %o1 ! OpenPROM stack
call prom_init
mov %l7, %o0 ! OpenPROM cif handler
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index d64b1ea848d..c3d068c7a41 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -372,14 +372,14 @@ static void run_pre_handler(unsigned int virt_irq)
}
}
-static struct hw_interrupt_type sun4u_irq = {
+static struct irq_chip sun4u_irq = {
.typename = "sun4u",
.enable = sun4u_irq_enable,
.disable = sun4u_irq_disable,
.end = sun4u_irq_end,
};
-static struct hw_interrupt_type sun4u_irq_ack = {
+static struct irq_chip sun4u_irq_ack = {
.typename = "sun4u+ack",
.enable = sun4u_irq_enable,
.disable = sun4u_irq_disable,
@@ -387,14 +387,14 @@ static struct hw_interrupt_type sun4u_irq_ack = {
.end = sun4u_irq_end,
};
-static struct hw_interrupt_type sun4v_irq = {
+static struct irq_chip sun4v_irq = {
.typename = "sun4v",
.enable = sun4v_irq_enable,
.disable = sun4v_irq_disable,
.end = sun4v_irq_end,
};
-static struct hw_interrupt_type sun4v_irq_ack = {
+static struct irq_chip sun4v_irq_ack = {
.typename = "sun4v+ack",
.enable = sun4v_irq_enable,
.disable = sun4v_irq_disable,
@@ -493,22 +493,6 @@ out:
return bucket->virt_irq;
}
-void hw_resend_irq(struct hw_interrupt_type *handler, unsigned int virt_irq)
-{
- struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned long pstate;
- unsigned int *ent;
-
- __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
- __asm__ __volatile__("wrpr %0, %1, %%pstate"
- : : "r" (pstate), "i" (PSTATE_IE));
- ent = irq_work(smp_processor_id());
- bucket->irq_chain = *ent;
- *ent = __irq(bucket);
- set_softint(1 << PIL_DEVICE_IRQ);
- __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
-}
-
void ack_bad_irq(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index f028e68b23f..98721a8f861 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -22,14 +22,15 @@ static void __init report_dev(struct sparc_isa_device *isa_dev, int child)
printk(" [%s", isa_dev->prom_node->name);
}
-static struct linux_prom_registers * __init
-isa_dev_get_resource(struct sparc_isa_device *isa_dev)
+static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev)
{
struct linux_prom_registers *pregs;
unsigned long base, len;
int prop_len;
pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len);
+ if (!pregs)
+ return;
/* Only the first one is interesting. */
len = pregs[0].reg_size;
@@ -44,12 +45,9 @@ isa_dev_get_resource(struct sparc_isa_device *isa_dev)
request_resource(&isa_dev->bus->parent->io_space,
&isa_dev->resource);
-
- return pregs;
}
-static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
- struct linux_prom_registers *pregs)
+static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev)
{
struct of_device *op = of_find_device_by_node(isa_dev->prom_node);
@@ -69,17 +67,14 @@ static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
printk(" ->");
while (dp) {
- struct linux_prom_registers *regs;
struct sparc_isa_device *isa_dev;
- isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
+ isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
fatal_err("cannot allocate child isa_dev");
prom_halt();
}
- memset(isa_dev, 0, sizeof(*isa_dev));
-
/* Link it in to parent. */
isa_dev->next = parent_isa_dev->child;
parent_isa_dev->child = isa_dev;
@@ -87,8 +82,8 @@ static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
isa_dev->bus = parent_isa_dev->bus;
isa_dev->prom_node = dp;
- regs = isa_dev_get_resource(isa_dev);
- isa_dev_get_irq(isa_dev, regs);
+ isa_dev_get_resource(isa_dev);
+ isa_dev_get_irq(isa_dev);
report_dev(isa_dev, 1);
@@ -101,17 +96,14 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
struct device_node *dp = isa_br->prom_node->child;
while (dp) {
- struct linux_prom_registers *regs;
struct sparc_isa_device *isa_dev;
- isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
+ isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
printk(KERN_DEBUG "ISA: cannot allocate isa_dev");
return;
}
- memset(isa_dev, 0, sizeof(*isa_dev));
-
isa_dev->ofdev.node = dp;
isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
isa_dev->ofdev.dev.bus = &isa_bus_type;
@@ -141,8 +133,8 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
isa_dev->bus = isa_br;
isa_dev->prom_node = dp;
- regs = isa_dev_get_resource(isa_dev);
- isa_dev_get_irq(isa_dev, regs);
+ isa_dev_get_resource(isa_dev);
+ isa_dev_get_irq(isa_dev);
report_dev(isa_dev, 0);
@@ -180,14 +172,12 @@ void __init isa_init(void)
pbm = pdev_cookie->pbm;
dp = pdev_cookie->prom_node;
- isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL);
+ isa_br = kzalloc(sizeof(*isa_br), GFP_KERNEL);
if (!isa_br) {
printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge");
return;
}
- memset(isa_br, 0, sizeof(*isa_br));
-
isa_br->ofdev.node = dp;
isa_br->ofdev.dev.parent = &pdev->dev;
isa_br->ofdev.dev.bus = &isa_bus_type;
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index 8e75ed762fd..ae221f0d4a6 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -45,7 +45,11 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
p->ainsn.insn[0] = *p->addr;
+ flushi(&p->ainsn.insn[0]);
+
p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
+ flushi(&p->ainsn.insn[1]);
+
p->opcode = *p->addr;
return 0;
}
@@ -185,16 +189,19 @@ no_kprobe:
/* If INSN is a relative control transfer instruction,
* return the corrected branch destination value.
*
- * The original INSN location was REAL_PC, it actually
- * executed at PC and produced destination address NPC.
+ * regs->tpc and regs->tnpc still hold the values of the
+ * program counters at the time of trap due to the execution
+ * of the BREAKPOINT_INSTRUCTION_2 at p->ainsn.insn[1]
+ *
*/
-static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc,
- unsigned long pc,
- unsigned long npc)
+static unsigned long __kprobes relbranch_fixup(u32 insn, struct kprobe *p,
+ struct pt_regs *regs)
{
+ unsigned long real_pc = (unsigned long) p->addr;
+
/* Branch not taken, no mods necessary. */
- if (npc == pc + 0x4UL)
- return real_pc + 0x4UL;
+ if (regs->tnpc == regs->tpc + 0x4UL)
+ return real_pc + 0x8UL;
/* The three cases are call, branch w/prediction,
* and traditional branch.
@@ -202,14 +209,21 @@ static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc,
if ((insn & 0xc0000000) == 0x40000000 ||
(insn & 0xc1c00000) == 0x00400000 ||
(insn & 0xc1c00000) == 0x00800000) {
+ unsigned long ainsn_addr;
+
+ ainsn_addr = (unsigned long) &p->ainsn.insn[0];
+
/* The instruction did all the work for us
* already, just apply the offset to the correct
* instruction location.
*/
- return (real_pc + (npc - pc));
+ return (real_pc + (regs->tnpc - ainsn_addr));
}
- return real_pc + 0x4UL;
+ /* It is jmpl or some other absolute PC modification instruction,
+ * leave NPC as-is.
+ */
+ return regs->tnpc;
}
/* If INSN is an instruction which writes it's PC location
@@ -220,12 +234,12 @@ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
{
unsigned long *slot = NULL;
- /* Simplest cast is call, which always uses %o7 */
+ /* Simplest case is 'call', which always uses %o7 */
if ((insn & 0xc0000000) == 0x40000000) {
slot = &regs->u_regs[UREG_I7];
}
- /* Jmpl encodes the register inside of the opcode */
+ /* 'jmpl' encodes the register inside of the opcode */
if ((insn & 0xc1f80000) == 0x81c00000) {
unsigned long rd = ((insn >> 25) & 0x1f);
@@ -247,11 +261,11 @@ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
/*
* Called after single-stepping. p->addr is the address of the
- * instruction whose first byte has been replaced by the breakpoint
+ * instruction which has been replaced by the breakpoint
* instruction. To avoid the SMP problems that can occur when we
* temporarily put back the original opcode to single-step, we
* single-stepped a copy of the instruction. The address of this
- * copy is p->ainsn.insn.
+ * copy is &p->ainsn.insn[0].
*
* This function prepares to return from the post-single-step
* breakpoint trap.
@@ -261,11 +275,11 @@ static void __kprobes resume_execution(struct kprobe *p,
{
u32 insn = p->ainsn.insn[0];
+ regs->tnpc = relbranch_fixup(insn, p, regs);
+
+ /* This assignment must occur after relbranch_fixup() */
regs->tpc = kcb->kprobe_orig_tnpc;
- regs->tnpc = relbranch_fixup(insn,
- (unsigned long) p->addr,
- (unsigned long) &p->ainsn.insn[0],
- regs->tnpc);
+
retpc_fixup(regs, insn, (unsigned long) p->addr);
regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
@@ -430,17 +444,8 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
struct jprobe *jp = container_of(p, struct jprobe, kp);
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
- kcb->jprobe_saved_regs_location = regs;
memcpy(&(kcb->jprobe_saved_regs), regs, sizeof(*regs));
- /* Save a whole stack frame, this gets arguments
- * pushed onto the stack after using up all the
- * arg registers.
- */
- memcpy(&(kcb->jprobe_saved_stack),
- (char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
- sizeof(kcb->jprobe_saved_stack));
-
regs->tpc = (unsigned long) jp->entry;
regs->tnpc = ((unsigned long) jp->entry) + 0x4UL;
regs->tstate |= TSTATE_PIL;
@@ -450,10 +455,19 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
void __kprobes jprobe_return(void)
{
- __asm__ __volatile__(
- ".globl jprobe_return_trap_instruction\n"
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+ register unsigned long orig_fp asm("g1");
+
+ orig_fp = kcb->jprobe_saved_regs.u_regs[UREG_FP];
+ __asm__ __volatile__("\n"
+"1: cmp %%sp, %0\n\t"
+ "blu,a,pt %%xcc, 1b\n\t"
+ " restore\n\t"
+ ".globl jprobe_return_trap_instruction\n"
"jprobe_return_trap_instruction:\n\t"
- "ta 0x70");
+ "ta 0x70"
+ : /* no outputs */
+ : "r" (orig_fp));
}
extern void jprobe_return_trap_instruction(void);
@@ -466,26 +480,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
if (addr == (u32 *) jprobe_return_trap_instruction) {
- if (kcb->jprobe_saved_regs_location != regs) {
- printk("JPROBE: Current regs (%p) does not match "
- "saved regs (%p).\n",
- regs, kcb->jprobe_saved_regs_location);
- printk("JPROBE: Saved registers\n");
- __show_regs(kcb->jprobe_saved_regs_location);
- printk("JPROBE: Current registers\n");
- __show_regs(regs);
- BUG();
- }
- /* Restore old register state. Do pt_regs
- * first so that UREG_FP is the original one for
- * the stack frame restore.
- */
memcpy(regs, &(kcb->jprobe_saved_regs), sizeof(*regs));
-
- memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
- &(kcb->jprobe_saved_stack),
- sizeof(kcb->jprobe_saved_stack));
-
preempt_enable_no_resched();
return 1;
}
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 8cc14fc6b6f..b0f3e0082a0 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -144,9 +144,12 @@ void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned lo
}
EXPORT_SYMBOL(of_ioremap);
-void of_iounmap(void __iomem *base, unsigned long size)
+void of_iounmap(struct resource *res, void __iomem *base, unsigned long size)
{
- release_region((unsigned long) base, size);
+ if (res->flags & IORESOURCE_MEM)
+ release_mem_region((unsigned long) base, size);
+ else
+ release_region((unsigned long) base, size);
}
EXPORT_SYMBOL(of_iounmap);
@@ -1007,10 +1010,9 @@ struct of_device* of_platform_device_create(struct device_node *np,
{
struct of_device *dev;
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
- memset(dev, 0, sizeof(*dev));
dev->dev.parent = parent;
dev->dev.bus = bus;
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 03ad4c06758..6b04794b7a9 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -798,7 +798,7 @@ static struct pci_ops pci_sun4v_ops = {
static void pbm_scan_bus(struct pci_controller_info *p,
struct pci_pbm_info *pbm)
{
- struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL);
+ struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
if (!cookie) {
prom_printf("%s: Critical allocation failure.\n", pbm->name);
@@ -806,7 +806,6 @@ static void pbm_scan_bus(struct pci_controller_info *p,
}
/* All we care about is the PBM. */
- memset(cookie, 0, sizeof(*cookie));
cookie->pbm = pbm;
pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm);
@@ -1048,12 +1047,11 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
/* Allocate and initialize the free area map. */
sz = num_tsb_entries / 8;
sz = (sz + 7UL) & ~7UL;
- iommu->arena.map = kmalloc(sz, GFP_KERNEL);
+ iommu->arena.map = kzalloc(sz, GFP_KERNEL);
if (!iommu->arena.map) {
prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
prom_halt();
}
- memset(iommu->arena.map, 0, sz);
iommu->arena.limit = num_tsb_entries;
sz = probe_existing_entries(pbm, iommu);
@@ -1164,24 +1162,20 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
per_cpu(pci_iommu_batch, i).pglist = (u64 *) page;
}
- p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
+ p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p)
goto fatal_memory_error;
- memset(p, 0, sizeof(*p));
-
- iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+ iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
if (!iommu)
goto fatal_memory_error;
- memset(iommu, 0, sizeof(*iommu));
p->pbm_A.iommu = iommu;
- iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+ iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
if (!iommu)
goto fatal_memory_error;
- memset(iommu, 0, sizeof(*iommu));
p->pbm_B.iommu = iommu;
p->next = pci_controller_root;
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index d31975e6d6f..81111a12f0a 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -202,7 +202,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
#endif
if (request == PTRACE_TRACEME) {
ret = ptrace_traceme();
- pt_succ_return(regs, 0);
+ if (ret < 0)
+ pt_error_return(regs, -ret);
+ else
+ pt_succ_return(regs, 0);
goto out;
}
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 3522cd66f3b..079d18a11d2 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -165,14 +165,26 @@ rtrap:
__handle_softirq_continue:
rtrap_xcall:
sethi %hi(0xf << 20), %l4
- andcc %l1, TSTATE_PRIV, %l3
and %l1, %l4, %l4
+ andn %l1, %l4, %l1
+ srl %l4, 20, %l4
+#ifdef CONFIG_TRACE_IRQFLAGS
+ brnz,pn %l4, rtrap_no_irq_enable
+ nop
+ call trace_hardirqs_on
+ nop
+ wrpr %l4, %pil
+rtrap_no_irq_enable:
+#endif
+ andcc %l1, TSTATE_PRIV, %l3
bne,pn %icc, to_kernel
- andn %l1, %l4, %l1
+ nop
/* We must hold IRQs off and atomically test schedule+signal
* state, then hold them off all the way back to userspace.
- * If we are returning to kernel, none of this matters.
+ * If we are returning to kernel, none of this matters. Note
+ * that we are disabling interrupts via PSTATE_IE, not using
+ * %pil.
*
* If we do not do this, there is a window where we would do
* the tests, later the signal/resched event arrives but we do
@@ -256,7 +268,6 @@ rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
ld [%sp + PTREGS_OFF + PT_V9_Y], %o3
wr %o3, %g0, %y
- srl %l4, 20, %l4
wrpr %l4, 0x0, %pil
wrpr %g0, 0x1, %tl
wrpr %l1, %g0, %tstate
@@ -374,8 +385,8 @@ to_kernel:
ldx [%g6 + TI_FLAGS], %l5
andcc %l5, _TIF_NEED_RESCHED, %g0
be,pt %xcc, kern_fpucheck
- srl %l4, 20, %l5
- cmp %l5, 0
+ nop
+ cmp %l4, 0
bne,pn %xcc, kern_fpucheck
sethi %hi(PREEMPT_ACTIVE), %l6
stw %l6, [%g6 + TI_PRE_COUNT]
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index cc09d826641..fc99f7b8012 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -1388,7 +1388,7 @@ void __devinit smp_prepare_boot_cpu(void)
{
}
-int __devinit __cpu_up(unsigned int cpu)
+int __cpuinit __cpu_up(unsigned int cpu)
{
int ret = smp_boot_one_cpu(cpu);
@@ -1447,11 +1447,8 @@ void __init setup_per_cpu_areas(void)
char *ptr;
/* Copy section for each CPU (we discard the original) */
- goal = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
-#ifdef CONFIG_MODULES
- if (goal < PERCPU_ENOUGH_ROOM)
- goal = PERCPU_ENOUGH_ROOM;
-#endif
+ goal = PERCPU_ENOUGH_ROOM;
+
__per_cpu_shift = 0;
for (size = 1UL; size < goal; size <<= 1UL)
__per_cpu_shift++;
diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c
new file mode 100644
index 00000000000..c4d15f2762b
--- /dev/null
+++ b/arch/sparc64/kernel/stacktrace.c
@@ -0,0 +1,41 @@
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/thread_info.h>
+#include <asm/ptrace.h>
+
+void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+{
+ unsigned long ksp, fp, thread_base;
+ struct thread_info *tp;
+
+ if (!task)
+ task = current;
+ tp = task_thread_info(task);
+ if (task == current) {
+ flushw_all();
+ __asm__ __volatile__(
+ "mov %%fp, %0"
+ : "=r" (ksp)
+ );
+ } else
+ ksp = tp->ksp;
+
+ fp = ksp + STACK_BIAS;
+ thread_base = (unsigned long) tp;
+ do {
+ struct reg_window *rw;
+
+ /* Bogus frame pointer? */
+ if (fp < (thread_base + sizeof(struct thread_info)) ||
+ fp >= (thread_base + THREAD_SIZE))
+ break;
+
+ rw = (struct reg_window *) fp;
+ if (trace->skip > 0)
+ trace->skip--;
+ else
+ trace->entries[trace->nr_entries++] = rw->ins[7];
+
+ fp = rw->ins[6] + STACK_BIAS;
+ } while (trace->nr_entries < trace->max_entries);
+}
diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S
index 49703c3c576..405855dd886 100644
--- a/arch/sparc64/kernel/sun4v_ivec.S
+++ b/arch/sparc64/kernel/sun4v_ivec.S
@@ -190,7 +190,10 @@ sun4v_res_mondo:
mov %g1, %g4
ba,pt %xcc, etrap_irq
rd %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
/* Log the event. */
add %sp, PTREGS_OFF, %o0
call sun4v_resum_error
@@ -216,7 +219,10 @@ sun4v_res_mondo_queue_full:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
call sun4v_resum_overflow
add %sp, PTREGS_OFF, %o0
@@ -295,7 +301,10 @@ sun4v_nonres_mondo:
mov %g1, %g4
ba,pt %xcc, etrap_irq
rd %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
/* Log the event. */
add %sp, PTREGS_OFF, %o0
call sun4v_nonresum_error
@@ -321,7 +330,10 @@ sun4v_nonres_mondo_queue_full:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
call sun4v_nonresum_overflow
add %sp, PTREGS_OFF, %o0
diff --git a/arch/sparc64/kernel/sun4v_tlb_miss.S b/arch/sparc64/kernel/sun4v_tlb_miss.S
index b731881224e..9871dbb1ab4 100644
--- a/arch/sparc64/kernel/sun4v_tlb_miss.S
+++ b/arch/sparc64/kernel/sun4v_tlb_miss.S
@@ -142,9 +142,9 @@ sun4v_dtlb_prot:
rdpr %tl, %g1
cmp %g1, 1
bgu,pn %xcc, winfix_trampoline
- nop
- ba,pt %xcc, sparc64_realfault_common
mov FAULT_CODE_DTLB | FAULT_CODE_WRITE, %g4
+ ba,pt %xcc, sparc64_realfault_common
+ nop
/* Called from trap table:
* %g4: vaddr
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index 7da72d3b322..2ebc2c05138 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -83,7 +83,7 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
file = fget(fd);
if (!file)
goto out;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (imajor(inode) == MEM_MAJOR && iminor(inode) == 5) {
flags |= MAP_ANONYMOUS;
fput(file);
@@ -615,7 +615,7 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
if (!file)
return 0;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
socket = SOCKET_I(inode);
local.sin_family = AF_INET;
@@ -1055,7 +1055,7 @@ asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
break;
case 2:
rval = -EFAULT;
- kmbuf = (struct msgbuf *)kmalloc(sizeof(struct msgbuf) + arg3,
+ kmbuf = kmalloc(sizeof(struct msgbuf) + arg3,
GFP_KERNEL);
if (!kmbuf)
break;
@@ -1078,7 +1078,7 @@ asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
break;
case 3:
rval = -EFAULT;
- kmbuf = (struct msgbuf *)kmalloc(sizeof(struct msgbuf) + arg3,
+ kmbuf = kmalloc(sizeof(struct msgbuf) + arg3,
GFP_KERNEL);
if (!kmbuf || sunos_msgbuf_get((struct msgbuf32 __user *)(unsigned long)arg2,
kmbuf, arg3))
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index fe1796c939c..ad67784292d 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -10,7 +10,7 @@
*/
#include <linux/module.h>
-#include <linux/sched.h> /* for jiffies */
+#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/kallsyms.h>
#include <linux/signal.h>
@@ -1873,6 +1873,16 @@ void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
put_cpu();
+ if (ent->err_type == SUN4V_ERR_TYPE_WARNING_RES) {
+ /* If err_type is 0x4, it's a powerdown request. Do
+ * not do the usual resumable error log because that
+ * makes it look like some abnormal error.
+ */
+ printk(KERN_INFO "Power down request...\n");
+ kill_cad_pid(SIGINT, 1);
+ return;
+ }
+
sun4v_log_error(regs, &local_copy, cpu,
KERN_ERR "RESUMABLE ERROR",
&sun4v_resum_oflow_cnt);
@@ -2261,8 +2271,12 @@ void die_if_kernel(char *str, struct pt_regs *regs)
do_exit(SIGSEGV);
}
+#define VIS_OPCODE_MASK ((0x3 << 30) | (0x3f << 19))
+#define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19))
+
extern int handle_popc(u32 insn, struct pt_regs *regs);
extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);
+extern int vis_emul(struct pt_regs *, unsigned int);
void do_illegal_instruction(struct pt_regs *regs)
{
@@ -2287,10 +2301,18 @@ void do_illegal_instruction(struct pt_regs *regs)
if (handle_ldf_stq(insn, regs))
return;
} else if (tlb_type == hypervisor) {
- extern int vis_emul(struct pt_regs *, unsigned int);
+ if ((insn & VIS_OPCODE_MASK) == VIS_OPCODE_VAL) {
+ if (!vis_emul(regs, insn))
+ return;
+ } else {
+ struct fpustate *f = FPUSTATE;
- if (!vis_emul(regs, insn))
- return;
+ /* XXX maybe verify XFSR bits like
+ * XXX do_fpother() does?
+ */
+ if (do_mathemu(regs, f))
+ return;
+ }
}
}
info.si_signo = SIGILL;
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index a9b765271b8..bc18d480dd1 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -243,7 +243,7 @@ static inline int ok_for_kernel(unsigned int insn)
return !floating_point_load_or_store_p(insn);
}
-static void kernel_mna_trap_fault(void)
+static void kernel_mna_trap_fault(int fixup_tstate_asi)
{
struct pt_regs *regs = current_thread_info()->kern_una_regs;
unsigned int insn = current_thread_info()->kern_una_insn;
@@ -274,18 +274,15 @@ static void kernel_mna_trap_fault(void)
regs->tpc = entry->fixup;
regs->tnpc = regs->tpc + 4;
- regs->tstate &= ~TSTATE_ASI;
- regs->tstate |= (ASI_AIUS << 24UL);
+ if (fixup_tstate_asi) {
+ regs->tstate &= ~TSTATE_ASI;
+ regs->tstate |= (ASI_AIUS << 24UL);
+ }
}
-asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
+static void log_unaligned(struct pt_regs *regs)
{
static unsigned long count, last_time;
- enum direction dir = decode_direction(insn);
- int size = decode_access_size(insn);
-
- current_thread_info()->kern_una_regs = regs;
- current_thread_info()->kern_una_insn = insn;
if (jiffies - last_time > 5 * HZ)
count = 0;
@@ -295,6 +292,28 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
printk("Kernel unaligned access at TPC[%lx] ", regs->tpc);
print_symbol("%s\n", regs->tpc);
}
+}
+
+asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
+{
+ enum direction dir = decode_direction(insn);
+ int size = decode_access_size(insn);
+ int orig_asi, asi;
+
+ current_thread_info()->kern_una_regs = regs;
+ current_thread_info()->kern_una_insn = insn;
+
+ orig_asi = asi = decode_asi(insn, regs);
+
+ /* If this is a {get,put}_user() on an unaligned userspace pointer,
+ * just signal a fault and do not log the event.
+ */
+ if (asi == ASI_AIUS) {
+ kernel_mna_trap_fault(0);
+ return;
+ }
+
+ log_unaligned(regs);
if (!ok_for_kernel(insn) || dir == both) {
printk("Unsupported unaligned load/store trap for kernel "
@@ -302,10 +321,10 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
unaligned_panic("Kernel does fpu/atomic "
"unaligned load/store.", regs);
- kernel_mna_trap_fault();
+ kernel_mna_trap_fault(0);
} else {
unsigned long addr, *reg_addr;
- int orig_asi, asi, err;
+ int err;
addr = compute_effective_address(regs, insn,
((insn >> 25) & 0x1f));
@@ -315,7 +334,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
regs->tpc, dirstrings[dir], addr, size,
regs->u_regs[UREG_RETPC]);
#endif
- orig_asi = asi = decode_asi(insn, regs);
switch (asi) {
case ASI_NL:
case ASI_AIUPL:
@@ -365,7 +383,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
/* Not reached... */
}
if (unlikely(err))
- kernel_mna_trap_fault();
+ kernel_mna_trap_fault(1);
else
advance(regs);
}
diff --git a/arch/sparc64/kernel/visemul.c b/arch/sparc64/kernel/visemul.c
index 84fedaa38aa..c3fd64706b5 100644
--- a/arch/sparc64/kernel/visemul.c
+++ b/arch/sparc64/kernel/visemul.c
@@ -128,9 +128,6 @@
/* 001001100 - Permute bytes as specified by GSR.MASK */
#define BSHUFFLE_OPF 0x04c
-#define VIS_OPCODE_MASK ((0x3 << 30) | (0x3f << 19))
-#define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19))
-
#define VIS_OPF_SHIFT 5
#define VIS_OPF_MASK (0x1ff << VIS_OPF_SHIFT)
@@ -810,9 +807,6 @@ int vis_emul(struct pt_regs *regs, unsigned int insn)
if (get_user(insn, (u32 __user *) pc))
return -EFAULT;
- if ((insn & VIS_OPCODE_MASK) != VIS_OPCODE_VAL)
- return -EINVAL;
-
opf = (insn & VIS_OPF_MASK) >> VIS_OPF_SHIFT;
switch (opf) {
default:
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index a8e8802eed4..054822a3e05 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -872,6 +872,115 @@ static unsigned long __init choose_bootmap_pfn(unsigned long start_pfn,
prom_halt();
}
+static void __init trim_pavail(unsigned long *cur_size_p,
+ unsigned long *end_of_phys_p)
+{
+ unsigned long to_trim = *cur_size_p - cmdline_memory_size;
+ unsigned long avoid_start, avoid_end;
+ int i;
+
+ to_trim = PAGE_ALIGN(to_trim);
+
+ avoid_start = avoid_end = 0;
+#ifdef CONFIG_BLK_DEV_INITRD
+ avoid_start = initrd_start;
+ avoid_end = PAGE_ALIGN(initrd_end);
+#endif
+
+ /* Trim some pavail[] entries in order to satisfy the
+ * requested "mem=xxx" kernel command line specification.
+ *
+ * We must not trim off the kernel image area nor the
+ * initial ramdisk range (if any). Also, we must not trim
+ * any pavail[] entry down to zero in order to preserve
+ * the invariant that all pavail[] entries have a non-zero
+ * size which is assumed by all of the code in here.
+ */
+ for (i = 0; i < pavail_ents; i++) {
+ unsigned long start, end, kern_end;
+ unsigned long trim_low, trim_high, n;
+
+ kern_end = PAGE_ALIGN(kern_base + kern_size);
+
+ trim_low = start = pavail[i].phys_addr;
+ trim_high = end = start + pavail[i].reg_size;
+
+ if (kern_base >= start &&
+ kern_base < end) {
+ trim_low = kern_base;
+ if (kern_end >= end)
+ continue;
+ }
+ if (kern_end >= start &&
+ kern_end < end) {
+ trim_high = kern_end;
+ }
+ if (avoid_start &&
+ avoid_start >= start &&
+ avoid_start < end) {
+ if (trim_low > avoid_start)
+ trim_low = avoid_start;
+ if (avoid_end >= end)
+ continue;
+ }
+ if (avoid_end &&
+ avoid_end >= start &&
+ avoid_end < end) {
+ if (trim_high < avoid_end)
+ trim_high = avoid_end;
+ }
+
+ if (trim_high <= trim_low)
+ continue;
+
+ if (trim_low == start && trim_high == end) {
+ /* Whole chunk is available for trimming.
+ * Trim all except one page, in order to keep
+ * entry non-empty.
+ */
+ n = (end - start) - PAGE_SIZE;
+ if (n > to_trim)
+ n = to_trim;
+
+ if (n) {
+ pavail[i].phys_addr += n;
+ pavail[i].reg_size -= n;
+ to_trim -= n;
+ }
+ } else {
+ n = (trim_low - start);
+ if (n > to_trim)
+ n = to_trim;
+
+ if (n) {
+ pavail[i].phys_addr += n;
+ pavail[i].reg_size -= n;
+ to_trim -= n;
+ }
+ if (to_trim) {
+ n = end - trim_high;
+ if (n > to_trim)
+ n = to_trim;
+ if (n) {
+ pavail[i].reg_size -= n;
+ to_trim -= n;
+ }
+ }
+ }
+
+ if (!to_trim)
+ break;
+ }
+
+ /* Recalculate. */
+ *cur_size_p = 0UL;
+ for (i = 0; i < pavail_ents; i++) {
+ *end_of_phys_p = pavail[i].phys_addr +
+ pavail[i].reg_size;
+ *cur_size_p += pavail[i].reg_size;
+ }
+}
+
static unsigned long __init bootmem_init(unsigned long *pages_avail,
unsigned long phys_base)
{
@@ -889,31 +998,13 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
end_of_phys_memory = pavail[i].phys_addr +
pavail[i].reg_size;
bytes_avail += pavail[i].reg_size;
- if (cmdline_memory_size) {
- if (bytes_avail > cmdline_memory_size) {
- unsigned long slack = bytes_avail - cmdline_memory_size;
-
- bytes_avail -= slack;
- end_of_phys_memory -= slack;
-
- pavail[i].reg_size -= slack;
- if ((long)pavail[i].reg_size <= 0L) {
- pavail[i].phys_addr = 0xdeadbeefUL;
- pavail[i].reg_size = 0UL;
- pavail_ents = i;
- } else {
- pavail[i+1].reg_size = 0Ul;
- pavail[i+1].phys_addr = 0xdeadbeefUL;
- pavail_ents = i + 1;
- }
- break;
- }
- }
}
- *pages_avail = bytes_avail >> PAGE_SHIFT;
-
- end_pfn = end_of_phys_memory >> PAGE_SHIFT;
+ /* Determine the location of the initial ramdisk before trying
+ * to honor the "mem=xxx" command line argument. We must know
+ * where the kernel image and the ramdisk image are so that we
+ * do not trim those two areas from the physical memory map.
+ */
#ifdef CONFIG_BLK_DEV_INITRD
/* Now have to check initial ramdisk, so that bootmap does not overwrite it */
@@ -932,6 +1023,16 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
}
}
#endif
+
+ if (cmdline_memory_size &&
+ bytes_avail > cmdline_memory_size)
+ trim_pavail(&bytes_avail,
+ &end_of_phys_memory);
+
+ *pages_avail = bytes_avail >> PAGE_SHIFT;
+
+ end_pfn = end_of_phys_memory >> PAGE_SHIFT;
+
/* Initialize the boot-time allocator. */
max_pfn = max_low_pfn = end_pfn;
min_low_pfn = (phys_base >> PAGE_SHIFT);
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index d70b60a3bbc..737c26923c0 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -477,6 +477,10 @@ xcall_sync_tick:
sethi %hi(109f), %g7
b,pt %xcc, etrap_irq
109: or %g7, %lo(109b), %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
call smp_synchronize_tick_client
nop
clr %l6
@@ -508,6 +512,10 @@ xcall_report_regs:
sethi %hi(109f), %g7
b,pt %xcc, etrap_irq
109: or %g7, %lo(109b), %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
call __show_regs
add %sp, PTREGS_OFF, %o0
clr %l6
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index 12a940cc791..61be597bf43 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -449,7 +449,7 @@ asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf)
error = -EBADF;
file = fget(fd);
if (file) {
- error = report_statvfs(file->f_vfsmnt, file->f_dentry->d_inode, buf);
+ error = report_statvfs(file->f_path.mnt, file->f_path.dentry->d_inode, buf);
fput(file);
}
@@ -481,7 +481,7 @@ asmlinkage int solaris_fstatvfs64(unsigned int fd, u32 buf)
file = fget(fd);
if (file) {
lock_kernel();
- error = report_statvfs64(file->f_vfsmnt, file->f_dentry->d_inode, buf);
+ error = report_statvfs64(file->f_path.mnt, file->f_path.dentry->d_inode, buf);
unlock_kernel();
fput(file);
}
diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c
index be0a054e3ed..330743c5b3d 100644
--- a/arch/sparc64/solaris/ioctl.c
+++ b/arch/sparc64/solaris/ioctl.c
@@ -299,8 +299,8 @@ static inline int solaris_sockmod(unsigned int fd, unsigned int cmd, u32 arg)
rcu_read_lock();
fdt = files_fdtable(current->files);
if (! fdt->fd[fd] ||
- ! fdt->fd[fd]->f_dentry ||
- ! (ino = fdt->fd[fd]->f_dentry->d_inode) ||
+ ! fdt->fd[fd]->f_path.dentry ||
+ ! (ino = fdt->fd[fd]->f_path.dentry->d_inode) ||
! S_ISSOCK(ino->i_mode)) {
rcu_read_unlock();
return TBADF;
@@ -480,7 +480,7 @@ static inline int solaris_S(struct file *filp, unsigned int fd, unsigned int cmd
struct sol_socket_struct *sock;
struct module_info *mi;
- ino = filp->f_dentry->d_inode;
+ ino = filp->f_path.dentry->d_inode;
if (!S_ISSOCK(ino->i_mode))
return -EBADF;
sock = filp->private_data;
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index 9ed997982f8..bca16e8c95c 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -77,7 +77,7 @@ static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 o
if (!file)
goto out;
else {
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
if(imajor(inode) == MEM_MAJOR &&
iminor(inode) == 5) {
flags |= MAP_ANONYMOUS;
@@ -423,9 +423,7 @@ 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);
+ proc_clear_tty(current);
return process_group(current);
}
case 2: /* getsid */
diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
index 7c90e41fd3b..89a4757f192 100644
--- a/arch/sparc64/solaris/socksys.c
+++ b/arch/sparc64/solaris/socksys.c
@@ -96,13 +96,13 @@ static int socksys_open(struct inode * inode, struct file * filp)
* No shit. WTF is it supposed to do, anyway?
*
* Try instead:
- * d_delete(filp->f_dentry), then d_instantiate with sock inode
+ * d_delete(filp->f_path.dentry), then d_instantiate with sock inode
*/
- dentry = filp->f_dentry;
- filp->f_dentry = dget(fcheck(fd)->f_dentry);
- filp->f_dentry->d_inode->i_rdev = inode->i_rdev;
- filp->f_dentry->d_inode->i_flock = inode->i_flock;
- SOCKET_I(filp->f_dentry->d_inode)->file = filp;
+ dentry = filp->f_path.dentry;
+ filp->f_path.dentry = dget(fcheck(fd)->f_path.dentry);
+ filp->f_path.dentry->d_inode->i_rdev = inode->i_rdev;
+ filp->f_path.dentry->d_inode->i_flock = inode->i_flock;
+ SOCKET_I(filp->f_path.dentry->d_inode)->file = filp;
filp->f_op = &socksys_file_ops;
sock = (struct sol_socket_struct*)
mykmalloc(sizeof(struct sol_socket_struct), GFP_KERNEL);
@@ -148,7 +148,7 @@ static unsigned int socksys_poll(struct file * filp, poll_table * wait)
struct inode *ino;
unsigned int mask = 0;
- ino=filp->f_dentry->d_inode;
+ ino=filp->f_path.dentry->d_inode;
if (ino && S_ISSOCK(ino->i_mode)) {
struct sol_socket_struct *sock;
sock = (struct sol_socket_struct*)filp->private_data;
diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
index b84e5456b02..a9d32ceabf2 100644
--- a/arch/sparc64/solaris/timod.c
+++ b/arch/sparc64/solaris/timod.c
@@ -147,7 +147,7 @@ static void timod_wake_socket(unsigned int fd)
SOLD("wakeing socket");
fdt = files_fdtable(current->files);
- sock = SOCKET_I(fdt->fd[fd]->f_dentry->d_inode);
+ sock = SOCKET_I(fdt->fd[fd]->f_path.dentry->d_inode);
wake_up_interruptible(&sock->wait);
read_lock(&sock->sk->sk_callback_lock);
if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
@@ -361,7 +361,7 @@ int timod_putmsg(unsigned int fd, char __user *ctl_buf, int ctl_len,
fdt = files_fdtable(current->files);
filp = fdt->fd[fd];
- ino = filp->f_dentry->d_inode;
+ ino = filp->f_path.dentry->d_inode;
sock = (struct sol_socket_struct *)filp->private_data;
SOLD("entry");
if (get_user(ret, (int __user *)A(ctl_buf)))
@@ -644,7 +644,7 @@ int timod_getmsg(unsigned int fd, char __user *ctl_buf, int ctl_maxlen, s32 __us
SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p));
fdt = files_fdtable(current->files);
filp = fdt->fd[fd];
- ino = filp->f_dentry->d_inode;
+ ino = filp->f_path.dentry->d_inode;
sock = (struct sol_socket_struct *)filp->private_data;
SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
if ( ctl_maxlen > 0 && !sock->pfirst && SOCKET_I(ino)->type == SOCK_STREAM
@@ -865,7 +865,7 @@ asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
filp = fdt->fd[fd];
if(!filp) goto out;
- ino = filp->f_dentry->d_inode;
+ ino = filp->f_path.dentry->d_inode;
if (!ino || !S_ISSOCK(ino->i_mode))
goto out;
@@ -933,7 +933,7 @@ asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
filp = fdt->fd[fd];
if(!filp) goto out;
- ino = filp->f_dentry->d_inode;
+ ino = filp->f_path.dentry->d_inode;
if (!ino) goto out;
if (!S_ISSOCK(ino->i_mode) &&
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 5ac1f2963ae..d32a80e6668 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -47,6 +47,11 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
+config GENERIC_BUG
+ bool
+ default y
+ depends on BUG
+
# Used in kernel/irq/manage.c and include/linux/irq.h
config IRQ_RELEASE_METHOD
bool
diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386
index f191a550a07..d6cffb27fff 100644
--- a/arch/um/Kconfig.i386
+++ b/arch/um/Kconfig.i386
@@ -19,31 +19,31 @@ config SEMAPHORE_SLEEPERS
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"
+ 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
@@ -67,13 +67,13 @@ config 3_LEVEL_PGTABLES
config STUB_CODE
hex
- default 0xbfffe000 if !HOST_2G_2G
- default 0x7fffe000 if HOST_2G_2G
+ default 0xbfffe000 if !HOST_VMSPLIT_2G
+ default 0x7fffe000 if HOST_VMSPLIT_2G
config STUB_DATA
hex
- default 0xbffff000 if !HOST_2G_2G
- default 0x7ffff000 if HOST_2G_2G
+ default 0xbffff000 if !HOST_VMSPLIT_2G
+ default 0x7ffff000 if HOST_VMSPLIT_2G
config STUB_START
hex
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index aa3090d05a8..83301e1ef67 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -246,7 +246,7 @@ out_up:
return ret;
}
-void line_set_termios(struct tty_struct *tty, struct termios * old)
+void line_set_termios(struct tty_struct *tty, struct ktermios * old)
{
/* nothing */
}
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 286bc0b3207..afe3d427ddf 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -72,9 +72,11 @@ static int uml_net_rx(struct net_device *dev)
return pkt_len;
}
-static void uml_dev_close(void* dev)
+static void uml_dev_close(struct work_struct *work)
{
- dev_close( (struct net_device *) dev);
+ struct uml_net_private *lp =
+ container_of(work, struct uml_net_private, work);
+ dev_close(lp->dev);
}
irqreturn_t uml_net_interrupt(int irq, void *dev_id)
@@ -89,7 +91,6 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id)
spin_lock(&lp->lock);
while((err = uml_net_rx(dev)) > 0) ;
if(err < 0) {
- DECLARE_WORK(close_work, uml_dev_close, dev);
printk(KERN_ERR
"Device '%s' read returned %d, shutting it down\n",
dev->name, err);
@@ -97,9 +98,10 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id)
* again lp->lock.
* And dev_close() can be safely called multiple times on the
* same device, since it tests for (dev->flags & IFF_UP). So
- * there's no harm in delaying the device shutdown. */
- schedule_work(&close_work);
-#error this is not permitted - close_work will go out of scope
+ * there's no harm in delaying the device shutdown.
+ * Furthermore, the workqueue will not re-enqueue an already
+ * enqueued work item. */
+ schedule_work(&lp->work);
goto out;
}
reactivate_fd(lp->fd, UM_ETH_IRQ);
@@ -334,13 +336,12 @@ static int eth_configure(int n, void *init, char *mac,
size = transport->private_size + sizeof(struct uml_net_private) +
sizeof(((struct uml_net_private *) 0)->user);
- device = kmalloc(sizeof(*device), GFP_KERNEL);
+ device = kzalloc(sizeof(*device), GFP_KERNEL);
if (device == NULL) {
printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
return(1);
}
- memset(device, 0, sizeof(*device));
INIT_LIST_HEAD(&device->list);
device->index = n;
@@ -366,6 +367,7 @@ static int eth_configure(int n, void *init, char *mac,
/* This points to the transport private data. It's still clear, but we
* must memset it to 0 *now*. Let's help the drivers. */
memset(lp, 0, size);
+ INIT_WORK(&lp->work, uml_dev_close);
/* sysfs register */
if (!driver_registered) {
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
index 214ee76c40d..5f232ae89fb 100644
--- a/arch/um/include/line.h
+++ b/arch/um/include/line.h
@@ -76,7 +76,7 @@ extern int line_setup(struct line *lines, unsigned int sizeof_lines,
extern int line_write(struct tty_struct *tty, const unsigned char *buf,
int len);
extern void line_put_char(struct tty_struct *tty, unsigned char ch);
-extern void line_set_termios(struct tty_struct *tty, struct termios * old);
+extern void line_set_termios(struct tty_struct *tty, struct ktermios * old);
extern int line_chars_in_buffer(struct tty_struct *tty);
extern void line_flush_buffer(struct tty_struct *tty);
extern void line_flush_chars(struct tty_struct *tty);
diff --git a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h
index 280459fb0b2..218f8b47fdc 100644
--- a/arch/um/include/net_kern.h
+++ b/arch/um/include/net_kern.h
@@ -11,6 +11,7 @@
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/list.h>
+#include <linux/workqueue.h>
struct uml_net {
struct list_head list;
@@ -26,6 +27,7 @@ struct uml_net_private {
struct net_device *dev;
struct timer_list tl;
struct net_device_stats stats;
+ struct work_struct work;
int fd;
unsigned char mac[ETH_ALEN];
unsigned short (*protocol)(struct sk_buff *);
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
index 0561c43b468..8d56ec6cca7 100644
--- a/arch/um/kernel/exec.c
+++ b/arch/um/kernel/exec.c
@@ -39,12 +39,13 @@ static long execve1(char *file, char __user * __user *argv,
char __user *__user *env)
{
long error;
+ struct tty_struct *tty;
#ifdef CONFIG_TTY_LOG
mutex_lock(&tty_mutex);
- task_lock(current); /* FIXME: is this needed ? */
- log_exec(argv, current->signal->tty);
- task_unlock(current);
+ tty = get_current_tty();
+ if (tty)
+ log_exec(argv, tty);
mutex_unlock(&tty_mutex);
#endif
error = do_execve(file, argv, env, &current->thread.regs);
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 0e32adf03be..098720be019 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,4 +1,4 @@
-obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
+obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
ptrace_user.o setjmp.o signal.o sigcontext.o syscalls.o sysrq.o \
sys_call_table.o tls.o
diff --git a/arch/um/sys-i386/bug.c b/arch/um/sys-i386/bug.c
new file mode 100644
index 00000000000..200c8ba2879
--- /dev/null
+++ b/arch/um/sys-i386/bug.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL V2
+ */
+
+#include <linux/uaccess.h>
+
+/* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
+ * that's not relevent in skas mode.
+ */
+
+int is_valid_bugaddr(unsigned long eip)
+{
+ unsigned short ud2;
+
+ if (probe_kernel_address((unsigned short __user *)eip, ud2))
+ return 0;
+
+ return ud2 == 0x0b0f;
+}
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
index 49057d8bc66..5db7737df0f 100644
--- a/arch/um/sys-i386/ldt.c
+++ b/arch/um/sys-i386/ldt.c
@@ -166,7 +166,7 @@ static long read_ldt_from_host(void __user * ptr, unsigned long bytecount)
struct ptrace_ldt ptrace_ldt = (struct ptrace_ldt) {
.func = 0,
.bytecount = bytecount,
- .ptr = (void *)kmalloc(bytecount, GFP_KERNEL)};
+ .ptr = kmalloc(bytecount, GFP_KERNEL)};
u32 cpu;
if(ptrace_ldt.ptr == NULL)
@@ -426,7 +426,7 @@ void ldt_get_host_info(void)
host_ldt_entries = dummy_list;
else {
size = (size + 1) * sizeof(dummy_list[0]);
- host_ldt_entries = (short *)kmalloc(size, GFP_KERNEL);
+ host_ldt_entries = kmalloc(size, GFP_KERNEL);
if(host_ldt_entries == NULL) {
printk("ldt_get_host_info: couldn't allocate host ldt list\n");
goto out_free;
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 0709fc6670c..3f6acd66771 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -219,7 +219,8 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
unsigned long save_sp = PT_REGS_SP(regs);
int err = 0;
- stack_top &= -8UL;
+ /* This is the same calculation as i386 - ((sp + 4) & 15) == 0 */
+ stack_top = ((stack_top + 4) & -16UL) - 4;
frame = (struct sigframe __user *) stack_top - 1;
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return 1;
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index f41768b8e25..4d9e5efa6fb 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -4,7 +4,7 @@
# Licensed under the GPL
#
-obj-y = bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
+obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
setjmp.o sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o \
ksyms.o tls.o
diff --git a/arch/um/sys-x86_64/bug.c b/arch/um/sys-x86_64/bug.c
new file mode 100644
index 00000000000..200c8ba2879
--- /dev/null
+++ b/arch/um/sys-x86_64/bug.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL V2
+ */
+
+#include <linux/uaccess.h>
+
+/* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
+ * that's not relevent in skas mode.
+ */
+
+int is_valid_bugaddr(unsigned long eip)
+{
+ unsigned short ud2;
+
+ if (probe_kernel_address((unsigned short __user *)eip, ud2))
+ return 0;
+
+ return ud2 == 0x0b0f;
+}
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index 9edf114faf7..af2f017617b 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -191,8 +191,9 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
struct task_struct *me = current;
frame = (struct rt_sigframe __user *)
- round_down(stack_top - sizeof(struct rt_sigframe), 16) - 8;
- frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128);
+ round_down(stack_top - sizeof(struct rt_sigframe), 16);
+ /* Subtract 128 for a red zone and 8 for proper alignment */
+ frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8);
if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
goto out;
diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig
index 37ec644603a..f0d4d72e560 100644
--- a/arch/v850/Kconfig
+++ b/arch/v850/Kconfig
@@ -38,6 +38,14 @@ config TIME_LOW_RES
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
# Turn off some random 386 crap that can affect device config
config ISA
bool
@@ -97,17 +105,17 @@ menu "Processor type and features"
# currently support
config V850E_MA1
bool
- depends RTE_CB_MA1
+ depends on RTE_CB_MA1
default y
# Similarly for the RTE-V850E/NB85E-CB - V850E/TEG
config V850E_TEG
bool
- depends RTE_CB_NB85E
+ depends on RTE_CB_NB85E
default y
# ... and the RTE-V850E/ME2-CB - V850E/ME2
config V850E_ME2
bool
- depends RTE_CB_ME2
+ depends on RTE_CB_ME2
default y
@@ -115,7 +123,7 @@ menu "Processor type and features"
config V850E2_SIM85E2
bool
- depends V850E2_SIM85E2C || V850E2_SIM85E2S
+ depends on V850E2_SIM85E2C || V850E2_SIM85E2S
default y
@@ -124,7 +132,7 @@ menu "Processor type and features"
# V850E2 processors
config V850E2
bool
- depends V850E2_SIM85E2 || V850E2_FPGA85E2C || V850E2_ANNA
+ depends on V850E2_SIM85E2 || V850E2_FPGA85E2C || V850E2_ANNA
default y
@@ -133,7 +141,7 @@ menu "Processor type and features"
# Boards in the RTE-x-CB series
config RTE_CB
bool
- depends RTE_CB_MA1 || RTE_CB_NB85E || RTE_CB_ME2
+ depends on RTE_CB_MA1 || RTE_CB_NB85E || RTE_CB_ME2
default y
config RTE_CB_MULTI
@@ -141,28 +149,28 @@ menu "Processor type and features"
# RTE_CB_NB85E can either have multi ROM support or not, but
# other platforms (currently only RTE_CB_MA1) require it.
prompt "Multi monitor ROM support" if RTE_CB_NB85E
- depends RTE_CB_MA1 || RTE_CB_NB85E
+ depends on RTE_CB_MA1 || RTE_CB_NB85E
default y
config RTE_CB_MULTI_DBTRAP
bool "Pass illegal insn trap / dbtrap to kernel"
- depends RTE_CB_MULTI
+ depends on RTE_CB_MULTI
default n
config RTE_CB_MA1_KSRAM
bool "Kernel in SRAM (limits size of kernel)"
- depends RTE_CB_MA1 && RTE_CB_MULTI
+ depends on RTE_CB_MA1 && RTE_CB_MULTI
default n
config RTE_MB_A_PCI
bool "Mother-A PCI support"
- depends RTE_CB
+ depends on RTE_CB
default y
# The GBUS is used to talk to the RTE-MOTHER-A board
config RTE_GBUS_INT
bool
- depends RTE_MB_A_PCI
+ depends on RTE_MB_A_PCI
default y
# The only PCI bus we support is on the RTE-MOTHER-A board
@@ -201,7 +209,7 @@ menu "Processor type and features"
config ROM_KERNEL
bool "Kernel in ROM"
- depends V850E2_ANNA || V850E_AS85EP1 || RTE_CB_ME2
+ depends on V850E2_ANNA || V850E_AS85EP1 || RTE_CB_ME2
# Some platforms pre-zero memory, in which case the kernel doesn't need to
config ZERO_BSS
@@ -217,10 +225,10 @@ menu "Processor type and features"
config V850E_HIGHRES_TIMER
bool "High resolution timer support"
- depends V850E_TIMER_D
+ depends on V850E_TIMER_D
config TIME_BOOTUP
bool "Time bootup"
- depends V850E_HIGHRES_TIMER
+ depends on V850E_HIGHRES_TIMER
config RESET_GUARD
bool "Reset Guard"
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index bfbb9bcae12..d4275537b25 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -96,6 +96,19 @@ config AUDIT_ARCH
bool
default y
+config GENERIC_BUG
+ bool
+ default y
+ depends on BUG
+
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
source "init/Kconfig"
@@ -571,7 +584,7 @@ config SECCOMP
If unsure, say Y. Only embedded should say N here.
config CC_STACKPROTECTOR
- bool "Enable -fstack-protector buffer overflow detection (EXPRIMENTAL)"
+ bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
depends on EXPERIMENTAL
help
This option turns on the -fstack-protector GCC feature. This
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index b471b8550d0..2941a915d4e 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -45,9 +45,7 @@ cflags-kernel-$(CONFIG_REORDER) += -ffunction-sections
# actually it makes the kernel smaller too.
cflags-y += -fno-reorder-blocks
cflags-y += -Wno-sign-compare
-ifneq ($(CONFIG_UNWIND_INFO),y)
cflags-y += -fno-asynchronous-unwind-tables
-endif
ifneq ($(CONFIG_DEBUG_INFO),y)
# -fweb shrinks the kernel a bit, but the difference is very small
# it also messes up debugging, so don't use it for now.
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index 96f226cfb33..69584c29530 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-git7
-# Wed Dec 6 23:50:47 2006
+# Linux kernel version: 2.6.20-rc3
+# Fri Jan 5 11:54:41 2007
#
CONFIG_X86_64=y
CONFIG_64BIT=y
@@ -22,6 +22,9 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_DMI=y
CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -170,6 +173,7 @@ CONFIG_SECCOMP=y
# CONFIG_CC_STACKPROTECTOR is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
# CONFIG_REORDER is not set
@@ -514,6 +518,7 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
# CONFIG_SCSI_PROC_FS is not set
@@ -534,6 +539,7 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
#
# SCSI Transports
@@ -587,6 +593,7 @@ CONFIG_MEGARAID_SAS=y
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
#
# Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -1049,6 +1056,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
@@ -1059,6 +1067,7 @@ CONFIG_SENSORS_SMSC47B397=m
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
@@ -1106,10 +1115,7 @@ CONFIG_SOUND=y
# Open Sound System
#
CONFIG_SOUND_PRIME=y
-CONFIG_OSS_OBSOLETE_DRIVER=y
# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_EMU10K1 is not set
-# CONFIG_SOUND_FUSION is not set
# CONFIG_SOUND_ES1371 is not set
CONFIG_SOUND_ICH=y
# CONFIG_SOUND_TRIDENT is not set
@@ -1119,6 +1125,11 @@ CONFIG_SOUND_ICH=y
# CONFIG_SOUND_OSS is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1182,7 +1193,6 @@ CONFIG_USB_STORAGE=y
# 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 is not set
@@ -1303,6 +1313,11 @@ CONFIG_USB_MON=y
#
#
+# Virtualization
+#
+# CONFIG_KVM is not set
+
+#
# Firmware Drivers
#
# CONFIG_EDD is not set
@@ -1475,6 +1490,11 @@ CONFIG_NLS_ISO8859_15=y
CONFIG_NLS_UTF8=y
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Instrumentation Support
#
CONFIG_PROFILING=y
@@ -1489,6 +1509,8 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1504,15 +1526,12 @@ 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_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 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
@@ -1534,9 +1553,11 @@ CONFIG_DEBUG_STACKOVERFLOW=y
#
# Library routines
#
+CONFIG_BITREVERSE=y
# 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
+CONFIG_IOMAP_COPY=y
diff --git a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c
index 396d3c10001..fe83edb93c1 100644
--- a/arch/x86_64/ia32/ia32_aout.c
+++ b/arch/x86_64/ia32/ia32_aout.c
@@ -241,7 +241,7 @@ static u32 __user *create_aout_tables(char __user *p, struct linux_binprm *bprm)
get_user(c,p++);
} while (c);
}
- put_user(NULL,argv);
+ put_user(0, argv);
current->mm->arg_end = current->mm->env_start = (unsigned long) p;
while (envc-->0) {
char c;
@@ -250,7 +250,7 @@ static u32 __user *create_aout_tables(char __user *p, struct linux_binprm *bprm)
get_user(c,p++);
} while (c);
}
- put_user(NULL,envp);
+ put_user(0, envp);
current->mm->env_end = (unsigned long) p;
return sp;
}
@@ -272,7 +272,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
N_TRSIZE(ex) || N_DRSIZE(ex) ||
- i_size_read(bprm->file->f_dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+ i_size_read(bprm->file->f_path.dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
return -ENOEXEC;
}
@@ -357,7 +357,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
printk(KERN_WARNING
"fd_offset is not page aligned. Please convert program: %s\n",
- bprm->file->f_dentry->d_name.name);
+ bprm->file->f_path.dentry->d_name.name);
error_time = jiffies;
}
#endif
@@ -440,7 +440,7 @@ static int load_aout_library(struct file *file)
int retval;
struct exec ex;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
retval = -ENOEXEC;
error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
@@ -471,7 +471,7 @@ static int load_aout_library(struct file *file)
{
printk(KERN_WARNING
"N_TXTOFF is not page aligned. Please convert library: %s\n",
- file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.name);
error_time = jiffies;
}
#endif
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index 543ef4f405e..5ce0bd486bb 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -64,55 +64,6 @@ typedef unsigned int elf_greg_t;
#define ELF_NGREG (sizeof (struct user_regs_struct32) / sizeof(elf_greg_t))
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-/*
- * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
- * extra segments containing the vsyscall DSO contents. Dumping its
- * contents makes post-mortem fully interpretable later without matching up
- * the same kernel and hardware config to see what PC values meant.
- * Dumping its extra ELF program headers includes all the other information
- * a debugger needs to easily find how the vsyscall DSO was being used.
- */
-#define ELF_CORE_EXTRA_PHDRS (find_vma(current->mm, VSYSCALL32_BASE) ? \
- (VSYSCALL32_EHDR->e_phnum) : 0)
-#define ELF_CORE_WRITE_EXTRA_PHDRS \
-do { \
- if (find_vma(current->mm, VSYSCALL32_BASE)) { \
- const struct elf32_phdr *const vsyscall_phdrs = \
- (const struct elf32_phdr *) (VSYSCALL32_BASE \
- + VSYSCALL32_EHDR->e_phoff);\
- int i; \
- Elf32_Off ofs = 0; \
- for (i = 0; i < VSYSCALL32_EHDR->e_phnum; ++i) { \
- struct elf32_phdr phdr = vsyscall_phdrs[i]; \
- if (phdr.p_type == PT_LOAD) { \
- BUG_ON(ofs != 0); \
- ofs = phdr.p_offset = offset; \
- phdr.p_memsz = PAGE_ALIGN(phdr.p_memsz); \
- phdr.p_filesz = phdr.p_memsz; \
- offset += phdr.p_filesz; \
- } \
- else \
- phdr.p_offset += ofs; \
- phdr.p_paddr = 0; /* match other core phdrs */ \
- DUMP_WRITE(&phdr, sizeof(phdr)); \
- } \
- } \
-} while (0)
-#define ELF_CORE_WRITE_EXTRA_DATA \
-do { \
- if (find_vma(current->mm, VSYSCALL32_BASE)) { \
- const struct elf32_phdr *const vsyscall_phdrs = \
- (const struct elf32_phdr *) (VSYSCALL32_BASE \
- + VSYSCALL32_EHDR->e_phoff); \
- int i; \
- for (i = 0; i < VSYSCALL32_EHDR->e_phnum; ++i) { \
- if (vsyscall_phdrs[i].p_type == PT_LOAD) \
- DUMP_WRITE((void *) (u64) vsyscall_phdrs[i].p_vaddr,\
- PAGE_ALIGN(vsyscall_phdrs[i].p_memsz)); \
- } \
- } \
-} while (0)
-
struct elf_siginfo
{
int si_signo; /* signal number */
diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c
index 3e5ed20cba4..568ff0df89e 100644
--- a/arch/x86_64/ia32/syscall32.c
+++ b/arch/x86_64/ia32/syscall32.c
@@ -18,68 +18,50 @@ extern unsigned char syscall32_syscall[], syscall32_syscall_end[];
extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[];
extern int sysctl_vsyscall32;
-char *syscall32_page;
+static struct page *syscall32_pages[1];
static int use_sysenter = -1;
-static struct page *
-syscall32_nopage(struct vm_area_struct *vma, unsigned long adr, int *type)
-{
- struct page *p = virt_to_page(adr - vma->vm_start + syscall32_page);
- get_page(p);
- return p;
-}
-
-/* Prevent VMA merging */
-static void syscall32_vma_close(struct vm_area_struct *vma)
-{
-}
-
-static struct vm_operations_struct syscall32_vm_ops = {
- .close = syscall32_vma_close,
- .nopage = syscall32_nopage,
-};
-
struct linux_binprm;
/* Setup a VMA at program startup for the vsyscall page */
int syscall32_setup_pages(struct linux_binprm *bprm, int exstack)
{
- int npages = (VSYSCALL32_END - VSYSCALL32_BASE) >> PAGE_SHIFT;
- struct vm_area_struct *vma;
struct mm_struct *mm = current->mm;
int ret;
- vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
- if (!vma)
- return -ENOMEM;
-
- memset(vma, 0, sizeof(struct vm_area_struct));
- /* Could randomize here */
- vma->vm_start = VSYSCALL32_BASE;
- vma->vm_end = VSYSCALL32_END;
- /* 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 = &syscall32_vm_ops;
- vma->vm_mm = mm;
-
down_write(&mm->mmap_sem);
- if ((ret = insert_vm_struct(mm, vma))) {
- up_write(&mm->mmap_sem);
- kmem_cache_free(vm_area_cachep, vma);
- return ret;
- }
- mm->total_vm += npages;
+ /*
+ * MAYWRITE to allow gdb to COW and set breakpoints
+ *
+ * Make sure the vDSO gets into every core dump.
+ * Dumping its contents makes post-mortem fully interpretable later
+ * without matching up the same kernel and hardware config to see
+ * what PC values meant.
+ */
+ /* Could randomize here */
+ ret = install_special_mapping(mm, VSYSCALL32_BASE, PAGE_SIZE,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+ VM_ALWAYSDUMP,
+ syscall32_pages);
up_write(&mm->mmap_sem);
- return 0;
+ return ret;
+}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+ if (vma->vm_start == VSYSCALL32_BASE &&
+ vma->vm_mm && vma->vm_mm->task_size == IA32_PAGE_OFFSET)
+ return "[vdso]";
+ return NULL;
}
static int __init init_syscall32(void)
{
- syscall32_page = (void *)get_zeroed_page(GFP_KERNEL);
+ char *syscall32_page = (void *)get_zeroed_page(GFP_KERNEL);
if (!syscall32_page)
panic("Cannot allocate syscall32 page");
+ syscall32_pages[0] = virt_to_page(syscall32_page);
if (use_sysenter > 0) {
memcpy(syscall32_page, syscall32_sysenter,
syscall32_sysenter_end - syscall32_sysenter);
diff --git a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig
index 81f1562e539..45a6a1fd14a 100644
--- a/arch/x86_64/kernel/cpufreq/Kconfig
+++ b/arch/x86_64/kernel/cpufreq/Kconfig
@@ -27,10 +27,13 @@ config X86_POWERNOW_K8_ACPI
default y
config X86_SPEEDSTEP_CENTRINO
- tristate "Intel Enhanced SpeedStep"
+ tristate "Intel Enhanced SpeedStep (deprecated)"
select CPU_FREQ_TABLE
depends on ACPI_PROCESSOR
help
+ This is deprecated and this functionality is now merged into
+ acpi_cpufreq (X86_ACPI_CPUFREQ). Use that driver instead of
+ speedstep_centrino.
This adds the CPUFreq driver for Enhanced SpeedStep enabled
mobile CPUs. This means Intel Pentium M (Centrino) CPUs
or 64bit enabled Intel Xeons.
@@ -46,10 +49,12 @@ config X86_SPEEDSTEP_CENTRINO_ACPI
config X86_ACPI_CPUFREQ
tristate "ACPI Processor P-States driver"
+ select CPU_FREQ_TABLE
depends on ACPI_PROCESSOR
help
This driver adds a CPUFreq driver which utilizes the ACPI
Processor Performance States.
+ This driver also supports Intel Enhanced Speedstep.
For details, take a look at <file:Documentation/cpu-freq/>.
diff --git a/arch/x86_64/kernel/cpufreq/Makefile b/arch/x86_64/kernel/cpufreq/Makefile
index d8b59387922..753ce1dd418 100644
--- a/arch/x86_64/kernel/cpufreq/Makefile
+++ b/arch/x86_64/kernel/cpufreq/Makefile
@@ -5,8 +5,8 @@
SRCDIR := ../../../i386/kernel/cpu/cpufreq
obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
-obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o
+obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o
diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c
index 829698f6d04..bd30d138113 100644
--- a/arch/x86_64/kernel/early-quirks.c
+++ b/arch/x86_64/kernel/early-quirks.c
@@ -32,7 +32,7 @@ static void via_bugs(void)
static int nvidia_hpet_detected __initdata;
-static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
+static int __init nvidia_hpet_check(struct acpi_table_header *header)
{
nvidia_hpet_detected = 1;
return 0;
@@ -53,7 +53,7 @@ static void nvidia_bugs(void)
return;
nvidia_hpet_detected = 0;
- acpi_table_parse(ACPI_HPET, nvidia_hpet_check);
+ acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check);
if (nvidia_hpet_detected == 0) {
acpi_skip_timer_override = 1;
printk(KERN_INFO "Nvidia board "
@@ -69,6 +69,11 @@ static void nvidia_bugs(void)
static void ati_bugs(void)
{
+ if (timer_over_8254 == 1) {
+ timer_over_8254 = 0;
+ printk(KERN_INFO
+ "ATI board detected. Disabling timer routing over 8254.\n");
+ }
}
static void intel_bugs(void)
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index 601d332c4b7..9f5dac64aa8 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -1155,36 +1155,3 @@ ENTRY(call_softirq)
ret
CFI_ENDPROC
ENDPROC(call_softirq)
-
-#ifdef CONFIG_STACK_UNWIND
-ENTRY(arch_unwind_init_running)
- CFI_STARTPROC
- movq %r15, R15(%rdi)
- movq %r14, R14(%rdi)
- xchgq %rsi, %rdx
- movq %r13, R13(%rdi)
- movq %r12, R12(%rdi)
- xorl %eax, %eax
- movq %rbp, RBP(%rdi)
- movq %rbx, RBX(%rdi)
- movq (%rsp), %rcx
- movq %rax, R11(%rdi)
- movq %rax, R10(%rdi)
- movq %rax, R9(%rdi)
- movq %rax, R8(%rdi)
- movq %rax, RAX(%rdi)
- movq %rax, RCX(%rdi)
- movq %rax, RDX(%rdi)
- movq %rax, RSI(%rdi)
- movq %rax, RDI(%rdi)
- movq %rax, ORIG_RAX(%rdi)
- movq %rcx, RIP(%rdi)
- leaq 8(%rsp), %rcx
- movq $__KERNEL_CS, CS(%rdi)
- movq %rax, EFLAGS(%rdi)
- movq %rcx, RSP(%rdi)
- movq $__KERNEL_DS, SS(%rdi)
- jmpq *%rdx
- CFI_ENDPROC
-ENDPROC(arch_unwind_init_running)
-#endif
diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c
index b007433f96b..0b3603adf56 100644
--- a/arch/x86_64/kernel/genapic.c
+++ b/arch/x86_64/kernel/genapic.c
@@ -58,8 +58,8 @@ void __init clustered_apic_check(void)
* Some x86_64 machines use physical APIC mode regardless of how many
* procs/clusters are present (x86_64 ES7000 is an example).
*/
- if (acpi_fadt.revision > FADT2_REVISION_ID)
- if (acpi_fadt.force_apic_physical_destination_mode) {
+ if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID)
+ if (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) {
genapic = &apic_cluster;
goto print;
}
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 2a1dcd5f69c..6be6730acb5 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -55,6 +55,10 @@ int sis_apic_bug; /* not actually supported, dummy for compile */
static int no_timer_check;
+static int disable_timer_pin_1 __initdata;
+
+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 };
@@ -350,6 +354,29 @@ static int __init disable_ioapic_setup(char *str)
}
early_param("noapic", disable_ioapic_setup);
+/* Actually the next is obsolete, but keep it for paranoid reasons -AK */
+static int __init disable_timer_pin_setup(char *arg)
+{
+ disable_timer_pin_1 = 1;
+ return 1;
+}
+__setup("disable_timer_pin_1", disable_timer_pin_setup);
+
+static int __init setup_disable_8254_timer(char *s)
+{
+ timer_over_8254 = -1;
+ return 1;
+}
+static int __init setup_enable_8254_timer(char *s)
+{
+ timer_over_8254 = 2;
+ return 1;
+}
+
+__setup("disable_8254_timer", setup_disable_8254_timer);
+__setup("enable_8254_timer", setup_enable_8254_timer);
+
+
/*
* Find the IRQ entry number of a certain pin.
*/
@@ -1568,33 +1595,10 @@ static inline void unlock_ExtINT_logic(void)
* a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
* is so screwy. Thanks to Brian Perkins for testing/hacking this beast
* fanatically on his truly buggy board.
+ *
+ * FIXME: really need to revamp this for modern platforms only.
*/
-
-static int try_apic_pin(int apic, int pin, char *msg)
-{
- apic_printk(APIC_VERBOSE, KERN_INFO
- "..TIMER: trying IO-APIC=%d PIN=%d %s",
- apic, pin, msg);
-
- /*
- * Ok, does IRQ0 through the IOAPIC work?
- */
- if (!no_timer_check && timer_irq_works()) {
- nmi_watchdog_default();
- if (nmi_watchdog == NMI_IO_APIC) {
- disable_8259A_irq(0);
- setup_nmi();
- enable_8259A_irq(0);
- }
- return 1;
- }
- clear_IO_APIC_pin(apic, pin);
- apic_printk(APIC_QUIET, KERN_ERR " .. failed\n");
- return 0;
-}
-
-/* The function from hell */
-static void check_timer(void)
+static inline void check_timer(void)
{
int apic1, pin1, apic2, pin2;
int vector;
@@ -1615,43 +1619,61 @@ static void check_timer(void)
*/
apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
init_8259A(1);
+ if (timer_over_8254 > 0)
+ enable_8259A_irq(0);
pin1 = find_isa_irq_pin(0, mp_INT);
apic1 = find_isa_irq_apic(0, mp_INT);
pin2 = ioapic_i8259.pin;
apic2 = ioapic_i8259.apic;
- /* Do this first, otherwise we get double interrupts on ATI boards */
- if ((pin1 != -1) && try_apic_pin(apic1, pin1,"with 8259 IRQ0 disabled"))
- return;
+ apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
+ vector, apic1, pin1, apic2, pin2);
- /* Now try again with IRQ0 8259A enabled.
- Assumes timer is on IO-APIC 0 ?!? */
- enable_8259A_irq(0);
- unmask_IO_APIC_irq(0);
- if (try_apic_pin(apic1, pin1, "with 8259 IRQ0 enabled"))
- return;
- disable_8259A_irq(0);
-
- /* Always try pin0 and pin2 on APIC 0 to handle buggy timer overrides
- on Nvidia boards */
- if (!(apic1 == 0 && pin1 == 0) &&
- try_apic_pin(0, 0, "fallback with 8259 IRQ0 disabled"))
- return;
- if (!(apic1 == 0 && pin1 == 2) &&
- try_apic_pin(0, 2, "fallback with 8259 IRQ0 disabled"))
- return;
+ if (pin1 != -1) {
+ /*
+ * Ok, does IRQ0 through the IOAPIC work?
+ */
+ unmask_IO_APIC_irq(0);
+ if (!no_timer_check && timer_irq_works()) {
+ nmi_watchdog_default();
+ if (nmi_watchdog == NMI_IO_APIC) {
+ disable_8259A_irq(0);
+ setup_nmi();
+ enable_8259A_irq(0);
+ }
+ if (disable_timer_pin_1 > 0)
+ clear_IO_APIC_pin(0, pin1);
+ return;
+ }
+ clear_IO_APIC_pin(apic1, pin1);
+ apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not "
+ "connected to IO-APIC\n");
+ }
- /* Then try pure 8259A routing on the 8259 as reported by BIOS*/
- enable_8259A_irq(0);
+ apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) "
+ "through the 8259A ... ");
if (pin2 != -1) {
+ apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...",
+ apic2, pin2);
+ /*
+ * legacy devices should be connected to IO APIC #0
+ */
setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
- if (try_apic_pin(apic2,pin2,"8259A broadcast ExtINT from BIOS"))
+ if (timer_irq_works()) {
+ apic_printk(APIC_VERBOSE," works.\n");
+ nmi_watchdog_default();
+ if (nmi_watchdog == NMI_IO_APIC) {
+ setup_nmi();
+ }
return;
+ }
+ /*
+ * Cleanup, just in case ...
+ */
+ clear_IO_APIC_pin(apic2, pin2);
}
-
- /* Tried all possibilities to go through the IO-APIC. Now come the
- really cheesy fallbacks. */
+ apic_printk(APIC_VERBOSE," failed.\n");
if (nmi_watchdog == NMI_IO_APIC) {
printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
@@ -1934,24 +1956,31 @@ static struct irq_chip msi_chip = {
.retrigger = ioapic_retrigger_irq,
};
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
{
struct msi_msg msg;
- int ret;
+ int irq, ret;
+ irq = create_irq();
+ if (irq < 0)
+ return irq;
+
+ set_irq_msi(irq, desc);
ret = msi_compose_msg(dev, irq, &msg);
- if (ret < 0)
+ if (ret < 0) {
+ destroy_irq(irq);
return ret;
+ }
write_msi_msg(irq, &msg);
set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
- return 0;
+ return irq;
}
void arch_teardown_msi_irq(unsigned int irq)
{
- return;
+ destroy_irq(irq);
}
#endif /* CONFIG_PCI_MSI */
diff --git a/arch/x86_64/kernel/module.c b/arch/x86_64/kernel/module.c
index 9d0958ff547..a888e67f587 100644
--- a/arch/x86_64/kernel/module.c
+++ b/arch/x86_64/kernel/module.c
@@ -23,6 +23,7 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/slab.h>
+#include <linux/bug.h>
#include <asm/system.h>
#include <asm/page.h>
@@ -173,10 +174,12 @@ int module_finalize(const Elf_Ehdr *hdr,
lseg, lseg + locks->sh_size,
tseg, tseg + text->sh_size);
}
- return 0;
+
+ return module_bug_finalize(hdr, sechdrs, me);
}
void module_arch_cleanup(struct module *mod)
{
alternatives_smp_module_del(mod);
+ module_bug_cleanup(mod);
}
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index 08072568847..50dd8bef850 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -798,7 +798,7 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
return gsi;
/* Don't set up the ACPI SCI because it's already set up */
- if (acpi_fadt.sci_int == gsi)
+ if (acpi_gbl_FADT.sci_interrupt == gsi)
return gsi;
ioapic = mp_find_ioapic(gsi);
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index 27e95e7922c..9cb42ecb7f8 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -193,6 +193,8 @@ void nmi_watchdog_default(void)
nmi_watchdog = NMI_IO_APIC;
}
+static int endflag __initdata = 0;
+
#ifdef CONFIG_SMP
/* The performance counters used by NMI_LOCAL_APIC don't trigger when
* the CPU is idle. To make sure the NMI watchdog really ticks on all
@@ -200,7 +202,6 @@ void nmi_watchdog_default(void)
*/
static __init void nmi_cpu_busy(void *data)
{
- volatile int *endflag = data;
local_irq_enable_in_hardirq();
/* Intentionally don't use cpu_relax here. This is
to make sure that the performance counter really ticks,
@@ -208,14 +209,13 @@ static __init void nmi_cpu_busy(void *data)
pause instruction. On a real HT machine this is fine because
all other CPUs are busy with "useless" delay loops and don't
care if they get somewhat less cycles. */
- while (*endflag == 0)
- barrier();
+ while (endflag == 0)
+ mb();
}
#endif
int __init check_nmi_watchdog (void)
{
- volatile int endflag = 0;
int *counts;
int cpu;
@@ -256,6 +256,7 @@ int __init check_nmi_watchdog (void)
if (!atomic_read(&nmi_active)) {
kfree(counts);
atomic_set(&nmi_active, -1);
+ endflag = 1;
return -1;
}
endflag = 1;
@@ -301,8 +302,6 @@ int __init setup_nmi_watchdog(char *str)
if ((nmi >= NMI_INVALID) || (nmi < NMI_NONE))
return 0;
- if ((nmi == NMI_LOCAL_APIC) && (nmi_known_cpu() == 0))
- return 0; /* no lapic support */
nmi_watchdog = nmi;
return 1;
}
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 3215675ab12..3d65b1d4c2b 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -1052,7 +1052,7 @@ void __init detect_calgary(void)
void *tbl;
int calgary_found = 0;
unsigned long ptr;
- int offset;
+ unsigned int offset, prev_offset;
int ret;
/*
@@ -1068,29 +1068,36 @@ void __init detect_calgary(void)
if (!early_pci_allowed())
return;
+ printk(KERN_DEBUG "Calgary: detecting Calgary via BIOS EBDA area\n");
+
ptr = (unsigned long)phys_to_virt(get_bios_ebda());
rio_table_hdr = NULL;
+ prev_offset = 0;
offset = 0x180;
- while (offset) {
+ /*
+ * The next offset is stored in the 1st word.
+ * Only parse up until the offset increases:
+ */
+ while (offset > prev_offset) {
/* The block id is stored in the 2nd word */
if (*((unsigned short *)(ptr + offset + 2)) == 0x4752){
/* set the pointer past the offset & block id */
rio_table_hdr = (struct rio_table_hdr *)(ptr + offset + 4);
break;
}
- /* The next offset is stored in the 1st word. 0 means no more */
+ prev_offset = offset;
offset = *((unsigned short *)(ptr + offset));
}
if (!rio_table_hdr) {
- printk(KERN_ERR "Calgary: Unable to locate "
- "Rio Grande Table in EBDA - bailing!\n");
+ printk(KERN_DEBUG "Calgary: Unable to locate Rio Grande table "
+ "in EBDA - bailing!\n");
return;
}
ret = build_detail_arrays();
if (ret) {
- printk(KERN_ERR "Calgary: build_detail_arrays ret %d\n", ret);
+ printk(KERN_DEBUG "Calgary: build_detail_arrays ret %d\n", ret);
return;
}
@@ -1123,6 +1130,9 @@ void __init detect_calgary(void)
}
}
+ printk(KERN_DEBUG "Calgary: finished detection, Calgary %s\n",
+ calgary_found ? "found" : "not found");
+
if (calgary_found) {
iommu_detected = 1;
calgary_detected = 1;
diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c
index 697f0aa794b..eb18be5a656 100644
--- a/arch/x86_64/kernel/pci-swiotlb.c
+++ b/arch/x86_64/kernel/pci-swiotlb.c
@@ -29,7 +29,7 @@ struct dma_mapping_ops swiotlb_dma_ops = {
.dma_supported = NULL,
};
-void pci_swiotlb_init(void)
+void __init pci_swiotlb_init(void)
{
/* don't initialize swiotlb if iommu=off (no_iommu=1) */
if (!iommu_detected && !no_iommu && end_pfn > MAX_DMA32_PFN)
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index a418ee4c8c6..cbbc6adc1a9 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -109,7 +109,11 @@ void exit_idle(void)
static void default_idle(void)
{
current_thread_info()->status &= ~TS_POLLING;
- smp_mb__after_clear_bit();
+ /*
+ * TS_POLLING-cleared state must be visible before we
+ * test NEED_RESCHED:
+ */
+ smp_mb();
local_irq_disable();
if (!need_resched()) {
/* Enables interrupts one instruction before HLT.
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 9f05bc9b2da..335cc91c49b 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -498,7 +498,7 @@ static unsigned long get_cmos_time(void)
{
unsigned int year, mon, day, hour, min, sec;
unsigned long flags;
- unsigned extyear = 0;
+ unsigned century = 0;
spin_lock_irqsave(&rtc_lock, flags);
@@ -510,9 +510,9 @@ static unsigned long get_cmos_time(void)
mon = CMOS_READ(RTC_MONTH);
year = CMOS_READ(RTC_YEAR);
#ifdef CONFIG_ACPI
- if (acpi_fadt.revision >= FADT2_REVISION_ID &&
- acpi_fadt.century)
- extyear = CMOS_READ(acpi_fadt.century);
+ if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
+ acpi_gbl_FADT.century)
+ century = CMOS_READ(acpi_gbl_FADT.century);
#endif
} while (sec != CMOS_READ(RTC_SECONDS));
@@ -530,10 +530,10 @@ static unsigned long get_cmos_time(void)
BCD_TO_BIN(mon);
BCD_TO_BIN(year);
- if (extyear) {
- BCD_TO_BIN(extyear);
- year += extyear;
- printk(KERN_INFO "Extended CMOS year: %d\n", extyear);
+ if (century) {
+ BCD_TO_BIN(century);
+ year += century * 100;
+ printk(KERN_INFO "Extended CMOS year: %d\n", century * 100);
} else {
/*
* x86-64 systems only exists since 2002.
@@ -656,6 +656,25 @@ core_initcall(cpufreq_tsc);
*/
#define TICK_COUNT 100000000
+#define TICK_MIN 5000
+
+/*
+ * Some platforms take periodic SMI interrupts with 5ms duration. Make sure none
+ * occurs between the reads of the hpet & TSC.
+ */
+static void __init read_hpet_tsc(int *hpet, int *tsc)
+{
+ int tsc1, tsc2, hpet1;
+
+ do {
+ tsc1 = get_cycles_sync();
+ hpet1 = hpet_readl(HPET_COUNTER);
+ tsc2 = get_cycles_sync();
+ } while (tsc2 - tsc1 > TICK_MIN);
+ *hpet = hpet1;
+ *tsc = tsc2;
+}
+
static unsigned int __init hpet_calibrate_tsc(void)
{
@@ -666,13 +685,11 @@ static unsigned int __init hpet_calibrate_tsc(void)
local_irq_save(flags);
local_irq_disable();
- hpet_start = hpet_readl(HPET_COUNTER);
- rdtscl(tsc_start);
+ read_hpet_tsc(&hpet_start, &tsc_start);
do {
local_irq_disable();
- hpet_now = hpet_readl(HPET_COUNTER);
- tsc_now = get_cycles_sync();
+ read_hpet_tsc(&hpet_now, &tsc_now);
local_irq_restore(flags);
} while ((tsc_now - tsc_start) < TICK_COUNT &&
(hpet_now - hpet_start) < TICK_COUNT);
@@ -937,7 +954,7 @@ __cpuinit int unsynchronized_tsc(void)
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
#ifdef CONFIG_ACPI
/* But TSC doesn't tick in C3 so don't use it there */
- if (acpi_fadt.length > 0 && acpi_fadt.plvl3_lat < 1000)
+ if (acpi_gbl_FADT.header.length > 0 && acpi_gbl_FADT.C3latency < 1000)
return 1;
#endif
return 0;
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index a1641ffdffc..09d2e8a10a4 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -31,6 +31,7 @@
#include <linux/kexec.h>
#include <linux/unwind.h>
#include <linux/uaccess.h>
+#include <linux/bug.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -109,11 +110,6 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
}
int kstack_depth_to_print = 12;
-#ifdef CONFIG_STACK_UNWIND
-static int call_trace = 1;
-#else
-#define call_trace (-1)
-#endif
#ifdef CONFIG_KALLSYMS
void printk_address(unsigned long address)
@@ -216,32 +212,6 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
return NULL;
}
-struct ops_and_data {
- struct stacktrace_ops *ops;
- void *data;
-};
-
-static int dump_trace_unwind(struct unwind_frame_info *info, void *context)
-{
- struct ops_and_data *oad = (struct ops_and_data *)context;
- int n = 0;
- unsigned long sp = UNW_SP(info);
-
- if (arch_unw_user_mode(info))
- return -1;
- while (unwind(info) == 0 && UNW_PC(info)) {
- n++;
- oad->ops->address(oad->data, UNW_PC(info));
- if (arch_unw_user_mode(info))
- break;
- if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1))
- && sp > UNW_SP(info))
- break;
- sp = UNW_SP(info);
- }
- return n;
-}
-
#define MSG(txt) ops->warning(data, txt)
/*
@@ -269,40 +239,6 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
if (!tsk)
tsk = current;
- if (call_trace >= 0) {
- int unw_ret = 0;
- struct unwind_frame_info info;
- struct ops_and_data oad = { .ops = ops, .data = data };
-
- if (regs) {
- if (unwind_init_frame_info(&info, tsk, regs) == 0)
- unw_ret = dump_trace_unwind(&info, &oad);
- } else if (tsk == current)
- unw_ret = unwind_init_running(&info, dump_trace_unwind,
- &oad);
- else {
- if (unwind_init_blocked(&info, tsk) == 0)
- unw_ret = dump_trace_unwind(&info, &oad);
- }
- if (unw_ret > 0) {
- if (call_trace == 1 && !arch_unw_user_mode(&info)) {
- ops->warning_symbol(data,
- "DWARF2 unwinder stuck at %s",
- UNW_PC(&info));
- if ((long)UNW_SP(&info) < 0) {
- MSG("Leftover inexact backtrace:");
- stack = (unsigned long *)UNW_SP(&info);
- if (!stack)
- goto out;
- } else
- MSG("Full inexact backtrace again:");
- } else if (call_trace >= 1)
- goto out;
- else
- MSG("Full inexact backtrace again:");
- } else
- MSG("Inexact backtrace:");
- }
if (!stack) {
unsigned long dummy;
stack = &dummy;
@@ -383,10 +319,9 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
/*
* This handles the process stack:
*/
- tinfo = current_thread_info();
+ tinfo = task_thread_info(tsk);
HANDLE_STACK (valid_stack_ptr(tinfo, stack));
#undef HANDLE_STACK
-out:
put_cpu();
}
EXPORT_SYMBOL(dump_trace);
@@ -524,30 +459,15 @@ bad:
printk("\n");
}
-void handle_BUG(struct pt_regs *regs)
-{
- struct bug_frame f;
- long len;
- const char *prefix = "";
+int is_valid_bugaddr(unsigned long rip)
+{
+ unsigned short ud2;
- if (user_mode(regs))
- return;
- if (__copy_from_user(&f, (const void __user *) regs->rip,
- sizeof(struct bug_frame)))
- return;
- if (f.filename >= 0 ||
- f.ud2[0] != 0x0f || f.ud2[1] != 0x0b)
- return;
- len = __strnlen_user((char *)(long)f.filename, PATH_MAX) - 1;
- if (len < 0 || len >= PATH_MAX)
- f.filename = (int)(long)"unmapped filename";
- else if (len > 50) {
- f.filename += len - 50;
- prefix = "...";
- }
- printk("----------- [cut here ] --------- [please bite here ] ---------\n");
- printk(KERN_ALERT "Kernel BUG at %s%.50s:%d\n", prefix, (char *)(long)f.filename, f.line);
-}
+ if (__copy_from_user(&ud2, (const void __user *) rip, sizeof(ud2)))
+ return 0;
+
+ return ud2 == 0x0b0f;
+}
#ifdef CONFIG_BUG
void out_of_line_bug(void)
@@ -627,7 +547,9 @@ void die(const char * str, struct pt_regs * regs, long err)
{
unsigned long flags = oops_begin();
- handle_BUG(regs);
+ if (!user_mode(regs))
+ report_bug(regs->rip);
+
__die(str, regs, err);
oops_end(flags);
do_exit(SIGSEGV);
@@ -1200,21 +1122,3 @@ static int __init kstack_setup(char *s)
return 0;
}
early_param("kstack", kstack_setup);
-
-#ifdef CONFIG_STACK_UNWIND
-static int __init call_trace_setup(char *s)
-{
- if (!s)
- return -EINVAL;
- if (strcmp(s, "old") == 0)
- call_trace = -1;
- else if (strcmp(s, "both") == 0)
- call_trace = 0;
- else if (strcmp(s, "newfallback") == 0)
- call_trace = 1;
- else if (strcmp(s, "new") == 0)
- call_trace = 2;
- return 0;
-}
-early_param("call_trace", call_trace_setup);
-#endif
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 6a1f8f491e5..1e54ddf2338 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -13,6 +13,7 @@ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(phys_startup_64)
jiffies_64 = jiffies;
+_proxy_pda = 0;
PHDRS {
text PT_LOAD FLAGS(5); /* R_E */
data PT_LOAD FLAGS(7); /* RWE */
@@ -51,6 +52,8 @@ SECTIONS
RODATA
+ BUG_TABLE
+
. = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */
/* Data */
.data : AT(ADDR(.data) - LOAD_OFFSET) {
@@ -218,9 +221,7 @@ SECTIONS
/* Sections to be discarded */
/DISCARD/ : {
*(.exitcall.exit)
-#ifndef CONFIG_UNWIND_INFO
*(.eh_frame)
-#endif
}
STABS_DEBUG
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index 4a673f5397a..2433d6fc68b 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -225,8 +225,7 @@ out:
static int vsyscall_sysctl_nostrat(ctl_table *t, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
+ void __user *newval, size_t newlen)
{
return -ENOSYS;
}
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index 1087e150a21..2efe215fc76 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -101,7 +101,7 @@ static __init inline int srat_disabled(void)
static __init int slit_valid(struct acpi_table_slit *slit)
{
int i, j;
- int d = slit->localities;
+ int d = slit->locality_count;
for (i = 0; i < d; i++) {
for (j = 0; j < d; j++) {
u8 val = slit->entry[d*i + j];
@@ -127,18 +127,18 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
/* Callback for Proximity Domain -> LAPIC mapping */
void __init
-acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
+acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
{
int pxm, node;
if (srat_disabled())
return;
- if (pa->header.length != sizeof(struct acpi_table_processor_affinity)) {
+ if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
bad_srat();
return;
}
- if (pa->flags.enabled == 0)
+ if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
return;
- pxm = pa->proximity_domain;
+ pxm = pa->proximity_domain_lo;
node = setup_node(pxm);
if (node < 0) {
printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
@@ -254,21 +254,21 @@ static int reserve_hotadd(int node, unsigned long start, unsigned long end)
/* Looks good */
if (nd->start == nd->end) {
- nd->start = start;
- nd->end = end;
+ nd->start = start;
+ nd->end = end;
changed = 1;
- } else {
- if (nd->start == end) {
- nd->start = start;
+ } else {
+ if (nd->start == end) {
+ nd->start = start;
changed = 1;
}
- if (nd->end == start) {
- nd->end = end;
+ if (nd->end == start) {
+ nd->end = end;
changed = 1;
}
if (!changed)
printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
- }
+ }
ret = update_end_of_memory(nd->end);
@@ -279,7 +279,7 @@ static int reserve_hotadd(int node, unsigned long start, unsigned long end)
/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
void __init
-acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
+acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
{
struct bootnode *nd, oldnode;
unsigned long start, end;
@@ -288,16 +288,17 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
if (srat_disabled())
return;
- if (ma->header.length != sizeof(struct acpi_table_memory_affinity)) {
+ if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
bad_srat();
return;
}
- if (ma->flags.enabled == 0)
+ if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
return;
- if (ma->flags.hot_pluggable && !save_add_info())
+
+ if ((ma->flags & ACPI_SRAT_MEM_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));
+ start = ma->base_address;
+ end = start + ma->length;
pxm = ma->proximity_domain;
node = setup_node(pxm);
if (node < 0) {
@@ -337,7 +338,8 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
push_node_boundaries(node, nd->start >> PAGE_SHIFT,
nd->end >> PAGE_SHIFT);
- if (ma->flags.hot_pluggable && (reserve_hotadd(node, start, end) < 0)) {
+ if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) &&
+ (reserve_hotadd(node, start, end) < 0)) {
/* Ignore hotadd region. Undo damage */
printk(KERN_NOTICE "SRAT: Hotplug region ignored\n");
*nd = oldnode;
@@ -394,7 +396,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
/* First clean up the node list */
for (i = 0; i < MAX_NUMNODES; i++) {
- cutoff_node(i, start, end);
+ cutoff_node(i, start, end);
if ((nodes[i].end - nodes[i].start) < NODE_MIN_SIZE) {
unparse_node(i);
node_set_offline(i);
@@ -426,7 +428,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
if (!node_online(i))
setup_node_bootmem(i, nodes[i].start, nodes[i].end);
- for (i = 0; i < NR_CPUS; i++) {
+ for (i = 0; i < NR_CPUS; i++) {
if (cpu_to_node[i] == NUMA_NO_NODE)
continue;
if (!node_isset(cpu_to_node[i], nodes_parsed))
@@ -461,7 +463,7 @@ int __node_distance(int a, int b)
if (!acpi_slit)
return a == b ? 10 : 20;
- index = acpi_slit->localities * node_to_pxm(a);
+ index = acpi_slit->locality_count * node_to_pxm(a);
return acpi_slit->entry[index + node_to_pxm(b)];
}
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index f8b6b2800a6..faabb6e87f1 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -1,6 +1,6 @@
/*
* mmconfig.c - Low-level direct PCI config space access via MMCONFIG
- *
+ *
* This is an 64bit optimized version that always keeps the full mmconfig
* space mapped. This allows lockless config space operation.
*/
@@ -25,7 +25,7 @@ static DECLARE_BITMAP(fallback_slots, 32*MAX_CHECK_BUS);
/* Static virtual mapping of the MMCONFIG aperture */
struct mmcfg_virt {
- struct acpi_table_mcfg_config *cfg;
+ struct acpi_mcfg_allocation *cfg;
char __iomem *virt;
};
static struct mmcfg_virt *pci_mmcfg_virt;
@@ -33,14 +33,14 @@ static struct mmcfg_virt *pci_mmcfg_virt;
static char __iomem *get_virt(unsigned int seg, unsigned bus)
{
int cfg_num = -1;
- struct acpi_table_mcfg_config *cfg;
+ struct acpi_mcfg_allocation *cfg;
while (1) {
++cfg_num;
if (cfg_num >= pci_mmcfg_config_num)
break;
cfg = pci_mmcfg_virt[cfg_num].cfg;
- if (cfg->pci_segment_group_number != seg)
+ if (cfg->pci_segment != seg)
continue;
if ((cfg->start_bus_number <= bus) &&
(cfg->end_bus_number >= bus))
@@ -52,7 +52,7 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus)
this applies to all busses. */
cfg = &pci_mmcfg_config[0];
if (pci_mmcfg_config_num == 1 &&
- cfg->pci_segment_group_number == 0 &&
+ cfg->pci_segment == 0 &&
(cfg->start_bus_number | cfg->end_bus_number) == 0)
return pci_mmcfg_virt[0].virt;
@@ -170,19 +170,19 @@ void __init pci_mmcfg_init(int type)
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return;
- acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+ acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
if ((pci_mmcfg_config_num == 0) ||
(pci_mmcfg_config == NULL) ||
- (pci_mmcfg_config[0].base_address == 0))
+ (pci_mmcfg_config[0].address == 0))
return;
/* Only do this check when type 1 works. If it doesn't work
assume we run on a Mac and always use MCFG */
- if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address,
- pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
+ if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].address,
+ pci_mmcfg_config[0].address + MMCONFIG_APER_MIN,
E820_RESERVED)) {
- printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
- pci_mmcfg_config[0].base_address);
+ printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n",
+ (unsigned long)pci_mmcfg_config[0].address);
printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
return;
}
@@ -194,15 +194,16 @@ void __init pci_mmcfg_init(int type)
}
for (i = 0; i < pci_mmcfg_config_num; ++i) {
pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
- pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address,
+ pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].address,
MMCONFIG_APER_MAX);
if (!pci_mmcfg_virt[i].virt) {
printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
"segment %d\n",
- pci_mmcfg_config[i].pci_segment_group_number);
+ pci_mmcfg_config[i].pci_segment);
return;
}
- printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
+ printk(KERN_INFO "PCI: Using MMCONFIG at %lx\n",
+ (unsigned long)pci_mmcfg_config[i].address);
}
unreachable_devices();
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index c1e69a1f92a..2e74cb0b780 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -34,31 +34,24 @@ config GENERIC_HARDIRQS
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
source "init/Kconfig"
menu "Processor type and features"
choice
prompt "Xtensa Processor Configuration"
- default XTENSA_CPU_LINUX_BE
+ default XTENSA_VARIANT_FSF
-config XTENSA_CPU_LINUX_BE
- bool "linux_be"
- ---help---
- The linux_be processor configuration is the baseline Xtensa
- configurations included in this kernel and also used by
- binutils, gcc, and gdb. It contains no TIE, no coprocessors,
- and the following configuration options:
-
- Code Density Option 2 Misc Special Registers
- NSA/NSAU Instructions 128-bit Data Bus Width
- Processor ID 8K, 2-way I and D Caches
- Zero-Overhead Loops 2 Inst Address Break Registers
- Big Endian 2 Data Address Break Registers
- 64 General-Purpose Registers JTAG Interface and Trace Port
- 17 Interrupts MMU w/ TLBs and Autorefill
- 3 Interrupt Levels 8 Autorefill Ways (I/D TLBs)
- 3 Timers Unaligned Exceptions
+config XTENSA_VARIANT_FSF
+ bool "fsf"
endchoice
config MMU
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile
index 3a3a4c66ef8..95f836db38f 100644
--- a/arch/xtensa/Makefile
+++ b/arch/xtensa/Makefile
@@ -11,13 +11,13 @@
# this architecture
# Core configuration.
-# (Use CPU=<xtensa_config> to use another default compiler.)
+# (Use VAR=<xtensa_config> to use another default compiler.)
-cpu-$(CONFIG_XTENSA_CPU_LINUX_BE) := linux_be
-cpu-$(CONFIG_XTENSA_CPU_LINUX_CUSTOM) := linux_custom
+variant-$(CONFIG_XTENSA_VARIANT_FSF) := fsf
+variant-$(CONFIG_XTENSA_VARIANT_LINUX_CUSTOM) := custom
-CPU = $(cpu-y)
-export CPU
+VARIANT = $(variant-y)
+export VARIANT
# Platform configuration
@@ -27,8 +27,6 @@ platform-$(CONFIG_XTENSA_PLATFORM_ISS) := iss
PLATFORM = $(platform-y)
export PLATFORM
-CPPFLAGS += $(if $(KBUILD_SRC),-I$(srctree)/include/asm-xtensa/)
-CPPFLAGS += -Iinclude/asm
CFLAGS += -pipe -mlongcalls
KBUILD_DEFCONFIG := iss_defconfig
@@ -41,12 +39,12 @@ core-$(CONFIG_EMBEDDED_RAMDISK) += arch/xtensa/boot/ramdisk/
# Test for cross compiling
-ifneq ($(CPU),)
+ifneq ($(VARIANT),)
COMPILE_ARCH = $(shell uname -m)
ifneq ($(COMPILE_ARCH), xtensa)
ifndef CROSS_COMPILE
- CROSS_COMPILE = xtensa_$(CPU)-
+ CROSS_COMPILE = xtensa_$(VARIANT)-
endif
endif
endif
@@ -68,14 +66,13 @@ archinc := include/asm-xtensa
archprepare: $(archinc)/.platform
-# Update machine cpu and platform symlinks if something which affects
+# Update processor variant and platform symlinks if something which affects
# them changed.
$(archinc)/.platform: $(wildcard include/config/arch/*.h) include/config/auto.conf
- @echo ' SYMLINK $(archinc)/xtensa/config -> $(archinc)/xtensa/config-$(CPU)'
+ @echo ' SYMLINK $(archinc)/variant -> $(archinc)/variant-$(VARIANT)'
$(Q)mkdir -p $(archinc)
- $(Q)mkdir -p $(archinc)/xtensa
- $(Q)ln -fsn $(srctree)/$(archinc)/xtensa/config-$(CPU) $(archinc)/xtensa/config
+ $(Q)ln -fsn $(srctree)/$(archinc)/variant-$(VARIANT) $(archinc)/variant
@echo ' SYMLINK $(archinc)/platform -> $(archinc)/platform-$(PLATFORM)'
$(Q)ln -fsn $(srctree)/$(archinc)/platform-$(PLATFORM) $(archinc)/platform
@touch $@
@@ -89,7 +86,7 @@ zImage zImage.initrd: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $@
CLEAN_FILES += arch/xtensa/vmlinux.lds \
- $(archinc)/platform $(archinc)/xtensa/config \
+ $(archinc)/platform $(archinc)/variant \
$(archinc)/.platform
define archhelp
diff --git a/arch/xtensa/boot/boot-elf/bootstrap.S b/arch/xtensa/boot/boot-elf/bootstrap.S
index f857fc760aa..464298bc348 100644
--- a/arch/xtensa/boot/boot-elf/bootstrap.S
+++ b/arch/xtensa/boot/boot-elf/bootstrap.S
@@ -1,7 +1,4 @@
-#include <xtensa/config/specreg.h>
-#include <xtensa/config/core.h>
-
#include <asm/bootparam.h>
diff --git a/arch/xtensa/boot/boot-redboot/bootstrap.S b/arch/xtensa/boot/boot-redboot/bootstrap.S
index ee636b0da81..84848123e2a 100644
--- a/arch/xtensa/boot/boot-redboot/bootstrap.S
+++ b/arch/xtensa/boot/boot-redboot/bootstrap.S
@@ -1,9 +1,7 @@
-
-#define _ASMLANGUAGE
-#include <xtensa/config/specreg.h>
-#include <xtensa/config/core.h>
-#include <xtensa/cacheasm.h>
-
+#include <asm/variant/core.h>
+#include <asm/regs.h>
+#include <asm/asmmacro.h>
+#include <asm/cacheasm.h>
/*
* RB-Data: RedBoot data/bss
* P: Boot-Parameters
@@ -77,8 +75,14 @@ _start:
/* Note: The assembler cannot relax "addi a0, a0, ..." to an
l32r, so we load to a4 first. */
- addi a4, a0, __start - __start_a0
- mov a0, a4
+ # addi a4, a0, __start - __start_a0
+ # mov a0, a4
+
+ movi a4, __start
+ movi a5, __start_a0
+ add a4, a0, a4
+ sub a0, a4, a5
+
movi a4, __start
movi a5, __reloc_end
@@ -106,9 +110,13 @@ _start:
/* We have to flush and invalidate the caches here before we jump. */
#if XCHAL_DCACHE_IS_WRITEBACK
- dcache_writeback_all a5, a6
+
+ ___flush_dcache_all a5 a6
+
#endif
- icache_invalidate_all a5, a6
+
+ ___invalidate_icache_all a5 a6
+ isync
movi a11, _reloc
jx a11
@@ -209,9 +217,14 @@ _reloc:
/* jump to the kernel */
2:
#if XCHAL_DCACHE_IS_WRITEBACK
- dcache_writeback_all a5, a6
+
+ ___flush_dcache_all a5 a6
+
#endif
- icache_invalidate_all a5, a6
+
+ ___invalidate_icache_all a5 a6
+
+ isync
movi a5, __start
movi a3, boot_initrd_start
diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig
index 802621dd486..f19854035e6 100644
--- a/arch/xtensa/configs/iss_defconfig
+++ b/arch/xtensa/configs/iss_defconfig
@@ -53,11 +53,7 @@ CONFIG_CC_ALIGN_JUMPS=0
#
# Processor type and features
#
-CONFIG_XTENSA_ARCH_LINUX_BE=y
-# CONFIG_XTENSA_ARCH_LINUX_LE is not set
-# CONFIG_XTENSA_ARCH_LINUX_TEST is not set
-# CONFIG_XTENSA_ARCH_S5 is not set
-# CONFIG_XTENSA_CUSTOM is not set
+CONFIG_XTENSA_VARIANT_FSF=y
CONFIG_MMU=y
# CONFIG_XTENSA_UNALIGNED_USER is not set
# CONFIG_PREEMPT is not set
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile
index d573017a5dd..71f733c4f66 100644
--- a/arch/xtensa/kernel/Makefile
+++ b/arch/xtensa/kernel/Makefile
@@ -6,7 +6,7 @@ extra-y := head.o vmlinux.lds
obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o semaphore.o \
- setup.o signal.o syscalls.o time.o traps.o vectors.o platform.o \
+ setup.o signal.o syscall.o time.o traps.o vectors.o platform.o \
pci-dma.o
## windowspill.o
diff --git a/arch/xtensa/kernel/align.S b/arch/xtensa/kernel/align.S
index a4956578a24..33d6e9d2e83 100644
--- a/arch/xtensa/kernel/align.S
+++ b/arch/xtensa/kernel/align.S
@@ -16,14 +16,9 @@
*/
#include <linux/linkage.h>
-#include <asm/ptrace.h>
-#include <asm/ptrace.h>
#include <asm/current.h>
#include <asm/asm-offsets.h>
-#include <asm/pgtable.h>
#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/thread_info.h>
#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
@@ -216,7 +211,7 @@ ENTRY(fast_unaligned)
extui a5, a4, INSN_OP0, 4 # get insn.op0 nibble
-#if XCHAL_HAVE_NARROW
+#if XCHAL_HAVE_DENSITY
_beqi a5, OP0_L32I_N, .Lload # L32I.N, jump
addi a6, a5, -OP0_S32I_N
_beqz a6, .Lstore # S32I.N, do a store
@@ -251,7 +246,7 @@ ENTRY(fast_unaligned)
#endif
__src_b a3, a5, a6 # a3 has the data word
-#if XCHAL_HAVE_NARROW
+#if XCHAL_HAVE_DENSITY
addi a7, a7, 2 # increment PC (assume 16-bit insn)
extui a5, a4, INSN_OP0, 4
@@ -279,14 +274,14 @@ ENTRY(fast_unaligned)
1:
-#if XCHAL_HAVE_LOOP
- rsr a3, LEND # check if we reached LEND
- bne a7, a3, 1f
- rsr a3, LCOUNT # and LCOUNT != 0
- beqz a3, 1f
- addi a3, a3, -1 # decrement LCOUNT and set
+#if XCHAL_HAVE_LOOPS
+ rsr a5, LEND # check if we reached LEND
+ bne a7, a5, 1f
+ rsr a5, LCOUNT # and LCOUNT != 0
+ beqz a5, 1f
+ addi a5, a5, -1 # decrement LCOUNT and set
rsr a7, LBEG # set PC to LBEGIN
- wsr a3, LCOUNT
+ wsr a5, LCOUNT
#endif
1: wsr a7, EPC_1 # skip load instruction
@@ -336,7 +331,7 @@ ENTRY(fast_unaligned)
movi a6, 0 # mask: ffffffff:00000000
-#if XCHAL_HAVE_NARROW
+#if XCHAL_HAVE_DENSITY
addi a7, a7, 2 # incr. PC,assume 16-bit instruction
extui a5, a4, INSN_OP0, 4 # extract OP0
@@ -359,14 +354,14 @@ ENTRY(fast_unaligned)
/* Get memory address */
1:
-#if XCHAL_HAVE_LOOP
- rsr a3, LEND # check if we reached LEND
- bne a7, a3, 1f
- rsr a3, LCOUNT # and LCOUNT != 0
- beqz a3, 1f
- addi a3, a3, -1 # decrement LCOUNT and set
+#if XCHAL_HAVE_LOOPS
+ rsr a4, LEND # check if we reached LEND
+ bne a7, a4, 1f
+ rsr a4, LCOUNT # and LCOUNT != 0
+ beqz a4, 1f
+ addi a4, a4, -1 # decrement LCOUNT and set
rsr a7, LBEG # set PC to LBEGIN
- wsr a3, LCOUNT
+ wsr a4, LCOUNT
#endif
1: wsr a7, EPC_1 # skip store instruction
@@ -416,6 +411,7 @@ ENTRY(fast_unaligned)
/* Restore working register */
+ l32i a8, a2, PT_AREG8
l32i a7, a2, PT_AREG7
l32i a6, a2, PT_AREG6
l32i a5, a2, PT_AREG5
@@ -446,7 +442,7 @@ ENTRY(fast_unaligned)
mov a1, a2
rsr a0, PS
- bbsi.l a2, PS_UM_SHIFT, 1f # jump if user mode
+ bbsi.l a2, PS_UM_BIT, 1f # jump if user mode
movi a0, _kernel_exception
jx a0
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
index 7cd1d7f8f60..b256cfbef34 100644
--- a/arch/xtensa/kernel/asm-offsets.c
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -87,6 +87,11 @@ int main(void)
DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context));
BLANK();
DEFINE(PT_SINGLESTEP_BIT, PT_SINGLESTEP_BIT);
+
+ /* constants */
+ DEFINE(_CLONE_VM, CLONE_VM);
+ DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED);
+
return 0;
}
diff --git a/arch/xtensa/kernel/coprocessor.S b/arch/xtensa/kernel/coprocessor.S
index cf5a93fb6a2..01bcb9fcfcb 100644
--- a/arch/xtensa/kernel/coprocessor.S
+++ b/arch/xtensa/kernel/coprocessor.S
@@ -90,7 +90,6 @@ ENTRY(enable_coprocessor)
rsync
retw
-#endif
ENTRY(save_coprocessor_extra)
entry sp, 16
@@ -197,4 +196,5 @@ _xtensa_reginfo_tables:
XCHAL_CP7_SA_CONTENTS_LIBDB
.word 0xFC000000 /* invalid register number,marks end of table*/
_xtensa_reginfo_table_end:
+#endif
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 89e409e9e0d..9e271ba009b 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -24,7 +24,7 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/signal.h>
-#include <xtensa/coreasm.h>
+#include <asm/tlbflush.h>
/* Unimplemented features. */
@@ -364,7 +364,7 @@ common_exception:
movi a2, 1
extui a3, a3, 0, 1 # a3 = PS.INTLEVEL[0]
moveqz a3, a2, a0 # a3 = 1 iff interrupt exception
- movi a2, PS_WOE_MASK
+ movi a2, 1 << PS_WOE_BIT
or a3, a3, a2
rsr a0, EXCCAUSE
xsr a3, PS
@@ -399,7 +399,7 @@ common_exception_return:
/* Jump if we are returning from kernel exceptions. */
1: l32i a3, a1, PT_PS
- _bbsi.l a3, PS_UM_SHIFT, 2f
+ _bbsi.l a3, PS_UM_BIT, 2f
j kernel_exception_exit
/* Specific to a user exception exit:
@@ -422,7 +422,7 @@ common_exception_return:
* (Hint: There is only one user exception frame on stack)
*/
- movi a3, PS_WOE_MASK
+ movi a3, 1 << PS_WOE_BIT
_bbsi.l a4, TIF_NEED_RESCHED, 3f
_bbci.l a4, TIF_SIGPENDING, 4f
@@ -694,7 +694,7 @@ common_exception_exit:
ENTRY(debug_exception)
rsr a0, EPS + XCHAL_DEBUGLEVEL
- bbsi.l a0, PS_EXCM_SHIFT, 1f # exception mode
+ bbsi.l a0, PS_EXCM_BIT, 1f # exception mode
/* Set EPC_1 and EXCCAUSE */
@@ -707,7 +707,7 @@ ENTRY(debug_exception)
/* Restore PS to the value before the debug exc but with PS.EXCM set.*/
- movi a2, 1 << PS_EXCM_SHIFT
+ movi a2, 1 << PS_EXCM_BIT
or a2, a0, a2
movi a0, debug_exception # restore a3, debug jump vector
wsr a2, PS
@@ -715,7 +715,7 @@ ENTRY(debug_exception)
/* Switch to kernel/user stack, restore jump vector, and save a0 */
- bbsi.l a2, PS_UM_SHIFT, 2f # jump if user mode
+ bbsi.l a2, PS_UM_BIT, 2f # jump if user mode
addi a2, a1, -16-PT_SIZE # assume kernel stack
s32i a0, a2, PT_AREG0
@@ -778,7 +778,7 @@ ENTRY(unrecoverable_exception)
wsr a1, WINDOWBASE
rsync
- movi a1, PS_WOE_MASK | 1
+ movi a1, (1 << PS_WOE_BIT) | 1
wsr a1, PS
rsync
@@ -1004,13 +1004,10 @@ ENTRY(fast_syscall_kernel)
rsr a0, DEPC # get syscall-nr
_beqz a0, fast_syscall_spill_registers
-
- addi a0, a0, -__NR_sysxtensa
- _beqz a0, fast_syscall_sysxtensa
+ _beqi a0, __NR_xtensa, fast_syscall_xtensa
j kernel_exception
-
ENTRY(fast_syscall_user)
/* Skip syscall. */
@@ -1024,9 +1021,7 @@ ENTRY(fast_syscall_user)
rsr a0, DEPC # get syscall-nr
_beqz a0, fast_syscall_spill_registers
-
- addi a0, a0, -__NR_sysxtensa
- _beqz a0, fast_syscall_sysxtensa
+ _beqi a0, __NR_xtensa, fast_syscall_xtensa
j user_exception
@@ -1047,18 +1042,19 @@ ENTRY(fast_syscall_unrecoverable)
/*
* sysxtensa syscall handler
*
- * int sysxtensa (XTENSA_ATOMIC_SET, ptr, val, unused);
- * int sysxtensa (XTENSA_ATOMIC_ADD, ptr, val, unused);
- * int sysxtensa (XTENSA_ATOMIC_EXG_ADD, ptr, val, unused);
- * int sysxtensa (XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
- * a2 a6 a3 a4 a5
+ * int sysxtensa (SYS_XTENSA_ATOMIC_SET, ptr, val, unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_ADD, ptr, val, unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val, unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
+ * a2 a6 a3 a4 a5
*
* Entry condition:
*
- * a0: trashed, original value saved on stack (PT_AREG0)
+ * a0: a2 (syscall-nr), original value saved on stack (PT_AREG0)
* a1: a1
- * a2: new stack pointer, original in DEPC
- * a3: dispatch table
+ * a2: new stack pointer, original in a0 and DEPC
+ * a3: dispatch table, original in excsave_1
+ * a4..a15: unchanged
* depc: a2, original value saved on stack (PT_DEPC)
* excsave_1: a3
*
@@ -1091,59 +1087,62 @@ ENTRY(fast_syscall_unrecoverable)
#define CATCH \
67:
-ENTRY(fast_syscall_sysxtensa)
-
- _beqz a6, 1f
- _blti a6, SYSXTENSA_COUNT, 2f
+ENTRY(fast_syscall_xtensa)
-1: j user_exception
-
-2: xsr a3, EXCSAVE_1 # restore a3, excsave1
- s32i a7, a2, PT_AREG7
+ xsr a3, EXCSAVE_1 # restore a3, excsave1
+ s32i a7, a2, PT_AREG7 # we need an additional register
movi a7, 4 # sizeof(unsigned int)
- access_ok a0, a3, a7, a2, .Leac
+ access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp
- _beqi a6, SYSXTENSA_ATOMIC_SET, .Lset
- _beqi a6, SYSXTENSA_ATOMIC_EXG_ADD, .Lexg
- _beqi a6, SYSXTENSA_ATOMIC_ADD, .Ladd
+ addi a6, a6, -1 # assuming SYS_XTENSA_ATOMIC_SET = 1
+ _bgeui a6, SYS_XTENSA_COUNT - 1, .Lill
+ _bnei a6, SYS_XTENSA_ATOMIC_CMP_SWP - 1, .Lnswp
- /* Fall through for SYSXTENSA_ATOMIC_CMP_SWP */
+ /* Fall through for ATOMIC_CMP_SWP. */
.Lswp: /* Atomic compare and swap */
-TRY l32i a7, a3, 0 # read old value
- bne a7, a4, 1f # same as old value? jump
- s32i a5, a3, 0 # different, modify value
- movi a7, 1 # and return 1
- j .Lret
-
-1: movi a7, 0 # same values: return 0
- j .Lret
-
-.Ladd: /* Atomic add */
-.Lexg: /* Atomic (exchange) add */
+TRY l32i a0, a3, 0 # read old value
+ bne a0, a4, 1f # same as old value? jump
+TRY s32i a5, a3, 0 # different, modify value
+ l32i a7, a2, PT_AREG7 # restore a7
+ l32i a0, a2, PT_AREG0 # restore a0
+ movi a2, 1 # and return 1
+ addi a6, a6, 1 # restore a6 (really necessary?)
+ rfe
-TRY l32i a7, a3, 0
- add a4, a4, a7
- s32i a4, a3, 0
- j .Lret
+1: l32i a7, a2, PT_AREG7 # restore a7
+ l32i a0, a2, PT_AREG0 # restore a0
+ movi a2, 0 # return 0 (note that we cannot set
+ addi a6, a6, 1 # restore a6 (really necessary?)
+ rfe
-.Lset: /* Atomic set */
+.Lnswp: /* Atomic set, add, and exg_add. */
-TRY l32i a7, a3, 0 # read old value as return value
- s32i a4, a3, 0 # write new value
+TRY l32i a7, a3, 0 # orig
+ add a0, a4, a7 # + arg
+ moveqz a0, a4, a6 # set
+TRY s32i a0, a3, 0 # write new value
-.Lret: mov a0, a2
+ mov a0, a2
mov a2, a7
- l32i a7, a0, PT_AREG7
- l32i a3, a0, PT_AREG3
- l32i a0, a0, PT_AREG0
+ l32i a7, a0, PT_AREG7 # restore a7
+ l32i a0, a0, PT_AREG0 # restore a0
+ addi a6, a6, 1 # restore a6 (really necessary?)
rfe
CATCH
-.Leac: movi a7, -EFAULT
- j .Lret
+.Leac: l32i a7, a2, PT_AREG7 # restore a7
+ l32i a0, a2, PT_AREG0 # restore a0
+ movi a2, -EFAULT
+ rfe
+
+.Lill: l32i a7, a2, PT_AREG0 # restore a7
+ l32i a0, a2, PT_AREG0 # restore a0
+ movi a2, -EINVAL
+ rfe
+
@@ -1491,7 +1490,7 @@ ENTRY(_spill_registers)
*/
rsr a0, PS
- _bbci.l a0, PS_UM_SHIFT, 1f
+ _bbci.l a0, PS_UM_BIT, 1f
/* User space: Setup a dummy frame and kill application.
* Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.
@@ -1510,7 +1509,7 @@ ENTRY(_spill_registers)
l32i a1, a3, EXC_TABLE_KSTK
wsr a3, EXCSAVE_1
- movi a4, PS_WOE_MASK | 1
+ movi a4, (1 << PS_WOE_BIT) | 1
wsr a4, PS
rsync
@@ -1612,7 +1611,7 @@ ENTRY(fast_second_level_miss)
rsr a1, PTEVADDR
srli a1, a1, PAGE_SHIFT
slli a1, a1, PAGE_SHIFT # ptevaddr & PAGE_MASK
- addi a1, a1, DTLB_WAY_PGTABLE # ... + way_number
+ addi a1, a1, DTLB_WAY_PGD # ... + way_number
wdtlb a0, a1
dsync
@@ -1654,7 +1653,7 @@ ENTRY(fast_second_level_miss)
mov a1, a2
rsr a2, PS
- bbsi.l a2, PS_UM_SHIFT, 1f
+ bbsi.l a2, PS_UM_BIT, 1f
j _kernel_exception
1: j _user_exception
@@ -1753,7 +1752,7 @@ ENTRY(fast_store_prohibited)
mov a1, a2
rsr a2, PS
- bbsi.l a2, PS_UM_SHIFT, 1f
+ bbsi.l a2, PS_UM_BIT, 1f
j _kernel_exception
1: j _user_exception
@@ -1907,6 +1906,103 @@ ENTRY(fast_coprocessor)
#endif /* XCHAL_EXTRA_SA_SIZE */
/*
+ * System Calls.
+ *
+ * void system_call (struct pt_regs* regs, int exccause)
+ * a2 a3
+ */
+
+ENTRY(system_call)
+ entry a1, 32
+
+ /* regs->syscall = regs->areg[2] */
+
+ l32i a3, a2, PT_AREG2
+ mov a6, a2
+ movi a4, do_syscall_trace_enter
+ s32i a3, a2, PT_SYSCALL
+ callx4 a4
+
+ /* syscall = sys_call_table[syscall_nr] */
+
+ movi a4, sys_call_table;
+ movi a5, __NR_syscall_count
+ movi a6, -ENOSYS
+ bgeu a3, a5, 1f
+
+ addx4 a4, a3, a4
+ l32i a4, a4, 0
+ movi a5, sys_ni_syscall;
+ beq a4, a5, 1f
+
+ /* Load args: arg0 - arg5 are passed via regs. */
+
+ l32i a6, a2, PT_AREG6
+ l32i a7, a2, PT_AREG3
+ l32i a8, a2, PT_AREG4
+ l32i a9, a2, PT_AREG5
+ l32i a10, a2, PT_AREG8
+ l32i a11, a2, PT_AREG9
+
+ /* Pass one additional argument to the syscall: pt_regs (on stack) */
+ s32i a2, a1, 0
+
+ callx4 a4
+
+1: /* regs->areg[2] = return_value */
+
+ s32i a6, a2, PT_AREG2
+ movi a4, do_syscall_trace_leave
+ mov a6, a2
+ callx4 a4
+ retw
+
+
+/*
+ * Create a kernel thread
+ *
+ * int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+ * a2 a2 a3 a4
+ */
+
+ENTRY(kernel_thread)
+ entry a1, 16
+
+ mov a5, a2 # preserve fn over syscall
+ mov a7, a3 # preserve args over syscall
+
+ movi a3, _CLONE_VM | _CLONE_UNTRACED
+ movi a2, __NR_clone
+ or a6, a4, a3 # arg0: flags
+ mov a3, a1 # arg1: sp
+ syscall
+
+ beq a3, a1, 1f # branch if parent
+ mov a6, a7 # args
+ callx4 a5 # fn(args)
+
+ movi a2, __NR_exit
+ syscall # return value of fn(args) still in a6
+
+1: retw
+
+/*
+ * Do a system call from kernel instead of calling sys_execve, so we end up
+ * with proper pt_regs.
+ *
+ * int kernel_execve(const char *fname, char *const argv[], charg *const envp[])
+ * a2 a2 a3 a4
+ */
+
+ENTRY(kernel_execve)
+ entry a1, 16
+ mov a6, a2 # arg0 is in a6
+ movi a2, __NR_execve
+ syscall
+
+ retw
+
+/*
* Task switch.
*
* struct task* _switch_to (struct task* prev, struct task* next)
@@ -1924,7 +2020,7 @@ ENTRY(_switch_to)
/* Disable ints while we manipulate the stack pointer; spill regs. */
- movi a5, PS_EXCM_MASK | LOCKLEVEL
+ movi a5, (1 << PS_EXCM_BIT) | LOCKLEVEL
xsr a5, PS
rsr a3, EXCSAVE_1
rsync
@@ -1964,33 +2060,9 @@ ENTRY(ret_from_fork)
movi a4, schedule_tail
callx4 a4
- movi a4, do_syscall_trace
+ movi a4, do_syscall_trace_leave
+ mov a6, a1
callx4 a4
j common_exception_return
-
-
-/*
- * Table of syscalls
- */
-
-.data
-.align 4
-.global sys_call_table
-sys_call_table:
-
-#define SYSCALL(call, narg) .word call
-#include "syscalls.h"
-
-/*
- * Number of arguments of each syscall
- */
-
-.global sys_narg_table
-sys_narg_table:
-
-#undef SYSCALL
-#define SYSCALL(call, narg) .byte narg
-#include "syscalls.h"
-
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S
index c07cb252299..ea89910efa4 100644
--- a/arch/xtensa/kernel/head.S
+++ b/arch/xtensa/kernel/head.S
@@ -15,9 +15,9 @@
* Kevin Chea
*/
-#include <xtensa/cacheasm.h>
#include <asm/processor.h>
#include <asm/page.h>
+#include <asm/cacheasm.h>
/*
* This module contains the entry code for kernel images. It performs the
@@ -32,13 +32,6 @@
*
*/
- .macro iterate from, to , cmd
- .ifeq ((\to - \from) & ~0xfff)
- \cmd \from
- iterate "(\from+1)", \to, \cmd
- .endif
- .endm
-
/*
* _start
*
@@ -64,7 +57,7 @@ _startup:
/* Disable interrupts and exceptions. */
- movi a0, XCHAL_PS_EXCM_MASK
+ movi a0, LOCKLEVEL
wsr a0, PS
/* Preserve the pointer to the boot parameter list in EXCSAVE_1 */
@@ -91,11 +84,11 @@ _startup:
movi a1, 15
wsr a0, ICOUNTLEVEL
- .macro reset_dbreak num
- wsr a0, DBREAKC + \num
- .endm
-
- iterate 0, XCHAL_NUM_IBREAK-1, reset_dbreak
+ .set _index, 0
+ .rept XCHAL_NUM_DBREAK - 1
+ wsr a0, DBREAKC + _index
+ .set _index, _index + 1
+ .endr
#endif
/* Clear CCOUNT (not really necessary, but nice) */
@@ -110,10 +103,11 @@ _startup:
/* Disable all timers. */
- .macro reset_timer num
- wsr a0, CCOMPARE_0 + \num
- .endm
- iterate 0, XCHAL_NUM_TIMERS-1, reset_timer
+ .set _index, 0
+ .rept XCHAL_NUM_TIMERS - 1
+ wsr a0, CCOMPARE + _index
+ .set _index, _index + 1
+ .endr
/* Interrupt initialization. */
@@ -139,12 +133,21 @@ _startup:
rsync
/* Initialize the caches.
- * Does not include flushing writeback d-cache.
- * a6, a7 are just working registers (clobbered).
+ * a2, a3 are just working registers (clobbered).
*/
- icache_reset a2, a3
- dcache_reset a2, a3
+#if XCHAL_DCACHE_LINE_LOCKABLE
+ ___unlock_dcache_all a2 a3
+#endif
+
+#if XCHAL_ICACHE_LINE_LOCKABLE
+ ___unlock_icache_all a2 a3
+#endif
+
+ ___invalidate_dcache_all a2 a3
+ ___invalidate_icache_all a2 a3
+
+ isync
/* Unpack data sections
*
@@ -181,9 +184,9 @@ _startup:
movi a2, _bss_start # start of BSS
movi a3, _bss_end # end of BSS
-1: addi a2, a2, 4
+ __loopt a2, a3, a4, 2
s32i a0, a2, 0
- blt a2, a3, 1b
+ __endla a2, a4, 4
#if XCHAL_DCACHE_IS_WRITEBACK
@@ -191,7 +194,7 @@ _startup:
* instructions/data are available.
*/
- dcache_writeback_all a2, a3
+ ___flush_dcache_all a2 a3
#endif
/* Setup stack and enable window exceptions (keep irqs disabled) */
diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c
index 1cf744ee095..c9ea73b7031 100644
--- a/arch/xtensa/kernel/irq.c
+++ b/arch/xtensa/kernel/irq.c
@@ -4,7 +4,7 @@
* Xtensa built-in interrupt controller and some generic functions copied
* from i386.
*
- * Copyright (C) 2002 - 2005 Tensilica, Inc.
+ * Copyright (C) 2002 - 2006 Tensilica, Inc.
* Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
*
*
@@ -22,11 +22,6 @@
#include <asm/uaccess.h>
#include <asm/platform.h>
-static void enable_xtensa_irq(unsigned int irq);
-static void disable_xtensa_irq(unsigned int irq);
-static void mask_and_ack_xtensa(unsigned int irq);
-static void end_xtensa_irq(unsigned int irq);
-
static unsigned int cached_irq_mask;
atomic_t irq_err_count;
@@ -46,8 +41,16 @@ void ack_bad_irq(unsigned int irq)
* handlers).
*/
-unsigned int do_IRQ(int irq, struct pt_regs *regs)
+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ struct irq_desc *desc = irq_desc + irq;
+
+ if (irq >= NR_IRQS) {
+ printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
+ __FUNCTION__, irq);
+ }
+
irq_enter();
#ifdef CONFIG_DEBUG_STACKOVERFLOW
@@ -63,12 +66,10 @@ unsigned int do_IRQ(int irq, struct pt_regs *regs)
sp - sizeof(struct thread_info));
}
#endif
-
- __do_IRQ(irq, regs);
+ desc->handle_irq(irq, desc);
irq_exit();
-
- return 1;
+ set_irq_regs(old_regs);
}
/*
@@ -118,72 +119,68 @@ skip:
}
return 0;
}
-/* shutdown is same as "disable" */
-#define shutdown_xtensa_irq disable_xtensa_irq
-static unsigned int startup_xtensa_irq(unsigned int irq)
-{
- enable_xtensa_irq(irq);
- return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type xtensa_irq_type = {
- "Xtensa-IRQ",
- startup_xtensa_irq,
- shutdown_xtensa_irq,
- enable_xtensa_irq,
- disable_xtensa_irq,
- mask_and_ack_xtensa,
- end_xtensa_irq
-};
-
-static inline void mask_irq(unsigned int irq)
+static void xtensa_irq_mask(unsigned int irq)
{
cached_irq_mask &= ~(1 << irq);
set_sr (cached_irq_mask, INTENABLE);
}
-static inline void unmask_irq(unsigned int irq)
+static void xtensa_irq_unmask(unsigned int irq)
{
cached_irq_mask |= 1 << irq;
set_sr (cached_irq_mask, INTENABLE);
}
-static void disable_xtensa_irq(unsigned int irq)
+static void xtensa_irq_ack(unsigned int irq)
{
- unsigned long flags;
- local_save_flags(flags);
- mask_irq(irq);
- local_irq_restore(flags);
+ set_sr(1 << irq, INTCLEAR);
}
-static void enable_xtensa_irq(unsigned int irq)
+static int xtensa_irq_retrigger(unsigned int irq)
{
- unsigned long flags;
- local_save_flags(flags);
- unmask_irq(irq);
- local_irq_restore(flags);
-}
-
-static void mask_and_ack_xtensa(unsigned int irq)
-{
- disable_xtensa_irq(irq);
+ set_sr (1 << irq, INTSET);
+ return 1;
}
-static void end_xtensa_irq(unsigned int irq)
-{
- enable_xtensa_irq(irq);
-}
+static struct irq_chip xtensa_irq_chip = {
+ .name = "xtensa",
+ .mask = xtensa_irq_mask,
+ .unmask = xtensa_irq_unmask,
+ .ack = xtensa_irq_ack,
+ .retrigger = xtensa_irq_retrigger,
+};
void __init init_IRQ(void)
{
- int i;
+ int index;
- for (i=0; i < XTENSA_NR_IRQS; i++)
- irq_desc[i].chip = &xtensa_irq_type;
+ for (index = 0; index < XTENSA_NR_IRQS; index++) {
+ int mask = 1 << index;
- cached_irq_mask = 0;
+ if (mask & XCHAL_INTTYPE_MASK_SOFTWARE)
+ set_irq_chip_and_handler(index, &xtensa_irq_chip,
+ handle_simple_irq);
- platform_init_irq();
+ else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE)
+ set_irq_chip_and_handler(index, &xtensa_irq_chip,
+ handle_edge_irq);
+
+ else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL)
+ set_irq_chip_and_handler(index, &xtensa_irq_chip,
+ handle_level_irq);
+
+ else if (mask & XCHAL_INTTYPE_MASK_TIMER)
+ set_irq_chip_and_handler(index, &xtensa_irq_chip,
+ handle_edge_irq);
+
+ else /* XCHAL_INTTYPE_MASK_WRITE_ERROR */
+ /* XCHAL_INTTYPE_MASK_NMI */
+
+ set_irq_chip_and_handler(index, &xtensa_irq_chip,
+ handle_level_irq);
+ }
+
+ cached_irq_mask = 0;
}
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c
index 6648fa9d919..ca76f071666 100644
--- a/arch/xtensa/kernel/pci-dma.c
+++ b/arch/xtensa/kernel/pci-dma.c
@@ -1,5 +1,5 @@
/*
- * arch/xtensa/kernel/pci-dma.c
+ * arch/xtensa/pci-dma.c
*
* DMA coherent memory allocation.
*
@@ -29,28 +29,48 @@
*/
void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
+dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *handle,gfp_t flag)
{
- void *ret;
+ unsigned long ret;
+ unsigned long uncached = 0;
/* ignore region speicifiers */
- gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
- if (dev == NULL || (*dev->dma_mask < 0xffffffff))
- gfp |= GFP_DMA;
- ret = (void *)__get_free_pages(gfp, get_order(size));
+ flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
- if (ret != NULL) {
- memset(ret, 0, size);
- *handle = virt_to_bus(ret);
+ if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
+ flag |= GFP_DMA;
+ ret = (unsigned long)__get_free_pages(flag, get_order(size));
+
+ if (ret == 0)
+ return NULL;
+
+ /* We currently don't support coherent memory outside KSEG */
+
+ if (ret < XCHAL_KSEG_CACHED_VADDR
+ || ret >= XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE)
+ BUG();
+
+
+ if (ret != 0) {
+ memset((void*) ret, 0, size);
+ uncached = ret+XCHAL_KSEG_BYPASS_VADDR-XCHAL_KSEG_CACHED_VADDR;
+ *handle = virt_to_bus((void*)ret);
+ __flush_invalidate_dcache_range(ret, size);
}
- return (void*) BYPASS_ADDR((unsigned long)ret);
+
+ return (void*)uncached;
}
void dma_free_coherent(struct device *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
- free_pages(CACHED_ADDR((unsigned long)vaddr), get_order(size));
+ long addr=(long)vaddr+XCHAL_KSEG_CACHED_VADDR-XCHAL_KSEG_BYPASS_VADDR;
+
+ if (addr < 0 || addr >= XCHAL_KSEG_SIZE)
+ BUG();
+
+ free_pages(addr, get_order(size));
}
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index a7c4178c2a8..795bd5ac6f4 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -1,4 +1,3 @@
-// TODO verify coprocessor handling
/*
* arch/xtensa/kernel/process.c
*
@@ -43,7 +42,7 @@
#include <asm/irq.h>
#include <asm/atomic.h>
#include <asm/asm-offsets.h>
-#include <asm/coprocessor.h>
+#include <asm/regs.h>
extern void ret_from_fork(void);
@@ -67,25 +66,6 @@ void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
-#if XCHAL_CP_NUM > 0
-
-/*
- * Coprocessor ownership.
- */
-
-coprocessor_info_t coprocessor_info[] = {
- { 0, XTENSA_CPE_CP0_OFFSET },
- { 0, XTENSA_CPE_CP1_OFFSET },
- { 0, XTENSA_CPE_CP2_OFFSET },
- { 0, XTENSA_CPE_CP3_OFFSET },
- { 0, XTENSA_CPE_CP4_OFFSET },
- { 0, XTENSA_CPE_CP5_OFFSET },
- { 0, XTENSA_CPE_CP6_OFFSET },
- { 0, XTENSA_CPE_CP7_OFFSET },
-};
-
-#endif
-
/*
* Powermanagement idle function, if any is provided by the platform.
*/
@@ -110,12 +90,10 @@ void cpu_idle(void)
void exit_thread(void)
{
- release_coprocessors(current); /* Empty macro if no CPs are defined */
}
void flush_thread(void)
{
- release_coprocessors(current); /* Empty macro if no CPs are defined */
}
/*
@@ -183,36 +161,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
/*
- * Create a kernel thread
- */
-
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- long retval;
- __asm__ __volatile__
- ("mov a5, %4\n\t" /* preserve fn in a5 */
- "mov a6, %3\n\t" /* preserve and setup arg in a6 */
- "movi a2, %1\n\t" /* load __NR_clone for syscall*/
- "mov a3, sp\n\t" /* sp check and sys_clone */
- "mov a4, %5\n\t" /* load flags for syscall */
- "syscall\n\t"
- "beq a3, sp, 1f\n\t" /* branch if parent */
- "callx4 a5\n\t" /* call fn */
- "movi a2, %2\n\t" /* load __NR_exit for syscall */
- "mov a3, a6\n\t" /* load fn return value */
- "syscall\n"
- "1:\n\t"
- "mov %0, a2\n\t" /* parent returns zero */
- :"=r" (retval)
- :"i" (__NR_clone), "i" (__NR_exit),
- "r" (arg), "r" (fn),
- "r" (flags | CLONE_VM)
- : "a2", "a3", "a4", "a5", "a6" );
- return retval;
-}
-
-
-/*
* These bracket the sleeping functions..
*/
@@ -275,7 +223,7 @@ void do_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
*/
elfregs->pc = regs->pc;
- elfregs->ps = (regs->ps & ~XCHAL_PS_EXCM_MASK);
+ elfregs->ps = (regs->ps & ~(1 << PS_EXCM_BIT));
elfregs->exccause = regs->exccause;
elfregs->excvaddr = regs->excvaddr;
elfregs->windowbase = regs->windowbase;
@@ -325,7 +273,7 @@ void do_restore_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
*/
regs->pc = elfregs->pc;
- regs->ps = (elfregs->ps | XCHAL_PS_EXCM_MASK);
+ regs->ps = (elfregs->ps | (1 << PS_EXCM_BIT));
regs->exccause = elfregs->exccause;
regs->excvaddr = elfregs->excvaddr;
regs->windowbase = elfregs->windowbase;
@@ -459,16 +407,7 @@ int do_restore_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs,
int
dump_task_fpu(struct pt_regs *regs, struct task_struct *task, elf_fpregset_t *r)
{
-/* see asm/coprocessor.h for this magic number 16 */
-#if XTENSA_CP_EXTRA_SIZE > 16
- do_save_fpregs (r, regs, task);
-
- /* For now, bit 16 means some extra state may be present: */
-// FIXME!! need to track to return more accurate mask
- return 0x10000 | XCHAL_CP_MASK;
-#else
return 0; /* no coprocessors active on this processor */
-#endif
}
/*
@@ -483,3 +422,44 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
{
return dump_task_fpu(regs, current, r);
}
+
+asmlinkage
+long xtensa_clone(unsigned long clone_flags, unsigned long newsp,
+ void __user *parent_tid, void *child_tls,
+ void __user *child_tid, long a5,
+ struct pt_regs *regs)
+{
+ if (!newsp)
+ newsp = regs->areg[1];
+ return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
+}
+
+/*
+ * * xtensa_execve() executes a new program.
+ * */
+
+asmlinkage
+long xtensa_execve(char __user *name, char __user * __user *argv,
+ char __user * __user *envp,
+ long a3, long a4, long a5,
+ struct pt_regs *regs)
+{
+ long error;
+ char * filename;
+
+ filename = getname(name);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ goto out;
+ // FIXME: release coprocessor??
+ error = do_execve(filename, argv, envp, regs);
+ if (error == 0) {
+ task_lock(current);
+ current->ptrace &= ~PT_DTRACE;
+ task_unlock(current);
+ }
+ putname(filename);
+out:
+ return error;
+}
+
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index 9aea23cc0dc..8b6d3d0623b 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -96,7 +96,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* Note: PS.EXCM is not set while user task is running;
* its being set in regs is for exception handling
* convenience. */
- tmp = (regs->ps & ~XCHAL_PS_EXCM_MASK);
+ tmp = (regs->ps & ~(1 << PS_EXCM_BIT));
break;
case REG_WB:
tmp = regs->windowbase;
@@ -332,12 +332,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
void do_syscall_trace(void)
{
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
-
- if (!(current->ptrace & PT_PTRACED))
- return;
-
/*
* The 0x80 provides a way for the tracing parent to distinguish
* between a syscall stop and SIGTRAP delivery
@@ -354,3 +348,23 @@ void do_syscall_trace(void)
current->exit_code = 0;
}
}
+
+void do_syscall_trace_enter(struct pt_regs *regs)
+{
+ if (test_thread_flag(TIF_SYSCALL_TRACE)
+ && (current->ptrace & PT_PTRACED))
+ do_syscall_trace();
+
+#if 0
+ if (unlikely(current->audit_context))
+ audit_syscall_entry(current, AUDIT_ARCH_XTENSA..);
+#endif
+}
+
+void do_syscall_trace_leave(struct pt_regs *regs)
+{
+ if ((test_thread_flag(TIF_SYSCALL_TRACE))
+ && (current->ptrace & PT_PTRACED))
+ do_syscall_trace();
+}
+
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index c99ab72b41b..b6374c09de2 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -42,8 +42,6 @@
#include <asm/page.h>
#include <asm/setup.h>
-#include <xtensa/config/system.h>
-
#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
#endif
@@ -336,7 +334,7 @@ c_show(struct seq_file *f, void *slot)
/* high-level stuff */
seq_printf(f,"processor\t: 0\n"
"vendor_id\t: Tensilica\n"
- "model\t\t: Xtensa " XCHAL_HW_RELEASE_NAME "\n"
+ "model\t\t: Xtensa " XCHAL_HW_VERSION_NAME "\n"
"core ID\t\t: " XCHAL_CORE_ID "\n"
"build ID\t: 0x%x\n"
"byte order\t: %s\n"
@@ -420,25 +418,6 @@ c_show(struct seq_file *f, void *slot)
XCHAL_NUM_TIMERS,
XCHAL_DEBUGLEVEL);
- /* Coprocessors */
-#if XCHAL_HAVE_CP
- seq_printf(f, "coprocessors\t: %d\n", XCHAL_CP_NUM);
-#else
- seq_printf(f, "coprocessors\t: none\n");
-#endif
-
- /* {I,D}{RAM,ROM} and XLMI */
- seq_printf(f,"inst ROMs\t: %d\n"
- "inst RAMs\t: %d\n"
- "data ROMs\t: %d\n"
- "data RAMs\t: %d\n"
- "XLMI ports\t: %d\n",
- XCHAL_NUM_IROM,
- XCHAL_NUM_IRAM,
- XCHAL_NUM_DROM,
- XCHAL_NUM_DRAM,
- XCHAL_NUM_XLMI);
-
/* Cache */
seq_printf(f,"icache line size: %d\n"
"icache ways\t: %d\n"
@@ -466,24 +445,6 @@ c_show(struct seq_file *f, void *slot)
XCHAL_DCACHE_WAYS,
XCHAL_DCACHE_SIZE);
- /* MMU */
- seq_printf(f,"ASID bits\t: %d\n"
- "ASID invalid\t: %d\n"
- "ASID kernel\t: %d\n"
- "rings\t\t: %d\n"
- "itlb ways\t: %d\n"
- "itlb AR ways\t: %d\n"
- "dtlb ways\t: %d\n"
- "dtlb AR ways\t: %d\n",
- XCHAL_MMU_ASID_BITS,
- XCHAL_MMU_ASID_INVALID,
- XCHAL_MMU_ASID_KERNEL,
- XCHAL_MMU_RINGS,
- XCHAL_ITLB_WAYS,
- XCHAL_ITLB_ARF_WAYS,
- XCHAL_DTLB_WAYS,
- XCHAL_DTLB_ARF_WAYS);
-
return 0;
}
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index c494f0826fc..c6d9880a4cd 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -12,8 +12,8 @@
*
*/
-#include <xtensa/config/core.h>
-#include <xtensa/hal.h>
+#include <asm/variant/core.h>
+#include <asm/coprocessor.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
@@ -46,7 +46,7 @@ extern struct task_struct *coproc_owners[];
* Atomically swap in the new signal mask, and wait for a signal.
*/
-int sys_sigsuspend(struct pt_regs *regs)
+int xtensa_sigsuspend(struct pt_regs *regs)
{
old_sigset_t mask = (old_sigset_t) regs->areg[3];
sigset_t saveset;
@@ -68,7 +68,7 @@ int sys_sigsuspend(struct pt_regs *regs)
}
asmlinkage int
-sys_rt_sigsuspend(struct pt_regs *regs)
+xtensa_rt_sigsuspend(struct pt_regs *regs)
{
sigset_t *unewset = (sigset_t *) regs->areg[4];
size_t sigsetsize = (size_t) regs->areg[3];
@@ -96,7 +96,7 @@ sys_rt_sigsuspend(struct pt_regs *regs)
}
asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction *act,
+xtensa_sigaction(int sig, const struct old_sigaction *act,
struct old_sigaction *oact)
{
struct k_sigaction new_ka, old_ka;
@@ -128,7 +128,7 @@ sys_sigaction(int sig, const struct old_sigaction *act,
}
asmlinkage int
-sys_sigaltstack(struct pt_regs *regs)
+xtensa_sigaltstack(struct pt_regs *regs)
{
const stack_t *uss = (stack_t *) regs->areg[4];
stack_t *uoss = (stack_t *) regs->areg[3];
@@ -216,8 +216,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
* handler, or the user mode value doesn't matter (e.g. PS.OWB).
*/
err |= __get_user(ps, &sc->sc_ps);
- regs->ps = (regs->ps & ~XCHAL_PS_CALLINC_MASK)
- | (ps & XCHAL_PS_CALLINC_MASK);
+ regs->ps = (regs->ps & ~PS_CALLINC_MASK)
+ | (ps & PS_CALLINC_MASK);
/* Additional corruption checks */
@@ -280,7 +280,7 @@ flush_my_cpstate(struct task_struct *tsk)
static int
save_cpextra (struct _cpstate *buf)
{
-#if (XCHAL_EXTRA_SA_SIZE == 0) && (XCHAL_CP_NUM == 0)
+#if XCHAL_CP_NUM == 0
return 0;
#else
@@ -350,7 +350,7 @@ setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate,
return err;
}
-asmlinkage int sys_sigreturn(struct pt_regs *regs)
+asmlinkage int xtensa_sigreturn(struct pt_regs *regs)
{
struct sigframe *frame = (struct sigframe *)regs->areg[1];
sigset_t set;
@@ -382,7 +382,7 @@ badframe:
return 0;
}
-asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+asmlinkage int xtensa_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1];
sigset_t set;
@@ -497,8 +497,10 @@ gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn)
/* Flush generated code out of the data cache */
- if (err == 0)
- __flush_invalidate_cache_range((unsigned long)codemem, 6UL);
+ if (err == 0) {
+ __invalidate_icache_range((unsigned long)codemem, 6UL);
+ __flush_invalidate_dcache_range((unsigned long)codemem, 6UL);
+ }
return err;
}
diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c
new file mode 100644
index 00000000000..fe3834bc1db
--- /dev/null
+++ b/arch/xtensa/kernel/syscall.c
@@ -0,0 +1,95 @@
+/*
+ * arch/xtensa/kernel/syscall.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.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1995 - 2000 by Ralf Baechle
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Chris Zankel <chris@zankel.net>
+ * Kevin Chea
+ *
+ */
+#include <asm/uaccess.h>
+#include <asm/syscall.h>
+#include <asm/unistd.h>
+#include <linux/linkage.h>
+#include <linux/stringify.h>
+#include <linux/errno.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/mman.h>
+#include <linux/shm.h>
+
+typedef void (*syscall_t)(void);
+
+syscall_t sys_call_table[__NR_syscall_count] /* FIXME __cacheline_aligned */= {
+ [0 ... __NR_syscall_count - 1] = (syscall_t)&sys_ni_syscall,
+
+#undef __SYSCALL
+#define __SYSCALL(nr,symbol,nargs) [ nr ] = (syscall_t)symbol,
+#undef _XTENSA_UNISTD_H
+#undef __KERNEL_SYSCALLS__
+#include <asm/unistd.h>
+};
+
+/*
+ * xtensa_pipe() is the normal C calling standard for creating a pipe. It's not
+ * the way unix traditional does this, though.
+ */
+
+asmlinkage long xtensa_pipe(int __user *userfds)
+{
+ int fd[2];
+ int error;
+
+ error = do_pipe(fd);
+ if (!error) {
+ if (copy_to_user(userfds, fd, 2 * sizeof(int)))
+ error = -EFAULT;
+ }
+ return error;
+}
+
+
+asmlinkage long xtensa_mmap2(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+{
+ int error = -EBADF;
+ struct file * file = NULL;
+
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ if (!(flags & MAP_ANONYMOUS)) {
+ file = fget(fd);
+ if (!file)
+ goto out;
+ }
+
+ down_write(&current->mm->mmap_sem);
+ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+ up_write(&current->mm->mmap_sem);
+
+ if (file)
+ fput(file);
+out:
+ return error;
+}
+
+asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
+{
+ unsigned long ret;
+ long err;
+
+ err = do_shmat(shmid, shmaddr, shmflg, &ret);
+ if (err)
+ return err;
+ return (long)ret;
+}
+
diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c
deleted file mode 100644
index f49cb239e60..00000000000
--- a/arch/xtensa/kernel/syscalls.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * 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
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- * Copyright (C) 2000 Silicon Graphics, Inc.
- * Copyright (C) 1995 - 2000 by Ralf Baechle
- *
- * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
- * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
- * Chris Zankel <chris@zankel.net>
- * Kevin Chea
- *
- */
-
-#define DEBUG 0
-
-#include <linux/linkage.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/mman.h>
-#include <linux/sched.h>
-#include <linux/file.h>
-#include <linux/slab.h>
-#include <linux/utsname.h>
-#include <linux/unistd.h>
-#include <linux/stringify.h>
-#include <linux/syscalls.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/errno.h>
-#include <asm/ptrace.h>
-#include <asm/signal.h>
-#include <asm/uaccess.h>
-#include <asm/hardirq.h>
-#include <asm/mman.h>
-#include <asm/shmparam.h>
-#include <asm/page.h>
-
-extern void do_syscall_trace(void);
-typedef int (*syscall_t)(void *a0,...);
-extern syscall_t sys_call_table[];
-extern unsigned char sys_narg_table[];
-
-/*
- * sys_pipe() is the normal C calling standard for creating a pipe. It's not
- * the way unix traditional does this, though.
- */
-
-int sys_pipe(int __user *userfds)
-{
- int fd[2];
- int error;
-
- error = do_pipe(fd);
- if (!error) {
- if (copy_to_user(userfds, fd, 2 * sizeof(int)))
- error = -EFAULT;
- }
- return error;
-}
-
-/*
- * Common code for old and new mmaps.
- */
-long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot,
- unsigned long flags, unsigned long fd, unsigned long pgoff)
-{
- int error = -EBADF;
- struct file * file = NULL;
-
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- if (!(flags & MAP_ANONYMOUS)) {
- file = fget(fd);
- if (!file)
- goto out;
- }
-
- down_write(&current->mm->mmap_sem);
- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
- up_write(&current->mm->mmap_sem);
-
- if (file)
- fput(file);
-out:
- return error;
-}
-
-int sys_clone(struct pt_regs *regs)
-{
- unsigned long clone_flags;
- unsigned long newsp;
- int __user *parent_tidptr, *child_tidptr;
- clone_flags = regs->areg[4];
- newsp = regs->areg[3];
- parent_tidptr = (int __user *)regs->areg[5];
- child_tidptr = (int __user *)regs->areg[6];
- if (!newsp)
- newsp = regs->areg[1];
- return do_fork(clone_flags,newsp,regs,0,parent_tidptr,child_tidptr);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-
-int sys_execve(struct pt_regs *regs)
-{
- int error;
- char * filename;
-
- filename = getname((char *) (long)regs->areg[5]);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename, (char **) (long)regs->areg[3],
- (char **) (long)regs->areg[4], regs);
- putname(filename);
-
-out:
- return error;
-}
-
-int sys_uname(struct old_utsname * name)
-{
- if (name && !copy_to_user(name, utsname(), sizeof (*name)))
- return 0;
- return -EFAULT;
-}
-
-/*
- * Build the string table for the builtin "poor man's strace".
- */
-
-#if DEBUG
-#define SYSCALL(fun, narg) #fun,
-static char *sfnames[] = {
-#include "syscalls.h"
-};
-#undef SYS
-#endif
-
-void system_call (struct pt_regs *regs)
-{
- syscall_t syscall;
- unsigned long parm0, parm1, parm2, parm3, parm4, parm5;
- int nargs, res;
- unsigned int syscallnr;
- int ps;
-
-#if DEBUG
- int i;
- unsigned long parms[6];
- char *sysname;
-#endif
-
- regs->syscall = regs->areg[2];
-
- do_syscall_trace();
-
- /* Have to load after syscall_trace because strace
- * sometimes changes regs->syscall.
- */
- syscallnr = regs->syscall;
-
- parm0 = parm1 = parm2 = parm3 = parm4 = parm5 = 0;
-
- /* Restore interrupt level to syscall invoker's.
- * If this were in assembly, we wouldn't disable
- * interrupts in the first place:
- */
- local_save_flags (ps);
- local_irq_restore((ps & ~XCHAL_PS_INTLEVEL_MASK) |
- (regs->ps & XCHAL_PS_INTLEVEL_MASK) );
-
- if (syscallnr > __NR_Linux_syscalls) {
- regs->areg[2] = -ENOSYS;
- return;
- }
-
- syscall = sys_call_table[syscallnr];
- nargs = sys_narg_table[syscallnr];
-
- if (syscall == NULL) {
- regs->areg[2] = -ENOSYS;
- return;
- }
-
- /* There shouldn't be more than six arguments in the table! */
-
- if (nargs > 6)
- panic("Internal error - too many syscall arguments (%d)!\n",
- nargs);
-
- /* Linux takes system-call arguments in registers. The ABI
- * and Xtensa software conventions require the system-call
- * number in a2. If an argument exists in a2, we move it to
- * the next available register. Note that for improved
- * efficiency, we do NOT shift all parameters down one
- * register to maintain the original order.
- *
- * At best case (zero arguments), we just write the syscall
- * number to a2. At worst case (1 to 6 arguments), we move
- * the argument in a2 to the next available register, then
- * write the syscall number to a2.
- *
- * For clarity, the following truth table enumerates all
- * possibilities.
- *
- * arguments syscall number arg0, arg1, arg2, arg3, arg4, arg5
- * --------- -------------- ----------------------------------
- * 0 a2
- * 1 a2 a3
- * 2 a2 a4, a3
- * 3 a2 a5, a3, a4
- * 4 a2 a6, a3, a4, a5
- * 5 a2 a7, a3, a4, a5, a6
- * 6 a2 a8, a3, a4, a5, a6, a7
- */
- if (nargs) {
- parm0 = regs->areg[nargs+2];
- parm1 = regs->areg[3];
- parm2 = regs->areg[4];
- parm3 = regs->areg[5];
- parm4 = regs->areg[6];
- parm5 = regs->areg[7];
- } else /* nargs == 0 */
- parm0 = (unsigned long) regs;
-
-#if DEBUG
- parms[0] = parm0;
- parms[1] = parm1;
- parms[2] = parm2;
- parms[3] = parm3;
- parms[4] = parm4;
- parms[5] = parm5;
-
- sysname = sfnames[syscallnr];
- if (strncmp(sysname, "sys_", 4) == 0)
- sysname = sysname + 4;
-
- printk("\017SYSCALL:I:%x:%d:%s %s(", regs->pc, current->pid,
- current->comm, sysname);
- for (i = 0; i < nargs; i++)
- printk((i>0) ? ", %#lx" : "%#lx", parms[i]);
- printk(")\n");
-#endif
-
- res = syscall((void *)parm0, parm1, parm2, parm3, parm4, parm5);
-
-#if DEBUG
- printk("\017SYSCALL:O:%d:%s %s(",current->pid, current->comm, sysname);
- for (i = 0; i < nargs; i++)
- printk((i>0) ? ", %#lx" : "%#lx", parms[i]);
- if (res < 4096)
- printk(") = %d\n", res);
- else
- printk(") = %#x\n", res);
-#endif /* DEBUG */
-
- 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/syscalls.h b/arch/xtensa/kernel/syscalls.h
deleted file mode 100644
index 216c10a3150..00000000000
--- a/arch/xtensa/kernel/syscalls.h
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * arch/xtensa/kernel/syscalls.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- *
- * Changes by Joe Taylor <joe@tensilica.com>
- */
-
-/*
- * This file is being included twice - once to build a list of all
- * syscalls and once to build a table of how many arguments each syscall
- * accepts. Syscalls that receive a pointer to the saved registers are
- * marked as having zero arguments.
- *
- * The binary compatibility calls are in a separate list.
- *
- * Entry '0' used to be system_call. It's removed to disable indirect
- * system calls for now so user tasks can't recurse. See mips'
- * sys_syscall for a comparable example.
- */
-
-SYSCALL(0, 0) /* 00 */
-SYSCALL(sys_exit, 1)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_read, 3)
-SYSCALL(sys_write, 3)
-SYSCALL(sys_open, 3) /* 05 */
-SYSCALL(sys_close, 1)
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_creat, 2)
-SYSCALL(sys_link, 2)
-SYSCALL(sys_unlink, 1) /* 10 */
-SYSCALL(sys_execve, 0)
-SYSCALL(sys_chdir, 1)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_mknod, 3)
-SYSCALL(sys_chmod, 2) /* 15 */
-SYSCALL(sys_lchown, 3)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_newstat, 2)
-SYSCALL(sys_lseek, 3)
-SYSCALL(sys_getpid, 0) /* 20 */
-SYSCALL(sys_mount, 5)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_setuid, 1)
-SYSCALL(sys_getuid, 0)
-SYSCALL(sys_ni_syscall, 1) /* 25 */
-SYSCALL(sys_ptrace, 4)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_newfstat, 2)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_utime, 2) /* 30 */
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_access, 2)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_ni_syscall, 0) /* 35 */
-SYSCALL(sys_sync, 0)
-SYSCALL(sys_kill, 2)
-SYSCALL(sys_rename, 2)
-SYSCALL(sys_mkdir, 2)
-SYSCALL(sys_rmdir, 1) /* 40 */
-SYSCALL(sys_dup, 1)
-SYSCALL(sys_pipe, 1)
-SYSCALL(sys_times, 1)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_brk, 1) /* 45 */
-SYSCALL(sys_setgid, 1)
-SYSCALL(sys_getgid, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_geteuid, 0)
-SYSCALL(sys_getegid, 0) /* 50 */
-SYSCALL(sys_acct, 1)
-SYSCALL(sys_umount, 2)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ioctl, 3)
-SYSCALL(sys_fcntl, 3) /* 55 */
-SYSCALL(sys_ni_syscall, 2)
-SYSCALL(sys_setpgid, 2)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_umask, 1) /* 60 */
-SYSCALL(sys_chroot, 1)
-SYSCALL(sys_ustat, 2)
-SYSCALL(sys_dup2, 2)
-SYSCALL(sys_getppid, 0)
-SYSCALL(sys_ni_syscall, 0) /* 65 */
-SYSCALL(sys_setsid, 0)
-SYSCALL(sys_sigaction, 3)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_setreuid, 2) /* 70 */
-SYSCALL(sys_setregid, 2)
-SYSCALL(sys_sigsuspend, 0)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_sethostname, 2)
-SYSCALL(sys_setrlimit, 2) /* 75 */
-SYSCALL(sys_getrlimit, 2)
-SYSCALL(sys_getrusage, 2)
-SYSCALL(sys_gettimeofday, 2)
-SYSCALL(sys_settimeofday, 2)
-SYSCALL(sys_getgroups, 2) /* 80 */
-SYSCALL(sys_setgroups, 2)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_symlink, 2)
-SYSCALL(sys_newlstat, 2)
-SYSCALL(sys_readlink, 3) /* 85 */
-SYSCALL(sys_uselib, 1)
-SYSCALL(sys_swapon, 2)
-SYSCALL(sys_reboot, 3)
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_ni_syscall, 6) /* 90 */
-SYSCALL(sys_munmap, 2)
-SYSCALL(sys_truncate, 2)
-SYSCALL(sys_ftruncate, 2)
-SYSCALL(sys_fchmod, 2)
-SYSCALL(sys_fchown, 3) /* 95 */
-SYSCALL(sys_getpriority, 2)
-SYSCALL(sys_setpriority, 3)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_statfs, 2)
-SYSCALL(sys_fstatfs, 2) /* 100 */
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_ni_syscall, 2)
-SYSCALL(sys_syslog, 3)
-SYSCALL(sys_setitimer, 3)
-SYSCALL(sys_getitimer, 2) /* 105 */
-SYSCALL(sys_newstat, 2)
-SYSCALL(sys_newlstat, 2)
-SYSCALL(sys_newfstat, 2)
-SYSCALL(sys_uname, 1)
-SYSCALL(sys_ni_syscall, 0) /* 110 */
-SYSCALL(sys_vhangup, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_wait4, 4)
-SYSCALL(sys_swapoff, 1) /* 115 */
-SYSCALL(sys_sysinfo, 1)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_fsync, 1)
-SYSCALL(sys_sigreturn, 0)
-SYSCALL(sys_clone, 0) /* 120 */
-SYSCALL(sys_setdomainname, 2)
-SYSCALL(sys_newuname, 1)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_adjtimex, 1)
-SYSCALL(sys_mprotect, 3) /* 125 */
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_ni_syscall, 2)
-SYSCALL(sys_init_module, 2)
-SYSCALL(sys_delete_module, 1)
-SYSCALL(sys_ni_syscall, 1) /* 130 */
-SYSCALL(sys_quotactl, 0)
-SYSCALL(sys_getpgid, 1)
-SYSCALL(sys_fchdir, 1)
-SYSCALL(sys_bdflush, 2)
-SYSCALL(sys_sysfs, 3) /* 135 */
-SYSCALL(sys_personality, 1)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_setfsuid, 1)
-SYSCALL(sys_setfsgid, 1)
-SYSCALL(sys_llseek, 5) /* 140 */
-SYSCALL(sys_getdents, 3)
-SYSCALL(sys_select, 5)
-SYSCALL(sys_flock, 2)
-SYSCALL(sys_msync, 3)
-SYSCALL(sys_readv, 3) /* 145 */
-SYSCALL(sys_writev, 3)
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_ni_syscall, 4) /* handled in fast syscall handler. */
-SYSCALL(sys_ni_syscall, 0) /* 150 */
-SYSCALL(sys_getsid, 1)
-SYSCALL(sys_fdatasync, 1)
-SYSCALL(sys_sysctl, 1)
-SYSCALL(sys_mlock, 2)
-SYSCALL(sys_munlock, 2) /* 155 */
-SYSCALL(sys_mlockall, 1)
-SYSCALL(sys_munlockall, 0)
-SYSCALL(sys_sched_setparam,2)
-SYSCALL(sys_sched_getparam,2)
-SYSCALL(sys_sched_setscheduler,3) /* 160 */
-SYSCALL(sys_sched_getscheduler,1)
-SYSCALL(sys_sched_yield,0)
-SYSCALL(sys_sched_get_priority_max,1)
-SYSCALL(sys_sched_get_priority_min,1)
-SYSCALL(sys_sched_rr_get_interval,2) /* 165 */
-SYSCALL(sys_nanosleep,2)
-SYSCALL(sys_mremap,4)
-SYSCALL(sys_accept, 3)
-SYSCALL(sys_bind, 3)
-SYSCALL(sys_connect, 3) /* 170 */
-SYSCALL(sys_getpeername, 3)
-SYSCALL(sys_getsockname, 3)
-SYSCALL(sys_getsockopt, 5)
-SYSCALL(sys_listen, 2)
-SYSCALL(sys_recv, 4) /* 175 */
-SYSCALL(sys_recvfrom, 6)
-SYSCALL(sys_recvmsg, 3)
-SYSCALL(sys_send, 4)
-SYSCALL(sys_sendmsg, 3)
-SYSCALL(sys_sendto, 6) /* 180 */
-SYSCALL(sys_setsockopt, 5)
-SYSCALL(sys_shutdown, 2)
-SYSCALL(sys_socket, 3)
-SYSCALL(sys_socketpair, 4)
-SYSCALL(sys_setresuid, 3) /* 185 */
-SYSCALL(sys_getresuid, 3)
-SYSCALL(sys_ni_syscall, 5)
-SYSCALL(sys_poll, 3)
-SYSCALL(sys_nfsservctl, 3)
-SYSCALL(sys_setresgid, 3) /* 190 */
-SYSCALL(sys_getresgid, 3)
-SYSCALL(sys_prctl, 5)
-SYSCALL(sys_rt_sigreturn, 0)
-SYSCALL(sys_rt_sigaction, 4)
-SYSCALL(sys_rt_sigprocmask, 4) /* 195 */
-SYSCALL(sys_rt_sigpending, 2)
-SYSCALL(sys_rt_sigtimedwait, 4)
-SYSCALL(sys_rt_sigqueueinfo, 3)
-SYSCALL(sys_rt_sigsuspend, 0)
-SYSCALL(sys_pread64, 5) /* 200 */
-SYSCALL(sys_pwrite64, 5)
-SYSCALL(sys_chown, 3)
-SYSCALL(sys_getcwd, 2)
-SYSCALL(sys_capget, 2)
-SYSCALL(sys_capset, 2) /* 205 */
-SYSCALL(sys_sigaltstack, 0)
-SYSCALL(sys_sendfile, 4)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_mmap, 6) /* 210 */
-SYSCALL(sys_truncate64, 2)
-SYSCALL(sys_ftruncate64, 2)
-SYSCALL(sys_stat64, 2)
-SYSCALL(sys_lstat64, 2)
-SYSCALL(sys_fstat64, 2) /* 215 */
-SYSCALL(sys_pivot_root, 2)
-SYSCALL(sys_mincore, 3)
-SYSCALL(sys_madvise, 3)
-SYSCALL(sys_getdents64, 3)
-SYSCALL(sys_ni_syscall, 0) /* 220 */
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index 37347e36998..a350431363a 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -47,7 +47,7 @@ unsigned long long sched_clock(void)
return (unsigned long long)jiffies * (1000000000 / HZ);
}
-static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t timer_interrupt(int irq, void *dev_id);
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
.flags = IRQF_DISABLED,
@@ -150,7 +150,7 @@ EXPORT_SYMBOL(do_gettimeofday);
* The timer interrupt is called HZ times per second.
*/
-irqreturn_t timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t timer_interrupt (int irq, void *dev_id)
{
unsigned long next;
@@ -160,9 +160,9 @@ irqreturn_t timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
again:
while ((signed long)(get_ccount() - next) > 0) {
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
write_seqlock(&xtime_lock);
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
index ce077d6bf3a..693ab268485 100644
--- a/arch/xtensa/kernel/traps.c
+++ b/arch/xtensa/kernel/traps.c
@@ -75,7 +75,7 @@ extern void system_call (struct pt_regs*);
#define USER 0x02
#define COPROCESSOR(x) \
-{ XCHAL_EXCCAUSE_COPROCESSOR ## x ## _DISABLED, USER, fast_coprocessor }
+{ EXCCAUSE_COPROCESSOR ## x ## _DISABLED, USER, fast_coprocessor }
typedef struct {
int cause;
@@ -85,38 +85,38 @@ typedef struct {
dispatch_init_table_t __init dispatch_init_table[] = {
-{ XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION, 0, do_illegal_instruction},
-{ XCHAL_EXCCAUSE_SYSTEM_CALL, KRNL, fast_syscall_kernel },
-{ XCHAL_EXCCAUSE_SYSTEM_CALL, USER, fast_syscall_user },
-{ XCHAL_EXCCAUSE_SYSTEM_CALL, 0, system_call },
-/* XCHAL_EXCCAUSE_INSTRUCTION_FETCH unhandled */
-/* XCHAL_EXCCAUSE_LOAD_STORE_ERROR unhandled*/
-{ XCHAL_EXCCAUSE_LEVEL1_INTERRUPT, 0, do_interrupt },
-{ XCHAL_EXCCAUSE_ALLOCA, USER|KRNL, fast_alloca },
-/* XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO unhandled */
-/* XCHAL_EXCCAUSE_PRIVILEGED unhandled */
+{ EXCCAUSE_ILLEGAL_INSTRUCTION, 0, do_illegal_instruction},
+{ EXCCAUSE_SYSTEM_CALL, KRNL, fast_syscall_kernel },
+{ EXCCAUSE_SYSTEM_CALL, USER, fast_syscall_user },
+{ EXCCAUSE_SYSTEM_CALL, 0, system_call },
+/* EXCCAUSE_INSTRUCTION_FETCH unhandled */
+/* EXCCAUSE_LOAD_STORE_ERROR unhandled*/
+{ EXCCAUSE_LEVEL1_INTERRUPT, 0, do_interrupt },
+{ EXCCAUSE_ALLOCA, USER|KRNL, fast_alloca },
+/* EXCCAUSE_INTEGER_DIVIDE_BY_ZERO unhandled */
+/* EXCCAUSE_PRIVILEGED unhandled */
#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
#ifdef CONFIG_UNALIGNED_USER
-{ XCHAL_EXCCAUSE_UNALIGNED, USER, fast_unaligned },
+{ EXCCAUSE_UNALIGNED, USER, fast_unaligned },
#else
-{ XCHAL_EXCCAUSE_UNALIGNED, 0, do_unaligned_user },
+{ EXCCAUSE_UNALIGNED, 0, do_unaligned_user },
#endif
-{ XCHAL_EXCCAUSE_UNALIGNED, KRNL, fast_unaligned },
+{ EXCCAUSE_UNALIGNED, KRNL, fast_unaligned },
#endif
-{ XCHAL_EXCCAUSE_ITLB_MISS, 0, do_page_fault },
-{ XCHAL_EXCCAUSE_ITLB_MISS, USER|KRNL, fast_second_level_miss},
-{ XCHAL_EXCCAUSE_ITLB_MULTIHIT, 0, do_multihit },
-{ XCHAL_EXCCAUSE_ITLB_PRIVILEGE, 0, do_page_fault },
-/* XCHAL_EXCCAUSE_SIZE_RESTRICTION unhandled */
-{ XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE, 0, do_page_fault },
-{ XCHAL_EXCCAUSE_DTLB_MISS, USER|KRNL, fast_second_level_miss},
-{ XCHAL_EXCCAUSE_DTLB_MISS, 0, do_page_fault },
-{ XCHAL_EXCCAUSE_DTLB_MULTIHIT, 0, do_multihit },
-{ XCHAL_EXCCAUSE_DTLB_PRIVILEGE, 0, do_page_fault },
-/* XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION unhandled */
-{ XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE, USER|KRNL, fast_store_prohibited },
-{ XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE, 0, do_page_fault },
-{ XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE, 0, do_page_fault },
+{ EXCCAUSE_ITLB_MISS, 0, do_page_fault },
+{ EXCCAUSE_ITLB_MISS, USER|KRNL, fast_second_level_miss},
+{ EXCCAUSE_ITLB_MULTIHIT, 0, do_multihit },
+{ EXCCAUSE_ITLB_PRIVILEGE, 0, do_page_fault },
+/* EXCCAUSE_SIZE_RESTRICTION unhandled */
+{ EXCCAUSE_FETCH_CACHE_ATTRIBUTE, 0, do_page_fault },
+{ EXCCAUSE_DTLB_MISS, USER|KRNL, fast_second_level_miss},
+{ EXCCAUSE_DTLB_MISS, 0, do_page_fault },
+{ EXCCAUSE_DTLB_MULTIHIT, 0, do_multihit },
+{ EXCCAUSE_DTLB_PRIVILEGE, 0, do_page_fault },
+/* EXCCAUSE_DTLB_SIZE_RESTRICTION unhandled */
+{ EXCCAUSE_STORE_CACHE_ATTRIBUTE, USER|KRNL, fast_store_prohibited },
+{ EXCCAUSE_STORE_CACHE_ATTRIBUTE, 0, do_page_fault },
+{ EXCCAUSE_LOAD_CACHE_ATTRIBUTE, 0, do_page_fault },
/* XCCHAL_EXCCAUSE_FLOATING_POINT unhandled */
#if (XCHAL_CP_MASK & 1)
COPROCESSOR(0),
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S
index 0e74397bfa2..eb2d7bb69ee 100644
--- a/arch/xtensa/kernel/vectors.S
+++ b/arch/xtensa/kernel/vectors.S
@@ -53,6 +53,8 @@
#include <asm/thread_info.h>
#include <asm/processor.h>
+#define WINDOW_VECTORS_SIZE 0x180
+
/*
* User exception vector. (Exceptions with PS.UM == 1, PS.EXCM == 0)
@@ -210,7 +212,7 @@ ENTRY(_DoubleExceptionVector)
/* Check for kernel double exception (usually fatal). */
rsr a3, PS
- _bbci.l a3, PS_UM_SHIFT, .Lksp
+ _bbci.l a3, PS_UM_BIT, .Lksp
/* Check if we are currently handling a window exception. */
/* Note: We don't need to indicate that we enter a critical section. */
@@ -219,7 +221,7 @@ ENTRY(_DoubleExceptionVector)
movi a3, XCHAL_WINDOW_VECTORS_VADDR
_bltu a0, a3, .Lfixup
- addi a3, a3, XSHAL_WINDOW_VECTORS_SIZE
+ addi a3, a3, WINDOW_VECTORS_SIZE
_bgeu a0, a3, .Lfixup
/* Window overflow/underflow exception. Get stack pointer. */
@@ -245,7 +247,7 @@ ENTRY(_DoubleExceptionVector)
wsr a2, DEPC # save stack pointer temporarily
rsr a0, PS
- extui a0, a0, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS
+ extui a0, a0, PS_OWB_SHIFT, 4
wsr a0, WINDOWBASE
rsync
@@ -312,8 +314,8 @@ ENTRY(_DoubleExceptionVector)
.Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
rsr a3, EXCCAUSE
- beqi a3, XCHAL_EXCCAUSE_ITLB_MISS, 1f
- addi a3, a3, -XCHAL_EXCCAUSE_DTLB_MISS
+ beqi a3, EXCCAUSE_ITLB_MISS, 1f
+ addi a3, a3, -EXCCAUSE_DTLB_MISS
bnez a3, .Lunrecoverable
1: movi a3, fast_second_level_miss_double_kernel
jx a3
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
index cfe75f52872..a36c104c3a5 100644
--- a/arch/xtensa/kernel/vmlinux.lds.S
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -16,19 +16,17 @@
#include <asm-generic/vmlinux.lds.h>
-#define _NOCLANGUAGE
-#include <xtensa/config/core.h>
-#include <xtensa/config/system.h>
+#include <asm/variant/core.h>
OUTPUT_ARCH(xtensa)
ENTRY(_start)
-#if XCHAL_MEMORY_ORDER == XTHAL_BIGENDIAN
+#ifdef __XTENSA_EB__
jiffies = jiffies_64 + 4;
#else
jiffies = jiffies_64;
#endif
-#define KERNELOFFSET 0x1000
+#define KERNELOFFSET 0xd0001000
/* Note: In the following macros, it would be nice to specify only the
vector name and section kind and construct "sym" and "section" using
@@ -75,7 +73,7 @@ jiffies = jiffies_64;
SECTIONS
{
- . = XCHAL_KSEG_CACHED_VADDR + KERNELOFFSET;
+ . = KERNELOFFSET;
/* .text section */
_text = .;
@@ -159,7 +157,7 @@ SECTIONS
/* Initialization code and data: */
- . = ALIGN(1<<XCHAL_MMU_MIN_PTE_PAGE_SIZE);
+ . = ALIGN(1 << 12);
__init_begin = .;
.init.text : {
_sinittext = .;
@@ -223,32 +221,32 @@ SECTIONS
.dummy)
SECTION_VECTOR (_DebugInterruptVector_literal,
.DebugInterruptVector.literal,
- XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL) - 4,
+ XCHAL_DEBUG_VECTOR_VADDR - 4,
SIZEOF(.WindowVectors.text),
.WindowVectors.text)
SECTION_VECTOR (_DebugInterruptVector_text,
.DebugInterruptVector.text,
- XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL),
+ XCHAL_DEBUG_VECTOR_VADDR,
4,
.DebugInterruptVector.literal)
SECTION_VECTOR (_KernelExceptionVector_literal,
.KernelExceptionVector.literal,
- XCHAL_KERNELEXC_VECTOR_VADDR - 4,
+ XCHAL_KERNEL_VECTOR_VADDR - 4,
SIZEOF(.DebugInterruptVector.text),
.DebugInterruptVector.text)
SECTION_VECTOR (_KernelExceptionVector_text,
.KernelExceptionVector.text,
- XCHAL_KERNELEXC_VECTOR_VADDR,
+ XCHAL_KERNEL_VECTOR_VADDR,
4,
.KernelExceptionVector.literal)
SECTION_VECTOR (_UserExceptionVector_literal,
.UserExceptionVector.literal,
- XCHAL_USEREXC_VECTOR_VADDR - 4,
+ XCHAL_USER_VECTOR_VADDR - 4,
SIZEOF(.KernelExceptionVector.text),
.KernelExceptionVector.text)
SECTION_VECTOR (_UserExceptionVector_text,
.UserExceptionVector.text,
- XCHAL_USEREXC_VECTOR_VADDR,
+ XCHAL_USER_VECTOR_VADDR,
4,
.UserExceptionVector.literal)
SECTION_VECTOR (_DoubleExceptionVector_literal,
@@ -263,7 +261,7 @@ SECTIONS
.DoubleExceptionVector.literal)
. = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3;
- . = ALIGN(1<<XCHAL_MMU_MIN_PTE_PAGE_SIZE);
+ . = ALIGN(1 << 12);
__init_end = .;
diff --git a/arch/xtensa/lib/checksum.S b/arch/xtensa/lib/checksum.S
index e2d64dfd530..9d9cd990afa 100644
--- a/arch/xtensa/lib/checksum.S
+++ b/arch/xtensa/lib/checksum.S
@@ -16,8 +16,7 @@
#include <asm/errno.h>
#include <linux/linkage.h>
-#define _ASMLANGUAGE
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
/*
* computes a partial checksum, e.g. for TCP/UDP fragments
diff --git a/arch/xtensa/lib/memcopy.S b/arch/xtensa/lib/memcopy.S
index e8f6d7eb722..ddda8f4bc86 100644
--- a/arch/xtensa/lib/memcopy.S
+++ b/arch/xtensa/lib/memcopy.S
@@ -9,7 +9,7 @@
* Copyright (C) 2002 - 2005 Tensilica Inc.
*/
-#include <xtensa/coreasm.h>
+#include <asm/variant/core.h>
.macro src_b r, w0, w1
#ifdef __XTENSA_EB__
diff --git a/arch/xtensa/lib/memset.S b/arch/xtensa/lib/memset.S
index 4de25134bc6..56a17495b2d 100644
--- a/arch/xtensa/lib/memset.S
+++ b/arch/xtensa/lib/memset.S
@@ -11,7 +11,7 @@
* Copyright (C) 2002 Tensilica Inc.
*/
-#include <xtensa/coreasm.h>
+#include <asm/variant/core.h>
/*
* void *memset(void *dst, int c, size_t length)
diff --git a/arch/xtensa/lib/strncpy_user.S b/arch/xtensa/lib/strncpy_user.S
index 71d55df4389..a834057bda6 100644
--- a/arch/xtensa/lib/strncpy_user.S
+++ b/arch/xtensa/lib/strncpy_user.S
@@ -11,7 +11,7 @@
* Copyright (C) 2002 Tensilica Inc.
*/
-#include <xtensa/coreasm.h>
+#include <asm/variant/core.h>
#include <linux/errno.h>
/* Load or store instructions that may cause exceptions use the EX macro. */
diff --git a/arch/xtensa/lib/strnlen_user.S b/arch/xtensa/lib/strnlen_user.S
index cdff4d670f3..5e9c1e709b2 100644
--- a/arch/xtensa/lib/strnlen_user.S
+++ b/arch/xtensa/lib/strnlen_user.S
@@ -11,7 +11,7 @@
* Copyright (C) 2002 Tensilica Inc.
*/
-#include <xtensa/coreasm.h>
+#include <asm/variant/core.h>
/* Load or store instructions that may cause exceptions use the EX macro. */
diff --git a/arch/xtensa/lib/usercopy.S b/arch/xtensa/lib/usercopy.S
index 4641ef510f0..a8ab1d4fe0a 100644
--- a/arch/xtensa/lib/usercopy.S
+++ b/arch/xtensa/lib/usercopy.S
@@ -53,7 +53,7 @@
* a11/ original length
*/
-#include <xtensa/coreasm.h>
+#include <asm/variant/core.h>
#ifdef __XTENSA_EB__
#define ALIGN(R, W0, W1) src R, W0, W1
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index dd0dbec2e57..3dc6f2f07bb 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -21,7 +21,7 @@
#include <asm/system.h>
#include <asm/pgalloc.h>
-unsigned long asid_cache = ASID_FIRST_VERSION;
+unsigned long asid_cache = ASID_USER_FIRST;
void bad_page_fault(struct pt_regs*, unsigned long, int);
/*
@@ -58,10 +58,10 @@ void do_page_fault(struct pt_regs *regs)
return;
}
- is_write = (exccause == XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE) ? 1 : 0;
- is_exec = (exccause == XCHAL_EXCCAUSE_ITLB_PRIVILEGE ||
- exccause == XCHAL_EXCCAUSE_ITLB_MISS ||
- exccause == XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0;
+ is_write = (exccause == EXCCAUSE_STORE_CACHE_ATTRIBUTE) ? 1 : 0;
+ is_exec = (exccause == EXCCAUSE_ITLB_PRIVILEGE ||
+ exccause == EXCCAUSE_ITLB_MISS ||
+ exccause == EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0;
#if 0
printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid,
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
index 660ef058c14..e1ec2d1e818 100644
--- a/arch/xtensa/mm/init.c
+++ b/arch/xtensa/mm/init.c
@@ -141,8 +141,8 @@ void __init bootmem_init(void)
if (min_low_pfn > max_pfn)
panic("No memory found!\n");
- max_low_pfn = max_pfn < MAX_LOW_MEMORY >> PAGE_SHIFT ?
- max_pfn : MAX_LOW_MEMORY >> PAGE_SHIFT;
+ max_low_pfn = max_pfn < MAX_MEM_PFN >> PAGE_SHIFT ?
+ max_pfn : MAX_MEM_PFN >> PAGE_SHIFT;
/* Find an area to use for the bootmem bitmap. */
@@ -215,7 +215,7 @@ void __init init_mmu (void)
/* Set rasid register to a known value. */
- set_rasid_register (ASID_ALL_RESERVED);
+ set_rasid_register (ASID_USER_FIRST);
/* Set PTEVADDR special register to the start of the page
* table, which is in kernel mappable space (ie. not
diff --git a/arch/xtensa/mm/misc.S b/arch/xtensa/mm/misc.S
index 327c0f17187..ae085332c60 100644
--- a/arch/xtensa/mm/misc.S
+++ b/arch/xtensa/mm/misc.S
@@ -19,9 +19,8 @@
#include <linux/linkage.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-
-#include <xtensa/cacheasm.h>
-#include <xtensa/cacheattrasm.h>
+#include <asm/asmmacro.h>
+#include <asm/cacheasm.h>
/* clear_page (page) */
@@ -74,104 +73,66 @@ ENTRY(copy_page)
retw
-
/*
- * void __flush_invalidate_cache_all(void)
+ * void __invalidate_icache_page(ulong start)
*/
-ENTRY(__flush_invalidate_cache_all)
+ENTRY(__invalidate_icache_page)
entry sp, 16
- dcache_writeback_inv_all a2, a3
- icache_invalidate_all a2, a3
- retw
-/*
- * void __invalidate_icache_all(void)
- */
+ ___invalidate_icache_page a2 a3
+ isync
-ENTRY(__invalidate_icache_all)
- entry sp, 16
- icache_invalidate_all a2, a3
retw
/*
- * void __flush_invalidate_dcache_all(void)
+ * void __invalidate_dcache_page(ulong start)
*/
-ENTRY(__flush_invalidate_dcache_all)
+ENTRY(__invalidate_dcache_page)
entry sp, 16
- dcache_writeback_inv_all a2, a3
- retw
-
-/*
- * void __flush_invalidate_cache_range(ulong start, ulong size)
- */
+ ___invalidate_dcache_page a2 a3
+ dsync
-ENTRY(__flush_invalidate_cache_range)
- entry sp, 16
- mov a4, a2
- mov a5, a3
- dcache_writeback_inv_region a4, a5, a6
- icache_invalidate_region a2, a3, a4
retw
/*
- * void __invalidate_icache_page(ulong start)
+ * void __flush_invalidate_dcache_page(ulong start)
*/
-ENTRY(__invalidate_icache_page)
+ENTRY(__flush_invalidate_dcache_page)
entry sp, 16
- movi a3, PAGE_SIZE
- icache_invalidate_region a2, a3, a4
- retw
-/*
- * void __invalidate_dcache_page(ulong start)
- */
+ ___flush_invalidate_dcache_page a2 a3
-ENTRY(__invalidate_dcache_page)
- entry sp, 16
- movi a3, PAGE_SIZE
- dcache_invalidate_region a2, a3, a4
+ dsync
retw
/*
- * void __invalidate_icache_range(ulong start, ulong size)
+ * void __flush_dcache_page(ulong start)
*/
-ENTRY(__invalidate_icache_range)
+ENTRY(__flush_dcache_page)
entry sp, 16
- icache_invalidate_region a2, a3, a4
- retw
-/*
- * void __invalidate_dcache_range(ulong start, ulong size)
- */
+ ___flush_dcache_page a2 a3
-ENTRY(__invalidate_dcache_range)
- entry sp, 16
- dcache_invalidate_region a2, a3, a4
+ dsync
retw
-/*
- * void __flush_dcache_page(ulong start)
- */
-ENTRY(__flush_dcache_page)
- entry sp, 16
- movi a3, PAGE_SIZE
- dcache_writeback_region a2, a3, a4
- retw
/*
- * void __flush_invalidate_dcache_page(ulong start)
+ * void __invalidate_icache_range(ulong start, ulong size)
*/
-ENTRY(__flush_invalidate_dcache_page)
+ENTRY(__invalidate_icache_range)
entry sp, 16
- movi a3, PAGE_SIZE
- dcache_writeback_inv_region a2, a3, a4
+
+ ___invalidate_icache_range a2 a3 a4
+ isync
+
retw
/*
@@ -180,195 +141,69 @@ ENTRY(__flush_invalidate_dcache_page)
ENTRY(__flush_invalidate_dcache_range)
entry sp, 16
- dcache_writeback_inv_region a2, a3, a4
- retw
-/*
- * void __invalidate_dcache_all(void)
- */
+ ___flush_invalidate_dcache_range a2 a3 a4
+ dsync
-ENTRY(__invalidate_dcache_all)
- entry sp, 16
- dcache_invalidate_all a2, a3
retw
/*
- * void __flush_invalidate_dcache_page_phys(ulong start)
+ * void _flush_dcache_range(ulong start, ulong size)
*/
-ENTRY(__flush_invalidate_dcache_page_phys)
+ENTRY(__flush_dcache_range)
entry sp, 16
- movi a3, XCHAL_DCACHE_SIZE
- movi a4, PAGE_MASK | 1
- addi a2, a2, 1
-
-1: addi a3, a3, -XCHAL_DCACHE_LINESIZE
-
- ldct a6, a3
+ ___flush_dcache_range a2 a3 a4
dsync
- and a6, a6, a4
- beq a6, a2, 2f
- bgeui a3, 2, 1b
- retw
-2: diwbi a3, 0
- bgeui a3, 2, 1b
retw
-ENTRY(check_dcache_low0)
- entry sp, 16
-
- movi a3, XCHAL_DCACHE_SIZE / 4
- movi a4, PAGE_MASK | 1
- addi a2, a2, 1
-
-1: addi a3, a3, -XCHAL_DCACHE_LINESIZE
-
- ldct a6, a3
- dsync
- and a6, a6, a4
- beq a6, a2, 2f
- bgeui a3, 2, 1b
- retw
-
-2: j 2b
-
-ENTRY(check_dcache_high0)
- entry sp, 16
-
- movi a5, XCHAL_DCACHE_SIZE / 4
- movi a3, XCHAL_DCACHE_SIZE / 2
- movi a4, PAGE_MASK | 1
- addi a2, a2, 1
-
-1: addi a3, a3, -XCHAL_DCACHE_LINESIZE
- addi a5, a5, -XCHAL_DCACHE_LINESIZE
-
- ldct a6, a3
- dsync
- and a6, a6, a4
- beq a6, a2, 2f
- bgeui a5, 2, 1b
- retw
-
-2: j 2b
+/*
+ * void _invalidate_dcache_range(ulong start, ulong size)
+ */
-ENTRY(check_dcache_low1)
+ENTRY(__invalidate_dcache_range)
entry sp, 16
- movi a5, XCHAL_DCACHE_SIZE / 4
- movi a3, XCHAL_DCACHE_SIZE * 3 / 4
- movi a4, PAGE_MASK | 1
- addi a2, a2, 1
+ ___invalidate_dcache_range a2 a3 a4
-1: addi a3, a3, -XCHAL_DCACHE_LINESIZE
- addi a5, a5, -XCHAL_DCACHE_LINESIZE
- ldct a6, a3
- dsync
- and a6, a6, a4
- beq a6, a2, 2f
- bgeui a5, 2, 1b
retw
-2: j 2b
+/*
+ * void _invalidate_icache_all(void)
+ */
-ENTRY(check_dcache_high1)
+ENTRY(__invalidate_icache_all)
entry sp, 16
- movi a5, XCHAL_DCACHE_SIZE / 4
- movi a3, XCHAL_DCACHE_SIZE
- movi a4, PAGE_MASK | 1
- addi a2, a2, 1
-
-1: addi a3, a3, -XCHAL_DCACHE_LINESIZE
- addi a5, a5, -XCHAL_DCACHE_LINESIZE
+ ___invalidate_icache_all a2 a3
+ isync
- ldct a6, a3
- dsync
- and a6, a6, a4
- beq a6, a2, 2f
- bgeui a5, 2, 1b
retw
-2: j 2b
-
-
/*
- * void __invalidate_icache_page_phys(ulong start)
+ * void _flush_invalidate_dcache_all(void)
*/
-ENTRY(__invalidate_icache_page_phys)
+ENTRY(__flush_invalidate_dcache_all)
entry sp, 16
- movi a3, XCHAL_ICACHE_SIZE
- movi a4, PAGE_MASK | 1
- addi a2, a2, 1
-
-1: addi a3, a3, -XCHAL_ICACHE_LINESIZE
-
- lict a6, a3
- isync
- and a6, a6, a4
- beq a6, a2, 2f
- bgeui a3, 2, 1b
- retw
+ ___flush_invalidate_dcache_all a2 a3
+ dsync
-2: iii a3, 0
- bgeui a3, 2, 1b
retw
+/*
+ * void _invalidate_dcache_all(void)
+ */
-#if 0
-
- movi a3, XCHAL_DCACHE_WAYS - 1
- movi a4, PAGE_SIZE
-
-1: mov a5, a2
- add a6, a2, a4
-
-2: diwbi a5, 0
- diwbi a5, XCHAL_DCACHE_LINESIZE
- diwbi a5, XCHAL_DCACHE_LINESIZE * 2
- diwbi a5, XCHAL_DCACHE_LINESIZE * 3
-
- addi a5, a5, XCHAL_DCACHE_LINESIZE * 4
- blt a5, a6, 2b
-
- addi a3, a3, -1
- addi a2, a2, XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS
- bgez a3, 1b
-
- retw
-
-ENTRY(__invalidate_icache_page_index)
+ENTRY(__invalidate_dcache_all)
entry sp, 16
- movi a3, XCHAL_ICACHE_WAYS - 1
- movi a4, PAGE_SIZE
-
-1: mov a5, a2
- add a6, a2, a4
-
-2: iii a5, 0
- iii a5, XCHAL_ICACHE_LINESIZE
- iii a5, XCHAL_ICACHE_LINESIZE * 2
- iii a5, XCHAL_ICACHE_LINESIZE * 3
-
- addi a5, a5, XCHAL_ICACHE_LINESIZE * 4
- blt a5, a6, 2b
-
- addi a3, a3, -1
- addi a2, a2, XCHAL_ICACHE_SIZE / XCHAL_ICACHE_WAYS
- bgez a3, 2b
+ ___invalidate_dcache_all a2 a3
+ dsync
retw
-#endif
-
-
-
-
-
-
diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c
index 0fefb866687..239461d8ea8 100644
--- a/arch/xtensa/mm/tlb.c
+++ b/arch/xtensa/mm/tlb.c
@@ -24,12 +24,12 @@
static inline void __flush_itlb_all (void)
{
- int way, index;
+ int w, i;
- for (way = 0; way < XCHAL_ITLB_ARF_WAYS; way++) {
- for (index = 0; index < ITLB_ENTRIES_PER_ARF_WAY; index++) {
- int entry = way + (index << PAGE_SHIFT);
- invalidate_itlb_entry_no_isync (entry);
+ for (w = 0; w < ITLB_ARF_WAYS; w++) {
+ for (i = 0; i < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); i++) {
+ int e = w + (i << PAGE_SHIFT);
+ invalidate_itlb_entry_no_isync(e);
}
}
asm volatile ("isync\n");
@@ -37,12 +37,12 @@ static inline void __flush_itlb_all (void)
static inline void __flush_dtlb_all (void)
{
- int way, index;
+ int w, i;
- for (way = 0; way < XCHAL_DTLB_ARF_WAYS; way++) {
- for (index = 0; index < DTLB_ENTRIES_PER_ARF_WAY; index++) {
- int entry = way + (index << PAGE_SHIFT);
- invalidate_dtlb_entry_no_isync (entry);
+ for (w = 0; w < DTLB_ARF_WAYS; w++) {
+ for (i = 0; i < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); i++) {
+ int e = w + (i << PAGE_SHIFT);
+ invalidate_dtlb_entry_no_isync(e);
}
}
asm volatile ("isync\n");
@@ -63,21 +63,25 @@ void flush_tlb_all (void)
void flush_tlb_mm(struct mm_struct *mm)
{
-#if 0
- printk("[tlbmm<%lx>]\n", (unsigned long)mm->context);
-#endif
-
if (mm == current->active_mm) {
int flags;
local_save_flags(flags);
- get_new_mmu_context(mm, asid_cache);
- set_rasid_register(ASID_INSERT(mm->context));
+ __get_new_mmu_context(mm);
+ __load_mmu_context(mm);
local_irq_restore(flags);
}
else
mm->context = 0;
}
+#define _ITLB_ENTRIES (ITLB_ARF_WAYS << XCHAL_ITLB_ARF_ENTRIES_LOG2)
+#define _DTLB_ENTRIES (DTLB_ARF_WAYS << XCHAL_DTLB_ARF_ENTRIES_LOG2)
+#if _ITLB_ENTRIES > _DTLB_ENTRIES
+# define _TLB_ENTRIES _ITLB_ENTRIES
+#else
+# define _TLB_ENTRIES _DTLB_ENTRIES
+#endif
+
void flush_tlb_range (struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
@@ -93,7 +97,7 @@ void flush_tlb_range (struct vm_area_struct *vma,
#endif
local_save_flags(flags);
- if (end-start + (PAGE_SIZE-1) <= SMALLEST_NTLB_ENTRIES << PAGE_SHIFT) {
+ if (end-start + (PAGE_SIZE-1) <= _TLB_ENTRIES << PAGE_SHIFT) {
int oldpid = get_rasid_register();
set_rasid_register (ASID_INSERT(mm->context));
start &= PAGE_MASK;
@@ -111,9 +115,7 @@ void flush_tlb_range (struct vm_area_struct *vma,
set_rasid_register(oldpid);
} else {
- get_new_mmu_context(mm, asid_cache);
- if (mm == current->active_mm)
- set_rasid_register(ASID_INSERT(mm->context));
+ flush_tlb_mm(mm);
}
local_irq_restore(flags);
}
@@ -123,10 +125,6 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
struct mm_struct* mm = vma->vm_mm;
unsigned long flags;
int oldpid;
-#if 0
- printk("[tlbpage<%02lx,%08lx>]\n",
- (unsigned long)mm->context, page);
-#endif
if(mm->context == NO_CONTEXT)
return;
@@ -142,404 +140,5 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
set_rasid_register(oldpid);
local_irq_restore(flags);
-
-#if 0
- flush_tlb_all();
- return;
-#endif
-}
-
-
-#ifdef DEBUG_TLB
-
-#define USE_ITLB 0
-#define USE_DTLB 1
-
-struct way_config_t {
- int indicies;
- int indicies_log2;
- int pgsz_log2;
- int arf;
-};
-
-static struct way_config_t itlb[XCHAL_ITLB_WAYS] =
-{
- { XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES_LOG2),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, PAGESZ_LOG2_MIN),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ARF)
- },
- { XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES_LOG2),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, PAGESZ_LOG2_MIN),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ARF)
- },
- { XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES_LOG2),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, PAGESZ_LOG2_MIN),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ARF)
- },
- { XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES_LOG2),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, PAGESZ_LOG2_MIN),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ARF)
- },
- { XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES_LOG2),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, PAGESZ_LOG2_MIN),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ARF)
- },
- { XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES_LOG2),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, PAGESZ_LOG2_MIN),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ARF)
- },
- { XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES_LOG2),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, PAGESZ_LOG2_MIN),
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ARF)
- }
-};
-
-static struct way_config_t dtlb[XCHAL_DTLB_WAYS] =
-{
- { XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES_LOG2),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, PAGESZ_LOG2_MIN),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ARF)
- },
- { XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES_LOG2),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, PAGESZ_LOG2_MIN),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ARF)
- },
- { XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES_LOG2),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, PAGESZ_LOG2_MIN),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ARF)
- },
- { XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES_LOG2),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, PAGESZ_LOG2_MIN),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ARF)
- },
- { XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES_LOG2),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, PAGESZ_LOG2_MIN),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ARF)
- },
- { XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES_LOG2),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, PAGESZ_LOG2_MIN),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ARF)
- },
- { XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES_LOG2),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, PAGESZ_LOG2_MIN),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ARF)
- },
- { XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES_LOG2),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, PAGESZ_LOG2_MIN),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ARF)
- },
- { XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES_LOG2),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, PAGESZ_LOG2_MIN),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ARF)
- },
- { XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES_LOG2),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, PAGESZ_LOG2_MIN),
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ARF)
- }
-};
-
-/* Total number of entries: */
-#define ITLB_TOTAL_ENTRIES \
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES) + \
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES) + \
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES) + \
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES) + \
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES) + \
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES) + \
- XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES)
-#define DTLB_TOTAL_ENTRIES \
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES) + \
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES) + \
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES) + \
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES) + \
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES) + \
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES) + \
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES) + \
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES) + \
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES) + \
- XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES)
-
-
-typedef struct {
- unsigned va;
- unsigned pa;
- unsigned char asid;
- unsigned char ca;
- unsigned char way;
- unsigned char index;
- unsigned char pgsz_log2; /* 0 .. 32 */
- unsigned char type; /* 0=ITLB 1=DTLB */
-} tlb_dump_entry_t;
-
-/* Return -1 if a precedes b, +1 if a follows b, 0 if same: */
-int cmp_tlb_dump_info( tlb_dump_entry_t *a, tlb_dump_entry_t *b )
-{
- if (a->asid < b->asid) return -1;
- if (a->asid > b->asid) return 1;
- if (a->va < b->va) return -1;
- if (a->va > b->va) return 1;
- if (a->pa < b->pa) return -1;
- if (a->pa > b->pa) return 1;
- if (a->ca < b->ca) return -1;
- if (a->ca > b->ca) return 1;
- if (a->way < b->way) return -1;
- if (a->way > b->way) return 1;
- if (a->index < b->index) return -1;
- if (a->index > b->index) return 1;
- return 0;
-}
-
-void sort_tlb_dump_info( tlb_dump_entry_t *t, int n )
-{
- int i, j;
- /* Simple O(n*n) sort: */
- for (i = 0; i < n-1; i++)
- for (j = i+1; j < n; j++)
- if (cmp_tlb_dump_info(t+i, t+j) > 0) {
- tlb_dump_entry_t tmp = t[i];
- t[i] = t[j];
- t[j] = tmp;
- }
-}
-
-
-static tlb_dump_entry_t itlb_dump_info[ITLB_TOTAL_ENTRIES];
-static tlb_dump_entry_t dtlb_dump_info[DTLB_TOTAL_ENTRIES];
-
-
-static inline char *way_type (int type)
-{
- return type ? "autorefill" : "non-autorefill";
-}
-
-void print_entry (struct way_config_t *way_info,
- unsigned int way,
- unsigned int index,
- unsigned int virtual,
- unsigned int translation)
-{
- char valid_chr;
- unsigned int va, pa, asid, ca;
-
- va = virtual &
- ~((1 << (way_info->pgsz_log2 + way_info->indicies_log2)) - 1);
- asid = virtual & ((1 << XCHAL_MMU_ASID_BITS) - 1);
- pa = translation & ~((1 << way_info->pgsz_log2) - 1);
- ca = translation & ((1 << XCHAL_MMU_CA_BITS) - 1);
- valid_chr = asid ? 'V' : 'I';
-
- /* Compute and incorporate the effect of the index bits on the
- * va. It's more useful for kernel debugging, since we always
- * want to know the effective va anyway. */
-
- va += index << way_info->pgsz_log2;
-
- printk ("\t[%d,%d] (%c) vpn 0x%.8x ppn 0x%.8x asid 0x%.2x am 0x%x\n",
- way, index, valid_chr, va, pa, asid, ca);
-}
-
-void print_itlb_entry (struct way_config_t *way_info, int way, int index)
-{
- print_entry (way_info, way, index,
- read_itlb_virtual (way + (index << way_info->pgsz_log2)),
- read_itlb_translation (way + (index << way_info->pgsz_log2)));
-}
-
-void print_dtlb_entry (struct way_config_t *way_info, int way, int index)
-{
- print_entry (way_info, way, index,
- read_dtlb_virtual (way + (index << way_info->pgsz_log2)),
- read_dtlb_translation (way + (index << way_info->pgsz_log2)));
-}
-
-void dump_itlb (void)
-{
- int way, index;
-
- printk ("\nITLB: ways = %d\n", XCHAL_ITLB_WAYS);
-
- for (way = 0; way < XCHAL_ITLB_WAYS; way++) {
- printk ("\nWay: %d, Entries: %d, MinPageSize: %d, Type: %s\n",
- way, itlb[way].indicies,
- itlb[way].pgsz_log2, way_type(itlb[way].arf));
- for (index = 0; index < itlb[way].indicies; index++) {
- print_itlb_entry(&itlb[way], way, index);
- }
- }
-}
-
-void dump_dtlb (void)
-{
- int way, index;
-
- printk ("\nDTLB: ways = %d\n", XCHAL_DTLB_WAYS);
-
- for (way = 0; way < XCHAL_DTLB_WAYS; way++) {
- printk ("\nWay: %d, Entries: %d, MinPageSize: %d, Type: %s\n",
- way, dtlb[way].indicies,
- dtlb[way].pgsz_log2, way_type(dtlb[way].arf));
- for (index = 0; index < dtlb[way].indicies; index++) {
- print_dtlb_entry(&dtlb[way], way, index);
- }
- }
-}
-
-void dump_tlb (tlb_dump_entry_t *tinfo, struct way_config_t *config,
- int entries, int ways, int type, int show_invalid)
-{
- tlb_dump_entry_t *e = tinfo;
- int way, i;
-
- /* Gather all info: */
- for (way = 0; way < ways; way++) {
- struct way_config_t *cfg = config + way;
- for (i = 0; i < cfg->indicies; i++) {
- unsigned wayindex = way + (i << cfg->pgsz_log2);
- unsigned vv = (type ? read_dtlb_virtual (wayindex)
- : read_itlb_virtual (wayindex));
- unsigned pp = (type ? read_dtlb_translation (wayindex)
- : read_itlb_translation (wayindex));
-
- /* Compute and incorporate the effect of the index bits on the
- * va. It's more useful for kernel debugging, since we always
- * want to know the effective va anyway. */
-
- e->va = (vv & ~((1 << (cfg->pgsz_log2 + cfg->indicies_log2)) - 1));
- e->va += (i << cfg->pgsz_log2);
- e->pa = (pp & ~((1 << cfg->pgsz_log2) - 1));
- e->asid = (vv & ((1 << XCHAL_MMU_ASID_BITS) - 1));
- e->ca = (pp & ((1 << XCHAL_MMU_CA_BITS) - 1));
- e->way = way;
- e->index = i;
- e->pgsz_log2 = cfg->pgsz_log2;
- e->type = type;
- e++;
- }
- }
-#if 1
- /* Sort by ASID and VADDR: */
- sort_tlb_dump_info (tinfo, entries);
-#endif
-
- /* Display all sorted info: */
- printk ("\n%cTLB dump:\n", (type ? 'D' : 'I'));
- for (e = tinfo, i = 0; i < entries; i++, e++) {
-#if 0
- if (e->asid == 0 && !show_invalid)
- continue;
-#endif
- printk ("%c way=%d i=%d ASID=%02X V=%08X -> P=%08X CA=%X (%d %cB)\n",
- (e->type ? 'D' : 'I'), e->way, e->index,
- e->asid, e->va, e->pa, e->ca,
- (1 << (e->pgsz_log2 % 10)),
- " kMG"[e->pgsz_log2 / 10]
- );
- }
-}
-
-void dump_tlbs2 (int showinv)
-{
- dump_tlb (itlb_dump_info, itlb, ITLB_TOTAL_ENTRIES, XCHAL_ITLB_WAYS, 0, showinv);
- dump_tlb (dtlb_dump_info, dtlb, DTLB_TOTAL_ENTRIES, XCHAL_DTLB_WAYS, 1, showinv);
-}
-
-void dump_all_tlbs (void)
-{
- dump_tlbs2 (1);
-}
-
-void dump_valid_tlbs (void)
-{
- dump_tlbs2 (0);
}
-
-void dump_tlbs (void)
-{
- dump_itlb();
- dump_dtlb();
-}
-
-void dump_cache_tag(int dcache, int idx)
-{
- int w, i, s, e;
- unsigned long tag, index;
- unsigned long num_lines, num_ways, cache_size, line_size;
-
- num_ways = dcache ? XCHAL_DCACHE_WAYS : XCHAL_ICACHE_WAYS;
- cache_size = dcache ? XCHAL_DCACHE_SIZE : XCHAL_ICACHE_SIZE;
- line_size = dcache ? XCHAL_DCACHE_LINESIZE : XCHAL_ICACHE_LINESIZE;
-
- num_lines = cache_size / num_ways;
-
- s = 0; e = num_lines;
-
- if (idx >= 0)
- e = (s = idx * line_size) + 1;
-
- for (i = s; i < e; i+= line_size) {
- printk("\nline %#08x:", i);
- for (w = 0; w < num_ways; w++) {
- index = w * num_lines + i;
- if (dcache)
- __asm__ __volatile__("ldct %0, %1\n\t"
- : "=a"(tag) : "a"(index));
- else
- __asm__ __volatile__("lict %0, %1\n\t"
- : "=a"(tag) : "a"(index));
-
- printk(" %#010lx", tag);
- }
- }
- printk ("\n");
-}
-
-void dump_icache(int index)
-{
- unsigned long data, addr;
- int w, i;
-
- const unsigned long num_ways = XCHAL_ICACHE_WAYS;
- const unsigned long cache_size = XCHAL_ICACHE_SIZE;
- const unsigned long line_size = XCHAL_ICACHE_LINESIZE;
- const unsigned long num_lines = cache_size / num_ways / line_size;
-
- for (w = 0; w < num_ways; w++) {
- printk ("\nWay %d", w);
-
- for (i = 0; i < line_size; i+= 4) {
- addr = w * num_lines + index * line_size + i;
- __asm__ __volatile__("licw %0, %1\n\t"
- : "=a"(data) : "a"(addr));
- printk(" %#010lx", data);
- }
- }
- printk ("\n");
-}
-
-void dump_cache_tags(void)
-{
- printk("Instruction cache\n");
- dump_cache_tag(0, -1);
- printk("Data cache\n");
- dump_cache_tag(1, -1);
-}
-
-#endif
diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c
index 5c947cae752..2f4f20ffe66 100644
--- a/arch/xtensa/platform-iss/console.c
+++ b/arch/xtensa/platform-iss/console.c
@@ -25,11 +25,15 @@
#include <asm/uaccess.h>
#include <asm/irq.h>
-#include <xtensa/simcall.h>
+#include <asm/platform/simcall.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#endif
+
#define SERIAL_MAX_NUM_LINES 1
#define SERIAL_TIMER_VALUE (20 * HZ)
@@ -191,7 +195,7 @@ static int rs_read_proc(char *page, char **start, off_t off, int count,
}
-static const struct tty_operations serial_ops = {
+static 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 15d64414bd6..8ebfc876122 100644
--- a/arch/xtensa/platform-iss/network.c
+++ b/arch/xtensa/platform-iss/network.c
@@ -34,7 +34,7 @@
#include <linux/timer.h>
#include <linux/platform_device.h>
-#include <xtensa/simcall.h>
+#include <asm/platform/simcall.h>
#define DRIVER_NAME "iss-netdev"
#define ETH_MAX_PACKET 1500
diff --git a/block/as-iosched.c b/block/as-iosched.c
index 5934c4bfd52..ef126277b4b 100644
--- a/block/as-iosched.c
+++ b/block/as-iosched.c
@@ -1462,20 +1462,7 @@ static struct elevator_type iosched_as = {
static int __init as_init(void)
{
- int ret;
-
- ret = elv_register(&iosched_as);
- if (!ret) {
- /*
- * don't allow AS to get unregistered, since we would have
- * to browse all tasks in the system and release their
- * as_io_context first
- */
- __module_get(THIS_MODULE);
- return 0;
- }
-
- return ret;
+ return elv_register(&iosched_as);
}
static void __exit as_exit(void)
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 78c6b312bd3..07b70624377 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -219,9 +219,12 @@ static int cfq_queue_empty(request_queue_t *q)
return !cfqd->busy_queues;
}
-static inline pid_t cfq_queue_pid(struct task_struct *task, int rw)
+static inline pid_t cfq_queue_pid(struct task_struct *task, int rw, int is_sync)
{
- if (rw == READ || rw == WRITE_SYNC)
+ /*
+ * Use the per-process queue, for read requests and syncronous writes
+ */
+ if (!(rw & REQ_RW) || is_sync)
return task->pid;
return CFQ_KEY_ASYNC;
@@ -473,7 +476,7 @@ static struct request *
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));
+ pid_t key = cfq_queue_pid(tsk, bio_data_dir(bio), bio_sync(bio));
struct cfq_queue *cfqq;
cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
@@ -565,6 +568,33 @@ cfq_merged_requests(request_queue_t *q, struct request *rq,
cfq_remove_request(next);
}
+static int cfq_allow_merge(request_queue_t *q, struct request *rq,
+ struct bio *bio)
+{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ const int rw = bio_data_dir(bio);
+ struct cfq_queue *cfqq;
+ pid_t key;
+
+ /*
+ * Disallow merge of a sync bio into an async request.
+ */
+ if ((bio_data_dir(bio) == READ || bio_sync(bio)) && !rq_is_sync(rq))
+ return 0;
+
+ /*
+ * Lookup the cfqq that this bio will be queued with. Allow
+ * merge only if rq is queued there.
+ */
+ key = cfq_queue_pid(current, rw, bio_sync(bio));
+ cfqq = cfq_find_cfq_hash(cfqd, key, current->ioprio);
+
+ if (cfqq == RQ_CFQQ(rq))
+ return 1;
+
+ return 0;
+}
+
static inline void
__cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
@@ -1748,6 +1778,9 @@ static int cfq_may_queue(request_queue_t *q, int rw)
struct cfq_data *cfqd = q->elevator->elevator_data;
struct task_struct *tsk = current;
struct cfq_queue *cfqq;
+ unsigned int key;
+
+ key = cfq_queue_pid(tsk, rw, rw & REQ_RW_SYNC);
/*
* don't force setup of a queue from here, as a call to may_queue
@@ -1755,7 +1788,7 @@ static int cfq_may_queue(request_queue_t *q, int rw)
* so just lookup a possibly existing queue, or return 'may queue'
* if that fails
*/
- cfqq = cfq_find_cfq_hash(cfqd, cfq_queue_pid(tsk, rw), tsk->ioprio);
+ cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
if (cfqq) {
cfq_init_prio_data(cfqq);
cfq_prio_boost(cfqq);
@@ -1798,10 +1831,10 @@ cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
struct task_struct *tsk = current;
struct cfq_io_context *cic;
const int rw = rq_data_dir(rq);
- pid_t key = cfq_queue_pid(tsk, rw);
+ const int is_sync = rq_is_sync(rq);
+ pid_t key = cfq_queue_pid(tsk, rw, is_sync);
struct cfq_queue *cfqq;
unsigned long flags;
- int is_sync = key != CFQ_KEY_ASYNC;
might_sleep_if(gfp_mask & __GFP_WAIT);
@@ -2119,6 +2152,7 @@ static struct elevator_type iosched_cfq = {
.elevator_merge_fn = cfq_merge,
.elevator_merged_fn = cfq_merged_request,
.elevator_merge_req_fn = cfq_merged_requests,
+ .elevator_allow_merge_fn = cfq_allow_merge,
.elevator_dispatch_fn = cfq_dispatch_requests,
.elevator_add_req_fn = cfq_insert_request,
.elevator_activate_req_fn = cfq_activate_request,
diff --git a/block/elevator.c b/block/elevator.c
index c0063f345c5..f6dafa8c7c4 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -51,6 +51,21 @@ static const int elv_hash_shift = 6;
#define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash))
/*
+ * Query io scheduler to see if the current process issuing bio may be
+ * merged with rq.
+ */
+static int elv_iosched_allow_merge(struct request *rq, struct bio *bio)
+{
+ request_queue_t *q = rq->q;
+ elevator_t *e = q->elevator;
+
+ if (e->ops->elevator_allow_merge_fn)
+ return e->ops->elevator_allow_merge_fn(q, rq, bio);
+
+ return 1;
+}
+
+/*
* can we safely merge with this request?
*/
inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
@@ -65,12 +80,15 @@ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
return 0;
/*
- * same device and no special stuff set, merge is ok
+ * must be same device and not a special request
*/
- if (rq->rq_disk == bio->bi_bdev->bd_disk && !rq->special)
- return 1;
+ if (rq->rq_disk != bio->bi_bdev->bd_disk || rq->special)
+ return 0;
- return 0;
+ if (!elv_iosched_allow_merge(rq, bio))
+ return 0;
+
+ return 1;
}
EXPORT_SYMBOL(elv_rq_merge_ok);
@@ -572,6 +590,12 @@ void elv_insert(request_queue_t *q, struct request *rq, int where)
*/
rq->cmd_flags |= REQ_SOFTBARRIER;
+ /*
+ * Most requeues happen because of a busy condition,
+ * don't force unplug of the queue for that case.
+ */
+ unplug_it = 0;
+
if (q->ordseq == 0) {
list_add(&rq->queuelist, &q->queue_head);
break;
@@ -586,11 +610,6 @@ void elv_insert(request_queue_t *q, struct request *rq, int where)
}
list_add_tail(&rq->queuelist, pos);
- /*
- * most requeues happen because of a busy condition, don't
- * force unplug of the queue for that case.
- */
- unplug_it = 0;
break;
default:
diff --git a/block/genhd.c b/block/genhd.c
index 653919d50cd..457fdac4c17 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -417,6 +417,34 @@ static struct disk_attribute disk_attr_stat = {
.show = disk_stats_read
};
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+
+static ssize_t disk_fail_store(struct gendisk * disk,
+ const char *buf, size_t count)
+{
+ int i;
+
+ if (count > 0 && sscanf(buf, "%d", &i) > 0) {
+ if (i == 0)
+ disk->flags &= ~GENHD_FL_FAIL;
+ else
+ disk->flags |= GENHD_FL_FAIL;
+ }
+
+ return count;
+}
+static ssize_t disk_fail_read(struct gendisk * disk, char *page)
+{
+ return sprintf(page, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0);
+}
+static struct disk_attribute disk_attr_fail = {
+ .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR },
+ .store = disk_fail_store,
+ .show = disk_fail_read
+};
+
+#endif
+
static struct attribute * default_attrs[] = {
&disk_attr_uevent.attr,
&disk_attr_dev.attr,
@@ -424,6 +452,9 @@ static struct attribute * default_attrs[] = {
&disk_attr_removable.attr,
&disk_attr_size.attr,
&disk_attr_stat.attr,
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+ &disk_attr_fail.attr,
+#endif
NULL,
};
diff --git a/block/ioctl.c b/block/ioctl.c
index 58aab630dfc..f6962b64660 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -72,7 +72,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
bdevp = bdget_disk(disk, part);
if (!bdevp)
return -ENOMEM;
- mutex_lock_nested(&bdevp->bd_mutex, BD_MUTEX_PARTITION);
+ mutex_lock(&bdevp->bd_mutex);
if (bdevp->bd_openers) {
mutex_unlock(&bdevp->bd_mutex);
bdput(bdevp);
@@ -82,7 +82,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
fsync_bdev(bdevp);
invalidate_bdev(bdevp, 0);
- mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_WHOLE);
+ mutex_lock(&bdev->bd_mutex);
delete_partition(disk, part);
mutex_unlock(&bdev->bd_mutex);
mutex_unlock(&bdevp->bd_mutex);
@@ -290,7 +290,7 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
ENOIOCTLCMD for unknown ioctls. */
long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
- struct block_device *bdev = file->f_dentry->d_inode->i_bdev;
+ struct block_device *bdev = file->f_path.dentry->d_inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
int ret = -ENOIOCTLCMD;
if (disk->fops->compat_ioctl) {
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 31512cd9f3a..38c293b987b 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -25,9 +25,11 @@
#include <linux/slab.h>
#include <linux/swap.h>
#include <linux/writeback.h>
+#include <linux/task_io_accounting_ops.h>
#include <linux/interrupt.h>
#include <linux/cpu.h>
#include <linux/blktrace_api.h>
+#include <linux/fault-inject.h>
/*
* for max sense size
@@ -127,13 +129,6 @@ struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
}
EXPORT_SYMBOL(blk_get_backing_dev_info);
-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);
-
/**
* blk_queue_prep_rq - set a prepare_request function for queue
* @q: queue
@@ -236,8 +231,6 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
* by default assume old behaviour and bounce for any highmem page
*/
blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
-
- blk_queue_activity_fn(q, NULL, NULL);
}
EXPORT_SYMBOL(blk_queue_make_request);
@@ -1271,7 +1264,7 @@ new_hw_segment:
bio->bi_hw_segments = nr_hw_segs;
bio->bi_flags |= (1 << BIO_SEG_VALID);
}
-
+EXPORT_SYMBOL(blk_recount_segments);
static int blk_phys_contig_segment(request_queue_t *q, struct bio *bio,
struct bio *nxt)
@@ -1412,8 +1405,7 @@ static inline int ll_new_hw_segment(request_queue_t *q,
return 1;
}
-static int ll_back_merge_fn(request_queue_t *q, struct request *req,
- struct bio *bio)
+int ll_back_merge_fn(request_queue_t *q, struct request *req, struct bio *bio)
{
unsigned short max_sectors;
int len;
@@ -1449,6 +1441,7 @@ static int ll_back_merge_fn(request_queue_t *q, struct request *req,
return ll_new_hw_segment(q, req, bio);
}
+EXPORT_SYMBOL(ll_back_merge_fn);
static int ll_front_merge_fn(request_queue_t *q, struct request *req,
struct bio *bio)
@@ -1919,9 +1912,6 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
}
q->request_fn = rfn;
- q->back_merge_fn = ll_back_merge_fn;
- q->front_merge_fn = ll_front_merge_fn;
- q->merge_requests_fn = ll_merge_requests_fn;
q->prep_rq_fn = NULL;
q->unplug_fn = generic_unplug_device;
q->queue_flags = (1 << QUEUE_FLAG_CLUSTER);
@@ -2065,15 +2055,16 @@ static void freed_request(request_queue_t *q, int rw, int priv)
* Returns NULL on failure, with queue_lock held.
* Returns !NULL on success, with queue_lock *not held*.
*/
-static struct request *get_request(request_queue_t *q, int rw, struct bio *bio,
- gfp_t gfp_mask)
+static struct request *get_request(request_queue_t *q, int rw_flags,
+ struct bio *bio, gfp_t gfp_mask)
{
struct request *rq = NULL;
struct request_list *rl = &q->rq;
struct io_context *ioc = NULL;
+ const int rw = rw_flags & 0x01;
int may_queue, priv;
- may_queue = elv_may_queue(q, rw);
+ may_queue = elv_may_queue(q, rw_flags);
if (may_queue == ELV_MQUEUE_NO)
goto rq_starved;
@@ -2121,7 +2112,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, priv, gfp_mask);
+ rq = blk_alloc_request(q, rw_flags, priv, gfp_mask);
if (unlikely(!rq)) {
/*
* Allocation failed presumably due to memory. Undo anything
@@ -2169,12 +2160,13 @@ out:
*
* Called with q->queue_lock held, and returns with it unlocked.
*/
-static struct request *get_request_wait(request_queue_t *q, int rw,
+static struct request *get_request_wait(request_queue_t *q, int rw_flags,
struct bio *bio)
{
+ const int rw = rw_flags & 0x01;
struct request *rq;
- rq = get_request(q, rw, bio, GFP_NOIO);
+ rq = get_request(q, rw_flags, bio, GFP_NOIO);
while (!rq) {
DEFINE_WAIT(wait);
struct request_list *rl = &q->rq;
@@ -2182,7 +2174,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw,
prepare_to_wait_exclusive(&rl->wait[rw], &wait,
TASK_UNINTERRUPTIBLE);
- rq = get_request(q, rw, bio, GFP_NOIO);
+ rq = get_request(q, rw_flags, bio, GFP_NOIO);
if (!rq) {
struct io_context *ioc;
@@ -2355,40 +2347,29 @@ static int __blk_rq_map_user(request_queue_t *q, struct request *rq,
else
bio = bio_copy_user(q, uaddr, len, reading);
- if (IS_ERR(bio)) {
+ if (IS_ERR(bio))
return PTR_ERR(bio);
- }
orig_bio = bio;
blk_queue_bounce(q, &bio);
+
/*
* We link the bounce buffer in and could have to traverse it
* later so we have to get a ref to prevent it from being freed
*/
bio_get(bio);
- /*
- * for most (all? don't know of any) queues we could
- * skip grabbing the queue lock here. only drivers with
- * funky private ->back_merge_fn() function could be
- * problematic.
- */
- spin_lock_irq(q->queue_lock);
if (!rq->bio)
blk_rq_bio_prep(q, rq, bio);
- else if (!q->back_merge_fn(q, rq, bio)) {
+ else if (!ll_back_merge_fn(q, rq, bio)) {
ret = -EINVAL;
- spin_unlock_irq(q->queue_lock);
goto unmap_bio;
} else {
rq->biotail->bi_next = bio;
rq->biotail = bio;
- rq->nr_sectors += bio_sectors(bio);
- rq->hard_nr_sectors = rq->nr_sectors;
rq->data_len += bio->bi_size;
}
- spin_unlock_irq(q->queue_lock);
return bio->bi_size;
@@ -2424,6 +2405,7 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf,
unsigned long len)
{
unsigned long bytes_read = 0;
+ struct bio *bio = NULL;
int ret;
if (len > (q->max_hw_sectors << 9))
@@ -2450,6 +2432,8 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf,
ret = __blk_rq_map_user(q, rq, ubuf, map_len);
if (ret < 0)
goto unmap_rq;
+ if (!bio)
+ bio = rq->bio;
bytes_read += ret;
ubuf += ret;
}
@@ -2457,7 +2441,7 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf,
rq->buffer = rq->data = NULL;
return 0;
unmap_rq:
- blk_rq_unmap_user(rq);
+ blk_rq_unmap_user(bio);
return ret;
}
@@ -2469,6 +2453,7 @@ EXPORT_SYMBOL(blk_rq_map_user);
* @rq: request to map data to
* @iov: pointer to the iovec
* @iov_count: number of elements in the iovec
+ * @len: I/O byte count
*
* Description:
* Data will be mapped directly for zero copy io, if possible. Otherwise
@@ -2514,27 +2499,33 @@ EXPORT_SYMBOL(blk_rq_map_user_iov);
/**
* blk_rq_unmap_user - unmap a request with user data
- * @rq: rq to be unmapped
+ * @bio: start of bio list
*
* Description:
- * Unmap a rq previously mapped by blk_rq_map_user().
- * rq->bio must be set to the original head of the request.
+ * Unmap a rq previously mapped by blk_rq_map_user(). The caller must
+ * supply the original rq->bio from the blk_rq_map_user() return, since
+ * the io completion may have changed rq->bio.
*/
-int blk_rq_unmap_user(struct request *rq)
+int blk_rq_unmap_user(struct bio *bio)
{
- struct bio *bio, *mapped_bio;
+ struct bio *mapped_bio;
+ int ret = 0, ret2;
- while ((bio = rq->bio)) {
- if (bio_flagged(bio, BIO_BOUNCED))
+ while (bio) {
+ mapped_bio = bio;
+ if (unlikely(bio_flagged(bio, BIO_BOUNCED)))
mapped_bio = bio->bi_private;
- else
- mapped_bio = bio;
- __blk_rq_unmap_user(mapped_bio);
- rq->bio = bio->bi_next;
- bio_put(bio);
+ ret2 = __blk_rq_unmap_user(mapped_bio);
+ if (ret2 && !ret)
+ ret = ret2;
+
+ mapped_bio = bio;
+ bio = bio->bi_next;
+ bio_put(mapped_bio);
}
- return 0;
+
+ return ret;
}
EXPORT_SYMBOL(blk_rq_unmap_user);
@@ -2694,9 +2685,6 @@ static inline void add_request(request_queue_t * q, struct request * req)
{
drive_stat_acct(req, req->nr_sectors, 1);
- if (q->activity_fn)
- q->activity_fn(q->activity_data, rq_data_dir(req));
-
/*
* elevator indicated where it wants this request to be
* inserted at elevator_merge time
@@ -2830,7 +2818,7 @@ static int attempt_merge(request_queue_t *q, struct request *req,
* will have updated segment counts, update sector
* counts here.
*/
- if (!q->merge_requests_fn(q, req, next))
+ if (!ll_merge_requests_fn(q, req, next))
return 0;
/*
@@ -2920,6 +2908,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
int el_ret, nr_sectors, barrier, err;
const unsigned short prio = bio_prio(bio);
const int sync = bio_sync(bio);
+ int rw_flags;
nr_sectors = bio_sectors(bio);
@@ -2946,7 +2935,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
case ELEVATOR_BACK_MERGE:
BUG_ON(!rq_mergeable(req));
- if (!q->back_merge_fn(q, req, bio))
+ if (!ll_back_merge_fn(q, req, bio))
break;
blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
@@ -2963,7 +2952,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
case ELEVATOR_FRONT_MERGE:
BUG_ON(!rq_mergeable(req));
- if (!q->front_merge_fn(q, req, bio))
+ if (!ll_front_merge_fn(q, req, bio))
break;
blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
@@ -2994,10 +2983,19 @@ static int __make_request(request_queue_t *q, struct bio *bio)
get_rq:
/*
+ * This sync check and mask will be re-done in init_request_from_bio(),
+ * but we need to set it earlier to expose the sync flag to the
+ * rq allocator and io schedulers.
+ */
+ rw_flags = bio_data_dir(bio);
+ if (sync)
+ rw_flags |= REQ_RW_SYNC;
+
+ /*
* Grab a free request. This is might sleep but can not fail.
* Returns with the queue unlocked.
*/
- req = get_request_wait(q, bio_data_dir(bio), bio);
+ req = get_request_wait(q, rw_flags, bio);
/*
* After dropping the lock and possibly sleeping here, our request
@@ -3056,6 +3054,42 @@ static void handle_bad_sector(struct bio *bio)
set_bit(BIO_EOF, &bio->bi_flags);
}
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+
+static DECLARE_FAULT_ATTR(fail_make_request);
+
+static int __init setup_fail_make_request(char *str)
+{
+ return setup_fault_attr(&fail_make_request, str);
+}
+__setup("fail_make_request=", setup_fail_make_request);
+
+static int should_fail_request(struct bio *bio)
+{
+ if ((bio->bi_bdev->bd_disk->flags & GENHD_FL_FAIL) ||
+ (bio->bi_bdev->bd_part && bio->bi_bdev->bd_part->make_it_fail))
+ return should_fail(&fail_make_request, bio->bi_size);
+
+ return 0;
+}
+
+static int __init fail_make_request_debugfs(void)
+{
+ return init_fault_attr_dentries(&fail_make_request,
+ "fail_make_request");
+}
+
+late_initcall(fail_make_request_debugfs);
+
+#else /* CONFIG_FAIL_MAKE_REQUEST */
+
+static inline int should_fail_request(struct bio *bio)
+{
+ return 0;
+}
+
+#endif /* CONFIG_FAIL_MAKE_REQUEST */
+
/**
* generic_make_request: hand a buffer to its device driver for I/O
* @bio: The bio describing the location in memory and on the device.
@@ -3141,6 +3175,9 @@ end_io:
if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)))
goto end_io;
+ if (should_fail_request(bio))
+ goto end_io;
+
/*
* If this device has partitions, remap block n
* of partition p to block n+start(p) of the disk.
@@ -3195,10 +3232,12 @@ void submit_bio(int rw, struct bio *bio)
BIO_BUG_ON(!bio->bi_size);
BIO_BUG_ON(!bio->bi_io_vec);
bio->bi_rw |= rw;
- if (rw & WRITE)
+ if (rw & WRITE) {
count_vm_events(PGPGOUT, count);
- else
+ } else {
+ task_io_account_read(bio->bi_size);
count_vm_events(PGPGIN, count);
+ }
if (unlikely(block_dump)) {
char b[BDEVNAME_SIZE];
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index b3e210723a7..65c6a3cba6d 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -223,11 +223,12 @@ static int verify_command(struct file *file, unsigned char *cmd)
static int sg_io(struct file *file, request_queue_t *q,
struct gendisk *bd_disk, struct sg_io_hdr *hdr)
{
- unsigned long start_time;
+ unsigned long start_time, timeout;
int writing = 0, ret = 0;
struct request *rq;
char sense[SCSI_SENSE_BUFFERSIZE];
unsigned char cmd[BLK_MAX_CDB];
+ struct bio *bio;
if (hdr->interface_id != 'S')
return -EINVAL;
@@ -270,14 +271,8 @@ static int sg_io(struct file *file, request_queue_t *q,
rq->cmd_type = REQ_TYPE_BLOCK_PC;
- /*
- * bounce this after holding a reference to the original bio, it's
- * needed for proper unmapping
- */
- if (rq->bio)
- blk_queue_bounce(q, &rq->bio);
-
- rq->timeout = jiffies_to_msecs(hdr->timeout);
+ timeout = msecs_to_jiffies(hdr->timeout);
+ rq->timeout = (timeout < INT_MAX) ? timeout : INT_MAX;
if (!rq->timeout)
rq->timeout = q->sg_timeout;
if (!rq->timeout)
@@ -308,6 +303,7 @@ static int sg_io(struct file *file, request_queue_t *q,
if (ret)
goto out;
+ bio = rq->bio;
rq->retries = 0;
start_time = jiffies;
@@ -338,7 +334,7 @@ static int sg_io(struct file *file, request_queue_t *q,
hdr->sb_len_wr = len;
}
- if (blk_rq_unmap_user(rq))
+ if (blk_rq_unmap_user(bio))
ret = -EFAULT;
/* may not have succeeded, but output values written to control
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 92ba249f3a5..086fcec4472 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -74,14 +74,6 @@ config CRYPTO_SHA1
help
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
-config CRYPTO_SHA1_S390
- tristate "SHA1 digest algorithm (s390)"
- depends on S390
- select CRYPTO_ALGAPI
- help
- This is the s390 hardware accelerated implementation of the
- SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
-
config CRYPTO_SHA256
tristate "SHA256 digest algorithm"
select CRYPTO_ALGAPI
@@ -91,17 +83,6 @@ config CRYPTO_SHA256
This version of SHA implements a 256 bit hash with 128 bits of
security against collision attacks.
-config CRYPTO_SHA256_S390
- tristate "SHA256 digest algorithm (s390)"
- depends on S390
- select CRYPTO_ALGAPI
- help
- This is the s390 hardware accelerated implementation of the
- SHA256 secure hash standard (DFIPS 180-2).
-
- This version of SHA implements a 256 bit hash with 128 bits of
- security against collision attacks.
-
config CRYPTO_SHA512
tristate "SHA384 and SHA512 digest algorithms"
select CRYPTO_ALGAPI
@@ -168,6 +149,15 @@ config CRYPTO_CBC
CBC: Cipher Block Chaining mode
This block cipher algorithm is required for IPSec.
+config CRYPTO_PCBC
+ tristate "PCBC support"
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_MANAGER
+ default m
+ help
+ PCBC: Propagating Cipher Block Chaining mode
+ This block cipher algorithm is required for RxRPC.
+
config CRYPTO_LRW
tristate "LRW support (EXPERIMENTAL)"
depends on EXPERIMENTAL
@@ -187,13 +177,12 @@ config CRYPTO_DES
help
DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
-config CRYPTO_DES_S390
- tristate "DES and Triple DES cipher algorithms (s390)"
- depends on S390
+config CRYPTO_FCRYPT
+ tristate "FCrypt cipher algorithm"
select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
help
- DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+ FCrypt algorithm used by RxRPC.
config CRYPTO_BLOWFISH
tristate "Blowfish cipher algorithm"
@@ -336,28 +325,6 @@ config CRYPTO_AES_X86_64
See <http://csrc.nist.gov/encryption/aes/> for more information.
-config CRYPTO_AES_S390
- tristate "AES cipher algorithms (s390)"
- depends on S390
- select CRYPTO_ALGAPI
- select CRYPTO_BLKCIPHER
- help
- This is the s390 hardware accelerated implementation of the
- AES cipher algorithms (FIPS-197). AES uses the Rijndael
- algorithm.
-
- Rijndael appears to be consistently a very good performer in
- both hardware and software across a wide range of computing
- environments regardless of its use in feedback or non-feedback
- modes. Its key setup time is excellent, and its key agility is
- good. Rijndael's very low memory requirements make it very well
- suited for restricted-space environments, in which it also
- demonstrates excellent performance. Rijndael's operations are
- among the easiest to defend against power and timing attacks.
-
- On s390 the System z9-109 currently only supports the key size
- of 128 bit.
-
config CRYPTO_CAST5
tristate "CAST5 (CAST-128) cipher algorithm"
select CRYPTO_ALGAPI
@@ -458,6 +425,21 @@ config CRYPTO_CRC32C
See Castagnoli93. This implementation uses lib/libcrc32c.
Module will be crc32c.
+config CRYPTO_CAMELLIA
+ tristate "Camellia cipher algorithms"
+ depends on CRYPTO
+ select CRYPTO_ALGAPI
+ help
+ Camellia cipher algorithms module.
+
+ Camellia is a symmetric key block cipher developed jointly
+ at NTT and Mitsubishi Electric Corporation.
+
+ The Camellia specifies three key sizes: 128, 192 and 256 bits.
+
+ See also:
+ <https://info.isl.ntt.co.jp/crypt/eng/camellia/index_s.html>
+
config CRYPTO_TEST
tristate "Testing module"
depends on m
diff --git a/crypto/Makefile b/crypto/Makefile
index 60e3d24f61f..12f93f57817 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -27,13 +27,16 @@ obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o
obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o
obj-$(CONFIG_CRYPTO_ECB) += ecb.o
obj-$(CONFIG_CRYPTO_CBC) += cbc.o
+obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
obj-$(CONFIG_CRYPTO_LRW) += lrw.o
obj-$(CONFIG_CRYPTO_DES) += des.o
+obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o
obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o
obj-$(CONFIG_CRYPTO_AES) += aes.o
+obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia.o
obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
obj-$(CONFIG_CRYPTO_CAST6) += cast6.o
obj-$(CONFIG_CRYPTO_ARC4) += arc4.o
diff --git a/crypto/algapi.c b/crypto/algapi.c
index c91530021e9..f7d2185b2c8 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -377,7 +377,8 @@ void crypto_drop_spawn(struct crypto_spawn *spawn)
}
EXPORT_SYMBOL_GPL(crypto_drop_spawn);
-struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn)
+struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
+ u32 mask)
{
struct crypto_alg *alg;
struct crypto_alg *alg2;
@@ -396,10 +397,18 @@ struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn)
return ERR_PTR(-EAGAIN);
}
- tfm = __crypto_alloc_tfm(alg, 0);
+ tfm = ERR_PTR(-EINVAL);
+ if (unlikely((alg->cra_flags ^ type) & mask))
+ goto out_put_alg;
+
+ tfm = __crypto_alloc_tfm(alg, type, mask);
if (IS_ERR(tfm))
- crypto_mod_put(alg);
+ goto out_put_alg;
+
+ return tfm;
+out_put_alg:
+ crypto_mod_put(alg);
return tfm;
}
EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
diff --git a/crypto/api.c b/crypto/api.c
index 8c446871cd5..55af8bb0f05 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -212,31 +212,12 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
}
EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup);
-static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
+static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
{
- tfm->crt_flags = flags & CRYPTO_TFM_REQ_MASK;
- flags &= ~CRYPTO_TFM_REQ_MASK;
-
- switch (crypto_tfm_alg_type(tfm)) {
- case CRYPTO_ALG_TYPE_CIPHER:
- return crypto_init_cipher_flags(tfm, flags);
-
- case CRYPTO_ALG_TYPE_DIGEST:
- return crypto_init_digest_flags(tfm, flags);
-
- case CRYPTO_ALG_TYPE_COMPRESS:
- return crypto_init_compress_flags(tfm, flags);
- }
-
- return 0;
-}
+ const struct crypto_type *type_obj = tfm->__crt_alg->cra_type;
-static int crypto_init_ops(struct crypto_tfm *tfm)
-{
- const struct crypto_type *type = tfm->__crt_alg->cra_type;
-
- if (type)
- return type->init(tfm);
+ if (type_obj)
+ return type_obj->init(tfm, type, mask);
switch (crypto_tfm_alg_type(tfm)) {
case CRYPTO_ALG_TYPE_CIPHER:
@@ -285,29 +266,29 @@ static void crypto_exit_ops(struct crypto_tfm *tfm)
}
}
-static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags)
+static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask)
{
- const struct crypto_type *type = alg->cra_type;
+ const struct crypto_type *type_obj = alg->cra_type;
unsigned int len;
len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1);
- if (type)
- return len + type->ctxsize(alg);
+ if (type_obj)
+ return len + type_obj->ctxsize(alg, type, mask);
switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
default:
BUG();
case CRYPTO_ALG_TYPE_CIPHER:
- len += crypto_cipher_ctxsize(alg, flags);
+ len += crypto_cipher_ctxsize(alg);
break;
case CRYPTO_ALG_TYPE_DIGEST:
- len += crypto_digest_ctxsize(alg, flags);
+ len += crypto_digest_ctxsize(alg);
break;
case CRYPTO_ALG_TYPE_COMPRESS:
- len += crypto_compress_ctxsize(alg, flags);
+ len += crypto_compress_ctxsize(alg);
break;
}
@@ -322,24 +303,21 @@ void crypto_shoot_alg(struct crypto_alg *alg)
}
EXPORT_SYMBOL_GPL(crypto_shoot_alg);
-struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags)
+struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
+ u32 mask)
{
struct crypto_tfm *tfm = NULL;
unsigned int tfm_size;
int err = -ENOMEM;
- tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags);
+ tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, type, mask);
tfm = kzalloc(tfm_size, GFP_KERNEL);
if (tfm == NULL)
goto out_err;
tfm->__crt_alg = alg;
- err = crypto_init_flags(tfm, flags);
- if (err)
- goto out_free_tfm;
-
- err = crypto_init_ops(tfm);
+ err = crypto_init_ops(tfm, type, mask);
if (err)
goto out_free_tfm;
@@ -362,31 +340,6 @@ out:
}
EXPORT_SYMBOL_GPL(__crypto_alloc_tfm);
-struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
-{
- struct crypto_tfm *tfm = NULL;
- int err;
-
- do {
- struct crypto_alg *alg;
-
- alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC);
- err = PTR_ERR(alg);
- if (IS_ERR(alg))
- continue;
-
- tfm = __crypto_alloc_tfm(alg, flags);
- err = 0;
- if (IS_ERR(tfm)) {
- crypto_mod_put(alg);
- err = PTR_ERR(tfm);
- tfm = NULL;
- }
- } while (err == -EAGAIN && !signal_pending(current));
-
- return tfm;
-}
-
/*
* crypto_alloc_base - Locate algorithm and allocate transform
* @alg_name: Name of algorithm
@@ -420,7 +373,7 @@ struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask)
goto err;
}
- tfm = __crypto_alloc_tfm(alg, 0);
+ tfm = __crypto_alloc_tfm(alg, type, mask);
if (!IS_ERR(tfm))
return tfm;
@@ -466,7 +419,6 @@ void crypto_free_tfm(struct crypto_tfm *tfm)
kfree(tfm);
}
-EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
EXPORT_SYMBOL_GPL(crypto_free_tfm);
int crypto_has_alg(const char *name, u32 type, u32 mask)
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index 034c939bf91..b5befe8c3a9 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -16,8 +16,8 @@
#include <linux/crypto.h>
#include <linux/errno.h>
+#include <linux/hardirq.h>
#include <linux/kernel.h>
-#include <linux/io.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/seq_file.h>
@@ -314,6 +314,9 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc,
struct crypto_blkcipher *tfm = desc->tfm;
unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
+ if (WARN_ON_ONCE(in_irq()))
+ return -EDEADLK;
+
walk->nbytes = walk->total;
if (unlikely(!walk->total))
return 0;
@@ -346,7 +349,8 @@ static int setkey(struct crypto_tfm *tfm, const u8 *key,
return cipher->setkey(tfm, key, keylen);
}
-static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg)
+static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type,
+ u32 mask)
{
struct blkcipher_alg *cipher = &alg->cra_blkcipher;
unsigned int len = alg->cra_ctxsize;
@@ -359,7 +363,7 @@ static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg)
return len;
}
-static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm)
+static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
{
struct blkcipher_tfm *crt = &tfm->crt_blkcipher;
struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
diff --git a/crypto/camellia.c b/crypto/camellia.c
new file mode 100644
index 00000000000..6877ecfd90b
--- /dev/null
+++ b/crypto/camellia.c
@@ -0,0 +1,1801 @@
+/*
+ * Copyright (C) 2006
+ * NTT (Nippon Telegraph and Telephone 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.
+ */
+
+/*
+ * Algorithm Specification
+ * http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html
+ */
+
+/*
+ *
+ * NOTE --- NOTE --- NOTE --- NOTE
+ * This implementation assumes that all memory addresses passed
+ * as parameters are four-byte aligned.
+ *
+ */
+
+#include <linux/crypto.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+
+#define CAMELLIA_MIN_KEY_SIZE 16
+#define CAMELLIA_MAX_KEY_SIZE 32
+#define CAMELLIA_BLOCK_SIZE 16
+#define CAMELLIA_TABLE_BYTE_LEN 272
+#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4)
+
+typedef u32 KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN];
+
+
+/* key constants */
+
+#define CAMELLIA_SIGMA1L (0xA09E667FL)
+#define CAMELLIA_SIGMA1R (0x3BCC908BL)
+#define CAMELLIA_SIGMA2L (0xB67AE858L)
+#define CAMELLIA_SIGMA2R (0x4CAA73B2L)
+#define CAMELLIA_SIGMA3L (0xC6EF372FL)
+#define CAMELLIA_SIGMA3R (0xE94F82BEL)
+#define CAMELLIA_SIGMA4L (0x54FF53A5L)
+#define CAMELLIA_SIGMA4R (0xF1D36F1CL)
+#define CAMELLIA_SIGMA5L (0x10E527FAL)
+#define CAMELLIA_SIGMA5R (0xDE682D1DL)
+#define CAMELLIA_SIGMA6L (0xB05688C2L)
+#define CAMELLIA_SIGMA6R (0xB3E6C1FDL)
+
+struct camellia_ctx {
+ int key_length;
+ KEY_TABLE_TYPE key_table;
+};
+
+
+/*
+ * macros
+ */
+
+
+# define GETU32(pt) (((u32)(pt)[0] << 24) \
+ ^ ((u32)(pt)[1] << 16) \
+ ^ ((u32)(pt)[2] << 8) \
+ ^ ((u32)(pt)[3]))
+
+#define COPY4WORD(dst, src) \
+ do { \
+ (dst)[0]=(src)[0]; \
+ (dst)[1]=(src)[1]; \
+ (dst)[2]=(src)[2]; \
+ (dst)[3]=(src)[3]; \
+ }while(0)
+
+#define SWAP4WORD(word) \
+ do { \
+ CAMELLIA_SWAP4((word)[0]); \
+ CAMELLIA_SWAP4((word)[1]); \
+ CAMELLIA_SWAP4((word)[2]); \
+ CAMELLIA_SWAP4((word)[3]); \
+ }while(0)
+
+#define XOR4WORD(a, b)/* a = a ^ b */ \
+ do { \
+ (a)[0]^=(b)[0]; \
+ (a)[1]^=(b)[1]; \
+ (a)[2]^=(b)[2]; \
+ (a)[3]^=(b)[3]; \
+ }while(0)
+
+#define XOR4WORD2(a, b, c)/* a = b ^ c */ \
+ do { \
+ (a)[0]=(b)[0]^(c)[0]; \
+ (a)[1]=(b)[1]^(c)[1]; \
+ (a)[2]=(b)[2]^(c)[2]; \
+ (a)[3]=(b)[3]^(c)[3]; \
+ }while(0)
+
+#define CAMELLIA_SUBKEY_L(INDEX) (subkey[(INDEX)*2])
+#define CAMELLIA_SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1])
+
+/* rotation right shift 1byte */
+#define CAMELLIA_RR8(x) (((x) >> 8) + ((x) << 24))
+/* rotation left shift 1bit */
+#define CAMELLIA_RL1(x) (((x) << 1) + ((x) >> 31))
+/* rotation left shift 1byte */
+#define CAMELLIA_RL8(x) (((x) << 8) + ((x) >> 24))
+
+#define CAMELLIA_ROLDQ(ll, lr, rl, rr, w0, w1, bits) \
+ do { \
+ w0 = ll; \
+ ll = (ll << bits) + (lr >> (32 - bits)); \
+ lr = (lr << bits) + (rl >> (32 - bits)); \
+ rl = (rl << bits) + (rr >> (32 - bits)); \
+ rr = (rr << bits) + (w0 >> (32 - bits)); \
+ } while(0)
+
+#define CAMELLIA_ROLDQo32(ll, lr, rl, rr, w0, w1, bits) \
+ do { \
+ w0 = ll; \
+ w1 = lr; \
+ ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \
+ lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \
+ rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \
+ rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \
+ } while(0)
+
+#define CAMELLIA_SP1110(INDEX) (camellia_sp1110[(INDEX)])
+#define CAMELLIA_SP0222(INDEX) (camellia_sp0222[(INDEX)])
+#define CAMELLIA_SP3033(INDEX) (camellia_sp3033[(INDEX)])
+#define CAMELLIA_SP4404(INDEX) (camellia_sp4404[(INDEX)])
+
+#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \
+ do { \
+ il = xl ^ kl; \
+ ir = xr ^ kr; \
+ t0 = il >> 16; \
+ t1 = ir >> 16; \
+ yl = CAMELLIA_SP1110(ir & 0xff) \
+ ^ CAMELLIA_SP0222((t1 >> 8) & 0xff) \
+ ^ CAMELLIA_SP3033(t1 & 0xff) \
+ ^ CAMELLIA_SP4404((ir >> 8) & 0xff); \
+ yr = CAMELLIA_SP1110((t0 >> 8) & 0xff) \
+ ^ CAMELLIA_SP0222(t0 & 0xff) \
+ ^ CAMELLIA_SP3033((il >> 8) & 0xff) \
+ ^ CAMELLIA_SP4404(il & 0xff); \
+ yl ^= yr; \
+ yr = CAMELLIA_RR8(yr); \
+ yr ^= yl; \
+ } while(0)
+
+
+/*
+ * for speed up
+ *
+ */
+#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \
+ do { \
+ t0 = kll; \
+ t2 = krr; \
+ t0 &= ll; \
+ t2 |= rr; \
+ rl ^= t2; \
+ lr ^= CAMELLIA_RL1(t0); \
+ t3 = krl; \
+ t1 = klr; \
+ t3 &= rl; \
+ t1 |= lr; \
+ ll ^= t1; \
+ rr ^= CAMELLIA_RL1(t3); \
+ } while(0)
+
+#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \
+ do { \
+ ir = CAMELLIA_SP1110(xr & 0xff); \
+ il = CAMELLIA_SP1110((xl>>24) & 0xff); \
+ ir ^= CAMELLIA_SP0222((xr>>24) & 0xff); \
+ il ^= CAMELLIA_SP0222((xl>>16) & 0xff); \
+ ir ^= CAMELLIA_SP3033((xr>>16) & 0xff); \
+ il ^= CAMELLIA_SP3033((xl>>8) & 0xff); \
+ ir ^= CAMELLIA_SP4404((xr>>8) & 0xff); \
+ il ^= CAMELLIA_SP4404(xl & 0xff); \
+ il ^= kl; \
+ ir ^= il ^ kr; \
+ yl ^= ir; \
+ yr ^= CAMELLIA_RR8(il) ^ ir; \
+ } while(0)
+
+/**
+ * Stuff related to the Camellia key schedule
+ */
+#define SUBL(x) subL[(x)]
+#define SUBR(x) subR[(x)]
+
+
+static const u32 camellia_sp1110[256] = {
+ 0x70707000,0x82828200,0x2c2c2c00,0xececec00,
+ 0xb3b3b300,0x27272700,0xc0c0c000,0xe5e5e500,
+ 0xe4e4e400,0x85858500,0x57575700,0x35353500,
+ 0xeaeaea00,0x0c0c0c00,0xaeaeae00,0x41414100,
+ 0x23232300,0xefefef00,0x6b6b6b00,0x93939300,
+ 0x45454500,0x19191900,0xa5a5a500,0x21212100,
+ 0xededed00,0x0e0e0e00,0x4f4f4f00,0x4e4e4e00,
+ 0x1d1d1d00,0x65656500,0x92929200,0xbdbdbd00,
+ 0x86868600,0xb8b8b800,0xafafaf00,0x8f8f8f00,
+ 0x7c7c7c00,0xebebeb00,0x1f1f1f00,0xcecece00,
+ 0x3e3e3e00,0x30303000,0xdcdcdc00,0x5f5f5f00,
+ 0x5e5e5e00,0xc5c5c500,0x0b0b0b00,0x1a1a1a00,
+ 0xa6a6a600,0xe1e1e100,0x39393900,0xcacaca00,
+ 0xd5d5d500,0x47474700,0x5d5d5d00,0x3d3d3d00,
+ 0xd9d9d900,0x01010100,0x5a5a5a00,0xd6d6d600,
+ 0x51515100,0x56565600,0x6c6c6c00,0x4d4d4d00,
+ 0x8b8b8b00,0x0d0d0d00,0x9a9a9a00,0x66666600,
+ 0xfbfbfb00,0xcccccc00,0xb0b0b000,0x2d2d2d00,
+ 0x74747400,0x12121200,0x2b2b2b00,0x20202000,
+ 0xf0f0f000,0xb1b1b100,0x84848400,0x99999900,
+ 0xdfdfdf00,0x4c4c4c00,0xcbcbcb00,0xc2c2c200,
+ 0x34343400,0x7e7e7e00,0x76767600,0x05050500,
+ 0x6d6d6d00,0xb7b7b700,0xa9a9a900,0x31313100,
+ 0xd1d1d100,0x17171700,0x04040400,0xd7d7d700,
+ 0x14141400,0x58585800,0x3a3a3a00,0x61616100,
+ 0xdedede00,0x1b1b1b00,0x11111100,0x1c1c1c00,
+ 0x32323200,0x0f0f0f00,0x9c9c9c00,0x16161600,
+ 0x53535300,0x18181800,0xf2f2f200,0x22222200,
+ 0xfefefe00,0x44444400,0xcfcfcf00,0xb2b2b200,
+ 0xc3c3c300,0xb5b5b500,0x7a7a7a00,0x91919100,
+ 0x24242400,0x08080800,0xe8e8e800,0xa8a8a800,
+ 0x60606000,0xfcfcfc00,0x69696900,0x50505000,
+ 0xaaaaaa00,0xd0d0d000,0xa0a0a000,0x7d7d7d00,
+ 0xa1a1a100,0x89898900,0x62626200,0x97979700,
+ 0x54545400,0x5b5b5b00,0x1e1e1e00,0x95959500,
+ 0xe0e0e000,0xffffff00,0x64646400,0xd2d2d200,
+ 0x10101000,0xc4c4c400,0x00000000,0x48484800,
+ 0xa3a3a300,0xf7f7f700,0x75757500,0xdbdbdb00,
+ 0x8a8a8a00,0x03030300,0xe6e6e600,0xdadada00,
+ 0x09090900,0x3f3f3f00,0xdddddd00,0x94949400,
+ 0x87878700,0x5c5c5c00,0x83838300,0x02020200,
+ 0xcdcdcd00,0x4a4a4a00,0x90909000,0x33333300,
+ 0x73737300,0x67676700,0xf6f6f600,0xf3f3f300,
+ 0x9d9d9d00,0x7f7f7f00,0xbfbfbf00,0xe2e2e200,
+ 0x52525200,0x9b9b9b00,0xd8d8d800,0x26262600,
+ 0xc8c8c800,0x37373700,0xc6c6c600,0x3b3b3b00,
+ 0x81818100,0x96969600,0x6f6f6f00,0x4b4b4b00,
+ 0x13131300,0xbebebe00,0x63636300,0x2e2e2e00,
+ 0xe9e9e900,0x79797900,0xa7a7a700,0x8c8c8c00,
+ 0x9f9f9f00,0x6e6e6e00,0xbcbcbc00,0x8e8e8e00,
+ 0x29292900,0xf5f5f500,0xf9f9f900,0xb6b6b600,
+ 0x2f2f2f00,0xfdfdfd00,0xb4b4b400,0x59595900,
+ 0x78787800,0x98989800,0x06060600,0x6a6a6a00,
+ 0xe7e7e700,0x46464600,0x71717100,0xbababa00,
+ 0xd4d4d400,0x25252500,0xababab00,0x42424200,
+ 0x88888800,0xa2a2a200,0x8d8d8d00,0xfafafa00,
+ 0x72727200,0x07070700,0xb9b9b900,0x55555500,
+ 0xf8f8f800,0xeeeeee00,0xacacac00,0x0a0a0a00,
+ 0x36363600,0x49494900,0x2a2a2a00,0x68686800,
+ 0x3c3c3c00,0x38383800,0xf1f1f100,0xa4a4a400,
+ 0x40404000,0x28282800,0xd3d3d300,0x7b7b7b00,
+ 0xbbbbbb00,0xc9c9c900,0x43434300,0xc1c1c100,
+ 0x15151500,0xe3e3e300,0xadadad00,0xf4f4f400,
+ 0x77777700,0xc7c7c700,0x80808000,0x9e9e9e00,
+};
+
+static const u32 camellia_sp0222[256] = {
+ 0x00e0e0e0,0x00050505,0x00585858,0x00d9d9d9,
+ 0x00676767,0x004e4e4e,0x00818181,0x00cbcbcb,
+ 0x00c9c9c9,0x000b0b0b,0x00aeaeae,0x006a6a6a,
+ 0x00d5d5d5,0x00181818,0x005d5d5d,0x00828282,
+ 0x00464646,0x00dfdfdf,0x00d6d6d6,0x00272727,
+ 0x008a8a8a,0x00323232,0x004b4b4b,0x00424242,
+ 0x00dbdbdb,0x001c1c1c,0x009e9e9e,0x009c9c9c,
+ 0x003a3a3a,0x00cacaca,0x00252525,0x007b7b7b,
+ 0x000d0d0d,0x00717171,0x005f5f5f,0x001f1f1f,
+ 0x00f8f8f8,0x00d7d7d7,0x003e3e3e,0x009d9d9d,
+ 0x007c7c7c,0x00606060,0x00b9b9b9,0x00bebebe,
+ 0x00bcbcbc,0x008b8b8b,0x00161616,0x00343434,
+ 0x004d4d4d,0x00c3c3c3,0x00727272,0x00959595,
+ 0x00ababab,0x008e8e8e,0x00bababa,0x007a7a7a,
+ 0x00b3b3b3,0x00020202,0x00b4b4b4,0x00adadad,
+ 0x00a2a2a2,0x00acacac,0x00d8d8d8,0x009a9a9a,
+ 0x00171717,0x001a1a1a,0x00353535,0x00cccccc,
+ 0x00f7f7f7,0x00999999,0x00616161,0x005a5a5a,
+ 0x00e8e8e8,0x00242424,0x00565656,0x00404040,
+ 0x00e1e1e1,0x00636363,0x00090909,0x00333333,
+ 0x00bfbfbf,0x00989898,0x00979797,0x00858585,
+ 0x00686868,0x00fcfcfc,0x00ececec,0x000a0a0a,
+ 0x00dadada,0x006f6f6f,0x00535353,0x00626262,
+ 0x00a3a3a3,0x002e2e2e,0x00080808,0x00afafaf,
+ 0x00282828,0x00b0b0b0,0x00747474,0x00c2c2c2,
+ 0x00bdbdbd,0x00363636,0x00222222,0x00383838,
+ 0x00646464,0x001e1e1e,0x00393939,0x002c2c2c,
+ 0x00a6a6a6,0x00303030,0x00e5e5e5,0x00444444,
+ 0x00fdfdfd,0x00888888,0x009f9f9f,0x00656565,
+ 0x00878787,0x006b6b6b,0x00f4f4f4,0x00232323,
+ 0x00484848,0x00101010,0x00d1d1d1,0x00515151,
+ 0x00c0c0c0,0x00f9f9f9,0x00d2d2d2,0x00a0a0a0,
+ 0x00555555,0x00a1a1a1,0x00414141,0x00fafafa,
+ 0x00434343,0x00131313,0x00c4c4c4,0x002f2f2f,
+ 0x00a8a8a8,0x00b6b6b6,0x003c3c3c,0x002b2b2b,
+ 0x00c1c1c1,0x00ffffff,0x00c8c8c8,0x00a5a5a5,
+ 0x00202020,0x00898989,0x00000000,0x00909090,
+ 0x00474747,0x00efefef,0x00eaeaea,0x00b7b7b7,
+ 0x00151515,0x00060606,0x00cdcdcd,0x00b5b5b5,
+ 0x00121212,0x007e7e7e,0x00bbbbbb,0x00292929,
+ 0x000f0f0f,0x00b8b8b8,0x00070707,0x00040404,
+ 0x009b9b9b,0x00949494,0x00212121,0x00666666,
+ 0x00e6e6e6,0x00cecece,0x00ededed,0x00e7e7e7,
+ 0x003b3b3b,0x00fefefe,0x007f7f7f,0x00c5c5c5,
+ 0x00a4a4a4,0x00373737,0x00b1b1b1,0x004c4c4c,
+ 0x00919191,0x006e6e6e,0x008d8d8d,0x00767676,
+ 0x00030303,0x002d2d2d,0x00dedede,0x00969696,
+ 0x00262626,0x007d7d7d,0x00c6c6c6,0x005c5c5c,
+ 0x00d3d3d3,0x00f2f2f2,0x004f4f4f,0x00191919,
+ 0x003f3f3f,0x00dcdcdc,0x00797979,0x001d1d1d,
+ 0x00525252,0x00ebebeb,0x00f3f3f3,0x006d6d6d,
+ 0x005e5e5e,0x00fbfbfb,0x00696969,0x00b2b2b2,
+ 0x00f0f0f0,0x00313131,0x000c0c0c,0x00d4d4d4,
+ 0x00cfcfcf,0x008c8c8c,0x00e2e2e2,0x00757575,
+ 0x00a9a9a9,0x004a4a4a,0x00575757,0x00848484,
+ 0x00111111,0x00454545,0x001b1b1b,0x00f5f5f5,
+ 0x00e4e4e4,0x000e0e0e,0x00737373,0x00aaaaaa,
+ 0x00f1f1f1,0x00dddddd,0x00595959,0x00141414,
+ 0x006c6c6c,0x00929292,0x00545454,0x00d0d0d0,
+ 0x00787878,0x00707070,0x00e3e3e3,0x00494949,
+ 0x00808080,0x00505050,0x00a7a7a7,0x00f6f6f6,
+ 0x00777777,0x00939393,0x00868686,0x00838383,
+ 0x002a2a2a,0x00c7c7c7,0x005b5b5b,0x00e9e9e9,
+ 0x00eeeeee,0x008f8f8f,0x00010101,0x003d3d3d,
+};
+
+static const u32 camellia_sp3033[256] = {
+ 0x38003838,0x41004141,0x16001616,0x76007676,
+ 0xd900d9d9,0x93009393,0x60006060,0xf200f2f2,
+ 0x72007272,0xc200c2c2,0xab00abab,0x9a009a9a,
+ 0x75007575,0x06000606,0x57005757,0xa000a0a0,
+ 0x91009191,0xf700f7f7,0xb500b5b5,0xc900c9c9,
+ 0xa200a2a2,0x8c008c8c,0xd200d2d2,0x90009090,
+ 0xf600f6f6,0x07000707,0xa700a7a7,0x27002727,
+ 0x8e008e8e,0xb200b2b2,0x49004949,0xde00dede,
+ 0x43004343,0x5c005c5c,0xd700d7d7,0xc700c7c7,
+ 0x3e003e3e,0xf500f5f5,0x8f008f8f,0x67006767,
+ 0x1f001f1f,0x18001818,0x6e006e6e,0xaf00afaf,
+ 0x2f002f2f,0xe200e2e2,0x85008585,0x0d000d0d,
+ 0x53005353,0xf000f0f0,0x9c009c9c,0x65006565,
+ 0xea00eaea,0xa300a3a3,0xae00aeae,0x9e009e9e,
+ 0xec00ecec,0x80008080,0x2d002d2d,0x6b006b6b,
+ 0xa800a8a8,0x2b002b2b,0x36003636,0xa600a6a6,
+ 0xc500c5c5,0x86008686,0x4d004d4d,0x33003333,
+ 0xfd00fdfd,0x66006666,0x58005858,0x96009696,
+ 0x3a003a3a,0x09000909,0x95009595,0x10001010,
+ 0x78007878,0xd800d8d8,0x42004242,0xcc00cccc,
+ 0xef00efef,0x26002626,0xe500e5e5,0x61006161,
+ 0x1a001a1a,0x3f003f3f,0x3b003b3b,0x82008282,
+ 0xb600b6b6,0xdb00dbdb,0xd400d4d4,0x98009898,
+ 0xe800e8e8,0x8b008b8b,0x02000202,0xeb00ebeb,
+ 0x0a000a0a,0x2c002c2c,0x1d001d1d,0xb000b0b0,
+ 0x6f006f6f,0x8d008d8d,0x88008888,0x0e000e0e,
+ 0x19001919,0x87008787,0x4e004e4e,0x0b000b0b,
+ 0xa900a9a9,0x0c000c0c,0x79007979,0x11001111,
+ 0x7f007f7f,0x22002222,0xe700e7e7,0x59005959,
+ 0xe100e1e1,0xda00dada,0x3d003d3d,0xc800c8c8,
+ 0x12001212,0x04000404,0x74007474,0x54005454,
+ 0x30003030,0x7e007e7e,0xb400b4b4,0x28002828,
+ 0x55005555,0x68006868,0x50005050,0xbe00bebe,
+ 0xd000d0d0,0xc400c4c4,0x31003131,0xcb00cbcb,
+ 0x2a002a2a,0xad00adad,0x0f000f0f,0xca00caca,
+ 0x70007070,0xff00ffff,0x32003232,0x69006969,
+ 0x08000808,0x62006262,0x00000000,0x24002424,
+ 0xd100d1d1,0xfb00fbfb,0xba00baba,0xed00eded,
+ 0x45004545,0x81008181,0x73007373,0x6d006d6d,
+ 0x84008484,0x9f009f9f,0xee00eeee,0x4a004a4a,
+ 0xc300c3c3,0x2e002e2e,0xc100c1c1,0x01000101,
+ 0xe600e6e6,0x25002525,0x48004848,0x99009999,
+ 0xb900b9b9,0xb300b3b3,0x7b007b7b,0xf900f9f9,
+ 0xce00cece,0xbf00bfbf,0xdf00dfdf,0x71007171,
+ 0x29002929,0xcd00cdcd,0x6c006c6c,0x13001313,
+ 0x64006464,0x9b009b9b,0x63006363,0x9d009d9d,
+ 0xc000c0c0,0x4b004b4b,0xb700b7b7,0xa500a5a5,
+ 0x89008989,0x5f005f5f,0xb100b1b1,0x17001717,
+ 0xf400f4f4,0xbc00bcbc,0xd300d3d3,0x46004646,
+ 0xcf00cfcf,0x37003737,0x5e005e5e,0x47004747,
+ 0x94009494,0xfa00fafa,0xfc00fcfc,0x5b005b5b,
+ 0x97009797,0xfe00fefe,0x5a005a5a,0xac00acac,
+ 0x3c003c3c,0x4c004c4c,0x03000303,0x35003535,
+ 0xf300f3f3,0x23002323,0xb800b8b8,0x5d005d5d,
+ 0x6a006a6a,0x92009292,0xd500d5d5,0x21002121,
+ 0x44004444,0x51005151,0xc600c6c6,0x7d007d7d,
+ 0x39003939,0x83008383,0xdc00dcdc,0xaa00aaaa,
+ 0x7c007c7c,0x77007777,0x56005656,0x05000505,
+ 0x1b001b1b,0xa400a4a4,0x15001515,0x34003434,
+ 0x1e001e1e,0x1c001c1c,0xf800f8f8,0x52005252,
+ 0x20002020,0x14001414,0xe900e9e9,0xbd00bdbd,
+ 0xdd00dddd,0xe400e4e4,0xa100a1a1,0xe000e0e0,
+ 0x8a008a8a,0xf100f1f1,0xd600d6d6,0x7a007a7a,
+ 0xbb00bbbb,0xe300e3e3,0x40004040,0x4f004f4f,
+};
+
+static const u32 camellia_sp4404[256] = {
+ 0x70700070,0x2c2c002c,0xb3b300b3,0xc0c000c0,
+ 0xe4e400e4,0x57570057,0xeaea00ea,0xaeae00ae,
+ 0x23230023,0x6b6b006b,0x45450045,0xa5a500a5,
+ 0xeded00ed,0x4f4f004f,0x1d1d001d,0x92920092,
+ 0x86860086,0xafaf00af,0x7c7c007c,0x1f1f001f,
+ 0x3e3e003e,0xdcdc00dc,0x5e5e005e,0x0b0b000b,
+ 0xa6a600a6,0x39390039,0xd5d500d5,0x5d5d005d,
+ 0xd9d900d9,0x5a5a005a,0x51510051,0x6c6c006c,
+ 0x8b8b008b,0x9a9a009a,0xfbfb00fb,0xb0b000b0,
+ 0x74740074,0x2b2b002b,0xf0f000f0,0x84840084,
+ 0xdfdf00df,0xcbcb00cb,0x34340034,0x76760076,
+ 0x6d6d006d,0xa9a900a9,0xd1d100d1,0x04040004,
+ 0x14140014,0x3a3a003a,0xdede00de,0x11110011,
+ 0x32320032,0x9c9c009c,0x53530053,0xf2f200f2,
+ 0xfefe00fe,0xcfcf00cf,0xc3c300c3,0x7a7a007a,
+ 0x24240024,0xe8e800e8,0x60600060,0x69690069,
+ 0xaaaa00aa,0xa0a000a0,0xa1a100a1,0x62620062,
+ 0x54540054,0x1e1e001e,0xe0e000e0,0x64640064,
+ 0x10100010,0x00000000,0xa3a300a3,0x75750075,
+ 0x8a8a008a,0xe6e600e6,0x09090009,0xdddd00dd,
+ 0x87870087,0x83830083,0xcdcd00cd,0x90900090,
+ 0x73730073,0xf6f600f6,0x9d9d009d,0xbfbf00bf,
+ 0x52520052,0xd8d800d8,0xc8c800c8,0xc6c600c6,
+ 0x81810081,0x6f6f006f,0x13130013,0x63630063,
+ 0xe9e900e9,0xa7a700a7,0x9f9f009f,0xbcbc00bc,
+ 0x29290029,0xf9f900f9,0x2f2f002f,0xb4b400b4,
+ 0x78780078,0x06060006,0xe7e700e7,0x71710071,
+ 0xd4d400d4,0xabab00ab,0x88880088,0x8d8d008d,
+ 0x72720072,0xb9b900b9,0xf8f800f8,0xacac00ac,
+ 0x36360036,0x2a2a002a,0x3c3c003c,0xf1f100f1,
+ 0x40400040,0xd3d300d3,0xbbbb00bb,0x43430043,
+ 0x15150015,0xadad00ad,0x77770077,0x80800080,
+ 0x82820082,0xecec00ec,0x27270027,0xe5e500e5,
+ 0x85850085,0x35350035,0x0c0c000c,0x41410041,
+ 0xefef00ef,0x93930093,0x19190019,0x21210021,
+ 0x0e0e000e,0x4e4e004e,0x65650065,0xbdbd00bd,
+ 0xb8b800b8,0x8f8f008f,0xebeb00eb,0xcece00ce,
+ 0x30300030,0x5f5f005f,0xc5c500c5,0x1a1a001a,
+ 0xe1e100e1,0xcaca00ca,0x47470047,0x3d3d003d,
+ 0x01010001,0xd6d600d6,0x56560056,0x4d4d004d,
+ 0x0d0d000d,0x66660066,0xcccc00cc,0x2d2d002d,
+ 0x12120012,0x20200020,0xb1b100b1,0x99990099,
+ 0x4c4c004c,0xc2c200c2,0x7e7e007e,0x05050005,
+ 0xb7b700b7,0x31310031,0x17170017,0xd7d700d7,
+ 0x58580058,0x61610061,0x1b1b001b,0x1c1c001c,
+ 0x0f0f000f,0x16160016,0x18180018,0x22220022,
+ 0x44440044,0xb2b200b2,0xb5b500b5,0x91910091,
+ 0x08080008,0xa8a800a8,0xfcfc00fc,0x50500050,
+ 0xd0d000d0,0x7d7d007d,0x89890089,0x97970097,
+ 0x5b5b005b,0x95950095,0xffff00ff,0xd2d200d2,
+ 0xc4c400c4,0x48480048,0xf7f700f7,0xdbdb00db,
+ 0x03030003,0xdada00da,0x3f3f003f,0x94940094,
+ 0x5c5c005c,0x02020002,0x4a4a004a,0x33330033,
+ 0x67670067,0xf3f300f3,0x7f7f007f,0xe2e200e2,
+ 0x9b9b009b,0x26260026,0x37370037,0x3b3b003b,
+ 0x96960096,0x4b4b004b,0xbebe00be,0x2e2e002e,
+ 0x79790079,0x8c8c008c,0x6e6e006e,0x8e8e008e,
+ 0xf5f500f5,0xb6b600b6,0xfdfd00fd,0x59590059,
+ 0x98980098,0x6a6a006a,0x46460046,0xbaba00ba,
+ 0x25250025,0x42420042,0xa2a200a2,0xfafa00fa,
+ 0x07070007,0x55550055,0xeeee00ee,0x0a0a000a,
+ 0x49490049,0x68680068,0x38380038,0xa4a400a4,
+ 0x28280028,0x7b7b007b,0xc9c900c9,0xc1c100c1,
+ 0xe3e300e3,0xf4f400f4,0xc7c700c7,0x9e9e009e,
+};
+
+
+
+static void camellia_setup128(const unsigned char *key, u32 *subkey)
+{
+ u32 kll, klr, krl, krr;
+ u32 il, ir, t0, t1, w0, w1;
+ u32 kw4l, kw4r, dw, tl, tr;
+ u32 subL[26];
+ u32 subR[26];
+
+ /**
+ * k == kll || klr || krl || krr (|| is concatination)
+ */
+ kll = GETU32(key );
+ klr = GETU32(key + 4);
+ krl = GETU32(key + 8);
+ krr = GETU32(key + 12);
+ /**
+ * generate KL dependent subkeys
+ */
+ /* kw1 */
+ SUBL(0) = kll; SUBR(0) = klr;
+ /* kw2 */
+ SUBL(1) = krl; SUBR(1) = krr;
+ /* rotation left shift 15bit */
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+ /* k3 */
+ SUBL(4) = kll; SUBR(4) = klr;
+ /* k4 */
+ SUBL(5) = krl; SUBR(5) = krr;
+ /* rotation left shift 15+30bit */
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+ /* k7 */
+ SUBL(10) = kll; SUBR(10) = klr;
+ /* k8 */
+ SUBL(11) = krl; SUBR(11) = krr;
+ /* rotation left shift 15+30+15bit */
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+ /* k10 */
+ SUBL(13) = krl; SUBR(13) = krr;
+ /* rotation left shift 15+30+15+17 bit */
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+ /* kl3 */
+ SUBL(16) = kll; SUBR(16) = klr;
+ /* kl4 */
+ SUBL(17) = krl; SUBR(17) = krr;
+ /* rotation left shift 15+30+15+17+17 bit */
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+ /* k13 */
+ SUBL(18) = kll; SUBR(18) = klr;
+ /* k14 */
+ SUBL(19) = krl; SUBR(19) = krr;
+ /* rotation left shift 15+30+15+17+17+17 bit */
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+ /* k17 */
+ SUBL(22) = kll; SUBR(22) = klr;
+ /* k18 */
+ SUBL(23) = krl; SUBR(23) = krr;
+
+ /* generate KA */
+ kll = SUBL(0); klr = SUBR(0);
+ krl = SUBL(1); krr = SUBR(1);
+ CAMELLIA_F(kll, klr,
+ CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
+ w0, w1, il, ir, t0, t1);
+ krl ^= w0; krr ^= w1;
+ CAMELLIA_F(krl, krr,
+ CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
+ kll, klr, il, ir, t0, t1);
+ /* current status == (kll, klr, w0, w1) */
+ CAMELLIA_F(kll, klr,
+ CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
+ krl, krr, il, ir, t0, t1);
+ krl ^= w0; krr ^= w1;
+ CAMELLIA_F(krl, krr,
+ CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
+ w0, w1, il, ir, t0, t1);
+ kll ^= w0; klr ^= w1;
+
+ /* generate KA dependent subkeys */
+ /* k1, k2 */
+ SUBL(2) = kll; SUBR(2) = klr;
+ SUBL(3) = krl; SUBR(3) = krr;
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+ /* k5,k6 */
+ SUBL(6) = kll; SUBR(6) = klr;
+ SUBL(7) = krl; SUBR(7) = krr;
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+ /* kl1, kl2 */
+ SUBL(8) = kll; SUBR(8) = klr;
+ SUBL(9) = krl; SUBR(9) = krr;
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+ /* k9 */
+ SUBL(12) = kll; SUBR(12) = klr;
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+ /* k11, k12 */
+ SUBL(14) = kll; SUBR(14) = klr;
+ SUBL(15) = krl; SUBR(15) = krr;
+ CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+ /* k15, k16 */
+ SUBL(20) = kll; SUBR(20) = klr;
+ SUBL(21) = krl; SUBR(21) = krr;
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+ /* kw3, kw4 */
+ SUBL(24) = kll; SUBR(24) = klr;
+ SUBL(25) = krl; SUBR(25) = krr;
+
+
+ /* absorb kw2 to other subkeys */
+ /* round 2 */
+ SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1);
+ /* round 4 */
+ SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1);
+ /* round 6 */
+ SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1);
+ SUBL(1) ^= SUBR(1) & ~SUBR(9);
+ dw = SUBL(1) & SUBL(9),
+ SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */
+ /* round 8 */
+ SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1);
+ /* round 10 */
+ SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1);
+ /* round 12 */
+ SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1);
+ SUBL(1) ^= SUBR(1) & ~SUBR(17);
+ dw = SUBL(1) & SUBL(17),
+ SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */
+ /* round 14 */
+ SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1);
+ /* round 16 */
+ SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1);
+ /* round 18 */
+ SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1);
+ /* kw3 */
+ SUBL(24) ^= SUBL(1); SUBR(24) ^= SUBR(1);
+
+ /* absorb kw4 to other subkeys */
+ kw4l = SUBL(25); kw4r = SUBR(25);
+ /* round 17 */
+ SUBL(22) ^= kw4l; SUBR(22) ^= kw4r;
+ /* round 15 */
+ SUBL(20) ^= kw4l; SUBR(20) ^= kw4r;
+ /* round 13 */
+ SUBL(18) ^= kw4l; SUBR(18) ^= kw4r;
+ kw4l ^= kw4r & ~SUBR(16);
+ dw = kw4l & SUBL(16),
+ kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */
+ /* round 11 */
+ SUBL(14) ^= kw4l; SUBR(14) ^= kw4r;
+ /* round 9 */
+ SUBL(12) ^= kw4l; SUBR(12) ^= kw4r;
+ /* round 7 */
+ SUBL(10) ^= kw4l; SUBR(10) ^= kw4r;
+ kw4l ^= kw4r & ~SUBR(8);
+ dw = kw4l & SUBL(8),
+ kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */
+ /* round 5 */
+ SUBL(6) ^= kw4l; SUBR(6) ^= kw4r;
+ /* round 3 */
+ SUBL(4) ^= kw4l; SUBR(4) ^= kw4r;
+ /* round 1 */
+ SUBL(2) ^= kw4l; SUBR(2) ^= kw4r;
+ /* kw1 */
+ SUBL(0) ^= kw4l; SUBR(0) ^= kw4r;
+
+
+ /* key XOR is end of F-function */
+ CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */
+ CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2);
+ CAMELLIA_SUBKEY_L(2) = SUBL(3); /* round 1 */
+ CAMELLIA_SUBKEY_R(2) = SUBR(3);
+ CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */
+ CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4);
+ CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */
+ CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5);
+ CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */
+ CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6);
+ CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */
+ CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7);
+ tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8));
+ dw = tl & SUBL(8), /* FL(kl1) */
+ tr = SUBR(10) ^ CAMELLIA_RL1(dw);
+ CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */
+ CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr;
+ CAMELLIA_SUBKEY_L(8) = SUBL(8); /* FL(kl1) */
+ CAMELLIA_SUBKEY_R(8) = SUBR(8);
+ CAMELLIA_SUBKEY_L(9) = SUBL(9); /* FLinv(kl2) */
+ CAMELLIA_SUBKEY_R(9) = SUBR(9);
+ tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9));
+ dw = tl & SUBL(9), /* FLinv(kl2) */
+ tr = SUBR(7) ^ CAMELLIA_RL1(dw);
+ CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */
+ CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11);
+ CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */
+ CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12);
+ CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */
+ CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13);
+ CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */
+ CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14);
+ CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */
+ CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15);
+ tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16));
+ dw = tl & SUBL(16), /* FL(kl3) */
+ tr = SUBR(18) ^ CAMELLIA_RL1(dw);
+ CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */
+ CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr;
+ CAMELLIA_SUBKEY_L(16) = SUBL(16); /* FL(kl3) */
+ CAMELLIA_SUBKEY_R(16) = SUBR(16);
+ CAMELLIA_SUBKEY_L(17) = SUBL(17); /* FLinv(kl4) */
+ CAMELLIA_SUBKEY_R(17) = SUBR(17);
+ tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17));
+ dw = tl & SUBL(17), /* FLinv(kl4) */
+ tr = SUBR(15) ^ CAMELLIA_RL1(dw);
+ CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */
+ CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19);
+ CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */
+ CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20);
+ CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */
+ CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21);
+ CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */
+ CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22);
+ CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */
+ CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23);
+ CAMELLIA_SUBKEY_L(23) = SUBL(22); /* round 18 */
+ CAMELLIA_SUBKEY_R(23) = SUBR(22);
+ CAMELLIA_SUBKEY_L(24) = SUBL(24) ^ SUBL(23); /* kw3 */
+ CAMELLIA_SUBKEY_R(24) = SUBR(24) ^ SUBR(23);
+
+ /* apply the inverse of the last half of P-function */
+ dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2),
+ dw = CAMELLIA_RL8(dw);/* round 1 */
+ CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw,
+ CAMELLIA_SUBKEY_L(2) = dw;
+ dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3),
+ dw = CAMELLIA_RL8(dw);/* round 2 */
+ CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw,
+ CAMELLIA_SUBKEY_L(3) = dw;
+ dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4),
+ dw = CAMELLIA_RL8(dw);/* round 3 */
+ CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw,
+ CAMELLIA_SUBKEY_L(4) = dw;
+ dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5),
+ dw = CAMELLIA_RL8(dw);/* round 4 */
+ CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw,
+ CAMELLIA_SUBKEY_L(5) = dw;
+ dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6),
+ dw = CAMELLIA_RL8(dw);/* round 5 */
+ CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw,
+ CAMELLIA_SUBKEY_L(6) = dw;
+ dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7),
+ dw = CAMELLIA_RL8(dw);/* round 6 */
+ CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw,
+ CAMELLIA_SUBKEY_L(7) = dw;
+ dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10),
+ dw = CAMELLIA_RL8(dw);/* round 7 */
+ CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw,
+ CAMELLIA_SUBKEY_L(10) = dw;
+ dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11),
+ dw = CAMELLIA_RL8(dw);/* round 8 */
+ CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw,
+ CAMELLIA_SUBKEY_L(11) = dw;
+ dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12),
+ dw = CAMELLIA_RL8(dw);/* round 9 */
+ CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw,
+ CAMELLIA_SUBKEY_L(12) = dw;
+ dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13),
+ dw = CAMELLIA_RL8(dw);/* round 10 */
+ CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw,
+ CAMELLIA_SUBKEY_L(13) = dw;
+ dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14),
+ dw = CAMELLIA_RL8(dw);/* round 11 */
+ CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw,
+ CAMELLIA_SUBKEY_L(14) = dw;
+ dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15),
+ dw = CAMELLIA_RL8(dw);/* round 12 */
+ CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw,
+ CAMELLIA_SUBKEY_L(15) = dw;
+ dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18),
+ dw = CAMELLIA_RL8(dw);/* round 13 */
+ CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw,
+ CAMELLIA_SUBKEY_L(18) = dw;
+ dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19),
+ dw = CAMELLIA_RL8(dw);/* round 14 */
+ CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw,
+ CAMELLIA_SUBKEY_L(19) = dw;
+ dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20),
+ dw = CAMELLIA_RL8(dw);/* round 15 */
+ CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw,
+ CAMELLIA_SUBKEY_L(20) = dw;
+ dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21),
+ dw = CAMELLIA_RL8(dw);/* round 16 */
+ CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw,
+ CAMELLIA_SUBKEY_L(21) = dw;
+ dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22),
+ dw = CAMELLIA_RL8(dw);/* round 17 */
+ CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw,
+ CAMELLIA_SUBKEY_L(22) = dw;
+ dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23),
+ dw = CAMELLIA_RL8(dw);/* round 18 */
+ CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw,
+ CAMELLIA_SUBKEY_L(23) = dw;
+
+ return;
+}
+
+
+static void camellia_setup256(const unsigned char *key, u32 *subkey)
+{
+ u32 kll,klr,krl,krr; /* left half of key */
+ u32 krll,krlr,krrl,krrr; /* right half of key */
+ u32 il, ir, t0, t1, w0, w1; /* temporary variables */
+ u32 kw4l, kw4r, dw, tl, tr;
+ u32 subL[34];
+ u32 subR[34];
+
+ /**
+ * key = (kll || klr || krl || krr || krll || krlr || krrl || krrr)
+ * (|| is concatination)
+ */
+
+ kll = GETU32(key );
+ klr = GETU32(key + 4);
+ krl = GETU32(key + 8);
+ krr = GETU32(key + 12);
+ krll = GETU32(key + 16);
+ krlr = GETU32(key + 20);
+ krrl = GETU32(key + 24);
+ krrr = GETU32(key + 28);
+
+ /* generate KL dependent subkeys */
+ /* kw1 */
+ SUBL(0) = kll; SUBR(0) = klr;
+ /* kw2 */
+ SUBL(1) = krl; SUBR(1) = krr;
+ CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 45);
+ /* k9 */
+ SUBL(12) = kll; SUBR(12) = klr;
+ /* k10 */
+ SUBL(13) = krl; SUBR(13) = krr;
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+ /* kl3 */
+ SUBL(16) = kll; SUBR(16) = klr;
+ /* kl4 */
+ SUBL(17) = krl; SUBR(17) = krr;
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+ /* k17 */
+ SUBL(22) = kll; SUBR(22) = klr;
+ /* k18 */
+ SUBL(23) = krl; SUBR(23) = krr;
+ CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+ /* k23 */
+ SUBL(30) = kll; SUBR(30) = klr;
+ /* k24 */
+ SUBL(31) = krl; SUBR(31) = krr;
+
+ /* generate KR dependent subkeys */
+ CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+ /* k3 */
+ SUBL(4) = krll; SUBR(4) = krlr;
+ /* k4 */
+ SUBL(5) = krrl; SUBR(5) = krrr;
+ CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+ /* kl1 */
+ SUBL(8) = krll; SUBR(8) = krlr;
+ /* kl2 */
+ SUBL(9) = krrl; SUBR(9) = krrr;
+ CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+ /* k13 */
+ SUBL(18) = krll; SUBR(18) = krlr;
+ /* k14 */
+ SUBL(19) = krrl; SUBR(19) = krrr;
+ CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+ /* k19 */
+ SUBL(26) = krll; SUBR(26) = krlr;
+ /* k20 */
+ SUBL(27) = krrl; SUBR(27) = krrr;
+ CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+
+ /* generate KA */
+ kll = SUBL(0) ^ krll; klr = SUBR(0) ^ krlr;
+ krl = SUBL(1) ^ krrl; krr = SUBR(1) ^ krrr;
+ CAMELLIA_F(kll, klr,
+ CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
+ w0, w1, il, ir, t0, t1);
+ krl ^= w0; krr ^= w1;
+ CAMELLIA_F(krl, krr,
+ CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
+ kll, klr, il, ir, t0, t1);
+ kll ^= krll; klr ^= krlr;
+ CAMELLIA_F(kll, klr,
+ CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
+ krl, krr, il, ir, t0, t1);
+ krl ^= w0 ^ krrl; krr ^= w1 ^ krrr;
+ CAMELLIA_F(krl, krr,
+ CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
+ w0, w1, il, ir, t0, t1);
+ kll ^= w0; klr ^= w1;
+
+ /* generate KB */
+ krll ^= kll; krlr ^= klr;
+ krrl ^= krl; krrr ^= krr;
+ CAMELLIA_F(krll, krlr,
+ CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R,
+ w0, w1, il, ir, t0, t1);
+ krrl ^= w0; krrr ^= w1;
+ CAMELLIA_F(krrl, krrr,
+ CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R,
+ w0, w1, il, ir, t0, t1);
+ krll ^= w0; krlr ^= w1;
+
+ /* generate KA dependent subkeys */
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+ /* k5 */
+ SUBL(6) = kll; SUBR(6) = klr;
+ /* k6 */
+ SUBL(7) = krl; SUBR(7) = krr;
+ CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+ /* k11 */
+ SUBL(14) = kll; SUBR(14) = klr;
+ /* k12 */
+ SUBL(15) = krl; SUBR(15) = krr;
+ /* rotation left shift 32bit */
+ /* kl5 */
+ SUBL(24) = klr; SUBR(24) = krl;
+ /* kl6 */
+ SUBL(25) = krr; SUBR(25) = kll;
+ /* rotation left shift 49 from k11,k12 -> k21,k22 */
+ CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 49);
+ /* k21 */
+ SUBL(28) = kll; SUBR(28) = klr;
+ /* k22 */
+ SUBL(29) = krl; SUBR(29) = krr;
+
+ /* generate KB dependent subkeys */
+ /* k1 */
+ SUBL(2) = krll; SUBR(2) = krlr;
+ /* k2 */
+ SUBL(3) = krrl; SUBR(3) = krrr;
+ CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+ /* k7 */
+ SUBL(10) = krll; SUBR(10) = krlr;
+ /* k8 */
+ SUBL(11) = krrl; SUBR(11) = krrr;
+ CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+ /* k15 */
+ SUBL(20) = krll; SUBR(20) = krlr;
+ /* k16 */
+ SUBL(21) = krrl; SUBR(21) = krrr;
+ CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51);
+ /* kw3 */
+ SUBL(32) = krll; SUBR(32) = krlr;
+ /* kw4 */
+ SUBL(33) = krrl; SUBR(33) = krrr;
+
+ /* absorb kw2 to other subkeys */
+ /* round 2 */
+ SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1);
+ /* round 4 */
+ SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1);
+ /* round 6 */
+ SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1);
+ SUBL(1) ^= SUBR(1) & ~SUBR(9);
+ dw = SUBL(1) & SUBL(9),
+ SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */
+ /* round 8 */
+ SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1);
+ /* round 10 */
+ SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1);
+ /* round 12 */
+ SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1);
+ SUBL(1) ^= SUBR(1) & ~SUBR(17);
+ dw = SUBL(1) & SUBL(17),
+ SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */
+ /* round 14 */
+ SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1);
+ /* round 16 */
+ SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1);
+ /* round 18 */
+ SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1);
+ SUBL(1) ^= SUBR(1) & ~SUBR(25);
+ dw = SUBL(1) & SUBL(25),
+ SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl6) */
+ /* round 20 */
+ SUBL(27) ^= SUBL(1); SUBR(27) ^= SUBR(1);
+ /* round 22 */
+ SUBL(29) ^= SUBL(1); SUBR(29) ^= SUBR(1);
+ /* round 24 */
+ SUBL(31) ^= SUBL(1); SUBR(31) ^= SUBR(1);
+ /* kw3 */
+ SUBL(32) ^= SUBL(1); SUBR(32) ^= SUBR(1);
+
+
+ /* absorb kw4 to other subkeys */
+ kw4l = SUBL(33); kw4r = SUBR(33);
+ /* round 23 */
+ SUBL(30) ^= kw4l; SUBR(30) ^= kw4r;
+ /* round 21 */
+ SUBL(28) ^= kw4l; SUBR(28) ^= kw4r;
+ /* round 19 */
+ SUBL(26) ^= kw4l; SUBR(26) ^= kw4r;
+ kw4l ^= kw4r & ~SUBR(24);
+ dw = kw4l & SUBL(24),
+ kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl5) */
+ /* round 17 */
+ SUBL(22) ^= kw4l; SUBR(22) ^= kw4r;
+ /* round 15 */
+ SUBL(20) ^= kw4l; SUBR(20) ^= kw4r;
+ /* round 13 */
+ SUBL(18) ^= kw4l; SUBR(18) ^= kw4r;
+ kw4l ^= kw4r & ~SUBR(16);
+ dw = kw4l & SUBL(16),
+ kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */
+ /* round 11 */
+ SUBL(14) ^= kw4l; SUBR(14) ^= kw4r;
+ /* round 9 */
+ SUBL(12) ^= kw4l; SUBR(12) ^= kw4r;
+ /* round 7 */
+ SUBL(10) ^= kw4l; SUBR(10) ^= kw4r;
+ kw4l ^= kw4r & ~SUBR(8);
+ dw = kw4l & SUBL(8),
+ kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */
+ /* round 5 */
+ SUBL(6) ^= kw4l; SUBR(6) ^= kw4r;
+ /* round 3 */
+ SUBL(4) ^= kw4l; SUBR(4) ^= kw4r;
+ /* round 1 */
+ SUBL(2) ^= kw4l; SUBR(2) ^= kw4r;
+ /* kw1 */
+ SUBL(0) ^= kw4l; SUBR(0) ^= kw4r;
+
+ /* key XOR is end of F-function */
+ CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */
+ CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2);
+ CAMELLIA_SUBKEY_L(2) = SUBL(3); /* round 1 */
+ CAMELLIA_SUBKEY_R(2) = SUBR(3);
+ CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */
+ CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4);
+ CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */
+ CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5);
+ CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */
+ CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6);
+ CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */
+ CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7);
+ tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8));
+ dw = tl & SUBL(8), /* FL(kl1) */
+ tr = SUBR(10) ^ CAMELLIA_RL1(dw);
+ CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */
+ CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr;
+ CAMELLIA_SUBKEY_L(8) = SUBL(8); /* FL(kl1) */
+ CAMELLIA_SUBKEY_R(8) = SUBR(8);
+ CAMELLIA_SUBKEY_L(9) = SUBL(9); /* FLinv(kl2) */
+ CAMELLIA_SUBKEY_R(9) = SUBR(9);
+ tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9));
+ dw = tl & SUBL(9), /* FLinv(kl2) */
+ tr = SUBR(7) ^ CAMELLIA_RL1(dw);
+ CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */
+ CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11);
+ CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */
+ CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12);
+ CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */
+ CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13);
+ CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */
+ CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14);
+ CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */
+ CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15);
+ tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16));
+ dw = tl & SUBL(16), /* FL(kl3) */
+ tr = SUBR(18) ^ CAMELLIA_RL1(dw);
+ CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */
+ CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr;
+ CAMELLIA_SUBKEY_L(16) = SUBL(16); /* FL(kl3) */
+ CAMELLIA_SUBKEY_R(16) = SUBR(16);
+ CAMELLIA_SUBKEY_L(17) = SUBL(17); /* FLinv(kl4) */
+ CAMELLIA_SUBKEY_R(17) = SUBR(17);
+ tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17));
+ dw = tl & SUBL(17), /* FLinv(kl4) */
+ tr = SUBR(15) ^ CAMELLIA_RL1(dw);
+ CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */
+ CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19);
+ CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */
+ CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20);
+ CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */
+ CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21);
+ CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */
+ CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22);
+ CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */
+ CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23);
+ tl = SUBL(26) ^ (SUBR(26)
+ & ~SUBR(24));
+ dw = tl & SUBL(24), /* FL(kl5) */
+ tr = SUBR(26) ^ CAMELLIA_RL1(dw);
+ CAMELLIA_SUBKEY_L(23) = SUBL(22) ^ tl; /* round 18 */
+ CAMELLIA_SUBKEY_R(23) = SUBR(22) ^ tr;
+ CAMELLIA_SUBKEY_L(24) = SUBL(24); /* FL(kl5) */
+ CAMELLIA_SUBKEY_R(24) = SUBR(24);
+ CAMELLIA_SUBKEY_L(25) = SUBL(25); /* FLinv(kl6) */
+ CAMELLIA_SUBKEY_R(25) = SUBR(25);
+ tl = SUBL(23) ^ (SUBR(23) &
+ ~SUBR(25));
+ dw = tl & SUBL(25), /* FLinv(kl6) */
+ tr = SUBR(23) ^ CAMELLIA_RL1(dw);
+ CAMELLIA_SUBKEY_L(26) = tl ^ SUBL(27); /* round 19 */
+ CAMELLIA_SUBKEY_R(26) = tr ^ SUBR(27);
+ CAMELLIA_SUBKEY_L(27) = SUBL(26) ^ SUBL(28); /* round 20 */
+ CAMELLIA_SUBKEY_R(27) = SUBR(26) ^ SUBR(28);
+ CAMELLIA_SUBKEY_L(28) = SUBL(27) ^ SUBL(29); /* round 21 */
+ CAMELLIA_SUBKEY_R(28) = SUBR(27) ^ SUBR(29);
+ CAMELLIA_SUBKEY_L(29) = SUBL(28) ^ SUBL(30); /* round 22 */
+ CAMELLIA_SUBKEY_R(29) = SUBR(28) ^ SUBR(30);
+ CAMELLIA_SUBKEY_L(30) = SUBL(29) ^ SUBL(31); /* round 23 */
+ CAMELLIA_SUBKEY_R(30) = SUBR(29) ^ SUBR(31);
+ CAMELLIA_SUBKEY_L(31) = SUBL(30); /* round 24 */
+ CAMELLIA_SUBKEY_R(31) = SUBR(30);
+ CAMELLIA_SUBKEY_L(32) = SUBL(32) ^ SUBL(31); /* kw3 */
+ CAMELLIA_SUBKEY_R(32) = SUBR(32) ^ SUBR(31);
+
+ /* apply the inverse of the last half of P-function */
+ dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2),
+ dw = CAMELLIA_RL8(dw);/* round 1 */
+ CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw,
+ CAMELLIA_SUBKEY_L(2) = dw;
+ dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3),
+ dw = CAMELLIA_RL8(dw);/* round 2 */
+ CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw,
+ CAMELLIA_SUBKEY_L(3) = dw;
+ dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4),
+ dw = CAMELLIA_RL8(dw);/* round 3 */
+ CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw,
+ CAMELLIA_SUBKEY_L(4) = dw;
+ dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5),
+ dw = CAMELLIA_RL8(dw);/* round 4 */
+ CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw,
+ CAMELLIA_SUBKEY_L(5) = dw;
+ dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6),
+ dw = CAMELLIA_RL8(dw);/* round 5 */
+ CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw,
+ CAMELLIA_SUBKEY_L(6) = dw;
+ dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7),
+ dw = CAMELLIA_RL8(dw);/* round 6 */
+ CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw,
+ CAMELLIA_SUBKEY_L(7) = dw;
+ dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10),
+ dw = CAMELLIA_RL8(dw);/* round 7 */
+ CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw,
+ CAMELLIA_SUBKEY_L(10) = dw;
+ dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11),
+ dw = CAMELLIA_RL8(dw);/* round 8 */
+ CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw,
+ CAMELLIA_SUBKEY_L(11) = dw;
+ dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12),
+ dw = CAMELLIA_RL8(dw);/* round 9 */
+ CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw,
+ CAMELLIA_SUBKEY_L(12) = dw;
+ dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13),
+ dw = CAMELLIA_RL8(dw);/* round 10 */
+ CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw,
+ CAMELLIA_SUBKEY_L(13) = dw;
+ dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14),
+ dw = CAMELLIA_RL8(dw);/* round 11 */
+ CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw,
+ CAMELLIA_SUBKEY_L(14) = dw;
+ dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15),
+ dw = CAMELLIA_RL8(dw);/* round 12 */
+ CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw,
+ CAMELLIA_SUBKEY_L(15) = dw;
+ dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18),
+ dw = CAMELLIA_RL8(dw);/* round 13 */
+ CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw,
+ CAMELLIA_SUBKEY_L(18) = dw;
+ dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19),
+ dw = CAMELLIA_RL8(dw);/* round 14 */
+ CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw,
+ CAMELLIA_SUBKEY_L(19) = dw;
+ dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20),
+ dw = CAMELLIA_RL8(dw);/* round 15 */
+ CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw,
+ CAMELLIA_SUBKEY_L(20) = dw;
+ dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21),
+ dw = CAMELLIA_RL8(dw);/* round 16 */
+ CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw,
+ CAMELLIA_SUBKEY_L(21) = dw;
+ dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22),
+ dw = CAMELLIA_RL8(dw);/* round 17 */
+ CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw,
+ CAMELLIA_SUBKEY_L(22) = dw;
+ dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23),
+ dw = CAMELLIA_RL8(dw);/* round 18 */
+ CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw,
+ CAMELLIA_SUBKEY_L(23) = dw;
+ dw = CAMELLIA_SUBKEY_L(26) ^ CAMELLIA_SUBKEY_R(26),
+ dw = CAMELLIA_RL8(dw);/* round 19 */
+ CAMELLIA_SUBKEY_R(26) = CAMELLIA_SUBKEY_L(26) ^ dw,
+ CAMELLIA_SUBKEY_L(26) = dw;
+ dw = CAMELLIA_SUBKEY_L(27) ^ CAMELLIA_SUBKEY_R(27),
+ dw = CAMELLIA_RL8(dw);/* round 20 */
+ CAMELLIA_SUBKEY_R(27) = CAMELLIA_SUBKEY_L(27) ^ dw,
+ CAMELLIA_SUBKEY_L(27) = dw;
+ dw = CAMELLIA_SUBKEY_L(28) ^ CAMELLIA_SUBKEY_R(28),
+ dw = CAMELLIA_RL8(dw);/* round 21 */
+ CAMELLIA_SUBKEY_R(28) = CAMELLIA_SUBKEY_L(28) ^ dw,
+ CAMELLIA_SUBKEY_L(28) = dw;
+ dw = CAMELLIA_SUBKEY_L(29) ^ CAMELLIA_SUBKEY_R(29),
+ dw = CAMELLIA_RL8(dw);/* round 22 */
+ CAMELLIA_SUBKEY_R(29) = CAMELLIA_SUBKEY_L(29) ^ dw,
+ CAMELLIA_SUBKEY_L(29) = dw;
+ dw = CAMELLIA_SUBKEY_L(30) ^ CAMELLIA_SUBKEY_R(30),
+ dw = CAMELLIA_RL8(dw);/* round 23 */
+ CAMELLIA_SUBKEY_R(30) = CAMELLIA_SUBKEY_L(30) ^ dw,
+ CAMELLIA_SUBKEY_L(30) = dw;
+ dw = CAMELLIA_SUBKEY_L(31) ^ CAMELLIA_SUBKEY_R(31),
+ dw = CAMELLIA_RL8(dw);/* round 24 */
+ CAMELLIA_SUBKEY_R(31) = CAMELLIA_SUBKEY_L(31) ^ dw,
+ CAMELLIA_SUBKEY_L(31) = dw;
+
+ return;
+}
+
+static void camellia_setup192(const unsigned char *key, u32 *subkey)
+{
+ unsigned char kk[32];
+ u32 krll, krlr, krrl,krrr;
+
+ memcpy(kk, key, 24);
+ memcpy((unsigned char *)&krll, key+16,4);
+ memcpy((unsigned char *)&krlr, key+20,4);
+ krrl = ~krll;
+ krrr = ~krlr;
+ memcpy(kk+24, (unsigned char *)&krrl, 4);
+ memcpy(kk+28, (unsigned char *)&krrr, 4);
+ camellia_setup256(kk, subkey);
+ return;
+}
+
+
+/**
+ * Stuff related to camellia encryption/decryption
+ */
+static void camellia_encrypt128(const u32 *subkey, __be32 *io_text)
+{
+ u32 il,ir,t0,t1; /* temporary valiables */
+
+ u32 io[4];
+
+ io[0] = be32_to_cpu(io_text[0]);
+ io[1] = be32_to_cpu(io_text[1]);
+ io[2] = be32_to_cpu(io_text[2]);
+ io[3] = be32_to_cpu(io_text[3]);
+
+ /* pre whitening but absorb kw2*/
+ io[0] ^= CAMELLIA_SUBKEY_L(0);
+ io[1] ^= CAMELLIA_SUBKEY_R(0);
+ /* main iteration */
+
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
+ io[0],io[1],il,ir,t0,t1);
+
+ CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+ CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
+ CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
+ t0,t1,il,ir);
+
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
+ io[0],io[1],il,ir,t0,t1);
+
+ CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+ CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
+ CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
+ t0,t1,il,ir);
+
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
+ io[0],io[1],il,ir,t0,t1);
+
+ /* post whitening but kw4 */
+ io[2] ^= CAMELLIA_SUBKEY_L(24);
+ io[3] ^= CAMELLIA_SUBKEY_R(24);
+
+ t0 = io[0];
+ t1 = io[1];
+ io[0] = io[2];
+ io[1] = io[3];
+ io[2] = t0;
+ io[3] = t1;
+
+ io_text[0] = cpu_to_be32(io[0]);
+ io_text[1] = cpu_to_be32(io[1]);
+ io_text[2] = cpu_to_be32(io[2]);
+ io_text[3] = cpu_to_be32(io[3]);
+
+ return;
+}
+
+static void camellia_decrypt128(const u32 *subkey, __be32 *io_text)
+{
+ u32 il,ir,t0,t1; /* temporary valiables */
+
+ u32 io[4];
+
+ io[0] = be32_to_cpu(io_text[0]);
+ io[1] = be32_to_cpu(io_text[1]);
+ io[2] = be32_to_cpu(io_text[2]);
+ io[3] = be32_to_cpu(io_text[3]);
+
+ /* pre whitening but absorb kw2*/
+ io[0] ^= CAMELLIA_SUBKEY_L(24);
+ io[1] ^= CAMELLIA_SUBKEY_R(24);
+
+ /* main iteration */
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
+ io[0],io[1],il,ir,t0,t1);
+
+ CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+ CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
+ CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
+ t0,t1,il,ir);
+
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
+ io[0],io[1],il,ir,t0,t1);
+
+ CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+ CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
+ CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
+ t0,t1,il,ir);
+
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
+ io[0],io[1],il,ir,t0,t1);
+
+ /* post whitening but kw4 */
+ io[2] ^= CAMELLIA_SUBKEY_L(0);
+ io[3] ^= CAMELLIA_SUBKEY_R(0);
+
+ t0 = io[0];
+ t1 = io[1];
+ io[0] = io[2];
+ io[1] = io[3];
+ io[2] = t0;
+ io[3] = t1;
+
+ io_text[0] = cpu_to_be32(io[0]);
+ io_text[1] = cpu_to_be32(io[1]);
+ io_text[2] = cpu_to_be32(io[2]);
+ io_text[3] = cpu_to_be32(io[3]);
+
+ return;
+}
+
+
+/**
+ * stuff for 192 and 256bit encryption/decryption
+ */
+static void camellia_encrypt256(const u32 *subkey, __be32 *io_text)
+{
+ u32 il,ir,t0,t1; /* temporary valiables */
+
+ u32 io[4];
+
+ io[0] = be32_to_cpu(io_text[0]);
+ io[1] = be32_to_cpu(io_text[1]);
+ io[2] = be32_to_cpu(io_text[2]);
+ io[3] = be32_to_cpu(io_text[3]);
+
+ /* pre whitening but absorb kw2*/
+ io[0] ^= CAMELLIA_SUBKEY_L(0);
+ io[1] ^= CAMELLIA_SUBKEY_R(0);
+
+ /* main iteration */
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
+ io[0],io[1],il,ir,t0,t1);
+
+ CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+ CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
+ CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
+ t0,t1,il,ir);
+
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
+ io[0],io[1],il,ir,t0,t1);
+
+ CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+ CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
+ CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
+ t0,t1,il,ir);
+
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
+ io[0],io[1],il,ir,t0,t1);
+
+ CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+ CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24),
+ CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25),
+ t0,t1,il,ir);
+
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31),
+ io[0],io[1],il,ir,t0,t1);
+
+ /* post whitening but kw4 */
+ io[2] ^= CAMELLIA_SUBKEY_L(32);
+ io[3] ^= CAMELLIA_SUBKEY_R(32);
+
+ t0 = io[0];
+ t1 = io[1];
+ io[0] = io[2];
+ io[1] = io[3];
+ io[2] = t0;
+ io[3] = t1;
+
+ io_text[0] = cpu_to_be32(io[0]);
+ io_text[1] = cpu_to_be32(io[1]);
+ io_text[2] = cpu_to_be32(io[2]);
+ io_text[3] = cpu_to_be32(io[3]);
+
+ return;
+}
+
+
+static void camellia_decrypt256(const u32 *subkey, __be32 *io_text)
+{
+ u32 il,ir,t0,t1; /* temporary valiables */
+
+ u32 io[4];
+
+ io[0] = be32_to_cpu(io_text[0]);
+ io[1] = be32_to_cpu(io_text[1]);
+ io[2] = be32_to_cpu(io_text[2]);
+ io[3] = be32_to_cpu(io_text[3]);
+
+ /* pre whitening but absorb kw2*/
+ io[0] ^= CAMELLIA_SUBKEY_L(32);
+ io[1] ^= CAMELLIA_SUBKEY_R(32);
+
+ /* main iteration */
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26),
+ io[0],io[1],il,ir,t0,t1);
+
+ CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+ CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25),
+ CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24),
+ t0,t1,il,ir);
+
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18),
+ io[0],io[1],il,ir,t0,t1);
+
+ CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+ CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17),
+ CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16),
+ t0,t1,il,ir);
+
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10),
+ io[0],io[1],il,ir,t0,t1);
+
+ CAMELLIA_FLS(io[0],io[1],io[2],io[3],
+ CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9),
+ CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8),
+ t0,t1,il,ir);
+
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4),
+ io[0],io[1],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[0],io[1],
+ CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3),
+ io[2],io[3],il,ir,t0,t1);
+ CAMELLIA_ROUNDSM(io[2],io[3],
+ CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2),
+ io[0],io[1],il,ir,t0,t1);
+
+ /* post whitening but kw4 */
+ io[2] ^= CAMELLIA_SUBKEY_L(0);
+ io[3] ^= CAMELLIA_SUBKEY_R(0);
+
+ t0 = io[0];
+ t1 = io[1];
+ io[0] = io[2];
+ io[1] = io[3];
+ io[2] = t0;
+ io[3] = t1;
+
+ io_text[0] = cpu_to_be32(io[0]);
+ io_text[1] = cpu_to_be32(io[1]);
+ io_text[2] = cpu_to_be32(io[2]);
+ io_text[3] = cpu_to_be32(io[3]);
+
+ return;
+}
+
+
+static int
+camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
+ const unsigned char *key = (const unsigned char *)in_key;
+ u32 *flags = &tfm->crt_flags;
+
+ if (key_len != 16 && key_len != 24 && key_len != 32) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+
+ cctx->key_length = key_len;
+
+ switch(key_len) {
+ case 16:
+ camellia_setup128(key, cctx->key_table);
+ break;
+ case 24:
+ camellia_setup192(key, cctx->key_table);
+ break;
+ case 32:
+ camellia_setup256(key, cctx->key_table);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
+ const __be32 *src = (const __be32 *)in;
+ __be32 *dst = (__be32 *)out;
+
+ __be32 tmp[4];
+
+ memcpy(tmp, src, CAMELLIA_BLOCK_SIZE);
+
+ switch (cctx->key_length) {
+ case 16:
+ camellia_encrypt128(cctx->key_table, tmp);
+ break;
+ case 24:
+ /* fall through */
+ case 32:
+ camellia_encrypt256(cctx->key_table, tmp);
+ break;
+ default:
+ break;
+ }
+
+ memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE);
+}
+
+
+static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
+ const __be32 *src = (const __be32 *)in;
+ __be32 *dst = (__be32 *)out;
+
+ __be32 tmp[4];
+
+ memcpy(tmp, src, CAMELLIA_BLOCK_SIZE);
+
+ switch (cctx->key_length) {
+ case 16:
+ camellia_decrypt128(cctx->key_table, tmp);
+ break;
+ case 24:
+ /* fall through */
+ case 32:
+ camellia_decrypt256(cctx->key_table, tmp);
+ break;
+ default:
+ break;
+ }
+
+ memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE);
+}
+
+
+static struct crypto_alg camellia_alg = {
+ .cra_name = "camellia",
+ .cra_driver_name = "camellia-generic",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = CAMELLIA_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct camellia_ctx),
+ .cra_alignmask = 3,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(camellia_alg.cra_list),
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE,
+ .cia_max_keysize = CAMELLIA_MAX_KEY_SIZE,
+ .cia_setkey = camellia_set_key,
+ .cia_encrypt = camellia_encrypt,
+ .cia_decrypt = camellia_decrypt
+ }
+ }
+};
+
+static int __init camellia_init(void)
+{
+ return crypto_register_alg(&camellia_alg);
+}
+
+
+static void __exit camellia_fini(void)
+{
+ crypto_unregister_alg(&camellia_alg);
+}
+
+
+module_init(camellia_init);
+module_exit(camellia_fini);
+
+
+MODULE_DESCRIPTION("Camellia Cipher Algorithm");
+MODULE_LICENSE("GPL");
diff --git a/crypto/cbc.c b/crypto/cbc.c
index f5542b4db38..136fea7e700 100644
--- a/crypto/cbc.c
+++ b/crypto/cbc.c
@@ -243,6 +243,7 @@ static int crypto_cbc_init_tfm(struct crypto_tfm *tfm)
struct crypto_instance *inst = (void *)tfm->__crt_alg;
struct crypto_spawn *spawn = crypto_instance_ctx(inst);
struct crypto_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_cipher *cipher;
switch (crypto_tfm_alg_blocksize(tfm)) {
case 8:
@@ -260,11 +261,11 @@ static int crypto_cbc_init_tfm(struct crypto_tfm *tfm)
ctx->xor = xor_quad;
}
- tfm = crypto_spawn_tfm(spawn);
- if (IS_ERR(tfm))
- return PTR_ERR(tfm);
+ cipher = crypto_spawn_cipher(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
- ctx->child = crypto_cipher_cast(tfm);
+ ctx->child = cipher;
return 0;
}
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 9e03701cfdc..333aab2f027 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -12,274 +12,13 @@
* any later version.
*
*/
-#include <linux/compiler.h>
+
#include <linux/kernel.h>
#include <linux/crypto.h>
#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
+#include <linux/scatterlist.h>
#include <linux/string.h>
-#include <asm/scatterlist.h>
#include "internal.h"
-#include "scatterwalk.h"
-
-struct cipher_alg_compat {
- unsigned int cia_min_keysize;
- unsigned int cia_max_keysize;
- int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen);
- void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
- void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-
- unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc,
- u8 *dst, const u8 *src,
- unsigned int nbytes);
- unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc,
- u8 *dst, const u8 *src,
- unsigned int nbytes);
- unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc,
- u8 *dst, const u8 *src,
- unsigned int nbytes);
- unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc,
- u8 *dst, const u8 *src,
- unsigned int nbytes);
-};
-
-static inline void xor_64(u8 *a, const u8 *b)
-{
- ((u32 *)a)[0] ^= ((u32 *)b)[0];
- ((u32 *)a)[1] ^= ((u32 *)b)[1];
-}
-
-static inline void xor_128(u8 *a, const u8 *b)
-{
- ((u32 *)a)[0] ^= ((u32 *)b)[0];
- ((u32 *)a)[1] ^= ((u32 *)b)[1];
- ((u32 *)a)[2] ^= ((u32 *)b)[2];
- ((u32 *)a)[3] ^= ((u32 *)b)[3];
-}
-
-static unsigned int crypt_slow(const struct cipher_desc *desc,
- struct scatter_walk *in,
- struct scatter_walk *out, unsigned int bsize)
-{
- unsigned long alignmask = crypto_tfm_alg_alignmask(desc->tfm);
- u8 buffer[bsize * 2 + alignmask];
- u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
- u8 *dst = src + bsize;
-
- scatterwalk_copychunks(src, in, bsize, 0);
- desc->prfn(desc, dst, src, bsize);
- scatterwalk_copychunks(dst, out, bsize, 1);
-
- return bsize;
-}
-
-static inline unsigned int crypt_fast(const struct cipher_desc *desc,
- struct scatter_walk *in,
- struct scatter_walk *out,
- unsigned int nbytes, u8 *tmp)
-{
- u8 *src, *dst;
- u8 *real_src, *real_dst;
-
- real_src = scatterwalk_map(in, 0);
- real_dst = scatterwalk_map(out, 1);
-
- src = real_src;
- dst = scatterwalk_samebuf(in, out) ? src : real_dst;
-
- if (tmp) {
- memcpy(tmp, src, nbytes);
- src = tmp;
- dst = tmp;
- }
-
- nbytes = desc->prfn(desc, dst, src, nbytes);
-
- if (tmp)
- memcpy(real_dst, tmp, nbytes);
-
- scatterwalk_unmap(real_src, 0);
- scatterwalk_unmap(real_dst, 1);
-
- scatterwalk_advance(in, nbytes);
- scatterwalk_advance(out, nbytes);
-
- return nbytes;
-}
-
-/*
- * Generic encrypt/decrypt wrapper for ciphers, handles operations across
- * multiple page boundaries by using temporary blocks. In user context,
- * the kernel is given a chance to schedule us once per page.
- */
-static int crypt(const struct cipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- struct scatter_walk walk_in, walk_out;
- struct crypto_tfm *tfm = desc->tfm;
- const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
- unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
- unsigned long buffer = 0;
-
- if (!nbytes)
- return 0;
-
- if (nbytes % bsize) {
- tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
- return -EINVAL;
- }
-
- scatterwalk_start(&walk_in, src);
- scatterwalk_start(&walk_out, dst);
-
- for(;;) {
- unsigned int n = nbytes;
- u8 *tmp = NULL;
-
- if (!scatterwalk_aligned(&walk_in, alignmask) ||
- !scatterwalk_aligned(&walk_out, alignmask)) {
- if (!buffer) {
- buffer = __get_free_page(GFP_ATOMIC);
- if (!buffer)
- n = 0;
- }
- tmp = (u8 *)buffer;
- }
-
- n = scatterwalk_clamp(&walk_in, n);
- n = scatterwalk_clamp(&walk_out, n);
-
- if (likely(n >= bsize))
- n = crypt_fast(desc, &walk_in, &walk_out, n, tmp);
- else
- n = crypt_slow(desc, &walk_in, &walk_out, bsize);
-
- nbytes -= n;
-
- scatterwalk_done(&walk_in, 0, nbytes);
- scatterwalk_done(&walk_out, 1, nbytes);
-
- if (!nbytes)
- break;
-
- crypto_yield(tfm->crt_flags);
- }
-
- if (buffer)
- free_page(buffer);
-
- return 0;
-}
-
-static int crypt_iv_unaligned(struct cipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- struct crypto_tfm *tfm = desc->tfm;
- unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
- u8 *iv = desc->info;
-
- if (unlikely(((unsigned long)iv & alignmask))) {
- unsigned int ivsize = tfm->crt_cipher.cit_ivsize;
- u8 buffer[ivsize + alignmask];
- u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
- int err;
-
- desc->info = memcpy(tmp, iv, ivsize);
- err = crypt(desc, dst, src, nbytes);
- memcpy(iv, tmp, ivsize);
-
- return err;
- }
-
- return crypt(desc, dst, src, nbytes);
-}
-
-static unsigned int cbc_process_encrypt(const struct cipher_desc *desc,
- u8 *dst, const u8 *src,
- unsigned int nbytes)
-{
- struct crypto_tfm *tfm = desc->tfm;
- void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block;
- int bsize = crypto_tfm_alg_blocksize(tfm);
-
- void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
- u8 *iv = desc->info;
- unsigned int done = 0;
-
- nbytes -= bsize;
-
- do {
- xor(iv, src);
- fn(tfm, dst, iv);
- memcpy(iv, dst, bsize);
-
- src += bsize;
- dst += bsize;
- } while ((done += bsize) <= nbytes);
-
- return done;
-}
-
-static unsigned int cbc_process_decrypt(const struct cipher_desc *desc,
- u8 *dst, const u8 *src,
- unsigned int nbytes)
-{
- struct crypto_tfm *tfm = desc->tfm;
- void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block;
- int bsize = crypto_tfm_alg_blocksize(tfm);
- unsigned long alignmask = crypto_tfm_alg_alignmask(desc->tfm);
-
- u8 stack[src == dst ? bsize + alignmask : 0];
- u8 *buf = (u8 *)ALIGN((unsigned long)stack, alignmask + 1);
- u8 **dst_p = src == dst ? &buf : &dst;
-
- void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
- u8 *iv = desc->info;
- unsigned int done = 0;
-
- nbytes -= bsize;
-
- do {
- u8 *tmp_dst = *dst_p;
-
- fn(tfm, tmp_dst, src);
- xor(tmp_dst, iv);
- memcpy(iv, src, bsize);
- if (tmp_dst != dst)
- memcpy(dst, tmp_dst, bsize);
-
- src += bsize;
- dst += bsize;
- } while ((done += bsize) <= nbytes);
-
- return done;
-}
-
-static unsigned int ecb_process(const struct cipher_desc *desc, u8 *dst,
- const u8 *src, unsigned int nbytes)
-{
- struct crypto_tfm *tfm = desc->tfm;
- int bsize = crypto_tfm_alg_blocksize(tfm);
- void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
- unsigned int done = 0;
-
- nbytes -= bsize;
-
- do {
- fn(tfm, dst, src);
-
- src += bsize;
- dst += bsize;
- } while ((done += bsize) <= nbytes);
-
- return done;
-}
static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
{
@@ -293,122 +32,6 @@ static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
return cia->cia_setkey(tfm, key, keylen);
}
-static int ecb_encrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct cipher_desc desc;
- struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
- desc.tfm = tfm;
- desc.crfn = cipher->cia_encrypt;
- desc.prfn = cipher->cia_encrypt_ecb ?: ecb_process;
-
- return crypt(&desc, dst, src, nbytes);
-}
-
-static int ecb_decrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- struct cipher_desc desc;
- struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
- desc.tfm = tfm;
- desc.crfn = cipher->cia_decrypt;
- desc.prfn = cipher->cia_decrypt_ecb ?: ecb_process;
-
- return crypt(&desc, dst, src, nbytes);
-}
-
-static int cbc_encrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- struct cipher_desc desc;
- struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
- desc.tfm = tfm;
- desc.crfn = cipher->cia_encrypt;
- desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt;
- desc.info = tfm->crt_cipher.cit_iv;
-
- return crypt(&desc, dst, src, nbytes);
-}
-
-static int cbc_encrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv)
-{
- struct cipher_desc desc;
- struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
- desc.tfm = tfm;
- desc.crfn = cipher->cia_encrypt;
- desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt;
- desc.info = iv;
-
- return crypt_iv_unaligned(&desc, dst, src, nbytes);
-}
-
-static int cbc_decrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- struct cipher_desc desc;
- struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
- desc.tfm = tfm;
- desc.crfn = cipher->cia_decrypt;
- desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt;
- desc.info = tfm->crt_cipher.cit_iv;
-
- return crypt(&desc, dst, src, nbytes);
-}
-
-static int cbc_decrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv)
-{
- struct cipher_desc desc;
- struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
-
- desc.tfm = tfm;
- desc.crfn = cipher->cia_decrypt;
- desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt;
- desc.info = iv;
-
- return crypt_iv_unaligned(&desc, dst, src, nbytes);
-}
-
-static int nocrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- return -ENOSYS;
-}
-
-static int nocrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv)
-{
- return -ENOSYS;
-}
-
-int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags)
-{
- u32 mode = flags & CRYPTO_TFM_MODE_MASK;
- tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB;
- return 0;
-}
-
static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *,
const u8 *),
struct crypto_tfm *tfm,
@@ -454,7 +77,6 @@ static void cipher_decrypt_unaligned(struct crypto_tfm *tfm,
int crypto_init_cipher_ops(struct crypto_tfm *tfm)
{
- int ret = 0;
struct cipher_tfm *ops = &tfm->crt_cipher;
struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
@@ -464,70 +86,7 @@ int crypto_init_cipher_ops(struct crypto_tfm *tfm)
ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ?
cipher_decrypt_unaligned : cipher->cia_decrypt;
- switch (tfm->crt_cipher.cit_mode) {
- case CRYPTO_TFM_MODE_ECB:
- ops->cit_encrypt = ecb_encrypt;
- ops->cit_decrypt = ecb_decrypt;
- ops->cit_encrypt_iv = nocrypt_iv;
- ops->cit_decrypt_iv = nocrypt_iv;
- break;
-
- case CRYPTO_TFM_MODE_CBC:
- ops->cit_encrypt = cbc_encrypt;
- ops->cit_decrypt = cbc_decrypt;
- ops->cit_encrypt_iv = cbc_encrypt_iv;
- ops->cit_decrypt_iv = cbc_decrypt_iv;
- break;
-
- case CRYPTO_TFM_MODE_CFB:
- ops->cit_encrypt = nocrypt;
- ops->cit_decrypt = nocrypt;
- ops->cit_encrypt_iv = nocrypt_iv;
- ops->cit_decrypt_iv = nocrypt_iv;
- break;
-
- case CRYPTO_TFM_MODE_CTR:
- ops->cit_encrypt = nocrypt;
- ops->cit_decrypt = nocrypt;
- ops->cit_encrypt_iv = nocrypt_iv;
- ops->cit_decrypt_iv = nocrypt_iv;
- break;
-
- default:
- BUG();
- }
-
- if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) {
- unsigned long align;
- unsigned long addr;
-
- switch (crypto_tfm_alg_blocksize(tfm)) {
- case 8:
- ops->cit_xor_block = xor_64;
- break;
-
- case 16:
- ops->cit_xor_block = xor_128;
- break;
-
- default:
- printk(KERN_WARNING "%s: block size %u not supported\n",
- crypto_tfm_alg_name(tfm),
- crypto_tfm_alg_blocksize(tfm));
- ret = -EINVAL;
- goto out;
- }
-
- ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm);
- align = crypto_tfm_alg_alignmask(tfm) + 1;
- addr = (unsigned long)crypto_tfm_ctx(tfm);
- addr = ALIGN(addr, align);
- addr += ALIGN(tfm->__crt_alg->cra_ctxsize, align);
- ops->cit_iv = (void *)addr;
- }
-
-out:
- return ret;
+ return 0;
}
void crypto_exit_cipher_ops(struct crypto_tfm *tfm)
diff --git a/crypto/compress.c b/crypto/compress.c
index eca182aa338..0a6570048c1 100644
--- a/crypto/compress.c
+++ b/crypto/compress.c
@@ -34,11 +34,6 @@ static int crypto_decompress(struct crypto_tfm *tfm,
dlen);
}
-int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags)
-{
- return flags ? -EINVAL : 0;
-}
-
int crypto_init_compress_ops(struct crypto_tfm *tfm)
{
struct compress_tfm *ops = &tfm->crt_compress;
diff --git a/crypto/digest.c b/crypto/digest.c
index 8f4593268ce..1bf7414aeb9 100644
--- a/crypto/digest.c
+++ b/crypto/digest.c
@@ -14,7 +14,9 @@
#include <linux/mm.h>
#include <linux/errno.h>
+#include <linux/hardirq.h>
#include <linux/highmem.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
@@ -29,8 +31,8 @@ static int init(struct hash_desc *desc)
return 0;
}
-static int update(struct hash_desc *desc,
- struct scatterlist *sg, unsigned int nbytes)
+static int update2(struct hash_desc *desc,
+ struct scatterlist *sg, unsigned int nbytes)
{
struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
@@ -81,6 +83,14 @@ static int update(struct hash_desc *desc,
return 0;
}
+static int update(struct hash_desc *desc,
+ struct scatterlist *sg, unsigned int nbytes)
+{
+ if (WARN_ON_ONCE(in_irq()))
+ return -EDEADLK;
+ return update2(desc, sg, nbytes);
+}
+
static int final(struct hash_desc *desc, u8 *out)
{
struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
@@ -118,16 +128,14 @@ static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen)
static int digest(struct hash_desc *desc,
struct scatterlist *sg, unsigned int nbytes, u8 *out)
{
+ if (WARN_ON_ONCE(in_irq()))
+ return -EDEADLK;
+
init(desc);
- update(desc, sg, nbytes);
+ update2(desc, sg, nbytes);
return final(desc, out);
}
-int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
-{
- return flags ? -EINVAL : 0;
-}
-
int crypto_init_digest_ops(struct crypto_tfm *tfm)
{
struct hash_tfm *ops = &tfm->crt_hash;
diff --git a/crypto/ecb.c b/crypto/ecb.c
index f239aa9c401..839a0aed8c2 100644
--- a/crypto/ecb.c
+++ b/crypto/ecb.c
@@ -99,12 +99,13 @@ static int crypto_ecb_init_tfm(struct crypto_tfm *tfm)
struct crypto_instance *inst = (void *)tfm->__crt_alg;
struct crypto_spawn *spawn = crypto_instance_ctx(inst);
struct crypto_ecb_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_cipher *cipher;
- tfm = crypto_spawn_tfm(spawn);
- if (IS_ERR(tfm))
- return PTR_ERR(tfm);
+ cipher = crypto_spawn_cipher(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
- ctx->child = crypto_cipher_cast(tfm);
+ ctx->child = cipher;
return 0;
}
diff --git a/crypto/fcrypt.c b/crypto/fcrypt.c
new file mode 100644
index 00000000000..9c2bb535b09
--- /dev/null
+++ b/crypto/fcrypt.c
@@ -0,0 +1,423 @@
+/* FCrypt encryption algorithm
+ *
+ * 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.
+ *
+ * Based on code:
+ *
+ * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+
+#define ROUNDS 16
+
+struct fcrypt_ctx {
+ u32 sched[ROUNDS];
+};
+
+/* Rotate right two 32 bit numbers as a 56 bit number */
+#define ror56(hi, lo, n) \
+do { \
+ u32 t = lo & ((1 << n) - 1); \
+ lo = (lo >> n) | ((hi & ((1 << n) - 1)) << (32 - n)); \
+ hi = (hi >> n) | (t << (24-n)); \
+} while(0)
+
+/* Rotate right one 64 bit number as a 56 bit number */
+#define ror56_64(k, n) \
+do { \
+ k = (k >> n) | ((k & ((1 << n) - 1)) << (56 - n)); \
+} while(0)
+
+/*
+ * Sboxes for Feistel network derived from
+ * /afs/transarc.com/public/afsps/afs.rel31b.export-src/rxkad/sboxes.h
+ */
+#undef Z
+#define Z(x) __constant_be32_to_cpu(x << 3)
+static const u32 sbox0[256] = {
+ Z(0xea), Z(0x7f), Z(0xb2), Z(0x64), Z(0x9d), Z(0xb0), Z(0xd9), Z(0x11),
+ Z(0xcd), Z(0x86), Z(0x86), Z(0x91), Z(0x0a), Z(0xb2), Z(0x93), Z(0x06),
+ Z(0x0e), Z(0x06), Z(0xd2), Z(0x65), Z(0x73), Z(0xc5), Z(0x28), Z(0x60),
+ Z(0xf2), Z(0x20), Z(0xb5), Z(0x38), Z(0x7e), Z(0xda), Z(0x9f), Z(0xe3),
+ Z(0xd2), Z(0xcf), Z(0xc4), Z(0x3c), Z(0x61), Z(0xff), Z(0x4a), Z(0x4a),
+ Z(0x35), Z(0xac), Z(0xaa), Z(0x5f), Z(0x2b), Z(0xbb), Z(0xbc), Z(0x53),
+ Z(0x4e), Z(0x9d), Z(0x78), Z(0xa3), Z(0xdc), Z(0x09), Z(0x32), Z(0x10),
+ Z(0xc6), Z(0x6f), Z(0x66), Z(0xd6), Z(0xab), Z(0xa9), Z(0xaf), Z(0xfd),
+ Z(0x3b), Z(0x95), Z(0xe8), Z(0x34), Z(0x9a), Z(0x81), Z(0x72), Z(0x80),
+ Z(0x9c), Z(0xf3), Z(0xec), Z(0xda), Z(0x9f), Z(0x26), Z(0x76), Z(0x15),
+ Z(0x3e), Z(0x55), Z(0x4d), Z(0xde), Z(0x84), Z(0xee), Z(0xad), Z(0xc7),
+ Z(0xf1), Z(0x6b), Z(0x3d), Z(0xd3), Z(0x04), Z(0x49), Z(0xaa), Z(0x24),
+ Z(0x0b), Z(0x8a), Z(0x83), Z(0xba), Z(0xfa), Z(0x85), Z(0xa0), Z(0xa8),
+ Z(0xb1), Z(0xd4), Z(0x01), Z(0xd8), Z(0x70), Z(0x64), Z(0xf0), Z(0x51),
+ Z(0xd2), Z(0xc3), Z(0xa7), Z(0x75), Z(0x8c), Z(0xa5), Z(0x64), Z(0xef),
+ Z(0x10), Z(0x4e), Z(0xb7), Z(0xc6), Z(0x61), Z(0x03), Z(0xeb), Z(0x44),
+ Z(0x3d), Z(0xe5), Z(0xb3), Z(0x5b), Z(0xae), Z(0xd5), Z(0xad), Z(0x1d),
+ Z(0xfa), Z(0x5a), Z(0x1e), Z(0x33), Z(0xab), Z(0x93), Z(0xa2), Z(0xb7),
+ Z(0xe7), Z(0xa8), Z(0x45), Z(0xa4), Z(0xcd), Z(0x29), Z(0x63), Z(0x44),
+ Z(0xb6), Z(0x69), Z(0x7e), Z(0x2e), Z(0x62), Z(0x03), Z(0xc8), Z(0xe0),
+ Z(0x17), Z(0xbb), Z(0xc7), Z(0xf3), Z(0x3f), Z(0x36), Z(0xba), Z(0x71),
+ Z(0x8e), Z(0x97), Z(0x65), Z(0x60), Z(0x69), Z(0xb6), Z(0xf6), Z(0xe6),
+ Z(0x6e), Z(0xe0), Z(0x81), Z(0x59), Z(0xe8), Z(0xaf), Z(0xdd), Z(0x95),
+ Z(0x22), Z(0x99), Z(0xfd), Z(0x63), Z(0x19), Z(0x74), Z(0x61), Z(0xb1),
+ Z(0xb6), Z(0x5b), Z(0xae), Z(0x54), Z(0xb3), Z(0x70), Z(0xff), Z(0xc6),
+ Z(0x3b), Z(0x3e), Z(0xc1), Z(0xd7), Z(0xe1), Z(0x0e), Z(0x76), Z(0xe5),
+ Z(0x36), Z(0x4f), Z(0x59), Z(0xc7), Z(0x08), Z(0x6e), Z(0x82), Z(0xa6),
+ Z(0x93), Z(0xc4), Z(0xaa), Z(0x26), Z(0x49), Z(0xe0), Z(0x21), Z(0x64),
+ Z(0x07), Z(0x9f), Z(0x64), Z(0x81), Z(0x9c), Z(0xbf), Z(0xf9), Z(0xd1),
+ Z(0x43), Z(0xf8), Z(0xb6), Z(0xb9), Z(0xf1), Z(0x24), Z(0x75), Z(0x03),
+ Z(0xe4), Z(0xb0), Z(0x99), Z(0x46), Z(0x3d), Z(0xf5), Z(0xd1), Z(0x39),
+ Z(0x72), Z(0x12), Z(0xf6), Z(0xba), Z(0x0c), Z(0x0d), Z(0x42), Z(0x2e)
+};
+
+#undef Z
+#define Z(x) __constant_be32_to_cpu((x << 27) | (x >> 5))
+static const u32 sbox1[256] = {
+ Z(0x77), Z(0x14), Z(0xa6), Z(0xfe), Z(0xb2), Z(0x5e), Z(0x8c), Z(0x3e),
+ Z(0x67), Z(0x6c), Z(0xa1), Z(0x0d), Z(0xc2), Z(0xa2), Z(0xc1), Z(0x85),
+ Z(0x6c), Z(0x7b), Z(0x67), Z(0xc6), Z(0x23), Z(0xe3), Z(0xf2), Z(0x89),
+ Z(0x50), Z(0x9c), Z(0x03), Z(0xb7), Z(0x73), Z(0xe6), Z(0xe1), Z(0x39),
+ Z(0x31), Z(0x2c), Z(0x27), Z(0x9f), Z(0xa5), Z(0x69), Z(0x44), Z(0xd6),
+ Z(0x23), Z(0x83), Z(0x98), Z(0x7d), Z(0x3c), Z(0xb4), Z(0x2d), Z(0x99),
+ Z(0x1c), Z(0x1f), Z(0x8c), Z(0x20), Z(0x03), Z(0x7c), Z(0x5f), Z(0xad),
+ Z(0xf4), Z(0xfa), Z(0x95), Z(0xca), Z(0x76), Z(0x44), Z(0xcd), Z(0xb6),
+ Z(0xb8), Z(0xa1), Z(0xa1), Z(0xbe), Z(0x9e), Z(0x54), Z(0x8f), Z(0x0b),
+ Z(0x16), Z(0x74), Z(0x31), Z(0x8a), Z(0x23), Z(0x17), Z(0x04), Z(0xfa),
+ Z(0x79), Z(0x84), Z(0xb1), Z(0xf5), Z(0x13), Z(0xab), Z(0xb5), Z(0x2e),
+ Z(0xaa), Z(0x0c), Z(0x60), Z(0x6b), Z(0x5b), Z(0xc4), Z(0x4b), Z(0xbc),
+ Z(0xe2), Z(0xaf), Z(0x45), Z(0x73), Z(0xfa), Z(0xc9), Z(0x49), Z(0xcd),
+ Z(0x00), Z(0x92), Z(0x7d), Z(0x97), Z(0x7a), Z(0x18), Z(0x60), Z(0x3d),
+ Z(0xcf), Z(0x5b), Z(0xde), Z(0xc6), Z(0xe2), Z(0xe6), Z(0xbb), Z(0x8b),
+ Z(0x06), Z(0xda), Z(0x08), Z(0x15), Z(0x1b), Z(0x88), Z(0x6a), Z(0x17),
+ Z(0x89), Z(0xd0), Z(0xa9), Z(0xc1), Z(0xc9), Z(0x70), Z(0x6b), Z(0xe5),
+ Z(0x43), Z(0xf4), Z(0x68), Z(0xc8), Z(0xd3), Z(0x84), Z(0x28), Z(0x0a),
+ Z(0x52), Z(0x66), Z(0xa3), Z(0xca), Z(0xf2), Z(0xe3), Z(0x7f), Z(0x7a),
+ Z(0x31), Z(0xf7), Z(0x88), Z(0x94), Z(0x5e), Z(0x9c), Z(0x63), Z(0xd5),
+ Z(0x24), Z(0x66), Z(0xfc), Z(0xb3), Z(0x57), Z(0x25), Z(0xbe), Z(0x89),
+ Z(0x44), Z(0xc4), Z(0xe0), Z(0x8f), Z(0x23), Z(0x3c), Z(0x12), Z(0x52),
+ Z(0xf5), Z(0x1e), Z(0xf4), Z(0xcb), Z(0x18), Z(0x33), Z(0x1f), Z(0xf8),
+ Z(0x69), Z(0x10), Z(0x9d), Z(0xd3), Z(0xf7), Z(0x28), Z(0xf8), Z(0x30),
+ Z(0x05), Z(0x5e), Z(0x32), Z(0xc0), Z(0xd5), Z(0x19), Z(0xbd), Z(0x45),
+ Z(0x8b), Z(0x5b), Z(0xfd), Z(0xbc), Z(0xe2), Z(0x5c), Z(0xa9), Z(0x96),
+ Z(0xef), Z(0x70), Z(0xcf), Z(0xc2), Z(0x2a), Z(0xb3), Z(0x61), Z(0xad),
+ Z(0x80), Z(0x48), Z(0x81), Z(0xb7), Z(0x1d), Z(0x43), Z(0xd9), Z(0xd7),
+ Z(0x45), Z(0xf0), Z(0xd8), Z(0x8a), Z(0x59), Z(0x7c), Z(0x57), Z(0xc1),
+ Z(0x79), Z(0xc7), Z(0x34), Z(0xd6), Z(0x43), Z(0xdf), Z(0xe4), Z(0x78),
+ Z(0x16), Z(0x06), Z(0xda), Z(0x92), Z(0x76), Z(0x51), Z(0xe1), Z(0xd4),
+ Z(0x70), Z(0x03), Z(0xe0), Z(0x2f), Z(0x96), Z(0x91), Z(0x82), Z(0x80)
+};
+
+#undef Z
+#define Z(x) __constant_be32_to_cpu(x << 11)
+static const u32 sbox2[256] = {
+ Z(0xf0), Z(0x37), Z(0x24), Z(0x53), Z(0x2a), Z(0x03), Z(0x83), Z(0x86),
+ Z(0xd1), Z(0xec), Z(0x50), Z(0xf0), Z(0x42), Z(0x78), Z(0x2f), Z(0x6d),
+ Z(0xbf), Z(0x80), Z(0x87), Z(0x27), Z(0x95), Z(0xe2), Z(0xc5), Z(0x5d),
+ Z(0xf9), Z(0x6f), Z(0xdb), Z(0xb4), Z(0x65), Z(0x6e), Z(0xe7), Z(0x24),
+ Z(0xc8), Z(0x1a), Z(0xbb), Z(0x49), Z(0xb5), Z(0x0a), Z(0x7d), Z(0xb9),
+ Z(0xe8), Z(0xdc), Z(0xb7), Z(0xd9), Z(0x45), Z(0x20), Z(0x1b), Z(0xce),
+ Z(0x59), Z(0x9d), Z(0x6b), Z(0xbd), Z(0x0e), Z(0x8f), Z(0xa3), Z(0xa9),
+ Z(0xbc), Z(0x74), Z(0xa6), Z(0xf6), Z(0x7f), Z(0x5f), Z(0xb1), Z(0x68),
+ Z(0x84), Z(0xbc), Z(0xa9), Z(0xfd), Z(0x55), Z(0x50), Z(0xe9), Z(0xb6),
+ Z(0x13), Z(0x5e), Z(0x07), Z(0xb8), Z(0x95), Z(0x02), Z(0xc0), Z(0xd0),
+ Z(0x6a), Z(0x1a), Z(0x85), Z(0xbd), Z(0xb6), Z(0xfd), Z(0xfe), Z(0x17),
+ Z(0x3f), Z(0x09), Z(0xa3), Z(0x8d), Z(0xfb), Z(0xed), Z(0xda), Z(0x1d),
+ Z(0x6d), Z(0x1c), Z(0x6c), Z(0x01), Z(0x5a), Z(0xe5), Z(0x71), Z(0x3e),
+ Z(0x8b), Z(0x6b), Z(0xbe), Z(0x29), Z(0xeb), Z(0x12), Z(0x19), Z(0x34),
+ Z(0xcd), Z(0xb3), Z(0xbd), Z(0x35), Z(0xea), Z(0x4b), Z(0xd5), Z(0xae),
+ Z(0x2a), Z(0x79), Z(0x5a), Z(0xa5), Z(0x32), Z(0x12), Z(0x7b), Z(0xdc),
+ Z(0x2c), Z(0xd0), Z(0x22), Z(0x4b), Z(0xb1), Z(0x85), Z(0x59), Z(0x80),
+ Z(0xc0), Z(0x30), Z(0x9f), Z(0x73), Z(0xd3), Z(0x14), Z(0x48), Z(0x40),
+ Z(0x07), Z(0x2d), Z(0x8f), Z(0x80), Z(0x0f), Z(0xce), Z(0x0b), Z(0x5e),
+ Z(0xb7), Z(0x5e), Z(0xac), Z(0x24), Z(0x94), Z(0x4a), Z(0x18), Z(0x15),
+ Z(0x05), Z(0xe8), Z(0x02), Z(0x77), Z(0xa9), Z(0xc7), Z(0x40), Z(0x45),
+ Z(0x89), Z(0xd1), Z(0xea), Z(0xde), Z(0x0c), Z(0x79), Z(0x2a), Z(0x99),
+ Z(0x6c), Z(0x3e), Z(0x95), Z(0xdd), Z(0x8c), Z(0x7d), Z(0xad), Z(0x6f),
+ Z(0xdc), Z(0xff), Z(0xfd), Z(0x62), Z(0x47), Z(0xb3), Z(0x21), Z(0x8a),
+ Z(0xec), Z(0x8e), Z(0x19), Z(0x18), Z(0xb4), Z(0x6e), Z(0x3d), Z(0xfd),
+ Z(0x74), Z(0x54), Z(0x1e), Z(0x04), Z(0x85), Z(0xd8), Z(0xbc), Z(0x1f),
+ Z(0x56), Z(0xe7), Z(0x3a), Z(0x56), Z(0x67), Z(0xd6), Z(0xc8), Z(0xa5),
+ Z(0xf3), Z(0x8e), Z(0xde), Z(0xae), Z(0x37), Z(0x49), Z(0xb7), Z(0xfa),
+ Z(0xc8), Z(0xf4), Z(0x1f), Z(0xe0), Z(0x2a), Z(0x9b), Z(0x15), Z(0xd1),
+ Z(0x34), Z(0x0e), Z(0xb5), Z(0xe0), Z(0x44), Z(0x78), Z(0x84), Z(0x59),
+ Z(0x56), Z(0x68), Z(0x77), Z(0xa5), Z(0x14), Z(0x06), Z(0xf5), Z(0x2f),
+ Z(0x8c), Z(0x8a), Z(0x73), Z(0x80), Z(0x76), Z(0xb4), Z(0x10), Z(0x86)
+};
+
+#undef Z
+#define Z(x) __constant_be32_to_cpu(x << 19)
+static const u32 sbox3[256] = {
+ Z(0xa9), Z(0x2a), Z(0x48), Z(0x51), Z(0x84), Z(0x7e), Z(0x49), Z(0xe2),
+ Z(0xb5), Z(0xb7), Z(0x42), Z(0x33), Z(0x7d), Z(0x5d), Z(0xa6), Z(0x12),
+ Z(0x44), Z(0x48), Z(0x6d), Z(0x28), Z(0xaa), Z(0x20), Z(0x6d), Z(0x57),
+ Z(0xd6), Z(0x6b), Z(0x5d), Z(0x72), Z(0xf0), Z(0x92), Z(0x5a), Z(0x1b),
+ Z(0x53), Z(0x80), Z(0x24), Z(0x70), Z(0x9a), Z(0xcc), Z(0xa7), Z(0x66),
+ Z(0xa1), Z(0x01), Z(0xa5), Z(0x41), Z(0x97), Z(0x41), Z(0x31), Z(0x82),
+ Z(0xf1), Z(0x14), Z(0xcf), Z(0x53), Z(0x0d), Z(0xa0), Z(0x10), Z(0xcc),
+ Z(0x2a), Z(0x7d), Z(0xd2), Z(0xbf), Z(0x4b), Z(0x1a), Z(0xdb), Z(0x16),
+ Z(0x47), Z(0xf6), Z(0x51), Z(0x36), Z(0xed), Z(0xf3), Z(0xb9), Z(0x1a),
+ Z(0xa7), Z(0xdf), Z(0x29), Z(0x43), Z(0x01), Z(0x54), Z(0x70), Z(0xa4),
+ Z(0xbf), Z(0xd4), Z(0x0b), Z(0x53), Z(0x44), Z(0x60), Z(0x9e), Z(0x23),
+ Z(0xa1), Z(0x18), Z(0x68), Z(0x4f), Z(0xf0), Z(0x2f), Z(0x82), Z(0xc2),
+ Z(0x2a), Z(0x41), Z(0xb2), Z(0x42), Z(0x0c), Z(0xed), Z(0x0c), Z(0x1d),
+ Z(0x13), Z(0x3a), Z(0x3c), Z(0x6e), Z(0x35), Z(0xdc), Z(0x60), Z(0x65),
+ Z(0x85), Z(0xe9), Z(0x64), Z(0x02), Z(0x9a), Z(0x3f), Z(0x9f), Z(0x87),
+ Z(0x96), Z(0xdf), Z(0xbe), Z(0xf2), Z(0xcb), Z(0xe5), Z(0x6c), Z(0xd4),
+ Z(0x5a), Z(0x83), Z(0xbf), Z(0x92), Z(0x1b), Z(0x94), Z(0x00), Z(0x42),
+ Z(0xcf), Z(0x4b), Z(0x00), Z(0x75), Z(0xba), Z(0x8f), Z(0x76), Z(0x5f),
+ Z(0x5d), Z(0x3a), Z(0x4d), Z(0x09), Z(0x12), Z(0x08), Z(0x38), Z(0x95),
+ Z(0x17), Z(0xe4), Z(0x01), Z(0x1d), Z(0x4c), Z(0xa9), Z(0xcc), Z(0x85),
+ Z(0x82), Z(0x4c), Z(0x9d), Z(0x2f), Z(0x3b), Z(0x66), Z(0xa1), Z(0x34),
+ Z(0x10), Z(0xcd), Z(0x59), Z(0x89), Z(0xa5), Z(0x31), Z(0xcf), Z(0x05),
+ Z(0xc8), Z(0x84), Z(0xfa), Z(0xc7), Z(0xba), Z(0x4e), Z(0x8b), Z(0x1a),
+ Z(0x19), Z(0xf1), Z(0xa1), Z(0x3b), Z(0x18), Z(0x12), Z(0x17), Z(0xb0),
+ Z(0x98), Z(0x8d), Z(0x0b), Z(0x23), Z(0xc3), Z(0x3a), Z(0x2d), Z(0x20),
+ Z(0xdf), Z(0x13), Z(0xa0), Z(0xa8), Z(0x4c), Z(0x0d), Z(0x6c), Z(0x2f),
+ Z(0x47), Z(0x13), Z(0x13), Z(0x52), Z(0x1f), Z(0x2d), Z(0xf5), Z(0x79),
+ Z(0x3d), Z(0xa2), Z(0x54), Z(0xbd), Z(0x69), Z(0xc8), Z(0x6b), Z(0xf3),
+ Z(0x05), Z(0x28), Z(0xf1), Z(0x16), Z(0x46), Z(0x40), Z(0xb0), Z(0x11),
+ Z(0xd3), Z(0xb7), Z(0x95), Z(0x49), Z(0xcf), Z(0xc3), Z(0x1d), Z(0x8f),
+ Z(0xd8), Z(0xe1), Z(0x73), Z(0xdb), Z(0xad), Z(0xc8), Z(0xc9), Z(0xa9),
+ Z(0xa1), Z(0xc2), Z(0xc5), Z(0xe3), Z(0xba), Z(0xfc), Z(0x0e), Z(0x25)
+};
+
+/*
+ * This is a 16 round Feistel network with permutation F_ENCRYPT
+ */
+#define F_ENCRYPT(R, L, sched) \
+do { \
+ union lc4 { u32 l; u8 c[4]; } u; \
+ u.l = sched ^ R; \
+ L ^= sbox0[u.c[0]] ^ sbox1[u.c[1]] ^ sbox2[u.c[2]] ^ sbox3[u.c[3]]; \
+} while(0)
+
+/*
+ * encryptor
+ */
+static void fcrypt_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+ const struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct {
+ u32 l, r;
+ } X;
+
+ memcpy(&X, src, sizeof(X));
+
+ F_ENCRYPT(X.r, X.l, ctx->sched[0x0]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0x1]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0x2]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0x3]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0x4]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0x5]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0x6]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0x7]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0x8]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0x9]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0xa]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0xb]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0xc]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0xd]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0xe]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0xf]);
+
+ memcpy(dst, &X, sizeof(X));
+}
+
+/*
+ * decryptor
+ */
+static void fcrypt_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+ const struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct {
+ u32 l, r;
+ } X;
+
+ memcpy(&X, src, sizeof(X));
+
+ F_ENCRYPT(X.l, X.r, ctx->sched[0xf]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0xe]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0xd]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0xc]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0xb]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0xa]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0x9]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0x8]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0x7]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0x6]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0x5]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0x4]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0x3]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0x2]);
+ F_ENCRYPT(X.l, X.r, ctx->sched[0x1]);
+ F_ENCRYPT(X.r, X.l, ctx->sched[0x0]);
+
+ memcpy(dst, &X, sizeof(X));
+}
+
+/*
+ * Generate a key schedule from key, the least significant bit in each key byte
+ * is parity and shall be ignored. This leaves 56 significant bits in the key
+ * to scatter over the 16 key schedules. For each schedule extract the low
+ * order 32 bits and use as schedule, then rotate right by 11 bits.
+ */
+static int fcrypt_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+ struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm);
+
+#if BITS_PER_LONG == 64 /* the 64-bit version can also be used for 32-bit
+ * kernels - it seems to be faster but the code is
+ * larger */
+
+ u64 k; /* k holds all 56 non-parity bits */
+
+ /* discard the parity bits */
+ k = (*key++) >> 1;
+ k <<= 7;
+ k |= (*key++) >> 1;
+ k <<= 7;
+ k |= (*key++) >> 1;
+ k <<= 7;
+ k |= (*key++) >> 1;
+ k <<= 7;
+ k |= (*key++) >> 1;
+ k <<= 7;
+ k |= (*key++) >> 1;
+ k <<= 7;
+ k |= (*key++) >> 1;
+ k <<= 7;
+ k |= (*key) >> 1;
+
+ /* Use lower 32 bits for schedule, rotate by 11 each round (16 times) */
+ ctx->sched[0x0] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0x1] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0x2] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0x3] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0x4] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0x5] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0x6] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0x7] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0x8] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0x9] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0xa] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0xb] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0xc] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0xd] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0xe] = be32_to_cpu(k); ror56_64(k, 11);
+ ctx->sched[0xf] = be32_to_cpu(k);
+
+ return 0;
+#else
+ u32 hi, lo; /* hi is upper 24 bits and lo lower 32, total 56 */
+
+ /* discard the parity bits */
+ lo = (*key++) >> 1;
+ lo <<= 7;
+ lo |= (*key++) >> 1;
+ lo <<= 7;
+ lo |= (*key++) >> 1;
+ lo <<= 7;
+ lo |= (*key++) >> 1;
+ hi = lo >> 4;
+ lo &= 0xf;
+ lo <<= 7;
+ lo |= (*key++) >> 1;
+ lo <<= 7;
+ lo |= (*key++) >> 1;
+ lo <<= 7;
+ lo |= (*key++) >> 1;
+ lo <<= 7;
+ lo |= (*key) >> 1;
+
+ /* Use lower 32 bits for schedule, rotate by 11 each round (16 times) */
+ ctx->sched[0x0] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0x1] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0x2] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0x3] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0x4] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0x5] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0x6] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0x7] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0x8] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0x9] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0xa] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0xb] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0xc] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0xd] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0xe] = be32_to_cpu(lo); ror56(hi, lo, 11);
+ ctx->sched[0xf] = be32_to_cpu(lo);
+ return 0;
+#endif
+}
+
+static struct crypto_alg fcrypt_alg = {
+ .cra_name = "fcrypt",
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = 8,
+ .cra_ctxsize = sizeof(struct fcrypt_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_alignmask = 3,
+ .cra_list = LIST_HEAD_INIT(fcrypt_alg.cra_list),
+ .cra_u = { .cipher = {
+ .cia_min_keysize = 8,
+ .cia_max_keysize = 8,
+ .cia_setkey = fcrypt_setkey,
+ .cia_encrypt = fcrypt_encrypt,
+ .cia_decrypt = fcrypt_decrypt } }
+};
+
+static int __init init(void)
+{
+ return crypto_register_alg(&fcrypt_alg);
+}
+
+static void __exit fini(void)
+{
+ crypto_unregister_alg(&fcrypt_alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FCrypt Cipher Algorithm");
+MODULE_AUTHOR("David Howells <dhowells@redhat.com>");
diff --git a/crypto/hash.c b/crypto/hash.c
index cdec23d885f..12c4514f347 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -16,12 +16,13 @@
#include "internal.h"
-static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg)
+static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg, u32 type,
+ u32 mask)
{
return alg->cra_ctxsize;
}
-static int crypto_init_hash_ops(struct crypto_tfm *tfm)
+static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
{
struct hash_tfm *crt = &tfm->crt_hash;
struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
diff --git a/crypto/hmac.c b/crypto/hmac.c
index b521bcd2b2c..44187c5ee59 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -172,15 +172,16 @@ static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg,
static int hmac_init_tfm(struct crypto_tfm *tfm)
{
+ struct crypto_hash *hash;
struct crypto_instance *inst = (void *)tfm->__crt_alg;
struct crypto_spawn *spawn = crypto_instance_ctx(inst);
struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
- tfm = crypto_spawn_tfm(spawn);
- if (IS_ERR(tfm))
- return PTR_ERR(tfm);
+ hash = crypto_spawn_hash(spawn);
+ if (IS_ERR(hash))
+ return PTR_ERR(hash);
- ctx->child = crypto_hash_cast(tfm);
+ ctx->child = hash;
return 0;
}
diff --git a/crypto/internal.h b/crypto/internal.h
index 2da6ad4f359..60acad9788c 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -83,8 +83,7 @@ static inline void crypto_exit_proc(void)
{ }
#endif
-static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg,
- int flags)
+static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg)
{
unsigned int len = alg->cra_ctxsize;
@@ -96,23 +95,12 @@ static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg,
return len;
}
-static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg,
- int flags)
+static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg)
{
- unsigned int len = alg->cra_ctxsize;
-
- switch (flags & CRYPTO_TFM_MODE_MASK) {
- case CRYPTO_TFM_MODE_CBC:
- len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1);
- len += alg->cra_blocksize;
- break;
- }
-
- return len;
+ return alg->cra_ctxsize;
}
-static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg,
- int flags)
+static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg)
{
return alg->cra_ctxsize;
}
@@ -121,10 +109,6 @@ struct crypto_alg *crypto_mod_get(struct crypto_alg *alg);
struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask);
struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask);
-int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags);
-int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags);
-int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags);
-
int crypto_init_digest_ops(struct crypto_tfm *tfm);
int crypto_init_cipher_ops(struct crypto_tfm *tfm);
int crypto_init_compress_ops(struct crypto_tfm *tfm);
@@ -136,7 +120,8 @@ void crypto_exit_compress_ops(struct crypto_tfm *tfm);
void crypto_larval_error(const char *name, u32 type, u32 mask);
void crypto_shoot_alg(struct crypto_alg *alg);
-struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags);
+struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
+ u32 mask);
int crypto_register_instance(struct crypto_template *tmpl,
struct crypto_instance *inst);
diff --git a/crypto/lrw.c b/crypto/lrw.c
index 56642586d84..b4105080ac7 100644
--- a/crypto/lrw.c
+++ b/crypto/lrw.c
@@ -201,21 +201,22 @@ static int decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
static int init_tfm(struct crypto_tfm *tfm)
{
+ struct crypto_cipher *cipher;
struct crypto_instance *inst = (void *)tfm->__crt_alg;
struct crypto_spawn *spawn = crypto_instance_ctx(inst);
struct priv *ctx = crypto_tfm_ctx(tfm);
u32 *flags = &tfm->crt_flags;
- tfm = crypto_spawn_tfm(spawn);
- if (IS_ERR(tfm))
- return PTR_ERR(tfm);
+ cipher = crypto_spawn_cipher(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
- if (crypto_tfm_alg_blocksize(tfm) != 16) {
+ if (crypto_cipher_blocksize(cipher) != 16) {
*flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
return -EINVAL;
}
- ctx->child = crypto_cipher_cast(tfm);
+ ctx->child = cipher;
return 0;
}
diff --git a/crypto/pcbc.c b/crypto/pcbc.c
new file mode 100644
index 00000000000..5174d7fdad6
--- /dev/null
+++ b/crypto/pcbc.c
@@ -0,0 +1,349 @@
+/*
+ * PCBC: Propagating Cipher Block Chaining mode
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Derived from cbc.c
+ * - Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify 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 <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+
+struct crypto_pcbc_ctx {
+ struct crypto_cipher *child;
+ void (*xor)(u8 *dst, const u8 *src, unsigned int bs);
+};
+
+static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key,
+ unsigned int keylen)
+{
+ struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(parent);
+ struct crypto_cipher *child = ctx->child;
+ int err;
+
+ crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
+ CRYPTO_TFM_REQ_MASK);
+ err = crypto_cipher_setkey(child, key, keylen);
+ crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
+ CRYPTO_TFM_RES_MASK);
+ return err;
+}
+
+static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc,
+ struct blkcipher_walk *walk,
+ struct crypto_cipher *tfm,
+ void (*xor)(u8 *, const u8 *,
+ unsigned int))
+{
+ void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+ crypto_cipher_alg(tfm)->cia_encrypt;
+ int bsize = crypto_cipher_blocksize(tfm);
+ unsigned int nbytes = walk->nbytes;
+ u8 *src = walk->src.virt.addr;
+ u8 *dst = walk->dst.virt.addr;
+ u8 *iv = walk->iv;
+
+ do {
+ xor(iv, src, bsize);
+ fn(crypto_cipher_tfm(tfm), dst, iv);
+ memcpy(iv, dst, bsize);
+ xor(iv, src, bsize);
+
+ src += bsize;
+ dst += bsize;
+ } while ((nbytes -= bsize) >= bsize);
+
+ return nbytes;
+}
+
+static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc,
+ struct blkcipher_walk *walk,
+ struct crypto_cipher *tfm,
+ void (*xor)(u8 *, const u8 *,
+ unsigned int))
+{
+ void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+ crypto_cipher_alg(tfm)->cia_encrypt;
+ int bsize = crypto_cipher_blocksize(tfm);
+ unsigned int nbytes = walk->nbytes;
+ u8 *src = walk->src.virt.addr;
+ u8 *iv = walk->iv;
+ u8 tmpbuf[bsize];
+
+ do {
+ memcpy(tmpbuf, src, bsize);
+ xor(iv, tmpbuf, bsize);
+ fn(crypto_cipher_tfm(tfm), src, iv);
+ memcpy(iv, src, bsize);
+ xor(iv, tmpbuf, bsize);
+
+ src += bsize;
+ } while ((nbytes -= bsize) >= bsize);
+
+ memcpy(walk->iv, iv, bsize);
+
+ return nbytes;
+}
+
+static int crypto_pcbc_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct blkcipher_walk walk;
+ struct crypto_blkcipher *tfm = desc->tfm;
+ struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
+ struct crypto_cipher *child = ctx->child;
+ void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt(desc, &walk);
+
+ while ((nbytes = walk.nbytes)) {
+ if (walk.src.virt.addr == walk.dst.virt.addr)
+ nbytes = crypto_pcbc_encrypt_inplace(desc, &walk, child,
+ xor);
+ else
+ nbytes = crypto_pcbc_encrypt_segment(desc, &walk, child,
+ xor);
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ return err;
+}
+
+static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc,
+ struct blkcipher_walk *walk,
+ struct crypto_cipher *tfm,
+ void (*xor)(u8 *, const u8 *,
+ unsigned int))
+{
+ void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+ crypto_cipher_alg(tfm)->cia_decrypt;
+ int bsize = crypto_cipher_blocksize(tfm);
+ unsigned int nbytes = walk->nbytes;
+ u8 *src = walk->src.virt.addr;
+ u8 *dst = walk->dst.virt.addr;
+ u8 *iv = walk->iv;
+
+ do {
+ fn(crypto_cipher_tfm(tfm), dst, src);
+ xor(dst, iv, bsize);
+ memcpy(iv, src, bsize);
+ xor(iv, dst, bsize);
+
+ src += bsize;
+ dst += bsize;
+ } while ((nbytes -= bsize) >= bsize);
+
+ memcpy(walk->iv, iv, bsize);
+
+ return nbytes;
+}
+
+static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc,
+ struct blkcipher_walk *walk,
+ struct crypto_cipher *tfm,
+ void (*xor)(u8 *, const u8 *,
+ unsigned int))
+{
+ void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+ crypto_cipher_alg(tfm)->cia_decrypt;
+ int bsize = crypto_cipher_blocksize(tfm);
+ unsigned int nbytes = walk->nbytes;
+ u8 *src = walk->src.virt.addr;
+ u8 *iv = walk->iv;
+ u8 tmpbuf[bsize];
+
+ do {
+ memcpy(tmpbuf, src, bsize);
+ fn(crypto_cipher_tfm(tfm), src, src);
+ xor(src, iv, bsize);
+ memcpy(iv, tmpbuf, bsize);
+ xor(iv, src, bsize);
+
+ src += bsize;
+ } while ((nbytes -= bsize) >= bsize);
+
+ memcpy(walk->iv, iv, bsize);
+
+ return nbytes;
+}
+
+static int crypto_pcbc_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct blkcipher_walk walk;
+ struct crypto_blkcipher *tfm = desc->tfm;
+ struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
+ struct crypto_cipher *child = ctx->child;
+ void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt(desc, &walk);
+
+ while ((nbytes = walk.nbytes)) {
+ if (walk.src.virt.addr == walk.dst.virt.addr)
+ nbytes = crypto_pcbc_decrypt_inplace(desc, &walk, child,
+ xor);
+ else
+ nbytes = crypto_pcbc_decrypt_segment(desc, &walk, child,
+ xor);
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ return err;
+}
+
+static void xor_byte(u8 *a, const u8 *b, unsigned int bs)
+{
+ do {
+ *a++ ^= *b++;
+ } while (--bs);
+}
+
+static void xor_quad(u8 *dst, const u8 *src, unsigned int bs)
+{
+ u32 *a = (u32 *)dst;
+ u32 *b = (u32 *)src;
+
+ do {
+ *a++ ^= *b++;
+ } while ((bs -= 4));
+}
+
+static void xor_64(u8 *a, const u8 *b, unsigned int bs)
+{
+ ((u32 *)a)[0] ^= ((u32 *)b)[0];
+ ((u32 *)a)[1] ^= ((u32 *)b)[1];
+}
+
+static void xor_128(u8 *a, const u8 *b, unsigned int bs)
+{
+ ((u32 *)a)[0] ^= ((u32 *)b)[0];
+ ((u32 *)a)[1] ^= ((u32 *)b)[1];
+ ((u32 *)a)[2] ^= ((u32 *)b)[2];
+ ((u32 *)a)[3] ^= ((u32 *)b)[3];
+}
+
+static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_instance *inst = (void *)tfm->__crt_alg;
+ struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+ struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_cipher *cipher;
+
+ switch (crypto_tfm_alg_blocksize(tfm)) {
+ case 8:
+ ctx->xor = xor_64;
+ break;
+
+ case 16:
+ ctx->xor = xor_128;
+ break;
+
+ default:
+ if (crypto_tfm_alg_blocksize(tfm) % 4)
+ ctx->xor = xor_byte;
+ else
+ ctx->xor = xor_quad;
+ }
+
+ cipher = crypto_spawn_cipher(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
+
+ ctx->child = cipher;
+ return 0;
+}
+
+static void crypto_pcbc_exit_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm);
+ crypto_free_cipher(ctx->child);
+}
+
+static struct crypto_instance *crypto_pcbc_alloc(void *param, unsigned int len)
+{
+ struct crypto_instance *inst;
+ struct crypto_alg *alg;
+
+ alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
+ CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+ if (IS_ERR(alg))
+ return ERR_PTR(PTR_ERR(alg));
+
+ inst = crypto_alloc_instance("pcbc", alg);
+ if (IS_ERR(inst))
+ goto out_put_alg;
+
+ inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
+ inst->alg.cra_priority = alg->cra_priority;
+ inst->alg.cra_blocksize = alg->cra_blocksize;
+ inst->alg.cra_alignmask = alg->cra_alignmask;
+ inst->alg.cra_type = &crypto_blkcipher_type;
+
+ if (!(alg->cra_blocksize % 4))
+ inst->alg.cra_alignmask |= 3;
+ inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
+ inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
+ inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
+
+ inst->alg.cra_ctxsize = sizeof(struct crypto_pcbc_ctx);
+
+ inst->alg.cra_init = crypto_pcbc_init_tfm;
+ inst->alg.cra_exit = crypto_pcbc_exit_tfm;
+
+ inst->alg.cra_blkcipher.setkey = crypto_pcbc_setkey;
+ inst->alg.cra_blkcipher.encrypt = crypto_pcbc_encrypt;
+ inst->alg.cra_blkcipher.decrypt = crypto_pcbc_decrypt;
+
+out_put_alg:
+ crypto_mod_put(alg);
+ return inst;
+}
+
+static void crypto_pcbc_free(struct crypto_instance *inst)
+{
+ crypto_drop_spawn(crypto_instance_ctx(inst));
+ kfree(inst);
+}
+
+static struct crypto_template crypto_pcbc_tmpl = {
+ .name = "pcbc",
+ .alloc = crypto_pcbc_alloc,
+ .free = crypto_pcbc_free,
+ .module = THIS_MODULE,
+};
+
+static int __init crypto_pcbc_module_init(void)
+{
+ return crypto_register_template(&crypto_pcbc_tmpl);
+}
+
+static void __exit crypto_pcbc_module_exit(void)
+{
+ crypto_unregister_template(&crypto_pcbc_tmpl);
+}
+
+module_init(crypto_pcbc_module_init);
+module_exit(crypto_pcbc_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCBC block cipher algorithm");
diff --git a/crypto/sha512.c b/crypto/sha512.c
index 2dfe7f170b4..15eab9db9be 100644
--- a/crypto/sha512.c
+++ b/crypto/sha512.c
@@ -24,7 +24,7 @@
#define SHA384_DIGEST_SIZE 48
#define SHA512_DIGEST_SIZE 64
-#define SHA384_HMAC_BLOCK_SIZE 96
+#define SHA384_HMAC_BLOCK_SIZE 128
#define SHA512_HMAC_BLOCK_SIZE 128
struct sha512_ctx {
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index d671e8942b1..f5e9da319ec 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -12,6 +12,7 @@
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
+ * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests
* 2004-08-09 Added cipher speed tests (Reyk Floeter <reyk@vantronix.net>)
* 2003-09-14 Rewritten by Kartikey Mahendra Bhatt
*
@@ -71,7 +72,8 @@ static char *check[] = {
"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
"twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6",
"arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
- "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", NULL
+ "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", "fcrypt",
+ "camellia", NULL
};
static void hexdump(unsigned char *buf, unsigned int len)
@@ -765,7 +767,7 @@ static void test_deflate(void)
memcpy(tvmem, deflate_comp_tv_template, tsize);
tv = (void *)tvmem;
- tfm = crypto_alloc_tfm("deflate", 0);
+ tfm = crypto_alloc_comp("deflate", 0, CRYPTO_ALG_ASYNC);
if (tfm == NULL) {
printk("failed to load transform for deflate\n");
return;
@@ -964,6 +966,26 @@ static void do_test(void)
test_cipher("ecb(xeta)", DECRYPT, xeta_dec_tv_template,
XETA_DEC_TEST_VECTORS);
+ //FCrypt
+ test_cipher("pcbc(fcrypt)", ENCRYPT, fcrypt_pcbc_enc_tv_template,
+ FCRYPT_ENC_TEST_VECTORS);
+ test_cipher("pcbc(fcrypt)", DECRYPT, fcrypt_pcbc_dec_tv_template,
+ FCRYPT_DEC_TEST_VECTORS);
+
+ //CAMELLIA
+ test_cipher("ecb(camellia)", ENCRYPT,
+ camellia_enc_tv_template,
+ CAMELLIA_ENC_TEST_VECTORS);
+ test_cipher("ecb(camellia)", DECRYPT,
+ camellia_dec_tv_template,
+ CAMELLIA_DEC_TEST_VECTORS);
+ test_cipher("cbc(camellia)", ENCRYPT,
+ camellia_cbc_enc_tv_template,
+ CAMELLIA_CBC_ENC_TEST_VECTORS);
+ test_cipher("cbc(camellia)", DECRYPT,
+ camellia_cbc_dec_tv_template,
+ CAMELLIA_CBC_DEC_TEST_VECTORS);
+
test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS);
@@ -980,6 +1002,10 @@ static void do_test(void)
HMAC_SHA1_TEST_VECTORS);
test_hash("hmac(sha256)", hmac_sha256_tv_template,
HMAC_SHA256_TEST_VECTORS);
+ test_hash("hmac(sha384)", hmac_sha384_tv_template,
+ HMAC_SHA384_TEST_VECTORS);
+ test_hash("hmac(sha512)", hmac_sha512_tv_template,
+ HMAC_SHA512_TEST_VECTORS);
test_hash("xcbc(aes)", aes_xcbc128_tv_template,
XCBC_AES_TEST_VECTORS);
@@ -1177,6 +1203,28 @@ static void do_test(void)
XETA_DEC_TEST_VECTORS);
break;
+ case 31:
+ test_cipher("pcbc(fcrypt)", ENCRYPT, fcrypt_pcbc_enc_tv_template,
+ FCRYPT_ENC_TEST_VECTORS);
+ test_cipher("pcbc(fcrypt)", DECRYPT, fcrypt_pcbc_dec_tv_template,
+ FCRYPT_DEC_TEST_VECTORS);
+ break;
+
+ case 32:
+ test_cipher("ecb(camellia)", ENCRYPT,
+ camellia_enc_tv_template,
+ CAMELLIA_ENC_TEST_VECTORS);
+ test_cipher("ecb(camellia)", DECRYPT,
+ camellia_dec_tv_template,
+ CAMELLIA_DEC_TEST_VECTORS);
+ test_cipher("cbc(camellia)", ENCRYPT,
+ camellia_cbc_enc_tv_template,
+ CAMELLIA_CBC_ENC_TEST_VECTORS);
+ test_cipher("cbc(camellia)", DECRYPT,
+ camellia_cbc_dec_tv_template,
+ CAMELLIA_CBC_DEC_TEST_VECTORS);
+ break;
+
case 100:
test_hash("hmac(md5)", hmac_md5_tv_template,
HMAC_MD5_TEST_VECTORS);
@@ -1192,6 +1240,16 @@ static void do_test(void)
HMAC_SHA256_TEST_VECTORS);
break;
+ case 103:
+ test_hash("hmac(sha384)", hmac_sha384_tv_template,
+ HMAC_SHA384_TEST_VECTORS);
+ break;
+
+ case 104:
+ test_hash("hmac(sha512)", hmac_sha512_tv_template,
+ HMAC_SHA512_TEST_VECTORS);
+ break;
+
case 200:
test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
@@ -1260,6 +1318,17 @@ static void do_test(void)
des_speed_template);
break;
+ case 205:
+ test_cipher_speed("ecb(camellia)", ENCRYPT, sec, NULL, 0,
+ camellia_speed_template);
+ test_cipher_speed("ecb(camellia)", DECRYPT, sec, NULL, 0,
+ camellia_speed_template);
+ test_cipher_speed("cbc(camellia)", ENCRYPT, sec, NULL, 0,
+ camellia_speed_template);
+ test_cipher_speed("cbc(camellia)", DECRYPT, sec, NULL, 0,
+ camellia_speed_template);
+ break;
+
case 300:
/* fall through */
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index 48a81362cb8..887527bd5bc 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -12,6 +12,7 @@
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
+ * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests
* 2004-08-09 Cipher speed tests by Reyk Floeter <reyk@vantronix.net>
* 2003-09-14 Changes by Kartikey Mahendra Bhatt
*
@@ -27,7 +28,7 @@
struct hash_testvec {
/* only used with keyed hash algorithms */
- char key[128] __attribute__ ((__aligned__(4)));
+ char key[132] __attribute__ ((__aligned__(4)));
char plaintext[240];
char digest[MAX_DIGEST_SIZE];
unsigned char tap[MAX_TAP];
@@ -1002,6 +1003,248 @@ static struct hash_testvec aes_xcbc128_tv_template[] = {
};
/*
+ * SHA384 HMAC test vectors from RFC4231
+ */
+
+#define HMAC_SHA384_TEST_VECTORS 4
+
+static struct hash_testvec hmac_sha384_tv_template[] = {
+ {
+ .key = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b }, // (20 bytes)
+ .ksize = 20,
+ .plaintext = { 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 }, // ("Hi There")
+ .psize = 8,
+ .digest = { 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62,
+ 0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f,
+ 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+ 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c,
+ 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f,
+ 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6 },
+ }, {
+ .key = { 0x4a, 0x65, 0x66, 0x65 }, // ("Jefe")
+ .ksize = 4,
+ .plaintext = { 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20,
+ 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, // ("what do ya want ")
+ 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
+ 0x69, 0x6e, 0x67, 0x3f }, // ("for nothing?")
+ .psize = 28,
+ .digest = { 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31,
+ 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b,
+ 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+ 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e,
+ 0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7,
+ 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49 },
+ .np = 4,
+ .tap = { 7, 7, 7, 7 }
+ }, {
+ .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa }, // (131 bytes)
+ .ksize = 131,
+ .plaintext = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69,
+ 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, // ("Test Using Large")
+ 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, // ("r Than Block-Siz")
+ 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20,
+ 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, // ("e Key - Hash Key")
+ 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 }, // (" First")
+ .psize = 54,
+ .digest = { 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90,
+ 0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4,
+ 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+ 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6,
+ 0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82,
+ 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52 },
+ }, {
+ .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa }, // (131 bytes)
+ .ksize = 131,
+ .plaintext = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+ 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, // ("This is a test u")
+ 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c,
+ 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, // ("sing a larger th")
+ 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, // ("an block-size ke")
+ 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20,
+ 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, // ("y and a larger t")
+ 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63,
+ 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, // ("han block-size d")
+ 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65,
+ 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, // ("ata. The key nee")
+ 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65,
+ 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, // ("ds to be hashed ")
+ 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62,
+ 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, // ("before being use")
+ 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, // ("d by the HMAC al")
+ 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e }, // ("gorithm.")
+ .psize = 152,
+ .digest = { 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d,
+ 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c,
+ 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+ 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5,
+ 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d,
+ 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e },
+ },
+};
+
+/*
+ * SHA512 HMAC test vectors from RFC4231
+ */
+
+#define HMAC_SHA512_TEST_VECTORS 4
+
+static struct hash_testvec hmac_sha512_tv_template[] = {
+ {
+ .key = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b }, // (20 bytes)
+ .ksize = 20,
+ .plaintext = { 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 }, // ("Hi There")
+ .psize = 8,
+ .digest = { 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d,
+ 0x4f, 0xf0, 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0,
+ 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78,
+ 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde,
+ 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02,
+ 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4,
+ 0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70,
+ 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54 },
+ }, {
+ .key = { 0x4a, 0x65, 0x66, 0x65 }, // ("Jefe")
+ .ksize = 4,
+ .plaintext = { 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20,
+ 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, // ("what do ya want ")
+ 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
+ 0x69, 0x6e, 0x67, 0x3f }, // ("for nothing?")
+ .psize = 28,
+ .digest = { 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2,
+ 0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3,
+ 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6,
+ 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54,
+ 0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99, 0x4a,
+ 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd,
+ 0xca, 0xea, 0xb1, 0xa3, 0x4d, 0x4a, 0x6b, 0x4b,
+ 0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37 },
+ .np = 4,
+ .tap = { 7, 7, 7, 7 }
+ }, {
+ .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa }, // (131 bytes)
+ .ksize = 131,
+ .plaintext = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69,
+ 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, // ("Test Using Large")
+ 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, // ("r Than Block-Siz")
+ 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20,
+ 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, // ("e Key - Hash Key")
+ 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 }, // (" First")
+ .psize = 54,
+ .digest = { 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb,
+ 0xb7, 0x14, 0x93, 0xc1, 0xdd, 0x7b, 0xe8, 0xb4,
+ 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1,
+ 0x12, 0x1b, 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52,
+ 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25, 0x98,
+ 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52,
+ 0x95, 0xe6, 0x4f, 0x73, 0xf6, 0x3f, 0x0a, 0xec,
+ 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98 },
+ }, {
+ .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa }, // (131 bytes)
+ .ksize = 131,
+ .plaintext = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+ 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, // ("This is a test u")
+ 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c,
+ 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, // ("sing a larger th")
+ 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, // ("an block-size ke")
+ 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20,
+ 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, // ("y and a larger t")
+ 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63,
+ 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, // ("han block-size d")
+ 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65,
+ 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, // ("ata. The key nee")
+ 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65,
+ 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, // ("ds to be hashed ")
+ 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62,
+ 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, // ("before being use")
+ 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, // ("d by the HMAC al")
+ 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e }, // ("gorithm.")
+ .psize = 152,
+ .digest = { 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba,
+ 0xa4, 0xdf, 0xa9, 0xf9, 0x6e, 0x5e, 0x3f, 0xfd,
+ 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86,
+ 0x5d, 0xf5, 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44,
+ 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82, 0xb1,
+ 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15,
+ 0x13, 0x46, 0x76, 0xfb, 0x6d, 0xe0, 0x44, 0x60,
+ 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58 },
+ },
+};
+
+/*
* DES test vectors.
*/
#define DES_ENC_TEST_VECTORS 10
@@ -3316,6 +3559,278 @@ static struct cipher_testvec xeta_dec_tv_template[] = {
}
};
+/*
+ * FCrypt test vectors
+ */
+#define FCRYPT_ENC_TEST_VECTORS ARRAY_SIZE(fcrypt_pcbc_enc_tv_template)
+#define FCRYPT_DEC_TEST_VECTORS ARRAY_SIZE(fcrypt_pcbc_dec_tv_template)
+
+static struct cipher_testvec fcrypt_pcbc_enc_tv_template[] = {
+ { /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */
+ .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .klen = 8,
+ .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .ilen = 8,
+ .result = { 0x0E, 0x09, 0x00, 0xC7, 0x3E, 0xF7, 0xED, 0x41 },
+ .rlen = 8,
+ }, {
+ .key = { 0x11, 0x44, 0x77, 0xAA, 0xDD, 0x00, 0x33, 0x66 },
+ .klen = 8,
+ .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 },
+ .ilen = 8,
+ .result = { 0xD8, 0xED, 0x78, 0x74, 0x77, 0xEC, 0x06, 0x80 },
+ .rlen = 8,
+ }, { /* From Arla */
+ .key = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+ .klen = 8,
+ .iv = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .input = "The quick brown fox jumps over the lazy dogs.\0\0",
+ .ilen = 48,
+ .result = { 0x00, 0xf0, 0xe, 0x11, 0x75, 0xe6, 0x23, 0x82,
+ 0xee, 0xac, 0x98, 0x62, 0x44, 0x51, 0xe4, 0x84,
+ 0xc3, 0x59, 0xd8, 0xaa, 0x64, 0x60, 0xae, 0xf7,
+ 0xd2, 0xd9, 0x13, 0x79, 0x72, 0xa3, 0x45, 0x03,
+ 0x23, 0xb5, 0x62, 0xd7, 0x0c, 0xf5, 0x27, 0xd1,
+ 0xf8, 0x91, 0x3c, 0xac, 0x44, 0x22, 0x92, 0xef },
+ .rlen = 48,
+ }, {
+ .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .klen = 8,
+ .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+ .input = "The quick brown fox jumps over the lazy dogs.\0\0",
+ .ilen = 48,
+ .result = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c,
+ 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d,
+ 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58,
+ 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0,
+ 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94,
+ 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f },
+ .rlen = 48,
+ }, { /* split-page version */
+ .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .klen = 8,
+ .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+ .input = "The quick brown fox jumps over the lazy dogs.\0\0",
+ .ilen = 48,
+ .result = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c,
+ 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d,
+ 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58,
+ 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0,
+ 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94,
+ 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f },
+ .rlen = 48,
+ .np = 2,
+ .tap = { 20, 28 },
+ }
+};
+
+static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = {
+ { /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */
+ .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .klen = 8,
+ .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0x0E, 0x09, 0x00, 0xC7, 0x3E, 0xF7, 0xED, 0x41 },
+ .ilen = 8,
+ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .rlen = 8,
+ }, {
+ .key = { 0x11, 0x44, 0x77, 0xAA, 0xDD, 0x00, 0x33, 0x66 },
+ .klen = 8,
+ .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .input = { 0xD8, 0xED, 0x78, 0x74, 0x77, 0xEC, 0x06, 0x80 },
+ .ilen = 8,
+ .result = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 },
+ .rlen = 8,
+ }, { /* From Arla */
+ .key = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+ .klen = 8,
+ .iv = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .input = { 0x00, 0xf0, 0xe, 0x11, 0x75, 0xe6, 0x23, 0x82,
+ 0xee, 0xac, 0x98, 0x62, 0x44, 0x51, 0xe4, 0x84,
+ 0xc3, 0x59, 0xd8, 0xaa, 0x64, 0x60, 0xae, 0xf7,
+ 0xd2, 0xd9, 0x13, 0x79, 0x72, 0xa3, 0x45, 0x03,
+ 0x23, 0xb5, 0x62, 0xd7, 0x0c, 0xf5, 0x27, 0xd1,
+ 0xf8, 0x91, 0x3c, 0xac, 0x44, 0x22, 0x92, 0xef },
+ .ilen = 48,
+ .result = "The quick brown fox jumps over the lazy dogs.\0\0",
+ .rlen = 48,
+ }, {
+ .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .klen = 8,
+ .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+ .input = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c,
+ 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d,
+ 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58,
+ 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0,
+ 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94,
+ 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f },
+ .ilen = 48,
+ .result = "The quick brown fox jumps over the lazy dogs.\0\0",
+ .rlen = 48,
+ }, { /* split-page version */
+ .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .klen = 8,
+ .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+ .input = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c,
+ 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d,
+ 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58,
+ 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0,
+ 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94,
+ 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f },
+ .ilen = 48,
+ .result = "The quick brown fox jumps over the lazy dogs.\0\0",
+ .rlen = 48,
+ .np = 2,
+ .tap = { 20, 28 },
+ }
+};
+
+/*
+ * CAMELLIA test vectors.
+ */
+#define CAMELLIA_ENC_TEST_VECTORS 3
+#define CAMELLIA_DEC_TEST_VECTORS 3
+#define CAMELLIA_CBC_ENC_TEST_VECTORS 2
+#define CAMELLIA_CBC_DEC_TEST_VECTORS 2
+
+static struct cipher_testvec camellia_enc_tv_template[] = {
+ {
+ .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .klen = 16,
+ .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .ilen = 16,
+ .result = { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73,
+ 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 },
+ .rlen = 16,
+ }, {
+ .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 },
+ .klen = 24,
+ .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .ilen = 16,
+ .result = { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8,
+ 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 },
+ .rlen = 16,
+ }, {
+ .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
+ .klen = 32,
+ .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .ilen = 16,
+ .result = { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c,
+ 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 },
+ .rlen = 16,
+ },
+};
+
+static struct cipher_testvec camellia_dec_tv_template[] = {
+ {
+ .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .klen = 16,
+ .input = { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73,
+ 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 },
+ .ilen = 16,
+ .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .rlen = 16,
+ }, {
+ .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 },
+ .klen = 24,
+ .input = { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8,
+ 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 },
+ .ilen = 16,
+ .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .rlen = 16,
+ }, {
+ .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
+ .klen = 32,
+ .input = { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c,
+ 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 },
+ .ilen = 16,
+ .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+ .rlen = 16,
+ },
+};
+
+static struct cipher_testvec camellia_cbc_enc_tv_template[] = {
+ {
+ .key = { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
+ 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
+ .klen = 16,
+ .iv = { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
+ 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
+ .input = { "Single block msg" },
+ .ilen = 16,
+ .result = { 0xea, 0x32, 0x12, 0x76, 0x3b, 0x50, 0x10, 0xe7,
+ 0x18, 0xf6, 0xfd, 0x5d, 0xf6, 0x8f, 0x13, 0x51 },
+ .rlen = 16,
+ }, {
+ .key = { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
+ 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
+ .klen = 16,
+ .iv = { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
+ 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
+ .input = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+ .ilen = 32,
+ .result = { 0xa5, 0xdf, 0x6e, 0x50, 0xda, 0x70, 0x6c, 0x01,
+ 0x4a, 0xab, 0xf3, 0xf2, 0xd6, 0xfc, 0x6c, 0xfd,
+ 0x19, 0xb4, 0x3e, 0x57, 0x1c, 0x02, 0x5e, 0xa0,
+ 0x15, 0x78, 0xe0, 0x5e, 0xf2, 0xcb, 0x87, 0x16 },
+ .rlen = 32,
+ },
+};
+
+static struct cipher_testvec camellia_cbc_dec_tv_template[] = {
+ {
+ .key = { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
+ 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
+ .klen = 16,
+ .iv = { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
+ 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
+ .input = { 0xea, 0x32, 0x12, 0x76, 0x3b, 0x50, 0x10, 0xe7,
+ 0x18, 0xf6, 0xfd, 0x5d, 0xf6, 0x8f, 0x13, 0x51 },
+ .ilen = 16,
+ .result = { "Single block msg" },
+ .rlen = 16,
+ }, {
+ .key = { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
+ 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
+ .klen = 16,
+ .iv = { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
+ 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
+ .input = { 0xa5, 0xdf, 0x6e, 0x50, 0xda, 0x70, 0x6c, 0x01,
+ 0x4a, 0xab, 0xf3, 0xf2, 0xd6, 0xfc, 0x6c, 0xfd,
+ 0x19, 0xb4, 0x3e, 0x57, 0x1c, 0x02, 0x5e, 0xa0,
+ 0x15, 0x78, 0xe0, 0x5e, 0xf2, 0xcb, 0x87, 0x16 },
+ .ilen = 32,
+ .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+ .rlen = 32,
+ },
+};
+
/*
* Compression stuff.
*/
@@ -3769,4 +4284,25 @@ static struct hash_speed generic_hash_speed_template[] = {
{ .blen = 0, .plen = 0, }
};
+static struct cipher_speed camellia_speed_template[] = {
+ { .klen = 16, .blen = 16, },
+ { .klen = 16, .blen = 64, },
+ { .klen = 16, .blen = 256, },
+ { .klen = 16, .blen = 1024, },
+ { .klen = 16, .blen = 8192, },
+ { .klen = 24, .blen = 16, },
+ { .klen = 24, .blen = 64, },
+ { .klen = 24, .blen = 256, },
+ { .klen = 24, .blen = 1024, },
+ { .klen = 24, .blen = 8192, },
+ { .klen = 32, .blen = 16, },
+ { .klen = 32, .blen = 64, },
+ { .klen = 32, .blen = 256, },
+ { .klen = 32, .blen = 1024, },
+ { .klen = 32, .blen = 8192, },
+
+ /* End marker */
+ { .klen = 0, .blen = 0, }
+};
+
#endif /* _CRYPTO_TCRYPT_H */
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
index 9347eb6bcf6..53e8ccbf0f5 100644
--- a/crypto/xcbc.c
+++ b/crypto/xcbc.c
@@ -21,6 +21,7 @@
#include <linux/crypto.h>
#include <linux/err.h>
+#include <linux/hardirq.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/rtnetlink.h>
@@ -47,7 +48,7 @@ static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101,
* +------------------------
*/
struct crypto_xcbc_ctx {
- struct crypto_tfm *child;
+ struct crypto_cipher *child;
u8 *odds;
u8 *prev;
u8 *key;
@@ -75,8 +76,7 @@ static int _crypto_xcbc_digest_setkey(struct crypto_hash *parent,
if ((err = crypto_cipher_setkey(ctx->child, ctx->key, ctx->keylen)))
return err;
- ctx->child->__crt_alg->cra_cipher.cia_encrypt(ctx->child, key1,
- ctx->consts);
+ crypto_cipher_encrypt_one(ctx->child, key1, ctx->consts);
return crypto_cipher_setkey(ctx->child, key1, bs);
}
@@ -86,7 +86,7 @@ static int crypto_xcbc_digest_setkey(struct crypto_hash *parent,
{
struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
- if (keylen != crypto_tfm_alg_blocksize(ctx->child))
+ if (keylen != crypto_cipher_blocksize(ctx->child))
return -EINVAL;
ctx->keylen = keylen;
@@ -108,13 +108,13 @@ static int crypto_xcbc_digest_init(struct hash_desc *pdesc)
return 0;
}
-static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
- struct scatterlist *sg,
- unsigned int nbytes)
+static int crypto_xcbc_digest_update2(struct hash_desc *pdesc,
+ struct scatterlist *sg,
+ unsigned int nbytes)
{
struct crypto_hash *parent = pdesc->tfm;
struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
- struct crypto_tfm *tfm = ctx->child;
+ struct crypto_cipher *tfm = ctx->child;
int bs = crypto_hash_blocksize(parent);
unsigned int i = 0;
@@ -142,7 +142,7 @@ static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
offset += len;
crypto_kunmap(p, 0);
- crypto_yield(tfm->crt_flags);
+ crypto_yield(pdesc->flags);
continue;
}
@@ -152,7 +152,7 @@ static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
p += bs - ctx->len;
ctx->xor(ctx->prev, ctx->odds, bs);
- tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, ctx->prev, ctx->prev);
+ crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev);
/* clearing the length */
ctx->len = 0;
@@ -160,7 +160,8 @@ static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
/* encrypting the rest of data */
while (len > bs) {
ctx->xor(ctx->prev, p, bs);
- tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, ctx->prev, ctx->prev);
+ crypto_cipher_encrypt_one(tfm, ctx->prev,
+ ctx->prev);
p += bs;
len -= bs;
}
@@ -171,7 +172,7 @@ static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
ctx->len = len;
}
crypto_kunmap(p, 0);
- crypto_yield(tfm->crt_flags);
+ crypto_yield(pdesc->flags);
slen -= min(slen, ((unsigned int)(PAGE_SIZE)) - offset);
offset = 0;
pg++;
@@ -183,11 +184,20 @@ static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
return 0;
}
+static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
+ struct scatterlist *sg,
+ unsigned int nbytes)
+{
+ if (WARN_ON_ONCE(in_irq()))
+ return -EDEADLK;
+ return crypto_xcbc_digest_update2(pdesc, sg, nbytes);
+}
+
static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out)
{
struct crypto_hash *parent = pdesc->tfm;
struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
- struct crypto_tfm *tfm = ctx->child;
+ struct crypto_cipher *tfm = ctx->child;
int bs = crypto_hash_blocksize(parent);
int err = 0;
@@ -197,13 +207,14 @@ static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out)
if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0)
return err;
- tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, key2, (const u8*)(ctx->consts+bs));
+ crypto_cipher_encrypt_one(tfm, key2,
+ (u8 *)(ctx->consts + bs));
ctx->xor(ctx->prev, ctx->odds, bs);
ctx->xor(ctx->prev, key2, bs);
_crypto_xcbc_digest_setkey(parent, ctx);
- tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, out, ctx->prev);
+ crypto_cipher_encrypt_one(tfm, out, ctx->prev);
} else {
u8 key3[bs];
unsigned int rlen;
@@ -218,14 +229,15 @@ static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out)
if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0)
return err;
- tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, key3, (const u8*)(ctx->consts+bs*2));
+ crypto_cipher_encrypt_one(tfm, key3,
+ (u8 *)(ctx->consts + bs * 2));
ctx->xor(ctx->prev, ctx->odds, bs);
ctx->xor(ctx->prev, key3, bs);
_crypto_xcbc_digest_setkey(parent, ctx);
- tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, out, ctx->prev);
+ crypto_cipher_encrypt_one(tfm, out, ctx->prev);
}
return 0;
@@ -234,21 +246,25 @@ static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out)
static int crypto_xcbc_digest(struct hash_desc *pdesc,
struct scatterlist *sg, unsigned int nbytes, u8 *out)
{
+ if (WARN_ON_ONCE(in_irq()))
+ return -EDEADLK;
+
crypto_xcbc_digest_init(pdesc);
- crypto_xcbc_digest_update(pdesc, sg, nbytes);
+ crypto_xcbc_digest_update2(pdesc, sg, nbytes);
return crypto_xcbc_digest_final(pdesc, out);
}
static int xcbc_init_tfm(struct crypto_tfm *tfm)
{
+ struct crypto_cipher *cipher;
struct crypto_instance *inst = (void *)tfm->__crt_alg;
struct crypto_spawn *spawn = crypto_instance_ctx(inst);
struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm));
int bs = crypto_hash_blocksize(__crypto_hash_cast(tfm));
- tfm = crypto_spawn_tfm(spawn);
- if (IS_ERR(tfm))
- return PTR_ERR(tfm);
+ cipher = crypto_spawn_cipher(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
switch(bs) {
case 16:
@@ -258,7 +274,7 @@ static int xcbc_init_tfm(struct crypto_tfm *tfm)
return -EINVAL;
}
- ctx->child = crypto_cipher_cast(tfm);
+ ctx->child = cipher;
ctx->odds = (u8*)(ctx+1);
ctx->prev = ctx->odds + bs;
ctx->key = ctx->prev + bs;
diff --git a/drivers/Kconfig b/drivers/Kconfig
index f3946341890..e7da9fa724e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -64,6 +64,8 @@ source "drivers/video/Kconfig"
source "sound/Kconfig"
+source "drivers/hid/Kconfig"
+
source "drivers/usb/Kconfig"
source "drivers/mmc/Kconfig"
@@ -78,4 +80,6 @@ source "drivers/rtc/Kconfig"
source "drivers/dma/Kconfig"
+source "drivers/kvm/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 67711770b1d..f28dcb4ec8b 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -30,7 +30,7 @@ obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ net/ media/
obj-$(CONFIG_NUBUS) += nubus/
obj-$(CONFIG_ATM) += atm/
-obj-$(CONFIG_PPC_PMAC) += macintosh/
+obj-y += macintosh/
obj-$(CONFIG_IDE) += ide/
obj-$(CONFIG_FC4) += fc4/
obj-$(CONFIG_SCSI) += scsi/
@@ -43,6 +43,7 @@ obj-$(CONFIG_SPI) += spi/
obj-$(CONFIG_PCCARD) += pcmcia/
obj-$(CONFIG_DIO) += dio/
obj-$(CONFIG_SBUS) += sbus/
+obj-$(CONFIG_KVM) += kvm/
obj-$(CONFIG_ZORRO) += zorro/
obj-$(CONFIG_MAC) += macintosh/
obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
@@ -77,4 +78,5 @@ obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
obj-$(CONFIG_GENERIC_TIME) += clocksource/
obj-$(CONFIG_DMA_ENGINE) += dma/
+obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
index 04854234120..674bf81c6e6 100644
--- a/drivers/acorn/block/fd1772.c
+++ b/drivers/acorn/block/fd1772.c
@@ -1549,12 +1549,12 @@ int fd1772_init(void)
#ifdef TRACKBUFFER
BufferDrive = BufferSide = BufferTrack = -1;
/* Atari uses 512 - I want to eventually cope with 1K sectors */
- DMABuffer = (char *)kmalloc((FD1772_MAX_SECTORS+1)*512,GFP_KERNEL);
+ DMABuffer = kmalloc((FD1772_MAX_SECTORS+1)*512,GFP_KERNEL);
TrackBuffer = DMABuffer + 512;
#else
/* Allocate memory for the DMAbuffer - on the Atari this takes it
out of some special memory... */
- DMABuffer = (char *) kmalloc(2048); /* Copes with pretty large sectors */
+ DMABuffer = kmalloc(2048); /* Copes with pretty large sectors */
#endif
err = -ENOMEM;
if (!DMAbuffer)
diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c
index bdb9c8b78ed..9e584a7af43 100644
--- a/drivers/acorn/char/i2c.c
+++ b/drivers/acorn/char/i2c.c
@@ -360,7 +360,7 @@ static int __init i2c_ioc_init(void)
if (ret >= 0){
ret = misc_register(&rtc_dev);
if(ret < 0)
- i2c_bit_del_bus(&ioc_ops);
+ i2c_del_adapter(&ioc_ops);
}
return ret;
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 0f9d4be7ed7..20eacc2c9e0 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -3,6 +3,7 @@
#
menu "ACPI (Advanced Configuration and Power Interface) Support"
+ depends on !X86_NUMAQ
depends on !X86_VISWS
depends on !IA64_HP_SIM
depends on IA64 || X86
@@ -11,7 +12,7 @@ config ACPI
bool "ACPI Support"
depends on IA64 || X86
depends on PCI
- select PM
+ depends on PM
default y
---help---
Advanced Configuration and Power Interface (ACPI) support for
@@ -77,6 +78,20 @@ config ACPI_SLEEP_PROC_SLEEP
Create /proc/acpi/sleep
Deprecated by /sys/power/state
+config ACPI_PROCFS
+ bool "Procfs interface (deprecated)"
+ depends on ACPI
+ default y
+ ---help---
+ Procfs interface for ACPI is made optional for back-compatible.
+ As the same functions are duplicated in sysfs interface
+ and this proc interface will be removed some time later,
+ it's marked as deprecated.
+ ( /proc/acpi/debug_layer && debug_level are deprecated by
+ /sys/module/acpi/parameters/debug_layer && debug_level.
+ /proc/acpi/info is deprecated by
+ /sys/module/acpi/parameters/acpica_version )
+
config ACPI_AC
tristate "AC Adapter"
depends on X86
@@ -97,6 +112,7 @@ config ACPI_BATTERY
config ACPI_BUTTON
tristate "Button"
+ depends on INPUT
default y
help
This driver handles events on the power, sleep and lid buttons.
@@ -106,7 +122,7 @@ config ACPI_BUTTON
config ACPI_VIDEO
tristate "Video"
- depends on X86
+ depends on X86 && BACKLIGHT_CLASS_DEVICE
help
This driver implement the ACPI Extensions For Display Adapters
for integrated graphics devices on motherboard, as specified in
@@ -138,6 +154,13 @@ config ACPI_DOCK
help
This driver adds support for ACPI controlled docking stations
+config ACPI_BAY
+ tristate "Removable Drive Bay (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ This driver adds support for ACPI controlled removable drive
+ bays such as the IBM ultrabay or the Dell Module Bay.
+
config ACPI_PROCESSOR
tristate "Processor"
default y
@@ -172,6 +195,7 @@ config ACPI_NUMA
config ACPI_ASUS
tristate "ASUS/Medion Laptop Extras"
depends on X86
+ select BACKLIGHT_CLASS_DEVICE
---help---
This driver provides support for extra features of ACPI-compatible
ASUS laptops. As some of Medion laptops are made by ASUS, it may also
@@ -184,22 +208,26 @@ config ACPI_ASUS
Note: display switching code is currently considered EXPERIMENTAL,
toying with these values may even lock your machine.
-
+
All settings are changed via /proc/acpi/asus directory entries. Owner
and group for these entries can be set with asus_uid and asus_gid
parameters.
-
+
More information and a userspace daemon for handling the extra buttons
at <http://sourceforge.net/projects/acpi4asus/>.
-
+
If you have an ACPI-compatible ASUS laptop, say Y or M here. This
driver is still under development, so if your laptop is unsupported or
something works not quite as expected, please use the mailing list
- available on the above page (acpi4asus-user@lists.sourceforge.net)
-
+ available on the above page (acpi4asus-user@lists.sourceforge.net).
+
+ NOTE: This driver is deprecated and will probably be removed soon,
+ use asus-laptop instead.
+
config ACPI_IBM
tristate "IBM ThinkPad Laptop Extras"
depends on X86
+ select BACKLIGHT_CLASS_DEVICE
---help---
This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
@@ -225,6 +253,7 @@ config ACPI_IBM_DOCK
config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras"
depends on X86
+ select BACKLIGHT_CLASS_DEVICE
---help---
This driver adds support for access to certain system settings
on "legacy free" Toshiba laptops. These laptops can be recognized by
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index bce7ca27b42..856c32bccac 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -37,13 +37,15 @@ endif
obj-y += sleep/
obj-y += bus.o glue.o
+obj-y += scan.o
obj-$(CONFIG_ACPI_AC) += ac.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o
obj-$(CONFIG_ACPI_EC) += ec.o
obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_DOCK) += dock.o
-obj-$(CONFIG_ACPI_VIDEO) += video.o
+obj-$(CONFIG_ACPI_BAY) += bay.o
+obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
obj-$(CONFIG_ACPI_POWER) += power.o
@@ -56,7 +58,6 @@ obj-$(CONFIG_ACPI_NUMA) += numa.o
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
-obj-y += scan.o motherboard.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
obj-y += cm_sbs.o
obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 11abc7bf777..6daeace796a 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -109,7 +109,7 @@ static struct proc_dir_entry *acpi_ac_dir;
static int acpi_ac_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_ac *ac = (struct acpi_ac *)seq->private;
+ struct acpi_ac *ac = seq->private;
if (!ac)
@@ -187,7 +187,7 @@ static int acpi_ac_remove_fs(struct acpi_device *device)
static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
{
- struct acpi_ac *ac = (struct acpi_ac *)data;
+ struct acpi_ac *ac = data;
struct acpi_device *device = NULL;
@@ -221,10 +221,9 @@ static int acpi_ac_add(struct acpi_device *device)
if (!device)
return -EINVAL;
- ac = kmalloc(sizeof(struct acpi_ac), GFP_KERNEL);
+ ac = kzalloc(sizeof(struct acpi_ac), GFP_KERNEL);
if (!ac)
return -ENOMEM;
- memset(ac, 0, sizeof(struct acpi_ac));
ac->device = device;
strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
@@ -269,7 +268,7 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- ac = (struct acpi_ac *)acpi_driver_data(device);
+ ac = acpi_driver_data(device);
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY, acpi_ac_notify);
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 6bcd9e8e7bc..cd946ed192d 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -395,10 +395,9 @@ static int acpi_memory_device_add(struct acpi_device *device)
if (!device)
return -EINVAL;
- mem_device = kmalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
+ mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
if (!mem_device)
return -ENOMEM;
- memset(mem_device, 0, sizeof(struct acpi_memory_device));
INIT_LIST_HEAD(&mem_device->res_list);
mem_device->device = device;
@@ -429,7 +428,7 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- mem_device = (struct acpi_memory_device *)acpi_driver_data(device);
+ mem_device = acpi_driver_data(device);
kfree(mem_device);
return 0;
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index c7ac9297a20..31ad70a6e22 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -26,7 +26,7 @@
* Pontus Fuchs - Helper functions, cleanup
* Johann Wiesner - Small compile fixes
* John Belmonte - ACPI code for Toshiba laptop was a good starting point.
- * Éric Burghard - LED display support for W1N
+ * �ic Burghard - LED display support for W1N
*
*/
@@ -35,6 +35,7 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
+#include <linux/backlight.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
@@ -402,6 +403,8 @@ static struct model_data model_conf[END_MODEL] = {
/* procdir we use */
static struct proc_dir_entry *asus_proc_dir;
+static struct backlight_device *asus_backlight_device;
+
/*
* This header is made available to allow proper configuration given model,
* revision number , ... this info cannot go in struct asus_hotk because it is
@@ -779,7 +782,7 @@ proc_write_lcd(struct file *file, const char __user * buffer,
return rv;
}
-static int read_brightness(void)
+static int read_brightness(struct backlight_device *bd)
{
int value;
@@ -801,9 +804,10 @@ static int read_brightness(void)
/*
* Change the brightness level
*/
-static void set_brightness(int value)
+static int set_brightness(int value)
{
acpi_status status = 0;
+ int ret = 0;
/* SPLV laptop */
if (hotk->methods->brightness_set) {
@@ -811,11 +815,12 @@ static void set_brightness(int value)
value, NULL))
printk(KERN_WARNING
"Asus ACPI: Error changing brightness\n");
- return;
+ ret = -EIO;
+ goto out;
}
/* No SPLV method if we are here, act as appropriate */
- value -= read_brightness();
+ value -= read_brightness(NULL);
while (value != 0) {
status = acpi_evaluate_object(NULL, (value > 0) ?
hotk->methods->brightness_up :
@@ -825,15 +830,22 @@ static void set_brightness(int value)
if (ACPI_FAILURE(status))
printk(KERN_WARNING
"Asus ACPI: Error changing brightness\n");
+ ret = -EIO;
}
- return;
+out:
+ return ret;
+}
+
+static int set_brightness_status(struct backlight_device *bd)
+{
+ return set_brightness(bd->props->brightness);
}
static int
proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
- return sprintf(page, "%d\n", read_brightness());
+ return sprintf(page, "%d\n", read_brightness(NULL));
}
static int
@@ -1116,7 +1128,6 @@ static int asus_model_match(char *model)
static int asus_hotk_get_info(void)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *model = NULL;
int bsts_result;
char *string = NULL;
@@ -1130,11 +1141,9 @@ static int asus_hotk_get_info(void)
* HID), this bit will be moved. A global variable asus_info contains
* the DSDT header.
*/
- status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
+ status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
if (ACPI_FAILURE(status))
printk(KERN_WARNING " Couldn't get the DSDT table header\n");
- else
- asus_info = (struct acpi_table_header *)dsdt.pointer;
/* We have to write 0 on init this far for all ASUS models */
if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
@@ -1156,7 +1165,7 @@ static int asus_hotk_get_info(void)
* asus_model_match() and try something completely different.
*/
if (buffer.pointer) {
- model = (union acpi_object *)buffer.pointer;
+ model = buffer.pointer;
switch (model->type) {
case ACPI_TYPE_STRING:
string = model->string.pointer;
@@ -1252,11 +1261,9 @@ static int asus_hotk_add(struct acpi_device *device)
printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",
ASUS_ACPI_VERSION);
- hotk =
- (struct asus_hotk *)kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+ hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
if (!hotk)
return -ENOMEM;
- memset(hotk, 0, sizeof(struct asus_hotk));
hotk->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
@@ -1333,6 +1340,24 @@ static int asus_hotk_remove(struct acpi_device *device, int type)
return 0;
}
+static struct backlight_properties asus_backlight_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = read_brightness,
+ .update_status = set_brightness_status,
+ .max_brightness = 15,
+};
+
+static void __exit asus_acpi_exit(void)
+{
+ if (asus_backlight_device)
+ backlight_device_unregister(asus_backlight_device);
+
+ acpi_bus_unregister_driver(&asus_hotk_driver);
+ remove_proc_entry(PROC_ASUS, acpi_root_dir);
+
+ return;
+}
+
static int __init asus_acpi_init(void)
{
int result;
@@ -1370,17 +1395,15 @@ static int __init asus_acpi_init(void)
return result;
}
- return 0;
-}
-
-static void __exit asus_acpi_exit(void)
-{
- acpi_bus_unregister_driver(&asus_hotk_driver);
- remove_proc_entry(PROC_ASUS, acpi_root_dir);
-
- kfree(asus_info);
+ asus_backlight_device = backlight_device_register("asus",NULL,NULL,
+ &asus_backlight_data);
+ if (IS_ERR(asus_backlight_device)) {
+ printk(KERN_ERR "Could not register asus backlight device\n");
+ asus_backlight_device = NULL;
+ asus_acpi_exit();
+ }
- return;
+ return 0;
}
module_init(asus_acpi_init);
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 026e40755cd..2f4521a48fe 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -64,7 +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 int acpi_battery_resume(struct acpi_device *device);
static struct acpi_driver acpi_battery_driver = {
.name = ACPI_BATTERY_DRIVER_NAME,
@@ -149,7 +149,7 @@ acpi_battery_get_info(struct acpi_battery *battery,
return -ENODEV;
}
- package = (union acpi_object *)buffer.pointer;
+ package = buffer.pointer;
/* Extract Package Data */
@@ -160,12 +160,11 @@ acpi_battery_get_info(struct acpi_battery *battery,
goto end;
}
- data.pointer = kmalloc(data.length, GFP_KERNEL);
+ data.pointer = kzalloc(data.length, GFP_KERNEL);
if (!data.pointer) {
result = -ENOMEM;
goto end;
}
- memset(data.pointer, 0, data.length);
status = acpi_extract_package(package, &format, &data);
if (ACPI_FAILURE(status)) {
@@ -179,7 +178,7 @@ acpi_battery_get_info(struct acpi_battery *battery,
kfree(buffer.pointer);
if (!result)
- (*bif) = (struct acpi_battery_info *)data.pointer;
+ (*bif) = data.pointer;
return result;
}
@@ -209,7 +208,7 @@ acpi_battery_get_status(struct acpi_battery *battery,
return -ENODEV;
}
- package = (union acpi_object *)buffer.pointer;
+ package = buffer.pointer;
/* Extract Package Data */
@@ -220,12 +219,11 @@ acpi_battery_get_status(struct acpi_battery *battery,
goto end;
}
- data.pointer = kmalloc(data.length, GFP_KERNEL);
+ data.pointer = kzalloc(data.length, GFP_KERNEL);
if (!data.pointer) {
result = -ENOMEM;
goto end;
}
- memset(data.pointer, 0, data.length);
status = acpi_extract_package(package, &format, &data);
if (ACPI_FAILURE(status)) {
@@ -239,7 +237,7 @@ acpi_battery_get_status(struct acpi_battery *battery,
kfree(buffer.pointer);
if (!result)
- (*bst) = (struct acpi_battery_status *)data.pointer;
+ (*bst) = data.pointer;
return result;
}
@@ -334,7 +332,7 @@ static struct proc_dir_entry *acpi_battery_dir;
static int acpi_battery_read_info(struct seq_file *seq, void *offset)
{
int result = 0;
- struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ struct acpi_battery *battery = seq->private;
struct acpi_battery_info *bif = NULL;
char *units = "?";
@@ -418,7 +416,7 @@ static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
static int acpi_battery_read_state(struct seq_file *seq, void *offset)
{
int result = 0;
- struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ struct acpi_battery *battery = seq->private;
struct acpi_battery_status *bst = NULL;
char *units = "?";
@@ -494,7 +492,7 @@ static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
{
- struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ struct acpi_battery *battery = seq->private;
char *units = "?";
@@ -531,8 +529,8 @@ acpi_battery_write_alarm(struct file *file,
{
int result = 0;
char alarm_string[12] = { '\0' };
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_battery *battery = (struct acpi_battery *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_battery *battery = m->private;
if (!battery || (count > sizeof(alarm_string) - 1))
@@ -658,7 +656,7 @@ static int acpi_battery_remove_fs(struct acpi_device *device)
static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
{
- struct acpi_battery *battery = (struct acpi_battery *)data;
+ struct acpi_battery *battery = data;
struct acpi_device *device = NULL;
@@ -694,10 +692,9 @@ static int acpi_battery_add(struct acpi_device *device)
if (!device)
return -EINVAL;
- battery = kmalloc(sizeof(struct acpi_battery), GFP_KERNEL);
+ battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
if (!battery)
return -ENOMEM;
- memset(battery, 0, sizeof(struct acpi_battery));
battery->device = device;
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
@@ -742,7 +739,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- battery = (struct acpi_battery *)acpi_driver_data(device);
+ battery = acpi_driver_data(device);
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY,
@@ -756,7 +753,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
}
/* this is needed to learn about changes made in suspended state */
-static int acpi_battery_resume(struct acpi_device *device, int state)
+static int acpi_battery_resume(struct acpi_device *device)
{
struct acpi_battery *battery;
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
new file mode 100644
index 00000000000..91082ce6f5d
--- /dev/null
+++ b/drivers/acpi/bay.c
@@ -0,0 +1,490 @@
+/*
+ * bay.c - ACPI removable drive bay driver
+ *
+ * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@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; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/notifier.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+#include <linux/platform_device.h>
+
+#define ACPI_BAY_DRIVER_NAME "ACPI Removable Drive Bay Driver"
+
+ACPI_MODULE_NAME("bay")
+MODULE_AUTHOR("Kristen Carlson Accardi");
+MODULE_DESCRIPTION(ACPI_BAY_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+#define ACPI_BAY_CLASS "bay"
+#define ACPI_BAY_COMPONENT 0x10000000
+#define _COMPONENT ACPI_BAY_COMPONENT
+#define bay_dprintk(h,s) {\
+ char prefix[80] = {'\0'};\
+ struct acpi_buffer buffer = {sizeof(prefix), prefix};\
+ acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
+ printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
+static void bay_notify(acpi_handle handle, u32 event, void *data);
+static int acpi_bay_add(struct acpi_device *device);
+static int acpi_bay_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_bay_driver = {
+ .name = ACPI_BAY_DRIVER_NAME,
+ .class = ACPI_BAY_CLASS,
+ .ids = ACPI_BAY_HID,
+ .ops = {
+ .add = acpi_bay_add,
+ .remove = acpi_bay_remove,
+ },
+};
+
+struct bay {
+ acpi_handle handle;
+ char *name;
+ struct list_head list;
+ struct platform_device *pdev;
+};
+
+static LIST_HEAD(drive_bays);
+
+
+/*****************************************************************************
+ * Drive Bay functions *
+ *****************************************************************************/
+/**
+ * is_ejectable - see if a device is ejectable
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object has a _EJ0 method, then it is ejectable
+ */
+static int is_ejectable(acpi_handle handle)
+{
+ acpi_status status;
+ acpi_handle tmp;
+
+ status = acpi_get_handle(handle, "_EJ0", &tmp);
+ if (ACPI_FAILURE(status))
+ return 0;
+ return 1;
+}
+
+/**
+ * bay_present - see if the bay device is present
+ * @bay: the drive bay
+ *
+ * execute the _STA method.
+ */
+static int bay_present(struct bay *bay)
+{
+ unsigned long sta;
+ acpi_status status;
+
+ if (bay) {
+ status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta);
+ if (ACPI_SUCCESS(status) && sta)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * eject_device - respond to an eject request
+ * @handle - the device to eject
+ *
+ * Call this devices _EJ0 method.
+ */
+static void eject_device(acpi_handle handle)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+
+ bay_dprintk(handle, "Ejecting device");
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
+ &arg_list, NULL)))
+ pr_debug("Failed to evaluate _EJ0!\n");
+}
+
+/*
+ * show_present - read method for "present" file in sysfs
+ */
+static ssize_t show_present(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bay *bay = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
+
+}
+DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
+
+/*
+ * write_eject - write method for "eject" file in sysfs
+ */
+static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bay *bay = dev_get_drvdata(dev);
+
+ if (!count)
+ return -EINVAL;
+
+ eject_device(bay->handle);
+ return count;
+}
+DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
+
+/**
+ * is_ata - see if a device is an ata device
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object has one of 4 ATA ACPI methods defined,
+ * then it is an ATA device
+ */
+static int is_ata(acpi_handle handle)
+{
+ acpi_handle tmp;
+
+ if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * parent_is_ata(acpi_handle handle)
+ *
+ */
+static int parent_is_ata(acpi_handle handle)
+{
+ acpi_handle phandle;
+
+ if (acpi_get_parent(handle, &phandle))
+ return 0;
+
+ return is_ata(phandle);
+}
+
+/**
+ * is_ejectable_bay - see if a device is an ejectable drive bay
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object is ejectable and has one of the ACPI ATA
+ * methods defined, then we can safely call it an ejectable
+ * drive bay
+ */
+static int is_ejectable_bay(acpi_handle handle)
+{
+ if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle))
+ return 1;
+ return 0;
+}
+
+/**
+ * eject_removable_drive - try to eject this drive
+ * @dev : the device structure of the drive
+ *
+ * If a device is a removable drive that requires an _EJ0 method
+ * to be executed in order to safely remove from the system, do
+ * it. ATM - always returns success
+ */
+int eject_removable_drive(struct device *dev)
+{
+ acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
+
+ if (handle) {
+ bay_dprintk(handle, "Got device handle");
+ if (is_ejectable_bay(handle))
+ eject_device(handle);
+ } else {
+ printk("No acpi handle for device\n");
+ }
+
+ /* should I return an error code? */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(eject_removable_drive);
+
+static int acpi_bay_add(struct acpi_device *device)
+{
+ bay_dprintk(device->handle, "adding bay device");
+ strcpy(acpi_device_name(device), "Dockable Bay");
+ strcpy(acpi_device_class(device), "bay");
+ return 0;
+}
+
+static int acpi_bay_add_fs(struct bay *bay)
+{
+ int ret;
+ struct device *dev = &bay->pdev->dev;
+
+ ret = device_create_file(dev, &dev_attr_present);
+ if (ret)
+ goto add_fs_err;
+ ret = device_create_file(dev, &dev_attr_eject);
+ if (ret) {
+ device_remove_file(dev, &dev_attr_present);
+ goto add_fs_err;
+ }
+ return 0;
+
+ add_fs_err:
+ bay_dprintk(bay->handle, "Error adding sysfs files\n");
+ return ret;
+}
+
+static void acpi_bay_remove_fs(struct bay *bay)
+{
+ struct device *dev = &bay->pdev->dev;
+
+ /* cleanup sysfs */
+ device_remove_file(dev, &dev_attr_present);
+ device_remove_file(dev, &dev_attr_eject);
+}
+
+static int bay_is_dock_device(acpi_handle handle)
+{
+ acpi_handle parent;
+
+ acpi_get_parent(handle, &parent);
+
+ /* if the device or it's parent is dependent on the
+ * dock, then we are a dock device
+ */
+ return (is_dock_device(handle) || is_dock_device(parent));
+}
+
+static int bay_add(acpi_handle handle, int id)
+{
+ acpi_status status;
+ struct bay *new_bay;
+ struct platform_device *pdev;
+ struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer);
+
+ bay_dprintk(handle, "Adding notify handler");
+
+ /*
+ * Initialize bay device structure
+ */
+ new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC);
+ INIT_LIST_HEAD(&new_bay->list);
+ new_bay->handle = handle;
+ new_bay->name = (char *)nbuffer.pointer;
+
+ /* initialize platform device stuff */
+ pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0);
+ if (pdev == NULL) {
+ printk(KERN_ERR PREFIX "Error registering bay device\n");
+ goto bay_add_err;
+ }
+ new_bay->pdev = pdev;
+ platform_set_drvdata(pdev, new_bay);
+
+ if (acpi_bay_add_fs(new_bay)) {
+ platform_device_unregister(new_bay->pdev);
+ goto bay_add_err;
+ }
+
+ /* register for events on this device */
+ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ bay_notify, new_bay);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Error installing bay notify handler\n");
+ }
+
+ /* if we are on a dock station, we should register for dock
+ * notifications.
+ */
+ if (bay_is_dock_device(handle)) {
+ bay_dprintk(handle, "Is dependent on dock\n");
+ register_hotplug_dock_device(handle, bay_notify, new_bay);
+ }
+ list_add(&new_bay->list, &drive_bays);
+ printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name);
+ return 0;
+
+bay_add_err:
+ kfree(new_bay->name);
+ kfree(new_bay);
+ return -ENODEV;
+}
+
+static int acpi_bay_remove(struct acpi_device *device, int type)
+{
+ /*** FIXME: do something here */
+ return 0;
+}
+
+/**
+ * bay_create_acpi_device - add new devices to acpi
+ * @handle - handle of the device to add
+ *
+ * This function will create a new acpi_device for the given
+ * handle if one does not exist already. This should cause
+ * acpi to scan for drivers for the given devices, and call
+ * matching driver's add routine.
+ *
+ * Returns a pointer to the acpi_device corresponding to the handle.
+ */
+static struct acpi_device * bay_create_acpi_device(acpi_handle handle)
+{
+ struct acpi_device *device = NULL;
+ struct acpi_device *parent_device;
+ acpi_handle parent;
+ int ret;
+
+ bay_dprintk(handle, "Trying to get device");
+ if (acpi_bus_get_device(handle, &device)) {
+ /*
+ * no device created for this object,
+ * so we should create one.
+ */
+ bay_dprintk(handle, "No device for handle");
+ acpi_get_parent(handle, &parent);
+ if (acpi_bus_get_device(parent, &parent_device))
+ parent_device = NULL;
+
+ ret = acpi_bus_add(&device, parent_device, handle,
+ ACPI_BUS_TYPE_DEVICE);
+ if (ret) {
+ pr_debug("error adding bus, %x\n",
+ -ret);
+ return NULL;
+ }
+ }
+ return device;
+}
+
+/**
+ * bay_notify - act upon an acpi bay notification
+ * @handle: the bay handle
+ * @event: the acpi event
+ * @data: our driver data struct
+ *
+ */
+static void bay_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct acpi_device *dev;
+
+ bay_dprintk(handle, "Bay event");
+
+ switch(event) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ printk("Bus Check\n");
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ printk("Device Check\n");
+ dev = bay_create_acpi_device(handle);
+ if (dev)
+ acpi_bus_generate_event(dev, event, 0);
+ else
+ printk("No device for generating event\n");
+ /* wouldn't it be a good idea to just rescan SATA
+ * right here?
+ */
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ printk("Eject request\n");
+ dev = bay_create_acpi_device(handle);
+ if (dev)
+ acpi_bus_generate_event(dev, event, 0);
+ else
+ printk("No device for generating eventn");
+
+ /* wouldn't it be a good idea to just call the
+ * eject_device here if we were a SATA device?
+ */
+ break;
+ default:
+ printk("unknown event %d\n", event);
+ }
+}
+
+static acpi_status
+find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int *count = (int *)context;
+
+ /*
+ * there could be more than one ejectable bay.
+ * so, just return AE_OK always so that every object
+ * will be checked.
+ */
+ if (is_ejectable_bay(handle)) {
+ bay_dprintk(handle, "found ejectable bay");
+ if (!bay_add(handle, *count))
+ (*count)++;
+ }
+ return AE_OK;
+}
+
+static int __init bay_init(void)
+{
+ int bays = 0;
+
+ INIT_LIST_HEAD(&drive_bays);
+
+ /* look for dockable drive bays */
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, find_bay, &bays, NULL);
+
+ if (bays)
+ if ((acpi_bus_register_driver(&acpi_bay_driver) < 0))
+ printk(KERN_ERR "Unable to register bay driver\n");
+
+ if (!bays)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void __exit bay_exit(void)
+{
+ struct bay *bay, *tmp;
+
+ list_for_each_entry_safe(bay, tmp, &drive_bays, list) {
+ if (is_dock_device(bay->handle))
+ unregister_hotplug_dock_device(bay->handle);
+ acpi_bay_remove_fs(bay);
+ acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY,
+ bay_notify);
+ platform_device_unregister(bay->pdev);
+ kfree(bay->name);
+ kfree(bay);
+ }
+
+ acpi_bus_unregister_driver(&acpi_bay_driver);
+}
+
+postcore_initcall(bay_init);
+module_exit(bay_exit);
+
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index f9c972b26f4..f289fd41e77 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -44,7 +44,7 @@ struct acpi_blacklist_item {
char oem_id[7];
char oem_table_id[9];
u32 oem_revision;
- acpi_table_type table;
+ char *table;
enum acpi_blacklist_predicates oem_revision_predicate;
char *reason;
u32 is_critical_error;
@@ -56,18 +56,18 @@ struct acpi_blacklist_item {
*/
static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
/* Compaq Presario 1700 */
- {"PTLTD ", " DSDT ", 0x06040000, ACPI_DSDT, less_than_or_equal,
+ {"PTLTD ", " DSDT ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal,
"Multiple problems", 1},
/* Sony FX120, FX140, FX150? */
- {"SONY ", "U0 ", 0x20010313, ACPI_DSDT, less_than_or_equal,
+ {"SONY ", "U0 ", 0x20010313, ACPI_SIG_DSDT, less_than_or_equal,
"ACPI driver problem", 1},
/* Compaq Presario 800, Insyde BIOS */
- {"INT440", "SYSFexxx", 0x00001001, ACPI_DSDT, less_than_or_equal,
+ {"INT440", "SYSFexxx", 0x00001001, ACPI_SIG_DSDT, less_than_or_equal,
"Does not use _REG to protect EC OpRegions", 1},
/* IBM 600E - _ADR should return 7, but it returns 1 */
- {"IBM ", "TP600E ", 0x00000105, ACPI_DSDT, less_than_or_equal,
+ {"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
"Incorrect _ADR", 1},
- {"ASUS\0\0", "P2B-S ", 0, ACPI_DSDT, all_versions,
+ {"ASUS\0\0", "P2B-S ", 0, ACPI_SIG_DSDT, all_versions,
"Bogus PCI routing", 1},
{""}
@@ -79,7 +79,7 @@ static int __init blacklist_by_year(void)
{
int year = dmi_get_year(DMI_BIOS_DATE);
/* Doesn't exist? Likely an old system */
- if (year == -1)
+ if (year == -1)
return 1;
/* 0? Likely a buggy new BIOS */
if (year == 0)
@@ -103,22 +103,21 @@ int __init acpi_blacklisted(void)
{
int i = 0;
int blacklisted = 0;
- struct acpi_table_header *table_header;
+ struct acpi_table_header table_header;
while (acpi_blacklist[i].oem_id[0] != '\0') {
- if (acpi_get_table_header_early
- (acpi_blacklist[i].table, &table_header)) {
+ if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) {
i++;
continue;
}
- if (strncmp(acpi_blacklist[i].oem_id, table_header->oem_id, 6)) {
+ if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) {
i++;
continue;
}
if (strncmp
- (acpi_blacklist[i].oem_table_id, table_header->oem_table_id,
+ (acpi_blacklist[i].oem_table_id, table_header.oem_table_id,
8)) {
i++;
continue;
@@ -127,14 +126,14 @@ int __init acpi_blacklisted(void)
if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
|| (acpi_blacklist[i].oem_revision_predicate ==
less_than_or_equal
- && table_header->oem_revision <=
+ && table_header.oem_revision <=
acpi_blacklist[i].oem_revision)
|| (acpi_blacklist[i].oem_revision_predicate ==
greater_than_or_equal
- && table_header->oem_revision >=
+ && table_header.oem_revision >=
acpi_blacklist[i].oem_revision)
|| (acpi_blacklist[i].oem_revision_predicate == equal
- && table_header->oem_revision ==
+ && table_header.oem_revision ==
acpi_blacklist[i].oem_revision)) {
printk(KERN_ERR PREFIX
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 279c4bac92e..c26468da429 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -44,9 +44,6 @@ ACPI_MODULE_NAME("acpi_bus")
extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
#endif
-struct fadt_descriptor acpi_fadt;
-EXPORT_SYMBOL(acpi_fadt);
-
struct acpi_device *acpi_root;
struct proc_dir_entry *acpi_root_dir;
EXPORT_SYMBOL(acpi_root_dir);
@@ -195,7 +192,7 @@ int acpi_bus_set_power(acpi_handle handle, int state)
if (!device->flags.power_manageable) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
- device->kobj.name));
+ device->dev.kobj.name));
return -ENODEV;
}
/*
@@ -561,6 +558,9 @@ static int __init acpi_bus_init_irq(void)
case ACPI_IRQ_MODEL_IOSAPIC:
message = "IOSAPIC";
break;
+ case ACPI_IRQ_MODEL_PLATFORM:
+ message = "platform specific model";
+ break;
default:
printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
return -ENODEV;
@@ -579,11 +579,12 @@ static int __init acpi_bus_init_irq(void)
return 0;
}
+acpi_native_uint acpi_gbl_permanent_mmap;
+
+
void __init acpi_early_init(void)
{
acpi_status status = AE_OK;
- struct acpi_buffer buffer = { sizeof(acpi_fadt), &acpi_fadt };
-
if (acpi_disabled)
return;
@@ -594,6 +595,15 @@ void __init acpi_early_init(void)
if (!acpi_strict)
acpi_gbl_enable_interpreter_slack = TRUE;
+ acpi_gbl_permanent_mmap = 1;
+
+ status = acpi_reallocate_root_table();
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX
+ "Unable to reallocate ACPI tables\n");
+ goto error0;
+ }
+
status = acpi_initialize_subsystem();
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX
@@ -608,32 +618,25 @@ void __init acpi_early_init(void)
goto error0;
}
- /*
- * Get a separate copy of the FADT for use by other drivers.
- */
- status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &buffer);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Unable to get the FADT\n");
- goto error0;
- }
#ifdef CONFIG_X86
if (!acpi_ioapic) {
- extern acpi_interrupt_flags acpi_sci_flags;
+ extern u8 acpi_sci_flags;
/* compatible (0) means level (3) */
- if (acpi_sci_flags.trigger == 0)
- acpi_sci_flags.trigger = 3;
-
+ if (!(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)) {
+ acpi_sci_flags &= ~ACPI_MADT_TRIGGER_MASK;
+ acpi_sci_flags |= ACPI_MADT_TRIGGER_LEVEL;
+ }
/* Set PIC-mode SCI trigger type */
- acpi_pic_sci_set_trigger(acpi_fadt.sci_int,
- acpi_sci_flags.trigger);
+ acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt,
+ (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
} else {
extern int acpi_sci_override_gsi;
/*
- * now that acpi_fadt is initialized,
+ * now that acpi_gbl_FADT is initialized,
* update it with result from INT_SRC_OVR parsing
*/
- acpi_fadt.sci_int = acpi_sci_override_gsi;
+ acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
}
#endif
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 5ef885e82c7..c726612fafb 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -29,6 +29,7 @@
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/input.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -62,7 +63,7 @@
#define _COMPONENT ACPI_BUTTON_COMPONENT
ACPI_MODULE_NAME("acpi_button")
- MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME);
MODULE_LICENSE("GPL");
@@ -74,16 +75,18 @@ static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
static struct acpi_driver acpi_button_driver = {
.name = ACPI_BUTTON_DRIVER_NAME,
.class = ACPI_BUTTON_CLASS,
- .ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
+ .ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E",
.ops = {
.add = acpi_button_add,
.remove = acpi_button_remove,
- },
+ },
};
struct acpi_button {
struct acpi_device *device; /* Fixed button kludge */
- u8 type;
+ unsigned int type;
+ struct input_dev *input;
+ char phys[32]; /* for input device */
unsigned long pushed;
};
@@ -109,8 +112,7 @@ static struct proc_dir_entry *acpi_button_dir;
static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_button *button = (struct acpi_button *)seq->private;
-
+ struct acpi_button *button = seq->private;
if (!button || !button->device)
return 0;
@@ -128,22 +130,17 @@ static int acpi_button_info_open_fs(struct inode *inode, struct file *file)
static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_button *button = (struct acpi_button *)seq->private;
+ struct acpi_button *button = seq->private;
acpi_status status;
unsigned long state;
-
if (!button || !button->device)
return 0;
status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, &state);
- if (ACPI_FAILURE(status)) {
- seq_printf(seq, "state: unsupported\n");
- } else {
- seq_printf(seq, "state: %s\n",
- (state ? "open" : "closed"));
- }
-
+ seq_printf(seq, "state: %s\n",
+ ACPI_FAILURE(status) ? "unsupported" :
+ (state ? "open" : "closed"));
return 0;
}
@@ -159,8 +156,7 @@ static struct proc_dir_entry *acpi_lid_dir;
static int acpi_button_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
- struct acpi_button *button = NULL;
-
+ struct acpi_button *button;
if (!device || !acpi_driver_data(device))
return -EINVAL;
@@ -228,10 +224,8 @@ static int acpi_button_add_fs(struct acpi_device *device)
static int acpi_button_remove_fs(struct acpi_device *device)
{
- struct acpi_button *button = NULL;
-
+ struct acpi_button *button = acpi_driver_data(device);
- button = acpi_driver_data(device);
if (acpi_device_dir(device)) {
if (button->type == ACPI_BUTTON_TYPE_LID)
remove_proc_entry(ACPI_BUTTON_FILE_STATE,
@@ -253,14 +247,34 @@ static int acpi_button_remove_fs(struct acpi_device *device)
static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
{
- struct acpi_button *button = (struct acpi_button *)data;
-
+ struct acpi_button *button = data;
+ struct input_dev *input;
if (!button || !button->device)
return;
switch (event) {
case ACPI_BUTTON_NOTIFY_STATUS:
+ input = button->input;
+
+ if (button->type == ACPI_BUTTON_TYPE_LID) {
+ struct acpi_handle *handle = button->device->handle;
+ unsigned long state;
+
+ if (!ACPI_FAILURE(acpi_evaluate_integer(handle, "_LID",
+ NULL, &state)))
+ input_report_switch(input, SW_LID, !state);
+
+ } else {
+ int keycode = test_bit(KEY_SLEEP, input->keybit) ?
+ KEY_SLEEP : KEY_POWER;
+
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ input_report_key(input, keycode, 0);
+ }
+ input_sync(input);
+
acpi_bus_generate_event(button->device, event,
++button->pushed);
break;
@@ -275,8 +289,7 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
static acpi_status acpi_button_notify_fixed(void *data)
{
- struct acpi_button *button = (struct acpi_button *)data;
-
+ struct acpi_button *button = data;
if (!button)
return AE_BAD_PARAMETER;
@@ -286,24 +299,75 @@ static acpi_status acpi_button_notify_fixed(void *data)
return AE_OK;
}
-static int acpi_button_add(struct acpi_device *device)
+static int acpi_button_install_notify_handlers(struct acpi_button *button)
{
- int result = 0;
- acpi_status status = AE_OK;
- struct acpi_button *button = NULL;
+ acpi_status status;
+ switch (button->type) {
+ case ACPI_BUTTON_TYPE_POWERF:
+ status =
+ acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+ acpi_button_notify_fixed,
+ button);
+ break;
+ case ACPI_BUTTON_TYPE_SLEEPF:
+ status =
+ acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+ acpi_button_notify_fixed,
+ button);
+ break;
+ default:
+ status = acpi_install_notify_handler(button->device->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_button_notify,
+ button);
+ break;
+ }
+
+ return ACPI_FAILURE(status) ? -ENODEV : 0;
+}
+
+static void acpi_button_remove_notify_handlers(struct acpi_button *button)
+{
+ switch (button->type) {
+ case ACPI_BUTTON_TYPE_POWERF:
+ acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+ acpi_button_notify_fixed);
+ break;
+ case ACPI_BUTTON_TYPE_SLEEPF:
+ acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+ acpi_button_notify_fixed);
+ break;
+ default:
+ acpi_remove_notify_handler(button->device->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_button_notify);
+ break;
+ }
+}
+
+static int acpi_button_add(struct acpi_device *device)
+{
+ int error;
+ struct acpi_button *button;
+ struct input_dev *input;
if (!device)
return -EINVAL;
- button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL);
+ button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
if (!button)
return -ENOMEM;
- memset(button, 0, sizeof(struct acpi_button));
button->device = device;
acpi_driver_data(device) = button;
+ button->input = input = input_allocate_device();
+ if (!input) {
+ error = -ENOMEM;
+ goto err_free_button;
+ }
+
/*
* Determine the button type (via hid), as fixed-feature buttons
* need to be handled a bit differently than generic-space.
@@ -338,39 +402,48 @@ static int acpi_button_add(struct acpi_device *device)
} else {
printk(KERN_ERR PREFIX "Unsupported hid [%s]\n",
acpi_device_hid(device));
- result = -ENODEV;
- goto end;
+ error = -ENODEV;
+ goto err_free_input;
}
- result = acpi_button_add_fs(device);
- if (result)
- goto end;
+ error = acpi_button_add_fs(device);
+ if (error)
+ goto err_free_input;
+
+ error = acpi_button_install_notify_handlers(button);
+ if (error)
+ goto err_remove_fs;
+
+ snprintf(button->phys, sizeof(button->phys),
+ "%s/button/input0", acpi_device_hid(device));
+
+ input->name = acpi_device_name(device);
+ input->phys = button->phys;
+ input->id.bustype = BUS_HOST;
+ input->id.product = button->type;
switch (button->type) {
+ case ACPI_BUTTON_TYPE_POWER:
case ACPI_BUTTON_TYPE_POWERF:
- status =
- acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
- acpi_button_notify_fixed,
- button);
+ input->evbit[0] = BIT(EV_KEY);
+ set_bit(KEY_POWER, input->keybit);
break;
+
+ case ACPI_BUTTON_TYPE_SLEEP:
case ACPI_BUTTON_TYPE_SLEEPF:
- status =
- acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
- acpi_button_notify_fixed,
- button);
+ input->evbit[0] = BIT(EV_KEY);
+ set_bit(KEY_SLEEP, input->keybit);
break;
- default:
- status = acpi_install_notify_handler(device->handle,
- ACPI_DEVICE_NOTIFY,
- acpi_button_notify,
- button);
+
+ case ACPI_BUTTON_TYPE_LID:
+ input->evbit[0] = BIT(EV_SW);
+ set_bit(SW_LID, input->swbit);
break;
}
- if (ACPI_FAILURE(status)) {
- result = -ENODEV;
- goto end;
- }
+ error = input_register_device(input);
+ if (error)
+ goto err_remove_handlers;
if (device->wakeup.flags.valid) {
/* Button's GPE is run-wake GPE */
@@ -385,47 +458,31 @@ static int acpi_button_add(struct acpi_device *device)
printk(KERN_INFO PREFIX "%s [%s]\n",
acpi_device_name(device), acpi_device_bid(device));
- end:
- if (result) {
- acpi_button_remove_fs(device);
- kfree(button);
- }
+ return 0;
- return result;
+ err_remove_handlers:
+ acpi_button_remove_notify_handlers(button);
+ err_remove_fs:
+ acpi_button_remove_fs(device);
+ err_free_input:
+ input_free_device(input);
+ err_free_button:
+ kfree(button);
+ return error;
}
static int acpi_button_remove(struct acpi_device *device, int type)
{
- acpi_status status = 0;
- struct acpi_button *button = NULL;
-
+ struct acpi_button *button;
if (!device || !acpi_driver_data(device))
return -EINVAL;
button = acpi_driver_data(device);
- /* Unregister for device notifications. */
- switch (button->type) {
- case ACPI_BUTTON_TYPE_POWERF:
- status =
- acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
- acpi_button_notify_fixed);
- break;
- case ACPI_BUTTON_TYPE_SLEEPF:
- status =
- acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
- acpi_button_notify_fixed);
- break;
- default:
- status = acpi_remove_notify_handler(device->handle,
- ACPI_DEVICE_NOTIFY,
- acpi_button_notify);
- break;
- }
-
+ acpi_button_remove_notify_handlers(button);
acpi_button_remove_fs(device);
-
+ input_unregister_device(button->input);
kfree(button);
return 0;
@@ -433,8 +490,7 @@ static int acpi_button_remove(struct acpi_device *device, int type)
static int __init acpi_button_init(void)
{
- int result = 0;
-
+ int result;
acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
if (!acpi_button_dir)
@@ -451,7 +507,6 @@ static int __init acpi_button_init(void)
static void __exit acpi_button_exit(void)
{
-
acpi_bus_unregister_driver(&acpi_button_driver);
if (acpi_power_dir)
@@ -461,8 +516,6 @@ static void __exit acpi_button_exit(void)
if (acpi_lid_dir)
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
-
- return;
}
module_init(acpi_button_init);
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 871aa520ece..69a68fd394c 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -96,11 +96,10 @@ static int acpi_container_add(struct acpi_device *device)
return -EINVAL;
}
- container = kmalloc(sizeof(struct acpi_container), GFP_KERNEL);
+ container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL);
if (!container)
return -ENOMEM;
- memset(container, 0, sizeof(struct acpi_container));
container->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
@@ -117,7 +116,7 @@ static int acpi_container_remove(struct acpi_device *device, int type)
acpi_status status = AE_OK;
struct acpi_container *pc = NULL;
- pc = (struct acpi_container *)acpi_driver_data(device);
+ pc = acpi_driver_data(device);
kfree(pc);
return status;
}
@@ -168,7 +167,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
if (ACPI_FAILURE(status) || !device) {
result = container_device_add(&device, handle);
if (!result)
- kobject_uevent(&device->kobj,
+ kobject_uevent(&device->dev.kobj,
KOBJ_ONLINE);
else
printk("Failed to add container\n");
@@ -176,13 +175,13 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
} else {
if (ACPI_SUCCESS(status)) {
/* device exist and this is a remove request */
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
}
}
break;
case ACPI_NOTIFY_EJECT_REQUEST:
if (!acpi_bus_get_device(handle, &device) && device) {
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
}
break;
default:
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index 35c6af8a83c..d48f65a8f65 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -13,14 +13,11 @@
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("debug")
-#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer"
-#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level"
+
#ifdef MODULE_PARAM_PREFIX
#undef MODULE_PARAM_PREFIX
#endif
-#define MODULE_PARAM_PREFIX
- module_param(acpi_dbg_layer, uint, 0400);
-module_param(acpi_dbg_level, uint, 0400);
+#define MODULE_PARAM_PREFIX "acpi."
struct acpi_dlayer {
const char *name;
@@ -86,6 +83,60 @@ static const struct acpi_dlevel acpi_debug_levels[] = {
ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
};
+/* --------------------------------------------------------------------------
+ FS Interface (/sys)
+ -------------------------------------------------------------------------- */
+static int param_get_debug_layer(char *buffer, struct kernel_param *kp) {
+ int result = 0;
+ int i;
+
+ result = sprintf(buffer, "%-25s\tHex SET\n", "Description");
+
+ for(i = 0; i <ARRAY_SIZE(acpi_debug_layers); i++) {
+ result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
+ acpi_debug_layers[i].name,
+ acpi_debug_layers[i].value,
+ (acpi_dbg_layer & acpi_debug_layers[i].value) ? '*' : ' ');
+ }
+ result += sprintf(buffer+result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
+ ACPI_ALL_DRIVERS,
+ (acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
+ ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer &
+ ACPI_ALL_DRIVERS) == 0 ? ' ' : '-');
+ result += sprintf(buffer+result, "--\ndebug_layer = 0x%08X ( * = enabled)\n", acpi_dbg_layer);
+
+ return result;
+}
+
+static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
+ int result = 0;
+ int i;
+
+ result = sprintf(buffer, "%-25s\tHex SET\n", "Description");
+
+ for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
+ result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
+ acpi_debug_levels[i].name,
+ acpi_debug_levels[i].value,
+ (acpi_dbg_level & acpi_debug_levels[i].
+ value) ? '*' : ' ');
+ }
+ result += sprintf(buffer+result, "--\ndebug_level = 0x%08X (* = enabled)\n",
+ acpi_dbg_level);
+
+ return result;
+}
+
+module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
+module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
+#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer"
+#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level"
+
static int
acpi_system_read_debug(char *page,
char **start, off_t off, int count, int *eof, void *data)
@@ -221,3 +272,4 @@ static int __init acpi_debug_init(void)
}
subsys_initcall(acpi_debug_init);
+#endif
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
index a6d77efb41a..f049639bac3 100644
--- a/drivers/acpi/dispatcher/dsfield.c
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -133,7 +133,8 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
}
}
- /* We could put the returned object (Node) on the object stack for later,
+ /*
+ * We could put the returned object (Node) on the object stack for later,
* but for now, we will put it in the "op" object that the parser uses,
* so we can get it again at the end of this scope
*/
@@ -514,8 +515,33 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
/* Third arg is the bank_value */
+ /* TBD: This arg is a term_arg, not a constant, and must be evaluated */
+
arg = arg->common.next;
- info.bank_value = (u32) arg->common.value.integer;
+
+ /* Currently, only the following constants are supported */
+
+ switch (arg->common.aml_opcode) {
+ case AML_ZERO_OP:
+ info.bank_value = 0;
+ break;
+
+ case AML_ONE_OP:
+ info.bank_value = 1;
+ break;
+
+ case AML_BYTE_OP:
+ case AML_WORD_OP:
+ case AML_DWORD_OP:
+ case AML_QWORD_OP:
+ info.bank_value = (u32) arg->common.value.integer;
+ break;
+
+ default:
+ info.bank_value = 0;
+ ACPI_ERROR((AE_INFO,
+ "Non-constant BankValue for BankField is not implemented"));
+ }
/* Fourth arg is the field flags */
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index 1888c055d10..af923c38852 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include <acpi/acdispat.h>
#include <acpi/acnamesp.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsinit")
@@ -90,7 +91,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
* We are only interested in NS nodes owned by the table that
* was just loaded
*/
- if (node->owner_id != info->table_desc->owner_id) {
+ if (node->owner_id != info->owner_id) {
return (AE_OK);
}
@@ -150,14 +151,21 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
******************************************************************************/
acpi_status
-acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
+acpi_ds_initialize_objects(acpi_native_uint table_index,
struct acpi_namespace_node * start_node)
{
acpi_status status;
struct acpi_init_walk_info info;
+ struct acpi_table_header *table;
+ acpi_owner_id owner_id;
ACPI_FUNCTION_TRACE(ds_initialize_objects);
+ status = acpi_tb_get_owner_id(table_index, &owner_id);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"**** Starting initialization of namespace objects ****\n"));
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:"));
@@ -166,7 +174,8 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
info.op_region_count = 0;
info.object_count = 0;
info.device_count = 0;
- info.table_desc = table_desc;
+ info.table_index = table_index;
+ info.owner_id = owner_id;
/* Walk entire namespace from the supplied root */
@@ -176,10 +185,14 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
}
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
"\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n",
- table_desc->pointer->signature,
- table_desc->owner_id, info.object_count,
+ table->signature, owner_id, info.object_count,
info.device_count, info.method_count,
info.op_region_count));
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index cf888add319..1cbe6190582 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -327,7 +327,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Execute method %p, currentstate=%p\n",
+ "Calling method %p, currentstate=%p\n",
this_walk_state->prev_op, this_walk_state));
/*
@@ -351,49 +351,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
return_ACPI_STATUS(status);
}
- /*
- * 1) Parse the method. All "normal" methods are parsed for each execution.
- * Internal methods (_OSI, etc.) do not require parsing.
- */
- if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
-
- /* Create a new walk state for the parse */
-
- next_walk_state =
- acpi_ds_create_walk_state(obj_desc->method.owner_id, op,
- obj_desc, NULL);
- if (!next_walk_state) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
-
- /* Create and init a parse tree root */
-
- op = acpi_ps_create_scope_op();
- if (!op) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
-
- status = acpi_ds_init_aml_walk(next_walk_state, op, method_node,
- obj_desc->method.aml_start,
- obj_desc->method.aml_length,
- NULL, 1);
- if (ACPI_FAILURE(status)) {
- acpi_ps_delete_parse_tree(op);
- goto cleanup;
- }
-
- /* Begin AML parse (deletes next_walk_state) */
-
- status = acpi_ps_parse_aml(next_walk_state);
- acpi_ps_delete_parse_tree(op);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
- }
-
- /* 2) Begin method execution. Create a new walk state */
+ /* Begin method parse/execution. Create a new walk state */
next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id,
NULL, obj_desc, thread);
@@ -424,7 +382,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
obj_desc->method.aml_start,
- obj_desc->method.aml_length, info, 3);
+ obj_desc->method.aml_length, info,
+ ACPI_IMODE_EXECUTE);
ACPI_FREE(info);
if (ACPI_FAILURE(status)) {
@@ -445,8 +404,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
this_walk_state->num_operands = 0;
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Starting nested execution, newstate=%p\n",
- next_walk_state));
+ "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
+ method_node->name.ascii, next_walk_state));
/* Invoke an internal method if necessary */
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
index 459160ff905..ba4626e06a5 100644
--- a/drivers/acpi/dispatcher/dsmthdat.c
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index 72190abb1d5..a474ca2334d 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -260,7 +260,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
}
obj_desc->buffer.flags |= AOPOBJ_DATA_VALID;
- op->common.node = (struct acpi_namespace_node *)obj_desc;
+ op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
return_ACPI_STATUS(AE_OK);
}
@@ -270,7 +270,8 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
*
* PARAMETERS: walk_state - Current walk state
* Op - Parser object to be translated
- * package_length - Number of elements in the package
+ * element_count - Number of elements in the package - this is
+ * the num_elements argument to Package()
* obj_desc_ptr - Where the ACPI internal object is returned
*
* RETURN: Status
@@ -278,18 +279,29 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
* DESCRIPTION: Translate a parser Op package object to the equivalent
* namespace object
*
+ * NOTE: The number of elements in the package will be always be the num_elements
+ * count, regardless of the number of elements in the package list. If
+ * num_elements is smaller, only that many package list elements are used.
+ * if num_elements is larger, the Package object is padded out with
+ * objects of type Uninitialized (as per ACPI spec.)
+ *
+ * Even though the ASL compilers do not allow num_elements to be smaller
+ * than the Package list length (for the fixed length package opcode), some
+ * BIOS code modifies the AML on the fly to adjust the num_elements, and
+ * this code compensates for that. This also provides compatibility with
+ * other AML interpreters.
+ *
******************************************************************************/
acpi_status
acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
union acpi_parse_object *op,
- u32 package_length,
+ u32 element_count,
union acpi_operand_object **obj_desc_ptr)
{
union acpi_parse_object *arg;
union acpi_parse_object *parent;
union acpi_operand_object *obj_desc = NULL;
- u32 package_list_length;
acpi_status status = AE_OK;
acpi_native_uint i;
@@ -318,32 +330,13 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
obj_desc->package.node = parent->common.node;
}
- obj_desc->package.count = package_length;
-
- /* Count the number of items in the package list */
-
- arg = op->common.value.arg;
- arg = arg->common.next;
- for (package_list_length = 0; arg; package_list_length++) {
- arg = arg->common.next;
- }
-
- /*
- * The package length (number of elements) will be the greater
- * of the specified length and the length of the initializer list
- */
- if (package_list_length > package_length) {
- obj_desc->package.count = package_list_length;
- }
-
/*
- * Allocate the pointer array (array of pointers to the
- * individual objects). Add an extra pointer slot so
- * that the list is always null terminated.
+ * Allocate the element array (array of pointers to the individual
+ * objects) based on the num_elements parameter. Add an extra pointer slot
+ * so that the list is always null terminated.
*/
obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)
- obj_desc->package.
- count +
+ element_count +
1) * sizeof(void *));
if (!obj_desc->package.elements) {
@@ -351,15 +344,20 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_NO_MEMORY);
}
+ obj_desc->package.count = element_count;
+
/*
- * Initialize all elements of the package
+ * Initialize the elements of the package, up to the num_elements count.
+ * Package is automatically padded with uninitialized (NULL) elements
+ * if num_elements is greater than the package list length. Likewise,
+ * Package is truncated if num_elements is less than the list length.
*/
arg = op->common.value.arg;
arg = arg->common.next;
- for (i = 0; arg; i++) {
+ for (i = 0; arg && (i < element_count); i++) {
if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
- /* Object (package or buffer) is already built */
+ /* This package element is already built, just get it */
obj_desc->package.elements[i] =
ACPI_CAST_PTR(union acpi_operand_object,
@@ -373,8 +371,14 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
arg = arg->common.next;
}
+ if (!arg) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Package List length larger than NumElements count (%X), truncated\n",
+ element_count));
+ }
+
obj_desc->package.flags |= AOPOBJ_DATA_VALID;
- op->common.node = (struct acpi_namespace_node *)obj_desc;
+ op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
return_ACPI_STATUS(status);
}
@@ -488,8 +492,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
/*
* Defer evaluation of Buffer term_arg operand
*/
- obj_desc->buffer.node = (struct acpi_namespace_node *)
- walk_state->operands[0];
+ obj_desc->buffer.node =
+ ACPI_CAST_PTR(struct acpi_namespace_node,
+ walk_state->operands[0]);
obj_desc->buffer.aml_start = op->named.data;
obj_desc->buffer.aml_length = op->named.length;
break;
@@ -499,8 +504,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
/*
* Defer evaluation of Package term_arg operand
*/
- obj_desc->package.node = (struct acpi_namespace_node *)
- walk_state->operands[0];
+ obj_desc->package.node =
+ ACPI_CAST_PTR(struct acpi_namespace_node,
+ walk_state->operands[0]);
obj_desc->package.aml_start = op->named.data;
obj_desc->package.aml_length = op->named.length;
break;
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index 5b974a8fe61..6c6104a7a24 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -114,7 +114,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node,
}
status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
- aml_length, NULL, 1);
+ aml_length, NULL, ACPI_IMODE_LOAD_PASS1);
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
goto cleanup;
@@ -157,7 +157,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node,
/* Execute the opcode and arguments */
status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
- aml_length, NULL, 3);
+ aml_length, NULL, ACPI_IMODE_EXECUTE);
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
goto cleanup;
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
index 05230baf5de..e4073e05a75 100644
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index d7a616c3104..69693fa0722 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -219,7 +219,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
if (!op) {
status = acpi_ds_load2_begin_op(walk_state, out_op);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit;
}
op = *out_op;
@@ -238,7 +238,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
status = acpi_ds_scope_stack_pop(walk_state);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit;
}
}
}
@@ -287,7 +287,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
status = acpi_ds_result_stack_push(walk_state);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit;
}
status = acpi_ds_exec_begin_control_op(walk_state, op);
@@ -328,6 +328,10 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
/* Nothing to do here during method execution */
return_ACPI_STATUS(status);
+
+ error_exit:
+ status = acpi_ds_method_error(status, walk_state);
+ return_ACPI_STATUS(status);
}
/*****************************************************************************
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index e3ca7f6539c..8ab9d1b29a4 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -196,6 +196,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
* one of the opcodes that actually opens a scope
*/
switch (node->type) {
+ case ACPI_TYPE_ANY:
case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_POWER:
@@ -546,6 +547,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
acpi_status status;
acpi_object_type object_type;
char *buffer_ptr;
+ u32 flags;
ACPI_FUNCTION_TRACE(ds_load2_begin_op);
@@ -669,6 +671,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
* one of the opcodes that actually opens a scope
*/
switch (node->type) {
+ case ACPI_TYPE_ANY:
case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_POWER:
@@ -750,12 +753,20 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
break;
}
- /* Add new entry into namespace */
+ flags = ACPI_NS_NO_UPSEARCH;
+ if (walk_state->pass_number == ACPI_IMODE_EXECUTE) {
+
+ /* Execution mode, node cannot already exist, node is temporary */
+
+ flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY);
+ }
+
+ /* Add new entry or lookup existing entry */
status =
acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
- object_type, ACPI_IMODE_LOAD_PASS2,
- ACPI_NS_NO_UPSEARCH, walk_state, &(node));
+ object_type, ACPI_IMODE_LOAD_PASS2, flags,
+ walk_state, &node);
break;
}
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
index c9228972f5f..3927c495e4b 100644
--- a/drivers/acpi/dispatcher/dswscope.c
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
index 7817e552267..16c8e38b51e 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index bf5b79ed361..688e83a1690 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -27,6 +27,7 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/notifier.h>
+#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -39,13 +40,15 @@ MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME);
MODULE_LICENSE("GPL");
static struct atomic_notifier_head dock_notifier_list;
+static struct platform_device dock_device;
+static char dock_device_name[] = "dock";
struct dock_station {
acpi_handle handle;
unsigned long last_dock_time;
u32 flags;
spinlock_t dd_lock;
- spinlock_t hp_lock;
+ struct mutex hp_lock;
struct list_head dependent_devices;
struct list_head hotplug_devices;
};
@@ -115,9 +118,9 @@ static void
dock_add_hotplug_device(struct dock_station *ds,
struct dock_dependent_device *dd)
{
- spin_lock(&ds->hp_lock);
+ mutex_lock(&ds->hp_lock);
list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
- spin_unlock(&ds->hp_lock);
+ mutex_unlock(&ds->hp_lock);
}
/**
@@ -131,9 +134,9 @@ static void
dock_del_hotplug_device(struct dock_station *ds,
struct dock_dependent_device *dd)
{
- spin_lock(&ds->hp_lock);
+ mutex_lock(&ds->hp_lock);
list_del(&dd->hotplug_list);
- spin_unlock(&ds->hp_lock);
+ mutex_unlock(&ds->hp_lock);
}
/**
@@ -296,7 +299,7 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
{
struct dock_dependent_device *dd;
- spin_lock(&ds->hp_lock);
+ mutex_lock(&ds->hp_lock);
/*
* First call driver specific hotplug functions
@@ -318,15 +321,17 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
else
dock_create_acpi_device(dd->handle);
}
- spin_unlock(&ds->hp_lock);
+ mutex_unlock(&ds->hp_lock);
}
static void dock_event(struct dock_station *ds, u32 event, int num)
{
+ struct device *dev = &dock_device.dev;
/*
- * we don't do events until someone tells me that
- * they would like to have them.
+ * Indicate that the status of the dock station has
+ * changed.
*/
+ kobject_uevent(&dev->kobj, KOBJ_CHANGE);
}
/**
@@ -441,6 +446,9 @@ static int dock_in_progress(struct dock_station *ds)
*/
int register_dock_notifier(struct notifier_block *nb)
{
+ if (!dock_station)
+ return -ENODEV;
+
return atomic_notifier_chain_register(&dock_notifier_list, nb);
}
@@ -452,6 +460,9 @@ EXPORT_SYMBOL_GPL(register_dock_notifier);
*/
void unregister_dock_notifier(struct notifier_block *nb)
{
+ if (!dock_station)
+ return;
+
atomic_notifier_chain_unregister(&dock_notifier_list, nb);
}
@@ -512,6 +523,37 @@ void unregister_hotplug_dock_device(acpi_handle handle)
EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
/**
+ * handle_eject_request - handle an undock request checking for error conditions
+ *
+ * Check to make sure the dock device is still present, then undock and
+ * hotremove all the devices that may need removing.
+ */
+static int handle_eject_request(struct dock_station *ds, u32 event)
+{
+ if (!dock_present(ds))
+ return -ENODEV;
+
+ if (dock_in_progress(ds))
+ return -EBUSY;
+
+ /*
+ * here we need to generate the undock
+ * event prior to actually doing the undock
+ * so that the device struct still exists.
+ */
+ dock_event(ds, event, UNDOCK_EVENT);
+ hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
+ undock(ds);
+ eject_dock(ds);
+ if (dock_present(ds)) {
+ printk(KERN_ERR PREFIX "Unable to undock!\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/**
* dock_notify - act upon an acpi dock notification
* @handle: the dock station handle
* @event: the acpi event
@@ -519,13 +561,11 @@ EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
*
* If we are notified to dock, then check to see if the dock is
* present and then dock. Notify all drivers of the dock event,
- * and then hotplug and devices that may need hotplugging. For undock
- * check to make sure the dock device is still present, then undock
- * and hotremove all the devices that may need removing.
+ * and then hotplug and devices that may need hotplugging.
*/
static void dock_notify(acpi_handle handle, u32 event, void *data)
{
- struct dock_station *ds = (struct dock_station *)data;
+ struct dock_station *ds = data;
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
@@ -553,19 +593,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
* to the driver who wish to hotplug.
*/
case ACPI_NOTIFY_EJECT_REQUEST:
- if (!dock_in_progress(ds) && dock_present(ds)) {
- /*
- * here we need to generate the undock
- * event prior to actually doing the undock
- * so that the device struct still exists.
- */
- dock_event(ds, event, UNDOCK_EVENT);
- hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
- undock(ds);
- eject_dock(ds);
- if (dock_present(ds))
- printk(KERN_ERR PREFIX "Unable to undock!\n");
- }
+ handle_eject_request(ds, event);
break;
default:
printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
@@ -587,23 +615,58 @@ static acpi_status
find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
- acpi_handle tmp;
- struct dock_station *ds = (struct dock_station *)context;
+ acpi_handle tmp, parent;
+ struct dock_station *ds = context;
struct dock_dependent_device *dd;
status = acpi_bus_get_ejd(handle, &tmp);
- if (ACPI_FAILURE(status))
- return AE_OK;
+ if (ACPI_FAILURE(status)) {
+ /* try the parent device as well */
+ status = acpi_get_parent(handle, &parent);
+ if (ACPI_FAILURE(status))
+ goto fdd_out;
+ /* see if parent is dependent on dock */
+ status = acpi_bus_get_ejd(parent, &tmp);
+ if (ACPI_FAILURE(status))
+ goto fdd_out;
+ }
if (tmp == ds->handle) {
dd = alloc_dock_dependent_device(handle);
if (dd)
add_dock_dependent_device(ds, dd);
}
-
+fdd_out:
return AE_OK;
}
+/*
+ * show_docked - read method for "docked" file in sysfs
+ */
+static ssize_t show_docked(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
+
+}
+DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
+
+/*
+ * write_undock - write method for "undock" file in sysfs
+ */
+static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+
+ if (!count)
+ return -EINVAL;
+
+ ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
+ return ret ? ret: count;
+}
+DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
+
/**
* dock_add - add a new dock station
* @handle: the dock station handle
@@ -626,9 +689,33 @@ static int dock_add(acpi_handle handle)
INIT_LIST_HEAD(&dock_station->dependent_devices);
INIT_LIST_HEAD(&dock_station->hotplug_devices);
spin_lock_init(&dock_station->dd_lock);
- spin_lock_init(&dock_station->hp_lock);
+ mutex_init(&dock_station->hp_lock);
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
+ /* initialize platform device stuff */
+ dock_device.name = dock_device_name;
+ ret = platform_device_register(&dock_device);
+ if (ret) {
+ printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret);
+ kfree(dock_station);
+ return ret;
+ }
+ ret = device_create_file(&dock_device.dev, &dev_attr_docked);
+ if (ret) {
+ printk("Error %d adding sysfs file\n", ret);
+ platform_device_unregister(&dock_device);
+ kfree(dock_station);
+ return ret;
+ }
+ ret = device_create_file(&dock_device.dev, &dev_attr_undock);
+ if (ret) {
+ printk("Error %d adding sysfs file\n", ret);
+ device_remove_file(&dock_device.dev, &dev_attr_docked);
+ platform_device_unregister(&dock_device);
+ kfree(dock_station);
+ return ret;
+ }
+
/* Find dependent devices */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_dock_devices, dock_station,
@@ -638,7 +725,8 @@ static int dock_add(acpi_handle handle)
dd = alloc_dock_dependent_device(handle);
if (!dd) {
kfree(dock_station);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto dock_add_err_unregister;
}
add_dock_dependent_device(dock_station, dd);
@@ -658,8 +746,12 @@ static int dock_add(acpi_handle handle)
return 0;
dock_add_err:
- kfree(dock_station);
kfree(dd);
+dock_add_err_unregister:
+ device_remove_file(&dock_device.dev, &dev_attr_docked);
+ device_remove_file(&dock_device.dev, &dev_attr_undock);
+ platform_device_unregister(&dock_device);
+ kfree(dock_station);
return ret;
}
@@ -686,6 +778,11 @@ static int dock_remove(void)
if (ACPI_FAILURE(status))
printk(KERN_ERR "Error removing notify handler\n");
+ /* cleanup sysfs */
+ device_remove_file(&dock_device.dev, &dev_attr_docked);
+ device_remove_file(&dock_device.dev, &dev_attr_undock);
+ platform_device_unregister(&dock_device);
+
/* free dock station memory */
kfree(dock_station);
return 0;
@@ -703,7 +800,7 @@ static int dock_remove(void)
static acpi_status
find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
{
- int *count = (int *)context;
+ int *count = context;
acpi_status status = AE_OK;
if (is_dock(handle)) {
@@ -726,7 +823,7 @@ static int __init dock_init(void)
ACPI_UINT32_MAX, find_dock, &num, NULL);
if (!num)
- return -ENODEV;
+ printk(KERN_INFO "No dock devices found.\n");
return 0;
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e6d4b084dca..743ce27fa0b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -45,35 +45,34 @@ 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"
-
+#undef PREFIX
+#define PREFIX "ACPI: EC: "
/* 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 */
-
/* 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
-
+enum ec_command {
+ ACPI_EC_COMMAND_READ = 0x80,
+ ACPI_EC_COMMAND_WRITE = 0x81,
+ ACPI_EC_BURST_ENABLE = 0x82,
+ ACPI_EC_BURST_DISABLE = 0x83,
+ ACPI_EC_COMMAND_QUERY = 0x84,
+};
/* EC events */
-enum {
+enum ec_event {
ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */
- ACPI_EC_EVENT_IBF_0, /* Input buffer empty */
+ ACPI_EC_EVENT_IBF_0, /* Input buffer empty */
};
-#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */
+#define ACPI_EC_DELAY 500 /* Wait 500ms 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 enum ec_mode {
+ EC_INTR = 1, /* Output buffer full */
+ EC_POLL, /* Input buffer empty */
+} acpi_ec_mode = EC_INTR;
static int acpi_ec_remove(struct acpi_device *device, int type);
static int acpi_ec_start(struct acpi_device *device);
@@ -93,22 +92,21 @@ static struct acpi_driver acpi_ec_driver = {
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
-struct acpi_ec {
+static struct acpi_ec {
acpi_handle handle;
unsigned long uid;
- unsigned long gpe_bit;
+ unsigned long gpe;
unsigned long command_addr;
unsigned long data_addr;
unsigned long global_lock;
- struct semaphore sem;
- unsigned int expect_event;
+ struct mutex lock;
+ atomic_t query_pending;
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_mode = EC_INTR;
/* --------------------------------------------------------------------------
Transaction Management
@@ -134,54 +132,41 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
outb(data, ec->data_addr);
}
-static int acpi_ec_check_status(u8 status, u8 event)
+static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
{
- switch (event) {
- case ACPI_EC_EVENT_OBF_1:
+ u8 status = acpi_ec_read_status(ec);
+
+ if (event == ACPI_EC_EVENT_OBF_1) {
if (status & ACPI_EC_FLAG_OBF)
return 1;
- break;
- case ACPI_EC_EVENT_IBF_0:
+ } else if (event == ACPI_EC_EVENT_IBF_0) {
if (!(status & ACPI_EC_FLAG_IBF))
return 1;
- break;
- default:
- break;
}
return 0;
}
-static int acpi_ec_wait(struct acpi_ec *ec, u8 event)
+static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event)
{
- int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0;
- long time_left;
-
- ec->expect_event = event;
- if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
- ec->expect_event = 0;
- return 0;
- }
-
- 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));
- if (time_left > 0) {
- ec->expect_event = 0;
+ if (acpi_ec_mode == EC_POLL) {
+ unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
+ while (time_before(jiffies, delay)) {
+ if (acpi_ec_check_status(ec, event))
return 0;
- }
}
- if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
- ec->expect_event = 0;
+ } else {
+ if (wait_event_timeout(ec->wait,
+ acpi_ec_check_status(ec, event),
+ msecs_to_jiffies(ACPI_EC_DELAY)) ||
+ acpi_ec_check_status(ec, event)) {
return 0;
+ } else {
+ printk(KERN_ERR PREFIX "acpi_ec_wait timeout,"
+ " status = %d, expect_event = %d\n",
+ acpi_ec_read_status(ec), event);
}
- } while (--i > 0);
-
- ec->expect_event = 0;
+ }
return -ETIME;
}
@@ -196,7 +181,6 @@ int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
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_IBF_0);
@@ -212,7 +196,7 @@ int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
atomic_set(&ec->leaving_burst, 0);
return 0;
- end:
+ end:
ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
return -1;
}
@@ -221,58 +205,68 @@ int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
{
u8 status = 0;
-
status = acpi_ec_read_status(ec);
- if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){
+ if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) {
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- if(status)
+ if (status)
goto end;
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:
+ end:
ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
return -1;
}
-#endif /* ACPI_FUTURE_USAGE */
+#endif /* ACPI_FUTURE_USAGE */
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
- const u8 *wdata, unsigned wdata_len,
- u8 *rdata, unsigned rdata_len)
+ const u8 * wdata, unsigned wdata_len,
+ u8 * rdata, unsigned rdata_len)
{
- int result;
+ int result = 0;
acpi_ec_write_cmd(ec, command);
- for (; wdata_len > 0; wdata_len --) {
+ for (; wdata_len > 0; --wdata_len) {
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- if (result)
- return result;
+ if (result) {
+ printk(KERN_ERR PREFIX
+ "write_cmd timeout, command = %d\n", command);
+ goto end;
+ }
acpi_ec_write_data(ec, *(wdata++));
}
- if (command == ACPI_EC_COMMAND_WRITE) {
+ if (!rdata_len) {
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- if (result)
- return result;
+ if (result) {
+ printk(KERN_ERR PREFIX
+ "finish-write timeout, command = %d\n", command);
+ goto end;
+ }
+ } else if (command == ACPI_EC_COMMAND_QUERY) {
+ atomic_set(&ec->query_pending, 0);
}
- for (; rdata_len > 0; rdata_len --) {
+ for (; rdata_len > 0; --rdata_len) {
result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
- if (result)
- return result;
+ if (result) {
+ printk(KERN_ERR PREFIX "read timeout, command = %d\n",
+ command);
+ goto end;
+ }
*(rdata++) = acpi_ec_read_data(ec);
}
-
- return 0;
+ end:
+ return result;
}
static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
- const u8 *wdata, unsigned wdata_len,
- u8 *rdata, unsigned rdata_len)
+ const u8 * wdata, unsigned wdata_len,
+ u8 * rdata, unsigned rdata_len)
{
int status;
u32 glk;
@@ -280,36 +274,40 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
return -EINVAL;
- if (rdata)
- memset(rdata, 0, rdata_len);
+ if (rdata)
+ memset(rdata, 0, rdata_len);
+ mutex_lock(&ec->lock);
if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status))
return -ENODEV;
}
- down(&ec->sem);
+
+ /* Make sure GPE is enabled before doing transaction */
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
if (status) {
- printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
+ printk(KERN_DEBUG PREFIX
+ "input buffer is not empty, aborting transaction\n");
goto end;
}
- status = acpi_ec_transaction_unlocked(ec, command,
- wdata, wdata_len,
- rdata, rdata_len);
+ status = acpi_ec_transaction_unlocked(ec, command,
+ wdata, wdata_len,
+ rdata, rdata_len);
-end:
- up(&ec->sem);
+ end:
if (ec->global_lock)
acpi_release_global_lock(glk);
+ mutex_unlock(&ec->lock);
return status;
}
-static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
+static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
{
int result;
u8 d;
@@ -322,15 +320,15 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
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,
+ 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)
{
struct acpi_ec *ec;
int err;
@@ -369,9 +367,9 @@ int ec_write(u8 addr, u8 val)
EXPORT_SYMBOL(ec_write);
-extern int ec_transaction(u8 command,
- const u8 *wdata, unsigned wdata_len,
- u8 *rdata, unsigned rdata_len)
+int ec_transaction(u8 command,
+ const u8 * wdata, unsigned wdata_len,
+ u8 * rdata, unsigned rdata_len)
{
struct acpi_ec *ec;
@@ -386,65 +384,49 @@ extern int ec_transaction(u8 command,
EXPORT_SYMBOL(ec_transaction);
-static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
+static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
{
int result;
- u8 d;
+ u8 d;
- if (!ec || !data)
- return -EINVAL;
+ if (!ec || !data)
+ return -EINVAL;
- /*
- * 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).
- */
+ /*
+ * 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).
+ */
- result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
- if (result)
- return result;
+ result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
+ if (result)
+ return result;
- if (!d)
- return -ENODATA;
+ if (!d)
+ return -ENODATA;
- *data = d;
- return 0;
+ *data = d;
+ return 0;
}
/* --------------------------------------------------------------------------
Event Management
-------------------------------------------------------------------------- */
-struct acpi_ec_query_data {
- acpi_handle handle;
- u8 data;
-};
-
static void acpi_ec_gpe_query(void *ec_cxt)
{
struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
u8 value = 0;
- static char object_name[8];
+ char object_name[8];
- if (!ec)
- goto end;
-
- value = acpi_ec_read_status(ec);
-
- if (!(value & ACPI_EC_FLAG_SCI))
- goto end;
-
- if (acpi_ec_query(ec, &value))
- goto end;
+ if (!ec || acpi_ec_query(ec, &value))
+ return;
snprintf(object_name, 8, "_Q%2.2X", value);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
-
- end:
- acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
}
static u32 acpi_ec_gpe_handler(void *data)
@@ -453,22 +435,18 @@ static u32 acpi_ec_gpe_handler(void *data)
u8 value;
struct acpi_ec *ec = (struct acpi_ec *)data;
- acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR);
- value = acpi_ec_read_status(ec);
-
if (acpi_ec_mode == EC_INTR) {
- if (acpi_ec_check_status(value, ec->expect_event)) {
- ec->expect_event = 0;
- wake_up(&ec->wait);
- }
+ wake_up(&ec->wait);
}
- if (value & ACPI_EC_FLAG_SCI) {
- status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
- return status == AE_OK ?
- ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
+ value = acpi_ec_read_status(ec);
+ if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) {
+ atomic_set(&ec->query_pending, 1);
+ status =
+ acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query,
+ ec);
}
- acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
+
return status == AE_OK ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}
@@ -504,7 +482,6 @@ acpi_ec_space_handler(u32 function,
acpi_integer f_v = 0;
int i = 0;
-
if ((address > 0xFF) || !value || !handler_context)
return AE_BAD_PARAMETER;
@@ -518,7 +495,7 @@ acpi_ec_space_handler(u32 function,
switch (function) {
case ACPI_READ:
temp = 0;
- result = acpi_ec_read(ec, (u8) address, (u8 *) &temp);
+ result = acpi_ec_read(ec, (u8) address, (u8 *) & temp);
break;
case ACPI_WRITE:
result = acpi_ec_write(ec, (u8) address, (u8) temp);
@@ -571,18 +548,15 @@ static int acpi_ec_read_info(struct seq_file *seq, void *offset)
{
struct acpi_ec *ec = (struct acpi_ec *)seq->private;
-
if (!ec)
goto end;
- seq_printf(seq, "gpe bit: 0x%02x\n",
- (u32) ec->gpe_bit);
+ seq_printf(seq, "gpe: 0x%02x\n", (u32) ec->gpe);
seq_printf(seq, "ports: 0x%02x, 0x%02x\n",
- (u32) ec->command_addr,
- (u32) ec->data_addr);
+ (u32) ec->command_addr, (u32) ec->data_addr);
seq_printf(seq, "use global lock: %s\n",
ec->global_lock ? "yes" : "no");
- acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
end:
return 0;
@@ -605,7 +579,6 @@ static int acpi_ec_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
-
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_ec_dir);
@@ -648,18 +621,17 @@ static int acpi_ec_add(struct acpi_device *device)
acpi_status status = AE_OK;
struct acpi_ec *ec = NULL;
-
if (!device)
return -EINVAL;
- ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!ec)
return -ENOMEM;
- memset(ec, 0, sizeof(struct acpi_ec));
ec->handle = device->handle;
ec->uid = -1;
- init_MUTEX(&ec->sem);
+ mutex_init(&ec->lock);
+ atomic_set(&ec->query_pending, 0);
if (acpi_ec_mode == EC_INTR) {
atomic_set(&ec->leaving_burst, 1);
init_waitqueue_head(&ec->wait);
@@ -669,8 +641,7 @@ static int acpi_ec_add(struct acpi_device *device)
acpi_driver_data(device) = ec;
/* Use the global lock for all EC transactions? */
- acpi_evaluate_integer(ec->handle, "_GLK", NULL,
- &ec->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 */
@@ -679,7 +650,7 @@ static int acpi_ec_add(struct acpi_device *device)
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler);
- acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
+ acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
&acpi_ec_gpe_handler);
kfree(ec_ecdt);
@@ -687,11 +658,10 @@ static int acpi_ec_add(struct acpi_device *device)
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
- status =
- acpi_evaluate_integer(ec->handle, "_GPE", NULL,
- &ec->gpe_bit);
+ status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit assignment"));
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Obtaining GPE bit assignment"));
result = -ENODEV;
goto end;
}
@@ -701,13 +671,13 @@ static int acpi_ec_add(struct acpi_device *device)
goto end;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
- acpi_device_name(device), acpi_device_bid(device),
- (u32) ec->gpe_bit));
+ acpi_device_name(device), acpi_device_bid(device),
+ (u32) ec->gpe));
if (!first_ec)
first_ec = device;
- end:
+ end:
if (result)
kfree(ec);
@@ -718,7 +688,6 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
{
struct acpi_ec *ec = NULL;
-
if (!device)
return -EINVAL;
@@ -761,7 +730,6 @@ static int acpi_ec_start(struct acpi_device *device)
acpi_status status = AE_OK;
struct acpi_ec *ec = NULL;
-
if (!device)
return -EINVAL;
@@ -782,27 +750,26 @@ static int acpi_ec_start(struct acpi_device *device)
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
- ec->gpe_bit, ec->command_addr, ec->data_addr));
+ ec->gpe, ec->command_addr, ec->data_addr));
/*
* Install GPE handler
*/
- status = acpi_install_gpe_handler(NULL, ec->gpe_bit,
+ status = acpi_install_gpe_handler(NULL, ec->gpe,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec);
if (ACPI_FAILURE(status)) {
return -ENODEV;
}
- acpi_set_gpe_type(NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
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->gpe_bit,
- &acpi_ec_gpe_handler);
+ acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
return -ENODEV;
}
@@ -814,7 +781,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
acpi_status status = AE_OK;
struct acpi_ec *ec = NULL;
-
if (!device)
return -EINVAL;
@@ -826,9 +792,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
if (ACPI_FAILURE(status))
return -ENODEV;
- status =
- acpi_remove_gpe_handler(NULL, ec->gpe_bit,
- &acpi_ec_gpe_handler);
+ status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -841,7 +805,7 @@ acpi_fake_ecdt_callback(acpi_handle handle,
{
acpi_status status;
- init_MUTEX(&ec_ecdt->sem);
+ mutex_init(&ec_ecdt->lock);
if (acpi_ec_mode == EC_INTR) {
init_waitqueue_head(&ec_ecdt->wait);
}
@@ -853,16 +817,15 @@ acpi_fake_ecdt_callback(acpi_handle handle,
ec_ecdt->uid = -1;
acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
- status =
- acpi_evaluate_integer(handle, "_GPE", NULL,
- &ec_ecdt->gpe_bit);
+ status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe);
if (ACPI_FAILURE(status))
return status;
ec_ecdt->global_lock = TRUE;
ec_ecdt->handle = handle;
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));
+ ec_ecdt->gpe, ec_ecdt->command_addr,
+ ec_ecdt->data_addr));
return AE_CTRL_TERMINATE;
}
@@ -884,12 +847,11 @@ static int __init acpi_ec_fake_ecdt(void)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
- ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!ec_ecdt) {
ret = -ENOMEM;
goto error;
}
- memset(ec_ecdt, 0, sizeof(struct acpi_ec));
status = acpi_get_devices(ACPI_EC_HID,
acpi_fake_ecdt_callback, NULL, NULL);
@@ -901,7 +863,7 @@ static int __init acpi_ec_fake_ecdt(void)
goto error;
}
return 0;
- error:
+ error:
return ret;
}
@@ -910,9 +872,8 @@ static int __init acpi_ec_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);
+ status = acpi_get_table(ACPI_SIG_ECDT, 1,
+ (struct acpi_table_header **)&ecdt_ptr);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -921,30 +882,28 @@ static int __init acpi_ec_get_real_ecdt(void)
/*
* Generate a temporary ec context to use until the namespace is scanned
*/
- ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!ec_ecdt)
return -ENOMEM;
- memset(ec_ecdt, 0, sizeof(struct acpi_ec));
- init_MUTEX(&ec_ecdt->sem);
+ mutex_init(&ec_ecdt->lock);
if (acpi_ec_mode == EC_INTR) {
init_waitqueue_head(&ec_ecdt->wait);
}
- 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;
+ ec_ecdt->command_addr = ecdt_ptr->control.address;
+ ec_ecdt->data_addr = ecdt_ptr->data.address;
+ ec_ecdt->gpe = ecdt_ptr->gpe;
/* use the GL just to be safe */
ec_ecdt->global_lock = TRUE;
ec_ecdt->uid = ecdt_ptr->uid;
- status =
- acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
+ status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle);
if (ACPI_FAILURE(status)) {
goto error;
}
return 0;
- error:
+ error:
ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
kfree(ec_ecdt);
ec_ecdt = NULL;
@@ -970,14 +929,14 @@ int __init acpi_ec_ecdt_probe(void)
/*
* Install GPE handler
*/
- status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit,
+ status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec_ecdt);
if (ACPI_FAILURE(status)) {
goto error;
}
- acpi_set_gpe_type(NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR);
+ acpi_set_gpe_type(NULL, ec_ecdt->gpe, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe(NULL, ec_ecdt->gpe, ACPI_NOT_ISR);
status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_EC,
@@ -985,7 +944,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->gpe_bit,
+ acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
&acpi_ec_gpe_handler);
goto error;
}
@@ -1004,7 +963,6 @@ static int __init acpi_ec_init(void)
{
int result = 0;
-
if (acpi_disabled)
return 0;
@@ -1057,7 +1015,8 @@ static int __init acpi_ec_set_intr_mode(char *str)
acpi_ec_mode = EC_POLL;
}
acpi_ec_driver.ops.add = acpi_ec_add;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", intr ? "interrupt" : "polling"));
+ printk(KERN_NOTICE PREFIX "%s mode.\n",
+ intr ? "interrupt" : "polling");
return 1;
}
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index 919037d6acf..a1f87b5def2 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,13 +70,6 @@ acpi_status acpi_ev_initialize_events(void)
ACPI_FUNCTION_TRACE(ev_initialize_events);
- /* Make sure we have ACPI tables */
-
- if (!acpi_gbl_DSDT) {
- ACPI_WARNING((AE_INFO, "No ACPI tables present!"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
/*
* Initialize the Fixed and General Purpose Events. This is done prior to
* enabling SCIs to prevent interrupts from occurring before the handlers are
@@ -211,8 +204,7 @@ static acpi_status acpi_ev_fixed_event_initialize(void)
if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) {
status =
acpi_set_register(acpi_gbl_fixed_event_info[i].
- enable_register_id, 0,
- ACPI_MTX_LOCK);
+ enable_register_id, 0);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -298,7 +290,7 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
/* Clear the status bit */
(void)acpi_set_register(acpi_gbl_fixed_event_info[event].
- status_register_id, 1, ACPI_MTX_DO_NOT_LOCK);
+ status_register_id, 1);
/*
* Make sure we've got a handler. If not, report an error.
@@ -306,8 +298,7 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
*/
if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
(void)acpi_set_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, 0,
- ACPI_MTX_DO_NOT_LOCK);
+ enable_register_id, 0);
ACPI_ERROR((AE_INFO,
"No installed handler for fixed event [%08X]",
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index c76c0583ca6..dfac3ecc596 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -121,7 +121,9 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
if (!gpe_register_info) {
return_ACPI_STATUS(AE_NOT_EXIST);
}
- register_bit = gpe_event_info->register_bit;
+ register_bit = (u8)
+ (1 <<
+ (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number));
/* 1) Disable case. Simply clear all enable bits */
@@ -458,8 +460,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/* Examine one GPE bit */
- if (enabled_status_byte &
- acpi_gbl_decode_to8bit[j]) {
+ if (enabled_status_byte & (1 << j)) {
/*
* Found an active GPE. Dispatch the event to a handler
* or method.
@@ -570,7 +571,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "While evaluating GPE method [%4.4s]",
+ "while evaluating GPE method [%4.4s]",
acpi_ut_get_node_name
(local_gpe_event_info.dispatch.
method_node)));
@@ -618,6 +619,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
+ acpi_gpe_count++;
+
/*
* If edge-triggered, clear the GPE status bit now. Note that
* level-triggered events are cleared after the GPE is serviced.
@@ -633,20 +636,23 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
}
}
- /* Save current system state */
-
- if (acpi_gbl_system_awake_and_running) {
- ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
- } else {
- ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
+ if (!acpi_gbl_system_awake_and_running) {
+ /*
+ * We just woke up because of a wake GPE. Disable any further GPEs
+ * until we are fully up and running (Only wake GPEs should be enabled
+ * at this time, but we just brute-force disable them all.)
+ * 1) We must disable this particular wake GPE so it won't fire again
+ * 2) We want to disable all wake GPEs, since we are now awake
+ */
+ (void)acpi_hw_disable_all_gpes();
}
/*
- * Dispatch the GPE to either an installed handler, or the control
- * method associated with this GPE (_Lxx or _Exx).
- * If a handler exists, we invoke it and do not attempt to run the method.
- * If there is neither a handler nor a method, we disable the level to
- * prevent further events from coming in here.
+ * Dispatch the GPE to either an installed handler, or the control method
+ * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
+ * it and do not attempt to run the method. If there is neither a handler
+ * nor a method, we disable this GPE to prevent further such pointless
+ * events from firing.
*/
switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
case ACPI_GPE_DISPATCH_HANDLER:
@@ -677,8 +683,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
case ACPI_GPE_DISPATCH_METHOD:
/*
- * Disable GPE, so it doesn't keep firing before the method has a
- * chance to run.
+ * Disable the GPE, so it doesn't keep firing before the method has a
+ * chance to run (it runs asynchronously with interrupts enabled).
*/
status = acpi_ev_disable_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
@@ -711,7 +717,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
gpe_number));
/*
- * Disable the GPE. The GPE will remain disabled until the ACPI
+ * Disable the GPE. The GPE will remain disabled until the ACPI
* Core Subsystem is restarted, or a handler is installed.
*/
status = acpi_ev_disable_gpe(gpe_event_info);
@@ -726,50 +732,3 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
return_UINT32(ACPI_INTERRUPT_HANDLED);
}
-
-#ifdef ACPI_GPE_NOTIFY_CHECK
-/*******************************************************************************
- * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED
- *
- * FUNCTION: acpi_ev_check_for_wake_only_gpe
- *
- * PARAMETERS: gpe_event_info - info for this GPE
- *
- * RETURN: Status
- *
- * DESCRIPTION: Determine if a a GPE is "wake-only".
- *
- * Called from Notify() code in interpreter when a "DeviceWake"
- * Notify comes in.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ev_check_for_wake_only_gpe);
-
- if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */
- ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) { /* System state at GPE time */
- /* This must be a wake-only GPE, disable it */
-
- status = acpi_ev_disable_gpe(gpe_event_info);
-
- /* Set GPE to wake-only. Do not change wake disabled/enabled status */
-
- acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE);
-
- ACPI_INFO((AE_INFO,
- "GPE %p was updated from wake/run to wake-only",
- gpe_event_info));
-
- /* This was a wake-only GPE */
-
- return_ACPI_STATUS(AE_WAKE_ONLY_GPE);
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-#endif
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 95ddeb48bc0..ad5bc76edf4 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -529,7 +529,7 @@ static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32
/* Install new interrupt handler if not SCI_INT */
- if (interrupt_number != acpi_gbl_FADT->sci_int) {
+ if (interrupt_number != acpi_gbl_FADT.sci_interrupt) {
status = acpi_os_install_interrupt_handler(interrupt_number,
acpi_ev_gpe_xrupt_handler,
gpe_xrupt);
@@ -567,7 +567,7 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
/* We never want to remove the SCI interrupt handler */
- if (gpe_xrupt->interrupt_number == acpi_gbl_FADT->sci_int) {
+ if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) {
gpe_xrupt->gpe_block_list_head = NULL;
return_ACPI_STATUS(AE_OK);
}
@@ -796,30 +796,31 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
(u8) (gpe_block->block_base_number +
(i * ACPI_GPE_REGISTER_WIDTH));
- ACPI_STORE_ADDRESS(this_register->status_address.address,
- (gpe_block->block_address.address + i));
+ this_register->status_address.address =
+ gpe_block->block_address.address + i;
- ACPI_STORE_ADDRESS(this_register->enable_address.address,
- (gpe_block->block_address.address
- + i + gpe_block->register_count));
+ this_register->enable_address.address =
+ gpe_block->block_address.address + i +
+ gpe_block->register_count;
- this_register->status_address.address_space_id =
- gpe_block->block_address.address_space_id;
- this_register->enable_address.address_space_id =
- gpe_block->block_address.address_space_id;
- this_register->status_address.register_bit_width =
+ this_register->status_address.space_id =
+ gpe_block->block_address.space_id;
+ this_register->enable_address.space_id =
+ gpe_block->block_address.space_id;
+ this_register->status_address.bit_width =
ACPI_GPE_REGISTER_WIDTH;
- this_register->enable_address.register_bit_width =
+ this_register->enable_address.bit_width =
ACPI_GPE_REGISTER_WIDTH;
- this_register->status_address.register_bit_offset =
+ this_register->status_address.bit_offset =
ACPI_GPE_REGISTER_WIDTH;
- this_register->enable_address.register_bit_offset =
+ this_register->enable_address.bit_offset =
ACPI_GPE_REGISTER_WIDTH;
/* Init the event_info for each GPE within this register */
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
- this_event->register_bit = acpi_gbl_decode_to8bit[j];
+ this_event->gpe_number =
+ (u8) (this_register->base_gpe_number + j);
this_event->register_info = this_register;
this_event++;
}
@@ -1109,11 +1110,12 @@ acpi_status acpi_ev_gpe_initialize(void)
* If EITHER the register length OR the block address are zero, then that
* particular block is not supported.
*/
- if (acpi_gbl_FADT->gpe0_blk_len && acpi_gbl_FADT->xgpe0_blk.address) {
+ if (acpi_gbl_FADT.gpe0_block_length &&
+ acpi_gbl_FADT.xgpe0_block.address) {
/* GPE block 0 exists (has both length and address > 0) */
- register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2);
+ register_count0 = (u16) (acpi_gbl_FADT.gpe0_block_length / 2);
gpe_number_max =
(register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
@@ -1121,9 +1123,9 @@ acpi_status acpi_ev_gpe_initialize(void)
/* Install GPE Block 0 */
status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
- &acpi_gbl_FADT->xgpe0_blk,
+ &acpi_gbl_FADT.xgpe0_block,
register_count0, 0,
- acpi_gbl_FADT->sci_int,
+ acpi_gbl_FADT.sci_interrupt,
&acpi_gbl_gpe_fadt_blocks[0]);
if (ACPI_FAILURE(status)) {
@@ -1132,20 +1134,21 @@ acpi_status acpi_ev_gpe_initialize(void)
}
}
- if (acpi_gbl_FADT->gpe1_blk_len && acpi_gbl_FADT->xgpe1_blk.address) {
+ if (acpi_gbl_FADT.gpe1_block_length &&
+ acpi_gbl_FADT.xgpe1_block.address) {
/* GPE block 1 exists (has both length and address > 0) */
- register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2);
+ register_count1 = (u16) (acpi_gbl_FADT.gpe1_block_length / 2);
/* Check for GPE0/GPE1 overlap (if both banks exist) */
if ((register_count0) &&
- (gpe_number_max >= acpi_gbl_FADT->gpe1_base)) {
+ (gpe_number_max >= acpi_gbl_FADT.gpe1_base)) {
ACPI_ERROR((AE_INFO,
"GPE0 block (GPE 0 to %d) overlaps the GPE1 block (GPE %d to %d) - Ignoring GPE1",
- gpe_number_max, acpi_gbl_FADT->gpe1_base,
- acpi_gbl_FADT->gpe1_base +
+ gpe_number_max, acpi_gbl_FADT.gpe1_base,
+ acpi_gbl_FADT.gpe1_base +
((register_count1 *
ACPI_GPE_REGISTER_WIDTH) - 1)));
@@ -1157,10 +1160,11 @@ acpi_status acpi_ev_gpe_initialize(void)
status =
acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
- &acpi_gbl_FADT->xgpe1_blk,
+ &acpi_gbl_FADT.xgpe1_block,
register_count1,
- acpi_gbl_FADT->gpe1_base,
- acpi_gbl_FADT->sci_int,
+ acpi_gbl_FADT.gpe1_base,
+ acpi_gbl_FADT.
+ sci_interrupt,
&acpi_gbl_gpe_fadt_blocks
[1]);
@@ -1173,7 +1177,7 @@ acpi_status acpi_ev_gpe_initialize(void)
* GPE0 and GPE1 do not have to be contiguous in the GPE number
* space. However, GPE0 always starts at GPE number zero.
*/
- gpe_number_max = acpi_gbl_FADT->gpe1_base +
+ gpe_number_max = acpi_gbl_FADT.gpe1_base +
((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1);
}
}
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index ee2a10bf907..1b784ffe54c 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,14 +63,18 @@ static const char *acpi_notify_value_names[] = {
};
#endif
+/* Pointer to FACS needed for the Global Lock */
+
+static struct acpi_table_facs *facs = NULL;
+
/* Local prototypes */
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
-static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context);
-
static u32 acpi_ev_global_lock_handler(void *context);
+static acpi_status acpi_ev_remove_global_lock_handler(void);
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_is_notify_object
@@ -282,68 +286,45 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
/*******************************************************************************
*
- * FUNCTION: acpi_ev_global_lock_thread
- *
- * PARAMETERS: Context - From thread interface, not used
- *
- * RETURN: None
- *
- * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
- * Global Lock. Simply signal all threads that are waiting
- * for the lock.
- *
- ******************************************************************************/
-
-static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context)
-{
- acpi_status status;
-
- /* Signal threads that are waiting for the lock */
-
- if (acpi_gbl_global_lock_thread_count) {
-
- /* Send sufficient units to the semaphore */
-
- status =
- acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore,
- acpi_gbl_global_lock_thread_count);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not signal Global Lock semaphore"));
- }
- }
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ev_global_lock_handler
*
* PARAMETERS: Context - From thread interface, not used
*
- * RETURN: ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED
+ * RETURN: ACPI_INTERRUPT_HANDLED
*
* DESCRIPTION: Invoked directly from the SCI handler when a global lock
- * release interrupt occurs. Grab the global lock and queue
- * the global lock thread for execution
+ * release interrupt occurs. Attempt to acquire the global lock,
+ * if successful, signal the thread waiting for the lock.
+ *
+ * NOTE: Assumes that the semaphore can be signaled from interrupt level. If
+ * this is not possible for some reason, a separate thread will have to be
+ * scheduled to do this.
*
******************************************************************************/
static u32 acpi_ev_global_lock_handler(void *context)
{
u8 acquired = FALSE;
- acpi_status status;
/*
- * Attempt to get the lock
+ * Attempt to get the lock.
+ *
* If we don't get it now, it will be marked pending and we will
* take another interrupt when it becomes free.
*/
- ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
+ ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
if (acquired) {
/* Got the lock, now wake all threads waiting for it */
+
acpi_gbl_global_lock_acquired = TRUE;
- acpi_ev_global_lock_thread(context);
+ /* Send a unit to the semaphore */
+
+ if (ACPI_FAILURE(acpi_os_signal_semaphore(
+ acpi_gbl_global_lock_semaphore, 1))) {
+ ACPI_ERROR((AE_INFO,
+ "Could not signal Global Lock semaphore"));
+ }
}
return (ACPI_INTERRUPT_HANDLED);
@@ -367,6 +348,13 @@ acpi_status acpi_ev_init_global_lock_handler(void)
ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
+ status =
+ acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ (struct acpi_table_header **)&facs);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
acpi_gbl_global_lock_present = TRUE;
status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
acpi_ev_global_lock_handler,
@@ -390,6 +378,31 @@ acpi_status acpi_ev_init_global_lock_handler(void)
return_ACPI_STATUS(status);
}
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_remove_global_lock_handler
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove the handler for the Global Lock
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ev_remove_global_lock_handler(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
+
+ acpi_gbl_global_lock_present = FALSE;
+ status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
+ acpi_ev_global_lock_handler);
+
+ return_ACPI_STATUS(status);
+}
+
/******************************************************************************
*
* FUNCTION: acpi_ev_acquire_global_lock
@@ -400,6 +413,16 @@ acpi_status acpi_ev_init_global_lock_handler(void)
*
* DESCRIPTION: Attempt to gain ownership of the Global Lock.
*
+ * MUTEX: Interpreter must be locked
+ *
+ * Note: The original implementation allowed multiple threads to "acquire" the
+ * Global Lock, and the OS would hold the lock until the last thread had
+ * released it. However, this could potentially starve the BIOS out of the
+ * lock, especially in the case where there is a tight handshake between the
+ * Embedded Controller driver and the BIOS. Therefore, this implementation
+ * allows only one thread to acquire the HW Global Lock at a time, and makes
+ * the global lock appear as a standard mutex on the OS side.
+ *
*****************************************************************************/
acpi_status acpi_ev_acquire_global_lock(u16 timeout)
@@ -409,53 +432,51 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
-#ifndef ACPI_APPLICATION
- /* Make sure that we actually have a global lock */
-
- if (!acpi_gbl_global_lock_present) {
- return_ACPI_STATUS(AE_NO_GLOBAL_LOCK);
+ /*
+ * Only one thread can acquire the GL at a time, the global_lock_mutex
+ * enforces this. This interface releases the interpreter if we must wait.
+ */
+ status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
}
-#endif
-
- /* One more thread wants the global lock */
-
- acpi_gbl_global_lock_thread_count++;
/*
- * If we (OS side vs. BIOS side) have the hardware lock already,
- * we are done
+ * Make sure that a global lock actually exists. If not, just treat
+ * the lock as a standard mutex.
*/
- if (acpi_gbl_global_lock_acquired) {
+ if (!acpi_gbl_global_lock_present) {
+ acpi_gbl_global_lock_acquired = TRUE;
return_ACPI_STATUS(AE_OK);
}
- /* We must acquire the actual hardware lock */
+ /* Attempt to acquire the actual hardware lock */
- ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
+ ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
if (acquired) {
/* We got the lock */
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Acquired the HW Global Lock\n"));
+ "Acquired hardware Global Lock\n"));
acpi_gbl_global_lock_acquired = TRUE;
return_ACPI_STATUS(AE_OK);
}
/*
- * Did not get the lock. The pending bit was set above, and we must now
+ * Did not get the lock. The pending bit was set above, and we must now
* wait until we get the global lock released interrupt.
*/
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for the HW Global Lock\n"));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n"));
/*
- * Acquire the global lock semaphore first.
- * Since this wait will block, we must release the interpreter
+ * Wait for handshake with the global lock interrupt handler.
+ * This interface releases the interpreter if we must wait.
*/
- status =
- acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
- timeout);
+ status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
+ ACPI_WAIT_FOREVER);
+
return_ACPI_STATUS(status);
}
@@ -478,38 +499,39 @@ acpi_status acpi_ev_release_global_lock(void)
ACPI_FUNCTION_TRACE(ev_release_global_lock);
- if (!acpi_gbl_global_lock_thread_count) {
+ /* Lock must be already acquired */
+
+ if (!acpi_gbl_global_lock_acquired) {
ACPI_WARNING((AE_INFO,
- "Cannot release HW Global Lock, it has not been acquired"));
+ "Cannot release the ACPI Global Lock, it has not been acquired"));
return_ACPI_STATUS(AE_NOT_ACQUIRED);
}
- /* One fewer thread has the global lock */
+ if (acpi_gbl_global_lock_present) {
- acpi_gbl_global_lock_thread_count--;
- if (acpi_gbl_global_lock_thread_count) {
+ /* Allow any thread to release the lock */
- /* There are still some threads holding the lock, cannot release */
+ ACPI_RELEASE_GLOBAL_LOCK(facs, pending);
- return_ACPI_STATUS(AE_OK);
+ /*
+ * If the pending bit was set, we must write GBL_RLS to the control
+ * register
+ */
+ if (pending) {
+ status =
+ acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
+ 1);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Released hardware Global Lock\n"));
}
- /*
- * No more threads holding lock, we can do the actual hardware
- * release
- */
- ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, pending);
acpi_gbl_global_lock_acquired = FALSE;
- /*
- * If the pending bit was set, we must write GBL_RLS to the control
- * register
- */
- if (pending) {
- status = acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
- 1, ACPI_MTX_LOCK);
- }
+ /* Release the local GL mutex */
+ acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
return_ACPI_STATUS(status);
}
@@ -559,6 +581,12 @@ void acpi_ev_terminate(void)
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
}
+
+ status = acpi_ev_remove_global_lock_handler();
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO,
+ "Could not remove Global Lock handler"));
+ }
}
/* Deallocate all handler objects installed within GPE info structs */
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 21caae04fe8..e99f0c435a4 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -291,7 +291,6 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
u32 bit_width, acpi_integer * value)
{
acpi_status status;
- acpi_status status2;
acpi_adr_space_handler handler;
acpi_adr_space_setup region_setup;
union acpi_operand_object *handler_desc;
@@ -345,7 +344,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
* setup will potentially execute control methods
* (e.g., _REG method for this region)
*/
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
handler_desc->address_space.context,
@@ -353,10 +352,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
/* Re-enter the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
/* Check for failure of the Region Setup */
@@ -409,7 +405,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
* exit the interpreter because the handler *might* block -- we don't
* know what it will do, so we can't hold the lock on the intepreter.
*/
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
}
/* Call the handler */
@@ -430,10 +426,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
* We just returned from a non-default handler, we must re-enter the
* interpreter
*/
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 203d1359190..a4fa7e6822a 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,11 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evrgnini")
+/* Local prototypes */
+static u8 acpi_ev_match_pci_root_bridge(char *id);
+
+static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node);
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_system_memory_region_setup
@@ -62,6 +67,7 @@ ACPI_MODULE_NAME("evrgnini")
* DESCRIPTION: Setup a system_memory operation region
*
******************************************************************************/
+
acpi_status
acpi_ev_system_memory_region_setup(acpi_handle handle,
u32 function,
@@ -168,9 +174,9 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
union acpi_operand_object *handler_obj;
struct acpi_namespace_node *parent_node;
struct acpi_namespace_node *pci_root_node;
+ struct acpi_namespace_node *pci_device_node;
union acpi_operand_object *region_obj =
(union acpi_operand_object *)handle;
- struct acpi_device_id object_hID;
ACPI_FUNCTION_TRACE(ev_pci_config_region_setup);
@@ -215,45 +221,30 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
pci_root_node = parent_node;
while (pci_root_node != acpi_gbl_root_node) {
- status =
- acpi_ut_execute_HID(pci_root_node, &object_hID);
- if (ACPI_SUCCESS(status)) {
- /*
- * Got a valid _HID string, check if this is a PCI root.
- * New for ACPI 3.0: check for a PCI Express root also.
- */
- 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)))) {
-
- /* Install a handler for this PCI root bridge */
- status =
- acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
- if (ACPI_FAILURE(status)) {
- if (status == AE_SAME_HANDLER) {
- /*
- * It is OK if the handler is already installed on the root
- * bridge. Still need to return a context object for the
- * new PCI_Config operation region, however.
- */
- status = AE_OK;
- } else {
- ACPI_EXCEPTION((AE_INFO,
- status,
- "Could not install PciConfig handler for Root Bridge %4.4s",
- acpi_ut_get_node_name
- (pci_root_node)));
- }
+ /* Get the _HID/_CID in order to detect a root_bridge */
+
+ if (acpi_ev_is_pci_root_bridge(pci_root_node)) {
+
+ /* Install a handler for this PCI root bridge */
+
+ status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_SAME_HANDLER) {
+ /*
+ * It is OK if the handler is already installed on the root
+ * bridge. Still need to return a context object for the
+ * new PCI_Config operation region, however.
+ */
+ status = AE_OK;
+ } else {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not install PciConfig handler for Root Bridge %4.4s",
+ acpi_ut_get_node_name
+ (pci_root_node)));
}
- break;
}
+ break;
}
pci_root_node = acpi_ns_get_parent_node(pci_root_node);
@@ -282,14 +273,25 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
/*
* For PCI_Config space access, we need the segment, bus,
* device and function numbers. Acquire them here.
+ *
+ * Find the parent device object. (This allows the operation region to be
+ * within a subscope under the device, such as a control method.)
*/
+ pci_device_node = region_obj->region.node;
+ while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) {
+ pci_device_node = acpi_ns_get_parent_node(pci_device_node);
+ }
+
+ if (!pci_device_node) {
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
/*
* Get the PCI device and function numbers from the _ADR object
* contained in the parent's scope.
*/
status =
- acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, parent_node,
+ acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node,
&pci_value);
/*
@@ -329,6 +331,91 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
/*******************************************************************************
*
+ * FUNCTION: acpi_ev_match_pci_root_bridge
+ *
+ * PARAMETERS: Id - The HID/CID in string format
+ *
+ * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID.
+ *
+ ******************************************************************************/
+
+static u8 acpi_ev_match_pci_root_bridge(char *id)
+{
+
+ /*
+ * Check if this is a PCI root.
+ * ACPI 3.0+: check for a PCI Express root also.
+ */
+ if (!(ACPI_STRNCMP(id,
+ PCI_ROOT_HID_STRING,
+ sizeof(PCI_ROOT_HID_STRING))) ||
+ !(ACPI_STRNCMP(id,
+ PCI_EXPRESS_ROOT_HID_STRING,
+ sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_is_pci_root_bridge
+ *
+ * PARAMETERS: Node - Device node being examined
+ *
+ * RETURN: TRUE if device is a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by
+ * examining the _HID and _CID for the device.
+ *
+ ******************************************************************************/
+
+static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
+{
+ acpi_status status;
+ struct acpi_device_id hid;
+ struct acpi_compatible_id_list *cid;
+ acpi_native_uint i;
+
+ /*
+ * Get the _HID and check for a PCI Root Bridge
+ */
+ status = acpi_ut_execute_HID(node, &hid);
+ if (ACPI_FAILURE(status)) {
+ return (FALSE);
+ }
+
+ if (acpi_ev_match_pci_root_bridge(hid.value)) {
+ return (TRUE);
+ }
+
+ /*
+ * The _HID did not match.
+ * Get the _CID and check for a PCI Root Bridge
+ */
+ status = acpi_ut_execute_CID(node, &cid);
+ if (ACPI_FAILURE(status)) {
+ return (FALSE);
+ }
+
+ /* Check all _CIDs in the returned list */
+
+ for (i = 0; i < cid->count; i++) {
+ if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) {
+ ACPI_FREE(cid);
+ return (TRUE);
+ }
+ }
+
+ ACPI_FREE(cid);
+ return (FALSE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ev_pci_bar_region_setup
*
* PARAMETERS: Handle - Region we are interested in
@@ -432,6 +519,9 @@ acpi_ev_default_region_setup(acpi_handle handle,
* a PCI address in the scope of the definition. This address is
* required to perform an access to PCI config space.
*
+ * MUTEX: Interpreter should be unlocked, because we may run the _REG
+ * method for this region.
+ *
******************************************************************************/
acpi_status
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c
index 8106215ad55..7e5d15ce239 100644
--- a/drivers/acpi/events/evsci.c
+++ b/drivers/acpi/events/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -142,9 +142,10 @@ u32 acpi_ev_install_sci_handler(void)
ACPI_FUNCTION_TRACE(ev_install_sci_handler);
- status = acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT->sci_int,
- acpi_ev_sci_xrupt_handler,
- acpi_gbl_gpe_xrupt_list_head);
+ status =
+ acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
+ acpi_ev_sci_xrupt_handler,
+ acpi_gbl_gpe_xrupt_list_head);
return_ACPI_STATUS(status);
}
@@ -175,8 +176,9 @@ acpi_status acpi_ev_remove_sci_handler(void)
/* Just let the OS remove the handler and disable the level */
- status = acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT->sci_int,
- acpi_ev_sci_xrupt_handler);
+ status =
+ acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
+ acpi_ev_sci_xrupt_handler);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index 923fd2b4695..685a103a358 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -768,11 +768,9 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
return (AE_BAD_PARAMETER);
}
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return (status);
- }
+ /* Must lock interpreter to prevent race conditions */
+ acpi_ex_enter_interpreter();
status = acpi_ev_acquire_global_lock(timeout);
acpi_ex_exit_interpreter();
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index 7ebc2efac93..17065e98807 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include <acpi/acevents.h>
#include <acpi/acnamesp.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evxfevnt")
@@ -65,13 +66,14 @@ acpi_status acpi_enable(void)
ACPI_FUNCTION_TRACE(acpi_enable);
- /* Make sure we have the FADT */
+ /* ACPI tables must be present */
- if (!acpi_gbl_FADT) {
- ACPI_WARNING((AE_INFO, "No FADT information present!"));
+ if (!acpi_tb_tables_loaded()) {
return_ACPI_STATUS(AE_NO_ACPI_TABLES);
}
+ /* Check current mode */
+
if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
"System is already in ACPI mode\n"));
@@ -111,11 +113,6 @@ acpi_status acpi_disable(void)
ACPI_FUNCTION_TRACE(acpi_disable);
- if (!acpi_gbl_FADT) {
- ACPI_WARNING((AE_INFO, "No FADT information present!"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) {
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
"System is already in legacy (non-ACPI) mode\n"));
@@ -169,7 +166,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, 1, ACPI_MTX_LOCK);
+ enable_register_id, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -178,7 +175,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags)
status =
acpi_get_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, &value, ACPI_MTX_LOCK);
+ enable_register_id, &value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -368,14 +365,14 @@ acpi_status acpi_disable_event(u32 event, u32 flags)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, 0, ACPI_MTX_LOCK);
+ enable_register_id, 0);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
status =
acpi_get_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, &value, ACPI_MTX_LOCK);
+ enable_register_id, &value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -421,7 +418,7 @@ acpi_status acpi_clear_event(u32 event)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
- status_register_id, 1, ACPI_MTX_LOCK);
+ status_register_id, 1);
return_ACPI_STATUS(status);
}
@@ -510,7 +507,7 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
status =
acpi_get_register(acpi_gbl_fixed_event_info[event].
- status_register_id, event_status, ACPI_MTX_LOCK);
+ status_register_id, event_status);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
index 83b12a9afa3..7bf09c5fb24 100644
--- a/drivers/acpi/events/evxfregn.c
+++ b/drivers/acpi/events/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index c8341fa5fe0..25802f302ff 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,7 +54,7 @@ ACPI_MODULE_NAME("exconfig")
/* Local prototypes */
static acpi_status
-acpi_ex_add_table(struct acpi_table_header *table,
+acpi_ex_add_table(acpi_native_uint table_index,
struct acpi_namespace_node *parent_node,
union acpi_operand_object **ddb_handle);
@@ -74,12 +74,11 @@ acpi_ex_add_table(struct acpi_table_header *table,
******************************************************************************/
static acpi_status
-acpi_ex_add_table(struct acpi_table_header *table,
+acpi_ex_add_table(acpi_native_uint table_index,
struct acpi_namespace_node *parent_node,
union acpi_operand_object **ddb_handle)
{
acpi_status status;
- struct acpi_table_desc table_info;
union acpi_operand_object *obj_desc;
ACPI_FUNCTION_TRACE(ex_add_table);
@@ -98,42 +97,16 @@ acpi_ex_add_table(struct acpi_table_header *table,
/* Install the new table into the local data structures */
- ACPI_MEMSET(&table_info, 0, sizeof(struct acpi_table_desc));
-
- table_info.type = ACPI_TABLE_ID_SSDT;
- table_info.pointer = table;
- table_info.length = (acpi_size) table->length;
- table_info.allocation = ACPI_MEM_ALLOCATED;
-
- status = acpi_tb_install_table(&table_info);
- obj_desc->reference.object = table_info.installed_desc;
-
- if (ACPI_FAILURE(status)) {
- if (status == AE_ALREADY_EXISTS) {
-
- /* Table already exists, just return the handle */
-
- return_ACPI_STATUS(AE_OK);
- }
- goto cleanup;
- }
+ obj_desc->reference.object = ACPI_CAST_PTR(void, table_index);
/* Add the table to the namespace */
- status = acpi_ns_load_table(table_info.installed_desc, parent_node);
+ status = acpi_ns_load_table(table_index, parent_node);
if (ACPI_FAILURE(status)) {
-
- /* Uninstall table on error */
-
- (void)acpi_tb_uninstall_table(table_info.installed_desc);
- goto cleanup;
+ acpi_ut_remove_reference(obj_desc);
+ *ddb_handle = NULL;
}
- return_ACPI_STATUS(AE_OK);
-
- cleanup:
- acpi_ut_remove_reference(obj_desc);
- *ddb_handle = NULL;
return_ACPI_STATUS(status);
}
@@ -146,7 +119,7 @@ acpi_ex_add_table(struct acpi_table_header *table,
*
* RETURN: Status
*
- * DESCRIPTION: Load an ACPI table
+ * DESCRIPTION: Load an ACPI table from the RSDT/XSDT
*
******************************************************************************/
@@ -156,33 +129,20 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
{
acpi_status status;
union acpi_operand_object **operand = &walk_state->operands[0];
- struct acpi_table_header *table;
+ acpi_native_uint table_index;
struct acpi_namespace_node *parent_node;
struct acpi_namespace_node *start_node;
struct acpi_namespace_node *parameter_node = NULL;
union acpi_operand_object *ddb_handle;
+ struct acpi_table_header *table;
ACPI_FUNCTION_TRACE(ex_load_table_op);
-#if 0
- /*
- * Make sure that the signature does not match one of the tables that
- * is already loaded.
- */
- status = acpi_tb_match_signature(operand[0]->string.pointer, NULL);
- if (status == AE_OK) {
-
- /* Signature matched -- don't allow override */
-
- return_ACPI_STATUS(AE_ALREADY_EXISTS);
- }
-#endif
-
- /* Find the ACPI table */
+ /* Find the ACPI table in the RSDT/XSDT */
status = acpi_tb_find_table(operand[0]->string.pointer,
operand[1]->string.pointer,
- operand[2]->string.pointer, &table);
+ operand[2]->string.pointer, &table_index);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND) {
return_ACPI_STATUS(status);
@@ -245,7 +205,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
/* Load the table into the namespace */
- status = acpi_ex_add_table(table, parent_node, &ddb_handle);
+ status = acpi_ex_add_table(table_index, parent_node, &ddb_handle);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -266,9 +226,13 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
}
}
- ACPI_INFO((AE_INFO,
- "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
- table->signature, table->oem_id, table->oem_table_id));
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_SUCCESS(status)) {
+ ACPI_INFO((AE_INFO,
+ "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
+ table->signature, table->oem_id,
+ table->oem_table_id));
+ }
*return_desc = ddb_handle;
return_ACPI_STATUS(status);
@@ -278,7 +242,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
*
* FUNCTION: acpi_ex_load_op
*
- * PARAMETERS: obj_desc - Region or Field where the table will be
+ * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be
* obtained
* Target - Where a handle to the table will be stored
* walk_state - Current state
@@ -287,6 +251,12 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
*
* DESCRIPTION: Load an ACPI table from a field or operation region
*
+ * NOTE: Region Fields (Field, bank_field, index_fields) are resolved to buffer
+ * objects before this code is reached.
+ *
+ * If source is an operation region, it must refer to system_memory, as
+ * per the ACPI specification.
+ *
******************************************************************************/
acpi_status
@@ -294,22 +264,26 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
union acpi_operand_object *target,
struct acpi_walk_state *walk_state)
{
- acpi_status status;
union acpi_operand_object *ddb_handle;
- union acpi_operand_object *buffer_desc = NULL;
- struct acpi_table_header *table_ptr = NULL;
- acpi_physical_address address;
- struct acpi_table_header table_header;
- acpi_integer temp;
- u32 i;
+ struct acpi_table_desc table_desc;
+ acpi_native_uint table_index;
+ acpi_status status;
ACPI_FUNCTION_TRACE(ex_load_op);
- /* Object can be either an op_region or a Field */
+ ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
+
+ /* Source Object can be either an op_region or a Buffer/Field */
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_REGION:
+ /* Region must be system_memory (from ACPI spec) */
+
+ if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
obj_desc,
acpi_ut_get_object_type_name(obj_desc)));
@@ -325,113 +299,41 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
}
}
- /* Get the base physical address of the region */
-
- address = obj_desc->region.address;
-
- /* Get part of the table header to get the table length */
-
- table_header.length = 0;
- for (i = 0; i < 8; i++) {
- status =
- acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
- (acpi_physical_address)
- (i + address), 8,
- &temp);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the one valid byte of the returned 64-bit value */
-
- ACPI_CAST_PTR(u8, &table_header)[i] = (u8) temp;
- }
-
- /* Sanity check the table length */
-
- if (table_header.length < sizeof(struct acpi_table_header)) {
- return_ACPI_STATUS(AE_BAD_HEADER);
- }
-
- /* Allocate a buffer for the entire table */
-
- table_ptr = ACPI_ALLOCATE(table_header.length);
- if (!table_ptr) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Get the entire table from the op region */
-
- for (i = 0; i < table_header.length; i++) {
- status =
- acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
- (acpi_physical_address)
- (i + address), 8,
- &temp);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- /* Get the one valid byte of the returned 64-bit value */
-
- ACPI_CAST_PTR(u8, table_ptr)[i] = (u8) temp;
- }
+ table_desc.address = obj_desc->region.address;
+ table_desc.length = obj_desc->region.length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
break;
- case ACPI_TYPE_LOCAL_REGION_FIELD:
- case ACPI_TYPE_LOCAL_BANK_FIELD:
- case ACPI_TYPE_LOCAL_INDEX_FIELD:
+ case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Field %p %s\n",
- obj_desc,
- acpi_ut_get_object_type_name(obj_desc)));
+ /* Simply extract the buffer from the buffer object */
- /*
- * The length of the field must be at least as large as the table.
- * Read the entire field and thus the entire table. Buffer is
- * allocated during the read.
- */
- status =
- acpi_ex_read_data_from_field(walk_state, obj_desc,
- &buffer_desc);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- table_ptr = ACPI_CAST_PTR(struct acpi_table_header,
- buffer_desc->buffer.pointer);
-
- /* All done with the buffer_desc, delete it */
-
- buffer_desc->buffer.pointer = NULL;
- acpi_ut_remove_reference(buffer_desc);
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Load from Buffer or Field %p %s\n", obj_desc,
+ acpi_ut_get_object_type_name(obj_desc)));
- /* Sanity check the table length */
+ table_desc.pointer = ACPI_CAST_PTR(struct acpi_table_header,
+ obj_desc->buffer.pointer);
+ table_desc.length = table_desc.pointer->length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
- if (table_ptr->length < sizeof(struct acpi_table_header)) {
- status = AE_BAD_HEADER;
- goto cleanup;
- }
+ obj_desc->buffer.pointer = NULL;
break;
default:
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- /* The table must be either an SSDT or a PSDT */
-
- if ((!ACPI_COMPARE_NAME(table_ptr->signature, PSDT_SIG)) &&
- (!ACPI_COMPARE_NAME(table_ptr->signature, SSDT_SIG))) {
- ACPI_ERROR((AE_INFO,
- "Table has invalid signature [%4.4s], must be SSDT or PSDT",
- table_ptr->signature));
- status = AE_BAD_SIGNATURE;
+ /*
+ * Install the new table into the local data structures
+ */
+ status = acpi_tb_add_table(&table_desc, &table_index);
+ if (ACPI_FAILURE(status)) {
goto cleanup;
}
- /* Install the new table into the local data structures */
-
- status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle);
+ status =
+ acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle);
if (ACPI_FAILURE(status)) {
/* On error, table_ptr was deallocated above */
@@ -450,13 +352,9 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(status);
}
- ACPI_INFO((AE_INFO,
- "Dynamic SSDT Load - OemId [%6.6s] OemTableId [%8.8s]",
- table_ptr->oem_id, table_ptr->oem_table_id));
-
cleanup:
if (ACPI_FAILURE(status)) {
- ACPI_FREE(table_ptr);
+ acpi_tb_delete_table(&table_desc);
}
return_ACPI_STATUS(status);
}
@@ -477,7 +375,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
{
acpi_status status = AE_OK;
union acpi_operand_object *table_desc = ddb_handle;
- struct acpi_table_desc *table_info;
+ acpi_native_uint table_index;
ACPI_FUNCTION_TRACE(ex_unload_table);
@@ -493,19 +391,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Get the actual table descriptor from the ddb_handle */
+ /* Get the table index from the ddb_handle */
- table_info = (struct acpi_table_desc *)table_desc->reference.object;
+ table_index = (acpi_native_uint) table_desc->reference.object;
/*
* Delete the entire namespace under this table Node
* (Offset contains the table_id)
*/
- acpi_ns_delete_namespace_by_owner(table_info->owner_id);
-
- /* Delete the table itself */
+ acpi_tb_delete_namespace_by_owner(table_index);
+ acpi_tb_release_owner_id(table_index);
- (void)acpi_tb_uninstall_table(table_info->installed_desc);
+ acpi_tb_set_table_loaded_flag(table_index, FALSE);
/* Delete the table descriptor (ddb_handle) */
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index 544e81a6a43..d470e8b1f4e 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
index 34eec82c1b1..7c38528a7e8 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -359,8 +359,9 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
union acpi_operand_object **operand = &walk_state->operands[0];
union acpi_operand_object *obj_desc;
struct acpi_namespace_node *node;
- struct acpi_table_header *table;
union acpi_operand_object *region_obj2;
+ acpi_native_uint table_index;
+ struct acpi_table_header *table;
ACPI_FUNCTION_TRACE(ex_create_table_region);
@@ -380,7 +381,7 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
status = acpi_tb_find_table(operand[1]->string.pointer,
operand[2]->string.pointer,
- operand[3]->string.pointer, &table);
+ operand[3]->string.pointer, &table_index);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -395,6 +396,11 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
region_obj2 = obj_desc->common.next_object;
region_obj2->extra.region_context = NULL;
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Init the region from the operands */
obj_desc->region.space_id = REGION_DATA_TABLE;
@@ -553,7 +559,8 @@ acpi_ex_create_method(u8 * aml_start,
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
if (!obj_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ status = AE_NO_MEMORY;
+ goto exit;
}
/* Save the method's AML pointer and length */
@@ -576,10 +583,7 @@ acpi_ex_create_method(u8 * aml_start,
* Get the sync_level. If method is serialized, a mutex will be
* created for this method when it is parsed.
*/
- if (acpi_gbl_all_methods_serialized) {
- obj_desc->method.sync_level = 0;
- obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
- } else if (method_flags & AML_METHOD_SERIALIZED) {
+ if (method_flags & AML_METHOD_SERIALIZED) {
/*
* ACPI 1.0: sync_level = 0
* ACPI 2.0: sync_level = sync_level in method declaration
@@ -597,6 +601,7 @@ acpi_ex_create_method(u8 * aml_start,
acpi_ut_remove_reference(obj_desc);
+ exit:
/* Remove a reference to the operand */
acpi_ut_remove_reference(operand[1]);
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 2450943add3..68d283fd60e 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -59,8 +59,6 @@ static void acpi_ex_out_string(char *title, char *value);
static void acpi_ex_out_pointer(char *title, void *value);
-static void acpi_ex_out_address(char *title, acpi_physical_address value);
-
static void
acpi_ex_dump_object(union acpi_operand_object *obj_desc,
struct acpi_exdump_info *info);
@@ -92,10 +90,11 @@ static struct acpi_exdump_info acpi_ex_dump_string[4] = {
{ACPI_EXD_STRING, 0, NULL}
};
-static struct acpi_exdump_info acpi_ex_dump_buffer[4] = {
+static struct acpi_exdump_info acpi_ex_dump_buffer[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer), NULL},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(buffer.length), "Length"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.pointer), "Pointer"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.node), "Parent Node"},
{ACPI_EXD_BUFFER, 0, NULL}
};
@@ -165,8 +164,8 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = {
static struct acpi_exdump_info acpi_ex_dump_processor[7] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_processor), NULL},
- {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
- {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.length), "Length"},
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"},
{ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.system_notify),
"System Notify"},
@@ -379,18 +378,12 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
break;
case ACPI_EXD_POINTER:
+ case ACPI_EXD_ADDRESS:
acpi_ex_out_pointer(name,
*ACPI_CAST_PTR(void *, target));
break;
- case ACPI_EXD_ADDRESS:
-
- acpi_ex_out_address(name,
- *ACPI_CAST_PTR
- (acpi_physical_address, target));
- break;
-
case ACPI_EXD_STRING:
acpi_ut_print_string(obj_desc->string.pointer,
@@ -834,16 +827,6 @@ static void acpi_ex_out_pointer(char *title, void *value)
acpi_os_printf("%20s : %p\n", title, value);
}
-static void acpi_ex_out_address(char *title, acpi_physical_address value)
-{
-
-#if ACPI_MACHINE_WIDTH == 16
- acpi_os_printf("%20s : %p\n", title, value);
-#else
- acpi_os_printf("%20s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64(value));
-#endif
-}
-
/*******************************************************************************
*
* FUNCTION: acpi_ex_dump_namespace_node
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
index 9ea9c3a67ca..2d88a3d8d1a 100644
--- a/drivers/acpi/executer/exfield.c
+++ b/drivers/acpi/executer/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
index 40f0bee6faa..65a48b6170e 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/executer/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -257,14 +257,13 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD,
- " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
+ " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
acpi_ut_get_region_name(rgn_desc->region.
space_id),
rgn_desc->region.space_id,
obj_desc->common_field.access_byte_width,
obj_desc->common_field.base_byte_offset,
- field_datum_byte_offset,
- ACPI_FORMAT_UINT64(address)));
+ field_datum_byte_offset, (void *)address));
/* Invoke the appropriate address_space/op_region handler */
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
index bd98aab017c..f13d1cec2d6 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index 3a39c2e8e10..5101bad5baf 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include <acpi/acinterp.h>
+#include <acpi/acevents.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exmutex")
@@ -150,7 +151,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Sanity check -- we must have a valid thread ID */
+ /* Sanity check: we must have a valid thread ID */
if (!walk_state->thread) {
ACPI_ERROR((AE_INFO,
@@ -174,24 +175,28 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/* Support for multiple acquires by the owning thread */
if (obj_desc->mutex.owner_thread) {
-
- /* Special case for Global Lock, allow all threads */
-
- if ((obj_desc->mutex.owner_thread->thread_id ==
- walk_state->thread->thread_id) ||
- (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK)) {
+ if (obj_desc->mutex.owner_thread->thread_id ==
+ walk_state->thread->thread_id) {
/*
- * The mutex is already owned by this thread,
- * just increment the acquisition depth
+ * The mutex is already owned by this thread, just increment the
+ * acquisition depth
*/
obj_desc->mutex.acquisition_depth++;
return_ACPI_STATUS(AE_OK);
}
}
- /* Acquire the mutex, wait if necessary */
+ /* Acquire the mutex, wait if necessary. Special case for Global Lock */
+
+ if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+ status =
+ acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
+ } else {
+ status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
+ (u16) time_desc->integer.
+ value);
+ }
- status = acpi_ex_system_acquire_mutex(time_desc, obj_desc);
if (ACPI_FAILURE(status)) {
/* Includes failure from a timeout on time_desc */
@@ -211,7 +216,6 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/* Link the mutex to the current thread for force-unlock at method exit */
acpi_ex_link_mutex(obj_desc, walk_state->thread);
-
return_ACPI_STATUS(AE_OK);
}
@@ -232,7 +236,7 @@ acpi_status
acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state)
{
- acpi_status status;
+ acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(ex_release_mutex);
@@ -249,7 +253,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
}
- /* Sanity check -- we must have a valid thread ID */
+ /* Sanity check: we must have a valid thread ID */
if (!walk_state->thread) {
ACPI_ERROR((AE_INFO,
@@ -264,18 +268,18 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
*/
if ((obj_desc->mutex.owner_thread->thread_id !=
walk_state->thread->thread_id)
- && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) {
+ && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
ACPI_ERROR((AE_INFO,
- "Thread %X cannot release Mutex [%4.4s] acquired by thread %X",
- (u32) walk_state->thread->thread_id,
+ "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
+ (unsigned long)walk_state->thread->thread_id,
acpi_ut_get_node_name(obj_desc->mutex.node),
- (u32) obj_desc->mutex.owner_thread->thread_id));
+ (unsigned long)obj_desc->mutex.owner_thread->thread_id));
return_ACPI_STATUS(AE_AML_NOT_OWNER);
}
/*
- * The sync level of the mutex must be less than or
- * equal to the current sync level
+ * The sync level of the mutex must be less than or equal to the current
+ * sync level
*/
if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
ACPI_ERROR((AE_INFO,
@@ -298,11 +302,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
acpi_ex_unlink_mutex(obj_desc);
- /* Release the mutex */
+ /* Release the mutex, special case for Global Lock */
- status = acpi_ex_system_release_mutex(obj_desc);
+ if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+ status = acpi_ev_release_global_lock();
+ } else {
+ acpi_os_release_mutex(obj_desc->mutex.os_mutex);
+ }
- /* Update the mutex and walk state, restore sync_level before acquire */
+ /* Update the mutex and restore sync_level */
obj_desc->mutex.owner_thread = NULL;
walk_state->thread->current_sync_level =
@@ -321,39 +329,49 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
*
* DESCRIPTION: Release all mutexes held by this thread
*
+ * NOTE: This function is called as the thread is exiting the interpreter.
+ * Mutexes are not released when an individual control method is exited, but
+ * only when the parent thread actually exits the interpreter. This allows one
+ * method to acquire a mutex, and a different method to release it, as long as
+ * this is performed underneath a single parent control method.
+ *
******************************************************************************/
void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
{
union acpi_operand_object *next = thread->acquired_mutex_list;
- union acpi_operand_object *this;
- acpi_status status;
+ union acpi_operand_object *obj_desc;
ACPI_FUNCTION_ENTRY();
/* Traverse the list of owned mutexes, releasing each one */
while (next) {
- this = next;
- next = this->mutex.next;
+ obj_desc = next;
+ next = obj_desc->mutex.next;
+
+ obj_desc->mutex.prev = NULL;
+ obj_desc->mutex.next = NULL;
+ obj_desc->mutex.acquisition_depth = 0;
+
+ /* Release the mutex, special case for Global Lock */
- this->mutex.acquisition_depth = 1;
- this->mutex.prev = NULL;
- this->mutex.next = NULL;
+ if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
- /* Release the mutex */
+ /* Ignore errors */
- status = acpi_ex_system_release_mutex(this);
- if (ACPI_FAILURE(status)) {
- continue;
+ (void)acpi_ev_release_global_lock();
+ } else {
+ acpi_os_release_mutex(obj_desc->mutex.os_mutex);
}
/* Mark mutex unowned */
- this->mutex.owner_thread = NULL;
+ obj_desc->mutex.owner_thread = NULL;
/* Update Thread sync_level (Last mutex is the important one) */
- thread->current_sync_level = this->mutex.original_sync_level;
+ thread->current_sync_level =
+ obj_desc->mutex.original_sync_level;
}
}
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c
index d3d70364626..1ee4fb1175c 100644
--- a/drivers/acpi/executer/exnames.c
+++ b/drivers/acpi/executer/exnames.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
index 6374d8be88e..252f10acbbc 100644
--- a/drivers/acpi/executer/exoparg1.c
+++ b/drivers/acpi/executer/exoparg1.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -104,9 +104,7 @@ acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state)
status = AE_NO_MEMORY;
goto cleanup;
}
-#if ACPI_MACHINE_WIDTH != 16
return_desc->integer.value = acpi_os_get_timer();
-#endif
break;
default: /* Unknown opcode */
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
index 7d2cbc11316..17e652e6537 100644
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/executer/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c
index e2d945dfd50..7fe67cf82ce 100644
--- a/drivers/acpi/executer/exoparg3.c
+++ b/drivers/acpi/executer/exoparg3.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c
index f0c0ba6eb40..bd80a9cb3d6 100644
--- a/drivers/acpi/executer/exoparg6.c
+++ b/drivers/acpi/executer/exoparg6.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
index 44d064f427b..a6696621ff1 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/executer/exprep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
index 3cc97ba48b3..2e9ce94798c 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/executer/exregion.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -155,16 +155,15 @@ acpi_ex_system_memory_space_handler(u32 function,
/* Create a new mapping starting at the address given */
- status = acpi_os_map_memory(address, window_size,
- (void **)&mem_info->
- mapped_logical_address);
- if (ACPI_FAILURE(status)) {
+ mem_info->mapped_logical_address =
+ acpi_os_map_memory((acpi_native_uint) address, window_size);
+ if (!mem_info->mapped_logical_address) {
ACPI_ERROR((AE_INFO,
"Could not map memory at %8.8X%8.8X, size %X",
ACPI_FORMAT_UINT64(address),
(u32) window_size));
mem_info->mapped_length = 0;
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
/* Save the physical address and mapping size */
@@ -210,11 +209,10 @@ acpi_ex_system_memory_space_handler(u32 function,
*value = (acpi_integer) ACPI_GET32(logical_addr_ptr);
break;
-#if ACPI_MACHINE_WIDTH != 16
case 64:
*value = (acpi_integer) ACPI_GET64(logical_addr_ptr);
break;
-#endif
+
default:
/* bit_width was already validated */
break;
@@ -236,11 +234,9 @@ acpi_ex_system_memory_space_handler(u32 function,
ACPI_SET32(logical_addr_ptr) = (u32) * value;
break;
-#if ACPI_MACHINE_WIDTH != 16
case 64:
ACPI_SET64(logical_addr_ptr) = (u64) * value;
break;
-#endif
default:
/* bit_width was already validated */
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
index 3089b05a136..2b3a01cc492 100644
--- a/drivers/acpi/executer/exresnte.c
+++ b/drivers/acpi/executer/exresnte.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
index 6499de87801..6c64e55dab0 100644
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/executer/exresolv.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -141,7 +141,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
acpi_status status = AE_OK;
union acpi_operand_object *stack_desc;
void *temp_node;
- union acpi_operand_object *obj_desc;
+ union acpi_operand_object *obj_desc = NULL;
u16 opcode;
ACPI_FUNCTION_TRACE(ex_resolve_object_to_value);
@@ -299,8 +299,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
status = acpi_ds_get_package_arguments(stack_desc);
break;
- /* These cases may never happen here, but just in case.. */
-
case ACPI_TYPE_BUFFER_FIELD:
case ACPI_TYPE_LOCAL_REGION_FIELD:
case ACPI_TYPE_LOCAL_BANK_FIELD:
@@ -314,6 +312,10 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
status =
acpi_ex_read_data_from_field(walk_state, stack_desc,
&obj_desc);
+
+ /* Remove a reference to the original operand, then override */
+
+ acpi_ut_remove_reference(*stack_ptr);
*stack_ptr = (void *)obj_desc;
break;
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index 4c93d097233..ba761862a59 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -611,22 +611,20 @@ acpi_ex_resolve_operands(u16 opcode,
}
goto next_operand;
- case ARGI_REGION_OR_FIELD:
+ case ARGI_REGION_OR_BUFFER: /* Used by Load() only */
- /* Need an operand of type REGION or a FIELD in a region */
+ /* Need an operand of type REGION or a BUFFER (which could be a resolved region field) */
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
+ case ACPI_TYPE_BUFFER:
case ACPI_TYPE_REGION:
- case ACPI_TYPE_LOCAL_REGION_FIELD:
- case ACPI_TYPE_LOCAL_BANK_FIELD:
- case ACPI_TYPE_LOCAL_INDEX_FIELD:
/* Valid operand */
break;
default:
ACPI_ERROR((AE_INFO,
- "Needed [Region/RegionField], found [%s] %p",
+ "Needed [Region/Buffer], found [%s] %p",
acpi_ut_get_object_type_name
(obj_desc), obj_desc));
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
index 0456405ba01..f4b69a63782 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/executer/exstore.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
index 591aaf0e18b..1d622c625c6 100644
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/executer/exstoren.c
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c
index 99ebe5adfcd..8233d40178e 100644
--- a/drivers/acpi/executer/exstorob.c
+++ b/drivers/acpi/executer/exstorob.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
index 28aef3e69ec..9460baff303 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,6 @@ ACPI_MODULE_NAME("exsystem")
acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
{
acpi_status status;
- acpi_status status2;
ACPI_FUNCTION_TRACE(ex_system_wait_semaphore);
@@ -79,7 +78,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
/* We must wait, so unlock the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = acpi_os_wait_semaphore(semaphore, 1, timeout);
@@ -89,13 +88,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
/* Reacquire the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
-
- /* Report fatal error, could not acquire interpreter */
-
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
@@ -119,7 +112,6 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
{
acpi_status status;
- acpi_status status2;
ACPI_FUNCTION_TRACE(ex_system_wait_mutex);
@@ -132,7 +124,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
/* We must wait, so unlock the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = acpi_os_acquire_mutex(mutex, timeout);
@@ -142,13 +134,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
/* Reacquire the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
-
- /* Report fatal error, could not acquire interpreter */
-
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
@@ -209,96 +195,18 @@ acpi_status acpi_ex_system_do_stall(u32 how_long)
acpi_status acpi_ex_system_do_suspend(acpi_integer how_long)
{
- acpi_status status;
-
ACPI_FUNCTION_ENTRY();
/* Since this thread will sleep, we must release the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
acpi_os_sleep(how_long);
/* And now we must get the interpreter again */
- status = acpi_ex_enter_interpreter();
- return (status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ex_system_acquire_mutex
- *
- * PARAMETERS: time_desc - Maximum time to wait for the mutex
- * obj_desc - The object descriptor for this op
- *
- * RETURN: Status
- *
- * DESCRIPTION: Provides an access point to perform synchronization operations
- * within the AML. This function will cause a lock to be generated
- * for the Mutex pointed to by obj_desc.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ex_system_acquire_mutex(union acpi_operand_object * time_desc,
- union acpi_operand_object * obj_desc)
-{
- acpi_status status = AE_OK;
-
- ACPI_FUNCTION_TRACE_PTR(ex_system_acquire_mutex, obj_desc);
-
- if (!obj_desc) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Support for the _GL_ Mutex object -- go get the global lock */
-
- if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
- status =
- acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
- return_ACPI_STATUS(status);
- }
-
- status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
- (u16) time_desc->integer.value);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ex_system_release_mutex
- *
- * PARAMETERS: obj_desc - The object descriptor for this op
- *
- * RETURN: Status
- *
- * DESCRIPTION: Provides an access point to perform synchronization operations
- * within the AML. This operation is a request to release a
- * previously acquired Mutex. If the Mutex variable is set then
- * it will be decremented.
- *
- ******************************************************************************/
-
-acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc)
-{
- acpi_status status = AE_OK;
-
- ACPI_FUNCTION_TRACE(ex_system_release_mutex);
-
- if (!obj_desc) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Support for the _GL_ Mutex object -- release the global lock */
-
- if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
- status = acpi_ev_release_global_lock();
- return_ACPI_STATUS(status);
- }
-
- acpi_os_release_mutex(obj_desc->mutex.os_mutex);
- return_ACPI_STATUS(AE_OK);
+ acpi_ex_reacquire_interpreter();
+ return (AE_OK);
}
/*******************************************************************************
@@ -314,7 +222,7 @@ acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc)
*
******************************************************************************/
-acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc)
+acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc)
{
acpi_status status = AE_OK;
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
index 982c8b65876..6b0aeccbb69 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/executer/exutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -76,14 +76,15 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base);
*
* PARAMETERS: None
*
- * RETURN: Status
+ * RETURN: None
*
- * DESCRIPTION: Enter the interpreter execution region. Failure to enter
- * the interpreter region is a fatal system error
+ * DESCRIPTION: Enter the interpreter execution region. Failure to enter
+ * the interpreter region is a fatal system error. Used in
+ * conjunction with exit_interpreter.
*
******************************************************************************/
-acpi_status acpi_ex_enter_interpreter(void)
+void acpi_ex_enter_interpreter(void)
{
acpi_status status;
@@ -91,31 +92,55 @@ acpi_status acpi_ex_enter_interpreter(void)
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex"));
+ ACPI_ERROR((AE_INFO,
+ "Could not acquire AML Interpreter mutex"));
}
- return_ACPI_STATUS(status);
+ return_VOID;
}
/*******************************************************************************
*
- * FUNCTION: acpi_ex_exit_interpreter
+ * FUNCTION: acpi_ex_reacquire_interpreter
*
* PARAMETERS: None
*
* RETURN: None
*
- * DESCRIPTION: Exit the interpreter execution region
+ * DESCRIPTION: Reacquire the interpreter execution region from within the
+ * interpreter code. Failure to enter the interpreter region is a
+ * fatal system error. Used in conjuction with
+ * relinquish_interpreter
+ *
+ ******************************************************************************/
+
+void acpi_ex_reacquire_interpreter(void)
+{
+ ACPI_FUNCTION_TRACE(ex_reacquire_interpreter);
+
+ /*
+ * If the global serialized flag is set, do not release the interpreter,
+ * since it was not actually released by acpi_ex_relinquish_interpreter.
+ * This forces the interpreter to be single threaded.
+ */
+ if (!acpi_gbl_all_methods_serialized) {
+ acpi_ex_enter_interpreter();
+ }
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_exit_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
*
- * Cases where the interpreter is unlocked:
- * 1) Completion of the execution of a control method
- * 2) Method blocked on a Sleep() AML opcode
- * 3) Method blocked on an Acquire() AML opcode
- * 4) Method blocked on a Wait() AML opcode
- * 5) Method blocked to acquire the global lock
- * 6) Method blocked to execute a serialized control method that is
- * already executing
- * 7) About to invoke a user-installed opregion handler
+ * DESCRIPTION: Exit the interpreter execution region. This is the top level
+ * routine used to exit the interpreter when all processing has
+ * been completed.
*
******************************************************************************/
@@ -127,7 +152,46 @@ void acpi_ex_exit_interpreter(void)
status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not release interpreter mutex"));
+ ACPI_ERROR((AE_INFO,
+ "Could not release AML Interpreter mutex"));
+ }
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_relinquish_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Exit the interpreter execution region, from within the
+ * interpreter - before attempting an operation that will possibly
+ * block the running thread.
+ *
+ * Cases where the interpreter is unlocked internally
+ * 1) Method to be blocked on a Sleep() AML opcode
+ * 2) Method to be blocked on an Acquire() AML opcode
+ * 3) Method to be blocked on a Wait() AML opcode
+ * 4) Method to be blocked to acquire the global lock
+ * 5) Method to be blocked waiting to execute a serialized control method
+ * that is currently executing
+ * 6) About to invoke a user-installed opregion handler
+ *
+ ******************************************************************************/
+
+void acpi_ex_relinquish_interpreter(void)
+{
+ ACPI_FUNCTION_TRACE(ex_relinquish_interpreter);
+
+ /*
+ * If the global serialized flag is set, do not release the interpreter.
+ * This forces the interpreter to be single threaded.
+ */
+ if (!acpi_gbl_all_methods_serialized) {
+ acpi_ex_exit_interpreter();
}
return_VOID;
@@ -141,8 +205,8 @@ void acpi_ex_exit_interpreter(void)
*
* RETURN: none
*
- * DESCRIPTION: Truncate a number to 32-bits if the currently executing method
- * belongs to a 32-bit ACPI table.
+ * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
+ * 32-bit, as determined by the revision of the DSDT.
*
******************************************************************************/
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 045c89477e5..af22fdf7341 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -48,8 +48,8 @@ MODULE_LICENSE("GPL");
static int acpi_fan_add(struct acpi_device *device);
static int acpi_fan_remove(struct acpi_device *device, int type);
-static int acpi_fan_suspend(struct acpi_device *device, int state);
-static int acpi_fan_resume(struct acpi_device *device, int state);
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
+static int acpi_fan_resume(struct acpi_device *device);
static struct acpi_driver acpi_fan_driver = {
.name = ACPI_FAN_DRIVER_NAME,
@@ -99,8 +99,8 @@ acpi_fan_write_state(struct file *file, const char __user * buffer,
size_t count, loff_t * ppos)
{
int result = 0;
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_fan *fan = (struct acpi_fan *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_fan *fan = m->private;
char state_string[12] = { '\0' };
@@ -186,10 +186,9 @@ static int acpi_fan_add(struct acpi_device *device)
if (!device)
return -EINVAL;
- fan = kmalloc(sizeof(struct acpi_fan), GFP_KERNEL);
+ fan = kzalloc(sizeof(struct acpi_fan), GFP_KERNEL);
if (!fan)
return -ENOMEM;
- memset(fan, 0, sizeof(struct acpi_fan));
fan->device = device;
strcpy(acpi_device_name(device), "Fan");
@@ -229,7 +228,7 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- fan = (struct acpi_fan *)acpi_driver_data(device);
+ fan = acpi_driver_data(device);
acpi_fan_remove_fs(device);
@@ -238,7 +237,7 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
return 0;
}
-static int acpi_fan_suspend(struct acpi_device *device, int state)
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
{
if (!device)
return -EINVAL;
@@ -248,7 +247,7 @@ static int acpi_fan_suspend(struct acpi_device *device, int state)
return AE_OK;
}
-static int acpi_fan_resume(struct acpi_device *device, int state)
+static int acpi_fan_resume(struct acpi_device *device)
{
int result = 0;
int power_state = 0;
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index a2f46d587d5..7b6c9ff9beb 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -86,125 +86,6 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
return ret;
}
-/* Get PCI root bridge's handle from its segment and bus number */
-struct acpi_find_pci_root {
- unsigned int seg;
- unsigned int bus;
- acpi_handle handle;
-};
-
-static acpi_status
-do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
-{
- unsigned long *busnr = (unsigned long *)data;
- struct acpi_resource_address64 address;
-
- if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
- resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
- resource->type != ACPI_RESOURCE_TYPE_ADDRESS64)
- return AE_OK;
-
- acpi_resource_to_address64(resource, &address);
- if ((address.address_length > 0) &&
- (address.resource_type == ACPI_BUS_NUMBER_RANGE))
- *busnr = address.minimum;
-
- return AE_OK;
-}
-
-static int get_root_bridge_busnr(acpi_handle handle)
-{
- acpi_status status;
- unsigned long bus, bbn;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
- status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL,
- &bbn);
- if (status == AE_NOT_FOUND) {
- /* Assume bus = 0 */
- printk(KERN_INFO PREFIX
- "Assume root bridge [%s] bus is 0\n",
- (char *)buffer.pointer);
- status = AE_OK;
- bbn = 0;
- }
- if (ACPI_FAILURE(status)) {
- bbn = -ENODEV;
- goto exit;
- }
- if (bbn > 0)
- goto exit;
-
- /* _BBN in some systems return 0 for all root bridges */
- bus = -1;
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- do_root_bridge_busnr_callback, &bus);
- /* If _CRS failed, we just use _BBN */
- if (ACPI_FAILURE(status) || (bus == -1))
- goto exit;
- /* We select _CRS */
- if (bbn != bus) {
- printk(KERN_INFO PREFIX
- "_BBN and _CRS returns different value for %s. Select _CRS\n",
- (char *)buffer.pointer);
- bbn = bus;
- }
- exit:
- kfree(buffer.pointer);
- return (int)bbn;
-}
-
-static acpi_status
-find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- struct acpi_find_pci_root *find = (struct acpi_find_pci_root *)context;
- unsigned long seg, bus;
- acpi_status status;
- int tmp;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
- status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &seg);
- if (status == AE_NOT_FOUND) {
- /* Assume seg = 0 */
- status = AE_OK;
- seg = 0;
- }
- if (ACPI_FAILURE(status)) {
- status = AE_CTRL_DEPTH;
- goto exit;
- }
-
- tmp = get_root_bridge_busnr(handle);
- if (tmp < 0) {
- printk(KERN_ERR PREFIX
- "Find root bridge failed for %s\n",
- (char *)buffer.pointer);
- status = AE_CTRL_DEPTH;
- goto exit;
- }
- bus = tmp;
-
- if (seg == find->seg && bus == find->bus)
- find->handle = handle;
- status = AE_OK;
- exit:
- kfree(buffer.pointer);
- return status;
-}
-
-acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
-{
- struct acpi_find_pci_root find = { seg, bus, NULL };
-
- acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL);
- return find.handle;
-}
-EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
-
/* Get device's handler per its address under its parent */
struct acpi_find_child {
acpi_handle handle;
@@ -217,7 +98,7 @@ do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv)
acpi_status status;
struct acpi_device_info *info;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- struct acpi_find_child *find = (struct acpi_find_child *)context;
+ struct acpi_find_child *find = context;
status = acpi_get_object_info(handle, &buffer);
if (ACPI_SUCCESS(status)) {
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
index de50fab2a91..6031ca13dd2 100644
--- a/drivers/acpi/hardware/hwacpi.c
+++ b/drivers/acpi/hardware/hwacpi.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,41 +49,6 @@ ACPI_MODULE_NAME("hwacpi")
/******************************************************************************
*
- * FUNCTION: acpi_hw_initialize
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Initialize and validate the various ACPI registers defined in
- * the FADT.
- *
- ******************************************************************************/
-acpi_status acpi_hw_initialize(void)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(hw_initialize);
-
- /* We must have the ACPI tables by the time we get here */
-
- if (!acpi_gbl_FADT) {
- ACPI_ERROR((AE_INFO, "No FADT is present"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /* Sanity check the FADT for valid values */
-
- status = acpi_ut_validate_fadt();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/******************************************************************************
- *
* FUNCTION: acpi_hw_set_mode
*
* PARAMETERS: Mode - SYS_MODE_ACPI or SYS_MODE_LEGACY
@@ -93,7 +58,6 @@ acpi_status acpi_hw_initialize(void)
* DESCRIPTION: Transitions the system into the requested mode.
*
******************************************************************************/
-
acpi_status acpi_hw_set_mode(u32 mode)
{
@@ -106,7 +70,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
* system does not support mode transition.
*/
- if (!acpi_gbl_FADT->smi_cmd) {
+ if (!acpi_gbl_FADT.smi_command) {
ACPI_ERROR((AE_INFO,
"No SMI_CMD in FADT, mode transition failed"));
return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
@@ -119,7 +83,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
* we make sure both the numbers are zero to determine these
* transitions are not supported.
*/
- if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) {
+ if (!acpi_gbl_FADT.acpi_enable && !acpi_gbl_FADT.acpi_disable) {
ACPI_ERROR((AE_INFO,
"No ACPI mode transition supported in this system (enable/disable both zero)"));
return_ACPI_STATUS(AE_OK);
@@ -130,9 +94,8 @@ acpi_status acpi_hw_set_mode(u32 mode)
/* BIOS should have disabled ALL fixed and GP events */
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
- (u32) acpi_gbl_FADT->acpi_enable,
- 8);
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.acpi_enable, 8);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Attempting to enable ACPI mode\n"));
break;
@@ -143,8 +106,8 @@ acpi_status acpi_hw_set_mode(u32 mode)
* BIOS should clear all fixed status bits and restore fixed event
* enable bits to default
*/
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
- (u32) acpi_gbl_FADT->acpi_disable,
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.acpi_disable,
8);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Attempting to enable Legacy (non-ACPI) mode\n"));
@@ -204,12 +167,11 @@ u32 acpi_hw_get_mode(void)
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
* system does not support mode transition.
*/
- if (!acpi_gbl_FADT->smi_cmd) {
+ if (!acpi_gbl_FADT.smi_command) {
return_UINT32(ACPI_SYS_MODE_ACPI);
}
- status =
- acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_LOCK);
+ status = acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value);
if (ACPI_FAILURE(status)) {
return_UINT32(ACPI_SYS_MODE_LEGACY);
}
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 608a3a60ee1..117a05cadaa 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -105,14 +105,20 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info)
acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
{
acpi_status status;
+ u8 register_bit;
ACPI_FUNCTION_ENTRY();
+ register_bit = (u8)
+ (1 <<
+ (gpe_event_info->gpe_number -
+ gpe_event_info->register_info->base_gpe_number));
+
/*
* Write a one to the appropriate bit in the status register to
* clear this GPE.
*/
- status = acpi_hw_low_level_write(8, gpe_event_info->register_bit,
+ status = acpi_hw_low_level_write(8, register_bit,
&gpe_event_info->register_info->
status_address);
@@ -155,7 +161,10 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
/* Get the register bitmask for this GPE */
- register_bit = gpe_event_info->register_bit;
+ register_bit = (u8)
+ (1 <<
+ (gpe_event_info->gpe_number -
+ gpe_event_info->register_info->base_gpe_number));
/* GPE currently enabled? (enabled for runtime?) */
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index fa58c1edce1..1d371fa663f 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -7,7 +7,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,17 +54,15 @@ ACPI_MODULE_NAME("hwregs")
*
* FUNCTION: acpi_hw_clear_acpi_status
*
- * PARAMETERS: Flags - Lock the hardware or not
+ * PARAMETERS: None
*
- * RETURN: none
+ * RETURN: None
*
* DESCRIPTION: Clears all fixed and general purpose status bits
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
*
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
******************************************************************************/
-acpi_status acpi_hw_clear_acpi_status(u32 flags)
+acpi_status acpi_hw_clear_acpi_status(void)
{
acpi_status status;
acpi_cpu_flags lock_flags = 0;
@@ -73,7 +71,7 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags)
ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n",
ACPI_BITMASK_ALL_FIXED_STATUS,
- (u16) acpi_gbl_FADT->xpm1a_evt_blk.address));
+ (u16) acpi_gbl_FADT.xpm1a_event_block.address));
lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
@@ -86,10 +84,10 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags)
/* Clear the fixed events */
- if (acpi_gbl_FADT->xpm1b_evt_blk.address) {
+ if (acpi_gbl_FADT.xpm1b_event_block.address) {
status =
acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS,
- &acpi_gbl_FADT->xpm1b_evt_blk);
+ &acpi_gbl_FADT.xpm1b_event_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -253,18 +251,15 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
*
* PARAMETERS: register_id - ID of ACPI bit_register to access
* return_value - Value that was read from the register
- * Flags - Lock the hardware or not
*
* RETURN: Status and the value read from specified Register. Value
* returned is normalized to bit0 (is shifted all the way right)
*
* DESCRIPTION: ACPI bit_register read function.
*
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
******************************************************************************/
-acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags)
+acpi_status acpi_get_register(u32 register_id, u32 * return_value)
{
u32 register_value = 0;
struct acpi_bit_register_info *bit_reg_info;
@@ -312,16 +307,13 @@ ACPI_EXPORT_SYMBOL(acpi_get_register)
* PARAMETERS: register_id - ID of ACPI bit_register to access
* Value - (only used on write) value to write to the
* Register, NOT pre-normalized to the bit pos
- * Flags - Lock the hardware or not
*
* RETURN: Status
*
* DESCRIPTION: ACPI Bit Register write function.
*
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
******************************************************************************/
-acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
+acpi_status acpi_set_register(u32 register_id, u32 value)
{
u32 register_value = 0;
struct acpi_bit_register_info *bit_reg_info;
@@ -422,8 +414,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"PM2 control: Read %X from %8.8X%8.8X\n",
register_value,
- ACPI_FORMAT_UINT64(acpi_gbl_FADT->
- xpm2_cnt_blk.address)));
+ ACPI_FORMAT_UINT64(acpi_gbl_FADT.
+ xpm2_control_block.
+ address)));
ACPI_REGISTER_INSERT_VALUE(register_value,
bit_reg_info->bit_position,
@@ -433,8 +426,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"About to write %4.4X to %8.8X%8.8X\n",
register_value,
- ACPI_FORMAT_UINT64(acpi_gbl_FADT->
- xpm2_cnt_blk.address)));
+ ACPI_FORMAT_UINT64(acpi_gbl_FADT.
+ xpm2_control_block.
+ address)));
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
ACPI_REGISTER_PM2_CONTROL,
@@ -495,7 +489,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(16, &value1,
- &acpi_gbl_FADT->xpm1a_evt_blk);
+ &acpi_gbl_FADT.xpm1a_event_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -504,7 +498,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(16, &value2,
- &acpi_gbl_FADT->xpm1b_evt_blk);
+ &acpi_gbl_FADT.xpm1b_event_block);
value1 |= value2;
break;
@@ -527,14 +521,14 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(16, &value1,
- &acpi_gbl_FADT->xpm1a_cnt_blk);
+ &acpi_gbl_FADT.xpm1a_control_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
status =
acpi_hw_low_level_read(16, &value2,
- &acpi_gbl_FADT->xpm1b_cnt_blk);
+ &acpi_gbl_FADT.xpm1b_control_block);
value1 |= value2;
break;
@@ -542,19 +536,20 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(8, &value1,
- &acpi_gbl_FADT->xpm2_cnt_blk);
+ &acpi_gbl_FADT.xpm2_control_block);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
status =
acpi_hw_low_level_read(32, &value1,
- &acpi_gbl_FADT->xpm_tmr_blk);
+ &acpi_gbl_FADT.xpm_timer_block);
break;
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
- status = acpi_os_read_port(acpi_gbl_FADT->smi_cmd, &value1, 8);
+ status =
+ acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8);
break;
default:
@@ -635,7 +630,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1a_evt_blk);
+ &acpi_gbl_FADT.xpm1a_event_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -644,7 +639,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1b_evt_blk);
+ &acpi_gbl_FADT.xpm1b_event_block);
break;
case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
@@ -682,49 +677,50 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1a_cnt_blk);
+ &acpi_gbl_FADT.xpm1a_control_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1b_cnt_blk);
+ &acpi_gbl_FADT.xpm1b_control_block);
break;
case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1a_cnt_blk);
+ &acpi_gbl_FADT.xpm1a_control_block);
break;
case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1b_cnt_blk);
+ &acpi_gbl_FADT.xpm1b_control_block);
break;
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
status =
acpi_hw_low_level_write(8, value,
- &acpi_gbl_FADT->xpm2_cnt_blk);
+ &acpi_gbl_FADT.xpm2_control_block);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
status =
acpi_hw_low_level_write(32, value,
- &acpi_gbl_FADT->xpm_tmr_blk);
+ &acpi_gbl_FADT.xpm_timer_block);
break;
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
/* SMI_CMD is currently always in IO space */
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, value, 8);
+ status =
+ acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8);
break;
default:
@@ -783,7 +779,7 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
* Two address spaces supported: Memory or IO.
* PCI_Config is not supported here because the GAS struct is insufficient
*/
- switch (reg->address_space_id) {
+ switch (reg->space_id) {
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
status = acpi_os_read_memory((acpi_physical_address) address,
@@ -792,22 +788,20 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
case ACPI_ADR_SPACE_SYSTEM_IO:
- status = acpi_os_read_port((acpi_io_address) address,
- value, width);
+ status =
+ acpi_os_read_port((acpi_io_address) address, value, width);
break;
default:
ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X",
- reg->address_space_id));
+ "Unsupported address space: %X", reg->space_id));
return (AE_BAD_PARAMETER);
}
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
- *value, width,
- ACPI_FORMAT_UINT64(address),
- acpi_ut_get_region_name(reg->address_space_id)));
+ *value, width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
return (status);
}
@@ -854,7 +848,7 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
* Two address spaces supported: Memory or IO.
* PCI_Config is not supported here because the GAS struct is insufficient
*/
- switch (reg->address_space_id) {
+ switch (reg->space_id) {
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
status = acpi_os_write_memory((acpi_physical_address) address,
@@ -863,22 +857,20 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
case ACPI_ADR_SPACE_SYSTEM_IO:
- status = acpi_os_write_port((acpi_io_address) address,
- value, width);
+ status = acpi_os_write_port((acpi_io_address) address, value,
+ width);
break;
default:
ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X",
- reg->address_space_id));
+ "Unsupported address space: %X", reg->space_id));
return (AE_BAD_PARAMETER);
}
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
- value, width,
- ACPI_FORMAT_UINT64(address),
- acpi_ut_get_region_name(reg->address_space_id)));
+ value, width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
return (status);
}
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 8bb43cae60c..57901ca3ade 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,7 @@
*/
#include <acpi/acpi.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME("hwsleep")
@@ -62,17 +63,32 @@ ACPI_MODULE_NAME("hwsleep")
acpi_status
acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
{
+ struct acpi_table_facs *facs;
+ acpi_status status;
ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
+ /* Get the FACS */
+
+ status =
+ acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ (struct acpi_table_header **)&facs);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Set the vector */
- if (acpi_gbl_common_fACS.vector_width == 32) {
- *(ACPI_CAST_PTR
- (u32, acpi_gbl_common_fACS.firmware_waking_vector))
- = (u32) physical_address;
+ if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
+ /*
+ * ACPI 1.0 FACS or short table or optional X_ field is zero
+ */
+ facs->firmware_waking_vector = (u32) physical_address;
} else {
- *acpi_gbl_common_fACS.firmware_waking_vector = physical_address;
+ /*
+ * ACPI 2.0 FACS with valid X_ field
+ */
+ facs->xfirmware_waking_vector = physical_address;
}
return_ACPI_STATUS(AE_OK);
@@ -97,6 +113,8 @@ ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
acpi_status
acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
{
+ struct acpi_table_facs *facs;
+ acpi_status status;
ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector);
@@ -104,16 +122,29 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
+ /* Get the FACS */
+
+ status =
+ acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ (struct acpi_table_header **)&facs);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Get the vector */
- if (acpi_gbl_common_fACS.vector_width == 32) {
- *physical_address = (acpi_physical_address)
- *
- (ACPI_CAST_PTR
- (u32, acpi_gbl_common_fACS.firmware_waking_vector));
+ if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
+ /*
+ * ACPI 1.0 FACS or short table or optional X_ field is zero
+ */
+ *physical_address =
+ (acpi_physical_address) facs->firmware_waking_vector;
} else {
+ /*
+ * ACPI 2.0 FACS with valid X_ field
+ */
*physical_address =
- *acpi_gbl_common_fACS.firmware_waking_vector;
+ (acpi_physical_address) facs->xfirmware_waking_vector;
}
return_ACPI_STATUS(AE_OK);
@@ -246,15 +277,14 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
/* Clear wake status */
- status =
- acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/* Clear all fixed and general purpose status bits */
- status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_hw_clear_acpi_status();
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -367,8 +397,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
/* Wait until we enter sleep state */
do {
- status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
- ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -401,13 +430,12 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
- status =
- acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_hw_clear_acpi_status();
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -429,13 +457,12 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
ACPI_FLUSH_CPU_CACHE();
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
- (u32) acpi_gbl_FADT->S4bios_req, 8);
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.S4bios_request, 8);
do {
acpi_os_stall(1000);
- status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
- ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -568,13 +595,11 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
(void)
acpi_set_register(acpi_gbl_fixed_event_info
- [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1);
(void)
acpi_set_register(acpi_gbl_fixed_event_info
- [ACPI_EVENT_POWER_BUTTON].status_register_id, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ [ACPI_EVENT_POWER_BUTTON].status_register_id, 1);
arg.integer.value = ACPI_SST_WORKING;
status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c
index c4ec47c939f..c32eab696ac 100644
--- a/drivers/acpi/hardware/hwtimer.c
+++ b/drivers/acpi/hardware/hwtimer.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,7 @@ acpi_status acpi_get_timer_resolution(u32 * resolution)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- if (acpi_gbl_FADT->tmr_val_ext == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {
*resolution = 24;
} else {
*resolution = 32;
@@ -98,7 +98,8 @@ acpi_status acpi_get_timer(u32 * ticks)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- status = acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT->xpm_tmr_blk);
+ status =
+ acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT.xpm_timer_block);
return_ACPI_STATUS(status);
}
@@ -153,7 +154,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
if (start_ticks < end_ticks) {
delta_ticks = end_ticks - start_ticks;
} else if (start_ticks > end_ticks) {
- if (acpi_gbl_FADT->tmr_val_ext == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {
/* 24-bit Timer */
diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c
index 1ba2db67186..8edfb92f7ed 100644
--- a/drivers/acpi/hotkey.c
+++ b/drivers/acpi/hotkey.c
@@ -265,8 +265,7 @@ static char *format_result(union acpi_object *object)
static int hotkey_polling_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_polling_hotkey *poll_hotkey =
- (struct acpi_polling_hotkey *)seq->private;
+ struct acpi_polling_hotkey *poll_hotkey = seq->private;
char *buf;
@@ -577,7 +576,7 @@ init_poll_hotkey_device(union acpi_hotkey *key, char **config_entry,
if (ACPI_FAILURE(status))
goto do_fail_zero;
key->poll_hotkey.poll_result =
- (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL);
+ kmalloc(sizeof(union acpi_object), GFP_KERNEL);
if (!key->poll_hotkey.poll_result)
goto do_fail_zero;
return AE_OK;
diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c
index 6342e612c20..8338be0990b 100644
--- a/drivers/acpi/i2c_ec.c
+++ b/drivers/acpi/i2c_ec.c
@@ -309,18 +309,16 @@ static int acpi_ec_hc_add(struct acpi_device *device)
return -EINVAL;
}
- ec_hc = kmalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
+ ec_hc = kzalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
if (!ec_hc) {
return -ENOMEM;
}
- memset(ec_hc, 0, sizeof(struct acpi_ec_hc));
- smbus = kmalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
+ smbus = kzalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
if (!smbus) {
kfree(ec_hc);
return -ENOMEM;
}
- memset(smbus, 0, sizeof(struct acpi_ec_smbus));
ec_hc->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME);
@@ -393,7 +391,7 @@ static void __exit acpi_ec_hc_exit(void)
struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device)
{
- return ((struct acpi_ec_hc *)acpi_driver_data(device->parent));
+ return acpi_driver_data(device->parent);
}
EXPORT_SYMBOL(acpi_get_ec_hc);
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index 003a9876c96..c6144ca6663 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -3,6 +3,7 @@
*
*
* Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
+ * Copyright (C) 2006 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,10 +20,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define IBM_VERSION "0.12a"
+#define IBM_VERSION "0.13"
/*
* Changelog:
+ *
+ * 2006-11-22 0.13 new maintainer
+ * changelog now lives in git commit history, and will
+ * not be updated further in-file.
*
* 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
* 2005-03-17 0.11 support for 600e, 770x
@@ -77,9 +82,16 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/string.h>
+
#include <linux/proc_fs.h>
+#include <linux/backlight.h>
#include <asm/uaccess.h>
+#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+
#include <acpi/acpi_drivers.h>
#include <acpi/acnamesp.h>
@@ -88,7 +100,7 @@
#define IBM_FILE "ibm_acpi"
#define IBM_URL "http://ibm-acpi.sf.net/"
-MODULE_AUTHOR("Borislav Deianov");
+MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
MODULE_DESCRIPTION(IBM_DESC);
MODULE_VERSION(IBM_VERSION);
MODULE_LICENSE("GPL");
@@ -116,28 +128,6 @@ static acpi_handle root_handle = NULL;
static char *object##_path; \
static char *object##_paths[] = { paths }
-/*
- * The following models are supported to various degrees:
- *
- * 570, 600e, 600x, 770e, 770x
- * A20m, A21e, A21m, A21p, A22p, A30, A30p, A31, A31p
- * G40, G41
- * R30, R31, R32, R40, R40e, R50, R50e, R50p, R51
- * T20, T21, T22, T23, T30, T40, T40p, T41, T41p, T42, T42p, T43
- * X20, X21, X22, X23, X24, X30, X31, X40
- *
- * The following models have no supported features:
- *
- * 240, 240x, i1400
- *
- * Still missing DSDTs for the following models:
- *
- * A20p, A22e, A22m
- * R52
- * S31
- * T43p
- */
-
IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
"\\_SB.PCI.ISA.EC", /* 570 */
"\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
@@ -169,6 +159,7 @@ IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
#endif
IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
"\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
+ "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
"\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
); /* A21e, R30, R31 */
@@ -203,7 +194,7 @@ IBM_HANDLE(led, ec, "SLED", /* 570 */
IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
-IBM_HANDLE(fans, ec, "FANS"); /* X31, X40 */
+IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
"\\FSPD", /* 600e/x, 770e, 770x */
@@ -216,6 +207,152 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
#define IBM_HKEY_HID "IBM0068"
#define IBM_PCI_HID "PNP0A03"
+enum thermal_access_mode {
+ IBMACPI_THERMAL_NONE = 0, /* No thermal support */
+ IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
+ IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
+ IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
+ IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
+};
+
+#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
+struct ibm_thermal_sensors_struct {
+ s32 temp[IBMACPI_MAX_THERMAL_SENSORS];
+};
+
+/*
+ * FAN ACCESS MODES
+ *
+ * IBMACPI_FAN_RD_ACPI_GFAN:
+ * ACPI GFAN method: returns fan level
+ *
+ * see IBMACPI_FAN_WR_ACPI_SFAN
+ * EC 0x2f not available if GFAN exists
+ *
+ * IBMACPI_FAN_WR_ACPI_SFAN:
+ * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
+ *
+ * EC 0x2f might be available *for reading*, but never for writing.
+ *
+ * IBMACPI_FAN_WR_TPEC:
+ * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
+ * on almost all ThinkPads
+ *
+ * Fan speed changes of any sort (including those caused by the
+ * disengaged mode) are usually done slowly by the firmware as the
+ * maximum ammount of fan duty cycle change per second seems to be
+ * limited.
+ *
+ * Reading is not available if GFAN exists.
+ * Writing is not available if SFAN exists.
+ *
+ * Bits
+ * 7 automatic mode engaged;
+ * (default operation mode of the ThinkPad)
+ * fan level is ignored in this mode.
+ * 6 disengage mode (takes precedence over bit 7);
+ * not available on all thinkpads. May disable
+ * the tachometer, and speeds up fan to 100% duty-cycle,
+ * which speeds it up far above the standard RPM
+ * levels. It is not impossible that it could cause
+ * hardware damage.
+ * 5-3 unused in some models. Extra bits for fan level
+ * in others, but still useless as all values above
+ * 7 map to the same speed as level 7 in these models.
+ * 2-0 fan level (0..7 usually)
+ * 0x00 = stop
+ * 0x07 = max (set when temperatures critical)
+ * Some ThinkPads may have other levels, see
+ * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
+ *
+ * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
+ * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
+ * does so, its initial value is meaningless (0x07).
+ *
+ * For firmware bugs, refer to:
+ * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * ----
+ *
+ * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
+ * Main fan tachometer reading (in RPM)
+ *
+ * This register is present on all ThinkPads with a new-style EC, and
+ * it is known not to be present on the A21m/e, and T22, as there is
+ * something else in offset 0x84 according to the ACPI DSDT. Other
+ * ThinkPads from this same time period (and earlier) probably lack the
+ * tachometer as well.
+ *
+ * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
+ * was never fixed by IBM to report the EC firmware version string
+ * probably support the tachometer (like the early X models), so
+ * detecting it is quite hard. We need more data to know for sure.
+ *
+ * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
+ * might result.
+ *
+ * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
+ * register is not invalidated in ThinkPads that disable tachometer
+ * readings. Thus, the tachometer readings go stale.
+ *
+ * For firmware bugs, refer to:
+ * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * IBMACPI_FAN_WR_ACPI_FANS:
+ * ThinkPad X31, X40, X41. Not available in the X60.
+ *
+ * FANS ACPI handle: takes three arguments: low speed, medium speed,
+ * high speed. ACPI DSDT seems to map these three speeds to levels
+ * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
+ * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
+ *
+ * The speeds are stored on handles
+ * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
+ *
+ * There are three default speed sets, acessible as handles:
+ * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
+ *
+ * ACPI DSDT switches which set is in use depending on various
+ * factors.
+ *
+ * IBMACPI_FAN_WR_TPEC is also available and should be used to
+ * command the fan. The X31/X40/X41 seems to have 8 fan levels,
+ * but the ACPI tables just mention level 7.
+ */
+
+enum fan_status_access_mode {
+ IBMACPI_FAN_NONE = 0, /* No fan status or control */
+ IBMACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
+ IBMACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
+};
+
+enum fan_control_access_mode {
+ IBMACPI_FAN_WR_NONE = 0, /* No fan control */
+ IBMACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
+ IBMACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
+ IBMACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
+};
+
+enum fan_control_commands {
+ IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
+ IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
+ IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
+ * and also watchdog cmd */
+};
+
+enum { /* Fan control constants */
+ fan_status_offset = 0x2f, /* EC register 0x2f */
+ fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
+ * 0x84 must be read before 0x85 */
+
+ IBMACPI_FAN_EC_DISENGAGED = 0x40, /* EC mode: tachometer
+ * disengaged */
+ IBMACPI_FAN_EC_AUTO = 0x80, /* EC mode: auto fan
+ * control */
+};
+
+static char *ibm_thinkpad_ec_found = NULL;
+
struct ibm_struct {
char *name;
char param[32];
@@ -243,6 +380,8 @@ struct ibm_struct {
static struct proc_dir_entry *proc_dir = NULL;
+static struct backlight_device *ibm_backlight_device = NULL;
+
#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -352,7 +491,7 @@ static char *next_cmd(char **cmds)
return start;
}
-static int driver_init(void)
+static int ibm_acpi_driver_init(void)
{
printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
printk(IBM_INFO "%s\n", IBM_URL);
@@ -581,8 +720,7 @@ static int wan_status(void)
{
int status;
- if (!wan_supported ||
- !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+ if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
status = 0;
return status;
@@ -630,12 +768,15 @@ static int wan_write(char *buf)
return 0;
}
-static int video_supported;
-static int video_orig_autosw;
+enum video_access_mode {
+ IBMACPI_VIDEO_NONE = 0,
+ IBMACPI_VIDEO_570, /* 570 */
+ IBMACPI_VIDEO_770, /* 600e/x, 770e, 770x */
+ IBMACPI_VIDEO_NEW, /* all others */
+};
-#define VIDEO_570 1
-#define VIDEO_770 2
-#define VIDEO_NEW 3
+static enum video_access_mode video_supported;
+static int video_orig_autosw;
static int video_init(void)
{
@@ -647,16 +788,16 @@ static int video_init(void)
if (!vid_handle)
/* video switching not supported on R30, R31 */
- video_supported = 0;
+ video_supported = IBMACPI_VIDEO_NONE;
else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
/* 570 */
- video_supported = VIDEO_570;
+ video_supported = IBMACPI_VIDEO_570;
else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
/* 600e/x, 770e, 770x */
- video_supported = VIDEO_770;
+ video_supported = IBMACPI_VIDEO_770;
else
/* all others */
- video_supported = VIDEO_NEW;
+ video_supported = IBMACPI_VIDEO_NEW;
return 0;
}
@@ -666,15 +807,15 @@ static int video_status(void)
int status = 0;
int i;
- if (video_supported == VIDEO_570) {
+ if (video_supported == IBMACPI_VIDEO_570) {
if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
status = i & 3;
- } else if (video_supported == VIDEO_770) {
+ } else if (video_supported == IBMACPI_VIDEO_770) {
if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
status |= 0x01 * i;
if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
status |= 0x02 * i;
- } else if (video_supported == VIDEO_NEW) {
+ } else if (video_supported == IBMACPI_VIDEO_NEW) {
acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
status |= 0x02 * i;
@@ -693,9 +834,10 @@ static int video_autosw(void)
{
int autosw = 0;
- if (video_supported == VIDEO_570)
+ if (video_supported == IBMACPI_VIDEO_570)
acpi_evalf(vid_handle, &autosw, "SWIT", "d");
- else if (video_supported == VIDEO_770 || video_supported == VIDEO_NEW)
+ else if (video_supported == IBMACPI_VIDEO_770 ||
+ video_supported == IBMACPI_VIDEO_NEW)
acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
return autosw & 1;
@@ -715,12 +857,12 @@ static int video_read(char *p)
len += sprintf(p + len, "status:\t\tsupported\n");
len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
- if (video_supported == VIDEO_NEW)
+ if (video_supported == IBMACPI_VIDEO_NEW)
len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
- if (video_supported == VIDEO_NEW)
+ if (video_supported == IBMACPI_VIDEO_NEW)
len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
@@ -735,7 +877,7 @@ static int video_switch(void)
if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
return -EIO;
- ret = video_supported == VIDEO_570 ?
+ ret = video_supported == IBMACPI_VIDEO_570 ?
acpi_evalf(ec_handle, NULL, "_Q16", "v") :
acpi_evalf(vid_handle, NULL, "VSWT", "v");
acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
@@ -745,9 +887,9 @@ static int video_switch(void)
static int video_expand(void)
{
- if (video_supported == VIDEO_570)
+ if (video_supported == IBMACPI_VIDEO_570)
return acpi_evalf(ec_handle, NULL, "_Q17", "v");
- else if (video_supported == VIDEO_770)
+ else if (video_supported == IBMACPI_VIDEO_770)
return acpi_evalf(vid_handle, NULL, "VEXP", "v");
else
return acpi_evalf(NULL, NULL, "\\VEXP", "v");
@@ -757,10 +899,10 @@ static int video_switch2(int status)
{
int ret;
- if (video_supported == VIDEO_570) {
+ if (video_supported == IBMACPI_VIDEO_570) {
ret = acpi_evalf(NULL, NULL,
"\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
- } else if (video_supported == VIDEO_770) {
+ } else if (video_supported == IBMACPI_VIDEO_770) {
int autosw = video_autosw();
if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
return -EIO;
@@ -796,10 +938,10 @@ static int video_write(char *buf)
enable |= 0x02;
} else if (strlencmp(cmd, "crt_disable") == 0) {
disable |= 0x02;
- } else if (video_supported == VIDEO_NEW &&
+ } else if (video_supported == IBMACPI_VIDEO_NEW &&
strlencmp(cmd, "dvi_enable") == 0) {
enable |= 0x08;
- } else if (video_supported == VIDEO_NEW &&
+ } else if (video_supported == IBMACPI_VIDEO_NEW &&
strlencmp(cmd, "dvi_disable") == 0) {
disable |= 0x08;
} else if (strlencmp(cmd, "auto_enable") == 0) {
@@ -907,6 +1049,7 @@ static int _sta(acpi_handle handle)
return status;
}
+
#ifdef CONFIG_ACPI_IBM_DOCK
#define dock_docked() (_sta(dock_handle) & 1)
@@ -1094,26 +1237,28 @@ static int cmos_write(char *buf)
return 0;
}
-static int led_supported;
-
-#define LED_570 1
-#define LED_OLD 2
-#define LED_NEW 3
+enum led_access_mode {
+ IBMACPI_LED_NONE = 0,
+ IBMACPI_LED_570, /* 570 */
+ IBMACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+ IBMACPI_LED_NEW, /* all others */
+};
+static enum led_access_mode led_supported;
static int led_init(void)
{
if (!led_handle)
/* led not supported on R30, R31 */
- led_supported = 0;
+ led_supported = IBMACPI_LED_NONE;
else if (strlencmp(led_path, "SLED") == 0)
/* 570 */
- led_supported = LED_570;
+ led_supported = IBMACPI_LED_570;
else if (strlencmp(led_path, "SYSL") == 0)
/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
- led_supported = LED_OLD;
+ led_supported = IBMACPI_LED_OLD;
else
/* all others */
- led_supported = LED_NEW;
+ led_supported = IBMACPI_LED_NEW;
return 0;
}
@@ -1130,7 +1275,7 @@ static int led_read(char *p)
}
len += sprintf(p + len, "status:\t\tsupported\n");
- if (led_supported == LED_570) {
+ if (led_supported == IBMACPI_LED_570) {
/* 570 */
int i, status;
for (i = 0; i < 8; i++) {
@@ -1179,13 +1324,13 @@ static int led_write(char *buf)
} else
return -EINVAL;
- if (led_supported == LED_570) {
+ if (led_supported == IBMACPI_LED_570) {
/* 570 */
led = 1 << led;
if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
led, led_sled_arg1[ind]))
return -EIO;
- } else if (led_supported == LED_OLD) {
+ } else if (led_supported == IBMACPI_LED_OLD) {
/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
led = 1 << led;
ret = ec_write(EC_HLMS, led);
@@ -1272,50 +1417,142 @@ static int acpi_ec_write(int i, u8 v)
return 1;
}
-static int thermal_tmp_supported;
-static int thermal_updt_supported;
+static enum thermal_access_mode thermal_read_mode;
static int thermal_init(void)
{
- /* temperatures not supported on 570, G4x, R30, R31, R32 */
- thermal_tmp_supported = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
+ u8 t, ta1, ta2;
+ int i;
+ int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
+
+ if (ibm_thinkpad_ec_found && experimental) {
+ /*
+ * Direct EC access mode: sensors at registers
+ * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
+ * non-implemented, thermal sensors return 0x80 when
+ * not available
+ */
- /* 600e/x, 770e, 770x */
- thermal_updt_supported = acpi_evalf(ec_handle, NULL, "UPDT", "qv");
+ ta1 = ta2 = 0;
+ for (i = 0; i < 8; i++) {
+ if (likely(acpi_ec_read(0x78 + i, &t))) {
+ ta1 |= t;
+ } else {
+ ta1 = 0;
+ break;
+ }
+ if (likely(acpi_ec_read(0xC0 + i, &t))) {
+ ta2 |= t;
+ } else {
+ ta1 = 0;
+ break;
+ }
+ }
+ if (ta1 == 0) {
+ /* This is sheer paranoia, but we handle it anyway */
+ if (acpi_tmp7) {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "falling back to ACPI TMPx access mode\n");
+ thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
+ } else {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "disabling thermal sensors access\n");
+ thermal_read_mode = IBMACPI_THERMAL_NONE;
+ }
+ } else {
+ thermal_read_mode =
+ (ta2 != 0) ?
+ IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8;
+ }
+ } else if (acpi_tmp7) {
+ if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
+ /* 600e/x, 770e, 770x */
+ thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT;
+ } else {
+ /* Standard ACPI TMPx access, max 8 sensors */
+ thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
+ }
+ } else {
+ /* temperatures not supported on 570, G4x, R30, R31, R32 */
+ thermal_read_mode = IBMACPI_THERMAL_NONE;
+ }
return 0;
}
-static int thermal_read(char *p)
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
{
- int len = 0;
+ int i, t;
+ s8 tmp;
+ char tmpi[] = "TMPi";
- if (!thermal_tmp_supported)
- len += sprintf(p + len, "temperatures:\tnot supported\n");
- else {
- int i, t;
- char tmpi[] = "TMPi";
- s8 tmp[8];
+ if (!s)
+ return -EINVAL;
- if (thermal_updt_supported)
- if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
+ switch (thermal_read_mode) {
+#if IBMACPI_MAX_THERMAL_SENSORS >= 16
+ case IBMACPI_THERMAL_TPEC_16:
+ for (i = 0; i < 8; i++) {
+ if (!acpi_ec_read(0xC0 + i, &tmp))
+ return -EIO;
+ s->temp[i + 8] = tmp * 1000;
+ }
+ /* fallthrough */
+#endif
+ case IBMACPI_THERMAL_TPEC_8:
+ for (i = 0; i < 8; i++) {
+ if (!acpi_ec_read(0x78 + i, &tmp))
return -EIO;
+ s->temp[i] = tmp * 1000;
+ }
+ return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8;
+ case IBMACPI_THERMAL_ACPI_UPDT:
+ if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
+ return -EIO;
for (i = 0; i < 8; i++) {
tmpi[3] = '0' + i;
if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
return -EIO;
- if (thermal_updt_supported)
- tmp[i] = (t - 2732 + 5) / 10;
- else
- tmp[i] = t;
+ s->temp[i] = (t - 2732) * 100;
}
+ return 8;
- len += sprintf(p + len,
- "temperatures:\t%d %d %d %d %d %d %d %d\n",
- tmp[0], tmp[1], tmp[2], tmp[3],
- tmp[4], tmp[5], tmp[6], tmp[7]);
+ case IBMACPI_THERMAL_ACPI_TMP07:
+ for (i = 0; i < 8; i++) {
+ tmpi[3] = '0' + i;
+ if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+ return -EIO;
+ s->temp[i] = t * 1000;
+ }
+ return 8;
+
+ case IBMACPI_THERMAL_NONE:
+ default:
+ return 0;
}
+}
+
+static int thermal_read(char *p)
+{
+ int len = 0;
+ int n, i;
+ struct ibm_thermal_sensors_struct t;
+
+ n = thermal_get_sensors(&t);
+ if (unlikely(n < 0))
+ return n;
+
+ len += sprintf(p + len, "temperatures:\t");
+
+ if (n > 0) {
+ for (i = 0; i < (n - 1); i++)
+ len += sprintf(p + len, "%d ", t.temp[i] / 1000);
+ len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
+ } else
+ len += sprintf(p + len, "not supported\n");
return len;
}
@@ -1381,12 +1618,23 @@ static int ecdump_write(char *buf)
static int brightness_offset = 0x31;
+static int brightness_get(struct backlight_device *bd)
+{
+ u8 level;
+ if (!acpi_ec_read(brightness_offset, &level))
+ return -EIO;
+
+ level &= 0x7;
+
+ return level;
+}
+
static int brightness_read(char *p)
{
int len = 0;
- u8 level;
+ int level;
- if (!acpi_ec_read(brightness_offset, &level)) {
+ if ((level = brightness_get(NULL)) < 0) {
len += sprintf(p + len, "level:\t\tunreadable\n");
} else {
len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
@@ -1401,16 +1649,34 @@ static int brightness_read(char *p)
#define BRIGHTNESS_UP 4
#define BRIGHTNESS_DOWN 5
-static int brightness_write(char *buf)
+static int brightness_set(int value)
{
int cmos_cmd, inc, i;
- u8 level;
+ int current_value = brightness_get(NULL);
+
+ value &= 7;
+
+ cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
+ inc = value > current_value ? 1 : -1;
+ for (i = current_value; i != value; i += inc) {
+ if (!cmos_eval(cmos_cmd))
+ return -EIO;
+ if (!acpi_ec_write(brightness_offset, i + inc))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int brightness_write(char *buf)
+{
+ int level;
int new_level;
char *cmd;
while ((cmd = next_cmd(&buf))) {
- if (!acpi_ec_read(brightness_offset, &level))
- return -EIO;
+ if ((level = brightness_get(NULL)) < 0)
+ return level;
level &= 7;
if (strlencmp(cmd, "up") == 0) {
@@ -1423,19 +1689,44 @@ static int brightness_write(char *buf)
} else
return -EINVAL;
- cmos_cmd = new_level > level ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
- inc = new_level > level ? 1 : -1;
- for (i = level; i != new_level; i += inc) {
- if (!cmos_eval(cmos_cmd))
- return -EIO;
- if (!acpi_ec_write(brightness_offset, i + inc))
- return -EIO;
- }
+ brightness_set(new_level);
+ }
+
+ return 0;
+}
+
+static int brightness_update_status(struct backlight_device *bd)
+{
+ return brightness_set(bd->props->brightness);
+}
+
+static struct backlight_properties ibm_backlight_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = brightness_get,
+ .update_status = brightness_update_status,
+ .max_brightness = 7,
+};
+
+static int brightness_init(void)
+{
+ ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
+ &ibm_backlight_data);
+ if (IS_ERR(ibm_backlight_device)) {
+ printk(IBM_ERR "Could not register backlight device\n");
+ return PTR_ERR(ibm_backlight_device);
}
return 0;
}
+static void brightness_exit(void)
+{
+ if (ibm_backlight_device) {
+ backlight_device_unregister(ibm_backlight_device);
+ ibm_backlight_device = NULL;
+ }
+}
+
static int volume_offset = 0x30;
static int volume_read(char *p)
@@ -1522,90 +1813,486 @@ static int volume_write(char *buf)
return 0;
}
-static int fan_status_offset = 0x2f;
-static int fan_rpm_offset = 0x84;
+static enum fan_status_access_mode fan_status_access_mode;
+static enum fan_control_access_mode fan_control_access_mode;
+static enum fan_control_commands fan_control_commands;
-static int fan_read(char *p)
+static int fan_control_status_known;
+static u8 fan_control_initial_status;
+
+static void fan_watchdog_fire(struct work_struct *ignored);
+static int fan_watchdog_maxinterval;
+static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
+
+static int fan_init(void)
{
- int len = 0;
- int s;
- u8 lo, hi, status;
+ fan_status_access_mode = IBMACPI_FAN_NONE;
+ fan_control_access_mode = IBMACPI_FAN_WR_NONE;
+ fan_control_commands = 0;
+ fan_control_status_known = 1;
+ fan_watchdog_maxinterval = 0;
if (gfan_handle) {
/* 570, 600e/x, 770e, 770x */
- if (!acpi_evalf(gfan_handle, &s, NULL, "d"))
- return -EIO;
+ fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN;
+ } else {
+ /* all other ThinkPads: note that even old-style
+ * ThinkPad ECs supports the fan control register */
+ if (likely(acpi_ec_read(fan_status_offset,
+ &fan_control_initial_status))) {
+ fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
+
+ /* In some ThinkPads, neither the EC nor the ACPI
+ * DSDT initialize the fan status, and it ends up
+ * being set to 0x07 when it *could* be either
+ * 0x07 or 0x80.
+ *
+ * Enable for TP-1Y (T43), TP-78 (R51e),
+ * TP-76 (R52), TP-70 (T43, R52), which are known
+ * to be buggy. */
+ if (fan_control_initial_status == 0x07 &&
+ ibm_thinkpad_ec_found &&
+ ((ibm_thinkpad_ec_found[0] == '1' &&
+ ibm_thinkpad_ec_found[1] == 'Y') ||
+ (ibm_thinkpad_ec_found[0] == '7' &&
+ (ibm_thinkpad_ec_found[1] == '6' ||
+ ibm_thinkpad_ec_found[1] == '8' ||
+ ibm_thinkpad_ec_found[1] == '0'))
+ )) {
+ printk(IBM_NOTICE
+ "fan_init: initial fan status is "
+ "unknown, assuming it is in auto "
+ "mode\n");
+ fan_control_status_known = 0;
+ }
+ } else {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "fan status and control unavailable\n");
+ return 0;
+ }
+ }
- len += sprintf(p + len, "level:\t\t%d\n", s);
+ if (sfan_handle) {
+ /* 570, 770x-JL */
+ fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN;
+ fan_control_commands |=
+ IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE;
} else {
+ if (!gfan_handle) {
+ /* gfan without sfan means no fan control */
+ /* all other models implement TP EC 0x2f control */
+
+ if (fans_handle) {
+ /* X31, X40, X41 */
+ fan_control_access_mode =
+ IBMACPI_FAN_WR_ACPI_FANS;
+ fan_control_commands |=
+ IBMACPI_FAN_CMD_SPEED |
+ IBMACPI_FAN_CMD_LEVEL |
+ IBMACPI_FAN_CMD_ENABLE;
+ } else {
+ fan_control_access_mode = IBMACPI_FAN_WR_TPEC;
+ fan_control_commands |=
+ IBMACPI_FAN_CMD_LEVEL |
+ IBMACPI_FAN_CMD_ENABLE;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int fan_get_status(u8 *status)
+{
+ u8 s;
+
+ /* TODO:
+ * Add IBMACPI_FAN_RD_ACPI_FANS ? */
+
+ switch (fan_status_access_mode) {
+ case IBMACPI_FAN_RD_ACPI_GFAN:
+ /* 570, 600e/x, 770e, 770x */
+
+ if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
+ return -EIO;
+
+ if (likely(status))
+ *status = s & 0x07;
+
+ break;
+
+ case IBMACPI_FAN_RD_TPEC:
/* all except 570, 600e/x, 770e, 770x */
- if (!acpi_ec_read(fan_status_offset, &status))
- len += sprintf(p + len, "status:\t\tunreadable\n");
- else
- len += sprintf(p + len, "status:\t\t%s\n",
- enabled(status, 7));
+ if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
+ return -EIO;
- if (!acpi_ec_read(fan_rpm_offset, &lo) ||
- !acpi_ec_read(fan_rpm_offset + 1, &hi))
- len += sprintf(p + len, "speed:\t\tunreadable\n");
- else
- len += sprintf(p + len, "speed:\t\t%d\n",
- (hi << 8) + lo);
+ if (likely(status))
+ *status = s;
+
+ break;
+
+ default:
+ return -ENXIO;
}
- if (sfan_handle)
- /* 570, 770x-JL */
- len += sprintf(p + len, "commands:\tlevel <level>"
- " (<level> is 0-7)\n");
- if (!gfan_handle)
+ return 0;
+}
+
+static int fan_get_speed(unsigned int *speed)
+{
+ u8 hi, lo;
+
+ switch (fan_status_access_mode) {
+ case IBMACPI_FAN_RD_TPEC:
/* all except 570, 600e/x, 770e, 770x */
- len += sprintf(p + len, "commands:\tenable, disable\n");
- if (fans_handle)
- /* X31, X40 */
+ if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
+ !acpi_ec_read(fan_rpm_offset + 1, &hi)))
+ return -EIO;
+
+ if (likely(speed))
+ *speed = (hi << 8) | lo;
+
+ break;
+
+ default:
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void fan_exit(void)
+{
+ cancel_delayed_work(&fan_watchdog_task);
+ flush_scheduled_work();
+}
+
+static void fan_watchdog_reset(void)
+{
+ static int fan_watchdog_active = 0;
+
+ if (fan_watchdog_active)
+ cancel_delayed_work(&fan_watchdog_task);
+
+ if (fan_watchdog_maxinterval > 0) {
+ fan_watchdog_active = 1;
+ if (!schedule_delayed_work(&fan_watchdog_task,
+ msecs_to_jiffies(fan_watchdog_maxinterval
+ * 1000))) {
+ printk(IBM_ERR "failed to schedule the fan watchdog, "
+ "watchdog will not trigger\n");
+ }
+ } else
+ fan_watchdog_active = 0;
+}
+
+static int fan_read(char *p)
+{
+ int len = 0;
+ int rc;
+ u8 status;
+ unsigned int speed = 0;
+
+ switch (fan_status_access_mode) {
+ case IBMACPI_FAN_RD_ACPI_GFAN:
+ /* 570, 600e/x, 770e, 770x */
+ if ((rc = fan_get_status(&status)) < 0)
+ return rc;
+
+ len += sprintf(p + len, "status:\t\t%s\n"
+ "level:\t\t%d\n",
+ (status != 0) ? "enabled" : "disabled", status);
+ break;
+
+ case IBMACPI_FAN_RD_TPEC:
+ /* all except 570, 600e/x, 770e, 770x */
+ if ((rc = fan_get_status(&status)) < 0)
+ return rc;
+
+ if (unlikely(!fan_control_status_known)) {
+ if (status != fan_control_initial_status)
+ fan_control_status_known = 1;
+ else
+ /* Return most likely status. In fact, it
+ * might be the only possible status */
+ status = IBMACPI_FAN_EC_AUTO;
+ }
+
+ len += sprintf(p + len, "status:\t\t%s\n",
+ (status != 0) ? "enabled" : "disabled");
+
+ /* No ThinkPad boots on disengaged mode, we can safely
+ * assume the tachometer is online if fan control status
+ * was unknown */
+ if ((rc = fan_get_speed(&speed)) < 0)
+ return rc;
+
+ len += sprintf(p + len, "speed:\t\t%d\n", speed);
+
+ if (status & IBMACPI_FAN_EC_DISENGAGED)
+ /* Disengaged mode takes precedence */
+ len += sprintf(p + len, "level:\t\tdisengaged\n");
+ else if (status & IBMACPI_FAN_EC_AUTO)
+ len += sprintf(p + len, "level:\t\tauto\n");
+ else
+ len += sprintf(p + len, "level:\t\t%d\n", status);
+ break;
+
+ case IBMACPI_FAN_NONE:
+ default:
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ }
+
+ if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
+ len += sprintf(p + len, "commands:\tlevel <level>");
+
+ switch (fan_control_access_mode) {
+ case IBMACPI_FAN_WR_ACPI_SFAN:
+ len += sprintf(p + len, " (<level> is 0-7)\n");
+ break;
+
+ default:
+ len += sprintf(p + len, " (<level> is 0-7, "
+ "auto, disengaged)\n");
+ break;
+ }
+ }
+
+ if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
+ len += sprintf(p + len, "commands:\tenable, disable\n"
+ "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
+ "1-120 (seconds))\n");
+
+ if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
len += sprintf(p + len, "commands:\tspeed <speed>"
" (<speed> is 0-65535)\n");
return len;
}
-static int fan_write(char *buf)
+static int fan_set_level(int level)
{
- char *cmd;
- int level, speed;
-
- while ((cmd = next_cmd(&buf))) {
- if (sfan_handle &&
- sscanf(cmd, "level %d", &level) == 1 &&
- level >= 0 && level <= 7) {
- /* 570, 770x-JL */
+ switch (fan_control_access_mode) {
+ case IBMACPI_FAN_WR_ACPI_SFAN:
+ if (level >= 0 && level <= 7) {
if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
return -EIO;
- } else if (!gfan_handle && strlencmp(cmd, "enable") == 0) {
- /* all except 570, 600e/x, 770e, 770x */
- if (!acpi_ec_write(fan_status_offset, 0x80))
- return -EIO;
- } else if (!gfan_handle && strlencmp(cmd, "disable") == 0) {
- /* all except 570, 600e/x, 770e, 770x */
- if (!acpi_ec_write(fan_status_offset, 0x00))
- return -EIO;
- } else if (fans_handle &&
- sscanf(cmd, "speed %d", &speed) == 1 &&
- speed >= 0 && speed <= 65535) {
- /* X31, X40 */
+ } else
+ return -EINVAL;
+ break;
+
+ case IBMACPI_FAN_WR_ACPI_FANS:
+ case IBMACPI_FAN_WR_TPEC:
+ if ((level != IBMACPI_FAN_EC_AUTO) &&
+ (level != IBMACPI_FAN_EC_DISENGAGED) &&
+ ((level < 0) || (level > 7)))
+ return -EINVAL;
+
+ if (!acpi_ec_write(fan_status_offset, level))
+ return -EIO;
+ else
+ fan_control_status_known = 1;
+ break;
+
+ default:
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int fan_set_enable(void)
+{
+ u8 s;
+ int rc;
+
+ switch (fan_control_access_mode) {
+ case IBMACPI_FAN_WR_ACPI_FANS:
+ case IBMACPI_FAN_WR_TPEC:
+ if ((rc = fan_get_status(&s)) < 0)
+ return rc;
+
+ /* Don't go out of emergency fan mode */
+ if (s != 7)
+ s = IBMACPI_FAN_EC_AUTO;
+
+ if (!acpi_ec_write(fan_status_offset, s))
+ return -EIO;
+ else
+ fan_control_status_known = 1;
+ break;
+
+ case IBMACPI_FAN_WR_ACPI_SFAN:
+ if ((rc = fan_get_status(&s)) < 0)
+ return rc;
+
+ s &= 0x07;
+
+ /* Set fan to at least level 4 */
+ if (s < 4)
+ s = 4;
+
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
+ return -EIO;
+ break;
+
+ default:
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int fan_set_disable(void)
+{
+ switch (fan_control_access_mode) {
+ case IBMACPI_FAN_WR_ACPI_FANS:
+ case IBMACPI_FAN_WR_TPEC:
+ if (!acpi_ec_write(fan_status_offset, 0x00))
+ return -EIO;
+ else
+ fan_control_status_known = 1;
+ break;
+
+ case IBMACPI_FAN_WR_ACPI_SFAN:
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
+ return -EIO;
+ break;
+
+ default:
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int fan_set_speed(int speed)
+{
+ switch (fan_control_access_mode) {
+ case IBMACPI_FAN_WR_ACPI_FANS:
+ if (speed >= 0 && speed <= 65535) {
if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
speed, speed, speed))
return -EIO;
} else
return -EINVAL;
- }
+ break;
+ default:
+ return -ENXIO;
+ }
return 0;
}
+static int fan_write_cmd_level(const char *cmd, int *rc)
+{
+ int level;
+
+ if (strlencmp(cmd, "level auto") == 0)
+ level = IBMACPI_FAN_EC_AUTO;
+ else if (strlencmp(cmd, "level disengaged") == 0)
+ level = IBMACPI_FAN_EC_DISENGAGED;
+ else if (sscanf(cmd, "level %d", &level) != 1)
+ return 0;
+
+ if ((*rc = fan_set_level(level)) == -ENXIO)
+ printk(IBM_ERR "level command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_enable(const char *cmd, int *rc)
+{
+ if (strlencmp(cmd, "enable") != 0)
+ return 0;
+
+ if ((*rc = fan_set_enable()) == -ENXIO)
+ printk(IBM_ERR "enable command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_disable(const char *cmd, int *rc)
+{
+ if (strlencmp(cmd, "disable") != 0)
+ return 0;
+
+ if ((*rc = fan_set_disable()) == -ENXIO)
+ printk(IBM_ERR "disable command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_speed(const char *cmd, int *rc)
+{
+ int speed;
+
+ /* TODO:
+ * Support speed <low> <medium> <high> ? */
+
+ if (sscanf(cmd, "speed %d", &speed) != 1)
+ return 0;
+
+ if ((*rc = fan_set_speed(speed)) == -ENXIO)
+ printk(IBM_ERR "speed command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_watchdog(const char *cmd, int *rc)
+{
+ int interval;
+
+ if (sscanf(cmd, "watchdog %d", &interval) != 1)
+ return 0;
+
+ if (interval < 0 || interval > 120)
+ *rc = -EINVAL;
+ else
+ fan_watchdog_maxinterval = interval;
+
+ return 1;
+}
+
+static int fan_write(char *buf)
+{
+ char *cmd;
+ int rc = 0;
+
+ while (!rc && (cmd = next_cmd(&buf))) {
+ if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) &&
+ fan_write_cmd_level(cmd, &rc)) &&
+ !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) &&
+ (fan_write_cmd_enable(cmd, &rc) ||
+ fan_write_cmd_disable(cmd, &rc) ||
+ fan_write_cmd_watchdog(cmd, &rc))) &&
+ !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) &&
+ fan_write_cmd_speed(cmd, &rc))
+ )
+ rc = -EINVAL;
+ else if (!rc)
+ fan_watchdog_reset();
+ }
+
+ return rc;
+}
+
+static void fan_watchdog_fire(struct work_struct *ignored)
+{
+ printk(IBM_NOTICE "fan watchdog: enabling fan\n");
+ if (fan_set_enable()) {
+ printk(IBM_ERR "fan watchdog: error while enabling fan\n");
+ /* reschedule for later */
+ fan_watchdog_reset();
+ }
+}
+
static struct ibm_struct ibms[] = {
{
.name = "driver",
- .init = driver_init,
+ .init = ibm_acpi_driver_init,
.read = driver_read,
},
{
@@ -1702,6 +2389,8 @@ static struct ibm_struct ibms[] = {
.name = "brightness",
.read = brightness_read,
.write = brightness_write,
+ .init = brightness_init,
+ .exit = brightness_exit,
},
{
.name = "volume",
@@ -1712,6 +2401,8 @@ static struct ibm_struct ibms[] = {
.name = "fan",
.read = fan_read,
.write = fan_write,
+ .init = fan_init,
+ .exit = fan_exit,
.experimental = 1,
},
};
@@ -1719,7 +2410,7 @@ static struct ibm_struct ibms[] = {
static int dispatch_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
- struct ibm_struct *ibm = (struct ibm_struct *)data;
+ struct ibm_struct *ibm = data;
int len;
if (!ibm || !ibm->read)
@@ -1744,7 +2435,7 @@ static int dispatch_read(char *page, char **start, off_t off, int count,
static int dispatch_write(struct file *file, const char __user * userbuf,
unsigned long count, void *data)
{
- struct ibm_struct *ibm = (struct ibm_struct *)data;
+ struct ibm_struct *ibm = data;
char *kernbuf;
int ret;
@@ -1773,7 +2464,7 @@ static int dispatch_write(struct file *file, const char __user * userbuf,
static void dispatch_notify(acpi_handle handle, u32 event, void *data)
{
- struct ibm_struct *ibm = (struct ibm_struct *)data;
+ struct ibm_struct *ibm = data;
if (!ibm || !ibm->notify)
return;
@@ -1805,7 +2496,7 @@ static int __init setup_notify(struct ibm_struct *ibm)
ibm->name, status);
return -ENODEV;
}
-
+ ibm->notify_installed = 1;
return 0;
}
@@ -1818,14 +2509,13 @@ static int __init register_driver(struct ibm_struct *ibm)
{
int ret;
- ibm->driver = kmalloc(sizeof(struct acpi_driver), GFP_KERNEL);
+ ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
if (!ibm->driver) {
printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
return -1;
}
- memset(ibm->driver, 0, sizeof(struct acpi_driver));
- sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name);
+ sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
ibm->driver->ids = ibm->hid;
ibm->driver->ops.add = &ibm_device_add;
@@ -1882,7 +2572,6 @@ static int __init ibm_init(struct ibm_struct *ibm)
ret = setup_notify(ibm);
if (ret < 0)
return ret;
- ibm->notify_installed = 1;
}
return 0;
@@ -1971,6 +2660,33 @@ static void acpi_ibm_exit(void)
ibm_exit(&ibms[i]);
remove_proc_entry(IBM_DIR, acpi_root_dir);
+
+ if (ibm_thinkpad_ec_found)
+ kfree(ibm_thinkpad_ec_found);
+}
+
+static char* __init check_dmi_for_ec(void)
+{
+ struct dmi_device *dev = NULL;
+ char ec_fw_string[18];
+
+ /*
+ * ThinkPad T23 or newer, A31 or newer, R50e or newer,
+ * X32 or newer, all Z series; Some models must have an
+ * up-to-date BIOS or they will not be detected.
+ *
+ * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+ */
+ while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+ if (sscanf(dev->name,
+ "IBM ThinkPad Embedded Controller -[%17c",
+ ec_fw_string) == 1) {
+ ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
+ ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
+ return kstrdup(ec_fw_string, GFP_KERNEL);
+ }
+ }
+ return NULL;
}
static int __init acpi_ibm_init(void)
@@ -1992,6 +2708,12 @@ static int __init acpi_ibm_init(void)
return -ENODEV;
}
+ /* Models with newer firmware report the EC in DMI */
+ ibm_thinkpad_ec_found = check_dmi_for_ec();
+ if (ibm_thinkpad_ec_found)
+ printk(IBM_INFO "ThinkPad EC firmware %s\n",
+ ibm_thinkpad_ec_found);
+
/* these handles are not required */
IBM_HANDLE_INIT(vid);
IBM_HANDLE_INIT(vid2);
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
deleted file mode 100644
index 2e17ec75af0..00000000000
--- a/drivers/acpi/motherboard.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * This program is free software; you can redistribute it and/or modify
- * 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.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-/* Purpose: Prevent PCMCIA cards from using motherboard resources. */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-
-#define _COMPONENT ACPI_SYSTEM_COMPONENT
-ACPI_MODULE_NAME("acpi_motherboard")
-
-/* Dell use PNP0C01 instead of PNP0C02 */
-#define ACPI_MB_HID1 "PNP0C01"
-#define ACPI_MB_HID2 "PNP0C02"
-/**
- * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved
- * Doesn't care about the failure of 'request_region', since other may reserve
- * the io ports as well
- */
-#define IS_RESERVED_ADDR(base, len) \
- (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \
- && ((base) + (len) > PCIBIOS_MIN_IO))
-/*
- * Clearing the flag (IORESOURCE_BUSY) allows drivers to use
- * 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;
-
-
- if (res->type == ACPI_RESOURCE_TYPE_IO) {
- struct acpi_resource_io *io_res = &res->data.io;
-
- if (io_res->minimum != io_res->maximum)
- return AE_OK;
- if (IS_RESERVED_ADDR
- (io_res->minimum, io_res->address_length)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Motherboard resources 0x%08x - 0x%08x\n",
- io_res->minimum,
- io_res->minimum +
- io_res->address_length));
- requested_res =
- request_region(io_res->minimum,
- io_res->address_length, "motherboard");
- }
- } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_IO) {
- struct acpi_resource_fixed_io *fixed_io_res =
- &res->data.fixed_io;
-
- if (IS_RESERVED_ADDR
- (fixed_io_res->address, fixed_io_res->address_length)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Motherboard resources 0x%08x - 0x%08x\n",
- fixed_io_res->address,
- fixed_io_res->address +
- fixed_io_res->address_length));
- requested_res =
- request_region(fixed_io_res->address,
- fixed_io_res->address_length,
- "motherboard");
- }
- } else {
- /* Memory mapped IO? */
- }
-
- if (requested_res)
- requested_res->flags &= ~IORESOURCE_BUSY;
- return AE_OK;
-}
-
-static int acpi_motherboard_add(struct acpi_device *device)
-{
- if (!device)
- return -EINVAL;
- acpi_walk_resources(device->handle, METHOD_NAME__CRS,
- acpi_reserve_io_ranges, NULL);
-
- return 0;
-}
-
-static struct acpi_driver acpi_motherboard_driver1 = {
- .name = "motherboard",
- .class = "",
- .ids = ACPI_MB_HID1,
- .ops = {
- .add = acpi_motherboard_add,
- },
-};
-
-static struct acpi_driver acpi_motherboard_driver2 = {
- .name = "motherboard",
- .class = "",
- .ids = ACPI_MB_HID2,
- .ops = {
- .add = acpi_motherboard_add,
- },
-};
-
-static void __init acpi_request_region (struct acpi_generic_address *addr,
- unsigned int length, char *desc)
-{
- if (!addr->address || !length)
- return;
-
- if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_IO)
- request_region(addr->address, length, desc);
- else if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
- request_mem_region(addr->address, length, desc);
-}
-
-static void __init acpi_reserve_resources(void)
-{
- acpi_request_region(&acpi_gbl_FADT->xpm1a_evt_blk,
- acpi_gbl_FADT->pm1_evt_len, "ACPI PM1a_EVT_BLK");
-
- acpi_request_region(&acpi_gbl_FADT->xpm1b_evt_blk,
- acpi_gbl_FADT->pm1_evt_len, "ACPI PM1b_EVT_BLK");
-
- acpi_request_region(&acpi_gbl_FADT->xpm1a_cnt_blk,
- acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1a_CNT_BLK");
-
- acpi_request_region(&acpi_gbl_FADT->xpm1b_cnt_blk,
- acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1b_CNT_BLK");
-
- if (acpi_gbl_FADT->pm_tm_len == 4)
- acpi_request_region(&acpi_gbl_FADT->xpm_tmr_blk, 4, "ACPI PM_TMR");
-
- acpi_request_region(&acpi_gbl_FADT->xpm2_cnt_blk,
- acpi_gbl_FADT->pm2_cnt_len, "ACPI PM2_CNT_BLK");
-
- /* Length of GPE blocks must be a non-negative multiple of 2 */
-
- if (!(acpi_gbl_FADT->gpe0_blk_len & 0x1))
- acpi_request_region(&acpi_gbl_FADT->xgpe0_blk,
- acpi_gbl_FADT->gpe0_blk_len, "ACPI GPE0_BLK");
-
- if (!(acpi_gbl_FADT->gpe1_blk_len & 0x1))
- acpi_request_region(&acpi_gbl_FADT->xgpe1_blk,
- acpi_gbl_FADT->gpe1_blk_len, "ACPI GPE1_BLK");
-}
-
-static int __init acpi_motherboard_init(void)
-{
- acpi_bus_register_driver(&acpi_motherboard_driver1);
- acpi_bus_register_driver(&acpi_motherboard_driver2);
- /*
- * Guarantee motherboard IO reservation first
- * This module must run after scan.c
- */
- if (!acpi_disabled)
- acpi_reserve_resources();
- return 0;
-}
-
-/**
- * Reserve motherboard resources after PCI claim BARs,
- * but before PCI assign resources for uninitialized PCI devices
- */
-fs_initcall(acpi_motherboard_init);
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
index c1c6c236df9..57faf598bad 100644
--- a/drivers/acpi/namespace/nsaccess.c
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -195,31 +195,27 @@ acpi_status acpi_ns_root_initialize(void)
obj_desc->mutex.sync_level =
(u8) (ACPI_TO_INTEGER(val) - 1);
- if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
+ /* Create a mutex */
- /* Create a counting semaphore for the global lock */
+ status =
+ acpi_os_create_mutex(&obj_desc->mutex.
+ os_mutex);
+ if (ACPI_FAILURE(status)) {
+ acpi_ut_remove_reference(obj_desc);
+ goto unlock_and_exit;
+ }
- status =
- acpi_os_create_semaphore
- (ACPI_NO_UNIT_LIMIT, 1,
- &acpi_gbl_global_lock_semaphore);
- if (ACPI_FAILURE(status)) {
- acpi_ut_remove_reference
- (obj_desc);
- goto unlock_and_exit;
- }
+ /* Special case for ACPI Global Lock */
- /* Mark this mutex as very special */
+ if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
+ acpi_gbl_global_lock_mutex =
+ obj_desc->mutex.os_mutex;
- obj_desc->mutex.os_mutex =
- ACPI_GLOBAL_LOCK;
- } else {
- /* Create a mutex */
+ /* Create additional counting semaphore for global lock */
status =
- acpi_os_create_mutex(&obj_desc->
- mutex.
- os_mutex);
+ acpi_os_create_semaphore(1, 0,
+ &acpi_gbl_global_lock_semaphore);
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference
(obj_desc);
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
index 55b407aae26..1d693d8ad2d 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,6 +61,9 @@ ACPI_MODULE_NAME("nsalloc")
struct acpi_namespace_node *acpi_ns_create_node(u32 name)
{
struct acpi_namespace_node *node;
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ u32 temp;
+#endif
ACPI_FUNCTION_TRACE(ns_create_node);
@@ -71,6 +74,15 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name)
ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++);
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ temp =
+ acpi_gbl_ns_node_list->total_allocated -
+ acpi_gbl_ns_node_list->total_freed;
+ if (temp > acpi_gbl_ns_node_list->max_occupied) {
+ acpi_gbl_ns_node_list->max_occupied = temp;
+ }
+#endif
+
node->name.integer = name;
ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED);
return_PTR(node);
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
index d72df66aa96..1fc4f86676e 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/namespace/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -205,7 +205,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
if (!acpi_ut_valid_acpi_name(this_node->name.integer)) {
this_node->name.integer =
- acpi_ut_repair_name(this_node->name.integer);
+ acpi_ut_repair_name(this_node->name.ascii);
ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X",
this_node->name.integer));
@@ -226,6 +226,12 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
obj_desc = acpi_ns_get_attached_object(this_node);
acpi_dbg_level = dbg_level;
+ /* Temp nodes are those nodes created by a control method */
+
+ if (this_node->flags & ANOBJ_TEMPORARY) {
+ acpi_os_printf("(T) ");
+ }
+
switch (info->display_type & ACPI_DISPLAY_MASK) {
case ACPI_DISPLAY_SUMMARY:
@@ -623,7 +629,8 @@ acpi_ns_dump_objects(acpi_object_type type,
info.display_type = display_type;
(void)acpi_ns_walk_namespace(type, start_handle, max_depth,
- ACPI_NS_WALK_NO_UNLOCK,
+ ACPI_NS_WALK_NO_UNLOCK |
+ ACPI_NS_WALK_TEMP_NODES,
acpi_ns_dump_one_object, (void *)&info,
NULL);
}
diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
index c6bf5d30fca..5097e167939 100644
--- a/drivers/acpi/namespace/nsdumpdv.c
+++ b/drivers/acpi/namespace/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index 4b0a4a8c984..aa6370c67ec 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -154,11 +154,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
* Execute the method via the interpreter. The interpreter is locked
* here before calling into the AML parser
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
+ acpi_ex_enter_interpreter();
status = acpi_ps_execute_method(info);
acpi_ex_exit_interpreter();
} else {
@@ -182,10 +178,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
* resolution, we must lock it because we could access an opregion.
* The opregion access code assumes that the interpreter is locked.
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ acpi_ex_enter_interpreter();
/* Function has a strange interface */
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
index aec8488c001..326af8fc0ce 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/namespace/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -213,7 +213,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
u32 level, void *context, void **return_value)
{
acpi_object_type type;
- acpi_status status;
+ acpi_status status = AE_OK;
struct acpi_init_walk_info *info =
(struct acpi_init_walk_info *)context;
struct acpi_namespace_node *node =
@@ -267,10 +267,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
/*
* Must lock the interpreter before executing AML code
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return (status);
- }
+ acpi_ex_enter_interpreter();
/*
* Each of these types can contain executable AML code within the
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
index fe75d888e18..d4f9654fd20 100644
--- a/drivers/acpi/namespace/nsload.c
+++ b/drivers/acpi/namespace/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,13 +44,12 @@
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acdispat.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsload")
/* Local prototypes */
-static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type);
-
#ifdef ACPI_FUTURE_IMPLEMENTATION
acpi_status acpi_ns_unload_namespace(acpi_handle handle);
@@ -62,7 +61,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
*
* FUNCTION: acpi_ns_load_table
*
- * PARAMETERS: table_desc - Descriptor for table to be loaded
+ * PARAMETERS: table_index - Index for table to be loaded
* Node - Owning NS node
*
* RETURN: Status
@@ -72,42 +71,13 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
******************************************************************************/
acpi_status
-acpi_ns_load_table(struct acpi_table_desc *table_desc,
+acpi_ns_load_table(acpi_native_uint table_index,
struct acpi_namespace_node *node)
{
acpi_status status;
ACPI_FUNCTION_TRACE(ns_load_table);
- /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */
-
- if (!
- (acpi_gbl_table_data[table_desc->type].
- flags & ACPI_TABLE_EXECUTABLE)) {
-
- /* Just ignore this table */
-
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Check validity of the AML start and length */
-
- if (!table_desc->aml_start) {
- ACPI_ERROR((AE_INFO, "Null AML pointer"));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AML block at %p\n",
- table_desc->aml_start));
-
- /* Ignore table if there is no AML contained within */
-
- if (!table_desc->aml_length) {
- ACPI_WARNING((AE_INFO, "Zero-length AML block in table [%4.4s]",
- table_desc->pointer->signature));
- return_ACPI_STATUS(AE_OK);
- }
-
/*
* Parse the table and load the namespace with all named
* objects found within. Control methods are NOT parsed
@@ -117,15 +87,34 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
* to another control method, we can't continue parsing
* because we don't know how many arguments to parse next!
*/
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* If table already loaded into namespace, just return */
+
+ if (acpi_tb_is_table_loaded(table_index)) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock;
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"**** Loading table into namespace ****\n"));
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ status = acpi_tb_allocate_owner_id(table_index);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto unlock;
+ }
+
+ status = acpi_ns_parse_table(table_index, node->child);
+ if (ACPI_SUCCESS(status)) {
+ acpi_tb_set_table_loaded_flag(table_index, TRUE);
+ } else {
+ acpi_tb_release_owner_id(table_index);
}
- status = acpi_ns_parse_table(table_desc, node->child);
+ unlock:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
@@ -141,7 +130,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"**** Begin Table Method Parsing and Object Initialization ****\n"));
- status = acpi_ds_initialize_objects(table_desc, node);
+ status = acpi_ds_initialize_objects(table_index, node);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"**** Completed Table Method Parsing and Object Initialization ****\n"));
@@ -149,99 +138,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
return_ACPI_STATUS(status);
}
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_load_table_by_type
- *
- * PARAMETERS: table_type - Id of the table type to load
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load an ACPI table or tables into the namespace. All tables
- * of the given type are loaded. The mechanism allows this
- * routine to be called repeatedly.
- *
- ******************************************************************************/
-
-static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type)
-{
- u32 i;
- acpi_status status;
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(ns_load_table_by_type);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /*
- * Table types supported are:
- * DSDT (one), SSDT/PSDT (multiple)
- */
- switch (table_type) {
- case ACPI_TABLE_ID_DSDT:
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: DSDT\n"));
-
- table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_DSDT].next;
-
- /* If table already loaded into namespace, just return */
-
- if (table_desc->loaded_into_namespace) {
- goto unlock_and_exit;
- }
-
- /* Now load the single DSDT */
-
- status = acpi_ns_load_table(table_desc, acpi_gbl_root_node);
- if (ACPI_SUCCESS(status)) {
- table_desc->loaded_into_namespace = TRUE;
- }
- break;
-
- case ACPI_TABLE_ID_SSDT:
- case ACPI_TABLE_ID_PSDT:
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Namespace load: %d SSDT or PSDTs\n",
- acpi_gbl_table_lists[table_type].count));
-
- /*
- * Traverse list of SSDT or PSDT tables
- */
- table_desc = acpi_gbl_table_lists[table_type].next;
- for (i = 0; i < acpi_gbl_table_lists[table_type].count; i++) {
- /*
- * Only attempt to load table into namespace if it is not
- * already loaded!
- */
- if (!table_desc->loaded_into_namespace) {
- status =
- acpi_ns_load_table(table_desc,
- acpi_gbl_root_node);
- if (ACPI_FAILURE(status)) {
- break;
- }
-
- table_desc->loaded_into_namespace = TRUE;
- }
-
- table_desc = table_desc->next;
- }
- break;
-
- default:
- status = AE_SUPPORT;
- break;
- }
-
- unlock_and_exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_ACPI_STATUS(status);
-}
-
+#ifdef ACPI_OBSOLETE_FUNCTIONS
/*******************************************************************************
*
* FUNCTION: acpi_load_namespace
@@ -288,6 +185,7 @@ acpi_status acpi_ns_load_namespace(void)
return_ACPI_STATUS(status);
}
+#endif
#ifdef ACPI_FUTURE_IMPLEMENTATION
/*******************************************************************************
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
index 97b8332c974..cbd94af08cc 100644
--- a/drivers/acpi/namespace/nsnames.c
+++ b/drivers/acpi/namespace/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c
index aabe8794b90..d9d7377bc6e 100644
--- a/drivers/acpi/namespace/nsobject.c
+++ b/drivers/acpi/namespace/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c
index 155505a4ef6..e696aa84799 100644
--- a/drivers/acpi/namespace/nsparse.c
+++ b/drivers/acpi/namespace/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,7 @@
#include <acpi/acnamesp.h>
#include <acpi/acparser.h>
#include <acpi/acdispat.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsparse")
@@ -62,14 +63,24 @@ ACPI_MODULE_NAME("nsparse")
*
******************************************************************************/
acpi_status
-acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
+acpi_ns_one_complete_parse(acpi_native_uint pass_number,
+ acpi_native_uint table_index)
{
union acpi_parse_object *parse_root;
acpi_status status;
+ acpi_native_uint aml_length;
+ u8 *aml_start;
struct acpi_walk_state *walk_state;
+ struct acpi_table_header *table;
+ acpi_owner_id owner_id;
ACPI_FUNCTION_TRACE(ns_one_complete_parse);
+ status = acpi_tb_get_owner_id(table_index, &owner_id);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Create and init a Root Node */
parse_root = acpi_ps_create_scope_op();
@@ -79,26 +90,41 @@ acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
/* Create and initialize a new walk state */
- walk_state = acpi_ds_create_walk_state(table_desc->owner_id,
- NULL, NULL, NULL);
+ walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL);
if (!walk_state) {
acpi_ps_free_op(parse_root);
return_ACPI_STATUS(AE_NO_MEMORY);
}
- status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
- table_desc->aml_start,
- table_desc->aml_length, NULL,
- pass_number);
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
+ acpi_ps_free_op(parse_root);
+ return_ACPI_STATUS(status);
+ }
+
+ /* Table must consist of at least a complete header */
+
+ if (table->length < sizeof(struct acpi_table_header)) {
+ status = AE_BAD_HEADER;
+ } else {
+ aml_start = (u8 *) table + sizeof(struct acpi_table_header);
+ aml_length = table->length - sizeof(struct acpi_table_header);
+ status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
+ aml_start, aml_length, NULL,
+ (u8) pass_number);
+ }
+
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
+ acpi_ps_delete_parse_tree(parse_root);
return_ACPI_STATUS(status);
}
/* Parse the AML */
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %d parse\n",
- pass_number));
+ (unsigned)pass_number));
status = acpi_ps_parse_aml(walk_state);
acpi_ps_delete_parse_tree(parse_root);
@@ -119,7 +145,7 @@ acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
******************************************************************************/
acpi_status
-acpi_ns_parse_table(struct acpi_table_desc *table_desc,
+acpi_ns_parse_table(acpi_native_uint table_index,
struct acpi_namespace_node *start_node)
{
acpi_status status;
@@ -134,10 +160,10 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc,
* each Parser Op subtree is deleted when it is finished. This saves
* a great deal of memory, and allows a small cache of parse objects
* to service the entire parse. The second pass of the parse then
- * performs another complete parse of the AML..
+ * performs another complete parse of the AML.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n"));
- status = acpi_ns_one_complete_parse(1, table_desc);
+ status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -152,7 +178,7 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc,
* parse objects are all cached.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n"));
- status = acpi_ns_one_complete_parse(2, table_desc);
+ status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
index 500e2bbcfaf..e863be665ce 100644
--- a/drivers/acpi/namespace/nssearch.c
+++ b/drivers/acpi/namespace/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -321,7 +321,8 @@ acpi_ns_search_and_enter(u32 target_name,
* even though there are a few bad names.
*/
if (!acpi_ut_valid_acpi_name(target_name)) {
- target_name = acpi_ut_repair_name(target_name);
+ target_name =
+ acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name));
/* Report warning only if in strict mode or debug mode */
@@ -401,6 +402,10 @@ acpi_ns_search_and_enter(u32 target_name,
}
#endif
+ if (flags & ACPI_NS_TEMPORARY) {
+ new_node->flags |= ANOBJ_TEMPORARY;
+ }
+
/* Install the new object into the parent's list of children */
acpi_ns_install_node(walk_state, node, new_node, type);
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
index aa4e799d9a8..90fd059615f 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/namespace/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -770,13 +770,6 @@ void acpi_ns_terminate(void)
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n"));
-
- /*
- * 2) Now we can delete the ACPI tables
- */
- acpi_tb_delete_all_tables();
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
-
return_VOID;
}
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
index c8f6bef16ed..94eb8f332d9 100644
--- a/drivers/acpi/namespace/nswalk.c
+++ b/drivers/acpi/namespace/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -126,7 +126,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
* PARAMETERS: Type - acpi_object_type to search for
* start_node - Handle in namespace where search begins
* max_depth - Depth to which search is to reach
- * unlock_before_callback- Whether to unlock the NS before invoking
+ * Flags - Whether to unlock the NS before invoking
* the callback routine
* user_function - Called when an object of "Type" is found
* Context - Passed to user function
@@ -153,7 +153,7 @@ acpi_status
acpi_ns_walk_namespace(acpi_object_type type,
acpi_handle start_node,
u32 max_depth,
- u8 unlock_before_callback,
+ u32 flags,
acpi_walk_callback user_function,
void *context, void **return_value)
{
@@ -193,20 +193,34 @@ acpi_ns_walk_namespace(acpi_object_type type,
acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
child_node);
if (child_node) {
- /*
- * Found node, Get the type if we are not
- * searching for ANY
- */
+
+ /* Found next child, get the type if we are not searching for ANY */
+
if (type != ACPI_TYPE_ANY) {
child_type = child_node->type;
}
- if (child_type == type) {
+ /*
+ * Ignore all temporary namespace nodes (created during control
+ * method execution) unless told otherwise. These temporary nodes
+ * can cause a race condition because they can be deleted during the
+ * execution of the user function (if the namespace is unlocked before
+ * invocation of the user function.) Only the debugger namespace dump
+ * will examine the temporary nodes.
+ */
+ if ((child_node->flags & ANOBJ_TEMPORARY) &&
+ !(flags & ACPI_NS_WALK_TEMP_NODES)) {
+ status = AE_CTRL_DEPTH;
+ }
+
+ /* Type must match requested type */
+
+ else if (child_type == type) {
/*
- * Found a matching node, invoke the user
- * callback function
+ * Found a matching node, invoke the user callback function.
+ * Unlock the namespace if flag is set.
*/
- if (unlock_before_callback) {
+ if (flags & ACPI_NS_WALK_UNLOCK) {
mutex_status =
acpi_ut_release_mutex
(ACPI_MTX_NAMESPACE);
@@ -216,10 +230,11 @@ acpi_ns_walk_namespace(acpi_object_type type,
}
}
- status = user_function(child_node, level,
- context, return_value);
+ status =
+ user_function(child_node, level, context,
+ return_value);
- if (unlock_before_callback) {
+ if (flags & ACPI_NS_WALK_UNLOCK) {
mutex_status =
acpi_ut_acquire_mutex
(ACPI_MTX_NAMESPACE);
@@ -251,20 +266,17 @@ acpi_ns_walk_namespace(acpi_object_type type,
}
/*
- * Depth first search:
- * Attempt to go down another level in the namespace
- * if we are allowed to. Don't go any further if we
- * have reached the caller specified maximum depth
- * or if the user function has specified that the
- * maximum depth has been reached.
+ * Depth first search: Attempt to go down another level in the
+ * namespace if we are allowed to. Don't go any further if we have
+ * reached the caller specified maximum depth or if the user
+ * function has specified that the maximum depth has been reached.
*/
if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
if (acpi_ns_get_next_node
(ACPI_TYPE_ANY, child_node, NULL)) {
- /*
- * There is at least one child of this
- * node, visit the onde
- */
+
+ /* There is at least one child of this node, visit it */
+
level++;
parent_node = child_node;
child_node = NULL;
@@ -272,9 +284,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
}
} else {
/*
- * No more children of this node (acpi_ns_get_next_node
- * failed), go back upwards in the namespace tree to
- * the node's parent.
+ * No more children of this node (acpi_ns_get_next_node failed), go
+ * back upwards in the namespace tree to the node's parent.
*/
level--;
child_node = parent_node;
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index dca6799ac67..7ac6ace5005 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -170,7 +170,6 @@ acpi_evaluate_object(acpi_handle handle,
struct acpi_buffer *return_buffer)
{
acpi_status status;
- acpi_status status2;
struct acpi_evaluate_info *info;
acpi_size buffer_space_needed;
u32 i;
@@ -329,14 +328,12 @@ acpi_evaluate_object(acpi_handle handle,
* Delete the internal return object. NOTE: Interpreter must be
* locked to avoid race condition.
*/
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_SUCCESS(status2)) {
+ acpi_ex_enter_interpreter();
- /* Remove one reference on the return object (should delete it) */
+ /* Remove one reference on the return object (should delete it) */
- acpi_ut_remove_reference(info->return_object);
- acpi_ex_exit_interpreter();
- }
+ acpi_ut_remove_reference(info->return_object);
+ acpi_ex_exit_interpreter();
}
cleanup:
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
index 978213a6c19..b489781b22a 100644
--- a/drivers/acpi/namespace/nsxfname.c
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -84,38 +84,41 @@ acpi_get_handle(acpi_handle parent,
/* Convert a parent handle to a prefix node */
if (parent) {
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
prefix_node = acpi_ns_map_handle_to_node(parent);
if (!prefix_node) {
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return (AE_BAD_PARAMETER);
}
+ }
+
+ /*
+ * Valid cases are:
+ * 1) Fully qualified pathname
+ * 2) Parent + Relative pathname
+ *
+ * Error for <null Parent + relative path>
+ */
+ if (acpi_ns_valid_root_prefix(pathname[0])) {
- status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
+ /* Pathname is fully qualified (starts with '\') */
+
+ /* Special case for root-only, since we can't search for it */
+
+ if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) {
+ *ret_handle =
+ acpi_ns_convert_entry_to_handle(acpi_gbl_root_node);
+ return (AE_OK);
}
- }
+ } else if (!prefix_node) {
- /* Special case for root, since we can't search for it */
+ /* Relative path with null prefix is disallowed */
- if (ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH) == 0) {
- *ret_handle =
- acpi_ns_convert_entry_to_handle(acpi_gbl_root_node);
- return (AE_OK);
+ return (AE_BAD_PARAMETER);
}
- /*
- * Find the Node and convert to a handle
- */
- status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH,
- &node);
+ /* Find the Node and convert to a handle */
- *ret_handle = NULL;
+ status =
+ acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node);
if (ACPI_SUCCESS(status)) {
*ret_handle = acpi_ns_convert_entry_to_handle(node);
}
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
index a163e1d3708..faa37588720 100644
--- a/drivers/acpi/namespace/nsxfobj.c
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -50,6 +50,50 @@ ACPI_MODULE_NAME("nsxfobj")
/*******************************************************************************
*
+ * FUNCTION: acpi_get_id
+ *
+ * PARAMETERS: Handle - Handle of object whose id is desired
+ * ret_id - Where the id will be placed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This routine returns the owner id associated with a handle
+ *
+ ******************************************************************************/
+acpi_status acpi_get_id(acpi_handle handle, acpi_owner_id * ret_id)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ /* Parameter Validation */
+
+ if (!ret_id) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* Convert and validate the handle */
+
+ node = acpi_ns_map_handle_to_node(handle);
+ if (!node) {
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ return (AE_BAD_PARAMETER);
+ }
+
+ *ret_id = node->owner_id;
+
+ status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ return (status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_id)
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_get_type
*
* PARAMETERS: Handle - Handle of object whose type is desired
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index e5e448edca4..4a9faff4c01 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -45,7 +45,7 @@ int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]
int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
-extern int __init acpi_table_parse_madt_family(enum acpi_table_id id,
+extern int __init acpi_table_parse_madt_family(char *id,
unsigned long madt_size,
int entry_id,
acpi_madt_entry_handler handler,
@@ -89,7 +89,7 @@ void __cpuinit acpi_unmap_pxm_to_node(int node)
node_clear(node, nodes_found_map);
}
-void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
+void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header)
{
ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
@@ -99,36 +99,35 @@ void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
switch (header->type) {
- case ACPI_SRAT_PROCESSOR_AFFINITY:
+ case ACPI_SRAT_TYPE_CPU_AFFINITY:
#ifdef ACPI_DEBUG_OUTPUT
{
- struct acpi_table_processor_affinity *p =
- (struct acpi_table_processor_affinity *)header;
+ struct acpi_srat_cpu_affinity *p =
+ (struct acpi_srat_cpu_affinity *)header;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
- p->apic_id, p->lsapic_eid,
- p->proximity_domain,
- p->flags.
- enabled ? "enabled" : "disabled"));
+ p->apic_id, p->local_sapic_eid,
+ p->proximity_domain_lo,
+ (p->flags & ACPI_SRAT_CPU_ENABLED)?
+ "enabled" : "disabled"));
}
#endif /* ACPI_DEBUG_OUTPUT */
break;
- case ACPI_SRAT_MEMORY_AFFINITY:
+ case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
#ifdef ACPI_DEBUG_OUTPUT
{
- struct acpi_table_memory_affinity *p =
- (struct acpi_table_memory_affinity *)header;
+ struct acpi_srat_mem_affinity *p =
+ (struct acpi_srat_mem_affinity *)header;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n",
- p->base_addr_hi, p->base_addr_lo,
- p->length_hi, p->length_lo,
+ "SRAT Memory (0x%lx length 0x%lx type 0x%x) in proximity domain %d %s%s\n",
+ (unsigned long)p->base_address,
+ (unsigned long)p->length,
p->memory_type, p->proximity_domain,
- p->flags.
- enabled ? "enabled" : "disabled",
- p->flags.
- hot_pluggable ? " hot-pluggable" :
- ""));
+ (p->flags & ACPI_SRAT_MEM_ENABLED)?
+ "enabled" : "disabled",
+ (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)?
+ " hot-pluggable" : ""));
}
#endif /* ACPI_DEBUG_OUTPUT */
break;
@@ -141,18 +140,18 @@ void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
}
}
-static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_slit(struct acpi_table_header *table)
{
struct acpi_table_slit *slit;
u32 localities;
- if (!phys_addr || !size)
+ if (!table)
return -EINVAL;
- slit = (struct acpi_table_slit *)__va(phys_addr);
+ slit = (struct acpi_table_slit *)table;
/* downcast just for %llu vs %lu for i386/ia64 */
- localities = (u32) slit->localities;
+ localities = (u32) slit->locality_count;
acpi_numa_slit_init(slit);
@@ -160,12 +159,12 @@ static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size)
}
static int __init
-acpi_parse_processor_affinity(acpi_table_entry_header * header,
+acpi_parse_processor_affinity(struct acpi_subtable_header * header,
const unsigned long end)
{
- struct acpi_table_processor_affinity *processor_affinity;
+ struct acpi_srat_cpu_affinity *processor_affinity;
- processor_affinity = (struct acpi_table_processor_affinity *)header;
+ processor_affinity = (struct acpi_srat_cpu_affinity *)header;
if (!processor_affinity)
return -EINVAL;
@@ -178,12 +177,12 @@ acpi_parse_processor_affinity(acpi_table_entry_header * header,
}
static int __init
-acpi_parse_memory_affinity(acpi_table_entry_header * header,
+acpi_parse_memory_affinity(struct acpi_subtable_header * header,
const unsigned long end)
{
- struct acpi_table_memory_affinity *memory_affinity;
+ struct acpi_srat_mem_affinity *memory_affinity;
- memory_affinity = (struct acpi_table_memory_affinity *)header;
+ memory_affinity = (struct acpi_srat_mem_affinity *)header;
if (!memory_affinity)
return -EINVAL;
@@ -195,23 +194,23 @@ acpi_parse_memory_affinity(acpi_table_entry_header * header,
return 0;
}
-static int __init acpi_parse_srat(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_srat(struct acpi_table_header *table)
{
struct acpi_table_srat *srat;
- if (!phys_addr || !size)
+ if (!table)
return -EINVAL;
- srat = (struct acpi_table_srat *)__va(phys_addr);
+ srat = (struct acpi_table_srat *)table;
return 0;
}
int __init
-acpi_table_parse_srat(enum acpi_srat_entry_id id,
+acpi_table_parse_srat(enum acpi_srat_type id,
acpi_madt_entry_handler handler, unsigned int max_entries)
{
- return acpi_table_parse_madt_family(ACPI_SRAT,
+ return acpi_table_parse_madt_family(ACPI_SIG_SRAT,
sizeof(struct acpi_table_srat), id,
handler, max_entries);
}
@@ -221,17 +220,17 @@ int __init acpi_numa_init(void)
int result;
/* SRAT: Static Resource Affinity Table */
- result = acpi_table_parse(ACPI_SRAT, acpi_parse_srat);
+ result = acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat);
if (result > 0) {
- result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY,
+ result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
acpi_parse_processor_affinity,
NR_CPUS);
- result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific
+ result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific
}
/* SLIT: System Locality Information Table */
- result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit);
+ result = acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
acpi_numa_arch_fixup();
return 0;
@@ -248,7 +247,7 @@ int acpi_get_pxm(acpi_handle h)
handle = phandle;
status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
if (ACPI_SUCCESS(status))
- return (int)pxm;
+ return pxm;
status = acpi_get_parent(handle, &phandle);
} while (ACPI_SUCCESS(status));
return -1;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 02b30ae6a68..0f6f3bcbc8e 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -36,6 +36,7 @@
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/nmi.h>
+#include <linux/acpi.h>
#include <acpi/acpi.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
@@ -75,6 +76,54 @@ static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq;
+static void __init acpi_request_region (struct acpi_generic_address *addr,
+ unsigned int length, char *desc)
+{
+ struct resource *res;
+
+ if (!addr->address || !length)
+ return;
+
+ if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+ res = request_region(addr->address, length, desc);
+ else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ res = request_mem_region(addr->address, length, desc);
+}
+
+static int __init acpi_reserve_resources(void)
+{
+ acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
+ "ACPI PM1a_EVT_BLK");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length,
+ "ACPI PM1b_EVT_BLK");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length,
+ "ACPI PM1a_CNT_BLK");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length,
+ "ACPI PM1b_CNT_BLK");
+
+ if (acpi_gbl_FADT.pm_timer_length == 4)
+ acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length,
+ "ACPI PM2_CNT_BLK");
+
+ /* Length of GPE blocks must be a non-negative multiple of 2 */
+
+ if (!(acpi_gbl_FADT.gpe0_block_length & 0x1))
+ acpi_request_region(&acpi_gbl_FADT.xgpe0_block,
+ acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK");
+
+ if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
+ acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
+ acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
+
+ return 0;
+}
+device_initcall(acpi_reserve_resources);
+
acpi_status acpi_os_initialize(void)
{
return AE_OK;
@@ -136,53 +185,43 @@ void acpi_os_vprintf(const char *fmt, va_list args)
#endif
}
-acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr)
+acpi_physical_address __init acpi_os_get_root_pointer(void)
{
if (efi_enabled) {
- addr->pointer_type = ACPI_PHYSICAL_POINTER;
if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
- addr->pointer.physical = efi.acpi20;
+ return efi.acpi20;
else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
- addr->pointer.physical = efi.acpi;
+ return efi.acpi;
else {
printk(KERN_ERR PREFIX
"System description tables not found\n");
- return AE_NOT_FOUND;
+ return 0;
}
- } else {
- if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
- printk(KERN_ERR PREFIX
- "System description tables not found\n");
- return AE_NOT_FOUND;
- }
- }
-
- return AE_OK;
+ } else
+ return acpi_find_rsdp();
}
-acpi_status
-acpi_os_map_memory(acpi_physical_address phys, acpi_size size,
- void __iomem ** virt)
+void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
{
if (phys > ULONG_MAX) {
printk(KERN_ERR PREFIX "Cannot map memory that high\n");
- return AE_BAD_PARAMETER;
+ return 0;
}
- /*
- * ioremap checks to ensure this is in reserved space
- */
- *virt = ioremap((unsigned long)phys, size);
-
- if (!*virt)
- return AE_NO_MEMORY;
-
- return AE_OK;
+ if (acpi_gbl_permanent_mmap)
+ /*
+ * ioremap checks to ensure this is in reserved space
+ */
+ return ioremap((unsigned long)phys, size);
+ else
+ return __acpi_map_table((unsigned long)phys, size);
}
EXPORT_SYMBOL_GPL(acpi_os_map_memory);
void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
{
- iounmap(virt);
+ if (acpi_gbl_permanent_mmap) {
+ iounmap(virt);
+ }
}
EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
@@ -254,7 +293,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
* FADT. It may not be the same if an interrupt source override exists
* for the SCI.
*/
- gsi = acpi_fadt.sci_int;
+ gsi = acpi_gbl_FADT.sci_interrupt;
if (acpi_gsi_to_irq(gsi, &irq) < 0) {
printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",
gsi);
@@ -568,6 +607,7 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */
static void acpi_os_execute_deferred(struct work_struct *work)
{
struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
+
if (!dpc) {
printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
return;
@@ -1031,7 +1071,7 @@ acpi_status
acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
{
*cache = kmem_cache_create(name, size, 0, 0, NULL, NULL);
- if (cache == NULL)
+ if (*cache == NULL)
return AE_ERROR;
else
return AE_OK;
@@ -1051,7 +1091,7 @@ acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
acpi_status acpi_os_purge_cache(acpi_cache_t * cache)
{
- (void)kmem_cache_shrink(cache);
+ kmem_cache_shrink(cache);
return (AE_OK);
}
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
index bf88e076c3e..c2b9835c890 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/parser/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c
index e1541db3753..773aee82fbb 100644
--- a/drivers/acpi/parser/psloop.c
+++ b/drivers/acpi/parser/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,12 +42,11 @@
*/
/*
- * Parse the AML and build an operation tree as most interpreters,
- * like Perl, do. Parsing is done by hand rather than with a YACC
- * generated parser to tightly constrain stack and dynamic memory
- * usage. At the same time, parsing is kept flexible and the code
- * fairly compact by parsing based on a list of AML opcode
- * templates in aml_op_info[]
+ * Parse the AML and build an operation tree as most interpreters, (such as
+ * Perl) do. Parsing is done by hand rather than with a YACC generated parser
+ * to tightly constrain stack and dynamic memory usage. Parsing is kept
+ * flexible and the code fairly compact by parsing based on a list of AML
+ * opcode templates in aml_op_info[].
*/
#include <acpi/acpi.h>
@@ -60,766 +59,679 @@ ACPI_MODULE_NAME("psloop")
static u32 acpi_gbl_depth = 0;
+/* Local prototypes */
+
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state);
+
+static acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start,
+ union acpi_parse_object *unnamed_op,
+ union acpi_parse_object **op);
+
+static acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object **new_op);
+
+static acpi_status
+acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object *op);
+
+static acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **op, acpi_status status);
+
+static acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op, acpi_status status);
+
/*******************************************************************************
*
- * FUNCTION: acpi_ps_parse_loop
+ * FUNCTION: acpi_ps_get_aml_opcode
*
* PARAMETERS: walk_state - Current state
*
* RETURN: Status
*
- * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
- * a tree of ops.
+ * DESCRIPTION: Extract the next AML opcode from the input stream.
*
******************************************************************************/
-acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state)
{
- acpi_status status = AE_OK;
- acpi_status status2;
- union acpi_parse_object *op = NULL; /* current op */
- union acpi_parse_object *arg = NULL;
- union acpi_parse_object *pre_op = NULL;
- struct acpi_parse_state *parser_state;
- u8 *aml_op_start = NULL;
- ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state);
- if (walk_state->descending_callback == NULL) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
+ walk_state->aml_offset =
+ (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
+ walk_state->parser_state.aml_start);
+ walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state));
- parser_state = &walk_state->parser_state;
- walk_state->arg_types = 0;
+ /*
+ * First cut to determine what we have found:
+ * 1) A valid AML opcode
+ * 2) A name string
+ * 3) An unknown/invalid opcode
+ */
+ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
-#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+ switch (walk_state->op_info->class) {
+ case AML_CLASS_ASCII:
+ case AML_CLASS_PREFIX:
+ /*
+ * Starts with a valid prefix or ASCII char, this is a name
+ * string. Convert the bare name string to a namepath.
+ */
+ walk_state->opcode = AML_INT_NAMEPATH_OP;
+ walk_state->arg_types = ARGP_NAMESTRING;
+ break;
- if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
+ case AML_CLASS_UNKNOWN:
- /* We are restarting a preempted control method */
+ /* The opcode is unrecognized. Just skip unknown opcodes */
- if (acpi_ps_has_completed_scope(parser_state)) {
- /*
- * We must check if a predicate to an IF or WHILE statement
- * was just completed
- */
- if ((parser_state->scope->parse_scope.op) &&
- ((parser_state->scope->parse_scope.op->common.
- aml_opcode == AML_IF_OP)
- || (parser_state->scope->parse_scope.op->common.
- aml_opcode == AML_WHILE_OP))
- && (walk_state->control_state)
- && (walk_state->control_state->common.state ==
- ACPI_CONTROL_PREDICATE_EXECUTING)) {
- /*
- * A predicate was just completed, get the value of the
- * predicate and branch based on that value
- */
- walk_state->op = NULL;
- status =
- acpi_ds_get_predicate_value(walk_state,
- ACPI_TO_POINTER
- (TRUE));
- if (ACPI_FAILURE(status)
- && ((status & AE_CODE_MASK) !=
- AE_CODE_CONTROL)) {
- if (status == AE_AML_NO_RETURN_VALUE) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Invoked method did not return a value"));
+ ACPI_ERROR((AE_INFO,
+ "Found unknown opcode %X at AML address %p offset %X, ignoring",
+ walk_state->opcode, walk_state->parser_state.aml,
+ walk_state->aml_offset));
- }
- ACPI_EXCEPTION((AE_INFO, status,
- "GetPredicate Failed"));
- return_ACPI_STATUS(status);
- }
+ ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128);
- status =
- acpi_ps_next_parse_state(walk_state, op,
- status);
- }
+ /* Assume one-byte bad opcode */
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Popped scope, Op=%p\n", op));
- } else if (walk_state->prev_op) {
+ walk_state->parser_state.aml++;
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
- /* We were in the middle of an op */
+ default:
- op = walk_state->prev_op;
- walk_state->arg_types = walk_state->prev_arg_types;
- }
+ /* Found opcode info, this is a normal opcode */
+
+ walk_state->parser_state.aml +=
+ acpi_ps_get_opcode_size(walk_state->opcode);
+ walk_state->arg_types = walk_state->op_info->parse_args;
+ break;
}
-#endif
- /* Iterative parsing loop, while there is more AML to process: */
+ return_ACPI_STATUS(AE_OK);
+}
- while ((parser_state->aml < parser_state->aml_end) || (op)) {
- aml_op_start = parser_state->aml;
- if (!op) {
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_build_named_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * aml_op_start - Begin of named Op in AML
+ * unnamed_op - Early Op (not a named Op)
+ * Op - Returned Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse a named Op
+ *
+ ******************************************************************************/
- /* Get the next opcode from the AML stream */
+static acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start,
+ union acpi_parse_object *unnamed_op,
+ union acpi_parse_object **op)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *arg = NULL;
- walk_state->aml_offset =
- (u32) ACPI_PTR_DIFF(parser_state->aml,
- parser_state->aml_start);
- walk_state->opcode = acpi_ps_peek_opcode(parser_state);
+ ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
- /*
- * First cut to determine what we have found:
- * 1) A valid AML opcode
- * 2) A name string
- * 3) An unknown/invalid opcode
- */
- walk_state->op_info =
- acpi_ps_get_opcode_info(walk_state->opcode);
- switch (walk_state->op_info->class) {
- case AML_CLASS_ASCII:
- case AML_CLASS_PREFIX:
- /*
- * Starts with a valid prefix or ASCII char, this is a name
- * string. Convert the bare name string to a namepath.
- */
- walk_state->opcode = AML_INT_NAMEPATH_OP;
- walk_state->arg_types = ARGP_NAMESTRING;
- break;
+ unnamed_op->common.value.arg = NULL;
+ unnamed_op->common.aml_opcode = walk_state->opcode;
- case AML_CLASS_UNKNOWN:
+ /*
+ * Get and append arguments until we find the node that contains
+ * the name (the type ARGP_NAME).
+ */
+ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) &&
+ (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) {
+ status =
+ acpi_ps_get_next_arg(walk_state,
+ &(walk_state->parser_state),
+ GET_CURRENT_ARG_TYPE(walk_state->
+ arg_types), &arg);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- /* The opcode is unrecognized. Just skip unknown opcodes */
+ acpi_ps_append_arg(unnamed_op, arg);
+ INCREMENT_ARG_LIST(walk_state->arg_types);
+ }
- ACPI_ERROR((AE_INFO,
- "Found unknown opcode %X at AML address %p offset %X, ignoring",
- walk_state->opcode,
- parser_state->aml,
- walk_state->aml_offset));
+ /*
+ * Make sure that we found a NAME and didn't run out of arguments
+ */
+ if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) {
+ return_ACPI_STATUS(AE_AML_NO_OPERAND);
+ }
- ACPI_DUMP_BUFFER(parser_state->aml, 128);
+ /* We know that this arg is a name, move to next arg */
- /* Assume one-byte bad opcode */
+ INCREMENT_ARG_LIST(walk_state->arg_types);
- parser_state->aml++;
- continue;
+ /*
+ * Find the object. This will either insert the object into
+ * the namespace or simply look it up
+ */
+ walk_state->op = NULL;
- default:
+ status = walk_state->descending_callback(walk_state, op);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog"));
+ return_ACPI_STATUS(status);
+ }
- /* Found opcode info, this is a normal opcode */
+ if (!*op) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+ }
- parser_state->aml +=
- acpi_ps_get_opcode_size(walk_state->opcode);
- walk_state->arg_types =
- walk_state->op_info->parse_args;
- break;
- }
+ status = acpi_ps_next_parse_state(walk_state, *op, status);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_CTRL_PENDING) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_PENDING);
+ }
+ return_ACPI_STATUS(status);
+ }
- /* Create Op structure and append to parent's argument list */
+ acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
+ acpi_gbl_depth++;
- if (walk_state->op_info->flags & AML_NAMED) {
+ if ((*op)->common.aml_opcode == AML_REGION_OP) {
+ /*
+ * Defer final parsing of an operation_region body, because we don't
+ * have enough info in the first pass to parse it correctly (i.e.,
+ * there may be method calls within the term_arg elements of the body.)
+ *
+ * However, we must continue parsing because the opregion is not a
+ * standalone package -- we don't know where the end is at this point.
+ *
+ * (Length is unknown until parse of the body complete)
+ */
+ (*op)->named.data = aml_op_start;
+ (*op)->named.length = 0;
+ }
- /* Allocate a new pre_op if necessary */
+ return_ACPI_STATUS(AE_OK);
+}
- if (!pre_op) {
- pre_op =
- acpi_ps_alloc_op(walk_state->
- opcode);
- if (!pre_op) {
- status = AE_NO_MEMORY;
- goto close_this_op;
- }
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_create_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * aml_op_start - Op start in AML
+ * new_op - Returned Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get Op from AML
+ *
+ ******************************************************************************/
- pre_op->common.value.arg = NULL;
- pre_op->common.aml_opcode = walk_state->opcode;
+static acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object **new_op)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op;
+ union acpi_parse_object *named_op = NULL;
- /*
- * Get and append arguments until we find the node that contains
- * the name (the type ARGP_NAME).
- */
- while (GET_CURRENT_ARG_TYPE
- (walk_state->arg_types)
- &&
- (GET_CURRENT_ARG_TYPE
- (walk_state->arg_types) != ARGP_NAME)) {
- status =
- acpi_ps_get_next_arg(walk_state,
- parser_state,
- GET_CURRENT_ARG_TYPE
- (walk_state->
- arg_types),
- &arg);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
+ ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
- acpi_ps_append_arg(pre_op, arg);
- INCREMENT_ARG_LIST(walk_state->
- arg_types);
- }
+ status = acpi_ps_get_aml_opcode(walk_state);
+ if (status == AE_CTRL_PARSE_CONTINUE) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+ }
- /*
- * Make sure that we found a NAME and didn't run out of
- * arguments
- */
- if (!GET_CURRENT_ARG_TYPE
- (walk_state->arg_types)) {
- status = AE_AML_NO_OPERAND;
- goto close_this_op;
- }
+ /* Create Op structure and append to parent's argument list */
- /* We know that this arg is a name, move to next arg */
+ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
+ op = acpi_ps_alloc_op(walk_state->opcode);
+ if (!op) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
- INCREMENT_ARG_LIST(walk_state->arg_types);
+ if (walk_state->op_info->flags & AML_NAMED) {
+ status =
+ acpi_ps_build_named_op(walk_state, aml_op_start, op,
+ &named_op);
+ acpi_ps_free_op(op);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- /*
- * Find the object. This will either insert the object into
- * the namespace or simply look it up
- */
- walk_state->op = NULL;
+ *new_op = named_op;
+ return_ACPI_STATUS(AE_OK);
+ }
- status =
- walk_state->descending_callback(walk_state,
- &op);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "During name lookup/catalog"));
- goto close_this_op;
- }
+ /* Not a named opcode, just allocate Op and append to parent */
- if (!op) {
- continue;
- }
+ if (walk_state->op_info->flags & AML_CREATE) {
+ /*
+ * Backup to beginning of create_xXXfield declaration
+ * body_length is unknown until we parse the body
+ */
+ op->named.data = aml_op_start;
+ op->named.length = 0;
+ }
- status =
- acpi_ps_next_parse_state(walk_state, op,
- status);
- if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
- }
+ acpi_ps_append_arg(acpi_ps_get_parent_scope
+ (&(walk_state->parser_state)), op);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
+ if (walk_state->descending_callback != NULL) {
+ /*
+ * Find the object. This will either insert the object into
+ * the namespace or simply look it up
+ */
+ walk_state->op = *new_op = op;
- acpi_ps_append_arg(op,
- pre_op->common.value.arg);
- acpi_gbl_depth++;
-
- if (op->common.aml_opcode == AML_REGION_OP) {
- /*
- * Defer final parsing of an operation_region body,
- * because we don't have enough info in the first pass
- * to parse it correctly (i.e., there may be method
- * calls within the term_arg elements of the body.)
- *
- * However, we must continue parsing because
- * the opregion is not a standalone package --
- * we don't know where the end is at this point.
- *
- * (Length is unknown until parse of the body complete)
- */
- op->named.data = aml_op_start;
- op->named.length = 0;
- }
- } else {
- /* Not a named opcode, just allocate Op and append to parent */
+ status = walk_state->descending_callback(walk_state, &op);
+ status = acpi_ps_next_parse_state(walk_state, op, status);
+ if (status == AE_CTRL_PENDING) {
+ status = AE_CTRL_PARSE_PENDING;
+ }
+ }
- walk_state->op_info =
- acpi_ps_get_opcode_info(walk_state->opcode);
- op = acpi_ps_alloc_op(walk_state->opcode);
- if (!op) {
- status = AE_NO_MEMORY;
- goto close_this_op;
- }
+ return_ACPI_STATUS(status);
+}
- if (walk_state->op_info->flags & AML_CREATE) {
- /*
- * Backup to beginning of create_xXXfield declaration
- * body_length is unknown until we parse the body
- */
- op->named.data = aml_op_start;
- op->named.length = 0;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_arguments
+ *
+ * PARAMETERS: walk_state - Current state
+ * aml_op_start - Op start in AML
+ * Op - Current Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get arguments for passed Op.
+ *
+ ******************************************************************************/
- acpi_ps_append_arg(acpi_ps_get_parent_scope
- (parser_state), op);
+static acpi_status
+acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object *op)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *arg = NULL;
- if ((walk_state->descending_callback != NULL)) {
- /*
- * Find the object. This will either insert the object into
- * the namespace or simply look it up
- */
- walk_state->op = op;
+ ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state);
- status =
- walk_state->
- descending_callback(walk_state,
- &op);
- status =
- acpi_ps_next_parse_state(walk_state,
- op,
- status);
- if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
- }
+ switch (op->common.aml_opcode) {
+ case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
+ case AML_WORD_OP: /* AML_WORDDATA_ARG */
+ case AML_DWORD_OP: /* AML_DWORDATA_ARG */
+ case AML_QWORD_OP: /* AML_QWORDATA_ARG */
+ case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
- }
- }
+ /* Fill in constant or string argument directly */
- op->common.aml_offset = walk_state->aml_offset;
+ acpi_ps_get_next_simple_arg(&(walk_state->parser_state),
+ GET_CURRENT_ARG_TYPE(walk_state->
+ arg_types),
+ op);
+ break;
- if (walk_state->op_info) {
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n",
- (u32) op->common.aml_opcode,
- walk_state->op_info->name, op,
- parser_state->aml,
- op->common.aml_offset));
- }
+ case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */
+
+ status =
+ acpi_ps_get_next_namepath(walk_state,
+ &(walk_state->parser_state), op,
+ 1);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
}
+ walk_state->arg_types = 0;
+ break;
+
+ default:
/*
- * Start arg_count at zero because we don't know if there are
- * any args yet
+ * Op is not a constant or string, append each argument to the Op
*/
- walk_state->arg_count = 0;
-
- /* Are there any arguments that must be processed? */
-
- if (walk_state->arg_types) {
-
- /* Get arguments */
-
- switch (op->common.aml_opcode) {
- case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
- case AML_WORD_OP: /* AML_WORDDATA_ARG */
- case AML_DWORD_OP: /* AML_DWORDATA_ARG */
- case AML_QWORD_OP: /* AML_QWORDATA_ARG */
- case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */
-
- /* Fill in constant or string argument directly */
-
- acpi_ps_get_next_simple_arg(parser_state,
- GET_CURRENT_ARG_TYPE
- (walk_state->
- arg_types), op);
- break;
-
- case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */
-
- status =
- acpi_ps_get_next_namepath(walk_state,
- parser_state, op,
- 1);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
-
- walk_state->arg_types = 0;
- break;
+ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types)
+ && !walk_state->arg_count) {
+ walk_state->aml_offset =
+ (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
+ walk_state->parser_state.
+ aml_start);
- default:
- /*
- * Op is not a constant or string, append each argument
- * to the Op
- */
- while (GET_CURRENT_ARG_TYPE
- (walk_state->arg_types)
- && !walk_state->arg_count) {
- walk_state->aml_offset = (u32)
- ACPI_PTR_DIFF(parser_state->aml,
- parser_state->
- aml_start);
+ status =
+ acpi_ps_get_next_arg(walk_state,
+ &(walk_state->parser_state),
+ GET_CURRENT_ARG_TYPE
+ (walk_state->arg_types), &arg);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- status =
- acpi_ps_get_next_arg(walk_state,
- parser_state,
- GET_CURRENT_ARG_TYPE
- (walk_state->
- arg_types),
- &arg);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
+ if (arg) {
+ arg->common.aml_offset = walk_state->aml_offset;
+ acpi_ps_append_arg(op, arg);
+ }
- if (arg) {
- arg->common.aml_offset =
- walk_state->aml_offset;
- acpi_ps_append_arg(op, arg);
- }
- INCREMENT_ARG_LIST(walk_state->
- arg_types);
- }
+ INCREMENT_ARG_LIST(walk_state->arg_types);
+ }
- /* Special processing for certain opcodes */
+ /* Special processing for certain opcodes */
- /* TBD (remove): Temporary mechanism to disable this code if needed */
+ /* TBD (remove): Temporary mechanism to disable this code if needed */
#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
- if ((walk_state->pass_number <=
- ACPI_IMODE_LOAD_PASS1)
- &&
- ((walk_state->
- parse_flags & ACPI_PARSE_DISASSEMBLE) ==
- 0)) {
- /*
- * We want to skip If/Else/While constructs during Pass1
- * because we want to actually conditionally execute the
- * code during Pass2.
- *
- * Except for disassembly, where we always want to
- * walk the If/Else/While packages
- */
- switch (op->common.aml_opcode) {
- case AML_IF_OP:
- case AML_ELSE_OP:
- case AML_WHILE_OP:
-
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Pass1: Skipping an If/Else/While body\n"));
-
- /* Skip body of if/else/while in pass 1 */
-
- parser_state->aml =
- parser_state->pkg_end;
- walk_state->arg_count = 0;
- break;
-
- default:
- break;
- }
- }
-#endif
- switch (op->common.aml_opcode) {
- case AML_METHOD_OP:
-
- /*
- * Skip parsing of control method
- * because we don't have enough info in the first pass
- * to parse it correctly.
- *
- * Save the length and address of the body
- */
- op->named.data = parser_state->aml;
- op->named.length =
- (u32) (parser_state->pkg_end -
- parser_state->aml);
-
- /* Skip body of method */
-
- parser_state->aml =
- parser_state->pkg_end;
- walk_state->arg_count = 0;
- break;
-
- case AML_BUFFER_OP:
- case AML_PACKAGE_OP:
- case AML_VAR_PACKAGE_OP:
-
- if ((op->common.parent) &&
- (op->common.parent->common.
- aml_opcode == AML_NAME_OP)
- && (walk_state->pass_number <=
- ACPI_IMODE_LOAD_PASS2)) {
- /*
- * Skip parsing of Buffers and Packages
- * because we don't have enough info in the first pass
- * to parse them correctly.
- */
- op->named.data = aml_op_start;
- op->named.length =
- (u32) (parser_state->
- pkg_end -
- aml_op_start);
-
- /* Skip body */
-
- parser_state->aml =
- parser_state->pkg_end;
- walk_state->arg_count = 0;
- }
- break;
+ if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) &&
+ ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) {
+ /*
+ * We want to skip If/Else/While constructs during Pass1 because we
+ * want to actually conditionally execute the code during Pass2.
+ *
+ * Except for disassembly, where we always want to walk the
+ * If/Else/While packages
+ */
+ switch (op->common.aml_opcode) {
+ case AML_IF_OP:
+ case AML_ELSE_OP:
+ case AML_WHILE_OP:
- case AML_WHILE_OP:
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Pass1: Skipping an If/Else/While body\n"));
- if (walk_state->control_state) {
- walk_state->control_state->
- control.package_end =
- parser_state->pkg_end;
- }
- break;
+ /* Skip body of if/else/while in pass 1 */
- default:
+ walk_state->parser_state.aml =
+ walk_state->parser_state.pkg_end;
+ walk_state->arg_count = 0;
+ break;
- /* No action for all other opcodes */
- break;
- }
+ default:
break;
}
}
+#endif
- /* Check for arguments that need to be processed */
-
- if (walk_state->arg_count) {
+ switch (op->common.aml_opcode) {
+ case AML_METHOD_OP:
/*
- * There are arguments (complex ones), push Op and
- * prepare for argument
+ * Skip parsing of control method because we don't have enough
+ * info in the first pass to parse it correctly.
+ *
+ * Save the length and address of the body
*/
- status = acpi_ps_push_scope(parser_state, op,
- walk_state->arg_types,
- walk_state->arg_count);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
- op = NULL;
- continue;
- }
+ op->named.data = walk_state->parser_state.aml;
+ op->named.length = (u32)
+ (walk_state->parser_state.pkg_end -
+ walk_state->parser_state.aml);
- /*
- * All arguments have been processed -- Op is complete,
- * prepare for next
- */
- walk_state->op_info =
- acpi_ps_get_opcode_info(op->common.aml_opcode);
- if (walk_state->op_info->flags & AML_NAMED) {
- if (acpi_gbl_depth) {
- acpi_gbl_depth--;
- }
+ /* Skip body of method */
- if (op->common.aml_opcode == AML_REGION_OP) {
+ walk_state->parser_state.aml =
+ walk_state->parser_state.pkg_end;
+ walk_state->arg_count = 0;
+ break;
+
+ case AML_BUFFER_OP:
+ case AML_PACKAGE_OP:
+ case AML_VAR_PACKAGE_OP:
+
+ if ((op->common.parent) &&
+ (op->common.parent->common.aml_opcode ==
+ AML_NAME_OP)
+ && (walk_state->pass_number <=
+ ACPI_IMODE_LOAD_PASS2)) {
/*
- * Skip parsing of control method or opregion body,
- * because we don't have enough info in the first pass
- * to parse them correctly.
- *
- * Completed parsing an op_region declaration, we now
- * know the length.
+ * Skip parsing of Buffers and Packages because we don't have
+ * enough info in the first pass to parse them correctly.
*/
- op->named.length =
- (u32) (parser_state->aml - op->named.data);
- }
- }
+ op->named.data = aml_op_start;
+ op->named.length = (u32)
+ (walk_state->parser_state.pkg_end -
+ aml_op_start);
- if (walk_state->op_info->flags & AML_CREATE) {
- /*
- * Backup to beginning of create_xXXfield declaration (1 for
- * Opcode)
- *
- * body_length is unknown until we parse the body
- */
- op->named.length =
- (u32) (parser_state->aml - op->named.data);
- }
+ /* Skip body */
- /* This op complete, notify the dispatcher */
+ walk_state->parser_state.aml =
+ walk_state->parser_state.pkg_end;
+ walk_state->arg_count = 0;
+ }
+ break;
- if (walk_state->ascending_callback != NULL) {
- walk_state->op = op;
- walk_state->opcode = op->common.aml_opcode;
+ case AML_WHILE_OP:
- status = walk_state->ascending_callback(walk_state);
- status =
- acpi_ps_next_parse_state(walk_state, op, status);
- if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
+ if (walk_state->control_state) {
+ walk_state->control_state->control.package_end =
+ walk_state->parser_state.pkg_end;
}
- }
-
- close_this_op:
- /*
- * Finished one argument of the containing scope
- */
- parser_state->scope->parse_scope.arg_count--;
+ break;
- /* Finished with pre_op */
+ default:
- if (pre_op) {
- acpi_ps_free_op(pre_op);
- pre_op = NULL;
+ /* No action for all other opcodes */
+ break;
}
- /* Close this Op (will result in parse subtree deletion) */
+ break;
+ }
- status2 = acpi_ps_complete_this_op(walk_state, op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- op = NULL;
+ return_ACPI_STATUS(AE_OK);
+}
- switch (status) {
- case AE_OK:
- break;
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_complete_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * Op - Returned Op
+ * Status - Parse status before complete Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Complete Op
+ *
+ ******************************************************************************/
- case AE_CTRL_TRANSFER:
+static acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **op, acpi_status status)
+{
+ acpi_status status2;
- /* We are about to transfer to a called method. */
+ ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state);
- walk_state->prev_op = op;
- walk_state->prev_arg_types = walk_state->arg_types;
- return_ACPI_STATUS(status);
+ /*
+ * Finished one argument of the containing scope
+ */
+ walk_state->parser_state.scope->parse_scope.arg_count--;
- case AE_CTRL_END:
+ /* Close this Op (will result in parse subtree deletion) */
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
- if (op) {
- walk_state->op = op;
- walk_state->op_info =
- acpi_ps_get_opcode_info(op->common.
- aml_opcode);
- walk_state->opcode = op->common.aml_opcode;
+ *op = NULL;
- status =
- walk_state->ascending_callback(walk_state);
- status =
- acpi_ps_next_parse_state(walk_state, op,
- status);
+ switch (status) {
+ case AE_OK:
+ break;
- status2 =
- acpi_ps_complete_this_op(walk_state, op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- op = NULL;
- }
- status = AE_OK;
- break;
+ case AE_CTRL_TRANSFER:
- case AE_CTRL_BREAK:
- case AE_CTRL_CONTINUE:
+ /* We are about to transfer to a called method */
- /* Pop off scopes until we find the While */
+ walk_state->prev_op = NULL;
+ walk_state->prev_arg_types = walk_state->arg_types;
+ return_ACPI_STATUS(status);
- while (!op || (op->common.aml_opcode != AML_WHILE_OP)) {
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ case AE_CTRL_END:
- if (op->common.aml_opcode != AML_WHILE_OP) {
- status2 =
- acpi_ds_result_stack_pop
- (walk_state);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- }
- }
-
- /* Close this iteration of the While loop */
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- walk_state->op = op;
+ if (*op) {
+ walk_state->op = *op;
walk_state->op_info =
- acpi_ps_get_opcode_info(op->common.aml_opcode);
- walk_state->opcode = op->common.aml_opcode;
+ acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+ walk_state->opcode = (*op)->common.aml_opcode;
status = walk_state->ascending_callback(walk_state);
status =
- acpi_ps_next_parse_state(walk_state, op, status);
+ acpi_ps_next_parse_state(walk_state, *op, status);
- status2 = acpi_ps_complete_this_op(walk_state, op);
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
if (ACPI_FAILURE(status2)) {
return_ACPI_STATUS(status2);
}
- op = NULL;
-
- status = AE_OK;
- break;
+ }
- case AE_CTRL_TERMINATE:
+ status = AE_OK;
+ break;
- status = AE_OK;
+ case AE_CTRL_BREAK:
+ case AE_CTRL_CONTINUE:
- /* Clean up */
- do {
- if (op) {
- status2 =
- acpi_ps_complete_this_op(walk_state,
- op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ /* Pop off scopes until we find the While */
- status2 =
- acpi_ds_result_stack_pop
- (walk_state);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) {
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- acpi_ut_delete_generic_state
- (acpi_ut_pop_generic_state
- (&walk_state->control_state));
+ if ((*op)->common.aml_opcode != AML_WHILE_OP) {
+ status2 = acpi_ds_result_stack_pop(walk_state);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
}
+ }
+ }
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ /* Close this iteration of the While loop */
- } while (op);
+ walk_state->op = *op;
+ walk_state->op_info =
+ acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+ walk_state->opcode = (*op)->common.aml_opcode;
- return_ACPI_STATUS(status);
+ status = walk_state->ascending_callback(walk_state);
+ status = acpi_ps_next_parse_state(walk_state, *op, status);
- default: /* All other non-AE_OK status */
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
- do {
- if (op) {
- status2 =
- acpi_ps_complete_this_op(walk_state,
- op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ status = AE_OK;
+ break;
+
+ case AE_CTRL_TERMINATE:
+
+ /* Clean up */
+ do {
+ if (*op) {
+ status2 =
+ acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
+ status2 = acpi_ds_result_stack_pop(walk_state);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
}
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ acpi_ut_delete_generic_state
+ (acpi_ut_pop_generic_state
+ (&walk_state->control_state));
+ }
- } while (op);
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- /*
- * TBD: Cleanup parse ops on error
- */
-#if 0
- if (op == NULL) {
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ } while (*op);
+
+ return_ACPI_STATUS(AE_OK);
+
+ default: /* All other non-AE_OK status */
+
+ do {
+ if (*op) {
+ status2 =
+ acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
}
-#endif
- walk_state->prev_op = op;
- walk_state->prev_arg_types = walk_state->arg_types;
- return_ACPI_STATUS(status);
- }
- /* This scope complete? */
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- if (acpi_ps_has_completed_scope(parser_state)) {
- acpi_ps_pop_scope(parser_state, &op,
+ } while (*op);
+
+#if 0
+ /*
+ * TBD: Cleanup parse ops on error
+ */
+ if (*op == NULL) {
+ acpi_ps_pop_scope(parser_state, op,
&walk_state->arg_types,
&walk_state->arg_count);
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Popped scope, Op=%p\n", op));
- } else {
- op = NULL;
}
+#endif
+ walk_state->prev_op = NULL;
+ walk_state->prev_arg_types = walk_state->arg_types;
+ return_ACPI_STATUS(status);
+ }
- } /* while parser_state->Aml */
+ /* This scope complete? */
+
+ if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) {
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op));
+ } else {
+ *op = NULL;
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_complete_final_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * Op - Current Op
+ * Status - Current parse status before complete last
+ * Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Complete last Op.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op, acpi_status status)
+{
+ acpi_status status2;
+
+ ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state);
/*
* Complete the last Op (if not completed), and clear the scope stack.
* It is easily possible to end an AML "package" with an unbounded number
* of open scopes (such as when several ASL blocks are closed with
- * sequential closing braces). We want to terminate each one cleanly.
+ * sequential closing braces). We want to terminate each one cleanly.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n",
op));
@@ -838,8 +750,12 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
acpi_ps_next_parse_state(walk_state, op,
status);
if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ AE_OK);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
if (status == AE_CTRL_TERMINATE) {
@@ -858,7 +774,9 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
}
}
- acpi_ps_pop_scope(parser_state,
+ acpi_ps_pop_scope(&
+ (walk_state->
+ parser_state),
&op,
&walk_state->
arg_types,
@@ -887,10 +805,252 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
}
}
- acpi_ps_pop_scope(parser_state, &op, &walk_state->arg_types,
+ acpi_ps_pop_scope(&(walk_state->parser_state), &op,
+ &walk_state->arg_types,
&walk_state->arg_count);
} while (op);
return_ACPI_STATUS(status);
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_parse_loop
+ *
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
+ * a tree of ops.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op = NULL; /* current op */
+ struct acpi_parse_state *parser_state;
+ u8 *aml_op_start = NULL;
+
+ ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state);
+
+ if (walk_state->descending_callback == NULL) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ parser_state = &walk_state->parser_state;
+ walk_state->arg_types = 0;
+
+#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+
+ if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
+
+ /* We are restarting a preempted control method */
+
+ if (acpi_ps_has_completed_scope(parser_state)) {
+ /*
+ * We must check if a predicate to an IF or WHILE statement
+ * was just completed
+ */
+ if ((parser_state->scope->parse_scope.op) &&
+ ((parser_state->scope->parse_scope.op->common.
+ aml_opcode == AML_IF_OP)
+ || (parser_state->scope->parse_scope.op->common.
+ aml_opcode == AML_WHILE_OP))
+ && (walk_state->control_state)
+ && (walk_state->control_state->common.state ==
+ ACPI_CONTROL_PREDICATE_EXECUTING)) {
+ /*
+ * A predicate was just completed, get the value of the
+ * predicate and branch based on that value
+ */
+ walk_state->op = NULL;
+ status =
+ acpi_ds_get_predicate_value(walk_state,
+ ACPI_TO_POINTER
+ (TRUE));
+ if (ACPI_FAILURE(status)
+ && ((status & AE_CODE_MASK) !=
+ AE_CODE_CONTROL)) {
+ if (status == AE_AML_NO_RETURN_VALUE) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Invoked method did not return a value"));
+
+ }
+
+ ACPI_EXCEPTION((AE_INFO, status,
+ "GetPredicate Failed"));
+ return_ACPI_STATUS(status);
+ }
+
+ status =
+ acpi_ps_next_parse_state(walk_state, op,
+ status);
+ }
+
+ acpi_ps_pop_scope(parser_state, &op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Popped scope, Op=%p\n", op));
+ } else if (walk_state->prev_op) {
+
+ /* We were in the middle of an op */
+
+ op = walk_state->prev_op;
+ walk_state->arg_types = walk_state->prev_arg_types;
+ }
+ }
+#endif
+
+ /* Iterative parsing loop, while there is more AML to process: */
+
+ while ((parser_state->aml < parser_state->aml_end) || (op)) {
+ aml_op_start = parser_state->aml;
+ if (!op) {
+ status =
+ acpi_ps_create_op(walk_state, aml_op_start, &op);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_CTRL_PARSE_CONTINUE) {
+ continue;
+ }
+
+ if (status == AE_CTRL_PARSE_PENDING) {
+ status = AE_OK;
+ }
+
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ continue;
+ }
+
+ op->common.aml_offset = walk_state->aml_offset;
+
+ if (walk_state->op_info) {
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n",
+ (u32) op->common.aml_opcode,
+ walk_state->op_info->name, op,
+ parser_state->aml,
+ op->common.aml_offset));
+ }
+ }
+
+ /*
+ * Start arg_count at zero because we don't know if there are
+ * any args yet
+ */
+ walk_state->arg_count = 0;
+
+ /* Are there any arguments that must be processed? */
+
+ if (walk_state->arg_types) {
+
+ /* Get arguments */
+
+ status =
+ acpi_ps_get_arguments(walk_state, aml_op_start, op);
+ if (ACPI_FAILURE(status)) {
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ continue;
+ }
+ }
+
+ /* Check for arguments that need to be processed */
+
+ if (walk_state->arg_count) {
+ /*
+ * There are arguments (complex ones), push Op and
+ * prepare for argument
+ */
+ status = acpi_ps_push_scope(parser_state, op,
+ walk_state->arg_types,
+ walk_state->arg_count);
+ if (ACPI_FAILURE(status)) {
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ continue;
+ }
+
+ op = NULL;
+ continue;
+ }
+
+ /*
+ * All arguments have been processed -- Op is complete,
+ * prepare for next
+ */
+ walk_state->op_info =
+ acpi_ps_get_opcode_info(op->common.aml_opcode);
+ if (walk_state->op_info->flags & AML_NAMED) {
+ if (acpi_gbl_depth) {
+ acpi_gbl_depth--;
+ }
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ /*
+ * Skip parsing of control method or opregion body,
+ * because we don't have enough info in the first pass
+ * to parse them correctly.
+ *
+ * Completed parsing an op_region declaration, we now
+ * know the length.
+ */
+ op->named.length =
+ (u32) (parser_state->aml - op->named.data);
+ }
+ }
+
+ if (walk_state->op_info->flags & AML_CREATE) {
+ /*
+ * Backup to beginning of create_xXXfield declaration (1 for
+ * Opcode)
+ *
+ * body_length is unknown until we parse the body
+ */
+ op->named.length =
+ (u32) (parser_state->aml - op->named.data);
+ }
+
+ /* This op complete, notify the dispatcher */
+
+ if (walk_state->ascending_callback != NULL) {
+ walk_state->op = op;
+ walk_state->opcode = op->common.aml_opcode;
+
+ status = walk_state->ascending_callback(walk_state);
+ status =
+ acpi_ps_next_parse_state(walk_state, op, status);
+ if (status == AE_CTRL_PENDING) {
+ status = AE_OK;
+ }
+ }
+
+ status = acpi_ps_complete_op(walk_state, &op, status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ } /* while parser_state->Aml */
+
+ status = acpi_ps_complete_final_op(walk_state, op, status);
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
index 4bd25e32769..16d8b6cc3c2 100644
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/parser/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index a02aa62fe1e..5d63f48e56b 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -540,6 +540,11 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
if ((status == AE_ALREADY_EXISTS) &&
(!walk_state->method_desc->method.mutex)) {
+ ACPI_INFO((AE_INFO,
+ "Marking method %4.4s as Serialized",
+ walk_state->method_node->name.
+ ascii));
+
/*
* Method tried to create an object twice. The probable cause is
* that the method cannot handle reentrancy.
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
index a3e0314de24..77cfa4ed0cf 100644
--- a/drivers/acpi/parser/psscope.c
+++ b/drivers/acpi/parser/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c
index 0015717ef09..966e7ea2a0c 100644
--- a/drivers/acpi/parser/pstree.c
+++ b/drivers/acpi/parser/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
index d405387b741..8ca52002db5 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/parser/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
index a84a547a0f1..49f9757434e 100644
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/parser/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
index 5d996c1140a..94103bced75 100644
--- a/drivers/acpi/parser/psxface.c
+++ b/drivers/acpi/parser/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,8 +54,6 @@ static void acpi_ps_start_trace(struct acpi_evaluate_info *info);
static void acpi_ps_stop_trace(struct acpi_evaluate_info *info);
-static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info);
-
static void
acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action);
@@ -215,6 +213,8 @@ static void acpi_ps_stop_trace(struct acpi_evaluate_info *info)
acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
{
acpi_status status;
+ union acpi_parse_object *op;
+ struct acpi_walk_state *walk_state;
ACPI_FUNCTION_TRACE(ps_execute_method);
@@ -234,8 +234,7 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
}
/*
- * The caller "owns" the parameters, so give each one an extra
- * reference
+ * The caller "owns" the parameters, so give each one an extra reference
*/
acpi_ps_update_parameter_list(info, REF_INCREMENT);
@@ -244,30 +243,50 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
acpi_ps_start_trace(info);
/*
- * 1) Perform the first pass parse of the method to enter any
- * named objects that it creates into the namespace
+ * Execute the method. Performs parse simultaneously
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "**** Begin Method Parse **** Entry=%p obj=%p\n",
- info->resolved_node, info->obj_desc));
+ "**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n",
+ info->resolved_node->name.ascii, info->resolved_node,
+ info->obj_desc));
+
+ /* Create and init a Root Node */
+
+ op = acpi_ps_create_scope_op();
+ if (!op) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Create and initialize a new walk state */
+
+ info->pass_number = ACPI_IMODE_EXECUTE;
+ walk_state =
+ acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL,
+ NULL, NULL);
+ if (!walk_state) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
- info->pass_number = 1;
- status = acpi_ps_execute_pass(info);
+ status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
+ info->obj_desc->method.aml_start,
+ info->obj_desc->method.aml_length, info,
+ info->pass_number);
if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
goto cleanup;
}
- /*
- * 2) Execute the method. Performs second pass parse simultaneously
- */
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "**** Begin Method Execution **** Entry=%p obj=%p\n",
- info->resolved_node, info->obj_desc));
+ /* Parse the AML */
- info->pass_number = 3;
- status = acpi_ps_execute_pass(info);
+ status = acpi_ps_parse_aml(walk_state);
+
+ /* walk_state was deleted by parse_aml */
cleanup:
+ acpi_ps_delete_parse_tree(op);
+
/* End optional tracing */
acpi_ps_stop_trace(info);
@@ -330,62 +349,3 @@ acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action)
}
}
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_execute_pass
- *
- * PARAMETERS: Info - See struct acpi_evaluate_info
- * (Used: pass_number, Node, and obj_desc)
- *
- * RETURN: Status
- *
- * DESCRIPTION: Single AML pass: Parse or Execute a control method
- *
- ******************************************************************************/
-
-static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info)
-{
- acpi_status status;
- union acpi_parse_object *op;
- struct acpi_walk_state *walk_state;
-
- ACPI_FUNCTION_TRACE(ps_execute_pass);
-
- /* Create and init a Root Node */
-
- op = acpi_ps_create_scope_op();
- if (!op) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Create and initialize a new walk state */
-
- walk_state =
- acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL,
- NULL, NULL);
- if (!walk_state) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
-
- status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
- info->obj_desc->method.aml_start,
- info->obj_desc->method.aml_length,
- info->pass_number == 1 ? NULL : info,
- info->pass_number);
- if (ACPI_FAILURE(status)) {
- acpi_ds_delete_walk_state(walk_state);
- goto cleanup;
- }
-
- /* Parse the AML */
-
- status = acpi_ps_parse_aml(walk_state);
-
- /* Walk state was deleted by parse_aml */
-
- cleanup:
- acpi_ps_delete_parse_tree(op);
- return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
index 1e2ae6e7a7e..55f57a61c55 100644
--- a/drivers/acpi/pci_bind.c
+++ b/drivers/acpi/pci_bind.c
@@ -122,19 +122,17 @@ int acpi_pci_bind(struct acpi_device *device)
if (!device || !device->parent)
return -EINVAL;
- pathname = kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+ pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
if (!pathname)
return -ENOMEM;
- memset(pathname, 0, ACPI_PATHNAME_MAX);
buffer.length = ACPI_PATHNAME_MAX;
buffer.pointer = pathname;
- data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
+ data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
if (!data) {
kfree(pathname);
return -ENOMEM;
}
- memset(data, 0, sizeof(struct acpi_pci_data));
acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n",
@@ -281,10 +279,9 @@ int acpi_pci_unbind(struct acpi_device *device)
if (!device || !device->parent)
return -EINVAL;
- pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+ pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
if (!pathname)
return -ENOMEM;
- memset(pathname, 0, ACPI_PATHNAME_MAX);
buffer.length = ACPI_PATHNAME_MAX;
buffer.pointer = pathname;
@@ -331,11 +328,9 @@ acpi_pci_bind_root(struct acpi_device *device,
char *pathname = NULL;
struct acpi_buffer buffer = { 0, NULL };
-
- pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+ pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
if (!pathname)
return -ENOMEM;
- memset(pathname, 0, ACPI_PATHNAME_MAX);
buffer.length = ACPI_PATHNAME_MAX;
buffer.pointer = pathname;
@@ -345,12 +340,11 @@ acpi_pci_bind_root(struct acpi_device *device,
return -EINVAL;
}
- data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
+ data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
if (!data) {
kfree(pathname);
return -ENOMEM;
}
- memset(data, 0, sizeof(struct acpi_pci_data));
data->id = *id;
data->bus = bus;
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index feda0341f5a..fe7d007833a 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -89,10 +89,9 @@ acpi_pci_irq_add_entry(acpi_handle handle,
if (!prt)
return -EINVAL;
- entry = kmalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
+ entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
- memset(entry, 0, sizeof(struct acpi_prt_entry));
entry->id.segment = segment;
entry->id.bus = bus;
@@ -161,10 +160,9 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
static int first_time = 1;
- pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+ pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
if (!pathname)
return -ENOMEM;
- memset(pathname, 0, ACPI_PATHNAME_MAX);
if (first_time) {
acpi_prt.count = 0;
@@ -198,11 +196,10 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
return -ENODEV;
}
- prt = kmalloc(buffer.length, GFP_KERNEL);
+ prt = kzalloc(buffer.length, GFP_KERNEL);
if (!prt) {
return -ENOMEM;
}
- memset(prt, 0, buffer.length);
buffer.pointer = prt;
status = acpi_get_irq_routing_table(handle, &buffer);
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index d53bd9878ca..0f683c8c6fb 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -103,7 +103,7 @@ DEFINE_MUTEX(acpi_link_lock);
static acpi_status
acpi_pci_link_check_possible(struct acpi_resource *resource, void *context)
{
- struct acpi_pci_link *link = (struct acpi_pci_link *)context;
+ struct acpi_pci_link *link = context;
u32 i = 0;
@@ -307,11 +307,10 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
if (!link || !irq)
return -EINVAL;
- resource = kmalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
+ resource = kzalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
if (!resource)
return -ENOMEM;
- memset(resource, 0, sizeof(*resource) + 1);
buffer.length = sizeof(*resource) + 1;
buffer.pointer = resource;
@@ -514,7 +513,7 @@ int __init acpi_irq_penalty_init(void)
}
}
/* Add a penalty for the SCI */
- acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING;
+ acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING;
return 0;
}
@@ -613,7 +612,7 @@ acpi_pci_link_allocate_irq(acpi_handle handle,
return -1;
}
- link = (struct acpi_pci_link *)acpi_driver_data(device);
+ link = acpi_driver_data(device);
if (!link) {
printk(KERN_ERR PREFIX "Invalid link context\n");
return -1;
@@ -668,7 +667,7 @@ int acpi_pci_link_free_irq(acpi_handle handle)
return -1;
}
- link = (struct acpi_pci_link *)acpi_driver_data(device);
+ link = acpi_driver_data(device);
if (!link) {
printk(KERN_ERR PREFIX "Invalid link context\n");
return -1;
@@ -718,10 +717,9 @@ static int acpi_pci_link_add(struct acpi_device *device)
if (!device)
return -EINVAL;
- link = kmalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
+ link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
if (!link)
return -ENOMEM;
- memset(link, 0, sizeof(struct acpi_pci_link));
link->device = device;
strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
@@ -787,7 +785,7 @@ static int irqrouter_resume(struct sys_device *dev)
/* Make sure SCI is enabled again (Apple firmware bug?) */
- acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1, ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1);
list_for_each(node, &acpi_link.entries) {
link = list_entry(node, struct acpi_pci_link, node);
@@ -808,7 +806,7 @@ static int acpi_pci_link_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- link = (struct acpi_pci_link *)acpi_driver_data(device);
+ link = acpi_driver_data(device);
mutex_lock(&acpi_link_lock);
list_del(&link->node);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 0984a1ee24e..4ecf701687e 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -98,11 +98,12 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
struct acpi_pci_driver **pptr = &sub_driver;
while (*pptr) {
- if (*pptr != driver)
- continue;
- *pptr = (*pptr)->next;
- break;
+ if (*pptr == driver)
+ break;
+ pptr = &(*pptr)->next;
}
+ BUG_ON(!*pptr);
+ *pptr = (*pptr)->next;
if (!driver->remove)
return;
@@ -116,10 +117,23 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
EXPORT_SYMBOL(acpi_pci_unregister_driver);
+acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
+{
+ struct acpi_pci_root *tmp;
+
+ list_for_each_entry(tmp, &acpi_pci_roots, node) {
+ if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus))
+ return tmp->device->handle;
+ }
+ return NULL;
+}
+
+EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
+
static acpi_status
get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
{
- int *busnr = (int *)data;
+ int *busnr = data;
struct acpi_resource_address64 address;
if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
@@ -151,6 +165,21 @@ static acpi_status try_get_root_bridge_busnr(acpi_handle handle, int *busnum)
return AE_OK;
}
+static void acpi_pci_bridge_scan(struct acpi_device *device)
+{
+ int status;
+ struct acpi_device *child = NULL;
+
+ if (device->flags.bus_address)
+ if (device->parent && device->parent->ops.bind) {
+ status = device->parent->ops.bind(device);
+ if (!status) {
+ list_for_each_entry(child, &device->children, node)
+ acpi_pci_bridge_scan(child);
+ }
+ }
+}
+
static int acpi_pci_root_add(struct acpi_device *device)
{
int result = 0;
@@ -159,15 +188,15 @@ static int acpi_pci_root_add(struct acpi_device *device)
acpi_status status = AE_OK;
unsigned long value = 0;
acpi_handle handle = NULL;
+ struct acpi_device *child;
if (!device)
return -EINVAL;
- root = kmalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
+ root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root)
return -ENOMEM;
- memset(root, 0, sizeof(struct acpi_pci_root));
INIT_LIST_HEAD(&root->node);
root->device = device;
@@ -175,9 +204,6 @@ static int acpi_pci_root_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
acpi_driver_data(device) = root;
- /*
- * TBD: Doesn't the bus driver automatically set this?
- */
device->ops.bind = acpi_pci_bind;
/*
@@ -299,6 +325,12 @@ static int acpi_pci_root_add(struct acpi_device *device)
result = acpi_pci_irq_add_prt(device->handle, root->id.segment,
root->id.bus);
+ /*
+ * Scan and bind all _ADR-Based Devices
+ */
+ list_for_each_entry(child, &device->children, node)
+ acpi_pci_bridge_scan(child);
+
end:
if (result) {
if (!list_empty(&root->node))
@@ -331,7 +363,7 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- root = (struct acpi_pci_root *)acpi_driver_data(device);
+ root = acpi_driver_data(device);
kfree(root);
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index fe67a8af520..0ba7dfbbb2e 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -108,7 +108,7 @@ acpi_power_get_context(acpi_handle handle,
return result;
}
- *resource = (struct acpi_power_resource *)acpi_driver_data(device);
+ *resource = acpi_driver_data(device);
if (!resource)
return -ENODEV;
@@ -442,7 +442,7 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset)
struct acpi_power_resource *resource = NULL;
- resource = (struct acpi_power_resource *)seq->private;
+ resource = seq->private;
if (!resource)
goto end;
@@ -532,10 +532,9 @@ static int acpi_power_add(struct acpi_device *device)
if (!device)
return -EINVAL;
- resource = kmalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
+ resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
if (!resource)
return -ENOMEM;
- memset(resource, 0, sizeof(struct acpi_power_resource));
resource->device = device;
strcpy(resource->name, device->pnp.bus_id);
@@ -590,7 +589,7 @@ static int acpi_power_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- resource = (struct acpi_power_resource *)acpi_driver_data(device);
+ resource = acpi_driver_data(device);
acpi_power_remove_fs(device);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 1908e0d2022..0079bc51082 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -277,7 +277,7 @@ static struct proc_dir_entry *acpi_processor_dir = NULL;
static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+ struct acpi_processor *pr = seq->private;
if (!pr)
@@ -375,30 +375,126 @@ static int acpi_processor_remove_fs(struct acpi_device *device)
}
/* Use the acpiid in MADT to map cpus in case of SMP */
+
#ifndef CONFIG_SMP
-#define convert_acpiid_to_cpu(acpi_id) (-1)
+static int get_cpu_id(acpi_handle handle, u32 acpi_id) {return -1;}
#else
+static struct acpi_table_madt *madt;
+
+static int map_lapic_id(struct acpi_subtable_header *entry,
+ u32 acpi_id, int *apic_id)
+{
+ struct acpi_madt_local_apic *lapic =
+ (struct acpi_madt_local_apic *)entry;
+ if ((lapic->lapic_flags & ACPI_MADT_ENABLED) &&
+ lapic->processor_id == acpi_id) {
+ *apic_id = lapic->id;
+ return 1;
+ }
+ return 0;
+}
+
+static int map_lsapic_id(struct acpi_subtable_header *entry,
+ u32 acpi_id, int *apic_id)
+{
+ struct acpi_madt_local_sapic *lsapic =
+ (struct acpi_madt_local_sapic *)entry;
+ /* Only check enabled APICs*/
+ if (lsapic->lapic_flags & ACPI_MADT_ENABLED) {
+ /* First check against id */
+ if (lsapic->processor_id == acpi_id) {
+ *apic_id = lsapic->id;
+ return 1;
+ /* Check against optional uid */
+ } else if (entry->length >= 16 &&
+ lsapic->uid == acpi_id) {
+ *apic_id = lsapic->uid;
+ return 1;
+ }
+ }
+ return 0;
+}
+
#ifdef CONFIG_IA64
-#define arch_acpiid_to_apicid ia64_acpiid_to_sapicid
#define arch_cpu_to_apicid ia64_cpu_to_sapicid
-#define ARCH_BAD_APICID (0xffff)
#else
-#define arch_acpiid_to_apicid x86_acpiid_to_apicid
#define arch_cpu_to_apicid x86_cpu_to_apicid
-#define ARCH_BAD_APICID (0xff)
#endif
-static int convert_acpiid_to_cpu(u8 acpi_id)
+static int map_madt_entry(u32 acpi_id)
+{
+ unsigned long madt_end, entry;
+ int apic_id = -1;
+
+ if (!madt)
+ return apic_id;
+
+ entry = (unsigned long)madt;
+ madt_end = entry + madt->header.length;
+
+ /* Parse all entries looking for a match. */
+
+ entry += sizeof(struct acpi_table_madt);
+ while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
+ struct acpi_subtable_header *header =
+ (struct acpi_subtable_header *)entry;
+ if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+ if (map_lapic_id(header, acpi_id, &apic_id))
+ break;
+ } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+ if (map_lsapic_id(header, acpi_id, &apic_id))
+ break;
+ }
+ entry += header->length;
+ }
+ return apic_id;
+}
+
+static int map_mat_entry(acpi_handle handle, u32 acpi_id)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ struct acpi_subtable_header *header;
+ int apic_id = -1;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
+ goto exit;
+
+ if (!buffer.length || !buffer.pointer)
+ goto exit;
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length < sizeof(struct acpi_subtable_header)) {
+ goto exit;
+ }
+
+ header = (struct acpi_subtable_header *)obj->buffer.pointer;
+ if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+ map_lapic_id(header, acpi_id, &apic_id);
+ } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+ map_lsapic_id(header, acpi_id, &apic_id);
+ }
+
+exit:
+ if (buffer.pointer)
+ kfree(buffer.pointer);
+ return apic_id;
+}
+
+static int get_cpu_id(acpi_handle handle, u32 acpi_id)
{
- u16 apic_id;
int i;
+ int apic_id = -1;
- apic_id = arch_acpiid_to_apicid[acpi_id];
- if (apic_id == ARCH_BAD_APICID)
- return -1;
+ apic_id = map_mat_entry(handle, acpi_id);
+ if (apic_id == -1)
+ apic_id = map_madt_entry(acpi_id);
+ if (apic_id == -1)
+ return apic_id;
- for (i = 0; i < NR_CPUS; i++) {
+ for (i = 0; i < NR_CPUS; ++i) {
if (arch_cpu_to_apicid[i] == apic_id)
return i;
}
@@ -410,7 +506,7 @@ static int convert_acpiid_to_cpu(u8 acpi_id)
Driver Interface
-------------------------------------------------------------------------- */
-static int acpi_processor_get_info(struct acpi_processor *pr)
+static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
{
acpi_status status = 0;
union acpi_object object = { 0 };
@@ -431,7 +527,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
* Check to see if we have bus mastering arbitration control. This
* is required for proper C3 usage (to maintain cache coherency).
*/
- if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) {
+ if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
pr->flags.bm_control = 1;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Bus mastering arbitration control present\n"));
@@ -439,24 +535,35 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No bus mastering arbitration control\n"));
- /*
- * Evalute the processor object. Note that it is common on SMP to
- * have the first (boot) processor with a valid PBLK address while
- * all others have a NULL address.
- */
- status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Evaluating processor object\n");
- return -ENODEV;
- }
-
- /*
- * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
- * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
- */
- pr->acpi_id = object.processor.proc_id;
+ /* Check if it is a Device with HID and UID */
+ if (has_uid) {
+ unsigned long value;
+ status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
+ NULL, &value);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Evaluating processor _UID\n");
+ return -ENODEV;
+ }
+ pr->acpi_id = value;
+ } else {
+ /*
+ * Evalute the processor object. Note that it is common on SMP to
+ * have the first (boot) processor with a valid PBLK address while
+ * all others have a NULL address.
+ */
+ status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Evaluating processor object\n");
+ return -ENODEV;
+ }
- cpu_index = convert_acpiid_to_cpu(pr->acpi_id);
+ /*
+ * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
+ * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
+ */
+ pr->acpi_id = object.processor.proc_id;
+ }
+ cpu_index = get_cpu_id(pr->handle, pr->acpi_id);
/* Handle UP system running SMP kernel, with no LAPIC in MADT */
if (!cpu0_initialized && (cpu_index == -1) &&
@@ -473,12 +580,9 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
* less than the max # of CPUs. They should be ignored _iff
* they are physically not present.
*/
- if (cpu_index == -1) {
+ if (pr->id == -1) {
if (ACPI_FAILURE
(acpi_processor_hotadd_init(pr->handle, &pr->id))) {
- printk(KERN_ERR PREFIX
- "Getting cpuindex for acpiid 0x%x\n",
- pr->acpi_id);
return -ENODEV;
}
}
@@ -493,8 +597,8 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
object.processor.pblk_length);
else {
pr->throttling.address = object.processor.pblk_address;
- pr->throttling.duty_offset = acpi_fadt.duty_offset;
- pr->throttling.duty_width = acpi_fadt.duty_width;
+ pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
+ pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
pr->pblk = object.processor.pblk_address;
@@ -528,7 +632,7 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
pr = acpi_driver_data(device);
- result = acpi_processor_get_info(pr);
+ result = acpi_processor_get_info(pr, device->flags.unique_id);
if (result) {
/* Processor is physically not present */
return 0;
@@ -542,12 +646,12 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
* Don't trust it blindly
*/
if (processor_device_array[pr->id] != NULL &&
- processor_device_array[pr->id] != (void *)device) {
+ processor_device_array[pr->id] != device) {
printk(KERN_WARNING "BIOS reported wrong ACPI id"
"for the processor\n");
return -ENODEV;
}
- processor_device_array[pr->id] = (void *)device;
+ processor_device_array[pr->id] = device;
processors[pr->id] = pr;
@@ -578,7 +682,7 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
{
- struct acpi_processor *pr = (struct acpi_processor *)data;
+ struct acpi_processor *pr = data;
struct acpi_device *device = NULL;
@@ -615,10 +719,9 @@ static int acpi_processor_add(struct acpi_device *device)
if (!device)
return -EINVAL;
- pr = kmalloc(sizeof(struct acpi_processor), GFP_KERNEL);
+ pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
if (!pr)
return -ENOMEM;
- memset(pr, 0, sizeof(struct acpi_processor));
pr->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
@@ -637,7 +740,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- pr = (struct acpi_processor *)acpi_driver_data(device);
+ pr = acpi_driver_data(device);
if (pr->id >= NR_CPUS) {
kfree(pr);
@@ -711,7 +814,7 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
return -ENODEV;
if ((pr->id >= 0) && (pr->id < NR_CPUS)) {
- kobject_uevent(&(*device)->kobj, KOBJ_ONLINE);
+ kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE);
}
return 0;
}
@@ -749,13 +852,13 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
}
if (pr->id >= 0 && (pr->id < NR_CPUS)) {
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
break;
}
result = acpi_processor_start(device);
if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) {
- kobject_uevent(&device->kobj, KOBJ_ONLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
} else {
printk(KERN_ERR PREFIX "Device [%s] failed to start\n",
acpi_device_bid(device));
@@ -778,7 +881,7 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
}
if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -899,15 +1002,21 @@ static int __init acpi_processor_init(void)
memset(&processors, 0, sizeof(processors));
memset(&errata, 0, sizeof(errata));
+#ifdef CONFIG_SMP
+ if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
+ (struct acpi_table_header **)&madt)))
+ madt = 0;
+#endif
+
acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
if (!acpi_processor_dir)
- return 0;
+ return -ENOMEM;
acpi_processor_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&acpi_processor_driver);
if (result < 0) {
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
- return 0;
+ return result;
}
acpi_processor_install_hotplug_notify();
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 65b3f056ad8..6c6751b1405 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -160,7 +160,7 @@ static inline u32 ticks_elapsed(u32 t1, u32 t2)
{
if (t2 >= t1)
return (t2 - t1);
- else if (!acpi_fadt.tmr_val_ext)
+ else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
else
return ((0xFFFFFFFF - t1) + t2);
@@ -187,8 +187,7 @@ acpi_processor_power_activate(struct acpi_processor *pr,
case ACPI_STATE_C3:
/* Disable bus master reload */
if (new->type != ACPI_STATE_C3 && pr->flags.bm_check)
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
break;
}
}
@@ -198,8 +197,7 @@ acpi_processor_power_activate(struct acpi_processor *pr,
case ACPI_STATE_C3:
/* Enable bus master reload */
if (old->type != ACPI_STATE_C3 && pr->flags.bm_check)
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
break;
}
@@ -211,7 +209,11 @@ acpi_processor_power_activate(struct acpi_processor *pr,
static void acpi_safe_halt(void)
{
current_thread_info()->status &= ~TS_POLLING;
- smp_mb__after_clear_bit();
+ /*
+ * TS_POLLING-cleared state must be visible before we
+ * test NEED_RESCHED:
+ */
+ smp_mb();
if (!need_resched())
safe_halt();
current_thread_info()->status |= TS_POLLING;
@@ -232,7 +234,7 @@ static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
/* 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);
+ unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
}
}
@@ -287,12 +289,10 @@ static void acpi_processor_idle(void)
pr->power.bm_activity <<= diff;
- acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS,
- &bm_status, ACPI_MTX_DO_NOT_LOCK);
+ acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
if (bm_status) {
pr->power.bm_activity |= 0x1;
- acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS,
- 1, ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
}
/*
* PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
@@ -334,7 +334,7 @@ static void acpi_processor_idle(void)
* detection phase, to work cleanly with logical CPU hotplug.
*/
if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
- !pr->flags.has_cst && !acpi_fadt.plvl2_up)
+ !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
cx = &pr->power.states[ACPI_STATE_C1];
#endif
@@ -345,7 +345,11 @@ static void acpi_processor_idle(void)
*/
if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) {
current_thread_info()->status &= ~TS_POLLING;
- smp_mb__after_clear_bit();
+ /*
+ * TS_POLLING-cleared state must be visible before we
+ * test NEED_RESCHED:
+ */
+ smp_mb();
if (need_resched()) {
current_thread_info()->status |= TS_POLLING;
local_irq_enable();
@@ -376,11 +380,11 @@ static void acpi_processor_idle(void)
case ACPI_STATE_C2:
/* Get start time (ticks) */
- t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
/* Invoke C2 */
acpi_cstate_enter(cx);
/* Get end time (ticks) */
- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
#ifdef CONFIG_GENERIC_TIME
/* TSC halts in C2, so notify users */
@@ -403,8 +407,7 @@ static void acpi_processor_idle(void)
* All CPUs are trying to go to C3
* Disable bus master arbitration
*/
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
}
} else {
/* SMP with no shared cache... Invalidate cache */
@@ -412,16 +415,15 @@ static void acpi_processor_idle(void)
}
/* Get start time (ticks) */
- t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
/* Invoke C3 */
acpi_cstate_enter(cx);
/* Get end time (ticks) */
- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
if (pr->flags.bm_check) {
/* Enable bus master arbitration */
atomic_dec(&c3_cpu_count);
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
}
#ifdef CONFIG_GENERIC_TIME
@@ -449,7 +451,7 @@ static void acpi_processor_idle(void)
#ifdef CONFIG_HOTPLUG_CPU
/* Don't do promotion/demotion */
if ((cx->type == ACPI_STATE_C1) && (num_online_cpus() > 1) &&
- !pr->flags.has_cst && !acpi_fadt.plvl2_up) {
+ !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) {
next_state = cx;
goto end;
}
@@ -619,7 +621,8 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
* Check for P_LVL2_UP flag before entering C2 and above on
* an SMP system.
*/
- if ((num_online_cpus() > 1) && !acpi_fadt.plvl2_up)
+ if ((num_online_cpus() > 1) &&
+ !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
return -ENODEV;
#endif
@@ -628,8 +631,8 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5;
/* determine latencies from FADT */
- pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat;
- pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat;
+ pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency;
+ pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"lvl2[0x%08x] lvl3[0x%08x]\n",
@@ -673,7 +676,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
return -ENODEV;
}
- cst = (union acpi_object *)buffer.pointer;
+ cst = buffer.pointer;
/* There must be at least 2 elements */
if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
@@ -702,14 +705,14 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
memset(&cx, 0, sizeof(cx));
- element = (union acpi_object *)&(cst->package.elements[i]);
+ element = &(cst->package.elements[i]);
if (element->type != ACPI_TYPE_PACKAGE)
continue;
if (element->package.count != 4)
continue;
- obj = (union acpi_object *)&(element->package.elements[0]);
+ obj = &(element->package.elements[0]);
if (obj->type != ACPI_TYPE_BUFFER)
continue;
@@ -721,7 +724,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
continue;
/* There should be an easy way to extract an integer... */
- obj = (union acpi_object *)&(element->package.elements[1]);
+ obj = &(element->package.elements[1]);
if (obj->type != ACPI_TYPE_INTEGER)
continue;
@@ -754,13 +757,13 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
}
}
- obj = (union acpi_object *)&(element->package.elements[2]);
+ obj = &(element->package.elements[2]);
if (obj->type != ACPI_TYPE_INTEGER)
continue;
cx.latency = obj->integer.value;
- obj = (union acpi_object *)&(element->package.elements[3]);
+ obj = &(element->package.elements[3]);
if (obj->type != ACPI_TYPE_INTEGER)
continue;
@@ -875,14 +878,13 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
* WBINVD should be set in fadt, for C3 state to be
* supported on when bm_check is not required.
*/
- if (acpi_fadt.wb_invd != 1) {
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_WBINVD)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Cache invalidation should work properly"
" for C3 to be enabled on SMP systems\n"));
return;
}
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD,
- 0, ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
}
/*
@@ -1029,7 +1031,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+ struct acpi_processor *pr = seq->private;
unsigned int i;
@@ -1088,7 +1090,7 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n",
pr->power.states[i].latency,
pr->power.states[i].usage,
- pr->power.states[i].time);
+ (unsigned long long)pr->power.states[i].time);
}
end:
@@ -1156,9 +1158,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
if (!pr)
return -EINVAL;
- if (acpi_fadt.cst_cnt && !nocst) {
+ if (acpi_gbl_FADT.cst_control && !nocst) {
status =
- acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8);
+ acpi_os_write_port(acpi_gbl_FADT.smi_command, acpi_gbl_FADT.cst_control, 8);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Notifying BIOS of _CST ability failed"));
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 6fd174a3714..058f13cf3b7 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -236,7 +236,7 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
return -ENODEV;
}
- pss = (union acpi_object *)buffer.pointer;
+ pss = buffer.pointer;
if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
printk(KERN_ERR PREFIX "Invalid _PSS data\n");
result = -EFAULT;
@@ -322,10 +322,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
if (result)
return result;
- result = acpi_processor_get_platform_limit(pr);
- if (result)
- return result;
-
return 0;
}
@@ -356,31 +352,24 @@ int acpi_processor_notify_smm(struct module *calling_module)
is_done = -EIO;
- /* Can't write pstate_cnt to smi_cmd if either value is zero */
- if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_cnt\n"));
+ /* Can't write pstate_control to smi_command if either value is zero */
+ if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
module_put(calling_module);
return 0;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n",
- acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd));
-
- /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use
- * it anyway, so we need to support it... */
- if (acpi_fadt_is_v1) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Using v1.0 FADT reserved value for pstate_cnt\n"));
- }
+ "Writing pstate_control [0x%x] to smi_command [0x%x]\n",
+ acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
- status = acpi_os_write_port(acpi_fadt.smi_cmd,
- (u32) acpi_fadt.pstate_cnt, 8);
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.pstate_control, 8);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Failed to write pstate_cnt [0x%x] to "
- "smi_cmd [0x%x]", acpi_fadt.pstate_cnt,
- acpi_fadt.smi_cmd));
+ "Failed to write pstate_control [0x%x] to "
+ "smi_command [0x%x]", acpi_gbl_FADT.pstate_control,
+ acpi_gbl_FADT.smi_command));
module_put(calling_module);
return status;
}
@@ -410,7 +399,7 @@ static struct file_operations acpi_processor_perf_fops = {
static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+ struct acpi_processor *pr = seq->private;
int i;
@@ -451,8 +440,8 @@ acpi_processor_write_performance(struct file *file,
size_t count, loff_t * data)
{
int result = 0;
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_processor *pr = (struct acpi_processor *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_processor *pr = m->private;
struct acpi_processor_performance *perf;
char state_string[12] = { '\0' };
unsigned int new_state = 0;
@@ -551,7 +540,7 @@ static int acpi_processor_get_psd(struct acpi_processor *pr)
return -ENODEV;
}
- psd = (union acpi_object *) buffer.pointer;
+ psd = buffer.pointer;
if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
result = -EFAULT;
@@ -736,10 +725,6 @@ int acpi_processor_preregister_performance(
}
err_ret:
- if (retval) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error while parsing _PSD domain information. Assuming no coordination\n"));
- }
-
for_each_possible_cpu(i) {
pr = processors[i];
if (!pr || !pr->performance)
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index ef5e0f6efdb..40fecd67ad8 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -208,7 +208,7 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type)
if (result)
return result;
- pr = (struct acpi_processor *)acpi_driver_data(device);
+ pr = acpi_driver_data(device);
if (!pr)
return -ENODEV;
@@ -348,8 +348,8 @@ static ssize_t acpi_processor_write_limit(struct file * file,
size_t count, loff_t * data)
{
int result = 0;
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_processor *pr = (struct acpi_processor *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_processor *pr = m->private;
char limit_string[25] = { '\0' };
int px = 0;
int tx = 0;
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index d044ec519db..89dff3639ab 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -125,7 +125,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
/* Used to clear all duty_value bits */
duty_mask = pr->throttling.state_count - 1;
- duty_mask <<= acpi_fadt.duty_offset;
+ duty_mask <<= acpi_gbl_FADT.duty_offset;
duty_mask = ~duty_mask;
}
@@ -208,7 +208,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
return 0;
}
- pr->throttling.state_count = 1 << acpi_fadt.duty_width;
+ pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width;
/*
* Compute state values. Note that throttling displays a linear power/
@@ -259,7 +259,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
static int acpi_processor_throttling_seq_show(struct seq_file *seq,
void *offset)
{
- struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+ struct acpi_processor *pr = seq->private;
int i = 0;
int result = 0;
@@ -307,8 +307,8 @@ static ssize_t acpi_processor_write_throttling(struct file * file,
size_t count, loff_t * data)
{
int result = 0;
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_processor *pr = (struct acpi_processor *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_processor *pr = m->private;
char state_string[12] = { '\0' };
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
index 8fa3213ce00..271e61509ee 100644
--- a/drivers/acpi/resources/rsaddr.c
+++ b/drivers/acpi/resources/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
index cf87b023002..8c6d3fdec38 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index 008058acdd3..1358c06a969 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
index 9c99a723a86..de20a5d6dec 100644
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/resources/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c
index 9e7ae2f8a1d..7e3c335ab32 100644
--- a/drivers/acpi/resources/rsinfo.c
+++ b/drivers/acpi/resources/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c
index ea567167c4f..b297bc3e441 100644
--- a/drivers/acpi/resources/rsio.c
+++ b/drivers/acpi/resources/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
index 1fa63bc2e36..5657f7b9503 100644
--- a/drivers/acpi/resources/rsirq.c
+++ b/drivers/acpi/resources/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
index 29423ce030c..a92755c8877 100644
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/resources/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c
index a5131936d69..521eab7dd8d 100644
--- a/drivers/acpi/resources/rsmemory.c
+++ b/drivers/acpi/resources/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
index faf6e106b78..3b63b561b94 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/resources/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
index a9cbee8e8b4..2442a8f8df5 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/resources/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index 1999e2ab7da..991f8901498 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 8908a975e57..f58fc7447ab 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -923,7 +923,7 @@ static struct proc_dir_entry *acpi_battery_dir = NULL;
static int acpi_battery_read_info(struct seq_file *seq, void *offset)
{
- struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ struct acpi_battery *battery = seq->private;
int cscale;
int result = 0;
@@ -1076,7 +1076,7 @@ static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
{
- struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ struct acpi_battery *battery = seq->private;
int result = 0;
int cscale;
@@ -1125,8 +1125,8 @@ static ssize_t
acpi_battery_write_alarm(struct file *file, const char __user * buffer,
size_t count, loff_t * ppos)
{
- struct seq_file *seq = (struct seq_file *)file->private_data;
- struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ struct seq_file *seq = file->private_data;
+ struct acpi_battery *battery = seq->private;
char alarm_string[12] = { '\0' };
int result, old_alarm, new_alarm;
@@ -1160,14 +1160,14 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer,
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"acpi_battery_set_alarm() failed\n"));
- (void)acpi_battery_set_alarm(battery, old_alarm);
+ acpi_battery_set_alarm(battery, old_alarm);
goto end;
}
result = acpi_battery_get_alarm(battery);
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"acpi_battery_get_alarm() failed\n"));
- (void)acpi_battery_set_alarm(battery, old_alarm);
+ acpi_battery_set_alarm(battery, old_alarm);
goto end;
}
@@ -1217,7 +1217,7 @@ static struct proc_dir_entry *acpi_ac_dir = NULL;
static int acpi_ac_read_state(struct seq_file *seq, void *offset)
{
- struct acpi_sbs *sbs = (struct acpi_sbs *)seq->private;
+ struct acpi_sbs *sbs = seq->private;
int result;
if (sbs->zombie) {
@@ -1302,7 +1302,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
battery->init_state = 1;
}
- (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
+ sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
result = acpi_sbs_generic_add_fs(&battery->battery_entry,
acpi_battery_dir,
@@ -1485,7 +1485,7 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
}
if (old_battery_present != new_battery_present) {
- (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
+ sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
result = acpi_sbs_generate_event(sbs->device,
ACPI_SBS_BATTERY_NOTIFY_STATUS,
new_battery_present,
@@ -1498,7 +1498,7 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
}
}
if (old_remaining_capacity != battery->state.remaining_capacity) {
- (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
+ sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
result = acpi_sbs_generate_event(sbs->device,
ACPI_SBS_BATTERY_NOTIFY_STATUS,
new_battery_present,
@@ -1576,12 +1576,11 @@ static int acpi_sbs_add(struct acpi_device *device)
int id, cnt;
acpi_status status = AE_OK;
- sbs = kmalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
+ sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
if (!sbs) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n"));
return -ENOMEM;
}
- memset(sbs, 0, sizeof(struct acpi_sbs));
cnt = 0;
while (cnt < 10) {
@@ -1659,7 +1658,7 @@ static int acpi_sbs_add(struct acpi_device *device)
init_timer(&sbs->update_timer);
if (update_mode == QUEUE_UPDATE_MODE) {
status = acpi_os_execute(OSL_GPE_HANDLER,
- acpi_sbs_update_queue, (void *)sbs);
+ acpi_sbs_update_queue, sbs);
if (status != AE_OK) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"acpi_os_execute() failed\n"));
@@ -1685,7 +1684,7 @@ static int acpi_sbs_add(struct acpi_device *device)
int acpi_sbs_remove(struct acpi_device *device, int type)
{
- struct acpi_sbs *sbs = NULL;
+ struct acpi_sbs *sbs;
int id;
if (!device) {
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 698a1540e30..64f26db10c8 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -21,101 +21,305 @@ extern struct acpi_device *acpi_root;
#define ACPI_BUS_DEVICE_NAME "System Bus"
static LIST_HEAD(acpi_device_list);
+static LIST_HEAD(acpi_bus_id_list);
DEFINE_SPINLOCK(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
+struct acpi_device_bus_id{
+ char bus_id[15];
+ unsigned int instance_no;
+ struct list_head node;
+};
+static int acpi_eject_operation(acpi_handle handle, int lockable)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ acpi_status status = AE_OK;
+
+ /*
+ * TBD: evaluate _PS3?
+ */
+
+ if (lockable) {
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 0;
+ acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
+ }
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ /*
+ * TBD: _EJD support.
+ */
+
+ status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
+ if (ACPI_FAILURE(status)) {
+ return (-ENODEV);
+ }
+
+ return (0);
+}
-static void acpi_device_release(struct kobject *kobj)
+static ssize_t
+acpi_eject_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct acpi_device *dev = container_of(kobj, struct acpi_device, kobj);
- kfree(dev->pnp.cid_list);
- kfree(dev);
+ int result;
+ int ret = count;
+ int islockable;
+ acpi_status status;
+ acpi_handle handle;
+ acpi_object_type type = 0;
+ struct acpi_device *acpi_device = to_acpi_device(d);
+
+ if ((!count) || (buf[0] != '1')) {
+ return -EINVAL;
+ }
+#ifndef FORCE_EJECT
+ if (acpi_device->driver == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+#endif
+ status = acpi_get_type(acpi_device->handle, &type);
+ if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ islockable = acpi_device->flags.lockable;
+ handle = acpi_device->handle;
+
+ result = acpi_bus_trim(acpi_device, 1);
+
+ if (!result)
+ result = acpi_eject_operation(handle, islockable);
+
+ if (result) {
+ ret = -EBUSY;
+ }
+ err:
+ return ret;
}
-struct acpi_device_attribute {
- struct attribute attr;
- ssize_t(*show) (struct acpi_device *, char *);
- ssize_t(*store) (struct acpi_device *, const char *, size_t);
-};
+static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
+
+static ssize_t
+acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+ return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id);
+}
+static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
+
+static ssize_t
+acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
+ int result;
+
+ result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
+ if(result)
+ goto end;
+
+ result = sprintf(buf, "%s\n", (char*)path.pointer);
+ kfree(path.pointer);
+ end:
+ return result;
+}
+static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
+
+static int acpi_device_setup_files(struct acpi_device *dev)
+{
+ acpi_status status;
+ acpi_handle temp;
+ int result = 0;
+
+ /*
+ * Devices gotten from FADT don't have a "path" attribute
+ */
+ if(dev->handle) {
+ result = device_create_file(&dev->dev, &dev_attr_path);
+ if(result)
+ goto end;
+ }
-typedef void acpi_device_sysfs_files(struct kobject *,
- const struct attribute *);
+ if(dev->flags.hardware_id) {
+ result = device_create_file(&dev->dev, &dev_attr_hid);
+ if(result)
+ goto end;
+ }
-static void setup_sys_fs_device_files(struct acpi_device *dev,
- acpi_device_sysfs_files * func);
+ /*
+ * If device has _EJ0, 'eject' file is created that is used to trigger
+ * hot-removal function from userland.
+ */
+ status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+ if (ACPI_SUCCESS(status))
+ result = device_create_file(&dev->dev, &dev_attr_eject);
+ end:
+ return result;
+}
-#define create_sysfs_device_files(dev) \
- setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file)
-#define remove_sysfs_device_files(dev) \
- setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file)
+static void acpi_device_remove_files(struct acpi_device *dev)
+{
+ acpi_status status;
+ acpi_handle temp;
-#define to_acpi_device(n) container_of(n, struct acpi_device, kobj)
-#define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr);
+ /*
+ * If device has _EJ0, 'eject' file is created that is used to trigger
+ * hot-removal function from userland.
+ */
+ status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+ if (ACPI_SUCCESS(status))
+ device_remove_file(&dev->dev, &dev_attr_eject);
-static ssize_t acpi_device_attr_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
+ if(dev->flags.hardware_id)
+ device_remove_file(&dev->dev, &dev_attr_hid);
+ if(dev->handle)
+ device_remove_file(&dev->dev, &dev_attr_path);
+}
+/* --------------------------------------------------------------------------
+ ACPI Bus operations
+ -------------------------------------------------------------------------- */
+static void acpi_device_release(struct device *dev)
{
- struct acpi_device *device = to_acpi_device(kobj);
- struct acpi_device_attribute *attribute = to_handle_attr(attr);
- return attribute->show ? attribute->show(device, buf) : -EIO;
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+ kfree(acpi_dev->pnp.cid_list);
+ kfree(acpi_dev);
}
-static ssize_t acpi_device_attr_store(struct kobject *kobj,
- struct attribute *attr, const char *buf,
- size_t len)
+
+static int acpi_device_suspend(struct device *dev, pm_message_t state)
{
- struct acpi_device *device = to_acpi_device(kobj);
- struct acpi_device_attribute *attribute = to_handle_attr(attr);
- return attribute->store ? attribute->store(device, buf, len) : -EIO;
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+ if (acpi_drv && acpi_drv->ops.suspend)
+ return acpi_drv->ops.suspend(acpi_dev, state);
+ return 0;
}
-static struct sysfs_ops acpi_device_sysfs_ops = {
- .show = acpi_device_attr_show,
- .store = acpi_device_attr_store,
-};
+static int acpi_device_resume(struct device *dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
-static struct kobj_type ktype_acpi_ns = {
- .sysfs_ops = &acpi_device_sysfs_ops,
- .release = acpi_device_release,
-};
+ if (acpi_drv && acpi_drv->ops.resume)
+ return acpi_drv->ops.resume(acpi_dev);
+ return 0;
+}
-static int namespace_uevent(struct kset *kset, struct kobject *kobj,
- char **envp, int num_envp, char *buffer,
- int buffer_size)
+static int acpi_bus_match(struct device *dev, struct device_driver *drv)
{
- struct acpi_device *dev = to_acpi_device(kobj);
- int i = 0;
- int len = 0;
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = to_acpi_driver(drv);
- if (!dev->driver)
- return 0;
+ return !acpi_match_ids(acpi_dev, acpi_drv->ids);
+}
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "PHYSDEVDRIVER=%s", dev->driver->name))
+static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ int i = 0, length = 0, ret = 0;
+
+ if (acpi_dev->flags.hardware_id)
+ ret = add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "HWID=%s", acpi_dev->pnp.hardware_id);
+ if (ret)
return -ENOMEM;
+ if (acpi_dev->flags.compatible_ids) {
+ int j;
+ struct acpi_compatible_id_list *cid_list;
+
+ cid_list = acpi_dev->pnp.cid_list;
+
+ for (j = 0; j < cid_list->count; j++) {
+ ret = add_uevent_var(envp, num_envp, &i, buffer,
+ buffer_size, &length, "COMPTID=%s",
+ cid_list->id[j].value);
+ if (ret)
+ return -ENOMEM;
+ }
+ }
envp[i] = NULL;
+ return 0;
+}
+
+static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
+static int acpi_start_single_object(struct acpi_device *);
+static int acpi_device_probe(struct device * dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
+ int ret;
+
+ ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
+ if (!ret) {
+ if (acpi_dev->bus_ops.acpi_op_start)
+ acpi_start_single_object(acpi_dev);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Found driver [%s] for device [%s]\n",
+ acpi_drv->name, acpi_dev->pnp.bus_id));
+ get_device(dev);
+ }
+ return ret;
+}
+static int acpi_device_remove(struct device * dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+ if (acpi_drv) {
+ if (acpi_drv->ops.stop)
+ acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type);
+ if (acpi_drv->ops.remove)
+ acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+ }
+ acpi_dev->driver = NULL;
+ acpi_driver_data(dev) = NULL;
+
+ put_device(dev);
return 0;
}
-static struct kset_uevent_ops namespace_uevent_ops = {
- .uevent = &namespace_uevent,
-};
+static void acpi_device_shutdown(struct device *dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+ if (acpi_drv && acpi_drv->ops.shutdown)
+ acpi_drv->ops.shutdown(acpi_dev);
-static struct kset acpi_namespace_kset = {
- .kobj = {
- .name = "namespace",
- },
- .subsys = &acpi_subsys,
- .ktype = &ktype_acpi_ns,
- .uevent_ops = &namespace_uevent_ops,
+ return ;
+}
+
+static struct bus_type acpi_bus_type = {
+ .name = "acpi",
+ .suspend = acpi_device_suspend,
+ .resume = acpi_device_resume,
+ .shutdown = acpi_device_shutdown,
+ .match = acpi_bus_match,
+ .probe = acpi_device_probe,
+ .remove = acpi_device_remove,
+ .uevent = acpi_device_uevent,
};
-static void acpi_device_register(struct acpi_device *device,
+static int acpi_device_register(struct acpi_device *device,
struct acpi_device *parent)
{
- int err;
-
+ int result;
+ struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
+ int found = 0;
/*
* Linkage
* -------
@@ -126,7 +330,33 @@ static void acpi_device_register(struct acpi_device *device,
INIT_LIST_HEAD(&device->g_list);
INIT_LIST_HEAD(&device->wakeup_list);
+ new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
+ if (!new_bus_id) {
+ printk(KERN_ERR PREFIX "Memory allocation error\n");
+ return -ENOMEM;
+ }
+
spin_lock(&acpi_device_lock);
+ /*
+ * Find suitable bus_id and instance number in acpi_bus_id_list
+ * If failed, create one and link it into acpi_bus_id_list
+ */
+ list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
+ if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) {
+ acpi_device_bus_id->instance_no ++;
+ found = 1;
+ kfree(new_bus_id);
+ break;
+ }
+ }
+ if(!found) {
+ acpi_device_bus_id = new_bus_id;
+ strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device");
+ acpi_device_bus_id->instance_no = 0;
+ list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
+ }
+ sprintf(device->dev.bus_id, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
+
if (device->parent) {
list_add_tail(&device->node, &device->parent->children);
list_add_tail(&device->g_list, &device->parent->g_list);
@@ -136,16 +366,33 @@ static void acpi_device_register(struct acpi_device *device,
list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
spin_unlock(&acpi_device_lock);
- strlcpy(device->kobj.name, device->pnp.bus_id, KOBJ_NAME_LEN);
- if (parent)
- device->kobj.parent = &parent->kobj;
- device->kobj.ktype = &ktype_acpi_ns;
- device->kobj.kset = &acpi_namespace_kset;
- err = kobject_register(&device->kobj);
- if (err < 0)
- printk(KERN_WARNING "%s: kobject_register error: %d\n",
- __FUNCTION__, err);
- create_sysfs_device_files(device);
+ if (device->parent)
+ device->dev.parent = &parent->dev;
+ device->dev.bus = &acpi_bus_type;
+ device_initialize(&device->dev);
+ device->dev.release = &acpi_device_release;
+ result = device_add(&device->dev);
+ if(result) {
+ printk("Error adding device %s", device->dev.bus_id);
+ goto end;
+ }
+
+ result = acpi_device_setup_files(device);
+ if(result)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id));
+
+ device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
+ return 0;
+ end:
+ spin_lock(&acpi_device_lock);
+ if (device->parent) {
+ list_del(&device->node);
+ list_del(&device->g_list);
+ } else
+ list_del(&device->g_list);
+ list_del(&device->wakeup_list);
+ spin_unlock(&acpi_device_lock);
+ return result;
}
static void acpi_device_unregister(struct acpi_device *device, int type)
@@ -158,81 +405,143 @@ static void acpi_device_unregister(struct acpi_device *device, int type)
list_del(&device->g_list);
list_del(&device->wakeup_list);
-
spin_unlock(&acpi_device_lock);
acpi_detach_data(device->handle, acpi_bus_data_handler);
- remove_sysfs_device_files(device);
- kobject_unregister(&device->kobj);
+
+ acpi_device_remove_files(device);
+ device_unregister(&device->dev);
}
-void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
+/* --------------------------------------------------------------------------
+ Driver Management
+ -------------------------------------------------------------------------- */
+/**
+ * acpi_bus_driver_init - add a device to a driver
+ * @device: the device to add and initialize
+ * @driver: driver for the device
+ *
+ * Used to initialize a device via its device driver. Called whenever a
+ * driver is bound to a device. Invokes the driver's add() ops.
+ */
+static int
+acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
{
+ int result = 0;
- /* TBD */
- return;
-}
+ if (!device || !driver)
+ return -EINVAL;
-static int acpi_bus_get_power_flags(struct acpi_device *device)
-{
- acpi_status status = 0;
- acpi_handle handle = NULL;
- u32 i = 0;
+ if (!driver->ops.add)
+ return -ENOSYS;
+ result = driver->ops.add(device);
+ if (result) {
+ device->driver = NULL;
+ acpi_driver_data(device) = NULL;
+ return result;
+ }
- /*
- * Power Management Flags
- */
- status = acpi_get_handle(device->handle, "_PSC", &handle);
- if (ACPI_SUCCESS(status))
- device->power.flags.explicit_get = 1;
- status = acpi_get_handle(device->handle, "_IRC", &handle);
- if (ACPI_SUCCESS(status))
- device->power.flags.inrush_current = 1;
+ device->driver = driver;
/*
- * Enumerate supported power management states
+ * TBD - Configuration Management: Assign resources to device based
+ * upon possible configuration and currently allocated resources.
*/
- for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
- struct acpi_device_power_state *ps = &device->power.states[i];
- char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
- /* Evaluate "_PRx" to se if power resources are referenced */
- acpi_evaluate_reference(device->handle, object_name, NULL,
- &ps->resources);
- if (ps->resources.count) {
- device->power.flags.power_resources = 1;
- ps->flags.valid = 1;
- }
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Driver successfully bound to device\n"));
+ return 0;
+}
- /* Evaluate "_PSx" to see if we can do explicit sets */
- object_name[2] = 'S';
- status = acpi_get_handle(device->handle, object_name, &handle);
- if (ACPI_SUCCESS(status)) {
- ps->flags.explicit_set = 1;
- ps->flags.valid = 1;
- }
+static int acpi_start_single_object(struct acpi_device *device)
+{
+ int result = 0;
+ struct acpi_driver *driver;
- /* State is valid if we have some power control */
- if (ps->resources.count || ps->flags.explicit_set)
- ps->flags.valid = 1;
- ps->power = -1; /* Unknown - driver assigned */
- ps->latency = -1; /* Unknown - driver assigned */
+ if (!(driver = device->driver))
+ return 0;
+
+ if (driver->ops.start) {
+ result = driver->ops.start(device);
+ if (result && driver->ops.remove)
+ driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
}
- /* Set defaults for D0 and D3 states (always valid) */
- device->power.states[ACPI_STATE_D0].flags.valid = 1;
- device->power.states[ACPI_STATE_D0].power = 100;
- device->power.states[ACPI_STATE_D3].flags.valid = 1;
- device->power.states[ACPI_STATE_D3].power = 0;
+ return result;
+}
- /* TBD: System wake support and resource requirements. */
+/**
+ * acpi_bus_register_driver - register a driver with the ACPI bus
+ * @driver: driver being registered
+ *
+ * Registers a driver with the ACPI bus. Searches the namespace for all
+ * devices that match the driver's criteria and binds. Returns zero for
+ * success or a negative error status for failure.
+ */
+int acpi_bus_register_driver(struct acpi_driver *driver)
+{
+ int ret;
- device->power.state = ACPI_STATE_UNKNOWN;
+ if (acpi_disabled)
+ return -ENODEV;
+ driver->drv.name = driver->name;
+ driver->drv.bus = &acpi_bus_type;
+ driver->drv.owner = driver->owner;
- return 0;
+ ret = driver_register(&driver->drv);
+ return ret;
+}
+
+EXPORT_SYMBOL(acpi_bus_register_driver);
+
+/**
+ * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
+ * @driver: driver to unregister
+ *
+ * Unregisters a driver with the ACPI bus. Searches the namespace for all
+ * devices that match the driver's criteria and unbinds.
+ */
+void acpi_bus_unregister_driver(struct acpi_driver *driver)
+{
+ driver_unregister(&driver->drv);
+}
+
+EXPORT_SYMBOL(acpi_bus_unregister_driver);
+
+/* --------------------------------------------------------------------------
+ Device Enumeration
+ -------------------------------------------------------------------------- */
+acpi_status
+acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
+{
+ acpi_status status;
+ acpi_handle tmp;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *obj;
+
+ status = acpi_get_handle(handle, "_EJD", &tmp);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
+ if (ACPI_SUCCESS(status)) {
+ obj = buffer.pointer;
+ status = acpi_get_handle(NULL, obj->string.pointer, ejd);
+ kfree(buffer.pointer);
+ }
+ return status;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
+
+void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
+{
+
+ /* TBD */
+
+ return;
}
int acpi_match_ids(struct acpi_device *device, char *ids)
@@ -254,6 +563,12 @@ int acpi_match_ids(struct acpi_device *device, char *ids)
return -ENOENT;
}
+static int acpi_bus_get_perf_flags(struct acpi_device *device)
+{
+ device->performance.state = ACPI_STATE_UNKNOWN;
+ return 0;
+}
+
static acpi_status
acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
union acpi_object *package)
@@ -338,359 +653,66 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
return 0;
}
-/* --------------------------------------------------------------------------
- ACPI sysfs device file support
- -------------------------------------------------------------------------- */
-static ssize_t acpi_eject_store(struct acpi_device *device,
- const char *buf, size_t count);
-
-#define ACPI_DEVICE_ATTR(_name,_mode,_show,_store) \
-static struct acpi_device_attribute acpi_device_attr_##_name = \
- __ATTR(_name, _mode, _show, _store)
-
-ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
-
-/**
- * setup_sys_fs_device_files - sets up the device files under device namespace
- * @dev: acpi_device object
- * @func: function pointer to create or destroy the device file
- */
-static void
-setup_sys_fs_device_files(struct acpi_device *dev,
- acpi_device_sysfs_files * func)
-{
- acpi_status status;
- acpi_handle temp = NULL;
-
- /*
- * If device has _EJ0, 'eject' file is created that is used to trigger
- * hot-removal function from userland.
- */
- status = acpi_get_handle(dev->handle, "_EJ0", &temp);
- if (ACPI_SUCCESS(status))
- (*(func)) (&dev->kobj, &acpi_device_attr_eject.attr);
-}
-
-static int acpi_eject_operation(acpi_handle handle, int lockable)
+static int acpi_bus_get_power_flags(struct acpi_device *device)
{
- struct acpi_object_list arg_list;
- union acpi_object arg;
- acpi_status status = AE_OK;
-
- /*
- * TBD: evaluate _PS3?
- */
-
- if (lockable) {
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 0;
- acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
- }
+ acpi_status status = 0;
+ acpi_handle handle = NULL;
+ u32 i = 0;
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 1;
/*
- * TBD: _EJD support.
+ * Power Management Flags
*/
-
- status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
- if (ACPI_FAILURE(status)) {
- return (-ENODEV);
- }
-
- return (0);
-}
-
-static ssize_t
-acpi_eject_store(struct acpi_device *device, const char *buf, size_t count)
-{
- int result;
- int ret = count;
- int islockable;
- acpi_status status;
- acpi_handle handle;
- acpi_object_type type = 0;
-
- if ((!count) || (buf[0] != '1')) {
- return -EINVAL;
- }
-#ifndef FORCE_EJECT
- if (device->driver == NULL) {
- ret = -ENODEV;
- goto err;
- }
-#endif
- status = acpi_get_type(device->handle, &type);
- if (ACPI_FAILURE(status) || (!device->flags.ejectable)) {
- ret = -ENODEV;
- goto err;
- }
-
- islockable = device->flags.lockable;
- handle = device->handle;
-
- result = acpi_bus_trim(device, 1);
-
- if (!result)
- result = acpi_eject_operation(handle, islockable);
-
- if (result) {
- ret = -EBUSY;
- }
- err:
- return ret;
-}
-
-/* --------------------------------------------------------------------------
- Performance Management
- -------------------------------------------------------------------------- */
-
-static int acpi_bus_get_perf_flags(struct acpi_device *device)
-{
- device->performance.state = ACPI_STATE_UNKNOWN;
- return 0;
-}
-
-/* --------------------------------------------------------------------------
- Driver Management
- -------------------------------------------------------------------------- */
-
-static LIST_HEAD(acpi_bus_drivers);
-
-/**
- * acpi_bus_match - match device IDs to driver's supported IDs
- * @device: the device that we are trying to match to a driver
- * @driver: driver whose device id table is being checked
- *
- * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it
- * matches the specified driver's criteria.
- */
-static int
-acpi_bus_match(struct acpi_device *device, struct acpi_driver *driver)
-{
- if (driver && driver->ops.match)
- return driver->ops.match(device, driver);
- return acpi_match_ids(device, driver->ids);
-}
-
-/**
- * acpi_bus_driver_init - add a device to a driver
- * @device: the device to add and initialize
- * @driver: driver for the device
- *
- * Used to initialize a device via its device driver. Called whenever a
- * driver is bound to a device. Invokes the driver's add() and start() ops.
- */
-static int
-acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
-{
- int result = 0;
-
-
- if (!device || !driver)
- return -EINVAL;
-
- if (!driver->ops.add)
- return -ENOSYS;
-
- result = driver->ops.add(device);
- if (result) {
- device->driver = NULL;
- acpi_driver_data(device) = NULL;
- return result;
- }
-
- device->driver = driver;
+ status = acpi_get_handle(device->handle, "_PSC", &handle);
+ if (ACPI_SUCCESS(status))
+ device->power.flags.explicit_get = 1;
+ status = acpi_get_handle(device->handle, "_IRC", &handle);
+ if (ACPI_SUCCESS(status))
+ device->power.flags.inrush_current = 1;
/*
- * TBD - Configuration Management: Assign resources to device based
- * upon possible configuration and currently allocated resources.
+ * Enumerate supported power management states
*/
+ for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
+ struct acpi_device_power_state *ps = &device->power.states[i];
+ char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Driver successfully bound to device\n"));
- return 0;
-}
-
-static int acpi_start_single_object(struct acpi_device *device)
-{
- int result = 0;
- struct acpi_driver *driver;
-
-
- if (!(driver = device->driver))
- return 0;
-
- if (driver->ops.start) {
- result = driver->ops.start(device);
- if (result && driver->ops.remove)
- driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
- }
-
- return result;
-}
-
-static void acpi_driver_attach(struct acpi_driver *drv)
-{
- struct list_head *node, *next;
-
-
- spin_lock(&acpi_device_lock);
- list_for_each_safe(node, next, &acpi_device_list) {
- struct acpi_device *dev =
- container_of(node, struct acpi_device, g_list);
-
- if (dev->driver || !dev->status.present)
- continue;
- spin_unlock(&acpi_device_lock);
-
- if (!acpi_bus_match(dev, drv)) {
- if (!acpi_bus_driver_init(dev, drv)) {
- acpi_start_single_object(dev);
- atomic_inc(&drv->references);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found driver [%s] for device [%s]\n",
- drv->name, dev->pnp.bus_id));
- }
+ /* Evaluate "_PRx" to se if power resources are referenced */
+ acpi_evaluate_reference(device->handle, object_name, NULL,
+ &ps->resources);
+ if (ps->resources.count) {
+ device->power.flags.power_resources = 1;
+ ps->flags.valid = 1;
}
- spin_lock(&acpi_device_lock);
- }
- spin_unlock(&acpi_device_lock);
-}
-
-static void acpi_driver_detach(struct acpi_driver *drv)
-{
- struct list_head *node, *next;
-
- spin_lock(&acpi_device_lock);
- list_for_each_safe(node, next, &acpi_device_list) {
- struct acpi_device *dev =
- container_of(node, struct acpi_device, g_list);
-
- if (dev->driver == drv) {
- spin_unlock(&acpi_device_lock);
- if (drv->ops.remove)
- drv->ops.remove(dev, ACPI_BUS_REMOVAL_NORMAL);
- spin_lock(&acpi_device_lock);
- dev->driver = NULL;
- dev->driver_data = NULL;
- atomic_dec(&drv->references);
+ /* Evaluate "_PSx" to see if we can do explicit sets */
+ object_name[2] = 'S';
+ status = acpi_get_handle(device->handle, object_name, &handle);
+ if (ACPI_SUCCESS(status)) {
+ ps->flags.explicit_set = 1;
+ ps->flags.valid = 1;
}
- }
- spin_unlock(&acpi_device_lock);
-}
-
-/**
- * acpi_bus_register_driver - register a driver with the ACPI bus
- * @driver: driver being registered
- *
- * Registers a driver with the ACPI bus. Searches the namespace for all
- * devices that match the driver's criteria and binds. Returns zero for
- * success or a negative error status for failure.
- */
-int acpi_bus_register_driver(struct acpi_driver *driver)
-{
-
- if (acpi_disabled)
- return -ENODEV;
-
- spin_lock(&acpi_device_lock);
- list_add_tail(&driver->node, &acpi_bus_drivers);
- spin_unlock(&acpi_device_lock);
- acpi_driver_attach(driver);
-
- return 0;
-}
-
-EXPORT_SYMBOL(acpi_bus_register_driver);
-
-/**
- * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
- * @driver: driver to unregister
- *
- * Unregisters a driver with the ACPI bus. Searches the namespace for all
- * devices that match the driver's criteria and unbinds.
- */
-void acpi_bus_unregister_driver(struct acpi_driver *driver)
-{
- acpi_driver_detach(driver);
-
- if (!atomic_read(&driver->references)) {
- spin_lock(&acpi_device_lock);
- list_del_init(&driver->node);
- spin_unlock(&acpi_device_lock);
- }
- return;
-}
-
-EXPORT_SYMBOL(acpi_bus_unregister_driver);
-
-/**
- * acpi_bus_find_driver - check if there is a driver installed for the device
- * @device: device that we are trying to find a supporting driver for
- *
- * Parses the list of registered drivers looking for a driver applicable for
- * the specified device.
- */
-static int acpi_bus_find_driver(struct acpi_device *device)
-{
- int result = 0;
- struct list_head *node, *next;
+ /* State is valid if we have some power control */
+ if (ps->resources.count || ps->flags.explicit_set)
+ ps->flags.valid = 1;
- spin_lock(&acpi_device_lock);
- list_for_each_safe(node, next, &acpi_bus_drivers) {
- struct acpi_driver *driver =
- container_of(node, struct acpi_driver, node);
-
- atomic_inc(&driver->references);
- spin_unlock(&acpi_device_lock);
- if (!acpi_bus_match(device, driver)) {
- result = acpi_bus_driver_init(device, driver);
- if (!result)
- goto Done;
- }
- atomic_dec(&driver->references);
- spin_lock(&acpi_device_lock);
+ ps->power = -1; /* Unknown - driver assigned */
+ ps->latency = -1; /* Unknown - driver assigned */
}
- spin_unlock(&acpi_device_lock);
-
- Done:
- return result;
-}
-/* --------------------------------------------------------------------------
- Device Enumeration
- -------------------------------------------------------------------------- */
+ /* Set defaults for D0 and D3 states (always valid) */
+ device->power.states[ACPI_STATE_D0].flags.valid = 1;
+ device->power.states[ACPI_STATE_D0].power = 100;
+ device->power.states[ACPI_STATE_D3].flags.valid = 1;
+ device->power.states[ACPI_STATE_D3].power = 0;
-acpi_status
-acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
-{
- acpi_status status;
- acpi_handle tmp;
- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
- union acpi_object *obj;
+ /* TBD: System wake support and resource requirements. */
- status = acpi_get_handle(handle, "_EJD", &tmp);
- if (ACPI_FAILURE(status))
- return status;
+ device->power.state = ACPI_STATE_UNKNOWN;
- status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
- if (ACPI_SUCCESS(status)) {
- obj = buffer.pointer;
- status = acpi_get_handle(NULL, obj->string.pointer, ejd);
- kfree(buffer.pointer);
- }
- return status;
+ return 0;
}
-EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
-
static int acpi_bus_get_flags(struct acpi_device *device)
{
@@ -782,6 +804,75 @@ static void acpi_device_get_busid(struct acpi_device *device,
}
}
+static int
+acpi_video_bus_match(struct acpi_device *device)
+{
+ acpi_handle h_dummy1;
+ acpi_handle h_dummy2;
+ acpi_handle h_dummy3;
+
+
+ if (!device)
+ return -EINVAL;
+
+ /* Since there is no HID, CID for ACPI Video drivers, we have
+ * to check well known required nodes for each feature we support.
+ */
+
+ /* Does this device able to support video switching ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
+ return 0;
+
+ /* Does this device able to retrieve a video ROM ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+ return 0;
+
+ /* Does this device able to configure which video head to be POSTed ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
+ return 0;
+
+ return -ENODEV;
+}
+
+/*
+ * acpi_bay_match - see if a device is an ejectable driver bay
+ *
+ * If an acpi object is ejectable and has one of the ACPI ATA methods defined,
+ * then we can safely call it an ejectable drive bay
+ */
+static int acpi_bay_match(struct acpi_device *device){
+ acpi_status status;
+ acpi_handle handle;
+ acpi_handle tmp;
+ acpi_handle phandle;
+
+ handle = device->handle;
+
+ status = acpi_get_handle(handle, "_EJ0", &tmp);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
+ return 0;
+
+ if (acpi_get_parent(handle, &phandle))
+ return -ENODEV;
+
+ if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
+ return 0;
+
+ return -ENODEV;
+}
+
static void acpi_device_set_id(struct acpi_device *device,
struct acpi_device *parent, acpi_handle handle,
int type)
@@ -812,6 +903,16 @@ static void acpi_device_set_id(struct acpi_device *device,
device->pnp.bus_address = info->address;
device->flags.bus_address = 1;
}
+
+ if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){
+ status = acpi_video_bus_match(device);
+ if(ACPI_SUCCESS(status))
+ hid = ACPI_VIDEO_HID;
+
+ status = acpi_bay_match(device);
+ if (ACPI_SUCCESS(status))
+ hid = ACPI_BAY_HID;
+ }
break;
case ACPI_BUS_TYPE_POWER:
hid = ACPI_POWER_HID;
@@ -888,86 +989,24 @@ static int acpi_device_set_context(struct acpi_device *device, int type)
return result;
}
-static void acpi_device_get_debug_info(struct acpi_device *device,
- acpi_handle handle, int type)
-{
-#ifdef CONFIG_ACPI_DEBUG_OUTPUT
- char *type_string = NULL;
- char name[80] = { '?', '\0' };
- struct acpi_buffer buffer = { sizeof(name), name };
-
- switch (type) {
- case ACPI_BUS_TYPE_DEVICE:
- type_string = "Device";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_POWER:
- type_string = "Power Resource";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_PROCESSOR:
- type_string = "Processor";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_SYSTEM:
- type_string = "System";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_THERMAL:
- type_string = "Thermal Zone";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_POWER_BUTTON:
- type_string = "Power Button";
- sprintf(name, "PWRB");
- break;
- case ACPI_BUS_TYPE_SLEEP_BUTTON:
- type_string = "Sleep Button";
- sprintf(name, "SLPB");
- break;
- }
-
- printk(KERN_DEBUG "Found %s %s [%p]\n", type_string, name, handle);
-#endif /*CONFIG_ACPI_DEBUG_OUTPUT */
-}
-
static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
{
- int result = 0;
- struct acpi_driver *driver;
-
-
if (!dev)
return -EINVAL;
- driver = dev->driver;
-
- if ((driver) && (driver->ops.remove)) {
-
- if (driver->ops.stop) {
- result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT);
- if (result)
- return result;
- }
-
- result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT);
- if (result) {
- return result;
- }
-
- atomic_dec(&dev->driver->references);
- dev->driver = NULL;
- acpi_driver_data(dev) = NULL;
- }
+ dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
+ device_release_driver(&dev->dev);
if (!rmdevice)
return 0;
+ /*
+ * unbind _ADR-Based Devices when hot removal
+ */
if (dev->flags.bus_address) {
if ((dev->parent) && (dev->parent->ops.unbind))
dev->parent->ops.unbind(dev);
}
-
acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
return 0;
@@ -975,7 +1014,8 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
static int
acpi_add_single_object(struct acpi_device **child,
- struct acpi_device *parent, acpi_handle handle, int type)
+ struct acpi_device *parent, acpi_handle handle, int type,
+ struct acpi_bus_ops *ops)
{
int result = 0;
struct acpi_device *device = NULL;
@@ -984,15 +1024,16 @@ acpi_add_single_object(struct acpi_device **child,
if (!child)
return -EINVAL;
- device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL);
+ device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
if (!device) {
printk(KERN_ERR PREFIX "Memory allocation error\n");
return -ENOMEM;
}
- memset(device, 0, sizeof(struct acpi_device));
device->handle = handle;
device->parent = parent;
+ device->bus_ops = *ops; /* workround for not call .start */
+
acpi_device_get_busid(device, handle, type);
@@ -1077,33 +1118,16 @@ acpi_add_single_object(struct acpi_device **child,
if ((result = acpi_device_set_context(device, type)))
goto end;
- acpi_device_get_debug_info(device, handle, type);
-
- acpi_device_register(device, parent);
+ result = acpi_device_register(device, parent);
/*
- * Bind _ADR-Based Devices
- * -----------------------
- * If there's a a bus address (_ADR) then we utilize the parent's
- * 'bind' function (if exists) to bind the ACPI- and natively-
- * enumerated device representations.
+ * Bind _ADR-Based Devices when hot add
*/
if (device->flags.bus_address) {
if (device->parent && device->parent->ops.bind)
device->parent->ops.bind(device);
}
- /*
- * Locate & Attach Driver
- * ----------------------
- * If there's a hardware id (_HID) or compatible ids (_CID) we check
- * to see if there's a driver installed for this kind of device. Note
- * that drivers can install before or after a device is enumerated.
- *
- * TBD: Assumes LDM provides driver hot-plug capability.
- */
- acpi_bus_find_driver(device);
-
end:
if (!result)
*child = device;
@@ -1189,14 +1213,14 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
if (ops->acpi_op_add)
status = acpi_add_single_object(&child, parent,
- chandle, type);
+ chandle, type, ops);
else
status = acpi_bus_get_device(chandle, &child);
if (ACPI_FAILURE(status))
continue;
- if (ops->acpi_op_start) {
+ if (ops->acpi_op_start && !(ops->acpi_op_add)) {
status = acpi_start_single_object(child);
if (ACPI_FAILURE(status))
continue;
@@ -1234,13 +1258,13 @@ acpi_bus_add(struct acpi_device **child,
int result;
struct acpi_bus_ops ops;
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_add = 1;
- result = acpi_add_single_object(child, parent, handle, type);
- if (!result) {
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
+ result = acpi_add_single_object(child, parent, handle, type, &ops);
+ if (!result)
result = acpi_bus_scan(*child, &ops);
- }
+
return result;
}
@@ -1326,127 +1350,35 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
{
int result = 0;
struct acpi_device *device = NULL;
-
+ struct acpi_bus_ops ops;
if (!root)
return -ENODEV;
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_add = 1;
+ ops.acpi_op_start = 1;
+
/*
* Enumerate all fixed-feature devices.
*/
- if (acpi_fadt.pwr_button == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
result = acpi_add_single_object(&device, acpi_root,
NULL,
- ACPI_BUS_TYPE_POWER_BUTTON);
- if (!result)
- result = acpi_start_single_object(device);
+ ACPI_BUS_TYPE_POWER_BUTTON,
+ &ops);
}
- if (acpi_fadt.sleep_button == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
result = acpi_add_single_object(&device, acpi_root,
NULL,
- ACPI_BUS_TYPE_SLEEP_BUTTON);
- if (!result)
- result = acpi_start_single_object(device);
+ ACPI_BUS_TYPE_SLEEP_BUTTON,
+ &ops);
}
return result;
}
-
-static inline struct acpi_device * to_acpi_dev(struct device * dev)
-{
- return container_of(dev, struct acpi_device, dev);
-}
-
-
-static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state)
-{
- struct acpi_device * dev, * next;
- int result;
-
- spin_lock(&acpi_device_lock);
- list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) {
- if (dev->driver && dev->driver->ops.suspend) {
- spin_unlock(&acpi_device_lock);
- result = dev->driver->ops.suspend(dev, 0);
- if (result) {
- printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n",
- acpi_device_name(dev),
- acpi_device_bid(dev), result);
- }
- spin_lock(&acpi_device_lock);
- }
- }
- spin_unlock(&acpi_device_lock);
- return 0;
-}
-
-
-static int acpi_device_suspend(struct device * dev, pm_message_t state)
-{
- struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
- /*
- * For now, we should only register 1 generic device -
- * the ACPI root device - and from there, we walk the
- * tree of ACPI devices to suspend each one using the
- * ACPI driver methods.
- */
- if (acpi_dev->handle == ACPI_ROOT_OBJECT)
- root_suspend(acpi_dev, state);
- return 0;
-}
-
-
-
-static int root_resume(struct acpi_device * acpi_dev)
-{
- struct acpi_device * dev, * next;
- int result;
-
- spin_lock(&acpi_device_lock);
- list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) {
- if (dev->driver && dev->driver->ops.resume) {
- spin_unlock(&acpi_device_lock);
- result = dev->driver->ops.resume(dev, 0);
- if (result) {
- printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n",
- acpi_device_name(dev),
- acpi_device_bid(dev), result);
- }
- spin_lock(&acpi_device_lock);
- }
- }
- spin_unlock(&acpi_device_lock);
- return 0;
-}
-
-
-static int acpi_device_resume(struct device * dev)
-{
- struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
- /*
- * For now, we should only register 1 generic device -
- * the ACPI root device - and from there, we walk the
- * tree of ACPI devices to resume each one using the
- * ACPI driver methods.
- */
- if (acpi_dev->handle == ACPI_ROOT_OBJECT)
- root_resume(acpi_dev);
- return 0;
-}
-
-
-static struct bus_type acpi_bus_type = {
- .name = "acpi",
- .suspend = acpi_device_suspend,
- .resume = acpi_device_resume,
-};
-
-
-
static int __init acpi_scan_init(void)
{
int result;
@@ -1456,9 +1388,9 @@ static int __init acpi_scan_init(void)
if (acpi_disabled)
return 0;
- result = kset_register(&acpi_namespace_kset);
- if (result < 0)
- printk(KERN_ERR PREFIX "kset_register error: %d\n", result);
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_add = 1;
+ ops.acpi_op_start = 1;
result = bus_register(&acpi_bus_type);
if (result) {
@@ -1470,32 +1402,16 @@ static int __init acpi_scan_init(void)
* Create the root device in the bus's device tree
*/
result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT,
- ACPI_BUS_TYPE_SYSTEM);
+ ACPI_BUS_TYPE_SYSTEM, &ops);
if (result)
goto Done;
- result = acpi_start_single_object(acpi_root);
- if (result)
- goto Done;
-
- acpi_root->dev.bus = &acpi_bus_type;
- snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name);
- result = device_register(&acpi_root->dev);
- if (result) {
- /* We don't want to quit even if we failed to add suspend/resume */
- printk(KERN_ERR PREFIX "Could not register device\n");
- }
-
/*
* Enumerate devices in the ACPI namespace.
*/
result = acpi_bus_scan_fixed(acpi_root);
- if (!result) {
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
- ops.acpi_op_start = 1;
+ if (!result)
result = acpi_bus_scan(acpi_root, &ops);
- }
if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 34962578039..ccc11b33d89 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -73,7 +73,7 @@ acpi_system_write_sleep(struct file *file,
static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
{
u32 sec, min, hr;
- u32 day, mo, yr;
+ u32 day, mo, yr, cent = 0;
unsigned char rtc_control = 0;
unsigned long flags;
@@ -87,20 +87,19 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
rtc_control = CMOS_READ(RTC_CONTROL);
/* If we ever get an FACP with proper values... */
- if (acpi_gbl_FADT->day_alrm)
+ if (acpi_gbl_FADT.day_alarm)
/* ACPI spec: only low 6 its should be cared */
- day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F;
+ day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F;
else
day = CMOS_READ(RTC_DAY_OF_MONTH);
- if (acpi_gbl_FADT->mon_alrm)
- mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
+ if (acpi_gbl_FADT.month_alarm)
+ mo = CMOS_READ(acpi_gbl_FADT.month_alarm);
else
mo = CMOS_READ(RTC_MONTH);
- if (acpi_gbl_FADT->century)
- yr = CMOS_READ(acpi_gbl_FADT->century) * 100 +
- CMOS_READ(RTC_YEAR);
- else
- yr = CMOS_READ(RTC_YEAR);
+ if (acpi_gbl_FADT.century)
+ cent = CMOS_READ(acpi_gbl_FADT.century);
+
+ yr = CMOS_READ(RTC_YEAR);
spin_unlock_irqrestore(&rtc_lock, flags);
@@ -111,10 +110,11 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
BCD_TO_BIN(day);
BCD_TO_BIN(mo);
BCD_TO_BIN(yr);
+ BCD_TO_BIN(cent);
}
/* we're trusting the FADT (see above) */
- if (!acpi_gbl_FADT->century)
+ if (!acpi_gbl_FADT.century)
/* If we're not trusting the FADT, we should at least make it
* right for _this_ century... ehm, what is _this_ century?
*
@@ -134,6 +134,8 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
*
*/
yr += 2000;
+ else
+ yr += cent * 100;
seq_printf(seq, "%4.4u-", yr);
(mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo);
@@ -317,12 +319,12 @@ acpi_system_write_alarm(struct file *file,
* offsets into the CMOS RAM here -- which for some reason are pointing
* to the RTC area of memory.
*/
- if (acpi_gbl_FADT->day_alrm)
- CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
- if (acpi_gbl_FADT->mon_alrm)
- CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
- if (acpi_gbl_FADT->century)
- CMOS_WRITE(yr / 100, acpi_gbl_FADT->century);
+ if (acpi_gbl_FADT.day_alarm)
+ CMOS_WRITE(day, acpi_gbl_FADT.day_alarm);
+ if (acpi_gbl_FADT.month_alarm)
+ CMOS_WRITE(mo, acpi_gbl_FADT.month_alarm);
+ if (acpi_gbl_FADT.century)
+ CMOS_WRITE(yr / 100, acpi_gbl_FADT.century);
/* enable the rtc alarm interrupt */
rtc_control |= RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL);
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c
index af1dbabaf0b..fab8f2694f0 100644
--- a/drivers/acpi/sleep/wakeup.c
+++ b/drivers/acpi/sleep/wakeup.c
@@ -183,11 +183,11 @@ late_initcall(acpi_wakeup_device_init);
#endif
/*
- * Disable all wakeup GPEs before power off.
- *
+ * Disable all wakeup GPEs before entering requested sleep state.
+ * @sleep_state: ACPI state
* Since acpi_enter_sleep_state() will disable all
* RUNTIME GPEs, we simply mark all GPES that
- * are not enabled for wakeup from S5 as RUNTIME.
+ * are not enabled for wakeup from requested state as RUNTIME.
*/
void acpi_gpe_sleep_prepare(u32 sleep_state)
{
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index d86dcb3c236..7147b0bdab0 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -32,6 +32,11 @@
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("acpi_system")
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "acpi."
+
#define ACPI_SYSTEM_CLASS "system"
#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver"
#define ACPI_SYSTEM_DEVICE_NAME "System"
@@ -39,11 +44,24 @@ ACPI_MODULE_NAME("acpi_system")
#define ACPI_SYSTEM_FILE_EVENT "event"
#define ACPI_SYSTEM_FILE_DSDT "dsdt"
#define ACPI_SYSTEM_FILE_FADT "fadt"
-extern struct fadt_descriptor acpi_fadt;
+
+/*
+ * Make ACPICA version work as module param
+ */
+static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
+ int result;
+
+ result = sprintf(buffer, "%x", ACPI_CA_VERSION);
+
+ return result;
+}
+
+module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_system_read_info(struct seq_file *seq, void *offset)
{
@@ -63,6 +81,7 @@ static const struct file_operations acpi_system_info_ops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif
static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
loff_t *);
@@ -76,17 +95,16 @@ acpi_system_read_dsdt(struct file *file,
char __user * buffer, size_t count, loff_t * ppos)
{
acpi_status status = AE_OK;
- struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_table_header *dsdt = NULL;
ssize_t res;
- status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
+ status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
if (ACPI_FAILURE(status))
return -ENODEV;
res = simple_read_from_buffer(buffer, count, ppos,
- dsdt.pointer, dsdt.length);
- kfree(dsdt.pointer);
+ dsdt, dsdt->length);
return res;
}
@@ -103,17 +121,16 @@ acpi_system_read_fadt(struct file *file,
char __user * buffer, size_t count, loff_t * ppos)
{
acpi_status status = AE_OK;
- struct acpi_buffer fadt = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_table_header *fadt = NULL;
ssize_t res;
- status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &fadt);
+ status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
if (ACPI_FAILURE(status))
return -ENODEV;
res = simple_read_from_buffer(buffer, count, ppos,
- fadt.pointer, fadt.length);
- kfree(fadt.pointer);
+ fadt, fadt->length);
return res;
}
@@ -128,6 +145,7 @@ static int __init acpi_system_init(void)
if (acpi_disabled)
return 0;
+#ifdef CONFIG_ACPI_PROCFS
/* 'info' [R] */
name = ACPI_SYSTEM_FILE_INFO;
entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
@@ -136,6 +154,7 @@ static int __init acpi_system_init(void)
else {
entry->proc_fops = &acpi_system_info_ops;
}
+#endif
/* 'dsdt' [R] */
name = ACPI_SYSTEM_FILE_DSDT;
@@ -159,7 +178,9 @@ static int __init acpi_system_init(void)
Error:
remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
+#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
+#endif
error = -EFAULT;
goto Done;
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index bfb3bfcf9e9..ba4cb200314 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -38,154 +38,97 @@
#define ACPI_MAX_TABLES 128
-static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
- [ACPI_TABLE_UNKNOWN] = "????",
- [ACPI_APIC] = "APIC",
- [ACPI_BOOT] = "BOOT",
- [ACPI_DBGP] = "DBGP",
- [ACPI_DSDT] = "DSDT",
- [ACPI_ECDT] = "ECDT",
- [ACPI_ETDT] = "ETDT",
- [ACPI_FADT] = "FACP",
- [ACPI_FACS] = "FACS",
- [ACPI_OEMX] = "OEM",
- [ACPI_PSDT] = "PSDT",
- [ACPI_SBST] = "SBST",
- [ACPI_SLIT] = "SLIT",
- [ACPI_SPCR] = "SPCR",
- [ACPI_SRAT] = "SRAT",
- [ACPI_SSDT] = "SSDT",
- [ACPI_SPMI] = "SPMI",
- [ACPI_HPET] = "HPET",
- [ACPI_MCFG] = "MCFG",
-};
-
static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
-/* System Description Table (RSDT/XSDT) */
-struct acpi_table_sdt {
- unsigned long pa;
- enum acpi_table_id id;
- unsigned long size;
-} __attribute__ ((packed));
-
-static unsigned long sdt_pa; /* Physical Address */
-static unsigned long sdt_count; /* Table count */
+static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
-static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata;
-
-void acpi_table_print(struct acpi_table_header *header, unsigned long phys_addr)
-{
- char *name = NULL;
-
- if (!header)
- return;
-
- /* Some table signatures aren't good table names */
-
- if (!strncmp((char *)&header->signature,
- acpi_table_signatures[ACPI_APIC],
- sizeof(header->signature))) {
- name = "MADT";
- } else if (!strncmp((char *)&header->signature,
- acpi_table_signatures[ACPI_FADT],
- sizeof(header->signature))) {
- name = "FADT";
- } else
- name = header->signature;
-
- printk(KERN_DEBUG PREFIX
- "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name,
- header->revision, header->oem_id, header->oem_table_id,
- header->oem_revision, header->asl_compiler_id,
- header->asl_compiler_revision, (void *)phys_addr);
-}
-
-void acpi_table_print_madt_entry(acpi_table_entry_header * header)
+void acpi_table_print_madt_entry(struct acpi_subtable_header * header)
{
if (!header)
return;
switch (header->type) {
- case ACPI_MADT_LAPIC:
+ case ACPI_MADT_TYPE_LOCAL_APIC:
{
- struct acpi_table_lapic *p =
- (struct acpi_table_lapic *)header;
+ struct acpi_madt_local_apic *p =
+ (struct acpi_madt_local_apic *)header;
printk(KERN_INFO PREFIX
"LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
- p->acpi_id, p->id,
- p->flags.enabled ? "enabled" : "disabled");
+ p->processor_id, p->id,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
- case ACPI_MADT_IOAPIC:
+ case ACPI_MADT_TYPE_IO_APIC:
{
- struct acpi_table_ioapic *p =
- (struct acpi_table_ioapic *)header;
+ struct acpi_madt_io_apic *p =
+ (struct acpi_madt_io_apic *)header;
printk(KERN_INFO PREFIX
"IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
p->id, p->address, p->global_irq_base);
}
break;
- case ACPI_MADT_INT_SRC_OVR:
+ case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
{
- struct acpi_table_int_src_ovr *p =
- (struct acpi_table_int_src_ovr *)header;
+ struct acpi_madt_interrupt_override *p =
+ (struct acpi_madt_interrupt_override *)header;
printk(KERN_INFO PREFIX
"INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
- p->bus, p->bus_irq, p->global_irq,
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger]);
- if (p->flags.reserved)
+ p->bus, p->source_irq, p->global_irq,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
+ if (p->inti_flags &
+ ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
printk(KERN_INFO PREFIX
"INT_SRC_OVR unexpected reserved flags: 0x%x\n",
- p->flags.reserved);
+ p->inti_flags &
+ ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
}
break;
- case ACPI_MADT_NMI_SRC:
+ case ACPI_MADT_TYPE_NMI_SOURCE:
{
- struct acpi_table_nmi_src *p =
- (struct acpi_table_nmi_src *)header;
+ struct acpi_madt_nmi_source *p =
+ (struct acpi_madt_nmi_source *)header;
printk(KERN_INFO PREFIX
"NMI_SRC (%s %s global_irq %d)\n",
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger],
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
p->global_irq);
}
break;
- case ACPI_MADT_LAPIC_NMI:
+ case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
{
- struct acpi_table_lapic_nmi *p =
- (struct acpi_table_lapic_nmi *)header;
+ struct acpi_madt_local_apic_nmi *p =
+ (struct acpi_madt_local_apic_nmi *)header;
printk(KERN_INFO PREFIX
"LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
- p->acpi_id,
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger],
+ p->processor_id,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
p->lint);
}
break;
- case ACPI_MADT_LAPIC_ADDR_OVR:
+ case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
{
- struct acpi_table_lapic_addr_ovr *p =
- (struct acpi_table_lapic_addr_ovr *)header;
+ struct acpi_madt_local_apic_override *p =
+ (struct acpi_madt_local_apic_override *)header;
printk(KERN_INFO PREFIX
"LAPIC_ADDR_OVR (address[%p])\n",
(void *)(unsigned long)p->address);
}
break;
- case ACPI_MADT_IOSAPIC:
+ case ACPI_MADT_TYPE_IO_SAPIC:
{
- struct acpi_table_iosapic *p =
- (struct acpi_table_iosapic *)header;
+ struct acpi_madt_io_sapic *p =
+ (struct acpi_madt_io_sapic *)header;
printk(KERN_INFO PREFIX
"IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
p->id, (void *)(unsigned long)p->address,
@@ -193,26 +136,26 @@ void acpi_table_print_madt_entry(acpi_table_entry_header * header)
}
break;
- case ACPI_MADT_LSAPIC:
+ case ACPI_MADT_TYPE_LOCAL_SAPIC:
{
- struct acpi_table_lsapic *p =
- (struct acpi_table_lsapic *)header;
+ struct acpi_madt_local_sapic *p =
+ (struct acpi_madt_local_sapic *)header;
printk(KERN_INFO PREFIX
"LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
- p->acpi_id, p->id, p->eid,
- p->flags.enabled ? "enabled" : "disabled");
+ p->processor_id, p->id, p->eid,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
- case ACPI_MADT_PLAT_INT_SRC:
+ case ACPI_MADT_TYPE_INTERRUPT_SOURCE:
{
- struct acpi_table_plat_int_src *p =
- (struct acpi_table_plat_int_src *)header;
+ struct acpi_madt_interrupt_source *p =
+ (struct acpi_madt_interrupt_source *)header;
printk(KERN_INFO PREFIX
"PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger],
- p->type, p->id, p->eid, p->iosapic_vector,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+ p->type, p->id, p->eid, p->io_sapic_vector,
p->global_irq);
}
break;
@@ -225,342 +168,76 @@ void acpi_table_print_madt_entry(acpi_table_entry_header * header)
}
}
-static int
-acpi_table_compute_checksum(void *table_pointer, unsigned long length)
-{
- u8 *p = (u8 *) table_pointer;
- unsigned long remains = length;
- unsigned long sum = 0;
-
- if (!p || !length)
- return -EINVAL;
-
- while (remains--)
- sum += *p++;
-
- return (sum & 0xFF);
-}
-/*
- * acpi_get_table_header_early()
- * for acpi_blacklisted(), acpi_table_get_sdt()
- */
int __init
-acpi_get_table_header_early(enum acpi_table_id id,
- struct acpi_table_header **header)
-{
- unsigned int i;
- enum acpi_table_id temp_id;
-
- /* DSDT is different from the rest */
- if (id == ACPI_DSDT)
- temp_id = ACPI_FADT;
- else
- temp_id = id;
-
- /* Locate the table. */
-
- for (i = 0; i < sdt_count; i++) {
- if (sdt_entry[i].id != temp_id)
- continue;
- *header = (void *)
- __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
- if (!*header) {
- printk(KERN_WARNING PREFIX "Unable to map %s\n",
- acpi_table_signatures[temp_id]);
- return -ENODEV;
- }
- break;
- }
-
- if (!*header) {
- printk(KERN_WARNING PREFIX "%s not present\n",
- acpi_table_signatures[id]);
- return -ENODEV;
- }
-
- /* Map the DSDT header via the pointer in the FADT */
- if (id == ACPI_DSDT) {
- struct fadt_descriptor *fadt =
- (struct fadt_descriptor *)*header;
-
- if (fadt->revision == 3 && fadt->Xdsdt) {
- *header = (void *)__acpi_map_table(fadt->Xdsdt,
- sizeof(struct
- acpi_table_header));
- } else if (fadt->V1_dsdt) {
- *header = (void *)__acpi_map_table(fadt->V1_dsdt,
- sizeof(struct
- acpi_table_header));
- } else
- *header = NULL;
-
- if (!*header) {
- printk(KERN_WARNING PREFIX "Unable to map DSDT\n");
- return -ENODEV;
- }
- }
-
- return 0;
-}
-
-int __init
-acpi_table_parse_madt_family(enum acpi_table_id id,
+acpi_table_parse_madt_family(char *id,
unsigned long madt_size,
int entry_id,
acpi_madt_entry_handler handler,
unsigned int max_entries)
{
- void *madt = NULL;
- acpi_table_entry_header *entry;
+ struct acpi_table_header *madt = NULL;
+ struct acpi_subtable_header *entry;
unsigned int count = 0;
unsigned long madt_end;
- unsigned int i;
if (!handler)
return -EINVAL;
/* Locate the MADT (if exists). There should only be one. */
-
- for (i = 0; i < sdt_count; i++) {
- if (sdt_entry[i].id != id)
- continue;
- madt = (void *)
- __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
- if (!madt) {
- printk(KERN_WARNING PREFIX "Unable to map %s\n",
- acpi_table_signatures[id]);
- return -ENODEV;
- }
- break;
- }
+ acpi_get_table(id, 0, &madt);
if (!madt) {
- printk(KERN_WARNING PREFIX "%s not present\n",
- acpi_table_signatures[id]);
+ printk(KERN_WARNING PREFIX "%4.4s not present\n", id);
return -ENODEV;
}
- madt_end = (unsigned long)madt + sdt_entry[i].size;
+ madt_end = (unsigned long)madt + madt->length;
/* Parse all entries looking for a match. */
- entry = (acpi_table_entry_header *)
+ entry = (struct acpi_subtable_header *)
((unsigned long)madt + madt_size);
- while (((unsigned long)entry) + sizeof(acpi_table_entry_header) <
+ while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
madt_end) {
if (entry->type == entry_id
&& (!max_entries || count++ < max_entries))
if (handler(entry, madt_end))
return -EINVAL;
- entry = (acpi_table_entry_header *)
+ entry = (struct acpi_subtable_header *)
((unsigned long)entry + entry->length);
}
if (max_entries && count > max_entries) {
- printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of "
- "%i found\n", acpi_table_signatures[id], entry_id,
- count - max_entries, count);
+ printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of "
+ "%i found\n", id, entry_id, count - max_entries, count);
}
return count;
}
int __init
-acpi_table_parse_madt(enum acpi_madt_entry_id id,
+acpi_table_parse_madt(enum acpi_madt_type id,
acpi_madt_entry_handler handler, unsigned int max_entries)
{
- return acpi_table_parse_madt_family(ACPI_APIC,
+ return acpi_table_parse_madt_family(ACPI_SIG_MADT,
sizeof(struct acpi_table_madt), id,
handler, max_entries);
}
-int __init acpi_table_parse(enum acpi_table_id id, acpi_table_handler handler)
+int __init acpi_table_parse(char *id, acpi_table_handler handler)
{
- int count = 0;
- unsigned int i = 0;
-
+ struct acpi_table_header *table = NULL;
if (!handler)
return -EINVAL;
- for (i = 0; i < sdt_count; i++) {
- if (sdt_entry[i].id != id)
- continue;
- count++;
- if (count == 1)
- handler(sdt_entry[i].pa, sdt_entry[i].size);
-
- else
- printk(KERN_WARNING PREFIX
- "%d duplicate %s table ignored.\n", count,
- acpi_table_signatures[id]);
- }
-
- return count;
-}
-
-static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp)
-{
- struct acpi_table_header *header = NULL;
- unsigned int i, id = 0;
-
- if (!rsdp)
- return -EINVAL;
-
- /* First check XSDT (but only on ACPI 2.0-compatible systems) */
-
- if ((rsdp->revision >= 2) &&
- (((struct acpi20_table_rsdp *)rsdp)->xsdt_address)) {
-
- struct acpi_table_xsdt *mapped_xsdt = NULL;
-
- sdt_pa = ((struct acpi20_table_rsdp *)rsdp)->xsdt_address;
-
- /* map in just the header */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
-
- if (!header) {
- printk(KERN_WARNING PREFIX
- "Unable to map XSDT header\n");
- return -ENODEV;
- }
-
- /* remap in the entire table before processing */
- mapped_xsdt = (struct acpi_table_xsdt *)
- __acpi_map_table(sdt_pa, header->length);
- if (!mapped_xsdt) {
- printk(KERN_WARNING PREFIX "Unable to map XSDT\n");
- return -ENODEV;
- }
- header = &mapped_xsdt->header;
-
- if (strncmp(header->signature, "XSDT", 4)) {
- printk(KERN_WARNING PREFIX
- "XSDT signature incorrect\n");
- return -ENODEV;
- }
-
- if (acpi_table_compute_checksum(header, header->length)) {
- printk(KERN_WARNING PREFIX "Invalid XSDT checksum\n");
- return -ENODEV;
- }
-
- sdt_count =
- (header->length - sizeof(struct acpi_table_header)) >> 3;
- if (sdt_count > ACPI_MAX_TABLES) {
- printk(KERN_WARNING PREFIX
- "Truncated %lu XSDT entries\n",
- (sdt_count - ACPI_MAX_TABLES));
- sdt_count = ACPI_MAX_TABLES;
- }
-
- for (i = 0; i < sdt_count; i++)
- sdt_entry[i].pa = (unsigned long)mapped_xsdt->entry[i];
- }
-
- /* Then check RSDT */
-
- else if (rsdp->rsdt_address) {
-
- struct acpi_table_rsdt *mapped_rsdt = NULL;
-
- sdt_pa = rsdp->rsdt_address;
-
- /* map in just the header */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
- if (!header) {
- printk(KERN_WARNING PREFIX
- "Unable to map RSDT header\n");
- return -ENODEV;
- }
-
- /* remap in the entire table before processing */
- mapped_rsdt = (struct acpi_table_rsdt *)
- __acpi_map_table(sdt_pa, header->length);
- if (!mapped_rsdt) {
- printk(KERN_WARNING PREFIX "Unable to map RSDT\n");
- return -ENODEV;
- }
- header = &mapped_rsdt->header;
-
- if (strncmp(header->signature, "RSDT", 4)) {
- printk(KERN_WARNING PREFIX
- "RSDT signature incorrect\n");
- return -ENODEV;
- }
-
- if (acpi_table_compute_checksum(header, header->length)) {
- printk(KERN_WARNING PREFIX "Invalid RSDT checksum\n");
- return -ENODEV;
- }
-
- sdt_count =
- (header->length - sizeof(struct acpi_table_header)) >> 2;
- if (sdt_count > ACPI_MAX_TABLES) {
- printk(KERN_WARNING PREFIX
- "Truncated %lu RSDT entries\n",
- (sdt_count - ACPI_MAX_TABLES));
- sdt_count = ACPI_MAX_TABLES;
- }
-
- for (i = 0; i < sdt_count; i++)
- sdt_entry[i].pa = (unsigned long)mapped_rsdt->entry[i];
- }
-
- else {
- printk(KERN_WARNING PREFIX
- "No System Description Table (RSDT/XSDT) specified in RSDP\n");
- return -ENODEV;
- }
-
- acpi_table_print(header, sdt_pa);
-
- for (i = 0; i < sdt_count; i++) {
-
- /* map in just the header */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_entry[i].pa,
- sizeof(struct acpi_table_header));
- if (!header)
- continue;
-
- /* remap in the entire table before processing */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_entry[i].pa, header->length);
- if (!header)
- continue;
-
- acpi_table_print(header, sdt_entry[i].pa);
-
- if (acpi_table_compute_checksum(header, header->length)) {
- printk(KERN_WARNING " >>> ERROR: Invalid checksum\n");
- continue;
- }
-
- sdt_entry[i].size = header->length;
-
- for (id = 0; id < ACPI_TABLE_COUNT; id++) {
- if (!strncmp((char *)&header->signature,
- acpi_table_signatures[id],
- sizeof(header->signature))) {
- sdt_entry[i].id = id;
- }
- }
- }
-
- /*
- * The DSDT is *not* in the RSDT (why not? no idea.) but we want
- * to print its info, because this is what people usually blacklist
- * against. Unfortunately, we don't know the phys_addr, so just
- * print 0. Maybe no one will notice.
- */
- if (!acpi_get_table_header_early(ACPI_DSDT, &header))
- acpi_table_print(header, 0);
-
- return 0;
+ acpi_get_table(id, 0, &table);
+ if (table) {
+ handler(table);
+ return 1;
+ } else
+ return 0;
}
/*
@@ -568,54 +245,13 @@ static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp)
*
* find RSDP, find and checksum SDT/XSDT.
* checksum all tables, print SDT/XSDT
- *
+ *
* result: sdt_entry[] is initialized
*/
+
int __init acpi_table_init(void)
{
- struct acpi_table_rsdp *rsdp = NULL;
- unsigned long rsdp_phys = 0;
- int result = 0;
-
- /* Locate and map the Root System Description Table (RSDP) */
-
- rsdp_phys = acpi_find_rsdp();
- if (!rsdp_phys) {
- printk(KERN_ERR PREFIX "Unable to locate RSDP\n");
- return -ENODEV;
- }
-
- rsdp = (struct acpi_table_rsdp *)__acpi_map_table(rsdp_phys,
- sizeof(struct acpi_table_rsdp));
- if (!rsdp) {
- printk(KERN_WARNING PREFIX "Unable to map RSDP\n");
- return -ENODEV;
- }
-
- printk(KERN_DEBUG PREFIX
- "RSDP (v%3.3d %6.6s ) @ 0x%p\n",
- rsdp->revision, rsdp->oem_id, (void *)rsdp_phys);
-
- if (rsdp->revision < 2)
- result =
- acpi_table_compute_checksum(rsdp,
- sizeof(struct acpi_table_rsdp));
- else
- result =
- acpi_table_compute_checksum(rsdp,
- ((struct acpi20_table_rsdp *)
- rsdp)->length);
-
- if (result) {
- printk(KERN_WARNING " >>> ERROR: Invalid checksum\n");
- return -ENODEV;
- }
-
- /* Locate and map the System Description table (RSDT/XSDT) */
-
- if (acpi_table_get_sdt(rsdp))
- return -ENODEV;
-
+ acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
return 0;
}
diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile
index aa4c69594d9..0a7d7afac25 100644
--- a/drivers/acpi/tables/Makefile
+++ b/drivers/acpi/tables/Makefile
@@ -2,7 +2,6 @@
# Makefile for all Linux ACPI interpreter subdirectories
#
-obj-y := tbconvrt.o tbget.o tbrsdt.o tbxface.o \
- tbgetall.o tbinstal.o tbutils.o tbxfroot.o
+obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o
EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c
deleted file mode 100644
index d697fcb35d5..00000000000
--- a/drivers/acpi/tables/tbconvrt.c
+++ /dev/null
@@ -1,622 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbconvrt - ACPI Table conversion utilities
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbconvrt")
-
-/* Local prototypes */
-static void
-acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
- u8 register_bit_width,
- acpi_physical_address address);
-
-static void
-acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor_rev1 *original_fadt);
-
-static void
-acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor *original_fadt);
-
-u8 acpi_fadt_is_v1;
-ACPI_EXPORT_SYMBOL(acpi_fadt_is_v1)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_count
- *
- * PARAMETERS: RSDP - Pointer to the RSDP
- * RSDT - Pointer to the RSDT/XSDT
- *
- * RETURN: The number of tables pointed to by the RSDT or XSDT.
- *
- * DESCRIPTION: Calculate the number of tables. Automatically handles either
- * an RSDT or XSDT.
- *
- ******************************************************************************/
-
-u32
-acpi_tb_get_table_count(struct rsdp_descriptor *RSDP,
- struct acpi_table_header *RSDT)
-{
- u32 pointer_size;
-
- ACPI_FUNCTION_ENTRY();
-
- /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
-
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- pointer_size = sizeof(u32);
- } else {
- pointer_size = sizeof(u64);
- }
-
- /*
- * Determine the number of tables pointed to by the RSDT/XSDT.
- * This is defined by the ACPI Specification to be the number of
- * pointers contained within the RSDT/XSDT. The size of the pointers
- * is architecture-dependent.
- */
- return ((RSDT->length -
- sizeof(struct acpi_table_header)) / pointer_size);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_to_xsdt
- *
- * PARAMETERS: table_info - Info about the RSDT
- *
- * RETURN: Status
- *
- * DESCRIPTION: Convert an RSDT to an XSDT (internal common format)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info)
-{
- acpi_size table_size;
- u32 i;
- struct xsdt_descriptor *new_table;
-
- ACPI_FUNCTION_ENTRY();
-
- /* Compute size of the converted XSDT */
-
- table_size = ((acpi_size) acpi_gbl_rsdt_table_count * sizeof(u64)) +
- sizeof(struct acpi_table_header);
-
- /* Allocate an XSDT */
-
- new_table = ACPI_ALLOCATE_ZEROED(table_size);
- if (!new_table) {
- return (AE_NO_MEMORY);
- }
-
- /* Copy the header and set the length */
-
- ACPI_MEMCPY(new_table, table_info->pointer,
- sizeof(struct acpi_table_header));
- new_table->length = (u32) table_size;
-
- /* Copy the table pointers */
-
- for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
-
- /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
-
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- ACPI_STORE_ADDRESS(new_table->table_offset_entry[i],
- (ACPI_CAST_PTR
- (struct rsdt_descriptor,
- table_info->pointer))->
- table_offset_entry[i]);
- } else {
- new_table->table_offset_entry[i] =
- (ACPI_CAST_PTR(struct xsdt_descriptor,
- table_info->pointer))->
- table_offset_entry[i];
- }
- }
-
- /* Delete the original table (either mapped or in a buffer) */
-
- acpi_tb_delete_single_table(table_info);
-
- /* Point the table descriptor to the new table */
-
- table_info->pointer =
- ACPI_CAST_PTR(struct acpi_table_header, new_table);
- table_info->length = table_size;
- table_info->allocation = ACPI_MEM_ALLOCATED;
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_init_generic_address
- *
- * PARAMETERS: new_gas_struct - GAS struct to be initialized
- * register_bit_width - Width of this register
- * Address - Address of the register
- *
- * RETURN: None
- *
- * DESCRIPTION: Initialize a GAS structure.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
- u8 register_bit_width,
- acpi_physical_address address)
-{
-
- ACPI_STORE_ADDRESS(new_gas_struct->address, address);
-
- new_gas_struct->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
- new_gas_struct->register_bit_width = register_bit_width;
- new_gas_struct->register_bit_offset = 0;
- new_gas_struct->access_width = 0;
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_fadt1
- *
- * PARAMETERS: local_fadt - Pointer to new FADT
- * original_fadt - Pointer to old FADT
- *
- * RETURN: None, populates local_fadt
- *
- * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format
- *
- ******************************************************************************/
-
-static void
-acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor_rev1 *original_fadt)
-{
-
- /* ACPI 1.0 FACS */
- /* The BIOS stored FADT should agree with Revision 1.0 */
- acpi_fadt_is_v1 = 1;
-
- /*
- * Copy the table header and the common part of the tables.
- *
- * The 2.0 table is an extension of the 1.0 table, so the entire 1.0
- * table can be copied first, then expand some fields to 64 bits.
- */
- ACPI_MEMCPY(local_fadt, original_fadt,
- sizeof(struct fadt_descriptor_rev1));
-
- /* Convert table pointers to 64-bit fields */
-
- ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl,
- local_fadt->V1_firmware_ctrl);
- ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt);
-
- /*
- * System Interrupt Model isn't used in ACPI 2.0
- * (local_fadt->Reserved1 = 0;)
- */
-
- /*
- * This field is set by the OEM to convey the preferred power management
- * profile to OSPM. It doesn't have any 1.0 equivalence. Since we don't
- * know what kind of 32-bit system this is, we will use "unspecified".
- */
- local_fadt->prefer_PM_profile = PM_UNSPECIFIED;
-
- /*
- * Processor Performance State Control. This is the value OSPM writes to
- * the SMI_CMD register to assume processor performance state control
- * responsibility. There isn't any equivalence in 1.0, but as many 1.x
- * ACPI tables contain _PCT and _PSS we also keep this value, unless
- * acpi_strict is set.
- */
- if (acpi_strict)
- local_fadt->pstate_cnt = 0;
-
- /*
- * Support for the _CST object and C States change notification.
- * This data item hasn't any 1.0 equivalence so leave it zero.
- */
- local_fadt->cst_cnt = 0;
-
- /*
- * FADT Rev 2 was an interim FADT released between ACPI 1.0 and ACPI 2.0.
- * It primarily adds the FADT reset mechanism.
- */
- if ((original_fadt->revision == 2) &&
- (original_fadt->length ==
- sizeof(struct fadt_descriptor_rev2_minus))) {
- /*
- * Grab the entire generic address struct, plus the 1-byte reset value
- * that immediately follows.
- */
- ACPI_MEMCPY(&local_fadt->reset_register,
- &(ACPI_CAST_PTR(struct fadt_descriptor_rev2_minus,
- original_fadt))->reset_register,
- sizeof(struct acpi_generic_address) + 1);
- } else {
- /*
- * Since there isn't any equivalence in 1.0 and since it is highly
- * likely that a 1.0 system has legacy support.
- */
- local_fadt->iapc_boot_arch = BAF_LEGACY_DEVICES;
- }
-
- /*
- * Convert the V1.0 block addresses to V2.0 GAS structures
- */
- acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1a_evt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1b_evt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1a_cnt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1b_cnt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk,
- local_fadt->pm2_cnt_len,
- (acpi_physical_address) local_fadt->
- V1_pm2_cnt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk,
- local_fadt->pm_tm_len,
- (acpi_physical_address) local_fadt->
- V1_pm_tmr_blk);
- acpi_tb_init_generic_address(&local_fadt->xgpe0_blk, 0,
- (acpi_physical_address) local_fadt->
- V1_gpe0_blk);
- acpi_tb_init_generic_address(&local_fadt->xgpe1_blk, 0,
- (acpi_physical_address) local_fadt->
- V1_gpe1_blk);
-
- /* Create separate GAS structs for the PM1 Enable registers */
-
- acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1a_evt_blk.address +
- ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len)));
-
- /* PM1B is optional; leave null if not present */
-
- if (local_fadt->xpm1b_evt_blk.address) {
- acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1b_evt_blk.
- address +
- ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len)));
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_fadt2
- *
- * PARAMETERS: local_fadt - Pointer to new FADT
- * original_fadt - Pointer to old FADT
- *
- * RETURN: None, populates local_fadt
- *
- * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format.
- * Handles optional "X" fields.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor *original_fadt)
-{
-
- /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */
-
- ACPI_MEMCPY(local_fadt, original_fadt, sizeof(struct fadt_descriptor));
-
- /*
- * "X" fields are optional extensions to the original V1.0 fields, so
- * we must selectively expand V1.0 fields if the corresponding X field
- * is zero.
- */
- if (!(local_fadt->xfirmware_ctrl)) {
- ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl,
- local_fadt->V1_firmware_ctrl);
- }
-
- if (!(local_fadt->Xdsdt)) {
- ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt);
- }
-
- if (!(local_fadt->xpm1a_evt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1a_evt_blk);
- }
-
- if (!(local_fadt->xpm1b_evt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1b_evt_blk);
- }
-
- if (!(local_fadt->xpm1a_cnt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1a_cnt_blk);
- }
-
- if (!(local_fadt->xpm1b_cnt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1b_cnt_blk);
- }
-
- if (!(local_fadt->xpm2_cnt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk,
- local_fadt->pm2_cnt_len,
- (acpi_physical_address)
- local_fadt->V1_pm2_cnt_blk);
- }
-
- if (!(local_fadt->xpm_tmr_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk,
- local_fadt->pm_tm_len,
- (acpi_physical_address)
- local_fadt->V1_pm_tmr_blk);
- }
-
- if (!(local_fadt->xgpe0_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xgpe0_blk,
- 0,
- (acpi_physical_address)
- local_fadt->V1_gpe0_blk);
- }
-
- if (!(local_fadt->xgpe1_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xgpe1_blk,
- 0,
- (acpi_physical_address)
- local_fadt->V1_gpe1_blk);
- }
-
- /* Create separate GAS structs for the PM1 Enable registers */
-
- acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1a_evt_blk.address +
- ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len)));
-
- acpi_gbl_xpm1a_enable.address_space_id =
- local_fadt->xpm1a_evt_blk.address_space_id;
-
- /* PM1B is optional; leave null if not present */
-
- if (local_fadt->xpm1b_evt_blk.address) {
- acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1b_evt_blk.
- address +
- ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len)));
-
- acpi_gbl_xpm1b_enable.address_space_id =
- local_fadt->xpm1b_evt_blk.address_space_id;
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_table_fadt
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local
- * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply
- * copied to the local FADT. The ACPI CA software uses this
- * local FADT. Thus a significant amount of special #ifdef
- * type codeing is saved.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_convert_table_fadt(void)
-{
- struct fadt_descriptor *local_fadt;
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(tb_convert_table_fadt);
-
- /*
- * acpi_gbl_FADT is valid. Validate the FADT length. The table must be
- * at least as long as the version 1.0 FADT
- */
- if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor_rev1)) {
- ACPI_ERROR((AE_INFO, "FADT is invalid, too short: 0x%X",
- acpi_gbl_FADT->length));
- return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
- }
-
- /* Allocate buffer for the ACPI 2.0(+) FADT */
-
- local_fadt = ACPI_ALLOCATE_ZEROED(sizeof(struct fadt_descriptor));
- if (!local_fadt) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) {
- if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor)) {
-
- /* Length is too short to be a V2.0 table */
-
- ACPI_WARNING((AE_INFO,
- "Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table",
- acpi_gbl_FADT->length,
- acpi_gbl_FADT->revision));
-
- acpi_tb_convert_fadt1(local_fadt,
- (void *)acpi_gbl_FADT);
- } else {
- /* Valid V2.0 table */
-
- acpi_tb_convert_fadt2(local_fadt, acpi_gbl_FADT);
- }
- } else {
- /* Valid V1.0 table */
-
- acpi_tb_convert_fadt1(local_fadt, (void *)acpi_gbl_FADT);
- }
-
- /* Global FADT pointer will point to the new common V2.0 FADT */
-
- acpi_gbl_FADT = local_fadt;
- acpi_gbl_FADT->length = sizeof(struct fadt_descriptor);
-
- /* Free the original table */
-
- table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_FADT].next;
- acpi_tb_delete_single_table(table_desc);
-
- /* Install the new table */
-
- table_desc->pointer =
- ACPI_CAST_PTR(struct acpi_table_header, acpi_gbl_FADT);
- table_desc->allocation = ACPI_MEM_ALLOCATED;
- table_desc->length = sizeof(struct fadt_descriptor);
-
- /* Dump the entire FADT */
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Hex dump of common internal FADT, size %d (%X)\n",
- acpi_gbl_FADT->length, acpi_gbl_FADT->length));
-
- ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_FADT),
- acpi_gbl_FADT->length);
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_build_common_facs
- *
- * PARAMETERS: table_info - Info for currently installed FACS
- *
- * RETURN: Status
- *
- * DESCRIPTION: Convert ACPI 1.0 and ACPI 2.0 FACS to a common internal
- * table format.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info)
-{
-
- ACPI_FUNCTION_TRACE(tb_build_common_facs);
-
- /* Absolute minimum length is 24, but the ACPI spec says 64 */
-
- if (acpi_gbl_FACS->length < 24) {
- ACPI_ERROR((AE_INFO, "Invalid FACS table length: 0x%X",
- acpi_gbl_FACS->length));
- return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
- }
-
- if (acpi_gbl_FACS->length < 64) {
- ACPI_WARNING((AE_INFO,
- "FACS is shorter than the ACPI specification allows: 0x%X, using anyway",
- acpi_gbl_FACS->length));
- }
-
- /* Copy fields to the new FACS */
-
- acpi_gbl_common_fACS.global_lock = &(acpi_gbl_FACS->global_lock);
-
- if ((acpi_gbl_RSDP->revision < 2) ||
- (acpi_gbl_FACS->length < 32) ||
- (!(acpi_gbl_FACS->xfirmware_waking_vector))) {
-
- /* ACPI 1.0 FACS or short table or optional X_ field is zero */
-
- acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR(u64,
- &
- (acpi_gbl_FACS->
- firmware_waking_vector));
- acpi_gbl_common_fACS.vector_width = 32;
- } else {
- /* ACPI 2.0 FACS with valid X_ field */
-
- acpi_gbl_common_fACS.firmware_waking_vector =
- &acpi_gbl_FACS->xfirmware_waking_vector;
- acpi_gbl_common_fACS.vector_width = 64;
- }
-
- return_ACPI_STATUS(AE_OK);
-}
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
new file mode 100644
index 00000000000..807c7116e94
--- /dev/null
+++ b/drivers/acpi/tables/tbfadt.c
@@ -0,0 +1,434 @@
+/******************************************************************************
+ *
+ * Module Name: tbfadt - FADT table utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2007, R. Byron Moore
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT ACPI_TABLES
+ACPI_MODULE_NAME("tbfadt")
+
+/* Local prototypes */
+static void inline
+acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
+ u8 bit_width, u64 address);
+
+static void acpi_tb_convert_fadt(void);
+
+static void acpi_tb_validate_fadt(void);
+
+/* Table for conversion of FADT to common internal format and FADT validation */
+
+typedef struct acpi_fadt_info {
+ char *name;
+ u8 target;
+ u8 source;
+ u8 length;
+ u8 type;
+
+} acpi_fadt_info;
+
+#define ACPI_FADT_REQUIRED 1
+#define ACPI_FADT_SEPARATE_LENGTH 2
+
+static struct acpi_fadt_info fadt_info_table[] = {
+ {"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block),
+ ACPI_FADT_OFFSET(pm1a_event_block),
+ ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED},
+
+ {"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block),
+ ACPI_FADT_OFFSET(pm1b_event_block),
+ ACPI_FADT_OFFSET(pm1_event_length), 0},
+
+ {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block),
+ ACPI_FADT_OFFSET(pm1a_control_block),
+ ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED},
+
+ {"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block),
+ ACPI_FADT_OFFSET(pm1b_control_block),
+ ACPI_FADT_OFFSET(pm1_control_length), 0},
+
+ {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block),
+ ACPI_FADT_OFFSET(pm2_control_block),
+ ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH},
+
+ {"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block),
+ ACPI_FADT_OFFSET(pm_timer_block),
+ ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED},
+
+ {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block),
+ ACPI_FADT_OFFSET(gpe0_block),
+ ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH},
+
+ {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block),
+ ACPI_FADT_OFFSET(gpe1_block),
+ ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH}
+};
+
+#define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info))
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_init_generic_address
+ *
+ * PARAMETERS: generic_address - GAS struct to be initialized
+ * bit_width - Width of this register
+ * Address - Address of the register
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Initialize a Generic Address Structure (GAS)
+ * See the ACPI specification for a full description and
+ * definition of this structure.
+ *
+ ******************************************************************************/
+
+static void inline
+acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
+ u8 bit_width, u64 address)
+{
+
+ /*
+ * The 64-bit Address field is non-aligned in the byte packed
+ * GAS struct.
+ */
+ ACPI_MOVE_64_TO_64(&generic_address->address, &address);
+
+ /* All other fields are byte-wide */
+
+ generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+ generic_address->bit_width = bit_width;
+ generic_address->bit_offset = 0;
+ generic_address->access_width = 0;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_parse_fadt
+ *
+ * PARAMETERS: table_index - Index for the FADT
+ * Flags - Flags
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Initialize the FADT, DSDT and FACS tables
+ * (FADT contains the addresses of the DSDT and FACS)
+ *
+ ******************************************************************************/
+
+void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
+{
+ u32 length;
+ struct acpi_table_header *table;
+
+ /*
+ * The FADT has multiple versions with different lengths,
+ * and it contains pointers to both the DSDT and FACS tables.
+ *
+ * Get a local copy of the FADT and convert it to a common format
+ * Map entire FADT, assumed to be smaller than one page.
+ */
+ length = acpi_gbl_root_table_list.tables[table_index].length;
+
+ table =
+ acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index].
+ address, length);
+ if (!table) {
+ return;
+ }
+
+ /*
+ * Validate the FADT checksum before we copy the table. Ignore
+ * checksum error as we want to try to get the DSDT and FACS.
+ */
+ (void)acpi_tb_verify_checksum(table, length);
+
+ /* Obtain a local copy of the FADT in common ACPI 2.0+ format */
+
+ acpi_tb_create_local_fadt(table, length);
+
+ /* All done with the real FADT, unmap it */
+
+ acpi_os_unmap_memory(table, length);
+
+ /* Obtain the DSDT and FACS tables via their addresses within the FADT */
+
+ acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
+ flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
+
+ acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs,
+ flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_create_local_fadt
+ *
+ * PARAMETERS: Table - Pointer to BIOS FADT
+ * Length - Length of the table
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
+ * Performs validation on some important FADT fields.
+ *
+ ******************************************************************************/
+
+void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
+{
+
+ /*
+ * Check if the FADT is larger than what we know about (ACPI 2.0 version).
+ * Truncate the table, but make some noise.
+ */
+ if (length > sizeof(struct acpi_table_fadt)) {
+ ACPI_WARNING((AE_INFO,
+ "FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX",
+ table->revision, (unsigned)length,
+ sizeof(struct acpi_table_fadt)));
+ }
+
+ /* Copy the entire FADT locally. Zero first for tb_convert_fadt */
+
+ ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
+
+ ACPI_MEMCPY(&acpi_gbl_FADT, table,
+ ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
+
+ /*
+ * 1) Convert the local copy of the FADT to the common internal format
+ * 2) Validate some of the important values within the FADT
+ */
+ acpi_tb_convert_fadt();
+ acpi_tb_validate_fadt();
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_convert_fadt
+ *
+ * PARAMETERS: None, uses acpi_gbl_FADT
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Converts all versions of the FADT to a common internal format.
+ * -> Expand all 32-bit addresses to 64-bit.
+ *
+ * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt),
+ * and must contain a copy of the actual FADT.
+ *
+ * ACPICA will use the "X" fields of the FADT for all addresses.
+ *
+ * "X" fields are optional extensions to the original V1.0 fields. Even if
+ * they are present in the structure, they can be optionally not used by
+ * setting them to zero. Therefore, we must selectively expand V1.0 fields
+ * if the corresponding X field is zero.
+ *
+ * For ACPI 1.0 FADTs, all address fields are expanded to the corresponding
+ * "X" fields.
+ *
+ * For ACPI 2.0 FADTs, any "X" fields that are NULL are filled in by
+ * expanding the corresponding ACPI 1.0 field.
+ *
+ ******************************************************************************/
+
+static void acpi_tb_convert_fadt(void)
+{
+ u8 pm1_register_length;
+ struct acpi_generic_address *target;
+ acpi_native_uint i;
+
+ /* Update the local FADT table header length */
+
+ acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
+
+ /* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */
+
+ if (!acpi_gbl_FADT.Xfacs) {
+ acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs;
+ }
+
+ if (!acpi_gbl_FADT.Xdsdt) {
+ acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt;
+ }
+
+ /*
+ * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
+ * structures as necessary.
+ */
+ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+ target =
+ ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
+ fadt_info_table[i].target);
+
+ /* Expand only if the X target is null */
+
+ if (!target->address) {
+ acpi_tb_init_generic_address(target,
+ *ACPI_ADD_PTR(u8,
+ &acpi_gbl_FADT,
+ fadt_info_table
+ [i].length),
+ (u64) * ACPI_ADD_PTR(u32,
+ &acpi_gbl_FADT,
+ fadt_info_table
+ [i].
+ source));
+ }
+ }
+
+ /*
+ * Calculate separate GAS structs for the PM1 Enable registers.
+ * These addresses do not appear (directly) in the FADT, so it is
+ * useful to calculate them once, here.
+ *
+ * The PM event blocks are split into two register blocks, first is the
+ * PM Status Register block, followed immediately by the PM Enable Register
+ * block. Each is of length (pm1_event_length/2)
+ */
+ pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
+
+ /* The PM1A register block is required */
+
+ acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
+ pm1_register_length,
+ (acpi_gbl_FADT.xpm1a_event_block.address +
+ pm1_register_length));
+ /* Don't forget to copy space_id of the GAS */
+ acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+
+ /* The PM1B register block is optional, ignore if not present */
+
+ if (acpi_gbl_FADT.xpm1b_event_block.address) {
+ acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
+ pm1_register_length,
+ (acpi_gbl_FADT.xpm1b_event_block.
+ address + pm1_register_length));
+ /* Don't forget to copy space_id of the GAS */
+ acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+
+ }
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_tb_validate_fadt
+ *
+ * PARAMETERS: Table - Pointer to the FADT to be validated
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Validate various important fields within the FADT. If a problem
+ * is found, issue a message, but no status is returned.
+ * Used by both the table manager and the disassembler.
+ *
+ * Possible additional checks:
+ * (acpi_gbl_FADT.pm1_event_length >= 4)
+ * (acpi_gbl_FADT.pm1_control_length >= 2)
+ * (acpi_gbl_FADT.pm_timer_length >= 4)
+ * Gpe block lengths must be multiple of 2
+ *
+ ******************************************************************************/
+
+static void acpi_tb_validate_fadt(void)
+{
+ u32 *address32;
+ struct acpi_generic_address *address64;
+ u8 length;
+ acpi_native_uint i;
+
+ /* Examine all of the 64-bit extended address fields (X fields) */
+
+ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+
+ /* Generate pointers to the 32-bit and 64-bit addresses and get the length */
+
+ address64 =
+ ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
+ fadt_info_table[i].target);
+ address32 =
+ ACPI_ADD_PTR(u32, &acpi_gbl_FADT,
+ fadt_info_table[i].source);
+ length =
+ *ACPI_ADD_PTR(u8, &acpi_gbl_FADT,
+ fadt_info_table[i].length);
+
+ if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) {
+ /*
+ * Field is required (Pm1a_event, Pm1a_control, pm_timer).
+ * Both the address and length must be non-zero.
+ */
+ if (!address64->address || !length) {
+ ACPI_ERROR((AE_INFO,
+ "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X",
+ fadt_info_table[i].name,
+ ACPI_FORMAT_UINT64(address64->
+ address),
+ length));
+ }
+ } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) {
+ /*
+ * Field is optional (PM2Control, GPE0, GPE1) AND has its own
+ * length field. If present, both the address and length must be valid.
+ */
+ if ((address64->address && !length)
+ || (!address64->address && length)) {
+ ACPI_WARNING((AE_INFO,
+ "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X",
+ fadt_info_table[i].name,
+ ACPI_FORMAT_UINT64(address64->
+ address),
+ length));
+ }
+ }
+
+ /* If both 32- and 64-bit addresses are valid (non-zero), they must match */
+
+ if (address64->address && *address32 &&
+ (address64->address != (u64) * address32)) {
+ ACPI_ERROR((AE_INFO,
+ "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X",
+ fadt_info_table[i].name, *address32,
+ ACPI_FORMAT_UINT64(address64->address)));
+ }
+ }
+}
diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c
new file mode 100644
index 00000000000..058c064948e
--- /dev/null
+++ b/drivers/acpi/tables/tbfind.c
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Module Name: tbfind - find table
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2007, R. Byron Moore
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT ACPI_TABLES
+ACPI_MODULE_NAME("tbfind")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_find_table
+ *
+ * PARAMETERS: Signature - String with ACPI table signature
+ * oem_id - String with the table OEM ID
+ * oem_table_id - String with the OEM Table ID
+ * table_index - Where the table index is returned
+ *
+ * RETURN: Status and table index
+ *
+ * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
+ * Signature, OEM ID and OEM Table ID. Returns an index that can
+ * be used to get the table header or entire table.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_tb_find_table(char *signature,
+ char *oem_id,
+ char *oem_table_id, acpi_native_uint * table_index)
+{
+ acpi_native_uint i;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(tb_find_table);
+
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature),
+ signature, ACPI_NAME_SIZE)) {
+
+ /* Not the requested table */
+
+ continue;
+ }
+
+ /* Table with matching signature has been found */
+
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+
+ /* Table is not currently mapped, map it */
+
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[i]);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+ continue;
+ }
+ }
+
+ /* Check for table match on all IDs */
+
+ if (!ACPI_MEMCMP
+ (acpi_gbl_root_table_list.tables[i].pointer->signature,
+ signature, ACPI_NAME_SIZE) && (!oem_id[0]
+ ||
+ !ACPI_MEMCMP
+ (acpi_gbl_root_table_list.
+ tables[i].pointer->oem_id,
+ oem_id, ACPI_OEM_ID_SIZE))
+ && (!oem_table_id[0]
+ || !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i].
+ pointer->oem_table_id, oem_table_id,
+ ACPI_OEM_TABLE_ID_SIZE))) {
+ *table_index = i;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
+ "Found table [%4.4s]\n", signature));
+ return_ACPI_STATUS(AE_OK);
+ }
+ }
+
+ return_ACPI_STATUS(AE_NOT_FOUND);
+}
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
deleted file mode 100644
index 11e2d4454e0..00000000000
--- a/drivers/acpi/tables/tbget.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbget - ACPI Table get* routines
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbget")
-
-/* Local prototypes */
-static acpi_status
-acpi_tb_get_this_table(struct acpi_pointer *address,
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info);
-
-static acpi_status
-acpi_tb_table_override(struct acpi_table_header *header,
- struct acpi_table_desc *table_info);
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * table_info - Where table info is returned
- *
- * RETURN: None
- *
- * DESCRIPTION: Get entire table of unknown size.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table(struct acpi_pointer *address,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
- struct acpi_table_header header;
-
- ACPI_FUNCTION_TRACE(tb_get_table);
-
- /* Get the header in order to get signature and table size */
-
- status = acpi_tb_get_table_header(address, &header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the entire table */
-
- status = acpi_tb_get_table_body(address, &header, table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get ACPI table (size %X)",
- header.length));
- return_ACPI_STATUS(status);
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_header
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * return_header - Where the table header is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get an ACPI table header. Works in both physical or virtual
- * addressing mode. Works with both physical or logical pointers.
- * Table is either copied or mapped, depending on the pointer
- * type and mode of the processor.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_header(struct acpi_pointer *address,
- struct acpi_table_header *return_header)
-{
- acpi_status status = AE_OK;
- struct acpi_table_header *header = NULL;
-
- ACPI_FUNCTION_TRACE(tb_get_table_header);
-
- /*
- * Flags contains the current processor mode (Virtual or Physical
- * addressing) The pointer_type is either Logical or Physical
- */
- switch (address->pointer_type) {
- case ACPI_PHYSMODE_PHYSPTR:
- case ACPI_LOGMODE_LOGPTR:
-
- /* Pointer matches processor mode, copy the header */
-
- ACPI_MEMCPY(return_header, address->pointer.logical,
- sizeof(struct acpi_table_header));
- break;
-
- case ACPI_LOGMODE_PHYSPTR:
-
- /* Create a logical address for the physical pointer */
-
- status = acpi_os_map_memory(address->pointer.physical,
- sizeof(struct acpi_table_header),
- (void *)&header);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X%8.8X for table header",
- ACPI_FORMAT_UINT64(address->pointer.
- physical)));
- return_ACPI_STATUS(status);
- }
-
- /* Copy header and delete mapping */
-
- ACPI_MEMCPY(return_header, header,
- sizeof(struct acpi_table_header));
- acpi_os_unmap_memory(header, sizeof(struct acpi_table_header));
- break;
-
- default:
-
- ACPI_ERROR((AE_INFO, "Invalid address flags %X",
- address->pointer_type));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Table Signature: [%4.4s]\n",
- return_header->signature));
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_body
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * Header - Header of the table to retrieve
- * table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get an entire ACPI table with support to allow the host OS to
- * replace the table with a newer version (table override.)
- * Works in both physical or virtual
- * addressing mode. Works with both physical or logical pointers.
- * Table is either copied or mapped, depending on the pointer
- * type and mode of the processor.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_body(struct acpi_pointer *address,
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(tb_get_table_body);
-
- if (!table_info || !address) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Attempt table override. */
-
- status = acpi_tb_table_override(header, table_info);
- if (ACPI_SUCCESS(status)) {
-
- /* Table was overridden by the host OS */
-
- return_ACPI_STATUS(status);
- }
-
- /* No override, get the original table */
-
- status = acpi_tb_get_this_table(address, header, table_info);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_table_override
- *
- * PARAMETERS: Header - Pointer to table header
- * table_info - Return info if table is overridden
- *
- * RETURN: None
- *
- * DESCRIPTION: Attempts override of current table with a new one if provided
- * by the host OS.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_table_override(struct acpi_table_header *header,
- struct acpi_table_desc *table_info)
-{
- struct acpi_table_header *new_table;
- acpi_status status;
- struct acpi_pointer address;
-
- ACPI_FUNCTION_TRACE(tb_table_override);
-
- /*
- * The OSL will examine the header and decide whether to override this
- * table. If it decides to override, a table will be returned in new_table,
- * which we will then copy.
- */
- status = acpi_os_table_override(header, &new_table);
- if (ACPI_FAILURE(status)) {
-
- /* Some severe error from the OSL, but we basically ignore it */
-
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not override ACPI table"));
- return_ACPI_STATUS(status);
- }
-
- if (!new_table) {
-
- /* No table override */
-
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /*
- * We have a new table to override the old one. Get a copy of
- * the new one. We know that the new table has a logical pointer.
- */
- address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
- address.pointer.logical = new_table;
-
- status = acpi_tb_get_this_table(&address, new_table, table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not copy ACPI table"));
- return_ACPI_STATUS(status);
- }
-
- /* Copy the table info */
-
- ACPI_INFO((AE_INFO, "Table [%4.4s] replaced by host OS",
- table_info->pointer->signature));
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_this_table
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * Header - Header of the table to retrieve
- * table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get an entire ACPI table. Works in both physical or virtual
- * addressing mode. Works with both physical or logical pointers.
- * Table is either copied or mapped, depending on the pointer
- * type and mode of the processor.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_this_table(struct acpi_pointer *address,
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info)
-{
- struct acpi_table_header *full_table = NULL;
- u8 allocation;
- acpi_status status = AE_OK;
-
- ACPI_FUNCTION_TRACE(tb_get_this_table);
-
- /* Validate minimum length */
-
- if (header->length < sizeof(struct acpi_table_header)) {
- ACPI_ERROR((AE_INFO,
- "Table length (%X) is smaller than minimum (%zX)",
- header->length, sizeof(struct acpi_table_header)));
-
- return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
- }
-
- /*
- * Flags contains the current processor mode (Virtual or Physical
- * addressing) The pointer_type is either Logical or Physical
- */
- switch (address->pointer_type) {
- case ACPI_PHYSMODE_PHYSPTR:
- case ACPI_LOGMODE_LOGPTR:
-
- /* Pointer matches processor mode, copy the table to a new buffer */
-
- full_table = ACPI_ALLOCATE(header->length);
- if (!full_table) {
- ACPI_ERROR((AE_INFO,
- "Could not allocate table memory for [%4.4s] length %X",
- header->signature, header->length));
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Copy the entire table (including header) to the local buffer */
-
- ACPI_MEMCPY(full_table, address->pointer.logical,
- header->length);
-
- /* Save allocation type */
-
- allocation = ACPI_MEM_ALLOCATED;
- break;
-
- case ACPI_LOGMODE_PHYSPTR:
-
- /*
- * Just map the table's physical memory
- * into our address space.
- */
- status = acpi_os_map_memory(address->pointer.physical,
- (acpi_size) header->length,
- ACPI_CAST_PTR(void, &full_table));
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X",
- header->signature,
- ACPI_FORMAT_UINT64(address->pointer.
- physical),
- header->length));
- return (status);
- }
-
- /* Save allocation type */
-
- allocation = ACPI_MEM_MAPPED;
- break;
-
- default:
-
- ACPI_ERROR((AE_INFO, "Invalid address flags %X",
- address->pointer_type));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /*
- * Validate checksum for _most_ tables,
- * even the ones whose signature we don't recognize
- */
- if (table_info->type != ACPI_TABLE_ID_FACS) {
- status = acpi_tb_verify_table_checksum(full_table);
-
-#if (!ACPI_CHECKSUM_ABORT)
- if (ACPI_FAILURE(status)) {
-
- /* Ignore the error if configuration says so */
-
- status = AE_OK;
- }
-#endif
- }
-
- /* Return values */
-
- table_info->pointer = full_table;
- table_info->length = (acpi_size) header->length;
- table_info->allocation = allocation;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n",
- full_table->signature,
- ACPI_FORMAT_UINT64(address->pointer.physical),
- full_table));
-
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_ptr
- *
- * PARAMETERS: table_type - one of the defined table types
- * Instance - Which table of this type
- * return_table - pointer to location to place the pointer for
- * return
- *
- * RETURN: Status
- *
- * DESCRIPTION: This function is called to get the pointer to an ACPI table.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_ptr(acpi_table_type table_type,
- u32 instance, struct acpi_table_header **return_table)
-{
- struct acpi_table_desc *table_desc;
- u32 i;
-
- ACPI_FUNCTION_TRACE(tb_get_table_ptr);
-
- if (table_type > ACPI_TABLE_ID_MAX) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Check for instance out of range of the current table count */
-
- if (instance > acpi_gbl_table_lists[table_type].count) {
- return_ACPI_STATUS(AE_NOT_EXIST);
- }
-
- /*
- * Walk the list to get the desired table
- * Note: Instance is one-based
- */
- table_desc = acpi_gbl_table_lists[table_type].next;
- for (i = 1; i < instance; i++) {
- table_desc = table_desc->next;
- }
-
- /* We are now pointing to the requested table's descriptor */
-
- *return_table = table_desc->pointer;
- return_ACPI_STATUS(AE_OK);
-}
diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c
deleted file mode 100644
index ad982112e4c..00000000000
--- a/drivers/acpi/tables/tbgetall.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbgetall - Get all required ACPI tables
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbgetall")
-
-/* Local prototypes */
-static acpi_status
-acpi_tb_get_primary_table(struct acpi_pointer *address,
- struct acpi_table_desc *table_info);
-
-static acpi_status
-acpi_tb_get_secondary_table(struct acpi_pointer *address,
- acpi_string signature,
- struct acpi_table_desc *table_info);
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_primary_table
- *
- * PARAMETERS: Address - Physical address of table to retrieve
- * *table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Maps the physical address of table into a logical address
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_primary_table(struct acpi_pointer *address,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
- struct acpi_table_header header;
-
- ACPI_FUNCTION_TRACE(tb_get_primary_table);
-
- /* Ignore a NULL address in the RSDT */
-
- if (!address->pointer.value) {
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Get the header in order to get signature and table size */
-
- status = acpi_tb_get_table_header(address, &header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Clear the table_info */
-
- ACPI_MEMSET(table_info, 0, sizeof(struct acpi_table_desc));
-
- /*
- * Check the table signature and make sure it is recognized.
- * Also checks the header checksum
- */
- table_info->pointer = &header;
- status = acpi_tb_recognize_table(table_info, ACPI_TABLE_PRIMARY);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the entire table */
-
- status = acpi_tb_get_table_body(address, &header, table_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Install the table */
-
- status = acpi_tb_install_table(table_info);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_secondary_table
- *
- * PARAMETERS: Address - Physical address of table to retrieve
- * *table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Maps the physical address of table into a logical address
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_secondary_table(struct acpi_pointer *address,
- acpi_string signature,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
- struct acpi_table_header header;
-
- ACPI_FUNCTION_TRACE_STR(tb_get_secondary_table, signature);
-
- /* Get the header in order to match the signature */
-
- status = acpi_tb_get_table_header(address, &header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Signature must match request */
-
- if (!ACPI_COMPARE_NAME(header.signature, signature)) {
- ACPI_ERROR((AE_INFO,
- "Incorrect table signature - wanted [%s] found [%4.4s]",
- signature, header.signature));
- return_ACPI_STATUS(AE_BAD_SIGNATURE);
- }
-
- /*
- * Check the table signature and make sure it is recognized.
- * Also checks the header checksum
- */
- table_info->pointer = &header;
- status = acpi_tb_recognize_table(table_info, ACPI_TABLE_SECONDARY);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the entire table */
-
- status = acpi_tb_get_table_body(address, &header, table_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Install the table */
-
- status = acpi_tb_install_table(table_info);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_required_tables
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load and validate tables other than the RSDT. The RSDT must
- * already be loaded and validated.
- *
- * Get the minimum set of ACPI tables, namely:
- *
- * 1) FADT (via RSDT in loop below)
- * 2) FACS (via FADT)
- * 3) DSDT (via FADT)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_get_required_tables(void)
-{
- acpi_status status = AE_OK;
- u32 i;
- struct acpi_table_desc table_info;
- struct acpi_pointer address;
-
- ACPI_FUNCTION_TRACE(tb_get_required_tables);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%d ACPI tables in RSDT\n",
- acpi_gbl_rsdt_table_count));
-
- address.pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
-
- /*
- * Loop through all table pointers found in RSDT.
- * This will NOT include the FACS and DSDT - we must get
- * them after the loop.
- *
- * The only tables we are interested in getting here is the FADT and
- * any SSDTs.
- */
- for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
-
- /* Get the table address from the common internal XSDT */
-
- address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i];
-
- /*
- * Get the tables needed by this subsystem (FADT and any SSDTs).
- * NOTE: All other tables are completely ignored at this time.
- */
- status = acpi_tb_get_primary_table(&address, &table_info);
- if ((status != AE_OK) && (status != AE_TABLE_NOT_SUPPORTED)) {
- ACPI_WARNING((AE_INFO,
- "%s, while getting table at %8.8X%8.8X",
- acpi_format_exception(status),
- ACPI_FORMAT_UINT64(address.pointer.
- value)));
- }
- }
-
- /* We must have a FADT to continue */
-
- if (!acpi_gbl_FADT) {
- ACPI_ERROR((AE_INFO, "No FADT present in RSDT/XSDT"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /*
- * Convert the FADT to a common format. This allows earlier revisions of
- * the table to coexist with newer versions, using common access code.
- */
- status = acpi_tb_convert_table_fadt();
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not convert FADT to internal common format"));
- return_ACPI_STATUS(status);
- }
-
- /* Get the FACS (Pointed to by the FADT) */
-
- address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl;
-
- status = acpi_tb_get_secondary_table(&address, FACS_SIG, &table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get/install the FACS"));
- return_ACPI_STATUS(status);
- }
-
- /*
- * Create the common FACS pointer table
- * (Contains pointers to the original table)
- */
- status = acpi_tb_build_common_facs(&table_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get/install the DSDT (Pointed to by the FADT) */
-
- address.pointer.value = acpi_gbl_FADT->Xdsdt;
-
- status = acpi_tb_get_secondary_table(&address, DSDT_SIG, &table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not get/install the DSDT"));
- return_ACPI_STATUS(status);
- }
-
- /* Set Integer Width (32/64) based upon DSDT revision */
-
- acpi_ut_set_integer_width(acpi_gbl_DSDT->revision);
-
- /* Dump the entire DSDT */
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n",
- acpi_gbl_DSDT->length, acpi_gbl_DSDT->length,
- acpi_gbl_integer_bit_width));
-
- ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_DSDT),
- acpi_gbl_DSDT->length);
-
- /* Always delete the RSDP mapping, we are done with it */
-
- acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_RSDP);
- return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 1668a232fb6..0e7b121a99c 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,510 +42,498 @@
*/
#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
#include <acpi/actables.h>
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbinstal")
-/* Local prototypes */
-static acpi_status
-acpi_tb_match_signature(char *signature,
- struct acpi_table_desc *table_info, u8 search_type);
-
-/*******************************************************************************
+/******************************************************************************
*
- * FUNCTION: acpi_tb_match_signature
+ * FUNCTION: acpi_tb_verify_table
*
- * PARAMETERS: Signature - Table signature to match
- * table_info - Return data
- * search_type - Table type to match (primary/secondary)
+ * PARAMETERS: table_desc - table
*
* RETURN: Status
*
- * DESCRIPTION: Compare signature against the list of "ACPI-subsystem-owned"
- * tables (DSDT/FADT/SSDT, etc.) Returns the table_type_iD on match.
+ * DESCRIPTION: this function is called to verify and map table
*
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_match_signature(char *signature,
- struct acpi_table_desc *table_info, u8 search_type)
+ *****************************************************************************/
+acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc)
{
- acpi_native_uint i;
+ acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE(tb_match_signature);
+ ACPI_FUNCTION_TRACE(tb_verify_table);
- /* Search for a signature match among the known table types */
+ /* Map the table if necessary */
- for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
- if (!(acpi_gbl_table_data[i].flags & search_type)) {
- continue;
+ if (!table_desc->pointer) {
+ if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
+ ACPI_TABLE_ORIGIN_MAPPED) {
+ table_desc->pointer =
+ acpi_os_map_memory(table_desc->address,
+ table_desc->length);
}
+ if (!table_desc->pointer) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+ }
- if (!ACPI_STRNCMP(signature, acpi_gbl_table_data[i].signature,
- acpi_gbl_table_data[i].sig_length)) {
-
- /* Found a signature match, return index if requested */
+ /* FACS is the odd table, has no standard ACPI header and no checksum */
- if (table_info) {
- table_info->type = (u8) i;
- }
+ if (!ACPI_COMPARE_NAME(&table_desc->signature, ACPI_SIG_FACS)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Table [%4.4s] is an ACPI table consumed by the core subsystem\n",
- (char *)acpi_gbl_table_data[i].
- signature));
+ /* Always calculate checksum, ignore bad checksum if requested */
- return_ACPI_STATUS(AE_OK);
- }
+ status =
+ acpi_tb_verify_checksum(table_desc->pointer,
+ table_desc->length);
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Table [%4.4s] is not an ACPI table consumed by the core subsystem - ignored\n",
- (char *)signature));
-
- return_ACPI_STATUS(AE_TABLE_NOT_SUPPORTED);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_install_table
+ * FUNCTION: acpi_tb_add_table
*
- * PARAMETERS: table_info - Return value from acpi_tb_get_table_body
+ * PARAMETERS: table_desc - Table descriptor
+ * table_index - Where the table index is returned
*
* RETURN: Status
*
- * DESCRIPTION: Install the table into the global data structures.
+ * DESCRIPTION: This function is called to add the ACPI table
*
******************************************************************************/
-acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info)
+acpi_status
+acpi_tb_add_table(struct acpi_table_desc *table_desc,
+ acpi_native_uint * table_index)
{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(tb_install_table);
+ acpi_native_uint i;
+ acpi_native_uint length;
+ acpi_status status = AE_OK;
- /* Lock tables while installing */
+ ACPI_FUNCTION_TRACE(tb_add_table);
- status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not acquire table mutex"));
- return_ACPI_STATUS(status);
+ if (!table_desc->pointer) {
+ status = acpi_tb_verify_table(table_desc);
+ if (ACPI_FAILURE(status) || !table_desc->pointer) {
+ return_ACPI_STATUS(status);
+ }
}
- /*
- * Ignore a table that is already installed. For example, some BIOS
- * ASL code will repeatedly attempt to load the same SSDT.
- */
- status = acpi_tb_is_table_installed(table_info);
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ /* The table must be either an SSDT or a PSDT */
+
+ if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT))
+ &&
+ (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)))
+ {
+ ACPI_ERROR((AE_INFO,
+ "Table has invalid signature [%4.4s], must be SSDT or PSDT",
+ table_desc->pointer->signature));
+ return_ACPI_STATUS(AE_BAD_SIGNATURE);
}
- /* Install the table into the global data structure */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+ /* Check if table is already registered */
+
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[i]);
+ if (ACPI_FAILURE(status)
+ || !acpi_gbl_root_table_list.tables[i].pointer) {
+ continue;
+ }
+ }
+
+ length = ACPI_MIN(table_desc->length,
+ acpi_gbl_root_table_list.tables[i].length);
+ if (ACPI_MEMCMP(table_desc->pointer,
+ acpi_gbl_root_table_list.tables[i].pointer,
+ length)) {
+ continue;
+ }
+
+ /* Table is already registered */
+
+ acpi_tb_delete_table(table_desc);
+ *table_index = i;
+ goto release;
+ }
- status = acpi_tb_init_table_descriptor(table_info->type, table_info);
+ /*
+ * Add the table to the global table list
+ */
+ status = acpi_tb_store_table(table_desc->address, table_desc->pointer,
+ table_desc->length, table_desc->flags,
+ table_index);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not install table [%4.4s]",
- table_info->pointer->signature));
+ goto release;
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s located at %p\n",
- acpi_gbl_table_data[table_info->type].name,
- table_info->pointer));
+ acpi_tb_print_table_header(table_desc->address, table_desc->pointer);
- unlock_and_exit:
+ release:
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_recognize_table
+ * FUNCTION: acpi_tb_resize_root_table_list
*
- * PARAMETERS: table_info - Return value from acpi_tb_get_table_body
- * search_type - Table type to match (primary/secondary)
+ * PARAMETERS: None
*
* RETURN: Status
*
- * DESCRIPTION: Check a table signature for a match against known table types
- *
- * NOTE: All table pointers are validated as follows:
- * 1) Table pointer must point to valid physical memory
- * 2) Signature must be 4 ASCII chars, even if we don't recognize the
- * name
- * 3) Table must be readable for length specified in the header
- * 4) Table checksum must be valid (with the exception of the FACS
- * which has no checksum for some odd reason)
+ * DESCRIPTION: Expand the size of global table array
*
******************************************************************************/
-acpi_status
-acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type)
+acpi_status acpi_tb_resize_root_table_list(void)
{
- struct acpi_table_header *table_header;
- acpi_status status;
+ struct acpi_table_desc *tables;
- ACPI_FUNCTION_TRACE(tb_recognize_table);
+ ACPI_FUNCTION_TRACE(tb_resize_root_table_list);
- /* Ensure that we have a valid table pointer */
+ /* allow_resize flag is a parameter to acpi_initialize_tables */
- table_header = (struct acpi_table_header *)table_info->pointer;
- if (!table_header) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) {
+ ACPI_ERROR((AE_INFO,
+ "Resize of Root Table Array is not allowed"));
+ return_ACPI_STATUS(AE_SUPPORT);
}
- /*
- * We only "recognize" a limited number of ACPI tables -- namely, the
- * ones that are used by the subsystem (DSDT, FADT, etc.)
- *
- * An AE_TABLE_NOT_SUPPORTED means that the table was not recognized.
- * This can be any one of many valid ACPI tables, it just isn't one of
- * the tables that is consumed by the core subsystem
- */
- status = acpi_tb_match_signature(table_header->signature,
- table_info, search_type);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /* Increase the Table Array size */
+
+ tables = ACPI_ALLOCATE_ZEROED((acpi_gbl_root_table_list.size +
+ ACPI_ROOT_TABLE_SIZE_INCREMENT)
+ * sizeof(struct acpi_table_desc));
+ if (!tables) {
+ ACPI_ERROR((AE_INFO,
+ "Could not allocate new root table array"));
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- status = acpi_tb_validate_table_header(table_header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /* Copy and free the previous table array */
+
+ if (acpi_gbl_root_table_list.tables) {
+ ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
+ acpi_gbl_root_table_list.size *
+ sizeof(struct acpi_table_desc));
+
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ ACPI_FREE(acpi_gbl_root_table_list.tables);
+ }
}
- /* Return the table type and length via the info struct */
+ acpi_gbl_root_table_list.tables = tables;
+ acpi_gbl_root_table_list.size += ACPI_ROOT_TABLE_SIZE_INCREMENT;
+ acpi_gbl_root_table_list.flags |= (u8) ACPI_ROOT_ORIGIN_ALLOCATED;
- table_info->length = (acpi_size) table_header->length;
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_init_table_descriptor
+ * FUNCTION: acpi_tb_store_table
*
- * PARAMETERS: table_type - The type of the table
- * table_info - A table info struct
+ * PARAMETERS: Address - Table address
+ * Table - Table header
+ * Length - Table length
+ * Flags - flags
*
- * RETURN: None.
+ * RETURN: Status and table index.
*
- * DESCRIPTION: Install a table into the global data structs.
+ * DESCRIPTION: Add an ACPI table to the global table list
*
******************************************************************************/
acpi_status
-acpi_tb_init_table_descriptor(acpi_table_type table_type,
- struct acpi_table_desc *table_info)
+acpi_tb_store_table(acpi_physical_address address,
+ struct acpi_table_header *table,
+ u32 length, u8 flags, acpi_native_uint * table_index)
{
- struct acpi_table_list *list_head;
- struct acpi_table_desc *table_desc;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE_U32(tb_init_table_descriptor, table_type);
+ acpi_status status = AE_OK;
- /* Allocate a descriptor for this table */
+ /* Ensure that there is room for the table in the Root Table List */
- table_desc = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
- if (!table_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ if (acpi_gbl_root_table_list.count >= acpi_gbl_root_table_list.size) {
+ status = acpi_tb_resize_root_table_list();
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
}
- /* Get a new owner ID for the table */
+ /* Initialize added table */
+
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ address = address;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ pointer = table;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].length =
+ length;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ owner_id = 0;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].flags =
+ flags;
+
+ ACPI_MOVE_32_TO_32(&
+ (acpi_gbl_root_table_list.
+ tables[acpi_gbl_root_table_list.count].signature),
+ table->signature);
+
+ *table_index = acpi_gbl_root_table_list.count;
+ acpi_gbl_root_table_list.count++;
+ return (status);
+}
- status = acpi_ut_allocate_owner_id(&table_desc->owner_id);
- if (ACPI_FAILURE(status)) {
- goto error_exit1;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_delete_table
+ *
+ * PARAMETERS: table_index - Table index
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete one internal ACPI table
+ *
+ ******************************************************************************/
- /* Install the table into the global data structure */
+void acpi_tb_delete_table(struct acpi_table_desc *table_desc)
+{
+ /* Table must be mapped or allocated */
+ if (!table_desc->pointer) {
+ return;
+ }
+ switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
+ case ACPI_TABLE_ORIGIN_MAPPED:
+ acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
+ break;
+ case ACPI_TABLE_ORIGIN_ALLOCATED:
+ ACPI_FREE(table_desc->pointer);
+ break;
+ default:;
+ }
- list_head = &acpi_gbl_table_lists[table_type];
+ table_desc->pointer = NULL;
+}
- /*
- * Two major types of tables: 1) Only one instance is allowed. This
- * includes most ACPI tables such as the DSDT. 2) Multiple instances of
- * the table are allowed. This includes SSDT and PSDTs.
- */
- if (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags)) {
- /*
- * Only one table allowed, and a table has alread been installed
- * at this location, so return an error.
- */
- if (list_head->next) {
- status = AE_ALREADY_EXISTS;
- goto error_exit2;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_terminate
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete all internal ACPI tables
+ *
+ ******************************************************************************/
- table_desc->next = list_head->next;
- list_head->next = table_desc;
+void acpi_tb_terminate(void)
+{
+ acpi_native_uint i;
- if (table_desc->next) {
- table_desc->next->prev = table_desc;
- }
+ ACPI_FUNCTION_TRACE(tb_terminate);
- list_head->count++;
- } else {
- /*
- * Link the new table in to the list of tables of this type.
- * Insert at the end of the list, order IS IMPORTANT.
- *
- * table_desc->Prev & Next are already NULL from calloc()
- */
- list_head->count++;
-
- if (!list_head->next) {
- list_head->next = table_desc;
- } else {
- table_desc->next = list_head->next;
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- while (table_desc->next->next) {
- table_desc->next = table_desc->next->next;
- }
+ /* Delete the individual tables */
- table_desc->next->next = table_desc;
- table_desc->prev = table_desc->next;
- table_desc->next = NULL;
- }
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]);
}
- /* Finish initialization of the table descriptor */
-
- table_desc->loaded_into_namespace = FALSE;
- table_desc->type = (u8) table_type;
- table_desc->pointer = table_info->pointer;
- table_desc->length = table_info->length;
- table_desc->allocation = table_info->allocation;
- table_desc->aml_start = (u8 *) (table_desc->pointer + 1),
- table_desc->aml_length = (u32)
- (table_desc->length - (u32) sizeof(struct acpi_table_header));
-
/*
- * Set the appropriate global pointer (if there is one) to point to the
- * newly installed table
+ * Delete the root table array if allocated locally. Array cannot be
+ * mapped, so we don't need to check for that flag.
*/
- if (acpi_gbl_table_data[table_type].global_ptr) {
- *(acpi_gbl_table_data[table_type].global_ptr) =
- table_info->pointer;
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ ACPI_FREE(acpi_gbl_root_table_list.tables);
}
- /* Return Data */
-
- table_info->owner_id = table_desc->owner_id;
- table_info->installed_desc = table_desc;
- return_ACPI_STATUS(AE_OK);
-
- /* Error exit with cleanup */
-
- error_exit2:
-
- acpi_ut_release_owner_id(&table_desc->owner_id);
+ acpi_gbl_root_table_list.tables = NULL;
+ acpi_gbl_root_table_list.flags = 0;
+ acpi_gbl_root_table_list.count = 0;
- error_exit1:
-
- ACPI_FREE(table_desc);
- return_ACPI_STATUS(status);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_delete_all_tables
+ * FUNCTION: acpi_tb_delete_namespace_by_owner
*
- * PARAMETERS: None.
+ * PARAMETERS: table_index - Table index
*
- * RETURN: None.
+ * RETURN: None
*
- * DESCRIPTION: Delete all internal ACPI tables
+ * DESCRIPTION: Delete all namespace objects created when this table was loaded.
*
******************************************************************************/
-void acpi_tb_delete_all_tables(void)
+void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index)
{
- acpi_table_type type;
+ acpi_owner_id owner_id;
- /*
- * Free memory allocated for ACPI tables
- * Memory can either be mapped or allocated
- */
- for (type = 0; type < (ACPI_TABLE_ID_MAX + 1); type++) {
- acpi_tb_delete_tables_by_type(type);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ owner_id =
+ acpi_gbl_root_table_list.tables[table_index].owner_id;
+ } else {
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return;
}
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ acpi_ns_delete_namespace_by_owner(owner_id);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_delete_tables_by_type
+ * FUNCTION: acpi_tb_allocate_owner_id
*
- * PARAMETERS: Type - The table type to be deleted
+ * PARAMETERS: table_index - Table index
*
- * RETURN: None.
+ * RETURN: Status
*
- * DESCRIPTION: Delete an internal ACPI table
- * Locks the ACPI table mutex
+ * DESCRIPTION: Allocates owner_id in table_desc
*
******************************************************************************/
-void acpi_tb_delete_tables_by_type(acpi_table_type type)
+acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index)
{
- struct acpi_table_desc *table_desc;
- u32 count;
- u32 i;
+ acpi_status status = AE_BAD_PARAMETER;
- ACPI_FUNCTION_TRACE_U32(tb_delete_tables_by_type, type);
+ ACPI_FUNCTION_TRACE(tb_allocate_owner_id);
- if (type > ACPI_TABLE_ID_MAX) {
- return_VOID;
- }
-
- if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_TABLES))) {
- return;
- }
-
- /* Clear the appropriate "typed" global table pointer */
-
- switch (type) {
- case ACPI_TABLE_ID_RSDP:
- acpi_gbl_RSDP = NULL;
- break;
-
- case ACPI_TABLE_ID_DSDT:
- acpi_gbl_DSDT = NULL;
- break;
-
- case ACPI_TABLE_ID_FADT:
- acpi_gbl_FADT = NULL;
- break;
-
- case ACPI_TABLE_ID_FACS:
- acpi_gbl_FACS = NULL;
- break;
-
- case ACPI_TABLE_ID_XSDT:
- acpi_gbl_XSDT = NULL;
- break;
-
- case ACPI_TABLE_ID_SSDT:
- case ACPI_TABLE_ID_PSDT:
- default:
- break;
- }
-
- /*
- * Free the table
- * 1) Get the head of the list
- */
- table_desc = acpi_gbl_table_lists[type].next;
- count = acpi_gbl_table_lists[type].count;
-
- /*
- * 2) Walk the entire list, deleting both the allocated tables
- * and the table descriptors
- */
- for (i = 0; i < count; i++) {
- table_desc = acpi_tb_uninstall_table(table_desc);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ status = acpi_ut_allocate_owner_id
+ (&(acpi_gbl_root_table_list.tables[table_index].owner_id));
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_VOID;
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_delete_single_table
+ * FUNCTION: acpi_tb_release_owner_id
*
- * PARAMETERS: table_info - A table info struct
+ * PARAMETERS: table_index - Table index
*
- * RETURN: None.
+ * RETURN: Status
*
- * DESCRIPTION: Low-level free for a single ACPI table. Handles cases where
- * the table was allocated a buffer or was mapped.
+ * DESCRIPTION: Releases owner_id in table_desc
*
******************************************************************************/
-void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc)
+acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index)
{
+ acpi_status status = AE_BAD_PARAMETER;
- /* Must have a valid table descriptor and pointer */
+ ACPI_FUNCTION_TRACE(tb_release_owner_id);
- if ((!table_desc) || (!table_desc->pointer)) {
- return;
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ acpi_ut_release_owner_id(&
+ (acpi_gbl_root_table_list.
+ tables[table_index].owner_id));
+ status = AE_OK;
}
- /* Valid table, determine type of memory allocation */
-
- switch (table_desc->allocation) {
- case ACPI_MEM_NOT_ALLOCATED:
- break;
-
- case ACPI_MEM_ALLOCATED:
-
- ACPI_FREE(table_desc->pointer);
- break;
-
- case ACPI_MEM_MAPPED:
-
- acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
- break;
-
- default:
- break;
- }
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_uninstall_table
+ * FUNCTION: acpi_tb_get_owner_id
*
- * PARAMETERS: table_info - A table info struct
+ * PARAMETERS: table_index - Table index
+ * owner_id - Where the table owner_id is returned
*
- * RETURN: Pointer to the next table in the list (of same type)
+ * RETURN: Status
*
- * DESCRIPTION: Free the memory associated with an internal ACPI table that
- * is either installed or has never been installed.
- * Table mutex should be locked.
+ * DESCRIPTION: returns owner_id for the ACPI table
*
******************************************************************************/
-struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
- *table_desc)
+acpi_status
+acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id)
{
- struct acpi_table_desc *next_desc;
+ acpi_status status = AE_BAD_PARAMETER;
- ACPI_FUNCTION_TRACE_PTR(tb_uninstall_table, table_desc);
+ ACPI_FUNCTION_TRACE(tb_get_owner_id);
- if (!table_desc) {
- return_PTR(NULL);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ *owner_id =
+ acpi_gbl_root_table_list.tables[table_index].owner_id;
+ status = AE_OK;
}
- /* Unlink the descriptor from the doubly linked list */
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+}
- if (table_desc->prev) {
- table_desc->prev->next = table_desc->next;
- } else {
- /* Is first on list, update list head */
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_is_table_loaded
+ *
+ * PARAMETERS: table_index - Table index
+ *
+ * RETURN: Table Loaded Flag
+ *
+ ******************************************************************************/
- acpi_gbl_table_lists[table_desc->type].next = table_desc->next;
- }
+u8 acpi_tb_is_table_loaded(acpi_native_uint table_index)
+{
+ u8 is_loaded = FALSE;
- if (table_desc->next) {
- table_desc->next->prev = table_desc->prev;
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ is_loaded = (u8)
+ (acpi_gbl_root_table_list.tables[table_index].
+ flags & ACPI_TABLE_IS_LOADED);
}
- /* Free the memory allocated for the table itself */
-
- acpi_tb_delete_single_table(table_desc);
-
- /* Free the owner ID associated with this table */
-
- acpi_ut_release_owner_id(&table_desc->owner_id);
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return (is_loaded);
+}
- /* Free the table descriptor */
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_set_table_loaded_flag
+ *
+ * PARAMETERS: table_index - Table index
+ * is_loaded - TRUE if table is loaded, FALSE otherwise
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
+ *
+ ******************************************************************************/
- next_desc = table_desc->next;
- ACPI_FREE(table_desc);
+void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded)
+{
- /* Return pointer to the next descriptor */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ if (is_loaded) {
+ acpi_gbl_root_table_list.tables[table_index].flags |=
+ ACPI_TABLE_IS_LOADED;
+ } else {
+ acpi_gbl_root_table_list.tables[table_index].flags &=
+ ~ACPI_TABLE_IS_LOADED;
+ }
+ }
- return_PTR(next_desc);
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
}
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
deleted file mode 100644
index 86a5fca9b73..00000000000
--- a/drivers/acpi/tables/tbrsdt.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbrsdt - ACPI RSDT table utilities
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbrsdt")
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_verify_rsdp
- *
- * PARAMETERS: Address - RSDP (Pointer to RSDT)
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
- *
- ******************************************************************************/
-acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address)
-{
- struct acpi_table_desc table_info;
- acpi_status status;
- struct rsdp_descriptor *rsdp;
-
- ACPI_FUNCTION_TRACE(tb_verify_rsdp);
-
- switch (address->pointer_type) {
- case ACPI_LOGICAL_POINTER:
-
- rsdp = address->pointer.logical;
- break;
-
- case ACPI_PHYSICAL_POINTER:
- /*
- * Obtain access to the RSDP structure
- */
- status = acpi_os_map_memory(address->pointer.physical,
- sizeof(struct rsdp_descriptor),
- ACPI_CAST_PTR(void, &rsdp));
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- break;
-
- default:
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Verify RSDP signature and checksum */
-
- status = acpi_tb_validate_rsdp(rsdp);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- /* RSDP is ok. Init the table info */
-
- table_info.pointer = ACPI_CAST_PTR(struct acpi_table_header, rsdp);
- table_info.length = sizeof(struct rsdp_descriptor);
-
- if (address->pointer_type == ACPI_PHYSICAL_POINTER) {
- table_info.allocation = ACPI_MEM_MAPPED;
- } else {
- table_info.allocation = ACPI_MEM_NOT_ALLOCATED;
- }
-
- /* Save the table pointers and allocation info */
-
- status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_RSDP, &table_info);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- /* Save the RSDP in a global for easy access */
-
- acpi_gbl_RSDP =
- ACPI_CAST_PTR(struct rsdp_descriptor, table_info.pointer);
- return_ACPI_STATUS(status);
-
- /* Error exit */
- cleanup:
-
- if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) {
- acpi_os_unmap_memory(rsdp, sizeof(struct rsdp_descriptor));
- }
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_rsdt_address
- *
- * PARAMETERS: out_address - Where the address is returned
- *
- * RETURN: None, Address
- *
- * DESCRIPTION: Extract the address of either the RSDT or XSDT, depending on the
- * version of the RSDP and whether the XSDT pointer is valid
- *
- ******************************************************************************/
-
-void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address)
-{
-
- ACPI_FUNCTION_ENTRY();
-
- out_address->pointer_type =
- acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
-
- /* Use XSDT if it is present */
-
- if ((acpi_gbl_RSDP->revision >= 2) &&
- acpi_gbl_RSDP->xsdt_physical_address) {
- out_address->pointer.value =
- acpi_gbl_RSDP->xsdt_physical_address;
- acpi_gbl_root_table_type = ACPI_TABLE_TYPE_XSDT;
- } else {
- /* No XSDT, use the RSDT */
-
- out_address->pointer.value =
- acpi_gbl_RSDP->rsdt_physical_address;
- acpi_gbl_root_table_type = ACPI_TABLE_TYPE_RSDT;
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_validate_rsdt
- *
- * PARAMETERS: table_ptr - Addressable pointer to the RSDT.
- *
- * RETURN: Status
- *
- * DESCRIPTION: Validate signature for the RSDT or XSDT
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
-{
- char *signature;
-
- ACPI_FUNCTION_ENTRY();
-
- /* Validate minimum length */
-
- if (table_ptr->length < sizeof(struct acpi_table_header)) {
- ACPI_ERROR((AE_INFO,
- "RSDT/XSDT length (%X) is smaller than minimum (%zX)",
- table_ptr->length,
- sizeof(struct acpi_table_header)));
-
- return (AE_INVALID_TABLE_LENGTH);
- }
-
- /* Search for appropriate signature, RSDT or XSDT */
-
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- signature = RSDT_SIG;
- } else {
- signature = XSDT_SIG;
- }
-
- if (!ACPI_COMPARE_NAME(table_ptr->signature, signature)) {
-
- /* Invalid RSDT or XSDT signature */
-
- ACPI_ERROR((AE_INFO,
- "Invalid signature where RSDP indicates RSDT/XSDT should be located. RSDP:"));
-
- ACPI_DUMP_BUFFER(acpi_gbl_RSDP, 20);
-
- ACPI_ERROR((AE_INFO,
- "RSDT/XSDT signature at %X is invalid",
- acpi_gbl_RSDP->rsdt_physical_address));
-
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- ACPI_ERROR((AE_INFO, "Looking for RSDT"));
- } else {
- ACPI_ERROR((AE_INFO, "Looking for XSDT"));
- }
-
- ACPI_DUMP_BUFFER(ACPI_CAST_PTR(char, table_ptr), 48);
- return (AE_BAD_SIGNATURE);
- }
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_rsdt
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_get_table_rsdt(void)
-{
- struct acpi_table_desc table_info;
- acpi_status status;
- struct acpi_pointer address;
-
- ACPI_FUNCTION_TRACE(tb_get_table_rsdt);
-
- /* Get the RSDT/XSDT via the RSDP */
-
- acpi_tb_get_rsdt_address(&address);
-
- table_info.type = ACPI_TABLE_ID_XSDT;
- status = acpi_tb_get_table(&address, &table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get the RSDT/XSDT"));
- return_ACPI_STATUS(status);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "RSDP located at %p, points to RSDT physical=%8.8X%8.8X\n",
- acpi_gbl_RSDP,
- ACPI_FORMAT_UINT64(address.pointer.value)));
-
- /* Check the RSDT or XSDT signature */
-
- status = acpi_tb_validate_rsdt(table_info.pointer);
- if (ACPI_FAILURE(status)) {
- goto error_cleanup;
- }
-
- /* Get the number of tables defined in the RSDT or XSDT */
-
- acpi_gbl_rsdt_table_count = acpi_tb_get_table_count(acpi_gbl_RSDP,
- table_info.pointer);
-
- /* Convert and/or copy to an XSDT structure */
-
- status = acpi_tb_convert_to_xsdt(&table_info);
- if (ACPI_FAILURE(status)) {
- goto error_cleanup;
- }
-
- /* Save the table pointers and allocation info */
-
- status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info);
- if (ACPI_FAILURE(status)) {
- goto error_cleanup;
- }
-
- acpi_gbl_XSDT =
- ACPI_CAST_PTR(struct xsdt_descriptor, table_info.pointer);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
- return_ACPI_STATUS(status);
-
- error_cleanup:
-
- /* Free table allocated by acpi_tb_get_table */
-
- acpi_tb_delete_single_table(&table_info);
-
- return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 209a401801e..1da64b4518c 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -1,11 +1,11 @@
/******************************************************************************
*
- * Module Name: tbutils - Table manipulation utilities
+ * Module Name: tbutils - table utilities
*
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,137 +48,119 @@
ACPI_MODULE_NAME("tbutils")
/* Local prototypes */
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-acpi_status
-acpi_tb_handle_to_object(u16 table_id, struct acpi_table_desc **table_desc);
-#endif
+static acpi_physical_address
+acpi_tb_get_root_table_entry(u8 * table_entry,
+ acpi_native_uint table_entry_size);
/*******************************************************************************
*
- * FUNCTION: acpi_tb_is_table_installed
- *
- * PARAMETERS: new_table_desc - Descriptor for new table being installed
+ * FUNCTION: acpi_tb_tables_loaded
*
- * RETURN: Status - AE_ALREADY_EXISTS if the table is already installed
+ * PARAMETERS: None
*
- * DESCRIPTION: Determine if an ACPI table is already installed
+ * RETURN: TRUE if required ACPI tables are loaded
*
- * MUTEX: Table data structures should be locked
+ * DESCRIPTION: Determine if the minimum required ACPI tables are present
+ * (FADT, FACS, DSDT)
*
******************************************************************************/
-acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc)
+u8 acpi_tb_tables_loaded(void)
{
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(tb_is_table_installed);
- /* Get the list descriptor and first table descriptor */
-
- table_desc = acpi_gbl_table_lists[new_table_desc->type].next;
+ if (acpi_gbl_root_table_list.count >= 3) {
+ return (TRUE);
+ }
- /* Examine all installed tables of this type */
+ return (FALSE);
+}
- while (table_desc) {
- /*
- * If the table lengths match, perform a full bytewise compare. This
- * means that we will allow tables with duplicate oem_table_id(s), as
- * long as the tables are different in some way.
- *
- * Checking if the table has been loaded into the namespace means that
- * we don't check for duplicate tables during the initial installation
- * of tables within the RSDT/XSDT.
- */
- if ((table_desc->loaded_into_namespace) &&
- (table_desc->pointer->length ==
- new_table_desc->pointer->length)
- &&
- (!ACPI_MEMCMP
- (table_desc->pointer, new_table_desc->pointer,
- new_table_desc->pointer->length))) {
-
- /* Match: this table is already installed */
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Table [%4.4s] already installed: Rev %X OemTableId [%8.8s]\n",
- new_table_desc->pointer->signature,
- new_table_desc->pointer->revision,
- new_table_desc->pointer->
- oem_table_id));
-
- new_table_desc->owner_id = table_desc->owner_id;
- new_table_desc->installed_desc = table_desc;
-
- return_ACPI_STATUS(AE_ALREADY_EXISTS);
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_print_table_header
+ *
+ * PARAMETERS: Address - Table physical address
+ * Header - Table header
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
+ *
+ ******************************************************************************/
- /* Get next table on the list */
+void
+acpi_tb_print_table_header(acpi_physical_address address,
+ struct acpi_table_header *header)
+{
- table_desc = table_desc->next;
+ if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
+
+ /* FACS only has signature and length fields of common table header */
+
+ ACPI_INFO((AE_INFO, "%4.4s %08lX, %04X",
+ header->signature, (unsigned long)address,
+ header->length));
+ } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {
+
+ /* RSDP has no common fields */
+
+ ACPI_INFO((AE_INFO, "RSDP %08lX, %04X (r%d %6.6s)",
+ (unsigned long)address,
+ (ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
+ revision >
+ 0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->length : 20,
+ ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->revision,
+ ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->oem_id));
+ } else {
+ /* Standard ACPI table with full common header */
+
+ ACPI_INFO((AE_INFO,
+ "%4.4s %08lX, %04X (r%d %6.6s %8.8s %8X %4.4s %8X)",
+ header->signature, (unsigned long)address,
+ header->length, header->revision, header->oem_id,
+ header->oem_table_id, header->oem_revision,
+ header->asl_compiler_id,
+ header->asl_compiler_revision));
}
-
- return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_validate_table_header
+ * FUNCTION: acpi_tb_validate_checksum
*
- * PARAMETERS: table_header - Logical pointer to the table
+ * PARAMETERS: Table - ACPI table to verify
+ * Length - Length of entire table
*
* RETURN: Status
*
- * DESCRIPTION: Check an ACPI table header for validity
- *
- * NOTE: Table pointers are validated as follows:
- * 1) Table pointer must point to valid physical memory
- * 2) Signature must be 4 ASCII chars, even if we don't recognize the
- * name
- * 3) Table must be readable for length specified in the header
- * 4) Table checksum must be valid (with the exception of the FACS
- * which has no checksum because it contains variable fields)
+ * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
+ * exception on bad checksum.
*
******************************************************************************/
-acpi_status
-acpi_tb_validate_table_header(struct acpi_table_header *table_header)
+acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
{
- acpi_name signature;
-
- ACPI_FUNCTION_ENTRY();
-
- /* Verify that this is a valid address */
-
- if (!acpi_os_readable(table_header, sizeof(struct acpi_table_header))) {
- ACPI_ERROR((AE_INFO,
- "Cannot read table header at %p", table_header));
-
- return (AE_BAD_ADDRESS);
- }
+ u8 checksum;
- /* Ensure that the signature is 4 ASCII characters */
+ /* Compute the checksum on the table */
- ACPI_MOVE_32_TO_32(&signature, table_header->signature);
- if (!acpi_ut_valid_acpi_name(signature)) {
- ACPI_ERROR((AE_INFO, "Invalid table signature 0x%8.8X",
- signature));
+ checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
- ACPI_DUMP_BUFFER(table_header,
- sizeof(struct acpi_table_header));
- return (AE_BAD_SIGNATURE);
- }
+ /* Checksum ok? (should be zero) */
- /* Validate the table length */
+ if (checksum) {
+ ACPI_WARNING((AE_INFO,
+ "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
+ table->signature, table->checksum,
+ (u8) (table->checksum - checksum)));
- if (table_header->length < sizeof(struct acpi_table_header)) {
- ACPI_ERROR((AE_INFO,
- "Invalid length 0x%X in table with signature %4.4s",
- (u32) table_header->length,
- ACPI_CAST_PTR(char, &signature)));
+#if (ACPI_CHECKSUM_ABORT)
- ACPI_DUMP_BUFFER(table_header,
- sizeof(struct acpi_table_header));
- return (AE_BAD_HEADER);
+ return (AE_BAD_CHECKSUM);
+#endif
}
return (AE_OK);
@@ -186,157 +168,320 @@ acpi_tb_validate_table_header(struct acpi_table_header *table_header)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_sum_table
+ * FUNCTION: acpi_tb_checksum
*
- * PARAMETERS: Buffer - Buffer to sum
- * Length - Size of the buffer
+ * PARAMETERS: Buffer - Pointer to memory region to be checked
+ * Length - Length of this memory region
*
- * RETURN: 8 bit sum of buffer
+ * RETURN: Checksum (u8)
*
- * DESCRIPTION: Computes an 8 bit sum of the buffer(length) and returns it.
+ * DESCRIPTION: Calculates circular checksum of memory region.
*
******************************************************************************/
-u8 acpi_tb_sum_table(void *buffer, u32 length)
+u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
{
- acpi_native_uint i;
u8 sum = 0;
+ u8 *end = buffer + length;
- if (!buffer || !length) {
- return (0);
+ while (buffer < end) {
+ sum = (u8) (sum + *(buffer++));
}
- for (i = 0; i < length; i++) {
- sum = (u8) (sum + ((u8 *) buffer)[i]);
- }
- return (sum);
+ return sum;
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_generate_checksum
+ * FUNCTION: acpi_tb_install_table
*
- * PARAMETERS: Table - Pointer to a valid ACPI table (with a
- * standard ACPI header)
+ * PARAMETERS: Address - Physical address of DSDT or FACS
+ * Flags - Flags
+ * Signature - Table signature, NULL if no need to
+ * match
+ * table_index - Index into root table array
*
- * RETURN: 8 bit checksum of buffer
+ * RETURN: None
*
- * DESCRIPTION: Computes an 8 bit checksum of the table.
+ * DESCRIPTION: Install an ACPI table into the global data structure.
*
******************************************************************************/
-u8 acpi_tb_generate_checksum(struct acpi_table_header * table)
+void
+acpi_tb_install_table(acpi_physical_address address,
+ u8 flags, char *signature, acpi_native_uint table_index)
{
- u8 checksum;
+ struct acpi_table_header *table;
+
+ if (!address) {
+ ACPI_ERROR((AE_INFO,
+ "Null physical address for ACPI table [%s]",
+ signature));
+ return;
+ }
+
+ /* Map just the table header */
+
+ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+ if (!table) {
+ return;
+ }
+
+ /* If a particular signature is expected, signature must match */
+
+ if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid signature 0x%X for ACPI table [%s]",
+ *ACPI_CAST_PTR(u32, table->signature), signature));
+ goto unmap_and_exit;
+ }
- /* Sum the entire table as-is */
+ /* Initialize the table entry */
- checksum = acpi_tb_sum_table(table, table->length);
+ acpi_gbl_root_table_list.tables[table_index].address = address;
+ acpi_gbl_root_table_list.tables[table_index].length = table->length;
+ acpi_gbl_root_table_list.tables[table_index].flags = flags;
- /* Subtract off the existing checksum value in the table */
+ ACPI_MOVE_32_TO_32(&
+ (acpi_gbl_root_table_list.tables[table_index].
+ signature), table->signature);
- checksum = (u8) (checksum - table->checksum);
+ acpi_tb_print_table_header(address, table);
- /* Compute the final checksum */
+ if (table_index == ACPI_TABLE_INDEX_DSDT) {
- checksum = (u8) (0 - checksum);
- return (checksum);
+ /* Global integer width is based upon revision of the DSDT */
+
+ acpi_ut_set_integer_width(table->revision);
+ }
+
+ unmap_and_exit:
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_set_checksum
+ * FUNCTION: acpi_tb_get_root_table_entry
*
- * PARAMETERS: Table - Pointer to a valid ACPI table (with a
- * standard ACPI header)
+ * PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry
+ * table_entry_size - sizeof 32 or 64 (RSDT or XSDT)
*
- * RETURN: None. Sets the table checksum field
+ * RETURN: Physical address extracted from the root table
*
- * DESCRIPTION: Computes an 8 bit checksum of the table and inserts the
- * checksum into the table header.
+ * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
+ * both 32-bit and 64-bit platforms
+ *
+ * NOTE: acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on
+ * 64-bit platforms.
*
******************************************************************************/
-void acpi_tb_set_checksum(struct acpi_table_header *table)
+static acpi_physical_address
+acpi_tb_get_root_table_entry(u8 * table_entry,
+ acpi_native_uint table_entry_size)
{
+ u64 address64;
+
+ /*
+ * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
+ * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
+ */
+ if (table_entry_size == sizeof(u32)) {
+ /*
+ * 32-bit platform, RSDT: Return 32-bit table entry
+ * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
+ */
+ return ((acpi_physical_address)
+ (*ACPI_CAST_PTR(u32, table_entry)));
+ } else {
+ /*
+ * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
+ * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, return 64-bit
+ */
+ ACPI_MOVE_64_TO_64(&address64, table_entry);
- table->checksum = acpi_tb_generate_checksum(table);
+#if ACPI_MACHINE_WIDTH == 32
+ if (address64 > ACPI_UINT32_MAX) {
+
+ /* Will truncate 64-bit address to 32 bits, issue warning */
+
+ ACPI_WARNING((AE_INFO,
+ "64-bit Physical Address in XSDT is too large (%8.8X%8.8X), truncating",
+ ACPI_FORMAT_UINT64(address64)));
+ }
+#endif
+ return ((acpi_physical_address) (address64));
+ }
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_verify_table_checksum
+ * FUNCTION: acpi_tb_parse_root_table
+ *
+ * PARAMETERS: Rsdp - Pointer to the RSDP
+ * Flags - Flags
*
- * PARAMETERS: *table_header - ACPI table to verify
+ * RETURN: Status
*
- * RETURN: 8 bit checksum of table
+ * DESCRIPTION: This function is called to parse the Root System Description
+ * Table (RSDT or XSDT)
*
- * DESCRIPTION: Generates an 8 bit checksum of table and returns and compares
- * it to the existing checksum value.
+ * NOTE: Tables are mapped (not copied) for efficiency. The FACS must
+ * be mapped and cannot be copied because it contains the actual
+ * memory location of the ACPI Global Lock.
*
******************************************************************************/
-acpi_status
-acpi_tb_verify_table_checksum(struct acpi_table_header *table_header)
+acpi_status __init
+acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
{
- u8 checksum;
+ struct acpi_table_rsdp *rsdp;
+ acpi_native_uint table_entry_size;
+ acpi_native_uint i;
+ u32 table_count;
+ struct acpi_table_header *table;
+ acpi_physical_address address;
+ u32 length;
+ u8 *table_entry;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(tb_parse_root_table);
+
+ /*
+ * Map the entire RSDP and extract the address of the RSDT or XSDT
+ */
+ rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
+ if (!rsdp) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
- ACPI_FUNCTION_TRACE(tb_verify_table_checksum);
+ acpi_tb_print_table_header(rsdp_address,
+ ACPI_CAST_PTR(struct acpi_table_header,
+ rsdp));
- /* Compute the checksum on the table */
+ /* Differentiate between RSDT and XSDT root tables */
- checksum = acpi_tb_generate_checksum(table_header);
+ if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
+ /*
+ * Root table is an XSDT (64-bit physical addresses). We must use the
+ * XSDT if the revision is > 1 and the XSDT pointer is present, as per
+ * the ACPI specification.
+ */
+ address = (acpi_physical_address) rsdp->xsdt_physical_address;
+ table_entry_size = sizeof(u64);
+ } else {
+ /* Root table is an RSDT (32-bit physical addresses) */
- /* Checksum ok? */
+ address = (acpi_physical_address) rsdp->rsdt_physical_address;
+ table_entry_size = sizeof(u32);
+ }
- if (checksum == table_header->checksum) {
- return_ACPI_STATUS(AE_OK);
+ /*
+ * It is not possible to map more than one entry in some environments,
+ * so unmap the RSDP here before mapping other tables
+ */
+ acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
+
+ /* Map the RSDT/XSDT table header to get the full table length */
+
+ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+ if (!table) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- ACPI_WARNING((AE_INFO,
- "Incorrect checksum in table [%4.4s] - is %2.2X, should be %2.2X",
- table_header->signature, table_header->checksum,
- checksum));
+ acpi_tb_print_table_header(address, table);
- return_ACPI_STATUS(AE_BAD_CHECKSUM);
-}
+ /* Get the length of the full table, verify length and map entire table */
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_handle_to_object
- *
- * PARAMETERS: table_id - Id for which the function is searching
- * table_desc - Pointer to return the matching table
- * descriptor.
- *
- * RETURN: Search the tables to find one with a matching table_id and
- * return a pointer to that table descriptor.
- *
- ******************************************************************************/
+ length = table->length;
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
-acpi_status
-acpi_tb_handle_to_object(u16 table_id,
- struct acpi_table_desc **return_table_desc)
-{
- u32 i;
- struct acpi_table_desc *table_desc;
+ if (length < sizeof(struct acpi_table_header)) {
+ ACPI_ERROR((AE_INFO, "Invalid length 0x%X in RSDT/XSDT",
+ length));
+ return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+ }
- ACPI_FUNCTION_NAME(tb_handle_to_object);
+ table = acpi_os_map_memory(address, length);
+ if (!table) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Validate the root table checksum */
+
+ status = acpi_tb_verify_checksum(table, length);
+ if (ACPI_FAILURE(status)) {
+ acpi_os_unmap_memory(table, length);
+ return_ACPI_STATUS(status);
+ }
- for (i = 0; i < ACPI_TABLE_MAX; i++) {
- table_desc = acpi_gbl_table_lists[i].next;
- while (table_desc) {
- if (table_desc->table_id == table_id) {
- *return_table_desc = table_desc;
- return (AE_OK);
+ /* Calculate the number of tables described in the root table */
+
+ table_count =
+ (u32) ((table->length -
+ sizeof(struct acpi_table_header)) / table_entry_size);
+
+ /*
+ * First two entries in the table array are reserved for the DSDT and FACS,
+ * which are not actually present in the RSDT/XSDT - they come from the FADT
+ */
+ table_entry =
+ ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
+ acpi_gbl_root_table_list.count = 2;
+
+ /*
+ * Initialize the root table array from the RSDT/XSDT
+ */
+ for (i = 0; i < table_count; i++) {
+ if (acpi_gbl_root_table_list.count >=
+ acpi_gbl_root_table_list.size) {
+
+ /* There is no more room in the root table array, attempt resize */
+
+ status = acpi_tb_resize_root_table_list();
+ if (ACPI_FAILURE(status)) {
+ ACPI_WARNING((AE_INFO,
+ "Truncating %u table entries!",
+ (unsigned)
+ (acpi_gbl_root_table_list.size -
+ acpi_gbl_root_table_list.
+ count)));
+ break;
}
+ }
+
+ /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
- table_desc = table_desc->next;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ address =
+ acpi_tb_get_root_table_entry(table_entry, table_entry_size);
+
+ table_entry += table_entry_size;
+ acpi_gbl_root_table_list.count++;
+ }
+
+ /*
+ * It is not possible to map more than one entry in some environments,
+ * so unmap the root table here before mapping other tables
+ */
+ acpi_os_unmap_memory(table, length);
+
+ /*
+ * Complete the initialization of the root table array by examining
+ * the header of each table
+ */
+ for (i = 2; i < acpi_gbl_root_table_list.count; i++) {
+ acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
+ address, flags, NULL, i);
+
+ /* Special case for FADT - get the DSDT and FACS */
+
+ if (ACPI_COMPARE_NAME
+ (&acpi_gbl_root_table_list.tables[i].signature,
+ ACPI_SIG_FADT)) {
+ acpi_tb_parse_fadt(i, flags);
}
}
- ACPI_ERROR((AE_INFO, "TableId=%X does not exist", table_id));
- return (AE_BAD_PARAMETER);
+ return_ACPI_STATUS(AE_OK);
}
-#endif
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 7767987be15..807978d5381 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,81 +49,158 @@
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbxface")
+/* Local prototypes */
+static acpi_status acpi_tb_load_namespace(void);
+
/*******************************************************************************
*
- * FUNCTION: acpi_load_tables
+ * FUNCTION: acpi_allocate_root_table
*
- * PARAMETERS: None
+ * PARAMETERS: initial_table_count - Size of initial_table_array, in number of
+ * struct acpi_table_desc structures
*
* RETURN: Status
*
- * DESCRIPTION: This function is called to load the ACPI tables from the
- * provided RSDT
+ * DESCRIPTION: Allocate a root table array. Used by i_aSL compiler and
+ * acpi_initialize_tables.
*
******************************************************************************/
-acpi_status acpi_load_tables(void)
+
+acpi_status acpi_allocate_root_table(u32 initial_table_count)
{
- struct acpi_pointer rsdp_address;
- acpi_status status;
- ACPI_FUNCTION_TRACE(acpi_load_tables);
+ acpi_gbl_root_table_list.size = initial_table_count;
+ acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE;
- /* Get the RSDP */
+ return (acpi_tb_resize_root_table_list());
+}
- status = acpi_os_get_root_pointer(ACPI_LOGICAL_ADDRESSING,
- &rsdp_address);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not get the RSDP"));
- goto error_exit;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_initialize_tables
+ *
+ * PARAMETERS: initial_table_array - Pointer to an array of pre-allocated
+ * struct acpi_table_desc structures. If NULL, the
+ * array is dynamically allocated.
+ * initial_table_count - Size of initial_table_array, in number of
+ * struct acpi_table_desc structures
+ * allow_realloc - Flag to tell Table Manager if resize of
+ * pre-allocated array is allowed. Ignored
+ * if initial_table_array is NULL.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT.
+ *
+ * NOTE: Allows static allocation of the initial table array in order
+ * to avoid the use of dynamic memory in confined environments
+ * such as the kernel boot sequence where it may not be available.
+ *
+ * If the host OS memory managers are initialized, use NULL for
+ * initial_table_array, and the table will be dynamically allocated.
+ *
+ ******************************************************************************/
- /* Map and validate the RSDP */
+acpi_status __init
+acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
+ u32 initial_table_count, u8 allow_resize)
+{
+ acpi_physical_address rsdp_address;
+ acpi_status status;
- acpi_gbl_table_flags = rsdp_address.pointer_type;
+ ACPI_FUNCTION_TRACE(acpi_initialize_tables);
- status = acpi_tb_verify_rsdp(&rsdp_address);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "During RSDP validation"));
- goto error_exit;
+ /*
+ * Set up the Root Table Array
+ * Allocate the table array if requested
+ */
+ if (!initial_table_array) {
+ status = acpi_allocate_root_table(initial_table_count);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ } else {
+ /* Root Table Array has been statically allocated by the host */
+
+ ACPI_MEMSET(initial_table_array, 0,
+ initial_table_count *
+ sizeof(struct acpi_table_desc));
+
+ acpi_gbl_root_table_list.tables = initial_table_array;
+ acpi_gbl_root_table_list.size = initial_table_count;
+ acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN;
+ if (allow_resize) {
+ acpi_gbl_root_table_list.flags |=
+ ACPI_ROOT_ALLOW_RESIZE;
+ }
}
- /* Get the RSDT via the RSDP */
+ /* Get the address of the RSDP */
- status = acpi_tb_get_table_rsdt();
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not load RSDT"));
- goto error_exit;
+ rsdp_address = acpi_os_get_root_pointer();
+ if (!rsdp_address) {
+ return_ACPI_STATUS(AE_NOT_FOUND);
}
- /* Now get the tables needed by this subsystem (FADT, DSDT, etc.) */
+ /*
+ * Get the root table (RSDT or XSDT) and extract all entries to the local
+ * Root Table Array. This array contains the information of the RSDT/XSDT
+ * in a common, more useable format.
+ */
+ status =
+ acpi_tb_parse_root_table(rsdp_address, ACPI_TABLE_ORIGIN_MAPPED);
+ return_ACPI_STATUS(status);
+}
- status = acpi_tb_get_required_tables();
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get all required tables (DSDT/FADT/FACS)"));
- goto error_exit;
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_reallocate_root_table
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the
+ * root list from the previously provided scratch area. Should
+ * be called once dynamic memory allocation is available in the
+ * kernel
+ *
+ ******************************************************************************/
+acpi_status acpi_reallocate_root_table(void)
+{
+ struct acpi_table_desc *tables;
+ acpi_size new_size;
+
+ ACPI_FUNCTION_TRACE(acpi_reallocate_root_table);
+
+ /*
+ * Only reallocate the root table if the host provided a static buffer
+ * for the table array in the call to acpi_initialize_tables.
+ */
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ return_ACPI_STATUS(AE_SUPPORT);
}
- ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
+ new_size =
+ (acpi_gbl_root_table_list.count +
+ ACPI_ROOT_TABLE_SIZE_INCREMENT) * sizeof(struct acpi_table_desc);
- /* Load the namespace from the tables */
+ /* Create new array and copy the old array */
- status = acpi_ns_load_namespace();
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not load namespace"));
- goto error_exit;
+ tables = ACPI_ALLOCATE_ZEROED(new_size);
+ if (!tables) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- return_ACPI_STATUS(AE_OK);
+ ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, new_size);
- error_exit:
- ACPI_EXCEPTION((AE_INFO, status, "Could not load tables"));
- return_ACPI_STATUS(status);
-}
+ acpi_gbl_root_table_list.size = acpi_gbl_root_table_list.count;
+ acpi_gbl_root_table_list.tables = tables;
+ acpi_gbl_root_table_list.flags =
+ ACPI_ROOT_ORIGIN_ALLOCATED | ACPI_ROOT_ALLOW_RESIZE;
-ACPI_EXPORT_SYMBOL(acpi_load_tables)
-
-#ifdef ACPI_FUTURE_USAGE
+ return_ACPI_STATUS(AE_OK);
+}
/*******************************************************************************
*
* FUNCTION: acpi_load_table
@@ -142,289 +219,405 @@ ACPI_EXPORT_SYMBOL(acpi_load_tables)
acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
{
acpi_status status;
- struct acpi_table_desc table_info;
- struct acpi_pointer address;
+ acpi_native_uint table_index;
+ struct acpi_table_desc table_desc;
- ACPI_FUNCTION_TRACE(acpi_load_table);
+ if (!table_ptr)
+ return AE_BAD_PARAMETER;
- if (!table_ptr) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Copy the table to a local buffer */
+ ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
+ table_desc.pointer = table_ptr;
+ table_desc.length = table_ptr->length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN;
- address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
- address.pointer.logical = table_ptr;
-
- status = acpi_tb_get_table_body(&address, table_ptr, &table_info);
+ /*
+ * Install the new table into the local data structures
+ */
+ status = acpi_tb_add_table(&table_desc, &table_index);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ return status;
}
+ status = acpi_ns_load_table(table_index, acpi_gbl_root_node);
+ return status;
+}
- /* Check signature for a valid table type */
-
- status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ACPI_EXPORT_SYMBOL(acpi_load_table)
- /* Install the new table into the local data structures */
+/******************************************************************************
+ *
+ * FUNCTION: acpi_get_table_header
+ *
+ * PARAMETERS: Signature - ACPI signature of needed table
+ * Instance - Which instance (for SSDTs)
+ * out_table_header - The pointer to the table header to fill
+ *
+ * RETURN: Status and pointer to mapped table header
+ *
+ * DESCRIPTION: Finds an ACPI table header.
+ *
+ * NOTE: Caller is responsible in unmapping the header with
+ * acpi_os_unmap_memory
+ *
+ *****************************************************************************/
+acpi_status
+acpi_get_table_header(char *signature,
+ acpi_native_uint instance,
+ struct acpi_table_header *out_table_header)
+{
+ acpi_native_uint i;
+ acpi_native_uint j;
+ struct acpi_table_header *header;
- status = acpi_tb_install_table(&table_info);
- if (ACPI_FAILURE(status)) {
- if (status == AE_ALREADY_EXISTS) {
+ /* Parameter validation */
- /* Table already exists, no error */
+ if (!signature || !out_table_header) {
+ return (AE_BAD_PARAMETER);
+ }
- status = AE_OK;
+ /*
+ * Walk the root table list
+ */
+ for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
+ if (!ACPI_COMPARE_NAME
+ (&(acpi_gbl_root_table_list.tables[i].signature),
+ signature)) {
+ continue;
}
- /* Free table allocated by acpi_tb_get_table_body */
+ if (++j < instance) {
+ continue;
+ }
- acpi_tb_delete_single_table(&table_info);
- return_ACPI_STATUS(status);
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+ if ((acpi_gbl_root_table_list.tables[i].
+ flags & ACPI_TABLE_ORIGIN_MASK) ==
+ ACPI_TABLE_ORIGIN_MAPPED) {
+ header =
+ acpi_os_map_memory(acpi_gbl_root_table_list.
+ tables[i].address,
+ sizeof(struct
+ acpi_table_header));
+ if (!header) {
+ return AE_NO_MEMORY;
+ }
+ ACPI_MEMCPY(out_table_header, header,
+ sizeof(struct acpi_table_header));
+ acpi_os_unmap_memory(header,
+ sizeof(struct
+ acpi_table_header));
+ } else {
+ return AE_NOT_FOUND;
+ }
+ } else {
+ ACPI_MEMCPY(out_table_header,
+ acpi_gbl_root_table_list.tables[i].pointer,
+ sizeof(struct acpi_table_header));
+ }
+ return (AE_OK);
}
- /* Convert the table to common format if necessary */
-
- switch (table_info.type) {
- case ACPI_TABLE_ID_FADT:
-
- status = acpi_tb_convert_table_fadt();
- break;
-
- case ACPI_TABLE_ID_FACS:
-
- status = acpi_tb_build_common_facs(&table_info);
- break;
+ return (AE_NOT_FOUND);
+}
- default:
- /* Load table into namespace if it contains executable AML */
+ACPI_EXPORT_SYMBOL(acpi_get_table_header)
- status =
- acpi_ns_load_table(table_info.installed_desc,
- acpi_gbl_root_node);
- break;
- }
- if (ACPI_FAILURE(status)) {
+/******************************************************************************
+ *
+ * FUNCTION: acpi_unload_table_id
+ *
+ * PARAMETERS: id - Owner ID of the table to be removed.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This routine is used to force the unload of a table (by id)
+ *
+ ******************************************************************************/
+acpi_status acpi_unload_table_id(acpi_owner_id id)
+{
+ int i;
+ acpi_status status = AE_NOT_EXIST;
- /* Uninstall table and free the buffer */
+ ACPI_FUNCTION_TRACE(acpi_unload_table);
- (void)acpi_tb_uninstall_table(table_info.installed_desc);
+ /* Find table from the requested type list */
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if (id != acpi_gbl_root_table_list.tables[i].owner_id) {
+ continue;
+ }
+ /*
+ * Delete all namespace objects owned by this table. Note that these
+ * objects can appear anywhere in the namespace by virtue of the AML
+ * "Scope" operator. Thus, we need to track ownership by an ID, not
+ * simply a position within the hierarchy
+ */
+ acpi_tb_delete_namespace_by_owner(i);
+ acpi_tb_release_owner_id(i);
+ acpi_tb_set_table_loaded_flag(i, FALSE);
}
-
return_ACPI_STATUS(status);
}
-ACPI_EXPORT_SYMBOL(acpi_load_table)
+ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
/*******************************************************************************
*
- * FUNCTION: acpi_unload_table
+ * FUNCTION: acpi_get_table
*
- * PARAMETERS: table_type - Type of table to be unloaded
+ * PARAMETERS: Signature - ACPI signature of needed table
+ * Instance - Which instance (for SSDTs)
+ * out_table - Where the pointer to the table is returned
*
- * RETURN: Status
+ * RETURN: Status and pointer to table
*
- * DESCRIPTION: This routine is used to force the unload of a table
+ * DESCRIPTION: Finds and verifies an ACPI table.
*
- ******************************************************************************/
-acpi_status acpi_unload_table(acpi_table_type table_type)
+ *****************************************************************************/
+acpi_status
+acpi_get_table(char *signature,
+ acpi_native_uint instance, struct acpi_table_header ** out_table)
{
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(acpi_unload_table);
+ acpi_native_uint i;
+ acpi_native_uint j;
+ acpi_status status;
/* Parameter validation */
- if (table_type > ACPI_TABLE_ID_MAX) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ if (!signature || !out_table) {
+ return (AE_BAD_PARAMETER);
}
- /* Find all tables of the requested type */
+ /*
+ * Walk the root table list
+ */
+ for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
+ if (!ACPI_COMPARE_NAME
+ (&(acpi_gbl_root_table_list.tables[i].signature),
+ signature)) {
+ continue;
+ }
- table_desc = acpi_gbl_table_lists[table_type].next;
- if (!table_desc) {
- return_ACPI_STATUS(AE_NOT_EXIST);
- }
+ if (++j < instance) {
+ continue;
+ }
- while (table_desc) {
- /*
- * Delete all namespace objects owned by this table. Note that these
- * objects can appear anywhere in the namespace by virtue of the AML
- * "Scope" operator. Thus, we need to track ownership by an ID, not
- * simply a position within the hierarchy
- */
- acpi_ns_delete_namespace_by_owner(table_desc->owner_id);
- table_desc = table_desc->next;
- }
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]);
+ if (ACPI_SUCCESS(status)) {
+ *out_table = acpi_gbl_root_table_list.tables[i].pointer;
+ }
- /* Delete (or unmap) all tables of this type */
+ if (!acpi_gbl_permanent_mmap) {
+ acpi_gbl_root_table_list.tables[i].pointer = 0;
+ }
- acpi_tb_delete_tables_by_type(table_type);
- return_ACPI_STATUS(AE_OK);
+ return (status);
+ }
+
+ return (AE_NOT_FOUND);
}
-ACPI_EXPORT_SYMBOL(acpi_unload_table)
+ACPI_EXPORT_SYMBOL(acpi_get_table)
/*******************************************************************************
*
- * FUNCTION: acpi_get_table_header
+ * FUNCTION: acpi_get_table_by_index
*
- * PARAMETERS: table_type - one of the defined table types
- * Instance - the non zero instance of the table, allows
- * support for multiple tables of the same type
- * see acpi_gbl_acpi_table_flag
- * out_table_header - pointer to the struct acpi_table_header if successful
+ * PARAMETERS: table_index - Table index
+ * Table - Where the pointer to the table is returned
*
- * DESCRIPTION: This function is called to get an ACPI table header. The caller
- * supplies an pointer to a data area sufficient to contain an ACPI
- * struct acpi_table_header structure.
+ * RETURN: Status and pointer to the table
*
- * The header contains a length field that can be used to determine
- * the size of the buffer needed to contain the entire table. This
- * function is not valid for the RSD PTR table since it does not
- * have a standard header and is fixed length.
+ * DESCRIPTION: Obtain a table by an index into the global table list.
*
******************************************************************************/
acpi_status
-acpi_get_table_header(acpi_table_type table_type,
- u32 instance, struct acpi_table_header *out_table_header)
+acpi_get_table_by_index(acpi_native_uint table_index,
+ struct acpi_table_header ** table)
{
- struct acpi_table_header *tbl_ptr;
acpi_status status;
- ACPI_FUNCTION_TRACE(acpi_get_table_header);
+ ACPI_FUNCTION_TRACE(acpi_get_table_by_index);
+
+ /* Parameter validation */
- if ((instance == 0) ||
- (table_type == ACPI_TABLE_ID_RSDP) || (!out_table_header)) {
+ if (!table) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Check the table type and instance */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if ((table_type > ACPI_TABLE_ID_MAX) ||
- (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
- instance > 1)) {
+ /* Validate index */
+
+ if (table_index >= acpi_gbl_root_table_list.count) {
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Get a pointer to the entire table */
-
- status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ if (!acpi_gbl_root_table_list.tables[table_index].pointer) {
- /* The function will return a NULL pointer if the table is not loaded */
+ /* Table is not mapped, map it */
- if (tbl_ptr == NULL) {
- return_ACPI_STATUS(AE_NOT_EXIST);
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[table_index]);
+ if (ACPI_FAILURE(status)) {
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+ }
}
- /* Copy the header to the caller's buffer */
-
- ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header),
- ACPI_CAST_PTR(void, tbl_ptr),
- sizeof(struct acpi_table_header));
-
- return_ACPI_STATUS(status);
+ *table = acpi_gbl_root_table_list.tables[table_index].pointer;
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(AE_OK);
}
-ACPI_EXPORT_SYMBOL(acpi_get_table_header)
-#endif /* ACPI_FUTURE_USAGE */
+ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
/*******************************************************************************
*
- * FUNCTION: acpi_get_table
+ * FUNCTION: acpi_tb_load_namespace
*
- * PARAMETERS: table_type - one of the defined table types
- * Instance - the non zero instance of the table, allows
- * support for multiple tables of the same type
- * see acpi_gbl_acpi_table_flag
- * ret_buffer - pointer to a structure containing a buffer to
- * receive the table
+ * PARAMETERS: None
*
* RETURN: Status
*
- * DESCRIPTION: This function is called to get an ACPI table. The caller
- * supplies an out_buffer large enough to contain the entire ACPI
- * table. The caller should call the acpi_get_table_header function
- * first to determine the buffer size needed. Upon completion
- * the out_buffer->Length field will indicate the number of bytes
- * copied into the out_buffer->buf_ptr buffer. This table will be
- * a complete table including the header.
+ * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in
+ * the RSDT/XSDT.
*
******************************************************************************/
-acpi_status
-acpi_get_table(acpi_table_type table_type,
- u32 instance, struct acpi_buffer *ret_buffer)
+static acpi_status acpi_tb_load_namespace(void)
{
- struct acpi_table_header *tbl_ptr;
acpi_status status;
- acpi_size table_length;
+ struct acpi_table_header *table;
+ acpi_native_uint i;
- ACPI_FUNCTION_TRACE(acpi_get_table);
+ ACPI_FUNCTION_TRACE(tb_load_namespace);
- /* Parameter validation */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (instance == 0) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ /*
+ * Load the namespace. The DSDT is required, but any SSDT and PSDT tables
+ * are optional.
+ */
+ if (!acpi_gbl_root_table_list.count ||
+ !ACPI_COMPARE_NAME(&
+ (acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT].signature),
+ ACPI_SIG_DSDT)
+ ||
+ ACPI_FAILURE(acpi_tb_verify_table
+ (&acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT]))) {
+ status = AE_NO_ACPI_TABLES;
+ goto unlock_and_exit;
}
- status = acpi_ut_validate_buffer(ret_buffer);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /*
+ * Find DSDT table
+ */
+ status =
+ acpi_os_table_override(acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT].pointer,
+ &table);
+ if (ACPI_SUCCESS(status) && table) {
+ /*
+ * DSDT table has been found
+ */
+ acpi_tb_delete_table(&acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT]);
+ acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer =
+ table;
+ acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].length =
+ table->length;
+ acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].flags =
+ ACPI_TABLE_ORIGIN_UNKNOWN;
+
+ ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS"));
+ acpi_tb_print_table_header(0, table);
}
- /* Check the table type and instance */
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT]);
+ if (ACPI_FAILURE(status)) {
- if ((table_type > ACPI_TABLE_ID_MAX) ||
- (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
- instance > 1)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ /* A valid DSDT is required */
+
+ status = AE_NO_ACPI_TABLES;
+ goto unlock_and_exit;
}
- /* Get a pointer to the entire table */
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr);
+ /*
+ * Load and parse tables.
+ */
+ status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/*
- * acpi_tb_get_table_ptr will return a NULL pointer if the
- * table is not loaded.
+ * Load any SSDT or PSDT tables. Note: Loop leaves tables locked
*/
- if (tbl_ptr == NULL) {
- return_ACPI_STATUS(AE_NOT_EXIST);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if ((!ACPI_COMPARE_NAME
+ (&(acpi_gbl_root_table_list.tables[i].signature),
+ ACPI_SIG_SSDT)
+ &&
+ !ACPI_COMPARE_NAME(&
+ (acpi_gbl_root_table_list.tables[i].
+ signature), ACPI_SIG_PSDT))
+ ||
+ ACPI_FAILURE(acpi_tb_verify_table
+ (&acpi_gbl_root_table_list.tables[i]))) {
+ continue;
+ }
+
+ /* Ignore errors while loading tables, get as many as possible */
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ (void)acpi_ns_load_table(i, acpi_gbl_root_node);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
}
- /* Get the table length */
+ ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
- if (table_type == ACPI_TABLE_ID_RSDP) {
+ unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+}
- /* RSD PTR is the only "table" without a header */
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_load_tables
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT
+ *
+ ******************************************************************************/
- table_length = sizeof(struct rsdp_descriptor);
- } else {
- table_length = (acpi_size) tbl_ptr->length;
- }
+acpi_status acpi_load_tables(void)
+{
+ acpi_status status;
- /* Validate/Allocate/Clear caller buffer */
+ ACPI_FUNCTION_TRACE(acpi_load_tables);
- status = acpi_ut_initialize_buffer(ret_buffer, table_length);
+ /*
+ * Load the namespace from the tables
+ */
+ status = acpi_tb_load_namespace();
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ ACPI_EXCEPTION((AE_INFO, status,
+ "While loading namespace from ACPI tables"));
}
- /* Copy the table to the buffer */
-
- ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer),
- ACPI_CAST_PTR(void, tbl_ptr), table_length);
-
- return_ACPI_STATUS(AE_OK);
+ return_ACPI_STATUS(status);
}
-ACPI_EXPORT_SYMBOL(acpi_get_table)
+ACPI_EXPORT_SYMBOL(acpi_load_tables)
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index da2648bbdbc..cf8fa514189 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,16 +48,15 @@
ACPI_MODULE_NAME("tbxfroot")
/* Local prototypes */
-static acpi_status
-acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags);
-
static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
+static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
+
/*******************************************************************************
*
* FUNCTION: acpi_tb_validate_rsdp
*
- * PARAMETERS: Rsdp - Pointer to unvalidated RSDP
+ * PARAMETERS: Rsdp - Pointer to unvalidated RSDP
*
* RETURN: Status
*
@@ -65,14 +64,18 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
*
******************************************************************************/
-acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
+static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
{
ACPI_FUNCTION_ENTRY();
/*
- * The signature and checksum must both be correct
+ * The signature and checksum must both be correct
+ *
+ * Note: Sometimes there exists more than one RSDP in memory; the valid
+ * RSDP has a valid checksum, all others have an invalid checksum.
*/
- if (ACPI_STRNCMP((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) {
+ if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)
+ != 0) {
/* Nope, BAD Signature */
@@ -81,14 +84,14 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
/* Check the standard checksum */
- if (acpi_tb_sum_table(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
+ if (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
return (AE_BAD_CHECKSUM);
}
/* Check extended checksum if table version >= 2 */
if ((rsdp->revision >= 2) &&
- (acpi_tb_sum_table(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
+ (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
return (AE_BAD_CHECKSUM);
}
@@ -97,314 +100,123 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_find_table
- *
- * PARAMETERS: Signature - String with ACPI table signature
- * oem_id - String with the table OEM ID
- * oem_table_id - String with the OEM Table ID
- * table_ptr - Where the table pointer is returned
- *
- * RETURN: Status
+ * FUNCTION: acpi_tb_find_rsdp
*
- * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
- * Signature, OEM ID and OEM Table ID.
+ * PARAMETERS: table_address - Where the table pointer is returned
*
- ******************************************************************************/
-
-acpi_status
-acpi_tb_find_table(char *signature,
- char *oem_id,
- char *oem_table_id, struct acpi_table_header ** table_ptr)
-{
- acpi_status status;
- struct acpi_table_header *table;
-
- ACPI_FUNCTION_TRACE(tb_find_table);
-
- /* Validate string lengths */
-
- if ((ACPI_STRLEN(signature) > ACPI_NAME_SIZE) ||
- (ACPI_STRLEN(oem_id) > sizeof(table->oem_id)) ||
- (ACPI_STRLEN(oem_table_id) > sizeof(table->oem_table_id))) {
- return_ACPI_STATUS(AE_AML_STRING_LIMIT);
- }
-
- if (ACPI_COMPARE_NAME(signature, DSDT_SIG)) {
- /*
- * The DSDT pointer is contained in the FADT, not the RSDT.
- * This code should suffice, because the only code that would perform
- * a "find" on the DSDT is the data_table_region() AML opcode -- in
- * which case, the DSDT is guaranteed to be already loaded.
- * If this becomes insufficient, the FADT will have to be found first.
- */
- if (!acpi_gbl_DSDT) {
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
- table = acpi_gbl_DSDT;
- } else {
- /* Find the table */
-
- status = acpi_get_firmware_table(signature, 1,
- ACPI_LOGICAL_ADDRESSING,
- &table);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
- /* Check oem_id and oem_table_id */
-
- if ((oem_id[0] &&
- ACPI_STRNCMP(oem_id, table->oem_id,
- sizeof(table->oem_id))) ||
- (oem_table_id[0] &&
- ACPI_STRNCMP(oem_table_id, table->oem_table_id,
- sizeof(table->oem_table_id)))) {
- return_ACPI_STATUS(AE_AML_NAME_NOT_FOUND);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Found table [%4.4s]\n",
- table->signature));
-
- *table_ptr = table;
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_get_firmware_table
+ * RETURN: Status, RSDP physical address
*
- * PARAMETERS: Signature - Any ACPI table signature
- * Instance - the non zero instance of the table, allows
- * support for multiple tables of the same type
- * Flags - Physical/Virtual support
- * table_pointer - Where a buffer containing the table is
- * returned
+ * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
+ * pointer structure. If it is found, set *RSDP to point to it.
*
- * RETURN: Status
+ * NOTE1: The RSDP must be either in the first 1_k of the Extended
+ * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
+ * Only a 32-bit physical address is necessary.
*
- * DESCRIPTION: This function is called to get an ACPI table. A buffer is
- * allocated for the table and returned in table_pointer.
- * This table will be a complete table including the header.
+ * NOTE2: This function is always available, regardless of the
+ * initialization state of the rest of ACPI.
*
******************************************************************************/
-acpi_status
-acpi_get_firmware_table(acpi_string signature,
- u32 instance,
- u32 flags, struct acpi_table_header **table_pointer)
+acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
{
- acpi_status status;
- struct acpi_pointer address;
- struct acpi_table_header *header = NULL;
- struct acpi_table_desc *table_info = NULL;
- struct acpi_table_desc *rsdt_info;
- u32 table_count;
- u32 i;
- u32 j;
-
- ACPI_FUNCTION_TRACE(acpi_get_firmware_table);
-
- /*
- * Ensure that at least the table manager is initialized. We don't
- * require that the entire ACPI subsystem is up for this interface.
- * If we have a buffer, we must have a length too
- */
- if ((instance == 0) || (!signature) || (!table_pointer)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Ensure that we have a RSDP */
-
- if (!acpi_gbl_RSDP) {
-
- /* Get the RSDP */
-
- status = acpi_os_get_root_pointer(flags, &address);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "RSDP not found\n"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /* Map and validate the RSDP */
-
- if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
- status = acpi_os_map_memory(address.pointer.physical,
- sizeof(struct
- rsdp_descriptor),
- (void *)&acpi_gbl_RSDP);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- } else {
- acpi_gbl_RSDP = address.pointer.logical;
- }
-
- /* The RDSP signature and checksum must both be correct */
-
- status = acpi_tb_validate_rsdp(acpi_gbl_RSDP);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
- /* Get the RSDT address via the RSDP */
-
- acpi_tb_get_rsdt_address(&address);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "RSDP located at %p, RSDT physical=%8.8X%8.8X\n",
- acpi_gbl_RSDP,
- ACPI_FORMAT_UINT64(address.pointer.value)));
+ u8 *table_ptr;
+ u8 *mem_rover;
+ u32 physical_address;
- /* Insert processor_mode flags */
+ ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
- address.pointer_type |= flags;
+ /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
- /* Get and validate the RSDT */
+ table_ptr = acpi_os_map_memory((acpi_physical_address)
+ ACPI_EBDA_PTR_LOCATION,
+ ACPI_EBDA_PTR_LENGTH);
+ if (!table_ptr) {
+ ACPI_ERROR((AE_INFO,
+ "Could not map memory at %8.8X for length %X",
+ ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
- rsdt_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
- if (!rsdt_info) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
- status = acpi_tb_get_table(&address, rsdt_info);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- status = acpi_tb_validate_rsdt(rsdt_info->pointer);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
+ ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
- /* Allocate a scratch table header and table descriptor */
+ /* Convert segment part to physical address */
- header = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
- if (!header) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
+ physical_address <<= 4;
+ acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
- table_info = ACPI_ALLOCATE(sizeof(struct acpi_table_desc));
- if (!table_info) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
+ /* EBDA present? */
- /* Get the number of table pointers within the RSDT */
-
- table_count =
- acpi_tb_get_table_count(acpi_gbl_RSDP, rsdt_info->pointer);
- address.pointer_type = acpi_gbl_table_flags | flags;
-
- /*
- * Search the RSDT/XSDT for the correct instance of the
- * requested table
- */
- for (i = 0, j = 0; i < table_count; i++) {
+ if (physical_address > 0x400) {
/*
- * Get the next table pointer, handle RSDT vs. XSDT
- * RSDT pointers are 32 bits, XSDT pointers are 64 bits
+ * 1b) Search EBDA paragraphs (EBDA is required to be a
+ * minimum of 1_k length)
*/
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- address.pointer.value =
- (ACPI_CAST_PTR
- (struct rsdt_descriptor,
- rsdt_info->pointer))->table_offset_entry[i];
- } else {
- address.pointer.value =
- (ACPI_CAST_PTR
- (struct xsdt_descriptor,
- rsdt_info->pointer))->table_offset_entry[i];
- }
-
- /* Get the table header */
+ table_ptr = acpi_os_map_memory((acpi_native_uint)
+ physical_address,
+ ACPI_EBDA_WINDOW_SIZE);
+ if (!table_ptr) {
+ ACPI_ERROR((AE_INFO,
+ "Could not map memory at %8.8X for length %X",
+ physical_address, ACPI_EBDA_WINDOW_SIZE));
- status = acpi_tb_get_table_header(&address, header);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- /* Compare table signatures and table instance */
-
- if (ACPI_COMPARE_NAME(header->signature, signature)) {
-
- /* An instance of the table was found */
+ mem_rover =
+ acpi_tb_scan_memory_for_rsdp(table_ptr,
+ ACPI_EBDA_WINDOW_SIZE);
+ acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
- j++;
- if (j >= instance) {
+ if (mem_rover) {
- /* Found the correct instance, get the entire table */
+ /* Return the physical address */
- status =
- acpi_tb_get_table_body(&address, header,
- table_info);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
+ physical_address +=
+ (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
- *table_pointer = table_info->pointer;
- goto cleanup;
- }
+ *table_address = physical_address;
+ return_ACPI_STATUS(AE_OK);
}
}
- /* Did not find the table */
+ /*
+ * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
+ */
+ table_ptr = acpi_os_map_memory((acpi_physical_address)
+ ACPI_HI_RSDP_WINDOW_BASE,
+ ACPI_HI_RSDP_WINDOW_SIZE);
- status = AE_NOT_EXIST;
+ if (!table_ptr) {
+ ACPI_ERROR((AE_INFO,
+ "Could not map memory at %8.8X for length %X",
+ ACPI_HI_RSDP_WINDOW_BASE,
+ ACPI_HI_RSDP_WINDOW_SIZE));
- cleanup:
- if (rsdt_info->pointer) {
- acpi_os_unmap_memory(rsdt_info->pointer,
- (acpi_size) rsdt_info->pointer->length);
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- ACPI_FREE(rsdt_info);
- if (header) {
- ACPI_FREE(header);
- }
- if (table_info) {
- ACPI_FREE(table_info);
- }
- return_ACPI_STATUS(status);
-}
+ mem_rover =
+ acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
+ acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
-ACPI_EXPORT_SYMBOL(acpi_get_firmware_table)
+ if (mem_rover) {
-/* TBD: Move to a new file */
-#if ACPI_MACHINE_WIDTH != 16
-/*******************************************************************************
- *
- * FUNCTION: acpi_find_root_pointer
- *
- * PARAMETERS: Flags - Logical/Physical addressing
- * rsdp_address - Where to place the RSDP address
- *
- * RETURN: Status, Physical address of the RSDP
- *
- * DESCRIPTION: Find the RSDP
- *
- ******************************************************************************/
-acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address)
-{
- struct acpi_table_desc table_info;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
-
- /* Get the RSDP */
+ /* Return the physical address */
- status = acpi_tb_find_rsdp(&table_info, flags);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "RSDP structure not found - Flags=%X", flags));
+ physical_address = (u32)
+ (ACPI_HI_RSDP_WINDOW_BASE +
+ ACPI_PTR_DIFF(mem_rover, table_ptr));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
+ *table_address = physical_address;
+ return_ACPI_STATUS(AE_OK);
}
- rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER;
- rsdp_address->pointer.physical = table_info.physical_address;
- return_ACPI_STATUS(AE_OK);
+ /* A valid RSDP was not found */
+
+ ACPI_ERROR((AE_INFO, "A valid RSDP was not found"));
+ return_ACPI_STATUS(AE_NOT_FOUND);
}
ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
@@ -440,7 +252,7 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
status =
acpi_tb_validate_rsdp(ACPI_CAST_PTR
- (struct rsdp_descriptor, mem_rover));
+ (struct acpi_table_rsdp, mem_rover));
if (ACPI_SUCCESS(status)) {
/* Sig and checksum valid, we have found a real RSDP */
@@ -461,189 +273,3 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
start_address));
return_PTR(NULL);
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_find_rsdp
- *
- * PARAMETERS: table_info - Where the table info is returned
- * Flags - Current memory mode (logical vs.
- * physical addressing)
- *
- * RETURN: Status, RSDP physical address
- *
- * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
- * pointer structure. If it is found, set *RSDP to point to it.
- *
- * NOTE1: The RSDP must be either in the first 1_k of the Extended
- * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
- * Only a 32-bit physical address is necessary.
- *
- * NOTE2: This function is always available, regardless of the
- * initialization state of the rest of ACPI.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
-{
- u8 *table_ptr;
- u8 *mem_rover;
- u32 physical_address;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(tb_find_rsdp);
-
- /*
- * Scan supports either logical addressing or physical addressing
- */
- if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
-
- /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
-
- status = acpi_os_map_memory((acpi_physical_address)
- ACPI_EBDA_PTR_LOCATION,
- ACPI_EBDA_PTR_LENGTH,
- (void *)&table_ptr);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X for length %X",
- ACPI_EBDA_PTR_LOCATION,
- ACPI_EBDA_PTR_LENGTH));
-
- return_ACPI_STATUS(status);
- }
-
- ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
-
- /* Convert segment part to physical address */
-
- physical_address <<= 4;
- acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
-
- /* EBDA present? */
-
- if (physical_address > 0x400) {
- /*
- * 1b) Search EBDA paragraphs (EBDA is required to be a
- * minimum of 1_k length)
- */
- status = acpi_os_map_memory((acpi_physical_address)
- physical_address,
- ACPI_EBDA_WINDOW_SIZE,
- (void *)&table_ptr);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X for length %X",
- physical_address,
- ACPI_EBDA_WINDOW_SIZE));
-
- return_ACPI_STATUS(status);
- }
-
- mem_rover = acpi_tb_scan_memory_for_rsdp(table_ptr,
- ACPI_EBDA_WINDOW_SIZE);
- acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
-
- if (mem_rover) {
-
- /* Return the physical address */
-
- physical_address +=
- (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
-
- table_info->physical_address =
- (acpi_physical_address) physical_address;
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /*
- * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
- */
- status = acpi_os_map_memory((acpi_physical_address)
- ACPI_HI_RSDP_WINDOW_BASE,
- ACPI_HI_RSDP_WINDOW_SIZE,
- (void *)&table_ptr);
-
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X for length %X",
- ACPI_HI_RSDP_WINDOW_BASE,
- ACPI_HI_RSDP_WINDOW_SIZE));
-
- return_ACPI_STATUS(status);
- }
-
- mem_rover =
- acpi_tb_scan_memory_for_rsdp(table_ptr,
- ACPI_HI_RSDP_WINDOW_SIZE);
- acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
-
- if (mem_rover) {
-
- /* Return the physical address */
-
- physical_address = (u32)
- (ACPI_HI_RSDP_WINDOW_BASE +
- ACPI_PTR_DIFF(mem_rover, table_ptr));
-
- table_info->physical_address =
- (acpi_physical_address) physical_address;
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /*
- * Physical addressing
- */
- else {
- /* 1a) Get the location of the EBDA */
-
- ACPI_MOVE_16_TO_32(&physical_address, ACPI_EBDA_PTR_LOCATION);
- physical_address <<= 4; /* Convert segment to physical address */
-
- /* EBDA present? */
-
- if (physical_address > 0x400) {
- /*
- * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of
- * 1_k length)
- */
- mem_rover =
- acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR
- (physical_address),
- ACPI_EBDA_WINDOW_SIZE);
- if (mem_rover) {
-
- /* Return the physical address */
-
- table_info->physical_address =
- ACPI_TO_INTEGER(mem_rover);
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */
-
- mem_rover =
- acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR
- (ACPI_HI_RSDP_WINDOW_BASE),
- ACPI_HI_RSDP_WINDOW_SIZE);
- if (mem_rover) {
-
- /* Found it, return the physical address */
-
- table_info->physical_address =
- ACPI_TO_INTEGER(mem_rover);
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /* A valid RSDP was not found */
-
- ACPI_ERROR((AE_INFO, "No valid RSDP was found"));
- return_ACPI_STATUS(AE_NOT_FOUND);
-}
-
-#endif
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 5753d06b786..f76d3168c2b 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -82,7 +82,7 @@ MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
static int acpi_thermal_add(struct acpi_device *device);
static int acpi_thermal_remove(struct acpi_device *device, int type);
-static int acpi_thermal_resume(struct acpi_device *device, int state);
+static int acpi_thermal_resume(struct acpi_device *device);
static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
@@ -663,7 +663,7 @@ static void acpi_thermal_run(unsigned long data)
static void acpi_thermal_check(void *data)
{
int result = 0;
- struct acpi_thermal *tz = (struct acpi_thermal *)data;
+ struct acpi_thermal *tz = data;
unsigned long sleep_time = 0;
int i = 0;
struct acpi_thermal_state state;
@@ -778,7 +778,7 @@ static struct proc_dir_entry *acpi_thermal_dir;
static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+ struct acpi_thermal *tz = seq->private;
if (!tz)
@@ -813,7 +813,7 @@ static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file)
static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
{
int result = 0;
- struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+ struct acpi_thermal *tz = seq->private;
if (!tz)
@@ -837,7 +837,7 @@ static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file)
static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+ struct acpi_thermal *tz = seq->private;
int i = 0;
int j = 0;
@@ -893,8 +893,8 @@ acpi_thermal_write_trip_points(struct file *file,
const char __user * buffer,
size_t count, loff_t * ppos)
{
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_thermal *tz = m->private;
char *limit_string;
int num, critical, hot, passive;
@@ -902,12 +902,10 @@ acpi_thermal_write_trip_points(struct file *file,
int i = 0;
- limit_string = kmalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL);
+ limit_string = kzalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL);
if (!limit_string)
return -ENOMEM;
- memset(limit_string, 0, ACPI_THERMAL_MAX_LIMIT_STR_LEN);
-
active = kmalloc(ACPI_THERMAL_MAX_ACTIVE * sizeof(int), GFP_KERNEL);
if (!active) {
kfree(limit_string);
@@ -953,7 +951,7 @@ acpi_thermal_write_trip_points(struct file *file,
static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+ struct acpi_thermal *tz = seq->private;
if (!tz)
@@ -984,8 +982,8 @@ acpi_thermal_write_cooling_mode(struct file *file,
const char __user * buffer,
size_t count, loff_t * ppos)
{
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_thermal *tz = m->private;
int result = 0;
char mode_string[12] = { '\0' };
@@ -1014,7 +1012,7 @@ acpi_thermal_write_cooling_mode(struct file *file,
static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+ struct acpi_thermal *tz = seq->private;
if (!tz)
@@ -1043,8 +1041,8 @@ acpi_thermal_write_polling(struct file *file,
const char __user * buffer,
size_t count, loff_t * ppos)
{
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_thermal *tz = m->private;
int result = 0;
char polling_string[12] = { '\0' };
int seconds = 0;
@@ -1170,7 +1168,7 @@ static int acpi_thermal_remove_fs(struct acpi_device *device)
static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
{
- struct acpi_thermal *tz = (struct acpi_thermal *)data;
+ struct acpi_thermal *tz = data;
struct acpi_device *device = NULL;
@@ -1271,10 +1269,9 @@ static int acpi_thermal_add(struct acpi_device *device)
if (!device)
return -EINVAL;
- tz = kmalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
+ tz = kzalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
if (!tz)
return -ENOMEM;
- memset(tz, 0, sizeof(struct acpi_thermal));
tz->device = device;
strcpy(tz->name, device->pnp.bus_id);
@@ -1324,7 +1321,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- tz = (struct acpi_thermal *)acpi_driver_data(device);
+ tz = acpi_driver_data(device);
/* avoid timer adding new defer task */
tz->zombie = 1;
@@ -1356,7 +1353,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
return 0;
}
-static int acpi_thermal_resume(struct acpi_device *device, int state)
+static int acpi_thermal_resume(struct acpi_device *device)
{
struct acpi_thermal *tz = NULL;
int i;
@@ -1364,7 +1361,7 @@ static int acpi_thermal_resume(struct acpi_device *device, int state)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- tz = (struct acpi_thermal *)acpi_driver_data(device);
+ tz = acpi_driver_data(device);
acpi_thermal_get_temperature(tz);
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index 7fe0b7ae973..d9b651ffcdc 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -41,6 +41,8 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
+#include <linux/backlight.h>
+
#include <asm/uaccess.h>
#include <acpi/acpi_drivers.h>
@@ -210,6 +212,7 @@ static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result)
}
static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
+static struct backlight_device *toshiba_backlight_device;
static int force_fan;
static int last_key_event;
static int key_event_valid;
@@ -271,14 +274,23 @@ dispatch_write(struct file *file, const char __user * buffer,
return result;
}
-static char *read_lcd(char *p)
+static int get_lcd(struct backlight_device *bd)
{
u32 hci_result;
u32 value;
hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result);
if (hci_result == HCI_SUCCESS) {
- value = value >> HCI_LCD_BRIGHTNESS_SHIFT;
+ return (value >> HCI_LCD_BRIGHTNESS_SHIFT);
+ } else
+ return -EFAULT;
+}
+
+static char *read_lcd(char *p)
+{
+ int value = get_lcd(NULL);
+
+ if (value >= 0) {
p += sprintf(p, "brightness: %d\n", value);
p += sprintf(p, "brightness_levels: %d\n",
HCI_LCD_BRIGHTNESS_LEVELS);
@@ -289,22 +301,37 @@ static char *read_lcd(char *p)
return p;
}
+static int set_lcd(int value)
+{
+ u32 hci_result;
+
+ value = value << HCI_LCD_BRIGHTNESS_SHIFT;
+ hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
+ if (hci_result != HCI_SUCCESS)
+ return -EFAULT;
+
+ return 0;
+}
+
+static int set_lcd_status(struct backlight_device *bd)
+{
+ return set_lcd(bd->props->brightness);
+}
+
static unsigned long write_lcd(const char *buffer, unsigned long count)
{
int value;
- u32 hci_result;
+ int ret;
if (sscanf(buffer, " brightness : %i", &value) == 1 &&
value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
- value = value << HCI_LCD_BRIGHTNESS_SHIFT;
- hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
- if (hci_result != HCI_SUCCESS)
- return -EFAULT;
+ ret = set_lcd(value);
+ if (ret == 0)
+ ret = count;
} else {
- return -EINVAL;
+ ret = -EINVAL;
}
-
- return count;
+ return ret;
}
static char *read_video(char *p)
@@ -506,6 +533,26 @@ static acpi_status __exit remove_device(void)
return AE_OK;
}
+static struct backlight_properties toshiba_backlight_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = get_lcd,
+ .update_status = set_lcd_status,
+ .max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1,
+};
+
+static void __exit toshiba_acpi_exit(void)
+{
+ if (toshiba_backlight_device)
+ backlight_device_unregister(toshiba_backlight_device);
+
+ remove_device();
+
+ if (toshiba_proc_dir)
+ remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+
+ return;
+}
+
static int __init toshiba_acpi_init(void)
{
acpi_status status = AE_OK;
@@ -546,17 +593,16 @@ static int __init toshiba_acpi_init(void)
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
}
- return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
-}
-
-static void __exit toshiba_acpi_exit(void)
-{
- remove_device();
-
- if (toshiba_proc_dir)
- remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+ toshiba_backlight_device = backlight_device_register("toshiba",NULL,
+ NULL,
+ &toshiba_backlight_data);
+ if (IS_ERR(toshiba_backlight_device)) {
+ printk(KERN_ERR "Could not register toshiba backlight device\n");
+ toshiba_backlight_device = NULL;
+ toshiba_acpi_exit();
+ }
- return;
+ return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
}
module_init(toshiba_acpi_init);
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index f6cbc0b1bfd..55a76480749 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,7 @@
*/
#include <acpi/acpi.h>
+#include <acpi/acdebug.h>
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utalloc")
@@ -142,6 +143,14 @@ acpi_status acpi_ut_create_caches(void)
acpi_status acpi_ut_delete_caches(void)
{
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ char buffer[7];
+
+ if (acpi_gbl_display_final_mem_stats) {
+ ACPI_STRCPY(buffer, "MEMORY");
+ acpi_db_display_statistics(buffer);
+ }
+#endif
(void)acpi_os_delete_cache(acpi_gbl_namespace_cache);
acpi_gbl_namespace_cache = NULL;
diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c
index 1a1f8109159..870f6edeb5f 100644
--- a/drivers/acpi/utilities/utcache.c
+++ b/drivers/acpi/utilities/utcache.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -289,6 +289,14 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
ACPI_MEM_TRACKING(cache->total_allocated++);
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ if ((cache->total_allocated - cache->total_freed) >
+ cache->max_occupied) {
+ cache->max_occupied =
+ cache->total_allocated - cache->total_freed;
+ }
+#endif
+
/* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index 5e1a80d1bc3..84d529db0a6 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -719,6 +719,15 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
acpi_ut_add_reference(source_desc->reference.object);
break;
+ case ACPI_TYPE_REGION:
+ /*
+ * We copied the Region Handler, so we now must add a reference
+ */
+ if (dest_desc->region.handler) {
+ acpi_ut_add_reference(dest_desc->region.handler);
+ }
+ break;
+
default:
/* Nothing to do for other simple objects */
break;
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index bb1eaf9aa65..61ad4f2daee 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -180,8 +180,8 @@ acpi_ut_debug_print(u32 requested_debug_level,
if (thread_id != acpi_gbl_prev_thread_id) {
if (ACPI_LV_THREADS & acpi_dbg_level) {
acpi_os_printf
- ("\n**** Context Switch from TID %X to TID %X ****\n\n",
- (u32) acpi_gbl_prev_thread_id, (u32) thread_id);
+ ("\n**** Context Switch from TID %lX to TID %lX ****\n\n",
+ (unsigned long)acpi_gbl_prev_thread_id, (unsigned long)thread_id);
}
acpi_gbl_prev_thread_id = thread_id;
@@ -194,7 +194,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
acpi_os_printf("%8s-%04ld ", module_name, line_number);
if (ACPI_LV_THREADS & acpi_dbg_level) {
- acpi_os_printf("[%04lX] ", thread_id);
+ acpi_os_printf("[%04lX] ", (unsigned long)thread_id);
}
acpi_os_printf("[%02ld] %-22.22s: ",
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index 9d3f1149ba2..f777cebdc46 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -158,16 +158,20 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
"***** Mutex %p, OS Mutex %p\n",
object, object->mutex.os_mutex));
- if (object->mutex.os_mutex != ACPI_GLOBAL_LOCK) {
- acpi_ex_unlink_mutex(object);
- acpi_os_delete_mutex(object->mutex.os_mutex);
- } else {
- /* Global Lock "mutex" is actually a counting semaphore */
+ if (object->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+
+ /* Global Lock has extra semaphore */
(void)
acpi_os_delete_semaphore
(acpi_gbl_global_lock_semaphore);
acpi_gbl_global_lock_semaphore = NULL;
+
+ acpi_os_delete_mutex(object->mutex.os_mutex);
+ acpi_gbl_global_lock_mutex = NULL;
+ } else {
+ acpi_ex_unlink_mutex(object);
+ acpi_os_delete_mutex(object->mutex.os_mutex);
}
break;
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index d6d7121583c..13d5879cd98 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 014030af8b5..af33358a964 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,89 +46,9 @@
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
+ACPI_EXPORT_SYMBOL(acpi_gbl_FADT)
#define _COMPONENT ACPI_UTILITIES
-ACPI_MODULE_NAME("utglobal")
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_format_exception
- *
- * PARAMETERS: Status - The acpi_status code to be formatted
- *
- * RETURN: A string containing the exception text. A valid pointer is
- * always returned.
- *
- * DESCRIPTION: This function translates an ACPI exception into an ASCII string.
- *
- ******************************************************************************/
-const char *acpi_format_exception(acpi_status status)
-{
- acpi_status sub_status;
- const char *exception = NULL;
-
- ACPI_FUNCTION_ENTRY();
-
- /*
- * Status is composed of two parts, a "type" and an actual code
- */
- sub_status = (status & ~AE_CODE_MASK);
-
- switch (status & AE_CODE_MASK) {
- case AE_CODE_ENVIRONMENTAL:
-
- if (sub_status <= AE_CODE_ENV_MAX) {
- exception = acpi_gbl_exception_names_env[sub_status];
- }
- break;
-
- case AE_CODE_PROGRAMMER:
-
- if (sub_status <= AE_CODE_PGM_MAX) {
- exception =
- acpi_gbl_exception_names_pgm[sub_status - 1];
- }
- break;
-
- case AE_CODE_ACPI_TABLES:
-
- if (sub_status <= AE_CODE_TBL_MAX) {
- exception =
- acpi_gbl_exception_names_tbl[sub_status - 1];
- }
- break;
-
- case AE_CODE_AML:
-
- if (sub_status <= AE_CODE_AML_MAX) {
- exception =
- acpi_gbl_exception_names_aml[sub_status - 1];
- }
- break;
-
- case AE_CODE_CONTROL:
-
- if (sub_status <= AE_CODE_CTRL_MAX) {
- exception =
- acpi_gbl_exception_names_ctrl[sub_status - 1];
- }
- break;
-
- default:
- break;
- }
-
- if (!exception) {
-
- /* Exception code was not recognized */
-
- ACPI_ERROR((AE_INFO,
- "Unknown exception code: 0x%8.8X", status));
-
- exception = "UNKNOWN_STATUS_CODE";
- }
-
- return (ACPI_CAST_PTR(const char, exception));
-}
+ ACPI_MODULE_NAME("utglobal")
/*******************************************************************************
*
@@ -163,8 +83,6 @@ u32 acpi_gbl_startup_flags = 0;
u8 acpi_gbl_shutdown = TRUE;
-const u8 acpi_gbl_decode_to8bit[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
-
const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
"\\_S0_",
"\\_S1_",
@@ -183,10 +101,45 @@ const char *acpi_gbl_highest_dstate_names[4] = {
/*******************************************************************************
*
- * Namespace globals
+ * FUNCTION: acpi_format_exception
+ *
+ * PARAMETERS: Status - The acpi_status code to be formatted
+ *
+ * RETURN: A string containing the exception text. A valid pointer is
+ * always returned.
+ *
+ * DESCRIPTION: This function translates an ACPI exception into an ASCII string
+ * It is here instead of utxface.c so it is always present.
*
******************************************************************************/
+const char *acpi_format_exception(acpi_status status)
+{
+ const char *exception = NULL;
+
+ ACPI_FUNCTION_ENTRY();
+
+ exception = acpi_ut_validate_exception(status);
+ if (!exception) {
+
+ /* Exception code was not recognized */
+
+ ACPI_ERROR((AE_INFO,
+ "Unknown exception code: 0x%8.8X", status));
+
+ exception = "UNKNOWN_STATUS_CODE";
+ }
+
+ return (ACPI_CAST_PTR(const char, exception));
+}
+
+ACPI_EXPORT_SYMBOL(acpi_format_exception)
+
+/*******************************************************************************
+ *
+ * Namespace globals
+ *
+ ******************************************************************************/
/*
* Predefined ACPI Names (Built-in to the Interpreter)
*
@@ -280,53 +233,6 @@ char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position)
return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]);
}
-/*******************************************************************************
- *
- * Table name globals
- *
- * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes.
- * it is NOT an exhaustive list of all possible ACPI tables. All ACPI tables
- * that are not used by the subsystem are simply ignored.
- *
- * Do NOT add any table to this list that is not consumed directly by this
- * subsystem (No MADT, ECDT, SBST, etc.)
- *
- ******************************************************************************/
-
-struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1];
-
-struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1] = {
- /*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */
-
- /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof(RSDP_SIG) - 1,
- ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}
- ,
- /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void *)&acpi_gbl_DSDT,
- sizeof(DSDT_SIG) - 1,
- ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE |
- ACPI_TABLE_EXECUTABLE}
- ,
- /* FADT 2 */ {FADT_SIG, FADT_SIG, (void *)&acpi_gbl_FADT,
- sizeof(FADT_SIG) - 1,
- ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE}
- ,
- /* FACS 3 */ {FACS_SIG, FACS_SIG, (void *)&acpi_gbl_FACS,
- sizeof(FACS_SIG) - 1,
- ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE}
- ,
- /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, NULL, sizeof(PSDT_SIG) - 1,
- ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE |
- ACPI_TABLE_EXECUTABLE}
- ,
- /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, NULL, sizeof(SSDT_SIG) - 1,
- ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE |
- ACPI_TABLE_EXECUTABLE}
- ,
- /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, NULL, sizeof(RSDT_SIG) - 1,
- ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}
- ,
-};
-
/******************************************************************************
*
* Event and Hardware globals
@@ -612,7 +518,7 @@ char *acpi_ut_get_node_name(void *object)
/* Name must be a valid ACPI name */
if (!acpi_ut_valid_acpi_name(node->name.integer)) {
- node->name.integer = acpi_ut_repair_name(node->name.integer);
+ node->name.integer = acpi_ut_repair_name(node->name.ascii);
}
/* Return the name */
@@ -751,13 +657,6 @@ void acpi_ut_init_globals(void)
return;
}
- /* ACPI table structure */
-
- for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
- acpi_gbl_table_lists[i].next = NULL;
- acpi_gbl_table_lists[i].count = 0;
- }
-
/* Mutex locked flags */
for (i = 0; i < ACPI_NUM_MUTEX; i++) {
@@ -773,6 +672,7 @@ void acpi_ut_init_globals(void)
/* GPE support */
+ acpi_gpe_count = 0;
acpi_gbl_gpe_xrupt_list_head = NULL;
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
@@ -784,25 +684,15 @@ void acpi_ut_init_globals(void)
acpi_gbl_exception_handler = NULL;
acpi_gbl_init_handler = NULL;
- /* Global "typed" ACPI table pointers */
-
- acpi_gbl_RSDP = NULL;
- acpi_gbl_XSDT = NULL;
- acpi_gbl_FACS = NULL;
- acpi_gbl_FADT = NULL;
- acpi_gbl_DSDT = NULL;
-
/* Global Lock support */
acpi_gbl_global_lock_semaphore = NULL;
+ acpi_gbl_global_lock_mutex = NULL;
acpi_gbl_global_lock_acquired = FALSE;
- acpi_gbl_global_lock_thread_count = 0;
acpi_gbl_global_lock_handle = 0;
/* Miscellaneous variables */
- acpi_gbl_table_flags = ACPI_PHYSICAL_POINTER;
- acpi_gbl_rsdp_original_location = 0;
acpi_gbl_cm_single_step = FALSE;
acpi_gbl_db_terminate_threads = FALSE;
acpi_gbl_shutdown = FALSE;
@@ -837,8 +727,13 @@ void acpi_ut_init_globals(void)
acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX;
#endif
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ acpi_gbl_display_final_mem_stats = FALSE;
+#endif
+
return_VOID;
}
ACPI_EXPORT_SYMBOL(acpi_dbg_level)
ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
+ACPI_EXPORT_SYMBOL(acpi_gpe_count)
diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
index ff76055eb7d..ad3c0d0a5cf 100644
--- a/drivers/acpi/utilities/utinit.c
+++ b/drivers/acpi/utilities/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,119 +44,14 @@
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acevents.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utinit")
/* Local prototypes */
-static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset);
-
static void acpi_ut_terminate(void);
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_fadt_register_error
- *
- * PARAMETERS: register_name - Pointer to string identifying register
- * Value - Actual register contents value
- * Offset - Byte offset in the FADT
- *
- * RETURN: AE_BAD_VALUE
- *
- * DESCRIPTION: Display failure message
- *
- ******************************************************************************/
-
-static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset)
-{
-
- ACPI_WARNING((AE_INFO,
- "Invalid FADT value %s=%X at offset %X FADT=%p",
- register_name, value, offset, acpi_gbl_FADT));
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_ut_validate_fadt
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Validate various ACPI registers in the FADT
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_validate_fadt(void)
-{
-
- /*
- * Verify Fixed ACPI Description Table fields,
- * but don't abort on any problems, just display error
- */
- if (acpi_gbl_FADT->pm1_evt_len < 4) {
- acpi_ut_fadt_register_error("PM1_EVT_LEN",
- (u32) acpi_gbl_FADT->pm1_evt_len,
- ACPI_FADT_OFFSET(pm1_evt_len));
- }
-
- if (!acpi_gbl_FADT->pm1_cnt_len) {
- acpi_ut_fadt_register_error("PM1_CNT_LEN", 0,
- ACPI_FADT_OFFSET(pm1_cnt_len));
- }
-
- if (!acpi_gbl_FADT->xpm1a_evt_blk.address) {
- acpi_ut_fadt_register_error("X_PM1a_EVT_BLK", 0,
- ACPI_FADT_OFFSET(xpm1a_evt_blk.
- address));
- }
-
- if (!acpi_gbl_FADT->xpm1a_cnt_blk.address) {
- acpi_ut_fadt_register_error("X_PM1a_CNT_BLK", 0,
- ACPI_FADT_OFFSET(xpm1a_cnt_blk.
- address));
- }
-
- if (!acpi_gbl_FADT->xpm_tmr_blk.address) {
- acpi_ut_fadt_register_error("X_PM_TMR_BLK", 0,
- ACPI_FADT_OFFSET(xpm_tmr_blk.
- address));
- }
-
- if ((acpi_gbl_FADT->xpm2_cnt_blk.address &&
- !acpi_gbl_FADT->pm2_cnt_len)) {
- acpi_ut_fadt_register_error("PM2_CNT_LEN",
- (u32) acpi_gbl_FADT->pm2_cnt_len,
- ACPI_FADT_OFFSET(pm2_cnt_len));
- }
-
- if (acpi_gbl_FADT->pm_tm_len < 4) {
- acpi_ut_fadt_register_error("PM_TM_LEN",
- (u32) acpi_gbl_FADT->pm_tm_len,
- ACPI_FADT_OFFSET(pm_tm_len));
- }
-
- /* Length of GPE blocks must be a multiple of 2 */
-
- if (acpi_gbl_FADT->xgpe0_blk.address &&
- (acpi_gbl_FADT->gpe0_blk_len & 1)) {
- acpi_ut_fadt_register_error("(x)GPE0_BLK_LEN",
- (u32) acpi_gbl_FADT->gpe0_blk_len,
- ACPI_FADT_OFFSET(gpe0_blk_len));
- }
-
- if (acpi_gbl_FADT->xgpe1_blk.address &&
- (acpi_gbl_FADT->gpe1_blk_len & 1)) {
- acpi_ut_fadt_register_error("(x)GPE1_BLK_LEN",
- (u32) acpi_gbl_FADT->gpe1_blk_len,
- ACPI_FADT_OFFSET(gpe1_blk_len));
- }
-
- return (AE_OK);
-}
-
/******************************************************************************
*
* FUNCTION: acpi_ut_terminate
@@ -178,7 +73,6 @@ static void acpi_ut_terminate(void)
ACPI_FUNCTION_TRACE(ut_terminate);
- /* Free global tables, etc. */
/* Free global GPE blocks and related info structures */
gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
@@ -239,6 +133,10 @@ void acpi_ut_subsystem_shutdown(void)
acpi_ns_terminate();
+ /* Delete the ACPI tables */
+
+ acpi_tb_terminate();
+
/* Close the globals */
acpi_ut_terminate();
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c
index 19d74bedce2..0c56a0d20b2 100644
--- a/drivers/acpi/utilities/utmath.c
+++ b/drivers/acpi/utilities/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 6d8a8211be9..50133fffe42 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,78 @@ ACPI_MODULE_NAME("utmisc")
/*******************************************************************************
*
+ * FUNCTION: acpi_ut_validate_exception
+ *
+ * PARAMETERS: Status - The acpi_status code to be formatted
+ *
+ * RETURN: A string containing the exception text. NULL if exception is
+ * not valid.
+ *
+ * DESCRIPTION: This function validates and translates an ACPI exception into
+ * an ASCII string.
+ *
+ ******************************************************************************/
+const char *acpi_ut_validate_exception(acpi_status status)
+{
+ acpi_status sub_status;
+ const char *exception = NULL;
+
+ ACPI_FUNCTION_ENTRY();
+
+ /*
+ * Status is composed of two parts, a "type" and an actual code
+ */
+ sub_status = (status & ~AE_CODE_MASK);
+
+ switch (status & AE_CODE_MASK) {
+ case AE_CODE_ENVIRONMENTAL:
+
+ if (sub_status <= AE_CODE_ENV_MAX) {
+ exception = acpi_gbl_exception_names_env[sub_status];
+ }
+ break;
+
+ case AE_CODE_PROGRAMMER:
+
+ if (sub_status <= AE_CODE_PGM_MAX) {
+ exception =
+ acpi_gbl_exception_names_pgm[sub_status - 1];
+ }
+ break;
+
+ case AE_CODE_ACPI_TABLES:
+
+ if (sub_status <= AE_CODE_TBL_MAX) {
+ exception =
+ acpi_gbl_exception_names_tbl[sub_status - 1];
+ }
+ break;
+
+ case AE_CODE_AML:
+
+ if (sub_status <= AE_CODE_AML_MAX) {
+ exception =
+ acpi_gbl_exception_names_aml[sub_status - 1];
+ }
+ break;
+
+ case AE_CODE_CONTROL:
+
+ if (sub_status <= AE_CODE_CTRL_MAX) {
+ exception =
+ acpi_gbl_exception_names_ctrl[sub_status - 1];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return (ACPI_CAST_PTR(const char, exception));
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ut_is_aml_table
*
* PARAMETERS: Table - An ACPI table
@@ -62,14 +134,15 @@ ACPI_MODULE_NAME("utmisc")
* data tables that do not contain AML code.
*
******************************************************************************/
+
u8 acpi_ut_is_aml_table(struct acpi_table_header *table)
{
/* These are the only tables that contain executable AML */
- if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) ||
- ACPI_COMPARE_NAME(table->signature, PSDT_SIG) ||
- ACPI_COMPARE_NAME(table->signature, SSDT_SIG)) {
+ if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) ||
+ ACPI_COMPARE_NAME(table->signature, ACPI_SIG_PSDT) ||
+ ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) {
return (TRUE);
}
@@ -418,7 +491,7 @@ u32 acpi_ut_dword_byte_swap(u32 value)
void acpi_ut_set_integer_width(u8 revision)
{
- if (revision <= 1) {
+ if (revision < 2) {
/* 32-bit case */
@@ -582,26 +655,25 @@ u8 acpi_ut_valid_acpi_name(u32 name)
*
******************************************************************************/
-acpi_name acpi_ut_repair_name(acpi_name name)
+acpi_name acpi_ut_repair_name(char *name)
{
- char *name_ptr = ACPI_CAST_PTR(char, &name);
- char new_name[ACPI_NAME_SIZE];
acpi_native_uint i;
+ char new_name[ACPI_NAME_SIZE];
for (i = 0; i < ACPI_NAME_SIZE; i++) {
- new_name[i] = name_ptr[i];
+ new_name[i] = name[i];
/*
* Replace a bad character with something printable, yet technically
* still invalid. This prevents any collisions with existing "good"
* names in the namespace.
*/
- if (!acpi_ut_valid_acpi_char(name_ptr[i], i)) {
+ if (!acpi_ut_valid_acpi_char(name[i], i)) {
new_name[i] = '*';
}
}
- return (*ACPI_CAST_PTR(u32, new_name));
+ return (*(u32 *) new_name);
}
/*******************************************************************************
@@ -996,9 +1068,13 @@ acpi_ut_info(char *module_name, u32 line_number, char *format, ...)
{
va_list args;
- acpi_os_printf("ACPI (%s-%04d): ", module_name, line_number);
+ /*
+ * Removed module_name, line_number, and acpica version, not needed
+ * for info output
+ */
+ acpi_os_printf("ACPI: ");
va_start(args, format);
acpi_os_vprintf(format, args);
- acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+ acpi_os_printf("\n");
}
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index c39062a047c..cbad2ef5987 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -243,23 +243,24 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
#endif
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Thread %X attempting to acquire Mutex [%s]\n",
- (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id)));
+ "Thread %lX attempting to acquire Mutex [%s]\n",
+ (unsigned long) this_thread_id,
+ acpi_ut_get_mutex_name(mutex_id)));
status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
ACPI_WAIT_FOREVER);
if (ACPI_SUCCESS(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Thread %X acquired Mutex [%s]\n",
- (u32) this_thread_id,
+ "Thread %lX acquired Mutex [%s]\n",
+ (unsigned long) this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
acpi_gbl_mutex_info[mutex_id].use_count++;
acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id;
} else {
ACPI_EXCEPTION((AE_INFO, status,
- "Thread %X could not acquire Mutex [%X]",
- (u32) this_thread_id, mutex_id));
+ "Thread %lX could not acquire Mutex [%X]",
+ (unsigned long) this_thread_id, mutex_id));
}
return (status);
@@ -285,7 +286,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
this_thread_id = acpi_os_get_thread_id();
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Thread %X releasing Mutex [%s]\n", (u32) this_thread_id,
+ "Thread %lX releasing Mutex [%s]\n",
+ (unsigned long) this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
if (mutex_id > ACPI_MAX_MUTEX) {
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c
index ba7d8ac702d..4696124759e 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/utilities/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c
index 5a2de92831d..e8fe1ba6cc2 100644
--- a/drivers/acpi/utilities/utresrc.c
+++ b/drivers/acpi/utilities/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c
index eaa13d05c85..edcaafad0a3 100644
--- a/drivers/acpi/utilities/utstate.c
+++ b/drivers/acpi/utilities/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
index 3538f69c82a..de3276f4f46 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/utilities/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -67,6 +67,7 @@ acpi_status acpi_initialize_subsystem(void)
ACPI_FUNCTION_TRACE(acpi_initialize_subsystem);
+ acpi_gbl_startup_flags = ACPI_SUBSYSTEM_INITIALIZE;
ACPI_DEBUG_EXEC(acpi_ut_init_stack_ptr_trace());
/* Initialize the OS-Dependent layer */
@@ -127,20 +128,6 @@ acpi_status acpi_enable_subsystem(u32 flags)
ACPI_FUNCTION_TRACE(acpi_enable_subsystem);
- /*
- * We must initialize the hardware before we can enable ACPI.
- * The values from the FADT are validated here.
- */
- if (!(flags & ACPI_NO_HARDWARE_INIT)) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "[Init] Initializing ACPI hardware\n"));
-
- status = acpi_hw_initialize();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
/* Enable ACPI mode */
if (!(flags & ACPI_NO_ACPI_ENABLE)) {
@@ -398,7 +385,6 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
{
struct acpi_system_info *info_ptr;
acpi_status status;
- u32 i;
ACPI_FUNCTION_TRACE(acpi_get_system_info);
@@ -431,9 +417,7 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
/* Timer resolution - 24 or 32 bits */
- if (!acpi_gbl_FADT) {
- info_ptr->timer_resolution = 0;
- } else if (acpi_gbl_FADT->tmr_val_ext == 0) {
+ if (acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) {
info_ptr->timer_resolution = 24;
} else {
info_ptr->timer_resolution = 32;
@@ -449,13 +433,6 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
info_ptr->debug_layer = acpi_dbg_layer;
info_ptr->debug_level = acpi_dbg_level;
- /* Current status of the ACPI tables, per table type */
-
- info_ptr->num_table_types = ACPI_TABLE_ID_MAX + 1;
- for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
- info_ptr->table_info[i].count = acpi_gbl_table_lists[i].count;
- }
-
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index d0d84c43a9d..68a809fa7b1 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -83,7 +83,7 @@ acpi_extract_package(union acpi_object *package,
return AE_BAD_DATA;
}
- format_string = (char *)format->pointer;
+ format_string = format->pointer;
/*
* Calculate size_required.
@@ -262,11 +262,10 @@ acpi_evaluate_integer(acpi_handle handle,
if (!data)
return AE_BAD_PARAMETER;
- element = kmalloc(sizeof(union acpi_object), irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
+ element = kzalloc(sizeof(union acpi_object), irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
if (!element)
return AE_NO_MEMORY;
- memset(element, 0, sizeof(union acpi_object));
buffer.length = sizeof(union acpi_object);
buffer.pointer = element;
status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
@@ -321,12 +320,11 @@ acpi_evaluate_string(acpi_handle handle,
return AE_BAD_DATA;
}
- *data = kmalloc(element->string.length + 1, GFP_KERNEL);
+ *data = kzalloc(element->string.length + 1, GFP_KERNEL);
if (!data) {
printk(KERN_ERR PREFIX "Memory allocation\n");
return -ENOMEM;
}
- memset(*data, 0, element->string.length + 1);
memcpy(*data, element->string.pointer, element->string.length);
@@ -361,7 +359,7 @@ acpi_evaluate_reference(acpi_handle handle,
if (ACPI_FAILURE(status))
goto end;
- package = (union acpi_object *)buffer.pointer;
+ package = buffer.pointer;
if ((buffer.length == 0) || !package) {
printk(KERN_ERR PREFIX "No return object (len %X ptr %p)\n",
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 56666a98247..e0b97add8c6 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
* Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
+ * Copyright (C) 2006 Thomas Tuttle <linux-kernel@ttuttle.net>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -31,6 +32,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/backlight.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
@@ -47,14 +49,20 @@
#define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT 0x83
#define ACPI_VIDEO_NOTIFY_PREV_OUTPUT 0x84
-#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x82
-#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x83
-#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x84
-#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x85
-#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x86
+#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x85
+#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86
+#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
+#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88
+#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89
#define ACPI_VIDEO_HEAD_INVALID (~0u - 1)
#define ACPI_VIDEO_HEAD_END (~0u)
+#define MAX_NAME_LEN 20
+
+#define ACPI_VIDEO_DISPLAY_CRT 1
+#define ACPI_VIDEO_DISPLAY_TV 2
+#define ACPI_VIDEO_DISPLAY_DVI 3
+#define ACPI_VIDEO_DISPLAY_LCD 4
#define _COMPONENT ACPI_VIDEO_COMPONENT
ACPI_MODULE_NAME("acpi_video")
@@ -65,16 +73,14 @@ MODULE_LICENSE("GPL");
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device, int type);
-static int acpi_video_bus_match(struct acpi_device *device,
- struct acpi_driver *driver);
static struct acpi_driver acpi_video_bus = {
.name = ACPI_VIDEO_DRIVER_NAME,
.class = ACPI_VIDEO_CLASS,
+ .ids = ACPI_VIDEO_HID,
.ops = {
.add = acpi_video_bus_add,
.remove = acpi_video_bus_remove,
- .match = acpi_video_bus_match,
},
};
@@ -132,20 +138,21 @@ struct acpi_video_device_flags {
u8 crt:1;
u8 lcd:1;
u8 tvout:1;
+ u8 dvi:1;
u8 bios:1;
u8 unknown:1;
- u8 reserved:3;
+ u8 reserved:2;
};
struct acpi_video_device_cap {
u8 _ADR:1; /*Return the unique ID */
u8 _BCL:1; /*Query list of brightness control levels supported */
u8 _BCM:1; /*Set the brightness level */
+ u8 _BQC:1; /* Get current brightness level */
u8 _DDC:1; /*Return the EDID for this device */
u8 _DCS:1; /*Return status of output device */
u8 _DGS:1; /*Query graphics state */
u8 _DSS:1; /*Device state set */
- u8 _reserved:1;
};
struct acpi_video_device_brightness {
@@ -162,6 +169,8 @@ struct acpi_video_device {
struct acpi_video_bus *video;
struct acpi_device *dev;
struct acpi_video_device_brightness *brightness;
+ struct backlight_device *backlight;
+ struct backlight_properties *data;
};
/* bus */
@@ -256,11 +265,35 @@ static void acpi_video_device_bind(struct acpi_video_bus *video,
struct acpi_video_device *device);
static int acpi_video_device_enumerate(struct acpi_video_bus *video);
static int acpi_video_switch_output(struct acpi_video_bus *video, int event);
+static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
+ int level);
+static int acpi_video_device_lcd_get_level_current(
+ struct acpi_video_device *device,
+ unsigned long *level);
static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static void acpi_video_switch_brightness(struct acpi_video_device *device,
int event);
+/*backlight device sysfs support*/
+static int acpi_video_get_brightness(struct backlight_device *bd)
+{
+ unsigned long cur_level;
+ struct acpi_video_device *vd =
+ (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+ acpi_video_device_lcd_get_level_current(vd, &cur_level);
+ return (int) cur_level;
+}
+
+static int acpi_video_set_brightness(struct backlight_device *bd)
+{
+ int request_level = bd->props->brightness;
+ struct acpi_video_device *vd =
+ (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+ acpi_video_device_lcd_set_level(vd, request_level);
+ return 0;
+}
+
/* --------------------------------------------------------------------------
Video Management
-------------------------------------------------------------------------- */
@@ -386,7 +419,7 @@ acpi_video_device_EDID(struct acpi_video_device *device,
if (ACPI_FAILURE(status))
return -ENODEV;
- obj = (union acpi_object *)buffer.pointer;
+ obj = buffer.pointer;
if (obj && obj->type == ACPI_TYPE_BUFFER)
*edid = obj;
@@ -498,6 +531,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
acpi_integer status;
acpi_handle h_dummy1;
int i;
+ u32 max_level = 0;
union acpi_object *obj = NULL;
struct acpi_video_device_brightness *br = NULL;
@@ -513,6 +547,8 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
device->cap._BCM = 1;
}
+ if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1)))
+ device->cap._BQC = 1;
if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
device->cap._DDC = 1;
}
@@ -532,11 +568,10 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
int count = 0;
union acpi_object *o;
- br = kmalloc(sizeof(*br), GFP_KERNEL);
+ br = kzalloc(sizeof(*br), GFP_KERNEL);
if (!br) {
printk(KERN_ERR "can't allocate memory\n");
} else {
- memset(br, 0, sizeof(*br));
br->levels = kmalloc(obj->package.count *
sizeof *(br->levels), GFP_KERNEL);
if (!br->levels)
@@ -550,6 +585,8 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
continue;
}
br->levels[count] = (u32) o->integer.value;
+ if (br->levels[count] > max_level)
+ max_level = br->levels[count];
count++;
}
out:
@@ -568,6 +605,37 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
kfree(obj);
+ if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
+ unsigned long tmp;
+ static int count = 0;
+ char *name;
+ struct backlight_properties *acpi_video_data;
+
+ name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+ if (!name)
+ return;
+
+ acpi_video_data = kzalloc(
+ sizeof(struct backlight_properties),
+ GFP_KERNEL);
+ if (!acpi_video_data){
+ kfree(name);
+ return;
+ }
+ acpi_video_data->owner = THIS_MODULE;
+ acpi_video_data->get_brightness =
+ acpi_video_get_brightness;
+ acpi_video_data->update_status =
+ acpi_video_set_brightness;
+ sprintf(name, "acpi_video%d", count++);
+ device->data = acpi_video_data;
+ acpi_video_data->max_brightness = max_level;
+ acpi_video_device_lcd_get_level_current(device, &tmp);
+ acpi_video_data->brightness = (int)tmp;
+ device->backlight = backlight_device_register(name,
+ NULL, device, acpi_video_data);
+ kfree(name);
+ }
return;
}
@@ -654,8 +722,7 @@ static struct proc_dir_entry *acpi_video_dir;
static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_video_device *dev =
- (struct acpi_video_device *)seq->private;
+ struct acpi_video_device *dev = seq->private;
if (!dev)
@@ -669,6 +736,8 @@ static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "LCD\n");
else if (dev->flags.tvout)
seq_printf(seq, "TVOUT\n");
+ else if (dev->flags.dvi)
+ seq_printf(seq, "DVI\n");
else
seq_printf(seq, "UNKNOWN\n");
@@ -688,8 +757,7 @@ acpi_video_device_info_open_fs(struct inode *inode, struct file *file)
static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
{
int status;
- struct acpi_video_device *dev =
- (struct acpi_video_device *)seq->private;
+ struct acpi_video_device *dev = seq->private;
unsigned long state;
@@ -727,8 +795,8 @@ acpi_video_device_write_state(struct file *file,
size_t count, loff_t * data)
{
int status;
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_video_device *dev = (struct acpi_video_device *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_video_device *dev = m->private;
char str[12] = { 0 };
u32 state = 0;
@@ -754,8 +822,7 @@ acpi_video_device_write_state(struct file *file,
static int
acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_video_device *dev =
- (struct acpi_video_device *)seq->private;
+ struct acpi_video_device *dev = seq->private;
int i;
@@ -784,8 +851,8 @@ acpi_video_device_write_brightness(struct file *file,
const char __user * buffer,
size_t count, loff_t * data)
{
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_video_device *dev = (struct acpi_video_device *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_video_device *dev = m->private;
char str[4] = { 0 };
unsigned int level = 0;
int i;
@@ -817,8 +884,7 @@ acpi_video_device_write_brightness(struct file *file,
static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_video_device *dev =
- (struct acpi_video_device *)seq->private;
+ struct acpi_video_device *dev = seq->private;
int status;
int i;
union acpi_object *edid = NULL;
@@ -866,7 +932,7 @@ static int acpi_video_device_add_fs(struct acpi_device *device)
if (!device)
return -ENODEV;
- vid_dev = (struct acpi_video_device *)acpi_driver_data(device);
+ vid_dev = acpi_driver_data(device);
if (!vid_dev)
return -ENODEV;
@@ -931,7 +997,7 @@ static int acpi_video_device_remove_fs(struct acpi_device *device)
{
struct acpi_video_device *vid_dev;
- vid_dev = (struct acpi_video_device *)acpi_driver_data(device);
+ vid_dev = acpi_driver_data(device);
if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
return -ENODEV;
@@ -950,7 +1016,7 @@ static int acpi_video_device_remove_fs(struct acpi_device *device)
/* video bus */
static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
+ struct acpi_video_bus *video = seq->private;
if (!video)
@@ -975,7 +1041,7 @@ static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file)
static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
+ struct acpi_video_bus *video = seq->private;
if (!video)
@@ -995,7 +1061,7 @@ static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file)
static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
+ struct acpi_video_bus *video = seq->private;
unsigned long options;
int status;
@@ -1033,7 +1099,7 @@ acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file)
static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
+ struct acpi_video_bus *video = seq->private;
int status;
unsigned long id;
@@ -1054,7 +1120,7 @@ static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
+ struct acpi_video_bus *video = seq->private;
seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting);
@@ -1079,8 +1145,8 @@ acpi_video_bus_write_POST(struct file *file,
size_t count, loff_t * data)
{
int status;
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_video_bus *video = (struct acpi_video_bus *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_video_bus *video = m->private;
char str[12] = { 0 };
unsigned long opt, options;
@@ -1119,8 +1185,8 @@ acpi_video_bus_write_DOS(struct file *file,
size_t count, loff_t * data)
{
int status;
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_video_bus *video = (struct acpi_video_bus *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_video_bus *video = m->private;
char str[12] = { 0 };
unsigned long opt;
@@ -1150,7 +1216,7 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
struct acpi_video_bus *video;
- video = (struct acpi_video_bus *)acpi_driver_data(device);
+ video = acpi_driver_data(device);
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
@@ -1226,7 +1292,7 @@ static int acpi_video_bus_remove_fs(struct acpi_device *device)
struct acpi_video_bus *video;
- video = (struct acpi_video_bus *)acpi_driver_data(device);
+ video = acpi_driver_data(device);
if (acpi_device_dir(device)) {
remove_proc_entry("info", acpi_device_dir(device));
@@ -1246,6 +1312,16 @@ static int acpi_video_bus_remove_fs(struct acpi_device *device)
-------------------------------------------------------------------------- */
/* device interface */
+static struct acpi_video_device_attrib*
+acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
+{
+ int count;
+
+ for(count = 0; count < video->attached_count; count++)
+ if((video->attached_array[count].value.int_val & 0xffff) == device_id)
+ return &(video->attached_array[count].value.attrib);
+ return NULL;
+}
static int
acpi_video_bus_get_one_device(struct acpi_device *device,
@@ -1254,7 +1330,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
unsigned long device_id;
int status;
struct acpi_video_device *data;
-
+ struct acpi_video_device_attrib* attribute;
if (!device || !video)
return -EINVAL;
@@ -1263,12 +1339,10 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
if (ACPI_SUCCESS(status)) {
- data = kmalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
+ data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
if (!data)
return -ENOMEM;
- memset(data, 0, sizeof(struct acpi_video_device));
-
strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
acpi_driver_data(device) = data;
@@ -1277,20 +1351,30 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
data->video = video;
data->dev = device;
- switch (device_id & 0xffff) {
- case 0x0100:
- data->flags.crt = 1;
- break;
- case 0x0400:
- data->flags.lcd = 1;
- break;
- case 0x0200:
- data->flags.tvout = 1;
- break;
- default:
+ attribute = acpi_video_get_device_attr(video, device_id);
+
+ if((attribute != NULL) && attribute->device_id_scheme) {
+ switch (attribute->display_type) {
+ case ACPI_VIDEO_DISPLAY_CRT:
+ data->flags.crt = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_TV:
+ data->flags.tvout = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_DVI:
+ data->flags.dvi = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_LCD:
+ data->flags.lcd = 1;
+ break;
+ default:
+ data->flags.unknown = 1;
+ break;
+ }
+ if(attribute->bios_can_detect)
+ data->flags.bios = 1;
+ } else
data->flags.unknown = 1;
- break;
- }
acpi_video_device_bind(video, data);
acpi_video_device_find_cap(data);
@@ -1403,7 +1487,7 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
return status;
}
- dod = (union acpi_object *)buffer.pointer;
+ dod = buffer.pointer;
if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data"));
status = -EFAULT;
@@ -1426,7 +1510,7 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
count = 0;
for (i = 0; i < dod->package.count; i++) {
- obj = (union acpi_object *)&dod->package.elements[i];
+ obj = &dod->package.elements[i];
if (obj->type != ACPI_TYPE_INTEGER) {
printk(KERN_ERR PREFIX "Invalid _DOD data\n");
@@ -1509,8 +1593,34 @@ static int
acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event)
{
- /*Fix me */
- return level_current;
+ int min, max, min_above, max_below, i, l;
+ max = max_below = 0;
+ min = min_above = 255;
+ for (i = 0; i < device->brightness->count; i++) {
+ l = device->brightness->levels[i];
+ if (l < min)
+ min = l;
+ if (l > max)
+ max = l;
+ if (l < min_above && l > level_current)
+ min_above = l;
+ if (l > max_below && l < level_current)
+ max_below = l;
+ }
+
+ switch (event) {
+ case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:
+ return (level_current < max) ? min_above : min;
+ case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:
+ return (level_current < max) ? min_above : max;
+ case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:
+ return (level_current > min) ? max_below : min;
+ case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS:
+ case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:
+ return 0;
+ default:
+ return level_current;
+ }
}
static void
@@ -1568,7 +1678,10 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
status = acpi_remove_notify_handler(device->dev->handle,
ACPI_DEVICE_NOTIFY,
acpi_video_device_notify);
-
+ if (device->backlight){
+ backlight_device_unregister(device->backlight);
+ kfree(device->data);
+ }
return 0;
}
@@ -1612,7 +1725,7 @@ static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
{
- struct acpi_video_bus *video = (struct acpi_video_bus *)data;
+ struct acpi_video_bus *video = data;
struct acpi_device *device = NULL;
printk("video bus notify\n");
@@ -1654,12 +1767,9 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
{
- struct acpi_video_device *video_device =
- (struct acpi_video_device *)data;
+ struct acpi_video_device *video_device = data;
struct acpi_device *device = NULL;
-
- printk("video device notify\n");
if (!video_device)
return;
@@ -1696,10 +1806,9 @@ static int acpi_video_bus_add(struct acpi_device *device)
if (!device)
return -EINVAL;
- video = kmalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
+ video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
if (!video)
return -ENOMEM;
- memset(video, 0, sizeof(struct acpi_video_bus));
video->device = device;
strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
@@ -1757,7 +1866,7 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- video = (struct acpi_video_bus *)acpi_driver_data(device);
+ video = acpi_driver_data(device);
acpi_video_bus_stop_devices(video);
@@ -1774,39 +1883,6 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
return 0;
}
-static int
-acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver)
-{
- acpi_handle h_dummy1;
- acpi_handle h_dummy2;
- acpi_handle h_dummy3;
-
-
- if (!device || !driver)
- return -EINVAL;
-
- /* Since there is no HID, CID for ACPI Video drivers, we have
- * to check well known required nodes for each feature we support.
- */
-
- /* Does this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
- return 0;
-
- /* Does this device able to retrieve a video ROM ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
- return 0;
-
- /* Does this device able to configure which video head to be POSTed ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
- return 0;
-
- return -ENODEV;
-}
-
static int __init acpi_video_init(void)
{
int result = 0;
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 984ab284382..3747457fee7 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -19,6 +19,10 @@ config ATA
if ATA
+config ATA_NONSTANDARD
+ bool
+ default n
+
config SATA_AHCI
tristate "AHCI SATA support"
depends on PCI
@@ -37,12 +41,12 @@ config SATA_SVW
If unsure, say N.
config ATA_PIIX
- tristate "Intel PIIX/ICH SATA support"
+ tristate "Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support"
depends on PCI
help
- This option enables support for ICH5/6/7/8 Serial ATA.
- If PATA support was enabled previously, this enables
- support for select Intel PIIX/ICH PATA host controllers.
+ This option enables support for ICH5/6/7/8 Serial ATA
+ and support for PATA on the Intel ESB/ICH/PIIX3/PIIX4 series
+ host controllers.
If unsure, say N.
@@ -112,11 +116,14 @@ config SATA_SIL24
If unsure, say N.
config SATA_SIS
- tristate "SiS 964/180 SATA support"
+ tristate "SiS 964/965/966/180 SATA support"
depends on PCI
+ select PATA_SIS
help
- This option enables support for SiS Serial ATA 964/180.
-
+ This option enables support for SiS Serial ATA on
+ SiS 964/965/966/180 and Parallel ATA on SiS 180.
+ The PATA support for SiS 180 requires additionally to
+ enable the PATA_SIS driver in the config.
If unsure, say N.
config SATA_ULI
@@ -143,6 +150,12 @@ config SATA_VITESSE
If unsure, say N.
+config SATA_INIC162X
+ tristate "Initio 162x SATA support (HIGHLY EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for Initio 162x Serial ATA.
+
config SATA_INTEL_COMBINED
bool
depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX)
@@ -292,7 +305,7 @@ config PATA_ISAPNP
If unsure, say N.
config PATA_IT821X
- tristate "IT821x PATA support (Experimental)"
+ tristate "IT8211/2 PATA support (Experimental)"
depends on PCI && EXPERIMENTAL
help
This option enables support for the ITE 8211 and 8212
@@ -301,6 +314,15 @@ config PATA_IT821X
If unsure, say N.
+config PATA_IT8213
+ tristate "IT8213 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the ITE 821 PATA
+ controllers via the new ATA layer.
+
+ If unsure, say N.
+
config PATA_JMICRON
tristate "JMicron PATA support"
depends on PCI
@@ -337,6 +359,15 @@ config PATA_MARVELL
If unsure, say N.
+config PATA_MPC52xx
+ tristate "Freescale MPC52xx SoC internal IDE"
+ depends on PPC_MPC52xx
+ help
+ This option enables support for integrated IDE controller
+ of the Freescale MPC52xx SoC.
+
+ If unsure, say N.
+
config PATA_MPIIX
tristate "Intel PATA MPIIX support"
depends on PCI
@@ -381,7 +412,7 @@ config PATA_OPTI
If unsure, say N.
config PATA_OPTIDMA
- tristate "OPTI FireStar PATA support (Veyr Experimental)"
+ tristate "OPTI FireStar PATA support (Very Experimental)"
depends on PCI && EXPERIMENTAL
help
This option enables DMA/PIO support for the later OPTi
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index bc3d81ae757..cd096f0c78a 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_SATA_SX4) += sata_sx4.o
obj-$(CONFIG_SATA_NV) += sata_nv.o
obj-$(CONFIG_SATA_ULI) += sata_uli.o
obj-$(CONFIG_SATA_MV) += sata_mv.o
+obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
obj-$(CONFIG_PATA_ALI) += pata_ali.o
@@ -33,11 +34,13 @@ obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
obj-$(CONFIG_PATA_HPT3X3) += pata_hpt3x3.o
obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o
obj-$(CONFIG_PATA_IT821X) += pata_it821x.o
+obj-$(CONFIG_PATA_IT8213) += pata_it8213.o
obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
obj-$(CONFIG_PATA_OPTI) += pata_opti.o
obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
+obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o
obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index f36da488a2c..92cdb0c5171 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -45,7 +45,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#define DRV_NAME "ahci"
#define DRV_VERSION "2.0"
@@ -75,6 +74,7 @@ enum {
AHCI_CMD_CLR_BUSY = (1 << 10),
RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
+ RX_FIS_SDB = 0x58, /* offset of SDB FIS data */
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
board_ahci = 0,
@@ -165,9 +165,6 @@ enum {
PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
- /* hpriv->flags bits */
- AHCI_FLAG_MSI = (1 << 0),
-
/* ap->flags bits */
AHCI_FLAG_NO_NCQ = (1 << 24),
AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */
@@ -190,7 +187,6 @@ struct ahci_sg {
};
struct ahci_host_priv {
- unsigned long flags;
u32 cap; /* cache of HOST_CAP register */
u32 port_map; /* cache of HOST_PORTS_IMPL reg */
};
@@ -202,6 +198,10 @@ struct ahci_port_priv {
dma_addr_t cmd_tbl_dma;
void *rx_fis;
dma_addr_t rx_fis_dma;
+ /* for NCQ spurious interrupt analysis */
+ int ncq_saw_spurious_sdb_cnt;
+ unsigned int ncq_saw_d2h:1;
+ unsigned int ncq_saw_dmas:1;
};
static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
@@ -224,7 +224,6 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
static int ahci_port_resume(struct ata_port *ap);
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int ahci_pci_device_resume(struct pci_dev *pdev);
-static void ahci_remove_one (struct pci_dev *pdev);
static struct scsi_host_template ahci_sht = {
.module = THIS_MODULE,
@@ -261,6 +260,8 @@ static const struct ata_port_operations ahci_ops = {
.irq_handler = ahci_interrupt,
.irq_clear = ahci_irq_clear,
+ .irq_on = ata_dummy_irq_on,
+ .irq_ack = ata_dummy_irq_ack,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
@@ -292,6 +293,8 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.irq_handler = ahci_interrupt,
.irq_clear = ahci_irq_clear,
+ .irq_on = ata_dummy_irq_on,
+ .irq_ack = ata_dummy_irq_ack,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
@@ -361,7 +364,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ 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(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
@@ -402,6 +405,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */
{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */
{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */
@@ -418,7 +429,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* Generic, PCI class code for AHCI */
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
- 0x010601, 0xffffff, board_ahci },
+ PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
{ } /* terminate list */
};
@@ -428,9 +439,9 @@ static struct pci_driver ahci_pci_driver = {
.name = DRV_NAME,
.id_table = ahci_pci_tbl,
.probe = ahci_init_one,
+ .remove = ata_pci_remove_one,
.suspend = ahci_pci_device_suspend,
.resume = ahci_pci_device_resume,
- .remove = ahci_remove_one,
};
@@ -439,16 +450,12 @@ static inline int ahci_nr_ports(u32 cap)
return (cap & 0x1f) + 1;
}
-static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port)
+static inline void __iomem *ahci_port_base(void __iomem *base,
+ unsigned int port)
{
return base + 0x100 + (port * 0x80);
}
-static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port)
-{
- return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
-}
-
static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
{
unsigned int sc_reg;
@@ -462,7 +469,7 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
return 0xffffffffU;
}
- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -480,7 +487,7 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
return;
}
- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
}
static void ahci_start_engine(void __iomem *port_mmio)
@@ -578,35 +585,18 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap)
{
u32 cmd, scontrol;
- cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
-
- if (cap & HOST_CAP_SSC) {
- /* enable transitions to slumber mode */
- scontrol = readl(port_mmio + PORT_SCR_CTL);
- if ((scontrol & 0x0f00) > 0x100) {
- scontrol &= ~0xf00;
- writel(scontrol, port_mmio + PORT_SCR_CTL);
- }
-
- /* put device into slumber mode */
- writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD);
-
- /* wait for the transition to complete */
- ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER,
- PORT_CMD_ICC_SLUMBER, 1, 50);
- }
+ if (!(cap & HOST_CAP_SSS))
+ return;
- /* put device into listen mode */
- if (cap & HOST_CAP_SSS) {
- /* first set PxSCTL.DET to 0 */
- scontrol = readl(port_mmio + PORT_SCR_CTL);
- scontrol &= ~0xf;
- writel(scontrol, port_mmio + PORT_SCR_CTL);
+ /* put device into listen mode, first set PxSCTL.DET to 0 */
+ scontrol = readl(port_mmio + PORT_SCR_CTL);
+ scontrol &= ~0xf;
+ writel(scontrol, port_mmio + PORT_SCR_CTL);
- /* then set PxCMD.SUD to 0 */
- cmd &= ~PORT_CMD_SPIN_UP;
- writel(cmd, port_mmio + PORT_CMD);
- }
+ /* then set PxCMD.SUD to 0 */
+ cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
+ cmd &= ~PORT_CMD_SPIN_UP;
+ writel(cmd, port_mmio + PORT_CMD);
}
static void ahci_init_port(void __iomem *port_mmio, u32 cap,
@@ -645,8 +635,6 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
u32 cap_save, impl_save, tmp;
cap_save = readl(mmio + HOST_CAP);
- cap_save &= ( (1<<28) | (1<<17) );
- cap_save |= (1 << 27);
impl_save = readl(mmio + HOST_PORTS_IMPL);
/* global controller reset */
@@ -741,7 +729,7 @@ static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
static unsigned int ahci_dev_classify(struct ata_port *ap)
{
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ata_taskfile tf;
u32 tmp;
@@ -769,7 +757,7 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
static int ahci_clo(struct ata_port *ap)
{
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ahci_host_priv *hpriv = ap->host->private_data;
u32 tmp;
@@ -791,7 +779,7 @@ static int ahci_clo(struct ata_port *ap)
static int ahci_softreset(struct ata_port *ap, unsigned int *class)
{
struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
const u32 cmd_fis_len = 5; /* five dwords */
const char *reason = NULL;
@@ -899,7 +887,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
struct ahci_port_priv *pp = ap->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
int rc;
@@ -909,7 +897,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(ap->device, &tf);
- tf.command = 0xff;
+ tf.command = 0x80;
ata_tf_to_fis(&tf, d2h_fis, 0);
rc = sata_std_hardreset(ap, class);
@@ -927,7 +915,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
int rc;
@@ -952,7 +940,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
static void ahci_postreset(struct ata_port *ap, unsigned int *class)
{
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ap->ioaddr.cmd_addr;
u32 new_tmp, tmp;
ata_std_postreset(ap, class);
@@ -971,7 +959,7 @@ static void ahci_postreset(struct ata_port *ap, unsigned int *class)
static u8 ahci_check_status(struct ata_port *ap)
{
- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ void __iomem *mmio = ap->ioaddr.cmd_addr;
return readl(mmio + PORT_TFDATA) & 0xFF;
}
@@ -1117,11 +1105,12 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
static void ahci_host_intr(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
struct ata_eh_info *ehi = &ap->eh_info;
+ struct ahci_port_priv *pp = ap->private_data;
u32 status, qc_active;
- int rc;
+ int rc, known_irq = 0;
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
@@ -1148,17 +1137,53 @@ static void ahci_host_intr(struct ata_port *ap)
/* hmmm... a spurious interupt */
- /* some devices send D2H reg with I bit set during NCQ command phase */
- if (ap->sactive && (status & PORT_IRQ_D2H_REG_FIS))
+ /* if !NCQ, ignore. No modern ATA device has broken HSM
+ * implementation for non-NCQ commands.
+ */
+ if (!ap->sactive)
return;
- /* ignore interim PIO setup fis interrupts */
- if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS))
- return;
+ if (status & PORT_IRQ_D2H_REG_FIS) {
+ if (!pp->ncq_saw_d2h)
+ ata_port_printk(ap, KERN_INFO,
+ "D2H reg with I during NCQ, "
+ "this message won't be printed again\n");
+ pp->ncq_saw_d2h = 1;
+ known_irq = 1;
+ }
+
+ if (status & PORT_IRQ_DMAS_FIS) {
+ if (!pp->ncq_saw_dmas)
+ ata_port_printk(ap, KERN_INFO,
+ "DMAS FIS during NCQ, "
+ "this message won't be printed again\n");
+ pp->ncq_saw_dmas = 1;
+ known_irq = 1;
+ }
+
+ if (status & PORT_IRQ_SDB_FIS &&
+ pp->ncq_saw_spurious_sdb_cnt < 10) {
+ /* SDB FIS containing spurious completions might be
+ * dangerous, we need to know more about them. Print
+ * more of it.
+ */
+ const __le32 *f = pp->rx_fis + RX_FIS_SDB;
+
+ ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ "
+ "issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n",
+ readl(port_mmio + PORT_CMD_ISSUE),
+ readl(port_mmio + PORT_SCR_ACT),
+ le32_to_cpu(f[0]), le32_to_cpu(f[1]),
+ pp->ncq_saw_spurious_sdb_cnt < 10 ?
+ "" : ", shutting up");
+
+ pp->ncq_saw_spurious_sdb_cnt++;
+ known_irq = 1;
+ }
- if (ata_ratelimit())
+ if (!known_irq)
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
- "(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
+ "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
status, ap->active_tag, ap->sactive);
}
@@ -1178,7 +1203,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
VPRINTK("ENTER\n");
hpriv = host->private_data;
- mmio = host->mmio_base;
+ mmio = host->iomap[AHCI_PCI_BAR];
/* sigh. 0xffffffff is a valid return from h/w */
irq_stat = readl(mmio + HOST_IRQ_STAT);
@@ -1223,7 +1248,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ap->ioaddr.cmd_addr;
if (qc->tf.protocol == ATA_PROT_NCQ)
writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1235,7 +1260,7 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
static void ahci_freeze(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
/* turn IRQ off */
@@ -1244,14 +1269,14 @@ static void ahci_freeze(struct ata_port *ap)
static void ahci_thaw(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
u32 tmp;
/* clear IRQ */
tmp = readl(port_mmio + PORT_IRQ_STAT);
writel(tmp, port_mmio + PORT_IRQ_STAT);
- writel(1 << ap->id, mmio + HOST_IRQ_STAT);
+ writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
/* turn IRQ back on */
writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
@@ -1259,7 +1284,7 @@ static void ahci_thaw(struct ata_port *ap)
static void ahci_error_handler(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
@@ -1275,7 +1300,7 @@ static void ahci_error_handler(struct ata_port *ap)
static void ahci_vt8251_error_handler(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
@@ -1292,7 +1317,7 @@ static void ahci_vt8251_error_handler(struct ata_port *ap)
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
if (qc->flags & ATA_QCFLAG_FAILED)
@@ -1309,7 +1334,7 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
const char *emsg = NULL;
int rc;
@@ -1330,7 +1355,7 @@ static int ahci_port_resume(struct ata_port *ap)
{
struct ahci_port_priv *pp = ap->private_data;
struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
ahci_power_up(port_mmio, hpriv->cap);
@@ -1342,7 +1367,7 @@ static int ahci_port_resume(struct ata_port *ap)
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
u32 ctl;
if (mesg.event == PM_EVENT_SUSPEND) {
@@ -1363,10 +1388,12 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
struct ahci_host_priv *hpriv = host->private_data;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
int rc;
- ata_pci_device_do_resume(pdev);
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_reset_controller(mmio, pdev);
@@ -1387,29 +1414,24 @@ static int ahci_port_start(struct ata_port *ap)
struct device *dev = ap->host->dev;
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
void *mem;
dma_addr_t mem_dma;
int rc;
- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
- memset(pp, 0, sizeof(*pp));
rc = ata_pad_alloc(ap, dev);
- if (rc) {
- kfree(pp);
+ if (rc)
return rc;
- }
- mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
- if (!mem) {
- ata_pad_free(ap, dev);
- kfree(pp);
+ mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
+ GFP_KERNEL);
+ if (!mem)
return -ENOMEM;
- }
memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
/*
@@ -1451,10 +1473,8 @@ static int ahci_port_start(struct ata_port *ap)
static void ahci_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host->dev;
struct ahci_host_priv *hpriv = ap->host->private_data;
- struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
const char *emsg = NULL;
int rc;
@@ -1463,19 +1483,13 @@ static void ahci_port_stop(struct ata_port *ap)
rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
if (rc)
ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
-
- ap->private_data = NULL;
- dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
- pp->cmd_slot, pp->cmd_slot_dma);
- ata_pad_free(ap, dev);
- kfree(pp);
}
-static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
+static void ahci_setup_port(struct ata_ioports *port, void __iomem *base,
unsigned int port_idx)
{
VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
- base = ahci_port_base_ul(base, port_idx);
+ base = ahci_port_base(base, port_idx);
VPRINTK("base now==0x%lx\n", base);
port->cmd_addr = base;
@@ -1488,7 +1502,7 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
{
struct ahci_host_priv *hpriv = probe_ent->private_data;
struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- void __iomem *mmio = probe_ent->mmio_base;
+ void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
unsigned int i, cap_n_ports, using_dac;
int rc;
@@ -1555,7 +1569,7 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
}
for (i = 0; i < probe_ent->n_ports; i++)
- ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i);
+ ahci_setup_port(&probe_ent->port[i], mmio, i);
ahci_init_controller(mmio, pdev, probe_ent->n_ports,
probe_ent->port_flags, hpriv);
@@ -1569,7 +1583,7 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
{
struct ahci_host_priv *hpriv = probe_ent->private_data;
struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- void __iomem *mmio = probe_ent->mmio_base;
+ void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
u32 vers, cap, impl, speed;
const char *speed_s;
u16 cc;
@@ -1588,11 +1602,11 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
speed_s = "?";
pci_read_config_word(pdev, 0x0a, &cc);
- if (cc == 0x0101)
+ if (cc == PCI_CLASS_STORAGE_IDE)
scc_s = "IDE";
- else if (cc == 0x0106)
+ else if (cc == PCI_CLASS_STORAGE_SATA)
scc_s = "SATA";
- else if (cc == 0x0104)
+ else if (cc == PCI_CLASS_STORAGE_RAID)
scc_s = "RAID";
else
scc_s = "unknown";
@@ -1636,15 +1650,13 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
);
}
-static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- struct ahci_host_priv *hpriv;
- unsigned long base;
- void __iomem *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data;
- int have_msi, pci_dev_busy = 0;
+ struct device *dev = &pdev->dev;
+ struct ata_probe_ent *probe_ent;
+ struct ahci_host_priv *hpriv;
int rc;
VPRINTK("ENTER\n");
@@ -1654,57 +1666,36 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- /* JMicron-specific fixup: make sure we're in AHCI mode */
- /* This is protected from races with ata_jmicron by the pci probe
- locking */
if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
- /* AHCI enable, AHCI on function 0 */
- pci_write_config_byte(pdev, 0x41, 0xa1);
- /* Function 1 is the PATA controller */
+ /* Function 1 is the PATA controller except on the 368, where
+ we are not AHCI anyway */
if (PCI_FUNC(pdev->devfn))
return -ENODEV;
}
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
- if (pci_enable_msi(pdev) == 0)
- have_msi = 1;
- else {
+ if (pci_enable_msi(pdev))
pci_intx(pdev, 1);
- have_msi = 0;
- }
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_msi;
- }
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
- memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
- memset(hpriv, 0, sizeof(*hpriv));
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
probe_ent->sht = ahci_port_info[board_idx].sht;
probe_ent->port_flags = ahci_port_info[board_idx].flags;
@@ -1714,16 +1705,13 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
probe_ent->private_data = hpriv;
- if (have_msi)
- hpriv->flags |= AHCI_FLAG_MSI;
-
/* initialize adapter */
rc = ahci_host_init(probe_ent);
if (rc)
- goto err_out_hpriv;
+ return rc;
if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
(hpriv->cap & HOST_CAP_NCQ))
@@ -1731,62 +1719,11 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ahci_print_info(probe_ent);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(dev, probe_ent);
return 0;
-
-err_out_hpriv:
- kfree(hpriv);
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_msi:
- if (have_msi)
- pci_disable_msi(pdev);
- else
- pci_intx(pdev, 0);
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-}
-
-static void ahci_remove_one (struct pci_dev *pdev)
-{
- struct device *dev = pci_dev_to_dev(pdev);
- struct ata_host *host = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = host->private_data;
- unsigned int i;
- int have_msi;
-
- for (i = 0; i < host->n_ports; i++)
- ata_port_detach(host->ports[i]);
-
- have_msi = hpriv->flags & AHCI_FLAG_MSI;
- free_irq(host->irq, host);
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- ata_scsi_release(ap->scsi_host);
- scsi_host_put(ap->scsi_host);
- }
-
- kfree(hpriv);
- pci_iounmap(pdev, host->mmio_base);
- kfree(host);
-
- if (have_msi)
- pci_disable_msi(pdev);
- else
- pci_intx(pdev, 0);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- dev_set_drvdata(dev, NULL);
}
static int __init ahci_init(void)
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 908751d27e7..be66ea08da5 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -64,6 +64,7 @@ static void generic_error_handler(struct ata_port *ap)
/**
* generic_set_mode - mode setting
* @ap: interface to set up
+ * @unused: returned device on error
*
* Use a non standard set_mode function. We don't want to be tuned.
* The BIOS configured everything. Our job is not to fiddle. We
@@ -71,18 +72,18 @@ static void generic_error_handler(struct ata_port *ap)
* and respect them.
*/
-static void generic_set_mode(struct ata_port *ap)
+static int generic_set_mode(struct ata_port *ap, struct ata_device **unused)
{
int dma_enabled = 0;
int i;
/* Bits 5 and 6 indicate if DMA is active on master/slave */
if (ap->ioaddr.bmdma_addr)
- dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
- if (ata_dev_enabled(dev)) {
+ if (ata_dev_ready(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
dev->dma_mode = XFER_MW_DMA_0;
@@ -99,6 +100,7 @@ static void generic_set_mode(struct ata_port *ap)
}
}
}
+ return 0;
}
static struct scsi_host_template generic_sht = {
@@ -136,7 +138,7 @@ static struct ata_port_operations generic_port_ops = {
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -148,10 +150,10 @@ static struct ata_port_operations generic_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int all_generic_ide; /* Set to claim all devices */
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index c7de0bb1591..4d716c7347e 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -118,7 +118,7 @@ enum {
PIIX_80C_SEC = (1 << 7) | (1 << 6),
/* controller IDs */
- piix_pata_33 = 0, /* PIIX3 or 4 at 33Mhz */
+ piix_pata_33 = 0, /* PIIX4 at 33Mhz */
ich_pata_33 = 1, /* ICH up to UDMA 33 only */
ich_pata_66 = 2, /* ICH up to 66 Mhz */
ich_pata_100 = 3, /* ICH up to UDMA 100 */
@@ -128,6 +128,7 @@ enum {
ich6_sata_ahci = 7,
ich6m_sata_ahci = 8,
ich8_sata_ahci = 9,
+ piix_pata_mwdma = 10, /* PIIX3 MWDMA only */
/* constants for mapping table */
P0 = 0, /* port 0 */
@@ -153,7 +154,6 @@ struct piix_host_priv {
static int piix_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent);
-static void piix_host_stop(struct ata_host *host);
static void piix_pata_error_handler(struct ata_port *ap);
static void ich_pata_error_handler(struct ata_port *ap);
static void piix_sata_error_handler(struct ata_port *ap);
@@ -164,7 +164,8 @@ static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
static unsigned int in_module_init = 1;
static const struct pci_device_id piix_pci_tbl[] = {
-#ifdef ATA_ENABLE_PATA
+ /* Intel PIIX3 for the 430HX etc */
+ { 0x8086, 0x7010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_mwdma },
/* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */
/* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */
{ 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
@@ -202,7 +203,6 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* ICH7/7-R (i945, i975) UDMA 100*/
{ 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
{ 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-#endif
/* NOTE: The following PCI ids must be kept in sync with the
* list in drivers/pci/quirks.c.
@@ -226,14 +226,26 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
/* 2801GBM/GHM (ICH7M, identical to ICH6M) */
{ 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
- /* Enterprise Southbridge 2 (where's the datasheet?) */
+ /* Enterprise Southbridge 2 (631xESB/632xESB) */
{ 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
- /* SATA Controller 1 IDE (ICH8, no datasheet yet) */
+ /* SATA Controller 1 IDE (ICH8) */
{ 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
- /* SATA Controller 2 IDE (ICH8, ditto) */
+ /* SATA Controller 2 IDE (ICH8) */
{ 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
- /* Mobile SATA Controller IDE (ICH8M, ditto) */
+ /* Mobile SATA Controller IDE (ICH8M) */
{ 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ /* SATA Controller IDE (ICH9) */
+ { 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ /* SATA Controller IDE (ICH9) */
+ { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ /* SATA Controller IDE (ICH9) */
+ { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ /* SATA Controller IDE (ICH9M) */
+ { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ /* SATA Controller IDE (ICH9M) */
+ { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ /* SATA Controller IDE (ICH9M) */
+ { 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
{ } /* terminate list */
};
@@ -285,7 +297,7 @@ static const struct ata_port_operations piix_pata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -294,10 +306,10 @@ static const struct ata_port_operations piix_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = piix_host_stop,
};
static const struct ata_port_operations ich_pata_ops = {
@@ -318,7 +330,7 @@ static const struct ata_port_operations ich_pata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -327,10 +339,10 @@ static const struct ata_port_operations ich_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static const struct ata_port_operations piix_sata_ops = {
@@ -348,7 +360,7 @@ static const struct ata_port_operations piix_sata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -357,10 +369,10 @@ static const struct ata_port_operations piix_sata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = piix_host_stop,
};
static const struct piix_map_db ich5_map_db = {
@@ -429,7 +441,7 @@ static const struct piix_map_db *piix_map_db_table[] = {
};
static struct ata_port_info piix_port_info[] = {
- /* piix_pata_33: 0: PIIX3 or 4 at 33MHz */
+ /* piix_pata_33: 0: PIIX4 at 33MHz */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -531,6 +543,14 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
+ /* piix_pata_mwdma: 10: PIIX3 MWDMA only */
+ {
+ .sht = &piix_sht,
+ .flags = PIIX_PATA_FLAGS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
+ .port_ops = &piix_pata_ops,
+ },
};
static struct pci_bits piix_enable_bits[] = {
@@ -557,6 +577,7 @@ struct ich_laptop {
static const struct ich_laptop ich_laptop[] = {
/* devid, subvendor, subdev */
{ 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
+ { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
/* end marker */
{ 0, }
};
@@ -620,7 +641,7 @@ static int piix_pata_prereset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
return -ENOENT;
-
+
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
@@ -764,7 +785,7 @@ static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, i
u16 master_data;
u8 speed = adev->dma_mode;
int devid = adev->devno + 2 * ap->port_no;
- u8 udma_enable;
+ u8 udma_enable = 0;
static const /* ISP RTC */
u8 timings[][2] = { { 0, 0 },
@@ -774,7 +795,8 @@ static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, i
{ 2, 3 }, };
pci_read_config_word(dev, master_port, &master_data);
- pci_read_config_byte(dev, 0x48, &udma_enable);
+ if (ap->udma_mask)
+ pci_read_config_byte(dev, 0x48, &udma_enable);
if (speed >= XFER_UDMA_0) {
unsigned int udma = adev->dma_mode - XFER_UDMA_0;
@@ -1047,6 +1069,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
+ struct device *dev = &pdev->dev;
struct ata_port_info port_info[2];
struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] };
struct piix_host_priv *hpriv;
@@ -1060,7 +1083,7 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!in_module_init)
return -ENODEV;
- hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
@@ -1110,15 +1133,6 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return ata_pci_init_one(pdev, ppinfo, 2);
}
-static void piix_host_stop(struct ata_host *host)
-{
- struct piix_host_priv *hpriv = host->private_data;
-
- ata_host_stop(host);
-
- kfree(hpriv);
-}
-
static int __init piix_init(void)
{
int rc;
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 011c0a8a2dc..25d8d3f778a 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -59,6 +59,9 @@
#include "libata.h"
+#define DRV_VERSION "2.10" /* must be exactly four chars */
+
+
/* debounce timing parameters in msecs { interval, duration, timeout } */
const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 };
@@ -598,51 +601,7 @@ void ata_dev_disable(struct ata_device *dev)
}
/**
- * ata_pio_devchk - PATA device presence detection
- * @ap: ATA channel to examine
- * @device: Device to examine (starting at zero)
- *
- * This technique was originally described in
- * Hale Landis's ATADRVR (www.ata-atapi.com), and
- * later found its way into the ATA/ATAPI spec.
- *
- * Write a pattern to the ATA shadow registers,
- * and if a device is present, it will respond by
- * correctly storing and echoing back the
- * ATA shadow register contents.
- *
- * LOCKING:
- * caller.
- */
-
-static unsigned int ata_pio_devchk(struct ata_port *ap,
- unsigned int device)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- u8 nsect, lbal;
-
- ap->ops->dev_select(ap, device);
-
- outb(0x55, ioaddr->nsect_addr);
- outb(0xaa, ioaddr->lbal_addr);
-
- outb(0xaa, ioaddr->nsect_addr);
- outb(0x55, ioaddr->lbal_addr);
-
- outb(0x55, ioaddr->nsect_addr);
- outb(0xaa, ioaddr->lbal_addr);
-
- nsect = inb(ioaddr->nsect_addr);
- lbal = inb(ioaddr->lbal_addr);
-
- if ((nsect == 0x55) && (lbal == 0xaa))
- return 1; /* we found a device */
-
- return 0; /* nothing found */
-}
-
-/**
- * ata_mmio_devchk - PATA device presence detection
+ * ata_devchk - PATA device presence detection
* @ap: ATA channel to examine
* @device: Device to examine (starting at zero)
*
@@ -659,25 +618,24 @@ static unsigned int ata_pio_devchk(struct ata_port *ap,
* caller.
*/
-static unsigned int ata_mmio_devchk(struct ata_port *ap,
- unsigned int device)
+static unsigned int ata_devchk(struct ata_port *ap, unsigned int device)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
u8 nsect, lbal;
ap->ops->dev_select(ap, device);
- writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
- writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
+ iowrite8(0x55, ioaddr->nsect_addr);
+ iowrite8(0xaa, ioaddr->lbal_addr);
- writeb(0xaa, (void __iomem *) ioaddr->nsect_addr);
- writeb(0x55, (void __iomem *) ioaddr->lbal_addr);
+ iowrite8(0xaa, ioaddr->nsect_addr);
+ iowrite8(0x55, ioaddr->lbal_addr);
- writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
- writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
+ iowrite8(0x55, ioaddr->nsect_addr);
+ iowrite8(0xaa, ioaddr->lbal_addr);
- nsect = readb((void __iomem *) ioaddr->nsect_addr);
- lbal = readb((void __iomem *) ioaddr->lbal_addr);
+ nsect = ioread8(ioaddr->nsect_addr);
+ lbal = ioread8(ioaddr->lbal_addr);
if ((nsect == 0x55) && (lbal == 0xaa))
return 1; /* we found a device */
@@ -686,27 +644,6 @@ static unsigned int ata_mmio_devchk(struct ata_port *ap,
}
/**
- * ata_devchk - PATA device presence detection
- * @ap: ATA channel to examine
- * @device: Device to examine (starting at zero)
- *
- * Dispatch ATA device presence detection, depending
- * on whether we are using PIO or MMIO to talk to the
- * ATA shadow registers.
- *
- * LOCKING:
- * caller.
- */
-
-static unsigned int ata_devchk(struct ata_port *ap,
- unsigned int device)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- return ata_mmio_devchk(ap, device);
- return ata_pio_devchk(ap, device);
-}
-
-/**
* ata_dev_classify - determine device type based on ATA-spec signature
* @tf: ATA taskfile register set for device to be identified
*
@@ -923,11 +860,7 @@ void ata_std_dev_select (struct ata_port *ap, unsigned int device)
else
tmp = ATA_DEVICE_OBS | ATA_DEV1;
- if (ap->flags & ATA_FLAG_MMIO) {
- writeb(tmp, (void __iomem *) ap->ioaddr.device_addr);
- } else {
- outb(tmp, ap->ioaddr.device_addr);
- }
+ iowrite8(tmp, ap->ioaddr.device_addr);
ata_pause(ap); /* needed; also flushes, for mmio */
}
@@ -1037,7 +970,7 @@ static unsigned int ata_id_xfermask(const u16 *id)
* the PIO timing number for the maximum. Turn it into
* a mask.
*/
- u8 mode = id[ATA_ID_OLD_PIO_MODES] & 0xFF;
+ u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF;
if (mode < 5) /* Valid PIO range */
pio_mask = (2 << mode) - 1;
else
@@ -1156,7 +1089,7 @@ void ata_port_flush_task(struct ata_port *ap)
ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__);
}
-void ata_qc_complete_internal(struct ata_queued_cmd *qc)
+static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
{
struct completion *waiting = qc->private_data;
@@ -1249,7 +1182,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
buflen += sg[i].length;
ata_sg_init(qc, sg, n_elem);
- qc->nsect = buflen / ATA_SECT_SIZE;
+ qc->nbytes = buflen;
}
qc->private_data = &wait;
@@ -1291,7 +1224,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
if (ap->ops->post_internal_cmd)
ap->ops->post_internal_cmd(qc);
- if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
+ if ((qc->flags & ATA_QCFLAG_FAILED) && !qc->err_mask) {
if (ata_msg_warn(ap))
ata_dev_printk(dev, KERN_WARNING,
"zero err_mask for failed "
@@ -1332,7 +1265,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
}
/**
- * ata_exec_internal_sg - execute libata internal command
+ * ata_exec_internal - execute libata internal command
* @dev: Device to which the command is sent
* @tf: Taskfile registers for the command and the result
* @cdb: CDB for packet command
@@ -1353,11 +1286,17 @@ unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, void *buf, unsigned int buflen)
{
- struct scatterlist sg;
+ struct scatterlist *psg = NULL, sg;
+ unsigned int n_elem = 0;
- sg_init_one(&sg, buf, buflen);
+ if (dma_dir != DMA_NONE) {
+ WARN_ON(!buf);
+ sg_init_one(&sg, buf, buflen);
+ psg = &sg;
+ n_elem++;
+ }
- return ata_exec_internal_sg(dev, tf, cdb, dma_dir, &sg, 1);
+ return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem);
}
/**
@@ -1601,6 +1540,8 @@ int ata_dev_configure(struct ata_device *dev)
const u16 *id = dev->id;
unsigned int xfer_mask;
char revbuf[7]; /* XYZ-99\0 */
+ char fwrevbuf[ATA_ID_FW_REV_LEN+1];
+ char modelbuf[ATA_ID_PROD_LEN+1];
int rc;
if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
@@ -1655,6 +1596,16 @@ int ata_dev_configure(struct ata_device *dev)
dev->n_sectors = ata_id_n_sectors(id);
+ /* SCSI only uses 4-char revisions, dump full 8 chars from ATA */
+ ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV,
+ sizeof(fwrevbuf));
+
+ ata_id_c_string(dev->id, modelbuf, ATA_ID_PROD,
+ sizeof(modelbuf));
+
+ if (dev->id[59] & 0x100)
+ dev->multi_count = dev->id[59] & 0xff;
+
if (ata_id_has_lba(id)) {
const char *lba_desc;
char ncq_desc[20];
@@ -1674,13 +1625,16 @@ int ata_dev_configure(struct ata_device *dev)
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
/* print device info to dmesg */
- if (ata_msg_drv(ap) && print_info)
- ata_dev_printk(dev, KERN_INFO, "%s, "
- "max %s, %Lu sectors: %s %s\n",
- revbuf,
- ata_mode_string(xfer_mask),
+ if (ata_msg_drv(ap) && print_info) {
+ ata_dev_printk(dev, KERN_INFO,
+ "%s: %s, %s, max %s\n",
+ revbuf, modelbuf, fwrevbuf,
+ ata_mode_string(xfer_mask));
+ ata_dev_printk(dev, KERN_INFO,
+ "%Lu sectors, multi %u: %s %s\n",
(unsigned long long)dev->n_sectors,
- lba_desc, ncq_desc);
+ dev->multi_count, lba_desc, ncq_desc);
+ }
} else {
/* CHS */
@@ -1697,22 +1651,17 @@ int ata_dev_configure(struct ata_device *dev)
}
/* print device info to dmesg */
- if (ata_msg_drv(ap) && print_info)
- ata_dev_printk(dev, KERN_INFO, "%s, "
- "max %s, %Lu sectors: CHS %u/%u/%u\n",
- revbuf,
- ata_mode_string(xfer_mask),
- (unsigned long long)dev->n_sectors,
- dev->cylinders, dev->heads,
- dev->sectors);
- }
-
- if (dev->id[59] & 0x100) {
- dev->multi_count = dev->id[59] & 0xff;
- if (ata_msg_drv(ap) && print_info)
+ if (ata_msg_drv(ap) && print_info) {
ata_dev_printk(dev, KERN_INFO,
- "ata%u: dev %u multi count %u\n",
- ap->id, dev->devno, dev->multi_count);
+ "%s: %s, %s, max %s\n",
+ revbuf, modelbuf, fwrevbuf,
+ ata_mode_string(xfer_mask));
+ ata_dev_printk(dev, KERN_INFO,
+ "%Lu sectors, multi %u, CHS %u/%u/%u\n",
+ (unsigned long long)dev->n_sectors,
+ dev->multi_count, dev->cylinders,
+ dev->heads, dev->sectors);
+ }
}
dev->cdb_len = 16;
@@ -2384,6 +2333,10 @@ static int ata_dev_set_mode(struct ata_device *dev)
dev->flags |= ATA_DFLAG_PIO;
err_mask = ata_dev_set_xfermode(dev);
+ /* Old CFA may refuse this command, which is just fine */
+ if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id))
+ err_mask &= ~AC_ERR_DEV;
+
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
"(err_mask=0x%x)\n", err_mask);
@@ -2425,18 +2378,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
int i, rc = 0, used_dma = 0, found = 0;
/* has private set_mode? */
- if (ap->ops->set_mode) {
- /* FIXME: make ->set_mode handle no device case and
- * return error code and failing device on failure.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- if (ata_dev_ready(&ap->device[i])) {
- ap->ops->set_mode(ap);
- break;
- }
- }
- return 0;
- }
+ if (ap->ops->set_mode)
+ return ap->ops->set_mode(ap, r_failed_dev);
/* step 1: calculate xfer_mask */
for (i = 0; i < ATA_MAX_DEVICES; i++) {
@@ -2496,7 +2439,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
for (i = 0; i < ATA_MAX_DEVICES; i++) {
dev = &ap->device[i];
- /* don't udpate suspended devices' xfer mode */
+ /* don't update suspended devices' xfer mode */
if (!ata_dev_ready(dev))
continue;
@@ -2617,13 +2560,8 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
u8 nsect, lbal;
ap->ops->dev_select(ap, 1);
- if (ap->flags & ATA_FLAG_MMIO) {
- nsect = readb((void __iomem *) ioaddr->nsect_addr);
- lbal = readb((void __iomem *) ioaddr->lbal_addr);
- } else {
- nsect = inb(ioaddr->nsect_addr);
- lbal = inb(ioaddr->lbal_addr);
- }
+ nsect = ioread8(ioaddr->nsect_addr);
+ lbal = ioread8(ioaddr->lbal_addr);
if ((nsect == 1) && (lbal == 1))
break;
if (time_after(jiffies, timeout)) {
@@ -2651,19 +2589,11 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
DPRINTK("ata%u: bus reset via SRST\n", ap->id);
/* software reset. causes dev0 to be selected */
- if (ap->flags & ATA_FLAG_MMIO) {
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- udelay(20); /* FIXME: flush */
- writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr);
- udelay(20); /* FIXME: flush */
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- } else {
- outb(ap->ctl, ioaddr->ctl_addr);
- udelay(10);
- outb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
- udelay(10);
- outb(ap->ctl, ioaddr->ctl_addr);
- }
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
+ udelay(20); /* FIXME: flush */
+ iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+ udelay(20); /* FIXME: flush */
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
/* spec mandates ">= 2ms" before checking status.
* We wait 150ms, because that was the magic delay used for
@@ -2748,8 +2678,7 @@ void ata_bus_reset(struct ata_port *ap)
ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
/* re-enable interrupts */
- if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
- ata_irq_on(ap);
+ ap->ops->irq_on(ap);
/* is double-select really necessary? */
if (ap->device[1].class != ATA_DEV_NONE)
@@ -2764,10 +2693,7 @@ void ata_bus_reset(struct ata_port *ap)
if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
/* set up device control for ATA_FLAG_SATA_RESET */
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- else
- outb(ap->ctl, ioaddr->ctl_addr);
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
}
DPRINTK("EXIT\n");
@@ -3101,6 +3027,9 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
return 0;
}
+ /* wait a while before checking status, see SRST for more info */
+ msleep(150);
+
if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
ata_port_printk(ap, KERN_ERR,
"COMRESET failed (device not ready)\n");
@@ -3141,11 +3070,8 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
sata_scr_write(ap, SCR_ERROR, serror);
/* re-enable interrupts */
- if (!ap->ops->error_handler) {
- /* FIXME: hack. create a hook instead */
- if (ap->ioaddr.ctl_addr)
- ata_irq_on(ap);
- }
+ if (!ap->ops->error_handler)
+ ap->ops->irq_on(ap);
/* is double-select really necessary? */
if (classes[0] != ATA_DEV_NONE)
@@ -3160,12 +3086,8 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
}
/* set up device control */
- if (ap->ioaddr.ctl_addr) {
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
- else
- outb(ap->ctl, ap->ioaddr.ctl_addr);
- }
+ if (ap->ioaddr.ctl_addr)
+ iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
DPRINTK("EXIT\n");
}
@@ -3190,7 +3112,8 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
const u16 *new_id)
{
const u16 *old_id = dev->id;
- unsigned char model[2][41], serial[2][21];
+ unsigned char model[2][ATA_ID_PROD_LEN + 1];
+ unsigned char serial[2][ATA_ID_SERNO_LEN + 1];
u64 new_n_sectors;
if (dev->class != new_class) {
@@ -3199,10 +3122,10 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
return 0;
}
- ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0]));
- ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1]));
- ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0]));
- ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1]));
+ ata_id_c_string(old_id, model[0], ATA_ID_PROD, sizeof(model[0]));
+ ata_id_c_string(new_id, model[1], ATA_ID_PROD, sizeof(model[1]));
+ ata_id_c_string(old_id, serial[0], ATA_ID_SERNO, sizeof(serial[0]));
+ ata_id_c_string(new_id, serial[1], ATA_ID_SERNO, sizeof(serial[1]));
new_n_sectors = ata_id_n_sectors(new_id);
if (strcmp(model[0], model[1])) {
@@ -3327,37 +3250,20 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ }
};
-static int ata_strim(char *s, size_t len)
-{
- len = strnlen(s, len);
-
- /* ATAPI specifies that empty space is blank-filled; remove blanks */
- while ((len > 0) && (s[len - 1] == ' ')) {
- len--;
- s[len] = 0;
- }
- return len;
-}
-
unsigned long ata_device_blacklisted(const struct ata_device *dev)
{
- unsigned char model_num[40];
- unsigned char model_rev[16];
- unsigned int nlen, rlen;
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
+ unsigned char model_rev[ATA_ID_FW_REV_LEN + 1];
const struct ata_blacklist_entry *ad = ata_device_blacklist;
- ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
- sizeof(model_num));
- ata_id_string(dev->id, model_rev, ATA_ID_FW_REV_OFS,
- sizeof(model_rev));
- nlen = ata_strim(model_num, sizeof(model_num));
- rlen = ata_strim(model_rev, sizeof(model_rev));
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
+ ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev));
while (ad->model_num) {
- if (!strncmp(ad->model_num, model_num, nlen)) {
+ if (!strcmp(ad->model_num, model_num)) {
if (ad->model_rev == NULL)
return ad->horkage;
- if (!strncmp(ad->model_rev, model_rev, rlen))
+ if (!strcmp(ad->model_rev, model_rev))
return ad->horkage;
}
ad++;
@@ -3897,53 +3803,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
}
/**
- * ata_mmio_data_xfer - Transfer data by MMIO
- * @adev: device for this I/O
- * @buf: data buffer
- * @buflen: buffer length
- * @write_data: read/write
- *
- * Transfer data from/to the device data register by MMIO.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
-{
- struct ata_port *ap = adev->ap;
- unsigned int i;
- unsigned int words = buflen >> 1;
- u16 *buf16 = (u16 *) buf;
- void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
-
- /* Transfer multiple of 2 bytes */
- if (write_data) {
- for (i = 0; i < words; i++)
- writew(le16_to_cpu(buf16[i]), mmio);
- } else {
- for (i = 0; i < words; i++)
- buf16[i] = cpu_to_le16(readw(mmio));
- }
-
- /* Transfer trailing 1 byte, if any. */
- if (unlikely(buflen & 0x01)) {
- u16 align_buf[1] = { 0 };
- unsigned char *trailing_buf = buf + buflen - 1;
-
- if (write_data) {
- memcpy(align_buf, trailing_buf, 1);
- writew(le16_to_cpu(align_buf[0]), mmio);
- } else {
- align_buf[0] = cpu_to_le16(readw(mmio));
- memcpy(trailing_buf, align_buf, 1);
- }
- }
-}
-
-/**
- * ata_pio_data_xfer - Transfer data by PIO
+ * ata_data_xfer - Transfer data by PIO
* @adev: device to target
* @buf: data buffer
* @buflen: buffer length
@@ -3954,18 +3814,17 @@ void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
* LOCKING:
* Inherited from caller.
*/
-
-void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
+void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
{
struct ata_port *ap = adev->ap;
unsigned int words = buflen >> 1;
/* Transfer multiple of 2 bytes */
if (write_data)
- outsw(ap->ioaddr.data_addr, buf, words);
+ iowrite16_rep(ap->ioaddr.data_addr, buf, words);
else
- insw(ap->ioaddr.data_addr, buf, words);
+ ioread16_rep(ap->ioaddr.data_addr, buf, words);
/* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) {
@@ -3974,16 +3833,16 @@ void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
if (write_data) {
memcpy(align_buf, trailing_buf, 1);
- outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
+ iowrite16(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
} else {
- align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr));
+ align_buf[0] = cpu_to_le16(ioread16(ap->ioaddr.data_addr));
memcpy(trailing_buf, align_buf, 1);
}
}
}
/**
- * ata_pio_data_xfer_noirq - Transfer data by PIO
+ * ata_data_xfer_noirq - Transfer data by PIO
* @adev: device to target
* @buf: data buffer
* @buflen: buffer length
@@ -3995,13 +3854,12 @@ void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
* LOCKING:
* Inherited from caller.
*/
-
-void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
+void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
{
unsigned long flags;
local_irq_save(flags);
- ata_pio_data_xfer(adev, buf, buflen, write_data);
+ ata_data_xfer(adev, buf, buflen, write_data);
local_irq_restore(flags);
}
@@ -4025,11 +3883,11 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
unsigned int offset;
unsigned char *buf;
- if (qc->cursect == (qc->nsect - 1))
+ if (qc->curbytes == qc->nbytes - ATA_SECT_SIZE)
ap->hsm_task_state = HSM_ST_LAST;
page = sg[qc->cursg].page;
- offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
+ offset = sg[qc->cursg].offset + qc->cursg_ofs;
/* get the current page and offset */
page = nth_page(page, (offset >> PAGE_SHIFT));
@@ -4054,10 +3912,10 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
}
- qc->cursect++;
- qc->cursg_ofs++;
+ qc->curbytes += ATA_SECT_SIZE;
+ qc->cursg_ofs += ATA_SECT_SIZE;
- if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) {
+ if (qc->cursg_ofs == (&sg[qc->cursg])->length) {
qc->cursg++;
qc->cursg_ofs = 0;
}
@@ -4082,7 +3940,8 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
WARN_ON(qc->dev->multi_count == 0);
- nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count);
+ nsect = min((qc->nbytes - qc->curbytes) / ATA_SECT_SIZE,
+ qc->dev->multi_count);
while (nsect--)
ata_pio_sector(qc);
} else
@@ -4323,7 +4182,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
qc = ata_qc_from_tag(ap, qc->tag);
if (qc) {
if (likely(!(qc->err_mask & AC_ERR_HSM))) {
- ata_irq_on(ap);
+ ap->ops->irq_on(ap);
ata_qc_complete(qc);
} else
ata_port_freeze(ap);
@@ -4339,7 +4198,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
} else {
if (in_wq) {
spin_lock_irqsave(ap->lock, flags);
- ata_irq_on(ap);
+ ap->ops->irq_on(ap);
ata_qc_complete(qc);
spin_unlock_irqrestore(ap->lock, flags);
} else
@@ -5164,7 +5023,7 @@ idle_irq:
#ifdef ATA_IRQ_TRAP
if ((ap->stats.idle_irq % 1000) == 0) {
- ata_irq_ack(ap, 0); /* debug trap */
+ ap->ops->irq_ack(ap, 0); /* debug trap */
ata_port_printk(ap, KERN_WARNING, "irq trap\n");
return 1;
}
@@ -5505,54 +5364,25 @@ void ata_host_resume(struct ata_host *host)
* LOCKING:
* Inherited from caller.
*/
-
-int ata_port_start (struct ata_port *ap)
+int ata_port_start(struct ata_port *ap)
{
struct device *dev = ap->dev;
int rc;
- ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL);
+ ap->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma,
+ GFP_KERNEL);
if (!ap->prd)
return -ENOMEM;
rc = ata_pad_alloc(ap, dev);
- if (rc) {
- dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+ if (rc)
return rc;
- }
-
- DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
+ DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd,
+ (unsigned long long)ap->prd_dma);
return 0;
}
-
-/**
- * ata_port_stop - Undo ata_port_start()
- * @ap: Port to shut down
- *
- * Frees the PRD table.
- *
- * May be used as the port_stop() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-void ata_port_stop (struct ata_port *ap)
-{
- struct device *dev = ap->dev;
-
- dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
- ata_pad_free(ap, dev);
-}
-
-void ata_host_stop (struct ata_host *host)
-{
- if (host->mmio_base)
- iounmap(host->mmio_base);
-}
-
/**
* ata_dev_init - Initialize an ata_device structure
* @dev: Device structure to initialize
@@ -5726,6 +5556,27 @@ static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
return ap;
}
+static void ata_host_release(struct device *gendev, void *res)
+{
+ struct ata_host *host = dev_get_drvdata(gendev);
+ int i;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (!ap)
+ continue;
+
+ if (ap->ops->port_stop)
+ ap->ops->port_stop(ap);
+
+ scsi_host_put(ap->scsi_host);
+ }
+
+ if (host->ops->host_stop)
+ host->ops->host_stop(host);
+}
+
/**
* ata_sas_host_init - Initialize a host struct
* @host: host to initialize
@@ -5773,22 +5624,28 @@ 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;
}
+
+ if (!devres_open_group(dev, ata_device_add, GFP_KERNEL))
+ 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);
+ host = devres_alloc(ata_host_release, sizeof(struct ata_host) +
+ (ent->n_ports * sizeof(void *)), GFP_KERNEL);
if (!host)
- return 0;
+ goto err_out;
+ devres_add(dev, host);
+ dev_set_drvdata(dev, host);
ata_host_init(host, dev, ent->_host_flags, ent->port_ops);
host->n_ports = ent->n_ports;
host->irq = ent->irq;
host->irq2 = ent->irq2;
- host->mmio_base = ent->mmio_base;
+ host->iomap = ent->iomap;
host->private_data = ent->private_data;
/* register each port bound to this device */
@@ -5826,8 +5683,8 @@ int ata_device_add(const struct ata_probe_ent *ent)
(ap->pio_mask << ATA_SHIFT_PIO);
/* print per-port info to dmesg */
- ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX "
- "ctl 0x%lX bmdma 0x%lX irq %d\n",
+ ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
+ "ctl 0x%p bmdma 0x%p irq %d\n",
ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
ata_mode_string(xfer_mode_mask),
ap->ioaddr.cmd_addr,
@@ -5840,8 +5697,8 @@ int ata_device_add(const struct ata_probe_ent *ent)
}
/* obtain irq, that may be shared between channels */
- rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
- DRV_NAME, host);
+ rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler,
+ ent->irq_flags, DRV_NAME, host);
if (rc) {
dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
ent->irq, rc);
@@ -5854,15 +5711,19 @@ int ata_device_add(const struct ata_probe_ent *ent)
so trap it now */
BUG_ON(ent->irq == ent->irq2);
- rc = request_irq(ent->irq2, ent->port_ops->irq_handler, ent->irq_flags,
- DRV_NAME, host);
+ rc = devm_request_irq(dev, ent->irq2,
+ ent->port_ops->irq_handler, ent->irq_flags,
+ DRV_NAME, host);
if (rc) {
dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
ent->irq2, rc);
- goto err_out_free_irq;
+ goto err_out;
}
}
+ /* resource acquisition complete */
+ devres_remove_group(dev, ata_device_add);
+
/* perform each probe synchronously */
DPRINTK("probe begin\n");
for (i = 0; i < host->n_ports; i++) {
@@ -5931,24 +5792,13 @@ int ata_device_add(const struct ata_probe_ent *ent)
ata_scsi_scan_host(ap);
}
- dev_set_drvdata(dev, host);
-
VPRINTK("EXIT, returning %u\n", ent->n_ports);
return ent->n_ports; /* success */
-err_out_free_irq:
- free_irq(ent->irq, host);
-err_out:
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
- if (ap) {
- ap->ops->port_stop(ap);
- scsi_host_put(ap->scsi_host);
- }
- }
-
- kfree(host);
- VPRINTK("EXIT, returning 0\n");
+ err_out:
+ devres_release_group(dev, ata_device_add);
+ dev_set_drvdata(dev, NULL);
+ VPRINTK("EXIT, returning %d\n", rc);
return 0;
}
@@ -6011,76 +5861,20 @@ void ata_port_detach(struct ata_port *ap)
}
/**
- * ata_host_remove - PCI layer callback for device removal
- * @host: ATA host set that was removed
+ * ata_host_detach - Detach all ports of an ATA host
+ * @host: Host to detach
*
- * Unregister all objects associated with this host set. Free those
- * objects.
+ * Detach all ports of @host.
*
* LOCKING:
- * Inherited from calling layer (may sleep).
+ * Kernel thread context (may sleep).
*/
-
-void ata_host_remove(struct ata_host *host)
+void ata_host_detach(struct ata_host *host)
{
- unsigned int i;
+ int i;
for (i = 0; i < host->n_ports; i++)
ata_port_detach(host->ports[i]);
-
- free_irq(host->irq, host);
- if (host->irq2)
- free_irq(host->irq2, host);
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- ata_scsi_release(ap->scsi_host);
-
- if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- /* FIXME: Add -ac IDE pci mods to remove these special cases */
- if (ioaddr->cmd_addr == ATA_PRIMARY_CMD)
- release_region(ATA_PRIMARY_CMD, 8);
- else if (ioaddr->cmd_addr == ATA_SECONDARY_CMD)
- release_region(ATA_SECONDARY_CMD, 8);
- }
-
- scsi_host_put(ap->scsi_host);
- }
-
- if (host->ops->host_stop)
- host->ops->host_stop(host);
-
- kfree(host);
-}
-
-/**
- * ata_scsi_release - SCSI layer callback hook for host unload
- * @shost: libata host to be unloaded
- *
- * Performs all duties necessary to shut down a libata port...
- * Kill port kthread, disable port, and release resources.
- *
- * LOCKING:
- * Inherited from SCSI layer.
- *
- * RETURNS:
- * One.
- */
-
-int ata_scsi_release(struct Scsi_Host *shost)
-{
- struct ata_port *ap = ata_shost_to_port(shost);
-
- DPRINTK("ENTER\n");
-
- ap->ops->port_disable(ap);
- ap->ops->port_stop(ap);
-
- DPRINTK("EXIT\n");
- return 1;
}
struct ata_probe_ent *
@@ -6088,7 +5882,11 @@ ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
{
struct ata_probe_ent *probe_ent;
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+ /* XXX - the following if can go away once all LLDs are managed */
+ if (!list_empty(&dev->devres_head))
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ else
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
if (!probe_ent) {
printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
kobject_name(&(dev->kobj)));
@@ -6138,37 +5936,23 @@ void ata_std_ports(struct ata_ioports *ioaddr)
#ifdef CONFIG_PCI
-void ata_pci_host_stop (struct ata_host *host)
-{
- struct pci_dev *pdev = to_pci_dev(host->dev);
-
- pci_iounmap(pdev, host->mmio_base);
-}
-
/**
* ata_pci_remove_one - PCI layer callback for device removal
* @pdev: PCI device that was removed
*
- * PCI layer indicates to libata via this hook that
- * hot-unplug or module unload event has occurred.
- * Handle this by unregistering all objects associated
- * with this PCI device. Free those objects. Then finally
- * release PCI resources and disable device.
+ * PCI layer indicates to libata via this hook that hot-unplug or
+ * module unload event has occurred. Detach all ports. Resource
+ * release is handled via devres.
*
* LOCKING:
* Inherited from PCI layer (may sleep).
*/
-
-void ata_pci_remove_one (struct pci_dev *pdev)
+void ata_pci_remove_one(struct pci_dev *pdev)
{
struct device *dev = pci_dev_to_dev(pdev);
struct ata_host *host = dev_get_drvdata(dev);
- ata_host_remove(host);
-
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- dev_set_drvdata(dev, NULL);
+ ata_host_detach(host);
}
/* move to PCI subsystem */
@@ -6215,12 +5999,22 @@ void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg)
}
}
-void ata_pci_device_do_resume(struct pci_dev *pdev)
+int ata_pci_device_do_resume(struct pci_dev *pdev)
{
+ int rc;
+
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+
+ rc = pcim_enable_device(pdev);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to enable device after resume (%d)\n", rc);
+ return rc;
+ }
+
pci_set_master(pdev);
+ return 0;
}
int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
@@ -6240,10 +6034,12 @@ int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
int ata_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc;
- ata_pci_device_do_resume(pdev);
- ata_host_resume(host);
- return 0;
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc == 0)
+ ata_host_resume(host);
+ return rc;
}
#endif /* CONFIG_PCI */
@@ -6389,8 +6185,7 @@ EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_host_init);
EXPORT_SYMBOL_GPL(ata_device_add);
-EXPORT_SYMBOL_GPL(ata_port_detach);
-EXPORT_SYMBOL_GPL(ata_host_remove);
+EXPORT_SYMBOL_GPL(ata_host_detach);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_sg_init_one);
EXPORT_SYMBOL_GPL(ata_hsm_move);
@@ -6407,12 +6202,9 @@ EXPORT_SYMBOL_GPL(ata_check_status);
EXPORT_SYMBOL_GPL(ata_altstatus);
EXPORT_SYMBOL_GPL(ata_exec_command);
EXPORT_SYMBOL_GPL(ata_port_start);
-EXPORT_SYMBOL_GPL(ata_port_stop);
-EXPORT_SYMBOL_GPL(ata_host_stop);
EXPORT_SYMBOL_GPL(ata_interrupt);
-EXPORT_SYMBOL_GPL(ata_mmio_data_xfer);
-EXPORT_SYMBOL_GPL(ata_pio_data_xfer);
-EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq);
+EXPORT_SYMBOL_GPL(ata_data_xfer);
+EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
EXPORT_SYMBOL_GPL(ata_qc_prep);
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
EXPORT_SYMBOL_GPL(ata_bmdma_setup);
@@ -6449,7 +6241,6 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
-EXPORT_SYMBOL_GPL(ata_scsi_release);
EXPORT_SYMBOL_GPL(ata_host_intr);
EXPORT_SYMBOL_GPL(sata_scr_valid);
EXPORT_SYMBOL_GPL(sata_scr_read);
@@ -6470,7 +6261,6 @@ EXPORT_SYMBOL_GPL(ata_timing_merge);
#ifdef CONFIG_PCI
EXPORT_SYMBOL_GPL(pci_test_config_bits);
-EXPORT_SYMBOL_GPL(ata_pci_host_stop);
EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
@@ -6494,3 +6284,7 @@ EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
EXPORT_SYMBOL_GPL(ata_do_eh);
+EXPORT_SYMBOL_GPL(ata_irq_on);
+EXPORT_SYMBOL_GPL(ata_dummy_irq_on);
+EXPORT_SYMBOL_GPL(ata_irq_ack);
+EXPORT_SYMBOL_GPL(ata_dummy_irq_ack);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 08ad44b3e48..52c85af7fe9 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1443,15 +1443,10 @@ static void ata_eh_report(struct ata_port *ap)
};
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf;
- unsigned int nbytes;
if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
continue;
- nbytes = qc->nbytes;
- if (!nbytes)
- nbytes = qc->nsect << 9;
-
ata_dev_printk(qc->dev, KERN_ERR,
"cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
"tag %d cdb 0x%x data %u %s\n "
@@ -1461,7 +1456,7 @@ static void ata_eh_report(struct ata_port *ap)
cmd->lbal, cmd->lbam, cmd->lbah,
cmd->hob_feature, cmd->hob_nsect,
cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah,
- cmd->device, qc->tag, qc->cdb[0], nbytes,
+ cmd->device, qc->tag, qc->cdb[0], qc->nbytes,
dma_str[qc->dma_dir],
res->command, res->feature, res->nsect,
res->lbal, res->lbam, res->lbah,
@@ -1796,7 +1791,7 @@ static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
*r_failed_dev = dev;
DPRINTK("EXIT\n");
- return 0;
+ return rc;
}
/**
@@ -1979,6 +1974,10 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+ /* collect port action mask recorded in dev actions */
+ ehc->i.action |= ehc->i.dev_action[i] & ~ATA_EH_PERDEV_MASK;
+ ehc->i.dev_action[i] &= ATA_EH_PERDEV_MASK;
+
/* process hotplug request */
if (dev->flags & ATA_DFLAG_DETACH)
ata_eh_detach_dev(dev);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 664e1377b54..0009818a430 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -51,7 +51,7 @@
#define SECTOR_SIZE 512
-typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd);
+typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc);
static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev);
@@ -149,6 +149,45 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
}
/**
+ * ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl
+ * @sdev: SCSI device to get identify data for
+ * @arg: User buffer area for identify data
+ *
+ * LOCKING:
+ * Defined by the SCSI layer. We don't really care.
+ *
+ * RETURNS:
+ * Zero on success, negative errno on error.
+ */
+static int ata_get_identity(struct scsi_device *sdev, void __user *arg)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+ u16 __user *dst = arg;
+ char buf[40];
+
+ if (!dev)
+ return -ENOMSG;
+
+ if (copy_to_user(dst, dev->id, ATA_ID_WORDS * sizeof(u16)))
+ return -EFAULT;
+
+ ata_id_string(dev->id, buf, ATA_ID_PROD, ATA_ID_PROD_LEN);
+ if (copy_to_user(dst + ATA_ID_PROD, buf, ATA_ID_PROD_LEN))
+ return -EFAULT;
+
+ ata_id_string(dev->id, buf, ATA_ID_FW_REV, ATA_ID_FW_REV_LEN);
+ if (copy_to_user(dst + ATA_ID_FW_REV, buf, ATA_ID_FW_REV_LEN))
+ return -EFAULT;
+
+ ata_id_string(dev->id, buf, ATA_ID_SERNO, ATA_ID_SERNO_LEN);
+ if (copy_to_user(dst + ATA_ID_SERNO, buf, ATA_ID_SERNO_LEN))
+ return -EFAULT;
+
+ return 0;
+}
+
+/**
* ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl
* @scsidev: Device to which we are issuing command
* @arg: User provided data for issuing command
@@ -159,7 +198,6 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
* RETURNS:
* Zero on success, negative errno on error.
*/
-
int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
{
int rc = 0;
@@ -273,8 +311,8 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
{
int rc = 0;
u8 scsi_cmd[MAX_COMMAND_SIZE];
- u8 args[7];
- struct scsi_sense_hdr sshdr;
+ u8 args[7], *sensebuf = NULL;
+ int cmd_result;
if (arg == NULL)
return -EINVAL;
@@ -282,10 +320,14 @@ int ata_task_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));
scsi_cmd[0] = ATA_16;
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 */
scsi_cmd[4] = args[1];
scsi_cmd[6] = args[2];
scsi_cmd[8] = args[3];
@@ -295,11 +337,46 @@ int ata_task_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, DMA_NONE, NULL, 0, &sshdr,
- (10*HZ), 5))
+ cmd_result = scsi_execute(scsidev, scsi_cmd, DMA_NONE, NULL, 0,
+ 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 ATA registers */
+ 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) */
+ args[3] = desc[7]; /* lbal */
+ args[4] = desc[9]; /* lbam */
+ args[5] = desc[11]; /* lbah */
+ args[6] = desc[12]; /* select */
+ 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? */
+ error:
+ kfree(sensebuf);
return rc;
}
@@ -320,6 +397,9 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
return -EINVAL;
return 0;
+ case HDIO_GET_IDENTITY:
+ return ata_get_identity(scsidev, arg);
+
case HDIO_DRIVE_CMD:
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
return -EACCES;
@@ -358,9 +438,9 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
* RETURNS:
* Command allocated, or %NULL if none available.
*/
-struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
- struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
+static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
+ struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
{
struct ata_queued_cmd *qc;
@@ -372,7 +452,7 @@ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
if (cmd->use_sg) {
qc->__sg = (struct scatterlist *) cmd->request_buffer;
qc->n_elem = cmd->use_sg;
- } else {
+ } else if (cmd->request_bufflen) {
qc->__sg = &qc->sgent;
qc->n_elem = 1;
}
@@ -396,7 +476,7 @@ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
* LOCKING:
* inherited from caller
*/
-void ata_dump_status(unsigned id, struct ata_taskfile *tf)
+static void ata_dump_status(unsigned id, struct ata_taskfile *tf)
{
u8 stat = tf->command, err = tf->feature;
@@ -571,8 +651,8 @@ int ata_scsi_device_resume(struct scsi_device *sdev)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
- u8 *ascq, int verbose)
+static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
+ u8 *asc, u8 *ascq, int verbose)
{
int i;
@@ -935,7 +1015,6 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
/**
* ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
* @qc: Storage for translated ATA taskfile
- * @scsicmd: SCSI command to translate
*
* Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY
* (to start). Perhaps these commands should be preceded by
@@ -948,22 +1027,25 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
* RETURNS:
* Zero on success, non-zero on error.
*/
-
-static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc,
- const u8 *scsicmd)
+static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
{
+ struct scsi_cmnd *scmd = qc->scsicmd;
struct ata_taskfile *tf = &qc->tf;
+ const u8 *cdb = scmd->cmnd;
+
+ if (scmd->cmd_len < 5)
+ goto invalid_fld;
tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
tf->protocol = ATA_PROT_NODATA;
- if (scsicmd[1] & 0x1) {
+ if (cdb[1] & 0x1) {
; /* ignore IMMED bit, violates sat-r05 */
}
- if (scsicmd[4] & 0x2)
+ if (cdb[4] & 0x2)
goto invalid_fld; /* LOEJ bit set not supported */
- if (((scsicmd[4] >> 4) & 0xf) != 0)
+ if (((cdb[4] >> 4) & 0xf) != 0)
goto invalid_fld; /* power conditions not supported */
- if (scsicmd[4] & 0x1) {
+ if (cdb[4] & 0x1) {
tf->nsect = 1; /* 1 sector, lba=0 */
if (qc->dev->flags & ATA_DFLAG_LBA) {
@@ -981,11 +1063,10 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc,
}
tf->command = ATA_CMD_VERIFY; /* READ VERIFY */
- } else {
- tf->nsect = 0; /* time period value (0 implies now) */
- tf->command = ATA_CMD_STANDBY;
- /* Consider: ATA STANDBY IMMEDIATE command */
- }
+ } else
+ /* Issue ATA STANDBY IMMEDIATE command */
+ tf->command = ATA_CMD_STANDBYNOW1;
+
/*
* Standby and Idle condition timers could be implemented but that
* would require libata to implement the Power condition mode page
@@ -996,7 +1077,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc,
return 0;
invalid_fld:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+ ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0);
/* "Invalid field in cbd" */
return 1;
}
@@ -1005,7 +1086,6 @@ invalid_fld:
/**
* ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command
* @qc: Storage for translated ATA taskfile
- * @scsicmd: SCSI command to translate (ignored)
*
* Sets up an ATA taskfile to issue FLUSH CACHE or
* FLUSH CACHE EXT.
@@ -1016,8 +1096,7 @@ invalid_fld:
* RETURNS:
* Zero on success, non-zero on error.
*/
-
-static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc)
{
struct ata_taskfile *tf = &qc->tf;
@@ -1034,7 +1113,7 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scs
/**
* scsi_6_lba_len - Get LBA and transfer length
- * @scsicmd: SCSI command to translate
+ * @cdb: SCSI command to translate
*
* Calculate LBA and transfer length for 6-byte commands.
*
@@ -1042,18 +1121,17 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scs
* @plba: the LBA
* @plen: the transfer length
*/
-
-static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
+static void scsi_6_lba_len(const u8 *cdb, u64 *plba, u32 *plen)
{
u64 lba = 0;
u32 len = 0;
VPRINTK("six-byte command\n");
- lba |= ((u64)scsicmd[2]) << 8;
- lba |= ((u64)scsicmd[3]);
+ lba |= ((u64)cdb[2]) << 8;
+ lba |= ((u64)cdb[3]);
- len |= ((u32)scsicmd[4]);
+ len |= ((u32)cdb[4]);
*plba = lba;
*plen = len;
@@ -1061,7 +1139,7 @@ static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
/**
* scsi_10_lba_len - Get LBA and transfer length
- * @scsicmd: SCSI command to translate
+ * @cdb: SCSI command to translate
*
* Calculate LBA and transfer length for 10-byte commands.
*
@@ -1069,21 +1147,20 @@ static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
* @plba: the LBA
* @plen: the transfer length
*/
-
-static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
+static void scsi_10_lba_len(const u8 *cdb, u64 *plba, u32 *plen)
{
u64 lba = 0;
u32 len = 0;
VPRINTK("ten-byte command\n");
- lba |= ((u64)scsicmd[2]) << 24;
- lba |= ((u64)scsicmd[3]) << 16;
- lba |= ((u64)scsicmd[4]) << 8;
- lba |= ((u64)scsicmd[5]);
+ lba |= ((u64)cdb[2]) << 24;
+ lba |= ((u64)cdb[3]) << 16;
+ lba |= ((u64)cdb[4]) << 8;
+ lba |= ((u64)cdb[5]);
- len |= ((u32)scsicmd[7]) << 8;
- len |= ((u32)scsicmd[8]);
+ len |= ((u32)cdb[7]) << 8;
+ len |= ((u32)cdb[8]);
*plba = lba;
*plen = len;
@@ -1091,7 +1168,7 @@ static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
/**
* scsi_16_lba_len - Get LBA and transfer length
- * @scsicmd: SCSI command to translate
+ * @cdb: SCSI command to translate
*
* Calculate LBA and transfer length for 16-byte commands.
*
@@ -1099,27 +1176,26 @@ static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
* @plba: the LBA
* @plen: the transfer length
*/
-
-static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
+static void scsi_16_lba_len(const u8 *cdb, u64 *plba, u32 *plen)
{
u64 lba = 0;
u32 len = 0;
VPRINTK("sixteen-byte command\n");
- lba |= ((u64)scsicmd[2]) << 56;
- lba |= ((u64)scsicmd[3]) << 48;
- lba |= ((u64)scsicmd[4]) << 40;
- lba |= ((u64)scsicmd[5]) << 32;
- lba |= ((u64)scsicmd[6]) << 24;
- lba |= ((u64)scsicmd[7]) << 16;
- lba |= ((u64)scsicmd[8]) << 8;
- lba |= ((u64)scsicmd[9]);
+ lba |= ((u64)cdb[2]) << 56;
+ lba |= ((u64)cdb[3]) << 48;
+ lba |= ((u64)cdb[4]) << 40;
+ lba |= ((u64)cdb[5]) << 32;
+ lba |= ((u64)cdb[6]) << 24;
+ lba |= ((u64)cdb[7]) << 16;
+ lba |= ((u64)cdb[8]) << 8;
+ lba |= ((u64)cdb[9]);
- len |= ((u32)scsicmd[10]) << 24;
- len |= ((u32)scsicmd[11]) << 16;
- len |= ((u32)scsicmd[12]) << 8;
- len |= ((u32)scsicmd[13]);
+ len |= ((u32)cdb[10]) << 24;
+ len |= ((u32)cdb[11]) << 16;
+ len |= ((u32)cdb[12]) << 8;
+ len |= ((u32)cdb[13]);
*plba = lba;
*plen = len;
@@ -1128,7 +1204,6 @@ static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
/**
* ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
* @qc: Storage for translated ATA taskfile
- * @scsicmd: SCSI command to translate
*
* Converts SCSI VERIFY command to an ATA READ VERIFY command.
*
@@ -1138,23 +1213,28 @@ static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
* RETURNS:
* Zero on success, non-zero on error.
*/
-
-static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc)
{
+ struct scsi_cmnd *scmd = qc->scsicmd;
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
u64 dev_sectors = qc->dev->n_sectors;
+ const u8 *cdb = scmd->cmnd;
u64 block;
u32 n_block;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf->protocol = ATA_PROT_NODATA;
- if (scsicmd[0] == VERIFY)
- scsi_10_lba_len(scsicmd, &block, &n_block);
- else if (scsicmd[0] == VERIFY_16)
- scsi_16_lba_len(scsicmd, &block, &n_block);
- else
+ if (cdb[0] == VERIFY) {
+ if (scmd->cmd_len < 10)
+ goto invalid_fld;
+ scsi_10_lba_len(cdb, &block, &n_block);
+ } else if (cdb[0] == VERIFY_16) {
+ if (scmd->cmd_len < 16)
+ goto invalid_fld;
+ scsi_16_lba_len(cdb, &block, &n_block);
+ } else
goto invalid_fld;
if (!n_block)
@@ -1229,24 +1309,23 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *sc
return 0;
invalid_fld:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+ ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0);
/* "Invalid field in cbd" */
return 1;
out_of_range:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
+ ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0);
/* "Logical Block Address out of range" */
return 1;
nothing_to_do:
- qc->scsicmd->result = SAM_STAT_GOOD;
+ scmd->result = SAM_STAT_GOOD;
return 1;
}
/**
* ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one
* @qc: Storage for translated ATA taskfile
- * @scsicmd: SCSI command to translate
*
* Converts any of six SCSI read/write commands into the
* ATA counterpart, including starting sector (LBA),
@@ -1262,29 +1341,33 @@ nothing_to_do:
* RETURNS:
* Zero on success, non-zero on error.
*/
-
-static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
{
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ const u8 *cdb = scmd->cmnd;
unsigned int tf_flags = 0;
u64 block;
u32 n_block;
int rc;
- if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
- scsicmd[0] == WRITE_16)
+ if (cdb[0] == WRITE_10 || cdb[0] == WRITE_6 || cdb[0] == WRITE_16)
tf_flags |= ATA_TFLAG_WRITE;
/* Calculate the SCSI LBA, transfer length and FUA. */
- switch (scsicmd[0]) {
+ switch (cdb[0]) {
case READ_10:
case WRITE_10:
- scsi_10_lba_len(scsicmd, &block, &n_block);
- if (unlikely(scsicmd[1] & (1 << 3)))
+ if (unlikely(scmd->cmd_len < 10))
+ goto invalid_fld;
+ scsi_10_lba_len(cdb, &block, &n_block);
+ if (unlikely(cdb[1] & (1 << 3)))
tf_flags |= ATA_TFLAG_FUA;
break;
case READ_6:
case WRITE_6:
- scsi_6_lba_len(scsicmd, &block, &n_block);
+ if (unlikely(scmd->cmd_len < 6))
+ goto invalid_fld;
+ scsi_6_lba_len(cdb, &block, &n_block);
/* for 6-byte r/w commands, transfer length 0
* means 256 blocks of data, not 0 block.
@@ -1294,8 +1377,10 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
break;
case READ_16:
case WRITE_16:
- scsi_16_lba_len(scsicmd, &block, &n_block);
- if (unlikely(scsicmd[1] & (1 << 3)))
+ if (unlikely(scmd->cmd_len < 16))
+ goto invalid_fld;
+ scsi_16_lba_len(cdb, &block, &n_block);
+ if (unlikely(cdb[1] & (1 << 3)))
tf_flags |= ATA_TFLAG_FUA;
break;
default:
@@ -1315,7 +1400,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
goto nothing_to_do;
qc->flags |= ATA_QCFLAG_IO;
- qc->nsect = n_block;
+ qc->nbytes = n_block * ATA_SECT_SIZE;
rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
qc->tag);
@@ -1326,17 +1411,17 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
goto out_of_range;
/* treat all other errors as -EINVAL, fall through */
invalid_fld:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+ ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0);
/* "Invalid field in cbd" */
return 1;
out_of_range:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
+ ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0);
/* "Logical Block Address out of range" */
return 1;
nothing_to_do:
- qc->scsicmd->result = SAM_STAT_GOOD;
+ scmd->result = SAM_STAT_GOOD;
return 1;
}
@@ -1456,7 +1541,6 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
ata_xlat_func_t xlat_func)
{
struct ata_queued_cmd *qc;
- u8 *scsicmd = cmd->cmnd;
int is_io = xlat_func == ata_scsi_rw_xlat;
VPRINTK("ENTER\n");
@@ -1488,7 +1572,7 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
qc->complete_fn = ata_scsi_qc_complete;
- if (xlat_func(qc, scsicmd))
+ if (xlat_func(qc))
goto early_finish;
/* select device, send command to hardware */
@@ -1539,7 +1623,7 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
struct scatterlist *sg;
sg = (struct scatterlist *) cmd->request_buffer;
- buf = kmap_atomic(sg->page, KM_USER0) + sg->offset;
+ buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
buflen = sg->length;
} else {
buf = cmd->request_buffer;
@@ -1567,7 +1651,7 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
struct scatterlist *sg;
sg = (struct scatterlist *) cmd->request_buffer;
- kunmap_atomic(buf - sg->offset, KM_USER0);
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
}
}
@@ -1655,8 +1739,8 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
if (buflen > 35) {
memcpy(&rbuf[8], "ATA ", 8);
- ata_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
- ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
+ ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16);
+ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
if (rbuf[32] == 0 || rbuf[32] == ' ')
memcpy(&rbuf[32], "n/a ", 4);
}
@@ -1725,13 +1809,13 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
0,
0x80, /* this page code */
0,
- ATA_SERNO_LEN, /* page len */
+ ATA_ID_SERNO_LEN, /* page len */
};
memcpy(rbuf, hdr, sizeof(hdr));
- if (buflen > (ATA_SERNO_LEN + 4 - 1))
+ if (buflen > (ATA_ID_SERNO_LEN + 4 - 1))
ata_id_string(args->id, (unsigned char *) &rbuf[4],
- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
return 0;
}
@@ -1756,19 +1840,18 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
{
int num;
const int sat_model_serial_desc_len = 68;
- const int ata_model_byte_len = 40;
rbuf[1] = 0x83; /* this page code */
num = 4;
- if (buflen > (ATA_SERNO_LEN + num + 3)) {
+ if (buflen > (ATA_ID_SERNO_LEN + num + 3)) {
/* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
rbuf[num + 0] = 2;
- rbuf[num + 3] = ATA_SERNO_LEN;
+ rbuf[num + 3] = ATA_ID_SERNO_LEN;
num += 4;
ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
- num += ATA_SERNO_LEN;
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
+ num += ATA_ID_SERNO_LEN;
}
if (buflen > (sat_model_serial_desc_len + num + 3)) {
/* SAT defined lu model and serial numbers descriptor */
@@ -1780,11 +1863,11 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
memcpy(rbuf + num, "ATA ", 8);
num += 8;
ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_PROD_OFS, ata_model_byte_len);
- num += ata_model_byte_len;
+ ATA_ID_PROD, ATA_ID_PROD_LEN);
+ num += ATA_ID_PROD_LEN;
ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
- num += ATA_SERNO_LEN;
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
+ num += ATA_ID_SERNO_LEN;
}
rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */
return 0;
@@ -1912,15 +1995,15 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
*/
static int ata_dev_supports_fua(u16 *id)
{
- unsigned char model[41], fw[9];
+ unsigned char model[ATA_ID_PROD_LEN + 1], fw[ATA_ID_FW_REV_LEN + 1];
if (!libata_fua)
return 0;
if (!ata_id_has_fua(id))
return 0;
- ata_id_c_string(id, model, ATA_ID_PROD_OFS, sizeof(model));
- ata_id_c_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw));
+ ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model));
+ ata_id_c_string(id, fw, ATA_ID_FW_REV, sizeof(fw));
if (strcmp(model, "Maxtor"))
return 1;
@@ -2344,7 +2427,6 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
/**
* atapi_xlat - Initialize PACKET taskfile
* @qc: command structure to be initialized
- * @scsicmd: SCSI CDB associated with this PACKET command
*
* LOCKING:
* spin_lock_irqsave(host lock)
@@ -2352,25 +2434,25 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
* RETURNS:
* Zero on success, non-zero on failure.
*/
-
-static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
{
- struct scsi_cmnd *cmd = qc->scsicmd;
+ struct scsi_cmnd *scmd = qc->scsicmd;
struct ata_device *dev = qc->dev;
int using_pio = (dev->flags & ATA_DFLAG_PIO);
- int nodata = (cmd->sc_data_direction == DMA_NONE);
+ int nodata = (scmd->sc_data_direction == DMA_NONE);
if (!using_pio)
/* Check whether ATAPI DMA is safe */
if (ata_check_atapi_dma(qc))
using_pio = 1;
- memcpy(&qc->cdb, scsicmd, dev->cdb_len);
+ memset(qc->cdb, 0, dev->cdb_len);
+ memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len);
qc->complete_fn = atapi_qc_complete;
qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+ if (scmd->sc_data_direction == DMA_TO_DEVICE) {
qc->tf.flags |= ATA_TFLAG_WRITE;
DPRINTK("direction: write\n");
}
@@ -2392,12 +2474,12 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
qc->tf.protocol = ATA_PROT_ATAPI_DMA;
qc->tf.feature |= ATAPI_PKT_DMA;
- if (atapi_dmadir && (cmd->sc_data_direction != DMA_TO_DEVICE))
+ if (atapi_dmadir && (scmd->sc_data_direction != DMA_TO_DEVICE))
/* some SATA bridges need us to indicate data xfer direction */
qc->tf.feature |= ATAPI_DMADIR;
}
- qc->nbytes = cmd->request_bufflen;
+ qc->nbytes = scmd->request_bufflen;
return 0;
}
@@ -2517,28 +2599,27 @@ ata_scsi_map_proto(u8 byte1)
/**
* ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile
* @qc: command structure to be initialized
- * @scsicmd: SCSI command to convert
*
* Handles either 12 or 16-byte versions of the CDB.
*
* RETURNS:
* Zero on success, non-zero on failure.
*/
-static unsigned int
-ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
+static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
{
struct ata_taskfile *tf = &(qc->tf);
- struct scsi_cmnd *cmd = qc->scsicmd;
+ struct scsi_cmnd *scmd = qc->scsicmd;
struct ata_device *dev = qc->dev;
+ const u8 *cdb = scmd->cmnd;
- if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN)
+ if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN)
goto invalid_fld;
/* We may not issue DMA commands if no DMA mode is set */
if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
goto invalid_fld;
- if (scsicmd[1] & 0xe0)
+ if (cdb[1] & 0xe0)
/* PIO multi not supported yet */
goto invalid_fld;
@@ -2546,18 +2627,18 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
* 12 and 16 byte CDBs use different offsets to
* provide the various register values.
*/
- if (scsicmd[0] == ATA_16) {
+ if (cdb[0] == ATA_16) {
/*
* 16-byte CDB - may contain extended commands.
*
* If that is the case, copy the upper byte register values.
*/
- if (scsicmd[1] & 0x01) {
- tf->hob_feature = scsicmd[3];
- tf->hob_nsect = scsicmd[5];
- tf->hob_lbal = scsicmd[7];
- tf->hob_lbam = scsicmd[9];
- tf->hob_lbah = scsicmd[11];
+ if (cdb[1] & 0x01) {
+ tf->hob_feature = cdb[3];
+ tf->hob_nsect = cdb[5];
+ tf->hob_lbal = cdb[7];
+ tf->hob_lbam = cdb[9];
+ tf->hob_lbah = cdb[11];
tf->flags |= ATA_TFLAG_LBA48;
} else
tf->flags &= ~ATA_TFLAG_LBA48;
@@ -2565,26 +2646,26 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
/*
* Always copy low byte, device and command registers.
*/
- tf->feature = scsicmd[4];
- tf->nsect = scsicmd[6];
- tf->lbal = scsicmd[8];
- tf->lbam = scsicmd[10];
- tf->lbah = scsicmd[12];
- tf->device = scsicmd[13];
- tf->command = scsicmd[14];
+ tf->feature = cdb[4];
+ tf->nsect = cdb[6];
+ tf->lbal = cdb[8];
+ tf->lbam = cdb[10];
+ tf->lbah = cdb[12];
+ tf->device = cdb[13];
+ tf->command = cdb[14];
} else {
/*
* 12-byte CDB - incapable of extended commands.
*/
tf->flags &= ~ATA_TFLAG_LBA48;
- tf->feature = scsicmd[3];
- tf->nsect = scsicmd[4];
- tf->lbal = scsicmd[5];
- tf->lbam = scsicmd[6];
- tf->lbah = scsicmd[7];
- tf->device = scsicmd[8];
- tf->command = scsicmd[9];
+ tf->feature = cdb[3];
+ tf->nsect = cdb[4];
+ tf->lbal = cdb[5];
+ tf->lbam = cdb[6];
+ tf->lbah = cdb[7];
+ tf->device = cdb[8];
+ tf->command = cdb[9];
}
/*
* If slave is possible, enforce correct master/slave bit
@@ -2611,7 +2692,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
*/
tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE);
- if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ if (scmd->sc_data_direction == DMA_TO_DEVICE)
tf->flags |= ATA_TFLAG_WRITE;
/*
@@ -2620,7 +2701,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
* TODO: find out if we need to do more here to
* cover scatter/gather case.
*/
- qc->nsect = cmd->request_bufflen / ATA_SECT_SIZE;
+ qc->nbytes = scmd->request_bufflen;
/* request result TF */
qc->flags |= ATA_QCFLAG_RESULT_TF;
@@ -2628,7 +2709,7 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
return 0;
invalid_fld:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x00);
+ ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00);
/* "Invalid field in cdb" */
return 1;
}
@@ -2701,22 +2782,29 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap,
#endif
}
-static inline int __ata_scsi_queuecmd(struct scsi_cmnd *cmd,
+static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
void (*done)(struct scsi_cmnd *),
struct ata_device *dev)
{
int rc = 0;
+ if (unlikely(!scmd->cmd_len)) {
+ ata_dev_printk(dev, KERN_WARNING, "WARNING: zero len CDB\n");
+ scmd->result = DID_ERROR << 16;
+ done(scmd);
+ return 0;
+ }
+
if (dev->class == ATA_DEV_ATA) {
ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
- cmd->cmnd[0]);
+ scmd->cmnd[0]);
if (xlat_func)
- rc = ata_scsi_translate(dev, cmd, done, xlat_func);
+ rc = ata_scsi_translate(dev, scmd, done, xlat_func);
else
- ata_scsi_simulate(dev, cmd, done);
+ ata_scsi_simulate(dev, scmd, done);
} else
- rc = ata_scsi_translate(dev, cmd, done, atapi_xlat);
+ rc = ata_scsi_translate(dev, scmd, done, atapi_xlat);
return rc;
}
@@ -3011,7 +3099,8 @@ void ata_scsi_hotplug(struct work_struct *work)
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
if (ata_dev_enabled(dev) && !dev->sdev) {
- queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ);
+ queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+ round_jiffies_relative(HZ));
break;
}
}
@@ -3216,7 +3305,8 @@ EXPORT_SYMBOL_GPL(ata_sas_port_init);
void ata_sas_port_destroy(struct ata_port *ap)
{
- ap->ops->port_stop(ap);
+ if (ap->ops->port_stop)
+ ap->ops->port_stop(ap);
kfree(ap);
}
EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 10ee22ae5c1..16bc3e35bdd 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -56,10 +56,7 @@ u8 ata_irq_on(struct ata_port *ap)
ap->ctl &= ~ATA_NIEN;
ap->last_ctl = ap->ctl;
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- else
- outb(ap->ctl, ioaddr->ctl_addr);
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
tmp = ata_wait_idle(ap);
ap->ops->irq_clear(ap);
@@ -67,92 +64,74 @@ u8 ata_irq_on(struct ata_port *ap)
return tmp;
}
+u8 ata_dummy_irq_on (struct ata_port *ap) { return 0; }
+
/**
- * ata_tf_load_pio - send taskfile registers to host controller
- * @ap: Port to which output is sent
- * @tf: ATA taskfile register set
+ * ata_irq_ack - Acknowledge a device interrupt.
+ * @ap: Port on which interrupts are enabled.
*
- * Outputs ATA taskfile to standard ATA host controller.
+ * Wait up to 10 ms for legacy IDE device to become idle (BUSY
+ * or BUSY+DRQ clear). Obtain dma status and port status from
+ * device. Clear the interrupt. Return port status.
*
* LOCKING:
- * Inherited from caller.
*/
-static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf)
+u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+ unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
+ u8 host_stat, post_stat, status;
- if (tf->ctl != ap->last_ctl) {
- outb(tf->ctl, ioaddr->ctl_addr);
- ap->last_ctl = tf->ctl;
- ata_wait_idle(ap);
- }
+ status = ata_busy_wait(ap, bits, 1000);
+ if (status & bits)
+ if (ata_msg_err(ap))
+ printk(KERN_ERR "abnormal status 0x%X\n", status);
- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- outb(tf->hob_feature, ioaddr->feature_addr);
- outb(tf->hob_nsect, ioaddr->nsect_addr);
- outb(tf->hob_lbal, ioaddr->lbal_addr);
- outb(tf->hob_lbam, ioaddr->lbam_addr);
- outb(tf->hob_lbah, ioaddr->lbah_addr);
- VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
- tf->hob_feature,
- tf->hob_nsect,
- tf->hob_lbal,
- tf->hob_lbam,
- tf->hob_lbah);
- }
+ /* get controller status; clear intr, err bits */
+ host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
+ ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- if (is_addr) {
- outb(tf->feature, ioaddr->feature_addr);
- outb(tf->nsect, ioaddr->nsect_addr);
- outb(tf->lbal, ioaddr->lbal_addr);
- outb(tf->lbam, ioaddr->lbam_addr);
- outb(tf->lbah, ioaddr->lbah_addr);
- VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
- tf->feature,
- tf->nsect,
- tf->lbal,
- tf->lbam,
- tf->lbah);
- }
+ post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- if (tf->flags & ATA_TFLAG_DEVICE) {
- outb(tf->device, ioaddr->device_addr);
- VPRINTK("device 0x%X\n", tf->device);
- }
+ if (ata_msg_intr(ap))
+ printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
+ __FUNCTION__,
+ host_stat, post_stat, status);
- ata_wait_idle(ap);
+ return status;
}
+u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; }
+
/**
- * ata_tf_load_mmio - send taskfile registers to host controller
+ * ata_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
* @tf: ATA taskfile register set
*
- * Outputs ATA taskfile to standard ATA host controller using MMIO.
+ * Outputs ATA taskfile to standard ATA host controller.
*
* LOCKING:
* Inherited from caller.
*/
-static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
if (tf->ctl != ap->last_ctl) {
- writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+ iowrite8(tf->ctl, ioaddr->ctl_addr);
ap->last_ctl = tf->ctl;
ata_wait_idle(ap);
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
- writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
- writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
- writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
- writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
+ iowrite8(tf->hob_feature, ioaddr->feature_addr);
+ iowrite8(tf->hob_nsect, ioaddr->nsect_addr);
+ iowrite8(tf->hob_lbal, ioaddr->lbal_addr);
+ iowrite8(tf->hob_lbam, ioaddr->lbam_addr);
+ iowrite8(tf->hob_lbah, ioaddr->lbah_addr);
VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
tf->hob_feature,
tf->hob_nsect,
@@ -162,11 +141,11 @@ static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
}
if (is_addr) {
- writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
- writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
- writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
- writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
- writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
+ iowrite8(tf->feature, ioaddr->feature_addr);
+ iowrite8(tf->nsect, ioaddr->nsect_addr);
+ iowrite8(tf->lbal, ioaddr->lbal_addr);
+ iowrite8(tf->lbam, ioaddr->lbam_addr);
+ iowrite8(tf->lbah, ioaddr->lbah_addr);
VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
tf->feature,
tf->nsect,
@@ -176,108 +155,34 @@ static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
}
if (tf->flags & ATA_TFLAG_DEVICE) {
- writeb(tf->device, (void __iomem *) ioaddr->device_addr);
+ iowrite8(tf->device, ioaddr->device_addr);
VPRINTK("device 0x%X\n", tf->device);
}
ata_wait_idle(ap);
}
-
-/**
- * ata_tf_load - send taskfile registers to host controller
- * @ap: Port to which output is sent
- * @tf: ATA taskfile register set
- *
- * Outputs ATA taskfile to standard ATA host controller using MMIO
- * or PIO as indicated by the ATA_FLAG_MMIO flag.
- * Writes the control, feature, nsect, lbal, lbam, and lbah registers.
- * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
- * hob_lbal, hob_lbam, and hob_lbah.
- *
- * This function waits for idle (!BUSY and !DRQ) after writing
- * registers. If the control register has a new value, this
- * function also waits for idle after writing control and before
- * writing the remaining registers.
- *
- * May be used as the tf_load() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_tf_load_mmio(ap, tf);
- else
- ata_tf_load_pio(ap, tf);
-}
-
-/**
- * ata_exec_command_pio - issue ATA command to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues PIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-
-static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
-
- outb(tf->command, ap->ioaddr.command_addr);
- ata_pause(ap);
-}
-
-
/**
- * ata_exec_command_mmio - issue ATA command to host controller
+ * ata_exec_command - issue ATA command to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
- * Issues MMIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * FIXME: missing write posting for 400nS delay enforcement
+ * Issues ATA command, with proper synchronization with interrupt
+ * handler / other threads.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
{
DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
- writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
+ iowrite8(tf->command, ap->ioaddr.command_addr);
ata_pause(ap);
}
-
/**
- * ata_exec_command - issue ATA command to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues PIO/MMIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_exec_command_mmio(ap, tf);
- else
- ata_exec_command_pio(ap, tf);
-}
-
-/**
- * ata_tf_read_pio - input device's ATA taskfile shadow registers
+ * ata_tf_read - input device's ATA taskfile shadow registers
* @ap: Port from which input is read
* @tf: ATA taskfile register set for storing input
*
@@ -287,121 +192,28 @@ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
* LOCKING:
* Inherited from caller.
*/
-
-static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- tf->command = ata_check_status(ap);
- tf->feature = inb(ioaddr->error_addr);
- tf->nsect = inb(ioaddr->nsect_addr);
- tf->lbal = inb(ioaddr->lbal_addr);
- tf->lbam = inb(ioaddr->lbam_addr);
- tf->lbah = inb(ioaddr->lbah_addr);
- tf->device = inb(ioaddr->device_addr);
-
- if (tf->flags & ATA_TFLAG_LBA48) {
- outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
- tf->hob_feature = inb(ioaddr->error_addr);
- tf->hob_nsect = inb(ioaddr->nsect_addr);
- tf->hob_lbal = inb(ioaddr->lbal_addr);
- tf->hob_lbam = inb(ioaddr->lbam_addr);
- tf->hob_lbah = inb(ioaddr->lbah_addr);
- }
-}
-
-/**
- * ata_tf_read_mmio - input device's ATA taskfile shadow registers
- * @ap: Port from which input is read
- * @tf: ATA taskfile register set for storing input
- *
- * Reads ATA taskfile registers for currently-selected device
- * into @tf via MMIO.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
tf->command = ata_check_status(ap);
- tf->feature = readb((void __iomem *)ioaddr->error_addr);
- tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
- tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
- tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
- tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
- tf->device = readb((void __iomem *)ioaddr->device_addr);
+ tf->feature = ioread8(ioaddr->error_addr);
+ tf->nsect = ioread8(ioaddr->nsect_addr);
+ tf->lbal = ioread8(ioaddr->lbal_addr);
+ tf->lbam = ioread8(ioaddr->lbam_addr);
+ tf->lbah = ioread8(ioaddr->lbah_addr);
+ tf->device = ioread8(ioaddr->device_addr);
if (tf->flags & ATA_TFLAG_LBA48) {
- writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
- tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
- tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
- tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
- tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
- tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
+ iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+ tf->hob_feature = ioread8(ioaddr->error_addr);
+ tf->hob_nsect = ioread8(ioaddr->nsect_addr);
+ tf->hob_lbal = ioread8(ioaddr->lbal_addr);
+ tf->hob_lbam = ioread8(ioaddr->lbam_addr);
+ tf->hob_lbah = ioread8(ioaddr->lbah_addr);
}
}
-
-/**
- * ata_tf_read - input device's ATA taskfile shadow registers
- * @ap: Port from which input is read
- * @tf: ATA taskfile register set for storing input
- *
- * Reads ATA taskfile registers for currently-selected device
- * into @tf.
- *
- * Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48
- * is set, also reads the hob registers.
- *
- * May be used as the tf_read() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_tf_read_mmio(ap, tf);
- else
- ata_tf_read_pio(ap, tf);
-}
-
-/**
- * ata_check_status_pio - Read device status reg & clear interrupt
- * @ap: port where the device is
- *
- * Reads ATA taskfile status register for currently-selected device
- * and return its value. This also clears pending interrupts
- * from this device
- *
- * LOCKING:
- * Inherited from caller.
- */
-static u8 ata_check_status_pio(struct ata_port *ap)
-{
- return inb(ap->ioaddr.status_addr);
-}
-
-/**
- * ata_check_status_mmio - Read device status reg & clear interrupt
- * @ap: port where the device is
- *
- * Reads ATA taskfile status register for currently-selected device
- * via MMIO and return its value. This also clears pending interrupts
- * from this device
- *
- * LOCKING:
- * Inherited from caller.
- */
-static u8 ata_check_status_mmio(struct ata_port *ap)
-{
- return readb((void __iomem *) ap->ioaddr.status_addr);
-}
-
-
/**
* ata_check_status - Read device status reg & clear interrupt
* @ap: port where the device is
@@ -410,19 +222,14 @@ static u8 ata_check_status_mmio(struct ata_port *ap)
* and return its value. This also clears pending interrupts
* from this device
*
- * May be used as the check_status() entry in ata_port_operations.
- *
* LOCKING:
* Inherited from caller.
*/
u8 ata_check_status(struct ata_port *ap)
{
- if (ap->flags & ATA_FLAG_MMIO)
- return ata_check_status_mmio(ap);
- return ata_check_status_pio(ap);
+ return ioread8(ap->ioaddr.status_addr);
}
-
/**
* ata_altstatus - Read device alternate status reg
* @ap: port where the device is
@@ -441,58 +248,52 @@ u8 ata_altstatus(struct ata_port *ap)
if (ap->ops->check_altstatus)
return ap->ops->check_altstatus(ap);
- if (ap->flags & ATA_FLAG_MMIO)
- return readb((void __iomem *)ap->ioaddr.altstatus_addr);
- return inb(ap->ioaddr.altstatus_addr);
+ return ioread8(ap->ioaddr.altstatus_addr);
}
/**
- * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction
+ * ata_bmdma_setup - Set up PCI IDE BMDMA transaction
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+void ata_bmdma_setup(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
u8 dmactl;
- 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);
+ iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
/* specify data direction, triple-check start bit is clear */
- dmactl = readb(mmio + ATA_DMA_CMD);
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
if (!rw)
dmactl |= ATA_DMA_WR;
- writeb(dmactl, mmio + ATA_DMA_CMD);
+ iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
/* issue r/w command */
ap->ops->exec_command(ap, &qc->tf);
}
/**
- * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction
+ * ata_bmdma_start - Start a PCI IDE BMDMA transaction
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
+void ata_bmdma_start (struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
u8 dmactl;
/* start host DMA transaction */
- dmactl = readb(mmio + ATA_DMA_CMD);
- writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
/* Strictly, one may wish to issue a readb() here, to
* flush the mmio write. However, control also passes
@@ -508,96 +309,6 @@ static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
}
/**
- * ata_bmdma_setup_pio - Set up PCI IDE BMDMA transaction (PIO)
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-
-static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
- u8 dmactl;
-
- /* load PRD table addr. */
- outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
-
- /* specify data direction, triple-check start bit is clear */
- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
- if (!rw)
- dmactl |= ATA_DMA_WR;
- outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-
- /* issue r/w command */
- ap->ops->exec_command(ap, &qc->tf);
-}
-
-/**
- * ata_bmdma_start_pio - Start a PCI IDE BMDMA transaction (PIO)
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-
-static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- u8 dmactl;
-
- /* start host DMA transaction */
- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- outb(dmactl | ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-}
-
-
-/**
- * ata_bmdma_start - Start a PCI IDE BMDMA transaction
- * @qc: Info associated with this ATA transaction.
- *
- * Writes the ATA_DMA_START flag to the DMA command register.
- *
- * May be used as the bmdma_start() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_bmdma_start(struct ata_queued_cmd *qc)
-{
- if (qc->ap->flags & ATA_FLAG_MMIO)
- ata_bmdma_start_mmio(qc);
- else
- ata_bmdma_start_pio(qc);
-}
-
-
-/**
- * ata_bmdma_setup - Set up PCI IDE BMDMA transaction
- * @qc: Info associated with this ATA transaction.
- *
- * Writes address of PRD table to device's PRD Table Address
- * register, sets the DMA control register, and calls
- * ops->exec_command() to start the transfer.
- *
- * May be used as the bmdma_setup() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_bmdma_setup(struct ata_queued_cmd *qc)
-{
- if (qc->ap->flags & ATA_FLAG_MMIO)
- ata_bmdma_setup_mmio(qc);
- else
- ata_bmdma_setup_pio(qc);
-}
-
-
-/**
* ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
* @ap: Port associated with this ATA transaction.
*
@@ -608,23 +319,16 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
void ata_bmdma_irq_clear(struct ata_port *ap)
{
- if (!ap->ioaddr.bmdma_addr)
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ if (!mmio)
return;
- if (ap->flags & ATA_FLAG_MMIO) {
- void __iomem *mmio =
- ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
- writeb(readb(mmio), mmio);
- } else {
- unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
- outb(inb(addr), addr);
- }
+ iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS);
}
-
/**
* ata_bmdma_status - Read PCI IDE BMDMA status
* @ap: Port associated with this ATA transaction.
@@ -636,19 +340,11 @@ void ata_bmdma_irq_clear(struct ata_port *ap)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
u8 ata_bmdma_status(struct ata_port *ap)
{
- u8 host_stat;
- if (ap->flags & ATA_FLAG_MMIO) {
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
- host_stat = readb(mmio + ATA_DMA_STATUS);
- } else
- host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- return host_stat;
+ return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
}
-
/**
* ata_bmdma_stop - Stop PCI IDE BMDMA transfer
* @qc: Command we are ending DMA for
@@ -660,21 +356,14 @@ u8 ata_bmdma_status(struct ata_port *ap)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
void ata_bmdma_stop(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- if (ap->flags & ATA_FLAG_MMIO) {
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
- /* clear start/stop bit */
- writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
- mmio + ATA_DMA_CMD);
- } else {
- /* clear start/stop bit */
- outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- }
+ /* clear start/stop bit */
+ iowrite8(ioread8(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
+ mmio + ATA_DMA_CMD);
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
ata_altstatus(ap); /* dummy read */
@@ -696,10 +385,7 @@ void ata_bmdma_freeze(struct ata_port *ap)
ap->ctl |= ATA_NIEN;
ap->last_ctl = ap->ctl;
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr);
- else
- outb(ap->ctl, ioaddr->ctl_addr);
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
/* Under certain circumstances, some controllers raise IRQ on
* ATA_NIEN manipulation. Also, many controllers fail to mask
@@ -724,8 +410,7 @@ void ata_bmdma_thaw(struct ata_port *ap)
/* clear & re-enable interrupts */
ata_chk_status(ap);
ap->ops->irq_clear(ap);
- if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
- ata_irq_on(ap);
+ ap->ops->irq_on(ap);
}
/**
@@ -775,7 +460,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
* really a timeout event, adjust error mask and
* cancel frozen state.
*/
- if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) {
+ if (qc->err_mask == AC_ERR_TIMEOUT && (host_stat & ATA_DMA_ERR)) {
qc->err_mask = AC_ERR_HOST_BUS;
thaw = 1;
}
@@ -827,10 +512,26 @@ void ata_bmdma_error_handler(struct ata_port *ap)
*/
void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
{
- ata_bmdma_stop(qc);
+ if (qc->ap->ioaddr.bmdma_addr)
+ ata_bmdma_stop(qc);
}
#ifdef CONFIG_PCI
+
+static int ata_resources_present(struct pci_dev *pdev, int port)
+{
+ int i;
+
+ /* Check the PCI resources for this channel are enabled */
+ port = port * 2;
+ for (i = 0; i < 2; i ++) {
+ if (pci_resource_start(pdev, port + i) == 0 ||
+ pci_resource_len(pdev, port + i) == 0)
+ return 0;
+ }
+ return 1;
+}
+
/**
* ata_pci_init_native_mode - Initialize native-mode driver
* @pdev: pci device to be initialized
@@ -852,43 +553,62 @@ void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
struct ata_probe_ent *
ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
{
- struct ata_probe_ent *probe_ent =
- ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
- int p = 0;
- unsigned long bmdma;
+ struct ata_probe_ent *probe_ent;
+ int i, p = 0;
+ void __iomem * const *iomap;
+
+ /* iomap BARs */
+ for (i = 0; i < 4; i++) {
+ if (pcim_iomap(pdev, i, 0) == NULL) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to iomap PCI BAR %d\n", i);
+ return NULL;
+ }
+ }
+
+ pcim_iomap(pdev, 4, 0); /* may fail */
+ iomap = pcim_iomap_table(pdev);
+ /* alloc and init probe_ent */
+ probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
if (!probe_ent)
return NULL;
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
+
+ /* Discard disabled ports. Some controllers show their
+ unused channels this way */
+ if (ata_resources_present(pdev, 0) == 0)
+ ports &= ~ATA_PORT_PRIMARY;
+ if (ata_resources_present(pdev, 1) == 0)
+ ports &= ~ATA_PORT_SECONDARY;
if (ports & ATA_PORT_PRIMARY) {
- probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
+ probe_ent->port[p].cmd_addr = iomap[0];
probe_ent->port[p].altstatus_addr =
- probe_ent->port[p].ctl_addr =
- pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
- bmdma = pci_resource_start(pdev, 4);
- if (bmdma) {
- if (inb(bmdma + 2) & 0x80)
+ probe_ent->port[p].ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS);
+ if (iomap[4]) {
+ if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
+ (ioread8(iomap[4] + 2) & 0x80))
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
- probe_ent->port[p].bmdma_addr = bmdma;
+ probe_ent->port[p].bmdma_addr = iomap[4];
}
ata_std_ports(&probe_ent->port[p]);
p++;
}
if (ports & ATA_PORT_SECONDARY) {
- probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
+ probe_ent->port[p].cmd_addr = iomap[2];
probe_ent->port[p].altstatus_addr =
- probe_ent->port[p].ctl_addr =
- pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
- bmdma = pci_resource_start(pdev, 4);
- if (bmdma) {
- bmdma += 8;
- if(inb(bmdma + 2) & 0x80)
+ probe_ent->port[p].ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS);
+ if (iomap[4]) {
+ if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
+ (ioread8(iomap[4] + 10) & 0x80))
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
- probe_ent->port[p].bmdma_addr = bmdma;
+ probe_ent->port[p].bmdma_addr = iomap[4] + 8;
}
ata_std_ports(&probe_ent->port[p]);
probe_ent->pinfo2 = port[1];
@@ -899,13 +619,29 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
return probe_ent;
}
-
static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
struct ata_port_info **port, int port_mask)
{
struct ata_probe_ent *probe_ent;
- unsigned long bmdma = pci_resource_start(pdev, 4);
+ void __iomem *iomap[5] = { }, *bmdma;
+
+ if (port_mask & ATA_PORT_PRIMARY) {
+ iomap[0] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CMD, 8);
+ iomap[1] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CTL, 1);
+ if (!iomap[0] || !iomap[1])
+ return NULL;
+ }
+
+ if (port_mask & ATA_PORT_SECONDARY) {
+ iomap[2] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CMD, 8);
+ iomap[3] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CTL, 1);
+ if (!iomap[2] || !iomap[3])
+ return NULL;
+ }
+
+ bmdma = pcim_iomap(pdev, 4, 16); /* may fail */
+ /* alloc and init probe_ent */
probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
if (!probe_ent)
return NULL;
@@ -914,13 +650,14 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
probe_ent->irq_flags = IRQF_SHARED;
if (port_mask & ATA_PORT_PRIMARY) {
- probe_ent->irq = ATA_PRIMARY_IRQ;
- probe_ent->port[0].cmd_addr = ATA_PRIMARY_CMD;
+ probe_ent->irq = ATA_PRIMARY_IRQ(pdev);
+ probe_ent->port[0].cmd_addr = iomap[0];
probe_ent->port[0].altstatus_addr =
- probe_ent->port[0].ctl_addr = ATA_PRIMARY_CTL;
+ probe_ent->port[0].ctl_addr = iomap[1];
if (bmdma) {
probe_ent->port[0].bmdma_addr = bmdma;
- if (inb(bmdma + 2) & 0x80)
+ if ((!(port[0]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
+ (ioread8(bmdma + 2) & 0x80))
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
}
ata_std_ports(&probe_ent->port[0]);
@@ -929,15 +666,16 @@ 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 = ATA_SECONDARY_IRQ;
+ probe_ent->irq2 = ATA_SECONDARY_IRQ(pdev);
else
- probe_ent->irq = ATA_SECONDARY_IRQ;
- probe_ent->port[1].cmd_addr = ATA_SECONDARY_CMD;
+ probe_ent->irq = ATA_SECONDARY_IRQ(pdev);
+ probe_ent->port[1].cmd_addr = iomap[2];
probe_ent->port[1].altstatus_addr =
- probe_ent->port[1].ctl_addr = ATA_SECONDARY_CTL;
+ probe_ent->port[1].ctl_addr = iomap[3];
if (bmdma) {
probe_ent->port[1].bmdma_addr = bmdma + 8;
- if (inb(bmdma + 10) & 0x80)
+ if ((!(port[1]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
+ (ioread8(bmdma + 10) & 0x80))
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
}
ata_std_ports(&probe_ent->port[1]);
@@ -979,15 +717,18 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
unsigned int n_ports)
{
+ struct device *dev = &pdev->dev;
struct ata_probe_ent *probe_ent = NULL;
struct ata_port_info *port[2];
u8 mask;
unsigned int legacy_mode = 0;
- int disable_dev_on_err = 1;
int rc;
DPRINTK("ENTER\n");
+ if (!devres_open_group(dev, NULL, GFP_KERNEL))
+ return -ENOMEM;
+
BUG_ON(n_ports < 1 || n_ports > 2);
port[0] = port_info[0];
@@ -1004,9 +745,9 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
boot for the primary video which is BIOS enabled
*/
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
- return rc;
+ goto err_out;
if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
u8 tmp8;
@@ -1022,19 +763,22 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
left a device in compatibility mode */
if (legacy_mode) {
printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
- return -EOPNOTSUPP;
+ rc = -EOPNOTSUPP;
+ goto err_out;
}
#endif
}
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- disable_dev_on_err = 0;
- goto err_out;
- }
-
- if (legacy_mode) {
- if (!request_region(ATA_PRIMARY_CMD, 8, "libata")) {
+ if (!legacy_mode) {
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pcim_pin_device(pdev);
+ goto err_out;
+ }
+ } else {
+ /* Deal with combined mode hack. This side of the logic all
+ goes away once the combined mode hack is killed in 2.6.21 */
+ if (!devm_request_region(dev, ATA_PRIMARY_CMD, 8, "libata")) {
struct resource *conflict, res;
res.start = ATA_PRIMARY_CMD;
res.end = ATA_PRIMARY_CMD + 8 - 1;
@@ -1044,7 +788,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
if (!strcmp(conflict->name, "libata"))
legacy_mode |= ATA_PORT_PRIMARY;
else {
- disable_dev_on_err = 0;
+ pcim_pin_device(pdev);
printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \
"ata: conflict with %s\n",
ATA_PRIMARY_CMD,
@@ -1053,7 +797,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
} else
legacy_mode |= ATA_PORT_PRIMARY;
- if (!request_region(ATA_SECONDARY_CMD, 8, "libata")) {
+ if (!devm_request_region(dev, ATA_SECONDARY_CMD, 8, "libata")) {
struct resource *conflict, res;
res.start = ATA_SECONDARY_CMD;
res.end = ATA_SECONDARY_CMD + 8 - 1;
@@ -1063,7 +807,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
if (!strcmp(conflict->name, "libata"))
legacy_mode |= ATA_PORT_SECONDARY;
else {
- disable_dev_on_err = 0;
+ pcim_pin_device(pdev);
printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \
"ata: conflict with %s\n",
ATA_SECONDARY_CMD,
@@ -1071,21 +815,28 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
}
} else
legacy_mode |= ATA_PORT_SECONDARY;
+
+ if (legacy_mode & ATA_PORT_PRIMARY)
+ pci_request_region(pdev, 1, DRV_NAME);
+ if (legacy_mode & ATA_PORT_SECONDARY)
+ pci_request_region(pdev, 3, DRV_NAME);
+ /* If there is a DMA resource, allocate it */
+ pci_request_region(pdev, 4, DRV_NAME);
}
/* we have legacy mode, but all ports are unavailable */
if (legacy_mode == (1 << 3)) {
rc = -EBUSY;
- goto err_out_regions;
+ goto err_out;
}
/* 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;
+ goto err_out;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ goto err_out;
if (legacy_mode) {
probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode);
@@ -1097,31 +848,22 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
}
if (!probe_ent) {
rc = -ENOMEM;
- goto err_out_regions;
+ goto err_out;
}
pci_set_master(pdev);
if (!ata_device_add(probe_ent)) {
rc = -ENODEV;
- goto err_out_ent;
+ goto err_out;
}
- kfree(probe_ent);
-
+ devm_kfree(dev, probe_ent);
+ devres_remove_group(dev, NULL);
return 0;
-err_out_ent:
- kfree(probe_ent);
-err_out_regions:
- if (legacy_mode & ATA_PORT_PRIMARY)
- release_region(ATA_PRIMARY_CMD, 8);
- if (legacy_mode & ATA_PORT_SECONDARY)
- release_region(ATA_SECONDARY_CMD, 8);
- pci_release_regions(pdev);
err_out:
- if (disable_dev_on_err)
- pci_disable_device(pdev);
+ devres_release_group(dev, NULL);
return rc;
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 81ae41d5f23..06ccf230e3c 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -29,7 +29,6 @@
#define __LIBATA_H__
#define DRV_NAME "libata"
-#define DRV_VERSION "2.00" /* must be exactly four chars */
struct ata_scsi_args {
struct ata_device *dev;
@@ -136,4 +135,7 @@ extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
/* libata-sff.c */
extern u8 ata_irq_on(struct ata_port *ap);
+/* pata_sis.c */
+extern struct ata_port_info sis_info133;
+
#endif /* __LIBATA_H__ */
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index c5d61d1911a..ab44d18850f 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -153,11 +153,11 @@ static void ali_early_error_handler(struct ata_port *ap)
static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
{
- char model_num[40];
+ char model_num[ATA_ID_PROD_LEN + 1];
/* No DMA on anything but a disk for now */
if (adev->class != ATA_DEV_ATA)
mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
- ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+ ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
if (strstr(model_num, "WDC"))
return mask &= ~ATA_MASK_UDMA;
return ata_pci_default_filter(ap, adev, mask);
@@ -370,14 +370,14 @@ static struct ata_port_operations ali_early_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -411,14 +411,14 @@ static struct ata_port_operations ali_20_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -449,14 +449,14 @@ static struct ata_port_operations ali_c2_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -486,14 +486,14 @@ static struct ata_port_operations ali_c5_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
@@ -504,7 +504,7 @@ static struct ata_port_operations ali_c5_port_ops = {
* Perform the setup on the device that must be done both at boot
* and at resume time.
*/
-
+
static void ali_init_chipset(struct pci_dev *pdev)
{
u8 rev, tmp;
@@ -655,7 +655,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
port_info[0] = port_info[1] = &info_c5;
ali_init_chipset(pdev);
-
+
isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
if (isa_bridge && rev >= 0x20 && rev < 0xC2) {
/* Are we paired with a UDMA capable chip */
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index a6b330089f2..619e44b0403 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -362,14 +362,14 @@ static struct ata_port_operations amd33_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations amd66_port_ops = {
@@ -396,14 +396,14 @@ static struct ata_port_operations amd66_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations amd100_port_ops = {
@@ -430,14 +430,14 @@ static struct ata_port_operations amd100_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations amd133_port_ops = {
@@ -464,14 +464,14 @@ static struct ata_port_operations amd133_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations nv100_port_ops = {
@@ -498,14 +498,14 @@ static struct ata_port_operations nv100_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations nv133_port_ops = {
@@ -532,14 +532,14 @@ static struct ata_port_operations nv133_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index 37bc1323bda..21c30282717 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -341,14 +341,14 @@ static const struct ata_port_operations artop6210_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static const struct ata_port_operations artop6260_ops = {
@@ -373,14 +373,14 @@ static const struct ata_port_operations artop6260_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 6f6672c5513..c3eb40c91c8 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -36,15 +36,22 @@ enum {
static int atiixp_pre_reset(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- static struct pci_bits atiixp_enable_bits[] = {
+ static const struct pci_bits atiixp_enable_bits[] = {
{ 0x48, 1, 0x01, 0x00 },
{ 0x48, 1, 0x08, 0x00 }
};
+ u8 udma;
if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
return -ENOENT;
- ap->cbl = ATA_CBL_PATA80;
+ /* Hack from drivers/ide/pci. Really we want to know how to do the
+ raw detection not play follow the bios mode guess */
+ pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma);
+ if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40)
+ ap->cbl = ATA_CBL_PATA80;
+ else
+ ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
@@ -245,14 +252,14 @@ static struct ata_port_operations atiixp_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index 15841a56369..da098282b5f 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -197,7 +197,7 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
static const u8 udma_data[] = {
- 0x31, 0x21, 0x11, 0x25, 0x15, 0x05
+ 0x30, 0x20, 0x10, 0x20, 0x10, 0x00
};
static const u8 mwdma_data[] = {
0x30, 0x20, 0x10
@@ -213,12 +213,21 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
pci_read_config_byte(pdev, pciD, &regD);
pci_read_config_byte(pdev, pciU, &regU);
- regD &= ~(0x20 << shift);
- regU &= ~(0x35 << shift);
+ /* DMA bits off */
+ regD &= ~(0x20 << adev->devno);
+ /* DMA control bits */
+ regU &= ~(0x30 << shift);
+ /* DMA timing bits */
+ regU &= ~(0x05 << adev->devno);
- if (adev->dma_mode >= XFER_UDMA_0)
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ /* Merge thge timing value */
regU |= udma_data[adev->dma_mode - XFER_UDMA_0] << shift;
- else
+ /* Merge the control bits */
+ regU |= 1 << adev->devno; /* UDMA on */
+ if (adev->dma_mode > 2) /* 15nS timing */
+ regU |= 4 << adev->devno;
+ } else
regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift;
regD |= 0x20 << adev->devno;
@@ -239,8 +248,8 @@ static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 dma_intr;
- int dma_reg = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
- int dma_mask = ap->port_no ? ARTTIM2 : CFR;
+ int dma_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
+ int dma_reg = ap->port_no ? ARTTIM2 : CFR;
ata_bmdma_stop(qc);
@@ -304,14 +313,14 @@ static struct ata_port_operations cmd64x_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations cmd646r1_port_ops = {
@@ -338,14 +347,14 @@ static struct ata_port_operations cmd646r1_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations cmd648_port_ops = {
@@ -372,14 +381,14 @@ static struct ata_port_operations cmd648_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 9f165a8e032..1ce8fcfd782 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -99,9 +99,9 @@ static void cs5520_set_timings(struct ata_port *ap, struct ata_device *adev, int
static void cs5520_enable_dma(struct ata_port *ap, struct ata_device *adev)
{
/* Set the DMA enable/disable flag */
- u8 reg = inb(ap->ioaddr.bmdma_addr + 0x02);
+ u8 reg = ioread8(ap->ioaddr.bmdma_addr + 0x02);
reg |= 1<<(adev->devno + 5);
- outb(reg, ap->ioaddr.bmdma_addr + 0x02);
+ iowrite8(reg, ap->ioaddr.bmdma_addr + 0x02);
}
/**
@@ -193,19 +193,20 @@ static struct ata_port_operations cs5520_port_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
u8 pcicfg;
+ void *iomap[5];
static struct ata_probe_ent probe[2];
int ports = 0;
@@ -236,6 +237,16 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
return -ENODEV;
}
+ /* Map IO ports */
+ iomap[0] = devm_ioport_map(&dev->dev, 0x1F0, 8);
+ iomap[1] = devm_ioport_map(&dev->dev, 0x3F6, 1);
+ iomap[2] = devm_ioport_map(&dev->dev, 0x170, 8);
+ iomap[3] = devm_ioport_map(&dev->dev, 0x376, 1);
+ iomap[4] = pcim_iomap(dev, 2, 0);
+
+ if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
+ return -ENOMEM;
+
/* We have to do our own plumbing as the PCI setup for this
chipset is non-standard so we can't punt to the libata code */
@@ -249,10 +260,10 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
probe[0].irq_flags = 0;
probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
probe[0].n_ports = 1;
- probe[0].port[0].cmd_addr = 0x1F0;
- probe[0].port[0].ctl_addr = 0x3F6;
- probe[0].port[0].altstatus_addr = 0x3F6;
- probe[0].port[0].bmdma_addr = pci_resource_start(dev, 2);
+ probe[0].port[0].cmd_addr = iomap[0];
+ probe[0].port[0].ctl_addr = iomap[1];
+ probe[0].port[0].altstatus_addr = iomap[1];
+ probe[0].port[0].bmdma_addr = iomap[4];
/* The secondary lurks at different addresses but is otherwise
the same beastie */
@@ -260,10 +271,10 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
probe[1] = probe[0];
INIT_LIST_HEAD(&probe[1].node);
probe[1].irq = 15;
- probe[1].port[0].cmd_addr = 0x170;
- probe[1].port[0].ctl_addr = 0x376;
- probe[1].port[0].altstatus_addr = 0x376;
- probe[1].port[0].bmdma_addr = pci_resource_start(dev, 2) + 8;
+ probe[1].port[0].cmd_addr = iomap[2];
+ probe[1].port[0].ctl_addr = iomap[3];
+ probe[1].port[0].altstatus_addr = iomap[3];
+ probe[1].port[0].bmdma_addr = iomap[4] + 8;
/* Let libata fill in the port details */
ata_std_ports(&probe[0].port[0]);
@@ -294,7 +305,7 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev)
struct device *dev = pci_dev_to_dev(pdev);
struct ata_host *host = dev_get_drvdata(dev);
- ata_host_remove(host);
+ ata_host_detach(host);
dev_set_drvdata(dev, NULL);
}
@@ -305,7 +316,7 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev)
* Do any reconfiguration work needed by a resume from RAM. We need
* to restore DMA mode support on BIOSen which disabled it
*/
-
+
static int cs5520_reinit_one(struct pci_dev *pdev)
{
u8 pcicfg;
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index 1c628014dae..3d7b7d87ec6 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -37,6 +37,13 @@
#define DRV_NAME "pata_cs5530"
#define DRV_VERSION "0.7.1"
+static void __iomem *cs5530_port_base(struct ata_port *ap)
+{
+ unsigned long bmdma = (unsigned long)ap->ioaddr.bmdma_addr;
+
+ return (void __iomem *)((bmdma & ~0x0F) + 0x20 + 0x10 * ap->port_no);
+}
+
/**
* cs5530_set_piomode - PIO setup
* @ap: ATA interface
@@ -52,19 +59,19 @@ static void cs5530_set_piomode(struct ata_port *ap, struct ata_device *adev)
{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
{0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
};
- unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no;
+ void __iomem *base = cs5530_port_base(ap);
u32 tuning;
int format;
/* Find out which table to use */
- tuning = inl(base + 0x04);
+ tuning = ioread32(base + 0x04);
format = (tuning & 0x80000000UL) ? 1 : 0;
/* Now load the right timing register */
if (adev->devno)
base += 0x08;
- outl(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base);
+ iowrite32(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base);
}
/**
@@ -79,12 +86,12 @@ static void cs5530_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
- unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no;
+ void __iomem *base = cs5530_port_base(ap);
u32 tuning, timing = 0;
u8 reg;
/* Find out which table to use */
- tuning = inl(base + 0x04);
+ tuning = ioread32(base + 0x04);
switch(adev->dma_mode) {
case XFER_UDMA_0:
@@ -105,20 +112,20 @@ static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/* Merge in the PIO format bit */
timing |= (tuning & 0x80000000UL);
if (adev->devno == 0) /* Master */
- outl(timing, base + 0x04);
+ iowrite32(timing, base + 0x04);
else {
if (timing & 0x00100000)
tuning |= 0x00100000; /* UDMA for both */
else
tuning &= ~0x00100000; /* MWDMA for both */
- outl(tuning, base + 0x04);
- outl(timing, base + 0x0C);
+ iowrite32(tuning, base + 0x04);
+ iowrite32(timing, base + 0x0C);
}
/* Set the DMA capable bit in the BMDMA area */
- reg = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ reg = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
reg |= (1 << (5 + adev->devno));
- outb(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ iowrite8(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
/* Remember the last DMA setup we did */
@@ -210,14 +217,14 @@ static struct ata_port_operations cs5530_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = cs5530_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct dmi_system_id palmax_dmi_table[] = {
@@ -247,7 +254,7 @@ static int cs5530_is_palmax(void)
* Perform the chip initialisation work that is shared between both
* setup and resume paths
*/
-
+
static int cs5530_init_chip(void)
{
struct pci_dev *master_0 = NULL, *cs5530_0 = NULL, *dev = NULL;
@@ -357,11 +364,11 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
.port_ops = &cs5530_port_ops
};
static struct ata_port_info *port_info[2] = { &info, &info };
-
+
/* Chip initialisation */
if (cs5530_init_chip())
return -ENODEV;
-
+
if (cs5530_is_palmax())
port_info[1] = &info_palmax_secondary;
@@ -372,10 +379,11 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
static int cs5530_reinit_one(struct pci_dev *pdev)
{
/* If we fail on resume we are doomed */
- BUG_ON(cs5530_init_chip());
+ if (cs5530_init_chip())
+ BUG();
return ata_pci_device_resume(pdev);
}
-
+
static const struct pci_device_id cs5530[] = {
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index e3efec4ffc7..17bc693cc51 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -214,14 +214,14 @@ static struct ata_port_operations cs5535_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index e2a95699bae..63f48f08763 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -165,14 +165,14 @@ static struct ata_port_operations cy82c693_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index edf8a63f50a..c19b6a8a7dc 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -261,14 +261,14 @@ static const struct ata_port_operations efar_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 2663599a7c0..27d724b5eea 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -151,23 +151,13 @@ static const char *bad_ata66_3[] = {
static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
{
- unsigned char model_num[40];
- char *s;
- unsigned int len;
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
int i = 0;
- ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
- s = &model_num[0];
- len = strnlen(s, sizeof(model_num));
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
- /* ATAPI specifies that empty space is blank-filled; remove blanks */
- while ((len > 0) && (s[len - 1] == ' ')) {
- len--;
- s[len] = 0;
- }
-
- while(list[i] != NULL) {
- if (!strncmp(list[i], s, len)) {
+ while (list[i] != NULL) {
+ if (!strcmp(list[i], model_num)) {
printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
modestr, list[i]);
return 1;
@@ -232,7 +222,7 @@ static int hpt36x_pre_reset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no]))
return -ENOENT;
-
+
pci_read_config_byte(pdev, 0x5A, &ata66);
if (ata66 & (1 << ap->port_no))
ap->cbl = ATA_CBL_PATA40;
@@ -371,14 +361,14 @@ static struct ata_port_operations hpt366_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index 47082df7199..4ffc392052c 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt37x"
-#define DRV_VERSION "0.5.1"
+#define DRV_VERSION "0.5.2"
struct hpt_clock {
u8 xfer_speed;
@@ -349,24 +349,13 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
{
- unsigned char model_num[40];
- char *s;
- unsigned int len;
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
int i = 0;
- ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
- sizeof(model_num));
- s = &model_num[0];
- len = strnlen(s, sizeof(model_num));
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
- /* ATAPI specifies that empty space is blank-filled; remove blanks */
- while ((len > 0) && (s[len - 1] == ' ')) {
- len--;
- s[len] = 0;
- }
-
- while(list[i] != NULL) {
- if (!strncmp(list[i], s, len)) {
+ while (list[i] != NULL) {
+ if (!strcmp(list[i], model_num)) {
printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
modestr, list[i]);
return 1;
@@ -416,7 +405,7 @@ static const char *bad_ata100_5[] = {
static unsigned long hpt370_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
{
- if (adev->class != ATA_DEV_ATA) {
+ if (adev->class == ATA_DEV_ATA) {
if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
mask &= ~ATA_MASK_UDMA;
if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
@@ -459,7 +448,7 @@ static int hpt37x_pre_reset(struct ata_port *ap)
};
if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
return -ENOENT;
-
+
pci_read_config_byte(pdev, 0x5B, &scr2);
pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
/* Cable register now active */
@@ -504,7 +493,7 @@ static int hpt374_pre_reset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
return -ENOENT;
-
+
/* Do the extra channel work */
pci_read_config_word(pdev, 0x52, &mcr3);
pci_read_config_word(pdev, 0x56, &mcr6);
@@ -645,24 +634,24 @@ static void hpt370_bmdma_stop(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 dma_stat = inb(ap->ioaddr.bmdma_addr + 2);
+ u8 dma_stat = ioread8(ap->ioaddr.bmdma_addr + 2);
u8 dma_cmd;
- unsigned long bmdma = ap->ioaddr.bmdma_addr;
+ void __iomem *bmdma = ap->ioaddr.bmdma_addr;
if (dma_stat & 0x01) {
udelay(20);
- dma_stat = inb(bmdma + 2);
+ dma_stat = ioread8(bmdma + 2);
}
if (dma_stat & 0x01) {
/* Clear the engine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(10);
/* Stop DMA */
- dma_cmd = inb(bmdma );
- outb(dma_cmd & 0xFE, bmdma);
+ dma_cmd = ioread8(bmdma );
+ iowrite8(dma_cmd & 0xFE, bmdma);
/* Clear Error */
- dma_stat = inb(bmdma + 2);
- outb(dma_stat | 0x06 , bmdma + 2);
+ dma_stat = ioread8(bmdma + 2);
+ iowrite8(dma_stat | 0x06 , bmdma + 2);
/* Clear the engine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(10);
@@ -749,7 +738,7 @@ static void hpt37x_bmdma_stop(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- int mscreg = 0x50 + 2 * ap->port_no;
+ int mscreg = 0x50 + 4 * ap->port_no;
u8 bwsr_stat, msc_stat;
pci_read_config_byte(pdev, 0x6A, &bwsr_stat);
@@ -807,14 +796,14 @@ static struct ata_port_operations hpt370_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -846,14 +835,14 @@ static struct ata_port_operations hpt370a_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -886,14 +875,14 @@ static struct ata_port_operations hpt372_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -926,14 +915,14 @@ static struct ata_port_operations hpt374_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index f6817b4093a..65f2e180e7f 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt3x2n"
-#define DRV_VERSION "0.3"
+#define DRV_VERSION "0.3.2"
enum {
HPT_PCI_FAST = (1 << 31),
@@ -263,26 +263,26 @@ static void hpt3x2n_bmdma_stop(struct ata_queued_cmd *qc)
static void hpt3x2n_set_clock(struct ata_port *ap, int source)
{
- unsigned long bmdma = ap->ioaddr.bmdma_addr;
+ void __iomem *bmdma = ap->ioaddr.bmdma_addr;
/* Tristate the bus */
- outb(0x80, bmdma+0x73);
- outb(0x80, bmdma+0x77);
+ iowrite8(0x80, bmdma+0x73);
+ iowrite8(0x80, bmdma+0x77);
/* Switch clock and reset channels */
- outb(source, bmdma+0x7B);
- outb(0xC0, bmdma+0x79);
+ iowrite8(source, bmdma+0x7B);
+ iowrite8(0xC0, bmdma+0x79);
/* Reset state machines */
- outb(0x37, bmdma+0x70);
- outb(0x37, bmdma+0x74);
+ iowrite8(0x37, bmdma+0x70);
+ iowrite8(0x37, bmdma+0x74);
/* Complete reset */
- outb(0x00, bmdma+0x79);
+ iowrite8(0x00, bmdma+0x79);
/* Reconnect channels to bus */
- outb(0x00, bmdma+0x73);
- outb(0x00, bmdma+0x77);
+ iowrite8(0x00, bmdma+0x73);
+ iowrite8(0x00, bmdma+0x77);
}
/* Check if our partner interface is busy */
@@ -297,11 +297,11 @@ static int hpt3x2n_pair_idle(struct ata_port *ap)
return 0;
}
-static int hpt3x2n_use_dpll(struct ata_port *ap, int reading)
+static int hpt3x2n_use_dpll(struct ata_port *ap, int writing)
{
long flags = (long)ap->host->private_data;
/* See if we should use the DPLL */
- if (reading == 0)
+ if (writing)
return USE_DPLL; /* Needed for write */
if (flags & PCI66)
return USE_DPLL; /* Needed at 66Mhz */
@@ -373,14 +373,14 @@ static struct ata_port_operations hpt3x2n_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = hpt3x2n_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 5f1d385eb59..483ce7c12c9 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -148,14 +148,14 @@ static struct ata_port_operations hpt3x3_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -164,7 +164,7 @@ static struct ata_port_operations hpt3x3_port_ops = {
*
* Perform the setup required at boot and on resume.
*/
-
+
static void hpt3x3_init_chipset(struct pci_dev *dev)
{
u16 cmd;
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index a97d55ae95c..1bf5ec18b2e 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -53,14 +53,14 @@ static struct ata_port_operations isapnp_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -75,6 +75,7 @@ static struct ata_port_operations isapnp_port_ops = {
static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id)
{
struct ata_probe_ent ae;
+ void __iomem *cmd_addr, *ctl_addr;
if (pnp_port_valid(idev, 0) == 0)
return -ENODEV;
@@ -83,6 +84,10 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
if (pnp_irq_valid(idev, 0) == 0)
return -ENODEV;
+ cmd_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 0), 8);
+ if (!cmd_addr)
+ return -ENOMEM;
+
memset(&ae, 0, sizeof(struct ata_probe_ent));
INIT_LIST_HEAD(&ae.node);
ae.dev = &idev->dev;
@@ -93,11 +98,13 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
ae.irq = pnp_irq(idev, 0);
ae.irq_flags = 0;
ae.port_flags = ATA_FLAG_SLAVE_POSS;
- ae.port[0].cmd_addr = pnp_port_start(idev, 0);
+ ae.port[0].cmd_addr = cmd_addr;
if (pnp_port_valid(idev, 1) == 0) {
- ae.port[0].altstatus_addr = pnp_port_start(idev, 1);
- ae.port[0].ctl_addr = pnp_port_start(idev, 1);
+ ctl_addr = devm_ioport_map(&idev->dev,
+ pnp_port_start(idev, 1), 1);
+ ae.port[0].altstatus_addr = ctl_addr;
+ ae.port[0].ctl_addr = ctl_addr;
ae.port_flags |= ATA_FLAG_SRST;
}
ata_std_ports(&ae.port[0]);
@@ -120,7 +127,7 @@ static void isapnp_remove_one(struct pnp_dev *idev)
struct device *dev = &idev->dev;
struct ata_host *host = dev_get_drvdata(dev);
- ata_host_remove(host);
+ ata_host_detach(host);
dev_set_drvdata(dev, NULL);
}
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
new file mode 100644
index 00000000000..7eac869dfcd
--- /dev/null
+++ b/drivers/ata/pata_it8213.c
@@ -0,0 +1,354 @@
+/*
+ * pata_it8213.c - iTE Tech. Inc. IT8213 PATA driver
+ *
+ * The IT8213 is a very Intel ICH like device for timing purposes, having
+ * a similar register layout and the same split clock arrangement. Cable
+ * detection is different, and it does not have slave channels or all the
+ * clutter of later ICH/SATA setups.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_it8213"
+#define DRV_VERSION "0.0.2"
+
+/**
+ * it8213_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection for the 8213 ATA interface. This is
+ * different to the PIIX arrangement
+ */
+
+static int it8213_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits it8213_enable_bits[] = {
+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ pci_read_config_byte(pdev, 0x42, &tmp);
+ if (tmp & 2) /* The initial docs are incorrect */
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * it8213_probe_reset - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void it8213_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, it8213_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * it8213_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void it8213_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
+ u16 idetm_data;
+ int control = 0;
+
+ /*
+ * See Intel Document 298600-004 for the timing programing rules
+ * for PIIX/ICH. The 8213 is a clone so very similar
+ */
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ if (pio > 2)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev)) /* PIO 3/4 require IORDY */
+ control |= 2; /* IORDY enable */
+ /* Bit 2 is set for ATAPI on the IT8213 - reverse of ICH/PIIX */
+ if (adev->class != ATA_DEV_ATA)
+ control |= 4;
+
+ pci_read_config_word(dev, idetm_port, &idetm_data);
+
+ /* Enable PPE, IE and TIME as appropriate */
+
+ if (adev->devno == 0) {
+ idetm_data &= 0xCCF0;
+ idetm_data |= control;
+ idetm_data |= (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ } else {
+ u8 slave_data;
+
+ idetm_data &= 0xCC0F;
+ idetm_data |= (control << 4);
+
+ /* Slave timing in seperate register */
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= 0xF0;
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << 4;
+ pci_write_config_byte(dev, 0x44, slave_data);
+ }
+
+ idetm_data |= 0x4000; /* Ensure SITRE is enabled */
+ pci_write_config_word(dev, idetm_port, idetm_data);
+}
+
+/**
+ * it8213_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * This device is basically an ICH alike.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void it8213_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u16 master_data;
+ u8 speed = adev->dma_mode;
+ int devid = adev->devno;
+ u8 udma_enable;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pci_read_config_word(dev, 0x40, &master_data);
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+
+ if (speed >= XFER_UDMA_0) {
+ unsigned int udma = adev->dma_mode - XFER_UDMA_0;
+ u16 udma_timing;
+ u16 ideconf;
+ int u_clock, u_speed;
+
+ /* Clocks follow the PIIX style */
+ u_speed = min(2 - (udma & 1), udma);
+ if (udma == 5)
+ u_clock = 0x1000; /* 100Mhz */
+ else if (udma > 2)
+ u_clock = 1; /* 66Mhz */
+ else
+ u_clock = 0; /* 33Mhz */
+
+ udma_enable |= (1 << devid);
+
+ /* Load the UDMA mode number */
+ pci_read_config_word(dev, 0x4A, &udma_timing);
+ udma_timing &= ~(3 << (4 * devid));
+ udma_timing |= (udma & 3) << (4 * devid);
+ pci_write_config_word(dev, 0x4A, udma_timing);
+
+ /* Load the clock selection */
+ pci_read_config_word(dev, 0x54, &ideconf);
+ ideconf &= ~(0x1001 << devid);
+ ideconf |= u_clock << devid;
+ pci_write_config_word(dev, 0x54, ideconf);
+ } else {
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally along with TIME1. PPE has already
+ * been set when the PIO timing was set.
+ */
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned int control;
+ u8 slave_data;
+ static const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+
+ control = 3; /* IORDY|TIME1 */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO into PIO0 */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ /* Enable DMA timing only */
+ control |= 8; /* PIO cycles in PIO0 */
+
+ if (devid) { /* Slave */
+ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
+ master_data |= control << 4;
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= (0x0F + 0xE1 * ap->port_no);
+ /* Load the matching timing */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
+ pci_write_config_byte(dev, 0x44, slave_data);
+ } else { /* Master */
+ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
+ and master timing bits */
+ master_data |= control;
+ master_data |=
+ (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ }
+ udma_enable &= ~(1 << devid);
+ pci_write_config_word(dev, 0x40, master_data);
+ }
+ pci_write_config_byte(dev, 0x48, udma_enable);
+}
+
+static struct scsi_host_template it8213_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+ .resume = ata_scsi_device_resume,
+ .suspend = ata_scsi_device_suspend,
+};
+
+static const struct ata_port_operations it8213_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = it8213_set_piomode,
+ .set_dmamode = it8213_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = it8213_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .port_start = ata_port_start,
+};
+
+
+/**
+ * it8213_init_one - Register 8213 ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in it8213_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info info = {
+ .sht = &it8213_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x1f, /* UDMA 100 */
+ .port_ops = &it8213_ops,
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ /* Current IT8213 stuff is single port */
+ return ata_pci_init_one(pdev, port_info, 1);
+}
+
+static const struct pci_device_id it8213_pci_tbl[] = {
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), },
+
+ { } /* terminate list */
+};
+
+static struct pci_driver it8213_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = it8213_pci_tbl,
+ .probe = it8213_init_one,
+ .remove = ata_pci_remove_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+};
+
+static int __init it8213_init(void)
+{
+ return pci_register_driver(&it8213_pci_driver);
+}
+
+static void __exit it8213_exit(void)
+{
+ pci_unregister_driver(&it8213_pci_driver);
+}
+
+module_init(it8213_init);
+module_exit(it8213_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for the ITE 8213");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 0b56ff3d1cf..73394c75be4 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -476,6 +476,7 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
/**
* it821x_smart_set_mode - mode setting
* @ap: interface to set up
+ * @unused: device that failed (error only)
*
* Use a non standard set_mode function. We don't want to be tuned.
* The BIOS configured everything. Our job is not to fiddle. We
@@ -483,7 +484,7 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
* and respect them.
*/
-static void it821x_smart_set_mode(struct ata_port *ap)
+static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused)
{
int dma_enabled = 0;
int i;
@@ -491,7 +492,7 @@ static void it821x_smart_set_mode(struct ata_port *ap)
/* Bits 5 and 6 indicate if DMA is active on master/slave */
/* It is possible that BMDMA isn't allocated */
if (ap->ioaddr.bmdma_addr)
- dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
@@ -512,6 +513,7 @@ static void it821x_smart_set_mode(struct ata_port *ap)
}
}
}
+ return 0;
}
/**
@@ -529,23 +531,9 @@ static void it821x_smart_set_mode(struct ata_port *ap)
static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev)
{
- unsigned char model_num[40];
- char *s;
- unsigned int len;
-
- /* This block ought to be a library routine as it is in several
- drivers now */
-
- ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS,
- sizeof(model_num));
- s = &model_num[0];
- len = strnlen(s, sizeof(model_num));
-
- /* ATAPI specifies that empty space is blank-filled; remove blanks */
- while ((len > 0) && (s[len - 1] == ' ')) {
- len--;
- s[len] = 0;
- }
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
+
+ ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
if (adev->max_sectors > 255)
adev->max_sectors = 255;
@@ -606,14 +594,10 @@ static int it821x_port_start(struct ata_port *ap)
if (ret < 0)
return ret;
- ap->private_data = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL);
- if (ap->private_data == NULL) {
- ata_port_stop(ap);
+ itdev = devm_kzalloc(&pdev->dev, sizeof(struct it821x_dev), GFP_KERNEL);
+ if (itdev == NULL)
return -ENOMEM;
- }
-
- itdev = ap->private_data;
- memset(itdev, 0, sizeof(struct it821x_dev));
+ ap->private_data = itdev;
pci_read_config_byte(pdev, 0x50, &conf);
@@ -644,20 +628,6 @@ static int it821x_port_start(struct ata_port *ap)
return 0;
}
-/**
- * it821x_port_stop - port shutdown
- * @ap: ATA port being removed
- *
- * Release the private objects we added in it821x_port_start
- */
-
-static void it821x_port_stop(struct ata_port *ap) {
- kfree(ap->private_data);
- ap->private_data = NULL; /* We want an OOPS if we reuse this
- too late! */
- ata_port_stop(ap);
-}
-
static struct scsi_host_template it821x_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -704,14 +674,14 @@ static struct ata_port_operations it821x_smart_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = it821x_smart_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = it821x_port_start,
- .port_stop = it821x_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations it821x_passthru_port_ops = {
@@ -740,14 +710,14 @@ static struct ata_port_operations it821x_passthru_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = it821x_passthru_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_handler = ata_interrupt,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = it821x_port_start,
- .port_stop = it821x_port_stop,
- .host_stop = ata_host_stop
};
static void __devinit it821x_disable_raid(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index cb8924109f5..3222ac7b945 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -23,9 +23,9 @@
#include <scsi/scsi_host.h>
#define DRV_NAME "pata_ixp4xx_cf"
-#define DRV_VERSION "0.1.1"
+#define DRV_VERSION "0.1.1ac1"
-static void ixp4xx_set_mode(struct ata_port *ap)
+static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device *adev)
{
int i;
@@ -38,6 +38,7 @@ static void ixp4xx_set_mode(struct ata_port *ap)
dev->flags |= ATA_DFLAG_PIO;
}
}
+ return 0;
}
static void ixp4xx_phy_reset(struct ata_port *ap)
@@ -94,14 +95,6 @@ static void ixp4xx_irq_clear(struct ata_port *ap)
{
}
-static void ixp4xx_host_stop (struct ata_host *host)
-{
- struct ixp4xx_pata_data *data = host->dev->platform_data;
-
- iounmap(data->cs0);
- iounmap(data->cs1);
-}
-
static struct scsi_host_template ixp4xx_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -138,10 +131,10 @@ static struct ata_port_operations ixp4xx_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ixp4xx_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ixp4xx_host_stop,
.phy_reset = ixp4xx_phy_reset,
};
@@ -149,9 +142,9 @@ static struct ata_port_operations ixp4xx_port_ops = {
static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
struct ixp4xx_pata_data *data)
{
- ioaddr->cmd_addr = (unsigned long) data->cs0;
- ioaddr->altstatus_addr = (unsigned long) data->cs1 + 0x06;
- ioaddr->ctl_addr = (unsigned long) data->cs1 + 0x06;
+ ioaddr->cmd_addr = data->cs0;
+ ioaddr->altstatus_addr = data->cs1 + 0x06;
+ ioaddr->ctl_addr = data->cs1 + 0x06;
ata_std_ports(ioaddr);
@@ -161,19 +154,19 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
* ixp4xx in little endian mode.
*/
- ioaddr->data_addr ^= 0x02;
- ioaddr->cmd_addr ^= 0x03;
- ioaddr->altstatus_addr ^= 0x03;
- ioaddr->ctl_addr ^= 0x03;
- ioaddr->error_addr ^= 0x03;
- ioaddr->feature_addr ^= 0x03;
- ioaddr->nsect_addr ^= 0x03;
- ioaddr->lbal_addr ^= 0x03;
- ioaddr->lbam_addr ^= 0x03;
- ioaddr->lbah_addr ^= 0x03;
- ioaddr->device_addr ^= 0x03;
- ioaddr->status_addr ^= 0x03;
- ioaddr->command_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->data_addr ^= 0x02;
+ *(unsigned long *)&ioaddr->cmd_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->altstatus_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->ctl_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->error_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->feature_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->nsect_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->lbal_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->lbam_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->lbah_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->device_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->status_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->command_addr ^= 0x03;
#endif
}
@@ -194,8 +187,8 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
- data->cs0 = ioremap(cs0->start, 0x1000);
- data->cs1 = ioremap(cs1->start, 0x1000);
+ data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
+ data->cs1 = devm_ioremap(&pdev->dev, cs1->start, 0x1000);
irq = platform_get_irq(pdev, 0);
if (irq)
@@ -237,7 +230,7 @@ static __devexit int ixp4xx_pata_remove(struct platform_device *dev)
{
struct ata_host *host = platform_get_drvdata(dev);
- ata_host_remove(host);
+ ata_host_detach(host);
platform_set_drvdata(dev, NULL);
return 0;
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 2d661cb4df3..7a635dd326f 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -161,16 +161,16 @@ static const struct ata_port_operations jmicron_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
/* IRQ-related hooks */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
@@ -204,20 +204,12 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
u32 reg;
- if (id->driver_data != 368) {
- /* Put the controller into AHCI mode in case the AHCI driver
- has not yet been loaded. This can be done with either
- function present */
+ /* PATA controller is fn 1, AHCI is fn 0 */
+ if (id->driver_data != 368 && PCI_FUNC(pdev->devfn) != 1)
+ return -ENODEV;
- /* FIXME: We may want a way to override this in future */
- pci_write_config_byte(pdev, 0x41, 0xa1);
-
- /* PATA controller is fn 1, AHCI is fn 0 */
- if (PCI_FUNC(pdev->devfn) != 1)
- return -ENODEV;
- }
- if ( id->driver_data == 365 || id->driver_data == 366) {
- /* The 365/66 have two PATA channels, redirect the second */
+ /* The 365/66 have two PATA channels, redirect the second */
+ if (id->driver_data == 365 || id->driver_data == 366) {
pci_read_config_dword(pdev, 0x80, &reg);
reg |= (1 << 24); /* IDE1 to PATA IDE secondary */
pci_write_config_dword(pdev, 0x80, reg);
@@ -229,7 +221,7 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
static int jmicron_reinit_one(struct pci_dev *pdev)
{
u32 reg;
-
+
switch(pdev->device) {
case PCI_DEVICE_ID_JMICRON_JMB368:
break;
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index c7d1738e4e6..4223e10de6a 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -96,6 +96,7 @@ static int pio_mask = 0x1F; /* PIO range for autospeed devices */
/**
* legacy_set_mode - mode setting
* @ap: IDE interface
+ * @unused: Device that failed when error is returned
*
* Use a non standard set_mode function. We don't want to be tuned.
*
@@ -105,7 +106,7 @@ static int pio_mask = 0x1F; /* PIO range for autospeed devices */
* expand on this as per hdparm in the base kernel.
*/
-static void legacy_set_mode(struct ata_port *ap)
+static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused)
{
int i;
@@ -118,6 +119,7 @@ static void legacy_set_mode(struct ata_port *ap)
dev->flags |= ATA_DFLAG_PIO;
}
}
+ return 0;
}
static struct scsi_host_template legacy_sht = {
@@ -162,14 +164,14 @@ static struct ata_port_operations simple_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer_noirq,
+ .data_xfer = ata_data_xfer_noirq,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations legacy_port_ops = {
@@ -187,14 +189,14 @@ static struct ata_port_operations legacy_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer_noirq,
+ .data_xfer = ata_data_xfer_noirq,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -255,31 +257,33 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig
local_irq_save(flags);
/* Perform the 32bit I/O synchronization sequence */
- inb(ap->ioaddr.nsect_addr);
- inb(ap->ioaddr.nsect_addr);
- inb(ap->ioaddr.nsect_addr);
+ ioread8(ap->ioaddr.nsect_addr);
+ ioread8(ap->ioaddr.nsect_addr);
+ ioread8(ap->ioaddr.nsect_addr);
/* Now the data */
if (write_data)
- outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
- insl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) {
u32 pad;
if (write_data) {
memcpy(&pad, buf + buflen - slop, slop);
- outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ pad = le32_to_cpu(pad);
+ iowrite32(pad, ap->ioaddr.data_addr);
} else {
- pad = cpu_to_le16(inl(ap->ioaddr.data_addr));
+ pad = ioread32(ap->ioaddr.data_addr);
+ pad = cpu_to_le16(pad);
memcpy(buf + buflen - slop, &pad, slop);
}
}
local_irq_restore(flags);
}
else
- ata_pio_data_xfer_noirq(adev, buf, buflen, write_data);
+ ata_data_xfer_noirq(adev, buf, buflen, write_data);
}
static struct ata_port_operations pdc20230_port_ops = {
@@ -301,10 +305,10 @@ static struct ata_port_operations pdc20230_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -330,8 +334,8 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
inb(0x3E6);
inb(0x3E6);
- outb(recover << 4 | active, ap->ioaddr.device_addr);
- inb(ap->ioaddr.status_addr);
+ iowrite8(recover << 4 | active, ap->ioaddr.device_addr);
+ ioread8(ap->ioaddr.status_addr);
}
static struct ata_port_operations ht6560a_port_ops = {
@@ -349,14 +353,14 @@ static struct ata_port_operations ht6560a_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer, /* Check vlb/noirq */
+ .data_xfer = ata_data_xfer, /* Check vlb/noirq */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -385,7 +389,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
inb(0x3E6);
inb(0x3E6);
- outb(recover << 4 | active, ap->ioaddr.device_addr);
+ iowrite8(recover << 4 | active, ap->ioaddr.device_addr);
if (adev->class != ATA_DEV_ATA) {
u8 rconf = inb(0x3E6);
@@ -394,7 +398,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
outb(rconf, 0x3E6);
}
}
- inb(ap->ioaddr.status_addr);
+ ioread8(ap->ioaddr.status_addr);
}
static struct ata_port_operations ht6560b_port_ops = {
@@ -412,14 +416,14 @@ static struct ata_port_operations ht6560b_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer, /* FIXME: Check 32bit and noirq */
+ .data_xfer = ata_data_xfer, /* FIXME: Check 32bit and noirq */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -462,12 +466,12 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev
u8 rc;
/* Enter configuration mode */
- inw(ap->ioaddr.error_addr);
- inw(ap->ioaddr.error_addr);
- outb(3, ap->ioaddr.nsect_addr);
+ ioread16(ap->ioaddr.error_addr);
+ ioread16(ap->ioaddr.error_addr);
+ iowrite8(3, ap->ioaddr.nsect_addr);
/* Read VLB clock strapping */
- clock = 1000000000 / khz[inb(ap->ioaddr.lbah_addr) & 0x03];
+ clock = 1000000000 / khz[ioread8(ap->ioaddr.lbah_addr) & 0x03];
/* Get the timing data in cycles */
ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000);
@@ -485,33 +489,33 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev
setup = FIT(t.setup, 1, 4) - 1;
/* Select the right timing bank for write timing */
- rc = inb(ap->ioaddr.lbal_addr);
+ rc = ioread8(ap->ioaddr.lbal_addr);
rc &= 0x7F;
rc |= (adev->devno << 7);
- outb(rc, ap->ioaddr.lbal_addr);
+ iowrite8(rc, ap->ioaddr.lbal_addr);
/* Write the timings */
- outb(active << 4 | recover, ap->ioaddr.error_addr);
+ iowrite8(active << 4 | recover, ap->ioaddr.error_addr);
/* Select the right bank for read timings, also
load the shared timings for address */
- rc = inb(ap->ioaddr.device_addr);
+ rc = ioread8(ap->ioaddr.device_addr);
rc &= 0xC0;
rc |= adev->devno; /* Index select */
rc |= (setup << 4) | 0x04;
- outb(rc, ap->ioaddr.device_addr);
+ iowrite8(rc, ap->ioaddr.device_addr);
/* Load the read timings */
- outb(active << 4 | recover, ap->ioaddr.data_addr);
+ iowrite8(active << 4 | recover, ap->ioaddr.data_addr);
/* Ensure the timing register mode is right */
- rc = inb (ap->ioaddr.lbal_addr);
+ rc = ioread8(ap->ioaddr.lbal_addr);
rc &= 0x73;
rc |= 0x84;
- outb(rc, ap->ioaddr.lbal_addr);
+ iowrite8(rc, ap->ioaddr.lbal_addr);
/* Exit command mode */
- outb(0x83, ap->ioaddr.nsect_addr);
+ iowrite8(0x83, ap->ioaddr.nsect_addr);
}
@@ -530,14 +534,14 @@ static struct ata_port_operations opti82c611a_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -561,9 +565,9 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
sysclk = opti_syscfg(0xAC) & 0xC0; /* BIOS set */
/* Enter configuration mode */
- inw(ap->ioaddr.error_addr);
- inw(ap->ioaddr.error_addr);
- outb(3, ap->ioaddr.nsect_addr);
+ ioread16(ap->ioaddr.error_addr);
+ ioread16(ap->ioaddr.error_addr);
+ iowrite8(3, ap->ioaddr.nsect_addr);
/* Read VLB clock strapping */
clock = 1000000000 / khz[sysclk];
@@ -584,33 +588,33 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
setup = FIT(t.setup, 1, 4) - 1;
/* Select the right timing bank for write timing */
- rc = inb(ap->ioaddr.lbal_addr);
+ rc = ioread8(ap->ioaddr.lbal_addr);
rc &= 0x7F;
rc |= (adev->devno << 7);
- outb(rc, ap->ioaddr.lbal_addr);
+ iowrite8(rc, ap->ioaddr.lbal_addr);
/* Write the timings */
- outb(active << 4 | recover, ap->ioaddr.error_addr);
+ iowrite8(active << 4 | recover, ap->ioaddr.error_addr);
/* Select the right bank for read timings, also
load the shared timings for address */
- rc = inb(ap->ioaddr.device_addr);
+ rc = ioread8(ap->ioaddr.device_addr);
rc &= 0xC0;
rc |= adev->devno; /* Index select */
rc |= (setup << 4) | 0x04;
- outb(rc, ap->ioaddr.device_addr);
+ iowrite8(rc, ap->ioaddr.device_addr);
/* Load the read timings */
- outb(active << 4 | recover, ap->ioaddr.data_addr);
+ iowrite8(active << 4 | recover, ap->ioaddr.data_addr);
/* Ensure the timing register mode is right */
- rc = inb (ap->ioaddr.lbal_addr);
+ rc = ioread8(ap->ioaddr.lbal_addr);
rc &= 0x73;
rc |= 0x84;
- outb(rc, ap->ioaddr.lbal_addr);
+ iowrite8(rc, ap->ioaddr.lbal_addr);
/* Exit command mode */
- outb(0x83, ap->ioaddr.nsect_addr);
+ iowrite8(0x83, ap->ioaddr.nsect_addr);
/* We need to know this for quad device on the MVB */
ap->host->private_data = ap;
@@ -660,14 +664,14 @@ static struct ata_port_operations opti82c46x_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = opti82c46x_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
@@ -687,19 +691,26 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
struct legacy_data *ld = &legacy_data[nr_legacy_host];
struct ata_probe_ent ae;
struct platform_device *pdev;
- int ret = -EBUSY;
struct ata_port_operations *ops = &legacy_port_ops;
+ void __iomem *io_addr, *ctrl_addr;
int pio_modes = pio_mask;
u32 mask = (1 << port);
-
- if (request_region(io, 8, "pata_legacy") == NULL)
- return -EBUSY;
- if (request_region(ctrl, 1, "pata_legacy") == NULL)
- goto fail_io;
+ int ret;
pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0);
- if (pdev == NULL)
- goto fail_dev;
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ ret = -EBUSY;
+ if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL ||
+ devm_request_region(&pdev->dev, ctrl, 1, "pata_legacy") == NULL)
+ goto fail;
+
+ ret = -ENOMEM;
+ io_addr = devm_ioport_map(&pdev->dev, io, 8);
+ ctrl_addr = devm_ioport_map(&pdev->dev, ctrl, 1);
+ if (!io_addr || !ctrl_addr)
+ goto fail;
if (ht6560a & mask) {
ops = &ht6560a_port_ops;
@@ -766,27 +777,22 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
ae.irq = irq;
ae.irq_flags = 0;
ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
- ae.port[0].cmd_addr = io;
- ae.port[0].altstatus_addr = ctrl;
- ae.port[0].ctl_addr = ctrl;
+ ae.port[0].cmd_addr = io_addr;
+ ae.port[0].altstatus_addr = ctrl_addr;
+ ae.port[0].ctl_addr = ctrl_addr;
ata_std_ports(&ae.port[0]);
ae.private_data = ld;
- ret = ata_device_add(&ae);
- if (ret == 0) {
- ret = -ENODEV;
+ ret = -ENODEV;
+ if (!ata_device_add(&ae))
goto fail;
- }
+
legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
ld->platform_dev = pdev;
return 0;
fail:
platform_device_unregister(pdev);
-fail_dev:
- release_region(ctrl, 1);
-fail_io:
- release_region(io, 8);
return ret;
}
@@ -919,15 +925,11 @@ static __exit void legacy_exit(void)
for (i = 0; i < nr_legacy_host; i++) {
struct legacy_data *ld = &legacy_data[i];
- struct ata_port *ap =legacy_host[i]->ports[0];
- unsigned long io = ap->ioaddr.cmd_addr;
- unsigned long ctrl = ap->ioaddr.ctl_addr;
- ata_host_remove(legacy_host[i]);
+
+ ata_host_detach(legacy_host[i]);
platform_device_unregister(ld->platform_dev);
if (ld->timing)
release_region(ld->timing, 2);
- release_region(io, 8);
- release_region(ctrl, 1);
}
}
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 1c810ea0025..13a70ac6f1d 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -45,10 +45,10 @@ static int marvell_pre_reset(struct ata_port *ap)
for(i = 0; i <= 0x0F; i++)
printk("%02X:%02X ", i, readb(barp + i));
printk("\n");
-
+
devices = readl(barp + 0x0C);
pci_iounmap(pdev, barp);
-
+
if ((pdev->device == 0x6145) && (ap->port_no == 0) &&
(!(devices & 0x10))) /* PATA enable ? */
return -ENOENT;
@@ -57,7 +57,7 @@ static int marvell_pre_reset(struct ata_port *ap)
switch(ap->port_no)
{
case 0:
- if (inb(ap->ioaddr.bmdma_addr + 1) & 1)
+ if (ioread8(ap->ioaddr.bmdma_addr + 1) & 1)
ap->cbl = ATA_CBL_PATA40;
else
ap->cbl = ATA_CBL_PATA80;
@@ -129,16 +129,16 @@ static const struct ata_port_operations marvell_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
/* Timeout handling */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
new file mode 100644
index 00000000000..d7378df4497
--- /dev/null
+++ b/drivers/ata/pata_mpc52xx.c
@@ -0,0 +1,538 @@
+/*
+ * drivers/ata/pata_mpc52xx.c
+ *
+ * libata driver for the Freescale MPC52xx on-chip IDE interface
+ *
+ * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/libata.h>
+
+#include <asm/types.h>
+#include <asm/prom.h>
+#include <asm/of_platform.h>
+#include <asm/mpc52xx.h>
+
+
+#define DRV_NAME "mpc52xx_ata"
+#define DRV_VERSION "0.1.0"
+
+
+/* Private structures used by the driver */
+struct mpc52xx_ata_timings {
+ u32 pio1;
+ u32 pio2;
+};
+
+struct mpc52xx_ata_priv {
+ unsigned int ipb_period;
+ struct mpc52xx_ata __iomem * ata_regs;
+ int ata_irq;
+ struct mpc52xx_ata_timings timings[2];
+ int csel;
+};
+
+
+/* ATAPI-4 PIO specs (in ns) */
+static const int ataspec_t0[5] = {600, 383, 240, 180, 120};
+static const int ataspec_t1[5] = { 70, 50, 30, 30, 25};
+static const int ataspec_t2_8[5] = {290, 290, 290, 80, 70};
+static const int ataspec_t2_16[5] = {165, 125, 100, 80, 70};
+static const int ataspec_t2i[5] = { 0, 0, 0, 70, 25};
+static const int ataspec_t4[5] = { 30, 20, 15, 10, 10};
+static const int ataspec_ta[5] = { 35, 35, 35, 35, 35};
+
+#define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c)))
+
+
+/* Bit definitions inside the registers */
+#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */
+#define MPC52xx_ATA_HOSTCONF_FR 0x40000000UL /* FIFO Reset */
+#define MPC52xx_ATA_HOSTCONF_IE 0x02000000UL /* Enable interrupt in PIO */
+#define MPC52xx_ATA_HOSTCONF_IORDY 0x01000000UL /* Drive supports IORDY protocol */
+
+#define MPC52xx_ATA_HOSTSTAT_TIP 0x80000000UL /* Transaction in progress */
+#define MPC52xx_ATA_HOSTSTAT_UREP 0x40000000UL /* UDMA Read Extended Pause */
+#define MPC52xx_ATA_HOSTSTAT_RERR 0x02000000UL /* Read Error */
+#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */
+
+#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */
+
+#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */
+#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */
+#define MPC52xx_ATA_DMAMODE_UDMA 0x04 /* UDMA enabled */
+#define MPC52xx_ATA_DMAMODE_IE 0x08 /* Enable drive interrupt to CPU in DMA mode */
+#define MPC52xx_ATA_DMAMODE_FE 0x10 /* FIFO Flush enable in Rx mode */
+#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */
+#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */
+
+
+/* Structure of the hardware registers */
+struct mpc52xx_ata {
+
+ /* Host interface registers */
+ u32 config; /* ATA + 0x00 Host configuration */
+ u32 host_status; /* ATA + 0x04 Host controller status */
+ u32 pio1; /* ATA + 0x08 PIO Timing 1 */
+ u32 pio2; /* ATA + 0x0c PIO Timing 2 */
+ u32 mdma1; /* ATA + 0x10 MDMA Timing 1 */
+ u32 mdma2; /* ATA + 0x14 MDMA Timing 2 */
+ u32 udma1; /* ATA + 0x18 UDMA Timing 1 */
+ u32 udma2; /* ATA + 0x1c UDMA Timing 2 */
+ u32 udma3; /* ATA + 0x20 UDMA Timing 3 */
+ u32 udma4; /* ATA + 0x24 UDMA Timing 4 */
+ u32 udma5; /* ATA + 0x28 UDMA Timing 5 */
+ u32 share_cnt; /* ATA + 0x2c ATA share counter */
+ u32 reserved0[3];
+
+ /* FIFO registers */
+ u32 fifo_data; /* ATA + 0x3c */
+ u8 fifo_status_frame; /* ATA + 0x40 */
+ u8 fifo_status; /* ATA + 0x41 */
+ u16 reserved7[1];
+ u8 fifo_control; /* ATA + 0x44 */
+ u8 reserved8[5];
+ u16 fifo_alarm; /* ATA + 0x4a */
+ u16 reserved9;
+ u16 fifo_rdp; /* ATA + 0x4e */
+ u16 reserved10;
+ u16 fifo_wrp; /* ATA + 0x52 */
+ u16 reserved11;
+ u16 fifo_lfrdp; /* ATA + 0x56 */
+ u16 reserved12;
+ u16 fifo_lfwrp; /* ATA + 0x5a */
+
+ /* Drive TaskFile registers */
+ u8 tf_control; /* ATA + 0x5c TASKFILE Control/Alt Status */
+ u8 reserved13[3];
+ u16 tf_data; /* ATA + 0x60 TASKFILE Data */
+ u16 reserved14;
+ u8 tf_features; /* ATA + 0x64 TASKFILE Features/Error */
+ u8 reserved15[3];
+ u8 tf_sec_count; /* ATA + 0x68 TASKFILE Sector Count */
+ u8 reserved16[3];
+ u8 tf_sec_num; /* ATA + 0x6c TASKFILE Sector Number */
+ u8 reserved17[3];
+ u8 tf_cyl_low; /* ATA + 0x70 TASKFILE Cylinder Low */
+ u8 reserved18[3];
+ u8 tf_cyl_high; /* ATA + 0x74 TASKFILE Cylinder High */
+ u8 reserved19[3];
+ u8 tf_dev_head; /* ATA + 0x78 TASKFILE Device/Head */
+ u8 reserved20[3];
+ u8 tf_command; /* ATA + 0x7c TASKFILE Command/Status */
+ u8 dma_mode; /* ATA + 0x7d ATA Host DMA Mode configuration */
+ u8 reserved21[2];
+};
+
+
+/* ======================================================================== */
+/* Aux fns */
+/* ======================================================================== */
+
+
+/* MPC52xx low level hw control */
+
+static int
+mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio)
+{
+ struct mpc52xx_ata_timings *timing = &priv->timings[dev];
+ unsigned int ipb_period = priv->ipb_period;
+ unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta;
+
+ if ((pio<0) || (pio>4))
+ return -EINVAL;
+
+ t0 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]);
+ t1 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t1[pio]);
+ t2_8 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_8[pio]);
+ t2_16 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_16[pio]);
+ t2i = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2i[pio]);
+ t4 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t4[pio]);
+ ta = CALC_CLKCYC(ipb_period, 1000 * ataspec_ta[pio]);
+
+ timing->pio1 = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8) | (t2i);
+ timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8);
+
+ return 0;
+}
+
+static void
+mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device)
+{
+ struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+ struct mpc52xx_ata_timings *timing = &priv->timings[device];
+
+ out_be32(&regs->pio1, timing->pio1);
+ out_be32(&regs->pio2, timing->pio2);
+ out_be32(&regs->mdma1, 0);
+ out_be32(&regs->mdma2, 0);
+ out_be32(&regs->udma1, 0);
+ out_be32(&regs->udma2, 0);
+ out_be32(&regs->udma3, 0);
+ out_be32(&regs->udma4, 0);
+ out_be32(&regs->udma5, 0);
+
+ priv->csel = device;
+}
+
+static int
+mpc52xx_ata_hw_init(struct mpc52xx_ata_priv *priv)
+{
+ struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+ int tslot;
+
+ /* Clear share_cnt (all sample code do this ...) */
+ out_be32(&regs->share_cnt, 0);
+
+ /* Configure and reset host */
+ out_be32(&regs->config,
+ MPC52xx_ATA_HOSTCONF_IE |
+ MPC52xx_ATA_HOSTCONF_IORDY |
+ MPC52xx_ATA_HOSTCONF_SMR |
+ MPC52xx_ATA_HOSTCONF_FR);
+
+ udelay(10);
+
+ out_be32(&regs->config,
+ MPC52xx_ATA_HOSTCONF_IE |
+ MPC52xx_ATA_HOSTCONF_IORDY);
+
+ /* Set the time slot to 1us */
+ tslot = CALC_CLKCYC(priv->ipb_period, 1000000);
+ out_be32(&regs->share_cnt, tslot << 16 );
+
+ /* Init timings to PIO0 */
+ memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));
+
+ mpc52xx_ata_compute_pio_timings(priv, 0, 0);
+ mpc52xx_ata_compute_pio_timings(priv, 1, 0);
+
+ mpc52xx_ata_apply_timings(priv, 0);
+
+ return 0;
+}
+
+
+/* ======================================================================== */
+/* libata driver */
+/* ======================================================================== */
+
+static void
+mpc52xx_ata_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+ int pio, rv;
+
+ pio = adev->pio_mode - XFER_PIO_0;
+
+ rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio);
+
+ if (rv) {
+ printk(KERN_ERR DRV_NAME
+ ": Trying to select invalid PIO mode %d\n", pio);
+ return;
+ }
+
+ mpc52xx_ata_apply_timings(priv, adev->devno);
+}
+static void
+mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device)
+{
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+ if (device != priv->csel)
+ mpc52xx_ata_apply_timings(priv, device);
+
+ ata_std_dev_select(ap,device);
+}
+
+static void
+mpc52xx_ata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+
+
+static struct scsi_host_template mpc52xx_ata_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations mpc52xx_ata_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = mpc52xx_ata_set_piomode,
+ .dev_select = mpc52xx_ata_dev_select,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = mpc52xx_ata_error_handler,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+ .port_start = ata_port_start,
+};
+
+static struct ata_probe_ent mpc52xx_ata_probe_ent = {
+ .port_ops = &mpc52xx_ata_port_ops,
+ .sht = &mpc52xx_ata_sht,
+ .n_ports = 1,
+ .pio_mask = 0x1f, /* Up to PIO4 */
+ .mwdma_mask = 0x00, /* No MWDMA */
+ .udma_mask = 0x00, /* No UDMA */
+ .port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .irq_flags = 0,
+};
+
+static int __devinit
+mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
+{
+ struct ata_probe_ent *ae = &mpc52xx_ata_probe_ent;
+ struct ata_ioports *aio = &ae->port[0];
+ int rv;
+
+ INIT_LIST_HEAD(&ae->node);
+ ae->dev = dev;
+ ae->irq = priv->ata_irq;
+
+ aio->cmd_addr = 0; /* Don't have a classic reg block */
+ aio->altstatus_addr = &priv->ata_regs->tf_control;
+ aio->ctl_addr = &priv->ata_regs->tf_control;
+ aio->data_addr = &priv->ata_regs->tf_data;
+ aio->error_addr = &priv->ata_regs->tf_features;
+ aio->feature_addr = &priv->ata_regs->tf_features;
+ aio->nsect_addr = &priv->ata_regs->tf_sec_count;
+ aio->lbal_addr = &priv->ata_regs->tf_sec_num;
+ aio->lbam_addr = &priv->ata_regs->tf_cyl_low;
+ aio->lbah_addr = &priv->ata_regs->tf_cyl_high;
+ aio->device_addr = &priv->ata_regs->tf_dev_head;
+ aio->status_addr = &priv->ata_regs->tf_command;
+ aio->command_addr = &priv->ata_regs->tf_command;
+
+ ae->private_data = priv;
+
+ rv = ata_device_add(ae);
+
+ return rv ? 0 : -EINVAL;
+}
+
+static struct mpc52xx_ata_priv *
+mpc52xx_ata_remove_one(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct mpc52xx_ata_priv *priv = host->private_data;
+
+ ata_host_detach(host);
+
+ return priv;
+}
+
+
+/* ======================================================================== */
+/* OF Platform driver */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
+{
+ unsigned int ipb_freq;
+ struct resource res_mem;
+ int ata_irq = NO_IRQ;
+ struct mpc52xx_ata __iomem *ata_regs;
+ struct mpc52xx_ata_priv *priv;
+ int rv;
+
+ /* Get ipb frequency */
+ ipb_freq = mpc52xx_find_ipb_freq(op->node);
+ if (!ipb_freq) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Unable to find IPB Bus frequency\n" );
+ return -ENODEV;
+ }
+
+ /* Get IRQ and register */
+ rv = of_address_to_resource(op->node, 0, &res_mem);
+ if (rv) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while parsing device node resource\n" );
+ return rv;
+ }
+
+ ata_irq = irq_of_parse_and_map(op->node, 0);
+ if (ata_irq == NO_IRQ) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while mapping the irq\n");
+ return -EINVAL;
+ }
+
+ /* Request mem region */
+ if (!devm_request_mem_region(&op->dev, res_mem.start,
+ sizeof(struct mpc52xx_ata), DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while requesting mem region\n");
+ rv = -EBUSY;
+ goto err;
+ }
+
+ /* Remap registers */
+ ata_regs = devm_ioremap(&op->dev, res_mem.start,
+ sizeof(struct mpc52xx_ata));
+ if (!ata_regs) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while mapping register set\n");
+ rv = -ENOMEM;
+ goto err;
+ }
+
+ /* Prepare our private structure */
+ priv = devm_kzalloc(&op->dev, sizeof(struct mpc52xx_ata_priv),
+ GFP_ATOMIC);
+ if (!priv) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while allocating private structure\n");
+ rv = -ENOMEM;
+ goto err;
+ }
+
+ priv->ipb_period = 1000000000 / (ipb_freq / 1000);
+ priv->ata_regs = ata_regs;
+ priv->ata_irq = ata_irq;
+ priv->csel = -1;
+
+ /* Init the hw */
+ rv = mpc52xx_ata_hw_init(priv);
+ if (rv) {
+ printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ goto err;
+ }
+
+ /* Register ourselves to libata */
+ rv = mpc52xx_ata_init_one(&op->dev, priv);
+ if (rv) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while registering to ATA layer\n");
+ return rv;
+ }
+
+ /* Done */
+ return 0;
+
+ /* Error path */
+err:
+ irq_dispose_mapping(ata_irq);
+ return rv;
+}
+
+static int
+mpc52xx_ata_remove(struct of_device *op)
+{
+ struct mpc52xx_ata_priv *priv;
+
+ priv = mpc52xx_ata_remove_one(&op->dev);
+ irq_dispose_mapping(priv->ata_irq);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+
+static int
+mpc52xx_ata_suspend(struct of_device *op, pm_message_t state)
+{
+ return 0; /* FIXME : What to do here ? */
+}
+
+static int
+mpc52xx_ata_resume(struct of_device *op)
+{
+ return 0; /* FIXME : What to do here ? */
+}
+
+#endif
+
+
+static struct of_device_id mpc52xx_ata_of_match[] = {
+ {
+ .compatible = "mpc5200-ata",
+ },
+ {
+ .compatible = "mpc52xx-ata",
+ },
+ {},
+};
+
+
+static struct of_platform_driver mpc52xx_ata_of_platform_driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ .match_table = mpc52xx_ata_of_match,
+ .probe = mpc52xx_ata_probe,
+ .remove = mpc52xx_ata_remove,
+#ifdef CONFIG_PM
+ .suspend = mpc52xx_ata_suspend,
+ .resume = mpc52xx_ata_resume,
+#endif
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_ata_init(void)
+{
+ printk(KERN_INFO "ata: MPC52xx IDE/ATA libata driver\n");
+ return of_register_platform_driver(&mpc52xx_ata_of_platform_driver);
+}
+
+static void __exit
+mpc52xx_ata_exit(void)
+{
+ of_unregister_platform_driver(&mpc52xx_ata_of_platform_driver);
+}
+
+module_init(mpc52xx_ata_init);
+module_exit(mpc52xx_ata_exit);
+
+MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
+MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 4ccca938675..ca8c965179b 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_mpiix"
-#define DRV_VERSION "0.7.3"
+#define DRV_VERSION "0.7.5"
enum {
IDETIM = 0x6C, /* IDE control register */
@@ -49,12 +49,9 @@ enum {
static int mpiix_pre_reset(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- static const struct pci_bits mpiix_enable_bits[] = {
- { 0x6D, 1, 0x80, 0x80 },
- { 0x6F, 1, 0x80, 0x80 }
- };
+ static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 };
- if (!pci_test_config_bits(pdev, &mpiix_enable_bits[ap->port_no]))
+ if (!pci_test_config_bits(pdev, &mpiix_enable_bits))
return -ENOENT;
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
@@ -80,8 +77,8 @@ static void mpiix_error_handler(struct ata_port *ap)
* @adev: ATA device
*
* Called to do the PIO mode setup. The MPIIX allows us to program the
- * IORDY sample point (2-5 clocks), recovery 1-4 clocks and whether
- * prefetching or iordy are used.
+ * IORDY sample point (2-5 clocks), recovery (1-4 clocks) and whether
+ * prefetching or IORDY are used.
*
* This would get very ugly because we can only program timing for one
* device at a time, the other gets PIO0. Fortunately libata calls
@@ -103,18 +100,19 @@ static void mpiix_set_piomode(struct ata_port *ap, struct ata_device *adev)
{ 2, 3 }, };
pci_read_config_word(pdev, IDETIM, &idetim);
- /* Mask the IORDY/TIME/PPE0 bank for this device */
+
+ /* Mask the IORDY/TIME/PPE for this device */
if (adev->class == ATA_DEV_ATA)
- control |= PPE; /* PPE enable for disk */
+ control |= PPE; /* Enable prefetch/posting for disk */
if (ata_pio_need_iordy(adev))
- control |= IORDY; /* IORDY */
- if (pio > 0)
+ control |= IORDY;
+ if (pio > 1)
control |= FTIM; /* This drive is on the fast timing bank */
/* Mask out timing and clear both TIME bank selects */
idetim &= 0xCCEE;
- idetim &= ~(0x07 << (2 * adev->devno));
- idetim |= (control << (2 * adev->devno));
+ idetim &= ~(0x07 << (4 * adev->devno));
+ idetim |= control << (4 * adev->devno);
idetim |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
pci_write_config_word(pdev, IDETIM, idetim);
@@ -188,23 +186,24 @@ static struct ata_port_operations mpiix_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = mpiix_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
/* Single threaded by the PCI probe logic */
- static struct ata_probe_ent probe[2];
+ static struct ata_probe_ent probe;
static int printed_version;
+ void __iomem *cmd_addr, *ctl_addr;
u16 idetim;
- int enabled;
+ int irq;
if (!printed_version++)
dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
@@ -217,65 +216,49 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (!(idetim & ENABLED))
return -ENODEV;
+ /* See if it's primary or secondary channel... */
+ if (!(idetim & SECONDARY)) {
+ irq = 14;
+ cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8);
+ ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1);
+ } else {
+ irq = 15;
+ cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8);
+ ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1);
+ }
+
+ if (!cmd_addr || !ctl_addr)
+ return -ENOMEM;
+
/* We do our own plumbing to avoid leaking special cases for whacko
ancient hardware into the core code. There are two issues to
worry about. #1 The chip is a bridge so if in legacy mode and
without BARs set fools the setup. #2 If you pci_disable_device
the MPIIX your box goes castors up */
- INIT_LIST_HEAD(&probe[0].node);
- probe[0].dev = pci_dev_to_dev(dev);
- probe[0].port_ops = &mpiix_port_ops;
- probe[0].sht = &mpiix_sht;
- probe[0].pio_mask = 0x1F;
- probe[0].irq = 14;
- probe[0].irq_flags = SA_SHIRQ;
- probe[0].port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- probe[0].n_ports = 1;
- probe[0].port[0].cmd_addr = 0x1F0;
- probe[0].port[0].ctl_addr = 0x3F6;
- probe[0].port[0].altstatus_addr = 0x3F6;
-
- /* The secondary lurks at different addresses but is otherwise
- the same beastie */
-
- INIT_LIST_HEAD(&probe[1].node);
- probe[1] = probe[0];
- probe[1].irq = 15;
- probe[1].port[0].cmd_addr = 0x170;
- probe[1].port[0].ctl_addr = 0x376;
- probe[1].port[0].altstatus_addr = 0x376;
+ INIT_LIST_HEAD(&probe.node);
+ probe.dev = pci_dev_to_dev(dev);
+ probe.port_ops = &mpiix_port_ops;
+ probe.sht = &mpiix_sht;
+ probe.pio_mask = 0x1F;
+ probe.irq_flags = SA_SHIRQ;
+ probe.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ probe.n_ports = 1;
+
+ probe.irq = irq;
+ probe.port[0].cmd_addr = cmd_addr;
+ probe.port[0].ctl_addr = ctl_addr;
+ probe.port[0].altstatus_addr = ctl_addr;
/* Let libata fill in the port details */
- ata_std_ports(&probe[0].port[0]);
- ata_std_ports(&probe[1].port[0]);
+ ata_std_ports(&probe.port[0]);
/* Now add the port that is active */
- enabled = (idetim & SECONDARY) ? 1 : 0;
-
- if (ata_device_add(&probe[enabled]))
+ if (ata_device_add(&probe))
return 0;
return -ENODEV;
}
-/**
- * mpiix_remove_one - device unload
- * @pdev: PCI device being removed
- *
- * Handle an unplug/unload event for a PCI device. Unload the
- * PCI driver but do not use the default handler as we *MUST NOT*
- * disable the device as it has other functions.
- */
-
-static void __devexit mpiix_remove_one(struct pci_dev *pdev)
-{
- struct device *dev = pci_dev_to_dev(pdev);
- struct ata_host *host = dev_get_drvdata(dev);
-
- ata_host_remove(host);
- dev_set_drvdata(dev, NULL);
-}
-
static const struct pci_device_id mpiix[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
@@ -286,7 +269,7 @@ static struct pci_driver mpiix_pci_driver = {
.name = DRV_NAME,
.id_table = mpiix,
.probe = mpiix_init_one,
- .remove = mpiix_remove_one,
+ .remove = ata_pci_remove_one,
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
};
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index cf7fe037471..e8393e19be4 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -89,16 +89,16 @@ static const struct ata_port_operations netcell_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
/* IRQ-related hooks */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index c3032eb9010..3d1fa487c48 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -179,14 +179,14 @@ static struct ata_port_operations ns87410_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ns87410_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index 10ac3cc1018..45215aa05e7 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.2"
+#define DRV_VERSION "0.5.3"
/**
* oldpiix_pre_reset - probe begin
@@ -94,19 +94,21 @@ static void oldpiix_set_piomode (struct ata_port *ap, struct ata_device *adev)
{ 2, 1 },
{ 2, 3 }, };
- if (pio > 2)
- control |= 1; /* TIME1 enable */
+ if (pio > 1)
+ control |= 1; /* TIME */
if (ata_pio_need_iordy(adev))
- control |= 2; /* IE IORDY */
+ control |= 2; /* IE */
- /* Intel specifies that the PPE functionality is for disk only */
+ /* Intel specifies that the prefetch/posting is for disk only */
if (adev->class == ATA_DEV_ATA)
- control |= 4; /* PPE enable */
+ control |= 4; /* PPE */
pci_read_config_word(dev, idetm_port, &idetm_data);
- /* Enable PPE, IE and TIME as appropriate. Clear the other
- drive timing bits */
+ /*
+ * Set PPE, IE and TIME as appropriate.
+ * Clear the other drive's timing bits.
+ */
if (adev->devno == 0) {
idetm_data &= 0xCCE0;
idetm_data |= control;
@@ -259,14 +261,14 @@ static const struct ata_port_operations oldpiix_pata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = oldpiix_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index c2988b0aa8e..da1aa148b37 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -95,18 +95,18 @@ static void opti_error_handler(struct ata_port *ap)
static void opti_write_reg(struct ata_port *ap, u8 val, int reg)
{
- unsigned long regio = ap->ioaddr.cmd_addr;
+ void __iomem *regio = ap->ioaddr.cmd_addr;
/* These 3 unlock the control register access */
- inw(regio + 1);
- inw(regio + 1);
- outb(3, regio + 2);
+ ioread16(regio + 1);
+ ioread16(regio + 1);
+ iowrite8(3, regio + 2);
/* Do the I/O */
- outb(val, regio + reg);
+ iowrite8(val, regio + reg);
/* Relock */
- outb(0x83, regio + 2);
+ iowrite8(0x83, regio + 2);
}
/**
@@ -124,7 +124,7 @@ static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev)
struct ata_device *pair = ata_dev_pair(adev);
int clock;
int pio = adev->pio_mode - XFER_PIO_0;
- unsigned long regio = ap->ioaddr.cmd_addr;
+ void __iomem *regio = ap->ioaddr.cmd_addr;
u8 addr;
/* Address table precomputed with prefetch off and a DCLK of 2 */
@@ -137,8 +137,8 @@ static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev)
{ 0x58, 0x44, 0x32, 0x22, 0x21 }
};
- outb(0xff, regio + 5);
- clock = inw(regio + 5) & 1;
+ iowrite8(0xff, regio + 5);
+ clock = ioread16(regio + 5) & 1;
/*
* As with many controllers the address setup time is shared
@@ -205,14 +205,14 @@ static struct ata_port_operations opti_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 80d111c569d..d80b36e209c 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -91,12 +91,12 @@ static void optidma_error_handler(struct ata_port *ap)
static void optidma_unlock(struct ata_port *ap)
{
- unsigned long regio = ap->ioaddr.cmd_addr;
+ void __iomem *regio = ap->ioaddr.cmd_addr;
/* These 3 unlock the control register access */
- inw(regio + 1);
- inw(regio + 1);
- outb(3, regio + 2);
+ ioread16(regio + 1);
+ ioread16(regio + 1);
+ iowrite8(3, regio + 2);
}
/**
@@ -108,10 +108,10 @@ static void optidma_unlock(struct ata_port *ap)
static void optidma_lock(struct ata_port *ap)
{
- unsigned long regio = ap->ioaddr.cmd_addr;
+ void __iomem *regio = ap->ioaddr.cmd_addr;
/* Relock */
- outb(0x83, regio + 2);
+ iowrite8(0x83, regio + 2);
}
/**
@@ -133,7 +133,7 @@ static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo
struct ata_device *pair = ata_dev_pair(adev);
int pio = adev->pio_mode - XFER_PIO_0;
int dma = adev->dma_mode - XFER_MW_DMA_0;
- unsigned long regio = ap->ioaddr.cmd_addr;
+ void __iomem *regio = ap->ioaddr.cmd_addr;
u8 addr;
/* Address table precomputed with a DCLK of 2 */
@@ -178,20 +178,20 @@ static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo
/* Commence primary programming sequence */
/* First we load the device number into the timing select */
- outb(adev->devno, regio + MISC_REG);
+ iowrite8(adev->devno, regio + MISC_REG);
/* Now we load the data timings into read data/write data */
if (mode < XFER_MW_DMA_0) {
- outb(data_rec_timing[pci_clock][pio], regio + READ_REG);
- outb(data_rec_timing[pci_clock][pio], regio + WRITE_REG);
+ iowrite8(data_rec_timing[pci_clock][pio], regio + READ_REG);
+ iowrite8(data_rec_timing[pci_clock][pio], regio + WRITE_REG);
} else if (mode < XFER_UDMA_0) {
- outb(dma_data_rec_timing[pci_clock][dma], regio + READ_REG);
- outb(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG);
+ iowrite8(dma_data_rec_timing[pci_clock][dma], regio + READ_REG);
+ iowrite8(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG);
}
/* Finally we load the address setup into the misc register */
- outb(addr | adev->devno, regio + MISC_REG);
+ iowrite8(addr | adev->devno, regio + MISC_REG);
/* Programming sequence complete, timing 0 dev 0, timing 1 dev 1 */
- outb(0x85, regio + CNTRL_REG);
+ iowrite8(0x85, regio + CNTRL_REG);
/* Switch back to IDE mode */
optidma_lock(ap);
@@ -389,14 +389,14 @@ static struct ata_port_operations optidma_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations optiplus_port_ops = {
@@ -424,14 +424,14 @@ static struct ata_port_operations optiplus_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 9ed7f58424a..acfc09f9abd 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -88,14 +88,14 @@ static struct ata_port_operations pcmcia_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer_noirq,
+ .data_xfer = ata_data_xfer_noirq,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
#define CS_CHECK(fn, ret) \
@@ -123,6 +123,7 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
cistpl_cftable_entry_t *cfg;
int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM;
unsigned long io_base, ctl_base;
+ void __iomem *io_addr, *ctl_addr;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL)
@@ -233,10 +234,17 @@ next_entry:
CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
+ /* iomap */
+ ret = -ENOMEM;
+ io_addr = devm_ioport_map(&pdev->dev, io_base, 8);
+ ctl_addr = devm_ioport_map(&pdev->dev, ctl_base, 1);
+ if (!io_addr || !ctl_addr)
+ goto failed;
+
/* Success. Disable the IRQ nIEN line, do quirks */
- outb(0x02, ctl_base);
+ iowrite8(0x02, ctl_addr);
if (is_kme)
- outb(0x81, ctl_base + 0x01);
+ iowrite8(0x81, ctl_addr + 0x01);
/* FIXME: Could be more ports at base + 0x10 but we only deal with
one right now */
@@ -258,11 +266,12 @@ next_entry:
ae.irq = pdev->irq.AssignedIRQ;
ae.irq_flags = SA_SHIRQ;
ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- ae.port[0].cmd_addr = io_base;
- ae.port[0].altstatus_addr = ctl_base;
- ae.port[0].ctl_addr = ctl_base;
+ ae.port[0].cmd_addr = io_addr;
+ ae.port[0].altstatus_addr = ctl_addr;
+ ae.port[0].ctl_addr = ctl_addr;
ata_std_ports(&ae.port[0]);
+ ret = -ENODEV;
if (ata_device_add(&ae) == 0)
goto failed;
@@ -298,7 +307,7 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev)
/* If we have attached the device to the ATA layer, detach it */
if (info->ndev) {
struct ata_host *host = dev_get_drvdata(dev);
- ata_host_remove(host);
+ ata_host_detach(host);
dev_set_drvdata(dev, NULL);
}
info->ndev = 0;
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 76dd1c935db..ffa7f47fbb2 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -33,7 +33,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#define DRV_NAME "pata_pdc2027x"
#define DRV_VERSION "0.74-ac5"
@@ -46,6 +45,8 @@
#endif
enum {
+ PDC_MMIO_BAR = 5,
+
PDC_UDMA_100 = 0,
PDC_UDMA_133 = 1,
@@ -62,7 +63,6 @@ enum {
};
static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static void pdc2027x_remove_one(struct pci_dev *pdev);
static void pdc2027x_error_handler(struct ata_port *ap);
static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev);
static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
@@ -123,7 +123,7 @@ static struct pci_driver pdc2027x_pci_driver = {
.name = DRV_NAME,
.id_table = pdc2027x_pci_tbl,
.probe = pdc2027x_init_one,
- .remove = __devexit_p(pdc2027x_remove_one),
+ .remove = ata_pci_remove_one,
};
static struct scsi_host_template pdc2027x_sht = {
@@ -160,7 +160,7 @@ static struct ata_port_operations pdc2027x_pata100_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -169,10 +169,10 @@ static struct ata_port_operations pdc2027x_pata100_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
static struct ata_port_operations pdc2027x_pata133_ops = {
@@ -194,7 +194,7 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -203,10 +203,10 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
static struct ata_port_info pdc2027x_port_info[] = {
@@ -245,7 +245,7 @@ MODULE_DEVICE_TABLE(pci, pdc2027x_pci_tbl);
*/
static inline void __iomem *port_mmio(struct ata_port *ap, unsigned int offset)
{
- return ap->host->mmio_base + ap->port_no * 0x100 + offset;
+ return ap->host->iomap[PDC_MMIO_BAR] + ap->port_no * 0x100 + offset;
}
/**
@@ -526,18 +526,19 @@ static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc)
static long pdc_read_counter(struct ata_probe_ent *probe_ent)
{
+ void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
long counter;
int retry = 1;
u32 bccrl, bccrh, bccrlv, bccrhv;
retry:
- bccrl = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff;
- bccrh = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
+ bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
+ bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
rmb();
/* Read the counter values again for verification */
- bccrlv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff;
- bccrhv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
+ bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
+ bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
rmb();
counter = (bccrh << 15) | bccrl;
@@ -568,7 +569,7 @@ retry:
*/
static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx)
{
-
+ void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
u16 pll_ctl;
long pll_clock_khz = pll_clock / 1000;
long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ;
@@ -587,7 +588,7 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi
/* Show the current clock value of PLL control register
* (maybe already configured by the firmware)
*/
- pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL);
+ pll_ctl = readw(mmio_base + PDC_PLL_CTL);
PDPRINTK("pll_ctl[%X]\n", pll_ctl);
#endif
@@ -627,8 +628,8 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi
PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl);
- writew(pll_ctl, probe_ent->mmio_base + PDC_PLL_CTL);
- readw(probe_ent->mmio_base + PDC_PLL_CTL); /* flush */
+ writew(pll_ctl, mmio_base + PDC_PLL_CTL);
+ readw(mmio_base + PDC_PLL_CTL); /* flush */
/* Wait the PLL circuit to be stable */
mdelay(30);
@@ -638,7 +639,7 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi
* Show the current clock value of PLL control register
* (maybe configured by the firmware)
*/
- pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL);
+ pll_ctl = readw(mmio_base + PDC_PLL_CTL);
PDPRINTK("pll_ctl[%X]\n", pll_ctl);
#endif
@@ -654,6 +655,7 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi
*/
static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
{
+ void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
u32 scr;
long start_count, end_count;
long pll_clock;
@@ -662,10 +664,10 @@ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
start_count = pdc_read_counter(probe_ent);
/* Start the test mode */
- scr = readl(probe_ent->mmio_base + PDC_SYS_CTL);
+ scr = readl(mmio_base + PDC_SYS_CTL);
PDPRINTK("scr[%X]\n", scr);
- writel(scr | (0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL);
- readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */
+ writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
+ readl(mmio_base + PDC_SYS_CTL); /* flush */
/* Let the counter run for 100 ms. */
mdelay(100);
@@ -674,10 +676,10 @@ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
end_count = pdc_read_counter(probe_ent);
/* Stop the test mode */
- scr = readl(probe_ent->mmio_base + PDC_SYS_CTL);
+ scr = readl(mmio_base + PDC_SYS_CTL);
PDPRINTK("scr[%X]\n", scr);
- writel(scr & ~(0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL);
- readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */
+ writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
+ readl(mmio_base + PDC_SYS_CTL); /* flush */
/* calculate the input clock in Hz */
pll_clock = (start_count - end_count) * 10;
@@ -722,7 +724,7 @@ static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, uns
* @port: ata ioports to setup
* @base: base address
*/
-static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
+static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr =
port->data_addr = base;
@@ -755,48 +757,37 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
static int printed_version;
unsigned int board_idx = (unsigned int) ent->driver_data;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
+ struct ata_probe_ent *probe_ent;
void __iomem *mmio_base;
int rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
+ rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME);
if (rc)
- goto err_out;
+ return rc;
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
/* Prepare the probe entry */
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, 5, 0);
- if (!mmio_base) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
-
- base = (unsigned long) mmio_base;
-
probe_ent->sht = pdc2027x_port_info[board_idx].sht;
probe_ent->port_flags = pdc2027x_port_info[board_idx].flags;
probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask;
@@ -806,12 +797,14 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
- pdc_ata_setup_port(&probe_ent->port[0], base + 0x17c0);
- probe_ent->port[0].bmdma_addr = base + 0x1000;
- pdc_ata_setup_port(&probe_ent->port[1], base + 0x15c0);
- probe_ent->port[1].bmdma_addr = base + 0x1008;
+ mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
+
+ pdc_ata_setup_port(&probe_ent->port[0], mmio_base + 0x17c0);
+ probe_ent->port[0].bmdma_addr = mmio_base + 0x1000;
+ pdc_ata_setup_port(&probe_ent->port[1], mmio_base + 0x15c0);
+ probe_ent->port[1].bmdma_addr = mmio_base + 0x1008;
probe_ent->n_ports = 2;
@@ -820,32 +813,13 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
/* initialize adapter */
if (pdc_hardware_init(pdev, probe_ent, board_idx) != 0)
- goto err_out_free_ent;
+ return -EIO;
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- pci_disable_device(pdev);
- return rc;
-}
-
-/**
- * pdc2027x_remove_one - Called to remove a single instance of the
- * adapter.
- *
- * @dev: The PCI device to remove.
- * FIXME: module load/unload not working yet
- */
-static void __devexit pdc2027x_remove_one(struct pci_dev *pdev)
-{
- ata_pci_remove_one(pdev);
}
/**
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index ad691b9e774..6dd63413a52 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -170,17 +170,17 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
struct ata_taskfile *tf = &qc->tf;
int sel66 = ap->port_no ? 0x08: 0x02;
- unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr;
- unsigned long clock = master + 0x11;
- unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no);
+ void __iomem *master = ap->host->ports[0]->ioaddr.bmdma_addr;
+ void __iomem *clock = master + 0x11;
+ void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no);
u32 len;
/* Check we keep host level locking here */
if (adev->dma_mode >= XFER_UDMA_2)
- outb(inb(clock) | sel66, clock);
+ iowrite8(ioread8(clock) | sel66, clock);
else
- outb(inb(clock) & ~sel66, clock);
+ iowrite8(ioread8(clock) & ~sel66, clock);
/* The DMA clocks may have been trashed by a reset. FIXME: make conditional
and move to qc_issue ? */
@@ -189,17 +189,14 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
/* Cases the state machine will not complete correctly without help */
if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA)
{
- if (tf->flags & ATA_TFLAG_LBA48)
- len = qc->nsect * 512;
- else
- len = qc->nbytes;
+ len = qc->nbytes;
if (tf->flags & ATA_TFLAG_WRITE)
len |= 0x06000000;
else
len |= 0x05000000;
- outl(len, atapi_reg);
+ iowrite32(len, atapi_reg);
}
/* Activate DMA */
@@ -222,19 +219,19 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
int sel66 = ap->port_no ? 0x08: 0x02;
/* The clock bits are in the same register for both channels */
- unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr;
- unsigned long clock = master + 0x11;
- unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no);
+ void __iomem *master = ap->host->ports[0]->ioaddr.bmdma_addr;
+ void __iomem *clock = master + 0x11;
+ void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no);
/* Cases the state machine will not complete correctly */
if (tf->protocol == ATA_PROT_ATAPI_DMA || ( tf->flags & ATA_TFLAG_LBA48)) {
- outl(0, atapi_reg);
- outb(inb(clock) & ~sel66, clock);
+ iowrite32(0, atapi_reg);
+ iowrite8(ioread8(clock) & ~sel66, clock);
}
/* Check we keep host level locking here */
/* Flip back to 33Mhz for PIO */
if (adev->dma_mode >= XFER_UDMA_2)
- outb(inb(clock) & ~sel66, clock);
+ iowrite8(ioread8(clock) & ~sel66, clock);
ata_bmdma_stop(qc);
}
@@ -297,14 +294,14 @@ static struct ata_port_operations pdc2024x_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations pdc2026x_port_ops = {
@@ -331,14 +328,14 @@ static struct ata_port_operations pdc2026x_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 443b1d85c6c..479a326114e 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -30,7 +30,7 @@ static int pio_mask = 1;
* Provide our own set_mode() as we don't want to change anything that has
* already been configured..
*/
-static void pata_platform_set_mode(struct ata_port *ap)
+static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused)
{
int i;
@@ -44,23 +44,7 @@ static void pata_platform_set_mode(struct ata_port *ap)
dev->flags |= ATA_DFLAG_PIO;
}
}
-}
-
-static void pata_platform_host_stop(struct ata_host *host)
-{
- int i;
-
- /*
- * Unmap the bases for MMIO
- */
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- if (ap->flags & ATA_FLAG_MMIO) {
- iounmap((void __iomem *)ap->ioaddr.ctl_addr);
- iounmap((void __iomem *)ap->ioaddr.cmd_addr);
- }
- }
+ return 0;
}
static struct scsi_host_template pata_platform_sht = {
@@ -99,14 +83,14 @@ static struct ata_port_operations pata_platform_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer_noirq,
+ .data_xfer = ata_data_xfer_noirq,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = pata_platform_host_stop
};
static void pata_platform_setup_port(struct ata_ioports *ioaddr,
@@ -152,7 +136,6 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
struct resource *io_res, *ctl_res;
struct ata_probe_ent ae;
unsigned int mmio;
- int ret;
/*
* Simple resource validation ..
@@ -206,46 +189,29 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
* Handle the MMIO case
*/
if (mmio) {
- ae.port_flags |= ATA_FLAG_MMIO;
-
- ae.port[0].cmd_addr = (unsigned long)ioremap(io_res->start,
+ ae.port[0].cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
io_res->end - io_res->start + 1);
- if (unlikely(!ae.port[0].cmd_addr)) {
- dev_err(&pdev->dev, "failed to remap IO base\n");
- return -ENXIO;
- }
-
- ae.port[0].ctl_addr = (unsigned long)ioremap(ctl_res->start,
+ ae.port[0].ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
ctl_res->end - ctl_res->start + 1);
- if (unlikely(!ae.port[0].ctl_addr)) {
- dev_err(&pdev->dev, "failed to remap CTL base\n");
- ret = -ENXIO;
- goto bad_remap;
- }
} else {
- ae.port[0].cmd_addr = io_res->start;
- ae.port[0].ctl_addr = ctl_res->start;
+ ae.port[0].cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
+ io_res->end - io_res->start + 1);
+ ae.port[0].ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
+ ctl_res->end - ctl_res->start + 1);
+ }
+ if (!ae.port[0].cmd_addr || !ae.port[0].ctl_addr) {
+ dev_err(&pdev->dev, "failed to map IO/CTL base\n");
+ return -ENOMEM;
}
ae.port[0].altstatus_addr = ae.port[0].ctl_addr;
pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data);
- if (unlikely(ata_device_add(&ae) == 0)) {
- ret = -ENODEV;
- goto add_failed;
- }
+ if (unlikely(ata_device_add(&ae) == 0))
+ return -ENODEV;
return 0;
-
-add_failed:
- if (ae.port[0].ctl_addr && mmio)
- iounmap((void __iomem *)ae.port[0].ctl_addr);
-bad_remap:
- if (ae.port[0].cmd_addr && mmio)
- iounmap((void __iomem *)ae.port[0].cmd_addr);
-
- return ret;
}
/**
@@ -260,7 +226,7 @@ static int __devexit pata_platform_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct ata_host *host = dev_get_drvdata(dev);
- ata_host_remove(host);
+ ata_host_detach(host);
dev_set_drvdata(dev, NULL);
return 0;
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index 36f621abc39..1b3b4ed8eb1 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -131,22 +131,24 @@ static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned
if (ata_id_has_dword_io(adev->id)) {
if (write_data)
- outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
- insl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) {
u32 pad;
if (write_data) {
memcpy(&pad, buf + buflen - slop, slop);
- outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ pad = le32_to_cpu(pad);
+ iowrite32(pad, ap->ioaddr.data_addr);
} else {
- pad = cpu_to_le32(inl(ap->ioaddr.data_addr));
+ pad = ioread32(ap->ioaddr.data_addr);
+ pad = cpu_to_le32(pad);
memcpy(buf + buflen - slop, &pad, slop);
}
}
} else
- ata_pio_data_xfer(adev, buf, buflen, write_data);
+ ata_data_xfer(adev, buf, buflen, write_data);
}
static struct scsi_host_template qdi_sht = {
@@ -189,10 +191,10 @@ static struct ata_port_operations qdi6500_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations qdi6580_port_ops = {
@@ -217,10 +219,10 @@ static struct ata_port_operations qdi6580_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -238,17 +240,22 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
{
struct ata_probe_ent ae;
struct platform_device *pdev;
+ void __iomem *io_addr, *ctl_addr;
int ret;
- unsigned long ctrl = io + 0x206;
-
/*
* Fill in a probe structure first of all
*/
pdev = platform_device_register_simple(DRV_NAME, nr_qdi_host, NULL, 0);
- if (pdev == NULL)
- return -ENOMEM;
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ ret = -ENOMEM;
+ io_addr = devm_ioport_map(&pdev->dev, io, 8);
+ ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1);
+ if (!io_addr || !ctl_addr)
+ goto fail;
memset(&ae, 0, sizeof(struct ata_probe_ent));
INIT_LIST_HEAD(&ae.node);
@@ -267,9 +274,9 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
ae.irq = irq;
ae.irq_flags = 0;
ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- ae.port[0].cmd_addr = io;
- ae.port[0].altstatus_addr = ctrl;
- ae.port[0].ctl_addr = ctrl;
+ ae.port[0].cmd_addr = io_addr;
+ ae.port[0].altstatus_addr = ctl_addr;
+ ae.port[0].ctl_addr = ctl_addr;
ata_std_ports(&ae.port[0]);
/*
@@ -282,14 +289,17 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
qdi_data[nr_qdi_host].platform_dev = pdev;
printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io);
- ret = ata_device_add(&ae);
- if (ret == 0) {
- platform_device_unregister(pdev);
- return -ENODEV;
- }
+
+ ret = -ENODEV;
+ if (!ata_device_add(&ae))
+ goto fail;
qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev);
return 0;
+
+ fail:
+ platform_device_unregister(pdev);
+ return ret;
}
/**
@@ -382,7 +392,7 @@ static __exit void qdi_exit(void)
int i;
for (i = 0; i < nr_qdi_host; i++) {
- ata_host_remove(qdi_host[i]);
+ ata_host_detach(qdi_host[i]);
/* Free the control resource. The 6580 dual channel has the resources
* claimed as a pair of 2 byte resources so we need no special cases...
*/
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 065541d034a..0d1e571ef63 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -255,14 +255,14 @@ static const struct ata_port_operations radisys_pata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = radisys_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 3677c642c9f..71a2bac09e0 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -52,19 +52,20 @@ static void rz1000_error_handler(struct ata_port *ap)
/**
* rz1000_set_mode - mode setting function
* @ap: ATA interface
+ * @unused: returned device on set_mode failure
*
* Use a non standard set_mode function. We don't want to be tuned. We
* would prefer to be BIOS generic but for the fact our hardware is
* whacked out.
*/
-static void rz1000_set_mode(struct ata_port *ap)
+static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused)
{
int i;
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
- if (ata_dev_enabled(dev)) {
+ if (ata_dev_ready(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
dev->xfer_mode = XFER_PIO_0;
@@ -72,6 +73,7 @@ static void rz1000_set_mode(struct ata_port *ap)
dev->flags |= ATA_DFLAG_PIO;
}
}
+ return 0;
}
@@ -105,8 +107,6 @@ static struct ata_port_operations rz1000_port_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .error_handler = rz1000_error_handler,
-
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
@@ -115,7 +115,7 @@ static struct ata_port_operations rz1000_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -124,10 +124,10 @@ static struct ata_port_operations rz1000_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int rz1000_fifo_disable(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index a3b35bc5039..58e42fbd14f 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -220,14 +220,14 @@ static struct ata_port_operations sc1200_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = sc1200_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index f02b6a3b0f1..ad5b43fef3d 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -218,25 +218,18 @@ static unsigned long serverworks_osb4_filter(const struct ata_port *ap, struct a
static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
{
const char *p;
- char model_num[40];
- int len, i;
+ char model_num[ATA_ID_PROD_LEN + 1];
+ int i;
/* Disk, UDMA */
if (adev->class != ATA_DEV_ATA)
return ata_pci_default_filter(ap, adev, mask);
/* Actually do need to check */
- ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
- /* Precuationary - why not do this in the libata core ?? */
+ ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
- len = strlen(model_num);
- while ((len > 0) && (model_num[len - 1] == ' ')) {
- len--;
- model_num[len] = 0;
- }
-
- for(i = 0; (p = csb_bad_ata100[i]) != NULL; i++) {
- if (!strncmp(p, model_num, len))
+ for (i = 0; (p = csb_bad_ata100[i]) != NULL; i++) {
+ if (!strcmp(p, model_num))
mask &= ~(0x1F << ATA_SHIFT_UDMA);
}
return ata_pci_default_filter(ap, adev, mask);
@@ -355,14 +348,14 @@ static struct ata_port_operations serverworks_osb4_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations serverworks_csb_port_ops = {
@@ -390,14 +383,14 @@ static struct ata_port_operations serverworks_csb_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int serverworks_fixup_osb4(struct pci_dev *pdev)
@@ -559,7 +552,7 @@ static int serverworks_reinit_one(struct pci_dev *pdev)
{
/* Force master latency timer to 64 PCI clocks */
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
-
+
switch (pdev->device)
{
case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index 32cf0bfa892..ed79fabe025 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -135,7 +135,7 @@ static void sil680_error_handler(struct ata_port *ap)
static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
static u16 speed_p[5] = { 0x328A, 0x2283, 0x1104, 0x10C3, 0x10C1 };
- static u16 speed_t[5] = { 0x328A, 0x1281, 0x1281, 0x10C3, 0x10C1 };
+ static u16 speed_t[5] = { 0x328A, 0x2283, 0x1281, 0x10C3, 0x10C1 };
unsigned long tfaddr = sil680_selreg(ap, 0x02);
unsigned long addr = sil680_seldev(ap, adev, 0x04);
@@ -252,14 +252,14 @@ static struct ata_port_operations sil680_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -270,7 +270,7 @@ static struct ata_port_operations sil680_port_ops = {
* is powered up on boot and when we resume in case we resumed from RAM.
* Returns the final clock settings.
*/
-
+
static u8 sil680_init_chip(struct pci_dev *pdev)
{
u32 class_rev = 0;
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 916cedb3d75..560103d55b2 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -32,7 +32,9 @@
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <linux/ata.h>
+#include "libata.h"
+#undef DRV_NAME /* already defined in libata.h, for libata-core */
#define DRV_NAME "pata_sis"
#define DRV_VERSION "0.4.5"
@@ -43,6 +45,34 @@ struct sis_chipset {
up code later */
};
+struct sis_laptop {
+ u16 device;
+ u16 subvendor;
+ u16 subdevice;
+};
+
+static const struct sis_laptop sis_laptop[] = {
+ /* devid, subvendor, subdev */
+ { 0x5513, 0x1043, 0x1107 }, /* ASUS A6K */
+ /* end marker */
+ { 0, }
+};
+
+static int sis_short_ata40(struct pci_dev *dev)
+{
+ const struct sis_laptop *lap = &sis_laptop[0];
+
+ while (lap->device) {
+ if (lap->device == dev->device &&
+ lap->subvendor == dev->subsystem_vendor &&
+ lap->subdevice == dev->subsystem_device)
+ return 1;
+ lap++;
+ }
+
+ return 0;
+}
+
/**
* sis_port_base - return PCI configuration base for dev
* @adev: device
@@ -79,7 +109,7 @@ static int sis_133_pre_reset(struct ata_port *ap)
/* 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)
+ if ((tmp & 0x8000) && !sis_short_ata40(pdev))
ap->cbl = ATA_CBL_PATA40;
else
ap->cbl = ATA_CBL_PATA80;
@@ -127,7 +157,7 @@ static int sis_66_pre_reset(struct ata_port *ap)
/* Older chips keep cable detect in bits 4/5 of reg 0x48 */
pci_read_config_byte(pdev, 0x48, &tmp);
tmp >>= ap->port_no;
- if (tmp & 0x10)
+ if ((tmp & 0x10) && !sis_short_ata40(pdev))
ap->cbl = ATA_CBL_PATA40;
else
ap->cbl = ATA_CBL_PATA80;
@@ -573,14 +603,14 @@ static const struct ata_port_operations sis_133_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static const struct ata_port_operations sis_133_early_ops = {
@@ -606,14 +636,14 @@ static const struct ata_port_operations sis_133_early_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static const struct ata_port_operations sis_100_ops = {
@@ -640,14 +670,14 @@ static const struct ata_port_operations sis_100_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static const struct ata_port_operations sis_66_ops = {
@@ -673,14 +703,14 @@ static const struct ata_port_operations sis_66_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static const struct ata_port_operations sis_old_ops = {
@@ -706,14 +736,14 @@ static const struct ata_port_operations sis_old_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static struct ata_port_info sis_info = {
@@ -753,7 +783,7 @@ static struct ata_port_info sis_info100_early = {
.pio_mask = 0x1f, /* pio0-4 */
.port_ops = &sis_66_ops,
};
-static struct ata_port_info sis_info133 = {
+struct ata_port_info sis_info133 = {
.sht = &sis_sht,
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
.pio_mask = 0x1f, /* pio0-4 */
@@ -768,6 +798,8 @@ static struct ata_port_info sis_info133_early = {
.port_ops = &sis_133_early_ops,
};
+/* Privately shared with the SiS180 SATA driver, not for use elsewhere */
+EXPORT_SYMBOL_GPL(sis_info133);
static void sis_fixup(struct pci_dev *pdev, struct sis_chipset *sis)
{
@@ -847,7 +879,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct sis_chipset *chipset = NULL;
static struct sis_chipset sis_chipsets[] = {
-
+
{ 0x0968, &sis_info133 },
{ 0x0966, &sis_info133 },
{ 0x0965, &sis_info133 },
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index e94f515ef54..f2fa158d07c 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -139,13 +139,13 @@ static void sl82c105_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
switch(adev->dma_mode) {
case XFER_MW_DMA_0:
- sl82c105_configure_piomode(ap, adev, 1);
+ sl82c105_configure_piomode(ap, adev, 0);
break;
case XFER_MW_DMA_1:
sl82c105_configure_piomode(ap, adev, 3);
break;
case XFER_MW_DMA_2:
- sl82c105_configure_piomode(ap, adev, 3);
+ sl82c105_configure_piomode(ap, adev, 4);
break;
default:
BUG();
@@ -262,14 +262,14 @@ static struct ata_port_operations sl82c105_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index a142971f130..453ab90b721 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -221,14 +221,14 @@ static struct ata_port_operations triflex_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index cc09d47fb92..220fcd6c549 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -23,6 +23,7 @@
* VIA VT8233c - UDMA100
* VIA VT8235 - UDMA133
* VIA VT8237 - UDMA133
+ * VIA VT8237S - UDMA133
* VIA VT8251 - UDMA133
*
* Most registers remain compatible across chips. Others start reserved
@@ -61,7 +62,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_via"
-#define DRV_VERSION "0.2.0"
+#define DRV_VERSION "0.2.1"
/*
* The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
@@ -95,6 +96,7 @@ static const struct via_isa_bridge {
u8 rev_max;
u16 flags;
} via_isa_bridges[] = {
+ { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES},
@@ -161,10 +163,15 @@ static int via_pre_reset(struct ata_port *ap)
return -ENOENT;
}
- if ((config->flags & VIA_UDMA) >= VIA_UDMA_66)
+ if ((config->flags & VIA_UDMA) >= VIA_UDMA_100)
ap->cbl = via_cable_detect(ap);
- else
+ /* The UDMA66 series has no cable detect so do drive side detect */
+ else if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA_UNK;
+
+
return ata_std_prereset(ap);
}
@@ -327,14 +334,14 @@ static struct ata_port_operations via_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations via_port_ops_noirq = {
@@ -362,14 +369,14 @@ static struct ata_port_operations via_port_ops_noirq = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer_noirq,
+ .data_xfer = ata_data_xfer_noirq,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -384,13 +391,13 @@ static struct ata_port_operations via_port_ops_noirq = {
static void via_config_fifo(struct pci_dev *pdev, unsigned int flags)
{
u8 enable;
-
+
/* 0x40 low bits indicate enabled channels */
pci_read_config_byte(pdev, 0x40 , &enable);
enable &= 3;
-
+
if (flags & VIA_SET_FIFO) {
- u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20};
+ static const u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20};
u8 fifo;
pci_read_config_byte(pdev, 0x43, &fifo);
@@ -509,7 +516,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
/* Initialise the FIFO for the enabled channels. */
via_config_fifo(pdev, config->flags);
-
+
/* Clock set up */
switch(config->flags & VIA_UDMA) {
case VIA_UDMA_NONE:
@@ -568,7 +575,7 @@ static int via_reinit_one(struct pci_dev *pdev)
u32 timing;
struct ata_host *host = dev_get_drvdata(&pdev->dev);
const struct via_isa_bridge *config = host->private_data;
-
+
via_config_fifo(pdev, config->flags);
if ((config->flags & VIA_UDMA) == VIA_UDMA_66) {
@@ -583,7 +590,7 @@ static int via_reinit_one(struct pci_dev *pdev)
timing &= ~0x80008;
pci_write_config_dword(pdev, 0x50, timing);
}
- return ata_pci_device_resume(pdev);
+ return ata_pci_device_resume(pdev);
}
static const struct pci_device_id via[] = {
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 3ea345cde52..0888b4f19f4 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -5,7 +5,7 @@
* Support for the Winbond 83759A when operating in advanced mode.
* Multichip mode is not currently supported.
*/
-
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -69,7 +69,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2);
reg = winbond_readcfg(winbond->config, 0x81);
-
+
/* Get the timing data in cycles */
if (reg & 0x40) /* Fast VLB bus, assume 50MHz */
ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
@@ -80,9 +80,9 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
timing = (active << 4) | recovery;
winbond_writecfg(winbond->config, timing, reg);
-
+
/* Load the setup timing */
-
+
reg = 0x35;
if (adev->class != ATA_DEV_ATA)
reg |= 0x08; /* FIFO off */
@@ -100,22 +100,24 @@ static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsig
if (ata_id_has_dword_io(adev->id)) {
if (write_data)
- outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
- insl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) {
u32 pad;
if (write_data) {
memcpy(&pad, buf + buflen - slop, slop);
- outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ pad = le32_to_cpu(pad);
+ iowrite32(pad, ap->ioaddr.data_addr);
} else {
- pad = cpu_to_le16(inl(ap->ioaddr.data_addr));
+ pad = ioread32(ap->ioaddr.data_addr);
+ pad = cpu_to_le16(pad);
memcpy(buf + buflen - slop, &pad, slop);
}
}
} else
- ata_pio_data_xfer(adev, buf, buflen, write_data);
+ ata_data_xfer(adev, buf, buflen, write_data);
}
static struct scsi_host_template winbond_sht = {
@@ -158,10 +160,10 @@ static struct ata_port_operations winbond_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -194,20 +196,29 @@ static __init int winbond_init_one(unsigned long port)
winbond_writecfg(port, 0x85, reg);
reg = winbond_readcfg(port, 0x81);
-
+
if (!(reg & 0x03)) /* Disabled */
return 0;
for (i = 0; i < 2 ; i ++) {
+ unsigned long cmd_port = 0x1F0 - (0x80 * i);
+ void __iomem *cmd_addr, *ctl_addr;
- if (reg & (1 << i)) {
+ if (reg & (1 << i)) {
/*
* Fill in a probe structure first of all
*/
pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0);
- if (pdev == NULL)
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
+ ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
+ if (!cmd_addr || !ctl_addr) {
+ platform_device_unregister(pdev);
return -ENOMEM;
+ }
memset(&ae, 0, sizeof(struct ata_probe_ent));
INIT_LIST_HEAD(&ae.node);
@@ -217,14 +228,14 @@ static __init int winbond_init_one(unsigned long port)
ae.pio_mask = 0x1F;
ae.sht = &winbond_sht;
-
+
ae.n_ports = 1;
ae.irq = 14 + i;
ae.irq_flags = 0;
ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- ae.port[0].cmd_addr = 0x1F0 - (0x80 * i);
- ae.port[0].altstatus_addr = ae.port[0].cmd_addr + 0x0206;
- ae.port[0].ctl_addr = ae.port[0].altstatus_addr;
+ ae.port[0].cmd_addr = cmd_addr;
+ ae.port[0].altstatus_addr = ctl_addr;
+ ae.port[0].ctl_addr = ctl_addr;
ata_std_ports(&ae.port[0]);
/*
* Hook in a private data structure per channel
@@ -257,7 +268,7 @@ static __init int winbond_init(void)
int ct = 0;
int i;
-
+
if (probe_winbond == 0)
return -ENODEV;
@@ -288,7 +299,7 @@ static __exit void winbond_exit(void)
int i;
for (i = 0; i < nr_winbond_host; i++) {
- ata_host_remove(winbond_host[i]);
+ ata_host_detach(winbond_host[i]);
release_region(winbond_data[i].config, 2);
platform_device_unregister(winbond_data[i].platform_dev);
}
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 9021e34d209..b4ed8ce553e 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -42,7 +42,6 @@
#include <linux/sched.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
-#include <asm/io.h>
#include <linux/libata.h>
#define DRV_NAME "pdc_adma"
@@ -52,9 +51,15 @@
#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40))
/* macro to calculate base address for ADMA regs */
-#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
+#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
+
+/* macro to obtain addresses from ata_host */
+#define ADMA_HOST_REGS(host,port_no) \
+ ADMA_REGS((host)->iomap[ADMA_MMIO_BAR], port_no)
enum {
+ ADMA_MMIO_BAR = 4,
+
ADMA_PORTS = 2,
ADMA_CPB_BYTES = 40,
ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16,
@@ -167,9 +172,11 @@ static const struct ata_port_operations adma_ata_ops = {
.qc_prep = adma_qc_prep,
.qc_issue = adma_qc_issue,
.eng_timeout = adma_eng_timeout,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = adma_intr,
.irq_clear = adma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = adma_port_start,
.port_stop = adma_port_stop,
.host_stop = adma_host_stop,
@@ -235,11 +242,10 @@ static void adma_reset_engine(void __iomem *chan)
static void adma_reinit_engine(struct ata_port *ap)
{
struct adma_port_priv *pp = ap->private_data;
- void __iomem *mmio_base = ap->host->mmio_base;
- void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no);
+ void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
/* mask/clear ATA interrupts */
- writeb(ATA_NIEN, (void __iomem *)ap->ioaddr.ctl_addr);
+ writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
ata_check_status(ap);
/* reset the ADMA engine */
@@ -263,7 +269,7 @@ static void adma_reinit_engine(struct ata_port *ap)
static inline void adma_enter_reg_mode(struct ata_port *ap)
{
- void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no);
+ void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
writew(aPIOMD4, chan + ADMA_CONTROL);
readb(chan + ADMA_STATUS); /* flush */
@@ -410,7 +416,7 @@ static void adma_qc_prep(struct ata_queued_cmd *qc)
static inline void adma_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no);
+ void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
VPRINTK("ENTER, ap %p\n", ap);
@@ -443,13 +449,12 @@ static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
static inline unsigned int adma_intr_pkt(struct ata_host *host)
{
unsigned int handled = 0, port_no;
- u8 __iomem *mmio_base = host->mmio_base;
for (port_no = 0; port_no < host->n_ports; ++port_no) {
struct ata_port *ap = host->ports[port_no];
struct adma_port_priv *pp;
struct ata_queued_cmd *qc;
- void __iomem *chan = ADMA_REGS(mmio_base, port_no);
+ void __iomem *chan = ADMA_HOST_REGS(host, port_no);
u8 status = readb(chan + ADMA_STATUS);
if (status == 0)
@@ -523,7 +528,7 @@ static irqreturn_t adma_intr(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
-static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base)
+static void adma_ata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr =
port->data_addr = base + 0x000;
@@ -550,48 +555,28 @@ static int adma_port_start(struct ata_port *ap)
if (rc)
return rc;
adma_enter_reg_mode(ap);
- rc = -ENOMEM;
- pp = kcalloc(1, sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
- goto err_out;
- pp->pkt = dma_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma,
- GFP_KERNEL);
+ return -ENOMEM;
+ pp->pkt = dmam_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma,
+ GFP_KERNEL);
if (!pp->pkt)
- goto err_out_kfree;
+ return -ENOMEM;
/* paranoia? */
if ((pp->pkt_dma & 7) != 0) {
printk("bad alignment for pp->pkt_dma: %08x\n",
(u32)pp->pkt_dma);
- dma_free_coherent(dev, ADMA_PKT_BYTES,
- pp->pkt, pp->pkt_dma);
- goto err_out_kfree;
+ return -ENOMEM;
}
memset(pp->pkt, 0, ADMA_PKT_BYTES);
ap->private_data = pp;
adma_reinit_engine(ap);
return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
}
static void adma_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host->dev;
- struct adma_port_priv *pp = ap->private_data;
-
- adma_reset_engine(ADMA_REGS(ap->host->mmio_base, ap->port_no));
- if (pp != NULL) {
- ap->private_data = NULL;
- if (pp->pkt != NULL)
- dma_free_coherent(dev, ADMA_PKT_BYTES,
- pp->pkt, pp->pkt_dma);
- kfree(pp);
- }
- ata_port_stop(ap);
+ adma_reset_engine(ADMA_HOST_REGS(ap->host, ap->port_no));
}
static void adma_host_stop(struct ata_host *host)
@@ -599,16 +584,14 @@ static void adma_host_stop(struct ata_host *host)
unsigned int port_no;
for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
- adma_reset_engine(ADMA_REGS(host->mmio_base, port_no));
-
- ata_pci_host_stop(host);
+ adma_reset_engine(ADMA_HOST_REGS(host, port_no));
}
static void adma_host_init(unsigned int chip_id,
struct ata_probe_ent *probe_ent)
{
unsigned int port_no;
- void __iomem *mmio_base = probe_ent->mmio_base;
+ void __iomem *mmio_base = probe_ent->iomap[ADMA_MMIO_BAR];
/* enable/lock aGO operation */
writeb(7, mmio_base + ADMA_MODE_LOCK);
@@ -638,7 +621,7 @@ static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
}
static int adma_ata_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
static int printed_version;
struct ata_probe_ent *probe_ent = NULL;
@@ -649,34 +632,25 @@ static int adma_ata_init_one(struct pci_dev *pdev,
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc)
- goto err_out;
-
- if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
- rc = -ENODEV;
- goto err_out_regions;
- }
+ if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0)
+ return -ENODEV;
- mmio_base = pci_iomap(pdev, 4, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME);
+ if (rc)
+ return rc;
+ mmio_base = pcim_iomap_table(pdev)[ADMA_MMIO_BAR];
rc = adma_set_dma_masks(pdev, mmio_base);
if (rc)
- goto err_out_iounmap;
+ return rc;
- probe_ent = kcalloc(1, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
@@ -690,12 +664,12 @@ static int adma_ata_init_one(struct pci_dev *pdev,
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
probe_ent->n_ports = ADMA_PORTS;
+ probe_ent->iomap = pcim_iomap_table(pdev);
for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
adma_ata_setup_port(&probe_ent->port[port_no],
- ADMA_ATA_REGS((unsigned long)mmio_base, port_no));
+ ADMA_ATA_REGS(mmio_base, port_no));
}
pci_set_master(pdev);
@@ -703,19 +677,11 @@ static int adma_ata_init_one(struct pci_dev *pdev,
/* initialize adapter */
adma_host_init(board_idx, probe_ent);
- rc = ata_device_add(probe_ent);
- kfree(probe_ent);
- if (rc != ADMA_PORTS)
- goto err_out_iounmap;
- return 0;
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- pci_disable_device(pdev);
- return rc;
+ devm_kfree(&pdev->dev, probe_ent);
+ return 0;
}
static int __init adma_ata_init(void)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
new file mode 100644
index 00000000000..c5335f42280
--- /dev/null
+++ b/drivers/ata/sata_inic162x.c
@@ -0,0 +1,781 @@
+/*
+ * sata_inic162x.c - Driver for Initio 162x SATA controllers
+ *
+ * Copyright 2006 SUSE Linux Products GmbH
+ * Copyright 2006 Tejun Heo <teheo@novell.com>
+ *
+ * This file is released under GPL v2.
+ *
+ * This controller is eccentric and easily locks up if something isn't
+ * right. Documentation is available at initio's website but it only
+ * documents registers (not programming model).
+ *
+ * - ATA disks work.
+ * - Hotplug works.
+ * - ATAPI read works but burning doesn't. This thing is really
+ * peculiar about ATAPI and I couldn't figure out how ATAPI PIO and
+ * ATAPI DMA WRITE should be programmed. If you've got a clue, be
+ * my guest.
+ * - Both STR and STD work.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_device.h>
+
+#define DRV_NAME "sata_inic162x"
+#define DRV_VERSION "0.1"
+
+enum {
+ MMIO_BAR = 5,
+
+ NR_PORTS = 2,
+
+ HOST_CTL = 0x7c,
+ HOST_STAT = 0x7e,
+ HOST_IRQ_STAT = 0xbc,
+ HOST_IRQ_MASK = 0xbe,
+
+ PORT_SIZE = 0x40,
+
+ /* registers for ATA TF operation */
+ PORT_TF = 0x00,
+ PORT_ALT_STAT = 0x08,
+ PORT_IRQ_STAT = 0x09,
+ PORT_IRQ_MASK = 0x0a,
+ PORT_PRD_CTL = 0x0b,
+ PORT_PRD_ADDR = 0x0c,
+ PORT_PRD_XFERLEN = 0x10,
+
+ /* IDMA register */
+ PORT_IDMA_CTL = 0x14,
+
+ PORT_SCR = 0x20,
+
+ /* HOST_CTL bits */
+ HCTL_IRQOFF = (1 << 8), /* global IRQ off */
+ HCTL_PWRDWN = (1 << 13), /* power down PHYs */
+ HCTL_SOFTRST = (1 << 13), /* global reset (no phy reset) */
+ HCTL_RPGSEL = (1 << 15), /* register page select */
+
+ HCTL_KNOWN_BITS = HCTL_IRQOFF | HCTL_PWRDWN | HCTL_SOFTRST |
+ HCTL_RPGSEL,
+
+ /* HOST_IRQ_(STAT|MASK) bits */
+ HIRQ_PORT0 = (1 << 0),
+ HIRQ_PORT1 = (1 << 1),
+ HIRQ_SOFT = (1 << 14),
+ HIRQ_GLOBAL = (1 << 15), /* STAT only */
+
+ /* PORT_IRQ_(STAT|MASK) bits */
+ PIRQ_OFFLINE = (1 << 0), /* device unplugged */
+ PIRQ_ONLINE = (1 << 1), /* device plugged */
+ PIRQ_COMPLETE = (1 << 2), /* completion interrupt */
+ PIRQ_FATAL = (1 << 3), /* fatal error */
+ PIRQ_ATA = (1 << 4), /* ATA interrupt */
+ PIRQ_REPLY = (1 << 5), /* reply FIFO not empty */
+ PIRQ_PENDING = (1 << 7), /* port IRQ pending (STAT only) */
+
+ PIRQ_ERR = PIRQ_OFFLINE | PIRQ_ONLINE | PIRQ_FATAL,
+
+ PIRQ_MASK_DMA_READ = PIRQ_REPLY | PIRQ_ATA,
+ PIRQ_MASK_OTHER = PIRQ_REPLY | PIRQ_COMPLETE,
+ PIRQ_MASK_FREEZE = 0xff,
+
+ /* PORT_PRD_CTL bits */
+ PRD_CTL_START = (1 << 0),
+ PRD_CTL_WR = (1 << 3),
+ PRD_CTL_DMAEN = (1 << 7), /* DMA enable */
+
+ /* PORT_IDMA_CTL bits */
+ IDMA_CTL_RST_ATA = (1 << 2), /* hardreset ATA bus */
+ IDMA_CTL_RST_IDMA = (1 << 5), /* reset IDMA machinary */
+ IDMA_CTL_GO = (1 << 7), /* IDMA mode go */
+ IDMA_CTL_ATA_NIEN = (1 << 8), /* ATA IRQ disable */
+};
+
+struct inic_host_priv {
+ u16 cached_hctl;
+};
+
+struct inic_port_priv {
+ u8 dfl_prdctl;
+ u8 cached_prdctl;
+ u8 cached_pirq_mask;
+};
+
+static int inic_slave_config(struct scsi_device *sdev)
+{
+ /* This controller is braindamaged. dma_boundary is 0xffff
+ * like others but it will lock up the whole machine HARD if
+ * 65536 byte PRD entry is fed. Reduce maximum segment size.
+ */
+ blk_queue_max_segment_size(sdev->request_queue, 65536 - 512);
+
+ return ata_scsi_slave_config(sdev);
+}
+
+static struct scsi_host_template inic_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = inic_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
+};
+
+static const int scr_map[] = {
+ [SCR_STATUS] = 0,
+ [SCR_ERROR] = 1,
+ [SCR_CONTROL] = 2,
+};
+
+static void __iomem * inic_port_base(struct ata_port *ap)
+{
+ return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE;
+}
+
+static void __inic_set_pirq_mask(struct ata_port *ap, u8 mask)
+{
+ void __iomem *port_base = inic_port_base(ap);
+ struct inic_port_priv *pp = ap->private_data;
+
+ writeb(mask, port_base + PORT_IRQ_MASK);
+ pp->cached_pirq_mask = mask;
+}
+
+static void inic_set_pirq_mask(struct ata_port *ap, u8 mask)
+{
+ struct inic_port_priv *pp = ap->private_data;
+
+ if (pp->cached_pirq_mask != mask)
+ __inic_set_pirq_mask(ap, mask);
+}
+
+static void inic_reset_port(void __iomem *port_base)
+{
+ void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
+ u16 ctl;
+
+ ctl = readw(idma_ctl);
+ ctl &= ~(IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN | IDMA_CTL_GO);
+
+ /* mask IRQ and assert reset */
+ writew(ctl | IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN, idma_ctl);
+ readw(idma_ctl); /* flush */
+
+ /* give it some time */
+ msleep(1);
+
+ /* release reset */
+ writew(ctl | IDMA_CTL_ATA_NIEN, idma_ctl);
+
+ /* clear irq */
+ writeb(0xff, port_base + PORT_IRQ_STAT);
+
+ /* reenable ATA IRQ, turn off IDMA mode */
+ writew(ctl, idma_ctl);
+}
+
+static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg)
+{
+ void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+ void __iomem *addr;
+ u32 val;
+
+ if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
+ return 0xffffffffU;
+
+ addr = scr_addr + scr_map[sc_reg] * 4;
+ val = readl(scr_addr + scr_map[sc_reg] * 4);
+
+ /* this controller has stuck DIAG.N, ignore it */
+ if (sc_reg == SCR_ERROR)
+ val &= ~SERR_PHYRDY_CHG;
+ return val;
+}
+
+static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+{
+ void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+ void __iomem *addr;
+
+ if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
+ return;
+
+ addr = scr_addr + scr_map[sc_reg] * 4;
+ writel(val, scr_addr + scr_map[sc_reg] * 4);
+}
+
+/*
+ * In TF mode, inic162x is very similar to SFF device. TF registers
+ * function the same. DMA engine behaves similary using the same PRD
+ * format as BMDMA but different command register, interrupt and event
+ * notification methods are used. The following inic_bmdma_*()
+ * functions do the impedance matching.
+ */
+static void inic_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct inic_port_priv *pp = ap->private_data;
+ void __iomem *port_base = inic_port_base(ap);
+ int rw = qc->tf.flags & ATA_TFLAG_WRITE;
+
+ /* make sure device sees PRD table writes */
+ wmb();
+
+ /* load transfer length */
+ writel(qc->nbytes, port_base + PORT_PRD_XFERLEN);
+
+ /* turn on DMA and specify data direction */
+ pp->cached_prdctl = pp->dfl_prdctl | PRD_CTL_DMAEN;
+ if (!rw)
+ pp->cached_prdctl |= PRD_CTL_WR;
+ writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
+
+ /* issue r/w command */
+ ap->ops->exec_command(ap, &qc->tf);
+}
+
+static void inic_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct inic_port_priv *pp = ap->private_data;
+ void __iomem *port_base = inic_port_base(ap);
+
+ /* start host DMA transaction */
+ pp->cached_prdctl |= PRD_CTL_START;
+ writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
+}
+
+static void inic_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct inic_port_priv *pp = ap->private_data;
+ void __iomem *port_base = inic_port_base(ap);
+
+ /* stop DMA engine */
+ writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
+}
+
+static u8 inic_bmdma_status(struct ata_port *ap)
+{
+ /* event is already verified by the interrupt handler */
+ return ATA_DMA_INTR;
+}
+
+static void inic_irq_clear(struct ata_port *ap)
+{
+ /* noop */
+}
+
+static void inic_host_intr(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+ struct ata_eh_info *ehi = &ap->eh_info;
+ u8 irq_stat;
+
+ /* fetch and clear irq */
+ irq_stat = readb(port_base + PORT_IRQ_STAT);
+ writeb(irq_stat, port_base + PORT_IRQ_STAT);
+
+ if (likely(!(irq_stat & PIRQ_ERR))) {
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+
+ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+ ata_chk_status(ap); /* clear ATA interrupt */
+ return;
+ }
+
+ if (likely(ata_host_intr(ap, qc)))
+ return;
+
+ ata_chk_status(ap); /* clear ATA interrupt */
+ ata_port_printk(ap, KERN_WARNING, "unhandled "
+ "interrupt, irq_stat=%x\n", irq_stat);
+ return;
+ }
+
+ /* error */
+ ata_ehi_push_desc(ehi, "irq_stat=0x%x", irq_stat);
+
+ if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
+ ata_ehi_hotplugged(ehi);
+ ata_port_freeze(ap);
+ } else
+ ata_port_abort(ap);
+}
+
+static irqreturn_t inic_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ void __iomem *mmio_base = host->iomap[MMIO_BAR];
+ u16 host_irq_stat;
+ int i, handled = 0;;
+
+ host_irq_stat = readw(mmio_base + HOST_IRQ_STAT);
+
+ if (unlikely(!(host_irq_stat & HIRQ_GLOBAL)))
+ goto out;
+
+ spin_lock(&host->lock);
+
+ for (i = 0; i < NR_PORTS; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (!(host_irq_stat & (HIRQ_PORT0 << i)))
+ continue;
+
+ if (likely(ap && !(ap->flags & ATA_FLAG_DISABLED))) {
+ inic_host_intr(ap);
+ handled++;
+ } else {
+ if (ata_ratelimit())
+ dev_printk(KERN_ERR, host->dev, "interrupt "
+ "from disabled port %d (0x%x)\n",
+ i, host_irq_stat);
+ }
+ }
+
+ spin_unlock(&host->lock);
+
+ out:
+ return IRQ_RETVAL(handled);
+}
+
+static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ /* ATA IRQ doesn't wait for DMA transfer completion and vice
+ * versa. Mask IRQ selectively to detect command completion.
+ * Without it, ATA DMA read command can cause data corruption.
+ *
+ * Something similar might be needed for ATAPI writes. I
+ * tried a lot of combinations but couldn't find the solution.
+ */
+ if (qc->tf.protocol == ATA_PROT_DMA &&
+ !(qc->tf.flags & ATA_TFLAG_WRITE))
+ inic_set_pirq_mask(ap, PIRQ_MASK_DMA_READ);
+ else
+ inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+
+ /* Issuing a command to yet uninitialized port locks up the
+ * controller. Most of the time, this happens for the first
+ * command after reset which are ATA and ATAPI IDENTIFYs.
+ * Fast fail if stat is 0x7f or 0xff for those commands.
+ */
+ if (unlikely(qc->tf.command == ATA_CMD_ID_ATA ||
+ qc->tf.command == ATA_CMD_ID_ATAPI)) {
+ u8 stat = ata_chk_status(ap);
+ if (stat == 0x7f || stat == 0xff)
+ return AC_ERR_HSM;
+ }
+
+ return ata_qc_issue_prot(qc);
+}
+
+static void inic_freeze(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ __inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE);
+
+ ata_chk_status(ap);
+ writeb(0xff, port_base + PORT_IRQ_STAT);
+
+ readb(port_base + PORT_IRQ_STAT); /* flush */
+}
+
+static void inic_thaw(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ ata_chk_status(ap);
+ writeb(0xff, port_base + PORT_IRQ_STAT);
+
+ __inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+
+ readb(port_base + PORT_IRQ_STAT); /* flush */
+}
+
+/*
+ * SRST and SControl hardreset don't give valid signature on this
+ * controller. Only controller specific hardreset mechanism works.
+ */
+static int inic_hardreset(struct ata_port *ap, unsigned int *class)
+{
+ void __iomem *port_base = inic_port_base(ap);
+ void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
+ const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+ u16 val;
+ int rc;
+
+ /* hammer it into sane state */
+ inic_reset_port(port_base);
+
+ val = readw(idma_ctl);
+ writew(val | IDMA_CTL_RST_ATA, idma_ctl);
+ readw(idma_ctl); /* flush */
+ msleep(1);
+ writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
+
+ rc = sata_phy_resume(ap, timing);
+ if (rc) {
+ ata_port_printk(ap, KERN_WARNING, "failed to resume "
+ "link after reset (errno=%d)\n", rc);
+ return rc;
+ }
+
+ *class = ATA_DEV_NONE;
+ if (ata_port_online(ap)) {
+ struct ata_taskfile tf;
+
+ /* wait a while before checking status */
+ msleep(150);
+
+ if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+ ata_port_printk(ap, KERN_WARNING,
+ "device busy after hardreset\n");
+ return -EIO;
+ }
+
+ ata_tf_read(ap, &tf);
+ *class = ata_dev_classify(&tf);
+ if (*class == ATA_DEV_UNKNOWN)
+ *class = ATA_DEV_NONE;
+ }
+
+ return 0;
+}
+
+static void inic_error_handler(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+ struct inic_port_priv *pp = ap->private_data;
+ unsigned long flags;
+
+ /* reset PIO HSM and stop DMA engine */
+ inic_reset_port(port_base);
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->hsm_task_state = HSM_ST_IDLE;
+ writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* PIO and DMA engines have been stopped, perform recovery */
+ ata_do_eh(ap, ata_std_prereset, NULL, inic_hardreset,
+ ata_std_postreset);
+}
+
+static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ /* make DMA engine forget about the failed command */
+ if (qc->err_mask)
+ inic_reset_port(inic_port_base(qc->ap));
+}
+
+static void inic_dev_config(struct ata_port *ap, struct ata_device *dev)
+{
+ /* inic can only handle upto LBA28 max sectors */
+ if (dev->max_sectors > ATA_MAX_SECTORS)
+ dev->max_sectors = ATA_MAX_SECTORS;
+}
+
+static void init_port(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ /* Setup PRD address */
+ writel(ap->prd_dma, port_base + PORT_PRD_ADDR);
+}
+
+static int inic_port_resume(struct ata_port *ap)
+{
+ init_port(ap);
+ return 0;
+}
+
+static int inic_port_start(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+ struct inic_port_priv *pp;
+ u8 tmp;
+ int rc;
+
+ /* alloc and initialize private data */
+ pp = devm_kzalloc(ap->host->dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+ ap->private_data = pp;
+
+ /* default PRD_CTL value, DMAEN, WR and START off */
+ tmp = readb(port_base + PORT_PRD_CTL);
+ tmp &= ~(PRD_CTL_DMAEN | PRD_CTL_WR | PRD_CTL_START);
+ pp->dfl_prdctl = tmp;
+
+ /* Alloc resources */
+ rc = ata_port_start(ap);
+ if (rc) {
+ kfree(pp);
+ return rc;
+ }
+
+ init_port(ap);
+
+ return 0;
+}
+
+static struct ata_port_operations inic_port_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .scr_read = inic_scr_read,
+ .scr_write = inic_scr_write,
+
+ .bmdma_setup = inic_bmdma_setup,
+ .bmdma_start = inic_bmdma_start,
+ .bmdma_stop = inic_bmdma_stop,
+ .bmdma_status = inic_bmdma_status,
+
+ .irq_handler = inic_interrupt,
+ .irq_clear = inic_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = inic_qc_issue,
+ .data_xfer = ata_data_xfer,
+
+ .freeze = inic_freeze,
+ .thaw = inic_thaw,
+ .error_handler = inic_error_handler,
+ .post_internal_cmd = inic_post_internal_cmd,
+ .dev_config = inic_dev_config,
+
+ .port_resume = inic_port_resume,
+
+ .port_start = inic_port_start,
+};
+
+static struct ata_port_info inic_port_info = {
+ .sht = &inic_sht,
+ /* For some reason, ATA_PROT_ATAPI is broken on this
+ * controller, and no, PIO_POLLING does't fix it. It somehow
+ * manages to report the wrong ireason and ignoring ireason
+ * results in machine lock up. Tell libata to always prefer
+ * DMA.
+ */
+ .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &inic_port_ops
+};
+
+static int init_controller(void __iomem *mmio_base, u16 hctl)
+{
+ int i;
+ u16 val;
+
+ hctl &= ~HCTL_KNOWN_BITS;
+
+ /* Soft reset whole controller. Spec says reset duration is 3
+ * PCI clocks, be generous and give it 10ms.
+ */
+ writew(hctl | HCTL_SOFTRST, mmio_base + HOST_CTL);
+ readw(mmio_base + HOST_CTL); /* flush */
+
+ for (i = 0; i < 10; i++) {
+ msleep(1);
+ val = readw(mmio_base + HOST_CTL);
+ if (!(val & HCTL_SOFTRST))
+ break;
+ }
+
+ if (val & HCTL_SOFTRST)
+ return -EIO;
+
+ /* mask all interrupts and reset ports */
+ for (i = 0; i < NR_PORTS; i++) {
+ void __iomem *port_base = mmio_base + i * PORT_SIZE;
+
+ writeb(0xff, port_base + PORT_IRQ_MASK);
+ inic_reset_port(port_base);
+ }
+
+ /* port IRQ is masked now, unmask global IRQ */
+ writew(hctl & ~HCTL_IRQOFF, mmio_base + HOST_CTL);
+ val = readw(mmio_base + HOST_IRQ_MASK);
+ val &= ~(HIRQ_PORT0 | HIRQ_PORT1);
+ writew(val, mmio_base + HOST_IRQ_MASK);
+
+ return 0;
+}
+
+static int inic_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct inic_host_priv *hpriv = host->private_data;
+ void __iomem *mmio_base = host->iomap[MMIO_BAR];
+ int rc;
+
+ ata_pci_device_do_resume(pdev);
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ printk("XXX\n");
+ rc = init_controller(mmio_base, hpriv->cached_hctl);
+ if (rc)
+ return rc;
+ }
+
+ ata_host_resume(host);
+
+ return 0;
+}
+
+static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_port_info *pinfo = &inic_port_info;
+ struct ata_probe_ent *probe_ent;
+ struct inic_host_priv *hpriv;
+ void __iomem * const *iomap;
+ int i, rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ return rc;
+
+ rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
+ if (rc)
+ return rc;
+ iomap = pcim_iomap_table(pdev);
+
+ /* Set dma_mask. This devices doesn't support 64bit addressing. */
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ return rc;
+ }
+
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!probe_ent || !hpriv)
+ return -ENOMEM;
+
+ probe_ent->dev = &pdev->dev;
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ probe_ent->sht = pinfo->sht;
+ probe_ent->port_flags = pinfo->flags;
+ probe_ent->pio_mask = pinfo->pio_mask;
+ probe_ent->mwdma_mask = pinfo->mwdma_mask;
+ probe_ent->udma_mask = pinfo->udma_mask;
+ probe_ent->port_ops = pinfo->port_ops;
+ probe_ent->n_ports = NR_PORTS;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = SA_SHIRQ;
+
+ probe_ent->iomap = iomap;
+
+ for (i = 0; i < NR_PORTS; i++) {
+ struct ata_ioports *port = &probe_ent->port[i];
+ void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
+
+ port->cmd_addr = iomap[2 * i];
+ port->altstatus_addr =
+ port->ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
+ port->scr_addr = port_base + PORT_SCR;
+
+ ata_std_ports(port);
+ }
+
+ probe_ent->private_data = hpriv;
+ hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
+
+ rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to initialize controller\n");
+ return rc;
+ }
+
+ pci_set_master(pdev);
+
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+
+ devm_kfree(&pdev->dev, probe_ent);
+
+ return 0;
+}
+
+static const struct pci_device_id inic_pci_tbl[] = {
+ { PCI_VDEVICE(INIT, 0x1622), },
+ { },
+};
+
+static struct pci_driver inic_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = inic_pci_tbl,
+ .suspend = ata_pci_device_suspend,
+ .resume = inic_pci_device_resume,
+ .probe = inic_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init inic_init(void)
+{
+ return pci_register_driver(&inic_pci_driver);
+}
+
+static void __exit inic_exit(void)
+{
+ pci_unregister_driver(&inic_pci_driver);
+}
+
+MODULE_AUTHOR("Tejun Heo");
+MODULE_DESCRIPTION("low-level driver for Initio 162x SATA");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, inic_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(inic_init);
+module_exit(inic_exit);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 1b8e0eb9e03..769eca52442 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -34,7 +34,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#define DRV_NAME "sata_mv"
#define DRV_VERSION "0.7"
@@ -342,7 +341,6 @@ static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
static void mv_phy_reset(struct ata_port *ap);
static void __mv_phy_reset(struct ata_port *ap, int can_sleep);
-static void mv_host_stop(struct ata_host *host);
static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap);
static void mv_qc_prep(struct ata_queued_cmd *qc);
@@ -406,19 +404,20 @@ static const struct ata_port_operations mv5_ops = {
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.eng_timeout = mv_eng_timeout,
.irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = mv5_scr_read,
.scr_write = mv5_scr_write,
.port_start = mv_port_start,
.port_stop = mv_port_stop,
- .host_stop = mv_host_stop,
};
static const struct ata_port_operations mv6_ops = {
@@ -434,19 +433,20 @@ static const struct ata_port_operations mv6_ops = {
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.eng_timeout = mv_eng_timeout,
.irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = mv_scr_read,
.scr_write = mv_scr_write,
.port_start = mv_port_start,
.port_stop = mv_port_stop,
- .host_stop = mv_host_stop,
};
static const struct ata_port_operations mv_iie_ops = {
@@ -462,19 +462,20 @@ 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,
+ .data_xfer = ata_data_xfer,
.eng_timeout = mv_eng_timeout,
.irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = mv_scr_read,
.scr_write = mv_scr_write,
.port_start = mv_port_start,
.port_stop = mv_port_stop,
- .host_stop = mv_host_stop,
};
static const struct ata_port_info mv_port_info[] = {
@@ -523,8 +524,7 @@ static const struct ata_port_info mv_port_info[] = {
},
{ /* chip_7042 */
.sht = &mv_sht,
- .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- MV_FLAG_DUAL_HC),
+ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv_iie_ops,
@@ -545,6 +545,8 @@ static const struct pci_device_id mv_pci_tbl[] = {
{ PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
+ { PCI_VDEVICE(TTI, 0x2310), chip_7042 },
+
{ } /* terminate list */
};
@@ -619,7 +621,7 @@ static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
static inline void __iomem *mv_ap_base(struct ata_port *ap)
{
- return mv_port_base(ap->host->mmio_base, ap->port_no);
+ return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no);
}
static inline int mv_get_hc_count(unsigned long port_flags)
@@ -808,35 +810,6 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
}
}
-/**
- * mv_host_stop - Host specific cleanup/stop routine.
- * @host: host data structure
- *
- * Disable ints, cleanup host memory, call general purpose
- * host_stop.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_host_stop(struct ata_host *host)
-{
- struct mv_host_priv *hpriv = host->private_data;
- struct pci_dev *pdev = to_pci_dev(host->dev);
-
- if (hpriv->hp_flags & MV_HP_FLAG_MSI) {
- pci_disable_msi(pdev);
- } else {
- pci_intx(pdev, 0);
- }
- kfree(hpriv);
- ata_host_stop(host);
-}
-
-static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev)
-{
- dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma);
-}
-
static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
{
u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
@@ -882,22 +855,21 @@ static int mv_port_start(struct ata_port *ap)
void __iomem *port_mmio = mv_ap_base(ap);
void *mem;
dma_addr_t mem_dma;
- int rc = -ENOMEM;
+ int rc;
- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
- goto err_out;
- memset(pp, 0, sizeof(*pp));
+ return -ENOMEM;
- mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
- GFP_KERNEL);
+ mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
+ GFP_KERNEL);
if (!mem)
- goto err_out_pp;
+ return -ENOMEM;
memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
rc = ata_pad_alloc(ap, dev);
if (rc)
- goto err_out_priv;
+ return rc;
/* First item in chunk of DMA memory:
* 32-slot command request table (CRQB), 32 bytes each in size
@@ -950,13 +922,6 @@ static int mv_port_start(struct ata_port *ap)
*/
ap->private_data = pp;
return 0;
-
-err_out_priv:
- mv_priv_free(pp, dev);
-err_out_pp:
- kfree(pp);
-err_out:
- return rc;
}
/**
@@ -970,18 +935,11 @@ err_out:
*/
static void mv_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host->dev;
- struct mv_port_priv *pp = ap->private_data;
unsigned long flags;
spin_lock_irqsave(&ap->host->lock, flags);
mv_stop_dma(ap);
spin_unlock_irqrestore(&ap->host->lock, flags);
-
- ap->private_data = NULL;
- ata_pad_free(ap, dev);
- mv_priv_free(pp, dev);
- kfree(pp);
}
/**
@@ -1347,7 +1305,7 @@ static void mv_err_intr(struct ata_port *ap, int reset_allowed)
*/
static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
{
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
void __iomem *hc_mmio = mv_hc_base(mmio, hc);
struct ata_queued_cmd *qc;
u32 hc_irq_cause;
@@ -1390,8 +1348,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
} else {
/* PIO: check for device (drive) interrupt */
if ((DEV_IRQ << hard_port) & hc_irq_cause) {
- ata_status = readb((void __iomem *)
- ap->ioaddr.status_addr);
+ ata_status = readb(ap->ioaddr.status_addr);
handled = 1;
/* ignore spurious intr if drive still BUSY */
if (ata_status & ATA_BUSY) {
@@ -1451,7 +1408,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int hc, handled = 0, n_hcs;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
struct mv_host_priv *hpriv;
u32 irq_stat;
@@ -1527,22 +1484,24 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
{
- void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no);
+ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+ void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU)
- return readl(mmio + ofs);
+ return readl(addr + ofs);
else
return (u32) ofs;
}
static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
{
- void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no);
+ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+ void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU)
- writelfl(val, mmio + ofs);
+ writelfl(val, addr + ofs);
}
static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
@@ -1904,7 +1863,7 @@ static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
static void mv_stop_and_reset(struct ata_port *ap)
{
struct mv_host_priv *hpriv = ap->host->private_data;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
mv_stop_dma(ap);
@@ -2002,10 +1961,10 @@ comreset_retry:
break;
}
- tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr);
- tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr);
- tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr);
- tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr);
+ tf.lbah = readb(ap->ioaddr.lbah_addr);
+ tf.lbam = readb(ap->ioaddr.lbam_addr);
+ tf.lbal = readb(ap->ioaddr.lbal_addr);
+ tf.nsect = readb(ap->ioaddr.nsect_addr);
dev->class = ata_dev_classify(&tf);
if (!ata_dev_enabled(dev)) {
@@ -2037,17 +1996,17 @@ static void mv_phy_reset(struct ata_port *ap)
*/
static void mv_eng_timeout(struct ata_port *ap)
{
+ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
struct ata_queued_cmd *qc;
unsigned long flags;
ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
DPRINTK("All regs @ start of eng_timeout\n");
- mv_dump_all_regs(ap->host->mmio_base, ap->port_no,
- to_pci_dev(ap->host->dev));
+ mv_dump_all_regs(mmio, ap->port_no, to_pci_dev(ap->host->dev));
qc = ata_qc_from_tag(ap, ap->active_tag);
printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
- ap->host->mmio_base, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd);
+ mmio, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd);
spin_lock_irqsave(&ap->host->lock, flags);
mv_err_intr(ap, 0);
@@ -2075,7 +2034,7 @@ static void mv_eng_timeout(struct ata_port *ap)
*/
static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
{
- unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS;
+ void __iomem *shd_base = port_mmio + SHD_BLK_OFS;
unsigned serr_ofs;
/* PIO related setup
@@ -2223,7 +2182,7 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
unsigned int board_idx)
{
int rc = 0, n_hc, port, hc;
- void __iomem *mmio = probe_ent->mmio_base;
+ void __iomem *mmio = probe_ent->iomap[MV_PRIMARY_BAR];
struct mv_host_priv *hpriv = probe_ent->private_data;
/* global interrupt mask */
@@ -2341,49 +2300,36 @@ static void mv_print_info(struct ata_probe_ent *probe_ent)
static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
- struct ata_probe_ent *probe_ent = NULL;
+ struct device *dev = &pdev->dev;
+ struct ata_probe_ent *probe_ent;
struct mv_host_priv *hpriv;
unsigned int board_idx = (unsigned int)ent->driver_data;
- void __iomem *mmio_base;
- int pci_dev_busy = 0, rc;
+ int rc;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
- if (rc) {
+ rc = pcim_enable_device(pdev);
+ if (rc)
return rc;
- }
pci_set_master(pdev);
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
- memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, MV_PRIMARY_BAR, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
-
- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
- memset(hpriv, 0, sizeof(*hpriv));
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
probe_ent->sht = mv_port_info[board_idx].sht;
probe_ent->port_flags = mv_port_info[board_idx].flags;
@@ -2393,53 +2339,26 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
probe_ent->private_data = hpriv;
/* initialize adapter */
rc = mv_init_host(pdev, probe_ent, board_idx);
- if (rc) {
- goto err_out_hpriv;
- }
+ if (rc)
+ return rc;
/* Enable interrupts */
- if (msi && pci_enable_msi(pdev) == 0) {
- hpriv->hp_flags |= MV_HP_FLAG_MSI;
- } else {
+ if (msi && !pci_enable_msi(pdev))
pci_intx(pdev, 1);
- }
mv_dump_pci_cfg(pdev, 0x68);
mv_print_info(probe_ent);
- if (ata_device_add(probe_ent) == 0) {
- rc = -ENODEV; /* No devices discovered */
- goto err_out_dev_add;
- }
+ if (ata_device_add(probe_ent) == 0)
+ return -ENODEV;
- kfree(probe_ent);
+ devm_kfree(dev, probe_ent);
return 0;
-
-err_out_dev_add:
- if (MV_HP_FLAG_MSI & hpriv->hp_flags) {
- pci_disable_msi(pdev);
- } else {
- pci_intx(pdev, 0);
- }
-err_out_hpriv:
- kfree(hpriv);
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy) {
- pci_disable_device(pdev);
- }
-
- return rc;
}
static int __init mv_init(void)
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 0d316eb3c21..095ef1b2cd0 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -49,11 +49,13 @@
#include <linux/libata.h>
#define DRV_NAME "sata_nv"
-#define DRV_VERSION "3.2"
+#define DRV_VERSION "3.3"
#define NV_ADMA_DMA_BOUNDARY 0xffffffffUL
enum {
+ NV_MMIO_BAR = 5,
+
NV_PORTS = 2,
NV_PIO_MASK = 0x1f,
NV_MWDMA_MASK = 0x07,
@@ -213,12 +215,21 @@ struct nv_adma_port_priv {
dma_addr_t cpb_dma;
struct nv_adma_prd *aprd;
dma_addr_t aprd_dma;
+ void __iomem * ctl_block;
+ void __iomem * gen_block;
+ void __iomem * notifier_clear_block;
u8 flags;
};
+struct nv_host_priv {
+ unsigned long type;
+};
+
#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT)))))
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void nv_remove_one (struct pci_dev *pdev);
+static int nv_pci_device_resume(struct pci_dev *pdev);
static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
@@ -239,6 +250,8 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance);
static void nv_adma_irq_clear(struct ata_port *ap);
static int nv_adma_port_start(struct ata_port *ap);
static void nv_adma_port_stop(struct ata_port *ap);
+static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg);
+static int nv_adma_port_resume(struct ata_port *ap);
static void nv_adma_error_handler(struct ata_port *ap);
static void nv_adma_host_stop(struct ata_host *host);
static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc);
@@ -270,14 +283,6 @@ static const struct pci_device_id nv_pci_tbl[] = {
{ 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 }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045d), GENERIC }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045e), GENERIC }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045f), GENERIC }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x0550), GENERIC }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0551), GENERIC }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0552), GENERIC }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0553), GENERIC }, /* MCP67 */
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
@@ -292,7 +297,9 @@ static struct pci_driver nv_pci_driver = {
.name = DRV_NAME,
.id_table = nv_pci_tbl,
.probe = nv_init_one,
- .remove = ata_pci_remove_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = nv_pci_device_resume,
+ .remove = nv_remove_one,
};
static struct scsi_host_template nv_sht = {
@@ -311,6 +318,8 @@ static struct scsi_host_template nv_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
};
static struct scsi_host_template nv_adma_sht = {
@@ -329,6 +338,8 @@ static struct scsi_host_template nv_adma_sht = {
.slave_configure = nv_adma_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
};
static const struct ata_port_operations nv_generic_ops = {
@@ -348,14 +359,14 @@ static const struct ata_port_operations nv_generic_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = nv_generic_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
static const struct ata_port_operations nv_nf2_ops = {
@@ -375,14 +386,14 @@ static const struct ata_port_operations nv_nf2_ops = {
.thaw = nv_nf2_thaw,
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = nv_nf2_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
static const struct ata_port_operations nv_ck804_ops = {
@@ -402,13 +413,14 @@ static const struct ata_port_operations nv_ck804_ops = {
.thaw = nv_ck804_thaw,
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = nv_ck804_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
.host_stop = nv_ck804_host_stop,
};
@@ -430,13 +442,17 @@ static const struct ata_port_operations nv_adma_ops = {
.thaw = nv_ck804_thaw,
.error_handler = nv_adma_error_handler,
.post_internal_cmd = nv_adma_bmdma_stop,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = nv_adma_interrupt,
.irq_clear = nv_adma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = nv_adma_port_start,
.port_stop = nv_adma_port_stop,
+ .port_suspend = nv_adma_port_suspend,
+ .port_resume = nv_adma_port_resume,
.host_stop = nv_adma_host_stop,
};
@@ -475,6 +491,7 @@ static struct ata_port_info nv_port_info[] = {
{
.sht = &nv_adma_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_HRST_TO_RESUME |
ATA_FLAG_MMIO | ATA_FLAG_NCQ,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
@@ -491,57 +508,72 @@ MODULE_VERSION(DRV_VERSION);
static int adma_enabled = 1;
-static inline void __iomem *__nv_adma_ctl_block(void __iomem *mmio,
- unsigned int port_no)
-{
- mmio += NV_ADMA_PORT + port_no * NV_ADMA_PORT_SIZE;
- return mmio;
-}
-
-static inline void __iomem *nv_adma_ctl_block(struct ata_port *ap)
-{
- return __nv_adma_ctl_block(ap->host->mmio_base, ap->port_no);
-}
-
-static inline void __iomem *nv_adma_gen_block(struct ata_port *ap)
-{
- return (ap->host->mmio_base + NV_ADMA_GEN);
-}
-
-static inline void __iomem *nv_adma_notifier_clear_block(struct ata_port *ap)
-{
- return (nv_adma_gen_block(ap) + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no));
-}
-
static void nv_adma_register_mode(struct ata_port *ap)
{
- void __iomem *mmio = nv_adma_ctl_block(ap);
struct nv_adma_port_priv *pp = ap->private_data;
- u16 tmp;
+ void __iomem *mmio = pp->ctl_block;
+ u16 tmp, status;
+ int count = 0;
if (pp->flags & NV_ADMA_PORT_REGISTER_MODE)
return;
+ status = readw(mmio + NV_ADMA_STAT);
+ while(!(status & NV_ADMA_STAT_IDLE) && count < 20) {
+ ndelay(50);
+ status = readw(mmio + NV_ADMA_STAT);
+ count++;
+ }
+ if(count == 20)
+ ata_port_printk(ap, KERN_WARNING,
+ "timeout waiting for ADMA IDLE, stat=0x%hx\n",
+ status);
+
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
+ count = 0;
+ status = readw(mmio + NV_ADMA_STAT);
+ while(!(status & NV_ADMA_STAT_LEGACY) && count < 20) {
+ ndelay(50);
+ status = readw(mmio + NV_ADMA_STAT);
+ count++;
+ }
+ if(count == 20)
+ ata_port_printk(ap, KERN_WARNING,
+ "timeout waiting for ADMA LEGACY, stat=0x%hx\n",
+ status);
+
pp->flags |= NV_ADMA_PORT_REGISTER_MODE;
}
static void nv_adma_mode(struct ata_port *ap)
{
- void __iomem *mmio = nv_adma_ctl_block(ap);
struct nv_adma_port_priv *pp = ap->private_data;
- u16 tmp;
+ void __iomem *mmio = pp->ctl_block;
+ u16 tmp, status;
+ int count = 0;
if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE))
return;
-
+
WARN_ON(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE);
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp | NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
+ status = readw(mmio + NV_ADMA_STAT);
+ while(((status & NV_ADMA_STAT_LEGACY) ||
+ !(status & NV_ADMA_STAT_IDLE)) && count < 20) {
+ ndelay(50);
+ status = readw(mmio + NV_ADMA_STAT);
+ count++;
+ }
+ if(count == 20)
+ ata_port_printk(ap, KERN_WARNING,
+ "timeout waiting for ADMA LEGACY clear and IDLE, stat=0x%hx\n",
+ status);
+
pp->flags &= ~NV_ADMA_PORT_REGISTER_MODE;
}
@@ -576,7 +608,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
/* Subtract 1 since an extra entry may be needed for padding, see
libata-scsi.c */
sg_tablesize = LIBATA_MAX_PRD - 1;
-
+
/* Since the legacy DMA engine is in use, we need to disable ADMA
on the port. */
adma_enable = 0;
@@ -588,7 +620,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN;
adma_enable = 1;
}
-
+
pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &current_reg);
if(ap->port_no == 1)
@@ -597,7 +629,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
else
config_mask = NV_MCP_SATA_CFG_20_PORT0_EN |
NV_MCP_SATA_CFG_20_PORT0_PWB_EN;
-
+
if(adma_enable) {
new_reg = current_reg | config_mask;
pp->flags &= ~NV_ADMA_ATAPI_SETUP_COMPLETE;
@@ -606,10 +638,10 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
new_reg = current_reg & ~config_mask;
pp->flags |= NV_ADMA_ATAPI_SETUP_COMPLETE;
}
-
+
if(current_reg != new_reg)
pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg);
-
+
blk_queue_bounce_limit(sdev->request_queue, bounce_limit);
blk_queue_segment_boundary(sdev->request_queue, segment_boundary);
blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize);
@@ -656,59 +688,67 @@ static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
return idx;
}
-static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
+static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
{
struct nv_adma_port_priv *pp = ap->private_data;
- int complete = 0, have_err = 0;
u8 flags = pp->cpb[cpb_num].resp_flags;
VPRINTK("CPB %d, flags=0x%x\n", cpb_num, flags);
- if (flags & NV_CPB_RESP_DONE) {
- VPRINTK("CPB flags done, flags=0x%x\n", flags);
- complete = 1;
- }
- if (flags & NV_CPB_RESP_ATA_ERR) {
- ata_port_printk(ap, KERN_ERR, "CPB flags ATA err, flags=0x%x\n", flags);
- have_err = 1;
- complete = 1;
- }
- if (flags & NV_CPB_RESP_CMD_ERR) {
- ata_port_printk(ap, KERN_ERR, "CPB flags CMD err, flags=0x%x\n", flags);
- have_err = 1;
- complete = 1;
- }
- if (flags & NV_CPB_RESP_CPB_ERR) {
- ata_port_printk(ap, KERN_ERR, "CPB flags CPB err, flags=0x%x\n", flags);
- have_err = 1;
- complete = 1;
+ if (unlikely((force_err ||
+ flags & (NV_CPB_RESP_ATA_ERR |
+ NV_CPB_RESP_CMD_ERR |
+ NV_CPB_RESP_CPB_ERR)))) {
+ struct ata_eh_info *ehi = &ap->eh_info;
+ int freeze = 0;
+
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags );
+ if (flags & NV_CPB_RESP_ATA_ERR) {
+ ata_ehi_push_desc(ehi, ": ATA error");
+ ehi->err_mask |= AC_ERR_DEV;
+ } else if (flags & NV_CPB_RESP_CMD_ERR) {
+ ata_ehi_push_desc(ehi, ": CMD error");
+ ehi->err_mask |= AC_ERR_DEV;
+ } else if (flags & NV_CPB_RESP_CPB_ERR) {
+ ata_ehi_push_desc(ehi, ": CPB error");
+ ehi->err_mask |= AC_ERR_SYSTEM;
+ freeze = 1;
+ } else {
+ /* notifier error, but no error in CPB flags? */
+ ehi->err_mask |= AC_ERR_OTHER;
+ freeze = 1;
+ }
+ /* Kill all commands. EH will determine what actually failed. */
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+ return 1;
}
- if(complete || force_err)
- {
+
+ if (flags & NV_CPB_RESP_DONE) {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
- if(likely(qc)) {
- u8 ata_status = 0;
- /* Only use the ATA port status for non-NCQ commands.
+ VPRINTK("CPB flags done, flags=0x%x\n", flags);
+ if (likely(qc)) {
+ /* Grab the ATA port status for non-NCQ commands.
For NCQ commands the current status may have nothing to do with
the command just completed. */
- if(qc->tf.protocol != ATA_PROT_NCQ)
- ata_status = readb(nv_adma_ctl_block(ap) + (ATA_REG_STATUS * 4));
-
- if(have_err || force_err)
- ata_status |= ATA_ERR;
-
- qc->err_mask |= ac_err_mask(ata_status);
+ if (qc->tf.protocol != ATA_PROT_NCQ) {
+ u8 ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4));
+ qc->err_mask |= ac_err_mask(ata_status);
+ }
DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num,
qc->err_mask);
ata_qc_complete(qc);
}
}
+ return 0;
}
static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
{
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
- int handled;
/* freeze if hotplugged */
if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
@@ -727,13 +767,7 @@ static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
}
/* handle interrupt */
- handled = ata_host_intr(ap, qc);
- if (unlikely(!handled)) {
- /* spurious, clear it */
- ata_check_status(ap);
- }
-
- return 1;
+ return ata_host_intr(ap, qc);
}
static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
@@ -750,16 +784,20 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
struct nv_adma_port_priv *pp = ap->private_data;
- void __iomem *mmio = nv_adma_ctl_block(ap);
+ void __iomem *mmio = pp->ctl_block;
u16 status;
u32 gen_ctl;
- int have_global_err = 0;
u32 notifier, notifier_error;
/* if in ATA register mode, use standard ata interrupt handler */
if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
- u8 irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804)
+ u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
>> (NV_INT_PORT_SHIFT * i);
+ if(ata_tag_valid(ap->active_tag))
+ /** NV_INT_DEV indication seems unreliable at times
+ at least in ADMA mode. Force it on always when a
+ command is active, to prevent losing interrupts. */
+ irq_stat |= NV_INT_DEV;
handled += nv_host_intr(ap, irq_stat);
continue;
}
@@ -768,7 +806,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
notifier_clears[i] = notifier | notifier_error;
- gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL);
+ gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
if( !NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier &&
!notifier_error)
@@ -784,52 +822,60 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
readw(mmio + NV_ADMA_STAT); /* flush posted write */
rmb();
- /* freeze if hotplugged */
- if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | NV_ADMA_STAT_HOTUNPLUG))) {
- ata_port_printk(ap, KERN_NOTICE, "Hotplug event, freezing\n");
+ handled++; /* irq handled if we got here */
+
+ /* freeze if hotplugged or controller error */
+ if (unlikely(status & (NV_ADMA_STAT_HOTPLUG |
+ NV_ADMA_STAT_HOTUNPLUG |
+ NV_ADMA_STAT_TIMEOUT))) {
+ struct ata_eh_info *ehi = &ap->eh_info;
+
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status );
+ if (status & NV_ADMA_STAT_TIMEOUT) {
+ ehi->err_mask |= AC_ERR_SYSTEM;
+ ata_ehi_push_desc(ehi, ": timeout");
+ } else if (status & NV_ADMA_STAT_HOTPLUG) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, ": hotplug");
+ } else if (status & NV_ADMA_STAT_HOTUNPLUG) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, ": hot unplug");
+ }
ata_port_freeze(ap);
- handled++;
continue;
}
- if (status & NV_ADMA_STAT_TIMEOUT) {
- ata_port_printk(ap, KERN_ERR, "timeout, stat=0x%x\n", status);
- have_global_err = 1;
- }
- if (status & NV_ADMA_STAT_CPBERR) {
- ata_port_printk(ap, KERN_ERR, "CPB error, stat=0x%x\n", status);
- have_global_err = 1;
- }
- if ((status & NV_ADMA_STAT_DONE) || have_global_err) {
+ if (status & (NV_ADMA_STAT_DONE |
+ NV_ADMA_STAT_CPBERR)) {
/** Check CPBs for completed commands */
- if(ata_tag_valid(ap->active_tag))
+ if (ata_tag_valid(ap->active_tag)) {
/* Non-NCQ command */
- nv_adma_check_cpb(ap, ap->active_tag, have_global_err ||
- (notifier_error & (1 << ap->active_tag)));
- else {
- int pos;
+ nv_adma_check_cpb(ap, ap->active_tag,
+ notifier_error & (1 << ap->active_tag));
+ } else {
+ int pos, error = 0;
u32 active = ap->sactive;
- while( (pos = ffs(active)) ) {
+
+ while ((pos = ffs(active)) && !error) {
pos--;
- nv_adma_check_cpb(ap, pos, have_global_err ||
- (notifier_error & (1 << pos)) );
+ error = nv_adma_check_cpb(ap, pos,
+ notifier_error & (1 << pos) );
active &= ~(1 << pos );
}
}
}
-
- handled++; /* irq handled if we got here */
}
}
-
+
if(notifier_clears[0] || notifier_clears[1]) {
/* Note: Both notifier clear registers must be written
if either is set, even if one is zero, according to NVIDIA. */
- writel(notifier_clears[0],
- nv_adma_notifier_clear_block(host->ports[0]));
- writel(notifier_clears[1],
- nv_adma_notifier_clear_block(host->ports[1]));
+ struct nv_adma_port_priv *pp = host->ports[0]->private_data;
+ writel(notifier_clears[0], pp->notifier_clear_block);
+ pp = host->ports[1]->private_data;
+ writel(notifier_clears[1], pp->notifier_clear_block);
}
spin_unlock(&host->lock);
@@ -839,19 +885,20 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
static void nv_adma_irq_clear(struct ata_port *ap)
{
- void __iomem *mmio = nv_adma_ctl_block(ap);
+ struct nv_adma_port_priv *pp = ap->private_data;
+ void __iomem *mmio = pp->ctl_block;
u16 status = readw(mmio + NV_ADMA_STAT);
u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
- unsigned long dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
+ void __iomem *dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
/* clear ADMA status */
writew(status, mmio + NV_ADMA_STAT);
writel(notifier | notifier_error,
- nv_adma_notifier_clear_block(ap));
+ pp->notifier_clear_block);
/** clear legacy status */
- outb(inb(dma_stat_addr), dma_stat_addr);
+ iowrite8(ioread8(dma_stat_addr), dma_stat_addr);
}
static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc)
@@ -867,15 +914,15 @@ static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc)
}
/* load PRD table addr. */
- outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+ iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
/* specify data direction, triple-check start bit is clear */
- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
if (!rw)
dmactl |= ATA_DMA_WR;
- outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
/* issue r/w command */
ata_exec_command(ap, &qc->tf);
@@ -893,9 +940,9 @@ static void nv_adma_bmdma_start(struct ata_queued_cmd *qc)
}
/* start host DMA transaction */
- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- outb(dmactl | ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ iowrite8(dmactl | ATA_DMA_START,
+ ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
}
static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc)
@@ -907,8 +954,8 @@ static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc)
return;
/* clear start/stop bit */
- outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ iowrite8(ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
+ ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
ata_altstatus(ap); /* dummy read */
@@ -920,7 +967,7 @@ static u8 nv_adma_bmdma_status(struct ata_port *ap)
WARN_ON(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE));
- return inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
}
static int nv_adma_port_start(struct ata_port *ap)
@@ -930,7 +977,7 @@ static int nv_adma_port_start(struct ata_port *ap)
int rc;
void *mem;
dma_addr_t mem_dma;
- void __iomem *mmio = nv_adma_ctl_block(ap);
+ void __iomem *mmio;
u16 tmp;
VPRINTK("ENTER\n");
@@ -939,19 +986,21 @@ static int nv_adma_port_start(struct ata_port *ap)
if (rc)
return rc;
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
-
- mem = dma_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,
- &mem_dma, GFP_KERNEL);
-
- if (!mem) {
- rc = -ENOMEM;
- goto err_out_kfree;
- }
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+
+ mmio = ap->host->iomap[NV_MMIO_BAR] + NV_ADMA_PORT +
+ ap->port_no * NV_ADMA_PORT_SIZE;
+ pp->ctl_block = mmio;
+ pp->gen_block = ap->host->iomap[NV_MMIO_BAR] + NV_ADMA_GEN;
+ pp->notifier_clear_block = pp->gen_block +
+ NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no);
+
+ mem = dmam_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,
+ &mem_dma, GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
memset(mem, 0, NV_ADMA_PORT_PRIV_DMA_SZ);
/*
@@ -985,9 +1034,9 @@ static int nv_adma_port_start(struct ata_port *ap)
/* clear CPB fetch count */
writew(0, mmio + NV_ADMA_CPB_COUNT);
- /* clear GO for register mode */
+ /* clear GO for register mode, enable interrupt */
tmp = readw(mmio + NV_ADMA_CTL);
- writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
+ writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
@@ -997,53 +1046,89 @@ static int nv_adma_port_start(struct ata_port *ap)
readl( mmio + NV_ADMA_CTL ); /* flush posted write */
return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
}
static void nv_adma_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host->dev;
struct nv_adma_port_priv *pp = ap->private_data;
- void __iomem *mmio = nv_adma_ctl_block(ap);
+ void __iomem *mmio = pp->ctl_block;
VPRINTK("ENTER\n");
+ writew(0, mmio + NV_ADMA_CTL);
+}
+static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg)
+{
+ struct nv_adma_port_priv *pp = ap->private_data;
+ void __iomem *mmio = pp->ctl_block;
+
+ /* Go to register mode - clears GO */
+ nv_adma_register_mode(ap);
+
+ /* clear CPB fetch count */
+ writew(0, mmio + NV_ADMA_CPB_COUNT);
+
+ /* disable interrupt, shut down port */
writew(0, mmio + NV_ADMA_CTL);
- ap->private_data = NULL;
- dma_free_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, pp->cpb, pp->cpb_dma);
- kfree(pp);
- ata_port_stop(ap);
+ return 0;
}
+static int nv_adma_port_resume(struct ata_port *ap)
+{
+ struct nv_adma_port_priv *pp = ap->private_data;
+ void __iomem *mmio = pp->ctl_block;
+ u16 tmp;
+
+ /* set CPB block location */
+ writel(pp->cpb_dma & 0xFFFFFFFF, mmio + NV_ADMA_CPB_BASE_LOW);
+ writel((pp->cpb_dma >> 16 ) >> 16, mmio + NV_ADMA_CPB_BASE_HIGH);
+
+ /* clear any outstanding interrupt conditions */
+ writew(0xffff, mmio + NV_ADMA_STAT);
+
+ /* initialize port variables */
+ pp->flags |= NV_ADMA_PORT_REGISTER_MODE;
+
+ /* clear CPB fetch count */
+ writew(0, mmio + NV_ADMA_CPB_COUNT);
+
+ /* clear GO for register mode, enable interrupt */
+ tmp = readw(mmio + NV_ADMA_CTL);
+ writew((tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
+
+ tmp = readw(mmio + NV_ADMA_CTL);
+ writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
+ readl( mmio + NV_ADMA_CTL ); /* flush posted write */
+ udelay(1);
+ writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
+ readl( mmio + NV_ADMA_CTL ); /* flush posted write */
+
+ return 0;
+}
static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
{
- void __iomem *mmio = probe_ent->mmio_base;
+ void __iomem *mmio = probe_ent->iomap[NV_MMIO_BAR];
struct ata_ioports *ioport = &probe_ent->port[port];
VPRINTK("ENTER\n");
mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE;
- ioport->cmd_addr = (unsigned long) mmio;
- ioport->data_addr = (unsigned long) mmio + (ATA_REG_DATA * 4);
+ ioport->cmd_addr = mmio;
+ ioport->data_addr = mmio + (ATA_REG_DATA * 4);
ioport->error_addr =
- ioport->feature_addr = (unsigned long) mmio + (ATA_REG_ERR * 4);
- ioport->nsect_addr = (unsigned long) mmio + (ATA_REG_NSECT * 4);
- ioport->lbal_addr = (unsigned long) mmio + (ATA_REG_LBAL * 4);
- ioport->lbam_addr = (unsigned long) mmio + (ATA_REG_LBAM * 4);
- ioport->lbah_addr = (unsigned long) mmio + (ATA_REG_LBAH * 4);
- ioport->device_addr = (unsigned long) mmio + (ATA_REG_DEVICE * 4);
+ ioport->feature_addr = mmio + (ATA_REG_ERR * 4);
+ ioport->nsect_addr = mmio + (ATA_REG_NSECT * 4);
+ ioport->lbal_addr = mmio + (ATA_REG_LBAL * 4);
+ ioport->lbam_addr = mmio + (ATA_REG_LBAM * 4);
+ ioport->lbah_addr = mmio + (ATA_REG_LBAH * 4);
+ ioport->device_addr = mmio + (ATA_REG_DEVICE * 4);
ioport->status_addr =
- ioport->command_addr = (unsigned long) mmio + (ATA_REG_STATUS * 4);
+ ioport->command_addr = mmio + (ATA_REG_STATUS * 4);
ioport->altstatus_addr =
- ioport->ctl_addr = (unsigned long) mmio + 0x20;
+ ioport->ctl_addr = mmio + 0x20;
}
static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
@@ -1066,15 +1151,6 @@ static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
for (i = 0; i < probe_ent->n_ports; i++)
nv_adma_setup_port(probe_ent, i);
- for (i = 0; i < probe_ent->n_ports; i++) {
- void __iomem *mmio = __nv_adma_ctl_block(probe_ent->mmio_base, i);
- u16 tmp;
-
- /* enable interrupt, clear reset if not already clear */
- tmp = readw(mmio + NV_ADMA_CTL);
- writew(tmp | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
- }
-
return 0;
}
@@ -1120,18 +1196,31 @@ static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag)));
}
+static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc)
+{
+ struct nv_adma_port_priv *pp = qc->ap->private_data;
+
+ /* ADMA engine can only be used for non-ATAPI DMA commands,
+ or interrupt-driven no-data commands. */
+ if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
+ (qc->tf.flags & ATA_TFLAG_POLLING))
+ return 1;
+
+ if((qc->flags & ATA_QCFLAG_DMAMAP) ||
+ (qc->tf.protocol == ATA_PROT_NODATA))
+ return 0;
+
+ return 1;
+}
+
static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
{
struct nv_adma_port_priv *pp = qc->ap->private_data;
struct nv_adma_cpb *cpb = &pp->cpb[qc->tag];
u8 ctl_flags = NV_CPB_CTL_CPB_VALID |
- NV_CPB_CTL_APRD_VALID |
NV_CPB_CTL_IEN;
- VPRINTK("qc->flags = 0x%lx\n", qc->flags);
-
- if (!(qc->flags & ATA_QCFLAG_DMAMAP) ||
- (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
+ if (nv_adma_use_reg_mode(qc)) {
nv_adma_register_mode(qc->ap);
ata_qc_prep(qc);
return;
@@ -1147,9 +1236,15 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
if (qc->tf.protocol == ATA_PROT_NCQ)
ctl_flags |= NV_CPB_CTL_QUEUE | NV_CPB_CTL_FPDMA;
+ VPRINTK("qc->flags = 0x%lx\n", qc->flags);
+
nv_adma_tf_to_cpb(&qc->tf, cpb->tf);
- nv_adma_fill_sg(qc, cpb);
+ if(qc->flags & ATA_QCFLAG_DMAMAP) {
+ nv_adma_fill_sg(qc, cpb);
+ ctl_flags |= NV_CPB_CTL_APRD_VALID;
+ } else
+ memset(&cpb->aprd[0], 0, sizeof(struct nv_adma_prd) * 5);
/* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are
finished filling in all of the contents */
@@ -1160,14 +1255,13 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
{
struct nv_adma_port_priv *pp = qc->ap->private_data;
- void __iomem *mmio = nv_adma_ctl_block(qc->ap);
+ void __iomem *mmio = pp->ctl_block;
VPRINTK("ENTER\n");
- if (!(qc->flags & ATA_QCFLAG_DMAMAP) ||
- (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
+ if (nv_adma_use_reg_mode(qc)) {
/* use ATA register mode */
- VPRINTK("no dmamap or ATAPI, using ATA register mode: 0x%lx\n", qc->flags);
+ VPRINTK("using ATA register mode: 0x%lx\n", qc->flags);
nv_adma_register_mode(qc->ap);
return ata_qc_issue_prot(qc);
} else
@@ -1239,7 +1333,7 @@ static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance)
irqreturn_t ret;
spin_lock(&host->lock);
- irq_stat = inb(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
+ irq_stat = ioread8(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
ret = nv_do_interrupt(host, irq_stat);
spin_unlock(&host->lock);
@@ -1253,7 +1347,7 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
irqreturn_t ret;
spin_lock(&host->lock);
- irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804);
+ irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804);
ret = nv_do_interrupt(host, irq_stat);
spin_unlock(&host->lock);
@@ -1265,7 +1359,7 @@ static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
- return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+ return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
}
static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
@@ -1273,36 +1367,36 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
if (sc_reg > SCR_CONTROL)
return;
- iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+ iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
}
static void nv_nf2_freeze(struct ata_port *ap)
{
- unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
+ void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
- mask = inb(scr_addr + NV_INT_ENABLE);
+ mask = ioread8(scr_addr + NV_INT_ENABLE);
mask &= ~(NV_INT_ALL << shift);
- outb(mask, scr_addr + NV_INT_ENABLE);
+ iowrite8(mask, scr_addr + NV_INT_ENABLE);
}
static void nv_nf2_thaw(struct ata_port *ap)
{
- unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
+ void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
- outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS);
+ iowrite8(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS);
- mask = inb(scr_addr + NV_INT_ENABLE);
+ mask = ioread8(scr_addr + NV_INT_ENABLE);
mask |= (NV_INT_MASK << shift);
- outb(mask, scr_addr + NV_INT_ENABLE);
+ iowrite8(mask, scr_addr + NV_INT_ENABLE);
}
static void nv_ck804_freeze(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
@@ -1313,7 +1407,7 @@ static void nv_ck804_freeze(struct ata_port *ap)
static void nv_ck804_thaw(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
@@ -1345,32 +1439,13 @@ static void nv_adma_error_handler(struct ata_port *ap)
{
struct nv_adma_port_priv *pp = ap->private_data;
if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
- void __iomem *mmio = nv_adma_ctl_block(ap);
+ void __iomem *mmio = pp->ctl_block;
int i;
u16 tmp;
- u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
- u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
- u32 gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL);
- u32 status = readw(mmio + NV_ADMA_STAT);
-
- ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X "
- "notifier_error 0x%X gen_ctl 0x%X status 0x%X\n",
- notifier, notifier_error, gen_ctl, status);
-
- for( i=0;i<NV_ADMA_MAX_CPBS;i++) {
- struct nv_adma_cpb *cpb = &pp->cpb[i];
- if( cpb->ctl_flags || cpb->resp_flags )
- ata_port_printk(ap, KERN_ERR,
- "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n",
- i, cpb->ctl_flags, cpb->resp_flags);
- }
-
/* Push us back into port register mode for error handling. */
nv_adma_register_mode(ap);
- ata_port_printk(ap, KERN_ERR, "Resetting port\n");
-
/* Mark all of the CPBs as invalid to prevent them from being executed */
for( i=0;i<NV_ADMA_MAX_CPBS;i++)
pp->cpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID;
@@ -1396,10 +1471,10 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
static int printed_version = 0;
struct ata_port_info *ppi[2];
struct ata_probe_ent *probe_ent;
- int pci_dev_busy = 0;
+ struct nv_host_priv *hpriv;
int rc;
u32 bar;
- unsigned long base;
+ void __iomem *base;
unsigned long type = ent->driver_data;
int mask_set = 0;
@@ -1410,17 +1485,17 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (pci_resource_start(pdev, bar) == 0)
return -ENODEV;
- if ( !printed_version++)
+ if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
- goto err_out;
+ return rc;
rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
- pci_dev_busy = 1;
- goto err_out_disable;
+ pcim_pin_device(pdev);
+ return rc;
}
if(type >= CK804 && adma_enabled) {
@@ -1434,27 +1509,31 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if(!mask_set) {
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
}
rc = -ENOMEM;
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
+
ppi[0] = ppi[1] = &nv_port_info[type];
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent)
- goto err_out_regions;
+ return -ENOMEM;
- probe_ent->mmio_base = pci_iomap(pdev, 5, 0);
- if (!probe_ent->mmio_base) {
- rc = -EIO;
- goto err_out_free_ent;
- }
+ if (!pcim_iomap(pdev, NV_MMIO_BAR, 0))
+ return -EIO;
+ probe_ent->iomap = pcim_iomap_table(pdev);
- base = (unsigned long)probe_ent->mmio_base;
+ probe_ent->private_data = hpriv;
+ hpriv->type = type;
+ base = probe_ent->iomap[NV_MMIO_BAR];
probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
@@ -1472,28 +1551,72 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (type == ADMA) {
rc = nv_adma_host_init(probe_ent);
if (rc)
- goto err_out_iounmap;
+ return rc;
}
rc = ata_device_add(probe_ent);
if (rc != NV_PORTS)
- goto err_out_iounmap;
-
- kfree(probe_ent);
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
+}
-err_out_iounmap:
- pci_iounmap(pdev, probe_ent->mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out_disable:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
-err_out:
- return rc;
+static void nv_remove_one (struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct nv_host_priv *hpriv = host->private_data;
+
+ ata_pci_remove_one(pdev);
+ kfree(hpriv);
+}
+
+static int nv_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct nv_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if(rc)
+ return rc;
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ if(hpriv->type >= CK804) {
+ u8 regval;
+
+ pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
+ regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+ pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
+ }
+ if(hpriv->type == ADMA) {
+ u32 tmp32;
+ struct nv_adma_port_priv *pp;
+ /* enable/disable ADMA on the ports appropriately */
+ pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32);
+
+ pp = host->ports[0]->private_data;
+ if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+ tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN |
+ NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
+ else
+ tmp32 |= (NV_MCP_SATA_CFG_20_PORT0_EN |
+ NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
+ pp = host->ports[1]->private_data;
+ if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+ tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT1_EN |
+ NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
+ else
+ tmp32 |= (NV_MCP_SATA_CFG_20_PORT1_EN |
+ NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
+
+ pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
+ }
+ }
+
+ ata_host_resume(host);
+
+ return 0;
}
static void nv_ck804_host_stop(struct ata_host *host)
@@ -1505,25 +1628,13 @@ static void nv_ck804_host_stop(struct ata_host *host)
pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
-
- ata_pci_host_stop(host);
}
static void nv_adma_host_stop(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
- int i;
u32 tmp32;
- for (i = 0; i < host->n_ports; i++) {
- void __iomem *mmio = __nv_adma_ctl_block(host->mmio_base, i);
- u16 tmp;
-
- /* disable interrupt */
- tmp = readw(mmio + NV_ADMA_CTL);
- writew(tmp & ~NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
- }
-
/* disable ADMA on the ports */
pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32);
tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN |
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index f055874a6ec..3be4cc338d7 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -39,10 +39,10 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/device.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#include "sata_promise.h"
#define DRV_NAME "sata_promise"
@@ -50,6 +50,17 @@
enum {
+ PDC_MMIO_BAR = 3,
+
+ /* register offsets */
+ PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
+ PDC_SECTOR_COUNT = 0x08, /* Sector count reg (per port) */
+ PDC_SECTOR_NUMBER = 0x0C, /* Sector number reg (per port) */
+ PDC_CYLINDER_LOW = 0x10, /* Cylinder low reg (per port) */
+ PDC_CYLINDER_HIGH = 0x14, /* Cylinder high reg (per port) */
+ PDC_DEVICE = 0x18, /* Device/Head reg (per port) */
+ PDC_COMMAND = 0x1C, /* Command/status reg (per port) */
+ PDC_ALTSTATUS = 0x38, /* Alternate-status/device-control reg (per port) */
PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
PDC_FLASH_CTL = 0x44, /* Flash control register */
@@ -71,13 +82,23 @@ enum {
PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */
+ /* Sequence counter control registers bit definitions */
+ PDC_SEQCNTRL_INT_MASK = (1 << 5), /* Sequence Interrupt Mask */
+
+ /* Feature register values */
+ PDC_FEATURE_ATAPI_PIO = 0x00, /* ATAPI data xfer by PIO */
+ PDC_FEATURE_ATAPI_DMA = 0x01, /* ATAPI data xfer by DMA */
+
+ /* Device/Head register values */
+ PDC_DEVICE_SATA = 0xE0, /* Device/Head value for SATA devices */
+
/* PDC_CTLSTAT bit definitions */
PDC_DMA_ENABLE = (1 << 7),
PDC_IRQ_DISABLE = (1 << 10),
PDC_RESET = (1 << 11), /* HDMA reset */
PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
+ ATA_FLAG_MMIO |
ATA_FLAG_PIO_POLLING,
/* hp->flags bits */
@@ -92,6 +113,7 @@ struct pdc_port_priv {
struct pdc_host_priv {
unsigned long flags;
+ unsigned long port_flags[ATA_MAX_PORTS];
};
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
@@ -100,14 +122,14 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
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);
static void pdc_pata_phy_reset(struct ata_port *ap);
static void pdc_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
+static int pdc_check_atapi_dma(struct ata_queued_cmd *qc);
+static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc);
static void pdc_irq_clear(struct ata_port *ap);
static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
-static void pdc_host_stop(struct ata_host *host);
static void pdc_freeze(struct ata_port *ap);
static void pdc_thaw(struct ata_port *ap);
static void pdc_error_handler(struct ata_port *ap);
@@ -139,6 +161,34 @@ static const struct ata_port_operations pdc_sata_ops = {
.check_status = ata_check_status,
.exec_command = pdc_exec_command_mmio,
.dev_select = ata_std_dev_select,
+ .check_atapi_dma = pdc_check_atapi_dma,
+
+ .qc_prep = pdc_qc_prep,
+ .qc_issue = pdc_qc_issue_prot,
+ .freeze = pdc_freeze,
+ .thaw = pdc_thaw,
+ .error_handler = pdc_error_handler,
+ .post_internal_cmd = pdc_post_internal_cmd,
+ .data_xfer = ata_data_xfer,
+ .irq_handler = pdc_interrupt,
+ .irq_clear = pdc_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .scr_read = pdc_sata_scr_read,
+ .scr_write = pdc_sata_scr_write,
+ .port_start = pdc_port_start,
+};
+
+/* First-generation chips need a more restrictive ->check_atapi_dma op */
+static const struct ata_port_operations pdc_old_sata_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = pdc_tf_load_mmio,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = pdc_exec_command_mmio,
+ .dev_select = ata_std_dev_select,
+ .check_atapi_dma = pdc_old_check_atapi_dma,
.qc_prep = pdc_qc_prep,
.qc_issue = pdc_qc_issue_prot,
@@ -146,15 +196,15 @@ static const struct ata_port_operations pdc_sata_ops = {
.thaw = pdc_thaw,
.error_handler = pdc_error_handler,
.post_internal_cmd = pdc_post_internal_cmd,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
.port_start = pdc_port_start,
- .port_stop = pdc_port_stop,
- .host_stop = pdc_host_stop,
};
static const struct ata_port_operations pdc_pata_ops = {
@@ -164,30 +214,31 @@ static const struct ata_port_operations pdc_pata_ops = {
.check_status = ata_check_status,
.exec_command = pdc_exec_command_mmio,
.dev_select = ata_std_dev_select,
+ .check_atapi_dma = pdc_check_atapi_dma,
.phy_reset = pdc_pata_phy_reset,
.qc_prep = pdc_qc_prep,
.qc_issue = pdc_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.eng_timeout = pdc_eng_timeout,
.irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = pdc_port_start,
- .port_stop = pdc_port_stop,
- .host_stop = pdc_host_stop,
};
static const struct ata_port_info pdc_port_info[] = {
/* board_2037x */
{
.sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_sata_ops,
+ .port_ops = &pdc_old_sata_ops,
},
/* board_20319 */
@@ -197,7 +248,7 @@ static const struct ata_port_info pdc_port_info[] = {
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_sata_ops,
+ .port_ops = &pdc_old_sata_ops,
},
/* board_20619 */
@@ -213,7 +264,7 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_2057x */
{
.sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -271,21 +322,22 @@ static int pdc_port_start(struct ata_port *ap)
struct pdc_port_priv *pp;
int rc;
+ /* fix up port flags and cable type for SATA+PATA chips */
+ ap->flags |= hp->port_flags[ap->port_no];
+ if (ap->flags & ATA_FLAG_SATA)
+ ap->cbl = ATA_CBL_SATA;
+
rc = ata_port_start(ap);
if (rc)
return rc;
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
- pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
- if (!pp->pkt) {
- rc = -ENOMEM;
- goto err_out_kfree;
- }
+ pp->pkt = dmam_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
+ if (!pp->pkt)
+ return -ENOMEM;
ap->private_data = pp;
@@ -300,40 +352,11 @@ static int pdc_port_start(struct ata_port *ap)
}
return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
-}
-
-
-static void pdc_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host->dev;
- struct pdc_port_priv *pp = ap->private_data;
-
- ap->private_data = NULL;
- dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
- kfree(pp);
- ata_port_stop(ap);
}
-
-static void pdc_host_stop(struct ata_host *host)
-{
- struct pdc_host_priv *hp = host->private_data;
-
- ata_pci_host_stop(host);
-
- kfree(hp);
-}
-
-
static void pdc_reset_port(struct ata_port *ap)
{
- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+ void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
unsigned int i;
u32 tmp;
@@ -377,18 +400,102 @@ static void pdc_pata_phy_reset(struct ata_port *ap)
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
- if (sc_reg > SCR_CONTROL)
+ if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
return 0xffffffffU;
- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
}
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
u32 val)
{
- if (sc_reg > SCR_CONTROL)
+ if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
return;
- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ dma_addr_t sg_table = ap->prd_dma;
+ unsigned int cdb_len = qc->dev->cdb_len;
+ u8 *cdb = qc->cdb;
+ struct pdc_port_priv *pp = ap->private_data;
+ u8 *buf = pp->pkt;
+ u32 *buf32 = (u32 *) buf;
+ unsigned int dev_sel, feature, nbytes;
+
+ /* set control bits (byte 0), zero delay seq id (byte 3),
+ * and seq id (byte 2)
+ */
+ switch (qc->tf.protocol) {
+ case ATA_PROT_ATAPI_DMA:
+ if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+ buf32[0] = cpu_to_le32(PDC_PKT_READ);
+ else
+ buf32[0] = 0;
+ break;
+ case ATA_PROT_ATAPI_NODATA:
+ buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
+ break;
+ default:
+ BUG();
+ break;
+ }
+ buf32[1] = cpu_to_le32(sg_table); /* S/G table addr */
+ buf32[2] = 0; /* no next-packet */
+
+ /* select drive */
+ if (sata_scr_valid(ap)) {
+ dev_sel = PDC_DEVICE_SATA;
+ } else {
+ dev_sel = ATA_DEVICE_OBS;
+ if (qc->dev->devno != 0)
+ dev_sel |= ATA_DEV1;
+ }
+ buf[12] = (1 << 5) | ATA_REG_DEVICE;
+ buf[13] = dev_sel;
+ buf[14] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_CLEAR_BSY;
+ buf[15] = dev_sel; /* once more, waiting for BSY to clear */
+
+ buf[16] = (1 << 5) | ATA_REG_NSECT;
+ buf[17] = 0x00;
+ buf[18] = (1 << 5) | ATA_REG_LBAL;
+ buf[19] = 0x00;
+
+ /* set feature and byte counter registers */
+ if (qc->tf.protocol != ATA_PROT_ATAPI_DMA) {
+ feature = PDC_FEATURE_ATAPI_PIO;
+ /* set byte counter register to real transfer byte count */
+ nbytes = qc->nbytes;
+ if (nbytes > 0xffff)
+ nbytes = 0xffff;
+ } else {
+ feature = PDC_FEATURE_ATAPI_DMA;
+ /* set byte counter register to 0 */
+ nbytes = 0;
+ }
+ buf[20] = (1 << 5) | ATA_REG_FEATURE;
+ buf[21] = feature;
+ buf[22] = (1 << 5) | ATA_REG_BYTEL;
+ buf[23] = nbytes & 0xFF;
+ buf[24] = (1 << 5) | ATA_REG_BYTEH;
+ buf[25] = (nbytes >> 8) & 0xFF;
+
+ /* send ATAPI packet command 0xA0 */
+ buf[26] = (1 << 5) | ATA_REG_CMD;
+ buf[27] = ATA_CMD_PACKET;
+
+ /* select drive and check DRQ */
+ buf[28] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_WAIT_DRDY;
+ buf[29] = dev_sel;
+
+ /* we can represent cdb lengths 2/4/6/8/10/12/14/16 */
+ BUG_ON(cdb_len & ~0x1E);
+
+ /* append the CDB as the final part */
+ buf[30] = (((cdb_len >> 1) & 7) << 5) | ATA_REG_DATA | PDC_LAST_REG;
+ memcpy(buf+31, cdb, cdb_len);
}
static void pdc_qc_prep(struct ata_queued_cmd *qc)
@@ -415,6 +522,17 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
pdc_pkt_footer(&qc->tf, pp->pkt, i);
break;
+ case ATA_PROT_ATAPI:
+ ata_qc_prep(qc);
+ break;
+
+ case ATA_PROT_ATAPI_DMA:
+ ata_qc_prep(qc);
+ /*FALLTHROUGH*/
+ case ATA_PROT_ATAPI_NODATA:
+ pdc_atapi_pkt(qc);
+ break;
+
default:
break;
}
@@ -517,7 +635,7 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap,
{
unsigned int handled = 0;
u32 tmp;
- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+ void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
tmp = readl(mmio);
if (tmp & PDC_ERR_MASK) {
@@ -528,6 +646,8 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap,
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
case ATA_PROT_NODATA:
+ case ATA_PROT_ATAPI_DMA:
+ case ATA_PROT_ATAPI_NODATA:
qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
ata_qc_complete(qc);
handled = 1;
@@ -544,7 +664,7 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap,
static void pdc_irq_clear(struct ata_port *ap)
{
struct ata_host *host = ap->host;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
readl(mmio + PDC_INT_SEQMASK);
}
@@ -560,12 +680,12 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
VPRINTK("ENTER\n");
- if (!host || !host->mmio_base) {
+ if (!host || !host->iomap[PDC_MMIO_BAR]) {
VPRINTK("QUICK EXIT\n");
return IRQ_NONE;
}
- mmio_base = host->mmio_base;
+ mmio_base = host->iomap[PDC_MMIO_BAR];
/* reading should also clear interrupts */
mask = readl(mmio_base + PDC_INT_SEQMASK);
@@ -610,32 +730,34 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
+ void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
unsigned int port_no = ap->port_no;
u8 seq = (u8) (port_no + 1);
VPRINTK("ENTER, ap %p\n", ap);
- writel(0x00000001, ap->host->mmio_base + (seq * 4));
- readl(ap->host->mmio_base + (seq * 4)); /* flush */
+ writel(0x00000001, mmio + (seq * 4));
+ readl(mmio + (seq * 4)); /* flush */
pp->pkt[2] = seq;
wmb(); /* flush PRD, pkt writes */
- writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
+ writel(pp->pkt_dma, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
}
static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
{
switch (qc->tf.protocol) {
+ case ATA_PROT_ATAPI_NODATA:
+ if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
+ break;
+ /*FALLTHROUGH*/
+ case ATA_PROT_ATAPI_DMA:
case ATA_PROT_DMA:
case ATA_PROT_NODATA:
pdc_packet_start(qc);
return 0;
- case ATA_PROT_ATAPI_DMA:
- BUG();
- break;
-
default:
break;
}
@@ -658,8 +780,44 @@ static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile
ata_exec_command(ap, tf);
}
+static int pdc_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ u8 *scsicmd = qc->scsicmd->cmnd;
+ int pio = 1; /* atapi dma off by default */
+
+ /* Whitelist commands that may use DMA. */
+ switch (scsicmd[0]) {
+ case WRITE_12:
+ case WRITE_10:
+ case WRITE_6:
+ case READ_12:
+ case READ_10:
+ case READ_6:
+ case 0xad: /* READ_DVD_STRUCTURE */
+ case 0xbe: /* READ_CD */
+ pio = 0;
+ }
+ /* -45150 (FFFF4FA2) to -1 (FFFFFFFF) shall use PIO mode */
+ if (scsicmd[0] == WRITE_10) {
+ unsigned int lba;
+ lba = (scsicmd[2] << 24) | (scsicmd[3] << 16) | (scsicmd[4] << 8) | scsicmd[5];
+ if (lba >= 0xFFFF4FA2)
+ pio = 1;
+ }
+ return pio;
+}
-static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
+static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ /* First generation chips cannot use ATAPI DMA on SATA ports */
+ if (sata_scr_valid(ap))
+ return 1;
+ return pdc_check_atapi_dma(qc);
+}
+
+static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr = base;
port->data_addr = base;
@@ -679,7 +837,7 @@ static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
{
- void __iomem *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
struct pdc_host_priv *hp = pe->private_data;
int hotplug_offset;
u32 tmp;
@@ -733,55 +891,43 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
+ struct ata_probe_ent *probe_ent;
struct pdc_host_priv *hp;
- unsigned long base;
- void __iomem *mmio_base;
+ void __iomem *base;
unsigned int board_idx = (unsigned int) ent->driver_data;
- int pci_dev_busy = 0;
int rc;
+ u8 tmp;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, 3, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- hp = kzalloc(sizeof(*hp), GFP_KERNEL);
- if (hp == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
+ hp = devm_kzalloc(&pdev->dev, sizeof(*hp), GFP_KERNEL);
+ if (hp == NULL)
+ return -ENOMEM;
probe_ent->private_data = hp;
@@ -794,7 +940,9 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
+
+ base = probe_ent->iomap[PDC_MMIO_BAR];
pdc_ata_setup_port(&probe_ent->port[0], base + 0x200);
pdc_ata_setup_port(&probe_ent->port[1], base + 0x280);
@@ -820,7 +968,17 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
hp->flags |= PDC_FLAG_GEN_II;
/* Fall through */
case board_2037x:
- probe_ent->n_ports = 2;
+ /* TX2plus boards also have a PATA port */
+ tmp = readb(base + PDC_FLASH_CTL+1);
+ if (!(tmp & 0x80)) {
+ probe_ent->n_ports = 3;
+ pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
+ hp->port_flags[2] = ATA_FLAG_SLAVE_POSS;
+ printk(KERN_INFO DRV_NAME " PATA port found\n");
+ } else
+ probe_ent->n_ports = 2;
+ hp->port_flags[0] = ATA_FLAG_SATA;
+ hp->port_flags[1] = ATA_FLAG_SATA;
break;
case board_20619:
probe_ent->n_ports = 4;
@@ -841,22 +999,11 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
/* initialize adapter */
pdc_host_init(board_idx, probe_ent);
- /* FIXME: Need any other frees than hp? */
if (!ata_device_add(probe_ent))
- kfree(hp);
-
- kfree(probe_ent);
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 710909df4ea..bfa35ede655 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -37,13 +37,14 @@
#include <linux/sched.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
-#include <asm/io.h>
#include <linux/libata.h>
#define DRV_NAME "sata_qstor"
#define DRV_VERSION "0.06"
enum {
+ QS_MMIO_BAR = 4,
+
QS_PORTS = 4,
QS_MAX_PRD = LIBATA_MAX_PRD,
QS_CPB_ORDER = 6,
@@ -117,7 +118,6 @@ static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *en
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);
static void qs_phy_reset(struct ata_port *ap);
static void qs_qc_prep(struct ata_queued_cmd *qc);
static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
@@ -157,14 +157,15 @@ static const struct ata_port_operations qs_ata_ops = {
.phy_reset = qs_phy_reset,
.qc_prep = qs_qc_prep,
.qc_issue = qs_qc_issue,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.eng_timeout = qs_eng_timeout,
.irq_handler = qs_intr,
.irq_clear = qs_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = qs_scr_read,
.scr_write = qs_scr_write,
.port_start = qs_port_start,
- .port_stop = qs_port_stop,
.host_stop = qs_host_stop,
.bmdma_stop = qs_bmdma_stop,
.bmdma_status = qs_bmdma_status,
@@ -197,6 +198,11 @@ static struct pci_driver qs_ata_pci_driver = {
.remove = ata_pci_remove_one,
};
+static void __iomem *qs_mmio_base(struct ata_host *host)
+{
+ return host->iomap[QS_MMIO_BAR];
+}
+
static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
{
return 1; /* ATAPI DMA not supported */
@@ -219,7 +225,7 @@ static void qs_irq_clear(struct ata_port *ap)
static inline void qs_enter_reg_mode(struct ata_port *ap)
{
- u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
+ u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
readb(chan + QS_CCT_CTR0); /* flush */
@@ -227,7 +233,7 @@ static inline void qs_enter_reg_mode(struct ata_port *ap)
static inline void qs_reset_channel_logic(struct ata_port *ap)
{
- u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
+ u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1);
readb(chan + QS_CCT_CTR0); /* flush */
@@ -257,14 +263,14 @@ static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
return ~0U;
- return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
+ return readl(ap->ioaddr.scr_addr + (sc_reg * 8));
}
static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return;
- writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
+ writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
}
static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
@@ -325,7 +331,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
/* host control block (HCB) */
buf[ 0] = QS_HCB_HDR;
buf[ 1] = hflags;
- *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE);
+ *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nbytes);
*(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem);
addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES;
*(__le64 *)(&buf[16]) = cpu_to_le64(addr);
@@ -341,7 +347,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
static inline void qs_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
+ u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
VPRINTK("ENTER, ap %p\n", ap);
@@ -378,7 +384,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host)
{
unsigned int handled = 0;
u8 sFFE;
- u8 __iomem *mmio_base = host->mmio_base;
+ u8 __iomem *mmio_base = qs_mmio_base(host);
do {
u32 sff0 = readl(mmio_base + QS_HST_SFF);
@@ -470,7 +476,7 @@ static irqreturn_t qs_intr(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
-static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base)
+static void qs_ata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr =
port->data_addr = base + 0x400;
@@ -492,7 +498,7 @@ static int qs_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
struct qs_port_priv *pp;
- void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *mmio_base = qs_mmio_base(ap->host);
void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
u64 addr;
int rc;
@@ -501,17 +507,13 @@ static int qs_port_start(struct ata_port *ap)
if (rc)
return rc;
qs_enter_reg_mode(ap);
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
- pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
- GFP_KERNEL);
- if (!pp->pkt) {
- rc = -ENOMEM;
- goto err_out_kfree;
- }
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+ pp->pkt = dmam_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
+ GFP_KERNEL);
+ if (!pp->pkt)
+ return -ENOMEM;
memset(pp->pkt, 0, QS_PKT_BYTES);
ap->private_data = pp;
@@ -519,43 +521,19 @@ static int qs_port_start(struct ata_port *ap)
writel((u32) addr, chan + QS_CCF_CPBA);
writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
-}
-
-static void qs_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host->dev;
- struct qs_port_priv *pp = ap->private_data;
-
- if (pp != NULL) {
- ap->private_data = NULL;
- if (pp->pkt != NULL)
- dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt,
- pp->pkt_dma);
- kfree(pp);
- }
- ata_port_stop(ap);
}
static void qs_host_stop(struct ata_host *host)
{
- void __iomem *mmio_base = host->mmio_base;
- struct pci_dev *pdev = to_pci_dev(host->dev);
+ void __iomem *mmio_base = qs_mmio_base(host);
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
-
- pci_iounmap(pdev, mmio_base);
}
static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
{
- void __iomem *mmio_base = pe->mmio_base;
+ void __iomem *mmio_base = pe->iomap[QS_MMIO_BAR];
unsigned int port_no;
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
@@ -630,44 +608,34 @@ static int qs_ata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- void __iomem *mmio_base;
+ struct ata_probe_ent *probe_ent;
+ void __iomem * const *iomap;
unsigned int board_idx = (unsigned int) ent->driver_data;
int rc, port_no;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc)
- goto err_out;
-
- if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
- rc = -ENODEV;
- goto err_out_regions;
- }
+ if ((pci_resource_flags(pdev, QS_MMIO_BAR) & IORESOURCE_MEM) == 0)
+ return -ENODEV;
- mmio_base = pci_iomap(pdev, 4, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME);
+ if (rc)
+ return rc;
+ iomap = pcim_iomap_table(pdev);
- rc = qs_set_dma_masks(pdev, mmio_base);
+ rc = qs_set_dma_masks(pdev, iomap[QS_MMIO_BAR]);
if (rc)
- goto err_out_iounmap;
+ return rc;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
- memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
@@ -680,12 +648,12 @@ static int qs_ata_init_one(struct pci_dev *pdev,
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = iomap;
probe_ent->n_ports = QS_PORTS;
for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
- unsigned long chan = (unsigned long)mmio_base +
- (port_no * 0x4000);
+ void __iomem *chan =
+ probe_ent->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
qs_ata_setup_port(&probe_ent->port[port_no], chan);
}
@@ -694,19 +662,11 @@ static int qs_ata_init_one(struct pci_dev *pdev,
/* initialize adapter */
qs_host_init(board_idx, probe_ent);
- rc = ata_device_add(probe_ent);
- kfree(probe_ent);
- if (rc != QS_PORTS)
- goto err_out_iounmap;
- return 0;
+ if (ata_device_add(probe_ent) != QS_PORTS)
+ return -EIO;
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- pci_disable_device(pdev);
- return rc;
+ devm_kfree(&pdev->dev, probe_ent);
+ return 0;
}
static int __init qs_ata_init(void)
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 7808d0369d9..dca3d3749f0 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -49,6 +49,8 @@
#define DRV_VERSION "2.0"
enum {
+ SIL_MMIO_BAR = 5,
+
/*
* host flags
*/
@@ -200,18 +202,18 @@ static const struct ata_port_operations sil_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = sil_freeze,
.thaw = sil_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = sil_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = sil_scr_read,
.scr_write = sil_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
static const struct ata_port_info sil_port_info[] = {
@@ -297,7 +299,8 @@ static void sil_post_set_mode (struct ata_port *ap)
{
struct ata_host *host = ap->host;
struct ata_device *dev;
- void __iomem *addr = host->mmio_base + sil_port[ap->port_no].xfer_mode;
+ void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
+ void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
u32 tmp, dev_mode[2];
unsigned int i;
@@ -320,9 +323,9 @@ static void sil_post_set_mode (struct ata_port *ap)
readl(addr); /* flush */
}
-static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
+static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
{
- unsigned long offset = ap->ioaddr.scr_addr;
+ void __iomem *offset = ap->ioaddr.scr_addr;
switch (sc_reg) {
case SCR_STATUS:
@@ -341,7 +344,7 @@ static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_re
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
- void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
+ void __iomem *mmio = sil_scr_addr(ap, sc_reg);
if (mmio)
return readl(mmio);
return 0xffffffffU;
@@ -349,7 +352,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 __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
+ void __iomem *mmio = sil_scr_addr(ap, sc_reg);
if (mmio)
writel(val, mmio);
}
@@ -444,7 +447,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
static irqreturn_t sil_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
- void __iomem *mmio_base = host->mmio_base;
+ void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
int handled = 0;
int i;
@@ -476,7 +479,7 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance)
static void sil_freeze(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
u32 tmp;
/* global IRQ mask doesn't block SATA IRQ, turn off explicitly */
@@ -491,7 +494,7 @@ static void sil_freeze(struct ata_port *ap)
static void sil_thaw(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
u32 tmp;
/* clear IRQ */
@@ -541,9 +544,9 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
{
int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
unsigned int n, quirks = 0;
- unsigned char model_num[41];
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
- ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
for (n = 0; sil_blacklist[n].product; n++)
if (!strcmp(sil_blacklist[n].product, model_num)) {
@@ -621,38 +624,35 @@ static void sil_init_controller(struct pci_dev *pdev,
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
+ struct device *dev = &pdev->dev;
+ struct ata_probe_ent *probe_ent;
void __iomem *mmio_base;
int rc;
unsigned int i;
- int pci_dev_busy = 0;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, 1 << SIL_MMIO_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
INIT_LIST_HEAD(&probe_ent->node);
probe_ent->dev = pci_dev_to_dev(pdev);
@@ -666,22 +666,16 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->irq_flags = IRQF_SHARED;
probe_ent->port_flags = sil_port_info[ent->driver_data].flags;
- mmio_base = pci_iomap(pdev, 5, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
-
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
- base = (unsigned long) mmio_base;
+ mmio_base = probe_ent->iomap[SIL_MMIO_BAR];
for (i = 0; i < probe_ent->n_ports; i++) {
- probe_ent->port[i].cmd_addr = base + sil_port[i].tf;
+ probe_ent->port[i].cmd_addr = mmio_base + sil_port[i].tf;
probe_ent->port[i].altstatus_addr =
- probe_ent->port[i].ctl_addr = base + sil_port[i].ctl;
- probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma;
- probe_ent->port[i].scr_addr = base + sil_port[i].scr;
+ probe_ent->port[i].ctl_addr = mmio_base + sil_port[i].ctl;
+ probe_ent->port[i].bmdma_addr = mmio_base + sil_port[i].bmdma;
+ probe_ent->port[i].scr_addr = mmio_base + sil_port[i].scr;
ata_std_ports(&probe_ent->port[i]);
}
@@ -690,30 +684,25 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(dev, probe_ent);
return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
#ifdef CONFIG_PM
static int sil_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
- ata_pci_device_do_resume(pdev);
sil_init_controller(pdev, host->n_ports, host->ports[0]->flags,
- host->mmio_base);
+ host->iomap[SIL_MMIO_BAR]);
ata_host_resume(host);
return 0;
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 5aa288d2fb8..e65e8d55da3 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -28,7 +28,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#define DRV_NAME "sata_sil24"
#define DRV_VERSION "0.3"
@@ -61,6 +60,9 @@ struct sil24_port_multiplier {
};
enum {
+ SIL24_HOST_BAR = 0,
+ SIL24_PORT_BAR = 2,
+
/*
* Global controller registers (128 bytes @ BAR0)
*/
@@ -321,12 +323,6 @@ struct sil24_port_priv {
struct ata_taskfile tf; /* Cached taskfile registers */
};
-/* ap->host->private_data */
-struct sil24_host_priv {
- void __iomem *host_base; /* global controller control (128 bytes @BAR0) */
- void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */
-};
-
static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
static u8 sil24_check_status(struct ata_port *ap);
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
@@ -341,8 +337,6 @@ static void sil24_thaw(struct ata_port *ap);
static void sil24_error_handler(struct ata_port *ap);
static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);
static int sil24_port_start(struct ata_port *ap);
-static void sil24_port_stop(struct ata_port *ap);
-static void sil24_host_stop(struct ata_host *host);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
#ifdef CONFIG_PM
static int sil24_pci_device_resume(struct pci_dev *pdev);
@@ -362,7 +356,7 @@ static struct pci_driver sil24_pci_driver = {
.name = DRV_NAME,
.id_table = sil24_pci_tbl,
.probe = sil24_init_one,
- .remove = ata_pci_remove_one, /* safe? */
+ .remove = ata_pci_remove_one,
#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = sil24_pci_device_resume,
@@ -406,6 +400,8 @@ static const struct ata_port_operations sil24_ops = {
.irq_handler = sil24_interrupt,
.irq_clear = sil24_irq_clear,
+ .irq_on = ata_dummy_irq_on,
+ .irq_ack = ata_dummy_irq_ack,
.scr_read = sil24_scr_read,
.scr_write = sil24_scr_write,
@@ -416,8 +412,6 @@ static const struct ata_port_operations sil24_ops = {
.post_internal_cmd = sil24_post_internal_cmd,
.port_start = sil24_port_start,
- .port_stop = sil24_port_stop,
- .host_stop = sil24_host_stop,
};
/*
@@ -467,7 +461,7 @@ static int sil24_tag(int tag)
static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
if (dev->cdb_len == 16)
writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
@@ -478,7 +472,7 @@ static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
static inline void sil24_update_tf(struct ata_port *ap)
{
struct sil24_port_priv *pp = ap->private_data;
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_prb __iomem *prb = port;
u8 fis[6 * 4];
@@ -501,7 +495,7 @@ static int sil24_scr_map[] = {
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
{
- void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+ void __iomem *scr_addr = ap->ioaddr.scr_addr;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4;
@@ -512,7 +506,7 @@ static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
- void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+ void __iomem *scr_addr = ap->ioaddr.scr_addr;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4;
@@ -528,7 +522,7 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
static int sil24_init_port(struct ata_port *ap)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
u32 tmp;
writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
@@ -544,7 +538,7 @@ static int sil24_init_port(struct ata_port *ap)
static int sil24_softreset(struct ata_port *ap, unsigned int *class)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
dma_addr_t paddr = pp->cmd_block_dma;
@@ -604,7 +598,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class)
static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
const char *reason;
int tout_msec, rc;
u32 tmp;
@@ -721,7 +715,7 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct sil24_port_priv *pp = ap->private_data;
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
unsigned int tag = sil24_tag(qc->tag);
dma_addr_t paddr;
void __iomem *activate;
@@ -742,7 +736,7 @@ static void sil24_irq_clear(struct ata_port *ap)
static void sil24_freeze(struct ata_port *ap)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
/* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear
* PORT_IRQ_ENABLE instead.
@@ -752,7 +746,7 @@ static void sil24_freeze(struct ata_port *ap)
static void sil24_thaw(struct ata_port *ap)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
u32 tmp;
/* clear IRQ */
@@ -765,7 +759,7 @@ static void sil24_thaw(struct ata_port *ap)
static void sil24_error_intr(struct ata_port *ap)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
struct ata_eh_info *ehi = &ap->eh_info;
int freeze = 0;
u32 irq_stat;
@@ -843,7 +837,7 @@ static void sil24_finish_qc(struct ata_queued_cmd *qc)
static inline void sil24_host_intr(struct ata_port *ap)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
u32 slot_stat, qc_active;
int rc;
@@ -878,12 +872,12 @@ static inline void sil24_host_intr(struct ata_port *ap)
static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
- struct sil24_host_priv *hpriv = host->private_data;
+ void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
unsigned handled = 0;
u32 status;
int i;
- status = readl(hpriv->host_base + HOST_IRQ_STAT);
+ status = readl(host_base + HOST_IRQ_STAT);
if (status == 0xffffffff) {
printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, "
@@ -938,13 +932,6 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
sil24_init_port(ap);
}
-static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
-{
- const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS;
-
- dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
-}
-
static int sil24_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
@@ -952,22 +939,22 @@ static int sil24_port_start(struct ata_port *ap)
union sil24_cmd_block *cb;
size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
dma_addr_t cb_dma;
- int rc = -ENOMEM;
+ int rc;
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
- goto err_out;
+ return -ENOMEM;
pp->tf.command = ATA_DRDY;
- cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
+ cb = dmam_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
if (!cb)
- goto err_out_pp;
+ return -ENOMEM;
memset(cb, 0, cb_size);
rc = ata_pad_alloc(ap, dev);
if (rc)
- goto err_out_pad;
+ return rc;
pp->cmd_block = cb;
pp->cmd_block_dma = cb_dma;
@@ -975,33 +962,6 @@ static int sil24_port_start(struct ata_port *ap)
ap->private_data = pp;
return 0;
-
-err_out_pad:
- sil24_cblk_free(pp, dev);
-err_out_pp:
- kfree(pp);
-err_out:
- return rc;
-}
-
-static void sil24_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host->dev;
- struct sil24_port_priv *pp = ap->private_data;
-
- sil24_cblk_free(pp, dev);
- ata_pad_free(ap, dev);
- kfree(pp);
-}
-
-static void sil24_host_stop(struct ata_host *host)
-{
- struct sil24_host_priv *hpriv = host->private_data;
- struct pci_dev *pdev = to_pci_dev(host->dev);
-
- pci_iounmap(pdev, hpriv->host_base);
- pci_iounmap(pdev, hpriv->port_base);
- kfree(hpriv);
}
static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
@@ -1066,43 +1026,32 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
+ struct device *dev = &pdev->dev;
unsigned int board_id = (unsigned int)ent->driver_data;
struct ata_port_info *pinfo = &sil24_port_info[board_id];
- struct ata_probe_ent *probe_ent = NULL;
- struct sil24_host_priv *hpriv = NULL;
- void __iomem *host_base = NULL;
- void __iomem *port_base = NULL;
+ struct ata_probe_ent *probe_ent;
+ void __iomem *host_base;
+ void __iomem *port_base;
int i, rc;
u32 tmp;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
+ rc = pcim_iomap_regions(pdev,
+ (1 << SIL24_HOST_BAR) | (1 << SIL24_PORT_BAR),
+ DRV_NAME);
if (rc)
- goto out_disable;
-
- rc = -ENOMEM;
- /* map mmio registers */
- host_base = pci_iomap(pdev, 0, 0);
- if (!host_base)
- goto out_free;
- port_base = pci_iomap(pdev, 2, 0);
- if (!port_base)
- goto out_free;
-
- /* allocate & init probe_ent and hpriv */
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent)
- goto out_free;
+ return rc;
- hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv)
- goto out_free;
+ /* allocate & init probe_ent */
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (!probe_ent)
+ return -ENOMEM;
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
@@ -1117,10 +1066,10 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->private_data = hpriv;
+ probe_ent->iomap = pcim_iomap_table(pdev);
- hpriv->host_base = host_base;
- hpriv->port_base = port_base;
+ host_base = probe_ent->iomap[SIL24_HOST_BAR];
+ port_base = probe_ent->iomap[SIL24_PORT_BAR];
/*
* Configure the device
@@ -1132,7 +1081,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"64-bit DMA enable failed\n");
- goto out_free;
+ return rc;
}
}
} else {
@@ -1140,13 +1089,13 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"32-bit DMA enable failed\n");
- goto out_free;
+ return rc;
}
rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"32-bit consistent DMA enable failed\n");
- goto out_free;
+ return rc;
}
}
@@ -1162,11 +1111,10 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
for (i = 0; i < probe_ent->n_ports; i++) {
- unsigned long portu =
- (unsigned long)port_base + i * PORT_REGS_SIZE;
+ void __iomem *port = port_base + i * PORT_REGS_SIZE;
- probe_ent->port[i].cmd_addr = portu;
- probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
+ probe_ent->port[i].cmd_addr = port;
+ probe_ent->port[i].scr_addr = port + PORT_SCONTROL;
ata_std_ports(&probe_ent->port[i]);
}
@@ -1176,38 +1124,30 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
- kfree(probe_ent);
+ devm_kfree(dev, probe_ent);
return 0;
-
- out_free:
- if (host_base)
- pci_iounmap(pdev, host_base);
- if (port_base)
- pci_iounmap(pdev, port_base);
- kfree(probe_ent);
- kfree(hpriv);
- pci_release_regions(pdev);
- out_disable:
- pci_disable_device(pdev);
- return rc;
}
#ifdef CONFIG_PM
static int sil24_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
- struct sil24_host_priv *hpriv = host->private_data;
+ void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
+ void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
+ int rc;
- ata_pci_device_do_resume(pdev);
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
- writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
+ writel(HOST_CTRL_GLOBAL_RST, host_base + HOST_CTRL);
sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags,
- hpriv->host_base, hpriv->port_base);
+ host_base, port_base);
ata_host_resume(host);
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 9c25a1e9173..49c9e2bd706 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -40,9 +40,11 @@
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
+#include "libata.h"
+#undef DRV_NAME /* already defined in libata.h, for libata-core */
#define DRV_NAME "sata_sis"
-#define DRV_VERSION "0.6"
+#define DRV_VERSION "0.7"
enum {
sis_180 = 0,
@@ -67,9 +69,12 @@ 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_VDEVICE(SI, 0x180), sis_180 },
- { PCI_VDEVICE(SI, 0x181), sis_180 },
- { PCI_VDEVICE(SI, 0x182), sis_180 },
+ { PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
+ { PCI_VDEVICE(SI, 0x0181), sis_180 }, /* SiS 964/180 */
+ { PCI_VDEVICE(SI, 0x0182), sis_180 }, /* SiS 965/965L */
+ { PCI_VDEVICE(SI, 0x0183), sis_180 }, /* SiS 965/965L */
+ { PCI_VDEVICE(SI, 0x1182), sis_180 }, /* SiS 966/966L */
+ { PCI_VDEVICE(SI, 0x1183), sis_180 }, /* SiS 966/966L */
{ } /* terminate list */
};
@@ -112,18 +117,18 @@ static const struct ata_port_operations sis_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = sis_scr_read,
.scr_write = sis_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static struct ata_port_info sis_port_info = {
@@ -135,31 +140,42 @@ static struct ata_port_info sis_port_info = {
.port_ops = &sis_ops,
};
-
MODULE_AUTHOR("Uwe Koziolek");
MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device)
+static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
+ u8 pmr;
- if (port_no) {
- if (device == 0x182)
- addr += SIS182_SATA1_OFS;
- else
- addr += SIS180_SATA1_OFS;
+ if (ap->port_no) {
+ switch (pdev->device) {
+ case 0x0180:
+ case 0x0181:
+ pci_read_config_byte(pdev, SIS_PMR, &pmr);
+ if ((pmr & SIS_PMR_COMBINED) == 0)
+ addr += SIS180_SATA1_OFS;
+ break;
+
+ case 0x0182:
+ case 0x0183:
+ case 0x1182:
+ case 0x1183:
+ addr += SIS182_SATA1_OFS;
+ break;
+ }
}
-
return addr;
}
static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device);
+ unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
u32 val, val2 = 0;
u8 pmr;
@@ -170,26 +186,28 @@ static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
pci_read_config_dword(pdev, cfg_addr, &val);
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+ if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
+ (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED))
pci_read_config_dword(pdev, cfg_addr+0x10, &val2);
return (val|val2) & 0xfffffffb; /* avoid problems with powerdowned ports */
}
-static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device);
+ unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
u8 pmr;
- if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
+ if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
return;
pci_read_config_byte(pdev, SIS_PMR, &pmr);
pci_write_config_dword(pdev, cfg_addr, val);
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+ if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
+ (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED))
pci_write_config_dword(pdev, cfg_addr+0x10, val);
}
@@ -207,10 +225,11 @@ static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
pci_read_config_byte(pdev, SIS_PMR, &pmr);
- val = inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
- val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+ if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
+ (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED))
+ val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
return (val | val2) & 0xfffffffb;
}
@@ -228,9 +247,10 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
if (ap->flags & SIS_FLAG_CFGSCR)
sis_scr_cfg_write(ap, sc_reg, val);
else {
- outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
- outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
+ iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
+ (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED))
+ iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
}
}
@@ -241,29 +261,28 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
int rc;
u32 genctl, val;
struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi };
- int pci_dev_busy = 0;
u8 pmr;
- u8 port2_start;
+ u8 port2_start = 0x20;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
- pci_dev_busy = 1;
- goto err_out;
+ pcim_pin_device(pdev);
+ return rc;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
/* check and see if the SCRs are in IO space or PCI cfg space */
pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
@@ -282,60 +301,79 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
pci_read_config_byte(pdev, SIS_PMR, &pmr);
- if (ent->device != 0x182) {
+ switch (ent->device) {
+ case 0x0180:
+ case 0x0181:
+
+ /* The PATA-handling is provided by pata_sis */
+ switch (pmr & 0x30) {
+ case 0x10:
+ ppi[1] = &sis_info133;
+ break;
+
+ case 0x30:
+ ppi[0] = &sis_info133;
+ break;
+ }
if ((pmr & SIS_PMR_COMBINED) == 0) {
dev_printk(KERN_INFO, &pdev->dev,
"Detected SiS 180/181/964 chipset in SATA mode\n");
port2_start = 64;
- }
- else {
+ } else {
dev_printk(KERN_INFO, &pdev->dev,
"Detected SiS 180/181 chipset in combined mode\n");
port2_start=0;
pi.flags |= ATA_FLAG_SLAVE_POSS;
}
- }
- else {
+ break;
+
+ case 0x0182:
+ case 0x0183:
pci_read_config_dword ( pdev, 0x6C, &val);
if (val & (1L << 31)) {
dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965 chipset\n");
pi.flags |= ATA_FLAG_SLAVE_POSS;
- }
- else
+ } else {
dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965L chipset\n");
- port2_start = 0x20;
+ }
+ break;
+
+ case 0x1182:
+ case 0x1183:
+ pci_read_config_dword(pdev, 0x64, &val);
+ if (val & 0x10000000) {
+ dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 1182/1183/966L SATA controller\n");
+ } else {
+ dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 1182/1183/966 SATA controller\n");
+ pi.flags |= ATA_FLAG_SLAVE_POSS;
+ }
+ break;
}
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ if (!probe_ent)
+ return -ENOMEM;
if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) {
- probe_ent->port[0].scr_addr =
- pci_resource_start(pdev, SIS_SCR_PCI_BAR);
- probe_ent->port[1].scr_addr =
- pci_resource_start(pdev, SIS_SCR_PCI_BAR) + port2_start;
+ void *mmio;
+
+ mmio = pcim_iomap(pdev, SIS_SCR_PCI_BAR, 0);
+ if (!mmio)
+ return -ENOMEM;
+
+ probe_ent->port[0].scr_addr = mmio;
+ probe_ent->port[1].scr_addr = mmio + port2_start;
}
pci_set_master(pdev);
pci_intx(pdev, 1);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -EIO;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-err_out_regions:
- pci_release_regions(pdev);
-
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-
}
static int __init sis_init(void)
@@ -350,4 +388,3 @@ static void __exit sis_exit(void)
module_init(sis_init);
module_exit(sis_exit);
-
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index db32d15b7fa..4e428999420 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -56,6 +56,8 @@
#define DRV_VERSION "2.0"
enum {
+ K2_FLAG_NO_ATAPI_DMA = (1 << 29),
+
/* Taskfile registers offsets */
K2_SATA_TF_CMD_OFFSET = 0x00,
K2_SATA_TF_DATA_OFFSET = 0x00,
@@ -83,16 +85,38 @@ enum {
/* Port stride */
K2_SATA_PORT_OFFSET = 0x100,
+
+ board_svw4 = 0,
+ board_svw8 = 1,
+};
+
+static const struct k2_board_info {
+ unsigned int n_ports;
+ unsigned long port_flags;
+} k2_board_info[] = {
+ /* board_svw4 */
+ { 4, K2_FLAG_NO_ATAPI_DMA },
+
+ /* board_svw8 */
+ { 8, K2_FLAG_NO_ATAPI_DMA },
};
static u8 k2_stat_check_status(struct ata_port *ap);
+static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ if (qc->ap->flags & K2_FLAG_NO_ATAPI_DMA)
+ return -1; /* ATAPI DMA not supported */
+
+ return 0;
+}
+
static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
- return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -101,7 +125,7 @@ static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
{
if (sc_reg > SCR_CONTROL)
return;
- writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -116,11 +140,16 @@ static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
ata_wait_idle(ap);
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
- writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
- writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
- writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
- writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
+ writew(tf->feature | (((u16)tf->hob_feature) << 8),
+ ioaddr->feature_addr);
+ writew(tf->nsect | (((u16)tf->hob_nsect) << 8),
+ ioaddr->nsect_addr);
+ writew(tf->lbal | (((u16)tf->hob_lbal) << 8),
+ ioaddr->lbal_addr);
+ writew(tf->lbam | (((u16)tf->hob_lbam) << 8),
+ ioaddr->lbam_addr);
+ writew(tf->lbah | (((u16)tf->hob_lbah) << 8),
+ ioaddr->lbah_addr);
} else if (is_addr) {
writew(tf->feature, ioaddr->feature_addr);
writew(tf->nsect, ioaddr->nsect_addr);
@@ -233,7 +262,7 @@ static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
static u8 k2_stat_check_status(struct ata_port *ap)
{
- return readl((void *) ap->ioaddr.status_addr);
+ return readl((void __iomem *) ap->ioaddr.status_addr);
}
#ifdef CONFIG_PPC_OF
@@ -313,27 +342,28 @@ static const struct ata_port_operations k2_sata_ops = {
.check_status = k2_stat_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .check_atapi_dma = k2_sata_check_atapi_dma,
.bmdma_setup = k2_bmdma_setup_mmio,
.bmdma_start = k2_bmdma_start_mmio,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = k2_sata_scr_read,
.scr_write = k2_sata_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
-static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
+static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET;
port->data_addr = base + K2_SATA_TF_DATA_OFFSET;
@@ -356,10 +386,11 @@ static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
+ struct device *dev = &pdev->dev;
+ struct ata_probe_ent *probe_ent;
void __iomem *mmio_base;
- int pci_dev_busy = 0;
+ const struct k2_board_info *board_info =
+ &k2_board_info[ent->driver_data];
int rc;
int i;
@@ -370,7 +401,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
* If this driver happens to only be useful on Apple's K2, then
* we should check that here as it has a normal Serverworks ID
*/
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
/*
@@ -380,56 +411,35 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
if (pci_resource_len(pdev, 5) == 0)
return -ENODEV;
- /* Request PCI regions */
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ /* Request and iomap PCI regions */
+ rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
- memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, 5, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- /* Clear a magic bit in SCR1 according to Darwin, those help
- * some funky seagate drives (though so far, those were already
- * set by the firmware on the machines I had access to)
- */
- writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000,
- mmio_base + K2_SATA_SICR1_OFFSET);
-
- /* Clear SATA error & interrupts we don't use */
- writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET);
- writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
-
probe_ent->sht = &k2_sata_sht;
probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO;
+ ATA_FLAG_MMIO | board_info->port_flags;
probe_ent->port_ops = &k2_sata_ops;
probe_ent->n_ports = 4;
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
/* We don't care much about the PIO/UDMA masks, but the core won't like us
* if we don't fill these
@@ -438,28 +448,33 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
probe_ent->mwdma_mask = 0x7;
probe_ent->udma_mask = 0x7f;
+ mmio_base = probe_ent->iomap[5];
+
/* different controllers have different number of ports - currently 4 or 8 */
/* All ports are on the same function. Multi-function device is no
* longer available. This should not be seen in any system. */
- for (i = 0; i < ent->driver_data; i++)
- k2_sata_setup_port(&probe_ent->port[i], base + i * K2_SATA_PORT_OFFSET);
+ for (i = 0; i < board_info->n_ports; i++)
+ k2_sata_setup_port(&probe_ent->port[i],
+ mmio_base + i * K2_SATA_PORT_OFFSET);
+
+ /* Clear a magic bit in SCR1 according to Darwin, those help
+ * some funky seagate drives (though so far, those were already
+ * set by the firmware on the machines I had access to)
+ */
+ writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000,
+ mmio_base + K2_SATA_SICR1_OFFSET);
+
+ /* Clear SATA error & interrupts we don't use */
+ writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET);
+ writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
pci_set_master(pdev);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(dev, probe_ent);
return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
/* 0x240 is device ID for Apple K2 device
@@ -469,11 +484,11 @@ err_out:
* controller
* */
static const struct pci_device_id k2_sata_pci_tbl[] = {
- { 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 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0240), board_svw4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0241), board_svw4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0242), board_svw8 },
+ { PCI_VDEVICE(SERVERWORKS, 0x024a), board_svw4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x024b), board_svw4 },
{ }
};
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index ae7992de4b0..06e87a37738 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -42,7 +42,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#include "sata_promise.h"
#define DRV_NAME "sata_sx4"
@@ -50,6 +49,9 @@
enum {
+ PDC_MMIO_BAR = 3,
+ PDC_DIMM_BAR = 4,
+
PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */
PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
@@ -138,8 +140,6 @@ struct pdc_port_priv {
};
struct pdc_host_priv {
- void __iomem *dimm_mmio;
-
unsigned int doing_hdma;
unsigned int hdma_prod;
unsigned int hdma_cons;
@@ -156,11 +156,9 @@ 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);
-static void pdc_port_stop(struct ata_port *ap);
static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
-static void pdc20621_host_stop(struct ata_host *host);
static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
@@ -205,13 +203,13 @@ static const struct ata_port_operations pdc_20621_ops = {
.phy_reset = pdc_20621_phy_reset,
.qc_prep = pdc20621_qc_prep,
.qc_issue = pdc20621_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.eng_timeout = pdc_eng_timeout,
.irq_handler = pdc20621_interrupt,
.irq_clear = pdc20621_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = pdc_port_start,
- .port_stop = pdc_port_stop,
- .host_stop = pdc20621_host_stop,
};
static const struct ata_port_info pdc_port_info[] = {
@@ -243,18 +241,6 @@ static struct pci_driver pdc_sata_pci_driver = {
};
-static void pdc20621_host_stop(struct ata_host *host)
-{
- struct pci_dev *pdev = to_pci_dev(host->dev);
- struct pdc_host_priv *hpriv = host->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
-
- pci_iounmap(pdev, dimm_mmio);
- kfree(hpriv);
-
- pci_iounmap(pdev, host->mmio_base);
-}
-
static int pdc_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
@@ -265,43 +251,19 @@ static int pdc_port_start(struct ata_port *ap)
if (rc)
return rc;
- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
- memset(pp, 0, sizeof(*pp));
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
- pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
- if (!pp->pkt) {
- rc = -ENOMEM;
- goto err_out_kfree;
- }
+ pp->pkt = dmam_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
+ if (!pp->pkt)
+ return -ENOMEM;
ap->private_data = pp;
return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
-}
-
-
-static void pdc_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host->dev;
- struct pdc_port_priv *pp = ap->private_data;
-
- ap->private_data = NULL;
- dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
- kfree(pp);
- ata_port_stop(ap);
}
-
static void pdc_20621_phy_reset (struct ata_port *ap)
{
VPRINTK("ENTER\n");
@@ -452,9 +414,8 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
struct scatterlist *sg;
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->mmio_base;
- struct pdc_host_priv *hpriv = ap->host->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
unsigned int portno = ap->port_no;
unsigned int i, idx, total_len = 0, sgt_len;
u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
@@ -513,9 +474,8 @@ static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->mmio_base;
- struct pdc_host_priv *hpriv = ap->host->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
unsigned int portno = ap->port_no;
unsigned int i;
@@ -565,7 +525,7 @@ static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
{
struct ata_port *ap = qc->ap;
struct ata_host *host = ap->host;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -619,8 +579,7 @@ static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
unsigned int port_no = ap->port_no;
- struct pdc_host_priv *hpriv = ap->host->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
dimm_mmio += PDC_DIMM_HOST_PKT;
@@ -639,7 +598,7 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct ata_host *host = ap->host;
unsigned int port_no = ap->port_no;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
u8 seq = (u8) (port_no + 1);
unsigned int port_ofs;
@@ -668,8 +627,8 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc)
readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
writel(port_ofs + PDC_DIMM_ATA_PKT,
- (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
port_ofs + PDC_DIMM_ATA_PKT,
port_ofs + PDC_DIMM_ATA_PKT,
@@ -747,8 +706,8 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
readl(mmio + PDC_20621_SEQCTL + (seq * 4));
writel(port_ofs + PDC_DIMM_ATA_PKT,
- (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
}
/* step two - execute ATA command */
@@ -781,7 +740,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
static void pdc20621_irq_clear(struct ata_port *ap)
{
struct ata_host *host = ap->host;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
mmio += PDC_CHIP0_OFS;
@@ -799,12 +758,12 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance)
VPRINTK("ENTER\n");
- if (!host || !host->mmio_base) {
+ if (!host || !host->iomap[PDC_MMIO_BAR]) {
VPRINTK("QUICK EXIT\n");
return IRQ_NONE;
}
- mmio_base = host->mmio_base;
+ mmio_base = host->iomap[PDC_MMIO_BAR];
/* reading should also clear interrupts */
mmio_base += PDC_CHIP0_OFS;
@@ -905,7 +864,7 @@ static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile
}
-static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+static void pdc_sata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr = base;
port->data_addr = base;
@@ -931,9 +890,8 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
u16 idx;
u8 page_mask;
long dist;
- void __iomem *mmio = pe->mmio_base;
- struct pdc_host_priv *hpriv = pe->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -987,9 +945,8 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
u16 idx;
u8 page_mask;
long dist;
- void __iomem *mmio = pe->mmio_base;
- struct pdc_host_priv *hpriv = pe->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1034,7 +991,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
u32 subaddr, u32 *pdata)
{
- void __iomem *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
u32 i2creg = 0;
u32 status;
u32 count =0;
@@ -1093,7 +1050,7 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
u32 data = 0;
int size, i;
u8 bdimmsize;
- void __iomem *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
static const struct {
unsigned int reg;
unsigned int ofs;
@@ -1155,8 +1112,8 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
{
u32 data, spd0;
- int error, i;
- void __iomem *mmio = pe->mmio_base;
+ int error, i;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1210,7 +1167,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
u32 ticks=0;
u32 clock=0;
u32 fparam=0;
- void __iomem *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1334,7 +1291,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
static void pdc_20621_init(struct ata_probe_ent *pe)
{
u32 tmp;
- void __iomem *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1365,67 +1322,43 @@ static void pdc_20621_init(struct ata_probe_ent *pe)
static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
- void __iomem *mmio_base;
- void __iomem *dimm_mmio = NULL;
- struct pdc_host_priv *hpriv = NULL;
+ struct ata_probe_ent *probe_ent;
+ void __iomem *base;
+ struct pdc_host_priv *hpriv;
unsigned int board_idx = (unsigned int) ent->driver_data;
- int pci_dev_busy = 0;
int rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, (1 << PDC_MMIO_BAR) | (1 << PDC_DIMM_BAR),
+ DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
- memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, 3, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
- memset(hpriv, 0, sizeof(*hpriv));
-
- dimm_mmio = pci_iomap(pdev, 4, 0);
- if (!dimm_mmio) {
- kfree(hpriv);
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
-
- hpriv->dimm_mmio = dimm_mmio;
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
probe_ent->sht = pdc_port_info[board_idx].sht;
probe_ent->port_flags = pdc_port_info[board_idx].flags;
@@ -1436,10 +1369,10 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
probe_ent->private_data = hpriv;
- base += PDC_CHIP0_OFS;
+ base = probe_ent->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
probe_ent->n_ports = 4;
pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
@@ -1451,31 +1384,15 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
/* initialize adapter */
/* initialize local dimm */
- if (pdc20621_dimm_init(probe_ent)) {
- rc = -ENOMEM;
- goto err_out_iounmap_dimm;
- }
+ if (pdc20621_dimm_init(probe_ent))
+ return -ENOMEM;
pdc_20621_init(probe_ent);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_iounmap_dimm: /* only get to this label if 20621 */
- kfree(hpriv);
- pci_iounmap(pdev, dimm_mmio);
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index 5c603ca3a50..80131eec68f 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -108,7 +108,7 @@ static const struct ata_port_operations uli_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -117,18 +117,19 @@ static const struct ata_port_operations uli_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = uli_scr_read,
.scr_write = uli_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static struct ata_port_info uli_port_info = {
.sht = &uli_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_IGN_SIMPLEX,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &uli_ops,
@@ -188,62 +189,60 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_port_info *ppi[2];
int rc;
unsigned int board_idx = (unsigned int) ent->driver_data;
- int pci_dev_busy = 0;
struct uli_priv *hpriv;
+ void __iomem * const *iomap;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
- pci_dev_busy = 1;
- goto err_out;
+ pcim_pin_device(pdev);
+ return rc;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
ppi[0] = ppi[1] = &uli_port_info;
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ if (!probe_ent)
+ return -ENOMEM;
- hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_probe_ent;
- }
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
probe_ent->private_data = hpriv;
+ iomap = pcim_iomap_table(pdev);
+
switch (board_idx) {
case uli_5287:
hpriv->scr_cfg_addr[0] = ULI5287_BASE;
hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
probe_ent->n_ports = 4;
- probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8;
+ probe_ent->port[2].cmd_addr = iomap[0] + 8;
probe_ent->port[2].altstatus_addr =
- probe_ent->port[2].ctl_addr =
- (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4;
- probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16;
+ probe_ent->port[2].ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4;
+ probe_ent->port[2].bmdma_addr = iomap[4] + 16;
hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
- probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8;
+ probe_ent->port[3].cmd_addr = iomap[2] + 8;
probe_ent->port[3].altstatus_addr =
- probe_ent->port[3].ctl_addr =
- (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4;
- probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24;
+ probe_ent->port[3].ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4;
+ probe_ent->port[3].bmdma_addr = iomap[4] + 24;
hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
ata_std_ports(&probe_ent->port[2]);
@@ -268,21 +267,11 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
pci_intx(pdev, 1);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_probe_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-
}
static int __init uli_init(void)
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 1c7f19aecc2..baca6d79bb0 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -44,7 +44,6 @@
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
-#include <asm/io.h>
#define DRV_NAME "sata_via"
#define DRV_VERSION "2.0"
@@ -59,11 +58,14 @@ enum {
SATA_INT_GATE = 0x41, /* SATA interrupt gating */
SATA_NATIVE_MODE = 0x42, /* Native mode enable */
SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */
-
+ PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */
+ PATA_PIO_TIMING = 0xAB, /* PATA timing register */
+
PORT0 = (1 << 1),
PORT1 = (1 << 0),
ALL_PORTS = PORT0 | PORT1,
- N_PORTS = 2,
+ PATA_PORT = 2, /* PATA is port 2 */
+ N_PORTS = 3,
NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
@@ -74,9 +76,16 @@ enum {
static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void svia_noop_freeze(struct ata_port *ap);
static void vt6420_error_handler(struct ata_port *ap);
+static void vt6421_sata_error_handler(struct ata_port *ap);
+static void vt6421_pata_error_handler(struct ata_port *ap);
+static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
+static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
+static int vt6421_port_start(struct ata_port *ap);
static const struct pci_device_id svia_pci_tbl[] = {
+ { PCI_VDEVICE(VIA, 0x5337), vt6420 },
{ PCI_VDEVICE(VIA, 0x0591), vt6420 },
{ PCI_VDEVICE(VIA, 0x3149), vt6420 },
{ PCI_VDEVICE(VIA, 0x3249), vt6421 },
@@ -125,24 +134,58 @@ static const struct ata_port_operations vt6420_sata_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
- .freeze = ata_bmdma_freeze,
+ .freeze = svia_noop_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = vt6420_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
-static const struct ata_port_operations vt6421_sata_ops = {
+static const struct ata_port_operations vt6421_pata_ops = {
.port_disable = ata_port_disable,
+
+ .set_piomode = vt6421_set_pio_mode,
+ .set_dmamode = vt6421_set_dma_mode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = vt6421_pata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .port_start = vt6421_port_start,
+};
+static const struct ata_port_operations vt6421_sata_ops = {
+ .port_disable = ata_port_disable,
+
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -156,22 +199,22 @@ static const struct ata_port_operations vt6421_sata_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ata_bmdma_error_handler,
+ .error_handler = vt6421_sata_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = svia_scr_read,
.scr_write = svia_scr_write,
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
+ .port_start = vt6421_port_start,
};
static struct ata_port_info vt6420_port_info = {
@@ -193,14 +236,23 @@ static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
- return inl(ap->ioaddr.scr_addr + (4 * sc_reg));
+ return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
}
static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return;
- outl(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+ iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+}
+
+static void svia_noop_freeze(struct ata_port *ap)
+{
+ /* Some VIA controllers choke if ATA_NIEN is manipulated in
+ * certain way. Leave it alone and just clear pending IRQ.
+ */
+ ata_chk_status(ap);
+ ata_bmdma_irq_clear(ap);
}
/**
@@ -278,6 +330,61 @@ static void vt6420_error_handler(struct ata_port *ap)
NULL, ata_std_postreset);
}
+static int vt6421_pata_prereset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ pci_read_config_byte(pdev, PATA_UDMA_TIMING, &tmp);
+ if (tmp & 0x10)
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ return 0;
+}
+
+static void vt6421_pata_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, vt6421_pata_prereset, ata_std_softreset,
+ NULL, ata_std_postreset);
+}
+
+static int vt6421_sata_prereset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_SATA;
+ return 0;
+}
+
+static void vt6421_sata_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, vt6421_sata_prereset, ata_std_softreset,
+ NULL, ata_std_postreset);
+}
+
+static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const u8 pio_bits[] = { 0xA8, 0x65, 0x65, 0x31, 0x20 };
+ pci_write_config_byte(pdev, PATA_PIO_TIMING, pio_bits[adev->pio_mode - XFER_PIO_0]);
+}
+
+static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const u8 udma_bits[] = { 0xEE, 0xE8, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0, 0xE0 };
+ pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->pio_mode - XFER_UDMA_0]);
+}
+
+static int vt6421_port_start(struct ata_port *ap)
+{
+ if (ap->port_no == PATA_PORT) {
+ ap->ops = &vt6421_pata_ops;
+ ap->mwdma_mask = 0;
+ ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST;
+ }
+ return ata_port_start(ap);
+}
+
static const unsigned int svia_bar_sizes[] = {
8, 4, 8, 4, 16, 256
};
@@ -286,31 +393,28 @@ static const unsigned int vt6421_bar_sizes[] = {
16, 16, 16, 16, 32, 128
};
-static unsigned long svia_scr_addr(unsigned long addr, unsigned int port)
+static void __iomem * svia_scr_addr(void __iomem *addr, unsigned int port)
{
return addr + (port * 128);
}
-static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port)
+static void __iomem * vt6421_scr_addr(void __iomem *addr, unsigned int port)
{
return addr + (port * 64);
}
static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
- struct pci_dev *pdev,
- unsigned int port)
+ void __iomem * const *iomap, unsigned int port)
{
- unsigned long reg_addr = pci_resource_start(pdev, port);
- unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8);
- unsigned long scr_addr;
+ void __iomem *reg_addr = iomap[port];
+ void __iomem *bmdma_addr = iomap[4] + (port * 8);
probe_ent->port[port].cmd_addr = reg_addr;
probe_ent->port[port].altstatus_addr =
- probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS;
+ probe_ent->port[port].ctl_addr = (void __iomem *)
+ ((unsigned long)(reg_addr + 8) | ATA_PCI_CTL_OFS);
probe_ent->port[port].bmdma_addr = bmdma_addr;
-
- scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port);
- probe_ent->port[port].scr_addr = scr_addr;
+ probe_ent->port[port].scr_addr = vt6421_scr_addr(iomap[5], port);
ata_std_ports(&probe_ent->port[port]);
}
@@ -319,16 +423,16 @@ static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
{
struct ata_probe_ent *probe_ent;
struct ata_port_info *ppi[2];
-
+ void __iomem * const *iomap;
+
ppi[0] = ppi[1] = &vt6420_port_info;
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent)
return NULL;
- probe_ent->port[0].scr_addr =
- svia_scr_addr(pci_resource_start(pdev, 5), 0);
- probe_ent->port[1].scr_addr =
- svia_scr_addr(pci_resource_start(pdev, 5), 1);
+ iomap = pcim_iomap_table(pdev);
+ probe_ent->port[0].scr_addr = svia_scr_addr(iomap[5], 0);
+ probe_ent->port[1].scr_addr = svia_scr_addr(iomap[5], 1);
return probe_ent;
}
@@ -338,7 +442,7 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
struct ata_probe_ent *probe_ent;
unsigned int i;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
if (!probe_ent)
return NULL;
@@ -357,7 +461,7 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
probe_ent->udma_mask = 0x7f;
for (i = 0; i < N_PORTS; i++)
- vt6421_init_addrs(probe_ent, pdev, i);
+ vt6421_init_addrs(probe_ent, pcim_iomap_table(pdev), i);
return probe_ent;
}
@@ -409,20 +513,19 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_probe_ent *probe_ent;
int board_id = (int) ent->driver_data;
const int *bar_sizes;
- int pci_dev_busy = 0;
u8 tmp8;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
+ rc = pcim_iomap_regions(pdev, 0x1f, DRV_NAME);
if (rc) {
- pci_dev_busy = 1;
- goto err_out;
+ pcim_pin_device(pdev);
+ return rc;
}
if (board_id == vt6420) {
@@ -431,8 +534,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
dev_printk(KERN_ERR, &pdev->dev,
"SATA master/slave not supported (0x%x)\n",
(int) tmp8);
- rc = -EIO;
- goto err_out_regions;
+ return -EIO;
}
bar_sizes = &svia_bar_sizes[0];
@@ -448,16 +550,15 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
i,
(unsigned long long)pci_resource_start(pdev, i),
(unsigned long long)pci_resource_len(pdev, i));
- rc = -ENODEV;
- goto err_out_regions;
+ return -ENODEV;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
if (board_id == vt6420)
probe_ent = vt6420_init_probe_ent(pdev);
@@ -466,26 +567,18 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!probe_ent) {
dev_printk(KERN_ERR, &pdev->dev, "out of memory\n");
- rc = -ENOMEM;
- goto err_out_regions;
+ return -ENOMEM;
}
svia_configure(pdev);
pci_set_master(pdev);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
static int __init svia_init(void)
@@ -500,4 +593,3 @@ static void __exit svia_exit(void)
module_init(svia_init);
module_exit(svia_exit);
-
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index e654b990b90..3d9daf23111 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -50,6 +50,8 @@
#define DRV_VERSION "2.0"
enum {
+ VSC_MMIO_BAR = 0,
+
/* Interrupt register offsets (from chip base address) */
VSC_SATA_INT_STAT_OFFSET = 0x00,
VSC_SATA_INT_MASK_OFFSET = 0x04,
@@ -96,7 +98,6 @@ enum {
VSC_SATA_INT_PHY_CHANGE),
};
-
#define is_vsc_sata_int_err(port_idx, int_status) \
(int_status & (VSC_SATA_INT_ERROR << (8 * port_idx)))
@@ -105,7 +106,7 @@ static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -114,7 +115,7 @@ static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
{
if (sc_reg > SCR_CONTROL)
return;
- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -123,7 +124,7 @@ static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
void __iomem *mask_addr;
u8 mask;
- mask_addr = ap->host->mmio_base +
+ mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
VSC_SATA_INT_MASK_OFFSET + ap->port_no;
mask = readb(mask_addr);
if (ctl & ATA_NIEN)
@@ -149,11 +150,16 @@ static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN);
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
- writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
- writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
- writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
- writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
+ writew(tf->feature | (((u16)tf->hob_feature) << 8),
+ ioaddr->feature_addr);
+ writew(tf->nsect | (((u16)tf->hob_nsect) << 8),
+ ioaddr->nsect_addr);
+ writew(tf->lbal | (((u16)tf->hob_lbal) << 8),
+ ioaddr->lbal_addr);
+ writew(tf->lbam | (((u16)tf->hob_lbam) << 8),
+ ioaddr->lbam_addr);
+ writew(tf->lbah | (((u16)tf->hob_lbah) << 8),
+ ioaddr->lbah_addr);
} else if (is_addr) {
writew(tf->feature, ioaddr->feature_addr);
writew(tf->nsect, ioaddr->nsect_addr);
@@ -212,7 +218,8 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance)
spin_lock(&host->lock);
- int_status = readl(host->mmio_base + VSC_SATA_INT_STAT_OFFSET);
+ int_status = readl(host->iomap[VSC_MMIO_BAR] +
+ VSC_SATA_INT_STAT_OFFSET);
for (i = 0; i < host->n_ports; i++) {
if (int_status & ((u32) 0xFF << (8 * i))) {
@@ -296,21 +303,22 @@ static const struct ata_port_operations vsc_sata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = vsc_sata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = vsc_sata_scr_read,
.scr_write = vsc_sata_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
-static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+static void __devinit vsc_sata_setup_port(struct ata_ioports *port,
+ void __iomem *base)
{
port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET;
port->data_addr = base + VSC_SATA_TF_DATA_OFFSET;
@@ -335,72 +343,62 @@ static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned lon
static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
- int pci_dev_busy = 0;
+ struct ata_probe_ent *probe_ent;
void __iomem *mmio_base;
int rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
/*
* Check if we have needed resource mapped.
*/
- if (pci_resource_len(pdev, 0) == 0) {
- rc = -ENODEV;
- goto err_out;
- }
+ if (pci_resource_len(pdev, 0) == 0)
+ return -ENODEV;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
/*
* Use 32 bit DMA mask, because 64 bit address support is poor.
*/
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
- memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, 0, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
/*
* Due to a bug in the chip, the default cache line size can't be used
*/
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
+ if (pci_enable_msi(pdev) == 0)
+ pci_intx(pdev, 0);
+ else
+ probe_ent->irq_flags = IRQF_SHARED;
+
probe_ent->sht = &vsc_sata_sht;
probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO;
probe_ent->port_ops = &vsc_sata_ops;
probe_ent->n_ports = 4;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
/* We don't care much about the PIO/UDMA masks, but the core won't like us
* if we don't fill these
@@ -409,11 +407,13 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
probe_ent->mwdma_mask = 0x07;
probe_ent->udma_mask = 0x7f;
+ mmio_base = probe_ent->iomap[VSC_MMIO_BAR];
+
/* We have 4 ports per PCI function */
- vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET);
+ vsc_sata_setup_port(&probe_ent->port[0], mmio_base + 1 * VSC_SATA_PORT_OFFSET);
+ vsc_sata_setup_port(&probe_ent->port[1], mmio_base + 2 * VSC_SATA_PORT_OFFSET);
+ vsc_sata_setup_port(&probe_ent->port[2], mmio_base + 3 * VSC_SATA_PORT_OFFSET);
+ vsc_sata_setup_port(&probe_ent->port[3], mmio_base + 4 * VSC_SATA_PORT_OFFSET);
pci_set_master(pdev);
@@ -425,20 +425,11 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
*/
pci_write_config_dword(pdev, 0x98, 0);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
static const struct pci_device_id vsc_sata_pci_tbl[] = {
diff --git a/drivers/atm/.gitignore b/drivers/atm/.gitignore
index a165b716771..fc0ae5eb05d 100644
--- a/drivers/atm/.gitignore
+++ b/drivers/atm/.gitignore
@@ -2,4 +2,4 @@
fore200e_mkfirm
fore200e_pca_fw.c
pca200e.bin
-
+pca200e_ecd.bin2
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index cfa5af883e1..33687454eb3 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -167,10 +167,6 @@ config ATM_ZATM_DEBUG
Note that extended debugging may create certain race conditions
itself. Enable this ONLY if you suspect problems with the driver.
-# bool 'Rolfs TI TNETA1570' CONFIG_ATM_TNETA1570 y
-# if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then
-# bool ' Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n
-# fi
config ATM_NICSTAR
tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
depends on PCI && ATM && !64BIT
@@ -242,6 +238,7 @@ config ATM_IDT77252_USE_SUNI
config ATM_AMBASSADOR
tristate "Madge Ambassador (Collage PCI 155 Server)"
depends on PCI && ATM
+ select BITREVERSE
help
This is a driver for ATMizer based ATM card produced by Madge
Networks Ltd. Say Y (or M to compile as a module named ambassador)
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index afa7d750a59..3c372e08f77 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/poison.h>
+#include <linux/bitrev.h>
#include <asm/atomic.h>
#include <asm/io.h>
@@ -2068,18 +2069,6 @@ static void __devinit amb_ucode_version (amb_dev * dev) {
PRINTK (KERN_INFO, "microcode version is %u.%u", major, minor);
}
-// swap bits within byte to get Ethernet ordering
-static u8 bit_swap (u8 byte)
-{
- const u8 swap[] = {
- 0x0, 0x8, 0x4, 0xc,
- 0x2, 0xa, 0x6, 0xe,
- 0x1, 0x9, 0x5, 0xd,
- 0x3, 0xb, 0x7, 0xf
- };
- return ((swap[byte & 0xf]<<4) | swap[byte>>4]);
-}
-
// get end station address
static void __devinit amb_esi (amb_dev * dev, u8 * esi) {
u32 lower4;
@@ -2101,9 +2090,9 @@ static void __devinit amb_esi (amb_dev * dev, u8 * esi) {
PRINTDB (DBG_INIT, "ESI:");
for (i = 0; i < ESI_LEN; ++i) {
if (i < 4)
- esi[i] = bit_swap (lower4>>(8*i));
+ esi[i] = bitrev8(lower4>>(8*i));
else
- esi[i] = bit_swap (upper2>>(8*(i-4)));
+ esi[i] = bitrev8(upper2>>(8*(i-4)));
PRINTDM (DBG_INIT, " %02x", esi[i]);
}
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index bc1b13c8f5d..5aab7bd473a 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -1832,7 +1832,7 @@ static int __devinit eni_start(struct atm_dev *dev)
/* initialize memory management */
buffer_mem = eni_dev->mem - (buf - eni_dev->ram);
eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2;
- eni_dev->free_list = (struct eni_free *) kmalloc(
+ eni_dev->free_list = kmalloc(
sizeof(struct eni_free)*(eni_dev->free_list_size+1),GFP_KERNEL);
if (!eni_dev->free_list) {
printk(KERN_ERR DEV_LABEL "(itf %d): couldn't get free page\n",
@@ -2232,7 +2232,7 @@ static int __devinit eni_init_one(struct pci_dev *pci_dev,
goto out0;
}
- eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),GFP_KERNEL);
+ eni_dev = kmalloc(sizeof(struct eni_dev),GFP_KERNEL);
if (!eni_dev) goto out0;
if (!cpu_zeroes) {
cpu_zeroes = pci_alloc_consistent(pci_dev,ENI_ZEROES_SIZE,
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 3a7b21ff30a..4aeb3d062ff 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -172,25 +172,6 @@ fore200e_irq_itoa(int irq)
}
-static void*
-fore200e_kmalloc(int size, gfp_t flags)
-{
- void *chunk = kzalloc(size, flags);
-
- if (!chunk)
- printk(FORE200E "kmalloc() failed, requested size = %d, flags = 0x%x\n", size, flags);
-
- return chunk;
-}
-
-
-static void
-fore200e_kfree(void* chunk)
-{
- kfree(chunk);
-}
-
-
/* allocate and align a chunk of memory intended to hold the data behing exchanged
between the driver and the adapter (using streaming DVMA) */
@@ -206,7 +187,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
chunk->align_size = size;
chunk->direction = direction;
- chunk->alloc_addr = fore200e_kmalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA);
+ chunk->alloc_addr = kzalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA);
if (chunk->alloc_addr == NULL)
return -ENOMEM;
@@ -228,7 +209,7 @@ fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
{
fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size, chunk->direction);
- fore200e_kfree(chunk->alloc_addr);
+ kfree(chunk->alloc_addr);
}
@@ -882,7 +863,7 @@ fore200e_sba_detect(const struct fore200e_bus* bus, int index)
return NULL;
}
- fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
+ fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
if (fore200e == NULL)
return NULL;
@@ -1505,7 +1486,7 @@ fore200e_open(struct atm_vcc *vcc)
spin_unlock_irqrestore(&fore200e->q_lock, flags);
- fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_ATOMIC);
+ fore200e_vcc = kzalloc(sizeof(struct fore200e_vcc), GFP_ATOMIC);
if (fore200e_vcc == NULL) {
vc_map->vcc = NULL;
return -ENOMEM;
@@ -1526,7 +1507,7 @@ fore200e_open(struct atm_vcc *vcc)
if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) {
up(&fore200e->rate_sf);
- fore200e_kfree(fore200e_vcc);
+ kfree(fore200e_vcc);
vc_map->vcc = NULL;
return -EAGAIN;
}
@@ -1554,7 +1535,7 @@ fore200e_open(struct atm_vcc *vcc)
fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
- fore200e_kfree(fore200e_vcc);
+ kfree(fore200e_vcc);
return -EINVAL;
}
@@ -1630,7 +1611,7 @@ fore200e_close(struct atm_vcc* vcc)
clear_bit(ATM_VF_PARTIAL,&vcc->flags);
ASSERT(fore200e_vcc);
- fore200e_kfree(fore200e_vcc);
+ kfree(fore200e_vcc);
}
@@ -1831,7 +1812,7 @@ fore200e_getstats(struct fore200e* fore200e)
u32 stats_dma_addr;
if (fore200e->stats == NULL) {
- fore200e->stats = fore200e_kmalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA);
+ fore200e->stats = kzalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA);
if (fore200e->stats == NULL)
return -ENOMEM;
}
@@ -2002,17 +1983,6 @@ fore200e_setloop(struct fore200e* fore200e, int loop_mode)
}
-static inline unsigned int
-fore200e_swap(unsigned int in)
-{
-#if defined(__LITTLE_ENDIAN)
- return swab32(in);
-#else
- return in;
-#endif
-}
-
-
static int
fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats __user *arg)
{
@@ -2021,19 +1991,19 @@ fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats __user *arg)
if (fore200e_getstats(fore200e) < 0)
return -EIO;
- tmp.section_bip = fore200e_swap(fore200e->stats->oc3.section_bip8_errors);
- tmp.line_bip = fore200e_swap(fore200e->stats->oc3.line_bip24_errors);
- tmp.path_bip = fore200e_swap(fore200e->stats->oc3.path_bip8_errors);
- tmp.line_febe = fore200e_swap(fore200e->stats->oc3.line_febe_errors);
- tmp.path_febe = fore200e_swap(fore200e->stats->oc3.path_febe_errors);
- tmp.corr_hcs = fore200e_swap(fore200e->stats->oc3.corr_hcs_errors);
- tmp.uncorr_hcs = fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors);
- tmp.tx_cells = fore200e_swap(fore200e->stats->aal0.cells_transmitted) +
- fore200e_swap(fore200e->stats->aal34.cells_transmitted) +
- fore200e_swap(fore200e->stats->aal5.cells_transmitted);
- tmp.rx_cells = fore200e_swap(fore200e->stats->aal0.cells_received) +
- fore200e_swap(fore200e->stats->aal34.cells_received) +
- fore200e_swap(fore200e->stats->aal5.cells_received);
+ tmp.section_bip = cpu_to_be32(fore200e->stats->oc3.section_bip8_errors);
+ tmp.line_bip = cpu_to_be32(fore200e->stats->oc3.line_bip24_errors);
+ tmp.path_bip = cpu_to_be32(fore200e->stats->oc3.path_bip8_errors);
+ tmp.line_febe = cpu_to_be32(fore200e->stats->oc3.line_febe_errors);
+ tmp.path_febe = cpu_to_be32(fore200e->stats->oc3.path_febe_errors);
+ tmp.corr_hcs = cpu_to_be32(fore200e->stats->oc3.corr_hcs_errors);
+ tmp.uncorr_hcs = cpu_to_be32(fore200e->stats->oc3.ucorr_hcs_errors);
+ tmp.tx_cells = cpu_to_be32(fore200e->stats->aal0.cells_transmitted) +
+ cpu_to_be32(fore200e->stats->aal34.cells_transmitted) +
+ cpu_to_be32(fore200e->stats->aal5.cells_transmitted);
+ tmp.rx_cells = cpu_to_be32(fore200e->stats->aal0.cells_received) +
+ cpu_to_be32(fore200e->stats->aal34.cells_received) +
+ cpu_to_be32(fore200e->stats->aal5.cells_received);
if (arg)
return copy_to_user(arg, &tmp, sizeof(struct sonet_stats)) ? -EFAULT : 0;
@@ -2146,7 +2116,7 @@ fore200e_irq_request(struct fore200e* fore200e)
static int __devinit
fore200e_get_esi(struct fore200e* fore200e)
{
- struct prom_data* prom = fore200e_kmalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA);
+ struct prom_data* prom = kzalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA);
int ok, i;
if (!prom)
@@ -2154,7 +2124,7 @@ fore200e_get_esi(struct fore200e* fore200e)
ok = fore200e->bus->prom_read(fore200e, prom);
if (ok < 0) {
- fore200e_kfree(prom);
+ kfree(prom);
return -EBUSY;
}
@@ -2169,7 +2139,7 @@ fore200e_get_esi(struct fore200e* fore200e)
fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ];
}
- fore200e_kfree(prom);
+ kfree(prom);
return 0;
}
@@ -2194,7 +2164,7 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e)
DPRINTK(2, "rx buffers %d / %d are being allocated\n", scheme, magn);
/* allocate the array of receive buffers */
- buffer = bsq->buffer = fore200e_kmalloc(nbr * sizeof(struct buffer), GFP_KERNEL);
+ buffer = bsq->buffer = kzalloc(nbr * sizeof(struct buffer), GFP_KERNEL);
if (buffer == NULL)
return -ENOMEM;
@@ -2217,7 +2187,7 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e)
while (i > 0)
fore200e_chunk_free(fore200e, &buffer[ --i ].data);
- fore200e_kfree(buffer);
+ kfree(buffer);
return -ENOMEM;
}
@@ -2736,7 +2706,7 @@ fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent
goto out;
}
- fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
+ fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
if (fore200e == NULL) {
err = -ENOMEM;
goto out_disable;
@@ -2999,8 +2969,8 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
" 4b5b:\n"
" crc_header_errors:\t\t%10u\n"
" framing_errors:\t\t%10u\n",
- fore200e_swap(fore200e->stats->phy.crc_header_errors),
- fore200e_swap(fore200e->stats->phy.framing_errors));
+ cpu_to_be32(fore200e->stats->phy.crc_header_errors),
+ cpu_to_be32(fore200e->stats->phy.framing_errors));
if (!left--)
return sprintf(page, "\n"
@@ -3012,13 +2982,13 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
" path_febe_errors:\t\t%10u\n"
" corr_hcs_errors:\t\t%10u\n"
" ucorr_hcs_errors:\t\t%10u\n",
- fore200e_swap(fore200e->stats->oc3.section_bip8_errors),
- fore200e_swap(fore200e->stats->oc3.path_bip8_errors),
- fore200e_swap(fore200e->stats->oc3.line_bip24_errors),
- fore200e_swap(fore200e->stats->oc3.line_febe_errors),
- fore200e_swap(fore200e->stats->oc3.path_febe_errors),
- fore200e_swap(fore200e->stats->oc3.corr_hcs_errors),
- fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors));
+ cpu_to_be32(fore200e->stats->oc3.section_bip8_errors),
+ cpu_to_be32(fore200e->stats->oc3.path_bip8_errors),
+ cpu_to_be32(fore200e->stats->oc3.line_bip24_errors),
+ cpu_to_be32(fore200e->stats->oc3.line_febe_errors),
+ cpu_to_be32(fore200e->stats->oc3.path_febe_errors),
+ cpu_to_be32(fore200e->stats->oc3.corr_hcs_errors),
+ cpu_to_be32(fore200e->stats->oc3.ucorr_hcs_errors));
if (!left--)
return sprintf(page,"\n"
@@ -3029,12 +2999,12 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
" vpi no conn:\t\t%10u\n"
" vci out of range:\t\t%10u\n"
" vci no conn:\t\t%10u\n",
- fore200e_swap(fore200e->stats->atm.cells_transmitted),
- fore200e_swap(fore200e->stats->atm.cells_received),
- fore200e_swap(fore200e->stats->atm.vpi_bad_range),
- fore200e_swap(fore200e->stats->atm.vpi_no_conn),
- fore200e_swap(fore200e->stats->atm.vci_bad_range),
- fore200e_swap(fore200e->stats->atm.vci_no_conn));
+ cpu_to_be32(fore200e->stats->atm.cells_transmitted),
+ cpu_to_be32(fore200e->stats->atm.cells_received),
+ cpu_to_be32(fore200e->stats->atm.vpi_bad_range),
+ cpu_to_be32(fore200e->stats->atm.vpi_no_conn),
+ cpu_to_be32(fore200e->stats->atm.vci_bad_range),
+ cpu_to_be32(fore200e->stats->atm.vci_no_conn));
if (!left--)
return sprintf(page,"\n"
@@ -3042,9 +3012,9 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
" TX:\t\t\t%10u\n"
" RX:\t\t\t%10u\n"
" dropped:\t\t\t%10u\n",
- fore200e_swap(fore200e->stats->aal0.cells_transmitted),
- fore200e_swap(fore200e->stats->aal0.cells_received),
- fore200e_swap(fore200e->stats->aal0.cells_dropped));
+ cpu_to_be32(fore200e->stats->aal0.cells_transmitted),
+ cpu_to_be32(fore200e->stats->aal0.cells_received),
+ cpu_to_be32(fore200e->stats->aal0.cells_dropped));
if (!left--)
return sprintf(page,"\n"
@@ -3060,15 +3030,15 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
" RX:\t\t\t%10u\n"
" dropped:\t\t\t%10u\n"
" protocol errors:\t\t%10u\n",
- fore200e_swap(fore200e->stats->aal34.cells_transmitted),
- fore200e_swap(fore200e->stats->aal34.cells_received),
- fore200e_swap(fore200e->stats->aal34.cells_dropped),
- fore200e_swap(fore200e->stats->aal34.cells_crc_errors),
- fore200e_swap(fore200e->stats->aal34.cells_protocol_errors),
- fore200e_swap(fore200e->stats->aal34.cspdus_transmitted),
- fore200e_swap(fore200e->stats->aal34.cspdus_received),
- fore200e_swap(fore200e->stats->aal34.cspdus_dropped),
- fore200e_swap(fore200e->stats->aal34.cspdus_protocol_errors));
+ cpu_to_be32(fore200e->stats->aal34.cells_transmitted),
+ cpu_to_be32(fore200e->stats->aal34.cells_received),
+ cpu_to_be32(fore200e->stats->aal34.cells_dropped),
+ cpu_to_be32(fore200e->stats->aal34.cells_crc_errors),
+ cpu_to_be32(fore200e->stats->aal34.cells_protocol_errors),
+ cpu_to_be32(fore200e->stats->aal34.cspdus_transmitted),
+ cpu_to_be32(fore200e->stats->aal34.cspdus_received),
+ cpu_to_be32(fore200e->stats->aal34.cspdus_dropped),
+ cpu_to_be32(fore200e->stats->aal34.cspdus_protocol_errors));
if (!left--)
return sprintf(page,"\n"
@@ -3084,15 +3054,15 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
" dropped:\t\t\t%10u\n"
" CRC errors:\t\t%10u\n"
" protocol errors:\t\t%10u\n",
- fore200e_swap(fore200e->stats->aal5.cells_transmitted),
- fore200e_swap(fore200e->stats->aal5.cells_received),
- fore200e_swap(fore200e->stats->aal5.cells_dropped),
- fore200e_swap(fore200e->stats->aal5.congestion_experienced),
- fore200e_swap(fore200e->stats->aal5.cspdus_transmitted),
- fore200e_swap(fore200e->stats->aal5.cspdus_received),
- fore200e_swap(fore200e->stats->aal5.cspdus_dropped),
- fore200e_swap(fore200e->stats->aal5.cspdus_crc_errors),
- fore200e_swap(fore200e->stats->aal5.cspdus_protocol_errors));
+ cpu_to_be32(fore200e->stats->aal5.cells_transmitted),
+ cpu_to_be32(fore200e->stats->aal5.cells_received),
+ cpu_to_be32(fore200e->stats->aal5.cells_dropped),
+ cpu_to_be32(fore200e->stats->aal5.congestion_experienced),
+ cpu_to_be32(fore200e->stats->aal5.cspdus_transmitted),
+ cpu_to_be32(fore200e->stats->aal5.cspdus_received),
+ cpu_to_be32(fore200e->stats->aal5.cspdus_dropped),
+ cpu_to_be32(fore200e->stats->aal5.cspdus_crc_errors),
+ cpu_to_be32(fore200e->stats->aal5.cspdus_protocol_errors));
if (!left--)
return sprintf(page,"\n"
@@ -3103,11 +3073,11 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
" large b2:\t\t\t%10u\n"
" RX PDUs:\t\t\t%10u\n"
" TX PDUs:\t\t\t%10lu\n",
- fore200e_swap(fore200e->stats->aux.small_b1_failed),
- fore200e_swap(fore200e->stats->aux.large_b1_failed),
- fore200e_swap(fore200e->stats->aux.small_b2_failed),
- fore200e_swap(fore200e->stats->aux.large_b2_failed),
- fore200e_swap(fore200e->stats->aux.rpd_alloc_failed),
+ cpu_to_be32(fore200e->stats->aux.small_b1_failed),
+ cpu_to_be32(fore200e->stats->aux.large_b1_failed),
+ cpu_to_be32(fore200e->stats->aux.small_b2_failed),
+ cpu_to_be32(fore200e->stats->aux.large_b2_failed),
+ cpu_to_be32(fore200e->stats->aux.rpd_alloc_failed),
fore200e->tx_sat);
if (!left--)
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 7d9b4e52f0b..db33f6f4dd2 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -2351,7 +2351,7 @@ he_open(struct atm_vcc *vcc)
cid = he_mkcid(he_dev, vpi, vci);
- he_vcc = (struct he_vcc *) kmalloc(sizeof(struct he_vcc), GFP_ATOMIC);
+ he_vcc = kmalloc(sizeof(struct he_vcc), GFP_ATOMIC);
if (he_vcc == NULL) {
hprintk("unable to allocate he_vcc during open\n");
return -ENOMEM;
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index 4dc10105d61..f96446c358b 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -1845,7 +1845,7 @@ static u16 __devinit read_bia (const hrz_dev * dev, u16 addr)
/********** initialise a card **********/
-static int __init hrz_init (hrz_dev * dev) {
+static int __devinit hrz_init (hrz_dev * dev) {
int onefivefive;
u16 chan;
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index 267825501df..09f477d4237 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -2602,7 +2602,7 @@ static int __devinit lanai_init_one(struct pci_dev *pci,
struct atm_dev *atmdev;
int result;
- lanai = (struct lanai_dev *) kmalloc(sizeof(*lanai), GFP_KERNEL);
+ lanai = kmalloc(sizeof(*lanai), GFP_KERNEL);
if (lanai == NULL) {
printk(KERN_ERR DEV_LABEL
": couldn't allocate dev_data structure!\n");
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index bd090459480..aab9b3733d5 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -997,7 +997,7 @@ static scq_info *get_scq(int size, u32 scd)
if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
return NULL;
- scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL);
+ scq = kmalloc(sizeof(scq_info), GFP_KERNEL);
if (scq == NULL)
return NULL;
scq->org = kmalloc(2 * size, GFP_KERNEL);
@@ -1006,7 +1006,7 @@ static scq_info *get_scq(int size, u32 scd)
kfree(scq);
return NULL;
}
- scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) *
+ scq->skb = kmalloc(sizeof(struct sk_buff *) *
(size / NS_SCQE_SIZE), GFP_KERNEL);
if (scq->skb == NULL)
{
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 7df0f373188..756d4f760da 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -996,7 +996,7 @@ static int start_tx(struct atm_dev *dev)
DPRINTK("start_tx\n");
zatm_dev = ZATM_DEV(dev);
- zatm_dev->tx_map = (struct atm_vcc **) kmalloc(sizeof(struct atm_vcc *)*
+ zatm_dev->tx_map = kmalloc(sizeof(struct atm_vcc *)*
zatm_dev->chans,GFP_KERNEL);
if (!zatm_dev->tx_map) return -ENOMEM;
zatm_dev->tx_bw = ATM_OC3_PCR;
@@ -1591,7 +1591,7 @@ static int __devinit zatm_init_one(struct pci_dev *pci_dev,
struct zatm_dev *zatm_dev;
int ret = -ENOMEM;
- zatm_dev = (struct zatm_dev *) kmalloc(sizeof(*zatm_dev), GFP_KERNEL);
+ zatm_dev = kmalloc(sizeof(*zatm_dev), GFP_KERNEL);
if (!zatm_dev) {
printk(KERN_EMERG "%s: memory shortage\n", DEV_LABEL);
goto out;
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 1429f3a2629..5d6312e3349 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -37,6 +37,18 @@ config DEBUG_DRIVER
If you are unsure about this, say N here.
+config DEBUG_DEVRES
+ bool "Managed device resources verbose debug messages"
+ depends on DEBUG_KERNEL
+ help
+ This option enables kernel parameter devres.log. If set to
+ non-zero, devres debug messages are printed. Select this if
+ you are having a problem with devres or want to debug
+ resource management for a managed device. devres.log can be
+ switched on and off from sysfs node.
+
+ If you are unsure about this, Say N here.
+
config SYS_HYPERVISOR
bool
default n
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 7bbb9eeda23..e9eb7382ac3 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -3,6 +3,7 @@
obj-y := core.o sys.o bus.o dd.o \
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o dmapool.o \
+ dma-mapping.o devres.o \
attribute_container.o transport_class.o
obj-y += power/
obj-$(CONFIG_ISA) += isa.o
diff --git a/drivers/base/base.h b/drivers/base/base.h
index d26644a5953..de7e1442ce6 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -44,3 +44,4 @@ struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
extern char *make_class_name(const char *name, struct kobject *kobj);
+extern void devres_release_all(struct device *dev);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index f098881f45b..96def1ddba1 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -163,6 +163,8 @@ int class_register(struct class * cls)
void class_unregister(struct class * cls)
{
pr_debug("device class '%s': unregistering\n", cls->name);
+ if (cls->virtual_dir)
+ kobject_unregister(cls->virtual_dir);
remove_class_attrs(cls);
subsystem_unregister(&cls->subsys);
}
@@ -362,7 +364,7 @@ char *make_class_name(const char *name, struct kobject *kobj)
class_name = kmalloc(size, GFP_KERNEL);
if (!class_name)
- return ERR_PTR(-ENOMEM);
+ return NULL;
strcpy(class_name, name);
strcat(class_name, ":");
@@ -409,8 +411,11 @@ static int make_deprecated_class_device_links(struct class_device *class_dev)
return 0;
class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
- error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
- class_name);
+ if (class_name)
+ error = sysfs_create_link(&class_dev->dev->kobj,
+ &class_dev->kobj, class_name);
+ else
+ error = -ENOMEM;
kfree(class_name);
return error;
}
@@ -423,7 +428,8 @@ static void remove_deprecated_class_device_links(struct class_device *class_dev)
return;
class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
- sysfs_remove_link(&class_dev->dev->kobj, class_name);
+ if (class_name)
+ sysfs_remove_link(&class_dev->dev->kobj, class_name);
kfree(class_name);
}
#else
@@ -861,9 +867,12 @@ int class_device_rename(struct class_device *class_dev, char *new_name)
if (class_dev->dev) {
new_class_name = make_class_name(class_dev->class->name,
&class_dev->kobj);
- sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
- new_class_name);
- sysfs_remove_link(&class_dev->dev->kobj, old_class_name);
+ if (new_class_name)
+ sysfs_create_link(&class_dev->dev->kobj,
+ &class_dev->kobj, new_class_name);
+ if (old_class_name)
+ sysfs_remove_link(&class_dev->dev->kobj,
+ old_class_name);
}
#endif
class_device_put(class_dev);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 67b79a7592a..a8ac34ba610 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -95,6 +95,8 @@ static void device_release(struct kobject * kobj)
if (dev->release)
dev->release(dev);
+ else if (dev->type && dev->type->release)
+ dev->type->release(dev);
else if (dev->class && dev->class->dev_release)
dev->class->dev_release(dev);
else {
@@ -154,25 +156,47 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
"MINOR=%u", MINOR(dev->devt));
}
-#ifdef CONFIG_SYSFS_DEPRECATED
- /* add bus name (same as SUBSYSTEM, deprecated) */
- if (dev->bus)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", dev->bus->name);
-#endif
-
- /* add driver name (PHYSDEV* values are deprecated)*/
- if (dev->driver) {
+ if (dev->driver)
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"DRIVER=%s", dev->driver->name);
+
#ifdef CONFIG_SYSFS_DEPRECATED
+ if (dev->class) {
+ struct device *parent = dev->parent;
+
+ /* find first bus device in parent chain */
+ while (parent && !parent->bus)
+ parent = parent->parent;
+ if (parent && parent->bus) {
+ const char *path;
+
+ path = kobject_get_path(&parent->kobj, GFP_KERNEL);
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVPATH=%s", path);
+ kfree(path);
+
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVBUS=%s", parent->bus->name);
+
+ if (parent->driver)
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVDRIVER=%s", parent->driver->name);
+ }
+ } else if (dev->bus) {
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", dev->driver->name);
-#endif
+ "PHYSDEVBUS=%s", dev->bus->name);
+
+ if (dev->driver)
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVDRIVER=%s", dev->driver->name);
}
+#endif
/* terminate, set to next free slot, shrink available space */
envp[i] = NULL;
@@ -184,19 +208,25 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
if (dev->bus && dev->bus->uevent) {
/* have the bus specific function add its stuff */
retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
- if (retval) {
- pr_debug ("%s - uevent() returned %d\n",
+ if (retval)
+ pr_debug ("%s: bus uevent() returned %d\n",
__FUNCTION__, retval);
- }
}
if (dev->class && dev->class->dev_uevent) {
/* have the class specific function add its stuff */
retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
- if (retval) {
- pr_debug("%s - dev_uevent() returned %d\n",
- __FUNCTION__, retval);
- }
+ if (retval)
+ pr_debug("%s: class uevent() returned %d\n",
+ __FUNCTION__, retval);
+ }
+
+ if (dev->type && dev->type->uevent) {
+ /* have the device type specific fuction add its stuff */
+ retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+ if (retval)
+ pr_debug("%s: dev_type uevent() returned %d\n",
+ __FUNCTION__, retval);
}
return retval;
@@ -247,37 +277,50 @@ static void device_remove_groups(struct device *dev)
static int device_add_attrs(struct device *dev)
{
struct class *class = dev->class;
+ struct device_type *type = dev->type;
int error = 0;
int i;
- if (!class)
- return 0;
-
- if (class->dev_attrs) {
+ if (class && class->dev_attrs) {
for (i = 0; attr_name(class->dev_attrs[i]); i++) {
error = device_create_file(dev, &class->dev_attrs[i]);
if (error)
break;
}
+ if (error)
+ while (--i >= 0)
+ device_remove_file(dev, &class->dev_attrs[i]);
}
- if (error)
- while (--i >= 0)
- device_remove_file(dev, &class->dev_attrs[i]);
+
+ if (type && type->attrs) {
+ for (i = 0; attr_name(type->attrs[i]); i++) {
+ error = device_create_file(dev, &type->attrs[i]);
+ if (error)
+ break;
+ }
+ if (error)
+ while (--i >= 0)
+ device_remove_file(dev, &type->attrs[i]);
+ }
+
return error;
}
static void device_remove_attrs(struct device *dev)
{
struct class *class = dev->class;
+ struct device_type *type = dev->type;
int i;
- if (!class)
- return;
-
- if (class->dev_attrs) {
+ if (class && class->dev_attrs) {
for (i = 0; attr_name(class->dev_attrs[i]); i++)
device_remove_file(dev, &class->dev_attrs[i]);
}
+
+ if (type && type->attrs) {
+ for (i = 0; attr_name(type->attrs[i]); i++)
+ device_remove_file(dev, &type->attrs[i]);
+ }
}
@@ -385,27 +428,30 @@ void device_initialize(struct device *dev)
INIT_LIST_HEAD(&dev->dma_pools);
INIT_LIST_HEAD(&dev->node);
init_MUTEX(&dev->sem);
+ spin_lock_init(&dev->devres_lock);
+ INIT_LIST_HEAD(&dev->devres_head);
device_init_wakeup(dev, 0);
set_dev_node(dev, -1);
}
#ifdef CONFIG_SYSFS_DEPRECATED
-static int setup_parent(struct device *dev, struct device *parent)
+static struct kobject * get_device_parent(struct device *dev,
+ struct device *parent)
{
/* Set the parent to the class, not the parent device */
/* this keeps sysfs from having a symlink to make old udevs happy */
if (dev->class)
- dev->kobj.parent = &dev->class->subsys.kset.kobj;
+ return &dev->class->subsys.kset.kobj;
else if (parent)
- dev->kobj.parent = &parent->kobj;
+ return &parent->kobj;
- return 0;
+ return NULL;
}
#else
-static int virtual_device_parent(struct device *dev)
+static struct kobject * virtual_device_parent(struct device *dev)
{
if (!dev->class)
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
if (!dev->class->virtual_dir) {
static struct kobject *virtual_dir = NULL;
@@ -415,25 +461,31 @@ static int virtual_device_parent(struct device *dev)
dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
}
- dev->kobj.parent = dev->class->virtual_dir;
- return 0;
+ return dev->class->virtual_dir;
}
-static int setup_parent(struct device *dev, struct device *parent)
+static struct kobject * get_device_parent(struct device *dev,
+ struct device *parent)
{
- int error;
-
/* if this is a class device, and has no parent, create one */
if ((dev->class) && (parent == NULL)) {
- error = virtual_device_parent(dev);
- if (error)
- return error;
+ return virtual_device_parent(dev);
} else if (parent)
- dev->kobj.parent = &parent->kobj;
+ return &parent->kobj;
+ return NULL;
+}
+#endif
+static int setup_parent(struct device *dev, struct device *parent)
+{
+ struct kobject *kobj;
+ kobj = get_device_parent(dev, parent);
+ if (IS_ERR(kobj))
+ return PTR_ERR(kobj);
+ if (kobj)
+ dev->kobj.parent = kobj;
return 0;
}
-#endif
/**
* device_add - add device to device hierarchy.
@@ -520,9 +572,13 @@ int device_add(struct device *dev)
&dev->kobj, dev->bus_id);
#ifdef CONFIG_SYSFS_DEPRECATED
if (parent) {
- sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
- class_name = make_class_name(dev->class->name, &dev->kobj);
- sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
+ sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+ "device");
+ class_name = make_class_name(dev->class->name,
+ &dev->kobj);
+ if (class_name)
+ sysfs_create_link(&dev->parent->kobj,
+ &dev->kobj, class_name);
}
#endif
}
@@ -535,7 +591,8 @@ int device_add(struct device *dev)
goto PMError;
if ((error = bus_add_device(dev)))
goto BusError;
- kobject_uevent(&dev->kobj, KOBJ_ADD);
+ if (!dev->uevent_suppress)
+ kobject_uevent(&dev->kobj, KOBJ_ADD);
if ((error = bus_attach_device(dev)))
goto AttachError;
if (parent)
@@ -665,7 +722,9 @@ void device_del(struct device * dev)
if (parent) {
char *class_name = make_class_name(dev->class->name,
&dev->kobj);
- sysfs_remove_link(&dev->parent->kobj, class_name);
+ if (class_name)
+ sysfs_remove_link(&dev->parent->kobj,
+ class_name);
kfree(class_name);
sysfs_remove_link(&dev->kobj, "device");
}
@@ -968,20 +1027,25 @@ static int device_move_class_links(struct device *dev,
class_name = make_class_name(dev->class->name, &dev->kobj);
if (!class_name) {
- error = PTR_ERR(class_name);
- class_name = NULL;
+ error = -ENOMEM;
goto out;
}
if (old_parent) {
sysfs_remove_link(&dev->kobj, "device");
sysfs_remove_link(&old_parent->kobj, class_name);
}
- error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device");
- if (error)
- goto out;
- error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name);
- if (error)
- sysfs_remove_link(&dev->kobj, "device");
+ if (new_parent) {
+ error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
+ "device");
+ if (error)
+ goto out;
+ error = sysfs_create_link(&new_parent->kobj, &dev->kobj,
+ class_name);
+ if (error)
+ sysfs_remove_link(&dev->kobj, "device");
+ }
+ else
+ error = 0;
out:
kfree(class_name);
return error;
@@ -993,29 +1057,28 @@ out:
/**
* device_move - moves a device to a new parent
* @dev: the pointer to the struct device to be moved
- * @new_parent: the new parent of the device
+ * @new_parent: the new parent of the device (can by NULL)
*/
int device_move(struct device *dev, struct device *new_parent)
{
int error;
struct device *old_parent;
+ struct kobject *new_parent_kobj;
dev = get_device(dev);
if (!dev)
return -EINVAL;
- if (!device_is_registered(dev)) {
- error = -EINVAL;
- goto out;
- }
new_parent = get_device(new_parent);
- if (!new_parent) {
- error = -EINVAL;
+ new_parent_kobj = get_device_parent (dev, new_parent);
+ if (IS_ERR(new_parent_kobj)) {
+ error = PTR_ERR(new_parent_kobj);
+ put_device(new_parent);
goto out;
}
pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
- new_parent->bus_id);
- error = kobject_move(&dev->kobj, &new_parent->kobj);
+ new_parent ? new_parent->bus_id : "<NULL>");
+ error = kobject_move(&dev->kobj, new_parent_kobj);
if (error) {
put_device(new_parent);
goto out;
@@ -1024,7 +1087,8 @@ int device_move(struct device *dev, struct device *new_parent)
dev->parent = new_parent;
if (old_parent)
klist_remove(&dev->knode_parent);
- klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
+ if (new_parent)
+ klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
if (!dev->class)
goto out_put;
error = device_move_class_links(dev, old_parent, new_parent);
@@ -1032,7 +1096,8 @@ int device_move(struct device *dev, struct device *new_parent)
/* We ignore errors on cleanup since we're hosed anyway... */
device_move_class_links(dev, new_parent, old_parent);
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
- klist_remove(&dev->knode_parent);
+ if (new_parent)
+ klist_remove(&dev->knode_parent);
if (old_parent)
klist_add_tail(&dev->knode_parent,
&old_parent->klist_children);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 510e7884975..6a48824e43f 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -86,8 +86,12 @@ static void driver_sysfs_remove(struct device *dev)
*/
int device_bind_driver(struct device *dev)
{
- driver_bound(dev);
- return driver_sysfs_add(dev);
+ int ret;
+
+ ret = driver_sysfs_add(dev);
+ if (!ret)
+ driver_bound(dev);
+ return ret;
}
struct stupid_thread_structure {
@@ -108,6 +112,7 @@ static int really_probe(void *void_data)
atomic_inc(&probe_count);
pr_debug("%s: Probing driver %s with device %s\n",
drv->bus->name, drv->name, dev->bus_id);
+ WARN_ON(!list_empty(&dev->devres_head));
dev->driver = drv;
if (driver_sysfs_add(dev)) {
@@ -133,21 +138,21 @@ static int really_probe(void *void_data)
goto done;
probe_failed:
+ devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
- if (ret == -ENODEV || ret == -ENXIO) {
- /* Driver matched, but didn't support device
- * or device not found.
- * Not an error; keep going.
- */
- ret = 0;
- } else {
+ if (ret != -ENODEV && ret != -ENXIO) {
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
drv->name, dev->bus_id, ret);
}
+ /*
+ * Ignore errors returned by ->probe so that the next driver can try
+ * its luck.
+ */
+ ret = 0;
done:
kfree(data);
atomic_dec(&probe_count);
@@ -324,6 +329,7 @@ static void __device_release_driver(struct device * dev)
dev->bus->remove(dev);
else if (drv->remove)
drv->remove(dev);
+ devres_release_all(dev);
dev->driver = NULL;
put_driver(drv);
}
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
new file mode 100644
index 00000000000..e177c9533b6
--- /dev/null
+++ b/drivers/base/devres.c
@@ -0,0 +1,644 @@
+/*
+ * drivers/base/devres.c - device resource management
+ *
+ * Copyright (c) 2006 SUSE Linux Products GmbH
+ * Copyright (c) 2006 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+
+struct devres_node {
+ struct list_head entry;
+ dr_release_t release;
+#ifdef CONFIG_DEBUG_DEVRES
+ const char *name;
+ size_t size;
+#endif
+};
+
+struct devres {
+ struct devres_node node;
+ /* -- 3 pointers */
+ unsigned long long data[]; /* guarantee ull alignment */
+};
+
+struct devres_group {
+ struct devres_node node[2];
+ void *id;
+ int color;
+ /* -- 8 pointers */
+};
+
+#ifdef CONFIG_DEBUG_DEVRES
+static int log_devres = 0;
+module_param_named(log, log_devres, int, S_IRUGO | S_IWUSR);
+
+static void set_node_dbginfo(struct devres_node *node, const char *name,
+ size_t size)
+{
+ node->name = name;
+ node->size = size;
+}
+
+static void devres_log(struct device *dev, struct devres_node *node,
+ const char *op)
+{
+ if (unlikely(log_devres))
+ dev_printk(KERN_ERR, dev, "DEVRES %3s %p %s (%lu bytes)\n",
+ op, node, node->name, (unsigned long)node->size);
+}
+#else /* CONFIG_DEBUG_DEVRES */
+#define set_node_dbginfo(node, n, s) do {} while (0)
+#define devres_log(dev, node, op) do {} while (0)
+#endif /* CONFIG_DEBUG_DEVRES */
+
+/*
+ * Release functions for devres group. These callbacks are used only
+ * for identification.
+ */
+static void group_open_release(struct device *dev, void *res)
+{
+ /* noop */
+}
+
+static void group_close_release(struct device *dev, void *res)
+{
+ /* noop */
+}
+
+static struct devres_group * node_to_group(struct devres_node *node)
+{
+ if (node->release == &group_open_release)
+ return container_of(node, struct devres_group, node[0]);
+ if (node->release == &group_close_release)
+ return container_of(node, struct devres_group, node[1]);
+ return NULL;
+}
+
+static __always_inline struct devres * alloc_dr(dr_release_t release,
+ size_t size, gfp_t gfp)
+{
+ size_t tot_size = sizeof(struct devres) + size;
+ struct devres *dr;
+
+ dr = kmalloc_track_caller(tot_size, gfp);
+ if (unlikely(!dr))
+ return NULL;
+
+ memset(dr, 0, tot_size);
+ INIT_LIST_HEAD(&dr->node.entry);
+ dr->node.release = release;
+ return dr;
+}
+
+static void add_dr(struct device *dev, struct devres_node *node)
+{
+ devres_log(dev, node, "ADD");
+ BUG_ON(!list_empty(&node->entry));
+ list_add_tail(&node->entry, &dev->devres_head);
+}
+
+/**
+ * devres_alloc - Allocate device resource data
+ * @release: Release function devres will be associated with
+ * @size: Allocation size
+ * @gfp: Allocation flags
+ *
+ * allocate devres of @size bytes. The allocated area is zeroed, then
+ * associated with @release. The returned pointer can be passed to
+ * other devres_*() functions.
+ *
+ * RETURNS:
+ * Pointer to allocated devres on success, NULL on failure.
+ */
+#ifdef CONFIG_DEBUG_DEVRES
+void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
+ const char *name)
+{
+ struct devres *dr;
+
+ dr = alloc_dr(release, size, gfp);
+ if (unlikely(!dr))
+ return NULL;
+ set_node_dbginfo(&dr->node, name, size);
+ return dr->data;
+}
+EXPORT_SYMBOL_GPL(__devres_alloc);
+#else
+void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
+{
+ struct devres *dr;
+
+ dr = alloc_dr(release, size, gfp);
+ if (unlikely(!dr))
+ return NULL;
+ return dr->data;
+}
+EXPORT_SYMBOL_GPL(devres_alloc);
+#endif
+
+/**
+ * devres_free - Free device resource data
+ * @res: Pointer to devres data to free
+ *
+ * Free devres created with devres_alloc().
+ */
+void devres_free(void *res)
+{
+ if (res) {
+ struct devres *dr = container_of(res, struct devres, data);
+
+ BUG_ON(!list_empty(&dr->node.entry));
+ kfree(dr);
+ }
+}
+EXPORT_SYMBOL_GPL(devres_free);
+
+/**
+ * devres_add - Register device resource
+ * @dev: Device to add resource to
+ * @res: Resource to register
+ *
+ * Register devres @res to @dev. @res should have been allocated
+ * using devres_alloc(). On driver detach, the associated release
+ * function will be invoked and devres will be freed automatically.
+ */
+void devres_add(struct device *dev, void *res)
+{
+ struct devres *dr = container_of(res, struct devres, data);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ add_dr(dev, &dr->node);
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+}
+EXPORT_SYMBOL_GPL(devres_add);
+
+static struct devres *find_dr(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ struct devres_node *node;
+
+ list_for_each_entry_reverse(node, &dev->devres_head, entry) {
+ struct devres *dr = container_of(node, struct devres, node);
+
+ if (node->release != release)
+ continue;
+ if (match && !match(dev, dr->data, match_data))
+ continue;
+ return dr;
+ }
+
+ return NULL;
+}
+
+/**
+ * devres_find - Find device resource
+ * @dev: Device to lookup resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev which is associated with @release
+ * and for which @match returns 1. If @match is NULL, it's considered
+ * to match all.
+ *
+ * RETURNS:
+ * Pointer to found devres, NULL if not found.
+ */
+void * devres_find(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ struct devres *dr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ dr = find_dr(dev, release, match, match_data);
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+
+ if (dr)
+ return dr->data;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(devres_find);
+
+/**
+ * devres_get - Find devres, if non-existent, add one atomically
+ * @dev: Device to lookup or add devres for
+ * @new_res: Pointer to new initialized devres to add if not found
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev which has the same release function
+ * as @new_res and for which @match return 1. If found, @new_res is
+ * freed; otherwise, @new_res is added atomically.
+ *
+ * RETURNS:
+ * Pointer to found or added devres.
+ */
+void * devres_get(struct device *dev, void *new_res,
+ dr_match_t match, void *match_data)
+{
+ struct devres *new_dr = container_of(new_res, struct devres, data);
+ struct devres *dr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ dr = find_dr(dev, new_dr->node.release, match, match_data);
+ if (!dr) {
+ add_dr(dev, &new_dr->node);
+ dr = new_dr;
+ new_dr = NULL;
+ }
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+ devres_free(new_dr);
+
+ return dr->data;
+}
+EXPORT_SYMBOL_GPL(devres_get);
+
+/**
+ * devres_remove - Find a device resource and remove it
+ * @dev: Device to find resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev associated with @release and for
+ * which @match returns 1. If @match is NULL, it's considered to
+ * match all. If found, the resource is removed atomically and
+ * returned.
+ *
+ * RETURNS:
+ * Pointer to removed devres on success, NULL if not found.
+ */
+void * devres_remove(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ struct devres *dr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ dr = find_dr(dev, release, match, match_data);
+ if (dr) {
+ list_del_init(&dr->node.entry);
+ devres_log(dev, &dr->node, "REM");
+ }
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+
+ if (dr)
+ return dr->data;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(devres_remove);
+
+/**
+ * devres_destroy - Find a device resource and destroy it
+ * @dev: Device to find resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev associated with @release and for
+ * which @match returns 1. If @match is NULL, it's considered to
+ * match all. If found, the resource is removed atomically and freed.
+ *
+ * RETURNS:
+ * 0 if devres is found and freed, -ENOENT if not found.
+ */
+int devres_destroy(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ void *res;
+
+ res = devres_remove(dev, release, match, match_data);
+ if (unlikely(!res))
+ return -ENOENT;
+
+ devres_free(res);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devres_destroy);
+
+static int remove_nodes(struct device *dev,
+ struct list_head *first, struct list_head *end,
+ struct list_head *todo)
+{
+ int cnt = 0, nr_groups = 0;
+ struct list_head *cur;
+
+ /* First pass - move normal devres entries to @todo and clear
+ * devres_group colors.
+ */
+ cur = first;
+ while (cur != end) {
+ struct devres_node *node;
+ struct devres_group *grp;
+
+ node = list_entry(cur, struct devres_node, entry);
+ cur = cur->next;
+
+ grp = node_to_group(node);
+ if (grp) {
+ /* clear color of group markers in the first pass */
+ grp->color = 0;
+ nr_groups++;
+ } else {
+ /* regular devres entry */
+ if (&node->entry == first)
+ first = first->next;
+ list_move_tail(&node->entry, todo);
+ cnt++;
+ }
+ }
+
+ if (!nr_groups)
+ return cnt;
+
+ /* Second pass - Scan groups and color them. A group gets
+ * color value of two iff the group is wholly contained in
+ * [cur, end). That is, for a closed group, both opening and
+ * closing markers should be in the range, while just the
+ * opening marker is enough for an open group.
+ */
+ cur = first;
+ while (cur != end) {
+ struct devres_node *node;
+ struct devres_group *grp;
+
+ node = list_entry(cur, struct devres_node, entry);
+ cur = cur->next;
+
+ grp = node_to_group(node);
+ BUG_ON(!grp || list_empty(&grp->node[0].entry));
+
+ grp->color++;
+ if (list_empty(&grp->node[1].entry))
+ grp->color++;
+
+ BUG_ON(grp->color <= 0 || grp->color > 2);
+ if (grp->color == 2) {
+ /* No need to update cur or end. The removed
+ * nodes are always before both.
+ */
+ list_move_tail(&grp->node[0].entry, todo);
+ list_del_init(&grp->node[1].entry);
+ }
+ }
+
+ return cnt;
+}
+
+static int release_nodes(struct device *dev, struct list_head *first,
+ struct list_head *end, unsigned long flags)
+{
+ LIST_HEAD(todo);
+ int cnt;
+ struct devres *dr, *tmp;
+
+ cnt = remove_nodes(dev, first, end, &todo);
+
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+
+ /* Release. Note that both devres and devres_group are
+ * handled as devres in the following loop. This is safe.
+ */
+ list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) {
+ devres_log(dev, &dr->node, "REL");
+ dr->node.release(dev, dr->data);
+ kfree(dr);
+ }
+
+ return cnt;
+}
+
+/**
+ * devres_release_all - Release all resources
+ * @dev: Device to release resources for
+ *
+ * Release all resources associated with @dev. This function is
+ * called on driver detach.
+ */
+int devres_release_all(struct device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ return release_nodes(dev, dev->devres_head.next, &dev->devres_head,
+ flags);
+}
+
+/**
+ * devres_open_group - Open a new devres group
+ * @dev: Device to open devres group for
+ * @id: Separator ID
+ * @gfp: Allocation flags
+ *
+ * Open a new devres group for @dev with @id. For @id, using a
+ * pointer to an object which won't be used for another group is
+ * recommended. If @id is NULL, address-wise unique ID is created.
+ *
+ * RETURNS:
+ * ID of the new group, NULL on failure.
+ */
+void * devres_open_group(struct device *dev, void *id, gfp_t gfp)
+{
+ struct devres_group *grp;
+ unsigned long flags;
+
+ grp = kmalloc(sizeof(*grp), gfp);
+ if (unlikely(!grp))
+ return NULL;
+
+ grp->node[0].release = &group_open_release;
+ grp->node[1].release = &group_close_release;
+ INIT_LIST_HEAD(&grp->node[0].entry);
+ INIT_LIST_HEAD(&grp->node[1].entry);
+ set_node_dbginfo(&grp->node[0], "grp<", 0);
+ set_node_dbginfo(&grp->node[1], "grp>", 0);
+ grp->id = grp;
+ if (id)
+ grp->id = id;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ add_dr(dev, &grp->node[0]);
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+ return grp->id;
+}
+EXPORT_SYMBOL_GPL(devres_open_group);
+
+/* Find devres group with ID @id. If @id is NULL, look for the latest. */
+static struct devres_group * find_group(struct device *dev, void *id)
+{
+ struct devres_node *node;
+
+ list_for_each_entry_reverse(node, &dev->devres_head, entry) {
+ struct devres_group *grp;
+
+ if (node->release != &group_open_release)
+ continue;
+
+ grp = container_of(node, struct devres_group, node[0]);
+
+ if (id) {
+ if (grp->id == id)
+ return grp;
+ } else if (list_empty(&grp->node[1].entry))
+ return grp;
+ }
+
+ return NULL;
+}
+
+/**
+ * devres_close_group - Close a devres group
+ * @dev: Device to close devres group for
+ * @id: ID of target group, can be NULL
+ *
+ * Close the group identified by @id. If @id is NULL, the latest open
+ * group is selected.
+ */
+void devres_close_group(struct device *dev, void *id)
+{
+ struct devres_group *grp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+
+ grp = find_group(dev, id);
+ if (grp)
+ add_dr(dev, &grp->node[1]);
+ else
+ WARN_ON(1);
+
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+}
+EXPORT_SYMBOL_GPL(devres_close_group);
+
+/**
+ * devres_remove_group - Remove a devres group
+ * @dev: Device to remove group for
+ * @id: ID of target group, can be NULL
+ *
+ * Remove the group identified by @id. If @id is NULL, the latest
+ * open group is selected. Note that removing a group doesn't affect
+ * any other resources.
+ */
+void devres_remove_group(struct device *dev, void *id)
+{
+ struct devres_group *grp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+
+ grp = find_group(dev, id);
+ if (grp) {
+ list_del_init(&grp->node[0].entry);
+ list_del_init(&grp->node[1].entry);
+ devres_log(dev, &grp->node[0], "REM");
+ } else
+ WARN_ON(1);
+
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+
+ kfree(grp);
+}
+EXPORT_SYMBOL_GPL(devres_remove_group);
+
+/**
+ * devres_release_group - Release resources in a devres group
+ * @dev: Device to release group for
+ * @id: ID of target group, can be NULL
+ *
+ * Release all resources in the group identified by @id. If @id is
+ * NULL, the latest open group is selected. The selected group and
+ * groups properly nested inside the selected group are removed.
+ *
+ * RETURNS:
+ * The number of released non-group resources.
+ */
+int devres_release_group(struct device *dev, void *id)
+{
+ struct devres_group *grp;
+ unsigned long flags;
+ int cnt = 0;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+
+ grp = find_group(dev, id);
+ if (grp) {
+ struct list_head *first = &grp->node[0].entry;
+ struct list_head *end = &dev->devres_head;
+
+ if (!list_empty(&grp->node[1].entry))
+ end = grp->node[1].entry.next;
+
+ cnt = release_nodes(dev, first, end, flags);
+ } else {
+ WARN_ON(1);
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+ }
+
+ return cnt;
+}
+EXPORT_SYMBOL_GPL(devres_release_group);
+
+/*
+ * Managed kzalloc/kfree
+ */
+static void devm_kzalloc_release(struct device *dev, void *res)
+{
+ /* noop */
+}
+
+static int devm_kzalloc_match(struct device *dev, void *res, void *data)
+{
+ return res == data;
+}
+
+/**
+ * devm_kzalloc - Managed kzalloc
+ * @dev: Device to allocate memory for
+ * @size: Allocation size
+ * @gfp: Allocation gfp flags
+ *
+ * Managed kzalloc. Memory allocated with this function is
+ * automatically freed on driver detach. Like all other devres
+ * resources, guaranteed alignment is unsigned long long.
+ *
+ * RETURNS:
+ * Pointer to allocated memory on success, NULL on failure.
+ */
+void * devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
+{
+ struct devres *dr;
+
+ /* use raw alloc_dr for kmalloc caller tracing */
+ dr = alloc_dr(devm_kzalloc_release, size, gfp);
+ if (unlikely(!dr))
+ return NULL;
+
+ set_node_dbginfo(&dr->node, "devm_kzalloc_release", size);
+ devres_add(dev, dr->data);
+ return dr->data;
+}
+EXPORT_SYMBOL_GPL(devm_kzalloc);
+
+/**
+ * devm_kfree - Managed kfree
+ * @dev: Device this memory belongs to
+ * @p: Memory to free
+ *
+ * Free memory allocated with dev_kzalloc().
+ */
+void devm_kfree(struct device *dev, void *p)
+{
+ int rc;
+
+ rc = devres_destroy(dev, devm_kzalloc_release, devm_kzalloc_match, p);
+ WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_kfree);
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
new file mode 100644
index 00000000000..ca9186f70a6
--- /dev/null
+++ b/drivers/base/dma-mapping.c
@@ -0,0 +1,218 @@
+/*
+ * drivers/base/dma-mapping.c - arch-independent dma-mapping routines
+ *
+ * Copyright (c) 2006 SUSE Linux Products GmbH
+ * Copyright (c) 2006 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/dma-mapping.h>
+
+/*
+ * Managed DMA API
+ */
+struct dma_devres {
+ size_t size;
+ void *vaddr;
+ dma_addr_t dma_handle;
+};
+
+static void dmam_coherent_release(struct device *dev, void *res)
+{
+ struct dma_devres *this = res;
+
+ dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle);
+}
+
+static void dmam_noncoherent_release(struct device *dev, void *res)
+{
+ struct dma_devres *this = res;
+
+ dma_free_noncoherent(dev, this->size, this->vaddr, this->dma_handle);
+}
+
+static int dmam_match(struct device *dev, void *res, void *match_data)
+{
+ struct dma_devres *this = res, *match = match_data;
+
+ if (this->vaddr == match->vaddr) {
+ WARN_ON(this->size != match->size ||
+ this->dma_handle != match->dma_handle);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * dmam_alloc_coherent - Managed dma_alloc_coherent()
+ * @dev: Device to allocate coherent memory for
+ * @size: Size of allocation
+ * @dma_handle: Out argument for allocated DMA handle
+ * @gfp: Allocation flags
+ *
+ * Managed dma_alloc_coherent(). Memory allocated using this function
+ * will be automatically released on driver detach.
+ *
+ * RETURNS:
+ * Pointer to allocated memory on success, NULL on failure.
+ */
+void * dmam_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
+{
+ struct dma_devres *dr;
+ void *vaddr;
+
+ dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp);
+ if (!dr)
+ return NULL;
+
+ vaddr = dma_alloc_coherent(dev, size, dma_handle, gfp);
+ if (!vaddr) {
+ devres_free(dr);
+ return NULL;
+ }
+
+ dr->vaddr = vaddr;
+ dr->dma_handle = *dma_handle;
+ dr->size = size;
+
+ devres_add(dev, dr);
+
+ return vaddr;
+}
+EXPORT_SYMBOL(dmam_alloc_coherent);
+
+/**
+ * dmam_free_coherent - Managed dma_free_coherent()
+ * @dev: Device to free coherent memory for
+ * @size: Size of allocation
+ * @vaddr: Virtual address of the memory to free
+ * @dma_handle: DMA handle of the memory to free
+ *
+ * Managed dma_free_coherent().
+ */
+void dmam_free_coherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle)
+{
+ struct dma_devres match_data = { size, vaddr, dma_handle };
+
+ dma_free_coherent(dev, size, vaddr, dma_handle);
+ WARN_ON(devres_destroy(dev, dmam_coherent_release, dmam_match,
+ &match_data));
+}
+EXPORT_SYMBOL(dmam_free_coherent);
+
+/**
+ * dmam_alloc_non_coherent - Managed dma_alloc_non_coherent()
+ * @dev: Device to allocate non_coherent memory for
+ * @size: Size of allocation
+ * @dma_handle: Out argument for allocated DMA handle
+ * @gfp: Allocation flags
+ *
+ * Managed dma_alloc_non_coherent(). Memory allocated using this
+ * function will be automatically released on driver detach.
+ *
+ * RETURNS:
+ * Pointer to allocated memory on success, NULL on failure.
+ */
+void *dmam_alloc_noncoherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
+{
+ struct dma_devres *dr;
+ void *vaddr;
+
+ dr = devres_alloc(dmam_noncoherent_release, sizeof(*dr), gfp);
+ if (!dr)
+ return NULL;
+
+ vaddr = dma_alloc_noncoherent(dev, size, dma_handle, gfp);
+ if (!vaddr) {
+ devres_free(dr);
+ return NULL;
+ }
+
+ dr->vaddr = vaddr;
+ dr->dma_handle = *dma_handle;
+ dr->size = size;
+
+ devres_add(dev, dr);
+
+ return vaddr;
+}
+EXPORT_SYMBOL(dmam_alloc_noncoherent);
+
+/**
+ * dmam_free_coherent - Managed dma_free_noncoherent()
+ * @dev: Device to free noncoherent memory for
+ * @size: Size of allocation
+ * @vaddr: Virtual address of the memory to free
+ * @dma_handle: DMA handle of the memory to free
+ *
+ * Managed dma_free_noncoherent().
+ */
+void dmam_free_noncoherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle)
+{
+ struct dma_devres match_data = { size, vaddr, dma_handle };
+
+ dma_free_noncoherent(dev, size, vaddr, dma_handle);
+ WARN_ON(!devres_destroy(dev, dmam_noncoherent_release, dmam_match,
+ &match_data));
+}
+EXPORT_SYMBOL(dmam_free_noncoherent);
+
+#ifdef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
+
+static void dmam_coherent_decl_release(struct device *dev, void *res)
+{
+ dma_release_declared_memory(dev);
+}
+
+/**
+ * dmam_declare_coherent_memory - Managed dma_declare_coherent_memory()
+ * @dev: Device to declare coherent memory for
+ * @bus_addr: Bus address of coherent memory to be declared
+ * @device_addr: Device address of coherent memory to be declared
+ * @size: Size of coherent memory to be declared
+ * @flags: Flags
+ *
+ * Managed dma_declare_coherent_memory().
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int dmam_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
+ dma_addr_t device_addr, size_t size, int flags)
+{
+ void *res;
+ int rc;
+
+ res = devres_alloc(dmam_coherent_decl_release, 0, GFP_KERNEL);
+ if (!res)
+ return -ENOMEM;
+
+ rc = dma_declare_coherent_memory(dev, bus_addr, device_addr, size,
+ flags);
+ if (rc == 0)
+ devres_add(dev, res);
+ else
+ devres_free(res);
+
+ return rc;
+}
+EXPORT_SYMBOL(dmam_declare_coherent_memory);
+
+/**
+ * dmam_release_declared_memory - Managed dma_release_declared_memory().
+ * @dev: Device to release declared coherent memory for
+ *
+ * Managed dmam_release_declared_memory().
+ */
+void dmam_release_declared_memory(struct device *dev)
+{
+ WARN_ON(devres_destroy(dev, dmam_coherent_decl_release, NULL, NULL));
+}
+EXPORT_SYMBOL(dmam_release_declared_memory);
+
+#endif
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
index dbe0735f8c9..cd467c9f33b 100644
--- a/drivers/base/dmapool.c
+++ b/drivers/base/dmapool.c
@@ -173,7 +173,7 @@ pool_alloc_page (struct dma_pool *pool, gfp_t mem_flags)
mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
mapsize *= sizeof (long);
- page = (struct dma_page *) kmalloc (mapsize + sizeof *page, mem_flags);
+ page = kmalloc(mapsize + sizeof *page, mem_flags);
if (!page)
return NULL;
page->vaddr = dma_alloc_coherent (pool->dev,
@@ -415,8 +415,67 @@ dma_pool_free (struct dma_pool *pool, void *vaddr, dma_addr_t dma)
spin_unlock_irqrestore (&pool->lock, flags);
}
+/*
+ * Managed DMA pool
+ */
+static void dmam_pool_release(struct device *dev, void *res)
+{
+ struct dma_pool *pool = *(struct dma_pool **)res;
+
+ dma_pool_destroy(pool);
+}
+
+static int dmam_pool_match(struct device *dev, void *res, void *match_data)
+{
+ return *(struct dma_pool **)res == match_data;
+}
+
+/**
+ * dmam_pool_create - Managed dma_pool_create()
+ * @name: name of pool, for diagnostics
+ * @dev: device that will be doing the DMA
+ * @size: size of the blocks in this pool.
+ * @align: alignment requirement for blocks; must be a power of two
+ * @allocation: returned blocks won't cross this boundary (or zero)
+ *
+ * Managed dma_pool_create(). DMA pool created with this function is
+ * automatically destroyed on driver detach.
+ */
+struct dma_pool *dmam_pool_create(const char *name, struct device *dev,
+ size_t size, size_t align, size_t allocation)
+{
+ struct dma_pool **ptr, *pool;
+
+ ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ pool = *ptr = dma_pool_create(name, dev, size, align, allocation);
+ if (pool)
+ devres_add(dev, ptr);
+ else
+ devres_free(ptr);
+
+ return pool;
+}
+
+/**
+ * dmam_pool_destroy - Managed dma_pool_destroy()
+ * @pool: dma pool that will be destroyed
+ *
+ * Managed dma_pool_destroy().
+ */
+void dmam_pool_destroy(struct dma_pool *pool)
+{
+ struct device *dev = pool->dev;
+
+ dma_pool_destroy(pool);
+ WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool));
+}
EXPORT_SYMBOL (dma_pool_create);
EXPORT_SYMBOL (dma_pool_destroy);
EXPORT_SYMBOL (dma_pool_alloc);
EXPORT_SYMBOL (dma_pool_free);
+EXPORT_SYMBOL (dmam_pool_create);
+EXPORT_SYMBOL (dmam_pool_destroy);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 4bad2870c48..c0a979a5074 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -35,7 +35,7 @@ enum {
FW_STATUS_READY_NOHOTPLUG,
};
-static int loading_timeout = 10; /* In seconds */
+static int loading_timeout = 60; /* In seconds */
/* fw_lock could be moved to 'struct firmware_priv' but since it is just
* guarding for corner cases a global lock should be OK */
@@ -127,6 +127,7 @@ static ssize_t firmware_loading_show(struct device *dev,
/**
* firmware_loading_store - set value in the 'loading' control file
* @dev: device pointer
+ * @attr: device attribute pointer
* @buf: buffer to scan for loading control value
* @count: number of bytes in @buf
*
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index d1df4a08792..30480f6f2af 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -212,7 +212,7 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources);
* pointer. The memory associated with the platform data will be freed
* when the platform device is released.
*/
-int platform_device_add_data(struct platform_device *pdev, void *data, size_t size)
+int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size)
{
void *d;
@@ -473,7 +473,7 @@ EXPORT_SYMBOL_GPL(platform_driver_unregister);
* Returns zero if the driver registered and bound to a device, else returns
* a negative error code and with the driver not registered.
*/
-int platform_driver_probe(struct platform_driver *drv,
+int __init_or_module platform_driver_probe(struct platform_driver *drv,
int (*probe)(struct platform_device *))
{
int retval, code;
@@ -611,8 +611,15 @@ EXPORT_SYMBOL_GPL(platform_bus_type);
int __init platform_bus_init(void)
{
- device_register(&platform_bus);
- return bus_register(&platform_bus_type);
+ int error;
+
+ error = device_register(&platform_bus);
+ if (error)
+ return error;
+ error = bus_register(&platform_bus_type);
+ if (error)
+ device_unregister(&platform_bus);
+ return error;
}
#ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 85072446d77..58c1debf86f 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -28,13 +28,6 @@ config ATARI_FLOPPY
tristate "Atari floppy support"
depends on ATARI
-config BLK_DEV_SWIM_IOP
- bool "Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)"
- depends on MAC && EXPERIMENTAL && BROKEN
- help
- Say Y here to support the SWIM (Super Woz Integrated Machine) IOP
- floppy controller on the Macintosh IIfx and Quadra 900/950.
-
config MAC_FLOPPY
tristate "Support for PowerMac floppy"
depends on PPC_PMAC && !PPC_PMAC64
@@ -431,14 +424,18 @@ config CDROM_PKTCDVD
tristate "Packet writing on CD/DVD media"
depends on !UML
help
- If you have a CDROM drive that supports packet writing, say Y to
- include preliminary support. It should work with any MMC/Mt Fuji
- compliant ATAPI or SCSI drive, which is just about any newer CD
- writer.
+ If you have a CDROM/DVD drive that supports packet writing, say
+ Y to include support. It should work with any MMC/Mt Fuji
+ compliant ATAPI or SCSI drive, which is just about any newer
+ DVD/CD writer.
- Currently only writing to CD-RW, DVD-RW and DVD+RW discs is possible.
+ Currently only writing to CD-RW, DVD-RW, DVD+RW and DVDRAM discs
+ is possible.
DVD-RW disks must be in restricted overwrite mode.
+ See the file <file:Documentation/cdrom/packet-writing.txt>
+ for further information on the use of this driver.
+
To compile this driver as a module, choose M here: the
module will be called pktcdvd.
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 410f259a803..dd88e33c1eb 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_MAC_FLOPPY) += swim3.o
obj-$(CONFIG_BLK_DEV_FD) += floppy.o
obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o
obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o
-obj-$(CONFIG_BLK_DEV_SWIM_IOP) += swim_iop.o
obj-$(CONFIG_ATARI_ACSI) += acsi.o
obj-$(CONFIG_ATARI_SLM) += acsi_slm.o
obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index 8e41c87b026..e04be94d195 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -363,7 +363,7 @@ static ssize_t slm_read( struct file *file, char *buf, size_t count,
loff_t *ppos )
{
- struct inode *node = file->f_dentry->d_inode;
+ struct inode *node = file->f_path.dentry->d_inode;
unsigned long page;
int length;
int end;
@@ -618,7 +618,7 @@ static ssize_t slm_write( struct file *file, const char *buf, size_t count,
loff_t *ppos )
{
- struct inode *node = file->f_dentry->d_inode;
+ struct inode *node = file->f_path.dentry->d_inode;
int device = iminor(node);
int n, filled, w, h;
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 97f7f535f41..bb022ed4a86 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -30,8 +30,6 @@ new_skb(ulong len)
skb->nh.raw = skb->mac.raw = skb->data;
skb->protocol = __constant_htons(ETH_P_AOE);
skb->priority = 0;
- skb_put(skb, len);
- memset(skb->head, 0, len);
skb->next = skb->prev = NULL;
/* tell the network layer not to perform IP checksums
@@ -122,8 +120,8 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
skb = f->skb;
h = (struct aoe_hdr *) skb->mac.raw;
ah = (struct aoe_atahdr *) (h+1);
- skb->len = sizeof *h + sizeof *ah;
- memset(h, 0, ETH_ZLEN);
+ skb_put(skb, sizeof *h + sizeof *ah);
+ memset(h, 0, skb->len);
f->tag = aoehdr_atainit(d, h);
f->waited = 0;
f->buf = buf;
@@ -149,7 +147,6 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
skb->len += bcnt;
skb->data_len = bcnt;
} else {
- skb->len = ETH_ZLEN;
writebit = 0;
}
@@ -206,6 +203,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
printk(KERN_INFO "aoe: skb alloc failure\n");
continue;
}
+ skb_put(skb, sizeof *h + sizeof *ch);
skb->dev = ifp;
if (sl_tail == NULL)
sl_tail = skb;
@@ -243,6 +241,7 @@ freeframe(struct aoedev *d)
continue;
if (atomic_read(&skb_shinfo(f->skb)->dataref) == 1) {
skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0;
+ skb_trim(f->skb, 0);
return f;
}
n++;
@@ -698,8 +697,8 @@ aoecmd_ata_id(struct aoedev *d)
skb = f->skb;
h = (struct aoe_hdr *) skb->mac.raw;
ah = (struct aoe_atahdr *) (h+1);
- skb->len = ETH_ZLEN;
- memset(h, 0, ETH_ZLEN);
+ skb_put(skb, sizeof *h + sizeof *ah);
+ memset(h, 0, skb->len);
f->tag = aoehdr_atainit(d, h);
f->waited = 0;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 892e092afe9..05dfe357527 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -225,6 +225,8 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
#include "cciss_scsi.c" /* For SCSI tape support */
+#define RAID_UNKNOWN 6
+
#ifdef CONFIG_PROC_FS
/*
@@ -232,7 +234,6 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
*/
#define ENG_GIG 1000000000
#define ENG_GIG_FACTOR (ENG_GIG/512)
-#define RAID_UNKNOWN 6
static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
"UNKNOWN"
};
@@ -535,7 +536,7 @@ static int do_ioctl(struct file *f, unsigned cmd, unsigned long arg)
{
int ret;
lock_kernel();
- ret = cciss_ioctl(f->f_dentry->d_inode, f, cmd, arg);
+ ret = cciss_ioctl(f->f_path.dentry->d_inode, f, cmd, arg);
unlock_kernel();
return ret;
}
@@ -1039,7 +1040,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
status = -ENOMEM;
goto cleanup1;
}
- buff_size = (int *)kmalloc(MAXSGENTRIES * sizeof(int),
+ buff_size = kmalloc(MAXSGENTRIES * sizeof(int),
GFP_KERNEL);
if (!buff_size) {
status = -ENOMEM;
@@ -1907,6 +1908,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
"does not support reading geometry\n");
drv->heads = 255;
drv->sectors = 32; // Sectors per track
+ drv->raid_level = RAID_UNKNOWN;
} else {
drv->heads = inq_buff->data_byte[6];
drv->sectors = inq_buff->data_byte[7];
@@ -2491,7 +2493,7 @@ 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) ? h->cciss_read : h->cciss_write;
+ (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE;
c->Request.Timeout = 0; // Don't time out
c->Request.CDB[0] =
(rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
@@ -2837,7 +2839,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
if (err) {
printk(KERN_ERR "cciss: Cannot obtain PCI resources, "
"aborting\n");
- goto err_out_disable_pdev;
+ return err;
}
subsystem_vendor_id = pdev->subsystem_vendor;
@@ -2865,7 +2867,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
#ifdef CCISS_DEBUG
printk("address 0 = %x\n", c->paddr);
#endif /* CCISS_DEBUG */
- c->vaddr = remap_pci_mem(c->paddr, 200);
+ c->vaddr = remap_pci_mem(c->paddr, 0x250);
/* Wait for the board to become ready. (PCI hotplug needs this.)
* We poll for up to 120 secs, once per 100ms. */
@@ -3004,11 +3006,12 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
}
return 0;
- err_out_free_res:
+err_out_free_res:
+ /*
+ * Deliberately omit pci_disable_device(): it does something nasty to
+ * Smart Array controllers that pci_enable_device does not undo
+ */
pci_release_regions(pdev);
-
- err_out_disable_pdev:
- pci_disable_device(pdev);
return err;
}
@@ -3382,8 +3385,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
if (drv->queue)
blk_cleanup_queue(drv->queue);
}
+ /*
+ * Deliberately omit pci_disable_device(): it does something nasty to
+ * Smart Array controllers that pci_enable_device does not undo
+ */
pci_release_regions(pdev);
- pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
free_hba(i);
return -1;
@@ -3452,8 +3458,11 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
#ifdef CONFIG_CISS_SCSI_TAPE
kfree(hba[i]->scsi_rejects.complete);
#endif
+ /*
+ * Deliberately omit pci_disable_device(): it does something nasty to
+ * Smart Array controllers that pci_enable_device does not undo
+ */
pci_release_regions(pdev);
- pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
free_hba(i);
}
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index d5f519ebbc0..b94cd1c3213 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -1625,7 +1625,7 @@ static void start_fwbk(int ctlr)
" processing\n");
/* Command does not return anything, but idasend command needs a
buffer */
- id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
+ id_ctlr_buf = kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
if(id_ctlr_buf==NULL)
{
printk(KERN_WARNING "cpqarray: Out of memory. "
@@ -1660,14 +1660,14 @@ static void getgeometry(int ctlr)
info_p->log_drv_map = 0;
- id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
+ id_ldrive = kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
if(id_ldrive == NULL)
{
printk( KERN_ERR "cpqarray: out of memory.\n");
return;
}
- id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
+ id_ctlr_buf = kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
if(id_ctlr_buf == NULL)
{
kfree(id_ldrive);
@@ -1675,7 +1675,7 @@ static void getgeometry(int ctlr)
return;
}
- id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
+ id_lstatus_buf = kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
if(id_lstatus_buf == NULL)
{
kfree(id_ctlr_buf);
@@ -1684,7 +1684,7 @@ static void getgeometry(int ctlr)
return;
}
- sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
+ sense_config_buf = kmalloc(sizeof(config_t), GFP_KERNEL);
if(sense_config_buf == NULL)
{
kfree(id_lstatus_buf);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index beab6d2643c..6b5b6420740 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1000,7 +1000,7 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info)
if (lo->lo_state != Lo_bound)
return -ENXIO;
- error = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
+ error = vfs_getattr(file->f_path.mnt, file->f_path.dentry, &stat);
if (error)
return error;
memset(info, 0, sizeof(*info));
@@ -1287,7 +1287,7 @@ loop_get_status_compat(struct loop_device *lo,
static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
int err;
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 7bf2cfbd628..090796bef78 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -537,7 +537,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
error = -EINVAL;
file = fget(arg);
if (file) {
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (S_ISSOCK(inode->i_mode)) {
lo->file = file;
lo->sock = SOCKET_I(inode);
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index e45eaa26411..62462190e07 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2000 Jens Axboe <axboe@suse.de>
* Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com>
+ * Copyright (C) 2006 Thomas Maier <balagi@justmail.de>
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
@@ -59,6 +60,8 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/scsi.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
#include <asm/uaccess.h>
@@ -83,9 +86,424 @@
static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
static struct proc_dir_entry *pkt_proc;
static int pktdev_major;
+static int write_congestion_on = PKT_WRITE_CONGESTION_ON;
+static int write_congestion_off = PKT_WRITE_CONGESTION_OFF;
static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */
static mempool_t *psd_pool;
+static struct class *class_pktcdvd = NULL; /* /sys/class/pktcdvd */
+static struct dentry *pkt_debugfs_root = NULL; /* /debug/pktcdvd */
+
+/* forward declaration */
+static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev);
+static int pkt_remove_dev(dev_t pkt_dev);
+static int pkt_seq_show(struct seq_file *m, void *p);
+
+
+
+/*
+ * create and register a pktcdvd kernel object.
+ */
+static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd,
+ const char* name,
+ struct kobject* parent,
+ struct kobj_type* ktype)
+{
+ struct pktcdvd_kobj *p;
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return NULL;
+ kobject_set_name(&p->kobj, "%s", name);
+ p->kobj.parent = parent;
+ p->kobj.ktype = ktype;
+ p->pd = pd;
+ if (kobject_register(&p->kobj) != 0)
+ return NULL;
+ return p;
+}
+/*
+ * remove a pktcdvd kernel object.
+ */
+static void pkt_kobj_remove(struct pktcdvd_kobj *p)
+{
+ if (p)
+ kobject_unregister(&p->kobj);
+}
+/*
+ * default release function for pktcdvd kernel objects.
+ */
+static void pkt_kobj_release(struct kobject *kobj)
+{
+ kfree(to_pktcdvdkobj(kobj));
+}
+
+
+/**********************************************************
+ *
+ * sysfs interface for pktcdvd
+ * by (C) 2006 Thomas Maier <balagi@justmail.de>
+ *
+ **********************************************************/
+
+#define DEF_ATTR(_obj,_name,_mode) \
+ static struct attribute _obj = { \
+ .name = _name, .owner = THIS_MODULE, .mode = _mode }
+
+/**********************************************************
+ /sys/class/pktcdvd/pktcdvd[0-7]/
+ stat/reset
+ stat/packets_started
+ stat/packets_finished
+ stat/kb_written
+ stat/kb_read
+ stat/kb_read_gather
+ write_queue/size
+ write_queue/congestion_off
+ write_queue/congestion_on
+ **********************************************************/
+
+DEF_ATTR(kobj_pkt_attr_st1, "reset", 0200);
+DEF_ATTR(kobj_pkt_attr_st2, "packets_started", 0444);
+DEF_ATTR(kobj_pkt_attr_st3, "packets_finished", 0444);
+DEF_ATTR(kobj_pkt_attr_st4, "kb_written", 0444);
+DEF_ATTR(kobj_pkt_attr_st5, "kb_read", 0444);
+DEF_ATTR(kobj_pkt_attr_st6, "kb_read_gather", 0444);
+
+static struct attribute *kobj_pkt_attrs_stat[] = {
+ &kobj_pkt_attr_st1,
+ &kobj_pkt_attr_st2,
+ &kobj_pkt_attr_st3,
+ &kobj_pkt_attr_st4,
+ &kobj_pkt_attr_st5,
+ &kobj_pkt_attr_st6,
+ NULL
+};
+
+DEF_ATTR(kobj_pkt_attr_wq1, "size", 0444);
+DEF_ATTR(kobj_pkt_attr_wq2, "congestion_off", 0644);
+DEF_ATTR(kobj_pkt_attr_wq3, "congestion_on", 0644);
+
+static struct attribute *kobj_pkt_attrs_wqueue[] = {
+ &kobj_pkt_attr_wq1,
+ &kobj_pkt_attr_wq2,
+ &kobj_pkt_attr_wq3,
+ NULL
+};
+
+/* declares a char buffer[64] _dbuf, copies data from
+ * _b with length _l into it and ensures that _dbuf ends
+ * with a \0 character.
+ */
+#define DECLARE_BUF_AS_STRING(_dbuf, _b, _l) \
+ char _dbuf[64]; int dlen = (_l) < 0 ? 0 : (_l); \
+ if (dlen >= sizeof(_dbuf)) dlen = sizeof(_dbuf)-1; \
+ memcpy(_dbuf, _b, dlen); _dbuf[dlen] = 0
+
+static ssize_t kobj_pkt_show(struct kobject *kobj,
+ struct attribute *attr, char *data)
+{
+ struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd;
+ int n = 0;
+ int v;
+ if (strcmp(attr->name, "packets_started") == 0) {
+ n = sprintf(data, "%lu\n", pd->stats.pkt_started);
+
+ } else if (strcmp(attr->name, "packets_finished") == 0) {
+ n = sprintf(data, "%lu\n", pd->stats.pkt_ended);
+
+ } else if (strcmp(attr->name, "kb_written") == 0) {
+ n = sprintf(data, "%lu\n", pd->stats.secs_w >> 1);
+
+ } else if (strcmp(attr->name, "kb_read") == 0) {
+ n = sprintf(data, "%lu\n", pd->stats.secs_r >> 1);
+
+ } else if (strcmp(attr->name, "kb_read_gather") == 0) {
+ n = sprintf(data, "%lu\n", pd->stats.secs_rg >> 1);
+
+ } else if (strcmp(attr->name, "size") == 0) {
+ spin_lock(&pd->lock);
+ v = pd->bio_queue_size;
+ spin_unlock(&pd->lock);
+ n = sprintf(data, "%d\n", v);
+
+ } else if (strcmp(attr->name, "congestion_off") == 0) {
+ spin_lock(&pd->lock);
+ v = pd->write_congestion_off;
+ spin_unlock(&pd->lock);
+ n = sprintf(data, "%d\n", v);
+
+ } else if (strcmp(attr->name, "congestion_on") == 0) {
+ spin_lock(&pd->lock);
+ v = pd->write_congestion_on;
+ spin_unlock(&pd->lock);
+ n = sprintf(data, "%d\n", v);
+ }
+ return n;
+}
+
+static void init_write_congestion_marks(int* lo, int* hi)
+{
+ if (*hi > 0) {
+ *hi = max(*hi, 500);
+ *hi = min(*hi, 1000000);
+ if (*lo <= 0)
+ *lo = *hi - 100;
+ else {
+ *lo = min(*lo, *hi - 100);
+ *lo = max(*lo, 100);
+ }
+ } else {
+ *hi = -1;
+ *lo = -1;
+ }
+}
+
+static ssize_t kobj_pkt_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *data, size_t len)
+{
+ struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd;
+ int val;
+ DECLARE_BUF_AS_STRING(dbuf, data, len); /* ensure sscanf scans a string */
+
+ if (strcmp(attr->name, "reset") == 0 && dlen > 0) {
+ pd->stats.pkt_started = 0;
+ pd->stats.pkt_ended = 0;
+ pd->stats.secs_w = 0;
+ pd->stats.secs_rg = 0;
+ pd->stats.secs_r = 0;
+
+ } else if (strcmp(attr->name, "congestion_off") == 0
+ && sscanf(dbuf, "%d", &val) == 1) {
+ spin_lock(&pd->lock);
+ pd->write_congestion_off = val;
+ init_write_congestion_marks(&pd->write_congestion_off,
+ &pd->write_congestion_on);
+ spin_unlock(&pd->lock);
+
+ } else if (strcmp(attr->name, "congestion_on") == 0
+ && sscanf(dbuf, "%d", &val) == 1) {
+ spin_lock(&pd->lock);
+ pd->write_congestion_on = val;
+ init_write_congestion_marks(&pd->write_congestion_off,
+ &pd->write_congestion_on);
+ spin_unlock(&pd->lock);
+ }
+ return len;
+}
+
+static struct sysfs_ops kobj_pkt_ops = {
+ .show = kobj_pkt_show,
+ .store = kobj_pkt_store
+};
+static struct kobj_type kobj_pkt_type_stat = {
+ .release = pkt_kobj_release,
+ .sysfs_ops = &kobj_pkt_ops,
+ .default_attrs = kobj_pkt_attrs_stat
+};
+static struct kobj_type kobj_pkt_type_wqueue = {
+ .release = pkt_kobj_release,
+ .sysfs_ops = &kobj_pkt_ops,
+ .default_attrs = kobj_pkt_attrs_wqueue
+};
+
+static void pkt_sysfs_dev_new(struct pktcdvd_device *pd)
+{
+ if (class_pktcdvd) {
+ pd->clsdev = class_device_create(class_pktcdvd,
+ NULL, pd->pkt_dev,
+ NULL, "%s", pd->name);
+ if (IS_ERR(pd->clsdev))
+ pd->clsdev = NULL;
+ }
+ if (pd->clsdev) {
+ pd->kobj_stat = pkt_kobj_create(pd, "stat",
+ &pd->clsdev->kobj,
+ &kobj_pkt_type_stat);
+ pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue",
+ &pd->clsdev->kobj,
+ &kobj_pkt_type_wqueue);
+ }
+}
+
+static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd)
+{
+ pkt_kobj_remove(pd->kobj_stat);
+ pkt_kobj_remove(pd->kobj_wqueue);
+ if (class_pktcdvd)
+ class_device_destroy(class_pktcdvd, pd->pkt_dev);
+}
+
+
+/********************************************************************
+ /sys/class/pktcdvd/
+ add map block device
+ remove unmap packet dev
+ device_map show mappings
+ *******************************************************************/
+
+static void class_pktcdvd_release(struct class *cls)
+{
+ kfree(cls);
+}
+static ssize_t class_pktcdvd_show_map(struct class *c, char *data)
+{
+ int n = 0;
+ int idx;
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+ for (idx = 0; idx < MAX_WRITERS; idx++) {
+ struct pktcdvd_device *pd = pkt_devs[idx];
+ if (!pd)
+ continue;
+ n += sprintf(data+n, "%s %u:%u %u:%u\n",
+ pd->name,
+ MAJOR(pd->pkt_dev), MINOR(pd->pkt_dev),
+ MAJOR(pd->bdev->bd_dev),
+ MINOR(pd->bdev->bd_dev));
+ }
+ mutex_unlock(&ctl_mutex);
+ return n;
+}
+
+static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf,
+ size_t count)
+{
+ unsigned int major, minor;
+ DECLARE_BUF_AS_STRING(dbuf, buf, count);
+ if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) {
+ pkt_setup_dev(MKDEV(major, minor), NULL);
+ return count;
+ }
+ return -EINVAL;
+}
+
+static ssize_t class_pktcdvd_store_remove(struct class *c, const char *buf,
+ size_t count)
+{
+ unsigned int major, minor;
+ DECLARE_BUF_AS_STRING(dbuf, buf, count);
+ if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) {
+ pkt_remove_dev(MKDEV(major, minor));
+ return count;
+ }
+ return -EINVAL;
+}
+
+static struct class_attribute class_pktcdvd_attrs[] = {
+ __ATTR(add, 0200, NULL, class_pktcdvd_store_add),
+ __ATTR(remove, 0200, NULL, class_pktcdvd_store_remove),
+ __ATTR(device_map, 0444, class_pktcdvd_show_map, NULL),
+ __ATTR_NULL
+};
+
+
+static int pkt_sysfs_init(void)
+{
+ int ret = 0;
+
+ /*
+ * create control files in sysfs
+ * /sys/class/pktcdvd/...
+ */
+ class_pktcdvd = kzalloc(sizeof(*class_pktcdvd), GFP_KERNEL);
+ if (!class_pktcdvd)
+ return -ENOMEM;
+ class_pktcdvd->name = DRIVER_NAME;
+ class_pktcdvd->owner = THIS_MODULE;
+ class_pktcdvd->class_release = class_pktcdvd_release;
+ class_pktcdvd->class_attrs = class_pktcdvd_attrs;
+ ret = class_register(class_pktcdvd);
+ if (ret) {
+ kfree(class_pktcdvd);
+ class_pktcdvd = NULL;
+ printk(DRIVER_NAME": failed to create class pktcdvd\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void pkt_sysfs_cleanup(void)
+{
+ if (class_pktcdvd)
+ class_destroy(class_pktcdvd);
+ class_pktcdvd = NULL;
+}
+
+/********************************************************************
+ entries in debugfs
+
+ /debugfs/pktcdvd[0-7]/
+ info
+
+ *******************************************************************/
+
+static int pkt_debugfs_seq_show(struct seq_file *m, void *p)
+{
+ return pkt_seq_show(m, p);
+}
+
+static int pkt_debugfs_fops_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pkt_debugfs_seq_show, inode->i_private);
+}
+
+static struct file_operations debug_fops = {
+ .open = pkt_debugfs_fops_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static void pkt_debugfs_dev_new(struct pktcdvd_device *pd)
+{
+ if (!pkt_debugfs_root)
+ return;
+ pd->dfs_f_info = NULL;
+ pd->dfs_d_root = debugfs_create_dir(pd->name, pkt_debugfs_root);
+ if (IS_ERR(pd->dfs_d_root)) {
+ pd->dfs_d_root = NULL;
+ return;
+ }
+ pd->dfs_f_info = debugfs_create_file("info", S_IRUGO,
+ pd->dfs_d_root, pd, &debug_fops);
+ if (IS_ERR(pd->dfs_f_info)) {
+ pd->dfs_f_info = NULL;
+ return;
+ }
+}
+
+static void pkt_debugfs_dev_remove(struct pktcdvd_device *pd)
+{
+ if (!pkt_debugfs_root)
+ return;
+ if (pd->dfs_f_info)
+ debugfs_remove(pd->dfs_f_info);
+ pd->dfs_f_info = NULL;
+ if (pd->dfs_d_root)
+ debugfs_remove(pd->dfs_d_root);
+ pd->dfs_d_root = NULL;
+}
+
+static void pkt_debugfs_init(void)
+{
+ pkt_debugfs_root = debugfs_create_dir(DRIVER_NAME, NULL);
+ if (IS_ERR(pkt_debugfs_root)) {
+ pkt_debugfs_root = NULL;
+ return;
+ }
+}
+
+static void pkt_debugfs_cleanup(void)
+{
+ if (!pkt_debugfs_root)
+ return;
+ debugfs_remove(pkt_debugfs_root);
+ pkt_debugfs_root = NULL;
+}
+
+/* ----------------------------------------------------------*/
+
static void pkt_bio_finished(struct pktcdvd_device *pd)
{
@@ -347,47 +765,34 @@ static inline struct bio *pkt_get_list_first(struct bio **list_head, struct bio
*/
static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc)
{
- char sense[SCSI_SENSE_BUFFERSIZE];
- request_queue_t *q;
+ request_queue_t *q = bdev_get_queue(pd->bdev);
struct request *rq;
- DECLARE_COMPLETION_ONSTACK(wait);
- int err = 0;
+ int ret = 0;
- q = bdev_get_queue(pd->bdev);
+ rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
+ WRITE : READ, __GFP_WAIT);
+
+ if (cgc->buflen) {
+ if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT))
+ goto out;
+ }
+
+ rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
+ 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 = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? WRITE : READ,
- __GFP_WAIT);
- rq->errors = 0;
- rq->rq_disk = pd->bdev->bd_disk;
- rq->bio = NULL;
- rq->buffer = NULL;
rq->timeout = 60*HZ;
- rq->data = cgc->buffer;
- rq->data_len = cgc->buflen;
- rq->sense = sense;
- memset(sense, 0, sizeof(sense));
- rq->sense_len = 0;
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->cmd_flags |= REQ_HARDBARRIER;
if (cgc->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->end_io_data = &wait;
- rq->end_io = blk_end_sync_rq;
- elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
- generic_unplug_device(q);
- wait_for_completion(&wait);
-
- if (rq->errors)
- err = -EIO;
+ blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0);
+ ret = rq->errors;
+out:
blk_put_request(rq);
- return err;
+ return ret;
}
/*
@@ -893,6 +1298,7 @@ static int pkt_handle_queue(struct pktcdvd_device *pd)
sector_t zone = 0; /* Suppress gcc warning */
struct pkt_rb_node *node, *first_node;
struct rb_node *n;
+ int wakeup;
VPRINTK("handle_queue\n");
@@ -965,7 +1371,13 @@ try_next_bio:
pkt->write_size += bio->bi_size / CD_FRAMESIZE;
spin_unlock(&pkt->lock);
}
+ /* check write congestion marks, and if bio_queue_size is
+ below, wake up any waiters */
+ wakeup = (pd->write_congestion_on > 0
+ && pd->bio_queue_size <= pd->write_congestion_off);
spin_unlock(&pd->lock);
+ if (wakeup)
+ blk_clear_queue_congested(pd->disk->queue, WRITE);
pkt->sleep_time = max(PACKET_WAIT_TIME, 1);
pkt_set_state(pkt, PACKET_WAITING_STATE);
@@ -2178,6 +2590,23 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio)
}
spin_unlock(&pd->cdrw.active_list_lock);
+ /*
+ * Test if there is enough room left in the bio work queue
+ * (queue size >= congestion on mark).
+ * If not, wait till the work queue size is below the congestion off mark.
+ */
+ spin_lock(&pd->lock);
+ if (pd->write_congestion_on > 0
+ && pd->bio_queue_size >= pd->write_congestion_on) {
+ blk_set_queue_congested(q, WRITE);
+ do {
+ spin_unlock(&pd->lock);
+ congestion_wait(WRITE, HZ);
+ spin_lock(&pd->lock);
+ } while(pd->bio_queue_size > pd->write_congestion_off);
+ }
+ spin_unlock(&pd->lock);
+
/*
* No matching packet found. Store the bio in the work queue.
*/
@@ -2297,6 +2726,9 @@ static int pkt_seq_show(struct seq_file *m, void *p)
seq_printf(m, "\tstate:\t\t\ti:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n",
states[0], states[1], states[2], states[3], states[4], states[5]);
+ seq_printf(m, "\twrite congestion marks:\toff=%d on=%d\n",
+ pd->write_congestion_off,
+ pd->write_congestion_on);
return 0;
}
@@ -2436,36 +2868,33 @@ static struct block_device_operations pktcdvd_ops = {
/*
* Set up mapping from pktcdvd device to CD-ROM device.
*/
-static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
+static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
{
int idx;
int ret = -ENOMEM;
struct pktcdvd_device *pd;
struct gendisk *disk;
- dev_t dev = new_decode_dev(ctrl_cmd->dev);
+
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
for (idx = 0; idx < MAX_WRITERS; idx++)
if (!pkt_devs[idx])
break;
if (idx == MAX_WRITERS) {
printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS);
- return -EBUSY;
+ ret = -EBUSY;
+ goto out_mutex;
}
pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
if (!pd)
- return ret;
+ goto out_mutex;
pd->rb_pool = mempool_create_kmalloc_pool(PKT_RB_POOL_SIZE,
sizeof(struct pkt_rb_node));
if (!pd->rb_pool)
goto out_mem;
- disk = alloc_disk(1);
- if (!disk)
- goto out_mem;
- pd->disk = disk;
-
INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
INIT_LIST_HEAD(&pd->cdrw.pkt_active_list);
spin_lock_init(&pd->cdrw.active_list_lock);
@@ -2476,11 +2905,18 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
init_waitqueue_head(&pd->wqueue);
pd->bio_queue = RB_ROOT;
+ pd->write_congestion_on = write_congestion_on;
+ pd->write_congestion_off = write_congestion_off;
+
+ disk = alloc_disk(1);
+ if (!disk)
+ goto out_mem;
+ pd->disk = disk;
disk->major = pktdev_major;
disk->first_minor = idx;
disk->fops = &pktcdvd_ops;
disk->flags = GENHD_FL_REMOVABLE;
- sprintf(disk->disk_name, DRIVER_NAME"%d", idx);
+ strcpy(disk->disk_name, pd->name);
disk->private_data = pd;
disk->queue = blk_alloc_queue(GFP_KERNEL);
if (!disk->queue)
@@ -2492,8 +2928,15 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
goto out_new_dev;
add_disk(disk);
+
+ pkt_sysfs_dev_new(pd);
+ pkt_debugfs_dev_new(pd);
+
pkt_devs[idx] = pd;
- ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev);
+ if (pkt_dev)
+ *pkt_dev = pd->pkt_dev;
+
+ mutex_unlock(&ctl_mutex);
return 0;
out_new_dev:
@@ -2504,17 +2947,22 @@ out_mem:
if (pd->rb_pool)
mempool_destroy(pd->rb_pool);
kfree(pd);
+out_mutex:
+ mutex_unlock(&ctl_mutex);
+ printk(DRIVER_NAME": setup of pktcdvd device failed\n");
return ret;
}
/*
* Tear down mapping from pktcdvd device to CD-ROM device.
*/
-static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)
+static int pkt_remove_dev(dev_t pkt_dev)
{
struct pktcdvd_device *pd;
int idx;
- dev_t pkt_dev = new_decode_dev(ctrl_cmd->pkt_dev);
+ int ret = 0;
+
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
for (idx = 0; idx < MAX_WRITERS; idx++) {
pd = pkt_devs[idx];
@@ -2523,15 +2971,22 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)
}
if (idx == MAX_WRITERS) {
DPRINTK(DRIVER_NAME": dev not setup\n");
- return -ENXIO;
+ ret = -ENXIO;
+ goto out;
}
- if (pd->refcnt > 0)
- return -EBUSY;
-
+ if (pd->refcnt > 0) {
+ ret = -EBUSY;
+ goto out;
+ }
if (!IS_ERR(pd->cdrw.thread))
kthread_stop(pd->cdrw.thread);
+ pkt_devs[idx] = NULL;
+
+ pkt_debugfs_dev_remove(pd);
+ pkt_sysfs_dev_remove(pd);
+
blkdev_put(pd->bdev);
remove_proc_entry(pd->name, pkt_proc);
@@ -2541,18 +2996,24 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)
blk_cleanup_queue(pd->disk->queue);
put_disk(pd->disk);
- pkt_devs[idx] = NULL;
mempool_destroy(pd->rb_pool);
kfree(pd);
/* This is safe: open() is still holding a reference. */
module_put(THIS_MODULE);
- return 0;
+
+out:
+ mutex_unlock(&ctl_mutex);
+ return ret;
}
static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd)
{
- struct pktcdvd_device *pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index);
+ struct pktcdvd_device *pd;
+
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+ pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index);
if (pd) {
ctrl_cmd->dev = new_encode_dev(pd->bdev->bd_dev);
ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev);
@@ -2561,6 +3022,8 @@ static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd)
ctrl_cmd->pkt_dev = 0;
}
ctrl_cmd->num_devices = MAX_WRITERS;
+
+ mutex_unlock(&ctl_mutex);
}
static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -2568,6 +3031,7 @@ static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cm
void __user *argp = (void __user *)arg;
struct pkt_ctrl_command ctrl_cmd;
int ret = 0;
+ dev_t pkt_dev = 0;
if (cmd != PACKET_CTRL_CMD)
return -ENOTTY;
@@ -2579,21 +3043,16 @@ static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cm
case PKT_CTRL_CMD_SETUP:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- ret = pkt_setup_dev(&ctrl_cmd);
- mutex_unlock(&ctl_mutex);
+ ret = pkt_setup_dev(new_decode_dev(ctrl_cmd.dev), &pkt_dev);
+ ctrl_cmd.pkt_dev = new_encode_dev(pkt_dev);
break;
case PKT_CTRL_CMD_TEARDOWN:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- ret = pkt_remove_dev(&ctrl_cmd);
- mutex_unlock(&ctl_mutex);
+ ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev));
break;
case PKT_CTRL_CMD_STATUS:
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
pkt_get_status(&ctrl_cmd);
- mutex_unlock(&ctl_mutex);
break;
default:
return -ENOTTY;
@@ -2620,6 +3079,8 @@ static int __init pkt_init(void)
{
int ret;
+ mutex_init(&ctl_mutex);
+
psd_pool = mempool_create_kmalloc_pool(PSD_POOL_SIZE,
sizeof(struct packet_stacked_data));
if (!psd_pool)
@@ -2633,18 +3094,25 @@ static int __init pkt_init(void)
if (!pktdev_major)
pktdev_major = ret;
+ ret = pkt_sysfs_init();
+ if (ret)
+ goto out;
+
+ pkt_debugfs_init();
+
ret = misc_register(&pkt_misc);
if (ret) {
printk(DRIVER_NAME": Unable to register misc device\n");
- goto out;
+ goto out_misc;
}
- mutex_init(&ctl_mutex);
-
pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver);
return 0;
+out_misc:
+ pkt_debugfs_cleanup();
+ pkt_sysfs_cleanup();
out:
unregister_blkdev(pktdev_major, DRIVER_NAME);
out2:
@@ -2656,6 +3124,10 @@ static void __exit pkt_exit(void)
{
remove_proc_entry(DRIVER_NAME, proc_root_driver);
misc_deregister(&pkt_misc);
+
+ pkt_debugfs_cleanup();
+ pkt_sysfs_cleanup();
+
unregister_blkdev(pktdev_major, DRIVER_NAME);
mempool_destroy(psd_pool);
}
diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
deleted file mode 100644
index ed7b06cf3e6..00000000000
--- a/drivers/block/swim_iop.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- * Driver for the SWIM (Super Woz Integrated Machine) IOP
- * floppy controller on the Macintosh IIfx and Quadra 900/950
- *
- * Written by Joshua M. Thompson (funaho@jurai.org)
- * based on the SWIM3 driver (c) 1996 by Paul Mackerras.
- *
- * This program is free software; you can redistribute it and/or
- * modify 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.
- *
- * 1999-06-12 (jmt) - Initial implementation.
- */
-
-/*
- * -------------------
- * Theory of Operation
- * -------------------
- *
- * Since the SWIM IOP is message-driven we implement a simple request queue
- * system. One outstanding request may be queued at any given time (this is
- * an IOP limitation); only when that request has completed can a new request
- * be sent.
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/fd.h>
-#include <linux/ioctl.h>
-#include <linux/blkdev.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/mac_iop.h>
-#include <asm/swim_iop.h>
-
-#define DRIVER_VERSION "Version 0.1 (1999-06-12)"
-
-#define MAX_FLOPPIES 4
-
-enum swim_state {
- idle,
- available,
- revalidating,
- transferring,
- ejecting
-};
-
-struct floppy_state {
- enum swim_state state;
- int drive_num; /* device number */
- int secpercyl; /* disk geometry information */
- int secpertrack;
- int total_secs;
- int write_prot; /* 1 if write-protected, 0 if not, -1 dunno */
- int ref_count;
- struct timer_list timeout;
- int ejected;
- struct wait_queue *wait;
- int wanted;
- int timeout_pending;
-};
-
-struct swim_iop_req {
- int sent;
- int complete;
- __u8 command[32];
- struct floppy_state *fs;
- void (*done)(struct swim_iop_req *);
-};
-
-static struct swim_iop_req *current_req;
-static int floppy_count;
-
-static struct floppy_state floppy_states[MAX_FLOPPIES];
-static DEFINE_SPINLOCK(swim_iop_lock);
-
-#define CURRENT elv_next_request(swim_queue)
-
-static char *drive_names[7] = {
- "not installed", /* DRV_NONE */
- "unknown (1)", /* DRV_UNKNOWN */
- "a 400K drive", /* DRV_400K */
- "an 800K drive" /* DRV_800K */
- "unknown (4)", /* ???? */
- "an FDHD", /* DRV_FDHD */
- "unknown (6)", /* ???? */
- "an Apple HD20" /* DRV_HD20 */
-};
-
-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 *);
-static void swimiop_status_update(int, struct swim_drvstatus *);
-static int swimiop_eject(struct floppy_state *fs);
-
-static int floppy_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long param);
-static int floppy_open(struct inode *inode, struct file *filp);
-static int floppy_release(struct inode *inode, struct file *filp);
-static int floppy_check_change(struct gendisk *disk);
-static int floppy_revalidate(struct gendisk *disk);
-static int grab_drive(struct floppy_state *fs, enum swim_state state,
- int interruptible);
-static void release_drive(struct floppy_state *fs);
-static void set_timeout(struct floppy_state *fs, int nticks,
- void (*proc)(unsigned long));
-static void fd_request_timeout(unsigned long);
-static void do_fd_request(request_queue_t * q);
-static void start_request(struct floppy_state *fs);
-
-static struct block_device_operations floppy_fops = {
- .open = floppy_open,
- .release = floppy_release,
- .ioctl = floppy_ioctl,
- .media_changed = floppy_check_change,
- .revalidate_disk= floppy_revalidate,
-};
-
-static struct request_queue *swim_queue;
-/*
- * SWIM IOP initialization
- */
-
-int swimiop_init(void)
-{
- volatile struct swim_iop_req req;
- struct swimcmd_status *cmd = (struct swimcmd_status *) &req.command[0];
- struct swim_drvstatus *ds = &cmd->status;
- struct floppy_state *fs;
- int i;
-
- current_req = NULL;
- floppy_count = 0;
-
- if (!iop_ism_present)
- return -ENODEV;
-
- if (register_blkdev(FLOPPY_MAJOR, "fd"))
- return -EBUSY;
-
- swim_queue = blk_init_queue(do_fd_request, &swim_iop_lock);
- if (!swim_queue) {
- unregister_blkdev(FLOPPY_MAJOR, "fd");
- return -ENOMEM;
- }
-
- printk("SWIM-IOP: %s by Joshua M. Thompson (funaho@jurai.org)\n",
- DRIVER_VERSION);
-
- if (iop_listen(SWIM_IOP, SWIM_CHAN, swimiop_receive, "SWIM") != 0) {
- printk(KERN_ERR "SWIM-IOP: IOP channel already in use; can't initialize.\n");
- unregister_blkdev(FLOPPY_MAJOR, "fd");
- blk_cleanup_queue(swim_queue);
- return -EBUSY;
- }
-
- printk(KERN_ERR "SWIM_IOP: probing for installed drives.\n");
-
- for (i = 0 ; i < MAX_FLOPPIES ; i++) {
- memset(&floppy_states[i], 0, sizeof(struct floppy_state));
- fs = &floppy_states[floppy_count];
-
- swimiop_init_request(&req);
- cmd->code = CMD_STATUS;
- cmd->drive_num = i + 1;
- if (swimiop_send_request(&req) != 0) continue;
- while (!req.complete);
- if (cmd->error != 0) {
- printk(KERN_ERR "SWIM-IOP: probe on drive %d returned error %d\n", i, (uint) cmd->error);
- continue;
- }
- if (ds->installed != 0x01) continue;
- printk("SWIM-IOP: drive %d is %s (%s, %s, %s, %s)\n", i,
- drive_names[ds->info.type],
- ds->info.external? "ext" : "int",
- ds->info.scsi? "scsi" : "floppy",
- ds->info.fixed? "fixed" : "removable",
- ds->info.secondary? "secondary" : "primary");
- swimiop_status_update(floppy_count, ds);
- fs->state = idle;
-
- init_timer(&fs->timeout);
- floppy_count++;
- }
- printk("SWIM-IOP: detected %d installed drives.\n", floppy_count);
-
- for (i = 0; i < floppy_count; i++) {
- struct gendisk *disk = alloc_disk(1);
- if (!disk)
- continue;
- disk->major = FLOPPY_MAJOR;
- disk->first_minor = i;
- disk->fops = &floppy_fops;
- sprintf(disk->disk_name, "fd%d", i);
- disk->private_data = &floppy_states[i];
- disk->queue = swim_queue;
- set_capacity(disk, 2880 * 2);
- add_disk(disk);
- }
-
- return 0;
-}
-
-static void swimiop_init_request(struct swim_iop_req *req)
-{
- req->sent = 0;
- req->complete = 0;
- req->done = NULL;
-}
-
-static int swimiop_send_request(struct swim_iop_req *req)
-{
- unsigned long flags;
- int err;
-
- /* It's doubtful an interrupt routine would try to send */
- /* a SWIM request, but I'd rather play it safe here. */
-
- local_irq_save(flags);
-
- if (current_req != NULL) {
- local_irq_restore(flags);
- return -ENOMEM;
- }
-
- current_req = req;
-
- /* Interrupts should be back on for iop_send_message() */
-
- local_irq_restore(flags);
-
- err = iop_send_message(SWIM_IOP, SWIM_CHAN, (void *) req,
- sizeof(req->command), (__u8 *) &req->command[0],
- swimiop_receive);
-
- /* No race condition here; we own current_req at this point */
-
- if (err) {
- current_req = NULL;
- } else {
- req->sent = 1;
- }
- return err;
-}
-
-/*
- * Receive a SWIM message from the IOP.
- *
- * This will be called in two cases:
- *
- * 1. A message has been successfully sent to the IOP.
- * 2. An unsolicited message was received from the IOP.
- */
-
-void swimiop_receive(struct iop_msg *msg)
-{
- struct swim_iop_req *req;
- struct swimmsg_status *sm;
- struct swim_drvstatus *ds;
-
- req = current_req;
-
- switch(msg->status) {
- case IOP_MSGSTATUS_COMPLETE:
- memcpy(&req->command[0], &msg->reply[0], sizeof(req->command));
- req->complete = 1;
- if (req->done) (*req->done)(req);
- current_req = NULL;
- break;
- case IOP_MSGSTATUS_UNSOL:
- sm = (struct swimmsg_status *) &msg->message[0];
- ds = &sm->status;
- swimiop_status_update(sm->drive_num, ds);
- iop_complete_message(msg);
- break;
- }
-}
-
-static void swimiop_status_update(int drive_num, struct swim_drvstatus *ds)
-{
- struct floppy_state *fs = &floppy_states[drive_num];
-
- fs->write_prot = (ds->write_prot == 0x80);
- if ((ds->disk_in_drive != 0x01) && (ds->disk_in_drive != 0x02)) {
- fs->ejected = 1;
- } else {
- fs->ejected = 0;
- }
- switch(ds->info.type) {
- case DRV_400K:
- fs->secpercyl = 10;
- fs->secpertrack = 10;
- fs->total_secs = 800;
- break;
- case DRV_800K:
- fs->secpercyl = 20;
- fs->secpertrack = 10;
- fs->total_secs = 1600;
- break;
- case DRV_FDHD:
- fs->secpercyl = 36;
- fs->secpertrack = 18;
- fs->total_secs = 2880;
- break;
- default:
- fs->secpercyl = 0;
- fs->secpertrack = 0;
- fs->total_secs = 0;
- break;
- }
-}
-
-static int swimiop_eject(struct floppy_state *fs)
-{
- int err, n;
- struct swim_iop_req req;
- struct swimcmd_eject *cmd = (struct swimcmd_eject *) &req.command[0];
-
- err = grab_drive(fs, ejecting, 1);
- if (err) return err;
-
- swimiop_init_request(&req);
- cmd->code = CMD_EJECT;
- cmd->drive_num = fs->drive_num;
- err = swimiop_send_request(&req);
- if (err) {
- release_drive(fs);
- return err;
- }
- for (n = 2*HZ; n > 0; --n) {
- if (req.complete) break;
- if (signal_pending(current)) {
- err = -EINTR;
- break;
- }
- schedule_timeout_interruptible(1);
- }
- release_drive(fs);
- return cmd->error;
-}
-
-static struct floppy_struct floppy_type =
- { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */
-
-static int floppy_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long param)
-{
- struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
- int err;
-
- if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- switch (cmd) {
- case FDEJECT:
- if (fs->ref_count != 1)
- return -EBUSY;
- err = swimiop_eject(fs);
- return err;
- case FDGETPRM:
- if (copy_to_user((void *) param, (void *) &floppy_type,
- sizeof(struct floppy_struct)))
- return -EFAULT;
- return 0;
- }
- return -ENOTTY;
-}
-
-static int floppy_open(struct inode *inode, struct file *filp)
-{
- struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
-
- if (fs->ref_count == -1 || filp->f_flags & O_EXCL)
- return -EBUSY;
-
- if ((filp->f_flags & O_NDELAY) == 0 && (filp->f_mode & 3)) {
- check_disk_change(inode->i_bdev);
- if (fs->ejected)
- return -ENXIO;
- }
-
- if ((filp->f_mode & 2) && fs->write_prot)
- return -EROFS;
-
- if (filp->f_flags & O_EXCL)
- fs->ref_count = -1;
- else
- ++fs->ref_count;
-
- return 0;
-}
-
-static int floppy_release(struct inode *inode, struct file *filp)
-{
- struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
- if (fs->ref_count > 0)
- fs->ref_count--;
- return 0;
-}
-
-static int floppy_check_change(struct gendisk *disk)
-{
- struct floppy_state *fs = disk->private_data;
- return fs->ejected;
-}
-
-static int floppy_revalidate(struct gendisk *disk)
-{
- struct floppy_state *fs = disk->private_data;
- grab_drive(fs, revalidating, 0);
- /* yadda, yadda */
- release_drive(fs);
- return 0;
-}
-
-static void floppy_off(unsigned int nr)
-{
-}
-
-static int grab_drive(struct floppy_state *fs, enum swim_state state,
- int interruptible)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- if (fs->state != idle) {
- ++fs->wanted;
- while (fs->state != available) {
- if (interruptible && signal_pending(current)) {
- --fs->wanted;
- local_irq_restore(flags);
- return -EINTR;
- }
- interruptible_sleep_on(&fs->wait);
- }
- --fs->wanted;
- }
- fs->state = state;
- local_irq_restore(flags);
- return 0;
-}
-
-static void release_drive(struct floppy_state *fs)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- fs->state = idle;
- start_request(fs);
- local_irq_restore(flags);
-}
-
-static void set_timeout(struct floppy_state *fs, int nticks,
- void (*proc)(unsigned long))
-{
- unsigned long flags;
-
- local_irq_save(flags);
- if (fs->timeout_pending)
- del_timer(&fs->timeout);
- init_timer(&fs->timeout);
- fs->timeout.expires = jiffies + nticks;
- fs->timeout.function = proc;
- fs->timeout.data = (unsigned long) fs;
- add_timer(&fs->timeout);
- fs->timeout_pending = 1;
- local_irq_restore(flags);
-}
-
-static void do_fd_request(request_queue_t * q)
-{
- int i;
-
- for (i = 0 ; i < floppy_count ; i++) {
- start_request(&floppy_states[i]);
- }
-}
-
-static void fd_request_complete(struct swim_iop_req *req)
-{
- struct floppy_state *fs = req->fs;
- struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req->command[0];
-
- del_timer(&fs->timeout);
- fs->timeout_pending = 0;
- fs->state = idle;
- if (cmd->error) {
- printk(KERN_ERR "SWIM-IOP: error %d on read/write request.\n", cmd->error);
- end_request(CURRENT, 0);
- } else {
- CURRENT->sector += cmd->num_blocks;
- CURRENT->current_nr_sectors -= cmd->num_blocks;
- if (CURRENT->current_nr_sectors <= 0) {
- end_request(CURRENT, 1);
- return;
- }
- }
- start_request(fs);
-}
-
-static void fd_request_timeout(unsigned long data)
-{
- struct floppy_state *fs = (struct floppy_state *) data;
-
- fs->timeout_pending = 0;
- end_request(CURRENT, 0);
- fs->state = idle;
-}
-
-static void start_request(struct floppy_state *fs)
-{
- volatile struct swim_iop_req req;
- struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req.command[0];
-
- if (fs->state == idle && fs->wanted) {
- fs->state = available;
- wake_up(&fs->wait);
- return;
- }
- while (CURRENT && fs->state == idle) {
- if (CURRENT->bh && !buffer_locked(CURRENT->bh))
- panic("floppy: block not locked");
-#if 0
- 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(" errors=%d current_nr_sectors=%ld\n",
- CURRENT->errors, CURRENT->current_nr_sectors);
-#endif
-
- if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) {
- end_request(CURRENT, 0);
- continue;
- }
- if (CURRENT->current_nr_sectors == 0) {
- end_request(CURRENT, 1);
- continue;
- }
- if (fs->ejected) {
- end_request(CURRENT, 0);
- continue;
- }
-
- swimiop_init_request(&req);
- req.fs = fs;
- req.done = fd_request_complete;
-
- if (CURRENT->cmd == WRITE) {
- if (fs->write_prot) {
- end_request(CURRENT, 0);
- continue;
- }
- cmd->code = CMD_WRITE;
- } else {
- cmd->code = CMD_READ;
-
- }
- cmd->drive_num = fs->drive_num;
- cmd->buffer = CURRENT->buffer;
- cmd->first_block = CURRENT->sector;
- cmd->num_blocks = CURRENT->current_nr_sectors;
-
- if (swimiop_send_request(&req)) {
- end_request(CURRENT, 0);
- continue;
- }
-
- set_timeout(fs, HZ*CURRENT->current_nr_sectors,
- fd_request_timeout);
-
- fs->state = transferring;
- }
-}
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index e19ba4ebcd4..68592c33601 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -49,6 +49,7 @@
#include <asm/iseries/hv_lp_event.h>
#include <asm/iseries/hv_lp_config.h>
#include <asm/iseries/vio.h>
+#include <asm/firmware.h>
MODULE_DESCRIPTION("iSeries Virtual DASD");
MODULE_AUTHOR("Dave Boutcher");
@@ -769,6 +770,11 @@ static int __init viodasd_init(void)
{
int rc;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES)) {
+ rc = -ENODEV;
+ goto early_fail;
+ }
+
/* Try to open to our host lp */
if (viopath_hostLp == HvLpIndexInvalid)
vio_set_hostlp();
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index fdea58ae16b..6bdf593081d 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -117,15 +117,23 @@ static struct usb_device_id blacklist_ids[] = {
/* IBM/Lenovo ThinkPad with Broadcom chip */
{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU },
+ { USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_WRONG_SCO_MTU },
/* ANYCOM Bluetooth USB-200 and USB-250 */
{ USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET },
+ /* HP laptop with Broadcom chip */
+ { USB_DEVICE(0x03f0, 0x171d), .driver_info = HCI_WRONG_SCO_MTU },
+
+ /* Dell laptop with Broadcom chip */
+ { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_WRONG_SCO_MTU },
+
/* Microsoft Wireless Transceiver for Bluetooth 2.0 */
{ USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET },
/* Kensington Bluetooth USB adapter */
{ USB_DEVICE(0x047d, 0x105d), .driver_info = HCI_RESET },
+ { USB_DEVICE(0x047d, 0x105e), .driver_info = HCI_WRONG_SCO_MTU },
/* ISSC Bluetooth Adapter v3.1 */
{ USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET },
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 2df5cf4ec74..3105dddf59f 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -337,6 +337,12 @@ static const char *mrw_address_space[] = { "DMA", "GAA" };
/* used in the audio ioctls */
#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret
+/*
+ * Another popular OS uses 7 seconds as the hard timeout for default
+ * commands, so it is a good choice for us as well.
+ */
+#define CDROM_DEF_TIMEOUT (7 * HZ)
+
/* Not-exported routines. */
static int open_for_data(struct cdrom_device_info * cdi);
static int check_for_audio_disc(struct cdrom_device_info * cdi,
@@ -1528,7 +1534,7 @@ void init_cdrom_command(struct packet_command *cgc, void *buf, int len,
cgc->buffer = (char *) buf;
cgc->buflen = len;
cgc->data_direction = type;
- cgc->timeout = 5*HZ;
+ cgc->timeout = CDROM_DEF_TIMEOUT;
}
/* DVD handling */
@@ -1810,7 +1816,7 @@ static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s)
size = sizeof(s->disckey.value) + 4;
- if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)
+ if ((buf = kmalloc(size, GFP_KERNEL)) == NULL)
return -ENOMEM;
init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
@@ -1861,7 +1867,7 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s)
size = sizeof(s->manufact.value) + 4;
- if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)
+ if ((buf = kmalloc(size, GFP_KERNEL)) == NULL)
return -ENOMEM;
init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
@@ -2139,8 +2145,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
cdi->last_sense = s->sense_key;
}
- rq->bio = bio;
- if (blk_rq_unmap_user(rq))
+ if (blk_rq_unmap_user(bio))
ret = -EFAULT;
if (ret)
@@ -2849,7 +2854,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
/* FIXME: we need upper bound checking, too!! */
if (lba < 0)
return -EINVAL;
- cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL);
+ cgc.buffer = kmalloc(blocksize, GFP_KERNEL);
if (cgc.buffer == NULL)
return -ENOMEM;
memset(&sense, 0, sizeof(sense));
@@ -3031,7 +3036,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
int size = sizeof(dvd_struct);
if (!CDROM_CAN(CDC_DVD))
return -ENOSYS;
- if ((s = (dvd_struct *) kmalloc(size, GFP_KERNEL)) == NULL)
+ if ((s = kmalloc(size, GFP_KERNEL)) == NULL)
return -ENOMEM;
cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n");
if (copy_from_user(s, (dvd_struct __user *)arg, size)) {
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index e6d8e9edede..b6c61bbb20e 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -1420,7 +1420,7 @@ int __init cm206_init(void)
return -EIO;
}
printk(" adapter at 0x%x", cm206_base);
- cd = (struct cm206_struct *) kmalloc(size, GFP_KERNEL);
+ cd = kmalloc(size, GFP_KERNEL);
if (!cd)
goto out_base;
/* Now we have found the adaptor card, try to reset it. As we have
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index 54ca931e19e..93fbf84dcc4 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -47,6 +47,7 @@
#include <asm/iseries/hv_types.h>
#include <asm/iseries/hv_lp_event.h>
#include <asm/iseries/vio.h>
+#include <asm/firmware.h>
#define VIOCD_DEVICE "iseries/vcd"
@@ -748,6 +749,9 @@ static int __init viocd_init(void)
struct proc_dir_entry *e;
int ret = 0;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return -ENODEV;
+
if (viopath_hostLp == HvLpIndexInvalid) {
vio_set_hostlp();
/* If we don't have a host, bail out */
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 24f922f1278..d08bb4ee130 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -97,7 +97,7 @@ config SERIAL_NONSTANDARD
config COMPUTONE
tristate "Computone IntelliPort Plus serial support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
---help---
This driver supports the entire family of Intelliport II/Plus
controllers with the exception of the MicroChannel controllers and
@@ -201,9 +201,24 @@ config MOXA_SMARTIO
The module will be called mxser. If you want to do that, say M
here.
+config MOXA_SMARTIO_NEW
+ tristate "Moxa SmartIO support v. 2.0 (EXPERIMENTAL)"
+ depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
+ help
+ Say Y here if you have a Moxa SmartIO multiport serial card and/or
+ want to help develop a new version of this driver.
+
+ This is upgraded (1.9.1) driver from original Moxa drivers with
+ changes finally resulting in PCI probing.
+
+ Use at your own risk.
+
+ This driver can also be built as a module. The module will be called
+ mxser_new. If you want to do that, say M here.
+
config ISI
tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && PCI
select FW_LOADER
help
This is a driver for the Multi-Tech cards which provide several
@@ -297,7 +312,7 @@ config SPECIALIX_RTSCTS
config SX
tristate "Specialix SX (and SI) card support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
help
This is a driver for the SX and SI multiport serial cards.
Please read the file <file:Documentation/sx.txt> for details.
@@ -595,6 +610,13 @@ config HVC_RTAS
help
IBM Console device driver which makes use of RTAS
+config HVC_BEAT
+ bool "Toshiba's Beat Hypervisor Console support"
+ depends on PPC_CELLEB
+ select HVC_DRIVER
+ help
+ Toshiba's Cell Reference Set Beat Console device driver
+
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
depends on PPC_PSERIES
@@ -852,7 +874,7 @@ config SONYPI
config TANBAC_TB0219
tristate "TANBAC TB0219 base board support"
- depends TANBAC_TB022X
+ depends on TANBAC_TB022X
select GPIO_VR41XX
source "drivers/char/agp/Kconfig"
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index b1fcdab9094..ae8567cc529 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
+obj-$(CONFIG_MOXA_SMARTIO_NEW) += mxser_new.o
obj-$(CONFIG_COMPUTONE) += ip2/
obj-$(CONFIG_RISCOM8) += riscom8.o
obj-$(CONFIG_ISI) += isicom.o
@@ -44,6 +45,7 @@ obj-$(CONFIG_RIO) += rio/ generic_serial.o
obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
+obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
@@ -58,6 +60,8 @@ obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
obj-$(CONFIG_PRINTER) += lp.o
obj-$(CONFIG_TIPAR) += tipar.o
+obj-$(CONFIG_APM_EMULATION) += apm-emulation.o
+
obj-$(CONFIG_DTLK) += dtlk.o
obj-$(CONFIG_R3964) += n_r3964.o
obj-$(CONFIG_APPLICOM) += applicom.o
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index c603bf29158..a9f9c48c242 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -86,7 +86,7 @@ config AGP_NVIDIA
config AGP_SIS
tristate "SiS chipset support"
- depends on AGP
+ depends on AGP && X86
help
This option gives you AGP support for the GLX component of
X on Silicon Integrated Systems [SiS] chipsets.
@@ -103,7 +103,7 @@ config AGP_SWORKS
config AGP_VIA
tristate "VIA chipset support"
- depends on AGP
+ depends on AGP && X86
help
This option gives you AGP support for the GLX component of
X on VIA MVP3/Apollo Pro chipsets.
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 8b3317fd46c..1d59e2a5b9a 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -225,6 +225,10 @@ struct agp_bridge_data {
#define I810_GMS_DISABLE 0x00000000
#define I810_PGETBL_CTL 0x2020
#define I810_PGETBL_ENABLED 0x00000001
+#define I965_PGETBL_SIZE_MASK 0x0000000e
+#define I965_PGETBL_SIZE_512KB (0 << 1)
+#define I965_PGETBL_SIZE_256KB (1 << 1)
+#define I965_PGETBL_SIZE_128KB (2 << 1)
#define I810_DRAM_CTL 0x3000
#define I810_DRAM_ROW_0 0x00000001
#define I810_DRAM_ROW_0_SDRAM 0x00000001
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index 51d0d562d01..c85c8cadb6d 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -101,6 +101,11 @@ static int amd_create_gatt_pages(int nr_tables)
for (i = 0; i < nr_tables; i++) {
entry = kzalloc(sizeof(struct amd_page_map), GFP_KERNEL);
if (entry == NULL) {
+ while (i > 0) {
+ kfree(tables[i-1]);
+ i--;
+ }
+ kfree(tables);
retval = -ENOMEM;
break;
}
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 2f2c4efff8a..93d2209fee4 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -650,6 +650,15 @@ static struct pci_device_id agp_amd64_pci_table[] = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
+ /* VIA K8M890 / K8N890 */
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_VIA,
+ .device = PCI_DEVICE_ID_VIA_VT3336,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
/* VIA K8T890 */
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index f244c668273..9987dc2e0c3 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -41,18 +41,18 @@ static struct gatt_mask ati_generic_masks[] =
};
-typedef struct _ati_page_map {
+struct ati_page_map {
unsigned long *real;
unsigned long __iomem *remapped;
-} ati_page_map;
+};
static struct _ati_generic_private {
volatile u8 __iomem *registers;
- ati_page_map **gatt_pages;
+ struct ati_page_map **gatt_pages;
int num_tables;
} ati_generic_private;
-static int ati_create_page_map(ati_page_map *page_map)
+static int ati_create_page_map(struct ati_page_map *page_map)
{
int i, err = 0;
@@ -82,7 +82,7 @@ static int ati_create_page_map(ati_page_map *page_map)
}
-static void ati_free_page_map(ati_page_map *page_map)
+static void ati_free_page_map(struct ati_page_map *page_map)
{
unmap_page_from_agp(virt_to_page(page_map->real));
iounmap(page_map->remapped);
@@ -94,8 +94,8 @@ static void ati_free_page_map(ati_page_map *page_map)
static void ati_free_gatt_pages(void)
{
int i;
- ati_page_map **tables;
- ati_page_map *entry;
+ struct ati_page_map **tables;
+ struct ati_page_map *entry;
tables = ati_generic_private.gatt_pages;
for (i = 0; i < ati_generic_private.num_tables; i++) {
@@ -112,30 +112,30 @@ static void ati_free_gatt_pages(void)
static int ati_create_gatt_pages(int nr_tables)
{
- ati_page_map **tables;
- ati_page_map *entry;
+ struct ati_page_map **tables;
+ struct ati_page_map *entry;
int retval = 0;
int i;
- tables = kzalloc((nr_tables + 1) * sizeof(ati_page_map *),GFP_KERNEL);
+ tables = kzalloc((nr_tables + 1) * sizeof(struct ati_page_map *),GFP_KERNEL);
if (tables == NULL)
return -ENOMEM;
for (i = 0; i < nr_tables; i++) {
- entry = kzalloc(sizeof(ati_page_map), GFP_KERNEL);
+ entry = kzalloc(sizeof(struct ati_page_map), GFP_KERNEL);
if (entry == NULL) {
- while (i>0) {
- kfree (tables[i-1]);
+ while (i > 0) {
+ kfree(tables[i-1]);
i--;
}
- kfree (tables);
- tables = NULL;
+ kfree(tables);
retval = -ENOMEM;
break;
}
tables[i] = entry;
retval = ati_create_page_map(entry);
- if (retval != 0) break;
+ if (retval != 0)
+ break;
}
ati_generic_private.num_tables = nr_tables;
ati_generic_private.gatt_pages = tables;
@@ -340,7 +340,7 @@ static int ati_remove_memory(struct agp_memory * mem, off_t pg_start,
static int ati_create_gatt_table(struct agp_bridge_data *bridge)
{
struct aper_size_info_lvl2 *value;
- ati_page_map page_dir;
+ struct ati_page_map page_dir;
unsigned long addr;
int retval;
u32 temp;
@@ -400,7 +400,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge)
static int ati_free_gatt_table(struct agp_bridge_data *bridge)
{
- ati_page_map page_dir;
+ struct ati_page_map page_dir;
page_dir.real = (unsigned long *)agp_bridge->gatt_table_real;
page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table;
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 5ff457b41ef..3491d6f84bc 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -419,6 +419,31 @@ static void agp_v2_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_
*requested_mode &= ~AGP2_RESERVED_MASK;
}
+ /*
+ * Some dumb bridges are programmed to disobey the AGP2 spec.
+ * This is likely a BIOS misprogramming rather than poweron default, or
+ * it would be a lot more common.
+ * https://bugs.freedesktop.org/show_bug.cgi?id=8816
+ * AGPv2 spec 6.1.9 states:
+ * The RATE field indicates the data transfer rates supported by this
+ * device. A.G.P. devices must report all that apply.
+ * Fix them up as best we can.
+ */
+ switch (*bridge_agpstat & 7) {
+ case 4:
+ *bridge_agpstat |= (AGPSTAT2_2X | AGPSTAT2_1X);
+ printk(KERN_INFO PFX "BIOS bug. AGP bridge claims to only support x4 rate"
+ "Fixing up support for x2 & x1\n");
+ break;
+ case 2:
+ *bridge_agpstat |= AGPSTAT2_1X;
+ printk(KERN_INFO PFX "BIOS bug. AGP bridge claims to only support x2 rate"
+ "Fixing up support for x1\n");
+ break;
+ default:
+ break;
+ }
+
/* Check the speed bits make sense. Only one should be set. */
tmp = *requested_mode & 7;
switch (tmp) {
@@ -940,6 +965,9 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
if (!bridge)
return -EINVAL;
+ if (mem->page_count == 0)
+ return 0;
+
temp = bridge->current_size;
switch (bridge->driver->size_type) {
@@ -991,8 +1019,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(bridge->driver->mask_memory(bridge, mem->memory[i], mem->type), bridge->gatt_table+j);
- readl(bridge->gatt_table+j); /* PCI Posting. */
}
+ readl(bridge->gatt_table+j-1); /* PCI Posting. */
bridge->driver->tlb_flush(mem);
return 0;
@@ -1009,6 +1037,9 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
if (!bridge)
return -EINVAL;
+ if (mem->page_count == 0)
+ return 0;
+
if (type != 0 || mem->type != 0) {
/* The generic routines know nothing of memory types */
return -EINVAL;
@@ -1017,10 +1048,9 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
/* AK: bogus, should encode addresses > 4GB */
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
writel(bridge->scratch_page, bridge->gatt_table+i);
- readl(bridge->gatt_table+i); /* PCI Posting. */
}
+ readl(bridge->gatt_table+i-1); /* PCI Posting. */
- global_cache_flush();
bridge->driver->tlb_flush(mem);
return 0;
}
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 555b3a8ab49..a3011de51f7 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -207,6 +207,9 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
int i, j, num_entries;
void *temp;
+ if (mem->page_count == 0)
+ return 0;
+
temp = agp_bridge->current_size;
num_entries = A_SIZE_FIX(temp)->num_entries;
@@ -221,12 +224,16 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
if (type != 0 || mem->type != 0) {
if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) {
/* special insert */
- global_cache_flush();
+ if (!mem->is_flushed) {
+ global_cache_flush();
+ mem->is_flushed = TRUE;
+ }
+
for (i = pg_start; i < (pg_start + mem->page_count); i++) {
writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, intel_i810_private.registers+I810_PTE_BASE+(i*4));
- readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */
}
- global_cache_flush();
+ readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */
+
agp_bridge->driver->tlb_flush(mem);
return 0;
}
@@ -236,14 +243,17 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
}
insert:
- global_cache_flush();
+ if (!mem->is_flushed) {
+ global_cache_flush();
+ mem->is_flushed = TRUE;
+ }
+
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
mem->memory[i], mem->type),
intel_i810_private.registers+I810_PTE_BASE+(j*4));
- readl(intel_i810_private.registers+I810_PTE_BASE+(j*4)); /* PCI Posting. */
}
- global_cache_flush();
+ readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4)); /* PCI Posting. */
agp_bridge->driver->tlb_flush(mem);
return 0;
@@ -254,12 +264,14 @@ static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
{
int i;
+ if (mem->page_count == 0)
+ return 0;
+
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4));
- readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */
}
+ readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4));
- global_cache_flush();
agp_bridge->driver->tlb_flush(mem);
return 0;
}
@@ -370,6 +382,11 @@ static struct _intel_i830_private {
struct pci_dev *i830_dev; /* device one */
volatile u8 __iomem *registers;
volatile u32 __iomem *gtt; /* I915G */
+ /* gtt_entries is the number of gtt entries that are already mapped
+ * to stolen memory. Stolen memory is larger than the memory mapped
+ * through gtt_entries, as it includes some reserved space for the BIOS
+ * popup and for the GTT.
+ */
int gtt_entries;
} intel_i830_private;
@@ -380,14 +397,41 @@ static void intel_i830_init_gtt_entries(void)
u8 rdct;
int local = 0;
static const int ddt[4] = { 0, 16, 32, 64 };
- int size;
+ int size; /* reserved space (in kb) at the top of stolen memory */
pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
- /* We obtain the size of the GTT, which is also stored (for some
- * reason) at the top of stolen memory. Then we add 4KB to that
- * for the video BIOS popup, which is also stored in there. */
- size = agp_bridge->driver->fetch_size() + 4;
+ if (IS_I965) {
+ u32 pgetbl_ctl;
+
+ pci_read_config_dword(agp_bridge->dev, I810_PGETBL_CTL,
+ &pgetbl_ctl);
+ /* The 965 has a field telling us the size of the GTT,
+ * which may be larger than what is necessary to map the
+ * aperture.
+ */
+ switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
+ case I965_PGETBL_SIZE_128KB:
+ size = 128;
+ break;
+ case I965_PGETBL_SIZE_256KB:
+ size = 256;
+ break;
+ case I965_PGETBL_SIZE_512KB:
+ size = 512;
+ break;
+ default:
+ printk(KERN_INFO PFX "Unknown page table size, "
+ "assuming 512KB\n");
+ size = 512;
+ }
+ size += 4; /* add in BIOS popup space */
+ } else {
+ /* On previous hardware, the GTT size was just what was
+ * required to map the aperture.
+ */
+ size = agp_bridge->driver->fetch_size() + 4;
+ }
if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
@@ -576,6 +620,9 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int
int i,j,num_entries;
void *temp;
+ if (mem->page_count == 0)
+ return 0;
+
temp = agp_bridge->current_size;
num_entries = A_SIZE_FIX(temp)->num_entries;
@@ -598,16 +645,18 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int
(mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
return -EINVAL;
- global_cache_flush(); /* FIXME: Necessary ?*/
+ if (!mem->is_flushed) {
+ global_cache_flush();
+ mem->is_flushed = TRUE;
+ }
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
mem->memory[i], mem->type),
intel_i830_private.registers+I810_PTE_BASE+(j*4));
- readl(intel_i830_private.registers+I810_PTE_BASE+(j*4)); /* PCI Posting. */
}
+ readl(intel_i830_private.registers+I810_PTE_BASE+((j-1)*4));
- global_cache_flush();
agp_bridge->driver->tlb_flush(mem);
return 0;
}
@@ -617,7 +666,8 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
{
int i;
- global_cache_flush();
+ if (mem->page_count == 0)
+ return 0;
if (pg_start < intel_i830_private.gtt_entries) {
printk (KERN_INFO PFX "Trying to disable local/stolen memory\n");
@@ -626,10 +676,9 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4));
- readl(intel_i830_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */
}
+ readl(intel_i830_private.registers+I810_PTE_BASE+((i-1)*4));
- global_cache_flush();
agp_bridge->driver->tlb_flush(mem);
return 0;
}
@@ -686,6 +735,9 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
int i,j,num_entries;
void *temp;
+ if (mem->page_count == 0)
+ return 0;
+
temp = agp_bridge->current_size;
num_entries = A_SIZE_FIX(temp)->num_entries;
@@ -708,15 +760,17 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
(mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
return -EINVAL;
- global_cache_flush();
+ if (!mem->is_flushed) {
+ global_cache_flush();
+ mem->is_flushed = TRUE;
+ }
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
mem->memory[i], mem->type), intel_i830_private.gtt+j);
- readl(intel_i830_private.gtt+j); /* PCI Posting. */
}
+ readl(intel_i830_private.gtt+j-1);
- global_cache_flush();
agp_bridge->driver->tlb_flush(mem);
return 0;
}
@@ -726,7 +780,8 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
{
int i;
- global_cache_flush();
+ if (mem->page_count == 0)
+ return 0;
if (pg_start < intel_i830_private.gtt_entries) {
printk (KERN_INFO PFX "Trying to disable local/stolen memory\n");
@@ -735,30 +790,34 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
writel(agp_bridge->scratch_page, intel_i830_private.gtt+i);
- readl(intel_i830_private.gtt+i);
}
+ readl(intel_i830_private.gtt+i-1);
- global_cache_flush();
agp_bridge->driver->tlb_flush(mem);
return 0;
}
-static int intel_i915_fetch_size(void)
+/* Return the aperture size by just checking the resource length. The effect
+ * described in the spec of the MSAC registers is just changing of the
+ * resource size.
+ */
+static int intel_i9xx_fetch_size(void)
{
- struct aper_size_info_fixed *values;
- u32 temp, offset;
+ int num_sizes = sizeof(intel_i830_sizes) / sizeof(*intel_i830_sizes);
+ int aper_size; /* size in megabytes */
+ int i;
-#define I915_256MB_ADDRESS_MASK (1<<27)
+ aper_size = pci_resource_len(intel_i830_private.i830_dev, 2) / MB(1);
- values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
+ for (i = 0; i < num_sizes; i++) {
+ if (aper_size == intel_i830_sizes[i].size) {
+ agp_bridge->current_size = intel_i830_sizes + i;
+ agp_bridge->previous_size = agp_bridge->current_size;
+ return aper_size;
+ }
+ }
- pci_read_config_dword(intel_i830_private.i830_dev, I915_GMADDR, &temp);
- if (temp & I915_256MB_ADDRESS_MASK)
- offset = 0; /* 128MB aperture */
- else
- offset = 2; /* 256MB aperture */
- agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset);
- return values[offset].size;
+ return 0;
}
/* The intel i915 automatically initializes the agp aperture during POST.
@@ -821,40 +880,9 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
return addr | bridge->driver->masks[type].mask;
}
-static int intel_i965_fetch_size(void)
-{
- struct aper_size_info_fixed *values;
- u32 offset = 0;
- u8 temp;
-
-#define I965_512MB_ADDRESS_MASK (3<<1)
-
- values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
-
- pci_read_config_byte(intel_i830_private.i830_dev, I965_MSAC, &temp);
- temp &= I965_512MB_ADDRESS_MASK;
- switch (temp) {
- case 0x00:
- offset = 0; /* 128MB */
- break;
- case 0x06:
- offset = 3; /* 512MB */
- break;
- default:
- case 0x02:
- offset = 2; /* 256MB */
- break;
- }
-
- agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset);
-
- /* The i965 GTT is always sized as if it had a 512kB aperture size */
- return 512;
-}
-
/* The intel i965 automatically initializes the agp aperture during POST.
-+ * Use the memory already set aside for in the GTT.
-+ */
+ * Use the memory already set aside for in the GTT.
+ */
static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
{
int page_order;
@@ -1574,7 +1602,7 @@ static struct agp_bridge_driver intel_915_driver = {
.num_aperture_sizes = 4,
.needs_scratch_page = TRUE,
.configure = intel_i915_configure,
- .fetch_size = intel_i915_fetch_size,
+ .fetch_size = intel_i9xx_fetch_size,
.cleanup = intel_i915_cleanup,
.tlb_flush = intel_i810_tlbflush,
.mask_memory = intel_i810_mask_memory,
@@ -1598,7 +1626,7 @@ static struct agp_bridge_driver intel_i965_driver = {
.num_aperture_sizes = 4,
.needs_scratch_page = TRUE,
.configure = intel_i915_configure,
- .fetch_size = intel_i965_fetch_size,
+ .fetch_size = intel_i9xx_fetch_size,
.cleanup = intel_i915_cleanup,
.tlb_flush = intel_i810_tlbflush,
.mask_memory = intel_i965_mask_memory,
@@ -1927,6 +1955,15 @@ static int agp_intel_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
+ /* We should restore our graphics device's config space,
+ * as host bridge (00:00) resumes before graphics device (02:00),
+ * then our access to its pci space can work right.
+ */
+ if (intel_i810_private.i810_dev)
+ pci_restore_state(intel_i810_private.i810_dev);
+ if (intel_i830_private.i830_dev)
+ pci_restore_state(intel_i830_private.i830_dev);
+
if (bridge->driver == &intel_generic_driver)
intel_configure();
else if (bridge->driver == &intel_850_driver)
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index d73be4c2db8..902648db7ef 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -281,10 +281,11 @@ static int __devinit agp_sgi_init(void)
else
return 0;
- sgi_tioca_agp_bridges =
- (struct agp_bridge_data **)kmalloc(tioca_gart_found *
- sizeof(struct agp_bridge_data *),
- GFP_KERNEL);
+ sgi_tioca_agp_bridges = kmalloc(tioca_gart_found *
+ sizeof(struct agp_bridge_data *),
+ GFP_KERNEL);
+ if (!sgi_tioca_agp_bridges)
+ return -ENOMEM;
j = 0;
list_for_each_entry(info, &tioca_list, ca_list) {
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index c149ac9ce9a..2ded7a280d7 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -380,9 +380,23 @@ static struct agp_device_ids via_agp_device_ids[] __devinitdata =
/* P4M800CE */
{
.device_id = PCI_DEVICE_ID_VIA_P4M800CE,
- .chipset_name = "P4M800CE",
+ .chipset_name = "VT3314",
+ },
+ /* CX700 */
+ {
+ .device_id = PCI_DEVICE_ID_VIA_CX700,
+ .chipset_name = "CX700",
+ },
+ /* VT3336 */
+ {
+ .device_id = PCI_DEVICE_ID_VIA_VT3336,
+ .chipset_name = "VT3336",
+ },
+ /* P4M890 */
+ {
+ .device_id = PCI_DEVICE_ID_VIA_P4M890,
+ .chipset_name = "P4M890",
},
-
{ }, /* dummy final entry, always present */
};
@@ -524,6 +538,9 @@ static const struct pci_device_id agp_via_pci_table[] = {
ID(PCI_DEVICE_ID_VIA_83_87XX_1),
ID(PCI_DEVICE_ID_VIA_3296_0),
ID(PCI_DEVICE_ID_VIA_P4M800CE),
+ ID(PCI_DEVICE_ID_VIA_CX700),
+ ID(PCI_DEVICE_ID_VIA_VT3336),
+ ID(PCI_DEVICE_ID_VIA_P4M890),
{ }
};
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 66086fa2d59..feb4ac802a0 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -104,7 +104,7 @@ static struct async_struct *IRQ_ports;
static unsigned char current_ctl_bits;
-static void change_speed(struct async_struct *info, struct termios *old);
+static void change_speed(struct async_struct *info, struct ktermios *old);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -694,7 +694,7 @@ static void shutdown(struct async_struct * info)
* the specified baud rate for a serial port.
*/
static void change_speed(struct async_struct *info,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
int quot = 0, baud_base, baud;
unsigned cflag, cval = 0;
@@ -1365,7 +1365,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
return 0;
}
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
diff --git a/arch/arm/kernel/apm.c b/drivers/char/apm-emulation.c
index a11fb9a40c0..179c7a3b6e7 100644
--- a/arch/arm/kernel/apm.c
+++ b/drivers/char/apm-emulation.c
@@ -1,5 +1,5 @@
/*
- * bios-less APM driver for ARM Linux
+ * bios-less APM driver for ARM Linux
* Jamey Hicks <jamey@crl.dec.com>
* adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com)
*
@@ -19,6 +19,7 @@
#include <linux/capability.h>
#include <linux/sched.h>
#include <linux/pm.h>
+#include <linux/apm-emulation.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -27,7 +28,6 @@
#include <linux/kthread.h>
#include <linux/delay.h>
-#include <asm/apm.h> /* apm_power_info */
#include <asm/system.h>
/*
@@ -225,7 +225,7 @@ static void apm_suspend(void)
list_for_each_entry(as, &apm_user_list, list) {
if (as->suspend_state == SUSPEND_WAIT ||
as->suspend_state == SUSPEND_ACKED) {
- as->suspend_result = err;
+ as->suspend_result = err;
as->suspend_state = SUSPEND_DONE;
}
}
@@ -423,7 +423,7 @@ static int apm_open(struct inode * inode, struct file * filp)
{
struct apm_user *as;
- as = (struct apm_user *)kzalloc(sizeof(*as), GFP_KERNEL);
+ as = kzalloc(sizeof(*as), GFP_KERNEL);
if (as) {
/*
* XXX - this is a tiny bit broken, when we consider BSD
@@ -529,7 +529,7 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length)
info.battery_flag, info.battery_life,
info.time, units);
- return ret;
+ return ret;
}
#endif
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index 04a12027a74..b99b7561260 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -443,7 +443,7 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p && p->readonly) return -EIO;
if (!p || --p->refcount) {
- q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL);
+ q = kmalloc(sizeof(*p), GFP_KERNEL);
if (!q) {
if (p) p->refcount++;
return -ENOMEM;
diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c
index 8ce3f34cfc2..c02d9e99e05 100644
--- a/drivers/char/cs5535_gpio.c
+++ b/drivers/char/cs5535_gpio.c
@@ -82,7 +82,7 @@ static inline u32 cs5535_lowhigh_base(int reg)
static ssize_t cs5535_gpio_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
- u32 m = iminor(file->f_dentry->d_inode);
+ u32 m = iminor(file->f_path.dentry->d_inode);
int i, j;
u32 base = gpio_base + cs5535_lowhigh_base(m);
u32 m0, m1;
@@ -117,7 +117,7 @@ static ssize_t cs5535_gpio_write(struct file *file, const char __user *data,
static ssize_t cs5535_gpio_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos)
{
- u32 m = iminor(file->f_dentry->d_inode);
+ u32 m = iminor(file->f_path.dentry->d_inode);
u32 base = gpio_base + cs5535_lowhigh_base(m);
int rd_bit = 1 << (m & 0x0f);
int i;
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index acb2de5e3a9..3ffa0807754 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -1,8 +1,6 @@
#undef BLOCKMOVE
#define Z_WAKE
#undef Z_EXT_CHARS_IN_BUFFER
-static char rcsid[] =
-"$Revision: 2.3.2.20 $$Date: 2004/02/25 18:14:16 $";
/*
* linux/drivers/char/cyclades.c
@@ -593,18 +591,20 @@ static char rcsid[] =
*
*/
+#define CY_VERSION "2.4"
+
/* If you need to install more boards than NR_CARDS, change the constant
in the definition below. No other change is necessary to support up to
eight boards. Beyond that you'll have to extend cy_isa_addresses. */
-#define NR_CARDS 4
+#define NR_CARDS 4
/*
If the total number of ports is larger than NR_PORTS, change this
constant in the definition below. No other change is necessary to
support more boards/ports. */
-#define NR_PORTS 256
+#define NR_PORTS 256
#define ZE_V1_NPORTS 64
#define ZO_V1 0
@@ -625,9 +625,9 @@ static char rcsid[] =
#undef CY_PCI_DEBUG
#if 0
-#define PAUSE __asm__("nop");
+#define PAUSE __asm__("nop")
#else
-#define PAUSE ;
+#define PAUSE do {} while (0)
#endif
/*
@@ -663,7 +663,7 @@ static char rcsid[] =
do { \
spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \
} while (0)
-
+
#define CY_UNLOCK(info,flags) \
do { \
spin_unlock_irqrestore(&cy_card[info->card].card_lock, flags); \
@@ -676,14 +676,14 @@ static char rcsid[] =
#include <linux/stat.h>
#include <linux/proc_fs.h>
-static void cy_throttle (struct tty_struct *tty);
-static void cy_send_xchar (struct tty_struct *tty, char ch);
+static void cy_throttle(struct tty_struct *tty);
+static void cy_send_xchar(struct tty_struct *tty, char ch);
#define IS_CYC_Z(card) ((card).num_chips == -1)
#define Z_FPGA_CHECK(card) \
- ((cy_readl(&((struct RUNTIME_9060 __iomem *) \
- ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
+ ((cy_readl(&((struct RUNTIME_9060 __iomem *) \
+ ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
#define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->mail_box_0)) || \
@@ -698,8 +698,6 @@ static void cy_send_xchar (struct tty_struct *tty, char ch);
#define STD_COM_FLAGS (0)
-#define JIFFIES_DIFF(n, j) ((j) - (n))
-
static struct tty_driver *cy_serial_driver;
#ifdef CONFIG_ISA
@@ -713,27 +711,28 @@ static struct tty_driver *cy_serial_driver;
*/
static unsigned int cy_isa_addresses[] = {
- 0xD0000,
- 0xD2000,
- 0xD4000,
- 0xD6000,
- 0xD8000,
- 0xDA000,
- 0xDC000,
- 0xDE000,
- 0,0,0,0,0,0,0,0
+ 0xD0000,
+ 0xD2000,
+ 0xD4000,
+ 0xD6000,
+ 0xD8000,
+ 0xDA000,
+ 0xDC000,
+ 0xDE000,
+ 0, 0, 0, 0, 0, 0, 0, 0
};
+
#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
#ifdef MODULE
static long maddr[NR_CARDS] = { 0, };
-static int irq[NR_CARDS] = { 0, };
+static int irq[NR_CARDS] = { 0, };
module_param_array(maddr, long, NULL, 0);
module_param_array(irq, int, NULL, 0);
#endif
-#endif /* CONFIG_ISA */
+#endif /* CONFIG_ISA */
/* This is the per-card data structure containing address, irq, number of
channels, etc. This driver supports a maximum of NR_CARDS cards.
@@ -745,7 +744,7 @@ static struct cyclades_card cy_card[NR_CARDS];
*/
static struct cyclades_port cy_port[NR_PORTS];
-static int cy_next_channel; /* next minor available */
+static int cy_next_channel; /* next minor available */
/*
* This is used to look up the divisor speeds and the timeouts
@@ -757,36 +756,42 @@ static int cy_next_channel; /* next minor available */
* 20
*/
static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
- 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000,
- 230400, 0};
-
-static char baud_co_25[] = { /* 25 MHz clock option table */
- /* value => 00 01 02 03 04 */
- /* divide by 8 32 128 512 2048 */
- 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
- 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-static char baud_bpr_25[] = { /* 25 MHz baud rate period table */
- 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
- 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15};
-
-static char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
- /* value => 00 01 02 03 04 */
- /* divide by 8 32 128 512 2048 */
- 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
- 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00};
-
-static char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
- 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
- 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
- 0x21};
-
-static char baud_cor3[] = { /* receive threshold */
- 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
- 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
- 0x07};
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
+ 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
+ 230400, 0
+};
+
+static char baud_co_25[] = { /* 25 MHz clock option table */
+ /* value => 00 01 02 03 04 */
+ /* divide by 8 32 128 512 2048 */
+ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
+ 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static char baud_bpr_25[] = { /* 25 MHz baud rate period table */
+ 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
+ 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
+};
+
+static char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
+ /* value => 00 01 02 03 04 */
+ /* divide by 8 32 128 512 2048 */
+ 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
+ 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+};
+
+static char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
+ 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
+ 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
+ 0x21
+};
+
+static char baud_cor3[] = { /* receive threshold */
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
+ 0x07
+};
/*
* The Cyclades driver implements HW flow control as any serial driver.
@@ -799,42 +804,42 @@ static char baud_cor3[] = { /* receive threshold */
* cables.
*/
-static char rflow_thr[] = { /* rflow threshold */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
- 0x0a};
+static char rflow_thr[] = { /* rflow threshold */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a
+};
/* The Cyclom-Ye has placed the sequential chips in non-sequential
* address order. This look-up table overcomes that problem.
*/
-static int cy_chip_offset [] =
- { 0x0000,
- 0x0400,
- 0x0800,
- 0x0C00,
- 0x0200,
- 0x0600,
- 0x0A00,
- 0x0E00
- };
+static int cy_chip_offset[] = { 0x0000,
+ 0x0400,
+ 0x0800,
+ 0x0C00,
+ 0x0200,
+ 0x0600,
+ 0x0A00,
+ 0x0E00
+};
/* PCI related definitions */
-static unsigned short cy_pci_nboard;
-static unsigned short cy_isa_nboard;
-static unsigned short cy_nboard;
+static unsigned short cy_pci_nboard;
+static unsigned short cy_isa_nboard;
+static unsigned short cy_nboard;
#ifdef CONFIG_PCI
-static unsigned short cy_pci_dev_id[] = {
- PCI_DEVICE_ID_CYCLOM_Y_Lo, /* PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_Y_Hi, /* PCI > 1Mb */
- PCI_DEVICE_ID_CYCLOM_4Y_Lo, /* 4Y PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_4Y_Hi, /* 4Y PCI > 1Mb */
- PCI_DEVICE_ID_CYCLOM_8Y_Lo, /* 8Y PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_8Y_Hi, /* 8Y PCI > 1Mb */
- PCI_DEVICE_ID_CYCLOM_Z_Lo, /* Z PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_Z_Hi, /* Z PCI > 1Mb */
- 0 /* end of table */
- };
+static unsigned short cy_pci_dev_id[] = {
+ PCI_DEVICE_ID_CYCLOM_Y_Lo, /* PCI < 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Y_Hi, /* PCI > 1Mb */
+ PCI_DEVICE_ID_CYCLOM_4Y_Lo, /* 4Y PCI < 1Mb */
+ PCI_DEVICE_ID_CYCLOM_4Y_Hi, /* 4Y PCI > 1Mb */
+ PCI_DEVICE_ID_CYCLOM_8Y_Lo, /* 8Y PCI < 1Mb */
+ PCI_DEVICE_ID_CYCLOM_8Y_Hi, /* 8Y PCI > 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Z_Lo, /* Z PCI < 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Z_Hi, /* Z PCI > 1Mb */
+ 0 /* end of table */
+};
#endif
static void cy_start(struct tty_struct *);
@@ -842,9 +847,9 @@ static void set_line_char(struct cyclades_port *);
static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong);
#ifdef CONFIG_ISA
static unsigned detect_isa_irq(void __iomem *);
-#endif /* CONFIG_ISA */
+#endif /* CONFIG_ISA */
-static int cyclades_get_proc_info(char *, char **, off_t , int , int *, void *);
+static int cyclades_get_proc_info(char *, char **, off_t, int, int *, void *);
#ifndef CONFIG_CYZ_INTR
static void cyz_poll(unsigned long);
@@ -855,41 +860,36 @@ static long cyz_polling_cycle = CZ_DEF_POLL;
static int cyz_timeron = 0;
static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
-#else /* CONFIG_CYZ_INTR */
+#else /* CONFIG_CYZ_INTR */
static void cyz_rx_restart(unsigned long);
static struct timer_list cyz_rx_full_timer[NR_PORTS];
-#endif /* CONFIG_CYZ_INTR */
+#endif /* CONFIG_CYZ_INTR */
-static inline int
-serial_paranoia_check(struct cyclades_port *info,
- char *name, const char *routine)
+static inline int serial_paranoia_check(struct cyclades_port *info,
+ char *name, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
- static const char *badmagic =
- "cyc Warning: bad magic number for serial struct (%s) in %s\n";
- static const char *badinfo =
- "cyc Warning: null cyclades_port for (%s) in %s\n";
- static const char *badrange =
- "cyc Warning: cyclades_port out of range for (%s) in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
-
- if( (long)info < (long)(&cy_port[0])
- || (long)(&cy_port[NR_PORTS]) < (long)info ){
- printk(badrange, name, routine);
- return 1;
- }
-
- if (info->magic != CYCLADES_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
+ if (!info) {
+ printk("cyc Warning: null cyclades_port for (%s) in %s\n",
+ name, routine);
+ return 1;
+ }
+
+ if ((long)info < (long)(&cy_port[0]) ||
+ (long)(&cy_port[NR_PORTS]) < (long)info) {
+ printk("cyc Warning: cyclades_port out of range for (%s) in "
+ "%s\n", name, routine);
+ return 1;
+ }
+
+ if (info->magic != CYCLADES_MAGIC) {
+ printk("cyc Warning: bad magic number for serial struct (%s) "
+ "in %s\n", name, routine);
+ return 1;
+ }
#endif
- return 0;
-} /* serial_paranoia_check */
+ return 0;
+} /* serial_paranoia_check */
/*
* This routine is used by the interrupt handler to schedule
@@ -897,13 +897,11 @@ serial_paranoia_check(struct cyclades_port *info,
* (also known as the "bottom half"). This can be called any
* number of times for any channel without harm.
*/
-static inline void
-cy_sched_event(struct cyclades_port *info, int event)
+static inline void cy_sched_event(struct cyclades_port *info, int event)
{
- info->event |= 1 << event; /* remember what kind of event and who */
- schedule_work(&info->tqueue);
-} /* cy_sched_event */
-
+ info->event |= 1 << event; /* remember what kind of event and who */
+ schedule_work(&info->tqueue);
+} /* cy_sched_event */
/*
* This routine is used to handle the "bottom half" processing for the
@@ -930,41 +928,36 @@ do_softint(struct work_struct *work)
{
struct cyclades_port *info =
container_of(work, struct cyclades_port, tqueue);
- struct tty_struct *tty;
-
- tty = info->tty;
- if (!tty)
- return;
-
- if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
- tty_hangup(info->tty);
- wake_up_interruptible(&info->open_wait);
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
- }
- if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
- wake_up_interruptible(&info->open_wait);
- }
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
+ tty_hangup(info->tty);
+ wake_up_interruptible(&info->open_wait);
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ }
+ if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event))
+ wake_up_interruptible(&info->open_wait);
#ifdef CONFIG_CYZ_INTR
- if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) {
- if (cyz_rx_full_timer[info->line].function == NULL) {
- cyz_rx_full_timer[info->line].expires = jiffies + 1;
- cyz_rx_full_timer[info->line].function = cyz_rx_restart;
- cyz_rx_full_timer[info->line].data = (unsigned long)info;
- add_timer(&cyz_rx_full_timer[info->line]);
+ if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) {
+ if (cyz_rx_full_timer[info->line].function == NULL) {
+ cyz_rx_full_timer[info->line].expires = jiffies + 1;
+ cyz_rx_full_timer[info->line].function = cyz_rx_restart;
+ cyz_rx_full_timer[info->line].data =
+ (unsigned long)info;
+ add_timer(&cyz_rx_full_timer[info->line]);
+ }
}
- }
#endif
- if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event)) {
- wake_up_interruptible(&info->delta_msr_wait);
- }
- if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
- tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
- }
+ if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event))
+ wake_up_interruptible(&info->delta_msr_wait);
+ tty_wakeup(tty);
#ifdef Z_WAKE
- if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) {
- wake_up_interruptible(&info->shutdown_wait);
- }
+ if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event))
+ wake_up_interruptible(&info->shutdown_wait);
#endif
} /* do_softint */
@@ -979,341 +972,339 @@ do_softint(struct work_struct *work)
This function is only called from inside spinlock-protected code.
*/
-static int
-cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
+static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
{
- volatile int i;
+ volatile int i;
- /* Check to see that the previous command has completed */
- for(i = 0 ; i < 100 ; i++){
- if (cy_readb(base_addr+(CyCCR<<index)) == 0){
- break;
+ /* Check to see that the previous command has completed */
+ for (i = 0; i < 100; i++) {
+ if (cy_readb(base_addr + (CyCCR << index)) == 0) {
+ break;
+ }
+ udelay(10L);
}
- udelay(10L);
- }
- /* if the CCR never cleared, the previous command
- didn't finish within the "reasonable time" */
- if (i == 100) return (-1);
+ /* if the CCR never cleared, the previous command
+ didn't finish within the "reasonable time" */
+ if (i == 100)
+ return -1;
- /* Issue the new command */
- cy_writeb(base_addr+(CyCCR<<index), cmd);
+ /* Issue the new command */
+ cy_writeb(base_addr + (CyCCR << index), cmd);
- return(0);
-} /* cyy_issue_cmd */
+ return 0;
+} /* cyy_issue_cmd */
#ifdef CONFIG_ISA
/* ISA interrupt detection code */
-static unsigned
-detect_isa_irq(void __iomem *address)
+static unsigned detect_isa_irq(void __iomem * address)
{
- int irq;
- unsigned long irqs, flags;
- int save_xir, save_car;
- int index = 0; /* IRQ probing is only for ISA */
-
- /* forget possible initially masked and pending IRQ */
- irq = probe_irq_off(probe_irq_on());
-
- /* Clear interrupts on the board first */
- cy_writeb(address + (Cy_ClrIntr<<index), 0);
- /* Cy_ClrIntr is 0x1800 */
-
- irqs = probe_irq_on();
- /* Wait ... */
- udelay(5000L);
-
- /* Enable the Tx interrupts on the CD1400 */
- local_irq_save(flags);
- cy_writeb(address + (CyCAR<<index), 0);
- cyy_issue_cmd(address, CyCHAN_CTL|CyENB_XMTR, index);
-
- cy_writeb(address + (CyCAR<<index), 0);
- cy_writeb(address + (CySRER<<index),
- cy_readb(address + (CySRER<<index)) | CyTxRdy);
- local_irq_restore(flags);
-
- /* Wait ... */
- udelay(5000L);
-
- /* Check which interrupt is in use */
- irq = probe_irq_off(irqs);
-
- /* Clean up */
- save_xir = (u_char) cy_readb(address + (CyTIR<<index));
- save_car = cy_readb(address + (CyCAR<<index));
- cy_writeb(address + (CyCAR<<index), (save_xir & 0x3));
- cy_writeb(address + (CySRER<<index),
- cy_readb(address + (CySRER<<index)) & ~CyTxRdy);
- cy_writeb(address + (CyTIR<<index), (save_xir & 0x3f));
- cy_writeb(address + (CyCAR<<index), (save_car));
- cy_writeb(address + (Cy_ClrIntr<<index), 0);
- /* Cy_ClrIntr is 0x1800 */
-
- return (irq > 0)? irq : 0;
+ int irq;
+ unsigned long irqs, flags;
+ int save_xir, save_car;
+ int index = 0; /* IRQ probing is only for ISA */
+
+ /* forget possible initially masked and pending IRQ */
+ irq = probe_irq_off(probe_irq_on());
+
+ /* Clear interrupts on the board first */
+ cy_writeb(address + (Cy_ClrIntr << index), 0);
+ /* Cy_ClrIntr is 0x1800 */
+
+ irqs = probe_irq_on();
+ /* Wait ... */
+ udelay(5000L);
+
+ /* Enable the Tx interrupts on the CD1400 */
+ local_irq_save(flags);
+ cy_writeb(address + (CyCAR << index), 0);
+ cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
+
+ cy_writeb(address + (CyCAR << index), 0);
+ cy_writeb(address + (CySRER << index),
+ cy_readb(address + (CySRER << index)) | CyTxRdy);
+ local_irq_restore(flags);
+
+ /* Wait ... */
+ udelay(5000L);
+
+ /* Check which interrupt is in use */
+ irq = probe_irq_off(irqs);
+
+ /* Clean up */
+ save_xir = (u_char) cy_readb(address + (CyTIR << index));
+ save_car = cy_readb(address + (CyCAR << index));
+ cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
+ cy_writeb(address + (CySRER << index),
+ cy_readb(address + (CySRER << index)) & ~CyTxRdy);
+ cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
+ cy_writeb(address + (CyCAR << index), (save_car));
+ cy_writeb(address + (Cy_ClrIntr << index), 0);
+ /* Cy_ClrIntr is 0x1800 */
+
+ return (irq > 0) ? irq : 0;
}
-#endif /* CONFIG_ISA */
+#endif /* CONFIG_ISA */
-/* The real interrupt service routine is called
- whenever the card wants its hand held--chars
- received, out buffer empty, modem change, etc.
- */
-static irqreturn_t
-cyy_interrupt(int irq, void *dev_id)
+static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
+ void __iomem * base_addr, int status, int index)
{
- struct tty_struct *tty;
- int status;
- struct cyclades_card *cinfo;
- struct cyclades_port *info;
- void __iomem *base_addr, *card_base_addr;
- int chip;
- int save_xir, channel, save_car;
- char data;
- volatile int char_count;
- int outch;
- int i,j,index;
- int too_many;
- int had_work;
- int mdm_change;
- int mdm_status;
- int len;
- if((cinfo = (struct cyclades_card *)dev_id) == 0){
-#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: spurious interrupt %d\n\r", irq);
-#endif
- return IRQ_NONE; /* spurious interrupt */
- }
-
- card_base_addr = cinfo->base_addr;
- index = cinfo->bus_index;
-
-
- /* This loop checks all chips in the card. Make a note whenever
- _any_ chip had some work to do, as this is considered an
- indication that there will be more to do. Only when no chip
- has any work does this outermost loop exit.
- */
- do{
- had_work = 0;
- for ( chip = 0 ; chip < cinfo->num_chips ; chip ++) {
- base_addr = cinfo->base_addr + (cy_chip_offset[chip]<<index);
- too_many = 0;
- while ( (status = cy_readb(base_addr+(CySVRR<<index))) != 0x00) {
- had_work++;
- /* The purpose of the following test is to ensure that
- no chip can monopolize the driver. This forces the
- chips to be checked in a round-robin fashion (after
- draining each of a bunch (1000) of characters).
- */
- if(1000<too_many++){
- break;
- }
- if (status & CySRReceive) { /* reception interrupt */
+ struct cyclades_port *info;
+ struct tty_struct *tty;
+ volatile int char_count;
+ int i, j, len, mdm_change, mdm_status, outch;
+ int save_xir, channel, save_car;
+ char data;
+
+ if (status & CySRReceive) { /* reception interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip);
+ printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip);
#endif
- /* determine the channel & change to that context */
- spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr+(CyRIR<<index));
- channel = (u_short ) (save_xir & CyIRChannel);
- i = channel + chip * 4 + cinfo->first_line;
- info = &cy_port[i];
- info->last_active = jiffies;
- save_car = cy_readb(base_addr+(CyCAR<<index));
- cy_writeb(base_addr+(CyCAR<<index), save_xir);
-
- /* if there is nowhere to put the data, discard it */
- if(info->tty == 0){
- j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask);
- if ( j == CyIVRRxEx ) { /* exception */
- data = cy_readb(base_addr+(CyRDSR<<index));
- } else { /* normal character reception */
- char_count = cy_readb(base_addr+(CyRDCR<<index));
- while(char_count--){
- data = cy_readb(base_addr+(CyRDSR<<index));
- }
- }
- }else{ /* there is an open port for this data */
- tty = info->tty;
- j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask);
- if ( j == CyIVRRxEx ) { /* exception */
- data = cy_readb(base_addr+(CyRDSR<<index));
-
- /* For statistics only */
- if (data & CyBREAK)
- info->icount.brk++;
- else if(data & CyFRAME)
- info->icount.frame++;
- else if(data & CyPARITY)
- info->icount.parity++;
- else if(data & CyOVERRUN)
- info->icount.overrun++;
-
- if(data & info->ignore_status_mask){
- info->icount.rx++;
- continue;
- }
- if (tty_buffer_request_room(tty, 1)) {
- if (data & info->read_status_mask){
- if(data & CyBREAK){
- tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_BREAK);
- info->icount.rx++;
- if (info->flags & ASYNC_SAK){
- do_SAK(tty);
- }
- }else if(data & CyFRAME){
- tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME);
- info->icount.rx++;
- info->idle_stats.frame_errs++;
- }else if(data & CyPARITY){
- /* Pieces of seven... */
- tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_PARITY);
- info->icount.rx++;
- info->idle_stats.parity_errs++;
- }else if(data & CyOVERRUN){
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ /* determine the channel & change to that context */
+ spin_lock(&cinfo->card_lock);
+ save_xir = (u_char) cy_readb(base_addr + (CyRIR << index));
+ channel = (u_short) (save_xir & CyIRChannel);
+ i = channel + chip * 4 + cinfo->first_line;
+ info = &cy_port[i];
+ info->last_active = jiffies;
+ save_car = cy_readb(base_addr + (CyCAR << index));
+ cy_writeb(base_addr + (CyCAR << index), save_xir);
+
+ /* if there is nowhere to put the data, discard it */
+ if (info->tty == 0) {
+ j = (cy_readb(base_addr + (CyRIVR << index)) &
+ CyIVRMask);
+ if (j == CyIVRRxEx) { /* exception */
+ data = cy_readb(base_addr + (CyRDSR << index));
+ } else { /* normal character reception */
+ char_count = cy_readb(base_addr +
+ (CyRDCR << index));
+ while (char_count--) {
+ data = cy_readb(base_addr +
+ (CyRDSR << index));
+ }
+ }
+ } else { /* there is an open port for this data */
+ tty = info->tty;
+ j = (cy_readb(base_addr + (CyRIVR << index)) &
+ CyIVRMask);
+ if (j == CyIVRRxEx) { /* exception */
+ data = cy_readb(base_addr + (CyRDSR << index));
+
+ /* For statistics only */
+ if (data & CyBREAK)
+ info->icount.brk++;
+ else if (data & CyFRAME)
+ info->icount.frame++;
+ else if (data & CyPARITY)
+ info->icount.parity++;
+ else if (data & CyOVERRUN)
+ info->icount.overrun++;
+
+ if (data & info->ignore_status_mask) {
info->icount.rx++;
- /* If the flip buffer itself is
- overflowing, we still lose
- the next incoming character.
- */
- tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME);
- info->icount.rx++;
+ return;
+ }
+ if (tty_buffer_request_room(tty, 1)) {
+ if (data & info->read_status_mask) {
+ if (data & CyBREAK) {
+ tty_insert_flip_char(
+ tty,
+ cy_readb(
+ base_addr +
+ (CyRDSR <<
+ index)),
+ TTY_BREAK);
+ info->icount.rx++;
+ if (info->flags &
+ ASYNC_SAK) {
+ do_SAK(tty);
+ }
+ } else if (data & CyFRAME) {
+ tty_insert_flip_char(
+ tty,
+ cy_readb(
+ base_addr +
+ (CyRDSR <<
+ index)),
+ TTY_FRAME);
+ info->icount.rx++;
+ info->idle_stats.
+ frame_errs++;
+ } else if (data & CyPARITY) {
+ /* Pieces of seven... */
+ tty_insert_flip_char(
+ tty,
+ cy_readb(
+ base_addr +
+ (CyRDSR <<
+ index)),
+ TTY_PARITY);
+ info->icount.rx++;
+ info->idle_stats.
+ parity_errs++;
+ } else if (data & CyOVERRUN) {
+ tty_insert_flip_char(
+ tty, 0,
+ TTY_OVERRUN);
+ info->icount.rx++;
+ /* If the flip buffer itself is
+ overflowing, we still lose
+ the next incoming character.
+ */
+ tty_insert_flip_char(
+ tty,
+ cy_readb(
+ base_addr +
+ (CyRDSR <<
+ index)),
+ TTY_FRAME);
+ info->icount.rx++;
+ info->idle_stats.
+ overruns++;
+ /* These two conditions may imply */
+ /* a normal read should be done. */
+ /* }else if(data & CyTIMEOUT){ */
+ /* }else if(data & CySPECHAR){ */
+ } else {
+ tty_insert_flip_char(
+ tty, 0,
+ TTY_NORMAL);
+ info->icount.rx++;
+ }
+ } else {
+ tty_insert_flip_char(tty, 0,
+ TTY_NORMAL);
+ info->icount.rx++;
+ }
+ } else {
+ /* there was a software buffer
+ overrun and nothing could be
+ done about it!!! */
+ info->icount.buf_overrun++;
info->idle_stats.overruns++;
- /* These two conditions may imply */
- /* a normal read should be done. */
- /* }else if(data & CyTIMEOUT){ */
- /* }else if(data & CySPECHAR){ */
- }else {
- tty_insert_flip_char(tty, 0, TTY_NORMAL);
- info->icount.rx++;
- }
- }else{
- tty_insert_flip_char(tty, 0, TTY_NORMAL);
- info->icount.rx++;
- }
- }else{
- /* there was a software buffer
- overrun and nothing could be
- done about it!!! */
- info->icount.buf_overrun++;
- info->idle_stats.overruns++;
- }
- } else { /* normal character reception */
- /* load # chars available from the chip */
- char_count = cy_readb(base_addr+(CyRDCR<<index));
+ }
+ } else { /* normal character reception */
+ /* load # chars available from the chip */
+ char_count = cy_readb(base_addr +
+ (CyRDCR << index));
#ifdef CY_ENABLE_MONITORING
- ++info->mon.int_count;
- info->mon.char_count += char_count;
- if (char_count > info->mon.char_max)
- info->mon.char_max = char_count;
- info->mon.char_last = char_count;
+ ++info->mon.int_count;
+ info->mon.char_count += char_count;
+ if (char_count > info->mon.char_max)
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
#endif
- len = tty_buffer_request_room(tty, char_count);
- while(len--){
- data = cy_readb(base_addr+(CyRDSR<<index));
- tty_insert_flip_char(tty, data, TTY_NORMAL);
- info->idle_stats.recv_bytes++;
- info->icount.rx++;
+ len = tty_buffer_request_room(tty, char_count);
+ while (len--) {
+ data = cy_readb(base_addr +
+ (CyRDSR << index));
+ tty_insert_flip_char(tty, data,
+ TTY_NORMAL);
+ info->idle_stats.recv_bytes++;
+ info->icount.rx++;
#ifdef CY_16Y_HACK
- udelay(10L);
+ udelay(10L);
#endif
- }
- info->idle_stats.recv_idle = jiffies;
- }
+ }
+ info->idle_stats.recv_idle = jiffies;
+ }
tty_schedule_flip(tty);
- }
- /* end of service */
- cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f));
- cy_writeb(base_addr+(CyCAR<<index), (save_car));
- spin_unlock(&cinfo->card_lock);
- }
-
-
- if (status & CySRTransmit) { /* transmission interrupt */
- /* Since we only get here when the transmit buffer
- is empty, we know we can always stuff a dozen
- characters. */
+ }
+ /* end of service */
+ cy_writeb(base_addr + (CyRIR << index), (save_xir & 0x3f));
+ cy_writeb(base_addr + (CyCAR << index), (save_car));
+ spin_unlock(&cinfo->card_lock);
+ }
+
+ if (status & CySRTransmit) { /* transmission interrupt */
+ /* Since we only get here when the transmit buffer
+ is empty, we know we can always stuff a dozen
+ characters. */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: xmit intr, chip %d\n\r", chip);
+ printk("cyy_interrupt: xmit intr, chip %d\n\r", chip);
#endif
- /* determine the channel & change to that context */
- spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr+(CyTIR<<index));
- channel = (u_short ) (save_xir & CyIRChannel);
- i = channel + chip * 4 + cinfo->first_line;
- save_car = cy_readb(base_addr+(CyCAR<<index));
- cy_writeb(base_addr+(CyCAR<<index), save_xir);
-
- /* validate the port# (as configured and open) */
- if( (i < 0) || (NR_PORTS <= i) ){
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy);
- goto txend;
- }
- info = &cy_port[i];
- info->last_active = jiffies;
- if(info->tty == 0){
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy);
- goto txdone;
- }
-
- /* load the on-chip space for outbound data */
- char_count = info->xmit_fifo_size;
-
- if(info->x_char) { /* send special char */
- outch = info->x_char;
- cy_writeb(base_addr+(CyTDR<<index), outch);
- char_count--;
+ /* determine the channel & change to that context */
+ spin_lock(&cinfo->card_lock);
+ save_xir = (u_char) cy_readb(base_addr + (CyTIR << index));
+ channel = (u_short) (save_xir & CyIRChannel);
+ i = channel + chip * 4 + cinfo->first_line;
+ save_car = cy_readb(base_addr + (CyCAR << index));
+ cy_writeb(base_addr + (CyCAR << index), save_xir);
+
+ /* validate the port# (as configured and open) */
+ if ((i < 0) || (NR_PORTS <= i)) {
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) &
+ ~CyTxRdy);
+ goto txend;
+ }
+ info = &cy_port[i];
+ info->last_active = jiffies;
+ if (info->tty == 0) {
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) &
+ ~CyTxRdy);
+ goto txdone;
+ }
+
+ /* load the on-chip space for outbound data */
+ char_count = info->xmit_fifo_size;
+
+ if (info->x_char) { /* send special char */
+ outch = info->x_char;
+ cy_writeb(base_addr + (CyTDR << index), outch);
+ char_count--;
info->icount.tx++;
- info->x_char = 0;
- }
+ info->x_char = 0;
+ }
- if (info->breakon || info->breakoff) {
+ if (info->breakon || info->breakoff) {
if (info->breakon) {
- cy_writeb(base_addr + (CyTDR<<index), 0);
- cy_writeb(base_addr + (CyTDR<<index), 0x81);
- info->breakon = 0;
- char_count -= 2;
+ cy_writeb(base_addr + (CyTDR << index), 0);
+ cy_writeb(base_addr + (CyTDR << index), 0x81);
+ info->breakon = 0;
+ char_count -= 2;
}
if (info->breakoff) {
- cy_writeb(base_addr + (CyTDR<<index), 0);
- cy_writeb(base_addr + (CyTDR<<index), 0x83);
- info->breakoff = 0;
- char_count -= 2;
+ cy_writeb(base_addr + (CyTDR << index), 0);
+ cy_writeb(base_addr + (CyTDR << index), 0x83);
+ info->breakoff = 0;
+ char_count -= 2;
}
- }
-
- while (char_count-- > 0){
- if (!info->xmit_cnt){
- if (cy_readb(base_addr+(CySRER<<index))&CyTxMpty) {
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) &
- ~CyTxMpty);
- } else {
- cy_writeb(base_addr+(CySRER<<index),
- ((cy_readb(base_addr+(CySRER<<index))
- & ~CyTxRdy)
- | CyTxMpty));
- }
- goto txdone;
+ }
+
+ while (char_count-- > 0) {
+ if (!info->xmit_cnt) {
+ if (cy_readb(base_addr + (CySRER << index)) &
+ CyTxMpty) {
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr +
+ (CySRER << index)) &
+ ~CyTxMpty);
+ } else {
+ cy_writeb(base_addr + (CySRER << index),
+ (cy_readb(base_addr +
+ (CySRER << index)) &
+ ~CyTxRdy) | CyTxMpty);
+ }
+ goto txdone;
}
- if (info->xmit_buf == 0){
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) &
+ if (info->xmit_buf == 0) {
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index))&
~CyTxRdy);
- goto txdone;
+ goto txdone;
}
- if (info->tty->stopped || info->tty->hw_stopped){
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) &
+ if (info->tty->stopped || info->tty->hw_stopped) {
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index))&
~CyTxRdy);
- goto txdone;
+ goto txdone;
}
- /* Because the Embedded Transmit Commands have
- been enabled, we must check to see if the
+ /* Because the Embedded Transmit Commands have
+ been enabled, we must check to see if the
escape character, NULL, is being sent. If it
is, we must ensure that there is room for it
to be doubled in the output stream. Therefore
@@ -1322,125 +1313,182 @@ cyy_interrupt(int irq, void *dev_id)
after the check for a NULL output character.
This is necessary because there may not be
room for the two chars needed to send a NULL.)
- */
- outch = info->xmit_buf[info->xmit_tail];
- if( outch ){
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1)
- & (SERIAL_XMIT_SIZE - 1);
- cy_writeb(base_addr+(CyTDR<<index), outch);
- info->icount.tx++;
- }else{
- if(char_count > 1){
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1)
- & (SERIAL_XMIT_SIZE - 1);
- cy_writeb(base_addr+(CyTDR<<index),
- outch);
- cy_writeb(base_addr+(CyTDR<<index), 0);
+ */
+ outch = info->xmit_buf[info->xmit_tail];
+ if (outch) {
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1) &
+ (SERIAL_XMIT_SIZE - 1);
+ cy_writeb(base_addr + (CyTDR << index), outch);
info->icount.tx++;
- char_count--;
- }else{
- }
- }
- }
-
- txdone:
- if (info->xmit_cnt < WAKEUP_CHARS) {
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
- }
- txend:
- /* end of service */
- cy_writeb(base_addr+(CyTIR<<index),
- (save_xir & 0x3f));
- cy_writeb(base_addr+(CyCAR<<index), (save_car));
- spin_unlock(&cinfo->card_lock);
- }
-
- if (status & CySRModem) { /* modem interrupt */
-
- /* determine the channel & change to that context */
- spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr+(CyMIR<<index));
- channel = (u_short ) (save_xir & CyIRChannel);
- info = &cy_port[channel + chip * 4
- + cinfo->first_line];
- info->last_active = jiffies;
- save_car = cy_readb(base_addr+(CyCAR<<index));
- cy_writeb(base_addr+(CyCAR<<index), save_xir);
-
- mdm_change = cy_readb(base_addr+(CyMISR<<index));
- mdm_status = cy_readb(base_addr+(CyMSVR1<<index));
-
- if(info->tty == 0){/* no place for data, ignore it*/
- ;
- }else{
+ } else {
+ if (char_count > 1) {
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1)&
+ (SERIAL_XMIT_SIZE - 1);
+ cy_writeb(base_addr + (CyTDR << index),
+ outch);
+ cy_writeb(base_addr + (CyTDR << index),
+ 0);
+ info->icount.tx++;
+ char_count--;
+ } else {
+ }
+ }
+ }
+
+txdone:
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ }
+txend:
+ /* end of service */
+ cy_writeb(base_addr + (CyTIR << index), (save_xir & 0x3f));
+ cy_writeb(base_addr + (CyCAR << index), (save_car));
+ spin_unlock(&cinfo->card_lock);
+ }
+
+ if (status & CySRModem) { /* modem interrupt */
+
+ /* determine the channel & change to that context */
+ spin_lock(&cinfo->card_lock);
+ save_xir = (u_char) cy_readb(base_addr + (CyMIR << index));
+ channel = (u_short) (save_xir & CyIRChannel);
+ info = &cy_port[channel + chip * 4 + cinfo->first_line];
+ info->last_active = jiffies;
+ save_car = cy_readb(base_addr + (CyCAR << index));
+ cy_writeb(base_addr + (CyCAR << index), save_xir);
+
+ mdm_change = cy_readb(base_addr + (CyMISR << index));
+ mdm_status = cy_readb(base_addr + (CyMSVR1 << index));
+
+ if (info->tty == 0) { /* no place for data, ignore it */
+ ;
+ } else {
if (mdm_change & CyANY_DELTA) {
- /* For statistics only */
- if (mdm_change & CyDCD) info->icount.dcd++;
- if (mdm_change & CyCTS) info->icount.cts++;
- if (mdm_change & CyDSR) info->icount.dsr++;
- if (mdm_change & CyRI) info->icount.rng++;
+ /* For statistics only */
+ if (mdm_change & CyDCD)
+ info->icount.dcd++;
+ if (mdm_change & CyCTS)
+ info->icount.cts++;
+ if (mdm_change & CyDSR)
+ info->icount.dsr++;
+ if (mdm_change & CyRI)
+ info->icount.rng++;
+
+ cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
+ }
+
+ if ((mdm_change & CyDCD) &&
+ (info->flags & ASYNC_CHECK_CD)) {
+ if (mdm_status & CyDCD) {
+ cy_sched_event(info,
+ Cy_EVENT_OPEN_WAKEUP);
+ } else {
+ cy_sched_event(info, Cy_EVENT_HANGUP);
+ }
+ }
+ if ((mdm_change & CyCTS) &&
+ (info->flags & ASYNC_CTS_FLOW)) {
+ if (info->tty->hw_stopped) {
+ if (mdm_status & CyCTS) {
+ /* cy_start isn't used
+ because... !!! */
+ info->tty->hw_stopped = 0;
+ cy_writeb(base_addr +
+ (CySRER << index),
+ cy_readb(base_addr +
+ (CySRER <<
+ index))|
+ CyTxRdy);
+ cy_sched_event(info,
+ Cy_EVENT_WRITE_WAKEUP);
+ }
+ } else {
+ if (!(mdm_status & CyCTS)) {
+ /* cy_stop isn't used
+ because ... !!! */
+ info->tty->hw_stopped = 1;
+ cy_writeb(base_addr +
+ (CySRER << index),
+ cy_readb(base_addr +
+ (CySRER <<
+ index)) &
+ ~CyTxRdy);
+ }
+ }
+ }
+ if (mdm_change & CyDSR) {
+ }
+ if (mdm_change & CyRI) {
+ }
+ }
+ /* end of service */
+ cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f));
+ cy_writeb(base_addr + (CyCAR << index), save_car);
+ spin_unlock(&cinfo->card_lock);
+ }
+}
+
+/* The real interrupt service routine is called
+ whenever the card wants its hand held--chars
+ received, out buffer empty, modem change, etc.
+ */
+static irqreturn_t cyy_interrupt(int irq, void *dev_id)
+{
+ int status;
+ struct cyclades_card *cinfo;
+ void __iomem *base_addr, *card_base_addr;
+ int chip;
+ int index;
+ int too_many;
+ int had_work;
+
+ if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
+#ifdef CY_DEBUG_INTERRUPTS
+ printk("cyy_interrupt: spurious interrupt %d\n\r", irq);
+#endif
+ return IRQ_NONE; /* spurious interrupt */
+ }
+
+ card_base_addr = cinfo->base_addr;
+ index = cinfo->bus_index;
- cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
+ /* This loop checks all chips in the card. Make a note whenever
+ _any_ chip had some work to do, as this is considered an
+ indication that there will be more to do. Only when no chip
+ has any work does this outermost loop exit.
+ */
+ do {
+ had_work = 0;
+ for (chip = 0; chip < cinfo->num_chips; chip++) {
+ base_addr = cinfo->base_addr +
+ (cy_chip_offset[chip] << index);
+ too_many = 0;
+ while ((status = cy_readb(base_addr +
+ (CySVRR << index))) != 0x00) {
+ had_work++;
+ /* The purpose of the following test is to ensure that
+ no chip can monopolize the driver. This forces the
+ chips to be checked in a round-robin fashion (after
+ draining each of a bunch (1000) of characters).
+ */
+ if (1000 < too_many++) {
+ break;
+ }
+ cyy_intr_chip(cinfo, chip, base_addr, status,
+ index);
}
+ }
+ } while (had_work);
- if((mdm_change & CyDCD)
- && (info->flags & ASYNC_CHECK_CD)){
- if(mdm_status & CyDCD){
- cy_sched_event(info,
- Cy_EVENT_OPEN_WAKEUP);
- }else{
- cy_sched_event(info,
- Cy_EVENT_HANGUP);
- }
- }
- if((mdm_change & CyCTS)
- && (info->flags & ASYNC_CTS_FLOW)){
- if(info->tty->hw_stopped){
- if(mdm_status & CyCTS){
- /* cy_start isn't used
- because... !!! */
- info->tty->hw_stopped = 0;
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) |
- CyTxRdy);
- cy_sched_event(info,
- Cy_EVENT_WRITE_WAKEUP);
- }
- }else{
- if(!(mdm_status & CyCTS)){
- /* cy_stop isn't used
- because ... !!! */
- info->tty->hw_stopped = 1;
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) &
- ~CyTxRdy);
- }
- }
- }
- if(mdm_change & CyDSR){
- }
- if(mdm_change & CyRI){
- }
- }
- /* end of service */
- cy_writeb(base_addr+(CyMIR<<index),
- (save_xir & 0x3f));
- cy_writeb(base_addr+(CyCAR<<index), save_car);
- spin_unlock(&cinfo->card_lock);
- }
- } /* end while status != 0 */
- } /* end loop for chips... */
- } while(had_work);
-
- /* clear interrupts */
- spin_lock(&cinfo->card_lock);
- cy_writeb(card_base_addr + (Cy_ClrIntr<<index), 0);
- /* Cy_ClrIntr is 0x1800 */
- spin_unlock(&cinfo->card_lock);
- return IRQ_HANDLED;
-} /* cyy_interrupt */
+ /* clear interrupts */
+ spin_lock(&cinfo->card_lock);
+ cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
+ /* Cy_ClrIntr is 0x1800 */
+ spin_unlock(&cinfo->card_lock);
+ return IRQ_HANDLED;
+} /* cyy_interrupt */
/***********************************************************/
/********* End of block of Cyclom-Y specific code **********/
@@ -1448,643 +1496,655 @@ cyy_interrupt(int irq, void *dev_id)
/***********************************************************/
static int
-cyz_fetch_msg( struct cyclades_card *cinfo,
- uclong *channel, ucchar *cmd, uclong *param)
+cyz_fetch_msg(struct cyclades_card *cinfo,
+ uclong * channel, ucchar * cmd, uclong * param)
{
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- unsigned long loc_doorbell;
-
- firm_id = cinfo->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)){
- return (-1);
- }
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
-
- loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *)
- (cinfo->ctl_addr))->loc_doorbell);
- if (loc_doorbell){
- *cmd = (char)(0xff & loc_doorbell);
- *channel = cy_readl(&board_ctrl->fwcmd_channel);
- *param = (uclong)cy_readl(&board_ctrl->fwcmd_param);
- cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->loc_doorbell,
- 0xffffffff);
- return 1;
- }
- return 0;
-} /* cyz_fetch_msg */
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ unsigned long loc_doorbell;
+
+ firm_id = cinfo->base_addr + ID_ADDRESS;
+ if (!ISZLOADED(*cinfo)) {
+ return -1;
+ }
+ zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *)
+ (cinfo->ctl_addr))->loc_doorbell);
+ if (loc_doorbell) {
+ *cmd = (char)(0xff & loc_doorbell);
+ *channel = cy_readl(&board_ctrl->fwcmd_channel);
+ *param = (uclong) cy_readl(&board_ctrl->fwcmd_param);
+ cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
+ loc_doorbell, 0xffffffff);
+ return 1;
+ }
+ return 0;
+} /* cyz_fetch_msg */
static int
-cyz_issue_cmd( struct cyclades_card *cinfo,
- uclong channel, ucchar cmd, uclong param)
+cyz_issue_cmd(struct cyclades_card *cinfo,
+ uclong channel, ucchar cmd, uclong param)
{
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- unsigned long __iomem *pci_doorbell;
- int index;
-
- firm_id = cinfo->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)){
- return (-1);
- }
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
-
- index = 0;
- pci_doorbell = &((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->pci_doorbell;
- while( (cy_readl(pci_doorbell) & 0xff) != 0){
- if (index++ == 1000){
- return((int)(cy_readl(pci_doorbell) & 0xff));
- }
- udelay(50L);
- }
- cy_writel(&board_ctrl->hcmd_channel, channel);
- cy_writel(&board_ctrl->hcmd_param , param);
- cy_writel(pci_doorbell, (long)cmd);
-
- return(0);
-} /* cyz_issue_cmd */
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ unsigned long __iomem *pci_doorbell;
+ int index;
+
+ firm_id = cinfo->base_addr + ID_ADDRESS;
+ if (!ISZLOADED(*cinfo)) {
+ return -1;
+ }
+ zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ index = 0;
+ pci_doorbell =
+ &((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
+ while ((cy_readl(pci_doorbell) & 0xff) != 0) {
+ if (index++ == 1000) {
+ return (int)(cy_readl(pci_doorbell) & 0xff);
+ }
+ udelay(50L);
+ }
+ cy_writel(&board_ctrl->hcmd_channel, channel);
+ cy_writel(&board_ctrl->hcmd_param, param);
+ cy_writel(pci_doorbell, (long)cmd);
+
+ return 0;
+} /* cyz_issue_cmd */
static void
cyz_handle_rx(struct cyclades_port *info,
- volatile struct CH_CTRL __iomem *ch_ctrl,
- volatile struct BUF_CTRL __iomem *buf_ctrl)
+ volatile struct CH_CTRL __iomem * ch_ctrl,
+ volatile struct BUF_CTRL __iomem * buf_ctrl)
{
- struct cyclades_card *cinfo = &cy_card[info->card];
- struct tty_struct *tty = info->tty;
- volatile int char_count;
- int len;
+ struct cyclades_card *cinfo = &cy_card[info->card];
+ struct tty_struct *tty = info->tty;
+ volatile int char_count;
+ int len;
#ifdef BLOCKMOVE
- int small_count;
+ int small_count;
#else
- char data;
+ char data;
#endif
- volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
+ volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
- rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get);
- rx_put = cy_readl(&buf_ctrl->rx_put);
- rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
- rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr);
- if (rx_put >= rx_get)
- char_count = rx_put - rx_get;
- else
- char_count = rx_put - rx_get + rx_bufsize;
+ rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get);
+ rx_put = cy_readl(&buf_ctrl->rx_put);
+ rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
+ rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr);
+ if (rx_put >= rx_get)
+ char_count = rx_put - rx_get;
+ else
+ char_count = rx_put - rx_get + rx_bufsize;
- if ( char_count ) {
- info->last_active = jiffies;
- info->jiffies[1] = jiffies;
+ if (char_count) {
+ info->last_active = jiffies;
+ info->jiffies[1] = jiffies;
#ifdef CY_ENABLE_MONITORING
- info->mon.int_count++;
- info->mon.char_count += char_count;
- if (char_count > info->mon.char_max)
- info->mon.char_max = char_count;
- info->mon.char_last = char_count;
+ info->mon.int_count++;
+ info->mon.char_count += char_count;
+ if (char_count > info->mon.char_max)
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
#endif
- if(tty == 0){
- /* flush received characters */
- new_rx_get = (new_rx_get + char_count) & (rx_bufsize - 1);
- info->rflush_count++;
- }else{
+ if (tty == 0) {
+ /* flush received characters */
+ new_rx_get = (new_rx_get + char_count) &
+ (rx_bufsize - 1);
+ info->rflush_count++;
+ } else {
#ifdef BLOCKMOVE
- /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
- for performance, but because of buffer boundaries, there
- may be several steps to the operation */
- while(0 < (small_count =
- min_t(unsigned int, (rx_bufsize - new_rx_get),
- min_t(unsigned int, (TTY_FLIPBUF_SIZE - tty->flip.count), char_count))
- )) {
- memcpy_fromio(tty->flip.char_buf_ptr,
- (char *)(cinfo->base_addr
- + rx_bufaddr + new_rx_get),
- small_count);
-
- tty->flip.char_buf_ptr += small_count;
- memset(tty->flip.flag_buf_ptr, TTY_NORMAL, small_count);
- tty->flip.flag_buf_ptr += small_count;
- new_rx_get = (new_rx_get + small_count) & (rx_bufsize - 1);
- char_count -= small_count;
- info->icount.rx += small_count;
- info->idle_stats.recv_bytes += small_count;
- tty->flip.count += small_count;
- }
+ /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
+ for performance, but because of buffer boundaries, there
+ may be several steps to the operation */
+ while (0 < (small_count = min_t(unsigned int,
+ rx_bufsize - new_rx_get,
+ min_t(unsigned int, TTY_FLIPBUF_SIZE -
+ tty->flip.count, char_count)))){
+ memcpy_fromio(tty->flip.char_buf_ptr,
+ (char *)(cinfo->base_addr + rx_bufaddr +
+ new_rx_get),
+ small_count);
+
+ tty->flip.char_buf_ptr += small_count;
+ memset(tty->flip.flag_buf_ptr, TTY_NORMAL,
+ small_count);
+ tty->flip.flag_buf_ptr += small_count;
+ new_rx_get = (new_rx_get + small_count) &
+ (rx_bufsize - 1);
+ char_count -= small_count;
+ info->icount.rx += small_count;
+ info->idle_stats.recv_bytes += small_count;
+ tty->flip.count += small_count;
+ }
#else
- len = tty_buffer_request_room(tty, char_count);
- while(len--){
- data = cy_readb(cinfo->base_addr + rx_bufaddr + new_rx_get);
- new_rx_get = (new_rx_get + 1) & (rx_bufsize - 1);
- tty_insert_flip_char(tty, data, TTY_NORMAL);
- info->idle_stats.recv_bytes++;
- info->icount.rx++;
- }
+ len = tty_buffer_request_room(tty, char_count);
+ while (len--) {
+ data = cy_readb(cinfo->base_addr + rx_bufaddr +
+ new_rx_get);
+ new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1);
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
+ info->idle_stats.recv_bytes++;
+ info->icount.rx++;
+ }
#endif
#ifdef CONFIG_CYZ_INTR
- /* Recalculate the number of chars in the RX buffer and issue
- a cmd in case it's higher than the RX high water mark */
- rx_put = cy_readl(&buf_ctrl->rx_put);
- if (rx_put >= rx_get)
- char_count = rx_put - rx_get;
- else
- char_count = rx_put - rx_get + rx_bufsize;
- if(char_count >= cy_readl(&buf_ctrl->rx_threshold)) {
- cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
- }
+ /* Recalculate the number of chars in the RX buffer and issue
+ a cmd in case it's higher than the RX high water mark */
+ rx_put = cy_readl(&buf_ctrl->rx_put);
+ if (rx_put >= rx_get)
+ char_count = rx_put - rx_get;
+ else
+ char_count = rx_put - rx_get + rx_bufsize;
+ if (char_count >= (int)cy_readl(&buf_ctrl->
+ rx_threshold)) {
+ cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
+ }
#endif
- info->idle_stats.recv_idle = jiffies;
- tty_schedule_flip(tty);
+ info->idle_stats.recv_idle = jiffies;
+ tty_schedule_flip(tty);
+ }
+ /* Update rx_get */
+ cy_writel(&buf_ctrl->rx_get, new_rx_get);
}
- /* Update rx_get */
- cy_writel(&buf_ctrl->rx_get, new_rx_get);
- }
}
static void
cyz_handle_tx(struct cyclades_port *info,
- volatile struct CH_CTRL __iomem *ch_ctrl,
- volatile struct BUF_CTRL __iomem *buf_ctrl)
+ volatile struct CH_CTRL __iomem * ch_ctrl,
+ volatile struct BUF_CTRL __iomem * buf_ctrl)
{
- struct cyclades_card *cinfo = &cy_card[info->card];
- struct tty_struct *tty = info->tty;
- char data;
- volatile int char_count;
+ struct cyclades_card *cinfo = &cy_card[info->card];
+ struct tty_struct *tty = info->tty;
+ char data;
+ volatile int char_count;
#ifdef BLOCKMOVE
- int small_count;
+ int small_count;
#endif
- volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr;
+ volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr;
- if (info->xmit_cnt <= 0) /* Nothing to transmit */
- return;
+ if (info->xmit_cnt <= 0) /* Nothing to transmit */
+ return;
- tx_get = cy_readl(&buf_ctrl->tx_get);
- tx_put = cy_readl(&buf_ctrl->tx_put);
- tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
- tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr);
- if (tx_put >= tx_get)
- char_count = tx_get - tx_put - 1 + tx_bufsize;
- else
- char_count = tx_get - tx_put - 1;
+ tx_get = cy_readl(&buf_ctrl->tx_get);
+ tx_put = cy_readl(&buf_ctrl->tx_put);
+ tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+ tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr);
+ if (tx_put >= tx_get)
+ char_count = tx_get - tx_put - 1 + tx_bufsize;
+ else
+ char_count = tx_get - tx_put - 1;
- if ( char_count ) {
+ if (char_count) {
- if( tty == 0 ){
- goto ztxdone;
- }
+ if (tty == 0) {
+ goto ztxdone;
+ }
- if(info->x_char) { /* send special char */
- data = info->x_char;
+ if (info->x_char) { /* send special char */
+ data = info->x_char;
- cy_writeb((cinfo->base_addr + tx_bufaddr + tx_put), data);
- tx_put = (tx_put + 1) & (tx_bufsize - 1);
- info->x_char = 0;
- char_count--;
- info->icount.tx++;
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
- }
+ cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
+ tx_put = (tx_put + 1) & (tx_bufsize - 1);
+ info->x_char = 0;
+ char_count--;
+ info->icount.tx++;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
#ifdef BLOCKMOVE
- while(0 < (small_count =
- min_t(unsigned int, (tx_bufsize - tx_put),
- min_t(unsigned int, (SERIAL_XMIT_SIZE - info->xmit_tail),
- min_t(unsigned int, info->xmit_cnt, char_count))))) {
-
- memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put),
- &info->xmit_buf[info->xmit_tail],
- small_count);
-
- tx_put = (tx_put + small_count) & (tx_bufsize - 1);
- char_count -= small_count;
- info->icount.tx += small_count;
- info->xmit_cnt -= small_count;
- info->xmit_tail =
- (info->xmit_tail + small_count) & (SERIAL_XMIT_SIZE - 1);
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
- }
+ while (0 < (small_count = min_t(unsigned int,
+ tx_bufsize - tx_put, min_t(unsigned int,
+ (SERIAL_XMIT_SIZE - info->xmit_tail),
+ min_t(unsigned int, info->xmit_cnt,
+ char_count))))) {
+
+ memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
+ tx_put),
+ &info->xmit_buf[info->xmit_tail],
+ small_count);
+
+ tx_put = (tx_put + small_count) & (tx_bufsize - 1);
+ char_count -= small_count;
+ info->icount.tx += small_count;
+ info->xmit_cnt -= small_count;
+ info->xmit_tail = (info->xmit_tail + small_count) &
+ (SERIAL_XMIT_SIZE - 1);
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
#else
- while (info->xmit_cnt && char_count){
- data = info->xmit_buf[info->xmit_tail];
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
-
- cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
- tx_put = (tx_put + 1) & (tx_bufsize - 1);
- char_count--;
- info->icount.tx++;
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
- }
+ while (info->xmit_cnt && char_count) {
+ data = info->xmit_buf[info->xmit_tail];
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1) &
+ (SERIAL_XMIT_SIZE - 1);
+
+ cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
+ tx_put = (tx_put + 1) & (tx_bufsize - 1);
+ char_count--;
+ info->icount.tx++;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
#endif
- ztxdone:
- if (info->xmit_cnt < WAKEUP_CHARS) {
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ztxdone:
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ }
+ /* Update tx_put */
+ cy_writel(&buf_ctrl->tx_put, tx_put);
}
- /* Update tx_put */
- cy_writel(&buf_ctrl->tx_put, tx_put);
- }
}
-static void
-cyz_handle_cmd(struct cyclades_card *cinfo)
+static void cyz_handle_cmd(struct cyclades_card *cinfo)
{
- struct tty_struct *tty;
- struct cyclades_port *info;
- static volatile struct FIRM_ID __iomem *firm_id;
- static volatile struct ZFW_CTRL __iomem *zfw_ctrl;
- static volatile struct BOARD_CTRL __iomem *board_ctrl;
- static volatile struct CH_CTRL __iomem *ch_ctrl;
- static volatile struct BUF_CTRL __iomem *buf_ctrl;
- uclong channel;
- ucchar cmd;
- uclong param;
- uclong hw_ver, fw_ver;
- int special_count;
- int delta_count;
-
- firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- fw_ver = cy_readl(&board_ctrl->fw_version);
- hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->mail_box_0);
-
-
- while(cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
- special_count = 0;
- delta_count = 0;
- info = &cy_port[channel + cinfo->first_line];
- if((tty = info->tty) == 0) {
- continue;
- }
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
-
- switch(cmd) {
- case C_CM_PR_ERROR:
- tty_insert_flip_char(tty, 0, TTY_PARITY);
- info->icount.rx++;
- special_count++;
- break;
- case C_CM_FR_ERROR:
- tty_insert_flip_char(tty, 0, TTY_FRAME);
- info->icount.rx++;
- special_count++;
- break;
- case C_CM_RXBRK:
- tty_insert_flip_char(tty, 0, TTY_BREAK);
- info->icount.rx++;
- special_count++;
- break;
- case C_CM_MDCD:
- info->icount.dcd++;
- delta_count++;
- if (info->flags & ASYNC_CHECK_CD){
- if ((fw_ver > 241 ?
- ((u_long)param) :
- cy_readl(&ch_ctrl->rs_status)) & C_RS_DCD) {
- cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
- }else{
- cy_sched_event(info, Cy_EVENT_HANGUP);
- }
+ struct tty_struct *tty;
+ struct cyclades_port *info;
+ static volatile struct FIRM_ID __iomem *firm_id;
+ static volatile struct ZFW_CTRL __iomem *zfw_ctrl;
+ static volatile struct BOARD_CTRL __iomem *board_ctrl;
+ static volatile struct CH_CTRL __iomem *ch_ctrl;
+ static volatile struct BUF_CTRL __iomem *buf_ctrl;
+ uclong channel;
+ ucchar cmd;
+ uclong param;
+ uclong hw_ver, fw_ver;
+ int special_count;
+ int delta_count;
+
+ firm_id = cinfo->base_addr + ID_ADDRESS;
+ zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ fw_ver = cy_readl(&board_ctrl->fw_version);
+ hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
+ mail_box_0);
+
+ while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
+ special_count = 0;
+ delta_count = 0;
+ info = &cy_port[channel + cinfo->first_line];
+ if ((tty = info->tty) == 0) {
+ continue;
}
- break;
- case C_CM_MCTS:
- info->icount.cts++;
- delta_count++;
- break;
- case C_CM_MRI:
- info->icount.rng++;
- delta_count++;
- break;
- case C_CM_MDSR:
- info->icount.dsr++;
- delta_count++;
- break;
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+ switch (cmd) {
+ case C_CM_PR_ERROR:
+ tty_insert_flip_char(tty, 0, TTY_PARITY);
+ info->icount.rx++;
+ special_count++;
+ break;
+ case C_CM_FR_ERROR:
+ tty_insert_flip_char(tty, 0, TTY_FRAME);
+ info->icount.rx++;
+ special_count++;
+ break;
+ case C_CM_RXBRK:
+ tty_insert_flip_char(tty, 0, TTY_BREAK);
+ info->icount.rx++;
+ special_count++;
+ break;
+ case C_CM_MDCD:
+ info->icount.dcd++;
+ delta_count++;
+ if (info->flags & ASYNC_CHECK_CD) {
+ if ((fw_ver > 241 ? ((u_long) param) :
+ cy_readl(&ch_ctrl->rs_status)) &
+ C_RS_DCD) {
+ cy_sched_event(info,
+ Cy_EVENT_OPEN_WAKEUP);
+ } else {
+ cy_sched_event(info, Cy_EVENT_HANGUP);
+ }
+ }
+ break;
+ case C_CM_MCTS:
+ info->icount.cts++;
+ delta_count++;
+ break;
+ case C_CM_MRI:
+ info->icount.rng++;
+ delta_count++;
+ break;
+ case C_CM_MDSR:
+ info->icount.dsr++;
+ delta_count++;
+ break;
#ifdef Z_WAKE
- case C_CM_IOCTLW:
- cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
- break;
+ case C_CM_IOCTLW:
+ cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+ break;
#endif
#ifdef CONFIG_CYZ_INTR
- case C_CM_RXHIWM:
- case C_CM_RXNNDT:
- case C_CM_INTBACK2:
- /* Reception Interrupt */
+ case C_CM_RXHIWM:
+ case C_CM_RXNNDT:
+ case C_CM_INTBACK2:
+ /* Reception Interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: rcvd intr, card %d, port %ld\n\r",
- info->card, channel);
+ printk("cyz_interrupt: rcvd intr, card %d, "
+ "port %ld\n\r", info->card, channel);
#endif
- cyz_handle_rx(info, ch_ctrl, buf_ctrl);
- break;
- case C_CM_TXBEMPTY:
- case C_CM_TXLOWWM:
- case C_CM_INTBACK:
- /* Transmission Interrupt */
+ cyz_handle_rx(info, ch_ctrl, buf_ctrl);
+ break;
+ case C_CM_TXBEMPTY:
+ case C_CM_TXLOWWM:
+ case C_CM_INTBACK:
+ /* Transmission Interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: xmit intr, card %d, port %ld\n\r",
- info->card, channel);
+ printk("cyz_interrupt: xmit intr, card %d, "
+ "port %ld\n\r", info->card, channel);
#endif
- cyz_handle_tx(info, ch_ctrl, buf_ctrl);
- break;
-#endif /* CONFIG_CYZ_INTR */
- case C_CM_FATAL:
- /* should do something with this !!! */
- break;
- default:
- break;
+ cyz_handle_tx(info, ch_ctrl, buf_ctrl);
+ break;
+#endif /* CONFIG_CYZ_INTR */
+ case C_CM_FATAL:
+ /* should do something with this !!! */
+ break;
+ default:
+ break;
+ }
+ if (delta_count)
+ cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
+ if (special_count)
+ tty_schedule_flip(tty);
}
- if(delta_count)
- cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
- if(special_count)
- tty_schedule_flip(tty);
- }
}
#ifdef CONFIG_CYZ_INTR
-static irqreturn_t
-cyz_interrupt(int irq, void *dev_id)
+static irqreturn_t cyz_interrupt(int irq, void *dev_id)
{
- struct cyclades_card *cinfo;
+ struct cyclades_card *cinfo;
- if((cinfo = (struct cyclades_card *)dev_id) == 0){
+ if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: spurious interrupt %d\n\r", irq);
+ printk("cyz_interrupt: spurious interrupt %d\n\r", irq);
#endif
- return IRQ_NONE; /* spurious interrupt */
- }
+ return IRQ_NONE; /* spurious interrupt */
+ }
- if (!ISZLOADED(*cinfo)) {
+ if (!ISZLOADED(*cinfo)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: board not yet loaded (IRQ%d).\n\r", irq);
+ printk("cyz_interrupt: board not yet loaded (IRQ%d).\n\r", irq);
#endif
- return IRQ_NONE;
- }
+ return IRQ_NONE;
+ }
- /* Handle the interrupts */
- cyz_handle_cmd(cinfo);
+ /* Handle the interrupts */
+ cyz_handle_cmd(cinfo);
- return IRQ_HANDLED;
-} /* cyz_interrupt */
+ return IRQ_HANDLED;
+} /* cyz_interrupt */
-static void
-cyz_rx_restart(unsigned long arg)
+static void cyz_rx_restart(unsigned long arg)
{
- struct cyclades_port *info = (struct cyclades_port *)arg;
- int retval;
- int card = info->card;
- uclong channel = (info->line) - (cy_card[card].first_line);
- unsigned long flags;
-
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L);
- if (retval != 0){
- printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n",
- info->line, retval);
- }
- cyz_rx_full_timer[info->line].function = NULL;
- CY_UNLOCK(info, flags);
+ struct cyclades_port *info = (struct cyclades_port *)arg;
+ int retval;
+ int card = info->card;
+ uclong channel = (info->line) - (cy_card[card].first_line);
+ unsigned long flags;
+
+ CY_LOCK(info, flags);
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L);
+ if (retval != 0) {
+ printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+ cyz_rx_full_timer[info->line].function = NULL;
+ CY_UNLOCK(info, flags);
}
-#else /* CONFIG_CYZ_INTR */
+#else /* CONFIG_CYZ_INTR */
-static void
-cyz_poll(unsigned long arg)
+static void cyz_poll(unsigned long arg)
{
- struct cyclades_card *cinfo;
- struct cyclades_port *info;
- struct tty_struct *tty;
- static volatile struct FIRM_ID *firm_id;
- static volatile struct ZFW_CTRL *zfw_ctrl;
- static volatile struct BOARD_CTRL *board_ctrl;
- static volatile struct CH_CTRL *ch_ctrl;
- static volatile struct BUF_CTRL *buf_ctrl;
- int card, port;
-
- cyz_timerlist.expires = jiffies + (HZ);
- for (card = 0 ; card < NR_CARDS ; card++){
- cinfo = &cy_card[card];
-
- if (!IS_CYC_Z(*cinfo)) continue;
- if (!ISZLOADED(*cinfo)) continue;
+ struct cyclades_card *cinfo;
+ struct cyclades_port *info;
+ struct tty_struct *tty;
+ static volatile struct FIRM_ID *firm_id;
+ static volatile struct ZFW_CTRL *zfw_ctrl;
+ static volatile struct BOARD_CTRL *board_ctrl;
+ static volatile struct CH_CTRL *ch_ctrl;
+ static volatile struct BUF_CTRL *buf_ctrl;
+ int card, port;
- firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &(zfw_ctrl->board_ctrl);
+ cyz_timerlist.expires = jiffies + (HZ);
+ for (card = 0; card < NR_CARDS; card++) {
+ cinfo = &cy_card[card];
+
+ if (!IS_CYC_Z(*cinfo))
+ continue;
+ if (!ISZLOADED(*cinfo))
+ continue;
+
+ firm_id = cinfo->base_addr + ID_ADDRESS;
+ zfw_ctrl = cinfo->base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &(zfw_ctrl->board_ctrl);
/* Skip first polling cycle to avoid racing conditions with the FW */
- if (!cinfo->intr_enabled) {
- cinfo->nports = (int) cy_readl(&board_ctrl->n_channel);
- cinfo->intr_enabled = 1;
- continue;
- }
+ if (!cinfo->intr_enabled) {
+ cinfo->nports = (int)cy_readl(&board_ctrl->n_channel);
+ cinfo->intr_enabled = 1;
+ continue;
+ }
- cyz_handle_cmd(cinfo);
+ cyz_handle_cmd(cinfo);
- for (port = 0 ; port < cinfo->nports ; port++) {
- info = &cy_port[ port + cinfo->first_line ];
- tty = info->tty;
- ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
+ for (port = 0; port < cinfo->nports; port++) {
+ info = &cy_port[port + cinfo->first_line];
+ tty = info->tty;
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
- if (!info->throttle)
- cyz_handle_rx(info, ch_ctrl, buf_ctrl);
- cyz_handle_tx(info, ch_ctrl, buf_ctrl);
+ if (!info->throttle)
+ cyz_handle_rx(info, ch_ctrl, buf_ctrl);
+ cyz_handle_tx(info, ch_ctrl, buf_ctrl);
+ }
+ /* poll every 'cyz_polling_cycle' period */
+ cyz_timerlist.expires = jiffies + cyz_polling_cycle;
}
- /* poll every 'cyz_polling_cycle' period */
- cyz_timerlist.expires = jiffies + cyz_polling_cycle;
- }
- add_timer(&cyz_timerlist);
+ add_timer(&cyz_timerlist);
+} /* cyz_poll */
- return;
-} /* cyz_poll */
-
-#endif /* CONFIG_CYZ_INTR */
+#endif /* CONFIG_CYZ_INTR */
/********** End of block of Cyclades-Z specific code *********/
/***********************************************************/
-
/* This is called whenever a port becomes active;
interrupts are enabled and DTR & RTS are turned on.
*/
-static int
-startup(struct cyclades_port * info)
+static int startup(struct cyclades_port *info)
{
- unsigned long flags;
- int retval = 0;
- void __iomem *base_addr;
- int card,chip,channel,index;
- unsigned long page;
+ unsigned long flags;
+ int retval = 0;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
+ unsigned long page;
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
+ page = get_zeroed_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
- CY_LOCK(info, flags);
+ CY_LOCK(info, flags);
- if (info->flags & ASYNC_INITIALIZED){
- free_page(page);
- goto errout;
- }
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ goto errout;
+ }
- if (!info->type){
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- free_page(page);
- goto errout;
- }
+ if (!info->type) {
+ if (info->tty) {
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ free_page(page);
+ goto errout;
+ }
- if (info->xmit_buf)
- free_page(page);
- else
- info->xmit_buf = (unsigned char *) page;
+ if (info->xmit_buf)
+ free_page(page);
+ else
+ info->xmit_buf = (unsigned char *)page;
- CY_UNLOCK(info, flags);
+ CY_UNLOCK(info, flags);
- set_line_char(info);
+ set_line_char(info);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
#ifdef CY_DEBUG_OPEN
- printk("cyc startup card %d, chip %d, channel %d, base_addr %lx\n",
- card, chip, channel, (long)base_addr);/**/
+ printk("cyc startup card %d, chip %d, channel %d, "
+ "base_addr %lx\n",
+ card, chip, channel, (long)base_addr);
+ /**/
#endif
+ CY_LOCK(info, flags);
- CY_LOCK(info, flags);
-
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- cy_writeb(base_addr+(CyRTPR<<index), (info->default_timeout
- ? info->default_timeout : 0x02)); /* 10ms rx timeout */
+ cy_writeb(base_addr + (CyRTPR << index),
+ (info->default_timeout ? info->default_timeout : 0x02));
+ /* 10ms rx timeout */
- cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
+ cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,
+ index);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);
+ cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:startup raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:startup raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyRxData);
- info->flags |= ASYNC_INITIALIZED;
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) | CyRxData);
+ info->flags |= ASYNC_INITIALIZED;
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- info->breakon = info->breakoff = 0;
- memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
- info->idle_stats.in_use =
- info->idle_stats.recv_idle =
- info->idle_stats.xmit_idle = jiffies;
+ if (info->tty) {
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->breakon = info->breakoff = 0;
+ memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
+ info->idle_stats.in_use =
+ info->idle_stats.recv_idle =
+ info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
+ CY_UNLOCK(info, flags);
- } else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
+ } else {
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+ int retval;
- base_addr = cy_card[card].base_addr;
+ base_addr = cy_card[card].base_addr;
- firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])){
- return -ENODEV;
- }
+ firm_id = base_addr + ID_ADDRESS;
+ if (!ISZLOADED(cy_card[card])) {
+ return -ENODEV;
+ }
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
#ifdef CY_DEBUG_OPEN
- printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
- card, channel, (long)base_addr);/**/
+ printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
+ card, channel, (long)base_addr);
+ /**/
#endif
+ CY_LOCK(info, flags);
- CY_LOCK(info, flags);
-
- cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
+ cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
#ifdef Z_WAKE
#ifdef CONFIG_CYZ_INTR
- cy_writel(&ch_ctrl[channel].intr_enable,
- C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT|
- C_IN_IOCTLW|
- C_IN_MDCD);
+ cy_writel(&ch_ctrl[channel].intr_enable,
+ C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
+ C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
#else
- cy_writel(&ch_ctrl[channel].intr_enable,
- C_IN_IOCTLW|
- C_IN_MDCD);
-#endif /* CONFIG_CYZ_INTR */
+ cy_writel(&ch_ctrl[channel].intr_enable,
+ C_IN_IOCTLW | C_IN_MDCD);
+#endif /* CONFIG_CYZ_INTR */
#else
#ifdef CONFIG_CYZ_INTR
- cy_writel(&ch_ctrl[channel].intr_enable,
- C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT|
- C_IN_MDCD);
+ cy_writel(&ch_ctrl[channel].intr_enable,
+ C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
+ C_IN_RXNNDT | C_IN_MDCD);
#else
- cy_writel(&ch_ctrl[channel].intr_enable,
- C_IN_MDCD);
-#endif /* CONFIG_CYZ_INTR */
-#endif /* Z_WAKE */
-
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
- if (retval != 0){
- printk("cyc:startup(1) retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD);
+#endif /* CONFIG_CYZ_INTR */
+#endif /* Z_WAKE */
+
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
+ if (retval != 0) {
+ printk("cyc:startup(1) retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
- /* Flush RX buffers before raising DTR and RTS */
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX, 0L);
- if (retval != 0){
- printk("cyc:startup(2) retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ /* Flush RX buffers before raising DTR and RTS */
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX,
+ 0L);
+ if (retval != 0) {
+ printk("cyc:startup(2) retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
- /* set timeout !!! */
- /* set RTS and DTR !!! */
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | C_RS_DTR) ;
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM, 0L);
- if (retval != 0){
- printk("cyc:startup(3) retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ /* set timeout !!! */
+ /* set RTS and DTR !!! */
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
+ C_RS_DTR);
+ retval = cyz_issue_cmd(&cy_card[info->card], channel,
+ C_CM_IOCTLM, 0L);
+ if (retval != 0) {
+ printk("cyc:startup(3) retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:startup raising Z DTR\n");
+ printk("cyc:startup raising Z DTR\n");
#endif
- /* enable send, recv, modem !!! */
+ /* enable send, recv, modem !!! */
- info->flags |= ASYNC_INITIALIZED;
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- info->breakon = info->breakoff = 0;
- memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
- info->idle_stats.in_use =
- info->idle_stats.recv_idle =
- info->idle_stats.xmit_idle = jiffies;
+ info->flags |= ASYNC_INITIALIZED;
+ if (info->tty) {
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->breakon = info->breakoff = 0;
+ memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
+ info->idle_stats.in_use =
+ info->idle_stats.recv_idle =
+ info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
- }
+ CY_UNLOCK(info, flags);
+ }
#ifdef CY_DEBUG_OPEN
printk(" cyc startup done\n");
@@ -2094,165 +2154,165 @@ startup(struct cyclades_port * info)
errout:
CY_UNLOCK(info, flags);
return retval;
-} /* startup */
-
+} /* startup */
-static void
-start_xmit( struct cyclades_port *info )
+static void start_xmit(struct cyclades_port *info)
{
- unsigned long flags;
- void __iomem *base_addr;
- int card,chip,channel,index;
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ unsigned long flags;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), channel);
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyTxRdy);
- CY_UNLOCK(info, flags);
- } else {
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
+
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index), channel);
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
+ CY_UNLOCK(info, flags);
+ } else {
#ifdef CONFIG_CYZ_INTR
- int retval;
+ int retval;
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK, 0L);
- if (retval != 0){
- printk("cyc:start_xmit retval on ttyC%d was %x\n",
- info->line, retval);
- }
- CY_UNLOCK(info, flags);
-#else /* CONFIG_CYZ_INTR */
- /* Don't have to do anything at this time */
-#endif /* CONFIG_CYZ_INTR */
- }
-} /* start_xmit */
+ CY_LOCK(info, flags);
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK,
+ 0L);
+ if (retval != 0) {
+ printk("cyc:start_xmit retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+ CY_UNLOCK(info, flags);
+#else /* CONFIG_CYZ_INTR */
+ /* Don't have to do anything at this time */
+#endif /* CONFIG_CYZ_INTR */
+ }
+} /* start_xmit */
/*
* This routine shuts down a serial port; interrupts are disabled,
* and DTR is dropped if the hangup on close termio flag is on.
*/
-static void
-shutdown(struct cyclades_port * info)
+static void shutdown(struct cyclades_port *info)
{
- unsigned long flags;
- void __iomem *base_addr;
- int card,chip,channel,index;
-
- if (!(info->flags & ASYNC_INITIALIZED)){
- return;
- }
-
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ unsigned long flags;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
+
+ if (!(info->flags & ASYNC_INITIALIZED)) {
+ return;
+ }
+
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
#ifdef CY_DEBUG_OPEN
- printk("cyc shutdown Y card %d, chip %d, channel %d, base_addr %lx\n",
- card, chip, channel, (long)base_addr);
+ printk("cyc shutdown Y card %d, chip %d, channel %d, "
+ "base_addr %lx\n",
+ card, chip, channel, (long)base_addr);
#endif
- CY_LOCK(info, flags);
+ CY_LOCK(info, flags);
- /* Clear delta_msr_wait queue to avoid mem leaks. */
- wake_up_interruptible(&info->delta_msr_wait);
-
- if (info->xmit_buf){
- unsigned char * temp;
- temp = info->xmit_buf;
- info->xmit_buf = NULL;
- free_page((unsigned long) temp);
- }
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
- cy_writeb(base_addr+(CyMSVR1<<index), ~CyRTS);
- cy_writeb(base_addr+(CyMSVR2<<index), ~CyDTR);
+ /* Clear delta_msr_wait queue to avoid mem leaks. */
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ if (info->xmit_buf) {
+ unsigned char *temp;
+ temp = info->xmit_buf;
+ info->xmit_buf = NULL;
+ free_page((unsigned long)temp);
+ }
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
+ cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc shutdown dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc shutdown dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- }
- cyy_issue_cmd(base_addr,CyCHAN_CTL|CyDIS_RCVR,index);
- /* it may be appropriate to clear _XMIT at
- some later date (after testing)!!! */
-
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- info->flags &= ~ASYNC_INITIALIZED;
- CY_UNLOCK(info, flags);
- } else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
-
- base_addr = cy_card[card].base_addr;
+ }
+ cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
+ /* it may be appropriate to clear _XMIT at
+ some later date (after testing)!!! */
+
+ if (info->tty) {
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->flags &= ~ASYNC_INITIALIZED;
+ CY_UNLOCK(info, flags);
+ } else {
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+ int retval;
+
+ base_addr = cy_card[card].base_addr;
#ifdef CY_DEBUG_OPEN
- printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
- card, channel, (long)base_addr);
+ printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
+ card, channel, (long)base_addr);
#endif
- firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])) {
- return;
- }
+ firm_id = base_addr + ID_ADDRESS;
+ if (!ISZLOADED(cy_card[card])) {
+ return;
+ }
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
- CY_LOCK(info, flags);
+ CY_LOCK(info, flags);
- if (info->xmit_buf){
- unsigned char * temp;
- temp = info->xmit_buf;
- info->xmit_buf = NULL;
- free_page((unsigned long) temp);
- }
-
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
- cy_writel(&ch_ctrl[channel].rs_control,
- (uclong)(cy_readl(&ch_ctrl[channel].rs_control) &
- ~(C_RS_RTS | C_RS_DTR)));
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM, 0L);
- if (retval != 0){
- printk("cyc:shutdown retval on ttyC%d was %x\n",
- info->line, retval);
+ if (info->xmit_buf) {
+ unsigned char *temp;
+ temp = info->xmit_buf;
+ info->xmit_buf = NULL;
+ free_page((unsigned long)temp);
}
+
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ cy_writel(&ch_ctrl[channel].rs_control,
+ (uclong)(cy_readl(&ch_ctrl[channel].rs_control)&
+ ~(C_RS_RTS | C_RS_DTR)));
+ retval = cyz_issue_cmd(&cy_card[info->card], channel,
+ C_CM_IOCTLM, 0L);
+ if (retval != 0) {
+ printk("cyc:shutdown retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:shutdown dropping Z DTR\n");
+ printk("cyc:shutdown dropping Z DTR\n");
#endif
- }
-
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- info->flags &= ~ASYNC_INITIALIZED;
+ }
- CY_UNLOCK(info, flags);
- }
+ if (info->tty) {
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->flags &= ~ASYNC_INITIALIZED;
+
+ CY_UNLOCK(info, flags);
+ }
#ifdef CY_DEBUG_OPEN
- printk(" cyc shutdown done\n");
+ printk(" cyc shutdown done\n");
#endif
- return;
-} /* shutdown */
-
+} /* shutdown */
/*
* ------------------------------------------------------------
@@ -2261,527 +2321,546 @@ shutdown(struct cyclades_port * info)
*/
static int
-block_til_ready(struct tty_struct *tty, struct file * filp,
- struct cyclades_port *info)
+block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct cyclades_port *info)
{
- DECLARE_WAITQUEUE(wait, current);
- struct cyclades_card *cinfo;
- unsigned long flags;
- int chip, channel,index;
- int retval;
- void __iomem *base_addr;
-
- cinfo = &cy_card[info->card];
- channel = info->line - cinfo->first_line;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
+ DECLARE_WAITQUEUE(wait, current);
+ struct cyclades_card *cinfo;
+ unsigned long flags;
+ int chip, channel, index;
+ int retval;
+ void __iomem *base_addr;
+
+ cinfo = &cy_card[info->card];
+ channel = info->line - cinfo->first_line;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING) {
+ interruptible_sleep_on(&info->close_wait);
+ }
+ return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
+ }
+
+ /*
+ * If non-blocking mode is set, then make the check up front
+ * and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
}
- return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
- }
-
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * cy_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * cy_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
- info->line, info->count);/**/
+ printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
+ info->line, info->count);
+ /**/
#endif
- CY_LOCK(info, flags);
- if (!tty_hung_up_p(filp))
- info->count--;
- CY_UNLOCK(info, flags);
+ CY_LOCK(info, flags);
+ if (!tty_hung_up_p(filp))
+ info->count--;
+ CY_UNLOCK(info, flags);
#ifdef CY_DEBUG_COUNT
- printk("cyc block_til_ready: (%d): decrementing count to %d\n",
- current->pid, info->count);
+ printk("cyc block_til_ready: (%d): decrementing count to %d\n",
+ current->pid, info->count);
#endif
- info->blocked_open++;
-
- if (!IS_CYC_Z(*cinfo)) {
- chip = channel>>2;
- channel &= 0x03;
- index = cinfo->bus_index;
- base_addr = cinfo->base_addr + (cy_chip_offset[chip]<<index);
-
- while (1) {
- CY_LOCK(info, flags);
- if ((tty->termios->c_cflag & CBAUD)){
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
+ info->blocked_open++;
+
+ if (!IS_CYC_Z(*cinfo)) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cinfo->bus_index;
+ base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
+
+ while (1) {
+ CY_LOCK(info, flags);
+ if ((tty->termios->c_cflag & CBAUD)) {
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ CyRTS);
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:block_til_ready raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:block_til_ready raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr +
+ (CyMSVR1 << index)),
+ cy_readb(base_addr +
+ (CyMSVR2 << index)));
#endif
- }
- CY_UNLOCK(info, flags);
+ }
+ CY_UNLOCK(info, flags);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp)
- || !(info->flags & ASYNC_INITIALIZED) ){
- retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
- break;
- }
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ASYNC_INITIALIZED)) {
+ retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+ break;
+ }
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (!(info->flags & ASYNC_CLOSING)
- && (C_CLOCAL(tty)
- || (cy_readb(base_addr+(CyMSVR1<<index)) & CyDCD))) {
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
+ (cy_readb(base_addr +
+ (CyMSVR1 << index)) & CyDCD))) {
+ CY_UNLOCK(info, flags);
+ break;
+ }
CY_UNLOCK(info, flags);
- break;
- }
- CY_UNLOCK(info, flags);
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
- info->line, info->count);/**/
+ printk("cyc block_til_ready blocking: ttyC%d, "
+ "count = %d\n",
+ info->line, info->count);
+ /**/
#endif
- schedule();
- }
- } else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
-
- base_addr = cinfo->base_addr;
- firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)){
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- return -EINVAL;
- }
-
- zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
- while (1) {
- if ((tty->termios->c_cflag & CBAUD)){
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) |
- (C_RS_RTS | C_RS_DTR));
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM, 0L);
- if (retval != 0){
- printk("cyc:block_til_ready retval on ttyC%d was %x\n",
- info->line, retval);
+ schedule();
+ }
+ } else {
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+ int retval;
+
+ base_addr = cinfo->base_addr;
+ firm_id = base_addr + ID_ADDRESS;
+ if (!ISZLOADED(*cinfo)) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ return -EINVAL;
}
+
+ zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ while (1) {
+ if ((tty->termios->c_cflag & CBAUD)) {
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].
+ rs_control) | (C_RS_RTS |
+ C_RS_DTR));
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM, 0L);
+ if (retval != 0) {
+ printk("cyc:block_til_ready retval on "
+ "ttyC%d was %x\n",
+ info->line, retval);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:block_til_ready raising Z DTR\n");
+ printk("cyc:block_til_ready raising Z DTR\n");
#endif
- }
+ }
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp)
- || !(info->flags & ASYNC_INITIALIZED) ){
- retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
- break;
- }
- if (!(info->flags & ASYNC_CLOSING)
- && (C_CLOCAL(tty)
- || (cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD))) {
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ASYNC_INITIALIZED)) {
+ retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+ break;
+ }
+ if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
+ (cy_readl(&ch_ctrl[channel].rs_status) &
+ C_RS_DCD))) {
+ break;
+ }
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
- info->line, info->count);/**/
+ printk("cyc block_til_ready blocking: ttyC%d, "
+ "count = %d\n",
+ info->line, info->count);
+ /**/
#endif
- schedule();
+ schedule();
+ }
}
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp)){
- info->count++;
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp)) {
+ info->count++;
#ifdef CY_DEBUG_COUNT
- printk("cyc:block_til_ready (%d): incrementing count to %d\n",
- current->pid, info->count);
+ printk("cyc:block_til_ready (%d): incrementing count to %d\n",
+ current->pid, info->count);
#endif
- }
- info->blocked_open--;
+ }
+ info->blocked_open--;
#ifdef CY_DEBUG_OPEN
- printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
- info->line, info->count);/**/
+ printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
+ info->line, info->count);
+ /**/
#endif
- if (retval)
- return retval;
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-} /* block_til_ready */
-
+ if (retval)
+ return retval;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+} /* block_til_ready */
/*
* This routine is called whenever a serial port is opened. It
* performs the serial-specific initialization for the tty structure.
*/
-static int
-cy_open(struct tty_struct *tty, struct file * filp)
+static int cy_open(struct tty_struct *tty, struct file *filp)
{
- struct cyclades_port *info;
- int retval, line;
-
- line = tty->index;
- if ((line < 0) || (NR_PORTS <= line)){
- return -ENODEV;
- }
- info = &cy_port[line];
- if (info->line < 0){
- return -ENODEV;
- }
-
- /* If the card's firmware hasn't been loaded,
- treat it as absent from the system. This
- will make the user pay attention.
- */
- if (IS_CYC_Z(cy_card[info->card])) {
- struct cyclades_card *cinfo = &cy_card[info->card];
- struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
-
- if (!ISZLOADED(*cinfo)) {
- if (((ZE_V1 ==cy_readl(&((struct RUNTIME_9060 __iomem *)
- (cinfo->ctl_addr))->mail_box_0)) &&
- Z_FPGA_CHECK (*cinfo)) &&
- (ZFIRM_HLT == cy_readl (&firm_id->signature)))
- {
- printk ("cyc:Cyclades-Z Error: you need an external power supply for this number of ports.\n\rFirmware halted.\r\n");
- } else {
- printk("cyc:Cyclades-Z firmware not yet loaded\n");
- }
- return -ENODEV;
- }
-#ifdef CONFIG_CYZ_INTR
- else {
- /* In case this Z board is operating in interrupt mode, its
- interrupts should be enabled as soon as the first open happens
- to one of its ports. */
- if (!cinfo->intr_enabled) {
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
-
- zfw_ctrl = cinfo->base_addr + (cy_readl (&firm_id->zfwctrl_addr) & 0xfffff);
+ struct cyclades_port *info;
+ int retval, line;
- board_ctrl = &zfw_ctrl->board_ctrl;
+ line = tty->index;
+ if ((line < 0) || (NR_PORTS <= line)) {
+ return -ENODEV;
+ }
+ info = &cy_port[line];
+ if (info->line < 0) {
+ return -ENODEV;
+ }
- /* Enable interrupts on the PLX chip */
- cy_writew(cinfo->ctl_addr+0x68,
- cy_readw(cinfo->ctl_addr+0x68)|0x0900);
- /* Enable interrupts on the FW */
- retval = cyz_issue_cmd(cinfo,
- 0, C_CM_IRQ_ENBL, 0L);
- if (retval != 0){
- printk("cyc:IRQ enable retval was %x\n", retval);
+ /* If the card's firmware hasn't been loaded,
+ treat it as absent from the system. This
+ will make the user pay attention.
+ */
+ if (IS_CYC_Z(cy_card[info->card])) {
+ struct cyclades_card *cinfo = &cy_card[info->card];
+ struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
+
+ if (!ISZLOADED(*cinfo)) {
+ if (((ZE_V1 == cy_readl(
+ &((struct RUNTIME_9060 __iomem *)
+ (cinfo->ctl_addr))->mail_box_0)) &&
+ Z_FPGA_CHECK(*cinfo)) &&
+ (ZFIRM_HLT == cy_readl(
+ &firm_id->signature))) {
+ printk("cyc:Cyclades-Z Error: you need an "
+ "external power supply for this number "
+ "of ports.\n\rFirmware halted.\r\n");
+ } else {
+ printk("cyc:Cyclades-Z firmware not yet "
+ "loaded\n");
+ }
+ return -ENODEV;
}
- cinfo->nports = (int) cy_readl (&board_ctrl->n_channel);
- cinfo->intr_enabled = 1;
- }
+#ifdef CONFIG_CYZ_INTR
+ else {
+ /* In case this Z board is operating in interrupt mode, its
+ interrupts should be enabled as soon as the first open
+ happens to one of its ports. */
+ if (!cinfo->intr_enabled) {
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+
+ zfw_ctrl = cinfo->base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
+
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ /* Enable interrupts on the PLX chip */
+ cy_writew(cinfo->ctl_addr + 0x68,
+ cy_readw(cinfo->ctl_addr +
+ 0x68) | 0x0900);
+ /* Enable interrupts on the FW */
+ retval = cyz_issue_cmd(cinfo, 0,
+ C_CM_IRQ_ENBL, 0L);
+ if (retval != 0) {
+ printk("cyc:IRQ enable retval was %x\n",
+ retval);
+ }
+ cinfo->nports =
+ (int)cy_readl(&board_ctrl->n_channel);
+ cinfo->intr_enabled = 1;
+ }
+ }
+#endif /* CONFIG_CYZ_INTR */
+ /* Make sure this Z port really exists in hardware */
+ if (info->line > (cinfo->first_line + cinfo->nports - 1))
+ return -ENODEV;
}
-#endif /* CONFIG_CYZ_INTR */
- /* Make sure this Z port really exists in hardware */
- if (info->line > (cinfo->first_line + cinfo->nports - 1))
- return -ENODEV;
- }
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_open ttyC%d\n", info->line); /* */
+ printk("cyc:cy_open ttyC%d\n", info->line); /* */
#endif
- tty->driver_data = info;
- info->tty = tty;
- if (serial_paranoia_check(info, tty->name, "cy_open")){
- return -ENODEV;
- }
+ tty->driver_data = info;
+ info->tty = tty;
+ if (serial_paranoia_check(info, tty->name, "cy_open")) {
+ return -ENODEV;
+ }
#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_open ttyC%d, count = %d\n",
- info->line, info->count);/**/
+ printk("cyc:cy_open ttyC%d, count = %d\n", info->line, info->count);
+ /**/
#endif
- info->count++;
+ info->count++;
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_open (%d): incrementing count to %d\n",
- current->pid, info->count);
+ printk("cyc:cy_open (%d): incrementing count to %d\n",
+ current->pid, info->count);
#endif
- /*
- * If the port is the middle of closing, bail out now
- */
- if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
- return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
- }
-
- /*
- * Start up serial port
- */
- retval = startup(info);
- if (retval){
- return retval;
- }
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
-#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_open returning after block_til_ready with %d\n",
- retval);
-#endif
- return retval;
- }
+ /*
+ * If the port is the middle of closing, bail out now
+ */
+ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+ return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
+ }
- info->throttle = 0;
+ /*
+ * Start up serial port
+ */
+ retval = startup(info);
+ if (retval) {
+ return retval;
+ }
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
#ifdef CY_DEBUG_OPEN
- printk(" cyc:cy_open done\n");/**/
+ printk("cyc:cy_open returning after block_til_ready with %d\n",
+ retval);
#endif
+ return retval;
+ }
- return 0;
-} /* cy_open */
+ info->throttle = 0;
+#ifdef CY_DEBUG_OPEN
+ printk(" cyc:cy_open done\n");
+ /**/
+#endif
+ return 0;
+} /* cy_open */
/*
* cy_wait_until_sent() --- wait until the transmitter is empty
*/
-static void
-cy_wait_until_sent(struct tty_struct *tty, int timeout)
+static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- void __iomem *base_addr;
- int card,chip,channel,index;
- unsigned long orig_jiffies;
- int char_time;
-
- if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
- return;
-
- if (info->xmit_fifo_size == 0)
- return; /* Just in case.... */
-
-
- orig_jiffies = jiffies;
- /*
- * Set the check interval to be 1/5 of the estimated time to
- * send a single character, and make it at least 1. The check
- * interval should also be less than the timeout.
- *
- * Note: we have to use pretty tight timings here to satisfy
- * the NIST-PCTS.
- */
- char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
- char_time = char_time / 5;
- if (char_time <= 0)
- char_time = 1;
- if (timeout < 0)
- timeout = 0;
- if (timeout)
- char_time = min(char_time, timeout);
- /*
- * If the transmitter hasn't cleared in twice the approximate
- * amount of time to send the entire FIFO, it probably won't
- * ever clear. This assumes the UART isn't doing flow
- * control, which is currently the case. Hence, if it ever
- * takes longer than info->timeout, this is probably due to a
- * UART bug of some kind. So, we clamp the timeout parameter at
- * 2*info->timeout.
- */
- if (!timeout || timeout > 2*info->timeout)
- timeout = 2*info->timeout;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
+ unsigned long orig_jiffies;
+ int char_time;
+
+ if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
+ return;
+
+ if (info->xmit_fifo_size == 0)
+ return; /* Just in case.... */
+
+ orig_jiffies = jiffies;
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ *
+ * Note: we have to use pretty tight timings here to satisfy
+ * the NIST-PCTS.
+ */
+ char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
+ char_time = char_time / 5;
+ if (char_time <= 0)
+ char_time = 1;
+ if (timeout < 0)
+ timeout = 0;
+ if (timeout)
+ char_time = min(char_time, timeout);
+ /*
+ * If the transmitter hasn't cleared in twice the approximate
+ * amount of time to send the entire FIFO, it probably won't
+ * ever clear. This assumes the UART isn't doing flow
+ * control, which is currently the case. Hence, if it ever
+ * takes longer than info->timeout, this is probably due to a
+ * UART bug of some kind. So, we clamp the timeout parameter at
+ * 2*info->timeout.
+ */
+ if (!timeout || timeout > 2 * info->timeout)
+ timeout = 2 * info->timeout;
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time);
- printk("jiff=%lu...", jiffies);
+ printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time);
+ printk("jiff=%lu...", jiffies);
#endif
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
- while (cy_readb(base_addr+(CySRER<<index)) & CyTxRdy) {
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ while (cy_readb(base_addr + (CySRER << index)) & CyTxRdy) {
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("Not clean (jiff=%lu)...", jiffies);
+ printk("Not clean (jiff=%lu)...", jiffies);
#endif
- if (msleep_interruptible(jiffies_to_msecs(char_time)))
- break;
- if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
+ if (msleep_interruptible(jiffies_to_msecs(char_time)))
+ break;
+ if (timeout && time_after(jiffies, orig_jiffies +
+ timeout))
+ break;
+ }
+ } else {
+ /* Nothing to do! */
}
- } else {
- // Nothing to do!
- }
- /* Run one more char cycle */
- msleep_interruptible(jiffies_to_msecs(char_time * 5));
+ /* Run one more char cycle */
+ msleep_interruptible(jiffies_to_msecs(char_time * 5));
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("Clean (jiff=%lu)...done\n", jiffies);
+ printk("Clean (jiff=%lu)...done\n", jiffies);
#endif
}
/*
* This routine is called when a particular tty device is closed.
*/
-static void
-cy_close(struct tty_struct *tty, struct file *filp)
+static void cy_close(struct tty_struct *tty, struct file *filp)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_close ttyC%d\n", info->line);
+ printk("cyc:cy_close ttyC%d\n", info->line);
#endif
- if (!info || serial_paranoia_check(info, tty->name, "cy_close")){
- return;
- }
+ if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
+ return;
+ }
- CY_LOCK(info, flags);
- /* If the TTY is being hung up, nothing to do */
- if (tty_hung_up_p(filp)) {
- CY_UNLOCK(info, flags);
- return;
- }
-
+ CY_LOCK(info, flags);
+ /* If the TTY is being hung up, nothing to do */
+ if (tty_hung_up_p(filp)) {
+ CY_UNLOCK(info, flags);
+ return;
+ }
#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
+ printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
#endif
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("cyc:cy_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
- }
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("cyc:cy_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_close at (%d): decrementing count to %d\n",
- current->pid, info->count - 1);
+ printk("cyc:cy_close at (%d): decrementing count to %d\n",
+ current->pid, info->count - 1);
#endif
- if (--info->count < 0) {
+ if (--info->count < 0) {
#ifdef CY_DEBUG_COUNT
- printk("cyc:cyc_close setting count to 0\n");
+ printk("cyc:cyc_close setting count to 0\n");
#endif
- info->count = 0;
- }
- if (info->count) {
- CY_UNLOCK(info, flags);
- return;
- }
- info->flags |= ASYNC_CLOSING;
-
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- CY_UNLOCK(info, flags);
- if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
- tty_wait_until_sent(tty, info->closing_wait);
- }
- CY_LOCK(info, flags);
-
- if (!IS_CYC_Z(cy_card[info->card])) {
- int channel = info->line - cy_card[info->card].first_line;
- int index = cy_card[info->card].bus_index;
- void __iomem *base_addr = cy_card[info->card].base_addr + (cy_chip_offset[channel>>2] << index);
- /* Stop accepting input */
- channel &= 0x03;
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyRxData);
- if (info->flags & ASYNC_INITIALIZED) {
- /* Waiting for on-board buffers to be empty before closing
- the port */
- CY_UNLOCK(info, flags);
- cy_wait_until_sent(tty, info->timeout);
- CY_LOCK(info, flags);
+ info->count = 0;
}
- } else {
-#ifdef Z_WAKE
- /* Waiting for on-board buffers to be empty before closing the port */
- void __iomem *base_addr = cy_card[info->card].base_addr;
- struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
- struct ZFW_CTRL __iomem *zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
- int channel = info->line - cy_card[info->card].first_line;
- int retval;
+ if (info->count) {
+ CY_UNLOCK(info, flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
- if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
- retval = cyz_issue_cmd(&cy_card[info->card], channel,
- C_CM_IOCTLW, 0L);
- if (retval != 0){
- printk("cyc:cy_close retval on ttyC%d was %x\n",
- info->line, retval);
- }
- CY_UNLOCK(info, flags);
- interruptible_sleep_on(&info->shutdown_wait);
- CY_LOCK(info, flags);
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ CY_UNLOCK(info, flags);
+ if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
+ tty_wait_until_sent(tty, info->closing_wait);
}
+ CY_LOCK(info, flags);
+
+ if (!IS_CYC_Z(cy_card[info->card])) {
+ int channel = info->line - cy_card[info->card].first_line;
+ int index = cy_card[info->card].bus_index;
+ void __iomem *base_addr = cy_card[info->card].base_addr +
+ (cy_chip_offset[channel >> 2] << index);
+ /* Stop accepting input */
+ channel &= 0x03;
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) & ~CyRxData);
+ if (info->flags & ASYNC_INITIALIZED) {
+ /* Waiting for on-board buffers to be empty before closing
+ the port */
+ CY_UNLOCK(info, flags);
+ cy_wait_until_sent(tty, info->timeout);
+ CY_LOCK(info, flags);
+ }
+ } else {
+#ifdef Z_WAKE
+ /* Waiting for on-board buffers to be empty before closing the port */
+ void __iomem *base_addr = cy_card[info->card].base_addr;
+ struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
+ struct ZFW_CTRL __iomem *zfw_ctrl =
+ base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
+ int channel = info->line - cy_card[info->card].first_line;
+ int retval;
+
+ if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
+ retval = cyz_issue_cmd(&cy_card[info->card], channel,
+ C_CM_IOCTLW, 0L);
+ if (retval != 0) {
+ printk("cyc:cy_close retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+ CY_UNLOCK(info, flags);
+ interruptible_sleep_on(&info->shutdown_wait);
+ CY_LOCK(info, flags);
+ }
#endif
- }
-
- CY_UNLOCK(info, flags);
- shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
- CY_LOCK(info, flags);
-
- tty->closing = 0;
- info->event = 0;
- info->tty = NULL;
- if (info->blocked_open) {
+ }
+
CY_UNLOCK(info, flags);
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
- wake_up_interruptible(&info->open_wait);
+ shutdown(info);
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+ tty_ldisc_flush(tty);
CY_LOCK(info, flags);
- }
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
+
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = NULL;
+ if (info->blocked_open) {
+ CY_UNLOCK(info, flags);
+ if (info->close_delay) {
+ msleep_interruptible(jiffies_to_msecs
+ (info->close_delay));
+ }
+ wake_up_interruptible(&info->open_wait);
+ CY_LOCK(info, flags);
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
#ifdef CY_DEBUG_OTHER
- printk(" cyc:cy_close done\n");
+ printk(" cyc:cy_close done\n");
#endif
- CY_UNLOCK(info, flags);
- return;
-} /* cy_close */
-
+ CY_UNLOCK(info, flags);
+} /* cy_close */
/* This routine gets called when tty_write has put something into
* the write_queue. The characters may come from user space or
@@ -2796,50 +2875,49 @@ cy_close(struct tty_struct *tty, struct file *filp)
* If the port is already active, there is no need to kick it.
*
*/
-static int
-cy_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- int c, ret = 0;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ int c, ret = 0;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_write ttyC%d\n", info->line); /* */
+ printk("cyc:cy_write ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_write")){
- return 0;
- }
-
- if (!info->xmit_buf)
- return 0;
+ if (serial_paranoia_check(info, tty->name, "cy_write")) {
+ return 0;
+ }
- CY_LOCK(info, flags);
- while (1) {
- c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
- (int)(SERIAL_XMIT_SIZE - info->xmit_head)));
-
- if (c <= 0)
- break;
-
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- buf += c;
- count -= c;
- ret += c;
- }
- CY_UNLOCK(info, flags);
-
- info->idle_stats.xmit_bytes += ret;
- info->idle_stats.xmit_idle = jiffies;
-
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
- start_xmit(info);
- }
- return ret;
-} /* cy_write */
+ if (!info->xmit_buf)
+ return 0;
+ CY_LOCK(info, flags);
+ while (1) {
+ c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
+ (int)(SERIAL_XMIT_SIZE - info->xmit_head)));
+
+ if (c <= 0)
+ break;
+
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE - 1);
+ info->xmit_cnt += c;
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ CY_UNLOCK(info, flags);
+
+ info->idle_stats.xmit_bytes += ret;
+ info->idle_stats.xmit_idle = jiffies;
+
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+ start_xmit(info);
+ }
+ return ret;
+} /* cy_write */
/*
* This routine is called by the kernel to write a single
@@ -2848,60 +2926,56 @@ cy_write(struct tty_struct * tty, const unsigned char *buf, int count)
* done stuffing characters into the driver. If there is no room
* in the queue, the character is ignored.
*/
-static void
-cy_put_char(struct tty_struct *tty, unsigned char ch)
+static void cy_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_put_char ttyC%d\n", info->line);
+ printk("cyc:cy_put_char ttyC%d\n", info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_put_char"))
- return;
+ if (serial_paranoia_check(info, tty->name, "cy_put_char"))
+ return;
- if (!info->xmit_buf)
- return;
+ if (!info->xmit_buf)
+ return;
- CY_LOCK(info, flags);
- if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
- CY_UNLOCK(info, flags);
- return;
- }
+ CY_LOCK(info, flags);
+ if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
+ CY_UNLOCK(info, flags);
+ return;
+ }
- info->xmit_buf[info->xmit_head++] = ch;
- info->xmit_head &= SERIAL_XMIT_SIZE - 1;
- info->xmit_cnt++;
+ info->xmit_buf[info->xmit_head++] = ch;
+ info->xmit_head &= SERIAL_XMIT_SIZE - 1;
+ info->xmit_cnt++;
info->idle_stats.xmit_bytes++;
info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
-} /* cy_put_char */
-
+ CY_UNLOCK(info, flags);
+} /* cy_put_char */
/*
* This routine is called by the kernel after it has written a
* series of characters to the tty device using put_char().
*/
-static void
-cy_flush_chars(struct tty_struct *tty)
+static void cy_flush_chars(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+
#ifdef CY_DEBUG_IO
- printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
+ printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
- return;
-
- if (info->xmit_cnt <= 0 || tty->stopped
- || tty->hw_stopped || !info->xmit_buf)
- return;
+ if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
+ return;
- start_xmit(info);
-} /* cy_flush_chars */
+ if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+ !info->xmit_buf)
+ return;
+ start_xmit(info);
+} /* cy_flush_chars */
/*
* This routine returns the numbers of characters the tty driver
@@ -2909,75 +2983,70 @@ cy_flush_chars(struct tty_struct *tty)
* to change as output buffers get emptied, or if the output flow
* control is activated.
*/
-static int
-cy_write_room(struct tty_struct *tty)
+static int cy_write_room(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int ret;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int ret;
+
#ifdef CY_DEBUG_IO
- printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
+ printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_write_room"))
- return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
-} /* cy_write_room */
-
+ if (serial_paranoia_check(info, tty->name, "cy_write_room"))
+ return 0;
+ ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return ret;
+} /* cy_write_room */
-static int
-cy_chars_in_buffer(struct tty_struct *tty)
+static int cy_chars_in_buffer(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, channel;
-
- if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
- return 0;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int card, channel;
+
+ if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
+ return 0;
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
#ifdef Z_EXT_CHARS_IN_BUFFER
- if (!IS_CYC_Z(cy_card[card])) {
-#endif /* Z_EXT_CHARS_IN_BUFFER */
+ if (!IS_CYC_Z(cy_card[card])) {
+#endif /* Z_EXT_CHARS_IN_BUFFER */
#ifdef CY_DEBUG_IO
- printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
- info->line, info->xmit_cnt); /* */
+ printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */
#endif
- return info->xmit_cnt;
+ return info->xmit_cnt;
#ifdef Z_EXT_CHARS_IN_BUFFER
- } else {
- static volatile struct FIRM_ID *firm_id;
- static volatile struct ZFW_CTRL *zfw_ctrl;
- static volatile struct CH_CTRL *ch_ctrl;
- static volatile struct BUF_CTRL *buf_ctrl;
- int char_count;
- volatile uclong tx_put, tx_get, tx_bufsize;
-
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
-
- tx_get = cy_readl(&buf_ctrl->tx_get);
- tx_put = cy_readl(&buf_ctrl->tx_put);
- tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
- if (tx_put >= tx_get)
- char_count = tx_put - tx_get;
- else
- char_count = tx_put - tx_get + tx_bufsize;
+ } else {
+ static volatile struct FIRM_ID *firm_id;
+ static volatile struct ZFW_CTRL *zfw_ctrl;
+ static volatile struct CH_CTRL *ch_ctrl;
+ static volatile struct BUF_CTRL *buf_ctrl;
+ int char_count;
+ volatile uclong tx_put, tx_get, tx_bufsize;
+
+ firm_id = cy_card[card].base_addr + ID_ADDRESS;
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+ tx_get = cy_readl(&buf_ctrl->tx_get);
+ tx_put = cy_readl(&buf_ctrl->tx_put);
+ tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+ if (tx_put >= tx_get)
+ char_count = tx_put - tx_get;
+ else
+ char_count = tx_put - tx_get + tx_bufsize;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
- info->line, info->xmit_cnt + char_count); /* */
+ printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt + char_count); /* */
#endif
- return (info->xmit_cnt + char_count);
- }
-#endif /* Z_EXT_CHARS_IN_BUFFER */
-} /* cy_chars_in_buffer */
-
+ return info->xmit_cnt + char_count;
+ }
+#endif /* Z_EXT_CHARS_IN_BUFFER */
+} /* cy_chars_in_buffer */
/*
* ------------------------------------------------------------
@@ -2985,178 +3054,179 @@ cy_chars_in_buffer(struct tty_struct *tty)
* ------------------------------------------------------------
*/
-static void
-cyy_baud_calc(struct cyclades_port *info, uclong baud)
+static void cyy_baud_calc(struct cyclades_port *info, uclong baud)
{
- int co, co_val, bpr;
- uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 : 25000000);
-
- if (baud == 0) {
- info->tbpr = info->tco = info->rbpr = info->rco = 0;
- return;
- }
-
- /* determine which prescaler to use */
- for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
- if (cy_clock / co_val / baud > 63)
- break;
- }
-
- bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
- if (bpr > 255)
- bpr = 255;
-
- info->tbpr = info->rbpr = bpr;
- info->tco = info->rco = co;
+ int co, co_val, bpr;
+ uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
+ 25000000);
+
+ if (baud == 0) {
+ info->tbpr = info->tco = info->rbpr = info->rco = 0;
+ return;
+ }
+
+ /* determine which prescaler to use */
+ for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
+ if (cy_clock / co_val / baud > 63)
+ break;
+ }
+
+ bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
+ if (bpr > 255)
+ bpr = 255;
+
+ info->tbpr = info->rbpr = bpr;
+ info->tco = info->rco = co;
}
/*
* This routine finds or computes the various line characteristics.
* It used to be called config_setup
*/
-static void
-set_line_char(struct cyclades_port * info)
+static void set_line_char(struct cyclades_port *info)
{
- unsigned long flags;
- void __iomem *base_addr;
- int card,chip,channel,index;
- unsigned cflag, iflag;
- unsigned short chip_number;
- int baud, baud_rate = 0;
- int i;
-
-
- if (!info->tty || !info->tty->termios){
- return;
- }
- if (info->line == -1){
- return;
- }
- cflag = info->tty->termios->c_cflag;
- iflag = info->tty->termios->c_iflag;
-
- /*
- * Set up the tty->alt_speed kludge
- */
- if (info->tty) {
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- info->tty->alt_speed = 57600;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- info->tty->alt_speed = 115200;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
- info->tty->alt_speed = 230400;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
- info->tty->alt_speed = 460800;
- }
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- chip_number = channel / 4;
-
- if (!IS_CYC_Z(cy_card[card])) {
-
- index = cy_card[card].bus_index;
-
- /* baud rate */
- baud = tty_get_baud_rate(info->tty);
- if ((baud == 38400) &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
- if (info->custom_divisor)
- baud_rate = info->baud / info->custom_divisor;
- else
- baud_rate = info->baud;
- } else if (baud > CD1400_MAX_SPEED) {
- baud = CD1400_MAX_SPEED;
+ unsigned long flags;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
+ unsigned cflag, iflag;
+ unsigned short chip_number;
+ int baud, baud_rate = 0;
+ int i;
+
+ if (!info->tty || !info->tty->termios) {
+ return;
}
- /* find the baud index */
- for (i = 0; i < 20; i++) {
- if (baud == baud_table[i]) {
- break;
- }
+ if (info->line == -1) {
+ return;
}
- if (i == 20) {
- i = 19; /* CD1400_MAX_SPEED */
- }
+ cflag = info->tty->termios->c_cflag;
+ iflag = info->tty->termios->c_iflag;
- if ((baud == 38400) &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
- cyy_baud_calc(info, baud_rate);
- } else {
- if(info->chip_rev >= CD1400_REV_J) {
- /* It is a CD1400 rev. J or later */
- info->tbpr = baud_bpr_60[i]; /* Tx BPR */
- info->tco = baud_co_60[i]; /* Tx CO */
- info->rbpr = baud_bpr_60[i]; /* Rx BPR */
- info->rco = baud_co_60[i]; /* Rx CO */
- } else {
- info->tbpr = baud_bpr_25[i]; /* Tx BPR */
- info->tco = baud_co_25[i]; /* Tx CO */
- info->rbpr = baud_bpr_25[i]; /* Rx BPR */
- info->rco = baud_co_25[i]; /* Rx CO */
- }
- }
- if (baud_table[i] == 134) {
- /* get it right for 134.5 baud */
- info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
- } else if ((baud == 38400) &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
- info->timeout = (info->xmit_fifo_size*HZ*15/baud_rate) + 2;
- } else if (baud_table[i]) {
- info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
- /* this needs to be propagated into the card info */
- } else {
- info->timeout = 0;
- }
- /* By tradition (is it a standard?) a baud rate of zero
- implies the line should be/has been closed. A bit
- later in this routine such a test is performed. */
-
- /* byte size and parity */
- info->cor5 = 0;
- info->cor4 = 0;
- info->cor3 = (info->default_threshold
- ? info->default_threshold
- : baud_cor3[i]); /* receive threshold */
- info->cor2 = CyETC;
- switch(cflag & CSIZE){
- case CS5:
- info->cor1 = Cy_5_BITS;
- break;
- case CS6:
- info->cor1 = Cy_6_BITS;
- break;
- case CS7:
- info->cor1 = Cy_7_BITS;
- break;
- case CS8:
- info->cor1 = Cy_8_BITS;
- break;
- }
- if(cflag & CSTOPB){
- info->cor1 |= Cy_2_STOP;
- }
- if (cflag & PARENB){
- if (cflag & PARODD){
- info->cor1 |= CyPARITY_O;
- }else{
- info->cor1 |= CyPARITY_E;
- }
- }else{
- info->cor1 |= CyPARITY_NONE;
- }
-
- /* CTS flow control flag */
- if (cflag & CRTSCTS){
- info->flags |= ASYNC_CTS_FLOW;
- info->cor2 |= CyCtsAE;
- }else{
- info->flags &= ~ASYNC_CTS_FLOW;
- info->cor2 &= ~CyCtsAE;
+ /*
+ * Set up the tty->alt_speed kludge
+ */
+ if (info->tty) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ info->tty->alt_speed = 115200;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ info->tty->alt_speed = 230400;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
}
- if (cflag & CLOCAL)
- info->flags &= ~ASYNC_CHECK_CD;
- else
- info->flags |= ASYNC_CHECK_CD;
+
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ chip_number = channel / 4;
+
+ if (!IS_CYC_Z(cy_card[card])) {
+
+ index = cy_card[card].bus_index;
+
+ /* baud rate */
+ baud = tty_get_baud_rate(info->tty);
+ if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+ ASYNC_SPD_CUST) {
+ if (info->custom_divisor)
+ baud_rate = info->baud / info->custom_divisor;
+ else
+ baud_rate = info->baud;
+ } else if (baud > CD1400_MAX_SPEED) {
+ baud = CD1400_MAX_SPEED;
+ }
+ /* find the baud index */
+ for (i = 0; i < 20; i++) {
+ if (baud == baud_table[i]) {
+ break;
+ }
+ }
+ if (i == 20) {
+ i = 19; /* CD1400_MAX_SPEED */
+ }
+
+ if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+ ASYNC_SPD_CUST) {
+ cyy_baud_calc(info, baud_rate);
+ } else {
+ if (info->chip_rev >= CD1400_REV_J) {
+ /* It is a CD1400 rev. J or later */
+ info->tbpr = baud_bpr_60[i]; /* Tx BPR */
+ info->tco = baud_co_60[i]; /* Tx CO */
+ info->rbpr = baud_bpr_60[i]; /* Rx BPR */
+ info->rco = baud_co_60[i]; /* Rx CO */
+ } else {
+ info->tbpr = baud_bpr_25[i]; /* Tx BPR */
+ info->tco = baud_co_25[i]; /* Tx CO */
+ info->rbpr = baud_bpr_25[i]; /* Rx BPR */
+ info->rco = baud_co_25[i]; /* Rx CO */
+ }
+ }
+ if (baud_table[i] == 134) {
+ /* get it right for 134.5 baud */
+ info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
+ 2;
+ } else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+ ASYNC_SPD_CUST) {
+ info->timeout = (info->xmit_fifo_size * HZ * 15 /
+ baud_rate) + 2;
+ } else if (baud_table[i]) {
+ info->timeout = (info->xmit_fifo_size * HZ * 15 /
+ baud_table[i]) + 2;
+ /* this needs to be propagated into the card info */
+ } else {
+ info->timeout = 0;
+ }
+ /* By tradition (is it a standard?) a baud rate of zero
+ implies the line should be/has been closed. A bit
+ later in this routine such a test is performed. */
+
+ /* byte size and parity */
+ info->cor5 = 0;
+ info->cor4 = 0;
+ /* receive threshold */
+ info->cor3 = (info->default_threshold ?
+ info->default_threshold : baud_cor3[i]);
+ info->cor2 = CyETC;
+ switch (cflag & CSIZE) {
+ case CS5:
+ info->cor1 = Cy_5_BITS;
+ break;
+ case CS6:
+ info->cor1 = Cy_6_BITS;
+ break;
+ case CS7:
+ info->cor1 = Cy_7_BITS;
+ break;
+ case CS8:
+ info->cor1 = Cy_8_BITS;
+ break;
+ }
+ if (cflag & CSTOPB) {
+ info->cor1 |= Cy_2_STOP;
+ }
+ if (cflag & PARENB) {
+ if (cflag & PARODD) {
+ info->cor1 |= CyPARITY_O;
+ } else {
+ info->cor1 |= CyPARITY_E;
+ }
+ } else {
+ info->cor1 |= CyPARITY_NONE;
+ }
+
+ /* CTS flow control flag */
+ if (cflag & CRTSCTS) {
+ info->flags |= ASYNC_CTS_FLOW;
+ info->cor2 |= CyCtsAE;
+ } else {
+ info->flags &= ~ASYNC_CTS_FLOW;
+ info->cor2 &= ~CyCtsAE;
+ }
+ if (cflag & CLOCAL)
+ info->flags &= ~ASYNC_CHECK_CD;
+ else
+ info->flags |= ASYNC_CHECK_CD;
/***********************************************
The hardware option, CyRtsAO, presents RTS when
@@ -3168,300 +3238,319 @@ set_line_char(struct cyclades_port * info)
cable. Contact Marcio Saito for details.
***********************************************/
- chip = channel>>2;
- channel &= 0x03;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ chip = channel >> 2;
+ channel &= 0x03;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
-
- /* tx and rx baud rate */
-
- cy_writeb(base_addr+(CyTCOR<<index), info->tco);
- cy_writeb(base_addr+(CyTBPR<<index), info->tbpr);
- cy_writeb(base_addr+(CyRCOR<<index), info->rco);
- cy_writeb(base_addr+(CyRBPR<<index), info->rbpr);
-
- /* set line characteristics according configuration */
-
- cy_writeb(base_addr+(CySCHR1<<index),
- START_CHAR(info->tty));
- cy_writeb(base_addr+(CySCHR2<<index),
- STOP_CHAR(info->tty));
- cy_writeb(base_addr+(CyCOR1<<index), info->cor1);
- cy_writeb(base_addr+(CyCOR2<<index), info->cor2);
- cy_writeb(base_addr+(CyCOR3<<index), info->cor3);
- cy_writeb(base_addr+(CyCOR4<<index), info->cor4);
- cy_writeb(base_addr+(CyCOR5<<index), info->cor5);
-
- cyy_issue_cmd(base_addr,
- CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index);
-
- cy_writeb(base_addr+(CyCAR<<index),
- (u_char)channel); /* !!! Is this needed? */
- cy_writeb(base_addr+(CyRTPR<<index), (info->default_timeout
- ? info->default_timeout
- : 0x02)); /* 10ms rx timeout */
-
- if (C_CLOCAL(info->tty)) {
- /* without modem intr */
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyMdmCh);
- /* act on 1->0 modem transitions */
- if ((cflag & CRTSCTS) && info->rflow) {
- cy_writeb(base_addr+(CyMCOR1<<index),
- (CyCTS|rflow_thr[i]));
- } else {
- cy_writeb(base_addr+(CyMCOR1<<index), CyCTS);
- }
- /* act on 0->1 modem transitions */
- cy_writeb(base_addr+(CyMCOR2<<index), CyCTS);
- } else {
- /* without modem intr */
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyMdmCh);
- /* act on 1->0 modem transitions */
- if ((cflag & CRTSCTS) && info->rflow) {
- cy_writeb(base_addr+(CyMCOR1<<index),
- (CyDSR|CyCTS|CyRI|CyDCD|rflow_thr[i]));
- } else {
- cy_writeb(base_addr+(CyMCOR1<<index),
- CyDSR|CyCTS|CyRI|CyDCD);
- }
- /* act on 0->1 modem transitions */
- cy_writeb(base_addr+(CyMCOR2<<index),
- CyDSR|CyCTS|CyRI|CyDCD);
- }
-
- if(i == 0){ /* baud rate is zero, turn off line */
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR1<<index), ~CyRTS);
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+
+ /* tx and rx baud rate */
+
+ cy_writeb(base_addr + (CyTCOR << index), info->tco);
+ cy_writeb(base_addr + (CyTBPR << index), info->tbpr);
+ cy_writeb(base_addr + (CyRCOR << index), info->rco);
+ cy_writeb(base_addr + (CyRBPR << index), info->rbpr);
+
+ /* set line characteristics according configuration */
+
+ cy_writeb(base_addr + (CySCHR1 << index),
+ START_CHAR(info->tty));
+ cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->tty));
+ cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
+ cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
+ cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
+ cy_writeb(base_addr + (CyCOR4 << index), info->cor4);
+ cy_writeb(base_addr + (CyCOR5 << index), info->cor5);
+
+ cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
+ CyCOR3ch, index);
+
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel); /* !!! Is this needed? */
+ cy_writeb(base_addr + (CyRTPR << index),
+ (info->default_timeout ? info->default_timeout : 0x02));
+ /* 10ms rx timeout */
+
+ if (C_CLOCAL(info->tty)) {
+ /* without modem intr */
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr +
+ (CySRER << index)) | CyMdmCh);
+ /* act on 1->0 modem transitions */
+ if ((cflag & CRTSCTS) && info->rflow) {
+ cy_writeb(base_addr + (CyMCOR1 << index),
+ (CyCTS | rflow_thr[i]));
+ } else {
+ cy_writeb(base_addr + (CyMCOR1 << index),
+ CyCTS);
+ }
+ /* act on 0->1 modem transitions */
+ cy_writeb(base_addr + (CyMCOR2 << index), CyCTS);
} else {
- cy_writeb(base_addr+(CyMSVR2<<index), ~CyDTR);
+ /* without modem intr */
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr +
+ (CySRER << index)) | CyMdmCh);
+ /* act on 1->0 modem transitions */
+ if ((cflag & CRTSCTS) && info->rflow) {
+ cy_writeb(base_addr + (CyMCOR1 << index),
+ (CyDSR | CyCTS | CyRI | CyDCD |
+ rflow_thr[i]));
+ } else {
+ cy_writeb(base_addr + (CyMCOR1 << index),
+ CyDSR | CyCTS | CyRI | CyDCD);
+ }
+ /* act on 0->1 modem transitions */
+ cy_writeb(base_addr + (CyMCOR2 << index),
+ CyDSR | CyCTS | CyRI | CyDCD);
}
+
+ if (i == 0) { /* baud rate is zero, turn off line */
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ ~CyRTS);
+ } else {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ ~CyDTR);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:set_line_char dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- }else{
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- } else {
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
- }
+ } else {
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ CyRTS);
+ } else {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ CyDTR);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:set_line_char raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- }
-
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- CY_UNLOCK(info, flags);
+ }
- } else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- struct BUF_CTRL __iomem *buf_ctrl;
- uclong sw_flow;
- int retval;
-
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])) {
- return;
- }
+ if (info->tty) {
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ CY_UNLOCK(info, flags);
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
-
- /* baud rate */
- baud = tty_get_baud_rate(info->tty);
- if ((baud == 38400) &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
- if (info->custom_divisor)
- baud_rate = info->baud / info->custom_divisor;
- else
- baud_rate = info->baud;
- } else if (baud > CYZ_MAX_SPEED) {
- baud = CYZ_MAX_SPEED;
- }
- cy_writel(&ch_ctrl->comm_baud , baud);
-
- if (baud == 134) {
- /* get it right for 134.5 baud */
- info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
- } else if ((baud == 38400) &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
- info->timeout = (info->xmit_fifo_size*HZ*15/baud_rate) + 2;
- } else if (baud) {
- info->timeout = (info->xmit_fifo_size*HZ*15/baud) + 2;
- /* this needs to be propagated into the card info */
} else {
- info->timeout = 0;
- }
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+ struct BUF_CTRL __iomem *buf_ctrl;
+ uclong sw_flow;
+ int retval;
+
+ firm_id = cy_card[card].base_addr + ID_ADDRESS;
+ if (!ISZLOADED(cy_card[card])) {
+ return;
+ }
- /* byte size and parity */
- switch(cflag & CSIZE){
- case CS5: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS5); break;
- case CS6: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS6); break;
- case CS7: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS7); break;
- case CS8: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS8); break;
- }
- if(cflag & CSTOPB){
- cy_writel(&ch_ctrl->comm_data_l,
- cy_readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
- }else{
- cy_writel(&ch_ctrl->comm_data_l,
- cy_readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
- }
- if (cflag & PARENB){
- if (cflag & PARODD){
- cy_writel(&ch_ctrl->comm_parity , C_PR_ODD);
- }else{
- cy_writel(&ch_ctrl->comm_parity , C_PR_EVEN);
- }
- }else{
- cy_writel(&ch_ctrl->comm_parity , C_PR_NONE);
- }
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+ buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
+
+ /* baud rate */
+ baud = tty_get_baud_rate(info->tty);
+ if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+ ASYNC_SPD_CUST) {
+ if (info->custom_divisor)
+ baud_rate = info->baud / info->custom_divisor;
+ else
+ baud_rate = info->baud;
+ } else if (baud > CYZ_MAX_SPEED) {
+ baud = CYZ_MAX_SPEED;
+ }
+ cy_writel(&ch_ctrl->comm_baud, baud);
+
+ if (baud == 134) {
+ /* get it right for 134.5 baud */
+ info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
+ 2;
+ } else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+ ASYNC_SPD_CUST) {
+ info->timeout = (info->xmit_fifo_size * HZ * 15 /
+ baud_rate) + 2;
+ } else if (baud) {
+ info->timeout = (info->xmit_fifo_size * HZ * 15 /
+ baud) + 2;
+ /* this needs to be propagated into the card info */
+ } else {
+ info->timeout = 0;
+ }
- /* CTS flow control flag */
- if (cflag & CRTSCTS){
- cy_writel(&ch_ctrl->hw_flow,
- cy_readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
- }else{
- cy_writel(&ch_ctrl->hw_flow,
- cy_readl(&ch_ctrl->hw_flow) & ~(C_RS_CTS | C_RS_RTS));
- }
- /* As the HW flow control is done in firmware, the driver doesn't
- need to care about it */
- info->flags &= ~ASYNC_CTS_FLOW;
-
- /* XON/XOFF/XANY flow control flags */
- sw_flow = 0;
- if (iflag & IXON){
- sw_flow |= C_FL_OXX;
- if (iflag & IXANY)
- sw_flow |= C_FL_OIXANY;
- }
- cy_writel(&ch_ctrl->sw_flow, sw_flow);
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
+ break;
+ case CS6:
+ cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
+ break;
+ case CS7:
+ cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
+ break;
+ case CS8:
+ cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
+ break;
+ }
+ if (cflag & CSTOPB) {
+ cy_writel(&ch_ctrl->comm_data_l,
+ cy_readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
+ } else {
+ cy_writel(&ch_ctrl->comm_data_l,
+ cy_readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
+ }
+ if (cflag & PARENB) {
+ if (cflag & PARODD) {
+ cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
+ } else {
+ cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
+ }
+ } else {
+ cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
+ }
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
- if (retval != 0){
- printk("cyc:set_line_char retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ /* CTS flow control flag */
+ if (cflag & CRTSCTS) {
+ cy_writel(&ch_ctrl->hw_flow,
+ cy_readl(&ch_ctrl->
+ hw_flow) | C_RS_CTS | C_RS_RTS);
+ } else {
+ cy_writel(&ch_ctrl->hw_flow,
+ cy_readl(&ch_ctrl->
+ hw_flow) & ~(C_RS_CTS | C_RS_RTS));
+ }
+ /* As the HW flow control is done in firmware, the driver
+ doesn't need to care about it */
+ info->flags &= ~ASYNC_CTS_FLOW;
+
+ /* XON/XOFF/XANY flow control flags */
+ sw_flow = 0;
+ if (iflag & IXON) {
+ sw_flow |= C_FL_OXX;
+ if (iflag & IXANY)
+ sw_flow |= C_FL_OIXANY;
+ }
+ cy_writel(&ch_ctrl->sw_flow, sw_flow);
- /* CD sensitivity */
- if (cflag & CLOCAL){
- info->flags &= ~ASYNC_CHECK_CD;
- }else{
- info->flags |= ASYNC_CHECK_CD;
- }
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
+ if (retval != 0) {
+ printk("cyc:set_line_char retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+
+ /* CD sensitivity */
+ if (cflag & CLOCAL) {
+ info->flags &= ~ASYNC_CHECK_CD;
+ } else {
+ info->flags |= ASYNC_CHECK_CD;
+ }
- if(baud == 0){ /* baud rate is zero, turn off line */
- cy_writel(&ch_ctrl->rs_control,
- cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
+ if (baud == 0) { /* baud rate is zero, turn off line */
+ cy_writel(&ch_ctrl->rs_control,
+ cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char dropping Z DTR\n");
+ printk("cyc:set_line_char dropping Z DTR\n");
#endif
- }else{
- cy_writel(&ch_ctrl->rs_control,
- cy_readl(&ch_ctrl->rs_control) | C_RS_DTR);
+ } else {
+ cy_writel(&ch_ctrl->rs_control,
+ cy_readl(&ch_ctrl->rs_control) | C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char raising Z DTR\n");
+ printk("cyc:set_line_char raising Z DTR\n");
#endif
- }
+ }
- retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTLM, 0L);
- if (retval != 0){
- printk("cyc:set_line_char(2) retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTLM,0L);
+ if (retval != 0) {
+ printk("cyc:set_line_char(2) retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (info->tty) {
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
}
- }
-} /* set_line_char */
-
+} /* set_line_char */
static int
-get_serial_info(struct cyclades_port * info,
- struct serial_struct __user * retinfo)
+get_serial_info(struct cyclades_port *info,
+ struct serial_struct __user * retinfo)
{
- struct serial_struct tmp;
- struct cyclades_card *cinfo = &cy_card[info->card];
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
- tmp.irq = cinfo->irq;
- tmp.flags = info->flags;
- tmp.close_delay = info->close_delay;
- tmp.baud_base = info->baud;
- tmp.custom_divisor = info->custom_divisor;
- tmp.hub6 = 0; /*!!!*/
- return copy_to_user(retinfo,&tmp,sizeof(*retinfo))?-EFAULT:0;
-} /* get_serial_info */
+ struct serial_struct tmp;
+ struct cyclades_card *cinfo = &cy_card[info->card];
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->line;
+ tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
+ tmp.irq = cinfo->irq;
+ tmp.flags = info->flags;
+ tmp.close_delay = info->close_delay;
+ tmp.baud_base = info->baud;
+ tmp.custom_divisor = info->custom_divisor;
+ tmp.hub6 = 0; /*!!! */
+ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
+} /* get_serial_info */
static int
-set_serial_info(struct cyclades_port * info,
- struct serial_struct __user * new_info)
+set_serial_info(struct cyclades_port *info,
+ struct serial_struct __user * new_info)
{
- struct serial_struct new_serial;
- struct cyclades_port old_info;
-
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
- return -EFAULT;
- old_info = *info;
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.close_delay != info->close_delay) ||
- (new_serial.baud_base != info->baud) ||
- ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
- (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
- return -EPERM;
- info->flags = ((info->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- info->baud = new_serial.baud_base;
- info->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- info->baud = new_serial.baud_base;
- info->custom_divisor = new_serial.custom_divisor;
- info->flags = ((info->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- info->close_delay = new_serial.close_delay * HZ/100;
- info->closing_wait = new_serial.closing_wait * HZ/100;
+ struct serial_struct new_serial;
+ struct cyclades_port old_info;
+
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ return -EFAULT;
+ old_info = *info;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if (new_serial.close_delay != info->close_delay ||
+ new_serial.baud_base != info->baud ||
+ (new_serial.flags & ASYNC_FLAGS &
+ ~ASYNC_USR_MASK) !=
+ (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
+ return -EPERM;
+ info->flags = (info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK);
+ info->baud = new_serial.baud_base;
+ info->custom_divisor = new_serial.custom_divisor;
+ goto check_and_exit;
+ }
+
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+
+ info->baud = new_serial.baud_base;
+ info->custom_divisor = new_serial.custom_divisor;
+ info->flags = (info->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS);
+ info->close_delay = new_serial.close_delay * HZ / 100;
+ info->closing_wait = new_serial.closing_wait * HZ / 100;
check_and_exit:
- if (info->flags & ASYNC_INITIALIZED){
- set_line_char(info);
- return 0;
- }else{
- return startup(info);
- }
-} /* set_serial_info */
+ if (info->flags & ASYNC_INITIALIZED) {
+ set_line_char(info);
+ return 0;
+ } else {
+ return startup(info);
+ }
+} /* set_serial_info */
/*
* get_lsr_info - get line status register info
@@ -3473,441 +3562,452 @@ check_and_exit:
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
-static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
+static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
{
- int card, chip, channel, index;
- unsigned char status;
- unsigned int result;
- unsigned long flags;
- void __iomem *base_addr;
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ int card, chip, channel, index;
+ unsigned char status;
+ unsigned int result;
+ unsigned long flags;
+ void __iomem *base_addr;
- CY_LOCK(info, flags);
- status = cy_readb(base_addr+(CySRER<<index)) & (CyTxRdy|CyTxMpty);
- CY_UNLOCK(info, flags);
- result = (status ? 0 : TIOCSER_TEMT);
- } else {
- /* Not supported yet */
- return -EINVAL;
- }
- return put_user(result, (unsigned long __user *) value);
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+
+ CY_LOCK(info, flags);
+ status = cy_readb(base_addr + (CySRER << index)) &
+ (CyTxRdy | CyTxMpty);
+ CY_UNLOCK(info, flags);
+ result = (status ? 0 : TIOCSER_TEMT);
+ } else {
+ /* Not supported yet */
+ return -EINVAL;
+ }
+ return put_user(result, (unsigned long __user *)value);
}
-static int
-cy_tiocmget(struct tty_struct *tty, struct file *file)
+static int cy_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- int card,chip,channel,index;
- void __iomem *base_addr;
- unsigned long flags;
- unsigned char status;
- unsigned long lstatus;
- unsigned int result;
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
-
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int card, chip, channel, index;
+ void __iomem *base_addr;
+ unsigned long flags;
+ unsigned char status;
+ unsigned long lstatus;
+ unsigned int result;
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+
+ if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ return -ENODEV;
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- status = cy_readb(base_addr+(CyMSVR1<<index));
- status |= cy_readb(base_addr+(CyMSVR2<<index));
- CY_UNLOCK(info, flags);
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
- if (info->rtsdtr_inv) {
- result = ((status & CyRTS) ? TIOCM_DTR : 0)
- | ((status & CyDTR) ? TIOCM_RTS : 0);
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ status = cy_readb(base_addr + (CyMSVR1 << index));
+ status |= cy_readb(base_addr + (CyMSVR2 << index));
+ CY_UNLOCK(info, flags);
+
+ if (info->rtsdtr_inv) {
+ result = ((status & CyRTS) ? TIOCM_DTR : 0) |
+ ((status & CyDTR) ? TIOCM_RTS : 0);
+ } else {
+ result = ((status & CyRTS) ? TIOCM_RTS : 0) |
+ ((status & CyDTR) ? TIOCM_DTR : 0);
+ }
+ result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
+ ((status & CyRI) ? TIOCM_RNG : 0) |
+ ((status & CyDSR) ? TIOCM_DSR : 0) |
+ ((status & CyCTS) ? TIOCM_CTS : 0);
} else {
- result = ((status & CyRTS) ? TIOCM_RTS : 0)
- | ((status & CyDTR) ? TIOCM_DTR : 0);
- }
- result |= ((status & CyDCD) ? TIOCM_CAR : 0)
- | ((status & CyRI) ? TIOCM_RNG : 0)
- | ((status & CyDSR) ? TIOCM_DSR : 0)
- | ((status & CyCTS) ? TIOCM_CTS : 0);
- } else {
- base_addr = cy_card[card].base_addr;
-
- if (cy_card[card].num_chips != -1){
- return -EINVAL;
- }
+ base_addr = cy_card[card].base_addr;
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (ISZLOADED(cy_card[card])) {
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
- lstatus = cy_readl(&ch_ctrl[channel].rs_status);
- result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0)
- | ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0)
- | ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0)
- | ((lstatus & C_RS_RI) ? TIOCM_RNG : 0)
- | ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0)
- | ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
- }else{
- result = 0;
- return -ENODEV;
- }
+ if (cy_card[card].num_chips != -1) {
+ return -EINVAL;
+ }
- }
- return result;
-} /* cy_tiomget */
+ firm_id = cy_card[card].base_addr + ID_ADDRESS;
+ if (ISZLOADED(cy_card[card])) {
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+ lstatus = cy_readl(&ch_ctrl[channel].rs_status);
+ result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
+ ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
+ ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
+ ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
+ ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
+ ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
+ } else {
+ result = 0;
+ return -ENODEV;
+ }
+ }
+ return result;
+} /* cy_tiomget */
static int
cy_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
+ unsigned int set, unsigned int clear)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- int card,chip,channel,index;
- void __iomem *base_addr;
- unsigned long flags;
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
-
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- if (set & TIOCM_RTS){
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
- } else {
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- }
- CY_UNLOCK(info, flags);
- }
- if (clear & TIOCM_RTS) {
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR2<<index), ~CyDTR);
- } else {
- cy_writeb(base_addr+(CyMSVR1<<index), ~CyRTS);
- }
- CY_UNLOCK(info, flags);
- }
- if (set & TIOCM_DTR){
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- } else {
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
- }
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int card, chip, channel, index;
+ void __iomem *base_addr;
+ unsigned long flags;
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+ int retval;
+
+ if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ return -ENODEV;
+
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+
+ if (set & TIOCM_RTS) {
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ CyDTR);
+ } else {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ CyRTS);
+ }
+ CY_UNLOCK(info, flags);
+ }
+ if (clear & TIOCM_RTS) {
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ ~CyDTR);
+ } else {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ ~CyRTS);
+ }
+ CY_UNLOCK(info, flags);
+ }
+ if (set & TIOCM_DTR) {
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ CyRTS);
+ } else {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ CyDTR);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:set_modem_info raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- CY_UNLOCK(info, flags);
- }
- if (clear & TIOCM_DTR) {
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR1<<index), ~CyRTS);
- } else {
- cy_writeb(base_addr+(CyMSVR2<<index), ~CyDTR);
- }
+ CY_UNLOCK(info, flags);
+ }
+ if (clear & TIOCM_DTR) {
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ ~CyRTS);
+ } else {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ ~CyDTR);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:set_modem_info dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- CY_UNLOCK(info, flags);
- }
- } else {
- base_addr = cy_card[card].base_addr;
-
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (ISZLOADED(cy_card[card])) {
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
- if (set & TIOCM_RTS){
- CY_LOCK(info, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS);
- CY_UNLOCK(info, flags);
- }
- if (clear & TIOCM_RTS) {
- CY_LOCK(info, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS);
- CY_UNLOCK(info, flags);
- }
- if (set & TIOCM_DTR){
- CY_LOCK(info, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
+ CY_UNLOCK(info, flags);
+ }
+ } else {
+ base_addr = cy_card[card].base_addr;
+
+ firm_id = cy_card[card].base_addr + ID_ADDRESS;
+ if (ISZLOADED(cy_card[card])) {
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ if (set & TIOCM_RTS) {
+ CY_LOCK(info, flags);
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].
+ rs_control) | C_RS_RTS);
+ CY_UNLOCK(info, flags);
+ }
+ if (clear & TIOCM_RTS) {
+ CY_LOCK(info, flags);
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].
+ rs_control) & ~C_RS_RTS);
+ CY_UNLOCK(info, flags);
+ }
+ if (set & TIOCM_DTR) {
+ CY_LOCK(info, flags);
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].
+ rs_control) | C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info raising Z DTR\n");
+ printk("cyc:set_modem_info raising Z DTR\n");
#endif
- CY_UNLOCK(info, flags);
- }
- if (clear & TIOCM_DTR) {
- CY_LOCK(info, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
+ CY_UNLOCK(info, flags);
+ }
+ if (clear & TIOCM_DTR) {
+ CY_LOCK(info, flags);
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].
+ rs_control) & ~C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info clearing Z DTR\n");
+ printk("cyc:set_modem_info clearing Z DTR\n");
#endif
- CY_UNLOCK(info, flags);
- }
- }else{
- return -ENODEV;
- }
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM,0L);
- if (retval != 0){
- printk("cyc:set_modem_info retval on ttyC%d was %x\n",
- info->line, retval);
+ CY_UNLOCK(info, flags);
+ }
+ } else {
+ return -ENODEV;
+ }
+ CY_LOCK(info, flags);
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM, 0L);
+ if (retval != 0) {
+ printk("cyc:set_modem_info retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+ CY_UNLOCK(info, flags);
}
- CY_UNLOCK(info, flags);
- }
- return 0;
-} /* cy_tiocmset */
+ return 0;
+} /* cy_tiocmset */
/*
* cy_break() --- routine which turns the break handling on or off
*/
-static void
-cy_break(struct tty_struct *tty, int break_state)
+static void cy_break(struct tty_struct *tty, int break_state)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "cy_break"))
- return;
-
- CY_LOCK(info, flags);
- if (!IS_CYC_Z(cy_card[info->card])) {
- /* Let the transmit ISR take care of this (since it
- requires stuffing characters into the output stream).
- */
- if (break_state == -1) {
- if (!info->breakon) {
- info->breakon = 1;
- if (!info->xmit_cnt) {
- CY_UNLOCK(info, flags);
- start_xmit(info);
- CY_LOCK(info, flags);
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->name, "cy_break"))
+ return;
+
+ CY_LOCK(info, flags);
+ if (!IS_CYC_Z(cy_card[info->card])) {
+ /* Let the transmit ISR take care of this (since it
+ requires stuffing characters into the output stream).
+ */
+ if (break_state == -1) {
+ if (!info->breakon) {
+ info->breakon = 1;
+ if (!info->xmit_cnt) {
+ CY_UNLOCK(info, flags);
+ start_xmit(info);
+ CY_LOCK(info, flags);
+ }
+ }
+ } else {
+ if (!info->breakoff) {
+ info->breakoff = 1;
+ if (!info->xmit_cnt) {
+ CY_UNLOCK(info, flags);
+ start_xmit(info);
+ CY_LOCK(info, flags);
+ }
+ }
}
- }
} else {
- if (!info->breakoff) {
- info->breakoff = 1;
- if (!info->xmit_cnt) {
- CY_UNLOCK(info, flags);
- start_xmit(info);
- CY_LOCK(info, flags);
+ int retval;
+
+ if (break_state == -1) {
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ info->line - cy_card[info->card].first_line,
+ C_CM_SET_BREAK, 0L);
+ if (retval != 0) {
+ printk("cyc:cy_break (set) retval on ttyC%d "
+ "was %x\n", info->line, retval);
+ }
+ } else {
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ info->line - cy_card[info->card].first_line,
+ C_CM_CLR_BREAK, 0L);
+ if (retval != 0) {
+ printk("cyc:cy_break (clr) retval on ttyC%d "
+ "was %x\n", info->line, retval);
+ }
}
- }
- }
- } else {
- int retval;
-
- if (break_state == -1) {
- retval = cyz_issue_cmd(&cy_card[info->card],
- (info->line) - (cy_card[info->card].first_line),
- C_CM_SET_BREAK, 0L);
- if (retval != 0) {
- printk("cyc:cy_break (set) retval on ttyC%d was %x\n",
- info->line, retval);
- }
- } else {
- retval = cyz_issue_cmd(&cy_card[info->card],
- (info->line) - (cy_card[info->card].first_line),
- C_CM_CLR_BREAK, 0L);
- if (retval != 0) {
- printk("cyc:cy_break (clr) retval on ttyC%d was %x\n",
- info->line, retval);
- }
}
- }
- CY_UNLOCK(info, flags);
-} /* cy_break */
+ CY_UNLOCK(info, flags);
+} /* cy_break */
static int
-get_mon_info(struct cyclades_port * info, struct cyclades_monitor __user * mon)
+get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
{
- if(copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
- return -EFAULT;
- info->mon.int_count = 0;
- info->mon.char_count = 0;
- info->mon.char_max = 0;
- info->mon.char_last = 0;
- return 0;
-}/* get_mon_info */
-
+ if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
+ return -EFAULT;
+ info->mon.int_count = 0;
+ info->mon.char_count = 0;
+ info->mon.char_max = 0;
+ info->mon.char_last = 0;
+ return 0;
+} /* get_mon_info */
-static int
-set_threshold(struct cyclades_port * info, unsigned long value)
+static int set_threshold(struct cyclades_port *info, unsigned long value)
{
- void __iomem *base_addr;
- int card,channel,chip,index;
- unsigned long flags;
-
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- info->cor3 &= ~CyREC_FIFO;
- info->cor3 |= value & CyREC_FIFO;
+ void __iomem *base_addr;
+ int card, channel, chip, index;
+ unsigned long flags;
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCOR3<<index), info->cor3);
- cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
- CY_UNLOCK(info, flags);
- } else {
- // Nothing to do!
- }
- return 0;
-}/* set_threshold */
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ info->cor3 &= ~CyREC_FIFO;
+ info->cor3 |= value & CyREC_FIFO;
-static int
-get_threshold(struct cyclades_port * info, unsigned long __user *value)
-{
- void __iomem *base_addr;
- int card,channel,chip,index;
- unsigned long tmp;
-
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- tmp = cy_readb(base_addr+(CyCOR3<<index)) & CyREC_FIFO;
- return put_user(tmp,value);
- } else {
- // Nothing to do!
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
+ cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
+ CY_UNLOCK(info, flags);
+ } else {
+ /* Nothing to do! */
+ }
return 0;
- }
-}/* get_threshold */
-
+} /* set_threshold */
static int
-set_default_threshold(struct cyclades_port * info, unsigned long value)
+get_threshold(struct cyclades_port *info, unsigned long __user * value)
{
- info->default_threshold = value & 0x0f;
- return 0;
-}/* set_default_threshold */
+ void __iomem *base_addr;
+ int card, channel, chip, index;
+ unsigned long tmp;
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+
+ tmp = cy_readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
+ return put_user(tmp, value);
+ } else {
+ /* Nothing to do! */
+ return 0;
+ }
+} /* get_threshold */
static int
-get_default_threshold(struct cyclades_port * info, unsigned long __user *value)
+set_default_threshold(struct cyclades_port *info, unsigned long value)
{
- return put_user(info->default_threshold,value);
-}/* get_default_threshold */
-
+ info->default_threshold = value & 0x0f;
+ return 0;
+} /* set_default_threshold */
static int
-set_timeout(struct cyclades_port * info, unsigned long value)
+get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
{
- void __iomem *base_addr;
- int card,channel,chip,index;
- unsigned long flags;
-
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ return put_user(info->default_threshold, value);
+} /* get_default_threshold */
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyRTPR<<index), value & 0xff);
- CY_UNLOCK(info, flags);
- } else {
- // Nothing to do!
- }
- return 0;
-}/* set_timeout */
+static int set_timeout(struct cyclades_port *info, unsigned long value)
+{
+ void __iomem *base_addr;
+ int card, channel, chip, index;
+ unsigned long flags;
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
-static int
-get_timeout(struct cyclades_port * info, unsigned long __user *value)
-{
- void __iomem *base_addr;
- int card,channel,chip,index;
- unsigned long tmp;
-
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- tmp = cy_readb(base_addr+(CyRTPR<<index));
- return put_user(tmp,value);
- } else {
- // Nothing to do!
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
+ CY_UNLOCK(info, flags);
+ } else {
+ /* Nothing to do! */
+ }
return 0;
- }
-}/* get_timeout */
-
+} /* set_timeout */
-static int
-set_default_timeout(struct cyclades_port * info, unsigned long value)
+static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
{
- info->default_timeout = value & 0xff;
- return 0;
-}/* set_default_timeout */
+ void __iomem *base_addr;
+ int card, channel, chip, index;
+ unsigned long tmp;
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+
+ tmp = cy_readb(base_addr + (CyRTPR << index));
+ return put_user(tmp, value);
+ } else {
+ /* Nothing to do! */
+ return 0;
+ }
+} /* get_timeout */
+
+static int set_default_timeout(struct cyclades_port *info, unsigned long value)
+{
+ info->default_timeout = value & 0xff;
+ return 0;
+} /* set_default_timeout */
static int
-get_default_timeout(struct cyclades_port * info, unsigned long __user *value)
+get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
{
- return put_user(info->default_timeout,value);
-}/* get_default_timeout */
+ return put_user(info->default_timeout, value);
+} /* get_default_timeout */
/*
* This routine allows the tty driver to implement device-
@@ -3915,184 +4015,193 @@ get_default_timeout(struct cyclades_port * info, unsigned long __user *value)
* not recognized by the driver, it should return ENOIOCTLCMD.
*/
static int
-cy_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
+cy_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- struct cyclades_icount cprev, cnow; /* kernel counter temps */
- struct serial_icounter_struct __user *p_cuser; /* user space */
- int ret_val = 0;
- unsigned long flags;
- void __user *argp = (void __user *)arg;
-
- if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
- return -ENODEV;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct __user *p_cuser; /* user space */
+ int ret_val = 0;
+ unsigned long flags;
+ void __user *argp = (void __user *)arg;
+
+ if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
+ return -ENODEV;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
- info->line, cmd, arg); /* */
+ printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */
#endif
- switch (cmd) {
- case CYGETMON:
- ret_val = get_mon_info(info, argp);
- break;
- case CYGETTHRESH:
- ret_val = get_threshold(info, argp);
- break;
- case CYSETTHRESH:
- ret_val = set_threshold(info, arg);
- break;
- case CYGETDEFTHRESH:
- ret_val = get_default_threshold(info, argp);
- break;
- case CYSETDEFTHRESH:
- ret_val = set_default_threshold(info, arg);
- break;
- case CYGETTIMEOUT:
- ret_val = get_timeout(info, argp);
- break;
- case CYSETTIMEOUT:
- ret_val = set_timeout(info, arg);
- break;
- case CYGETDEFTIMEOUT:
- ret_val = get_default_timeout(info, argp);
- break;
- case CYSETDEFTIMEOUT:
- ret_val = set_default_timeout(info, arg);
- break;
+ switch (cmd) {
+ case CYGETMON:
+ ret_val = get_mon_info(info, argp);
+ break;
+ case CYGETTHRESH:
+ ret_val = get_threshold(info, argp);
+ break;
+ case CYSETTHRESH:
+ ret_val = set_threshold(info, arg);
+ break;
+ case CYGETDEFTHRESH:
+ ret_val = get_default_threshold(info, argp);
+ break;
+ case CYSETDEFTHRESH:
+ ret_val = set_default_threshold(info, arg);
+ break;
+ case CYGETTIMEOUT:
+ ret_val = get_timeout(info, argp);
+ break;
+ case CYSETTIMEOUT:
+ ret_val = set_timeout(info, arg);
+ break;
+ case CYGETDEFTIMEOUT:
+ ret_val = get_default_timeout(info, argp);
+ break;
+ case CYSETDEFTIMEOUT:
+ ret_val = set_default_timeout(info, arg);
+ break;
case CYSETRFLOW:
- info->rflow = (int)arg;
- ret_val = 0;
- break;
+ info->rflow = (int)arg;
+ ret_val = 0;
+ break;
case CYGETRFLOW:
- ret_val = info->rflow;
- break;
+ ret_val = info->rflow;
+ break;
case CYSETRTSDTR_INV:
- info->rtsdtr_inv = (int)arg;
- ret_val = 0;
- break;
+ info->rtsdtr_inv = (int)arg;
+ ret_val = 0;
+ break;
case CYGETRTSDTR_INV:
- ret_val = info->rtsdtr_inv;
- break;
+ ret_val = info->rtsdtr_inv;
+ break;
case CYGETCARDINFO:
- if (copy_to_user(argp, &cy_card[info->card],
- sizeof (struct cyclades_card))) {
- ret_val = -EFAULT;
+ if (copy_to_user(argp, &cy_card[info->card],
+ sizeof(struct cyclades_card))) {
+ ret_val = -EFAULT;
+ break;
+ }
+ ret_val = 0;
break;
- }
- ret_val = 0;
- break;
case CYGETCD1400VER:
- ret_val = info->chip_rev;
- break;
+ ret_val = info->chip_rev;
+ break;
#ifndef CONFIG_CYZ_INTR
case CYZSETPOLLCYCLE:
- cyz_polling_cycle = (arg * HZ) / 1000;
- ret_val = 0;
- break;
+ cyz_polling_cycle = (arg * HZ) / 1000;
+ ret_val = 0;
+ break;
case CYZGETPOLLCYCLE:
- ret_val = (cyz_polling_cycle * 1000) / HZ;
- break;
-#endif /* CONFIG_CYZ_INTR */
+ ret_val = (cyz_polling_cycle * 1000) / HZ;
+ break;
+#endif /* CONFIG_CYZ_INTR */
case CYSETWAIT:
- info->closing_wait = (unsigned short)arg * HZ/100;
- ret_val = 0;
- break;
+ info->closing_wait = (unsigned short)arg *HZ / 100;
+ ret_val = 0;
+ break;
case CYGETWAIT:
- ret_val = info->closing_wait / (HZ/100);
- break;
- case TIOCGSERIAL:
- ret_val = get_serial_info(info, argp);
- break;
- case TIOCSSERIAL:
- ret_val = set_serial_info(info, argp);
- break;
- case TIOCSERGETLSR: /* Get line status register */
- ret_val = get_lsr_info(info, argp);
- break;
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- */
+ ret_val = info->closing_wait / (HZ / 100);
+ break;
+ case TIOCGSERIAL:
+ ret_val = get_serial_info(info, argp);
+ break;
+ case TIOCSSERIAL:
+ ret_val = set_serial_info(info, argp);
+ break;
+ case TIOCSERGETLSR: /* Get line status register */
+ ret_val = get_lsr_info(info, argp);
+ break;
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
case TIOCMIWAIT:
- CY_LOCK(info, flags);
- /* note the counters on entry */
- cprev = info->icount;
- CY_UNLOCK(info, flags);
- while (1) {
- interruptible_sleep_on(&info->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current)) {
- return -ERESTARTSYS;
- }
-
CY_LOCK(info, flags);
- cnow = info->icount; /* atomic copy */
+ /* note the counters on entry */
+ cprev = info->icount;
CY_UNLOCK(info, flags);
+ while (1) {
+ interruptible_sleep_on(&info->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current)) {
+ return -ERESTARTSYS;
+ }
- 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 */
+ CY_LOCK(info, flags);
+ cnow = info->icount; /* atomic copy */
+ CY_UNLOCK(info, flags);
- /*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- * RI where only 0->1 is counted.
- */
+ 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 */
+
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
case TIOCGICOUNT:
- CY_LOCK(info, flags);
- cnow = info->icount;
- CY_UNLOCK(info, flags);
- p_cuser = argp;
- ret_val = put_user(cnow.cts, &p_cuser->cts);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.dsr, &p_cuser->dsr);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.rng, &p_cuser->rng);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.dcd, &p_cuser->dcd);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.rx, &p_cuser->rx);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.tx, &p_cuser->tx);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.frame, &p_cuser->frame);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.overrun, &p_cuser->overrun);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.parity, &p_cuser->parity);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.brk, &p_cuser->brk);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
- if (ret_val) return ret_val;
- ret_val = 0;
- break;
- default:
- ret_val = -ENOIOCTLCMD;
- }
+ CY_LOCK(info, flags);
+ cnow = info->icount;
+ CY_UNLOCK(info, flags);
+ p_cuser = argp;
+ ret_val = put_user(cnow.cts, &p_cuser->cts);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.dsr, &p_cuser->dsr);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.rng, &p_cuser->rng);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.dcd, &p_cuser->dcd);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.rx, &p_cuser->rx);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.tx, &p_cuser->tx);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.frame, &p_cuser->frame);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.overrun, &p_cuser->overrun);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.parity, &p_cuser->parity);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.brk, &p_cuser->brk);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
+ if (ret_val)
+ return ret_val;
+ ret_val = 0;
+ break;
+ default:
+ ret_val = -ENOIOCTLCMD;
+ }
#ifdef CY_DEBUG_OTHER
- printk(" cyc:cy_ioctl done\n");
+ printk(" cyc:cy_ioctl done\n");
#endif
- return ret_val;
-} /* cy_ioctl */
-
+ return ret_val;
+} /* cy_ioctl */
/*
* This routine allows the tty driver to be notified when
@@ -4100,66 +4209,64 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
* well-designed tty driver should be prepared to accept the case
* where old == NULL, and try to do something rational.
*/
-static void
-cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
+static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_set_termios ttyC%d\n", info->line);
+ printk("cyc:cy_set_termios ttyC%d\n", info->line);
#endif
- if ((tty->termios->c_cflag == old_termios->c_cflag) &&
- ((tty->termios->c_iflag & (IXON|IXANY)) ==
- (old_termios->c_iflag & (IXON|IXANY))))
- return;
- set_line_char(info);
-
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- cy_start(tty);
- }
+ if (tty->termios->c_cflag == old_termios->c_cflag &&
+ (tty->termios->c_iflag & (IXON | IXANY)) ==
+ (old_termios->c_iflag & (IXON | IXANY)))
+ return;
+ set_line_char(info);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ cy_start(tty);
+ }
#if 0
- /*
- * No need to wake up processes in open wait, since they
- * sample the CLOCAL flag once, and don't recheck it.
- * XXX It's not clear whether the current behavior is correct
- * or not. Hence, this may change.....
- */
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
- wake_up_interruptible(&info->open_wait);
+ /*
+ * No need to wake up processes in open wait, since they
+ * sample the CLOCAL flag once, and don't recheck it.
+ * XXX It's not clear whether the current behavior is correct
+ * or not. Hence, this may change.....
+ */
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&info->open_wait);
#endif
-
- return;
-} /* cy_set_termios */
+} /* cy_set_termios */
/* This function is used to send a high-priority XON/XOFF character to
the device.
*/
-static void
-cy_send_xchar (struct tty_struct *tty, char ch)
+static void cy_send_xchar(struct tty_struct *tty, char ch)
{
- struct cyclades_port *info = (struct cyclades_port *) tty->driver_data;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
int card, channel;
- if (serial_paranoia_check (info, tty->name, "cy_send_xchar"))
+ if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
return;
- info->x_char = ch;
+ info->x_char = ch;
if (ch)
- cy_start (tty);
+ cy_start(tty);
card = info->card;
channel = info->line - cy_card[card].first_line;
- if (IS_CYC_Z (cy_card[card])) {
- if (ch == STOP_CHAR (tty))
- cyz_issue_cmd (&cy_card[card], channel, C_CM_SENDXOFF, 0L);
- else if (ch == START_CHAR (tty))
- cyz_issue_cmd (&cy_card[card], channel, C_CM_SENDXON, 0L);
+ if (IS_CYC_Z(cy_card[card])) {
+ if (ch == STOP_CHAR(tty))
+ cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXOFF,
+ 0L);
+ else if (ch == START_CHAR(tty))
+ cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXON,
+ 0L);
}
}
@@ -4167,260 +4274,248 @@ cy_send_xchar (struct tty_struct *tty, char ch)
that incoming characters should be throttled because the input
buffers are close to full.
*/
-static void
-cy_throttle(struct tty_struct * tty)
+static void cy_throttle(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- void __iomem *base_addr;
- int card,chip,channel,index;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
- char buf[64];
+ char buf[64];
- printk("cyc:throttle %s: %d....ttyC%d\n",
- tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty), info->line);
+ printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty), info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_throttle")){
- return;
- }
-
- card = info->card;
-
- if (I_IXOFF(tty)) {
- if (!IS_CYC_Z (cy_card[card]))
- cy_send_xchar (tty, STOP_CHAR (tty));
- else
- info->throttle = 1;
- }
-
- if (tty->termios->c_cflag & CRTSCTS) {
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR2<<index), ~CyDTR);
- } else {
- cy_writeb(base_addr+(CyMSVR1<<index), ~CyRTS);
- }
- CY_UNLOCK(info, flags);
- } else {
- info->throttle = 1;
- }
- }
+ if (serial_paranoia_check(info, tty->name, "cy_throttle")) {
+ return;
+ }
- return;
-} /* cy_throttle */
+ card = info->card;
+
+ if (I_IXOFF(tty)) {
+ if (!IS_CYC_Z(cy_card[card]))
+ cy_send_xchar(tty, STOP_CHAR(tty));
+ else
+ info->throttle = 1;
+ }
+ if (tty->termios->c_cflag & CRTSCTS) {
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
+
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ ~CyDTR);
+ } else {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ ~CyRTS);
+ }
+ CY_UNLOCK(info, flags);
+ } else {
+ info->throttle = 1;
+ }
+ }
+} /* cy_throttle */
/*
* This routine notifies the tty driver that it should signal
* that characters can now be sent to the tty without fear of
* overrunning the input buffers of the line disciplines.
*/
-static void
-cy_unthrottle(struct tty_struct * tty)
+static void cy_unthrottle(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- void __iomem *base_addr;
- int card,chip,channel,index;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
- char buf[64];
-
- printk("cyc:unthrottle %s: %d....ttyC%d\n",
- tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty), info->line);
-#endif
+ char buf[64];
- if (serial_paranoia_check(info, tty->name, "cy_unthrottle")){
- return;
- }
+ printk("cyc:unthrottle %s: %d....ttyC%d\n", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty), info->line);
+#endif
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- cy_send_xchar (tty, START_CHAR (tty));
- }
-
- if (tty->termios->c_cflag & CRTSCTS) {
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
- } else {
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- }
- CY_UNLOCK(info, flags);
- } else {
- info->throttle = 0;
+ if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) {
+ return;
}
- }
- return;
-} /* cy_unthrottle */
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ cy_send_xchar(tty, START_CHAR(tty));
+ }
+ if (tty->termios->c_cflag & CRTSCTS) {
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
+
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ CyDTR);
+ } else {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ CyRTS);
+ }
+ CY_UNLOCK(info, flags);
+ } else {
+ info->throttle = 0;
+ }
+ }
+} /* cy_unthrottle */
/* cy_start and cy_stop provide software output flow control as a
function of XON/XOFF, software CTS, and other such stuff.
*/
-static void
-cy_stop(struct tty_struct *tty)
+static void cy_stop(struct tty_struct *tty)
{
- struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- void __iomem *base_addr;
- int chip,channel,index;
- unsigned long flags;
+ struct cyclades_card *cinfo;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ void __iomem *base_addr;
+ int chip, channel, index;
+ unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_stop ttyC%d\n", info->line); /* */
+ printk("cyc:cy_stop ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_stop"))
- return;
-
- cinfo = &cy_card[info->card];
- channel = info->line - cinfo->first_line;
- if (!IS_CYC_Z(*cinfo)) {
- index = cinfo->bus_index;
- chip = channel>>2;
- channel &= 0x03;
- base_addr = cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index);
-
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index),
- (u_char)(channel & 0x0003)); /* index channel */
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy);
- CY_UNLOCK(info, flags);
- } else {
- // Nothing to do!
- }
+ if (serial_paranoia_check(info, tty->name, "cy_stop"))
+ return;
- return;
-} /* cy_stop */
+ cinfo = &cy_card[info->card];
+ channel = info->line - cinfo->first_line;
+ if (!IS_CYC_Z(*cinfo)) {
+ index = cinfo->bus_index;
+ chip = channel >> 2;
+ channel &= 0x03;
+ base_addr = cy_card[info->card].base_addr +
+ (cy_chip_offset[chip] << index);
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char)(channel & 0x0003)); /* index channel */
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+ CY_UNLOCK(info, flags);
+ } else {
+ /* Nothing to do! */
+ }
+} /* cy_stop */
-static void
-cy_start(struct tty_struct *tty)
+static void cy_start(struct tty_struct *tty)
{
- struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- void __iomem *base_addr;
- int chip,channel,index;
- unsigned long flags;
+ struct cyclades_card *cinfo;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ void __iomem *base_addr;
+ int chip, channel, index;
+ unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_start ttyC%d\n", info->line); /* */
+ printk("cyc:cy_start ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_start"))
- return;
-
- cinfo = &cy_card[info->card];
- channel = info->line - cinfo->first_line;
- index = cinfo->bus_index;
- if (!IS_CYC_Z(*cinfo)) {
- chip = channel>>2;
- channel &= 0x03;
- base_addr = cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index);
-
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index),
- (u_char)(channel & 0x0003)); /* index channel */
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyTxRdy);
- CY_UNLOCK(info, flags);
- } else {
- // Nothing to do!
- }
+ if (serial_paranoia_check(info, tty->name, "cy_start"))
+ return;
- return;
-} /* cy_start */
+ cinfo = &cy_card[info->card];
+ channel = info->line - cinfo->first_line;
+ index = cinfo->bus_index;
+ if (!IS_CYC_Z(*cinfo)) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ base_addr = cy_card[info->card].base_addr +
+ (cy_chip_offset[chip] << index);
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
+ CY_UNLOCK(info, flags);
+ } else {
+ /* Nothing to do! */
+ }
+} /* cy_start */
-static void
-cy_flush_buffer(struct tty_struct *tty)
+static void cy_flush_buffer(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, channel, retval;
- unsigned long flags;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int card, channel, retval;
+ unsigned long flags;
+
#ifdef CY_DEBUG_IO
- printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
+ printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
- return;
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
+ return;
- CY_LOCK(info, flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- CY_UNLOCK(info, flags);
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
- if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board
- buffers as well */
CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
- if (retval != 0) {
- printk("cyc: flush_buffer retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
CY_UNLOCK(info, flags);
- }
- tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
-} /* cy_flush_buffer */
+ if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board
+ buffers as well */
+ CY_LOCK(info, flags);
+ retval =
+ cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
+ if (retval != 0) {
+ printk("cyc: flush_buffer retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+ CY_UNLOCK(info, flags);
+ }
+ tty_wakeup(tty);
+ wake_up_interruptible(&tty->write_wait);
+} /* cy_flush_buffer */
/*
* cy_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
-static void
-cy_hangup(struct tty_struct *tty)
+static void cy_hangup(struct tty_struct *tty)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
+ printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_hangup"))
- return;
+ if (serial_paranoia_check(info, tty->name, "cy_hangup"))
+ return;
- cy_flush_buffer(tty);
- shutdown(info);
- info->event = 0;
- info->count = 0;
+ cy_flush_buffer(tty);
+ shutdown(info);
+ info->event = 0;
+ info->count = 0;
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
+ printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
#endif
- info->tty = NULL;
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
- wake_up_interruptible(&info->open_wait);
-} /* cy_hangup */
-
+ info->tty = NULL;
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ wake_up_interruptible(&info->open_wait);
+} /* cy_hangup */
/*
* ---------------------------------------------------------------------
@@ -4433,82 +4528,84 @@ cy_hangup(struct tty_struct *tty)
/* initialize chips on Cyclom-Y card -- return number of valid
chips (which is number of ports/4) */
static unsigned short __init
-cyy_init_card(void __iomem *true_base_addr,int index)
+cyy_init_card(void __iomem * true_base_addr, int index)
{
- unsigned int chip_number;
- void __iomem *base_addr;
-
- cy_writeb(true_base_addr+(Cy_HwReset<<index), 0);
- /* Cy_HwReset is 0x1400 */
- cy_writeb(true_base_addr+(Cy_ClrIntr<<index), 0);
- /* Cy_ClrIntr is 0x1800 */
- udelay(500L);
-
- for(chip_number=0; chip_number<CyMAX_CHIPS_PER_CARD; chip_number++){
- base_addr = true_base_addr + (cy_chip_offset[chip_number]<<index);
- mdelay(1);
- if(cy_readb(base_addr+(CyCCR<<index)) != 0x00){
- /*************
- printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
- chip_number, (unsigned long)base_addr);
- *************/
- return chip_number;
- }
-
- cy_writeb(base_addr+(CyGFRCR<<index), 0);
- udelay(10L);
-
- /* The Cyclom-16Y does not decode address bit 9 and therefore
- cannot distinguish between references to chip 0 and a non-
- existent chip 4. If the preceding clearing of the supposed
- chip 4 GFRCR register appears at chip 0, there is no chip 4
- and this must be a Cyclom-16Y, not a Cyclom-32Ye.
- */
- if (chip_number == 4
- && cy_readb(true_base_addr
- + (cy_chip_offset[0]<<index)
- + (CyGFRCR<<index)) == 0){
- return chip_number;
- }
-
- cy_writeb(base_addr+(CyCCR<<index), CyCHIP_RESET);
- mdelay(1);
-
- if(cy_readb(base_addr+(CyGFRCR<<index)) == 0x00){
- /*
- printk(" chip #%d at %#6lx is not responding ",
- chip_number, (unsigned long)base_addr);
- printk("(GFRCR stayed 0)\n",
- */
- return chip_number;
- }
- if((0xf0 & (cy_readb(base_addr+(CyGFRCR<<index)))) != 0x40){
- /*
- printk(" chip #%d at %#6lx is not valid (GFRCR == %#2x)\n",
- chip_number, (unsigned long)base_addr,
- base_addr[CyGFRCR<<index]);
- */
- return chip_number;
- }
- cy_writeb(base_addr+(CyGCR<<index), CyCH0_SERIAL);
- if (cy_readb(base_addr+(CyGFRCR<<index)) >= CD1400_REV_J){
- /* It is a CD1400 rev. J or later */
- /* Impossible to reach 5ms with this chip.
- Changed to 2ms instead (f = 500 Hz). */
- cy_writeb(base_addr+(CyPPR<<index), CyCLOCK_60_2MS);
- } else {
- /* f = 200 Hz */
- cy_writeb(base_addr+(CyPPR<<index), CyCLOCK_25_5MS);
- }
+ unsigned int chip_number;
+ void __iomem *base_addr;
+
+ cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
+ /* Cy_HwReset is 0x1400 */
+ cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
+ /* Cy_ClrIntr is 0x1800 */
+ udelay(500L);
+
+ for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; chip_number++) {
+ base_addr =
+ true_base_addr + (cy_chip_offset[chip_number] << index);
+ mdelay(1);
+ if (cy_readb(base_addr + (CyCCR << index)) != 0x00) {
+ /*************
+ printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
+ chip_number, (unsigned long)base_addr);
+ *************/
+ return chip_number;
+ }
+
+ cy_writeb(base_addr + (CyGFRCR << index), 0);
+ udelay(10L);
+
+ /* The Cyclom-16Y does not decode address bit 9 and therefore
+ cannot distinguish between references to chip 0 and a non-
+ existent chip 4. If the preceding clearing of the supposed
+ chip 4 GFRCR register appears at chip 0, there is no chip 4
+ and this must be a Cyclom-16Y, not a Cyclom-32Ye.
+ */
+ if (chip_number == 4 && cy_readb(true_base_addr +
+ (cy_chip_offset[0] << index) +
+ (CyGFRCR << index)) == 0) {
+ return chip_number;
+ }
+
+ cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
+ mdelay(1);
+
+ if (cy_readb(base_addr + (CyGFRCR << index)) == 0x00) {
+ /*
+ printk(" chip #%d at %#6lx is not responding ",
+ chip_number, (unsigned long)base_addr);
+ printk("(GFRCR stayed 0)\n",
+ */
+ return chip_number;
+ }
+ if ((0xf0 & (cy_readb(base_addr + (CyGFRCR << index)))) !=
+ 0x40) {
+ /*
+ printk(" chip #%d at %#6lx is not valid (GFRCR == "
+ "%#2x)\n",
+ chip_number, (unsigned long)base_addr,
+ base_addr[CyGFRCR<<index]);
+ */
+ return chip_number;
+ }
+ cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
+ if (cy_readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
+ /* It is a CD1400 rev. J or later */
+ /* Impossible to reach 5ms with this chip.
+ Changed to 2ms instead (f = 500 Hz). */
+ cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
+ } else {
+ /* f = 200 Hz */
+ cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
+ }
- /*
- printk(" chip #%d at %#6lx is rev 0x%2x\n",
- chip_number, (unsigned long)base_addr,
- cy_readb(base_addr+(CyGFRCR<<index)));
- */
- }
- return chip_number;
-} /* cyy_init_card */
+ /*
+ printk(" chip #%d at %#6lx is rev 0x%2x\n",
+ chip_number, (unsigned long)base_addr,
+ cy_readb(base_addr+(CyGFRCR<<index)));
+ */
+ }
+ return chip_number;
+} /* cyy_init_card */
/*
* ---------------------------------------------------------------------
@@ -4516,126 +4613,124 @@ cyy_init_card(void __iomem *true_base_addr,int index)
* sets global variables and return the number of ISA boards found.
* ---------------------------------------------------------------------
*/
-static int __init
-cy_detect_isa(void)
+static int __init cy_detect_isa(void)
{
#ifdef CONFIG_ISA
- unsigned short cy_isa_irq,nboard;
- void __iomem *cy_isa_address;
- unsigned short i,j,cy_isa_nchan;
+ unsigned short cy_isa_irq, nboard;
+ void __iomem *cy_isa_address;
+ unsigned short i, j, cy_isa_nchan;
#ifdef MODULE
- int isparam = 0;
+ int isparam = 0;
#endif
- nboard = 0;
+ nboard = 0;
#ifdef MODULE
/* Check for module parameters */
- for(i = 0 ; i < NR_CARDS; i++) {
- if (maddr[i] || i) {
- isparam = 1;
- cy_isa_addresses[i] = maddr[i];
- }
- if (!maddr[i])
- break;
+ for (i = 0; i < NR_CARDS; i++) {
+ if (maddr[i] || i) {
+ isparam = 1;
+ cy_isa_addresses[i] = maddr[i];
+ }
+ if (!maddr[i])
+ break;
}
#endif
- /* scan the address table probing for Cyclom-Y/ISA boards */
- for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
- unsigned int isa_address = cy_isa_addresses[i];
- if (isa_address == 0x0000) {
- return(nboard);
- }
+ /* scan the address table probing for Cyclom-Y/ISA boards */
+ for (i = 0; i < NR_ISA_ADDRS; i++) {
+ unsigned int isa_address = cy_isa_addresses[i];
+ if (isa_address == 0x0000) {
+ return nboard;
+ }
- /* probe for CD1400... */
+ /* probe for CD1400... */
cy_isa_address = ioremap(isa_address, CyISA_Ywin);
- cy_isa_nchan = CyPORTS_PER_CHIP *
- cyy_init_card(cy_isa_address,0);
- if (cy_isa_nchan == 0) {
- continue;
- }
-
+ cy_isa_nchan = CyPORTS_PER_CHIP *
+ cyy_init_card(cy_isa_address, 0);
+ if (cy_isa_nchan == 0) {
+ continue;
+ }
#ifdef MODULE
if (isparam && irq[i])
- cy_isa_irq = irq[i];
+ cy_isa_irq = irq[i];
else
#endif
- /* find out the board's irq by probing */
- cy_isa_irq = detect_isa_irq(cy_isa_address);
- if (cy_isa_irq == 0) {
- printk("Cyclom-Y/ISA found at 0x%lx ",
- (unsigned long) cy_isa_address);
- printk("but the IRQ could not be detected.\n");
- continue;
- }
-
- if((cy_next_channel+cy_isa_nchan) > NR_PORTS) {
- printk("Cyclom-Y/ISA found at 0x%lx ",
- (unsigned long) cy_isa_address);
- printk("but no more channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
- return(nboard);
- }
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/ISA found at 0x%lx ",
- (unsigned long) cy_isa_address);
- printk("but no more cards can be used .\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
- return(nboard);
- }
-
- /* allocate IRQ */
- if(request_irq(cy_isa_irq, cyy_interrupt,
- IRQF_DISABLED, "Cyclom-Y", &cy_card[j]))
- {
- printk("Cyclom-Y/ISA found at 0x%lx ",
- (unsigned long) cy_isa_address);
- printk("but could not allocate IRQ#%d.\n",
- cy_isa_irq);
- return(nboard);
- }
-
- /* set cy_card */
- cy_card[j].base_addr = cy_isa_address;
- cy_card[j].ctl_addr = NULL;
- cy_card[j].irq = (int) cy_isa_irq;
- cy_card[j].bus_index = 0;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = cy_isa_nchan/4;
- nboard++;
-
- /* print message */
- printk("Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d, ",
- j+1, (unsigned long) cy_isa_address,
- (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
- cy_isa_irq);
- printk("%d channels starting from port %d.\n",
- cy_isa_nchan, cy_next_channel);
- cy_next_channel += cy_isa_nchan;
- }
- return(nboard);
+ /* find out the board's irq by probing */
+ cy_isa_irq = detect_isa_irq(cy_isa_address);
+ if (cy_isa_irq == 0) {
+ printk("Cyclom-Y/ISA found at 0x%lx ",
+ (unsigned long)cy_isa_address);
+ printk("but the IRQ could not be detected.\n");
+ continue;
+ }
+
+ if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
+ printk("Cyclom-Y/ISA found at 0x%lx ",
+ (unsigned long)cy_isa_address);
+ printk("but no more channels are available.\n");
+ printk("Change NR_PORTS in cyclades.c and recompile "
+ "kernel.\n");
+ return nboard;
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0; j < NR_CARDS; j++) {
+ if (cy_card[j].base_addr == 0)
+ break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclom-Y/ISA found at 0x%lx ",
+ (unsigned long)cy_isa_address);
+ printk("but no more cards can be used .\n");
+ printk("Change NR_CARDS in cyclades.c and recompile "
+ "kernel.\n");
+ return nboard;
+ }
+
+ /* allocate IRQ */
+ if (request_irq(cy_isa_irq, cyy_interrupt,
+ IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
+ printk("Cyclom-Y/ISA found at 0x%lx ",
+ (unsigned long)cy_isa_address);
+ printk("but could not allocate IRQ#%d.\n", cy_isa_irq);
+ return nboard;
+ }
+
+ /* set cy_card */
+ cy_card[j].base_addr = cy_isa_address;
+ cy_card[j].ctl_addr = NULL;
+ cy_card[j].irq = (int)cy_isa_irq;
+ cy_card[j].bus_index = 0;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = cy_isa_nchan / 4;
+ nboard++;
+
+ /* print message */
+ printk("Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d, ",
+ j + 1, (unsigned long)cy_isa_address,
+ (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
+ cy_isa_irq);
+ printk("%d channels starting from port %d.\n",
+ cy_isa_nchan, cy_next_channel);
+ cy_next_channel += cy_isa_nchan;
+ }
+ return nboard;
#else
- return(0);
-#endif /* CONFIG_ISA */
-} /* cy_detect_isa */
+ return 0;
+#endif /* CONFIG_ISA */
+} /* cy_detect_isa */
-static void
-plx_init(void __iomem *addr, uclong initctl)
+static void plx_init(void __iomem * addr, uclong initctl)
{
- /* Reset PLX */
- cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000);
- udelay(100L);
- cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000);
-
- /* Reload Config. Registers from EEPROM */
- cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000);
- udelay(100L);
- cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000);
+ /* Reset PLX */
+ cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000);
+ udelay(100L);
+ cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000);
+
+ /* Reload Config. Registers from EEPROM */
+ cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000);
+ udelay(100L);
+ cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000);
}
/*
@@ -4644,43 +4739,42 @@ plx_init(void __iomem *addr, uclong initctl)
* sets global variables and return the number of PCI boards found.
* ---------------------------------------------------------------------
*/
-static int __init
-cy_detect_pci(void)
+static int __init cy_detect_pci(void)
{
#ifdef CONFIG_PCI
- struct pci_dev *pdev = NULL;
- unsigned char cyy_rev_id;
- unsigned char cy_pci_irq = 0;
- uclong cy_pci_phys0, cy_pci_phys2;
- void __iomem *cy_pci_addr0, *cy_pci_addr2;
- unsigned short i,j,cy_pci_nchan, plx_ver;
- unsigned short device_id,dev_index = 0;
- uclong mailbox;
- uclong ZeIndex = 0;
- void __iomem *Ze_addr0[NR_CARDS], *Ze_addr2[NR_CARDS];
- uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
- unsigned char Ze_irq[NR_CARDS];
- struct pci_dev *Ze_pdev[NR_CARDS];
-
- for (i = 0; i < NR_CARDS; i++) {
- /* look for a Cyclades card by vendor and device id */
- while((device_id = cy_pci_dev_id[dev_index]) != 0) {
- if((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES,
- device_id, pdev)) == NULL) {
- dev_index++; /* try next device id */
- } else {
- break; /* found a board */
- }
- }
+ struct pci_dev *pdev = NULL;
+ unsigned char cyy_rev_id;
+ unsigned char cy_pci_irq = 0;
+ uclong cy_pci_phys0, cy_pci_phys2;
+ void __iomem *cy_pci_addr0, *cy_pci_addr2;
+ unsigned short i, j, cy_pci_nchan, plx_ver;
+ unsigned short device_id, dev_index = 0;
+ uclong mailbox;
+ uclong ZeIndex = 0;
+ void __iomem *Ze_addr0[NR_CARDS], *Ze_addr2[NR_CARDS];
+ uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
+ unsigned char Ze_irq[NR_CARDS];
+ struct pci_dev *Ze_pdev[NR_CARDS];
+
+ for (i = 0; i < NR_CARDS; i++) {
+ /* look for a Cyclades card by vendor and device id */
+ while ((device_id = cy_pci_dev_id[dev_index]) != 0) {
+ if ((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES,
+ device_id, pdev)) == NULL) {
+ dev_index++; /* try next device id */
+ } else {
+ break; /* found a board */
+ }
+ }
if (device_id == 0)
- break;
+ break;
if (pci_enable_device(pdev))
- continue;
+ continue;
- /* read PCI configuration area */
+ /* read PCI configuration area */
cy_pci_irq = pdev->irq;
cy_pci_phys0 = pci_resource_start(pdev, 0);
cy_pci_phys2 = pci_resource_start(pdev, 2);
@@ -4688,482 +4782,497 @@ cy_detect_pci(void)
device_id &= ~PCI_DEVICE_ID_MASK;
- if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
- || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
+ device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
#ifdef CY_PCI_DEBUG
- printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclom-Y/PCI:found winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
+ printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+ pdev->bus->number, pdev->devfn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclom-Y/PCI:found winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
#endif
- if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
- printk(" Warning: PCI I/O bit incorrectly set. "
- "Ignoring it...\n");
- pdev->resource[2].flags &= ~IORESOURCE_IO;
- }
-
- /* Although we don't use this I/O region, we should
- request it from the kernel anyway, to avoid problems
- with other drivers accessing it. */
- if (pci_request_regions(pdev, "Cyclom-Y") != 0) {
- printk(KERN_ERR "cyclades: failed to reserve PCI resources\n");
- continue;
- }
+ if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
+ printk(" Warning: PCI I/O bit incorrectly "
+ "set. Ignoring it...\n");
+ pdev->resource[2].flags &= ~IORESOURCE_IO;
+ }
+ /* Although we don't use this I/O region, we should
+ request it from the kernel anyway, to avoid problems
+ with other drivers accessing it. */
+ if (pci_request_regions(pdev, "Cyclom-Y") != 0) {
+ printk(KERN_ERR "cyclades: failed to reserve "
+ "PCI resources\n");
+ continue;
+ }
#if defined(__alpha__)
- if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
- printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclom-Y/PCI:found winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
- printk("Cyclom-Y/PCI not supported for low addresses in "
- "Alpha systems.\n");
- i--;
- continue;
- }
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
+ printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+ pdev->bus->number, pdev->devfn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclom-Y/PCI:found winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (ulong)cy_pci_phys2,
+ (ulong)cy_pci_phys0);
+ printk("Cyclom-Y/PCI not supported for low "
+ "addresses in Alpha systems.\n");
+ i--;
+ continue;
+ }
#endif
- cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Yctl);
- cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ywin);
+ cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Yctl);
+ cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ywin);
#ifdef CY_PCI_DEBUG
- printk("Cyclom-Y/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
- (u_long)cy_pci_addr2, (u_long)cy_pci_addr0);
+ printk("Cyclom-Y/PCI: relocate winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (u_long)cy_pci_addr2, (u_long)cy_pci_addr0);
#endif
- cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP *
- cyy_init_card(cy_pci_addr2, 1));
- if(cy_pci_nchan == 0) {
- printk("Cyclom-Y PCI host card with ");
- printk("no Serial-Modules at 0x%lx.\n",
- (ulong) cy_pci_phys2);
- i--;
- continue;
- }
- if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but no channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
- return(i);
- }
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
- return(i);
- }
-
- /* allocate IRQ */
- if(request_irq(cy_pci_irq, cyy_interrupt,
- IRQF_SHARED, "Cyclom-Y", &cy_card[j]))
- {
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but could not allocate IRQ%d.\n",
- cy_pci_irq);
- return(i);
- }
-
- /* set cy_card */
- cy_card[j].base_phys = (ulong)cy_pci_phys2;
- cy_card[j].ctl_phys = (ulong)cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int) cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = cy_pci_nchan/4;
- cy_card[j].pdev = pdev;
-
- /* enable interrupts in the PCI interface */
- plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
- switch (plx_ver) {
- case PLX_9050:
-
- cy_writeb(cy_pci_addr0+0x4c, 0x43);
- break;
-
- case PLX_9060:
- case PLX_9080:
- default: /* Old boards, use PLX_9060 */
-
- plx_init(cy_pci_addr0, 0x6c);
- /* For some yet unknown reason, once the PLX9060 reloads
- the EEPROM, the IRQ is lost and, thus, we have to
- re-write it to the PCI config. registers.
- This will remain here until we find a permanent fix. */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, cy_pci_irq);
-
- cy_writew(cy_pci_addr0+0x68,
- cy_readw(cy_pci_addr0+0x68)|0x0900);
- break;
- }
+ cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP *
+ cyy_init_card(cy_pci_addr2, 1));
+ if (cy_pci_nchan == 0) {
+ printk("Cyclom-Y PCI host card with ");
+ printk("no Serial-Modules at 0x%lx.\n",
+ (ulong) cy_pci_phys2);
+ i--;
+ continue;
+ }
+ if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
+ printk("Cyclom-Y/PCI found at 0x%lx ",
+ (ulong) cy_pci_phys2);
+ printk("but no channels are available.\n");
+ printk("Change NR_PORTS in cyclades.c and "
+ "recompile kernel.\n");
+ return i;
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0; j < NR_CARDS; j++) {
+ if (cy_card[j].base_addr == 0)
+ break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclom-Y/PCI found at 0x%lx ",
+ (ulong) cy_pci_phys2);
+ printk("but no more cards can be used.\n");
+ printk("Change NR_CARDS in cyclades.c and "
+ "recompile kernel.\n");
+ return i;
+ }
+
+ /* allocate IRQ */
+ if (request_irq(cy_pci_irq, cyy_interrupt,
+ IRQF_SHARED, "Cyclom-Y", &cy_card[j])) {
+ printk("Cyclom-Y/PCI found at 0x%lx ",
+ (ulong) cy_pci_phys2);
+ printk("but could not allocate IRQ%d.\n",
+ cy_pci_irq);
+ return i;
+ }
- /* print message */
- printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
- j+1,
- (ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Ywin - 1),
- (int)cy_pci_irq);
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan, cy_next_channel);
-
- cy_next_channel += cy_pci_nchan;
- }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
- /* print message */
- printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
- printk("Cyclades-Z/PCI not supported for low addresses\n");
- break;
- }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
+ /* set cy_card */
+ cy_card[j].base_phys = (ulong) cy_pci_phys2;
+ cy_card[j].ctl_phys = (ulong) cy_pci_phys0;
+ cy_card[j].base_addr = cy_pci_addr2;
+ cy_card[j].ctl_addr = cy_pci_addr0;
+ cy_card[j].irq = (int)cy_pci_irq;
+ cy_card[j].bus_index = 1;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = cy_pci_nchan / 4;
+ cy_card[j].pdev = pdev;
+
+ /* enable interrupts in the PCI interface */
+ plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
+ switch (plx_ver) {
+ case PLX_9050:
+
+ cy_writeb(cy_pci_addr0 + 0x4c, 0x43);
+ break;
+
+ case PLX_9060:
+ case PLX_9080:
+ default: /* Old boards, use PLX_9060 */
+
+ plx_init(cy_pci_addr0, 0x6c);
+ /* For some yet unknown reason, once the PLX9060 reloads
+ the EEPROM, the IRQ is lost and, thus, we have to
+ re-write it to the PCI config. registers.
+ This will remain here until we find a permanent
+ fix. */
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
+ cy_pci_irq);
+
+ cy_writew(cy_pci_addr0 + 0x68,
+ cy_readw(cy_pci_addr0 +
+ 0x68) | 0x0900);
+ break;
+ }
+
+ /* print message */
+ printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
+ j + 1, (ulong)cy_pci_phys2,
+ (ulong) (cy_pci_phys2 + CyPCI_Ywin - 1),
+ (int)cy_pci_irq);
+ printk("%d channels starting from port %d.\n",
+ cy_pci_nchan, cy_next_channel);
+
+ cy_next_channel += cy_pci_nchan;
+ } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
+ /* print message */
+ printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+ pdev->bus->number, pdev->devfn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclades-Z/PCI: found winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
+ printk("Cyclades-Z/PCI not supported for low "
+ "addresses\n");
+ break;
+ } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
+ printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+ pdev->bus->number, pdev->devfn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclades-Z/PCI: found winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (ulong) cy_pci_phys2, (ulong) cy_pci_phys0);
#endif
- cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Zctl);
-
- /* Disable interrupts on the PLX before resetting it */
- cy_writew(cy_pci_addr0+0x68,
- cy_readw(cy_pci_addr0+0x68) & ~0x0900);
-
- plx_init(cy_pci_addr0, 0x6c);
- /* For some yet unknown reason, once the PLX9060 reloads
- the EEPROM, the IRQ is lost and, thus, we have to
- re-write it to the PCI config. registers.
- This will remain here until we find a permanent fix. */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, cy_pci_irq);
-
- mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_pci_addr0)->mail_box_0);
-
- if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
- printk(" Warning: PCI I/O bit incorrectly set. "
- "Ignoring it...\n");
- pdev->resource[2].flags &= ~IORESOURCE_IO;
- }
+ cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Zctl);
+
+ /* Disable interrupts on the PLX before resetting it */
+ cy_writew(cy_pci_addr0 + 0x68,
+ cy_readw(cy_pci_addr0 + 0x68) & ~0x0900);
+
+ plx_init(cy_pci_addr0, 0x6c);
+ /* For some yet unknown reason, once the PLX9060 reloads
+ the EEPROM, the IRQ is lost and, thus, we have to
+ re-write it to the PCI config. registers.
+ This will remain here until we find a permanent
+ fix. */
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
+ cy_pci_irq);
+
+ mailbox =
+ (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
+ cy_pci_addr0)->mail_box_0);
+
+ if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
+ printk(" Warning: PCI I/O bit incorrectly "
+ "set. Ignoring it...\n");
+ pdev->resource[2].flags &= ~IORESOURCE_IO;
+ }
- /* Although we don't use this I/O region, we should
- request it from the kernel anyway, to avoid problems
- with other drivers accessing it. */
- if (pci_request_regions(pdev, "Cyclades-Z") != 0) {
- printk(KERN_ERR "cyclades: failed to reserve PCI resources\n");
- continue;
- }
-
- if (mailbox == ZE_V1) {
- cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ze_win);
- if (ZeIndex == NR_CARDS) {
- printk("Cyclades-Ze/PCI found at 0x%lx ",
- (ulong)cy_pci_phys2);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
- } else {
- Ze_phys0[ZeIndex] = cy_pci_phys0;
- Ze_phys2[ZeIndex] = cy_pci_phys2;
- Ze_addr0[ZeIndex] = cy_pci_addr0;
- Ze_addr2[ZeIndex] = cy_pci_addr2;
- Ze_irq[ZeIndex] = cy_pci_irq;
- Ze_pdev[ZeIndex] = pdev;
- ZeIndex++;
- }
- i--;
- continue;
- } else {
- cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Zwin);
- }
+ /* Although we don't use this I/O region, we should
+ request it from the kernel anyway, to avoid problems
+ with other drivers accessing it. */
+ if (pci_request_regions(pdev, "Cyclades-Z") != 0) {
+ printk(KERN_ERR "cyclades: failed to reserve "
+ "PCI resources\n");
+ continue;
+ }
+
+ if (mailbox == ZE_V1) {
+ cy_pci_addr2 = ioremap(cy_pci_phys2,
+ CyPCI_Ze_win);
+ if (ZeIndex == NR_CARDS) {
+ printk("Cyclades-Ze/PCI found at "
+ "0x%lx but no more cards can "
+ "be used.\nChange NR_CARDS in "
+ "cyclades.c and recompile "
+ "kernel.\n",
+ (ulong)cy_pci_phys2);
+ } else {
+ Ze_phys0[ZeIndex] = cy_pci_phys0;
+ Ze_phys2[ZeIndex] = cy_pci_phys2;
+ Ze_addr0[ZeIndex] = cy_pci_addr0;
+ Ze_addr2[ZeIndex] = cy_pci_addr2;
+ Ze_irq[ZeIndex] = cy_pci_irq;
+ Ze_pdev[ZeIndex] = pdev;
+ ZeIndex++;
+ }
+ i--;
+ continue;
+ } else {
+ cy_pci_addr2 = ioremap(cy_pci_phys2,CyPCI_Zwin);
+ }
#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
- if (mailbox == ZO_V1) {
- cy_writel(&((struct RUNTIME_9060 *)
- (cy_pci_addr0))->loc_addr_base, WIN_CREG);
- PAUSE
- printk("Cyclades-8Zo/PCI: FPGA id %lx, ver %lx\n",
- (ulong)(0xff & cy_readl(&((struct CUSTOM_REG *)
- (cy_pci_addr2))->fpga_id)),
- (ulong)(0xff & cy_readl(&((struct CUSTOM_REG *)
- (cy_pci_addr2))->fpga_version)));
- cy_writel(&((struct RUNTIME_9060 *)
- (cy_pci_addr0))->loc_addr_base, WIN_RAM);
- } else {
- printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not loaded\n");
- }
+ printk("Cyclades-Z/PCI: relocate winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (ulong) cy_pci_addr2, (ulong) cy_pci_addr0);
+ if (mailbox == ZO_V1) {
+ cy_writel(&((struct RUNTIME_9060 *)
+ (cy_pci_addr0))->loc_addr_base,
+ WIN_CREG);
+ PAUSE;
+ printk("Cyclades-8Zo/PCI: FPGA id %lx, ver "
+ "%lx\n", (ulong) (0xff &
+ cy_readl(&((struct CUSTOM_REG *)
+ (cy_pci_addr2))->fpga_id)),
+ (ulong)(0xff &
+ cy_readl(&((struct CUSTOM_REG *)
+ (cy_pci_addr2))->
+ fpga_version)));
+ cy_writel(&((struct RUNTIME_9060 *)
+ (cy_pci_addr0))->loc_addr_base,
+ WIN_RAM);
+ } else {
+ printk("Cyclades-Z/PCI: New Cyclades-Z board. "
+ "FPGA not loaded\n");
+ }
#endif
- /* The following clears the firmware id word. This ensures
- that the driver will not attempt to talk to the board
- until it has been properly initialized.
- */
- PAUSE
- if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
- cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L);
-
- /* This must be a Cyclades-8Zo/PCI. The extendable
- version will have a different device_id and will
- be allocated its maximum number of ports. */
- cy_pci_nchan = 8;
-
- if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
- printk("Cyclades-8Zo/PCI found at 0x%lx ",
- (ulong)cy_pci_phys2);
- printk("but no channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
- return(i);
- }
-
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclades-8Zo/PCI found at 0x%lx ",
- (ulong)cy_pci_phys2);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
- return(i);
- }
+ /* The following clears the firmware id word. This
+ ensures that the driver will not attempt to talk to
+ the board until it has been properly initialized.
+ */
+ PAUSE;
+ if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
+ cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L);
+
+ /* This must be a Cyclades-8Zo/PCI. The extendable
+ version will have a different device_id and will
+ be allocated its maximum number of ports. */
+ cy_pci_nchan = 8;
+
+ if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
+ printk("Cyclades-8Zo/PCI found at 0x%lx but"
+ "no channels are available.\nChange "
+ "NR_PORTS in cyclades.c and recompile "
+ "kernel.\n", (ulong)cy_pci_phys2);
+ return i;
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0; j < NR_CARDS; j++) {
+ if (cy_card[j].base_addr == 0)
+ break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclades-8Zo/PCI found at 0x%lx but"
+ "no more cards can be used.\nChange "
+ "NR_CARDS in cyclades.c and recompile "
+ "kernel.\n", (ulong)cy_pci_phys2);
+ return i;
+ }
+#ifdef CONFIG_CYZ_INTR
+ /* allocate IRQ only if board has an IRQ */
+ if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
+ if (request_irq(cy_pci_irq, cyz_interrupt,
+ IRQF_SHARED, "Cyclades-Z",
+ &cy_card[j])) {
+ printk("Cyclom-8Zo/PCI found at 0x%lx "
+ "but could not allocate "
+ "IRQ%d.\n", (ulong)cy_pci_phys2,
+ cy_pci_irq);
+ return i;
+ }
+ }
+#endif /* CONFIG_CYZ_INTR */
+
+ /* set cy_card */
+ cy_card[j].base_phys = cy_pci_phys2;
+ cy_card[j].ctl_phys = cy_pci_phys0;
+ cy_card[j].base_addr = cy_pci_addr2;
+ cy_card[j].ctl_addr = cy_pci_addr0;
+ cy_card[j].irq = (int)cy_pci_irq;
+ cy_card[j].bus_index = 1;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = -1;
+ cy_card[j].pdev = pdev;
+
+ /* print message */
#ifdef CONFIG_CYZ_INTR
- /* allocate IRQ only if board has an IRQ */
- if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
- if(request_irq(cy_pci_irq, cyz_interrupt,
- IRQF_SHARED, "Cyclades-Z", &cy_card[j]))
- {
- printk("Cyclom-8Zo/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but could not allocate IRQ%d.\n",
- cy_pci_irq);
- return(i);
- }
+ /* don't report IRQ if board is no IRQ */
+ if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
+ printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, "
+ "IRQ%d, ", j + 1, (ulong)cy_pci_phys2,
+ (ulong) (cy_pci_phys2 + CyPCI_Zwin - 1),
+ (int)cy_pci_irq);
+ else
+#endif /* CONFIG_CYZ_INTR */
+ printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ",
+ j + 1, (ulong)cy_pci_phys2,
+ (ulong)(cy_pci_phys2 + CyPCI_Zwin - 1));
+
+ printk("%d channels starting from port %d.\n",
+ cy_pci_nchan, cy_next_channel);
+ cy_next_channel += cy_pci_nchan;
}
-#endif /* CONFIG_CYZ_INTR */
-
-
- /* set cy_card */
- cy_card[j].base_phys = cy_pci_phys2;
- cy_card[j].ctl_phys = cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int) cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = -1;
- cy_card[j].pdev = pdev;
+ }
- /* print message */
-#ifdef CONFIG_CYZ_INTR
- /* don't report IRQ if board is no IRQ */
- if( (cy_pci_irq != 0) && (cy_pci_irq != 255) )
- printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
- j+1,(ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Zwin - 1),
- (int)cy_pci_irq);
- else
-#endif /* CONFIG_CYZ_INTR */
- printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ",
- j+1,(ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Zwin - 1));
-
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan,cy_next_channel);
- cy_next_channel += cy_pci_nchan;
- }
- }
-
- for (; ZeIndex != 0 && i < NR_CARDS; i++) {
- cy_pci_phys0 = Ze_phys0[0];
- cy_pci_phys2 = Ze_phys2[0];
- cy_pci_addr0 = Ze_addr0[0];
- cy_pci_addr2 = Ze_addr2[0];
- cy_pci_irq = Ze_irq[0];
- pdev = Ze_pdev[0];
- for (j = 0 ; j < ZeIndex-1 ; j++) {
- Ze_phys0[j] = Ze_phys0[j+1];
- Ze_phys2[j] = Ze_phys2[j+1];
- Ze_addr0[j] = Ze_addr0[j+1];
- Ze_addr2[j] = Ze_addr2[j+1];
- Ze_irq[j] = Ze_irq[j+1];
- Ze_pdev[j] = Ze_pdev[j+1];
- }
- ZeIndex--;
- mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_pci_addr0)->mail_box_0);
+ for (; ZeIndex != 0 && i < NR_CARDS; i++) {
+ cy_pci_phys0 = Ze_phys0[0];
+ cy_pci_phys2 = Ze_phys2[0];
+ cy_pci_addr0 = Ze_addr0[0];
+ cy_pci_addr2 = Ze_addr2[0];
+ cy_pci_irq = Ze_irq[0];
+ pdev = Ze_pdev[0];
+ for (j = 0; j < ZeIndex - 1; j++) {
+ Ze_phys0[j] = Ze_phys0[j + 1];
+ Ze_phys2[j] = Ze_phys2[j + 1];
+ Ze_addr0[j] = Ze_addr0[j + 1];
+ Ze_addr2[j] = Ze_addr2[j + 1];
+ Ze_irq[j] = Ze_irq[j + 1];
+ Ze_pdev[j] = Ze_pdev[j + 1];
+ }
+ ZeIndex--;
+ mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
+ cy_pci_addr0)->mail_box_0);
#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
- printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not loaded\n");
+ printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
+ (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
+ printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not "
+ "loaded\n");
#endif
- PAUSE
- /* This must be the new Cyclades-Ze/PCI. */
- cy_pci_nchan = ZE_V1_NPORTS;
-
- if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
- printk("Cyclades-Ze/PCI found at 0x%lx ",
- (ulong)cy_pci_phys2);
- printk("but no channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
- return(i);
- }
-
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclades-Ze/PCI found at 0x%lx ",
- (ulong)cy_pci_phys2);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
- return(i);
- }
+ PAUSE;
+ /* This must be the new Cyclades-Ze/PCI. */
+ cy_pci_nchan = ZE_V1_NPORTS;
+
+ if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
+ printk("Cyclades-Ze/PCI found at 0x%lx but no channels "
+ "are available.\nChange NR_PORTS in cyclades.c "
+ "and recompile kernel.\n",
+ (ulong) cy_pci_phys2);
+ return i;
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0; j < NR_CARDS; j++) {
+ if (cy_card[j].base_addr == 0)
+ break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclades-Ze/PCI found at 0x%lx but no more "
+ "cards can be used.\nChange NR_CARDS in "
+ "cyclades.c and recompile kernel.\n",
+ (ulong) cy_pci_phys2);
+ return i;
+ }
#ifdef CONFIG_CYZ_INTR
- /* allocate IRQ only if board has an IRQ */
- if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
- if(request_irq(cy_pci_irq, cyz_interrupt,
- IRQF_SHARED, "Cyclades-Z", &cy_card[j]))
- {
- printk("Cyclom-Ze/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but could not allocate IRQ%d.\n",
- cy_pci_irq);
- return(i);
- }
+ /* allocate IRQ only if board has an IRQ */
+ if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
+ if (request_irq(cy_pci_irq, cyz_interrupt,
+ IRQF_SHARED, "Cyclades-Z",
+ &cy_card[j])) {
+ printk("Cyclom-Ze/PCI found at 0x%lx ",
+ (ulong) cy_pci_phys2);
+ printk("but could not allocate IRQ%d.\n",
+ cy_pci_irq);
+ return i;
+ }
}
-#endif /* CONFIG_CYZ_INTR */
-
- /* set cy_card */
- cy_card[j].base_phys = cy_pci_phys2;
- cy_card[j].ctl_phys = cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int) cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = -1;
+#endif /* CONFIG_CYZ_INTR */
+
+ /* set cy_card */
+ cy_card[j].base_phys = cy_pci_phys2;
+ cy_card[j].ctl_phys = cy_pci_phys0;
+ cy_card[j].base_addr = cy_pci_addr2;
+ cy_card[j].ctl_addr = cy_pci_addr0;
+ cy_card[j].irq = (int)cy_pci_irq;
+ cy_card[j].bus_index = 1;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = -1;
cy_card[j].pdev = pdev;
- /* print message */
+ /* print message */
#ifdef CONFIG_CYZ_INTR
/* don't report IRQ if board is no IRQ */
- if( (cy_pci_irq != 0) && (cy_pci_irq != 255) )
- printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
- j+1,(ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Ze_win - 1),
- (int)cy_pci_irq);
+ if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
+ printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
+ j + 1, (ulong) cy_pci_phys2,
+ (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1),
+ (int)cy_pci_irq);
else
-#endif /* CONFIG_CYZ_INTR */
- printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ",
- j+1,(ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Ze_win - 1));
-
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan,cy_next_channel);
- cy_next_channel += cy_pci_nchan;
- }
+#endif /* CONFIG_CYZ_INTR */
+ printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ",
+ j + 1, (ulong) cy_pci_phys2,
+ (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1));
+
+ printk("%d channels starting from port %d.\n",
+ cy_pci_nchan, cy_next_channel);
+ cy_next_channel += cy_pci_nchan;
+ }
if (ZeIndex != 0) {
- printk("Cyclades-Ze/PCI found at 0x%x ",
- (unsigned int) Ze_phys2[0]);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
+ printk("Cyclades-Ze/PCI found at 0x%x but no more cards can be "
+ "used.\nChange NR_CARDS in cyclades.c and recompile "
+ "kernel.\n", (unsigned int)Ze_phys2[0]);
}
- return(i);
+ return i;
#else
- return(0);
-#endif /* ifdef CONFIG_PCI */
-} /* cy_detect_pci */
-
+ return 0;
+#endif /* ifdef CONFIG_PCI */
+} /* cy_detect_pci */
/*
* This routine prints out the appropriate serial driver version number
* and identifies which options were configured into this driver.
*/
-static inline void
-show_version(void)
+static inline void show_version(void)
{
- char *rcsvers, *rcsdate, *tmp;
- rcsvers = strchr(rcsid, ' '); rcsvers++;
- tmp = strchr(rcsvers, ' '); *tmp++ = '\0';
- rcsdate = strchr(tmp, ' '); rcsdate++;
- tmp = strrchr(rcsdate, ' '); *tmp = '\0';
- printk("Cyclades driver %s %s\n",
- rcsvers, rcsdate);
- printk(" built %s %s\n",
- __DATE__, __TIME__);
-} /* show_version */
-
-static int
+ printk("Cyclades driver " CY_VERSION "\n");
+ printk(" built %s %s\n", __DATE__, __TIME__);
+} /* show_version */
+
+static int
cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
- int *eof, void *data)
+ int *eof, void *data)
{
- struct cyclades_port *info;
- int i;
- int len=0;
- off_t begin=0;
- off_t pos=0;
- int size;
- __u32 cur_jifs = jiffies;
-
- size = sprintf(buf, "Dev TimeOpen BytesOut IdleOut BytesIn IdleIn Overruns Ldisc\n");
-
- pos += size;
- len += size;
-
- /* Output one line for each known port */
- for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) {
- info = &cy_port[i];
-
- if (info->count)
- size = sprintf(buf+len,
- "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6ld\n",
- info->line,
- JIFFIES_DIFF(info->idle_stats.in_use, cur_jifs) / HZ,
- info->idle_stats.xmit_bytes,
- JIFFIES_DIFF(info->idle_stats.xmit_idle, cur_jifs) / HZ,
- info->idle_stats.recv_bytes,
- JIFFIES_DIFF(info->idle_stats.recv_idle, cur_jifs) / HZ,
- info->idle_stats.overruns,
- (long) info->tty->ldisc.num);
- else
- size = sprintf(buf+len,
- "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6ld\n",
- info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
+ struct cyclades_port *info;
+ int i;
+ int len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+ int size;
+ __u32 cur_jifs = jiffies;
+
+ size = sprintf(buf, "Dev TimeOpen BytesOut IdleOut BytesIn "
+ "IdleIn Overruns Ldisc\n");
+
+ pos += size;
len += size;
- pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
+ /* Output one line for each known port */
+ for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) {
+ info = &cy_port[i];
+
+ if (info->count)
+ size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
+ "%8lu %9lu %6ld\n", info->line,
+ (cur_jifs - info->idle_stats.in_use) / HZ,
+ info->idle_stats.xmit_bytes,
+ (cur_jifs - info->idle_stats.xmit_idle) / HZ,
+ info->idle_stats.recv_bytes,
+ (cur_jifs - info->idle_stats.recv_idle) / HZ,
+ info->idle_stats.overruns,
+ (long)info->tty->ldisc.num);
+ else
+ size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
+ "%8lu %9lu %6ld\n",
+ info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto done;
}
- if (pos > offset + length)
- goto done;
- }
- *eof = 1;
+ *eof = 1;
done:
- *start = buf + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- len = length; /* Ending slop */
- if (len < 0)
- len = 0;
- return len;
+ *start = buf + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length; /* Ending slop */
+ if (len < 0)
+ len = 0;
+ return len;
}
/* The serial driver boot-time initialization code!
@@ -5185,290 +5294,288 @@ done:
*/
static const struct tty_operations cy_ops = {
- .open = cy_open,
- .close = cy_close,
- .write = cy_write,
- .put_char = cy_put_char,
- .flush_chars = cy_flush_chars,
- .write_room = cy_write_room,
- .chars_in_buffer = cy_chars_in_buffer,
- .flush_buffer = cy_flush_buffer,
- .ioctl = cy_ioctl,
- .throttle = cy_throttle,
- .unthrottle = cy_unthrottle,
- .set_termios = cy_set_termios,
- .stop = cy_stop,
- .start = cy_start,
- .hangup = cy_hangup,
- .break_ctl = cy_break,
- .wait_until_sent = cy_wait_until_sent,
- .read_proc = cyclades_get_proc_info,
- .tiocmget = cy_tiocmget,
- .tiocmset = cy_tiocmset,
+ .open = cy_open,
+ .close = cy_close,
+ .write = cy_write,
+ .put_char = cy_put_char,
+ .flush_chars = cy_flush_chars,
+ .write_room = cy_write_room,
+ .chars_in_buffer = cy_chars_in_buffer,
+ .flush_buffer = cy_flush_buffer,
+ .ioctl = cy_ioctl,
+ .throttle = cy_throttle,
+ .unthrottle = cy_unthrottle,
+ .set_termios = cy_set_termios,
+ .stop = cy_stop,
+ .start = cy_start,
+ .hangup = cy_hangup,
+ .break_ctl = cy_break,
+ .wait_until_sent = cy_wait_until_sent,
+ .read_proc = cyclades_get_proc_info,
+ .tiocmget = cy_tiocmget,
+ .tiocmset = cy_tiocmset,
};
-static int __init
-cy_init(void)
+static int __init cy_init(void)
{
- struct cyclades_port *info;
- struct cyclades_card *cinfo;
- int number_z_boards = 0;
- int board,port,i,index;
- unsigned long mailbox;
- unsigned short chip_number;
- int nports;
-
- cy_serial_driver = alloc_tty_driver(NR_PORTS);
- if (!cy_serial_driver)
- return -ENOMEM;
- show_version();
-
- /* Initialize the tty_driver structure */
-
- cy_serial_driver->owner = THIS_MODULE;
- cy_serial_driver->driver_name = "cyclades";
- cy_serial_driver->name = "ttyC";
- cy_serial_driver->major = CYCLADES_MAJOR;
- cy_serial_driver->minor_start = 0;
- cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
- cy_serial_driver->init_termios = tty_std_termios;
- cy_serial_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(cy_serial_driver, &cy_ops);
-
- if (tty_register_driver(cy_serial_driver))
- panic("Couldn't register Cyclades serial driver\n");
-
- for (i = 0; i < NR_CARDS; i++) {
- /* base_addr=0 indicates board not found */
- cy_card[i].base_addr = NULL;
- }
-
- /* the code below is responsible to find the boards. Each different
- type of board has its own detection routine. If a board is found,
- the next cy_card structure available is set by the detection
- routine. These functions are responsible for checking the
- availability of cy_card and cy_port data structures and updating
- the cy_next_channel. */
-
- /* look for isa boards */
- cy_isa_nboard = cy_detect_isa();
-
- /* look for pci boards */
- cy_pci_nboard = cy_detect_pci();
-
- cy_nboard = cy_isa_nboard + cy_pci_nboard;
-
- /* invalidate remaining cy_card structures */
- for (i = 0 ; i < NR_CARDS ; i++) {
- if (cy_card[i].base_addr == 0) {
- cy_card[i].first_line = -1;
- cy_card[i].ctl_addr = NULL;
- cy_card[i].irq = 0;
- cy_card[i].bus_index = 0;
- cy_card[i].first_line = 0;
- cy_card[i].num_chips = 0;
- }
- }
- /* invalidate remaining cy_port structures */
- for (i = cy_next_channel ; i < NR_PORTS ; i++) {
- cy_port[i].line = -1;
- cy_port[i].magic = -1;
- }
-
- /* initialize per-port data structures for each valid board found */
- for (board = 0 ; board < cy_nboard ; board++) {
- cinfo = &cy_card[board];
- if (cinfo->num_chips == -1) { /* Cyclades-Z */
- number_z_boards++;
- mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_card[board].ctl_addr)->mail_box_0);
- nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
- cinfo->intr_enabled = 0;
- cinfo->nports = 0; /* Will be correctly set later, after
- Z FW is loaded */
- spin_lock_init(&cinfo->card_lock);
- for (port = cinfo->first_line ;
- port < cinfo->first_line + nports;
- port++)
- {
- info = &cy_port[port];
- info->magic = CYCLADES_MAGIC;
- info->type = PORT_STARTECH;
- info->card = board;
- info->line = port;
- info->chip_rev = 0;
- info->flags = STD_COM_FLAGS;
- info->tty = NULL;
- if (mailbox == ZO_V1)
- info->xmit_fifo_size = CYZ_FIFO_SIZE;
- else
- info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
- info->cor1 = 0;
- info->cor2 = 0;
- info->cor3 = 0;
- info->cor4 = 0;
- info->cor5 = 0;
- info->tbpr = 0;
- info->tco = 0;
- info->rbpr = 0;
- info->rco = 0;
- info->custom_divisor = 0;
- info->close_delay = 5*HZ/10;
- info->closing_wait = CLOSING_WAIT_DELAY;
- info->icount.cts = info->icount.dsr =
- info->icount.rng = info->icount.dcd = 0;
- info->icount.rx = info->icount.tx = 0;
- info->icount.frame = info->icount.parity = 0;
- info->icount.overrun = info->icount.brk = 0;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- info->default_threshold = 0;
- info->default_timeout = 0;
- INIT_WORK(&info->tqueue, do_softint);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- init_waitqueue_head(&info->shutdown_wait);
- init_waitqueue_head(&info->delta_msr_wait);
- /* info->session */
- /* info->pgrp */
- info->read_status_mask = 0;
- /* info->timeout */
- /* Bentson's vars */
- info->jiffies[0] = 0;
- info->jiffies[1] = 0;
- info->jiffies[2] = 0;
- info->rflush_count = 0;
+ struct cyclades_port *info;
+ struct cyclades_card *cinfo;
+ int number_z_boards = 0;
+ int board, port, i, index;
+ unsigned long mailbox;
+ unsigned short chip_number;
+ int nports;
+
+ cy_serial_driver = alloc_tty_driver(NR_PORTS);
+ if (!cy_serial_driver)
+ return -ENOMEM;
+ show_version();
+
+ /* Initialize the tty_driver structure */
+
+ cy_serial_driver->owner = THIS_MODULE;
+ cy_serial_driver->driver_name = "cyclades";
+ cy_serial_driver->name = "ttyC";
+ cy_serial_driver->major = CYCLADES_MAJOR;
+ cy_serial_driver->minor_start = 0;
+ cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
+ cy_serial_driver->init_termios = tty_std_termios;
+ cy_serial_driver->init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(cy_serial_driver, &cy_ops);
+
+ if (tty_register_driver(cy_serial_driver))
+ panic("Couldn't register Cyclades serial driver\n");
+
+ for (i = 0; i < NR_CARDS; i++) {
+ /* base_addr=0 indicates board not found */
+ cy_card[i].base_addr = NULL;
+ }
+
+ /* the code below is responsible to find the boards. Each different
+ type of board has its own detection routine. If a board is found,
+ the next cy_card structure available is set by the detection
+ routine. These functions are responsible for checking the
+ availability of cy_card and cy_port data structures and updating
+ the cy_next_channel. */
+
+ /* look for isa boards */
+ cy_isa_nboard = cy_detect_isa();
+
+ /* look for pci boards */
+ cy_pci_nboard = cy_detect_pci();
+
+ cy_nboard = cy_isa_nboard + cy_pci_nboard;
+
+ /* invalidate remaining cy_card structures */
+ for (i = 0; i < NR_CARDS; i++) {
+ if (cy_card[i].base_addr == 0) {
+ cy_card[i].first_line = -1;
+ cy_card[i].ctl_addr = NULL;
+ cy_card[i].irq = 0;
+ cy_card[i].bus_index = 0;
+ cy_card[i].first_line = 0;
+ cy_card[i].num_chips = 0;
+ }
+ }
+ /* invalidate remaining cy_port structures */
+ for (i = cy_next_channel; i < NR_PORTS; i++) {
+ cy_port[i].line = -1;
+ cy_port[i].magic = -1;
+ }
+
+ /* initialize per-port data structures for each valid board found */
+ for (board = 0; board < cy_nboard; board++) {
+ cinfo = &cy_card[board];
+ if (cinfo->num_chips == -1) { /* Cyclades-Z */
+ number_z_boards++;
+ mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *)
+ cy_card[board].ctl_addr)->
+ mail_box_0);
+ nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
+ cinfo->intr_enabled = 0;
+ cinfo->nports = 0; /* Will be correctly set later, after
+ Z FW is loaded */
+ spin_lock_init(&cinfo->card_lock);
+ for (port = cinfo->first_line;
+ port < cinfo->first_line + nports; port++) {
+ info = &cy_port[port];
+ info->magic = CYCLADES_MAGIC;
+ info->type = PORT_STARTECH;
+ info->card = board;
+ info->line = port;
+ info->chip_rev = 0;
+ info->flags = STD_COM_FLAGS;
+ info->tty = NULL;
+ if (mailbox == ZO_V1)
+ info->xmit_fifo_size = CYZ_FIFO_SIZE;
+ else
+ info->xmit_fifo_size =
+ 4 * CYZ_FIFO_SIZE;
+ info->cor1 = 0;
+ info->cor2 = 0;
+ info->cor3 = 0;
+ info->cor4 = 0;
+ info->cor5 = 0;
+ info->tbpr = 0;
+ info->tco = 0;
+ info->rbpr = 0;
+ info->rco = 0;
+ info->custom_divisor = 0;
+ info->close_delay = 5 * HZ / 10;
+ info->closing_wait = CLOSING_WAIT_DELAY;
+ info->icount.cts = info->icount.dsr =
+ info->icount.rng = info->icount.dcd = 0;
+ info->icount.rx = info->icount.tx = 0;
+ info->icount.frame = info->icount.parity = 0;
+ info->icount.overrun = info->icount.brk = 0;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->default_threshold = 0;
+ info->default_timeout = 0;
+ INIT_WORK(&info->tqueue, do_softint);
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->shutdown_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+ /* info->session */
+ /* info->pgrp */
+ info->read_status_mask = 0;
+ /* info->timeout */
+ /* Bentson's vars */
+ info->jiffies[0] = 0;
+ info->jiffies[1] = 0;
+ info->jiffies[2] = 0;
+ info->rflush_count = 0;
#ifdef CONFIG_CYZ_INTR
- init_timer(&cyz_rx_full_timer[port]);
- cyz_rx_full_timer[port].function = NULL;
+ init_timer(&cyz_rx_full_timer[port]);
+ cyz_rx_full_timer[port].function = NULL;
#endif
- }
- continue;
- }else{ /* Cyclom-Y of some kind*/
- index = cinfo->bus_index;
- spin_lock_init(&cinfo->card_lock);
- cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
- for (port = cinfo->first_line ;
- port < cinfo->first_line + cinfo->nports ;
- port++)
- {
- info = &cy_port[port];
- info->magic = CYCLADES_MAGIC;
- info->type = PORT_CIRRUS;
- info->card = board;
- info->line = port;
- info->flags = STD_COM_FLAGS;
- info->tty = NULL;
- info->xmit_fifo_size = CyMAX_CHAR_FIFO;
- info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
- info->cor2 = CyETC;
- info->cor3 = 0x08; /* _very_ small rcv threshold */
- info->cor4 = 0;
- info->cor5 = 0;
- info->custom_divisor = 0;
- info->close_delay = 5*HZ/10;
- info->closing_wait = CLOSING_WAIT_DELAY;
- info->icount.cts = info->icount.dsr =
- info->icount.rng = info->icount.dcd = 0;
- info->icount.rx = info->icount.tx = 0;
- info->icount.frame = info->icount.parity = 0;
- info->icount.overrun = info->icount.brk = 0;
- chip_number = (port - cinfo->first_line) / 4;
- if ((info->chip_rev =
- cy_readb(cinfo->base_addr +
- (cy_chip_offset[chip_number]<<index) +
- (CyGFRCR<<index))) >= CD1400_REV_J) {
- /* It is a CD1400 rev. J or later */
- info->tbpr = baud_bpr_60[13]; /* Tx BPR */
- info->tco = baud_co_60[13]; /* Tx CO */
- info->rbpr = baud_bpr_60[13]; /* Rx BPR */
- info->rco = baud_co_60[13]; /* Rx CO */
- info->rflow = 0;
- info->rtsdtr_inv = 1;
- } else {
- info->tbpr = baud_bpr_25[13]; /* Tx BPR */
- info->tco = baud_co_25[13]; /* Tx CO */
- info->rbpr = baud_bpr_25[13]; /* Rx BPR */
- info->rco = baud_co_25[13]; /* Rx CO */
- info->rflow = 0;
- info->rtsdtr_inv = 0;
- }
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- info->default_threshold = 0;
- info->default_timeout = 0;
- INIT_WORK(&info->tqueue, do_softint);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- init_waitqueue_head(&info->shutdown_wait);
- init_waitqueue_head(&info->delta_msr_wait);
- /* info->session */
- /* info->pgrp */
- info->read_status_mask =
- CyTIMEOUT| CySPECHAR| CyBREAK
- | CyPARITY| CyFRAME| CyOVERRUN;
- /* info->timeout */
- }
- }
- }
+ }
+ continue;
+ } else { /* Cyclom-Y of some kind */
+ index = cinfo->bus_index;
+ spin_lock_init(&cinfo->card_lock);
+ cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
+ for (port = cinfo->first_line;
+ port < cinfo->first_line + cinfo->nports; port++) {
+ info = &cy_port[port];
+ info->magic = CYCLADES_MAGIC;
+ info->type = PORT_CIRRUS;
+ info->card = board;
+ info->line = port;
+ info->flags = STD_COM_FLAGS;
+ info->tty = NULL;
+ info->xmit_fifo_size = CyMAX_CHAR_FIFO;
+ info->cor1 =
+ CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
+ info->cor2 = CyETC;
+ info->cor3 = 0x08; /* _very_ small rcv threshold */
+ info->cor4 = 0;
+ info->cor5 = 0;
+ info->custom_divisor = 0;
+ info->close_delay = 5 * HZ / 10;
+ info->closing_wait = CLOSING_WAIT_DELAY;
+ info->icount.cts = info->icount.dsr =
+ info->icount.rng = info->icount.dcd = 0;
+ info->icount.rx = info->icount.tx = 0;
+ info->icount.frame = info->icount.parity = 0;
+ info->icount.overrun = info->icount.brk = 0;
+ chip_number = (port - cinfo->first_line) / 4;
+ if ((info->chip_rev =
+ cy_readb(cinfo->base_addr +
+ (cy_chip_offset[chip_number] <<
+ index) + (CyGFRCR << index))) >=
+ CD1400_REV_J) {
+ /* It is a CD1400 rev. J or later */
+ info->tbpr = baud_bpr_60[13]; /* Tx BPR */
+ info->tco = baud_co_60[13]; /* Tx CO */
+ info->rbpr = baud_bpr_60[13]; /* Rx BPR */
+ info->rco = baud_co_60[13]; /* Rx CO */
+ info->rflow = 0;
+ info->rtsdtr_inv = 1;
+ } else {
+ info->tbpr = baud_bpr_25[13]; /* Tx BPR */
+ info->tco = baud_co_25[13]; /* Tx CO */
+ info->rbpr = baud_bpr_25[13]; /* Rx BPR */
+ info->rco = baud_co_25[13]; /* Rx CO */
+ info->rflow = 0;
+ info->rtsdtr_inv = 0;
+ }
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->default_threshold = 0;
+ info->default_timeout = 0;
+ INIT_WORK(&info->tqueue, do_softint);
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->shutdown_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+ /* info->session */
+ /* info->pgrp */
+ info->read_status_mask =
+ CyTIMEOUT | CySPECHAR | CyBREAK
+ | CyPARITY | CyFRAME | CyOVERRUN;
+ /* info->timeout */
+ }
+ }
+ }
#ifndef CONFIG_CYZ_INTR
- if (number_z_boards && !cyz_timeron){
- cyz_timeron++;
- cyz_timerlist.expires = jiffies + 1;
- add_timer(&cyz_timerlist);
+ if (number_z_boards && !cyz_timeron) {
+ cyz_timeron++;
+ cyz_timerlist.expires = jiffies + 1;
+ add_timer(&cyz_timerlist);
#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z polling initialized\n");
+ printk("Cyclades-Z polling initialized\n");
#endif
- }
-#endif /* CONFIG_CYZ_INTR */
+ }
+#endif /* CONFIG_CYZ_INTR */
+
+ return 0;
- return 0;
-
-} /* cy_init */
+} /* cy_init */
-static void __exit
-cy_cleanup_module(void)
+static void __exit cy_cleanup_module(void)
{
- int i, e1;
+ int i, e1;
#ifndef CONFIG_CYZ_INTR
- if (cyz_timeron){
- cyz_timeron = 0;
- del_timer(&cyz_timerlist);
- }
+ if (cyz_timeron){
+ cyz_timeron = 0;
+ del_timer(&cyz_timerlist);
+ }
#endif /* CONFIG_CYZ_INTR */
- if ((e1 = tty_unregister_driver(cy_serial_driver)))
- printk("cyc: failed to unregister Cyclades serial driver(%d)\n",
- e1);
+ if ((e1 = tty_unregister_driver(cy_serial_driver)))
+ printk("cyc: failed to unregister Cyclades serial driver(%d)\n",
+ e1);
- put_tty_driver(cy_serial_driver);
+ put_tty_driver(cy_serial_driver);
- for (i = 0; i < NR_CARDS; i++) {
- if (cy_card[i].base_addr) {
- iounmap(cy_card[i].base_addr);
- if (cy_card[i].ctl_addr)
- iounmap(cy_card[i].ctl_addr);
- if (cy_card[i].irq
+ for (i = 0; i < NR_CARDS; i++) {
+ if (cy_card[i].base_addr) {
+ iounmap(cy_card[i].base_addr);
+ if (cy_card[i].ctl_addr)
+ iounmap(cy_card[i].ctl_addr);
+ if (cy_card[i].irq
#ifndef CONFIG_CYZ_INTR
- && cy_card[i].num_chips != -1 /* not a Z card */
+ && cy_card[i].num_chips != -1 /* not a Z card */
#endif /* CONFIG_CYZ_INTR */
- )
- free_irq(cy_card[i].irq, &cy_card[i]);
+ )
+ free_irq(cy_card[i].irq, &cy_card[i]);
#ifdef CONFIG_PCI
- if (cy_card[i].pdev)
- pci_release_regions(cy_card[i].pdev);
+ if (cy_card[i].pdev)
+ pci_release_regions(cy_card[i].pdev);
#endif
- }
- }
+ }
+ }
} /* cy_cleanup_module */
module_init(cy_init);
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 5642ac43e0f..8db9041e306 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -117,6 +117,14 @@ typedef struct drm_clip_rect {
} drm_clip_rect_t;
/**
+ * Drawable information.
+ */
+typedef struct drm_drawable_info {
+ unsigned int num_rects;
+ drm_clip_rect_t *rects;
+} drm_drawable_info_t;
+
+/**
* Texture region,
*/
typedef struct drm_tex_region {
@@ -348,7 +356,8 @@ typedef struct drm_buf_desc {
_DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */
_DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */
_DRM_SG_BUFFER = 0x04, /**< Scatter/gather memory buffer */
- _DRM_FB_BUFFER = 0x08 /**< Buffer is in frame buffer */
+ _DRM_FB_BUFFER = 0x08, /**< Buffer is in frame buffer */
+ _DRM_PCI_BUFFER_RO = 0x10 /**< Map PCI DMA buffer read-only */
} flags;
unsigned long agp_start; /**<
* Start address of where the AGP buffers are
@@ -444,6 +453,20 @@ typedef struct drm_draw {
} drm_draw_t;
/**
+ * DRM_IOCTL_UPDATE_DRAW ioctl argument type.
+ */
+typedef enum {
+ DRM_DRAWABLE_CLIPRECTS,
+} drm_drawable_info_type_t;
+
+typedef struct drm_update_draw {
+ drm_drawable_t handle;
+ unsigned int type;
+ unsigned int num;
+ unsigned long long data;
+} drm_update_draw_t;
+
+/**
* DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type.
*/
typedef struct drm_auth {
@@ -465,10 +488,14 @@ typedef struct drm_irq_busid {
typedef enum {
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
+ _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
+ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
_DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
} drm_vblank_seq_type_t;
-#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL
+#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
+#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \
+ _DRM_VBLANK_NEXTONMISS)
struct drm_wait_vblank_request {
drm_vblank_seq_type_t type;
@@ -623,6 +650,8 @@ typedef struct drm_set_version {
#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
+#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t)
+
/**
* Device specific ioctls should only be in their respective headers
* The device specific ioctl range is from 0x40 to 0x79.
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 7690a59ace0..85d99e21e18 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -97,6 +97,7 @@
#define DRIVER_IRQ_VBL 0x100
#define DRIVER_DMA_QUEUE 0x200
#define DRIVER_FB_DMA 0x400
+#define DRIVER_IRQ_VBL2 0x800
/***********************************************************************/
/** \name Begin the DRM... */
@@ -430,7 +431,8 @@ typedef struct drm_device_dma {
enum {
_DRM_DMA_USE_AGP = 0x01,
_DRM_DMA_USE_SG = 0x02,
- _DRM_DMA_USE_FB = 0x04
+ _DRM_DMA_USE_FB = 0x04,
+ _DRM_DMA_USE_PCI_RO = 0x08
} flags;
} drm_device_dma_t;
@@ -530,11 +532,13 @@ typedef struct drm_mm_node {
int free;
unsigned long start;
unsigned long size;
+ struct drm_mm *mm;
void *private;
} drm_mm_node_t;
typedef struct drm_mm {
- drm_mm_node_t root_node;
+ struct list_head fl_entry;
+ struct list_head ml_entry;
} drm_mm_t;
/**
@@ -559,9 +563,9 @@ struct drm_driver {
int (*context_dtor) (struct drm_device * dev, int context);
int (*kernel_context_switch) (struct drm_device * dev, int old,
int new);
- void (*kernel_context_switch_unlock) (struct drm_device * dev,
- drm_lock_t *lock);
+ void (*kernel_context_switch_unlock) (struct drm_device * dev);
int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence);
+ int (*vblank_wait2) (struct drm_device * dev, unsigned int *sequence);
int (*dri_library_name) (struct drm_device *dev, char *buf);
/**
@@ -708,9 +712,13 @@ typedef struct drm_device {
wait_queue_head_t vbl_queue; /**< VBLANK wait queue */
atomic_t vbl_received;
+ atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */
spinlock_t vbl_lock;
drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */
+ drm_vbl_sig_t vbl_sigs2; /**< signals to send on secondary VBLANK */
unsigned int vbl_pending;
+ spinlock_t tasklet_lock; /**< For drm_locked_tasklet */
+ void (*locked_tasklet_func)(struct drm_device *dev);
/*@} */
cycles_t ctx_start;
@@ -738,6 +746,15 @@ typedef struct drm_device {
drm_local_map_t *agp_buffer_map;
unsigned int agp_buffer_token;
drm_head_t primary; /**< primary screen head */
+
+ /** \name Drawable information */
+ /*@{ */
+ spinlock_t drw_lock;
+ unsigned int drw_bitfield_length;
+ u32 *drw_bitfield;
+ unsigned int drw_info_length;
+ drm_drawable_info_t **drw_info;
+ /*@} */
} drm_device_t;
static __inline__ int drm_core_check_feature(struct drm_device *dev,
@@ -828,9 +845,6 @@ extern void drm_mem_init(void);
extern int drm_mem_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-extern void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev);
-extern void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev);
extern DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type);
extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
@@ -885,6 +899,10 @@ extern int drm_adddraw(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_rmdraw(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
+extern int drm_update_drawable_info(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev,
+ drm_drawable_t id);
/* Authentication IOCTL support (drm_auth.h) */
extern int drm_getmagic(struct inode *inode, struct file *filp,
@@ -949,6 +967,7 @@ extern int drm_wait_vblank(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_vblank_wait(drm_device_t * dev, unsigned int *vbl_seq);
extern void drm_vbl_send_signals(drm_device_t * dev);
+extern void drm_locked_tasklet(drm_device_t *dev, void(*func)(drm_device_t*));
/* AGP/GART support (drm_agpsupport.h) */
extern drm_agp_head_t *drm_agp_init(drm_device_t * dev);
@@ -1033,33 +1052,18 @@ extern void drm_sysfs_device_remove(struct class_device *class_dev);
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);
+void drm_mm_put_block(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);
+extern int drm_mm_clean(drm_mm_t *mm);
+extern unsigned long drm_mm_tail_space(drm_mm_t *mm);
+extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size);
+extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size);
-/* Inline replacements for DRM_IOREMAP macros */
-static __inline__ void drm_core_ioremap(struct drm_map *map,
- struct drm_device *dev)
-{
- map->handle = drm_ioremap(map->offset, map->size, dev);
-}
-
-#if 0
-static __inline__ void drm_core_ioremap_nocache(struct drm_map *map,
- struct drm_device *dev)
-{
- map->handle = drm_ioremap_nocache(map->offset, map->size, dev);
-}
-#endif /* 0 */
-
-static __inline__ void drm_core_ioremapfree(struct drm_map *map,
- struct drm_device *dev)
-{
- if (map->handle && map->size)
- drm_ioremapfree(map->handle, map->size, dev);
-}
+extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev);
+extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev);
static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev,
unsigned int token)
@@ -1122,9 +1126,5 @@ extern void *drm_calloc(size_t nmemb, size_t size, int area);
extern unsigned long drm_core_get_map_ofs(drm_map_t * map);
extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev);
-#ifndef pci_pretty_name
-#define pci_pretty_name(dev) ""
-#endif
-
#endif /* __KERNEL__ */
#endif
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 6eafff13dab..a6828cc14e5 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -79,14 +79,14 @@ static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
if (!use_hashed_handle) {
int ret;
- hash->key = user_token;
+ hash->key = user_token >> PAGE_SHIFT;
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);
+ 0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT);
}
/**
@@ -178,11 +178,11 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
}
}
if (map->type == _DRM_REGISTERS)
- map->handle = drm_ioremap(map->offset, map->size, dev);
+ map->handle = ioremap(map->offset, map->size);
break;
case _DRM_SHM:
- map->handle = vmalloc_32(map->size);
+ map->handle = vmalloc_user(map->size);
DRM_DEBUG("%lu %d %p\n",
map->size, drm_order(map->size), map->handle);
if (!map->handle) {
@@ -238,7 +238,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
if (!list) {
if (map->type == _DRM_REGISTERS)
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL;
}
@@ -255,14 +255,14 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
ret = drm_map_handle(dev, &list->hash, user_token, 0);
if (ret) {
if (map->type == _DRM_REGISTERS)
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
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;
+ list->user_token = list->hash.key << PAGE_SHIFT;
mutex_unlock(&dev->struct_mutex);
*maplist = list;
@@ -347,7 +347,8 @@ 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_ht_remove_key(&dev->map_hash,
+ r_list->user_token >> PAGE_SHIFT);
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
break;
}
@@ -362,7 +363,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
switch (map->type) {
case _DRM_REGISTERS:
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
/* FALLTHROUGH */
case _DRM_FRAME_BUFFER:
if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
@@ -887,6 +888,9 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
request->count = entry->buf_count;
request->size = size;
+ if (request->flags & _DRM_PCI_BUFFER_RO)
+ dma->flags = _DRM_DMA_USE_PCI_RO;
+
atomic_dec(&dev->buf_alloc);
return 0;
@@ -1471,9 +1475,10 @@ int drm_freebufs(struct inode *inode, struct file *filp,
* \param arg pointer to a drm_buf_map structure.
* \return zero on success or a negative number on failure.
*
- * Maps the AGP or SG buffer region with do_mmap(), and copies information
- * about each buffer into user space. The PCI buffers are already mapped on the
- * addbufs_pci() call.
+ * Maps the AGP, SG or PCI buffer region with do_mmap(), and copies information
+ * about each buffer into user space. For PCI buffers, it calls do_mmap() with
+ * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls
+ * drm_mmap_dma().
*/
int drm_mapbufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
diff --git a/drivers/char/drm/drm_core.h b/drivers/char/drm/drm_core.h
index f4f9db6c7ed..31673903607 100644
--- a/drivers/char/drm/drm_core.h
+++ b/drivers/char/drm/drm_core.h
@@ -24,11 +24,11 @@
#define CORE_NAME "drm"
#define CORE_DESC "DRM shared core routines"
-#define CORE_DATE "20051102"
+#define CORE_DATE "20060810"
#define DRM_IF_MAJOR 1
-#define DRM_IF_MINOR 2
+#define DRM_IF_MINOR 3
#define CORE_MAJOR 1
-#define CORE_MINOR 0
-#define CORE_PATCHLEVEL 1
+#define CORE_MINOR 1
+#define CORE_PATCHLEVEL 0
diff --git a/drivers/char/drm/drm_drawable.c b/drivers/char/drm/drm_drawable.c
index 7857453c4f4..de37d5f7456 100644
--- a/drivers/char/drm/drm_drawable.c
+++ b/drivers/char/drm/drm_drawable.c
@@ -4,6 +4,7 @@
*
* \author Rickard E. (Rik) Faith <faith@valinux.com>
* \author Gareth Hughes <gareth@valinux.com>
+ * \author Michel Dänzer <michel@tungstengraphics.com>
*/
/*
@@ -11,6 +12,7 @@
*
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -35,22 +37,294 @@
#include "drmP.h"
-/** No-op. */
-int drm_adddraw(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+/**
+ * Allocate drawable ID and memory to store information about it.
+ */
+int drm_adddraw(DRM_IOCTL_ARGS)
{
+ DRM_DEVICE;
+ unsigned long irqflags;
+ int i, j;
+ u32 *bitfield = dev->drw_bitfield;
+ unsigned int bitfield_length = dev->drw_bitfield_length;
+ drm_drawable_info_t **info = dev->drw_info;
+ unsigned int info_length = dev->drw_info_length;
drm_draw_t draw;
- draw.handle = 0; /* NOOP */
+ for (i = 0, j = 0; i < bitfield_length; i++) {
+ if (bitfield[i] == ~0)
+ continue;
+
+ for (; j < 8 * sizeof(*bitfield); j++)
+ if (!(bitfield[i] & (1 << j)))
+ goto done;
+ }
+done:
+
+ if (i == bitfield_length) {
+ bitfield_length++;
+
+ bitfield = drm_alloc(bitfield_length * sizeof(*bitfield),
+ DRM_MEM_BUFS);
+
+ if (!bitfield) {
+ DRM_ERROR("Failed to allocate new drawable bitfield\n");
+ return DRM_ERR(ENOMEM);
+ }
+
+ if (8 * sizeof(*bitfield) * bitfield_length > info_length) {
+ info_length += 8 * sizeof(*bitfield);
+
+ info = drm_alloc(info_length * sizeof(*info),
+ DRM_MEM_BUFS);
+
+ if (!info) {
+ DRM_ERROR("Failed to allocate new drawable info"
+ " array\n");
+
+ drm_free(bitfield,
+ bitfield_length * sizeof(*bitfield),
+ DRM_MEM_BUFS);
+ return DRM_ERR(ENOMEM);
+ }
+ }
+
+ bitfield[i] = 0;
+ }
+
+ draw.handle = i * 8 * sizeof(*bitfield) + j + 1;
DRM_DEBUG("%d\n", draw.handle);
- if (copy_to_user((drm_draw_t __user *) arg, &draw, sizeof(draw)))
- return -EFAULT;
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ bitfield[i] |= 1 << j;
+ info[draw.handle - 1] = NULL;
+
+ if (bitfield != dev->drw_bitfield) {
+ memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length *
+ sizeof(*bitfield));
+ drm_free(dev->drw_bitfield, sizeof(*bitfield) *
+ dev->drw_bitfield_length, DRM_MEM_BUFS);
+ dev->drw_bitfield = bitfield;
+ dev->drw_bitfield_length = bitfield_length;
+ }
+
+ if (info != dev->drw_info) {
+ memcpy(info, dev->drw_info, dev->drw_info_length *
+ sizeof(*info));
+ drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length,
+ DRM_MEM_BUFS);
+ dev->drw_info = info;
+ dev->drw_info_length = info_length;
+ }
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw));
+
return 0;
}
-/** No-op. */
-int drm_rmdraw(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+/**
+ * Free drawable ID and memory to store information about it.
+ */
+int drm_rmdraw(DRM_IOCTL_ARGS)
{
- return 0; /* NOOP */
+ DRM_DEVICE;
+ drm_draw_t draw;
+ int id, idx;
+ unsigned int shift;
+ unsigned long irqflags;
+ u32 *bitfield = dev->drw_bitfield;
+ unsigned int bitfield_length = dev->drw_bitfield_length;
+ drm_drawable_info_t **info = dev->drw_info;
+ unsigned int info_length = dev->drw_info_length;
+
+ DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data,
+ sizeof(draw));
+
+ id = draw.handle - 1;
+ idx = id / (8 * sizeof(*bitfield));
+ shift = id % (8 * sizeof(*bitfield));
+
+ if (idx < 0 || idx >= bitfield_length ||
+ !(bitfield[idx] & (1 << shift))) {
+ DRM_DEBUG("No such drawable %d\n", draw.handle);
+ return 0;
+ }
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ bitfield[idx] &= ~(1 << shift);
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ if (info[id]) {
+ drm_free(info[id]->rects, info[id]->num_rects *
+ sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+ drm_free(info[id], sizeof(**info), DRM_MEM_BUFS);
+ }
+
+ /* Can we shrink the arrays? */
+ if (idx == bitfield_length - 1) {
+ while (idx >= 0 && !bitfield[idx])
+ --idx;
+
+ bitfield_length = idx + 1;
+
+ if (idx != id / (8 * sizeof(*bitfield)))
+ bitfield = drm_alloc(bitfield_length *
+ sizeof(*bitfield), DRM_MEM_BUFS);
+
+ if (!bitfield && bitfield_length) {
+ bitfield = dev->drw_bitfield;
+ bitfield_length = dev->drw_bitfield_length;
+ }
+ }
+
+ if (bitfield != dev->drw_bitfield) {
+ info_length = 8 * sizeof(*bitfield) * bitfield_length;
+
+ info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS);
+
+ if (!info && info_length) {
+ info = dev->drw_info;
+ info_length = dev->drw_info_length;
+ }
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ memcpy(bitfield, dev->drw_bitfield, bitfield_length *
+ sizeof(*bitfield));
+ drm_free(dev->drw_bitfield, sizeof(*bitfield) *
+ dev->drw_bitfield_length, DRM_MEM_BUFS);
+ dev->drw_bitfield = bitfield;
+ dev->drw_bitfield_length = bitfield_length;
+
+ if (info != dev->drw_info) {
+ memcpy(info, dev->drw_info, info_length *
+ sizeof(*info));
+ drm_free(dev->drw_info, sizeof(*info) *
+ dev->drw_info_length, DRM_MEM_BUFS);
+ dev->drw_info = info;
+ dev->drw_info_length = info_length;
+ }
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ }
+
+ DRM_DEBUG("%d\n", draw.handle);
+ return 0;
+}
+
+int drm_update_drawable_info(DRM_IOCTL_ARGS) {
+ DRM_DEVICE;
+ drm_update_draw_t update;
+ unsigned int id, idx, shift;
+ u32 *bitfield = dev->drw_bitfield;
+ unsigned long irqflags, bitfield_length = dev->drw_bitfield_length;
+ drm_drawable_info_t *info;
+ drm_clip_rect_t *rects;
+ int err;
+
+ DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data,
+ sizeof(update));
+
+ id = update.handle - 1;
+ idx = id / (8 * sizeof(*bitfield));
+ shift = id % (8 * sizeof(*bitfield));
+
+ if (idx < 0 || idx >= bitfield_length ||
+ !(bitfield[idx] & (1 << shift))) {
+ DRM_ERROR("No such drawable %d\n", update.handle);
+ return DRM_ERR(EINVAL);
+ }
+
+ info = dev->drw_info[id];
+
+ if (!info) {
+ info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS);
+
+ if (!info) {
+ DRM_ERROR("Failed to allocate drawable info memory\n");
+ return DRM_ERR(ENOMEM);
+ }
+ }
+
+ switch (update.type) {
+ case DRM_DRAWABLE_CLIPRECTS:
+ if (update.num != info->num_rects) {
+ rects = drm_alloc(update.num * sizeof(drm_clip_rect_t),
+ DRM_MEM_BUFS);
+ } else
+ rects = info->rects;
+
+ if (update.num && !rects) {
+ DRM_ERROR("Failed to allocate cliprect memory\n");
+ err = DRM_ERR(ENOMEM);
+ goto error;
+ }
+
+ if (update.num && DRM_COPY_FROM_USER(rects,
+ (drm_clip_rect_t __user *)
+ (unsigned long)update.data,
+ update.num *
+ sizeof(*rects))) {
+ DRM_ERROR("Failed to copy cliprects from userspace\n");
+ err = DRM_ERR(EFAULT);
+ goto error;
+ }
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ if (rects != info->rects) {
+ drm_free(info->rects, info->num_rects *
+ sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+ }
+
+ info->rects = rects;
+ info->num_rects = update.num;
+ dev->drw_info[id] = info;
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ DRM_DEBUG("Updated %d cliprects for drawable %d\n",
+ info->num_rects, id);
+ break;
+ default:
+ DRM_ERROR("Invalid update type %d\n", update.type);
+ return DRM_ERR(EINVAL);
+ }
+
+ return 0;
+
+error:
+ if (!dev->drw_info[id])
+ drm_free(info, sizeof(*info), DRM_MEM_BUFS);
+ else if (rects != dev->drw_info[id]->rects)
+ drm_free(rects, update.num *
+ sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+
+ return err;
+}
+
+/**
+ * Caller must hold the drawable spinlock!
+ */
+drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) {
+ u32 *bitfield = dev->drw_bitfield;
+ unsigned int idx, shift;
+
+ id--;
+ idx = id / (8 * sizeof(*bitfield));
+ shift = id % (8 * sizeof(*bitfield));
+
+ if (idx < 0 || idx >= dev->drw_bitfield_length ||
+ !(bitfield[idx] & (1 << shift))) {
+ DRM_DEBUG("No such drawable %d\n", id);
+ return NULL;
+ }
+
+ return dev->drw_info[id];
}
+EXPORT_SYMBOL(drm_get_drawable_info);
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index b366c5b1bd1..a70af0de445 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -116,6 +116,8 @@ static drm_ioctl_desc_t drm_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
+
+ [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
};
#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
@@ -151,6 +153,18 @@ int drm_lastclose(drm_device_t * dev)
if (dev->irq_enabled)
drm_irq_uninstall(dev);
+ /* Free drawable information memory */
+ for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield);
+ i++) {
+ drm_drawable_info_t *info = drm_get_drawable_info(dev, i);
+
+ if (info) {
+ drm_free(info->rects, info->num_rects *
+ sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+ drm_free(info, sizeof(*info), DRM_MEM_BUFS);
+ }
+ }
+
mutex_lock(&dev->struct_mutex);
del_timer(&dev->timer);
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
index d4f87452008..fafeb34f89d 100644
--- a/drivers/char/drm/drm_ioc32.c
+++ b/drivers/char/drm/drm_ioc32.c
@@ -102,7 +102,7 @@ static int compat_drm_version(struct file *file, unsigned int cmd,
&version->desc))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_VERSION, (unsigned long)version);
if (err)
return err;
@@ -143,7 +143,7 @@ static int compat_drm_getunique(struct file *file, unsigned int cmd,
&u->unique))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_UNIQUE, (unsigned long)u);
if (err)
return err;
@@ -172,7 +172,7 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd,
&u->unique))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SET_UNIQUE, (unsigned long)u);
}
@@ -203,7 +203,7 @@ static int compat_drm_getmap(struct file *file, unsigned int cmd,
if (__put_user(idx, &map->offset))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_MAP, (unsigned long)map);
if (err)
return err;
@@ -244,7 +244,7 @@ static int compat_drm_addmap(struct file *file, unsigned int cmd,
|| __put_user(m32.flags, &map->flags))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_ADD_MAP, (unsigned long)map);
if (err)
return err;
@@ -282,7 +282,7 @@ static int compat_drm_rmmap(struct file *file, unsigned int cmd,
if (__put_user((void *)(unsigned long)handle, &map->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RM_MAP, (unsigned long)map);
}
@@ -312,7 +312,7 @@ static int compat_drm_getclient(struct file *file, unsigned int cmd,
if (__put_user(idx, &client->idx))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_CLIENT, (unsigned long)client);
if (err)
return err;
@@ -349,7 +349,7 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd,
if (!access_ok(VERIFY_WRITE, stats, sizeof(*stats)))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_STATS, (unsigned long)stats);
if (err)
return err;
@@ -393,7 +393,7 @@ static int compat_drm_addbufs(struct file *file, unsigned int cmd,
|| __put_user(agp_start, &buf->agp_start))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_ADD_BUFS, (unsigned long)buf);
if (err)
return err;
@@ -425,7 +425,7 @@ static int compat_drm_markbufs(struct file *file, unsigned int cmd,
|| __put_user(b32.high_mark, &buf->high_mark))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MARK_BUFS, (unsigned long)buf);
}
@@ -467,7 +467,7 @@ static int compat_drm_infobufs(struct file *file, unsigned int cmd,
|| __put_user(list, &request->list))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_INFO_BUFS, (unsigned long)request);
if (err)
return err;
@@ -529,7 +529,7 @@ static int compat_drm_mapbufs(struct file *file, unsigned int cmd,
|| __put_user(list, &request->list))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MAP_BUFS, (unsigned long)request);
if (err)
return err;
@@ -576,7 +576,7 @@ static int compat_drm_freebufs(struct file *file, unsigned int cmd,
&request->list))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_FREE_BUFS, (unsigned long)request);
}
@@ -603,7 +603,7 @@ static int compat_drm_setsareactx(struct file *file, unsigned int cmd,
&request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SET_SAREA_CTX, (unsigned long)request);
}
@@ -626,7 +626,7 @@ static int compat_drm_getsareactx(struct file *file, unsigned int cmd,
if (__put_user(ctx_id, &request->ctx_id))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_SAREA_CTX, (unsigned long)request);
if (err)
return err;
@@ -662,7 +662,7 @@ static int compat_drm_resctx(struct file *file, unsigned int cmd,
&res->contexts))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RES_CTX, (unsigned long)res);
if (err)
return err;
@@ -716,7 +716,7 @@ static int compat_drm_dma(struct file *file, unsigned int cmd,
&d->request_sizes))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_DMA, (unsigned long)d);
if (err)
return err;
@@ -749,7 +749,7 @@ static int compat_drm_agp_enable(struct file *file, unsigned int cmd,
if (put_user(m32.mode, &mode->mode))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_ENABLE, (unsigned long)mode);
}
@@ -779,7 +779,7 @@ static int compat_drm_agp_info(struct file *file, unsigned int cmd,
if (!access_ok(VERIFY_WRITE, info, sizeof(*info)))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_INFO, (unsigned long)info);
if (err)
return err;
@@ -825,7 +825,7 @@ static int compat_drm_agp_alloc(struct file *file, unsigned int cmd,
|| __put_user(req32.type, &request->type))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_ALLOC, (unsigned long)request);
if (err)
return err;
@@ -833,7 +833,7 @@ static int compat_drm_agp_alloc(struct file *file, unsigned int cmd,
if (__get_user(req32.handle, &request->handle)
|| __get_user(req32.physical, &request->physical)
|| copy_to_user(argp, &req32, sizeof(req32))) {
- drm_ioctl(file->f_dentry->d_inode, file,
+ drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_FREE, (unsigned long)request);
return -EFAULT;
}
@@ -854,7 +854,7 @@ static int compat_drm_agp_free(struct file *file, unsigned int cmd,
|| __put_user(handle, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_FREE, (unsigned long)request);
}
@@ -879,7 +879,7 @@ static int compat_drm_agp_bind(struct file *file, unsigned int cmd,
|| __put_user(req32.offset, &request->offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_BIND, (unsigned long)request);
}
@@ -896,7 +896,7 @@ static int compat_drm_agp_unbind(struct file *file, unsigned int cmd,
|| __put_user(handle, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_UNBIND, (unsigned long)request);
}
#endif /* __OS_HAS_AGP */
@@ -921,7 +921,7 @@ static int compat_drm_sg_alloc(struct file *file, unsigned int cmd,
|| __put_user(x, &request->size))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SG_ALLOC, (unsigned long)request);
if (err)
return err;
@@ -948,7 +948,7 @@ static int compat_drm_sg_free(struct file *file, unsigned int cmd,
|| __put_user(x << PAGE_SHIFT, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SG_FREE, (unsigned long)request);
}
@@ -988,7 +988,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
|| __put_user(req32.request.signal, &request->request.signal))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_WAIT_VBLANK, (unsigned long)request);
if (err)
return err;
@@ -1060,7 +1060,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 4553a3a1e49..9d00c51fe2c 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -121,6 +121,7 @@ static int drm_irq_install(drm_device_t * dev)
spin_lock_init(&dev->vbl_lock);
INIT_LIST_HEAD(&dev->vbl_sigs.head);
+ INIT_LIST_HEAD(&dev->vbl_sigs2.head);
dev->vbl_pending = 0;
}
@@ -175,6 +176,8 @@ int drm_irq_uninstall(drm_device_t * dev)
free_irq(dev->irq, dev);
+ dev->locked_tasklet_func = NULL;
+
return 0;
}
@@ -247,10 +250,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
drm_wait_vblank_t vblwait;
struct timeval now;
int ret = 0;
- unsigned int flags;
-
- if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL))
- return -EINVAL;
+ unsigned int flags, seq;
if (!dev->irq)
return -EINVAL;
@@ -258,9 +258,26 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
return -EFAULT;
- switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) {
+ if (vblwait.request.type &
+ ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
+ DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
+ vblwait.request.type,
+ (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
+ return -EINVAL;
+ }
+
+ flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+
+ if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
+ DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
+ return -EINVAL;
+
+ seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
+ : &dev->vbl_received);
+
+ switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
case _DRM_VBLANK_RELATIVE:
- vblwait.request.sequence += atomic_read(&dev->vbl_received);
+ vblwait.request.sequence += seq;
vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
case _DRM_VBLANK_ABSOLUTE:
break;
@@ -268,26 +285,30 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
return -EINVAL;
}
- flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+ if ((flags & _DRM_VBLANK_NEXTONMISS) &&
+ (seq - vblwait.request.sequence) <= (1<<23)) {
+ vblwait.request.sequence = seq + 1;
+ }
if (flags & _DRM_VBLANK_SIGNAL) {
unsigned long irqflags;
+ drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
+ ? &dev->vbl_sigs2 : &dev->vbl_sigs;
drm_vbl_sig_t *vbl_sig;
- vblwait.reply.sequence = atomic_read(&dev->vbl_received);
-
spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* Check if this task has already scheduled the same signal
* for the same vblank sequence number; nothing to be done in
* that case
*/
- list_for_each_entry(vbl_sig, &dev->vbl_sigs.head, head) {
+ list_for_each_entry(vbl_sig, &vbl_sigs->head, head) {
if (vbl_sig->sequence == vblwait.request.sequence
&& vbl_sig->info.si_signo == vblwait.request.signal
&& vbl_sig->task == current) {
spin_unlock_irqrestore(&dev->vbl_lock,
irqflags);
+ vblwait.reply.sequence = seq;
goto done;
}
}
@@ -315,11 +336,16 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
spin_lock_irqsave(&dev->vbl_lock, irqflags);
- list_add_tail((struct list_head *)vbl_sig, &dev->vbl_sigs.head);
+ list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head);
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+
+ vblwait.reply.sequence = seq;
} else {
- if (dev->driver->vblank_wait)
+ if (flags & _DRM_VBLANK_SECONDARY) {
+ if (dev->driver->vblank_wait2)
+ ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence);
+ } else if (dev->driver->vblank_wait)
ret =
dev->driver->vblank_wait(dev,
&vblwait.request.sequence);
@@ -347,25 +373,32 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
*/
void drm_vbl_send_signals(drm_device_t * dev)
{
- struct list_head *list, *tmp;
- drm_vbl_sig_t *vbl_sig;
- unsigned int vbl_seq = atomic_read(&dev->vbl_received);
unsigned long flags;
+ int i;
spin_lock_irqsave(&dev->vbl_lock, flags);
- list_for_each_safe(list, tmp, &dev->vbl_sigs.head) {
- vbl_sig = list_entry(list, drm_vbl_sig_t, head);
- if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
- vbl_sig->info.si_code = vbl_seq;
- send_sig_info(vbl_sig->info.si_signo, &vbl_sig->info,
- vbl_sig->task);
+ for (i = 0; i < 2; i++) {
+ struct list_head *list, *tmp;
+ drm_vbl_sig_t *vbl_sig;
+ drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
+ unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
+ &dev->vbl_received);
+
+ list_for_each_safe(list, tmp, &vbl_sigs->head) {
+ vbl_sig = list_entry(list, drm_vbl_sig_t, head);
+ if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
+ vbl_sig->info.si_code = vbl_seq;
+ send_sig_info(vbl_sig->info.si_signo,
+ &vbl_sig->info, vbl_sig->task);
- list_del(list);
+ list_del(list);
- drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER);
+ drm_free(vbl_sig, sizeof(*vbl_sig),
+ DRM_MEM_DRIVER);
- dev->vbl_pending--;
+ dev->vbl_pending--;
+ }
}
}
@@ -373,3 +406,77 @@ void drm_vbl_send_signals(drm_device_t * dev)
}
EXPORT_SYMBOL(drm_vbl_send_signals);
+
+/**
+ * Tasklet wrapper function.
+ *
+ * \param data DRM device in disguise.
+ *
+ * Attempts to grab the HW lock and calls the driver callback on success. On
+ * failure, leave the lock marked as contended so the callback can be called
+ * from drm_unlock().
+ */
+static void drm_locked_tasklet_func(unsigned long data)
+{
+ drm_device_t *dev = (drm_device_t*)data;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+
+ if (!dev->locked_tasklet_func ||
+ !drm_lock_take(&dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+ return;
+ }
+
+ dev->lock.lock_time = jiffies;
+ atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
+
+ dev->locked_tasklet_func(dev);
+
+ drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT);
+
+ dev->locked_tasklet_func = NULL;
+
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+}
+
+/**
+ * Schedule a tasklet to call back a driver hook with the HW lock held.
+ *
+ * \param dev DRM device.
+ * \param func Driver callback.
+ *
+ * This is intended for triggering actions that require the HW lock from an
+ * interrupt handler. The lock will be grabbed ASAP after the interrupt handler
+ * completes. Note that the callback may be called from interrupt or process
+ * context, it must not make any assumptions about this. Also, the HW lock will
+ * be held with the kernel context or any client context.
+ */
+void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*))
+{
+ unsigned long irqflags;
+ static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0);
+
+ if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ) ||
+ test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state))
+ return;
+
+ spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+
+ if (dev->locked_tasklet_func) {
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+ return;
+ }
+
+ dev->locked_tasklet_func = func;
+
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+
+ drm_tasklet.data = (unsigned long)dev;
+
+ tasklet_hi_schedule(&drm_tasklet);
+}
+EXPORT_SYMBOL(drm_locked_tasklet);
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index f9e45303498..e9993ba461a 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -155,6 +155,7 @@ int drm_unlock(struct inode *inode, struct file *filp,
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
drm_lock_t lock;
+ unsigned long irqflags;
if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock)))
return -EFAULT;
@@ -165,13 +166,23 @@ int drm_unlock(struct inode *inode, struct file *filp,
return -EINVAL;
}
+ spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+
+ if (dev->locked_tasklet_func) {
+ dev->locked_tasklet_func(dev);
+
+ dev->locked_tasklet_func = NULL;
+ }
+
+ spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+
atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
/* kernel_context_switch isn't used by any of the x86 drm
* modules but is required by the Sparc driver.
*/
if (dev->driver->kernel_context_switch_unlock)
- dev->driver->kernel_context_switch_unlock(dev, &lock);
+ dev->driver->kernel_context_switch_unlock(dev);
else {
drm_lock_transfer(dev, &dev->lock.hw_lock->lock,
DRM_KERNEL_CONTEXT);
diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c
index 5681cae1d40..92a86708237 100644
--- a/drivers/char/drm/drm_memory.c
+++ b/drivers/char/drm/drm_memory.c
@@ -79,28 +79,6 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
}
#if __OS_HAS_AGP
-/*
- * Find the drm_map that covers the range [offset, offset+size).
- */
-static drm_map_t *drm_lookup_map(unsigned long offset,
- unsigned long size, drm_device_t * dev)
-{
- struct list_head *list;
- drm_map_list_t *r_list;
- drm_map_t *map;
-
- list_for_each(list, &dev->maplist->head) {
- r_list = (drm_map_list_t *) list;
- map = r_list->map;
- if (!map)
- continue;
- if (map->offset <= offset
- && (offset + size) <= (map->offset + map->size))
- return map;
- }
- return NULL;
-}
-
static void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
@@ -169,13 +147,6 @@ int drm_unbind_agp(DRM_AGP_MEM * handle)
}
#else /* __OS_HAS_AGP */
-
-static inline drm_map_t *drm_lookup_map(unsigned long offset,
- unsigned long size, drm_device_t * dev)
-{
- return NULL;
-}
-
static inline void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
@@ -184,57 +155,28 @@ static inline void *agp_remap(unsigned long offset, unsigned long size,
#endif /* agp */
-void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev)
-{
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
- drm_map_t *map = drm_lookup_map(offset, size, dev);
-
- if (map && map->type == _DRM_AGP)
- return agp_remap(offset, size, dev);
- }
- return ioremap(offset, size);
-}
-EXPORT_SYMBOL(drm_ioremap);
+#endif /* debug_memory */
-#if 0
-void *drm_ioremap_nocache(unsigned long offset,
- unsigned long size, drm_device_t * dev)
+void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
{
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
- drm_map_t *map = drm_lookup_map(offset, size, dev);
-
- if (map && map->type == _DRM_AGP)
- return agp_remap(offset, size, dev);
- }
- return ioremap_nocache(offset, size);
+ if (drm_core_has_AGP(dev) &&
+ dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+ map->handle = agp_remap(map->offset, map->size, dev);
+ else
+ map->handle = ioremap(map->offset, map->size);
}
-#endif /* 0 */
+EXPORT_SYMBOL(drm_core_ioremap);
-void drm_ioremapfree(void *pt, unsigned long size,
- drm_device_t * dev)
+void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev)
{
- /*
- * This is a bit ugly. It would be much cleaner if the DRM API would use separate
- * routines for handling mappings in the AGP space. Hopefully this can be done in
- * a future revision of the interface...
- */
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture
- && ((unsigned long)pt >= VMALLOC_START
- && (unsigned long)pt < VMALLOC_END)) {
- unsigned long offset;
- drm_map_t *map;
-
- offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK);
- map = drm_lookup_map(offset, size, dev);
- if (map && map->type == _DRM_AGP) {
- vunmap(pt);
- return;
- }
- }
-
- iounmap(pt);
+ if (!map->handle || !map->size)
+ return;
+
+ if (drm_core_has_AGP(dev) &&
+ dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+ vunmap(map->handle);
+ else
+ iounmap(map->handle);
}
-EXPORT_SYMBOL(drm_ioremapfree);
+EXPORT_SYMBOL(drm_core_ioremapfree);
-#endif /* debug_memory */
diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h
index f1b97aff10c..63e425b5ea8 100644
--- a/drivers/char/drm/drm_memory.h
+++ b/drivers/char/drm/drm_memory.h
@@ -56,26 +56,6 @@
# endif
#endif
-static inline unsigned long drm_follow_page(void *vaddr)
-{
- pgd_t *pgd = pgd_offset_k((unsigned long)vaddr);
- pud_t *pud = pud_offset(pgd, (unsigned long)vaddr);
- pmd_t *pmd = pmd_offset(pud, (unsigned long)vaddr);
- pte_t *ptep = pte_offset_kernel(pmd, (unsigned long)vaddr);
- return pte_pfn(*ptep) << PAGE_SHIFT;
-}
-
#else /* __OS_HAS_AGP */
-static inline unsigned long drm_follow_page(void *vaddr)
-{
- return 0;
-}
-
#endif
-
-void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev);
-
-void drm_ioremapfree(void *pt, unsigned long size,
- drm_device_t * dev);
diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h
index 74581af806e..6463271deea 100644
--- a/drivers/char/drm/drm_memory_debug.h
+++ b/drivers/char/drm/drm_memory_debug.h
@@ -205,76 +205,6 @@ void drm_free (void *pt, size_t size, int area) {
}
}
-void *drm_ioremap (unsigned long offset, unsigned long size,
- drm_device_t * dev) {
- void *pt;
-
- if (!size) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Mapping 0 bytes at 0x%08lx\n", offset);
- return NULL;
- }
-
- if (!(pt = drm_ioremap(offset, size, dev))) {
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
- spin_unlock(&drm_mem_lock);
- return NULL;
- }
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
- spin_unlock(&drm_mem_lock);
- return pt;
-}
-
-#if 0
-void *drm_ioremap_nocache (unsigned long offset, unsigned long size,
- drm_device_t * dev) {
- void *pt;
-
- if (!size) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Mapping 0 bytes at 0x%08lx\n", offset);
- return NULL;
- }
-
- if (!(pt = drm_ioremap_nocache(offset, size, dev))) {
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
- spin_unlock(&drm_mem_lock);
- return NULL;
- }
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
- spin_unlock(&drm_mem_lock);
- return pt;
-}
-#endif /* 0 */
-
-void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) {
- int alloc_count;
- int free_count;
-
- if (!pt)
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Attempt to free NULL pointer\n");
- else
- drm_ioremapfree(pt, size, dev);
-
- spin_lock(&drm_mem_lock);
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
- free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
- alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- spin_unlock(&drm_mem_lock);
- if (free_count > alloc_count) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Excess frees: %d frees, %d allocs\n",
- free_count, alloc_count);
- }
-}
-
#if __OS_HAS_AGP
DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) {
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
index 617526bd5b0..9b46b85027d 100644
--- a/drivers/char/drm/drm_mm.c
+++ b/drivers/char/drm/drm_mm.c
@@ -42,36 +42,131 @@
*/
#include "drmP.h"
+#include <linux/slab.h>
+
+unsigned long drm_mm_tail_space(drm_mm_t *mm)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free)
+ return 0;
+
+ return entry->size;
+}
+
+int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free)
+ return -ENOMEM;
+
+ if (entry->size <= size)
+ return -ENOMEM;
+
+ entry->size -= size;
+ return 0;
+}
+
+
+static int drm_mm_create_tail_node(drm_mm_t *mm,
+ unsigned long start,
+ unsigned long size)
+{
+ drm_mm_node_t *child;
+
+ child = (drm_mm_node_t *)
+ drm_alloc(sizeof(*child), DRM_MEM_MM);
+ if (!child)
+ return -ENOMEM;
+
+ child->free = 1;
+ child->size = size;
+ child->start = start;
+ child->mm = mm;
+
+ list_add_tail(&child->ml_entry, &mm->ml_entry);
+ list_add_tail(&child->fl_entry, &mm->fl_entry);
+
+ return 0;
+}
+
+
+int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free) {
+ return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
+ }
+ entry->size += size;
+ return 0;
+}
+
+static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent,
+ unsigned long size)
+{
+ drm_mm_node_t *child;
+
+ child = (drm_mm_node_t *)
+ drm_alloc(sizeof(*child), DRM_MEM_MM);
+ if (!child)
+ return NULL;
+
+ INIT_LIST_HEAD(&child->fl_entry);
+
+ child->free = 0;
+ child->size = size;
+ child->start = parent->start;
+ child->mm = parent->mm;
+
+ list_add_tail(&child->ml_entry, &parent->ml_entry);
+ INIT_LIST_HEAD(&child->fl_entry);
+
+ parent->size -= size;
+ parent->start += size;
+ return child;
+}
+
+
drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
unsigned long size, unsigned alignment)
{
+ drm_mm_node_t *align_splitoff = NULL;
drm_mm_node_t *child;
+ unsigned tmp = 0;
if (alignment)
- size += alignment - 1;
+ tmp = parent->start % alignment;
+
+ if (tmp) {
+ align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
+ if (!align_splitoff)
+ return NULL;
+ }
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 = drm_mm_split_at_start(parent, size);
+ }
- child->free = 0;
- child->size = size;
- child->start = parent->start;
+ if (align_splitoff)
+ drm_mm_put_block(align_splitoff);
- list_add_tail(&child->ml_entry, &parent->ml_entry);
- parent->size -= size;
- parent->start += size;
- }
return child;
}
@@ -80,12 +175,12 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
* Otherwise add to the free stack.
*/
-void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
+void drm_mm_put_block(drm_mm_node_t * cur)
{
- drm_mm_node_t *list_root = &mm->root_node;
+ drm_mm_t *mm = cur->mm;
struct list_head *cur_head = &cur->ml_entry;
- struct list_head *root_head = &list_root->ml_entry;
+ struct list_head *root_head = &mm->ml_entry;
drm_mm_node_t *prev_node = NULL;
drm_mm_node_t *next_node;
@@ -116,7 +211,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
}
if (!merged) {
cur->free = 1;
- list_add(&cur->fl_entry, &list_root->fl_entry);
+ list_add(&cur->fl_entry, &mm->fl_entry);
} else {
list_del(&cur->ml_entry);
drm_free(cur, sizeof(*cur), DRM_MEM_MM);
@@ -128,20 +223,30 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
unsigned alignment, int best_match)
{
struct list_head *list;
- const struct list_head *free_stack = &mm->root_node.fl_entry;
+ const struct list_head *free_stack = &mm->fl_entry;
drm_mm_node_t *entry;
drm_mm_node_t *best;
unsigned long best_size;
+ unsigned wasted;
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) {
+ wasted = 0;
+
+ if (entry->size < size)
+ continue;
+
+ if (alignment) {
+ register unsigned tmp = entry->start % alignment;
+ if (tmp)
+ wasted += alignment - tmp;
+ }
+
+
+ if (entry->size >= size + wasted) {
if (!best_match)
return entry;
if (size < best_size) {
@@ -154,40 +259,32 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
return best;
}
-int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+int drm_mm_clean(drm_mm_t * mm)
{
- 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);
+ struct list_head *head = &mm->ml_entry;
- child->start = start;
- child->size = size;
- child->free = 1;
+ return (head->next->next == head);
+}
- list_add(&child->fl_entry, &mm->root_node.fl_entry);
- list_add(&child->ml_entry, &mm->root_node.ml_entry);
+int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+{
+ INIT_LIST_HEAD(&mm->ml_entry);
+ INIT_LIST_HEAD(&mm->fl_entry);
- return 0;
+ return drm_mm_create_tail_node(mm, start, size);
}
EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(drm_mm_t * mm)
{
- struct list_head *bnode = mm->root_node.fl_entry.next;
+ struct list_head *bnode = mm->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) {
+ if (entry->ml_entry.next != &mm->ml_entry ||
+ entry->fl_entry.next != &mm->fl_entry) {
DRM_ERROR("Memory manager not clean. Delaying takedown\n");
return;
}
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 09398d5fbd3..ad54b845978 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -226,12 +226,14 @@
{0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x7204, 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}, \
+ {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
{0, 0, 0}
#define i810_PCI_IDS \
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 62d5fe15f04..7fd0da71214 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -500,7 +500,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
for (pt = dev->vmalist; pt; pt = pt->next) {
if (!(vma = pt->vma))
continue;
- DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+ DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
pt->pid,
vma->vm_start,
vma->vm_end,
@@ -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' : '-',
- vma->vm_pgoff << PAGE_SHIFT);
+ vma->vm_pgoff);
#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
index 19c81d2e13d..e15db6d6bea 100644
--- a/drivers/char/drm/drm_sman.c
+++ b/drivers/char/drm/drm_sman.c
@@ -101,10 +101,9 @@ static void *drm_sman_mm_allocate(void *private, unsigned long size,
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);
+ drm_mm_put_block(node);
}
static void drm_sman_mm_destroy(void *private)
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 7b1d4e8659b..120d10256fe 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -60,6 +60,8 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
int retcode;
spin_lock_init(&dev->count_lock);
+ spin_lock_init(&dev->drw_lock);
+ spin_lock_init(&dev->tasklet_lock);
init_timer(&dev->timer);
mutex_init(&dev->struct_mutex);
mutex_init(&dev->ctxlist_mutex);
@@ -209,14 +211,16 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
if (!dev)
return -ENOMEM;
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret)
+ goto err_g1;
if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
- goto err_g1;
+ goto err_g2;
}
if ((ret = drm_get_head(dev, &dev->primary)))
- goto err_g1;
+ goto err_g2;
DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
@@ -224,7 +228,9 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
return 0;
- err_g1:
+err_g2:
+ pci_disable_device(pdev);
+err_g1:
drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
return ret;
}
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
index ba4b8de83cf..cc8e2ebe128 100644
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -45,8 +45,8 @@ struct class *drm_sysfs_create(struct module *owner, char *name)
int err;
class = class_create(owner, name);
- if (!class) {
- err = -ENOMEM;
+ if (IS_ERR(class)) {
+ err = PTR_ERR(class);
goto err_out;
}
@@ -113,8 +113,8 @@ struct class_device *drm_sysfs_device_add(struct class *cs, drm_head_t *head)
MKDEV(DRM_MAJOR, head->minor),
&(head->dev->pdev)->dev,
"card%d", head->minor);
- if (!class_dev) {
- err = -ENOMEM;
+ if (IS_ERR(class_dev)) {
+ err = PTR_ERR(class_dev);
goto err_out;
}
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index ae2691942dd..54a63284895 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -70,7 +70,7 @@ 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;
- if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash))
+ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash))
goto vm_nopage_error;
r_list = drm_hash_entry(hash, drm_map_list_t, hash);
@@ -227,7 +227,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
map->size);
DRM_DEBUG("mtrr_del = %d\n", retcode);
}
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
break;
case _DRM_SHM:
vfree(map->handle);
@@ -463,8 +463,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
lock_kernel();
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, vma->vm_pgoff << PAGE_SHIFT);
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, vma->vm_pgoff);
/* Length must match exact page count */
if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
@@ -473,6 +473,22 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
}
unlock_kernel();
+ if (!capable(CAP_SYS_ADMIN) &&
+ (dma->flags & _DRM_DMA_USE_PCI_RO)) {
+ vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE);
+#if defined(__i386__) || defined(__x86_64__)
+ pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
+#else
+ /* Ye gads this is ugly. With more thought
+ we could move this up higher and use
+ `protection_map' instead. */
+ vma->vm_page_prot =
+ __pgprot(pte_val
+ (pte_wrprotect
+ (__pte(pgprot_val(vma->vm_page_prot)))));
+#endif
+ }
+
vma->vm_ops = &drm_vm_dma_ops;
vma->vm_flags |= VM_RESERVED; /* Don't swap */
@@ -521,8 +537,8 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
unsigned long offset = 0;
drm_hash_item_t *hash;
- DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
- vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, vma->vm_pgoff);
if (!priv->authenticated)
return -EACCES;
@@ -531,7 +547,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
* the AGP mapped at physical address 0
* --BenH.
*/
- if (!(vma->vm_pgoff << PAGE_SHIFT)
+ if (!vma->vm_pgoff
#if __OS_HAS_AGP
&& (!dev->agp
|| dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
@@ -539,7 +555,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
)
return drm_mmap_dma(filp, vma);
- if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
+ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) {
DRM_ERROR("Could not find map\n");
return -EINVAL;
}
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index fa2de70f740..60cb4e45a75 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -219,8 +219,7 @@ static int i810_dma_cleanup(drm_device_t * dev)
(drm_i810_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
- drm_ioremapfree((void *)dev_priv->ring.virtual_start,
- dev_priv->ring.Size, dev);
+ drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -236,9 +235,9 @@ static int i810_dma_cleanup(drm_device_t * dev)
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+
if (buf_priv->kernel_virtual && buf->total)
- drm_ioremapfree(buf_priv->kernel_virtual,
- buf->total, dev);
+ drm_core_ioremapfree(&buf_priv->map, dev);
}
}
return 0;
@@ -311,8 +310,15 @@ static int i810_freelist_init(drm_device_t * dev, drm_i810_private_t * dev_priv)
*buf_priv->in_use = I810_BUF_FREE;
- buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
- buf->total, dev);
+ buf_priv->map.offset = buf->bus_address;
+ buf_priv->map.size = buf->total;
+ buf_priv->map.type = _DRM_AGP;
+ buf_priv->map.flags = 0;
+ buf_priv->map.mtrr = 0;
+
+ drm_core_ioremap(&buf_priv->map, dev);
+ buf_priv->kernel_virtual = buf_priv->map.handle;
+
}
return 0;
}
@@ -363,18 +369,24 @@ static int i810_dma_initialize(drm_device_t * dev,
dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
- init->ring_start,
- init->ring_size, dev);
+ dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+ dev_priv->ring.map.size = init->ring_size;
+ dev_priv->ring.map.type = _DRM_AGP;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
- if (dev_priv->ring.virtual_start == NULL) {
+ drm_core_ioremap(&dev_priv->ring.map, dev);
+
+ if (dev_priv->ring.map.handle == NULL) {
dev->dev_private = (void *)dev_priv;
i810_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return -ENOMEM;
+ return DRM_ERR(ENOMEM);
}
+ dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
dev_priv->w = init->w;
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
index e8cf3ff606f..e6df49f4928 100644
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -61,6 +61,7 @@ typedef struct drm_i810_buf_priv {
int currently_mapped;
void *virtual;
void *kernel_virtual;
+ drm_local_map_t map;
} drm_i810_buf_priv_t;
typedef struct _drm_i810_ring_buffer {
@@ -72,6 +73,7 @@ typedef struct _drm_i810_ring_buffer {
int head;
int tail;
int space;
+ drm_local_map_t map;
} drm_i810_ring_buffer_t;
typedef struct drm_i810_private {
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 4f0e5746ab3..95224455ec0 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -223,8 +223,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
(drm_i830_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
- drm_ioremapfree((void *)dev_priv->ring.virtual_start,
- dev_priv->ring.Size, dev);
+ drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -242,8 +241,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
drm_buf_t *buf = dma->buflist[i];
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
if (buf_priv->kernel_virtual && buf->total)
- drm_ioremapfree(buf_priv->kernel_virtual,
- buf->total, dev);
+ drm_core_ioremapfree(&buf_priv->map, dev);
}
}
return 0;
@@ -320,8 +318,14 @@ static int i830_freelist_init(drm_device_t * dev, drm_i830_private_t * dev_priv)
*buf_priv->in_use = I830_BUF_FREE;
- buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
- buf->total, dev);
+ buf_priv->map.offset = buf->bus_address;
+ buf_priv->map.size = buf->total;
+ buf_priv->map.type = _DRM_AGP;
+ buf_priv->map.flags = 0;
+ buf_priv->map.mtrr = 0;
+
+ drm_core_ioremap(&buf_priv->map, dev);
+ buf_priv->kernel_virtual = buf_priv->map.handle;
}
return 0;
}
@@ -373,18 +377,24 @@ static int i830_dma_initialize(drm_device_t * dev,
dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
- init->ring_start,
- init->ring_size, dev);
+ dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+ dev_priv->ring.map.size = init->ring_size;
+ dev_priv->ring.map.type = _DRM_AGP;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
+
+ drm_core_ioremap(&dev_priv->ring.map, dev);
- if (dev_priv->ring.virtual_start == NULL) {
+ if (dev_priv->ring.map.handle == NULL) {
dev->dev_private = (void *)dev_priv;
i830_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return -ENOMEM;
+ return DRM_ERR(ENOMEM);
}
+ dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
dev_priv->w = init->w;
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index 85bc5be6f91..e91f94afb4b 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -68,6 +68,7 @@ typedef struct drm_i830_buf_priv {
int currently_mapped;
void __user *virtual;
void *kernel_virtual;
+ drm_local_map_t map;
} drm_i830_buf_priv_t;
typedef struct _drm_i830_ring_buffer {
@@ -79,6 +80,7 @@ typedef struct _drm_i830_ring_buffer {
int head;
int tail;
int space;
+ drm_local_map_t map;
} drm_i830_ring_buffer_t;
typedef struct drm_i830_private {
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index fb7913ff528..9354ce3b009 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -162,6 +162,7 @@ static int i915_initialize(drm_device_t * dev,
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+ dev_priv->cpp = init->cpp;
dev_priv->back_offset = init->back_offset;
dev_priv->front_offset = init->front_offset;
dev_priv->current_page = 0;
@@ -782,6 +783,7 @@ drm_ioctl_desc_t i915_ioctls[] = {
[DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
[DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
[DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH },
+ [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH},
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
index 6af83e613f2..96a468886a7 100644
--- a/drivers/char/drm/i915_drm.h
+++ b/drivers/char/drm/i915_drm.h
@@ -104,6 +104,15 @@ typedef struct _drm_i915_sarea {
unsigned int depth_tiled;
unsigned int rotated_tiled;
unsigned int rotated2_tiled;
+
+ int pipeA_x;
+ int pipeA_y;
+ int pipeA_w;
+ int pipeA_h;
+ int pipeB_x;
+ int pipeB_y;
+ int pipeB_w;
+ int pipeB_h;
} drm_i915_sarea_t;
/* Flags for perf_boxes
@@ -132,6 +141,7 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_DESTROY_HEAP 0x0c
#define DRM_I915_SET_VBLANK_PIPE 0x0d
#define DRM_I915_GET_VBLANK_PIPE 0x0e
+#define DRM_I915_VBLANK_SWAP 0x0f
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -148,6 +158,7 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
+#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@@ -243,4 +254,12 @@ typedef struct drm_i915_vblank_pipe {
int pipe;
} drm_i915_vblank_pipe_t;
+/* Schedule buffer swap at given vertical blank:
+ */
+typedef struct drm_i915_vblank_swap {
+ drm_drawable_t drawable;
+ drm_vblank_seq_type_t seqtype;
+ unsigned int sequence;
+} drm_i915_vblank_swap_t;
+
#endif /* _I915_DRM_H_ */
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c
index 8e2e6095c4b..85bcc276f80 100644
--- a/drivers/char/drm/i915_drv.c
+++ b/drivers/char/drm/i915_drv.c
@@ -44,12 +44,14 @@ static struct drm_driver driver = {
*/
.driver_features =
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
+ DRIVER_IRQ_VBL2,
.load = i915_driver_load,
.lastclose = i915_driver_lastclose,
.preclose = i915_driver_preclose,
.device_is_agp = i915_driver_device_is_agp,
.vblank_wait = i915_driver_vblank_wait,
+ .vblank_wait2 = i915_driver_vblank_wait2,
.irq_preinstall = i915_driver_irq_preinstall,
.irq_postinstall = i915_driver_irq_postinstall,
.irq_uninstall = i915_driver_irq_uninstall,
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index fdc2bf19271..93cdcfe6aa8 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -46,9 +46,11 @@
* 1.3: Add vblank support
* 1.4: Fix cmdbuffer path, add heap destroy
* 1.5: Add vblank pipe configuration
+ * 1.6: - New ioctl for scheduling buffer swaps on vertical blank
+ * - Support vertical blank on secondary display pipe
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 5
+#define DRIVER_MINOR 6
#define DRIVER_PATCHLEVEL 0
typedef struct _drm_i915_ring_buffer {
@@ -71,6 +73,13 @@ struct mem_block {
DRMFILE filp; /* 0: free, -1: heap, other: real files */
};
+typedef struct _drm_i915_vbl_swap {
+ struct list_head head;
+ drm_drawable_t drw_id;
+ unsigned int pipe;
+ unsigned int sequence;
+} drm_i915_vbl_swap_t;
+
typedef struct drm_i915_private {
drm_local_map_t *sarea;
drm_local_map_t *mmio_map;
@@ -83,6 +92,7 @@ typedef struct drm_i915_private {
dma_addr_t dma_status_page;
unsigned long counter;
+ unsigned int cpp;
int back_offset;
int front_offset;
int current_page;
@@ -98,6 +108,10 @@ typedef struct drm_i915_private {
struct mem_block *agp_heap;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int vblank_pipe;
+
+ spinlock_t swaps_lock;
+ drm_i915_vbl_swap_t vbl_swaps;
+ unsigned int swaps_pending;
} drm_i915_private_t;
extern drm_ioctl_desc_t i915_ioctls[];
@@ -117,12 +131,14 @@ extern int i915_irq_emit(DRM_IOCTL_ARGS);
extern int i915_irq_wait(DRM_IOCTL_ARGS);
extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
+extern int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence);
extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(drm_device_t * dev);
extern void i915_driver_irq_postinstall(drm_device_t * dev);
extern void i915_driver_irq_uninstall(drm_device_t * dev);
extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
+extern int i915_vblank_swap(DRM_IOCTL_ARGS);
/* i915_mem.c */
extern int i915_mem_alloc(DRM_IOCTL_ARGS);
@@ -256,6 +272,10 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2)
+#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
+#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
+
#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_ioc32.c b/drivers/char/drm/i915_ioc32.c
index 296248cdc76..1fe68a251b7 100644
--- a/drivers/char/drm/i915_ioc32.c
+++ b/drivers/char/drm/i915_ioc32.c
@@ -66,7 +66,7 @@ static int compat_i915_batchbuffer(struct file *file, unsigned int cmd,
&batchbuffer->cliprects))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_BATCHBUFFER,
(unsigned long)batchbuffer);
}
@@ -102,7 +102,7 @@ static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd,
&cmdbuffer->cliprects))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_CMDBUFFER, (unsigned long)cmdbuffer);
}
@@ -125,7 +125,7 @@ static int compat_i915_irq_emit(struct file *file, unsigned int cmd,
&request->irq_seq))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_IRQ_EMIT, (unsigned long)request);
}
typedef struct drm_i915_getparam32 {
@@ -149,7 +149,7 @@ static int compat_i915_getparam(struct file *file, unsigned int cmd,
&request->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_GETPARAM, (unsigned long)request);
}
@@ -178,7 +178,7 @@ static int compat_i915_alloc(struct file *file, unsigned int cmd,
&request->region_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_ALLOC, (unsigned long)request);
}
@@ -215,7 +215,7 @@ long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index 0d4a162aa38..78c1ae28f17 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -37,6 +37,178 @@
#define MAX_NOPID ((u32)~0)
+/**
+ * Emit blits for scheduled buffer swaps.
+ *
+ * This function will be called with the HW lock held.
+ */
+static void i915_vblank_tasklet(drm_device_t *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+ struct list_head *list, *tmp, hits, *hit;
+ int nhits, nrects, slice[2], upper[2], lower[2], i;
+ unsigned counter[2] = { atomic_read(&dev->vbl_received),
+ atomic_read(&dev->vbl_received2) };
+ drm_drawable_info_t *drw;
+ drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ u32 cpp = dev_priv->cpp;
+ u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB)
+ : XY_SRC_COPY_BLT_CMD;
+ u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) |
+ (cpp << 23) | (1 << 24);
+ RING_LOCALS;
+
+ DRM_DEBUG("\n");
+
+ INIT_LIST_HEAD(&hits);
+
+ nhits = nrects = 0;
+
+ spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ /* Find buffer swaps scheduled for this vertical blank */
+ list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
+ drm_i915_vbl_swap_t *vbl_swap =
+ list_entry(list, drm_i915_vbl_swap_t, head);
+
+ if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
+ continue;
+
+ list_del(list);
+ dev_priv->swaps_pending--;
+
+ spin_unlock(&dev_priv->swaps_lock);
+ spin_lock(&dev->drw_lock);
+
+ drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
+
+ if (!drw) {
+ spin_unlock(&dev->drw_lock);
+ drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
+ spin_lock(&dev_priv->swaps_lock);
+ continue;
+ }
+
+ list_for_each(hit, &hits) {
+ drm_i915_vbl_swap_t *swap_cmp =
+ list_entry(hit, drm_i915_vbl_swap_t, head);
+ drm_drawable_info_t *drw_cmp =
+ drm_get_drawable_info(dev, swap_cmp->drw_id);
+
+ if (drw_cmp &&
+ drw_cmp->rects[0].y1 > drw->rects[0].y1) {
+ list_add_tail(list, hit);
+ break;
+ }
+ }
+
+ spin_unlock(&dev->drw_lock);
+
+ /* List of hits was empty, or we reached the end of it */
+ if (hit == &hits)
+ list_add_tail(list, hits.prev);
+
+ nhits++;
+
+ spin_lock(&dev_priv->swaps_lock);
+ }
+
+ if (nhits == 0) {
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+ return;
+ }
+
+ spin_unlock(&dev_priv->swaps_lock);
+
+ i915_kernel_lost_context(dev);
+
+ BEGIN_LP_RING(6);
+
+ OUT_RING(GFX_OP_DRAWRECT_INFO);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(sarea_priv->width | sarea_priv->height << 16);
+ OUT_RING(sarea_priv->width | sarea_priv->height << 16);
+ OUT_RING(0);
+
+ ADVANCE_LP_RING();
+
+ sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
+
+ upper[0] = upper[1] = 0;
+ slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
+ slice[1] = max(sarea_priv->pipeB_h / nhits, 1);
+ lower[0] = sarea_priv->pipeA_y + slice[0];
+ lower[1] = sarea_priv->pipeB_y + slice[0];
+
+ spin_lock(&dev->drw_lock);
+
+ /* Emit blits for buffer swaps, partitioning both outputs into as many
+ * slices as there are buffer swaps scheduled in order to avoid tearing
+ * (based on the assumption that a single buffer swap would always
+ * complete before scanout starts).
+ */
+ for (i = 0; i++ < nhits;
+ upper[0] = lower[0], lower[0] += slice[0],
+ upper[1] = lower[1], lower[1] += slice[1]) {
+ if (i == nhits)
+ lower[0] = lower[1] = sarea_priv->height;
+
+ list_for_each(hit, &hits) {
+ drm_i915_vbl_swap_t *swap_hit =
+ list_entry(hit, drm_i915_vbl_swap_t, head);
+ drm_clip_rect_t *rect;
+ int num_rects, pipe;
+ unsigned short top, bottom;
+
+ drw = drm_get_drawable_info(dev, swap_hit->drw_id);
+
+ if (!drw)
+ continue;
+
+ rect = drw->rects;
+ pipe = swap_hit->pipe;
+ top = upper[pipe];
+ bottom = lower[pipe];
+
+ for (num_rects = drw->num_rects; num_rects--; rect++) {
+ int y1 = max(rect->y1, top);
+ int y2 = min(rect->y2, bottom);
+
+ if (y1 >= y2)
+ continue;
+
+ BEGIN_LP_RING(8);
+
+ OUT_RING(cmd);
+ OUT_RING(pitchropcpp);
+ OUT_RING((y1 << 16) | rect->x1);
+ OUT_RING((y2 << 16) | rect->x2);
+ OUT_RING(sarea_priv->front_offset);
+ OUT_RING((y1 << 16) | rect->x1);
+ OUT_RING(pitchropcpp & 0xffff);
+ OUT_RING(sarea_priv->back_offset);
+
+ ADVANCE_LP_RING();
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ list_for_each_safe(hit, tmp, &hits) {
+ drm_i915_vbl_swap_t *swap_hit =
+ list_entry(hit, drm_i915_vbl_swap_t, head);
+
+ list_del(hit);
+
+ drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER);
+ }
+}
+
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
drm_device_t *dev = (drm_device_t *) arg;
@@ -60,9 +232,26 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
DRM_WAKEUP(&dev_priv->irq_queue);
if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
- atomic_inc(&dev->vbl_received);
+ int vblank_pipe = dev_priv->vblank_pipe;
+
+ if ((vblank_pipe &
+ (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
+ == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
+ if (temp & VSYNC_PIPEA_FLAG)
+ atomic_inc(&dev->vbl_received);
+ if (temp & VSYNC_PIPEB_FLAG)
+ atomic_inc(&dev->vbl_received2);
+ } else if (((temp & VSYNC_PIPEA_FLAG) &&
+ (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
+ ((temp & VSYNC_PIPEB_FLAG) &&
+ (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
+ atomic_inc(&dev->vbl_received);
+
DRM_WAKEUP(&dev->vbl_queue);
drm_vbl_send_signals(dev);
+
+ if (dev_priv->swaps_pending > 0)
+ drm_locked_tasklet(dev, i915_vblank_tasklet);
}
return IRQ_HANDLED;
@@ -120,7 +309,8 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr)
return ret;
}
-int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
+static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence,
+ atomic_t *counter)
{
drm_i915_private_t *dev_priv = dev->dev_private;
unsigned int cur_vblank;
@@ -132,7 +322,7 @@ int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
}
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(&dev->vbl_received))
+ (((cur_vblank = atomic_read(counter))
- *sequence) <= (1<<23)));
*sequence = cur_vblank;
@@ -141,6 +331,16 @@ int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
}
+int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
+{
+ return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
+}
+
+int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence)
+{
+ return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
+}
+
/* Needs the lock as it touches the ring.
*/
int i915_irq_emit(DRM_IOCTL_ARGS)
@@ -189,7 +389,7 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
return i915_wait_irq(dev, irqwait.irq_seq);
}
-static int i915_enable_interrupt (drm_device_t *dev)
+static void i915_enable_interrupt (drm_device_t *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u16 flag;
@@ -199,13 +399,8 @@ static int i915_enable_interrupt (drm_device_t *dev)
flag |= VSYNC_PIPEA_FLAG;
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
flag |= VSYNC_PIPEB_FLAG;
- if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
- DRM_ERROR("%s called with invalid pipe 0x%x\n",
- __FUNCTION__, dev_priv->vblank_pipe);
- return DRM_ERR(EINVAL);
- }
+
I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
- return 0;
}
/* Set the vblank monitor pipe
@@ -224,8 +419,17 @@ int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data,
sizeof(pipe));
+ if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
+ DRM_ERROR("%s called with invalid pipe 0x%x\n",
+ __FUNCTION__, pipe.pipe);
+ return DRM_ERR(EINVAL);
+ }
+
dev_priv->vblank_pipe = pipe.pipe;
- return i915_enable_interrupt (dev);
+
+ i915_enable_interrupt (dev);
+
+ return 0;
}
int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
@@ -251,6 +455,118 @@ int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
return 0;
}
+/**
+ * Schedule buffer swap at given vertical blank.
+ */
+int i915_vblank_swap(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_vblank_swap_t swap;
+ drm_i915_vbl_swap_t *vbl_swap;
+ unsigned int pipe, seqtype, curseq;
+ unsigned long irqflags;
+ struct list_head *list;
+
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __func__);
+ return DRM_ERR(EINVAL);
+ }
+
+ if (dev_priv->sarea_priv->rotation) {
+ DRM_DEBUG("Rotation not supported\n");
+ return DRM_ERR(EINVAL);
+ }
+
+ DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
+ sizeof(swap));
+
+ if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
+ _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
+ DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
+ return DRM_ERR(EINVAL);
+ }
+
+ pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+
+ seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
+
+ if (!(dev_priv->vblank_pipe & (1 << pipe))) {
+ DRM_ERROR("Invalid pipe %d\n", pipe);
+ return DRM_ERR(EINVAL);
+ }
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ if (!drm_get_drawable_info(dev, swap.drawable)) {
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable);
+ return DRM_ERR(EINVAL);
+ }
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
+
+ if (seqtype == _DRM_VBLANK_RELATIVE)
+ swap.sequence += curseq;
+
+ if ((curseq - swap.sequence) <= (1<<23)) {
+ if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) {
+ swap.sequence = curseq + 1;
+ } else {
+ DRM_DEBUG("Missed target sequence\n");
+ return DRM_ERR(EINVAL);
+ }
+ }
+
+ spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ list_for_each(list, &dev_priv->vbl_swaps.head) {
+ vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
+
+ if (vbl_swap->drw_id == swap.drawable &&
+ vbl_swap->pipe == pipe &&
+ vbl_swap->sequence == swap.sequence) {
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+ DRM_DEBUG("Already scheduled\n");
+ return 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+ if (dev_priv->swaps_pending >= 100) {
+ DRM_DEBUG("Too many swaps queued\n");
+ return DRM_ERR(EBUSY);
+ }
+
+ vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER);
+
+ if (!vbl_swap) {
+ DRM_ERROR("Failed to allocate memory to queue swap\n");
+ return DRM_ERR(ENOMEM);
+ }
+
+ DRM_DEBUG("\n");
+
+ vbl_swap->drw_id = swap.drawable;
+ vbl_swap->pipe = pipe;
+ vbl_swap->sequence = swap.sequence;
+
+ spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+ list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head);
+ dev_priv->swaps_pending++;
+
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+ DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap,
+ sizeof(swap));
+
+ return 0;
+}
+
/* drm_dma.h hooks
*/
void i915_driver_irq_preinstall(drm_device_t * dev)
@@ -266,6 +582,12 @@ void i915_driver_irq_postinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED;
+ INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
+ dev_priv->swaps_pending = 0;
+
+ if (!dev_priv->vblank_pipe)
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
i915_enable_interrupt(dev);
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
}
diff --git a/drivers/char/drm/mga_ioc32.c b/drivers/char/drm/mga_ioc32.c
index 54a18eb2fc0..30d00478dde 100644
--- a/drivers/char/drm/mga_ioc32.c
+++ b/drivers/char/drm/mga_ioc32.c
@@ -100,7 +100,7 @@ static int compat_mga_init(struct file *file, unsigned int cmd,
if (err)
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MGA_INIT, (unsigned long)init);
}
@@ -125,7 +125,7 @@ static int compat_mga_getparam(struct file *file, unsigned int cmd,
&getparam->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
}
@@ -166,7 +166,7 @@ static int compat_mga_dma_bootstrap(struct file *file, unsigned int cmd,
|| __put_user(dma_bootstrap32.agp_size, &dma_bootstrap->agp_size))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MGA_DMA_BOOTSTRAP,
(unsigned long)dma_bootstrap);
if (err)
@@ -224,7 +224,7 @@ long mga_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
diff --git a/drivers/char/drm/r128_drm.h b/drivers/char/drm/r128_drm.h
index 5d835b006f5..6e8af313f2b 100644
--- a/drivers/char/drm/r128_drm.h
+++ b/drivers/char/drm/r128_drm.h
@@ -1,7 +1,8 @@
/* r128_drm.h -- Public header for the r128 driver -*- linux-c -*-
* Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com
*/
-/* Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+/*
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All rights reserved.
*
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index 94abffb2cca..f1efb49de8d 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -1,7 +1,8 @@
/* r128_drv.h -- Private header for r128 driver -*- linux-c -*-
* Created: Mon Dec 13 09:51:11 1999 by faith@precisioninsight.com
*/
-/* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+/*
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All rights reserved.
*
diff --git a/drivers/char/drm/r128_ioc32.c b/drivers/char/drm/r128_ioc32.c
index 9dd6d4116e4..d3cb676eee8 100644
--- a/drivers/char/drm/r128_ioc32.c
+++ b/drivers/char/drm/r128_ioc32.c
@@ -95,7 +95,7 @@ static int compat_r128_init(struct file *file, unsigned int cmd,
&init->agp_textures_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_INIT, (unsigned long)init);
}
@@ -129,7 +129,7 @@ static int compat_r128_depth(struct file *file, unsigned int cmd,
&depth->mask))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_DEPTH, (unsigned long)depth);
}
@@ -153,7 +153,7 @@ static int compat_r128_stipple(struct file *file, unsigned int cmd,
&stipple->mask))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
}
@@ -178,7 +178,7 @@ static int compat_r128_getparam(struct file *file, unsigned int cmd,
&getparam->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
}
@@ -214,7 +214,7 @@ long r128_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c
index a080cdd6081..17b11e7d8f3 100644
--- a/drivers/char/drm/r128_state.c
+++ b/drivers/char/drm/r128_state.c
@@ -1,7 +1,8 @@
/* r128_state.c -- State support for r128 -*- linux-c -*-
* Created: Thu Jan 27 02:53:43 2000 by gareth@valinux.com
*/
-/* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+/*
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
index d14477ba367..032a022ec6a 100644
--- a/drivers/char/drm/r300_cmdbuf.c
+++ b/drivers/char/drm/r300_cmdbuf.c
@@ -242,26 +242,6 @@ static __inline__ int r300_check_range(unsigned reg, int count)
return 0;
}
-/*
- * we expect offsets passed to the framebuffer to be either within video
- * memory or within AGP space
- */
-static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
- u32 offset)
-{
- /* we realy want to check against end of video aperture
- but this value is not being kept.
- This code is correct for now (does the same thing as the
- code that sets MC_FB_LOCATION) in radeon_cp.c */
- if (offset >= dev_priv->fb_location &&
- offset < (dev_priv->fb_location + dev_priv->fb_size))
- return 0;
- if (offset >= dev_priv->gart_vm_start &&
- offset < (dev_priv->gart_vm_start + dev_priv->gart_size))
- return 0;
- return 1;
-}
-
static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
dev_priv,
drm_radeon_kcmd_buffer_t
@@ -290,7 +270,7 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
case MARK_SAFE:
break;
case MARK_CHECK_OFFSET:
- if (r300_check_offset(dev_priv, (u32) values[i])) {
+ if (!radeon_check_offset(dev_priv, (u32) values[i])) {
DRM_ERROR
("Offset failed range check (reg=%04x sz=%d)\n",
reg, sz);
@@ -452,7 +432,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
i = 1;
while ((k < narrays) && (i < (count + 1))) {
i++; /* skip attribute field */
- if (r300_check_offset(dev_priv, payload[i])) {
+ if (!radeon_check_offset(dev_priv, payload[i])) {
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
@@ -463,7 +443,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
if (k == narrays)
break;
/* have one more to process, they come in pairs */
- if (r300_check_offset(dev_priv, payload[i])) {
+ if (!radeon_check_offset(dev_priv, payload[i])) {
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
@@ -508,7 +488,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
| RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[2] << 10;
- ret = r300_check_offset(dev_priv, offset);
+ ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
return DRM_ERR(EINVAL);
@@ -518,7 +498,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
(cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[3] << 10;
- ret = r300_check_offset(dev_priv, offset);
+ ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
return DRM_ERR(EINVAL);
@@ -551,7 +531,7 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
return DRM_ERR(EINVAL);
}
- ret = r300_check_offset(dev_priv, cmd[2]);
+ ret = !radeon_check_offset(dev_priv, cmd[2]);
if (ret) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
return DRM_ERR(EINVAL);
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index f45cd7f147a..8b105f1460a 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -303,6 +303,21 @@ extern int radeon_no_wb;
extern drm_ioctl_desc_t radeon_ioctls[];
extern int radeon_max_ioctl;
+/* Check whether the given hardware address is inside the framebuffer or the
+ * GART area.
+ */
+static __inline__ int radeon_check_offset(drm_radeon_private_t *dev_priv,
+ u64 off)
+{
+ 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;
+
+ return ((off >= fb_start && off <= fb_end) ||
+ (off >= gart_start && off <= gart_end));
+}
+
/* radeon_cp.c */
extern int radeon_cp_init(DRM_IOCTL_ARGS);
extern int radeon_cp_start(DRM_IOCTL_ARGS);
diff --git a/drivers/char/drm/radeon_ioc32.c b/drivers/char/drm/radeon_ioc32.c
index 0ccfd3618ff..1f1f9cc055a 100644
--- a/drivers/char/drm/radeon_ioc32.c
+++ b/drivers/char/drm/radeon_ioc32.c
@@ -92,7 +92,7 @@ static int compat_radeon_cp_init(struct file *file, unsigned int cmd,
&init->gart_textures_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_CP_INIT, (unsigned long)init);
}
@@ -125,7 +125,7 @@ static int compat_radeon_cp_clear(struct file *file, unsigned int cmd,
&clr->depth_boxes))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_CLEAR, (unsigned long)clr);
}
@@ -149,7 +149,7 @@ static int compat_radeon_cp_stipple(struct file *file, unsigned int cmd,
&request->mask))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_STIPPLE, (unsigned long)request);
}
@@ -204,7 +204,7 @@ static int compat_radeon_cp_texture(struct file *file, unsigned int cmd,
&image->data))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_TEXTURE, (unsigned long)request);
}
@@ -238,7 +238,7 @@ static int compat_radeon_cp_vertex2(struct file *file, unsigned int cmd,
&request->prim))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_VERTEX2, (unsigned long)request);
}
@@ -268,7 +268,7 @@ static int compat_radeon_cp_cmdbuf(struct file *file, unsigned int cmd,
&request->boxes))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_CMDBUF, (unsigned long)request);
}
@@ -293,7 +293,7 @@ static int compat_radeon_cp_getparam(struct file *file, unsigned int cmd,
&request->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_GETPARAM, (unsigned long)request);
}
@@ -322,7 +322,7 @@ static int compat_radeon_mem_alloc(struct file *file, unsigned int cmd,
&request->region_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_ALLOC, (unsigned long)request);
}
@@ -345,7 +345,7 @@ static int compat_radeon_irq_emit(struct file *file, unsigned int cmd,
&request->irq_seq))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long)request);
}
@@ -386,7 +386,7 @@ long radeon_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
index d60519de887..3ff0baa2fbf 100644
--- a/drivers/char/drm/radeon_irq.c
+++ b/drivers/char/drm/radeon_irq.c
@@ -1,5 +1,5 @@
-/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*-
- *
+/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*- */
+/*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
diff --git a/drivers/char/drm/radeon_mem.c b/drivers/char/drm/radeon_mem.c
index 030a6fad0d8..517cad8b6e3 100644
--- a/drivers/char/drm/radeon_mem.c
+++ b/drivers/char/drm/radeon_mem.c
@@ -1,5 +1,5 @@
-/* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*-
- *
+/* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*- */
+/*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 6e04fdd732a..938eccb78cc 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -43,10 +43,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
u32 *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;
+ u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1;
struct drm_radeon_driver_file_fields *radeon_priv;
/* Hrm ... the story of the offset ... So this function converts
@@ -66,8 +63,7 @@ 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 >= fb_start && off <= fb_end) ||
- (off >= gart_start && off <= gart_end))
+ if (radeon_check_offset(dev_priv, off))
return 0;
/* Ok, that didn't happen... now check if we have a zero based
@@ -81,11 +77,10 @@ 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 > fb_end)
- off = off - fb_end - 1 + gart_start;
+ off = off - fb_end - 1 + dev_priv->gart_vm_start;
/* Now recheck and fail if out of bounds */
- if ((off >= fb_start && off <= fb_end) ||
- (off >= gart_start && off <= gart_end)) {
+ if (radeon_check_offset(dev_priv, off)) {
DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
*offset = off;
return 0;
diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c
index a9a84f88df5..b94fab55680 100644
--- a/drivers/char/drm/savage_bci.c
+++ b/drivers/char/drm/savage_bci.c
@@ -963,8 +963,8 @@ static int savage_bci_event_emit(DRM_IOCTL_ARGS)
event.count = savage_bci_emit_event(dev_priv, event.flags);
event.count |= dev_priv->event_wrap << 16;
- DRM_COPY_TO_USER_IOCTL(&((drm_savage_event_emit_t __user *) data)->
- count, event.count, sizeof(event.count));
+ DRM_COPY_TO_USER_IOCTL((drm_savage_event_emit_t __user *) data,
+ event, sizeof(event));
return 0;
}
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index a691ae74129..c0539c6299c 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -190,6 +190,11 @@ static int via_initialize(drm_device_t * dev,
return DRM_ERR(EFAULT);
}
+ if (dev_priv->chipset == VIA_DX9_0) {
+ DRM_ERROR("AGP DMA is not supported on this chip\n");
+ return DRM_ERR(EINVAL);
+ }
+
dev_priv->ring.map.offset = dev->agp->base + init->offset;
dev_priv->ring.map.size = init->size;
dev_priv->ring.map.type = 0;
@@ -480,6 +485,7 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
+ VIA_READ(VIA_REG_TRANSPACE);
}
}
return paused;
@@ -557,8 +563,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
-
+ DRM_WRITEMEMORYBARRIER();
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
+ VIA_READ(VIA_REG_TRANSPACE);
}
static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 806f9ce5f47..2054d577371 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -218,7 +218,9 @@ via_fire_dmablit(drm_device_t *dev, drm_via_sg_info_t *vsg, int engine)
VIA_WRITE(VIA_PCI_DMA_MR0 + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE);
VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0);
VIA_WRITE(VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start);
+ DRM_WRITEMEMORYBARRIER();
VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS);
+ VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04);
}
/*
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index d21b5b75da0..8b8778d4a42 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -29,10 +29,10 @@
#define DRIVER_NAME "via"
#define DRIVER_DESC "VIA Unichrome / Pro"
-#define DRIVER_DATE "20060529"
+#define DRIVER_DATE "20061227"
#define DRIVER_MAJOR 2
-#define DRIVER_MINOR 10
+#define DRIVER_MINOR 11
#define DRIVER_PATCHLEVEL 0
#include "via_verifier.h"
@@ -79,7 +79,7 @@ typedef struct drm_via_private {
char pci_buf[VIA_PCI_BUF_SIZE];
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
uint32_t num_fire_offsets;
- int pro_group_a;
+ int chipset;
drm_via_irq_t via_irqs[VIA_NUM_IRQS];
unsigned num_irqs;
maskarray_t *irq_masks;
@@ -96,8 +96,9 @@ typedef struct drm_via_private {
} drm_via_private_t;
enum via_family {
- VIA_OTHER = 0,
- VIA_PRO_GROUP_A,
+ VIA_OTHER = 0, /* Baseline */
+ VIA_PRO_GROUP_A, /* Another video engine and DMA commands */
+ VIA_DX9_0 /* Same video as pro_group_a, but 3D is unsupported */
};
/* VIA MMIO register access */
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
index c33d068cde1..1ac5941ad23 100644
--- a/drivers/char/drm/via_irq.c
+++ b/drivers/char/drm/via_irq.c
@@ -258,12 +258,16 @@ void via_driver_irq_preinstall(drm_device_t * dev)
dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
- dev_priv->irq_masks = (dev_priv->pro_group_a) ?
- via_pro_group_a_irqs : via_unichrome_irqs;
- dev_priv->num_irqs = (dev_priv->pro_group_a) ?
- via_num_pro_group_a : via_num_unichrome;
- dev_priv->irq_map = (dev_priv->pro_group_a) ?
- via_irqmap_pro_group_a : via_irqmap_unichrome;
+ if (dev_priv->chipset == VIA_PRO_GROUP_A ||
+ dev_priv->chipset == VIA_DX9_0) {
+ dev_priv->irq_masks = via_pro_group_a_irqs;
+ dev_priv->num_irqs = via_num_pro_group_a;
+ dev_priv->irq_map = via_irqmap_pro_group_a;
+ } else {
+ dev_priv->irq_masks = via_unichrome_irqs;
+ dev_priv->num_irqs = via_num_unichrome;
+ dev_priv->irq_map = via_irqmap_unichrome;
+ }
for (i = 0; i < dev_priv->num_irqs; ++i) {
atomic_set(&cur_irq->irq_received, 0);
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
index 782011e0a58..4e3fc072aa3 100644
--- a/drivers/char/drm/via_map.c
+++ b/drivers/char/drm/via_map.c
@@ -106,8 +106,7 @@ int via_driver_load(drm_device_t *dev, unsigned long chipset)
dev->dev_private = (void *)dev_priv;
- if (chipset == VIA_PRO_GROUP_A)
- dev_priv->pro_group_a = 1;
+ dev_priv->chipset = chipset;
ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
if (ret) {
diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c
index 70c897c8876..2e7e0807828 100644
--- a/drivers/char/drm/via_verifier.c
+++ b/drivers/char/drm/via_verifier.c
@@ -306,6 +306,7 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
unsigned long lo = ~0, hi = 0, tmp;
uint32_t *addr, *pitch, *height, tex;
unsigned i;
+ int npot;
if (end > 9)
end = 9;
@@ -316,12 +317,15 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
&(cur_seq->t_addr[tex = cur_seq->texture][start]);
pitch = &(cur_seq->pitch[tex][start]);
height = &(cur_seq->height[tex][start]);
-
+ npot = cur_seq->tex_npot[tex];
for (i = start; i <= end; ++i) {
tmp = *addr++;
if (tmp < lo)
lo = tmp;
- tmp += (*height++ << *pitch++);
+ if (i == 0 && npot)
+ tmp += (*height++ * *pitch++);
+ else
+ tmp += (*height++ << *pitch++);
if (tmp > hi)
hi = tmp;
}
@@ -443,13 +447,21 @@ investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq)
return 0;
case check_texture_addr3:
cur_seq->unfinished = tex_address;
- tmp = ((cmd >> 24) - 0x2B);
- cur_seq->pitch[cur_seq->texture][tmp] =
- (cmd & 0x00F00000) >> 20;
- if (!tmp && (cmd & 0x000FFFFF)) {
- DRM_ERROR
- ("Unimplemented texture level 0 pitch mode.\n");
- return 2;
+ tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit);
+ if (tmp == 0 &&
+ (cmd & HC_HTXnEnPit_MASK)) {
+ cur_seq->pitch[cur_seq->texture][tmp] =
+ (cmd & HC_HTXnLnPit_MASK);
+ cur_seq->tex_npot[cur_seq->texture] = 1;
+ } else {
+ cur_seq->pitch[cur_seq->texture][tmp] =
+ (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT;
+ cur_seq->tex_npot[cur_seq->texture] = 0;
+ if (cmd & 0x000FFFFF) {
+ DRM_ERROR
+ ("Unimplemented texture level 0 pitch mode.\n");
+ return 2;
+ }
}
return 0;
case check_texture_addr4:
@@ -961,7 +973,13 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
uint32_t cmd;
const uint32_t *buf_end = buf + (size >> 2);
verifier_state_t state = state_command;
- int pro_group_a = dev_priv->pro_group_a;
+ int cme_video;
+ int supported_3d;
+
+ cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A ||
+ dev_priv->chipset == VIA_DX9_0);
+
+ supported_3d = dev_priv->chipset != VIA_DX9_0;
hc_state->dev = dev;
hc_state->unfinished = no_sequence;
@@ -986,17 +1004,21 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
state = via_check_vheader6(&buf, buf_end);
break;
case state_command:
- if (HALCYON_HEADER2 == (cmd = *buf))
+ if ((HALCYON_HEADER2 == (cmd = *buf)) &&
+ supported_3d)
state = state_header2;
else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
state = state_header1;
- else if (pro_group_a
+ else if (cme_video
&& (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
state = state_vheader5;
- else if (pro_group_a
+ else if (cme_video
&& (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
state = state_vheader6;
- else {
+ else if ((cmd == HALCYON_HEADER2) && !supported_3d) {
+ DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n");
+ state = state_error;
+ } else {
DRM_ERROR
("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
cmd);
diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h
index 256590fcc22..b77f59df027 100644
--- a/drivers/char/drm/via_verifier.h
+++ b/drivers/char/drm/via_verifier.h
@@ -43,6 +43,7 @@ typedef struct {
uint32_t tex_level_lo[2];
uint32_t tex_level_hi[2];
uint32_t tex_palette_size[2];
+ uint32_t tex_npot[2];
drm_via_sequence_t unfinished;
int agp_texture;
int multitex;
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index 9b1bf60ffbe..06f2dbf1771 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -201,7 +201,7 @@ static int dsp56k_upload(u_char __user *bin, int len)
static ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int dev = iminor(inode) & 0x0f;
switch(dev)
@@ -264,7 +264,7 @@ static ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count,
static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int dev = iminor(inode) & 0x0f;
switch(dev)
@@ -420,7 +420,7 @@ static int dsp56k_ioctl(struct inode *inode, struct file *file,
#if 0
static unsigned int dsp56k_poll(struct file *file, poll_table *wait)
{
- int dev = iminor(file->f_dentry->d_inode) & 0x0f;
+ int dev = iminor(file->f_path.dentry->d_inode) & 0x0f;
switch(dev)
{
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index 5e82c3bad2e..d4005e94fe5 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -122,7 +122,7 @@ static void dtlk_timer_tick(unsigned long data);
static ssize_t dtlk_read(struct file *file, char __user *buf,
size_t count, loff_t * ppos)
{
- unsigned int minor = iminor(file->f_dentry->d_inode);
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
char ch;
int i = 0, retries;
@@ -174,7 +174,7 @@ static ssize_t dtlk_write(struct file *file, const char __user *buf,
}
#endif
- if (iminor(file->f_dentry->d_inode) != DTLK_MINOR)
+ if (iminor(file->f_path.dentry->d_inode) != DTLK_MINOR)
return -EINVAL;
while (1) {
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 7c71eb77980..a0f822c9d74 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -199,7 +199,7 @@ static int pc_ioctl(struct tty_struct *, struct file *,
unsigned int, unsigned long);
static int info_ioctl(struct tty_struct *, struct file *,
unsigned int, unsigned long);
-static void pc_set_termios(struct tty_struct *, struct termios *);
+static void pc_set_termios(struct tty_struct *, struct ktermios *);
static void do_softint(struct work_struct *work);
static void pc_stop(struct tty_struct *);
static void pc_start(struct tty_struct *);
@@ -1236,6 +1236,8 @@ static int __init pc_init(void)
pc_driver->init_termios.c_oflag = 0;
pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
pc_driver->init_termios.c_lflag = 0;
+ pc_driver->init_termios.c_ispeed = 9600;
+ pc_driver->init_termios.c_ospeed = 9600;
pc_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(pc_driver, &pc_ops);
@@ -1250,6 +1252,8 @@ static int __init pc_init(void)
pc_info->init_termios.c_oflag = 0;
pc_info->init_termios.c_lflag = 0;
pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+ pc_info->init_termios.c_ispeed = 9600;
+ pc_info->init_termios.c_ospeed = 9600;
pc_info->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(pc_info, &info_ops);
@@ -1999,7 +2003,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
{ /* Begin epcaparam */
unsigned int cmdHead;
- struct termios *ts;
+ struct ktermios *ts;
struct board_chan __iomem *bc;
unsigned mval, hflow, cflag, iflag;
@@ -2114,7 +2118,7 @@ static void receive_data(struct channel *ch)
{ /* Begin receive_data */
unchar *rptr;
- struct termios *ts = NULL;
+ struct ktermios *ts = NULL;
struct tty_struct *tty;
struct board_chan __iomem *bc;
int dataToRead, wrapgap, bytesAvailable;
@@ -2362,12 +2366,14 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
switch (cmd)
{ /* Begin switch cmd */
+#if 0 /* Handled by calling layer properly */
case TCGETS:
- if (copy_to_user(argp, tty->termios, sizeof(struct termios)))
+ if (copy_to_user(argp, tty->termios, sizeof(struct ktermios)))
return -EFAULT;
return 0;
case TCGETA:
return get_termio(tty, argp);
+#endif
case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
if (retval)
@@ -2536,7 +2542,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
/* --------------------- Begin pc_set_termios ----------------------- */
-static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{ /* Begin pc_set_termios */
struct channel *ch;
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 93b55196251..d1bfbaa2aa0 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -1915,7 +1915,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
return 0;
}
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct esp_struct *info = (struct esp_struct *)tty->driver_data;
unsigned long flags;
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 87127e49c0d..e769811e741 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -718,11 +718,11 @@ static unsigned int gs_baudrates[] = {
void gs_set_termios (struct tty_struct * tty,
- struct termios * old_termios)
+ struct ktermios * old_termios)
{
struct gs_port *port;
int baudrate, tmp, rv;
- struct termios *tiosp;
+ struct ktermios *tiosp;
func_enter();
diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c
new file mode 100644
index 00000000000..6f019f19be7
--- /dev/null
+++ b/drivers/char/hvc_beat.c
@@ -0,0 +1,134 @@
+/*
+ * Beat hypervisor console driver
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * This code is based on drivers/char/hvc_rtas.c:
+ * (C) Copyright IBM Corporation 2001-2005
+ * (C) Copyright Red Hat, Inc. 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.
+ *
+ * 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/init.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <asm/prom.h>
+#include <asm/hvconsole.h>
+#include <asm/firmware.h>
+
+#include "hvc_console.h"
+
+extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *);
+extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t);
+
+struct hvc_struct *hvc_beat_dev = NULL;
+
+/* bug: only one queue is available regardless of vtermno */
+static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt)
+{
+ static unsigned char q[sizeof(unsigned long) * 2]
+ __attribute__((aligned(sizeof(unsigned long))));
+ static int qlen = 0;
+ unsigned long got;
+
+again:
+ if (qlen) {
+ if (qlen > cnt) {
+ memcpy(buf, q, cnt);
+ qlen -= cnt;
+ memmove(q + cnt, q, qlen);
+ return cnt;
+ } else { /* qlen <= cnt */
+ int r;
+
+ memcpy(buf, q, qlen);
+ r = qlen;
+ qlen = 0;
+ return r;
+ }
+ }
+ if (beat_get_term_char(vtermno, &got,
+ ((unsigned long *)q), ((unsigned long *)q) + 1) == 0) {
+ qlen = got;
+ goto again;
+ }
+ return 0;
+}
+
+static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
+{
+ unsigned long kb[2];
+ int rest, nlen;
+
+ for (rest = cnt; rest > 0; rest -= nlen) {
+ nlen = (rest > 16) ? 16 : rest;
+ memcpy(kb, buf, nlen);
+ beat_put_term_char(vtermno, rest, kb[0], kb[1]);
+ rest -= nlen;
+ }
+ return cnt;
+}
+
+static struct hv_ops hvc_beat_get_put_ops = {
+ .get_chars = hvc_beat_get_chars,
+ .put_chars = hvc_beat_put_chars,
+};
+
+static int hvc_beat_useit = 1;
+
+static int hvc_beat_config(char *p)
+{
+ hvc_beat_useit = simple_strtoul(p, NULL, 0);
+ return 0;
+}
+
+static int hvc_beat_console_init(void)
+{
+ if (hvc_beat_useit && machine_is_compatible("Beat")) {
+ hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
+ }
+ return 0;
+}
+
+/* temp */
+static int hvc_beat_init(void)
+{
+ struct hvc_struct *hp;
+
+ if (!firmware_has_feature(FW_FEATURE_BEAT))
+ return -ENODEV;
+
+ hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+ hvc_beat_dev = hp;
+ return 0;
+}
+
+static void __exit hvc_beat_exit(void)
+{
+ if (hvc_beat_dev)
+ hvc_remove(hvc_beat_dev);
+}
+
+module_init(hvc_beat_init);
+module_exit(hvc_beat_exit);
+
+__setup("hvc_beat=", hvc_beat_config);
+
+console_initcall(hvc_beat_console_init);
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index d090622f1de..207f7343ba6 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -192,11 +192,13 @@ MODULE_VERSION(HVCS_DRIVER_VERSION);
* that will cause echoing or we'll go into recursive loop echoing chars back
* and forth with the console drivers.
*/
-static struct termios hvcs_tty_termios = {
+static struct ktermios hvcs_tty_termios = {
.c_iflag = IGNBRK | IGNPAR,
.c_oflag = OPOST,
.c_cflag = B38400 | CS8 | CREAD | HUPCL,
- .c_cc = INIT_C_CC
+ .c_cc = INIT_C_CC,
+ .c_ispeed = 38400,
+ .c_ospeed = 38400
};
/*
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index 82a41d5b4ed..d7806834fc1 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -1161,6 +1161,8 @@ static int __init hvsi_init(void)
hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM;
hvsi_driver->init_termios = tty_std_termios;
hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+ hvsi_driver->init_termios.c_ispeed = 9600;
+ hvsi_driver->init_termios.c_ospeed = 9600;
hvsi_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(hvsi_driver, &hvsi_ops);
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 71e4e0f3fd5..556fd81fa81 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -144,7 +144,7 @@ static void __exit mod_exit(void)
hwrng_unregister(&amd_rng);
}
-subsys_initcall(mod_init);
+module_init(mod_init);
module_exit(mod_exit);
MODULE_AUTHOR("The Linux Kernel team");
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c
index d37ced0d132..8e8658dcd2e 100644
--- a/drivers/char/hw_random/geode-rng.c
+++ b/drivers/char/hw_random/geode-rng.c
@@ -125,7 +125,7 @@ static void __exit mod_exit(void)
iounmap(mem);
}
-subsys_initcall(mod_init);
+module_init(mod_init);
module_exit(mod_exit);
MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs");
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index 8efbc9c0e54..f22e78e3c70 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -143,6 +143,11 @@ static const struct pci_device_id pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, pci_tbl);
+static __initdata int no_fwh_detect;
+module_param(no_fwh_detect, int, 0);
+MODULE_PARM_DESC(no_fwh_detect, "Skip FWH detection:\n"
+ " positive value - skip if FWH space locked read-only\n"
+ " negative value - skip always");
static inline u8 hwstatus_get(void __iomem *mem)
{
@@ -240,6 +245,11 @@ static int __init mod_init(void)
if (!dev)
goto out; /* Device not found. */
+ if (no_fwh_detect < 0) {
+ pci_dev_put(dev);
+ goto fwh_done;
+ }
+
/* Check for Intel 82802 */
if (dev->device < 0x2640) {
fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
@@ -252,6 +262,23 @@ static int __init mod_init(void)
pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val);
pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val);
+ if ((bios_cntl_val &
+ (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
+ == BIOS_CNTL_LOCK_ENABLE_MASK) {
+ static __initdata /*const*/ char warning[] =
+ KERN_WARNING PFX "Firmware space is locked read-only. If you can't or\n"
+ KERN_WARNING PFX "don't want to disable this in firmware setup, and if\n"
+ KERN_WARNING PFX "you are certain that your system has a functional\n"
+ KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n";
+
+ pci_dev_put(dev);
+ if (no_fwh_detect)
+ goto fwh_done;
+ printk(warning);
+ err = -EBUSY;
+ goto out;
+ }
+
mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
if (mem == NULL) {
pci_dev_put(dev);
@@ -280,8 +307,7 @@ static int __init mod_init(void)
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)))
+ if (!(bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK))
pci_write_config_byte(dev,
bios_cntl_off,
bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK);
@@ -315,6 +341,8 @@ static int __init mod_init(void)
goto out;
}
+fwh_done:
+
err = -ENOMEM;
mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
if (!mem)
@@ -350,7 +378,7 @@ static void __exit mod_exit(void)
iounmap(mem);
}
-subsys_initcall(mod_init);
+module_init(mod_init);
module_exit(mod_exit);
MODULE_DESCRIPTION("H/W RNG driver for Intel chipsets");
diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c
index c9caff57db8..bab43ca32ac 100644
--- a/drivers/char/hw_random/ixp4xx-rng.c
+++ b/drivers/char/hw_random/ixp4xx-rng.c
@@ -64,7 +64,7 @@ static void __exit ixp4xx_rng_exit(void)
iounmap(rng_base);
}
-subsys_initcall(ixp4xx_rng_init);
+module_init(ixp4xx_rng_init);
module_exit(ixp4xx_rng_exit);
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index 0e786b617bb..9ebf84d1865 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -176,7 +176,7 @@ static void __exit mod_exit(void)
hwrng_unregister(&via_rng);
}
-subsys_initcall(mod_init);
+module_init(mod_init);
module_exit(mod_exit);
MODULE_DESCRIPTION("H/W RNG driver for VIA chipsets");
diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h
index 5eabe47b0bc..433305062fb 100644
--- a/drivers/char/ip2/i2ellis.h
+++ b/drivers/char/ip2/i2ellis.h
@@ -606,9 +606,9 @@ static int iiDownloadAll(i2eBordStrPtr, loadHdrStrPtr, int, int);
// code and returning.
//
#define COMPLETE(pB,code) \
- if(1){ \
+ do { \
pB->i2eError = code; \
return (code == I2EE_GOOD);\
- }
+ } while (0)
#endif // I2ELLIS_H
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index cda2459c1d6..7c70310a49b 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -177,7 +177,7 @@ static int ip2_write_room(PTTY);
static int ip2_chars_in_buf(PTTY);
static void ip2_flush_buffer(PTTY);
static int ip2_ioctl(PTTY, struct file *, UINT, ULONG);
-static void ip2_set_termios(PTTY, struct termios *);
+static void ip2_set_termios(PTTY, struct ktermios *);
static void ip2_set_line_discipline(PTTY);
static void ip2_throttle(PTTY);
static void ip2_unthrottle(PTTY);
@@ -198,7 +198,7 @@ static void do_status(struct work_struct *);
static void ip2_wait_until_sent(PTTY,int);
-static void set_params (i2ChanStrPtr, struct termios *);
+static void set_params (i2ChanStrPtr, struct ktermios *);
static int get_serial_info(i2ChanStrPtr, struct serial_struct __user *);
static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *);
@@ -2398,7 +2398,7 @@ set_serial_info( i2ChanStrPtr pCh, struct serial_struct __user *new_info )
/* */
/******************************************************************************/
static void
-ip2_set_termios( PTTY tty, struct termios *old_termios )
+ip2_set_termios( PTTY tty, struct ktermios *old_termios )
{
i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
@@ -2440,11 +2440,11 @@ ip2_set_line_discipline ( PTTY tty )
/* change. */
/******************************************************************************/
static void
-set_params( i2ChanStrPtr pCh, struct termios *o_tios )
+set_params( i2ChanStrPtr pCh, struct ktermios *o_tios )
{
tcflag_t cflag, iflag, lflag;
char stop_char, start_char;
- struct termios dummy;
+ struct ktermios dummy;
lflag = pCh->pTTY->termios->c_lflag;
cflag = pCh->pTTY->termios->c_cflag;
@@ -2700,7 +2700,7 @@ static
ssize_t
ip2_ipl_read(struct file *pFile, char __user *pData, size_t count, loff_t *off )
{
- unsigned int minor = iminor(pFile->f_dentry->d_inode);
+ unsigned int minor = iminor(pFile->f_path.dentry->d_inode);
int rc = 0;
#ifdef IP2DEBUG_IPL
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index 6c59baa887a..e736119b649 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -37,8 +37,10 @@
#define BT_DEBUG_ENABLE 1 /* Generic messages */
#define BT_DEBUG_MSG 2 /* Prints all request/response buffers */
#define BT_DEBUG_STATES 4 /* Verbose look at state changes */
+/* BT_DEBUG_OFF must be zero to correspond to the default uninitialized
+ value */
-static int bt_debug = BT_DEBUG_OFF;
+static int bt_debug; /* 0 == BT_DEBUG_OFF */
module_param(bt_debug, int, 0644);
MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states");
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 375d3378eec..ff2d052177c 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -798,7 +798,7 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
if (copy_to_user(precv64, &recv64, sizeof(recv64)))
return -EFAULT;
- rc = ipmi_ioctl(filep->f_dentry->d_inode, filep,
+ rc = ipmi_ioctl(filep->f_path.dentry->d_inode, filep,
((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
? IPMICTL_RECEIVE_MSG
: IPMICTL_RECEIVE_MSG_TRUNC),
@@ -815,7 +815,7 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
return rc;
}
default:
- return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg);
+ return ipmi_ioctl(filep->f_path.dentry->d_inode, filep, cmd, arg);
}
}
#endif
@@ -834,7 +834,7 @@ static const struct file_operations ipmi_fops = {
#define DEVICE_NAME "ipmidev"
-static int ipmi_major = 0;
+static int ipmi_major;
module_param(ipmi_major, int, 0);
MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device. By"
" default, or if you set it to zero, it will choose the next"
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 5703ee28e1c..53582b53da9 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -53,10 +53,10 @@
static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
-static int initialized = 0;
+static int initialized;
#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *proc_ipmi_root = NULL;
+static struct proc_dir_entry *proc_ipmi_root;
#endif /* CONFIG_PROC_FS */
/* Remain in auto-maintenance mode for this amount of time (in ms). */
@@ -2142,8 +2142,7 @@ cleanup_bmc_device(struct kref *ref)
bmc = container_of(ref, struct bmc_device, refcount);
remove_files(bmc);
- if (bmc->dev)
- platform_device_unregister(bmc->dev);
+ platform_device_unregister(bmc->dev);
kfree(bmc);
}
@@ -2341,8 +2340,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
while (ipmi_find_bmc_prod_dev_id(&ipmidriver,
bmc->id.product_id,
- bmc->id.device_id))
- {
+ bmc->id.device_id)) {
if (!warn_printed) {
printk(KERN_WARNING PFX
"This machine has two different BMCs"
@@ -3651,8 +3649,6 @@ static void ipmi_timeout_handler(long timeout_period)
unsigned long flags;
int i;
- INIT_LIST_HEAD(&timeouts);
-
rcu_read_lock();
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
/* See if any waiting messages need to be processed. */
@@ -3673,6 +3669,7 @@ static void ipmi_timeout_handler(long timeout_period)
/* Go through the seq table and find any messages that
have timed out, putting them in the timeouts
list. */
+ INIT_LIST_HEAD(&timeouts);
spin_lock_irqsave(&intf->seq_lock, flags);
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
check_msg_timeout(intf, &(intf->seq_table[i]),
@@ -4043,7 +4040,7 @@ static void send_panic_events(char *str)
}
#endif /* CONFIG_IPMI_PANIC_EVENT */
-static int has_panicked = 0;
+static int has_panicked;
static int panic_event(struct notifier_block *this,
unsigned long event,
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index 597eb4f88b8..9d23136e598 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -58,10 +58,10 @@ static int poweroff_powercycle;
static int ifnum_to_use = -1;
/* Our local state. */
-static int ready = 0;
+static int ready;
static ipmi_user_t ipmi_user;
static int ipmi_ifnum;
-static void (*specific_poweroff_func)(ipmi_user_t user) = NULL;
+static void (*specific_poweroff_func)(ipmi_user_t user);
/* Holds the old poweroff function so we can restore it on removal. */
static void (*old_poweroff_func)(void);
@@ -182,7 +182,7 @@ static int ipmi_request_in_rc_mode(ipmi_user_t user,
#define IPMI_MOTOROLA_MANUFACTURER_ID 0x0000A1
#define IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID 0x0051
-static void (*atca_oem_poweroff_hook)(ipmi_user_t user) = NULL;
+static void (*atca_oem_poweroff_hook)(ipmi_user_t user);
static void pps_poweroff_atca (ipmi_user_t user)
{
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 81a0c89598e..a7b33d2f599 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -845,7 +845,7 @@ static void request_events(void *send_info)
atomic_set(&smi_info->req_events, 1);
}
-static int initialized = 0;
+static int initialized;
static void smi_timeout(unsigned long data)
{
@@ -1018,17 +1018,17 @@ static int num_ports;
static int irqs[SI_MAX_PARMS];
static int num_irqs;
static int regspacings[SI_MAX_PARMS];
-static int num_regspacings = 0;
+static int num_regspacings;
static int regsizes[SI_MAX_PARMS];
-static int num_regsizes = 0;
+static int num_regsizes;
static int regshifts[SI_MAX_PARMS];
-static int num_regshifts = 0;
+static int num_regshifts;
static int slave_addrs[SI_MAX_PARMS];
-static int num_slave_addrs = 0;
+static int num_slave_addrs;
#define IPMI_IO_ADDR_SPACE 0
#define IPMI_MEM_ADDR_SPACE 1
-static char *addr_space_to_str[] = { "I/O", "mem" };
+static char *addr_space_to_str[] = { "i/o", "mem" };
static int hotmod_handler(const char *val, struct kernel_param *kp);
@@ -1397,20 +1397,7 @@ static struct hotmod_vals hotmod_as[] = {
{ "i/o", IPMI_IO_ADDR_SPACE },
{ NULL }
};
-static int ipmi_strcasecmp(const char *s1, const char *s2)
-{
- while (*s1 || *s2) {
- if (!*s1)
- return -1;
- if (!*s2)
- return 1;
- if (*s1 != *s2)
- return *s1 - *s2;
- s1++;
- s2++;
- }
- return 0;
-}
+
static int parse_str(struct hotmod_vals *v, int *val, char *name, char **curr)
{
char *s;
@@ -1424,7 +1411,7 @@ static int parse_str(struct hotmod_vals *v, int *val, char *name, char **curr)
*s = '\0';
s++;
for (i = 0; hotmod_ops[i].name; i++) {
- if (ipmi_strcasecmp(*curr, v[i].name) == 0) {
+ if (strcmp(*curr, v[i].name) == 0) {
*val = v[i].val;
*curr = s;
return 0;
@@ -1435,10 +1422,34 @@ static int parse_str(struct hotmod_vals *v, int *val, char *name, char **curr)
return -EINVAL;
}
+static int check_hotmod_int_op(const char *curr, const char *option,
+ const char *name, int *val)
+{
+ char *n;
+
+ if (strcmp(curr, name) == 0) {
+ if (!option) {
+ printk(KERN_WARNING PFX
+ "No option given for '%s'\n",
+ curr);
+ return -EINVAL;
+ }
+ *val = simple_strtoul(option, &n, 0);
+ if ((*n != '\0') || (*option == '\0')) {
+ printk(KERN_WARNING PFX
+ "Bad option given for '%s'\n",
+ curr);
+ return -EINVAL;
+ }
+ return 1;
+ }
+ return 0;
+}
+
static int hotmod_handler(const char *val, struct kernel_param *kp)
{
char *str = kstrdup(val, GFP_KERNEL);
- int rv = -EINVAL;
+ int rv;
char *next, *curr, *s, *n, *o;
enum hotmod_op op;
enum si_type si_type;
@@ -1450,13 +1461,15 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
int irq;
int ipmb;
int ival;
+ int len;
struct smi_info *info;
if (!str)
return -ENOMEM;
/* Kill any trailing spaces, as we can get a "\n" from echo. */
- ival = strlen(str) - 1;
+ len = strlen(str);
+ ival = len - 1;
while ((ival >= 0) && isspace(str[ival])) {
str[ival] = '\0';
ival--;
@@ -1513,35 +1526,37 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
*o = '\0';
o++;
}
-#define HOTMOD_INT_OPT(name, val) \
- if (ipmi_strcasecmp(curr, name) == 0) { \
- if (!o) { \
- printk(KERN_WARNING PFX \
- "No option given for '%s'\n", \
- curr); \
- goto out; \
- } \
- val = simple_strtoul(o, &n, 0); \
- if ((*n != '\0') || (*o == '\0')) { \
- printk(KERN_WARNING PFX \
- "Bad option given for '%s'\n", \
- curr); \
- goto out; \
- } \
- }
-
- HOTMOD_INT_OPT("rsp", regspacing)
- else HOTMOD_INT_OPT("rsi", regsize)
- else HOTMOD_INT_OPT("rsh", regshift)
- else HOTMOD_INT_OPT("irq", irq)
- else HOTMOD_INT_OPT("ipmb", ipmb)
- else {
- printk(KERN_WARNING PFX
- "Invalid hotmod option '%s'\n",
- curr);
+ rv = check_hotmod_int_op(curr, o, "rsp", &regspacing);
+ if (rv < 0)
goto out;
- }
-#undef HOTMOD_INT_OPT
+ else if (rv)
+ continue;
+ rv = check_hotmod_int_op(curr, o, "rsi", &regsize);
+ if (rv < 0)
+ goto out;
+ else if (rv)
+ continue;
+ rv = check_hotmod_int_op(curr, o, "rsh", &regshift);
+ if (rv < 0)
+ goto out;
+ else if (rv)
+ continue;
+ rv = check_hotmod_int_op(curr, o, "irq", &irq);
+ if (rv < 0)
+ goto out;
+ else if (rv)
+ continue;
+ rv = check_hotmod_int_op(curr, o, "ipmb", &ipmb);
+ if (rv < 0)
+ goto out;
+ else if (rv)
+ continue;
+
+ rv = -EINVAL;
+ printk(KERN_WARNING PFX
+ "Invalid hotmod option '%s'\n",
+ curr);
+ goto out;
}
if (op == HM_ADD) {
@@ -1590,6 +1605,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
mutex_unlock(&smi_infos_lock);
}
}
+ rv = len;
out:
kfree(str);
return rv;
@@ -1610,11 +1626,11 @@ static __devinit void hardcode_find_bmc(void)
info->addr_source = "hardcoded";
- if (!si_type[i] || ipmi_strcasecmp(si_type[i], "kcs") == 0) {
+ if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
info->si_type = SI_KCS;
- } else if (ipmi_strcasecmp(si_type[i], "smic") == 0) {
+ } else if (strcmp(si_type[i], "smic") == 0) {
info->si_type = SI_SMIC;
- } else if (ipmi_strcasecmp(si_type[i], "bt") == 0) {
+ } else if (strcmp(si_type[i], "bt") == 0) {
info->si_type = SI_BT;
} else {
printk(KERN_WARNING
@@ -1668,7 +1684,7 @@ static __devinit void hardcode_find_bmc(void)
/* Once we get an ACPI failure, we don't try any more, because we go
through the tables sequentially. Once we don't find a table, there
are no more. */
-static int acpi_failure = 0;
+static int acpi_failure;
/* For GPE-type interrupts. */
static u32 ipmi_acpi_gpe(void *context)
@@ -1779,7 +1795,6 @@ struct SPMITable {
static __devinit int try_init_acpi(struct SPMITable *spmi)
{
struct smi_info *info;
- char *io_type;
u8 addr_space;
if (spmi->IPMIlegacy != 1) {
@@ -1787,7 +1802,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
return -ENODEV;
}
- if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
addr_space = IPMI_MEM_ADDR_SPACE;
else
addr_space = IPMI_IO_ADDR_SPACE;
@@ -1833,21 +1848,19 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
info->irq_setup = NULL;
}
- if (spmi->addr.register_bit_width) {
+ if (spmi->addr.bit_width) {
/* A (hopefully) properly formed register bit width. */
- info->io.regspacing = spmi->addr.register_bit_width / 8;
+ info->io.regspacing = spmi->addr.bit_width / 8;
} else {
info->io.regspacing = DEFAULT_REGSPACING;
}
info->io.regsize = info->io.regspacing;
- info->io.regshift = spmi->addr.register_bit_offset;
+ info->io.regshift = spmi->addr.bit_offset;
- if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
- io_type = "memory";
+ if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
info->io_setup = mem_setup;
info->io.addr_type = IPMI_IO_ADDR_SPACE;
- } else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
- io_type = "I/O";
+ } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
info->io_setup = port_setup;
info->io.addr_type = IPMI_MEM_ADDR_SPACE;
} else {
@@ -1875,10 +1888,8 @@ static __devinit void acpi_find_bmc(void)
return;
for (i = 0; ; i++) {
- status = acpi_get_firmware_table("SPMI", i+1,
- ACPI_LOGICAL_ADDRESSING,
- (struct acpi_table_header **)
- &spmi);
+ status = acpi_get_table(ACPI_SIG_SPMI, i+1,
+ (struct acpi_table_header **)&spmi);
if (status != AE_OK)
return;
@@ -2773,8 +2784,7 @@ static __devinit int init_ipmi_si(void)
#endif
#ifdef CONFIG_ACPI
- if (si_trydefaults)
- acpi_find_bmc();
+ acpi_find_bmc();
#endif
#ifdef CONFIG_PCI
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 90fb2a54191..6b634e8d951 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -134,14 +134,14 @@
static int nowayout = WATCHDOG_NOWAYOUT;
-static ipmi_user_t watchdog_user = NULL;
+static ipmi_user_t watchdog_user;
static int watchdog_ifnum;
/* Default the timeout to 10 seconds. */
static int timeout = 10;
/* The pre-timeout is disabled by default. */
-static int pretimeout = 0;
+static int pretimeout;
/* Default action is to reset the board on a timeout. */
static unsigned char action_val = WDOG_TIMEOUT_RESET;
@@ -156,10 +156,10 @@ static unsigned char preop_val = WDOG_PREOP_NONE;
static char preop[16] = "preop_none";
static DEFINE_SPINLOCK(ipmi_read_lock);
-static char data_to_read = 0;
+static char data_to_read;
static DECLARE_WAIT_QUEUE_HEAD(read_q);
-static struct fasync_struct *fasync_q = NULL;
-static char pretimeout_since_last_heartbeat = 0;
+static struct fasync_struct *fasync_q;
+static char pretimeout_since_last_heartbeat;
static char expect_close;
static int ifnum_to_use = -1;
@@ -177,7 +177,7 @@ static void ipmi_unregister_watchdog(int ipmi_intf);
/* If true, the driver will start running as soon as it is configured
and ready. */
-static int start_now = 0;
+static int start_now;
static int set_param_int(const char *val, struct kernel_param *kp)
{
@@ -216,13 +216,13 @@ static int set_param_str(const char *val, struct kernel_param *kp)
{
action_fn fn = (action_fn) kp->arg;
int rv = 0;
- char *dup, *s;
+ char valcp[16];
+ char *s;
- dup = kstrdup(val, GFP_KERNEL);
- if (!dup)
- return -ENOMEM;
+ strncpy(valcp, val, 16);
+ valcp[15] = '\0';
- s = strstrip(dup);
+ s = strstrip(valcp);
down_read(&register_sem);
rv = fn(s, NULL);
@@ -235,7 +235,6 @@ static int set_param_str(const char *val, struct kernel_param *kp)
out_unlock:
up_read(&register_sem);
- kfree(dup);
return rv;
}
@@ -300,16 +299,16 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
/* If shutting down via IPMI, we ignore the heartbeat. */
-static int ipmi_ignore_heartbeat = 0;
+static int ipmi_ignore_heartbeat;
/* Is someone using the watchdog? Only one user is allowed. */
-static unsigned long ipmi_wdog_open = 0;
+static unsigned long ipmi_wdog_open;
/* If set to 1, the heartbeat command will set the state to reset and
start the timer. The timer doesn't normally run when the driver is
first opened until the heartbeat is set the first time, this
variable is used to accomplish this. */
-static int ipmi_start_timer_on_heartbeat = 0;
+static int ipmi_start_timer_on_heartbeat;
/* IPMI version of the BMC. */
static unsigned char ipmi_version_major;
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 1637c1d9a4b..01084abffdd 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -172,12 +172,14 @@ static struct pci_driver isicom_driver = {
static int prev_card = 3; /* start servicing isi_card[0] */
static struct tty_driver *isicom_normal;
-static struct timer_list tx;
+static DECLARE_COMPLETION(isi_timerdone);
static char re_schedule = 1;
static void isicom_tx(unsigned long _data);
static void isicom_start(struct tty_struct *tty);
+static DEFINE_TIMER(tx, isicom_tx, 0, 0);
+
/* baud index mappings from linux defns to isi */
static signed char linuxb_to_isib[] = {
@@ -193,9 +195,9 @@ struct isi_board {
unsigned short shift_count;
struct isi_port * ports;
signed char count;
- unsigned char isa;
spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */
unsigned long flags;
+ unsigned int index;
};
struct isi_port {
@@ -228,6 +230,20 @@ static struct isi_port isi_ports[PORT_COUNT];
* it wants to talk.
*/
+static inline int WaitTillCardIsFree(u16 base)
+{
+ unsigned int count = 0;
+ unsigned int a = in_atomic(); /* do we run under spinlock? */
+
+ while (!(inw(base + 0xe) & 0x1) && count++ < 100)
+ if (a)
+ mdelay(1);
+ else
+ msleep(1);
+
+ return !(inw(base + 0xe) & 0x1);
+}
+
static int lock_card(struct isi_board *card)
{
char retries;
@@ -274,69 +290,71 @@ static void unlock_card(struct isi_board *card)
* ISI Card specific ops ...
*/
+/* card->lock HAS to be held */
static void raise_dtr(struct isi_port *port)
{
struct isi_board *card = port->card;
unsigned long base = card->base;
u16 channel = port->channel;
- if (!lock_card(card))
+ if (WaitTillCardIsFree(base))
return;
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0504, base);
InterruptTheCard(base);
port->status |= ISI_DTR;
- unlock_card(card);
}
+/* card->lock HAS to be held */
static inline void drop_dtr(struct isi_port *port)
{
struct isi_board *card = port->card;
unsigned long base = card->base;
u16 channel = port->channel;
- if (!lock_card(card))
+ if (WaitTillCardIsFree(base))
return;
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0404, base);
InterruptTheCard(base);
port->status &= ~ISI_DTR;
- unlock_card(card);
}
+/* card->lock HAS to be held */
static inline void raise_rts(struct isi_port *port)
{
struct isi_board *card = port->card;
unsigned long base = card->base;
u16 channel = port->channel;
- if (!lock_card(card))
+ if (WaitTillCardIsFree(base))
return;
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0a04, base);
InterruptTheCard(base);
port->status |= ISI_RTS;
- unlock_card(card);
}
+
+/* card->lock HAS to be held */
static inline void drop_rts(struct isi_port *port)
{
struct isi_board *card = port->card;
unsigned long base = card->base;
u16 channel = port->channel;
- if (!lock_card(card))
+ if (WaitTillCardIsFree(base))
return;
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0804, base);
InterruptTheCard(base);
port->status &= ~ISI_RTS;
- unlock_card(card);
}
+/* card->lock MUST NOT be held */
static inline void raise_dtr_rts(struct isi_port *port)
{
struct isi_board *card = port->card;
@@ -353,35 +371,20 @@ static inline void raise_dtr_rts(struct isi_port *port)
unlock_card(card);
}
+/* card->lock HAS to be held */
static void drop_dtr_rts(struct isi_port *port)
{
struct isi_board *card = port->card;
unsigned long base = card->base;
u16 channel = port->channel;
- if (!lock_card(card))
+ if (WaitTillCardIsFree(base))
return;
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0c04, base);
InterruptTheCard(base);
port->status &= ~(ISI_RTS | ISI_DTR);
- unlock_card(card);
-}
-
-static inline void kill_queue(struct isi_port *port, short queue)
-{
- struct isi_board *card = port->card;
- unsigned long base = card->base;
- u16 channel = port->channel;
-
- if (!lock_card(card))
- return;
-
- outw(0x8000 | (channel << card->shift_count) | 0x02, base);
- outw((queue << 8) | 0x06, base);
- InterruptTheCard(base);
- unlock_card(card);
}
/*
@@ -514,17 +517,11 @@ static void isicom_tx(unsigned long _data)
/* schedule another tx for hopefully in about 10ms */
sched_again:
if (!re_schedule) {
- re_schedule = 2;
+ complete(&isi_timerdone);
return;
}
- init_timer(&tx);
- tx.expires = jiffies + HZ/100;
- tx.data = 0;
- tx.function = isicom_tx;
- add_timer(&tx);
-
- return;
+ mod_timer(&tx, jiffies + msecs_to_jiffies(10));
}
/* Interrupt handlers */
@@ -562,14 +559,12 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
base = card->base;
spin_lock(&card->card_lock);
- if (card->isa == NO) {
- /*
- * disable any interrupts from the PCI card and lower the
- * interrupt line
- */
- outw(0x8000, base+0x04);
- ClearInterrupt(base);
- }
+ /*
+ * disable any interrupts from the PCI card and lower the
+ * interrupt line
+ */
+ outw(0x8000, base+0x04);
+ ClearInterrupt(base);
inw(base); /* get the dummy word out */
header = inw(base);
@@ -579,19 +574,13 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
if (channel + 1 > card->port_count) {
printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): "
"%d(channel) > port_count.\n", base, channel+1);
- if (card->isa)
- ClearInterrupt(base);
- else
- outw(0x0000, base+0x04); /* enable interrupts */
+ outw(0x0000, base+0x04); /* enable interrupts */
spin_unlock(&card->card_lock);
return IRQ_HANDLED;
}
port = card->ports + channel;
if (!(port->flags & ASYNC_INITIALIZED)) {
- if (card->isa)
- ClearInterrupt(base);
- else
- outw(0x0000, base+0x04); /* enable interrupts */
+ outw(0x0000, base+0x04); /* enable interrupts */
return IRQ_HANDLED;
}
@@ -604,10 +593,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
}
if (byte_count & 0x01)
inw(base);
- if (card->isa == YES)
- ClearInterrupt(base);
- else
- outw(0x0000, base+0x04); /* enable interrupts */
+ outw(0x0000, base+0x04); /* enable interrupts */
spin_unlock(&card->card_lock);
return IRQ_HANDLED;
}
@@ -708,10 +694,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
}
tty_flip_buffer_push(tty);
}
- if (card->isa == YES)
- ClearInterrupt(base);
- else
- outw(0x0000, base+0x04); /* enable interrupts */
+ outw(0x0000, base+0x04); /* enable interrupts */
return IRQ_HANDLED;
}
@@ -762,7 +745,7 @@ static void isicom_config_port(struct isi_port *port)
else
raise_dtr(port);
- if (lock_card(card)) {
+ if (WaitTillCardIsFree(base) == 0) {
outw(0x8000 | (channel << shift_count) |0x03, base);
outw(linuxb_to_isib[baud] << 8 | 0x03, base);
channel_setup = 0;
@@ -790,7 +773,6 @@ static void isicom_config_port(struct isi_port *port)
}
outw(channel_setup, base);
InterruptTheCard(base);
- unlock_card(card);
}
if (C_CLOCAL(tty))
port->flags &= ~ASYNC_CHECK_CD;
@@ -809,12 +791,11 @@ static void isicom_config_port(struct isi_port *port)
if (I_IXOFF(tty))
flow_ctrl |= ISICOM_INITIATE_XONXOFF;
- if (lock_card(card)) {
+ if (WaitTillCardIsFree(base) == 0) {
outw(0x8000 | (channel << shift_count) |0x04, base);
outw(flow_ctrl << 8 | 0x05, base);
outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
InterruptTheCard(base);
- unlock_card(card);
}
/* rx enabled -> enable port for rx on the card */
@@ -839,10 +820,9 @@ static inline void isicom_setup_board(struct isi_board *bp)
}
port = bp->ports;
bp->status |= BOARD_ACTIVE;
- spin_unlock_irqrestore(&bp->card_lock, flags);
for (channel = 0; channel < bp->port_count; channel++, port++)
drop_dtr_rts(port);
- return;
+ spin_unlock_irqrestore(&bp->card_lock, flags);
}
static int isicom_setup_port(struct isi_port *port)
@@ -875,7 +855,12 @@ static int isicom_setup_port(struct isi_port *port)
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
/* discard any residual data */
- kill_queue(port, ISICOM_KILLTX | ISICOM_KILLRX);
+ if (WaitTillCardIsFree(card->base) == 0) {
+ outw(0x8000 | (port->channel << card->shift_count) | 0x02,
+ card->base);
+ outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
+ InterruptTheCard(card->base);
+ }
isicom_config_port(port);
port->flags |= ASYNC_INITIALIZED;
@@ -964,8 +949,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
{
struct isi_port *port;
struct isi_board *card;
- unsigned int line, board;
- int error;
+ unsigned int board;
+ int error, line;
line = tty->index;
if (line < 0 || line > PORT_COUNT-1)
@@ -1001,28 +986,22 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
static inline void isicom_shutdown_board(struct isi_board *bp)
{
- unsigned long flags;
-
- spin_lock_irqsave(&bp->card_lock, flags);
if (bp->status & BOARD_ACTIVE) {
bp->status &= ~BOARD_ACTIVE;
}
- spin_unlock_irqrestore(&bp->card_lock, flags);
}
+/* card->lock HAS to be held */
static void isicom_shutdown_port(struct isi_port *port)
{
struct isi_board *card = port->card;
struct tty_struct *tty;
- unsigned long flags;
tty = port->tty;
- spin_lock_irqsave(&card->card_lock, flags);
- if (!(port->flags & ASYNC_INITIALIZED)) {
- spin_unlock_irqrestore(&card->card_lock, flags);
+ if (!(port->flags & ASYNC_INITIALIZED))
return;
- }
+
if (port->xmit_buf) {
free_page((unsigned long) port->xmit_buf);
port->xmit_buf = NULL;
@@ -1030,7 +1009,6 @@ static void isicom_shutdown_port(struct isi_port *port)
port->flags &= ~ASYNC_INITIALIZED;
/* 3rd October 2000 : Vinayak P Risbud */
port->tty = NULL;
- spin_unlock_irqrestore(&card->card_lock, flags);
/*Fix done by Anil .S on 30-04-2001
remote login through isi port has dtr toggle problem
@@ -1276,10 +1254,12 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct isi_port *port = tty->driver_data;
+ unsigned long flags;
if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
return -ENODEV;
+ spin_lock_irqsave(&port->card->card_lock, flags);
if (set & TIOCM_RTS)
raise_rts(port);
if (set & TIOCM_DTR)
@@ -1289,6 +1269,7 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
drop_rts(port);
if (clear & TIOCM_DTR)
drop_dtr(port);
+ spin_unlock_irqrestore(&port->card->card_lock, flags);
return 0;
}
@@ -1321,7 +1302,10 @@ static int isicom_set_serial_info(struct isi_port *port,
(newinfo.flags & ASYNC_FLAGS));
}
if (reconfig_port) {
+ unsigned long flags;
+ spin_lock_irqsave(&port->card->card_lock, flags);
isicom_config_port(port);
+ spin_unlock_irqrestore(&port->card->card_lock, flags);
}
return 0;
}
@@ -1399,9 +1383,10 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
/* set_termios et all */
static void isicom_set_termios(struct tty_struct *tty,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct isi_port *port = tty->driver_data;
+ unsigned long flags;
if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
return;
@@ -1410,7 +1395,9 @@ static void isicom_set_termios(struct tty_struct *tty,
tty->termios->c_iflag == old_termios->c_iflag)
return;
+ spin_lock_irqsave(&port->card->card_lock, flags);
isicom_config_port(port);
+ spin_unlock_irqrestore(&port->card->card_lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -1487,11 +1474,15 @@ static void do_isicom_hangup(struct work_struct *work)
static void isicom_hangup(struct tty_struct *tty)
{
struct isi_port *port = tty->driver_data;
+ unsigned long flags;
if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
return;
+ spin_lock_irqsave(&port->card->card_lock, flags);
isicom_shutdown_port(port);
+ spin_unlock_irqrestore(&port->card->card_lock, flags);
+
port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE;
port->tty = NULL;
@@ -1520,37 +1511,6 @@ static void isicom_flush_buffer(struct tty_struct *tty)
* Driver init and deinit functions
*/
-static int __devinit isicom_register_ioregion(struct pci_dev *pdev,
- const unsigned int index)
-{
- struct isi_board *board = pci_get_drvdata(pdev);
-
- if (!board->base)
- return -EINVAL;
-
- if (!request_region(board->base, 16, ISICOM_NAME)) {
- dev_dbg(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
- "will be disabled.\n", board->base, board->base + 15,
- index + 1);
- return -EBUSY;
- }
-
- return 0;
-}
-
-static void isicom_unregister_ioregion(struct pci_dev *pdev)
-{
- struct isi_board *board = pci_get_drvdata(pdev);
-
- if (!board->base)
- return;
-
- release_region(board->base, 16);
- dev_dbg(&pdev->dev, "I/O Region 0x%lx-0x%lx released.\n",
- board->base, board->base + 15);
- board->base = 0;
-}
-
static const struct tty_operations isicom_ops = {
.open = isicom_open,
.close = isicom_close,
@@ -1571,70 +1531,6 @@ static const struct tty_operations isicom_ops = {
.tiocmset = isicom_tiocmset,
};
-static int __devinit isicom_register_tty_driver(void)
-{
- int error = -ENOMEM;
-
- /* tty driver structure initialization */
- isicom_normal = alloc_tty_driver(PORT_COUNT);
- if (!isicom_normal)
- goto end;
-
- isicom_normal->owner = THIS_MODULE;
- isicom_normal->name = "ttyM";
- isicom_normal->major = ISICOM_NMAJOR;
- isicom_normal->minor_start = 0;
- isicom_normal->type = TTY_DRIVER_TYPE_SERIAL;
- isicom_normal->subtype = SERIAL_TYPE_NORMAL;
- isicom_normal->init_termios = tty_std_termios;
- isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
- CLOCAL;
- isicom_normal->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(isicom_normal, &isicom_ops);
-
- if ((error = tty_register_driver(isicom_normal))) {
- pr_dbg("Couldn't register the dialin driver, error=%d\n",
- error);
- put_tty_driver(isicom_normal);
- }
-end:
- return error;
-}
-
-static void isicom_unregister_tty_driver(void)
-{
- int error;
-
- if ((error = tty_unregister_driver(isicom_normal)))
- pr_dbg("couldn't unregister normal driver, error=%d.\n", error);
-
- put_tty_driver(isicom_normal);
-}
-
-static int __devinit isicom_register_isr(struct pci_dev *pdev,
- const unsigned int index)
-{
- struct isi_board *board = pci_get_drvdata(pdev);
- unsigned long irqflags = IRQF_DISABLED;
- int retval = -EINVAL;
-
- if (!board->base)
- goto end;
-
- if (board->isa == NO)
- irqflags |= IRQF_SHARED;
-
- retval = request_irq(board->irq, isicom_interrupt, irqflags,
- ISICOM_NAME, board);
- if (retval < 0)
- dev_warn(&pdev->dev, "Could not install handler at Irq %d. "
- "Card%d will be disabled.\n", board->irq, index + 1);
- else
- retval = 0;
-end:
- return retval;
-}
-
static int __devinit reset_card(struct pci_dev *pdev,
const unsigned int card, unsigned int *signature)
{
@@ -1656,36 +1552,23 @@ static int __devinit reset_card(struct pci_dev *pdev,
*signature = inw(base + 0x4) & 0xff;
- if (board->isa == YES) {
- if (!(inw(base + 0xe) & 0x1) || (inw(base + 0x2))) {
- dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n",
- inw(base + 0x2), inw(base + 0xe));
- dev_err(&pdev->dev, "ISILoad:ISA Card%d reset failure "
- "(Possible bad I/O Port Address 0x%lx).\n",
- card + 1, base);
- retval = -EIO;
- goto end;
- }
- } else {
- portcount = inw(base + 0x2);
- if (!(inw(base + 0xe) & 0x1) || ((portcount != 0) &&
- (portcount != 4) && (portcount != 8))) {
- dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n",
- inw(base + 0x2), inw(base + 0xe));
- dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure "
- "(Possible bad I/O Port Address 0x%lx).\n",
- card + 1, base);
- retval = -EIO;
- goto end;
- }
+ portcount = inw(base + 0x2);
+ if (!(inw(base + 0xe) & 0x1) || ((portcount != 0) &&
+ (portcount != 4) && (portcount != 8))) {
+ dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n",
+ inw(base + 0x2), inw(base + 0xe));
+ dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure "
+ "(Possible bad I/O Port Address 0x%lx).\n",
+ card + 1, base);
+ retval = -EIO;
+ goto end;
}
switch (*signature) {
case 0xa5:
case 0xbb:
case 0xdd:
- board->port_count = (board->isa == NO && portcount == 4) ? 4 :
- 8;
+ board->port_count = (portcount == 4) ? 4 : 8;
board->shift_count = 12;
break;
case 0xcc:
@@ -1704,16 +1587,6 @@ end:
return retval;
}
-static inline int WaitTillCardIsFree(u16 base)
-{
- unsigned long count = 0;
-
- while (!(inw(base + 0xe) & 0x1) && count++ < 100)
- msleep(5);
-
- return !(inw(base + 0xe) & 0x1);
-}
-
static int __devinit load_firmware(struct pci_dev *pdev,
const unsigned int index, const unsigned int signature)
{
@@ -1831,6 +1704,11 @@ static int __devinit load_firmware(struct pci_dev *pdev,
}
data = kmalloc(word_count * 2, GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(&pdev->dev, "Card%d, firmware upload "
+ "failed, not enough memory\n", index + 1);
+ goto errrelfw;
+ }
inw(base);
insw(base, data, word_count);
InterruptTheCard(base);
@@ -1879,8 +1757,6 @@ end:
/*
* Insmod can set static symbols so keep these static
*/
-static int io[4];
-static int irq[4];
static int card;
static int __devinit isicom_probe(struct pci_dev *pdev,
@@ -1906,20 +1782,29 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
break;
}
+ board->index = index;
board->base = ioaddr;
board->irq = pciirq;
- board->isa = NO;
card++;
pci_set_drvdata(pdev, board);
- retval = isicom_register_ioregion(pdev, index);
- if (retval < 0)
+ retval = pci_request_region(pdev, 3, ISICOM_NAME);
+ if (retval) {
+ dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
+ "will be disabled.\n", board->base, board->base + 15,
+ index + 1);
+ retval = -EBUSY;
goto err;
+ }
- retval = isicom_register_isr(pdev, index);
- if (retval < 0)
+ retval = request_irq(board->irq, isicom_interrupt,
+ IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board);
+ if (retval < 0) {
+ dev_err(&pdev->dev, "Could not install handler at Irq %d. "
+ "Card%d will be disabled.\n", board->irq, index + 1);
goto errunrr;
+ }
retval = reset_card(pdev, index, &signature);
if (retval < 0)
@@ -1929,12 +1814,16 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
if (retval < 0)
goto errunri;
+ for (index = 0; index < board->port_count; index++)
+ tty_register_device(isicom_normal, board->index * 16 + index,
+ &pdev->dev);
+
return 0;
errunri:
free_irq(board->irq, board);
errunrr:
- isicom_unregister_ioregion(pdev);
+ pci_release_region(pdev, 3);
err:
board->base = 0;
return retval;
@@ -1943,18 +1832,21 @@ err:
static void __devexit isicom_remove(struct pci_dev *pdev)
{
struct isi_board *board = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < board->port_count; i++)
+ tty_unregister_device(isicom_normal, board->index * 16 + i);
free_irq(board->irq, board);
- isicom_unregister_ioregion(pdev);
+ pci_release_region(pdev, 3);
}
-static int __devinit isicom_setup(void)
+static int __init isicom_init(void)
{
int retval, idx, channel;
struct isi_port *port;
card = 0;
- memset(isi_ports, 0, sizeof(isi_ports));
for(idx = 0; idx < BOARD_COUNT; idx++) {
port = &isi_ports[idx * 16];
@@ -1975,66 +1867,65 @@ static int __devinit isicom_setup(void)
}
isi_card[idx].base = 0;
isi_card[idx].irq = 0;
-
- if (!io[idx])
- continue;
-
- if (irq[idx] == 2 || irq[idx] == 3 || irq[idx] == 4 ||
- irq[idx] == 5 || irq[idx] == 7 ||
- irq[idx] == 10 || irq[idx] == 11 ||
- irq[idx] == 12 || irq[idx] == 15) {
- printk(KERN_ERR "ISICOM: ISA not supported yet.\n");
- retval = -EINVAL;
- goto error;
- } else
- printk(KERN_ERR "ISICOM: Irq %d unsupported. "
- "Disabling Card%d...\n", irq[idx], idx + 1);
}
- retval = isicom_register_tty_driver();
- if (retval < 0)
+ /* tty driver structure initialization */
+ isicom_normal = alloc_tty_driver(PORT_COUNT);
+ if (!isicom_normal) {
+ retval = -ENOMEM;
goto error;
+ }
+
+ isicom_normal->owner = THIS_MODULE;
+ isicom_normal->name = "ttyM";
+ isicom_normal->major = ISICOM_NMAJOR;
+ isicom_normal->minor_start = 0;
+ isicom_normal->type = TTY_DRIVER_TYPE_SERIAL;
+ isicom_normal->subtype = SERIAL_TYPE_NORMAL;
+ isicom_normal->init_termios = tty_std_termios;
+ isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
+ CLOCAL;
+ isicom_normal->flags = TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(isicom_normal, &isicom_ops);
+
+ retval = tty_register_driver(isicom_normal);
+ if (retval) {
+ pr_dbg("Couldn't register the dialin driver\n");
+ goto err_puttty;
+ }
retval = pci_register_driver(&isicom_driver);
if (retval < 0) {
printk(KERN_ERR "ISICOM: Unable to register pci driver.\n");
- goto errtty;
+ goto err_unrtty;
}
- init_timer(&tx);
- tx.expires = jiffies + 1;
- tx.data = 0;
- tx.function = isicom_tx;
- re_schedule = 1;
- add_timer(&tx);
+ mod_timer(&tx, jiffies + 1);
return 0;
-errtty:
- isicom_unregister_tty_driver();
+err_unrtty:
+ tty_unregister_driver(isicom_normal);
+err_puttty:
+ put_tty_driver(isicom_normal);
error:
return retval;
}
static void __exit isicom_exit(void)
{
- unsigned int index = 0;
-
re_schedule = 0;
- while (re_schedule != 2 && index++ < 100)
- msleep(10);
+ wait_for_completion_timeout(&isi_timerdone, HZ);
pci_unregister_driver(&isicom_driver);
- isicom_unregister_tty_driver();
+ tty_unregister_driver(isicom_normal);
+ put_tty_driver(isicom_normal);
}
-module_init(isicom_setup);
+module_init(isicom_init);
module_exit(isicom_exit);
MODULE_AUTHOR("MultiTech");
MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
MODULE_LICENSE("GPL");
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O ports for the cards");
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(irq, "Interrupts for the cards");
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 8f591945ebd..68645d35187 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -14,14 +14,6 @@
* 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.
*/
/*****************************************************************************/
@@ -41,6 +33,7 @@
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/eisa.h>
+#include <linux/ctype.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -61,21 +54,10 @@
#define BRD_BRUMBY4 2
#define BRD_ONBOARD2 3
#define BRD_ONBOARD 4
-#define BRD_BRUMBY8 5
-#define BRD_BRUMBY16 6
#define BRD_ONBOARDE 7
-#define BRD_ONBOARD32 9
-#define BRD_ONBOARD2_32 10
-#define BRD_ONBOARDRS 11
-#define BRD_EASYIO 20
-#define BRD_ECH 21
-#define BRD_ECHMC 22
#define BRD_ECP 23
#define BRD_ECPE 24
#define BRD_ECPMC 25
-#define BRD_ECHPCI 26
-#define BRD_ECH64PCI 27
-#define BRD_EASYIOPCI 28
#define BRD_ECPPCI 29
#define BRD_BRUMBY BRD_BRUMBY4
@@ -119,20 +101,16 @@
* interrupt is required.
*/
-typedef struct {
+struct stlconf {
int brdtype;
int ioaddr1;
int ioaddr2;
unsigned long memaddr;
int irq;
int irqtype;
-} stlconf_t;
-
-static stlconf_t stli_brdconf[] = {
- /*{ BRD_ECP, 0x2a0, 0, 0xcc000, 0, 0 },*/
};
-static int stli_nrbrds = ARRAY_SIZE(stli_brdconf);
+static unsigned int stli_nrbrds;
/* stli_lock must NOT be taken holding brd_lock */
static spinlock_t stli_lock; /* TTY logic lock */
@@ -194,9 +172,11 @@ static struct tty_struct *stli_txcooktty;
* with this termios initially. Basically all it defines is a raw port
* at 9600 baud, 8 data bits, no parity, 1 stop bit.
*/
-static struct termios stli_deftermios = {
+static struct ktermios stli_deftermios = {
.c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
.c_cc = INIT_C_CC,
+ .c_ispeed = 9600,
+ .c_ospeed = 9600,
};
/*
@@ -205,13 +185,12 @@ static struct termios stli_deftermios = {
*/
static comstats_t stli_comstats;
static combrd_t stli_brdstats;
-static asystats_t stli_cdkstats;
-static stlibrd_t stli_dummybrd;
-static stliport_t stli_dummyport;
+static struct asystats stli_cdkstats;
/*****************************************************************************/
-static stlibrd_t *stli_brds[STL_MAXBRDS];
+static DEFINE_MUTEX(stli_brdslock);
+static struct stlibrd *stli_brds[STL_MAXBRDS];
static int stli_shared;
@@ -223,6 +202,7 @@ static int stli_shared;
*/
#define BST_FOUND 0x1
#define BST_STARTED 0x2
+#define BST_PROBED 0x4
/*
* Define the set of port state flags. These are marked for internal
@@ -255,18 +235,18 @@ static char *stli_brdnames[] = {
"Brumby",
"Brumby",
"ONboard-EI",
- (char *) NULL,
+ NULL,
"ONboard",
"ONboard-MC",
"ONboard-MC",
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
"EasyIO",
"EC8/32-AT",
"EC8/32-MC",
@@ -304,12 +284,10 @@ static char **stli_brdsp[] = {
* parse any module arguments.
*/
-typedef struct stlibrdtype {
+static struct stlibrdtype {
char *name;
int type;
-} stlibrdtype_t;
-
-static stlibrdtype_t stli_brdstr[] = {
+} stli_brdstr[] = {
{ "stallion", BRD_STALLION },
{ "1", BRD_STALLION },
{ "brumby", BRD_BRUMBY },
@@ -379,6 +357,7 @@ MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,memaddr]");
module_param_array(board3, charp, NULL, 0);
MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,memaddr]");
+#if STLI_EISAPROBE != 0
/*
* Set up a default memory address table for EISA board probing.
* The default addresses are all bellow 1Mbyte, which has to be the
@@ -396,14 +375,11 @@ static unsigned long stli_eisamemprobeaddrs[] = {
};
static int stli_eisamempsize = ARRAY_SIZE(stli_eisamemprobeaddrs);
+#endif
/*
* Define the Stallion PCI vendor and device IDs.
*/
-#ifdef CONFIG_PCI
-#ifndef PCI_VENDOR_ID_STALLION
-#define PCI_VENDOR_ID_STALLION 0x124d
-#endif
#ifndef PCI_DEVICE_ID_ECRA
#define PCI_DEVICE_ID_ECRA 0x0004
#endif
@@ -414,7 +390,7 @@ static struct pci_device_id istallion_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, istallion_pci_tbl);
-#endif /* CONFIG_PCI */
+static struct pci_driver stli_pcidriver;
/*****************************************************************************/
@@ -615,22 +591,10 @@ MODULE_DEVICE_TABLE(pci, istallion_pci_tbl);
/*****************************************************************************/
/*
- * Define some handy local macros...
- */
-#undef MIN
-#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
-
-#undef TOLOWER
-#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x))
-
-/*****************************************************************************/
-
-/*
* Prototype all functions in this driver!
*/
-static int stli_parsebrd(stlconf_t *confp, char **argp);
-static int stli_init(void);
+static int stli_parsebrd(struct stlconf *confp, char **argp);
static int stli_open(struct tty_struct *tty, struct file *filp);
static void stli_close(struct tty_struct *tty, struct file *filp);
static int stli_write(struct tty_struct *tty, const unsigned char *buf, int count);
@@ -639,7 +603,7 @@ static void stli_flushchars(struct tty_struct *tty);
static int stli_writeroom(struct tty_struct *tty);
static int stli_charsinbuffer(struct tty_struct *tty);
static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static void stli_settermios(struct tty_struct *tty, struct termios *old);
+static void stli_settermios(struct tty_struct *tty, struct ktermios *old);
static void stli_throttle(struct tty_struct *tty);
static void stli_unthrottle(struct tty_struct *tty);
static void stli_stop(struct tty_struct *tty);
@@ -649,86 +613,84 @@ static void stli_breakctl(struct tty_struct *tty, int state);
static void stli_waituntilsent(struct tty_struct *tty, int timeout);
static void stli_sendxchar(struct tty_struct *tty, char ch);
static void stli_hangup(struct tty_struct *tty);
-static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *pos);
+static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos);
-static int stli_brdinit(stlibrd_t *brdp);
-static int stli_startbrd(stlibrd_t *brdp);
+static int stli_brdinit(struct stlibrd *brdp);
+static int stli_startbrd(struct stlibrd *brdp);
static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp);
static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp);
static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
-static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp);
+static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
static void stli_poll(unsigned long arg);
-static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp);
-static int stli_initopen(stlibrd_t *brdp, stliport_t *portp);
-static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait);
-static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait);
-static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp);
+static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
+static int stli_initopen(struct stlibrd *brdp, struct stliport *portp);
+static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
+static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
+static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp);
static void stli_dohangup(struct work_struct *);
-static int stli_setport(stliport_t *portp);
-static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
-static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
-static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
-static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp);
-static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp);
+static int stli_setport(struct stliport *portp);
+static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
+static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
+static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
+static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp);
+static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts);
static long stli_mktiocm(unsigned long sigvalue);
-static void stli_read(stlibrd_t *brdp, stliport_t *portp);
-static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp);
-static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp);
+static void stli_read(struct stlibrd *brdp, struct stliport *portp);
+static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp);
+static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp);
static int stli_getbrdstats(combrd_t __user *bp);
-static int stli_getportstats(stliport_t *portp, comstats_t __user *cp);
-static int stli_portcmdstats(stliport_t *portp);
-static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp);
-static int stli_getportstruct(stliport_t __user *arg);
-static int stli_getbrdstruct(stlibrd_t __user *arg);
-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 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 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 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 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 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 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 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 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);
-
-static int stli_initecp(stlibrd_t *brdp);
-static int stli_initonb(stlibrd_t *brdp);
-static int stli_eisamemprobe(stlibrd_t *brdp);
-static int stli_initports(stlibrd_t *brdp);
-
-#ifdef CONFIG_PCI
-static int stli_initpcibrd(int brdtype, struct pci_dev *devp);
+static int stli_getportstats(struct stliport *portp, comstats_t __user *cp);
+static int stli_portcmdstats(struct stliport *portp);
+static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp);
+static int stli_getportstruct(struct stliport __user *arg);
+static int stli_getbrdstruct(struct stlibrd __user *arg);
+static struct stlibrd *stli_allocbrd(void);
+
+static void stli_ecpinit(struct stlibrd *brdp);
+static void stli_ecpenable(struct stlibrd *brdp);
+static void stli_ecpdisable(struct stlibrd *brdp);
+static void __iomem *stli_ecpgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_ecpreset(struct stlibrd *brdp);
+static void stli_ecpintr(struct stlibrd *brdp);
+static void stli_ecpeiinit(struct stlibrd *brdp);
+static void stli_ecpeienable(struct stlibrd *brdp);
+static void stli_ecpeidisable(struct stlibrd *brdp);
+static void __iomem *stli_ecpeigetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_ecpeireset(struct stlibrd *brdp);
+static void stli_ecpmcenable(struct stlibrd *brdp);
+static void stli_ecpmcdisable(struct stlibrd *brdp);
+static void __iomem *stli_ecpmcgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_ecpmcreset(struct stlibrd *brdp);
+static void stli_ecppciinit(struct stlibrd *brdp);
+static void __iomem *stli_ecppcigetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_ecppcireset(struct stlibrd *brdp);
+
+static void stli_onbinit(struct stlibrd *brdp);
+static void stli_onbenable(struct stlibrd *brdp);
+static void stli_onbdisable(struct stlibrd *brdp);
+static void __iomem *stli_onbgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_onbreset(struct stlibrd *brdp);
+static void stli_onbeinit(struct stlibrd *brdp);
+static void stli_onbeenable(struct stlibrd *brdp);
+static void stli_onbedisable(struct stlibrd *brdp);
+static void __iomem *stli_onbegetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_onbereset(struct stlibrd *brdp);
+static void stli_bbyinit(struct stlibrd *brdp);
+static void __iomem *stli_bbygetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_bbyreset(struct stlibrd *brdp);
+static void stli_stalinit(struct stlibrd *brdp);
+static void __iomem *stli_stalgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_stalreset(struct stlibrd *brdp);
+
+static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr, unsigned int portnr);
+
+static int stli_initecp(struct stlibrd *brdp);
+static int stli_initonb(struct stlibrd *brdp);
+#if STLI_EISAPROBE != 0
+static int stli_eisamemprobe(struct stlibrd *brdp);
#endif
+static int stli_initports(struct stlibrd *brdp);
/*****************************************************************************/
@@ -766,136 +728,19 @@ static int stli_timeron;
static struct class *istallion_class;
-/*
- * Loadable module initialization stuff.
- */
-
-static int __init istallion_module_init(void)
-{
- stli_init();
- return 0;
-}
-
-/*****************************************************************************/
-
-static void __exit istallion_module_exit(void)
-{
- stlibrd_t *brdp;
- stliport_t *portp;
- int i, j;
-
- printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
- stli_drvversion);
-
- /*
- * Free up all allocated resources used by the ports. This includes
- * memory and interrupts.
- */
- if (stli_timeron) {
- stli_timeron = 0;
- del_timer_sync(&stli_timerlist);
- }
-
- i = tty_unregister_driver(stli_serial);
- if (i) {
- printk("STALLION: failed to un-register tty driver, "
- "errno=%d\n", -i);
- return;
- }
- put_tty_driver(stli_serial);
- for (i = 0; i < 4; i++)
- class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, i));
- class_destroy(istallion_class);
- if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
- printk("STALLION: failed to un-register serial memory device, "
- "errno=%d\n", -i);
-
- kfree(stli_txcookbuf);
-
- for (i = 0; (i < stli_nrbrds); i++) {
- if ((brdp = stli_brds[i]) == NULL)
- continue;
- for (j = 0; (j < STL_MAXPORTS); j++) {
- portp = brdp->ports[j];
- if (portp != NULL) {
- if (portp->tty != NULL)
- tty_hangup(portp->tty);
- kfree(portp);
- }
- }
-
- iounmap(brdp->membase);
- if (brdp->iosize > 0)
- release_region(brdp->iobase, brdp->iosize);
- kfree(brdp);
- stli_brds[i] = NULL;
- }
-}
-
-module_init(istallion_module_init);
-module_exit(istallion_module_exit);
-
-/*****************************************************************************/
-
-/*
- * Check for any arguments passed in on the module load command line.
- */
-
-static void stli_argbrds(void)
+static void stli_cleanup_ports(struct stlibrd *brdp)
{
- stlconf_t conf;
- stlibrd_t *brdp;
- int i;
-
- for (i = stli_nrbrds; i < ARRAY_SIZE(stli_brdsp); i++) {
- memset(&conf, 0, sizeof(conf));
- if (stli_parsebrd(&conf, stli_brdsp[i]) == 0)
- continue;
- if ((brdp = stli_allocbrd()) == NULL)
- continue;
- stli_nrbrds = i + 1;
- brdp->brdnr = i;
- brdp->brdtype = conf.brdtype;
- brdp->iobase = conf.ioaddr1;
- brdp->memaddr = conf.memaddr;
- stli_brdinit(brdp);
- }
-}
-
-/*****************************************************************************/
-
-/*
- * Convert an ascii string number into an unsigned long.
- */
-
-static unsigned long stli_atol(char *str)
-{
- unsigned long val;
- int base, c;
- char *sp;
-
- val = 0;
- sp = str;
- if ((*sp == '0') && (*(sp+1) == 'x')) {
- base = 16;
- sp += 2;
- } else if (*sp == '0') {
- base = 8;
- sp++;
- } else {
- base = 10;
- }
-
- for (; (*sp != 0); sp++) {
- c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0');
- if ((c < 0) || (c >= base)) {
- printk("STALLION: invalid argument %s\n", str);
- val = 0;
- break;
+ struct stliport *portp;
+ unsigned int j;
+
+ for (j = 0; j < STL_MAXPORTS; j++) {
+ portp = brdp->ports[j];
+ if (portp != NULL) {
+ if (portp->tty != NULL)
+ tty_hangup(portp->tty);
+ kfree(portp);
}
- val = (val * base) + c;
}
- return(val);
}
/*****************************************************************************/
@@ -904,16 +749,16 @@ static unsigned long stli_atol(char *str)
* Parse the supplied argument string, into the board conf struct.
*/
-static int stli_parsebrd(stlconf_t *confp, char **argp)
+static int stli_parsebrd(struct stlconf *confp, char **argp)
{
+ unsigned int i;
char *sp;
- int i;
if (argp[0] == NULL || *argp[0] == 0)
return 0;
for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++)
- *sp = TOLOWER(*sp);
+ *sp = tolower(*sp);
for (i = 0; i < ARRAY_SIZE(stli_brdstr); i++) {
if (strcmp(stli_brdstr[i].name, argp[0]) == 0)
@@ -926,9 +771,9 @@ static int stli_parsebrd(stlconf_t *confp, char **argp)
confp->brdtype = stli_brdstr[i].type;
if (argp[1] != NULL && *argp[1] != 0)
- confp->ioaddr1 = stli_atol(argp[1]);
+ confp->ioaddr1 = simple_strtoul(argp[1], NULL, 0);
if (argp[2] != NULL && *argp[2] != 0)
- confp->memaddr = stli_atol(argp[2]);
+ confp->memaddr = simple_strtoul(argp[2], NULL, 0);
return(1);
}
@@ -936,10 +781,10 @@ static int stli_parsebrd(stlconf_t *confp, char **argp)
static int stli_open(struct tty_struct *tty, struct file *filp)
{
- stlibrd_t *brdp;
- stliport_t *portp;
- unsigned int minordev;
- int brdnr, portnr, rc;
+ struct stlibrd *brdp;
+ struct stliport *portp;
+ unsigned int minordev, brdnr, portnr;
+ int rc;
minordev = tty->index;
brdnr = MINOR2BRD(minordev);
@@ -951,7 +796,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
if ((brdp->state & BST_STARTED) == 0)
return -ENODEV;
portnr = MINOR2PORT(minordev);
- if ((portnr < 0) || (portnr > brdp->nrports))
+ if (portnr > brdp->nrports)
return -ENODEV;
portp = brdp->ports[portnr];
@@ -1031,8 +876,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
static void stli_close(struct tty_struct *tty, struct file *filp)
{
- stlibrd_t *brdp;
- stliport_t *portp;
+ struct stlibrd *brdp;
+ struct stliport *portp;
unsigned long flags;
portp = tty->driver_data;
@@ -1109,7 +954,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
* this still all happens pretty quickly.
*/
-static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
+static int stli_initopen(struct stlibrd *brdp, struct stliport *portp)
{
struct tty_struct *tty;
asynotify_t nt;
@@ -1157,7 +1002,7 @@ static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
* to overlap.
*/
-static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait)
+static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait)
{
cdkhdr_t __iomem *hdrp;
cdkctrl_t __iomem *cp;
@@ -1228,7 +1073,7 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
* wait is true then must have user context (to sleep).
*/
-static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait)
+static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait)
{
cdkhdr_t __iomem *hdrp;
cdkctrl_t __iomem *cp;
@@ -1292,7 +1137,7 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
* to complete (as opposed to initiating the command then returning).
*/
-static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
{
wait_event_interruptible(portp->raw_wait,
!test_bit(ST_CMDING, &portp->state));
@@ -1318,16 +1163,16 @@ static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, v
* waiting for the command to complete - so must have user context.
*/
-static int stli_setport(stliport_t *portp)
+static int stli_setport(struct stliport *portp)
{
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
asyport_t aport;
if (portp == NULL)
return -ENODEV;
if (portp->tty == NULL)
return -ENODEV;
- if (portp->brdnr < 0 && portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return -ENODEV;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -1344,7 +1189,7 @@ static int stli_setport(stliport_t *portp)
* maybe because if we are clocal then we don't need to wait...
*/
-static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp)
+static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp)
{
unsigned long flags;
int rc, doclocal;
@@ -1409,8 +1254,8 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
unsigned char __iomem *bits;
unsigned char __iomem *shbuf;
unsigned char *chbuf;
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned int len, stlen, head, tail, size;
unsigned long flags;
@@ -1419,7 +1264,7 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
portp = tty->driver_data;
if (portp == NULL)
return 0;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -1445,12 +1290,12 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
stlen = len;
}
- len = MIN(len, count);
+ len = min(len, (unsigned int)count);
count = 0;
shbuf = (char __iomem *) EBRDGETMEMPTR(brdp, portp->txoffset);
while (len > 0) {
- stlen = MIN(len, stlen);
+ stlen = min(len, stlen);
memcpy_toio(shbuf + head, chbuf, stlen);
chbuf += stlen;
len -= stlen;
@@ -1516,8 +1361,8 @@ static void stli_flushchars(struct tty_struct *tty)
unsigned char __iomem *bits;
cdkasy_t __iomem *ap;
struct tty_struct *cooktty;
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned int len, stlen, head, tail, size, count, cooksize;
unsigned char *buf;
unsigned char __iomem *shbuf;
@@ -1541,7 +1386,7 @@ static void stli_flushchars(struct tty_struct *tty)
portp = tty->driver_data;
if (portp == NULL)
return;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -1564,13 +1409,13 @@ static void stli_flushchars(struct tty_struct *tty)
stlen = len;
}
- len = MIN(len, cooksize);
+ len = min(len, cooksize);
count = 0;
shbuf = EBRDGETMEMPTR(brdp, portp->txoffset);
buf = stli_txcookbuf;
while (len > 0) {
- stlen = MIN(len, stlen);
+ stlen = min(len, stlen);
memcpy_toio(shbuf + head, buf, stlen);
buf += stlen;
len -= stlen;
@@ -1604,8 +1449,8 @@ static void stli_flushchars(struct tty_struct *tty)
static int stli_writeroom(struct tty_struct *tty)
{
cdkasyrq_t __iomem *rp;
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned int head, tail, len;
unsigned long flags;
@@ -1619,7 +1464,7 @@ static int stli_writeroom(struct tty_struct *tty)
portp = tty->driver_data;
if (portp == NULL)
return 0;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -1657,8 +1502,8 @@ static int stli_writeroom(struct tty_struct *tty)
static int stli_charsinbuffer(struct tty_struct *tty)
{
cdkasyrq_t __iomem *rp;
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned int head, tail, len;
unsigned long flags;
@@ -1667,7 +1512,7 @@ static int stli_charsinbuffer(struct tty_struct *tty)
portp = tty->driver_data;
if (portp == NULL)
return 0;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -1695,10 +1540,10 @@ static int stli_charsinbuffer(struct tty_struct *tty)
* Generate the serial struct info.
*/
-static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
+static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp)
{
struct serial_struct sio;
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
memset(&sio, 0, sizeof(struct serial_struct));
sio.type = PORT_UNKNOWN;
@@ -1728,7 +1573,7 @@ static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
* just quietly ignore any requests to change irq, etc.
*/
-static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
+static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp)
{
struct serial_struct sio;
int rc;
@@ -1759,13 +1604,13 @@ static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
static int stli_tiocmget(struct tty_struct *tty, struct file *file)
{
- stliport_t *portp = tty->driver_data;
- stlibrd_t *brdp;
+ struct stliport *portp = tty->driver_data;
+ struct stlibrd *brdp;
int rc;
if (portp == NULL)
return -ENODEV;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -1783,13 +1628,13 @@ static int stli_tiocmget(struct tty_struct *tty, struct file *file)
static int stli_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- stliport_t *portp = tty->driver_data;
- stlibrd_t *brdp;
+ struct stliport *portp = tty->driver_data;
+ struct stlibrd *brdp;
int rts = -1, dtr = -1;
if (portp == NULL)
return -ENODEV;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -1814,8 +1659,8 @@ static int stli_tiocmset(struct tty_struct *tty, struct file *file,
static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned int ival;
int rc;
void __user *argp = (void __user *)arg;
@@ -1823,7 +1668,7 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
portp = tty->driver_data;
if (portp == NULL)
return -ENODEV;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -1889,11 +1734,11 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
* Looks like it is true for the current ttys implementation..!!
*/
-static void stli_settermios(struct tty_struct *tty, struct termios *old)
+static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
{
- stliport_t *portp;
- stlibrd_t *brdp;
- struct termios *tiosp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
+ struct ktermios *tiosp;
asyport_t aport;
if (tty == NULL)
@@ -1901,7 +1746,7 @@ static void stli_settermios(struct tty_struct *tty, struct termios *old)
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -1937,7 +1782,7 @@ static void stli_settermios(struct tty_struct *tty, struct termios *old)
static void stli_throttle(struct tty_struct *tty)
{
- stliport_t *portp = tty->driver_data;
+ struct stliport *portp = tty->driver_data;
if (portp == NULL)
return;
set_bit(ST_RXSTOP, &portp->state);
@@ -1953,7 +1798,7 @@ static void stli_throttle(struct tty_struct *tty)
static void stli_unthrottle(struct tty_struct *tty)
{
- stliport_t *portp = tty->driver_data;
+ struct stliport *portp = tty->driver_data;
if (portp == NULL)
return;
clear_bit(ST_RXSTOP, &portp->state);
@@ -1992,7 +1837,7 @@ static void stli_start(struct tty_struct *tty)
static void stli_dohangup(struct work_struct *ugly_api)
{
- stliport_t *portp = container_of(ugly_api, stliport_t, tqhangup);
+ struct stliport *portp = container_of(ugly_api, struct stliport, tqhangup);
if (portp->tty != NULL) {
tty_hangup(portp->tty);
}
@@ -2009,14 +1854,14 @@ static void stli_dohangup(struct work_struct *ugly_api)
static void stli_hangup(struct tty_struct *tty)
{
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned long flags;
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -2062,14 +1907,14 @@ static void stli_hangup(struct tty_struct *tty)
static void stli_flushbuffer(struct tty_struct *tty)
{
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned long ftype, flags;
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -2099,14 +1944,14 @@ static void stli_flushbuffer(struct tty_struct *tty)
static void stli_breakctl(struct tty_struct *tty, int state)
{
- stlibrd_t *brdp;
- stliport_t *portp;
+ struct stlibrd *brdp;
+ struct stliport *portp;
long arg;
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -2120,7 +1965,7 @@ static void stli_breakctl(struct tty_struct *tty, int state)
static void stli_waituntilsent(struct tty_struct *tty, int timeout)
{
- stliport_t *portp;
+ struct stliport *portp;
unsigned long tend;
if (tty == NULL)
@@ -2146,14 +1991,14 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout)
static void stli_sendxchar(struct tty_struct *tty, char ch)
{
- stlibrd_t *brdp;
- stliport_t *portp;
+ struct stlibrd *brdp;
+ struct stliport *portp;
asyctrl_t actrl;
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
@@ -2181,7 +2026,7 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
* short then padded with spaces).
*/
-static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *pos)
+static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos)
{
char *sp, *uart;
int rc, cnt;
@@ -2244,9 +2089,9 @@ static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *p
static int stli_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- stlibrd_t *brdp;
- stliport_t *portp;
- int brdnr, portnr, totalport;
+ struct stlibrd *brdp;
+ struct stliport *portp;
+ unsigned int brdnr, portnr, totalport;
int curoff, maxoff;
char *pos;
@@ -2316,7 +2161,7 @@ stli_readdone:
* entry point)
*/
-static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
{
cdkhdr_t __iomem *hdrp;
cdkctrl_t __iomem *cp;
@@ -2352,7 +2197,7 @@ static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd
spin_unlock_irqrestore(&brd_lock, flags);
}
-static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
{
unsigned long flags;
@@ -2371,7 +2216,7 @@ static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd,
* more chars to unload.
*/
-static void stli_read(stlibrd_t *brdp, stliport_t *portp)
+static void stli_read(struct stlibrd *brdp, struct stliport *portp)
{
cdkasyrq_t __iomem *rp;
char __iomem *shbuf;
@@ -2406,7 +2251,7 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
while (len > 0) {
unsigned char *cptr;
- stlen = MIN(len, stlen);
+ stlen = min(len, stlen);
tty_prepare_flip_string(tty, &cptr, stlen);
memcpy_fromio(cptr, shbuf + tail, stlen);
len -= stlen;
@@ -2433,7 +2278,7 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
* difficult to deal with them here.
*/
-static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp)
+static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp)
{
int cmd;
@@ -2481,7 +2326,7 @@ static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp)
* then port is still busy, otherwise no longer busy.
*/
-static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
+static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
{
cdkasy_t __iomem *ap;
cdkctrl_t __iomem *cp;
@@ -2628,9 +2473,9 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
* at the cdk header structure.
*/
-static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp)
+static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp)
{
- stliport_t *portp;
+ struct stliport *portp;
unsigned char hostbits[(STL_MAXCHANS / 8) + 1];
unsigned char slavebits[(STL_MAXCHANS / 8) + 1];
unsigned char __iomem *slavep;
@@ -2697,11 +2542,10 @@ static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp)
static void stli_poll(unsigned long arg)
{
cdkhdr_t __iomem *hdrp;
- stlibrd_t *brdp;
- int brdnr;
+ struct stlibrd *brdp;
+ unsigned int brdnr;
- stli_timerlist.expires = STLI_TIMEOUT;
- add_timer(&stli_timerlist);
+ mod_timer(&stli_timerlist, STLI_TIMEOUT);
/*
* Check each board and do any servicing required.
@@ -2730,7 +2574,7 @@ static void stli_poll(unsigned long arg)
* the slave.
*/
-static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp)
+static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp)
{
memset(pp, 0, sizeof(asyport_t));
@@ -2879,13 +2723,13 @@ static long stli_mktiocm(unsigned long sigvalue)
* we need to do here is set up the appropriate per port data structures.
*/
-static int stli_initports(stlibrd_t *brdp)
+static int stli_initports(struct stlibrd *brdp)
{
- stliport_t *portp;
- int i, panelnr, panelport;
+ struct stliport *portp;
+ unsigned int i, panelnr, panelport;
for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) {
- portp = kzalloc(sizeof(stliport_t), GFP_KERNEL);
+ portp = kzalloc(sizeof(struct stliport), GFP_KERNEL);
if (!portp) {
printk("STALLION: failed to allocate port structure\n");
continue;
@@ -2919,7 +2763,7 @@ static int stli_initports(stlibrd_t *brdp)
* All the following routines are board specific hardware operations.
*/
-static void stli_ecpinit(stlibrd_t *brdp)
+static void stli_ecpinit(struct stlibrd *brdp)
{
unsigned long memconf;
@@ -2934,21 +2778,21 @@ static void stli_ecpinit(stlibrd_t *brdp)
/*****************************************************************************/
-static void stli_ecpenable(stlibrd_t *brdp)
+static void stli_ecpenable(struct stlibrd *brdp)
{
outb(ECP_ATENABLE, (brdp->iobase + ECP_ATCONFR));
}
/*****************************************************************************/
-static void stli_ecpdisable(stlibrd_t *brdp)
+static void stli_ecpdisable(struct stlibrd *brdp)
{
outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
}
/*****************************************************************************/
-static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecpgetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
@@ -2969,7 +2813,7 @@ static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, in
/*****************************************************************************/
-static void stli_ecpreset(stlibrd_t *brdp)
+static void stli_ecpreset(struct stlibrd *brdp)
{
outb(ECP_ATSTOP, (brdp->iobase + ECP_ATCONFR));
udelay(10);
@@ -2979,7 +2823,7 @@ static void stli_ecpreset(stlibrd_t *brdp)
/*****************************************************************************/
-static void stli_ecpintr(stlibrd_t *brdp)
+static void stli_ecpintr(struct stlibrd *brdp)
{
outb(0x1, brdp->iobase);
}
@@ -2990,7 +2834,7 @@ static void stli_ecpintr(stlibrd_t *brdp)
* The following set of functions act on ECP EISA boards.
*/
-static void stli_ecpeiinit(stlibrd_t *brdp)
+static void stli_ecpeiinit(struct stlibrd *brdp)
{
unsigned long memconf;
@@ -3008,21 +2852,21 @@ static void stli_ecpeiinit(stlibrd_t *brdp)
/*****************************************************************************/
-static void stli_ecpeienable(stlibrd_t *brdp)
+static void stli_ecpeienable(struct stlibrd *brdp)
{
outb(ECP_EIENABLE, (brdp->iobase + ECP_EICONFR));
}
/*****************************************************************************/
-static void stli_ecpeidisable(stlibrd_t *brdp)
+static void stli_ecpeidisable(struct stlibrd *brdp)
{
outb(ECP_EIDISABLE, (brdp->iobase + ECP_EICONFR));
}
/*****************************************************************************/
-static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecpeigetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
@@ -3046,7 +2890,7 @@ static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset,
/*****************************************************************************/
-static void stli_ecpeireset(stlibrd_t *brdp)
+static void stli_ecpeireset(struct stlibrd *brdp)
{
outb(ECP_EISTOP, (brdp->iobase + ECP_EICONFR));
udelay(10);
@@ -3060,21 +2904,21 @@ static void stli_ecpeireset(stlibrd_t *brdp)
* The following set of functions act on ECP MCA boards.
*/
-static void stli_ecpmcenable(stlibrd_t *brdp)
+static void stli_ecpmcenable(struct stlibrd *brdp)
{
outb(ECP_MCENABLE, (brdp->iobase + ECP_MCCONFR));
}
/*****************************************************************************/
-static void stli_ecpmcdisable(stlibrd_t *brdp)
+static void stli_ecpmcdisable(struct stlibrd *brdp)
{
outb(ECP_MCDISABLE, (brdp->iobase + ECP_MCCONFR));
}
/*****************************************************************************/
-static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecpmcgetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
@@ -3095,7 +2939,7 @@ static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset,
/*****************************************************************************/
-static void stli_ecpmcreset(stlibrd_t *brdp)
+static void stli_ecpmcreset(struct stlibrd *brdp)
{
outb(ECP_MCSTOP, (brdp->iobase + ECP_MCCONFR));
udelay(10);
@@ -3109,7 +2953,7 @@ static void stli_ecpmcreset(stlibrd_t *brdp)
* The following set of functions act on ECP PCI boards.
*/
-static void stli_ecppciinit(stlibrd_t *brdp)
+static void stli_ecppciinit(struct stlibrd *brdp)
{
outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR));
udelay(10);
@@ -3119,7 +2963,7 @@ static void stli_ecppciinit(stlibrd_t *brdp)
/*****************************************************************************/
-static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecppcigetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
@@ -3140,7 +2984,7 @@ static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset,
/*****************************************************************************/
-static void stli_ecppcireset(stlibrd_t *brdp)
+static void stli_ecppcireset(struct stlibrd *brdp)
{
outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR));
udelay(10);
@@ -3154,7 +2998,7 @@ static void stli_ecppcireset(stlibrd_t *brdp)
* The following routines act on ONboards.
*/
-static void stli_onbinit(stlibrd_t *brdp)
+static void stli_onbinit(struct stlibrd *brdp)
{
unsigned long memconf;
@@ -3171,21 +3015,21 @@ static void stli_onbinit(stlibrd_t *brdp)
/*****************************************************************************/
-static void stli_onbenable(stlibrd_t *brdp)
+static void stli_onbenable(struct stlibrd *brdp)
{
outb((brdp->enabval | ONB_ATENABLE), (brdp->iobase + ONB_ATCONFR));
}
/*****************************************************************************/
-static void stli_onbdisable(stlibrd_t *brdp)
+static void stli_onbdisable(struct stlibrd *brdp)
{
outb((brdp->enabval | ONB_ATDISABLE), (brdp->iobase + ONB_ATCONFR));
}
/*****************************************************************************/
-static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_onbgetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
@@ -3202,7 +3046,7 @@ static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, in
/*****************************************************************************/
-static void stli_onbreset(stlibrd_t *brdp)
+static void stli_onbreset(struct stlibrd *brdp)
{
outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
udelay(10);
@@ -3216,7 +3060,7 @@ static void stli_onbreset(stlibrd_t *brdp)
* The following routines act on ONboard EISA.
*/
-static void stli_onbeinit(stlibrd_t *brdp)
+static void stli_onbeinit(struct stlibrd *brdp)
{
unsigned long memconf;
@@ -3236,21 +3080,21 @@ static void stli_onbeinit(stlibrd_t *brdp)
/*****************************************************************************/
-static void stli_onbeenable(stlibrd_t *brdp)
+static void stli_onbeenable(struct stlibrd *brdp)
{
outb(ONB_EIENABLE, (brdp->iobase + ONB_EICONFR));
}
/*****************************************************************************/
-static void stli_onbedisable(stlibrd_t *brdp)
+static void stli_onbedisable(struct stlibrd *brdp)
{
outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
}
/*****************************************************************************/
-static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_onbegetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
@@ -3274,7 +3118,7 @@ static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, i
/*****************************************************************************/
-static void stli_onbereset(stlibrd_t *brdp)
+static void stli_onbereset(struct stlibrd *brdp)
{
outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
udelay(10);
@@ -3288,7 +3132,7 @@ static void stli_onbereset(stlibrd_t *brdp)
* The following routines act on Brumby boards.
*/
-static void stli_bbyinit(stlibrd_t *brdp)
+static void stli_bbyinit(struct stlibrd *brdp)
{
outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
udelay(10);
@@ -3300,7 +3144,7 @@ static void stli_bbyinit(stlibrd_t *brdp)
/*****************************************************************************/
-static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_bbygetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
@@ -3315,7 +3159,7 @@ static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, in
/*****************************************************************************/
-static void stli_bbyreset(stlibrd_t *brdp)
+static void stli_bbyreset(struct stlibrd *brdp)
{
outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
udelay(10);
@@ -3329,7 +3173,7 @@ static void stli_bbyreset(stlibrd_t *brdp)
* The following routines act on original old Stallion boards.
*/
-static void stli_stalinit(stlibrd_t *brdp)
+static void stli_stalinit(struct stlibrd *brdp)
{
outb(0x1, brdp->iobase);
mdelay(1000);
@@ -3337,7 +3181,7 @@ static void stli_stalinit(stlibrd_t *brdp)
/*****************************************************************************/
-static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_stalgetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
BUG_ON(offset > brdp->memsize);
return brdp->membase + (offset % STAL_PAGESIZE);
@@ -3345,7 +3189,7 @@ static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, i
/*****************************************************************************/
-static void stli_stalreset(stlibrd_t *brdp)
+static void stli_stalreset(struct stlibrd *brdp)
{
u32 __iomem *vecp;
@@ -3362,21 +3206,22 @@ static void stli_stalreset(stlibrd_t *brdp)
* board types.
*/
-static int stli_initecp(stlibrd_t *brdp)
+static int stli_initecp(struct stlibrd *brdp)
{
cdkecpsig_t sig;
cdkecpsig_t __iomem *sigsp;
unsigned int status, nxtid;
char *name;
- int panelnr, nrports;
+ int retval, panelnr, nrports;
- if (!request_region(brdp->iobase, brdp->iosize, "istallion"))
- return -EIO;
-
- if ((brdp->iobase == 0) || (brdp->memaddr == 0))
- {
- release_region(brdp->iobase, brdp->iosize);
- return -ENODEV;
+ if ((brdp->iobase == 0) || (brdp->memaddr == 0)) {
+ retval = -ENODEV;
+ goto err;
+ }
+
+ if (!request_region(brdp->iobase, brdp->iosize, "istallion")) {
+ retval = -EIO;
+ goto err;
}
brdp->iosize = ECP_IOSIZE;
@@ -3388,7 +3233,6 @@ static int stli_initecp(stlibrd_t *brdp)
*/
switch (brdp->brdtype) {
case BRD_ECP:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = ECP_MEMSIZE;
brdp->pagesize = ECP_ATPAGESIZE;
brdp->init = stli_ecpinit;
@@ -3402,7 +3246,6 @@ static int stli_initecp(stlibrd_t *brdp)
break;
case BRD_ECPE:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = ECP_MEMSIZE;
brdp->pagesize = ECP_EIPAGESIZE;
brdp->init = stli_ecpeiinit;
@@ -3416,7 +3259,6 @@ static int stli_initecp(stlibrd_t *brdp)
break;
case BRD_ECPMC:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = ECP_MEMSIZE;
brdp->pagesize = ECP_MCPAGESIZE;
brdp->init = NULL;
@@ -3430,7 +3272,6 @@ static int stli_initecp(stlibrd_t *brdp)
break;
case BRD_ECPPCI:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = ECP_PCIMEMSIZE;
brdp->pagesize = ECP_PCIPAGESIZE;
brdp->init = stli_ecppciinit;
@@ -3444,8 +3285,8 @@ static int stli_initecp(stlibrd_t *brdp)
break;
default:
- release_region(brdp->iobase, brdp->iosize);
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_reg;
}
/*
@@ -3457,10 +3298,9 @@ static int stli_initecp(stlibrd_t *brdp)
EBRDINIT(brdp);
brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
- if (brdp->membase == NULL)
- {
- release_region(brdp->iobase, brdp->iosize);
- return -ENOMEM;
+ if (brdp->membase == NULL) {
+ retval = -ENOMEM;
+ goto err_reg;
}
/*
@@ -3473,12 +3313,9 @@ static int stli_initecp(stlibrd_t *brdp)
memcpy_fromio(&sig, sigsp, sizeof(cdkecpsig_t));
EBRDDISABLE(brdp);
- if (sig.magic != cpu_to_le32(ECP_MAGIC))
- {
- release_region(brdp->iobase, brdp->iosize);
- iounmap(brdp->membase);
- brdp->membase = NULL;
- return -ENODEV;
+ if (sig.magic != cpu_to_le32(ECP_MAGIC)) {
+ retval = -ENODEV;
+ goto err_unmap;
}
/*
@@ -3503,6 +3340,13 @@ static int stli_initecp(stlibrd_t *brdp)
brdp->state |= BST_FOUND;
return 0;
+err_unmap:
+ iounmap(brdp->membase);
+ brdp->membase = NULL;
+err_reg:
+ release_region(brdp->iobase, brdp->iosize);
+err:
+ return retval;
}
/*****************************************************************************/
@@ -3512,23 +3356,27 @@ static int stli_initecp(stlibrd_t *brdp)
* This handles only these board types.
*/
-static int stli_initonb(stlibrd_t *brdp)
+static int stli_initonb(struct stlibrd *brdp)
{
cdkonbsig_t sig;
cdkonbsig_t __iomem *sigsp;
char *name;
- int i;
+ int i, retval;
/*
* Do a basic sanity check on the IO and memory addresses.
*/
- if (brdp->iobase == 0 || brdp->memaddr == 0)
- return -ENODEV;
+ if (brdp->iobase == 0 || brdp->memaddr == 0) {
+ retval = -ENODEV;
+ goto err;
+ }
brdp->iosize = ONB_IOSIZE;
- if (!request_region(brdp->iobase, brdp->iosize, "istallion"))
- return -EIO;
+ if (!request_region(brdp->iobase, brdp->iosize, "istallion")) {
+ retval = -EIO;
+ goto err;
+ }
/*
* Based on the specific board type setup the common vars to access
@@ -3537,10 +3385,7 @@ static int stli_initonb(stlibrd_t *brdp)
*/
switch (brdp->brdtype) {
case BRD_ONBOARD:
- case BRD_ONBOARD32:
case BRD_ONBOARD2:
- case BRD_ONBOARD2_32:
- case BRD_ONBOARDRS:
brdp->memsize = ONB_MEMSIZE;
brdp->pagesize = ONB_ATPAGESIZE;
brdp->init = stli_onbinit;
@@ -3571,8 +3416,6 @@ static int stli_initonb(stlibrd_t *brdp)
break;
case BRD_BRUMBY4:
- case BRD_BRUMBY8:
- case BRD_BRUMBY16:
brdp->memsize = BBY_MEMSIZE;
brdp->pagesize = BBY_PAGESIZE;
brdp->init = stli_bbyinit;
@@ -3599,8 +3442,8 @@ static int stli_initonb(stlibrd_t *brdp)
break;
default:
- release_region(brdp->iobase, brdp->iosize);
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_reg;
}
/*
@@ -3612,10 +3455,9 @@ static int stli_initonb(stlibrd_t *brdp)
EBRDINIT(brdp);
brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
- if (brdp->membase == NULL)
- {
- release_region(brdp->iobase, brdp->iosize);
- return -ENOMEM;
+ if (brdp->membase == NULL) {
+ retval = -ENOMEM;
+ goto err_reg;
}
/*
@@ -3631,12 +3473,9 @@ static int stli_initonb(stlibrd_t *brdp)
if (sig.magic0 != cpu_to_le16(ONB_MAGIC0) ||
sig.magic1 != cpu_to_le16(ONB_MAGIC1) ||
sig.magic2 != cpu_to_le16(ONB_MAGIC2) ||
- sig.magic3 != cpu_to_le16(ONB_MAGIC3))
- {
- release_region(brdp->iobase, brdp->iosize);
- iounmap(brdp->membase);
- brdp->membase = NULL;
- return -ENODEV;
+ sig.magic3 != cpu_to_le16(ONB_MAGIC3)) {
+ retval = -ENODEV;
+ goto err_unmap;
}
/*
@@ -3658,6 +3497,13 @@ static int stli_initonb(stlibrd_t *brdp)
brdp->state |= BST_FOUND;
return 0;
+err_unmap:
+ iounmap(brdp->membase);
+ brdp->membase = NULL;
+err_reg:
+ release_region(brdp->iobase, brdp->iosize);
+err:
+ return retval;
}
/*****************************************************************************/
@@ -3668,14 +3514,15 @@ static int stli_initonb(stlibrd_t *brdp)
* read in the memory map, and get the show on the road...
*/
-static int stli_startbrd(stlibrd_t *brdp)
+static int stli_startbrd(struct stlibrd *brdp)
{
cdkhdr_t __iomem *hdrp;
cdkmem_t __iomem *memp;
cdkasy_t __iomem *ap;
unsigned long flags;
- stliport_t *portp;
- int portnr, nrdevs, i, rc = 0;
+ unsigned int portnr, nrdevs, i;
+ struct stliport *portp;
+ int rc = 0;
u32 memoff;
spin_lock_irqsave(&brd_lock, flags);
@@ -3762,8 +3609,7 @@ stli_donestartup:
if (! stli_timeron) {
stli_timeron++;
- stli_timerlist.expires = STLI_TIMEOUT;
- add_timer(&stli_timerlist);
+ mod_timer(&stli_timerlist, STLI_TIMEOUT);
}
return rc;
@@ -3775,49 +3621,32 @@ stli_donestartup:
* Probe and initialize the specified board.
*/
-static int __init stli_brdinit(stlibrd_t *brdp)
+static int __devinit stli_brdinit(struct stlibrd *brdp)
{
- stli_brds[brdp->brdnr] = brdp;
+ int retval;
switch (brdp->brdtype) {
case BRD_ECP:
case BRD_ECPE:
case BRD_ECPMC:
case BRD_ECPPCI:
- stli_initecp(brdp);
+ retval = stli_initecp(brdp);
break;
case BRD_ONBOARD:
case BRD_ONBOARDE:
case BRD_ONBOARD2:
- case BRD_ONBOARD32:
- case BRD_ONBOARD2_32:
- case BRD_ONBOARDRS:
case BRD_BRUMBY4:
- case BRD_BRUMBY8:
- case BRD_BRUMBY16:
case BRD_STALLION:
- stli_initonb(brdp);
+ retval = stli_initonb(brdp);
break;
- case BRD_EASYIO:
- case BRD_ECH:
- case BRD_ECHMC:
- case BRD_ECHPCI:
- printk(KERN_ERR "STALLION: %s board type not supported in "
- "this driver\n", stli_brdnames[brdp->brdtype]);
- return -ENODEV;
default:
printk(KERN_ERR "STALLION: board=%d is unknown board "
"type=%d\n", brdp->brdnr, brdp->brdtype);
- return -ENODEV;
+ retval = -ENODEV;
}
- if ((brdp->state & BST_FOUND) == 0) {
- printk(KERN_ERR "STALLION: %s board not found, board=%d "
- "io=%x mem=%x\n",
- stli_brdnames[brdp->brdtype], brdp->brdnr,
- brdp->iobase, (int) brdp->memaddr);
- return -ENODEV;
- }
+ if (retval)
+ return retval;
stli_initports(brdp);
printk(KERN_INFO "STALLION: %s found, board=%d io=%x mem=%x "
@@ -3827,6 +3656,7 @@ static int __init stli_brdinit(stlibrd_t *brdp)
return 0;
}
+#if STLI_EISAPROBE != 0
/*****************************************************************************/
/*
@@ -3834,7 +3664,7 @@ static int __init stli_brdinit(stlibrd_t *brdp)
* might be. This is a bit if hack, but it is the best we can do.
*/
-static int stli_eisamemprobe(stlibrd_t *brdp)
+static int stli_eisamemprobe(struct stlibrd *brdp)
{
cdkecpsig_t ecpsig, __iomem *ecpsigp;
cdkonbsig_t onbsig, __iomem *onbsigp;
@@ -3920,10 +3750,11 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
}
return 0;
}
+#endif
static int stli_getbrdnr(void)
{
- int i;
+ unsigned int i;
for (i = 0; i < STL_MAXBRDS; i++) {
if (!stli_brds[i]) {
@@ -3935,6 +3766,7 @@ static int stli_getbrdnr(void)
return -1;
}
+#if STLI_EISAPROBE != 0
/*****************************************************************************/
/*
@@ -3949,9 +3781,9 @@ static int stli_getbrdnr(void)
static int stli_findeisabrds(void)
{
- stlibrd_t *brdp;
- unsigned int iobase, eid;
- int i;
+ struct stlibrd *brdp;
+ unsigned int iobase, eid, i;
+ int brdnr, found = 0;
/*
* Firstly check if this is an EISA system. If this is not an EISA system then
@@ -3989,9 +3821,11 @@ static int stli_findeisabrds(void)
* Allocate a board structure and initialize it.
*/
if ((brdp = stli_allocbrd()) == NULL)
- return -ENOMEM;
- if ((brdp->brdnr = stli_getbrdnr()) < 0)
- return -ENOMEM;
+ return found ? : -ENOMEM;
+ brdnr = stli_getbrdnr();
+ if (brdnr < 0)
+ return found ? : -ENOMEM;
+ brdp->brdnr = (unsigned int)brdnr;
eid = inb(iobase + 0xc82);
if (eid == ECP_EISAID)
brdp->brdtype = BRD_ECPE;
@@ -4003,11 +3837,24 @@ static int stli_findeisabrds(void)
outb(0x1, (iobase + 0xc84));
if (stli_eisamemprobe(brdp))
outb(0, (iobase + 0xc84));
- stli_brdinit(brdp);
+ if (stli_brdinit(brdp) < 0) {
+ kfree(brdp);
+ continue;
+ }
+
+ stli_brds[brdp->brdnr] = brdp;
+ found++;
+
+ for (i = 0; i < brdp->nrports; i++)
+ tty_register_device(stli_serial,
+ brdp->brdnr * STL_MAXPORTS + i, NULL);
}
- return 0;
+ return found;
}
+#else
+static inline int stli_findeisabrds(void) { return 0; }
+#endif
/*****************************************************************************/
@@ -4017,72 +3864,104 @@ static int stli_findeisabrds(void)
/*****************************************************************************/
-#ifdef CONFIG_PCI
-
/*
* We have a Stallion board. Allocate a board structure and
* initialize it. Read its IO and MEMORY resources from PCI
* configuration space.
*/
-static int stli_initpcibrd(int brdtype, struct pci_dev *devp)
+static int __devinit stli_pciprobe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- stlibrd_t *brdp;
-
- if (pci_enable_device(devp))
- return -EIO;
- if ((brdp = stli_allocbrd()) == NULL)
- return -ENOMEM;
- if ((brdp->brdnr = stli_getbrdnr()) < 0) {
+ struct stlibrd *brdp;
+ unsigned int i;
+ int brdnr, retval = -EIO;
+
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err;
+ brdp = stli_allocbrd();
+ if (brdp == NULL) {
+ retval = -ENOMEM;
+ goto err;
+ }
+ mutex_lock(&stli_brdslock);
+ brdnr = stli_getbrdnr();
+ if (brdnr < 0) {
printk(KERN_INFO "STALLION: too many boards found, "
"maximum supported %d\n", STL_MAXBRDS);
- return 0;
+ mutex_unlock(&stli_brdslock);
+ retval = -EIO;
+ goto err_fr;
}
- brdp->brdtype = brdtype;
+ brdp->brdnr = (unsigned int)brdnr;
+ stli_brds[brdp->brdnr] = brdp;
+ mutex_unlock(&stli_brdslock);
+ brdp->brdtype = BRD_ECPPCI;
/*
* We have all resources from the board, so lets setup the actual
* board structure now.
*/
- brdp->iobase = pci_resource_start(devp, 3);
- brdp->memaddr = pci_resource_start(devp, 2);
- stli_brdinit(brdp);
+ brdp->iobase = pci_resource_start(pdev, 3);
+ brdp->memaddr = pci_resource_start(pdev, 2);
+ retval = stli_brdinit(brdp);
+ if (retval)
+ goto err_null;
+
+ brdp->state |= BST_PROBED;
+ pci_set_drvdata(pdev, brdp);
+
+ EBRDENABLE(brdp);
+ brdp->enable = NULL;
+ brdp->disable = NULL;
+
+ for (i = 0; i < brdp->nrports; i++)
+ tty_register_device(stli_serial, brdp->brdnr * STL_MAXPORTS + i,
+ &pdev->dev);
return 0;
+err_null:
+ stli_brds[brdp->brdnr] = NULL;
+err_fr:
+ kfree(brdp);
+err:
+ return retval;
}
-/*****************************************************************************/
+static void stli_pciremove(struct pci_dev *pdev)
+{
+ struct stlibrd *brdp = pci_get_drvdata(pdev);
-/*
- * Find all Stallion PCI boards that might be installed. Initialize each
- * one as it is found.
- */
+ stli_cleanup_ports(brdp);
-static int stli_findpcibrds(void)
-{
- struct pci_dev *dev = NULL;
+ iounmap(brdp->membase);
+ if (brdp->iosize > 0)
+ release_region(brdp->iobase, brdp->iosize);
- while ((dev = pci_get_device(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECRA, dev))) {
- stli_initpcibrd(BRD_ECPPCI, dev);
- }
- return 0;
+ stli_brds[brdp->brdnr] = NULL;
+ kfree(brdp);
}
-#endif
-
+static struct pci_driver stli_pcidriver = {
+ .name = "istallion",
+ .id_table = istallion_pci_tbl,
+ .probe = stli_pciprobe,
+ .remove = __devexit_p(stli_pciremove)
+};
/*****************************************************************************/
/*
* Allocate a new board structure. Fill out the basic info in it.
*/
-static stlibrd_t *stli_allocbrd(void)
+static struct stlibrd *stli_allocbrd(void)
{
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
- brdp = kzalloc(sizeof(stlibrd_t), GFP_KERNEL);
+ brdp = kzalloc(sizeof(struct stlibrd), GFP_KERNEL);
if (!brdp) {
printk(KERN_ERR "STALLION: failed to allocate memory "
- "(size=%Zd)\n", sizeof(stlibrd_t));
+ "(size=%Zd)\n", sizeof(struct stlibrd));
return NULL;
}
brdp->magic = STLI_BOARDMAGIC;
@@ -4098,43 +3977,37 @@ static stlibrd_t *stli_allocbrd(void)
static int stli_initbrds(void)
{
- stlibrd_t *brdp, *nxtbrdp;
- stlconf_t *confp;
- int i, j;
-
- if (stli_nrbrds > STL_MAXBRDS) {
- printk(KERN_INFO "STALLION: too many boards in configuration "
- "table, truncating to %d\n", STL_MAXBRDS);
- stli_nrbrds = STL_MAXBRDS;
- }
+ struct stlibrd *brdp, *nxtbrdp;
+ struct stlconf conf;
+ unsigned int i, j, found = 0;
+ int retval;
-/*
- * Firstly scan the list of static boards configured. Allocate
- * resources and initialize the boards as found. If this is a
- * module then let the module args override static configuration.
- */
- for (i = 0; (i < stli_nrbrds); i++) {
- confp = &stli_brdconf[i];
- stli_parsebrd(confp, stli_brdsp[i]);
+ for (stli_nrbrds = 0; stli_nrbrds < ARRAY_SIZE(stli_brdsp);
+ stli_nrbrds++) {
+ memset(&conf, 0, sizeof(conf));
+ if (stli_parsebrd(&conf, stli_brdsp[stli_nrbrds]) == 0)
+ continue;
if ((brdp = stli_allocbrd()) == NULL)
- return -ENOMEM;
- brdp->brdnr = i;
- brdp->brdtype = confp->brdtype;
- brdp->iobase = confp->ioaddr1;
- brdp->memaddr = confp->memaddr;
- stli_brdinit(brdp);
+ continue;
+ brdp->brdnr = stli_nrbrds;
+ brdp->brdtype = conf.brdtype;
+ brdp->iobase = conf.ioaddr1;
+ brdp->memaddr = conf.memaddr;
+ if (stli_brdinit(brdp) < 0) {
+ kfree(brdp);
+ continue;
+ }
+ stli_brds[brdp->brdnr] = brdp;
+ found++;
+
+ for (i = 0; i < brdp->nrports; i++)
+ tty_register_device(stli_serial,
+ brdp->brdnr * STL_MAXPORTS + i, NULL);
}
-/*
- * Static configuration table done, so now use dynamic methods to
- * see if any more boards should be configured.
- */
- stli_argbrds();
- if (STLI_EISAPROBE)
- stli_findeisabrds();
-#ifdef CONFIG_PCI
- stli_findpcibrds();
-#endif
+ retval = stli_findeisabrds();
+ if (retval > 0)
+ found += retval;
/*
* All found boards are initialized. Now for a little optimization, if
@@ -4174,7 +4047,16 @@ static int stli_initbrds(void)
}
}
+ retval = pci_register_driver(&stli_pcidriver);
+ if (retval && found == 0) {
+ printk(KERN_ERR "Neither isa nor eisa cards found nor pci "
+ "driver can be registered!\n");
+ goto err;
+ }
+
return 0;
+err:
+ return retval;
}
/*****************************************************************************/
@@ -4189,12 +4071,13 @@ static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, lof
{
unsigned long flags;
void __iomem *memptr;
- stlibrd_t *brdp;
- int brdnr, size, n;
+ struct stlibrd *brdp;
+ unsigned int brdnr;
+ int size, n;
void *p;
loff_t off = *offp;
- brdnr = iminor(fp->f_dentry->d_inode);
+ brdnr = iminor(fp->f_path.dentry->d_inode);
if (brdnr >= stli_nrbrds)
return -ENODEV;
brdp = stli_brds[brdnr];
@@ -4205,7 +4088,7 @@ static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, lof
if (off >= brdp->memsize || off + count < off)
return 0;
- size = MIN(count, (brdp->memsize - off));
+ size = min(count, (size_t)(brdp->memsize - off));
/*
* Copy the data a page at a time
@@ -4219,8 +4102,8 @@ static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, lof
spin_lock_irqsave(&brd_lock, flags);
EBRDENABLE(brdp);
memptr = EBRDGETMEMPTR(brdp, off);
- n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
- n = MIN(n, PAGE_SIZE);
+ n = min(size, (int)(brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
+ n = min(n, (int)PAGE_SIZE);
memcpy_fromio(p, memptr, n);
EBRDDISABLE(brdp);
spin_unlock_irqrestore(&brd_lock, flags);
@@ -4252,13 +4135,14 @@ static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t cou
{
unsigned long flags;
void __iomem *memptr;
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
char __user *chbuf;
- int brdnr, size, n;
+ unsigned int brdnr;
+ int size, n;
void *p;
loff_t off = *offp;
- brdnr = iminor(fp->f_dentry->d_inode);
+ brdnr = iminor(fp->f_path.dentry->d_inode);
if (brdnr >= stli_nrbrds)
return -ENODEV;
@@ -4271,7 +4155,7 @@ static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t cou
return 0;
chbuf = (char __user *) buf;
- size = MIN(count, (brdp->memsize - off));
+ size = min(count, (size_t)(brdp->memsize - off));
/*
* Copy the data a page at a time
@@ -4282,8 +4166,8 @@ static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t cou
return -ENOMEM;
while (size > 0) {
- n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
- n = MIN(n, PAGE_SIZE);
+ n = min(size, (int)(brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
+ n = min(n, (int)PAGE_SIZE);
if (copy_from_user(p, chbuf, n)) {
if (count == 0)
count = -EFAULT;
@@ -4313,8 +4197,8 @@ out:
static int stli_getbrdstats(combrd_t __user *bp)
{
- stlibrd_t *brdp;
- int i;
+ struct stlibrd *brdp;
+ unsigned int i;
if (copy_from_user(&stli_brdstats, bp, sizeof(combrd_t)))
return -EFAULT;
@@ -4350,19 +4234,20 @@ static int stli_getbrdstats(combrd_t __user *bp)
* Resolve the referenced port number into a port struct pointer.
*/
-static stliport_t *stli_getport(int brdnr, int panelnr, int portnr)
+static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr,
+ unsigned int portnr)
{
- stlibrd_t *brdp;
- int i;
+ struct stlibrd *brdp;
+ unsigned int i;
- if (brdnr < 0 || brdnr >= STL_MAXBRDS)
+ if (brdnr >= STL_MAXBRDS)
return NULL;
brdp = stli_brds[brdnr];
if (brdp == NULL)
return NULL;
for (i = 0; (i < panelnr); i++)
portnr += brdp->panels[i];
- if ((portnr < 0) || (portnr >= brdp->nrports))
+ if (portnr >= brdp->nrports)
return NULL;
return brdp->ports[portnr];
}
@@ -4375,10 +4260,10 @@ static stliport_t *stli_getport(int brdnr, int panelnr, int portnr)
* what port to get stats for (used through board control device).
*/
-static int stli_portcmdstats(stliport_t *portp)
+static int stli_portcmdstats(struct stliport *portp)
{
unsigned long flags;
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
int rc;
memset(&stli_comstats, 0, sizeof(comstats_t));
@@ -4449,9 +4334,9 @@ static int stli_portcmdstats(stliport_t *portp)
* what port to get stats for (used through board control device).
*/
-static int stli_getportstats(stliport_t *portp, comstats_t __user *cp)
+static int stli_getportstats(struct stliport *portp, comstats_t __user *cp)
{
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
int rc;
if (!portp) {
@@ -4480,9 +4365,9 @@ static int stli_getportstats(stliport_t *portp, comstats_t __user *cp)
* Clear the port stats structure. We also return it zeroed out...
*/
-static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp)
+static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp)
{
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
int rc;
if (!portp) {
@@ -4519,17 +4404,18 @@ static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp)
* Return the entire driver ports structure to a user app.
*/
-static int stli_getportstruct(stliport_t __user *arg)
+static int stli_getportstruct(struct stliport __user *arg)
{
- stliport_t *portp;
+ struct stliport stli_dummyport;
+ struct stliport *portp;
- if (copy_from_user(&stli_dummyport, arg, sizeof(stliport_t)))
+ if (copy_from_user(&stli_dummyport, arg, sizeof(struct stliport)))
return -EFAULT;
portp = stli_getport(stli_dummyport.brdnr, stli_dummyport.panelnr,
stli_dummyport.portnr);
if (!portp)
return -ENODEV;
- if (copy_to_user(arg, portp, sizeof(stliport_t)))
+ if (copy_to_user(arg, portp, sizeof(struct stliport)))
return -EFAULT;
return 0;
}
@@ -4540,18 +4426,19 @@ static int stli_getportstruct(stliport_t __user *arg)
* Return the entire driver board structure to a user app.
*/
-static int stli_getbrdstruct(stlibrd_t __user *arg)
+static int stli_getbrdstruct(struct stlibrd __user *arg)
{
- stlibrd_t *brdp;
+ struct stlibrd stli_dummybrd;
+ struct stlibrd *brdp;
- if (copy_from_user(&stli_dummybrd, arg, sizeof(stlibrd_t)))
+ if (copy_from_user(&stli_dummybrd, arg, sizeof(struct stlibrd)))
return -EFAULT;
- if ((stli_dummybrd.brdnr < 0) || (stli_dummybrd.brdnr >= STL_MAXBRDS))
+ if (stli_dummybrd.brdnr >= STL_MAXBRDS)
return -ENODEV;
brdp = stli_brds[stli_dummybrd.brdnr];
if (!brdp)
return -ENODEV;
- if (copy_to_user(arg, brdp, sizeof(stlibrd_t)))
+ if (copy_to_user(arg, brdp, sizeof(struct stlibrd)))
return -EFAULT;
return 0;
}
@@ -4566,7 +4453,7 @@ static int stli_getbrdstruct(stlibrd_t __user *arg)
static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
{
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
int brdnr, rc, done;
void __user *argp = (void __user *)arg;
@@ -4665,46 +4552,53 @@ static const struct tty_operations stli_ops = {
};
/*****************************************************************************/
+/*
+ * Loadable module initialization stuff.
+ */
+
+static void istallion_cleanup_isa(void)
+{
+ struct stlibrd *brdp;
+ unsigned int j;
+
+ for (j = 0; (j < stli_nrbrds); j++) {
+ if ((brdp = stli_brds[j]) == NULL || (brdp->state & BST_PROBED))
+ continue;
+
+ stli_cleanup_ports(brdp);
-static int __init stli_init(void)
+ iounmap(brdp->membase);
+ if (brdp->iosize > 0)
+ release_region(brdp->iobase, brdp->iosize);
+ kfree(brdp);
+ stli_brds[j] = NULL;
+ }
+}
+
+static int __init istallion_module_init(void)
{
- int i;
+ unsigned int i;
+ int retval;
+
printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);
spin_lock_init(&stli_lock);
spin_lock_init(&brd_lock);
- stli_initbrds();
-
- stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
- if (!stli_serial)
- return -ENOMEM;
-
-/*
- * Allocate a temporary write buffer.
- */
stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
- if (!stli_txcookbuf)
+ if (!stli_txcookbuf) {
printk(KERN_ERR "STALLION: failed to allocate memory "
"(size=%d)\n", STLI_TXBUFSIZE);
+ retval = -ENOMEM;
+ goto err;
+ }
-/*
- * Set up a character driver for the shared memory region. We need this
- * to down load the slave code image. Also it is a useful debugging tool.
- */
- if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem))
- printk(KERN_ERR "STALLION: failed to register serial memory "
- "device\n");
-
- istallion_class = class_create(THIS_MODULE, "staliomem");
- for (i = 0; i < 4; i++)
- class_device_create(istallion_class, NULL,
- MKDEV(STL_SIOMEMMAJOR, i),
- NULL, "staliomem%d", i);
+ stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
+ if (!stli_serial) {
+ retval = -ENOMEM;
+ goto err_free;
+ }
-/*
- * Set up the tty driver structure and register us as a driver.
- */
stli_serial->owner = THIS_MODULE;
stli_serial->driver_name = stli_drvname;
stli_serial->name = stli_serialname;
@@ -4713,15 +4607,79 @@ static int __init stli_init(void)
stli_serial->type = TTY_DRIVER_TYPE_SERIAL;
stli_serial->subtype = SERIAL_TYPE_NORMAL;
stli_serial->init_termios = stli_deftermios;
- stli_serial->flags = TTY_DRIVER_REAL_RAW;
+ stli_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(stli_serial, &stli_ops);
- if (tty_register_driver(stli_serial)) {
- put_tty_driver(stli_serial);
+ retval = tty_register_driver(stli_serial);
+ if (retval) {
printk(KERN_ERR "STALLION: failed to register serial driver\n");
- return -EBUSY;
+ goto err_ttyput;
}
+
+ retval = stli_initbrds();
+ if (retval)
+ goto err_ttyunr;
+
+/*
+ * Set up a character driver for the shared memory region. We need this
+ * to down load the slave code image. Also it is a useful debugging tool.
+ */
+ retval = register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem);
+ if (retval) {
+ printk(KERN_ERR "STALLION: failed to register serial memory "
+ "device\n");
+ goto err_deinit;
+ }
+
+ istallion_class = class_create(THIS_MODULE, "staliomem");
+ for (i = 0; i < 4; i++)
+ class_device_create(istallion_class, NULL,
+ MKDEV(STL_SIOMEMMAJOR, i),
+ NULL, "staliomem%d", i);
+
return 0;
+err_deinit:
+ pci_unregister_driver(&stli_pcidriver);
+ istallion_cleanup_isa();
+err_ttyunr:
+ tty_unregister_driver(stli_serial);
+err_ttyput:
+ put_tty_driver(stli_serial);
+err_free:
+ kfree(stli_txcookbuf);
+err:
+ return retval;
}
/*****************************************************************************/
+
+static void __exit istallion_module_exit(void)
+{
+ unsigned int j;
+
+ printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
+ stli_drvversion);
+
+ if (stli_timeron) {
+ stli_timeron = 0;
+ del_timer_sync(&stli_timerlist);
+ }
+
+ unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
+
+ for (j = 0; j < 4; j++)
+ class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR,
+ j));
+ class_destroy(istallion_class);
+
+ pci_unregister_driver(&stli_pcidriver);
+ istallion_cleanup_isa();
+
+ tty_unregister_driver(stli_serial);
+ put_tty_driver(stli_serial);
+
+ kfree(stli_txcookbuf);
+}
+
+module_init(istallion_module_init);
+module_exit(istallion_module_exit);
diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c
index da601fd6c07..d649abbf085 100644
--- a/drivers/char/lcd.c
+++ b/drivers/char/lcd.c
@@ -459,7 +459,7 @@ static int lcd_ioctl(struct inode *inode, struct file *file,
(&display, (struct lcd_display *) arg,
sizeof(struct lcd_display)))
return -EFAULT;
- rom = (unsigned char *) kmalloc((128), GFP_ATOMIC);
+ rom = kmalloc((128), GFP_ATOMIC);
if (rom == NULL) {
printk(KERN_ERR LCD "kmalloc() failed in %s\n",
__FUNCTION__);
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 1ecea7d448f..b51d08be0bc 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -296,7 +296,7 @@ static int lp_wait_ready(int minor, int nonblock)
static ssize_t lp_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
- unsigned int minor = iminor(file->f_dentry->d_inode);
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct parport *port = lp_table[minor].dev->port;
char *kbuf = lp_table[minor].lp_buffer;
ssize_t retv = 0;
@@ -415,7 +415,7 @@ static ssize_t lp_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
DEFINE_WAIT(wait);
- unsigned int minor=iminor(file->f_dentry->d_inode);
+ unsigned int minor=iminor(file->f_path.dentry->d_inode);
struct parport *port = lp_table[minor].dev->port;
ssize_t retval = 0;
char *kbuf = lp_table[minor].lp_buffer;
@@ -525,7 +525,7 @@ static int lp_open(struct inode * inode, struct file * file)
return -EIO;
}
}
- lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
+ lp_table[minor].lp_buffer = kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
if (!lp_table[minor].lp_buffer) {
LP_F(minor) &= ~LP_BUSY;
return -ENOMEM;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index e67eef4867b..f5c160caf9f 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -293,8 +293,8 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
{
unsigned long pfn;
- /* Turn a pfn offset into an absolute pfn */
- pfn = PFN_DOWN(virt_to_phys((void *)PAGE_OFFSET)) + vma->vm_pgoff;
+ /* Turn a kernel-virtual address into a physical page frame */
+ pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT;
/*
* RED-PEN: on some architectures there is more mapped memory
@@ -646,7 +646,8 @@ static inline size_t read_zero_pagealigned(char __user * buf, size_t size)
count = size;
zap_page_range(vma, addr, count, NULL);
- zeromap_page_range(vma, addr, count, PAGE_COPY);
+ if (zeromap_page_range(vma, addr, count, PAGE_COPY))
+ break;
size -= count;
buf += count;
@@ -713,11 +714,14 @@ out:
static int mmap_zero(struct file * file, struct vm_area_struct * vma)
{
+ int err;
+
if (vma->vm_flags & VM_SHARED)
return shmem_zero_setup(vma);
- if (zeromap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
- return -EAGAIN;
- return 0;
+ err = zeromap_page_range(vma, vma->vm_start,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot);
+ BUG_ON(err == -EEXIST);
+ return err;
}
#else /* CONFIG_MMU */
static ssize_t read_zero(struct file * file, char * buf,
@@ -774,7 +778,7 @@ static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
{
loff_t ret;
- mutex_lock(&file->f_dentry->d_inode->i_mutex);
+ mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
switch (orig) {
case 0:
file->f_pos = offset;
@@ -789,7 +793,7 @@ static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
default:
ret = -EINVAL;
}
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return ret;
}
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 8b316953173..f391a24a1b4 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -234,7 +234,7 @@ static void moxa_put_char(struct tty_struct *, unsigned char);
static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
static void moxa_throttle(struct tty_struct *);
static void moxa_unthrottle(struct tty_struct *);
-static void moxa_set_termios(struct tty_struct *, struct termios *);
+static void moxa_set_termios(struct tty_struct *, struct ktermios *);
static void moxa_stop(struct tty_struct *);
static void moxa_start(struct tty_struct *);
static void moxa_hangup(struct tty_struct *);
@@ -261,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 *, speed_t);
+static int MoxaPortSetTermio(int, struct ktermios *, speed_t);
static int MoxaPortGetLineOut(int, int *, int *);
static void MoxaPortLineCtrl(int, int, int);
static void MoxaPortFlowCtrl(int, int, int, int, int, int);
@@ -355,6 +355,8 @@ static int __init moxa_init(void)
moxaDriver->init_termios.c_oflag = 0;
moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
moxaDriver->init_termios.c_lflag = 0;
+ moxaDriver->init_termios.c_ispeed = 9600;
+ moxaDriver->init_termios.c_ospeed = 9600;
moxaDriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(moxaDriver, &moxa_ops);
@@ -864,7 +866,7 @@ static void moxa_unthrottle(struct tty_struct *tty)
}
static void moxa_set_termios(struct tty_struct *tty,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
@@ -978,7 +980,7 @@ static void moxa_poll(unsigned long ignored)
static void set_tty_param(struct tty_struct *tty)
{
- register struct termios *ts;
+ register struct ktermios *ts;
struct moxa_str *ch;
int rts, cts, txflow, rxflow, xany;
@@ -1149,7 +1151,7 @@ static void shut_down(struct moxa_str *ch)
static void receive_data(struct moxa_str *ch)
{
struct tty_struct *tp;
- struct termios *ts;
+ struct ktermios *ts;
unsigned long flags;
ts = NULL;
@@ -1912,9 +1914,9 @@ int MoxaPortsOfCard(int cardno)
*
* Function 12: Configure the port.
* Syntax:
- * int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud);
+ * int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud);
* int port : port number (0 - 127)
- * struct termios * termio : termio structure pointer
+ * struct ktermios * termio : termio structure pointer
* speed_t baud : baud rate
*
* return: -1 : this port is invalid or termio == NULL
@@ -2195,7 +2197,7 @@ long MoxaPortSetBaud(int port, long baud)
return (baud);
}
-int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud)
+int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
{
void __iomem *ofsAddr;
tcflag_t cflag;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 5ed2486b758..83f604b1929 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -328,8 +328,8 @@ struct mxser_struct {
int xmit_tail;
int xmit_cnt;
struct work_struct tqueue;
- struct termios normal_termios;
- struct termios callout_termios;
+ struct ktermios normal_termios;
+ struct ktermios callout_termios;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
wait_queue_head_t delta_msr_wait;
@@ -364,8 +364,8 @@ static int mxserBoardCAP[MXSER_BOARDS] = {
static struct tty_driver *mxvar_sdriver;
static struct mxser_struct mxvar_table[MXSER_PORTS];
static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];
-static struct termios *mxvar_termios[MXSER_PORTS + 1];
-static struct termios *mxvar_termios_locked[MXSER_PORTS + 1];
+static struct ktermios *mxvar_termios[MXSER_PORTS + 1];
+static struct ktermios *mxvar_termios_locked[MXSER_PORTS + 1];
static struct mxser_log mxvar_log;
static int mxvar_diagflag;
static unsigned char mxser_msr[MXSER_PORTS + 1];
@@ -402,7 +402,7 @@ static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong);
static int mxser_ioctl_special(unsigned int, void __user *);
static void mxser_throttle(struct tty_struct *);
static void mxser_unthrottle(struct tty_struct *);
-static void mxser_set_termios(struct tty_struct *, struct termios *);
+static void mxser_set_termios(struct tty_struct *, struct ktermios *);
static void mxser_stop(struct tty_struct *);
static void mxser_start(struct tty_struct *);
static void mxser_hangup(struct tty_struct *);
@@ -414,7 +414,7 @@ static void mxser_check_modem_status(struct mxser_struct *, int);
static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);
static int mxser_startup(struct mxser_struct *);
static void mxser_shutdown(struct mxser_struct *);
-static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios);
+static int mxser_change_speed(struct mxser_struct *, struct ktermios *old_termios);
static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct __user *);
static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct __user *);
static int mxser_get_lsr_info(struct mxser_struct *, unsigned int __user *);
@@ -515,6 +515,7 @@ static void __exit mxser_module_exit(void)
if (pdev != NULL) { /* PCI */
release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
+ pci_dev_put(pdev);
} else {
release_region(mxsercfg[i].ioaddr[0], 8 * mxsercfg[i].ports);
release_region(mxsercfg[i].vector, 1);
@@ -556,7 +557,7 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
n = board * MXSER_PORTS_PER_BOARD;
info = &mxvar_table[n];
/*if (verbose) */ {
- printk(KERN_DEBUG " ttyM%d - ttyM%d ",
+ printk(KERN_DEBUG " ttyMI%d - ttyMI%d ",
n, n + hwconf->ports - 1);
printk(" max. baud rate = %d bps.\n",
hwconf->MaxCanSetBaudRate[0]);
@@ -716,8 +717,9 @@ static int mxser_init(void)
/* Initialize the tty_driver structure */
memset(mxvar_sdriver, 0, sizeof(struct tty_driver));
+ mxvar_sdriver->owner = THIS_MODULE;
mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
- mxvar_sdriver->name = "ttyM";
+ mxvar_sdriver->name = "ttyMI";
mxvar_sdriver->major = ttymajor;
mxvar_sdriver->minor_start = 0;
mxvar_sdriver->num = MXSER_PORTS + 1;
@@ -725,6 +727,8 @@ static int mxser_init(void)
mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
mxvar_sdriver->init_termios = tty_std_termios;
mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
+ mxvar_sdriver->init_termios.c_ispeed = 9600;
+ mxvar_sdriver->init_termios.c_ospeed = 9600;
mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(mxvar_sdriver, &mxser_ops);
mxvar_sdriver->ttys = mxvar_tty;
@@ -839,9 +843,9 @@ static int mxser_init(void)
index = 0;
b = 0;
while (b < n) {
- pdev = pci_find_device(mxser_pcibrds[b].vendor,
+ pdev = pci_get_device(mxser_pcibrds[b].vendor,
mxser_pcibrds[b].device, pdev);
- if (pdev == NULL) {
+ if (pdev == NULL) {
b++;
continue;
}
@@ -893,6 +897,9 @@ static int mxser_init(void)
if (mxser_initbrd(m, &hwconf) < 0)
continue;
m++;
+ /* Keep an extra reference if we succeeded. It will
+ be returned at unload time */
+ pci_dev_get(pdev);
}
}
#endif
@@ -994,7 +1001,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
mxser_change_speed(info, NULL);
}
- info->session = current->signal->session;
+ info->session = process_session(current);
info->pgrp = process_group(current);
/*
@@ -1745,7 +1752,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
/* MX_UNLOCK(&info->slock); */
}
-static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct mxser_struct *info = tty->driver_data;
unsigned long flags;
@@ -2537,7 +2544,7 @@ static void mxser_shutdown(struct mxser_struct *info)
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
-static int mxser_change_speed(struct mxser_struct *info, struct termios *old_termios)
+static int mxser_change_speed(struct mxser_struct *info, struct ktermios *old_termios)
{
unsigned cflag, cval, fcr;
int ret = 0;
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c
new file mode 100644
index 00000000000..1bb030b3a51
--- /dev/null
+++ b/drivers/char/mxser_new.c
@@ -0,0 +1,2813 @@
+/*
+ * mxser.c -- MOXA Smartio/Industio family multiport serial driver.
+ *
+ * Copyright (C) 1999-2006 Moxa Technologies (support@moxa.com.tw).
+ * Copyright (C) 2006 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * This code is loosely based on the 1.8 moxa driver which is based on
+ * Linux serial driver, written by Linus Torvalds, Theodore T'so and
+ * others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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.
+ *
+ * Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox
+ * <alan@redhat.com>. The original 1.8 code is available on www.moxa.com.
+ * - Fixed x86_64 cleanness
+ * - Fixed sleep with spinlock held in mxser_send_break
+ */
+
+#include <linux/module.h>
+#include <linux/autoconf.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>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/gfp.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+#include "mxser_new.h"
+
+#define MXSER_VERSION "2.0"
+#define MXSERMAJOR 174
+#define MXSERCUMAJOR 175
+
+#define MXSER_EVENT_TXLOW 1
+
+#define MXSER_BOARDS 4 /* Max. boards */
+#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */
+#define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
+#define MXSER_ISR_PASS_LIMIT 99999L
+
+#define MXSER_ERR_IOADDR -1
+#define MXSER_ERR_IRQ -2
+#define MXSER_ERR_IRQ_CONFLIT -3
+#define MXSER_ERR_VECTOR -4
+
+#define WAKEUP_CHARS 256
+
+#define UART_MCR_AFE 0x20
+#define UART_LSR_SPECIAL 0x1E
+
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\
+ IXON|IXOFF))
+
+#define C168_ASIC_ID 1
+#define C104_ASIC_ID 2
+#define C102_ASIC_ID 0xB
+#define CI132_ASIC_ID 4
+#define CI134_ASIC_ID 3
+#define CI104J_ASIC_ID 5
+
+#define MXSER_HIGHBAUD 1
+#define MXSER_HAS2 2
+
+/* This is only for PCI */
+static const struct {
+ int type;
+ int tx_fifo;
+ int rx_fifo;
+ int xmit_fifo_size;
+ int rx_high_water;
+ int rx_trigger;
+ int rx_low_water;
+ long max_baud;
+} Gpci_uart_info[] = {
+ {MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L},
+ {MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L},
+ {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L}
+};
+#define UART_INFO_NUM ARRAY_SIZE(Gpci_uart_info)
+
+struct mxser_cardinfo {
+ unsigned int nports;
+ char *name;
+ unsigned int flags;
+};
+
+static const struct mxser_cardinfo mxser_cards[] = {
+ { 8, "C168 series", }, /* C168-ISA */
+ { 4, "C104 series", }, /* C104-ISA */
+ { 4, "CI-104J series", }, /* CI104J */
+ { 8, "C168H/PCI series", }, /* C168-PCI */
+ { 4, "C104H/PCI series", }, /* C104-PCI */
+ { 4, "C102 series", MXSER_HAS2 }, /* C102-ISA */
+ { 4, "CI-132 series", MXSER_HAS2 }, /* CI132 */
+ { 4, "CI-134 series", }, /* CI134 */
+ { 2, "CP-132 series", }, /* CP132 */
+ { 4, "CP-114 series", }, /* CP114 */
+ { 4, "CT-114 series", }, /* CT114 */
+ { 2, "CP-102 series", MXSER_HIGHBAUD }, /* CP102 */
+ { 4, "CP-104U series", }, /* CP104U */
+ { 8, "CP-168U series", }, /* CP168U */
+ { 2, "CP-132U series", }, /* CP132U */
+ { 4, "CP-134U series", }, /* CP134U */
+ { 4, "CP-104JU series", }, /* CP104JU */
+ { 8, "Moxa UC7000 Serial", }, /* RC7000 */
+ { 8, "CP-118U series", }, /* CP118U */
+ { 2, "CP-102UL series", }, /* CP102UL */
+ { 2, "CP-102U series", }, /* CP102U */
+ { 8, "CP-118EL series", }, /* CP118EL */
+ { 8, "CP-168EL series", }, /* CP168EL */
+ { 4, "CP-104EL series", } /* CP104EL */
+};
+
+/* driver_data correspond to the lines in the structure above
+ see also ISA probe function before you change something */
+static struct pci_device_id mxser_pcibrds[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168),
+ .driver_data = 3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104),
+ .driver_data = 4 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132),
+ .driver_data = 8 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114),
+ .driver_data = 9 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114),
+ .driver_data = 10 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102),
+ .driver_data = 11 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U),
+ .driver_data = 12 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U),
+ .driver_data = 13 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U),
+ .driver_data = 14 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U),
+ .driver_data = 15 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU),
+ .driver_data = 16 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000),
+ .driver_data = 17 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U),
+ .driver_data = 18 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL),
+ .driver_data = 19 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U),
+ .driver_data = 20 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL),
+ .driver_data = 21 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL),
+ .driver_data = 22 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL),
+ .driver_data = 23 },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
+
+static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
+static int ttymajor = MXSERMAJOR;
+static int calloutmajor = MXSERCUMAJOR;
+
+/* Variables for insmod */
+
+MODULE_AUTHOR("Casper Yang");
+MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
+module_param_array(ioaddr, int, NULL, 0);
+module_param(ttymajor, int, 0);
+MODULE_LICENSE("GPL");
+
+struct mxser_log {
+ int tick;
+ unsigned long rxcnt[MXSER_PORTS];
+ unsigned long txcnt[MXSER_PORTS];
+};
+
+
+struct mxser_mon {
+ unsigned long rxcnt;
+ unsigned long txcnt;
+ unsigned long up_rxcnt;
+ unsigned long up_txcnt;
+ int modem_status;
+ unsigned char hold_reason;
+};
+
+struct mxser_mon_ext {
+ unsigned long rx_cnt[32];
+ unsigned long tx_cnt[32];
+ unsigned long up_rxcnt[32];
+ unsigned long up_txcnt[32];
+ int modem_status[32];
+
+ long baudrate[32];
+ int databits[32];
+ int stopbits[32];
+ int parity[32];
+ int flowctrl[32];
+ int fifo[32];
+ int iftype[32];
+};
+
+struct mxser_board;
+
+struct mxser_port {
+ struct mxser_board *board;
+ struct tty_struct *tty;
+
+ unsigned long ioaddr;
+ unsigned long opmode_ioaddr;
+ int max_baud;
+
+ int rx_high_water;
+ int rx_trigger; /* Rx fifo trigger level */
+ int rx_low_water;
+ int baud_base; /* max. speed */
+ long realbaud;
+ int type; /* UART type */
+ int flags; /* defined in tty.h */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+
+ int x_char; /* xon/xoff character */
+ int IER; /* Interrupt Enable Register */
+ int MCR; /* Modem control register */
+
+ unsigned char stop_rx;
+ unsigned char ldisc_stop_rx;
+
+ int custom_divisor;
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned char err_shadow;
+ unsigned long event;
+
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ struct async_icount icount; /* kernel counters for 4 input interrupts */
+ int timeout;
+
+ int read_status_mask;
+ int ignore_status_mask;
+ int xmit_fifo_size;
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+
+ struct ktermios normal_termios;
+ struct ktermios callout_termios;
+
+ struct mxser_mon mon_data;
+
+ spinlock_t slock;
+ struct work_struct tqueue;
+ wait_queue_head_t open_wait;
+ wait_queue_head_t close_wait;
+ wait_queue_head_t delta_msr_wait;
+};
+
+struct mxser_board {
+ unsigned int idx;
+ int irq;
+ const struct mxser_cardinfo *info;
+ unsigned long vector;
+ unsigned long vector_mask;
+
+ int chip_flag;
+ int uart_type;
+
+ struct mxser_port ports[MXSER_PORTS_PER_BOARD];
+};
+
+struct mxser_mstatus {
+ tcflag_t cflag;
+ int cts;
+ int dsr;
+ int ri;
+ int dcd;
+};
+
+static struct mxser_mstatus GMStatus[MXSER_PORTS];
+
+static int mxserBoardCAP[MXSER_BOARDS] = {
+ 0, 0, 0, 0
+ /* 0x180, 0x280, 0x200, 0x320 */
+};
+
+static struct mxser_board mxser_boards[MXSER_BOARDS];
+static struct tty_driver *mxvar_sdriver;
+static struct mxser_log mxvar_log;
+static int mxvar_diagflag;
+static unsigned char mxser_msr[MXSER_PORTS + 1];
+static struct mxser_mon_ext mon_data_ext;
+static int mxser_set_baud_method[MXSER_PORTS + 1];
+static spinlock_t gm_lock;
+
+#ifdef CONFIG_PCI
+static int CheckIsMoxaMust(int io)
+{
+ u8 oldmcr, hwid;
+ int i;
+
+ outb(0, io + UART_LCR);
+ DISABLE_MOXA_MUST_ENCHANCE_MODE(io);
+ oldmcr = inb(io + UART_MCR);
+ outb(0, io + UART_MCR);
+ SET_MOXA_MUST_XON1_VALUE(io, 0x11);
+ if ((hwid = inb(io + UART_MCR)) != 0) {
+ outb(oldmcr, io + UART_MCR);
+ return MOXA_OTHER_UART;
+ }
+
+ GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
+ for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
+ if (hwid == Gpci_uart_info[i].type)
+ return (int)hwid;
+ }
+ return MOXA_OTHER_UART;
+}
+#endif
+
+static void process_txrx_fifo(struct mxser_port *info)
+{
+ int i;
+
+ if ((info->type == PORT_16450) || (info->type == PORT_8250)) {
+ info->rx_trigger = 1;
+ info->rx_high_water = 1;
+ info->rx_low_water = 1;
+ info->xmit_fifo_size = 1;
+ } else
+ for (i = 0; i < UART_INFO_NUM; i++)
+ if (info->board->chip_flag == Gpci_uart_info[i].type) {
+ info->rx_trigger = Gpci_uart_info[i].rx_trigger;
+ info->rx_low_water = Gpci_uart_info[i].rx_low_water;
+ info->rx_high_water = Gpci_uart_info[i].rx_high_water;
+ info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size;
+ break;
+ }
+}
+
+static void mxser_do_softint(struct work_struct *work)
+{
+ struct mxser_port *info = container_of(work, struct mxser_port, tqueue);
+ struct tty_struct *tty = info->tty;
+
+ if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event))
+ tty_wakeup(tty);
+}
+
+static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
+{
+ unsigned char status = 0;
+
+ status = inb(baseaddr + UART_MSR);
+
+ mxser_msr[port] &= 0x0F;
+ mxser_msr[port] |= status;
+ status = mxser_msr[port];
+ if (mode)
+ mxser_msr[port] = 0;
+
+ return status;
+}
+
+static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct mxser_port *port)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int retval;
+ int do_clocal = 0;
+ unsigned long flags;
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ test_bit(TTY_IO_ERROR, &tty->flags)) {
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, port->count is dropped by one, so that
+ * mxser_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&port->open_wait, &wait);
+
+ spin_lock_irqsave(&port->slock, flags);
+ if (!tty_hung_up_p(filp))
+ port->count--;
+ spin_unlock_irqrestore(&port->slock, flags);
+ port->blocked_open++;
+ while (1) {
+ spin_lock_irqsave(&port->slock, flags);
+ outb(inb(port->ioaddr + UART_MCR) |
+ UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR);
+ spin_unlock_irqrestore(&port->slock, flags);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
+ if (port->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+ break;
+ }
+ if (!(port->flags & ASYNC_CLOSING) &&
+ (do_clocal ||
+ (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD)))
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&port->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ port->count++;
+ port->blocked_open--;
+ if (retval)
+ return retval;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+}
+
+static int mxser_set_baud(struct mxser_port *info, long newspd)
+{
+ int quot = 0;
+ unsigned char cval;
+ int ret = 0;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return ret;
+
+ if (!(info->ioaddr))
+ return ret;
+
+ if (newspd > info->max_baud)
+ return 0;
+
+ info->realbaud = newspd;
+ if (newspd == 134) {
+ quot = (2 * info->baud_base / 269);
+ } else if (newspd) {
+ quot = info->baud_base / newspd;
+ if (quot == 0)
+ quot = 1;
+ } else {
+ quot = 0;
+ }
+
+ info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
+ info->timeout += HZ / 50; /* Add .02 seconds of slop */
+
+ if (quot) {
+ spin_lock_irqsave(&info->slock, flags);
+ info->MCR |= UART_MCR_DTR;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ } else {
+ spin_lock_irqsave(&info->slock, flags);
+ info->MCR &= ~UART_MCR_DTR;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return ret;
+ }
+
+ cval = inb(info->ioaddr + UART_LCR);
+
+ outb(cval | UART_LCR_DLAB, info->ioaddr + UART_LCR); /* set DLAB */
+
+ outb(quot & 0xff, info->ioaddr + UART_DLL); /* LS of divisor */
+ outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */
+ outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */
+
+
+ return ret;
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static int mxser_change_speed(struct mxser_port *info,
+ struct ktermios *old_termios)
+{
+ unsigned cflag, cval, fcr;
+ int ret = 0;
+ unsigned char status;
+ long baud;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return ret;
+ cflag = info->tty->termios->c_cflag;
+ if (!(info->ioaddr))
+ return ret;
+
+ if (mxser_set_baud_method[info->tty->index] == 0) {
+ baud = tty_get_baud_rate(info->tty);
+ mxser_set_baud(info, baud);
+ }
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ cval = 0x00;
+ break;
+ case CS6:
+ cval = 0x01;
+ break;
+ case CS7:
+ cval = 0x02;
+ break;
+ case CS8:
+ cval = 0x03;
+ break;
+ default:
+ cval = 0x00;
+ break; /* too keep GCC shut... */
+ }
+ if (cflag & CSTOPB)
+ cval |= 0x04;
+ if (cflag & PARENB)
+ cval |= UART_LCR_PARITY;
+ if (!(cflag & PARODD))
+ cval |= UART_LCR_EPAR;
+ if (cflag & CMSPAR)
+ cval |= UART_LCR_SPAR;
+
+ if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
+ if (info->board->chip_flag) {
+ fcr = UART_FCR_ENABLE_FIFO;
+ fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
+ SET_MOXA_MUST_FIFO_VALUE(info);
+ } else
+ fcr = 0;
+ } else {
+ fcr = UART_FCR_ENABLE_FIFO;
+ if (info->board->chip_flag) {
+ fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
+ SET_MOXA_MUST_FIFO_VALUE(info);
+ } else {
+ switch (info->rx_trigger) {
+ case 1:
+ fcr |= UART_FCR_TRIGGER_1;
+ break;
+ case 4:
+ fcr |= UART_FCR_TRIGGER_4;
+ break;
+ case 8:
+ fcr |= UART_FCR_TRIGGER_8;
+ break;
+ default:
+ fcr |= UART_FCR_TRIGGER_14;
+ break;
+ }
+ }
+ }
+
+ /* CTS flow control flag and modem status interrupts */
+ info->IER &= ~UART_IER_MSI;
+ info->MCR &= ~UART_MCR_AFE;
+ if (cflag & CRTSCTS) {
+ info->flags |= ASYNC_CTS_FLOW;
+ info->IER |= UART_IER_MSI;
+ if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
+ info->MCR |= UART_MCR_AFE;
+ } else {
+ status = inb(info->ioaddr + UART_MSR);
+ if (info->tty->hw_stopped) {
+ if (status & UART_MSR_CTS) {
+ info->tty->hw_stopped = 0;
+ if (info->type != PORT_16550A &&
+ !info->board->chip_flag) {
+ outb(info->IER & ~UART_IER_THRI,
+ info->ioaddr +
+ UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr +
+ UART_IER);
+ }
+ set_bit(MXSER_EVENT_TXLOW, &info->event);
+ schedule_work(&info->tqueue); }
+ } else {
+ if (!(status & UART_MSR_CTS)) {
+ info->tty->hw_stopped = 1;
+ if ((info->type != PORT_16550A) &&
+ (!info->board->chip_flag)) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->ioaddr +
+ UART_IER);
+ }
+ }
+ }
+ }
+ } else {
+ info->flags &= ~ASYNC_CTS_FLOW;
+ }
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ if (cflag & CLOCAL) {
+ info->flags &= ~ASYNC_CHECK_CD;
+ } else {
+ info->flags |= ASYNC_CHECK_CD;
+ info->IER |= UART_IER_MSI;
+ }
+ outb(info->IER, info->ioaddr + UART_IER);
+
+ /*
+ * Set up parity check flag
+ */
+ info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ info->read_status_mask |= UART_LSR_BI;
+
+ info->ignore_status_mask = 0;
+
+ if (I_IGNBRK(info->tty)) {
+ info->ignore_status_mask |= UART_LSR_BI;
+ info->read_status_mask |= UART_LSR_BI;
+ /*
+ * If we're ignore parity and break indicators, ignore
+ * overruns too. (For real raw support).
+ */
+ if (I_IGNPAR(info->tty)) {
+ info->ignore_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
+ info->read_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
+ }
+ }
+ if (info->board->chip_flag) {
+ spin_lock_irqsave(&info->slock, flags);
+ SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
+ SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty));
+ if (I_IXON(info->tty)) {
+ ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ } else {
+ DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ }
+ if (I_IXOFF(info->tty)) {
+ ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ } else {
+ DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ }
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+
+
+ outb(fcr, info->ioaddr + UART_FCR); /* set fcr */
+ outb(cval, info->ioaddr + UART_LCR);
+
+ return ret;
+}
+
+static void mxser_check_modem_status(struct mxser_port *port, int status)
+{
+ /* update input line counters */
+ if (status & UART_MSR_TERI)
+ port->icount.rng++;
+ if (status & UART_MSR_DDSR)
+ port->icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ port->icount.dcd++;
+ if (status & UART_MSR_DCTS)
+ port->icount.cts++;
+ port->mon_data.modem_status = status;
+ wake_up_interruptible(&port->delta_msr_wait);
+
+ if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+ if (status & UART_MSR_DCD)
+ wake_up_interruptible(&port->open_wait);
+ schedule_work(&port->tqueue);
+ }
+
+ if (port->flags & ASYNC_CTS_FLOW) {
+ if (port->tty->hw_stopped) {
+ if (status & UART_MSR_CTS) {
+ port->tty->hw_stopped = 0;
+
+ if ((port->type != PORT_16550A) &&
+ (!port->board->chip_flag)) {
+ outb(port->IER & ~UART_IER_THRI,
+ port->ioaddr + UART_IER);
+ port->IER |= UART_IER_THRI;
+ outb(port->IER, port->ioaddr +
+ UART_IER);
+ }
+ set_bit(MXSER_EVENT_TXLOW, &port->event);
+ schedule_work(&port->tqueue);
+ }
+ } else {
+ if (!(status & UART_MSR_CTS)) {
+ port->tty->hw_stopped = 1;
+ if (port->type != PORT_16550A &&
+ !port->board->chip_flag) {
+ port->IER &= ~UART_IER_THRI;
+ outb(port->IER, port->ioaddr +
+ UART_IER);
+ }
+ }
+ }
+ }
+}
+
+static int mxser_startup(struct mxser_port *info)
+{
+ unsigned long page;
+ unsigned long flags;
+
+ page = __get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+ }
+
+ if (!info->ioaddr || !info->type) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ free_page(page);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+ }
+ if (info->xmit_buf)
+ free_page(page);
+ else
+ info->xmit_buf = (unsigned char *) page;
+
+ /*
+ * Clear the FIFO buffers and disable them
+ * (they will be reenabled in mxser_change_speed())
+ */
+ if (info->board->chip_flag)
+ outb((UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR);
+ else
+ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->ioaddr + UART_FCR);
+
+ /*
+ * At this point there's no way the LSR could still be 0xFF;
+ * if it is, then bail out, because there's likely no UART
+ * here.
+ */
+ if (inb(info->ioaddr + UART_LSR) == 0xff) {
+ spin_unlock_irqrestore(&info->slock, flags);
+ if (capable(CAP_SYS_ADMIN)) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ return 0;
+ } else
+ return -ENODEV;
+ }
+
+ /*
+ * Clear the interrupt registers.
+ */
+ (void) inb(info->ioaddr + UART_LSR);
+ (void) inb(info->ioaddr + UART_RX);
+ (void) inb(info->ioaddr + UART_IIR);
+ (void) inb(info->ioaddr + UART_MSR);
+
+ /*
+ * Now, initialize the UART
+ */
+ outb(UART_LCR_WLEN8, info->ioaddr + UART_LCR); /* reset DLAB */
+ info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+
+ /*
+ * Finally, enable interrupts
+ */
+ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+
+ if (info->board->chip_flag)
+ info->IER |= MOXA_MUST_IER_EGDAI;
+ outb(info->IER, info->ioaddr + UART_IER); /* enable interrupts */
+
+ /*
+ * And clear the interrupt registers again for luck.
+ */
+ (void) inb(info->ioaddr + UART_LSR);
+ (void) inb(info->ioaddr + UART_RX);
+ (void) inb(info->ioaddr + UART_IIR);
+ (void) inb(info->ioaddr + UART_MSR);
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ /*
+ * and set the speed of the serial port
+ */
+ spin_unlock_irqrestore(&info->slock, flags);
+ mxser_change_speed(info, NULL);
+
+ info->flags |= ASYNC_INITIALIZED;
+ return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts maybe disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void mxser_shutdown(struct mxser_port *info)
+{
+ unsigned long flags;
+
+ if (!(info->flags & ASYNC_INITIALIZED))
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ /*
+ * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+ * here so the queue might never be waken up
+ */
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ /*
+ * Free the IRQ, if necessary
+ */
+ if (info->xmit_buf) {
+ free_page((unsigned long) info->xmit_buf);
+ info->xmit_buf = NULL;
+ }
+
+ info->IER = 0;
+ outb(0x00, info->ioaddr + UART_IER);
+
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+ info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
+ outb(info->MCR, info->ioaddr + UART_MCR);
+
+ /* clear Rx/Tx FIFO's */
+ if (info->board->chip_flag)
+ outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE,
+ info->ioaddr + UART_FCR);
+ else
+ outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+ info->ioaddr + UART_FCR);
+
+ /* read data port to reset things */
+ (void) inb(info->ioaddr + UART_RX);
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+
+ if (info->board->chip_flag)
+ SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int mxser_open(struct tty_struct *tty, struct file *filp)
+{
+ struct mxser_port *info;
+ int retval, line;
+
+ /* initialize driver_data in case something fails */
+ tty->driver_data = NULL;
+
+ line = tty->index;
+ if (line == MXSER_PORTS)
+ return 0;
+ if (line < 0 || line > MXSER_PORTS)
+ return -ENODEV;
+ info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
+ if (!info->ioaddr)
+ return -ENODEV;
+
+ tty->driver_data = info;
+ info->tty = tty;
+ /*
+ * Start up serial port
+ */
+ info->count++;
+ retval = mxser_startup(info);
+ if (retval)
+ return retval;
+
+ retval = mxser_block_til_ready(tty, filp, info);
+ if (retval)
+ return retval;
+
+ if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ mxser_change_speed(info, NULL);
+ }
+
+ info->session = process_session(current);
+ info->pgrp = process_group(current);
+
+ /* unmark here for very high baud rate (ex. 921600 bps) used */
+ tty->low_latency = 1;
+ return 0;
+}
+
+/*
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ */
+static void mxser_close(struct tty_struct *tty, struct file *filp)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ unsigned long timeout;
+ unsigned long flags;
+
+ if (tty->index == MXSER_PORTS)
+ return;
+ if (!info)
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ if (tty_hung_up_p(filp)) {
+ spin_unlock_irqrestore(&info->slock, flags);
+ return;
+ }
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk(KERN_ERR "mxser_close: bad serial port count; "
+ "tty->count is 1, info->count is %d\n", info->count);
+ info->count = 1;
+ }
+ if (--info->count < 0) {
+ printk(KERN_ERR "mxser_close: bad serial port count for "
+ "ttys%d: %d\n", tty->index, info->count);
+ info->count = 0;
+ }
+ if (info->count) {
+ spin_unlock_irqrestore(&info->slock, flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+ spin_unlock_irqrestore(&info->slock, flags);
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ info->normal_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait);
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receive line status interrupts, and tell the
+ * interrupt driver to stop checking the data ready bit in the
+ * line status register.
+ */
+ info->IER &= ~UART_IER_RLSI;
+ if (info->board->chip_flag)
+ info->IER &= ~MOXA_MUST_RECV_ISR;
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ outb(info->IER, info->ioaddr + UART_IER);
+ /*
+ * Before we drop DTR, make sure the UART transmitter
+ * has completely drained; this is especially
+ * important if there is a transmit FIFO!
+ */
+ timeout = jiffies + HZ;
+ while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
+ schedule_timeout_interruptible(5);
+ if (time_after(jiffies, timeout))
+ break;
+ }
+ }
+ mxser_shutdown(info);
+
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+
+ tty_ldisc_flush(tty);
+
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = NULL;
+ if (info->blocked_open) {
+ if (info->close_delay)
+ schedule_timeout_interruptible(info->close_delay);
+ wake_up_interruptible(&info->open_wait);
+ }
+
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+
+}
+
+static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+ int c, total = 0;
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ if (!info->xmit_buf)
+ return 0;
+
+ while (1) {
+ c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_head = (info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE - 1);
+ info->xmit_cnt += c;
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ buf += c;
+ count -= c;
+ total += c;
+ }
+
+ if (info->xmit_cnt && !tty->stopped) {
+ if (!tty->hw_stopped ||
+ (info->type == PORT_16550A) ||
+ (info->board->chip_flag)) {
+ spin_lock_irqsave(&info->slock, flags);
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr +
+ UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+ }
+ return total;
+}
+
+static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ if (!info->xmit_buf)
+ return;
+
+ if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_buf[info->xmit_head++] = ch;
+ info->xmit_head &= SERIAL_XMIT_SIZE - 1;
+ info->xmit_cnt++;
+ spin_unlock_irqrestore(&info->slock, flags);
+ if (!tty->stopped) {
+ if (!tty->hw_stopped ||
+ (info->type == PORT_16550A) ||
+ info->board->chip_flag) {
+ spin_lock_irqsave(&info->slock, flags);
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+ }
+}
+
+
+static void mxser_flush_chars(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ if (info->xmit_cnt <= 0 ||
+ tty->stopped ||
+ !info->xmit_buf ||
+ (tty->hw_stopped &&
+ (info->type != PORT_16550A) &&
+ (!info->board->chip_flag)
+ ))
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static int mxser_write_room(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ int ret;
+
+ ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return ret;
+}
+
+static int mxser_chars_in_buffer(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ return info->xmit_cnt;
+}
+
+static void mxser_flush_buffer(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ char fcr;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ fcr = inb(info->ioaddr + UART_FCR);
+ outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->ioaddr + UART_FCR);
+ outb(fcr, info->ioaddr + UART_FCR);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ tty_wakeup(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * friends of mxser_ioctl()
+ * ------------------------------------------------------------
+ */
+static int mxser_get_serial_info(struct mxser_port *info,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->tty->index;
+ tmp.port = info->ioaddr;
+ tmp.irq = info->board->irq;
+ tmp.flags = info->flags;
+ tmp.baud_base = info->baud_base;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+ tmp.custom_divisor = info->custom_divisor;
+ tmp.hub6 = 0;
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int mxser_set_serial_info(struct mxser_port *info,
+ struct serial_struct __user *new_info)
+{
+ struct serial_struct new_serial;
+ unsigned int flags;
+ int retval = 0;
+
+ if (!new_info || !info->ioaddr)
+ return -EFAULT;
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ return -EFAULT;
+
+ if ((new_serial.irq != info->board->irq) ||
+ (new_serial.port != info->ioaddr) ||
+ (new_serial.custom_divisor != info->custom_divisor) ||
+ (new_serial.baud_base != info->baud_base))
+ return -EPERM;
+
+ flags = info->flags & ASYNC_SPD_MASK;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if ((new_serial.baud_base != info->baud_base) ||
+ (new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ } else {
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+ info->flags = ((info->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
+ info->close_delay = new_serial.close_delay * HZ / 100;
+ info->closing_wait = new_serial.closing_wait * HZ / 100;
+ info->tty->low_latency =
+ (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ info->tty->low_latency = 0;
+ }
+
+ info->type = new_serial.type;
+
+ process_txrx_fifo(info);
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ if (flags != (info->flags & ASYNC_SPD_MASK))
+ mxser_change_speed(info, NULL);
+ } else
+ retval = mxser_startup(info);
+
+ return retval;
+}
+
+/*
+ * mxser_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 mxser_get_lsr_info(struct mxser_port *info,
+ unsigned int __user *value)
+{
+ unsigned char status;
+ unsigned int result;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ status = inb(info->ioaddr + UART_LSR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+ return put_user(result, value);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void mxser_send_break(struct mxser_port *info, int duration)
+{
+ unsigned long flags;
+
+ if (!info->ioaddr)
+ return;
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&info->slock, flags);
+ outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ schedule_timeout(duration);
+ spin_lock_irqsave(&info->slock, flags);
+ outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned char control, status;
+ unsigned long flags;
+
+
+ if (tty->index == MXSER_PORTS)
+ return -ENOIOCTLCMD;
+ if (test_bit(TTY_IO_ERROR, &tty->flags))
+ return -EIO;
+
+ control = info->MCR;
+
+ spin_lock_irqsave(&info->slock, flags);
+ status = inb(info->ioaddr + UART_MSR);
+ if (status & UART_MSR_ANY_DELTA)
+ mxser_check_modem_status(info, status);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
+ ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
+ ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
+ ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
+ ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
+ ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+}
+
+static int mxser_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+
+ if (tty->index == MXSER_PORTS)
+ return -ENOIOCTLCMD;
+ if (test_bit(TTY_IO_ERROR, &tty->flags))
+ return -EIO;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ if (set & TIOCM_RTS)
+ info->MCR |= UART_MCR_RTS;
+ if (set & TIOCM_DTR)
+ info->MCR |= UART_MCR_DTR;
+
+ if (clear & TIOCM_RTS)
+ info->MCR &= ~UART_MCR_RTS;
+ if (clear & TIOCM_DTR)
+ info->MCR &= ~UART_MCR_DTR;
+
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+}
+
+static int mxser_program_mode(int port)
+{
+ int id, i, j, n;
+
+ spin_lock(&gm_lock);
+ outb(0, port);
+ outb(0, port);
+ outb(0, port);
+ (void)inb(port);
+ (void)inb(port);
+ outb(0, port);
+ (void)inb(port);
+ spin_unlock(&gm_lock);
+
+ id = inb(port + 1) & 0x1F;
+ if ((id != C168_ASIC_ID) &&
+ (id != C104_ASIC_ID) &&
+ (id != C102_ASIC_ID) &&
+ (id != CI132_ASIC_ID) &&
+ (id != CI134_ASIC_ID) &&
+ (id != CI104J_ASIC_ID))
+ return -1;
+ for (i = 0, j = 0; i < 4; i++) {
+ n = inb(port + 2);
+ if (n == 'M') {
+ j = 1;
+ } else if ((j == 1) && (n == 1)) {
+ j = 2;
+ break;
+ } else
+ j = 0;
+ }
+ if (j != 2)
+ id = -2;
+ return id;
+}
+
+static void mxser_normal_mode(int port)
+{
+ int i, n;
+
+ outb(0xA5, port + 1);
+ outb(0x80, port + 3);
+ outb(12, port + 0); /* 9600 bps */
+ outb(0, port + 1);
+ outb(0x03, port + 3); /* 8 data bits */
+ outb(0x13, port + 4); /* loop back mode */
+ for (i = 0; i < 16; i++) {
+ n = inb(port + 5);
+ if ((n & 0x61) == 0x60)
+ break;
+ if ((n & 1) == 1)
+ (void)inb(port);
+ }
+ outb(0x00, port + 4);
+}
+
+#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */
+#define CHIP_DO 0x02 /* Serial Data Output in Eprom */
+#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */
+#define CHIP_DI 0x08 /* Serial Data Input in Eprom */
+#define EN_CCMD 0x000 /* Chip's command register */
+#define EN0_RSARLO 0x008 /* Remote start address reg 0 */
+#define EN0_RSARHI 0x009 /* Remote start address reg 1 */
+#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */
+#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */
+#define EN0_DCFG 0x00E /* Data configuration reg WR */
+#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */
+#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */
+#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */
+static int mxser_read_register(int port, unsigned short *regs)
+{
+ int i, k, value, id;
+ unsigned int j;
+
+ id = mxser_program_mode(port);
+ if (id < 0)
+ return id;
+ for (i = 0; i < 14; i++) {
+ k = (i & 0x3F) | 0x180;
+ for (j = 0x100; j > 0; j >>= 1) {
+ outb(CHIP_CS, port);
+ if (k & j) {
+ outb(CHIP_CS | CHIP_DO, port);
+ outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */
+ } else {
+ outb(CHIP_CS, port);
+ outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */
+ }
+ }
+ (void)inb(port);
+ value = 0;
+ for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
+ outb(CHIP_CS, port);
+ outb(CHIP_CS | CHIP_SK, port);
+ if (inb(port) & CHIP_DI)
+ value |= j;
+ }
+ regs[i] = value;
+ outb(0, port);
+ }
+ mxser_normal_mode(port);
+ return id;
+}
+
+static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
+{
+ struct mxser_port *port;
+ int result, status;
+ unsigned int i, j;
+
+ switch (cmd) {
+ case MOXA_GET_CONF:
+/* if (copy_to_user(argp, mxsercfg,
+ sizeof(struct mxser_hwconf) * 4))
+ return -EFAULT;
+ return 0;*/
+ return -ENXIO;
+ case MOXA_GET_MAJOR:
+ if (copy_to_user(argp, &ttymajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
+
+ case MOXA_GET_CUMAJOR:
+ if (copy_to_user(argp, &calloutmajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
+
+ case MOXA_CHKPORTENABLE:
+ result = 0;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
+ if (mxser_boards[i].ports[j].ioaddr)
+ result |= (1 << i);
+
+ return put_user(result, (unsigned long __user *)argp);
+ case MOXA_GETDATACOUNT:
+ if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
+ return -EFAULT;
+ return 0;
+ case MOXA_GETMSTATUS:
+ for (i = 0; i < MXSER_BOARDS; i++)
+ for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
+ port = &mxser_boards[i].ports[j];
+
+ GMStatus[i].ri = 0;
+ if (!port->ioaddr) {
+ GMStatus[i].dcd = 0;
+ GMStatus[i].dsr = 0;
+ GMStatus[i].cts = 0;
+ continue;
+ }
+
+ if (!port->tty || !port->tty->termios)
+ GMStatus[i].cflag =
+ port->normal_termios.c_cflag;
+ else
+ GMStatus[i].cflag =
+ port->tty->termios->c_cflag;
+
+ status = inb(port->ioaddr + UART_MSR);
+ if (status & 0x80 /*UART_MSR_DCD */ )
+ GMStatus[i].dcd = 1;
+ else
+ GMStatus[i].dcd = 0;
+
+ if (status & 0x20 /*UART_MSR_DSR */ )
+ GMStatus[i].dsr = 1;
+ else
+ GMStatus[i].dsr = 0;
+
+
+ if (status & 0x10 /*UART_MSR_CTS */ )
+ GMStatus[i].cts = 1;
+ else
+ GMStatus[i].cts = 0;
+ }
+ if (copy_to_user(argp, GMStatus,
+ sizeof(struct mxser_mstatus) * MXSER_PORTS))
+ return -EFAULT;
+ return 0;
+ case MOXA_ASPP_MON_EXT: {
+ int status, p, shiftbit;
+ unsigned long opmode;
+ unsigned cflag, iflag;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
+ port = &mxser_boards[i].ports[j];
+ if (!port->ioaddr)
+ continue;
+
+ status = mxser_get_msr(port->ioaddr, 0, i);
+
+ if (status & UART_MSR_TERI)
+ port->icount.rng++;
+ if (status & UART_MSR_DDSR)
+ port->icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ port->icount.dcd++;
+ if (status & UART_MSR_DCTS)
+ port->icount.cts++;
+
+ port->mon_data.modem_status = status;
+ mon_data_ext.rx_cnt[i] = port->mon_data.rxcnt;
+ mon_data_ext.tx_cnt[i] = port->mon_data.txcnt;
+ mon_data_ext.up_rxcnt[i] =
+ port->mon_data.up_rxcnt;
+ mon_data_ext.up_txcnt[i] =
+ port->mon_data.up_txcnt;
+ mon_data_ext.modem_status[i] =
+ port->mon_data.modem_status;
+ mon_data_ext.baudrate[i] = port->realbaud;
+
+ if (!port->tty || !port->tty->termios) {
+ cflag = port->normal_termios.c_cflag;
+ iflag = port->normal_termios.c_iflag;
+ } else {
+ cflag = port->tty->termios->c_cflag;
+ iflag = port->tty->termios->c_iflag;
+ }
+
+ mon_data_ext.databits[i] = cflag & CSIZE;
+
+ mon_data_ext.stopbits[i] = cflag & CSTOPB;
+
+ mon_data_ext.parity[i] =
+ cflag & (PARENB | PARODD | CMSPAR);
+
+ mon_data_ext.flowctrl[i] = 0x00;
+
+ if (cflag & CRTSCTS)
+ mon_data_ext.flowctrl[i] |= 0x03;
+
+ if (iflag & (IXON | IXOFF))
+ mon_data_ext.flowctrl[i] |= 0x0C;
+
+ if (port->type == PORT_16550A)
+ mon_data_ext.fifo[i] = 1;
+ else
+ mon_data_ext.fifo[i] = 0;
+
+ p = i % 4;
+ shiftbit = p * 2;
+ opmode = inb(port->opmode_ioaddr) >> shiftbit;
+ opmode &= OP_MODE_MASK;
+
+ mon_data_ext.iftype[i] = opmode;
+
+ }
+ if (copy_to_user(argp, &mon_data_ext,
+ sizeof(mon_data_ext)))
+ return -EFAULT;
+
+ return 0;
+
+ } default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int mxser_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mxser_port *info = tty->driver_data;
+ struct async_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct __user *p_cuser;
+ unsigned long templ;
+ unsigned long flags;
+ void __user *argp = (void __user *)arg;
+ int retval;
+
+ if (tty->index == MXSER_PORTS)
+ return mxser_ioctl_special(cmd, argp);
+
+ if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
+ int p;
+ unsigned long opmode;
+ static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
+ int shiftbit;
+ unsigned char val, mask;
+
+ p = tty->index % 4;
+ if (cmd == MOXA_SET_OP_MODE) {
+ if (get_user(opmode, (int __user *) argp))
+ return -EFAULT;
+ if (opmode != RS232_MODE &&
+ opmode != RS485_2WIRE_MODE &&
+ opmode != RS422_MODE &&
+ opmode != RS485_4WIRE_MODE)
+ return -EFAULT;
+ mask = ModeMask[p];
+ shiftbit = p * 2;
+ val = inb(info->opmode_ioaddr);
+ val &= mask;
+ val |= (opmode << shiftbit);
+ outb(val, info->opmode_ioaddr);
+ } else {
+ shiftbit = p * 2;
+ opmode = inb(info->opmode_ioaddr) >> shiftbit;
+ opmode &= OP_MODE_MASK;
+ if (copy_to_user(argp, &opmode, sizeof(int)))
+ return -EFAULT;
+ }
+ return 0;
+ }
+
+ if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
+ test_bit(TTY_IO_ERROR, &tty->flags))
+ return -EIO;
+
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ mxser_send_break(info, HZ / 4); /* 1/4 second */
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
+ return 0;
+ case TIOCGSOFTCAR:
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
+ case TIOCSSOFTCAR:
+ if (get_user(templ, (unsigned long __user *) argp))
+ return -EFAULT;
+ arg = templ;
+ tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+ return 0;
+ case TIOCGSERIAL:
+ return mxser_get_serial_info(info, argp);
+ case TIOCSSERIAL:
+ return mxser_set_serial_info(info, argp);
+ case TIOCSERGETLSR: /* Get line status register */
+ return mxser_get_lsr_info(info, argp);
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT: {
+ DECLARE_WAITQUEUE(wait, current);
+ int ret;
+ spin_lock_irqsave(&info->slock, flags);
+ cprev = info->icount; /* note the counters on entry */
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ add_wait_queue(&info->delta_msr_wait, &wait);
+ while (1) {
+ spin_lock_irqsave(&info->slock, flags);
+ cnow = info->icount; /* atomic copy */
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ 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))) {
+ ret = 0;
+ break;
+ }
+ /* see if a signal did it */
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ cprev = cnow;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->delta_msr_wait, &wait);
+ break;
+ }
+ /* NOTREACHED */
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ spin_lock_irqsave(&info->slock, flags);
+ cnow = info->icount;
+ spin_unlock_irqrestore(&info->slock, flags);
+ p_cuser = argp;
+ if (put_user(cnow.frame, &p_cuser->frame))
+ return -EFAULT;
+ if (put_user(cnow.brk, &p_cuser->brk))
+ return -EFAULT;
+ if (put_user(cnow.overrun, &p_cuser->overrun))
+ return -EFAULT;
+ if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
+ return -EFAULT;
+ if (put_user(cnow.parity, &p_cuser->parity))
+ return -EFAULT;
+ if (put_user(cnow.rx, &p_cuser->rx))
+ return -EFAULT;
+ if (put_user(cnow.tx, &p_cuser->tx))
+ return -EFAULT;
+ put_user(cnow.cts, &p_cuser->cts);
+ put_user(cnow.dsr, &p_cuser->dsr);
+ put_user(cnow.rng, &p_cuser->rng);
+ put_user(cnow.dcd, &p_cuser->dcd);
+ return 0;
+ case MOXA_HighSpeedOn:
+ return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
+ case MOXA_SDS_RSTICOUNTER:
+ info->mon_data.rxcnt = 0;
+ info->mon_data.txcnt = 0;
+ return 0;
+ case MOXA_ASPP_SETBAUD:{
+ long baud;
+ if (get_user(baud, (long __user *)argp))
+ return -EFAULT;
+ mxser_set_baud(info, baud);
+ return 0;
+ }
+ case MOXA_ASPP_GETBAUD:
+ if (copy_to_user(argp, &info->realbaud, sizeof(long)))
+ return -EFAULT;
+
+ return 0;
+
+ case MOXA_ASPP_OQUEUE:{
+ int len, lsr;
+
+ len = mxser_chars_in_buffer(tty);
+
+ lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT;
+
+ len += (lsr ? 0 : 1);
+
+ if (copy_to_user(argp, &len, sizeof(int)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case MOXA_ASPP_MON: {
+ int mcr, status;
+
+ status = mxser_get_msr(info->ioaddr, 1, tty->index);
+ mxser_check_modem_status(info, status);
+
+ mcr = inb(info->ioaddr + UART_MCR);
+ if (mcr & MOXA_MUST_MCR_XON_FLAG)
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
+ else
+ info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD;
+
+ if (mcr & MOXA_MUST_MCR_TX_XON)
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT;
+ else
+ info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
+
+ if (info->tty->hw_stopped)
+ info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
+ else
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
+
+ if (copy_to_user(argp, &info->mon_data,
+ sizeof(struct mxser_mon)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case MOXA_ASPP_LSTATUS: {
+ if (copy_to_user(argp, &info->err_shadow,
+ sizeof(unsigned char)))
+ return -EFAULT;
+
+ info->err_shadow = 0;
+ return 0;
+ }
+ case MOXA_SET_BAUD_METHOD: {
+ int method;
+
+ if (get_user(method, (int __user *)argp))
+ return -EFAULT;
+ mxser_set_baud_method[tty->index] = method;
+ if (copy_to_user(argp, &method, sizeof(int)))
+ return -EFAULT;
+
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static void mxser_stoprx(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ info->ldisc_stop_rx = 1;
+ if (I_IXOFF(tty)) {
+ if (info->board->chip_flag) {
+ info->IER &= ~MOXA_MUST_RECV_ISR;
+ outb(info->IER, info->ioaddr + UART_IER);
+ } else {
+ info->x_char = STOP_CHAR(tty);
+ outb(0, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ }
+
+ if (info->tty->termios->c_cflag & CRTSCTS) {
+ info->MCR &= ~UART_MCR_RTS;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ }
+}
+
+/*
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ */
+static void mxser_throttle(struct tty_struct *tty)
+{
+ mxser_stoprx(tty);
+}
+
+static void mxser_unthrottle(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ /* startrx */
+ info->ldisc_stop_rx = 0;
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else {
+ if (info->board->chip_flag) {
+ info->IER |= MOXA_MUST_RECV_ISR;
+ outb(info->IER, info->ioaddr + UART_IER);
+ } else {
+ info->x_char = START_CHAR(tty);
+ outb(0, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ }
+ }
+
+ if (info->tty->termios->c_cflag & CRTSCTS) {
+ info->MCR |= UART_MCR_RTS;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ }
+}
+
+/*
+ * mxser_stop() and mxser_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ */
+static void mxser_stop(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ if (info->IER & UART_IER_THRI) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static void mxser_start(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ if (info->xmit_cnt && info->xmit_buf) {
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ if ((tty->termios->c_cflag != old_termios->c_cflag) ||
+ (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
+
+ mxser_change_speed(info, old_termios);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ mxser_start(tty);
+ }
+ }
+
+ /* Handle sw stopped */
+ if ((old_termios->c_iflag & IXON) &&
+ !(tty->termios->c_iflag & IXON)) {
+ tty->stopped = 0;
+
+ if (info->board->chip_flag) {
+ spin_lock_irqsave(&info->slock, flags);
+ DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+
+ mxser_start(tty);
+ }
+}
+
+/*
+ * mxser_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long orig_jiffies, char_time;
+ int lsr;
+
+ if (info->type == PORT_UNKNOWN)
+ return;
+
+ if (info->xmit_fifo_size == 0)
+ return; /* Just in case.... */
+
+ orig_jiffies = jiffies;
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ *
+ * Note: we have to use pretty tight timings here to satisfy
+ * the NIST-PCTS.
+ */
+ char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
+ char_time = char_time / 5;
+ if (char_time == 0)
+ char_time = 1;
+ if (timeout && timeout < char_time)
+ char_time = timeout;
+ /*
+ * If the transmitter hasn't cleared in twice the approximate
+ * amount of time to send the entire FIFO, it probably won't
+ * ever clear. This assumes the UART isn't doing flow
+ * control, which is currently the case. Hence, if it ever
+ * takes longer than info->timeout, this is probably due to a
+ * UART bug of some kind. So, we clamp the timeout parameter at
+ * 2*info->timeout.
+ */
+ if (!timeout || timeout > 2 * info->timeout)
+ timeout = 2 * info->timeout;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...",
+ timeout, char_time);
+ printk("jiff=%lu...", jiffies);
+#endif
+ while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+ schedule_timeout_interruptible(char_time);
+ if (signal_pending(current))
+ break;
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
+ break;
+ }
+ set_current_state(TASK_RUNNING);
+
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * This routine is called by tty_hangup() when a hangup is signaled.
+ */
+void mxser_hangup(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ mxser_flush_buffer(tty);
+ mxser_shutdown(info);
+ info->event = 0;
+ info->count = 0;
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ info->tty = NULL;
+ wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * mxser_rs_break() --- routine which turns the break handling on or off
+ */
+static void mxser_rs_break(struct tty_struct *tty, int break_state)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ if (break_state == -1)
+ outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ else
+ outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static void mxser_receive_chars(struct mxser_port *port, int *status)
+{
+ struct tty_struct *tty = port->tty;
+ unsigned char ch, gdl;
+ int ignored = 0;
+ int cnt = 0;
+ int recv_room;
+ int max = 256;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->slock, flags);
+
+ recv_room = tty->receive_room;
+ if ((recv_room == 0) && (!port->ldisc_stop_rx))
+ mxser_stoprx(tty);
+
+ if (port->board->chip_flag != MOXA_OTHER_UART) {
+
+ if (*status & UART_LSR_SPECIAL)
+ goto intr_old;
+ if (port->board->chip_flag == MOXA_MUST_MU860_HWID &&
+ (*status & MOXA_MUST_LSR_RERR))
+ goto intr_old;
+ if (*status & MOXA_MUST_LSR_RERR)
+ goto intr_old;
+
+ gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
+
+ if (port->board->chip_flag == MOXA_MUST_MU150_HWID)
+ gdl &= MOXA_MUST_GDL_MASK;
+ if (gdl >= recv_room) {
+ if (!port->ldisc_stop_rx)
+ mxser_stoprx(tty);
+ }
+ while (gdl--) {
+ ch = inb(port->ioaddr + UART_RX);
+ tty_insert_flip_char(tty, ch, 0);
+ cnt++;
+ }
+ goto end_intr;
+ }
+intr_old:
+
+ do {
+ if (max-- < 0)
+ break;
+
+ ch = inb(port->ioaddr + UART_RX);
+ if (port->board->chip_flag && (*status & UART_LSR_OE))
+ outb(0x23, port->ioaddr + UART_FCR);
+ *status &= port->read_status_mask;
+ if (*status & port->ignore_status_mask) {
+ if (++ignored > 100)
+ break;
+ } else {
+ char flag = 0;
+ if (*status & UART_LSR_SPECIAL) {
+ if (*status & UART_LSR_BI) {
+ flag = TTY_BREAK;
+ port->icount.brk++;
+
+ if (port->flags & ASYNC_SAK)
+ do_SAK(tty);
+ } else if (*status & UART_LSR_PE) {
+ flag = TTY_PARITY;
+ port->icount.parity++;
+ } else if (*status & UART_LSR_FE) {
+ flag = TTY_FRAME;
+ port->icount.frame++;
+ } else if (*status & UART_LSR_OE) {
+ flag = TTY_OVERRUN;
+ port->icount.overrun++;
+ }
+ }
+ tty_insert_flip_char(tty, ch, flag);
+ cnt++;
+ if (cnt >= recv_room) {
+ if (!port->ldisc_stop_rx)
+ mxser_stoprx(tty);
+ break;
+ }
+
+ }
+
+ if (port->board->chip_flag)
+ break;
+
+ *status = inb(port->ioaddr + UART_LSR);
+ } while (*status & UART_LSR_DR);
+
+end_intr:
+ mxvar_log.rxcnt[port->tty->index] += cnt;
+ port->mon_data.rxcnt += cnt;
+ port->mon_data.up_rxcnt += cnt;
+ spin_unlock_irqrestore(&port->slock, flags);
+
+ tty_flip_buffer_push(tty);
+}
+
+static void mxser_transmit_chars(struct mxser_port *port)
+{
+ int count, cnt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->slock, flags);
+
+ if (port->x_char) {
+ outb(port->x_char, port->ioaddr + UART_TX);
+ port->x_char = 0;
+ mxvar_log.txcnt[port->tty->index]++;
+ port->mon_data.txcnt++;
+ port->mon_data.up_txcnt++;
+ port->icount.tx++;
+ goto unlock;
+ }
+
+ if (port->xmit_buf == 0)
+ goto unlock;
+
+ if ((port->xmit_cnt <= 0) || port->tty->stopped ||
+ (port->tty->hw_stopped &&
+ (port->type != PORT_16550A) &&
+ (!port->board->chip_flag))) {
+ port->IER &= ~UART_IER_THRI;
+ outb(port->IER, port->ioaddr + UART_IER);
+ goto unlock;
+ }
+
+ cnt = port->xmit_cnt;
+ count = port->xmit_fifo_size;
+ do {
+ outb(port->xmit_buf[port->xmit_tail++],
+ port->ioaddr + UART_TX);
+ port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
+ if (--port->xmit_cnt <= 0)
+ break;
+ } while (--count > 0);
+ mxvar_log.txcnt[port->tty->index] += (cnt - port->xmit_cnt);
+
+ port->mon_data.txcnt += (cnt - port->xmit_cnt);
+ port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
+ port->icount.tx += (cnt - port->xmit_cnt);
+
+ if (port->xmit_cnt < WAKEUP_CHARS) {
+ set_bit(MXSER_EVENT_TXLOW, &port->event);
+ schedule_work(&port->tqueue);
+ }
+ if (port->xmit_cnt <= 0) {
+ port->IER &= ~UART_IER_THRI;
+ outb(port->IER, port->ioaddr + UART_IER);
+ }
+unlock:
+ spin_unlock_irqrestore(&port->slock, flags);
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static irqreturn_t mxser_interrupt(int irq, void *dev_id)
+{
+ int status, iir, i;
+ struct mxser_board *brd = NULL;
+ struct mxser_port *port;
+ int max, irqbits, bits, msr;
+ int pass_counter = 0;
+ unsigned int int_cnt;
+ int handled = IRQ_NONE;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ if (dev_id == &mxser_boards[i]) {
+ brd = dev_id;
+ break;
+ }
+
+ if (i == MXSER_BOARDS)
+ goto irq_stop;
+ if (brd == NULL)
+ goto irq_stop;
+ max = brd->info->nports;
+ while (1) {
+ irqbits = inb(brd->vector) & brd->vector_mask;
+ if (irqbits == brd->vector_mask)
+ break;
+
+ handled = IRQ_HANDLED;
+ for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
+ if (irqbits == brd->vector_mask)
+ break;
+ if (bits & irqbits)
+ continue;
+ port = &brd->ports[i];
+
+ int_cnt = 0;
+ do {
+ iir = inb(port->ioaddr + UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ break;
+ iir &= MOXA_MUST_IIR_MASK;
+ if (!port->tty) {
+ status = inb(port->ioaddr + UART_LSR);
+ outb(0x27, port->ioaddr + UART_FCR);
+ inb(port->ioaddr + UART_MSR);
+ break;
+ }
+
+ status = inb(port->ioaddr + UART_LSR);
+
+ if (status & UART_LSR_PE)
+ port->err_shadow |= NPPI_NOTIFY_PARITY;
+ if (status & UART_LSR_FE)
+ port->err_shadow |= NPPI_NOTIFY_FRAMING;
+ if (status & UART_LSR_OE)
+ port->err_shadow |=
+ NPPI_NOTIFY_HW_OVERRUN;
+ if (status & UART_LSR_BI)
+ port->err_shadow |= NPPI_NOTIFY_BREAK;
+
+ if (port->board->chip_flag) {
+ if (iir == MOXA_MUST_IIR_GDA ||
+ iir == MOXA_MUST_IIR_RDA ||
+ iir == MOXA_MUST_IIR_RTO ||
+ iir == MOXA_MUST_IIR_LSR)
+ mxser_receive_chars(port,
+ &status);
+
+ } else {
+ status &= port->read_status_mask;
+ if (status & UART_LSR_DR)
+ mxser_receive_chars(port,
+ &status);
+ }
+ msr = inb(port->ioaddr + UART_MSR);
+ if (msr & UART_MSR_ANY_DELTA)
+ mxser_check_modem_status(port, msr);
+
+ if (port->board->chip_flag) {
+ if (iir == 0x02 && (status &
+ UART_LSR_THRE))
+ mxser_transmit_chars(port);
+ } else {
+ if (status & UART_LSR_THRE)
+ mxser_transmit_chars(port);
+ }
+ } while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
+ }
+ if (pass_counter++ > MXSER_ISR_PASS_LIMIT)
+ break; /* Prevent infinite loops */
+ }
+
+irq_stop:
+ return handled;
+}
+
+static const struct tty_operations mxser_ops = {
+ .open = mxser_open,
+ .close = mxser_close,
+ .write = mxser_write,
+ .put_char = mxser_put_char,
+ .flush_chars = mxser_flush_chars,
+ .write_room = mxser_write_room,
+ .chars_in_buffer = mxser_chars_in_buffer,
+ .flush_buffer = mxser_flush_buffer,
+ .ioctl = mxser_ioctl,
+ .throttle = mxser_throttle,
+ .unthrottle = mxser_unthrottle,
+ .set_termios = mxser_set_termios,
+ .stop = mxser_stop,
+ .start = mxser_start,
+ .hangup = mxser_hangup,
+ .break_ctl = mxser_rs_break,
+ .wait_until_sent = mxser_wait_until_sent,
+ .tiocmget = mxser_tiocmget,
+ .tiocmset = mxser_tiocmset,
+};
+
+/*
+ * The MOXA Smartio/Industio serial driver boot-time initialization code!
+ */
+
+static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev,
+ unsigned int irq)
+{
+ if (irq)
+ free_irq(brd->irq, brd);
+ if (pdev != NULL) { /* PCI */
+#ifdef CONFIG_PCI
+ pci_release_region(pdev, 2);
+ pci_release_region(pdev, 3);
+ pci_dev_put(pdev);
+#endif
+ } else {
+ release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
+ release_region(brd->vector, 1);
+ }
+}
+
+static int __devinit mxser_initbrd(struct mxser_board *brd,
+ struct pci_dev *pdev)
+{
+ struct mxser_port *info;
+ unsigned int i;
+ int retval;
+
+ printk(KERN_INFO "max. baud rate = %d bps.\n", brd->ports[0].max_baud);
+
+ for (i = 0; i < brd->info->nports; i++) {
+ info = &brd->ports[i];
+ info->board = brd;
+ info->stop_rx = 0;
+ info->ldisc_stop_rx = 0;
+
+ /* Enhance mode enabled here */
+ if (brd->chip_flag != MOXA_OTHER_UART)
+ ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr);
+
+ info->flags = ASYNC_SHARE_IRQ;
+ info->type = brd->uart_type;
+
+ process_txrx_fifo(info);
+
+ info->custom_divisor = info->baud_base * 16;
+ info->close_delay = 5 * HZ / 10;
+ info->closing_wait = 30 * HZ;
+ INIT_WORK(&info->tqueue, mxser_do_softint);
+ info->normal_termios = mxvar_sdriver->init_termios;
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+ memset(&info->mon_data, 0, sizeof(struct mxser_mon));
+ info->err_shadow = 0;
+ spin_lock_init(&info->slock);
+
+ /* before set INT ISR, disable all int */
+ outb(inb(info->ioaddr + UART_IER) & 0xf0,
+ info->ioaddr + UART_IER);
+ }
+ /*
+ * Allocate the IRQ if necessary
+ */
+
+ retval = request_irq(brd->irq, mxser_interrupt,
+ (brd->ports[0].flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED :
+ IRQF_DISABLED, "mxser", brd);
+ if (retval) {
+ printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
+ "conflict with another device.\n",
+ brd->info->name, brd->irq);
+ /* We hold resources, we need to release them. */
+ mxser_release_res(brd, pdev, 0);
+ return retval;
+ }
+ return 0;
+}
+
+static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
+{
+ int id, i, bits;
+ unsigned short regs[16], irq;
+ unsigned char scratch, scratch2;
+
+ brd->chip_flag = MOXA_OTHER_UART;
+
+ id = mxser_read_register(cap, regs);
+ switch (id) {
+ case C168_ASIC_ID:
+ brd->info = &mxser_cards[0];
+ break;
+ case C104_ASIC_ID:
+ brd->info = &mxser_cards[1];
+ break;
+ case CI104J_ASIC_ID:
+ brd->info = &mxser_cards[2];
+ break;
+ case C102_ASIC_ID:
+ brd->info = &mxser_cards[5];
+ break;
+ case CI132_ASIC_ID:
+ brd->info = &mxser_cards[6];
+ break;
+ case CI134_ASIC_ID:
+ brd->info = &mxser_cards[7];
+ break;
+ default:
+ return 0;
+ }
+
+ irq = 0;
+ /* some ISA cards have 2 ports, but we want to see them as 4-port (why?)
+ Flag-hack checks if configuration should be read as 2-port here. */
+ if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) {
+ irq = regs[9] & 0xF000;
+ irq = irq | (irq >> 4);
+ if (irq != (regs[9] & 0xFF00))
+ return MXSER_ERR_IRQ_CONFLIT;
+ } else if (brd->info->nports == 4) {
+ irq = regs[9] & 0xF000;
+ irq = irq | (irq >> 4);
+ irq = irq | (irq >> 8);
+ if (irq != regs[9])
+ return MXSER_ERR_IRQ_CONFLIT;
+ } else if (brd->info->nports == 8) {
+ irq = regs[9] & 0xF000;
+ irq = irq | (irq >> 4);
+ irq = irq | (irq >> 8);
+ if ((irq != regs[9]) || (irq != regs[10]))
+ return MXSER_ERR_IRQ_CONFLIT;
+ }
+
+ if (!irq)
+ return MXSER_ERR_IRQ;
+ brd->irq = ((int)(irq & 0xF000) >> 12);
+ for (i = 0; i < 8; i++)
+ brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8;
+ if ((regs[12] & 0x80) == 0)
+ return MXSER_ERR_VECTOR;
+ brd->vector = (int)regs[11]; /* interrupt vector */
+ if (id == 1)
+ brd->vector_mask = 0x00FF;
+ else
+ brd->vector_mask = 0x000F;
+ for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
+ if (regs[12] & bits) {
+ brd->ports[i].baud_base = 921600;
+ brd->ports[i].max_baud = 921600;
+ } else {
+ brd->ports[i].baud_base = 115200;
+ brd->ports[i].max_baud = 115200;
+ }
+ }
+ scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
+ outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR);
+ outb(0, cap + UART_EFR); /* EFR is the same as FCR */
+ outb(scratch2, cap + UART_LCR);
+ outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR);
+ scratch = inb(cap + UART_IIR);
+
+ if (scratch & 0xC0)
+ brd->uart_type = PORT_16550A;
+ else
+ brd->uart_type = PORT_16450;
+ if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports,
+ "mxser(IO)"))
+ return MXSER_ERR_IOADDR;
+ if (!request_region(brd->vector, 1, "mxser(vector)")) {
+ release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
+ return MXSER_ERR_VECTOR;
+ }
+ return brd->info->nports;
+}
+
+static int __devinit mxser_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+#ifdef CONFIG_PCI
+ struct mxser_board *brd;
+ unsigned int i, j;
+ unsigned long ioaddress;
+ int retval = -EINVAL;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ if (mxser_boards[i].info == NULL)
+ break;
+
+ if (i >= MXSER_BOARDS) {
+ printk(KERN_ERR "Too many Smartio/Industio family boards found "
+ "(maximum %d), board not configured\n", MXSER_BOARDS);
+ goto err;
+ }
+
+ brd = &mxser_boards[i];
+ brd->idx = i * MXSER_PORTS_PER_BOARD;
+ printk(KERN_INFO "Found MOXA %s board (BusNo=%d, DevNo=%d)\n",
+ mxser_cards[ent->driver_data].name,
+ pdev->bus->number, PCI_SLOT(pdev->devfn));
+
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+ goto err;
+ }
+
+ /* io address */
+ ioaddress = pci_resource_start(pdev, 2);
+ retval = pci_request_region(pdev, 2, "mxser(IO)");
+ if (retval)
+ goto err;
+
+ brd->info = &mxser_cards[ent->driver_data];
+ for (i = 0; i < brd->info->nports; i++)
+ brd->ports[i].ioaddr = ioaddress + 8 * i;
+
+ /* vector */
+ ioaddress = pci_resource_start(pdev, 3);
+ retval = pci_request_region(pdev, 3, "mxser(vector)");
+ if (retval)
+ goto err_relio;
+ brd->vector = ioaddress;
+
+ /* irq */
+ brd->irq = pdev->irq;
+
+ brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr);
+ brd->uart_type = PORT_16550A;
+ brd->vector_mask = 0;
+
+ for (i = 0; i < brd->info->nports; i++) {
+ for (j = 0; j < UART_INFO_NUM; j++) {
+ if (Gpci_uart_info[j].type == brd->chip_flag) {
+ brd->ports[i].max_baud =
+ Gpci_uart_info[j].max_baud;
+
+ /* exception....CP-102 */
+ if (brd->info->flags & MXSER_HIGHBAUD)
+ brd->ports[i].max_baud = 921600;
+ break;
+ }
+ }
+ }
+
+ if (brd->chip_flag == MOXA_MUST_MU860_HWID) {
+ for (i = 0; i < brd->info->nports; i++) {
+ if (i < 4)
+ brd->ports[i].opmode_ioaddr = ioaddress + 4;
+ else
+ brd->ports[i].opmode_ioaddr = ioaddress + 0x0c;
+ }
+ outb(0, ioaddress + 4); /* default set to RS232 mode */
+ outb(0, ioaddress + 0x0c); /* default set to RS232 mode */
+ }
+
+ for (i = 0; i < brd->info->nports; i++) {
+ brd->vector_mask |= (1 << i);
+ brd->ports[i].baud_base = 921600;
+ }
+
+ /* mxser_initbrd will hook ISR. */
+ if (mxser_initbrd(brd, pdev) < 0)
+ goto err_relvec;
+
+ for (i = 0; i < brd->info->nports; i++)
+ tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
+
+ pci_set_drvdata(pdev, brd);
+
+ return 0;
+err_relvec:
+ pci_release_region(pdev, 3);
+err_relio:
+ pci_release_region(pdev, 2);
+ brd->info = NULL;
+err:
+ return retval;
+#else
+ return -ENODEV;
+#endif
+}
+
+static void __devexit mxser_remove(struct pci_dev *pdev)
+{
+ struct mxser_board *brd = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < brd->info->nports; i++)
+ tty_unregister_device(mxvar_sdriver, brd->idx + i);
+
+ mxser_release_res(brd, pdev, 1);
+}
+
+static struct pci_driver mxser_driver = {
+ .name = "mxser",
+ .id_table = mxser_pcibrds,
+ .probe = mxser_probe,
+ .remove = __devexit_p(mxser_remove)
+};
+
+static int __init mxser_module_init(void)
+{
+ struct mxser_board *brd;
+ unsigned long cap;
+ unsigned int i, m, isaloop;
+ int retval, b;
+
+ pr_debug("Loading module mxser ...\n");
+
+ mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
+ if (!mxvar_sdriver)
+ return -ENOMEM;
+ spin_lock_init(&gm_lock);
+
+ printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
+ MXSER_VERSION);
+
+ /* Initialize the tty_driver structure */
+ mxvar_sdriver->owner = THIS_MODULE;
+ mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
+ mxvar_sdriver->name = "ttyMI";
+ mxvar_sdriver->major = ttymajor;
+ mxvar_sdriver->minor_start = 0;
+ mxvar_sdriver->num = MXSER_PORTS + 1;
+ mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
+ mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
+ mxvar_sdriver->init_termios = tty_std_termios;
+ mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
+ mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(mxvar_sdriver, &mxser_ops);
+
+ retval = tty_register_driver(mxvar_sdriver);
+ if (retval) {
+ printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family "
+ "tty driver !\n");
+ goto err_put;
+ }
+
+ mxvar_diagflag = 0;
+
+ m = 0;
+ /* Start finding ISA boards here */
+ for (isaloop = 0; isaloop < 2; isaloop++)
+ for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
+ if (!isaloop)
+ cap = mxserBoardCAP[b]; /* predefined */
+ else
+ cap = ioaddr[b]; /* module param */
+
+ if (!cap)
+ continue;
+
+ brd = &mxser_boards[m];
+ retval = mxser_get_ISA_conf(cap, brd);
+
+ if (retval != 0)
+ printk(KERN_INFO "Found MOXA %s board "
+ "(CAP=0x%x)\n",
+ brd->info->name, ioaddr[b]);
+
+ if (retval <= 0) {
+ if (retval == MXSER_ERR_IRQ)
+ printk(KERN_ERR "Invalid interrupt "
+ "number, board not "
+ "configured\n");
+ else if (retval == MXSER_ERR_IRQ_CONFLIT)
+ printk(KERN_ERR "Invalid interrupt "
+ "number, board not "
+ "configured\n");
+ else if (retval == MXSER_ERR_VECTOR)
+ printk(KERN_ERR "Invalid interrupt "
+ "vector, board not "
+ "configured\n");
+ else if (retval == MXSER_ERR_IOADDR)
+ printk(KERN_ERR "Invalid I/O address, "
+ "board not configured\n");
+
+ brd->info = NULL;
+ continue;
+ }
+
+ /* mxser_initbrd will hook ISR. */
+ if (mxser_initbrd(brd, NULL) < 0) {
+ brd->info = NULL;
+ continue;
+ }
+
+ brd->idx = m * MXSER_PORTS_PER_BOARD;
+ for (i = 0; i < brd->info->nports; i++)
+ tty_register_device(mxvar_sdriver, brd->idx + i,
+ NULL);
+
+ m++;
+ }
+
+ retval = pci_register_driver(&mxser_driver);
+ if (retval) {
+ printk(KERN_ERR "Can't register pci driver\n");
+ if (!m) {
+ retval = -ENODEV;
+ goto err_unr;
+ } /* else: we have some ISA cards under control */
+ }
+
+ pr_debug("Done.\n");
+
+ return 0;
+err_unr:
+ tty_unregister_driver(mxvar_sdriver);
+err_put:
+ put_tty_driver(mxvar_sdriver);
+ return retval;
+}
+
+static void __exit mxser_module_exit(void)
+{
+ unsigned int i, j;
+
+ pr_debug("Unloading module mxser ...\n");
+
+ pci_unregister_driver(&mxser_driver);
+
+ for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
+ if (mxser_boards[i].info != NULL)
+ for (j = 0; j < mxser_boards[i].info->nports; j++)
+ tty_unregister_device(mxvar_sdriver,
+ mxser_boards[i].idx + j);
+ tty_unregister_driver(mxvar_sdriver);
+ put_tty_driver(mxvar_sdriver);
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ if (mxser_boards[i].info != NULL)
+ mxser_release_res(&mxser_boards[i], NULL, 1);
+
+ pr_debug("Done.\n");
+}
+
+module_init(mxser_module_init);
+module_exit(mxser_module_exit);
diff --git a/drivers/char/mxser_new.h b/drivers/char/mxser_new.h
new file mode 100644
index 00000000000..a08f0ecb09b
--- /dev/null
+++ b/drivers/char/mxser_new.h
@@ -0,0 +1,450 @@
+#ifndef _MXSER_H
+#define _MXSER_H
+
+/*
+ * Semi-public control interfaces
+ */
+
+/*
+ * MOXA ioctls
+ */
+
+#define MOXA 0x400
+#define MOXA_GETDATACOUNT (MOXA + 23)
+#define MOXA_GET_CONF (MOXA + 35)
+#define MOXA_DIAGNOSE (MOXA + 50)
+#define MOXA_CHKPORTENABLE (MOXA + 60)
+#define MOXA_HighSpeedOn (MOXA + 61)
+#define MOXA_GET_MAJOR (MOXA + 63)
+#define MOXA_GET_CUMAJOR (MOXA + 64)
+#define MOXA_GETMSTATUS (MOXA + 65)
+#define MOXA_SET_OP_MODE (MOXA + 66)
+#define MOXA_GET_OP_MODE (MOXA + 67)
+
+#define RS232_MODE 0
+#define RS485_2WIRE_MODE 1
+#define RS422_MODE 2
+#define RS485_4WIRE_MODE 3
+#define OP_MODE_MASK 3
+// above add by Victor Yu. 01-05-2004
+
+#define TTY_THRESHOLD_THROTTLE 128
+
+#define LO_WATER (TTY_FLIPBUF_SIZE)
+#define HI_WATER (TTY_FLIPBUF_SIZE*2*3/4)
+
+// added by James. 03-11-2004.
+#define MOXA_SDS_GETICOUNTER (MOXA + 68)
+#define MOXA_SDS_RSTICOUNTER (MOXA + 69)
+// (above) added by James.
+
+#define MOXA_ASPP_OQUEUE (MOXA + 70)
+#define MOXA_ASPP_SETBAUD (MOXA + 71)
+#define MOXA_ASPP_GETBAUD (MOXA + 72)
+#define MOXA_ASPP_MON (MOXA + 73)
+#define MOXA_ASPP_LSTATUS (MOXA + 74)
+#define MOXA_ASPP_MON_EXT (MOXA + 75)
+#define MOXA_SET_BAUD_METHOD (MOXA + 76)
+
+
+/* --------------------------------------------------- */
+
+#define NPPI_NOTIFY_PARITY 0x01
+#define NPPI_NOTIFY_FRAMING 0x02
+#define NPPI_NOTIFY_HW_OVERRUN 0x04
+#define NPPI_NOTIFY_SW_OVERRUN 0x08
+#define NPPI_NOTIFY_BREAK 0x10
+
+#define NPPI_NOTIFY_CTSHOLD 0x01 // Tx hold by CTS low
+#define NPPI_NOTIFY_DSRHOLD 0x02 // Tx hold by DSR low
+#define NPPI_NOTIFY_XOFFHOLD 0x08 // Tx hold by Xoff received
+#define NPPI_NOTIFY_XOFFXENT 0x10 // Xoff Sent
+
+//CheckIsMoxaMust return value
+#define MOXA_OTHER_UART 0x00
+#define MOXA_MUST_MU150_HWID 0x01
+#define MOXA_MUST_MU860_HWID 0x02
+
+// follow just for Moxa Must chip define.
+//
+// when LCR register (offset 0x03) write following value,
+// the Must chip will enter enchance mode. And write value
+// on EFR (offset 0x02) bit 6,7 to change bank.
+#define MOXA_MUST_ENTER_ENCHANCE 0xBF
+
+// when enhance mode enable, access on general bank register
+#define MOXA_MUST_GDL_REGISTER 0x07
+#define MOXA_MUST_GDL_MASK 0x7F
+#define MOXA_MUST_GDL_HAS_BAD_DATA 0x80
+
+#define MOXA_MUST_LSR_RERR 0x80 // error in receive FIFO
+// enchance register bank select and enchance mode setting register
+// when LCR register equal to 0xBF
+#define MOXA_MUST_EFR_REGISTER 0x02
+// enchance mode enable
+#define MOXA_MUST_EFR_EFRB_ENABLE 0x10
+// enchance reister bank set 0, 1, 2
+#define MOXA_MUST_EFR_BANK0 0x00
+#define MOXA_MUST_EFR_BANK1 0x40
+#define MOXA_MUST_EFR_BANK2 0x80
+#define MOXA_MUST_EFR_BANK3 0xC0
+#define MOXA_MUST_EFR_BANK_MASK 0xC0
+
+// set XON1 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XON1_REGISTER 0x04
+
+// set XON2 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XON2_REGISTER 0x05
+
+// set XOFF1 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XOFF1_REGISTER 0x06
+
+// set XOFF2 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XOFF2_REGISTER 0x07
+
+#define MOXA_MUST_RBRTL_REGISTER 0x04
+#define MOXA_MUST_RBRTH_REGISTER 0x05
+#define MOXA_MUST_RBRTI_REGISTER 0x06
+#define MOXA_MUST_THRTL_REGISTER 0x07
+#define MOXA_MUST_ENUM_REGISTER 0x04
+#define MOXA_MUST_HWID_REGISTER 0x05
+#define MOXA_MUST_ECR_REGISTER 0x06
+#define MOXA_MUST_CSR_REGISTER 0x07
+
+// good data mode enable
+#define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20
+// only good data put into RxFIFO
+#define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10
+
+// enable CTS interrupt
+#define MOXA_MUST_IER_ECTSI 0x80
+// enable RTS interrupt
+#define MOXA_MUST_IER_ERTSI 0x40
+// enable Xon/Xoff interrupt
+#define MOXA_MUST_IER_XINT 0x20
+// enable GDA interrupt
+#define MOXA_MUST_IER_EGDAI 0x10
+
+#define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
+
+// GDA interrupt pending
+#define MOXA_MUST_IIR_GDA 0x1C
+#define MOXA_MUST_IIR_RDA 0x04
+#define MOXA_MUST_IIR_RTO 0x0C
+#define MOXA_MUST_IIR_LSR 0x06
+
+// recieved Xon/Xoff or specical interrupt pending
+#define MOXA_MUST_IIR_XSC 0x10
+
+// RTS/CTS change state interrupt pending
+#define MOXA_MUST_IIR_RTSCTS 0x20
+#define MOXA_MUST_IIR_MASK 0x3E
+
+#define MOXA_MUST_MCR_XON_FLAG 0x40
+#define MOXA_MUST_MCR_XON_ANY 0x80
+#define MOXA_MUST_MCR_TX_XON 0x08
+
+
+// software flow control on chip mask value
+#define MOXA_MUST_EFR_SF_MASK 0x0F
+// send Xon1/Xoff1
+#define MOXA_MUST_EFR_SF_TX1 0x08
+// send Xon2/Xoff2
+#define MOXA_MUST_EFR_SF_TX2 0x04
+// send Xon1,Xon2/Xoff1,Xoff2
+#define MOXA_MUST_EFR_SF_TX12 0x0C
+// don't send Xon/Xoff
+#define MOXA_MUST_EFR_SF_TX_NO 0x00
+// Tx software flow control mask
+#define MOXA_MUST_EFR_SF_TX_MASK 0x0C
+// don't receive Xon/Xoff
+#define MOXA_MUST_EFR_SF_RX_NO 0x00
+// receive Xon1/Xoff1
+#define MOXA_MUST_EFR_SF_RX1 0x02
+// receive Xon2/Xoff2
+#define MOXA_MUST_EFR_SF_RX2 0x01
+// receive Xon1,Xon2/Xoff1,Xoff2
+#define MOXA_MUST_EFR_SF_RX12 0x03
+// Rx software flow control mask
+#define MOXA_MUST_EFR_SF_RX_MASK 0x03
+
+//#define MOXA_MUST_MIN_XOFFLIMIT 66
+//#define MOXA_MUST_MIN_XONLIMIT 20
+//#define ID1_RX_TRIG 120
+
+
+#define CHECK_MOXA_MUST_XOFFLIMIT(info) { \
+ if ( (info)->IsMoxaMustChipFlag && \
+ (info)->HandFlow.XoffLimit < MOXA_MUST_MIN_XOFFLIMIT ) { \
+ (info)->HandFlow.XoffLimit = MOXA_MUST_MIN_XOFFLIMIT; \
+ (info)->HandFlow.XonLimit = MOXA_MUST_MIN_XONLIMIT; \
+ } \
+}
+
+#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_XON2_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XON2_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_XOFF2_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XOFF2_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_RBRTL_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_RBRTL_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_RBRTH_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_RBRTH_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_RBRTI_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_RBRTI_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_THRTL_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_THRTL_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+//#define MOXA_MUST_RBRL_VALUE 4
+#define SET_MOXA_MUST_FIFO_VALUE(info) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((info)->ioaddr+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR); \
+ __efr = inb((info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)((info)->rx_high_water), (info)->ioaddr+MOXA_MUST_RBRTH_REGISTER); \
+ outb((u8)((info)->rx_trigger), (info)->ioaddr+MOXA_MUST_RBRTI_REGISTER); \
+ outb((u8)((info)->rx_low_water), (info)->ioaddr+MOXA_MUST_RBRTL_REGISTER); \
+ outb(__oldlcr, (info)->ioaddr+UART_LCR); \
+}
+
+
+
+#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK2; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK2; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_JUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_TX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_TX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_JUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_RX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_RX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_TX_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ __efr |= (MOXA_MUST_EFR_SF_RX1|MOXA_MUST_EFR_SF_TX1); \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \
+ u8 __oldmcr; \
+ __oldmcr = inb((baseio)+UART_MCR); \
+ __oldmcr |= MOXA_MUST_MCR_XON_ANY; \
+ outb(__oldmcr, (baseio)+UART_MCR); \
+}
+
+#define DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \
+ u8 __oldmcr; \
+ __oldmcr = inb((baseio)+UART_MCR); \
+ __oldmcr &= ~MOXA_MUST_MCR_XON_ANY; \
+ outb(__oldmcr, (baseio)+UART_MCR); \
+}
+
+#define READ_MOXA_MUST_GDL(baseio) inb((baseio)+MOXA_MUST_GDL_REGISTER)
+
+
+#ifndef INIT_WORK
+#define INIT_WORK(_work, _func, _data){ \
+ _data->tqueue.routine = _func;\
+ _data->tqueue.data = _data;\
+ }
+#endif
+
+#endif
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 203dc2b661d..dc6d4184145 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -125,8 +125,8 @@ static void transmit_block(struct r3964_info *pInfo);
static void receive_char(struct r3964_info *pInfo, const unsigned char c);
static void receive_error(struct r3964_info *pInfo, const char flag);
static void on_timeout(unsigned long priv);
-static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg);
-static int read_telegram(struct r3964_info *pInfo, pid_t pid, unsigned char __user *buf);
+static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
+static int read_telegram(struct r3964_info *pInfo, struct pid *pid, unsigned char __user *buf);
static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
int error_code, struct r3964_block_header *pBlock);
static struct r3964_message* remove_msg(struct r3964_info *pInfo,
@@ -142,7 +142,7 @@ static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
const unsigned char * buf, size_t nr);
static int r3964_ioctl(struct tty_struct * tty, struct file * file,
unsigned int cmd, unsigned long arg);
-static void r3964_set_termios(struct tty_struct *tty, struct termios * old);
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios * old);
static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
struct poll_table_struct *wait);
static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
@@ -829,7 +829,7 @@ static void on_timeout(unsigned long priv)
}
static struct r3964_client_info *findClient(
- struct r3964_info *pInfo, pid_t pid)
+ struct r3964_info *pInfo, struct pid *pid)
{
struct r3964_client_info *pClient;
@@ -843,7 +843,7 @@ static struct r3964_client_info *findClient(
return NULL;
}
-static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg)
+static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
{
struct r3964_client_info *pClient;
struct r3964_client_info **ppClient;
@@ -858,7 +858,7 @@ static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg)
if(pClient->pid == pid)
{
- TRACE_PS("removing client %d from client list", pid);
+ TRACE_PS("removing client %d from client list", pid_nr(pid));
*ppClient = pClient->next;
while(pClient->msg_count)
{
@@ -869,6 +869,7 @@ static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg)
TRACE_M("enable_signals - msg kfree %p",pMsg);
}
}
+ put_pid(pClient->pid);
kfree(pClient);
TRACE_M("enable_signals - kfree %p",pClient);
return 0;
@@ -892,10 +893,10 @@ static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg)
if(pClient==NULL)
return -ENOMEM;
- TRACE_PS("add client %d to client list", pid);
+ TRACE_PS("add client %d to client list", pid_nr(pid));
spin_lock_init(&pClient->lock);
pClient->sig_flags=arg;
- pClient->pid = pid;
+ pClient->pid = get_pid(pid);
pClient->next=pInfo->firstClient;
pClient->first_msg = NULL;
pClient->last_msg = NULL;
@@ -908,7 +909,7 @@ static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg)
return 0;
}
-static int read_telegram(struct r3964_info *pInfo, pid_t pid, unsigned char __user *buf)
+static int read_telegram(struct r3964_info *pInfo, struct pid *pid, unsigned char __user *buf)
{
struct r3964_client_info *pClient;
struct r3964_block_header *block;
@@ -1005,7 +1006,7 @@ queue_the_message:
/* Send SIGIO signal to client process: */
if(pClient->sig_flags & R3964_USE_SIGIO)
{
- kill_proc(pClient->pid, SIGIO, 1);
+ kill_pid(pClient->pid, SIGIO, 1);
}
}
@@ -1042,7 +1043,7 @@ static void remove_client_block(struct r3964_info *pInfo,
{
struct r3964_block_header *block;
- TRACE_PS("remove_client_block PID %d", pClient->pid);
+ TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
block=pClient->next_block_to_read;
if(block)
@@ -1157,6 +1158,7 @@ static void r3964_close(struct tty_struct *tty)
TRACE_M("r3964_close - msg kfree %p",pMsg);
}
}
+ put_pid(pClient->pid);
kfree(pClient);
TRACE_M("r3964_close - client kfree %p",pClient);
pClient=pNext;
@@ -1193,12 +1195,11 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
struct r3964_client_message theMsg;
DECLARE_WAITQUEUE (wait, current);
- int pid = current->pid;
int count;
TRACE_L("read()");
- pClient=findClient(pInfo, pid);
+ pClient=findClient(pInfo, task_pid(current));
if(pClient)
{
pMsg = remove_msg(pInfo, pClient);
@@ -1252,7 +1253,6 @@ static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
struct r3964_block_header *pHeader;
struct r3964_client_info *pClient;
unsigned char *new_data;
- int pid;
TRACE_L("write request, %d characters", count);
/*
@@ -1295,9 +1295,7 @@ static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
pHeader->locks = 0;
pHeader->owner = NULL;
- pid=current->pid;
-
- pClient=findClient(pInfo, pid);
+ pClient=findClient(pInfo, task_pid(current));
if(pClient)
{
pHeader->owner = pClient;
@@ -1328,7 +1326,7 @@ static int r3964_ioctl(struct tty_struct * tty, struct file * file,
switch(cmd)
{
case R3964_ENABLE_SIGNALS:
- return enable_signals(pInfo, current->pid, arg);
+ return enable_signals(pInfo, task_pid(current), arg);
case R3964_SETPRIORITY:
if(arg<R3964_MASTER || arg>R3964_SLAVE)
return -EINVAL;
@@ -1341,13 +1339,13 @@ static int r3964_ioctl(struct tty_struct * tty, struct file * file,
pInfo->flags &= ~R3964_BCC;
return 0;
case R3964_READ_TELEGRAM:
- return read_telegram(pInfo, current->pid, (unsigned char __user *)arg);
+ return read_telegram(pInfo, task_pid(current), (unsigned char __user *)arg);
default:
return -ENOIOCTLCMD;
}
}
-static void r3964_set_termios(struct tty_struct *tty, struct termios * old)
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios * old)
{
TRACE_L("set_termios");
}
@@ -1357,7 +1355,6 @@ static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
struct poll_table_struct *wait)
{
struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
- int pid=current->pid;
struct r3964_client_info *pClient;
struct r3964_message *pMsg=NULL;
unsigned long flags;
@@ -1365,7 +1362,7 @@ static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
TRACE_L("POLL");
- pClient=findClient(pInfo,pid);
+ pClient=findClient(pInfo, task_pid(current));
if(pClient)
{
poll_wait(file, &pInfo->read_wait, wait);
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 603b9ade5eb..2bdb0144a22 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -994,7 +994,7 @@ int is_ignored(int sig)
* when the ldisc is closed.
*/
-static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
+static void n_tty_set_termios(struct tty_struct *tty, struct ktermios * old)
{
if (!tty)
return;
@@ -1151,7 +1151,6 @@ static int copy_from_read_buf(struct tty_struct *tty,
n = min(*nr, n);
spin_unlock_irqrestore(&tty->read_lock, flags);
if (n) {
- mb();
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
n -= retval;
spin_lock_irqsave(&tty->read_lock, flags);
diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c
index 4d47d79bcea..808d44e9a32 100644
--- a/drivers/char/nsc_gpio.c
+++ b/drivers/char/nsc_gpio.c
@@ -41,7 +41,7 @@ void nsc_gpio_dump(struct nsc_gpio_ops *amp, unsigned index)
ssize_t nsc_gpio_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
- unsigned m = iminor(file->f_dentry->d_inode);
+ unsigned m = iminor(file->f_path.dentry->d_inode);
struct nsc_gpio_ops *amp = file->private_data;
struct device *dev = amp->dev;
size_t i;
@@ -104,7 +104,7 @@ ssize_t nsc_gpio_write(struct file *file, const char __user *data,
ssize_t nsc_gpio_read(struct file *file, char __user * buf,
size_t len, loff_t * ppos)
{
- unsigned m = iminor(file->f_dentry->d_inode);
+ unsigned m = iminor(file->f_path.dentry->d_inode);
int value;
struct nsc_gpio_ops *amp = file->private_data;
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 74d21c1c104..f108c136800 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -541,7 +541,7 @@ static int mgslpc_probe(struct pcmcia_device *link)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("mgslpc_attach\n");
- info = (MGSLPC_INFO *)kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
+ info = kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
if (!info) {
printk("Error can't allocate device instance data\n");
return -ENOMEM;
@@ -2375,7 +2375,7 @@ static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
* tty pointer to tty structure
* termios pointer to buffer to hold returned old termios
*/
-static void mgslpc_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index c1e3dd837fc..4abd1eff61d 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -106,7 +106,7 @@ static inline void pp_enable_irq (struct pp_struct *pp)
static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
loff_t * ppos)
{
- unsigned int minor = iminor(file->f_dentry->d_inode);
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct pp_struct *pp = file->private_data;
char * kbuffer;
ssize_t bytes_read = 0;
@@ -189,7 +189,7 @@ static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
static ssize_t pp_write (struct file * file, const char __user * buf,
size_t count, loff_t * ppos)
{
- unsigned int minor = iminor(file->f_dentry->d_inode);
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct pp_struct *pp = file->private_data;
char * kbuffer;
ssize_t bytes_written = 0;
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 80d3eedd7f9..c07a1b5cd05 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -218,7 +218,7 @@ out:
return retval;
}
-static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
tty->termios->c_cflag &= ~(CSIZE | PARENB);
tty->termios->c_cflag |= (CS8 | CREAD);
@@ -272,6 +272,8 @@ static void __init legacy_pty_init(void)
pty_driver->init_termios.c_oflag = 0;
pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pty_driver->init_termios.c_lflag = 0;
+ pty_driver->init_termios.c_ispeed = 38400;
+ pty_driver->init_termios.c_ospeed = 38400;
pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
pty_driver->other = pty_slave_driver;
tty_set_operations(pty_driver, &pty_ops);
@@ -286,6 +288,8 @@ static void __init legacy_pty_init(void)
pty_slave_driver->subtype = PTY_TYPE_SLAVE;
pty_slave_driver->init_termios = tty_std_termios;
pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+ pty_slave_driver->init_termios.c_ispeed = 38400;
+ pty_slave_driver->init_termios.c_ospeed = 38400;
pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW;
pty_slave_driver->other = pty_driver;
@@ -366,6 +370,8 @@ static void __init unix98_pty_init(void)
ptm_driver->init_termios.c_oflag = 0;
ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
ptm_driver->init_termios.c_lflag = 0;
+ ptm_driver->init_termios.c_ispeed = 38400;
+ ptm_driver->init_termios.c_ospeed = 38400;
ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
@@ -381,6 +387,8 @@ static void __init unix98_pty_init(void)
pts_driver->subtype = PTY_TYPE_SLAVE;
pts_driver->init_termios = tty_std_termios;
pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+ pts_driver->init_termios.c_ispeed = 38400;
+ pts_driver->init_termios.c_ospeed = 38400;
pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
pts_driver->other = ptm_driver;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 4c6782a1ecd..13d0b1350a6 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1048,7 +1048,7 @@ random_write(struct file * file, const char __user * buffer,
if (p == buffer) {
return (ssize_t)ret;
} else {
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
inode->i_mtime = current_fs_time(inode->i_sb);
mark_inode_dirty(inode);
return (ssize_t)(p - buffer);
@@ -1203,7 +1203,7 @@ static int proc_do_uuid(ctl_table *table, int write, struct file *filp,
static int uuid_strategy(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
unsigned char tmp_uuid[16], *uuid;
unsigned int len;
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 3b32313f6eb..645e20a06ec 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -75,7 +75,7 @@ static int raw_open(struct inode *inode, struct file *filp)
filp->f_flags |= O_DIRECT;
filp->f_mapping = bdev->bd_inode->i_mapping;
if (++raw_devices[minor].inuse == 1)
- filp->f_dentry->d_inode->i_mapping =
+ filp->f_path.dentry->d_inode->i_mapping =
bdev->bd_inode->i_mapping;
filp->private_data = bdev;
mutex_unlock(&raw_mutex);
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index 167ebc84e8d..245f03195b7 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -556,7 +556,7 @@ struct CmdBlk *RIOGetCmdBlk(void)
{
struct CmdBlk *CmdBlkP;
- CmdBlkP = (struct CmdBlk *)kmalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
+ CmdBlkP = kmalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
if (CmdBlkP)
memset(CmdBlkP, 0, sizeof(struct CmdBlk));
return CmdBlkP;
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 0a77bfcd5b5..e2a94bfb2a4 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -1539,7 +1539,7 @@ static void rc_hangup(struct tty_struct * tty)
wake_up_interruptible(&port->open_wait);
}
-static void rc_set_termios(struct tty_struct * tty, struct termios * old_termios)
+static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termios)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
unsigned long flags;
@@ -1614,6 +1614,8 @@ static inline int rc_init_drivers(void)
riscom_driver->init_termios = tty_std_termios;
riscom_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ riscom_driver->init_termios.c_ispeed = 9600;
+ riscom_driver->init_termios.c_ospeed = 9600;
riscom_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(riscom_driver, &riscom_ops);
if ((error = tty_register_driver(riscom_driver))) {
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index bac80056f7e..e94a62e30fc 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -712,7 +712,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
* user mode into the driver (exception handler). *info CD manipulation is spinlock protected.
*/
static void configure_r_port(struct r_port *info,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
unsigned cflag;
unsigned long flags;
@@ -1017,7 +1017,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
/*
* Info->count is now 1; so it's safe to sleep now.
*/
- info->session = current->signal->session;
+ info->session = process_session(current);
info->pgrp = process_group(current);
if ((info->flags & ROCKET_INITIALIZED) == 0) {
@@ -1194,7 +1194,7 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
}
static void rp_set_termios(struct tty_struct *tty,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct r_port *info = (struct r_port *) tty->driver_data;
CHANNEL_t *cp;
@@ -2214,7 +2214,7 @@ static int __init init_PCI(int boards_found)
int count = 0;
/* Work through the PCI device list, pulling out ours */
- while ((dev = pci_find_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) {
+ while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) {
if (register_PCI(count + boards_found, dev))
count++;
}
@@ -2436,6 +2436,8 @@ static int __init rp_init(void)
rocket_driver->init_termios = tty_std_termios;
rocket_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ rocket_driver->init_termios.c_ispeed = 9600;
+ rocket_driver->init_termios.c_ospeed = 9600;
#ifdef ROCKET_SOFT_FLOW
rocket_driver->flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
#endif
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 66a7385bc34..664f36c98e6 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -113,7 +113,12 @@ 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) {return 0;}
+#ifdef RTC_IRQ
+static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
+{
+ return 0;
+}
+#endif
#else
extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
#endif
@@ -165,7 +170,9 @@ static void mask_rtc_irq_bit(unsigned char bit)
}
#endif
+#ifdef CONFIG_PROC_FS
static int rtc_proc_open(struct inode *inode, struct file *file);
+#endif
/*
* Bits in rtc_status. (6 bits of room for future expansion)
@@ -906,6 +913,7 @@ static struct miscdevice rtc_dev = {
.fops = &rtc_fops,
};
+#ifdef CONFIG_PROC_FS
static const struct file_operations rtc_proc_fops = {
.owner = THIS_MODULE,
.open = rtc_proc_open,
@@ -913,14 +921,13 @@ static const struct file_operations rtc_proc_fops = {
.llseek = seq_lseek,
.release = single_release,
};
-
-#if defined(RTC_IRQ) && !defined(__sparc__)
-static irq_handler_t rtc_int_handler_ptr;
#endif
static int __init rtc_init(void)
{
+#ifdef CONFIG_PROC_FS
struct proc_dir_entry *ent;
+#endif
#if defined(__alpha__) || defined(__mips__)
unsigned int year, ctrl;
char *guess = NULL;
@@ -932,9 +939,11 @@ static int __init rtc_init(void)
struct sparc_isa_bridge *isa_br;
struct sparc_isa_device *isa_dev;
#endif
-#endif
-#ifndef __sparc__
+#else
void *r;
+#ifdef RTC_IRQ
+ irq_handler_t rtc_int_handler_ptr;
+#endif
#endif
#ifdef __sparc__
@@ -958,6 +967,7 @@ static int __init rtc_init(void)
}
}
#endif
+ rtc_has_irq = 0;
printk(KERN_ERR "rtc_init: no PC rtc found\n");
return -EIO;
@@ -972,6 +982,7 @@ found:
* PCI Slot 2 INTA# (and some INTx# in Slot 1).
*/
if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", (void *)&rtc_port)) {
+ rtc_has_irq = 0;
printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq);
return -EIO;
}
@@ -982,6 +993,9 @@ no_irq:
else
r = request_mem_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
if (!r) {
+#ifdef RTC_IRQ
+ rtc_has_irq = 0;
+#endif
printk(KERN_ERR "rtc: I/O resource %lx is not free.\n",
(long)(RTC_PORT(0)));
return -EIO;
@@ -996,6 +1010,7 @@ no_irq:
if(request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, "rtc", NULL)) {
/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
+ rtc_has_irq = 0;
printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
if (RTC_IOMAPPED)
release_region(RTC_PORT(0), RTC_IO_EXTENT);
@@ -1012,21 +1027,19 @@ no_irq:
if (misc_register(&rtc_dev)) {
#ifdef RTC_IRQ
free_irq(RTC_IRQ, NULL);
+ rtc_has_irq = 0;
#endif
release_region(RTC_PORT(0), RTC_IO_EXTENT);
return -ENODEV;
}
+#ifdef CONFIG_PROC_FS
ent = create_proc_entry("driver/rtc", 0, NULL);
- if (!ent) {
-#ifdef RTC_IRQ
- free_irq(RTC_IRQ, NULL);
+ if (ent)
+ ent->proc_fops = &rtc_proc_fops;
+ else
+ printk(KERN_WARNING "rtc: Failed to register with procfs.\n");
#endif
- release_region(RTC_PORT(0), RTC_IO_EXTENT);
- misc_deregister(&rtc_dev);
- return -ENOMEM;
- }
- ent->proc_fops = &rtc_proc_fops;
#if defined(__alpha__) || defined(__mips__)
rtc_freq = HZ;
@@ -1159,6 +1172,7 @@ static void rtc_dropped_irq(unsigned long data)
}
#endif
+#ifdef CONFIG_PROC_FS
/*
* Info exported via "/proc/driver/rtc".
*/
@@ -1243,6 +1257,7 @@ static int rtc_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, rtc_proc_show, NULL);
}
+#endif
void rtc_get_rtc_time(struct rtc_time *rtc_tm)
{
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
index 4217d38caef..75de5f66517 100644
--- a/drivers/char/ser_a2232.c
+++ b/drivers/char/ser_a2232.c
@@ -695,6 +695,8 @@ static int a2232_init_drivers(void)
a2232_driver->init_termios = tty_std_termios;
a2232_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ a2232_driver->init_termios.c_ispeed = 9600;
+ a2232_driver->init_termios.c_ospeed = 9600;
a2232_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(a2232_driver, &a2232_ops);
if ((error = tty_register_driver(a2232_driver))) {
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 9ba13af234b..af50d32ae2c 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -1695,7 +1695,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
static void
-cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
+cy_set_termios(struct tty_struct *tty, struct ktermios * old_termios)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index fc87070f186..17d54e1331b 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -979,7 +979,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
}
if (ret > 0) {
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
inode->i_atime = current_fs_time(inode->i_sb);
}
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 99137ab66b6..20946f5127e 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -2311,7 +2311,7 @@ static void sx_hangup(struct tty_struct * tty)
}
-static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios)
+static void sx_set_termios(struct tty_struct * tty, struct ktermios * old_termios)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
@@ -2400,6 +2400,8 @@ static int sx_init_drivers(void)
specialix_driver->init_termios = tty_std_termios;
specialix_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ specialix_driver->init_termios.c_ispeed = 9600;
+ specialix_driver->init_termios.c_ospeed = 9600;
specialix_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(specialix_driver, &sx_ops);
@@ -2475,7 +2477,7 @@ static int __init specialix_init(void)
i++;
continue;
}
- pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
+ pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX,
PCI_DEVICE_ID_SPECIALIX_IO8,
pdev);
if (!pdev) break;
@@ -2491,6 +2493,9 @@ static int __init specialix_init(void)
if (!sx_probe(&sx_board[i]))
found ++;
}
+ /* May exit pci_get sequence early with lots of boards */
+ if (pdev != NULL)
+ pci_dev_put(pdev);
}
#endif
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 5e2de62bce7..e45113a7a47 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -41,13 +41,12 @@
#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/ctype.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#ifdef CONFIG_PCI
#include <linux/pci.h>
-#endif
/*****************************************************************************/
@@ -63,45 +62,16 @@
#define BRD_ECH64PCI 27
#define BRD_EASYIOPCI 28
-/*
- * Define a configuration structure to hold the board configuration.
- * Need to set this up in the code (for now) with the boards that are
- * to be configured into the system. This is what needs to be modified
- * when adding/removing/modifying boards. Each line entry in the
- * stl_brdconf[] array is a board. Each line contains io/irq/memory
- * ranges for that board (as well as what type of board it is).
- * Some examples:
- * { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },
- * This line would configure an EasyIO board (4 or 8, no difference),
- * at io address 2a0 and irq 10.
- * Another example:
- * { BRD_ECH, 0x2a8, 0x280, 0, 12, 0 },
- * This line will configure an EasyConnection 8/32 board at primary io
- * address 2a8, secondary io address 280 and irq 12.
- * Enter as many lines into this array as you want (only the first 4
- * will actually be used!). Any combination of EasyIO and EasyConnection
- * boards can be specified. EasyConnection 8/32 boards can share their
- * secondary io addresses between each other.
- *
- * NOTE: there is no need to put any entries in this table for PCI
- * boards. They will be found automatically by the driver - provided
- * PCI BIOS32 support is compiled into the kernel.
- */
-
-typedef struct {
- int brdtype;
+struct stlconf {
+ unsigned int brdtype;
int ioaddr1;
int ioaddr2;
unsigned long memaddr;
int irq;
int irqtype;
-} stlconf_t;
-
-static stlconf_t stl_brdconf[] = {
- /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/
};
-static int stl_nrbrds = ARRAY_SIZE(stl_brdconf);
+static unsigned int stl_nrbrds;
/*****************************************************************************/
@@ -143,34 +113,30 @@ static struct tty_driver *stl_serial;
* with this termios initially. Basically all it defines is a raw port
* at 9600, 8 data bits, 1 stop bit.
*/
-static struct termios stl_deftermios = {
+static struct ktermios stl_deftermios = {
.c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
.c_cc = INIT_C_CC,
+ .c_ispeed = 9600,
+ .c_ospeed = 9600,
};
/*
- * Define global stats structures. Not used often, and can be
- * re-used for each stats call.
- */
-static comstats_t stl_comstats;
-static combrd_t stl_brdstats;
-static stlbrd_t stl_dummybrd;
-static stlport_t stl_dummyport;
-
-/*
* Define global place to put buffer overflow characters.
*/
static char stl_unwanted[SC26198_RXFIFOSIZE];
/*****************************************************************************/
-static stlbrd_t *stl_brds[STL_MAXBRDS];
+static DEFINE_MUTEX(stl_brdslock);
+static struct stlbrd *stl_brds[STL_MAXBRDS];
/*
* Per board state flags. Used with the state field of the board struct.
* Not really much here!
*/
#define BRD_FOUND 0x1
+#define STL_PROBED 0x2
+
/*
* Define the port structure istate flags. These set of flags are
@@ -187,32 +153,32 @@ static stlbrd_t *stl_brds[STL_MAXBRDS];
* referencing boards when printing trace and stuff.
*/
static char *stl_brdnames[] = {
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
"EasyIO",
"EC8/32-AT",
"EC8/32-MC",
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
+ NULL,
+ NULL,
+ NULL,
"EC8/32-PCI",
"EC8/64-PCI",
"EasyIO-PCI",
@@ -225,7 +191,7 @@ static char *stl_brdnames[] = {
* load line. These allow for easy board definitions, and easy
* modification of the io, memory and irq resoucres.
*/
-static int stl_nargs = 0;
+static unsigned int stl_nargs;
static char *board0[4];
static char *board1[4];
static char *board2[4];
@@ -243,12 +209,10 @@ static char **stl_brdsp[] = {
* parse any module arguments.
*/
-typedef struct stlbrdtype {
+static struct {
char *name;
int type;
-} stlbrdtype_t;
-
-static stlbrdtype_t stl_brdstr[] = {
+} stl_brdstr[] = {
{ "easyio", BRD_EASYIO },
{ "eio", BRD_EASYIO },
{ "20", BRD_EASYIO },
@@ -282,9 +246,6 @@ static stlbrdtype_t stl_brdstr[] = {
/*
* Define the module agruments.
*/
-MODULE_AUTHOR("Greg Ungerer");
-MODULE_DESCRIPTION("Stallion Multiport Serial Driver");
-MODULE_LICENSE("GPL");
module_param_array(board0, charp, &stl_nargs, 0);
MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]");
@@ -386,8 +347,6 @@ static spinlock_t stallion_lock; /* Guard the tty driver */
/*****************************************************************************/
-#ifdef CONFIG_PCI
-
/*
* Define the Stallion PCI vendor and device IDs.
*/
@@ -407,22 +366,19 @@ static spinlock_t stallion_lock; /* Guard the tty driver */
/*
* Define structure to hold all Stallion PCI boards.
*/
-typedef struct stlpcibrd {
- unsigned short vendid;
- unsigned short devid;
- int brdtype;
-} stlpcibrd_t;
-
-static stlpcibrd_t stl_pcibrds[] = {
- { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864, BRD_ECH64PCI },
- { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI, BRD_EASYIOPCI },
- { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832, BRD_ECHPCI },
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, BRD_ECHPCI },
-};
-
-static int stl_nrpcibrds = ARRAY_SIZE(stl_pcibrds);
-#endif
+static struct pci_device_id stl_pcibrds[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864),
+ .driver_data = BRD_ECH64PCI },
+ { PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI),
+ .driver_data = BRD_EASYIOPCI },
+ { PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832),
+ .driver_data = BRD_ECHPCI },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410),
+ .driver_data = BRD_ECHPCI },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, stl_pcibrds);
/*****************************************************************************/
@@ -442,134 +398,74 @@ static unsigned int stl_baudrates[] = {
9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
};
-/*
- * Define some handy local macros...
- */
-#undef MIN
-#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
-
-#undef TOLOWER
-#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x))
-
/*****************************************************************************/
/*
* Declare all those functions in this driver!
*/
-static void stl_argbrds(void);
-static int stl_parsebrd(stlconf_t *confp, char **argp);
-
-static unsigned long stl_atol(char *str);
-
-static int stl_init(void);
-static int stl_open(struct tty_struct *tty, struct file *filp);
-static void stl_close(struct tty_struct *tty, struct file *filp);
-static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count);
-static void stl_putchar(struct tty_struct *tty, unsigned char ch);
-static void stl_flushchars(struct tty_struct *tty);
-static int stl_writeroom(struct tty_struct *tty);
-static int stl_charsinbuffer(struct tty_struct *tty);
-static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static void stl_settermios(struct tty_struct *tty, struct termios *old);
-static void stl_throttle(struct tty_struct *tty);
-static void stl_unthrottle(struct tty_struct *tty);
-static void stl_stop(struct tty_struct *tty);
-static void stl_start(struct tty_struct *tty);
-static void stl_flushbuffer(struct tty_struct *tty);
-static void stl_breakctl(struct tty_struct *tty, int state);
-static void stl_waituntilsent(struct tty_struct *tty, int timeout);
-static void stl_sendxchar(struct tty_struct *tty, char ch);
-static void stl_hangup(struct tty_struct *tty);
static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
-static int stl_portinfo(stlport_t *portp, int portnr, char *pos);
-static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data);
-
-static int stl_brdinit(stlbrd_t *brdp);
-static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp);
-static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp);
-static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp);
-static int stl_getbrdstats(combrd_t __user *bp);
-static int stl_getportstats(stlport_t *portp, comstats_t __user *cp);
-static int stl_clrportstats(stlport_t *portp, comstats_t __user *cp);
-static int stl_getportstruct(stlport_t __user *arg);
-static int stl_getbrdstruct(stlbrd_t __user *arg);
-static int stl_waitcarrier(stlport_t *portp, struct file *filp);
-static int stl_eiointr(stlbrd_t *brdp);
-static int stl_echatintr(stlbrd_t *brdp);
-static int stl_echmcaintr(stlbrd_t *brdp);
-static int stl_echpciintr(stlbrd_t *brdp);
-static int stl_echpci64intr(stlbrd_t *brdp);
-static void stl_offintr(struct work_struct *);
-static stlbrd_t *stl_allocbrd(void);
-static stlport_t *stl_getport(int brdnr, int panelnr, int portnr);
-
-static inline int stl_initbrds(void);
-static inline int stl_initeio(stlbrd_t *brdp);
-static inline int stl_initech(stlbrd_t *brdp);
-static inline int stl_getbrdnr(void);
-
-#ifdef CONFIG_PCI
-static inline int stl_findpcibrds(void);
-static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp);
-#endif
+static int stl_brdinit(struct stlbrd *brdp);
+static int stl_getportstats(struct stlport *portp, comstats_t __user *cp);
+static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp);
+static int stl_waitcarrier(struct stlport *portp, struct file *filp);
/*
* CD1400 uart specific handling functions.
*/
-static void stl_cd1400setreg(stlport_t *portp, int regnr, int value);
-static int stl_cd1400getreg(stlport_t *portp, int regnr);
-static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value);
-static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp);
-static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp);
-static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp);
-static int stl_cd1400getsignals(stlport_t *portp);
-static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts);
-static void stl_cd1400ccrwait(stlport_t *portp);
-static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx);
-static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx);
-static void stl_cd1400disableintrs(stlport_t *portp);
-static void stl_cd1400sendbreak(stlport_t *portp, int len);
-static void stl_cd1400flowctrl(stlport_t *portp, int state);
-static void stl_cd1400sendflow(stlport_t *portp, int state);
-static void stl_cd1400flush(stlport_t *portp);
-static int stl_cd1400datastate(stlport_t *portp);
-static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase);
-static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase);
-static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr);
-static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr);
-static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr);
-
-static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr);
+static void stl_cd1400setreg(struct stlport *portp, int regnr, int value);
+static int stl_cd1400getreg(struct stlport *portp, int regnr);
+static int stl_cd1400updatereg(struct stlport *portp, int regnr, int value);
+static int stl_cd1400panelinit(struct stlbrd *brdp, struct stlpanel *panelp);
+static void stl_cd1400portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp);
+static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp);
+static int stl_cd1400getsignals(struct stlport *portp);
+static void stl_cd1400setsignals(struct stlport *portp, int dtr, int rts);
+static void stl_cd1400ccrwait(struct stlport *portp);
+static void stl_cd1400enablerxtx(struct stlport *portp, int rx, int tx);
+static void stl_cd1400startrxtx(struct stlport *portp, int rx, int tx);
+static void stl_cd1400disableintrs(struct stlport *portp);
+static void stl_cd1400sendbreak(struct stlport *portp, int len);
+static void stl_cd1400flowctrl(struct stlport *portp, int state);
+static void stl_cd1400sendflow(struct stlport *portp, int state);
+static void stl_cd1400flush(struct stlport *portp);
+static int stl_cd1400datastate(struct stlport *portp);
+static void stl_cd1400eiointr(struct stlpanel *panelp, unsigned int iobase);
+static void stl_cd1400echintr(struct stlpanel *panelp, unsigned int iobase);
+static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr);
+static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr);
+static void stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr);
+
+static inline int stl_cd1400breakisr(struct stlport *portp, int ioaddr);
/*
* SC26198 uart specific handling functions.
*/
-static void stl_sc26198setreg(stlport_t *portp, int regnr, int value);
-static int stl_sc26198getreg(stlport_t *portp, int regnr);
-static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value);
-static int stl_sc26198getglobreg(stlport_t *portp, int regnr);
-static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp);
-static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp);
-static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp);
-static int stl_sc26198getsignals(stlport_t *portp);
-static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts);
-static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx);
-static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx);
-static void stl_sc26198disableintrs(stlport_t *portp);
-static void stl_sc26198sendbreak(stlport_t *portp, int len);
-static void stl_sc26198flowctrl(stlport_t *portp, int state);
-static void stl_sc26198sendflow(stlport_t *portp, int state);
-static void stl_sc26198flush(stlport_t *portp);
-static int stl_sc26198datastate(stlport_t *portp);
-static void stl_sc26198wait(stlport_t *portp);
-static void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty);
-static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase);
-static void stl_sc26198txisr(stlport_t *port);
-static void stl_sc26198rxisr(stlport_t *port, unsigned int iack);
-static void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch);
-static void stl_sc26198rxbadchars(stlport_t *portp);
-static void stl_sc26198otherisr(stlport_t *port, unsigned int iack);
+static void stl_sc26198setreg(struct stlport *portp, int regnr, int value);
+static int stl_sc26198getreg(struct stlport *portp, int regnr);
+static int stl_sc26198updatereg(struct stlport *portp, int regnr, int value);
+static int stl_sc26198getglobreg(struct stlport *portp, int regnr);
+static int stl_sc26198panelinit(struct stlbrd *brdp, struct stlpanel *panelp);
+static void stl_sc26198portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp);
+static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp);
+static int stl_sc26198getsignals(struct stlport *portp);
+static void stl_sc26198setsignals(struct stlport *portp, int dtr, int rts);
+static void stl_sc26198enablerxtx(struct stlport *portp, int rx, int tx);
+static void stl_sc26198startrxtx(struct stlport *portp, int rx, int tx);
+static void stl_sc26198disableintrs(struct stlport *portp);
+static void stl_sc26198sendbreak(struct stlport *portp, int len);
+static void stl_sc26198flowctrl(struct stlport *portp, int state);
+static void stl_sc26198sendflow(struct stlport *portp, int state);
+static void stl_sc26198flush(struct stlport *portp);
+static int stl_sc26198datastate(struct stlport *portp);
+static void stl_sc26198wait(struct stlport *portp);
+static void stl_sc26198txunflow(struct stlport *portp, struct tty_struct *tty);
+static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase);
+static void stl_sc26198txisr(struct stlport *port);
+static void stl_sc26198rxisr(struct stlport *port, unsigned int iack);
+static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char ch);
+static void stl_sc26198rxbadchars(struct stlport *portp);
+static void stl_sc26198otherisr(struct stlport *port, unsigned int iack);
/*****************************************************************************/
@@ -577,20 +473,20 @@ static void stl_sc26198otherisr(stlport_t *port, unsigned int iack);
* Generic UART support structure.
*/
typedef struct uart {
- int (*panelinit)(stlbrd_t *brdp, stlpanel_t *panelp);
- void (*portinit)(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp);
- void (*setport)(stlport_t *portp, struct termios *tiosp);
- int (*getsignals)(stlport_t *portp);
- void (*setsignals)(stlport_t *portp, int dtr, int rts);
- void (*enablerxtx)(stlport_t *portp, int rx, int tx);
- void (*startrxtx)(stlport_t *portp, int rx, int tx);
- void (*disableintrs)(stlport_t *portp);
- void (*sendbreak)(stlport_t *portp, int len);
- void (*flowctrl)(stlport_t *portp, int state);
- void (*sendflow)(stlport_t *portp, int state);
- void (*flush)(stlport_t *portp);
- int (*datastate)(stlport_t *portp);
- void (*intr)(stlpanel_t *panelp, unsigned int iobase);
+ int (*panelinit)(struct stlbrd *brdp, struct stlpanel *panelp);
+ void (*portinit)(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp);
+ void (*setport)(struct stlport *portp, struct ktermios *tiosp);
+ int (*getsignals)(struct stlport *portp);
+ void (*setsignals)(struct stlport *portp, int dtr, int rts);
+ void (*enablerxtx)(struct stlport *portp, int rx, int tx);
+ void (*startrxtx)(struct stlport *portp, int rx, int tx);
+ void (*disableintrs)(struct stlport *portp);
+ void (*sendbreak)(struct stlport *portp, int len);
+ void (*flowctrl)(struct stlport *portp, int state);
+ void (*sendflow)(struct stlport *portp, int state);
+ void (*flush)(struct stlport *portp);
+ int (*datastate)(struct stlport *portp);
+ void (*intr)(struct stlpanel *panelp, unsigned int iobase);
} uart_t;
/*
@@ -712,184 +608,35 @@ static const struct file_operations stl_fsiomem = {
.ioctl = stl_memioctl,
};
-/*****************************************************************************/
-
static struct class *stallion_class;
/*
- * Loadable module initialization stuff.
- */
-
-static int __init stallion_module_init(void)
-{
- stl_init();
- return 0;
-}
-
-/*****************************************************************************/
-
-static void __exit stallion_module_exit(void)
-{
- stlbrd_t *brdp;
- stlpanel_t *panelp;
- stlport_t *portp;
- int i, j, k;
-
-#ifdef DEBUG
- printk("cleanup_module()\n");
-#endif
-
- printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle,
- stl_drvversion);
-
-/*
- * Free up all allocated resources used by the ports. This includes
- * memory and interrupts. As part of this process we will also do
- * a hangup on every open port - to try to flush out any processes
- * hanging onto ports.
- */
- i = tty_unregister_driver(stl_serial);
- put_tty_driver(stl_serial);
- if (i) {
- printk("STALLION: failed to un-register tty driver, "
- "errno=%d\n", -i);
- return;
- }
- for (i = 0; i < 4; i++)
- class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
- if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
- printk("STALLION: failed to un-register serial memory device, "
- "errno=%d\n", -i);
- class_destroy(stallion_class);
-
- for (i = 0; (i < stl_nrbrds); i++) {
- if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL)
- continue;
-
- free_irq(brdp->irq, brdp);
-
- for (j = 0; (j < STL_MAXPANELS); j++) {
- panelp = brdp->panels[j];
- if (panelp == (stlpanel_t *) NULL)
- continue;
- for (k = 0; (k < STL_PORTSPERPANEL); k++) {
- portp = panelp->ports[k];
- if (portp == (stlport_t *) NULL)
- continue;
- if (portp->tty != (struct tty_struct *) NULL)
- stl_hangup(portp->tty);
- kfree(portp->tx.buf);
- kfree(portp);
- }
- kfree(panelp);
- }
-
- release_region(brdp->ioaddr1, brdp->iosize1);
- if (brdp->iosize2 > 0)
- release_region(brdp->ioaddr2, brdp->iosize2);
-
- kfree(brdp);
- stl_brds[i] = (stlbrd_t *) NULL;
- }
-}
-
-module_init(stallion_module_init);
-module_exit(stallion_module_exit);
-
-/*****************************************************************************/
-
-/*
* Check for any arguments passed in on the module load command line.
*/
-static void stl_argbrds(void)
-{
- stlconf_t conf;
- stlbrd_t *brdp;
- int i;
-
-#ifdef DEBUG
- printk("stl_argbrds()\n");
-#endif
-
- for (i = stl_nrbrds; (i < stl_nargs); i++) {
- memset(&conf, 0, sizeof(conf));
- if (stl_parsebrd(&conf, stl_brdsp[i]) == 0)
- continue;
- if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
- continue;
- stl_nrbrds = i + 1;
- brdp->brdnr = i;
- brdp->brdtype = conf.brdtype;
- brdp->ioaddr1 = conf.ioaddr1;
- brdp->ioaddr2 = conf.ioaddr2;
- brdp->irq = conf.irq;
- brdp->irqtype = conf.irqtype;
- stl_brdinit(brdp);
- }
-}
-
-/*****************************************************************************/
-
-/*
- * Convert an ascii string number into an unsigned long.
- */
-
-static unsigned long stl_atol(char *str)
-{
- unsigned long val;
- int base, c;
- char *sp;
-
- val = 0;
- sp = str;
- if ((*sp == '0') && (*(sp+1) == 'x')) {
- base = 16;
- sp += 2;
- } else if (*sp == '0') {
- base = 8;
- sp++;
- } else {
- base = 10;
- }
-
- for (; (*sp != 0); sp++) {
- c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0');
- if ((c < 0) || (c >= base)) {
- printk("STALLION: invalid argument %s\n", str);
- val = 0;
- break;
- }
- val = (val * base) + c;
- }
- return val;
-}
-
/*****************************************************************************/
/*
* Parse the supplied argument string, into the board conf struct.
*/
-static int stl_parsebrd(stlconf_t *confp, char **argp)
+static int __init stl_parsebrd(struct stlconf *confp, char **argp)
{
char *sp;
- int i;
+ unsigned int i;
-#ifdef DEBUG
- printk("stl_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp);
-#endif
+ pr_debug("stl_parsebrd(confp=%p,argp=%p)\n", confp, argp);
- if ((argp[0] == (char *) NULL) || (*argp[0] == 0))
+ if ((argp[0] == NULL) || (*argp[0] == 0))
return 0;
- for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++)
- *sp = TOLOWER(*sp);
+ for (sp = argp[0], i = 0; (*sp != 0) && (i < 25); sp++, i++)
+ *sp = tolower(*sp);
- for (i = 0; i < ARRAY_SIZE(stl_brdstr); i++) {
+ for (i = 0; i < ARRAY_SIZE(stl_brdstr); i++)
if (strcmp(stl_brdstr[i].name, argp[0]) == 0)
break;
- }
+
if (i == ARRAY_SIZE(stl_brdstr)) {
printk("STALLION: unknown board name, %s?\n", argp[0]);
return 0;
@@ -898,16 +645,16 @@ static int stl_parsebrd(stlconf_t *confp, char **argp)
confp->brdtype = stl_brdstr[i].type;
i = 1;
- if ((argp[i] != (char *) NULL) && (*argp[i] != 0))
- confp->ioaddr1 = stl_atol(argp[i]);
+ if ((argp[i] != NULL) && (*argp[i] != 0))
+ confp->ioaddr1 = simple_strtoul(argp[i], NULL, 0);
i++;
if (confp->brdtype == BRD_ECH) {
- if ((argp[i] != (char *) NULL) && (*argp[i] != 0))
- confp->ioaddr2 = stl_atol(argp[i]);
+ if ((argp[i] != NULL) && (*argp[i] != 0))
+ confp->ioaddr2 = simple_strtoul(argp[i], NULL, 0);
i++;
}
- if ((argp[i] != (char *) NULL) && (*argp[i] != 0))
- confp->irq = stl_atol(argp[i]);
+ if ((argp[i] != NULL) && (*argp[i] != 0))
+ confp->irq = simple_strtoul(argp[i], NULL, 0);
return 1;
}
@@ -917,14 +664,14 @@ static int stl_parsebrd(stlconf_t *confp, char **argp)
* Allocate a new board structure. Fill out the basic info in it.
*/
-static stlbrd_t *stl_allocbrd(void)
+static struct stlbrd *stl_allocbrd(void)
{
- stlbrd_t *brdp;
+ struct stlbrd *brdp;
- brdp = kzalloc(sizeof(stlbrd_t), GFP_KERNEL);
+ brdp = kzalloc(sizeof(struct stlbrd), GFP_KERNEL);
if (!brdp) {
printk("STALLION: failed to allocate memory (size=%Zd)\n",
- sizeof(stlbrd_t));
+ sizeof(struct stlbrd));
return NULL;
}
@@ -936,26 +683,23 @@ static stlbrd_t *stl_allocbrd(void)
static int stl_open(struct tty_struct *tty, struct file *filp)
{
- stlport_t *portp;
- stlbrd_t *brdp;
- unsigned int minordev;
- int brdnr, panelnr, portnr, rc;
-
-#ifdef DEBUG
- printk("stl_open(tty=%x,filp=%x): device=%s\n", (int) tty,
- (int) filp, tty->name);
-#endif
+ struct stlport *portp;
+ struct stlbrd *brdp;
+ unsigned int minordev, brdnr, panelnr;
+ int portnr, rc;
+
+ pr_debug("stl_open(tty=%p,filp=%p): device=%s\n", tty, filp, tty->name);
minordev = tty->index;
brdnr = MINOR2BRD(minordev);
if (brdnr >= stl_nrbrds)
return -ENODEV;
brdp = stl_brds[brdnr];
- if (brdp == (stlbrd_t *) NULL)
+ if (brdp == NULL)
return -ENODEV;
minordev = MINOR2PORT(minordev);
- for (portnr = -1, panelnr = 0; (panelnr < STL_MAXPANELS); panelnr++) {
- if (brdp->panels[panelnr] == (stlpanel_t *) NULL)
+ for (portnr = -1, panelnr = 0; panelnr < STL_MAXPANELS; panelnr++) {
+ if (brdp->panels[panelnr] == NULL)
break;
if (minordev < brdp->panels[panelnr]->nrports) {
portnr = minordev;
@@ -967,7 +711,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
portp = brdp->panels[panelnr]->ports[portnr];
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return -ENODEV;
/*
@@ -1013,10 +757,10 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
* previous opens still in effect. If we are a normal serial device
* then also we might have to wait for carrier.
*/
- if (!(filp->f_flags & O_NONBLOCK)) {
+ if (!(filp->f_flags & O_NONBLOCK))
if ((rc = stl_waitcarrier(portp, filp)) != 0)
return rc;
- }
+
portp->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
@@ -1029,14 +773,12 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
* maybe because if we are clocal then we don't need to wait...
*/
-static int stl_waitcarrier(stlport_t *portp, struct file *filp)
+static int stl_waitcarrier(struct stlport *portp, struct file *filp)
{
unsigned long flags;
int rc, doclocal;
-#ifdef DEBUG
- printk("stl_waitcarrier(portp=%x,filp=%x)\n", (int) portp, (int) filp);
-#endif
+ pr_debug("stl_waitcarrier(portp=%p,filp=%p)\n", portp, filp);
rc = 0;
doclocal = 0;
@@ -1062,9 +804,8 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp)
break;
}
if (((portp->flags & ASYNC_CLOSING) == 0) &&
- (doclocal || (portp->sigs & TIOCM_CD))) {
+ (doclocal || (portp->sigs & TIOCM_CD)))
break;
- }
if (signal_pending(current)) {
rc = -ERESTARTSYS;
break;
@@ -1083,17 +824,61 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp)
/*****************************************************************************/
+static void stl_flushbuffer(struct tty_struct *tty)
+{
+ struct stlport *portp;
+
+ pr_debug("stl_flushbuffer(tty=%p)\n", tty);
+
+ if (tty == NULL)
+ return;
+ portp = tty->driver_data;
+ if (portp == NULL)
+ return;
+
+ stl_flush(portp);
+ tty_wakeup(tty);
+}
+
+/*****************************************************************************/
+
+static void stl_waituntilsent(struct tty_struct *tty, int timeout)
+{
+ struct stlport *portp;
+ unsigned long tend;
+
+ pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout);
+
+ if (tty == NULL)
+ return;
+ portp = tty->driver_data;
+ if (portp == NULL)
+ return;
+
+ if (timeout == 0)
+ timeout = HZ;
+ tend = jiffies + timeout;
+
+ while (stl_datastate(portp)) {
+ if (signal_pending(current))
+ break;
+ msleep_interruptible(20);
+ if (time_after_eq(jiffies, tend))
+ break;
+ }
+}
+
+/*****************************************************************************/
+
static void stl_close(struct tty_struct *tty, struct file *filp)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_close(tty=%x,filp=%x)\n", (int) tty, (int) filp);
-#endif
+ pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp);
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
spin_lock_irqsave(&stallion_lock, flags);
@@ -1136,17 +921,17 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
stl_enablerxtx(portp, 0, 0);
stl_flushbuffer(tty);
portp->istate = 0;
- if (portp->tx.buf != (char *) NULL) {
+ if (portp->tx.buf != NULL) {
kfree(portp->tx.buf);
- portp->tx.buf = (char *) NULL;
- portp->tx.head = (char *) NULL;
- portp->tx.tail = (char *) NULL;
+ portp->tx.buf = NULL;
+ portp->tx.head = NULL;
+ portp->tx.tail = NULL;
}
set_bit(TTY_IO_ERROR, &tty->flags);
tty_ldisc_flush(tty);
tty->closing = 0;
- portp->tty = (struct tty_struct *) NULL;
+ portp->tty = NULL;
if (portp->openwaitcnt) {
if (portp->close_delay)
@@ -1167,20 +952,17 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int len, stlen;
unsigned char *chbuf;
char *head, *tail;
-#ifdef DEBUG
- printk("stl_write(tty=%x,buf=%x,count=%d)\n",
- (int) tty, (int) buf, count);
-#endif
+ pr_debug("stl_write(tty=%p,buf=%p,count=%d)\n", tty, buf, count);
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return 0;
- if (portp->tx.buf == (char *) NULL)
+ if (portp->tx.buf == NULL)
return 0;
/*
@@ -1201,10 +983,10 @@ static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count
stlen = len;
}
- len = MIN(len, count);
+ len = min(len, (unsigned int)count);
count = 0;
while (len > 0) {
- stlen = MIN(len, stlen);
+ stlen = min(len, stlen);
memcpy(head, chbuf, stlen);
len -= stlen;
chbuf += stlen;
@@ -1227,20 +1009,18 @@ static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count
static void stl_putchar(struct tty_struct *tty, unsigned char ch)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int len;
char *head, *tail;
-#ifdef DEBUG
- printk("stl_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch);
-#endif
+ pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
- if (portp->tx.buf == (char *) NULL)
+ if (portp->tx.buf == NULL)
return;
head = portp->tx.head;
@@ -1267,18 +1047,16 @@ static void stl_putchar(struct tty_struct *tty, unsigned char ch)
static void stl_flushchars(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_flushchars(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_flushchars(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
- if (portp->tx.buf == (char *) NULL)
+ if (portp->tx.buf == NULL)
return;
stl_startrxtx(portp, -1, 1);
@@ -1288,24 +1066,22 @@ static void stl_flushchars(struct tty_struct *tty)
static int stl_writeroom(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
char *head, *tail;
-#ifdef DEBUG
- printk("stl_writeroom(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_writeroom(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return 0;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return 0;
- if (portp->tx.buf == (char *) NULL)
+ if (portp->tx.buf == NULL)
return 0;
head = portp->tx.head;
tail = portp->tx.tail;
- return ((head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1));
+ return (head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1);
}
/*****************************************************************************/
@@ -1321,20 +1097,18 @@ static int stl_writeroom(struct tty_struct *tty)
static int stl_charsinbuffer(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int size;
char *head, *tail;
-#ifdef DEBUG
- printk("stl_charsinbuffer(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_charsinbuffer(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return 0;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return 0;
- if (portp->tx.buf == (char *) NULL)
+ if (portp->tx.buf == NULL)
return 0;
head = portp->tx.head;
@@ -1351,14 +1125,12 @@ static int stl_charsinbuffer(struct tty_struct *tty)
* Generate the serial struct info.
*/
-static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp)
+static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp)
{
struct serial_struct sio;
- stlbrd_t *brdp;
+ struct stlbrd *brdp;
-#ifdef DEBUG
- printk("stl_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);
-#endif
+ pr_debug("stl_getserial(portp=%p,sp=%p)\n", portp, sp);
memset(&sio, 0, sizeof(struct serial_struct));
sio.line = portp->portnr;
@@ -1378,7 +1150,7 @@ static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp)
}
brdp = stl_brds[portp->brdnr];
- if (brdp != (stlbrd_t *) NULL)
+ if (brdp != NULL)
sio.irq = brdp->irq;
return copy_to_user(sp, &sio, sizeof(struct serial_struct)) ? -EFAULT : 0;
@@ -1392,13 +1164,11 @@ static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp)
* just quietly ignore any requests to change irq, etc.
*/
-static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp)
+static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
{
struct serial_struct sio;
-#ifdef DEBUG
- printk("stl_setserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);
-#endif
+ pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp);
if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
return -EFAULT;
@@ -1424,12 +1194,12 @@ static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp)
static int stl_tiocmget(struct tty_struct *tty, struct file *file)
{
- stlport_t *portp;
+ struct stlport *portp;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return -ENODEV;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -1440,13 +1210,13 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file)
static int stl_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- stlport_t *portp;
+ struct stlport *portp;
int rts = -1, dtr = -1;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return -ENODEV;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -1466,27 +1236,24 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file,
static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int ival;
int rc;
void __user *argp = (void __user *)arg;
-#ifdef DEBUG
- printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n",
- (int) tty, (int) file, cmd, (int) arg);
-#endif
+ pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd,
+ arg);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return -ENODEV;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return -ENODEV;
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) {
+ (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS))
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
- }
rc = 0;
@@ -1531,19 +1298,37 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
/*****************************************************************************/
-static void stl_settermios(struct tty_struct *tty, struct termios *old)
+/*
+ * Start the transmitter again. Just turn TX interrupts back on.
+ */
+
+static void stl_start(struct tty_struct *tty)
{
- stlport_t *portp;
- struct termios *tiosp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_settermios(tty=%x,old=%x)\n", (int) tty, (int) old);
-#endif
+ pr_debug("stl_start(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
+ return;
+ stl_startrxtx(portp, -1, 1);
+}
+
+/*****************************************************************************/
+
+static void stl_settermios(struct tty_struct *tty, struct ktermios *old)
+{
+ struct stlport *portp;
+ struct ktermios *tiosp;
+
+ pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old);
+
+ if (tty == NULL)
+ return;
+ portp = tty->driver_data;
+ if (portp == NULL)
return;
tiosp = tty->termios;
@@ -1571,16 +1356,14 @@ static void stl_settermios(struct tty_struct *tty, struct termios *old)
static void stl_throttle(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_throttle(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_throttle(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
stl_flowctrl(portp, 0);
}
@@ -1593,16 +1376,14 @@ static void stl_throttle(struct tty_struct *tty)
static void stl_unthrottle(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_unthrottle(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_unthrottle(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
stl_flowctrl(portp, 1);
}
@@ -1616,16 +1397,14 @@ static void stl_unthrottle(struct tty_struct *tty)
static void stl_stop(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_stop(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_stop(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
stl_startrxtx(portp, -1, 0);
}
@@ -1633,28 +1412,6 @@ static void stl_stop(struct tty_struct *tty)
/*****************************************************************************/
/*
- * Start the transmitter again. Just turn TX interrupts back on.
- */
-
-static void stl_start(struct tty_struct *tty)
-{
- stlport_t *portp;
-
-#ifdef DEBUG
- printk("stl_start(tty=%x)\n", (int) tty);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return;
- portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
- return;
- stl_startrxtx(portp, -1, 1);
-}
-
-/*****************************************************************************/
-
-/*
* Hangup this port. This is pretty much like closing the port, only
* a little more brutal. No waiting for data to drain. Shutdown the
* port and maybe drop signals.
@@ -1662,16 +1419,14 @@ static void stl_start(struct tty_struct *tty)
static void stl_hangup(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_hangup(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_hangup(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
portp->flags &= ~ASYNC_INITIALIZED;
@@ -1682,13 +1437,13 @@ static void stl_hangup(struct tty_struct *tty)
stl_flushbuffer(tty);
portp->istate = 0;
set_bit(TTY_IO_ERROR, &tty->flags);
- if (portp->tx.buf != (char *) NULL) {
+ if (portp->tx.buf != NULL) {
kfree(portp->tx.buf);
- portp->tx.buf = (char *) NULL;
- portp->tx.head = (char *) NULL;
- portp->tx.tail = (char *) NULL;
+ portp->tx.buf = NULL;
+ portp->tx.head = NULL;
+ portp->tx.tail = NULL;
}
- portp->tty = (struct tty_struct *) NULL;
+ portp->tty = NULL;
portp->flags &= ~ASYNC_NORMAL_ACTIVE;
portp->refcount = 0;
wake_up_interruptible(&portp->open_wait);
@@ -1696,38 +1451,16 @@ static void stl_hangup(struct tty_struct *tty)
/*****************************************************************************/
-static void stl_flushbuffer(struct tty_struct *tty)
-{
- stlport_t *portp;
-
-#ifdef DEBUG
- printk("stl_flushbuffer(tty=%x)\n", (int) tty);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return;
- portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
- return;
-
- stl_flush(portp);
- tty_wakeup(tty);
-}
-
-/*****************************************************************************/
-
static void stl_breakctl(struct tty_struct *tty, int state)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_breakctl(tty=%x,state=%d)\n", (int) tty, state);
-#endif
+ pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
stl_sendbreak(portp, ((state == -1) ? 1 : 2));
@@ -1735,48 +1468,16 @@ static void stl_breakctl(struct tty_struct *tty, int state)
/*****************************************************************************/
-static void stl_waituntilsent(struct tty_struct *tty, int timeout)
-{
- stlport_t *portp;
- unsigned long tend;
-
-#ifdef DEBUG
- printk("stl_waituntilsent(tty=%x,timeout=%d)\n", (int) tty, timeout);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return;
- portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
- return;
-
- if (timeout == 0)
- timeout = HZ;
- tend = jiffies + timeout;
-
- while (stl_datastate(portp)) {
- if (signal_pending(current))
- break;
- msleep_interruptible(20);
- if (time_after_eq(jiffies, tend))
- break;
- }
-}
-
-/*****************************************************************************/
-
static void stl_sendxchar(struct tty_struct *tty, char ch)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch);
-#endif
+ pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
if (ch == STOP_CHAR(tty))
@@ -1797,7 +1498,7 @@ static void stl_sendxchar(struct tty_struct *tty, char ch)
* short then padded with spaces).
*/
-static int stl_portinfo(stlport_t *portp, int portnr, char *pos)
+static int stl_portinfo(struct stlport *portp, int portnr, char *pos)
{
char *sp;
int sigs, cnt;
@@ -1826,7 +1527,7 @@ static int stl_portinfo(stlport_t *portp, int portnr, char *pos)
*sp = ' ';
sp += cnt;
- for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++)
+ for (cnt = sp - pos; cnt < (MAXLINE - 1); cnt++)
*sp++ = ' ';
if (cnt >= MAXLINE)
pos[(MAXLINE - 2)] = '+';
@@ -1843,18 +1544,15 @@ static int stl_portinfo(stlport_t *portp, int portnr, char *pos)
static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- stlbrd_t *brdp;
- stlpanel_t *panelp;
- stlport_t *portp;
- int brdnr, panelnr, portnr, totalport;
- int curoff, maxoff;
+ struct stlbrd *brdp;
+ struct stlpanel *panelp;
+ struct stlport *portp;
+ unsigned int brdnr, panelnr, portnr;
+ int totalport, curoff, maxoff;
char *pos;
-#ifdef DEBUG
- printk("stl_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x,"
- "data=%x\n", (int) page, (int) start, (int) off, count,
- (int) eof, (int) data);
-#endif
+ pr_debug("stl_readproc(page=%p,start=%p,off=%lx,count=%d,eof=%p,"
+ "data=%p\n", page, start, off, count, eof, data);
pos = page;
totalport = 0;
@@ -1873,9 +1571,9 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof
* We scan through for each board, panel and port. The offset is
* calculated on the fly, and irrelevant ports are skipped.
*/
- for (brdnr = 0; (brdnr < stl_nrbrds); brdnr++) {
+ for (brdnr = 0; brdnr < stl_nrbrds; brdnr++) {
brdp = stl_brds[brdnr];
- if (brdp == (stlbrd_t *) NULL)
+ if (brdp == NULL)
continue;
if (brdp->state == 0)
continue;
@@ -1887,9 +1585,9 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof
}
totalport = brdnr * STL_MAXPORTS;
- for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) {
+ for (panelnr = 0; panelnr < brdp->nrpanels; panelnr++) {
panelp = brdp->panels[panelnr];
- if (panelp == (stlpanel_t *) NULL)
+ if (panelp == NULL)
continue;
maxoff = curoff + (panelp->nrports * MAXLINE);
@@ -1899,10 +1597,10 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof
continue;
}
- for (portnr = 0; (portnr < panelp->nrports); portnr++,
+ for (portnr = 0; portnr < panelp->nrports; portnr++,
totalport++) {
portp = panelp->ports[portnr];
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
continue;
if (off >= (curoff += MAXLINE))
continue;
@@ -1917,7 +1615,7 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof
stl_readdone:
*start = page;
- return (pos - page);
+ return pos - page;
}
/*****************************************************************************/
@@ -1929,11 +1627,9 @@ stl_readdone:
static irqreturn_t stl_intr(int irq, void *dev_id)
{
- stlbrd_t *brdp = (stlbrd_t *) dev_id;
+ struct stlbrd *brdp = dev_id;
-#ifdef DEBUG
- printk("stl_intr(brdp=%x,irq=%d)\n", (int) brdp, irq);
-#endif
+ pr_debug("stl_intr(brdp=%p,irq=%d)\n", brdp, irq);
return IRQ_RETVAL((* brdp->isr)(brdp));
}
@@ -1944,9 +1640,9 @@ static irqreturn_t stl_intr(int irq, void *dev_id)
* Interrupt service routine for EasyIO board types.
*/
-static int stl_eiointr(stlbrd_t *brdp)
+static int stl_eiointr(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
+ struct stlpanel *panelp;
unsigned int iobase;
int handled = 0;
@@ -1967,18 +1663,17 @@ static int stl_eiointr(stlbrd_t *brdp)
* Interrupt service routine for ECH-AT board types.
*/
-static int stl_echatintr(stlbrd_t *brdp)
+static int stl_echatintr(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
- unsigned int ioaddr;
- int bnknr;
+ struct stlpanel *panelp;
+ unsigned int ioaddr, bnknr;
int handled = 0;
outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
while (inb(brdp->iostatus) & ECH_INTRPEND) {
handled = 1;
- for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+ for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
ioaddr = brdp->bnkstataddr[bnknr];
if (inb(ioaddr) & ECH_PNLINTRPEND) {
panelp = brdp->bnk2panel[bnknr];
@@ -1998,16 +1693,15 @@ static int stl_echatintr(stlbrd_t *brdp)
* Interrupt service routine for ECH-MCA board types.
*/
-static int stl_echmcaintr(stlbrd_t *brdp)
+static int stl_echmcaintr(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
- unsigned int ioaddr;
- int bnknr;
+ struct stlpanel *panelp;
+ unsigned int ioaddr, bnknr;
int handled = 0;
while (inb(brdp->iostatus) & ECH_INTRPEND) {
handled = 1;
- for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+ for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
ioaddr = brdp->bnkstataddr[bnknr];
if (inb(ioaddr) & ECH_PNLINTRPEND) {
panelp = brdp->bnk2panel[bnknr];
@@ -2024,16 +1718,15 @@ static int stl_echmcaintr(stlbrd_t *brdp)
* Interrupt service routine for ECH-PCI board types.
*/
-static int stl_echpciintr(stlbrd_t *brdp)
+static int stl_echpciintr(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
- unsigned int ioaddr;
- int bnknr, recheck;
+ struct stlpanel *panelp;
+ unsigned int ioaddr, bnknr, recheck;
int handled = 0;
while (1) {
recheck = 0;
- for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+ for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
outb(brdp->bnkpageaddr[bnknr], brdp->ioctrl);
ioaddr = brdp->bnkstataddr[bnknr];
if (inb(ioaddr) & ECH_PNLINTRPEND) {
@@ -2055,16 +1748,15 @@ static int stl_echpciintr(stlbrd_t *brdp)
* Interrupt service routine for ECH-8/64-PCI board types.
*/
-static int stl_echpci64intr(stlbrd_t *brdp)
+static int stl_echpci64intr(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
- unsigned int ioaddr;
- int bnknr;
+ struct stlpanel *panelp;
+ unsigned int ioaddr, bnknr;
int handled = 0;
while (inb(brdp->ioctrl) & 0x1) {
handled = 1;
- for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+ for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
ioaddr = brdp->bnkstataddr[bnknr];
if (inb(ioaddr) & ECH_PNLINTRPEND) {
panelp = brdp->bnk2panel[bnknr];
@@ -2083,35 +1775,32 @@ static int stl_echpci64intr(stlbrd_t *brdp)
*/
static void stl_offintr(struct work_struct *work)
{
- stlport_t *portp = container_of(work, stlport_t, tqueue);
+ struct stlport *portp = container_of(work, struct stlport, tqueue);
struct tty_struct *tty;
unsigned int oldsigs;
-#ifdef DEBUG
- printk("stl_offintr(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_offintr(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
lock_kernel();
- if (test_bit(ASYI_TXLOW, &portp->istate)) {
+ if (test_bit(ASYI_TXLOW, &portp->istate))
tty_wakeup(tty);
- }
+
if (test_bit(ASYI_DCDCHANGE, &portp->istate)) {
clear_bit(ASYI_DCDCHANGE, &portp->istate);
oldsigs = portp->sigs;
portp->sigs = stl_getsignals(portp);
if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
wake_up_interruptible(&portp->open_wait);
- if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) {
+ if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
if (portp->flags & ASYNC_CHECK_CD)
tty_hangup(tty); /* FIXME: module removal race here - AKPM */
- }
}
unlock_kernel();
}
@@ -2122,14 +1811,13 @@ static void stl_offintr(struct work_struct *work)
* Initialize all the ports on a panel.
*/
-static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
+static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
{
- stlport_t *portp;
- int chipmask, i;
+ struct stlport *portp;
+ unsigned int i;
+ int chipmask;
-#ifdef DEBUG
- printk("stl_initports(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp);
-#endif
+ pr_debug("stl_initports(brdp=%p,panelp=%p)\n", brdp, panelp);
chipmask = stl_panelinit(brdp, panelp);
@@ -2137,11 +1825,11 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
* All UART's are initialized (if found!). Now go through and setup
* each ports data structures.
*/
- for (i = 0; (i < panelp->nrports); i++) {
- portp = kzalloc(sizeof(stlport_t), GFP_KERNEL);
+ for (i = 0; i < panelp->nrports; i++) {
+ portp = kzalloc(sizeof(struct stlport), GFP_KERNEL);
if (!portp) {
printk("STALLION: failed to allocate memory "
- "(size=%Zd)\n", sizeof(stlport_t));
+ "(size=%Zd)\n", sizeof(struct stlport));
break;
}
@@ -2164,7 +1852,30 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
stl_portinit(brdp, panelp, portp);
}
- return(0);
+ return 0;
+}
+
+static void stl_cleanup_panels(struct stlbrd *brdp)
+{
+ struct stlpanel *panelp;
+ struct stlport *portp;
+ unsigned int j, k;
+
+ for (j = 0; j < STL_MAXPANELS; j++) {
+ panelp = brdp->panels[j];
+ if (panelp == NULL)
+ continue;
+ for (k = 0; k < STL_PORTSPERPANEL; k++) {
+ portp = panelp->ports[k];
+ if (portp == NULL)
+ continue;
+ if (portp->tty != NULL)
+ stl_hangup(portp->tty);
+ kfree(portp->tx.buf);
+ kfree(portp);
+ }
+ kfree(panelp);
+ }
}
/*****************************************************************************/
@@ -2173,16 +1884,14 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
* Try to find and initialize an EasyIO board.
*/
-static inline int stl_initeio(stlbrd_t *brdp)
+static int __devinit stl_initeio(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
+ struct stlpanel *panelp;
unsigned int status;
char *name;
- int rc;
+ int retval;
-#ifdef DEBUG
- printk("stl_initeio(brdp=%x)\n", (int) brdp);
-#endif
+ pr_debug("stl_initeio(brdp=%p)\n", brdp);
brdp->ioctrl = brdp->ioaddr1 + 1;
brdp->iostatus = brdp->ioaddr1 + 2;
@@ -2207,18 +1916,20 @@ static inline int stl_initeio(stlbrd_t *brdp)
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
printk("STALLION: invalid irq=%d for brd=%d\n",
brdp->irq, brdp->brdnr);
- return(-EINVAL);
+ retval = -EINVAL;
+ goto err;
}
outb((stl_vecmap[brdp->irq] | EIO_0WS |
((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)),
brdp->ioctrl);
}
+ retval = -EBUSY;
if (!request_region(brdp->ioaddr1, brdp->iosize1, name)) {
printk(KERN_WARNING "STALLION: Warning, board %d I/O address "
"%x conflicts with another device\n", brdp->brdnr,
brdp->ioaddr1);
- return(-EBUSY);
+ goto err;
}
if (brdp->iosize2 > 0)
@@ -2229,8 +1940,7 @@ static inline int stl_initeio(stlbrd_t *brdp)
printk(KERN_WARNING "STALLION: Warning, also "
"releasing board %d I/O address %x \n",
brdp->brdnr, brdp->ioaddr1);
- release_region(brdp->ioaddr1, brdp->iosize1);
- return(-EBUSY);
+ goto err_rel1;
}
/*
@@ -2239,6 +1949,7 @@ static inline int stl_initeio(stlbrd_t *brdp)
brdp->clk = CD1400_CLK;
brdp->isr = stl_eiointr;
+ retval = -ENODEV;
switch (status & EIO_IDBITMASK) {
case EIO_8PORTM:
brdp->clk = CD1400_CLK8M;
@@ -2262,11 +1973,11 @@ static inline int stl_initeio(stlbrd_t *brdp)
brdp->nrports = 16;
break;
default:
- return(-ENODEV);
+ goto err_rel2;
}
break;
default:
- return(-ENODEV);
+ goto err_rel2;
}
/*
@@ -2274,11 +1985,12 @@ static inline int stl_initeio(stlbrd_t *brdp)
* can complete the setup.
*/
- panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
+ panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL);
if (!panelp) {
printk(KERN_WARNING "STALLION: failed to allocate memory "
- "(size=%Zd)\n", sizeof(stlpanel_t));
- return -ENOMEM;
+ "(size=%Zd)\n", sizeof(struct stlpanel));
+ retval = -ENOMEM;
+ goto err_rel2;
}
panelp->magic = STL_PANELMAGIC;
@@ -2288,10 +2000,10 @@ static inline int stl_initeio(stlbrd_t *brdp)
panelp->iobase = brdp->ioaddr1;
panelp->hwid = status;
if ((status & EIO_IDBITMASK) == EIO_MK3) {
- panelp->uartp = (void *) &stl_sc26198uart;
+ panelp->uartp = &stl_sc26198uart;
panelp->isr = stl_sc26198intr;
} else {
- panelp->uartp = (void *) &stl_cd1400uart;
+ panelp->uartp = &stl_cd1400uart;
panelp->isr = stl_cd1400eiointr;
}
@@ -2302,11 +2014,20 @@ static inline int stl_initeio(stlbrd_t *brdp)
if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) {
printk("STALLION: failed to register interrupt "
"routine for %s irq=%d\n", name, brdp->irq);
- rc = -ENODEV;
- } else {
- rc = 0;
+ retval = -ENODEV;
+ goto err_fr;
}
- return rc;
+
+ return 0;
+err_fr:
+ stl_cleanup_panels(brdp);
+err_rel2:
+ if (brdp->iosize2 > 0)
+ release_region(brdp->ioaddr2, brdp->iosize2);
+err_rel1:
+ release_region(brdp->ioaddr1, brdp->iosize1);
+err:
+ return retval;
}
/*****************************************************************************/
@@ -2316,16 +2037,14 @@ static inline int stl_initeio(stlbrd_t *brdp)
* dealing with all types of ECH board.
*/
-static inline int stl_initech(stlbrd_t *brdp)
+static int __devinit stl_initech(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
- unsigned int status, nxtid, ioaddr, conflict;
- int panelnr, banknr, i;
+ struct stlpanel *panelp;
+ unsigned int status, nxtid, ioaddr, conflict, panelnr, banknr, i;
+ int retval;
char *name;
-#ifdef DEBUG
- printk("stl_initech(brdp=%x)\n", (int) brdp);
-#endif
+ pr_debug("stl_initech(brdp=%p)\n", brdp);
status = 0;
conflict = 0;
@@ -2342,20 +2061,23 @@ static inline int stl_initech(stlbrd_t *brdp)
brdp->ioctrl = brdp->ioaddr1 + 1;
brdp->iostatus = brdp->ioaddr1 + 1;
status = inb(brdp->iostatus);
- if ((status & ECH_IDBITMASK) != ECH_ID)
- return(-ENODEV);
+ if ((status & ECH_IDBITMASK) != ECH_ID) {
+ retval = -ENODEV;
+ goto err;
+ }
if ((brdp->irq < 0) || (brdp->irq > 15) ||
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
printk("STALLION: invalid irq=%d for brd=%d\n",
brdp->irq, brdp->brdnr);
- return(-EINVAL);
+ retval = -EINVAL;
+ goto err;
}
status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1);
status |= (stl_vecmap[brdp->irq] << 1);
outb((status | ECH_BRDRESET), brdp->ioaddr1);
brdp->ioctrlval = ECH_INTENABLE |
((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE);
- for (i = 0; (i < 10); i++)
+ for (i = 0; i < 10; i++)
outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
brdp->iosize1 = 2;
brdp->iosize2 = 32;
@@ -2368,13 +2090,16 @@ static inline int stl_initech(stlbrd_t *brdp)
brdp->ioctrl = brdp->ioaddr1 + 0x20;
brdp->iostatus = brdp->ioctrl;
status = inb(brdp->iostatus);
- if ((status & ECH_IDBITMASK) != ECH_ID)
- return(-ENODEV);
+ if ((status & ECH_IDBITMASK) != ECH_ID) {
+ retval = -ENODEV;
+ goto err;
+ }
if ((brdp->irq < 0) || (brdp->irq > 15) ||
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
printk("STALLION: invalid irq=%d for brd=%d\n",
brdp->irq, brdp->brdnr);
- return(-EINVAL);
+ retval = -EINVAL;
+ goto err;
}
outb(ECHMC_BRDRESET, brdp->ioctrl);
outb(ECHMC_INTENABLE, brdp->ioctrl);
@@ -2401,19 +2126,20 @@ static inline int stl_initech(stlbrd_t *brdp)
default:
printk("STALLION: unknown board type=%d\n", brdp->brdtype);
- return(-EINVAL);
- break;
+ retval = -EINVAL;
+ goto err;
}
/*
* Check boards for possible IO address conflicts and return fail status
* if an IO conflict found.
*/
+ retval = -EBUSY;
if (!request_region(brdp->ioaddr1, brdp->iosize1, name)) {
printk(KERN_WARNING "STALLION: Warning, board %d I/O address "
"%x conflicts with another device\n", brdp->brdnr,
brdp->ioaddr1);
- return(-EBUSY);
+ goto err;
}
if (brdp->iosize2 > 0)
@@ -2424,8 +2150,7 @@ static inline int stl_initech(stlbrd_t *brdp)
printk(KERN_WARNING "STALLION: Warning, also "
"releasing board %d I/O address %x \n",
brdp->brdnr, brdp->ioaddr1);
- release_region(brdp->ioaddr1, brdp->iosize1);
- return(-EBUSY);
+ goto err_rel1;
}
/*
@@ -2440,19 +2165,19 @@ static inline int stl_initech(stlbrd_t *brdp)
panelnr = 0;
nxtid = 0;
- for (i = 0; (i < STL_MAXPANELS); i++) {
+ for (i = 0; i < STL_MAXPANELS; i++) {
if (brdp->brdtype == BRD_ECHPCI) {
outb(nxtid, brdp->ioctrl);
ioaddr = brdp->ioaddr2;
}
status = inb(ioaddr + ECH_PNLSTATUS);
if ((status & ECH_PNLIDMASK) != nxtid)
- break;
- panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
+ goto err_fr;
+ panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL);
if (!panelp) {
printk("STALLION: failed to allocate memory "
- "(size=%Zd)\n", sizeof(stlpanel_t));
- break;
+ "(size=%Zd)\n", sizeof(struct stlpanel));
+ goto err_fr;
}
panelp->magic = STL_PANELMAGIC;
panelp->brdnr = brdp->brdnr;
@@ -2465,7 +2190,7 @@ static inline int stl_initech(stlbrd_t *brdp)
brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS;
if (status & ECH_PNLXPID) {
- panelp->uartp = (void *) &stl_sc26198uart;
+ panelp->uartp = &stl_sc26198uart;
panelp->isr = stl_sc26198intr;
if (status & ECH_PNL16PORT) {
panelp->nrports = 16;
@@ -2473,11 +2198,10 @@ static inline int stl_initech(stlbrd_t *brdp)
brdp->bnkpageaddr[banknr] = nxtid;
brdp->bnkstataddr[banknr++] = ioaddr + 4 +
ECH_PNLSTATUS;
- } else {
+ } else
panelp->nrports = 8;
- }
} else {
- panelp->uartp = (void *) &stl_cd1400uart;
+ panelp->uartp = &stl_cd1400uart;
panelp->isr = stl_cd1400echintr;
if (status & ECH_PNL16PORT) {
panelp->nrports = 16;
@@ -2500,7 +2224,7 @@ static inline int stl_initech(stlbrd_t *brdp)
brdp->panels[panelnr++] = panelp;
if ((brdp->brdtype != BRD_ECHPCI) &&
(ioaddr >= (brdp->ioaddr2 + brdp->iosize2)))
- break;
+ goto err_fr;
}
brdp->nrpanels = panelnr;
@@ -2512,12 +2236,19 @@ static inline int stl_initech(stlbrd_t *brdp)
if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) {
printk("STALLION: failed to register interrupt "
"routine for %s irq=%d\n", name, brdp->irq);
- i = -ENODEV;
- } else {
- i = 0;
+ retval = -ENODEV;
+ goto err_fr;
}
- return(i);
+ return 0;
+err_fr:
+ stl_cleanup_panels(brdp);
+ if (brdp->iosize2 > 0)
+ release_region(brdp->ioaddr2, brdp->iosize2);
+err_rel1:
+ release_region(brdp->ioaddr1, brdp->iosize1);
+err:
+ return retval;
}
/*****************************************************************************/
@@ -2529,48 +2260,61 @@ static inline int stl_initech(stlbrd_t *brdp)
* since the initial search and setup is very different.
*/
-static int __init stl_brdinit(stlbrd_t *brdp)
+static int __devinit stl_brdinit(struct stlbrd *brdp)
{
- int i;
+ int i, retval;
-#ifdef DEBUG
- printk("stl_brdinit(brdp=%x)\n", (int) brdp);
-#endif
+ pr_debug("stl_brdinit(brdp=%p)\n", brdp);
switch (brdp->brdtype) {
case BRD_EASYIO:
case BRD_EASYIOPCI:
- stl_initeio(brdp);
+ retval = stl_initeio(brdp);
+ if (retval)
+ goto err;
break;
case BRD_ECH:
case BRD_ECHMC:
case BRD_ECHPCI:
case BRD_ECH64PCI:
- stl_initech(brdp);
+ retval = stl_initech(brdp);
+ if (retval)
+ goto err;
break;
default:
printk("STALLION: board=%d is unknown board type=%d\n",
brdp->brdnr, brdp->brdtype);
- return(ENODEV);
+ retval = -ENODEV;
+ goto err;
}
- stl_brds[brdp->brdnr] = brdp;
if ((brdp->state & BRD_FOUND) == 0) {
printk("STALLION: %s board not found, board=%d io=%x irq=%d\n",
stl_brdnames[brdp->brdtype], brdp->brdnr,
brdp->ioaddr1, brdp->irq);
- return(ENODEV);
+ goto err_free;
}
- for (i = 0; (i < STL_MAXPANELS); i++)
- if (brdp->panels[i] != (stlpanel_t *) NULL)
+ for (i = 0; i < STL_MAXPANELS; i++)
+ if (brdp->panels[i] != NULL)
stl_initports(brdp, brdp->panels[i]);
printk("STALLION: %s found, board=%d io=%x irq=%d "
"nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype],
brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels,
brdp->nrports);
- return(0);
+
+ return 0;
+err_free:
+ free_irq(brdp->irq, brdp);
+
+ stl_cleanup_panels(brdp);
+
+ release_region(brdp->ioaddr1, brdp->iosize1);
+ if (brdp->iosize2 > 0)
+ release_region(brdp->ioaddr2, brdp->iosize2);
+err:
+ return retval;
}
/*****************************************************************************/
@@ -2579,59 +2323,62 @@ static int __init stl_brdinit(stlbrd_t *brdp)
* Find the next available board number that is free.
*/
-static inline int stl_getbrdnr(void)
+static int __devinit stl_getbrdnr(void)
{
- int i;
+ unsigned int i;
- for (i = 0; (i < STL_MAXBRDS); i++) {
- if (stl_brds[i] == (stlbrd_t *) NULL) {
+ for (i = 0; i < STL_MAXBRDS; i++)
+ if (stl_brds[i] == NULL) {
if (i >= stl_nrbrds)
stl_nrbrds = i + 1;
- return(i);
+ return i;
}
- }
- return(-1);
+
+ return -1;
}
/*****************************************************************************/
-
-#ifdef CONFIG_PCI
-
/*
* We have a Stallion board. Allocate a board structure and
* initialize it. Read its IO and IRQ resources from PCI
* configuration space.
*/
-static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
+static int __devinit stl_pciprobe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- stlbrd_t *brdp;
-
-#ifdef DEBUG
- printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype,
- devp->bus->number, devp->devfn);
-#endif
-
- if (pci_enable_device(devp))
- return(-EIO);
- if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
- return(-ENOMEM);
- if ((brdp->brdnr = stl_getbrdnr()) < 0) {
- printk("STALLION: too many boards found, "
+ struct stlbrd *brdp;
+ unsigned int i, brdtype = ent->driver_data;
+ int brdnr, retval = -ENODEV;
+
+ if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE)
+ goto err;
+
+ dev_info(&pdev->dev, "please, report this to LKML: %x/%x/%x\n",
+ pdev->vendor, pdev->device, pdev->class);
+
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err;
+ brdp = stl_allocbrd();
+ if (brdp == NULL) {
+ retval = -ENOMEM;
+ goto err;
+ }
+ mutex_lock(&stl_brdslock);
+ brdnr = stl_getbrdnr();
+ if (brdnr < 0) {
+ dev_err(&pdev->dev, "too many boards found, "
"maximum supported %d\n", STL_MAXBRDS);
- return(0);
+ mutex_unlock(&stl_brdslock);
+ goto err_fr;
}
- brdp->brdtype = brdtype;
+ brdp->brdnr = (unsigned int)brdnr;
+ stl_brds[brdp->brdnr] = brdp;
+ mutex_unlock(&stl_brdslock);
-/*
- * Different Stallion boards use the BAR registers in different ways,
- * so set up io addresses based on board type.
- */
-#ifdef DEBUG
- printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__,
- pci_resource_start(devp, 0), pci_resource_start(devp, 1),
- pci_resource_start(devp, 2), pci_resource_start(devp, 3), devp->irq);
-#endif
+ brdp->brdtype = brdtype;
+ brdp->state |= STL_PROBED;
/*
* We have all resources from the board, so let's setup the actual
@@ -2639,120 +2386,70 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
*/
switch (brdtype) {
case BRD_ECHPCI:
- brdp->ioaddr2 = pci_resource_start(devp, 0);
- brdp->ioaddr1 = pci_resource_start(devp, 1);
+ brdp->ioaddr2 = pci_resource_start(pdev, 0);
+ brdp->ioaddr1 = pci_resource_start(pdev, 1);
break;
case BRD_ECH64PCI:
- brdp->ioaddr2 = pci_resource_start(devp, 2);
- brdp->ioaddr1 = pci_resource_start(devp, 1);
+ brdp->ioaddr2 = pci_resource_start(pdev, 2);
+ brdp->ioaddr1 = pci_resource_start(pdev, 1);
break;
case BRD_EASYIOPCI:
- brdp->ioaddr1 = pci_resource_start(devp, 2);
- brdp->ioaddr2 = pci_resource_start(devp, 1);
+ brdp->ioaddr1 = pci_resource_start(pdev, 2);
+ brdp->ioaddr2 = pci_resource_start(pdev, 1);
break;
default:
- printk("STALLION: unknown PCI board type=%d\n", brdtype);
+ dev_err(&pdev->dev, "unknown PCI board type=%u\n", brdtype);
break;
}
- brdp->irq = devp->irq;
- stl_brdinit(brdp);
-
- return(0);
-}
-
-/*****************************************************************************/
-
-/*
- * Find all Stallion PCI boards that might be installed. Initialize each
- * one as it is found.
- */
-
+ brdp->irq = pdev->irq;
+ retval = stl_brdinit(brdp);
+ if (retval)
+ goto err_null;
-static inline int stl_findpcibrds(void)
-{
- struct pci_dev *dev = NULL;
- int i, rc;
-
-#ifdef DEBUG
- printk("stl_findpcibrds()\n");
-#endif
+ pci_set_drvdata(pdev, brdp);
- for (i = 0; (i < stl_nrpcibrds); i++)
- while ((dev = pci_find_device(stl_pcibrds[i].vendid,
- stl_pcibrds[i].devid, dev))) {
-
-/*
- * Found a device on the PCI bus that has our vendor and
- * device ID. Need to check now that it is really us.
- */
- if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)
- continue;
-
- rc = stl_initpcibrd(stl_pcibrds[i].brdtype, dev);
- if (rc)
- return(rc);
- }
+ for (i = 0; i < brdp->nrports; i++)
+ tty_register_device(stl_serial,
+ brdp->brdnr * STL_MAXPORTS + i, &pdev->dev);
- return(0);
+ return 0;
+err_null:
+ stl_brds[brdp->brdnr] = NULL;
+err_fr:
+ kfree(brdp);
+err:
+ return retval;
}
-#endif
-
-/*****************************************************************************/
-
-/*
- * Scan through all the boards in the configuration and see what we
- * can find. Handle EIO and the ECH boards a little differently here
- * since the initial search and setup is too different.
- */
-
-static inline int stl_initbrds(void)
+static void __devexit stl_pciremove(struct pci_dev *pdev)
{
- stlbrd_t *brdp;
- stlconf_t *confp;
- int i;
+ struct stlbrd *brdp = pci_get_drvdata(pdev);
+ unsigned int i;
-#ifdef DEBUG
- printk("stl_initbrds()\n");
-#endif
+ free_irq(brdp->irq, brdp);
- if (stl_nrbrds > STL_MAXBRDS) {
- printk("STALLION: too many boards in configuration table, "
- "truncating to %d\n", STL_MAXBRDS);
- stl_nrbrds = STL_MAXBRDS;
- }
+ stl_cleanup_panels(brdp);
-/*
- * Firstly scan the list of static boards configured. Allocate
- * resources and initialize the boards as found.
- */
- for (i = 0; (i < stl_nrbrds); i++) {
- confp = &stl_brdconf[i];
- stl_parsebrd(confp, stl_brdsp[i]);
- if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
- return(-ENOMEM);
- brdp->brdnr = i;
- brdp->brdtype = confp->brdtype;
- brdp->ioaddr1 = confp->ioaddr1;
- brdp->ioaddr2 = confp->ioaddr2;
- brdp->irq = confp->irq;
- brdp->irqtype = confp->irqtype;
- stl_brdinit(brdp);
- }
+ release_region(brdp->ioaddr1, brdp->iosize1);
+ if (brdp->iosize2 > 0)
+ release_region(brdp->ioaddr2, brdp->iosize2);
-/*
- * Find any dynamically supported boards. That is via module load
- * line options or auto-detected on the PCI bus.
- */
- stl_argbrds();
-#ifdef CONFIG_PCI
- stl_findpcibrds();
-#endif
+ for (i = 0; i < brdp->nrports; i++)
+ tty_unregister_device(stl_serial,
+ brdp->brdnr * STL_MAXPORTS + i);
- return(0);
+ stl_brds[brdp->brdnr] = NULL;
+ kfree(brdp);
}
+static struct pci_driver stl_pcidriver = {
+ .name = "stallion",
+ .id_table = stl_pcibrds,
+ .probe = stl_pciprobe,
+ .remove = __devexit_p(stl_pciremove)
+};
+
/*****************************************************************************/
/*
@@ -2761,17 +2458,18 @@ static inline int stl_initbrds(void)
static int stl_getbrdstats(combrd_t __user *bp)
{
- stlbrd_t *brdp;
- stlpanel_t *panelp;
- int i;
+ combrd_t stl_brdstats;
+ struct stlbrd *brdp;
+ struct stlpanel *panelp;
+ unsigned int i;
if (copy_from_user(&stl_brdstats, bp, sizeof(combrd_t)))
return -EFAULT;
if (stl_brdstats.brd >= STL_MAXBRDS)
- return(-ENODEV);
+ return -ENODEV;
brdp = stl_brds[stl_brdstats.brd];
- if (brdp == (stlbrd_t *) NULL)
- return(-ENODEV);
+ if (brdp == NULL)
+ return -ENODEV;
memset(&stl_brdstats, 0, sizeof(combrd_t));
stl_brdstats.brd = brdp->brdnr;
@@ -2783,7 +2481,7 @@ static int stl_getbrdstats(combrd_t __user *bp)
stl_brdstats.irq = brdp->irq;
stl_brdstats.nrpanels = brdp->nrpanels;
stl_brdstats.nrports = brdp->nrports;
- for (i = 0; (i < brdp->nrpanels); i++) {
+ for (i = 0; i < brdp->nrpanels; i++) {
panelp = brdp->panels[i];
stl_brdstats.panels[i].panel = i;
stl_brdstats.panels[i].hwid = panelp->hwid;
@@ -2799,24 +2497,24 @@ static int stl_getbrdstats(combrd_t __user *bp)
* Resolve the referenced port number into a port struct pointer.
*/
-static stlport_t *stl_getport(int brdnr, int panelnr, int portnr)
+static struct stlport *stl_getport(int brdnr, int panelnr, int portnr)
{
- stlbrd_t *brdp;
- stlpanel_t *panelp;
+ struct stlbrd *brdp;
+ struct stlpanel *panelp;
- if ((brdnr < 0) || (brdnr >= STL_MAXBRDS))
- return((stlport_t *) NULL);
+ if (brdnr < 0 || brdnr >= STL_MAXBRDS)
+ return NULL;
brdp = stl_brds[brdnr];
- if (brdp == (stlbrd_t *) NULL)
- return((stlport_t *) NULL);
- if ((panelnr < 0) || (panelnr >= brdp->nrpanels))
- return((stlport_t *) NULL);
+ if (brdp == NULL)
+ return NULL;
+ if (panelnr < 0 || (unsigned int)panelnr >= brdp->nrpanels)
+ return NULL;
panelp = brdp->panels[panelnr];
- if (panelp == (stlpanel_t *) NULL)
- return((stlport_t *) NULL);
- if ((portnr < 0) || (portnr >= panelp->nrports))
- return((stlport_t *) NULL);
- return(panelp->ports[portnr]);
+ if (panelp == NULL)
+ return NULL;
+ if (portnr < 0 || (unsigned int)portnr >= panelp->nrports)
+ return NULL;
+ return panelp->ports[portnr];
}
/*****************************************************************************/
@@ -2827,8 +2525,9 @@ static stlport_t *stl_getport(int brdnr, int panelnr, int portnr)
* what port to get stats for (used through board control device).
*/
-static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
+static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
{
+ comstats_t stl_comstats;
unsigned char *head, *tail;
unsigned long flags;
@@ -2837,8 +2536,8 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
return -EFAULT;
portp = stl_getport(stl_comstats.brd, stl_comstats.panel,
stl_comstats.port);
- if (portp == (stlport_t *) NULL)
- return(-ENODEV);
+ if (portp == NULL)
+ return -ENODEV;
}
portp->stats.state = portp->istate;
@@ -2853,25 +2552,24 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
portp->stats.rxbuffered = 0;
spin_lock_irqsave(&stallion_lock, flags);
- if (portp->tty != (struct tty_struct *) NULL) {
+ if (portp->tty != NULL)
if (portp->tty->driver_data == portp) {
portp->stats.ttystate = portp->tty->flags;
/* No longer available as a statistic */
portp->stats.rxbuffered = 1; /*portp->tty->flip.count; */
- if (portp->tty->termios != (struct termios *) NULL) {
+ if (portp->tty->termios != NULL) {
portp->stats.cflags = portp->tty->termios->c_cflag;
portp->stats.iflags = portp->tty->termios->c_iflag;
portp->stats.oflags = portp->tty->termios->c_oflag;
portp->stats.lflags = portp->tty->termios->c_lflag;
}
}
- }
spin_unlock_irqrestore(&stallion_lock, flags);
head = portp->tx.head;
tail = portp->tx.tail;
- portp->stats.txbuffered = ((head >= tail) ? (head - tail) :
- (STL_TXBUFSIZE - (tail - head)));
+ portp->stats.txbuffered = (head >= tail) ? (head - tail) :
+ (STL_TXBUFSIZE - (tail - head));
portp->stats.signals = (unsigned long) stl_getsignals(portp);
@@ -2885,15 +2583,17 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
* Clear the port stats structure. We also return it zeroed out...
*/
-static int stl_clrportstats(stlport_t *portp, comstats_t __user *cp)
+static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp)
{
+ comstats_t stl_comstats;
+
if (!portp) {
if (copy_from_user(&stl_comstats, cp, sizeof(comstats_t)))
return -EFAULT;
portp = stl_getport(stl_comstats.brd, stl_comstats.panel,
stl_comstats.port);
- if (portp == (stlport_t *) NULL)
- return(-ENODEV);
+ if (portp == NULL)
+ return -ENODEV;
}
memset(&portp->stats, 0, sizeof(comstats_t));
@@ -2910,17 +2610,18 @@ static int stl_clrportstats(stlport_t *portp, comstats_t __user *cp)
* Return the entire driver ports structure to a user app.
*/
-static int stl_getportstruct(stlport_t __user *arg)
+static int stl_getportstruct(struct stlport __user *arg)
{
- stlport_t *portp;
+ struct stlport stl_dummyport;
+ struct stlport *portp;
- if (copy_from_user(&stl_dummyport, arg, sizeof(stlport_t)))
+ if (copy_from_user(&stl_dummyport, arg, sizeof(struct stlport)))
return -EFAULT;
portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr,
stl_dummyport.portnr);
if (!portp)
return -ENODEV;
- return copy_to_user(arg, portp, sizeof(stlport_t)) ? -EFAULT : 0;
+ return copy_to_user(arg, portp, sizeof(struct stlport)) ? -EFAULT : 0;
}
/*****************************************************************************/
@@ -2929,18 +2630,19 @@ static int stl_getportstruct(stlport_t __user *arg)
* Return the entire driver board structure to a user app.
*/
-static int stl_getbrdstruct(stlbrd_t __user *arg)
+static int stl_getbrdstruct(struct stlbrd __user *arg)
{
- stlbrd_t *brdp;
+ struct stlbrd stl_dummybrd;
+ struct stlbrd *brdp;
- if (copy_from_user(&stl_dummybrd, arg, sizeof(stlbrd_t)))
+ if (copy_from_user(&stl_dummybrd, arg, sizeof(struct stlbrd)))
return -EFAULT;
- if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS))
+ if (stl_dummybrd.brdnr >= STL_MAXBRDS)
return -ENODEV;
brdp = stl_brds[stl_dummybrd.brdnr];
if (!brdp)
- return(-ENODEV);
- return copy_to_user(arg, brdp, sizeof(stlbrd_t)) ? -EFAULT : 0;
+ return -ENODEV;
+ return copy_to_user(arg, brdp, sizeof(struct stlbrd)) ? -EFAULT : 0;
}
/*****************************************************************************/
@@ -2956,14 +2658,11 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
int brdnr, rc;
void __user *argp = (void __user *)arg;
-#ifdef DEBUG
- printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip,
- (int) fp, cmd, (int) arg);
-#endif
+ pr_debug("stl_memioctl(ip=%p,fp=%p,cmd=%x,arg=%lx)\n", ip, fp, cmd,arg);
brdnr = iminor(ip);
if (brdnr >= STL_MAXBRDS)
- return(-ENODEV);
+ return -ENODEV;
rc = 0;
switch (cmd) {
@@ -2987,7 +2686,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
break;
}
- return(rc);
+ return rc;
}
static const struct tty_operations stl_ops = {
@@ -3015,55 +2714,6 @@ static const struct tty_operations stl_ops = {
};
/*****************************************************************************/
-
-static int __init stl_init(void)
-{
- int i;
- printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
-
- spin_lock_init(&stallion_lock);
- spin_lock_init(&brd_lock);
-
- stl_initbrds();
-
- stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
- if (!stl_serial)
- return -1;
-
-/*
- * Set up a character driver for per board stuff. This is mainly used
- * to do stats ioctls on the ports.
- */
- if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
- printk("STALLION: failed to register serial board device\n");
-
- stallion_class = class_create(THIS_MODULE, "staliomem");
- for (i = 0; i < 4; i++)
- class_device_create(stallion_class, NULL,
- MKDEV(STL_SIOMEMMAJOR, i), NULL,
- "staliomem%d", i);
-
- stl_serial->owner = THIS_MODULE;
- stl_serial->driver_name = stl_drvname;
- stl_serial->name = "ttyE";
- stl_serial->major = STL_SERIALMAJOR;
- stl_serial->minor_start = 0;
- stl_serial->type = TTY_DRIVER_TYPE_SERIAL;
- stl_serial->subtype = SERIAL_TYPE_NORMAL;
- stl_serial->init_termios = stl_deftermios;
- stl_serial->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(stl_serial, &stl_ops);
-
- if (tty_register_driver(stl_serial)) {
- put_tty_driver(stl_serial);
- printk("STALLION: failed to register serial driver\n");
- return -1;
- }
-
- return 0;
-}
-
-/*****************************************************************************/
/* CD1400 HARDWARE FUNCTIONS */
/*****************************************************************************/
@@ -3073,21 +2723,21 @@ static int __init stl_init(void)
* (Maybe should make this inline...)
*/
-static int stl_cd1400getreg(stlport_t *portp, int regnr)
+static int stl_cd1400getreg(struct stlport *portp, int regnr)
{
outb((regnr + portp->uartaddr), portp->ioaddr);
return inb(portp->ioaddr + EREG_DATA);
}
-static void stl_cd1400setreg(stlport_t *portp, int regnr, int value)
+static void stl_cd1400setreg(struct stlport *portp, int regnr, int value)
{
- outb((regnr + portp->uartaddr), portp->ioaddr);
+ outb(regnr + portp->uartaddr, portp->ioaddr);
outb(value, portp->ioaddr + EREG_DATA);
}
-static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value)
+static int stl_cd1400updatereg(struct stlport *portp, int regnr, int value)
{
- outb((regnr + portp->uartaddr), portp->ioaddr);
+ outb(regnr + portp->uartaddr, portp->ioaddr);
if (inb(portp->ioaddr + EREG_DATA) != value) {
outb(value, portp->ioaddr + EREG_DATA);
return 1;
@@ -3103,16 +2753,14 @@ static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value)
* identical when dealing with ports.
*/
-static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
+static int stl_cd1400panelinit(struct stlbrd *brdp, struct stlpanel *panelp)
{
unsigned int gfrcr;
int chipmask, i, j;
int nrchips, uartaddr, ioaddr;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp);
-#endif
+ pr_debug("stl_panelinit(brdp=%p,panelp=%p)\n", brdp, panelp);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(panelp->brdnr, panelp->pagenr);
@@ -3122,13 +2770,12 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
*/
chipmask = 0;
nrchips = panelp->nrports / CD1400_PORTS;
- for (i = 0; (i < nrchips); i++) {
+ for (i = 0; i < nrchips; i++) {
if (brdp->brdtype == BRD_ECHPCI) {
outb((panelp->pagenr + (i >> 1)), brdp->ioctrl);
ioaddr = panelp->iobase;
- } else {
+ } else
ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1));
- }
uartaddr = (i & 0x01) ? 0x080 : 0;
outb((GFRCR + uartaddr), ioaddr);
outb(0, (ioaddr + EREG_DATA));
@@ -3136,10 +2783,10 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
outb((GFRCR + uartaddr), ioaddr);
- for (j = 0; (j < CCR_MAXWAIT); j++) {
+ for (j = 0; j < CCR_MAXWAIT; j++)
if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0)
break;
- }
+
if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) {
printk("STALLION: cd1400 not responding, "
"brd=%d panel=%d chip=%d\n",
@@ -3162,16 +2809,14 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
* Initialize hardware specific port registers.
*/
-static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp)
+static void stl_cd1400portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n",
- (int) brdp, (int) panelp, (int) portp);
-#endif
+ pr_debug("stl_cd1400portinit(brdp=%p,panelp=%p,portp=%p)\n", brdp,
+ panelp, portp);
- if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) ||
- (portp == (stlport_t *) NULL))
+ if ((brdp == NULL) || (panelp == NULL) ||
+ (portp == NULL))
return;
spin_lock_irqsave(&brd_lock, flags);
@@ -3195,15 +2840,13 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po
* since it won't usually take too long to be ready.
*/
-static void stl_cd1400ccrwait(stlport_t *portp)
+static void stl_cd1400ccrwait(struct stlport *portp)
{
int i;
- for (i = 0; (i < CCR_MAXWAIT); i++) {
- if (stl_cd1400getreg(portp, CCR) == 0) {
+ for (i = 0; i < CCR_MAXWAIT; i++)
+ if (stl_cd1400getreg(portp, CCR) == 0)
return;
- }
- }
printk("STALLION: cd1400 not responding, port=%d panel=%d brd=%d\n",
portp->portnr, portp->panelnr, portp->brdnr);
@@ -3216,9 +2859,9 @@ static void stl_cd1400ccrwait(stlport_t *portp)
* settings.
*/
-static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
+static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp)
{
- stlbrd_t *brdp;
+ struct stlbrd *brdp;
unsigned long flags;
unsigned int clkdiv, baudrate;
unsigned char cor1, cor2, cor3;
@@ -3242,7 +2885,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
sreroff = 0;
brdp = stl_brds[portp->brdnr];
- if (brdp == (stlbrd_t *) NULL)
+ if (brdp == NULL)
return;
/*
@@ -3339,8 +2982,8 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
baudrate = STL_CD1400MAXBAUD;
if (baudrate > 0) {
- for (clk = 0; (clk < CD1400_NUMCLKS); clk++) {
- clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / baudrate);
+ for (clk = 0; clk < CD1400_NUMCLKS; clk++) {
+ clkdiv = (portp->clk / stl_cd1400clkdivs[clk]) / baudrate;
if (clkdiv < 0x100)
break;
}
@@ -3355,9 +2998,8 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
mcor2 |= MCOR2_DCD;
sreron |= SRER_MODEM;
portp->flags |= ASYNC_CHECK_CD;
- } else {
+ } else
portp->flags &= ~ASYNC_CHECK_CD;
- }
/*
* Setup cd1400 enhanced modes if we can. In particular we want to
@@ -3382,18 +3024,16 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
* them all up.
*/
-#ifdef DEBUG
- printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
+ pr_debug("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
portp->portnr, portp->panelnr, portp->brdnr);
- printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n",
+ pr_debug(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n",
cor1, cor2, cor3, cor4, cor5);
- printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n",
+ pr_debug(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n",
mcor1, mcor2, rtpr, sreron, sreroff);
- printk(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div);
- printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n",
+ pr_debug(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div);
+ pr_debug(" schr1=%x schr2=%x schr3=%x schr4=%x\n",
tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP],
tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
-#endif
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
@@ -3441,15 +3081,13 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
* Set the state of the DTR and RTS signals.
*/
-static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts)
+static void stl_cd1400setsignals(struct stlport *portp, int dtr, int rts)
{
unsigned char msvr1, msvr2;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400setsignals(portp=%x,dtr=%d,rts=%d)\n",
- (int) portp, dtr, rts);
-#endif
+ pr_debug("stl_cd1400setsignals(portp=%p,dtr=%d,rts=%d)\n",
+ portp, dtr, rts);
msvr1 = 0;
msvr2 = 0;
@@ -3475,15 +3113,13 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts)
* Return the state of the signals.
*/
-static int stl_cd1400getsignals(stlport_t *portp)
+static int stl_cd1400getsignals(struct stlport *portp)
{
unsigned char msvr1, msvr2;
unsigned long flags;
int sigs;
-#ifdef DEBUG
- printk("stl_cd1400getsignals(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_cd1400getsignals(portp=%p)\n", portp);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
@@ -3513,15 +3149,13 @@ static int stl_cd1400getsignals(stlport_t *portp)
* Enable/Disable the Transmitter and/or Receiver.
*/
-static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx)
+static void stl_cd1400enablerxtx(struct stlport *portp, int rx, int tx)
{
unsigned char ccr;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400enablerxtx(portp=%x,rx=%d,tx=%d)\n",
- (int) portp, rx, tx);
-#endif
+ pr_debug("stl_cd1400enablerxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx, tx);
+
ccr = 0;
if (tx == 0)
@@ -3549,15 +3183,12 @@ static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx)
* Start/stop the Transmitter and/or Receiver.
*/
-static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx)
+static void stl_cd1400startrxtx(struct stlport *portp, int rx, int tx)
{
unsigned char sreron, sreroff;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400startrxtx(portp=%x,rx=%d,tx=%d)\n",
- (int) portp, rx, tx);
-#endif
+ pr_debug("stl_cd1400startrxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx, tx);
sreron = 0;
sreroff = 0;
@@ -3589,13 +3220,12 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx)
* Disable all interrupts from this port.
*/
-static void stl_cd1400disableintrs(stlport_t *portp)
+static void stl_cd1400disableintrs(struct stlport *portp)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_cd1400disableintrs(portp=%p)\n", portp);
+
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
@@ -3606,13 +3236,11 @@ static void stl_cd1400disableintrs(stlport_t *portp)
/*****************************************************************************/
-static void stl_cd1400sendbreak(stlport_t *portp, int len)
+static void stl_cd1400sendbreak(struct stlport *portp, int len)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len);
-#endif
+ pr_debug("stl_cd1400sendbreak(portp=%p,len=%d)\n", portp, len);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
@@ -3633,19 +3261,17 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len)
* Take flow control actions...
*/
-static void stl_cd1400flowctrl(stlport_t *portp, int state)
+static void stl_cd1400flowctrl(struct stlport *portp, int state)
{
struct tty_struct *tty;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400flowctrl(portp=%x,state=%x)\n", (int) portp, state);
-#endif
+ pr_debug("stl_cd1400flowctrl(portp=%p,state=%x)\n", portp, state);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
@@ -3697,19 +3323,17 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state)
* Send a flow control character...
*/
-static void stl_cd1400sendflow(stlport_t *portp, int state)
+static void stl_cd1400sendflow(struct stlport *portp, int state)
{
struct tty_struct *tty;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400sendflow(portp=%x,state=%x)\n", (int) portp, state);
-#endif
+ pr_debug("stl_cd1400sendflow(portp=%p,state=%x)\n", portp, state);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
@@ -3732,15 +3356,13 @@ static void stl_cd1400sendflow(stlport_t *portp, int state)
/*****************************************************************************/
-static void stl_cd1400flush(stlport_t *portp)
+static void stl_cd1400flush(struct stlport *portp)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400flush(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_cd1400flush(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
@@ -3763,13 +3385,11 @@ static void stl_cd1400flush(stlport_t *portp)
* maintains the busy port flag.
*/
-static int stl_cd1400datastate(stlport_t *portp)
+static int stl_cd1400datastate(struct stlport *portp)
{
-#ifdef DEBUG
- printk("stl_cd1400datastate(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_cd1400datastate(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return 0;
return test_bit(ASYI_TXBUSY, &portp->istate) ? 1 : 0;
@@ -3781,14 +3401,11 @@ static int stl_cd1400datastate(stlport_t *portp)
* Interrupt service routine for cd1400 EasyIO boards.
*/
-static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase)
+static void stl_cd1400eiointr(struct stlpanel *panelp, unsigned int iobase)
{
unsigned char svrtype;
-#ifdef DEBUG
- printk("stl_cd1400eiointr(panelp=%x,iobase=%x)\n",
- (int) panelp, iobase);
-#endif
+ pr_debug("stl_cd1400eiointr(panelp=%p,iobase=%x)\n", panelp, iobase);
spin_lock(&brd_lock);
outb(SVRR, iobase);
@@ -3814,14 +3431,11 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase)
* Interrupt service routine for cd1400 panels.
*/
-static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase)
+static void stl_cd1400echintr(struct stlpanel *panelp, unsigned int iobase)
{
unsigned char svrtype;
-#ifdef DEBUG
- printk("stl_cd1400echintr(panelp=%x,iobase=%x)\n", (int) panelp,
- iobase);
-#endif
+ pr_debug("stl_cd1400echintr(panelp=%p,iobase=%x)\n", panelp, iobase);
outb(SVRR, iobase);
svrtype = inb(iobase + EREG_DATA);
@@ -3843,7 +3457,7 @@ static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase)
* this is the only way to generate them on the cd1400.
*/
-static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr)
+static int stl_cd1400breakisr(struct stlport *portp, int ioaddr)
{
if (portp->brklen == 1) {
outb((COR2 + portp->uartaddr), ioaddr);
@@ -3885,16 +3499,14 @@ static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr)
* be NULL if the buffer has been freed.
*/
-static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr)
+static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
{
- stlport_t *portp;
+ struct stlport *portp;
int len, stlen;
char *head, *tail;
unsigned char ioack, srer;
-#ifdef DEBUG
- printk("stl_cd1400txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr);
-#endif
+ pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr);
ioack = inb(ioaddr + EREG_TXACK);
if (((ioack & panelp->ackmask) != 0) ||
@@ -3933,9 +3545,9 @@ static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr)
}
outb(srer, (ioaddr + EREG_DATA));
} else {
- len = MIN(len, CD1400_TXFIFOSIZE);
+ len = min(len, CD1400_TXFIFOSIZE);
portp->stats.txtotal += len;
- stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+ stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
outb((TDR + portp->uartaddr), ioaddr);
outsb((ioaddr + EREG_DATA), tail, stlen);
len -= stlen;
@@ -3966,17 +3578,15 @@ stl_txalldone:
* shutdown a port not in user context. Need to handle this case.
*/
-static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr)
+static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
{
- stlport_t *portp;
+ struct stlport *portp;
struct tty_struct *tty;
unsigned int ioack, len, buflen;
unsigned char status;
char ch;
-#ifdef DEBUG
- printk("stl_cd1400rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr);
-#endif
+ pr_debug("stl_cd1400rxisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr);
ioack = inb(ioaddr + EREG_RXACK);
if ((ioack & panelp->ackmask) != 0) {
@@ -3990,13 +3600,13 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr)
outb((RDCR + portp->uartaddr), ioaddr);
len = inb(ioaddr + EREG_DATA);
if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
- len = MIN(len, sizeof(stl_unwanted));
+ len = min(len, sizeof(stl_unwanted));
outb((RDSR + portp->uartaddr), ioaddr);
insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
portp->stats.rxtotal += len;
} else {
- len = MIN(len, buflen);
+ len = min(len, buflen);
if (len > 0) {
unsigned char *ptr;
outb((RDSR + portp->uartaddr), ioaddr);
@@ -4033,18 +3643,16 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr)
do_SAK(tty);
BRDENABLE(portp->brdnr, portp->pagenr);
}
- } else if (status & ST_PARITY) {
+ } else if (status & ST_PARITY)
status = TTY_PARITY;
- } else if (status & ST_FRAMING) {
+ else if (status & ST_FRAMING)
status = TTY_FRAME;
- } else if(status & ST_OVERRUN) {
+ else if(status & ST_OVERRUN)
status = TTY_OVERRUN;
- } else {
+ else
status = 0;
- }
- } else {
+ } else
status = 0;
- }
tty_insert_flip_char(tty, ch, status);
tty_schedule_flip(tty);
}
@@ -4066,15 +3674,13 @@ stl_rxalldone:
* processing routine.
*/
-static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr)
+static void stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int ioack;
unsigned char misr;
-#ifdef DEBUG
- printk("stl_cd1400mdmisr(panelp=%x)\n", (int) panelp);
-#endif
+ pr_debug("stl_cd1400mdmisr(panelp=%p)\n", panelp);
ioack = inb(ioaddr + EREG_MDACK);
if (((ioack & panelp->ackmask) != 0) ||
@@ -4106,19 +3712,19 @@ static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr)
* (Maybe should make this inline...)
*/
-static int stl_sc26198getreg(stlport_t *portp, int regnr)
+static int stl_sc26198getreg(struct stlport *portp, int regnr)
{
outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR));
return inb(portp->ioaddr + XP_DATA);
}
-static void stl_sc26198setreg(stlport_t *portp, int regnr, int value)
+static void stl_sc26198setreg(struct stlport *portp, int regnr, int value)
{
outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR));
outb(value, (portp->ioaddr + XP_DATA));
}
-static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value)
+static int stl_sc26198updatereg(struct stlport *portp, int regnr, int value)
{
outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR));
if (inb(portp->ioaddr + XP_DATA) != value) {
@@ -4134,14 +3740,14 @@ static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value)
* Functions to get and set the sc26198 global registers.
*/
-static int stl_sc26198getglobreg(stlport_t *portp, int regnr)
+static int stl_sc26198getglobreg(struct stlport *portp, int regnr)
{
outb(regnr, (portp->ioaddr + XP_ADDR));
return inb(portp->ioaddr + XP_DATA);
}
#if 0
-static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value)
+static void stl_sc26198setglobreg(struct stlport *portp, int regnr, int value)
{
outb(regnr, (portp->ioaddr + XP_ADDR));
outb(value, (portp->ioaddr + XP_DATA));
@@ -4156,15 +3762,12 @@ static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value)
* identical when dealing with ports.
*/
-static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
+static int stl_sc26198panelinit(struct stlbrd *brdp, struct stlpanel *panelp)
{
int chipmask, i;
int nrchips, ioaddr;
-#ifdef DEBUG
- printk("stl_sc26198panelinit(brdp=%x,panelp=%x)\n",
- (int) brdp, (int) panelp);
-#endif
+ pr_debug("stl_sc26198panelinit(brdp=%p,panelp=%p)\n", brdp, panelp);
BRDENABLE(panelp->brdnr, panelp->pagenr);
@@ -4176,7 +3779,7 @@ static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
if (brdp->brdtype == BRD_ECHPCI)
outb(panelp->pagenr, brdp->ioctrl);
- for (i = 0; (i < nrchips); i++) {
+ for (i = 0; i < nrchips; i++) {
ioaddr = panelp->iobase + (i * 4);
outb(SCCR, (ioaddr + XP_ADDR));
outb(CR_RESETALL, (ioaddr + XP_DATA));
@@ -4204,15 +3807,13 @@ static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
* Initialize hardware specific port registers.
*/
-static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp)
+static void stl_sc26198portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp)
{
-#ifdef DEBUG
- printk("stl_sc26198portinit(brdp=%x,panelp=%x,portp=%x)\n",
- (int) brdp, (int) panelp, (int) portp);
-#endif
+ pr_debug("stl_sc26198portinit(brdp=%p,panelp=%p,portp=%p)\n", brdp,
+ panelp, portp);
- if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) ||
- (portp == (stlport_t *) NULL))
+ if ((brdp == NULL) || (panelp == NULL) ||
+ (portp == NULL))
return;
portp->ioaddr = panelp->iobase + ((portp->portnr < 8) ? 0 : 4);
@@ -4232,9 +3833,9 @@ static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *p
* settings.
*/
-static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
+static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp)
{
- stlbrd_t *brdp;
+ struct stlbrd *brdp;
unsigned long flags;
unsigned int baudrate;
unsigned char mr0, mr1, mr2, clk;
@@ -4249,7 +3850,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
imroff = 0;
brdp = stl_brds[portp->brdnr];
- if (brdp == (stlbrd_t *) NULL)
+ if (brdp == NULL)
return;
/*
@@ -4298,9 +3899,8 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
mr1 |= (MR1_PARENB | MR1_PARODD);
else
mr1 |= (MR1_PARENB | MR1_PAREVEN);
- } else {
+ } else
mr1 |= MR1_PARNONE;
- }
mr1 |= MR1_ERRBLOCK;
@@ -4340,12 +3940,10 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
if (baudrate > STL_SC26198MAXBAUD)
baudrate = STL_SC26198MAXBAUD;
- if (baudrate > 0) {
- for (clk = 0; (clk < SC26198_NRBAUDS); clk++) {
+ if (baudrate > 0)
+ for (clk = 0; clk < SC26198_NRBAUDS; clk++)
if (baudrate <= sc26198_baudtable[clk])
break;
- }
- }
/*
* Check what form of modem signaling is required and set it up.
@@ -4367,9 +3965,9 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
if (tiosp->c_iflag & IXON) {
mr0 |= MR0_SWFTX | MR0_SWFT;
imron |= IR_XONXOFF;
- } else {
+ } else
imroff |= IR_XONXOFF;
- }
+
if (tiosp->c_iflag & IXOFF)
mr0 |= MR0_SWFRX;
@@ -4383,15 +3981,13 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
* them all up.
*/
-#ifdef DEBUG
- printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
+ pr_debug("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
portp->portnr, portp->panelnr, portp->brdnr);
- printk(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk);
- printk(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff);
- printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n",
+ pr_debug(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk);
+ pr_debug(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff);
+ pr_debug(" schr1=%x schr2=%x schr3=%x schr4=%x\n",
tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP],
tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
-#endif
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
@@ -4429,15 +4025,13 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
* Set the state of the DTR and RTS signals.
*/
-static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts)
+static void stl_sc26198setsignals(struct stlport *portp, int dtr, int rts)
{
unsigned char iopioron, iopioroff;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198setsignals(portp=%x,dtr=%d,rts=%d)\n",
- (int) portp, dtr, rts);
-#endif
+ pr_debug("stl_sc26198setsignals(portp=%p,dtr=%d,rts=%d)\n", portp,
+ dtr, rts);
iopioron = 0;
iopioroff = 0;
@@ -4464,15 +4058,13 @@ static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts)
* Return the state of the signals.
*/
-static int stl_sc26198getsignals(stlport_t *portp)
+static int stl_sc26198getsignals(struct stlport *portp)
{
unsigned char ipr;
unsigned long flags;
int sigs;
-#ifdef DEBUG
- printk("stl_sc26198getsignals(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198getsignals(portp=%p)\n", portp);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
@@ -4495,15 +4087,12 @@ static int stl_sc26198getsignals(stlport_t *portp)
* Enable/Disable the Transmitter and/or Receiver.
*/
-static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx)
+static void stl_sc26198enablerxtx(struct stlport *portp, int rx, int tx)
{
unsigned char ccr;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198enablerxtx(portp=%x,rx=%d,tx=%d)\n",
- (int) portp, rx, tx);
-#endif
+ pr_debug("stl_sc26198enablerxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx,tx);
ccr = portp->crenable;
if (tx == 0)
@@ -4529,15 +4118,12 @@ static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx)
* Start/stop the Transmitter and/or Receiver.
*/
-static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx)
+static void stl_sc26198startrxtx(struct stlport *portp, int rx, int tx)
{
unsigned char imr;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198startrxtx(portp=%x,rx=%d,tx=%d)\n",
- (int) portp, rx, tx);
-#endif
+ pr_debug("stl_sc26198startrxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx, tx);
imr = portp->imr;
if (tx == 0)
@@ -4565,13 +4151,11 @@ static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx)
* Disable all interrupts from this port.
*/
-static void stl_sc26198disableintrs(stlport_t *portp)
+static void stl_sc26198disableintrs(struct stlport *portp)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198disableintrs(portp=%p)\n", portp);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
@@ -4583,22 +4167,20 @@ static void stl_sc26198disableintrs(stlport_t *portp)
/*****************************************************************************/
-static void stl_sc26198sendbreak(stlport_t *portp, int len)
+static void stl_sc26198sendbreak(struct stlport *portp, int len)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len);
-#endif
+ pr_debug("stl_sc26198sendbreak(portp=%p,len=%d)\n", portp, len);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
if (len == 1) {
stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK);
portp->stats.txbreaks++;
- } else {
+ } else
stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK);
- }
+
BRDDISABLE(portp->brdnr);
spin_unlock_irqrestore(&brd_lock, flags);
}
@@ -4609,20 +4191,18 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len)
* Take flow control actions...
*/
-static void stl_sc26198flowctrl(stlport_t *portp, int state)
+static void stl_sc26198flowctrl(struct stlport *portp, int state)
{
struct tty_struct *tty;
unsigned long flags;
unsigned char mr0;
-#ifdef DEBUG
- printk("stl_sc26198flowctrl(portp=%x,state=%x)\n", (int) portp, state);
-#endif
+ pr_debug("stl_sc26198flowctrl(portp=%p,state=%x)\n", portp, state);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
@@ -4680,20 +4260,18 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state)
* Send a flow control character.
*/
-static void stl_sc26198sendflow(stlport_t *portp, int state)
+static void stl_sc26198sendflow(struct stlport *portp, int state)
{
struct tty_struct *tty;
unsigned long flags;
unsigned char mr0;
-#ifdef DEBUG
- printk("stl_sc26198sendflow(portp=%x,state=%x)\n", (int) portp, state);
-#endif
+ pr_debug("stl_sc26198sendflow(portp=%p,state=%x)\n", portp, state);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
@@ -4721,15 +4299,13 @@ static void stl_sc26198sendflow(stlport_t *portp, int state)
/*****************************************************************************/
-static void stl_sc26198flush(stlport_t *portp)
+static void stl_sc26198flush(struct stlport *portp)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198flush(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198flush(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
@@ -4751,16 +4327,14 @@ static void stl_sc26198flush(stlport_t *portp)
* check the port statusy register to be sure.
*/
-static int stl_sc26198datastate(stlport_t *portp)
+static int stl_sc26198datastate(struct stlport *portp)
{
unsigned long flags;
unsigned char sr;
-#ifdef DEBUG
- printk("stl_sc26198datastate(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198datastate(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return 0;
if (test_bit(ASYI_TXBUSY, &portp->istate))
return 1;
@@ -4781,18 +4355,16 @@ static int stl_sc26198datastate(stlport_t *portp)
* to process a command...
*/
-static void stl_sc26198wait(stlport_t *portp)
+static void stl_sc26198wait(struct stlport *portp)
{
int i;
-#ifdef DEBUG
- printk("stl_sc26198wait(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198wait(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
- for (i = 0; (i < 20); i++)
+ for (i = 0; i < 20; i++)
stl_sc26198getglobreg(portp, TSTR);
}
@@ -4804,7 +4376,7 @@ static void stl_sc26198wait(stlport_t *portp)
* automatic flow control modes of the sc26198.
*/
-static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty)
+static void stl_sc26198txunflow(struct stlport *portp, struct tty_struct *tty)
{
unsigned char mr0;
@@ -4822,9 +4394,9 @@ static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty)
* Interrupt service routine for sc26198 panels.
*/
-static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase)
+static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int iack;
spin_lock(&brd_lock);
@@ -4860,16 +4432,14 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase)
* be NULL if the buffer has been freed.
*/
-static void stl_sc26198txisr(stlport_t *portp)
+static void stl_sc26198txisr(struct stlport *portp)
{
unsigned int ioaddr;
unsigned char mr0;
int len, stlen;
char *head, *tail;
-#ifdef DEBUG
- printk("stl_sc26198txisr(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198txisr(portp=%p)\n", portp);
ioaddr = portp->ioaddr;
head = portp->tx.head;
@@ -4894,9 +4464,9 @@ static void stl_sc26198txisr(stlport_t *portp)
outb(mr0, (ioaddr + XP_DATA));
}
} else {
- len = MIN(len, SC26198_TXFIFOSIZE);
+ len = min(len, SC26198_TXFIFOSIZE);
portp->stats.txtotal += len;
- stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+ stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
outb(GTXFIFO, (ioaddr + XP_ADDR));
outsb((ioaddr + XP_DATA), tail, stlen);
len -= stlen;
@@ -4923,14 +4493,12 @@ static void stl_sc26198txisr(stlport_t *portp)
* shutdown a port not in user context. Need to handle this case.
*/
-static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack)
+static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
{
struct tty_struct *tty;
unsigned int len, buflen, ioaddr;
-#ifdef DEBUG
- printk("stl_sc26198rxisr(portp=%x,iack=%x)\n", (int) portp, iack);
-#endif
+ pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack);
tty = portp->tty;
ioaddr = portp->ioaddr;
@@ -4939,13 +4507,13 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack)
if ((iack & IVR_TYPEMASK) == IVR_RXDATA) {
if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
- len = MIN(len, sizeof(stl_unwanted));
+ len = min(len, sizeof(stl_unwanted));
outb(GRXFIFO, (ioaddr + XP_ADDR));
insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
portp->stats.rxtotal += len;
} else {
- len = MIN(len, buflen);
+ len = min(len, buflen);
if (len > 0) {
unsigned char *ptr;
outb(GRXFIFO, (ioaddr + XP_ADDR));
@@ -4965,8 +4533,8 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack)
* flow control modes of the sc26198.
*/
if (test_bit(ASYI_TXFLOWED, &portp->istate)) {
- if ((tty != (struct tty_struct *) NULL) &&
- (tty->termios != (struct termios *) NULL) &&
+ if ((tty != NULL) &&
+ (tty->termios != NULL) &&
(tty->termios->c_iflag & IXANY)) {
stl_sc26198txunflow(portp, tty);
}
@@ -4979,7 +4547,7 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack)
* Process an RX bad character.
*/
-static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch)
+static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char ch)
{
struct tty_struct *tty;
unsigned int ioaddr;
@@ -4996,7 +4564,7 @@ static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, ch
if (status & SR_RXBREAK)
portp->stats.rxbreaks++;
- if ((tty != (struct tty_struct *) NULL) &&
+ if ((tty != NULL) &&
((portp->rxignoremsk & status) == 0)) {
if (portp->rxmarkmsk & status) {
if (status & SR_RXBREAK) {
@@ -5005,18 +4573,16 @@ static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, ch
do_SAK(tty);
BRDENABLE(portp->brdnr, portp->pagenr);
}
- } else if (status & SR_RXPARITY) {
+ } else if (status & SR_RXPARITY)
status = TTY_PARITY;
- } else if (status & SR_RXFRAMING) {
+ else if (status & SR_RXFRAMING)
status = TTY_FRAME;
- } else if(status & SR_RXOVERRUN) {
+ else if(status & SR_RXOVERRUN)
status = TTY_OVERRUN;
- } else {
+ else
status = 0;
- }
- } else {
+ } else
status = 0;
- }
tty_insert_flip_char(tty, ch, status);
tty_schedule_flip(tty);
@@ -5037,7 +4603,7 @@ static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, ch
* the FIFO).
*/
-static void stl_sc26198rxbadchars(stlport_t *portp)
+static void stl_sc26198rxbadchars(struct stlport *portp)
{
unsigned char status, mr1;
char ch;
@@ -5070,13 +4636,11 @@ static void stl_sc26198rxbadchars(stlport_t *portp)
* processing time.
*/
-static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack)
+static void stl_sc26198otherisr(struct stlport *portp, unsigned int iack)
{
unsigned char cir, ipr, xisr;
-#ifdef DEBUG
- printk("stl_sc26198otherisr(portp=%x,iack=%x)\n", (int) portp, iack);
-#endif
+ pr_debug("stl_sc26198otherisr(portp=%p,iack=%x)\n", portp, iack);
cir = stl_sc26198getglobreg(portp, CIR);
@@ -5109,4 +4673,172 @@ static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack)
}
}
-/*****************************************************************************/
+static void stl_free_isabrds(void)
+{
+ struct stlbrd *brdp;
+ unsigned int i;
+
+ for (i = 0; i < stl_nrbrds; i++) {
+ if ((brdp = stl_brds[i]) == NULL || (brdp->state & STL_PROBED))
+ continue;
+
+ free_irq(brdp->irq, brdp);
+
+ stl_cleanup_panels(brdp);
+
+ release_region(brdp->ioaddr1, brdp->iosize1);
+ if (brdp->iosize2 > 0)
+ release_region(brdp->ioaddr2, brdp->iosize2);
+
+ kfree(brdp);
+ stl_brds[i] = NULL;
+ }
+}
+
+/*
+ * Loadable module initialization stuff.
+ */
+static int __init stallion_module_init(void)
+{
+ struct stlbrd *brdp;
+ struct stlconf conf;
+ unsigned int i, j;
+ int retval;
+
+ printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
+
+ spin_lock_init(&stallion_lock);
+ spin_lock_init(&brd_lock);
+
+/*
+ * Find any dynamically supported boards. That is via module load
+ * line options.
+ */
+ for (i = stl_nrbrds; i < stl_nargs; i++) {
+ memset(&conf, 0, sizeof(conf));
+ if (stl_parsebrd(&conf, stl_brdsp[i]) == 0)
+ continue;
+ if ((brdp = stl_allocbrd()) == NULL)
+ continue;
+ brdp->brdnr = i;
+ brdp->brdtype = conf.brdtype;
+ brdp->ioaddr1 = conf.ioaddr1;
+ brdp->ioaddr2 = conf.ioaddr2;
+ brdp->irq = conf.irq;
+ brdp->irqtype = conf.irqtype;
+ if (stl_brdinit(brdp))
+ kfree(brdp);
+ else {
+ for (j = 0; j < brdp->nrports; j++)
+ tty_register_device(stl_serial,
+ brdp->brdnr * STL_MAXPORTS + j, NULL);
+ stl_brds[brdp->brdnr] = brdp;
+ stl_nrbrds = i + 1;
+ }
+ }
+
+ /* this has to be _after_ isa finding because of locking */
+ retval = pci_register_driver(&stl_pcidriver);
+ if (retval && stl_nrbrds == 0)
+ goto err;
+
+ stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
+ if (!stl_serial) {
+ retval = -ENOMEM;
+ goto err_pcidr;
+ }
+
+/*
+ * Set up a character driver for per board stuff. This is mainly used
+ * to do stats ioctls on the ports.
+ */
+ if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
+ printk("STALLION: failed to register serial board device\n");
+
+ stallion_class = class_create(THIS_MODULE, "staliomem");
+ if (IS_ERR(stallion_class)) {
+ retval = PTR_ERR(stallion_class);
+ goto err_reg;
+ }
+ for (i = 0; i < 4; i++)
+ class_device_create(stallion_class, NULL,
+ MKDEV(STL_SIOMEMMAJOR, i), NULL,
+ "staliomem%d", i);
+
+ stl_serial->owner = THIS_MODULE;
+ stl_serial->driver_name = stl_drvname;
+ stl_serial->name = "ttyE";
+ stl_serial->major = STL_SERIALMAJOR;
+ stl_serial->minor_start = 0;
+ stl_serial->type = TTY_DRIVER_TYPE_SERIAL;
+ stl_serial->subtype = SERIAL_TYPE_NORMAL;
+ stl_serial->init_termios = stl_deftermios;
+ stl_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(stl_serial, &stl_ops);
+
+ retval = tty_register_driver(stl_serial);
+ if (retval) {
+ printk("STALLION: failed to register serial driver\n");
+ goto err_clsdev;
+ }
+
+ return 0;
+err_clsdev:
+ for (i = 0; i < 4; i++)
+ class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
+ class_destroy(stallion_class);
+err_reg:
+ unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
+ put_tty_driver(stl_serial);
+err_pcidr:
+ pci_unregister_driver(&stl_pcidriver);
+ stl_free_isabrds();
+err:
+ return retval;
+}
+
+static void __exit stallion_module_exit(void)
+{
+ struct stlbrd *brdp;
+ unsigned int i, j;
+ int retval;
+
+ pr_debug("cleanup_module()\n");
+
+ printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle,
+ stl_drvversion);
+
+/*
+ * Free up all allocated resources used by the ports. This includes
+ * memory and interrupts. As part of this process we will also do
+ * a hangup on every open port - to try to flush out any processes
+ * hanging onto ports.
+ */
+ for (i = 0; i < stl_nrbrds; i++) {
+ if ((brdp = stl_brds[i]) == NULL || (brdp->state & STL_PROBED))
+ continue;
+ for (j = 0; j < brdp->nrports; j++)
+ tty_unregister_device(stl_serial,
+ brdp->brdnr * STL_MAXPORTS + j);
+ }
+ tty_unregister_driver(stl_serial);
+ put_tty_driver(stl_serial);
+
+ for (i = 0; i < 4; i++)
+ class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
+ if ((retval = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
+ printk("STALLION: failed to un-register serial memory device, "
+ "errno=%d\n", -retval);
+ class_destroy(stallion_class);
+
+ pci_unregister_driver(&stl_pcidriver);
+
+ stl_free_isabrds();
+}
+
+module_init(stallion_module_init);
+module_exit(stallion_module_exit);
+
+MODULE_AUTHOR("Greg Ungerer");
+MODULE_DESCRIPTION("Stallion Multiport Serial Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index cc10af08cb0..1da92a689ae 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -32,7 +32,6 @@
* USA.
*
* Revision history:
- * $Log: sx.c,v $
* Revision 1.33 2000/03/09 10:00:00 pvdl,wolff
* - Fixed module and port counting
* - Fixed signal handling
@@ -199,9 +198,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 $"
+#define SX_VERSION 1.33
#include <linux/module.h>
#include <linux/kdev_t.h>
@@ -217,6 +214,7 @@
#include <linux/fcntl.h>
#include <linux/major.h>
#include <linux/delay.h>
+#include <linux/eisa.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -240,7 +238,6 @@
#include <linux/generic_serial.h>
#include "sx.h"
-
/* I don't think that this driver can handle more than 256 ports on
one machine. You'll have to increase the number of boards in sx.h
if you want more than 4 boards. */
@@ -249,21 +246,12 @@
#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
#endif
-#ifdef CONFIG_PCI
-static struct pci_device_id sx_pci_tbl[] = {
- { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, PCI_ANY_ID, PCI_ANY_ID },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, sx_pci_tbl);
-#endif /* CONFIG_PCI */
-
/* Configurable options:
(Don't be too sure that it'll work if you toggle them) */
/* Am I paranoid or not ? ;-) */
#undef SX_PARANOIA_CHECK
-
/* 20 -> 2000 per second. The card should rate-limit interrupts at 100
Hz, but it is user configurable. I don't recommend going above 1000
Hz. The interrupt ratelimit might trigger if the interrupt is
@@ -277,7 +265,6 @@ MODULE_DEVICE_TABLE(pci, sx_pci_tbl);
interrupt. Use polling. */
#undef IRQ_RATE_LIMIT
-
#if 0
/* Not implemented */
/*
@@ -286,35 +273,33 @@ MODULE_DEVICE_TABLE(pci, sx_pci_tbl);
*/
#define SX_REPORT_FIFO
#define SX_REPORT_OVERRUN
-#endif
-
+#endif
/* Function prototypes */
-static void sx_disable_tx_interrupts (void * ptr);
-static void sx_enable_tx_interrupts (void * ptr);
-static void sx_disable_rx_interrupts (void * ptr);
-static void sx_enable_rx_interrupts (void * ptr);
-static int sx_get_CD (void * ptr);
-static void sx_shutdown_port (void * ptr);
-static int sx_set_real_termios (void *ptr);
-static void sx_close (void *ptr);
-static int sx_chars_in_buffer (void * ptr);
-static int sx_init_board (struct sx_board *board);
-static int sx_init_portstructs (int nboards, int nports);
-static int sx_fw_ioctl (struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+static void sx_disable_tx_interrupts(void *ptr);
+static void sx_enable_tx_interrupts(void *ptr);
+static void sx_disable_rx_interrupts(void *ptr);
+static void sx_enable_rx_interrupts(void *ptr);
+static int sx_get_CD(void *ptr);
+static void sx_shutdown_port(void *ptr);
+static int sx_set_real_termios(void *ptr);
+static void sx_close(void *ptr);
+static int sx_chars_in_buffer(void *ptr);
+static int sx_init_board(struct sx_board *board);
+static int sx_init_portstructs(int nboards, int nports);
+static int sx_fw_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
static int sx_init_drivers(void);
-
static struct tty_driver *sx_driver;
+static DEFINE_MUTEX(sx_boards_lock);
static struct sx_board boards[SX_NBOARDS];
static struct sx_port *sx_ports;
static int sx_initialized;
static int sx_nports;
static int sx_debug;
-
/* You can have the driver poll your card.
- Set sx_poll to 1 to poll every timer tick (10ms on Intel).
This is used when the card cannot use an interrupt for some reason.
@@ -333,27 +318,36 @@ static int sx_slowpoll;
static int sx_maxints = 100;
+#ifdef CONFIG_ISA
+
/* These are the only open spaces in my computer. Yours may have more
or less.... -- REW
duh: Card at 0xa0000 is possible on HP Netserver?? -- pvdl
*/
-static int sx_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000,
- 0xc8000, 0xd8000, 0xe8000};
-static int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000,
- 0xc8000, 0xd8000, 0xe8000, 0xa0000};
-static int si1_probe_addrs[]= { 0xd0000};
+static int sx_probe_addrs[] = {
+ 0xc0000, 0xd0000, 0xe0000,
+ 0xc8000, 0xd8000, 0xe8000
+};
+static int si_probe_addrs[] = {
+ 0xc0000, 0xd0000, 0xe0000,
+ 0xc8000, 0xd8000, 0xe8000, 0xa0000
+};
+static int si1_probe_addrs[] = {
+ 0xd0000
+};
#define NR_SX_ADDRS ARRAY_SIZE(sx_probe_addrs)
#define NR_SI_ADDRS ARRAY_SIZE(si_probe_addrs)
#define NR_SI1_ADDRS ARRAY_SIZE(si1_probe_addrs)
+module_param_array(sx_probe_addrs, int, NULL, 0);
+module_param_array(si_probe_addrs, int, NULL, 0);
+#endif
/* Set the mask to all-ones. This alas, only supports 32 interrupts.
Some architectures may need more. */
static int sx_irqmask = -1;
-module_param_array(sx_probe_addrs, int, NULL, 0);
-module_param_array(si_probe_addrs, int, NULL, 0);
module_param(sx_poll, int, 0);
module_param(sx_slowpoll, int, 0);
module_param(sx_maxints, int, 0);
@@ -368,13 +362,12 @@ static struct real_driver sx_real_driver = {
sx_disable_rx_interrupts,
sx_enable_rx_interrupts,
sx_get_CD,
- sx_shutdown_port,
- sx_set_real_termios,
+ sx_shutdown_port,
+ sx_set_real_termios,
sx_chars_in_buffer,
sx_close,
};
-
/*
This driver can spew a whole lot of debugging output at you. If you
need maximum performance, you should disable the DEBUG define. To
@@ -385,23 +378,17 @@ static struct real_driver sx_real_driver = {
*/
#define DEBUG
-
#ifdef DEBUG
-#define sx_dprintk(f, str...) if (sx_debug & f) printk (str)
+#define sx_dprintk(f, str...) if (sx_debug & f) printk (str)
#else
-#define sx_dprintk(f, str...) /* nothing */
+#define sx_dprintk(f, str...) /* nothing */
#endif
+#define func_enter() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__FUNCTION__)
+#define func_exit() sx_dprintk(SX_DEBUG_FLOW, "sx: exit %s\n",__FUNCTION__)
-
-#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s\n",__FUNCTION__)
-#define func_exit() sx_dprintk (SX_DEBUG_FLOW, "sx: exit %s\n", __FUNCTION__)
-
-#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
- __FUNCTION__, port->line)
-
-
-
+#define func_enter2() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
+ __FUNCTION__, port->line)
/*
* Firmware loader driver specific routines
@@ -409,31 +396,26 @@ static struct real_driver sx_real_driver = {
*/
static const struct file_operations sx_fw_fops = {
- .owner = THIS_MODULE,
- .ioctl = sx_fw_ioctl,
+ .owner = THIS_MODULE,
+ .ioctl = sx_fw_ioctl,
};
static struct miscdevice sx_fw_device = {
SXCTL_MISC_MINOR, "sxctl", &sx_fw_fops
};
-
-
-
-
#ifdef SX_PARANOIA_CHECK
/* This doesn't work. Who's paranoid around here? Not me! */
-static inline int sx_paranoia_check(struct sx_port const * port,
+static inline int sx_paranoia_check(struct sx_port const *port,
char *name, const char *routine)
{
+ static const char *badmagic = KERN_ERR "sx: Warning: bad sx port magic "
+ "number for device %s in %s\n";
+ static const char *badinfo = KERN_ERR "sx: Warning: null sx port for "
+ "device %s in %s\n";
- static const char *badmagic =
- KERN_ERR "sx: Warning: bad sx port magic number for device %s in %s\n";
- static const char *badinfo =
- KERN_ERR "sx: Warning: null sx port for device %s in %s\n";
-
if (!port) {
printk(badinfo, name, routine);
return 1;
@@ -456,23 +438,24 @@ static inline int sx_paranoia_check(struct sx_port const * port,
#define TIMEOUT_1 30
#define TIMEOUT_2 1000000
-
#ifdef DEBUG
static void my_hd_io(void __iomem *p, int len)
{
int i, j, ch;
unsigned char __iomem *addr = p;
- for (i=0;i<len;i+=16) {
- printk ("%p ", addr+i);
- for (j=0;j<16;j++) {
- printk ("%02x %s", readb(addr+j+i), (j==7)?" ":"");
+ for (i = 0; i < len; i += 16) {
+ printk("%p ", addr + i);
+ for (j = 0; j < 16; j++) {
+ printk("%02x %s", readb(addr + j + i),
+ (j == 7) ? " " : "");
}
- for (j=0;j<16;j++) {
- ch = readb(addr+j+i);
- printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+ for (j = 0; j < 16; j++) {
+ ch = readb(addr + j + i);
+ printk("%c", (ch < 0x20) ? '.' :
+ ((ch > 0x7f) ? '.' : ch));
}
- printk ("\n");
+ printk("\n");
}
}
static void my_hd(void *p, int len)
@@ -480,419 +463,468 @@ static void my_hd(void *p, int len)
int i, j, ch;
unsigned char *addr = p;
- for (i=0;i<len;i+=16) {
- printk ("%p ", addr+i);
- for (j=0;j<16;j++) {
- printk ("%02x %s", addr[j+i], (j==7)?" ":"");
+ for (i = 0; i < len; i += 16) {
+ printk("%p ", addr + i);
+ for (j = 0; j < 16; j++) {
+ printk("%02x %s", addr[j + i], (j == 7) ? " " : "");
}
- for (j=0;j<16;j++) {
- ch = addr[j+i];
- printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+ for (j = 0; j < 16; j++) {
+ ch = addr[j + i];
+ printk("%c", (ch < 0x20) ? '.' :
+ ((ch > 0x7f) ? '.' : ch));
}
- printk ("\n");
+ printk("\n");
}
}
#endif
-
-
/* This needs redoing for Alpha -- REW -- Done. */
-static inline void write_sx_byte (struct sx_board *board, int offset, u8 byte)
+static inline void write_sx_byte(struct sx_board *board, int offset, u8 byte)
{
- writeb (byte, board->base+offset);
+ writeb(byte, board->base + offset);
}
-static inline u8 read_sx_byte (struct sx_board *board, int offset)
+static inline u8 read_sx_byte(struct sx_board *board, int offset)
{
- return readb (board->base+offset);
+ return readb(board->base + offset);
}
-
-static inline void write_sx_word (struct sx_board *board, int offset, u16 word)
+static inline void write_sx_word(struct sx_board *board, int offset, u16 word)
{
- writew (word, board->base+offset);
+ writew(word, board->base + offset);
}
-static inline u16 read_sx_word (struct sx_board *board, int offset)
+static inline u16 read_sx_word(struct sx_board *board, int offset)
{
- return readw (board->base + offset);
+ return readw(board->base + offset);
}
-
-static int sx_busy_wait_eq (struct sx_board *board,
- int offset, int mask, int correctval)
+static int sx_busy_wait_eq(struct sx_board *board,
+ int offset, int mask, int correctval)
{
int i;
- func_enter ();
+ func_enter();
- for (i=0; i < TIMEOUT_1 ;i++)
- if ((read_sx_byte (board, offset) & mask) == correctval) {
- func_exit ();
+ for (i = 0; i < TIMEOUT_1; i++)
+ if ((read_sx_byte(board, offset) & mask) == correctval) {
+ func_exit();
return 1;
}
- for (i=0; i < TIMEOUT_2 ;i++) {
- if ((read_sx_byte (board, offset) & mask) == correctval) {
- func_exit ();
+ for (i = 0; i < TIMEOUT_2; i++) {
+ if ((read_sx_byte(board, offset) & mask) == correctval) {
+ func_exit();
return 1;
}
- udelay (1);
+ udelay(1);
}
- func_exit ();
+ func_exit();
return 0;
}
-
-static int sx_busy_wait_neq (struct sx_board *board,
- int offset, int mask, int badval)
+static int sx_busy_wait_neq(struct sx_board *board,
+ int offset, int mask, int badval)
{
int i;
- func_enter ();
+ func_enter();
- for (i=0; i < TIMEOUT_1 ;i++)
- if ((read_sx_byte (board, offset) & mask) != badval) {
- func_exit ();
+ for (i = 0; i < TIMEOUT_1; i++)
+ if ((read_sx_byte(board, offset) & mask) != badval) {
+ func_exit();
return 1;
}
- for (i=0; i < TIMEOUT_2 ;i++) {
- if ((read_sx_byte (board, offset) & mask) != badval) {
- func_exit ();
+ for (i = 0; i < TIMEOUT_2; i++) {
+ if ((read_sx_byte(board, offset) & mask) != badval) {
+ func_exit();
return 1;
}
- udelay (1);
+ udelay(1);
}
- func_exit ();
+ func_exit();
return 0;
}
-
-
/* 5.6.4 of 6210028 r2.3 */
-static int sx_reset (struct sx_board *board)
+static int sx_reset(struct sx_board *board)
{
- func_enter ();
+ func_enter();
- if (IS_SX_BOARD (board)) {
+ if (IS_SX_BOARD(board)) {
- write_sx_byte (board, SX_CONFIG, 0);
- write_sx_byte (board, SX_RESET, 1); /* Value doesn't matter */
+ write_sx_byte(board, SX_CONFIG, 0);
+ write_sx_byte(board, SX_RESET, 1); /* Value doesn't matter */
- if (!sx_busy_wait_eq (board, SX_RESET_STATUS, 1, 0)) {
- printk (KERN_INFO "sx: Card doesn't respond to reset....\n");
+ if (!sx_busy_wait_eq(board, SX_RESET_STATUS, 1, 0)) {
+ printk(KERN_INFO "sx: Card doesn't respond to "
+ "reset...\n");
return 0;
}
} else if (IS_EISA_BOARD(board)) {
- outb(board->irq<<4, board->eisa_base+0xc02);
+ outb(board->irq << 4, board->eisa_base + 0xc02);
} else if (IS_SI1_BOARD(board)) {
- write_sx_byte (board, SI1_ISA_RESET, 0); // value does not matter
+ write_sx_byte(board, SI1_ISA_RESET, 0); /*value doesn't matter*/
} else {
/* Gory details of the SI/ISA board */
- write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_SET);
- write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_CLEAR);
- write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_CLEAR);
- write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_CLEAR);
- write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
- write_sx_byte (board, SI2_ISA_IRQSET, SI2_ISA_IRQSET_CLEAR);
+ write_sx_byte(board, SI2_ISA_RESET, SI2_ISA_RESET_SET);
+ write_sx_byte(board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_CLEAR);
+ write_sx_byte(board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_CLEAR);
+ write_sx_byte(board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_CLEAR);
+ write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
+ write_sx_byte(board, SI2_ISA_IRQSET, SI2_ISA_IRQSET_CLEAR);
}
- func_exit ();
+ func_exit();
return 1;
}
-
/* This doesn't work on machines where "NULL" isn't 0 */
/* If you have one of those, someone will need to write
the equivalent of this, which will amount to about 3 lines. I don't
want to complicate this right now. -- REW
(See, I do write comments every now and then :-) */
-#define OFFSETOF(strct, elem) ((long)&(((struct strct *)NULL)->elem))
-
-
-#define CHAN_OFFSET(port,elem) (port->ch_base + OFFSETOF (_SXCHANNEL, elem))
-#define MODU_OFFSET(board,addr,elem) (addr + OFFSETOF (_SXMODULE, elem))
-#define BRD_OFFSET(board,elem) (OFFSETOF (_SXCARD, elem))
+#define OFFSETOF(strct, elem) ((long)&(((struct strct *)NULL)->elem))
+#define CHAN_OFFSET(port,elem) (port->ch_base + OFFSETOF (_SXCHANNEL, elem))
+#define MODU_OFFSET(board,addr,elem) (addr + OFFSETOF (_SXMODULE, elem))
+#define BRD_OFFSET(board,elem) (OFFSETOF (_SXCARD, elem))
#define sx_write_channel_byte(port, elem, val) \
- write_sx_byte (port->board, CHAN_OFFSET (port, elem), val)
+ write_sx_byte (port->board, CHAN_OFFSET (port, elem), val)
#define sx_read_channel_byte(port, elem) \
- read_sx_byte (port->board, CHAN_OFFSET (port, elem))
+ read_sx_byte (port->board, CHAN_OFFSET (port, elem))
#define sx_write_channel_word(port, elem, val) \
- write_sx_word (port->board, CHAN_OFFSET (port, elem), val)
+ write_sx_word (port->board, CHAN_OFFSET (port, elem), val)
#define sx_read_channel_word(port, elem) \
- read_sx_word (port->board, CHAN_OFFSET (port, elem))
-
+ read_sx_word (port->board, CHAN_OFFSET (port, elem))
#define sx_write_module_byte(board, addr, elem, val) \
- write_sx_byte (board, MODU_OFFSET (board, addr, elem), val)
+ write_sx_byte (board, MODU_OFFSET (board, addr, elem), val)
#define sx_read_module_byte(board, addr, elem) \
- read_sx_byte (board, MODU_OFFSET (board, addr, elem))
+ read_sx_byte (board, MODU_OFFSET (board, addr, elem))
#define sx_write_module_word(board, addr, elem, val) \
- write_sx_word (board, MODU_OFFSET (board, addr, elem), val)
+ write_sx_word (board, MODU_OFFSET (board, addr, elem), val)
#define sx_read_module_word(board, addr, elem) \
- read_sx_word (board, MODU_OFFSET (board, addr, elem))
-
+ read_sx_word (board, MODU_OFFSET (board, addr, elem))
#define sx_write_board_byte(board, elem, val) \
- write_sx_byte (board, BRD_OFFSET (board, elem), val)
+ write_sx_byte (board, BRD_OFFSET (board, elem), val)
#define sx_read_board_byte(board, elem) \
- read_sx_byte (board, BRD_OFFSET (board, elem))
+ read_sx_byte (board, BRD_OFFSET (board, elem))
#define sx_write_board_word(board, elem, val) \
- write_sx_word (board, BRD_OFFSET (board, elem), val)
+ write_sx_word (board, BRD_OFFSET (board, elem), val)
#define sx_read_board_word(board, elem) \
- read_sx_word (board, BRD_OFFSET (board, elem))
+ read_sx_word (board, BRD_OFFSET (board, elem))
-
-static int sx_start_board (struct sx_board *board)
+static int sx_start_board(struct sx_board *board)
{
- if (IS_SX_BOARD (board)) {
- write_sx_byte (board, SX_CONFIG, SX_CONF_BUSEN);
+ if (IS_SX_BOARD(board)) {
+ write_sx_byte(board, SX_CONFIG, SX_CONF_BUSEN);
} else if (IS_EISA_BOARD(board)) {
write_sx_byte(board, SI2_EISA_OFF, SI2_EISA_VAL);
- outb((board->irq<<4)|4, board->eisa_base+0xc02);
+ outb((board->irq << 4) | 4, board->eisa_base + 0xc02);
} else if (IS_SI1_BOARD(board)) {
- write_sx_byte (board, SI1_ISA_RESET_CLEAR, 0);
- write_sx_byte (board, SI1_ISA_INTCL, 0);
+ write_sx_byte(board, SI1_ISA_RESET_CLEAR, 0);
+ write_sx_byte(board, SI1_ISA_INTCL, 0);
} else {
/* Don't bug me about the clear_set.
I haven't the foggiest idea what it's about -- REW */
- write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_CLEAR);
- write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+ write_sx_byte(board, SI2_ISA_RESET, SI2_ISA_RESET_CLEAR);
+ write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
}
return 1;
}
#define SX_IRQ_REG_VAL(board) \
- ((board->flags & SX_ISA_BOARD)?(board->irq << 4):0)
+ ((board->flags & SX_ISA_BOARD) ? (board->irq << 4) : 0)
/* Note. The SX register is write-only. Therefore, we have to enable the
bus too. This is a no-op, if you don't mess with this driver... */
-static int sx_start_interrupts (struct sx_board *board)
+static int sx_start_interrupts(struct sx_board *board)
{
/* Don't call this with board->irq == 0 */
if (IS_SX_BOARD(board)) {
- write_sx_byte (board, SX_CONFIG, SX_IRQ_REG_VAL (board) |
- SX_CONF_BUSEN |
- SX_CONF_HOSTIRQ);
+ write_sx_byte(board, SX_CONFIG, SX_IRQ_REG_VAL(board) |
+ SX_CONF_BUSEN | SX_CONF_HOSTIRQ);
} else if (IS_EISA_BOARD(board)) {
- inb(board->eisa_base+0xc03);
+ inb(board->eisa_base + 0xc03);
} else if (IS_SI1_BOARD(board)) {
- write_sx_byte (board, SI1_ISA_INTCL,0);
- write_sx_byte (board, SI1_ISA_INTCL_CLEAR,0);
+ write_sx_byte(board, SI1_ISA_INTCL, 0);
+ write_sx_byte(board, SI1_ISA_INTCL_CLEAR, 0);
} else {
switch (board->irq) {
- case 11:write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);break;
- case 12:write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_SET);break;
- case 15:write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_SET);break;
- default:printk (KERN_INFO "sx: SI/XIO card doesn't support interrupt %d.\n",
- board->irq);
- return 0;
+ case 11:
+ write_sx_byte(board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);
+ break;
+ case 12:
+ write_sx_byte(board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_SET);
+ break;
+ case 15:
+ write_sx_byte(board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_SET);
+ break;
+ default:
+ printk(KERN_INFO "sx: SI/XIO card doesn't support "
+ "interrupt %d.\n", board->irq);
+ return 0;
}
- write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+ write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
}
return 1;
}
-
-static int sx_send_command (struct sx_port *port,
- int command, int mask, int newstat)
+static int sx_send_command(struct sx_port *port,
+ int command, int mask, int newstat)
{
- func_enter2 ();
- write_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat), command);
- func_exit ();
- return sx_busy_wait_eq (port->board, CHAN_OFFSET (port, hi_hstat), mask, newstat);
+ func_enter2();
+ write_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat), command);
+ func_exit();
+ return sx_busy_wait_eq(port->board, CHAN_OFFSET(port, hi_hstat), mask,
+ newstat);
}
-
-static char *mod_type_s (int module_type)
+static char *mod_type_s(int module_type)
{
switch (module_type) {
- case TA4: return "TA4";
- case TA8: return "TA8";
- case TA4_ASIC: return "TA4_ASIC";
- case TA8_ASIC: return "TA8_ASIC";
- case MTA_CD1400:return "MTA_CD1400";
- case SXDC: return "SXDC";
- default:return "Unknown/invalid";
+ case TA4:
+ return "TA4";
+ case TA8:
+ return "TA8";
+ case TA4_ASIC:
+ return "TA4_ASIC";
+ case TA8_ASIC:
+ return "TA8_ASIC";
+ case MTA_CD1400:
+ return "MTA_CD1400";
+ case SXDC:
+ return "SXDC";
+ default:
+ return "Unknown/invalid";
}
}
-
-static char *pan_type_s (int pan_type)
+static char *pan_type_s(int pan_type)
{
switch (pan_type) {
- case MOD_RS232DB25: return "MOD_RS232DB25";
- case MOD_RS232RJ45: return "MOD_RS232RJ45";
- case MOD_RS422DB25: return "MOD_RS422DB25";
- case MOD_PARALLEL: return "MOD_PARALLEL";
- case MOD_2_RS232DB25: return "MOD_2_RS232DB25";
- case MOD_2_RS232RJ45: return "MOD_2_RS232RJ45";
- case MOD_2_RS422DB25: return "MOD_2_RS422DB25";
- case MOD_RS232DB25MALE: return "MOD_RS232DB25MALE";
- case MOD_2_PARALLEL: return "MOD_2_PARALLEL";
- case MOD_BLANK: return "empty";
- default:return "invalid";
+ case MOD_RS232DB25:
+ return "MOD_RS232DB25";
+ case MOD_RS232RJ45:
+ return "MOD_RS232RJ45";
+ case MOD_RS422DB25:
+ return "MOD_RS422DB25";
+ case MOD_PARALLEL:
+ return "MOD_PARALLEL";
+ case MOD_2_RS232DB25:
+ return "MOD_2_RS232DB25";
+ case MOD_2_RS232RJ45:
+ return "MOD_2_RS232RJ45";
+ case MOD_2_RS422DB25:
+ return "MOD_2_RS422DB25";
+ case MOD_RS232DB25MALE:
+ return "MOD_RS232DB25MALE";
+ case MOD_2_PARALLEL:
+ return "MOD_2_PARALLEL";
+ case MOD_BLANK:
+ return "empty";
+ default:
+ return "invalid";
}
}
-
-static int mod_compat_type (int module_type)
+static int mod_compat_type(int module_type)
{
return module_type >> 4;
}
static void sx_reconfigure_port(struct sx_port *port)
{
- if (sx_read_channel_byte (port, hi_hstat) == HS_IDLE_OPEN) {
- if (sx_send_command (port, HS_CONFIG, -1, HS_IDLE_OPEN) != 1) {
- printk (KERN_WARNING "sx: Sent reconfigure command, but card didn't react.\n");
+ if (sx_read_channel_byte(port, hi_hstat) == HS_IDLE_OPEN) {
+ if (sx_send_command(port, HS_CONFIG, -1, HS_IDLE_OPEN) != 1) {
+ printk(KERN_WARNING "sx: Sent reconfigure command, but "
+ "card didn't react.\n");
}
} else {
- sx_dprintk (SX_DEBUG_TERMIOS,
- "sx: Not sending reconfigure: port isn't open (%02x).\n",
- sx_read_channel_byte (port, hi_hstat));
- }
+ sx_dprintk(SX_DEBUG_TERMIOS, "sx: Not sending reconfigure: "
+ "port isn't open (%02x).\n",
+ sx_read_channel_byte(port, hi_hstat));
+ }
}
-static void sx_setsignals (struct sx_port *port, int dtr, int rts)
+static void sx_setsignals(struct sx_port *port, int dtr, int rts)
{
int t;
- func_enter2 ();
+ func_enter2();
- t = sx_read_channel_byte (port, hi_op);
- if (dtr >= 0) t = dtr? (t | OP_DTR): (t & ~OP_DTR);
- if (rts >= 0) t = rts? (t | OP_RTS): (t & ~OP_RTS);
- sx_write_channel_byte (port, hi_op, t);
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts);
+ t = sx_read_channel_byte(port, hi_op);
+ if (dtr >= 0)
+ t = dtr ? (t | OP_DTR) : (t & ~OP_DTR);
+ if (rts >= 0)
+ t = rts ? (t | OP_RTS) : (t & ~OP_RTS);
+ sx_write_channel_byte(port, hi_op, t);
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts);
- func_exit ();
+ func_exit();
}
-
-
-static int sx_getsignals (struct sx_port *port)
+static int sx_getsignals(struct sx_port *port)
{
- int i_stat,o_stat;
-
- o_stat = sx_read_channel_byte (port, hi_op);
- i_stat = sx_read_channel_byte (port, hi_ip);
-
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d (%d/%d) %02x/%02x\n",
- (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0,
- port->c_dcd, sx_get_CD (port),
- sx_read_channel_byte (port, hi_ip),
- sx_read_channel_byte (port, hi_state));
-
- return (((o_stat & OP_DTR)?TIOCM_DTR:0) |
- ((o_stat & OP_RTS)?TIOCM_RTS:0) |
- ((i_stat & IP_CTS)?TIOCM_CTS:0) |
- ((i_stat & IP_DCD)?TIOCM_CAR:0) |
- ((i_stat & IP_DSR)?TIOCM_DSR:0) |
- ((i_stat & IP_RI)?TIOCM_RNG:0)
- );
+ int i_stat, o_stat;
+
+ o_stat = sx_read_channel_byte(port, hi_op);
+ i_stat = sx_read_channel_byte(port, hi_ip);
+
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d (%d/%d) "
+ "%02x/%02x\n",
+ (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0,
+ port->c_dcd, sx_get_CD(port),
+ sx_read_channel_byte(port, hi_ip),
+ sx_read_channel_byte(port, hi_state));
+
+ return (((o_stat & OP_DTR) ? TIOCM_DTR : 0) |
+ ((o_stat & OP_RTS) ? TIOCM_RTS : 0) |
+ ((i_stat & IP_CTS) ? TIOCM_CTS : 0) |
+ ((i_stat & IP_DCD) ? TIOCM_CAR : 0) |
+ ((i_stat & IP_DSR) ? TIOCM_DSR : 0) |
+ ((i_stat & IP_RI) ? TIOCM_RNG : 0));
}
-
-static void sx_set_baud (struct sx_port *port)
+static void sx_set_baud(struct sx_port *port)
{
int t;
if (port->board->ta_type == MOD_SXDC) {
switch (port->gs.baud) {
- /* Save some typing work... */
-#define e(x) case x:t= BAUD_ ## x ; break
- e(50);e(75);e(110);e(150);e(200);e(300);e(600);
- e(1200);e(1800);e(2000);e(2400);e(4800);e(7200);
- e(9600);e(14400);e(19200);e(28800);e(38400);
- e(56000);e(57600);e(64000);e(76800);e(115200);
- e(128000);e(150000);e(230400);e(256000);e(460800);
- e(921600);
- case 134 :t = BAUD_134_5; break;
- case 0 :t = -1;
- break;
+ /* Save some typing work... */
+#define e(x) case x: t = BAUD_ ## x; break
+ e(50);
+ e(75);
+ e(110);
+ e(150);
+ e(200);
+ e(300);
+ e(600);
+ e(1200);
+ e(1800);
+ e(2000);
+ e(2400);
+ e(4800);
+ e(7200);
+ e(9600);
+ e(14400);
+ e(19200);
+ e(28800);
+ e(38400);
+ e(56000);
+ e(57600);
+ e(64000);
+ e(76800);
+ e(115200);
+ e(128000);
+ e(150000);
+ e(230400);
+ e(256000);
+ e(460800);
+ e(921600);
+ case 134:
+ t = BAUD_134_5;
+ break;
+ case 0:
+ t = -1;
+ break;
default:
/* Can I return "invalid"? */
t = BAUD_9600;
- printk (KERN_INFO "sx: unsupported baud rate: %d.\n", port->gs.baud);
+ printk(KERN_INFO "sx: unsupported baud rate: %d.\n",
+ port->gs.baud);
break;
}
#undef e
if (t > 0) {
- /* The baud rate is not set to 0, so we're enabeling DTR... -- REW */
- sx_setsignals (port, 1, -1);
+/* The baud rate is not set to 0, so we're enabeling DTR... -- REW */
+ sx_setsignals(port, 1, -1);
/* XXX This is not TA & MTA compatible */
- sx_write_channel_byte (port, hi_csr, 0xff);
+ sx_write_channel_byte(port, hi_csr, 0xff);
- sx_write_channel_byte (port, hi_txbaud, t);
- sx_write_channel_byte (port, hi_rxbaud, t);
+ sx_write_channel_byte(port, hi_txbaud, t);
+ sx_write_channel_byte(port, hi_rxbaud, t);
} else {
- sx_setsignals (port, 0, -1);
+ sx_setsignals(port, 0, -1);
}
} else {
switch (port->gs.baud) {
-#define e(x) case x:t= CSR_ ## x ; break
- e(75);e(150);e(300);e(600);e(1200);e(2400);e(4800);
- e(1800);e(9600);
- e(19200);e(57600);e(38400);
- /* TA supports 110, but not 115200, MTA supports 115200, but not 110 */
- case 110:
+#define e(x) case x: t = CSR_ ## x; break
+ e(75);
+ e(150);
+ e(300);
+ e(600);
+ e(1200);
+ e(2400);
+ e(4800);
+ e(1800);
+ e(9600);
+ e(19200);
+ e(57600);
+ e(38400);
+/* TA supports 110, but not 115200, MTA supports 115200, but not 110 */
+ case 110:
if (port->board->ta_type == MOD_TA) {
t = CSR_110;
break;
} else {
t = CSR_9600;
- printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+ printk(KERN_INFO "sx: Unsupported baud rate: "
+ "%d.\n", port->gs.baud);
break;
}
- case 115200:
+ case 115200:
if (port->board->ta_type == MOD_TA) {
t = CSR_9600;
- printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+ printk(KERN_INFO "sx: Unsupported baud rate: "
+ "%d.\n", port->gs.baud);
break;
} else {
t = CSR_110;
break;
}
- case 0 :t = -1;
- break;
+ case 0:
+ t = -1;
+ break;
default:
t = CSR_9600;
- printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+ printk(KERN_INFO "sx: Unsupported baud rate: %d.\n",
+ port->gs.baud);
break;
}
#undef e
if (t >= 0) {
- sx_setsignals (port, 1, -1);
- sx_write_channel_byte (port, hi_csr, t * 0x11);
+ sx_setsignals(port, 1, -1);
+ sx_write_channel_byte(port, hi_csr, t * 0x11);
} else {
- sx_setsignals (port, 0, -1);
+ sx_setsignals(port, 0, -1);
}
}
}
-
/* Simon Allen's version of this routine was 225 lines long. 85 is a lot
better. -- REW */
-static int sx_set_real_termios (void *ptr)
+static int sx_set_real_termios(void *ptr)
{
struct sx_port *port = ptr;
@@ -907,80 +939,83 @@ static int sx_set_real_termios (void *ptr)
belongs (next to the drop dtr if baud == 0) -- REW */
/* sx_setsignals (port, 1, -1); */
- sx_set_baud (port);
+ sx_set_baud(port);
#define CFLAG port->gs.tty->termios->c_cflag
- sx_write_channel_byte (port, hi_mr1,
- (C_PARENB (port->gs.tty)? MR1_WITH:MR1_NONE) |
- (C_PARODD (port->gs.tty)? MR1_ODD:MR1_EVEN) |
- (C_CRTSCTS(port->gs.tty)? MR1_RTS_RXFLOW:0) |
- (((CFLAG & CSIZE)==CS8) ? MR1_8_BITS:0) |
- (((CFLAG & CSIZE)==CS7) ? MR1_7_BITS:0) |
- (((CFLAG & CSIZE)==CS6) ? MR1_6_BITS:0) |
- (((CFLAG & CSIZE)==CS5) ? MR1_5_BITS:0) );
-
- sx_write_channel_byte (port, hi_mr2,
- (C_CRTSCTS(port->gs.tty)?MR2_CTS_TXFLOW:0) |
- (C_CSTOPB (port->gs.tty)?MR2_2_STOP:MR2_1_STOP));
+ sx_write_channel_byte(port, hi_mr1,
+ (C_PARENB(port->gs.tty) ? MR1_WITH : MR1_NONE) |
+ (C_PARODD(port->gs.tty) ? MR1_ODD : MR1_EVEN) |
+ (C_CRTSCTS(port->gs.tty) ? MR1_RTS_RXFLOW : 0) |
+ (((CFLAG & CSIZE) == CS8) ? MR1_8_BITS : 0) |
+ (((CFLAG & CSIZE) == CS7) ? MR1_7_BITS : 0) |
+ (((CFLAG & CSIZE) == CS6) ? MR1_6_BITS : 0) |
+ (((CFLAG & CSIZE) == CS5) ? MR1_5_BITS : 0));
+
+ sx_write_channel_byte(port, hi_mr2,
+ (C_CRTSCTS(port->gs.tty) ? MR2_CTS_TXFLOW : 0) |
+ (C_CSTOPB(port->gs.tty) ? MR2_2_STOP :
+ MR2_1_STOP));
switch (CFLAG & CSIZE) {
- case CS8:sx_write_channel_byte (port, hi_mask, 0xff);break;
- case CS7:sx_write_channel_byte (port, hi_mask, 0x7f);break;
- case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break;
- case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break;
+ case CS8:
+ sx_write_channel_byte(port, hi_mask, 0xff);
+ break;
+ case CS7:
+ sx_write_channel_byte(port, hi_mask, 0x7f);
+ break;
+ case CS6:
+ sx_write_channel_byte(port, hi_mask, 0x3f);
+ break;
+ case CS5:
+ sx_write_channel_byte(port, hi_mask, 0x1f);
+ break;
default:
- printk (KERN_INFO "sx: Invalid wordsize: %u\n", CFLAG & CSIZE);
+ printk(KERN_INFO "sx: Invalid wordsize: %u\n", CFLAG & CSIZE);
break;
}
- sx_write_channel_byte (port, hi_prtcl,
- (I_IXON (port->gs.tty)?SP_TXEN:0) |
- (I_IXOFF (port->gs.tty)?SP_RXEN:0) |
- (I_IXANY (port->gs.tty)?SP_TANY:0) |
- SP_DCEN);
+ sx_write_channel_byte(port, hi_prtcl,
+ (I_IXON(port->gs.tty) ? SP_TXEN : 0) |
+ (I_IXOFF(port->gs.tty) ? SP_RXEN : 0) |
+ (I_IXANY(port->gs.tty) ? SP_TANY : 0) | SP_DCEN);
- sx_write_channel_byte (port, hi_break,
- (I_IGNBRK(port->gs.tty)?BR_IGN:0 |
- I_BRKINT(port->gs.tty)?BR_INT:0));
+ sx_write_channel_byte(port, hi_break,
+ (I_IGNBRK(port->gs.tty) ? BR_IGN : 0 |
+ I_BRKINT(port->gs.tty) ? BR_INT : 0));
- sx_write_channel_byte (port, hi_txon, START_CHAR (port->gs.tty));
- sx_write_channel_byte (port, hi_rxon, START_CHAR (port->gs.tty));
- sx_write_channel_byte (port, hi_txoff, STOP_CHAR (port->gs.tty));
- sx_write_channel_byte (port, hi_rxoff, STOP_CHAR (port->gs.tty));
+ sx_write_channel_byte(port, hi_txon, START_CHAR(port->gs.tty));
+ sx_write_channel_byte(port, hi_rxon, START_CHAR(port->gs.tty));
+ sx_write_channel_byte(port, hi_txoff, STOP_CHAR(port->gs.tty));
+ sx_write_channel_byte(port, hi_rxoff, STOP_CHAR(port->gs.tty));
sx_reconfigure_port(port);
/* Tell line discipline whether we will do input cooking */
- if(I_OTHER(port->gs.tty)) {
+ if (I_OTHER(port->gs.tty)) {
clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
} else {
set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
}
- sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
- port->gs.tty->termios->c_iflag,
- I_OTHER(port->gs.tty));
-
+ sx_dprintk(SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
+ port->gs.tty->termios->c_iflag, I_OTHER(port->gs.tty));
/* Tell line discipline whether we will do output cooking.
* If OPOST is set and no other output flags are set then we can do output
* processing. Even if only *one* other flag in the O_OTHER group is set
* we do cooking in software.
*/
- if(O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) {
+ if (O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) {
set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
} else {
clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
}
- sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
- port->gs.tty->termios->c_oflag,
- O_OTHER(port->gs.tty));
+ sx_dprintk(SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
+ port->gs.tty->termios->c_oflag, O_OTHER(port->gs.tty));
/* port->c_dcd = sx_get_CD (port); */
- func_exit ();
+ func_exit();
return 0;
}
-
-
/* ********************************************************************** *
* the interrupt related routines *
* ********************************************************************** */
@@ -996,245 +1031,260 @@ static int sx_set_real_termios (void *ptr)
know I'm dead against that, but I think it is required in this
case. */
-
-static void sx_transmit_chars (struct sx_port *port)
+static void sx_transmit_chars(struct sx_port *port)
{
int c;
int tx_ip;
int txroom;
- func_enter2 ();
- sx_dprintk (SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n",
- port, port->gs.xmit_cnt);
+ func_enter2();
+ sx_dprintk(SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n",
+ port, port->gs.xmit_cnt);
- if (test_and_set_bit (SX_PORT_TRANSMIT_LOCK, &port->locks)) {
+ if (test_and_set_bit(SX_PORT_TRANSMIT_LOCK, &port->locks)) {
return;
}
while (1) {
c = port->gs.xmit_cnt;
- sx_dprintk (SX_DEBUG_TRANSMIT, "Copying %d ", c);
- tx_ip = sx_read_channel_byte (port, hi_txipos);
+ sx_dprintk(SX_DEBUG_TRANSMIT, "Copying %d ", c);
+ tx_ip = sx_read_channel_byte(port, hi_txipos);
/* Took me 5 minutes to deduce this formula.
Luckily it is literally in the manual in section 6.5.4.3.5 */
- txroom = (sx_read_channel_byte (port, hi_txopos) - tx_ip - 1) & 0xff;
+ txroom = (sx_read_channel_byte(port, hi_txopos) - tx_ip - 1) &
+ 0xff;
/* Don't copy more bytes than there is room for in the buffer */
if (c > txroom)
c = txroom;
- sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom );
+ sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom);
/* Don't copy past the end of the hardware transmit buffer */
- if (c > 0x100 - tx_ip)
+ if (c > 0x100 - tx_ip)
c = 0x100 - tx_ip;
- sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100-tx_ip );
+ sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100 - tx_ip);
/* Don't copy pas the end of the source buffer */
- if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail)
+ if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail)
c = SERIAL_XMIT_SIZE - port->gs.xmit_tail;
- sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%ld) \n",
- c, SERIAL_XMIT_SIZE- port->gs.xmit_tail);
-
- /* If for one reason or another, we can't copy more data, we're done! */
- if (c == 0) break;
+ sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%ld) \n",
+ c, SERIAL_XMIT_SIZE - port->gs.xmit_tail);
+ /* If for one reason or another, we can't copy more data, we're
+ done! */
+ if (c == 0)
+ break;
- memcpy_toio (port->board->base + CHAN_OFFSET(port,hi_txbuf) + tx_ip,
- port->gs.xmit_buf + port->gs.xmit_tail, c);
+ memcpy_toio(port->board->base + CHAN_OFFSET(port, hi_txbuf) +
+ tx_ip, port->gs.xmit_buf + port->gs.xmit_tail, c);
/* Update the pointer in the card */
- sx_write_channel_byte (port, hi_txipos, (tx_ip+c) & 0xff);
+ sx_write_channel_byte(port, hi_txipos, (tx_ip + c) & 0xff);
/* Update the kernel buffer end */
- port->gs.xmit_tail = (port->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE-1);
+ port->gs.xmit_tail = (port->gs.xmit_tail + c) &
+ (SERIAL_XMIT_SIZE - 1);
/* This one last. (this is essential)
- It would allow others to start putting more data into the buffer! */
+ It would allow others to start putting more data into the
+ buffer! */
port->gs.xmit_cnt -= c;
}
if (port->gs.xmit_cnt == 0) {
- sx_disable_tx_interrupts (port);
+ sx_disable_tx_interrupts(port);
}
if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) {
tty_wakeup(port->gs.tty);
- sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
- port->gs.wakeup_chars);
+ sx_dprintk(SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
+ port->gs.wakeup_chars);
}
- clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks);
- func_exit ();
+ clear_bit(SX_PORT_TRANSMIT_LOCK, &port->locks);
+ func_exit();
}
-
/* Note the symmetry between receiving chars and transmitting them!
Note: The kernel should have implemented both a receive buffer and
a transmit buffer. */
/* Inlined: Called only once. Remove the inline when you add another call */
-static inline void sx_receive_chars (struct sx_port *port)
+static inline void sx_receive_chars(struct sx_port *port)
{
int c;
int rx_op;
struct tty_struct *tty;
- int copied=0;
+ int copied = 0;
unsigned char *rp;
- func_enter2 ();
+ func_enter2();
tty = port->gs.tty;
while (1) {
- rx_op = sx_read_channel_byte (port, hi_rxopos);
- c = (sx_read_channel_byte (port, hi_rxipos) - rx_op) & 0xff;
+ rx_op = sx_read_channel_byte(port, hi_rxopos);
+ c = (sx_read_channel_byte(port, hi_rxipos) - rx_op) & 0xff;
- sx_dprintk (SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c);
+ sx_dprintk(SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c);
/* Don't copy past the end of the hardware receive buffer */
- if (rx_op + c > 0x100) c = 0x100 - rx_op;
+ if (rx_op + c > 0x100)
+ c = 0x100 - rx_op;
- sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);
+ sx_dprintk(SX_DEBUG_RECEIVE, "c = %d.\n", c);
/* Don't copy more bytes than there is room for in the buffer */
c = tty_prepare_flip_string(tty, &rp, c);
- sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);
+ sx_dprintk(SX_DEBUG_RECEIVE, "c = %d.\n", c);
/* If for one reason or another, we can't copy more data, we're done! */
- if (c == 0) break;
+ if (c == 0)
+ break;
- sx_dprintk (SX_DEBUG_RECEIVE , "Copying over %d chars. First is %d at %lx\n", c,
- read_sx_byte (port->board, CHAN_OFFSET(port,hi_rxbuf) + rx_op),
- CHAN_OFFSET(port, hi_rxbuf));
- memcpy_fromio (rp,
- port->board->base + CHAN_OFFSET(port,hi_rxbuf) + rx_op, c);
+ sx_dprintk(SX_DEBUG_RECEIVE, "Copying over %d chars. First is "
+ "%d at %lx\n", c, read_sx_byte(port->board,
+ CHAN_OFFSET(port, hi_rxbuf) + rx_op),
+ CHAN_OFFSET(port, hi_rxbuf));
+ memcpy_fromio(rp, port->board->base +
+ CHAN_OFFSET(port, hi_rxbuf) + rx_op, c);
/* This one last. ( Not essential.)
- It allows the card to start putting more data into the buffer!
+ It allows the card to start putting more data into the
+ buffer!
Update the pointer in the card */
- sx_write_channel_byte (port, hi_rxopos, (rx_op + c) & 0xff);
+ sx_write_channel_byte(port, hi_rxopos, (rx_op + c) & 0xff);
copied += c;
}
if (copied) {
struct timeval tv;
- do_gettimeofday (&tv);
- sx_dprintk (SX_DEBUG_RECEIVE,
- "pushing flipq port %d (%3d chars): %d.%06d (%d/%d)\n",
- port->line, copied,
- (int) (tv.tv_sec % 60), (int)tv.tv_usec, tty->raw, tty->real_raw);
+ do_gettimeofday(&tv);
+ sx_dprintk(SX_DEBUG_RECEIVE, "pushing flipq port %d (%3d "
+ "chars): %d.%06d (%d/%d)\n", port->line,
+ copied, (int)(tv.tv_sec % 60), (int)tv.tv_usec,
+ tty->raw, tty->real_raw);
- /* Tell the rest of the system the news. Great news. New characters! */
- tty_flip_buffer_push (tty);
+ /* Tell the rest of the system the news. Great news. New
+ characters! */
+ tty_flip_buffer_push(tty);
/* tty_schedule_flip (tty); */
}
- func_exit ();
+ func_exit();
}
/* Inlined: it is called only once. Remove the inline if you add another
call */
-static inline void sx_check_modem_signals (struct sx_port *port)
+static inline void sx_check_modem_signals(struct sx_port *port)
{
int hi_state;
int c_dcd;
- hi_state = sx_read_channel_byte (port, hi_state);
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n",
- port->c_dcd, sx_get_CD (port));
+ hi_state = sx_read_channel_byte(port, hi_state);
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n",
+ port->c_dcd, sx_get_CD(port));
if (hi_state & ST_BREAK) {
hi_state &= ~ST_BREAK;
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n");
- sx_write_channel_byte (port, hi_state, hi_state);
- gs_got_break (&port->gs);
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "got a break.\n");
+ sx_write_channel_byte(port, hi_state, hi_state);
+ gs_got_break(&port->gs);
}
if (hi_state & ST_DCD) {
hi_state &= ~ST_DCD;
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n");
- sx_write_channel_byte (port, hi_state, hi_state);
- c_dcd = sx_get_CD (port);
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd);
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n");
+ sx_write_channel_byte(port, hi_state, hi_state);
+ c_dcd = sx_get_CD(port);
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd);
if (c_dcd != port->c_dcd) {
port->c_dcd = c_dcd;
- if (sx_get_CD (port)) {
+ if (sx_get_CD(port)) {
/* DCD went UP */
- if ((sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) &&
- !(port->gs.tty->termios->c_cflag & CLOCAL) ) {
- /* Are we blocking in open?*/
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD active, unblocking open\n");
- wake_up_interruptible(&port->gs.open_wait);
+ if ((sx_read_channel_byte(port, hi_hstat) !=
+ HS_IDLE_CLOSED) &&
+ !(port->gs.tty->termios->
+ c_cflag & CLOCAL)) {
+ /* Are we blocking in open? */
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+ "active, unblocking open\n");
+ wake_up_interruptible(&port->gs.
+ open_wait);
} else {
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD raised. Ignoring.\n");
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+ "raised. Ignoring.\n");
}
} else {
/* DCD went down! */
- if (!(port->gs.tty->termios->c_cflag & CLOCAL) ) {
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. hanging up....\n");
- tty_hangup (port->gs.tty);
+ if (!(port->gs.tty->termios->c_cflag & CLOCAL)){
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+ "dropped. hanging up....\n");
+ tty_hangup(port->gs.tty);
} else {
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. ignoring.\n");
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+ "dropped. ignoring.\n");
}
}
} else {
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us DCD changed, but it didn't.\n");
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us "
+ "DCD changed, but it didn't.\n");
}
}
}
-
/* This is what an interrupt routine should look like.
* Small, elegant, clear.
*/
-static irqreturn_t sx_interrupt (int irq, void *ptr)
+static irqreturn_t sx_interrupt(int irq, void *ptr)
{
struct sx_board *board = ptr;
struct sx_port *port;
int i;
- func_enter ();
- sx_dprintk (SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq, board->irq);
+ func_enter();
+ sx_dprintk(SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq,
+ board->irq);
/* AAargh! The order in which to do these things is essential and
not trivial.
- Rate limit goes before "recursive". Otherwise a series of
- recursive calls will hang the machine in the interrupt routine.
+ recursive calls will hang the machine in the interrupt routine.
- hardware twiddling goes before "recursive". Otherwise when we
- poll the card, and a recursive interrupt happens, we won't
- ack the card, so it might keep on interrupting us. (especially
- level sensitive interrupt systems like PCI).
+ poll the card, and a recursive interrupt happens, we won't
+ ack the card, so it might keep on interrupting us. (especially
+ level sensitive interrupt systems like PCI).
- Rate limit goes before hardware twiddling. Otherwise we won't
- catch a card that has gone bonkers.
+ catch a card that has gone bonkers.
- The "initialized" test goes after the hardware twiddling. Otherwise
- the card will stick us in the interrupt routine again.
+ the card will stick us in the interrupt routine again.
- The initialized test goes before recursive.
- */
-
-
+ */
#ifdef IRQ_RATE_LIMIT
/* Aaargh! I'm ashamed. This costs more lines-of-code than the
- actual interrupt routine!. (Well, used to when I wrote that comment) */
+ actual interrupt routine!. (Well, used to when I wrote that
+ comment) */
{
static int lastjif;
- static int nintr=0;
+ static int nintr = 0;
if (lastjif == jiffies) {
if (++nintr > IRQ_RATE_LIMIT) {
- free_irq (board->irq, board);
- printk (KERN_ERR "sx: Too many interrupts. Turning off interrupt %d.\n",
- board->irq);
+ free_irq(board->irq, board);
+ printk(KERN_ERR "sx: Too many interrupts. "
+ "Turning off interrupt %d.\n",
+ board->irq);
}
} else {
lastjif = jiffies;
@@ -1243,19 +1293,20 @@ static irqreturn_t sx_interrupt (int irq, void *ptr)
}
#endif
-
if (board->irq == irq) {
/* Tell the card we've noticed the interrupt. */
- sx_write_board_word (board, cc_int_pending, 0);
- if (IS_SX_BOARD (board)) {
- write_sx_byte (board, SX_RESET_IRQ, 1);
+ sx_write_board_word(board, cc_int_pending, 0);
+ if (IS_SX_BOARD(board)) {
+ write_sx_byte(board, SX_RESET_IRQ, 1);
} else if (IS_EISA_BOARD(board)) {
- inb(board->eisa_base+0xc03);
- write_sx_word(board, 8, 0);
+ inb(board->eisa_base + 0xc03);
+ write_sx_word(board, 8, 0);
} else {
- write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
- write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+ write_sx_byte(board, SI2_ISA_INTCLEAR,
+ SI2_ISA_INTCLEAR_CLEAR);
+ write_sx_byte(board, SI2_ISA_INTCLEAR,
+ SI2_ISA_INTCLEAR_SET);
}
}
@@ -1264,53 +1315,48 @@ static irqreturn_t sx_interrupt (int irq, void *ptr)
if (!(board->flags & SX_BOARD_INITIALIZED))
return IRQ_HANDLED;
- if (test_and_set_bit (SX_BOARD_INTR_LOCK, &board->locks)) {
- printk (KERN_ERR "Recursive interrupt! (%d)\n", board->irq);
+ if (test_and_set_bit(SX_BOARD_INTR_LOCK, &board->locks)) {
+ printk(KERN_ERR "Recursive interrupt! (%d)\n", board->irq);
return IRQ_HANDLED;
}
- for (i=0;i<board->nports;i++) {
+ for (i = 0; i < board->nports; i++) {
port = &board->ports[i];
if (port->gs.flags & GS_ACTIVE) {
- if (sx_read_channel_byte (port, hi_state)) {
- sx_dprintk (SX_DEBUG_INTERRUPTS,
- "Port %d: modem signal change?... \n", i);
- sx_check_modem_signals (port);
+ if (sx_read_channel_byte(port, hi_state)) {
+ sx_dprintk(SX_DEBUG_INTERRUPTS, "Port %d: "
+ "modem signal change?... \n",i);
+ sx_check_modem_signals(port);
}
if (port->gs.xmit_cnt) {
- sx_transmit_chars (port);
+ sx_transmit_chars(port);
}
if (!(port->gs.flags & SX_RX_THROTTLE)) {
- sx_receive_chars (port);
+ sx_receive_chars(port);
}
}
}
- clear_bit (SX_BOARD_INTR_LOCK, &board->locks);
+ clear_bit(SX_BOARD_INTR_LOCK, &board->locks);
- sx_dprintk (SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq, board->irq);
- func_exit ();
+ sx_dprintk(SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq,
+ board->irq);
+ func_exit();
return IRQ_HANDLED;
}
-
-static void sx_pollfunc (unsigned long data)
+static void sx_pollfunc(unsigned long data)
{
- struct sx_board *board = (struct sx_board *) data;
-
- func_enter ();
+ struct sx_board *board = (struct sx_board *)data;
- sx_interrupt (0, board);
+ func_enter();
- init_timer(&board->timer);
+ sx_interrupt(0, board);
- board->timer.expires = jiffies + sx_poll;
- add_timer (&board->timer);
- func_exit ();
+ mod_timer(&board->timer, jiffies + sx_poll);
+ func_exit();
}
-
-
/* ********************************************************************** *
* Here are the routines that actually *
* interface with the generic_serial driver *
@@ -1319,9 +1365,9 @@ static void sx_pollfunc (unsigned long data)
/* Ehhm. I don't know how to fiddle with interrupts on the SX card. --REW */
/* Hmm. Ok I figured it out. You don't. */
-static void sx_disable_tx_interrupts (void * ptr)
+static void sx_disable_tx_interrupts(void *ptr)
{
- struct sx_port *port = ptr;
+ struct sx_port *port = ptr;
func_enter2();
port->gs.flags &= ~GS_TX_INTEN;
@@ -1329,30 +1375,28 @@ static void sx_disable_tx_interrupts (void * ptr)
func_exit();
}
-
-static void sx_enable_tx_interrupts (void * ptr)
+static void sx_enable_tx_interrupts(void *ptr)
{
- struct sx_port *port = ptr;
+ struct sx_port *port = ptr;
int data_in_buffer;
func_enter2();
/* First transmit the characters that we're supposed to */
- sx_transmit_chars (port);
+ sx_transmit_chars(port);
/* The sx card will never interrupt us if we don't fill the buffer
past 25%. So we keep considering interrupts off if that's the case. */
- data_in_buffer = (sx_read_channel_byte (port, hi_txipos) -
- sx_read_channel_byte (port, hi_txopos)) & 0xff;
+ data_in_buffer = (sx_read_channel_byte(port, hi_txipos) -
+ sx_read_channel_byte(port, hi_txopos)) & 0xff;
/* XXX Must be "HIGH_WATER" for SI card according to doc. */
- if (data_in_buffer < LOW_WATER)
+ if (data_in_buffer < LOW_WATER)
port->gs.flags &= ~GS_TX_INTEN;
func_exit();
}
-
-static void sx_disable_rx_interrupts (void * ptr)
+static void sx_disable_rx_interrupts(void *ptr)
{
/* struct sx_port *port = ptr; */
func_enter();
@@ -1360,7 +1404,7 @@ static void sx_disable_rx_interrupts (void * ptr)
func_exit();
}
-static void sx_enable_rx_interrupts (void * ptr)
+static void sx_enable_rx_interrupts(void *ptr)
{
/* struct sx_port *port = ptr; */
func_enter();
@@ -1368,55 +1412,48 @@ static void sx_enable_rx_interrupts (void * ptr)
func_exit();
}
-
/* Jeez. Isn't this simple? */
-static int sx_get_CD (void * ptr)
+static int sx_get_CD(void *ptr)
{
struct sx_port *port = ptr;
func_enter2();
func_exit();
- return ((sx_read_channel_byte (port, hi_ip) & IP_DCD) != 0);
+ return ((sx_read_channel_byte(port, hi_ip) & IP_DCD) != 0);
}
-
/* Jeez. Isn't this simple? */
-static int sx_chars_in_buffer (void * ptr)
+static int sx_chars_in_buffer(void *ptr)
{
struct sx_port *port = ptr;
func_enter2();
func_exit();
- return ((sx_read_channel_byte (port, hi_txipos) -
- sx_read_channel_byte (port, hi_txopos)) & 0xff);
+ return ((sx_read_channel_byte(port, hi_txipos) -
+ sx_read_channel_byte(port, hi_txopos)) & 0xff);
}
-
-static void sx_shutdown_port (void * ptr)
+static void sx_shutdown_port(void *ptr)
{
- struct sx_port *port = ptr;
+ struct sx_port *port = ptr;
func_enter();
- port->gs.flags &= ~ GS_ACTIVE;
+ port->gs.flags &= ~GS_ACTIVE;
if (port->gs.tty && (port->gs.tty->termios->c_cflag & HUPCL)) {
- sx_setsignals (port, 0, 0);
+ sx_setsignals(port, 0, 0);
sx_reconfigure_port(port);
}
func_exit();
}
-
-
-
-
/* ********************************************************************** *
* Here are the routines that actually *
* interface with the rest of the system *
* ********************************************************************** */
-static int sx_open (struct tty_struct * tty, struct file * filp)
+static int sx_open(struct tty_struct *tty, struct file *filp)
{
struct sx_port *port;
int retval, line;
@@ -1429,18 +1466,18 @@ static int sx_open (struct tty_struct * tty, struct file * filp)
}
line = tty->index;
- sx_dprintk (SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, np=%d)\n",
- current->pid, line, tty, current->signal->tty, sx_nports);
+ sx_dprintk(SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, "
+ "np=%d)\n", current->pid, line, tty,
+ current->signal->tty, sx_nports);
if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports))
return -ENODEV;
- port = & sx_ports[line];
+ port = &sx_ports[line];
port->c_dcd = 0; /* Make sure that the first interrupt doesn't detect a
- 1 -> 0 transition. */
+ 1 -> 0 transition. */
-
- sx_dprintk (SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd);
+ sx_dprintk(SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd);
spin_lock_irqsave(&port->gs.driver_lock, flags);
@@ -1449,13 +1486,13 @@ static int sx_open (struct tty_struct * tty, struct file * filp)
port->gs.count++;
spin_unlock_irqrestore(&port->gs.driver_lock, flags);
- sx_dprintk (SX_DEBUG_OPEN, "starting port\n");
+ sx_dprintk(SX_DEBUG_OPEN, "starting port\n");
/*
* Start up serial port
*/
retval = gs_init_port(&port->gs);
- sx_dprintk (SX_DEBUG_OPEN, "done gs_init\n");
+ sx_dprintk(SX_DEBUG_OPEN, "done gs_init\n");
if (retval) {
port->gs.count--;
return retval;
@@ -1463,19 +1500,20 @@ static int sx_open (struct tty_struct * tty, struct file * filp)
port->gs.flags |= GS_ACTIVE;
if (port->gs.count <= 1)
- sx_setsignals (port, 1,1);
+ sx_setsignals(port, 1, 1);
#if 0
if (sx_debug & SX_DEBUG_OPEN)
- my_hd (port, sizeof (*port));
+ my_hd(port, sizeof(*port));
#else
if (sx_debug & SX_DEBUG_OPEN)
- my_hd_io (port->board->base + port->ch_base, sizeof (*port));
+ my_hd_io(port->board->base + port->ch_base, sizeof(*port));
#endif
if (port->gs.count <= 1) {
- if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
- printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n");
+ if (sx_send_command(port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
+ printk(KERN_ERR "sx: Card didn't respond to LOPEN "
+ "command.\n");
spin_lock_irqsave(&port->gs.driver_lock, flags);
port->gs.count--;
spin_unlock_irqrestore(&port->gs.driver_lock, flags);
@@ -1484,75 +1522,76 @@ static int sx_open (struct tty_struct * tty, struct file * filp)
}
retval = gs_block_til_ready(port, filp);
- sx_dprintk (SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n",
- retval, port->gs.count);
+ sx_dprintk(SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n",
+ retval, port->gs.count);
if (retval) {
- /*
- * Don't lower gs.count here because sx_close() will be called later
- */
+/*
+ * Don't lower gs.count here because sx_close() will be called later
+ */
return retval;
}
/* tty->low_latency = 1; */
- port->c_dcd = sx_get_CD (port);
- sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
+ port->c_dcd = sx_get_CD(port);
+ sx_dprintk(SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
func_exit();
return 0;
}
-
-static void sx_close (void *ptr)
+static void sx_close(void *ptr)
{
- struct sx_port *port = ptr;
+ struct sx_port *port = ptr;
/* Give the port 5 seconds to close down. */
- int to = 5 * HZ;
+ int to = 5 * HZ;
- func_enter ();
+ func_enter();
- sx_setsignals (port, 0, 0);
- sx_reconfigure_port(port);
- sx_send_command (port, HS_CLOSE, 0, 0);
+ sx_setsignals(port, 0, 0);
+ sx_reconfigure_port(port);
+ sx_send_command(port, HS_CLOSE, 0, 0);
- while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED))
+ while (to-- && (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED))
if (msleep_interruptible(10))
break;
- if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) {
- if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) {
- printk (KERN_ERR
- "sx: sent the force_close command, but card didn't react\n");
+ if (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) {
+ if (sx_send_command(port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED)
+ != 1) {
+ printk(KERN_ERR "sx: sent the force_close command, but "
+ "card didn't react\n");
} else
- sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n");
+ sx_dprintk(SX_DEBUG_CLOSE, "sent the force_close "
+ "command.\n");
}
- sx_dprintk (SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n",
- 5 * HZ - to - 1, port->gs.count);
+ sx_dprintk(SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n",
+ 5 * HZ - to - 1, port->gs.count);
- if(port->gs.count) {
- sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n", port->gs.count);
- //printk ("%s SETTING port count to zero: %p count: %d\n", __FUNCTION__, port, port->gs.count);
- //port->gs.count = 0;
+ if (port->gs.count) {
+ sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n",
+ port->gs.count);
+ /*printk("%s SETTING port count to zero: %p count: %d\n",
+ __FUNCTION__, port, port->gs.count);
+ port->gs.count = 0;*/
}
- func_exit ();
+ func_exit();
}
-
-
/* This is relatively thorough. But then again it is only 20 lines. */
-#define MARCHUP for (i=min;i<max;i++)
-#define MARCHDOWN for (i=max-1;i>=min;i--)
-#define W0 write_sx_byte (board, i, 0x55)
-#define W1 write_sx_byte (board, i, 0xaa)
-#define R0 if (read_sx_byte (board, i) != 0x55) return 1
-#define R1 if (read_sx_byte (board, i) != 0xaa) return 1
+#define MARCHUP for (i = min; i < max; i++)
+#define MARCHDOWN for (i = max - 1; i >= min; i--)
+#define W0 write_sx_byte(board, i, 0x55)
+#define W1 write_sx_byte(board, i, 0xaa)
+#define R0 if (read_sx_byte(board, i) != 0x55) return 1
+#define R1 if (read_sx_byte(board, i) != 0xaa) return 1
/* This memtest takes a human-noticable time. You normally only do it
once a boot, so I guess that it is worth it. */
-static int do_memtest (struct sx_board *board, int min, int max)
+static int do_memtest(struct sx_board *board, int min, int max)
{
int i;
@@ -1561,16 +1600,37 @@ static int do_memtest (struct sx_board *board, int min, int max)
intermittent errors. -- REW
(For the theory behind memory testing see:
Testing Semiconductor Memories by A.J. van de Goor.) */
- MARCHUP {W0;}
- MARCHUP {R0;W1;R1;W0;R0;W1;}
- MARCHUP {R1;W0;W1;}
- MARCHDOWN {R1;W0;W1;W0;}
- MARCHDOWN {R0;W1;W0;}
+ MARCHUP {
+ W0;
+ }
+ MARCHUP {
+ R0;
+ W1;
+ R1;
+ W0;
+ R0;
+ W1;
+ }
+ MARCHUP {
+ R1;
+ W0;
+ W1;
+ }
+ MARCHDOWN {
+ R1;
+ W0;
+ W1;
+ W0;
+ }
+ MARCHDOWN {
+ R0;
+ W1;
+ W0;
+ }
return 0;
}
-
#undef MARCHUP
#undef MARCHDOWN
#undef W0
@@ -1578,33 +1638,54 @@ static int do_memtest (struct sx_board *board, int min, int max)
#undef R0
#undef R1
-#define MARCHUP for (i=min;i<max;i+=2)
-#define MARCHDOWN for (i=max-1;i>=min;i-=2)
-#define W0 write_sx_word (board, i, 0x55aa)
-#define W1 write_sx_word (board, i, 0xaa55)
-#define R0 if (read_sx_word (board, i) != 0x55aa) return 1
-#define R1 if (read_sx_word (board, i) != 0xaa55) return 1
+#define MARCHUP for (i = min; i < max; i += 2)
+#define MARCHDOWN for (i = max - 1; i >= min; i -= 2)
+#define W0 write_sx_word(board, i, 0x55aa)
+#define W1 write_sx_word(board, i, 0xaa55)
+#define R0 if (read_sx_word(board, i) != 0x55aa) return 1
+#define R1 if (read_sx_word(board, i) != 0xaa55) return 1
#if 0
/* This memtest takes a human-noticable time. You normally only do it
once a boot, so I guess that it is worth it. */
-static int do_memtest_w (struct sx_board *board, int min, int max)
+static int do_memtest_w(struct sx_board *board, int min, int max)
{
int i;
- MARCHUP {W0;}
- MARCHUP {R0;W1;R1;W0;R0;W1;}
- MARCHUP {R1;W0;W1;}
- MARCHDOWN {R1;W0;W1;W0;}
- MARCHDOWN {R0;W1;W0;}
+ MARCHUP {
+ W0;
+ }
+ MARCHUP {
+ R0;
+ W1;
+ R1;
+ W0;
+ R0;
+ W1;
+ }
+ MARCHUP {
+ R1;
+ W0;
+ W1;
+ }
+ MARCHDOWN {
+ R1;
+ W0;
+ W1;
+ W0;
+ }
+ MARCHDOWN {
+ R0;
+ W1;
+ W0;
+ }
return 0;
}
#endif
-
-static int sx_fw_ioctl (struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int sx_fw_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
int rc = 0;
int __user *descr = (int __user *)arg;
@@ -1616,7 +1697,7 @@ static int sx_fw_ioctl (struct inode *inode, struct file *filp,
func_enter();
-#if 0
+#if 0
/* Removed superuser check: Sysops can use the permissions on the device
file to restrict access. Recommendation: Root only. (root.root 600) */
if (!capable(CAP_SYS_ADMIN)) {
@@ -1624,103 +1705,115 @@ static int sx_fw_ioctl (struct inode *inode, struct file *filp,
}
#endif
- sx_dprintk (SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg);
+ sx_dprintk(SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg);
- if (!board) board = &boards[0];
+ if (!board)
+ board = &boards[0];
if (board->flags & SX_BOARD_PRESENT) {
- sx_dprintk (SX_DEBUG_FIRMWARE, "Board present! (%x)\n",
- board->flags);
+ sx_dprintk(SX_DEBUG_FIRMWARE, "Board present! (%x)\n",
+ board->flags);
} else {
- sx_dprintk (SX_DEBUG_FIRMWARE, "Board not present! (%x) all:",
- board->flags);
- for (i=0;i< SX_NBOARDS;i++)
- sx_dprintk (SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags);
- sx_dprintk (SX_DEBUG_FIRMWARE, "\n");
+ sx_dprintk(SX_DEBUG_FIRMWARE, "Board not present! (%x) all:",
+ board->flags);
+ for (i = 0; i < SX_NBOARDS; i++)
+ sx_dprintk(SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags);
+ sx_dprintk(SX_DEBUG_FIRMWARE, "\n");
return -EIO;
}
switch (cmd) {
case SXIO_SET_BOARD:
- sx_dprintk (SX_DEBUG_FIRMWARE, "set board to %ld\n", arg);
- if (arg >= SX_NBOARDS) return -EIO;
- sx_dprintk (SX_DEBUG_FIRMWARE, "not out of range\n");
- if (!(boards[arg].flags & SX_BOARD_PRESENT)) return -EIO;
- sx_dprintk (SX_DEBUG_FIRMWARE, ".. and present!\n");
+ sx_dprintk(SX_DEBUG_FIRMWARE, "set board to %ld\n", arg);
+ if (arg >= SX_NBOARDS)
+ return -EIO;
+ sx_dprintk(SX_DEBUG_FIRMWARE, "not out of range\n");
+ if (!(boards[arg].flags & SX_BOARD_PRESENT))
+ return -EIO;
+ sx_dprintk(SX_DEBUG_FIRMWARE, ".. and present!\n");
board = &boards[arg];
break;
case SXIO_GET_TYPE:
- rc = -ENOENT; /* If we manage to miss one, return error. */
- if (IS_SX_BOARD (board)) rc = SX_TYPE_SX;
- if (IS_CF_BOARD (board)) rc = SX_TYPE_CF;
- if (IS_SI_BOARD (board)) rc = SX_TYPE_SI;
- if (IS_SI1_BOARD (board)) rc = SX_TYPE_SI;
- if (IS_EISA_BOARD (board)) rc = SX_TYPE_SI;
- sx_dprintk (SX_DEBUG_FIRMWARE, "returning type= %d\n", rc);
+ rc = -ENOENT; /* If we manage to miss one, return error. */
+ if (IS_SX_BOARD(board))
+ rc = SX_TYPE_SX;
+ if (IS_CF_BOARD(board))
+ rc = SX_TYPE_CF;
+ if (IS_SI_BOARD(board))
+ rc = SX_TYPE_SI;
+ if (IS_SI1_BOARD(board))
+ rc = SX_TYPE_SI;
+ if (IS_EISA_BOARD(board))
+ rc = SX_TYPE_SI;
+ sx_dprintk(SX_DEBUG_FIRMWARE, "returning type= %d\n", rc);
break;
case SXIO_DO_RAMTEST:
- if (sx_initialized) /* Already initialized: better not ramtest the board. */
+ if (sx_initialized) /* Already initialized: better not ramtest the board. */
return -EPERM;
- if (IS_SX_BOARD (board)) {
- rc = do_memtest (board, 0, 0x7000);
- if (!rc) rc = do_memtest (board, 0, 0x7000);
- /*if (!rc) rc = do_memtest_w (board, 0, 0x7000);*/
+ if (IS_SX_BOARD(board)) {
+ rc = do_memtest(board, 0, 0x7000);
+ if (!rc)
+ rc = do_memtest(board, 0, 0x7000);
+ /*if (!rc) rc = do_memtest_w (board, 0, 0x7000); */
} else {
- rc = do_memtest (board, 0, 0x7ff8);
+ rc = do_memtest(board, 0, 0x7ff8);
/* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */
}
- sx_dprintk (SX_DEBUG_FIRMWARE, "returning memtest result= %d\n", rc);
+ sx_dprintk(SX_DEBUG_FIRMWARE, "returning memtest result= %d\n",
+ rc);
break;
case SXIO_DOWNLOAD:
- if (sx_initialized) /* Already initialized */
+ if (sx_initialized) /* Already initialized */
return -EEXIST;
- if (!sx_reset (board))
+ if (!sx_reset(board))
return -EIO;
- sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
-
- tmp = kmalloc (SX_CHUNK_SIZE, GFP_USER);
- if (!tmp) return -ENOMEM;
- get_user (nbytes, descr++);
- get_user (offset, descr++);
- get_user (data, descr++);
+ sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
+
+ tmp = kmalloc(SX_CHUNK_SIZE, GFP_USER);
+ if (!tmp)
+ return -ENOMEM;
+ get_user(nbytes, descr++);
+ get_user(offset, descr++);
+ get_user(data, descr++);
while (nbytes && data) {
- for (i=0;i<nbytes;i += SX_CHUNK_SIZE) {
- if (copy_from_user(tmp, (char __user *)data+i,
- (i + SX_CHUNK_SIZE >
- nbytes) ? nbytes - i :
- SX_CHUNK_SIZE)) {
- kfree (tmp);
+ for (i = 0; i < nbytes; i += SX_CHUNK_SIZE) {
+ if (copy_from_user(tmp, (char __user *)data + i,
+ (i + SX_CHUNK_SIZE > nbytes) ?
+ nbytes - i : SX_CHUNK_SIZE)) {
+ kfree(tmp);
return -EFAULT;
}
- memcpy_toio(board->base2 + offset + i, tmp,
- (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE);
+ memcpy_toio(board->base2 + offset + i, tmp,
+ (i + SX_CHUNK_SIZE > nbytes) ?
+ nbytes - i : SX_CHUNK_SIZE);
}
- get_user (nbytes, descr++);
- get_user (offset, descr++);
- get_user (data, descr++);
+ get_user(nbytes, descr++);
+ get_user(offset, descr++);
+ get_user(data, descr++);
}
- kfree (tmp);
- sx_nports += sx_init_board (board);
+ kfree(tmp);
+ sx_nports += sx_init_board(board);
rc = sx_nports;
break;
case SXIO_INIT:
- if (sx_initialized) /* Already initialized */
+ if (sx_initialized) /* Already initialized */
return -EEXIST;
/* This is not allowed until all boards are initialized... */
- for (i=0;i<SX_NBOARDS;i++) {
- if ( (boards[i].flags & SX_BOARD_PRESENT) &&
- !(boards[i].flags & SX_BOARD_INITIALIZED))
+ for (i = 0; i < SX_NBOARDS; i++) {
+ if ((boards[i].flags & SX_BOARD_PRESENT) &&
+ !(boards[i].flags & SX_BOARD_INITIALIZED))
return -EIO;
}
- for (i=0;i<SX_NBOARDS;i++)
- if (!(boards[i].flags & SX_BOARD_PRESENT)) break;
-
- sx_dprintk (SX_DEBUG_FIRMWARE, "initing portstructs, %d boards, "
- "%d channels, first board: %d ports\n",
- i, sx_nports, boards[0].nports);
- rc = sx_init_portstructs (i, sx_nports);
- sx_init_drivers ();
- if (rc >= 0)
+ for (i = 0; i < SX_NBOARDS; i++)
+ if (!(boards[i].flags & SX_BOARD_PRESENT))
+ break;
+
+ sx_dprintk(SX_DEBUG_FIRMWARE, "initing portstructs, %d boards, "
+ "%d channels, first board: %d ports\n",
+ i, sx_nports, boards[0].nports);
+ rc = sx_init_portstructs(i, sx_nports);
+ sx_init_drivers();
+ if (rc >= 0)
sx_initialized++;
break;
case SXIO_SETDEBUG:
@@ -1737,32 +1830,32 @@ static int sx_fw_ioctl (struct inode *inode, struct file *filp,
rc = sx_nports;
break;
default:
- printk (KERN_WARNING "Unknown ioctl on firmware device (%x).\n", cmd);
+ printk(KERN_WARNING "Unknown ioctl on firmware device (%x).\n",
+ cmd);
break;
}
- func_exit ();
+ func_exit();
return rc;
}
-
-static void sx_break (struct tty_struct * tty, int flag)
+static void sx_break(struct tty_struct *tty, int flag)
{
struct sx_port *port = tty->driver_data;
int rv;
- func_enter ();
+ func_enter();
- if (flag)
- rv = sx_send_command (port, HS_START, -1, HS_IDLE_BREAK);
- else
- rv = sx_send_command (port, HS_STOP, -1, HS_IDLE_OPEN);
- if (rv != 1) printk (KERN_ERR "sx: couldn't send break (%x).\n",
- read_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat)));
+ if (flag)
+ rv = sx_send_command(port, HS_START, -1, HS_IDLE_BREAK);
+ else
+ rv = sx_send_command(port, HS_STOP, -1, HS_IDLE_OPEN);
+ if (rv != 1)
+ printk(KERN_ERR "sx: couldn't send break (%x).\n",
+ read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat)));
- func_exit ();
+ func_exit();
}
-
static int sx_tiocmget(struct tty_struct *tty, struct file *file)
{
struct sx_port *port = tty->driver_data;
@@ -1770,7 +1863,7 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file)
}
static int sx_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
+ unsigned int set, unsigned int clear)
{
struct sx_port *port = tty->driver_data;
int rts = -1, dtr = -1;
@@ -1789,8 +1882,8 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file,
return 0;
}
-static int sx_ioctl (struct tty_struct * tty, struct file * filp,
- unsigned int cmd, unsigned long arg)
+static int sx_ioctl(struct tty_struct *tty, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
int rc;
struct sx_port *port = tty->driver_data;
@@ -1803,10 +1896,10 @@ static int sx_ioctl (struct tty_struct * tty, struct file * filp,
switch (cmd) {
case TIOCGSOFTCAR:
rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *) argp);
+ (unsigned __user *)argp);
break;
case TIOCSSOFTCAR:
- if ((rc = get_user(ival, (unsigned __user *) argp)) == 0) {
+ if ((rc = get_user(ival, (unsigned __user *)argp)) == 0) {
tty->termios->c_cflag =
(tty->termios->c_cflag & ~CLOCAL) |
(ival ? CLOCAL : 0);
@@ -1827,7 +1920,6 @@ static int sx_ioctl (struct tty_struct * tty, struct file * filp,
return rc;
}
-
/* The throttle/unthrottle scheme for the Specialix card is different
* from other drivers and deserves some explanation.
* The Specialix hardware takes care of XON/XOFF
@@ -1844,7 +1936,7 @@ static int sx_ioctl (struct tty_struct * tty, struct file * filp,
* flow control scheme is in use for that port. -- Simon Allen
*/
-static void sx_throttle (struct tty_struct * tty)
+static void sx_throttle(struct tty_struct *tty)
{
struct sx_port *port = (struct sx_port *)tty->driver_data;
@@ -1852,14 +1944,13 @@ static void sx_throttle (struct tty_struct * tty)
/* If the port is using any type of input flow
* control then throttle the port.
*/
- if((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) {
+ if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty))) {
port->gs.flags |= SX_RX_THROTTLE;
}
func_exit();
}
-
-static void sx_unthrottle (struct tty_struct * tty)
+static void sx_unthrottle(struct tty_struct *tty)
{
struct sx_port *port = (struct sx_port *)tty->driver_data;
@@ -1873,15 +1964,11 @@ static void sx_unthrottle (struct tty_struct * tty)
return;
}
-
/* ********************************************************************** *
* Here are the initialization routines. *
* ********************************************************************** */
-
-
-
-static int sx_init_board (struct sx_board *board)
+static int sx_init_board(struct sx_board *board)
{
int addr;
int chans;
@@ -1893,36 +1980,38 @@ static int sx_init_board (struct sx_board *board)
board->flags |= SX_BOARD_INITIALIZED;
- if (read_sx_byte (board, 0))
+ if (read_sx_byte(board, 0))
/* CF boards may need this. */
- write_sx_byte(board,0, 0);
+ write_sx_byte(board, 0, 0);
/* This resets the processor again, to make sure it didn't do any
foolish things while we were downloading the image */
- if (!sx_reset (board))
+ if (!sx_reset(board))
return 0;
- sx_start_board (board);
- udelay (10);
- if (!sx_busy_wait_neq (board, 0, 0xff, 0)) {
- printk (KERN_ERR "sx: Ooops. Board won't initialize.\n");
+ sx_start_board(board);
+ udelay(10);
+ if (!sx_busy_wait_neq(board, 0, 0xff, 0)) {
+ printk(KERN_ERR "sx: Ooops. Board won't initialize.\n");
return 0;
}
/* Ok. So now the processor on the card is running. It gathered
some info for us... */
- sx_dprintk (SX_DEBUG_INIT, "The sxcard structure:\n");
- if (sx_debug & SX_DEBUG_INIT) my_hd_io (board->base, 0x10);
- sx_dprintk (SX_DEBUG_INIT, "the first sx_module structure:\n");
- if (sx_debug & SX_DEBUG_INIT) my_hd_io (board->base + 0x80, 0x30);
-
- sx_dprintk (SX_DEBUG_INIT,
- "init_status: %x, %dk memory, firmware V%x.%02x,\n",
- read_sx_byte (board, 0), read_sx_byte(board, 1),
- read_sx_byte (board, 5), read_sx_byte(board, 4));
-
- if (read_sx_byte (board, 0) == 0xff) {
- printk (KERN_INFO "sx: No modules found. Sorry.\n");
+ sx_dprintk(SX_DEBUG_INIT, "The sxcard structure:\n");
+ if (sx_debug & SX_DEBUG_INIT)
+ my_hd_io(board->base, 0x10);
+ sx_dprintk(SX_DEBUG_INIT, "the first sx_module structure:\n");
+ if (sx_debug & SX_DEBUG_INIT)
+ my_hd_io(board->base + 0x80, 0x30);
+
+ sx_dprintk(SX_DEBUG_INIT, "init_status: %x, %dk memory, firmware "
+ "V%x.%02x,\n",
+ read_sx_byte(board, 0), read_sx_byte(board, 1),
+ read_sx_byte(board, 5), read_sx_byte(board, 4));
+
+ if (read_sx_byte(board, 0) == 0xff) {
+ printk(KERN_INFO "sx: No modules found. Sorry.\n");
board->nports = 0;
return 0;
}
@@ -1930,82 +2019,97 @@ static int sx_init_board (struct sx_board *board)
chans = 0;
if (IS_SX_BOARD(board)) {
- sx_write_board_word (board, cc_int_count, sx_maxints);
+ sx_write_board_word(board, cc_int_count, sx_maxints);
} else {
if (sx_maxints)
- sx_write_board_word (board, cc_int_count, SI_PROCESSOR_CLOCK/8/sx_maxints);
+ sx_write_board_word(board, cc_int_count,
+ SI_PROCESSOR_CLOCK / 8 / sx_maxints);
}
/* grab the first module type... */
- /* board->ta_type = mod_compat_type (read_sx_byte (board, 0x80 + 0x08)); */
- board->ta_type = mod_compat_type (sx_read_module_byte (board, 0x80, mc_chip));
+ /* board->ta_type = mod_compat_type (read_sx_byte (board, 0x80 + 0x08)); */
+ board->ta_type = mod_compat_type(sx_read_module_byte(board, 0x80,
+ mc_chip));
/* XXX byteorder */
- for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) {
- type = sx_read_module_byte (board, addr, mc_chip);
- sx_dprintk (SX_DEBUG_INIT, "Module at %x: %d channels\n",
- addr, read_sx_byte (board, addr + 2));
-
- chans += sx_read_module_byte (board, addr, mc_type);
-
- sx_dprintk (SX_DEBUG_INIT, "module is an %s, which has %s/%s panels\n",
- mod_type_s (type),
- pan_type_s (sx_read_module_byte (board, addr, mc_mods) & 0xf),
- pan_type_s (sx_read_module_byte (board, addr, mc_mods) >> 4));
-
- sx_dprintk (SX_DEBUG_INIT, "CD1400 versions: %x/%x, ASIC version: %x\n",
- sx_read_module_byte (board, addr, mc_rev1),
- sx_read_module_byte (board, addr, mc_rev2),
- sx_read_module_byte (board, addr, mc_mtaasic_rev));
+ for (addr = 0x80; addr != 0; addr = read_sx_word(board, addr) & 0x7fff){
+ type = sx_read_module_byte(board, addr, mc_chip);
+ sx_dprintk(SX_DEBUG_INIT, "Module at %x: %d channels\n",
+ addr, read_sx_byte(board, addr + 2));
+
+ chans += sx_read_module_byte(board, addr, mc_type);
+
+ sx_dprintk(SX_DEBUG_INIT, "module is an %s, which has %s/%s "
+ "panels\n",
+ mod_type_s(type),
+ pan_type_s(sx_read_module_byte(board, addr,
+ mc_mods) & 0xf),
+ pan_type_s(sx_read_module_byte(board, addr,
+ mc_mods) >> 4));
+
+ sx_dprintk(SX_DEBUG_INIT, "CD1400 versions: %x/%x, ASIC "
+ "version: %x\n",
+ sx_read_module_byte(board, addr, mc_rev1),
+ sx_read_module_byte(board, addr, mc_rev2),
+ sx_read_module_byte(board, addr, mc_mtaasic_rev));
/* The following combinations are illegal: It should theoretically
work, but timing problems make the bus HANG. */
- if (mod_compat_type (type) != board->ta_type) {
- printk (KERN_ERR "sx: This is an invalid configuration.\n"
- "Don't mix TA/MTA/SXDC on the same hostadapter.\n");
- chans=0;
+ if (mod_compat_type(type) != board->ta_type) {
+ printk(KERN_ERR "sx: This is an invalid "
+ "configuration.\nDon't mix TA/MTA/SXDC on the "
+ "same hostadapter.\n");
+ chans = 0;
break;
}
- if ((IS_EISA_BOARD(board) ||
- IS_SI_BOARD(board)) && (mod_compat_type(type) == 4)) {
- printk (KERN_ERR "sx: This is an invalid configuration.\n"
- "Don't use SXDCs on an SI/XIO adapter.\n");
- chans=0;
+ if ((IS_EISA_BOARD(board) ||
+ IS_SI_BOARD(board)) &&
+ (mod_compat_type(type) == 4)) {
+ printk(KERN_ERR "sx: This is an invalid "
+ "configuration.\nDon't use SXDCs on an SI/XIO "
+ "adapter.\n");
+ chans = 0;
break;
}
-#if 0 /* Problem fixed: firmware 3.05 */
+#if 0 /* Problem fixed: firmware 3.05 */
if (IS_SX_BOARD(board) && (type == TA8)) {
/* There are some issues with the firmware and the DCD/RTS
lines. It might work if you tie them together or something.
- It might also work if you get a newer sx_firmware. Therefore
+ It might also work if you get a newer sx_firmware. Therefore
this is just a warning. */
- printk (KERN_WARNING "sx: The SX host doesn't work too well "
- "with the TA8 adapters.\nSpecialix is working on it.\n");
+ printk(KERN_WARNING
+ "sx: The SX host doesn't work too well "
+ "with the TA8 adapters.\nSpecialix is working on it.\n");
}
#endif
}
if (chans) {
- /* board->flags |= SX_BOARD_PRESENT; */
- if(board->irq > 0) {
+ if (board->irq > 0) {
/* fixed irq, probably PCI */
- if(sx_irqmask & (1 << board->irq)) { /* may we use this irq? */
- if(request_irq(board->irq, sx_interrupt, IRQF_SHARED | IRQF_DISABLED, "sx", board)) {
- printk(KERN_ERR "sx: Cannot allocate irq %d.\n", board->irq);
+ if (sx_irqmask & (1 << board->irq)) { /* may we use this irq? */
+ if (request_irq(board->irq, sx_interrupt,
+ IRQF_SHARED | IRQF_DISABLED,
+ "sx", board)) {
+ printk(KERN_ERR "sx: Cannot allocate "
+ "irq %d.\n", board->irq);
board->irq = 0;
}
} else
board->irq = 0;
- } else if(board->irq < 0 && sx_irqmask) {
+ } else if (board->irq < 0 && sx_irqmask) {
/* auto-allocate irq */
int irqnr;
- int irqmask = sx_irqmask & (IS_SX_BOARD(board) ? SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK);
- for(irqnr = 15; irqnr > 0; irqnr--)
- if(irqmask & (1 << irqnr))
- if(! request_irq(irqnr, sx_interrupt, IRQF_SHARED | IRQF_DISABLED, "sx", board))
+ int irqmask = sx_irqmask & (IS_SX_BOARD(board) ?
+ SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK);
+ for (irqnr = 15; irqnr > 0; irqnr--)
+ if (irqmask & (1 << irqnr))
+ if (!request_irq(irqnr, sx_interrupt,
+ IRQF_SHARED | IRQF_DISABLED,
+ "sx", board))
break;
- if(! irqnr)
+ if (!irqnr)
printk(KERN_ERR "sx: Cannot allocate IRQ.\n");
board->irq = irqnr;
} else
@@ -2013,52 +2117,48 @@ static int sx_init_board (struct sx_board *board)
if (board->irq) {
/* Found a valid interrupt, start up interrupts! */
- sx_dprintk (SX_DEBUG_INIT, "Using irq %d.\n", board->irq);
- sx_start_interrupts (board);
+ sx_dprintk(SX_DEBUG_INIT, "Using irq %d.\n",
+ board->irq);
+ sx_start_interrupts(board);
board->poll = sx_slowpoll;
board->flags |= SX_IRQ_ALLOCATED;
} else {
/* no irq: setup board for polled operation */
board->poll = sx_poll;
- sx_dprintk (SX_DEBUG_INIT, "Using poll-interval %d.\n", board->poll);
+ sx_dprintk(SX_DEBUG_INIT, "Using poll-interval %d.\n",
+ board->poll);
}
- /* The timer should be initialized anyway: That way we can safely
- del_timer it when the module is unloaded. */
- init_timer (&board->timer);
+ /* The timer should be initialized anyway: That way we can
+ safely del_timer it when the module is unloaded. */
+ setup_timer(&board->timer, sx_pollfunc, (unsigned long)board);
- if (board->poll) {
- board->timer.data = (unsigned long) board;
- board->timer.function = sx_pollfunc;
- board->timer.expires = jiffies + board->poll;
- add_timer (&board->timer);
- }
+ if (board->poll)
+ mod_timer(&board->timer, jiffies + board->poll);
} else {
board->irq = 0;
}
board->nports = chans;
- sx_dprintk (SX_DEBUG_INIT, "returning %d ports.", board->nports);
+ sx_dprintk(SX_DEBUG_INIT, "returning %d ports.", board->nports);
func_exit();
return chans;
}
-
-static void printheader(void)
+static void __devinit printheader(void)
{
static int header_printed;
if (!header_printed) {
- printk (KERN_INFO "Specialix SX driver "
- "(C) 1998/1999 R.E.Wolff@BitWizard.nl \n");
- printk (KERN_INFO "sx: version %s\n", RCS_ID);
+ printk(KERN_INFO "Specialix SX driver "
+ "(C) 1998/1999 R.E.Wolff@BitWizard.nl\n");
+ printk(KERN_INFO "sx: version " __stringify(SX_VERSION) "\n");
header_printed = 1;
}
}
-
-static int probe_sx (struct sx_board *board)
+static int __devinit probe_sx(struct sx_board *board)
{
struct vpd_prom vpdp;
char *p;
@@ -2066,51 +2166,57 @@ static int probe_sx (struct sx_board *board)
func_enter();
- if (!IS_CF_BOARD (board)) {
- sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %p.\n",
- board->base + SX_VPD_ROM);
+ if (!IS_CF_BOARD(board)) {
+ sx_dprintk(SX_DEBUG_PROBE, "Going to verify vpd prom at %p.\n",
+ board->base + SX_VPD_ROM);
if (sx_debug & SX_DEBUG_PROBE)
my_hd_io(board->base + SX_VPD_ROM, 0x40);
- p = (char *) &vpdp;
- for (i=0;i< sizeof (struct vpd_prom);i++)
- *p++ = read_sx_byte (board, SX_VPD_ROM + i*2);
+ p = (char *)&vpdp;
+ for (i = 0; i < sizeof(struct vpd_prom); i++)
+ *p++ = read_sx_byte(board, SX_VPD_ROM + i * 2);
if (sx_debug & SX_DEBUG_PROBE)
- my_hd (&vpdp, 0x20);
+ my_hd(&vpdp, 0x20);
- sx_dprintk (SX_DEBUG_PROBE, "checking identifier...\n");
+ sx_dprintk(SX_DEBUG_PROBE, "checking identifier...\n");
- if (strncmp (vpdp.identifier, SX_VPD_IDENT_STRING, 16) != 0) {
- sx_dprintk (SX_DEBUG_PROBE, "Got non-SX identifier: '%s'\n",
- vpdp.identifier);
+ if (strncmp(vpdp.identifier, SX_VPD_IDENT_STRING, 16) != 0) {
+ sx_dprintk(SX_DEBUG_PROBE, "Got non-SX identifier: "
+ "'%s'\n", vpdp.identifier);
return 0;
}
}
- printheader ();
-
- if (!IS_CF_BOARD (board)) {
- printk (KERN_DEBUG "sx: Found an SX board at %lx\n", board->hw_base);
- printk (KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, uniq ID:%08x, ",
- vpdp.hwrev, vpdp.hwass, vpdp.uniqid);
- printk ( "Manufactured: %d/%d\n",
- 1970 + vpdp.myear, vpdp.mweek);
+ printheader();
+ if (!IS_CF_BOARD(board)) {
+ printk(KERN_DEBUG "sx: Found an SX board at %lx\n",
+ board->hw_base);
+ printk(KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, "
+ "uniq ID:%08x, ",
+ vpdp.hwrev, vpdp.hwass, vpdp.uniqid);
+ printk("Manufactured: %d/%d\n", 1970 + vpdp.myear, vpdp.mweek);
- if ((((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_PCI_UNIQUEID1) &&
- (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_ISA_UNIQUEID1)) {
- /* This might be a bit harsh. This was the primary reason the
- SX/ISA card didn't work at first... */
- printk (KERN_ERR "sx: Hmm. Not an SX/PCI or SX/ISA card. Sorry: giving up.\n");
+ if ((((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) !=
+ SX_PCI_UNIQUEID1) && (((vpdp.uniqid >> 24) &
+ SX_UNIQUEID_MASK) != SX_ISA_UNIQUEID1)) {
+ /* This might be a bit harsh. This was the primary
+ reason the SX/ISA card didn't work at first... */
+ printk(KERN_ERR "sx: Hmm. Not an SX/PCI or SX/ISA "
+ "card. Sorry: giving up.\n");
return (0);
}
- if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) {
+ if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) ==
+ SX_ISA_UNIQUEID1) {
if (((unsigned long)board->hw_base) & 0x8000) {
- printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %lx.\n", board->hw_base);
- printk (KERN_WARNING "sx: Read sx.txt for more info.\n");
+ printk(KERN_WARNING "sx: Warning: There may be "
+ "hardware problems with the card at "
+ "%lx.\n", board->hw_base);
+ printk(KERN_WARNING "sx: Read sx.txt for more "
+ "info.\n");
}
}
}
@@ -2118,17 +2224,15 @@ static int probe_sx (struct sx_board *board)
board->nports = -1;
/* This resets the processor, and keeps it off the bus. */
- if (!sx_reset (board))
+ if (!sx_reset(board))
return 0;
- sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
-
- board->flags |= SX_BOARD_PRESENT;
+ sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
func_exit();
return 1;
}
-
+#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
/* Specialix probes for this card at 32k increments from 640k to 16M.
I consider machines with less than 16M unlikely nowadays, so I'm
@@ -2136,28 +2240,27 @@ static int probe_sx (struct sx_board *board)
card. 0xe0000 and 0xf0000 are taken by the BIOS. That only leaves
0xc0000, 0xc8000, 0xd0000 and 0xd8000 . */
-static int probe_si (struct sx_board *board)
+static int __devinit probe_si(struct sx_board *board)
{
int i;
func_enter();
- sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at %p.\n", board->hw_base,
- board->base + SI2_ISA_ID_BASE);
+ sx_dprintk(SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at "
+ "%p.\n", board->hw_base, board->base + SI2_ISA_ID_BASE);
if (sx_debug & SX_DEBUG_PROBE)
my_hd_io(board->base + SI2_ISA_ID_BASE, 0x8);
if (!IS_EISA_BOARD(board)) {
- if( IS_SI1_BOARD(board) )
- {
- for (i=0;i<8;i++) {
- write_sx_byte (board, SI2_ISA_ID_BASE+7-i,i);
-
+ if (IS_SI1_BOARD(board)) {
+ for (i = 0; i < 8; i++) {
+ write_sx_byte(board, SI2_ISA_ID_BASE + 7 - i,i);
+ }
}
- }
- for (i=0;i<8;i++) {
- if ((read_sx_byte (board, SI2_ISA_ID_BASE+7-i) & 7) != i) {
- func_exit ();
+ for (i = 0; i < 8; i++) {
+ if ((read_sx_byte(board, SI2_ISA_ID_BASE + 7 - i) & 7)
+ != i) {
+ func_exit();
return 0;
}
}
@@ -2167,20 +2270,20 @@ static int probe_si (struct sx_board *board)
but to prevent trouble, we'd better double check that we don't
have an SI1 board when we're probing for an SI2 board.... */
- write_sx_byte (board, SI2_ISA_ID_BASE,0x10);
- if ( IS_SI1_BOARD(board)) {
+ write_sx_byte(board, SI2_ISA_ID_BASE, 0x10);
+ if (IS_SI1_BOARD(board)) {
/* This should be an SI1 board, which has this
location writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10) {
- func_exit ();
- return 0;
+ if (read_sx_byte(board, SI2_ISA_ID_BASE) != 0x10) {
+ func_exit();
+ return 0;
}
} else {
/* This should be an SI2 board, which has the bottom
3 bits non-writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10) {
- func_exit ();
- return 0;
+ if (read_sx_byte(board, SI2_ISA_ID_BASE) == 0x10) {
+ func_exit();
+ return 0;
}
}
@@ -2188,45 +2291,44 @@ static int probe_si (struct sx_board *board)
but to prevent trouble, we'd better double check that we don't
have an SI1 board when we're probing for an SI2 board.... */
- write_sx_byte (board, SI2_ISA_ID_BASE,0x10);
- if ( IS_SI1_BOARD(board)) {
+ write_sx_byte(board, SI2_ISA_ID_BASE, 0x10);
+ if (IS_SI1_BOARD(board)) {
/* This should be an SI1 board, which has this
location writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10) {
+ if (read_sx_byte(board, SI2_ISA_ID_BASE) != 0x10) {
func_exit();
- return 0;
+ return 0;
}
} else {
/* This should be an SI2 board, which has the bottom
3 bits non-writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10) {
- func_exit ();
- return 0;
+ if (read_sx_byte(board, SI2_ISA_ID_BASE) == 0x10) {
+ func_exit();
+ return 0;
}
}
- printheader ();
+ printheader();
- printk (KERN_DEBUG "sx: Found an SI board at %lx\n", board->hw_base);
+ printk(KERN_DEBUG "sx: Found an SI board at %lx\n", board->hw_base);
/* Compared to the SX boards, it is a complete guess as to what
- this card is up to... */
+ this card is up to... */
board->nports = -1;
/* This resets the processor, and keeps it off the bus. */
- if (!sx_reset (board))
+ if (!sx_reset(board))
return 0;
- sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
-
- board->flags |= SX_BOARD_PRESENT;
+ sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
func_exit();
return 1;
}
+#endif
static const struct tty_operations sx_ops = {
.break_ctl = sx_break,
- .open = sx_open,
+ .open = sx_open,
.close = gs_close,
.write = gs_write,
.put_char = gs_put_char,
@@ -2261,34 +2363,23 @@ static int sx_init_drivers(void)
sx_driver->type = TTY_DRIVER_TYPE_SERIAL;
sx_driver->subtype = SERIAL_TYPE_NORMAL;
sx_driver->init_termios = tty_std_termios;
- sx_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ sx_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ sx_driver->init_termios.c_ispeed = 9600;
+ sx_driver->init_termios.c_ospeed = 9600;
sx_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(sx_driver, &sx_ops);
if ((error = tty_register_driver(sx_driver))) {
put_tty_driver(sx_driver);
printk(KERN_ERR "sx: Couldn't register sx driver, error = %d\n",
- error);
+ error);
return 1;
}
func_exit();
return 0;
}
-
-static void * ckmalloc (int size)
-{
- void *p;
-
- p = kmalloc(size, GFP_KERNEL);
- if (p)
- memset(p, 0, size);
- return p;
-}
-
-
-static int sx_init_portstructs (int nboards, int nports)
+static int sx_init_portstructs(int nboards, int nports)
{
struct sx_board *board;
struct sx_port *port;
@@ -2299,8 +2390,9 @@ static int sx_init_portstructs (int nboards, int nports)
func_enter();
/* Many drivers statically allocate the maximum number of ports
- There is no reason not to allocate them dynamically. Is there? -- REW */
- sx_ports = ckmalloc(nports * sizeof (struct sx_port));
+ There is no reason not to allocate them dynamically.
+ Is there? -- REW */
+ sx_ports = kcalloc(nports, sizeof(struct sx_port), GFP_KERNEL);
if (!sx_ports)
return -ENOMEM;
@@ -2308,10 +2400,10 @@ static int sx_init_portstructs (int nboards, int nports)
for (i = 0; i < nboards; i++) {
board = &boards[i];
board->ports = port;
- for (j=0; j < boards[i].nports;j++) {
- sx_dprintk (SX_DEBUG_INIT, "initing port %d\n", j);
+ for (j = 0; j < boards[i].nports; j++) {
+ sx_dprintk(SX_DEBUG_INIT, "initing port %d\n", j);
port->gs.magic = SX_MAGIC;
- port->gs.close_delay = HZ/2;
+ port->gs.close_delay = HZ / 2;
port->gs.closing_wait = 30 * HZ;
port->board = board;
port->gs.rd = &sx_real_driver;
@@ -2323,8 +2415,8 @@ static int sx_init_portstructs (int nboards, int nports)
* Initializing wait queue
*/
init_waitqueue_head(&port->gs.open_wait);
- init_waitqueue_head(&port->gs.close_wait);
-
+ init_waitqueue_head(&port->gs.close_wait);
+
port++;
}
}
@@ -2335,28 +2427,36 @@ static int sx_init_portstructs (int nboards, int nports)
board = &boards[i];
board->port_base = portno;
/* Possibly the configuration was rejected. */
- sx_dprintk (SX_DEBUG_PROBE, "Board has %d channels\n", board->nports);
- if (board->nports <= 0) continue;
+ sx_dprintk(SX_DEBUG_PROBE, "Board has %d channels\n",
+ board->nports);
+ if (board->nports <= 0)
+ continue;
/* XXX byteorder ?? */
- for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) {
- chans = sx_read_module_byte (board, addr, mc_type);
- sx_dprintk (SX_DEBUG_PROBE, "Module at %x: %d channels\n", addr, chans);
- sx_dprintk (SX_DEBUG_PROBE, "Port at");
- for (j=0;j<chans;j++) {
- /* The "sx-way" is the way it SHOULD be done. That way in the
- future, the firmware may for example pack the structures a bit
- more efficient. Neil tells me it isn't going to happen anytime
- soon though. */
+ for (addr = 0x80; addr != 0;
+ addr = read_sx_word(board, addr) & 0x7fff) {
+ chans = sx_read_module_byte(board, addr, mc_type);
+ sx_dprintk(SX_DEBUG_PROBE, "Module at %x: %d "
+ "channels\n", addr, chans);
+ sx_dprintk(SX_DEBUG_PROBE, "Port at");
+ for (j = 0; j < chans; j++) {
+ /* The "sx-way" is the way it SHOULD be done.
+ That way in the future, the firmware may for
+ example pack the structures a bit more
+ efficient. Neil tells me it isn't going to
+ happen anytime soon though. */
if (IS_SX_BOARD(board))
- port->ch_base = sx_read_module_word (board, addr+j*2, mc_chan_pointer);
+ port->ch_base = sx_read_module_word(
+ board, addr + j * 2,
+ mc_chan_pointer);
else
- port->ch_base = addr + 0x100 + 0x300*j;
+ port->ch_base = addr + 0x100 + 0x300 *j;
- sx_dprintk (SX_DEBUG_PROBE, " %x", port->ch_base);
+ sx_dprintk(SX_DEBUG_PROBE, " %x",
+ port->ch_base);
port->line = portno++;
port++;
}
- sx_dprintk (SX_DEBUG_PROBE, "\n");
+ sx_dprintk(SX_DEBUG_PROBE, "\n");
}
/* This has to be done earlier. */
/* board->flags |= SX_BOARD_INITIALIZED; */
@@ -2366,6 +2466,17 @@ static int sx_init_portstructs (int nboards, int nports)
return 0;
}
+static unsigned int sx_find_free_board(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < SX_NBOARDS; i++)
+ if (!(boards[i].flags & SX_BOARD_PRESENT))
+ break;
+
+ return i;
+}
+
static void __exit sx_release_drivers(void)
{
func_enter();
@@ -2374,6 +2485,124 @@ static void __exit sx_release_drivers(void)
func_exit();
}
+static void __devexit sx_remove_card(struct sx_board *board,
+ struct pci_dev *pdev)
+{
+ if (board->flags & SX_BOARD_INITIALIZED) {
+ /* The board should stop messing with us. (actually I mean the
+ interrupt) */
+ sx_reset(board);
+ if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED))
+ free_irq(board->irq, board);
+
+ /* It is safe/allowed to del_timer a non-active timer */
+ del_timer(&board->timer);
+ if (pdev) {
+#ifdef CONFIG_PCI
+ pci_iounmap(pdev, board->base);
+ pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2);
+#endif
+ } else {
+ iounmap(board->base);
+ release_region(board->hw_base, board->hw_len);
+ }
+
+ board->flags &= ~(SX_BOARD_INITIALIZED | SX_BOARD_PRESENT);
+ }
+}
+
+#ifdef CONFIG_EISA
+
+static int __devinit sx_eisa_probe(struct device *dev)
+{
+ struct eisa_device *edev = to_eisa_device(dev);
+ struct sx_board *board;
+ unsigned long eisa_slot = edev->base_addr;
+ unsigned int i;
+ int retval = -EIO;
+
+ mutex_lock(&sx_boards_lock);
+ i = sx_find_free_board();
+ if (i == SX_NBOARDS) {
+ mutex_unlock(&sx_boards_lock);
+ goto err;
+ }
+ board = &boards[i];
+ board->flags |= SX_BOARD_PRESENT;
+ mutex_unlock(&sx_boards_lock);
+
+ dev_info(dev, "XIO : Signature found in EISA slot %lu, "
+ "Product %d Rev %d (REPORT THIS TO LKLM)\n",
+ eisa_slot >> 12,
+ inb(eisa_slot + EISA_VENDOR_ID_OFFSET + 2),
+ inb(eisa_slot + EISA_VENDOR_ID_OFFSET + 3));
+
+ board->eisa_base = eisa_slot;
+ board->flags &= ~SX_BOARD_TYPE;
+ board->flags |= SI_EISA_BOARD;
+
+ board->hw_base = ((inb(eisa_slot + 0xc01) << 8) +
+ inb(eisa_slot + 0xc00)) << 16;
+ board->hw_len = SI2_EISA_WINDOW_LEN;
+ if (!request_region(board->hw_base, board->hw_len, "sx")) {
+ dev_err(dev, "can't request region\n");
+ goto err_flag;
+ }
+ board->base2 =
+ board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
+ if (!board->base) {
+ dev_err(dev, "can't remap memory\n");
+ goto err_reg;
+ }
+
+ sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
+ sx_dprintk(SX_DEBUG_PROBE, "base: %p\n", board->base);
+ board->irq = inb(eisa_slot + 0xc02) >> 4;
+ sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
+
+ if (!probe_si(board))
+ goto err_unmap;
+
+ dev_set_drvdata(dev, board);
+
+ return 0;
+err_unmap:
+ iounmap(board->base);
+err_reg:
+ release_region(board->hw_base, board->hw_len);
+err_flag:
+ board->flags &= ~SX_BOARD_PRESENT;
+err:
+ return retval;
+}
+
+static int __devexit sx_eisa_remove(struct device *dev)
+{
+ struct sx_board *board = dev_get_drvdata(dev);
+
+ sx_remove_card(board, NULL);
+
+ return 0;
+}
+
+static struct eisa_device_id sx_eisa_tbl[] = {
+ { "SLX" },
+ { "" }
+};
+
+MODULE_DEVICE_TABLE(eisa, sx_eisa_tbl);
+
+static struct eisa_driver sx_eisadriver = {
+ .id_table = sx_eisa_tbl,
+ .driver = {
+ .name = "sx",
+ .probe = sx_eisa_probe,
+ .remove = __devexit_p(sx_eisa_remove),
+ }
+};
+
+#endif
+
#ifdef CONFIG_PCI
/********************************************************
* Setting bit 17 in the CNTRL register of the PLX 9050 *
@@ -2386,233 +2615,270 @@ static void __exit sx_release_drivers(void)
EEprom. As the bit is read/write for the CPU, we can fix it here,
if we detect that it isn't set correctly. -- REW */
-static void fix_sx_pci (struct pci_dev *pdev, struct sx_board *board)
+static void __devinit fix_sx_pci(struct pci_dev *pdev, struct sx_board *board)
{
unsigned int hwbase;
void __iomem *rebase;
unsigned int t;
-#define CNTRL_REG_OFFSET 0x50
-#define CNTRL_REG_GOODVALUE 0x18260000
+#define CNTRL_REG_OFFSET 0x50
+#define CNTRL_REG_GOODVALUE 0x18260000
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
rebase = ioremap(hwbase, 0x80);
- t = readl (rebase + CNTRL_REG_OFFSET);
+ t = readl(rebase + CNTRL_REG_OFFSET);
if (t != CNTRL_REG_GOODVALUE) {
- printk (KERN_DEBUG "sx: performing cntrl reg fix: %08x -> %08x\n", t, CNTRL_REG_GOODVALUE);
- writel (CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);
+ printk(KERN_DEBUG "sx: performing cntrl reg fix: %08x -> "
+ "%08x\n", t, CNTRL_REG_GOODVALUE);
+ writel(CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);
}
iounmap(rebase);
}
#endif
-
-static int __init sx_init(void)
+static int __devinit sx_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- int i;
- int found = 0;
- int eisa_slot;
+#ifdef CONFIG_PCI
struct sx_board *board;
+ unsigned int i, reg;
+ int retval = -EIO;
-#ifdef CONFIG_PCI
- struct pci_dev *pdev = NULL;
- unsigned int tint;
- unsigned short tshort;
-#endif
+ mutex_lock(&sx_boards_lock);
+ i = sx_find_free_board();
+ if (i == SX_NBOARDS) {
+ mutex_unlock(&sx_boards_lock);
+ goto err;
+ }
+ board = &boards[i];
+ board->flags |= SX_BOARD_PRESENT;
+ mutex_unlock(&sx_boards_lock);
- func_enter();
- sx_dprintk (SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n", sx_debug);
- if (abs ((long) (&sx_debug) - sx_debug) < 0x10000) {
- printk (KERN_WARNING "sx: sx_debug is an address, instead of a value. "
- "Assuming -1.\n");
- printk ("(%p)\n", &sx_debug);
- sx_debug=-1;
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err_flag;
+
+ board->flags &= ~SX_BOARD_TYPE;
+ board->flags |= (pdev->subsystem_vendor == 0x200) ? SX_PCI_BOARD :
+ SX_CFPCI_BOARD;
+
+ /* CF boards use base address 3.... */
+ reg = IS_CF_BOARD(board) ? 3 : 2;
+ retval = pci_request_region(pdev, reg, "sx");
+ if (retval) {
+ dev_err(&pdev->dev, "can't request region\n");
+ goto err_flag;
+ }
+ board->hw_base = pci_resource_start(pdev, reg);
+ board->base2 =
+ board->base = pci_iomap(pdev, reg, WINDOW_LEN(board));
+ if (!board->base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ goto err_reg;
}
- if (misc_register(&sx_fw_device) < 0) {
- printk(KERN_ERR "SX: Unable to register firmware loader driver.\n");
- return -EIO;
+ /* Most of the stuff on the CF board is offset by 0x18000 .... */
+ if (IS_CF_BOARD(board))
+ board->base += 0x18000;
+
+ board->irq = pdev->irq;
+
+ dev_info(&pdev->dev, "Got a specialix card: %p(%d) %x.\n", board->base,
+ board->irq, board->flags);
+
+ if (!probe_sx(board)) {
+ retval = -EIO;
+ goto err_unmap;
}
-#ifdef CONFIG_PCI
- while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
- PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
- pdev))) {
- if (pci_enable_device(pdev))
- continue;
+ fix_sx_pci(pdev, board);
- /* Specialix has a whole bunch of cards with
- 0x2000 as the device ID. They say its because
- the standard requires it. Stupid standard. */
- /* It seems that reading a word doesn't work reliably on 2.0.
- Also, reading a non-aligned dword doesn't work. So we read the
- whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID)
- ourselves */
- /* I don't know why the define doesn't work, constant 0x2c does --REW */
- pci_read_config_dword (pdev, 0x2c, &tint);
- tshort = (tint >> 16) & 0xffff;
- sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x.\n", tint);
- /* sx_dprintk (SX_DEBUG_PROBE, "pdev = %d/%d (%x)\n", pdev, tint); */
- if ((tshort != 0x0200) && (tshort != 0x0300)) {
- sx_dprintk (SX_DEBUG_PROBE, "But it's not an SX card (%d)...\n",
- tshort);
- continue;
- }
- board = &boards[found];
+ pci_set_drvdata(pdev, board);
- board->flags &= ~SX_BOARD_TYPE;
- board->flags |= (tshort == 0x200)?SX_PCI_BOARD:
- SX_CFPCI_BOARD;
-
- /* CF boards use base address 3.... */
- if (IS_CF_BOARD (board))
- board->hw_base = pci_resource_start (pdev, 3);
- else
- board->hw_base = pci_resource_start (pdev, 2);
- board->base2 =
- board->base = ioremap(board->hw_base, WINDOW_LEN (board));
- if (!board->base) {
- printk(KERN_ERR "ioremap failed\n");
- /* XXX handle error */
- }
+ return 0;
+err_unmap:
+ pci_iounmap(pdev, board->base);
+err_reg:
+ pci_release_region(pdev, reg);
+err_flag:
+ board->flags &= ~SX_BOARD_PRESENT;
+err:
+ return retval;
+#else
+ return -ENODEV;
+#endif
+}
- /* Most of the stuff on the CF board is offset by
- 0x18000 .... */
- if (IS_CF_BOARD (board)) board->base += 0x18000;
+static void __devexit sx_pci_remove(struct pci_dev *pdev)
+{
+ struct sx_board *board = pci_get_drvdata(pdev);
- board->irq = pdev->irq;
+ sx_remove_card(board, pdev);
+}
- sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%p(%d) %x.\n",
- tint, boards[found].base, board->irq, board->flags);
+/* Specialix has a whole bunch of cards with 0x2000 as the device ID. They say
+ its because the standard requires it. So check for SUBVENDOR_ID. */
+static struct pci_device_id sx_pci_tbl[] = {
+ { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
+ .subvendor = 0x0200,.subdevice = PCI_ANY_ID },
+ { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
+ .subvendor = 0x0300,.subdevice = PCI_ANY_ID },
+ { 0 }
+};
- if (probe_sx (board)) {
- found++;
- fix_sx_pci (pdev, board);
- } else
- iounmap(board->base2);
- }
+MODULE_DEVICE_TABLE(pci, sx_pci_tbl);
+
+static struct pci_driver sx_pcidriver = {
+ .name = "sx",
+ .id_table = sx_pci_tbl,
+ .probe = sx_pci_probe,
+ .remove = __devexit_p(sx_pci_remove)
+};
+
+static int __init sx_init(void)
+{
+#ifdef CONFIG_EISA
+ int retval1;
+#endif
+#ifdef CONFIG_ISA
+ struct sx_board *board;
+ unsigned int i;
#endif
+ unsigned int found = 0;
+ int retval;
- for (i=0;i<NR_SX_ADDRS;i++) {
+ func_enter();
+ sx_dprintk(SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n",
+ sx_debug);
+ if (abs((long)(&sx_debug) - sx_debug) < 0x10000) {
+ printk(KERN_WARNING "sx: sx_debug is an address, instead of a "
+ "value. Assuming -1.\n(%p)\n", &sx_debug);
+ sx_debug = -1;
+ }
+
+ if (misc_register(&sx_fw_device) < 0) {
+ printk(KERN_ERR "SX: Unable to register firmware loader "
+ "driver.\n");
+ return -EIO;
+ }
+#ifdef CONFIG_ISA
+ for (i = 0; i < NR_SX_ADDRS; i++) {
board = &boards[found];
board->hw_base = sx_probe_addrs[i];
+ board->hw_len = SX_WINDOW_LEN;
+ if (!request_region(board->hw_base, board->hw_len, "sx"))
+ continue;
board->base2 =
- board->base = ioremap(board->hw_base, SX_WINDOW_LEN);
+ board->base = ioremap(board->hw_base, board->hw_len);
+ if (!board->base)
+ goto err_sx_reg;
board->flags &= ~SX_BOARD_TYPE;
- board->flags |= SX_ISA_BOARD;
- board->irq = sx_irqmask?-1:0;
+ board->flags |= SX_ISA_BOARD;
+ board->irq = sx_irqmask ? -1 : 0;
- if (probe_sx (board)) {
+ if (probe_sx(board)) {
+ board->flags |= SX_BOARD_PRESENT;
found++;
} else {
iounmap(board->base);
+err_sx_reg:
+ release_region(board->hw_base, board->hw_len);
}
}
- for (i=0;i<NR_SI_ADDRS;i++) {
+ for (i = 0; i < NR_SI_ADDRS; i++) {
board = &boards[found];
board->hw_base = si_probe_addrs[i];
+ board->hw_len = SI2_ISA_WINDOW_LEN;
+ if (!request_region(board->hw_base, board->hw_len, "sx"))
+ continue;
board->base2 =
- board->base = ioremap(board->hw_base, SI2_ISA_WINDOW_LEN);
+ board->base = ioremap(board->hw_base, board->hw_len);
+ if (!board->base)
+ goto err_si_reg;
board->flags &= ~SX_BOARD_TYPE;
- board->flags |= SI_ISA_BOARD;
- board->irq = sx_irqmask ?-1:0;
+ board->flags |= SI_ISA_BOARD;
+ board->irq = sx_irqmask ? -1 : 0;
- if (probe_si (board)) {
+ if (probe_si(board)) {
+ board->flags |= SX_BOARD_PRESENT;
found++;
} else {
- iounmap (board->base);
+ iounmap(board->base);
+err_si_reg:
+ release_region(board->hw_base, board->hw_len);
}
}
- for (i=0;i<NR_SI1_ADDRS;i++) {
+ for (i = 0; i < NR_SI1_ADDRS; i++) {
board = &boards[found];
board->hw_base = si1_probe_addrs[i];
+ board->hw_len = SI1_ISA_WINDOW_LEN;
+ if (!request_region(board->hw_base, board->hw_len, "sx"))
+ continue;
board->base2 =
- board->base = ioremap(board->hw_base, SI1_ISA_WINDOW_LEN);
+ board->base = ioremap(board->hw_base, board->hw_len);
+ if (!board->base)
+ goto err_si1_reg;
board->flags &= ~SX_BOARD_TYPE;
- board->flags |= SI1_ISA_BOARD;
- board->irq = sx_irqmask ?-1:0;
+ board->flags |= SI1_ISA_BOARD;
+ board->irq = sx_irqmask ? -1 : 0;
- if (probe_si (board)) {
+ if (probe_si(board)) {
+ board->flags |= SX_BOARD_PRESENT;
found++;
} else {
- iounmap (board->base);
+ iounmap(board->base);
+err_si1_reg:
+ release_region(board->hw_base, board->hw_len);
}
}
+#endif
+#ifdef CONFIG_EISA
+ retval1 = eisa_driver_register(&sx_eisadriver);
+#endif
+ retval = pci_register_driver(&sx_pcidriver);
- sx_dprintk(SX_DEBUG_PROBE, "Probing for EISA cards\n");
- for(eisa_slot=0x1000; eisa_slot<0x10000; eisa_slot+=0x1000)
- {
- if((inb(eisa_slot+0xc80)==0x4d) &&
- (inb(eisa_slot+0xc81)==0x98))
- {
- sx_dprintk(SX_DEBUG_PROBE, "%s : Signature found in EISA slot %d, Product %d Rev %d\n",
- "XIO", (eisa_slot>>12), inb(eisa_slot+0xc82), inb(eisa_slot+0xc83));
-
- board = &boards[found];
- board->eisa_base = eisa_slot;
- board->flags &= ~SX_BOARD_TYPE;
- board->flags |= SI_EISA_BOARD;
-
- board->hw_base = (((inb(0xc01+eisa_slot) << 8) + inb(0xc00+eisa_slot)) << 16);
- board->base2 =
- board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
-
- sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
- sx_dprintk(SX_DEBUG_PROBE, "base: %p\n", board->base);
- board->irq = inb(board->eisa_base+0xc02)>>4;
- sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
-
- probe_si(board);
-
- found++;
- }
- }
if (found) {
- printk (KERN_INFO "sx: total of %d boards detected.\n", found);
- } else {
- misc_deregister(&sx_fw_device);
+ printk(KERN_INFO "sx: total of %d boards detected.\n", found);
+ retval = 0;
+ } else if (retval) {
+#ifdef CONFIG_EISA
+ retval = retval1;
+ if (retval1)
+#endif
+ misc_deregister(&sx_fw_device);
}
func_exit();
- return found?0:-EIO;
+ return retval;
}
-
-static void __exit sx_exit (void)
+static void __exit sx_exit(void)
{
- int i;
- struct sx_board *board;
+ int i;
func_enter();
- for (i = 0; i < SX_NBOARDS; i++) {
- board = &boards[i];
- if (board->flags & SX_BOARD_INITIALIZED) {
- sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %p\n", board->base);
- /* The board should stop messing with us.
- (actually I mean the interrupt) */
- sx_reset (board);
- if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED))
- free_irq (board->irq, board);
-
- /* It is safe/allowed to del_timer a non-active timer */
- del_timer (& board->timer);
- iounmap(board->base);
- }
- }
+#ifdef CONFIG_EISA
+ eisa_driver_unregister(&sx_eisadriver);
+#endif
+ pci_unregister_driver(&sx_pcidriver);
+
+ for (i = 0; i < SX_NBOARDS; i++)
+ sx_remove_card(&boards[i], NULL);
+
if (misc_deregister(&sx_fw_device) < 0) {
- printk (KERN_INFO "sx: couldn't deregister firmware loader device\n");
+ printk(KERN_INFO "sx: couldn't deregister firmware loader "
+ "device\n");
}
- sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized);
+ sx_dprintk(SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n",
+ sx_initialized);
if (sx_initialized)
- sx_release_drivers ();
+ sx_release_drivers();
- kfree (sx_ports);
+ kfree(sx_ports);
func_exit();
}
module_init(sx_init);
module_exit(sx_exit);
-
-
diff --git a/drivers/char/sx.h b/drivers/char/sx.h
index e01f83cbe29..432aad0a2dd 100644
--- a/drivers/char/sx.h
+++ b/drivers/char/sx.h
@@ -35,6 +35,7 @@ struct sx_board {
void __iomem *base;
void __iomem *base2;
unsigned long hw_base;
+ resource_size_t hw_len;
int eisa_base;
int port_base; /* Number of the first port */
struct sx_port *ports;
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 645187b9141..3fa625db9e4 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -3060,7 +3060,7 @@ static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigne
*
* Return Value: None
*/
-static void mgsl_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
unsigned long flags;
@@ -4332,7 +4332,7 @@ static struct mgsl_struct* mgsl_allocate_device(void)
{
struct mgsl_struct *info;
- info = (struct mgsl_struct *)kmalloc(sizeof(struct mgsl_struct),
+ info = kmalloc(sizeof(struct mgsl_struct),
GFP_KERNEL);
if (!info) {
@@ -4405,6 +4405,8 @@ static int mgsl_init_tty(void)
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver->init_termios.c_ispeed = 9600;
+ serial_driver->init_termios.c_ospeed = 9600;
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &mgsl_ops);
if ((rc = tty_register_driver(serial_driver)) < 0) {
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index e4730a7312b..792c79c315e 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -151,7 +151,7 @@ static struct tty_driver *serial_driver;
static int open(struct tty_struct *tty, struct file * filp);
static void close(struct tty_struct *tty, struct file * filp);
static void hangup(struct tty_struct *tty);
-static void set_termios(struct tty_struct *tty, struct termios *old_termios);
+static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
static int write(struct tty_struct *tty, const unsigned char *buf, int count);
static void put_char(struct tty_struct *tty, unsigned char ch);
@@ -816,7 +816,7 @@ static void hangup(struct tty_struct *tty)
wake_up_interruptible(&info->open_wait);
}
-static void set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct slgt_info *info = tty->driver_data;
unsigned long flags;
@@ -3546,6 +3546,8 @@ static int __init slgt_init(void)
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver->init_termios.c_ispeed = 9600;
+ serial_driver->init_termios.c_ospeed = 9600;
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &ops);
if ((rc = tty_register_driver(serial_driver)) < 0) {
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 20a96ef250b..8f4d67afe5b 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -519,7 +519,7 @@ static struct tty_driver *serial_driver;
static int open(struct tty_struct *tty, struct file * filp);
static void close(struct tty_struct *tty, struct file * filp);
static void hangup(struct tty_struct *tty);
-static void set_termios(struct tty_struct *tty, struct termios *old_termios);
+static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
static int write(struct tty_struct *tty, const unsigned char *buf, int count);
static void put_char(struct tty_struct *tty, unsigned char ch);
@@ -918,7 +918,7 @@ static void hangup(struct tty_struct *tty)
/* Set new termios settings
*/
-static void set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
unsigned long flags;
@@ -2730,7 +2730,7 @@ static int startup(SLMP_INFO * info)
return 0;
if (!info->tx_buf) {
- info->tx_buf = (unsigned char *)kmalloc(info->max_frame_size, GFP_KERNEL);
+ info->tx_buf = kmalloc(info->max_frame_size, GFP_KERNEL);
if (!info->tx_buf) {
printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n",
__FILE__,__LINE__,info->device_name);
@@ -3798,7 +3798,7 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
{
SLMP_INFO *info;
- info = (SLMP_INFO *)kmalloc(sizeof(SLMP_INFO),
+ info = kmalloc(sizeof(SLMP_INFO),
GFP_KERNEL);
if (!info) {
@@ -4034,6 +4034,8 @@ static int __init synclinkmp_init(void)
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver->init_termios.c_ispeed = 9600;
+ serial_driver->init_termios.c_ospeed = 9600;
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &ops);
if ((rc = tty_register_driver(serial_driver)) < 0) {
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 05810c8d20b..7fd3cd5ddf2 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -41,7 +41,34 @@
#include <asm/irq_regs.h>
/* Whether we react on sysrq keys or just ignore them */
-int sysrq_enabled = 1;
+int __read_mostly __sysrq_enabled = 1;
+
+static int __read_mostly sysrq_always_enabled;
+
+int sysrq_on(void)
+{
+ return __sysrq_enabled || sysrq_always_enabled;
+}
+
+/*
+ * A value of 1 means 'all', other nonzero values are an op mask:
+ */
+static inline int sysrq_on_mask(int mask)
+{
+ return sysrq_always_enabled || __sysrq_enabled == 1 ||
+ (__sysrq_enabled & mask);
+}
+
+static int __init sysrq_always_enabled_setup(char *str)
+{
+ sysrq_always_enabled = 1;
+ printk(KERN_INFO "debug: sysrq always enabled.\n");
+
+ return 1;
+}
+
+__setup("sysrq_always_enabled", sysrq_always_enabled_setup);
+
static void sysrq_handle_loglevel(int key, struct tty_struct *tty)
{
@@ -188,7 +215,7 @@ static void sysrq_handle_showstate_blocked(int key, struct tty_struct *tty)
}
static struct sysrq_key_op sysrq_showstate_blocked_op = {
.handler = sysrq_handle_showstate_blocked,
- .help_msg = "showBlockedTasks",
+ .help_msg = "shoW-blocked-tasks",
.action_msg = "Show Blocked State",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
@@ -288,15 +315,16 @@ static struct sysrq_key_op *sysrq_key_table[36] = {
&sysrq_loglevel_op, /* 9 */
/*
- * Don't use for system provided sysrqs, it is handled specially on
- * sparc and will never arrive
+ * a: Don't use for system provided sysrqs, it is handled specially on
+ * sparc and will never arrive.
*/
NULL, /* a */
&sysrq_reboot_op, /* b */
- &sysrq_crashdump_op, /* c */
+ &sysrq_crashdump_op, /* c & ibm_emac driver debug */
&sysrq_showlocks_op, /* d */
&sysrq_term_op, /* e */
&sysrq_moom_op, /* f */
+ /* g: May be registered by ppc for kgdb */
NULL, /* g */
NULL, /* h */
&sysrq_kill_op, /* i */
@@ -305,18 +333,19 @@ static struct sysrq_key_op *sysrq_key_table[36] = {
NULL, /* l */
&sysrq_showmem_op, /* m */
&sysrq_unrt_op, /* n */
- /* This will often be registered as 'Off' at init time */
+ /* o: This will often be registered as 'Off' at init time */
NULL, /* o */
&sysrq_showregs_op, /* p */
NULL, /* q */
- &sysrq_unraw_op, /* r */
+ &sysrq_unraw_op, /* r */
&sysrq_sync_op, /* s */
&sysrq_showstate_op, /* t */
&sysrq_mountro_op, /* u */
- /* May be assigned at init time by SMP VOYAGER */
+ /* v: May be registered at init time by SMP VOYAGER */
NULL, /* v */
- NULL, /* w */
- &sysrq_showstate_blocked_op, /* x */
+ &sysrq_showstate_blocked_op, /* w */
+ /* x: May be registered on ppc/powerpc for xmon */
+ NULL, /* x */
NULL, /* y */
NULL /* z */
};
@@ -379,8 +408,7 @@ void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
* Should we check for enabled operations (/proc/sysrq-trigger
* should not) and is the invoked operation enabled?
*/
- if (!check_mask || sysrq_enabled == 1 ||
- (sysrq_enabled & op_p->enable_mask)) {
+ if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
printk("%s\n", op_p->action_msg);
console_loglevel = orig_log_level;
op_p->handler(key, tty);
@@ -414,9 +442,8 @@ void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
*/
void handle_sysrq(int key, struct tty_struct *tty)
{
- if (!sysrq_enabled)
- return;
- __handle_sysrq(key, tty, 1);
+ if (sysrq_on())
+ __handle_sysrq(key, tty, 1);
}
EXPORT_SYMBOL(handle_sysrq);
diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c
index bb1bad4c18f..4c431cb7cf1 100644
--- a/drivers/char/tb0219.c
+++ b/drivers/char/tb0219.c
@@ -164,7 +164,7 @@ static ssize_t tanbac_tb0219_read(struct file *file, char __user *buf, size_t le
unsigned int minor;
char value;
- minor = iminor(file->f_dentry->d_inode);
+ minor = iminor(file->f_path.dentry->d_inode);
switch (minor) {
case 0:
value = get_led();
@@ -200,7 +200,7 @@ static ssize_t tanbac_tb0219_write(struct file *file, const char __user *data,
int retval = 0;
char c;
- minor = iminor(file->f_dentry->d_inode);
+ minor = iminor(file->f_path.dentry->d_inode);
switch (minor) {
case 0:
type = TYPE_LED;
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 9df0ca1be0e..47fb20f6969 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -285,7 +285,7 @@ static ssize_t
tipar_write (struct file *file, const char __user *buf, size_t count,
loff_t * ppos)
{
- unsigned int minor = iminor(file->f_dentry->d_inode) - TIPAR_MINOR;
+ unsigned int minor = iminor(file->f_path.dentry->d_inode) - TIPAR_MINOR;
ssize_t n;
parport_claim_or_block(table[minor].dev);
@@ -313,7 +313,7 @@ static ssize_t
tipar_read(struct file *file, char __user *buf, size_t count, loff_t * ppos)
{
int b = 0;
- unsigned int minor = iminor(file->f_dentry->d_inode) - TIPAR_MINOR;
+ unsigned int minor = iminor(file->f_path.dentry->d_inode) - TIPAR_MINOR;
ssize_t retval = 0;
ssize_t n = 0;
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index 244d30a03fe..4fac2bdf621 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -186,6 +186,7 @@ static int got_event; /* if events processing have been done */
static void switchover_timeout(unsigned long data);
static struct timer_list switchover_timer =
TIMER_INITIALIZER(switchover_timeout , 0, 0);
+static unsigned long tlclk_timer_data;
static struct tlclk_alarms *alarm_events;
@@ -197,10 +198,19 @@ static irqreturn_t tlclk_interrupt(int irq, void *dev_id);
static DECLARE_WAIT_QUEUE_HEAD(wq);
+static unsigned long useflags;
+static DEFINE_MUTEX(tlclk_mutex);
+
static int tlclk_open(struct inode *inode, struct file *filp)
{
int result;
+ if (test_and_set_bit(0, &useflags))
+ return -EBUSY;
+ /* this legacy device is always one per system and it doesn't
+ * know how to handle multiple concurrent clients.
+ */
+
/* Make sure there is no interrupt pending while
* initialising interrupt handler */
inb(TLCLK_REG6);
@@ -221,6 +231,7 @@ static int tlclk_open(struct inode *inode, struct file *filp)
static int tlclk_release(struct inode *inode, struct file *filp)
{
free_irq(telclk_interrupt, tlclk_interrupt);
+ clear_bit(0, &useflags);
return 0;
}
@@ -230,26 +241,25 @@ static ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count,
{
if (count < sizeof(struct tlclk_alarms))
return -EIO;
+ if (mutex_lock_interruptible(&tlclk_mutex))
+ return -EINTR;
+
wait_event_interruptible(wq, got_event);
- if (copy_to_user(buf, alarm_events, sizeof(struct tlclk_alarms)))
+ if (copy_to_user(buf, alarm_events, sizeof(struct tlclk_alarms))) {
+ mutex_unlock(&tlclk_mutex);
return -EFAULT;
+ }
memset(alarm_events, 0, sizeof(struct tlclk_alarms));
got_event = 0;
+ mutex_unlock(&tlclk_mutex);
return sizeof(struct tlclk_alarms);
}
-static ssize_t tlclk_write(struct file *filp, const char __user *buf, size_t count,
- loff_t *f_pos)
-{
- return 0;
-}
-
static const struct file_operations tlclk_fops = {
.read = tlclk_read,
- .write = tlclk_write,
.open = tlclk_open,
.release = tlclk_release,
@@ -540,7 +550,7 @@ static ssize_t store_select_amcb1_transmit_clock(struct device *d,
SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x7);
switch (val) {
case CLK_8_592MHz:
- SET_PORT_BITS(TLCLK_REG0, 0xfc, 1);
+ SET_PORT_BITS(TLCLK_REG0, 0xfc, 2);
break;
case CLK_11_184MHz:
SET_PORT_BITS(TLCLK_REG0, 0xfc, 0);
@@ -549,7 +559,7 @@ static ssize_t store_select_amcb1_transmit_clock(struct device *d,
SET_PORT_BITS(TLCLK_REG0, 0xfc, 3);
break;
case CLK_44_736MHz:
- SET_PORT_BITS(TLCLK_REG0, 0xfc, 2);
+ SET_PORT_BITS(TLCLK_REG0, 0xfc, 1);
break;
}
} else
@@ -807,8 +817,6 @@ static int __init tlclk_init(void)
&tlclk_attribute_group);
if (ret) {
printk(KERN_ERR "tlclk: failed to create sysfs device attributes.\n");
- sysfs_remove_group(&tlclk_device->dev.kobj,
- &tlclk_attribute_group);
goto out5;
}
@@ -841,11 +849,13 @@ static void __exit tlclk_cleanup(void)
static void switchover_timeout(unsigned long data)
{
- if ((data & 1)) {
- if ((inb(TLCLK_REG1) & 0x08) != (data & 0x08))
+ unsigned long flags = *(unsigned long *) data;
+
+ if ((flags & 1)) {
+ if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08))
alarm_events->switchover_primary++;
} else {
- if ((inb(TLCLK_REG1) & 0x08) != (data & 0x08))
+ if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08))
alarm_events->switchover_secondary++;
}
@@ -903,8 +913,9 @@ static irqreturn_t tlclk_interrupt(int irq, void *dev_id)
/* TIMEOUT in ~10ms */
switchover_timer.expires = jiffies + msecs_to_jiffies(10);
- switchover_timer.data = inb(TLCLK_REG1);
- add_timer(&switchover_timer);
+ tlclk_timer_data = inb(TLCLK_REG1);
+ switchover_timer.data = (unsigned long) &tlclk_timer_data;
+ mod_timer(&switchover_timer, switchover_timer.expires);
} else {
got_event = 1;
wake_up(&wq);
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index a611972024e..7fca5f470be 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -372,10 +372,8 @@ static int read_log(struct tpm_bios_log *log)
}
/* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
- status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
- ACPI_LOGICAL_ADDRESSING,
- (struct acpi_table_header **)
- &buff);
+ status = acpi_get_table(ACPI_SIG_TCPA, 1,
+ (struct acpi_table_header **)&buff);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
@@ -409,7 +407,7 @@ static int read_log(struct tpm_bios_log *log)
log->bios_event_log_end = log->bios_event_log + len;
- acpi_os_map_memory(start, len, (void *) &virt);
+ virt = acpi_os_map_memory(start, len);
memcpy(log->bios_event_log, virt, len);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index b3cfc8bc613..47a6eacb10b 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -109,13 +109,15 @@
#define TTY_PARANOIA_CHECK 1
#define CHECK_TTY_COUNT 1
-struct termios tty_std_termios = { /* for the benefit of tty drivers */
+struct ktermios tty_std_termios = { /* for the benefit of tty drivers */
.c_iflag = ICRNL | IXON,
.c_oflag = OPOST | ONLCR,
.c_cflag = B38400 | CS8 | CREAD | HUPCL,
.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN,
- .c_cc = INIT_C_CC
+ .c_cc = INIT_C_CC,
+ .c_ispeed = 38400,
+ .c_ospeed = 38400
};
EXPORT_SYMBOL(tty_std_termios);
@@ -126,7 +128,7 @@ EXPORT_SYMBOL(tty_std_termios);
LIST_HEAD(tty_drivers); /* linked list of tty drivers */
-/* Semaphore to protect creating and releasing a tty. This is shared with
+/* Mutex 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);
@@ -250,7 +252,7 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
"!= #fd's(%d) in %s\n",
tty->name, tty->count, count, routine);
return count;
- }
+ }
#endif
return 0;
}
@@ -259,18 +261,6 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
* Tty buffer allocation management
*/
-
-/**
- * tty_buffer_free_all - free buffers used by a tty
- * @tty: tty to free from
- *
- * Remove all the buffers pending on a tty whether queued with data
- * or in the free ring. Must be called when the tty is no longer in use
- *
- * Locking: none
- */
-
-
/**
* tty_buffer_free_all - free buffers used by a tty
* @tty: tty to free from
@@ -614,7 +604,7 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
* they are not on hot paths so a little discipline won't do
* any harm.
*
- * Locking: takes termios_sem
+ * Locking: takes termios_mutex
*/
static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
@@ -915,7 +905,7 @@ static void tty_ldisc_enable(struct tty_struct *tty)
* context.
*
* Locking: takes tty_ldisc_lock.
- * called functions take termios_sem
+ * called functions take termios_mutex
*/
static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
@@ -1251,6 +1241,22 @@ void tty_ldisc_flush(struct tty_struct *tty)
}
EXPORT_SYMBOL_GPL(tty_ldisc_flush);
+
+/**
+ * tty_reset_termios - reset terminal state
+ * @tty: tty to reset
+ *
+ * Restore a terminal to the driver default state
+ */
+
+static void tty_reset_termios(struct tty_struct *tty)
+{
+ mutex_lock(&tty->termios_mutex);
+ *tty->termios = tty->driver->init_termios;
+ tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+ tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+ mutex_unlock(&tty->termios_mutex);
+}
/**
* do_tty_hangup - actual handler for hangup events
@@ -1267,12 +1273,12 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
*
* Locking:
* BKL
- * redirect lock for undoing redirection
- * file list lock for manipulating list of ttys
- * tty_ldisc_lock from called functions
- * termios_sem resetting termios data
- * tasklist_lock to walk task list for hangup event
- *
+ * redirect lock for undoing redirection
+ * file list lock for manipulating list of ttys
+ * tty_ldisc_lock from called functions
+ * termios_mutex resetting termios data
+ * tasklist_lock to walk task list for hangup event
+ * ->siglock to protect ->signal/->sighand
*/
static void do_tty_hangup(struct work_struct *work)
{
@@ -1339,11 +1345,7 @@ static void do_tty_hangup(struct work_struct *work)
* N_TTY.
*/
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
- {
- mutex_lock(&tty->termios_mutex);
- *tty->termios = tty->driver->init_termios;
- mutex_unlock(&tty->termios_mutex);
- }
+ tty_reset_termios(tty);
/* Defer ldisc switch */
/* tty_deferred_ldisc_switch(N_TTY);
@@ -1354,14 +1356,18 @@ static void do_tty_hangup(struct work_struct *work)
read_lock(&tasklist_lock);
if (tty->session > 0) {
do_each_task_pid(tty->session, PIDTYPE_SID, p) {
+ spin_lock_irq(&p->sighand->siglock);
if (p->signal->tty == tty)
p->signal->tty = NULL;
- if (!p->signal->leader)
+ if (!p->signal->leader) {
+ spin_unlock_irq(&p->sighand->siglock);
continue;
- group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
- group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
+ }
+ __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+ __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
if (tty->pgrp > 0)
p->signal->tty_old_pgrp = tty->pgrp;
+ spin_unlock_irq(&p->sighand->siglock);
} while_each_task_pid(tty->session, PIDTYPE_SID, p);
}
read_unlock(&tasklist_lock);
@@ -1453,6 +1459,14 @@ int tty_hung_up_p(struct file * filp)
EXPORT_SYMBOL(tty_hung_up_p);
+static void session_clear_tty(pid_t session)
+{
+ struct task_struct *p;
+ do_each_task_pid(session, PIDTYPE_SID, p) {
+ proc_clear_tty(p);
+ } while_each_task_pid(session, PIDTYPE_SID, p);
+}
+
/**
* disassociate_ctty - disconnect controlling tty
* @on_exit: true if exiting so need to "hang up" the session
@@ -1469,31 +1483,35 @@ EXPORT_SYMBOL(tty_hung_up_p);
* The argument on_exit is set to 1 if called when a process is
* exiting; it is 0 if called by the ioctl TIOCNOTTY.
*
- * Locking: tty_mutex is taken to protect current->signal->tty
+ * Locking:
* BKL is taken for hysterical raisins
- * Tasklist lock is taken (under tty_mutex) to walk process
- * lists for the session.
+ * tty_mutex is taken to protect tty
+ * ->siglock is taken to protect ->signal/->sighand
+ * tasklist_lock is taken to walk process list for sessions
+ * ->siglock is taken to protect ->signal/->sighand
*/
void disassociate_ctty(int on_exit)
{
struct tty_struct *tty;
- struct task_struct *p;
int tty_pgrp = -1;
+ int session;
lock_kernel();
mutex_lock(&tty_mutex);
- tty = current->signal->tty;
+ tty = get_current_tty();
if (tty) {
tty_pgrp = tty->pgrp;
mutex_unlock(&tty_mutex);
+ /* XXX: here we race, there is nothing protecting tty */
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
tty_vhangup(tty);
} else {
- if (current->signal->tty_old_pgrp) {
- kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit);
- kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit);
+ pid_t old_pgrp = current->signal->tty_old_pgrp;
+ if (old_pgrp) {
+ kill_pg(old_pgrp, SIGHUP, on_exit);
+ kill_pg(old_pgrp, SIGCONT, on_exit);
}
mutex_unlock(&tty_mutex);
unlock_kernel();
@@ -1505,19 +1523,29 @@ void disassociate_ctty(int on_exit)
kill_pg(tty_pgrp, SIGCONT, on_exit);
}
- /* Must lock changes to tty_old_pgrp */
- mutex_lock(&tty_mutex);
+ spin_lock_irq(&current->sighand->siglock);
current->signal->tty_old_pgrp = 0;
- tty->session = 0;
- tty->pgrp = -1;
+ session = process_session(current);
+ spin_unlock_irq(&current->sighand->siglock);
+
+ mutex_lock(&tty_mutex);
+ /* It is possible that do_tty_hangup has free'd this tty */
+ tty = get_current_tty();
+ if (tty) {
+ tty->session = 0;
+ tty->pgrp = 0;
+ } else {
+#ifdef TTY_DEBUG_HANGUP
+ printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
+ " = NULL", tty);
+#endif
+ }
+ mutex_unlock(&tty_mutex);
/* Now clear signal->tty under the lock */
read_lock(&tasklist_lock);
- do_each_task_pid(current->signal->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
- } while_each_task_pid(current->signal->session, PIDTYPE_SID, p);
+ session_clear_tty(session);
read_unlock(&tasklist_lock);
- mutex_unlock(&tty_mutex);
unlock_kernel();
}
@@ -1615,7 +1643,7 @@ static ssize_t tty_read(struct file * file, char __user * buf, size_t count,
struct tty_ldisc *ld;
tty = (struct tty_struct *)file->private_data;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (tty_paranoia_check(tty, inode, "tty_read"))
return -EIO;
if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
@@ -1718,7 +1746,7 @@ static inline ssize_t do_tty_write(
cond_resched();
}
if (written) {
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
inode->i_mtime = current_fs_time(inode->i_sb);
ret = written;
}
@@ -1749,7 +1777,7 @@ static ssize_t tty_write(struct file * file, const char __user * buf, size_t cou
loff_t *ppos)
{
struct tty_struct * tty;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
ssize_t ret;
struct tty_ldisc *ld;
@@ -1856,8 +1884,8 @@ static int init_dev(struct tty_driver *driver, int idx,
struct tty_struct **ret_tty)
{
struct tty_struct *tty, *o_tty;
- struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
- struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
+ struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
+ struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
int retval = 0;
/* check whether we're reopening an existing tty */
@@ -1904,7 +1932,7 @@ static int init_dev(struct tty_driver *driver, int idx,
}
if (!*tp_loc) {
- tp = (struct termios *) kmalloc(sizeof(struct termios),
+ tp = (struct ktermios *) kmalloc(sizeof(struct ktermios),
GFP_KERNEL);
if (!tp)
goto free_mem_out;
@@ -1912,11 +1940,11 @@ static int init_dev(struct tty_driver *driver, int idx,
}
if (!*ltp_loc) {
- ltp = (struct termios *) kmalloc(sizeof(struct termios),
+ ltp = (struct ktermios *) kmalloc(sizeof(struct ktermios),
GFP_KERNEL);
if (!ltp)
goto free_mem_out;
- memset(ltp, 0, sizeof(struct termios));
+ memset(ltp, 0, sizeof(struct ktermios));
}
if (driver->type == TTY_DRIVER_TYPE_PTY) {
@@ -1937,19 +1965,19 @@ static int init_dev(struct tty_driver *driver, int idx,
}
if (!*o_tp_loc) {
- o_tp = (struct termios *)
- kmalloc(sizeof(struct termios), GFP_KERNEL);
+ o_tp = (struct ktermios *)
+ kmalloc(sizeof(struct ktermios), GFP_KERNEL);
if (!o_tp)
goto free_mem_out;
*o_tp = driver->other->init_termios;
}
if (!*o_ltp_loc) {
- o_ltp = (struct termios *)
- kmalloc(sizeof(struct termios), GFP_KERNEL);
+ o_ltp = (struct ktermios *)
+ kmalloc(sizeof(struct ktermios), GFP_KERNEL);
if (!o_ltp)
goto free_mem_out;
- memset(o_ltp, 0, sizeof(struct termios));
+ memset(o_ltp, 0, sizeof(struct ktermios));
}
/*
@@ -1988,6 +2016,9 @@ static int init_dev(struct tty_driver *driver, int idx,
*ltp_loc = ltp;
tty->termios = *tp_loc;
tty->termios_locked = *ltp_loc;
+ /* Compatibility until drivers always set this */
+ tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+ tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
driver->refcount++;
tty->count++;
@@ -2090,7 +2121,7 @@ release_mem_out:
static void release_mem(struct tty_struct *tty, int idx)
{
struct tty_struct *o_tty;
- struct termios *tp;
+ struct ktermios *tp;
int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
if ((o_tty = tty->link) != NULL) {
@@ -2156,7 +2187,7 @@ static void release_dev(struct file * filp)
unsigned long flags;
tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "release_dev"))
+ if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "release_dev"))
return;
check_tty_count(tty, "release_dev");
@@ -2337,16 +2368,10 @@ static void release_dev(struct file * filp)
* tty.
*/
if (tty_closing || o_tty_closing) {
- struct task_struct *p;
-
read_lock(&tasklist_lock);
- do_each_task_pid(tty->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
- } while_each_task_pid(tty->session, PIDTYPE_SID, p);
+ session_clear_tty(tty->session);
if (o_tty)
- do_each_task_pid(o_tty->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
- } while_each_task_pid(o_tty->session, PIDTYPE_SID, p);
+ session_clear_tty(o_tty->session);
read_unlock(&tasklist_lock);
}
@@ -2443,9 +2468,9 @@ static void release_dev(struct file * filp)
* The termios state of a pty is reset on first open so that
* settings don't persist across reuse.
*
- * Locking: tty_mutex protects current->signal->tty, get_tty_driver and
- * init_dev work. tty->count should protect the rest.
- * task_lock is held to update task details for sessions
+ * Locking: tty_mutex protects tty, get_tty_driver and init_dev work.
+ * tty->count should protect the rest.
+ * ->siglock protects ->signal/->sighand
*/
static int tty_open(struct inode * inode, struct file * filp)
@@ -2467,12 +2492,13 @@ retry_open:
mutex_lock(&tty_mutex);
if (device == MKDEV(TTYAUX_MAJOR,0)) {
- if (!current->signal->tty) {
+ tty = get_current_tty();
+ if (!tty) {
mutex_unlock(&tty_mutex);
return -ENXIO;
}
- driver = current->signal->tty->driver;
- index = current->signal->tty->index;
+ driver = tty->driver;
+ index = tty->index;
filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
/* noctty = 1; */
goto got_driver;
@@ -2547,17 +2573,16 @@ got_driver:
filp->f_op = &tty_fops;
goto retry_open;
}
+
+ mutex_lock(&tty_mutex);
+ spin_lock_irq(&current->sighand->siglock);
if (!noctty &&
current->signal->leader &&
!current->signal->tty &&
- tty->session == 0) {
- task_lock(current);
- current->signal->tty = tty;
- task_unlock(current);
- current->signal->tty_old_pgrp = 0;
- tty->session = current->signal->session;
- tty->pgrp = process_group(current);
- }
+ tty->session == 0)
+ __proc_set_tty(current, tty);
+ spin_unlock_irq(&current->sighand->siglock);
+ mutex_unlock(&tty_mutex);
return 0;
}
@@ -2672,7 +2697,7 @@ static unsigned int tty_poll(struct file * filp, poll_table * wait)
int ret = 0;
tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_poll"))
+ if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
return 0;
ld = tty_ldisc_ref_wait(tty);
@@ -2688,7 +2713,7 @@ static int tty_fasync(int fd, struct file * filp, int on)
int retval;
tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_fasync"))
+ if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
return 0;
retval = fasync_helper(fd, filp, on, &tty->fasync);
@@ -2747,7 +2772,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
*
* Copies the kernel idea of the window size into the user buffer.
*
- * Locking: tty->termios_sem is taken to ensure the winsize data
+ * Locking: tty->termios_mutex is taken to ensure the winsize data
* is consistent.
*/
@@ -2774,8 +2799,8 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg)
* Locking:
* 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
+ * The tty->termios_mutex is used to ensure we don't double
+ * resize and get confused. Lock order - tty->termios_mutex before
* console sem
*/
@@ -2880,25 +2905,28 @@ static int fionbio(struct file *file, int __user *p)
* leader to set this tty as the controlling tty for the session.
*
* Locking:
- * Takes tasklist lock internally to walk sessions
- * Takes task_lock() when updating signal->tty
* Takes tty_mutex() to protect tty instance
- *
+ * Takes tasklist_lock internally to walk sessions
+ * Takes ->siglock() when updating signal->tty
*/
static int tiocsctty(struct tty_struct *tty, int arg)
{
- struct task_struct *p;
-
+ int ret = 0;
if (current->signal->leader &&
- (current->signal->session == tty->session))
- return 0;
+ (process_session(current) == tty->session))
+ return ret;
+
+ mutex_lock(&tty_mutex);
/*
* The process must be a session leader and
* not have a controlling tty already.
*/
- if (!current->signal->leader || current->signal->tty)
- return -EPERM;
+ if (!current->signal->leader || current->signal->tty) {
+ ret = -EPERM;
+ goto unlock;
+ }
+
if (tty->session > 0) {
/*
* This tty is already the controlling
@@ -2908,24 +2936,18 @@ static int tiocsctty(struct tty_struct *tty, int arg)
/*
* Steal it away
*/
-
read_lock(&tasklist_lock);
- do_each_task_pid(tty->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
- } while_each_task_pid(tty->session, PIDTYPE_SID, p);
+ session_clear_tty(tty->session);
read_unlock(&tasklist_lock);
- } else
- return -EPERM;
+ } else {
+ ret = -EPERM;
+ goto unlock;
+ }
}
- mutex_lock(&tty_mutex);
- task_lock(current);
- current->signal->tty = tty;
- task_unlock(current);
+ proc_set_tty(current, tty);
+unlock:
mutex_unlock(&tty_mutex);
- current->signal->tty_old_pgrp = 0;
- tty->session = current->signal->session;
- tty->pgrp = process_group(current);
- return 0;
+ return ret;
}
/**
@@ -2937,7 +2959,7 @@ static int tiocsctty(struct tty_struct *tty, int arg)
* Obtain the process group of the tty. If there is no process group
* return an error.
*
- * Locking: none. Reference to ->signal->tty is safe.
+ * Locking: none. Reference to current->signal->tty is safe.
*/
static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
@@ -2974,13 +2996,13 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
return retval;
if (!current->signal->tty ||
(current->signal->tty != real_tty) ||
- (real_tty->session != current->signal->session))
+ (real_tty->session != process_session(current)))
return -ENOTTY;
if (get_user(pgrp, p))
return -EFAULT;
if (pgrp < 0)
return -EINVAL;
- if (session_of_pgrp(pgrp) != current->signal->session)
+ if (session_of_pgrp(pgrp) != process_session(current))
return -EPERM;
real_tty->pgrp = pgrp;
return 0;
@@ -2995,7 +3017,7 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
* Obtain the session id of the tty. If there is no session
* return an error.
*
- * Locking: none. Reference to ->signal->tty is safe.
+ * Locking: none. Reference to current->signal->tty is safe.
*/
static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
@@ -3214,14 +3236,11 @@ int tty_ioctl(struct inode * inode, struct file * file,
clear_bit(TTY_EXCLUSIVE, &tty->flags);
return 0;
case TIOCNOTTY:
- /* FIXME: taks lock or tty_mutex ? */
if (current->signal->tty != tty)
return -ENOTTY;
if (current->signal->leader)
disassociate_ctty(0);
- task_lock(current);
- current->signal->tty = NULL;
- task_unlock(current);
+ proc_clear_tty(current);
return 0;
case TIOCSCTTY:
return tiocsctty(tty, arg);
@@ -3316,18 +3335,13 @@ static void __do_SAK(struct work_struct *work)
int session;
int i;
struct file *filp;
- struct tty_ldisc *disc;
struct fdtable *fdt;
if (!tty)
return;
- session = tty->session;
+ session = tty->session;
- /* We don't want an ldisc switch during this */
- disc = tty_ldisc_ref(tty);
- if (disc && disc->flush_buffer)
- disc->flush_buffer(tty);
- tty_ldisc_deref(disc);
+ tty_ldisc_flush(tty);
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
@@ -3336,7 +3350,7 @@ static void __do_SAK(struct work_struct *work)
/* Kill the entire session */
do_each_task_pid(session, PIDTYPE_SID, p) {
printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): p->signal->session==tty->session\n",
+ " (%s): process_session(p)==tty->session\n",
p->pid, p->comm);
send_sig(SIGKILL, p, 1);
} while_each_task_pid(session, PIDTYPE_SID, p);
@@ -3346,7 +3360,7 @@ static void __do_SAK(struct work_struct *work)
do_each_thread(g, p) {
if (p->signal->tty == tty) {
printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): p->signal->session==tty->session\n",
+ " (%s): process_session(p)==tty->session\n",
p->pid, p->comm);
send_sig(SIGKILL, p, 1);
continue;
@@ -3456,84 +3470,6 @@ static void flush_to_ldisc(struct work_struct *work)
tty_ldisc_deref(disc);
}
-/*
- * Routine which returns the baud rate of the tty
- *
- * Note that the baud_table needs to be kept in sync with the
- * include/asm/termbits.h file.
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800,
-#ifdef __sparc__
- 76800, 153600, 307200, 614400, 921600
-#else
- 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
- 2500000, 3000000, 3500000, 4000000
-#endif
-};
-
-static int n_baud_table = ARRAY_SIZE(baud_table);
-
-/**
- * tty_termios_baud_rate
- * @termios: termios structure
- *
- * Convert termios baud rate data into a speed. This should be called
- * with the termios lock held if this termios is a terminal termios
- * structure. May change the termios data.
- *
- * Locking: none
- */
-
-int tty_termios_baud_rate(struct termios *termios)
-{
- unsigned int cbaud;
-
- cbaud = termios->c_cflag & CBAUD;
-
- if (cbaud & CBAUDEX) {
- cbaud &= ~CBAUDEX;
-
- if (cbaud < 1 || cbaud + 15 > n_baud_table)
- termios->c_cflag &= ~CBAUDEX;
- else
- cbaud += 15;
- }
- return baud_table[cbaud];
-}
-
-EXPORT_SYMBOL(tty_termios_baud_rate);
-
-/**
- * tty_get_baud_rate - get tty bit rates
- * @tty: tty to query
- *
- * Returns the baud rate as an integer for this terminal. The
- * termios lock must be held by the caller and the terminal bit
- * flags may be updated.
- *
- * Locking: none
- */
-
-int tty_get_baud_rate(struct tty_struct *tty)
-{
- int baud = tty_termios_baud_rate(tty->termios);
-
- if (baud == 38400 && tty->alt_speed) {
- if (!tty->warned) {
- printk(KERN_WARNING "Use of setserial/setrocket to "
- "set SPD_* flags is deprecated\n");
- tty->warned = 1;
- }
- baud = tty->alt_speed;
- }
-
- return baud;
-}
-
-EXPORT_SYMBOL(tty_get_baud_rate);
-
/**
* tty_flip_buffer_push - terminal
* @tty: tty to push
@@ -3756,8 +3692,8 @@ int tty_register_driver(struct tty_driver *driver)
if (p) {
driver->ttys = (struct tty_struct **)p;
- driver->termios = (struct termios **)(p + driver->num);
- driver->termios_locked = (struct termios **)(p + driver->num * 2);
+ driver->termios = (struct ktermios **)(p + driver->num);
+ driver->termios_locked = (struct ktermios **)(p + driver->num * 2);
} else {
driver->ttys = NULL;
driver->termios = NULL;
@@ -3796,7 +3732,7 @@ EXPORT_SYMBOL(tty_register_driver);
int tty_unregister_driver(struct tty_driver *driver)
{
int i;
- struct termios *tp;
+ struct ktermios *tp;
void *p;
if (driver->refcount)
@@ -3834,9 +3770,53 @@ int tty_unregister_driver(struct tty_driver *driver)
cdev_del(&driver->cdev);
return 0;
}
-
EXPORT_SYMBOL(tty_unregister_driver);
+dev_t tty_devnum(struct tty_struct *tty)
+{
+ return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
+}
+EXPORT_SYMBOL(tty_devnum);
+
+void proc_clear_tty(struct task_struct *p)
+{
+ spin_lock_irq(&p->sighand->siglock);
+ p->signal->tty = NULL;
+ spin_unlock_irq(&p->sighand->siglock);
+}
+EXPORT_SYMBOL(proc_clear_tty);
+
+void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+{
+ if (tty) {
+ tty->session = process_session(tsk);
+ tty->pgrp = process_group(tsk);
+ }
+ tsk->signal->tty = tty;
+ tsk->signal->tty_old_pgrp = 0;
+}
+
+void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+{
+ spin_lock_irq(&tsk->sighand->siglock);
+ __proc_set_tty(tsk, tty);
+ spin_unlock_irq(&tsk->sighand->siglock);
+}
+
+struct tty_struct *get_current_tty(void)
+{
+ struct tty_struct *tty;
+ WARN_ON_ONCE(!mutex_is_locked(&tty_mutex));
+ tty = current->signal->tty;
+ /*
+ * session->tty can be changed/cleared from under us, make sure we
+ * issue the load. The obtained pointer, when not NULL, is valid as
+ * long as we hold tty_mutex.
+ */
+ barrier();
+ return tty;
+}
+EXPORT_SYMBOL_GPL(get_current_tty);
/*
* Initialize the console device. This is called *early*, so
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 3b6fa7b0be8..dee47f40c6a 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -36,6 +36,7 @@
#define TERMIOS_FLUSH 1
#define TERMIOS_WAIT 2
#define TERMIOS_TERMIO 4
+#define TERMIOS_OLD 8
/**
@@ -84,9 +85,9 @@ stop_waiting:
EXPORT_SYMBOL(tty_wait_until_sent);
-static void unset_locked_termios(struct termios *termios,
- struct termios *old,
- struct termios *locked)
+static void unset_locked_termios(struct ktermios *termios,
+ struct ktermios *old,
+ struct ktermios *locked)
{
int i;
@@ -105,8 +106,204 @@ static void unset_locked_termios(struct termios *termios,
for (i=0; i < NCCS; i++)
termios->c_cc[i] = locked->c_cc[i] ?
old->c_cc[i] : termios->c_cc[i];
+ /* FIXME: What should we do for i/ospeed */
}
+/*
+ * Routine which returns the baud rate of the tty
+ *
+ * Note that the baud_table needs to be kept in sync with the
+ * include/asm/termbits.h file.
+ */
+static const speed_t baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 230400, 460800,
+#ifdef __sparc__
+ 76800, 153600, 307200, 614400, 921600
+#else
+ 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
+ 2500000, 3000000, 3500000, 4000000
+#endif
+};
+
+#ifndef __sparc__
+static const tcflag_t baud_bits[] = {
+ B0, B50, B75, B110, B134, B150, B200, B300, B600,
+ B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+ B57600, B115200, B230400, B460800, B500000, B576000,
+ B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
+ B3000000, B3500000, B4000000
+};
+#else
+static const tcflag_t baud_bits[] = {
+ B0, B50, B75, B110, B134, B150, B200, B300, B600,
+ B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+ B57600, B115200, B230400, B460800, B76800, B153600,
+ B307200, B614400, B921600
+};
+#endif
+
+static int n_baud_table = ARRAY_SIZE(baud_table);
+
+/**
+ * tty_termios_baud_rate
+ * @termios: termios structure
+ *
+ * Convert termios baud rate data into a speed. This should be called
+ * with the termios lock held if this termios is a terminal termios
+ * structure. May change the termios data. Device drivers can call this
+ * function but should use ->c_[io]speed directly as they are updated.
+ *
+ * Locking: none
+ */
+
+speed_t tty_termios_baud_rate(struct ktermios *termios)
+{
+ unsigned int cbaud;
+
+ cbaud = termios->c_cflag & CBAUD;
+
+#ifdef BOTHER
+ /* Magic token for arbitary speed via c_ispeed/c_ospeed */
+ if (cbaud == BOTHER)
+ return termios->c_ospeed;
+#endif
+ if (cbaud & CBAUDEX) {
+ cbaud &= ~CBAUDEX;
+
+ if (cbaud < 1 || cbaud + 15 > n_baud_table)
+ termios->c_cflag &= ~CBAUDEX;
+ else
+ cbaud += 15;
+ }
+ return baud_table[cbaud];
+}
+
+EXPORT_SYMBOL(tty_termios_baud_rate);
+
+/**
+ * tty_termios_input_baud_rate
+ * @termios: termios structure
+ *
+ * Convert termios baud rate data into a speed. This should be called
+ * with the termios lock held if this termios is a terminal termios
+ * structure. May change the termios data. Device drivers can call this
+ * function but should use ->c_[io]speed directly as they are updated.
+ *
+ * Locking: none
+ */
+
+speed_t tty_termios_input_baud_rate(struct ktermios *termios)
+{
+#ifdef IBSHIFT
+ unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
+
+ if (cbaud == B0)
+ return tty_termios_baud_rate(termios);
+
+ /* Magic token for arbitary speed via c_ispeed*/
+ if (cbaud == BOTHER)
+ return termios->c_ispeed;
+
+ if (cbaud & CBAUDEX) {
+ cbaud &= ~CBAUDEX;
+
+ if (cbaud < 1 || cbaud + 15 > n_baud_table)
+ termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
+ else
+ cbaud += 15;
+ }
+ return baud_table[cbaud];
+#else
+ return tty_termios_baud_rate(termios);
+#endif
+}
+
+EXPORT_SYMBOL(tty_termios_input_baud_rate);
+
+#ifdef BOTHER
+
+/**
+ * tty_termios_encode_baud_rate
+ * @termios: termios structure
+ * @ispeed: input speed
+ * @ospeed: output speed
+ *
+ * Encode the speeds set into the passed termios structure. This is
+ * used as a library helper for drivers os that they can report back
+ * the actual speed selected when it differs from the speed requested
+ *
+ * For now input and output speed must agree.
+ *
+ * Locking: Caller should hold termios lock. This is already held
+ * when calling this function from the driver termios handler.
+ */
+
+void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
+{
+ int i = 0;
+ int ifound = 0, ofound = 0;
+
+ termios->c_ispeed = ibaud;
+ termios->c_ospeed = obaud;
+
+ termios->c_cflag &= ~CBAUD;
+ /* Identical speed means no input encoding (ie B0 << IBSHIFT)*/
+ if (termios->c_ispeed == termios->c_ospeed)
+ ifound = 1;
+
+ do {
+ if (obaud == baud_table[i]) {
+ termios->c_cflag |= baud_bits[i];
+ ofound = 1;
+ /* So that if ibaud == obaud we don't set it */
+ continue;
+ }
+ if (ibaud == baud_table[i]) {
+ termios->c_cflag |= (baud_bits[i] << IBSHIFT);
+ ifound = 1;
+ }
+ }
+ while(++i < n_baud_table);
+ if (!ofound)
+ termios->c_cflag |= BOTHER;
+ if (!ifound)
+ termios->c_cflag |= (BOTHER << IBSHIFT);
+}
+
+EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
+
+#endif
+
+/**
+ * tty_get_baud_rate - get tty bit rates
+ * @tty: tty to query
+ *
+ * Returns the baud rate as an integer for this terminal. The
+ * termios lock must be held by the caller and the terminal bit
+ * flags may be updated.
+ *
+ * Locking: none
+ */
+
+speed_t tty_get_baud_rate(struct tty_struct *tty)
+{
+ speed_t baud = tty_termios_baud_rate(tty->termios);
+
+ if (baud == 38400 && tty->alt_speed) {
+ if (!tty->warned) {
+ printk(KERN_WARNING "Use of setserial/setrocket to "
+ "set SPD_* flags is deprecated\n");
+ tty->warned = 1;
+ }
+ baud = tty->alt_speed;
+ }
+
+ return baud;
+}
+
+EXPORT_SYMBOL(tty_get_baud_rate);
+
/**
* change_termios - update termios values
* @tty: tty to update
@@ -119,10 +316,10 @@ static void unset_locked_termios(struct termios *termios,
* Locking: termios_sem
*/
-static void change_termios(struct tty_struct * tty, struct termios * new_termios)
+static void change_termios(struct tty_struct * tty, struct ktermios * new_termios)
{
int canon_change;
- struct termios old_termios = *tty->termios;
+ struct ktermios old_termios = *tty->termios;
struct tty_ldisc *ld;
/*
@@ -195,23 +392,39 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios
static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
{
- struct termios tmp_termios;
+ struct ktermios tmp_termios;
struct tty_ldisc *ld;
int retval = tty_check_change(tty);
if (retval)
return retval;
+ memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
+
if (opt & TERMIOS_TERMIO) {
- memcpy(&tmp_termios, tty->termios, sizeof(struct termios));
if (user_termio_to_kernel_termios(&tmp_termios,
(struct termio __user *)arg))
return -EFAULT;
+#ifdef TCGETS2
+ } else if (opt & TERMIOS_OLD) {
+ if (user_termios_to_kernel_termios_1(&tmp_termios,
+ (struct termios __user *)arg))
+ return -EFAULT;
} else {
if (user_termios_to_kernel_termios(&tmp_termios,
- (struct termios __user *)arg))
+ (struct termios2 __user *)arg))
return -EFAULT;
}
+#else
+ } else if (user_termios_to_kernel_termios(&tmp_termios,
+ (struct termios __user *)arg))
+ return -EFAULT;
+#endif
+
+ /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed
+ so its unconditionally usable */
+ tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
+ tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
ld = tty_ldisc_ref(tty);
@@ -286,8 +499,8 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
struct sgttyb tmp;
mutex_lock(&tty->termios_mutex);
- tmp.sg_ispeed = 0;
- tmp.sg_ospeed = 0;
+ tmp.sg_ispeed = tty->termios->c_ispeed;
+ tmp.sg_ospeed = tty->termios->c_ospeed;
tmp.sg_erase = tty->termios->c_cc[VERASE];
tmp.sg_kill = tty->termios->c_cc[VKILL];
tmp.sg_flags = get_sgflags(tty);
@@ -296,7 +509,7 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
-static void set_sgflags(struct termios * termios, int flags)
+static void set_sgflags(struct ktermios * termios, int flags)
{
termios->c_iflag = ICRNL | IXON;
termios->c_oflag = 0;
@@ -337,7 +550,7 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
{
int retval;
struct sgttyb tmp;
- struct termios termios;
+ struct ktermios termios;
retval = tty_check_change(tty);
if (retval)
@@ -351,6 +564,10 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
set_sgflags(&termios, tmp.sg_flags);
+ /* Try and encode into Bfoo format */
+#ifdef BOTHER
+ tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed);
+#endif
mutex_unlock(&tty->termios_mutex);
change_termios(tty, &termios);
return 0;
@@ -481,16 +698,33 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
case TIOCSLTC:
return set_ltchars(real_tty, p);
#endif
+ case TCSETSF:
+ return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
+ case TCSETSW:
+ return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
+ case TCSETS:
+ return set_termios(real_tty, p, TERMIOS_OLD);
+#ifndef TCGETS2
case TCGETS:
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
return -EFAULT;
return 0;
- case TCSETSF:
+#else
+ case TCGETS:
+ if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
+ return -EFAULT;
+ return 0;
+ case TCGETS2:
+ if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
+ return -EFAULT;
+ return 0;
+ case TCSETSF2:
return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
- case TCSETSW:
+ case TCSETSW2:
return set_termios(real_tty, p, TERMIOS_WAIT);
- case TCSETS:
+ case TCSETS2:
return set_termios(real_tty, p, 0);
+#endif
case TCGETA:
return get_termio(real_tty, p);
case TCSETAF:
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index f442b574b44..26776517f04 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -72,7 +72,7 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
int size;
down(&con_buf_sem);
- size = vcs_size(file->f_dentry->d_inode);
+ size = vcs_size(file->f_path.dentry->d_inode);
switch (orig) {
default:
up(&con_buf_sem);
@@ -98,7 +98,7 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
static ssize_t
vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
unsigned int currcons = iminor(inode);
struct vc_data *vc;
long pos;
@@ -271,7 +271,7 @@ unlock_out:
static ssize_t
vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
unsigned int currcons = iminor(inode);
struct vc_data *vc;
long pos;
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
index 6d2e314860d..8de6b95aeb8 100644
--- a/drivers/char/viocons.c
+++ b/drivers/char/viocons.c
@@ -42,6 +42,7 @@
#include <linux/tty_flip.h>
#include <linux/sysrq.h>
+#include <asm/firmware.h>
#include <asm/iseries/vio.h>
#include <asm/iseries/hv_lp_event.h>
#include <asm/iseries/hv_call_event.h>
@@ -61,10 +62,7 @@
static DEFINE_SPINLOCK(consolelock);
static DEFINE_SPINLOCK(consoleloglock);
-#ifdef CONFIG_MAGIC_SYSRQ
static int vio_sysrq_pressed;
-extern int sysrq_enabled;
-#endif
#define VIOCHAR_NUM_BUF 16
@@ -936,8 +934,10 @@ static void vioHandleData(struct HvLpEvent *event)
*/
num_pushed = 0;
for (index = 0; index < cevent->len; index++) {
-#ifdef CONFIG_MAGIC_SYSRQ
- if (sysrq_enabled) {
+ /*
+ * Will be optimized away if !CONFIG_MAGIC_SYSRQ:
+ */
+ if (sysrq_on()) {
/* 0x0f is the ascii character for ^O */
if (cevent->data[index] == '\x0f') {
vio_sysrq_pressed = 1;
@@ -956,7 +956,6 @@ static void vioHandleData(struct HvLpEvent *event)
continue;
}
}
-#endif
/*
* The sysrq sequence isn't included in this check if
* sysrq is enabled and compiled into the kernel because
@@ -1062,6 +1061,9 @@ static int __init viocons_init2(void)
atomic_t wait_flag;
int rc;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return -ENODEV;
+
/* +2 for fudge */
rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
@@ -1147,6 +1149,9 @@ static int __init viocons_init(void)
{
int i;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return -ENODEV;
+
printk(VIOCONS_KERN_INFO "registering console\n");
for (i = 0; i < VTTY_PORTS; i++) {
port_info[i].lp = HvLpIndexInvalid;
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index 73c78bf75d7..9438512b17f 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -49,7 +49,7 @@
#include <asm/uaccess.h>
#include <asm/ioctls.h>
-
+#include <asm/firmware.h>
#include <asm/vio.h>
#include <asm/iseries/vio.h>
#include <asm/iseries/hv_lp_event.h>
@@ -442,7 +442,7 @@ static ssize_t viotap_write(struct file *file, const char *buf,
if (op == NULL)
return -ENOMEM;
- get_dev_info(file->f_dentry->d_inode, &devi);
+ get_dev_info(file->f_path.dentry->d_inode, &devi);
/*
* We need to make sure we can send a request. We use
@@ -532,7 +532,7 @@ static ssize_t viotap_read(struct file *file, char *buf, size_t count,
if (op == NULL)
return -ENOMEM;
- get_dev_info(file->f_dentry->d_inode, &devi);
+ get_dev_info(file->f_path.dentry->d_inode, &devi);
/*
* We need to make sure we can send a request. We use
@@ -612,7 +612,7 @@ static int viotap_ioctl(struct inode *inode, struct file *file,
if (op == NULL)
return -ENOMEM;
- get_dev_info(file->f_dentry->d_inode, &devi);
+ get_dev_info(file->f_path.dentry->d_inode, &devi);
down(&reqSem);
@@ -777,7 +777,7 @@ static int viotap_open(struct inode *inode, struct file *file)
if (op == NULL)
return -ENOMEM;
- get_dev_info(file->f_dentry->d_inode, &devi);
+ get_dev_info(file->f_path.dentry->d_inode, &devi);
/* Note: We currently only support one mode! */
if ((devi.devno >= viotape_numdev) || (devi.mode)) {
@@ -822,7 +822,7 @@ static int viotap_release(struct inode *inode, struct file *file)
return -ENOMEM;
init_completion(&op->com);
- get_dev_info(file->f_dentry->d_inode, &devi);
+ get_dev_info(file->f_path.dentry->d_inode, &devi);
if (devi.devno >= viotape_numdev) {
ret = -ENODEV;
@@ -997,6 +997,9 @@ int __init viotap_init(void)
int ret;
struct proc_dir_entry *e;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return -ENODEV;
+
op_struct_list = NULL;
if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) {
printk(VIOTAPE_KERN_WARN "couldn't allocate op structs\n");
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index d0b94dd1af6..e01317cb1a0 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -153,6 +153,8 @@ static int scc_init_drivers(void)
scc_driver->init_termios = tty_std_termios;
scc_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ scc_driver->init_termios.c_ispeed = 9600;
+ scc_driver->init_termios.c_ospeed = 9600;
scc_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(scc_driver, &scc_ops);
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
index 8e794930517..0cea8d4907d 100644
--- a/drivers/char/vr41xx_giu.c
+++ b/drivers/char/vr41xx_giu.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2002 MontaVista Software Inc.
* Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- * Copyright (C) 2003-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -125,30 +125,17 @@ static inline uint16_t giu_clear(uint16_t offset, uint16_t clear)
return data;
}
-static unsigned int startup_giuint_low_irq(unsigned int irq)
+static void ack_giuint_low(unsigned int irq)
{
- unsigned int pin;
-
- pin = GPIO_PIN_OF_IRQ(irq);
- giu_write(GIUINTSTATL, 1 << pin);
- giu_set(GIUINTENL, 1 << pin);
-
- return 0;
+ giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
}
-static void shutdown_giuint_low_irq(unsigned int irq)
+static void mask_giuint_low(unsigned int irq)
{
giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
}
-static void enable_giuint_low_irq(unsigned int irq)
-{
- giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-#define disable_giuint_low_irq shutdown_giuint_low_irq
-
-static void ack_giuint_low_irq(unsigned int irq)
+static void mask_ack_giuint_low(unsigned int irq)
{
unsigned int pin;
@@ -157,46 +144,30 @@ static void ack_giuint_low_irq(unsigned int irq)
giu_write(GIUINTSTATL, 1 << pin);
}
-static void end_giuint_low_irq(unsigned int irq)
+static void unmask_giuint_low(unsigned int irq)
{
- if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+ giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
}
-static struct hw_interrupt_type giuint_low_irq_type = {
- .typename = "GIUINTL",
- .startup = startup_giuint_low_irq,
- .shutdown = shutdown_giuint_low_irq,
- .enable = enable_giuint_low_irq,
- .disable = disable_giuint_low_irq,
- .ack = ack_giuint_low_irq,
- .end = end_giuint_low_irq,
+static struct irq_chip giuint_low_irq_chip = {
+ .name = "GIUINTL",
+ .ack = ack_giuint_low,
+ .mask = mask_giuint_low,
+ .mask_ack = mask_ack_giuint_low,
+ .unmask = unmask_giuint_low,
};
-static unsigned int startup_giuint_high_irq(unsigned int irq)
+static void ack_giuint_high(unsigned int irq)
{
- unsigned int pin;
-
- pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
- giu_write(GIUINTSTATH, 1 << pin);
- giu_set(GIUINTENH, 1 << pin);
-
- return 0;
+ giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
}
-static void shutdown_giuint_high_irq(unsigned int irq)
+static void mask_giuint_high(unsigned int irq)
{
giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
}
-static void enable_giuint_high_irq(unsigned int irq)
-{
- giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-#define disable_giuint_high_irq shutdown_giuint_high_irq
-
-static void ack_giuint_high_irq(unsigned int irq)
+static void mask_ack_giuint_high(unsigned int irq)
{
unsigned int pin;
@@ -205,20 +176,17 @@ static void ack_giuint_high_irq(unsigned int irq)
giu_write(GIUINTSTATH, 1 << pin);
}
-static void end_giuint_high_irq(unsigned int irq)
+static void unmask_giuint_high(unsigned int irq)
{
- if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+ giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
}
-static struct hw_interrupt_type giuint_high_irq_type = {
- .typename = "GIUINTH",
- .startup = startup_giuint_high_irq,
- .shutdown = shutdown_giuint_high_irq,
- .enable = enable_giuint_high_irq,
- .disable = disable_giuint_high_irq,
- .ack = ack_giuint_high_irq,
- .end = end_giuint_high_irq,
+static struct irq_chip giuint_high_irq_chip = {
+ .name = "GIUINTH",
+ .ack = ack_giuint_high,
+ .mask = mask_giuint_high,
+ .mask_ack = mask_ack_giuint_high,
+ .unmask = unmask_giuint_high,
};
static int giu_get_irq(unsigned int irq)
@@ -282,9 +250,15 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_
break;
}
}
+ set_irq_chip_and_handler(GIU_IRQ(pin),
+ &giuint_low_irq_chip,
+ handle_edge_irq);
} else {
giu_clear(GIUINTTYPL, mask);
giu_clear(GIUINTHTSELL, mask);
+ set_irq_chip_and_handler(GIU_IRQ(pin),
+ &giuint_low_irq_chip,
+ handle_level_irq);
}
giu_write(GIUINTSTATL, mask);
} else if (pin < GIUINT_HIGH_MAX) {
@@ -311,9 +285,15 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_
break;
}
}
+ set_irq_chip_and_handler(GIU_IRQ(pin),
+ &giuint_high_irq_chip,
+ handle_edge_irq);
} else {
giu_clear(GIUINTTYPH, mask);
giu_clear(GIUINTHTSELH, mask);
+ set_irq_chip_and_handler(GIU_IRQ(pin),
+ &giuint_high_irq_chip,
+ handle_level_irq);
}
giu_write(GIUINTSTATH, mask);
}
@@ -506,7 +486,7 @@ static ssize_t gpio_read(struct file *file, char __user *buf, size_t len,
unsigned int pin;
char value = '0';
- pin = iminor(file->f_dentry->d_inode);
+ pin = iminor(file->f_path.dentry->d_inode);
if (pin >= giu_nr_pins)
return -EBADF;
@@ -530,7 +510,7 @@ static ssize_t gpio_write(struct file *file, const char __user *data,
char c;
int retval = 0;
- pin = iminor(file->f_dentry->d_inode);
+ pin = iminor(file->f_path.dentry->d_inode);
if (pin >= giu_nr_pins)
return -EBADF;
@@ -617,10 +597,11 @@ static const struct file_operations gpio_fops = {
static int __devinit giu_probe(struct platform_device *dev)
{
unsigned long start, size, flags = 0;
- unsigned int nr_pins = 0;
+ unsigned int nr_pins = 0, trigger, i, pin;
struct resource *res1, *res2 = NULL;
void *base;
- int retval, i;
+ struct irq_chip *chip;
+ int retval;
switch (current_cpu_data.cputype) {
case CPU_VR4111:
@@ -688,11 +669,20 @@ static int __devinit giu_probe(struct platform_device *dev)
giu_write(GIUINTENL, 0);
giu_write(GIUINTENH, 0);
+ trigger = giu_read(GIUINTTYPH) << 16;
+ trigger |= giu_read(GIUINTTYPL);
for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
- if (i < GIU_IRQ(GIUINT_HIGH_OFFSET))
- irq_desc[i].chip = &giuint_low_irq_type;
+ pin = GPIO_PIN_OF_IRQ(i);
+ if (pin < GIUINT_HIGH_OFFSET)
+ chip = &giuint_low_irq_chip;
else
- irq_desc[i].chip = &giuint_high_irq_type;
+ chip = &giuint_high_irq_chip;
+
+ if (trigger & (1 << pin))
+ set_irq_chip_and_handler(i, chip, handle_edge_irq);
+ else
+ set_irq_chip_and_handler(i, chip, handle_level_irq);
+
}
return cascade_irq(GIUINT_IRQ, giu_get_irq);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index a8239dac994..06c32a3e3ca 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -784,7 +784,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
return 0;
- newscreen = (unsigned short *) kmalloc(new_screen_size, GFP_USER);
+ newscreen = kmalloc(new_screen_size, GFP_USER);
if (!newscreen)
return -ENOMEM;
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index ac5d60edbaf..dc8368ebb1a 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -129,7 +129,7 @@ do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_str
!capable(CAP_SYS_RESOURCE))
return -EPERM;
- key_map = (ushort *) kmalloc(sizeof(plain_map),
+ key_map = kmalloc(sizeof(plain_map),
GFP_KERNEL);
if (!key_map)
return -ENOMEM;
@@ -259,7 +259,7 @@ do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
sz = 256;
while (sz < funcbufsize - funcbufleft + delta)
sz <<= 1;
- fnw = (char *) kmalloc(sz, GFP_KERNEL);
+ fnw = kmalloc(sz, GFP_KERNEL);
if(!fnw) {
ret = -ENOMEM;
goto reterr;
@@ -1087,7 +1087,7 @@ static void complete_change_console(struct vc_data *vc)
switch_screen(vc);
/*
- * This can't appear below a successful kill_proc(). If it did,
+ * This can't appear below a successful kill_pid(). If it did,
* then the *blank_screen operation could occur while X, having
* received acqsig, is waking up on another processor. This
* condition can lead to overlapping accesses to the VGA range
@@ -1110,7 +1110,7 @@ static void complete_change_console(struct vc_data *vc)
*/
if (vc->vt_mode.mode == VT_PROCESS) {
/*
- * Send the signal as privileged - kill_proc() will
+ * Send the signal as privileged - kill_pid() will
* tell us if the process has gone or something else
* is awry
*/
@@ -1170,7 +1170,7 @@ void change_console(struct vc_data *new_vc)
vc = vc_cons[fg_console].d;
if (vc->vt_mode.mode == VT_PROCESS) {
/*
- * Send the signal as privileged - kill_proc() will
+ * Send the signal as privileged - kill_pid() will
* tell us if the process has gone or something else
* is awry
*/
diff --git a/drivers/char/watchdog/at91rm9200_wdt.c b/drivers/char/watchdog/at91rm9200_wdt.c
index cb86967e2c5..38bd3737259 100644
--- a/drivers/char/watchdog/at91rm9200_wdt.c
+++ b/drivers/char/watchdog/at91rm9200_wdt.c
@@ -203,9 +203,9 @@ static int __init at91wdt_probe(struct platform_device *pdev)
{
int res;
- if (at91wdt_miscdev.dev)
+ if (at91wdt_miscdev.parent)
return -EBUSY;
- at91wdt_miscdev.dev = &pdev->dev;
+ at91wdt_miscdev.parent = &pdev->dev;
res = misc_register(&at91wdt_miscdev);
if (res)
@@ -221,7 +221,7 @@ static int __exit at91wdt_remove(struct platform_device *pdev)
res = misc_deregister(&at91wdt_miscdev);
if (!res)
- at91wdt_miscdev.dev = NULL;
+ at91wdt_miscdev.parent = NULL;
return res;
}
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index 488902231cc..0e23f29f71a 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -35,7 +35,7 @@
#ifdef CONFIG_FSL_BOOKE
#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */
#else
-#define WDT_PERIOD_DEFAULT 4 /* Refer to the PPC40x and PPC4xx manuals */
+#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */
#endif /* for timing information */
u32 booke_wdt_enabled = 0;
@@ -48,12 +48,22 @@ u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
#endif
/*
+ * booke_wdt_ping:
+ */
+static __inline__ void booke_wdt_ping(void)
+{
+ mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
+}
+
+/*
* booke_wdt_enable:
*/
static __inline__ void booke_wdt_enable(void)
{
u32 val;
+ /* clear status before enabling watchdog */
+ booke_wdt_ping();
val = mfspr(SPRN_TCR);
val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
@@ -61,14 +71,6 @@ static __inline__ void booke_wdt_enable(void)
}
/*
- * booke_wdt_ping:
- */
-static __inline__ void booke_wdt_ping(void)
-{
- mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
-}
-
-/*
* booke_wdt_write:
*/
static ssize_t booke_wdt_write (struct file *file, const char __user *buf,
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index 276577d08fb..4d730fdbd52 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -325,7 +325,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return put_user(0, p);
case WDIOC_KEEPALIVE:
- zf_ping(0);
+ zf_ping(NULL);
break;
default:
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
index 3404a9c67f0..e88947f8fe5 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -347,7 +347,7 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
goto err_free;
}
- mpcore_wdt_miscdev.dev = &dev->dev;
+ mpcore_wdt_miscdev.parent = &dev->dev;
ret = misc_register(&mpcore_wdt_miscdev);
if (ret) {
dev_printk(KERN_ERR, _dev, "cannot register miscdev on minor=%d (err=%d)\n",
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
index 5dbd7dc2936..6c6f97332db 100644
--- a/drivers/char/watchdog/omap_wdt.c
+++ b/drivers/char/watchdog/omap_wdt.c
@@ -290,7 +290,7 @@ static int __init omap_wdt_probe(struct platform_device *pdev)
omap_wdt_disable();
omap_wdt_adjust_timeout(timer_margin);
- omap_wdt_miscdev.dev = &pdev->dev;
+ omap_wdt_miscdev.parent = &pdev->dev;
ret = misc_register(&omap_wdt_miscdev);
if (ret)
goto fail;
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index 61138726b50..2da5ac99687 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -42,6 +42,7 @@
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/mutex.h>
+#include <linux/hid.h> /* For HID_REQ_SET_REPORT & HID_DT_REPORT */
#ifdef CONFIG_USB_DEBUG
@@ -109,10 +110,6 @@ MODULE_DEVICE_TABLE (usb, usb_pcwd_table);
#define CMD_ENABLE_WATCHDOG 0x30 /* Enable / Disable Watchdog */
#define CMD_DISABLE_WATCHDOG CMD_ENABLE_WATCHDOG
-/* Some defines that I like to be somewhere else like include/linux/usb_hid.h */
-#define HID_REQ_SET_REPORT 0x09
-#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02)
-
/* We can only use 1 card due to the /dev/watchdog restriction */
static int cards_found;
diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c
index ec3909371c2..7576a13e86b 100644
--- a/drivers/char/watchdog/rm9k_wdt.c
+++ b/drivers/char/watchdog/rm9k_wdt.c
@@ -47,7 +47,7 @@
/* Function prototypes */
-static irqreturn_t wdt_gpi_irqhdl(int, void *, struct pt_regs *);
+static irqreturn_t wdt_gpi_irqhdl(int, void *);
static void wdt_gpi_start(void);
static void wdt_gpi_stop(void);
static void wdt_gpi_set_timeout(unsigned int);
@@ -94,8 +94,28 @@ module_param(nowayout, bool, 0444);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be disabled once started");
+/* Kernel interfaces */
+static struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = wdt_gpi_open,
+ .release = wdt_gpi_release,
+ .write = wdt_gpi_write,
+ .unlocked_ioctl = wdt_gpi_ioctl,
+};
+
+static struct miscdevice miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = wdt_gpi_name,
+ .fops = &fops,
+};
+
+static struct notifier_block wdt_gpi_shutdown = {
+ .notifier_call = wdt_gpi_notify,
+};
+
+
/* Interrupt handler */
-static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt, struct pt_regs *regs)
+static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt)
{
if (!unlikely(__raw_readl(wd_regs + 0x0008) & 0x1))
return IRQ_NONE;
@@ -312,26 +332,6 @@ wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused)
}
-/* Kernel interfaces */
-static struct file_operations fops = {
- .owner = THIS_MODULE,
- .open = wdt_gpi_open,
- .release = wdt_gpi_release,
- .write = wdt_gpi_write,
- .unlocked_ioctl = wdt_gpi_ioctl,
-};
-
-static struct miscdevice miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = wdt_gpi_name,
- .fops = &fops,
-};
-
-static struct notifier_block wdt_gpi_shutdown = {
- .notifier_call = wdt_gpi_notify,
-};
-
-
/* Init & exit procedures */
static const struct resource *
wdt_gpi_get_resource(struct platform_device *pdv, const char *name,
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 7fcb77a9d01..b6bcdbbf57b 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -77,11 +77,11 @@ static struct clocksource clocksource_acpi_pm = {
#ifdef CONFIG_PCI
-static int acpi_pm_good;
+static int __devinitdata acpi_pm_good;
static int __init acpi_pm_good_setup(char *__str)
{
- acpi_pm_good = 1;
- return 1;
+ acpi_pm_good = 1;
+ return 1;
}
__setup("acpi_pm_good", acpi_pm_good_setup);
@@ -142,6 +142,39 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE,
acpi_pm_check_graylist);
#endif
+#ifndef CONFIG_X86_64
+#include "mach_timer.h"
+#define PMTMR_EXPECTED_RATE \
+ ((CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (CLOCK_TICK_RATE>>10))
+/*
+ * Some boards have the PMTMR running way too fast. We check
+ * the PMTMR rate against PIT channel 2 to catch these cases.
+ */
+static int verify_pmtmr_rate(void)
+{
+ u32 value1, value2;
+ unsigned long count, delta;
+
+ mach_prepare_counter();
+ value1 = read_pmtmr();
+ mach_countup(&count);
+ value2 = read_pmtmr();
+ delta = (value2 - value1) & ACPI_PM_MASK;
+
+ /* Check that the PMTMR delta is within 5% of what we expect */
+ if (delta < (PMTMR_EXPECTED_RATE * 19) / 20 ||
+ delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
+ printk(KERN_INFO "PM-Timer running at invalid rate: %lu%% "
+ "of normal - aborting.\n",
+ 100UL * delta / PMTMR_EXPECTED_RATE);
+ return -1;
+ }
+
+ return 0;
+}
+#else
+#define verify_pmtmr_rate() (0)
+#endif
static int __init init_acpi_pm_clocksource(void)
{
@@ -173,6 +206,9 @@ static int __init init_acpi_pm_clocksource(void)
return -ENODEV;
pm_good:
+ if (verify_pmtmr_rate() != 0)
+ return -ENODEV;
+
return clocksource_register(&clocksource_acpi_pm);
}
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 3ece6923134..5c9f67f98d1 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -28,6 +28,7 @@
#include <linux/init.h>
#include <linux/connector.h>
#include <asm/atomic.h>
+#include <asm/unaligned.h>
#include <linux/cn_proc.h>
@@ -60,7 +61,7 @@ void proc_fork_connector(struct task_struct *task)
ev = (struct proc_event*)msg->data;
get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */
- ev->timestamp_ns = timespec_to_ns(&ts);
+ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
ev->what = PROC_EVENT_FORK;
ev->event_data.fork.parent_pid = task->real_parent->pid;
ev->event_data.fork.parent_tgid = task->real_parent->tgid;
@@ -88,7 +89,7 @@ void proc_exec_connector(struct task_struct *task)
ev = (struct proc_event*)msg->data;
get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */
- ev->timestamp_ns = timespec_to_ns(&ts);
+ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
ev->what = PROC_EVENT_EXEC;
ev->event_data.exec.process_pid = task->pid;
ev->event_data.exec.process_tgid = task->tgid;
@@ -124,7 +125,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
return;
get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */
- ev->timestamp_ns = timespec_to_ns(&ts);
+ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
msg->ack = 0; /* not used */
@@ -146,7 +147,7 @@ void proc_exit_connector(struct task_struct *task)
ev = (struct proc_event*)msg->data;
get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */
- ev->timestamp_ns = timespec_to_ns(&ts);
+ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
ev->what = PROC_EVENT_EXIT;
ev->event_data.exit.process_pid = task->pid;
ev->event_data.exit.process_tgid = task->tgid;
@@ -181,7 +182,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
ev = (struct proc_event*)msg->data;
msg->seq = rcvd_seq;
ktime_get_ts(&ts); /* get high res monotonic timestamp */
- ev->timestamp_ns = timespec_to_ns(&ts);
+ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
ev->cpu = -1;
ev->what = PROC_EVENT_NONE;
ev->event_data.ack.err = err;
diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
index b418b16e910..296f51002b5 100644
--- a/drivers/connector/cn_queue.c
+++ b/drivers/connector/cn_queue.c
@@ -34,7 +34,7 @@
void cn_queue_wrapper(struct work_struct *work)
{
struct cn_callback_entry *cbq =
- container_of(work, struct cn_callback_entry, work.work);
+ container_of(work, struct cn_callback_entry, work);
struct cn_callback_data *d = &cbq->data;
d->callback(d->callback_priv);
@@ -59,13 +59,12 @@ static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struc
memcpy(&cbq->id.id, id, sizeof(struct cb_id));
cbq->data.callback = callback;
- INIT_DELAYED_WORK(&cbq->work, &cn_queue_wrapper);
+ INIT_WORK(&cbq->work, &cn_queue_wrapper);
return cbq;
}
static void cn_queue_free_callback(struct cn_callback_entry *cbq)
{
- cancel_delayed_work(&cbq->work);
flush_workqueue(cbq->pdev->cn_queue);
kfree(cbq);
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 5e7cd45d10e..a44db75bc25 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -135,17 +135,15 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
spin_lock_bh(&dev->cbdev->queue_lock);
list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) {
if (cn_cb_equal(&__cbq->id.id, &msg->id)) {
- if (likely(!test_bit(WORK_STRUCT_PENDING,
- &__cbq->work.work.management) &&
+ if (likely(!work_pending(&__cbq->work) &&
__cbq->data.ddata == NULL)) {
__cbq->data.callback_priv = msg;
__cbq->data.ddata = data;
__cbq->data.destruct_data = destruct_data;
- if (queue_delayed_work(
- dev->cbdev->cn_queue,
- &__cbq->work, 0))
+ if (queue_work(dev->cbdev->cn_queue,
+ &__cbq->work))
err = 0;
} else {
struct cn_callback_data *d;
@@ -159,12 +157,11 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
d->destruct_data = destruct_data;
d->free = __cbq;
- INIT_DELAYED_WORK(&__cbq->work,
- &cn_queue_wrapper);
+ INIT_WORK(&__cbq->work,
+ &cn_queue_wrapper);
- if (queue_delayed_work(
- dev->cbdev->cn_queue,
- &__cbq->work, 0))
+ if (queue_work(dev->cbdev->cn_queue,
+ &__cbq->work))
err = 0;
else {
kfree(__cbq);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 47ab42db122..a45cc89e387 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -29,7 +29,8 @@
#include <linux/completion.h>
#include <linux/mutex.h>
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "cpufreq-core", msg)
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \
+ "cpufreq-core", msg)
/**
* The "cpufreq driver" - the arch- or hardware-dependent low
@@ -151,7 +152,8 @@ static void cpufreq_debug_disable_ratelimit(void)
spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
}
-void cpufreq_debug_printk(unsigned int type, const char *prefix, const char *fmt, ...)
+void cpufreq_debug_printk(unsigned int type, const char *prefix,
+ const char *fmt, ...)
{
char s[256];
va_list args;
@@ -161,7 +163,8 @@ void cpufreq_debug_printk(unsigned int type, const char *prefix, const char *fmt
WARN_ON(!prefix);
if (type & debug) {
spin_lock_irqsave(&disable_ratelimit_lock, flags);
- if (!disable_ratelimit && debug_ratelimit && !printk_ratelimit()) {
+ if (!disable_ratelimit && debug_ratelimit
+ && !printk_ratelimit()) {
spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
return;
}
@@ -182,10 +185,12 @@ EXPORT_SYMBOL(cpufreq_debug_printk);
module_param(debug, uint, 0644);
-MODULE_PARM_DESC(debug, "CPUfreq debugging: add 1 to debug core, 2 to debug drivers, and 4 to debug governors.");
+MODULE_PARM_DESC(debug, "CPUfreq debugging: add 1 to debug core,"
+ " 2 to debug drivers, and 4 to debug governors.");
module_param(debug_ratelimit, uint, 0644);
-MODULE_PARM_DESC(debug_ratelimit, "CPUfreq debugging: set to 0 to disable ratelimiting.");
+MODULE_PARM_DESC(debug_ratelimit, "CPUfreq debugging:"
+ " set to 0 to disable ratelimiting.");
#else /* !CONFIG_CPU_FREQ_DEBUG */
@@ -219,17 +224,23 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
if (!l_p_j_ref_freq) {
l_p_j_ref = loops_per_jiffy;
l_p_j_ref_freq = ci->old;
- dprintk("saving %lu as reference value for loops_per_jiffy; freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
+ dprintk("saving %lu as reference value for loops_per_jiffy;"
+ "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
}
if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) ||
(val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
(val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
- loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
- dprintk("scaling loops_per_jiffy to %lu for frequency %u kHz\n", loops_per_jiffy, ci->new);
+ loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
+ ci->new);
+ dprintk("scaling loops_per_jiffy to %lu"
+ "for frequency %u kHz\n", loops_per_jiffy, ci->new);
}
}
#else
-static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; }
+static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
+{
+ return;
+}
#endif
@@ -316,7 +327,8 @@ static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
*policy = CPUFREQ_POLICY_PERFORMANCE;
err = 0;
- } else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) {
+ } else if (!strnicmp(str_governor, "powersave",
+ CPUFREQ_NAME_LEN)) {
*policy = CPUFREQ_POLICY_POWERSAVE;
err = 0;
}
@@ -328,7 +340,8 @@ static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
t = __find_governor(str_governor);
if (t == NULL) {
- char *name = kasprintf(GFP_KERNEL, "cpufreq_%s", str_governor);
+ char *name = kasprintf(GFP_KERNEL, "cpufreq_%s",
+ str_governor);
if (name) {
int ret;
@@ -361,7 +374,8 @@ extern struct sysdev_class cpu_sysdev_class;
/**
- * cpufreq_per_cpu_attr_read() / show_##file_name() - print out cpufreq information
+ * cpufreq_per_cpu_attr_read() / show_##file_name() -
+ * print out cpufreq information
*
* Write out information from cpufreq_driver->policy[cpu]; object must be
* "unsigned int".
@@ -380,7 +394,8 @@ show_one(scaling_min_freq, min);
show_one(scaling_max_freq, max);
show_one(scaling_cur_freq, cur);
-static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_policy *policy);
+static int __cpufreq_set_policy(struct cpufreq_policy *data,
+ struct cpufreq_policy *policy);
/**
* cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access
@@ -416,7 +431,8 @@ store_one(scaling_max_freq,max);
/**
* show_cpuinfo_cur_freq - current CPU frequency as detected by hardware
*/
-static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, char *buf)
+static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy,
+ char *buf)
{
unsigned int cur_freq = cpufreq_get(policy->cpu);
if (!cur_freq)
@@ -428,7 +444,8 @@ static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, char *buf)
/**
* show_scaling_governor - show the current policy for the specified CPU
*/
-static ssize_t show_scaling_governor (struct cpufreq_policy * policy, char *buf)
+static ssize_t show_scaling_governor (struct cpufreq_policy * policy,
+ char *buf)
{
if(policy->policy == CPUFREQ_POLICY_POWERSAVE)
return sprintf(buf, "powersave\n");
@@ -458,7 +475,8 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy,
if (ret != 1)
return -EINVAL;
- if (cpufreq_parse_governor(str_governor, &new_policy.policy, &new_policy.governor))
+ if (cpufreq_parse_governor(str_governor, &new_policy.policy,
+ &new_policy.governor))
return -EINVAL;
lock_cpu_hotplug();
@@ -474,7 +492,10 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy,
unlock_cpu_hotplug();
- return ret ? ret : count;
+ if (ret)
+ return ret;
+ else
+ return count;
}
/**
@@ -488,7 +509,7 @@ static ssize_t show_scaling_driver (struct cpufreq_policy * policy, char *buf)
/**
* show_scaling_available_governors - show the available CPUfreq governors
*/
-static ssize_t show_scaling_available_governors (struct cpufreq_policy * policy,
+static ssize_t show_scaling_available_governors (struct cpufreq_policy *policy,
char *buf)
{
ssize_t i = 0;
@@ -574,7 +595,11 @@ static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf)
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
return -EINVAL;
- ret = fattr->show ? fattr->show(policy,buf) : -EIO;
+ if (fattr->show)
+ ret = fattr->show(policy, buf);
+ else
+ ret = -EIO;
+
cpufreq_cpu_put(policy);
return ret;
}
@@ -588,7 +613,11 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr,
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
return -EINVAL;
- ret = fattr->store ? fattr->store(policy,buf,count) : -EIO;
+ if (fattr->store)
+ ret = fattr->store(policy, buf, count);
+ else
+ ret = -EIO;
+
cpufreq_cpu_put(policy);
return ret;
}
@@ -693,8 +722,13 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
dprintk("CPU already managed, adding link\n");
- sysfs_create_link(&sys_dev->kobj,
- &managed_policy->kobj, "cpufreq");
+ ret = sysfs_create_link(&sys_dev->kobj,
+ &managed_policy->kobj,
+ "cpufreq");
+ if (ret) {
+ mutex_unlock(&policy->lock);
+ goto err_out_driver_exit;
+ }
cpufreq_debug_enable_ratelimit();
mutex_unlock(&policy->lock);
@@ -741,8 +775,12 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
dprintk("CPU %u already managed, adding link\n", j);
cpufreq_cpu_get(cpu);
cpu_sys_dev = get_cpu_sysdev(j);
- sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
- "cpufreq");
+ ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
+ "cpufreq");
+ if (ret) {
+ mutex_unlock(&policy->lock);
+ goto err_out_unregister;
+ }
}
policy->governor = NULL; /* to assure that the starting sequence is
@@ -913,7 +951,8 @@ static void handle_update(struct work_struct *work)
* We adjust to current frequency first, and need to clean up later. So either call
* to cpufreq_update_policy() or schedule handle_update()).
*/
-static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigned int new_freq)
+static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
+ unsigned int new_freq)
{
struct cpufreq_freqs freqs;
@@ -929,7 +968,7 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigne
/**
- * cpufreq_quick_get - get the CPU frequency (in kHz) frpm policy->cur
+ * cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur
* @cpu: CPU number
*
* This is the last known freq, without actually getting it from the driver.
@@ -938,16 +977,16 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigne
unsigned int cpufreq_quick_get(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- unsigned int ret = 0;
+ unsigned int ret_freq = 0;
if (policy) {
mutex_lock(&policy->lock);
- ret = policy->cur;
+ ret_freq = policy->cur;
mutex_unlock(&policy->lock);
cpufreq_cpu_put(policy);
}
- return (ret);
+ return (ret_freq);
}
EXPORT_SYMBOL(cpufreq_quick_get);
@@ -961,7 +1000,7 @@ EXPORT_SYMBOL(cpufreq_quick_get);
unsigned int cpufreq_get(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- unsigned int ret = 0;
+ unsigned int ret_freq = 0;
if (!policy)
return 0;
@@ -971,12 +1010,14 @@ unsigned int cpufreq_get(unsigned int cpu)
mutex_lock(&policy->lock);
- ret = cpufreq_driver->get(cpu);
+ ret_freq = cpufreq_driver->get(cpu);
- if (ret && policy->cur && !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
- /* verify no discrepancy between actual and saved value exists */
- if (unlikely(ret != policy->cur)) {
- cpufreq_out_of_sync(cpu, policy->cur, ret);
+ if (ret_freq && policy->cur &&
+ !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
+ /* verify no discrepancy between actual and
+ saved value exists */
+ if (unlikely(ret_freq != policy->cur)) {
+ cpufreq_out_of_sync(cpu, policy->cur, ret_freq);
schedule_work(&policy->update);
}
}
@@ -986,7 +1027,7 @@ unsigned int cpufreq_get(unsigned int cpu)
out:
cpufreq_cpu_put(policy);
- return (ret);
+ return (ret_freq);
}
EXPORT_SYMBOL(cpufreq_get);
@@ -998,7 +1039,7 @@ EXPORT_SYMBOL(cpufreq_get);
static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
{
int cpu = sysdev->id;
- unsigned int ret = 0;
+ int ret = 0;
unsigned int cur_freq = 0;
struct cpufreq_policy *cpu_policy;
@@ -1080,7 +1121,7 @@ out:
static int cpufreq_resume(struct sys_device * sysdev)
{
int cpu = sysdev->id;
- unsigned int ret = 0;
+ int ret = 0;
struct cpufreq_policy *cpu_policy;
dprintk("resuming cpu %u\n", cpu);
@@ -1276,22 +1317,45 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
+int cpufreq_driver_getavg(struct cpufreq_policy *policy)
+{
+ int ret = 0;
+
+ policy = cpufreq_cpu_get(policy->cpu);
+ if (!policy)
+ return -EINVAL;
+
+ mutex_lock(&policy->lock);
+
+ if (cpu_online(policy->cpu) && cpufreq_driver->getavg)
+ ret = cpufreq_driver->getavg(policy->cpu);
+
+ mutex_unlock(&policy->lock);
+
+ cpufreq_cpu_put(policy);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpufreq_driver_getavg);
+
/*
* Locking: Must be called with the lock_cpu_hotplug() lock held
* when "event" is CPUFREQ_GOV_LIMITS
*/
-static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
+static int __cpufreq_governor(struct cpufreq_policy *policy,
+ unsigned int event)
{
int ret;
if (!try_module_get(policy->governor->owner))
return -EINVAL;
- dprintk("__cpufreq_governor for CPU %u, event %u\n", policy->cpu, event);
+ dprintk("__cpufreq_governor for CPU %u, event %u\n",
+ policy->cpu, event);
ret = policy->governor->governor(policy, event);
- /* we keep one module reference alive for each CPU governed by this CPU */
+ /* we keep one module reference alive for
+ each CPU governed by this CPU */
if ((event != CPUFREQ_GOV_START) || ret)
module_put(policy->governor->owner);
if ((event == CPUFREQ_GOV_STOP) && !ret)
@@ -1367,9 +1431,12 @@ EXPORT_SYMBOL(cpufreq_get_policy);
/*
+ * data : current policy.
+ * policy : policy to be set.
* Locking: Must be called with the lock_cpu_hotplug() lock held
*/
-static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_policy *policy)
+static int __cpufreq_set_policy(struct cpufreq_policy *data,
+ struct cpufreq_policy *policy)
{
int ret = 0;
@@ -1377,7 +1444,8 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli
dprintk("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
policy->min, policy->max);
- memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo));
+ memcpy(&policy->cpuinfo, &data->cpuinfo,
+ sizeof(struct cpufreq_cpuinfo));
if (policy->min > data->min && policy->min > policy->max) {
ret = -EINVAL;
@@ -1410,7 +1478,8 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli
data->min = policy->min;
data->max = policy->max;
- dprintk("new min and max freqs are %u - %u kHz\n", data->min, data->max);
+ dprintk("new min and max freqs are %u - %u kHz\n",
+ data->min, data->max);
if (cpufreq_driver->setpolicy) {
data->policy = policy->policy;
@@ -1431,10 +1500,12 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli
data->governor = policy->governor;
if (__cpufreq_governor(data, CPUFREQ_GOV_START)) {
/* new governor failed, so re-start old one */
- dprintk("starting governor %s failed\n", data->governor->name);
+ dprintk("starting governor %s failed\n",
+ data->governor->name);
if (old_gov) {
data->governor = old_gov;
- __cpufreq_governor(data, CPUFREQ_GOV_START);
+ __cpufreq_governor(data,
+ CPUFREQ_GOV_START);
}
ret = -EINVAL;
goto error_out;
@@ -1524,7 +1595,8 @@ int cpufreq_update_policy(unsigned int cpu)
data->cur = policy.cur;
} else {
if (data->cur != policy.cur)
- cpufreq_out_of_sync(cpu, data->cur, policy.cur);
+ cpufreq_out_of_sync(cpu, data->cur,
+ policy.cur);
}
}
@@ -1626,8 +1698,10 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
/* if all ->init() calls failed, unregister */
if (ret) {
- dprintk("no CPU initialized for driver %s\n", driver_data->name);
- sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
+ dprintk("no CPU initialized for driver %s\n",
+ driver_data->name);
+ sysdev_driver_unregister(&cpu_sysdev_class,
+ &cpufreq_sysdev_driver);
spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 5ef5ede5b88..eef0270c6f3 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -44,15 +44,17 @@
* latency of the processor. The governor will work on any processor with
* transition latency <= 10mS, using appropriate sampling
* rate.
- * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
- * this governor will not work.
+ * For CPUs with transition latency > 10mS (mostly drivers
+ * with CPUFREQ_ETERNAL), this governor will not work.
* All times here are in uS.
*/
static unsigned int def_sampling_rate;
#define MIN_SAMPLING_RATE_RATIO (2)
/* for correct statistics, we need at least 10 ticks between each measure */
-#define MIN_STAT_SAMPLING_RATE (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10))
-#define MIN_SAMPLING_RATE (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
+#define MIN_STAT_SAMPLING_RATE \
+ (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10))
+#define MIN_SAMPLING_RATE \
+ (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
#define DEF_SAMPLING_DOWN_FACTOR (1)
@@ -103,11 +105,16 @@ static struct dbs_tuners dbs_tuners_ins = {
static inline unsigned int get_cpu_idle_time(unsigned int cpu)
{
- return kstat_cpu(cpu).cpustat.idle +
+ unsigned int add_nice = 0, ret;
+
+ if (dbs_tuners_ins.ignore_nice)
+ add_nice = kstat_cpu(cpu).cpustat.nice;
+
+ ret = kstat_cpu(cpu).cpustat.idle +
kstat_cpu(cpu).cpustat.iowait +
- ( dbs_tuners_ins.ignore_nice ?
- kstat_cpu(cpu).cpustat.nice :
- 0);
+ add_nice;
+
+ return ret;
}
/************************** sysfs interface ************************/
@@ -452,6 +459,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
unsigned int cpu = policy->cpu;
struct cpu_dbs_info_s *this_dbs_info;
unsigned int j;
+ int rc;
this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
@@ -468,6 +476,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
break;
mutex_lock(&dbs_mutex);
+
+ rc = sysfs_create_group(&policy->kobj, &dbs_attr_group);
+ if (rc) {
+ mutex_unlock(&dbs_mutex);
+ return rc;
+ }
+
for_each_cpu_mask(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
@@ -480,7 +495,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
this_dbs_info->enable = 1;
this_dbs_info->down_skip = 0;
this_dbs_info->requested_freq = policy->cur;
- sysfs_create_group(&policy->kobj, &dbs_attr_group);
+
dbs_enable++;
/*
* Start the timerschedule work, when this governor
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index e1cc5113c2a..f697449327c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -41,8 +41,10 @@
static unsigned int def_sampling_rate;
#define MIN_SAMPLING_RATE_RATIO (2)
/* for correct statistics, we need at least 10 ticks between each measure */
-#define MIN_STAT_SAMPLING_RATE (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10))
-#define MIN_SAMPLING_RATE (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
+#define MIN_STAT_SAMPLING_RATE \
+ (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10))
+#define MIN_SAMPLING_RATE \
+ (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
#define TRANSITION_LATENCY_LIMIT (10 * 1000)
@@ -206,7 +208,8 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
ret = sscanf(buf, "%u", &input);
mutex_lock(&dbs_mutex);
- if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) {
+ if (ret != 1 || input > MAX_SAMPLING_RATE
+ || input < MIN_SAMPLING_RATE) {
mutex_unlock(&dbs_mutex);
return -EINVAL;
}
@@ -397,8 +400,15 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
* policy. To be safe, we focus 10 points under the threshold.
*/
if (load < (dbs_tuners_ins.up_threshold - 10)) {
- unsigned int freq_next = (policy->cur * load) /
+ unsigned int freq_next, freq_cur;
+
+ freq_cur = cpufreq_driver_getavg(policy);
+ if (!freq_cur)
+ freq_cur = policy->cur;
+
+ freq_next = (freq_cur * load) /
(dbs_tuners_ins.up_threshold - 10);
+
if (!dbs_tuners_ins.powersave_bias) {
__cpufreq_driver_target(policy, freq_next,
CPUFREQ_RELATION_L);
@@ -472,6 +482,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
unsigned int cpu = policy->cpu;
struct cpu_dbs_info_s *this_dbs_info;
unsigned int j;
+ int rc;
this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
@@ -494,12 +505,23 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
if (dbs_enable == 1) {
kondemand_wq = create_workqueue("kondemand");
if (!kondemand_wq) {
- printk(KERN_ERR "Creation of kondemand failed\n");
+ printk(KERN_ERR
+ "Creation of kondemand failed\n");
dbs_enable--;
mutex_unlock(&dbs_mutex);
return -ENOSPC;
}
}
+
+ rc = sysfs_create_group(&policy->kobj, &dbs_attr_group);
+ if (rc) {
+ if (dbs_enable == 1)
+ destroy_workqueue(kondemand_wq);
+ dbs_enable--;
+ mutex_unlock(&dbs_mutex);
+ return rc;
+ }
+
for_each_cpu_mask(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
@@ -509,7 +531,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
j_dbs_info->prev_cpu_wall = get_jiffies_64();
}
this_dbs_info->enable = 1;
- sysfs_create_group(&policy->kobj, &dbs_attr_group);
/*
* Start the timerschedule work, when this governor
* is used for first time
diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c
index de91e3371ef..e8e1451ef1c 100644
--- a/drivers/cpufreq/cpufreq_performance.c
+++ b/drivers/cpufreq/cpufreq_performance.c
@@ -15,7 +15,8 @@
#include <linux/cpufreq.h>
#include <linux/init.h>
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "performance", msg)
+#define dprintk(msg...) \
+ cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "performance", msg)
static int cpufreq_governor_performance(struct cpufreq_policy *policy,
@@ -24,8 +25,10 @@ static int cpufreq_governor_performance(struct cpufreq_policy *policy,
switch (event) {
case CPUFREQ_GOV_START:
case CPUFREQ_GOV_LIMITS:
- dprintk("setting to %u kHz because of event %u\n", policy->max, event);
- __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
+ dprintk("setting to %u kHz because of event %u\n",
+ policy->max, event);
+ __cpufreq_driver_target(policy, policy->max,
+ CPUFREQ_RELATION_H);
break;
default:
break;
diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c
index 0a2596044e6..13fe06b94b0 100644
--- a/drivers/cpufreq/cpufreq_powersave.c
+++ b/drivers/cpufreq/cpufreq_powersave.c
@@ -15,7 +15,8 @@
#include <linux/cpufreq.h>
#include <linux/init.h>
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "powersave", msg)
+#define dprintk(msg...) \
+ cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "powersave", msg)
static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
unsigned int event)
@@ -23,8 +24,10 @@ static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
switch (event) {
case CPUFREQ_GOV_START:
case CPUFREQ_GOV_LIMITS:
- dprintk("setting to %u kHz because of event %u\n", policy->min, event);
- __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
+ dprintk("setting to %u kHz because of event %u\n",
+ policy->min, event);
+ __cpufreq_driver_target(policy, policy->min,
+ CPUFREQ_RELATION_L);
break;
default:
break;
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index c2ecc599dc5..91ad342a605 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -285,6 +285,7 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
stat = cpufreq_stats_table[freq->cpu];
if (!stat)
return 0;
+
old_index = freq_table_get_index(stat, freq->old);
new_index = freq_table_get_index(stat, freq->new);
@@ -292,6 +293,9 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
if (old_index == new_index)
return 0;
+ if (old_index == -1 || new_index == -1)
+ return 0;
+
spin_lock(&cpufreq_stats_lock);
stat->last_index = new_index;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
@@ -351,8 +355,8 @@ __init cpufreq_stats_init(void)
register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
- cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE,
- (void *)(long)cpu);
+ cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
+ CPU_ONLINE, (void *)(long)cpu);
}
return 0;
}
@@ -368,14 +372,15 @@ __exit cpufreq_stats_exit(void)
unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
lock_cpu_hotplug();
for_each_online_cpu(cpu) {
- cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD,
- (void *)(long)cpu);
+ cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
+ CPU_DEAD, (void *)(long)cpu);
}
unlock_cpu_hotplug();
}
MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
-MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats through sysfs filesystem");
+MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats"
+ "through sysfs filesystem");
MODULE_LICENSE ("GPL");
module_init(cpufreq_stats_init);
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index a06c204589c..2a4eb0bfaf3 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -131,19 +131,26 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
unsigned int event)
{
unsigned int cpu = policy->cpu;
+ int rc = 0;
+
switch (event) {
case CPUFREQ_GOV_START:
if (!cpu_online(cpu))
return -EINVAL;
BUG_ON(!policy->cur);
mutex_lock(&userspace_mutex);
+ rc = sysfs_create_file (&policy->kobj,
+ &freq_attr_scaling_setspeed.attr);
+ if (rc)
+ goto start_out;
+
cpu_is_managed[cpu] = 1;
cpu_min_freq[cpu] = policy->min;
cpu_max_freq[cpu] = policy->max;
cpu_cur_freq[cpu] = policy->cur;
cpu_set_freq[cpu] = policy->cur;
- sysfs_create_file (&policy->kobj, &freq_attr_scaling_setspeed.attr);
dprintk("managing cpu %u started (%u - %u kHz, currently %u kHz)\n", cpu, cpu_min_freq[cpu], cpu_max_freq[cpu], cpu_cur_freq[cpu]);
+start_out:
mutex_unlock(&userspace_mutex);
break;
case CPUFREQ_GOV_STOP:
@@ -180,7 +187,7 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
mutex_unlock(&userspace_mutex);
break;
}
- return 0;
+ return rc;
}
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 551f4ccf87f..e7490925fdc 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -9,7 +9,8 @@
#include <linux/init.h>
#include <linux/cpufreq.h>
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg)
+#define dprintk(msg...) \
+ cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg)
/*********************************************************************
* FREQUENCY TABLE HELPERS *
@@ -29,7 +30,8 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
continue;
}
- dprintk("table entry %u: %u kHz, %u index\n", i, freq, table[i].index);
+ dprintk("table entry %u: %u kHz, %u index\n",
+ i, freq, table[i].index);
if (freq < min_freq)
min_freq = freq;
if (freq > max_freq)
@@ -54,13 +56,14 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
unsigned int i;
unsigned int count = 0;
- dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu);
+ dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n",
+ policy->min, policy->max, policy->cpu);
if (!cpu_online(policy->cpu))
return -EINVAL;
- cpufreq_verify_within_limits(policy,
- policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
@@ -75,10 +78,11 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
if (!count)
policy->max = next_larger;
- cpufreq_verify_within_limits(policy,
- policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
- dprintk("verification lead to (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu);
+ dprintk("verification lead to (%u - %u kHz) for cpu %u\n",
+ policy->min, policy->max, policy->cpu);
return 0;
}
@@ -101,7 +105,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
};
unsigned int i;
- dprintk("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu);
+ dprintk("request for target %u kHz (relation: %u) for cpu %u\n",
+ target_freq, relation, policy->cpu);
switch (relation) {
case CPUFREQ_RELATION_H:
@@ -192,7 +197,10 @@ static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
}
struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
- .attr = { .name = "scaling_available_frequencies", .mode = 0444, .owner=THIS_MODULE },
+ .attr = { .name = "scaling_available_frequencies",
+ .mode = 0444,
+ .owner=THIS_MODULE
+ },
.show = show_available_freqs,
};
EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index e816535ab30..ff8c4beaace 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -51,9 +51,11 @@ config CRYPTO_DEV_PADLOCK_SHA
If unsure say M. The compiled module will be
called padlock-sha.ko
+source "arch/s390/crypto/Kconfig"
+
config CRYPTO_DEV_GEODE
tristate "Support for the Geode LX AES engine"
- depends on CRYPTO && X86_32
+ depends on CRYPTO && X86_32 && PCI
select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
default m
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 43a68398656..31ea405f2ee 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -457,7 +457,7 @@ static struct pci_driver geode_aes_driver = {
static int __init
geode_aes_init(void)
{
- return pci_module_init(&geode_aes_driver);
+ return pci_register_driver(&geode_aes_driver);
}
static void __exit
diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c
index ca4e67a022d..22b62b3cd14 100644
--- a/drivers/fc4/fc.c
+++ b/drivers/fc4/fc.c
@@ -266,7 +266,7 @@ static void fcp_report_map_done(fc_channel *fc, int i, int status)
printk ("FC: Bad magic from REPORT_AL_MAP on %s - %08x\n", fc->name, p->magic);
fc->state = FC_STATE_OFFLINE;
} else {
- fc->posmap = (fcp_posmap *)kzalloc(sizeof(fcp_posmap)+p->len, GFP_KERNEL);
+ fc->posmap = kzalloc(sizeof(fcp_posmap)+p->len, GFP_KERNEL);
if (!fc->posmap) {
printk("FC: Not enough memory, offlining channel\n");
fc->state = FC_STATE_OFFLINE;
@@ -355,7 +355,7 @@ void fcp_register(fc_channel *fc, u8 type, int unregister)
for (i = fc->can_queue; i < fc->scsi_bitmap_end; i++)
set_bit (i, fc->scsi_bitmap);
fc->scsi_free = fc->can_queue;
- fc->cmd_slots = (fcp_cmnd **)kzalloc(slots * sizeof(fcp_cmnd*), GFP_KERNEL);
+ fc->cmd_slots = kzalloc(slots * sizeof(fcp_cmnd*), GFP_KERNEL);
fc->abort_count = 0;
} else {
fc->scsi_name[0] = 0;
@@ -933,7 +933,7 @@ int fcp_scsi_dev_reset(struct scsi_cmnd *SCpnt)
DECLARE_MUTEX_LOCKED(sem);
if (!fc->rst_pkt) {
- fc->rst_pkt = (struct scsi_cmnd *) kmalloc(sizeof(SCpnt), GFP_KERNEL);
+ fc->rst_pkt = kmalloc(sizeof(SCpnt), GFP_KERNEL);
if (!fc->rst_pkt) return FAILED;
fcmd = FCP_CMND(fc->rst_pkt);
@@ -1107,7 +1107,7 @@ int fc_do_plogi(fc_channel *fc, unsigned char alpa, fc_wwn *node, fc_wwn *nport)
logi *l;
int status;
- l = (logi *)kzalloc(2 * sizeof(logi), GFP_KERNEL);
+ l = kzalloc(2 * sizeof(logi), GFP_KERNEL);
if (!l) return -ENOMEM;
l->code = LS_PLOGI;
memcpy (&l->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn));
@@ -1141,7 +1141,7 @@ int fc_do_prli(fc_channel *fc, unsigned char alpa)
prli *p;
int status;
- p = (prli *)kzalloc(2 * sizeof(prli), GFP_KERNEL);
+ p = kzalloc(2 * sizeof(prli), GFP_KERNEL);
if (!p) return -ENOMEM;
p->code = LS_PRLI;
p->params[0] = 0x08002000;
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 5ab5e393b88..c6281ccd4fe 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -122,8 +122,6 @@ struct efivar_entry {
struct kobject kobj;
};
-#define get_efivar_entry(n) list_entry(n, struct efivar_entry, list)
-
struct efivar_attribute {
struct attribute attr;
ssize_t (*show) (struct efivar_entry *entry, char *buf);
@@ -386,9 +384,6 @@ static struct sysfs_ops efivar_attr_ops = {
static void efivar_release(struct kobject *kobj)
{
struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj);
- spin_lock(&efivars_lock);
- list_del(&var->list);
- spin_unlock(&efivars_lock);
kfree(var);
}
@@ -430,9 +425,8 @@ static ssize_t
efivar_create(struct subsystem *sub, const char *buf, size_t count)
{
struct efi_variable *new_var = (struct efi_variable *)buf;
- struct efivar_entry *search_efivar = NULL;
+ struct efivar_entry *search_efivar, *n;
unsigned long strsize1, strsize2;
- struct list_head *pos, *n;
efi_status_t status = EFI_NOT_FOUND;
int found = 0;
@@ -444,8 +438,7 @@ efivar_create(struct subsystem *sub, const char *buf, size_t count)
/*
* Does this variable already exist?
*/
- list_for_each_safe(pos, n, &efivar_list) {
- search_efivar = get_efivar_entry(pos);
+ list_for_each_entry_safe(search_efivar, n, &efivar_list, list) {
strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
strsize2 = utf8_strsize(new_var->VariableName, 1024);
if (strsize1 == strsize2 &&
@@ -490,9 +483,8 @@ static ssize_t
efivar_delete(struct subsystem *sub, const char *buf, size_t count)
{
struct efi_variable *del_var = (struct efi_variable *)buf;
- struct efivar_entry *search_efivar = NULL;
+ struct efivar_entry *search_efivar, *n;
unsigned long strsize1, strsize2;
- struct list_head *pos, *n;
efi_status_t status = EFI_NOT_FOUND;
int found = 0;
@@ -504,8 +496,7 @@ efivar_delete(struct subsystem *sub, const char *buf, size_t count)
/*
* Does this variable already exist?
*/
- list_for_each_safe(pos, n, &efivar_list) {
- search_efivar = get_efivar_entry(pos);
+ list_for_each_entry_safe(search_efivar, n, &efivar_list, list) {
strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
strsize2 = utf8_strsize(del_var->VariableName, 1024);
if (strsize1 == strsize2 &&
@@ -537,9 +528,9 @@ efivar_delete(struct subsystem *sub, const char *buf, size_t count)
spin_unlock(&efivars_lock);
return -EIO;
}
+ list_del(&search_efivar->list);
/* We need to release this lock before unregistering. */
spin_unlock(&efivars_lock);
-
efivar_unregister(search_efivar);
/* It's dead Jim.... */
@@ -768,10 +759,14 @@ out_free:
static void __exit
efivars_exit(void)
{
- struct list_head *pos, *n;
+ struct efivar_entry *entry, *n;
- list_for_each_safe(pos, n, &efivar_list)
- efivar_unregister(get_efivar_entry(pos));
+ list_for_each_entry_safe(entry, n, &efivar_list, list) {
+ spin_lock(&efivars_lock);
+ list_del(&entry->list);
+ spin_unlock(&efivars_lock);
+ efivar_unregister(entry);
+ }
subsystem_unregister(&vars_subsys);
firmware_unregister(&efi_subsys);
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
index c2ad72fefd9..2b4b76e8bd7 100644
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -26,7 +26,7 @@ setup_serial_console(struct pcdp_uart *uart)
static char options[64], *p = options;
char parity;
- mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
+ mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
p += sprintf(p, "console=uart,%s,0x%lx",
mmio ? "mmio" : "io", uart->addr.address);
if (uart->baud) {
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
new file mode 100644
index 00000000000..850788f4dd2
--- /dev/null
+++ b/drivers/hid/Kconfig
@@ -0,0 +1,40 @@
+#
+# HID driver configuration
+#
+menu "HID Devices"
+ depends on INPUT
+
+config HID
+ tristate "Generic HID support"
+ depends on INPUT
+ default y
+ ---help---
+ A human interface device (HID) is a type of computer device that
+ interacts directly with and takes input from humans. The term "HID"
+ most commonly used to refer to the USB-HID specification, but other
+ devices (such as, but not strictly limited to, Bluetooth) are
+ designed using HID specification (this involves certain keyboards,
+ mice, tablets, etc). This option compiles into kernel the generic
+ HID layer code (parser, usages, etc.), which can then be used by
+ transport-specific HID implementation (like USB or Bluetooth).
+
+ For docs and specs, see http://www.usb.org/developers/hidpage/
+
+ If unsure, say Y
+
+config HID_DEBUG
+ bool "HID debugging support"
+ depends on HID
+ ---help---
+ This option lets the HID layer output diagnostics about its internal
+ state, resolve HID usages, dump HID fields, etc. Individual HID drivers
+ use this debugging facility to output information about individual HID
+ devices, etc.
+
+ This feature is useful for those who are either debugging the HID parser
+ or any HID hardware device.
+
+ If unsure, say N
+
+endmenu
+
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
new file mode 100644
index 00000000000..52e97d8f3c9
--- /dev/null
+++ b/drivers/hid/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the HID driver
+#
+hid-objs := hid-core.o hid-input.o
+
+obj-$(CONFIG_HID) += hid.o
+hid-$(CONFIG_HID_DEBUG) += hid-debug.o
+
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
new file mode 100644
index 00000000000..8c7d48eff7b
--- /dev/null
+++ b/drivers/hid/hid-core.c
@@ -0,0 +1,998 @@
+/*
+ * HID support for Linux
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <linux/input.h>
+#include <linux/wait.h>
+
+#include <linux/hid.h>
+#include <linux/hiddev.h>
+#include <linux/hid-debug.h>
+
+/*
+ * Version Information
+ */
+
+#define DRIVER_VERSION "v2.6"
+#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
+#define DRIVER_DESC "HID core driver"
+#define DRIVER_LICENSE "GPL"
+
+/*
+ * Register a new report for a device.
+ */
+
+static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
+{
+ struct hid_report_enum *report_enum = device->report_enum + type;
+ struct hid_report *report;
+
+ if (report_enum->report_id_hash[id])
+ return report_enum->report_id_hash[id];
+
+ if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
+ return NULL;
+
+ if (id != 0)
+ report_enum->numbered = 1;
+
+ report->id = id;
+ report->type = type;
+ report->size = 0;
+ report->device = device;
+ report_enum->report_id_hash[id] = report;
+
+ list_add_tail(&report->list, &report_enum->report_list);
+
+ return report;
+}
+
+/*
+ * Register a new field for this report.
+ */
+
+static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
+{
+ struct hid_field *field;
+
+ if (report->maxfield == HID_MAX_FIELDS) {
+ dbg("too many fields in report");
+ return NULL;
+ }
+
+ if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+ + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
+
+ field->index = report->maxfield++;
+ report->field[field->index] = field;
+ field->usage = (struct hid_usage *)(field + 1);
+ field->value = (unsigned *)(field->usage + usages);
+ field->report = report;
+
+ return field;
+}
+
+/*
+ * Open a collection. The type/usage is pushed on the stack.
+ */
+
+static int open_collection(struct hid_parser *parser, unsigned type)
+{
+ struct hid_collection *collection;
+ unsigned usage;
+
+ usage = parser->local.usage[0];
+
+ if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
+ dbg("collection stack overflow");
+ return -1;
+ }
+
+ if (parser->device->maxcollection == parser->device->collection_size) {
+ collection = kmalloc(sizeof(struct hid_collection) *
+ parser->device->collection_size * 2, GFP_KERNEL);
+ if (collection == NULL) {
+ dbg("failed to reallocate collection array");
+ return -1;
+ }
+ memcpy(collection, parser->device->collection,
+ sizeof(struct hid_collection) *
+ parser->device->collection_size);
+ memset(collection + parser->device->collection_size, 0,
+ sizeof(struct hid_collection) *
+ parser->device->collection_size);
+ kfree(parser->device->collection);
+ parser->device->collection = collection;
+ parser->device->collection_size *= 2;
+ }
+
+ parser->collection_stack[parser->collection_stack_ptr++] =
+ parser->device->maxcollection;
+
+ collection = parser->device->collection +
+ parser->device->maxcollection++;
+ collection->type = type;
+ collection->usage = usage;
+ collection->level = parser->collection_stack_ptr - 1;
+
+ if (type == HID_COLLECTION_APPLICATION)
+ parser->device->maxapplication++;
+
+ return 0;
+}
+
+/*
+ * Close a collection.
+ */
+
+static int close_collection(struct hid_parser *parser)
+{
+ if (!parser->collection_stack_ptr) {
+ dbg("collection stack underflow");
+ return -1;
+ }
+ parser->collection_stack_ptr--;
+ return 0;
+}
+
+/*
+ * Climb up the stack, search for the specified collection type
+ * and return the usage.
+ */
+
+static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
+{
+ int n;
+ for (n = parser->collection_stack_ptr - 1; n >= 0; n--)
+ if (parser->device->collection[parser->collection_stack[n]].type == type)
+ return parser->device->collection[parser->collection_stack[n]].usage;
+ return 0; /* we know nothing about this usage type */
+}
+
+/*
+ * Add a usage to the temporary parser table.
+ */
+
+static int hid_add_usage(struct hid_parser *parser, unsigned usage)
+{
+ if (parser->local.usage_index >= HID_MAX_USAGES) {
+ dbg("usage index exceeded");
+ return -1;
+ }
+ parser->local.usage[parser->local.usage_index] = usage;
+ parser->local.collection_index[parser->local.usage_index] =
+ parser->collection_stack_ptr ?
+ parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
+ parser->local.usage_index++;
+ return 0;
+}
+
+/*
+ * Register a new field for this report.
+ */
+
+static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags)
+{
+ struct hid_report *report;
+ struct hid_field *field;
+ int usages;
+ unsigned offset;
+ int i;
+
+ if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
+ dbg("hid_register_report failed");
+ return -1;
+ }
+
+ if (parser->global.logical_maximum < parser->global.logical_minimum) {
+ dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
+ return -1;
+ }
+
+ offset = report->size;
+ report->size += parser->global.report_size * parser->global.report_count;
+
+ if (!parser->local.usage_index) /* Ignore padding fields */
+ return 0;
+
+ usages = max_t(int, parser->local.usage_index, parser->global.report_count);
+
+ if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
+ return 0;
+
+ field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
+ field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
+ field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
+
+ for (i = 0; i < usages; i++) {
+ int j = i;
+ /* Duplicate the last usage we parsed if we have excess values */
+ if (i >= parser->local.usage_index)
+ j = parser->local.usage_index - 1;
+ field->usage[i].hid = parser->local.usage[j];
+ field->usage[i].collection_index =
+ parser->local.collection_index[j];
+ }
+
+ field->maxusage = usages;
+ field->flags = flags;
+ field->report_offset = offset;
+ field->report_type = report_type;
+ field->report_size = parser->global.report_size;
+ field->report_count = parser->global.report_count;
+ field->logical_minimum = parser->global.logical_minimum;
+ field->logical_maximum = parser->global.logical_maximum;
+ field->physical_minimum = parser->global.physical_minimum;
+ field->physical_maximum = parser->global.physical_maximum;
+ field->unit_exponent = parser->global.unit_exponent;
+ field->unit = parser->global.unit;
+
+ return 0;
+}
+
+/*
+ * Read data value from item.
+ */
+
+static u32 item_udata(struct hid_item *item)
+{
+ switch (item->size) {
+ case 1: return item->data.u8;
+ case 2: return item->data.u16;
+ case 4: return item->data.u32;
+ }
+ return 0;
+}
+
+static s32 item_sdata(struct hid_item *item)
+{
+ switch (item->size) {
+ case 1: return item->data.s8;
+ case 2: return item->data.s16;
+ case 4: return item->data.s32;
+ }
+ return 0;
+}
+
+/*
+ * Process a global item.
+ */
+
+static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
+{
+ switch (item->tag) {
+
+ case HID_GLOBAL_ITEM_TAG_PUSH:
+
+ if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
+ dbg("global enviroment stack overflow");
+ return -1;
+ }
+
+ memcpy(parser->global_stack + parser->global_stack_ptr++,
+ &parser->global, sizeof(struct hid_global));
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_POP:
+
+ if (!parser->global_stack_ptr) {
+ dbg("global enviroment stack underflow");
+ return -1;
+ }
+
+ memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
+ sizeof(struct hid_global));
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+ parser->global.usage_page = item_udata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+ parser->global.logical_minimum = item_sdata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+ if (parser->global.logical_minimum < 0)
+ parser->global.logical_maximum = item_sdata(item);
+ else
+ parser->global.logical_maximum = item_udata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
+ parser->global.physical_minimum = item_sdata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
+ if (parser->global.physical_minimum < 0)
+ parser->global.physical_maximum = item_sdata(item);
+ else
+ parser->global.physical_maximum = item_udata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
+ parser->global.unit_exponent = item_sdata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_UNIT:
+ parser->global.unit = item_udata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+ if ((parser->global.report_size = item_udata(item)) > 32) {
+ dbg("invalid report_size %d", parser->global.report_size);
+ return -1;
+ }
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+ if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
+ dbg("invalid report_count %d", parser->global.report_count);
+ return -1;
+ }
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+ if ((parser->global.report_id = item_udata(item)) == 0) {
+ dbg("report_id 0 is invalid");
+ return -1;
+ }
+ return 0;
+
+ default:
+ dbg("unknown global tag 0x%x", item->tag);
+ return -1;
+ }
+}
+
+/*
+ * Process a local item.
+ */
+
+static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
+{
+ __u32 data;
+ unsigned n;
+
+ if (item->size == 0) {
+ dbg("item data expected for local item");
+ return -1;
+ }
+
+ data = item_udata(item);
+
+ switch (item->tag) {
+
+ case HID_LOCAL_ITEM_TAG_DELIMITER:
+
+ if (data) {
+ /*
+ * We treat items before the first delimiter
+ * as global to all usage sets (branch 0).
+ * In the moment we process only these global
+ * items and the first delimiter set.
+ */
+ if (parser->local.delimiter_depth != 0) {
+ dbg("nested delimiters");
+ return -1;
+ }
+ parser->local.delimiter_depth++;
+ parser->local.delimiter_branch++;
+ } else {
+ if (parser->local.delimiter_depth < 1) {
+ dbg("bogus close delimiter");
+ return -1;
+ }
+ parser->local.delimiter_depth--;
+ }
+ return 1;
+
+ case HID_LOCAL_ITEM_TAG_USAGE:
+
+ if (parser->local.delimiter_branch > 1) {
+ dbg("alternative usage ignored");
+ return 0;
+ }
+
+ if (item->size <= 2)
+ data = (parser->global.usage_page << 16) + data;
+
+ return hid_add_usage(parser, data);
+
+ case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+
+ if (parser->local.delimiter_branch > 1) {
+ dbg("alternative usage ignored");
+ return 0;
+ }
+
+ if (item->size <= 2)
+ data = (parser->global.usage_page << 16) + data;
+
+ parser->local.usage_minimum = data;
+ return 0;
+
+ case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+
+ if (parser->local.delimiter_branch > 1) {
+ dbg("alternative usage ignored");
+ return 0;
+ }
+
+ if (item->size <= 2)
+ data = (parser->global.usage_page << 16) + data;
+
+ for (n = parser->local.usage_minimum; n <= data; n++)
+ if (hid_add_usage(parser, n)) {
+ dbg("hid_add_usage failed\n");
+ return -1;
+ }
+ return 0;
+
+ default:
+
+ dbg("unknown local item tag 0x%x", item->tag);
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * Process a main item.
+ */
+
+static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
+{
+ __u32 data;
+ int ret;
+
+ data = item_udata(item);
+
+ switch (item->tag) {
+ case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+ ret = open_collection(parser, data & 0xff);
+ break;
+ case HID_MAIN_ITEM_TAG_END_COLLECTION:
+ ret = close_collection(parser);
+ break;
+ case HID_MAIN_ITEM_TAG_INPUT:
+ ret = hid_add_field(parser, HID_INPUT_REPORT, data);
+ break;
+ case HID_MAIN_ITEM_TAG_OUTPUT:
+ ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
+ break;
+ case HID_MAIN_ITEM_TAG_FEATURE:
+ ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
+ break;
+ default:
+ dbg("unknown main item tag 0x%x", item->tag);
+ ret = 0;
+ }
+
+ memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */
+
+ return ret;
+}
+
+/*
+ * Process a reserved item.
+ */
+
+static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item)
+{
+ dbg("reserved item type, tag 0x%x", item->tag);
+ return 0;
+}
+
+/*
+ * Free a report and all registered fields. The field->usage and
+ * field->value table's are allocated behind the field, so we need
+ * only to free(field) itself.
+ */
+
+static void hid_free_report(struct hid_report *report)
+{
+ unsigned n;
+
+ for (n = 0; n < report->maxfield; n++)
+ kfree(report->field[n]);
+ kfree(report);
+}
+
+/*
+ * Free a device structure, all reports, and all fields.
+ */
+
+void hid_free_device(struct hid_device *device)
+{
+ unsigned i,j;
+
+ for (i = 0; i < HID_REPORT_TYPES; i++) {
+ struct hid_report_enum *report_enum = device->report_enum + i;
+
+ for (j = 0; j < 256; j++) {
+ struct hid_report *report = report_enum->report_id_hash[j];
+ if (report)
+ hid_free_report(report);
+ }
+ }
+
+ kfree(device->rdesc);
+ kfree(device->collection);
+ kfree(device);
+}
+EXPORT_SYMBOL_GPL(hid_free_device);
+
+/*
+ * Fetch a report description item from the data stream. We support long
+ * items, though they are not used yet.
+ */
+
+static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
+{
+ u8 b;
+
+ if ((end - start) <= 0)
+ return NULL;
+
+ b = *start++;
+
+ item->type = (b >> 2) & 3;
+ item->tag = (b >> 4) & 15;
+
+ if (item->tag == HID_ITEM_TAG_LONG) {
+
+ item->format = HID_ITEM_FORMAT_LONG;
+
+ if ((end - start) < 2)
+ return NULL;
+
+ item->size = *start++;
+ item->tag = *start++;
+
+ if ((end - start) < item->size)
+ return NULL;
+
+ item->data.longdata = start;
+ start += item->size;
+ return start;
+ }
+
+ item->format = HID_ITEM_FORMAT_SHORT;
+ item->size = b & 3;
+
+ switch (item->size) {
+
+ case 0:
+ return start;
+
+ case 1:
+ if ((end - start) < 1)
+ return NULL;
+ item->data.u8 = *start++;
+ return start;
+
+ case 2:
+ if ((end - start) < 2)
+ return NULL;
+ item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));
+ start = (__u8 *)((__le16 *)start + 1);
+ return start;
+
+ case 3:
+ item->size++;
+ if ((end - start) < 4)
+ return NULL;
+ item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start));
+ start = (__u8 *)((__le32 *)start + 1);
+ return start;
+ }
+
+ return NULL;
+}
+
+/*
+ * Parse a report description into a hid_device structure. Reports are
+ * enumerated, fields are attached to these reports.
+ */
+
+struct hid_device *hid_parse_report(__u8 *start, unsigned size)
+{
+ struct hid_device *device;
+ struct hid_parser *parser;
+ struct hid_item item;
+ __u8 *end;
+ unsigned i;
+ static int (*dispatch_type[])(struct hid_parser *parser,
+ struct hid_item *item) = {
+ hid_parser_main,
+ hid_parser_global,
+ hid_parser_local,
+ hid_parser_reserved
+ };
+
+ if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
+ return NULL;
+
+ if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
+ HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
+ kfree(device);
+ return NULL;
+ }
+ device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+
+ for (i = 0; i < HID_REPORT_TYPES; i++)
+ INIT_LIST_HEAD(&device->report_enum[i].report_list);
+
+ if (!(device->rdesc = kmalloc(size, GFP_KERNEL))) {
+ kfree(device->collection);
+ kfree(device);
+ return NULL;
+ }
+ memcpy(device->rdesc, start, size);
+ device->rsize = size;
+
+ if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
+ kfree(device->rdesc);
+ kfree(device->collection);
+ kfree(device);
+ return NULL;
+ }
+ parser->device = device;
+
+ end = start + size;
+ while ((start = fetch_item(start, end, &item)) != NULL) {
+
+ if (item.format != HID_ITEM_FORMAT_SHORT) {
+ dbg("unexpected long global item");
+ kfree(device->collection);
+ hid_free_device(device);
+ kfree(parser);
+ return NULL;
+ }
+
+ if (dispatch_type[item.type](parser, &item)) {
+ dbg("item %u %u %u %u parsing failed\n",
+ item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
+ kfree(device->collection);
+ hid_free_device(device);
+ kfree(parser);
+ return NULL;
+ }
+
+ if (start == end) {
+ if (parser->collection_stack_ptr) {
+ dbg("unbalanced collection at end of report description");
+ kfree(device->collection);
+ hid_free_device(device);
+ kfree(parser);
+ return NULL;
+ }
+ if (parser->local.delimiter_depth) {
+ dbg("unbalanced delimiter at end of report description");
+ kfree(device->collection);
+ hid_free_device(device);
+ kfree(parser);
+ return NULL;
+ }
+ kfree(parser);
+ return device;
+ }
+ }
+
+ dbg("item fetching failed at offset %d\n", (int)(end - start));
+ kfree(device->collection);
+ hid_free_device(device);
+ kfree(parser);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(hid_parse_report);
+
+/*
+ * Convert a signed n-bit integer to signed 32-bit integer. Common
+ * cases are done through the compiler, the screwed things has to be
+ * done by hand.
+ */
+
+static s32 snto32(__u32 value, unsigned n)
+{
+ switch (n) {
+ case 8: return ((__s8)value);
+ case 16: return ((__s16)value);
+ case 32: return ((__s32)value);
+ }
+ return value & (1 << (n - 1)) ? value | (-1 << n) : value;
+}
+
+/*
+ * Convert a signed 32-bit integer to a signed n-bit integer.
+ */
+
+static u32 s32ton(__s32 value, unsigned n)
+{
+ s32 a = value >> (n - 1);
+ if (a && a != -1)
+ return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
+ return value & ((1 << n) - 1);
+}
+
+/*
+ * Extract/implement a data field from/to a little endian report (bit array).
+ *
+ * Code sort-of follows HID spec:
+ * http://www.usb.org/developers/devclass_docs/HID1_11.pdf
+ *
+ * While the USB HID spec allows unlimited length bit fields in "report
+ * descriptors", most devices never use more than 16 bits.
+ * One model of UPS is claimed to report "LINEV" as a 32-bit field.
+ * Search linux-kernel and linux-usb-devel archives for "hid-core extract".
+ */
+
+static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
+{
+ u64 x;
+
+ WARN_ON(n > 32);
+
+ report += offset >> 3; /* adjust byte index */
+ offset &= 7; /* now only need bit offset into one byte */
+ x = get_unaligned((u64 *) report);
+ x = le64_to_cpu(x);
+ x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */
+ return (u32) x;
+}
+
+/*
+ * "implement" : set bits in a little endian bit stream.
+ * Same concepts as "extract" (see comments above).
+ * The data mangled in the bit stream remains in little endian
+ * order the whole time. It make more sense to talk about
+ * endianness of register values by considering a register
+ * a "cached" copy of the little endiad bit stream.
+ */
+static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
+{
+ u64 x;
+ u64 m = (1ULL << n) - 1;
+
+ WARN_ON(n > 32);
+
+ WARN_ON(value > m);
+ value &= m;
+
+ report += offset >> 3;
+ offset &= 7;
+
+ x = get_unaligned((u64 *)report);
+ x &= cpu_to_le64(~(m << offset));
+ x |= cpu_to_le64(((u64) value) << offset);
+ put_unaligned(x, (u64 *) report);
+}
+
+/*
+ * Search an array for a value.
+ */
+
+static __inline__ int search(__s32 *array, __s32 value, unsigned n)
+{
+ while (n--) {
+ if (*array++ == value)
+ return 0;
+ }
+ return -1;
+}
+
+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);
+ if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+}
+
+/*
+ * Analyse a received field, and fetch the data from it. The field
+ * content is stored for next report processing (we do differential
+ * reporting to the layer).
+ */
+
+void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt)
+{
+ unsigned n;
+ unsigned count = field->report_count;
+ unsigned offset = field->report_offset;
+ unsigned size = field->report_size;
+ __s32 min = field->logical_minimum;
+ __s32 max = field->logical_maximum;
+ __s32 *value;
+
+ if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
+ return;
+
+ for (n = 0; n < count; n++) {
+
+ value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :
+ extract(data, offset + n * size, size);
+
+ if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */
+ && value[n] >= min && value[n] <= max
+ && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
+ goto exit;
+ }
+
+ for (n = 0; n < count; n++) {
+
+ if (HID_MAIN_ITEM_VARIABLE & field->flags) {
+ 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);
+
+ 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);
+ }
+
+ memcpy(field->value, value, count * sizeof(__s32));
+exit:
+ kfree(value);
+}
+EXPORT_SYMBOL_GPL(hid_input_field);
+
+/*
+ * Output the field into the report.
+ */
+
+static void hid_output_field(struct hid_field *field, __u8 *data)
+{
+ unsigned count = field->report_count;
+ unsigned offset = field->report_offset;
+ unsigned size = field->report_size;
+ unsigned n;
+
+ /* make sure the unused bits in the last byte are zeros */
+ if (count > 0 && size > 0)
+ data[(count*size-1)/8] = 0;
+
+ for (n = 0; n < count; n++) {
+ if (field->logical_minimum < 0) /* signed values */
+ implement(data, offset + n * size, size, s32ton(field->value[n], size));
+ else /* unsigned values */
+ implement(data, offset + n * size, size, field->value[n]);
+ }
+}
+
+/*
+ * Create a report.
+ */
+
+void hid_output_report(struct hid_report *report, __u8 *data)
+{
+ unsigned n;
+
+ if (report->id > 0)
+ *data++ = report->id;
+
+ for (n = 0; n < report->maxfield; n++)
+ hid_output_field(report->field[n], data);
+}
+EXPORT_SYMBOL_GPL(hid_output_report);
+
+/*
+ * Set a field value. The report this field belongs to has to be
+ * created and transferred to the device, to set this value in the
+ * device.
+ */
+
+int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
+{
+ unsigned size = field->report_size;
+
+ hid_dump_input(field->usage + offset, value);
+
+ if (offset >= field->report_count) {
+ dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count);
+ hid_dump_field(field, 8);
+ return -1;
+ }
+ if (field->logical_minimum < 0) {
+ if (value != snto32(s32ton(value, size), size)) {
+ dbg("value %d is out of range", value);
+ return -1;
+ }
+ }
+ field->value[offset] = value;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hid_set_field);
+
+int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+{
+ struct hid_report_enum *report_enum = hid->report_enum + type;
+ struct hid_report *report;
+ int n, rsize;
+
+ if (!hid)
+ return -ENODEV;
+
+ if (!size) {
+ dbg("empty report");
+ return -1;
+ }
+
+#ifdef CONFIG_HID_DEBUG
+ printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
+#endif
+
+ n = 0; /* Normally report number is 0 */
+ if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */
+ n = *data++;
+ size--;
+ }
+
+#ifdef CONFIG_HID_DEBUG
+ {
+ int i;
+ printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size);
+ for (i = 0; i < size; i++)
+ printk(" %02x", data[i]);
+ printk("\n");
+ }
+#endif
+
+ if (!(report = report_enum->report_id_hash[n])) {
+ dbg("undefined report_id %d received", n);
+ return -1;
+ }
+
+ rsize = ((report->size - 1) >> 3) + 1;
+
+ if (size < rsize) {
+ dbg("report %d is too short, (%d < %d)", report->id, size, rsize);
+ return -1;
+ }
+
+ if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
+ hid->hiddev_report_event(hid, report);
+
+ for (n = 0; n < report->maxfield; n++)
+ hid_input_field(hid, report->field[n], data, interrupt);
+
+ if (hid->claimed & HID_CLAIMED_INPUT)
+ hidinput_report_event(hid, report);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hid_input_report);
+
+MODULE_LICENSE(DRIVER_LICENSE);
+
diff --git a/drivers/usb/input/hid-debug.h b/drivers/hid/hid-debug.c
index f04d6d75c09..89241be4ec9 100644
--- a/drivers/usb/input/hid-debug.h
+++ b/drivers/hid/hid-debug.c
@@ -3,6 +3,7 @@
*
* (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de>
* (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
+ * (c) 2007 Jiri Kosina
*
* Some debug stuff for the HID parser.
*/
@@ -27,7 +28,7 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
-#include <linux/input.h>
+#include <linux/hid.h>
struct hid_usage_entry {
unsigned page;
@@ -342,7 +343,7 @@ static void resolv_usage_page(unsigned page) {
printk("%04x", page);
}
-static void resolv_usage(unsigned usage) {
+void hid_resolv_usage(unsigned usage) {
const struct hid_usage_entry *p;
resolv_usage_page(usage >> 16);
@@ -358,27 +359,28 @@ static void resolv_usage(unsigned usage) {
}
printk("%04x", usage & 0xffff);
}
+EXPORT_SYMBOL_GPL(hid_resolv_usage);
__inline__ static void tab(int n) {
while (n--) printk(" ");
}
-static void hid_dump_field(struct hid_field *field, int n) {
+void hid_dump_field(struct hid_field *field, int n) {
int j;
if (field->physical) {
tab(n);
printk("Physical(");
- resolv_usage(field->physical); printk(")\n");
+ hid_resolv_usage(field->physical); printk(")\n");
}
if (field->logical) {
tab(n);
printk("Logical(");
- resolv_usage(field->logical); printk(")\n");
+ hid_resolv_usage(field->logical); printk(")\n");
}
tab(n); printk("Usage(%d)\n", field->maxusage);
for (j = 0; j < field->maxusage; j++) {
- tab(n+2);resolv_usage(field->usage[j].hid); printk("\n");
+ tab(n+2); hid_resolv_usage(field->usage[j].hid); printk("\n");
}
if (field->logical_minimum != field->logical_maximum) {
tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum);
@@ -454,8 +456,9 @@ static void hid_dump_field(struct hid_field *field, int n) {
printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
printk(")\n");
}
+EXPORT_SYMBOL_GPL(hid_dump_field);
-static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
+void hid_dump_device(struct hid_device *device) {
struct hid_report_enum *report_enum;
struct hid_report *report;
struct list_head *list;
@@ -482,13 +485,14 @@ static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
}
}
}
+EXPORT_SYMBOL_GPL(hid_dump_device);
-static void __attribute__((unused)) hid_dump_input(struct hid_usage *usage, __s32 value) {
+void hid_dump_input(struct hid_usage *usage, __s32 value) {
printk("hid-debug: input ");
- resolv_usage(usage->hid);
+ hid_resolv_usage(usage->hid);
printk(" = %d\n", value);
}
-
+EXPORT_SYMBOL_GPL(hid_dump_input);
static char *events[EV_MAX + 1] = {
[EV_SYN] = "Sync", [EV_KEY] = "Key",
@@ -700,9 +704,10 @@ static char *keys[KEY_MAX + 1] = {
static char *relatives[REL_MAX + 1] = {
[REL_X] = "X", [REL_Y] = "Y",
- [REL_Z] = "Z", [REL_HWHEEL] = "HWheel",
- [REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel",
- [REL_MISC] = "Misc",
+ [REL_Z] = "Z", [REL_RX] = "Rx",
+ [REL_RY] = "Ry", [REL_RZ] = "Rz",
+ [REL_HWHEEL] = "HWheel", [REL_DIAL] = "Dial",
+ [REL_WHEEL] = "Wheel", [REL_MISC] = "Misc",
};
static char *absolutes[ABS_MAX + 1] = {
@@ -750,8 +755,10 @@ static char **names[EV_MAX + 1] = {
[EV_SND] = sounds, [EV_REP] = repeats,
};
-static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) {
+void hid_resolv_event(__u8 type, __u16 code) {
printk("%s.%s", events[type] ? events[type] : "?",
names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
}
+EXPORT_SYMBOL_GPL(hid_resolv_event);
+
diff --git a/drivers/usb/input/hid-input.c b/drivers/hid/hid-input.c
index 3a7e5fbff02..25d180a24fc 100644
--- a/drivers/usb/input/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -2,8 +2,9 @@
* $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik
+ * Copyright (c) 2006 Jiri Kosina
*
- * USB HID to Linux Input mapping
+ * HID to Linux Input mapping
*/
/*
@@ -29,11 +30,14 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kernel.h>
-#include <linux/usb/input.h>
-#undef DEBUG
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
-#include "hid.h"
+static int hid_pb_fnmode = 1;
+module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644);
+MODULE_PARM_DESC(pb_fnmode,
+ "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
#define unk KEY_UNKNOWN
@@ -67,6 +71,7 @@ static const struct {
#define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0)
+#define map_rel_clear(c) do { map_rel(c); clear_bit(c, bit); } while (0)
#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
@@ -81,42 +86,42 @@ struct hidinput_key_translation {
static struct hidinput_key_translation powerbook_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
- { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY },
- { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY },
- { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY },
- { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY },
- { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY },
- { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY },
- { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY },
- { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY },
- { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY },
- { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY },
- { KEY_UP, KEY_PAGEUP },
- { KEY_DOWN, KEY_PAGEDOWN },
- { KEY_LEFT, KEY_HOME },
- { KEY_RIGHT, KEY_END },
+ { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY },
+ { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY },
+ { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY },
+ { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY },
+ { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY },
+ { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY },
+ { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY },
+ { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY },
+ { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY },
+ { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY },
+ { KEY_UP, KEY_PAGEUP },
+ { KEY_DOWN, KEY_PAGEDOWN },
+ { KEY_LEFT, KEY_HOME },
+ { KEY_RIGHT, KEY_END },
{ }
};
static struct hidinput_key_translation powerbook_numlock_keys[] = {
- { KEY_J, KEY_KP1 },
- { KEY_K, KEY_KP2 },
- { KEY_L, KEY_KP3 },
- { KEY_U, KEY_KP4 },
- { KEY_I, KEY_KP5 },
- { KEY_O, KEY_KP6 },
- { KEY_7, KEY_KP7 },
- { KEY_8, KEY_KP8 },
- { KEY_9, KEY_KP9 },
- { KEY_M, KEY_KP0 },
- { KEY_DOT, KEY_KPDOT },
- { KEY_SLASH, KEY_KPPLUS },
+ { KEY_J, KEY_KP1 },
+ { KEY_K, KEY_KP2 },
+ { KEY_L, KEY_KP3 },
+ { KEY_U, KEY_KP4 },
+ { KEY_I, KEY_KP5 },
+ { KEY_O, KEY_KP6 },
+ { KEY_7, KEY_KP7 },
+ { KEY_8, KEY_KP8 },
+ { KEY_9, KEY_KP9 },
+ { KEY_M, KEY_KP0 },
+ { KEY_DOT, KEY_KPDOT },
+ { KEY_SLASH, KEY_KPPLUS },
{ KEY_SEMICOLON, KEY_KPMINUS },
- { KEY_P, KEY_KPASTERISK },
- { KEY_MINUS, KEY_KPEQUAL },
- { KEY_0, KEY_KPSLASH },
- { KEY_F6, KEY_NUMLOCK },
- { KEY_KPENTER, KEY_KPENTER },
+ { KEY_P, KEY_KPASTERISK },
+ { KEY_MINUS, KEY_KPEQUAL },
+ { KEY_0, KEY_KPSLASH },
+ { KEY_F6, KEY_NUMLOCK },
+ { KEY_KPENTER, KEY_KPENTER },
{ KEY_BACKSPACE, KEY_BACKSPACE },
{ }
};
@@ -127,11 +132,6 @@ static struct hidinput_key_translation powerbook_iso_keyboard[] = {
{ }
};
-static int usbhid_pb_fnmode = 1;
-module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
-MODULE_PARM_DESC(pb_fnmode,
- "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
-
static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
{
struct hidinput_key_translation *trans;
@@ -145,7 +145,7 @@ static struct hidinput_key_translation *find_translation(struct hidinput_key_tra
}
static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
- struct hid_usage *usage, __s32 value)
+ struct hid_usage *usage, __s32 value)
{
struct hidinput_key_translation *trans;
@@ -158,7 +158,7 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
return 1;
}
- if (usbhid_pb_fnmode) {
+ if (hid_pb_fnmode) {
int do_translate;
trans = find_translation(powerbook_fn_keys, usage->code);
@@ -167,8 +167,8 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
do_translate = 1;
else if (trans->flags & POWERBOOK_FLAG_FKEY)
do_translate =
- (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
- (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
+ (hid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
+ (hid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
else
do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
@@ -185,7 +185,7 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
}
if (test_bit(usage->code, hid->pb_pressed_numlock) ||
- test_bit(LED_NUML, input->led)) {
+ test_bit(LED_NUML, input->led)) {
trans = find_translation(powerbook_numlock_keys, usage->code);
if (trans) {
@@ -227,10 +227,11 @@ static void hidinput_pb_setup(struct input_dev *input)
for (trans = powerbook_iso_keyboard; trans->from; trans++)
set_bit(trans->to, input->keybit);
+
}
#else
static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
- struct hid_usage *usage, __s32 value)
+ struct hid_usage *usage, __s32 value)
{
return 0;
}
@@ -250,9 +251,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
field->hidinput = hidinput;
-#ifdef DEBUG
+#ifdef CONFIG_HID_DEBUG
printk(KERN_DEBUG "Mapping: ");
- resolv_usage(usage->hid);
+ hid_resolv_usage(usage->hid);
printk(" ---> ");
#endif
@@ -295,7 +296,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
}
}
- map_key(code);
+ map_key_clear(code);
break;
@@ -346,9 +347,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
if (field->flags & HID_MAIN_ITEM_RELATIVE)
- map_rel(usage->hid & 0xf);
+ map_rel_clear(usage->hid & 0xf);
else
- map_abs(usage->hid & 0xf);
+ map_abs_clear(usage->hid & 0xf);
break;
case HID_GD_HATSWITCH:
@@ -366,9 +367,22 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break;
case HID_UP_LED:
- if (((usage->hid - 1) & 0xffff) >= LED_MAX)
- goto ignore;
- map_led((usage->hid - 1) & 0xffff);
+
+ switch (usage->hid & 0xffff) { /* HID-Value: */
+ case 0x01: map_led (LED_NUML); break; /* "Num Lock" */
+ case 0x02: map_led (LED_CAPSL); break; /* "Caps Lock" */
+ case 0x03: map_led (LED_SCROLLL); break; /* "Scroll Lock" */
+ case 0x04: map_led (LED_COMPOSE); break; /* "Compose" */
+ case 0x05: map_led (LED_KANA); break; /* "Kana" */
+ case 0x27: map_led (LED_SLEEP); break; /* "Stand-By" */
+ case 0x4c: map_led (LED_SUSPEND); break; /* "System Suspend" */
+ case 0x09: map_led (LED_MUTE); break; /* "Mute" */
+ case 0x4b: map_led (LED_MISC); break; /* "Generic Indicator" */
+ case 0x19: map_led (LED_MAIL); break; /* "Message Waiting" */
+ case 0x4d: map_led (LED_CHARGING); break; /* "External Power Connected" */
+
+ default: goto ignore;
+ }
break;
case HID_UP_DIGITIZER:
@@ -418,12 +432,33 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x000: goto ignore;
case 0x034: map_key_clear(KEY_SLEEP); break;
case 0x036: map_key_clear(BTN_MISC); break;
+ case 0x040: map_key_clear(KEY_MENU); break;
case 0x045: map_key_clear(KEY_RADIO); break;
+
+ case 0x083: map_key_clear(KEY_LAST); break;
+ case 0x088: map_key_clear(KEY_PC); break;
+ case 0x089: map_key_clear(KEY_TV); break;
case 0x08a: map_key_clear(KEY_WWW); break;
+ case 0x08b: map_key_clear(KEY_DVD); break;
+ case 0x08c: map_key_clear(KEY_PHONE); break;
case 0x08d: map_key_clear(KEY_PROGRAM); break;
+ case 0x08e: map_key_clear(KEY_VIDEOPHONE); break;
+ case 0x08f: map_key_clear(KEY_GAMES); break;
+ case 0x090: map_key_clear(KEY_MEMO); break;
+ case 0x091: map_key_clear(KEY_CD); break;
+ case 0x092: map_key_clear(KEY_VCR); break;
+ case 0x093: map_key_clear(KEY_TUNER); break;
+ case 0x094: map_key_clear(KEY_EXIT); break;
case 0x095: map_key_clear(KEY_HELP); break;
+ case 0x096: map_key_clear(KEY_TAPE); break;
+ case 0x097: map_key_clear(KEY_TV2); break;
+ case 0x098: map_key_clear(KEY_SAT); break;
+ case 0x09a: map_key_clear(KEY_PVR); break;
+
case 0x09c: map_key_clear(KEY_CHANNELUP); break;
case 0x09d: map_key_clear(KEY_CHANNELDOWN); break;
+ case 0x0a0: map_key_clear(KEY_VCR2); break;
+
case 0x0b0: map_key_clear(KEY_PLAY); break;
case 0x0b1: map_key_clear(KEY_PAUSE); break;
case 0x0b2: map_key_clear(KEY_RECORD); break;
@@ -433,6 +468,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break;
case 0x0b7: map_key_clear(KEY_STOPCD); break;
case 0x0b8: map_key_clear(KEY_EJECTCD); break;
+
case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
case 0x0e0: map_abs_clear(ABS_VOLUME); break;
case 0x0e2: map_key_clear(KEY_MUTE); break;
@@ -440,11 +476,30 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
case 0x183: map_key_clear(KEY_CONFIG); break;
+ case 0x184: map_key_clear(KEY_WORDPROCESSOR); break;
+ case 0x185: map_key_clear(KEY_EDITOR); break;
+ case 0x186: map_key_clear(KEY_SPREADSHEET); break;
+ case 0x187: map_key_clear(KEY_GRAPHICSEDITOR); break;
+ case 0x188: map_key_clear(KEY_PRESENTATION); break;
+ case 0x189: map_key_clear(KEY_DATABASE); break;
case 0x18a: map_key_clear(KEY_MAIL); break;
+ case 0x18b: map_key_clear(KEY_NEWS); break;
+ case 0x18c: map_key_clear(KEY_VOICEMAIL); break;
+ case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break;
+ case 0x18e: map_key_clear(KEY_CALENDAR); break;
+ case 0x191: map_key_clear(KEY_FINANCE); break;
case 0x192: map_key_clear(KEY_CALC); break;
case 0x194: map_key_clear(KEY_FILE); break;
+ case 0x196: map_key_clear(KEY_WWW); break;
+ case 0x19e: map_key_clear(KEY_COFFEE); break;
+ case 0x1a6: map_key_clear(KEY_HELP); break;
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
+ case 0x1bc: map_key_clear(KEY_MESSENGER); break;
+ case 0x1bd: map_key_clear(KEY_INFO); break;
case 0x201: map_key_clear(KEY_NEW); break;
+ case 0x202: map_key_clear(KEY_OPEN); break;
+ case 0x203: map_key_clear(KEY_CLOSE); break;
+ case 0x204: map_key_clear(KEY_EXIT); break;
case 0x207: map_key_clear(KEY_SAVE); break;
case 0x208: map_key_clear(KEY_PRINT); break;
case 0x209: map_key_clear(KEY_PROPS); break;
@@ -459,10 +514,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x226: map_key_clear(KEY_STOP); break;
case 0x227: map_key_clear(KEY_REFRESH); break;
case 0x22a: map_key_clear(KEY_BOOKMARKS); break;
+ case 0x22d: map_key_clear(KEY_ZOOMIN); break;
+ case 0x22e: map_key_clear(KEY_ZOOMOUT); break;
+ case 0x22f: map_key_clear(KEY_ZOOMRESET); break;
case 0x233: map_key_clear(KEY_SCROLLUP); break;
case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
- case 0x238: map_rel(REL_HWHEEL); break;
+ case 0x238: map_rel_clear(REL_HWHEEL); break;
+ case 0x25f: map_key_clear(KEY_CANCEL); break;
case 0x279: map_key_clear(KEY_REDO); break;
+
case 0x289: map_key_clear(KEY_REPLY); break;
case 0x28b: map_key_clear(KEY_FORWARDMAIL); break;
case 0x28c: map_key_clear(KEY_SEND); break;
@@ -582,7 +642,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
goto ignore;
if ((device->quirks & HID_QUIRK_BAD_RELATIVE_KEYS) &&
- usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE))
+ usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE))
field->flags &= ~HID_MAIN_ITEM_RELATIVE;
set_bit(usage->type, input->evbit);
@@ -621,14 +681,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
field->dpad = usage->code;
}
-#ifdef DEBUG
- resolv_event(usage->type, usage->code);
+ hid_resolv_event(usage->type, usage->code);
+#ifdef CONFIG_HID_DEBUG
printk("\n");
#endif
return;
ignore:
-#ifdef DEBUG
+#ifdef CONFIG_HID_DEBUG
printk("IGNORED\n");
#endif
return;
@@ -724,8 +784,9 @@ void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
list_for_each_entry(hidinput, &hid->inputs, list)
input_sync(hidinput->input);
}
+EXPORT_SYMBOL_GPL(hidinput_report_event);
-static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
+int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
{
struct hid_report *report;
int i, j;
@@ -740,40 +801,18 @@ static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsign
}
return -1;
}
-
-static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
- struct hid_device *hid = dev->private;
- struct hid_field *field;
- int offset;
-
- if (type == EV_FF)
- return input_ff_event(dev, type, code, value);
-
- if (type != EV_LED)
- return -1;
-
- if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
- warn("event field not found");
- return -1;
- }
-
- hid_set_field(field, offset, value);
- hid_submit_report(hid, field->report, USB_DIR_OUT);
-
- return 0;
-}
+EXPORT_SYMBOL_GPL(hidinput_find_field);
static int hidinput_open(struct input_dev *dev)
{
struct hid_device *hid = dev->private;
- return hid_open(hid);
+ return hid->hid_open(hid);
}
static void hidinput_close(struct input_dev *dev)
{
struct hid_device *hid = dev->private;
- hid_close(hid);
+ hid->hid_close(hid);
}
/*
@@ -784,11 +823,11 @@ static void hidinput_close(struct input_dev *dev)
int hidinput_connect(struct hid_device *hid)
{
- struct usb_device *dev = hid->dev;
struct hid_report *report;
struct hid_input *hidinput = NULL;
struct input_dev *input_dev;
int i, j, k;
+ int max_report_type = HID_OUTPUT_REPORT;
INIT_LIST_HEAD(&hid->inputs);
@@ -801,7 +840,10 @@ int hidinput_connect(struct hid_device *hid)
if (i == hid->maxcollection)
return -1;
- for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
+ if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
+ max_report_type = HID_INPUT_REPORT;
+
+ for (k = HID_INPUT_REPORT; k <= max_report_type; k++)
list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
if (!report->maxfield)
@@ -818,16 +860,18 @@ int hidinput_connect(struct hid_device *hid)
}
input_dev->private = hid;
- input_dev->event = hidinput_input_event;
+ input_dev->event = hid->hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
input_dev->uniq = hid->uniq;
- usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &hid->intf->dev;
-
+ input_dev->id.bustype = hid->bus;
+ input_dev->id.vendor = hid->vendor;
+ input_dev->id.product = hid->product;
+ input_dev->id.version = hid->version;
+ input_dev->cdev.dev = hid->dev;
hidinput->input = input_dev;
list_add_tail(&hidinput->list, &hid->inputs);
}
@@ -849,16 +893,12 @@ int hidinput_connect(struct hid_device *hid)
}
}
- /* This only gets called when we are a single-input (most of the
- * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
- * only useful in this case, and not for multi-input quirks. */
- if (hidinput) {
- hid_ff_init(hid);
+ if (hidinput)
input_register_device(hidinput->input);
- }
return 0;
}
+EXPORT_SYMBOL_GPL(hidinput_connect);
void hidinput_disconnect(struct hid_device *hid)
{
@@ -870,3 +910,5 @@ void hidinput_disconnect(struct hid_device *hid)
kfree(hidinput);
}
}
+EXPORT_SYMBOL_GPL(hidinput_disconnect);
+
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index e76d91906c9..891ef6d0b1b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -106,6 +106,31 @@ config SENSORS_K8TEMP
This driver can also be built as a module. If so, the module
will be called k8temp.
+config SENSORS_AMS
+ tristate "Apple Motion Sensor driver"
+ depends on HWMON && PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
+ help
+ Support for the motion sensor included in PowerBooks. Includes
+ implementations for PMU and I2C.
+
+ This driver can also be built as a module. If so, the module
+ will be called ams.
+
+config SENSORS_AMS_PMU
+ bool "PMU variant"
+ depends on SENSORS_AMS && ADB_PMU
+ default y
+ help
+ PMU variant of motion sensor, found in late 2005 PowerBooks.
+
+config SENSORS_AMS_I2C
+ bool "I2C variant"
+ depends on SENSORS_AMS && I2C
+ default y
+ help
+ I2C variant of motion sensor, found in early 2005 PowerBooks and
+ iBooks.
+
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
depends on HWMON && I2C && EXPERIMENTAL
@@ -142,11 +167,12 @@ config SENSORS_DS1621
will be called ds1621.
config SENSORS_F71805F
- tristate "Fintek F71805F/FG"
+ tristate "Fintek F71805F/FG and F71872F/FG"
depends on HWMON && EXPERIMENTAL
help
If you say yes here you get support for hardware monitoring
- features of the Fintek F71805F/FG chips.
+ features of the Fintek F71805F/FG and F71872F/FG Super-I/O
+ chips.
This driver can also be built as a module. If so, the module
will be called f71805f.
@@ -353,6 +379,19 @@ config SENSORS_PC87360
This driver can also be built as a module. If so, the module
will be called pc87360.
+config SENSORS_PC87427
+ tristate "National Semiconductor PC87427"
+ depends on HWMON && EXPERIMENTAL
+ help
+ If you say yes here you get access to the hardware monitoring
+ functions of the National Semiconductor PC87427 Super-I/O chip.
+ The chip has two distinct logical devices, one for fan speed
+ monitoring and control, and one for voltage and temperature
+ monitoring. Only fan speed monitoring is supported right now.
+
+ This driver can also be built as a module. If so, the module
+ will be called pc87427.
+
config SENSORS_SIS5595
tristate "Silicon Integrated Systems Corp. SiS5595"
depends on HWMON && I2C && PCI && EXPERIMENTAL
@@ -474,6 +513,16 @@ config SENSORS_W83792D
This driver can also be built as a module. If so, the module
will be called w83792d.
+config SENSORS_W83793
+ tristate "Winbond W83793"
+ depends on HWMON && I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Winbond W83793
+ hardware monitoring chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called w83793.
+
config SENSORS_W83L785TS
tristate "Winbond W83L785TS-S"
depends on HWMON && I2C && EXPERIMENTAL
@@ -527,6 +576,9 @@ config SENSORS_HDAPS
This driver also provides an absolute input class device, allowing
the laptop to act as a pinball machine-esque joystick.
+ If your ThinkPad is not recognized by the driver, please update to latest
+ BIOS. This is especially the case for some R52 ThinkPads.
+
Say Y here if you have an applicable laptop and want to experience
the awesome power of hdaps.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index af01cc64f7d..31661124271 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_HWMON_VID) += hwmon-vid.o
obj-$(CONFIG_SENSORS_ASB100) += asb100.o
obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o
obj-$(CONFIG_SENSORS_W83792D) += w83792d.o
+obj-$(CONFIG_SENSORS_W83793) += w83793.o
obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
@@ -18,6 +19,7 @@ obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
+obj-$(CONFIG_SENSORS_AMS) += ams/
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
@@ -41,6 +43,7 @@ obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_LM92) += lm92.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
+obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
diff --git a/drivers/hwmon/ams/Makefile b/drivers/hwmon/ams/Makefile
new file mode 100644
index 00000000000..41c95b2089d
--- /dev/null
+++ b/drivers/hwmon/ams/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for Apple Motion Sensor driver
+#
+
+ams-y := ams-core.o ams-input.o
+ams-$(CONFIG_SENSORS_AMS_PMU) += ams-pmu.o
+ams-$(CONFIG_SENSORS_AMS_I2C) += ams-i2c.o
+obj-$(CONFIG_SENSORS_AMS) += ams.o
diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c
new file mode 100644
index 00000000000..f1f0f5d0442
--- /dev/null
+++ b/drivers/hwmon/ams/ams-core.c
@@ -0,0 +1,265 @@
+/*
+ * Apple Motion Sensor driver
+ *
+ * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
+ * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/pmac_pfunc.h>
+#include <asm/of_platform.h>
+
+#include "ams.h"
+
+/* There is only one motion sensor per machine */
+struct ams ams_info;
+
+static unsigned int verbose;
+module_param(verbose, bool, 0644);
+MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output");
+
+/* Call with ams_info.lock held! */
+void ams_sensors(s8 *x, s8 *y, s8 *z)
+{
+ u32 orient = ams_info.vflag? ams_info.orient1 : ams_info.orient2;
+
+ if (orient & 0x80)
+ /* X and Y swapped */
+ ams_info.get_xyz(y, x, z);
+ else
+ ams_info.get_xyz(x, y, z);
+
+ if (orient & 0x04)
+ *z = ~(*z);
+ if (orient & 0x02)
+ *y = ~(*y);
+ if (orient & 0x01)
+ *x = ~(*x);
+}
+
+static ssize_t ams_show_current(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ s8 x, y, z;
+
+ mutex_lock(&ams_info.lock);
+ ams_sensors(&x, &y, &z);
+ mutex_unlock(&ams_info.lock);
+
+ return snprintf(buf, PAGE_SIZE, "%d %d %d\n", x, y, z);
+}
+
+static DEVICE_ATTR(current, S_IRUGO, ams_show_current, NULL);
+
+static void ams_handle_irq(void *data)
+{
+ enum ams_irq irq = *((enum ams_irq *)data);
+
+ spin_lock(&ams_info.irq_lock);
+
+ ams_info.worker_irqs |= irq;
+ schedule_work(&ams_info.worker);
+
+ spin_unlock(&ams_info.irq_lock);
+}
+
+static enum ams_irq ams_freefall_irq_data = AMS_IRQ_FREEFALL;
+static struct pmf_irq_client ams_freefall_client = {
+ .owner = THIS_MODULE,
+ .handler = ams_handle_irq,
+ .data = &ams_freefall_irq_data,
+};
+
+static enum ams_irq ams_shock_irq_data = AMS_IRQ_SHOCK;
+static struct pmf_irq_client ams_shock_client = {
+ .owner = THIS_MODULE,
+ .handler = ams_handle_irq,
+ .data = &ams_shock_irq_data,
+};
+
+/* Once hard disk parking is implemented in the kernel, this function can
+ * trigger it.
+ */
+static void ams_worker(struct work_struct *work)
+{
+ mutex_lock(&ams_info.lock);
+
+ if (ams_info.has_device) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&ams_info.irq_lock, flags);
+
+ if (ams_info.worker_irqs & AMS_IRQ_FREEFALL) {
+ if (verbose)
+ printk(KERN_INFO "ams: freefall detected!\n");
+
+ ams_info.worker_irqs &= ~AMS_IRQ_FREEFALL;
+
+ /* we must call this with interrupts enabled */
+ spin_unlock_irqrestore(&ams_info.irq_lock, flags);
+ ams_info.clear_irq(AMS_IRQ_FREEFALL);
+ spin_lock_irqsave(&ams_info.irq_lock, flags);
+ }
+
+ if (ams_info.worker_irqs & AMS_IRQ_SHOCK) {
+ if (verbose)
+ printk(KERN_INFO "ams: shock detected!\n");
+
+ ams_info.worker_irqs &= ~AMS_IRQ_SHOCK;
+
+ /* we must call this with interrupts enabled */
+ spin_unlock_irqrestore(&ams_info.irq_lock, flags);
+ ams_info.clear_irq(AMS_IRQ_SHOCK);
+ spin_lock_irqsave(&ams_info.irq_lock, flags);
+ }
+
+ spin_unlock_irqrestore(&ams_info.irq_lock, flags);
+ }
+
+ mutex_unlock(&ams_info.lock);
+}
+
+/* Call with ams_info.lock held! */
+int ams_sensor_attach(void)
+{
+ int result;
+ u32 *prop;
+
+ /* Get orientation */
+ prop = (u32*)get_property(ams_info.of_node, "orientation", NULL);
+ if (!prop)
+ return -ENODEV;
+ ams_info.orient1 = *prop;
+ ams_info.orient2 = *(prop + 1);
+
+ /* Register freefall interrupt handler */
+ result = pmf_register_irq_client(ams_info.of_node,
+ "accel-int-1",
+ &ams_freefall_client);
+ if (result < 0)
+ return -ENODEV;
+
+ /* Reset saved irqs */
+ ams_info.worker_irqs = 0;
+
+ /* Register shock interrupt handler */
+ result = pmf_register_irq_client(ams_info.of_node,
+ "accel-int-2",
+ &ams_shock_client);
+ if (result < 0)
+ goto release_freefall;
+
+ /* Create device */
+ ams_info.of_dev = of_platform_device_create(ams_info.of_node, "ams", NULL);
+ if (!ams_info.of_dev) {
+ result = -ENODEV;
+ goto release_shock;
+ }
+
+ /* Create attributes */
+ result = device_create_file(&ams_info.of_dev->dev, &dev_attr_current);
+ if (result)
+ goto release_of;
+
+ ams_info.vflag = !!(ams_info.get_vendor() & 0x10);
+
+ /* Init input device */
+ result = ams_input_init();
+ if (result)
+ goto release_device_file;
+
+ return result;
+release_device_file:
+ device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
+release_of:
+ of_device_unregister(ams_info.of_dev);
+release_shock:
+ pmf_unregister_irq_client(&ams_shock_client);
+release_freefall:
+ pmf_unregister_irq_client(&ams_freefall_client);
+ return result;
+}
+
+int __init ams_init(void)
+{
+ struct device_node *np;
+
+ spin_lock_init(&ams_info.irq_lock);
+ mutex_init(&ams_info.lock);
+ INIT_WORK(&ams_info.worker, ams_worker);
+
+#ifdef CONFIG_SENSORS_AMS_I2C
+ np = of_find_node_by_name(NULL, "accelerometer");
+ if (np && device_is_compatible(np, "AAPL,accelerometer_1"))
+ /* Found I2C motion sensor */
+ return ams_i2c_init(np);
+#endif
+
+#ifdef CONFIG_SENSORS_AMS_PMU
+ np = of_find_node_by_name(NULL, "sms");
+ if (np && device_is_compatible(np, "sms"))
+ /* Found PMU motion sensor */
+ return ams_pmu_init(np);
+#endif
+
+ printk(KERN_ERR "ams: No motion sensor found.\n");
+
+ return -ENODEV;
+}
+
+void ams_exit(void)
+{
+ mutex_lock(&ams_info.lock);
+
+ if (ams_info.has_device) {
+ /* Remove input device */
+ ams_input_exit();
+
+ /* Shut down implementation */
+ ams_info.exit();
+
+ /* Flush interrupt worker
+ *
+ * We do this after ams_info.exit(), because an interrupt might
+ * have arrived before disabling them.
+ */
+ flush_scheduled_work();
+
+ /* Remove attributes */
+ device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
+
+ /* Remove device */
+ of_device_unregister(ams_info.of_dev);
+
+ /* Remove handler */
+ pmf_unregister_irq_client(&ams_shock_client);
+ pmf_unregister_irq_client(&ams_freefall_client);
+ }
+
+ mutex_unlock(&ams_info.lock);
+}
+
+MODULE_AUTHOR("Stelian Pop, Michael Hanselmann");
+MODULE_DESCRIPTION("Apple Motion Sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(ams_init);
+module_exit(ams_exit);
diff --git a/drivers/hwmon/ams/ams-i2c.c b/drivers/hwmon/ams/ams-i2c.c
new file mode 100644
index 00000000000..0d24bdfea53
--- /dev/null
+++ b/drivers/hwmon/ams/ams-i2c.c
@@ -0,0 +1,299 @@
+/*
+ * Apple Motion Sensor driver (I2C variant)
+ *
+ * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
+ * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
+ *
+ * Clean room implementation based on the reverse engineered Mac OS X driver by
+ * Johannes Berg <johannes@sipsolutions.net>, documentation available at
+ * http://johannes.sipsolutions.net/PowerBook/Apple_Motion_Sensor_Specification
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "ams.h"
+
+/* AMS registers */
+#define AMS_COMMAND 0x00 /* command register */
+#define AMS_STATUS 0x01 /* status register */
+#define AMS_CTRL1 0x02 /* read control 1 (number of values) */
+#define AMS_CTRL2 0x03 /* read control 2 (offset?) */
+#define AMS_CTRL3 0x04 /* read control 3 (size of each value?) */
+#define AMS_DATA1 0x05 /* read data 1 */
+#define AMS_DATA2 0x06 /* read data 2 */
+#define AMS_DATA3 0x07 /* read data 3 */
+#define AMS_DATA4 0x08 /* read data 4 */
+#define AMS_DATAX 0x20 /* data X */
+#define AMS_DATAY 0x21 /* data Y */
+#define AMS_DATAZ 0x22 /* data Z */
+#define AMS_FREEFALL 0x24 /* freefall int control */
+#define AMS_SHOCK 0x25 /* shock int control */
+#define AMS_SENSLOW 0x26 /* sensitivity low limit */
+#define AMS_SENSHIGH 0x27 /* sensitivity high limit */
+#define AMS_CTRLX 0x28 /* control X */
+#define AMS_CTRLY 0x29 /* control Y */
+#define AMS_CTRLZ 0x2A /* control Z */
+#define AMS_UNKNOWN1 0x2B /* unknown 1 */
+#define AMS_UNKNOWN2 0x2C /* unknown 2 */
+#define AMS_UNKNOWN3 0x2D /* unknown 3 */
+#define AMS_VENDOR 0x2E /* vendor */
+
+/* AMS commands - use with the AMS_COMMAND register */
+enum ams_i2c_cmd {
+ AMS_CMD_NOOP = 0,
+ AMS_CMD_VERSION,
+ AMS_CMD_READMEM,
+ AMS_CMD_WRITEMEM,
+ AMS_CMD_ERASEMEM,
+ AMS_CMD_READEE,
+ AMS_CMD_WRITEEE,
+ AMS_CMD_RESET,
+ AMS_CMD_START,
+};
+
+static int ams_i2c_attach(struct i2c_adapter *adapter);
+static int ams_i2c_detach(struct i2c_adapter *adapter);
+
+static struct i2c_driver ams_i2c_driver = {
+ .driver = {
+ .name = "ams",
+ .owner = THIS_MODULE,
+ },
+ .attach_adapter = ams_i2c_attach,
+ .detach_adapter = ams_i2c_detach,
+};
+
+static s32 ams_i2c_read(u8 reg)
+{
+ return i2c_smbus_read_byte_data(&ams_info.i2c_client, reg);
+}
+
+static int ams_i2c_write(u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(&ams_info.i2c_client, reg, value);
+}
+
+static int ams_i2c_cmd(enum ams_i2c_cmd cmd)
+{
+ s32 result;
+ int remaining = HZ / 20;
+
+ ams_i2c_write(AMS_COMMAND, cmd);
+ mdelay(5);
+
+ while (remaining) {
+ result = ams_i2c_read(AMS_COMMAND);
+ if (result == 0 || result & 0x80)
+ return 0;
+
+ remaining = schedule_timeout(remaining);
+ }
+
+ return -1;
+}
+
+static void ams_i2c_set_irq(enum ams_irq reg, char enable)
+{
+ if (reg & AMS_IRQ_FREEFALL) {
+ u8 val = ams_i2c_read(AMS_CTRLX);
+ if (enable)
+ val |= 0x80;
+ else
+ val &= ~0x80;
+ ams_i2c_write(AMS_CTRLX, val);
+ }
+
+ if (reg & AMS_IRQ_SHOCK) {
+ u8 val = ams_i2c_read(AMS_CTRLY);
+ if (enable)
+ val |= 0x80;
+ else
+ val &= ~0x80;
+ ams_i2c_write(AMS_CTRLY, val);
+ }
+
+ if (reg & AMS_IRQ_GLOBAL) {
+ u8 val = ams_i2c_read(AMS_CTRLZ);
+ if (enable)
+ val |= 0x80;
+ else
+ val &= ~0x80;
+ ams_i2c_write(AMS_CTRLZ, val);
+ }
+}
+
+static void ams_i2c_clear_irq(enum ams_irq reg)
+{
+ if (reg & AMS_IRQ_FREEFALL)
+ ams_i2c_write(AMS_FREEFALL, 0);
+
+ if (reg & AMS_IRQ_SHOCK)
+ ams_i2c_write(AMS_SHOCK, 0);
+}
+
+static u8 ams_i2c_get_vendor(void)
+{
+ return ams_i2c_read(AMS_VENDOR);
+}
+
+static void ams_i2c_get_xyz(s8 *x, s8 *y, s8 *z)
+{
+ *x = ams_i2c_read(AMS_DATAX);
+ *y = ams_i2c_read(AMS_DATAY);
+ *z = ams_i2c_read(AMS_DATAZ);
+}
+
+static int ams_i2c_attach(struct i2c_adapter *adapter)
+{
+ unsigned long bus;
+ int vmaj, vmin;
+ int result;
+
+ /* There can be only one */
+ if (unlikely(ams_info.has_device))
+ return -ENODEV;
+
+ if (strncmp(adapter->name, "uni-n", 5))
+ return -ENODEV;
+
+ bus = simple_strtoul(adapter->name + 6, NULL, 10);
+ if (bus != ams_info.i2c_bus)
+ return -ENODEV;
+
+ ams_info.i2c_client.addr = ams_info.i2c_address;
+ ams_info.i2c_client.adapter = adapter;
+ ams_info.i2c_client.driver = &ams_i2c_driver;
+ strcpy(ams_info.i2c_client.name, "Apple Motion Sensor");
+
+ if (ams_i2c_cmd(AMS_CMD_RESET)) {
+ printk(KERN_INFO "ams: Failed to reset the device\n");
+ return -ENODEV;
+ }
+
+ if (ams_i2c_cmd(AMS_CMD_START)) {
+ printk(KERN_INFO "ams: Failed to start the device\n");
+ return -ENODEV;
+ }
+
+ /* get version/vendor information */
+ ams_i2c_write(AMS_CTRL1, 0x02);
+ ams_i2c_write(AMS_CTRL2, 0x85);
+ ams_i2c_write(AMS_CTRL3, 0x01);
+
+ ams_i2c_cmd(AMS_CMD_READMEM);
+
+ vmaj = ams_i2c_read(AMS_DATA1);
+ vmin = ams_i2c_read(AMS_DATA2);
+ if (vmaj != 1 || vmin != 52) {
+ printk(KERN_INFO "ams: Incorrect device version (%d.%d)\n",
+ vmaj, vmin);
+ return -ENODEV;
+ }
+
+ ams_i2c_cmd(AMS_CMD_VERSION);
+
+ vmaj = ams_i2c_read(AMS_DATA1);
+ vmin = ams_i2c_read(AMS_DATA2);
+ if (vmaj != 0 || vmin != 1) {
+ printk(KERN_INFO "ams: Incorrect firmware version (%d.%d)\n",
+ vmaj, vmin);
+ return -ENODEV;
+ }
+
+ /* Disable interrupts */
+ ams_i2c_set_irq(AMS_IRQ_ALL, 0);
+
+ result = ams_sensor_attach();
+ if (result < 0)
+ return result;
+
+ /* Set default values */
+ ams_i2c_write(AMS_SENSLOW, 0x15);
+ ams_i2c_write(AMS_SENSHIGH, 0x60);
+ ams_i2c_write(AMS_CTRLX, 0x08);
+ ams_i2c_write(AMS_CTRLY, 0x0F);
+ ams_i2c_write(AMS_CTRLZ, 0x4F);
+ ams_i2c_write(AMS_UNKNOWN1, 0x14);
+
+ /* Clear interrupts */
+ ams_i2c_clear_irq(AMS_IRQ_ALL);
+
+ ams_info.has_device = 1;
+
+ /* Enable interrupts */
+ ams_i2c_set_irq(AMS_IRQ_ALL, 1);
+
+ printk(KERN_INFO "ams: Found I2C based motion sensor\n");
+
+ return 0;
+}
+
+static int ams_i2c_detach(struct i2c_adapter *adapter)
+{
+ if (ams_info.has_device) {
+ /* Disable interrupts */
+ ams_i2c_set_irq(AMS_IRQ_ALL, 0);
+
+ /* Clear interrupts */
+ ams_i2c_clear_irq(AMS_IRQ_ALL);
+
+ printk(KERN_INFO "ams: Unloading\n");
+
+ ams_info.has_device = 0;
+ }
+
+ return 0;
+}
+
+static void ams_i2c_exit(void)
+{
+ i2c_del_driver(&ams_i2c_driver);
+}
+
+int __init ams_i2c_init(struct device_node *np)
+{
+ char *tmp_bus;
+ int result;
+ u32 *prop;
+
+ mutex_lock(&ams_info.lock);
+
+ /* Set implementation stuff */
+ ams_info.of_node = np;
+ ams_info.exit = ams_i2c_exit;
+ ams_info.get_vendor = ams_i2c_get_vendor;
+ ams_info.get_xyz = ams_i2c_get_xyz;
+ ams_info.clear_irq = ams_i2c_clear_irq;
+ ams_info.bustype = BUS_I2C;
+
+ /* look for bus either using "reg" or by path */
+ prop = (u32*)get_property(ams_info.of_node, "reg", NULL);
+ if (!prop) {
+ result = -ENODEV;
+
+ goto exit;
+ }
+
+ tmp_bus = strstr(ams_info.of_node->full_name, "/i2c-bus@");
+ if (tmp_bus)
+ ams_info.i2c_bus = *(tmp_bus + 9) - '0';
+ else
+ ams_info.i2c_bus = ((*prop) >> 8) & 0x0f;
+ ams_info.i2c_address = ((*prop) & 0xff) >> 1;
+
+ result = i2c_add_driver(&ams_i2c_driver);
+
+exit:
+ mutex_unlock(&ams_info.lock);
+
+ return result;
+}
diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c
new file mode 100644
index 00000000000..18210164e30
--- /dev/null
+++ b/drivers/hwmon/ams/ams-input.c
@@ -0,0 +1,160 @@
+/*
+ * Apple Motion Sensor driver (joystick emulation)
+ *
+ * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
+ * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.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.
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "ams.h"
+
+static unsigned int joystick;
+module_param(joystick, bool, 0644);
+MODULE_PARM_DESC(joystick, "Enable the input class device on module load");
+
+static unsigned int invert;
+module_param(invert, bool, 0644);
+MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
+
+static int ams_input_kthread(void *data)
+{
+ s8 x, y, z;
+
+ while (!kthread_should_stop()) {
+ mutex_lock(&ams_info.lock);
+
+ ams_sensors(&x, &y, &z);
+
+ x -= ams_info.xcalib;
+ y -= ams_info.ycalib;
+ z -= ams_info.zcalib;
+
+ input_report_abs(ams_info.idev, ABS_X, invert ? -x : x);
+ input_report_abs(ams_info.idev, ABS_Y, invert ? -y : y);
+ input_report_abs(ams_info.idev, ABS_Z, z);
+
+ input_sync(ams_info.idev);
+
+ mutex_unlock(&ams_info.lock);
+
+ msleep(25);
+ }
+
+ return 0;
+}
+
+static int ams_input_open(struct input_dev *dev)
+{
+ ams_info.kthread = kthread_run(ams_input_kthread, NULL, "kams");
+ return IS_ERR(ams_info.kthread) ? PTR_ERR(ams_info.kthread) : 0;
+}
+
+static void ams_input_close(struct input_dev *dev)
+{
+ kthread_stop(ams_info.kthread);
+}
+
+/* Call with ams_info.lock held! */
+static void ams_input_enable(void)
+{
+ s8 x, y, z;
+
+ if (ams_info.idev)
+ return;
+
+ ams_sensors(&x, &y, &z);
+ ams_info.xcalib = x;
+ ams_info.ycalib = y;
+ ams_info.zcalib = z;
+
+ ams_info.idev = input_allocate_device();
+ if (!ams_info.idev)
+ return;
+
+ ams_info.idev->name = "Apple Motion Sensor";
+ ams_info.idev->id.bustype = ams_info.bustype;
+ ams_info.idev->id.vendor = 0;
+ ams_info.idev->open = ams_input_open;
+ ams_info.idev->close = ams_input_close;
+ ams_info.idev->cdev.dev = &ams_info.of_dev->dev;
+
+ input_set_abs_params(ams_info.idev, ABS_X, -50, 50, 3, 0);
+ input_set_abs_params(ams_info.idev, ABS_Y, -50, 50, 3, 0);
+ input_set_abs_params(ams_info.idev, ABS_Z, -50, 50, 3, 0);
+
+ set_bit(EV_ABS, ams_info.idev->evbit);
+ set_bit(EV_KEY, ams_info.idev->evbit);
+ set_bit(BTN_TOUCH, ams_info.idev->keybit);
+
+ if (input_register_device(ams_info.idev)) {
+ input_free_device(ams_info.idev);
+ ams_info.idev = NULL;
+ return;
+ }
+}
+
+/* Call with ams_info.lock held! */
+static void ams_input_disable(void)
+{
+ if (ams_info.idev) {
+ input_unregister_device(ams_info.idev);
+ ams_info.idev = NULL;
+ }
+}
+
+static ssize_t ams_input_show_joystick(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", joystick);
+}
+
+static ssize_t ams_input_store_joystick(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ if (sscanf(buf, "%d\n", &joystick) != 1)
+ return -EINVAL;
+
+ mutex_lock(&ams_info.lock);
+
+ if (joystick)
+ ams_input_enable();
+ else
+ ams_input_disable();
+
+ mutex_unlock(&ams_info.lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(joystick, S_IRUGO | S_IWUSR,
+ ams_input_show_joystick, ams_input_store_joystick);
+
+/* Call with ams_info.lock held! */
+int ams_input_init(void)
+{
+ int result;
+
+ result = device_create_file(&ams_info.of_dev->dev, &dev_attr_joystick);
+
+ if (!result && joystick)
+ ams_input_enable();
+ return result;
+}
+
+/* Call with ams_info.lock held! */
+void ams_input_exit(void)
+{
+ ams_input_disable();
+ device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick);
+}
diff --git a/drivers/hwmon/ams/ams-pmu.c b/drivers/hwmon/ams/ams-pmu.c
new file mode 100644
index 00000000000..4636ae031a5
--- /dev/null
+++ b/drivers/hwmon/ams/ams-pmu.c
@@ -0,0 +1,207 @@
+/*
+ * Apple Motion Sensor driver (PMU variant)
+ *
+ * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.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.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+
+#include "ams.h"
+
+/* Attitude */
+#define AMS_X 0x00
+#define AMS_Y 0x01
+#define AMS_Z 0x02
+
+/* Not exactly known, maybe chip vendor */
+#define AMS_VENDOR 0x03
+
+/* Freefall registers */
+#define AMS_FF_CLEAR 0x04
+#define AMS_FF_ENABLE 0x05
+#define AMS_FF_LOW_LIMIT 0x06
+#define AMS_FF_DEBOUNCE 0x07
+
+/* Shock registers */
+#define AMS_SHOCK_CLEAR 0x08
+#define AMS_SHOCK_ENABLE 0x09
+#define AMS_SHOCK_HIGH_LIMIT 0x0a
+#define AMS_SHOCK_DEBOUNCE 0x0b
+
+/* Global interrupt and power control register */
+#define AMS_CONTROL 0x0c
+
+static u8 ams_pmu_cmd;
+
+static void ams_pmu_req_complete(struct adb_request *req)
+{
+ complete((struct completion *)req->arg);
+}
+
+/* Only call this function from task context */
+static void ams_pmu_set_register(u8 reg, u8 value)
+{
+ static struct adb_request req;
+ DECLARE_COMPLETION(req_complete);
+
+ req.arg = &req_complete;
+ if (pmu_request(&req, ams_pmu_req_complete, 4, ams_pmu_cmd, 0x00, reg, value))
+ return;
+
+ wait_for_completion(&req_complete);
+}
+
+/* Only call this function from task context */
+static u8 ams_pmu_get_register(u8 reg)
+{
+ static struct adb_request req;
+ DECLARE_COMPLETION(req_complete);
+
+ req.arg = &req_complete;
+ if (pmu_request(&req, ams_pmu_req_complete, 3, ams_pmu_cmd, 0x01, reg))
+ return 0;
+
+ wait_for_completion(&req_complete);
+
+ if (req.reply_len > 0)
+ return req.reply[0];
+ else
+ return 0;
+}
+
+/* Enables or disables the specified interrupts */
+static void ams_pmu_set_irq(enum ams_irq reg, char enable)
+{
+ if (reg & AMS_IRQ_FREEFALL) {
+ u8 val = ams_pmu_get_register(AMS_FF_ENABLE);
+ if (enable)
+ val |= 0x80;
+ else
+ val &= ~0x80;
+ ams_pmu_set_register(AMS_FF_ENABLE, val);
+ }
+
+ if (reg & AMS_IRQ_SHOCK) {
+ u8 val = ams_pmu_get_register(AMS_SHOCK_ENABLE);
+ if (enable)
+ val |= 0x80;
+ else
+ val &= ~0x80;
+ ams_pmu_set_register(AMS_SHOCK_ENABLE, val);
+ }
+
+ if (reg & AMS_IRQ_GLOBAL) {
+ u8 val = ams_pmu_get_register(AMS_CONTROL);
+ if (enable)
+ val |= 0x80;
+ else
+ val &= ~0x80;
+ ams_pmu_set_register(AMS_CONTROL, val);
+ }
+}
+
+static void ams_pmu_clear_irq(enum ams_irq reg)
+{
+ if (reg & AMS_IRQ_FREEFALL)
+ ams_pmu_set_register(AMS_FF_CLEAR, 0x00);
+
+ if (reg & AMS_IRQ_SHOCK)
+ ams_pmu_set_register(AMS_SHOCK_CLEAR, 0x00);
+}
+
+static u8 ams_pmu_get_vendor(void)
+{
+ return ams_pmu_get_register(AMS_VENDOR);
+}
+
+static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z)
+{
+ *x = ams_pmu_get_register(AMS_X);
+ *y = ams_pmu_get_register(AMS_Y);
+ *z = ams_pmu_get_register(AMS_Z);
+}
+
+static void ams_pmu_exit(void)
+{
+ /* Disable interrupts */
+ ams_pmu_set_irq(AMS_IRQ_ALL, 0);
+
+ /* Clear interrupts */
+ ams_pmu_clear_irq(AMS_IRQ_ALL);
+
+ ams_info.has_device = 0;
+
+ printk(KERN_INFO "ams: Unloading\n");
+}
+
+int __init ams_pmu_init(struct device_node *np)
+{
+ u32 *prop;
+ int result;
+
+ mutex_lock(&ams_info.lock);
+
+ /* Set implementation stuff */
+ ams_info.of_node = np;
+ ams_info.exit = ams_pmu_exit;
+ ams_info.get_vendor = ams_pmu_get_vendor;
+ ams_info.get_xyz = ams_pmu_get_xyz;
+ ams_info.clear_irq = ams_pmu_clear_irq;
+ ams_info.bustype = BUS_HOST;
+
+ /* Get PMU command, should be 0x4e, but we can never know */
+ prop = (u32*)get_property(ams_info.of_node, "reg", NULL);
+ if (!prop) {
+ result = -ENODEV;
+ goto exit;
+ }
+ ams_pmu_cmd = ((*prop) >> 8) & 0xff;
+
+ /* Disable interrupts */
+ ams_pmu_set_irq(AMS_IRQ_ALL, 0);
+
+ /* Clear interrupts */
+ ams_pmu_clear_irq(AMS_IRQ_ALL);
+
+ result = ams_sensor_attach();
+ if (result < 0)
+ goto exit;
+
+ /* Set default values */
+ ams_pmu_set_register(AMS_FF_LOW_LIMIT, 0x15);
+ ams_pmu_set_register(AMS_FF_ENABLE, 0x08);
+ ams_pmu_set_register(AMS_FF_DEBOUNCE, 0x14);
+
+ ams_pmu_set_register(AMS_SHOCK_HIGH_LIMIT, 0x60);
+ ams_pmu_set_register(AMS_SHOCK_ENABLE, 0x0f);
+ ams_pmu_set_register(AMS_SHOCK_DEBOUNCE, 0x14);
+
+ ams_pmu_set_register(AMS_CONTROL, 0x4f);
+
+ /* Clear interrupts */
+ ams_pmu_clear_irq(AMS_IRQ_ALL);
+
+ ams_info.has_device = 1;
+
+ /* Enable interrupts */
+ ams_pmu_set_irq(AMS_IRQ_ALL, 1);
+
+ printk(KERN_INFO "ams: Found PMU based motion sensor\n");
+
+ result = 0;
+
+exit:
+ mutex_unlock(&ams_info.lock);
+
+ return result;
+}
diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h
new file mode 100644
index 00000000000..240730e6bcd
--- /dev/null
+++ b/drivers/hwmon/ams/ams.h
@@ -0,0 +1,72 @@
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <asm/of_device.h>
+
+enum ams_irq {
+ AMS_IRQ_FREEFALL = 0x01,
+ AMS_IRQ_SHOCK = 0x02,
+ AMS_IRQ_GLOBAL = 0x04,
+ AMS_IRQ_ALL =
+ AMS_IRQ_FREEFALL |
+ AMS_IRQ_SHOCK |
+ AMS_IRQ_GLOBAL,
+};
+
+struct ams {
+ /* Locks */
+ spinlock_t irq_lock;
+ struct mutex lock;
+
+ /* General properties */
+ struct device_node *of_node;
+ struct of_device *of_dev;
+ char has_device;
+ char vflag;
+ u32 orient1;
+ u32 orient2;
+
+ /* Interrupt worker */
+ struct work_struct worker;
+ u8 worker_irqs;
+
+ /* Implementation
+ *
+ * Only call these functions with the main lock held.
+ */
+ void (*exit)(void);
+
+ void (*get_xyz)(s8 *x, s8 *y, s8 *z);
+ u8 (*get_vendor)(void);
+
+ void (*clear_irq)(enum ams_irq reg);
+
+#ifdef CONFIG_SENSORS_AMS_I2C
+ /* I2C properties */
+ int i2c_bus;
+ int i2c_address;
+ struct i2c_client i2c_client;
+#endif
+
+ /* Joystick emulation */
+ struct task_struct *kthread;
+ struct input_dev *idev;
+ __u16 bustype;
+
+ /* calibrated null values */
+ int xcalib, ycalib, zcalib;
+};
+
+extern struct ams ams_info;
+
+extern void ams_sensors(s8 *x, s8 *y, s8 *z);
+extern int ams_sensor_attach(void);
+
+extern int ams_pmu_init(struct device_node *np);
+extern int ams_i2c_init(struct device_node *np);
+
+extern int ams_input_init(void);
+extern void ams_input_exit(void);
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index de17a72149d..a272cae8f60 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -1,12 +1,15 @@
/*
- * f71805f.c - driver for the Fintek F71805F/FG Super-I/O chip integrated
- * hardware monitoring features
+ * f71805f.c - driver for the Fintek F71805F/FG and F71872F/FG Super-I/O
+ * chips integrated hardware monitoring features
* 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
* sensors, and manual and automatic fan speed control.
*
+ * The F71872F/FG is almost the same, with two more voltages monitored,
+ * and 6 VID inputs.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -37,6 +40,7 @@
static struct platform_device *pdev;
#define DRVNAME "f71805f"
+enum kinds { f71805f, f71872f };
/*
* Super-I/O constants and functions
@@ -48,11 +52,13 @@ static struct platform_device *pdev;
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
#define SIO_REG_DEVREV 0x22 /* Device revision */
#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
+#define SIO_REG_FNSEL1 0x29 /* Multi Function Select 1 (F71872F) */
#define SIO_REG_ENABLE 0x30 /* Logical device enable */
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
#define SIO_FINTEK_ID 0x1934
#define SIO_F71805F_ID 0x0406
+#define SIO_F71872F_ID 0x0341
static inline int
superio_inb(int base, int reg)
@@ -96,22 +102,25 @@ superio_exit(int base)
* ISA constants
*/
-#define REGION_LENGTH 2
-#define ADDR_REG_OFFSET 0
-#define DATA_REG_OFFSET 1
+#define REGION_LENGTH 8
+#define ADDR_REG_OFFSET 5
+#define DATA_REG_OFFSET 6
/*
* Registers
*/
-/* in nr from 0 to 8 (8-bit values) */
+/* in nr from 0 to 10 (8-bit values) */
#define F71805F_REG_IN(nr) (0x10 + (nr))
-#define F71805F_REG_IN_HIGH(nr) (0x40 + 2 * (nr))
-#define F71805F_REG_IN_LOW(nr) (0x41 + 2 * (nr))
+#define F71805F_REG_IN_HIGH(nr) ((nr) < 10 ? 0x40 + 2 * (nr) : 0x2E)
+#define F71805F_REG_IN_LOW(nr) ((nr) < 10 ? 0x41 + 2 * (nr) : 0x2F)
/* fan nr from 0 to 2 (12-bit values, two registers) */
#define F71805F_REG_FAN(nr) (0x20 + 2 * (nr))
#define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr))
+#define F71805F_REG_FAN_TARGET(nr) (0x69 + 16 * (nr))
#define F71805F_REG_FAN_CTRL(nr) (0x60 + 16 * (nr))
+#define F71805F_REG_PWM_FREQ(nr) (0x63 + 16 * (nr))
+#define F71805F_REG_PWM_DUTY(nr) (0x6B + 16 * (nr))
/* temp nr from 0 to 2 (8-bit values) */
#define F71805F_REG_TEMP(nr) (0x1B + (nr))
#define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr))
@@ -122,6 +131,14 @@ superio_exit(int base)
/* status nr from 0 to 2 */
#define F71805F_REG_STATUS(nr) (0x36 + (nr))
+/* individual register bits */
+#define FAN_CTRL_DC_MODE 0x10
+#define FAN_CTRL_LATCH_FULL 0x08
+#define FAN_CTRL_MODE_MASK 0x03
+#define FAN_CTRL_MODE_SPEED 0x00
+#define FAN_CTRL_MODE_TEMPERATURE 0x01
+#define FAN_CTRL_MODE_MANUAL 0x02
+
/*
* Data structures and manipulation thereof
*/
@@ -138,12 +155,16 @@ struct f71805f_data {
unsigned long last_limits; /* In jiffies */
/* Register values */
- u8 in[9];
- u8 in_high[9];
- u8 in_low[9];
+ u8 in[11];
+ u8 in_high[11];
+ u8 in_low[11];
+ u16 has_in;
u16 fan[3];
u16 fan_low[3];
- u8 fan_enabled; /* Read once at init time */
+ u16 fan_target[3];
+ u8 fan_ctrl[3];
+ u8 pwm[3];
+ u8 pwm_freq[3];
u8 temp[3];
u8 temp_high[3];
u8 temp_hyst[3];
@@ -151,6 +172,11 @@ struct f71805f_data {
unsigned long alarms;
};
+struct f71805f_sio_data {
+ enum kinds kind;
+ u8 fnsel1;
+};
+
static inline long in_from_reg(u8 reg)
{
return (reg * 8);
@@ -200,6 +226,33 @@ static inline u16 fan_to_reg(long rpm)
return (1500000 / rpm);
}
+static inline unsigned long pwm_freq_from_reg(u8 reg)
+{
+ unsigned long clock = (reg & 0x80) ? 48000000UL : 1000000UL;
+
+ reg &= 0x7f;
+ if (reg == 0)
+ reg++;
+ return clock / (reg << 8);
+}
+
+static inline u8 pwm_freq_to_reg(unsigned long val)
+{
+ if (val >= 187500) /* The highest we can do */
+ return 0x80;
+ if (val >= 1475) /* Use 48 MHz clock */
+ return 0x80 | (48000000UL / (val << 8));
+ if (val < 31) /* The lowest we can do */
+ return 0x7f;
+ else /* Use 1 MHz clock */
+ return 1000000UL / (val << 8);
+}
+
+static inline int pwm_mode_from_reg(u8 reg)
+{
+ return !(reg & FAN_CTRL_DC_MODE);
+}
+
static inline long temp_from_reg(u8 reg)
{
return (reg * 1000);
@@ -274,16 +327,21 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
/* Limit registers cache is refreshed after 60 seconds */
if (time_after(jiffies, data->last_updated + 60 * HZ)
|| !data->valid) {
- for (nr = 0; nr < 9; nr++) {
+ for (nr = 0; nr < 11; nr++) {
+ if (!(data->has_in & (1 << nr)))
+ continue;
data->in_high[nr] = f71805f_read8(data,
F71805F_REG_IN_HIGH(nr));
data->in_low[nr] = f71805f_read8(data,
F71805F_REG_IN_LOW(nr));
}
for (nr = 0; nr < 3; nr++) {
- if (data->fan_enabled & (1 << nr))
- data->fan_low[nr] = f71805f_read16(data,
- F71805F_REG_FAN_LOW(nr));
+ data->fan_low[nr] = f71805f_read16(data,
+ F71805F_REG_FAN_LOW(nr));
+ data->fan_target[nr] = f71805f_read16(data,
+ F71805F_REG_FAN_TARGET(nr));
+ data->pwm_freq[nr] = f71805f_read8(data,
+ F71805F_REG_PWM_FREQ(nr));
}
for (nr = 0; nr < 3; nr++) {
data->temp_high[nr] = f71805f_read8(data,
@@ -299,14 +357,19 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
/* Measurement registers cache is refreshed after 1 second */
if (time_after(jiffies, data->last_updated + HZ)
|| !data->valid) {
- for (nr = 0; nr < 9; nr++) {
+ for (nr = 0; nr < 11; nr++) {
+ if (!(data->has_in & (1 << nr)))
+ continue;
data->in[nr] = f71805f_read8(data,
F71805F_REG_IN(nr));
}
for (nr = 0; nr < 3; nr++) {
- if (data->fan_enabled & (1 << nr))
- data->fan[nr] = f71805f_read16(data,
- F71805F_REG_FAN(nr));
+ data->fan[nr] = f71805f_read16(data,
+ F71805F_REG_FAN(nr));
+ data->fan_ctrl[nr] = f71805f_read8(data,
+ F71805F_REG_FAN_CTRL(nr));
+ data->pwm[nr] = f71805f_read8(data,
+ F71805F_REG_PWM_DUTY(nr));
}
for (nr = 0; nr < 3; nr++) {
data->temp[nr] = f71805f_read8(data,
@@ -333,35 +396,43 @@ static ssize_t show_in0(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 nr = attr->index;
- return sprintf(buf, "%ld\n", in0_from_reg(data->in[0]));
+ return sprintf(buf, "%ld\n", in0_from_reg(data->in[nr]));
}
static ssize_t show_in0_max(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 nr = attr->index;
- return sprintf(buf, "%ld\n", in0_from_reg(data->in_high[0]));
+ return sprintf(buf, "%ld\n", in0_from_reg(data->in_high[nr]));
}
static ssize_t show_in0_min(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 nr = attr->index;
- return sprintf(buf, "%ld\n", in0_from_reg(data->in_low[0]));
+ return sprintf(buf, "%ld\n", in0_from_reg(data->in_low[nr]));
}
static ssize_t set_in0_max(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int nr = attr->index;
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
- data->in_high[0] = in0_to_reg(val);
- f71805f_write8(data, F71805F_REG_IN_HIGH(0), data->in_high[0]);
+ data->in_high[nr] = in0_to_reg(val);
+ f71805f_write8(data, F71805F_REG_IN_HIGH(nr), data->in_high[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -371,11 +442,13 @@ static ssize_t set_in0_min(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int nr = attr->index;
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
- data->in_low[0] = in0_to_reg(val);
- f71805f_write8(data, F71805F_REG_IN_LOW(0), data->in_low[0]);
+ data->in_low[nr] = in0_to_reg(val);
+ f71805f_write8(data, F71805F_REG_IN_LOW(nr), data->in_low[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -463,6 +536,16 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute
return sprintf(buf, "%ld\n", fan_from_reg(data->fan_low[nr]));
}
+static ssize_t show_fan_target(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 nr = attr->index;
+
+ return sprintf(buf, "%ld\n", fan_from_reg(data->fan_target[nr]));
+}
+
static ssize_t set_fan_min(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
@@ -479,6 +562,157 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute
return count;
}
+static ssize_t set_fan_target(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int nr = attr->index;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->fan_target[nr] = fan_to_reg(val);
+ f71805f_write16(data, F71805F_REG_FAN_TARGET(nr),
+ data->fan_target[nr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_pwm(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 nr = attr->index;
+
+ return sprintf(buf, "%d\n", (int)data->pwm[nr]);
+}
+
+static ssize_t show_pwm_enable(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 nr = attr->index;
+ int mode;
+
+ switch (data->fan_ctrl[nr] & FAN_CTRL_MODE_MASK) {
+ case FAN_CTRL_MODE_SPEED:
+ mode = 3;
+ break;
+ case FAN_CTRL_MODE_TEMPERATURE:
+ mode = 2;
+ break;
+ default: /* MANUAL */
+ mode = 1;
+ }
+
+ return sprintf(buf, "%d\n", mode);
+}
+
+static ssize_t show_pwm_freq(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 nr = attr->index;
+
+ return sprintf(buf, "%lu\n", pwm_freq_from_reg(data->pwm_freq[nr]));
+}
+
+static ssize_t show_pwm_mode(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 nr = attr->index;
+
+ return sprintf(buf, "%d\n", pwm_mode_from_reg(data->fan_ctrl[nr]));
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int nr = attr->index;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+
+ if (val > 255)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->pwm[nr] = val;
+ f71805f_write8(data, F71805F_REG_PWM_DUTY(nr), data->pwm[nr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static struct attribute *f71805f_attr_pwm[];
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int nr = attr->index;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+ u8 reg;
+
+ if (val < 1 || val > 3)
+ return -EINVAL;
+
+ if (val > 1) { /* Automatic mode, user can't set PWM value */
+ if (sysfs_chmod_file(&dev->kobj, f71805f_attr_pwm[nr],
+ S_IRUGO))
+ dev_dbg(dev, "chmod -w pwm%d failed\n", nr + 1);
+ }
+
+ mutex_lock(&data->update_lock);
+ reg = f71805f_read8(data, F71805F_REG_FAN_CTRL(nr))
+ & ~FAN_CTRL_MODE_MASK;
+ switch (val) {
+ case 1:
+ reg |= FAN_CTRL_MODE_MANUAL;
+ break;
+ case 2:
+ reg |= FAN_CTRL_MODE_TEMPERATURE;
+ break;
+ case 3:
+ reg |= FAN_CTRL_MODE_SPEED;
+ break;
+ }
+ data->fan_ctrl[nr] = reg;
+ f71805f_write8(data, F71805F_REG_FAN_CTRL(nr), reg);
+ mutex_unlock(&data->update_lock);
+
+ if (val == 1) { /* Manual mode, user can set PWM value */
+ if (sysfs_chmod_file(&dev->kobj, f71805f_attr_pwm[nr],
+ S_IRUGO | S_IWUSR))
+ dev_dbg(dev, "chmod +w pwm%d failed\n", nr + 1);
+ }
+
+ return count;
+}
+
+static ssize_t set_pwm_freq(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int nr = attr->index;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->pwm_freq[nr] = pwm_freq_to_reg(val);
+ f71805f_write8(data, F71805F_REG_PWM_FREQ(nr), data->pwm_freq[nr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
char *buf)
{
@@ -557,7 +791,7 @@ static ssize_t show_alarms_in(struct device *dev, struct device_attribute
{
struct f71805f_data *data = f71805f_update_device(dev);
- return sprintf(buf, "%lu\n", data->alarms & 0x1ff);
+ return sprintf(buf, "%lu\n", data->alarms & 0x7ff);
}
static ssize_t show_alarms_fan(struct device *dev, struct device_attribute
@@ -594,9 +828,11 @@ static ssize_t show_name(struct device *dev, struct device_attribute
return sprintf(buf, "%s\n", data->name);
}
-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(in0_input, S_IRUGO, show_in0, NULL, 0);
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR,
+ show_in0_max, set_in0_max, 0);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR,
+ show_in0_min, set_in0_min, 0);
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);
@@ -637,16 +873,32 @@ 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(in9_input, S_IRUGO, show_in0, NULL, 9);
+static SENSOR_DEVICE_ATTR(in9_max, S_IRUGO | S_IWUSR,
+ show_in0_max, set_in0_max, 9);
+static SENSOR_DEVICE_ATTR(in9_min, S_IRUGO | S_IWUSR,
+ show_in0_min, set_in0_min, 9);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_in0, NULL, 10);
+static SENSOR_DEVICE_ATTR(in10_max, S_IRUGO | S_IWUSR,
+ show_in0_max, set_in0_max, 10);
+static SENSOR_DEVICE_ATTR(in10_min, S_IRUGO | S_IWUSR,
+ show_in0_min, set_in0_min, 10);
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(fan1_target, S_IRUGO | S_IWUSR,
+ show_fan_target, set_fan_target, 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(fan2_target, S_IRUGO | S_IWUSR,
+ show_fan_target, set_fan_target, 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(fan3_target, S_IRUGO | S_IWUSR,
+ show_fan_target, set_fan_target, 2);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
@@ -667,6 +919,27 @@ 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);
+/* pwm (value) files are created read-only, write permission is
+ then added or removed dynamically as needed */
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+ show_pwm_enable, set_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR,
+ show_pwm_freq, set_pwm_freq, 0);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
+ show_pwm_enable, set_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO | S_IWUSR,
+ show_pwm_freq, set_pwm_freq, 1);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO, show_pwm_mode, NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO, show_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
+ show_pwm_enable, set_pwm_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO | S_IWUSR,
+ show_pwm_freq, set_pwm_freq, 2);
+static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, 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);
@@ -676,6 +949,8 @@ 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(in9_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10);
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);
@@ -689,9 +964,9 @@ 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_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,
@@ -701,9 +976,6 @@ static struct attribute *f71805f_attributes[] = {
&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,
@@ -713,9 +985,29 @@ static struct attribute *f71805f_attributes[] = {
&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_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan1_target.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_target.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan3_target.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_mode.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
@@ -734,11 +1026,9 @@ static struct attribute *f71805f_attributes[] = {
&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,
@@ -754,29 +1044,59 @@ static const struct attribute_group f71805f_group = {
.attrs = f71805f_attributes,
};
-static struct attribute *f71805f_attributes_fan[3][4] = {
+static struct attribute *f71805f_attributes_optin[4][5] = {
{
- &sensor_dev_attr_fan1_input.dev_attr.attr,
- &sensor_dev_attr_fan1_min.dev_attr.attr,
- &sensor_dev_attr_fan1_alarm.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_in4_alarm.dev_attr.attr,
+ NULL
+ }, {
+ &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_in8_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,
+ &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_in9_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,
+ &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_in10_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] },
+static const struct attribute_group f71805f_group_optin[4] = {
+ { .attrs = f71805f_attributes_optin[0] },
+ { .attrs = f71805f_attributes_optin[1] },
+ { .attrs = f71805f_attributes_optin[2] },
+ { .attrs = f71805f_attributes_optin[3] },
+};
+
+/* We don't include pwm_freq files in the arrays above, because they must be
+ created conditionally (only if pwm_mode is 1 == PWM) */
+static struct attribute *f71805f_attributes_pwm_freq[] = {
+ &sensor_dev_attr_pwm1_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm2_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm3_freq.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group f71805f_group_pwm_freq = {
+ .attrs = f71805f_attributes_pwm_freq,
+};
+
+/* We also need an indexed access to pwmN files to toggle writability */
+static struct attribute *f71805f_attr_pwm[] = {
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
};
/*
@@ -798,18 +1118,30 @@ static void __devinit f71805f_init_device(struct f71805f_data *data)
/* Fan monitoring can be disabled. If it is, we won't be polling
the register values, and won't create the related sysfs files. */
for (i = 0; i < 3; i++) {
- reg = f71805f_read8(data, F71805F_REG_FAN_CTRL(i));
- if (!(reg & 0x80))
- data->fan_enabled |= (1 << i);
+ data->fan_ctrl[i] = f71805f_read8(data,
+ F71805F_REG_FAN_CTRL(i));
+ /* Clear latch full bit, else "speed mode" fan speed control
+ doesn't work */
+ if (data->fan_ctrl[i] & FAN_CTRL_LATCH_FULL) {
+ data->fan_ctrl[i] &= ~FAN_CTRL_LATCH_FULL;
+ f71805f_write8(data, F71805F_REG_FAN_CTRL(i),
+ data->fan_ctrl[i]);
+ }
}
}
static int __devinit f71805f_probe(struct platform_device *pdev)
{
+ struct f71805f_sio_data *sio_data = pdev->dev.platform_data;
struct f71805f_data *data;
struct resource *res;
int i, err;
+ static const char *names[] = {
+ "f71805f",
+ "f71872f",
+ };
+
if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) {
err = -ENOMEM;
printk(KERN_ERR DRVNAME ": Out of memory\n");
@@ -819,24 +1151,69 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
data->addr = res->start;
mutex_init(&data->lock);
- data->name = "f71805f";
+ data->name = names[sio_data->kind];
mutex_init(&data->update_lock);
platform_set_drvdata(pdev, data);
+ /* Some voltage inputs depend on chip model and configuration */
+ switch (sio_data->kind) {
+ case f71805f:
+ data->has_in = 0x1ff;
+ break;
+ case f71872f:
+ data->has_in = 0x6ef;
+ if (sio_data->fnsel1 & 0x01)
+ data->has_in |= (1 << 4); /* in4 */
+ if (sio_data->fnsel1 & 0x02)
+ data->has_in |= (1 << 8); /* in8 */
+ break;
+ }
+
/* Initialize the F71805F chip */
f71805f_init_device(data);
/* Register sysfs interface files */
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;
+ if (data->has_in & (1 << 4)) { /* in4 */
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
+ &f71805f_group_optin[0])))
+ goto exit_remove_files;
+ }
+ if (data->has_in & (1 << 8)) { /* in8 */
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
+ &f71805f_group_optin[1])))
+ goto exit_remove_files;
+ }
+ if (data->has_in & (1 << 9)) { /* in9 (F71872F/FG only) */
if ((err = sysfs_create_group(&pdev->dev.kobj,
- &f71805f_group_fan[i])))
+ &f71805f_group_optin[2])))
goto exit_remove_files;
}
+ if (data->has_in & (1 << 10)) { /* in9 (F71872F/FG only) */
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
+ &f71805f_group_optin[3])))
+ goto exit_remove_files;
+ }
+ for (i = 0; i < 3; i++) {
+ /* If control mode is PWM, create pwm_freq file */
+ if (!(data->fan_ctrl[i] & FAN_CTRL_DC_MODE)) {
+ if ((err = sysfs_create_file(&pdev->dev.kobj,
+ f71805f_attributes_pwm_freq[i])))
+ goto exit_remove_files;
+ }
+ /* If PWM is in manual mode, add write permission */
+ if (data->fan_ctrl[i] & FAN_CTRL_MODE_MANUAL) {
+ if ((err = sysfs_chmod_file(&pdev->dev.kobj,
+ f71805f_attr_pwm[i],
+ S_IRUGO | S_IWUSR))) {
+ dev_err(&pdev->dev, "chmod +w pwm%d failed\n",
+ i + 1);
+ goto exit_remove_files;
+ }
+ }
+ }
data->class_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->class_dev)) {
@@ -849,8 +1226,9 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
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]);
+ for (i = 0; i < 4; i++)
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
exit_free:
platform_set_drvdata(pdev, NULL);
kfree(data);
@@ -866,8 +1244,9 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
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]);
+ for (i = 0; i < 4; i++)
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
kfree(data);
return 0;
@@ -882,7 +1261,8 @@ static struct platform_driver f71805f_driver = {
.remove = __devexit_p(f71805f_remove),
};
-static int __init f71805f_device_add(unsigned short address)
+static int __init f71805f_device_add(unsigned short address,
+ const struct f71805f_sio_data *sio_data)
{
struct resource res = {
.start = address,
@@ -906,26 +1286,45 @@ static int __init f71805f_device_add(unsigned short address)
goto exit_device_put;
}
+ pdev->dev.platform_data = kmalloc(sizeof(struct f71805f_sio_data),
+ GFP_KERNEL);
+ if (!pdev->dev.platform_data) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ goto exit_device_put;
+ }
+ memcpy(pdev->dev.platform_data, sio_data,
+ sizeof(struct f71805f_sio_data));
+
err = platform_device_add(pdev);
if (err) {
printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
err);
- goto exit_device_put;
+ goto exit_kfree_data;
}
return 0;
+exit_kfree_data:
+ kfree(pdev->dev.platform_data);
+ pdev->dev.platform_data = NULL;
exit_device_put:
platform_device_put(pdev);
exit:
return err;
}
-static int __init f71805f_find(int sioaddr, unsigned short *address)
+static int __init f71805f_find(int sioaddr, unsigned short *address,
+ struct f71805f_sio_data *sio_data)
{
int err = -ENODEV;
u16 devid;
+ static const char *names[] = {
+ "F71805F/FG",
+ "F71872F/FG",
+ };
+
superio_enter(sioaddr);
devid = superio_inw(sioaddr, SIO_REG_MANID);
@@ -933,7 +1332,15 @@ static int __init f71805f_find(int sioaddr, unsigned short *address)
goto exit;
devid = superio_inw(sioaddr, SIO_REG_DEVID);
- if (devid != SIO_F71805F_ID) {
+ switch (devid) {
+ case SIO_F71805F_ID:
+ sio_data->kind = f71805f;
+ break;
+ case SIO_F71872F_ID:
+ sio_data->kind = f71872f;
+ sio_data->fnsel1 = superio_inb(sioaddr, SIO_REG_FNSEL1);
+ break;
+ default:
printk(KERN_INFO DRVNAME ": Unsupported Fintek device, "
"skipping\n");
goto exit;
@@ -952,10 +1359,12 @@ static int __init f71805f_find(int sioaddr, unsigned short *address)
"skipping\n");
goto exit;
}
+ *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
err = 0;
- printk(KERN_INFO DRVNAME ": Found F71805F chip at %#x, revision %u\n",
- *address, superio_inb(sioaddr, SIO_REG_DEVREV));
+ printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %u\n",
+ names[sio_data->kind], *address,
+ superio_inb(sioaddr, SIO_REG_DEVREV));
exit:
superio_exit(sioaddr);
@@ -966,9 +1375,10 @@ static int __init f71805f_init(void)
{
int err;
unsigned short address;
+ struct f71805f_sio_data sio_data;
- if (f71805f_find(0x2e, &address)
- && f71805f_find(0x4e, &address))
+ if (f71805f_find(0x2e, &address, &sio_data)
+ && f71805f_find(0x4e, &address, &sio_data))
return -ENODEV;
err = platform_driver_register(&f71805f_driver);
@@ -976,7 +1386,7 @@ static int __init f71805f_init(void)
goto exit;
/* Sets global pdev as a side effect */
- err = f71805f_device_add(address);
+ err = f71805f_device_add(address, &sio_data);
if (err)
goto exit_driver;
@@ -990,13 +1400,16 @@ exit:
static void __exit f71805f_exit(void)
{
+ kfree(pdev->dev.platform_data);
+ pdev->dev.platform_data = NULL;
platform_device_unregister(pdev);
+
platform_driver_unregister(&f71805f_driver);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr>");
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("F71805F hardware monitoring driver");
+MODULE_DESCRIPTION("F71805F/F71872F hardware monitoring driver");
module_init(f71805f_init);
module_exit(f71805f_exit);
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index e8ef62b83d6..bf759ea545a 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -478,74 +478,64 @@ static struct attribute_group hdaps_attribute_group = {
/* Module stuff */
/* hdaps_dmi_match - found a match. return one, short-circuiting the hunt. */
-static int hdaps_dmi_match(struct dmi_system_id *id)
+static int __init hdaps_dmi_match(struct dmi_system_id *id)
{
printk(KERN_INFO "hdaps: %s detected.\n", id->ident);
return 1;
}
/* hdaps_dmi_match_invert - found an inverted match. */
-static int hdaps_dmi_match_invert(struct dmi_system_id *id)
+static int __init hdaps_dmi_match_invert(struct dmi_system_id *id)
{
hdaps_invert = 1;
printk(KERN_INFO "hdaps: inverting axis readings.\n");
return hdaps_dmi_match(id);
}
-#define HDAPS_DMI_MATCH_NORMAL(model) { \
- .ident = "IBM " model, \
+#define HDAPS_DMI_MATCH_NORMAL(vendor, model) { \
+ .ident = vendor " " model, \
.callback = hdaps_dmi_match, \
.matches = { \
- DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), \
+ DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
} \
}
-#define HDAPS_DMI_MATCH_INVERT(model) { \
- .ident = "IBM " model, \
+#define HDAPS_DMI_MATCH_INVERT(vendor, model) { \
+ .ident = vendor " " model, \
.callback = hdaps_dmi_match_invert, \
.matches = { \
- DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), \
+ DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
} \
}
-#define HDAPS_DMI_MATCH_LENOVO(model) { \
- .ident = "Lenovo " model, \
- .callback = hdaps_dmi_match_invert, \
- .matches = { \
- DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), \
- DMI_MATCH(DMI_PRODUCT_VERSION, model) \
- } \
-}
+/* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
+ "ThinkPad T42p", so the order of the entries matters.
+ If your ThinkPad is not recognized, please update to latest
+ BIOS. This is especially the case for some R52 ThinkPads. */
+static struct dmi_system_id __initdata hdaps_whitelist[] = {
+ HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p"),
+ HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"),
+ HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"),
+ HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
+ HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p"),
+ HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"),
+ HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p"),
+ HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"),
+ HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"),
+ HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60"),
+ HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
+ HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X41"),
+ HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60"),
+ HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
+ { .ident = NULL }
+};
static int __init hdaps_init(void)
{
int ret;
- /* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
- "ThinkPad T42p", so the order of the entries matters */
- struct dmi_system_id hdaps_whitelist[] = {
- HDAPS_DMI_MATCH_NORMAL("ThinkPad H"),
- HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"),
- HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"),
- HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"),
- HDAPS_DMI_MATCH_NORMAL("ThinkPad R52"),
- HDAPS_DMI_MATCH_NORMAL("ThinkPad H"), /* R52 (1846AQG) */
- HDAPS_DMI_MATCH_INVERT("ThinkPad T41p"),
- HDAPS_DMI_MATCH_NORMAL("ThinkPad T41"),
- HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"),
- 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"),
- HDAPS_DMI_MATCH_NORMAL("ThinkPad Z60m"),
- { .ident = NULL }
- };
-
if (!dmi_check_system(hdaps_whitelist)) {
printk(KERN_WARNING "hdaps: supported laptop not found!\n");
ret = -ENODEV;
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index 9d67320e684..b80f6ed5acf 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -1,7 +1,7 @@
/*
hwmon-vid.c - VID/VRM/VRD voltage conversions
- Copyright (c) 2004 Rudolf Marek <r.marek@sh.cvut.cz>
+ Copyright (c) 2004 Rudolf Marek <r.marek@assembler.cz>
Partly imported from i2c-vid.h of the lm_sensors project
Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
@@ -93,7 +93,7 @@ int vid_from_reg(int val, u8 vrm)
case 110: /* Intel Conroe */
/* compute in uV, round to mV */
val &= 0xff;
- if(((val & 0x7e) == 0xfe) || (!(val & 0x7e)))
+ if (val < 0x02 || val > 0xb2)
return 0;
return((1600000 - (val - 2) * 6250 + 500) / 1000);
case 24: /* Opteron processor */
@@ -232,7 +232,7 @@ u8 vid_which_vrm(void)
EXPORT_SYMBOL(vid_from_reg);
EXPORT_SYMBOL(vid_which_vrm);
-MODULE_AUTHOR("Rudolf Marek <r.marek@sh.cvut.cz>");
+MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
MODULE_DESCRIPTION("hwmon-vid driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 323ef06719c..1ed8b7e2c35 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -3,7 +3,7 @@
monitoring.
Supports: IT8705F Super I/O chip w/LPC interface
- IT8712F Super I/O chip w/LPC interface & SMBus
+ IT8712F Super I/O chip w/LPC interface
IT8716F Super I/O chip w/LPC interface
IT8718F Super I/O chip w/LPC interface
Sis950 A clone of the IT8705F
@@ -41,12 +41,8 @@
#include <asm/io.h>
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
static unsigned short isa_address;
-
-/* Insmod parameters */
-I2C_CLIENT_INSMOD_4(it87, it8712, it8716, it8718);
+enum chips { it87, it8712, it8716, it8718 };
#define REG 0x2e /* The register to read/write */
#define DEV 0x07 /* Register: Logical device select */
@@ -162,8 +158,6 @@ static u8 vid_value;
#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2)
#define IT87_REG_TEMP_LOW(nr) (0x41 + (nr) * 2)
-#define IT87_REG_I2C_ADDR 0x48
-
#define IT87_REG_VIN_ENABLE 0x50
#define IT87_REG_TEMP_ENABLE 0x51
@@ -242,33 +236,22 @@ struct it87_data {
};
-static int it87_attach_adapter(struct i2c_adapter *adapter);
-static int it87_isa_attach_adapter(struct i2c_adapter *adapter);
-static int it87_detect(struct i2c_adapter *adapter, int address, int kind);
+static int it87_detect(struct i2c_adapter *adapter);
static int it87_detach_client(struct i2c_client *client);
static int it87_read_value(struct i2c_client *client, u8 reg);
-static int it87_write_value(struct i2c_client *client, u8 reg, u8 value);
+static void it87_write_value(struct i2c_client *client, u8 reg, u8 value);
static struct it87_data *it87_update_device(struct device *dev);
static int it87_check_pwm(struct i2c_client *client);
static void it87_init_client(struct i2c_client *client, struct it87_data *data);
-static struct i2c_driver it87_driver = {
- .driver = {
- .name = "it87",
- },
- .id = I2C_DRIVERID_IT87,
- .attach_adapter = it87_attach_adapter,
- .detach_client = it87_detach_client,
-};
-
static struct i2c_driver it87_isa_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "it87-isa",
},
- .attach_adapter = it87_isa_attach_adapter,
+ .attach_adapter = it87_detect,
.detach_client = it87_detach_client,
};
@@ -850,22 +833,6 @@ 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
- available adapter
- * when a new adapter is inserted (and it87_driver is still present) */
-static int it87_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, it87_detect);
-}
-
-static int it87_isa_attach_adapter(struct i2c_adapter *adapter)
-{
- return it87_detect(adapter, isa_address, -1);
-}
-
/* SuperIO detection - will change isa_address if a chip is found */
static int __init it87_find(unsigned short *address)
{
@@ -916,29 +883,20 @@ exit:
}
/* This function is called by i2c_probe */
-static int it87_detect(struct i2c_adapter *adapter, int address, int kind)
+static int it87_detect(struct i2c_adapter *adapter)
{
- int i;
struct i2c_client *new_client;
struct it87_data *data;
int err = 0;
- const char *name = "";
- int is_isa = i2c_is_isa_adapter(adapter);
+ const char *name;
int enable_pwm_interface;
- if (!is_isa &&
- !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto ERROR0;
-
/* Reserve the ISA region */
- if (is_isa)
- if (!request_region(address, IT87_EXTENT,
- it87_isa_driver.driver.name))
- goto ERROR0;
-
- /* For now, we presume we have a valid client. We create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access it87_{read,write}_value. */
+ if (!request_region(isa_address, IT87_EXTENT,
+ it87_isa_driver.driver.name)){
+ err = -EBUSY;
+ goto ERROR0;
+ }
if (!(data = kzalloc(sizeof(struct it87_data), GFP_KERNEL))) {
err = -ENOMEM;
@@ -946,80 +904,46 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind)
}
new_client = &data->client;
- if (is_isa)
- mutex_init(&data->lock);
+ mutex_init(&data->lock);
i2c_set_clientdata(new_client, data);
- new_client->addr = address;
+ new_client->addr = isa_address;
new_client->adapter = adapter;
- new_client->driver = is_isa ? &it87_isa_driver : &it87_driver;
- new_client->flags = 0;
+ new_client->driver = &it87_isa_driver;
/* Now, we do the remaining detection. */
-
- if (kind < 0) {
- if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80)
- || (!is_isa
- && it87_read_value(new_client, IT87_REG_I2C_ADDR) != address)) {
- err = -ENODEV;
- goto ERROR2;
- }
+ if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80)
+ || it87_read_value(new_client, IT87_REG_CHIPID) != 0x90) {
+ err = -ENODEV;
+ goto ERROR2;
}
/* Determine the chip type. */
- if (kind <= 0) {
- i = it87_read_value(new_client, IT87_REG_CHIPID);
- if (i == 0x90) {
- kind = it87;
- 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)
- dev_info(&adapter->dev,
- "Ignoring 'force' parameter for unknown chip at "
- "adapter %d, address 0x%02x\n",
- i2c_adapter_id(adapter), address);
- err = -ENODEV;
- goto ERROR2;
- }
- }
-
- if (kind == it87) {
- name = "it87";
- } else if (kind == it8712) {
+ switch (chip_type) {
+ case IT8712F_DEVID:
+ data->type = it8712;
name = "it8712";
- } else if (kind == it8716) {
+ break;
+ case IT8716F_DEVID:
+ data->type = it8716;
name = "it8716";
- } else if (kind == it8718) {
+ break;
+ case IT8718F_DEVID:
+ data->type = it8718;
name = "it8718";
+ break;
+ default:
+ data->type = it87;
+ name = "it87";
}
/* Fill in the remaining client fields and put it into the global list */
strlcpy(new_client->name, 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)))
goto ERROR2;
- if (!is_isa)
- dev_info(&new_client->dev, "The I2C interface to IT87xxF "
- "hardware monitoring chips is deprecated. Please "
- "report if you still rely on it.\n");
-
/* Check PWM configuration */
enable_pwm_interface = it87_check_pwm(new_client);
@@ -1129,8 +1053,7 @@ ERROR3:
ERROR2:
kfree(data);
ERROR1:
- if (is_isa)
- release_region(address, IT87_EXTENT);
+ release_region(isa_address, IT87_EXTENT);
ERROR0:
return err;
}
@@ -1147,50 +1070,39 @@ static int it87_detach_client(struct i2c_client *client)
if ((err = i2c_detach_client(client)))
return err;
- if(i2c_is_isa_client(client))
- release_region(client->addr, IT87_EXTENT);
+ release_region(client->addr, IT87_EXTENT);
kfree(data);
return 0;
}
-/* The SMBus locks itself, but ISA access must be locked explicitly!
- We don't want to lock the whole ISA bus, so we lock each client
- separately.
+/* ISA access must be locked explicitly!
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
would slow down the IT87 access and should not be necessary. */
static int it87_read_value(struct i2c_client *client, u8 reg)
{
struct it87_data *data = i2c_get_clientdata(client);
-
int res;
- if (i2c_is_isa_client(client)) {
- mutex_lock(&data->lock);
- outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
- res = inb_p(client->addr + IT87_DATA_REG_OFFSET);
- mutex_unlock(&data->lock);
- return res;
- } else
- return i2c_smbus_read_byte_data(client, reg);
+
+ mutex_lock(&data->lock);
+ outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
+ res = inb_p(client->addr + IT87_DATA_REG_OFFSET);
+ mutex_unlock(&data->lock);
+
+ return res;
}
-/* The SMBus locks itself, but ISA access muse be locked explicitly!
- We don't want to lock the whole ISA bus, so we lock each client
- separately.
+/* ISA access must be locked explicitly!
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
would slow down the IT87 access and should not be necessary. */
-static int it87_write_value(struct i2c_client *client, u8 reg, u8 value)
+static void it87_write_value(struct i2c_client *client, u8 reg, u8 value)
{
struct it87_data *data = i2c_get_clientdata(client);
- if (i2c_is_isa_client(client)) {
- mutex_lock(&data->lock);
- outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
- outb_p(value, client->addr + IT87_DATA_REG_OFFSET);
- mutex_unlock(&data->lock);
- return 0;
- } else
- return i2c_smbus_write_byte_data(client, reg, value);
+ mutex_lock(&data->lock);
+ outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
+ outb_p(value, client->addr + IT87_DATA_REG_OFFSET);
+ mutex_unlock(&data->lock);
}
/* Return 1 if and only if the PWM interface is safe to use */
@@ -1426,26 +1338,14 @@ static int __init sm_it87_init(void)
{
int res;
- res = i2c_add_driver(&it87_driver);
- if (res)
+ if ((res = it87_find(&isa_address)))
return res;
-
- if (!it87_find(&isa_address)) {
- res = i2c_isa_add_driver(&it87_isa_driver);
- if (res) {
- i2c_del_driver(&it87_driver);
- return res;
- }
- }
-
- return 0;
+ return i2c_isa_add_driver(&it87_isa_driver);
}
static void __exit sm_it87_exit(void)
{
- if (isa_address)
- i2c_isa_del_driver(&it87_isa_driver);
- i2c_del_driver(&it87_driver);
+ i2c_isa_del_driver(&it87_isa_driver);
}
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index f58b64ed09e..5d8d0ca08fa 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -1,7 +1,7 @@
/*
* k8temp.c - Linux kernel module for hardware monitoring
*
- * Copyright (C) 2006 Rudolf Marek <r.marek@sh.cvut.cz>
+ * Copyright (C) 2006 Rudolf Marek <r.marek@assembler.cz>
*
* Inspired from the w83785 and amd756 drivers.
*
@@ -286,7 +286,7 @@ static void __exit k8temp_exit(void)
pci_unregister_driver(&k8temp_driver);
}
-MODULE_AUTHOR("Rudolf Marek <r.marek@sh.cvut.cz>");
+MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
MODULE_DESCRIPTION("AMD K8 core temperature monitor");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index 3b8b81984ad..c8a21be09d8 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -1000,7 +1000,7 @@ static int pc87360_detect(struct i2c_adapter *adapter)
(i&0x02) ? "external" : "internal");
data->vid_conf = confreg[3];
- data->vrm = 90;
+ data->vrm = vid_which_vrm();
}
/* Fan clock dividers may be needed before any data is read */
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
new file mode 100644
index 00000000000..affa21a5ccf
--- /dev/null
+++ b/drivers/hwmon/pc87427.c
@@ -0,0 +1,627 @@
+/*
+ * pc87427.c - hardware monitoring driver for the
+ * National Semiconductor PC87427 Super-I/O chip
+ * Copyright (C) 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 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.
+ *
+ * Supports the following chips:
+ *
+ * Chip #vin #fan #pwm #temp devid
+ * PC87427 - 8 - - 0xF2
+ *
+ * This driver assumes that no more than one chip is present.
+ * Only fan inputs are supported so far, although the chip can do much more.
+ */
+
+#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/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <asm/io.h>
+
+static struct platform_device *pdev;
+
+#define DRVNAME "pc87427"
+
+/* The lock mutex protects both the I/O accesses (needed because the
+ device is using banked registers) and the register cache (needed to keep
+ the data in the registers and the cache in sync at any time). */
+struct pc87427_data {
+ struct class_device *class_dev;
+ struct mutex lock;
+ int address[2];
+ const char *name;
+
+ unsigned long last_updated; /* in jiffies */
+ u8 fan_enabled; /* bit vector */
+ u16 fan[8]; /* register values */
+ u16 fan_min[8]; /* register values */
+ u8 fan_status[8]; /* register values */
+};
+
+/*
+ * Super-I/O registers and operations
+ */
+
+#define SIOREG_LDSEL 0x07 /* Logical device select */
+#define SIOREG_DEVID 0x20 /* Device ID */
+#define SIOREG_ACT 0x30 /* Device activation */
+#define SIOREG_MAP 0x50 /* I/O or memory mapping */
+#define SIOREG_IOBASE 0x60 /* I/O base address */
+
+static const u8 logdev[2] = { 0x09, 0x14 };
+static const char *logdev_str[2] = { DRVNAME " FMC", DRVNAME " HMC" };
+#define LD_FAN 0
+#define LD_IN 1
+#define LD_TEMP 1
+
+static inline void superio_outb(int sioaddr, int reg, int val)
+{
+ outb(reg, sioaddr);
+ outb(val, sioaddr + 1);
+}
+
+static inline int superio_inb(int sioaddr, int reg)
+{
+ outb(reg, sioaddr);
+ return inb(sioaddr + 1);
+}
+
+static inline void superio_exit(int sioaddr)
+{
+ outb(0x02, sioaddr);
+ outb(0x02, sioaddr + 1);
+}
+
+/*
+ * Logical devices
+ */
+
+#define REGION_LENGTH 32
+#define PC87427_REG_BANK 0x0f
+#define BANK_FM(nr) (nr)
+#define BANK_FT(nr) (0x08 + (nr))
+#define BANK_FC(nr) (0x10 + (nr) * 2)
+
+/*
+ * I/O access functions
+ */
+
+/* ldi is the logical device index */
+static inline int pc87427_read8(struct pc87427_data *data, u8 ldi, u8 reg)
+{
+ return inb(data->address[ldi] + reg);
+}
+
+/* Must be called with data->lock held, except during init */
+static inline int pc87427_read8_bank(struct pc87427_data *data, u8 ldi,
+ u8 bank, u8 reg)
+{
+ outb(bank, data->address[ldi] + PC87427_REG_BANK);
+ return inb(data->address[ldi] + reg);
+}
+
+/* Must be called with data->lock held, except during init */
+static inline void pc87427_write8_bank(struct pc87427_data *data, u8 ldi,
+ u8 bank, u8 reg, u8 value)
+{
+ outb(bank, data->address[ldi] + PC87427_REG_BANK);
+ outb(value, data->address[ldi] + reg);
+}
+
+/*
+ * Fan registers and conversions
+ */
+
+/* fan data registers are 16-bit wide */
+#define PC87427_REG_FAN 0x12
+#define PC87427_REG_FAN_MIN 0x14
+#define PC87427_REG_FAN_STATUS 0x10
+
+#define FAN_STATUS_STALL (1 << 3)
+#define FAN_STATUS_LOSPD (1 << 1)
+#define FAN_STATUS_MONEN (1 << 0)
+
+/* Dedicated function to read all registers related to a given fan input.
+ This saves us quite a few locks and bank selections.
+ Must be called with data->lock held.
+ nr is from 0 to 7 */
+static void pc87427_readall_fan(struct pc87427_data *data, u8 nr)
+{
+ int iobase = data->address[LD_FAN];
+
+ outb(BANK_FM(nr), iobase + PC87427_REG_BANK);
+ data->fan[nr] = inw(iobase + PC87427_REG_FAN);
+ data->fan_min[nr] = inw(iobase + PC87427_REG_FAN_MIN);
+ data->fan_status[nr] = inb(iobase + PC87427_REG_FAN_STATUS);
+ /* Clear fan alarm bits */
+ outb(data->fan_status[nr], iobase + PC87427_REG_FAN_STATUS);
+}
+
+/* The 2 LSB of fan speed registers are used for something different.
+ The actual 2 LSB of the measurements are not available. */
+static inline unsigned long fan_from_reg(u16 reg)
+{
+ reg &= 0xfffc;
+ if (reg == 0x0000 || reg == 0xfffc)
+ return 0;
+ return 5400000UL / reg;
+}
+
+/* The 2 LSB of the fan speed limit registers are not significant. */
+static inline u16 fan_to_reg(unsigned long val)
+{
+ if (val < 83UL)
+ return 0xffff;
+ if (val >= 1350000UL)
+ return 0x0004;
+ return ((1350000UL + val / 2) / val) << 2;
+}
+
+/*
+ * Data interface
+ */
+
+static struct pc87427_data *pc87427_update_device(struct device *dev)
+{
+ struct pc87427_data *data = dev_get_drvdata(dev);
+ int i;
+
+ mutex_lock(&data->lock);
+ if (!time_after(jiffies, data->last_updated + HZ)
+ && data->last_updated)
+ goto done;
+
+ /* Fans */
+ for (i = 0; i < 8; i++) {
+ if (!(data->fan_enabled & (1 << i)))
+ continue;
+ pc87427_readall_fan(data, i);
+ }
+ data->last_updated = jiffies;
+
+done:
+ mutex_unlock(&data->lock);
+ return data;
+}
+
+static ssize_t show_fan_input(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87427_data *data = pc87427_update_device(dev);
+ int nr = attr->index;
+
+ return sprintf(buf, "%lu\n", fan_from_reg(data->fan[nr]));
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87427_data *data = pc87427_update_device(dev);
+ int nr = attr->index;
+
+ return sprintf(buf, "%lu\n", fan_from_reg(data->fan_min[nr]));
+}
+
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87427_data *data = pc87427_update_device(dev);
+ int nr = attr->index;
+
+ return sprintf(buf, "%d\n", !!(data->fan_status[nr]
+ & FAN_STATUS_LOSPD));
+}
+
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87427_data *data = pc87427_update_device(dev);
+ int nr = attr->index;
+
+ return sprintf(buf, "%d\n", !!(data->fan_status[nr]
+ & FAN_STATUS_STALL));
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct pc87427_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int nr = attr->index;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+ int iobase = data->address[LD_FAN];
+
+ mutex_lock(&data->lock);
+ outb(BANK_FM(nr), iobase + PC87427_REG_BANK);
+ /* The low speed limit registers are read-only while monitoring
+ is enabled, so we have to disable monitoring, then change the
+ limit, and finally enable monitoring again. */
+ outb(0, iobase + PC87427_REG_FAN_STATUS);
+ data->fan_min[nr] = fan_to_reg(val);
+ outw(data->fan_min[nr], iobase + PC87427_REG_FAN_MIN);
+ outb(FAN_STATUS_MONEN, iobase + PC87427_REG_FAN_STATUS);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan_input, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan_input, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_fan_input, NULL, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+ show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+ show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+ show_fan_min, set_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+ show_fan_min, set_fan_min, 3);
+static SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO,
+ show_fan_min, set_fan_min, 4);
+static SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO,
+ show_fan_min, set_fan_min, 5);
+static SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO,
+ show_fan_min, set_fan_min, 6);
+static SENSOR_DEVICE_ATTR(fan8_min, S_IWUSR | S_IRUGO,
+ show_fan_min, set_fan_min, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_fan_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_fan_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_fan_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan8_alarm, S_IRUGO, show_fan_alarm, NULL, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_fan_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, show_fan_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, show_fan_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_fault, S_IRUGO, show_fan_fault, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_fault, S_IRUGO, show_fan_fault, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan7_fault, S_IRUGO, show_fan_fault, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan8_fault, S_IRUGO, show_fan_fault, NULL, 7);
+
+static struct attribute *pc87427_attributes_fan[8][5] = {
+ {
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan1_fault.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,
+ &sensor_dev_attr_fan2_fault.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,
+ &sensor_dev_attr_fan3_fault.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan4_fault.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan5_input.dev_attr.attr,
+ &sensor_dev_attr_fan5_min.dev_attr.attr,
+ &sensor_dev_attr_fan5_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan5_fault.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan6_input.dev_attr.attr,
+ &sensor_dev_attr_fan6_min.dev_attr.attr,
+ &sensor_dev_attr_fan6_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan6_fault.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan7_input.dev_attr.attr,
+ &sensor_dev_attr_fan7_min.dev_attr.attr,
+ &sensor_dev_attr_fan7_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan7_fault.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan8_input.dev_attr.attr,
+ &sensor_dev_attr_fan8_min.dev_attr.attr,
+ &sensor_dev_attr_fan8_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan8_fault.dev_attr.attr,
+ NULL
+ }
+};
+
+static const struct attribute_group pc87427_group_fan[8] = {
+ { .attrs = pc87427_attributes_fan[0] },
+ { .attrs = pc87427_attributes_fan[1] },
+ { .attrs = pc87427_attributes_fan[2] },
+ { .attrs = pc87427_attributes_fan[3] },
+ { .attrs = pc87427_attributes_fan[4] },
+ { .attrs = pc87427_attributes_fan[5] },
+ { .attrs = pc87427_attributes_fan[6] },
+ { .attrs = pc87427_attributes_fan[7] },
+};
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct pc87427_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+
+/*
+ * Device detection, attach and detach
+ */
+
+static void __devinit pc87427_init_device(struct device *dev)
+{
+ struct pc87427_data *data = dev_get_drvdata(dev);
+ int i;
+ u8 reg;
+
+ /* The FMC module should be ready */
+ reg = pc87427_read8(data, LD_FAN, PC87427_REG_BANK);
+ if (!(reg & 0x80))
+ dev_warn(dev, "FMC module not ready!\n");
+
+ /* Check which fans are enabled */
+ for (i = 0; i < 8; i++) {
+ reg = pc87427_read8_bank(data, LD_FAN, BANK_FM(i),
+ PC87427_REG_FAN_STATUS);
+ if (reg & FAN_STATUS_MONEN)
+ data->fan_enabled |= (1 << i);
+ }
+
+ if (!data->fan_enabled) {
+ dev_dbg(dev, "Enabling all fan inputs\n");
+ for (i = 0; i < 8; i++)
+ pc87427_write8_bank(data, LD_FAN, BANK_FM(i),
+ PC87427_REG_FAN_STATUS,
+ FAN_STATUS_MONEN);
+ data->fan_enabled = 0xff;
+ }
+}
+
+static int __devinit pc87427_probe(struct platform_device *pdev)
+{
+ struct pc87427_data *data;
+ struct resource *res;
+ int i, err;
+
+ if (!(data = kzalloc(sizeof(struct pc87427_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Out of memory\n");
+ goto exit;
+ }
+
+ /* This will need to be revisited when we add support for
+ temperature and voltage monitoring. */
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ data->address[0] = res->start;
+
+ mutex_init(&data->lock);
+ data->name = "pc87427";
+ platform_set_drvdata(pdev, data);
+ pc87427_init_device(&pdev->dev);
+
+ /* Register sysfs hooks */
+ if ((err = device_create_file(&pdev->dev, &dev_attr_name)))
+ goto exit_kfree;
+ for (i = 0; i < 8; i++) {
+ if (!(data->fan_enabled & (1 << i)))
+ continue;
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
+ &pc87427_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_remove_files:
+ for (i = 0; i < 8; i++) {
+ if (!(data->fan_enabled & (1 << i)))
+ continue;
+ sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
+ }
+exit_kfree:
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+exit:
+ return err;
+}
+
+static int __devexit pc87427_remove(struct platform_device *pdev)
+{
+ struct pc87427_data *data = platform_get_drvdata(pdev);
+ int i;
+
+ platform_set_drvdata(pdev, NULL);
+ hwmon_device_unregister(data->class_dev);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ for (i = 0; i < 8; i++) {
+ if (!(data->fan_enabled & (1 << i)))
+ continue;
+ sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
+ }
+ kfree(data);
+
+ return 0;
+}
+
+
+static struct platform_driver pc87427_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = pc87427_probe,
+ .remove = __devexit_p(pc87427_remove),
+};
+
+static int __init pc87427_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + REGION_LENGTH - 1,
+ .name = logdev_str[0],
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
+static int __init pc87427_find(int sioaddr, unsigned short *address)
+{
+ u16 val;
+ int i, err = 0;
+
+ /* Identify device */
+ val = superio_inb(sioaddr, SIOREG_DEVID);
+ if (val != 0xf2) { /* PC87427 */
+ err = -ENODEV;
+ goto exit;
+ }
+
+ for (i = 0; i < 2; i++) {
+ address[i] = 0;
+ /* Select logical device */
+ superio_outb(sioaddr, SIOREG_LDSEL, logdev[i]);
+
+ val = superio_inb(sioaddr, SIOREG_ACT);
+ if (!(val & 0x01)) {
+ printk(KERN_INFO DRVNAME ": Logical device 0x%02x "
+ "not activated\n", logdev[i]);
+ continue;
+ }
+
+ val = superio_inb(sioaddr, SIOREG_MAP);
+ if (val & 0x01) {
+ printk(KERN_WARNING DRVNAME ": Logical device 0x%02x "
+ "is memory-mapped, can't use\n", logdev[i]);
+ continue;
+ }
+
+ val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8)
+ | superio_inb(sioaddr, SIOREG_IOBASE + 1);
+ if (!val) {
+ printk(KERN_INFO DRVNAME ": I/O base address not set "
+ "for logical device 0x%02x\n", logdev[i]);
+ continue;
+ }
+ address[i] = val;
+ }
+
+exit:
+ superio_exit(sioaddr);
+ return err;
+}
+
+static int __init pc87427_init(void)
+{
+ int err;
+ unsigned short address[2];
+
+ if (pc87427_find(0x2e, address)
+ && pc87427_find(0x4e, address))
+ return -ENODEV;
+
+ /* For now the driver only handles fans so we only care about the
+ first address. */
+ if (!address[0])
+ return -ENODEV;
+
+ err = platform_driver_register(&pc87427_driver);
+ if (err)
+ goto exit;
+
+ /* Sets global pdev as a side effect */
+ err = pc87427_device_add(address[0]);
+ if (err)
+ goto exit_driver;
+
+ return 0;
+
+exit_driver:
+ platform_driver_unregister(&pc87427_driver);
+exit:
+ return err;
+}
+
+static void __exit pc87427_exit(void)
+{
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&pc87427_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("PC87427 hardware monitoring driver");
+MODULE_LICENSE("GPL");
+
+module_init(pc87427_init);
+module_exit(pc87427_exit);
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 2257806d010..212a1558c63 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -3,7 +3,7 @@
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>
+ Rudolf Marek <r.marek@assembler.cz>
David Hubbard <david.c.hubbard@gmail.com>
Shamelessly ripped from the w83627hf driver
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 4e108262576..b0fa296740d 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -3,7 +3,7 @@
monitoring
Copyright (C) 2004, 2005 Winbond Electronics Corp.
Chunhao Huang <DZShen@Winbond.com.tw>,
- Rudolf Marek <r.marek@sh.cvut.cz>
+ Rudolf Marek <r.marek@assembler.cz>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
new file mode 100644
index 00000000000..253ffaf1568
--- /dev/null
+++ b/drivers/hwmon/w83793.c
@@ -0,0 +1,1702 @@
+/*
+ w83793.c - Linux kernel driver for hardware monitoring
+ Copyright (C) 2006 Winbond Electronics Corp.
+ Yuan Mu
+ Rudolf Marek <r.marek@assembler.cz>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation - version 2.
+
+ 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.
+*/
+
+/*
+ Supports following chips:
+
+ Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
+ w83793 10 12 8 6 0x7b 0x5ca3 yes no
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(w83793);
+I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
+ "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+
+static int reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
+
+/*
+ Address 0x00, 0x0d, 0x0e, 0x0f in all three banks are reserved
+ as ID, Bank Select registers
+*/
+#define W83793_REG_BANKSEL 0x00
+#define W83793_REG_VENDORID 0x0d
+#define W83793_REG_CHIPID 0x0e
+#define W83793_REG_DEVICEID 0x0f
+
+#define W83793_REG_CONFIG 0x40
+#define W83793_REG_MFC 0x58
+#define W83793_REG_FANIN_CTRL 0x5c
+#define W83793_REG_FANIN_SEL 0x5d
+#define W83793_REG_I2C_ADDR 0x0b
+#define W83793_REG_I2C_SUBADDR 0x0c
+#define W83793_REG_VID_INA 0x05
+#define W83793_REG_VID_INB 0x06
+#define W83793_REG_VID_LATCHA 0x07
+#define W83793_REG_VID_LATCHB 0x08
+#define W83793_REG_VID_CTRL 0x59
+
+static u16 W83793_REG_TEMP_MODE[2] = { 0x5e, 0x5f };
+
+#define TEMP_READ 0
+#define TEMP_CRIT 1
+#define TEMP_CRIT_HYST 2
+#define TEMP_WARN 3
+#define TEMP_WARN_HYST 4
+/* only crit and crit_hyst affect real-time alarm status
+ current crit crit_hyst warn warn_hyst */
+static u16 W83793_REG_TEMP[][5] = {
+ {0x1c, 0x78, 0x79, 0x7a, 0x7b},
+ {0x1d, 0x7c, 0x7d, 0x7e, 0x7f},
+ {0x1e, 0x80, 0x81, 0x82, 0x83},
+ {0x1f, 0x84, 0x85, 0x86, 0x87},
+ {0x20, 0x88, 0x89, 0x8a, 0x8b},
+ {0x21, 0x8c, 0x8d, 0x8e, 0x8f},
+};
+
+#define W83793_REG_TEMP_LOW_BITS 0x22
+
+#define W83793_REG_BEEP(index) (0x53 + (index))
+#define W83793_REG_ALARM(index) (0x4b + (index))
+
+#define W83793_REG_CLR_CHASSIS 0x4a /* SMI MASK4 */
+#define W83793_REG_IRQ_CTRL 0x50
+#define W83793_REG_OVT_CTRL 0x51
+#define W83793_REG_OVT_BEEP 0x52
+
+#define IN_READ 0
+#define IN_MAX 1
+#define IN_LOW 2
+static const u16 W83793_REG_IN[][3] = {
+ /* Current, High, Low */
+ {0x10, 0x60, 0x61}, /* Vcore A */
+ {0x11, 0x62, 0x63}, /* Vcore B */
+ {0x12, 0x64, 0x65}, /* Vtt */
+ {0x14, 0x6a, 0x6b}, /* VSEN1 */
+ {0x15, 0x6c, 0x6d}, /* VSEN2 */
+ {0x16, 0x6e, 0x6f}, /* +3VSEN */
+ {0x17, 0x70, 0x71}, /* +12VSEN */
+ {0x18, 0x72, 0x73}, /* 5VDD */
+ {0x19, 0x74, 0x75}, /* 5VSB */
+ {0x1a, 0x76, 0x77}, /* VBAT */
+};
+
+/* Low Bits of Vcore A/B Vtt Read/High/Low */
+static const u16 W83793_REG_IN_LOW_BITS[] = { 0x1b, 0x68, 0x69 };
+static u8 scale_in[] = { 2, 2, 2, 16, 16, 16, 8, 24, 24, 16 };
+static u8 scale_in_add[] = { 0, 0, 0, 0, 0, 0, 0, 150, 150, 0 };
+
+#define W83793_REG_FAN(index) (0x23 + 2 * (index)) /* High byte */
+#define W83793_REG_FAN_MIN(index) (0x90 + 2 * (index)) /* High byte */
+
+#define W83793_REG_PWM_DEFAULT 0xb2
+#define W83793_REG_PWM_ENABLE 0x207
+#define W83793_REG_PWM_UPTIME 0xc3 /* Unit in 0.1 second */
+#define W83793_REG_PWM_DOWNTIME 0xc4 /* Unit in 0.1 second */
+#define W83793_REG_TEMP_CRITICAL 0xc5
+
+#define PWM_DUTY 0
+#define PWM_START 1
+#define PWM_NONSTOP 2
+#define W83793_REG_PWM(index, nr) (((nr) == 0 ? 0xb3 : \
+ (nr) == 1 ? 0x220 : 0x218) + (index))
+
+/* bit field, fan1 is bit0, fan2 is bit1 ... */
+#define W83793_REG_TEMP_FAN_MAP(index) (0x201 + (index))
+#define W83793_REG_TEMP_TOL(index) (0x208 + (index))
+#define W83793_REG_TEMP_CRUISE(index) (0x210 + (index))
+#define W83793_REG_PWM_STOP_TIME(index) (0x228 + (index))
+#define W83793_REG_SF2_TEMP(index, nr) (0x230 + ((index) << 4) + (nr))
+#define W83793_REG_SF2_PWM(index, nr) (0x238 + ((index) << 4) + (nr))
+
+static inline unsigned long FAN_FROM_REG(u16 val)
+{
+ if ((val >= 0xfff) || (val == 0))
+ return 0;
+ return (1350000UL / val);
+}
+
+static inline u16 FAN_TO_REG(long rpm)
+{
+ if (rpm <= 0)
+ return 0x0fff;
+ return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
+}
+
+static inline unsigned long TIME_FROM_REG(u8 reg)
+{
+ return (reg * 100);
+}
+
+static inline u8 TIME_TO_REG(unsigned long val)
+{
+ return SENSORS_LIMIT((val + 50) / 100, 0, 0xff);
+}
+
+static inline long TEMP_FROM_REG(s8 reg)
+{
+ return (reg * 1000);
+}
+
+static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
+{
+ return SENSORS_LIMIT((val + (val < 0 ? -500 : 500)) / 1000, min, max);
+}
+
+struct w83793_data {
+ struct i2c_client client;
+ struct i2c_client *lm75[2];
+ struct class_device *class_dev;
+ struct mutex update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+ unsigned long last_nonvolatile; /* In jiffies, last time we update the
+ nonvolatile registers */
+
+ u8 bank;
+ u8 vrm;
+ u8 vid[2];
+ u8 in[10][3]; /* Register value, read/high/low */
+ u8 in_low_bits[3]; /* Additional resolution for VCore A/B Vtt */
+
+ u16 has_fan; /* Only fan1- fan5 has own pins */
+ u16 fan[12]; /* Register value combine */
+ u16 fan_min[12]; /* Register value combine */
+
+ s8 temp[6][5]; /* current, crit, crit_hyst,warn, warn_hyst */
+ u8 temp_low_bits; /* Additional resolution TD1-TD4 */
+ u8 temp_mode[2]; /* byte 0: Temp D1-D4 mode each has 2 bits
+ byte 1: Temp R1,R2 mode, each has 1 bit */
+ u8 temp_critical; /* If reached all fan will be at full speed */
+ u8 temp_fan_map[6]; /* Temp controls which pwm fan, bit field */
+
+ u8 has_pwm;
+ u8 has_temp;
+ u8 has_vid;
+ u8 pwm_enable; /* Register value, each Temp has 1 bit */
+ u8 pwm_uptime; /* Register value */
+ u8 pwm_downtime; /* Register value */
+ u8 pwm_default; /* All fan default pwm, next poweron valid */
+ u8 pwm[8][3]; /* Register value */
+ u8 pwm_stop_time[8];
+ u8 temp_cruise[6];
+
+ u8 alarms[5]; /* realtime status registers */
+ u8 beeps[5];
+ u8 beep_enable;
+ u8 tolerance[3]; /* Temp tolerance(Smart Fan I/II) */
+ u8 sf2_pwm[6][7]; /* Smart FanII: Fan duty cycle */
+ u8 sf2_temp[6][7]; /* Smart FanII: Temp level point */
+};
+
+static u8 w83793_read_value(struct i2c_client *client, u16 reg);
+static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value);
+static int w83793_attach_adapter(struct i2c_adapter *adapter);
+static int w83793_detect(struct i2c_adapter *adapter, int address, int kind);
+static int w83793_detach_client(struct i2c_client *client);
+static void w83793_init_client(struct i2c_client *client);
+static void w83793_update_nonvolatile(struct device *dev);
+static struct w83793_data *w83793_update_device(struct device *dev);
+
+static struct i2c_driver w83793_driver = {
+ .driver = {
+ .name = "w83793",
+ },
+ .attach_adapter = w83793_attach_adapter,
+ .detach_client = w83793_detach_client,
+};
+
+static ssize_t
+show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83793_data *data = w83793_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int index = sensor_attr->index;
+
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid[index], data->vrm));
+}
+
+static ssize_t
+store_vrm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+
+ data->vrm = simple_strtoul(buf, NULL, 10);
+ return count;
+}
+
+#define ALARM_STATUS 0
+#define BEEP_ENABLE 1
+static ssize_t
+show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83793_data *data = w83793_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index >> 3;
+ int bit = sensor_attr->index & 0x07;
+ u8 val;
+
+ if (ALARM_STATUS == nr) {
+ val = (data->alarms[index] >> (bit)) & 1;
+ } else { /* BEEP_ENABLE */
+ val = (data->beeps[index] >> (bit)) & 1;
+ }
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int index = sensor_attr->index >> 3;
+ int shift = sensor_attr->index & 0x07;
+ u8 beep_bit = 1 << shift;
+ u8 val;
+
+ val = simple_strtoul(buf, NULL, 10);
+ if (val != 0 && val != 1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->beeps[index] = w83793_read_value(client, W83793_REG_BEEP(index));
+ data->beeps[index] &= ~beep_bit;
+ data->beeps[index] |= val << shift;
+ w83793_write_value(client, W83793_REG_BEEP(index), data->beeps[index]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t
+show_beep_enable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83793_data *data = w83793_update_device(dev);
+ return sprintf(buf, "%u\n", (data->beep_enable >> 1) & 0x01);
+}
+
+static ssize_t
+store_beep_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ u8 val = simple_strtoul(buf, NULL, 10);
+
+ if (val != 0 && val != 1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->beep_enable = w83793_read_value(client, W83793_REG_OVT_BEEP)
+ & 0xfd;
+ data->beep_enable |= val << 1;
+ w83793_write_value(client, W83793_REG_OVT_BEEP, data->beep_enable);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* Write any value to clear chassis alarm */
+static ssize_t
+store_chassis_clear(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ u8 val;
+
+ mutex_lock(&data->update_lock);
+ val = w83793_read_value(client, W83793_REG_CLR_CHASSIS);
+ val |= 0x80;
+ w83793_write_value(client, W83793_REG_CLR_CHASSIS, val);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+#define FAN_INPUT 0
+#define FAN_MIN 1
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83793_data *data = w83793_update_device(dev);
+ u16 val;
+
+ if (FAN_INPUT == nr) {
+ val = data->fan[index] & 0x0fff;
+ } else {
+ val = data->fan_min[index] & 0x0fff;
+ }
+
+ return sprintf(buf, "%lu\n", FAN_FROM_REG(val));
+}
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int index = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ u16 val = FAN_TO_REG(simple_strtoul(buf, NULL, 10));
+
+ mutex_lock(&data->update_lock);
+ data->fan_min[index] = val;
+ w83793_write_value(client, W83793_REG_FAN_MIN(index),
+ (val >> 8) & 0xff);
+ w83793_write_value(client, W83793_REG_FAN_MIN(index) + 1, val & 0xff);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+#define PWM_DUTY 0
+#define PWM_START 1
+#define PWM_NONSTOP 2
+#define PWM_STOP_TIME 3
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ struct w83793_data *data = w83793_update_device(dev);
+ u16 val;
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+
+ if (PWM_STOP_TIME == nr)
+ val = TIME_FROM_REG(data->pwm_stop_time[index]);
+ else
+ val = (data->pwm[index][nr] & 0x3f) << 2;
+
+ return sprintf(buf, "%d\n", val);
+}
+
+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 w83793_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ u8 val;
+
+ mutex_lock(&data->update_lock);
+ if (PWM_STOP_TIME == nr) {
+ val = TIME_TO_REG(simple_strtoul(buf, NULL, 10));
+ data->pwm_stop_time[index] = val;
+ w83793_write_value(client, W83793_REG_PWM_STOP_TIME(index),
+ val);
+ } else {
+ val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 0xff)
+ >> 2;
+ data->pwm[index][nr] =
+ w83793_read_value(client, W83793_REG_PWM(index, nr)) & 0xc0;
+ data->pwm[index][nr] |= val;
+ w83793_write_value(client, W83793_REG_PWM(index, nr),
+ data->pwm[index][nr]);
+ }
+
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83793_data *data = w83793_update_device(dev);
+ long temp = TEMP_FROM_REG(data->temp[index][nr]);
+
+ if (TEMP_READ == nr && index < 4) { /* Only TD1-TD4 have low bits */
+ int low = ((data->temp_low_bits >> (index * 2)) & 0x03) * 250;
+ temp += temp > 0 ? low : -low;
+ }
+ return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t
+store_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ long tmp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->temp[index][nr] = TEMP_TO_REG(tmp, -128, 127);
+ w83793_write_value(client, W83793_REG_TEMP[index][nr],
+ data->temp[index][nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/*
+ TD1-TD4
+ each has 4 mode:(2 bits)
+ 0: Stop monitor
+ 1: Use internal temp sensor(default)
+ 2: Reserved
+ 3: Use sensor in Intel CPU and get result by PECI
+
+ TR1-TR2
+ each has 2 mode:(1 bit)
+ 0: Disable temp sensor monitor
+ 1: To enable temp sensors monitor
+*/
+
+/* 0 disable, 6 PECI */
+static u8 TO_TEMP_MODE[] = { 0, 0, 0, 6 };
+
+static ssize_t
+show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83793_data *data = w83793_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int index = sensor_attr->index;
+ u8 mask = (index < 4) ? 0x03 : 0x01;
+ u8 shift = (index < 4) ? (2 * index) : (index - 4);
+ u8 tmp;
+ index = (index < 4) ? 0 : 1;
+
+ tmp = (data->temp_mode[index] >> shift) & mask;
+
+ /* for the internal sensor, found out if diode or thermistor */
+ if (tmp == 1) {
+ tmp = index == 0 ? 3 : 4;
+ } else {
+ tmp = TO_TEMP_MODE[tmp];
+ }
+
+ return sprintf(buf, "%d\n", tmp);
+}
+
+static ssize_t
+store_temp_mode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int index = sensor_attr->index;
+ u8 mask = (index < 4) ? 0x03 : 0x01;
+ u8 shift = (index < 4) ? (2 * index) : (index - 4);
+ u8 val = simple_strtoul(buf, NULL, 10);
+
+ /* transform the sysfs interface values into table above */
+ if ((val == 6) && (index < 4)) {
+ val -= 3;
+ } else if ((val == 3 && index < 4)
+ || (val == 4 && index >= 4)) {
+ /* transform diode or thermistor into internal enable */
+ val = !!val;
+ } else {
+ return -EINVAL;
+ }
+
+ index = (index < 4) ? 0 : 1;
+ mutex_lock(&data->update_lock);
+ data->temp_mode[index] =
+ w83793_read_value(client, W83793_REG_TEMP_MODE[index]);
+ data->temp_mode[index] &= ~(mask << shift);
+ data->temp_mode[index] |= val << shift;
+ w83793_write_value(client, W83793_REG_TEMP_MODE[index],
+ data->temp_mode[index]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+#define SETUP_PWM_DEFAULT 0
+#define SETUP_PWM_UPTIME 1 /* Unit in 0.1s */
+#define SETUP_PWM_DOWNTIME 2 /* Unit in 0.1s */
+#define SETUP_TEMP_CRITICAL 3
+static ssize_t
+show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ struct w83793_data *data = w83793_update_device(dev);
+ u32 val = 0;
+
+ if (SETUP_PWM_DEFAULT == nr) {
+ val = (data->pwm_default & 0x3f) << 2;
+ } else if (SETUP_PWM_UPTIME == nr) {
+ val = TIME_FROM_REG(data->pwm_uptime);
+ } else if (SETUP_PWM_DOWNTIME == nr) {
+ val = TIME_FROM_REG(data->pwm_downtime);
+ } else if (SETUP_TEMP_CRITICAL == nr) {
+ val = TEMP_FROM_REG(data->temp_critical & 0x7f);
+ }
+
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+store_sf_setup(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->update_lock);
+ if (SETUP_PWM_DEFAULT == nr) {
+ data->pwm_default =
+ w83793_read_value(client, W83793_REG_PWM_DEFAULT) & 0xc0;
+ data->pwm_default |= SENSORS_LIMIT(simple_strtoul(buf, NULL,
+ 10),
+ 0, 0xff) >> 2;
+ w83793_write_value(client, W83793_REG_PWM_DEFAULT,
+ data->pwm_default);
+ } else if (SETUP_PWM_UPTIME == nr) {
+ data->pwm_uptime = TIME_TO_REG(simple_strtoul(buf, NULL, 10));
+ data->pwm_uptime += data->pwm_uptime == 0 ? 1 : 0;
+ w83793_write_value(client, W83793_REG_PWM_UPTIME,
+ data->pwm_uptime);
+ } else if (SETUP_PWM_DOWNTIME == nr) {
+ data->pwm_downtime = TIME_TO_REG(simple_strtoul(buf, NULL, 10));
+ data->pwm_downtime += data->pwm_downtime == 0 ? 1 : 0;
+ w83793_write_value(client, W83793_REG_PWM_DOWNTIME,
+ data->pwm_downtime);
+ } else { /* SETUP_TEMP_CRITICAL */
+ data->temp_critical =
+ w83793_read_value(client, W83793_REG_TEMP_CRITICAL) & 0x80;
+ data->temp_critical |= TEMP_TO_REG(simple_strtol(buf, NULL, 10),
+ 0, 0x7f);
+ w83793_write_value(client, W83793_REG_TEMP_CRITICAL,
+ data->temp_critical);
+ }
+
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/*
+ Temp SmartFan control
+ TEMP_FAN_MAP
+ Temp channel control which pwm fan, bitfield, bit 0 indicate pwm1...
+ It's possible two or more temp channels control the same fan, w83793
+ always prefers to pick the most critical request and applies it to
+ the related Fan.
+ It's possible one fan is not in any mapping of 6 temp channels, this
+ means the fan is manual mode
+
+ TEMP_PWM_ENABLE
+ Each temp channel has its own SmartFan mode, and temp channel
+ control fans that are set by TEMP_FAN_MAP
+ 0: SmartFanII mode
+ 1: Thermal Cruise Mode
+
+ TEMP_CRUISE
+ Target temperature in thermal cruise mode, w83793 will try to turn
+ fan speed to keep the temperature of target device around this
+ temperature.
+
+ TEMP_TOLERANCE
+ If Temp higher or lower than target with this tolerance, w83793
+ will take actions to speed up or slow down the fan to keep the
+ temperature within the tolerance range.
+*/
+
+#define TEMP_FAN_MAP 0
+#define TEMP_PWM_ENABLE 1
+#define TEMP_CRUISE 2
+#define TEMP_TOLERANCE 3
+static ssize_t
+show_sf_ctrl(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83793_data *data = w83793_update_device(dev);
+ u32 val;
+
+ if (TEMP_FAN_MAP == nr) {
+ val = data->temp_fan_map[index];
+ } else if (TEMP_PWM_ENABLE == nr) {
+ /* +2 to transfrom into 2 and 3 to conform with sysfs intf */
+ val = ((data->pwm_enable >> index) & 0x01) + 2;
+ } else if (TEMP_CRUISE == nr) {
+ val = TEMP_FROM_REG(data->temp_cruise[index] & 0x7f);
+ } else { /* TEMP_TOLERANCE */
+ val = data->tolerance[index >> 1] >> ((index & 0x01) ? 4 : 0);
+ val = TEMP_FROM_REG(val & 0x0f);
+ }
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+store_sf_ctrl(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ u32 val;
+
+ mutex_lock(&data->update_lock);
+ if (TEMP_FAN_MAP == nr) {
+ val = simple_strtoul(buf, NULL, 10) & 0xff;
+ w83793_write_value(client, W83793_REG_TEMP_FAN_MAP(index), val);
+ data->temp_fan_map[index] = val;
+ } else if (TEMP_PWM_ENABLE == nr) {
+ val = simple_strtoul(buf, NULL, 10);
+ if (2 == val || 3 == val) {
+ data->pwm_enable =
+ w83793_read_value(client, W83793_REG_PWM_ENABLE);
+ if (val - 2)
+ data->pwm_enable |= 1 << index;
+ else
+ data->pwm_enable &= ~(1 << index);
+ w83793_write_value(client, W83793_REG_PWM_ENABLE,
+ data->pwm_enable);
+ } else {
+ mutex_unlock(&data->update_lock);
+ return -EINVAL;
+ }
+ } else if (TEMP_CRUISE == nr) {
+ data->temp_cruise[index] =
+ w83793_read_value(client, W83793_REG_TEMP_CRUISE(index));
+ val = TEMP_TO_REG(simple_strtol(buf, NULL, 10), 0, 0x7f);
+ data->temp_cruise[index] &= 0x80;
+ data->temp_cruise[index] |= val;
+
+ w83793_write_value(client, W83793_REG_TEMP_CRUISE(index),
+ data->temp_cruise[index]);
+ } else { /* TEMP_TOLERANCE */
+ int i = index >> 1;
+ u8 shift = (index & 0x01) ? 4 : 0;
+ data->tolerance[i] =
+ w83793_read_value(client, W83793_REG_TEMP_TOL(i));
+
+ val = TEMP_TO_REG(simple_strtol(buf, NULL, 10), 0, 0x0f);
+ data->tolerance[i] &= ~(0x0f << shift);
+ data->tolerance[i] |= val << shift;
+ w83793_write_value(client, W83793_REG_TEMP_TOL(i),
+ data->tolerance[i]);
+ }
+
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_sf2_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83793_data *data = w83793_update_device(dev);
+
+ return sprintf(buf, "%d\n", (data->sf2_pwm[index][nr] & 0x3f) << 2);
+}
+
+static ssize_t
+store_sf2_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ u8 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 0xff) >> 2;
+
+ mutex_lock(&data->update_lock);
+ data->sf2_pwm[index][nr] =
+ w83793_read_value(client, W83793_REG_SF2_PWM(index, nr)) & 0xc0;
+ data->sf2_pwm[index][nr] |= val;
+ w83793_write_value(client, W83793_REG_SF2_PWM(index, nr),
+ data->sf2_pwm[index][nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_sf2_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83793_data *data = w83793_update_device(dev);
+
+ return sprintf(buf, "%ld\n",
+ TEMP_FROM_REG(data->sf2_temp[index][nr] & 0x7f));
+}
+
+static ssize_t
+store_sf2_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ u8 val = TEMP_TO_REG(simple_strtol(buf, NULL, 10), 0, 0x7f);
+
+ mutex_lock(&data->update_lock);
+ data->sf2_temp[index][nr] =
+ w83793_read_value(client, W83793_REG_SF2_TEMP(index, nr)) & 0x80;
+ data->sf2_temp[index][nr] |= val;
+ w83793_write_value(client, W83793_REG_SF2_TEMP(index, nr),
+ data->sf2_temp[index][nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/* only Vcore A/B and Vtt have additional 2 bits precision */
+static ssize_t
+show_in(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83793_data *data = w83793_update_device(dev);
+ u16 val = data->in[index][nr];
+
+ if (index < 3) {
+ val <<= 2;
+ val += (data->in_low_bits[nr] >> (index * 2)) & 0x3;
+ }
+ /* voltage inputs 5VDD and 5VSB needs 150mV offset */
+ val = val * scale_in[index] + scale_in_add[index];
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+store_in(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ u32 val;
+
+ val =
+ (simple_strtoul(buf, NULL, 10) +
+ scale_in[index] / 2) / scale_in[index];
+ mutex_lock(&data->update_lock);
+ if (index > 2) {
+ /* fix the limit values of 5VDD and 5VSB to ALARM mechanism */
+ if (1 == nr || 2 == nr) {
+ val -= scale_in_add[index] / scale_in[index];
+ }
+ val = SENSORS_LIMIT(val, 0, 255);
+ } else {
+ val = SENSORS_LIMIT(val, 0, 0x3FF);
+ data->in_low_bits[nr] =
+ w83793_read_value(client, W83793_REG_IN_LOW_BITS[nr]);
+ data->in_low_bits[nr] &= ~(0x03 << (2 * index));
+ data->in_low_bits[nr] |= (val & 0x03) << (2 * index);
+ w83793_write_value(client, W83793_REG_IN_LOW_BITS[nr],
+ data->in_low_bits[nr]);
+ val >>= 2;
+ }
+ data->in[index][nr] = val;
+ w83793_write_value(client, W83793_REG_IN[index][nr],
+ data->in[index][nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+#define NOT_USED -1
+
+#define SENSOR_ATTR_IN(index) \
+ SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \
+ IN_READ, index), \
+ SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \
+ store_in, IN_MAX, index), \
+ SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \
+ store_in, IN_LOW, index), \
+ SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \
+ NULL, ALARM_STATUS, index + ((index > 2) ? 1 : 0)), \
+ SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \
+ show_alarm_beep, store_beep, BEEP_ENABLE, \
+ index + ((index > 2) ? 1 : 0))
+
+#define SENSOR_ATTR_FAN(index) \
+ SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \
+ NULL, ALARM_STATUS, index + 17), \
+ SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \
+ show_alarm_beep, store_beep, BEEP_ENABLE, index + 17), \
+ SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \
+ NULL, FAN_INPUT, index - 1), \
+ SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \
+ show_fan, store_fan_min, FAN_MIN, index - 1)
+
+#define SENSOR_ATTR_PWM(index) \
+ SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \
+ store_pwm, PWM_DUTY, index - 1), \
+ SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \
+ show_pwm, store_pwm, PWM_NONSTOP, index - 1), \
+ SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \
+ show_pwm, store_pwm, PWM_START, index - 1), \
+ SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \
+ show_pwm, store_pwm, PWM_STOP_TIME, index - 1)
+
+#define SENSOR_ATTR_TEMP(index) \
+ SENSOR_ATTR_2(temp##index##_type, S_IRUGO | S_IWUSR, \
+ show_temp_mode, store_temp_mode, NOT_USED, index - 1), \
+ SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \
+ NULL, TEMP_READ, index - 1), \
+ SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \
+ store_temp, TEMP_CRIT, index - 1), \
+ SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \
+ show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \
+ SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_temp, \
+ store_temp, TEMP_WARN, index - 1), \
+ SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR, \
+ show_temp, store_temp, TEMP_WARN_HYST, index - 1), \
+ SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \
+ show_alarm_beep, NULL, ALARM_STATUS, index + 11), \
+ SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \
+ show_alarm_beep, store_beep, BEEP_ENABLE, index + 11), \
+ SENSOR_ATTR_2(temp##index##_auto_channels_pwm, \
+ S_IRUGO | S_IWUSR, show_sf_ctrl, store_sf_ctrl, \
+ TEMP_FAN_MAP, index - 1), \
+ SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \
+ show_sf_ctrl, store_sf_ctrl, TEMP_PWM_ENABLE, \
+ index - 1), \
+ SENSOR_ATTR_2(thermal_cruise##index, S_IRUGO | S_IWUSR, \
+ show_sf_ctrl, store_sf_ctrl, TEMP_CRUISE, index - 1), \
+ SENSOR_ATTR_2(tolerance##index, S_IRUGO | S_IWUSR, show_sf_ctrl,\
+ store_sf_ctrl, TEMP_TOLERANCE, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \
+ show_sf2_pwm, store_sf2_pwm, 0, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \
+ show_sf2_pwm, store_sf2_pwm, 1, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \
+ show_sf2_pwm, store_sf2_pwm, 2, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \
+ show_sf2_pwm, store_sf2_pwm, 3, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \
+ show_sf2_pwm, store_sf2_pwm, 4, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \
+ show_sf2_pwm, store_sf2_pwm, 5, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \
+ show_sf2_pwm, store_sf2_pwm, 6, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\
+ show_sf2_temp, store_sf2_temp, 0, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\
+ show_sf2_temp, store_sf2_temp, 1, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\
+ show_sf2_temp, store_sf2_temp, 2, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\
+ show_sf2_temp, store_sf2_temp, 3, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\
+ show_sf2_temp, store_sf2_temp, 4, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\
+ show_sf2_temp, store_sf2_temp, 5, index - 1), \
+ SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\
+ show_sf2_temp, store_sf2_temp, 6, index - 1)
+
+static struct sensor_device_attribute_2 w83793_sensor_attr_2[] = {
+ SENSOR_ATTR_IN(0),
+ SENSOR_ATTR_IN(1),
+ SENSOR_ATTR_IN(2),
+ SENSOR_ATTR_IN(3),
+ SENSOR_ATTR_IN(4),
+ SENSOR_ATTR_IN(5),
+ SENSOR_ATTR_IN(6),
+ SENSOR_ATTR_IN(7),
+ SENSOR_ATTR_IN(8),
+ SENSOR_ATTR_IN(9),
+ SENSOR_ATTR_FAN(1),
+ SENSOR_ATTR_FAN(2),
+ SENSOR_ATTR_FAN(3),
+ SENSOR_ATTR_FAN(4),
+ SENSOR_ATTR_FAN(5),
+ SENSOR_ATTR_PWM(1),
+ SENSOR_ATTR_PWM(2),
+ SENSOR_ATTR_PWM(3),
+};
+
+static struct sensor_device_attribute_2 w83793_temp[] = {
+ SENSOR_ATTR_TEMP(1),
+ SENSOR_ATTR_TEMP(2),
+ SENSOR_ATTR_TEMP(3),
+ SENSOR_ATTR_TEMP(4),
+ SENSOR_ATTR_TEMP(5),
+ SENSOR_ATTR_TEMP(6),
+};
+
+/* Fan6-Fan12 */
+static struct sensor_device_attribute_2 w83793_left_fan[] = {
+ SENSOR_ATTR_FAN(6),
+ SENSOR_ATTR_FAN(7),
+ SENSOR_ATTR_FAN(8),
+ SENSOR_ATTR_FAN(9),
+ SENSOR_ATTR_FAN(10),
+ SENSOR_ATTR_FAN(11),
+ SENSOR_ATTR_FAN(12),
+};
+
+/* Pwm4-Pwm8 */
+static struct sensor_device_attribute_2 w83793_left_pwm[] = {
+ SENSOR_ATTR_PWM(4),
+ SENSOR_ATTR_PWM(5),
+ SENSOR_ATTR_PWM(6),
+ SENSOR_ATTR_PWM(7),
+ SENSOR_ATTR_PWM(8),
+};
+
+static struct sensor_device_attribute_2 w83793_vid[] = {
+ SENSOR_ATTR_2(cpu0_vid, S_IRUGO, show_vid, NULL, NOT_USED, 0),
+ SENSOR_ATTR_2(cpu1_vid, S_IRUGO, show_vid, NULL, NOT_USED, 1),
+};
+
+static struct sensor_device_attribute_2 sda_single_files[] = {
+ SENSOR_ATTR_2(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm,
+ NOT_USED, NOT_USED),
+ SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep,
+ store_chassis_clear, ALARM_STATUS, 30),
+ SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
+ store_beep_enable, NOT_USED, NOT_USED),
+ SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup,
+ store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED),
+ SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup,
+ store_sf_setup, SETUP_PWM_UPTIME, NOT_USED),
+ SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup,
+ store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED),
+ SENSOR_ATTR_2(temp_critical, S_IWUSR | S_IRUGO, show_sf_setup,
+ store_sf_setup, SETUP_TEMP_CRITICAL, NOT_USED),
+};
+
+static void w83793_init_client(struct i2c_client *client)
+{
+ if (reset) {
+ w83793_write_value(client, W83793_REG_CONFIG, 0x80);
+ }
+
+ /* Start monitoring */
+ w83793_write_value(client, W83793_REG_CONFIG,
+ w83793_read_value(client, W83793_REG_CONFIG) | 0x01);
+
+}
+
+static int w83793_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, w83793_detect);
+}
+
+static int w83793_detach_client(struct i2c_client *client)
+{
+ struct w83793_data *data = i2c_get_clientdata(client);
+ struct device *dev = &client->dev;
+ int err, i;
+
+ /* main client */
+ if (data) {
+ hwmon_device_unregister(data->class_dev);
+
+ for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
+ device_remove_file(dev,
+ &w83793_sensor_attr_2[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
+ device_remove_file(dev, &sda_single_files[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
+ device_remove_file(dev, &w83793_vid[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
+ device_remove_file(dev, &w83793_left_fan[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++)
+ device_remove_file(dev, &w83793_left_pwm[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
+ device_remove_file(dev, &w83793_temp[i].dev_attr);
+ }
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ /* main client */
+ if (data)
+ kfree(data);
+ /* subclient */
+ else
+ kfree(client);
+
+ return 0;
+}
+
+static int
+w83793_create_subclient(struct i2c_adapter *adapter,
+ struct i2c_client *client, int addr,
+ struct i2c_client **sub_cli)
+{
+ int err = 0;
+ struct i2c_client *sub_client;
+
+ (*sub_cli) = sub_client =
+ kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (!(sub_client)) {
+ return -ENOMEM;
+ }
+ sub_client->addr = 0x48 + addr;
+ i2c_set_clientdata(sub_client, NULL);
+ sub_client->adapter = adapter;
+ sub_client->driver = &w83793_driver;
+ strlcpy(sub_client->name, "w83793 subclient", I2C_NAME_SIZE);
+ if ((err = i2c_attach_client(sub_client))) {
+ dev_err(&client->dev, "subclient registration "
+ "at address 0x%x failed\n", sub_client->addr);
+ kfree(sub_client);
+ }
+ return err;
+}
+
+static int
+w83793_detect_subclients(struct i2c_adapter *adapter, int address,
+ int kind, struct i2c_client *client)
+{
+ int i, id, err;
+ u8 tmp;
+ struct w83793_data *data = i2c_get_clientdata(client);
+
+ id = i2c_adapter_id(adapter);
+ if (force_subclients[0] == id && force_subclients[1] == address) {
+ for (i = 2; i <= 3; i++) {
+ if (force_subclients[i] < 0x48
+ || force_subclients[i] > 0x4f) {
+ dev_err(&client->dev,
+ "invalid subclient "
+ "address %d; must be 0x48-0x4f\n",
+ force_subclients[i]);
+ err = -EINVAL;
+ goto ERROR_SC_0;
+ }
+ }
+ w83793_write_value(client, W83793_REG_I2C_SUBADDR,
+ (force_subclients[2] & 0x07) |
+ ((force_subclients[3] & 0x07) << 4));
+ }
+
+ tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR);
+ if (!(tmp & 0x08)) {
+ err =
+ w83793_create_subclient(adapter, client, tmp & 0x7,
+ &data->lm75[0]);
+ if (err < 0)
+ goto ERROR_SC_0;
+ }
+ if (!(tmp & 0x80)) {
+ if ((data->lm75[0] != NULL)
+ && ((tmp & 0x7) == ((tmp >> 4) & 0x7))) {
+ dev_err(&client->dev,
+ "duplicate addresses 0x%x, "
+ "use force_subclients\n", data->lm75[0]->addr);
+ err = -ENODEV;
+ goto ERROR_SC_1;
+ }
+ err = w83793_create_subclient(adapter, client,
+ (tmp >> 4) & 0x7, &data->lm75[1]);
+ if (err < 0)
+ goto ERROR_SC_1;
+ }
+
+ return 0;
+
+ /* Undo inits in case of errors */
+
+ERROR_SC_1:
+ if (data->lm75[0] != NULL) {
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[0]);
+ }
+ERROR_SC_0:
+ return err;
+}
+
+static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ int i;
+ u8 tmp, val;
+ struct i2c_client *client;
+ struct device *dev;
+ struct w83793_data *data;
+ int files_fan = ARRAY_SIZE(w83793_left_fan) / 7;
+ int files_pwm = ARRAY_SIZE(w83793_left_pwm) / 5;
+ int files_temp = ARRAY_SIZE(w83793_temp) / 6;
+ int err = 0;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ goto exit;
+ }
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet.
+ But it allows us to access w83793_{read,write}_value. */
+
+ if (!(data = kzalloc(sizeof(struct w83793_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ dev = &client->dev;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &w83793_driver;
+
+ data->bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
+
+ /* Now, we do the remaining detection. */
+ if (kind < 0) {
+ tmp = data->bank & 0x80 ? 0x5c : 0xa3;
+ /* Check Winbond vendor ID */
+ if (tmp != i2c_smbus_read_byte_data(client,
+ W83793_REG_VENDORID)) {
+ pr_debug("w83793: Detection failed at check "
+ "vendor id\n");
+ err = -ENODEV;
+ goto free_mem;
+ }
+
+ /* If Winbond chip, address of chip and W83793_REG_I2C_ADDR
+ should match */
+ if ((data->bank & 0x07) == 0
+ && i2c_smbus_read_byte_data(client, W83793_REG_I2C_ADDR) !=
+ (address << 1)) {
+ pr_debug("w83793: Detection failed at check "
+ "i2c addr\n");
+ err = -ENODEV;
+ goto free_mem;
+ }
+
+ }
+
+ /* We have either had a force parameter, or we have already detected the
+ Winbond. Determine the chip type now */
+
+ if (kind <= 0) {
+ if (0x7b == w83793_read_value(client, W83793_REG_CHIPID)) {
+ kind = w83793;
+ } else {
+ if (kind == 0)
+ dev_warn(&adapter->dev, "w83793: Ignoring "
+ "'force' parameter for unknown chip "
+ "at address 0x%02x\n", address);
+ err = -ENODEV;
+ goto free_mem;
+ }
+ }
+
+ /* Fill in the remaining client fields and put into the global list */
+ strlcpy(client->name, "w83793", I2C_NAME_SIZE);
+
+ mutex_init(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto free_mem;
+
+ if ((err = w83793_detect_subclients(adapter, address, kind, client)))
+ goto detach_client;
+
+ /* Initialize the chip */
+ w83793_init_client(client);
+
+ data->vrm = vid_which_vrm();
+ /*
+ Only fan 1-5 has their own input pins,
+ Pwm 1-3 has their own pins
+ */
+ data->has_fan = 0x1f;
+ data->has_pwm = 0x07;
+ tmp = w83793_read_value(client, W83793_REG_MFC);
+ val = w83793_read_value(client, W83793_REG_FANIN_CTRL);
+
+ /* check the function of pins 49-56 */
+ if (!(tmp & 0x80)) {
+ data->has_pwm |= 0x18; /* pwm 4,5 */
+ if (val & 0x01) { /* fan 6 */
+ data->has_fan |= 0x20;
+ data->has_pwm |= 0x20;
+ }
+ if (val & 0x02) { /* fan 7 */
+ data->has_fan |= 0x40;
+ data->has_pwm |= 0x40;
+ }
+ if (!(tmp & 0x40) && (val & 0x04)) { /* fan 8 */
+ data->has_fan |= 0x80;
+ data->has_pwm |= 0x80;
+ }
+ }
+
+ if (0x08 == (tmp & 0x0c)) {
+ if (val & 0x08) /* fan 9 */
+ data->has_fan |= 0x100;
+ if (val & 0x10) /* fan 10 */
+ data->has_fan |= 0x200;
+ }
+
+ if (0x20 == (tmp & 0x30)) {
+ if (val & 0x20) /* fan 11 */
+ data->has_fan |= 0x400;
+ if (val & 0x40) /* fan 12 */
+ data->has_fan |= 0x800;
+ }
+
+ if ((tmp & 0x01) && (val & 0x04)) { /* fan 8, second location */
+ data->has_fan |= 0x80;
+ data->has_pwm |= 0x80;
+ }
+
+ tmp = w83793_read_value(client, W83793_REG_FANIN_SEL);
+ if ((tmp & 0x01) && (val & 0x08)) { /* fan 9, second location */
+ data->has_fan |= 0x100;
+ }
+ if ((tmp & 0x02) && (val & 0x10)) { /* fan 10, second location */
+ data->has_fan |= 0x200;
+ }
+ if ((tmp & 0x04) && (val & 0x20)) { /* fan 11, second location */
+ data->has_fan |= 0x400;
+ }
+ if ((tmp & 0x08) && (val & 0x40)) { /* fan 12, second location */
+ data->has_fan |= 0x800;
+ }
+
+ /* check the temp1-6 mode, ignore former AMDSI selected inputs */
+ tmp = w83793_read_value(client,W83793_REG_TEMP_MODE[0]);
+ if (tmp & 0x01)
+ data->has_temp |= 0x01;
+ if (tmp & 0x04)
+ data->has_temp |= 0x02;
+ if (tmp & 0x10)
+ data->has_temp |= 0x04;
+ if (tmp & 0x40)
+ data->has_temp |= 0x08;
+
+ tmp = w83793_read_value(client,W83793_REG_TEMP_MODE[1]);
+ if (tmp & 0x01)
+ data->has_temp |= 0x10;
+ if (tmp & 0x02)
+ data->has_temp |= 0x20;
+
+ /* Detect the VID usage and ignore unused input */
+ tmp = w83793_read_value(client, W83793_REG_MFC);
+ if (!(tmp & 0x29))
+ data->has_vid |= 0x1; /* has VIDA */
+ if (tmp & 0x80)
+ data->has_vid |= 0x2; /* has VIDB */
+
+ /* Register sysfs hooks */
+ for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) {
+ err = device_create_file(dev,
+ &w83793_sensor_attr_2[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(w83793_vid); i++) {
+ if (!(data->has_vid & (1 << i)))
+ continue;
+ err = device_create_file(dev, &w83793_vid[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
+ err = device_create_file(dev, &sda_single_files[i].dev_attr);
+ if (err)
+ goto exit_remove;
+
+ }
+
+ for (i = 0; i < 6; i++) {
+ int j;
+ if (!(data->has_temp & (1 << i)))
+ continue;
+ for (j = 0; j < files_temp; j++) {
+ err = device_create_file(dev,
+ &w83793_temp[(i) * files_temp
+ + j].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ }
+
+ for (i = 5; i < 12; i++) {
+ int j;
+ if (!(data->has_fan & (1 << i)))
+ continue;
+ for (j = 0; j < files_fan; j++) {
+ err = device_create_file(dev,
+ &w83793_left_fan[(i - 5) * files_fan
+ + j].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ }
+
+ for (i = 3; i < 8; i++) {
+ int j;
+ if (!(data->has_pwm & (1 << i)))
+ continue;
+ for (j = 0; j < files_pwm; j++) {
+ err = device_create_file(dev,
+ &w83793_left_pwm[(i - 3) * files_pwm
+ + j].dev_attr);
+ if (err)
+ 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;
+
+ /* Unregister sysfs hooks */
+
+exit_remove:
+ for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
+ device_remove_file(dev, &w83793_sensor_attr_2[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
+ device_remove_file(dev, &sda_single_files[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
+ device_remove_file(dev, &w83793_vid[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
+ device_remove_file(dev, &w83793_left_fan[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++)
+ device_remove_file(dev, &w83793_left_pwm[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
+ device_remove_file(dev, &w83793_temp[i].dev_attr);
+
+ if (data->lm75[0] != NULL) {
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[0]);
+ }
+ if (data->lm75[1] != NULL) {
+ i2c_detach_client(data->lm75[1]);
+ kfree(data->lm75[1]);
+ }
+detach_client:
+ i2c_detach_client(client);
+free_mem:
+ kfree(data);
+exit:
+ return err;
+}
+
+static void w83793_update_nonvolatile(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ int i, j;
+ /*
+ They are somewhat "stable" registers, and to update them everytime
+ takes so much time, it's just not worthy. Update them in a long
+ interval to avoid exception.
+ */
+ if (!(time_after(jiffies, data->last_nonvolatile + HZ * 300)
+ || !data->valid))
+ return;
+ /* update voltage limits */
+ for (i = 1; i < 3; i++) {
+ for (j = 0; j < ARRAY_SIZE(data->in); j++) {
+ data->in[j][i] =
+ w83793_read_value(client, W83793_REG_IN[j][i]);
+ }
+ data->in_low_bits[i] =
+ w83793_read_value(client, W83793_REG_IN_LOW_BITS[i]);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
+ /* Update the Fan measured value and limits */
+ if (!(data->has_fan & (1 << i))) {
+ continue;
+ }
+ data->fan_min[i] =
+ w83793_read_value(client, W83793_REG_FAN_MIN(i)) << 8;
+ data->fan_min[i] |=
+ w83793_read_value(client, W83793_REG_FAN_MIN(i) + 1);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(data->temp_fan_map); i++) {
+ if (!(data->has_temp & (1 << i)))
+ continue;
+ data->temp_fan_map[i] =
+ w83793_read_value(client, W83793_REG_TEMP_FAN_MAP(i));
+ for (j = 1; j < 5; j++) {
+ data->temp[i][j] =
+ w83793_read_value(client, W83793_REG_TEMP[i][j]);
+ }
+ data->temp_cruise[i] =
+ w83793_read_value(client, W83793_REG_TEMP_CRUISE(i));
+ for (j = 0; j < 7; j++) {
+ data->sf2_pwm[i][j] =
+ w83793_read_value(client, W83793_REG_SF2_PWM(i, j));
+ data->sf2_temp[i][j] =
+ w83793_read_value(client,
+ W83793_REG_SF2_TEMP(i, j));
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(data->temp_mode); i++)
+ data->temp_mode[i] =
+ w83793_read_value(client, W83793_REG_TEMP_MODE[i]);
+
+ for (i = 0; i < ARRAY_SIZE(data->tolerance); i++) {
+ data->tolerance[i] =
+ w83793_read_value(client, W83793_REG_TEMP_TOL(i));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(data->pwm); i++) {
+ if (!(data->has_pwm & (1 << i)))
+ continue;
+ data->pwm[i][PWM_NONSTOP] =
+ w83793_read_value(client, W83793_REG_PWM(i, PWM_NONSTOP));
+ data->pwm[i][PWM_START] =
+ w83793_read_value(client, W83793_REG_PWM(i, PWM_START));
+ data->pwm_stop_time[i] =
+ w83793_read_value(client, W83793_REG_PWM_STOP_TIME(i));
+ }
+
+ data->pwm_default = w83793_read_value(client, W83793_REG_PWM_DEFAULT);
+ data->pwm_enable = w83793_read_value(client, W83793_REG_PWM_ENABLE);
+ data->pwm_uptime = w83793_read_value(client, W83793_REG_PWM_UPTIME);
+ data->pwm_downtime = w83793_read_value(client, W83793_REG_PWM_DOWNTIME);
+ data->temp_critical =
+ w83793_read_value(client, W83793_REG_TEMP_CRITICAL);
+ data->beep_enable = w83793_read_value(client, W83793_REG_OVT_BEEP);
+
+ for (i = 0; i < ARRAY_SIZE(data->beeps); i++) {
+ data->beeps[i] = w83793_read_value(client, W83793_REG_BEEP(i));
+ }
+
+ data->last_nonvolatile = jiffies;
+}
+
+static struct w83793_data *w83793_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83793_data *data = i2c_get_clientdata(client);
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ if (!(time_after(jiffies, data->last_updated + HZ * 2)
+ || !data->valid))
+ goto END;
+
+ /* Update the voltages measured value and limits */
+ for (i = 0; i < ARRAY_SIZE(data->in); i++)
+ data->in[i][IN_READ] =
+ w83793_read_value(client, W83793_REG_IN[i][IN_READ]);
+
+ data->in_low_bits[IN_READ] =
+ w83793_read_value(client, W83793_REG_IN_LOW_BITS[IN_READ]);
+
+ for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
+ if (!(data->has_fan & (1 << i))) {
+ continue;
+ }
+ data->fan[i] =
+ w83793_read_value(client, W83793_REG_FAN(i)) << 8;
+ data->fan[i] |=
+ w83793_read_value(client, W83793_REG_FAN(i) + 1);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+ if (!(data->has_temp & (1 << i)))
+ continue;
+ data->temp[i][TEMP_READ] =
+ w83793_read_value(client, W83793_REG_TEMP[i][TEMP_READ]);
+ }
+
+ data->temp_low_bits =
+ w83793_read_value(client, W83793_REG_TEMP_LOW_BITS);
+
+ for (i = 0; i < ARRAY_SIZE(data->pwm); i++) {
+ if (data->has_pwm & (1 << i))
+ data->pwm[i][PWM_DUTY] =
+ w83793_read_value(client,
+ W83793_REG_PWM(i, PWM_DUTY));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(data->alarms); i++)
+ data->alarms[i] =
+ w83793_read_value(client, W83793_REG_ALARM(i));
+ if (data->has_vid & 0x01)
+ data->vid[0] = w83793_read_value(client, W83793_REG_VID_INA);
+ if (data->has_vid & 0x02)
+ data->vid[1] = w83793_read_value(client, W83793_REG_VID_INB);
+ w83793_update_nonvolatile(dev);
+ data->last_updated = jiffies;
+ data->valid = 1;
+
+END:
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+/* Ignore the possibility that somebody change bank outside the driver
+ Must be called with data->update_lock held, except during initialization */
+static u8 w83793_read_value(struct i2c_client *client, u16 reg)
+{
+ struct w83793_data *data = i2c_get_clientdata(client);
+ u8 res = 0xff;
+ u8 new_bank = reg >> 8;
+
+ new_bank |= data->bank & 0xfc;
+ if (data->bank != new_bank) {
+ if (i2c_smbus_write_byte_data
+ (client, W83793_REG_BANKSEL, new_bank) >= 0)
+ data->bank = new_bank;
+ else {
+ dev_err(&client->dev,
+ "set bank to %d failed, fall back "
+ "to bank %d, read reg 0x%x error\n",
+ new_bank, data->bank, reg);
+ res = 0x0; /* read 0x0 from the chip */
+ goto END;
+ }
+ }
+ res = i2c_smbus_read_byte_data(client, reg & 0xff);
+END:
+ return res;
+}
+
+/* Must be called with data->update_lock held, except during initialization */
+static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value)
+{
+ struct w83793_data *data = i2c_get_clientdata(client);
+ int res;
+ u8 new_bank = reg >> 8;
+
+ new_bank |= data->bank & 0xfc;
+ if (data->bank != new_bank) {
+ if ((res = i2c_smbus_write_byte_data
+ (client, W83793_REG_BANKSEL, new_bank)) >= 0)
+ data->bank = new_bank;
+ else {
+ dev_err(&client->dev,
+ "set bank to %d failed, fall back "
+ "to bank %d, write reg 0x%x error\n",
+ new_bank, data->bank, reg);
+ goto END;
+ }
+ }
+
+ res = i2c_smbus_write_byte_data(client, reg & 0xff, value);
+END:
+ return res;
+}
+
+static int __init sensors_w83793_init(void)
+{
+ return i2c_add_driver(&w83793_driver);
+}
+
+static void __exit sensors_w83793_exit(void)
+{
+ i2c_del_driver(&w83793_driver);
+}
+
+MODULE_AUTHOR("Yuan Mu");
+MODULE_DESCRIPTION("w83793 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83793_init);
+module_exit(sensors_w83793_exit);
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index c034820615b..af0203409dd 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -38,17 +38,6 @@ config I2C_ALGOPCA
This support is also available as a module. If so, the module
will be called i2c-algo-pca.
-config I2C_ALGOITE
- tristate "ITE I2C Algorithm"
- depends on MIPS_ITE8172 && I2C
- help
- This supports the use of the ITE8172 I2C interface found on some MIPS
- systems. Say Y if you have one of these. You should also say Y for
- the ITE I2C peripheral driver support below.
-
- This support is also available as a module. If so, the module
- will be called i2c-algo-ite.
-
config I2C_ALGO8XX
tristate "MPC8xx CPM I2C interface"
depends on 8xx && I2C
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
index 208be04a3db..cac1051bd4f 100644
--- a/drivers/i2c/algos/Makefile
+++ b/drivers/i2c/algos/Makefile
@@ -5,7 +5,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_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 21c36bfb5e6..95aa5395a5b 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -540,15 +540,7 @@ int i2c_bit_add_bus(struct i2c_adapter *adap)
return i2c_add_adapter(adap);
}
-
-
-int i2c_bit_del_bus(struct i2c_adapter *adap)
-{
- return i2c_del_adapter(adap);
-}
-
EXPORT_SYMBOL(i2c_bit_add_bus);
-EXPORT_SYMBOL(i2c_bit_del_bus);
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c
deleted file mode 100644
index 70d8eefb5ef..00000000000
--- a/drivers/i2c/algos/i2c-algo-ite.c
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- -------------------------------------------------------------------------
- i2c-algo-ite.c i2c driver algorithms for ITE adapters
-
- Hai-Pao Fan, MontaVista Software, Inc.
- hpfan@mvista.com or source@mvista.com
-
- Copyright 2000 MontaVista Software Inc.
-
- ---------------------------------------------------------------------------
- This file was highly leveraged from i2c-algo-pcf.c, which was created
- by Simon G. Vogl and Hans Berglund:
-
-
- Copyright (C) 1995-1997 Simon G. Vogl
- 1998-2000 Hans Berglund
-
- This program is free software; you can redistribute it and/or modify
- 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
- Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
- <mbailey@littlefeet-inc.com> */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-ite.h>
-#include "i2c-algo-ite.h"
-
-#define PM_DSR IT8172_PCI_IO_BASE + IT_PM_DSR
-#define PM_IBSR IT8172_PCI_IO_BASE + IT_PM_DSR + 0x04
-#define GPIO_CCR IT8172_PCI_IO_BASE + IT_GPCCR
-
-#define DEB2(x) if (i2c_debug>=2) x
-#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/
-#define DEF_TIMEOUT 16
-
-
-/* module parameters:
- */
-static int i2c_debug;
-static int iic_test; /* see if the line-setting functions work */
-
-/* --- setting states on the bus with the right timing: --------------- */
-
-#define get_clock(adap) adap->getclock(adap->data)
-#define iic_outw(adap, reg, val) adap->setiic(adap->data, reg, val)
-#define iic_inw(adap, reg) adap->getiic(adap->data, reg)
-
-
-/* --- other auxiliary functions -------------------------------------- */
-
-static void iic_start(struct i2c_algo_iic_data *adap)
-{
- iic_outw(adap,ITE_I2CHCR,ITE_CMD);
-}
-
-static void iic_stop(struct i2c_algo_iic_data *adap)
-{
- iic_outw(adap,ITE_I2CHCR,0);
- iic_outw(adap,ITE_I2CHSR,ITE_I2CHSR_TDI);
-}
-
-static void iic_reset(struct i2c_algo_iic_data *adap)
-{
- iic_outw(adap, PM_IBSR, iic_inw(adap, PM_IBSR) | 0x80);
-}
-
-
-static int wait_for_bb(struct i2c_algo_iic_data *adap)
-{
- int timeout = DEF_TIMEOUT;
- short status;
-
- status = iic_inw(adap, ITE_I2CHSR);
-#ifndef STUB_I2C
- while (timeout-- && (status & ITE_I2CHSR_HB)) {
- udelay(1000); /* How much is this? */
- status = iic_inw(adap, ITE_I2CHSR);
- }
-#endif
- if (timeout<=0) {
- printk(KERN_ERR "Timeout, host is busy\n");
- iic_reset(adap);
- }
- return(timeout<=0);
-}
-
-/* After we issue a transaction on the IIC bus, this function
- * is called. It puts this process to sleep until we get an interrupt from
- * from the controller telling us that the transaction we requested in complete.
- */
-static int wait_for_pin(struct i2c_algo_iic_data *adap, short *status) {
-
- int timeout = DEF_TIMEOUT;
-
- timeout = wait_for_bb(adap);
- if (timeout) {
- DEB2(printk("Timeout waiting for host not busy\n");)
- return -EIO;
- }
- timeout = DEF_TIMEOUT;
-
- *status = iic_inw(adap, ITE_I2CHSR);
-#ifndef STUB_I2C
- while (timeout-- && !(*status & ITE_I2CHSR_TDI)) {
- adap->waitforpin();
- *status = iic_inw(adap, ITE_I2CHSR);
- }
-#endif
- if (timeout <= 0)
- return(-1);
- else
- return(0);
-}
-
-static int wait_for_fe(struct i2c_algo_iic_data *adap, short *status)
-{
- int timeout = DEF_TIMEOUT;
-
- *status = iic_inw(adap, ITE_I2CFSR);
-#ifndef STUB_I2C
- while (timeout-- && (*status & ITE_I2CFSR_FE)) {
- udelay(1000);
- iic_inw(adap, ITE_I2CFSR);
- }
-#endif
- if (timeout <= 0)
- return(-1);
- else
- return(0);
-}
-
-static int iic_init (struct i2c_algo_iic_data *adap)
-{
- short i;
-
- /* Clear bit 7 to set I2C to normal operation mode */
- i=iic_inw(adap, PM_DSR)& 0xff7f;
- iic_outw(adap, PM_DSR, i);
-
- /* set IT_GPCCR port C bit 2&3 as function 2 */
- i = iic_inw(adap, GPIO_CCR) & 0xfc0f;
- iic_outw(adap,GPIO_CCR,i);
-
- /* Clear slave address/sub-address */
- iic_outw(adap,ITE_I2CSAR, 0);
- iic_outw(adap,ITE_I2CSSAR, 0);
-
- /* Set clock counter register */
- iic_outw(adap,ITE_I2CCKCNT, get_clock(adap));
-
- /* Set START/reSTART/STOP time registers */
- iic_outw(adap,ITE_I2CSHDR, 0x0a);
- iic_outw(adap,ITE_I2CRSUR, 0x0a);
- iic_outw(adap,ITE_I2CPSUR, 0x0a);
-
- /* Enable interrupts on completing the current transaction */
- iic_outw(adap,ITE_I2CHCR, ITE_I2CHCR_IE | ITE_I2CHCR_HCE);
-
- /* Clear transfer count */
- iic_outw(adap,ITE_I2CFBCR, 0x0);
-
- DEB2(printk("iic_init: Initialized IIC on ITE 0x%x\n",
- iic_inw(adap, ITE_I2CHSR)));
- return 0;
-}
-
-
-/*
- * Sanity check for the adapter hardware - check the reaction of
- * the bus lines only if it seems to be idle.
- */
-static int test_bus(struct i2c_algo_iic_data *adap, char *name) {
-#if 0
- int scl,sda;
- sda=getsda(adap);
- if (adap->getscl==NULL) {
- printk("test_bus: Warning: Adapter can't read from clock line - skipping test.\n");
- return 0;
- }
- scl=getscl(adap);
- printk("test_bus: Adapter: %s scl: %d sda: %d -- testing...\n",
- name,getscl(adap),getsda(adap));
- if (!scl || !sda ) {
- printk("test_bus: %s seems to be busy.\n",adap->name);
- goto bailout;
- }
- sdalo(adap);
- printk("test_bus:1 scl: %d sda: %d\n", getscl(adap),
- getsda(adap));
- if ( 0 != getsda(adap) ) {
- printk("test_bus: %s SDA stuck high!\n",name);
- sdahi(adap);
- goto bailout;
- }
- if ( 0 == getscl(adap) ) {
- printk("test_bus: %s SCL unexpected low while pulling SDA low!\n",
- name);
- goto bailout;
- }
- sdahi(adap);
- printk("test_bus:2 scl: %d sda: %d\n", getscl(adap),
- getsda(adap));
- if ( 0 == getsda(adap) ) {
- printk("test_bus: %s SDA stuck low!\n",name);
- sdahi(adap);
- goto bailout;
- }
- if ( 0 == getscl(adap) ) {
- printk("test_bus: %s SCL unexpected low while SDA high!\n",
- adap->name);
- goto bailout;
- }
- scllo(adap);
- printk("test_bus:3 scl: %d sda: %d\n", getscl(adap),
- getsda(adap));
- if ( 0 != getscl(adap) ) {
-
- sclhi(adap);
- goto bailout;
- }
- if ( 0 == getsda(adap) ) {
- printk("test_bus: %s SDA unexpected low while pulling SCL low!\n",
- name);
- goto bailout;
- }
- sclhi(adap);
- printk("test_bus:4 scl: %d sda: %d\n", getscl(adap),
- getsda(adap));
- if ( 0 == getscl(adap) ) {
- printk("test_bus: %s SCL stuck low!\n",name);
- sclhi(adap);
- goto bailout;
- }
- if ( 0 == getsda(adap) ) {
- printk("test_bus: %s SDA unexpected low while SCL high!\n",
- name);
- goto bailout;
- }
- printk("test_bus: %s passed test.\n",name);
- return 0;
-bailout:
- sdahi(adap);
- sclhi(adap);
- return -ENODEV;
-#endif
- return (0);
-}
-
-/* ----- Utility functions
- */
-
-
-/* Verify the device we want to talk to on the IIC bus really exists. */
-static inline int try_address(struct i2c_algo_iic_data *adap,
- unsigned int addr, int retries)
-{
- int i, ret = -1;
- short status;
-
- for (i=0;i<retries;i++) {
- iic_outw(adap, ITE_I2CSAR, addr);
- iic_start(adap);
- if (wait_for_pin(adap, &status) == 0) {
- if ((status & ITE_I2CHSR_DNE) == 0) {
- iic_stop(adap);
- iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH);
- ret=1;
- break; /* success! */
- }
- }
- iic_stop(adap);
- udelay(adap->udelay);
- }
- DEB2(if (i) printk("try_address: needed %d retries for 0x%x\n",i,
- addr));
- return ret;
-}
-
-
-static int iic_sendbytes(struct i2c_adapter *i2c_adap,const char *buf,
- int count)
-{
- struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
- int wrcount=0, timeout;
- short status;
- int loops, remainder, i, j;
- union {
- char byte[2];
- unsigned short word;
- } tmp;
-
- iic_outw(adap, ITE_I2CSSAR, (unsigned short)buf[wrcount++]);
- count--;
- if (count == 0)
- return -EIO;
-
- loops = count / 32; /* 32-byte FIFO */
- remainder = count % 32;
-
- if(loops) {
- for(i=0; i<loops; i++) {
-
- iic_outw(adap, ITE_I2CFBCR, 32);
- for(j=0; j<32/2; j++) {
- tmp.byte[1] = buf[wrcount++];
- tmp.byte[0] = buf[wrcount++];
- iic_outw(adap, ITE_I2CFDR, tmp.word);
- }
-
- /* status FIFO overrun */
- iic_inw(adap, ITE_I2CFSR);
- iic_inw(adap, ITE_I2CFBCR);
-
- iic_outw(adap, ITE_I2CHCR, ITE_WRITE); /* Issue WRITE command */
-
- /* Wait for transmission to complete */
- timeout = wait_for_pin(adap, &status);
- if(timeout) {
- iic_stop(adap);
- printk("iic_sendbytes: %s write timeout.\n", i2c_adap->name);
- return -EREMOTEIO; /* got a better one ?? */
- }
- if (status & ITE_I2CHSR_DB) {
- iic_stop(adap);
- printk("iic_sendbytes: %s write error - no ack.\n", i2c_adap->name);
- return -EREMOTEIO; /* got a better one ?? */
- }
- }
- }
- if(remainder) {
- iic_outw(adap, ITE_I2CFBCR, remainder);
- for(i=0; i<remainder/2; i++) {
- tmp.byte[1] = buf[wrcount++];
- tmp.byte[0] = buf[wrcount++];
- iic_outw(adap, ITE_I2CFDR, tmp.word);
- }
-
- /* status FIFO overrun */
- iic_inw(adap, ITE_I2CFSR);
- iic_inw(adap, ITE_I2CFBCR);
-
- iic_outw(adap, ITE_I2CHCR, ITE_WRITE); /* Issue WRITE command */
-
- timeout = wait_for_pin(adap, &status);
- if(timeout) {
- iic_stop(adap);
- printk("iic_sendbytes: %s write timeout.\n", i2c_adap->name);
- return -EREMOTEIO; /* got a better one ?? */
- }
-#ifndef STUB_I2C
- if (status & ITE_I2CHSR_DB) {
- iic_stop(adap);
- printk("iic_sendbytes: %s write error - no ack.\n", i2c_adap->name);
- return -EREMOTEIO; /* got a better one ?? */
- }
-#endif
- }
- iic_stop(adap);
- return wrcount;
-}
-
-
-static int iic_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count,
- int sread)
-{
- int rdcount=0, i, timeout;
- short status;
- struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
- int loops, remainder, j;
- union {
- char byte[2];
- unsigned short word;
- } tmp;
-
- loops = count / 32; /* 32-byte FIFO */
- remainder = count % 32;
-
- if(loops) {
- for(i=0; i<loops; i++) {
- iic_outw(adap, ITE_I2CFBCR, 32);
- if (sread)
- iic_outw(adap, ITE_I2CHCR, ITE_SREAD);
- else
- iic_outw(adap, ITE_I2CHCR, ITE_READ); /* Issue READ command */
-
- timeout = wait_for_pin(adap, &status);
- if(timeout) {
- iic_stop(adap);
- printk("iic_readbytes: %s read timeout.\n", i2c_adap->name);
- return (-1);
- }
-#ifndef STUB_I2C
- if (status & ITE_I2CHSR_DB) {
- iic_stop(adap);
- printk("iic_readbytes: %s read error - no ack.\n", i2c_adap->name);
- return (-1);
- }
-#endif
-
- timeout = wait_for_fe(adap, &status);
- if(timeout) {
- iic_stop(adap);
- printk("iic_readbytes: %s FIFO is empty\n", i2c_adap->name);
- return (-1);
- }
-
- for(j=0; j<32/2; j++) {
- tmp.word = iic_inw(adap, ITE_I2CFDR);
- buf[rdcount++] = tmp.byte[1];
- buf[rdcount++] = tmp.byte[0];
- }
-
- /* status FIFO underrun */
- iic_inw(adap, ITE_I2CFSR);
-
- }
- }
-
-
- if(remainder) {
- remainder=(remainder+1)/2 * 2;
- iic_outw(adap, ITE_I2CFBCR, remainder);
- if (sread)
- iic_outw(adap, ITE_I2CHCR, ITE_SREAD);
- else
- iic_outw(adap, ITE_I2CHCR, ITE_READ); /* Issue READ command */
-
- timeout = wait_for_pin(adap, &status);
- if(timeout) {
- iic_stop(adap);
- printk("iic_readbytes: %s read timeout.\n", i2c_adap->name);
- return (-1);
- }
-#ifndef STUB_I2C
- if (status & ITE_I2CHSR_DB) {
- iic_stop(adap);
- printk("iic_readbytes: %s read error - no ack.\n", i2c_adap->name);
- return (-1);
- }
-#endif
- timeout = wait_for_fe(adap, &status);
- if(timeout) {
- iic_stop(adap);
- printk("iic_readbytes: %s FIFO is empty\n", i2c_adap->name);
- return (-1);
- }
-
- for(i=0; i<(remainder+1)/2; i++) {
- tmp.word = iic_inw(adap, ITE_I2CFDR);
- buf[rdcount++] = tmp.byte[1];
- buf[rdcount++] = tmp.byte[0];
- }
-
- /* status FIFO underrun */
- iic_inw(adap, ITE_I2CFSR);
-
- }
-
- iic_stop(adap);
- return rdcount;
-}
-
-
-/* This function implements combined transactions. Combined
- * transactions consist of combinations of reading and writing blocks of data.
- * Each transfer (i.e. a read or a write) is separated by a repeated start
- * condition.
- */
-#if 0
-static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
-{
- int i;
- struct i2c_msg *pmsg;
- int ret;
-
- DEB2(printk("Beginning combined transaction\n"));
-
- for(i=0; i<(num-1); i++) {
- pmsg = &msgs[i];
- if(pmsg->flags & I2C_M_RD) {
- DEB2(printk(" This one is a read\n"));
- ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_COMBINED_XFER);
- }
- else if(!(pmsg->flags & I2C_M_RD)) {
- DEB2(printk("This one is a write\n"));
- ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_COMBINED_XFER);
- }
- }
- /* Last read or write segment needs to be terminated with a stop */
- pmsg = &msgs[i];
-
- if(pmsg->flags & I2C_M_RD) {
- DEB2(printk("Doing the last read\n"));
- ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
- }
- else if(!(pmsg->flags & I2C_M_RD)) {
- DEB2(printk("Doing the last write\n"));
- ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
- }
-
- return ret;
-}
-#endif
-
-
-/* Whenever we initiate a transaction, the first byte clocked
- * onto the bus after the start condition is the address (7 bit) of the
- * device we want to talk to. This function manipulates the address specified
- * so that it makes sense to the hardware when written to the IIC peripheral.
- *
- * Note: 10 bit addresses are not supported in this driver, although they are
- * supported by the hardware. This functionality needs to be implemented.
- */
-static inline int iic_doAddress(struct i2c_algo_iic_data *adap,
- struct i2c_msg *msg, int retries)
-{
- unsigned short flags = msg->flags;
- unsigned int addr;
- int ret;
-
-/* Ten bit addresses not supported right now */
- if ( (flags & I2C_M_TEN) ) {
-#if 0
- addr = 0xf0 | (( msg->addr >> 7) & 0x03);
- DEB2(printk("addr0: %d\n",addr));
- ret = try_address(adap, addr, retries);
- if (ret!=1) {
- printk("iic_doAddress: died at extended address code.\n");
- return -EREMOTEIO;
- }
- iic_outw(adap,msg->addr & 0x7f);
- if (ret != 1) {
- printk("iic_doAddress: died at 2nd address code.\n");
- return -EREMOTEIO;
- }
- if ( flags & I2C_M_RD ) {
- i2c_repstart(adap);
- addr |= 0x01;
- ret = try_address(adap, addr, retries);
- if (ret!=1) {
- printk("iic_doAddress: died at extended address code.\n");
- return -EREMOTEIO;
- }
- }
-#endif
- } else {
-
- addr = ( msg->addr << 1 );
-
-#if 0
- if (flags & I2C_M_RD )
- addr |= 1;
- if (flags & I2C_M_REV_DIR_ADDR )
- addr ^= 1;
-#endif
-
- if (iic_inw(adap, ITE_I2CSAR) != addr) {
- iic_outw(adap, ITE_I2CSAR, addr);
- ret = try_address(adap, addr, retries);
- if (ret!=1) {
- printk("iic_doAddress: died at address code.\n");
- return -EREMOTEIO;
- }
- }
-
- }
-
- return 0;
-}
-
-
-/* Description: Prepares the controller for a transaction (clearing status
- * registers, data buffers, etc), and then calls either iic_readbytes or
- * iic_sendbytes to do the actual transaction.
- *
- * still to be done: Before we issue a transaction, we should
- * verify that the bus is not busy or in some unknown state.
- */
-static int iic_xfer(struct i2c_adapter *i2c_adap,
- struct i2c_msg *msgs,
- int num)
-{
- struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
- struct i2c_msg *pmsg;
- int i = 0;
- int ret, timeout;
-
- pmsg = &msgs[i];
-
- if(!pmsg->len) {
- DEB2(printk("iic_xfer: read/write length is 0\n");)
- return -EIO;
- }
- if(!(pmsg->flags & I2C_M_RD) && (!(pmsg->len)%2) ) {
- DEB2(printk("iic_xfer: write buffer length is not odd\n");)
- return -EIO;
- }
-
- /* Wait for any pending transfers to complete */
- timeout = wait_for_bb(adap);
- if (timeout) {
- DEB2(printk("iic_xfer: Timeout waiting for host not busy\n");)
- return -EIO;
- }
-
- /* Flush FIFO */
- iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH);
-
- /* Load address */
- ret = iic_doAddress(adap, pmsg, i2c_adap->retries);
- if (ret)
- return -EIO;
-
-#if 0
- /* Combined transaction (read and write) */
- if(num > 1) {
- DEB2(printk("iic_xfer: Call combined transaction\n"));
- ret = iic_combined_transaction(i2c_adap, msgs, num);
- }
-#endif
-
- DEB3(printk("iic_xfer: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
- i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
-
- if(pmsg->flags & I2C_M_RD) /* Read */
- ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, 0);
- else { /* Write */
- udelay(1000);
- ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len);
- }
-
- if (ret != pmsg->len)
- DEB3(printk("iic_xfer: error or fail on read/write %d bytes.\n",ret));
- else
- DEB3(printk("iic_xfer: read/write %d bytes.\n",ret));
-
- return ret;
-}
-
-
-/* Implements device specific ioctls. Higher level ioctls can
- * be found in i2c-core.c and are typical of any i2c controller (specifying
- * slave address, timeouts, etc). These ioctls take advantage of any hardware
- * features built into the controller for which this algorithm-adapter set
- * was written. These ioctls allow you to take control of the data and clock
- * lines and set the either high or low,
- * similar to a GPIO pin.
- */
-static int algo_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
-
- struct i2c_algo_iic_data *adap = adapter->algo_data;
- struct i2c_iic_msg s_msg;
- char *buf;
- int ret;
-
- if (cmd == I2C_SREAD) {
- if(copy_from_user(&s_msg, (struct i2c_iic_msg *)arg,
- sizeof(struct i2c_iic_msg)))
- return -EFAULT;
- buf = kmalloc(s_msg.len, GFP_KERNEL);
- if (buf== NULL)
- return -ENOMEM;
-
- /* Flush FIFO */
- iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH);
-
- /* Load address */
- iic_outw(adap, ITE_I2CSAR,s_msg.addr<<1);
- iic_outw(adap, ITE_I2CSSAR,s_msg.waddr & 0xff);
-
- ret = iic_readbytes(adapter, buf, s_msg.len, 1);
- if (ret>=0) {
- if(copy_to_user( s_msg.buf, buf, s_msg.len) )
- ret = -EFAULT;
- }
- kfree(buf);
- }
- return 0;
-}
-
-
-static u32 iic_func(struct i2c_adapter *adap)
-{
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
- I2C_FUNC_PROTOCOL_MANGLING;
-}
-
-/* -----exported algorithm data: ------------------------------------- */
-
-static struct i2c_algorithm iic_algo = {
- .master_xfer = iic_xfer,
- .algo_control = algo_control, /* ioctl */
- .functionality = iic_func,
-};
-
-
-/*
- * registering functions to load algorithms at runtime
- */
-int i2c_iic_add_bus(struct i2c_adapter *adap)
-{
- struct i2c_algo_iic_data *iic_adap = adap->algo_data;
-
- if (iic_test) {
- int ret = test_bus(iic_adap, adap->name);
- if (ret<0)
- return -ENODEV;
- }
-
- DEB2(printk("i2c-algo-ite: hw routines for %s registered.\n",
- adap->name));
-
- /* register new adapter to i2c module... */
- adap->algo = &iic_algo;
-
- adap->timeout = 100; /* default values, should */
- adap->retries = 3; /* be replaced by defines */
- adap->flags = 0;
-
- iic_init(iic_adap);
- return i2c_add_adapter(adap);
-}
-
-
-int i2c_iic_del_bus(struct i2c_adapter *adap)
-{
- int res;
- if ((res = i2c_del_adapter(adap)) < 0)
- return res;
- DEB2(printk("i2c-algo-ite: adapter unregistered: %s\n",adap->name));
-
- return 0;
-}
-
-
-int __init i2c_algo_iic_init (void)
-{
- printk(KERN_INFO "ITE iic (i2c) algorithm module\n");
- return 0;
-}
-
-
-void i2c_algo_iic_exit(void)
-{
- return;
-}
-
-
-EXPORT_SYMBOL(i2c_iic_add_bus);
-EXPORT_SYMBOL(i2c_iic_del_bus);
-
-/* The MODULE_* macros resolve to nothing if MODULES is not defined
- * when this file is compiled.
- */
-MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
-MODULE_DESCRIPTION("ITE iic algorithm");
-MODULE_LICENSE("GPL");
-
-module_param(iic_test, bool, 0);
-module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
-
-MODULE_PARM_DESC(iic_test, "Test if the I2C bus is available");
-MODULE_PARM_DESC(i2c_debug,
- "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol");
-
-
-/* This function resolves to init_module (the function invoked when a module
- * is loaded via insmod) when this file is compiled with MODULES defined.
- * Otherwise (i.e. if you want this driver statically linked to the kernel),
- * a pointer to this function is stored in a table and called
- * during the initialization of the kernel (in do_basic_setup in /init/main.c)
- *
- * All this functionality is complements of the macros defined in linux/init.h
- */
-module_init(i2c_algo_iic_init);
-
-
-/* If MODULES is defined when this file is compiled, then this function will
- * resolved to cleanup_module.
- */
-module_exit(i2c_algo_iic_exit);
diff --git a/drivers/i2c/algos/i2c-algo-ite.h b/drivers/i2c/algos/i2c-algo-ite.h
deleted file mode 100644
index a8ca3c9b546..00000000000
--- a/drivers/i2c/algos/i2c-algo-ite.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- --------------------------------------------------------------------
- i2c-ite.h: Global defines for the I2C controller on board the
- ITE MIPS processor.
- --------------------------------------------------------------------
- Hai-Pao Fan, MontaVista Software, Inc.
- hpfan@mvista.com or source@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 I2C_ITE_H
-#define I2C_ITE_H 1
-
-#include <asm/it8172/it8172.h>
-
-/* I2C Registers */
-#define ITE_I2CHCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x30
-#define ITE_I2CHSR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x34
-#define ITE_I2CSAR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x38
-#define ITE_I2CSSAR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x3c
-#define ITE_I2CCKCNT IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x48
-#define ITE_I2CSHDR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x4c
-#define ITE_I2CRSUR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x50
-#define ITE_I2CPSUR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x54
-
-#define ITE_I2CFDR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x70
-#define ITE_I2CFBCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x74
-#define ITE_I2CFCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x78
-#define ITE_I2CFSR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x7c
-
-
-/* Host Control Register ITE_I2CHCR */
-#define ITE_I2CHCR_HCE 0x01 /* Enable I2C Host Controller */
-#define ITE_I2CHCR_IE 0x02 /* Enable the interrupt after completing
- the current transaction */
-#define ITE_I2CHCR_CP_W 0x00 /* bit2-4 000 - Write */
-#define ITE_I2CHCR_CP_R 0x08 /* 010 - Current address read */
-#define ITE_I2CHCR_CP_S 0x10 /* 100 - Sequential read */
-#define ITE_I2CHCR_ST 0x20 /* Initiates the I2C host controller to execute
- the command and send the data programmed in
- all required registers to I2C bus */
-#define ITE_CMD ITE_I2CHCR_HCE | ITE_I2CHCR_IE | ITE_I2CHCR_ST
-#define ITE_WRITE ITE_CMD | ITE_I2CHCR_CP_W
-#define ITE_READ ITE_CMD | ITE_I2CHCR_CP_R
-#define ITE_SREAD ITE_CMD | ITE_I2CHCR_CP_S
-
-/* Host Status Register ITE_I2CHSR */
-#define ITE_I2CHSR_DB 0x01 /* Device is busy, receives NACK response except
- in the first and last bytes */
-#define ITE_I2CHSR_DNE 0x02 /* Target address on I2C bus does not exist */
-#define ITE_I2CHSR_TDI 0x04 /* R/W Transaction on I2C bus was completed */
-#define ITE_I2CHSR_HB 0x08 /* Host controller is processing transactions */
-#define ITE_I2CHSR_FER 0x10 /* Error occurs in the FIFO */
-
-/* Slave Address Register ITE_I2CSAR */
-#define ITE_I2CSAR_SA_MASK 0xfe /* Target I2C device address */
-#define ITE_I2CSAR_ASO 0x0100 /* Output 1/0 to I2CAS port when the
- next slave address is addressed */
-
-/* Slave Sub-address Register ITE_I2CSSAR */
-#define ITE_I2CSSAR_SUBA_MASK 0xff /* Target I2C device sub-address */
-
-/* Clock Counter Register ITE_I2CCKCNT */
-#define ITE_I2CCKCNT_STOP 0x00 /* stop I2C clock */
-#define ITE_I2CCKCNT_HPCC_MASK 0x7f /* SCL high period counter */
-#define ITE_I2CCKCNT_LPCC_MASK 0x7f00 /* SCL low period counter */
-
-/* START Hold Time Register ITE_I2CSHDR */
-/* value is counted based on 16 MHz internal clock */
-#define ITE_I2CSHDR_FM 0x0a /* START condition at fast mode */
-#define ITE_I2CSHDR_SM 0x47 /* START contition at standard mode */
-
-/* (Repeated) START Setup Time Register ITE_I2CRSUR */
-/* value is counted based on 16 MHz internal clock */
-#define ITE_I2CRSUR_FM 0x0a /* repeated START condition at fast mode */
-#define ITE_I2CRSUR_SM 0x50 /* repeated START condition at standard mode */
-
-/* STOP setup Time Register ITE_I2CPSUR */
-
-/* FIFO Data Register ITE_I2CFDR */
-#define ITE_I2CFDR_MASK 0xff
-
-/* FIFO Byte Count Register ITE_I2CFBCR */
-#define ITE_I2CFBCR_MASK 0x3f
-
-/* FIFO Control Register ITE_I2CFCR */
-#define ITE_I2CFCR_FLUSH 0x01 /* Flush FIFO and reset the FIFO point
- and I2CFSR */
-/* FIFO Status Register ITE_I2CFSR */
-#define ITE_I2CFSR_FO 0x01 /* FIFO is overrun when write */
-#define ITE_I2CFSR_FU 0x02 /* FIFO is underrun when read */
-#define ITE_I2CFSR_FF 0x04 /* FIFO is full when write */
-#define ITE_I2CFSR_FE 0x08 /* FIFO is empty when read */
-
-#endif /* I2C_ITE_H */
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index 9081c9fbcd2..36fdf971f08 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -381,14 +381,7 @@ int i2c_pca_add_bus(struct i2c_adapter *adap)
return rval;
}
-
-int i2c_pca_del_bus(struct i2c_adapter *adap)
-{
- return i2c_del_adapter(adap);
-}
-
EXPORT_SYMBOL(i2c_pca_add_bus);
-EXPORT_SYMBOL(i2c_pca_del_bus);
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm");
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 3b200339896..ecb2c2d7d54 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -486,15 +486,7 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap)
return rval;
}
-
-
-int i2c_pcf_del_bus(struct i2c_adapter *adap)
-{
- return i2c_del_adapter(adap);
-}
-
EXPORT_SYMBOL(i2c_pcf_add_bus);
-EXPORT_SYMBOL(i2c_pcf_del_bus);
MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c
index 490d99997fd..ac2d5053078 100644
--- a/drivers/i2c/algos/i2c-algo-sgi.c
+++ b/drivers/i2c/algos/i2c-algo-sgi.c
@@ -171,15 +171,7 @@ int i2c_sgi_add_bus(struct i2c_adapter *adap)
return i2c_add_adapter(adap);
}
-
-
-int i2c_sgi_del_bus(struct i2c_adapter *adap)
-{
- return i2c_del_adapter(adap);
-}
-
EXPORT_SYMBOL(i2c_sgi_add_bus);
-EXPORT_SYMBOL(i2c_sgi_del_bus);
MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");
MODULE_DESCRIPTION("I2C-Bus SGI algorithm");
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 90f91d039ee..9367c4cfe93 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -74,6 +74,13 @@ config I2C_AMD8111
This driver can also be built as a module. If so, the module
will be called i2c-amd8111.
+config I2C_AT91
+ tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+ depends on I2C && ARCH_AT91 && EXPERIMENTAL
+ help
+ This supports the use of the I2C interface on Atmel AT91
+ processors.
+
config I2C_AU1550
tristate "Au1550/Au1200 SMBus interface"
depends on I2C && (SOC_AU1550 || SOC_AU1200)
@@ -209,18 +216,6 @@ config I2C_ISA
tristate
depends on I2C
-config I2C_ITE
- tristate "ITE I2C Adapter"
- depends on I2C && MIPS_ITE8172
- select I2C_ALGOITE
- help
- This supports the ITE8172 I2C peripheral found on some MIPS
- systems. Say Y if you have one of these. You should also say Y for
- the ITE I2C driver algorithm support above.
-
- This support is also available as a module. If so, the module
- will be called i2c-ite.
-
config I2C_IXP4XX
tristate "IXP4xx GPIO-Based I2C Interface"
depends on I2C && ARCH_IXP4XX
@@ -481,6 +476,17 @@ config I2C_STUB
If you don't know what to do here, definitely say N.
+config I2C_VERSATILE
+ tristate "ARM Versatile/Realview I2C bus support"
+ depends on I2C && (ARCH_VERSATILE || ARCH_REALVIEW)
+ select I2C_ALGOBIT
+ help
+ Say yes if you want to support the I2C serial bus on ARMs Versatile
+ range of platforms.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-versatile.
+
config I2C_VIA
tristate "VIA 82C586B"
depends on I2C && PCI && EXPERIMENTAL
@@ -548,4 +554,14 @@ config I2C_MV64XXX
This driver can also be built as a module. If so, the module
will be called i2c-mv64xxx.
+config I2C_PNX
+ tristate "I2C bus support for Philips PNX targets"
+ depends on ARCH_PNX4008 && I2C
+ help
+ This driver supports the Philips IP3204 I2C IP block master and/or
+ slave controller
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pnx.
+
endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 493c87289b6..37196c1d079 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
+obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
@@ -16,7 +17,6 @@ obj-$(CONFIG_I2C_I810) += i2c-i810.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_ISA) += i2c-isa.o
-obj-$(CONFIG_I2C_ITE) += i2c-ite.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o
obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
@@ -29,6 +29,7 @@ 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
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
+obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
@@ -39,6 +40,7 @@ obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
+obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index 33fbb47100a..8e1e3f8e40a 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -2,7 +2,7 @@
* i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge
*
* Copyright (C) 2004 Patrick Mochel
- * 2005 Rudolf Marek <r.marek@sh.cvut.cz>
+ * 2005 Rudolf Marek <r.marek@assembler.cz>
*
* The 1563 southbridge is deceptively similar to the 1533, with a
* few notable exceptions. One of those happens to be the fact they
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
new file mode 100644
index 00000000000..67f91bdda08
--- /dev/null
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -0,0 +1,325 @@
+/*
+ i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+
+ Copyright (C) 2004 Rick Bronson
+ Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
+
+ Borrowed heavily from original work by:
+ Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.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 <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/at91_twi.h>
+#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+
+#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */
+
+
+static struct clk *twi_clk;
+static void __iomem *twi_base;
+
+#define at91_twi_read(reg) __raw_readl(twi_base + (reg))
+#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg))
+
+
+/*
+ * Initialize the TWI hardware registers.
+ */
+static void __devinit at91_twi_hwinit(void)
+{
+ unsigned long cdiv, ckdiv;
+
+ at91_twi_write(AT91_TWI_IDR, 0xffffffff); /* Disable all interrupts */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); /* Reset peripheral */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */
+
+ /* Calcuate clock dividers */
+ cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
+ cdiv = cdiv + 1; /* round up */
+ ckdiv = 0;
+ while (cdiv > 255) {
+ ckdiv++;
+ cdiv = cdiv >> 1;
+ }
+
+ if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */
+ if (ckdiv > 5) {
+ printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
+ ckdiv = 5;
+ }
+ }
+
+ at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
+}
+
+/*
+ * Poll the i2c status register until the specified bit is set.
+ * Returns 0 if timed out (100 msec).
+ */
+static short at91_poll_status(unsigned long bit)
+{
+ int loop_cntr = 10000;
+
+ do {
+ udelay(10);
+ } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
+
+ return (loop_cntr > 0);
+}
+
+static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ /* Send Start */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+
+ /* Read data */
+ while (length--) {
+ if (!length) /* need to send Stop before reading last byte */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+ if (!at91_poll_status(AT91_TWI_RXRDY)) {
+ dev_dbg(&adap->dev, "RXRDY timeout\n");
+ return -ETIMEDOUT;
+ }
+ *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff);
+ }
+
+ return 0;
+}
+
+static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ /* Load first byte into transmitter */
+ at91_twi_write(AT91_TWI_THR, *buf++);
+
+ /* Send Start */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+
+ do {
+ if (!at91_poll_status(AT91_TWI_TXRDY)) {
+ dev_dbg(&adap->dev, "TXRDY timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ length--; /* byte was transmitted */
+
+ if (length > 0) /* more data to send? */
+ at91_twi_write(AT91_TWI_THR, *buf++);
+ } while (length);
+
+ /* Send Stop */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+
+ return 0;
+}
+
+/*
+ * Generic i2c master transfer entrypoint.
+ *
+ * Note: We do not use Atmel's feature of storing the "internal device address".
+ * Instead the "internal device address" has to be written using a seperate
+ * i2c message.
+ * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
+ */
+static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
+{
+ int i, ret;
+
+ dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
+
+ for (i = 0; i < num; i++) {
+ dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
+ pmsg->flags & I2C_M_RD ? "read" : "writ",
+ pmsg->len, pmsg->len > 1 ? "s" : "",
+ pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
+
+ at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16)
+ | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
+
+ if (pmsg->len && pmsg->buf) { /* sanity check */
+ if (pmsg->flags & I2C_M_RD)
+ ret = xfer_read(adap, pmsg->buf, pmsg->len);
+ else
+ ret = xfer_write(adap, pmsg->buf, pmsg->len);
+
+ if (ret)
+ return ret;
+
+ /* Wait until transfer is finished */
+ if (!at91_poll_status(AT91_TWI_TXCOMP)) {
+ dev_dbg(&adap->dev, "TXCOMP timeout\n");
+ return -ETIMEDOUT;
+ }
+ }
+ dev_dbg(&adap->dev, "transfer complete\n");
+ pmsg++; /* next message */
+ }
+ return i;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 at91_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm at91_algorithm = {
+ .master_xfer = at91_xfer,
+ .functionality = at91_func,
+};
+
+/*
+ * Main initialization routine.
+ */
+static int __devinit at91_i2c_probe(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter;
+ struct resource *res;
+ int rc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ if (!request_mem_region(res->start, res->end - res->start + 1, "at91_i2c"))
+ return -EBUSY;
+
+ twi_base = ioremap(res->start, res->end - res->start + 1);
+ if (!twi_base) {
+ rc = -ENOMEM;
+ goto fail0;
+ }
+
+ twi_clk = clk_get(NULL, "twi_clk");
+ if (IS_ERR(twi_clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ rc = -ENODEV;
+ goto fail1;
+ }
+
+ adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (adapter == NULL) {
+ dev_err(&pdev->dev, "can't allocate inteface!\n");
+ rc = -ENOMEM;
+ goto fail2;
+ }
+ sprintf(adapter->name, "AT91");
+ adapter->algo = &at91_algorithm;
+ adapter->class = I2C_CLASS_HWMON;
+ adapter->dev.parent = &pdev->dev;
+
+ platform_set_drvdata(pdev, adapter);
+
+ clk_enable(twi_clk); /* enable peripheral clock */
+ at91_twi_hwinit(); /* initialize TWI controller */
+
+ rc = i2c_add_adapter(adapter);
+ if (rc) {
+ dev_err(&pdev->dev, "Adapter %s registration failed\n",
+ adapter->name);
+ goto fail3;
+ }
+
+ dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
+ return 0;
+
+fail3:
+ platform_set_drvdata(pdev, NULL);
+ kfree(adapter);
+ clk_disable(twi_clk);
+fail2:
+ clk_put(twi_clk);
+fail1:
+ iounmap(twi_base);
+fail0:
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ return rc;
+}
+
+static int __devexit at91_i2c_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+ struct resource *res;
+ int rc;
+
+ rc = i2c_del_adapter(adapter);
+ platform_set_drvdata(pdev, NULL);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iounmap(twi_base);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ clk_disable(twi_clk); /* disable peripheral clock */
+ clk_put(twi_clk);
+
+ return rc;
+}
+
+#ifdef CONFIG_PM
+
+/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
+
+static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ clk_disable(twi_clk);
+ return 0;
+}
+
+static int at91_i2c_resume(struct platform_device *pdev)
+{
+ return clk_enable(twi_clk);
+}
+
+#else
+#define at91_i2c_suspend NULL
+#define at91_i2c_resume NULL
+#endif
+
+static struct platform_driver at91_i2c_driver = {
+ .probe = at91_i2c_probe,
+ .remove = __devexit_p(at91_i2c_remove),
+ .suspend = at91_i2c_suspend,
+ .resume = at91_i2c_resume,
+ .driver = {
+ .name = "at91_i2c",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at91_i2c_init(void)
+{
+ return platform_driver_register(&at91_i2c_driver);
+}
+
+static void __exit at91_i2c_exit(void)
+{
+ platform_driver_unregister(&at91_i2c_driver);
+}
+
+module_init(at91_i2c_init);
+module_exit(at91_i2c_exit);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index a591fe685f0..83496746481 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -293,7 +293,7 @@ static int __init i2c_pcfisa_init(void)
static void i2c_pcfisa_exit(void)
{
- i2c_pcf_del_bus(&pcf_isa_ops);
+ i2c_del_adapter(&pcf_isa_ops);
if (irq > 0) {
disable_irq(irq);
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
index 457d48a0ab9..9832f773651 100644
--- a/drivers/i2c/busses/i2c-hydra.c
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -146,7 +146,7 @@ static int __devinit hydra_probe(struct pci_dev *dev,
static void __devexit hydra_remove(struct pci_dev *dev)
{
pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */
- i2c_bit_del_bus(&hydra_adap);
+ i2c_del_adapter(&hydra_adap);
iounmap(hydra_bit_data.data);
release_mem_region(pci_resource_start(dev, 0)+
offsetof(struct Hydra, CachePD), 4);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index c7be2fdbd86..ae625b85447 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -470,12 +470,20 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
int err;
I801_dev = dev;
- if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) ||
- (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) ||
- (dev->device == PCI_DEVICE_ID_INTEL_ESB_4))
+ switch (dev->device) {
+ case PCI_DEVICE_ID_INTEL_82801DB_3:
+ case PCI_DEVICE_ID_INTEL_82801EB_3:
+ case PCI_DEVICE_ID_INTEL_ESB_4:
+ case PCI_DEVICE_ID_INTEL_ICH6_16:
+ case PCI_DEVICE_ID_INTEL_ICH7_17:
+ case PCI_DEVICE_ID_INTEL_ESB2_17:
+ case PCI_DEVICE_ID_INTEL_ICH8_5:
+ case PCI_DEVICE_ID_INTEL_ICH9_6:
isich4 = 1;
- else
+ break;
+ default:
isich4 = 0;
+ }
err = pci_enable_device(dev);
if (err) {
diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c
index b66fb6bb187..10c98bc88aa 100644
--- a/drivers/i2c/busses/i2c-i810.c
+++ b/drivers/i2c/busses/i2c-i810.c
@@ -219,14 +219,14 @@ static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id
return retval;
retval = i2c_bit_add_bus(&i810_ddc_adapter);
if (retval)
- i2c_bit_del_bus(&i810_i2c_adapter);
+ i2c_del_adapter(&i810_i2c_adapter);
return retval;
}
static void __devexit i810_remove(struct pci_dev *dev)
{
- i2c_bit_del_bus(&i810_ddc_adapter);
- i2c_bit_del_bus(&i810_i2c_adapter);
+ i2c_del_adapter(&i810_ddc_adapter);
+ i2c_del_adapter(&i810_i2c_adapter);
iounmap(ioaddr);
}
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 781a99c1647..1898e998702 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -680,6 +680,12 @@ static int __devinit iic_probe(struct ocp_device *ocp){
dev->idx = ocp->def->index;
ocp_set_drvdata(ocp, dev);
+ if (!request_mem_region(ocp->def->paddr, sizeof(struct iic_regs),
+ "ibm_iic")) {
+ ret = -EBUSY;
+ goto fail1;
+ }
+
if (!(dev->vaddr = ioremap(ocp->def->paddr, sizeof(struct iic_regs)))){
printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n",
dev->idx);
@@ -750,6 +756,8 @@ fail:
iounmap(dev->vaddr);
fail2:
+ release_mem_region(ocp->def->paddr, sizeof(struct iic_regs));
+fail1:
ocp_set_drvdata(ocp, NULL);
kfree(dev);
return ret;
@@ -777,6 +785,7 @@ static void __devexit iic_remove(struct ocp_device *ocp)
free_irq(dev->irq, dev);
}
iounmap(dev->vaddr);
+ release_mem_region(ocp->def->paddr, sizeof(struct iic_regs));
kfree(dev);
}
}
diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c
deleted file mode 100644
index f7d71869b3b..00000000000
--- a/drivers/i2c/busses/i2c-ite.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- -------------------------------------------------------------------------
- i2c-adap-ite.c i2c-hw access for the IIC peripheral on the ITE MIPS system
- -------------------------------------------------------------------------
- Hai-Pao Fan, MontaVista Software, Inc.
- hpfan@mvista.com or source@mvista.com
-
- Copyright 2001 MontaVista Software Inc.
-
- ----------------------------------------------------------------------------
- This file was highly leveraged from i2c-elektor.c, which was created
- by Simon G. Vogl and Hans Berglund:
-
-
- Copyright (C) 1995-97 Simon G. Vogl
- 1998-99 Hans Berglund
-
- This program is free software; you can redistribute it and/or modify
- 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> */
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-ite.h>
-#include <linux/i2c-adap-ite.h>
-#include "../i2c-ite.h"
-
-#define DEFAULT_BASE 0x14014030
-#define ITE_IIC_IO_SIZE 0x40
-#define DEFAULT_IRQ 0
-#define DEFAULT_CLOCK 0x1b0e /* default 16MHz/(27+14) = 400KHz */
-#define DEFAULT_OWN 0x55
-
-static int base;
-static int irq;
-static int clock;
-static int own;
-
-static struct iic_ite gpi;
-static wait_queue_head_t iic_wait;
-static int iic_pending;
-static spinlock_t lock;
-
-/* ----- local functions ---------------------------------------------- */
-
-static void iic_ite_setiic(void *data, int ctl, short val)
-{
- unsigned long j = jiffies + 10;
-
- pr_debug(" Write 0x%02x to 0x%x\n",(unsigned short)val, ctl&0xff);
-#ifdef DEBUG
- while (time_before(jiffies, j))
- schedule();
-#endif
- outw(val,ctl);
-}
-
-static short iic_ite_getiic(void *data, int ctl)
-{
- short val;
-
- val = inw(ctl);
- pr_debug("Read 0x%02x from 0x%x\n",(unsigned short)val, ctl&0xff);
- return (val);
-}
-
-/* Return our slave address. This is the address
- * put on the I2C bus when another master on the bus wants to address us
- * as a slave
- */
-static int iic_ite_getown(void *data)
-{
- return (gpi.iic_own);
-}
-
-
-static int iic_ite_getclock(void *data)
-{
- return (gpi.iic_clock);
-}
-
-
-/* Put this process to sleep. We will wake up when the
- * IIC controller interrupts.
- */
-static void iic_ite_waitforpin(void) {
- DEFINE_WAIT(wait);
- int timeout = 2;
- 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
- * the IIC peripheral interrupts or the timeout expires.
- * If interrupts are not enabled then delay for a reasonable amount
- * of time and return.
- */
- if (gpi.iic_irq > 0) {
- spin_lock_irqsave(&lock, flags);
- if (iic_pending == 0) {
- spin_unlock_irqrestore(&lock, flags);
- prepare_to_wait(&iic_wait, &wait, TASK_INTERRUPTIBLE);
- if (schedule_timeout(timeout*HZ)) {
- spin_lock_irqsave(&lock, flags);
- if (iic_pending == 1) {
- iic_pending = 0;
- }
- spin_unlock_irqrestore(&lock, flags);
- }
- finish_wait(&iic_wait, &wait);
- } else {
- iic_pending = 0;
- spin_unlock_irqrestore(&lock, flags);
- }
- } else {
- udelay(100);
- }
-}
-
-
-static irqreturn_t iic_ite_handler(int this_irq, void *dev_id)
-{
- spin_lock(&lock);
- iic_pending = 1;
- spin_unlock(&lock);
-
- wake_up_interruptible(&iic_wait);
-
- return IRQ_HANDLED;
-}
-
-
-/* Lock the region of memory where I/O registers exist. Request our
- * interrupt line and register its associated handler.
- */
-static int iic_hw_resrc_init(void)
-{
- if (!request_region(gpi.iic_base, ITE_IIC_IO_SIZE, "i2c"))
- return -ENODEV;
-
- if (gpi.iic_irq <= 0)
- return 0;
-
- if (request_irq(gpi.iic_irq, iic_ite_handler, 0, "ITE IIC", 0) < 0)
- gpi.iic_irq = 0;
- else
- enable_irq(gpi.iic_irq);
-
- return 0;
-}
-
-
-static void iic_ite_release(void)
-{
- if (gpi.iic_irq > 0) {
- disable_irq(gpi.iic_irq);
- free_irq(gpi.iic_irq, 0);
- }
- release_region(gpi.iic_base , 2);
-}
-
-/* ------------------------------------------------------------------------
- * Encapsulate the above functions in the correct operations structure.
- * This is only done when more than one hardware adapter is supported.
- */
-static struct i2c_algo_iic_data iic_ite_data = {
- NULL,
- iic_ite_setiic,
- iic_ite_getiic,
- iic_ite_getown,
- iic_ite_getclock,
- iic_ite_waitforpin,
- 80, 80, 100, /* waits, timeout */
-};
-
-static struct i2c_adapter iic_ite_ops = {
- .owner = THIS_MODULE,
- .id = I2C_HW_I_IIC,
- .algo_data = &iic_ite_data,
- .name = "ITE IIC adapter",
-};
-
-/* Called when the module is loaded. This function starts the
- * cascade of calls up through the hierarchy of i2c modules (i.e. up to the
- * algorithm layer and into to the core layer)
- */
-static int __init iic_ite_init(void)
-{
-
- struct iic_ite *piic = &gpi;
-
- printk(KERN_INFO "Initialize ITE IIC adapter module\n");
- if (base == 0)
- piic->iic_base = DEFAULT_BASE;
- else
- piic->iic_base = base;
-
- if (irq == 0)
- piic->iic_irq = DEFAULT_IRQ;
- else
- piic->iic_irq = irq;
-
- if (clock == 0)
- piic->iic_clock = DEFAULT_CLOCK;
- else
- piic->iic_clock = clock;
-
- if (own == 0)
- piic->iic_own = DEFAULT_OWN;
- else
- piic->iic_own = own;
-
- iic_ite_data.data = (void *)piic;
- init_waitqueue_head(&iic_wait);
- spin_lock_init(&lock);
- if (iic_hw_resrc_init() == 0) {
- if (i2c_iic_add_bus(&iic_ite_ops) < 0)
- return -ENODEV;
- } else {
- return -ENODEV;
- }
- printk(KERN_INFO " found device at %#x irq %d.\n",
- piic->iic_base, piic->iic_irq);
- return 0;
-}
-
-
-static void iic_ite_exit(void)
-{
- i2c_iic_del_bus(&iic_ite_ops);
- iic_ite_release();
-}
-
-/* If modules is NOT defined when this file is compiled, then the MODULE_*
- * macros will resolve to nothing
- */
-MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
-MODULE_DESCRIPTION("I2C-Bus adapter routines for ITE IIC bus adapter");
-MODULE_LICENSE("GPL");
-
-module_param(base, int, 0);
-module_param(irq, int, 0);
-module_param(clock, int, 0);
-module_param(own, int, 0);
-
-
-/* Called when module is loaded or when kernel is initialized.
- * If MODULES is defined when this file is compiled, then this function will
- * resolve to init_module (the function called when insmod is invoked for a
- * module). Otherwise, this function is called early in the boot, when the
- * kernel is intialized. Check out /include/init.h to see how this works.
- */
-module_init(iic_ite_init);
-
-/* Resolves to module_cleanup when MODULES is defined. */
-module_exit(iic_ite_exit);
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
index dd3f4cd3aa6..efa3ecc5522 100644
--- a/drivers/i2c/busses/i2c-ixp2000.c
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -90,7 +90,7 @@ static int ixp2000_i2c_remove(struct platform_device *plat_dev)
platform_set_drvdata(plat_dev, NULL);
- i2c_bit_del_bus(&drv_data->adapter);
+ i2c_del_adapter(&drv_data->adapter);
kfree(drv_data);
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
index 68fe863f9d5..08e89b83984 100644
--- a/drivers/i2c/busses/i2c-ixp4xx.c
+++ b/drivers/i2c/busses/i2c-ixp4xx.c
@@ -91,7 +91,7 @@ static int ixp4xx_i2c_remove(struct platform_device *plat_dev)
platform_set_drvdata(plat_dev, NULL);
- i2c_bit_del_bus(&drv_data->adapter);
+ i2c_del_adapter(&drv_data->adapter);
kfree(drv_data);
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index bbc8e3a7ff5..490173611d6 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -529,6 +529,8 @@ mv64xxx_i2c_probe(struct platform_device *pd)
platform_set_drvdata(pd, drv_data);
i2c_set_adapdata(&drv_data->adapter, drv_data);
+ mv64xxx_i2c_hw_init(drv_data);
+
if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
MV64XXX_I2C_CTLR_NAME, drv_data)) {
dev_err(&drv_data->adapter.dev,
@@ -542,8 +544,6 @@ mv64xxx_i2c_probe(struct platform_device *pd)
goto exit_free_irq;
}
- mv64xxx_i2c_hw_init(drv_data);
-
return 0;
exit_free_irq:
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index e0292e414ab..ad37c10e7fe 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -35,7 +35,7 @@
nForce4 MCP55 0368
This driver supports the 2 SMBuses that are included in the MCP of the
- nForce2/3/4 chipsets.
+ nForce2/3/4/5xx chipsets.
*/
/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
@@ -52,8 +52,8 @@
#include <asm/io.h>
MODULE_LICENSE("GPL");
-MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@arcor.de>");
-MODULE_DESCRIPTION("nForce2 SMBus driver");
+MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver");
struct nforce2_smbus {
@@ -80,9 +80,6 @@ struct nforce2_smbus {
#define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */
#define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */
#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */
-#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data bytes */
-#define NVIDIA_SMB_ALRM_A (smbus->base + 0x25) /* alarm address */
-#define NVIDIA_SMB_ALRM_D (smbus->base + 0x26) /* 2 bytes alarm data */
#define NVIDIA_SMB_STS_DONE 0x80
#define NVIDIA_SMB_STS_ALRM 0x40
@@ -95,40 +92,17 @@ struct nforce2_smbus {
#define NVIDIA_SMB_PRTCL_BYTE 0x04
#define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06
#define NVIDIA_SMB_PRTCL_WORD_DATA 0x08
-#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a
-#define NVIDIA_SMB_PRTCL_PROC_CALL 0x0c
-#define NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
-#define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
#define NVIDIA_SMB_PRTCL_PEC 0x80
static struct pci_driver nforce2_driver;
-static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
- unsigned short flags, char read_write,
- u8 command, int size, union i2c_smbus_data *data);
-static u32 nforce2_func(struct i2c_adapter *adapter);
-
-
-static const struct i2c_algorithm smbus_algorithm = {
- .smbus_xfer = nforce2_access,
- .functionality = nforce2_func,
-};
-
-static struct i2c_adapter nforce2_adapter = {
- .owner = THIS_MODULE,
- .class = I2C_CLASS_HWMON,
- .algo = &smbus_algorithm,
-};
-
-/* Return -1 on error. See smbus.h for more information */
+/* Return -1 on error */
static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data * data)
{
struct nforce2_smbus *smbus = adap->algo_data;
unsigned char protocol, pec, temp;
- unsigned char len = 0; /* to keep the compiler quiet */
- int i;
protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
NVIDIA_SMB_PRTCL_WRITE;
@@ -163,35 +137,6 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
break;
- case I2C_SMBUS_BLOCK_DATA:
- outb_p(command, NVIDIA_SMB_CMD);
- if (read_write == I2C_SMBUS_WRITE) {
- len = min_t(u8, data->block[0], 32);
- outb_p(len, NVIDIA_SMB_BCNT);
- for (i = 0; i < len; i++)
- outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
- }
- protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
- break;
-
- case I2C_SMBUS_I2C_BLOCK_DATA:
- len = min_t(u8, data->block[0], 32);
- outb_p(command, NVIDIA_SMB_CMD);
- outb_p(len, NVIDIA_SMB_BCNT);
- if (read_write == I2C_SMBUS_WRITE)
- for (i = 0; i < len; i++)
- outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
- protocol |= NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA;
- break;
-
- case I2C_SMBUS_PROC_CALL:
- dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
- return -1;
-
- case I2C_SMBUS_BLOCK_PROC_CALL:
- dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n");
- return -1;
-
default:
dev_err(&adap->dev, "Unsupported transaction %d\n", size);
return -1;
@@ -227,19 +172,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
break;
case I2C_SMBUS_WORD_DATA:
- /* case I2C_SMBUS_PROC_CALL: not supported */
data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
break;
-
- case I2C_SMBUS_BLOCK_DATA:
- /* case I2C_SMBUS_BLOCK_PROC_CALL: not supported */
- len = inb_p(NVIDIA_SMB_BCNT);
- len = min_t(u8, len, 32);
- case I2C_SMBUS_I2C_BLOCK_DATA:
- for (i = 0; i < len; i++)
- data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
- data->block[0] = len;
- break;
}
return 0;
@@ -250,10 +184,14 @@ static u32 nforce2_func(struct i2c_adapter *adapter)
{
/* other functionality might be possible, but is not tested */
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA /* |
- I2C_FUNC_SMBUS_BLOCK_DATA */;
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
}
+static struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = nforce2_access,
+ .functionality = nforce2_func,
+};
+
static struct pci_device_id nforce2_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
@@ -267,7 +205,6 @@ static struct pci_device_id nforce2_ids[] = {
{ 0 }
};
-
MODULE_DEVICE_TABLE (pci, nforce2_ids);
@@ -291,7 +228,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
}
smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;
- smbus->size = 8;
+ smbus->size = 64;
}
smbus->dev = dev;
@@ -300,7 +237,9 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
smbus->base, smbus->base+smbus->size-1, name);
return -1;
}
- smbus->adapter = nforce2_adapter;
+ smbus->adapter.owner = THIS_MODULE;
+ smbus->adapter.class = I2C_CLASS_HWMON;
+ smbus->adapter.algo = &smbus_algorithm;
smbus->adapter.algo_data = smbus;
smbus->adapter.dev.parent = &dev->dev;
snprintf(smbus->adapter.name, I2C_NAME_SIZE,
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index dec04da0455..bcd8367cede 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -231,8 +231,8 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
* 13 2 1
* 19.2 2 1
*/
- if (fclk_rate > 16000000)
- psc = (fclk_rate + 8000000) / 12000000;
+ if (fclk_rate > 12000000)
+ psc = fclk_rate / 12000000;
}
/* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index 5eb2bd294fd..4bc42810b9a 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -163,7 +163,7 @@ static void __exit i2c_parport_exit(void)
if (adapter_parm[type].init.val)
line_set(0, &adapter_parm[type].init);
- i2c_bit_del_bus(&parport_adapter);
+ i2c_del_adapter(&parport_adapter);
release_region(base, 3);
}
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index 48a829431c7..66696a40c7b 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -218,7 +218,7 @@ static void i2c_parport_detach (struct parport *port)
if (adapter_parm[type].init.val)
line_set(port, 0, &adapter_parm[type].init);
- i2c_bit_del_bus(&adapter->adapter);
+ i2c_del_adapter(&adapter->adapter);
parport_unregister_device(adapter->pdev);
if (prev)
prev->next = adapter->next;
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index 407840b6a26..cc6536a19ec 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -156,7 +156,7 @@ static int __init pca_isa_init(void)
static void pca_isa_exit(void)
{
- i2c_pca_del_bus(&pca_isa_ops);
+ i2c_del_adapter(&pca_isa_ops);
if (irq > 0) {
disable_irq(irq);
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
new file mode 100644
index 00000000000..17376feb1ac
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -0,0 +1,703 @@
+/*
+ * Provides I2C support for Philips PNX010x/PNX4008 boards.
+ *
+ * Authors: Dennis Kovalev <dkovalev@ru.mvista.com>
+ * Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * 2004-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/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-pnx.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#define I2C_PNX_TIMEOUT 10 /* msec */
+#define I2C_PNX_SPEED_KHZ 100
+#define I2C_PNX_REGION_SIZE 0x100
+#define PNX_DEFAULT_FREQ 13 /* MHz */
+
+static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
+{
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_STS(data)) & mstatus_active)) {
+ mdelay(1);
+ timeout--;
+ }
+ return (timeout <= 0);
+}
+
+static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
+{
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) {
+ mdelay(1);
+ timeout--;
+ }
+ return (timeout <= 0);
+}
+
+static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *data = adap->algo_data;
+ struct timer_list *timer = &data->mif.timer;
+ int expires = I2C_PNX_TIMEOUT / (1000 / HZ);
+
+ del_timer_sync(timer);
+
+ dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n",
+ jiffies, expires);
+
+ timer->expires = jiffies + expires;
+ timer->data = (unsigned long)adap;
+
+ add_timer(timer);
+}
+
+/**
+ * i2c_pnx_start - start a device
+ * @slave_addr: slave address
+ * @adap: pointer to adapter structure
+ *
+ * Generate a START signal in the desired mode.
+ */
+static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+
+ dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __FUNCTION__,
+ slave_addr, alg_data->mif.mode);
+
+ /* Check for 7 bit slave addresses only */
+ if (slave_addr & ~0x7f) {
+ dev_err(&adap->dev, "%s: Invalid slave address %x. "
+ "Only 7-bit addresses are supported\n",
+ adap->name, slave_addr);
+ return -EINVAL;
+ }
+
+ /* First, make sure bus is idle */
+ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) {
+ /* Somebody else is monopolizing the bus */
+ dev_err(&adap->dev, "%s: Bus busy. Slave addr = %02x, "
+ "cntrl = %x, stat = %x\n",
+ adap->name, slave_addr,
+ ioread32(I2C_REG_CTL(alg_data)),
+ ioread32(I2C_REG_STS(alg_data)));
+ return -EBUSY;
+ } else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) {
+ /* Sorry, we lost the bus */
+ dev_err(&adap->dev, "%s: Arbitration failure. "
+ "Slave addr = %02x\n", adap->name, slave_addr);
+ return -EIO;
+ }
+
+ /*
+ * OK, I2C is enabled and we have the bus.
+ * Clear the current TDI and AFI status flags.
+ */
+ iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi,
+ I2C_REG_STS(alg_data));
+
+ dev_dbg(&adap->dev, "%s(): sending %#x\n", __FUNCTION__,
+ (slave_addr << 1) | start_bit | alg_data->mif.mode);
+
+ /* Write the slave address, START bit and R/W bit */
+ iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode,
+ I2C_REG_TX(alg_data));
+
+ dev_dbg(&adap->dev, "%s(): exit\n", __FUNCTION__);
+
+ return 0;
+}
+
+/**
+ * i2c_pnx_stop - stop a device
+ * @adap: pointer to I2C adapter structure
+ *
+ * Generate a STOP signal to terminate the master transaction.
+ */
+static void i2c_pnx_stop(struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ /* Only 1 msec max timeout due to interrupt context */
+ long timeout = 1000;
+
+ dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ /* Write a STOP bit to TX FIFO */
+ iowrite32(0xff | stop_bit, I2C_REG_TX(alg_data));
+
+ /* Wait until the STOP is seen. */
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_STS(alg_data)) & mstatus_active)) {
+ /* may be called from interrupt context */
+ udelay(1);
+ timeout--;
+ }
+
+ dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+}
+
+/**
+ * i2c_pnx_master_xmit - transmit data to slave
+ * @adap: pointer to I2C adapter structure
+ *
+ * Sends one byte of data to the slave
+ */
+static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ u32 val;
+
+ dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ if (alg_data->mif.len > 0) {
+ /* We still have something to talk about... */
+ val = *alg_data->mif.buf++;
+
+ if (alg_data->mif.len == 1) {
+ val |= stop_bit;
+ if (!alg_data->last)
+ val |= start_bit;
+ }
+
+ alg_data->mif.len--;
+ iowrite32(val, I2C_REG_TX(alg_data));
+
+ dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __FUNCTION__,
+ val, alg_data->mif.len + 1);
+
+ if (alg_data->mif.len == 0) {
+ if (alg_data->last) {
+ /* Wait until the STOP is seen. */
+ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+ dev_err(&adap->dev, "The bus is still "
+ "active after timeout\n");
+ }
+ /* Disable master interrupts */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
+ ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
+ I2C_REG_CTL(alg_data));
+
+ del_timer_sync(&alg_data->mif.timer);
+
+ dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n",
+ __FUNCTION__);
+
+ complete(&alg_data->mif.complete);
+ }
+ } else if (alg_data->mif.len == 0) {
+ /* zero-sized transfer */
+ i2c_pnx_stop(adap);
+
+ /* Disable master interrupts. */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
+ ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
+ I2C_REG_CTL(alg_data));
+
+ /* Stop timer. */
+ del_timer_sync(&alg_data->mif.timer);
+ dev_dbg(&adap->dev, "%s(): Waking up xfer routine after "
+ "zero-xfer.\n", __FUNCTION__);
+
+ complete(&alg_data->mif.complete);
+ }
+
+ dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ return 0;
+}
+
+/**
+ * i2c_pnx_master_rcv - receive data from slave
+ * @adap: pointer to I2C adapter structure
+ *
+ * Reads one byte data from the slave
+ */
+static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ unsigned int val = 0;
+ u32 ctl = 0;
+
+ dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ /* Check, whether there is already data,
+ * or we didn't 'ask' for it yet.
+ */
+ if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) {
+ dev_dbg(&adap->dev, "%s(): Write dummy data to fill "
+ "Rx-fifo...\n", __FUNCTION__);
+
+ if (alg_data->mif.len == 1) {
+ /* Last byte, do not acknowledge next rcv. */
+ val |= stop_bit;
+ if (!alg_data->last)
+ val |= start_bit;
+
+ /*
+ * Enable interrupt RFDAIE (data in Rx fifo),
+ * and disable DRMIE (need data for Tx)
+ */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl |= mcntrl_rffie | mcntrl_daie;
+ ctl &= ~mcntrl_drmie;
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+ }
+
+ /*
+ * Now we'll 'ask' for data:
+ * For each byte we want to receive, we must
+ * write a (dummy) byte to the Tx-FIFO.
+ */
+ iowrite32(val, I2C_REG_TX(alg_data));
+
+ return 0;
+ }
+
+ /* Handle data. */
+ if (alg_data->mif.len > 0) {
+ val = ioread32(I2C_REG_RX(alg_data));
+ *alg_data->mif.buf++ = (u8) (val & 0xff);
+ dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __FUNCTION__, val,
+ alg_data->mif.len);
+
+ alg_data->mif.len--;
+ if (alg_data->mif.len == 0) {
+ if (alg_data->last)
+ /* Wait until the STOP is seen. */
+ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+ dev_err(&adap->dev, "The bus is still "
+ "active after timeout\n");
+
+ /* Disable master interrupts */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie | mcntrl_daie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Kill timer. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ }
+ }
+
+ dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ return 0;
+}
+
+static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
+{
+ u32 stat, ctl;
+ struct i2c_adapter *adap = dev_id;
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+
+ dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n",
+ __FUNCTION__,
+ ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)),
+ alg_data->mif.mode);
+ stat = ioread32(I2C_REG_STS(alg_data));
+
+ /* let's see what kind of event this is */
+ if (stat & mstatus_afi) {
+ /* We lost arbitration in the midst of a transfer */
+ alg_data->mif.ret = -EIO;
+
+ /* Disable master interrupts. */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Stop timer, to prevent timeout. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ } else if (stat & mstatus_nai) {
+ /* Slave did not acknowledge, generate a STOP */
+ dev_dbg(&adap->dev, "%s(): "
+ "Slave did not acknowledge, generating a STOP.\n",
+ __FUNCTION__);
+ i2c_pnx_stop(adap);
+
+ /* Disable master interrupts. */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Our return value. */
+ alg_data->mif.ret = -EIO;
+
+ /* Stop timer, to prevent timeout. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ } else {
+ /*
+ * Two options:
+ * - Master Tx needs data.
+ * - There is data in the Rx-fifo
+ * The latter is only the case if we have requested for data,
+ * via a dummy write. (See 'i2c_pnx_master_rcv'.)
+ * We therefore check, as a sanity check, whether that interrupt
+ * has been enabled.
+ */
+ if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) {
+ if (alg_data->mif.mode == I2C_SMBUS_WRITE) {
+ i2c_pnx_master_xmit(adap);
+ } else if (alg_data->mif.mode == I2C_SMBUS_READ) {
+ i2c_pnx_master_rcv(adap);
+ }
+ }
+ }
+
+ /* Clear TDI and AFI bits */
+ stat = ioread32(I2C_REG_STS(alg_data));
+ iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data));
+
+ dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)));
+
+ return IRQ_HANDLED;
+}
+
+static void i2c_pnx_timeout(unsigned long data)
+{
+ struct i2c_adapter *adap = (struct i2c_adapter *)data;
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ u32 ctl;
+
+ dev_err(&adap->dev, "Master timed out. stat = %04x, cntrl = %04x. "
+ "Resetting master...\n",
+ ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)));
+
+ /* Reset master and disable interrupts */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ ctl |= mcntrl_reset;
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+ wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ alg_data->mif.ret = -EIO;
+ complete(&alg_data->mif.complete);
+}
+
+static inline void bus_reset_if_active(struct i2c_adapter *adap)
+{
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ u32 stat;
+
+ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) {
+ dev_err(&adap->dev,
+ "%s: Bus is still active after xfer. Reset it...\n",
+ adap->name);
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+ I2C_REG_CTL(alg_data));
+ wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ } else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) {
+ /* If there is data in the fifo's after transfer,
+ * flush fifo's by reset.
+ */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+ I2C_REG_CTL(alg_data));
+ wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ } else if (stat & mstatus_nai) {
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+ I2C_REG_CTL(alg_data));
+ wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ }
+}
+
+/**
+ * i2c_pnx_xfer - generic transfer entry point
+ * @adap: pointer to I2C adapter structure
+ * @msgs: array of messages
+ * @num: number of messages
+ *
+ * Initiates the transfer
+ */
+static int
+i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *pmsg;
+ int rc = 0, completed = 0, i;
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ u32 stat = ioread32(I2C_REG_STS(alg_data));
+
+ dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n",
+ __FUNCTION__, num, ioread32(I2C_REG_STS(alg_data)));
+
+ bus_reset_if_active(adap);
+
+ /* Process transactions in a loop. */
+ for (i = 0; rc >= 0 && i < num; i++) {
+ u8 addr;
+
+ pmsg = &msgs[i];
+ addr = pmsg->addr;
+
+ if (pmsg->flags & I2C_M_TEN) {
+ dev_err(&adap->dev,
+ "%s: 10 bits addr not supported!\n",
+ adap->name);
+ rc = -EINVAL;
+ break;
+ }
+
+ alg_data->mif.buf = pmsg->buf;
+ alg_data->mif.len = pmsg->len;
+ alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ?
+ I2C_SMBUS_READ : I2C_SMBUS_WRITE;
+ alg_data->mif.ret = 0;
+ alg_data->last = (i == num - 1);
+
+ dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __FUNCTION__,
+ alg_data->mif.mode,
+ alg_data->mif.len);
+
+ i2c_pnx_arm_timer(adap);
+
+ /* initialize the completion var */
+ init_completion(&alg_data->mif.complete);
+
+ /* Enable master interrupt */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_afie |
+ mcntrl_naie | mcntrl_drmie,
+ I2C_REG_CTL(alg_data));
+
+ /* Put start-code and slave-address on the bus. */
+ rc = i2c_pnx_start(addr, adap);
+ if (rc < 0)
+ break;
+
+ /* Wait for completion */
+ wait_for_completion(&alg_data->mif.complete);
+
+ if (!(rc = alg_data->mif.ret))
+ completed++;
+ dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n",
+ __FUNCTION__, rc);
+
+ /* Clear TDI and AFI bits in case they are set. */
+ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) {
+ dev_dbg(&adap->dev,
+ "%s: TDI still set... clearing now.\n",
+ adap->name);
+ iowrite32(stat, I2C_REG_STS(alg_data));
+ }
+ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) {
+ dev_dbg(&adap->dev,
+ "%s: AFI still set... clearing now.\n",
+ adap->name);
+ iowrite32(stat, I2C_REG_STS(alg_data));
+ }
+ }
+
+ bus_reset_if_active(adap);
+
+ /* Cleanup to be sure... */
+ alg_data->mif.buf = NULL;
+ alg_data->mif.len = 0;
+
+ dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n",
+ __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+
+ if (completed != num)
+ return ((rc < 0) ? rc : -EREMOTEIO);
+
+ return num;
+}
+
+static u32 i2c_pnx_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm pnx_algorithm = {
+ .master_xfer = i2c_pnx_xfer,
+ .functionality = i2c_pnx_func,
+};
+
+static int i2c_pnx_controller_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
+ return i2c_pnx->suspend(pdev, state);
+}
+
+static int i2c_pnx_controller_resume(struct platform_device *pdev)
+{
+ struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
+ return i2c_pnx->resume(pdev);
+}
+
+static int __devinit i2c_pnx_probe(struct platform_device *pdev)
+{
+ unsigned long tmp;
+ int ret = 0;
+ struct i2c_pnx_algo_data *alg_data;
+ int freq_mhz;
+ struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
+
+ if (!i2c_pnx || !i2c_pnx->adapter) {
+ dev_err(&pdev->dev, "%s: no platform data supplied\n",
+ __FUNCTION__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ platform_set_drvdata(pdev, i2c_pnx);
+
+ if (i2c_pnx->calculate_input_freq)
+ freq_mhz = i2c_pnx->calculate_input_freq(pdev);
+ else {
+ freq_mhz = PNX_DEFAULT_FREQ;
+ dev_info(&pdev->dev, "Setting bus frequency to default value: "
+ "%d MHz", freq_mhz);
+ }
+
+ i2c_pnx->adapter->algo = &pnx_algorithm;
+
+ alg_data = i2c_pnx->adapter->algo_data;
+ init_timer(&alg_data->mif.timer);
+ alg_data->mif.timer.function = i2c_pnx_timeout;
+ alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter;
+
+ /* Register I/O resource */
+ if (!request_region(alg_data->base, I2C_PNX_REGION_SIZE, pdev->name)) {
+ dev_err(&pdev->dev,
+ "I/O region 0x%08x for I2C already in use.\n",
+ alg_data->base);
+ ret = -ENODEV;
+ goto out_drvdata;
+ }
+
+ if (!(alg_data->ioaddr =
+ (u32)ioremap(alg_data->base, I2C_PNX_REGION_SIZE))) {
+ dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n");
+ ret = -ENOMEM;
+ goto out_release;
+ }
+
+ i2c_pnx->set_clock_run(pdev);
+
+ /*
+ * Clock Divisor High This value is the number of system clocks
+ * the serial clock (SCL) will be high.
+ * For example, if the system clock period is 50 ns and the maximum
+ * desired serial period is 10000 ns (100 kHz), then CLKHI would be
+ * set to 0.5*(f_sys/f_i2c)-2=0.5*(20e6/100e3)-2=98. The actual value
+ * programmed into CLKHI will vary from this slightly due to
+ * variations in the output pad's rise and fall times as well as
+ * the deglitching filter length.
+ */
+
+ tmp = ((freq_mhz * 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+ iowrite32(tmp, I2C_REG_CKH(alg_data));
+ iowrite32(tmp, I2C_REG_CKL(alg_data));
+
+ iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
+ if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) {
+ ret = -ENODEV;
+ goto out_unmap;
+ }
+ init_completion(&alg_data->mif.complete);
+
+ ret = request_irq(alg_data->irq, i2c_pnx_interrupt,
+ 0, pdev->name, i2c_pnx->adapter);
+ if (ret)
+ goto out_clock;
+
+ /* Register this adapter with the I2C subsystem */
+ i2c_pnx->adapter->dev.parent = &pdev->dev;
+ ret = i2c_add_adapter(i2c_pnx->adapter);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "I2C: Failed to add bus\n");
+ goto out_irq;
+ }
+
+ dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
+ i2c_pnx->adapter->name, alg_data->base, alg_data->irq);
+
+ return 0;
+
+out_irq:
+ free_irq(alg_data->irq, alg_data);
+out_clock:
+ i2c_pnx->set_clock_stop(pdev);
+out_unmap:
+ iounmap((void *)alg_data->ioaddr);
+out_release:
+ release_region(alg_data->base, I2C_PNX_REGION_SIZE);
+out_drvdata:
+ platform_set_drvdata(pdev, NULL);
+out:
+ return ret;
+}
+
+static int __devexit i2c_pnx_remove(struct platform_device *pdev)
+{
+ struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev);
+ struct i2c_adapter *adap = i2c_pnx->adapter;
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+
+ free_irq(alg_data->irq, alg_data);
+ i2c_del_adapter(adap);
+ i2c_pnx->set_clock_stop(pdev);
+ iounmap((void *)alg_data->ioaddr);
+ release_region(alg_data->base, I2C_PNX_REGION_SIZE);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver i2c_pnx_driver = {
+ .driver = {
+ .name = "pnx-i2c",
+ .owner = THIS_MODULE,
+ },
+ .probe = i2c_pnx_probe,
+ .remove = __devexit_p(i2c_pnx_remove),
+ .suspend = i2c_pnx_controller_suspend,
+ .resume = i2c_pnx_controller_resume,
+};
+
+static int __init i2c_adap_pnx_init(void)
+{
+ return platform_driver_register(&i2c_pnx_driver);
+}
+
+static void __exit i2c_adap_pnx_exit(void)
+{
+ platform_driver_unregister(&i2c_pnx_driver);
+}
+
+MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev <source@mvista.com>");
+MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses");
+MODULE_LICENSE("GPL");
+
+/* We need to make sure I2C is initialized before USB */
+subsys_initcall(i2c_adap_pnx_init);
+module_exit(i2c_adap_pnx_exit);
diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c
index 7745e21874a..07c1f1e27df 100644
--- a/drivers/i2c/busses/i2c-prosavage.c
+++ b/drivers/i2c/busses/i2c-prosavage.c
@@ -212,7 +212,7 @@ static void prosavage_remove(struct pci_dev *dev)
if (chip->i2c_bus[i].adap_ok == 0)
continue;
- ret = i2c_bit_del_bus(&chip->i2c_bus[i].adap);
+ ret = i2c_del_adapter(&chip->i2c_bus[i].adap);
if (ret) {
dev_err(&dev->dev, "%s not removed\n",
chip->i2c_bus[i].adap.name);
diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c
index 209f47ea175..844b4ff9089 100644
--- a/drivers/i2c/busses/i2c-savage4.c
+++ b/drivers/i2c/busses/i2c-savage4.c
@@ -173,7 +173,7 @@ static int __devinit savage4_probe(struct pci_dev *dev, const struct pci_device_
static void __devexit savage4_remove(struct pci_dev *dev)
{
- i2c_bit_del_bus(&savage4_i2c_adapter);
+ i2c_del_adapter(&savage4_i2c_adapter);
iounmap(ioaddr);
}
diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c
new file mode 100644
index 00000000000..081d9578ce1
--- /dev/null
+++ b/drivers/i2c/busses/i2c-versatile.c
@@ -0,0 +1,153 @@
+/*
+ * i2c-versatile.c
+ *
+ * Copyright (C) 2006 ARM Ltd.
+ * written by Russell King, Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#define I2C_CONTROL 0x00
+#define I2C_CONTROLS 0x00
+#define I2C_CONTROLC 0x04
+#define SCL (1 << 0)
+#define SDA (1 << 1)
+
+struct i2c_versatile {
+ struct i2c_adapter adap;
+ struct i2c_algo_bit_data algo;
+ void __iomem *base;
+};
+
+static void i2c_versatile_setsda(void *data, int state)
+{
+ struct i2c_versatile *i2c = data;
+
+ writel(SDA, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static void i2c_versatile_setscl(void *data, int state)
+{
+ struct i2c_versatile *i2c = data;
+
+ writel(SCL, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static int i2c_versatile_getsda(void *data)
+{
+ struct i2c_versatile *i2c = data;
+ return !!(readl(i2c->base + I2C_CONTROL) & SDA);
+}
+
+static int i2c_versatile_getscl(void *data)
+{
+ struct i2c_versatile *i2c = data;
+ return !!(readl(i2c->base + I2C_CONTROL) & SCL);
+}
+
+static struct i2c_algo_bit_data i2c_versatile_algo = {
+ .setsda = i2c_versatile_setsda,
+ .setscl = i2c_versatile_setscl,
+ .getsda = i2c_versatile_getsda,
+ .getscl = i2c_versatile_getscl,
+ .udelay = 30,
+ .timeout = HZ,
+};
+
+static int i2c_versatile_probe(struct platform_device *dev)
+{
+ struct i2c_versatile *i2c;
+ struct resource *r;
+ int ret;
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!r) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if (!request_mem_region(r->start, r->end - r->start + 1, "versatile-i2c")) {
+ ret = -EBUSY;
+ goto err_out;
+ }
+
+ i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL);
+ if (!i2c) {
+ ret = -ENOMEM;
+ goto err_release;
+ }
+
+ i2c->base = ioremap(r->start, r->end - r->start + 1);
+ if (!i2c->base) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ writel(SCL | SDA, i2c->base + I2C_CONTROLS);
+
+ i2c->adap.owner = THIS_MODULE;
+ strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name));
+ i2c->adap.algo_data = &i2c->algo;
+ i2c->adap.dev.parent = &dev->dev;
+ i2c->algo = i2c_versatile_algo;
+ i2c->algo.data = i2c;
+
+ ret = i2c_bit_add_bus(&i2c->adap);
+ if (ret >= 0) {
+ platform_set_drvdata(dev, i2c);
+ return 0;
+ }
+
+ iounmap(i2c->base);
+ err_free:
+ kfree(i2c);
+ err_release:
+ release_mem_region(r->start, r->end - r->start + 1);
+ err_out:
+ return ret;
+}
+
+static int i2c_versatile_remove(struct platform_device *dev)
+{
+ struct i2c_versatile *i2c = platform_get_drvdata(dev);
+
+ platform_set_drvdata(dev, NULL);
+
+ i2c_del_adapter(&i2c->adap);
+ return 0;
+}
+
+static struct platform_driver i2c_versatile_driver = {
+ .probe = i2c_versatile_probe,
+ .remove = i2c_versatile_remove,
+ .driver = {
+ .name = "versatile-i2c",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init i2c_versatile_init(void)
+{
+ return platform_driver_register(&i2c_versatile_driver);
+}
+
+static void __exit i2c_versatile_exit(void)
+{
+ platform_driver_unregister(&i2c_versatile_driver);
+}
+
+module_init(i2c_versatile_init);
+module_exit(i2c_versatile_exit);
+
+MODULE_DESCRIPTION("ARM Versatile I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
index 910e200ad50..15d7e00e47e 100644
--- a/drivers/i2c/busses/i2c-via.c
+++ b/drivers/i2c/busses/i2c-via.c
@@ -151,7 +151,7 @@ static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_i
static void __devexit vt586b_remove(struct pci_dev *dev)
{
- i2c_bit_del_bus(&vt586b_adapter);
+ i2c_del_adapter(&vt586b_adapter);
release_region(I2C_DIR, IOSPACE);
pm_io_base = 0;
}
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
index 6c8d2518338..b0377b81744 100644
--- a/drivers/i2c/busses/i2c-voodoo3.c
+++ b/drivers/i2c/busses/i2c-voodoo3.c
@@ -211,14 +211,14 @@ static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_
return retval;
retval = i2c_bit_add_bus(&voodoo3_ddc_adapter);
if (retval)
- i2c_bit_del_bus(&voodoo3_i2c_adapter);
+ i2c_del_adapter(&voodoo3_i2c_adapter);
return retval;
}
static void __devexit voodoo3_remove(struct pci_dev *dev)
{
- i2c_bit_del_bus(&voodoo3_i2c_adapter);
- i2c_bit_del_bus(&voodoo3_ddc_adapter);
+ i2c_del_adapter(&voodoo3_i2c_adapter);
+ i2c_del_adapter(&voodoo3_ddc_adapter);
iounmap(ioaddr);
}
diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c
index 8ddbae4fafe..6cd96e43aa7 100644
--- a/drivers/i2c/busses/scx200_i2c.c
+++ b/drivers/i2c/busses/scx200_i2c.c
@@ -116,7 +116,7 @@ static int scx200_i2c_init(void)
static void scx200_i2c_cleanup(void)
{
- i2c_bit_del_bus(&scx200_i2c_ops);
+ i2c_del_adapter(&scx200_i2c_ops);
}
module_init(scx200_i2c_init);
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c
index 93d483b8b77..ec17d6b684a 100644
--- a/drivers/i2c/chips/ds1337.c
+++ b/drivers/i2c/chips/ds1337.c
@@ -347,13 +347,19 @@ static void ds1337_init_client(struct i2c_client *client)
if ((status & 0x80) || (control & 0x80)) {
/* RTC not running */
- u8 buf[16];
+ u8 buf[1+16]; /* First byte is interpreted as address */
struct i2c_msg msg[1];
dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__);
/* Initialize all, including STATUS and CONTROL to zero */
memset(buf, 0, sizeof(buf));
+
+ /* Write valid values in the date/time registers */
+ buf[1+DS1337_REG_DAY] = 1;
+ buf[1+DS1337_REG_DATE] = 1;
+ buf[1+DS1337_REG_MONTH] = 1;
+
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = sizeof(buf);
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index ccdf3e90862..9fafadb9251 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -27,7 +27,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c
index 420377c8642..3fcb646e207 100644
--- a/drivers/i2c/chips/m41t00.c
+++ b/drivers/i2c/chips/m41t00.c
@@ -209,6 +209,7 @@ m41t00_set(void *arg)
buf[m41t00_chip->hour] = (buf[m41t00_chip->hour] & ~0x3f) | (hour& 0x3f);
buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f);
buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f);
+ buf[m41t00_chip->year] = year;
if (i2c_master_send(save_client, wbuf, 9) < 0)
dev_err(&save_client->dev, "m41t00_set: Write error\n");
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 60bef94cd25..4ee56def61f 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -82,7 +82,7 @@ struct tps65010 {
struct i2c_client client;
struct mutex lock;
int irq;
- struct work_struct work;
+ struct delayed_work work;
struct dentry *file;
unsigned charging:1;
unsigned por:1;
@@ -328,7 +328,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
{
u8 tmp = 0, mask, poll;
- /* IRQs won't trigger irqs for certain events, but we can get
+ /* IRQs won't trigger for certain events, but we can get
* others by polling (normally, with external power applied).
*/
poll = 0;
@@ -411,10 +411,11 @@ static void tps65010_interrupt(struct tps65010 *tps)
}
/* handle IRQs and polling using keventd for now */
-static void tps65010_work(void *_tps)
+static void tps65010_work(struct work_struct *work)
{
- struct tps65010 *tps = _tps;
+ struct tps65010 *tps;
+ tps = container_of(work, struct tps65010, work.work);
mutex_lock(&tps->lock);
tps65010_interrupt(tps);
@@ -452,7 +453,7 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
disable_irq_nosync(irq);
set_bit(FLAG_IRQ_ENABLE, &tps->flags);
- (void) schedule_work(&tps->work);
+ (void) schedule_work(&tps->work.work);
return IRQ_HANDLED;
}
@@ -465,13 +466,15 @@ static int __exit tps65010_detach_client(struct i2c_client *client)
struct tps65010 *tps;
tps = container_of(client, struct tps65010, client);
+ free_irq(tps->irq, tps);
#ifdef CONFIG_ARM
if (machine_is_omap_h2())
omap_free_gpio(58);
if (machine_is_omap_osk())
omap_free_gpio(OMAP_MPUIO(1));
#endif
- free_irq(tps->irq, tps);
+ cancel_delayed_work(&tps->work);
+ flush_scheduled_work();
debugfs_remove(tps->file);
if (i2c_detach_client(client) == 0)
kfree(tps);
@@ -505,7 +508,7 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
return 0;
mutex_init(&tps->lock);
- INIT_WORK(&tps->work, tps65010_work, tps);
+ INIT_DELAYED_WORK(&tps->work, tps65010_work);
tps->irq = -1;
tps->client.addr = address;
tps->client.adapter = bus;
@@ -620,7 +623,7 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
(void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK3, 0x0f
| i2c_smbus_read_byte_data(&tps->client, TPS_MASK3));
- tps65010_work(tps);
+ tps65010_work(&tps->work.work);
tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL,
tps, DEBUG_FOPS);
@@ -672,7 +675,7 @@ int tps65010_set_vbus_draw(unsigned mA)
&& test_and_set_bit(
FLAG_VBUS_CHANGED, &the_tps->flags)) {
/* gadget drivers call this in_irq() */
- (void) schedule_work(&the_tps->work);
+ (void) schedule_work(&the_tps->work.work);
}
local_irq_restore(flags);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 7ca81f42d14..b05378a3d67 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -95,16 +95,32 @@ struct device_driver i2c_adapter_driver = {
.bus = &i2c_bus_type,
};
+/* ------------------------------------------------------------------------- */
+
+/* I2C bus adapters -- one roots each I2C or SMBUS segment */
+
static void i2c_adapter_class_dev_release(struct class_device *dev)
{
struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev);
complete(&adap->class_dev_released);
}
+static ssize_t i2c_adapter_show_name(struct class_device *cdev, char *buf)
+{
+ struct i2c_adapter *adap = class_dev_to_i2c_adapter(cdev);
+ return sprintf(buf, "%s\n", adap->name);
+}
+
+static struct class_device_attribute i2c_adapter_attrs[] = {
+ __ATTR(name, S_IRUGO, i2c_adapter_show_name, NULL),
+ { },
+};
+
struct class i2c_adapter_class = {
- .owner = THIS_MODULE,
- .name = "i2c-adapter",
- .release = &i2c_adapter_class_dev_release,
+ .owner = THIS_MODULE,
+ .name = "i2c-adapter",
+ .class_dev_attrs = i2c_adapter_attrs,
+ .release = &i2c_adapter_class_dev_release,
};
static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
@@ -127,20 +143,17 @@ static ssize_t show_client_name(struct device *dev, struct device_attribute *att
return sprintf(buf, "%s\n", client->name);
}
-/*
- * We can't use the DEVICE_ATTR() macro here as we want the same filename for a
- * different type of a device. So beware if the DEVICE_ATTR() macro ever
- * changes, this definition will also have to change.
+/*
+ * We can't use the DEVICE_ATTR() macro here, as we used the same name for
+ * an i2c adapter attribute (above).
*/
-static struct device_attribute dev_attr_client_name = {
- .attr = {.name = "name", .mode = S_IRUGO, .owner = THIS_MODULE },
- .show = &show_client_name,
-};
+static struct device_attribute dev_attr_client_name =
+ __ATTR(name, S_IRUGO, &show_client_name, NULL);
/* ---------------------------------------------------
- * registering functions
- * ---------------------------------------------------
+ * registering functions
+ * ---------------------------------------------------
*/
/* -----
@@ -178,8 +191,12 @@ int i2c_add_adapter(struct i2c_adapter *adap)
* If the parent pointer is not set up,
* we add this adapter to the host bus.
*/
- if (adap->dev.parent == NULL)
+ if (adap->dev.parent == NULL) {
adap->dev.parent = &platform_bus;
+ printk(KERN_WARNING "**WARNING** I2C adapter driver [%s] "
+ "forgot to specify physical device; fix it!\n",
+ adap->name);
+ }
sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
adap->dev.driver = &i2c_adapter_driver;
adap->dev.release = &i2c_adapter_dev_release;
@@ -314,7 +331,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
res = driver_register(&driver->driver);
if (res)
return res;
-
+
mutex_lock(&core_lists);
list_add_tail(&driver->list,&drivers);
@@ -338,13 +355,13 @@ int i2c_del_driver(struct i2c_driver *driver)
struct list_head *item1, *item2, *_n;
struct i2c_client *client;
struct i2c_adapter *adap;
-
+
int res = 0;
mutex_lock(&core_lists);
/* Have a look at each adapter, if clients of this driver are still
- * attached. If so, detach them to be able to kill the driver
+ * attached. If so, detach them to be able to kill the driver
* afterwards.
*/
list_for_each(item1,&adapters) {
@@ -419,14 +436,14 @@ int i2c_attach_client(struct i2c_client *client)
goto out_unlock;
}
list_add_tail(&client->list,&adapter->clients);
-
+
client->usage_count = 0;
client->dev.parent = &client->adapter->dev;
client->dev.driver = &client->driver->driver;
client->dev.bus = &i2c_bus_type;
client->dev.release = &i2c_client_release;
-
+
snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
"%d-%04x", i2c_adapter_id(adapter), client->addr);
dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
@@ -467,7 +484,7 @@ int i2c_detach_client(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
int res = 0;
-
+
if (client->usage_count > 0) {
dev_warn(&client->dev, "Client [%s] still busy, "
"can't detach\n", client->name);
@@ -535,10 +552,10 @@ int i2c_release_client(struct i2c_client *client)
__FUNCTION__);
return -EPERM;
}
-
+
client->usage_count--;
i2c_dec_use_client(client);
-
+
return 0;
}
@@ -603,7 +620,7 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
}
#endif
- mutex_lock(&adap->bus_lock);
+ mutex_lock_nested(&adap->bus_lock, adap->level);
ret = adap->algo->master_xfer(adap,msgs,num);
mutex_unlock(&adap->bus_lock);
@@ -624,7 +641,7 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
msg.flags = client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)buf;
-
+
ret = i2c_transfer(adap, &msg, 1);
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
@@ -757,7 +774,7 @@ int i2c_probe(struct i2c_adapter *adapter,
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
if (address_data->probe[0] == I2C_CLIENT_END
&& address_data->normal_i2c[0] == I2C_CLIENT_END)
- return 0;
+ return 0;
dev_warn(&adapter->dev, "SMBus Quick command not supported, "
"can't probe for chips\n");
@@ -817,7 +834,7 @@ int i2c_probe(struct i2c_adapter *adapter,
struct i2c_adapter* i2c_get_adapter(int id)
{
struct i2c_adapter *adapter;
-
+
mutex_lock(&core_lists);
adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
if (adapter && !try_module_get(adapter->owner))
@@ -834,14 +851,14 @@ void i2c_put_adapter(struct i2c_adapter *adap)
/* The SMBus parts */
-#define POLY (0x1070U << 3)
+#define POLY (0x1070U << 3)
static u8
crc8(u16 data)
{
int i;
-
+
for(i = 0; i < 8; i++) {
- if (data & 0x8000)
+ if (data & 0x8000)
data = data ^ POLY;
data = data << 1;
}
@@ -891,13 +908,13 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg)
rpec, cpec);
return -1;
}
- return 0;
+ return 0;
}
s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value)
{
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- value,0,I2C_SMBUS_QUICK,NULL);
+ value,0,I2C_SMBUS_QUICK,NULL);
}
s32 i2c_smbus_read_byte(struct i2c_client *client)
@@ -996,11 +1013,11 @@ s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command,
I2C_SMBUS_I2C_BLOCK_DATA, &data);
}
-/* Simulate a SMBus command using the i2c protocol
+/* Simulate a SMBus command using the i2c protocol
No checking of parameters is done! */
-static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
+static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
unsigned short flags,
- char read_write, u8 command, int size,
+ char read_write, u8 command, int size,
union i2c_smbus_data * data)
{
/* So we need to generate a series of msgs. In the case of writing, we
@@ -1010,7 +1027,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
int num = read_write == I2C_SMBUS_READ?2:1;
- struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
+ struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
{ addr, flags | I2C_M_RD, 0, msgbuf1 }
};
int i;
@@ -1103,14 +1120,14 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
if (i) {
/* Compute PEC if first message is a write */
if (!(msg[0].flags & I2C_M_RD)) {
- if (num == 1) /* Write only */
+ if (num == 1) /* Write only */
i2c_smbus_add_pec(&msg[0]);
else /* Write followed by read */
partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
}
/* Ask for PEC if last message is a read */
if (msg[num-1].flags & I2C_M_RD)
- msg[num-1].len++;
+ msg[num-1].len++;
}
if (i2c_transfer(adapter, msg, num) < 0)
@@ -1130,7 +1147,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
case I2C_SMBUS_BYTE_DATA:
data->byte = msgbuf1[0];
break;
- case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
data->word = msgbuf1[0] | (msgbuf1[1] << 8);
break;
@@ -1146,7 +1163,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
- char read_write, u8 command, int size,
+ char read_write, u8 command, int size,
union i2c_smbus_data * data)
{
s32 res;
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 94a4e9a3013..ac5bd2a7ca9 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -1,5 +1,5 @@
/*
- i2c-dev.c - i2c-bus driver, char device interface
+ i2c-dev.c - i2c-bus driver, char device interface
Copyright (C) 1995-97 Simon G. Vogl
Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
@@ -90,6 +90,7 @@ static void return_i2c_dev(struct i2c_dev *i2c_dev)
spin_lock(&i2c_dev_list_lock);
list_del(&i2c_dev->list);
spin_unlock(&i2c_dev_list_lock);
+ kfree(i2c_dev);
}
static ssize_t show_adapter_name(struct device *dev,
@@ -119,7 +120,7 @@ static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
return -ENOMEM;
pr_debug("i2c-dev: i2c-%d reading %zd bytes.\n",
- iminor(file->f_dentry->d_inode), count);
+ iminor(file->f_path.dentry->d_inode), count);
ret = i2c_master_recv(client,tmp,count);
if (ret >= 0)
@@ -147,7 +148,7 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c
}
pr_debug("i2c-dev: i2c-%d writing %zd bytes.\n",
- iminor(file->f_dentry->d_inode), count);
+ iminor(file->f_path.dentry->d_inode), count);
ret = i2c_master_send(client,tmp,count);
kfree(tmp);
@@ -172,7 +173,7 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
switch ( cmd ) {
case I2C_SLAVE:
case I2C_SLAVE_FORCE:
- if ((arg > 0x3ff) ||
+ if ((arg > 0x3ff) ||
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
return -EINVAL;
if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
@@ -193,12 +194,11 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
return 0;
case I2C_FUNCS:
funcs = i2c_get_functionality(client->adapter);
- return (copy_to_user((unsigned long __user *)arg, &funcs,
- sizeof(unsigned long)))?-EFAULT:0;
+ return put_user(funcs, (unsigned long __user *)arg);
case I2C_RDWR:
- if (copy_from_user(&rdwr_arg,
- (struct i2c_rdwr_ioctl_data __user *)arg,
+ if (copy_from_user(&rdwr_arg,
+ (struct i2c_rdwr_ioctl_data __user *)arg,
sizeof(rdwr_arg)))
return -EFAULT;
@@ -206,9 +206,9 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
* be sent at once */
if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
return -EINVAL;
-
+
rdwr_pa = (struct i2c_msg *)
- kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
+ kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
GFP_KERNEL);
if (rdwr_pa == NULL) return -ENOMEM;
@@ -278,9 +278,9 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
(struct i2c_smbus_ioctl_data __user *) arg,
sizeof(struct i2c_smbus_ioctl_data)))
return -EFAULT;
- if ((data_arg.size != I2C_SMBUS_BYTE) &&
+ if ((data_arg.size != I2C_SMBUS_BYTE) &&
(data_arg.size != I2C_SMBUS_QUICK) &&
- (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
+ (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
(data_arg.size != I2C_SMBUS_WORD_DATA) &&
(data_arg.size != I2C_SMBUS_PROC_CALL) &&
(data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
@@ -291,11 +291,11 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
data_arg.size);
return -EINVAL;
}
- /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
+ /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
so the check is valid if size==I2C_SMBUS_QUICK too. */
- if ((data_arg.read_write != I2C_SMBUS_READ) &&
+ if ((data_arg.read_write != I2C_SMBUS_READ) &&
(data_arg.read_write != I2C_SMBUS_WRITE)) {
- dev_dbg(&client->adapter->dev,
+ dev_dbg(&client->adapter->dev,
"read_write out of range (%x) in ioctl I2C_SMBUS.\n",
data_arg.read_write);
return -EINVAL;
@@ -304,7 +304,7 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
/* Note that command values are always valid! */
if ((data_arg.size == I2C_SMBUS_QUICK) ||
- ((data_arg.size == I2C_SMBUS_BYTE) &&
+ ((data_arg.size == I2C_SMBUS_BYTE) &&
(data_arg.read_write == I2C_SMBUS_WRITE)))
/* These are special: we do not use data */
return i2c_smbus_xfer(client->adapter, client->addr,
@@ -322,14 +322,14 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
(data_arg.size == I2C_SMBUS_BYTE))
datasize = sizeof(data_arg.data->byte);
- else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
+ else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
(data_arg.size == I2C_SMBUS_PROC_CALL))
datasize = sizeof(data_arg.data->word);
else /* size == smbus block, i2c block, or block proc. call */
datasize = sizeof(data_arg.data->block);
- if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
- (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
+ if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+ (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
(data_arg.read_write == I2C_SMBUS_WRITE)) {
if (copy_from_user(&temp, data_arg.data, datasize))
return -EFAULT;
@@ -337,8 +337,8 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
data_arg.read_write,
data_arg.command,data_arg.size,&temp);
- if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
- (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
+ if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+ (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
(data_arg.read_write == I2C_SMBUS_READ))) {
if (copy_to_user(data_arg.data, &temp, datasize))
return -EFAULT;
@@ -417,8 +417,8 @@ static int i2cdev_attach_adapter(struct i2c_adapter *adap)
i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
MKDEV(I2C_MAJOR, adap->nr),
"i2c-%d", adap->nr);
- if (!i2c_dev->dev) {
- res = -ENODEV;
+ if (IS_ERR(i2c_dev->dev)) {
+ res = PTR_ERR(i2c_dev->dev);
goto error;
}
res = device_create_file(i2c_dev->dev, &dev_attr_name);
@@ -432,7 +432,6 @@ error_destroy:
device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
return_i2c_dev(i2c_dev);
- kfree(i2c_dev);
return res;
}
@@ -447,7 +446,6 @@ static int i2cdev_detach_adapter(struct i2c_adapter *adap)
device_remove_file(i2c_dev->dev, &dev_attr_name);
return_i2c_dev(i2c_dev);
device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
- kfree(i2c_dev);
pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
return 0;
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index e23bc0d6215..ec03341d2bd 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -167,6 +167,13 @@ config BLK_DEV_IDECS
Support for Compact Flash cards, outboard IDE disks, tape drives,
and CD-ROM drives connected through a PCMCIA card.
+config BLK_DEV_DELKIN
+ tristate "Cardbus IDE support (Delkin/ASKA/Workbit)"
+ depends on CARDBUS && PCI
+ help
+ Support for Delkin, ASKA, and Workbit Cardbus CompactFlash
+ Adapters. This may also work for similar SD and XD adapters.
+
config BLK_DEV_IDECD
tristate "Include IDE/ATAPI CDROM support"
---help---
@@ -264,6 +271,13 @@ config BLK_DEV_IDESCSI
If both this SCSI emulation and native ATAPI support are compiled
into the kernel, the native support will be used.
+config BLK_DEV_IDEACPI
+ bool "IDE ACPI support"
+ depends on ACPI
+ ---help---
+ Implement ACPI support for generic IDE devices. On modern
+ machines ACPI support is required to properly handle ACPI S3 states.
+
config IDE_TASK_IOCTL
bool "IDE Taskfile Access"
help
@@ -606,6 +620,11 @@ config BLK_DEV_PIIX
the kernel to change PIO, DMA and UDMA speeds and to configure
the chip to optimum performance.
+config BLK_DEV_IT8213
+ tristate "IT8213 IDE support"
+ help
+ This driver adds support for the ITE 8213 IDE controller.
+
config BLK_DEV_IT821X
tristate "IT821X IDE support"
help
@@ -742,6 +761,11 @@ config BLK_DEV_VIA82CXXX
This allows the kernel to change PIO, DMA and UDMA speeds and to
configure the chip to optimum performance.
+config BLK_DEV_TC86C001
+ tristate "Toshiba TC86C001 support"
+ help
+ This driver adds support for Toshiba TC86C001 GOKU-S chip.
+
endif
config BLK_DEV_IDE_PMAC
@@ -796,7 +820,7 @@ endchoice
config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ
int "Maximum transfer size (KB) per request (up to 128)"
default "128"
- depends BLK_DEV_IDE_AU1XXX
+ depends on BLK_DEV_IDE_AU1XXX
config IDE_ARM
def_bool ARM && (ARCH_A5K || ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 569fae71750..d9f029e8ff7 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
ide-core-$(CONFIG_PROC_FS) += ide-proc.o
ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
+ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o
# built-in only drivers from arm/
ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
new file mode 100644
index 00000000000..17aea65d7dd
--- /dev/null
+++ b/drivers/ide/ide-acpi.c
@@ -0,0 +1,697 @@
+/*
+ * ide-acpi.c
+ * Provides ACPI support for IDE drives.
+ *
+ * Copyright (C) 2005 Intel Corp.
+ * Copyright (C) 2005 Randy Dunlap
+ * Copyright (C) 2006 SUSE Linux Products GmbH
+ * Copyright (C) 2006 Hannes Reinecke
+ */
+
+#include <linux/ata.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <acpi/acpi.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#define REGS_PER_GTF 7
+struct taskfile_array {
+ u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
+};
+
+struct GTM_buffer {
+ u32 PIO_speed0;
+ u32 DMA_speed0;
+ u32 PIO_speed1;
+ u32 DMA_speed1;
+ u32 GTM_flags;
+};
+
+struct ide_acpi_drive_link {
+ ide_drive_t *drive;
+ acpi_handle obj_handle;
+ u8 idbuff[512];
+};
+
+struct ide_acpi_hwif_link {
+ ide_hwif_t *hwif;
+ acpi_handle obj_handle;
+ struct GTM_buffer gtm;
+ struct ide_acpi_drive_link master;
+ struct ide_acpi_drive_link slave;
+};
+
+#undef DEBUGGING
+/* note: adds function name and KERN_DEBUG */
+#ifdef DEBUGGING
+#define DEBPRINT(fmt, args...) \
+ printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DEBPRINT(fmt, args...) do {} while (0)
+#endif /* DEBUGGING */
+
+extern int ide_noacpi;
+extern int ide_noacpitfs;
+extern int ide_noacpionboot;
+
+/**
+ * ide_get_dev_handle - finds acpi_handle and PCI device.function
+ * @dev: device to locate
+ * @handle: returned acpi_handle for @dev
+ * @pcidevfn: return PCI device.func for @dev
+ *
+ * Returns the ACPI object handle to the corresponding PCI device.
+ *
+ * Returns 0 on success, <0 on error.
+ */
+static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
+ acpi_integer *pcidevfn)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ unsigned int bus, devnum, func;
+ acpi_integer addr;
+ acpi_handle dev_handle;
+ struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
+ .pointer = NULL};
+ acpi_status status;
+ struct acpi_device_info *dinfo = NULL;
+ int ret = -ENODEV;
+
+ bus = pdev->bus->number;
+ devnum = PCI_SLOT(pdev->devfn);
+ func = PCI_FUNC(pdev->devfn);
+ /* ACPI _ADR encoding for PCI bus: */
+ addr = (acpi_integer)(devnum << 16 | func);
+
+ DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
+
+ dev_handle = DEVICE_ACPI_HANDLE(dev);
+ if (!dev_handle) {
+ DEBPRINT("no acpi handle for device\n");
+ goto err;
+ }
+
+ status = acpi_get_object_info(dev_handle, &buffer);
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("get_object_info for device failed\n");
+ goto err;
+ }
+ dinfo = buffer.pointer;
+ if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
+ dinfo->address == addr) {
+ *pcidevfn = addr;
+ *handle = dev_handle;
+ } else {
+ DEBPRINT("get_object_info for device has wrong "
+ " address: %llu, should be %u\n",
+ dinfo ? (unsigned long long)dinfo->address : -1ULL,
+ (unsigned int)addr);
+ goto err;
+ }
+
+ DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
+ devnum, func, (unsigned long long)addr, *handle);
+ ret = 0;
+err:
+ kfree(dinfo);
+ return ret;
+}
+
+/**
+ * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
+ * @hwif: device to locate
+ *
+ * Retrieves the object handle for a given hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
+{
+ struct device *dev = hwif->gendev.parent;
+ acpi_handle dev_handle;
+ acpi_integer pcidevfn;
+ acpi_handle chan_handle;
+ int err;
+
+ DEBPRINT("ENTER: device %s\n", hwif->name);
+
+ if (!dev) {
+ DEBPRINT("no PCI device for %s\n", hwif->name);
+ return NULL;
+ }
+
+ err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
+ if (err < 0) {
+ DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
+ return NULL;
+ }
+
+ /* get child objects of dev_handle == channel objects,
+ * + _their_ children == drive objects */
+ /* channel is hwif->channel */
+ chan_handle = acpi_get_child(dev_handle, hwif->channel);
+ DEBPRINT("chan adr=%d: handle=0x%p\n",
+ hwif->channel, chan_handle);
+
+ return chan_handle;
+}
+
+/**
+ * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive
+ * @drive: device to locate
+ *
+ * Retrieves the object handle of a given drive. According to the ACPI
+ * spec the drive is a child of the hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int port;
+ acpi_handle drive_handle;
+
+ if (!hwif->acpidata)
+ return NULL;
+
+ if (!hwif->acpidata->obj_handle)
+ return NULL;
+
+ port = hwif->channel ? drive->dn - 2: drive->dn;
+
+ DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
+ drive->name, hwif->channel, port);
+
+
+ /* TBD: could also check ACPI object VALID bits */
+ drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);
+ DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);
+
+ return drive_handle;
+}
+
+/**
+ * do_drive_get_GTF - get the drive bootup default taskfile settings
+ * @drive: the drive for which the taskfile settings should be retrieved
+ * @gtf_length: number of bytes of _GTF data returned at @gtf_address
+ * @gtf_address: buffer containing _GTF taskfile arrays
+ *
+ * The _GTF method has no input parameters.
+ * It returns a variable number of register set values (registers
+ * hex 1F1..1F7, taskfiles).
+ * The <variable number> is not known in advance, so have ACPI-CA
+ * allocate the buffer as needed and return it, then free it later.
+ *
+ * The returned @gtf_length and @gtf_address are only valid if the
+ * function return value is 0.
+ */
+static int do_drive_get_GTF(ide_drive_t *drive,
+ unsigned int *gtf_length, unsigned long *gtf_address,
+ unsigned long *obj_loc)
+{
+ acpi_status status;
+ struct acpi_buffer output;
+ union acpi_object *out_obj;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct device *dev = hwif->gendev.parent;
+ int err = -ENODEV;
+ int port;
+
+ *gtf_length = 0;
+ *gtf_address = 0UL;
+ *obj_loc = 0UL;
+
+ if (ide_noacpi)
+ return 0;
+
+ if (!dev) {
+ DEBPRINT("no PCI device for %s\n", hwif->name);
+ goto out;
+ }
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ goto out;
+ }
+
+ port = hwif->channel ? drive->dn - 2: drive->dn;
+
+ if (!drive->acpidata) {
+ if (port == 0) {
+ drive->acpidata = &hwif->acpidata->master;
+ hwif->acpidata->master.drive = drive;
+ } else {
+ drive->acpidata = &hwif->acpidata->slave;
+ hwif->acpidata->slave.drive = drive;
+ }
+ }
+
+ DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
+ hwif->name, dev->bus_id, port, hwif->channel);
+
+ if (!drive->present) {
+ DEBPRINT("%s drive %d:%d not present\n",
+ hwif->name, hwif->channel, port);
+ goto out;
+ }
+
+ /* Get this drive's _ADR info. if not already known. */
+ if (!drive->acpidata->obj_handle) {
+ drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+ if (!drive->acpidata->obj_handle) {
+ DEBPRINT("No ACPI object found for %s\n",
+ drive->name);
+ goto out;
+ }
+ }
+
+ /* Setting up output buffer */
+ output.length = ACPI_ALLOCATE_BUFFER;
+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
+
+ /* _GTF has no input parameters */
+ err = -EIO;
+ status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",
+ NULL, &output);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_DEBUG
+ "%s: Run _GTF error: status = 0x%x\n",
+ __FUNCTION__, status);
+ goto out;
+ }
+
+ if (!output.length || !output.pointer) {
+ DEBPRINT("Run _GTF: "
+ "length or ptr is NULL (0x%llx, 0x%p)\n",
+ (unsigned long long)output.length,
+ output.pointer);
+ goto out;
+ }
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ DEBPRINT("Run _GTF: error: "
+ "expected object type of ACPI_TYPE_BUFFER, "
+ "got 0x%x\n", out_obj->type);
+ err = -ENOENT;
+ kfree(output.pointer);
+ goto out;
+ }
+
+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+ out_obj->buffer.length % REGS_PER_GTF) {
+ printk(KERN_ERR
+ "%s: unexpected GTF length (%d) or addr (0x%p)\n",
+ __FUNCTION__, out_obj->buffer.length,
+ out_obj->buffer.pointer);
+ err = -ENOENT;
+ kfree(output.pointer);
+ goto out;
+ }
+
+ *gtf_length = out_obj->buffer.length;
+ *gtf_address = (unsigned long)out_obj->buffer.pointer;
+ *obj_loc = (unsigned long)out_obj;
+ DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
+ *gtf_length, *gtf_address, *obj_loc);
+ err = 0;
+out:
+ return err;
+}
+
+/**
+ * taskfile_load_raw - send taskfile registers to drive
+ * @drive: drive to which output is sent
+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
+ *
+ * Outputs IDE taskfile to the drive.
+ */
+static int taskfile_load_raw(ide_drive_t *drive,
+ const struct taskfile_array *gtf)
+{
+ ide_task_t args;
+ int err = 0;
+
+ DEBPRINT("(0x1f1-1f7): hex: "
+ "%02x %02x %02x %02x %02x %02x %02x\n",
+ gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
+ gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
+
+ memset(&args, 0, sizeof(ide_task_t));
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.data_phase = TASKFILE_IN;
+ args.handler = &task_no_data_intr;
+
+ /* convert gtf to IDE Taskfile */
+ args.tfRegister[1] = gtf->tfa[0]; /* 0x1f1 */
+ args.tfRegister[2] = gtf->tfa[1]; /* 0x1f2 */
+ args.tfRegister[3] = gtf->tfa[2]; /* 0x1f3 */
+ args.tfRegister[4] = gtf->tfa[3]; /* 0x1f4 */
+ args.tfRegister[5] = gtf->tfa[4]; /* 0x1f5 */
+ args.tfRegister[6] = gtf->tfa[5]; /* 0x1f6 */
+ args.tfRegister[7] = gtf->tfa[6]; /* 0x1f7 */
+
+ if (ide_noacpitfs) {
+ DEBPRINT("_GTF execution disabled\n");
+ return err;
+ }
+
+ err = ide_raw_taskfile(drive, &args, NULL);
+ if (err)
+ printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
+ __FUNCTION__, err);
+
+ return err;
+}
+
+/**
+ * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
+ * @drive: the drive to which the taskfile command should be sent
+ * @gtf_length: total number of bytes of _GTF taskfiles
+ * @gtf_address: location of _GTF taskfile arrays
+ *
+ * Write {gtf_address, length gtf_length} in groups of
+ * REGS_PER_GTF bytes.
+ */
+static int do_drive_set_taskfiles(ide_drive_t *drive,
+ unsigned int gtf_length,
+ unsigned long gtf_address)
+{
+ int rc = -ENODEV, err;
+ int gtf_count = gtf_length / REGS_PER_GTF;
+ int ix;
+ struct taskfile_array *gtf;
+
+ if (ide_noacpi)
+ return 0;
+
+ DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
+
+ if (!drive->present)
+ goto out;
+ if (!gtf_count) /* shouldn't be here */
+ goto out;
+
+ DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
+ gtf_length, gtf_length, gtf_count, gtf_address);
+
+ if (gtf_length % REGS_PER_GTF) {
+ printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
+ __FUNCTION__, gtf_length);
+ goto out;
+ }
+
+ rc = 0;
+ for (ix = 0; ix < gtf_count; ix++) {
+ gtf = (struct taskfile_array *)
+ (gtf_address + ix * REGS_PER_GTF);
+
+ /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
+ err = taskfile_load_raw(drive, gtf);
+ if (err)
+ rc = err;
+ }
+
+out:
+ return rc;
+}
+
+/**
+ * ide_acpi_exec_tfs - get then write drive taskfile settings
+ * @drive: the drive for which the taskfile settings should be
+ * written.
+ *
+ * According to the ACPI spec this should be called after _STM
+ * has been evaluated for the interface. Some ACPI vendors interpret
+ * that as a hard requirement and modify the taskfile according
+ * to the Identify Drive information passed down with _STM.
+ * So one should really make sure to call this only after _STM has
+ * been executed.
+ */
+int ide_acpi_exec_tfs(ide_drive_t *drive)
+{
+ int ret;
+ unsigned int gtf_length;
+ unsigned long gtf_address;
+ unsigned long obj_loc;
+
+ if (ide_noacpi)
+ return 0;
+
+ DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
+
+ ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
+ if (ret < 0) {
+ DEBPRINT("get_GTF error (%d)\n", ret);
+ return ret;
+ }
+
+ DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
+
+ ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
+ kfree((void *)obj_loc);
+ if (ret < 0) {
+ DEBPRINT("set_taskfiles error (%d)\n", ret);
+ }
+
+ DEBPRINT("ret=%d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs);
+
+/**
+ * ide_acpi_get_timing - get the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _GTM ACPI method for the target channel.
+ *
+ */
+void ide_acpi_get_timing(ide_hwif_t *hwif)
+{
+ acpi_status status;
+ struct acpi_buffer output;
+ union acpi_object *out_obj;
+
+ if (ide_noacpi)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+
+ /* Setting up output buffer for _GTM */
+ output.length = ACPI_ALLOCATE_BUFFER;
+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
+
+ /* _GTM has no input parameters */
+ status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
+ NULL, &output);
+
+ DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
+ status, output.pointer,
+ (unsigned long long)output.length);
+
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("Run _GTM error: status = 0x%x\n", status);
+ return;
+ }
+
+ if (!output.length || !output.pointer) {
+ DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
+ (unsigned long long)output.length,
+ output.pointer);
+ kfree(output.pointer);
+ return;
+ }
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ kfree(output.pointer);
+ DEBPRINT("Run _GTM: error: "
+ "expected object type of ACPI_TYPE_BUFFER, "
+ "got 0x%x\n", out_obj->type);
+ return;
+ }
+
+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+ out_obj->buffer.length != sizeof(struct GTM_buffer)) {
+ kfree(output.pointer);
+ printk(KERN_ERR
+ "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
+ "addr (0x%p)\n",
+ __FUNCTION__, out_obj->buffer.length,
+ sizeof(struct GTM_buffer), out_obj->buffer.pointer);
+ return;
+ }
+
+ memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
+ sizeof(struct GTM_buffer));
+
+ DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n",
+ out_obj->buffer.pointer, out_obj->buffer.length,
+ sizeof(struct GTM_buffer));
+
+ DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+ hwif->acpidata->gtm.PIO_speed0,
+ hwif->acpidata->gtm.DMA_speed0,
+ hwif->acpidata->gtm.PIO_speed1,
+ hwif->acpidata->gtm.DMA_speed1,
+ hwif->acpidata->gtm.GTM_flags);
+
+ kfree(output.pointer);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
+
+/**
+ * ide_acpi_push_timing - set the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _STM ACPI method for the target channel.
+ *
+ * _STM requires Identify Drive data, which has to passed as an argument.
+ * Unfortunately hd_driveid is a mangled version which we can't readily
+ * use; hence we'll get the information afresh.
+ */
+void ide_acpi_push_timing(ide_hwif_t *hwif)
+{
+ acpi_status status;
+ struct acpi_object_list input;
+ union acpi_object in_params[3];
+ struct ide_acpi_drive_link *master = &hwif->acpidata->master;
+ struct ide_acpi_drive_link *slave = &hwif->acpidata->slave;
+
+ if (ide_noacpi)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+
+ /* Give the GTM buffer + drive Identify data to the channel via the
+ * _STM method: */
+ /* setup input parameters buffer for _STM */
+ input.count = 3;
+ input.pointer = in_params;
+ in_params[0].type = ACPI_TYPE_BUFFER;
+ in_params[0].buffer.length = sizeof(struct GTM_buffer);
+ in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
+ in_params[1].type = ACPI_TYPE_BUFFER;
+ in_params[1].buffer.length = sizeof(struct hd_driveid);
+ in_params[1].buffer.pointer = (u8 *)&master->idbuff;
+ in_params[2].type = ACPI_TYPE_BUFFER;
+ in_params[2].buffer.length = sizeof(struct hd_driveid);
+ in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
+ /* Output buffer: _STM has no output */
+
+ status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
+ &input, NULL);
+
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("Run _STM error: status = 0x%x\n", status);
+ }
+ DEBPRINT("_STM status: %d\n", status);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
+
+/**
+ * ide_acpi_init - initialize the ACPI link for an IDE interface
+ * @hwif: target IDE interface (channel)
+ *
+ * The ACPI spec is not quite clear when the drive identify buffer
+ * should be obtained. Calling IDENTIFY DEVICE during shutdown
+ * is not the best of ideas as the drive might already being put to
+ * sleep. And obviously we can't call it during resume.
+ * So we get the information during startup; but this means that
+ * any changes during run-time will be lost after resume.
+ */
+void ide_acpi_init(ide_hwif_t *hwif)
+{
+ int unit;
+ int err;
+ struct ide_acpi_drive_link *master;
+ struct ide_acpi_drive_link *slave;
+
+ hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
+ if (!hwif->acpidata)
+ return;
+
+ hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
+ if (!hwif->acpidata->obj_handle) {
+ DEBPRINT("no ACPI object for %s found\n", hwif->name);
+ kfree(hwif->acpidata);
+ hwif->acpidata = NULL;
+ return;
+ }
+
+ /*
+ * The ACPI spec mandates that we send information
+ * for both drives, regardless whether they are connected
+ * or not.
+ */
+ hwif->acpidata->master.drive = &hwif->drives[0];
+ hwif->drives[0].acpidata = &hwif->acpidata->master;
+ master = &hwif->acpidata->master;
+
+ hwif->acpidata->slave.drive = &hwif->drives[1];
+ hwif->drives[1].acpidata = &hwif->acpidata->slave;
+ slave = &hwif->acpidata->slave;
+
+
+ /*
+ * Send IDENTIFY for each drive
+ */
+ if (master->drive->present) {
+ err = taskfile_lib_get_identify(master->drive, master->idbuff);
+ if (err) {
+ DEBPRINT("identify device %s failed (%d)\n",
+ master->drive->name, err);
+ }
+ }
+
+ if (slave->drive->present) {
+ err = taskfile_lib_get_identify(slave->drive, slave->idbuff);
+ if (err) {
+ DEBPRINT("identify device %s failed (%d)\n",
+ slave->drive->name, err);
+ }
+ }
+
+ if (ide_noacpionboot) {
+ DEBPRINT("ACPI methods disabled on boot\n");
+ return;
+ }
+
+ /*
+ * ACPI requires us to call _STM on startup
+ */
+ ide_acpi_get_timing(hwif);
+ ide_acpi_push_timing(hwif);
+
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if (drive->present) {
+ /* Execute ACPI startup code */
+ ide_acpi_exec_tfs(drive);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(ide_acpi_init);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 88214943d00..5969cec58dc 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -687,8 +687,15 @@ static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 sta
static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
{
struct request *rq = HWGROUP(drive)->rq;
+ ide_hwif_t *hwif = HWIF(drive);
int stat, err, sense_key;
+ /* We may have bogus DMA interrupts in PIO state here */
+ if (HWIF(drive)->dma_status && hwif->atapi_irq_bogon) {
+ stat = hwif->INB(hwif->dma_status);
+ /* Should we force the bit as well ? */
+ hwif->OUTB(stat, hwif->dma_status);
+ }
/* Check for errors. */
stat = HWIF(drive)->INB(IDE_STATUS_REG);
if (stat_ret)
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index e3a267622bb..d33717c8afd 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -2147,7 +2147,7 @@ static int ide_floppy_probe(ide_drive_t *drive)
printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
goto failed;
}
- if ((floppy = (idefloppy_floppy_t *) kzalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+ if ((floppy = kzalloc(sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
goto failed;
}
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index df7d1504f84..98410ca044c 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -73,3 +73,8 @@ void __init pnpide_init(void)
{
pnp_register_driver(&idepnp_driver);
}
+
+void __exit pnpide_exit(void)
+{
+ pnp_unregister_driver(&idepnp_driver);
+}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index dad9c47ebb6..176bbc850d6 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1000,10 +1000,6 @@ static int ide_init_queue(ide_drive_t *drive)
/* needs drive->queue to be set */
ide_toggle_bounce(drive, 1);
- /* enable led activity for disk drives only */
- if (drive->media == ide_disk && hwif->led_act)
- blk_queue_activity_fn(q, hwif->led_act, drive);
-
return 0;
}
@@ -1388,6 +1384,9 @@ static int hwif_init(ide_hwif_t *hwif)
done:
init_gendisk(hwif);
+
+ ide_acpi_init(hwif);
+
hwif->present = 1; /* success */
return 1;
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index e2f4bb54906..b3bcd1d7315 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -2573,11 +2573,11 @@ static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full,
int pages = tape->pages_per_stage;
char *b_data = NULL;
- if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
+ if ((stage = kmalloc(sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
return NULL;
stage->next = NULL;
- bh = stage->bh = (struct idetape_bh *)kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+ bh = stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
if (bh == NULL)
goto abort;
bh->b_reqnext = NULL;
@@ -2607,7 +2607,7 @@ static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full,
continue;
}
prev_bh = bh;
- if ((bh = (struct idetape_bh *)kmalloc(sizeof(struct idetape_bh), GFP_KERNEL)) == NULL) {
+ if ((bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL)) == NULL) {
free_page((unsigned long) b_data);
goto abort;
}
@@ -4860,7 +4860,7 @@ static int ide_tape_probe(ide_drive_t *drive)
printk(KERN_WARNING "ide-tape: Use drive %s with ide-scsi emulation and osst.\n", drive->name);
printk(KERN_WARNING "ide-tape: OnStream support will be removed soon from ide-tape!\n");
}
- tape = (idetape_tape_t *) kzalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+ tape = kzalloc(sizeof (idetape_tape_t), GFP_KERNEL);
if (tape == NULL) {
printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
goto failed;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 16890769dca..c750f6ce770 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -187,6 +187,12 @@ int noautodma = 1;
EXPORT_SYMBOL(noautodma);
+#ifdef CONFIG_BLK_DEV_IDEACPI
+int ide_noacpi = 0;
+int ide_noacpitfs = 1;
+int ide_noacpionboot = 1;
+#endif
+
/*
* This is declared extern in ide.h, for access by other IDE modules:
*/
@@ -1214,10 +1220,15 @@ EXPORT_SYMBOL(system_bus_clock);
static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
{
ide_drive_t *drive = dev->driver_data;
+ ide_hwif_t *hwif = HWIF(drive);
struct request rq;
struct request_pm_state rqpm;
ide_task_t args;
+ /* Call ACPI _GTM only once */
+ if (!(drive->dn % 2))
+ ide_acpi_get_timing(hwif);
+
memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
@@ -1235,10 +1246,17 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
static int generic_ide_resume(struct device *dev)
{
ide_drive_t *drive = dev->driver_data;
+ ide_hwif_t *hwif = HWIF(drive);
struct request rq;
struct request_pm_state rqpm;
ide_task_t args;
+ /* Call ACPI _STM only once */
+ if (!(drive->dn % 2))
+ ide_acpi_push_timing(hwif);
+
+ ide_acpi_exec_tfs(drive);
+
memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
@@ -1543,6 +1561,24 @@ static int __init ide_setup(char *s)
}
#endif /* CONFIG_BLK_DEV_IDEPCI */
+#ifdef CONFIG_BLK_DEV_IDEACPI
+ if (!strcmp(s, "ide=noacpi")) {
+ //printk(" : Disable IDE ACPI support.\n");
+ ide_noacpi = 1;
+ return 1;
+ }
+ if (!strcmp(s, "ide=acpigtf")) {
+ //printk(" : Enable IDE ACPI _GTF support.\n");
+ ide_noacpitfs = 0;
+ return 1;
+ }
+ if (!strcmp(s, "ide=acpionboot")) {
+ //printk(" : Call IDE ACPI methods on boot.\n");
+ ide_noacpionboot = 0;
+ return 1;
+ }
+#endif /* CONFIG_BLK_DEV_IDEACPI */
+
/*
* Look for drive options: "hdx="
*/
@@ -1781,8 +1817,9 @@ done:
return 1;
}
-extern void pnpide_init(void);
-extern void h8300_ide_init(void);
+extern void __init pnpide_init(void);
+extern void __exit pnpide_exit(void);
+extern void __init h8300_ide_init(void);
/*
* probe_for_hwifs() finds/initializes "known" IDE interfaces
@@ -2087,13 +2124,17 @@ int __init init_module (void)
return ide_init();
}
-void cleanup_module (void)
+void __exit cleanup_module (void)
{
int index;
for (index = 0; index < MAX_HWIFS; ++index)
ide_unregister(index);
+#ifdef CONFIG_BLK_DEV_IDEPNP
+ pnpide_exit();
+#endif
+
#ifdef CONFIG_PROC_FS
proc_ide_destroy();
#endif
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index fef08960aa4..6591ff4753c 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -9,9 +9,10 @@ obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o
obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
+obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.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_IT8213) += it8213.o
obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o
obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o
obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o
obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o
obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o
+obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o
obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o
obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o
obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index f286079d233..d261bfbad22 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -441,7 +441,7 @@ static struct pci_driver driver = {
.probe = aec62xx_init_one,
};
-static int aec62xx_ide_init(void)
+static int __init aec62xx_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index d419e4bb54f..68df77ec502 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -586,11 +586,11 @@ static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const c
{
unsigned long flags;
u8 tmpbyte;
- struct pci_dev *north = pci_find_slot(0, PCI_DEVFN(0,0));
+ struct pci_dev *north = pci_get_slot(dev->bus, PCI_DEVFN(0,0));
pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
- isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+ isa_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
if (!ali_proc) {
@@ -613,8 +613,7 @@ static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const c
* clear bit 7
*/
pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
- local_irq_restore(flags);
- return 0;
+ goto out;
}
/*
@@ -637,10 +636,8 @@ static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const c
* box without a device at 0:0.0. The ALi bridge will be at
* 0:0.0 so if we didn't find one we know what is cooking.
*/
- if (north && north->vendor != PCI_VENDOR_ID_AL) {
- local_irq_restore(flags);
- return 0;
- }
+ if (north && north->vendor != PCI_VENDOR_ID_AL)
+ goto out;
if (m5229_revision < 0xC5 && isa_dev)
{
@@ -661,6 +658,9 @@ static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const c
pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
}
}
+out:
+ pci_dev_put(north);
+ pci_dev_put(isa_dev);
local_irq_restore(flags);
return 0;
}
@@ -907,7 +907,7 @@ static struct pci_driver driver = {
.probe = alim15x3_init_one,
};
-static int ali15x3_ide_init(void)
+static int __init ali15x3_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 753fe0e2145..a4336995a41 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -544,7 +544,7 @@ static struct pci_driver driver = {
.probe = amd74xx_probe,
};
-static int amd74xx_ide_init(void)
+static int __init amd74xx_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index d55b938b1ae..982ac31fa99 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -46,6 +46,8 @@ static atiixp_ide_timing mdma_timing[] = {
static int save_mdma_mode[4];
+static DEFINE_SPINLOCK(atiixp_lock);
+
/**
* atiixp_ratemask - compute rate mask for ATIIXP IDE
* @drive: IDE drive to compute for
@@ -105,7 +107,7 @@ static int atiixp_ide_dma_host_on(ide_drive_t *drive)
unsigned long flags;
u16 tmp16;
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&atiixp_lock, flags);
pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
if (save_mdma_mode[drive->dn])
@@ -114,7 +116,7 @@ static int atiixp_ide_dma_host_on(ide_drive_t *drive)
tmp16 |= (1 << drive->dn);
pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&atiixp_lock, flags);
return __ide_dma_host_on(drive);
}
@@ -125,13 +127,13 @@ static int atiixp_ide_dma_host_off(ide_drive_t *drive)
unsigned long flags;
u16 tmp16;
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&atiixp_lock, flags);
pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
tmp16 &= ~(1 << drive->dn);
pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&atiixp_lock, flags);
return __ide_dma_host_off(drive);
}
@@ -152,7 +154,7 @@ static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
u32 pio_timing_data;
u16 pio_mode_data;
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&atiixp_lock, flags);
pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
pio_mode_data &= ~(0x07 << (drive->dn * 4));
@@ -165,7 +167,7 @@ static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
(pio_timing[pio].command_width << (timing_shift + 4));
pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&atiixp_lock, flags);
}
/**
@@ -189,7 +191,7 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
speed = ide_rate_filter(atiixp_ratemask(drive), xferspeed);
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&atiixp_lock, flags);
save_mdma_mode[drive->dn] = 0;
if (speed >= XFER_UDMA_0) {
@@ -208,7 +210,7 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
}
}
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&atiixp_lock, flags);
if (speed >= XFER_SW_DMA_0)
pio = atiixp_dma_2_pio(speed);
@@ -289,8 +291,12 @@ fast_ata_pio:
static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
{
+ u8 udma_mode = 0;
+ u8 ch = hwif->channel;
+ struct pci_dev *pdev = hwif->pci_dev;
+
if (!hwif->irq)
- hwif->irq = hwif->channel ? 15 : 14;
+ hwif->irq = ch ? 15 : 14;
hwif->autodma = 0;
hwif->tuneproc = &atiixp_tuneproc;
@@ -306,8 +312,12 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
hwif->mwdma_mask = 0x06;
hwif->swdma_mask = 0x04;
- /* FIXME: proper cable detection needed */
- hwif->udma_four = 1;
+ pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
+ if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
+ hwif->udma_four = 1;
+ else
+ hwif->udma_four = 0;
+
hwif->ide_dma_host_on = &atiixp_ide_dma_host_on;
hwif->ide_dma_host_off = &atiixp_ide_dma_host_off;
hwif->ide_dma_check = &atiixp_dma_check;
@@ -318,19 +328,6 @@ 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 */
@@ -341,12 +338,13 @@ static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
.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,
+ .name = "SB600_PATA",
+ .init_hwif = init_hwif_atiixp,
+ .channels = 1,
.autodma = AUTODMA,
- .bootable = ON_BOARD,
- }
+ .enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
+ .bootable = ON_BOARD,
+ },
};
/**
@@ -367,8 +365,7 @@ static struct pci_device_id atiixp_pci_tbl[] = {
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ 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},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
@@ -379,7 +376,7 @@ static struct pci_driver driver = {
.probe = atiixp_init_one,
};
-static int atiixp_ide_init(void)
+static int __init atiixp_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 20c32716bbc..aee947e8fc3 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -793,7 +793,7 @@ static struct pci_driver driver = {
.probe = cmd64x_init_one,
};
-static int cmd64x_ide_init(void)
+static int __init cmd64x_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index 079f7c86726..ba6786aabf3 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -260,7 +260,7 @@ static struct pci_driver driver = {
.probe = cs5520_init_one,
};
-static int cs5520_ide_init(void)
+static int __init cs5520_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index ae405fa3223..9bf5fdfc5b1 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -374,7 +374,7 @@ static struct pci_driver driver = {
.probe = cs5530_init_one,
};
-static int cs5530_ide_init(void)
+static int __init cs5530_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 64330c459bd..9eafcbf444f 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -519,7 +519,7 @@ static struct pci_driver driver = {
.probe = cy82c693_init_one,
};
-static int cy82c693_ide_init(void)
+static int __init cy82c693_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
new file mode 100644
index 00000000000..e2672fc65d3
--- /dev/null
+++ b/drivers/ide/pci/delkin_cb.c
@@ -0,0 +1,140 @@
+/*
+ * linux/drivers/ide/pci/delkin_cb.c
+ *
+ * Created 20 Oct 2004 by Mark Lord
+ *
+ * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
+ *
+ * Modeled after the 16-bit PCMCIA driver: ide-cs.c
+ *
+ * This is slightly peculiar, in that it is a PCI driver,
+ * but is NOT an IDE PCI driver -- the IDE layer does not directly
+ * support hot insertion/removal of PCI interfaces, so this driver
+ * is unable to use the IDE PCI interfaces. Instead, it uses the
+ * same interfaces as the ide-cs (PCMCIA) driver uses.
+ * On the plus side, the driver is also smaller/simpler this way.
+ *
+ * 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/autoconf.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/*
+ * No chip documentation has yet been found,
+ * so these configuration values were pulled from
+ * a running Win98 system using "debug".
+ * This gives around 3MByte/second read performance,
+ * which is about 2/3 of what the chip is capable of.
+ *
+ * There is also a 4KByte mmio region on the card,
+ * but its purpose has yet to be reverse-engineered.
+ */
+static const u8 setup[] = {
+ 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00,
+ 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
+};
+
+static int __devinit
+delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+ unsigned long base;
+ hw_regs_t hw;
+ ide_hwif_t *hwif = NULL;
+ ide_drive_t *drive;
+ int i, rc;
+
+ rc = pci_enable_device(dev);
+ if (rc) {
+ printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc);
+ return rc;
+ }
+ rc = pci_request_regions(dev, "delkin_cb");
+ if (rc) {
+ printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc);
+ pci_disable_device(dev);
+ return rc;
+ }
+ base = pci_resource_start(dev, 0);
+ outb(0x02, base + 0x1e); /* set nIEN to block interrupts */
+ inb(base + 0x17); /* read status to clear interrupts */
+ for (i = 0; i < sizeof(setup); ++i) {
+ if (setup[i])
+ outb(setup[i], base + i);
+ }
+ pci_release_regions(dev); /* IDE layer handles regions itself */
+
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
+ hw.irq = dev->irq;
+ hw.chipset = ide_pci; /* this enables IRQ sharing */
+
+ rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave);
+ if (rc < 0) {
+ printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
+ pci_disable_device(dev);
+ return -ENODEV;
+ }
+ pci_set_drvdata(dev, hwif);
+ hwif->pci_dev = dev;
+ drive = &hwif->drives[0];
+ if (drive->present) {
+ drive->io_32bit = 1;
+ drive->unmask = 1;
+ }
+ return 0;
+}
+
+static void
+delkin_cb_remove (struct pci_dev *dev)
+{
+ ide_hwif_t *hwif = pci_get_drvdata(dev);
+
+ if (hwif)
+ ide_unregister(hwif->index);
+ pci_disable_device(dev);
+}
+
+static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = {
+ { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "Delkin-ASKA-Workbit Cardbus IDE",
+ .id_table = delkin_cb_pci_tbl,
+ .probe = delkin_cb_probe,
+ .remove = delkin_cb_remove,
+};
+
+static int
+delkin_cb_init (void)
+{
+ return pci_module_init(&driver);
+}
+
+static void
+delkin_cb_exit (void)
+{
+ pci_unregister_driver(&driver);
+}
+
+module_init(delkin_cb_init);
+module_exit(delkin_cb_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 9f306880491..b408c6c517e 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -185,36 +185,6 @@ static ide_pci_device_t generic_chipsets[] __devinitdata = {
.channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
- },{ /* 15 */
- .name = "JMB361",
- .init_hwif = init_hwif_generic,
- .channels = 2,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- },{ /* 16 */
- .name = "JMB363",
- .init_hwif = init_hwif_generic,
- .channels = 2,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- },{ /* 17 */
- .name = "JMB365",
- .init_hwif = init_hwif_generic,
- .channels = 2,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- },{ /* 18 */
- .name = "JMB366",
- .init_hwif = init_hwif_generic,
- .channels = 2,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- },{ /* 19 */
- .name = "JMB368",
- .init_hwif = init_hwif_generic,
- .channels = 2,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
}
};
@@ -281,11 +251,6 @@ static struct pci_device_id generic_pci_tbl[] = {
{ PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
{ PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
{ PCI_VENDOR_ID_NETCELL,PCI_DEVICE_ID_REVOLUTION, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19},
/* Must come last. If you add entries adjust this table appropriately and the init_one code */
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0},
{ 0, },
@@ -298,7 +263,7 @@ static struct pci_driver driver = {
.probe = generic_init_one,
};
-static int generic_ide_init(void)
+static int __init generic_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index b46cb042290..ce7b08f08a0 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -265,7 +265,7 @@ static struct pci_driver driver = {
.probe = hpt34x_init_one,
};
-static int hpt34x_ide_init(void)
+static int __init hpt34x_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index e993a51f250..05be8fadda7 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1,9 +1,10 @@
/*
- * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
+ * linux/drivers/ide/pci/hpt366.c Version 1.01 Dec 23, 2006
*
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc
+ * Portions Copyright (C) 2005-2006 MontaVista Software, Inc.
*
* Thanks to HighPoint Technologies for their assistance, and hardware.
* Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
@@ -11,9 +12,11 @@
* development and support.
*
*
- * Highpoint have their own driver (source except for the raid part)
- * available from http://www.highpoint-tech.com/hpt3xx-opensource-v131.tgz
- * This may be useful to anyone wanting to work on the mainstream hpt IDE.
+ * HighPoint has its own drivers (open source except for the RAID part)
+ * available from http://www.highpoint-tech.com/BIOS%20+%20Driver/.
+ * This may be useful to anyone wanting to work on this driver, however do not
+ * trust them too much since the code tends to become less and less meaningful
+ * as the time passes... :-/
*
* Note that final HPT370 support was done by force extraction of GPL.
*
@@ -52,9 +55,65 @@
* keeping me sane.
* Alan Cox <alan@redhat.com>
*
+ * - fix the clock turnaround code: it was writing to the wrong ports when
+ * called for the secondary channel, caching the current clock mode per-
+ * channel caused the cached register value to get out of sync with the
+ * actual one, the channels weren't serialized, the turnaround shouldn't
+ * be done on 66 MHz PCI bus
+ * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used
+ * does not allow for this speed anyway
+ * - avoid touching disabled channels (e.g. HPT371/N are single channel chips,
+ * their primary channel is kind of virtual, it isn't tied to any pins)
+ * - fix/remove bad/unused timing tables and use one set of tables for the whole
+ * HPT37x chip family; save space by introducing the separate transfer mode
+ * table in which the mode lookup is done
+ * - use f_CNT value saved by the HighPoint BIOS as reading it directly gives
+ * the wrong PCI frequency since DPLL has already been calibrated by BIOS
+ * - fix the hotswap code: it caused RESET- to glitch when tristating the bus,
+ * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
+ * - pass to init_chipset() handlers a copy of the IDE PCI device structure as
+ * they tamper with its fields
+ * - pass to the init_setup handlers a copy of the ide_pci_device_t structure
+ * since they may tamper with its fields
+ * - prefix the driver startup messages with the real chip name
+ * - claim the extra 240 bytes of I/O space for all chips
+ * - optimize the rate masking/filtering and the drive list lookup code
+ * - use pci_get_slot() to get to the function 1 of HPT36x/374
+ * - cache offset of the channel's misc. control registers (MCRs) being used
+ * throughout the driver
+ * - only touch the relevant MCR when detecting the cable type on HPT374's
+ * function 1
+ * - rename all the register related variables consistently
+ * - move all the interrupt twiddling code from the speedproc handlers into
+ * init_hwif_hpt366(), also grouping all the DMA related code together there
+ * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
+ * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
+ * when setting an UltraDMA mode
+ * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
+ * the best possible one
+ * - clean up DMA timeout handling for HPT370
+ * - switch to using the enumeration type to differ between the numerous chip
+ * variants, matching PCI device/revision ID with the chip type early, at the
+ * init_setup stage
+ * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies,
+ * stop duplicating it for each channel by storing the pointer in the pci_dev
+ * structure: first, at the init_setup stage, point it to a static "template"
+ * with only the chip type and its specific base DPLL frequency, the highest
+ * supported DMA mode, and the chip settings table pointer filled, then, at
+ * the init_chipset stage, allocate per-chip instance and fill it with the
+ * rest of the necessary information
+ * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
+ * switch to calculating PCI clock frequency based on the chip's base DPLL
+ * frequency
+ * - switch to using the DPLL clock and enable UltraATA/133 mode by default on
+ * anything newer than HPT370/A
+ * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(),
+ * also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips;
+ * unify HPT36x/37x timing setup code and the speedproc handlers by joining
+ * the register setting lists into the table indexed by the clock selected
+ * Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
*/
-
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -76,8 +135,8 @@
/* various tuning parameters */
#define HPT_RESET_STATE_ENGINE
-#undef HPT_DELAY_INTERRUPT
-#undef HPT_SERIALIZE_IO
+#undef HPT_DELAY_INTERRUPT
+#define HPT_SERIALIZE_IO 0
static const char *quirk_drives[] = {
"QUANTUM FIREBALLlct08 08",
@@ -141,387 +200,324 @@ static const char *bad_ata33[] = {
NULL
};
-struct chipset_bus_clock_list_entry {
- u8 xfer_speed;
- unsigned int chipset_settings;
+static u8 xfer_speeds[] = {
+ XFER_UDMA_6,
+ XFER_UDMA_5,
+ XFER_UDMA_4,
+ XFER_UDMA_3,
+ XFER_UDMA_2,
+ XFER_UDMA_1,
+ XFER_UDMA_0,
+
+ XFER_MW_DMA_2,
+ XFER_MW_DMA_1,
+ XFER_MW_DMA_0,
+
+ XFER_PIO_4,
+ XFER_PIO_3,
+ XFER_PIO_2,
+ XFER_PIO_1,
+ XFER_PIO_0
};
-/* key for bus clock timings
- * bit
- * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
- * register access.
- * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
- * register access.
- * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- * during task file register access.
- * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- * xfer.
- * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
- * register access.
- * 28 UDMA enable
- * 29 DMA enable
- * 30 PIO_MST enable. if set, the chip is in bus master mode during
- * PIO.
- * 31 FIFO enable.
+/* Key for bus clock timings
+ * 36x 37x
+ * bits bits
+ * 0:3 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 4:7 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 8:11 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 12:15 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 16:18 18:20 udma_cycle_time. Clock cycles for UDMA xfer.
+ * - 21 CLK frequency: 0=ATA clock, 1=dual ATA clock.
+ * 19:21 22:24 pre_high_time. Time to initialize the 1st cycle for PIO and
+ * MW DMA xfer.
+ * 22:24 25:27 cmd_pre_high_time. Time to initialize the 1st PIO cycle for
+ * task file register access.
+ * 28 28 UDMA enable.
+ * 29 29 DMA enable.
+ * 30 30 PIO MST enable. If set, the chip is in bus master mode during
+ * PIO xfer.
+ * 31 31 FIFO enable.
*/
-static struct chipset_bus_clock_list_entry forty_base_hpt366[] = {
- { XFER_UDMA_4, 0x900fd943 },
- { XFER_UDMA_3, 0x900ad943 },
- { XFER_UDMA_2, 0x900bd943 },
- { XFER_UDMA_1, 0x9008d943 },
- { XFER_UDMA_0, 0x9008d943 },
-
- { XFER_MW_DMA_2, 0xa008d943 },
- { XFER_MW_DMA_1, 0xa010d955 },
- { XFER_MW_DMA_0, 0xa010d9fc },
-
- { XFER_PIO_4, 0xc008d963 },
- { XFER_PIO_3, 0xc010d974 },
- { XFER_PIO_2, 0xc010d997 },
- { XFER_PIO_1, 0xc010d9c7 },
- { XFER_PIO_0, 0xc018d9d9 },
- { 0, 0x0120d9d9 }
+
+static u32 forty_base_hpt36x[] = {
+ /* XFER_UDMA_6 */ 0x900fd943,
+ /* XFER_UDMA_5 */ 0x900fd943,
+ /* XFER_UDMA_4 */ 0x900fd943,
+ /* XFER_UDMA_3 */ 0x900ad943,
+ /* XFER_UDMA_2 */ 0x900bd943,
+ /* XFER_UDMA_1 */ 0x9008d943,
+ /* XFER_UDMA_0 */ 0x9008d943,
+
+ /* XFER_MW_DMA_2 */ 0xa008d943,
+ /* XFER_MW_DMA_1 */ 0xa010d955,
+ /* XFER_MW_DMA_0 */ 0xa010d9fc,
+
+ /* XFER_PIO_4 */ 0xc008d963,
+ /* XFER_PIO_3 */ 0xc010d974,
+ /* XFER_PIO_2 */ 0xc010d997,
+ /* XFER_PIO_1 */ 0xc010d9c7,
+ /* XFER_PIO_0 */ 0xc018d9d9
};
-static struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = {
- { XFER_UDMA_4, 0x90c9a731 },
- { XFER_UDMA_3, 0x90cfa731 },
- { XFER_UDMA_2, 0x90caa731 },
- { XFER_UDMA_1, 0x90cba731 },
- { XFER_UDMA_0, 0x90c8a731 },
-
- { XFER_MW_DMA_2, 0xa0c8a731 },
- { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */
- { XFER_MW_DMA_0, 0xa0c8a797 },
-
- { XFER_PIO_4, 0xc0c8a731 },
- { XFER_PIO_3, 0xc0c8a742 },
- { XFER_PIO_2, 0xc0d0a753 },
- { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */
- { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */
- { 0, 0x0120a7a7 }
+static u32 thirty_three_base_hpt36x[] = {
+ /* XFER_UDMA_6 */ 0x90c9a731,
+ /* XFER_UDMA_5 */ 0x90c9a731,
+ /* XFER_UDMA_4 */ 0x90c9a731,
+ /* XFER_UDMA_3 */ 0x90cfa731,
+ /* XFER_UDMA_2 */ 0x90caa731,
+ /* XFER_UDMA_1 */ 0x90cba731,
+ /* XFER_UDMA_0 */ 0x90c8a731,
+
+ /* XFER_MW_DMA_2 */ 0xa0c8a731,
+ /* XFER_MW_DMA_1 */ 0xa0c8a732, /* 0xa0c8a733 */
+ /* XFER_MW_DMA_0 */ 0xa0c8a797,
+
+ /* XFER_PIO_4 */ 0xc0c8a731,
+ /* XFER_PIO_3 */ 0xc0c8a742,
+ /* XFER_PIO_2 */ 0xc0d0a753,
+ /* XFER_PIO_1 */ 0xc0d0a7a3, /* 0xc0d0a793 */
+ /* XFER_PIO_0 */ 0xc0d0a7aa /* 0xc0d0a7a7 */
};
-static struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = {
- { XFER_UDMA_4, 0x90c98521 },
- { XFER_UDMA_3, 0x90cf8521 },
- { XFER_UDMA_2, 0x90cf8521 },
- { XFER_UDMA_1, 0x90cb8521 },
- { XFER_UDMA_0, 0x90cb8521 },
-
- { XFER_MW_DMA_2, 0xa0ca8521 },
- { XFER_MW_DMA_1, 0xa0ca8532 },
- { XFER_MW_DMA_0, 0xa0ca8575 },
-
- { XFER_PIO_4, 0xc0ca8521 },
- { XFER_PIO_3, 0xc0ca8532 },
- { XFER_PIO_2, 0xc0ca8542 },
- { XFER_PIO_1, 0xc0d08572 },
- { XFER_PIO_0, 0xc0d08585 },
- { 0, 0x01208585 }
+static u32 twenty_five_base_hpt36x[] = {
+ /* XFER_UDMA_6 */ 0x90c98521,
+ /* XFER_UDMA_5 */ 0x90c98521,
+ /* XFER_UDMA_4 */ 0x90c98521,
+ /* XFER_UDMA_3 */ 0x90cf8521,
+ /* XFER_UDMA_2 */ 0x90cf8521,
+ /* XFER_UDMA_1 */ 0x90cb8521,
+ /* XFER_UDMA_0 */ 0x90cb8521,
+
+ /* XFER_MW_DMA_2 */ 0xa0ca8521,
+ /* XFER_MW_DMA_1 */ 0xa0ca8532,
+ /* XFER_MW_DMA_0 */ 0xa0ca8575,
+
+ /* XFER_PIO_4 */ 0xc0ca8521,
+ /* XFER_PIO_3 */ 0xc0ca8532,
+ /* XFER_PIO_2 */ 0xc0ca8542,
+ /* XFER_PIO_1 */ 0xc0d08572,
+ /* XFER_PIO_0 */ 0xc0d08585
};
-/* from highpoint documentation. these are old values */
-static struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-/* { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, */
- { XFER_UDMA_5, 0x16454e31 },
- { XFER_UDMA_4, 0x16454e31 },
- { XFER_UDMA_3, 0x166d4e31 },
- { XFER_UDMA_2, 0x16494e31 },
- { XFER_UDMA_1, 0x164d4e31 },
- { XFER_UDMA_0, 0x16514e31 },
-
- { XFER_MW_DMA_2, 0x26514e21 },
- { XFER_MW_DMA_1, 0x26514e33 },
- { XFER_MW_DMA_0, 0x26514e97 },
-
- { XFER_PIO_4, 0x06514e21 },
- { XFER_PIO_3, 0x06514e22 },
- { XFER_PIO_2, 0x06514e33 },
- { XFER_PIO_1, 0x06914e43 },
- { XFER_PIO_0, 0x06914e57 },
- { 0, 0x06514e57 }
+static u32 thirty_three_base_hpt37x[] = {
+ /* XFER_UDMA_6 */ 0x12446231, /* 0x12646231 ?? */
+ /* XFER_UDMA_5 */ 0x12446231,
+ /* XFER_UDMA_4 */ 0x12446231,
+ /* XFER_UDMA_3 */ 0x126c6231,
+ /* XFER_UDMA_2 */ 0x12486231,
+ /* XFER_UDMA_1 */ 0x124c6233,
+ /* XFER_UDMA_0 */ 0x12506297,
+
+ /* XFER_MW_DMA_2 */ 0x22406c31,
+ /* XFER_MW_DMA_1 */ 0x22406c33,
+ /* XFER_MW_DMA_0 */ 0x22406c97,
+
+ /* XFER_PIO_4 */ 0x06414e31,
+ /* XFER_PIO_3 */ 0x06414e42,
+ /* XFER_PIO_2 */ 0x06414e53,
+ /* XFER_PIO_1 */ 0x06814e93,
+ /* XFER_PIO_0 */ 0x06814ea7
};
-static struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
- { XFER_UDMA_5, 0x14846231 },
- { XFER_UDMA_4, 0x14886231 },
- { XFER_UDMA_3, 0x148c6231 },
- { XFER_UDMA_2, 0x148c6231 },
- { XFER_UDMA_1, 0x14906231 },
- { XFER_UDMA_0, 0x14986231 },
-
- { XFER_MW_DMA_2, 0x26514e21 },
- { XFER_MW_DMA_1, 0x26514e33 },
- { XFER_MW_DMA_0, 0x26514e97 },
-
- { XFER_PIO_4, 0x06514e21 },
- { XFER_PIO_3, 0x06514e22 },
- { XFER_PIO_2, 0x06514e33 },
- { XFER_PIO_1, 0x06914e43 },
- { XFER_PIO_0, 0x06914e57 },
- { 0, 0x06514e57 }
+static u32 fifty_base_hpt37x[] = {
+ /* XFER_UDMA_6 */ 0x12848242,
+ /* XFER_UDMA_5 */ 0x12848242,
+ /* XFER_UDMA_4 */ 0x12ac8242,
+ /* XFER_UDMA_3 */ 0x128c8242,
+ /* XFER_UDMA_2 */ 0x120c8242,
+ /* XFER_UDMA_1 */ 0x12148254,
+ /* XFER_UDMA_0 */ 0x121882ea,
+
+ /* XFER_MW_DMA_2 */ 0x22808242,
+ /* XFER_MW_DMA_1 */ 0x22808254,
+ /* XFER_MW_DMA_0 */ 0x228082ea,
+
+ /* XFER_PIO_4 */ 0x0a81f442,
+ /* XFER_PIO_3 */ 0x0a81f443,
+ /* XFER_PIO_2 */ 0x0a81f454,
+ /* XFER_PIO_1 */ 0x0ac1f465,
+ /* XFER_PIO_0 */ 0x0ac1f48a
};
-/* these are the current (4 sep 2001) timings from highpoint */
-static struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = {
- { XFER_UDMA_5, 0x12446231 },
- { XFER_UDMA_4, 0x12446231 },
- { XFER_UDMA_3, 0x126c6231 },
- { XFER_UDMA_2, 0x12486231 },
- { XFER_UDMA_1, 0x124c6233 },
- { XFER_UDMA_0, 0x12506297 },
-
- { XFER_MW_DMA_2, 0x22406c31 },
- { XFER_MW_DMA_1, 0x22406c33 },
- { XFER_MW_DMA_0, 0x22406c97 },
-
- { XFER_PIO_4, 0x06414e31 },
- { XFER_PIO_3, 0x06414e42 },
- { XFER_PIO_2, 0x06414e53 },
- { XFER_PIO_1, 0x06814e93 },
- { XFER_PIO_0, 0x06814ea7 },
- { 0, 0x06814ea7 }
+static u32 sixty_six_base_hpt37x[] = {
+ /* XFER_UDMA_6 */ 0x1c869c62,
+ /* XFER_UDMA_5 */ 0x1cae9c62, /* 0x1c8a9c62 */
+ /* XFER_UDMA_4 */ 0x1c8a9c62,
+ /* XFER_UDMA_3 */ 0x1c8e9c62,
+ /* XFER_UDMA_2 */ 0x1c929c62,
+ /* XFER_UDMA_1 */ 0x1c9a9c62,
+ /* XFER_UDMA_0 */ 0x1c829c62,
+
+ /* XFER_MW_DMA_2 */ 0x2c829c62,
+ /* XFER_MW_DMA_1 */ 0x2c829c66,
+ /* XFER_MW_DMA_0 */ 0x2c829d2e,
+
+ /* XFER_PIO_4 */ 0x0c829c62,
+ /* XFER_PIO_3 */ 0x0c829c84,
+ /* XFER_PIO_2 */ 0x0c829ca6,
+ /* XFER_PIO_1 */ 0x0d029d26,
+ /* XFER_PIO_0 */ 0x0d029d5e
};
-/* 2x 33MHz timings */
-static struct chipset_bus_clock_list_entry sixty_six_base_hpt370a[] = {
- { XFER_UDMA_5, 0x1488e673 },
- { XFER_UDMA_4, 0x1488e673 },
- { XFER_UDMA_3, 0x1498e673 },
- { XFER_UDMA_2, 0x1490e673 },
- { XFER_UDMA_1, 0x1498e677 },
- { XFER_UDMA_0, 0x14a0e73f },
-
- { XFER_MW_DMA_2, 0x2480fa73 },
- { XFER_MW_DMA_1, 0x2480fa77 },
- { XFER_MW_DMA_0, 0x2480fb3f },
-
- { XFER_PIO_4, 0x0c82be73 },
- { XFER_PIO_3, 0x0c82be95 },
- { XFER_PIO_2, 0x0c82beb7 },
- { XFER_PIO_1, 0x0d02bf37 },
- { XFER_PIO_0, 0x0d02bf5f },
- { 0, 0x0d02bf5f }
+#define HPT366_DEBUG_DRIVE_INFO 0
+#define HPT374_ALLOW_ATA133_6 1
+#define HPT371_ALLOW_ATA133_6 1
+#define HPT302_ALLOW_ATA133_6 1
+#define HPT372_ALLOW_ATA133_6 1
+#define HPT370_ALLOW_ATA100_5 0
+#define HPT366_ALLOW_ATA66_4 1
+#define HPT366_ALLOW_ATA66_3 1
+#define HPT366_MAX_DEVS 8
+
+/* Supported ATA clock frequencies */
+enum ata_clock {
+ ATA_CLOCK_25MHZ,
+ ATA_CLOCK_33MHZ,
+ ATA_CLOCK_40MHZ,
+ ATA_CLOCK_50MHZ,
+ ATA_CLOCK_66MHZ,
+ NUM_ATA_CLOCKS
};
-static struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = {
- { XFER_UDMA_5, 0x12848242 },
- { XFER_UDMA_4, 0x12ac8242 },
- { XFER_UDMA_3, 0x128c8242 },
- { XFER_UDMA_2, 0x120c8242 },
- { XFER_UDMA_1, 0x12148254 },
- { XFER_UDMA_0, 0x121882ea },
-
- { XFER_MW_DMA_2, 0x22808242 },
- { XFER_MW_DMA_1, 0x22808254 },
- { XFER_MW_DMA_0, 0x228082ea },
-
- { XFER_PIO_4, 0x0a81f442 },
- { XFER_PIO_3, 0x0a81f443 },
- { XFER_PIO_2, 0x0a81f454 },
- { XFER_PIO_1, 0x0ac1f465 },
- { XFER_PIO_0, 0x0ac1f48a },
- { 0, 0x0ac1f48a }
+/*
+ * Hold all the HighPoint chip information in one place.
+ */
+
+struct hpt_info {
+ u8 chip_type; /* Chip type */
+ u8 max_mode; /* Speeds allowed */
+ u8 dpll_clk; /* DPLL clock in MHz */
+ u8 pci_clk; /* PCI clock in MHz */
+ u32 **settings; /* Chipset settings table */
};
-static struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
- { XFER_UDMA_6, 0x1c81dc62 },
- { XFER_UDMA_5, 0x1c6ddc62 },
- { XFER_UDMA_4, 0x1c8ddc62 },
- { XFER_UDMA_3, 0x1c8edc62 }, /* checkme */
- { XFER_UDMA_2, 0x1c91dc62 },
- { XFER_UDMA_1, 0x1c9adc62 }, /* checkme */
- { XFER_UDMA_0, 0x1c82dc62 }, /* checkme */
-
- { XFER_MW_DMA_2, 0x2c829262 },
- { XFER_MW_DMA_1, 0x2c829266 }, /* checkme */
- { XFER_MW_DMA_0, 0x2c82922e }, /* checkme */
-
- { XFER_PIO_4, 0x0c829c62 },
- { XFER_PIO_3, 0x0c829c84 },
- { XFER_PIO_2, 0x0c829ca6 },
- { XFER_PIO_1, 0x0d029d26 },
- { XFER_PIO_0, 0x0d029d5e },
- { 0, 0x0d029d5e }
+/* Supported HighPoint chips */
+enum {
+ HPT36x,
+ HPT370,
+ HPT370A,
+ HPT374,
+ HPT372,
+ HPT372A,
+ HPT302,
+ HPT371,
+ HPT372N,
+ HPT302N,
+ HPT371N
};
-static struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
- { XFER_UDMA_5, 0x12848242 },
- { XFER_UDMA_4, 0x12ac8242 },
- { XFER_UDMA_3, 0x128c8242 },
- { XFER_UDMA_2, 0x120c8242 },
- { XFER_UDMA_1, 0x12148254 },
- { XFER_UDMA_0, 0x121882ea },
-
- { XFER_MW_DMA_2, 0x22808242 },
- { XFER_MW_DMA_1, 0x22808254 },
- { XFER_MW_DMA_0, 0x228082ea },
-
- { XFER_PIO_4, 0x0a81f442 },
- { XFER_PIO_3, 0x0a81f443 },
- { XFER_PIO_2, 0x0a81f454 },
- { XFER_PIO_1, 0x0ac1f465 },
- { XFER_PIO_0, 0x0ac1f48a },
- { 0, 0x0a81f443 }
+static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
+ twenty_five_base_hpt36x,
+ thirty_three_base_hpt36x,
+ forty_base_hpt36x,
+ NULL,
+ NULL
};
-static struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
- { XFER_UDMA_6, 0x1c869c62 },
- { XFER_UDMA_5, 0x1cae9c62 },
- { XFER_UDMA_4, 0x1c8a9c62 },
- { XFER_UDMA_3, 0x1c8e9c62 },
- { XFER_UDMA_2, 0x1c929c62 },
- { XFER_UDMA_1, 0x1c9a9c62 },
- { XFER_UDMA_0, 0x1c829c62 },
-
- { XFER_MW_DMA_2, 0x2c829c62 },
- { XFER_MW_DMA_1, 0x2c829c66 },
- { XFER_MW_DMA_0, 0x2c829d2e },
-
- { XFER_PIO_4, 0x0c829c62 },
- { XFER_PIO_3, 0x0c829c84 },
- { XFER_PIO_2, 0x0c829ca6 },
- { XFER_PIO_1, 0x0d029d26 },
- { XFER_PIO_0, 0x0d029d5e },
- { 0, 0x0d029d26 }
+static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
+ NULL,
+ thirty_three_base_hpt37x,
+ NULL,
+ fifty_base_hpt37x,
+ sixty_six_base_hpt37x
};
-static struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
- { XFER_UDMA_6, 0x12808242 },
- { XFER_UDMA_5, 0x12848242 },
- { XFER_UDMA_4, 0x12ac8242 },
- { XFER_UDMA_3, 0x128c8242 },
- { XFER_UDMA_2, 0x120c8242 },
- { XFER_UDMA_1, 0x12148254 },
- { XFER_UDMA_0, 0x121882ea },
-
- { XFER_MW_DMA_2, 0x22808242 },
- { XFER_MW_DMA_1, 0x22808254 },
- { XFER_MW_DMA_0, 0x228082ea },
-
- { XFER_PIO_4, 0x0a81f442 },
- { XFER_PIO_3, 0x0a81f443 },
- { XFER_PIO_2, 0x0a81f454 },
- { XFER_PIO_1, 0x0ac1f465 },
- { XFER_PIO_0, 0x0ac1f48a },
- { 0, 0x06814e93 }
+static struct hpt_info hpt36x __devinitdata = {
+ .chip_type = HPT36x,
+ .max_mode = (HPT366_ALLOW_ATA66_4 || HPT366_ALLOW_ATA66_3) ? 2 : 1,
+ .dpll_clk = 0, /* no DPLL */
+ .settings = hpt36x_settings
};
-/* FIXME: 50MHz timings for HPT374 */
-
-#if 0
-static struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
- { XFER_UDMA_6, 0x12406231 }, /* checkme */
- { XFER_UDMA_5, 0x12446231 }, /* 0x14846231 */
- { XFER_UDMA_4, 0x16814ea7 }, /* 0x14886231 */
- { XFER_UDMA_3, 0x16814ea7 }, /* 0x148c6231 */
- { XFER_UDMA_2, 0x16814ea7 }, /* 0x148c6231 */
- { XFER_UDMA_1, 0x16814ea7 }, /* 0x14906231 */
- { XFER_UDMA_0, 0x16814ea7 }, /* 0x14986231 */
- { XFER_MW_DMA_2, 0x16814ea7 }, /* 0x26514e21 */
- { XFER_MW_DMA_1, 0x16814ea7 }, /* 0x26514e97 */
- { XFER_MW_DMA_0, 0x16814ea7 }, /* 0x26514e97 */
- { XFER_PIO_4, 0x06814ea7 }, /* 0x06514e21 */
- { XFER_PIO_3, 0x06814ea7 }, /* 0x06514e22 */
- { XFER_PIO_2, 0x06814ea7 }, /* 0x06514e33 */
- { XFER_PIO_1, 0x06814ea7 }, /* 0x06914e43 */
- { XFER_PIO_0, 0x06814ea7 }, /* 0x06914e57 */
- { 0, 0x06814ea7 }
+static struct hpt_info hpt370 __devinitdata = {
+ .chip_type = HPT370,
+ .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2,
+ .dpll_clk = 48,
+ .settings = hpt37x_settings
};
-#endif
-#define HPT366_DEBUG_DRIVE_INFO 0
-#define HPT374_ALLOW_ATA133_6 0
-#define HPT371_ALLOW_ATA133_6 0
-#define HPT302_ALLOW_ATA133_6 0
-#define HPT372_ALLOW_ATA133_6 1
-#define HPT370_ALLOW_ATA100_5 1
-#define HPT366_ALLOW_ATA66_4 1
-#define HPT366_ALLOW_ATA66_3 1
-#define HPT366_MAX_DEVS 8
+static struct hpt_info hpt370a __devinitdata = {
+ .chip_type = HPT370A,
+ .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2,
+ .dpll_clk = 48,
+ .settings = hpt37x_settings
+};
-#define F_LOW_PCI_33 0x23
-#define F_LOW_PCI_40 0x29
-#define F_LOW_PCI_50 0x2d
-#define F_LOW_PCI_66 0x42
+static struct hpt_info hpt374 __devinitdata = {
+ .chip_type = HPT374,
+ .max_mode = HPT374_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 48,
+ .settings = hpt37x_settings
+};
-/*
- * Hold all the highpoint quirks and revision information in one
- * place.
- */
+static struct hpt_info hpt372 __devinitdata = {
+ .chip_type = HPT372,
+ .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 55,
+ .settings = hpt37x_settings
+};
-struct hpt_info
-{
- u8 max_mode; /* Speeds allowed */
- int revision; /* Chipset revision */
- int flags; /* Chipset properties */
-#define PLL_MODE 1
-#define IS_372N 2
- /* Speed table */
- struct chipset_bus_clock_list_entry *speed;
+static struct hpt_info hpt372a __devinitdata = {
+ .chip_type = HPT372A,
+ .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 66,
+ .settings = hpt37x_settings
};
-/*
- * This wants fixing so that we do everything not by classrev
- * (which breaks on the newest chips) but by creating an
- * enumeration of chip variants and using that
- */
+static struct hpt_info hpt302 __devinitdata = {
+ .chip_type = HPT302,
+ .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 66,
+ .settings = hpt37x_settings
+};
-static __devinit u32 hpt_revision (struct pci_dev *dev)
+static struct hpt_info hpt371 __devinitdata = {
+ .chip_type = HPT371,
+ .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 66,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt372n __devinitdata = {
+ .chip_type = HPT372N,
+ .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 77,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt302n __devinitdata = {
+ .chip_type = HPT302N,
+ .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 77,
+};
+
+static struct hpt_info hpt371n __devinitdata = {
+ .chip_type = HPT371N,
+ .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 77,
+ .settings = hpt37x_settings
+};
+
+static int check_in_drive_list(ide_drive_t *drive, const char **list)
{
- u32 class_rev;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
-
- switch(dev->device) {
- /* Remap new 372N onto 372 */
- case PCI_DEVICE_ID_TTI_HPT372N:
- class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
- case PCI_DEVICE_ID_TTI_HPT374:
- class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
- case PCI_DEVICE_ID_TTI_HPT371:
- class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
- case PCI_DEVICE_ID_TTI_HPT302:
- class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
- case PCI_DEVICE_ID_TTI_HPT372:
- class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
- default:
- break;
- }
- return class_rev;
-}
+ struct hd_driveid *id = drive->id;
-static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+ while (*list)
+ if (!strcmp(*list++,id->model))
+ return 1;
+ return 0;
+}
-static u8 hpt3xx_ratemask (ide_drive_t *drive)
+static u8 hpt3xx_ratemask(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 mode = 0;
-
- /* FIXME: TODO - move this to set info->mode once at boot */
-
- if (info->revision >= 8) { /* HPT374 */
- mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 7) { /* HPT371 */
- mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 6) { /* HPT302 */
- mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 5) { /* HPT372 */
- mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 4) { /* HPT370A */
- mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
- } else if (info->revision >= 3) { /* HPT370 */
- mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
- mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
- } else { /* HPT366 and HPT368 */
- mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
- }
+ struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev);
+ u8 mode = info->max_mode;
+
if (!eighty_ninty_three(drive) && mode)
mode = min(mode, (u8)1);
return mode;
@@ -532,301 +528,228 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive)
* either PIO or UDMA modes 0,4,5
*/
-static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
+ struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev);
+ u8 chip_type = info->chip_type;
u8 mode = hpt3xx_ratemask(drive);
if (drive->media != ide_disk)
return min(speed, (u8)XFER_PIO_4);
- switch(mode) {
+ switch (mode) {
case 0x04:
- speed = min(speed, (u8)XFER_UDMA_6);
+ speed = min_t(u8, speed, XFER_UDMA_6);
break;
case 0x03:
- speed = min(speed, (u8)XFER_UDMA_5);
- if (info->revision >= 5)
+ speed = min_t(u8, speed, XFER_UDMA_5);
+ if (chip_type >= HPT374)
break;
- if (check_in_drive_lists(drive, bad_ata100_5))
- speed = min(speed, (u8)XFER_UDMA_4);
- break;
+ if (!check_in_drive_list(drive, bad_ata100_5))
+ goto check_bad_ata33;
+ /* fall thru */
case 0x02:
- speed = min(speed, (u8)XFER_UDMA_4);
- /*
- * CHECK ME, Does this need to be set to 5 ??
- */
- if (info->revision >= 3)
- break;
- if ((check_in_drive_lists(drive, bad_ata66_4)) ||
- (!(HPT366_ALLOW_ATA66_4)))
- speed = min(speed, (u8)XFER_UDMA_3);
- if ((check_in_drive_lists(drive, bad_ata66_3)) ||
- (!(HPT366_ALLOW_ATA66_3)))
- speed = min(speed, (u8)XFER_UDMA_2);
- break;
+ speed = min_t(u8, speed, XFER_UDMA_4);
+
+ /*
+ * CHECK ME, Does this need to be changed to HPT374 ??
+ */
+ if (chip_type >= HPT370)
+ goto check_bad_ata33;
+ if (HPT366_ALLOW_ATA66_4 &&
+ !check_in_drive_list(drive, bad_ata66_4))
+ goto check_bad_ata33;
+
+ speed = min_t(u8, speed, XFER_UDMA_3);
+ if (HPT366_ALLOW_ATA66_3 &&
+ !check_in_drive_list(drive, bad_ata66_3))
+ goto check_bad_ata33;
+ /* fall thru */
case 0x01:
- speed = min(speed, (u8)XFER_UDMA_2);
- /*
- * CHECK ME, Does this need to be set to 5 ??
- */
- if (info->revision >= 3)
+ speed = min_t(u8, speed, XFER_UDMA_2);
+
+ check_bad_ata33:
+ if (chip_type >= HPT370A)
break;
- if (check_in_drive_lists(drive, bad_ata33))
- speed = min(speed, (u8)XFER_MW_DMA_2);
- break;
+ if (!check_in_drive_list(drive, bad_ata33))
+ break;
+ /* fall thru */
case 0x00:
default:
- speed = min(speed, (u8)XFER_MW_DMA_2);
+ speed = min_t(u8, speed, XFER_MW_DMA_2);
break;
}
return speed;
}
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+static u32 get_speed_setting(u8 speed, struct hpt_info *info)
{
- struct hd_driveid *id = drive->id;
-
- if (quirk_drives == list) {
- while (*list)
- if (strstr(id->model, *list++))
- return 1;
- } else {
- while (*list)
- if (!strcmp(*list++,id->model))
- return 1;
- }
- return 0;
-}
-
-static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
- for ( ; chipset_table->xfer_speed ; chipset_table++)
- if (chipset_table->xfer_speed == speed)
- return chipset_table->chipset_settings;
- return chipset_table->chipset_settings;
-}
-
-static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 speed = hpt3xx_ratefilter(drive, xferspeed);
- u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
- u8 regfast = (hwif->channel) ? 0x55 : 0x51;
- u8 drive_fast = 0;
- u32 reg1 = 0, reg2 = 0;
+ int i;
/*
- * Disable the "fast interrupt" prediction.
+ * Lookup the transfer mode table to get the index into
+ * the timing table.
+ *
+ * NOTE: For XFER_PIO_SLOW, PIO mode 0 timings will be used.
*/
- pci_read_config_byte(dev, regfast, &drive_fast);
- if (drive_fast & 0x80)
- pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
-
- reg2 = pci_bus_clock_list(speed, info->speed);
-
+ for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
+ if (xfer_speeds[i] == speed)
+ break;
/*
- * Disable on-chip PIO FIFO/buffer
- * (to avoid problems handling I/O errors later)
+ * NOTE: info->settings only points to the pointer
+ * to the list of the actual register values
*/
- pci_read_config_dword(dev, regtime, &reg1);
- if (speed >= XFER_MW_DMA_0) {
- reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
- } else {
- reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
- }
- reg2 &= ~0x80000000;
-
- pci_write_config_dword(dev, regtime, reg2);
-
- return ide_config_drive_speed(drive, speed);
+ return (*info->settings)[i];
}
-static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 speed = hpt3xx_ratefilter(drive, xferspeed);
- u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51;
- u8 drive_pci = 0x40 + (drive->dn * 4);
- u8 new_fast = 0, drive_fast = 0;
- u32 list_conf = 0, drive_conf = 0;
- u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
+ u8 speed = hpt3xx_ratefilter(drive, xferspeed);
+ u8 itr_addr = drive->dn ? 0x44 : 0x40;
+ u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
+ (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff);
+ u32 new_itr = get_speed_setting(speed, info);
+ u32 old_itr = 0;
/*
- * Disable the "fast interrupt" prediction.
- * don't holdoff on interrupts. (== 0x01 despite what the docs say)
+ * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
+ * to avoid problems handling I/O errors later
*/
- pci_read_config_byte(dev, regfast, &drive_fast);
- new_fast = drive_fast;
- if (new_fast & 0x02)
- new_fast &= ~0x02;
+ pci_read_config_dword(dev, itr_addr, &old_itr);
+ new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
+ new_itr &= ~0xc0000000;
-#ifdef HPT_DELAY_INTERRUPT
- if (new_fast & 0x01)
- new_fast &= ~0x01;
-#else
- if ((new_fast & 0x01) == 0)
- new_fast |= 0x01;
-#endif
- if (new_fast != drive_fast)
- pci_write_config_byte(dev, regfast, new_fast);
-
- list_conf = pci_bus_clock_list(speed, info->speed);
-
- pci_read_config_dword(dev, drive_pci, &drive_conf);
- list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-
- if (speed < XFER_MW_DMA_0)
- list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
- pci_write_config_dword(dev, drive_pci, list_conf);
+ pci_write_config_dword(dev, itr_addr, new_itr);
return ide_config_drive_speed(drive, speed);
}
-static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 speed = hpt3xx_ratefilter(drive, xferspeed);
- u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51;
- u8 drive_fast = 0, drive_pci = 0x40 + (drive->dn * 4);
- u32 list_conf = 0, drive_conf = 0;
- u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-
- /*
- * Disable the "fast interrupt" prediction.
- * don't holdoff on interrupts. (== 0x01 despite what the docs say)
- */
- pci_read_config_byte(dev, regfast, &drive_fast);
- drive_fast &= ~0x07;
- pci_write_config_byte(dev, regfast, drive_fast);
-
- list_conf = pci_bus_clock_list(speed, info->speed);
- pci_read_config_dword(dev, drive_pci, &drive_conf);
- list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
+ u8 speed = hpt3xx_ratefilter(drive, xferspeed);
+ u8 itr_addr = 0x40 + (drive->dn * 4);
+ u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
+ (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff);
+ u32 new_itr = get_speed_setting(speed, info);
+ u32 old_itr = 0;
+
+ pci_read_config_dword(dev, itr_addr, &old_itr);
+ new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
+
if (speed < XFER_MW_DMA_0)
- list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
- pci_write_config_dword(dev, drive_pci, list_conf);
+ new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+ pci_write_config_dword(dev, itr_addr, new_itr);
return ide_config_drive_speed(drive, speed);
}
-static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
+static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
-
- if (info->revision >= 8)
- return hpt372_tune_chipset(drive, speed); /* not a typo */
- else if (info->revision >= 5)
- return hpt372_tune_chipset(drive, speed);
- else if (info->revision >= 3)
- return hpt370_tune_chipset(drive, speed);
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
+
+ if (info->chip_type >= HPT370)
+ return hpt37x_tune_chipset(drive, speed);
else /* hpt368: hpt_minimum_revision(dev, 2) */
return hpt36x_tune_chipset(drive, speed);
}
-static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
- (void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
}
/*
* This allows the configuration of ide_pci chipset registers
* for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS. Initially for designed for
+ * after the drive is reported by the OS. Initially designed for
* HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
*
- * check_in_drive_lists(drive, bad_ata66_4)
- * check_in_drive_lists(drive, bad_ata66_3)
- * check_in_drive_lists(drive, bad_ata33)
- *
*/
-static int config_chipset_for_dma (ide_drive_t *drive)
+static int config_chipset_for_dma(ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
if (!speed)
return 0;
- /* If we don't have any timings we can't do a lot */
- if (info->speed == NULL)
- return 0;
-
(void) hpt3xx_tune_chipset(drive, speed);
return ide_dma_enable(drive);
}
-static int hpt3xx_quirkproc (ide_drive_t *drive)
+static int hpt3xx_quirkproc(ide_drive_t *drive)
{
- return ((int) check_in_drive_lists(drive, quirk_drives));
+ struct hd_driveid *id = drive->id;
+ const char **list = quirk_drives;
+
+ while (*list)
+ if (strstr(id->model, *list++))
+ return 1;
+ return 0;
}
-static void hpt3xx_intrproc (ide_drive_t *drive)
+static void hpt3xx_intrproc(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
+ ide_hwif_t *hwif = HWIF(drive);
if (drive->quirk_list)
return;
/* drives in the quirk_list may not like intr setups/cleanups */
- hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+ hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
}
-static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- struct pci_dev *dev = hwif->pci_dev;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
if (drive->quirk_list) {
- if (info->revision >= 3) {
- u8 reg5a = 0;
- pci_read_config_byte(dev, 0x5a, &reg5a);
- if (((reg5a & 0x10) >> 4) != mask)
- pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+ if (info->chip_type >= HPT370) {
+ u8 scr1 = 0;
+
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ if (((scr1 & 0x10) >> 4) != mask) {
+ if (mask)
+ scr1 |= 0x10;
+ else
+ scr1 &= ~0x10;
+ pci_write_config_byte(dev, 0x5a, scr1);
+ }
} else {
- if (mask) {
+ if (mask)
disable_irq(hwif->irq);
- } else {
- enable_irq(hwif->irq);
- }
+ else
+ enable_irq (hwif->irq);
}
- } else {
- if (IDE_CONTROL_REG)
- hwif->OUTB(mask ? (drive->ctl | 2) :
- (drive->ctl & ~2),
- IDE_CONTROL_REG);
- }
+ } else
+ hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
+ IDE_CONTROL_REG);
}
-static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
+static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
+ ide_hwif_t *hwif = HWIF(drive);
struct hd_driveid *id = drive->id;
drive->init_speed = 0;
if ((id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
+ if (ide_use_dma(drive) && 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:
- hpt3xx_tune_drive(drive, 5);
+ hpt3xx_tune_drive(drive, 255);
return hwif->ide_dma_off_quietly(drive);
}
/* IORDY not supported */
@@ -834,31 +757,48 @@ fast_ata_pio:
}
/*
- * This is specific to the HPT366 UDMA bios chipset
+ * This is specific to the HPT366 UDMA chipset
* by HighPoint|Triones Technologies, Inc.
*/
-static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
+static int hpt366_ide_dma_lostirq(ide_drive_t *drive)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
- u8 reg50h = 0, reg52h = 0, reg5ah = 0;
-
- pci_read_config_byte(dev, 0x50, &reg50h);
- pci_read_config_byte(dev, 0x52, &reg52h);
- pci_read_config_byte(dev, 0x5a, &reg5ah);
- printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
- drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
- if (reg5ah & 0x10)
- pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
+
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ pci_read_config_byte(dev, 0x52, &mcr3);
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
+ drive->name, __FUNCTION__, mcr1, mcr3, scr1);
+ if (scr1 & 0x10)
+ pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
return __ide_dma_lostirq(drive);
}
-static void hpt370_clear_engine (ide_drive_t *drive)
+static void hpt370_clear_engine(ide_drive_t *drive)
{
- u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50;
- pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37);
+ ide_hwif_t *hwif = HWIF(drive);
+
+ pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37);
udelay(10);
}
+static void hpt370_irq_timeout(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u16 bfifo = 0;
+ u8 dma_cmd;
+
+ pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
+ printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
+
+ /* get DMA command mode */
+ dma_cmd = hwif->INB(hwif->dma_command);
+ /* stop DMA */
+ hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+ hpt370_clear_engine(drive);
+}
+
static void hpt370_ide_dma_start(ide_drive_t *drive)
{
#ifdef HPT_RESET_STATE_ENGINE
@@ -867,64 +807,35 @@ static void hpt370_ide_dma_start(ide_drive_t *drive)
ide_dma_start(drive);
}
-static int hpt370_ide_dma_end (ide_drive_t *drive)
+static int hpt370_ide_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- u8 dma_stat = hwif->INB(hwif->dma_status);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
if (dma_stat & 0x01) {
/* wait a little */
udelay(20);
dma_stat = hwif->INB(hwif->dma_status);
+ if (dma_stat & 0x01)
+ hpt370_irq_timeout(drive);
}
- if ((dma_stat & 0x01) != 0)
- /* fallthrough */
- (void) HWIF(drive)->ide_dma_timeout(drive);
-
return __ide_dma_end(drive);
}
-static void hpt370_lostirq_timeout (ide_drive_t *drive)
-{
- ide_hwif_t *hwif = HWIF(drive);
- u8 bfifo = 0, reginfo = hwif->channel ? 0x56 : 0x52;
- u8 dma_stat = 0, dma_cmd = 0;
-
- pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
- printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo);
- hpt370_clear_engine(drive);
- /* get dma command mode */
- dma_cmd = hwif->INB(hwif->dma_command);
- /* stop dma */
- hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
- dma_stat = hwif->INB(hwif->dma_status);
- /* clear errors */
- hwif->OUTB(dma_stat | 0x6, hwif->dma_status);
-}
-
-static int hpt370_ide_dma_timeout (ide_drive_t *drive)
+static int hpt370_ide_dma_timeout(ide_drive_t *drive)
{
- hpt370_lostirq_timeout(drive);
- hpt370_clear_engine(drive);
+ hpt370_irq_timeout(drive);
return __ide_dma_timeout(drive);
}
-static int hpt370_ide_dma_lostirq (ide_drive_t *drive)
-{
- hpt370_lostirq_timeout(drive);
- hpt370_clear_engine(drive);
- return __ide_dma_lostirq(drive);
-}
-
/* returns 1 if DMA IRQ issued, 0 otherwise */
static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
u16 bfifo = 0;
- u8 reginfo = hwif->channel ? 0x56 : 0x52;
- u8 dma_stat;
+ u8 dma_stat;
- pci_read_config_word(hwif->pci_dev, reginfo, &bfifo);
+ pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
if (bfifo & 0x1FF) {
// printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
return 0;
@@ -932,7 +843,7 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
dma_stat = hwif->INB(hwif->dma_status);
/* return 1 if INTR asserted */
- if ((dma_stat & 4) == 4)
+ if (dma_stat & 4)
return 1;
if (!drive->waiting_for_dma)
@@ -941,687 +852,711 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
return 0;
}
-static int hpt374_ide_dma_end (ide_drive_t *drive)
+static int hpt374_ide_dma_end(ide_drive_t *drive)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
ide_hwif_t *hwif = HWIF(drive);
- u8 msc_stat = 0, mscreg = hwif->channel ? 0x54 : 0x50;
- u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
-
- pci_read_config_byte(dev, 0x6a, &bwsr_stat);
- pci_read_config_byte(dev, mscreg, &msc_stat);
- if ((bwsr_stat & bwsr_mask) == bwsr_mask)
- pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 mcr = 0, mcr_addr = hwif->select_data;
+ u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01;
+
+ pci_read_config_byte(dev, 0x6a, &bwsr);
+ pci_read_config_byte(dev, mcr_addr, &mcr);
+ if (bwsr & mask)
+ pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
return __ide_dma_end(drive);
}
/**
- * hpt372n_set_clock - perform clock switching dance
- * @drive: Drive to switch
- * @mode: Switching mode (0x21 for write, 0x23 otherwise)
+ * hpt3xxn_set_clock - perform clock switching dance
+ * @hwif: hwif to switch
+ * @mode: clocking mode (0x21 for write, 0x23 otherwise)
*
- * Switch the DPLL clock on the HPT372N devices. This is a
- * right mess.
+ * Switch the DPLL clock on the HPT3xxN devices. This is a right mess.
*/
-
-static void hpt372n_set_clock(ide_drive_t *drive, int mode)
+
+static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
{
- ide_hwif_t *hwif = HWIF(drive);
-
- /* FIXME: should we check for DMA active and BUG() */
+ u8 scr2 = hwif->INB(hwif->dma_master + 0x7b);
+
+ if ((scr2 & 0x7f) == mode)
+ return;
+
/* Tristate the bus */
- outb(0x80, hwif->dma_base+0x73);
- outb(0x80, hwif->dma_base+0x77);
-
+ hwif->OUTB(0x80, hwif->dma_master + 0x73);
+ hwif->OUTB(0x80, hwif->dma_master + 0x77);
+
/* Switch clock and reset channels */
- outb(mode, hwif->dma_base+0x7B);
- outb(0xC0, hwif->dma_base+0x79);
-
- /* Reset state machines */
- outb(0x37, hwif->dma_base+0x70);
- outb(0x37, hwif->dma_base+0x74);
-
+ hwif->OUTB(mode, hwif->dma_master + 0x7b);
+ hwif->OUTB(0xc0, hwif->dma_master + 0x79);
+
+ /*
+ * Reset the state machines.
+ * NOTE: avoid accidentally enabling the disabled channels.
+ */
+ hwif->OUTB(hwif->INB(hwif->dma_master + 0x70) | 0x32,
+ hwif->dma_master + 0x70);
+ hwif->OUTB(hwif->INB(hwif->dma_master + 0x74) | 0x32,
+ hwif->dma_master + 0x74);
+
/* Complete reset */
- outb(0x00, hwif->dma_base+0x79);
-
+ hwif->OUTB(0x00, hwif->dma_master + 0x79);
+
/* Reconnect channels to bus */
- outb(0x00, hwif->dma_base+0x73);
- outb(0x00, hwif->dma_base+0x77);
+ hwif->OUTB(0x00, hwif->dma_master + 0x73);
+ hwif->OUTB(0x00, hwif->dma_master + 0x77);
}
/**
- * hpt372n_rw_disk - prepare for I/O
+ * hpt3xxn_rw_disk - prepare for I/O
* @drive: drive for command
* @rq: block request structure
*
- * This is called when a disk I/O is issued to the 372N.
+ * This is called when a disk I/O is issued to HPT3xxN.
* We need it because of the clock switching.
*/
-static void hpt372n_rw_disk(ide_drive_t *drive, struct request *rq)
+static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
{
- ide_hwif_t *hwif = drive->hwif;
- int wantclock;
-
- wantclock = rq_data_dir(rq) ? 0x23 : 0x21;
-
- if (hwif->config_data != wantclock) {
- hpt372n_set_clock(drive, wantclock);
- hwif->config_data = wantclock;
- }
-}
-
-/*
- * Since SUN Cobalt is attempting to do this operation, I should disclose
- * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
- * HOTSWAP ATA Infrastructure.
- */
-
-static void hpt3xx_reset (ide_drive_t *drive)
-{
-}
-
-static int hpt3xx_tristate (ide_drive_t * drive, int state)
-{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
- u8 reg59h = 0, reset = (hwif->channel) ? 0x80 : 0x40;
- u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53;
-
- pci_read_config_byte(dev, 0x59, &reg59h);
- pci_read_config_byte(dev, state_reg, &regXXh);
-
- if (state) {
- (void) ide_do_reset(drive);
- pci_write_config_byte(dev, state_reg, regXXh|0x80);
- pci_write_config_byte(dev, 0x59, reg59h|reset);
- } else {
- pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
- pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
- (void) ide_do_reset(drive);
- }
- return 0;
+ hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21);
}
/*
- * set/get power state for a drive.
- * turning the power off does the following things:
- * 1) soft-reset the drive
- * 2) tri-states the ide bus
+ * Set/get power state for a drive.
+ * NOTE: affects both drives on each channel.
*
- * when we turn things back on, we need to re-initialize things.
+ * When we turn the power back on, we need to re-initialize things.
*/
#define TRISTATE_BIT 0x8000
-static int hpt370_busproc(ide_drive_t * drive, int state)
+
+static int hpt3xx_busproc(ide_drive_t *drive, int state)
{
- ide_hwif_t *hwif = drive->hwif;
+ ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- u8 tristate = 0, resetmask = 0, bus_reg = 0;
- u16 tri_reg;
+ u8 mcr_addr = hwif->select_data + 2;
+ u8 resetmask = hwif->channel ? 0x80 : 0x40;
+ u8 bsr2 = 0;
+ u16 mcr = 0;
hwif->bus_state = state;
- if (hwif->channel) {
- /* secondary channel */
- tristate = 0x56;
- resetmask = 0x80;
- } else {
- /* primary channel */
- tristate = 0x52;
- resetmask = 0x40;
- }
+ /* Grab the status. */
+ pci_read_config_word(dev, mcr_addr, &mcr);
+ pci_read_config_byte(dev, 0x59, &bsr2);
- /* grab status */
- pci_read_config_word(dev, tristate, &tri_reg);
- pci_read_config_byte(dev, 0x59, &bus_reg);
-
- /* set the state. we don't set it if we don't need to do so.
- * make sure that the drive knows that it has failed if it's off */
+ /*
+ * Set the state. We don't set it if we don't need to do so.
+ * Make sure that the drive knows that it has failed if it's off.
+ */
switch (state) {
case BUSSTATE_ON:
- hwif->drives[0].failures = 0;
- hwif->drives[1].failures = 0;
- if ((bus_reg & resetmask) == 0)
+ if (!(bsr2 & resetmask))
return 0;
- tri_reg &= ~TRISTATE_BIT;
- bus_reg &= ~resetmask;
- break;
+ hwif->drives[0].failures = hwif->drives[1].failures = 0;
+
+ pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask);
+ pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT);
+ return 0;
case BUSSTATE_OFF:
- hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
- hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
- if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+ if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT))
return 0;
- tri_reg &= ~TRISTATE_BIT;
- bus_reg |= resetmask;
+ mcr &= ~TRISTATE_BIT;
break;
case BUSSTATE_TRISTATE:
- hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
- hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
- if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+ if ((bsr2 & resetmask) && (mcr & TRISTATE_BIT))
return 0;
- tri_reg |= TRISTATE_BIT;
- bus_reg |= resetmask;
+ mcr |= TRISTATE_BIT;
break;
+ default:
+ return -EINVAL;
}
- pci_write_config_byte(dev, 0x59, bus_reg);
- pci_write_config_word(dev, tristate, tri_reg);
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+
+ pci_write_config_word(dev, mcr_addr, mcr);
+ pci_write_config_byte(dev, 0x59, bsr2 | resetmask);
return 0;
}
-static void __devinit hpt366_clocking(ide_hwif_t *hwif)
+/**
+ * hpt37x_calibrate_dpll - calibrate the DPLL
+ * @dev: PCI device
+ *
+ * Perform a calibration cycle on the DPLL.
+ * Returns 1 if this succeeds
+ */
+static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
{
- u32 reg1 = 0;
- struct hpt_info *info = ide_get_hwifdata(hwif);
+ u32 dpll = (f_high << 16) | f_low | 0x100;
+ u8 scr2;
+ int i;
- pci_read_config_dword(hwif->pci_dev, 0x40, &reg1);
+ pci_write_config_dword(dev, 0x5c, dpll);
- /* detect bus speed by looking at control reg timing: */
- switch((reg1 >> 8) & 7) {
- case 5:
- info->speed = forty_base_hpt366;
- break;
- case 9:
- info->speed = twenty_five_base_hpt366;
- break;
- case 7:
- default:
- info->speed = thirty_three_base_hpt366;
+ /* Wait for oscillator ready */
+ for(i = 0; i < 0x5000; ++i) {
+ udelay(50);
+ pci_read_config_byte(dev, 0x5b, &scr2);
+ if (scr2 & 0x80)
break;
}
+ /* See if it stays ready (we'll just bail out if it's not yet) */
+ for(i = 0; i < 0x1000; ++i) {
+ pci_read_config_byte(dev, 0x5b, &scr2);
+ /* DPLL destabilized? */
+ if(!(scr2 & 0x80))
+ return 0;
+ }
+ /* Turn off tuning, we have the DPLL set */
+ pci_read_config_dword (dev, 0x5c, &dpll);
+ pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));
+ return 1;
}
-static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
+static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
{
- struct hpt_info *info = ide_get_hwifdata(hwif);
- struct pci_dev *dev = hwif->pci_dev;
- int adjust, i;
- u16 freq;
- u32 pll;
- u8 reg5bh;
-
+ struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
+ unsigned long io_base = pci_resource_start(dev, 4);
+ u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */
+ enum ata_clock clock;
+
+ if (info == NULL) {
+ printk(KERN_ERR "%s: out of memory!\n", name);
+ return -ENOMEM;
+ }
+
/*
- * default to pci clock. make sure MA15/16 are set to output
- * to prevent drives having problems with 40-pin cables. Needed
- * for some drives such as IBM-DTLA which will not enter ready
- * state on reset when PDIAG is a input.
- *
- * ToDo: should we set 0x21 when using PLL mode ?
+ * Copy everything from a static "template" structure
+ * to just allocated per-chip hpt_info structure.
*/
- pci_write_config_byte(dev, 0x5b, 0x23);
+ *info = *(struct hpt_info *)pci_get_drvdata(dev);
/*
- * set up the PLL. we need to adjust it so that it's stable.
- * freq = Tpll * 192 / Tpci
- *
- * Todo. For non x86 should probably check the dword is
- * set to 0xABCDExxx indicating the BIOS saved f_CNT
+ * FIXME: Not portable. Also, why do we enable the ROM in the first place?
+ * We don't seem to be using it.
*/
- pci_read_config_word(dev, 0x78, &freq);
- freq &= 0x1FF;
-
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+ dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
/*
- * The 372N uses different PCI clock information and has
- * some other complications
- * On PCI33 timing we must clock switch
- * On PCI66 timing we must NOT use the PCI clock
- *
- * Currently we always set up the PLL for the 372N
+ * First, try to estimate the PCI clock frequency...
*/
-
- if(info->flags & IS_372N)
- {
- printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n");
- if(freq < 0x55)
- pll = F_LOW_PCI_33;
- else if(freq < 0x70)
- pll = F_LOW_PCI_40;
- else if(freq < 0x7F)
- pll = F_LOW_PCI_50;
- else
- pll = F_LOW_PCI_66;
-
- printk(KERN_INFO "FREQ: %d PLL: %d\n", freq, pll);
-
- /* We always use the pll not the PCI clock on 372N */
- }
- else
- {
- if(freq < 0x9C)
- pll = F_LOW_PCI_33;
- else if(freq < 0xb0)
- pll = F_LOW_PCI_40;
- else if(freq <0xc8)
- pll = F_LOW_PCI_50;
- else
- pll = F_LOW_PCI_66;
-
- if (pll == F_LOW_PCI_33) {
- if (info->revision >= 8)
- info->speed = thirty_three_base_hpt374;
- else if (info->revision >= 5)
- info->speed = thirty_three_base_hpt372;
- else if (info->revision >= 4)
- info->speed = thirty_three_base_hpt370a;
- else
- info->speed = thirty_three_base_hpt370;
- printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n");
- } else if (pll == F_LOW_PCI_40) {
- /* Unsupported */
- } else if (pll == F_LOW_PCI_50) {
- if (info->revision >= 8)
- info->speed = fifty_base_hpt370a;
- else if (info->revision >= 5)
- info->speed = fifty_base_hpt372;
- else if (info->revision >= 4)
- info->speed = fifty_base_hpt370a;
- else
- info->speed = fifty_base_hpt370a;
- printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n");
- } else {
- if (info->revision >= 8) {
- printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
+ if (info->chip_type >= HPT370) {
+ u8 scr1 = 0;
+ u16 f_cnt = 0;
+ u32 temp = 0;
+
+ /* Interrupt force enable. */
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ if (scr1 & 0x10)
+ pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
+
+ /*
+ * HighPoint does this for HPT372A.
+ * NOTE: This register is only writeable via I/O space.
+ */
+ if (info->chip_type == HPT372A)
+ outb(0x0e, io_base + 0x9c);
+
+ /*
+ * Default to PCI clock. Make sure MA15/16 are set to output
+ * to prevent drives having problems with 40-pin cables.
+ */
+ pci_write_config_byte(dev, 0x5b, 0x23);
+
+ /*
+ * We'll have to read f_CNT value in order to determine
+ * the PCI clock frequency according to the following ratio:
+ *
+ * f_CNT = Fpci * 192 / Fdpll
+ *
+ * First try reading the register in which the HighPoint BIOS
+ * saves f_CNT value before reprogramming the DPLL from its
+ * default setting (which differs for the various chips).
+ * NOTE: This register is only accessible via I/O space.
+ *
+ * In case the signature check fails, we'll have to resort to
+ * reading the f_CNT register itself in hopes that nobody has
+ * touched the DPLL yet...
+ */
+ temp = inl(io_base + 0x90);
+ if ((temp & 0xFFFFF000) != 0xABCDE000) {
+ int i;
+
+ printk(KERN_WARNING "%s: no clock data saved by BIOS\n",
+ name);
+
+ /* Calculate the average value of f_CNT. */
+ for (temp = i = 0; i < 128; i++) {
+ pci_read_config_word(dev, 0x78, &f_cnt);
+ temp += f_cnt & 0x1ff;
+ mdelay(1);
}
- else if (info->revision >= 5)
- info->speed = sixty_six_base_hpt372;
- else if (info->revision >= 4)
- info->speed = sixty_six_base_hpt370a;
- else
- info->speed = sixty_six_base_hpt370;
- printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n");
+ f_cnt = temp / 128;
+ } else
+ f_cnt = temp & 0x1ff;
+
+ dpll_clk = info->dpll_clk;
+ pci_clk = (f_cnt * dpll_clk) / 192;
+
+ /* Clamp PCI clock to bands. */
+ if (pci_clk < 40)
+ pci_clk = 33;
+ else if(pci_clk < 45)
+ pci_clk = 40;
+ else if(pci_clk < 55)
+ pci_clk = 50;
+ else
+ pci_clk = 66;
+
+ printk(KERN_INFO "%s: DPLL base: %d MHz, f_CNT: %d, "
+ "assuming %d MHz PCI\n", name, dpll_clk, f_cnt, pci_clk);
+ } else {
+ u32 itr1 = 0;
+
+ pci_read_config_dword(dev, 0x40, &itr1);
+
+ /* Detect PCI clock by looking at cmd_high_time. */
+ switch((itr1 >> 8) & 0x07) {
+ case 0x09:
+ pci_clk = 40;
+ break;
+ case 0x05:
+ pci_clk = 25;
+ break;
+ case 0x07:
+ default:
+ pci_clk = 33;
+ break;
}
}
-
- /*
- * only try the pll if we don't have a table for the clock
- * speed that we're running at. NOTE: the internal PLL will
- * result in slow reads when using a 33MHz PCI clock. we also
- * don't like to use the PLL because it will cause glitches
- * on PRST/SRST when the HPT state engine gets reset.
- *
- * ToDo: Use 66MHz PLL when ATA133 devices are present on a
- * 372 device so we can get ATA133 support
- */
- if (info->speed)
- goto init_hpt37X_done;
- info->flags |= PLL_MODE;
-
+ /* Let's assume we'll use PCI clock for the ATA clock... */
+ switch (pci_clk) {
+ case 25:
+ clock = ATA_CLOCK_25MHZ;
+ break;
+ case 33:
+ default:
+ clock = ATA_CLOCK_33MHZ;
+ break;
+ case 40:
+ clock = ATA_CLOCK_40MHZ;
+ break;
+ case 50:
+ clock = ATA_CLOCK_50MHZ;
+ break;
+ case 66:
+ clock = ATA_CLOCK_66MHZ;
+ break;
+ }
+
/*
- * FIXME: make this work correctly, esp with 372N as per
- * reference driver code.
+ * Only try the DPLL if we don't have a table for the PCI clock that
+ * we are running at for HPT370/A, always use it for anything newer...
*
- * adjust PLL based upon PCI clock, enable it, and wait for
- * stabilization.
+ * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.
+ * We also don't like using the DPLL because this causes glitches
+ * on PRST-/SRST- when the state engine gets reset...
*/
- adjust = 0;
- freq = (pll < F_LOW_PCI_50) ? 2 : 4;
- while (adjust++ < 6) {
- pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
- pll | 0x100);
-
- /* wait for clock stabilization */
- for (i = 0; i < 0x50000; i++) {
- pci_read_config_byte(dev, 0x5b, &reg5bh);
- if (reg5bh & 0x80) {
- /* spin looking for the clock to destabilize */
- for (i = 0; i < 0x1000; ++i) {
- pci_read_config_byte(dev, 0x5b,
- &reg5bh);
- if ((reg5bh & 0x80) == 0)
- goto pll_recal;
- }
- pci_read_config_dword(dev, 0x5c, &pll);
- pci_write_config_dword(dev, 0x5c,
- pll & ~0x100);
- pci_write_config_byte(dev, 0x5b, 0x21);
- if (info->revision >= 8)
- info->speed = fifty_base_hpt370a;
- else if (info->revision >= 5)
- info->speed = fifty_base_hpt372;
- else if (info->revision >= 4)
- info->speed = fifty_base_hpt370a;
- else
- info->speed = fifty_base_hpt370a;
- printk("HPT37X: using 50MHz internal PLL\n");
- goto init_hpt37X_done;
- }
+ if (info->chip_type >= HPT374 || info->settings[clock] == NULL) {
+ u16 f_low, delta = pci_clk < 50 ? 2 : 4;
+ int adjust;
+
+ /*
+ * Select 66 MHz DPLL clock only if UltraATA/133 mode is
+ * supported/enabled, use 50 MHz DPLL clock otherwise...
+ */
+ if (info->max_mode == 0x04) {
+ dpll_clk = 66;
+ clock = ATA_CLOCK_66MHZ;
+ } else if (dpll_clk) { /* HPT36x chips don't have DPLL */
+ dpll_clk = 50;
+ clock = ATA_CLOCK_50MHZ;
}
- if (!pci_get_drvdata(dev)) {
- printk("No Clock Stabilization!!!\n");
- return;
+
+ if (info->settings[clock] == NULL) {
+ printk(KERN_ERR "%s: unknown bus timing!\n", name);
+ kfree(info);
+ return -EIO;
}
-pll_recal:
- if (adjust & 1)
- pll -= (adjust >> 1);
- else
- pll += (adjust >> 1);
- }
-
-init_hpt37X_done:
- if (!info->speed)
- printk(KERN_ERR "HPT37X%s: unknown bus timing [%d %d].\n",
- (info->flags & IS_372N)?"N":"", pll, freq);
- /* reset state engine */
- pci_write_config_byte(dev, 0x50, 0x37);
- pci_write_config_byte(dev, 0x54, 0x37);
- udelay(100);
-}
-static int __devinit init_hpt37x(struct pci_dev *dev)
-{
- u8 reg5ah;
+ /* Select the DPLL clock. */
+ pci_write_config_byte(dev, 0x5b, 0x21);
- pci_read_config_byte(dev, 0x5a, &reg5ah);
- /* interrupt force enable */
- pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
- return 0;
-}
+ /*
+ * Adjust the DPLL based upon PCI clock, enable it,
+ * and wait for stabilization...
+ */
+ f_low = (pci_clk * 48) / dpll_clk;
-static int __devinit init_hpt366(struct pci_dev *dev)
-{
- u32 reg1 = 0;
- u8 drive_fast = 0;
+ for (adjust = 0; adjust < 8; adjust++) {
+ if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))
+ break;
- /*
- * Disable the "fast interrupt" prediction.
- */
- pci_read_config_byte(dev, 0x51, &drive_fast);
- if (drive_fast & 0x80)
- pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
- pci_read_config_dword(dev, 0x40, &reg1);
-
- return 0;
-}
+ /*
+ * See if it'll settle at a fractionally different clock
+ */
+ if (adjust & 1)
+ f_low -= adjust >> 1;
+ else
+ f_low += adjust >> 1;
+ }
+ if (adjust == 8) {
+ printk(KERN_ERR "%s: DPLL did not stabilize!\n", name);
+ kfree(info);
+ return -EIO;
+ }
-static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
-{
- int ret = 0;
+ printk("%s: using %d MHz DPLL clock\n", name, dpll_clk);
+ } else {
+ /* Mark the fact that we're not using the DPLL. */
+ dpll_clk = 0;
+
+ printk("%s: using %d MHz PCI clock\n", name, pci_clk);
+ }
/*
- * FIXME: Not portable. Also, why do we enable the ROM in the first place?
- * We don't seem to be using it.
+ * Advance the table pointer to a slot which points to the list
+ * of the register values settings matching the clock being used.
*/
- if (dev->resource[PCI_ROM_RESOURCE].start)
- pci_write_config_dword(dev, PCI_ROM_ADDRESS,
- dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ info->settings += clock;
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
- pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
- pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+ /* Store the clock frequencies. */
+ info->dpll_clk = dpll_clk;
+ info->pci_clk = pci_clk;
- if (hpt_revision(dev) >= 3)
- ret = init_hpt37x(dev);
- else
- ret = init_hpt366(dev);
+ /* Point to this chip's own instance of the hpt_info structure. */
+ pci_set_drvdata(dev, info);
- if (ret)
- return ret;
+ if (info->chip_type >= HPT370) {
+ u8 mcr1, mcr4;
+
+ /*
+ * Reset the state engines.
+ * NOTE: Avoid accidentally enabling the disabled channels.
+ */
+ pci_read_config_byte (dev, 0x50, &mcr1);
+ pci_read_config_byte (dev, 0x54, &mcr4);
+ pci_write_config_byte(dev, 0x50, (mcr1 | 0x32));
+ pci_write_config_byte(dev, 0x54, (mcr4 | 0x32));
+ udelay(100);
+ }
+
+ /*
+ * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+ * the MISC. register to stretch the UltraDMA Tss timing.
+ * NOTE: This register is only writeable via I/O space.
+ */
+ if (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
+
+ outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
return dev->irq;
}
static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02;
-
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
+ int serialize = HPT_SERIALIZE_IO;
+ u8 scr1 = 0, ata66 = (hwif->channel) ? 0x01 : 0x02;
+ u8 chip_type = info->chip_type;
+ u8 new_mcr, old_mcr = 0;
+
+ /* Cache the channel's MISC. control registers' offset */
+ hwif->select_data = hwif->channel ? 0x54 : 0x50;
+
hwif->tuneproc = &hpt3xx_tune_drive;
hwif->speedproc = &hpt3xx_tune_chipset;
hwif->quirkproc = &hpt3xx_quirkproc;
hwif->intrproc = &hpt3xx_intrproc;
hwif->maskproc = &hpt3xx_maskproc;
-
- if(info->flags & IS_372N)
- hwif->rw_disk = &hpt372n_rw_disk;
+ hwif->busproc = &hpt3xx_busproc;
/*
- * The HPT37x uses the CBLID pins as outputs for MA15/MA16
- * address lines to access an external eeprom. To read valid
- * cable detect state the pins must be enabled as inputs.
+ * HPT3xxN chips have some complications:
+ *
+ * - on 33 MHz PCI we must clock switch
+ * - on 66 MHz PCI we must NOT use the PCI clock
*/
- if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) {
+ if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) {
/*
- * HPT374 PCI function 1
- * - set bit 15 of reg 0x52 to enable TCBLID as input
- * - set bit 15 of reg 0x56 to enable FCBLID as input
+ * Clock is shared between the channels,
+ * so we'll have to serialize them... :-(
*/
- u16 mcr3, mcr6;
- pci_read_config_word(dev, 0x52, &mcr3);
- pci_read_config_word(dev, 0x56, &mcr6);
- pci_write_config_word(dev, 0x52, mcr3 | 0x8000);
- pci_write_config_word(dev, 0x56, mcr6 | 0x8000);
- /* now read cable id register */
- pci_read_config_byte(dev, 0x5a, &ata66);
- pci_write_config_word(dev, 0x52, mcr3);
- pci_write_config_word(dev, 0x56, mcr6);
- } else if (info->revision >= 3) {
- /*
- * HPT370/372 and 374 pcifn 0
- * - clear bit 0 of 0x5b to enable P/SCBLID as inputs
- */
- u8 scr2;
- pci_read_config_byte(dev, 0x5b, &scr2);
- pci_write_config_byte(dev, 0x5b, scr2 & ~1);
- /* now read cable id register */
- pci_read_config_byte(dev, 0x5a, &ata66);
- pci_write_config_byte(dev, 0x5b, scr2);
- } else {
- pci_read_config_byte(dev, 0x5a, &ata66);
+ serialize = 1;
+ hwif->rw_disk = &hpt3xxn_rw_disk;
}
-#ifdef DEBUG
- printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
- ata66, (ata66 & regmask) ? "33" : "66",
- PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
-
-#ifdef HPT_SERIALIZE_IO
- /* serialize access to this device */
- if (hwif->mate)
+ /* Serialize access to this device if needed */
+ if (serialize && hwif->mate)
hwif->serialized = hwif->mate->serialized = 1;
+
+ /*
+ * Disable the "fast interrupt" prediction. Don't hold off
+ * on interrupts. (== 0x01 despite what the docs say)
+ */
+ pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr);
+
+ if (info->chip_type >= HPT374)
+ new_mcr = old_mcr & ~0x07;
+ else if (info->chip_type >= HPT370) {
+ new_mcr = old_mcr;
+ new_mcr &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+ new_mcr &= ~0x01;
+#else
+ new_mcr |= 0x01;
#endif
+ } else /* HPT366 and HPT368 */
+ new_mcr = old_mcr & ~0x80;
- if (info->revision >= 3) {
- u8 reg5ah = 0;
- pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
- /*
- * set up ioctl for power status.
- * note: power affects both
- * drives on each channel
- */
- hwif->resetproc = &hpt3xx_reset;
- hwif->busproc = &hpt370_busproc;
- } else if (info->revision >= 2) {
- hwif->resetproc = &hpt3xx_reset;
- hwif->busproc = &hpt3xx_tristate;
- } else {
- hwif->resetproc = &hpt3xx_reset;
- hwif->busproc = &hpt3xx_tristate;
- }
+ if (new_mcr != old_mcr)
+ pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
return;
}
hwif->ultra_mask = 0x7f;
hwif->mwdma_mask = 0x07;
- if (!(hwif->udma_four))
- hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
- hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
-
- if (info->revision >= 8) {
- hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
- hwif->ide_dma_end = &hpt374_ide_dma_end;
- } else if (info->revision >= 5) {
- hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
- hwif->ide_dma_end = &hpt374_ide_dma_end;
- } else if (info->revision >= 3) {
- hwif->dma_start = &hpt370_ide_dma_start;
- hwif->ide_dma_end = &hpt370_ide_dma_end;
- hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
- hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
- } else if (info->revision >= 2)
- hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
- else
- hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+ /*
+ * The HPT37x uses the CBLID pins as outputs for MA15/MA16
+ * address lines to access an external EEPROM. To read valid
+ * cable detect state the pins must be enabled as inputs.
+ */
+ if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
+ /*
+ * HPT374 PCI function 1
+ * - set bit 15 of reg 0x52 to enable TCBLID as input
+ * - set bit 15 of reg 0x56 to enable FCBLID as input
+ */
+ u8 mcr_addr = hwif->select_data + 2;
+ u16 mcr;
+
+ pci_read_config_word (dev, mcr_addr, &mcr);
+ pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
+ /* now read cable id register */
+ pci_read_config_byte (dev, 0x5a, &scr1);
+ pci_write_config_word(dev, mcr_addr, mcr);
+ } else if (chip_type >= HPT370) {
+ /*
+ * HPT370/372 and 374 pcifn 0
+ * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
+ */
+ u8 scr2 = 0;
+
+ pci_read_config_byte (dev, 0x5b, &scr2);
+ pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
+ /* now read cable id register */
+ pci_read_config_byte (dev, 0x5a, &scr1);
+ pci_write_config_byte(dev, 0x5b, scr2);
+ } else
+ pci_read_config_byte (dev, 0x5a, &scr1);
+
+ if (!hwif->udma_four)
+ hwif->udma_four = (scr1 & ata66) ? 0 : 1;
+
+ hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
+
+ if (chip_type >= HPT374) {
+ hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
+ hwif->ide_dma_end = &hpt374_ide_dma_end;
+ } else if (chip_type >= HPT370) {
+ hwif->dma_start = &hpt370_ide_dma_start;
+ hwif->ide_dma_end = &hpt370_ide_dma_end;
+ hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
+ } else
+ hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
if (!noautodma)
hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
+ hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
}
static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
{
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 masterdma = 0, slavedma = 0;
- u8 dma_new = 0, dma_old = 0;
- u8 primary = hwif->channel ? 0x4b : 0x43;
- u8 secondary = hwif->channel ? 0x4f : 0x47;
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 masterdma = 0, slavedma = 0;
+ u8 dma_new = 0, dma_old = 0;
unsigned long flags;
if (!dmabase)
return;
- if(info->speed == NULL) {
- printk(KERN_WARNING "hpt: no known IDE timings, disabling DMA.\n");
- return;
- }
-
- dma_old = hwif->INB(dmabase+2);
+ dma_old = hwif->INB(dmabase + 2);
local_irq_save(flags);
dma_new = dma_old;
- pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
- pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+ pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
+ pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma);
if (masterdma & 0x30) dma_new |= 0x20;
- if (slavedma & 0x30) dma_new |= 0x40;
+ if ( slavedma & 0x30) dma_new |= 0x40;
if (dma_new != dma_old)
- hwif->OUTB(dma_new, dmabase+2);
+ hwif->OUTB(dma_new, dmabase + 2);
local_irq_restore(flags);
ide_setup_dma(hwif, dmabase, 8);
}
-/*
- * We "borrow" this hook in order to set the data structures
- * up early enough before dma or init_hwif calls are made.
- */
-
-static void __devinit init_iops_hpt366(ide_hwif_t *hwif)
+static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
{
- struct hpt_info *info = kzalloc(sizeof(struct hpt_info), GFP_KERNEL);
- unsigned long dmabase = pci_resource_start(hwif->pci_dev, 4);
- u8 did, rid;
+ struct pci_dev *dev2;
- if(info == NULL) {
- printk(KERN_WARNING "hpt366: out of memory.\n");
- return;
- }
- ide_set_hwifdata(hwif, info);
+ if (PCI_FUNC(dev->devfn) & 1)
+ return -ENODEV;
+
+ pci_set_drvdata(dev, &hpt374);
+
+ if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+ int ret;
- if(dmabase) {
- did = inb(dmabase + 0x22);
- rid = inb(dmabase + 0x28);
+ pci_set_drvdata(dev2, &hpt374);
- if((did == 4 && rid == 6) || (did == 5 && rid > 1))
- info->flags |= IS_372N;
+ if (dev2->irq != dev->irq) {
+ /* FIXME: we need a core pci_set_interrupt() */
+ dev2->irq = dev->irq;
+ printk(KERN_WARNING "%s: PCI config space interrupt "
+ "fixed.\n", d->name);
+ }
+ ret = ide_setup_pci_devices(dev, dev2, d);
+ if (ret < 0)
+ pci_dev_put(dev2);
+ return ret;
}
+ return ide_setup_pci_device(dev, d);
+}
- info->revision = hpt_revision(hwif->pci_dev);
+static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ pci_set_drvdata(dev, &hpt372n);
- if (info->revision >= 3)
- hpt37x_clocking(hwif);
- else
- hpt366_clocking(hwif);
+ return ide_setup_pci_device(dev, d);
}
-static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
{
- struct pci_dev *findev = NULL;
+ struct hpt_info *info;
+ u8 rev = 0, mcr1 = 0;
- if (PCI_FUNC(dev->devfn) & 1)
- return -ENODEV;
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+ if (rev > 1) {
+ d->name = "HPT371N";
+
+ info = &hpt371n;
+ } else
+ info = &hpt371;
+
+ /*
+ * HPT371 chips physically have only one channel, the secondary one,
+ * but the primary channel registers do exist! Go figure...
+ * So, we manually disable the non-existing channel here
+ * (if the BIOS hasn't done this already).
+ */
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ if (mcr1 & 0x04)
+ pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
+
+ pci_set_drvdata(dev, info);
+
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ struct hpt_info *info;
+ u8 rev = 0;
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+ if (rev > 1) {
+ d->name = "HPT372N";
+
+ info = &hpt372n;
+ } else
+ info = &hpt372a;
+ pci_set_drvdata(dev, info);
- while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
- if ((findev->vendor == dev->vendor) &&
- (findev->device == dev->device) &&
- ((findev->devfn - dev->devfn) == 1) &&
- (PCI_FUNC(findev->devfn) & 1)) {
- if (findev->irq != dev->irq) {
- /* FIXME: we need a core pci_set_interrupt() */
- findev->irq = dev->irq;
- printk(KERN_WARNING "%s: pci-config space interrupt "
- "fixed.\n", d->name);
- }
- return ide_setup_pci_devices(dev, findev, d);
- }
- }
return ide_setup_pci_device(dev, d);
}
-static int __devinit init_setup_hpt37x(struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
{
+ struct hpt_info *info;
+ u8 rev = 0;
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+ if (rev > 1) {
+ d->name = "HPT302N";
+
+ info = &hpt302n;
+ } else
+ info = &hpt302;
+ pci_set_drvdata(dev, info);
+
return ide_setup_pci_device(dev, d);
}
static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
{
- struct pci_dev *findev = NULL;
- u8 pin1 = 0, pin2 = 0;
- unsigned int class_rev;
- char *chipset_names[] = {"HPT366", "HPT366", "HPT368",
- "HPT370", "HPT370A", "HPT372",
- "HPT372N" };
+ struct pci_dev *dev2;
+ u8 rev = 0;
+ static char *chipset_names[] = { "HPT366", "HPT366", "HPT368",
+ "HPT370", "HPT370A", "HPT372",
+ "HPT372N" };
+ static struct hpt_info *info[] = { &hpt36x, &hpt36x, &hpt36x,
+ &hpt370, &hpt370a, &hpt372,
+ &hpt372n };
if (PCI_FUNC(dev->devfn) & 1)
return -ENODEV;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
- if(dev->device == PCI_DEVICE_ID_TTI_HPT372N)
- class_rev = 6;
+ if (rev > 6)
+ rev = 6;
- if(class_rev <= 6)
- d->name = chipset_names[class_rev];
-
- switch(class_rev) {
- case 6:
- case 5:
- case 4:
- case 3:
- goto init_single;
- default:
- break;
- }
+ d->name = chipset_names[rev];
+
+ pci_set_drvdata(dev, info[rev]);
+
+ if (rev > 2)
+ goto init_single;
d->channels = 1;
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
- while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
- if ((findev->vendor == dev->vendor) &&
- (findev->device == dev->device) &&
- ((findev->devfn - dev->devfn) == 1) &&
- (PCI_FUNC(findev->devfn) & 1)) {
- pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2);
- if ((pin1 != pin2) && (dev->irq == findev->irq)) {
- d->bootable = ON_BOARD;
- printk("%s: onboard version of chipset, "
- "pin1=%d pin2=%d\n", d->name,
- pin1, pin2);
- }
- return ide_setup_pci_devices(dev, findev, d);
+ if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+ u8 pin1 = 0, pin2 = 0;
+ int ret;
+
+ pci_set_drvdata(dev2, info[rev]);
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
+ pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
+ if (pin1 != pin2 && dev->irq == dev2->irq) {
+ d->bootable = ON_BOARD;
+ printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
+ d->name, pin1, pin2);
}
+ ret = ide_setup_pci_devices(dev, dev2, d);
+ if (ret < 0)
+ pci_dev_put(dev2);
+ return ret;
}
init_single:
return ide_setup_pci_device(dev, d);
@@ -1632,63 +1567,68 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT366",
.init_setup = init_setup_hpt366,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
.extra = 240
},{ /* 1 */
.name = "HPT372A",
- .init_setup = init_setup_hpt37x,
+ .init_setup = init_setup_hpt372a,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 2 */
.name = "HPT302",
- .init_setup = init_setup_hpt37x,
+ .init_setup = init_setup_hpt302,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 3 */
.name = "HPT371",
- .init_setup = init_setup_hpt37x,
+ .init_setup = init_setup_hpt371,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 4 */
.name = "HPT374",
.init_setup = init_setup_hpt374,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2, /* 4 */
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 5 */
.name = "HPT372N",
- .init_setup = init_setup_hpt37x,
+ .init_setup = init_setup_hpt372n,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2, /* 4 */
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
}
};
@@ -1699,13 +1639,16 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
*
* Called when the PCI registration layer (or the IDE initialization)
* finds a device matching our IDE device tables.
+ *
+ * NOTE: since we'll have to modify some fields of the ide_pci_device_t
+ * structure depending on the chip's revision, we'd better pass a local
+ * copy down the call chain...
*/
-
static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t *d = &hpt366_chipsets[id->driver_data];
+ ide_pci_device_t d = hpt366_chipsets[id->driver_data];
- return d->init_setup(dev, d);
+ return d.init_setup(dev, &d);
}
static struct pci_device_id hpt366_pci_tbl[] = {
@@ -1725,7 +1668,7 @@ static struct pci_driver driver = {
.probe = hpt366_init_one,
};
-static int hpt366_ide_init(void)
+static int __init hpt366_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
new file mode 100644
index 00000000000..63248b6909f
--- /dev/null
+++ b/drivers/ide/pci/it8213.c
@@ -0,0 +1,362 @@
+/*
+ * ITE 8213 IDE driver
+ *
+ * Copyright (C) 2006 Jack Lee
+ * Copyright (C) 2006 Alan Cox
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ */
+
+#include <linux/kernel.h>
+#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>
+
+/*
+ * it8213_ratemask - Compute available modes
+ * @drive: IDE drive
+ *
+ * Compute the available speeds for the devices on the interface. This
+ * is all modes to ATA133 clipped by drive cable setup.
+ */
+
+static u8 it8213_ratemask (ide_drive_t *drive)
+{
+ u8 mode = 4;
+ if (!eighty_ninty_three(drive))
+ mode = min_t(u8, mode, 1);
+ return mode;
+}
+
+/**
+ * it8213_dma_2_pio - return the PIO mode matching DMA
+ * @xfer_rate: transfer speed
+ *
+ * Returns the nearest equivalent PIO timing for the PIO or DMA
+ * mode requested by the controller.
+ */
+
+static u8 it8213_dma_2_pio (u8 xfer_rate) {
+ switch(xfer_rate) {
+ case XFER_UDMA_6:
+ 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;
+ }
+}
+
+/*
+ * it8213_tuneproc - tune a drive
+ * @drive: drive to tune
+ * @pio: desired PIO mode
+ *
+ * Set the interface PIO mode.
+ */
+
+static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ int is_slave = drive->dn & 1;
+ int master_port = 0x40;
+ int slave_port = 0x44;
+ unsigned long flags;
+ u16 master_data;
+ u8 slave_data;
+ static DEFINE_SPINLOCK(tune_lock);
+ int control = 0;
+
+ static const u8 timings[][2]= {
+ { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+ spin_lock_irqsave(&tune_lock, flags);
+ pci_read_config_word(dev, master_port, &master_data);
+
+ if (pio > 1)
+ control |= 1; /* Programmable timing on */
+ if (drive->media != ide_disk)
+ control |= 4; /* ATAPI */
+ if (pio > 2)
+ control |= 2; /* IORDY */
+ if (is_slave) {
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
+ if (pio > 1)
+ master_data = master_data | (control << 4);
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data = slave_data & 0xf0;
+ slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1];
+ } else {
+ master_data &= ~0x3307;
+ if (pio > 1)
+ 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);
+ if (is_slave)
+ pci_write_config_byte(dev, slave_port, slave_data);
+ spin_unlock_irqrestore(&tune_lock, flags);
+}
+
+/**
+ * it8213_tune_chipset - set controller timings
+ * @drive: Drive to set up
+ * @xferspeed: speed we want to achieve
+ *
+ * Tune the ITE chipset for the desired mode. If we can't achieve
+ * the desired mode then tune for a lower one, but ultimately
+ * make the thing work.
+ */
+
+static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 maslave = 0x40;
+ u8 speed = ide_rate_filter(it8213_ratemask(drive), xferspeed);
+ int a_speed = 3 << (drive->dn * 4);
+ int u_flag = 1 << drive->dn;
+ int v_flag = 0x01 << drive->dn;
+ int w_flag = 0x10 << drive->dn;
+ int u_speed = 0;
+ u16 reg4042, reg4a;
+ u8 reg48, reg54, reg55;
+
+ pci_read_config_word(dev, maslave, &reg4042);
+ pci_read_config_byte(dev, 0x48, &reg48);
+ pci_read_config_word(dev, 0x4a, &reg4a);
+ pci_read_config_byte(dev, 0x54, &reg54);
+ pci_read_config_byte(dev, 0x55, &reg55);
+
+ switch(speed) {
+ case XFER_UDMA_6:
+ 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;
+ break;
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_SW_DMA_2:
+ break;
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ break;
+ default:
+ return -1;
+ }
+
+ if (speed >= XFER_UDMA_0) {
+ if (!(reg48 & u_flag))
+ pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+ if (speed >= XFER_UDMA_5) {
+ pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+ } else {
+ pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+ }
+
+ if ((reg4a & a_speed) != u_speed)
+ pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
+ if (speed > XFER_UDMA_2) {
+ if (!(reg54 & v_flag))
+ pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+ } else
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+ } else {
+ if (reg48 & u_flag)
+ pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+ if (reg4a & a_speed)
+ pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+ if (reg54 & v_flag)
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+ if (reg55 & w_flag)
+ pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+ }
+ it8213_tuneproc(drive, it8213_dma_2_pio(speed));
+ return ide_config_drive_speed(drive, speed);
+}
+
+/*
+ * config_chipset_for_dma - configure for DMA
+ * @drive: drive to configure
+ *
+ * Called by the IDE layer when it wants the timings set up.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, it8213_ratemask(drive));
+
+ if (!speed)
+ return 0;
+
+ it8213_tune_chipset(drive, speed);
+
+ return ide_dma_enable(drive);
+}
+
+/**
+ * it8213_configure_drive_for_dma - set up for DMA transfers
+ * @drive: drive we are going to set up
+ *
+ * Set up the drive for DMA, tune the controller and drive as
+ * required. If the drive isn't suitable for DMA or we hit
+ * other problems then we will drop down to PIO and set up
+ * PIO appropriately
+ */
+
+static int it8213_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);
+ }
+
+ hwif->speedproc(drive, XFER_PIO_0
+ + ide_get_best_pio_mode(drive, 255, 4, NULL));
+
+ return hwif->ide_dma_off_quietly(drive);
+}
+
+/**
+ * init_hwif_it8213 - set up hwif structs
+ * @hwif: interface to set up
+ *
+ * We do the basic set up of the interface structure. The IT8212
+ * requires several custom handlers so we override the default
+ * ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
+{
+ u8 reg42h = 0, ata66 = 0;
+
+ hwif->speedproc = &it8213_tune_chipset;
+ hwif->tuneproc = &it8213_tuneproc;
+
+ hwif->autodma = 0;
+
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
+ return;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x06;
+ hwif->swdma_mask = 0x04;
+
+ pci_read_config_byte(hwif->pci_dev, 0x42, &reg42h);
+ ata66 = (reg42h & 0x02) ? 0 : 1;
+
+ hwif->ide_dma_check = &it8213_config_drive_for_dma;
+ if (!(hwif->udma_four))
+ hwif->udma_four = ata66;
+
+ /*
+ * The BIOS often doesn't set up DMA on this controller
+ * so we always do it.
+ */
+ if (!noautodma)
+ hwif->autodma = 1;
+
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+
+#define DECLARE_ITE_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_hwif = init_hwif_it8213, \
+ .channels = 1, \
+ .autodma = AUTODMA, \
+ .enablebits = {{0x41,0x80,0x80}}, \
+ .bootable = ON_BOARD, \
+ }
+
+static ide_pci_device_t it8213_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_ITE_DEV("IT8213"),
+};
+
+
+/**
+ * it8213_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds an ITE8213 controller. As
+ * this device follows the standard interfaces we can use the
+ * standard helper functions to do almost all the work for us.
+ */
+
+static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]);
+ return 0;
+}
+
+
+static struct pci_device_id it8213_pci_tbl[] = {
+ { PCI_VENDOR_ID_ITE, 0x8213, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "ITE8213_IDE",
+ .id_table = it8213_pci_tbl,
+ .probe = it8213_init_one,
+};
+
+static int __init it8213_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(it8213_ide_init);
+
+MODULE_AUTHOR("Jack Lee, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 8213");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index c1cec236ecf..f07bbbed177 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -86,15 +86,16 @@ static int __devinit ata66_jmicron(ide_hwif_t *hwif)
{
case PORT_PATA0:
if (control & (1 << 3)) /* 40/80 pin primary */
- return 1;
- return 0;
+ return 0;
+ return 1;
case PORT_PATA1:
if (control5 & (1 << 19)) /* 40/80 pin secondary */
return 0;
return 1;
case PORT_SATA:
- return 1;
+ break;
}
+ return 1; /* Avoid bogus "control reaches end of non-void function" */
}
static void jmicron_tuneproc (ide_drive_t *drive, byte mode_wanted)
@@ -240,11 +241,11 @@ static int __devinit jmicron_init_one(struct pci_dev *dev, const struct pci_devi
}
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},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
{ 0, },
};
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index d95714bcee4..8aaea4ea554 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -302,7 +302,7 @@ static struct pci_driver driver = {
.probe = ns87415_init_one,
};
-static int ns87415_ide_init(void)
+static int __init ns87415_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index 7a7c2ef78ac..22bbf613f94 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -382,7 +382,7 @@ static struct pci_driver driver = {
.probe = opti621_init_one,
};
-static int opti621_ide_init(void)
+static int __init opti621_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index 6c097e80b4d..236a03144a2 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -9,6 +9,7 @@
* Split from:
* linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002
* Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2005-2006 MontaVista Software, Inc.
* Portions Copyright (C) 1999 Promise Technology, Inc.
* Author: Frank Tiernan (frankt@promise.com)
* Released under terms of General Public License
@@ -38,6 +39,14 @@
#define PDC202_DEBUG_CABLE 0
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk("%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
static const char *pdc_quirk_drives[] = {
"QUANTUM FIREBALLlct08 08",
"QUANTUM FIREBALLP KA6.4",
@@ -50,37 +59,11 @@ static const char *pdc_quirk_drives[] = {
NULL
};
-#define set_2regs(a, b) \
- do { \
- hwif->OUTB((a + adj), indexreg); \
- hwif->OUTB(b, datareg); \
- } while(0)
-
-#define set_ultra(a, b, c) \
- do { \
- set_2regs(0x10,(a)); \
- set_2regs(0x11,(b)); \
- set_2regs(0x12,(c)); \
- } while(0)
-
-#define set_ata2(a, b) \
- do { \
- set_2regs(0x0e,(a)); \
- set_2regs(0x0f,(b)); \
- } while(0)
-
-#define set_pio(a, b, c) \
- do { \
- set_2regs(0x0c,(a)); \
- set_2regs(0x0d,(b)); \
- set_2regs(0x13,(c)); \
- } while(0)
-
-static u8 pdcnew_ratemask (ide_drive_t *drive)
+static u8 max_dma_rate(struct pci_dev *pdev)
{
u8 mode;
- switch(HWIF(drive)->pci_dev->device) {
+ switch(pdev->device) {
case PCI_DEVICE_ID_PROMISE_20277:
case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20275:
@@ -95,178 +78,327 @@ static u8 pdcnew_ratemask (ide_drive_t *drive)
default:
return 0;
}
- if (!eighty_ninty_three(drive))
- mode = min(mode, (u8)1);
+
return mode;
}
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+static u8 pdcnew_ratemask(ide_drive_t *drive)
{
- struct hd_driveid *id = drive->id;
+ u8 mode = max_dma_rate(HWIF(drive)->pci_dev);
- if (pdc_quirk_drives == list) {
- while (*list) {
- if (strstr(id->model, *list++)) {
- return 2;
- }
- }
- } else {
- while (*list) {
- if (!strcmp(*list++,id->model)) {
- return 1;
- }
- }
- }
- return 0;
+ if (!eighty_ninty_three(drive))
+ mode = min_t(u8, mode, 1);
+
+ return mode;
}
-static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+/**
+ * get_indexed_reg - Get indexed register
+ * @hwif: for the port address
+ * @index: index of the indexed register
+ */
+static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index)
{
- ide_hwif_t *hwif = HWIF(drive);
- unsigned long indexreg = hwif->dma_vendor1;
- unsigned long datareg = hwif->dma_vendor3;
- u8 thold = 0x10;
- u8 adj = (drive->dn%2) ? 0x08 : 0x00;
- u8 speed = ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
-
- if (speed == XFER_UDMA_2) {
- hwif->OUTB((thold + adj), indexreg);
- hwif->OUTB((hwif->INB(datareg) & 0x7f), datareg);
- }
+ u8 value;
- switch (speed) {
- case XFER_UDMA_7:
- speed = XFER_UDMA_6;
- case XFER_UDMA_6: set_ultra(0x1a, 0x01, 0xcb); break;
- case XFER_UDMA_5: set_ultra(0x1a, 0x02, 0xcb); break;
- case XFER_UDMA_4: set_ultra(0x1a, 0x03, 0xcd); break;
- case XFER_UDMA_3: set_ultra(0x1a, 0x05, 0xcd); break;
- case XFER_UDMA_2: set_ultra(0x2a, 0x07, 0xcd); break;
- case XFER_UDMA_1: set_ultra(0x3a, 0x0a, 0xd0); break;
- case XFER_UDMA_0: set_ultra(0x4a, 0x0f, 0xd5); break;
- case XFER_MW_DMA_2: set_ata2(0x69, 0x25); break;
- case XFER_MW_DMA_1: set_ata2(0x6b, 0x27); break;
- case XFER_MW_DMA_0: set_ata2(0xdf, 0x5f); break;
- case XFER_PIO_4: set_pio(0x23, 0x09, 0x25); break;
- case XFER_PIO_3: set_pio(0x27, 0x0d, 0x35); break;
- case XFER_PIO_2: set_pio(0x23, 0x26, 0x64); break;
- case XFER_PIO_1: set_pio(0x46, 0x29, 0xa4); break;
- case XFER_PIO_0: set_pio(0xfb, 0x2b, 0xac); break;
- default:
- ;
- }
+ hwif->OUTB(index, hwif->dma_vendor1);
+ value = hwif->INB(hwif->dma_vendor3);
- return (ide_config_drive_speed(drive, speed));
+ DBG("index[%02X] value[%02X]\n", index, value);
+ return value;
}
-/* 0 1 2 3 4 5 6 7 8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- * 180, 150, 120, 90, 60
- * DMA_Speed
- * 180, 120, 90, 90, 90, 60, 30
- * 11, 5, 4, 3, 2, 1, 0
+/**
+ * set_indexed_reg - Set indexed register
+ * @hwif: for the port address
+ * @index: index of the indexed register
*/
-static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
+static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value)
{
- u8 speed;
+ hwif->OUTB(index, hwif->dma_vendor1);
+ hwif->OUTB(value, hwif->dma_vendor3);
+ DBG("index[%02X] value[%02X]\n", index, value);
+}
- if (pio == 5) pio = 4;
- speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+/*
+ * ATA Timing Tables based on 133 MHz PLL output clock.
+ *
+ * If the PLL outputs 100 MHz clock, the ASIC hardware will set
+ * the timing registers automatically when "set features" command is
+ * issued to the device. However, if the PLL output clock is 133 MHz,
+ * the following tables must be used.
+ */
+static struct pio_timing {
+ u8 reg0c, reg0d, reg13;
+} pio_timings [] = {
+ { 0xfb, 0x2b, 0xac }, /* PIO mode 0, IORDY off, Prefetch off */
+ { 0x46, 0x29, 0xa4 }, /* PIO mode 1, IORDY off, Prefetch off */
+ { 0x23, 0x26, 0x64 }, /* PIO mode 2, IORDY off, Prefetch off */
+ { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */
+ { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */
+};
- (void)pdcnew_new_tune_chipset(drive, speed);
+static struct mwdma_timing {
+ u8 reg0e, reg0f;
+} mwdma_timings [] = {
+ { 0xdf, 0x5f }, /* MWDMA mode 0 */
+ { 0x6b, 0x27 }, /* MWDMA mode 1 */
+ { 0x69, 0x25 }, /* MWDMA mode 2 */
+};
+
+static struct udma_timing {
+ u8 reg10, reg11, reg12;
+} udma_timings [] = {
+ { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */
+ { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */
+ { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */
+ { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */
+ { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */
+ { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */
+ { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */
+};
+
+static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
+ int err;
+
+ speed = ide_rate_filter(pdcnew_ratemask(drive), speed);
+
+ /*
+ * Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will
+ * automatically set the timing registers based on 100 MHz PLL output.
+ */
+ err = ide_config_drive_speed(drive, speed);
+
+ /*
+ * As we set up the PLL to output 133 MHz for UltraDMA/133 capable
+ * chips, we must override the default register settings...
+ */
+ if (max_dma_rate(hwif->pci_dev) == 4) {
+ u8 mode = speed & 0x07;
+
+ switch (speed) {
+ case XFER_UDMA_6:
+ case XFER_UDMA_5:
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ set_indexed_reg(hwif, 0x10 + adj,
+ udma_timings[mode].reg10);
+ set_indexed_reg(hwif, 0x11 + adj,
+ udma_timings[mode].reg11);
+ set_indexed_reg(hwif, 0x12 + adj,
+ udma_timings[mode].reg12);
+ break;
+
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_MW_DMA_0:
+ set_indexed_reg(hwif, 0x0e + adj,
+ mwdma_timings[mode].reg0e);
+ set_indexed_reg(hwif, 0x0f + adj,
+ mwdma_timings[mode].reg0f);
+ break;
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ set_indexed_reg(hwif, 0x0c + adj,
+ pio_timings[mode].reg0c);
+ set_indexed_reg(hwif, 0x0d + adj,
+ pio_timings[mode].reg0d);
+ set_indexed_reg(hwif, 0x13 + adj,
+ pio_timings[mode].reg13);
+ break;
+ default:
+ printk(KERN_ERR "pdc202xx_new: "
+ "Unknown speed %d ignored\n", speed);
+ }
+ } else if (speed == XFER_UDMA_2) {
+ /* Set tHOLD bit to 0 if using UDMA mode 2 */
+ u8 tmp = get_indexed_reg(hwif, 0x10 + adj);
+
+ set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f);
+ }
+
+ return err;
}
-static u8 pdcnew_new_cable_detect (ide_hwif_t *hwif)
+static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
{
- hwif->OUTB(0x0b, hwif->dma_vendor1);
- return ((u8)((hwif->INB(hwif->dma_vendor3) & 0x04)));
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ (void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio);
}
-static int config_chipset_for_dma (ide_drive_t *drive)
+
+static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
+{
+ return get_indexed_reg(hwif, 0x0b) & 0x04;
+}
+
+static int config_chipset_for_dma(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
- u8 speed = -1;
- u8 cable;
-
- u8 ultra_66 = ((id->dma_ultra & 0x0010) ||
- (id->dma_ultra & 0x0008)) ? 1 : 0;
-
- cable = pdcnew_new_cable_detect(hwif);
+ u8 ultra_66 = (id->dma_ultra & 0x0078) ? 1 : 0;
+ u8 cable = pdcnew_cable_detect(hwif);
+ u8 speed;
if (ultra_66 && cable) {
- printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+ printk(KERN_WARNING "Warning: %s channel "
+ "requires an 80-pin cable for operation.\n",
+ hwif->channel ? "Secondary" : "Primary");
printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
}
if (drive->media != ide_disk)
return 0;
- if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */
- hwif->OUTB((0x13 + ((drive->dn%2) ? 0x08 : 0x00)), hwif->dma_vendor1);
- hwif->OUTB((hwif->INB(hwif->dma_vendor3)|0x03), hwif->dma_vendor3);
+
+ if (id->capability & 4) {
+ /*
+ * Set IORDY_EN & PREFETCH_EN (this seems to have
+ * NO real effect since this register is reloaded
+ * by hardware when the transfer mode is selected)
+ */
+ u8 tmp, adj = (drive->dn & 1) ? 0x08 : 0x00;
+
+ tmp = get_indexed_reg(hwif, 0x13 + adj);
+ set_indexed_reg(hwif, 0x13 + adj, tmp | 0x03);
}
speed = ide_dma_speed(drive, pdcnew_ratemask(drive));
- if (!(speed)) {
- hwif->tuneproc(drive, 5);
+ if (!speed)
return 0;
- }
(void) hwif->speedproc(drive, speed);
return ide_dma_enable(drive);
}
-static int pdcnew_config_drive_xfer_rate (ide_drive_t *drive)
+static int pdcnew_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 ((id->capability & 1) && drive->autodma) {
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
+ if (ide_use_dma(drive) && 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:
- hwif->tuneproc(drive, 5);
+ hwif->tuneproc(drive, 255);
return hwif->ide_dma_off_quietly(drive);
}
/* IORDY not supported */
return 0;
}
-static int pdcnew_quirkproc (ide_drive_t *drive)
+static int pdcnew_quirkproc(ide_drive_t *drive)
{
- return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+ const char **list, *model = drive->id->model;
+
+ for (list = pdc_quirk_drives; *list != NULL; list++)
+ if (strstr(model, *list) != NULL)
+ return 2;
+ return 0;
}
-static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
+static void pdcnew_reset(ide_drive_t *drive)
{
- if (HWIF(drive)->resetproc != NULL)
- HWIF(drive)->resetproc(drive);
- return __ide_dma_lostirq(drive);
+ /*
+ * Deleted this because it is redundant from the caller.
+ */
+ printk(KERN_WARNING "pdc202xx_new: %s channel reset.\n",
+ HWIF(drive)->channel ? "Secondary" : "Primary");
}
-static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
+/**
+ * read_counter - Read the byte count registers
+ * @dma_base: for the port address
+ */
+static long __devinit read_counter(u32 dma_base)
{
- if (HWIF(drive)->resetproc != NULL)
- HWIF(drive)->resetproc(drive);
- return __ide_dma_timeout(drive);
+ u32 pri_dma_base = dma_base, sec_dma_base = dma_base + 0x08;
+ u8 cnt0, cnt1, cnt2, cnt3;
+ long count = 0, last;
+ int retry = 3;
+
+ do {
+ last = count;
+
+ /* Read the current count */
+ outb(0x20, pri_dma_base + 0x01);
+ cnt0 = inb(pri_dma_base + 0x03);
+ outb(0x21, pri_dma_base + 0x01);
+ cnt1 = inb(pri_dma_base + 0x03);
+ outb(0x20, sec_dma_base + 0x01);
+ cnt2 = inb(sec_dma_base + 0x03);
+ outb(0x21, sec_dma_base + 0x01);
+ cnt3 = inb(sec_dma_base + 0x03);
+
+ count = (cnt3 << 23) | (cnt2 << 15) | (cnt1 << 8) | cnt0;
+
+ /*
+ * The 30-bit decrementing counter is read in 4 pieces.
+ * Incorrect value may be read when the most significant bytes
+ * are changing...
+ */
+ } while (retry-- && (((last ^ count) & 0x3fff8000) || last < count));
+
+ DBG("cnt0[%02X] cnt1[%02X] cnt2[%02X] cnt3[%02X]\n",
+ cnt0, cnt1, cnt2, cnt3);
+
+ return count;
}
-static void pdcnew_new_reset (ide_drive_t *drive)
+/**
+ * detect_pll_input_clock - Detect the PLL input clock in Hz.
+ * @dma_base: for the port address
+ * E.g. 16949000 on 33 MHz PCI bus, i.e. half of the PCI clock.
+ */
+static long __devinit detect_pll_input_clock(unsigned long dma_base)
{
+ long start_count, end_count;
+ long pll_input;
+ u8 scr1;
+
+ start_count = read_counter(dma_base);
+
+ /* Start the test mode */
+ outb(0x01, dma_base + 0x01);
+ scr1 = inb(dma_base + 0x03);
+ DBG("scr1[%02X]\n", scr1);
+ outb(scr1 | 0x40, dma_base + 0x03);
+
+ /* Let the counter run for 10 ms. */
+ mdelay(10);
+
+ end_count = read_counter(dma_base);
+
+ /* Stop the test mode */
+ outb(0x01, dma_base + 0x01);
+ scr1 = inb(dma_base + 0x03);
+ DBG("scr1[%02X]\n", scr1);
+ outb(scr1 & ~0x40, dma_base + 0x03);
+
/*
- * Deleted this because it is redundant from the caller.
+ * Calculate the input clock in Hz
+ * (the clock counter is 30 bit wide and counts down)
*/
- printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
- HWIF(drive)->channel ? "Secondary" : "Primary");
+ pll_input = ((start_count - end_count) & 0x3ffffff) * 100;
+
+ DBG("start[%ld] end[%ld]\n", start_count, end_count);
+
+ return pll_input;
}
#ifdef CONFIG_PPC_PMAC
@@ -274,7 +406,6 @@ static void __devinit apple_kiwi_init(struct pci_dev *pdev)
{
struct device_node *np = pci_device_to_OF_node(pdev);
unsigned int class_rev = 0;
- void __iomem *mmio;
u8 conf;
if (np == NULL || !device_is_compatible(np, "kiwi-root"))
@@ -285,30 +416,20 @@ static void __devinit apple_kiwi_init(struct pci_dev *pdev)
if (class_rev >= 0x03) {
/* Setup chip magic config stuff (from darwin) */
- pci_read_config_byte(pdev, 0x40, &conf);
- pci_write_config_byte(pdev, 0x40, conf | 0x01);
+ pci_read_config_byte (pdev, 0x40, &conf);
+ pci_write_config_byte(pdev, 0x40, (conf | 0x01));
}
- mmio = ioremap(pci_resource_start(pdev, 5),
- pci_resource_len(pdev, 5));
-
- /* Setup some PLL stuffs */
- switch (pdev->device) {
- case PCI_DEVICE_ID_PROMISE_20270:
- writew(0x0d2b, mmio + 0x1202);
- mdelay(30);
- break;
- case PCI_DEVICE_ID_PROMISE_20271:
- writew(0x0826, mmio + 0x1202);
- mdelay(30);
- break;
- }
-
- iounmap(mmio);
}
#endif /* CONFIG_PPC_PMAC */
static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const char *name)
{
+ unsigned long dma_base = pci_resource_start(dev, 4);
+ unsigned long sec_dma_base = dma_base + 0x08;
+ long pll_input, pll_output, ratio;
+ int f, r;
+ u8 pll_ctl0, pll_ctl1;
+
if (dev->resource[PCI_ROM_RESOURCE].start) {
pci_write_config_dword(dev, PCI_ROM_ADDRESS,
dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
@@ -320,6 +441,106 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
apple_kiwi_init(dev);
#endif
+ /* Calculate the required PLL output frequency */
+ switch(max_dma_rate(dev)) {
+ case 4: /* it's 133 MHz for Ultra133 chips */
+ pll_output = 133333333;
+ break;
+ case 3: /* and 100 MHz for Ultra100 chips */
+ default:
+ pll_output = 100000000;
+ break;
+ }
+
+ /*
+ * Detect PLL input clock.
+ * On some systems, where PCI bus is running at non-standard clock rate
+ * (e.g. 25 or 40 MHz), we have to adjust the cycle time.
+ * PDC20268 and newer chips employ PLL circuit to help correct timing
+ * registers setting.
+ */
+ pll_input = detect_pll_input_clock(dma_base);
+ printk("%s: PLL input clock is %ld kHz\n", name, pll_input / 1000);
+
+ /* Sanity check */
+ if (unlikely(pll_input < 5000000L || pll_input > 70000000L)) {
+ printk(KERN_ERR "%s: Bad PLL input clock %ld Hz, giving up!\n",
+ name, pll_input);
+ goto out;
+ }
+
+#ifdef DEBUG
+ DBG("pll_output is %ld Hz\n", pll_output);
+
+ /* Show the current clock value of PLL control register
+ * (maybe already configured by the BIOS)
+ */
+ outb(0x02, sec_dma_base + 0x01);
+ pll_ctl0 = inb(sec_dma_base + 0x03);
+ outb(0x03, sec_dma_base + 0x01);
+ pll_ctl1 = inb(sec_dma_base + 0x03);
+
+ DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
+#endif
+
+ /*
+ * Calculate the ratio of F, R and NO
+ * POUT = (F + 2) / (( R + 2) * NO)
+ */
+ ratio = pll_output / (pll_input / 1000);
+ if (ratio < 8600L) { /* 8.6x */
+ /* Using NO = 0x01, R = 0x0d */
+ r = 0x0d;
+ } else if (ratio < 12900L) { /* 12.9x */
+ /* Using NO = 0x01, R = 0x08 */
+ r = 0x08;
+ } else if (ratio < 16100L) { /* 16.1x */
+ /* Using NO = 0x01, R = 0x06 */
+ r = 0x06;
+ } else if (ratio < 64000L) { /* 64x */
+ r = 0x00;
+ } else {
+ /* Invalid ratio */
+ printk(KERN_ERR "%s: Bad ratio %ld, giving up!\n", name, ratio);
+ goto out;
+ }
+
+ f = (ratio * (r + 2)) / 1000 - 2;
+
+ DBG("F[%d] R[%d] ratio*1000[%ld]\n", f, r, ratio);
+
+ if (unlikely(f < 0 || f > 127)) {
+ /* Invalid F */
+ printk(KERN_ERR "%s: F[%d] invalid!\n", name, f);
+ goto out;
+ }
+
+ pll_ctl0 = (u8) f;
+ pll_ctl1 = (u8) r;
+
+ DBG("Writing pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
+
+ outb(0x02, sec_dma_base + 0x01);
+ outb(pll_ctl0, sec_dma_base + 0x03);
+ outb(0x03, sec_dma_base + 0x01);
+ outb(pll_ctl1, sec_dma_base + 0x03);
+
+ /* Wait the PLL circuit to be stable */
+ mdelay(30);
+
+#ifdef DEBUG
+ /*
+ * Show the current clock value of PLL control register
+ */
+ outb(0x02, sec_dma_base + 0x01);
+ pll_ctl0 = inb(sec_dma_base + 0x03);
+ outb(0x03, sec_dma_base + 0x01);
+ pll_ctl1 = inb(sec_dma_base + 0x03);
+
+ DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
+#endif
+
+ out:
return dev->irq;
}
@@ -329,8 +550,8 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
hwif->tuneproc = &pdcnew_tune_drive;
hwif->quirkproc = &pdcnew_quirkproc;
- hwif->speedproc = &pdcnew_new_tune_chipset;
- hwif->resetproc = &pdcnew_new_reset;
+ hwif->speedproc = &pdcnew_tune_chipset;
+ hwif->resetproc = &pdcnew_reset;
hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
@@ -340,13 +561,14 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
hwif->err_stops_fifo = 1;
hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
- hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
- hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
- if (!(hwif->udma_four))
- hwif->udma_four = (pdcnew_new_cable_detect(hwif)) ? 0 : 1;
+
+ if (!hwif->udma_four)
+ hwif->udma_four = pdcnew_cable_detect(hwif) ? 0 : 1;
+
if (!noautodma)
hwif->autodma = 1;
hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+
#if PDC202_DEBUG_CABLE
printk(KERN_DEBUG "%s: %s-pin cable\n",
hwif->name, hwif->udma_four ? "80" : "40");
@@ -362,6 +584,7 @@ static int __devinit init_setup_pdc20270(struct pci_dev *dev,
ide_pci_device_t *d)
{
struct pci_dev *findev = NULL;
+ int ret;
if ((dev->bus->self &&
dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
@@ -369,14 +592,16 @@ static int __devinit init_setup_pdc20270(struct pci_dev *dev,
if (PCI_SLOT(dev->devfn) & 2)
return -ENODEV;
d->extra = 0;
- while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
+ while ((findev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
if ((findev->vendor == dev->vendor) &&
(findev->device == dev->device) &&
(PCI_SLOT(findev->devfn) & 2)) {
if (findev->irq != dev->irq) {
findev->irq = dev->irq;
}
- return ide_setup_pci_devices(dev, findev, d);
+ ret = ide_setup_pci_devices(dev, findev, d);
+ pci_dev_put(findev);
+ return ret;
}
}
}
@@ -491,7 +716,7 @@ static struct pci_driver driver = {
.probe = pdc202new_init_one,
};
-static int pdc202new_ide_init(void)
+static int __init pdc202new_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 184cdacddeb..730e8d1ec2f 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -123,26 +123,6 @@ static u8 pdc202xx_ratemask (ide_drive_t *drive)
return mode;
}
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
- struct hd_driveid *id = drive->id;
-
- if (pdc_quirk_drives == list) {
- while (*list) {
- if (strstr(id->model, *list++)) {
- return 2;
- }
- }
- } else {
- while (*list) {
- if (!strcmp(*list++,id->model)) {
- return 1;
- }
- }
- }
- return 0;
-}
-
static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -377,7 +357,12 @@ fast_ata_pio:
static int pdc202xx_quirkproc (ide_drive_t *drive)
{
- return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+ const char **list, *model = drive->id->model;
+
+ for (list = pdc_quirk_drives; *list != NULL; list++)
+ if (strstr(model, *list) != NULL)
+ return 2;
+ return 0;
}
static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
@@ -719,7 +704,7 @@ static struct pci_driver driver = {
.probe = pdc202xx_init_one,
};
-static int pdc202xx_ide_init(void)
+static int __init pdc202xx_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index cdc3aab9ebc..52cfc2ac22c 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -1,13 +1,14 @@
/*
- * linux/drivers/ide/pci/piix.c Version 0.44 March 20, 2003
+ * linux/drivers/ide/pci/piix.c Version 0.46 December 3, 2006
*
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
* Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
+ * Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com>
*
* May be copied or modified under the terms of the GNU General Public License
*
- * PIO mode setting function for Intel chipsets.
+ * PIO mode setting function for Intel chipsets.
* For use instead of BIOS settings.
*
* 40-41
@@ -25,7 +26,7 @@
* sitre = word42 & 0x4000; secondary
*
* 44 8421|8421 hdd|hdb
- *
+ *
* 48 8421 hdd|hdc|hdb|hda udma enabled
*
* 0001 hda
@@ -162,7 +163,7 @@ static u8 piix_ratemask (ide_drive_t *drive)
* if the drive cannot see an 80pin cable.
*/
if (!eighty_ninty_three(drive))
- mode = min(mode, (u8)1);
+ mode = min_t(u8, mode, 1);
return mode;
}
@@ -215,7 +216,7 @@ static void piix_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);
+ int is_slave = drive->dn & 1;
int master_port = hwif->channel ? 0x42 : 0x40;
int slave_port = 0x44;
unsigned long flags;
@@ -224,7 +225,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
static DEFINE_SPINLOCK(tune_lock);
int control = 0;
- /* ISP RTC */
+ /* ISP RTC */
static const u8 timings[][2]= {
{ 0, 0 },
{ 0, 0 },
@@ -232,7 +233,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
{ 2, 1 },
{ 2, 3 }, };
- pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
/*
* Master vs slave is synchronized above us but the slave register is
@@ -242,25 +243,24 @@ 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)
+ if (pio > 1)
control |= 1; /* Programmable timing on */
if (drive->media == ide_disk)
control |= 4; /* Prefetch, post write */
- if (pio >= 3)
+ if (pio > 2)
control |= 2; /* IORDY */
if (is_slave) {
- master_data = master_data | 0x4000;
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
if (pio > 1) {
/* enable PPE, IE and TIME */
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;
+ master_data &= ~0x3307;
if (pio > 1) {
/* enable PPE, IE and TIME */
master_data = master_data | control;
@@ -353,56 +353,24 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
}
/**
- * piix_faulty_dma0 - check for DMA0 errata
- * @hwif: IDE interface to check
- *
- * If an ICH/ICH0/ICH2 interface is is operating in multi-word
- * DMA mode with 600nS cycle time the IDE PIO prefetch buffer will
- * inadvertently provide an extra piece of secondary data to the primary
- * device resulting in data corruption.
- *
- * With such a device this test function returns true. This allows
- * our tuning code to follow Intel recommendations and use PIO on
- * such devices.
- */
-
-static int piix_faulty_dma0(ide_hwif_t *hwif)
-{
- switch(hwif->pci_dev->device)
- {
- case PCI_DEVICE_ID_INTEL_82801AA_1: /* ICH */
- case PCI_DEVICE_ID_INTEL_82801AB_1: /* ICH0 */
- case PCI_DEVICE_ID_INTEL_82801BA_8: /* ICH2 */
- case PCI_DEVICE_ID_INTEL_82801BA_9: /* ICH2 */
- return 1;
- }
- return 0;
-}
-
-/**
* piix_config_drive_for_dma - configure drive for DMA
* @drive: IDE drive to configure
*
* Set up a PIIX interface channel for the best available speed.
- * We prefer UDMA if it is available and then MWDMA. If DMA is
- * not available we switch to PIO and return 0.
+ * We prefer UDMA if it is available and then MWDMA. If DMA is
+ * not available we switch to PIO and return 0.
*/
static int piix_config_drive_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, piix_ratemask(drive));
-
- /* Some ICH devices cannot support DMA mode 0 */
- if(speed == XFER_MW_DMA_0 && piix_faulty_dma0(HWIF(drive)))
- speed = 0;
-
- /* If no DMA speed was available or the chipset has DMA bugs
- then disable DMA and use PIO */
-
- if (!speed || no_piix_dma) {
- u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
- speed = piix_dma_2_pio(XFER_PIO_0 + tspeed);
- }
+
+ /*
+ * If no DMA speed was available or the chipset has DMA bugs
+ * then disable DMA and use PIO
+ */
+ if (!speed || no_piix_dma)
+ return 0;
(void) piix_tune_chipset(drive, speed);
return ide_dma_enable(drive);
@@ -425,17 +393,16 @@ static int piix_config_drive_xfer_rate (ide_drive_t *drive)
if ((id->capability & 1) && drive->autodma) {
- if (ide_use_dma(drive)) {
- if (piix_config_drive_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
+ if (ide_use_dma(drive) && piix_config_drive_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:
/* Find best PIO mode. */
- hwif->tuneproc(drive, 255);
+ (void) hwif->speedproc(drive, XFER_PIO_0 +
+ ide_get_best_pio_mode(drive, 255, 4, NULL));
return hwif->ide_dma_off_quietly(drive);
}
/* IORDY not supported */
@@ -505,6 +472,10 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
/* This is a painful system best to let it self tune for now */
return;
}
+ /* ESB2 appears to generate spurious DMA interrupts in PIO mode
+ when in native mode */
+ if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_ESB2_18)
+ hwif->atapi_irq_bogon = 1;
hwif->autodma = 0;
hwif->tuneproc = &piix_tune_drive;
@@ -567,13 +538,19 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
/* 0 */ DECLARE_PIIX_DEV("PIIXa"),
/* 1 */ DECLARE_PIIX_DEV("PIIXb"),
- { /* 2 */
+ /* 2 */
+ { /*
+ * MPIIX actually has only a single IDE channel mapped to
+ * the primary or secondary ports depending on the value
+ * of the bit 14 of the IDETIM register at offset 0x6c
+ */
.name = "MPIIX",
.init_hwif = init_hwif_piix,
.channels = 2,
.autodma = NODMA,
- .enablebits = {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+ .enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
.bootable = ON_BOARD,
+ .flags = IDEPCI_FLAG_ISA_PORTS
},
/* 3 */ DECLARE_PIIX_DEV("PIIX3"),
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
index 5f6950c2d1d..c1855311052 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/pci/rz1000.c
@@ -77,7 +77,7 @@ static struct pci_driver driver = {
.probe = rz1000_init_one,
};
-static int rz1000_ide_init(void)
+static int __init rz1000_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index ff80937d94d..8d762d323f8 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -507,7 +507,7 @@ static struct pci_driver driver = {
#endif
};
-static int sc1200_ide_init(void)
+static int __init sc1200_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index 057548d0720..ea9a28a4585 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -666,7 +666,7 @@ static struct pci_driver driver = {
.probe = svwks_init_one,
};
-static int svwks_ide_init(void)
+static int __init svwks_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index cfad09accf5..b0bf0180927 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -762,8 +762,7 @@ static struct ioc4_submodule ioc4_ide_submodule = {
/* .is_remove = ioc4_ide_remove_one, */
};
-static int __devinit
-ioc4_ide_init(void)
+static int __init ioc4_ide_init(void)
{
return ioc4_register_submodule(&ioc4_ide_submodule);
}
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 697f566fb90..4ff89c7d990 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -1096,7 +1096,7 @@ static struct pci_driver driver = {
.probe = siimage_init_one,
};
-static int siimage_ide_init(void)
+static int __init siimage_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 92edf76bd7a..1afff659ab5 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -800,9 +800,10 @@ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const c
if (trueid == 0x5517) { /* SiS 961/961B */
- lpc_bridge = pci_find_slot(0x00, 0x10); /* Bus 0, Dev 2, Fn 0 */
+ lpc_bridge = pci_get_slot(dev->bus, 0x10); /* Bus 0, Dev 2, Fn 0 */
pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev);
pci_read_config_byte(dev, 0x49, &prefctl);
+ pci_dev_put(lpc_bridge);
if (sbrev == 0x10 && (prefctl & 0x80)) {
printk(KERN_INFO "SIS5513: SiS 961B MuTIOL IDE UDMA133 controller\n");
@@ -967,7 +968,7 @@ static struct pci_driver driver = {
.probe = sis5513_init_one,
};
-static int sis5513_ide_init(void)
+static int __init sis5513_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 0b4b6049851..170a2619905 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -299,14 +299,14 @@ static void sl82c105_selectproc(ide_drive_t *drive)
//DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16;
- old = val = *((u32 *)&hwif->hwif_data);
+ old = val = (u32)pci_get_drvdata(dev);
if (drive->using_dma)
val &= ~mask;
else
val |= mask;
if (old != val) {
pci_write_config_dword(dev, 0x40, val);
- *((u32 *)&hwif->hwif_data) = val;
+ pci_set_drvdata(dev, (void *)val);
}
}
@@ -316,14 +316,13 @@ static void sl82c105_selectproc(ide_drive_t *drive)
*/
static void sl82c105_resetproc(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
u32 val;
DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
pci_read_config_dword(dev, 0x40, &val);
- *((u32 *)&hwif->hwif_data) = val;
+ pci_set_drvdata(dev, (void *)val);
}
/*
@@ -394,6 +393,7 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
pci_read_config_dword(dev, 0x40, &val);
val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
pci_write_config_dword(dev, 0x40, val);
+ pci_set_drvdata(dev, (void *)val);
return dev->irq;
}
@@ -404,30 +404,25 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
unsigned int rev;
u8 dma_state;
- u32 val;
-
+
DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
hwif->tuneproc = tune_sl82c105;
hwif->selectproc = sl82c105_selectproc;
hwif->resetproc = sl82c105_resetproc;
-
- /* Default to PIO 0 for fallback unless tuned otherwise,
- * we always autotune PIO, this is done before DMA is
- * checked, so there is no risk of accidentally disabling
- * DMA
- */
+
+ /*
+ * Default to PIO 0 for fallback unless tuned otherwise.
+ * We always autotune PIO, this is done before DMA is checked,
+ * so there's no risk of accidentally disabling DMA
+ */
hwif->drives[0].pio_speed = XFER_PIO_0;
hwif->drives[0].autotune = 1;
- hwif->drives[1].pio_speed = XFER_PIO_1;
+ hwif->drives[1].pio_speed = XFER_PIO_0;
hwif->drives[1].autotune = 1;
- pci_read_config_dword(dev, 0x40, &val);
- *((u32 *)&hwif->hwif_data) = val;
-
hwif->atapi_dma = 0;
hwif->mwdma_mask = 0;
hwif->swdma_mask = 0;
@@ -497,7 +492,7 @@ static struct pci_driver driver = {
.probe = sl82c105_init_one,
};
-static int sl82c105_ide_init(void)
+static int __init sl82c105_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 4a1853af3bb..2663ddbd9b6 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -1,9 +1,10 @@
/*
- * linux/drivers/ide/pci/slc90e66.c Version 0.11 September 11, 2002
+ * linux/drivers/ide/pci/slc90e66.c Version 0.13 December 30, 2006
*
* Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com>
*
- * This a look-a-like variation of the ICH0 PIIX4 Ultra-66,
+ * This is a look-alike variation of the ICH0 PIIX4 Ultra-66,
* but this keeps the ISA-Bridge and slots alive.
*
*/
@@ -25,7 +26,7 @@ static u8 slc90e66_ratemask (ide_drive_t *drive)
u8 mode = 2;
if (!eighty_ninty_three(drive))
- mode = min(mode, (u8)1);
+ mode = min_t(u8, mode, 1);
return mode;
}
@@ -64,36 +65,47 @@ static void slc90e66_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);
+ int is_slave = drive->dn & 1;
int master_port = hwif->channel ? 0x42 : 0x40;
int slave_port = 0x44;
unsigned long flags;
u16 master_data;
u8 slave_data;
- /* ISP RTC */
+ int control = 0;
+ /* ISP RTC */
static const u8 timings[][2]= {
- { 0, 0 },
- { 0, 0 },
- { 1, 0 },
- { 2, 1 },
- { 2, 3 }, };
+ { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
- pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
spin_lock_irqsave(&ide_lock, flags);
pci_read_config_word(dev, master_port, &master_data);
+
+ if (pio > 1)
+ control |= 1; /* Programmable timing on */
+ if (drive->media == ide_disk)
+ control |= 4; /* Prefetch, post write */
+ if (pio > 2)
+ control |= 2; /* IORDY */
if (is_slave) {
- master_data = master_data | 0x4000;
- if (pio > 1)
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
+ if (pio > 1) {
/* enable PPE, IE and TIME */
- master_data = master_data | 0x0070;
+ master_data = master_data | (control << 4);
+ }
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)
+ master_data &= ~0x3307;
+ 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);
@@ -158,10 +170,8 @@ static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive));
- if (!(speed)) {
- u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
- speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed);
- }
+ if (!speed)
+ return 0;
(void) slc90e66_tune_chipset(drive, speed);
return ide_dma_enable(drive);
@@ -174,18 +184,17 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
drive->init_speed = 0;
- if (id && (id->capability & 1) && drive->autodma) {
+ if ((id->capability & 1) && drive->autodma) {
- if (ide_use_dma(drive)) {
- if (slc90e66_config_drive_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
+ if (ide_use_dma(drive) && slc90e66_config_drive_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:
- hwif->tuneproc(drive, 5);
+ (void) hwif->speedproc(drive, XFER_PIO_0 +
+ ide_get_best_pio_mode(drive, 255, 4, NULL));
return hwif->ide_dma_off_quietly(drive);
}
/* IORDY not supported */
@@ -203,7 +212,7 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
hwif->irq = hwif->channel ? 15 : 14;
hwif->speedproc = &slc90e66_tune_chipset;
- hwif->tuneproc = &slc90e66_tune_drive;
+ hwif->tuneproc = &slc90e66_tune_drive;
pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
@@ -215,14 +224,16 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
hwif->atapi_dma = 1;
hwif->ultra_mask = 0x1f;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
+ hwif->mwdma_mask = 0x06;
+ hwif->swdma_mask = 0x04;
- if (!(hwif->udma_four))
+ if (!hwif->udma_four) {
/* bit[0(1)]: 0:80, 1:40 */
hwif->udma_four = (reg47 & mask) ? 0 : 1;
+ }
hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
+
if (!noautodma)
hwif->autodma = 1;
hwif->drives[0].autodma = hwif->autodma;
@@ -255,7 +266,7 @@ static struct pci_driver driver = {
.probe = slc90e66_init_one,
};
-static int slc90e66_ide_init(void)
+static int __init slc90e66_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
new file mode 100644
index 00000000000..2ad72bbda34
--- /dev/null
+++ b/drivers/ide/pci/tc86c001.c
@@ -0,0 +1,309 @@
+/*
+ * drivers/ide/pci/tc86c001.c Version 1.00 Dec 12, 2006
+ *
+ * Copyright (C) 2002 Toshiba Corporation
+ * Copyright (C) 2005-2006 MontaVista Software, Inc. <source@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.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static inline u8 tc86c001_ratemask(ide_drive_t *drive)
+{
+ return eighty_ninty_three(drive) ? 2 : 1;
+}
+
+static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00);
+ u16 mode, scr = hwif->INW(scr_port);
+
+ speed = ide_rate_filter(tc86c001_ratemask(drive), speed);
+
+ switch (speed) {
+ case XFER_UDMA_4: mode = 0x00c0; break;
+ case XFER_UDMA_3: mode = 0x00b0; break;
+ case XFER_UDMA_2: mode = 0x00a0; break;
+ case XFER_UDMA_1: mode = 0x0090; break;
+ case XFER_UDMA_0: mode = 0x0080; break;
+ case XFER_MW_DMA_2: mode = 0x0070; break;
+ case XFER_MW_DMA_1: mode = 0x0060; break;
+ case XFER_MW_DMA_0: mode = 0x0050; break;
+ case XFER_PIO_4: mode = 0x0400; break;
+ case XFER_PIO_3: mode = 0x0300; break;
+ case XFER_PIO_2: mode = 0x0200; break;
+ case XFER_PIO_1: mode = 0x0100; break;
+ case XFER_PIO_0:
+ default: mode = 0x0000; break;
+ }
+
+ scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
+ scr |= mode;
+ hwif->OUTW(scr, scr_port);
+
+ return ide_config_drive_speed(drive, speed);
+}
+
+static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
+{
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
+}
+
+/*
+ * HACKITY HACK
+ *
+ * This is a workaround for the limitation 5 of the TC86C001 IDE controller:
+ * if a DMA transfer terminates prematurely, the controller leaves the device's
+ * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or
+ * set the interrupt bit in the DMA status register), thus no PCI interrupt
+ * will occur until a DMA transfer has been successfully completed.
+ *
+ * We work around this by initiating dummy, zero-length DMA transfer on
+ * a DMA timeout expiration. I found no better way to do this with the current
+ * IDE core than to temporarily replace a higher level driver's timer expiry
+ * handler with our own backing up to that handler in case our recovery fails.
+ */
+static int tc86c001_timer_expiry(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_expiry_t *expiry = ide_get_hwifdata(hwif);
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+
+ /* Restore a higher level driver's expiry handler first. */
+ hwgroup->expiry = expiry;
+
+ if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */
+ unsigned long sc_base = hwif->config_data;
+ unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
+ u8 dma_cmd = hwif->INB(hwif->dma_command);
+
+ printk(KERN_WARNING "%s: DMA interrupt possibly stuck, "
+ "attempting recovery...\n", drive->name);
+
+ /* Stop DMA */
+ hwif->OUTB(dma_cmd & ~0x01, hwif->dma_command);
+
+ /* Setup the dummy DMA transfer */
+ hwif->OUTW(0, sc_base + 0x0a); /* Sector Count */
+ hwif->OUTW(0, twcr_port); /* Transfer Word Count 1 or 2 */
+
+ /* Start the dummy DMA transfer */
+ hwif->OUTB(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */
+ hwif->OUTB(0x01, hwif->dma_command); /* set START_STOPBM */
+
+ /*
+ * If an interrupt was pending, it should come thru shortly.
+ * If not, a higher level driver's expiry handler should
+ * eventually cause some kind of recovery from the DMA stall.
+ */
+ return WAIT_MIN_SLEEP;
+ }
+
+ /* Chain to the restored expiry handler if DMA wasn't active. */
+ if (likely(expiry != NULL))
+ return expiry(drive);
+
+ /* If there was no handler, "emulate" that for ide_timer_expiry()... */
+ return -1;
+}
+
+static void tc86c001_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ unsigned long sc_base = hwif->config_data;
+ unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
+ unsigned long nsectors = hwgroup->rq->nr_sectors;
+
+ /*
+ * We have to manually load the sector count and size into
+ * the appropriate system control registers for DMA to work
+ * with LBA48 and ATAPI devices...
+ */
+ hwif->OUTW(nsectors, sc_base + 0x0a); /* Sector Count */
+ hwif->OUTW(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */
+
+ /* Install our timeout expiry hook, saving the current handler... */
+ ide_set_hwifdata(hwif, hwgroup->expiry);
+ hwgroup->expiry = &tc86c001_timer_expiry;
+
+ ide_dma_start(drive);
+}
+
+static int tc86c001_busproc(ide_drive_t *drive, int state)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long sc_base = hwif->config_data;
+ u16 scr1;
+
+ /* System Control 1 Register bit 11 (ATA Hard Reset) read */
+ scr1 = hwif->INW(sc_base + 0x00);
+
+ switch (state) {
+ case BUSSTATE_ON:
+ if (!(scr1 & 0x0800))
+ return 0;
+ scr1 &= ~0x0800;
+
+ hwif->drives[0].failures = hwif->drives[1].failures = 0;
+ break;
+ case BUSSTATE_OFF:
+ if (scr1 & 0x0800)
+ return 0;
+ scr1 |= 0x0800;
+
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* System Control 1 Register bit 11 (ATA Hard Reset) write */
+ hwif->OUTW(scr1, sc_base + 0x00);
+ return 0;
+}
+
+static int config_chipset_for_dma(ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, tc86c001_ratemask(drive));
+
+ if (!speed)
+ return 0;
+
+ (void) tc86c001_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ if ((id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive) && 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:
+ tc86c001_tune_drive(drive, 255);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
+{
+ unsigned long sc_base = pci_resource_start(hwif->pci_dev, 5);
+ u16 scr1 = hwif->INW(sc_base + 0x00);;
+
+ /* System Control 1 Register bit 15 (Soft Reset) set */
+ hwif->OUTW(scr1 | 0x8000, sc_base + 0x00);
+
+ /* System Control 1 Register bit 14 (FIFO Reset) set */
+ hwif->OUTW(scr1 | 0x4000, sc_base + 0x00);
+
+ /* System Control 1 Register: reset clear */
+ hwif->OUTW(scr1 & ~0xc000, sc_base + 0x00);
+
+ /* Store the system control register base for convenience... */
+ hwif->config_data = sc_base;
+
+ hwif->tuneproc = &tc86c001_tune_drive;
+ hwif->speedproc = &tc86c001_tune_chipset;
+ hwif->busproc = &tc86c001_busproc;
+
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
+ return;
+
+ /*
+ * Sector Count Control Register bits 0 and 1 set:
+ * software sets Sector Count Register for master and slave device
+ */
+ hwif->OUTW(0x0003, sc_base + 0x0c);
+
+ /* Sector Count Register limit */
+ hwif->rqsize = 0xffff;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x1f;
+ hwif->mwdma_mask = 0x07;
+
+ hwif->ide_dma_check = &tc86c001_config_drive_xfer_rate;
+ hwif->dma_start = &tc86c001_dma_start;
+
+ if (!hwif->udma_four) {
+ /*
+ * System Control 1 Register bit 13 (PDIAGN):
+ * 0=80-pin cable, 1=40-pin cable
+ */
+ scr1 = hwif->INW(sc_base + 0x00);
+ hwif->udma_four = (scr1 & 0x2000) ? 0 : 1;
+ }
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+}
+
+static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
+ const char *name)
+{
+ int err = pci_request_region(dev, 5, name);
+
+ if (err)
+ printk(KERN_ERR "%s: system control regs already in use", name);
+ return err;
+}
+
+static ide_pci_device_t tc86c001_chipset __devinitdata = {
+ .name = "TC86C001",
+ .init_chipset = init_chipset_tc86c001,
+ .init_hwif = init_hwif_tc86c001,
+ .channels = 1,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD
+};
+
+static int __devinit tc86c001_init_one(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &tc86c001_chipset);
+}
+
+static struct pci_device_id tc86c001_pci_tbl[] = {
+ { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "TC86C001",
+ .id_table = tc86c001_pci_tbl,
+ .probe = tc86c001_init_one
+};
+
+static int __init tc86c001_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+module_init(tc86c001_ide_init);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index 56d84931d6d..b13cce1fd1a 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -173,7 +173,7 @@ static struct pci_driver driver = {
.probe = triflex_init_one,
};
-static int triflex_ide_init(void)
+static int __init triflex_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index 2a282529bfc..174b88c4780 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -355,7 +355,7 @@ static struct pci_driver driver = {
.probe = trm290_init_one,
};
-static int trm290_ide_init(void)
+static int __init trm290_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index 61f1a9665a7..6fb6e50b823 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -78,6 +78,8 @@ static struct via_isa_bridge {
u8 rev_max;
u16 flags;
} via_isa_bridges[] = {
+ { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
@@ -123,7 +125,7 @@ struct via82cxxx_dev
static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
{
struct pci_dev *dev = hwif->pci_dev;
- struct via82cxxx_dev *vdev = ide_get_hwifdata(hwif);
+ struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev);
u8 t;
if (~vdev->via_config->flags & VIA_BAD_AST) {
@@ -162,7 +164,7 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
static int via_set_drive(ide_drive_t *drive, u8 speed)
{
ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
- struct via82cxxx_dev *vdev = ide_get_hwifdata(drive->hwif);
+ struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev);
struct ide_timing t, p;
unsigned int T, UT;
@@ -225,7 +227,7 @@ static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
static int via82cxxx_ide_dma_check (ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- struct via82cxxx_dev *vdev = ide_get_hwifdata(hwif);
+ struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev);
u16 w80 = hwif->udma_four;
u16 speed = ide_find_best_mode(drive,
@@ -262,6 +264,53 @@ static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
return via_config;
}
+/*
+ * Check and handle 80-wire cable presence
+ */
+static void __devinit via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
+{
+ int i;
+
+ switch (vdev->via_config->flags & VIA_UDMA) {
+ case VIA_UDMA_66:
+ for (i = 24; i >= 0; i -= 8)
+ if (((u >> (i & 16)) & 8) &&
+ ((u >> i) & 0x20) &&
+ (((u >> i) & 7) < 2)) {
+ /*
+ * 2x PCI clock and
+ * UDMA w/ < 3T/cycle
+ */
+ vdev->via_80w |= (1 << (1 - (i >> 4)));
+ }
+ break;
+
+ case VIA_UDMA_100:
+ for (i = 24; i >= 0; i -= 8)
+ if (((u >> i) & 0x10) ||
+ (((u >> i) & 0x20) &&
+ (((u >> i) & 7) < 4))) {
+ /* BIOS 80-wire bit or
+ * UDMA w/ < 60ns/cycle
+ */
+ vdev->via_80w |= (1 << (1 - (i >> 4)));
+ }
+ break;
+
+ case VIA_UDMA_133:
+ for (i = 24; i >= 0; i -= 8)
+ if (((u >> i) & 0x10) ||
+ (((u >> i) & 0x20) &&
+ (((u >> i) & 7) < 6))) {
+ /* BIOS 80-wire bit or
+ * UDMA w/ < 60ns/cycle
+ */
+ vdev->via_80w |= (1 << (1 - (i >> 4)));
+ }
+ break;
+ }
+}
+
/**
* init_chipset_via82cxxx - initialization handler
* @dev: PCI device
@@ -274,14 +323,22 @@ static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const char *name)
{
struct pci_dev *isa = NULL;
+ struct via82cxxx_dev *vdev;
struct via_isa_bridge *via_config;
u8 t, v;
- unsigned int u;
+ u32 u;
+
+ vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ if (!vdev) {
+ printk(KERN_ERR "VP_IDE: out of memory :(\n");
+ return -ENOMEM;
+ }
+ pci_set_drvdata(dev, vdev);
/*
* Find the ISA bridge to see how good the IDE is.
*/
- via_config = via_config_find(&isa);
+ vdev->via_config = via_config = via_config_find(&isa);
/* We checked this earlier so if it fails here deeep badness
is involved */
@@ -289,16 +346,17 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const
BUG_ON(!via_config->id);
/*
- * Setup or disable Clk66 if appropriate
+ * Detect cable and configure Clk66
*/
+ pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+
+ via_cable_detect(vdev, u);
if ((via_config->flags & VIA_UDMA) == VIA_UDMA_66) {
/* Enable Clk66 */
- pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008);
} else if (via_config->flags & VIA_BAD_CLK66) {
/* Would cause trouble on 596a and 686 */
- pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
}
@@ -367,75 +425,11 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const
return 0;
}
-/*
- * Check and handle 80-wire cable presence
- */
-static void __devinit via_cable_detect(struct pci_dev *dev, struct via82cxxx_dev *vdev)
-{
- unsigned int u;
- int i;
- pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-
- switch (vdev->via_config->flags & VIA_UDMA) {
-
- case VIA_UDMA_66:
- for (i = 24; i >= 0; i -= 8)
- if (((u >> (i & 16)) & 8) &&
- ((u >> i) & 0x20) &&
- (((u >> i) & 7) < 2)) {
- /*
- * 2x PCI clock and
- * UDMA w/ < 3T/cycle
- */
- vdev->via_80w |= (1 << (1 - (i >> 4)));
- }
- break;
-
- case VIA_UDMA_100:
- for (i = 24; i >= 0; i -= 8)
- if (((u >> i) & 0x10) ||
- (((u >> i) & 0x20) &&
- (((u >> i) & 7) < 4))) {
- /* BIOS 80-wire bit or
- * UDMA w/ < 60ns/cycle
- */
- vdev->via_80w |= (1 << (1 - (i >> 4)));
- }
- break;
-
- case VIA_UDMA_133:
- for (i = 24; i >= 0; i -= 8)
- if (((u >> i) & 0x10) ||
- (((u >> i) & 0x20) &&
- (((u >> i) & 7) < 6))) {
- /* BIOS 80-wire bit or
- * UDMA w/ < 60ns/cycle
- */
- vdev->via_80w |= (1 << (1 - (i >> 4)));
- }
- break;
-
- }
-}
-
static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
{
- struct via82cxxx_dev *vdev = kmalloc(sizeof(struct via82cxxx_dev),
- GFP_KERNEL);
- struct pci_dev *isa = NULL;
+ struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev);
int i;
- if (vdev == NULL) {
- printk(KERN_ERR "VP_IDE: out of memory :(\n");
- return;
- }
-
- memset(vdev, 0, sizeof(struct via82cxxx_dev));
- ide_set_hwifdata(hwif, vdev);
-
- vdev->via_config = via_config_find(&isa);
- via_cable_detect(hwif->pci_dev, vdev);
-
hwif->autodma = 0;
hwif->tuneproc = &via82cxxx_tune_drive;
@@ -512,6 +506,7 @@ static struct pci_device_id via_pci_tbl[] = {
{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_6410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_SATA_EIDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, via_pci_tbl);
@@ -522,7 +517,7 @@ static struct pci_driver driver = {
.probe = via_init_one,
};
-static int via_ide_init(void)
+static int __init via_ide_init(void)
{
return ide_pci_register_driver(&driver);
}
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index 0719b648482..a52c80fe7d3 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -783,10 +783,11 @@ static LIST_HEAD(ide_pci_drivers);
* Returns are the same as for pci_register_driver
*/
-int __ide_pci_register_driver(struct pci_driver *driver, struct module *module)
+int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
+ const char *mod_name)
{
if(!pre_init)
- return __pci_register_driver(driver, module);
+ return __pci_register_driver(driver, module, mod_name);
driver->driver.owner = module;
list_add_tail(&driver->node, &ide_pci_drivers);
return 0;
@@ -844,11 +845,11 @@ void __init ide_scan_pcibus (int scan_direction)
pre_init = 0;
if (!scan_direction) {
- while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
ide_scan_pcidev(dev);
}
} else {
- while ((dev = pci_find_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
ide_scan_pcidev(dev);
}
}
@@ -862,6 +863,6 @@ void __init ide_scan_pcibus (int scan_direction)
{
list_del(l);
d = list_entry(l, struct pci_driver, node);
- __pci_register_driver(d, d->driver.owner);
+ __pci_register_driver(d, d->driver.owner, d->driver.mod_name);
}
}
diff --git a/drivers/ieee1394/.gitignore b/drivers/ieee1394/.gitignore
deleted file mode 100644
index 33da10a2532..00000000000
--- a/drivers/ieee1394/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-oui.c
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index e7d56573fe5..b8a47342cd2 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -35,20 +35,6 @@ config IEEE1394_VERBOSEDEBUG
Say Y if you really want or need the debugging output, everyone
else says N.
-config IEEE1394_OUI_DB
- bool "OUI Database built-in (deprecated)"
- depends on IEEE1394
- help
- If you say Y here, then an OUI list (vendor unique ID's) will be
- compiled into the ieee1394 module. This doesn't really do much
- except being able to display the vendor of a hardware node. The
- downside is that it adds about 300k to the size of the module,
- or kernel (depending on whether you compile ieee1394 as a
- module, or static in the kernel).
-
- This option is not needed for userspace programs like gscanbus
- to show this information.
-
config IEEE1394_EXTRA_CONFIG_ROMS
bool "Build in extra config rom entries for certain functionality"
depends on IEEE1394
@@ -66,13 +52,6 @@ config IEEE1394_CONFIG_ROM_IP1394
with MacOSX and WinXP IP-over-1394), enable this option and the
eth1394 option below.
-config IEEE1394_EXPORT_FULL_API
- bool "Export all symbols of ieee1394's API (deprecated)"
- depends on IEEE1394
- default n
- help
- This option will be removed soon. Don't worry, say N.
-
comment "Device Drivers"
depends on IEEE1394
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
index d9650d3d77a..489c133664d 100644
--- a/drivers/ieee1394/Makefile
+++ b/drivers/ieee1394/Makefile
@@ -5,9 +5,6 @@
ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
highlevel.o csr.o nodemgr.o dma.o iso.o \
csr1212.o config_roms.o
-ifdef CONFIG_IEEE1394_OUI_DB
-ieee1394-objs += oui.o
-endif
obj-$(CONFIG_IEEE1394) += ieee1394.o
obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
@@ -18,10 +15,3 @@ obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
-quiet_cmd_oui2c = OUI2C $@
- cmd_oui2c = $(CONFIG_SHELL) $(srctree)/$(src)/oui2c.sh < $< > $@
-
-targets := oui.c
-$(obj)/oui.o: $(obj)/oui.c
-$(obj)/oui.c: $(src)/oui.db $(src)/oui2c.sh FORCE
- $(call if_changed,oui2c)
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index 586f71e7346..c28f639823d 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -47,14 +47,14 @@
#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
#define __L (1 << CSR1212_KV_TYPE_LEAF)
static const u_int8_t csr1212_key_id_type_map[0x30] = {
- 0, /* Reserved */
+ __C, /* used by Apple iSight */
__D | __L, /* Descriptor */
__I | __D | __L, /* Bus_Dependent_Info */
__I | __D | __L, /* Vendor */
__I, /* Hardware_Version */
0, 0, /* Reserved */
- __D | __L, /* Module */
- 0, 0, 0, 0, /* Reserved */
+ __D | __L | __I, /* Module */
+ __I, 0, 0, 0, /* used by Apple iSight, Reserved */
__I, /* Node_Capabilities */
__L, /* EUI_64 */
0, 0, 0, /* Reserved */
@@ -1234,6 +1234,12 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
csr->private);
if (ret != CSR1212_SUCCESS)
return ret;
+
+ /* check ROM header's info_length */
+ if (i == 0 &&
+ CSR1212_BE32_TO_CPU(csr->cache_head->data[0]) >> 24 !=
+ bytes_to_quads(csr->bus_info_len) - 1)
+ return CSR1212_EINVAL;
}
bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
@@ -1250,9 +1256,6 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
return ret;
}
- if (bytes_to_quads(csr->bus_info_len - sizeof(csr1212_quad_t)) != bi->length)
- return CSR1212_EINVAL;
-
#if 0
/* Apparently there are too many differnt wrong implementations of the
* CRC algorithm that verifying them is moot. */
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 1084da4d88a..55d6ae664fd 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -2255,49 +2255,37 @@ static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes
return 0;
}
-static void dv1394_un_init(struct video_card *video)
+static void dv1394_remove_host(struct hpsb_host *host)
{
- /* obviously nobody has the driver open at this point */
- do_dv1394_shutdown(video, 1);
- kfree(video);
-}
-
-
-static void dv1394_remove_host (struct hpsb_host *host)
-{
- struct video_card *video;
+ struct video_card *video, *tmp_video;
unsigned long flags;
- int id = host->id;
+ int found_ohci_card = 0;
- /* We only work with the OHCI-1394 driver */
- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
- return;
-
- /* find the corresponding video_cards */
do {
- struct video_card *tmp_vid;
-
video = NULL;
-
spin_lock_irqsave(&dv1394_cards_lock, flags);
- list_for_each_entry(tmp_vid, &dv1394_cards, list) {
- if ((tmp_vid->id >> 2) == id) {
- list_del(&tmp_vid->list);
- video = tmp_vid;
+ list_for_each_entry(tmp_video, &dv1394_cards, list) {
+ if ((tmp_video->id >> 2) == host->id) {
+ list_del(&tmp_video->list);
+ video = tmp_video;
+ found_ohci_card = 1;
break;
}
}
spin_unlock_irqrestore(&dv1394_cards_lock, flags);
- if (video)
- dv1394_un_init(video);
- } while (video != NULL);
+ if (video) {
+ do_dv1394_shutdown(video, 1);
+ kfree(video);
+ }
+ } while (video);
- class_device_destroy(hpsb_protocol_class,
- MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)));
+ if (found_ohci_card)
+ class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
+ IEEE1394_MINOR_BLOCK_DV1394 * 16 + (host->id << 2)));
}
-static void dv1394_add_host (struct hpsb_host *host)
+static void dv1394_add_host(struct hpsb_host *host)
{
struct ti_ohci *ohci;
int id = host->id;
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index ee82a5320bf..32a13092193 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -190,14 +190,19 @@ int hpsb_add_host(struct hpsb_host *host)
{
if (hpsb_default_host_entry(host))
return -ENOMEM;
-
hpsb_add_extra_config_roms(host);
-
highlevel_add_host(host);
-
return 0;
}
+void hpsb_resume_host(struct hpsb_host *host)
+{
+ if (host->driver->set_hw_config_rom)
+ host->driver->set_hw_config_rom(host,
+ host->csr.rom->bus_info_data);
+ host->driver->devctl(host, RESET_BUS, SHORT_RESET);
+}
+
void hpsb_remove_host(struct hpsb_host *host)
{
host->is_shutdown = 1;
@@ -206,9 +211,7 @@ void hpsb_remove_host(struct hpsb_host *host)
flush_scheduled_work();
host->driver = &dummy_driver;
-
highlevel_remove_host(host);
-
hpsb_remove_extra_config_roms(host);
class_device_unregister(&host->class_dev);
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index d553e38c954..4bf4fb7f67b 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -61,9 +61,9 @@ struct hpsb_host {
struct device device;
struct class_device class_dev;
- int update_config_rom;
struct delayed_work delayed_reset;
- unsigned int config_roms;
+ unsigned config_roms:31;
+ unsigned update_config_rom:1;
struct list_head addr_space;
u64 low_addr_space; /* upper bound of physical DMA area */
@@ -200,7 +200,8 @@ struct hpsb_host_driver {
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);
+void hpsb_resume_host(struct hpsb_host *host);
+void hpsb_remove_host(struct hpsb_host *host);
/* 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
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 9a48ca20d1f..1521e57e124 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -1178,6 +1178,7 @@ module_exit(ieee1394_cleanup);
/** hosts.c **/
EXPORT_SYMBOL(hpsb_alloc_host);
EXPORT_SYMBOL(hpsb_add_host);
+EXPORT_SYMBOL(hpsb_resume_host);
EXPORT_SYMBOL(hpsb_remove_host);
EXPORT_SYMBOL(hpsb_update_config_rom_image);
@@ -1195,10 +1196,6 @@ EXPORT_SYMBOL(hpsb_selfid_complete);
EXPORT_SYMBOL(hpsb_packet_sent);
EXPORT_SYMBOL(hpsb_packet_received);
EXPORT_SYMBOL_GPL(hpsb_disable_irm);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(hpsb_send_phy_config);
-EXPORT_SYMBOL(hpsb_send_packet_and_wait);
-#endif
/** ieee1394_transactions.c **/
EXPORT_SYMBOL(hpsb_get_tlabel);
@@ -1229,20 +1226,12 @@ EXPORT_SYMBOL(hpsb_set_hostinfo_key);
EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
EXPORT_SYMBOL(hpsb_set_hostinfo);
EXPORT_SYMBOL(highlevel_host_reset);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(highlevel_add_host);
-EXPORT_SYMBOL(highlevel_remove_host);
-#endif
/** nodemgr.c **/
EXPORT_SYMBOL(hpsb_node_fill_packet);
EXPORT_SYMBOL(hpsb_node_write);
EXPORT_SYMBOL(__hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(ieee1394_bus_type);
-EXPORT_SYMBOL(nodemgr_for_each_host);
-#endif
/** csr.c **/
EXPORT_SYMBOL(hpsb_update_config_rom);
@@ -1287,13 +1276,3 @@ EXPORT_SYMBOL(csr1212_read);
EXPORT_SYMBOL(csr1212_parse_keyval);
EXPORT_SYMBOL(_csr1212_read_keyval);
EXPORT_SYMBOL(_csr1212_destroy_keyval);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(csr1212_create_csr);
-EXPORT_SYMBOL(csr1212_init_local_csr);
-EXPORT_SYMBOL(csr1212_new_immediate);
-EXPORT_SYMBOL(csr1212_associate_keyval);
-EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
-EXPORT_SYMBOL(csr1212_destroy_csr);
-EXPORT_SYMBOL(csr1212_generate_csr_image);
-EXPORT_SYMBOL(csr1212_parse_csr);
-#endif
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index af4a78a8ef3..536ba3f580f 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -217,7 +217,7 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
/* return the index (within a minor number block) of a file */
static inline unsigned char ieee1394_file_to_instance(struct file *file)
{
- return file->f_dentry->d_inode->i_cindex;
+ return file->f_path.dentry->d_inode->i_cindex;
}
extern int hpsb_disable_irm;
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 61307ca296a..ba9faeff479 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -41,22 +41,6 @@ struct nodemgr_csr_info {
};
-static char *nodemgr_find_oui_name(int oui)
-{
-#ifdef CONFIG_IEEE1394_OUI_DB
- extern struct oui_list_struct {
- int oui;
- char *name;
- } oui_list[];
- int i;
-
- for (i = 0; oui_list[i].name; i++)
- if (oui_list[i].oui == oui)
- return oui_list[i].name;
-#endif
- return NULL;
-}
-
/*
* Correct the speed map entry. This is necessary
* - for nodes with link speed < phy speed,
@@ -274,7 +258,6 @@ static struct device_driver nodemgr_mid_layer_driver = {
struct device nodemgr_dev_template_host = {
.bus = &ieee1394_bus_type,
.release = nodemgr_release_host,
- .driver = &nodemgr_mid_layer_driver,
};
@@ -473,11 +456,9 @@ fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n")
fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")
fw_attr_td(ne, struct node_entry, vendor_name_kv)
-fw_attr(ne, struct node_entry, vendor_oui, const char *, "%s\n")
fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")
fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, guid_vendor_oui, const char *, "%s\n")
fw_attr(ne, struct node_entry, in_limbo, int, "%d\n");
static struct device_attribute *const fw_ne_attrs[] = {
@@ -503,7 +484,6 @@ fw_attr(ud, struct unit_directory, model_id, unsigned int, "0x%06x\n")
fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n")
fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n")
fw_attr_td(ud, struct unit_directory, vendor_name_kv)
-fw_attr(ud, struct unit_directory, vendor_oui, const char *, "%s\n")
fw_attr_td(ud, struct unit_directory, model_name_kv)
static struct device_attribute *const fw_ud_attrs[] = {
@@ -865,7 +845,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
ne->guid = guid;
ne->guid_vendor_id = (guid >> 40) & 0xffffff;
- ne->guid_vendor_oui = nodemgr_find_oui_name(ne->guid_vendor_id);
ne->csr = csr;
memcpy(&ne->device, &nodemgr_dev_template_ne,
@@ -885,9 +864,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
goto fail_classdevreg;
get_device(&ne->device);
- if (ne->guid_vendor_oui &&
- device_create_file(&ne->device, &dev_attr_ne_guid_vendor_oui))
- goto fail_addoiu;
nodemgr_create_ne_dev_files(ne);
nodemgr_update_bus_options(ne);
@@ -898,8 +874,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
return ne;
-fail_addoiu:
- put_device(&ne->device);
fail_classdevreg:
device_unregister(&ne->device);
fail_devreg:
@@ -975,15 +949,10 @@ static void nodemgr_register_device(struct node_entry *ne,
goto fail_classdevreg;
get_device(&ud->device);
- if (ud->vendor_oui &&
- device_create_file(&ud->device, &dev_attr_ud_vendor_oui))
- goto fail_addoui;
nodemgr_create_ud_dev_files(ud);
return;
-fail_addoui:
- put_device(&ud->device);
fail_classdevreg:
device_unregister(&ud->device);
fail_devreg:
@@ -1020,9 +989,6 @@ static struct unit_directory *nodemgr_process_unit_directory
if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
ud->vendor_id = kv->value.immediate;
ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
-
- if (ud->vendor_id)
- ud->vendor_oui = nodemgr_find_oui_name(ud->vendor_id);
}
break;
@@ -1153,9 +1119,6 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
switch (kv->key.id) {
case CSR1212_KV_ID_VENDOR:
ne->vendor_id = kv->value.immediate;
-
- if (ne->vendor_id)
- ne->vendor_oui = nodemgr_find_oui_name(ne->vendor_id);
break;
case CSR1212_KV_ID_NODE_CAPABILITIES:
@@ -1183,9 +1146,6 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
last_key_id = kv->key.id;
}
- if (ne->vendor_oui &&
- device_create_file(&ne->device, &dev_attr_ne_vendor_oui))
- goto fail;
if (ne->vendor_name_kv &&
device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv))
goto fail;
@@ -1889,22 +1849,31 @@ int init_ieee1394_nodemgr(void)
error = class_register(&nodemgr_ne_class);
if (error)
- return error;
-
+ goto fail_ne;
error = class_register(&nodemgr_ud_class);
- if (error) {
- class_unregister(&nodemgr_ne_class);
- return error;
- }
+ if (error)
+ goto fail_ud;
error = driver_register(&nodemgr_mid_layer_driver);
+ if (error)
+ goto fail_ml;
+ /* This driver is not used if nodemgr is off (disable_nodemgr=1). */
+ nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver;
+
hpsb_register_highlevel(&nodemgr_highlevel);
return 0;
+
+fail_ml:
+ class_unregister(&nodemgr_ud_class);
+fail_ud:
+ class_unregister(&nodemgr_ne_class);
+fail_ne:
+ return error;
}
void cleanup_ieee1394_nodemgr(void)
{
hpsb_unregister_highlevel(&nodemgr_highlevel);
-
+ driver_unregister(&nodemgr_mid_layer_driver);
class_unregister(&nodemgr_ud_class);
class_unregister(&nodemgr_ne_class);
}
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
index e25cbadb8be..4147303ad44 100644
--- a/drivers/ieee1394/nodemgr.h
+++ b/drivers/ieee1394/nodemgr.h
@@ -70,7 +70,6 @@ struct unit_directory {
quadlet_t vendor_id;
struct csr1212_keyval *vendor_name_kv;
- const char *vendor_oui;
quadlet_t model_id;
struct csr1212_keyval *model_name_kv;
@@ -93,7 +92,6 @@ struct unit_directory {
struct node_entry {
u64 guid; /* GUID of this node */
u32 guid_vendor_id; /* Top 24bits of guid */
- const char *guid_vendor_oui; /* OUI name of guid vendor id */
struct hpsb_host *host; /* Host this node is attached to */
nodeid_t nodeid; /* NodeID */
@@ -104,7 +102,6 @@ struct node_entry {
/* The following is read from the config rom */
u32 vendor_id;
struct csr1212_keyval *vendor_name_kv;
- const char *vendor_oui;
u32 capabilities;
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 628130a58af..5729e412cc4 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -3281,14 +3281,11 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!",
(unsigned long long)pci_resource_len(dev, 0));
- /* Seems PCMCIA handles this internally. Not sure why. Seems
- * pretty bogus to force a driver to special case this. */
-#ifndef PCMCIA
- if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME))
+ if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE,
+ OHCI1394_DRIVER_NAME))
FAIL(-ENOMEM, "MMIO resource (0x%llx - 0x%llx) unavailable",
(unsigned long long)ohci_base,
(unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE);
-#endif
ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE);
@@ -3509,10 +3506,8 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
iounmap(ohci->registers);
case OHCI_INIT_HAVE_MEM_REGION:
-#ifndef PCMCIA
release_mem_region(pci_resource_start(ohci->dev, 0),
OHCI1394_REGISTER_SIZE);
-#endif
#ifdef CONFIG_PPC_PMAC
/* On UniNorth, power down the cable and turn off the chip clock
@@ -3541,9 +3536,6 @@ static int ohci1394_pci_suspend(struct pci_dev *pdev, pm_message_t state)
int err;
struct ti_ohci *ohci = pci_get_drvdata(pdev);
- printk(KERN_INFO "%s does not fully support suspend and resume yet\n",
- OHCI1394_DRIVER_NAME);
-
if (!ohci) {
printk(KERN_ERR "%s: tried to suspend nonexisting host\n",
OHCI1394_DRIVER_NAME);
@@ -3630,15 +3622,14 @@ static int ohci1394_pci_resume(struct pci_dev *pdev)
mdelay(50);
ohci_initialize(ohci);
+ hpsb_resume_host(ohci->host);
return 0;
}
#endif /* CONFIG_PM */
-#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
-
static struct pci_device_id ohci1394_pci_tbl[] = {
{
- .class = PCI_CLASS_FIREWIRE_OHCI,
+ .class = PCI_CLASS_SERIAL_FIREWIRE_OHCI,
.class_mask = PCI_ANY_ID,
.vendor = PCI_ANY_ID,
.device = PCI_ANY_ID,
diff --git a/drivers/ieee1394/oui.db b/drivers/ieee1394/oui.db
deleted file mode 100644
index 592c8a60d01..00000000000
--- a/drivers/ieee1394/oui.db
+++ /dev/null
@@ -1,7048 +0,0 @@
-000000 XEROX CORPORATION
-000001 XEROX CORPORATION
-000002 XEROX CORPORATION
-000003 XEROX CORPORATION
-000004 XEROX CORPORATION
-000005 XEROX CORPORATION
-000006 XEROX CORPORATION
-000007 XEROX CORPORATION
-000008 XEROX CORPORATION
-000009 XEROX CORPORATION
-00000A OMRON TATEISI ELECTRONICS CO.
-00000B MATRIX CORPORATION
-00000C CISCO SYSTEMS, INC.
-00000D FIBRONICS LTD.
-00000E FUJITSU LIMITED
-00000F NEXT, INC.
-000010 SYTEK INC.
-000011 NORMEREL SYSTEMES
-000012 INFORMATION TECHNOLOGY LIMITED
-000013 CAMEX
-000014 NETRONIX
-000015 DATAPOINT CORPORATION
-000016 DU PONT PIXEL SYSTEMS .
-000017 TEKELEC
-000018 WEBSTER COMPUTER CORPORATION
-000019 APPLIED DYNAMICS INTERNATIONAL
-00001A ADVANCED MICRO DEVICES
-00001B NOVELL INC.
-00001C BELL TECHNOLOGIES
-00001D CABLETRON SYSTEMS, INC.
-00001E TELSIST INDUSTRIA ELECTRONICA
-00001F Telco Systems, Inc.
-000020 DATAINDUSTRIER DIAB AB
-000021 SUREMAN COMP. & COMMUN. CORP.
-000022 VISUAL TECHNOLOGY INC.
-000023 ABB INDUSTRIAL SYSTEMS AB
-000024 CONNECT AS
-000025 RAMTEK CORP.
-000026 SHA-KEN CO., LTD.
-000027 JAPAN RADIO COMPANY
-000028 PRODIGY SYSTEMS CORPORATION
-000029 IMC NETWORKS CORP.
-00002A TRW - SEDD/INP
-00002B CRISP AUTOMATION, INC
-00002C AUTOTOTE LIMITED
-00002D CHROMATICS INC
-00002E SOCIETE EVIRA
-00002F TIMEPLEX INC.
-000030 VG LABORATORY SYSTEMS LTD
-000031 QPSX COMMUNICATIONS PTY LTD
-000032 Marconi plc
-000033 EGAN MACHINERY COMPANY
-000034 NETWORK RESOURCES CORPORATION
-000035 SPECTRAGRAPHICS CORPORATION
-000036 ATARI CORPORATION
-000037 OXFORD METRICS LIMITED
-000038 CSS LABS
-000039 TOSHIBA CORPORATION
-00003A CHYRON CORPORATION
-00003B i Controls, Inc.
-00003C AUSPEX SYSTEMS INC.
-00003D UNISYS
-00003E SIMPACT
-00003F SYNTREX, INC.
-000040 APPLICON, INC.
-000041 ICE CORPORATION
-000042 METIER MANAGEMENT SYSTEMS LTD.
-000043 MICRO TECHNOLOGY
-000044 CASTELLE CORPORATION
-000045 FORD AEROSPACE & COMM. CORP.
-000046 OLIVETTI NORTH AMERICA
-000047 NICOLET INSTRUMENTS CORP.
-000048 SEIKO EPSON CORPORATION
-000049 APRICOT COMPUTERS, LTD
-00004A ADC CODENOLL TECHNOLOGY CORP.
-00004B ICL DATA OY
-00004C NEC CORPORATION
-00004D DCI CORPORATION
-00004E AMPEX CORPORATION
-00004F LOGICRAFT, INC.
-000050 RADISYS CORPORATION
-000051 HOB ELECTRONIC GMBH & CO. KG
-000052 Intrusion.com, Inc.
-000053 COMPUCORP
-000054 MODICON, INC.
-000055 COMMISSARIAT A L`ENERGIE ATOM.
-000056 DR. B. STRUCK
-000057 SCITEX CORPORATION LTD.
-000058 RACORE COMPUTER PRODUCTS INC.
-000059 HELLIGE GMBH
-00005A SysKonnect GmbH
-00005B ELTEC ELEKTRONIK AG
-00005C TELEMATICS INTERNATIONAL INC.
-00005D CS TELECOM
-00005E USC INFORMATION SCIENCES INST
-00005F SUMITOMO ELECTRIC IND., LTD.
-000060 KONTRON ELEKTRONIK GMBH
-000061 GATEWAY COMMUNICATIONS
-000062 BULL HN INFORMATION SYSTEMS
-000063 DR.ING.SEUFERT GMBH
-000064 YOKOGAWA DIGITAL COMPUTER CORP
-000065 NETWORK ASSOCIATES, INC.
-000066 TALARIS SYSTEMS, INC.
-000067 SOFT * RITE, INC.
-000068 ROSEMOUNT CONTROLS
-000069 CONCORD COMMUNICATIONS INC
-00006A COMPUTER CONSOLES INC.
-00006B SILICON GRAPHICS INC./MIPS
-00006D CRAY COMMUNICATIONS, LTD.
-00006E ARTISOFT, INC.
-00006F Madge Ltd.
-000070 HCL LIMITED
-000071 ADRA SYSTEMS INC.
-000072 MINIWARE TECHNOLOGY
-000073 SIECOR CORPORATION
-000074 RICOH COMPANY LTD.
-000075 Nortel Networks
-000076 ABEKAS VIDEO SYSTEM
-000077 INTERPHASE CORPORATION
-000078 LABTAM LIMITED
-000079 NETWORTH INCORPORATED
-00007A DANA COMPUTER INC.
-00007B RESEARCH MACHINES
-00007C AMPERE INCORPORATED
-00007D SUN MICROSYSTEMS, INC.
-00007E CLUSTRIX CORPORATION
-00007F LINOTYPE-HELL AG
-000080 CRAY COMMUNICATIONS A/S
-000081 BAY NETWORKS
-000082 LECTRA SYSTEMES SA
-000083 TADPOLE TECHNOLOGY PLC
-000084 SUPERNET
-000085 CANON INC.
-000086 MEGAHERTZ CORPORATION
-000087 HITACHI, LTD.
-000088 COMPUTER NETWORK TECH. CORP.
-000089 CAYMAN SYSTEMS INC.
-00008A DATAHOUSE INFORMATION SYSTEMS
-00008B INFOTRON
-00008C Alloy Computer Products (Australia) Pty Ltd
-00008D VERDIX CORPORATION
-00008E SOLBOURNE COMPUTER, INC.
-00008F RAYTHEON COMPANY
-000090 MICROCOM
-000091 ANRITSU CORPORATION
-000092 COGENT DATA TECHNOLOGIES
-000093 PROTEON INC.
-000094 ASANTE TECHNOLOGIES
-000095 SONY TEKTRONIX CORP.
-000096 MARCONI ELECTRONICS LTD.
-000097 EPOCH SYSTEMS
-000098 CROSSCOMM CORPORATION
-000099 MTX, INC.
-00009A RC COMPUTER A/S
-00009B INFORMATION INTERNATIONAL, INC
-00009C ROLM MIL-SPEC COMPUTERS
-00009D LOCUS COMPUTING CORPORATION
-00009E MARLI S.A.
-00009F AMERISTAR TECHNOLOGIES INC.
-0000A0 TOKYO SANYO ELECTRIC CO. LTD.
-0000A1 MARQUETTE ELECTRIC CO.
-0000A2 BAY NETWORKS
-0000A3 NETWORK APPLICATION TECHNOLOGY
-0000A4 ACORN COMPUTERS LIMITED
-0000A5 COMPATIBLE SYSTEMS CORP.
-0000A6 NETWORK GENERAL CORPORATION
-0000A7 NETWORK COMPUTING DEVICES INC.
-0000A8 STRATUS COMPUTER INC.
-0000A9 NETWORK SYSTEMS CORP.
-0000AA XEROX CORPORATION
-0000AB LOGIC MODELING CORPORATION
-0000AC CONWARE COMPUTER CONSULTING
-0000AD BRUKER INSTRUMENTS INC.
-0000AE DASSAULT ELECTRONIQUE
-0000AF NUCLEAR DATA INSTRUMENTATION
-0000B0 RND-RAD NETWORK DEVICES
-0000B1 ALPHA MICROSYSTEMS INC.
-0000B2 TELEVIDEO SYSTEMS, INC.
-0000B3 CIMLINC INCORPORATED
-0000B4 EDIMAX COMPUTER COMPANY
-0000B5 DATABILITY SOFTWARE SYS. INC.
-0000B6 MICRO-MATIC RESEARCH
-0000B7 DOVE COMPUTER CORPORATION
-0000B8 SEIKOSHA CO., LTD.
-0000B9 MCDONNELL DOUGLAS COMPUTER SYS
-0000BA SIIG, INC.
-0000BB TRI-DATA
-0000BC ALLEN-BRADLEY CO. INC.
-0000BD MITSUBISHI CABLE COMPANY
-0000BE THE NTI GROUP
-0000BF SYMMETRIC COMPUTER SYSTEMS
-0000C0 WESTERN DIGITAL CORPORATION
-0000C1 Madge Ltd.
-0000C2 INFORMATION PRESENTATION TECH.
-0000C3 HARRIS CORP COMPUTER SYS DIV
-0000C4 WATERS DIV. OF MILLIPORE
-0000C5 FARALLON COMPUTING/NETOPIA
-0000C6 EON SYSTEMS
-0000C7 ARIX CORPORATION
-0000C8 ALTOS COMPUTER SYSTEMS
-0000C9 EMULEX CORPORATION
-0000CA APPLITEK
-0000CB COMPU-SHACK ELECTRONIC GMBH
-0000CC DENSAN CO., LTD.
-0000CD Allied Telesyn Research Ltd.
-0000CE MEGADATA CORP.
-0000CF HAYES MICROCOMPUTER PRODUCTS
-0000D0 DEVELCON ELECTRONICS LTD.
-0000D1 ADAPTEC INCORPORATED
-0000D2 SBE, INC.
-0000D3 WANG LABORATORIES INC.
-0000D4 PURE DATA LTD.
-0000D5 MICROGNOSIS INTERNATIONAL
-0000D6 PUNCH LINE HOLDING
-0000D7 DARTMOUTH COLLEGE
-0000D8 NOVELL, INC.
-0000D9 NIPPON TELEGRAPH & TELEPHONE
-0000DA ATEX
-0000DB BRITISH TELECOMMUNICATIONS PLC
-0000DC HAYES MICROCOMPUTER PRODUCTS
-0000DD TCL INCORPORATED
-0000DE CETIA
-0000DF BELL & HOWELL PUB SYS DIV
-0000E0 QUADRAM CORP.
-0000E1 GRID SYSTEMS
-0000E2 ACER TECHNOLOGIES CORP.
-0000E3 INTEGRATED MICRO PRODUCTS LTD
-0000E4 IN2 GROUPE INTERTECHNIQUE
-0000E5 SIGMEX LTD.
-0000E6 APTOR PRODUITS DE COMM INDUST
-0000E7 STAR GATE TECHNOLOGIES
-0000E8 ACCTON TECHNOLOGY CORP.
-0000E9 ISICAD, INC.
-0000EA UPNOD AB
-0000EB MATSUSHITA COMM. IND. CO. LTD.
-0000EC MICROPROCESS
-0000ED APRIL
-0000EE NETWORK DESIGNERS, LTD.
-0000EF KTI
-0000F0 SAMSUNG ELECTRONICS CO., LTD.
-0000F1 MAGNA COMPUTER CORPORATION
-0000F2 SPIDER COMMUNICATIONS
-0000F3 GANDALF DATA LIMITED
-0000F4 ALLIED TELESYN INTERNATIONAL
-0000F5 DIAMOND SALES LIMITED
-0000F6 APPLIED MICROSYSTEMS CORP.
-0000F7 YOUTH KEEP ENTERPRISE CO LTD
-0000F8 DIGITAL EQUIPMENT CORPORATION
-0000F9 QUOTRON SYSTEMS INC.
-0000FA MICROSAGE COMPUTER SYSTEMS INC
-0000FB RECHNER ZUR KOMMUNIKATION
-0000FC MEIKO
-0000FD HIGH LEVEL HARDWARE
-0000FE ANNAPOLIS MICRO SYSTEMS
-0000FF CAMTEC ELECTRONICS LTD.
-000100 EQUIP'TRANS
-000102 3COM CORPORATION
-000103 3COM CORPORATION
-000104 DVICO Co., Ltd.
-000105 BECKHOFF GmbH
-000106 Tews Datentechnik GmbH
-000107 Leiser GmbH
-000108 AVLAB Technology, Inc.
-000109 Nagano Japan Radio Co., Ltd.
-00010A CIS TECHNOLOGY INC.
-00010B Space CyberLink, Inc.
-00010C System Talks Inc.
-00010D CORECO, INC.
-00010E Bri-Link Technologies Co., Ltd
-00010F Nishan Systems, Inc.
-000110 Gotham Networks
-000111 iDigm Inc.
-000112 Shark Multimedia Inc.
-000113 OLYMPUS CORPORATION
-000114 KANDA TSUSHIN KOGYO CO., LTD.
-000115 EXTRATECH CORPORATION
-000116 Netspect Technologies, Inc.
-000117 CANAL +
-000118 EZ Digital Co., Ltd.
-000119 Action Controls Pty. Ltd.
-00011A EEH DataLink GmbH
-00011B Unizone Technologies, Inc.
-00011C Universal Talkware Corporation
-00011D Centillium Communications
-00011E Precidia Technologies, Inc.
-00011F RC Networks, Inc.
-000120 OSCILLOQUARTZ S.A.
-000121 RapidStream Inc.
-000122 Trend Communications, Ltd.
-000123 DIGITAL ELECTRONICS CORP.
-000124 Acer Incorporated
-000125 YAESU MUSEN CO., LTD.
-000126 PAC Labs
-000127 The OPEN Group Limited
-000128 EnjoyWeb, Inc.
-000129 DFI Inc.
-00012A Telematica Sistems Inteligente
-00012B TELENET Co., Ltd.
-00012C Aravox Technologies, Inc.
-00012D Komodo Technology
-00012E PC Partner Ltd.
-00012F Twinhead International Corp
-000130 Extreme Networks
-000131 Detection Systems, Inc.
-000132 Dranetz - BMI
-000133 KYOWA Electronic Instruments C
-000134 SIG Positec Systems AG
-000135 KDC Corp.
-000136 CyberTAN Technology, Inc.
-000137 IT Farm Corporation
-000138 XAVi Technologies Corp.
-000139 Point Multimedia Systems
-00013A SHELCAD COMMUNICATIONS, LTD.
-00013B BNA SYSTEMS
-00013C TIW SYSTEMS
-00013D RiscStation Ltd.
-00013E Ascom Tateco AB
-00013F Neighbor World Co., Ltd.
-000140 Sendtek Corporation
-000141 CABLE PRINT
-000142 Cisco Systems, Inc.
-000143 Cisco Systems, Inc.
-000144 Cereva Networks, Inc.
-000145 WINSYSTEMS, INC.
-000146 Tesco Controls, Inc.
-000147 Zhone Technologies
-000148 X-traWeb Inc.
-000149 T.D.T. Transfer Data Test GmbH
-00014A SONY COMPUTER SCIENCE LABS., I
-00014B Ennovate Networks, Inc.
-00014C Berkeley Process Control
-00014D Shin Kin Enterprises Co., Ltd
-00014E WIN Enterprises, Inc.
-00014F LUMINOUS Networks, Inc.
-000150 GILAT COMMUNICATIONS, LTD.
-000151 Ensemble Communications
-000152 CHROMATEK INC.
-000153 ARCHTEK TELECOM CORPORATION
-000154 G3M Corporation
-000155 Promise Technology, Inc.
-000156 FIREWIREDIRECT.COM, INC.
-000157 SYSWAVE CO., LTD
-000158 Electro Industries/Gauge Tech
-000159 S1 Corporation
-00015A Digital Video Broadcasting
-00015B ITALTEL S.p.A/RF-UP-I
-00015C CADANT INC.
-00015D Sun Microsystems, Inc
-00015E BEST TECHNOLOGY CO., LTD.
-00015F DIGITAL DESIGN GmbH
-000160 ELMEX Co., LTD.
-000161 Meta Machine Technology
-000162 Cygnet Technologies, Inc.
-000163 Cisco Systems, Inc.
-000164 Cisco Systems, Inc.
-000165 AirSwitch Corporation
-000166 TC GROUP A/S
-000167 HIOKI E.E. CORPORATION
-000168 VITANA CORPORATION
-000169 Celestix Networks Pte Ltd.
-00016A ALITEC
-00016B LightChip, Inc.
-00016C FOXCONN
-00016D CarrierComm Inc.
-00016E Conklin Corporation
-00016F HAITAI ELECTRONICS CO., LTD.
-000170 ESE Embedded System Engineer'g
-000171 Allied Data Technologies
-000172 TechnoLand Co., LTD.
-000173 JNI Corporation
-000174 CyberOptics Corporation
-000175 Radiant Communications Corp.
-000176 Orient Silver Enterprises
-000177 EDSL
-000178 MARGI Systems, Inc.
-000179 WIRELESS TECHNOLOGY, INC.
-00017A Chengdu Maipu Electric Industrial Co., Ltd.
-00017B Heidelberger Druckmaschinen AG
-00017C AG-E GmbH
-00017D ThermoQuest
-00017E ADTEK System Science Co., Ltd.
-00017F Experience Music Project
-000180 AOpen, Inc.
-000181 Nortel Networks
-000182 DICA TECHNOLOGIES AG
-000183 ANITE TELECOMS
-000184 SIEB & MEYER AG
-000185 Aloka Co., Ltd.
-000186 DISCH GmbH
-000187 i2SE GmbH
-000188 LXCO Technologies ag
-000189 Refraction Technology, Inc.
-00018A ROI COMPUTER AG
-00018B NetLinks Co., Ltd.
-00018C Mega Vision
-00018D AudeSi Technologies
-00018E Logitec Corporation
-00018F Kenetec, Inc.
-000190 SMK-M
-000191 SYRED Data Systems
-000192 Texas Digital Systems
-000193 Hanbyul Telecom Co., Ltd.
-000194 Capital Equipment Corporation
-000195 Sena Technologies, Inc.
-000196 Cisco Systems, Inc.
-000197 Cisco Systems, Inc.
-000198 Darim Vision
-000199 HeiSei Electronics
-00019A LEUNIG GmbH
-00019B Kyoto Microcomputer Co., Ltd.
-00019C JDS Uniphase Inc.
-00019D E-Control Systems, Inc.
-00019E ESS Technology, Inc.
-00019F Phonex Broadband
-0001A0 Infinilink Corporation
-0001A1 Mag-Tek, Inc.
-0001A2 Logical Co., Ltd.
-0001A3 GENESYS LOGIC, INC.
-0001A4 Microlink Corporation
-0001A5 Nextcomm, Inc.
-0001A6 Scientific-Atlanta Arcodan A/S
-0001A7 UNEX TECHNOLOGY CORPORATION
-0001A8 Welltech Computer Co., Ltd.
-0001A9 BMW AG
-0001AA Airspan Communications, Ltd.
-0001AB Main Street Networks
-0001AC Sitara Networks, Inc.
-0001AD Coach Master International d.b.a. CMI Worldwide, Inc.
-0001AE Trex Enterprises
-0001AF Motorola Computer Group
-0001B0 Fulltek Technology Co., Ltd.
-0001B1 General Bandwidth
-0001B2 Digital Processing Systems, Inc.
-0001B3 Precision Electronic Manufacturing
-0001B4 Wayport, Inc.
-0001B5 Turin Networks, Inc.
-0001B6 SAEJIN T&M Co., Ltd.
-0001B7 Centos, Inc.
-0001B8 Netsensity, Inc.
-0001B9 SKF Condition Monitoring
-0001BA IC-Net, Inc.
-0001BB Frequentis
-0001BC Brains Corporation
-0001BD Peterson Electro-Musical Products, Inc.
-0001BE Gigalink Co., Ltd.
-0001BF Teleforce Co., Ltd.
-0001C0 CompuLab, Ltd.
-0001C1 Vitesse Semiconductor Corporation
-0001C2 ARK Research Corp.
-0001C3 Acromag, Inc.
-0001C4 NeoWave, Inc.
-0001C5 Simpler Networks
-0001C6 Quarry Technologies
-0001C7 Cisco Systems, Inc.
-0001C8 THOMAS CONRAD CORP.
-0001C8 CONRAD CORP.
-0001C9 Cisco Systems, Inc.
-0001CA Geocast Network Systems, Inc.
-0001CB NetGame, Ltd.
-0001CC Japan Total Design Communication Co., Ltd.
-0001CD ARtem
-0001CE Custom Micro Products, Ltd.
-0001CF Alpha Data Parallel Systems, Ltd.
-0001D0 VitalPoint, Inc.
-0001D1 CoNet Communications, Inc.
-0001D2 MacPower Peripherals, Ltd.
-0001D3 PAXCOMM, Inc.
-0001D4 Leisure Time, Inc.
-0001D5 HAEDONG INFO & COMM CO., LTD
-0001D6 MAN Roland Druckmaschinen AG
-0001D7 F5 Networks, Inc.
-0001D8 Teltronics, Inc.
-0001D9 Sigma, Inc.
-0001DA WINCOMM Corporation
-0001DB Freecom Technologies GmbH
-0001DC Activetelco
-0001DD Avail Networks
-0001DE Trango Systems, Inc.
-0001DF ISDN Communications, Ltd.
-0001E0 Fast Systems, Inc.
-0001E1 Kinpo Electronics, Inc.
-0001E2 Ando Electric Corporation
-0001E3 Siemens AG
-0001E4 Sitera, Inc.
-0001E5 Supernet, Inc.
-0001E6 Hewlett-Packard Company
-0001E7 Hewlett-Packard Company
-0001E8 Force10 Networks, Inc.
-0001E9 Litton Marine Systems B.V.
-0001EA Cirilium Corp.
-0001EB C-COM Corporation
-0001EC Ericsson Group
-0001ED SETA Corp.
-0001EE Comtrol Europe, Ltd.
-0001EF Camtel Technology Corp.
-0001F0 Tridium, Inc.
-0001F1 Innovative Concepts, Inc.
-0001F2 Mark of the Unicorn, Inc.
-0001F3 QPS, Inc.
-0001F4 Enterasys Networks
-0001F5 ERIM S.A.
-0001F6 Association of Musical Electronics Industry
-0001F7 Image Display Systems, Inc.
-0001F8 Adherent Systems, Ltd.
-0001F9 TeraGlobal Communications Corp.
-0001FA HOROSCAS
-0001FB DoTop Technology, Inc.
-0001FC Keyence Corporation
-0001FD Digital Voice Systems, Inc.
-0001FE DIGITAL EQUIPMENT CORPORATION
-0001FF Data Direct Networks, Inc.
-000200 Net & Sys Co., Ltd.
-000201 IFM Electronic gmbh
-000202 Amino Communications, Ltd.
-000203 Woonsang Telecom, Inc.
-000204 Bodmann Industries Elektronik GmbH
-000205 Hitachi Denshi, Ltd.
-000206 Telital R&D Denmark A/S
-000207 VisionGlobal Network Corp.
-000208 Unify Networks, Inc.
-000209 Shenzhen SED Information Technology Co., Ltd.
-00020A Gefran Spa
-00020B Native Networks, Inc.
-00020C Metro-Optix
-00020D Micronpc.com
-00020E Laurel Networks, Inc.
-00020F AATR
-000210 Fenecom
-000211 Nature Worldwide Technology Corp.
-000212 SierraCom
-000213 S.D.E.L.
-000214 DTVRO
-000215 Cotas Computer Technology A/B
-000216 Cisco Systems, Inc.
-000217 Cisco Systems, Inc.
-000218 Advanced Scientific Corp
-000219 Paralon Technologies
-00021A Zuma Networks
-00021B Kollmorgen-Servotronix
-00021C Network Elements, Inc.
-00021D Data General Communication Ltd.
-00021E SIMTEL S.R.L.
-00021F Aculab PLC
-000220 Canon Aptex, Inc.
-000221 DSP Application, Ltd.
-000222 Chromisys, Inc.
-000223 ClickTV
-000224 Lantern Communications, Inc.
-000225 Certus Technology, Inc.
-000226 XESystems, Inc.
-000227 ESD GmbH
-000228 Necsom, Ltd.
-000229 Adtec Corporation
-00022A Asound Electronic
-00022B Tamura Electric Works, Ltd.
-00022C ABB Bomem, Inc.
-00022D Agere Systems
-00022E TEAC Corp. R& D
-00022F P-Cube, Ltd.
-000230 Intersoft Electronics
-000231 Ingersoll-Rand
-000232 Avision, Inc.
-000233 Mantra Communications, Inc.
-000234 Imperial Technology, Inc.
-000235 Paragon Networks International
-000236 INIT GmbH
-000237 Cosmo Research Corp.
-000238 Serome Technology, Inc.
-000239 Visicom
-00023A ZSK Stickmaschinen GmbH
-00023B Redback Networks
-00023C Creative Technology, Ltd.
-00023D NuSpeed, Inc.
-00023E Selta Telematica S.p.a
-00023F Compal Electronics, Inc.
-000240 Seedek Co., Ltd.
-000241 Amer.com
-000242 Videoframe Systems
-000243 Raysis Co., Ltd.
-000244 SURECOM Technology Co.
-000245 Lampus Co, Ltd.
-000246 All-Win Tech Co., Ltd.
-000247 Great Dragon Information Technology (Group) Co., Ltd.
-000248 Pilz GmbH & Co.
-000249 Aviv Infocom Co, Ltd.
-00024A Cisco Systems, Inc.
-00024B Cisco Systems, Inc.
-00024C SiByte, Inc.
-00024D Mannesman Dematic Colby Pty. Ltd.
-00024E Datacard Group
-00024F IPM Datacom S.R.L.
-000250 Geyser Networks, Inc.
-000251 Soma Networks
-000252 Carrier Corporation
-000253 Televideo, Inc.
-000254 WorldGate
-000255 IBM Corporation
-000256 Alpha Processor, Inc.
-000257 Microcom Corp.
-000258 Flying Packets Communications
-000259 Tsann Kuen China (Shanghai)Enterprise Co., Ltd. IT Group
-00025A Catena Networks
-00025B Cambridge Silicon Radio
-00025C SCI Systems (Kunshan) Co., Ltd.
-00025D Calix Networks
-00025E High Technology Ltd
-00025F Nortel Networks
-000260 Accordion Networks, Inc.
-000261 i3 Micro Technology AB
-000262 Soyo Group Soyo Com Tech Co., Ltd
-000263 UPS Manufacturing SRL
-000264 AudioRamp.com
-000265 Virditech Co. Ltd.
-000266 Thermalogic Corporation
-000267 NODE RUNNER, INC.
-000268 Harris Government Communications
-000269 Nadatel Co., Ltd
-00026A Cocess Telecom Co., Ltd.
-00026B BCM Computers Co., Ltd.
-00026C Philips CFT
-00026D Adept Telecom
-00026E NeGeN Access, Inc.
-00026F Senao International Co., Ltd.
-000270 Crewave Co., Ltd.
-000271 Vpacket Communications
-000272 CC&C Technologies, Inc.
-000273 Coriolis Networks
-000274 Tommy Technologies Corp.
-000275 SMART Technologies, Inc.
-000276 Primax Electronics Ltd.
-000277 Cash Systemes Industrie
-000278 Samsung Electro-Mechanics Co., Ltd.
-000279 Control Applications, Ltd.
-00027A IOI Technology Corporation
-00027B Amplify Net, Inc.
-00027C Trilithic, Inc.
-00027D Cisco Systems, Inc.
-00027E Cisco Systems, Inc.
-00027F ask-technologies.com
-000280 Mu Net, Inc.
-000281 Madge Ltd.
-000282 ViaClix, Inc.
-000283 Spectrum Controls, Inc.
-000284 Alstom T&D P&C
-000285 Riverstone Networks
-000286 Occam Networks
-000287 Adapcom
-000288 GLOBAL VILLAGE COMMUNICATION
-000289 DNE Technologies
-00028A Ambit Microsystems Corporation
-00028B VDSL Systems OY
-00028C Micrel-Synergy Semiconductor
-00028D Movita Technologies, Inc.
-00028E Rapid 5 Networks, Inc.
-00028F Globetek, Inc.
-000290 Woorigisool, Inc.
-000291 Open Network Co., Ltd.
-000292 Logic Innovations, Inc.
-000293 Solid Data Systems
-000294 Tokyo Sokushin Co., Ltd.
-000295 IP.Access Limited
-000296 Lectron Co,. Ltd.
-000297 C-COR.net
-000298 Broadframe Corporation
-000299 Apex, Inc.
-00029A Storage Apps
-00029B Kreatel Communications AB
-00029C 3COM
-00029D Merix Corp.
-00029E Information Equipment Co., Ltd.
-00029F L-3 Communication Aviation Recorders
-0002A0 Flatstack Ltd.
-0002A1 World Wide Packets
-0002A2 Hilscher GmbH
-0002A3 ABB Power Automation
-0002A4 AddPac Technology Co., Ltd.
-0002A5 Compaq Computer Corporation
-0002A6 Effinet Systems Co., Ltd.
-0002A7 Vivace Networks
-0002A8 Air Link Technology
-0002A9 RACOM, s.r.o.
-0002AA PLcom Co., Ltd.
-0002AB CTC Union Technologies Co., Ltd.
-0002AC 3PAR data
-0002AD Pentax Corpotation
-0002AE Scannex Electronics Ltd.
-0002AF TeleCruz Technology, Inc.
-0002B0 Hokubu Communication & Industrial Co., Ltd.
-0002B1 Anritsu, Ltd.
-0002B2 Cablevision
-0002B3 Intel Corporation
-0002B4 DAPHNE
-0002B5 Avnet, Inc.
-0002B6 Acrosser Technology Co., Ltd.
-0002B7 Watanabe Electric Industry Co., Ltd.
-0002B8 WHI KONSULT AB
-0002B9 Cisco Systems, Inc.
-0002BA Cisco Systems, Inc.
-0002BB Continuous Computing
-0002BC LVL 7 Systems, Inc.
-0002BD Bionet Co., Ltd.
-0002BE Totsu Engineering, Inc.
-0002BF dotRocket, Inc.
-0002C0 Bencent Tzeng Industry Co., Ltd.
-0002C1 Innovative Electronic Designs, Inc.
-0002C2 Net Vision Telecom
-0002C3 Arelnet Ltd.
-0002C4 Vector International BUBA
-0002C5 Evertz Microsystems Ltd.
-0002C6 Data Track Technology PLC
-0002C7 ALPS ELECTRIC Co., Ltd.
-0002C8 Technocom Communications Technology (pte) Ltd
-0002C9 Mellanox Technologies
-0002CA EndPoints, Inc.
-0002CB TriState Ltd.
-0002CC M.C.C.I
-0002CD TeleDream, Inc.
-0002CE FoxJet, Inc.
-0002CF ZyGate Communications, Inc.
-0002D0 Comdial Corporation
-0002D1 Vivotek, Inc.
-0002D2 Workstation AG
-0002D3 NetBotz, Inc.
-0002D4 PDA Peripherals, Inc.
-0002D5 ACR
-0002D6 NICE Systems
-0002D7 EMPEG Ltd
-0002D8 BRECIS Communications Corporation
-0002D9 Reliable Controls
-0002DA ExiO Communications, Inc.
-0002DB NETSEC
-0002DC Fujitsu General Limited
-0002DD Bromax Communications, Ltd.
-0002DE Astrodesign, Inc.
-0002DF Net Com Systems, Inc.
-0002E0 ETAS GmbH
-0002E1 Integrated Network Corporation
-0002E2 NDC Infared Engineering
-0002E3 LITE-ON Communications, Inc.
-0002E4 JC HYUN Systems, Inc.
-0002E5 Timeware Ltd.
-0002E6 Gould Instrument Systems, Inc.
-0002E7 CAB GmbH & Co KG
-0002E8 E.D.&A.
-0002E9 CS Systemes De Securite - C3S
-0002EA Videonics, Inc.
-0002EB Pico Communications
-0002EC Maschoff Design Engineering
-0002ED DXO Telecom Co., Ltd.
-0002EE Nokia Danmark A/S
-0002EF CCC Network Systems Group Ltd.
-0002F0 AME Optimedia Technology Co., Ltd.
-0002F1 Pinetron Co., Ltd.
-0002F2 eDevice, Inc.
-0002F3 Media Serve Co., Ltd.
-0002F4 PCTEL, Inc.
-0002F5 VIVE Synergies, Inc.
-0002F6 Equipe Communications
-0002F7 ARM
-0002F8 SEAKR Engineering, Inc.
-0002F9 Mimos Semiconductor SDN BHD
-0002FA DX Antenna Co., Ltd.
-0002FB Baumuller Aulugen-Systemtechnik GmbH
-0002FC Cisco Systems, Inc.
-0002FD Cisco Systems, Inc.
-0002FE Viditec, Inc.
-0002FF Handan BroadInfoCom
-000300 NetContinuum, Inc.
-000301 Avantas Networks Corporation
-000302 Oasys Telecom, Inc.
-000303 JAMA Electronics Co., Ltd.
-000304 Pacific Broadband Communications
-000305 Smart Network Devices GmbH
-000306 Fusion In Tech Co., Ltd.
-000307 Secure Works, Inc.
-000308 AM Communications, Inc.
-000309 Texcel Technology PLC
-00030A Argus Technologies
-00030B Hunter Technology, Inc.
-00030C Telesoft Technologies Ltd.
-00030D Uniwill Computer Corp.
-00030E Core Communications Co., Ltd.
-00030F Digital China (Shanghai) Networks Ltd.
-000310 Link Evolution Corp.
-000311 Micro Technology Co., Ltd.
-000312 TR-Systemtechnik GmbH
-000313 Access Media SPA
-000314 Teleware Network Systems
-000315 Cidco Incorporated
-000316 Nobell Communications, Inc.
-000317 Merlin Systems, Inc.
-000318 Cyras Systems, Inc.
-000319 Infineon AG
-00031A Beijing Broad Telecom Ltd., China
-00031B Cellvision Systems, Inc.
-00031C Svenska Hardvarufabriken AB
-00031D Taiwan Commate Computer, Inc.
-00031E Optranet, Inc.
-00031F Condev Ltd.
-000320 Xpeed, Inc.
-000321 Reco Research Co., Ltd.
-000322 IDIS Co., Ltd.
-000323 Cornet Technology, Inc.
-000324 SANYO Multimedia Tottori Co., Ltd.
-000325 Arima Computer Corp.
-000326 Iwasaki Information Systems Co., Ltd.
-000327 ACT'L
-000328 Mace Group, Inc.
-000329 F3, Inc.
-00032A UniData Communication Systems, Inc.
-00032B GAI Datenfunksysteme GmbH
-00032C ABB Industrie AG
-00032D IBASE Technology, Inc.
-00032E Scope Information Management, Ltd.
-00032F Global Sun Technology, Inc.
-000330 Imagenics, Co., Ltd.
-000331 Cisco Systems, Inc.
-000332 Cisco Systems, Inc.
-000333 Digitel Co., Ltd.
-000334 Newport Electronics
-000335 Mirae Technology
-000336 Zetes Technologies
-000337 Vaone, Inc.
-000338 Oak Technology
-000339 Eurologic Systems, Ltd.
-00033A Silicon Wave, Inc.
-00033B TAMI Tech Co., Ltd.
-00033C Daiden Co., Ltd.
-00033D ILSHin Lab
-00033E Tateyama System Laboratory Co., Ltd.
-00033F BigBand Networks, Ltd.
-000340 Floware Wireless Systems, Ltd.
-000341 Axon Digital Design
-000342 Nortel Networks
-000343 Martin Professional A/S
-000344 Tietech.Co., Ltd.
-000345 Routrek Networks Corporation
-000346 Hitachi Kokusai Electric, Inc.
-000347 Intel Corporation
-000348 Norscan Instruments, Ltd.
-000349 Vidicode Datacommunicatie B.V.
-00034A RIAS Corporation
-00034B Nortel Networks
-00034C Shanghai DigiVision Technology Co., Ltd.
-00034D Chiaro Networks, Ltd.
-00034E Pos Data Company, Ltd.
-00034F Sur-Gard Security
-000350 BTICINO SPA
-000351 Diebold, Inc.
-000352 Colubris Networks
-000353 Mitac, Inc.
-000354 Fiber Logic Communications
-000355 TeraBeam Internet Systems
-000356 Wincor Nixdorf GmbH & Co KG
-000357 Intervoice-Brite, Inc.
-000358 iCable System Co., Ltd.
-000359 DigitalSis
-00035A Photron Limited
-00035B BridgeWave Communications
-00035C Saint Song Corp.
-00035D Bosung Hi-Net Co., Ltd.
-00035E Metropolitan Area Networks, Inc.
-00035F Prueftechnik Condition Monitoring GmbH & Co. KG
-000360 PAC Interactive Technology, Inc.
-000361 Widcomm, Inc.
-000362 Vodtel Communications, Inc.
-000363 Miraesys Co., Ltd.
-000364 Scenix Semiconductor, Inc.
-000365 Kira Information & Communications, Ltd.
-000366 ASM Pacific Technology
-000367 Jasmine Networks, Inc.
-000368 Embedone Co., Ltd.
-000369 Nippon Antenna Co., Ltd.
-00036A Mainnet, Ltd.
-00036B Cisco Systems, Inc.
-00036C Cisco Systems, Inc.
-00036D Runtop, Inc.
-00036E Nicon Systems (Pty) Limited
-00036F Telsey SPA
-000370 NXTV, Inc.
-000371 Acomz Networks Corp.
-000372 ULAN
-000373 Aselsan A.S
-000374 Hunter Watertech
-000375 NetMedia, Inc.
-000376 Graphtec Technology, Inc.
-000377 Gigabit Wireless
-000378 HUMAX Co., Ltd.
-000379 Proscend Communications, Inc.
-00037A Taiyo Yuden Co., Ltd.
-00037B IDEC IZUMI Corporation
-00037C Coax Media
-00037D Stellcom
-00037E PORTech Communications, Inc.
-00037F Atheros Communications, Inc.
-000380 SSH Communications Security Corp.
-000381 Ingenico International
-000382 A-One Co., Ltd.
-000383 Metera Networks, Inc.
-000384 AETA
-000385 Actelis Networks, Inc.
-000386 Ho Net, Inc.
-000387 Blaze Network Products
-000388 Fastfame Technology Co., Ltd.
-000389 Plantronics
-00038A America Online, Inc.
-00038B PLUS-ONE I&T, Inc.
-00038C Total Impact
-00038D PCS Revenue Control Systems, Inc.
-00038E Atoga Systems, Inc.
-00038F Weinschel Corporation
-000390 Digital Video Communications, Inc.
-000392 Hyundai Teletek Co., Ltd.
-000393 Apple Computer, Inc.
-000394 Connect One
-000395 California Amplifier
-000396 EZ Cast Co., Ltd.
-000397 Watchfront Electronics
-000398 WISI
-000399 Dongju Informations & Communications Co., Ltd.
-00039A nSine, Ltd.
-00039B NetChip Technology, Inc.
-00039C OptiMight Communications, Inc.
-00039D BENQ CORPORATION
-00039E Tera System Co., Ltd.
-00039F Cisco Systems, Inc.
-0003A0 Cisco Systems, Inc.
-0003A1 HIPER Information & Communication, Inc.
-0003A2 Catapult Communications
-0003A3 MAVIX, Ltd.
-0003A4 Data Storage and Information Management
-0003A5 Medea Corporation
-0003A7 Unixtar Technology, Inc.
-0003A8 IDOT Computers, Inc.
-0003A9 AXCENT Media AG
-0003AA Watlow
-0003AB Bridge Information Systems
-0003AC Fronius Schweissmaschinen
-0003AD Emerson Energy Systems AB
-0003AE Allied Advanced Manufacturing Pte, Ltd.
-0003AF Paragea Communications
-0003B0 Xsense Technology Corp.
-0003B1 Abbott Laboratories HPD
-0003B2 Radware
-0003B3 IA Link Systems Co., Ltd.
-0003B4 Macrotek International Corp.
-0003B5 Entra Technology Co.
-0003B6 QSI Corporation
-0003B7 ZACCESS Systems
-0003B8 NetKit Solutions, LLC
-0003B9 Hualong Telecom Co., Ltd.
-0003BA Sun Microsystems
-0003BB Signal Communications Limited
-0003BC COT GmbH
-0003BD OmniCluster Technologies, Inc.
-0003BE Netility
-0003BF Centerpoint Broadband Technologies, Inc.
-0003C0 RFTNC Co., Ltd.
-0003C1 Packet Dynamics Ltd
-0003C2 Solphone K.K.
-0003C3 Micronik Multimedia
-0003C4 Tomra Systems ASA
-0003C5 Mobotix AG
-0003C6 ICUE Systems, Inc.
-0003C7 hopf Elektronik GmbH
-0003C8 CML Emergency Services
-0003C9 TECOM Co., Ltd.
-0003CA MTS Systems Corp.
-0003CB Nippon Systems Development Co., Ltd.
-0003CC Momentum Computer, Inc.
-0003CD Clovertech, Inc.
-0003CE ETEN Technologies, Inc.
-0003CF Muxcom, Inc.
-0003D0 KOANKEISO Co., Ltd.
-0003D1 Takaya Corporation
-0003D2 Crossbeam Systems, Inc.
-0003D3 Internet Energy Systems, Inc.
-0003D4 Alloptic, Inc.
-0003D5 Advanced Communications Co., Ltd.
-0003D6 RADVision, Ltd.
-0003D7 NextNet Wireless, Inc.
-0003D8 iMPath Networks, Inc.
-0003D9 Secheron SA
-0003DA Takamisawa Cybernetics Co., Ltd.
-0003DB Apogee Electronics Corp.
-0003DC Lexar Media, Inc.
-0003DD Comark Corp.
-0003DE OTC Wireless
-0003DF Desana Systems
-0003E0 RadioFrame Networks, Inc.
-0003E1 Winmate Communication, Inc.
-0003E2 Comspace Corporation
-0003E3 Cisco Systems, Inc.
-0003E4 Cisco Systems, Inc.
-0003E5 Hermstedt SG
-0003E6 Entone Technologies, Inc.
-0003E7 Logostek Co. Ltd.
-0003E8 Wavelength Digital Limited
-0003E9 Akara Canada, Inc.
-0003EA Mega System Technologies, Inc.
-0003EB Atrica
-0003EC ICG Research, Inc.
-0003ED Shinkawa Electric Co., Ltd.
-0003EE MKNet Corporation
-0003EF Oneline AG
-0003F0 Redfern Broadband Networks
-0003F1 Cicada Semiconductor, Inc.
-0003F2 Seneca Networks
-0003F3 Dazzle Multimedia, Inc.
-0003F4 NetBurner
-0003F5 Chip2Chip
-0003F6 Allegro Networks, Inc.
-0003F7 Plast-Control GmbH
-0003F8 SanCastle Technologies, Inc.
-0003F9 Pleiades Communications, Inc.
-0003FA TiMetra Networks
-0003FB Toko Seiki Company, Ltd.
-0003FC Intertex Data AB
-0003FD Cisco Systems, Inc.
-0003FE Cisco Systems, Inc.
-0003FF Connectix
-000400 LEXMARK INTERNATIONAL, INC.
-000401 Osaki Electric Co., Ltd.
-000402 Nexsan Technologies, Ltd.
-000403 Nexsi Corporation
-000404 Makino Milling Machine Co., Ltd.
-000405 ACN Technologies
-000406 Fa. Metabox AG
-000407 Topcon Positioning Systems, Inc.
-000408 Sanko Electronics Co., Ltd.
-000409 Cratos Networks
-00040A Sage Systems
-00040B 3com Europe Ltd.
-00040C KANNO Work's Ltd.
-00040D Avaya, Inc.
-00040E AVM GmbH
-00040F Asus Network Technologies, Inc.
-000410 Spinnaker Networks, Inc.
-000411 Inkra Networks, Inc.
-000412 WaveSmith Networks, Inc.
-000413 SNOM Technology AG
-000414 Umezawa Musen Denki Co., Ltd.
-000415 Rasteme Systems Co., Ltd.
-000416 Parks S/A Comunicacoes Digitais
-000417 ELAU AG
-000418 Teltronic S.A.U.
-000419 Fibercycle Networks, Inc.
-00041A ines GmbH
-00041B Digital Interfaces Ltd.
-00041C ipDialog, Inc.
-00041D Corega of America
-00041E Shikoku Instrumentation Co., Ltd.
-00041F Sony Computer Entertainment, Inc.
-000420 Slim Devices, Inc.
-000421 Ocular Networks
-000422 Gordon Kapes, Inc.
-000423 Intel Corporation
-000424 TMC s.r.l.
-000425 Atmel Corporation
-000426 Autosys
-000427 Cisco Systems, Inc.
-000428 Cisco Systems, Inc.
-000429 Pixord Corporation
-00042A Wireless Networks, Inc.
-00042B IT Access Co., Ltd.
-00042C Minet, Inc.
-00042D Sarian Systems, Ltd.
-00042E Netous Technologies, Ltd.
-00042F International Communications Products, Inc.
-000430 Netgem
-000431 GlobalStreams, Inc.
-000432 Voyetra Turtle Beach, Inc.
-000433 Cyberboard A/S
-000434 Accelent Systems, Inc.
-000435 Comptek International, Inc.
-000436 ELANsat Technologies, Inc.
-000437 Powin Information Technology, Inc.
-000438 Nortel Networks
-000439 Rosco Entertainment Technology, Inc.
-00043A Intelligent Telecommunications, Inc.
-00043B Lava Computer Mfg., Inc.
-00043C SONOS Co., Ltd.
-00043D INDEL AG
-00043E Telencomm
-00043F Electronic Systems Technology, Inc.
-000440 cyberPIXIE, Inc.
-000441 Half Dome Systems, Inc.
-000442 NACT
-000443 Agilent Technologies, Inc.
-000444 Western Multiplex Corporation
-000445 LMS Skalar Instruments GmbH
-000446 CYZENTECH Co., Ltd.
-000447 Acrowave Systems Co., Ltd.
-000448 Polaroid Professional Imaging
-000449 Mapletree Networks
-00044A iPolicy Networks, Inc.
-00044B NVIDIA
-00044C JENOPTIK
-00044D Cisco Systems, Inc.
-00044E Cisco Systems, Inc.
-00044F Leukhardt Systemelektronik GmbH
-000450 DMD Computers SRL
-000451 Medrad, Inc.
-000452 RocketLogix, Inc.
-000453 YottaYotta, Inc.
-000454 Quadriga UK
-000455 ANTARA.net
-000456 PipingHot Networks
-000457 Universal Access Technology, Inc.
-000458 Fusion X Co., Ltd.
-000459 Veristar Corporation
-00045A The Linksys Group, Inc.
-00045B Techsan Electronics Co., Ltd.
-00045C Mobiwave Pte Ltd
-00045D BEKA Elektronik
-00045E PolyTrax Information Technology AG
-00045F Evalue Technology, Inc.
-000460 Knilink Technology, Inc.
-000461 EPOX Computer Co., Ltd.
-000462 DAKOS Data & Communication Co., Ltd.
-000463 Bosch Security Systems
-000464 Fantasma Networks, Inc.
-000465 i.s.t isdn-support technik GmbH
-000466 ARMITEL Co.
-000467 Wuhan Research Institute of MII
-000468 Vivity, Inc.
-000469 Innocom, Inc.
-00046A Navini Networks
-00046B Palm Wireless, Inc.
-00046C Cyber Technology Co., Ltd.
-00046D Cisco Systems, Inc.
-00046E Cisco Systems, Inc.
-00046F Digitel S/A Industria Eletronica
-000470 ipUnplugged AB
-000471 IPrad
-000472 Telelynx, Inc.
-000473 Photonex Corporation
-000474 LEGRAND
-000475 3 Com Corporation
-000476 3 Com Corporation
-000477 Scalant Systems, Inc.
-000478 G. Star Technology Corporation
-000479 Radius Co., Ltd.
-00047A AXXESSIT ASA
-00047B Schlumberger
-00047C Skidata AG
-00047D Pelco
-00047E NKF Electronics
-00047F Chr. Mayr GmbH & Co. KG
-000480 Foundry Networks, Inc.
-000481 Econolite Control Products, Inc.
-000482 Medialogic Corp.
-000483 Deltron Technology, Inc.
-000484 Amann GmbH
-000485 PicoLight
-000486 ITTC, University of Kansas
-000487 Cogency Semiconductor, Inc.
-000488 Eurotherm Action Incorporated.
-000489 YAFO Networks, Inc.
-00048A Temia Vertriebs GmbH
-00048B Poscon Corporation
-00048C Nayna Networks, Inc.
-00048D Tone Commander Systems, Inc.
-00048E Ohm Tech Labs, Inc.
-00048F TD Systems Corp.
-000490 Optical Access
-000491 Technovision, Inc.
-000492 Hive Internet, Ltd.
-000493 Tsinghua Unisplendour Co., Ltd.
-000494 Breezecom, Ltd.
-000495 Tejas Networks
-000496 Extreme Networks
-000497 MacroSystem Digital Video AG
-000499 Chino Corporation
-00049A Cisco Systems, Inc.
-00049B Cisco Systems, Inc.
-00049C Surgient Networks, Inc.
-00049D Ipanema Technologies
-00049E Wirelink Co., Ltd.
-00049F Metrowerks
-0004A0 Verity Instruments, Inc.
-0004A1 Pathway Connectivity
-0004A2 L.S.I. Japan Co., Ltd.
-0004A3 Microchip Technology, Inc.
-0004A4 NetEnabled, Inc.
-0004A5 Barco Projection Systems NV
-0004A6 SAF Tehnika Ltd.
-0004A7 FabiaTech Corporation
-0004A8 Broadmax Technologies, Inc.
-0004A9 SandStream Technologies, Inc.
-0004AA Jetstream Communications
-0004AB Comverse Network Systems, Inc.
-0004AC IBM CORP.
-0004AD Malibu Networks
-0004AE Liquid Metronics
-0004AF Digital Fountain, Inc.
-0004B0 ELESIGN Co., Ltd.
-0004B1 Signal Technology, Inc.
-0004B2 ESSEGI SRL
-0004B3 Videotek, Inc.
-0004B4 CIAC
-0004B5 Equitrac Corporation
-0004B6 Stratex Networks, Inc.
-0004B7 AMB i.t. Holding
-0004B8 Kumahira Co., Ltd.
-0004B9 S.I. Soubou, Inc.
-0004BA KDD Media Will Corporation
-0004BB Bardac Corporation
-0004BC Giantec, Inc.
-0004BD Motorola BCS
-0004BE OptXCon, Inc.
-0004BF VersaLogic Corp.
-0004C0 Cisco Systems, Inc.
-0004C1 Cisco Systems, Inc.
-0004C2 Magnipix, Inc.
-0004C3 CASTOR Informatique
-0004C4 Allen & Heath Limited
-0004C5 ASE Technologies, USA
-0004C6 Yamaha Motor Co., Ltd.
-0004C7 NetMount
-0004C8 LIBA Maschinenfabrik GmbH
-0004C9 Micro Electron Co., Ltd.
-0004CA FreeMs Corp.
-0004CB Tdsoft Communication, Ltd.
-0004CC Peek Traffic B.V.
-0004CD Informedia Research Group
-0004CE Patria Ailon
-0004CF Seagate Technology
-0004D0 Softlink s.r.o.
-0004D1 Drew Technologies, Inc.
-0004D2 Adcon Telemetry AG
-0004D3 Toyokeiki Co., Ltd.
-0004D4 Proview Electronics Co., Ltd.
-0004D5 Hitachi Communication Systems, Inc.
-0004D6 Takagi Industrial Co., Ltd.
-0004D7 Omitec Instrumentation Ltd.
-0004D8 IPWireless, Inc.
-0004D9 Titan Electronics, Inc.
-0004DA Relax Technology, Inc.
-0004DB Tellus Group Corp.
-0004DC Nortel Networks
-0004DD Cisco Systems, Inc.
-0004DE Cisco Systems, Inc.
-0004DF Teracom Telematica Ltda.
-0004E0 Procket Networks
-0004E1 Infinior Microsystems
-0004E2 SMC Networks, Inc.
-0004E3 Accton Technology Corp.
-0004E4 Daeryung Ind., Inc.
-0004E5 Glonet Systems, Inc.
-0004E6 Banyan Network Private Limited
-0004E7 Lightpointe Communications, Inc
-0004E8 IER, Inc.
-0004E9 Infiniswitch Corporation
-0004EA Hewlett-Packard Company
-0004EB Paxonet Communications, Inc.
-0004EC Memobox SA
-0004ED Billion Electric Co., Ltd.
-0004EE Lincoln Electric Company
-0004EF Polestar Corp.
-0004F0 International Computers, Ltd
-0004F1 WhereNet
-0004F2 Circa Communications, Ltd.
-0004F3 FS FORTH-SYSTEME GmbH
-0004F4 Infinite Electronics Inc.
-0004F5 SnowShore Networks, Inc.
-0004F6 Amphus
-0004F7 Omega Band, Inc.
-0004F8 QUALICABLE TV Industria E Com., Ltda
-0004F9 Xtera Communications, Inc.
-0004FA MIST Inc.
-0004FB Commtech, Inc.
-0004FC Stratus Computer (DE), Inc.
-0004FD Japan Control Engineering Co., Ltd.
-0004FE Pelago Networks
-0004FF Acronet Co., Ltd.
-000500 Cisco Systems, Inc.
-000501 Cisco Systems, Inc.
-000502 APPLE COMPUTER
-000503 ICONAG
-000504 Naray Information & Communication Enterprise
-000505 Systems Integration Solutions, Inc.
-000506 Reddo Networks AB
-000507 Fine Appliance Corp.
-000508 Inetcam, Inc.
-000509 AVOC Nishimura Ltd.
-00050A ICS Spa
-00050B SICOM Systems, Inc.
-00050C Network Photonics, Inc.
-00050D Midstream Technologies, Inc.
-00050E 3ware, Inc.
-00050F Tanaka S/S Ltd.
-000510 Infinite Shanghai Communication Terminals Ltd.
-000511 Complementary Technologies Ltd
-000512 MeshNetworks, Inc.
-000513 VTLinx Multimedia Systems, Inc.
-000514 KDT Systems Co., Ltd.
-000515 Nuark Co., Ltd.
-000516 SMART Modular Technologies
-000517 Shellcomm, Inc.
-000518 Jupiters Technology
-000519 Siemens Building Technologies AG,
-00051A 3Com Europe Ltd.
-00051B Magic Control Technology Corporation
-00051C Xnet Technology Corp.
-00051D Airocon, Inc.
-00051E Brocade Communications Systems, Inc.
-00051F Taijin Media Co., Ltd.
-000520 Smartronix, Inc.
-000521 Control Microsystems
-000522 LEA*D Corporation, Inc.
-000523 AVL List GmbH
-000524 BTL System (HK) Limited
-000525 Puretek Industrial Co., Ltd.
-000526 IPAS GmbH
-000527 SJ Tek Co. Ltd
-000528 New Focus, Inc.
-000529 Shanghai Broadan Communication Technology Co., Ltd
-00052A Ikegami Tsushinki Co., Ltd.
-00052B HORIBA, Ltd.
-00052C Supreme Magic Corporation
-00052D Zoltrix International Limited
-00052E Cinta Networks
-00052F Leviton Voice and Data
-000530 Andiamo Systems, Inc.
-000531 Cisco Systems, Inc.
-000532 Cisco Systems, Inc.
-000533 Sanera Systems, Inc.
-000534 Northstar Engineering Ltd.
-000535 Chip PC Ltd.
-000536 Danam Communications, Inc.
-000537 Nets Technology Co., Ltd.
-000538 Merilus, Inc.
-000539 A Brand New World in Sweden AB
-00053A Willowglen Services Pte Ltd
-00053B Harbour Networks Ltd., Co. Beijing
-00053C Xircom
-00053D Agere Systems
-00053E KID Systeme GmbH
-00053F VisionTek, Inc.
-000540 FAST Corporation
-000541 Advanced Systems Co., Ltd.
-000542 Otari, Inc.
-000543 IQ Wireless GmbH
-000544 Valley Technologies, Inc.
-000545 Internet Photonics
-000546 K-Solutions Inc.
-000547 Starent Networks
-000548 Disco Corporation
-000549 Salira Optical Network Systems
-00054A Ario Data Networks, Inc.
-00054B Micro Innovation AG
-00054C RF Innovations Pty Ltd
-00054D Brans Technologies, Inc.
-00054E Philips Components
-000550 Digi-Tech Communications Limited
-000551 F & S Elektronik Systeme GmbH
-000552 Xycotec Computer GmbH
-000553 DVC Company, Inc.
-000554 Rangestar Wireless
-000555 Japan Cash Machine Co., Ltd.
-000556 360 Systems
-000557 Agile TV Corporation
-000558 Synchronous, Inc.
-000559 Intracom S.A.
-00055A Power Dsine Ltd.
-00055B Charles Industries, Ltd.
-00055C Kowa Company, Ltd.
-00055D D-Link Systems, Inc.
-00055E Cisco Systems, Inc.
-00055F Cisco Systems, Inc.
-000560 LEADER COMM.CO., LTD
-000561 nac Image Technology, Inc.
-000562 Digital View Limited
-000563 J-Works, Inc.
-000564 Tsinghua Bitway Co., Ltd.
-000565 Tailyn Communication Company Ltd.
-000566 Secui.com Corporation
-000567 Etymonic Design, Inc.
-000568 Piltofish Networks AB
-000569 VMWARE, Inc.
-00056A Heuft Systemtechnik GmbH
-00056B C.P. Technology Co., Ltd.
-00056C Hung Chang Co., Ltd.
-00056D Pacific Corporation
-00056E National Enhance Technology, Inc.
-00056F Innomedia Technologies Pvt. Ltd.
-000570 Baydel Ltd.
-000571 Seiwa Electronics Co.
-000572 Deonet Co., Ltd.
-000573 Cisco Systems, Inc.
-000574 Cisco Systems, Inc.
-000575 CDS-Electronics BV
-000576 NSM Technology Ltd.
-000577 SM Information & Communication
-000579 Universal Control Solution Corp.
-00057A Hatteras Networks
-00057B Chung Nam Electronic Co., Ltd.
-00057C RCO Security AB
-00057D Sun Communications, Inc.
-00057E Eckelmann Steuerungstechnik GmbH
-00057F Acqis Technology
-000580 Fibrolan Ltd.
-000581 Snell & Wilcox Ltd.
-000582 ClearCube Technology
-000583 ImageCom Limited
-000584 AbsoluteValue Systems, Inc.
-000585 Juniper Networks, Inc.
-000586 Lucent Technologies
-000587 Locus, Incorporated
-000588 Sensoria Corp.
-000589 National Datacomputer
-00058A Netcom Co., Ltd.
-00058B IPmental, Inc.
-00058C Opentech Inc.
-00058D Lynx Photonic Networks, Inc.
-00058E Flextronics International GmbH & Co. Nfg. KG
-00058F CLCsoft co.
-000590 Swissvoice Ltd.
-000591 Active Silicon Ltd.
-000592 Pultek Corp.
-000593 Grammar Engine Inc.
-000594 IXXAT Automation GmbH
-000595 Alesis Corporation
-000596 Genotech Co., Ltd.
-000597 Eagle Traffic Control Systems
-000598 CRONOS S.r.l.
-000599 DRS Test and Energy Management or DRS-TEM
-00059A Cisco Systems, Inc.
-00059B Cisco Systems, Inc.
-00059C Kleinknecht GmbH, Ing. Buero
-00059D Daniel Computing Systems, Inc.
-00059E Zinwell Corporation
-00059F Yotta Networks, Inc.
-0005A0 MOBILINE Kft.
-0005A1 Zenocom
-0005A2 CELOX Networks
-0005A3 QEI, Inc.
-0005A4 Lucid Voice Ltd.
-0005A5 KOTT
-0005A6 Extron Electronics
-0005A7 Hyperchip, Inc.
-0005A8 WYLE ELECTRONICS
-0005A9 Princeton Networks, Inc.
-0005AA Moore Industries International Inc.
-0005AB Cyber Fone, Inc.
-0005AC Northern Digital, Inc.
-0005AD Topspin Communications, Inc.
-0005AE Mediaport USA
-0005AF InnoScan Computing A/S
-0005B0 Korea Computer Technology Co., Ltd.
-0005B1 ASB Technology BV
-0005B2 Medison Co., Ltd.
-0005B3 Asahi-Engineering Co., Ltd.
-0005B4 Aceex Corporation
-0005B5 Broadcom Technologies
-0005B6 INSYS Microelectronics GmbH
-0005B7 Arbor Technology Corp.
-0005B8 Electronic Design Associates, Inc.
-0005B9 Airvana, Inc.
-0005BA Area Netwoeks, Inc.
-0005BB Myspace AB
-0005BC Resorsys Ltd.
-0005BD ROAX BV
-0005BE Kongsberg Seatex AS
-0005BF JustEzy Technology, Inc.
-0005C0 Digital Network Alacarte Co., Ltd.
-0005C1 A-Kyung Motion, Inc.
-0005C2 Soronti, Inc.
-0005C3 Pacific Instruments, Inc.
-0005C4 Telect, Inc.
-0005C5 Flaga HF
-0005C6 Triz Communications
-0005C7 I/F-COM A/S
-0005C8 VERYTECH
-0005C9 LG Innotek
-0005CA Hitron Technology, Inc.
-0005CB ROIS Technologies, Inc.
-0005CC Sumtel Communications, Inc.
-0005CD Denon, Ltd.
-0005CE Prolink Microsystems Corporation
-0005CF Thunder River Technologies, Inc.
-0005D0 Solinet Systems
-0005D1 Metavector Technologies
-0005D2 DAP Technologies
-0005D3 eProduction Solutions, Inc.
-0005D4 FutureSmart Networks, Inc.
-0005D5 Speedcom Wireless
-0005D6 Titan Wireless
-0005D7 Vista Imaging, Inc.
-0005D8 Arescom, Inc.
-0005D9 Techno Valley, Inc.
-0005DA Apex Automationstechnik
-0005DB Nentec GmbH
-0005DC Cisco Systems, Inc.
-0005DD Cisco Systems, Inc.
-0005DE Gi Fone Korea, Inc.
-0005DF Electronic Innovation, Inc.
-0005E0 Empirix Corp.
-0005E1 Trellis Photonics, Ltd.
-0005E2 Creativ Network Technologies
-0005E3 LightSand Communications, Inc.
-0005E4 Red Lion Controls L.P.
-0005E5 Renishaw PLC
-0005E6 Egenera, Inc.
-0005E7 Netrake Corp.
-0005E8 TurboWave, Inc.
-0005E9 Unicess Network, Inc.
-0005EA Rednix
-0005EB Blue Ridge Networks, Inc.
-0005EC Mosaic Systems Inc.
-0005ED Technikum Joanneum GmbH
-0005EE BEWATOR Group
-0005EF ADOIR Digital Technology
-0005F0 SATEC
-0005F1 Vrcom, Inc.
-0005F2 Power R, Inc.
-0005F3 Weboyn
-0005F4 System Base Co., Ltd.
-0005F5 OYO Geospace Corp.
-0005F6 Young Chang Co. Ltd.
-0005F7 Analog Devices, Inc.
-0005F8 Real Time Access, Inc.
-0005F9 TOA Corporation
-0005FA IPOptical, Inc.
-0005FB ShareGate, Inc.
-0005FC Schenck Pegasus Corp.
-0005FD PacketLight Networks Ltd.
-0005FE Traficon N.V.
-0005FF SNS Solutions, Inc.
-000600 Tokyo Electronic Industry Co., Ltd.
-000601 Otanikeiki Co., Ltd.
-000602 Cirkitech Electronics Co.
-000603 Baker Hughes Inc.
-000604 @Track Communications, Inc.
-000605 Inncom International, Inc.
-000606 RapidWAN, Inc.
-000607 Omni Directional Control Technology Inc.
-000608 At-Sky SAS
-000609 Crossport Systems
-00060A Blue2space
-00060B Paceline Systems Corporation
-00060C Melco Industries, Inc.
-00060D Wave7 Optics
-00060E IGYS Systems, Inc.
-00060F Narad Networks Inc
-000610 Abeona Networks Inc
-000611 Zeus Wireless, Inc.
-000612 Accusys, Inc.
-000613 Kawasaki Microelectronics Incorporated
-000614 Prism Holdings
-000615 Kimoto Electric Co., Ltd.
-000616 Tel Net Co., Ltd.
-000617 Redswitch Inc.
-000618 DigiPower Manufacturing Inc.
-000619 Connection Technology Systems
-00061A Zetari Inc.
-00061B Portable Systems, IBM Japan Co, Ltd
-00061C Hoshino Metal Industries, Ltd.
-00061D MIP Telecom, Inc.
-00061E Maxan Systems
-00061F Vision Components GmbH
-000620 Serial System Ltd.
-000621 Hinox, Co., Ltd.
-000622 Chung Fu Chen Yeh Enterprise Corp.
-000623 MGE UPS Systems France
-000624 Gentner Communications Corp.
-000625 The Linksys Group, Inc.
-000626 MWE GmbH
-000627 Uniwide Technologies, Inc.
-000628 Cisco Systems, Inc.
-000629 IBM CORPORATION
-00062A Cisco Systems, Inc.
-00062B INTRASERVER TECHNOLOGY
-00062C Network Robots, Inc.
-00062D TouchStar Technologies, L.L.C.
-00062E Aristos Logic Corp.
-00062F Pivotech Systems Inc.
-000630 Adtranz Sweden
-000631 Optical Solutions, Inc.
-000632 Mesco Engineering GmbH
-000633 Heimann Biometric Systems GmbH
-000634 GTE Airfone Inc.
-000635 PacketAir Networks, Inc.
-000636 Jedai Broadband Networks
-000637 Toptrend-Meta Information (ShenZhen) Inc.
-000638 Sungjin C&C Co., Ltd.
-000639 Newtec
-00063A Dura Micro, Inc.
-00063B Arcturus Networks, Inc.
-00063C NMI Electronics Ltd
-00063D Microwave Data Systems Inc.
-00063E Opthos Inc.
-00063F Everex Communications Inc.
-000640 White Rock Networks
-000641 ITCN
-000642 Genetel Systems Inc.
-000643 SONO Computer Co., Ltd.
-000644 NEIX Inc.
-000645 Meisei Electric Co. Ltd.
-000646 ShenZhen XunBao Network Technology Co Ltd
-000647 Etrali S.A.
-000648 Seedsware, Inc.
-000649 Quante
-00064A Honeywell Co., Ltd. (KOREA)
-00064B Alexon Co., Ltd.
-00064C Invicta Networks, Inc.
-00064D Sencore
-00064E Broad Net Technology Inc.
-00064F PRO-NETS Technology Corporation
-000650 Tiburon Networks, Inc.
-000651 Aspen Networks Inc.
-000652 Cisco Systems, Inc.
-000653 Cisco Systems, Inc.
-000654 Maxxio Technologies
-000655 Yipee, Inc.
-000656 Tactel AB
-000657 Market Central, Inc.
-000658 Helmut Fischer GmbH & Co. KG
-000659 EAL (Apeldoorn) B.V.
-00065A Strix Systems
-00065B Dell Computer Corp.
-00065C Malachite Technologies, Inc.
-00065D Heidelberg Web Systems
-00065E Photuris, Inc.
-00065F ECI Telecom - NGTS Ltd.
-000660 NADEX Co., Ltd.
-000661 NIA Home Technologies Corp.
-000662 MBM Technology Ltd.
-000663 Human Technology Co., Ltd.
-000664 Fostex Corporation
-000665 Sunny Giken, Inc.
-000666 Roving Networks
-000667 Tripp Lite
-000668 Vicon Industries Inc.
-000669 Datasound Laboratories Ltd
-00066A InfiniCon Systems, Inc.
-00066B Sysmex Corporation
-00066C Robinson Corporation
-00066D Compuprint S.P.A.
-00066E Delta Electronics, Inc.
-00066F Korea Data Systems
-000670 Upponetti Oy
-000671 Softing AG
-000672 Netezza
-000673 Optelecom, Inc.
-000674 Spectrum Control, Inc.
-000675 Banderacom, Inc.
-000676 Novra Technologies Inc.
-000677 SICK AG
-000678 Marantz Japan, Inc.
-000679 Konami Corporation
-00067A JMP Systems
-00067B Toplink C&C Corporation
-00067C CISCO SYSTEMS, INC.
-00067D Takasago Ltd.
-00067E WinCom Systems, Inc.
-00067F Rearden Steel Technologies
-000680 Card Access, Inc.
-000681 Goepel Electronic GmbH
-000682 Convedia
-000683 Bravara Communications, Inc.
-000684 Biacore AB
-000685 NetNearU Corporation
-000686 ZARDCOM Co., Ltd.
-000687 Omnitron Systems Technology, Inc.
-000688 Telways Communication Co., Ltd.
-000689 yLez Technologies Pte Ltd
-00068A NeuronNet Co. Ltd. R&D Center
-00068B AirRunner Technologies, Inc.
-00068C 3Com Corporation
-00068D SANgate Systems
-00068E HID Corporation
-00068F Telemonitor, Inc.
-000690 Euracom Communication GmbH
-000691 PT Inovacao
-000692 Intruvert Networks, Inc.
-000693 Flexus Computer Technology, Inc.
-000694 Mobillian Corporation
-000695 Ensure Technologies, Inc.
-000696 Advent Networks
-000697 R & D Center
-000698 egnite Software GmbH
-000699 Vida Design Co.
-00069A e & Tel
-00069B AVT Audio Video Technologies GmbH
-00069C Transmode Systems AB
-00069D Petards Mobile Intelligence
-00069E UNIQA, Inc.
-00069F Kuokoa Networks
-0006A0 Mx Imaging
-0006A1 Celsian Technologies, Inc.
-0006A2 Microtune, Inc.
-0006A3 Bitran Corporation
-0006A4 INNOWELL Corp.
-0006A5 PINON Corp.
-0006A6 Artistic Licence (UK) Ltd
-0006A7 Primarion
-0006A8 KC Technology, Inc.
-0006A9 Universal Instruments Corp.
-0006AA Miltope Corporation
-0006AB W-Link Systems, Inc.
-0006AC Intersoft Co.
-0006AD KB Electronics Ltd.
-0006AE Himachal Futuristic Communications Ltd
-0006B0 Comtech EF Data Corp.
-0006B1 Sonicwall
-0006B2 Linxtek Co.
-0006B3 Diagraph Corporation
-0006B4 Vorne Industries, Inc.
-0006B5 Luminent, Inc.
-0006B6 Nir-Or Israel Ltd.
-0006B7 TELEM GmbH
-0006B8 Bandspeed Pty Ltd
-0006B9 A5TEK Corp.
-0006BA Westwave Communications
-0006BB ATI Technologies Inc.
-0006BC Macrolink, Inc.
-0006BD BNTECHNOLOGY Co., Ltd.
-0006BE Baumer Optronic GmbH
-0006BF Accella Technologies Co., Ltd.
-0006C0 United Internetworks, Inc.
-0006C1 CISCO SYSTEMS, INC.
-0006C2 Smartmatic Corporation
-0006C3 Schindler Elevators Ltd.
-0006C4 Piolink Inc.
-0006C5 INNOVI Technologies Limited
-0006C6 lesswire AG
-0006C7 RFNET Technologies Pte Ltd (S)
-0006C8 Sumitomo Metal Micro Devices, Inc.
-0006C9 Technical Marketing Research, Inc.
-0006CA American Computer & Digital Components, Inc. (ACDC)
-0006CB Jotron Electronics A/S
-0006CC JMI Electronics Co., Ltd.
-0006CD CreoScitex Corporation Ltd.
-0006CE DATENO
-0006CF Thales Avionics In-Flight Systems, LLC
-0006D0 Elgar Electronics Corp.
-0006D1 Tahoe Networks, Inc.
-0006D2 Tundra Semiconductor Corp.
-0006D3 Alpha Telecom, Inc. U.S.A.
-0006D4 Interactive Objects, Inc.
-0006D5 Diamond Systems Corp.
-0006D6 Cisco Systems, Inc.
-0006D7 Cisco Systems, Inc.
-0006D8 Maple Optical Systems
-0006D9 IPM-Net S.p.A.
-0006DA ITRAN Communications Ltd.
-0006DB ICHIPS Co., Ltd.
-0006DC Syabas Technology (Amquest)
-0006DD AT & T Laboratories - Cambridge Ltd
-0006DE Flash Technology
-0006DF AIDONIC Corporation
-0006E0 MAT Co., Ltd.
-0006E1 Techno Trade s.a
-0006E2 Ceemax Technology Co., Ltd.
-0006E3 Quantitative Imaging Corporation
-0006E4 Citel Technologies Ltd.
-0006E5 Fujian Newland Computer Ltd. Co.
-0006E6 DongYang Telecom Co., Ltd.
-0006E7 Bit Blitz Communications Inc.
-0006E8 Optical Network Testing, Inc.
-0006E9 Intime Corp.
-0006EA ELZET80 Mikrocomputer GmbH&Co. KG
-0006EB Global Data
-0006EC M/A COM Private Radio System Inc.
-0006ED Inara Networks
-0006EE Shenyang Neu-era Information & Technology Stock Co., Ltd
-0006EF Maxxan Systems, Inc.
-0006F0 Digeo, Inc.
-0006F1 Optillion
-0006F2 Platys Communications
-0006F3 AcceLight Networks
-0006F4 Prime Electronics & Satellitics Inc.
-0006F9 Mitsui Zosen Systems Research Inc.
-0006FA IP SQUARE Co, Ltd.
-0006FB Hitachi Printing Solutions, Ltd.
-0006FC Fnet Co., Ltd.
-0006FD Comjet Information Systems Corp.
-0006FE Celion Networks, Inc.
-0006FF Sheba Systems Co., Ltd.
-000700 Zettamedia Korea
-000701 RACAL-DATACOM
-000702 Varian Medical Systems
-000703 CSEE Transport
-000705 Endress & Hauser GmbH & Co
-000706 Sanritz Corporation
-000707 Interalia Inc.
-000708 Bitrage Inc.
-000709 Westerstrand Urfabrik AB
-00070A Unicom Automation Co., Ltd.
-00070B Octal, SA
-00070C SVA-Intrusion.com Co. Ltd.
-00070D Cisco Systems Inc.
-00070E Cisco Systems Inc.
-00070F Fujant, Inc.
-000710 Adax, Inc.
-000711 Acterna
-000712 JAL Information Technology
-000713 IP One, Inc.
-000714 Brightcom
-000715 General Research of Electronics, Inc.
-000716 J & S Marine Ltd.
-000717 Wieland Electric GmbH
-000718 iCanTek Co., Ltd.
-000719 Mobiis Co., Ltd.
-00071A Finedigital Inc.
-00071B Position Technology Inc.
-00071C AT&T Fixed Wireless Services
-00071D Satelsa Sistemas Y Aplicaciones De Telecomunicaciones, S.A.
-00071E Tri-M Engineering / Nupak Dev. Corp.
-00071F European Systems Integration
-000720 Trutzschler GmbH & Co. KG
-000721 Formac Elektronik GmbH
-000722 Nielsen Media Research
-000723 ELCON Systemtechnik GmbH
-000724 Telemax Co., Ltd.
-000725 Bematech International Corp.
-000727 Zi Corporation (HK) Ltd.
-000728 Neo Telecom
-000729 Kistler Instrumente AG
-00072A Innovance Networks
-00072B Jung Myung Telecom Co., Ltd.
-00072C Fabricom
-00072D CNSystems
-00072E North Node AB
-00072F Instransa, Inc.
-000730 Hutchison OPTEL Telecom Technology Co., Ltd.
-000731 Spiricon, Inc.
-000732 AAEON Technology Inc.
-000733 DANCONTROL Engineering
-000734 ONStor, Inc.
-000735 Flarion Technologies, Inc.
-000736 Data Video Technologies Co., Ltd.
-000737 Soriya Co. Ltd.
-000738 Young Technology Co., Ltd.
-000739 Motion Media Technology Ltd.
-00073A Inventel Systemes
-00073B Tenovis GmbH & Co KG
-00073C Telecom Design
-00073D Nanjing Postel Telecommunications Co., Ltd.
-00073E China Great-Wall Computer Shenzhen Co., Ltd.
-00073F Woojyun Systec Co., Ltd.
-000740 Melco Inc.
-000741 Sierra Automated Systems
-000742 Current Technologies
-000743 Chelsio Communications
-000744 Unico, Inc.
-000745 Radlan Computer Communications Ltd.
-000746 Interlink BT, LLC
-000747 Mecalc
-000748 The Imaging Source Europe
-000749 CENiX Inc.
-00074A Carl Valentin GmbH
-00074B Daihen Corporation
-00074C Beicom Inc.
-00074D Zebra Technologies Corp.
-00074E Naughty boy co., Ltd.
-00074F Cisco Systems, Inc.
-000750 Cisco Systems, Inc.
-000751 m.u.t. - GmbH
-000752 Rhythm Watch Co., Ltd.
-000753 Beijing Qxcomm Technology Co., Ltd.
-000754 Xyterra Computing, Inc.
-000755 Lafon SA
-000756 Juyoung Telecom
-000757 Topcall International AG
-000758 Dragonwave
-000759 Boris Manufacturing Corp.
-00075A Air Products and Chemicals, Inc.
-00075B Gibson Guitars
-00075C ENCAD, Inc.
-00075D Celleritas Inc.
-00075E Pulsar Technologies, Inc.
-00075F VCS Video Communication Systems AG
-000760 TOMIS Information & Telecom Corp.
-000761 Logitech SA
-000762 Group Sense Limited
-000763 Sunniwell Cyber Tech. Co., Ltd.
-000764 YoungWoo Telecom Co. Ltd.
-000765 Jade Quantum Technologies, Inc.
-000766 Chou Chin Industrial Co., Ltd.
-000767 Yuxing Electronics Company Limited
-000768 Danfoss A/S
-000769 Italiana Macchi SpA
-00076A NEXTEYE Co., Ltd.
-00076B Stralfors AB
-00076C Daehanet, Inc.
-00076D Flexlight Networks
-00076E Sinetica Corporation Ltd.
-00076F Synoptics Limited
-000770 Locusnetworks Corporation
-000771 Embedded System Corporation
-000772 Alcatel Shanghai Bell Co., Ltd.
-000773 Ascom Powerline Communications Ltd.
-000774 GuangZhou Thinker Technology Co. Ltd.
-000775 Valence Semiconductor, Inc.
-000776 Federal APD
-000777 Motah Ltd.
-000778 GERSTEL GmbH & Co. KG
-000779 Sungil Telecom Co., Ltd.
-00077A Infoware System Co., Ltd.
-00077B Millimetrix Broadband Networks
-00077C OnTime Networks
-00077E Elrest GmbH
-00077F J Communications Co., Ltd.
-000780 Bluegiga Technologies OY
-000781 Itron Inc.
-000782 Nauticus Networks, Inc.
-000783 SynCom Network, Inc.
-000784 Cisco Systems Inc.
-000785 Cisco Systems Inc.
-000786 Wireless Networks Inc.
-000787 Idea System Co., Ltd.
-000788 Clipcomm, Inc.
-000789 Eastel Systems Corporation
-00078A Mentor Data System Inc.
-00078B Wegener Communications, Inc.
-00078C Elektronikspecialisten i Borlange AB
-00078D NetEngines Ltd.
-00078E Garz & Friche GmbH
-00078F Emkay Innovative Products
-000790 Tri-M Technologies (s) Limited
-000791 International Data Communications, Inc.
-000792 Suetron Electronic GmbH
-000794 Simple Devices, Inc.
-000795 Elitegroup Computer System Co. (ECS)
-000796 LSI Systems, Inc.
-000797 Netpower Co., Ltd.
-000798 Selea SRL
-000799 Tipping Point Technologies, Inc.
-00079A SmartSight Networks Inc.
-00079B Aurora Networks
-00079C Golden Electronics Technology Co., Ltd.
-00079D Musashi Co., Ltd.
-00079E Ilinx Co., Ltd.
-00079F Action Digital Inc.
-0007A0 e-Watch Inc.
-0007A1 VIASYS Healthcare GmbH
-0007A2 Opteon Corporation
-0007A3 Ositis Software, Inc.
-0007A4 GN Netcom Ltd.
-0007A5 Y.D.K Co. Ltd.
-0007A6 Home Automation, Inc.
-0007A7 A-Z Inc.
-0007A8 Haier Group Technologies Ltd.
-0007A9 Novasonics
-0007AA Quantum Data Inc.
-0007AC Eolring
-0007AD Pentacon GmbH Foto-und Feinwerktechnik
-0007AE Layer N Networks
-0007AF N-Tron Corp.
-0007B0 Office Details, Inc.
-0007B1 Equator Technologies
-0007B2 Transaccess S.A.
-0007B3 Cisco Systems Inc.
-0007B4 Cisco Systems Inc.
-0007B5 Any One Wireless Ltd.
-0007B6 Telecom Technology Ltd.
-0007B7 Samurai Ind. Prods Eletronicos Ltda
-0007B8 American Predator Corp.
-0007B9 Ginganet Corporation
-0007BA Xebeo Communications, Inc.
-0007BB Candera Inc.
-0007BC Identix Inc.
-0007BD Radionet Ltd.
-0007BE DataLogic SpA
-0007BF Armillaire Technologies, Inc.
-0007C0 NetZerver Inc.
-0007C1 Overture Networks, Inc.
-0007C2 Netsys Telecom
-0007C3 Cirpack
-0007C4 JEAN Co. Ltd.
-0007C5 Gcom, Inc.
-0007C6 VDS Vosskuhler GmbH
-0007C7 Synectics Systems Limited
-0007C8 Brain21, Inc.
-0007C9 Technol Seven Co., Ltd.
-0007CA Creatix Polymedia Ges Fur Kommunikaitonssysteme
-0007CB Freebox SA
-0007CC Kaba Benzing GmbH
-0007CD NMTEL Co., Ltd.
-0007CE Cabletime Limited
-0007CF Anoto AB
-0007D0 Automat Engenharia de Automaoa Ltda.
-0007D1 Spectrum Signal Processing Inc.
-0007D2 Logopak Systeme
-0007D3 Stork Digital Imaging B.V.
-0007D4 Zhejiang Yutong Network Communication Co Ltd.
-0007D5 3e Technologies Int;., Inc.
-0007D6 Commil Ltd.
-0007D7 Caporis Networks AG
-0007D8 Hitron Systems Inc.
-0007D9 Splicecom
-0007DA Neuro Telecom Co., Ltd.
-0007DB Kirana Networks, Inc.
-0007DC Atek Co, Ltd.
-0007DD Cradle Technologies
-0007DE eCopilt AB
-0007DF Vbrick Systems Inc.
-0007E0 Palm Inc.
-0007E1 WIS Communications Co. Ltd.
-0007E2 Bitworks, Inc.
-0007E3 Navcom Technology, Inc.
-0007E4 SoftRadio Co., Ltd.
-0007E5 Coup Corporation
-0007E6 edgeflow Canada Inc.
-0007E7 FreeWave Technologies
-0007E8 St. Bernard Software
-0007E9 Intel Corporation
-0007EA Massana, Inc.
-0007EB Cisco Systems Inc.
-0007EC Cisco Systems Inc.
-0007ED Altera Corporation
-0007EE telco Informationssysteme GmbH
-0007EF Lockheed Martin Tactical Systems
-0007F0 LogiSync Corporation
-0007F1 TeraBurst Networks Inc.
-0007F2 IOA Corporation
-0007F3 Think Engine Networks
-0007F4 Eletex Co., Ltd.
-0007F5 Bridgeco Co AG
-0007F6 Qqest Software Systems
-0007F7 Galtronics
-0007F8 ITDevices, Inc.
-0007F9 Phonetics, Inc.
-0007FA ITT Co., Ltd.
-0007FB Giga Stream UMTS Technologies GmbH
-0007FC Adept Systems Inc.
-0007FD LANergy Ltd.
-0007FE Rigaku Corporation
-0007FF Gluon Networks
-000800 MULTITECH SYSTEMS, INC.
-000801 HighSpeed Surfing Inc.
-000802 Compaq Computer Corporation
-000803 Cos Tron
-000804 ICA Inc.
-000805 Techno-Holon Corporation
-000806 Raonet Systems, Inc.
-000807 Access Devices Limited
-000808 PPT Vision, Inc.
-000809 Systemonic AG
-00080A Espera-Werke GmbH
-00080B Birka BPA Informationssystem AB
-00080C VDA elettronica SrL
-00080D Toshiba
-00080E Motorola, BCS
-00080F Proximion Fiber Optics AB
-000810 Key Technology, Inc.
-000811 VOIX Corporation
-000812 GM-2 Corporation
-000813 Diskbank, Inc.
-000814 TIL Technologies
-000815 CATS Co., Ltd.
-000816 Bluetags A/S
-000817 EmergeCore Networks LLC
-000818 Pixelworks, Inc.
-000819 Banksys
-00081A Sanrad Intelligence Storage Communications (2000) Ltd.
-00081B Windigo Systems
-00081C @pos.com
-00081D Ipsil, Incorporated
-00081E Repeatit AB
-00081F Pou Yuen Tech Corp. Ltd.
-000820 Cisco Systems Inc.
-000821 Cisco Systems Inc.
-000822 InPro Comm
-000823 Texa Corp.
-000824 Promatek Industries Ltd.
-000825 Acme Packet
-000826 Colorado Med Tech
-000827 Pirelli Cables & Systems
-000828 Koei Engineering Ltd.
-000829 Aval Nagasaki Corporation
-00082A Powerwallz Network Security
-00082B Wooksung Electronics, Inc.
-00082C Homag AG
-00082D Indus Teqsite Private Limited
-00082E Multitone Electronics PLC
-00084E DivergeNet, Inc.
-00084F Qualstar Corporation
-000850 Arizona Instrument Corp.
-000851 Canadian Bank Note Company, Ltd.
-000852 Davolink Co. Inc.
-000853 Schleicher GmbH & Co. Relaiswerke KG
-000854 Netronix, Inc.
-000855 NASA-Goddard Space Flight Center
-000856 Gamatronic Electronic Industries Ltd.
-000857 Polaris Networks, Inc.
-000858 Novatechnology Inc.
-000859 ShenZhen Unitone Electronics Co., Ltd.
-00085A IntiGate Inc.
-00085B Hanbit Electronics Co., Ltd.
-00085C Shanghai Dare Technologies Co. Ltd.
-00085D Aastra
-00085E PCO AG
-00085F Picanol N.V.
-000860 LodgeNet Entertainment Corp.
-000861 SoftEnergy Co., Ltd.
-000862 NEC Eluminant Technologies, Inc.
-000863 Entrisphere Inc.
-000864 Fasy S.p.A.
-000865 JASCOM CO., LTD
-000866 DSX Access Systems, Inc.
-000867 Uptime Devices
-000868 PurOptix
-000869 Command-e Technology Co.,Ltd.
-00086A Industrie Technik IPS GmbH
-00086B MIPSYS
-00086C Plasmon LMS
-00086D Missouri FreeNet
-00086E Hyglo AB
-00086F Resources Computer Network Ltd.
-000870 Rasvia Systems, Inc.
-000871 NORTHDATA Co., Ltd.
-000872 Sorenson Technologies, Inc.
-000873 DAP Design B.V.
-000874 Dell Computer Corp.
-000875 Acorp Electronics Corp.
-000876 SDSystem
-000877 Liebert HIROSS S.p.A.
-000878 Benchmark Storage Innovations
-000879 CEM Corporation
-00087A Wipotec GmbH
-00087B RTX Telecom A/S
-00087C Cisco Systems, Inc.
-00087D Cisco Systems Inc.
-00087E Bon Electro-Telecom Inc.
-00087F SPAUN electronic GmbH & Co. KG
-000880 BroadTel Canada Communications inc.
-000881 DIGITAL HANDS CO.,LTD.
-000882 SIGMA CORPORATION
-000883 Hewlett-Packard Company
-000884 Index Braille AB
-000885 EMS Dr. Thomas Wuensche
-000886 Hansung Teliann, Inc.
-000887 Maschinenfabrik Reinhausen GmbH
-000888 OULLIM Information Technology Inc,.
-000889 Echostar Technologies Corp
-00088A Minds@Work
-00088B Tropic Networks Inc.
-00088C Quanta Network Systems Inc.
-00088D Sigma-Links Inc.
-00088E Nihon Computer Co., Ltd.
-00088F ADVANCED DIGITAL TECHNOLOGY
-000890 AVILINKS SA
-000891 Lyan Inc.
-000892 EM Solutions
-000894 InnoVISION Multimedia Ltd.
-000895 DIRC Technologie GmbH & Co.KG
-000896 Printronix, Inc.
-000897 Quake Technologies
-000898 Gigabit Optics Corporation
-000899 Netbind, Inc.
-00089A Alcatel Microelectronics
-00089B ICP Electronics Inc.
-00089C Elecs Industry Co., Ltd.
-00089D UHD-Elektronik
-00089E Beijing Enter-Net co.LTD
-00089F EFM Networks
-0008A0 Stotz Feinmesstechnik GmbH
-0008A1 CNet Technology Inc.
-0008A2 ADI Engineering, Inc.
-0008A3 Cisco Systems
-0008A4 Cisco Systems
-0008A5 Peninsula Systems Inc.
-0008A6 Multiware & Image Co., Ltd.
-0008A7 iLogic Inc.
-0008A8 Systec Co., Ltd.
-0008A9 SangSang Technology, Inc.
-0008AA KARAM
-0008AB EnerLinx.com, Inc.
-0008AD Toyo-Linx Co., Ltd.
-0008AE Packetfront
-0008AF Novatec Corporation
-0008B0 BKtel communications GmbH
-0008B1 ProQuent Systems
-0008B2 SHENZHEN COMPASS TECHNOLOGY DEVELOPMENT CO.,LTD
-0008B3 Fastwel
-0008B4 SYSPOL
-0008B5 TAI GUEN ENTERPRISE CO., LTD
-0008B6 RouteFree, Inc.
-0008B7 HIT Incorporated
-0008B8 E.F. Johnson
-0008B9 KAON MEDIA Co., Ltd.
-0008BA Erskine Systems Ltd
-0008BB NetExcell
-0008BC Ilevo AB
-0008BD TEPG-US
-0008BE XENPAK MSA Group
-0008BF Aptus Elektronik AB
-0008C0 ASA SYSTEMS
-0008C1 Avistar Communications Corporation
-0008C2 Cisco Systems
-0008C3 Contex A/S
-0008C4 Hikari Co.,Ltd.
-0008C5 Liontech Co., Ltd.
-0008C6 Philips Consumer Communications
-0008C7 COMPAQ COMPUTER CORPORATION
-0008C8 Soneticom, Inc.
-0008C9 TechniSat Digital GmbH
-0008CA TwinHan Technology Co.,Ltd
-0008CB Zeta Broadband Inc.
-0008CC Remotec, Inc.
-0008CD With-Net Inc
-0008CF Nippon Koei Power Systems Co., Ltd.
-0008D0 Musashi Engineering Co., LTD.
-0008D1 KAREL INC.
-0008D2 ZOOM Networks Inc.
-0008D3 Hercules Technologies S.A.
-0008D4 IneoQuest Technologies, Inc
-0008D5 Vanguard Managed Solutions
-0008D6 HASSNET Inc.
-0008D7 HOW CORPORATION
-0008D8 Dowkey Microwave
-0008D9 Mitadenshi Co.,LTD
-0008DA SofaWare Technologies Ltd.
-0008DB Corrigent Systems
-0008DC Wiznet
-0008DD Telena Communications, Inc.
-0008DE 3UP Systems
-0008DF Alistel Inc.
-0008E0 ATO Technology Ltd.
-0008E1 Barix AG
-0008E2 Cisco Systems
-0008E3 Cisco Systems
-0008E4 Envenergy Inc
-0008E5 IDK Corporation
-0008E6 Littlefeet
-0008E7 SHI ControlSystems,Ltd.
-0008E8 Excel Master Ltd.
-0008E9 NextGig
-0008EA Motion Control Engineering, Inc
-0008EB ROMWin Co.,Ltd.
-0008EC Zonu, Inc.
-0008ED ST&T Instrument Corp.
-0008EE Logic Product Development
-0008EF DIBAL,S.A.
-0008F0 Next Generation Systems, Inc.
-0008F1 Voltaire
-0008F2 C&S Technology
-0008F3 WANY
-0008F4 Bluetake Technology Co., Ltd.
-0008F5 YESTECHNOLOGY Co.,Ltd.
-0008F6 SUMITOMO ELECTRIC HIGHTECHS.co.,ltd.
-0008F7 Hitachi Ltd, Semiconductor &amp; Integrated Circuits Gr
-0008F8 Guardall Ltd
-0008F9 Padcom, Inc.
-0008FA Karl E.Brinkmann GmbH
-0008FB SonoSite, Inc.
-0008FC Gigaphoton Inc.
-0008FD BlueKorea Co., Ltd.
-0008FE UNIK C&C Co.,Ltd.
-0008FF Trilogy Broadcast (Holdings) Ltd
-000900 TMT
-000901 Shenzhen Shixuntong Information & Technoligy Co
-000902 Redline Communications Inc.
-000903 Panasas, Inc
-000904 MONDIAL electronic
-000905 iTEC Technologies Ltd.
-000906 Esteem Networks
-000907 Chrysalis Development
-000908 VTech Technology Corp.
-000909 Telenor Connect A/S
-00090A SnedFar Technology Co., Ltd.
-00090B MTL Instruments PLC
-00090C Mayekawa Mfg. Co. Ltd.
-00090D LEADER ELECTRONICS CORP.
-00090E Helix Technology Inc.
-00090F Fortinet Inc.
-000910 Simple Access Inc.
-000911 Cisco Systems
-000912 Cisco Systems
-000914 COMPUTROLS INC.
-000915 CAS Corp.
-000916 Listman Home Technologies, Inc.
-000917 WEM Technology Inc
-000918 SAMSUNG TECHWIN CO.,LTD
-000919 MDS Gateways
-00091A Macat Optics & Electronics Co., Ltd.
-00091B Digital Generation Inc.
-00091C CacheVision, Inc
-00091D Proteam Computer Corporation
-00091E Firstech Technology Corp.
-00091F A&amp;D Co., Ltd.
-000920 EpoX COMPUTER CO.,LTD.
-000921 Planmeca Oy
-000922 Touchless Sensor Technology AG
-000923 Heaman System Co., Ltd
-000924 Telebau GmbH
-000925 VSN Systemen BV
-000926 YODA COMMUNICATIONS, INC.
-000927 TOYOKEIKI CO.,LTD.
-000928 Telecore Inc
-000929 Sanyo Industries (UK) Limited
-00092A MYTECS Co.,Ltd.
-00092B iQstor Networks, Inc.
-00092C Hitpoint Inc.
-00092D High Tech Computer, Corp.
-00092E B&Tech System Inc.
-00092F Akom Technology Corporation
-000930 AeroConcierge Inc.
-000931 Future Internet, Inc.
-000932 Omnilux
-000933 OPTOVALLEY Co. Ltd.
-000934 Dream-Multimedia-Tv GmbH
-000935 Sandvine Incorporated
-000936 Ipetronik GmbH & Co.KG
-000937 Inventec Appliance Corp
-000938 Allot Communications
-000939 ShibaSoku Co.,Ltd.
-00093A Molex Fiber Optics
-00093B HYUNDAI NETWORKS INC.
-00093C Jacques Technologies P/L
-00093D Newisys,Inc.
-00093E C&I Technologies
-00093F Double-Win Enterpirse CO., LTD
-000940 AGFEO GmbH & Co. KG
-000941 Allied Telesis K.K.
-000942 CRESCO, LTD.
-000943 Cisco Systems
-000944 Cisco Systems
-000945 Palmmicro Communications Inc
-000946 Cluster Labs GmbH
-000947 Aztek, Inc.
-000948 Vista Control Systems, Corp.
-000949 Glyph Technologies Inc.
-00094A Homenet Communications
-00094B FillFactory NV
-00094C Communication Weaver Co.,Ltd.
-00094D Braintree Communications Pty Ltd
-00094E BARTECH SYSTEMS INTERNATIONAL, INC
-00094F elmegt GmbH & Co. KG
-000950 Independent Storage Corporation
-000951 Apogee Instruments, Inc
-000952 Auerswald GmbH & Co. KG
-000953 Linkage System Integration Co.Ltd.
-000954 AMiT spol. s. r. o.
-000955 Young Generation International Corp.
-000956 Network Systems Group, Ltd. (NSG)
-000957 Supercaller, Inc.
-000958 INTELNET S.A.
-000959 Sitecsoft
-00095A RACEWOOD TECHNOLOGY
-00095B Netgear, Inc.
-00095C Philips Medical Systems - Cardiac and Monitoring Systems (CM
-00095D Dialogue Technology Corp.
-00095E Masstech Group Inc.
-00095F Telebyte, Inc.
-000960 YOZAN Inc.
-000961 Switchgear and Instrumentation Ltd
-000962 Filetrac AS
-000963 Dominion Lasercom Inc.
-000964 Hi-Techniques
-000966 Thales Navigation
-000967 Tachyon, Inc
-000968 TECHNOVENTURE, INC.
-000969 Meret Optical Communications
-00096A Cloverleaf Communications Inc.
-00096B IBM Corporation
-00096C Imedia Semiconductor Corp.
-00096D Powernet Technologies Corp.
-00096E GIANT ELECTRONICS LTD.
-00096F Beijing Zhongqing Elegant Tech. Corp.,Limited
-000970 Vibration Research Corporation
-000971 Time Management, Inc.
-000972 Securebase,Inc
-000973 Lenten Technology Co., Ltd.
-000974 Innopia Technologies, Inc.
-000975 fSONA Communications Corporation
-000976 Datasoft ISDN Systems GmbH
-000977 Brunner Elektronik AG
-000978 AIJI System Co., Ltd.
-000979 Advanced Television Systems Committee, Inc.
-00097A Louis Design Labs.
-00097B Cisco Systems
-00097C Cisco Systems
-00097D SecWell Networks Oy
-00097E IMI TECHNOLOGY CO., LTD
-00097F Vsecure 2000 LTD.
-000980 Power Zenith Inc.
-000981 Newport Networks
-000982 Loewe Opta GmbH
-000983 Gvision Incorporated
-000984 MyCasa Network Inc.
-000985 Auto Telecom Company
-000986 Metalink LTD.
-000987 NISHI NIPPON ELECTRIC WIRE & CABLE CO.,LTD.
-000988 Nudian Electron Co., Ltd.
-000989 VividLogic Inc.
-00098A EqualLogic Inc
-00098B Entropic Communications, Inc.
-00098C Possio AB
-00098D DCT Ltd (Digital Communication Technologies Ltd)
-00098E ipcas GmbH
-00098F Cetacean Networks
-000990 ACKSYS Communications & systems
-000991 GE Fanuc Automation Manufacturing, Inc.
-000992 InterEpoch Technology,INC.
-000993 Visteon Corporation
-000994 Cronyx Engineering
-000995 Castle Technology Ltd
-000996 RDI
-000997 Nortel Networks
-000998 Capinfo Company Limited
-000999 CP GEORGES RENAULT
-00099A ELMO COMPANY, LIMITED
-00099B Western Telematic Inc.
-00099C Naval Research Laboratory
-00099D Haliplex Communications
-00099E Testech, Inc.
-00099F VIDEX INC.
-0009A0 Microtechno Corporation
-0009A1 Telewise Communications, Inc.
-0009A2 Interface Co., Ltd.
-0009A3 Leadfly Techologies Corp. Ltd.
-0009A4 HARTEC Corporation
-0009A5 HANSUNG ELETRONIC INDUSTRIES DEVELOPMENT CO., LTD
-0009A6 Ignis Optics, Inc.
-0009A7 Bang & Olufsen A/S
-0009A8 Eastmode Pte Ltd
-0009A9 Ikanos Communications
-0009AA Data Comm for Business, Inc.
-0009AB Netcontrol Oy
-0009AC LANVOICE
-0009AD HYUNDAI SYSCOMM, INC.
-0009AE OKANO ELECTRIC CO.,LTD
-0009AF e-generis
-0009B0 Onkyo Corporation
-0009B1 Kanematsu Electronics, Ltd.
-0009B2 L&F Inc.
-0009B3 MCM Systems Ltd
-0009B4 KISAN TELECOM CO., LTD.
-0009B5 3J Tech. Co., Ltd.
-0009B6 Cisco Systems
-0009B7 Cisco Systems
-0009B8 Entise Systems
-0009B9 Action Imaging Solutions
-0009BA MAKU Informationstechik GmbH
-0009BB MathStar, Inc.
-0009BC Digital Safety Technologies Inc.
-0009BD Epygi Technologies, Ltd.
-0009BE Mamiya-OP Co.,Ltd.
-0009BF Nintendo Co.,Ltd.
-0009C0 6WIND
-0009C1 PROCES-DATA A/S
-0009C3 NETAS
-0009C4 Medicore Co., Ltd
-0009C5 KINGENE Technology Corporation
-0009C6 Visionics Corporation
-0009C7 Movistec
-0009C8 SINAGAWA TSUSHIN KEISOU SERVICE
-0009C9 BlueWINC Co., Ltd.
-0009CA iMaxNetworks(Shenzhen)Limited.
-0009CB HBrain
-0009CC Moog GmbH
-0009CD HUDSON SOFT CO.,LTD.
-0009CE SpaceBridge Semiconductor Corp.
-0009CF iAd GmbH
-0009D0 Versatel Networks
-0009D1 SERANOA NETWORKS INC
-0009D2 Mai Logic Inc.
-0009D3 Western DataCom Co., Inc.
-0009D4 Transtech Networks
-0009D5 Signal Communication, Inc.
-0009D6 KNC One GmbH
-0009D7 DC Security Products
-0009D9 Neoscale Systems, Inc
-0009DA Control Module Inc.
-0009DB eSpace
-0009DC Galaxis Technology AG
-0009DD Mavin Technology Inc.
-0009DE Samjin Information & Communications Co., Ltd.
-0009DF Vestel Komunikasyon Sanayi ve Ticaret A.S.
-0009E0 XEMICS S.A.
-0009E1 Gemtek Technology Co., Ltd.
-0009E2 Sinbon Electronics Co., Ltd.
-0009E3 Angel Iglesias S.A.
-0009E4 K Tech Infosystem Inc.
-0009E5 Hottinger Baldwin Messtechnik GmbH
-0009E6 Cyber Switching Inc.
-0009E7 ADC Techonology
-0009E8 Cisco Systems
-0009E9 Cisco Systems
-0009EA YEM Inc.
-0009EB HuMANDATA LTD.
-0009EC Daktronics, Inc.
-0009ED CipherOptics
-0009EE MEIKYO ELECTRIC CO.,LTD
-0009EF Vocera Communications
-0009F0 Shimizu Technology Inc.
-0009F1 Yamaki Electric Corporation
-0009F2 Cohu, Inc., Electronics Division
-0009F3 WELL Communication Corp.
-0009F4 Alcon Laboratories, Inc.
-0009F5 Emerson Network Power Co.,Ltd
-0009F6 Shenzhen Eastern Digital Tech Ltd.
-0009F7 SED, a division of Calian
-0009F8 UNIMO TECHNOLOGY CO., LTD.
-0009F9 ART JAPAN CO., LTD.
-0009FB Philips Medizinsysteme Boeblingen GmbH
-0009FC IPFLEX Inc.
-0009FD Ubinetics Limited
-0009FE Daisy Technologies, Inc.
-0009FF X.net 2000 GmbH
-000A00 Mediatek Corp.
-000A01 SOHOware, Inc.
-000A02 ANNSO CO., LTD.
-000A03 ENDESA SERVICIOS, S.L.
-000A04 3Com Europe Ltd
-000A05 Widax Corp.
-000A06 Teledex LLC
-000A07 WebWayOne Ltd
-000A08 ALPINE ELECTRONICS, INC.
-000A09 TaraCom Integrated Products, Inc.
-000A0A SUNIX Co., Ltd.
-000A0B Sealevel Systems, Inc.
-000A0C Scientific Research Corporation
-000A0D MergeOptics GmbH
-000A0E Invivo Research Inc.
-000A0F Ilryung Telesys, Inc
-000A10 FAST media integrations AG
-000A11 ExPet Technologies, Inc
-000A12 Azylex Technology, Inc
-000A13 Silent Witness
-000A14 TECO a.s.
-000A15 Silicon Data, Inc
-000A16 Lassen Research
-000A17 NESTAR COMMUNICATIONS, INC
-000A18 Vichel Inc.
-000A19 Valere Power, Inc.
-000A1A Imerge Ltd
-000A1B Stream Labs
-000A1C Bridge Information Co., Ltd.
-000A1D Optical Communications Products Inc.
-000A1E Red-M (Communications) Limited
-000A1F ART WARE Telecommunication Co., Ltd.
-000A20 SVA Networks, Inc.
-000A21 Integra Telecom Co. Ltd
-000A22 Amperion Inc
-000A23 Parama Networks Inc
-000A24 Octave Communications
-000A25 CERAGON NETWORKS
-000A26 CEIA S.p.A.
-000A27 Apple Computer, Inc.
-000A28 Motorola
-000A29 Pan Dacom Networking AG
-000A2A QSI Systems Inc.
-000A2B Etherstuff
-000A2C Active Tchnology Corporation
-000A2E MAPLE NETWORKS CO., LTD
-000A2F Artnix Inc.
-000A30 Johnson Controls-ASG
-000A31 HCV Wireless
-000A32 Xsido Corporation
-000A33 Sierra Logic, Inc.
-000A34 Identicard Systems Incorporated
-000A35 Xilinx
-000A36 Synelec Telecom Multimedia
-000A37 Procera Networks, Inc.
-000A38 Netlock Technologies, Inc.
-000A39 LoPA Information Technology
-000A3A J-THREE INTERNATIONAL Holding Co., Ltd.
-000A3B GCT Semiconductor, Inc
-000A3C Enerpoint Ltd.
-000A3D Elo Sistemas Eletronicos S.A.
-000A3E EADS Telecom
-000A3F Data East Corporation
-000A40 Crown Audio
-000A41 Cisco Systems
-000A42 Cisco Systems
-000A43 Chunghwa Telecom Co., Ltd.
-000A44 Avery Dennison Deutschland GmbH
-000A45 Audio-Technica Corp.
-000A46 ARO Controls SAS
-000A47 Allied Vision Technologies
-000A48 Albatron Technology
-000A49 Acopia Networks
-000A4A Targa Systems Ltd.
-000A4B DataPower Technology, Inc.
-000A4C Molecular Devices Corporation
-000A4D Noritz Corporation
-000A4E UNITEK Electronics INC.
-000A4F Brain Boxes Limited
-000A50 REMOTEK CORPORATION
-000A51 GyroSignal Technology Co., Ltd.
-000A52 Venitek Co. Ltd.
-000A53 Intronics, Incorporated
-000A54 Laguna Hills, Inc.
-000A55 MARKEM Corporation
-000A56 HITACHI Maxell Ltd.
-000A57 Hewlett-Packard Company - Standards
-000A58 Ingenieur-Buero Freyer & Siegel
-000A59 HW server
-000A5A GreenNET Technologies Co.,Ltd.
-000A5B Power-One as
-000A5C Carel s.p.a.
-000A5D PUC Founder (MSC) Berhad
-000A5E 3COM Corporation
-000A5F almedio inc.
-000A60 Autostar Technology Pte Ltd
-000A61 Cellinx Systems Inc.
-000A62 Crinis Networks, Inc.
-000A63 DHD GmbH
-000A64 Eracom Technologies
-000A65 GentechMedia.co.,ltd.
-000A66 MITSUBISHI ELECTRIC SYSTEM & SERVICE CO.,LTD.
-000A67 OngCorp
-000A68 SolarFlare Communications, Inc.
-000A69 SUNNY bell Technology Co., Ltd.
-000A6A SVM Microwaves s.r.o.
-000A6B Tadiran Telecom Business Systems LTD
-000A6C Walchem Corporation
-000A6D EKS Elektronikservice GmbH
-000A6E Broadcast Technology Limited
-000A6F ZyTera Technologies Inc.
-000A70 MPLS Forum
-000A71 Avrio Technologies, Inc
-000A72 SimpleTech, Inc.
-000A73 Scientific Atlanta
-000A74 Manticom Networks Inc.
-000A75 Cat Electronics
-000A76 Beida Jade Bird Huaguang Technology Co.,Ltd
-000A77 Bluewire Technologies LLC
-000A78 OLITEC
-000A79 corega K.K.
-000A7A Kyoritsu Electric Co., Ltd.
-000A7B Cornelius Consult
-000A7C Tecton Ltd
-000A7D Valo, Inc.
-000A7E The Advantage Group
-000A7F Teradon Industries, Inc
-000A80 Telkonet Inc.
-000A81 TEIMA Audiotex S.L.
-000A82 TATSUTA SYSTEM ELECTRONICS CO.,LTD.
-000A83 SALTO SYSTEMS S.L.
-000A84 Rainsun Enterprise Co., Ltd.
-000A85 PLAT'C2,Inc
-000A86 Lenze
-000A87 Integrated Micromachines Inc.
-000A88 InCypher S.A.
-000A89 Creval Systems, Inc.
-000A8A Cisco Systems
-000A8B Cisco Systems
-000A8C Guardware Systems Ltd.
-000A8D EUROTHERM LIMITED
-000A8E Invacom Ltd
-000A8F Aska International Inc.
-000A90 Bayside Interactive, Inc.
-000A91 HemoCue AB
-000A92 Presonus Corporation
-000A93 W2 Networks, Inc.
-000A94 ShangHai cellink CO., LTD
-000A95 Apple Computer, Inc.
-000A96 MEWTEL TECHNOLOGY INC.
-000A97 SONICblue, Inc.
-000A98 M+F Gwinner GmbH & Co
-000A99 Dataradio Inc.
-000A9A Aiptek International Inc
-000A9B Towa Meccs Corporation
-000A9C Server Technology, Inc.
-000A9D King Young Technology Co. Ltd.
-000A9E BroadWeb Corportation
-000A9F Pannaway Technologies, Inc.
-000AA0 Cedar Point Communications
-000AA1 V V S Limited
-000AA2 SYSTEK INC.
-000AA3 SHIMAFUJI ELECTRIC CO.,LTD.
-000AA4 SHANGHAI SURVEILLANCE TECHNOLOGY CO,LTD
-000AA5 MAXLINK INDUSTRIES LIMITED
-000AA6 Hochiki Corporation
-000AA7 FEI Company
-000AA8 ePipe Pty. Ltd.
-000AA9 Brooks Automation GmbH
-000AAA AltiGen Communications Inc.
-000AAB TOYOTA MACS, INC.
-000AAC TerraTec Electronic GmbH
-000AAD Stargames Corporation
-000AAE Rosemount Process Analytical
-000AAF Pipal Systems
-000AB0 LOYTEC electronics GmbH
-000AB1 GENETEC Corporation
-000AB2 Fresnel Wireless Systems
-000AB3 Fa. GIRA
-000AB4 ETIC Telecommunications
-000AB5 Digital Electronic Network
-000AB6 COMPUNETIX, INC
-000AB7 Cisco Systems
-000AB8 Cisco Systems
-000AB9 Astera Technologies Corp.
-000ABA Arcon Technology Limited
-000ABB Taiwan Secom Co,. Ltd
-000ABC Seabridge Ltd.
-000ABD Rupprecht & Patashnick Co.
-000ABE OPNET Technologies CO., LTD.
-000ABF HIROTA SS
-000AC0 Fuyoh Video Industry CO., LTD.
-000AC1 Futuretel
-000AC2 FiberHome Telecommunication Technologies CO.,LTD
-000AC3 eM Technics Co., Ltd.
-000AC4 Daewoo Teletech Co., Ltd
-000AC5 Color Kinetics
-000AC7 Unication Group
-000AC8 ZPSYS CO.,LTD. (Planning&Management)
-000AC9 Zambeel Inc
-000ACA YOKOYAMA SHOKAI CO.,Ltd.
-000ACB XPAK MSA Group
-000ACC Winnow Networks, Inc.
-000ACD Sunrich Technology Limited
-000ACE RADIANTECH, INC.
-000ACF PROVIDEO Multimedia Co. Ltd.
-000AD0 Niigata Develoment Center, F.I.T. Co., Ltd.
-000AD1 MWS
-000AD2 JEPICO Corporation
-000AD3 INITECH Co., Ltd
-000AD4 CoreBell Systems Inc.
-000AD5 Brainchild Electronic Co., Ltd.
-000AD6 BeamReach Networks
-000AD8 IPCserv Technology Corp.
-000AD9 Sony Ericsson Mobile Communications AB
-000ADB SkyPilot Network, Inc
-000ADC RuggedCom Inc.
-000ADD InSciTek Microsystems, Inc.
-000ADE Happy Communication Co., Ltd.
-000ADF Gennum Corporation
-000AE0 Fujitsu Softek
-000AE1 EG Technology
-000AE2 Binatone Electronics International, Ltd
-000AE3 YANG MEI TECHNOLOGY CO., LTD
-000AE4 Wistron Corp.
-000AE5 ScottCare Corporation
-000AE6 Elitegroup Computer System Co. (ECS)
-000AE7 ELIOP S.A.
-000AE8 Cathay Roxus Information Technology Co. LTD
-000AE9 AirVast Technology Inc.
-000AEA ADAM ELEKTRONIK LTD.STI.
-000AEB Shenzhen Tp-link Technology Co; Ltd.
-000AEC Koatsu Gas Kogyo Co., Ltd.
-000AED HARTING Vending G.m.b.H. & CO KG
-000AEE GCD Hard- & Software GmbH
-000AEF OTRUM ASA
-000AF0 SHIN-OH ELECTRONICS CO., LTD. R&D
-000AF1 Clarity Design, Inc.
-000AF2 NeoAxiom Corp.
-000AF3 Cisco Systems
-000AF4 Cisco Systems
-000AF5 Airgo Networks, Inc.
-000AF6 Computer Process Controls
-000AF7 Broadcom Corp.
-000AF8 American Telecare Inc.
-000AFA Traverse Technologies Australia
-000AFB Ambri Limited
-000AFC Core Tec Communications, LLC
-000AFD Viking Electronic Services
-000AFE NovaPal Ltd
-000AFF Kilchherr Elektronik AG
-000B00 FUJIAN START COMPUTER EQUIPMENT CO.,LTD
-000B01 DAIICHI ELECTRONICS CO., LTD.
-000B02 Dallmeier electronic
-000B03 Taekwang Industrial Co., Ltd
-000B04 Volktek Corporation
-000B05 Pacific Broadband Networks
-000B06 Motorola BCS
-000B07 Voxpath Networks
-000B08 Pillar Data Systems
-000B09 Ifoundry Systems Singapore
-000B0A dBm Optics
-000B0B Corrent Corporation
-000B0C Agile Systems Inc.
-000B0D Air2U, Inc.
-000B0E Trapeze Networks
-000B0F Nyquist Industrial Control BV
-000B10 11wave Technonlogy Co.,Ltd
-000B11 HIMEJI ABC TRADING CO.,LTD.
-000B13 ZETRON INC
-000B14 ViewSonic Corporation
-000B15 Platypus Technology
-000B16 Communication Machinery Corporation
-000B17 MKS Instruments
-000B19 Vernier Networks, Inc.
-000B1A Teltone Corporation
-000B1B Systronix, Inc.
-000B1D LayerZero Power Systems, Inc.
-000B1E KAPPA opto-electronics GmbH
-000B1F I CON Computer Co.
-000B20 Hirata corporation
-000B21 G-Star Communications Inc.
-000B22 Environmental Systems and Services
-000B23 Efficient Networks, Inc.
-000B24 AirLogic
-000B25 Aeluros
-000B26 Wetek Corporation
-000B27 Scion Corporation
-000B28 Quatech Inc.
-000B29 LG Industrial Systems Co.,Ltd.
-000B2A HOWTEL Co., Ltd.
-000B2B HOSTNET CORPORATION
-000B2C Eiki Industrial Co. Ltd.
-000B2D Danfoss Inc.
-000B2E Cal-Comp Electronics (Thailand) Public Company Limited Taipe
-000B2F bplan GmbH
-000B30 Beijing Gongye Science & Technology Co.,Ltd
-000B31 Yantai ZhiYang Scientific and technology industry CO., LTD
-000B32 VORMETRIC, INC.
-000B33 Vivato
-000B34 ShangHai Broadband Technologies CO.LTD
-000B35 Quad Bit System co., Ltd.
-000B36 Productivity Systems, Inc.
-000B37 MANUFACTURE DES MONTRES ROLEX SA
-000B38 Knuerr AG
-000B39 Keisoku Giken Co.,Ltd.
-000B3A Fortel DTV, Inc.
-000B3B devolo AG
-000B3C Cygnal Integrated Products, Inc.
-000B3D CONTAL OK Ltd.
-000B3E BittWare, Inc
-000B3F Anthology Solutions Inc.
-000B40 OpNext Inc.
-000B41 Ing. Buero Dr. Beutlhauser
-000B42 commax Co., Ltd.
-000B43 Microscan Systems, Inc.
-000B44 Concord IDea Corp.
-000B45 Cisco
-000B46 Cisco
-000B47 Advanced Energy
-000B48 sofrel
-000B49 RF-Link System Inc.
-000B4A Visimetrics (UK) Ltd
-000B4B VISIOWAVE SA
-000B4C Clarion (M) Sdn Bhd
-000B4D Emuzed
-000B4E VertexRSI Antenna Products Division
-000B4F Verifone, INC.
-000B50 Oxygnet
-000B51 Micetek International Inc.
-000B52 JOYMAX ELECTRONICS CORP.
-000B53 INITIUM Co., Ltd.
-000B54 BiTMICRO Networks, Inc.
-000B55 ADInstruments
-000B56 Cybernetics
-000B57 Silicon Laboratories
-000B58 Astronautics C.A LTD
-000B59 ScriptPro, LLC
-000B5A HyperEdge
-000B5B Rincon Research Corporation
-000B5C Newtech Co.,Ltd
-000B5D FUJITSU LIMITED
-000B5E ATMAVA Ltd
-000B5F Cisco Systems
-000B60 Cisco Systems
-000B61 Friedrich Lütze GmbH &Co.
-000B62 Ingenieurbüro Ingo Mohnen
-000B64 Kieback & Peter GmbH & Co KG
-000B65 Sy.A.C. srl
-000B66 Teralink Communications
-000B67 Topview Technology Corporation
-000B68 Addvalue Communications Pte Ltd
-000B69 Franke Finland Oy
-000B6A Asiarock Incorporation
-000B6B Wistron Neweb Corp.
-000B6C Sychip Inc.
-000B6D SOLECTRON JAPAN NAKANIIDA
-000B6E Neff Instrument Corp.
-000B6F Media Streaming Networks Inc
-000B70 Load Technology, Inc.
-000B71 Litchfield Communications Inc.
-000B72 Lawo AG
-000B73 Kodeos Communications
-000B74 Kingwave Technology Co., Ltd.
-000B75 Iosoft Ltd.
-000B76 ET&T Co. Ltd.
-000B77 Cogent Systems, Inc.
-000B78 TAIFATECH INC.
-000B79 X-COM, Inc.
-000B7B Test-Um Inc.
-000B7C Telex Communications
-000B7D SOLOMON EXTREME INTERNATIONAL LTD.
-000B7E SAGINOMIYA Seisakusho Inc.
-000B7F OmniWerks
-000B81 Kaparel Corporation
-000B82 Grandstream Networks, Inc.
-000B83 DATAWATT B.V.
-000B84 BODET
-000B85 Airespace, Inc.
-000B86 Aruba Networks
-000B87 American Reliance Inc.
-000B88 Vidisco ltd.
-000B89 Top Global Technology, Ltd.
-000B8A MITEQ Inc.
-000B8B KERAJET, S.A.
-000B8C flextronics israel
-000B8D Avvio Networks
-000B8E Ascent Corporation
-000B8F AKITA ELECTRONICS SYSTEMS CO.,LTD.
-000B90 Covaro Networks, Inc.
-000B91 Aglaia Gesellschaft für Bildverarbeitung und Kommunikation m
-000B92 Ascom Danmark A/S
-000B93 Barmag Electronic
-000B94 Digital Monitoring Products, Inc.
-000B95 eBet Gaming Systems Pty Ltd
-000B96 Innotrac Diagnostics Oy
-000B97 Matsushita Electric Industrial Co.,Ltd.
-000B98 NiceTechVision
-000B99 SensAble Technologies, Inc.
-000B9A Shanghai Ulink Telecom Equipment Co. Ltd.
-000B9B Sirius System Co, Ltd.
-000B9C TriBeam Technologies, Inc.
-000B9D TwinMOS Technologies Inc.
-000B9E Yasing Technology Corp.
-000B9F Neue ELSA GmbH
-000BA0 T&L Information Inc.
-000BA1 SYSCOM Ltd.
-000BA2 Sumitomo Electric Networks, Inc
-000BA3 Siemens AG, I&S
-000BA4 Shiron Satellite Communications Ltd. (1996)
-000BA5 Quasar Cipta Mandiri, PT
-000BA6 Miyakawa Electric Works Ltd.
-000BA7 Maranti Networks
-000BA8 HANBACK ELECTRONICS CO., LTD.
-000BAA Aiphone co.,Ltd
-000BAB Advantech Technology (CHINA) Co., Ltd.
-000BAC 3Com Europe Ltd.
-000BAD PC-PoS Inc.
-000BAE Vitals System Inc.
-000BB0 Sysnet Telematica srl
-000BB1 Super Star Technology Co., Ltd.
-000BB2 SMALLBIG TECHNOLOGY
-000BB3 RiT technologies Ltd.
-000BB4 RDC Semiconductor Inc.,
-000BB5 nStor Technologies, Inc.
-000BB6 Mototech Inc.
-000BB7 Micro Systems Co.,Ltd.
-000BB8 Kihoku Electronic Co.
-000BB9 Imsys AB
-000BBA Harmonic Broadband Access Networks
-000BBB Etin Systems Co., Ltd
-000BBC En Garde Systems, Inc.
-000BBD Connexionz Limited
-000BBE Cisco Systems
-000BBF Cisco Systems
-000BC0 China IWNComm Co., Ltd.
-000BC1 Bay Microsystems, Inc.
-000BC2 Corinex Communication Corp.
-000BC3 Multiplex, Inc.
-000BC4 BIOTRONIK GmbH & Co
-000BC5 SMC Networks, Inc.
-000BC6 ISAC, Inc.
-000BC7 ICET S.p.A.
-000BC8 AirFlow Networks
-000BC9 Electroline Equipment
-000BCA DATAVAN International Corporation
-000BCB Fagor Automation , S. Coop
-000BCC JUSAN, S.A.
-000BCD Compaq (HP)
-000BCE Free2move AB
-000BCF AGFA NDT INC.
-000BD0 XiMeta Technology Americas Inc.
-000BD1 Aeronix, Inc.
-000BD2 Remopro Technology Inc.
-000BD3 cd3o
-000BD4 Beijing Wise Technology & Science Development Co.Ltd
-000BD5 Nvergence, Inc.
-000BD6 Paxton Access Ltd
-000BD7 MBB Gelma GmbH
-000BD8 Industrial Scientific Corp.
-000BD9 General Hydrogen
-000BDA EyeCross Co.,Inc.
-000BDB Dell ESG PCBA Test
-000BDC AKCP
-000BDD TOHOKU RICOH Co., LTD.
-000BDF Shenzhen RouterD Networks Limited
-000BE0 SercoNet Ltd.
-000BE2 Lumenera Corporation
-000BE3 Key Stream Co., Ltd.
-000BE4 Hosiden Corporation
-000BE5 HIMS Korea Co., Ltd.
-000BE6 Datel Electronics
-000BE7 COMFLUX TECHNOLOGY INC.
-000BE8 AOIP
-000BEA Zultys Technologies
-000BEB Systegra AG
-000BEC NIPPON ELECTRIC INSTRUMENT, INC.
-000BED ELM Inc.
-000BEE inc.jet, Incorporated
-000BEF Code Corporation
-000BF0 MoTEX Products Co., Ltd.
-000BF1 LAP Laser Applikations
-000BF2 Chih-Kan Technology Co., Ltd.
-000BF3 BAE SYSTEMS
-000BF5 Shanghai Sibo Telecom Technology Co.,Ltd
-000BF6 Nitgen Co., Ltd
-000BF7 NIDEK CO.,LTD
-000BF8 Infinera
-000BF9 Gemstone communications, Inc.
-000BFB D-NET International Corporation
-000BFC Cisco Systems
-000BFD Cisco Systems
-000BFE CASTEL Broadband Limited
-000BFF Berkeley Camera Engineering
-000C00 BEB Industrie-Elektronik AG
-000C01 Abatron AG
-000C02 ABB Oy
-000C03 HDMI Licensing, LLC
-000C04 Tecnova
-000C05 RPA Reserch Co., Ltd.
-000C06 Nixvue Systems Pte Ltd
-000C07 Iftest AG
-000C08 HUMEX Technologies Corp.
-000C09 Hitachi IE Systems Co., Ltd
-000C0A Guangdong Province Electronic Technology Research Institute
-000C0B Broadbus Technologies
-000C0C APPRO TECHNOLOGY INC.
-000C0D Communications & Power Industries / Satcom Division
-000C0E XtremeSpectrum, Inc.
-000C0F Techno-One Co., Ltd
-000C10 PNI Corporation
-000C11 NIPPON DEMPA CO.,LTD.
-000C12 Micro-Optronic-Messtechnik GmbH
-000C13 MediaQ
-000C14 Diagnostic Instruments, Inc.
-000C15 CyberPower Systems, Inc.
-000C16 Concorde Microsystems Inc.
-000C17 AJA Video Systems Inc
-000C18 Zenisu Keisoku Inc.
-000C19 Telio Communications GmbH
-000C1A Quest Technical Solutions Inc.
-000C1B ORACOM Co, Ltd.
-000C1C MicroWeb Co., Ltd.
-000C1D Mettler & Fuchs AG
-000C1E Global Cache
-000C1F Glimmerglass Networks
-000C20 Fi WIn, Inc.
-000C21 Faculty of Science and Technology, Keio University
-000C22 Double D Electronics Ltd
-000C23 Beijing Lanchuan Tech. Co., Ltd.
-000C25 Allied Telesyn Networks
-000C26 Weintek Labs. Inc.
-000C27 Sammy Corporation
-000C28 RIFATRON
-000C29 VMware, Inc.
-000C2A OCTTEL Communication Co., Ltd.
-000C2B ELIAS Technology, Inc.
-000C2C Enwiser Inc.
-000C2D FullWave Technology Co., Ltd.
-000C2E Openet information technology(shenzhen) Co., Ltd.
-000C2F SeorimTechnology Co.,Ltd.
-000C30 Cisco
-000C31 Cisco
-000C32 Avionic Design Development GmbH
-000C33 Compucase Enterprise Co. Ltd.
-000C34 Vixen Co., Ltd.
-000C35 KaVo Dental GmbH & Co. KG
-000C36 SHARP TAKAYA ELECTRONICS INDUSTRY CO.,LTD.
-000C37 Geomation, Inc.
-000C38 TelcoBridges Inc.
-000C39 Sentinel Wireless Inc.
-000C3A Oxance
-000C3B Orion Electric Co., Ltd.
-000C3C MediaChorus, Inc.
-000C3D Glsystech Co., Ltd.
-000C3E Crest Audio
-000C3F Cogent Defence & Security Networks,
-000C40 Altech Controls
-000C41 The Linksys Group, Inc.
-000C42 Routerboard.com
-000C43 Ralink Technology, Corp.
-000C44 Automated Interfaces, Inc.
-000C45 Animation Technologies Inc.
-000C46 Allied Telesyn Inc.
-000C47 SK Teletech(R&D Planning Team)
-000C48 QoStek Corporation
-000C49 Dangaard Telecom RTC Division A/S
-000C4A Cygnus Microsystems Private Limited
-000C4B Cheops Elektronik
-000C4C Arcor AG&Co.
-000C4D ACRA CONTROL
-000C4E Winbest Technology CO,LT
-000C4F UDTech Japan Corporation
-000C50 Seagate Technology
-000C51 Scientific Technologies Inc.
-000C52 Roll Systems Inc.
-000C54 Pedestal Networks, Inc
-000C55 Microlink Communications Inc.
-000C56 Megatel Computer (1986) Corp.
-000C57 MACKIE Engineering Services Belgium BVBA
-000C58 M&S Systems
-000C59 Indyme Electronics, Inc.
-000C5A IBSmm Industrieelektronik Multimedia
-000C5B HANWANG TECHNOLOGY CO.,LTD
-000C5C GTN Systems B.V.
-000C5D CHIC TECHNOLOGY (CHINA) CORP.
-000C5F Avtec, Inc.
-000C60 ACM Systems
-000C61 AC Tech corporation DBA Advanced Digital
-000C62 ABB Automation Technology Products AB, Control
-000C63 Zenith Electronics Corporation
-000C64 X2 MSA Group
-000C65 Sunin Telecom
-000C66 Pronto Networks Inc
-000C67 OYO ELECTRIC CO.,LTD
-000C68 Oasis Semiconductor, Inc.
-000C69 National Radio Astronomy Observatory
-000C6A MBARI
-000C6B Kurz Industrie-Elektronik GmbH
-000C6C Elgato Systems LLC
-000C6D BOC Edwards
-000C6E ASUSTEK COMPUTER INC.
-000C6F Amtek system co.,LTD.
-000C70 ACC GmbH
-000C71 Wybron, Inc
-000C72 Tempearl Industrial Co., Ltd.
-000C73 TELSON ELECTRONICS CO., LTD
-000C74 RIVERTEC CORPORATION
-000C75 Oriental integrated electronics. LTD
-000C76 MICRO-STAR INTERNATIONAL CO., LTD.
-000C77 Life Racing Ltd
-000C78 In-Tech Electronics Limited
-000C79 Extel Communications P/L
-000C7A DaTARIUS Technologies GmbH
-000C7B ALPHA PROJECT Co.,Ltd.
-000C7C Internet Information Image Inc.
-000C7D TEIKOKU ELECTRIC MFG. CO., LTD
-000C7E Tellium Incorporated
-000C7F synertronixx GmbH
-000C80 Opelcomm Inc.
-000C81 Nulec Industries Pty Ltd
-000C82 NETWORK TECHNOLOGIES INC
-000C83 Logical Solutions
-000C84 Eazix, Inc.
-000C85 Cisco Systems
-000C86 Cisco Systems
-000C87 ATI
-000C88 Apache Micro Peripherals, Inc.
-000C89 AC Electric Vehicles, Ltd.
-000C8A Bose Corporation
-000C8B Connect Tech Inc
-000C8C KODICOM CO.,LTD.
-000C8D MATRIX VISION GmbH
-000C8E Mentor Engineering Inc
-000C8F Nergal s.r.l.
-000C90 Octasic Inc.
-000C91 Riverhead Networks Inc.
-000C92 WolfVision Gmbh
-000C93 Xeline Co., Ltd.
-000C94 United Electronic Industries, Inc.
-000C95 PrimeNet
-000C96 OQO, Inc.
-000C97 NV ADB TTV Technologies SA
-000C98 LETEK Communications Inc.
-000C99 HITEL LINK Co.,Ltd
-000C9A Hitech Electronics Corp.
-000C9B EE Solutions, Inc
-000C9C Chongho information & communications
-000C9D AirWalk Communications, Inc.
-000C9E MemoryLink Corp.
-000C9F NKE Corporation
-000CA0 StorCase Technology, Inc.
-000CA1 SIGMACOM Co., LTD.
-000CA2 Scopus Network Technologies Ltd
-000CA3 Rancho Technology, Inc.
-000CA4 Prompttec Product Management GmbH
-000CA6 Mintera Corporation
-000CA7 Metro (Suzhou) Technologies Co., Ltd.
-000CA8 Garuda Networks Corporation
-000CA9 Ebtron Inc.
-000CAA Cubic Transportation Systems Inc
-000CAB COMMEND International
-000CAC Citizen Watch Co., Ltd.
-000CAD BTU International
-000CAE Ailocom Oy
-000CAF TRI TERM CO.,LTD.
-000CB0 Star Semiconductor Corporation
-000CB1 Salland Engineering (Europe) BV
-000CB2 safei Co., Ltd.
-000CB3 ROUND Co.,Ltd.
-000CB4 Propagate Networks, Inc
-000CB5 Premier Technolgies, Inc
-000CB6 NANJING SEU MOBILE & INTERNET TECHNOLOGY CO.,LTD
-000CB7 Nanjing Huazhuo Electronics Co., Ltd.
-000CB8 MEDION AG
-000CB9 LEA
-000CBA Jamex
-000CBB ISKRAEMECO
-000CBC Iscutum
-000CBD Interface Masters, Inc
-000CBF Holy Stone Ent. Co., Ltd.
-000CC0 Genera Oy
-000CC1 Cooper Industries Inc.
-000CC3 BeWAN systems
-000CC4 Tiptel AG
-000CC5 Nextlink Co., Ltd.
-000CC6 Ka-Ro electronics GmbH
-000CC7 Intelligent Computer Solutions Inc.
-000CC8 Integrated Digital Systems, Inc.
-000CC9 ILWOO DATA & TECHNOLOGY CO.,LTD
-000CCA Hitachi Global Storage Technologies
-000CCB Design Combus Ltd
-000CCC Bluesoft Ltd.
-000CCD IEC - TC57
-000CCE Cisco Systems
-000CCF Cisco Systems
-000CD0 Symetrix
-000CD1 SFOM Technology Corp.
-000CD2 Schaffner EMV AG
-000CD3 Prettl Elektronik Radeberg GmbH
-000CD4 Positron Public Safety Systems inc.
-000CD5 Passave Inc.
-000CD6 PARTNER TECH
-000CD7 Nallatech Ltd
-000CD8 M. K. Juchheim GmbH & Co
-000CD9 Itcare Co., Ltd
-000CDA FreeHand Systems, Inc.
-000CDB Foundry Networks
-000CDC BECS Technology, Inc
-000CDD AOS Technologies AG
-000CDE ABB STOTZ-KONTAKT GmbH
-000CDF PULNiX America, Inc
-000CE0 Trek Diagnostics Inc.
-000CE1 The Open Group
-000CE2 Rolls-Royce
-000CE3 Option International N.V.
-000CE4 NeuroCom International, Inc.
-000CE5 Motorola BCS
-000CE6 Meru Networks Inc
-000CE7 MediaTek Inc.
-000CE8 GuangZhou AnJuBao Co., Ltd
-000CE9 BLOOMBERG L.P.
-000CEA aphona Kommunikationssysteme
-000CEB CNMP Networks, Inc.
-000CEC Spectracom Corp.
-000CED Real Digital Media
-000CEE Q-Networks
-000CEF Open Networks Engineering Ltd
-000CF0 M & N GmbH
-000CF1 Intel Corporation
-000CF2 GAMESA EÓLICA
-000CF3 CALL IMAGE SA
-000CF4 AKATSUKI ELECTRIC MFG.CO.,LTD.
-000CF5 InfoExpress
-000CF6 Sitecom Europe BV
-000CF7 Nortel Networks
-000CF8 Nortel Networks
-000CF9 ITT Flygt AB
-000CFA Digital Systems Corp
-000CFB Korea Network Systems
-000CFC S2io Technologies Corp
-000CFE Grand Electronic Co., Ltd
-000CFF MRO-TEK LIMITED
-000D00 Seaway Networks Inc.
-000D01 P&E Microcomputer Systems, Inc.
-000D02 NEC Access Technica,Ltd
-000D03 Matrics, Inc.
-000D04 Foxboro Eckardt Development GmbH
-000D05 cybernet manufacturing inc.
-000D06 Compulogic Limited
-000D07 Calrec Audio Ltd
-000D08 AboveCable, Inc.
-000D09 Yuehua(Zhuhai) Electronic CO. LTD
-000D0A Projectiondesign as
-000D0B Melco Inc.
-000D0C MDI Security Systems
-000D0D ITSupported, LLC
-000D0E Inqnet Systems, Inc.
-000D0F Finlux Ltd
-000D10 Embedtronics Oy
-000D11 DENTSPLY - Gendex
-000D12 AXELL Corporation
-000D13 Wilhelm Rutenbeck GmbH&Co.
-000D14 Vtech Innovation LP dba Advanced American Telephones
-000D15 Voipac s.r.o.
-000D16 UHS Systems Pty Ltd
-000D17 Turbo Networks Co.Ltd
-000D18 Sunitec Enterprise Co., Ltd.
-000D19 ROBE Show lighting
-000D1A Mustek System Inc.
-000D1B Kyoto Electronics Manufacturing Co., Ltd.
-000D1C I2E TELECOM
-000D1D HIGH-TEK HARNESS ENT. CO., LTD.
-000D1E Control Techniques
-000D1F AV Digital
-000D20 ASAHIKASEI TECHNOSYSTEM CO.,LTD.
-000D21 WISCORE Inc.
-000D22 Unitronics
-000D23 Smart Solution, Inc
-000D24 SENTEC E&E CO., LTD.
-000D25 SANDEN CORPORATION
-000D26 Primagraphics Limited
-000D27 MICROPLEX Printware AG
-000D28 Cisco
-000D29 Cisco
-000D2A Scanmatic AS
-000D2B Racal Instruments
-000D2C Patapsco Designs Ltd
-000D2D NCT Deutschland GmbH
-000D2E Matsushita Avionics Systems Corporation
-000D2F AIN Comm.Tech.Co., LTD
-000D30 IceFyre Semiconductor
-000D31 Compellent Technologies, Inc.
-000D32 DispenseSource, Inc.
-000D33 Prediwave Corp.
-000D34 Shell International Exploration and Production, Inc.
-000D35 PAC International Ltd
-000D36 Wu Han Routon Electronic Co., Ltd
-000D37 WIPLUG
-000D38 NISSIN INC.
-000D39 Network Electronics
-000D3A Microsoft Corp.
-000D3B Microelectronics Technology Inc.
-000D3C i.Tech Dynamic Ltd
-000D3E APLUX Communications Ltd.
-000D3F VXI Technology
-000D40 Verint Loronix Video Solutions
-000D41 Siemens AG ICM MP UC RD IT KLF1
-000D42 Newbest Development Limited
-000D43 DRS Tactical Systems Inc.
-000D45 Tottori SANYO Electric Co., Ltd.
-000D46 Eurotherm Drives, Ltd.
-000D47 Collex
-000D48 AEWIN Technologies Co., Ltd.
-000D49 Triton Systems of Delaware, Inc.
-000D4A Steag ETA-Optik
-000D4B Roku, LLC
-000D4C Outline Electronics Ltd.
-000D4D Ninelanes
-000D4E NDR Co.,LTD.
-000D4F Kenwood Corporation
-000D50 Galazar Networks
-000D51 DIVR Systems, Inc.
-000D52 Comart system
-000D53 Beijing 5w Communication Corp.
-000D54 3Com Europe Ltd
-000D55 SANYCOM Technology Co.,Ltd
-000D56 Dell PCBA Test
-000D57 Fujitsu I-Network Systems Limited.
-000D59 Amity Systems, Inc.
-000D5A Tiesse SpA
-000D5B Smart Empire Investments Limited
-000D5C Robert Bosch GmbH, VT-ATMO
-000D5D Raritan Computer, Inc
-000D5E NEC CustomTechnica, Ltd.
-000D5F Minds Inc
-000D60 IBM Corporation
-000D61 Giga-Byte Technology Co., Ltd.
-000D62 Funkwerk Dabendorf GmbH
-000D63 DENT Instruments, Inc.
-000D64 COMAG Handels AG
-000D65 Cisco Systems
-000D66 Cisco Systems
-000D67 BelAir Networks Inc.
-000D68 Vinci Systems, Inc.
-000D69 TMT&D Corporation
-000D6A Redwood Technologies LTD
-000D6B Mita-Teknik A/S
-000D6C M-Audio
-000D6D K-Tech Devices Corp.
-000D6E K-Patents Oy
-000D6F Ember Corporation
-000D70 Datamax Corporation
-000D71 boca systems
-000D72 2Wire, Inc
-000D73 Technical Support, Inc.
-000D74 Sand Network Systems, Inc.
-000D75 Kobian Pte Ltd - Taiwan Branch
-000D76 Hokuto Denshi Co,. Ltd.
-000D77 FalconStor Software
-000D78 Engineering & Security
-000D79 Dynamic Solutions Co,.Ltd.
-000D7A DiGATTO Asia Pacific Pte Ltd
-000D7B Consensys Computers Inc.
-000D7C Codian Ltd
-000D7D Afco Systems
-000D7E Axiowave Networks, Inc.
-000D7F MIDAS COMMUNICATION TECHNOLOGIES PTE LTD ( Foreign Branch)
-000D80 Online Development Inc
-000D81 Pepperl+Fuchs GmbH
-000D82 PHS srl
-000D83 Sanmina-SCI Hungary Ltd.
-000D84 Seodu Inchip, Inc.
-000D85 Tapwave, Inc.
-000D86 Huber + Suhner AG
-000D87 Elitegroup Computer System Co. (ECS)
-000D88 D-Link Corporation
-000D89 Bils Technology Inc
-000D8A Winners Electronics Co., Ltd.
-000D8B T&D Corporation
-000D8C Shanghai Wedone Digital Ltd. CO.
-000D8D ProLinx Communication Gateways, Inc.
-000D8E Koden Electronics Co., Ltd.
-000D8F King Tsushin Kogyo Co., LTD.
-000D90 Factum Electronics AB
-000D91 Eclipse (HQ Espana) S.L.
-000D92 Arima Communication Corporation
-000D93 Apple Computer
-000D94 AFAR Communications,Inc
-000D96 Vtera Technology Inc.
-000D97 Tropos Networks, Inc.
-000D98 S.W.A.C. Schmitt-Walter Automation Consult GmbH
-000D99 Orbital Sciences Corp.; Launch Systems Group
-000D9A INFOTEC LTD
-000D9C Elan GmbH & Co KG
-000D9D Hewlett Packard
-000D9E TOKUDEN OHIZUMI SEISAKUSYO Co.,Ltd.
-000D9F RF Micro Devices
-000DA0 NEDAP N.V.
-000DA1 MIRAE ITS Co.,LTD.
-000DA2 Infrant Technologies, Inc.
-000DA3 Emerging Technologies Limited
-000DA4 DOSCH & AMAND SYSTEMS AG
-000DA5 Fabric7 Systems, Inc
-000DA6 Universal Switching Corporation
-000DA8 Teletronics Technology Corporation
-000DA9 T.E.A.M. S.L.
-000DAA S.A.Tehnology co.,Ltd.
-000DAB Parker Hannifin GmbH Electromechanical Division Europe
-000DAC Japan CBM Corporation
-000DAD Dataprobe Inc
-000DAE SAMSUNG HEAVY INDUSTRIES CO., LTD.
-000DAF Plexus Corp (UK) Ltd
-000DB0 Olym-tech Co.,Ltd.
-000DB1 Japan Network Service Co., Ltd.
-000DB2 Ammasso, Inc.
-000DB3 SDO Communication Corperation
-000DB4 NETASQ
-000DB5 GLOBALSAT TECHNOLOGY CORPORATION
-000DB6 Teknovus, Inc.
-000DB7 SANKO ELECTRIC CO,.LTD
-000DB8 SCHILLER AG
-000DB9 PC Engines GmbH
-000DBA Océ Document Technologies GmbH
-000DBB Nippon Dentsu Co.,Ltd.
-000DBC Cisco Systems
-000DBD Cisco Systems
-000DBE Bel Fuse Europe Ltd.,UK
-000DBF TekTone Sound & Signal Mfg., Inc.
-000DC0 Spagat AS
-000DC1 SafeWeb Inc
-000DC3 First Communication, Inc.
-000DC4 Emcore Corporation
-000DC5 EchoStar International Corporation
-000DC6 DigiRose Technology Co., Ltd.
-000DC7 COSMIC ENGINEERING INC.
-000DC8 AirMagnet, Inc
-000DC9 THALES Elektronik Systeme GmbH
-000DCA Tait Electronics
-000DCB Petcomkorea Co., Ltd.
-000DCC NEOSMART Corp.
-000DCD GROUPE TXCOM
-000DCE Dynavac Technology Pte Ltd
-000DCF Cidra Corp.
-000DD0 TetraTec Instruments GmbH
-000DD1 Stryker Corporation
-000DD2 Simrad Optronics ASA
-000DD3 SAMWOO Telecommunication Co.,Ltd.
-000DD4 Revivio Inc.
-000DD5 O'RITE TECHNOLOGY CO.,LTD
-000DD7 Bright
-000DD8 BBN
-000DD9 Anton Paar GmbH
-000DDA ALLIED TELESIS K.K.
-000DDB AIRWAVE TECHNOLOGIES INC.
-000DDC VAC
-000DDD PROFÝLO TELRA ELEKTRONÝK SANAYÝ VE TÝCARET A.Þ.
-000DDE Joyteck Co., Ltd.
-000DDF Japan Image & Network Inc.
-000DE0 ICPDAS Co.,LTD
-000DE1 Control Products, Inc.
-000DE2 CMZ Sistemi Elettronici
-000DE3 AT Sweden AB
-000DE4 DIGINICS, Inc.
-000DE5 Samsung Thales
-000DE6 YOUNGBO ENGINEERING CO.,LTD
-000DE7 Snap-on OEM Group
-000DE8 Nasaco Electronics Pte. Ltd
-000DE9 Napatech Aps
-000DEA Kingtel Telecommunication Corp.
-000DEB CompXs Limited
-000DEC Cisco Systems
-000DED Cisco Systems
-000DEF Soc. Coop. Bilanciai
-000DF0 QCOM TECHNOLOGY INC.
-000DF1 IONIX INC.
-000DF3 Asmax Solutions
-000DF4 Watertek Co.
-000DF5 Teletronics International Inc.
-000DF6 Technology Thesaurus Corp.
-000DF7 Space Dynamics Lab
-000DF8 ORGA Kartensysteme GmbH
-000DF9 NDS Limited
-000DFA Micro Control Systems Ltd.
-000DFB Komax AG
-000DFC ITFOR Inc. resarch and development
-000DFD Huges Hi-Tech Inc.,
-000DFE Hauppauge Computer Works, Inc.
-000DFF CHENMING MOLD INDUSTRY CORP.
-000E01 ASIP Technologies Inc.
-000E02 Advantech AMT Inc.
-000E03 Aarohi Communications, Inc.
-000E05 WIRELESS MATRIX CORP.
-000E06 Team Simoco Ltd
-000E07 Sony Ericsson Mobile Communications AB
-000E08 Sipura Technology, Inc.
-000E09 Shenzhen Coship Software Co.,LTD.
-000E0B Netac Technology Co., Ltd.
-000E0C Intel Corporation
-000E0D HESCH Schröder GmbH
-000E0E ESA elettronica S.P.A.
-000E0F ERMME
-000E11 BDT Büro- und Datentechnik GmbH & Co. KG
-000E12 Adaptive Micro Systems Inc.
-000E13 Accu-Sort Systems inc.
-000E14 Visionary Solutions, Inc.
-000E15 Tadlys LTD
-000E16 SouthWing
-000E18 MyA Technology
-000E19 LogicaCMG Pty Ltd
-000E1B IAV GmbH
-000E1C Hach Company
-000E1F TCL Networks Equipment Co., Ltd.
-000E20 PalmSource, Inc.
-000E21 MTU Friedrichshafen GmbH
-000E23 Incipient, Inc.
-000E25 Hannae Technology Co., Ltd
-000E26 Gincom Technology Corp.
-000E27 Crere Networks, Inc.
-000E28 Dynamic Ratings P/L
-000E29 Shester Communications Inc
-000E2B Safari Technologies
-000E2C Netcodec co.
-000E2D Hyundai Digital Technology Co.,Ltd.
-000E2E Edimax Technology Co., Ltd.
-000E2F Disetronic Medical Systems AG
-000E30 AERAS Networks, Inc.
-000E31 Olympus BioSystems GmbH
-000E32 Kontron Medical
-000E33 Shuko Electronics Co.,Ltd
-000E34 NexxGenCity
-000E35 Intel Corp
-000E36 HEINESYS, Inc.
-000E37 Harms & Wende GmbH & Co.KG
-000E38 Cisco Systems
-000E39 Cisco Systems
-000E3A Cirrus Logic
-000E3B Hawking Technologies, Inc.
-000E3C TransAct Technoloiges Inc.
-000E3D Televic N.V.
-000E3E Sun Optronics Inc
-000E3F Soronti, Inc.
-000E40 Nortel Networks
-000E41 NIHON MECHATRONICS CO.,LTD.
-000E42 Motic Incoporation Ltd.
-000E43 G-Tek Electronics Sdn. Bhd.
-000E44 Digital 5, Inc.
-000E45 Beijing Newtry Electronic Technology Ltd
-000E46 Niigata Seimitsu Co.,Ltd.
-000E47 NCI System Co.,Ltd.
-000E48 Lipman TransAction Solutions
-000E49 Forsway Scandinavia AB
-000E4A Changchun Huayu WEBPAD Co.,LTD
-000E4B atrium c and i
-000E4C Bermai Inc.
-000E4D Numesa Inc.
-000E4E Waveplus Technology Co., Ltd.
-000E4F Trajet GmbH
-000E50 Thomson Multi Media
-000E51 tecna elettronica srl
-000E52 Optium Corporation
-000E53 AV TECH CORPORATION
-000E54 AlphaCell Wireless Ltd.
-000E55 AUVITRAN
-000E56 4G Systems GmbH
-000E57 Iworld Networking, Inc.
-000E58 Rincon Networks
-000E5A TELEFIELD inc.
-000E5B ParkerVision - Direct2Data
-000E5C Motorola BCS
-000E5D Com-X Networks
-000E5E Beijing Raisecom Science & Technology Development Co.,Ltd
-000E5F activ-net GmbH & Co. KG
-000E60 360SUN Digital Broadband Corporation
-000E61 MICROTROL LIMITED
-000E62 Nortel Networks
-000E63 Lemke Diagnostics GmbH
-000E64 Elphel, Inc
-000E65 TransCore
-000E66 Hitachi Advanced Digital, Inc.
-000E67 Eltis Microelectronics Ltd.
-000E68 E-TOP Network Technology Inc.
-000E69 China Electric Power Research Institute
-000E6A 3COM EUROPE LTD
-000E6B Janitza electronics GmbH
-000E6C Device Drivers Limited
-000E6D Murata Manufacturing Co., Ltd.
-000E6E MICRELEC ELECTRONICS S.A
-000E6F IRIS Corporation Berhad
-000E70 in2 Networks
-000E71 Gemstar Technology Development Ltd.
-000E72 CTS electronics
-000E73 Tpack A/S
-000E74 Solar Telecom. Tech
-000E75 New York Air Brake Corp.
-000E76 GEMSOC INNOVISION INC.
-000E77 Decru, Inc.
-000E78 Amtelco
-000E79 Ample Communications Inc.
-000E7B Toshiba
-000E7D Electronics Line 3000 Ltd.
-000E7E Comprog Oy
-000E7F Hewlett Packard
-000E81 Instant802 Networks Inc.
-000E82 Commtech Wireless
-000E83 Cisco Systems
-000E84 Cisco Systems
-000E85 Catalyst Enterprises, Inc.
-000E86 Alcatel North America
-000E87 adp Gauselmann GmbH
-000E88 VIDEOTRON CORP.
-000E89 CLEMATIC
-000E8A Avara Technologies Pty. Ltd.
-000E8B Astarte Technology Co, Ltd.
-000E8C Siemens AG A&D ET
-000E8D Systems in Progress Holding GmbH
-000E8E SparkLAN Communications, Inc.
-000E8F Sercomm Corp.
-000E90 PONICO CORP.
-000E92 Millinet Co., Ltd.
-000E93 Milénio 3 Sistemas Electrónicos, Lda.
-000E94 Maas International BV
-000E95 Fujiya Denki Seisakusho Co.,Ltd.
-000E96 Cubic Defense Applications, Inc.
-000E97 Ultracker Technology CO., Inc
-000E98 Vitec CC, INC.
-000E99 Spectrum Digital, Inc
-000E9A BOE TECHNOLOGY GROUP CO.,LTD
-000E9C Pemstar
-000E9D Video Networks Ltd
-000E9E Topfield Co., Ltd
-000E9F TEMIC SDS GmbH
-000EA0 NetKlass Technology Inc.
-000EA1 Formosa Teletek Corporation
-000EA2 CyberGuard Corporation
-000EA3 CNCR-IT CO.,LTD,HangZhou P.R.CHINA
-000EA4 Certance Inc.
-000EA5 BLIP Systems
-000EA6 ASUSTEK COMPUTER INC.
-000EA7 Endace Inc Ltd.
-000EA8 United Technologists Europe Limited
-000EA9 Shanghai Xun Shi Communications Equipment Ltd. Co.
-000EAC MINTRON ENTERPRISE CO., LTD.
-000EAD Metanoia Technologies, Inc.
-000EAE GAWELL TECHNOLOGIES CORP.
-000EAF CASTEL
-000EB0 Solutions Radio BV
-000EB1 Newcotech,Ltd
-000EB2 Micro-Research Finland Oy
-000EB3 LeftHand Networks
-000EB4 GUANGZHOU GAOKE COMMUNICATIONS TECHNOLOGY CO.LTD.
-000EB5 Ecastle Electronics Co., Ltd.
-000EB6 Riverbed Technology, Inc.
-000EB7 Knovative, Inc.
-000EB8 Iiga co.,Ltd
-000EB9 HASHIMOTO Electronics Industry Co.,Ltd.
-000EBA HANMI SEMICONDUCTOR CO., LTD.
-000EBB Everbee Networks
-000EBC Cullmann GmbH
-000EBD Burdick, a Quinton Compny
-000EBE B&B Electronics Manufacturing Co.
-000EC0 Nortel Networks
-000EC1 MYNAH Technologies
-000EC2 Lowrance Electronics, Inc.
-000EC3 Logic Controls, Inc.
-000EC4 Iskra Transmission d.d.
-000EC6 ASIX ELECTRONICS CORP.
-000EC7 Appeal Telecom Co.,Ltd.
-000EC8 Zoran Corporation
-000EC9 YOKO Technology Corp.
-000ECB VineSys Technology
-000ECC Tableau
-000ECD SKOV A/S
-000ECE S.I.T.T.I. S.p.A.
-000ECF PROFIBUS Nutzerorganisation e.V.
-000ED0 Privaris, Inc.
-000ED1 Osaka Micro Computer.
-000ED2 Filtronic plc
-000ED3 Epicenter, Inc.
-000ED4 CRESITT INDUSTRIE
-000ED5 COPAN Systems Inc.
-000ED6 Cisco Systems
-000ED7 Cisco Systems
-000ED8 Aktino, Inc.
-000ED9 Aksys, Ltd.
-000EDA C-TECH UNITED CORP.
-000EDB XiNCOM Corp.
-000EDC Tellion INC.
-000EDD SHURE INCORPORATED
-000EDE REMEC, Inc.
-000EDF PLX Technology
-000EE0 Mcharge
-000EE1 ExtremeSpeed Inc.
-000EE2 Custom Engineering S.p.A.
-000EE3 Chiyu Technology Co.,Ltd
-000EE5 bitWallet, Inc.
-000EE6 Adimos Systems LTD
-000EE7 AAC ELECTRONICS CORP.
-000EE8 zioncom
-000EE9 WayTech Development, Inc.
-000EEA Shadong Luneng Jicheng Electronics,Co.,Ltd
-000EEB Sandmartin(zhong shan)Electronics Co.,Ltd
-000EEC Orban
-000EED Nokia Danmark A/S
-000EEE Muco Industrie BV
-000EF0 Festo AG & Co. KG
-000EF1 EZQUEST INC.
-000EF3 Smarthome
-000EF4 Shenzhen Kasda Digital Technology Co.,Ltd
-000EF5 iPAC Technology Co., Ltd.
-000EF6 E-TEN Information Systems Co., Ltd.
-000EF7 Vulcan Portals Inc
-000EF8 SBC ASI
-000EF9 REA Elektronik GmbH
-000EFA Optoway Technology Incorporation
-000EFB Macey Enterprises
-000EFC JTAG Technologies B.V.
-000EFD FUJI PHOTO OPTICAL CO., LTD.
-000EFE EndRun Technologies LLC
-000EFF Megasolution,Inc.
-000F00 Legra Systems, Inc.
-000F01 DIGITALKS INC
-000F02 Digicube Technology Co., Ltd
-000F03 COM&C CO., LTD
-000F04 cim-usa inc
-000F05 3B SYSTEM INC.
-000F06 Nortel Networks
-000F07 Mangrove Systems, Inc.
-000F08 Indagon Oy
-000F0B Kentima Technologies AB
-000F0C SYNCHRONIC ENGINEERING
-000F0D Hunt Electronic Co., Ltd.
-000F0E WaveSplitter Technologies, Inc.
-000F0F Real ID Technology Co., Ltd.
-000F10 RDM Corporation
-000F11 Prodrive B.V.
-000F12 Panasonic AVC Networks Germany GmbH
-000F13 Nisca corporation
-000F14 Mindray Co., Ltd.
-000F15 Kjaerulff1 A/S
-000F16 JAY HOW TECHNOLOGY CO.,
-000F17 Insta Elektro GmbH
-000F18 Industrial Control Systems
-000F19 Guidant Corporation
-000F1A Gaming Support B.V.
-000F1B Ego Systems Inc.
-000F1C DigitAll World Co., Ltd
-000F1D Cosmo Techs Co., Ltd.
-000F1E Chengdu KT Electric Co.of High & New Technology
-000F1F WW PCBA Test
-000F20 WW Ops
-000F21 Scientific Atlanta, Inc
-000F22 Helius, Inc.
-000F23 Cisco Systems
-000F24 Cisco Systems
-000F25 AimValley B.V.
-000F26 WorldAccxx LLC
-000F27 TEAL Electronics, Inc.
-000F28 Itronix Corporation
-000F29 Augmentix Corporation
-000F2A Cableware Electronics
-000F2B GREENBELL SYSTEMS
-000F2C Uplogix, Inc.
-001000 CABLE TELEVISION LABORATORIES, INC.
-001001 MCK COMMUNICATIONS
-001002 ACTIA
-001003 IMATRON, INC.
-001004 THE BRANTLEY COILE COMPANY,INC
-001005 UEC COMMERCIAL
-001006 Thales Contact Solutions Ltd.
-001007 CISCO SYSTEMS, INC.
-001008 VIENNA SYSTEMS CORPORATION
-001009 HORO QUARTZ
-00100A WILLIAMS COMMUNICATIONS GROUP
-00100B CISCO SYSTEMS, INC.
-00100C ITO CO., LTD.
-00100D CISCO SYSTEMS, INC.
-00100E MICRO LINEAR COPORATION
-00100F INDUSTRIAL CPU SYSTEMS
-001010 INITIO CORPORATION
-001011 CISCO SYSTEMS, INC.
-001012 PROCESSOR SYSTEMS (I) PVT LTD
-001013 INDUSTRIAL COMPUTER SOURCE
-001014 CISCO SYSTEMS, INC.
-001015 OOmon Inc.
-001016 T.SQWARE
-001017 MICOS GmbH
-001018 BROADCOM CORPORATION
-001019 SIRONA DENTAL SYSTEMS GmbH & Co. KG
-00101A PictureTel Corp.
-00101B CORNET TECHNOLOGY, INC.
-00101C OHM TECHNOLOGIES INTL, LLC
-00101D WINBOND ELECTRONICS CORP.
-00101E MATSUSHITA ELECTRONIC INSTRUMENTS CORP.
-00101F CISCO SYSTEMS, INC.
-001020 WELCH ALLYN, DATA COLLECTION
-001021 ENCANTO NETWORKS, INC.
-001022 SatCom Media Corporation
-001023 FLOWWISE NETWORKS, INC.
-001024 NAGOYA ELECTRIC WORKS CO., LTD
-001025 GRAYHILL INC.
-001026 ACCELERATED NETWORKS, INC.
-001027 L-3 COMMUNICATIONS EAST
-001028 COMPUTER TECHNICA, INC.
-001029 CISCO SYSTEMS, INC.
-00102A ZF MICROSYSTEMS, INC.
-00102B UMAX DATA SYSTEMS, INC.
-00102C Lasat Networks A/S
-00102D HITACHI SOFTWARE ENGINEERING
-00102E NETWORK SYSTEMS & TECHNOLOGIES PVT. LTD.
-00102F CISCO SYSTEMS, INC.
-001030 Wi-LAN, Inc.
-001031 OBJECTIVE COMMUNICATIONS, INC.
-001032 ALTA TECHNOLOGY
-001033 ACCESSLAN COMMUNICATIONS, INC.
-001034 GNP Computers
-001035 ELITEGROUP COMPUTER SYSTEMS CO., LTD
-001036 INTER-TEL INTEGRATED SYSTEMS
-001037 CYQ've Technology Co., Ltd.
-001038 MICRO RESEARCH INSTITUTE, INC.
-001039 Vectron Systems AG
-00103A DIAMOND NETWORK TECH
-00103B HIPPI NETWORKING FORUM
-00103C IC ENSEMBLE, INC.
-00103D PHASECOM, LTD.
-00103E NETSCHOOLS CORPORATION
-00103F TOLLGRADE COMMUNICATIONS, INC.
-001040 INTERMEC CORPORATION
-001041 BRISTOL BABCOCK, INC.
-001042 AlacriTech
-001043 A2 CORPORATION
-001044 InnoLabs Corporation
-001045 Nortel Networks
-001046 ALCORN MCBRIDE INC.
-001047 ECHO ELETRIC CO. LTD.
-001048 HTRC AUTOMATION, INC.
-001049 SHORELINE TELEWORKS, INC.
-00104A THE PARVUC CORPORATION
-00104B 3COM CORPORATION
-00104C COMPUTER ACCESS TECHNOLOGY
-00104D SURTEC INDUSTRIES, INC.
-00104E CEOLOGIC
-00104F STORAGE TECHNOLOGY CORPORATION
-001050 RION CO., LTD.
-001051 CMICRO CORPORATION
-001052 METTLER-TOLEDO (ALBSTADT) GMBH
-001053 COMPUTER TECHNOLOGY CORP.
-001054 CISCO SYSTEMS, INC.
-001055 FUJITSU MICROELECTRONICS, INC.
-001056 SODICK CO., LTD.
-001057 Rebel.com, Inc.
-001058 ArrowPoint Communications
-001059 DIABLO RESEARCH CO. LLC
-00105A 3COM CORPORATION
-00105B NET INSIGHT AB
-00105C QUANTUM DESIGNS (H.K.) LTD.
-00105D Draeger Medical
-00105E HEKIMIAN LABORATORIES, INC.
-00105F IN-SNEC
-001060 BILLIONTON SYSTEMS, INC.
-001061 HOSTLINK CORP.
-001062 NX SERVER, ILNC.
-001063 STARGUIDE DIGITAL NETWORKS
-001064 DIGITAL EQUIPMENT CORP.
-001065 RADYNE CORPORATION
-001066 ADVANCED CONTROL SYSTEMS, INC.
-001067 REDBACK NETWORKS, INC.
-001068 COMOS TELECOM
-001069 HELIOSS COMMUNICATIONS, INC.
-00106A DIGITAL MICROWAVE CORPORATION
-00106B SONUS NETWORKS, INC.
-00106C INFRATEC PLUS GmbH
-00106D INTEGRITY COMMUNICATIONS, INC.
-00106E TADIRAN COM. LTD.
-00106F TRENTON TECHNOLOGY INC.
-001070 CARADON TREND LTD.
-001071 ADVANET INC.
-001072 GVN TECHNOLOGIES, INC.
-001073 TECHNOBOX, INC.
-001074 ATEN INTERNATIONAL CO., LTD.
-001075 Maxtor Corporation
-001076 EUREM GmbH
-001077 SAF DRIVE SYSTEMS, LTD.
-001078 NUERA COMMUNICATIONS, INC.
-001079 CISCO SYSTEMS, INC.
-00107A AmbiCom, Inc.
-00107B CISCO SYSTEMS, INC.
-00107C P-COM, INC.
-00107D AURORA COMMUNICATIONS, LTD.
-00107E BACHMANN ELECTRONIC GmbH
-00107F CRESTRON ELECTRONICS, INC.
-001080 METAWAVE COMMUNICATIONS
-001081 DPS, INC.
-001082 JNA TELECOMMUNICATIONS LIMITED
-001083 HEWLETT-PACKARD COMPANY
-001084 K-BOT COMMUNICATIONS
-001085 POLARIS COMMUNICATIONS, INC.
-001086 ATTO TECHNOLOGY, INC.
-001087 Xstreamis PLC
-001088 AMERICAN NETWORKS INC.
-001089 WebSonic
-00108A TeraLogic, Inc.
-00108B LASERANIMATION SOLLINGER GmbH
-00108C FUJITSU TELECOMMUNICATIONS EUROPE, LTD.
-00108D JOHNSON CONTROLS, INC.
-00108E HUGH SYMONS CONCEPT Technologies Ltd.
-00108F RAPTOR SYSTEMS
-001090 CIMETRICS, INC.
-001091 NO WIRES NEEDED BV
-001092 NETCORE INC.
-001093 CMS COMPUTERS, LTD.
-001094 Performance Analysis Broadband, Spirent plc
-001095 Thomson Multimedia, Inc.
-001096 TRACEWELL SYSTEMS, INC.
-001097 WinNet Metropolitan Communications Systems, Inc.
-001098 STARNET TECHNOLOGIES, INC.
-001099 InnoMedia, Inc.
-00109A NETLINE
-00109B VIXEL CORPORATION
-00109C M-SYSTEM CO., LTD.
-00109D CLARINET SYSTEMS, INC.
-00109E AWARE, INC.
-00109F PAVO, INC.
-0010A0 INNOVEX TECHNOLOGIES, INC.
-0010A1 KENDIN SEMICONDUCTOR, INC.
-0010A2 TNS
-0010A3 OMNITRONIX, INC.
-0010A4 XIRCOM
-0010A5 OXFORD INSTRUMENTS
-0010A6 CISCO SYSTEMS, INC.
-0010A7 UNEX TECHNOLOGY CORPORATION
-0010A8 RELIANCE COMPUTER CORP.
-0010A9 ADHOC TECHNOLOGIES
-0010AA MEDIA4, INC.
-0010AB KOITO INDUSTRIES, LTD.
-0010AC IMCI TECHNOLOGIES
-0010AD SOFTRONICS USB, INC.
-0010AE SHINKO ELECTRIC INDUSTRIES CO.
-0010AF TAC SYSTEMS, INC.
-0010B0 MERIDIAN TECHNOLOGY CORP.
-0010B1 FOR-A CO., LTD.
-0010B2 COACTIVE AESTHETICS
-0010B3 NOKIA MULTIMEDIA TERMINALS
-0010B4 ATMOSPHERE NETWORKS
-0010B5 ACCTON TECHNOLOGY CORPORATION
-0010B6 ENTRATA COMMUNICATIONS CORP.
-0010B7 COYOTE TECHNOLOGIES, LLC
-0010B8 ISHIGAKI COMPUTER SYSTEM CO.
-0010B9 MAXTOR CORP.
-0010BA MARTINHO-DAVIS SYSTEMS, INC.
-0010BB DATA & INFORMATION TECHNOLOGY
-0010BC Aastra Telecom
-0010BD THE TELECOMMUNICATION TECHNOLOGY COMMITTEE
-0010BE TELEXIS CORP.
-0010BF InterAir Wireless
-0010C0 ARMA, INC.
-0010C1 OI ELECTRIC CO., LTD.
-0010C2 WILLNET, INC.
-0010C3 CSI-CONTROL SYSTEMS
-0010C4 MEDIA LINKS CO., LTD.
-0010C5 PROTOCOL TECHNOLOGIES, INC.
-0010C6 USI
-0010C7 DATA TRANSMISSION NETWORK
-0010C8 COMMUNICATIONS ELECTRONICS SECURITY GROUP
-0010C9 MITSUBISHI ELECTRONICS LOGISTIC SUPPORT CO.
-0010CA INTEGRAL ACCESS
-0010CB FACIT K.K.
-0010CC CLP COMPUTER LOGISTIK PLANUNG GmbH
-0010CD INTERFACE CONCEPT
-0010CE VOLAMP, LTD.
-0010CF FIBERLANE COMMUNICATIONS
-0010D0 WITCOM, LTD.
-0010D1 Top Layer Networks, Inc.
-0010D2 NITTO TSUSHINKI CO., LTD
-0010D3 GRIPS ELECTRONIC GMBH
-0010D4 STORAGE COMPUTER CORPORATION
-0010D5 IMASDE CANARIAS, S.A.
-0010D6 ITT - A/CD
-0010D7 ARGOSY RESEARCH INC.
-0010D8 CALISTA
-0010D9 IBM JAPAN, FUJISAWA MT+D
-0010DA MOTION ENGINEERING, INC.
-0010DB NetScreen Technologies, Inc.
-0010DC MICRO-STAR INTERNATIONAL CO., LTD.
-0010DD ENABLE SEMICONDUCTOR, INC.
-0010DE INTERNATIONAL DATACASTING CORPORATION
-0010DF RISE COMPUTER INC.
-0010E0 COBALT MICROSERVER, INC.
-0010E1 S.I. TECH, INC.
-0010E2 ArrayComm, Inc.
-0010E3 COMPAQ COMPUTER CORPORATION
-0010E4 NSI CORPORATION
-0010E5 SOLECTRON TEXAS
-0010E6 APPLIED INTELLIGENT SYSTEMS, INC.
-0010E7 BreezeCom
-0010E8 TELOCITY, INCORPORATED
-0010E9 RAIDTEC LTD.
-0010EA ADEPT TECHNOLOGY
-0010EB SELSIUS SYSTEMS, INC.
-0010EC RPCG, LLC
-0010ED SUNDANCE TECHNOLOGY, INC.
-0010EE CTI PRODUCTS, INC.
-0010EF DBTEL INCORPORATED
-0010F1 I-O CORPORATION
-0010F2 ANTEC
-0010F3 Nexcom International Co., Ltd.
-0010F4 VERTICAL NETWORKS, INC.
-0010F5 AMHERST SYSTEMS, INC.
-0010F6 CISCO SYSTEMS, INC.
-0010F7 IRIICHI TECHNOLOGIES Inc.
-0010F8 KENWOOD TMI CORPORATION
-0010F9 UNIQUE SYSTEMS, INC.
-0010FA ZAYANTE, INC.
-0010FB ZIDA TECHNOLOGIES LIMITED
-0010FC BROADBAND NETWORKS, INC.
-0010FD COCOM A/S
-0010FE DIGITAL EQUIPMENT CORPORATION
-0010FF CISCO SYSTEMS, INC.
-001C7C PERQ SYSTEMS CORPORATION
-002000 LEXMARK INTERNATIONAL, INC.
-002001 DSP SOLUTIONS, INC.
-002002 SERITECH ENTERPRISE CO., LTD.
-002003 PIXEL POWER LTD.
-002004 YAMATAKE-HONEYWELL CO., LTD.
-002005 SIMPLE TECHNOLOGY
-002006 GARRETT COMMUNICATIONS, INC.
-002007 SFA, INC.
-002008 CABLE & COMPUTER TECHNOLOGY
-002009 PACKARD BELL ELEC., INC.
-00200A SOURCE-COMM CORP.
-00200B OCTAGON SYSTEMS CORP.
-00200C ADASTRA SYSTEMS CORP.
-00200D CARL ZEISS
-00200E SATELLITE TECHNOLOGY MGMT, INC
-00200F TANBAC CO., LTD.
-002010 JEOL SYSTEM TECHNOLOGY CO. LTD
-002011 CANOPUS CO., LTD.
-002012 CAMTRONICS MEDICAL SYSTEMS
-002013 DIVERSIFIED TECHNOLOGY, INC.
-002014 GLOBAL VIEW CO., LTD.
-002015 ACTIS COMPUTER SA
-002016 SHOWA ELECTRIC WIRE & CABLE CO
-002017 ORBOTECH
-002018 CIS TECHNOLOGY INC.
-002019 OHLER GmbH
-00201A N-BASE SWITCH COMMUNICATIONS
-00201B NORTHERN TELECOM/NETWORK
-00201C EXCEL, INC.
-00201D KATANA PRODUCTS
-00201E NETQUEST CORPORATION
-00201F BEST POWER TECHNOLOGY, INC.
-002020 MEGATRON COMPUTER INDUSTRIES PTY, LTD.
-002021 ALGORITHMS SOFTWARE PVT. LTD.
-002022 TEKNIQUE, INC.
-002023 T.C. TECHNOLOGIES PTY. LTD
-002024 PACIFIC COMMUNICATION SCIENCES
-002025 CONTROL TECHNOLOGY, INC.
-002026 AMKLY SYSTEMS, INC.
-002027 MING FORTUNE INDUSTRY CO., LTD
-002028 WEST EGG SYSTEMS, INC.
-002029 TELEPROCESSING PRODUCTS, INC.
-00202A N.V. DZINE
-00202B ADVANCED TELECOMMUNICATIONS MODULES, LTD.
-00202C WELLTRONIX CO., LTD.
-00202D TAIYO CORPORATION
-00202E DAYSTAR DIGITAL
-00202F ZETA COMMUNICATIONS, LTD.
-002030 ANALOG & DIGITAL SYSTEMS
-002031 ERTEC GmbH
-002032 ALCATEL TAISEL
-002033 SYNAPSE TECHNOLOGIES, INC.
-002034 ROTEC INDUSTRIEAUTOMATION GMBH
-002035 IBM CORPORATION
-002036 BMC SOFTWARE
-002037 SEAGATE TECHNOLOGY
-002038 VME MICROSYSTEMS INTERNATIONAL CORPORATION
-002039 SCINETS
-00203A DIGITAL BI0METRICS INC.
-00203B WISDM LTD.
-00203C EUROTIME AB
-00203D NOVAR ELECTRONICS CORPORATION
-00203E LogiCan Technologies, Inc.
-00203F JUKI CORPORATION
-002040 Motorola Broadband Communications Sector
-002041 DATA NET
-002042 DATAMETRICS CORP.
-002043 NEURON COMPANY LIMITED
-002044 GENITECH PTY LTD
-002045 ION Networks, Inc.
-002046 CIPRICO, INC.
-002047 STEINBRECHER CORP.
-002048 Marconi Communications
-002049 COMTRON, INC.
-00204A PRONET GMBH
-00204B AUTOCOMPUTER CO., LTD.
-00204C MITRON COMPUTER PTE LTD.
-00204D INOVIS GMBH
-00204E NETWORK SECURITY SYSTEMS, INC.
-00204F DEUTSCHE AEROSPACE AG
-002050 KOREA COMPUTER INC.
-002051 Verilink Corporation
-002052 RAGULA SYSTEMS
-002053 HUNTSVILLE MICROSYSTEMS, INC.
-002054 EASTERN RESEARCH, INC.
-002055 ALTECH CO., LTD.
-002056 NEOPRODUCTS
-002057 TITZE DATENTECHNIK GmbH
-002058 ALLIED SIGNAL INC.
-002059 MIRO COMPUTER PRODUCTS AG
-00205A COMPUTER IDENTICS
-00205B SKYLINE TECHNOLOGY
-00205C InterNet Systems of Florida, Inc.
-00205D NANOMATIC OY
-00205E CASTLE ROCK, INC.
-00205F GAMMADATA COMPUTER GMBH
-002060 ALCATEL ITALIA S.p.A.
-002061 DYNATECH COMMUNICATIONS, INC.
-002062 SCORPION LOGIC, LTD.
-002063 WIPRO INFOTECH LTD.
-002064 PROTEC MICROSYSTEMS, INC.
-002065 SUPERNET NETWORKING INC.
-002066 GENERAL MAGIC, INC.
-002068 ISDYNE
-002069 ISDN SYSTEMS CORPORATION
-00206A OSAKA COMPUTER CORP.
-00206B KONICA MINOLTA HOLDINGS, INC.
-00206C EVERGREEN TECHNOLOGY CORP.
-00206D DATA RACE, INC.
-00206E XACT, INC.
-00206F FLOWPOINT CORPORATION
-002070 HYNET, LTD.
-002071 IBR GMBH
-002072 WORKLINK INNOVATIONS
-002073 FUSION SYSTEMS CORPORATION
-002074 SUNGWOON SYSTEMS
-002075 MOTOROLA COMMUNICATION ISRAEL
-002076 REUDO CORPORATION
-002077 KARDIOS SYSTEMS CORP.
-002078 RUNTOP, INC.
-002079 MIKRON GMBH
-00207A WiSE Communications, Inc.
-00207B Intel Corporation
-00207C AUTEC GmbH
-00207D ADVANCED COMPUTER APPLICATIONS
-00207E FINECOM Co., Ltd.
-00207F KYOEI SANGYO CO., LTD.
-002080 SYNERGY (UK) LTD.
-002081 TITAN ELECTRONICS
-002082 ONEAC CORPORATION
-002083 PRESTICOM INCORPORATED
-002084 OCE PRINTING SYSTEMS, GMBH
-002085 EXIDE ELECTRONICS
-002086 MICROTECH ELECTRONICS LIMITED
-002087 MEMOTEC COMMUNICATIONS CORP.
-002088 GLOBAL VILLAGE COMMUNICATION
-002089 T3PLUS NETWORKING, INC.
-00208A SONIX COMMUNICATIONS, LTD.
-00208B LAPIS TECHNOLOGIES, INC.
-00208C GALAXY NETWORKS, INC.
-00208D CMD TECHNOLOGY
-00208E CHEVIN SOFTWARE ENG. LTD.
-00208F ECI TELECOM LTD.
-002090 ADVANCED COMPRESSION TECHNOLOGY, INC.
-002091 J125, NATIONAL SECURITY AGENCY
-002092 CHESS ENGINEERING B.V.
-002093 LANDINGS TECHNOLOGY CORP.
-002094 CUBIX CORPORATION
-002095 RIVA ELECTRONICS
-002096 Invensys
-002097 APPLIED SIGNAL TECHNOLOGY
-002098 HECTRONIC AB
-002099 BON ELECTRIC CO., LTD.
-00209A THE 3DO COMPANY
-00209B ERSAT ELECTRONIC GMBH
-00209C PRIMARY ACCESS CORP.
-00209D LIPPERT AUTOMATIONSTECHNIK
-00209E BROWN'S OPERATING SYSTEM SERVICES, LTD.
-00209F MERCURY COMPUTER SYSTEMS, INC.
-0020A0 OA LABORATORY CO., LTD.
-0020A1 DOVATRON
-0020A2 GALCOM NETWORKING LTD.
-0020A3 DIVICOM INC.
-0020A4 MULTIPOINT NETWORKS
-0020A5 API ENGINEERING
-0020A6 PROXIM, INC.
-0020A7 PAIRGAIN TECHNOLOGIES, INC.
-0020A8 SAST TECHNOLOGY CORP.
-0020A9 WHITE HORSE INDUSTRIAL
-0020AA DIGIMEDIA VISION LTD.
-0020AB MICRO INDUSTRIES CORP.
-0020AC INTERFLEX DATENSYSTEME GMBH
-0020AD LINQ SYSTEMS
-0020AE ORNET DATA COMMUNICATION TECH.
-0020AF 3COM CORPORATION
-0020B0 GATEWAY DEVICES, INC.
-0020B1 COMTECH RESEARCH INC.
-0020B2 GKD Gesellschaft Fur Kommunikation Und Datentechnik
-0020B3 SCLTEC COMMUNICATIONS SYSTEMS
-0020B4 TERMA ELEKTRONIK AS
-0020B5 YASKAWA ELECTRIC CORPORATION
-0020B6 AGILE NETWORKS, INC.
-0020B7 NAMAQUA COMPUTERWARE
-0020B8 PRIME OPTION, INC.
-0020B9 METRICOM, INC.
-0020BA CENTER FOR HIGH PERFORMANCE
-0020BB ZAX CORPORATION
-0020BC JTEC PTY LTD.
-0020BD NIOBRARA R & D CORPORATION
-0020BE LAN ACCESS CORP.
-0020BF AEHR TEST SYSTEMS
-0020C0 PULSE ELECTRONICS, INC.
-0020C1 TAIKO ELECTRIC WORKS, LTD.
-0020C2 TEXAS MEMORY SYSTEMS, INC.
-0020C3 COUNTER SOLUTIONS LTD.
-0020C4 INET,INC.
-0020C5 EAGLE TECHNOLOGY
-0020C6 NECTEC
-0020C7 AKAI Professional M.I. Corp.
-0020C8 LARSCOM INCORPORATED
-0020C9 VICTRON BV
-0020CA DIGITAL OCEAN
-0020CB PRETEC ELECTRONICS CORP.
-0020CC DIGITAL SERVICES, LTD.
-0020CD HYBRID NETWORKS, INC.
-0020CE LOGICAL DESIGN GROUP, INC.
-0020CF TEST & MEASUREMENT SYSTEMS INC
-0020D0 VERSALYNX CORPORATION
-0020D1 MICROCOMPUTER SYSTEMS (M) SDN.
-0020D2 RAD DATA COMMUNICATIONS, LTD.
-0020D3 OST (OUEST STANDARD TELEMATIQU
-0020D4 CABLETRON - ZEITTNET INC.
-0020D5 VIPA GMBH
-0020D6 BREEZECOM
-0020D7 JAPAN MINICOMPUTER SYSTEMS CO., Ltd.
-0020D8 Nortel Networks
-0020D9 PANASONIC TECHNOLOGIES, INC./MIECO-US
-0020DA XYLAN CORPORATION
-0020DB XNET TECHNOLOGY, INC.
-0020DC DENSITRON TAIWAN LTD.
-0020DD Cybertec Pty Ltd
-0020DE JAPAN DIGITAL LABORAT'Y CO.LTD
-0020DF KYOSAN ELECTRIC MFG. CO., LTD.
-0020E0 PREMAX ELECTRONICS, INC.
-0020E1 ALAMAR ELECTRONICS
-0020E2 INFORMATION RESOURCE ENGINEERING
-0020E3 MCD KENCOM CORPORATION
-0020E4 HSING TECH ENTERPRISE CO., LTD
-0020E5 APEX DATA, INC.
-0020E6 LIDKOPING MACHINE TOOLS AB
-0020E7 B&W NUCLEAR SERVICE COMPANY
-0020E8 DATATREK CORPORATION
-0020E9 DANTEL
-0020EA EFFICIENT NETWORKS, INC.
-0020EB CINCINNATI MICROWAVE, INC.
-0020EC TECHWARE SYSTEMS CORP.
-0020ED GIGA-BYTE TECHNOLOGY CO., LTD.
-0020EE GTECH CORPORATION
-0020EF USC CORPORATION
-0020F0 UNIVERSAL MICROELECTRONICS CO.
-0020F1 ALTOS INDIA LIMITED
-0020F2 SUN MICROSYSTEMS, INC.
-0020F3 RAYNET CORPORATION
-0020F4 SPECTRIX CORPORATION
-0020F5 PANDATEL AG
-0020F6 NET TEK AND KARLNET, INC.
-0020F7 CYBERDATA
-0020F8 CARRERA COMPUTERS, INC.
-0020F9 PARALINK NETWORKS, INC.
-0020FA GDE SYSTEMS, INC.
-0020FB OCTEL COMMUNICATIONS CORP.
-0020FC MATROX
-0020FD ITV TECHNOLOGIES, INC.
-0020FE TOPWARE INC. / GRAND COMPUTER
-0020FF SYMMETRICAL TECHNOLOGIES
-003000 ALLWELL TECHNOLOGY CORP.
-003001 SMP
-003002 Expand Networks
-003003 Phasys Ltd.
-003004 LEADTEK RESEARCH INC.
-003005 Fujitsu Siemens Computers
-003006 SUPERPOWER COMPUTER
-003007 OPTI, INC.
-003008 AVIO DIGITAL, INC.
-003009 Tachion Networks, Inc.
-00300A AZTECH SYSTEMS LTD.
-00300B mPHASE Technologies, Inc.
-00300C CONGRUENCY, LTD.
-00300D MMC Technology, Inc.
-00300E Klotz Digital AG
-00300F IMT - Information Management T
-003010 VISIONETICS INTERNATIONAL
-003011 HMS FIELDBUS SYSTEMS AB
-003012 DIGITAL ENGINEERING LTD.
-003013 NEC Corporation
-003014 DIVIO, INC.
-003015 CP CLARE CORP.
-003016 ISHIDA CO., LTD.
-003017 TERASTACK LTD.
-003018 Jetway Information Co., Ltd.
-003019 CISCO SYSTEMS, INC.
-00301A SMARTBRIDGES PTE. LTD.
-00301B SHUTTLE, INC.
-00301C ALTVATER AIRDATA SYSTEMS
-00301D SKYSTREAM, INC.
-00301E 3COM Europe Ltd.
-00301F OPTICAL NETWORKS, INC.
-003020 TSI, Inc..
-003021 HSING TECH. ENTERPRISE CO.,LTD
-003022 Fong Kai Industrial Co., Ltd.
-003023 COGENT COMPUTER SYSTEMS, INC.
-003024 CISCO SYSTEMS, INC.
-003025 CHECKOUT COMPUTER SYSTEMS, LTD
-003026 HEITEL
-003027 KERBANGO, INC.
-003028 FASE Saldatura srl
-003029 OPICOM
-00302A SOUTHERN INFORMATION
-00302B INALP NETWORKS, INC.
-00302C SYLANTRO SYSTEMS CORPORATION
-00302D QUANTUM BRIDGE COMMUNICATIONS
-00302E Hoft & Wessel AG
-00302F Smiths Industries
-003030 HARMONIX CORPORATION
-003031 LIGHTWAVE COMMUNICATIONS, INC.
-003032 MagicRam, Inc.
-003033 ORIENT TELECOM CO., LTD.
-003036 RMP ELEKTRONIKSYSTEME GMBH
-003037 Packard Bell Nec Services
-003038 XCP, INC.
-003039 SOFTBOOK PRESS
-00303A MAATEL
-00303B PowerCom Technology
-00303C ONNTO CORP.
-00303D IVA CORPORATION
-00303E Radcom Ltd.
-00303F TurboComm Tech Inc.
-003040 CISCO SYSTEMS, INC.
-003041 SAEJIN T & M CO., LTD.
-003042 DeTeWe-Deutsche Telephonwerke
-003043 IDREAM TECHNOLOGIES, PTE. LTD.
-003044 Portsmith LLC
-003045 Village Networks, Inc. (VNI)
-003046 Controlled Electronic Manageme
-003047 NISSEI ELECTRIC CO., LTD.
-003048 Supermicro Computer, Inc.
-003049 BRYANT TECHNOLOGY, LTD.
-00304A FRAUNHOFER INSTITUTE IMS
-00304B ORBACOM SYSTEMS, INC.
-00304C APPIAN COMMUNICATIONS, INC.
-00304D ESI
-00304E BUSTEC PRODUCTION LTD.
-00304F PLANET Technology Corporation
-003050 Versa Technology
-003051 ORBIT AVIONIC & COMMUNICATION
-003052 ELASTIC NETWORKS
-003053 Basler AG
-003054 CASTLENET TECHNOLOGY, INC.
-003055 Hitachi Semiconductor America,
-003056 Beck IPC GmbH
-003057 E-Tel Corporation
-003058 API MOTION
-003059 DIGITAL-LOGIC AG
-00305A TELGEN CORPORATION
-00305B MODULE DEPARTMENT
-00305C SMAR Laboratories Corp.
-00305D DIGITRA SYSTEMS, INC.
-00305E Abelko Innovation
-00305F IMACON APS
-003060 STARMATIX, INC.
-003061 MobyTEL
-003062 PATH 1 NETWORK TECHNOL'S INC.
-003063 SANTERA SYSTEMS, INC.
-003064 ADLINK TECHNOLOGY, INC.
-003065 APPLE COMPUTER, INC.
-003066 DIGITAL WIRELESS CORPORATION
-003067 BIOSTAR MICROTECH INT'L CORP.
-003068 CYBERNETICS TECH. CO., LTD.
-003069 IMPACCT TECHNOLOGY CORP.
-00306A PENTA MEDIA CO., LTD.
-00306B CMOS SYSTEMS, INC.
-00306C Hitex Holding GmbH
-00306D LUCENT TECHNOLOGIES
-00306E HEWLETT PACKARD
-00306F SEYEON TECH. CO., LTD.
-003070 1Net Corporation
-003071 Cisco Systems, Inc.
-003072 INTELLIBYTE INC.
-003073 International Microsystems, In
-003074 EQUIINET LTD.
-003075 ADTECH
-003076 Akamba Corporation
-003077 ONPREM NETWORKS
-003078 Cisco Systems, Inc.
-003079 CQOS, INC.
-00307A Advanced Technology & Systems
-00307B Cisco Systems, Inc.
-00307C ADID SA
-00307D GRE AMERICA, INC.
-00307E Redflex Communication Systems
-00307F IRLAN LTD.
-003080 CISCO SYSTEMS, INC.
-003081 ALTOS C&C
-003082 TAIHAN ELECTRIC WIRE CO., LTD.
-003083 Ivron Systems
-003084 ALLIED TELESYN INTERNAIONAL
-003085 CISCO SYSTEMS, INC.
-003086 Transistor Devices, Inc.
-003087 VEGA GRIESHABER KG
-003088 Siara Systems, Inc.
-003089 Spectrapoint Wireless, LLC
-00308A NICOTRA SISTEMI S.P.A
-00308B Brix Networks
-00308C ADVANCED DIGITAL INFORMATION
-00308D PINNACLE SYSTEMS, INC.
-00308E CROSS MATCH TECHNOLOGIES, INC.
-00308F MICRILOR, Inc.
-003090 CYRA TECHNOLOGIES, INC.
-003091 TAIWAN FIRST LINE ELEC. CORP.
-003092 ModuNORM GmbH
-003093 SONNET TECHNOLOGIES, INC.
-003094 Cisco Systems, Inc.
-003095 Procomp Informatics, Ltd.
-003096 CISCO SYSTEMS, INC.
-003097 EXOMATIC AB
-003098 Global Converging Technologies
-003099 BOENIG UND KALLENBACH OHG
-00309A ASTRO TERRA CORP.
-00309B Smartware
-00309C Timing Applications, Inc.
-00309D Nimble Microsystems, Inc.
-00309E WORKBIT CORPORATION.
-00309F AMBER NETWORKS
-0030A0 TYCO SUBMARINE SYSTEMS, LTD.
-0030A1 WEBGATE Inc.
-0030A2 Lightner Engineering
-0030A3 CISCO SYSTEMS, INC.
-0030A4 Woodwind Communications System
-0030A5 ACTIVE POWER
-0030A6 VIANET TECHNOLOGIES, LTD.
-0030A7 SCHWEITZER ENGINEERING
-0030A8 OL'E COMMUNICATIONS, INC.
-0030A9 Netiverse, Inc.
-0030AA AXUS MICROSYSTEMS, INC.
-0030AB DELTA NETWORKS, INC.
-0030AC Systeme Lauer GmbH & Co., Ltd.
-0030AD SHANGHAI COMMUNICATION
-0030AE Times N System, Inc.
-0030AF Honeywell GmbH
-0030B0 Convergenet Technologies
-0030B1 GOC GESELLSCHAFT FUR OPTISCHE
-0030B2 WESCAM - HEALDSBURG
-0030B3 San Valley Systems, Inc.
-0030B4 INTERSIL CORP.
-0030B5 Tadiran Microwave Networks
-0030B6 CISCO SYSTEMS, INC.
-0030B7 Teletrol Systems, Inc.
-0030B8 RiverDelta Networks
-0030B9 ECTEL
-0030BA AC&T SYSTEM CO., LTD.
-0030BB CacheFlow, Inc.
-0030BC Optronic AG
-0030BD BELKIN COMPONENTS
-0030BE City-Net Technology, Inc.
-0030BF MULTIDATA GMBH
-0030C0 Lara Technology, Inc.
-0030C1 HEWLETT-PACKARD
-0030C2 COMONE
-0030C3 FLUECKIGER ELEKTRONIK AG
-0030C4 Niigata Canotec Co., Inc.
-0030C5 CADENCE DESIGN SYSTEMS
-0030C6 CONTROL SOLUTIONS, INC.
-0030C7 MACROMATE CORP.
-0030C8 GAD LINE, LTD.
-0030C9 LuxN, N
-0030CA Discovery Com
-0030CB OMNI FLOW COMPUTERS, INC.
-0030CC Tenor Networks, Inc.
-0030CD CONEXANT SYSTEMS, INC.
-0030CE Zaffire
-0030CF TWO TECHNOLOGIES, INC.
-0030D1 INOVA CORPORATION
-0030D2 WIN TECHNOLOGIES, CO., LTD.
-0030D3 Agilent Technologies
-0030D4 COMTIER
-0030D5 DResearch GmbH
-0030D6 MSC VERTRIEBS GMBH
-0030D7 Innovative Systems, L.L.C.
-0030D8 SITEK
-0030D9 DATACORE SOFTWARE CORP.
-0030DA COMTREND CO.
-0030DB Mindready Solutions, Inc.
-0030DC RIGHTECH CORPORATION
-0030DD INDIGITA CORPORATION
-0030DE WAGO Kontakttechnik GmbH
-0030DF KB/TEL TELECOMUNICACIONES
-0030E0 OXFORD SEMICONDUCTOR LTD.
-0030E1 ACROTRON SYSTEMS, INC.
-0030E2 GARNET SYSTEMS CO., LTD.
-0030E3 SEDONA NETWORKS CORP.
-0030E4 CHIYODA SYSTEM RIKEN
-0030E5 Amper Datos S.A.
-0030E6 SIEMENS MEDICAL SYSTEMS
-0030E7 CNF MOBILE SOLUTIONS, INC.
-0030E8 ENSIM CORP.
-0030E9 GMA COMMUNICATION MANUFACT'G
-0030EA TeraForce Technology Corporation
-0030EB TURBONET COMMUNICATIONS, INC.
-0030EC BORGARDT
-0030ED Expert Magnetics Corp.
-0030EE DSG Technology, Inc.
-0030EF NEON TECHNOLOGY, INC.
-0030F0 Uniform Industrial Corp.
-0030F1 Accton Technology Corp.
-0030F2 CISCO SYSTEMS, INC.
-0030F3 At Work Computers
-0030F4 STARDOT TECHNOLOGIES
-0030F5 Wild Lab. Ltd.
-0030F6 SECURELOGIX CORPORATION
-0030F7 RAMIX INC.
-0030F8 Dynapro Systems, Inc.
-0030F9 Sollae Systems Co., Ltd.
-0030FA TELICA, INC.
-0030FB AZS Technology AG
-0030FC Terawave Communications, Inc.
-0030FD INTEGRATED SYSTEMS DESIGN
-0030FE DSA GmbH
-0030FF DATAFAB SYSTEMS, INC.
-004000 PCI COMPONENTES DA AMZONIA LTD
-004001 ZYXEL COMMUNICATIONS, INC.
-004002 PERLE SYSTEMS LIMITED
-004003 WESTINGHOUSE PROCESS CONTROL
-004004 ICM CO. LTD.
-004005 ANI COMMUNICATIONS INC.
-004006 SAMPO TECHNOLOGY CORPORATION
-004007 TELMAT INFORMATIQUE
-004008 A PLUS INFO CORPORATION
-004009 TACHIBANA TECTRON CO., LTD.
-00400A PIVOTAL TECHNOLOGIES, INC.
-00400B CISCO SYSTEMS, INC.
-00400C GENERAL MICRO SYSTEMS, INC.
-00400D LANNET DATA COMMUNICATIONS,LTD
-00400E MEMOTEC COMMUNICATIONS, INC.
-00400F DATACOM TECHNOLOGIES
-004010 SONIC SYSTEMS, INC.
-004011 ANDOVER CONTROLS CORPORATION
-004012 WINDATA, INC.
-004013 NTT DATA COMM. SYSTEMS CORP.
-004014 COMSOFT GMBH
-004015 ASCOM INFRASYS AG
-004016 HADAX ELECTRONICS, INC.
-004017 XCD INC.
-004018 ADOBE SYSTEMS, INC.
-004019 AEON SYSTEMS, INC.
-00401A FUJI ELECTRIC CO., LTD.
-00401B PRINTER SYSTEMS CORP.
-00401C AST RESEARCH, INC.
-00401D INVISIBLE SOFTWARE, INC.
-00401E ICC
-00401F COLORGRAPH LTD
-004020 PINACL COMMUNICATION
-004021 RASTER GRAPHICS
-004022 KLEVER COMPUTERS, INC.
-004023 LOGIC CORPORATION
-004024 COMPAC INC.
-004025 MOLECULAR DYNAMICS
-004026 MELCO, INC.
-004027 SMC MASSACHUSETTS, INC.
-004028 NETCOMM LIMITED
-004029 COMPEX
-00402A CANOGA-PERKINS
-00402B TRIGEM COMPUTER, INC.
-00402C ISIS DISTRIBUTED SYSTEMS, INC.
-00402D HARRIS ADACOM CORPORATION
-00402E PRECISION SOFTWARE, INC.
-00402F XLNT DESIGNS INC.
-004030 GK COMPUTER
-004031 KOKUSAI ELECTRIC CO., LTD
-004032 DIGITAL COMMUNICATIONS
-004033 ADDTRON TECHNOLOGY CO., LTD.
-004034 BUSTEK CORPORATION
-004035 OPCOM
-004036 TRIBE COMPUTER WORKS, INC.
-004037 SEA-ILAN, INC.
-004038 TALENT ELECTRIC INCORPORATED
-004039 OPTEC DAIICHI DENKO CO., LTD.
-00403A IMPACT TECHNOLOGIES
-00403B SYNERJET INTERNATIONAL CORP.
-00403C FORKS, INC.
-00403D TERADATA
-00403E RASTER OPS CORPORATION
-00403F SSANGYONG COMPUTER SYSTEMS
-004040 RING ACCESS, INC.
-004041 FUJIKURA LTD.
-004042 N.A.T. GMBH
-004043 NOKIA TELECOMMUNICATIONS
-004044 QNIX COMPUTER CO., LTD.
-004045 TWINHEAD CORPORATION
-004046 UDC RESEARCH LIMITED
-004047 WIND RIVER SYSTEMS
-004048 SMD INFORMATICA S.A.
-004049 TEGIMENTA AG
-00404A WEST AUSTRALIAN DEPARTMENT
-00404B MAPLE COMPUTER SYSTEMS
-00404C HYPERTEC PTY LTD.
-00404D TELECOMMUNICATIONS TECHNIQUES
-00404E FLUENT, INC.
-00404F SPACE & NAVAL WARFARE SYSTEMS
-004050 IRONICS, INCORPORATED
-004051 GRACILIS, INC.
-004052 STAR TECHNOLOGIES, INC.
-004053 AMPRO COMPUTERS
-004054 CONNECTION MACHINES SERVICES
-004055 METRONIX GMBH
-004056 MCM JAPAN LTD.
-004057 LOCKHEED - SANDERS
-004058 KRONOS, INC.
-004059 YOSHIDA KOGYO K. K.
-00405A GOLDSTAR INFORMATION & COMM.
-00405B FUNASSET LIMITED
-00405C FUTURE SYSTEMS, INC.
-00405D STAR-TEK, INC.
-00405E NORTH HILLS ISRAEL
-00405F AFE COMPUTERS LTD.
-004060 COMENDEC LTD
-004061 DATATECH ENTERPRISES CO., LTD.
-004062 E-SYSTEMS, INC./GARLAND DIV.
-004063 VIA TECHNOLOGIES, INC.
-004064 KLA INSTRUMENTS CORPORATION
-004065 GTE SPACENET
-004066 HITACHI CABLE, LTD.
-004067 OMNIBYTE CORPORATION
-004068 EXTENDED SYSTEMS
-004069 LEMCOM SYSTEMS, INC.
-00406A KENTEK INFORMATION SYSTEMS,INC
-00406B SYSGEN
-00406C COPERNIQUE
-00406D LANCO, INC.
-00406E COROLLARY, INC.
-00406F SYNC RESEARCH INC.
-004070 INTERWARE CO., LTD.
-004071 ATM COMPUTER GMBH
-004072 Applied Innovation Inc.
-004073 BASS ASSOCIATES
-004074 CABLE AND WIRELESS
-004075 M-TRADE (UK) LTD
-004076 Sun Conversion Technologies
-004077 MAXTON TECHNOLOGY CORPORATION
-004078 WEARNES AUTOMATION PTE LTD
-004079 JUKO MANUFACTURE COMPANY, LTD.
-00407A SOCIETE D'EXPLOITATION DU CNIT
-00407B SCIENTIFIC ATLANTA
-00407C QUME CORPORATION
-00407D EXTENSION TECHNOLOGY CORP.
-00407E EVERGREEN SYSTEMS, INC.
-00407F FLIR Systems
-004080 ATHENIX CORPORATION
-004081 MANNESMANN SCANGRAPHIC GMBH
-004082 LABORATORY EQUIPMENT CORP.
-004083 TDA INDUSTRIA DE PRODUTOS
-004084 HONEYWELL INC.
-004085 SAAB INSTRUMENTS AB
-004086 MICHELS & KLEBERHOFF COMPUTER
-004087 UBITREX CORPORATION
-004088 MOBIUS TECHNOLOGIES, INC.
-004089 MEIDENSHA CORPORATION
-00408A TPS TELEPROCESSING SYS. GMBH
-00408B RAYLAN CORPORATION
-00408C AXIS COMMUNICATIONS AB
-00408D THE GOODYEAR TIRE & RUBBER CO.
-00408E DIGILOG, INC.
-00408F WM-DATA MINFO AB
-004090 ANSEL COMMUNICATIONS
-004091 PROCOMP INDUSTRIA ELETRONICA
-004092 ASP COMPUTER PRODUCTS, INC.
-004093 PAXDATA NETWORKS LTD.
-004094 SHOGRAPHICS, INC.
-004095 R.P.T. INTERGROUPS INT'L LTD.
-004096 Aironet Wireless Communication
-004097 DATEX DIVISION OF
-004098 DRESSLER GMBH & CO.
-004099 NEWGEN SYSTEMS CORP.
-00409A NETWORK EXPRESS, INC.
-00409B HAL COMPUTER SYSTEMS INC.
-00409C TRANSWARE
-00409D DIGIBOARD, INC.
-00409E CONCURRENT TECHNOLOGIES LTD.
-00409F LANCAST/CASAT TECHNOLOGY, INC.
-0040A0 GOLDSTAR CO., LTD.
-0040A1 ERGO COMPUTING
-0040A2 KINGSTAR TECHNOLOGY INC.
-0040A3 MICROUNITY SYSTEMS ENGINEERING
-0040A4 ROSE ELECTRONICS
-0040A5 CLINICOMP INTL.
-0040A6 Cray, Inc.
-0040A7 ITAUTEC PHILCO S.A.
-0040A8 IMF INTERNATIONAL LTD.
-0040A9 DATACOM INC.
-0040AA VALMET AUTOMATION INC.
-0040AB ROLAND DG CORPORATION
-0040AC SUPER WORKSTATION, INC.
-0040AD SMA REGELSYSTEME GMBH
-0040AE DELTA CONTROLS, INC.
-0040AF DIGITAL PRODUCTS, INC.
-0040B0 BYTEX CORPORATION, ENGINEERING
-0040B1 CODONICS INC.
-0040B2 SYSTEMFORSCHUNG
-0040B3 PAR MICROSYSTEMS CORPORATION
-0040B4 NEXTCOM K.K.
-0040B5 VIDEO TECHNOLOGY COMPUTERS LTD
-0040B6 COMPUTERM CORPORATION
-0040B7 STEALTH COMPUTER SYSTEMS
-0040B8 IDEA ASSOCIATES
-0040B9 MACQ ELECTRONIQUE SA
-0040BA ALLIANT COMPUTER SYSTEMS CORP.
-0040BB GOLDSTAR CABLE CO., LTD.
-0040BC ALGORITHMICS LTD.
-0040BD STARLIGHT NETWORKS, INC.
-0040BE BOEING DEFENSE & SPACE
-0040BF CHANNEL SYSTEMS INTERN'L INC.
-0040C0 VISTA CONTROLS CORPORATION
-0040C1 BIZERBA-WERKE WILHEIM KRAUT
-0040C2 APPLIED COMPUTING DEVICES
-0040C3 FISCHER AND PORTER CO.
-0040C4 KINKEI SYSTEM CORPORATION
-0040C5 MICOM COMMUNICATIONS INC.
-0040C6 FIBERNET RESEARCH, INC.
-0040C7 RUBY TECH CORPORATION
-0040C8 MILAN TECHNOLOGY CORPORATION
-0040C9 NCUBE
-0040CA FIRST INTERNAT'L COMPUTER, INC
-0040CB LANWAN TECHNOLOGIES
-0040CC SILCOM MANUF'G TECHNOLOGY INC.
-0040CD TERA MICROSYSTEMS, INC.
-0040CE NET-SOURCE, INC.
-0040CF STRAWBERRY TREE, INC.
-0040D0 MITAC INTERNATIONAL CORP.
-0040D1 FUKUDA DENSHI CO., LTD.
-0040D2 PAGINE CORPORATION
-0040D3 KIMPSION INTERNATIONAL CORP.
-0040D4 GAGE TALKER CORP.
-0040D5 SARTORIUS AG
-0040D6 LOCAMATION B.V.
-0040D7 STUDIO GEN INC.
-0040D8 OCEAN OFFICE AUTOMATION LTD.
-0040D9 AMERICAN MEGATRENDS INC.
-0040DA TELSPEC LTD
-0040DB ADVANCED TECHNICAL SOLUTIONS
-0040DC TRITEC ELECTRONIC GMBH
-0040DD HONG TECHNOLOGIES
-0040DE ELETTRONICA SAN GIORGIO
-0040DF DIGALOG SYSTEMS, INC.
-0040E0 ATOMWIDE LTD.
-0040E1 MARNER INTERNATIONAL, INC.
-0040E2 MESA RIDGE TECHNOLOGIES, INC.
-0040E3 QUIN SYSTEMS LTD
-0040E4 E-M TECHNOLOGY, INC.
-0040E5 SYBUS CORPORATION
-0040E6 C.A.E.N.
-0040E7 ARNOS INSTRUMENTS & COMPUTER
-0040E8 CHARLES RIVER DATA SYSTEMS,INC
-0040E9 ACCORD SYSTEMS, INC.
-0040EA PLAIN TREE SYSTEMS INC
-0040EB MARTIN MARIETTA CORPORATION
-0040EC MIKASA SYSTEM ENGINEERING
-0040ED NETWORK CONTROLS INT'NATL INC.
-0040EE OPTIMEM
-0040EF HYPERCOM, INC.
-0040F0 MICRO SYSTEMS, INC.
-0040F1 CHUO ELECTRONICS CO., LTD.
-0040F2 JANICH & KLASS COMPUTERTECHNIK
-0040F3 NETCOR
-0040F4 CAMEO COMMUNICATIONS, INC.
-0040F5 OEM ENGINES
-0040F6 KATRON COMPUTERS INC.
-0040F7 POLAROID MEDICAL IMAGING SYS.
-0040F8 SYSTEMHAUS DISCOM
-0040F9 COMBINET
-0040FA MICROBOARDS, INC.
-0040FB CASCADE COMMUNICATIONS CORP.
-0040FC IBR COMPUTER TECHNIK GMBH
-0040FD LXE
-0040FE SYMPLEX COMMUNICATIONS
-0040FF TELEBIT CORPORATION
-004252 RLX Technologies
-005000 NEXO COMMUNICATIONS, INC.
-005001 YAMASHITA SYSTEMS CORP.
-005002 OMNISEC AG
-005003 GRETAG MACBETH AG
-005004 3COM CORPORATION
-005006 TAC AB
-005007 SIEMENS TELECOMMUNICATION SYSTEMS LIMITED
-005008 TIVA MICROCOMPUTER CORP. (TMC)
-005009 PHILIPS BROADBAND NETWORKS
-00500A IRIS TECHNOLOGIES, INC.
-00500B CISCO SYSTEMS, INC.
-00500C e-Tek Labs, Inc.
-00500D SATORI ELECTORIC CO., LTD.
-00500E CHROMATIS NETWORKS, INC.
-00500F CISCO SYSTEMS, INC.
-005010 NovaNET Learning, Inc.
-005012 CBL - GMBH
-005013 Chaparral Network Storage
-005014 CISCO SYSTEMS, INC.
-005015 BRIGHT STAR ENGINEERING
-005016 SST/WOODHEAD INDUSTRIES
-005017 RSR S.R.L.
-005018 ADVANCED MULTIMEDIA INTERNET TECHNOLOGY INC.
-005019 SPRING TIDE NETWORKS, INC.
-00501A UISIQN
-00501B ABL CANADA, INC.
-00501C JATOM SYSTEMS, INC.
-00501E Miranda Technologies, Inc.
-00501F MRG SYSTEMS, LTD.
-005020 MEDIASTAR CO., LTD.
-005021 EIS INTERNATIONAL, INC.
-005022 ZONET TECHNOLOGY, INC.
-005023 PG DESIGN ELECTRONICS, INC.
-005024 NAVIC SYSTEMS, INC.
-005026 COSYSTEMS, INC.
-005027 GENICOM CORPORATION
-005028 AVAL COMMUNICATIONS
-005029 1394 PRINTER WORKING GROUP
-00502A CISCO SYSTEMS, INC.
-00502B GENRAD LTD.
-00502C SOYO COMPUTER, INC.
-00502D ACCEL, INC.
-00502E CAMBEX CORPORATION
-00502F TollBridge Technologies, Inc.
-005030 FUTURE PLUS SYSTEMS
-005031 AEROFLEX LABORATORIES, INC.
-005032 PICAZO COMMUNICATIONS, INC.
-005033 MAYAN NETWORKS
-005036 NETCAM, LTD.
-005037 KOGA ELECTRONICS CO.
-005038 DAIN TELECOM CO., LTD.
-005039 MARINER NETWORKS
-00503A DATONG ELECTRONICS LTD.
-00503B MEDIAFIRE CORPORATION
-00503C TSINGHUA NOVEL ELECTRONICS
-00503E CISCO SYSTEMS, INC.
-00503F ANCHOR GAMES
-005040 EMWARE, INC.
-005041 CTX OPTO ELECTRONIC CORP.
-005042 SCI MANUFACTURING SINGAPORE PTE, LTD.
-005043 MARVELL SEMICONDUCTOR, INC.
-005044 ASACA CORPORATION
-005045 RIOWORKS SOLUTIONS, INC.
-005046 MENICX INTERNATIONAL CO., LTD.
-005048 INFOLIBRIA
-005049 ELLACOYA NETWORKS, INC.
-00504A ELTECO A.S.
-00504B BARCONET N.V.
-00504C GALIL MOTION CONTROL, INC.
-00504D TOKYO ELECTRON DEVICE LTD.
-00504E SIERRA MONITOR CORP.
-00504F OLENCOM ELECTRONICS
-005050 CISCO SYSTEMS, INC.
-005051 IWATSU ELECTRIC CO., LTD.
-005052 TIARA NETWORKS, INC.
-005053 CISCO SYSTEMS, INC.
-005054 CISCO SYSTEMS, INC.
-005055 DOMS A/S
-005056 VMWare, Inc.
-005057 BROADBAND ACCESS SYSTEMS
-005058 VEGASTREAM LIMITED
-005059 SUITE TECHNOLOGY SYSTEMS NETWORK
-00505A NETWORK ALCHEMY, INC.
-00505B KAWASAKI LSI U.S.A., INC.
-00505C TUNDO CORPORATION
-00505E DIGITEK MICROLOGIC S.A.
-00505F BRAND INNOVATORS
-005060 TANDBERG TELECOM AS
-005062 KOUWELL ELECTRONICS CORP. **
-005063 OY COMSEL SYSTEM AB
-005064 CAE ELECTRONICS
-005065 DENSEI-LAMBAD Co., Ltd.
-005066 AtecoM GmbH advanced telecomunication modules
-005067 AEROCOMM, INC.
-005068 ELECTRONIC INDUSTRIES ASSOCIATION
-005069 PixStream Incorporated
-00506A EDEVA, INC.
-00506B SPX-ATEG
-00506C G & L BEIJER ELECTRONICS AB
-00506D VIDEOJET SYSTEMS
-00506E CORDER ENGINEERING CORPORATION
-00506F G-CONNECT
-005070 CHAINTECH COMPUTER CO., LTD.
-005071 AIWA CO., LTD.
-005072 CORVIS CORPORATION
-005073 CISCO SYSTEMS, INC.
-005074 ADVANCED HI-TECH CORP.
-005075 KESTREL SOLUTIONS
-005076 IBM
-005077 PROLIFIC TECHNOLOGY, INC.
-005078 MEGATON HOUSE, LTD.
-00507A XPEED, INC.
-00507B MERLOT COMMUNICATIONS
-00507C VIDEOCON AG
-00507D IFP
-00507E NEWER TECHNOLOGY
-00507F DrayTek Corp.
-005080 CISCO SYSTEMS, INC.
-005081 MURATA MACHINERY, LTD.
-005082 FORESSON CORPORATION
-005083 GILBARCO, INC.
-005084 ATL PRODUCTS
-005086 TELKOM SA, LTD.
-005087 TERASAKI ELECTRIC CO., LTD.
-005088 AMANO CORPORATION
-005089 SAFETY MANAGEMENT SYSTEMS
-00508B COMPAQ COMPUTER CORPORATION
-00508C RSI SYSTEMS
-00508D ABIT COMPUTER CORPORATION
-00508E OPTIMATION, INC.
-00508F ASITA TECHNOLOGIES INT'L LTD.
-005090 DCTRI
-005091 NETACCESS, INC.
-005092 RIGAKU INDUSTRIAL CORPORATION
-005093 BOEING
-005094 PACE MICRO TECHNOLOGY PLC
-005095 PERACOM NETWORKS
-005096 SALIX TECHNOLOGIES, INC.
-005097 MMC-EMBEDDED COMPUTERTECHNIK GmbH
-005098 GLOBALOOP, LTD.
-005099 3COM EUROPE, LTD.
-00509A TAG ELECTRONIC SYSTEMS
-00509B SWITCHCORE AB
-00509C BETA RESEARCH
-00509D THE INDUSTREE B.V.
-00509E Les Technologies SoftAcoustik Inc.
-00509F HORIZON COMPUTER
-0050A0 DELTA COMPUTER SYSTEMS, INC.
-0050A1 CARLO GAVAZZI, INC.
-0050A2 CISCO SYSTEMS, INC.
-0050A3 TransMedia Communications, Inc.
-0050A4 IO TECH, INC.
-0050A5 CAPITOL BUSINESS SYSTEMS, LTD.
-0050A6 OPTRONICS
-0050A7 CISCO SYSTEMS, INC.
-0050A8 OpenCon Systems, Inc.
-0050A9 MOLDAT WIRELESS TECHNOLGIES
-0050AA KONICA MINOLTA HOLDINGS, INC.
-0050AB NALTEC, INC.
-0050AC MAPLE COMPUTER CORPORATION
-0050AD CommUnique Wireless Corp.
-0050AE IWAKI ELECTRONICS CO., LTD.
-0050AF INTERGON, INC.
-0050B0 TECHNOLOGY ATLANTA CORPORATION
-0050B1 GIDDINGS & LEWIS
-0050B2 BRODEL AUTOMATION
-0050B3 VOICEBOARD CORPORATION
-0050B4 SATCHWELL CONTROL SYSTEMS, LTD
-0050B5 FICHET-BAUCHE
-0050B6 GOOD WAY IND. CO., LTD.
-0050B7 BOSER TECHNOLOGY CO., LTD.
-0050B8 INOVA COMPUTERS GMBH & CO. KG
-0050B9 XITRON TECHNOLOGIES, INC.
-0050BA D-LINK
-0050BB CMS TECHNOLOGIES
-0050BC HAMMER STORAGE SOLUTIONS
-0050BD CISCO SYSTEMS, INC.
-0050BE FAST MULTIMEDIA AG
-0050BF MOTOTECH INC.
-0050C0 GATAN, INC.
-0050C1 GEMFLEX NETWORKS, LTD.
-0050C2 IEEE REGISTRATION AUTHORITY
-0050C4 IMD
-0050C5 ADS TECHNOLOGIES, INC.
-0050C6 LOOP TELECOMMUNICATION INTERNATIONAL, INC.
-0050C8 ADDONICS COMMUNICATIONS, INC.
-0050C9 MASPRO DENKOH CORP.
-0050CA NET TO NET TECHNOLOGIES
-0050CB JETTER
-0050CC XYRATEX
-0050CD DIGIANSWER A/S
-0050CE LG INTERNATIONAL CORP.
-0050CF VANLINK COMMUNICATION TECHNOLOGY RESEARCH INSTITUTE
-0050D0 MINERVA SYSTEMS
-0050D1 CISCO SYSTEMS, INC.
-0050D2 BAE Systems Canada, Inc.
-0050D3 DIGITAL AUDIO PROCESSING PTY. LTD.
-0050D4 JOOHONG INFORMATION &
-0050D5 AD SYSTEMS CORP.
-0050D6 ATLAS COPCO TOOLS AB
-0050D7 TELSTRAT
-0050D8 UNICORN COMPUTER CORP.
-0050D9 ENGETRON-ENGENHARIA ELETRONICA IND. e COM. LTDA
-0050DA 3COM CORPORATION
-0050DB CONTEMPORARY CONTROL
-0050DC TAS TELEFONBAU A. SCHWABE GMBH & CO. KG
-0050DD SERRA SOLDADURA, S.A.
-0050DE SIGNUM SYSTEMS CORP.
-0050DF AirFiber, Inc.
-0050E1 NS TECH ELECTRONICS SDN BHD
-0050E2 CISCO SYSTEMS, INC.
-0050E3 Terayon Communications Systems
-0050E4 APPLE COMPUTER, INC.
-0050E6 HAKUSAN CORPORATION
-0050E7 PARADISE INNOVATIONS (ASIA)
-0050E8 NOMADIX INC.
-0050EA XEL COMMUNICATIONS, INC.
-0050EB ALPHA-TOP CORPORATION
-0050EC OLICOM A/S
-0050ED ANDA NETWORKS
-0050EE TEK DIGITEL CORPORATION
-0050EF SPE Systemhaus GmbH
-0050F0 CISCO SYSTEMS, INC.
-0050F1 LIBIT SIGNAL PROCESSING, LTD.
-0050F2 MICROSOFT CORP.
-0050F3 GLOBAL NET INFORMATION CO., Ltd.
-0050F4 SIGMATEK GMBH & CO. KG
-0050F6 PAN-INTERNATIONAL INDUSTRIAL CORP.
-0050F7 VENTURE MANUFACTURING (SINGAPORE) LTD.
-0050F8 ENTREGA TECHNOLOGIES, INC.
-0050FA OXTEL, LTD.
-0050FB VSK ELECTRONICS
-0050FC EDIMAX TECHNOLOGY CO., LTD.
-0050FD VISIONCOMM CO., LTD.
-0050FE PCTVnet ASA
-0050FF HAKKO ELECTRONICS CO., LTD.
-006000 XYCOM INC.
-006001 InnoSys, Inc.
-006002 SCREEN SUBTITLING SYSTEMS, LTD
-006003 TERAOKA WEIGH SYSTEM PTE, LTD.
-006004 COMPUTADORES MODULARES SA
-006005 FEEDBACK DATA LTD.
-006006 SOTEC CO., LTD
-006007 ACRES GAMING, INC.
-006008 3COM CORPORATION
-006009 CISCO SYSTEMS, INC.
-00600A SORD COMPUTER CORPORATION
-00600B LOGWARE GmbH
-00600C APPLIED DATA SYSTEMS, INC.
-00600D Digital Logic GmbH
-00600E WAVENET INTERNATIONAL, INC.
-00600F WESTELL, INC.
-006010 NETWORK MACHINES, INC.
-006011 CRYSTAL SEMICONDUCTOR CORP.
-006012 POWER COMPUTING CORPORATION
-006013 NETSTAL MASCHINEN AG
-006014 EDEC CO., LTD.
-006015 NET2NET CORPORATION
-006016 CLARIION
-006017 TOKIMEC INC.
-006018 STELLAR ONE CORPORATION
-006019 Roche Diagnostics
-00601A KEITHLEY INSTRUMENTS
-00601B MESA ELECTRONICS
-00601C TELXON CORPORATION
-00601D LUCENT TECHNOLOGIES
-00601E SOFTLAB, INC.
-00601F STALLION TECHNOLOGIES
-006020 PIVOTAL NETWORKING, INC.
-006021 DSC CORPORATION
-006022 VICOM SYSTEMS, INC.
-006023 PERICOM SEMICONDUCTOR CORP.
-006024 GRADIENT TECHNOLOGIES, INC.
-006025 ACTIVE IMAGING PLC
-006026 VIKING COMPONENTS, INC.
-006027 Superior Modular Products
-006028 MACROVISION CORPORATION
-006029 CARY PERIPHERALS INC.
-00602A SYMICRON COMPUTER COMMUNICATIONS, LTD.
-00602B PEAK AUDIO
-00602C LINX Data Terminals, Inc.
-00602D ALERTON TECHNOLOGIES, INC.
-00602E CYCLADES CORPORATION
-00602F CISCO SYSTEMS, INC.
-006030 VILLAGE TRONIC ENTWICKLUNG
-006031 HRK SYSTEMS
-006032 I-CUBE, INC.
-006033 ACUITY IMAGING, INC.
-006034 ROBERT BOSCH GmbH
-006035 DALLAS SEMICONDUCTOR, INC.
-006036 AUSTRIAN RESEARCH CENTER SEIBERSDORF
-006037 PHILIPS SEMICONDUCTORS
-006038 Nortel Networks
-006039 SanCom Technology, Inc.
-00603A QUICK CONTROLS LTD.
-00603B AMTEC spa
-00603C HAGIWARA SYS-COM CO., LTD.
-00603D 3CX
-00603E CISCO SYSTEMS, INC.
-00603F PATAPSCO DESIGNS
-006040 NETRO CORP.
-006041 Yokogawa Electric Corporation
-006042 TKS (USA), INC.
-006043 ComSoft Systems, Inc.
-006044 LITTON/POLY-SCIENTIFIC
-006045 PATHLIGHT TECHNOLOGIES
-006046 VMETRO, INC.
-006047 CISCO SYSTEMS, INC.
-006048 EMC CORPORATION
-006049 VINA TECHNOLOGIES
-00604A SAIC IDEAS GROUP
-00604B BIODATA GmbH
-00604C SAT
-00604D MMC NETWORKS, INC.
-00604E CYCLE COMPUTER CORPORATION, INC.
-00604F SUZUKI MFG. CO., LTD.
-006050 INTERNIX INC.
-006051 QUALITY SEMICONDUCTOR
-006052 PERIPHERALS ENTERPRISE CO., Ltd.
-006053 TOYODA MACHINE WORKS, LTD.
-006054 CONTROLWARE GMBH
-006055 CORNELL UNIVERSITY
-006056 NETWORK TOOLS, INC.
-006057 MURATA MANUFACTURING CO., LTD.
-006058 COPPER MOUNTAIN COMMUNICATIONS, INC.
-006059 TECHNICAL COMMUNICATIONS CORP.
-00605A CELCORE, INC.
-00605B IntraServer Technology, Inc.
-00605C CISCO SYSTEMS, INC.
-00605D SCANIVALVE CORP.
-00605E LIBERTY TECHNOLOGY NETWORKING
-00605F NIPPON UNISOFT CORPORATION
-006060 DAWNING TECHNOLOGIES, INC.
-006061 WHISTLE COMMUNICATIONS CORP.
-006062 TELESYNC, INC.
-006063 PSION DACOM PLC.
-006064 NETCOMM LIMITED
-006065 BERNECKER & RAINER INDUSTRIE-ELEKTRONIC GmbH
-006066 LACROIX TECHNOLGIE
-006067 ACER NETXUS INC.
-006068 EICON TECHNOLOGY CORPORATION
-006069 BROCADE COMMUNICATIONS SYSTEMS, Inc.
-00606A MITSUBISHI WIRELESS COMMUNICATIONS. INC.
-00606B Synclayer Inc.
-00606C ARESCOM
-00606D DIGITAL EQUIPMENT CORP.
-00606E DAVICOM SEMICONDUCTOR, INC.
-00606F CLARION CORPORATION OF AMERICA
-006070 CISCO SYSTEMS, INC.
-006071 MIDAS LAB, INC.
-006072 VXL INSTRUMENTS, LIMITED
-006073 REDCREEK COMMUNICATIONS, INC.
-006074 QSC AUDIO PRODUCTS
-006075 PENTEK, INC.
-006076 SCHLUMBERGER TECHNOLOGIES RETAIL PETROLEUM SYSTEMS
-006077 PRISA NETWORKS
-006078 POWER MEASUREMENT LTD.
-006079 Mainstream Data, Inc.
-00607A DVS GmbH
-00607B FORE SYSTEMS, INC.
-00607C WaveAccess, Ltd.
-00607D SENTIENT NETWORKS INC.
-00607E GIGALABS, INC.
-00607F AURORA TECHNOLOGIES, INC.
-006080 MICROTRONIX DATACOM LTD.
-006081 TV/COM INTERNATIONAL
-006082 NOVALINK TECHNOLOGIES, INC.
-006083 CISCO SYSTEMS, INC.
-006084 DIGITAL VIDEO
-006085 Storage Concepts
-006086 LOGIC REPLACEMENT TECH. LTD.
-006087 KANSAI ELECTRIC CO., LTD.
-006088 WHITE MOUNTAIN DSP, INC.
-006089 XATA
-00608A CITADEL COMPUTER
-00608B ConferTech International
-00608C 3COM CORPORATION
-00608D UNIPULSE CORP.
-00608E HE ELECTRONICS, TECHNOLOGIE & SYSTEMTECHNIK GmbH
-00608F TEKRAM TECHNOLOGY CO., LTD.
-006090 ABLE COMMUNICATIONS, INC.
-006091 FIRST PACIFIC NETWORKS, INC.
-006092 MICRO/SYS, INC.
-006093 VARIAN
-006094 IBM CORP.
-006095 ACCU-TIME SYSTEMS, INC.
-006096 T.S. MICROTECH INC.
-006097 3COM CORPORATION
-006098 HT COMMUNICATIONS
-006099 LAN MEDIA CORPORATION
-00609A NJK TECHNO CO.
-00609B ASTRO-MED, INC.
-00609C Perkin-Elmer Incorporated
-00609D PMI FOOD EQUIPMENT GROUP
-00609E ASC X3 - INFORMATION TECHNOLOGY STANDARDS SECRETARIATS
-00609F PHAST CORPORATION
-0060A0 SWITCHED NETWORK TECHNOLOGIES, INC.
-0060A1 VPNet, Inc.
-0060A2 NIHON UNISYS LIMITED CO.
-0060A3 CONTINUUM TECHNOLOGY CORP.
-0060A4 GRINAKER SYSTEM TECHNOLOGIES
-0060A5 PERFORMANCE TELECOM CORP.
-0060A6 PARTICLE MEASURING SYSTEMS
-0060A7 MICROSENS GmbH & CO. KG
-0060A8 TIDOMAT AB
-0060A9 GESYTEC MbH
-0060AA INTELLIGENT DEVICES INC. (IDI)
-0060AB LARSCOM INCORPORATED
-0060AC RESILIENCE CORPORATION
-0060AD MegaChips Corporation
-0060AE TRIO INFORMATION SYSTEMS AB
-0060AF PACIFIC MICRO DATA, INC.
-0060B0 HEWLETT-PACKARD CO.
-0060B1 INPUT/OUTPUT, INC.
-0060B2 PROCESS CONTROL CORP.
-0060B3 Z-COM, INC.
-0060B4 GLENAYRE R&D INC.
-0060B5 KEBA GmbH
-0060B6 LAND COMPUTER CO., LTD.
-0060B7 CHANNELMATIC, INC.
-0060B8 CORELIS INC.
-0060B9 NITSUKO CORPORATION
-0060BA SAHARA NETWORKS, INC.
-0060BB CABLETRON - NETLINK, INC.
-0060BC KeunYoung Electronics & Communication Co., Ltd.
-0060BD HUBBELL-PULSECOM
-0060BE WEBTRONICS
-0060BF MACRAIGOR SYSTEMS, INC.
-0060C0 NERA AS
-0060C1 WaveSpan Corporation
-0060C2 MPL AG
-0060C3 NETVISION CORPORATION
-0060C4 SOLITON SYSTEMS K.K.
-0060C5 ANCOT CORP.
-0060C6 DCS AG
-0060C7 AMATI COMMUNICATIONS CORP.
-0060C8 KUKA WELDING SYSTEMS & ROBOTS
-0060C9 ControlNet, Inc.
-0060CA HARMONIC SYSTEMS INCORPORATED
-0060CB HITACHI ZOSEN CORPORATION
-0060CC EMTRAK, INCORPORATED
-0060CD VideoServer, Inc.
-0060CE ACCLAIM COMMUNICATIONS
-0060CF ALTEON NETWORKS, INC.
-0060D0 SNMP RESEARCH INCORPORATED
-0060D1 CASCADE COMMUNICATIONS
-0060D2 LUCENT TECHNOLOGIES TAIWAN TELECOMMUNICATIONS CO., LTD.
-0060D3 AT&T
-0060D4 ELDAT COMMUNICATION LTD.
-0060D5 MIYACHI TECHNOS CORP.
-0060D6 NovAtel Wireless Technologies Ltd.
-0060D7 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE (EPFL)
-0060D8 ELMIC SYSTEMS, INC.
-0060D9 TRANSYS NETWORKS INC.
-0060DA JBM ELECTRONICS CO.
-0060DB NTP ELEKTRONIK A/S
-0060DC TOYO COMMUNICATION EQUIPMENT Co., Ltd.
-0060DD MYRICOM, INC.
-0060DE KAYSER-THREDE GmbH
-0060DF CNT Corporation
-0060E0 AXIOM TECHNOLOGY CO., LTD.
-0060E1 ORCKIT COMMUNICATIONS LTD.
-0060E2 QUEST ENGINEERING & DEVELOPMENT
-0060E3 ARBIN INSTRUMENTS
-0060E4 COMPUSERVE, INC.
-0060E5 FUJI AUTOMATION CO., LTD.
-0060E6 SHOMITI SYSTEMS INCORPORATED
-0060E7 RANDATA
-0060E8 HITACHI COMPUTER PRODUCTS (AMERICA), INC.
-0060E9 ATOP TECHNOLOGIES, INC.
-0060EA StreamLogic
-0060EB FOURTHTRACK SYSTEMS
-0060EC HERMARY OPTO ELECTRONICS INC.
-0060ED RICARDO TEST AUTOMATION LTD.
-0060EE APOLLO
-0060EF FLYTECH TECHNOLOGY CO., LTD.
-0060F0 JOHNSON & JOHNSON MEDICAL, INC
-0060F1 EXP COMPUTER, INC.
-0060F2 LASERGRAPHICS, INC.
-0060F3 Performance Analysis Broadband, Spirent plc
-0060F4 ADVANCED COMPUTER SOLUTIONS, Inc.
-0060F5 ICON WEST, INC.
-0060F6 NEXTEST COMMUNICATIONS PRODUCTS, INC.
-0060F7 DATAFUSION SYSTEMS
-0060F8 Loran International Technologies Inc.
-0060F9 DIAMOND LANE COMMUNICATIONS
-0060FA EDUCATIONAL TECHNOLOGY RESOURCES, INC.
-0060FB PACKETEER, INC.
-0060FC CONSERVATION THROUGH INNOVATION LTD.
-0060FD NetICs, Inc.
-0060FE LYNX SYSTEM DEVELOPERS, INC.
-0060FF QuVis, Inc.
-0070B0 M/A-COM INC. COMPANIES
-0070B3 DATA RECALL LTD.
-008000 MULTITECH SYSTEMS, INC.
-008001 PERIPHONICS CORPORATION
-008002 SATELCOM (UK) LTD
-008003 HYTEC ELECTRONICS LTD.
-008004 ANTLOW COMMUNICATIONS, LTD.
-008005 CACTUS COMPUTER INC.
-008006 COMPUADD CORPORATION
-008007 DLOG NC-SYSTEME
-008008 DYNATECH COMPUTER SYSTEMS
-008009 JUPITER SYSTEMS, INC.
-00800A JAPAN COMPUTER CORP.
-00800B CSK CORPORATION
-00800C VIDECOM LIMITED
-00800D VOSSWINKEL F.U.
-00800E ATLANTIX CORPORATION
-00800F STANDARD MICROSYSTEMS
-008010 COMMODORE INTERNATIONAL
-008011 DIGITAL SYSTEMS INT'L. INC.
-008012 INTEGRATED MEASUREMENT SYSTEMS
-008013 THOMAS-CONRAD CORPORATION
-008014 ESPRIT SYSTEMS
-008015 SEIKO SYSTEMS, INC.
-008016 WANDEL AND GOLTERMANN
-008017 PFU LIMITED
-008018 KOBE STEEL, LTD.
-008019 DAYNA COMMUNICATIONS, INC.
-00801A BELL ATLANTIC
-00801B KODIAK TECHNOLOGY
-00801C NEWPORT SYSTEMS SOLUTIONS
-00801D INTEGRATED INFERENCE MACHINES
-00801E XINETRON, INC.
-00801F KRUPP ATLAS ELECTRONIK GMBH
-008020 NETWORK PRODUCTS
-008021 Alcatel Canada Inc.
-008022 SCAN-OPTICS
-008023 INTEGRATED BUSINESS NETWORKS
-008024 KALPANA, INC.
-008025 STOLLMANN GMBH
-008026 NETWORK PRODUCTS CORPORATION
-008027 ADAPTIVE SYSTEMS, INC.
-008028 TRADPOST (HK) LTD
-008029 EAGLE TECHNOLOGY, INC.
-00802A TEST SYSTEMS & SIMULATIONS INC
-00802B INTEGRATED MARKETING CO
-00802C THE SAGE GROUP PLC
-00802D XYLOGICS INC
-00802E CASTLE ROCK COMPUTING
-00802F NATIONAL INSTRUMENTS CORP.
-008030 NEXUS ELECTRONICS
-008031 BASYS, CORP.
-008032 ACCESS CO., LTD.
-008033 FORMATION, INC.
-008034 SMT GOUPIL
-008035 TECHNOLOGY WORKS, INC.
-008036 REFLEX MANUFACTURING SYSTEMS
-008037 Ericsson Group
-008038 DATA RESEARCH & APPLICATIONS
-008039 ALCATEL STC AUSTRALIA
-00803A VARITYPER, INC.
-00803B APT COMMUNICATIONS, INC.
-00803C TVS ELECTRONICS LTD
-00803D SURIGIKEN CO., LTD.
-00803E SYNERNETICS
-00803F TATUNG COMPANY
-008040 JOHN FLUKE MANUFACTURING CO.
-008041 VEB KOMBINAT ROBOTRON
-008042 FORCE COMPUTERS
-008043 NETWORLD, INC.
-008044 SYSTECH COMPUTER CORP.
-008045 MATSUSHITA ELECTRIC IND. CO
-008046 UNIVERSITY OF TORONTO
-008047 IN-NET CORP.
-008048 COMPEX INCORPORATED
-008049 NISSIN ELECTRIC CO., LTD.
-00804A PRO-LOG
-00804B EAGLE TECHNOLOGIES PTY.LTD.
-00804C CONTEC CO., LTD.
-00804D CYCLONE MICROSYSTEMS, INC.
-00804E APEX COMPUTER COMPANY
-00804F DAIKIN INDUSTRIES, LTD.
-008050 ZIATECH CORPORATION
-008051 FIBERMUX
-008052 TECHNICALLY ELITE CONCEPTS
-008053 INTELLICOM, INC.
-008054 FRONTIER TECHNOLOGIES CORP.
-008055 FERMILAB
-008056 SPHINX ELEKTRONIK GMBH
-008057 ADSOFT, LTD.
-008058 PRINTER SYSTEMS CORPORATION
-008059 STANLEY ELECTRIC CO., LTD
-00805A TULIP COMPUTERS INTERNAT'L B.V
-00805B CONDOR SYSTEMS, INC.
-00805C AGILIS CORPORATION
-00805D CANSTAR
-00805E LSI LOGIC CORPORATION
-00805F COMPAQ COMPUTER CORPORATION
-008060 NETWORK INTERFACE CORPORATION
-008061 LITTON SYSTEMS, INC.
-008062 INTERFACE CO.
-008063 RICHARD HIRSCHMANN GMBH & CO.
-008064 WYSE TECHNOLOGY
-008065 CYBERGRAPHIC SYSTEMS PTY LTD.
-008066 ARCOM CONTROL SYSTEMS, LTD.
-008067 SQUARE D COMPANY
-008068 YAMATECH SCIENTIFIC LTD.
-008069 COMPUTONE SYSTEMS
-00806A ERI (EMPAC RESEARCH INC.)
-00806B SCHMID TELECOMMUNICATION
-00806C CEGELEC PROJECTS LTD
-00806D CENTURY SYSTEMS CORP.
-00806E NIPPON STEEL CORPORATION
-00806F ONELAN LTD.
-008070 COMPUTADORAS MICRON
-008071 SAI TECHNOLOGY
-008072 MICROPLEX SYSTEMS LTD.
-008073 DWB ASSOCIATES
-008074 FISHER CONTROLS
-008075 PARSYTEC GMBH
-008076 MCNC
-008077 BROTHER INDUSTRIES, LTD.
-008078 PRACTICAL PERIPHERALS, INC.
-008079 MICROBUS DESIGNS LTD.
-00807A AITECH SYSTEMS LTD.
-00807B ARTEL COMMUNICATIONS CORP.
-00807C FIBERCOM, INC.
-00807D EQUINOX SYSTEMS INC.
-00807E SOUTHERN PACIFIC LTD.
-00807F DY-4 INCORPORATED
-008080 DATAMEDIA CORPORATION
-008081 KENDALL SQUARE RESEARCH CORP.
-008082 PEP MODULAR COMPUTERS GMBH
-008083 AMDAHL
-008084 THE CLOUD INC.
-008085 H-THREE SYSTEMS CORPORATION
-008086 COMPUTER GENERATION INC.
-008087 OKI ELECTRIC INDUSTRY CO., LTD
-008088 VICTOR COMPANY OF JAPAN, LTD.
-008089 TECNETICS (PTY) LTD.
-00808A SUMMIT MICROSYSTEMS CORP.
-00808B DACOLL LIMITED
-00808C NetScout Systems, Inc.
-00808D WESTCOAST TECHNOLOGY B.V.
-00808E RADSTONE TECHNOLOGY
-00808F C. ITOH ELECTRONICS, INC.
-008090 MICROTEK INTERNATIONAL, INC.
-008091 TOKYO ELECTRIC CO.,LTD
-008092 JAPAN COMPUTER INDUSTRY, INC.
-008093 XYRON CORPORATION
-008094 ALFA LAVAL AUTOMATION AB
-008095 BASIC MERTON HANDELSGES.M.B.H.
-008096 HUMAN DESIGNED SYSTEMS, INC.
-008097 CENTRALP AUTOMATISMES
-008098 TDK CORPORATION
-008099 KLOCKNER MOELLER IPC
-00809A NOVUS NETWORKS LTD
-00809B JUSTSYSTEM CORPORATION
-00809C LUXCOM, INC.
-00809D Commscraft Ltd.
-00809E DATUS GMBH
-00809F ALCATEL BUSINESS SYSTEMS
-0080A0 EDISA HEWLETT PACKARD S/A
-0080A1 MICROTEST, INC.
-0080A2 CREATIVE ELECTRONIC SYSTEMS
-0080A3 LANTRONIX
-0080A4 LIBERTY ELECTRONICS
-0080A5 SPEED INTERNATIONAL
-0080A6 REPUBLIC TECHNOLOGY, INC.
-0080A7 MEASUREX CORP.
-0080A8 VITACOM CORPORATION
-0080A9 CLEARPOINT RESEARCH
-0080AA MAXPEED
-0080AB DUKANE NETWORK INTEGRATION
-0080AC IMLOGIX, DIVISION OF GENESYS
-0080AD CNET TECHNOLOGY, INC.
-0080AE HUGHES NETWORK SYSTEMS
-0080AF ALLUMER CO., LTD.
-0080B0 ADVANCED INFORMATION
-0080B1 SOFTCOM A/S
-0080B2 NETWORK EQUIPMENT TECHNOLOGIES
-0080B3 AVAL DATA CORPORATION
-0080B4 SOPHIA SYSTEMS
-0080B5 UNITED NETWORKS INC.
-0080B6 THEMIS COMPUTER
-0080B7 STELLAR COMPUTER
-0080B8 BUG, INCORPORATED
-0080B9 ARCHE TECHNOLIGIES INC.
-0080BA SPECIALIX (ASIA) PTE, LTD
-0080BB HUGHES LAN SYSTEMS
-0080BC HITACHI ENGINEERING CO., LTD
-0080BD THE FURUKAWA ELECTRIC CO., LTD
-0080BE ARIES RESEARCH
-0080BF TAKAOKA ELECTRIC MFG. CO. LTD.
-0080C0 PENRIL DATACOMM
-0080C1 LANEX CORPORATION
-0080C2 IEEE 802.1 COMMITTEE
-0080C3 BICC INFORMATION SYSTEMS & SVC
-0080C4 DOCUMENT TECHNOLOGIES, INC.
-0080C5 NOVELLCO DE MEXICO
-0080C6 NATIONAL DATACOMM CORPORATION
-0080C7 XIRCOM
-0080C8 D-LINK SYSTEMS, INC.
-0080C9 ALBERTA MICROELECTRONIC CENTRE
-0080CA NETCOM RESEARCH INCORPORATED
-0080CB FALCO DATA PRODUCTS
-0080CC MICROWAVE BYPASS SYSTEMS
-0080CD MICRONICS COMPUTER, INC.
-0080CE BROADCAST TELEVISION SYSTEMS
-0080CF EMBEDDED PERFORMANCE INC.
-0080D0 COMPUTER PERIPHERALS, INC.
-0080D1 KIMTRON CORPORATION
-0080D2 SHINNIHONDENKO CO., LTD.
-0080D3 SHIVA CORP.
-0080D4 CHASE RESEARCH LTD.
-0080D5 CADRE TECHNOLOGIES
-0080D6 NUVOTECH, INC.
-0080D7 Fantum Engineering
-0080D8 NETWORK PERIPHERALS INC.
-0080D9 EMK ELEKTRONIK
-0080DA BRUEL & KJAER
-0080DB GRAPHON CORPORATION
-0080DC PICKER INTERNATIONAL
-0080DD GMX INC/GIMIX
-0080DE GIPSI S.A.
-0080DF ADC CODENOLL TECHNOLOGY CORP.
-0080E0 XTP SYSTEMS, INC.
-0080E1 STMICROELECTRONICS
-0080E2 T.D.I. CO., LTD.
-0080E3 CORAL NETWORK CORPORATION
-0080E4 NORTHWEST DIGITAL SYSTEMS, INC
-0080E5 MYLEX CORPORATION
-0080E6 PEER NETWORKS, INC.
-0080E7 LYNWOOD SCIENTIFIC DEV. LTD.
-0080E8 CUMULUS CORPORATIION
-0080E9 Madge Ltd.
-0080EA ADVA Optical Networking Ltd.
-0080EB COMPCONTROL B.V.
-0080EC SUPERCOMPUTING SOLUTIONS, INC.
-0080ED IQ TECHNOLOGIES, INC.
-0080EE THOMSON CSF
-0080EF RATIONAL
-0080F0 Panasonic Communications Co., Ltd.
-0080F1 OPUS SYSTEMS
-0080F2 RAYCOM SYSTEMS INC
-0080F3 SUN ELECTRONICS CORP.
-0080F4 TELEMECANIQUE ELECTRIQUE
-0080F5 QUANTEL LTD
-0080F6 SYNERGY MICROSYSTEMS
-0080F7 ZENITH ELECTRONICS
-0080F8 MIZAR, INC.
-0080F9 HEURIKON CORPORATION
-0080FA RWT GMBH
-0080FB BVM LIMITED
-0080FC AVATAR CORPORATION
-0080FD EXSCEED CORPRATION
-0080FE AZURE TECHNOLOGIES, INC.
-0080FF SOC. DE TELEINFORMATIQUE RTC
-009000 DIAMOND MULTIMEDIA
-009001 NISHIMU ELECTRONICS INDUSTRIES CO., LTD.
-009002 ALLGON AB
-009003 APLIO
-009004 3COM EUROPE LTD.
-009005 PROTECH SYSTEMS CO., LTD.
-009006 HAMAMATSU PHOTONICS K.K.
-009007 DOMEX TECHNOLOGY CORP.
-009008 HanA Systems Inc.
-009009 i Controls, Inc.
-00900A PROTON ELECTRONIC INDUSTRIAL CO., LTD.
-00900B LANNER ELECTRONICS, INC.
-00900C CISCO SYSTEMS, INC.
-00900D OVERLAND DATA INC.
-00900E HANDLINK TECHNOLOGIES, INC.
-00900F KAWASAKI HEAVY INDUSTRIES, LTD
-009010 SIMULATION LABORATORIES, INC.
-009011 WAVTrace, Inc.
-009012 GLOBESPAN SEMICONDUCTOR, INC.
-009013 SAMSAN CORP.
-009014 ROTORK INSTRUMENTS, LTD.
-009015 CENTIGRAM COMMUNICATIONS CORP.
-009016 ZAC
-009017 ZYPCOM, INC.
-009018 ITO ELECTRIC INDUSTRY CO, LTD.
-009019 HERMES ELECTRONICS CO., LTD.
-00901A UNISPHERE SOLUTIONS
-00901B DIGITAL CONTROLS
-00901C mps Software Gmbh
-00901D PEC (NZ) LTD.
-00901E SELESTA INGEGNE RIA S.P.A.
-00901F ADTEC PRODUCTIONS, INC.
-009020 PHILIPS ANALYTICAL X-RAY B.V.
-009021 CISCO SYSTEMS, INC.
-009022 IVEX
-009023 ZILOG INC.
-009024 PIPELINKS, INC.
-009025 VISION SYSTEMS LTD. PTY
-009026 ADVANCED SWITCHING COMMUNICATIONS, INC.
-009027 INTEL CORPORATION
-009028 NIPPON SIGNAL CO., LTD.
-009029 CRYPTO AG
-00902A COMMUNICATION DEVICES, INC.
-00902B CISCO SYSTEMS, INC.
-00902C DATA & CONTROL EQUIPMENT LTD.
-00902D DATA ELECTRONICS (AUST.) PTY, LTD.
-00902E NAMCO LIMITED
-00902F NETCORE SYSTEMS, INC.
-009030 HONEYWELL-DATING
-009031 MYSTICOM, LTD.
-009032 PELCOMBE GROUP LTD.
-009033 INNOVAPHONE GmbH
-009034 IMAGIC, INC.
-009035 ALPHA TELECOM, INC.
-009036 ens, inc.
-009037 ACUCOMM, INC.
-009038 FOUNTAIN TECHNOLOGIES, INC.
-009039 SHASTA NETWORKS
-00903A NIHON MEDIA TOOL INC.
-00903B TriEMS Research Lab, Inc.
-00903C ATLANTIC NETWORK SYSTEMS
-00903D BIOPAC SYSTEMS, INC.
-00903E N.V. PHILIPS INDUSTRIAL ACTIVITIES
-00903F AZTEC RADIOMEDIA
-009040 Siemens Network Convergence LLC
-009041 APPLIED DIGITAL ACCESS
-009042 ECCS, Inc.
-009043 NICHIBEI DENSHI CO., LTD.
-009044 ASSURED DIGITAL, INC.
-009045 Marconi Communications
-009046 DEXDYNE, LTD.
-009047 GIGA FAST E. LTD.
-009048 ZEAL CORPORATION
-009049 ENTRIDIA CORPORATION
-00904A CONCUR SYSTEM TECHNOLOGIES
-00904B GemTek Technology Co., Ltd.
-00904C EPIGRAM, INC.
-00904D SPEC S.A.
-00904E DELEM BV
-00904F ABB POWER T&D COMPANY, INC.
-009050 TELESTE OY
-009051 ULTIMATE TECHNOLOGY CORP.
-009052 SELCOM ELETTRONICA S.R.L.
-009053 DAEWOO ELECTRONICS CO., LTD.
-009054 INNOVATIVE SEMICONDUCTORS, INC
-009055 PARKER HANNIFIN CORPORATION COMPUMOTOR DIVISION
-009056 TELESTREAM, INC.
-009057 AANetcom, Inc.
-009058 Ultra Electronics Ltd., Command and Control Systems
-009059 TELECOM DEVICE K.K.
-00905A DEARBORN GROUP, INC.
-00905B RAYMOND AND LAE ENGINEERING
-00905C EDMI
-00905D NETCOM SICHERHEITSTECHNIK GmbH
-00905E RAULAND-BORG CORPORATION
-00905F CISCO SYSTEMS, INC.
-009060 SYSTEM CREATE CORP.
-009061 PACIFIC RESEARCH & ENGINEERING CORPORATION
-009062 ICP VORTEX COMPUTERSYSTEME GmbH
-009063 COHERENT COMMUNICATIONS SYSTEMS CORPORATION
-009064 THOMSON BROADCAST SYSTEMS
-009065 FINISAR CORPORATION
-009066 Troika Networks, Inc.
-009067 WalkAbout Computers, Inc.
-009068 DVT CORP.
-009069 JUNIPER NETWORKS, INC.
-00906A TURNSTONE SYSTEMS, INC.
-00906B APPLIED RESOURCES, INC.
-00906C GWT GLOBAL WEIGHING TECHNOLOGIES GmbH
-00906D CISCO SYSTEMS, INC.
-00906E PRAXON, INC.
-00906F CISCO SYSTEMS, INC.
-009070 NEO NETWORKS, INC.
-009071 Applied Innovation Inc.
-009072 SIMRAD AS
-009073 GAIO TECHNOLOGY
-009074 ARGON NETWORKS, INC.
-009075 NEC DO BRASIL S.A.
-009076 FMT AIRCRAFT GATE SUPPORT SYSTEMS AB
-009077 ADVANCED FIBRE COMMUNICATIONS
-009078 MER TELEMANAGEMENT SOLUTIONS, LTD.
-009079 ClearOne, Inc.
-00907A SPECTRALINK CORP.
-00907B E-TECH, INC.
-00907C DIGITALCAST, INC.
-00907D Lake Communications
-00907E VETRONIX CORP.
-00907F WatchGuard Technologies, Inc.
-009080 NOT LIMITED, INC.
-009081 ALOHA NETWORKS, INC.
-009082 FORCE INSTITUTE
-009083 TURBO COMMUNICATION, INC.
-009084 ATECH SYSTEM
-009085 GOLDEN ENTERPRISES, INC.
-009086 CISCO SYSTEMS, INC.
-009087 ITIS
-009088 BAXALL SECURITY LTD.
-009089 SOFTCOM MICROSYSTEMS, INC.
-00908A BAYLY COMMUNICATIONS, INC.
-00908B CELL COMPUTING, INC.
-00908C ETREND ELECTRONICS, INC.
-00908D VICKERS ELECTRONICS SYSTEMS
-00908E Nortel Networks Broadband Access
-00908F AUDIO CODES LTD.
-009090 I-BUS
-009091 DigitalScape, Inc.
-009092 CISCO SYSTEMS, INC.
-009093 NANAO CORPORATION
-009094 OSPREY TECHNOLOGIES, INC.
-009095 UNIVERSAL AVIONICS
-009096 ASKEY COMPUTER CORP.
-009097 SYCAMORE NETWORKS
-009098 SBC DESIGNS, INC.
-009099 ALLIED TELESIS, K.K.
-00909A ONE WORLD SYSTEMS, INC.
-00909B MARKPOINT AB
-00909C Terayon Communications Systems
-00909D GSE SYSTEMS, INC.
-00909E Critical IO, LLC
-00909F DIGI-DATA CORPORATION
-0090A0 8X8 INC.
-0090A1 FLYING PIG SYSTEMS, LTD.
-0090A2 CYBERTAN TECHNOLOGY, INC.
-0090A3 Corecess Inc.
-0090A4 ALTIGA NETWORKS
-0090A5 SPECTRA LOGIC
-0090A6 CISCO SYSTEMS, INC.
-0090A7 CLIENTEC CORPORATION
-0090A8 NineTiles Networks, Ltd.
-0090A9 WESTERN DIGITAL
-0090AA INDIGO ACTIVE VISION SYSTEMS LIMITED
-0090AB CISCO SYSTEMS, INC.
-0090AC OPTIVISION, INC.
-0090AD ASPECT ELECTRONICS, INC.
-0090AE ITALTEL S.p.A.
-0090AF J. MORITA MFG. CORP.
-0090B0 VADEM
-0090B1 CISCO SYSTEMS, INC.
-0090B2 AVICI SYSTEMS INC.
-0090B3 AGRANAT SYSTEMS
-0090B4 WILLOWBROOK TECHNOLOGIES
-0090B5 NIKON CORPORATION
-0090B6 FIBEX SYSTEMS
-0090B7 DIGITAL LIGHTWAVE, INC.
-0090B8 ROHDE & SCHWARZ GMBH & CO. KG
-0090B9 BERAN INSTRUMENTS LTD.
-0090BA VALID NETWORKS, INC.
-0090BB TAINET COMMUNICATION SYSTEM Corp.
-0090BC TELEMANN CO., LTD.
-0090BD OMNIA COMMUNICATIONS, INC.
-0090BE IBC/INTEGRATED BUSINESS COMPUTERS
-0090BF CISCO SYSTEMS, INC.
-0090C0 K.J. LAW ENGINEERS, INC.
-0090C1 Peco II, Inc.
-0090C2 JK microsystems, Inc.
-0090C3 TOPIC SEMICONDUCTOR CORP.
-0090C4 JAVELIN SYSTEMS, INC.
-0090C5 INTERNET MAGIC, INC.
-0090C6 OPTIM SYSTEMS, INC.
-0090C7 ICOM INC.
-0090C8 WAVERIDER COMMUNICATIONS (CANADA) INC.
-0090C9 DPAC Technologies
-0090CA ACCORD VIDEO TELECOMMUNICATIONS, LTD.
-0090CB Wireless OnLine, Inc.
-0090CC PLANET COMMUNICATIONS, INC.
-0090CD ENT-EMPRESA NACIONAL DE TELECOMMUNICACOES, S.A.
-0090CE TETRA GmbH
-0090CF NORTEL
-0090D0 Thomson Belgium
-0090D1 LEICHU ENTERPRISE CO., LTD.
-0090D2 ARTEL VIDEO SYSTEMS
-0090D3 GIESECKE & DEVRIENT GmbH
-0090D4 BindView Development Corp.
-0090D5 EUPHONIX, INC.
-0090D6 CRYSTAL GROUP
-0090D7 NetBoost Corp.
-0090D8 WHITECROSS SYSTEMS
-0090D9 CISCO SYSTEMS, INC.
-0090DA DYNARC, INC.
-0090DB NEXT LEVEL COMMUNICATIONS
-0090DC TECO INFORMATION SYSTEMS
-0090DD THE MIHARU COMMUNICATIONS CO., LTD.
-0090DE CARDKEY SYSTEMS, INC.
-0090DF MITSUBISHI CHEMICAL AMERICA, INC.
-0090E0 SYSTRAN CORP.
-0090E1 TELENA S.P.A.
-0090E2 DISTRIBUTED PROCESSING TECHNOLOGY
-0090E3 AVEX ELECTRONICS INC.
-0090E4 NEC AMERICA, INC.
-0090E5 TEKNEMA, INC.
-0090E6 ACER LABORATORIES, INC.
-0090E7 HORSCH ELEKTRONIK AG
-0090E8 MOXA TECHNOLOGIES CORP., LTD.
-0090E9 JANZ COMPUTER AG
-0090EA ALPHA TECHNOLOGIES, INC.
-0090EB SENTRY TELECOM SYSTEMS
-0090EC PYRESCOM
-0090ED CENTRAL SYSTEM RESEARCH CO., LTD.
-0090EE PERSONAL COMMUNICATIONS TECHNOLOGIES
-0090EF INTEGRIX, INC.
-0090F0 HARMONIC LIGHTWAVES, LTD.
-0090F1 DOT HILL SYSTEMS CORPORATION
-0090F2 CISCO SYSTEMS, INC.
-0090F3 ASPECT COMMUNICATIONS
-0090F4 LIGHTNING INSTRUMENTATION
-0090F5 CLEVO CO.
-0090F6 ESCALATE NETWORKS, INC.
-0090F7 NBASE COMMUNICATIONS LTD.
-0090F8 MEDIATRIX TELECOM
-0090F9 LEITCH
-0090FA GigaNet, Inc.
-0090FB PORTWELL, INC.
-0090FC NETWORK COMPUTING DEVICES
-0090FD CopperCom, Inc.
-0090FE ELECOM CO., LTD. (LANEED DIV.)
-0090FF TELLUS TECHNOLOGY INC.
-0091D6 Crystal Group, Inc.
-009D8E CARDIAC RECORDERS, INC.
-00A000 CENTILLION NETWORKS, INC.
-00A001 WATKINS-JOHNSON COMPANY
-00A002 LEEDS & NORTHRUP AUSTRALIA PTY LTD
-00A003 STAEFA CONTROL SYSTEM
-00A004 NETPOWER, INC.
-00A005 DANIEL INSTRUMENTS, LTD.
-00A006 IMAGE DATA PROCESSING SYSTEM GROUP
-00A007 APEXX TECHNOLOGY, INC.
-00A008 NETCORP
-00A009 WHITETREE NETWORK
-00A00A R.D.C. COMMUNICATION
-00A00B COMPUTEX CO., LTD.
-00A00C KINGMAX TECHNOLOGY, INC.
-00A00D THE PANDA PROJECT
-00A00E VISUAL NETWORKS, INC.
-00A00F Broadband Technologies
-00A010 SYSLOGIC DATENTECHNIK AG
-00A011 MUTOH INDUSTRIES LTD.
-00A012 B.A.T.M. ADVANCED TECHNOLOGIES
-00A013 TELTREND LTD.
-00A014 CSIR
-00A015 WYLE
-00A016 MICROPOLIS CORP.
-00A017 J B M CORPORATION
-00A018 CREATIVE CONTROLLERS, INC.
-00A019 NEBULA CONSULTANTS, INC.
-00A01A BINAR ELEKTRONIK AB
-00A01B PREMISYS COMMUNICATIONS, INC.
-00A01C NASCENT NETWORKS CORPORATION
-00A01D SIXNET
-00A01E EST CORPORATION
-00A01F TRICORD SYSTEMS, INC.
-00A020 CITICORP/TTI
-00A021 GENERAL DYNAMICS-
-00A022 CENTRE FOR DEVELOPMENT OF ADVANCED COMPUTING
-00A023 APPLIED CREATIVE TECHNOLOGY, INC.
-00A024 3COM CORPORATION
-00A025 REDCOM LABS INC.
-00A026 TELDAT, S.A.
-00A027 FIREPOWER SYSTEMS, INC.
-00A028 CONNER PERIPHERALS
-00A029 COULTER CORPORATION
-00A02A TRANCELL SYSTEMS
-00A02B TRANSITIONS RESEARCH CORP.
-00A02C interWAVE Communications
-00A02D 1394 Trade Association
-00A02E BRAND COMMUNICATIONS, LTD.
-00A02F PIRELLI CAVI
-00A030 CAPTOR NV/SA
-00A031 HAZELTINE CORPORATION, MS 1-17
-00A032 GES SINGAPORE PTE. LTD.
-00A033 imc MeBsysteme GmbH
-00A034 AXEL
-00A035 CYLINK CORPORATION
-00A036 APPLIED NETWORK TECHNOLOGY
-00A037 DATASCOPE CORPORATION
-00A038 EMAIL ELECTRONICS
-00A039 ROSS TECHNOLOGY, INC.
-00A03A KUBOTEK CORPORATION
-00A03B TOSHIN ELECTRIC CO., LTD.
-00A03C EG&G NUCLEAR INSTRUMENTS
-00A03D OPTO-22
-00A03E ATM FORUM
-00A03F COMPUTER SOCIETY MICROPROCESSOR & MICROPROCESSOR STANDARDS C
-00A040 APPLE COMPUTER
-00A041 LEYBOLD-INFICON
-00A042 SPUR PRODUCTS CORP.
-00A043 AMERICAN TECHNOLOGY LABS, INC.
-00A044 NTT IT CO., LTD.
-00A045 PHOENIX CONTACT GMBH & CO.
-00A046 SCITEX CORP. LTD.
-00A047 INTEGRATED FITNESS CORP.
-00A048 QUESTECH, LTD.
-00A049 DIGITECH INDUSTRIES, INC.
-00A04A NISSHIN ELECTRIC CO., LTD.
-00A04B TFL LAN INC.
-00A04C INNOVATIVE SYSTEMS & TECHNOLOGIES, INC.
-00A04D EDA INSTRUMENTS, INC.
-00A04E VOELKER TECHNOLOGIES, INC.
-00A04F AMERITEC CORP.
-00A050 CYPRESS SEMICONDUCTOR
-00A051 ANGIA COMMUNICATIONS. INC.
-00A052 STANILITE ELECTRONICS PTY. LTD
-00A053 COMPACT DEVICES, INC.
-00A055 Data Device Corporation
-00A056 MICROPROSS
-00A057 LANCOM Systems GmbH
-00A058 GLORY, LTD.
-00A059 HAMILTON HALLMARK
-00A05A KOFAX IMAGE PRODUCTS
-00A05B MARQUIP, INC.
-00A05C INVENTORY CONVERSION, INC./
-00A05D CS COMPUTER SYSTEME GmbH
-00A05E MYRIAD LOGIC INC.
-00A05F BTG ENGINEERING BV
-00A060 ACER PERIPHERALS, INC.
-00A061 PURITAN BENNETT
-00A062 AES PRODATA
-00A063 JRL SYSTEMS, INC.
-00A064 KVB/ANALECT
-00A065 NEXLAND, INC.
-00A066 ISA CO., LTD.
-00A067 NETWORK SERVICES GROUP
-00A068 BHP LIMITED
-00A069 Symmetricom, Inc.
-00A06A Verilink Corporation
-00A06B DMS DORSCH MIKROSYSTEM GMBH
-00A06C SHINDENGEN ELECTRIC MFG. CO., LTD.
-00A06D MANNESMANN TALLY CORPORATION
-00A06E AUSTRON, INC.
-00A06F THE APPCON GROUP, INC.
-00A070 COASTCOM
-00A071 VIDEO LOTTERY TECHNOLOGIES,INC
-00A072 OVATION SYSTEMS LTD.
-00A073 COM21, INC.
-00A074 PERCEPTION TECHNOLOGY
-00A075 MICRON TECHNOLOGY, INC.
-00A076 CARDWARE LAB, INC.
-00A077 FUJITSU NEXION, INC.
-00A078 Marconi Communications
-00A079 ALPS ELECTRIC (USA), INC.
-00A07A ADVANCED PERIPHERALS TECHNOLOGIES, INC.
-00A07B DAWN COMPUTER INCORPORATION
-00A07C TONYANG NYLON CO., LTD.
-00A07D SEEQ TECHNOLOGY, INC.
-00A07E AVID TECHNOLOGY, INC.
-00A07F GSM-SYNTEL, LTD.
-00A080 ANTARES MICROSYSTEMS
-00A081 ALCATEL DATA NETWORKS
-00A082 NKT ELEKTRONIK A/S
-00A083 ASIMMPHONY TURKEY
-00A084 DATAPLEX PTY. LTD.
-00A086 AMBER WAVE SYSTEMS, INC.
-00A087 Zarlink Semiconductor Ltd.
-00A088 ESSENTIAL COMMUNICATIONS
-00A089 XPOINT TECHNOLOGIES, INC.
-00A08A BROOKTROUT TECHNOLOGY, INC.
-00A08B ASTON ELECTRONIC DESIGNS LTD.
-00A08C MultiMedia LANs, Inc.
-00A08D JACOMO CORPORATION
-00A08E Nokia Internet Communications
-00A08F DESKNET SYSTEMS, INC.
-00A090 TimeStep Corporation
-00A091 APPLICOM INTERNATIONAL
-00A092 H. BOLLMANN MANUFACTURERS, LTD
-00A093 B/E AEROSPACE, Inc.
-00A094 COMSAT CORPORATION
-00A095 ACACIA NETWORKS, INC.
-00A096 MITUMI ELECTRIC CO., LTD.
-00A097 JC INFORMATION SYSTEMS
-00A098 NETWORK APPLIANCE CORP.
-00A099 K-NET LTD.
-00A09A NIHON KOHDEN AMERICA
-00A09B QPSX COMMUNICATIONS, LTD.
-00A09C Xyplex, Inc.
-00A09D JOHNATHON FREEMAN TECHNOLOGIES
-00A09E ICTV
-00A09F COMMVISION CORP.
-00A0A0 COMPACT DATA, LTD.
-00A0A1 EPIC DATA INC.
-00A0A2 DIGICOM S.P.A.
-00A0A3 RELIABLE POWER METERS
-00A0A4 MICROS SYSTEMS, INC.
-00A0A5 TEKNOR MICROSYSTEME, INC.
-00A0A6 M.I. SYSTEMS, K.K.
-00A0A7 VORAX CORPORATION
-00A0A8 RENEX CORPORATION
-00A0A9 GN NETTEST (CANADA) NAVTEL DIVISION
-00A0AA SPACELABS MEDICAL
-00A0AB NETCS INFORMATIONSTECHNIK GMBH
-00A0AC GILAT SATELLITE NETWORKS, LTD.
-00A0AD MARCONI SPA
-00A0AE NUCOM SYSTEMS, INC.
-00A0AF WMS INDUSTRIES
-00A0B0 I-O DATA DEVICE, INC.
-00A0B1 FIRST VIRTUAL CORPORATION
-00A0B2 SHIMA SEIKI
-00A0B3 ZYKRONIX
-00A0B4 TEXAS MICROSYSTEMS, INC.
-00A0B5 3H TECHNOLOGY
-00A0B6 SANRITZ AUTOMATION CO., LTD.
-00A0B7 CORDANT, INC.
-00A0B8 SYMBIOS LOGIC INC.
-00A0B9 EAGLE TECHNOLOGY, INC.
-00A0BA PATTON ELECTRONICS CO.
-00A0BB HILAN GMBH
-00A0BC VIASAT, INCORPORATED
-00A0BD I-TECH CORP.
-00A0BE INTEGRATED CIRCUIT SYSTEMS, INC. COMMUNICATIONS GROUP
-00A0BF WIRELESS DATA GROUP MOTOROLA
-00A0C0 DIGITAL LINK CORP.
-00A0C1 ORTIVUS MEDICAL AB
-00A0C2 R.A. SYSTEMS CO., LTD.
-00A0C3 UNICOMPUTER GMBH
-00A0C4 CRISTIE ELECTRONICS LTD.
-00A0C5 ZYXEL COMMUNICATION
-00A0C6 QUALCOMM INCORPORATED
-00A0C7 TADIRAN TELECOMMUNICATIONS
-00A0C8 ADTRAN INC.
-00A0C9 INTEL CORPORATION - HF1-06
-00A0CA FUJITSU DENSO LTD.
-00A0CB ARK TELECOMMUNICATIONS, INC.
-00A0CC LITE-ON COMMUNICATIONS, INC.
-00A0CD DR. JOHANNES HEIDENHAIN GmbH
-00A0CE ASTROCOM CORPORATION
-00A0CF SOTAS, INC.
-00A0D0 TEN X TECHNOLOGY, INC.
-00A0D1 INVENTEC CORPORATION
-00A0D2 ALLIED TELESIS INTERNATIONAL CORPORATION
-00A0D3 INSTEM COMPUTER SYSTEMS, LTD.
-00A0D4 RADIOLAN, INC.
-00A0D5 SIERRA WIRELESS INC.
-00A0D6 SBE, INC.
-00A0D7 KASTEN CHASE APPLIED RESEARCH
-00A0D8 SPECTRA - TEK
-00A0D9 CONVEX COMPUTER CORPORATION
-00A0DA INTEGRATED SYSTEMS Technology, Inc.
-00A0DB FISHER & PAYKEL PRODUCTION
-00A0DC O.N. ELECTRONIC CO., LTD.
-00A0DD AZONIX CORPORATION
-00A0DE YAMAHA CORPORATION
-00A0DF STS TECHNOLOGIES, INC.
-00A0E0 TENNYSON TECHNOLOGIES PTY LTD
-00A0E1 WESTPORT RESEARCH ASSOCIATES, INC.
-00A0E2 KEISOKU GIKEN CORP.
-00A0E3 XKL SYSTEMS CORP.
-00A0E4 OPTIQUEST
-00A0E5 NHC COMMUNICATIONS
-00A0E6 DIALOGIC CORPORATION
-00A0E7 CENTRAL DATA CORPORATION
-00A0E8 REUTERS HOLDINGS PLC
-00A0E9 ELECTRONIC RETAILING SYSTEMS INTERNATIONAL
-00A0EA ETHERCOM CORP.
-00A0EB Encore Networks
-00A0EC TRANSMITTON LTD.
-00A0ED PRI AUTOMATION
-00A0EE NASHOBA NETWORKS
-00A0EF LUCIDATA LTD.
-00A0F0 TORONTO MICROELECTRONICS INC.
-00A0F1 MTI
-00A0F2 INFOTEK COMMUNICATIONS, INC.
-00A0F3 STAUBLI
-00A0F4 GE
-00A0F5 RADGUARD LTD.
-00A0F6 AutoGas Systems Inc.
-00A0F7 V.I COMPUTER CORP.
-00A0F8 SYMBOL TECHNOLOGIES, INC.
-00A0F9 BINTEC COMMUNICATIONS GMBH
-00A0FA Marconi Communication GmbH
-00A0FB TORAY ENGINEERING CO., LTD.
-00A0FC IMAGE SCIENCES, INC.
-00A0FD SCITEX DIGITAL PRINTING, INC.
-00A0FE BOSTON TECHNOLOGY, INC.
-00A0FF TELLABS OPERATIONS, INC.
-00AA00 INTEL CORPORATION
-00AA01 INTEL CORPORATION
-00AA02 INTEL CORPORATION
-00AA3C OLIVETTI TELECOM SPA (OLTECO)
-00B009 Grass Valley Group
-00B017 InfoGear Technology Corp.
-00B019 Casi-Rusco
-00B01C Westport Technologies
-00B01E Rantic Labs, Inc.
-00B02A ORSYS GmbH
-00B02D ViaGate Technologies, Inc.
-00B03B HiQ Networks
-00B048 Marconi Communications Inc.
-00B04A Cisco Systems, Inc.
-00B052 Intellon Corporation
-00B064 Cisco Systems, Inc.
-00B069 Honewell Oy
-00B06D Jones Futurex Inc.
-00B080 Mannesmann Ipulsys B.V.
-00B086 LocSoft Limited
-00B08E Cisco Systems, Inc.
-00B091 Transmeta Corp.
-00B094 Alaris, Inc.
-00B09A Morrow Technologies Corp.
-00B09D Point Grey Research Inc.
-00B0AC SIAE-Microelettronica S.p.A.
-00B0AE Symmetricom
-00B0B3 Xstreamis PLC
-00B0C2 Cisco Systems, Inc.
-00B0C7 Tellabs Operations, Inc.
-00B0CE TECHNOLOGY RESCUE
-00B0D0 Dell Computer Corp.
-00B0DB Nextcell, Inc.
-00B0DF Reliable Data Technology, Inc.
-00B0E7 British Federal Ltd.
-00B0EC EACEM
-00B0EE Ajile Systems, Inc.
-00B0F0 CALY NETWORKS
-00B0F5 NetWorth Technologies, Inc.
-00BB01 OCTOTHORPE CORP.
-00BBF0 UNGERMANN-BASS INC.
-00C000 LANOPTICS, LTD.
-00C001 DIATEK PATIENT MANAGMENT
-00C002 SERCOMM CORPORATION
-00C003 GLOBALNET COMMUNICATIONS
-00C004 JAPAN BUSINESS COMPUTER CO.LTD
-00C005 LIVINGSTON ENTERPRISES, INC.
-00C006 NIPPON AVIONICS CO., LTD.
-00C007 PINNACLE DATA SYSTEMS, INC.
-00C008 SECO SRL
-00C009 KT TECHNOLOGY (S) PTE LTD
-00C00A MICRO CRAFT
-00C00B NORCONTROL A.S.
-00C00C RELIA TECHNOLGIES
-00C00D ADVANCED LOGIC RESEARCH, INC.
-00C00E PSITECH, INC.
-00C00F QUANTUM SOFTWARE SYSTEMS LTD.
-00C010 HIRAKAWA HEWTECH CORP.
-00C011 INTERACTIVE COMPUTING DEVICES
-00C012 NETSPAN CORPORATION
-00C013 NETRIX
-00C014 TELEMATICS CALABASAS INT'L,INC
-00C015 NEW MEDIA CORPORATION
-00C016 ELECTRONIC THEATRE CONTROLS
-00C017 FORTE NETWORKS
-00C018 LANART CORPORATION
-00C019 LEAP TECHNOLOGY, INC.
-00C01A COROMETRICS MEDICAL SYSTEMS
-00C01B SOCKET COMMUNICATIONS, INC.
-00C01C INTERLINK COMMUNICATIONS LTD.
-00C01D GRAND JUNCTION NETWORKS, INC.
-00C01E LA FRANCAISE DES JEUX
-00C01F S.E.R.C.E.L.
-00C020 ARCO ELECTRONIC, CONTROL LTD.
-00C021 NETEXPRESS
-00C022 LASERMASTER TECHNOLOGIES, INC.
-00C023 TUTANKHAMON ELECTRONICS
-00C024 EDEN SISTEMAS DE COMPUTACAO SA
-00C025 DATAPRODUCTS CORPORATION
-00C026 LANS TECHNOLOGY CO., LTD.
-00C027 CIPHER SYSTEMS, INC.
-00C028 JASCO CORPORATION
-00C029 Nexans Deutschland AG - ANS
-00C02A OHKURA ELECTRIC CO., LTD.
-00C02B GERLOFF GESELLSCHAFT FUR
-00C02C CENTRUM COMMUNICATIONS, INC.
-00C02D FUJI PHOTO FILM CO., LTD.
-00C02E NETWIZ
-00C02F OKUMA CORPORATION
-00C030 INTEGRATED ENGINEERING B. V.
-00C031 DESIGN RESEARCH SYSTEMS, INC.
-00C032 I-CUBED LIMITED
-00C033 TELEBIT COMMUNICATIONS APS
-00C034 TRANSACTION NETWORK
-00C035 QUINTAR COMPANY
-00C036 RAYTECH ELECTRONIC CORP.
-00C037 DYNATEM
-00C038 RASTER IMAGE PROCESSING SYSTEM
-00C039 TDK SEMICONDUCTOR CORPORATION
-00C03A MEN-MIKRO ELEKTRONIK GMBH
-00C03B MULTIACCESS COMPUTING CORP.
-00C03C TOWER TECH S.R.L.
-00C03D WIESEMANN & THEIS GMBH
-00C03E FA. GEBR. HELLER GMBH
-00C03F STORES AUTOMATED SYSTEMS, INC.
-00C040 ECCI
-00C041 DIGITAL TRANSMISSION SYSTEMS
-00C042 DATALUX CORP.
-00C043 STRATACOM
-00C044 EMCOM CORPORATION
-00C045 ISOLATION SYSTEMS, LTD.
-00C046 KEMITRON LTD.
-00C047 UNIMICRO SYSTEMS, INC.
-00C048 BAY TECHNICAL ASSOCIATES
-00C049 U.S. ROBOTICS, INC.
-00C04A GROUP 2000 AG
-00C04B CREATIVE MICROSYSTEMS
-00C04C DEPARTMENT OF FOREIGN AFFAIRS
-00C04D MITEC, INC.
-00C04E COMTROL CORPORATION
-00C04F DELL COMPUTER CORPORATION
-00C050 TOYO DENKI SEIZO K.K.
-00C051 ADVANCED INTEGRATION RESEARCH
-00C052 BURR-BROWN
-00C053 DAVOX CORPORATION
-00C054 NETWORK PERIPHERALS, LTD.
-00C055 MODULAR COMPUTING TECHNOLOGIES
-00C056 SOMELEC
-00C057 MYCO ELECTRONICS
-00C058 DATAEXPERT CORP.
-00C059 NIPPON DENSO CO., LTD.
-00C05A SEMAPHORE COMMUNICATIONS CORP.
-00C05B NETWORKS NORTHWEST, INC.
-00C05C ELONEX PLC
-00C05D L&N TECHNOLOGIES
-00C05E VARI-LITE, INC.
-00C05F FINE-PAL COMPANY LIMITED
-00C060 ID SCANDINAVIA AS
-00C061 SOLECTEK CORPORATION
-00C062 IMPULSE TECHNOLOGY
-00C063 MORNING STAR TECHNOLOGIES, INC
-00C064 GENERAL DATACOMM IND. INC.
-00C065 SCOPE COMMUNICATIONS, INC.
-00C066 DOCUPOINT, INC.
-00C067 UNITED BARCODE INDUSTRIES
-00C068 PHILIP DRAKE ELECTRONICS LTD.
-00C069 Axxcelera Broadband Wireless
-00C06A ZAHNER-ELEKTRIK GMBH & CO. KG
-00C06B OSI PLUS CORPORATION
-00C06C SVEC COMPUTER CORP.
-00C06D BOCA RESEARCH, INC.
-00C06E HAFT TECHNOLOGY, INC.
-00C06F KOMATSU LTD.
-00C070 SECTRA SECURE-TRANSMISSION AB
-00C071 AREANEX COMMUNICATIONS, INC.
-00C072 KNX LTD.
-00C073 XEDIA CORPORATION
-00C074 TOYODA AUTOMATIC LOOM
-00C075 XANTE CORPORATION
-00C076 I-DATA INTERNATIONAL A-S
-00C077 DAEWOO TELECOM LTD.
-00C078 COMPUTER SYSTEMS ENGINEERING
-00C079 FONSYS CO.,LTD.
-00C07A PRIVA B.V.
-00C07B ASCEND COMMUNICATIONS, INC.
-00C07C HIGHTECH INFORMATION
-00C07D RISC DEVELOPMENTS LTD.
-00C07E KUBOTA CORPORATION ELECTRONIC
-00C07F NUPON COMPUTING CORP.
-00C080 NETSTAR, INC.
-00C081 METRODATA LTD.
-00C082 MOORE PRODUCTS CO.
-00C083 TRACE MOUNTAIN PRODUCTS, INC.
-00C084 DATA LINK CORP. LTD.
-00C085 ELECTRONICS FOR IMAGING, INC.
-00C086 THE LYNK CORPORATION
-00C087 UUNET TECHNOLOGIES, INC.
-00C088 EKF ELEKTRONIK GMBH
-00C089 TELINDUS DISTRIBUTION
-00C08A LAUTERBACH DATENTECHNIK GMBH
-00C08B RISQ MODULAR SYSTEMS, INC.
-00C08C PERFORMANCE TECHNOLOGIES, INC.
-00C08D TRONIX PRODUCT DEVELOPMENT
-00C08E NETWORK INFORMATION TECHNOLOGY
-00C08F MATSUSHITA ELECTRIC WORKS, LTD
-00C090 PRAIM S.R.L.
-00C091 JABIL CIRCUIT, INC.
-00C092 MENNEN MEDICAL INC.
-00C093 ALTA RESEARCH CORP.
-00C094 VMX INC.
-00C095 ZNYX
-00C096 TAMURA CORPORATION
-00C097 ARCHIPEL SA
-00C098 CHUNTEX ELECTRONIC CO., LTD.
-00C099 YOSHIKI INDUSTRIAL CO.,LTD.
-00C09A PHOTONICS CORPORATION
-00C09B RELIANCE COMM/TEC, R-TEC
-00C09C TOA ELECTRONIC LTD.
-00C09D DISTRIBUTED SYSTEMS INT'L, INC
-00C09E CACHE COMPUTERS, INC.
-00C09F QUANTA COMPUTER, INC.
-00C0A0 ADVANCE MICRO RESEARCH, INC.
-00C0A1 TOKYO DENSHI SEKEI CO.
-00C0A2 INTERMEDIUM A/S
-00C0A3 DUAL ENTERPRISES CORPORATION
-00C0A4 UNIGRAF OY
-00C0A5 DICKENS DATA SYSTEMS
-00C0A6 EXICOM AUSTRALIA PTY. LTD
-00C0A7 SEEL LTD.
-00C0A8 GVC CORPORATION
-00C0A9 BARRON MCCANN LTD.
-00C0AA SILICON VALLEY COMPUTER
-00C0AB Telco Systems, Inc.
-00C0AC GAMBIT COMPUTER COMMUNICATIONS
-00C0AD MARBEN COMMUNICATION SYSTEMS
-00C0AE TOWERCOM CO. INC. DBA PC HOUSE
-00C0AF TEKLOGIX INC.
-00C0B0 GCC TECHNOLOGIES,INC.
-00C0B1 GENIUS NET CO.
-00C0B2 NORAND CORPORATION
-00C0B3 COMSTAT DATACOMM CORPORATION
-00C0B4 MYSON TECHNOLOGY, INC.
-00C0B5 CORPORATE NETWORK SYSTEMS,INC.
-00C0B6 Snap Appliance, Inc.
-00C0B7 AMERICAN POWER CONVERSION CORP
-00C0B8 FRASER'S HILL LTD.
-00C0B9 FUNK SOFTWARE, INC.
-00C0BA NETVANTAGE
-00C0BB FORVAL CREATIVE, INC.
-00C0BC TELECOM AUSTRALIA/CSSC
-00C0BD INEX TECHNOLOGIES, INC.
-00C0BE ALCATEL - SEL
-00C0BF TECHNOLOGY CONCEPTS, LTD.
-00C0C0 SHORE MICROSYSTEMS, INC.
-00C0C1 QUAD/GRAPHICS, INC.
-00C0C2 INFINITE NETWORKS LTD.
-00C0C3 ACUSON COMPUTED SONOGRAPHY
-00C0C4 COMPUTER OPERATIONAL
-00C0C5 SID INFORMATICA
-00C0C6 PERSONAL MEDIA CORP.
-00C0C7 SPARKTRUM MICROSYSTEMS, INC.
-00C0C8 MICRO BYTE PTY. LTD.
-00C0C9 ELSAG BAILEY PROCESS
-00C0CA ALFA, INC.
-00C0CB CONTROL TECHNOLOGY CORPORATION
-00C0CC TELESCIENCES CO SYSTEMS, INC.
-00C0CD COMELTA, S.A.
-00C0CE CEI SYSTEMS & ENGINEERING PTE
-00C0CF IMATRAN VOIMA OY
-00C0D0 RATOC SYSTEM INC.
-00C0D1 COMTREE TECHNOLOGY CORPORATION
-00C0D2 SYNTELLECT, INC.
-00C0D3 OLYMPUS IMAGE SYSTEMS, INC.
-00C0D4 AXON NETWORKS, INC.
-00C0D5 QUANCOM ELECTRONIC GMBH
-00C0D6 J1 SYSTEMS, INC.
-00C0D7 TAIWAN TRADING CENTER DBA
-00C0D8 UNIVERSAL DATA SYSTEMS
-00C0D9 QUINTE NETWORK CONFIDENTIALITY
-00C0DA NICE SYSTEMS LTD.
-00C0DB IPC CORPORATION (PTE) LTD.
-00C0DC EOS TECHNOLOGIES, INC.
-00C0DD QLogic Corporation
-00C0DE ZCOMM, INC.
-00C0DF KYE Systems Corp.
-00C0E0 DSC COMMUNICATION CORP.
-00C0E1 SONIC SOLUTIONS
-00C0E2 CALCOMP, INC.
-00C0E3 OSITECH COMMUNICATIONS, INC.
-00C0E4 SIEMENS BUILDING
-00C0E5 GESPAC, S.A.
-00C0E6 Verilink Corporation
-00C0E7 FIBERDATA AB
-00C0E8 PLEXCOM, INC.
-00C0E9 OAK SOLUTIONS, LTD.
-00C0EA ARRAY TECHNOLOGY LTD.
-00C0EB SEH COMPUTERTECHNIK GMBH
-00C0EC DAUPHIN TECHNOLOGY
-00C0ED US ARMY ELECTRONIC
-00C0EE KYOCERA CORPORATION
-00C0EF ABIT CORPORATION
-00C0F0 KINGSTON TECHNOLOGY CORP.
-00C0F1 SHINKO ELECTRIC CO., LTD.
-00C0F2 TRANSITION NETWORKS
-00C0F3 NETWORK COMMUNICATIONS CORP.
-00C0F4 INTERLINK SYSTEM CO., LTD.
-00C0F5 METACOMP, INC.
-00C0F6 CELAN TECHNOLOGY INC.
-00C0F7 ENGAGE COMMUNICATION, INC.
-00C0F8 ABOUT COMPUTING INC.
-00C0F9 HARRIS AND JEFFRIES, INC.
-00C0FA CANARY COMMUNICATIONS, INC.
-00C0FB ADVANCED TECHNOLOGY LABS
-00C0FC ELASTIC REALITY, INC.
-00C0FD PROSUM
-00C0FE APTEC COMPUTER SYSTEMS, INC.
-00C0FF DOT HILL SYSTEMS CORPORATION
-00CBBD Cambridge Broadband Ltd.
-00CF1C COMMUNICATION MACHINERY CORP.
-00D000 FERRAN SCIENTIFIC, INC.
-00D001 VST TECHNOLOGIES, INC.
-00D002 DITECH CORPORATION
-00D003 COMDA ENTERPRISES CORP.
-00D004 PENTACOM LTD.
-00D005 ZHS ZEITMANAGEMENTSYSTEME
-00D006 CISCO SYSTEMS, INC.
-00D007 MIC ASSOCIATES, INC.
-00D008 MACTELL CORPORATION
-00D009 HSING TECH. ENTERPRISE CO. LTD
-00D00A LANACCESS TELECOM S.A.
-00D00B RHK TECHNOLOGY, INC.
-00D00C SNIJDER MICRO SYSTEMS
-00D00D MICROMERITICS INSTRUMENT
-00D00E PLURIS, INC.
-00D00F SPEECH DESIGN GMBH
-00D010 CONVERGENT NETWORKS, INC.
-00D011 PRISM VIDEO, INC.
-00D012 GATEWORKS CORP.
-00D013 PRIMEX AEROSPACE COMPANY
-00D014 ROOT, INC.
-00D015 UNIVEX MICROTECHNOLOGY CORP.
-00D016 SCM MICROSYSTEMS, INC.
-00D017 SYNTECH INFORMATION CO., LTD.
-00D018 QWES. COM, INC.
-00D019 DAINIPPON SCREEN CORPORATE
-00D01A URMET SUD S.P.A.
-00D01B MIMAKI ENGINEERING CO., LTD.
-00D01C SBS TECHNOLOGIES,
-00D01D FURUNO ELECTRIC CO., LTD.
-00D01E PINGTEL CORP.
-00D01F CTAM PTY. LTD.
-00D020 AIM SYSTEM, INC.
-00D021 REGENT ELECTRONICS CORP.
-00D022 INCREDIBLE TECHNOLOGIES, INC.
-00D023 INFORTREND TECHNOLOGY, INC.
-00D024 Cognex Corporation
-00D025 XROSSTECH, INC.
-00D026 HIRSCHMANN AUSTRIA GMBH
-00D027 APPLIED AUTOMATION, INC.
-00D028 OMNEON VIDEO NETWORKS
-00D029 WAKEFERN FOOD CORPORATION
-00D02A Voxent Systems Ltd.
-00D02B JETCELL, INC.
-00D02C CAMPBELL SCIENTIFIC, INC.
-00D02D ADEMCO
-00D02E COMMUNICATION AUTOMATION CORP.
-00D02F VLSI TECHNOLOGY INC.
-00D030 SAFETRAN SYSTEMS CORP.
-00D031 INDUSTRIAL LOGIC CORPORATION
-00D032 YANO ELECTRIC CO., LTD.
-00D033 DALIAN DAXIAN NETWORK
-00D034 ORMEC SYSTEMS CORP.
-00D035 BEHAVIOR TECH. COMPUTER CORP.
-00D036 TECHNOLOGY ATLANTA CORP.
-00D037 PHILIPS-DVS-LO BDR
-00D038 FIVEMERE, LTD.
-00D039 UTILICOM, INC.
-00D03A ZONEWORX, INC.
-00D03B VISION PRODUCTS PTY. LTD.
-00D03C Vieo, Inc.
-00D03D GALILEO TECHNOLOGY, LTD.
-00D03E ROCKETCHIPS, INC.
-00D03F AMERICAN COMMUNICATION
-00D040 SYSMATE CO., LTD.
-00D041 AMIGO TECHNOLOGY CO., LTD.
-00D042 MAHLO GMBH & CO. UG
-00D043 ZONAL RETAIL DATA SYSTEMS
-00D044 ALIDIAN NETWORKS, INC.
-00D045 KVASER AB
-00D046 DOLBY LABORATORIES, INC.
-00D047 XN TECHNOLOGIES
-00D048 ECTON, INC.
-00D049 IMPRESSTEK CO., LTD.
-00D04A PRESENCE TECHNOLOGY GMBH
-00D04B LA CIE GROUP S.A.
-00D04C EUROTEL TELECOM LTD.
-00D04D DIV OF RESEARCH & STATISTICS
-00D04E LOGIBAG
-00D04F BITRONICS, INC.
-00D050 ISKRATEL
-00D051 O2 MICRO, INC.
-00D052 ASCEND COMMUNICATIONS, INC.
-00D053 CONNECTED SYSTEMS
-00D054 SAS INSTITUTE INC.
-00D055 KATHREIN-WERKE KG
-00D056 SOMAT CORPORATION
-00D057 ULTRAK, INC.
-00D058 CISCO SYSTEMS, INC.
-00D059 AMBIT MICROSYSTEMS CORP.
-00D05A SYMBIONICS, LTD.
-00D05B ACROLOOP MOTION CONTROL
-00D05C TECHNOTREND SYSTEMTECHNIK GMBH
-00D05D INTELLIWORXX, INC.
-00D05E STRATABEAM TECHNOLOGY, INC.
-00D05F VALCOM, INC.
-00D060 PANASONIC EUROPEAN
-00D061 TREMON ENTERPRISES CO., LTD.
-00D062 DIGIGRAM
-00D063 CISCO SYSTEMS, INC.
-00D064 MULTITEL
-00D065 TOKO ELECTRIC
-00D066 WINTRISS ENGINEERING CORP.
-00D067 CAMPIO COMMUNICATIONS
-00D068 IWILL CORPORATION
-00D069 TECHNOLOGIC SYSTEMS
-00D06A LINKUP SYSTEMS CORPORATION
-00D06B SR TELECOM INC.
-00D06C SHAREWAVE, INC.
-00D06D ACRISON, INC.
-00D06E TRENDVIEW RECORDERS LTD.
-00D06F KMC CONTROLS
-00D070 LONG WELL ELECTRONICS CORP.
-00D071 ECHELON CORP.
-00D072 BROADLOGIC
-00D073 ACN ADVANCED COMMUNICATIONS
-00D074 TAQUA SYSTEMS, INC.
-00D075 ALARIS MEDICAL SYSTEMS, INC.
-00D076 MERRILL LYNCH & CO., INC.
-00D077 LUCENT TECHNOLOGIES
-00D078 ELTEX OF SWEDEN AB
-00D079 CISCO SYSTEMS, INC.
-00D07A AMAQUEST COMPUTER CORP.
-00D07B COMCAM INTERNATIONAL LTD.
-00D07C KOYO ELECTRONICS INC. CO.,LTD.
-00D07D COSINE COMMUNICATIONS
-00D07E KEYCORP LTD.
-00D07F STRATEGY & TECHNOLOGY, LIMITED
-00D080 EXABYTE CORPORATION
-00D081 REAL TIME DEVICES USA, INC.
-00D082 IOWAVE INC.
-00D083 INVERTEX, INC.
-00D084 NEXCOMM SYSTEMS, INC.
-00D085 OTIS ELEVATOR COMPANY
-00D086 FOVEON, INC.
-00D087 MICROFIRST INC.
-00D088 Terayon Communications Systems
-00D089 DYNACOLOR, INC.
-00D08A PHOTRON USA
-00D08B ADVA Limited
-00D08C GENOA TECHNOLOGY, INC.
-00D08D PHOENIX GROUP, INC.
-00D08E NVISION INC.
-00D08F ARDENT TECHNOLOGIES, INC.
-00D090 CISCO SYSTEMS, INC.
-00D091 SMARTSAN SYSTEMS, INC.
-00D092 GLENAYRE WESTERN MULTIPLEX
-00D093 TQ - COMPONENTS GMBH
-00D094 TIMELINE VISTA, INC.
-00D095 XYLAN CORPORATION
-00D096 3COM EUROPE LTD.
-00D097 CISCO SYSTEMS, INC.
-00D098 Photon Dynamics Canada Inc.
-00D099 ELCARD OY
-00D09A FILANET CORPORATION
-00D09B SPECTEL LTD.
-00D09C KAPADIA COMMUNICATIONS
-00D09D VERIS INDUSTRIES
-00D09E 2WIRE, INC.
-00D09F NOVTEK TEST SYSTEMS
-00D0A0 MIPS DENMARK
-00D0A1 OSKAR VIERLING GMBH + CO. KG
-00D0A2 INTEGRATED DEVICE
-00D0A3 VOCAL DATA, INC.
-00D0A4 ALANTRO COMMUNICATIONS
-00D0A5 AMERICAN ARIUM
-00D0A6 LANBIRD TECHNOLOGY CO., LTD.
-00D0A7 TOKYO SOKKI KENKYUJO CO., LTD.
-00D0A8 NETWORK ENGINES, INC.
-00D0A9 SHINANO KENSHI CO., LTD.
-00D0AA CHASE COMMUNICATIONS
-00D0AB DELTAKABEL TELECOM CV
-00D0AC GRAYSON WIRELESS
-00D0AD TL INDUSTRIES
-00D0AE ORESIS COMMUNICATIONS, INC.
-00D0AF CUTLER-HAMMER, INC.
-00D0B0 BITSWITCH LTD.
-00D0B1 OMEGA ELECTRONICS SA
-00D0B2 XIOTECH CORPORATION
-00D0B3 DRS FLIGHT SAFETY AND
-00D0B4 KATSUJIMA CO., LTD.
-00D0B5 IPricot formerly DotCom
-00D0B6 CRESCENT NETWORKS, INC.
-00D0B7 INTEL CORPORATION
-00D0B8 IOMEGA CORP.
-00D0B9 MICROTEK INTERNATIONAL, INC.
-00D0BA CISCO SYSTEMS, INC.
-00D0BB CISCO SYSTEMS, INC.
-00D0BC CISCO SYSTEMS, INC.
-00D0BD SICAN GMBH
-00D0BE EMUTEC INC.
-00D0BF PIVOTAL TECHNOLOGIES
-00D0C0 CISCO SYSTEMS, INC.
-00D0C1 HARMONIC DATA SYSTEMS, LTD.
-00D0C2 BALTHAZAR TECHNOLOGY AB
-00D0C3 VIVID TECHNOLOGY PTE, LTD.
-00D0C4 TERATECH CORPORATION
-00D0C5 COMPUTATIONAL SYSTEMS, INC.
-00D0C6 THOMAS & BETTS CORP.
-00D0C7 PATHWAY, INC.
-00D0C8 I/O CONSULTING A/S
-00D0C9 ADVANTECH CO., LTD.
-00D0CA INTRINSYC SOFTWARE INC.
-00D0CB DASAN CO., LTD.
-00D0CC TECHNOLOGIES LYRE INC.
-00D0CD ATAN TECHNOLOGY INC.
-00D0CE ASYST ELECTRONIC
-00D0CF MORETON BAY
-00D0D0 ZHONGXING TELECOM LTD.
-00D0D1 SIROCCO SYSTEMS, INC.
-00D0D2 EPILOG CORPORATION
-00D0D3 CISCO SYSTEMS, INC.
-00D0D4 V-BITS, INC.
-00D0D5 GRUNDIG AG
-00D0D6 AETHRA TELECOMUNICAZIONI
-00D0D7 B2C2, INC.
-00D0D8 3Com Corporation
-00D0D9 DEDICATED MICROCOMPUTERS
-00D0DA TAICOM DATA SYSTEMS CO., LTD.
-00D0DB MCQUAY INTERNATIONAL
-00D0DC MODULAR MINING SYSTEMS, INC.
-00D0DD SUNRISE TELECOM, INC.
-00D0DE PHILIPS MULTIMEDIA NETWORK
-00D0DF KUZUMI ELECTRONICS, INC.
-00D0E0 DOOIN ELECTRONICS CO.
-00D0E1 AVIONITEK ISRAEL INC.
-00D0E2 MRT MICRO, INC.
-00D0E3 ELE-CHEM ENGINEERING CO., LTD.
-00D0E4 CISCO SYSTEMS, INC.
-00D0E5 SOLIDUM SYSTEMS CORP.
-00D0E6 IBOND INC.
-00D0E7 VCON TELECOMMUNICATION LTD.
-00D0E8 MAC SYSTEM CO., LTD.
-00D0E9 ADVANTAGE CENTURY
-00D0EA NEXTONE COMMUNICATIONS, INC.
-00D0EB LIGHTERA NETWORKS, INC.
-00D0EC NAKAYO TELECOMMUNICATIONS, INC
-00D0ED XIOX
-00D0EE DICTAPHONE CORPORATION
-00D0EF IGT
-00D0F0 CONVISION TECHNOLOGY GMBH
-00D0F1 SEGA ENTERPRISES, LTD.
-00D0F2 MONTEREY NETWORKS
-00D0F3 SOLARI DI UDINE SPA
-00D0F4 CARINTHIAN TECH INSTITUTE
-00D0F5 ORANGE MICRO, INC.
-00D0F6 Alcatel Canada
-00D0F7 NEXT NETS CORPORATION
-00D0F8 FUJIAN STAR TERMINAL
-00D0F9 ACUTE COMMUNICATIONS CORP.
-00D0FA RACAL GUARDATA
-00D0FB TEK MICROSYSTEMS, INCORPORATED
-00D0FC GRANITE MICROSYSTEMS
-00D0FD OPTIMA TELE.COM, INC.
-00D0FE ASTRAL POINT
-00D0FF CISCO SYSTEMS, INC.
-00DD00 UNGERMANN-BASS INC.
-00DD01 UNGERMANN-BASS INC.
-00DD02 UNGERMANN-BASS INC.
-00DD03 UNGERMANN-BASS INC.
-00DD04 UNGERMANN-BASS INC.
-00DD05 UNGERMANN-BASS INC.
-00DD06 UNGERMANN-BASS INC.
-00DD07 UNGERMANN-BASS INC.
-00DD08 UNGERMANN-BASS INC.
-00DD09 UNGERMANN-BASS INC.
-00DD0A UNGERMANN-BASS INC.
-00DD0B UNGERMANN-BASS INC.
-00DD0C UNGERMANN-BASS INC.
-00DD0D UNGERMANN-BASS INC.
-00DD0E UNGERMANN-BASS INC.
-00DD0F UNGERMANN-BASS INC.
-00E000 FUJITSU, LTD
-00E001 STRAND LIGHTING LIMITED
-00E002 CROSSROADS SYSTEMS, INC.
-00E003 NOKIA WIRELESS BUSINESS COMMUN
-00E004 PMC-SIERRA, INC.
-00E005 TECHNICAL CORP.
-00E006 SILICON INTEGRATED SYS. CORP.
-00E007 NETWORK ALCHEMY LTD.
-00E008 AMAZING CONTROLS! INC.
-00E009 MARATHON TECHNOLOGIES CORP.
-00E00A DIBA, INC.
-00E00B ROOFTOP COMMUNICATIONS CORP.
-00E00C MOTOROLA
-00E00D RADIANT SYSTEMS
-00E00E AVALON IMAGING SYSTEMS, INC.
-00E00F SHANGHAI BAUD DATA
-00E010 HESS SB-AUTOMATENBAU GmbH
-00E011 UNIDEN SAN DIEGO R&D CENTER, INC.
-00E012 PLUTO TECHNOLOGIES INTERNATIONAL INC.
-00E013 EASTERN ELECTRONIC CO., LTD.
-00E014 CISCO SYSTEMS, INC.
-00E015 HEIWA CORPORATION
-00E016 RAPID CITY COMMUNICATIONS
-00E017 EXXACT GmbH
-00E018 ASUSTEK COMPUTER INC.
-00E019 ING. GIORDANO ELETTRONICA
-00E01A COMTEC SYSTEMS. CO., LTD.
-00E01B SPHERE COMMUNICATIONS, INC.
-00E01C MOBILITY ELECTRONICSY
-00E01D WebTV NETWORKS, INC.
-00E01E CISCO SYSTEMS, INC.
-00E01F AVIDIA Systems, Inc.
-00E020 TECNOMEN OY
-00E021 FREEGATE CORP.
-00E022 MediaLight, Inc.
-00E023 TELRAD
-00E024 GADZOOX NETWORKS
-00E025 dit CO., LTD.
-00E026 EASTMAN KODAK CO.
-00E027 DUX, INC.
-00E028 APTIX CORPORATION
-00E029 STANDARD MICROSYSTEMS CORP.
-00E02A TANDBERG TELEVISION AS
-00E02B EXTREME NETWORKS
-00E02C AST COMPUTER
-00E02D InnoMediaLogic, Inc.
-00E02E SPC ELECTRONICS CORPORATION
-00E02F MCNS HOLDINGS, L.P.
-00E030 MELITA INTERNATIONAL CORP.
-00E031 HAGIWARA ELECTRIC CO., LTD.
-00E032 MISYS FINANCIAL SYSTEMS, LTD.
-00E033 E.E.P.D. GmbH
-00E034 CISCO SYSTEMS, INC.
-00E035 LOUGHBOROUGH SOUND IMAGES, PLC
-00E036 PIONEER CORPORATION
-00E037 CENTURY CORPORATION
-00E038 PROXIMA CORPORATION
-00E039 PARADYNE CORP.
-00E03A CABLETRON SYSTEMS, INC.
-00E03B PROMINET CORPORATION
-00E03C AdvanSys
-00E03D FOCON ELECTRONIC SYSTEMS A/S
-00E03E ALFATECH, INC.
-00E03F JATON CORPORATION
-00E040 DeskStation Technology, Inc.
-00E041 CSPI
-00E042 Pacom Systems Ltd.
-00E043 VitalCom
-00E044 LSICS CORPORATION
-00E045 TOUCHWAVE, INC.
-00E046 BENTLY NEVADA CORP.
-00E047 INFOCUS SYSTEMS
-00E048 SDL COMMUNICATIONS, INC.
-00E049 MICROWI ELECTRONIC GmbH
-00E04A ENHANCED MESSAGING SYSTEMS, INC
-00E04B JUMP INDUSTRIELLE COMPUTERTECHNIK GmbH
-00E04C REALTEK SEMICONDUCTOR CORP.
-00E04D INTERNET INITIATIVE JAPAN, INC
-00E04E SANYO DENKI CO., LTD.
-00E04F CISCO SYSTEMS, INC.
-00E050 EXECUTONE INFORMATION SYSTEMS, INC.
-00E051 TALX CORPORATION
-00E052 FOUNDRY NETWORKS, INC.
-00E053 CELLPORT LABS, INC.
-00E054 KODAI HITEC CO., LTD.
-00E055 INGENIERIA ELECTRONICA COMERCIAL INELCOM S.A.
-00E056 HOLONTECH CORPORATION
-00E057 HAN MICROTELECOM. CO., LTD.
-00E058 PHASE ONE DENMARK A/S
-00E059 CONTROLLED ENVIRONMENTS, LTD.
-00E05A GALEA NETWORK SECURITY
-00E05B WEST END SYSTEMS CORP.
-00E05C MATSUSHITA KOTOBUKI ELECTRONICS INDUSTRIES, LTD.
-00E05D UNITEC CO., LTD.
-00E05E JAPAN AVIATION ELECTRONICS INDUSTRY, LTD.
-00E05F e-Net, Inc.
-00E060 SHERWOOD
-00E061 EdgePoint Networks, Inc.
-00E062 HOST ENGINEERING
-00E063 CABLETRON - YAGO SYSTEMS, INC.
-00E064 SAMSUNG ELECTRONICS
-00E065 OPTICAL ACCESS INTERNATIONAL
-00E066 ProMax Systems, Inc.
-00E067 eac AUTOMATION-CONSULTING GmbH
-00E068 MERRIMAC SYSTEMS INC.
-00E069 JAYCOR
-00E06A KAPSCH AG
-00E06B W&G SPECIAL PRODUCTS
-00E06C AEP Systems International Ltd
-00E06D COMPUWARE CORPORATION
-00E06E FAR SYSTEMS S.p.A.
-00E06F Terayon Communications Systems
-00E070 DH TECHNOLOGY
-00E071 EPIS MICROCOMPUTER
-00E072 LYNK
-00E073 NATIONAL AMUSEMENT NETWORK, INC.
-00E074 TIERNAN COMMUNICATIONS, INC.
-00E075 Verilink Corporation
-00E076 DEVELOPMENT CONCEPTS, INC.
-00E077 WEBGEAR, INC.
-00E078 BERKELEY NETWORKS
-00E079 A.T.N.R.
-00E07A MIKRODIDAKT AB
-00E07B BAY NETWORKS
-00E07C METTLER-TOLEDO, INC.
-00E07D NETRONIX, INC.
-00E07E WALT DISNEY IMAGINEERING
-00E07F LOGISTISTEM s.r.l.
-00E080 CONTROL RESOURCES CORPORATION
-00E081 TYAN COMPUTER CORP.
-00E082 ANERMA
-00E083 JATO TECHNOLOGIES, INC.
-00E084 COMPULITE R&D
-00E085 GLOBAL MAINTECH, INC.
-00E086 CYBEX COMPUTER PRODUCTS
-00E087 LeCroy - Networking Productions Division
-00E088 LTX CORPORATION
-00E089 ION Networks, Inc.
-00E08A GEC AVERY, LTD.
-00E08B QLogic Corp.
-00E08C NEOPARADIGM LABS, INC.
-00E08D PRESSURE SYSTEMS, INC.
-00E08E UTSTARCOM
-00E08F CISCO SYSTEMS, INC.
-00E090 BECKMAN LAB. AUTOMATION DIV.
-00E091 LG ELECTRONICS, INC.
-00E092 ADMTEK INCORPORATED
-00E093 ACKFIN NETWORKS
-00E094 OSAI SRL
-00E095 ADVANCED-VISION TECHNOLGIES CORP.
-00E096 SHIMADZU CORPORATION
-00E097 CARRIER ACCESS CORPORATION
-00E098 AboCom Systems, Inc.
-00E099 SAMSON AG
-00E09A POSITRON INDUSTRIES, INC.
-00E09B ENGAGE NETWORKS, INC.
-00E09C MII
-00E09D SARNOFF CORPORATION
-00E09E QUANTUM CORPORATION
-00E09F PIXEL VISION
-00E0A0 WILTRON CO.
-00E0A1 HIMA PAUL HILDEBRANDT GmbH Co. KG
-00E0A2 MICROSLATE INC.
-00E0A3 CISCO SYSTEMS, INC.
-00E0A4 ESAOTE S.p.A.
-00E0A5 ComCore Semiconductor, Inc.
-00E0A6 TELOGY NETWORKS, INC.
-00E0A7 IPC INFORMATION SYSTEMS, INC.
-00E0A8 SAT GmbH & Co.
-00E0A9 FUNAI ELECTRIC CO., LTD.
-00E0AA ELECTROSONIC LTD.
-00E0AB DIMAT S.A.
-00E0AC MIDSCO, INC.
-00E0AD EES TECHNOLOGY, LTD.
-00E0AE XAQTI CORPORATION
-00E0AF GENERAL DYNAMICS INFORMATION SYSTEMS
-00E0B0 CISCO SYSTEMS, INC.
-00E0B1 PACKET ENGINES, INC.
-00E0B2 TELMAX COMMUNICATIONS CORP.
-00E0B3 EtherWAN Systems, Inc.
-00E0B4 TECHNO SCOPE CO., LTD.
-00E0B5 ARDENT COMMUNICATIONS CORP.
-00E0B6 Entrada Networks
-00E0B7 PI GROUP, LTD.
-00E0B8 GATEWAY 2000
-00E0B9 BYAS SYSTEMS
-00E0BA BERGHOF AUTOMATIONSTECHNIK GmbH
-00E0BB NBX CORPORATION
-00E0BC SYMON COMMUNICATIONS, INC.
-00E0BD INTERFACE SYSTEMS, INC.
-00E0BE GENROCO INTERNATIONAL, INC.
-00E0BF TORRENT NETWORKING TECHNOLOGIES CORP.
-00E0C0 SEIWA ELECTRIC MFG. CO., LTD.
-00E0C1 MEMOREX TELEX JAPAN, LTD.
-00E0C2 NECSY S.p.A.
-00E0C3 SAKAI SYSTEM DEVELOPMENT CORP.
-00E0C4 HORNER ELECTRIC, INC.
-00E0C5 BCOM ELECTRONICS INC.
-00E0C6 LINK2IT, L.L.C.
-00E0C7 EUROTECH SRL
-00E0C8 VIRTUAL ACCESS, LTD.
-00E0C9 AutomatedLogic Corporation
-00E0CA BEST DATA PRODUCTS
-00E0CB RESON, INC.
-00E0CC HERO SYSTEMS, LTD.
-00E0CD SENSIS CORPORATION
-00E0CE ARN
-00E0CF INTEGRATED DEVICE TECHNOLOGY, INC.
-00E0D0 NETSPEED, INC.
-00E0D1 TELSIS LIMITED
-00E0D2 VERSANET COMMUNICATIONS, INC.
-00E0D3 DATENTECHNIK GmbH
-00E0D4 EXCELLENT COMPUTER
-00E0D5 ARCXEL TECHNOLOGIES, INC.
-00E0D6 COMPUTER & COMMUNICATION RESEARCH LAB.
-00E0D7 SUNSHINE ELECTRONICS, INC.
-00E0D8 LANBit Computer, Inc.
-00E0D9 TAZMO CO., LTD.
-00E0DA ASSURED ACCESS TECHNOLOGY, INC.
-00E0DB ViaVideo Communications, Inc.
-00E0DC NEXWARE CORP.
-00E0DD ZENITH ELECTRONICS CORPORATION
-00E0DE DATAX NV
-00E0DF KE KOMMUNIKATIONS-ELECTRONIK
-00E0E0 SI ELECTRONICS, LTD.
-00E0E1 G2 NETWORKS, INC.
-00E0E2 INNOVA CORP.
-00E0E3 SK-ELEKTRONIK GmbH
-00E0E4 FANUC ROBOTICS NORTH AMERICA, Inc.
-00E0E5 CINCO NETWORKS, INC.
-00E0E6 INCAA DATACOM B.V.
-00E0E7 RAYTHEON E-SYSTEMS, INC.
-00E0E8 GRETACODER Data Systems AG
-00E0E9 DATA LABS, INC.
-00E0EA INNOVAT COMMUNICATIONS, INC.
-00E0EB DIGICOM SYSTEMS, INCORPORATED
-00E0EC CELESTICA INC.
-00E0ED SILICOM, LTD.
-00E0EE MAREL HF
-00E0EF DIONEX
-00E0F0 ABLER TECHNOLOGY, INC.
-00E0F1 THAT CORPORATION
-00E0F2 ARLOTTO COMNET, INC.
-00E0F3 WebSprint Communications, Inc.
-00E0F4 INSIDE Technology A/S
-00E0F5 TELES AG
-00E0F6 DECISION EUROPE
-00E0F7 CISCO SYSTEMS, INC.
-00E0F8 DICNA CONTROL AB
-00E0F9 CISCO SYSTEMS, INC.
-00E0FA TRL TECHNOLOGY, LTD.
-00E0FB LEIGHTRONIX, INC.
-00E0FC HUAWEI TECHNOLOGIES CO., LTD.
-00E0FD A-TREND TECHNOLOGY CO., LTD.
-00E0FE CISCO SYSTEMS, INC.
-00E0FF SECURITY DYNAMICS TECHNOLOGIES, Inc.
-00E6D3 NIXDORF COMPUTER CORP.
-020701 RACAL-DATACOM
-021C7C PERQ SYSTEMS CORPORATION
-026086 LOGIC REPLACEMENT TECH. LTD.
-02608C 3COM CORPORATION
-027001 RACAL-DATACOM
-0270B0 M/A-COM INC. COMPANIES
-0270B3 DATA RECALL LTD
-029D8E CARDIAC RECORDERS INC.
-02AA3C OLIVETTI TELECOMM SPA (OLTECO)
-02BB01 OCTOTHORPE CORP.
-02C08C 3COM CORPORATION
-02CF1C COMMUNICATION MACHINERY CORP.
-02E6D3 NIXDORF COMPUTER CORPORATION
-040AE0 XMIT AG COMPUTER NETWORKS
-04E0C4 TRIUMPH-ADLER AG
-080001 COMPUTERVISION CORPORATION
-080002 BRIDGE COMMUNICATIONS INC.
-080003 ADVANCED COMPUTER COMM.
-080004 CROMEMCO INCORPORATED
-080005 SYMBOLICS INC.
-080006 SIEMENS AG
-080007 APPLE COMPUTER INC.
-080008 BOLT BERANEK AND NEWMAN INC.
-080009 HEWLETT PACKARD
-08000A NESTAR SYSTEMS INCORPORATED
-08000B UNISYS CORPORATION
-08000C MIKLYN DEVELOPMENT CO.
-08000D INTERNATIONAL COMPUTERS LTD.
-08000E NCR CORPORATION
-08000F MITEL CORPORATION
-080011 TEKTRONIX INC.
-080012 BELL ATLANTIC INTEGRATED SYST.
-080013 EXXON
-080014 EXCELAN
-080015 STC BUSINESS SYSTEMS
-080016 BARRISTER INFO SYS CORP
-080017 NATIONAL SEMICONDUCTOR
-080018 PIRELLI FOCOM NETWORKS
-080019 GENERAL ELECTRIC CORPORATION
-08001A TIARA/ 10NET
-08001B DATA GENERAL
-08001C KDD-KOKUSAI DEBNSIN DENWA CO.
-08001D ABLE COMMUNICATIONS INC.
-08001E APOLLO COMPUTER INC.
-08001F SHARP CORPORATION
-080020 SUN MICROSYSTEMS INC.
-080021 3M COMPANY
-080022 NBI INC.
-080023 Panasonic Communications Co., Ltd.
-080024 10NET COMMUNICATIONS/DCA
-080025 CONTROL DATA
-080026 NORSK DATA A.S.
-080027 CADMUS COMPUTER SYSTEMS
-080028 Texas Instruments
-080029 MEGATEK CORPORATION
-08002A MOSAIC TECHNOLOGIES INC.
-08002B DIGITAL EQUIPMENT CORPORATION
-08002C BRITTON LEE INC.
-08002D LAN-TEC INC.
-08002E METAPHOR COMPUTER SYSTEMS
-08002F PRIME COMPUTER INC.
-080030 NETWORK RESEARCH CORPORATION
-080030 CERN
-080030 ROYAL MELBOURNE INST OF TECH
-080031 LITTLE MACHINES INC.
-080032 TIGAN INCORPORATED
-080033 BAUSCH & LOMB
-080034 FILENET CORPORATION
-080035 MICROFIVE CORPORATION
-080036 INTERGRAPH CORPORATION
-080037 FUJI-XEROX CO. LTD.
-080038 CII HONEYWELL BULL
-080039 SPIDER SYSTEMS LIMITED
-08003A ORCATECH INC.
-08003B TORUS SYSTEMS LIMITED
-08003C SCHLUMBERGER WELL SERVICES
-08003D CADNETIX CORPORATIONS
-08003E CODEX CORPORATION
-08003F FRED KOSCHARA ENTERPRISES
-080040 FERRANTI COMPUTER SYS. LIMITED
-080041 RACAL-MILGO INFORMATION SYS..
-080042 JAPAN MACNICS CORP.
-080043 PIXEL COMPUTER INC.
-080044 DAVID SYSTEMS INC.
-080045 CONCURRENT COMPUTER CORP.
-080046 SONY CORPORATION LTD.
-080047 SEQUENT COMPUTER SYSTEMS INC.
-080048 EUROTHERM GAUGING SYSTEMS
-080049 UNIVATION
-08004A BANYAN SYSTEMS INC.
-08004B PLANNING RESEARCH CORP.
-08004C HYDRA COMPUTER SYSTEMS INC.
-08004D CORVUS SYSTEMS INC.
-08004E 3COM EUROPE LTD.
-08004F CYGNET SYSTEMS
-080050 DAISY SYSTEMS CORP.
-080051 EXPERDATA
-080052 INSYSTEC
-080053 MIDDLE EAST TECH. UNIVERSITY
-080055 STANFORD TELECOMM. INC.
-080056 STANFORD LINEAR ACCEL. CENTER
-080057 EVANS & SUTHERLAND
-080058 SYSTEMS CONCEPTS
-080059 A/S MYCRON
-08005A IBM CORPORATION
-08005B VTA TECHNOLOGIES INC.
-08005C FOUR PHASE SYSTEMS
-08005D GOULD INC.
-08005E COUNTERPOINT COMPUTER INC.
-08005F SABER TECHNOLOGY CORP.
-080060 INDUSTRIAL NETWORKING INC.
-080061 JAROGATE LTD.
-080062 GENERAL DYNAMICS
-080063 PLESSEY
-080064 AUTOPHON AG
-080065 GENRAD INC.
-080066 AGFA CORPORATION
-080067 COMDESIGN
-080068 RIDGE COMPUTERS
-080069 SILICON GRAPHICS INC.
-08006A ATT BELL LABORATORIES
-08006B ACCEL TECHNOLOGIES INC.
-08006C SUNTEK TECHNOLOGY INT'L
-08006D WHITECHAPEL COMPUTER WORKS
-08006E MASSCOMP
-08006F PHILIPS APELDOORN B.V.
-080070 MITSUBISHI ELECTRIC CORP.
-080071 MATRA (DSIE)
-080072 XEROX CORP UNIV GRANT PROGRAM
-080073 TECMAR INC.
-080074 CASIO COMPUTER CO. LTD.
-080075 DANSK DATA ELECTRONIK
-080076 PC LAN TECHNOLOGIES
-080077 TSL COMMUNICATIONS LTD.
-080078 ACCELL CORPORATION
-080079 THE DROID WORKS
-08007A INDATA
-08007B SANYO ELECTRIC CO. LTD.
-08007C VITALINK COMMUNICATIONS CORP.
-08007E AMALGAMATED WIRELESS(AUS) LTD
-08007F CARNEGIE-MELLON UNIVERSITY
-080080 AES DATA INC.
-080081 ,ASTECH INC.
-080082 VERITAS SOFTWARE
-080083 Seiko Instruments Inc.
-080084 TOMEN ELECTRONICS CORP.
-080085 ELXSI
-080086 KONICA MINOLTA HOLDINGS, INC.
-080087 XYPLEX
-080088 MCDATA CORPORATION
-080089 KINETICS
-08008A PERFORMANCE TECHNOLOGY
-08008B PYRAMID TECHNOLOGY CORP.
-08008C NETWORK RESEARCH CORPORATION
-08008D XYVISION INC.
-08008E TANDEM COMPUTERS
-08008F CHIPCOM CORPORATION
-080090 SONOMA SYSTEMS
-081443 UNIBRAIN S.A.
-08BBCC AK-NORD EDV VERTRIEBSGES. mbH
-10005A IBM CORPORATION
-1000E8 NATIONAL SEMICONDUCTOR
-800010 ATT BELL LABORATORIES
-A06A00 Verilink Corporation
-AA0000 DIGITAL EQUIPMENT CORPORATION
-AA0001 DIGITAL EQUIPMENT CORPORATION
-AA0002 DIGITAL EQUIPMENT CORPORATION
-AA0003 DIGITAL EQUIPMENT CORPORATION
-AA0004 DIGITAL EQUIPMENT CORPORATION
diff --git a/drivers/ieee1394/oui2c.sh b/drivers/ieee1394/oui2c.sh
deleted file mode 100644
index b9d0e8f10ab..00000000000
--- a/drivers/ieee1394/oui2c.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-cat <<EOF
-/* Generated file for OUI database */
-
-
-#ifdef CONFIG_IEEE1394_OUI_DB
-struct oui_list_struct {
- int oui;
- char *name;
-} oui_list[] = {
-EOF
-
-while read oui name; do
- echo " { 0x$oui, \"$name\" },"
-done
-
-cat <<EOF
-};
-
-#endif /* CONFIG_IEEE1394_OUI_DB */
-EOF
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index 13a617917bf..fbb7f14ec50 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -1485,7 +1485,7 @@ static int __devinit add_card(struct pci_dev *dev,
}
- i2c_bit_del_bus(i2c_ad);
+ i2c_del_adapter(i2c_ad);
kfree(i2c_ad);
}
}
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index ad2108f27a0..a77a832828c 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -636,27 +636,32 @@ static int state_initialized(struct file_info *fi, struct pending_request *req)
case RAW1394_REQ_SET_CARD:
spin_lock_irqsave(&host_info_lock, flags);
- if (req->req.misc < host_count) {
- list_for_each_entry(hi, &host_info_list, list) {
- if (!req->req.misc--)
- break;
- }
- get_device(&hi->host->device); // XXX Need to handle failure case
- list_add_tail(&fi->list, &hi->file_info_list);
- fi->host = hi->host;
- fi->state = connected;
-
- req->req.error = RAW1394_ERROR_NONE;
- req->req.generation = get_hpsb_generation(fi->host);
- req->req.misc = (fi->host->node_id << 16)
- | fi->host->node_count;
- if (fi->protocol_version > 3) {
- req->req.misc |=
- NODEID_TO_NODE(fi->host->irm_id) << 8;
- }
- } else {
+ if (req->req.misc >= host_count) {
req->req.error = RAW1394_ERROR_INVALID_ARG;
+ goto out_set_card;
}
+ list_for_each_entry(hi, &host_info_list, list)
+ if (!req->req.misc--)
+ break;
+ get_device(&hi->host->device); /* FIXME handle failure case */
+ list_add_tail(&fi->list, &hi->file_info_list);
+
+ /* prevent unloading of the host's low-level driver */
+ if (!try_module_get(hi->host->driver->owner)) {
+ req->req.error = RAW1394_ERROR_ABORTED;
+ goto out_set_card;
+ }
+ WARN_ON(fi->host);
+ fi->host = hi->host;
+ fi->state = connected;
+
+ req->req.error = RAW1394_ERROR_NONE;
+ req->req.generation = get_hpsb_generation(fi->host);
+ req->req.misc = (fi->host->node_id << 16)
+ | fi->host->node_count;
+ if (fi->protocol_version > 3)
+ req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
+out_set_card:
spin_unlock_irqrestore(&host_info_lock, flags);
req->req.length = 0;
@@ -2955,6 +2960,11 @@ static int raw1394_release(struct inode *inode, struct file *file)
put_device(&fi->host->device);
}
+ spin_lock_irqsave(&host_info_lock, flags);
+ if (fi->host)
+ module_put(fi->host->driver->owner);
+ spin_unlock_irqrestore(&host_info_lock, flags);
+
kfree(fi);
return 0;
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index e68b80b7340..4edfff46b1e 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -51,7 +51,6 @@
* Grep for inline FIXME comments below.
*/
-#include <linux/blkdev.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -304,10 +303,11 @@ static struct scsi_host_template sbp2_shost_template = {
.use_clustering = ENABLE_CLUSTERING,
.cmd_per_lun = SBP2_MAX_CMDS,
.can_queue = SBP2_MAX_CMDS,
- .emulated = 1,
.sdev_attrs = sbp2_sysfs_sdev_attrs,
};
+/* for match-all entries in sbp2_workarounds_table */
+#define SBP2_ROM_VALUE_WILDCARD 0x1000000
/*
* List of devices with known bugs.
@@ -329,22 +329,14 @@ static const struct {
},
/* Initio bridges, actually only needed for some older ones */ {
.firmware_revision = 0x000200,
+ .model_id = SBP2_ROM_VALUE_WILDCARD,
.workarounds = SBP2_WORKAROUND_INQUIRY_36,
},
/* Symbios bridge */ {
.firmware_revision = 0xa0b800,
+ .model_id = SBP2_ROM_VALUE_WILDCARD,
.workarounds = SBP2_WORKAROUND_128K_MAX_TRANS,
},
- /*
- * Note about the following Apple iPod blacklist entries:
- *
- * There are iPods (2nd gen, 3rd gen) with model_id==0. Since our
- * matching logic treats 0 as a wildcard, we cannot match this ID
- * without rewriting the matching routine. Fortunately these iPods
- * do not feature the read_capacity bug according to one report.
- * Read_capacity behaviour as well as model_id could change due to
- * Apple-supplied firmware updates though.
- */
/* iPod 4th generation */ {
.firmware_revision = 0x0a2700,
.model_id = 0x000021,
@@ -490,11 +482,11 @@ static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
return -ENOMEM;
}
- cmd->command_orb_dma = dma_map_single(&hi->host->device,
+ cmd->command_orb_dma = dma_map_single(hi->host->device.parent,
&cmd->command_orb,
sizeof(struct sbp2_command_orb),
DMA_TO_DEVICE);
- cmd->sge_dma = dma_map_single(&hi->host->device,
+ cmd->sge_dma = dma_map_single(hi->host->device.parent,
&cmd->scatter_gather_element,
sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL);
@@ -516,10 +508,11 @@ static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu)
if (!list_empty(&lu->cmd_orb_completed))
list_for_each_safe(lh, next, &lu->cmd_orb_completed) {
cmd = list_entry(lh, struct sbp2_command_info, list);
- dma_unmap_single(&host->device, cmd->command_orb_dma,
+ dma_unmap_single(host->device.parent,
+ cmd->command_orb_dma,
sizeof(struct sbp2_command_orb),
DMA_TO_DEVICE);
- dma_unmap_single(&host->device, cmd->sge_dma,
+ dma_unmap_single(host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL);
kfree(cmd);
@@ -601,17 +594,17 @@ static void sbp2util_mark_command_completed(struct sbp2_lu *lu,
if (cmd->cmd_dma) {
if (cmd->dma_type == CMD_DMA_SINGLE)
- dma_unmap_single(&host->device, cmd->cmd_dma,
+ dma_unmap_single(host->device.parent, cmd->cmd_dma,
cmd->dma_size, cmd->dma_dir);
else if (cmd->dma_type == CMD_DMA_PAGE)
- dma_unmap_page(&host->device, cmd->cmd_dma,
+ dma_unmap_page(host->device.parent, cmd->cmd_dma,
cmd->dma_size, cmd->dma_dir);
/* XXX: Check for CMD_DMA_NONE bug */
cmd->dma_type = CMD_DMA_NONE;
cmd->cmd_dma = 0;
}
if (cmd->sge_buffer) {
- dma_unmap_sg(&host->device, cmd->sge_buffer,
+ dma_unmap_sg(host->device.parent, cmd->sge_buffer,
cmd->dma_size, cmd->dma_dir);
cmd->sge_buffer = NULL;
}
@@ -836,37 +829,37 @@ static int sbp2_start_device(struct sbp2_lu *lu)
struct sbp2_fwhost_info *hi = lu->hi;
int error;
- lu->login_response = dma_alloc_coherent(&hi->host->device,
+ lu->login_response = dma_alloc_coherent(hi->host->device.parent,
sizeof(struct sbp2_login_response),
&lu->login_response_dma, GFP_KERNEL);
if (!lu->login_response)
goto alloc_fail;
- lu->query_logins_orb = dma_alloc_coherent(&hi->host->device,
+ lu->query_logins_orb = dma_alloc_coherent(hi->host->device.parent,
sizeof(struct sbp2_query_logins_orb),
&lu->query_logins_orb_dma, GFP_KERNEL);
if (!lu->query_logins_orb)
goto alloc_fail;
- lu->query_logins_response = dma_alloc_coherent(&hi->host->device,
+ lu->query_logins_response = dma_alloc_coherent(hi->host->device.parent,
sizeof(struct sbp2_query_logins_response),
&lu->query_logins_response_dma, GFP_KERNEL);
if (!lu->query_logins_response)
goto alloc_fail;
- lu->reconnect_orb = dma_alloc_coherent(&hi->host->device,
+ lu->reconnect_orb = dma_alloc_coherent(hi->host->device.parent,
sizeof(struct sbp2_reconnect_orb),
&lu->reconnect_orb_dma, GFP_KERNEL);
if (!lu->reconnect_orb)
goto alloc_fail;
- lu->logout_orb = dma_alloc_coherent(&hi->host->device,
+ lu->logout_orb = dma_alloc_coherent(hi->host->device.parent,
sizeof(struct sbp2_logout_orb),
&lu->logout_orb_dma, GFP_KERNEL);
if (!lu->logout_orb)
goto alloc_fail;
- lu->login_orb = dma_alloc_coherent(&hi->host->device,
+ lu->login_orb = dma_alloc_coherent(hi->host->device.parent,
sizeof(struct sbp2_login_orb),
&lu->login_orb_dma, GFP_KERNEL);
if (!lu->login_orb)
@@ -929,32 +922,32 @@ static void sbp2_remove_device(struct sbp2_lu *lu)
list_del(&lu->lu_list);
if (lu->login_response)
- dma_free_coherent(&hi->host->device,
+ dma_free_coherent(hi->host->device.parent,
sizeof(struct sbp2_login_response),
lu->login_response,
lu->login_response_dma);
if (lu->login_orb)
- dma_free_coherent(&hi->host->device,
+ dma_free_coherent(hi->host->device.parent,
sizeof(struct sbp2_login_orb),
lu->login_orb,
lu->login_orb_dma);
if (lu->reconnect_orb)
- dma_free_coherent(&hi->host->device,
+ dma_free_coherent(hi->host->device.parent,
sizeof(struct sbp2_reconnect_orb),
lu->reconnect_orb,
lu->reconnect_orb_dma);
if (lu->logout_orb)
- dma_free_coherent(&hi->host->device,
+ dma_free_coherent(hi->host->device.parent,
sizeof(struct sbp2_logout_orb),
lu->logout_orb,
lu->logout_orb_dma);
if (lu->query_logins_orb)
- dma_free_coherent(&hi->host->device,
+ dma_free_coherent(hi->host->device.parent,
sizeof(struct sbp2_query_logins_orb),
lu->query_logins_orb,
lu->query_logins_orb_dma);
if (lu->query_logins_response)
- dma_free_coherent(&hi->host->device,
+ dma_free_coherent(hi->host->device.parent,
sizeof(struct sbp2_query_logins_response),
lu->query_logins_response,
lu->query_logins_response_dma);
@@ -1306,11 +1299,13 @@ static void sbp2_parse_unit_directory(struct sbp2_lu *lu,
if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
- if (sbp2_workarounds_table[i].firmware_revision &&
+ if (sbp2_workarounds_table[i].firmware_revision !=
+ SBP2_ROM_VALUE_WILDCARD &&
sbp2_workarounds_table[i].firmware_revision !=
(firmware_revision & 0xffff00))
continue;
- if (sbp2_workarounds_table[i].model_id &&
+ if (sbp2_workarounds_table[i].model_id !=
+ SBP2_ROM_VALUE_WILDCARD &&
sbp2_workarounds_table[i].model_id != ud->model_id)
continue;
workarounds |= sbp2_workarounds_table[i].workarounds;
@@ -1445,7 +1440,7 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
cmd->dma_size = sgpnt[0].length;
cmd->dma_type = CMD_DMA_PAGE;
- cmd->cmd_dma = dma_map_page(&hi->host->device,
+ cmd->cmd_dma = dma_map_page(hi->host->device.parent,
sgpnt[0].page, sgpnt[0].offset,
cmd->dma_size, cmd->dma_dir);
@@ -1457,8 +1452,8 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
&cmd->scatter_gather_element[0];
u32 sg_count, sg_len;
dma_addr_t sg_addr;
- int i, count = dma_map_sg(&hi->host->device, sgpnt, scsi_use_sg,
- dma_dir);
+ int i, count = dma_map_sg(hi->host->device.parent, sgpnt,
+ scsi_use_sg, dma_dir);
cmd->dma_size = scsi_use_sg;
cmd->sge_buffer = sgpnt;
@@ -1508,7 +1503,8 @@ static void sbp2_prep_command_orb_no_sg(struct sbp2_command_orb *orb,
cmd->dma_dir = dma_dir;
cmd->dma_size = scsi_request_bufflen;
cmd->dma_type = CMD_DMA_SINGLE;
- cmd->cmd_dma = dma_map_single(&hi->host->device, scsi_request_buffer,
+ cmd->cmd_dma = dma_map_single(hi->host->device.parent,
+ scsi_request_buffer,
cmd->dma_size, cmd->dma_dir);
orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
orb->misc |= ORB_SET_DIRECTION(orb_direction);
@@ -1626,10 +1622,11 @@ static void sbp2_link_orb_command(struct sbp2_lu *lu,
size_t length;
unsigned long flags;
- dma_sync_single_for_device(&hi->host->device, cmd->command_orb_dma,
+ dma_sync_single_for_device(hi->host->device.parent,
+ cmd->command_orb_dma,
sizeof(struct sbp2_command_orb),
DMA_TO_DEVICE);
- dma_sync_single_for_device(&hi->host->device, cmd->sge_dma,
+ dma_sync_single_for_device(hi->host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL);
@@ -1655,14 +1652,15 @@ static void sbp2_link_orb_command(struct sbp2_lu *lu,
* The target's fetch agent may or may not have read this
* previous ORB yet.
*/
- dma_sync_single_for_cpu(&hi->host->device, last_orb_dma,
+ dma_sync_single_for_cpu(hi->host->device.parent, last_orb_dma,
sizeof(struct sbp2_command_orb),
DMA_TO_DEVICE);
last_orb->next_ORB_lo = cpu_to_be32(cmd->command_orb_dma);
wmb();
/* Tells hardware that this pointer is valid */
last_orb->next_ORB_hi = 0;
- dma_sync_single_for_device(&hi->host->device, last_orb_dma,
+ dma_sync_single_for_device(hi->host->device.parent,
+ last_orb_dma,
sizeof(struct sbp2_command_orb),
DMA_TO_DEVICE);
addr += SBP2_DOORBELL_OFFSET;
@@ -1790,10 +1788,11 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
else
cmd = sbp2util_find_command_for_orb(lu, sb->ORB_offset_lo);
if (cmd) {
- dma_sync_single_for_cpu(&hi->host->device, cmd->command_orb_dma,
+ dma_sync_single_for_cpu(hi->host->device.parent,
+ cmd->command_orb_dma,
sizeof(struct sbp2_command_orb),
DMA_TO_DEVICE);
- dma_sync_single_for_cpu(&hi->host->device, cmd->sge_dma,
+ dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL);
/* Grab SCSI command pointers and check status. */
@@ -1882,16 +1881,6 @@ static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt,
if (unlikely(SCpnt->device->lun))
goto done;
- /* handle the request sense command here (auto-request sense) */
- if (SCpnt->cmnd[0] == REQUEST_SENSE) {
- memcpy(SCpnt->request_buffer, SCpnt->sense_buffer,
- SCpnt->request_bufflen);
- memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
- sbp2scsi_complete_command(lu, SBP2_SCSI_STATUS_GOOD, SCpnt,
- done);
- return 0;
- }
-
if (unlikely(!hpsb_node_entry_valid(lu->ne))) {
SBP2_ERR("Bus reset in progress - rejecting command");
result = DID_BUS_BUSY << 16;
@@ -1931,10 +1920,11 @@ static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status)
while (!list_empty(&lu->cmd_orb_inuse)) {
lh = lu->cmd_orb_inuse.next;
cmd = list_entry(lh, struct sbp2_command_info, list);
- dma_sync_single_for_cpu(&hi->host->device, cmd->command_orb_dma,
+ dma_sync_single_for_cpu(hi->host->device.parent,
+ cmd->command_orb_dma,
sizeof(struct sbp2_command_orb),
DMA_TO_DEVICE);
- dma_sync_single_for_cpu(&hi->host->device, cmd->sge_dma,
+ dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL);
sbp2util_mark_command_completed(lu, cmd);
@@ -2021,9 +2011,10 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev)
{
struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
- blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
sdev->use_10_for_rw = 1;
+ if (sdev->type == TYPE_ROM)
+ sdev->use_10_for_ms = 1;
if (sdev->type == TYPE_DISK &&
lu->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
sdev->skip_ms_page_8 = 1;
@@ -2059,11 +2050,12 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
spin_lock_irqsave(&lu->cmd_orb_lock, flags);
cmd = sbp2util_find_command_for_SCpnt(lu, SCpnt);
if (cmd) {
- dma_sync_single_for_cpu(&hi->host->device,
+ dma_sync_single_for_cpu(hi->host->device.parent,
cmd->command_orb_dma,
sizeof(struct sbp2_command_orb),
DMA_TO_DEVICE);
- dma_sync_single_for_cpu(&hi->host->device, cmd->sge_dma,
+ dma_sync_single_for_cpu(hi->host->device.parent,
+ cmd->sge_dma,
sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL);
sbp2util_mark_command_completed(lu, cmd);
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index 598b19fc598..f4d1ec00af6 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -489,6 +489,9 @@ static void wakeup_dma_ir_ctx(unsigned long l)
reset_ir_status(d, i);
d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]);
+ dma_region_sync_for_cpu(&d->dma,
+ d->buffer_prg_assignment[i] * d->buf_size,
+ d->buf_size);
}
}
@@ -1096,6 +1099,8 @@ static long video1394_ioctl(struct file *file,
DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d",
d->ctx);
put_timestamp(ohci, d, d->last_buffer);
+ dma_region_sync_for_device(&d->dma,
+ v.buffer * d->buf_size, d->buf_size);
/* Tell the controller where the first program is */
reg_write(ohci, d->cmdPtr,
@@ -1111,6 +1116,9 @@ static long video1394_ioctl(struct file *file,
"Waking up iso transmit dma ctx=%d",
d->ctx);
put_timestamp(ohci, d, d->last_buffer);
+ dma_region_sync_for_device(&d->dma,
+ v.buffer * d->buf_size, d->buf_size);
+
reg_write(ohci, d->ctrlSet, 0x1000);
}
}
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index 163d991eb8c..50fb1cd447b 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -1,9 +1,11 @@
infiniband-$(CONFIG_INFINIBAND_ADDR_TRANS) := ib_addr.o rdma_cm.o
+user_access-$(CONFIG_INFINIBAND_ADDR_TRANS) := rdma_ucm.o
obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \
ib_cm.o iw_cm.o $(infiniband-y)
obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o
-obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o
+obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o \
+ $(user_access-y)
ib_core-y := packer.o ud_header.o verbs.o sysfs.o \
device.o fmr_pool.o cache.o
@@ -18,6 +20,8 @@ iw_cm-y := iwcm.o
rdma_cm-y := cma.o
+rdma_ucm-y := ucma.o
+
ib_addr-y := addr.o
ib_umad-y := user_mad.o
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index af939796750..d2bb5a9a303 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -360,8 +360,7 @@ static int netevent_callback(struct notifier_block *self, unsigned long event,
if (event == NETEVENT_NEIGH_UPDATE) {
struct neighbour *neigh = ctx;
- if (neigh->dev->type == ARPHRD_INFINIBAND &&
- (neigh->nud_state & NUD_VALID)) {
+ if (neigh->nud_state & NUD_VALID) {
set_timeout(jiffies);
}
}
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 79c937bf696..d446998b12a 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -3289,6 +3289,10 @@ static int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv,
spin_lock_irqsave(&cm_id_priv->lock, flags);
switch (cm_id_priv->id.state) {
+ /* Allow transition to RTS before sending REP */
+ case IB_CM_REQ_RCVD:
+ case IB_CM_MRA_REQ_SENT:
+
case IB_CM_REP_RCVD:
case IB_CM_MRA_REP_SENT:
case IB_CM_REP_SENT:
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 985a6b564d8..9e0ab048c87 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -70,6 +70,7 @@ static DEFINE_MUTEX(lock);
static struct workqueue_struct *cma_wq;
static DEFINE_IDR(sdp_ps);
static DEFINE_IDR(tcp_ps);
+static DEFINE_IDR(udp_ps);
struct cma_device {
struct list_head list;
@@ -133,7 +134,6 @@ struct rdma_id_private {
u32 seq_num;
u32 qp_num;
- enum ib_qp_type qp_type;
u8 srq;
};
@@ -392,7 +392,6 @@ int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
id->qp = qp;
id_priv->qp_num = qp->qp_num;
- id_priv->qp_type = qp->qp_type;
id_priv->srq = (qp->srq != NULL);
return 0;
err:
@@ -510,9 +509,17 @@ static inline int cma_any_addr(struct sockaddr *addr)
return cma_zero_addr(addr) || cma_loopback_addr(addr);
}
+static inline __be16 cma_port(struct sockaddr *addr)
+{
+ if (addr->sa_family == AF_INET)
+ return ((struct sockaddr_in *) addr)->sin_port;
+ else
+ return ((struct sockaddr_in6 *) addr)->sin6_port;
+}
+
static inline int cma_any_port(struct sockaddr *addr)
{
- return !((struct sockaddr_in *) addr)->sin_port;
+ return !cma_port(addr);
}
static int cma_get_net_info(void *hdr, enum rdma_port_space ps,
@@ -594,20 +601,6 @@ static inline int cma_user_data_offset(enum rdma_port_space ps)
}
}
-static int cma_notify_user(struct rdma_id_private *id_priv,
- enum rdma_cm_event_type type, int status,
- void *data, u8 data_len)
-{
- struct rdma_cm_event event;
-
- event.event = type;
- event.status = status;
- event.private_data = data;
- event.private_data_len = data_len;
-
- return id_priv->id.event_handler(&id_priv->id, &event);
-}
-
static void cma_cancel_route(struct rdma_id_private *id_priv)
{
switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
@@ -776,63 +769,61 @@ static int cma_verify_rep(struct rdma_id_private *id_priv, void *data)
return 0;
}
-static int cma_rtu_recv(struct rdma_id_private *id_priv)
+static void cma_set_rep_event_data(struct rdma_cm_event *event,
+ struct ib_cm_rep_event_param *rep_data,
+ void *private_data)
{
- int ret;
-
- ret = cma_modify_qp_rts(&id_priv->id);
- if (ret)
- goto reject;
-
- return 0;
-reject:
- cma_modify_qp_err(&id_priv->id);
- ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED,
- NULL, 0, NULL, 0);
- return ret;
+ event->param.conn.private_data = private_data;
+ event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE;
+ event->param.conn.responder_resources = rep_data->responder_resources;
+ event->param.conn.initiator_depth = rep_data->initiator_depth;
+ event->param.conn.flow_control = rep_data->flow_control;
+ event->param.conn.rnr_retry_count = rep_data->rnr_retry_count;
+ event->param.conn.srq = rep_data->srq;
+ event->param.conn.qp_num = rep_data->remote_qpn;
}
static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
{
struct rdma_id_private *id_priv = cm_id->context;
- enum rdma_cm_event_type event;
- u8 private_data_len = 0;
- int ret = 0, status = 0;
+ struct rdma_cm_event event;
+ int ret = 0;
atomic_inc(&id_priv->dev_remove);
if (!cma_comp(id_priv, CMA_CONNECT))
goto out;
+ memset(&event, 0, sizeof event);
switch (ib_event->event) {
case IB_CM_REQ_ERROR:
case IB_CM_REP_ERROR:
- event = RDMA_CM_EVENT_UNREACHABLE;
- status = -ETIMEDOUT;
+ event.event = RDMA_CM_EVENT_UNREACHABLE;
+ event.status = -ETIMEDOUT;
break;
case IB_CM_REP_RECEIVED:
- status = cma_verify_rep(id_priv, ib_event->private_data);
- if (status)
- event = RDMA_CM_EVENT_CONNECT_ERROR;
+ event.status = cma_verify_rep(id_priv, ib_event->private_data);
+ if (event.status)
+ event.event = RDMA_CM_EVENT_CONNECT_ERROR;
else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) {
- status = cma_rep_recv(id_priv);
- event = status ? RDMA_CM_EVENT_CONNECT_ERROR :
- RDMA_CM_EVENT_ESTABLISHED;
+ event.status = cma_rep_recv(id_priv);
+ event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR :
+ RDMA_CM_EVENT_ESTABLISHED;
} else
- event = RDMA_CM_EVENT_CONNECT_RESPONSE;
- private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE;
+ event.event = RDMA_CM_EVENT_CONNECT_RESPONSE;
+ cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd,
+ ib_event->private_data);
break;
case IB_CM_RTU_RECEIVED:
- status = cma_rtu_recv(id_priv);
- event = status ? RDMA_CM_EVENT_CONNECT_ERROR :
- RDMA_CM_EVENT_ESTABLISHED;
+ case IB_CM_USER_ESTABLISHED:
+ event.event = RDMA_CM_EVENT_ESTABLISHED;
break;
case IB_CM_DREQ_ERROR:
- status = -ETIMEDOUT; /* fall through */
+ event.status = -ETIMEDOUT; /* fall through */
case IB_CM_DREQ_RECEIVED:
case IB_CM_DREP_RECEIVED:
if (!cma_comp_exch(id_priv, CMA_CONNECT, CMA_DISCONNECT))
goto out;
- event = RDMA_CM_EVENT_DISCONNECTED;
+ event.event = RDMA_CM_EVENT_DISCONNECTED;
break;
case IB_CM_TIMEWAIT_EXIT:
case IB_CM_MRA_RECEIVED:
@@ -840,9 +831,10 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
goto out;
case IB_CM_REJ_RECEIVED:
cma_modify_qp_err(&id_priv->id);
- status = ib_event->param.rej_rcvd.reason;
- event = RDMA_CM_EVENT_REJECTED;
- private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE;
+ event.status = ib_event->param.rej_rcvd.reason;
+ event.event = RDMA_CM_EVENT_REJECTED;
+ event.param.conn.private_data = ib_event->private_data;
+ event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE;
break;
default:
printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d",
@@ -850,8 +842,7 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
goto out;
}
- ret = cma_notify_user(id_priv, event, status, ib_event->private_data,
- private_data_len);
+ ret = id_priv->id.event_handler(&id_priv->id, &event);
if (ret) {
/* Destroy the CM ID by returning a non-zero value. */
id_priv->cm_id.ib = NULL;
@@ -865,8 +856,8 @@ out:
return ret;
}
-static struct rdma_id_private *cma_new_id(struct rdma_cm_id *listen_id,
- struct ib_cm_event *ib_event)
+static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
+ struct ib_cm_event *ib_event)
{
struct rdma_id_private *id_priv;
struct rdma_cm_id *id;
@@ -913,9 +904,61 @@ err:
return NULL;
}
+static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
+ struct ib_cm_event *ib_event)
+{
+ struct rdma_id_private *id_priv;
+ struct rdma_cm_id *id;
+ union cma_ip_addr *src, *dst;
+ __u16 port;
+ u8 ip_ver;
+ int ret;
+
+ id = rdma_create_id(listen_id->event_handler, listen_id->context,
+ listen_id->ps);
+ if (IS_ERR(id))
+ return NULL;
+
+
+ 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);
+
+ ret = rdma_translate_ip(&id->route.addr.src_addr,
+ &id->route.addr.dev_addr);
+ if (ret)
+ goto err;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ id_priv->state = CMA_CONNECT;
+ return id_priv;
+err:
+ rdma_destroy_id(id);
+ return NULL;
+}
+
+static void cma_set_req_event_data(struct rdma_cm_event *event,
+ struct ib_cm_req_event_param *req_data,
+ void *private_data, int offset)
+{
+ event->param.conn.private_data = private_data + offset;
+ event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset;
+ event->param.conn.responder_resources = req_data->responder_resources;
+ event->param.conn.initiator_depth = req_data->initiator_depth;
+ event->param.conn.flow_control = req_data->flow_control;
+ event->param.conn.retry_count = req_data->retry_count;
+ event->param.conn.rnr_retry_count = req_data->rnr_retry_count;
+ event->param.conn.srq = req_data->srq;
+ event->param.conn.qp_num = req_data->remote_qpn;
+}
+
static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
{
struct rdma_id_private *listen_id, *conn_id;
+ struct rdma_cm_event event;
int offset, ret;
listen_id = cm_id->context;
@@ -925,7 +968,19 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
goto out;
}
- conn_id = cma_new_id(&listen_id->id, ib_event);
+ memset(&event, 0, sizeof event);
+ offset = cma_user_data_offset(listen_id->id.ps);
+ event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
+ if (listen_id->id.ps == RDMA_PS_UDP) {
+ conn_id = cma_new_udp_id(&listen_id->id, ib_event);
+ event.param.ud.private_data = ib_event->private_data + offset;
+ event.param.ud.private_data_len =
+ IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset;
+ } else {
+ conn_id = cma_new_conn_id(&listen_id->id, ib_event);
+ cma_set_req_event_data(&event, &ib_event->param.req_rcvd,
+ ib_event->private_data, offset);
+ }
if (!conn_id) {
ret = -ENOMEM;
goto out;
@@ -942,10 +997,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
cm_id->context = conn_id;
cm_id->cm_handler = cma_ib_handler;
- offset = cma_user_data_offset(listen_id->id.ps);
- ret = cma_notify_user(conn_id, RDMA_CM_EVENT_CONNECT_REQUEST, 0,
- ib_event->private_data + offset,
- IB_CM_REQ_PRIVATE_DATA_SIZE - offset);
+ ret = conn_id->id.event_handler(&conn_id->id, &event);
if (!ret)
goto out;
@@ -964,8 +1016,7 @@ out:
static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr)
{
- return cpu_to_be64(((u64)ps << 16) +
- be16_to_cpu(((struct sockaddr_in *) addr)->sin_port));
+ return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr)));
}
static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr,
@@ -1021,36 +1072,49 @@ static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr,
static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
{
struct rdma_id_private *id_priv = iw_id->context;
- enum rdma_cm_event_type event = 0;
+ struct rdma_cm_event event;
struct sockaddr_in *sin;
int ret = 0;
+ memset(&event, 0, sizeof event);
atomic_inc(&id_priv->dev_remove);
switch (iw_event->event) {
case IW_CM_EVENT_CLOSE:
- event = RDMA_CM_EVENT_DISCONNECTED;
+ event.event = RDMA_CM_EVENT_DISCONNECTED;
break;
case IW_CM_EVENT_CONNECT_REPLY:
sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
*sin = iw_event->local_addr;
sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr;
*sin = iw_event->remote_addr;
- if (iw_event->status)
- event = RDMA_CM_EVENT_REJECTED;
- else
- event = RDMA_CM_EVENT_ESTABLISHED;
+ switch (iw_event->status) {
+ case 0:
+ event.event = RDMA_CM_EVENT_ESTABLISHED;
+ break;
+ case -ECONNRESET:
+ case -ECONNREFUSED:
+ event.event = RDMA_CM_EVENT_REJECTED;
+ break;
+ case -ETIMEDOUT:
+ event.event = RDMA_CM_EVENT_UNREACHABLE;
+ break;
+ default:
+ event.event = RDMA_CM_EVENT_CONNECT_ERROR;
+ break;
+ }
break;
case IW_CM_EVENT_ESTABLISHED:
- event = RDMA_CM_EVENT_ESTABLISHED;
+ event.event = RDMA_CM_EVENT_ESTABLISHED;
break;
default:
BUG_ON(1);
}
- ret = cma_notify_user(id_priv, event, iw_event->status,
- iw_event->private_data,
- iw_event->private_data_len);
+ event.status = iw_event->status;
+ event.param.conn.private_data = iw_event->private_data;
+ event.param.conn.private_data_len = iw_event->private_data_len;
+ ret = id_priv->id.event_handler(&id_priv->id, &event);
if (ret) {
/* Destroy the CM ID by returning a non-zero value. */
id_priv->cm_id.iw = NULL;
@@ -1071,6 +1135,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
struct rdma_id_private *listen_id, *conn_id;
struct sockaddr_in *sin;
struct net_device *dev = NULL;
+ struct rdma_cm_event event;
int ret;
listen_id = cm_id->context;
@@ -1124,9 +1189,11 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
*sin = iw_event->remote_addr;
- ret = cma_notify_user(conn_id, RDMA_CM_EVENT_CONNECT_REQUEST, 0,
- iw_event->private_data,
- iw_event->private_data_len);
+ memset(&event, 0, sizeof event);
+ event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
+ event.param.conn.private_data = iw_event->private_data;
+ event.param.conn.private_data_len = iw_event->private_data_len;
+ ret = conn_id->id.event_handler(&conn_id->id, &event);
if (ret) {
/* User wants to destroy the CM ID */
conn_id->cm_id.iw = NULL;
@@ -1515,8 +1582,9 @@ static void addr_handler(int status, struct sockaddr *src_addr,
struct rdma_dev_addr *dev_addr, void *context)
{
struct rdma_id_private *id_priv = context;
- enum rdma_cm_event_type event;
+ struct rdma_cm_event event;
+ memset(&event, 0, sizeof event);
atomic_inc(&id_priv->dev_remove);
/*
@@ -1536,14 +1604,15 @@ static void addr_handler(int status, struct sockaddr *src_addr,
if (status) {
if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND))
goto out;
- event = RDMA_CM_EVENT_ADDR_ERROR;
+ event.event = RDMA_CM_EVENT_ADDR_ERROR;
+ event.status = status;
} else {
memcpy(&id_priv->id.route.addr.src_addr, src_addr,
ip_addr_size(src_addr));
- event = RDMA_CM_EVENT_ADDR_RESOLVED;
+ event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
}
- if (cma_notify_user(id_priv, event, status, NULL, 0)) {
+ if (id_priv->id.event_handler(&id_priv->id, &event)) {
cma_exch(id_priv, CMA_DESTROYING);
cma_release_remove(id_priv);
cma_deref_id(id_priv);
@@ -1733,6 +1802,9 @@ static int cma_get_port(struct rdma_id_private *id_priv)
case RDMA_PS_TCP:
ps = &tcp_ps;
break;
+ case RDMA_PS_UDP:
+ ps = &udp_ps;
+ break;
default:
return -EPROTONOSUPPORT;
}
@@ -1821,6 +1893,110 @@ static int cma_format_hdr(void *hdr, enum rdma_port_space ps,
return 0;
}
+static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
+ struct ib_cm_event *ib_event)
+{
+ struct rdma_id_private *id_priv = cm_id->context;
+ struct rdma_cm_event event;
+ struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd;
+ int ret = 0;
+
+ memset(&event, 0, sizeof event);
+ atomic_inc(&id_priv->dev_remove);
+ if (!cma_comp(id_priv, CMA_CONNECT))
+ goto out;
+
+ switch (ib_event->event) {
+ case IB_CM_SIDR_REQ_ERROR:
+ event.event = RDMA_CM_EVENT_UNREACHABLE;
+ event.status = -ETIMEDOUT;
+ break;
+ case IB_CM_SIDR_REP_RECEIVED:
+ event.param.ud.private_data = ib_event->private_data;
+ event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE;
+ if (rep->status != IB_SIDR_SUCCESS) {
+ event.event = RDMA_CM_EVENT_UNREACHABLE;
+ event.status = ib_event->param.sidr_rep_rcvd.status;
+ break;
+ }
+ if (rep->qkey != RDMA_UD_QKEY) {
+ event.event = RDMA_CM_EVENT_UNREACHABLE;
+ event.status = -EINVAL;
+ break;
+ }
+ ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num,
+ id_priv->id.route.path_rec,
+ &event.param.ud.ah_attr);
+ event.param.ud.qp_num = rep->qpn;
+ event.param.ud.qkey = rep->qkey;
+ event.event = RDMA_CM_EVENT_ESTABLISHED;
+ event.status = 0;
+ break;
+ default:
+ printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d",
+ ib_event->event);
+ goto out;
+ }
+
+ ret = id_priv->id.event_handler(&id_priv->id, &event);
+ if (ret) {
+ /* Destroy the CM ID by returning a non-zero value. */
+ id_priv->cm_id.ib = NULL;
+ cma_exch(id_priv, CMA_DESTROYING);
+ cma_release_remove(id_priv);
+ rdma_destroy_id(&id_priv->id);
+ return ret;
+ }
+out:
+ cma_release_remove(id_priv);
+ return ret;
+}
+
+static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
+ struct rdma_conn_param *conn_param)
+{
+ struct ib_cm_sidr_req_param req;
+ struct rdma_route *route;
+ int ret;
+
+ req.private_data_len = sizeof(struct cma_hdr) +
+ conn_param->private_data_len;
+ req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+ if (!req.private_data)
+ return -ENOMEM;
+
+ if (conn_param->private_data && conn_param->private_data_len)
+ memcpy((void *) req.private_data + sizeof(struct cma_hdr),
+ conn_param->private_data, conn_param->private_data_len);
+
+ route = &id_priv->id.route;
+ ret = cma_format_hdr((void *) req.private_data, id_priv->id.ps, route);
+ if (ret)
+ goto out;
+
+ id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device,
+ cma_sidr_rep_handler, id_priv);
+ if (IS_ERR(id_priv->cm_id.ib)) {
+ ret = PTR_ERR(id_priv->cm_id.ib);
+ goto out;
+ }
+
+ req.path = route->path_rec;
+ req.service_id = cma_get_service_id(id_priv->id.ps,
+ &route->addr.dst_addr);
+ req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8);
+ req.max_cm_retries = CMA_MAX_CM_RETRIES;
+
+ ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req);
+ if (ret) {
+ ib_destroy_cm_id(id_priv->cm_id.ib);
+ id_priv->cm_id.ib = NULL;
+ }
+out:
+ kfree(req.private_data);
+ return ret;
+}
+
static int cma_connect_ib(struct rdma_id_private *id_priv,
struct rdma_conn_param *conn_param)
{
@@ -1860,7 +2036,7 @@ static int cma_connect_ib(struct rdma_id_private *id_priv,
req.service_id = cma_get_service_id(id_priv->id.ps,
&route->addr.dst_addr);
req.qp_num = id_priv->qp_num;
- req.qp_type = id_priv->qp_type;
+ req.qp_type = IB_QPT_RC;
req.starting_psn = id_priv->seq_num;
req.responder_resources = conn_param->responder_resources;
req.initiator_depth = conn_param->initiator_depth;
@@ -1937,13 +2113,15 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
if (!id->qp) {
id_priv->qp_num = conn_param->qp_num;
- id_priv->qp_type = conn_param->qp_type;
id_priv->srq = conn_param->srq;
}
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- ret = cma_connect_ib(id_priv, conn_param);
+ if (id->ps == RDMA_PS_UDP)
+ ret = cma_resolve_ib_udp(id_priv, conn_param);
+ else
+ ret = cma_connect_ib(id_priv, conn_param);
break;
case RDMA_TRANSPORT_IWARP:
ret = cma_connect_iw(id_priv, conn_param);
@@ -1966,11 +2144,25 @@ static int cma_accept_ib(struct rdma_id_private *id_priv,
struct rdma_conn_param *conn_param)
{
struct ib_cm_rep_param rep;
- int ret;
+ struct ib_qp_attr qp_attr;
+ int qp_attr_mask, ret;
- ret = cma_modify_qp_rtr(&id_priv->id);
- if (ret)
- return ret;
+ if (id_priv->id.qp) {
+ ret = cma_modify_qp_rtr(&id_priv->id);
+ if (ret)
+ goto out;
+
+ qp_attr.qp_state = IB_QPS_RTS;
+ ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, &qp_attr,
+ &qp_attr_mask);
+ if (ret)
+ goto out;
+
+ qp_attr.max_rd_atomic = conn_param->initiator_depth;
+ ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
+ if (ret)
+ goto out;
+ }
memset(&rep, 0, sizeof rep);
rep.qp_num = id_priv->qp_num;
@@ -1985,7 +2177,9 @@ static int cma_accept_ib(struct rdma_id_private *id_priv,
rep.rnr_retry_count = conn_param->rnr_retry_count;
rep.srq = id_priv->srq ? 1 : 0;
- return ib_send_cm_rep(id_priv->cm_id.ib, &rep);
+ ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep);
+out:
+ return ret;
}
static int cma_accept_iw(struct rdma_id_private *id_priv,
@@ -2010,6 +2204,24 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
return iw_cm_accept(id_priv->cm_id.iw, &iw_param);
}
+static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
+ enum ib_cm_sidr_status status,
+ const void *private_data, int private_data_len)
+{
+ struct ib_cm_sidr_rep_param rep;
+
+ memset(&rep, 0, sizeof rep);
+ rep.status = status;
+ if (status == IB_SIDR_SUCCESS) {
+ rep.qp_num = id_priv->qp_num;
+ rep.qkey = RDMA_UD_QKEY;
+ }
+ rep.private_data = private_data;
+ rep.private_data_len = private_data_len;
+
+ return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep);
+}
+
int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
{
struct rdma_id_private *id_priv;
@@ -2021,13 +2233,16 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
if (!id->qp && conn_param) {
id_priv->qp_num = conn_param->qp_num;
- id_priv->qp_type = conn_param->qp_type;
id_priv->srq = conn_param->srq;
}
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- if (conn_param)
+ if (id->ps == RDMA_PS_UDP)
+ ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
+ conn_param->private_data,
+ conn_param->private_data_len);
+ else if (conn_param)
ret = cma_accept_ib(id_priv, conn_param);
else
ret = cma_rep_recv(id_priv);
@@ -2051,6 +2266,27 @@ reject:
}
EXPORT_SYMBOL(rdma_accept);
+int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (!cma_comp(id_priv, CMA_CONNECT))
+ return -EINVAL;
+
+ switch (id->device->node_type) {
+ case RDMA_NODE_IB_CA:
+ ret = ib_cm_notify(id_priv->cm_id.ib, event);
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(rdma_notify);
+
int rdma_reject(struct rdma_cm_id *id, const void *private_data,
u8 private_data_len)
{
@@ -2063,9 +2299,13 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data,
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- ret = ib_send_cm_rej(id_priv->cm_id.ib,
- IB_CM_REJ_CONSUMER_DEFINED, NULL, 0,
- private_data, private_data_len);
+ if (id->ps == RDMA_PS_UDP)
+ ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT,
+ private_data, private_data_len);
+ else
+ ret = ib_send_cm_rej(id_priv->cm_id.ib,
+ IB_CM_REJ_CONSUMER_DEFINED, NULL,
+ 0, private_data, private_data_len);
break;
case RDMA_TRANSPORT_IWARP:
ret = iw_cm_reject(id_priv->cm_id.iw,
@@ -2136,6 +2376,7 @@ static void cma_add_one(struct ib_device *device)
static int cma_remove_id_dev(struct rdma_id_private *id_priv)
{
+ struct rdma_cm_event event;
enum cma_state state;
/* Record that we want to remove the device */
@@ -2150,8 +2391,9 @@ static int cma_remove_id_dev(struct rdma_id_private *id_priv)
if (!cma_comp(id_priv, CMA_DEVICE_REMOVAL))
return 0;
- return cma_notify_user(id_priv, RDMA_CM_EVENT_DEVICE_REMOVAL,
- 0, NULL, 0);
+ memset(&event, 0, sizeof event);
+ event.event = RDMA_CM_EVENT_DEVICE_REMOVAL;
+ return id_priv->id.event_handler(&id_priv->id, &event);
}
static void cma_process_remove(struct cma_device *cma_dev)
@@ -2233,6 +2475,7 @@ static void cma_cleanup(void)
destroy_workqueue(cma_wq);
idr_destroy(&sdp_ps);
idr_destroy(&tcp_ps);
+ idr_destroy(&udp_ps);
}
module_init(cma_init);
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index 86a3b2d401d..8926a2bd4a8 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -394,20 +394,12 @@ EXPORT_SYMBOL(ib_destroy_fmr_pool);
*/
int ib_flush_fmr_pool(struct ib_fmr_pool *pool)
{
- int serial;
-
- atomic_inc(&pool->req_ser);
- /*
- * It's OK if someone else bumps req_ser again here -- we'll
- * just wait a little longer.
- */
- serial = atomic_read(&pool->req_ser);
+ int serial = atomic_inc_return(&pool->req_ser);
wake_up_process(pool->thread);
if (wait_event_interruptible(pool->force_wait,
- atomic_read(&pool->flush_ser) -
- atomic_read(&pool->req_ser) >= 0))
+ atomic_read(&pool->flush_ser) - serial >= 0))
return -EINTR;
return 0;
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 15f38d94b3a..13efd417034 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -642,7 +642,8 @@ static void snoop_recv(struct ib_mad_qp_info *qp_info,
spin_unlock_irqrestore(&qp_info->snoop_lock, flags);
}
-static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
+static void build_smp_wc(struct ib_qp *qp,
+ u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
struct ib_wc *wc)
{
memset(wc, 0, sizeof *wc);
@@ -652,7 +653,7 @@ static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
wc->pkey_index = pkey_index;
wc->byte_len = sizeof(struct ib_mad) + sizeof(struct ib_grh);
wc->src_qp = IB_QP0;
- wc->qp_num = IB_QP0;
+ wc->qp = qp;
wc->slid = slid;
wc->sl = 0;
wc->dlid_path_bits = 0;
@@ -713,7 +714,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
goto out;
}
- build_smp_wc(send_wr->wr_id, be16_to_cpu(smp->dr_slid),
+ build_smp_wc(mad_agent_priv->agent.qp,
+ send_wr->wr_id, be16_to_cpu(smp->dr_slid),
send_wr->wr.ud.pkey_index,
send_wr->wr.ud.port_num, &mad_wc);
@@ -998,17 +1000,17 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr)
mad_agent = mad_send_wr->send_buf.mad_agent;
sge = mad_send_wr->sg_list;
- sge[0].addr = dma_map_single(mad_agent->device->dma_device,
- mad_send_wr->send_buf.mad,
- sge[0].length,
- DMA_TO_DEVICE);
- pci_unmap_addr_set(mad_send_wr, header_mapping, sge[0].addr);
-
- sge[1].addr = dma_map_single(mad_agent->device->dma_device,
- ib_get_payload(mad_send_wr),
- sge[1].length,
- DMA_TO_DEVICE);
- pci_unmap_addr_set(mad_send_wr, payload_mapping, sge[1].addr);
+ sge[0].addr = ib_dma_map_single(mad_agent->device,
+ mad_send_wr->send_buf.mad,
+ sge[0].length,
+ DMA_TO_DEVICE);
+ mad_send_wr->header_mapping = sge[0].addr;
+
+ sge[1].addr = ib_dma_map_single(mad_agent->device,
+ ib_get_payload(mad_send_wr),
+ sge[1].length,
+ DMA_TO_DEVICE);
+ mad_send_wr->payload_mapping = sge[1].addr;
spin_lock_irqsave(&qp_info->send_queue.lock, flags);
if (qp_info->send_queue.count < qp_info->send_queue.max_active) {
@@ -1026,12 +1028,12 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr)
}
spin_unlock_irqrestore(&qp_info->send_queue.lock, flags);
if (ret) {
- dma_unmap_single(mad_agent->device->dma_device,
- pci_unmap_addr(mad_send_wr, header_mapping),
- sge[0].length, DMA_TO_DEVICE);
- dma_unmap_single(mad_agent->device->dma_device,
- pci_unmap_addr(mad_send_wr, payload_mapping),
- sge[1].length, DMA_TO_DEVICE);
+ ib_dma_unmap_single(mad_agent->device,
+ mad_send_wr->header_mapping,
+ sge[0].length, DMA_TO_DEVICE);
+ ib_dma_unmap_single(mad_agent->device,
+ mad_send_wr->payload_mapping,
+ sge[1].length, DMA_TO_DEVICE);
}
return ret;
}
@@ -1850,11 +1852,11 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
mad_priv_hdr = container_of(mad_list, struct ib_mad_private_header,
mad_list);
recv = container_of(mad_priv_hdr, struct ib_mad_private, header);
- dma_unmap_single(port_priv->device->dma_device,
- pci_unmap_addr(&recv->header, mapping),
- sizeof(struct ib_mad_private) -
- sizeof(struct ib_mad_private_header),
- DMA_FROM_DEVICE);
+ ib_dma_unmap_single(port_priv->device,
+ recv->header.mapping,
+ sizeof(struct ib_mad_private) -
+ sizeof(struct ib_mad_private_header),
+ DMA_FROM_DEVICE);
/* Setup MAD receive work completion from "normal" work completion */
recv->header.wc = *wc;
@@ -2080,12 +2082,12 @@ static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv,
qp_info = send_queue->qp_info;
retry:
- dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device,
- pci_unmap_addr(mad_send_wr, header_mapping),
- mad_send_wr->sg_list[0].length, DMA_TO_DEVICE);
- dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device,
- pci_unmap_addr(mad_send_wr, payload_mapping),
- mad_send_wr->sg_list[1].length, DMA_TO_DEVICE);
+ ib_dma_unmap_single(mad_send_wr->send_buf.mad_agent->device,
+ mad_send_wr->header_mapping,
+ mad_send_wr->sg_list[0].length, DMA_TO_DEVICE);
+ ib_dma_unmap_single(mad_send_wr->send_buf.mad_agent->device,
+ mad_send_wr->payload_mapping,
+ mad_send_wr->sg_list[1].length, DMA_TO_DEVICE);
queued_send_wr = NULL;
spin_lock_irqsave(&send_queue->lock, flags);
list_del(&mad_list->list);
@@ -2355,7 +2357,8 @@ static void local_completions(struct work_struct *work)
* Defined behavior is to complete response
* before request
*/
- build_smp_wc((unsigned long) local->mad_send_wr,
+ build_smp_wc(recv_mad_agent->agent.qp,
+ (unsigned long) local->mad_send_wr,
be16_to_cpu(IB_LID_PERMISSIVE),
0, recv_mad_agent->agent.port_num, &wc);
@@ -2528,13 +2531,12 @@ static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info,
break;
}
}
- sg_list.addr = dma_map_single(qp_info->port_priv->
- device->dma_device,
- &mad_priv->grh,
- sizeof *mad_priv -
- sizeof mad_priv->header,
- DMA_FROM_DEVICE);
- pci_unmap_addr_set(&mad_priv->header, mapping, sg_list.addr);
+ sg_list.addr = ib_dma_map_single(qp_info->port_priv->device,
+ &mad_priv->grh,
+ sizeof *mad_priv -
+ sizeof mad_priv->header,
+ DMA_FROM_DEVICE);
+ mad_priv->header.mapping = sg_list.addr;
recv_wr.wr_id = (unsigned long)&mad_priv->header.mad_list;
mad_priv->header.mad_list.mad_queue = recv_queue;
@@ -2549,12 +2551,11 @@ static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info,
list_del(&mad_priv->header.mad_list.list);
recv_queue->count--;
spin_unlock_irqrestore(&recv_queue->lock, flags);
- dma_unmap_single(qp_info->port_priv->device->dma_device,
- pci_unmap_addr(&mad_priv->header,
- mapping),
- sizeof *mad_priv -
- sizeof mad_priv->header,
- DMA_FROM_DEVICE);
+ ib_dma_unmap_single(qp_info->port_priv->device,
+ mad_priv->header.mapping,
+ sizeof *mad_priv -
+ sizeof mad_priv->header,
+ DMA_FROM_DEVICE);
kmem_cache_free(ib_mad_cache, mad_priv);
printk(KERN_ERR PFX "ib_post_recv failed: %d\n", ret);
break;
@@ -2586,11 +2587,11 @@ static void cleanup_recv_queue(struct ib_mad_qp_info *qp_info)
/* Remove from posted receive MAD list */
list_del(&mad_list->list);
- dma_unmap_single(qp_info->port_priv->device->dma_device,
- pci_unmap_addr(&recv->header, mapping),
- sizeof(struct ib_mad_private) -
- sizeof(struct ib_mad_private_header),
- DMA_FROM_DEVICE);
+ ib_dma_unmap_single(qp_info->port_priv->device,
+ recv->header.mapping,
+ sizeof(struct ib_mad_private) -
+ sizeof(struct ib_mad_private_header),
+ DMA_FROM_DEVICE);
kmem_cache_free(ib_mad_cache, recv);
}
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index d5548e73e06..de89717f49f 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -73,7 +73,7 @@ struct ib_mad_private_header {
struct ib_mad_list_head mad_list;
struct ib_mad_recv_wc recv_wc;
struct ib_wc wc;
- DECLARE_PCI_UNMAP_ADDR(mapping)
+ u64 mapping;
} __attribute__ ((packed));
struct ib_mad_private {
@@ -126,8 +126,8 @@ struct ib_mad_send_wr_private {
struct list_head agent_list;
struct ib_mad_agent_private *mad_agent_priv;
struct ib_mad_send_buf send_buf;
- DECLARE_PCI_UNMAP_ADDR(header_mapping)
- DECLARE_PCI_UNMAP_ADDR(payload_mapping)
+ u64 header_mapping;
+ u64 payload_mapping;
struct ib_send_wr send_wr;
struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
__be64 tid;
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
new file mode 100644
index 00000000000..e2e8d329b44
--- /dev/null
+++ b/drivers/infiniband/core/ucma.c
@@ -0,0 +1,885 @@
+/*
+ * Copyright (c) 2005-2006 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/idr.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/miscdevice.h>
+
+#include <rdma/rdma_user_cm.h>
+#include <rdma/ib_marshall.h>
+#include <rdma/rdma_cm.h>
+
+MODULE_AUTHOR("Sean Hefty");
+MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access");
+MODULE_LICENSE("Dual BSD/GPL");
+
+enum {
+ UCMA_MAX_BACKLOG = 128
+};
+
+struct ucma_file {
+ struct mutex mut;
+ struct file *filp;
+ struct list_head ctx_list;
+ struct list_head event_list;
+ wait_queue_head_t poll_wait;
+};
+
+struct ucma_context {
+ int id;
+ struct completion comp;
+ atomic_t ref;
+ int events_reported;
+ int backlog;
+
+ struct ucma_file *file;
+ struct rdma_cm_id *cm_id;
+ u64 uid;
+
+ struct list_head list;
+};
+
+struct ucma_event {
+ struct ucma_context *ctx;
+ struct list_head list;
+ struct rdma_cm_id *cm_id;
+ struct rdma_ucm_event_resp resp;
+};
+
+static DEFINE_MUTEX(mut);
+static DEFINE_IDR(ctx_idr);
+
+static inline struct ucma_context *_ucma_find_context(int id,
+ struct ucma_file *file)
+{
+ struct ucma_context *ctx;
+
+ ctx = idr_find(&ctx_idr, id);
+ if (!ctx)
+ ctx = ERR_PTR(-ENOENT);
+ else if (ctx->file != file)
+ ctx = ERR_PTR(-EINVAL);
+ return ctx;
+}
+
+static struct ucma_context *ucma_get_ctx(struct ucma_file *file, int id)
+{
+ struct ucma_context *ctx;
+
+ mutex_lock(&mut);
+ ctx = _ucma_find_context(id, file);
+ if (!IS_ERR(ctx))
+ atomic_inc(&ctx->ref);
+ mutex_unlock(&mut);
+ return ctx;
+}
+
+static void ucma_put_ctx(struct ucma_context *ctx)
+{
+ if (atomic_dec_and_test(&ctx->ref))
+ complete(&ctx->comp);
+}
+
+static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
+{
+ struct ucma_context *ctx;
+ int ret;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ atomic_set(&ctx->ref, 1);
+ init_completion(&ctx->comp);
+ ctx->file = file;
+
+ do {
+ ret = idr_pre_get(&ctx_idr, GFP_KERNEL);
+ if (!ret)
+ goto error;
+
+ mutex_lock(&mut);
+ ret = idr_get_new(&ctx_idr, ctx, &ctx->id);
+ mutex_unlock(&mut);
+ } while (ret == -EAGAIN);
+
+ if (ret)
+ goto error;
+
+ list_add_tail(&ctx->list, &file->ctx_list);
+ return ctx;
+
+error:
+ kfree(ctx);
+ return NULL;
+}
+
+static void ucma_copy_conn_event(struct rdma_ucm_conn_param *dst,
+ struct rdma_conn_param *src)
+{
+ if (src->private_data_len)
+ memcpy(dst->private_data, src->private_data,
+ src->private_data_len);
+ dst->private_data_len = src->private_data_len;
+ dst->responder_resources =src->responder_resources;
+ dst->initiator_depth = src->initiator_depth;
+ dst->flow_control = src->flow_control;
+ dst->retry_count = src->retry_count;
+ dst->rnr_retry_count = src->rnr_retry_count;
+ dst->srq = src->srq;
+ dst->qp_num = src->qp_num;
+}
+
+static void ucma_copy_ud_event(struct rdma_ucm_ud_param *dst,
+ struct rdma_ud_param *src)
+{
+ if (src->private_data_len)
+ memcpy(dst->private_data, src->private_data,
+ src->private_data_len);
+ dst->private_data_len = src->private_data_len;
+ ib_copy_ah_attr_to_user(&dst->ah_attr, &src->ah_attr);
+ dst->qp_num = src->qp_num;
+ dst->qkey = src->qkey;
+}
+
+static void ucma_set_event_context(struct ucma_context *ctx,
+ struct rdma_cm_event *event,
+ struct ucma_event *uevent)
+{
+ uevent->ctx = ctx;
+ uevent->resp.uid = ctx->uid;
+ uevent->resp.id = ctx->id;
+}
+
+static int ucma_event_handler(struct rdma_cm_id *cm_id,
+ struct rdma_cm_event *event)
+{
+ struct ucma_event *uevent;
+ struct ucma_context *ctx = cm_id->context;
+ int ret = 0;
+
+ uevent = kzalloc(sizeof(*uevent), GFP_KERNEL);
+ if (!uevent)
+ return event->event == RDMA_CM_EVENT_CONNECT_REQUEST;
+
+ uevent->cm_id = cm_id;
+ ucma_set_event_context(ctx, event, uevent);
+ uevent->resp.event = event->event;
+ uevent->resp.status = event->status;
+ if (cm_id->ps == RDMA_PS_UDP)
+ ucma_copy_ud_event(&uevent->resp.param.ud, &event->param.ud);
+ else
+ ucma_copy_conn_event(&uevent->resp.param.conn,
+ &event->param.conn);
+
+ mutex_lock(&ctx->file->mut);
+ if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) {
+ if (!ctx->backlog) {
+ ret = -EDQUOT;
+ kfree(uevent);
+ goto out;
+ }
+ ctx->backlog--;
+ } else if (!ctx->uid) {
+ /*
+ * We ignore events for new connections until userspace has set
+ * their context. This can only happen if an error occurs on a
+ * new connection before the user accepts it. This is okay,
+ * since the accept will just fail later.
+ */
+ kfree(uevent);
+ goto out;
+ }
+
+ list_add_tail(&uevent->list, &ctx->file->event_list);
+ wake_up_interruptible(&ctx->file->poll_wait);
+out:
+ mutex_unlock(&ctx->file->mut);
+ return ret;
+}
+
+static ssize_t ucma_get_event(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct ucma_context *ctx;
+ struct rdma_ucm_get_event cmd;
+ struct ucma_event *uevent;
+ int ret = 0;
+ DEFINE_WAIT(wait);
+
+ if (out_len < sizeof uevent->resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ mutex_lock(&file->mut);
+ while (list_empty(&file->event_list)) {
+ if (file->filp->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ prepare_to_wait(&file->poll_wait, &wait, TASK_INTERRUPTIBLE);
+ mutex_unlock(&file->mut);
+ schedule();
+ mutex_lock(&file->mut);
+ finish_wait(&file->poll_wait, &wait);
+ }
+
+ if (ret)
+ goto done;
+
+ uevent = list_entry(file->event_list.next, struct ucma_event, list);
+
+ if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST) {
+ ctx = ucma_alloc_ctx(file);
+ if (!ctx) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ uevent->ctx->backlog++;
+ ctx->cm_id = uevent->cm_id;
+ ctx->cm_id->context = ctx;
+ uevent->resp.id = ctx->id;
+ }
+
+ if (copy_to_user((void __user *)(unsigned long)cmd.response,
+ &uevent->resp, sizeof uevent->resp)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ list_del(&uevent->list);
+ uevent->ctx->events_reported++;
+ kfree(uevent);
+done:
+ mutex_unlock(&file->mut);
+ return ret;
+}
+
+static ssize_t ucma_create_id(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_create_id cmd;
+ struct rdma_ucm_create_id_resp resp;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (out_len < sizeof(resp))
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ mutex_lock(&file->mut);
+ ctx = ucma_alloc_ctx(file);
+ mutex_unlock(&file->mut);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->uid = cmd.uid;
+ ctx->cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps);
+ if (IS_ERR(ctx->cm_id)) {
+ ret = PTR_ERR(ctx->cm_id);
+ goto err1;
+ }
+
+ resp.id = ctx->id;
+ if (copy_to_user((void __user *)(unsigned long)cmd.response,
+ &resp, sizeof(resp))) {
+ ret = -EFAULT;
+ goto err2;
+ }
+ return 0;
+
+err2:
+ rdma_destroy_id(ctx->cm_id);
+err1:
+ mutex_lock(&mut);
+ idr_remove(&ctx_idr, ctx->id);
+ mutex_unlock(&mut);
+ kfree(ctx);
+ return ret;
+}
+
+static void ucma_cleanup_events(struct ucma_context *ctx)
+{
+ struct ucma_event *uevent, *tmp;
+
+ list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list) {
+ if (uevent->ctx != ctx)
+ continue;
+
+ list_del(&uevent->list);
+
+ /* clear incoming connections. */
+ if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST)
+ rdma_destroy_id(uevent->cm_id);
+
+ kfree(uevent);
+ }
+}
+
+static int ucma_free_ctx(struct ucma_context *ctx)
+{
+ int events_reported;
+
+ /* No new events will be generated after destroying the id. */
+ rdma_destroy_id(ctx->cm_id);
+
+ /* Cleanup events not yet reported to the user. */
+ mutex_lock(&ctx->file->mut);
+ ucma_cleanup_events(ctx);
+ list_del(&ctx->list);
+ mutex_unlock(&ctx->file->mut);
+
+ events_reported = ctx->events_reported;
+ kfree(ctx);
+ return events_reported;
+}
+
+static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_destroy_id cmd;
+ struct rdma_ucm_destroy_id_resp resp;
+ struct ucma_context *ctx;
+ int ret = 0;
+
+ if (out_len < sizeof(resp))
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ mutex_lock(&mut);
+ ctx = _ucma_find_context(cmd.id, file);
+ if (!IS_ERR(ctx))
+ idr_remove(&ctx_idr, ctx->id);
+ mutex_unlock(&mut);
+
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ucma_put_ctx(ctx);
+ wait_for_completion(&ctx->comp);
+ resp.events_reported = ucma_free_ctx(ctx);
+
+ if (copy_to_user((void __user *)(unsigned long)cmd.response,
+ &resp, sizeof(resp)))
+ ret = -EFAULT;
+
+ return ret;
+}
+
+static ssize_t ucma_bind_addr(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_bind_addr cmd;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr);
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static ssize_t ucma_resolve_addr(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_resolve_addr cmd;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
+ (struct sockaddr *) &cmd.dst_addr,
+ cmd.timeout_ms);
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static ssize_t ucma_resolve_route(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_resolve_route cmd;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ret = rdma_resolve_route(ctx->cm_id, cmd.timeout_ms);
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static void ucma_copy_ib_route(struct rdma_ucm_query_route_resp *resp,
+ struct rdma_route *route)
+{
+ struct rdma_dev_addr *dev_addr;
+
+ resp->num_paths = route->num_paths;
+ switch (route->num_paths) {
+ case 0:
+ dev_addr = &route->addr.dev_addr;
+ ib_addr_get_dgid(dev_addr,
+ (union ib_gid *) &resp->ib_route[0].dgid);
+ ib_addr_get_sgid(dev_addr,
+ (union ib_gid *) &resp->ib_route[0].sgid);
+ resp->ib_route[0].pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
+ break;
+ case 2:
+ ib_copy_path_rec_to_user(&resp->ib_route[1],
+ &route->path_rec[1]);
+ /* fall through */
+ case 1:
+ ib_copy_path_rec_to_user(&resp->ib_route[0],
+ &route->path_rec[0]);
+ break;
+ default:
+ break;
+ }
+}
+
+static ssize_t ucma_query_route(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_query_route cmd;
+ struct rdma_ucm_query_route_resp resp;
+ struct ucma_context *ctx;
+ struct sockaddr *addr;
+ int ret = 0;
+
+ if (out_len < sizeof(resp))
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ memset(&resp, 0, sizeof resp);
+ addr = &ctx->cm_id->route.addr.src_addr;
+ memcpy(&resp.src_addr, addr, addr->sa_family == AF_INET ?
+ sizeof(struct sockaddr_in) :
+ sizeof(struct sockaddr_in6));
+ addr = &ctx->cm_id->route.addr.dst_addr;
+ memcpy(&resp.dst_addr, addr, addr->sa_family == AF_INET ?
+ sizeof(struct sockaddr_in) :
+ sizeof(struct sockaddr_in6));
+ if (!ctx->cm_id->device)
+ goto out;
+
+ resp.node_guid = ctx->cm_id->device->node_guid;
+ resp.port_num = ctx->cm_id->port_num;
+ switch (rdma_node_get_transport(ctx->cm_id->device->node_type)) {
+ case RDMA_TRANSPORT_IB:
+ ucma_copy_ib_route(&resp, &ctx->cm_id->route);
+ break;
+ default:
+ break;
+ }
+
+out:
+ if (copy_to_user((void __user *)(unsigned long)cmd.response,
+ &resp, sizeof(resp)))
+ ret = -EFAULT;
+
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static void ucma_copy_conn_param(struct rdma_conn_param *dst,
+ struct rdma_ucm_conn_param *src)
+{
+ dst->private_data = src->private_data;
+ dst->private_data_len = src->private_data_len;
+ dst->responder_resources =src->responder_resources;
+ dst->initiator_depth = src->initiator_depth;
+ dst->flow_control = src->flow_control;
+ dst->retry_count = src->retry_count;
+ dst->rnr_retry_count = src->rnr_retry_count;
+ dst->srq = src->srq;
+ dst->qp_num = src->qp_num;
+}
+
+static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_connect cmd;
+ struct rdma_conn_param conn_param;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ if (!cmd.conn_param.valid)
+ return -EINVAL;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ucma_copy_conn_param(&conn_param, &cmd.conn_param);
+ ret = rdma_connect(ctx->cm_id, &conn_param);
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static ssize_t ucma_listen(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_listen cmd;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ctx->backlog = cmd.backlog > 0 && cmd.backlog < UCMA_MAX_BACKLOG ?
+ cmd.backlog : UCMA_MAX_BACKLOG;
+ ret = rdma_listen(ctx->cm_id, ctx->backlog);
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static ssize_t ucma_accept(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_accept cmd;
+ struct rdma_conn_param conn_param;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ if (cmd.conn_param.valid) {
+ ctx->uid = cmd.uid;
+ ucma_copy_conn_param(&conn_param, &cmd.conn_param);
+ ret = rdma_accept(ctx->cm_id, &conn_param);
+ } else
+ ret = rdma_accept(ctx->cm_id, NULL);
+
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static ssize_t ucma_reject(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_reject cmd;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ret = rdma_reject(ctx->cm_id, cmd.private_data, cmd.private_data_len);
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static ssize_t ucma_disconnect(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_disconnect cmd;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ret = rdma_disconnect(ctx->cm_id);
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static ssize_t ucma_init_qp_attr(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_init_qp_attr cmd;
+ struct ib_uverbs_qp_attr resp;
+ struct ucma_context *ctx;
+ struct ib_qp_attr qp_attr;
+ int ret;
+
+ if (out_len < sizeof(resp))
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ resp.qp_attr_mask = 0;
+ memset(&qp_attr, 0, sizeof qp_attr);
+ qp_attr.qp_state = cmd.qp_state;
+ ret = rdma_init_qp_attr(ctx->cm_id, &qp_attr, &resp.qp_attr_mask);
+ if (ret)
+ goto out;
+
+ ib_copy_qp_attr_to_user(&resp, &qp_attr);
+ if (copy_to_user((void __user *)(unsigned long)cmd.response,
+ &resp, sizeof(resp)))
+ ret = -EFAULT;
+
+out:
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_notify cmd;
+ struct ucma_context *ctx;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event);
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len) = {
+ [RDMA_USER_CM_CMD_CREATE_ID] = ucma_create_id,
+ [RDMA_USER_CM_CMD_DESTROY_ID] = ucma_destroy_id,
+ [RDMA_USER_CM_CMD_BIND_ADDR] = ucma_bind_addr,
+ [RDMA_USER_CM_CMD_RESOLVE_ADDR] = ucma_resolve_addr,
+ [RDMA_USER_CM_CMD_RESOLVE_ROUTE]= ucma_resolve_route,
+ [RDMA_USER_CM_CMD_QUERY_ROUTE] = ucma_query_route,
+ [RDMA_USER_CM_CMD_CONNECT] = ucma_connect,
+ [RDMA_USER_CM_CMD_LISTEN] = ucma_listen,
+ [RDMA_USER_CM_CMD_ACCEPT] = ucma_accept,
+ [RDMA_USER_CM_CMD_REJECT] = ucma_reject,
+ [RDMA_USER_CM_CMD_DISCONNECT] = ucma_disconnect,
+ [RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr,
+ [RDMA_USER_CM_CMD_GET_EVENT] = ucma_get_event,
+ [RDMA_USER_CM_CMD_GET_OPTION] = NULL,
+ [RDMA_USER_CM_CMD_SET_OPTION] = NULL,
+ [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify,
+};
+
+static ssize_t ucma_write(struct file *filp, const char __user *buf,
+ size_t len, loff_t *pos)
+{
+ struct ucma_file *file = filp->private_data;
+ struct rdma_ucm_cmd_hdr hdr;
+ ssize_t ret;
+
+ if (len < sizeof(hdr))
+ return -EINVAL;
+
+ if (copy_from_user(&hdr, buf, sizeof(hdr)))
+ return -EFAULT;
+
+ if (hdr.cmd < 0 || hdr.cmd >= ARRAY_SIZE(ucma_cmd_table))
+ return -EINVAL;
+
+ if (hdr.in + sizeof(hdr) > len)
+ return -EINVAL;
+
+ if (!ucma_cmd_table[hdr.cmd])
+ return -ENOSYS;
+
+ ret = ucma_cmd_table[hdr.cmd](file, buf + sizeof(hdr), hdr.in, hdr.out);
+ if (!ret)
+ ret = len;
+
+ return ret;
+}
+
+static unsigned int ucma_poll(struct file *filp, struct poll_table_struct *wait)
+{
+ struct ucma_file *file = filp->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(filp, &file->poll_wait, wait);
+
+ if (!list_empty(&file->event_list))
+ mask = POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+static int ucma_open(struct inode *inode, struct file *filp)
+{
+ struct ucma_file *file;
+
+ file = kmalloc(sizeof *file, GFP_KERNEL);
+ if (!file)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&file->event_list);
+ INIT_LIST_HEAD(&file->ctx_list);
+ init_waitqueue_head(&file->poll_wait);
+ mutex_init(&file->mut);
+
+ filp->private_data = file;
+ file->filp = filp;
+ return 0;
+}
+
+static int ucma_close(struct inode *inode, struct file *filp)
+{
+ struct ucma_file *file = filp->private_data;
+ struct ucma_context *ctx, *tmp;
+
+ mutex_lock(&file->mut);
+ list_for_each_entry_safe(ctx, tmp, &file->ctx_list, list) {
+ mutex_unlock(&file->mut);
+
+ mutex_lock(&mut);
+ idr_remove(&ctx_idr, ctx->id);
+ mutex_unlock(&mut);
+
+ ucma_free_ctx(ctx);
+ mutex_lock(&file->mut);
+ }
+ mutex_unlock(&file->mut);
+ kfree(file);
+ return 0;
+}
+
+static struct file_operations ucma_fops = {
+ .owner = THIS_MODULE,
+ .open = ucma_open,
+ .release = ucma_close,
+ .write = ucma_write,
+ .poll = ucma_poll,
+};
+
+static struct miscdevice ucma_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "rdma_cm",
+ .fops = &ucma_fops,
+};
+
+static ssize_t show_abi_version(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", RDMA_USER_CM_ABI_VERSION);
+}
+static DEVICE_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
+
+static int __init ucma_init(void)
+{
+ int ret;
+
+ ret = misc_register(&ucma_misc);
+ if (ret)
+ return ret;
+
+ ret = device_create_file(ucma_misc.this_device, &dev_attr_abi_version);
+ if (ret) {
+ printk(KERN_ERR "rdma_ucm: couldn't create abi_version attr\n");
+ goto err;
+ }
+ return 0;
+err:
+ misc_deregister(&ucma_misc);
+ return ret;
+}
+
+static void __exit ucma_cleanup(void)
+{
+ device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);
+ misc_deregister(&ucma_misc);
+ idr_destroy(&ctx_idr);
+}
+
+module_init(ucma_init);
+module_exit(ucma_cleanup);
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 743247ec065..df1efbc1088 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -933,7 +933,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
resp->wc[i].vendor_err = wc[i].vendor_err;
resp->wc[i].byte_len = wc[i].byte_len;
resp->wc[i].imm_data = (__u32 __force) wc[i].imm_data;
- resp->wc[i].qp_num = wc[i].qp_num;
+ resp->wc[i].qp_num = wc[i].qp->qp_num;
resp->wc[i].src_qp = wc[i].src_qp;
resp->wc[i].wc_flags = wc[i].wc_flags;
resp->wc[i].pkey_index = wc[i].pkey_index;
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 4e16314e8e6..a617ca7b692 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -534,9 +534,9 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
* module reference.
*/
filp->f_op = fops_get(&uverbs_event_fops);
- filp->f_vfsmnt = mntget(uverbs_event_mnt);
- filp->f_dentry = dget(uverbs_event_mnt->mnt_root);
- filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+ filp->f_path.mnt = mntget(uverbs_event_mnt);
+ filp->f_path.dentry = dget(uverbs_event_mnt->mnt_root);
+ filp->f_mapping = filp->f_path.dentry->d_inode->i_mapping;
filp->f_flags = O_RDONLY;
filp->f_mode = FMODE_READ;
filp->private_data = ev_file;
diff --git a/drivers/infiniband/core/uverbs_marshall.c b/drivers/infiniband/core/uverbs_marshall.c
index ce46b13ae02..5440da0e59b 100644
--- a/drivers/infiniband/core/uverbs_marshall.c
+++ b/drivers/infiniband/core/uverbs_marshall.c
@@ -32,8 +32,8 @@
#include <rdma/ib_marshall.h>
-static void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst,
- struct ib_ah_attr *src)
+void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst,
+ struct ib_ah_attr *src)
{
memcpy(dst->grh.dgid, src->grh.dgid.raw, sizeof src->grh.dgid);
dst->grh.flow_label = src->grh.flow_label;
@@ -47,6 +47,7 @@ static void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst,
dst->is_global = src->ah_flags & IB_AH_GRH ? 1 : 0;
dst->port_num = src->port_num;
}
+EXPORT_SYMBOL(ib_copy_ah_attr_to_user);
void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
struct ib_qp_attr *src)
diff --git a/drivers/infiniband/core/uverbs_mem.c b/drivers/infiniband/core/uverbs_mem.c
index db12cc0841d..c95fe952abd 100644
--- a/drivers/infiniband/core/uverbs_mem.c
+++ b/drivers/infiniband/core/uverbs_mem.c
@@ -52,8 +52,8 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d
int i;
list_for_each_entry_safe(chunk, tmp, &umem->chunk_list, list) {
- dma_unmap_sg(dev->dma_device, chunk->page_list,
- chunk->nents, DMA_BIDIRECTIONAL);
+ ib_dma_unmap_sg(dev, chunk->page_list,
+ chunk->nents, DMA_BIDIRECTIONAL);
for (i = 0; i < chunk->nents; ++i) {
if (umem->writable && dirty)
set_page_dirty_lock(chunk->page_list[i].page);
@@ -136,10 +136,10 @@ int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
chunk->page_list[i].length = PAGE_SIZE;
}
- chunk->nmap = dma_map_sg(dev->dma_device,
- &chunk->page_list[0],
- chunk->nents,
- DMA_BIDIRECTIONAL);
+ chunk->nmap = ib_dma_map_sg(dev,
+ &chunk->page_list[0],
+ chunk->nents,
+ DMA_BIDIRECTIONAL);
if (chunk->nmap <= 0) {
for (i = 0; i < chunk->nents; ++i)
put_page(chunk->page_list[i].page);
diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c
index 05c9154d46f..5175c99ee58 100644
--- a/drivers/infiniband/hw/amso1100/c2_cq.c
+++ b/drivers/infiniband/hw/amso1100/c2_cq.c
@@ -153,7 +153,7 @@ static inline int c2_poll_one(struct c2_dev *c2dev,
entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce));
entry->wr_id = ce->hdr.context;
- entry->qp_num = ce->handle;
+ entry->qp = &qp->ibqp;
entry->wc_flags = 0;
entry->slid = 0;
entry->sl = 0;
diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/infiniband/hw/amso1100/c2_qp.c
index 179d005ed4a..420c1380f5c 100644
--- a/drivers/infiniband/hw/amso1100/c2_qp.c
+++ b/drivers/infiniband/hw/amso1100/c2_qp.c
@@ -161,8 +161,10 @@ int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
if (attr_mask & IB_QP_STATE) {
/* Ensure the state is valid */
- if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR)
- return -EINVAL;
+ if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR) {
+ err = -EINVAL;
+ goto bail0;
+ }
wr.next_qp_state = cpu_to_be32(to_c2_state(attr->qp_state));
@@ -184,9 +186,10 @@ int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
if (attr->cur_qp_state != IB_QPS_RTR &&
attr->cur_qp_state != IB_QPS_RTS &&
attr->cur_qp_state != IB_QPS_SQD &&
- attr->cur_qp_state != IB_QPS_SQE)
- return -EINVAL;
- else
+ attr->cur_qp_state != IB_QPS_SQE) {
+ err = -EINVAL;
+ goto bail0;
+ } else
wr.next_qp_state =
cpu_to_be32(to_c2_state(attr->cur_qp_state));
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 1c722032319..cf95ee474b0 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -119,13 +119,14 @@ struct ehca_qp {
struct ipz_qp_handle ipz_qp_handle;
struct ehca_pfqp pf;
struct ib_qp_init_attr init_attr;
- u64 uspace_squeue;
- u64 uspace_rqueue;
- u64 uspace_fwh;
struct ehca_cq *send_cq;
struct ehca_cq *recv_cq;
unsigned int sqerr_purgeflag;
struct hlist_node list_entries;
+ /* mmap counter for resources mapped into user space */
+ u32 mm_count_squeue;
+ u32 mm_count_rqueue;
+ u32 mm_count_galpa;
};
/* must be power of 2 */
@@ -142,13 +143,14 @@ struct ehca_cq {
struct ipz_cq_handle ipz_cq_handle;
struct ehca_pfcq pf;
spinlock_t cb_lock;
- u64 uspace_queue;
- u64 uspace_fwh;
struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
struct list_head entry;
u32 nr_callbacks;
spinlock_t task_lock;
u32 ownpid;
+ /* mmap counter for resources mapped into user space */
+ u32 mm_count_queue;
+ u32 mm_count_galpa;
};
enum ehca_mr_flag {
@@ -248,20 +250,6 @@ struct ehca_ucontext {
struct ib_ucontext ib_ucontext;
};
-struct ehca_module *ehca_module_new(void);
-
-int ehca_module_delete(struct ehca_module *me);
-
-int ehca_eq_ctor(struct ehca_eq *eq);
-
-int ehca_eq_dtor(struct ehca_eq *eq);
-
-struct ehca_shca *ehca_shca_new(void);
-
-int ehca_shca_delete(struct ehca_shca *me);
-
-struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor);
-
int ehca_init_pd_cache(void);
void ehca_cleanup_pd_cache(void);
int ehca_init_cq_cache(void);
@@ -283,7 +271,6 @@ extern int ehca_port_act_time;
extern int ehca_use_hp_mr;
struct ipzu_queue_resp {
- u64 queue; /* points to first queue entry */
u32 qe_size; /* queue entry size */
u32 act_nr_of_sg;
u32 queue_length; /* queue length allocated in bytes */
@@ -296,7 +283,6 @@ struct ehca_create_cq_resp {
u32 cq_number;
u32 token;
struct ipzu_queue_resp ipz_queue;
- struct h_galpas galpas;
};
struct ehca_create_qp_resp {
@@ -309,7 +295,6 @@ struct ehca_create_qp_resp {
u32 dummy; /* padding for 8 byte alignment */
struct ipzu_queue_resp ipz_squeue;
struct ipzu_queue_resp ipz_rqueue;
- struct h_galpas galpas;
};
struct ehca_alloc_cq_parms {
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 93995b658d9..9291a86ca05 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -267,7 +267,6 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
if (context) {
struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
struct ehca_create_cq_resp resp;
- struct vm_area_struct *vma;
memset(&resp, 0, sizeof(resp));
resp.cq_number = my_cq->cq_number;
resp.token = my_cq->token;
@@ -276,40 +275,14 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
resp.ipz_queue.queue_length = ipz_queue->queue_length;
resp.ipz_queue.pagesize = ipz_queue->pagesize;
resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
- ret = ehca_mmap_nopage(((u64)(my_cq->token) << 32) | 0x12000000,
- ipz_queue->queue_length,
- (void**)&resp.ipz_queue.queue,
- &vma);
- if (ret) {
- ehca_err(device, "Could not mmap queue pages");
- cq = ERR_PTR(ret);
- goto create_cq_exit4;
- }
- my_cq->uspace_queue = resp.ipz_queue.queue;
- resp.galpas = my_cq->galpas;
- ret = ehca_mmap_register(my_cq->galpas.user.fw_handle,
- (void**)&resp.galpas.kernel.fw_handle,
- &vma);
- if (ret) {
- ehca_err(device, "Could not mmap fw_handle");
- cq = ERR_PTR(ret);
- goto create_cq_exit5;
- }
- my_cq->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
ehca_err(device, "Copy to udata failed.");
- goto create_cq_exit6;
+ goto create_cq_exit4;
}
}
return cq;
-create_cq_exit6:
- ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
-
-create_cq_exit5:
- ehca_munmap(my_cq->uspace_queue, my_cq->ipz_queue.queue_length);
-
create_cq_exit4:
ipz_queue_dtor(&my_cq->ipz_queue);
@@ -333,7 +306,6 @@ create_cq_exit1:
int ehca_destroy_cq(struct ib_cq *cq)
{
u64 h_ret;
- int ret;
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
int cq_num = my_cq->cq_number;
struct ib_device *device = cq->device;
@@ -343,32 +315,30 @@ int ehca_destroy_cq(struct ib_cq *cq)
u32 cur_pid = current->tgid;
unsigned long flags;
+ if (cq->uobject) {
+ if (my_cq->mm_count_galpa || my_cq->mm_count_queue) {
+ ehca_err(device, "Resources still referenced in "
+ "user space cq_num=%x", my_cq->cq_number);
+ return -EINVAL;
+ }
+ if (my_cq->ownpid != cur_pid) {
+ ehca_err(device, "Invalid caller pid=%x ownpid=%x "
+ "cq_num=%x",
+ cur_pid, my_cq->ownpid, my_cq->cq_number);
+ return -EINVAL;
+ }
+ }
+
spin_lock_irqsave(&ehca_cq_idr_lock, flags);
- while (my_cq->nr_callbacks)
+ while (my_cq->nr_callbacks) {
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
yield();
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ }
idr_remove(&ehca_cq_idr, my_cq->token);
spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
- if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
- ehca_err(device, "Invalid caller pid=%x ownpid=%x",
- cur_pid, my_cq->ownpid);
- return -EINVAL;
- }
-
- /* un-mmap if vma alloc */
- if (my_cq->uspace_queue ) {
- ret = ehca_munmap(my_cq->uspace_queue,
- my_cq->ipz_queue.queue_length);
- if (ret)
- ehca_err(device, "Could not munmap queue ehca_cq=%p "
- "cq_num=%x", my_cq, cq_num);
- ret = ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
- if (ret)
- ehca_err(device, "Could not munmap fwh ehca_cq=%p "
- "cq_num=%x", my_cq, cq_num);
- }
-
h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
if (h_ret == H_R_STATE) {
/* cq in err: read err data and destroy it forcibly */
@@ -397,7 +367,7 @@ int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
u32 cur_pid = current->tgid;
- if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
+ if (cq->uobject && my_cq->ownpid != cur_pid) {
ehca_err(cq->device, "Invalid caller pid=%x ownpid=%x",
cur_pid, my_cq->ownpid);
return -EINVAL;
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
index e1b618c5f68..b7be950ab47 100644
--- a/drivers/infiniband/hw/ehca/ehca_hca.c
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -50,7 +50,7 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
ib_device);
struct hipz_query_hca *rblock;
- rblock = ehca_alloc_fw_ctrlblock();
+ rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!rblock) {
ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
return -ENOMEM;
@@ -110,7 +110,7 @@ int ehca_query_port(struct ib_device *ibdev,
ib_device);
struct hipz_query_port *rblock;
- rblock = ehca_alloc_fw_ctrlblock();
+ rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!rblock) {
ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
return -ENOMEM;
@@ -179,7 +179,7 @@ int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
return -EINVAL;
}
- rblock = ehca_alloc_fw_ctrlblock();
+ rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!rblock) {
ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
return -ENOMEM;
@@ -212,7 +212,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
return -EINVAL;
}
- rblock = ehca_alloc_fw_ctrlblock();
+ rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!rblock) {
ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
return -ENOMEM;
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index c3ea746e904..c069be8cbcb 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -138,7 +138,7 @@ int ehca_error_data(struct ehca_shca *shca, void *data,
u64 *rblock;
unsigned long block_count;
- rblock = ehca_alloc_fw_ctrlblock();
+ rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
if (!rblock) {
ehca_err(&shca->ib_device, "Cannot allocate rblock memory.");
ret = -ENOMEM;
@@ -440,7 +440,8 @@ void ehca_tasklet_eq(unsigned long data)
cq = idr_find(&ehca_cq_idr, token);
if (cq == NULL) {
- spin_unlock(&ehca_cq_idr_lock);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock,
+ flags);
break;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index 3720e3032cc..95fd59fb452 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -171,19 +171,11 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
void ehca_poll_eqs(unsigned long data);
-int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped,
- struct vm_area_struct **vma);
-
-int ehca_mmap_register(u64 physical,void **mapped,
- struct vm_area_struct **vma);
-
-int ehca_munmap(unsigned long addr, size_t len);
-
#ifdef CONFIG_PPC_64K_PAGES
-void *ehca_alloc_fw_ctrlblock(void);
+void *ehca_alloc_fw_ctrlblock(gfp_t flags);
void ehca_free_fw_ctrlblock(void *ptr);
#else
-#define ehca_alloc_fw_ctrlblock() ((void *) get_zeroed_page(GFP_KERNEL))
+#define ehca_alloc_fw_ctrlblock(flags) ((void *) get_zeroed_page(flags))
#define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index cc47e4c13a1..1155bcf4821 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -52,7 +52,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_0019");
+MODULE_VERSION("SVNEHCA_0020");
int ehca_open_aqp1 = 0;
int ehca_debug_level = 0;
@@ -106,9 +106,9 @@ static struct timer_list poll_eqs_timer;
#ifdef CONFIG_PPC_64K_PAGES
static struct kmem_cache *ctblk_cache = NULL;
-void *ehca_alloc_fw_ctrlblock(void)
+void *ehca_alloc_fw_ctrlblock(gfp_t flags)
{
- void *ret = kmem_cache_zalloc(ctblk_cache, GFP_KERNEL);
+ void *ret = kmem_cache_zalloc(ctblk_cache, flags);
if (!ret)
ehca_gen_err("Out of memory for ctblk");
return ret;
@@ -206,7 +206,7 @@ int ehca_sense_attributes(struct ehca_shca *shca)
u64 h_ret;
struct hipz_query_hca *rblock;
- rblock = ehca_alloc_fw_ctrlblock();
+ rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!rblock) {
ehca_gen_err("Cannot allocate rblock memory.");
return -ENOMEM;
@@ -258,7 +258,7 @@ static int init_node_guid(struct ehca_shca *shca)
int ret = 0;
struct hipz_query_hca *rblock;
- rblock = ehca_alloc_fw_ctrlblock();
+ rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!rblock) {
ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
return -ENOMEM;
@@ -288,7 +288,7 @@ int ehca_init_device(struct ehca_shca *shca)
strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
shca->ib_device.owner = THIS_MODULE;
- shca->ib_device.uverbs_abi_ver = 5;
+ shca->ib_device.uverbs_abi_ver = 6;
shca->ib_device.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -469,7 +469,7 @@ static ssize_t ehca_show_##name(struct device *dev, \
\
shca = dev->driver_data; \
\
- rblock = ehca_alloc_fw_ctrlblock(); \
+ rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); \
if (!rblock) { \
dev_err(dev, "Can't allocate rblock memory."); \
return 0; \
@@ -790,7 +790,7 @@ int __init ehca_module_init(void)
int ret;
printk(KERN_INFO "eHCA Infiniband Device Driver "
- "(Rel.: SVNEHCA_0019)\n");
+ "(Rel.: SVNEHCA_0020)\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_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index 0a5e2214cc5..cfb362a1029 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -1013,7 +1013,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
u32 i;
u64 *kpage;
- kpage = ehca_alloc_fw_ctrlblock();
+ kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!kpage) {
ehca_err(&shca->ib_device, "kpage alloc failed");
ret = -ENOMEM;
@@ -1124,7 +1124,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
ehca_mrmw_map_acl(acl, &hipz_acl);
ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
- kpage = ehca_alloc_fw_ctrlblock();
+ kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!kpage) {
ehca_err(&shca->ib_device, "kpage alloc failed");
ret = -ENOMEM;
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index c6c9cef203e..95efef921f1 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -637,7 +637,6 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue;
struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue;
struct ehca_create_qp_resp resp;
- struct vm_area_struct * vma;
memset(&resp, 0, sizeof(resp));
resp.qp_num = my_qp->real_qp_num;
@@ -651,59 +650,21 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length;
resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize;
resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state;
- ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x22000000,
- ipz_rqueue->queue_length,
- (void**)&resp.ipz_rqueue.queue,
- &vma);
- if (ret) {
- ehca_err(pd->device, "Could not mmap rqueue pages");
- goto create_qp_exit3;
- }
- my_qp->uspace_rqueue = resp.ipz_rqueue.queue;
/* squeue properties */
resp.ipz_squeue.qe_size = ipz_squeue->qe_size;
resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg;
resp.ipz_squeue.queue_length = ipz_squeue->queue_length;
resp.ipz_squeue.pagesize = ipz_squeue->pagesize;
resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state;
- ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x23000000,
- ipz_squeue->queue_length,
- (void**)&resp.ipz_squeue.queue,
- &vma);
- if (ret) {
- ehca_err(pd->device, "Could not mmap squeue pages");
- goto create_qp_exit4;
- }
- my_qp->uspace_squeue = resp.ipz_squeue.queue;
- /* fw_handle */
- resp.galpas = my_qp->galpas;
- ret = ehca_mmap_register(my_qp->galpas.user.fw_handle,
- (void**)&resp.galpas.kernel.fw_handle,
- &vma);
- if (ret) {
- ehca_err(pd->device, "Could not mmap fw_handle");
- goto create_qp_exit5;
- }
- my_qp->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
-
if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
ehca_err(pd->device, "Copy to udata failed");
ret = -EINVAL;
- goto create_qp_exit6;
+ goto create_qp_exit3;
}
}
return &my_qp->ib_qp;
-create_qp_exit6:
- ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
-
-create_qp_exit5:
- ehca_munmap(my_qp->uspace_squeue, my_qp->ipz_squeue.queue_length);
-
-create_qp_exit4:
- ehca_munmap(my_qp->uspace_rqueue, my_qp->ipz_rqueue.queue_length);
-
create_qp_exit3:
ipz_queue_dtor(&my_qp->ipz_rqueue);
ipz_queue_dtor(&my_qp->ipz_squeue);
@@ -807,7 +768,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
unsigned long spl_flags = 0;
/* do query_qp to obtain current attr values */
- mqpcb = ehca_alloc_fw_ctrlblock();
+ mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!mqpcb) {
ehca_err(ibqp->device, "Could not get zeroed page for mqpcb "
"ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num);
@@ -931,7 +892,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
my_qp->qp_type == IB_QPT_SMI) &&
statetrans == IB_QPST_SQE2RTS) {
/* mark next free wqe if kernel */
- if (my_qp->uspace_squeue == 0) {
+ if (!ibqp->uobject) {
struct ehca_wqe *wqe;
/* lock send queue */
spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
@@ -1273,7 +1234,7 @@ int ehca_query_qp(struct ib_qp *qp,
return -EINVAL;
}
- qpcb = ehca_alloc_fw_ctrlblock();
+ qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!qpcb) {
ehca_err(qp->device,"Out of memory for qpcb "
"ehca_qp=%p qp_num=%x", my_qp, qp->qp_num);
@@ -1417,11 +1378,18 @@ int ehca_destroy_qp(struct ib_qp *ibqp)
enum ib_qp_type qp_type;
unsigned long flags;
- if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
- my_pd->ownpid != cur_pid) {
- ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
- cur_pid, my_pd->ownpid);
- return -EINVAL;
+ if (ibqp->uobject) {
+ if (my_qp->mm_count_galpa ||
+ my_qp->mm_count_rqueue || my_qp->mm_count_squeue) {
+ ehca_err(ibqp->device, "Resources still referenced in "
+ "user space qp_num=%x", ibqp->qp_num);
+ return -EINVAL;
+ }
+ if (my_pd->ownpid != cur_pid) {
+ ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
}
if (my_qp->send_cq) {
@@ -1439,24 +1407,6 @@ int ehca_destroy_qp(struct ib_qp *ibqp)
idr_remove(&ehca_qp_idr, my_qp->token);
spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
- /* un-mmap if vma alloc */
- if (my_qp->uspace_rqueue) {
- ret = ehca_munmap(my_qp->uspace_rqueue,
- my_qp->ipz_rqueue.queue_length);
- if (ret)
- ehca_err(ibqp->device, "Could not munmap rqueue "
- "qp_num=%x", qp_num);
- ret = ehca_munmap(my_qp->uspace_squeue,
- my_qp->ipz_squeue.queue_length);
- if (ret)
- ehca_err(ibqp->device, "Could not munmap squeue "
- "qp_num=%x", qp_num);
- ret = ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
- if (ret)
- ehca_err(ibqp->device, "Could not munmap fwh qp_num=%x",
- qp_num);
- }
-
h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
if (h_ret != H_SUCCESS) {
ehca_err(ibqp->device, "hipz_h_destroy_qp() failed rc=%lx "
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index b46bda1bf85..08d3f892d9f 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -579,7 +579,7 @@ poll_cq_one_read_cqe:
} else
wc->status = IB_WC_SUCCESS;
- wc->qp_num = cqe->local_qp_number;
+ wc->qp = NULL;
wc->byte_len = cqe->nr_bytes_transferred;
wc->pkey_index = cqe->pkey_index;
wc->slid = cqe->rlid;
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index e08764e4aef..73db920b694 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -68,105 +68,183 @@ int ehca_dealloc_ucontext(struct ib_ucontext *context)
return 0;
}
-struct page *ehca_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static void ehca_mm_open(struct vm_area_struct *vma)
{
- struct page *mypage = NULL;
- u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
- u32 idr_handle = fileoffset >> 32;
- u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
- u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
- u32 cur_pid = current->tgid;
- unsigned long flags;
- struct ehca_cq *cq;
- struct ehca_qp *qp;
- struct ehca_pd *pd;
- u64 offset;
- void *vaddr;
+ u32 *count = (u32*)vma->vm_private_data;
+ if (!count) {
+ ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
+ vma->vm_start, vma->vm_end);
+ return;
+ }
+ (*count)++;
+ if (!(*count))
+ ehca_gen_err("Use count overflow vm_start=%lx vm_end=%lx",
+ vma->vm_start, vma->vm_end);
+ ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
+ vma->vm_start, vma->vm_end, *count);
+}
- switch (q_type) {
- case 1: /* CQ */
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
- cq = idr_find(&ehca_cq_idr, idr_handle);
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+static void ehca_mm_close(struct vm_area_struct *vma)
+{
+ u32 *count = (u32*)vma->vm_private_data;
+ if (!count) {
+ ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
+ vma->vm_start, vma->vm_end);
+ return;
+ }
+ (*count)--;
+ ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
+ vma->vm_start, vma->vm_end, *count);
+}
- /* make sure this mmap really belongs to the authorized user */
- if (!cq) {
- ehca_gen_err("cq is NULL ret=NOPAGE_SIGBUS");
- return NOPAGE_SIGBUS;
+static struct vm_operations_struct vm_ops = {
+ .open = ehca_mm_open,
+ .close = ehca_mm_close,
+};
+
+static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
+ u32 *mm_count)
+{
+ int ret;
+ u64 vsize, physical;
+
+ vsize = vma->vm_end - vma->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);
+ return -EINVAL;
+ }
+
+ physical = galpas->user.fw_handle;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical);
+ /* VM_IO | VM_RESERVED are set by remap_pfn_range() */
+ ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT,
+ vsize, vma->vm_page_prot);
+ if (unlikely(ret)) {
+ ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
+ return -ENOMEM;
+ }
+
+ vma->vm_private_data = mm_count;
+ (*mm_count)++;
+ vma->vm_ops = &vm_ops;
+
+ return 0;
+}
+
+static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
+ u32 *mm_count)
+{
+ int ret;
+ u64 start, ofs;
+ struct page *page;
+
+ vma->vm_flags |= VM_RESERVED;
+ start = vma->vm_start;
+ for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) {
+ u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs);
+ page = virt_to_page(virt_addr);
+ ret = vm_insert_page(vma, start, page);
+ if (unlikely(ret)) {
+ ehca_gen_err("vm_insert_page() failed rc=%x", ret);
+ return ret;
}
+ start += PAGE_SIZE;
+ }
+ vma->vm_private_data = mm_count;
+ (*mm_count)++;
+ vma->vm_ops = &vm_ops;
- if (cq->ownpid != cur_pid) {
+ return 0;
+}
+
+static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq,
+ u32 rsrc_type)
+{
+ int ret;
+
+ switch (rsrc_type) {
+ case 1: /* galpa fw handle */
+ ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);
+ ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);
+ if (unlikely(ret)) {
ehca_err(cq->ib_cq.device,
- "Invalid caller pid=%x ownpid=%x",
- cur_pid, cq->ownpid);
- return NOPAGE_SIGBUS;
+ "ehca_mmap_fw() failed rc=%x cq_num=%x",
+ ret, cq->cq_number);
+ return ret;
}
+ break;
- if (rsrc_type == 2) {
- ehca_dbg(cq->ib_cq.device, "cq=%p cq queuearea", cq);
- offset = address - vma->vm_start;
- vaddr = ipz_qeit_calc(&cq->ipz_queue, offset);
- ehca_dbg(cq->ib_cq.device, "offset=%lx vaddr=%p",
- offset, vaddr);
- mypage = virt_to_page(vaddr);
+ case 2: /* cq queue_addr */
+ ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);
+ ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);
+ if (unlikely(ret)) {
+ ehca_err(cq->ib_cq.device,
+ "ehca_mmap_queue() failed rc=%x cq_num=%x",
+ ret, cq->cq_number);
+ return ret;
}
break;
- case 2: /* QP */
- spin_lock_irqsave(&ehca_qp_idr_lock, flags);
- qp = idr_find(&ehca_qp_idr, idr_handle);
- spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+ default:
+ ehca_err(cq->ib_cq.device, "bad resource type=%x cq_num=%x",
+ rsrc_type, cq->cq_number);
+ return -EINVAL;
+ }
- /* make sure this mmap really belongs to the authorized user */
- if (!qp) {
- ehca_gen_err("qp is NULL ret=NOPAGE_SIGBUS");
- return NOPAGE_SIGBUS;
+ return 0;
+}
+
+static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
+ u32 rsrc_type)
+{
+ int ret;
+
+ switch (rsrc_type) {
+ case 1: /* galpa fw handle */
+ ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);
+ ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);
+ if (unlikely(ret)) {
+ ehca_err(qp->ib_qp.device,
+ "remap_pfn_range() failed ret=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return -ENOMEM;
}
+ break;
- pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
- if (pd->ownpid != cur_pid) {
+ case 2: /* qp rqueue_addr */
+ ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
+ qp->ib_qp.qp_num);
+ ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue);
+ if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
- "Invalid caller pid=%x ownpid=%x",
- cur_pid, pd->ownpid);
- return NOPAGE_SIGBUS;
+ "ehca_mmap_queue(rq) failed rc=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return ret;
}
+ break;
- if (rsrc_type == 2) { /* rqueue */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueuearea", qp);
- offset = address - vma->vm_start;
- vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset);
- ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
- offset, vaddr);
- mypage = virt_to_page(vaddr);
- } else if (rsrc_type == 3) { /* squeue */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp squeuearea", qp);
- offset = address - vma->vm_start;
- vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset);
- ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
- offset, vaddr);
- mypage = virt_to_page(vaddr);
+ case 3: /* qp squeue_addr */
+ ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
+ qp->ib_qp.qp_num);
+ ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue);
+ if (unlikely(ret)) {
+ ehca_err(qp->ib_qp.device,
+ "ehca_mmap_queue(sq) failed rc=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return ret;
}
break;
default:
- ehca_gen_err("bad queue type %x", q_type);
- return NOPAGE_SIGBUS;
- }
-
- if (!mypage) {
- ehca_gen_err("Invalid page adr==NULL ret=NOPAGE_SIGBUS");
- return NOPAGE_SIGBUS;
+ ehca_err(qp->ib_qp.device, "bad resource type=%x qp=num=%x",
+ rsrc_type, qp->ib_qp.qp_num);
+ return -EINVAL;
}
- get_page(mypage);
- return mypage;
+ return 0;
}
-static struct vm_operations_struct ehcau_vm_ops = {
- .nopage = ehca_nopage,
-};
-
int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
{
u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
@@ -175,7 +253,6 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
u32 cur_pid = current->tgid;
u32 ret;
- u64 vsize, physical;
unsigned long flags;
struct ehca_cq *cq;
struct ehca_qp *qp;
@@ -201,44 +278,12 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context)
return -EINVAL;
- switch (rsrc_type) {
- case 1: /* galpa fw handle */
- ehca_dbg(cq->ib_cq.device, "cq=%p cq triggerarea", cq);
- vma->vm_flags |= VM_RESERVED;
- vsize = vma->vm_end - vma->vm_start;
- if (vsize != EHCA_PAGESIZE) {
- ehca_err(cq->ib_cq.device, "invalid vsize=%lx",
- vma->vm_end - vma->vm_start);
- return -EINVAL;
- }
-
- physical = cq->galpas.user.fw_handle;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_IO | VM_RESERVED;
-
- ehca_dbg(cq->ib_cq.device,
- "vsize=%lx physical=%lx", vsize, physical);
- ret = remap_pfn_range(vma, vma->vm_start,
- physical >> PAGE_SHIFT, vsize,
- vma->vm_page_prot);
- if (ret) {
- ehca_err(cq->ib_cq.device,
- "remap_pfn_range() failed ret=%x",
- ret);
- return -ENOMEM;
- }
- break;
-
- case 2: /* cq queue_addr */
- ehca_dbg(cq->ib_cq.device, "cq=%p cq q_addr", cq);
- vma->vm_flags |= VM_RESERVED;
- vma->vm_ops = &ehcau_vm_ops;
- break;
-
- default:
- ehca_err(cq->ib_cq.device, "bad resource type %x",
- rsrc_type);
- return -EINVAL;
+ ret = ehca_mmap_cq(vma, cq, rsrc_type);
+ if (unlikely(ret)) {
+ ehca_err(cq->ib_cq.device,
+ "ehca_mmap_cq() failed rc=%x cq_num=%x",
+ ret, cq->cq_number);
+ return ret;
}
break;
@@ -262,50 +307,12 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
if (!qp->ib_qp.uobject || qp->ib_qp.uobject->context != context)
return -EINVAL;
- switch (rsrc_type) {
- case 1: /* galpa fw handle */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp triggerarea", qp);
- vma->vm_flags |= VM_RESERVED;
- vsize = vma->vm_end - vma->vm_start;
- if (vsize != EHCA_PAGESIZE) {
- ehca_err(qp->ib_qp.device, "invalid vsize=%lx",
- vma->vm_end - vma->vm_start);
- return -EINVAL;
- }
-
- physical = qp->galpas.user.fw_handle;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_IO | VM_RESERVED;
-
- ehca_dbg(qp->ib_qp.device, "vsize=%lx physical=%lx",
- vsize, physical);
- ret = remap_pfn_range(vma, vma->vm_start,
- physical >> PAGE_SHIFT, vsize,
- vma->vm_page_prot);
- if (ret) {
- ehca_err(qp->ib_qp.device,
- "remap_pfn_range() failed ret=%x",
- ret);
- return -ENOMEM;
- }
- break;
-
- case 2: /* qp rqueue_addr */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueue_addr", qp);
- vma->vm_flags |= VM_RESERVED;
- vma->vm_ops = &ehcau_vm_ops;
- break;
-
- case 3: /* qp squeue_addr */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp squeue_addr", qp);
- vma->vm_flags |= VM_RESERVED;
- vma->vm_ops = &ehcau_vm_ops;
- break;
-
- default:
- ehca_err(qp->ib_qp.device, "bad resource type %x",
- rsrc_type);
- return -EINVAL;
+ ret = ehca_mmap_qp(vma, qp, rsrc_type);
+ if (unlikely(ret)) {
+ ehca_err(qp->ib_qp.device,
+ "ehca_mmap_qp() failed rc=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return ret;
}
break;
@@ -316,77 +323,3 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
return 0;
}
-
-int ehca_mmap_nopage(u64 foffset, u64 length, void **mapped,
- struct vm_area_struct **vma)
-{
- down_write(&current->mm->mmap_sem);
- *mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS,
- foffset);
- up_write(&current->mm->mmap_sem);
- if (!(*mapped)) {
- ehca_gen_err("couldn't mmap foffset=%lx length=%lx",
- foffset, length);
- return -EINVAL;
- }
-
- *vma = find_vma(current->mm, (u64)*mapped);
- if (!(*vma)) {
- down_write(&current->mm->mmap_sem);
- do_munmap(current->mm, 0, length);
- up_write(&current->mm->mmap_sem);
- ehca_gen_err("couldn't find vma queue=%p", *mapped);
- return -EINVAL;
- }
- (*vma)->vm_flags |= VM_RESERVED;
- (*vma)->vm_ops = &ehcau_vm_ops;
-
- return 0;
-}
-
-int ehca_mmap_register(u64 physical, void **mapped,
- struct vm_area_struct **vma)
-{
- int ret;
- unsigned long vsize;
- /* ehca hw supports only 4k page */
- ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma);
- if (ret) {
- ehca_gen_err("could'nt mmap physical=%lx", physical);
- return ret;
- }
-
- (*vma)->vm_flags |= VM_RESERVED;
- vsize = (*vma)->vm_end - (*vma)->vm_start;
- if (vsize != EHCA_PAGESIZE) {
- ehca_gen_err("invalid vsize=%lx",
- (*vma)->vm_end - (*vma)->vm_start);
- return -EINVAL;
- }
-
- (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot);
- (*vma)->vm_flags |= VM_IO | VM_RESERVED;
-
- ret = remap_pfn_range((*vma), (*vma)->vm_start,
- physical >> PAGE_SHIFT, vsize,
- (*vma)->vm_page_prot);
- if (ret) {
- ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
- return -ENOMEM;
- }
-
- return 0;
-
-}
-
-int ehca_munmap(unsigned long addr, size_t len) {
- int ret = 0;
- struct mm_struct *mm = current->mm;
- if (mm) {
- down_write(&mm->mmap_sem);
- ret = do_munmap(mm, addr, len);
- up_write(&mm->mmap_sem);
- }
- return ret;
-}
diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/infiniband/hw/ipath/Makefile
index 7dc10551cf1..ec2e603ea24 100644
--- a/drivers/infiniband/hw/ipath/Makefile
+++ b/drivers/infiniband/hw/ipath/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o
ib_ipath-y := \
ipath_cq.o \
ipath_diag.o \
+ ipath_dma.o \
ipath_driver.o \
ipath_eeprom.o \
ipath_file_ops.o \
diff --git a/drivers/infiniband/hw/ipath/ipath_dma.c b/drivers/infiniband/hw/ipath/ipath_dma.c
new file mode 100644
index 00000000000..6e0f2b8918c
--- /dev/null
+++ b/drivers/infiniband/hw/ipath/ipath_dma.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2006 QLogic, Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <rdma/ib_verbs.h>
+
+#include "ipath_verbs.h"
+
+#define BAD_DMA_ADDRESS ((u64) 0)
+
+/*
+ * The following functions implement driver specific replacements
+ * for the ib_dma_*() functions.
+ *
+ * These functions return kernel virtual addresses instead of
+ * device bus addresses since the driver uses the CPU to copy
+ * data instead of using hardware DMA.
+ */
+
+static int ipath_mapping_error(struct ib_device *dev, u64 dma_addr)
+{
+ return dma_addr == BAD_DMA_ADDRESS;
+}
+
+static u64 ipath_dma_map_single(struct ib_device *dev,
+ void *cpu_addr, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+ return (u64) cpu_addr;
+}
+
+static void ipath_dma_unmap_single(struct ib_device *dev,
+ u64 addr, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+}
+
+static u64 ipath_dma_map_page(struct ib_device *dev,
+ struct page *page,
+ unsigned long offset,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ u64 addr;
+
+ BUG_ON(!valid_dma_direction(direction));
+
+ if (offset + size > PAGE_SIZE) {
+ addr = BAD_DMA_ADDRESS;
+ goto done;
+ }
+
+ addr = (u64) page_address(page);
+ if (addr)
+ addr += offset;
+ /* TODO: handle highmem pages */
+
+done:
+ return addr;
+}
+
+static void ipath_dma_unmap_page(struct ib_device *dev,
+ u64 addr, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+}
+
+int ipath_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ u64 addr;
+ int i;
+ int ret = nents;
+
+ BUG_ON(!valid_dma_direction(direction));
+
+ for (i = 0; i < nents; i++) {
+ addr = (u64) page_address(sg[i].page);
+ /* TODO: handle highmem pages */
+ if (!addr) {
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static void ipath_unmap_sg(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+}
+
+static u64 ipath_sg_dma_address(struct ib_device *dev, struct scatterlist *sg)
+{
+ u64 addr = (u64) page_address(sg->page);
+
+ if (addr)
+ addr += sg->offset;
+ return addr;
+}
+
+static unsigned int ipath_sg_dma_len(struct ib_device *dev,
+ struct scatterlist *sg)
+{
+ return sg->length;
+}
+
+static void ipath_sync_single_for_cpu(struct ib_device *dev,
+ u64 addr,
+ size_t size,
+ enum dma_data_direction dir)
+{
+}
+
+static void ipath_sync_single_for_device(struct ib_device *dev,
+ u64 addr,
+ size_t size,
+ enum dma_data_direction dir)
+{
+}
+
+static void *ipath_dma_alloc_coherent(struct ib_device *dev, size_t size,
+ u64 *dma_handle, gfp_t flag)
+{
+ struct page *p;
+ void *addr = NULL;
+
+ p = alloc_pages(flag, get_order(size));
+ if (p)
+ addr = page_address(p);
+ if (dma_handle)
+ *dma_handle = (u64) addr;
+ return addr;
+}
+
+static void ipath_dma_free_coherent(struct ib_device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle)
+{
+ free_pages((unsigned long) cpu_addr, get_order(size));
+}
+
+struct ib_dma_mapping_ops ipath_dma_mapping_ops = {
+ ipath_mapping_error,
+ ipath_dma_map_single,
+ ipath_dma_unmap_single,
+ ipath_dma_map_page,
+ ipath_dma_unmap_page,
+ ipath_map_sg,
+ ipath_unmap_sg,
+ ipath_sg_dma_address,
+ ipath_sg_dma_len,
+ ipath_sync_single_for_cpu,
+ ipath_sync_single_for_device,
+ ipath_dma_alloc_coherent,
+ ipath_dma_free_coherent
+};
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 1aeddb48e35..ae7f21a0cdc 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -1825,8 +1825,6 @@ void ipath_write_kreg_port(const struct ipath_devdata *dd, ipath_kreg regno,
*/
void ipath_shutdown_device(struct ipath_devdata *dd)
{
- u64 val;
-
ipath_dbg("Shutting down the device\n");
dd->ipath_flags |= IPATH_LINKUNK;
@@ -1849,7 +1847,7 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
*/
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL);
/* flush it */
- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
/*
* enough for anything that's going to trickle out to have actually
* done so.
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index a9ddc6911f6..b932bcb67a5 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -699,7 +699,6 @@ 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:%u\n",
start_stop ? "en" : "dis", dd->ipath_unit,
@@ -729,7 +728,7 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport,
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
/* now be sure chip saw it before we return */
- tval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
if (start_stop) {
/*
* And try to be sure that tail reg update has happened too.
@@ -738,7 +737,7 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport,
* in memory copy, since we could overwrite an update by the
* chip if we did.
*/
- tval = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
+ ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
}
/* always; new head should be equal to new tail; see above */
bail:
@@ -1745,9 +1744,9 @@ static int ipath_assign_port(struct file *fp,
goto done;
}
- i_minor = iminor(fp->f_dentry->d_inode) - IPATH_USER_MINOR_BASE;
+ i_minor = iminor(fp->f_path.dentry->d_inode) - IPATH_USER_MINOR_BASE;
ipath_cdbg(VERBOSE, "open on dev %lx (minor %d)\n",
- (long)fp->f_dentry->d_inode->i_rdev, i_minor);
+ (long)fp->f_path.dentry->d_inode->i_rdev, i_minor);
if (i_minor)
ret = find_free_port(i_minor - 1, fp, uinfo);
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index d9ff283f725..79a60f020a2 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -118,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->i_private;
+ dd = file->f_path.dentry->d_inode->i_private;
for (i = 0; i < NUM_COUNTERS; i++)
counters[i] = ipath_snap_cntr(dd, i);
@@ -138,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->i_private;
+ dd = file->f_path.dentry->d_inode->i_private;
guid = be64_to_cpu(dd->ipath_guid);
@@ -177,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->i_private;
+ dd = file->f_path.dentry->d_inode->i_private;
/* so we only initialize non-zero fields. */
memset(portinfo, 0, sizeof portinfo);
@@ -324,7 +324,7 @@ static ssize_t flash_read(struct file *file, char __user *buf,
goto bail;
}
- dd = file->f_dentry->d_inode->i_private;
+ dd = file->f_path.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;
@@ -377,7 +377,7 @@ static ssize_t flash_write(struct file *file, const char __user *buf,
goto bail_tmp;
}
- dd = file->f_dentry->d_inode->i_private;
+ dd = file->f_path.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 e57c7a351cb..7468477ba83 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -1447,7 +1447,7 @@ static void ipath_ht_tidtemplate(struct ipath_devdata *dd)
static int ipath_ht_early_init(struct ipath_devdata *dd)
{
u32 __iomem *piobuf;
- u32 pioincr, val32, egrsize;
+ u32 pioincr, val32;
int i;
/*
@@ -1467,7 +1467,6 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
* errors interrupts if we ever see one).
*/
dd->ipath_rcvegrbufsize = dd->ipath_piosize2k;
- egrsize = dd->ipath_rcvegrbufsize;
/*
* the min() check here is currently a nop, but it may not
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index 6af89683f71..ae8bf9950c6 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -602,7 +602,7 @@ static void ipath_pe_init_hwerrors(struct ipath_devdata *dd)
*/
static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
{
- u64 val, tmp, config1, prev_val;
+ u64 val, config1, prev_val;
int ret = 0;
ipath_dbg("Trying to bringup serdes\n");
@@ -633,7 +633,7 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
| INFINIPATH_SERDC0_L1PWR_DN;
ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
/* be sure chip saw it */
- tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
udelay(5); /* need pll reset set at least for a bit */
/*
* after PLL is reset, set the per-lane Resets and TxIdle and
@@ -647,7 +647,7 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
"and txidle (%llx)\n", (unsigned long long) val);
ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
/* be sure chip saw it */
- tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
/* need PLL reset clear for at least 11 usec before lane
* resets cleared; give it a few more to be sure */
udelay(15);
@@ -851,12 +851,12 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd,
int pos, ret;
dd->ipath_msi_lo = 0; /* used as a flag during reset processing */
- dd->ipath_irq = pdev->irq;
ret = pci_enable_msi(dd->pcidev);
if (ret)
ipath_dev_err(dd, "pci_enable_msi failed: %d, "
"interrupts may not work\n", ret);
/* continue even if it fails, we may still be OK... */
+ dd->ipath_irq = pdev->irq;
if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) {
u16 control;
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index d819cca524c..d4f6b5239ef 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -347,10 +347,9 @@ done:
static int init_chip_reset(struct ipath_devdata *dd,
struct ipath_portdata **pdp)
{
- struct ipath_portdata *pd;
u32 rtmp;
- *pdp = pd = dd->ipath_pd[0];
+ *pdp = dd->ipath_pd[0];
/* ensure chip does no sends or receives while we re-initialize */
dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U;
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, 0);
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index 5652a550d44..72b9e279d19 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -598,10 +598,9 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
* on close
*/
if (errs & INFINIPATH_E_RRCVHDRFULL) {
- int any;
u32 hd, tl;
ipath_stats.sps_hdrqfull++;
- for (any = i = 0; i < dd->ipath_cfgports; i++) {
+ for (i = 0; i < dd->ipath_cfgports; i++) {
struct ipath_portdata *pd = dd->ipath_pd[i];
if (i == 0) {
hd = dd->ipath_port0head;
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
index 9a6cbd05adc..851763d7d2d 100644
--- a/drivers/infiniband/hw/ipath/ipath_keys.c
+++ b/drivers/infiniband/hw/ipath/ipath_keys.c
@@ -134,7 +134,7 @@ int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
*/
if (sge->lkey == 0) {
isge->mr = NULL;
- isge->vaddr = bus_to_virt(sge->addr);
+ isge->vaddr = (void *) sge->addr;
isge->length = sge->length;
isge->sge_length = sge->length;
ret = 1;
@@ -202,12 +202,12 @@ int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss,
int ret;
/*
- * We use RKEY == zero for physical addresses
- * (see ipath_get_dma_mr).
+ * We use RKEY == zero for kernel virtual addresses
+ * (see ipath_get_dma_mr and ipath_dma.c).
*/
if (rkey == 0) {
sge->mr = NULL;
- sge->vaddr = phys_to_virt(vaddr);
+ sge->vaddr = (void *) vaddr;
sge->length = len;
sge->sge_length = len;
ss->sg_list = NULL;
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c
index a0673c1eef7..8cc8598d6c6 100644
--- a/drivers/infiniband/hw/ipath/ipath_mr.c
+++ b/drivers/infiniband/hw/ipath/ipath_mr.c
@@ -54,6 +54,8 @@ static inline struct ipath_fmr *to_ifmr(struct ib_fmr *ibfmr)
* @acc: access flags
*
* Returns the memory region on success, otherwise returns an errno.
+ * Note that all DMA addresses should be created via the
+ * struct ib_dma_mapping_ops functions (see ipath_dma.c).
*/
struct ib_mr *ipath_get_dma_mr(struct ib_pd *pd, int acc)
{
@@ -149,8 +151,7 @@ struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd,
m = 0;
n = 0;
for (i = 0; i < num_phys_buf; i++) {
- mr->mr.map[m]->segs[n].vaddr =
- phys_to_virt(buffer_list[i].addr);
+ mr->mr.map[m]->segs[n].vaddr = (void *) buffer_list[i].addr;
mr->mr.map[m]->segs[n].length = buffer_list[i].size;
mr->mr.length += buffer_list[i].size;
n++;
@@ -347,7 +348,7 @@ int ipath_map_phys_fmr(struct ib_fmr *ibfmr, u64 * page_list,
n = 0;
ps = 1 << fmr->page_shift;
for (i = 0; i < list_len; i++) {
- fmr->mr.map[m]->segs[n].vaddr = phys_to_virt(page_list[i]);
+ fmr->mr.map[m]->segs[n].vaddr = (void *) page_list[i];
fmr->mr.map[m]->segs[n].length = ps;
if (++n == IPATH_SEGSZ) {
m++;
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 46c1c89bf6a..64f07b19349 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -379,7 +379,7 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
wc.pkey_index = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index ce6038743c5..5ff20cb0449 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -702,7 +702,7 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc->vendor_err = 0;
wc->byte_len = 0;
- wc->qp_num = qp->ibqp.qp_num;
+ wc->qp = &qp->ibqp;
wc->src_qp = qp->remote_qpn;
wc->pkey_index = 0;
wc->slid = qp->remote_ah_attr.dlid;
@@ -836,7 +836,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = wqe->length;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
@@ -951,7 +951,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
@@ -1511,7 +1511,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
wc.vendor_err = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index f7530512045..e86cb171872 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -137,7 +137,7 @@ bad_lkey:
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
wc.pkey_index = 0;
@@ -336,7 +336,7 @@ again:
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = 0;
- wc.qp_num = sqp->ibqp.qp_num;
+ wc.qp = &sqp->ibqp;
wc.src_qp = sqp->remote_qpn;
wc.pkey_index = 0;
wc.slid = sqp->remote_ah_attr.dlid;
@@ -426,7 +426,7 @@ again:
wc.status = IB_WC_SUCCESS;
wc.vendor_err = 0;
wc.byte_len = wqe->length;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
/* XXX do we know which pkey matched? Only needed for GSI. */
wc.pkey_index = 0;
@@ -447,7 +447,7 @@ send_comp:
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = wqe->length;
- wc.qp_num = sqp->ibqp.qp_num;
+ wc.qp = &sqp->ibqp;
wc.src_qp = 0;
wc.pkey_index = 0;
wc.slid = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index 182de34f9f4..ffa6318ad0c 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -215,7 +215,6 @@ static ssize_t store_mlid(struct device *dev,
size_t count)
{
struct ipath_devdata *dd = dev_get_drvdata(dev);
- int unit;
u16 mlid;
int ret;
@@ -223,8 +222,6 @@ static ssize_t store_mlid(struct device *dev,
if (ret < 0 || mlid < IPATH_MULTICAST_LID_BASE)
goto invalid;
- unit = dd->ipath_unit;
-
dd->ipath_mlid = mlid;
goto bail;
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index e636cfd67a8..325d6634ff5 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -49,7 +49,7 @@ static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe,
wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc->vendor_err = 0;
wc->byte_len = wqe->length;
- wc->qp_num = qp->ibqp.qp_num;
+ wc->qp = &qp->ibqp;
wc->src_qp = qp->remote_qpn;
wc->pkey_index = 0;
wc->slid = qp->remote_ah_attr.dlid;
@@ -411,7 +411,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
wc.vendor_err = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index 49f1102af8b..9a3e54664ee 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -66,7 +66,7 @@ bad_lkey:
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
wc.pkey_index = 0;
@@ -255,7 +255,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
wc->status = IB_WC_SUCCESS;
wc->opcode = IB_WC_RECV;
wc->vendor_err = 0;
- wc->qp_num = qp->ibqp.qp_num;
+ wc->qp = &qp->ibqp;
wc->src_qp = sqp->ibqp.qp_num;
/* XXX do we know which pkey matched? Only needed for GSI. */
wc->pkey_index = 0;
@@ -474,7 +474,7 @@ done:
wc.vendor_err = 0;
wc.opcode = IB_WC_SEND;
wc.byte_len = len;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
/* XXX initialize other fields? */
@@ -651,7 +651,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
wc.vendor_err = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = src_qp;
/* XXX do we know which pkey matched? Only needed for GSI. */
wc.pkey_index = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index acdee33ee1f..2aaacdb7e52 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -1599,6 +1599,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
dev->detach_mcast = ipath_multicast_detach;
dev->process_mad = ipath_process_mad;
dev->mmap = ipath_mmap;
+ dev->dma_ops = &ipath_dma_mapping_ops;
snprintf(dev->node_desc, sizeof(dev->node_desc),
IPATH_IDSTR " %s", init_utsname()->nodename);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index 8039f6e5f0c..c0c8d5b24a7 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -812,4 +812,6 @@ extern unsigned int ib_ipath_max_srq_wrs;
extern const u32 ib_ipath_rnr_table[];
+extern struct ib_dma_mapping_ops ipath_dma_mapping_ops;
+
#endif /* IPATH_VERBS_H */
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 768df7265b8..968d1519761 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -1854,7 +1854,7 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
memset(inbox + 256, 0, 256);
- MTHCA_PUT(inbox, in_wc->qp_num, MAD_IFC_MY_QPN_OFFSET);
+ MTHCA_PUT(inbox, in_wc->qp->qp_num, MAD_IFC_MY_QPN_OFFSET);
MTHCA_PUT(inbox, in_wc->src_qp, MAD_IFC_RQPN_OFFSET);
val = in_wc->sl << 4;
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 283d50b76c3..efd79ef109a 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -54,6 +54,10 @@ enum {
MTHCA_CQ_ENTRY_SIZE = 0x20
};
+enum {
+ MTHCA_ATOMIC_BYTE_LEN = 8
+};
+
/*
* Must be packed because start is 64 bits but only aligned to 32 bits.
*/
@@ -530,7 +534,7 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
}
}
- entry->qp_num = (*cur_qp)->qpn;
+ entry->qp = &(*cur_qp)->ibqp;
if (is_send) {
wq = &(*cur_qp)->sq;
@@ -599,11 +603,11 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
break;
case MTHCA_OPCODE_ATOMIC_CS:
entry->opcode = IB_WC_COMP_SWAP;
- entry->byte_len = be32_to_cpu(cqe->byte_cnt);
+ entry->byte_len = MTHCA_ATOMIC_BYTE_LEN;
break;
case MTHCA_OPCODE_ATOMIC_FA:
entry->opcode = IB_WC_FETCH_ADD;
- entry->byte_len = be32_to_cpu(cqe->byte_cnt);
+ entry->byte_len = MTHCA_ATOMIC_BYTE_LEN;
break;
case MTHCA_OPCODE_BIND_MW:
entry->opcode = IB_WC_BIND_MW;
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 0491ec7a7c0..44bc6cc734a 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -80,24 +80,61 @@ static int tune_pci = 0;
module_param(tune_pci, int, 0444);
MODULE_PARM_DESC(tune_pci, "increase PCI burst from the default set by BIOS if nonzero");
-struct mutex mthca_device_mutex;
+DEFINE_MUTEX(mthca_device_mutex);
+
+#define MTHCA_DEFAULT_NUM_QP (1 << 16)
+#define MTHCA_DEFAULT_RDB_PER_QP (1 << 2)
+#define MTHCA_DEFAULT_NUM_CQ (1 << 16)
+#define MTHCA_DEFAULT_NUM_MCG (1 << 13)
+#define MTHCA_DEFAULT_NUM_MPT (1 << 17)
+#define MTHCA_DEFAULT_NUM_MTT (1 << 20)
+#define MTHCA_DEFAULT_NUM_UDAV (1 << 15)
+#define MTHCA_DEFAULT_NUM_RESERVED_MTTS (1 << 18)
+#define MTHCA_DEFAULT_NUM_UARC_SIZE (1 << 18)
+
+static struct mthca_profile hca_profile = {
+ .num_qp = MTHCA_DEFAULT_NUM_QP,
+ .rdb_per_qp = MTHCA_DEFAULT_RDB_PER_QP,
+ .num_cq = MTHCA_DEFAULT_NUM_CQ,
+ .num_mcg = MTHCA_DEFAULT_NUM_MCG,
+ .num_mpt = MTHCA_DEFAULT_NUM_MPT,
+ .num_mtt = MTHCA_DEFAULT_NUM_MTT,
+ .num_udav = MTHCA_DEFAULT_NUM_UDAV, /* Tavor only */
+ .fmr_reserved_mtts = MTHCA_DEFAULT_NUM_RESERVED_MTTS, /* Tavor only */
+ .uarc_size = MTHCA_DEFAULT_NUM_UARC_SIZE, /* Arbel only */
+};
+
+module_param_named(num_qp, hca_profile.num_qp, int, 0444);
+MODULE_PARM_DESC(num_qp, "maximum number of QPs per HCA");
+
+module_param_named(rdb_per_qp, hca_profile.rdb_per_qp, int, 0444);
+MODULE_PARM_DESC(rdb_per_qp, "number of RDB buffers per QP");
+
+module_param_named(num_cq, hca_profile.num_cq, int, 0444);
+MODULE_PARM_DESC(num_cq, "maximum number of CQs per HCA");
+
+module_param_named(num_mcg, hca_profile.num_mcg, int, 0444);
+MODULE_PARM_DESC(num_mcg, "maximum number of multicast groups per HCA");
+
+module_param_named(num_mpt, hca_profile.num_mpt, int, 0444);
+MODULE_PARM_DESC(num_mpt,
+ "maximum number of memory protection table entries per HCA");
+
+module_param_named(num_mtt, hca_profile.num_mtt, int, 0444);
+MODULE_PARM_DESC(num_mtt,
+ "maximum number of memory translation table segments per HCA");
+
+module_param_named(num_udav, hca_profile.num_udav, int, 0444);
+MODULE_PARM_DESC(num_udav, "maximum number of UD address vectors per HCA");
+
+module_param_named(fmr_reserved_mtts, hca_profile.fmr_reserved_mtts, int, 0444);
+MODULE_PARM_DESC(fmr_reserved_mtts,
+ "number of memory translation table segments reserved for FMR");
static const char mthca_version[] __devinitdata =
DRV_NAME ": Mellanox InfiniBand HCA driver v"
DRV_VERSION " (" DRV_RELDATE ")\n";
-static struct mthca_profile default_profile = {
- .num_qp = 1 << 16,
- .rdb_per_qp = 4,
- .num_cq = 1 << 16,
- .num_mcg = 1 << 13,
- .num_mpt = 1 << 17,
- .num_mtt = 1 << 20,
- .num_udav = 1 << 15, /* Tavor only */
- .fmr_reserved_mtts = 1 << 18, /* Tavor only */
- .uarc_size = 1 << 18, /* Arbel only */
-};
-
static int mthca_tune_pci(struct mthca_dev *mdev)
{
int cap;
@@ -303,7 +340,7 @@ static int mthca_init_tavor(struct mthca_dev *mdev)
goto err_disable;
}
- profile = default_profile;
+ profile = hca_profile;
profile.num_uar = dev_lim.uar_size / PAGE_SIZE;
profile.uarc_size = 0;
if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
@@ -621,7 +658,7 @@ static int mthca_init_arbel(struct mthca_dev *mdev)
goto err_stop_fw;
}
- profile = default_profile;
+ profile = hca_profile;
profile.num_uar = dev_lim.uar_size / PAGE_SIZE;
profile.num_udav = 0;
if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
@@ -1278,11 +1315,55 @@ static struct pci_driver mthca_driver = {
.remove = __devexit_p(mthca_remove_one)
};
+static void __init __mthca_check_profile_val(const char *name, int *pval,
+ int pval_default)
+{
+ /* value must be positive and power of 2 */
+ int old_pval = *pval;
+
+ if (old_pval <= 0)
+ *pval = pval_default;
+ else
+ *pval = roundup_pow_of_two(old_pval);
+
+ if (old_pval != *pval) {
+ printk(KERN_WARNING PFX "Invalid value %d for %s in module parameter.\n",
+ old_pval, name);
+ printk(KERN_WARNING PFX "Corrected %s to %d.\n", name, *pval);
+ }
+}
+
+#define mthca_check_profile_val(name, default) \
+ __mthca_check_profile_val(#name, &hca_profile.name, default)
+
+static void __init mthca_validate_profile(void)
+{
+ mthca_check_profile_val(num_qp, MTHCA_DEFAULT_NUM_QP);
+ mthca_check_profile_val(rdb_per_qp, MTHCA_DEFAULT_RDB_PER_QP);
+ mthca_check_profile_val(num_cq, MTHCA_DEFAULT_NUM_CQ);
+ mthca_check_profile_val(num_mcg, MTHCA_DEFAULT_NUM_MCG);
+ mthca_check_profile_val(num_mpt, MTHCA_DEFAULT_NUM_MPT);
+ mthca_check_profile_val(num_mtt, MTHCA_DEFAULT_NUM_MTT);
+ mthca_check_profile_val(num_udav, MTHCA_DEFAULT_NUM_UDAV);
+ mthca_check_profile_val(fmr_reserved_mtts, MTHCA_DEFAULT_NUM_RESERVED_MTTS);
+
+ if (hca_profile.fmr_reserved_mtts >= hca_profile.num_mtt) {
+ printk(KERN_WARNING PFX "Invalid fmr_reserved_mtts module parameter %d.\n",
+ hca_profile.fmr_reserved_mtts);
+ printk(KERN_WARNING PFX "(Must be smaller than num_mtt %d)\n",
+ hca_profile.num_mtt);
+ hca_profile.fmr_reserved_mtts = hca_profile.num_mtt / 2;
+ printk(KERN_WARNING PFX "Corrected fmr_reserved_mtts to %d.\n",
+ hca_profile.fmr_reserved_mtts);
+ }
+}
+
static int __init mthca_init(void)
{
int ret;
- mutex_init(&mthca_device_mutex);
+ mthca_validate_profile();
+
ret = mthca_catas_init();
if (ret)
return ret;
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index 15cc2f6eb47..6b19645d946 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -232,7 +232,7 @@ void *mthca_table_find(struct mthca_icm_table *table, int obj)
list_for_each_entry(chunk, &icm->chunk_list, list) {
for (i = 0; i < chunk->npages; ++i) {
- if (chunk->mem[i].length >= offset) {
+ if (chunk->mem[i].length > offset) {
page = chunk->mem[i].page;
goto out;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 21422a3336a..7b96751695e 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -124,7 +124,7 @@ static int mthca_query_device(struct ib_device *ibdev,
props->max_map_per_fmr = 255;
else
props->max_map_per_fmr =
- (1 << (32 - long_log2(mdev->limits.num_mpts))) - 1;
+ (1 << (32 - ilog2(mdev->limits.num_mpts))) - 1;
err = 0;
out:
@@ -816,7 +816,7 @@ static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *uda
lkey = ucmd.lkey;
}
- ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, long_log2(entries), &status);
+ ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, ilog2(entries), &status);
if (status)
ret = -EINVAL;
@@ -1100,10 +1100,11 @@ static struct ib_fmr *mthca_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
struct mthca_fmr *fmr;
int err;
- fmr = kmemdup(fmr_attr, sizeof *fmr, GFP_KERNEL);
+ fmr = kmalloc(sizeof *fmr, GFP_KERNEL);
if (!fmr)
return ERR_PTR(-ENOMEM);
+ memcpy(&fmr->attr, fmr_attr, sizeof *fmr_attr);
err = mthca_fmr_alloc(to_mdev(pd->device), to_mpd(pd)->pd_num,
convert_access(mr_access_flags), fmr);
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 33e3ba7937f..5f5214c0337 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -429,13 +429,18 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m
{
struct mthca_dev *dev = to_mdev(ibqp->device);
struct mthca_qp *qp = to_mqp(ibqp);
- int err;
- struct mthca_mailbox *mailbox;
+ int err = 0;
+ struct mthca_mailbox *mailbox = NULL;
struct mthca_qp_param *qp_param;
struct mthca_qp_context *context;
int mthca_state;
u8 status;
+ if (qp->state == IB_QPS_RESET) {
+ qp_attr->qp_state = IB_QPS_RESET;
+ goto done;
+ }
+
mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
if (IS_ERR(mailbox))
return PTR_ERR(mailbox);
@@ -454,7 +459,6 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m
mthca_state = be32_to_cpu(context->flags) >> 28;
qp_attr->qp_state = to_ib_qp_state(mthca_state);
- qp_attr->cur_qp_state = qp_attr->qp_state;
qp_attr->path_mtu = context->mtu_msgmax >> 5;
qp_attr->path_mig_state =
to_ib_mig_state((be32_to_cpu(context->flags) >> 11) & 0x3);
@@ -464,11 +468,6 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m
qp_attr->dest_qp_num = be32_to_cpu(context->remote_qpn) & 0xffffff;
qp_attr->qp_access_flags =
to_ib_qp_access_flags(be32_to_cpu(context->params2));
- qp_attr->cap.max_send_wr = qp->sq.max;
- qp_attr->cap.max_recv_wr = qp->rq.max;
- qp_attr->cap.max_send_sge = qp->sq.max_gs;
- qp_attr->cap.max_recv_sge = qp->rq.max_gs;
- qp_attr->cap.max_inline_data = qp->max_inline_data;
if (qp->transport == RC || qp->transport == UC) {
to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path);
@@ -495,7 +494,16 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m
qp_attr->retry_cnt = (be32_to_cpu(context->params1) >> 16) & 0x7;
qp_attr->rnr_retry = context->pri_path.rnr_retry >> 5;
qp_attr->alt_timeout = context->alt_path.ackto >> 3;
- qp_init_attr->cap = qp_attr->cap;
+
+done:
+ qp_attr->cur_qp_state = qp_attr->qp_state;
+ qp_attr->cap.max_send_wr = qp->sq.max;
+ qp_attr->cap.max_recv_wr = qp->rq.max;
+ qp_attr->cap.max_send_sge = qp->sq.max_gs;
+ qp_attr->cap.max_recv_sge = qp->rq.max_gs;
+ qp_attr->cap.max_inline_data = qp->max_inline_data;
+
+ qp_init_attr->cap = qp_attr->cap;
out:
mthca_free_mailbox(dev, mailbox);
@@ -636,11 +644,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
if (mthca_is_memfree(dev)) {
if (qp->rq.max)
- qp_context->rq_size_stride = long_log2(qp->rq.max) << 3;
+ qp_context->rq_size_stride = ilog2(qp->rq.max) << 3;
qp_context->rq_size_stride |= qp->rq.wqe_shift - 4;
if (qp->sq.max)
- qp_context->sq_size_stride = long_log2(qp->sq.max) << 3;
+ qp_context->sq_size_stride = ilog2(qp->sq.max) << 3;
qp_context->sq_size_stride |= qp->sq.wqe_shift - 4;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index 34d2c476896..10684da33d5 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -120,7 +120,7 @@ static void mthca_arbel_init_srq_context(struct mthca_dev *dev,
memset(context, 0, sizeof *context);
- logsize = long_log2(srq->max);
+ logsize = ilog2(srq->max);
context->state_logsize_srqn = cpu_to_be32(logsize << 24 | srq->srqn);
context->lkey = cpu_to_be32(srq->mr.ibmr.lkey);
context->db_index = cpu_to_be32(srq->db_index);
@@ -213,7 +213,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
if (!mthca_is_memfree(dev) && (ds > dev->limits.max_desc_sz))
return -EINVAL;
- srq->wqe_shift = long_log2(ds);
+ srq->wqe_shift = ilog2(ds);
srq->srqn = mthca_alloc(&dev->srq_table.alloc);
if (srq->srqn == -1)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 99547996aba..07deee8f81c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -105,12 +105,12 @@ struct ipoib_mcast;
struct ipoib_rx_buf {
struct sk_buff *skb;
- dma_addr_t mapping;
+ u64 mapping;
};
struct ipoib_tx_buf {
struct sk_buff *skb;
- DECLARE_PCI_UNMAP_ADDR(mapping)
+ u64 mapping;
};
/*
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index f10fba5d326..59d9594ed6d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -109,9 +109,8 @@ static int ipoib_ib_post_receive(struct net_device *dev, int id)
ret = ib_post_recv(priv->qp, &param, &bad_wr);
if (unlikely(ret)) {
ipoib_warn(priv, "receive failed for buf %d (%d)\n", id, ret);
- dma_unmap_single(priv->ca->dma_device,
- priv->rx_ring[id].mapping,
- IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
+ ib_dma_unmap_single(priv->ca, priv->rx_ring[id].mapping,
+ IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
dev_kfree_skb_any(priv->rx_ring[id].skb);
priv->rx_ring[id].skb = NULL;
}
@@ -123,7 +122,7 @@ static int ipoib_alloc_rx_skb(struct net_device *dev, int id)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct sk_buff *skb;
- dma_addr_t addr;
+ u64 addr;
skb = dev_alloc_skb(IPOIB_BUF_SIZE + 4);
if (!skb)
@@ -136,10 +135,9 @@ static int ipoib_alloc_rx_skb(struct net_device *dev, int id)
*/
skb_reserve(skb, 4);
- addr = dma_map_single(priv->ca->dma_device,
- skb->data, IPOIB_BUF_SIZE,
- DMA_FROM_DEVICE);
- if (unlikely(dma_mapping_error(addr))) {
+ addr = ib_dma_map_single(priv->ca, skb->data, IPOIB_BUF_SIZE,
+ DMA_FROM_DEVICE);
+ if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
dev_kfree_skb_any(skb);
return -EIO;
}
@@ -174,7 +172,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
struct ipoib_dev_priv *priv = netdev_priv(dev);
unsigned int wr_id = wc->wr_id & ~IPOIB_OP_RECV;
struct sk_buff *skb;
- dma_addr_t addr;
+ u64 addr;
ipoib_dbg_data(priv, "recv completion: id %d, op %d, status: %d\n",
wr_id, wc->opcode, wc->status);
@@ -193,8 +191,8 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
ipoib_warn(priv, "failed recv event "
"(status=%d, wrid=%d vend_err %x)\n",
wc->status, wr_id, wc->vendor_err);
- dma_unmap_single(priv->ca->dma_device, addr,
- IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
+ ib_dma_unmap_single(priv->ca, addr,
+ IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
priv->rx_ring[wr_id].skb = NULL;
return;
@@ -212,8 +210,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
wc->byte_len, wc->slid);
- dma_unmap_single(priv->ca->dma_device, addr,
- IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
+ ib_dma_unmap_single(priv->ca, addr, IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
skb_put(skb, wc->byte_len);
skb_pull(skb, IB_GRH_BYTES);
@@ -261,10 +258,8 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
tx_req = &priv->tx_ring[wr_id];
- dma_unmap_single(priv->ca->dma_device,
- pci_unmap_addr(tx_req, mapping),
- tx_req->skb->len,
- DMA_TO_DEVICE);
+ ib_dma_unmap_single(priv->ca, tx_req->mapping,
+ tx_req->skb->len, DMA_TO_DEVICE);
++priv->stats.tx_packets;
priv->stats.tx_bytes += tx_req->skb->len;
@@ -311,7 +306,7 @@ void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
static inline int post_send(struct ipoib_dev_priv *priv,
unsigned int wr_id,
struct ib_ah *address, u32 qpn,
- dma_addr_t addr, int len)
+ u64 addr, int len)
{
struct ib_send_wr *bad_wr;
@@ -330,7 +325,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_tx_buf *tx_req;
- dma_addr_t addr;
+ u64 addr;
if (unlikely(skb->len > dev->mtu + INFINIBAND_ALEN)) {
ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
@@ -353,21 +348,20 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
*/
tx_req = &priv->tx_ring[priv->tx_head & (ipoib_sendq_size - 1)];
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))) {
+ addr = ib_dma_map_single(priv->ca, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
++priv->stats.tx_errors;
dev_kfree_skb_any(skb);
return;
}
- pci_unmap_addr_set(tx_req, mapping, addr);
+ tx_req->mapping = addr;
if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
address->ah, qpn, addr, skb->len))) {
ipoib_warn(priv, "post_send failed\n");
++priv->stats.tx_errors;
- dma_unmap_single(priv->ca->dma_device, addr, skb->len,
- DMA_TO_DEVICE);
+ ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
} else {
dev->trans_start = jiffies;
@@ -538,24 +532,27 @@ int ipoib_ib_dev_stop(struct net_device *dev)
while ((int) priv->tx_tail - (int) priv->tx_head < 0) {
tx_req = &priv->tx_ring[priv->tx_tail &
(ipoib_sendq_size - 1)];
- dma_unmap_single(priv->ca->dma_device,
- pci_unmap_addr(tx_req, mapping),
- tx_req->skb->len,
- DMA_TO_DEVICE);
+ ib_dma_unmap_single(priv->ca,
+ tx_req->mapping,
+ tx_req->skb->len,
+ DMA_TO_DEVICE);
dev_kfree_skb_any(tx_req->skb);
++priv->tx_tail;
}
- for (i = 0; i < ipoib_recvq_size; ++i)
- if (priv->rx_ring[i].skb) {
- dma_unmap_single(priv->ca->dma_device,
- pci_unmap_addr(&priv->rx_ring[i],
- mapping),
- IPOIB_BUF_SIZE,
- DMA_FROM_DEVICE);
- dev_kfree_skb_any(priv->rx_ring[i].skb);
- priv->rx_ring[i].skb = NULL;
- }
+ for (i = 0; i < ipoib_recvq_size; ++i) {
+ struct ipoib_rx_buf *rx_req;
+
+ rx_req = &priv->rx_ring[i];
+ if (!rx_req->skb)
+ continue;
+ ib_dma_unmap_single(priv->ca,
+ rx_req->mapping,
+ IPOIB_BUF_SIZE,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(rx_req->skb);
+ rx_req->skb = NULL;
+ }
goto timeout;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index c0928024372..af5ee2ec449 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -497,8 +497,6 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
return;
}
- skb_queue_head_init(&neigh->queue);
-
/*
* We can only be called from ipoib_start_xmit, so we're
* inside tx_lock -- no need to save/restore flags.
@@ -806,6 +804,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
neigh->neighbour = neighbour;
*to_ipoib_neigh(neighbour) = neigh;
+ skb_queue_head_init(&neigh->queue);
return neigh;
}
@@ -959,16 +958,17 @@ struct ipoib_dev_priv *ipoib_intf_alloc(const char *name)
return netdev_priv(dev);
}
-static ssize_t show_pkey(struct class_device *cdev, char *buf)
+static ssize_t show_pkey(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct ipoib_dev_priv *priv =
- netdev_priv(container_of(cdev, struct net_device, class_dev));
+ struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "0x%04x\n", priv->pkey);
}
-static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
-static ssize_t create_child(struct class_device *cdev,
+static ssize_t create_child(struct device *dev,
+ struct device_attribute *attr,
const char *buf, size_t count)
{
int pkey;
@@ -986,14 +986,14 @@ static ssize_t create_child(struct class_device *cdev,
*/
pkey |= 0x8000;
- ret = ipoib_vlan_add(container_of(cdev, struct net_device, class_dev),
- pkey);
+ ret = ipoib_vlan_add(to_net_dev(dev), pkey);
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child);
+static DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child);
-static ssize_t delete_child(struct class_device *cdev,
+static ssize_t delete_child(struct device *dev,
+ struct device_attribute *attr,
const char *buf, size_t count)
{
int pkey;
@@ -1005,18 +1005,16 @@ static ssize_t delete_child(struct class_device *cdev,
if (pkey < 0 || pkey > 0xffff)
return -EINVAL;
- ret = ipoib_vlan_delete(container_of(cdev, struct net_device, class_dev),
- pkey);
+ ret = ipoib_vlan_delete(to_net_dev(dev), pkey);
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child);
+static DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child);
int ipoib_add_pkey_attr(struct net_device *dev)
{
- return class_device_create_file(&dev->class_dev,
- &class_device_attr_pkey);
+ return device_create_file(&dev->dev, &dev_attr_pkey);
}
static struct net_device *ipoib_add_port(const char *format,
@@ -1084,11 +1082,9 @@ static struct net_device *ipoib_add_port(const char *format,
if (ipoib_add_pkey_attr(priv->dev))
goto sysfs_failed;
- if (class_device_create_file(&priv->dev->class_dev,
- &class_device_attr_create_child))
+ if (device_create_file(&priv->dev->dev, &dev_attr_create_child))
goto sysfs_failed;
- if (class_device_create_file(&priv->dev->class_dev,
- &class_device_attr_delete_child))
+ if (device_create_file(&priv->dev->dev, &dev_attr_delete_child))
goto sysfs_failed;
return priv->dev;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index f887780e809..085eafe6667 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -42,15 +42,15 @@
#include "ipoib.h"
-static ssize_t show_parent(struct class_device *class_dev, char *buf)
+static ssize_t show_parent(struct device *d, struct device_attribute *attr,
+ char *buf)
{
- struct net_device *dev =
- container_of(class_dev, struct net_device, class_dev);
+ struct net_device *dev = to_net_dev(d);
struct ipoib_dev_priv *priv = netdev_priv(dev);
return sprintf(buf, "%s\n", priv->parent->name);
}
-static CLASS_DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
+static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
{
@@ -118,8 +118,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
if (ipoib_add_pkey_attr(priv->dev))
goto sysfs_failed;
- if (class_device_create_file(&priv->dev->class_dev,
- &class_device_attr_parent))
+ if (device_create_file(&priv->dev->dev, &dev_attr_parent))
goto sysfs_failed;
list_add_tail(&priv->list, &ppriv->child_intfs);
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 9b2041e25d5..dd221eda3ea 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -177,7 +177,7 @@ iscsi_iser_mtask_xmit(struct iscsi_conn *conn,
* - if yes, the mtask is recycled at iscsi_complete_pdu
* - if no, the mtask is recycled at iser_snd_completion
*/
- if (error && error != -EAGAIN)
+ if (error && error != -ENOBUFS)
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return error;
@@ -241,7 +241,7 @@ iscsi_iser_ctask_xmit(struct iscsi_conn *conn,
error = iscsi_iser_ctask_xmit_unsol_data(conn, ctask);
iscsi_iser_ctask_xmit_exit:
- if (error && error != -EAGAIN)
+ if (error && error != -ENOBUFS)
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return error;
}
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 234e5b061a7..cae8c96a55f 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -182,7 +182,7 @@ struct iser_regd_buf {
struct iser_mem_reg reg; /* memory registration info */
void *virt_addr;
struct iser_device *device; /* device->device for dma_unmap */
- dma_addr_t dma_addr; /* if non zero, addr for dma_unmap */
+ u64 dma_addr; /* if non zero, addr for dma_unmap */
enum dma_data_direction direction; /* direction for dma_unmap */
unsigned int data_size;
atomic_t ref_count; /* refcount, freed when dec to 0 */
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 9b3d79c796c..89e37283c83 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -304,18 +304,14 @@ int iser_conn_set_full_featured_mode(struct iscsi_conn *conn)
static int
iser_check_xmit(struct iscsi_conn *conn, void *task)
{
- int rc = 0;
struct iscsi_iser_conn *iser_conn = conn->dd_data;
- write_lock_bh(conn->recv_lock);
if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) ==
ISER_QP_MAX_REQ_DTOS) {
- iser_dbg("%ld can't xmit task %p, suspending tx\n",jiffies,task);
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- rc = -EAGAIN;
+ iser_dbg("%ld can't xmit task %p\n",jiffies,task);
+ return -ENOBUFS;
}
- write_unlock_bh(conn->recv_lock);
- return rc;
+ return 0;
}
@@ -340,7 +336,7 @@ int iser_send_command(struct iscsi_conn *conn,
return -EPERM;
}
if (iser_check_xmit(conn, ctask))
- return -EAGAIN;
+ return -ENOBUFS;
edtl = ntohl(hdr->data_length);
@@ -426,7 +422,7 @@ int iser_send_data_out(struct iscsi_conn *conn,
}
if (iser_check_xmit(conn, ctask))
- return -EAGAIN;
+ return -ENOBUFS;
itt = ntohl(hdr->itt);
data_seg_len = ntoh24(hdr->dlength);
@@ -487,10 +483,8 @@ int iser_send_control(struct iscsi_conn *conn,
struct iscsi_iser_conn *iser_conn = conn->dd_data;
struct iser_desc *mdesc = mtask->dd_data;
struct iser_dto *send_dto = NULL;
- unsigned int itt;
unsigned long data_seg_len;
int err = 0;
- unsigned char opcode;
struct iser_regd_buf *regd_buf;
struct iser_device *device;
@@ -500,7 +494,7 @@ int iser_send_control(struct iscsi_conn *conn,
}
if (iser_check_xmit(conn,mtask))
- return -EAGAIN;
+ return -ENOBUFS;
/* build the tx desc regd header and add it to the tx desc dto */
mdesc->type = ISCSI_TX_CONTROL;
@@ -512,8 +506,6 @@ int iser_send_control(struct iscsi_conn *conn,
iser_reg_single(device, send_dto->regd[0], DMA_TO_DEVICE);
- itt = ntohl(mtask->hdr->itt);
- opcode = mtask->hdr->opcode & ISCSI_OPCODE_MASK;
data_seg_len = ntoh24(mtask->hdr->dlength);
if (data_seg_len > 0) {
@@ -575,7 +567,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc,
opcode = hdr->opcode & ISCSI_OPCODE_MASK;
if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
- itt = hdr->itt & ISCSI_ITT_MASK; /* mask out cid and age bits */
+ itt = get_itt(hdr->itt); /* mask out cid and age bits */
if (!(itt < session->cmds_max))
iser_err("itt can't be matched to task!!!"
"conn %p opcode %d cmds_max %d itt %d\n",
@@ -609,6 +601,7 @@ void iser_snd_completion(struct iser_desc *tx_desc)
struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn;
struct iscsi_conn *conn = iser_conn->iscsi_conn;
struct iscsi_mgmt_task *mtask;
+ int resume_tx = 0;
iser_dbg("Initiator, Data sent dto=0x%p\n", dto);
@@ -617,21 +610,22 @@ void iser_snd_completion(struct iser_desc *tx_desc)
if (tx_desc->type == ISCSI_TX_DATAOUT)
kmem_cache_free(ig.desc_cache, tx_desc);
+ if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) ==
+ ISER_QP_MAX_REQ_DTOS)
+ resume_tx = 1;
+
atomic_dec(&ib_conn->post_send_buf_count);
- write_lock(conn->recv_lock);
- if (conn->suspend_tx) {
+ if (resume_tx) {
iser_dbg("%ld resuming tx\n",jiffies);
- clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
scsi_queue_work(conn->session->host, &conn->xmitwork);
}
- write_unlock(conn->recv_lock);
if (tx_desc->type == ISCSI_TX_CONTROL) {
/* this arithmetic is legal by libiscsi dd_data allocation */
mtask = (void *) ((long)(void *)tx_desc -
sizeof(struct iscsi_mgmt_task));
- if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
+ if (mtask->hdr->itt == RESERVED_ITT) {
struct iscsi_session *session = conn->session;
spin_lock(&conn->session->lock);
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index 5e122501fd8..fc9f1fd0ae5 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -52,7 +52,7 @@
*/
int iser_regd_buff_release(struct iser_regd_buf *regd_buf)
{
- struct device *dma_device;
+ struct ib_device *dev;
if ((atomic_read(&regd_buf->ref_count) == 0) ||
atomic_dec_and_test(&regd_buf->ref_count)) {
@@ -61,8 +61,8 @@ int iser_regd_buff_release(struct iser_regd_buf *regd_buf)
iser_unreg_mem(&regd_buf->reg);
if (regd_buf->dma_addr) {
- dma_device = regd_buf->device->ib_device->dma_device;
- dma_unmap_single(dma_device,
+ dev = regd_buf->device->ib_device;
+ ib_dma_unmap_single(dev,
regd_buf->dma_addr,
regd_buf->data_size,
regd_buf->direction);
@@ -84,12 +84,12 @@ void iser_reg_single(struct iser_device *device,
struct iser_regd_buf *regd_buf,
enum dma_data_direction direction)
{
- dma_addr_t dma_addr;
+ u64 dma_addr;
- dma_addr = dma_map_single(device->ib_device->dma_device,
- regd_buf->virt_addr,
- regd_buf->data_size, direction);
- BUG_ON(dma_mapping_error(dma_addr));
+ dma_addr = ib_dma_map_single(device->ib_device,
+ regd_buf->virt_addr,
+ regd_buf->data_size, direction);
+ BUG_ON(ib_dma_mapping_error(device->ib_device, dma_addr));
regd_buf->reg.lkey = device->mr->lkey;
regd_buf->reg.len = regd_buf->data_size;
@@ -107,14 +107,14 @@ int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
enum iser_data_dir cmd_dir)
{
int dma_nents;
- struct device *dma_device;
+ struct ib_device *dev;
char *mem = NULL;
struct iser_data_buf *data = &iser_ctask->data[cmd_dir];
unsigned long cmd_data_len = data->data_len;
if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
mem = (void *)__get_free_pages(GFP_NOIO,
- long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+ ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
else
mem = kmalloc(cmd_data_len, GFP_NOIO);
@@ -147,17 +147,12 @@ int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
iser_ctask->data_copy[cmd_dir].copy_buf = mem;
- dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
-
- if (cmd_dir == ISER_DIR_OUT)
- dma_nents = dma_map_sg(dma_device,
- &iser_ctask->data_copy[cmd_dir].sg_single,
- 1, DMA_TO_DEVICE);
- else
- dma_nents = dma_map_sg(dma_device,
- &iser_ctask->data_copy[cmd_dir].sg_single,
- 1, DMA_FROM_DEVICE);
-
+ dev = iser_ctask->iser_conn->ib_conn->device->ib_device;
+ dma_nents = ib_dma_map_sg(dev,
+ &iser_ctask->data_copy[cmd_dir].sg_single,
+ 1,
+ (cmd_dir == ISER_DIR_OUT) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
BUG_ON(dma_nents == 0);
iser_ctask->data_copy[cmd_dir].dma_nents = dma_nents;
@@ -170,19 +165,16 @@ int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
enum iser_data_dir cmd_dir)
{
- struct device *dma_device;
+ struct ib_device *dev;
struct iser_data_buf *mem_copy;
unsigned long cmd_data_len;
- dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
- mem_copy = &iser_ctask->data_copy[cmd_dir];
+ dev = iser_ctask->iser_conn->ib_conn->device->ib_device;
+ mem_copy = &iser_ctask->data_copy[cmd_dir];
- if (cmd_dir == ISER_DIR_OUT)
- dma_unmap_sg(dma_device, &mem_copy->sg_single, 1,
- DMA_TO_DEVICE);
- else
- dma_unmap_sg(dma_device, &mem_copy->sg_single, 1,
- DMA_FROM_DEVICE);
+ ib_dma_unmap_sg(dev, &mem_copy->sg_single, 1,
+ (cmd_dir == ISER_DIR_OUT) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (cmd_dir == ISER_DIR_IN) {
char *mem;
@@ -211,7 +203,7 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
free_pages((unsigned long)mem_copy->copy_buf,
- long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+ ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
else
kfree(mem_copy->copy_buf);
@@ -231,11 +223,12 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
* consecutive elements. Also, it handles one entry SG.
*/
static int iser_sg_to_page_vec(struct iser_data_buf *data,
- struct iser_page_vec *page_vec)
+ struct iser_page_vec *page_vec,
+ struct ib_device *ibdev)
{
struct scatterlist *sg = (struct scatterlist *)data->buf;
- dma_addr_t first_addr, last_addr, page;
- int start_aligned, end_aligned;
+ u64 first_addr, last_addr, page;
+ int end_aligned;
unsigned int cur_page = 0;
unsigned long total_sz = 0;
int i;
@@ -244,19 +237,21 @@ static int iser_sg_to_page_vec(struct iser_data_buf *data,
page_vec->offset = (u64) sg[0].offset & ~MASK_4K;
for (i = 0; i < data->dma_nents; i++) {
- total_sz += sg_dma_len(&sg[i]);
+ unsigned int dma_len = ib_sg_dma_len(ibdev, &sg[i]);
+
+ total_sz += dma_len;
- first_addr = sg_dma_address(&sg[i]);
- last_addr = first_addr + sg_dma_len(&sg[i]);
+ first_addr = ib_sg_dma_address(ibdev, &sg[i]);
+ last_addr = first_addr + dma_len;
- start_aligned = !(first_addr & ~MASK_4K);
end_aligned = !(last_addr & ~MASK_4K);
/* continue to collect page fragments till aligned or SG ends */
while (!end_aligned && (i + 1 < data->dma_nents)) {
i++;
- total_sz += sg_dma_len(&sg[i]);
- last_addr = sg_dma_address(&sg[i]) + sg_dma_len(&sg[i]);
+ dma_len = ib_sg_dma_len(ibdev, &sg[i]);
+ total_sz += dma_len;
+ last_addr = ib_sg_dma_address(ibdev, &sg[i]) + dma_len;
end_aligned = !(last_addr & ~MASK_4K);
}
@@ -288,10 +283,11 @@ static int iser_sg_to_page_vec(struct iser_data_buf *data,
* the number of entries which are aligned correctly. Supports the case where
* consecutive SG elements are actually fragments of the same physcial page.
*/
-static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data)
+static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data,
+ struct ib_device *ibdev)
{
struct scatterlist *sg;
- dma_addr_t end_addr, next_addr;
+ u64 end_addr, next_addr;
int i, cnt;
unsigned int ret_len = 0;
@@ -303,12 +299,12 @@ static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data)
(unsigned long)page_to_phys(sg[i].page),
(unsigned long)sg[i].offset,
(unsigned long)sg[i].length); */
- end_addr = sg_dma_address(&sg[i]) +
- sg_dma_len(&sg[i]);
+ end_addr = ib_sg_dma_address(ibdev, &sg[i]) +
+ ib_sg_dma_len(ibdev, &sg[i]);
/* iser_dbg("Checking sg iobuf end address "
"0x%08lX\n", end_addr); */
if (i + 1 < data->dma_nents) {
- next_addr = sg_dma_address(&sg[i+1]);
+ next_addr = ib_sg_dma_address(ibdev, &sg[i+1]);
/* are i, i+1 fragments of the same page? */
if (end_addr == next_addr)
continue;
@@ -325,7 +321,8 @@ static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data)
return ret_len;
}
-static void iser_data_buf_dump(struct iser_data_buf *data)
+static void iser_data_buf_dump(struct iser_data_buf *data,
+ struct ib_device *ibdev)
{
struct scatterlist *sg = (struct scatterlist *)data->buf;
int i;
@@ -333,9 +330,9 @@ static void iser_data_buf_dump(struct iser_data_buf *data)
for (i = 0; i < data->dma_nents; i++)
iser_err("sg[%d] dma_addr:0x%lX page:0x%p "
"off:0x%x sz:0x%x dma_len:0x%x\n",
- i, (unsigned long)sg_dma_address(&sg[i]),
+ i, (unsigned long)ib_sg_dma_address(ibdev, &sg[i]),
sg[i].page, sg[i].offset,
- sg[i].length,sg_dma_len(&sg[i]));
+ sg[i].length, ib_sg_dma_len(ibdev, &sg[i]));
}
static void iser_dump_page_vec(struct iser_page_vec *page_vec)
@@ -349,7 +346,8 @@ static void iser_dump_page_vec(struct iser_page_vec *page_vec)
}
static void iser_page_vec_build(struct iser_data_buf *data,
- struct iser_page_vec *page_vec)
+ struct iser_page_vec *page_vec,
+ struct ib_device *ibdev)
{
int page_vec_len = 0;
@@ -357,14 +355,14 @@ static void iser_page_vec_build(struct iser_data_buf *data,
page_vec->offset = 0;
iser_dbg("Translating sg sz: %d\n", data->dma_nents);
- page_vec_len = iser_sg_to_page_vec(data,page_vec);
+ page_vec_len = iser_sg_to_page_vec(data, page_vec, ibdev);
iser_dbg("sg len %d page_vec_len %d\n", data->dma_nents,page_vec_len);
page_vec->length = page_vec_len;
if (page_vec_len * SIZE_4K < page_vec->data_size) {
iser_err("page_vec too short to hold this SG\n");
- iser_data_buf_dump(data);
+ iser_data_buf_dump(data, ibdev);
iser_dump_page_vec(page_vec);
BUG();
}
@@ -375,13 +373,12 @@ int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
enum iser_data_dir iser_dir,
enum dma_data_direction dma_dir)
{
- struct device *dma_device;
+ struct ib_device *dev;
iser_ctask->dir[iser_dir] = 1;
- dma_device =
- iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+ dev = iser_ctask->iser_conn->ib_conn->device->ib_device;
- data->dma_nents = dma_map_sg(dma_device, data->buf, data->size, dma_dir);
+ data->dma_nents = ib_dma_map_sg(dev, data->buf, data->size, dma_dir);
if (data->dma_nents == 0) {
iser_err("dma_map_sg failed!!!\n");
return -EINVAL;
@@ -391,20 +388,19 @@ int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask)
{
- struct device *dma_device;
+ struct ib_device *dev;
struct iser_data_buf *data;
- dma_device =
- iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+ dev = iser_ctask->iser_conn->ib_conn->device->ib_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);
+ ib_dma_unmap_sg(dev, 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);
+ ib_dma_unmap_sg(dev, data->buf, data->size, DMA_TO_DEVICE);
}
}
@@ -419,6 +415,7 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
{
struct iser_conn *ib_conn = iser_ctask->iser_conn->ib_conn;
struct iser_device *device = ib_conn->device;
+ struct ib_device *ibdev = device->ib_device;
struct iser_data_buf *mem = &iser_ctask->data[cmd_dir];
struct iser_regd_buf *regd_buf;
int aligned_len;
@@ -428,11 +425,11 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
regd_buf = &iser_ctask->rdma_regd[cmd_dir];
- aligned_len = iser_data_buf_aligned_len(mem);
+ aligned_len = iser_data_buf_aligned_len(mem, ibdev);
if (aligned_len != mem->dma_nents) {
iser_err("rdma alignment violation %d/%d aligned\n",
aligned_len, mem->size);
- iser_data_buf_dump(mem);
+ iser_data_buf_dump(mem, ibdev);
/* unmap the command data before accessing it */
iser_dma_unmap_task_data(iser_ctask);
@@ -450,8 +447,8 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
regd_buf->reg.lkey = device->mr->lkey;
regd_buf->reg.rkey = device->mr->rkey;
- regd_buf->reg.len = sg_dma_len(&sg[0]);
- regd_buf->reg.va = sg_dma_address(&sg[0]);
+ regd_buf->reg.len = ib_sg_dma_len(ibdev, &sg[0]);
+ regd_buf->reg.va = ib_sg_dma_address(ibdev, &sg[0]);
regd_buf->reg.is_fmr = 0;
iser_dbg("PHYSICAL Mem.register: lkey: 0x%08X rkey: 0x%08X "
@@ -461,10 +458,10 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
(unsigned long)regd_buf->reg.va,
(unsigned long)regd_buf->reg.len);
} else { /* use FMR for multiple dma entries */
- iser_page_vec_build(mem, ib_conn->page_vec);
+ iser_page_vec_build(mem, ib_conn->page_vec, ibdev);
err = iser_reg_page_vec(ib_conn, ib_conn->page_vec, &regd_buf->reg);
if (err) {
- iser_data_buf_dump(mem);
+ iser_data_buf_dump(mem, ibdev);
iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", mem->dma_nents,
ntoh24(iser_ctask->desc.iscsi_header.dlength));
iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n",
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index a6289595557..5e8ac577f0a 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -122,9 +122,8 @@ static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size,
if (!iu->buf)
goto out_free_iu;
- iu->dma = dma_map_single(host->dev->dev->dma_device,
- iu->buf, size, direction);
- if (dma_mapping_error(iu->dma))
+ iu->dma = ib_dma_map_single(host->dev->dev, iu->buf, size, direction);
+ if (ib_dma_mapping_error(host->dev->dev, iu->dma))
goto out_free_buf;
iu->size = size;
@@ -145,8 +144,7 @@ static void srp_free_iu(struct srp_host *host, struct srp_iu *iu)
if (!iu)
return;
- dma_unmap_single(host->dev->dev->dma_device,
- iu->dma, iu->size, iu->direction);
+ ib_dma_unmap_single(host->dev->dev, iu->dma, iu->size, iu->direction);
kfree(iu->buf);
kfree(iu);
}
@@ -482,8 +480,8 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
scat = &req->fake_sg;
}
- dma_unmap_sg(target->srp_host->dev->dev->dma_device, scat, nents,
- scmnd->sc_data_direction);
+ ib_dma_unmap_sg(target->srp_host->dev->dev, scat, nents,
+ scmnd->sc_data_direction);
}
static void srp_remove_req(struct srp_target_port *target, struct srp_request *req)
@@ -550,6 +548,7 @@ static int srp_reconnect_target(struct srp_target_port *target)
target->tx_head = 0;
target->tx_tail = 0;
+ target->qp_in_error = 0;
ret = srp_connect_target(target);
if (ret)
goto err;
@@ -595,23 +594,26 @@ static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
int i, j;
int ret;
struct srp_device *dev = target->srp_host->dev;
+ struct ib_device *ibdev = dev->dev;
if (!dev->fmr_pool)
return -ENODEV;
- if ((sg_dma_address(&scat[0]) & ~dev->fmr_page_mask) &&
+ if ((ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask) &&
mellanox_workarounds && !memcmp(&target->ioc_guid, mellanox_oui, 3))
return -EINVAL;
len = page_cnt = 0;
for (i = 0; i < sg_cnt; ++i) {
- if (sg_dma_address(&scat[i]) & ~dev->fmr_page_mask) {
+ unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+
+ if (ib_sg_dma_address(ibdev, &scat[i]) & ~dev->fmr_page_mask) {
if (i > 0)
return -EINVAL;
else
++page_cnt;
}
- if ((sg_dma_address(&scat[i]) + sg_dma_len(&scat[i])) &
+ if ((ib_sg_dma_address(ibdev, &scat[i]) + dma_len) &
~dev->fmr_page_mask) {
if (i < sg_cnt - 1)
return -EINVAL;
@@ -619,7 +621,7 @@ static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
++page_cnt;
}
- len += sg_dma_len(&scat[i]);
+ len += dma_len;
}
page_cnt += len >> dev->fmr_page_shift;
@@ -631,10 +633,14 @@ static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
return -ENOMEM;
page_cnt = 0;
- for (i = 0; i < sg_cnt; ++i)
- for (j = 0; j < sg_dma_len(&scat[i]); j += dev->fmr_page_size)
+ for (i = 0; i < sg_cnt; ++i) {
+ unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+
+ for (j = 0; j < dma_len; j += dev->fmr_page_size)
dma_pages[page_cnt++] =
- (sg_dma_address(&scat[i]) & dev->fmr_page_mask) + j;
+ (ib_sg_dma_address(ibdev, &scat[i]) &
+ dev->fmr_page_mask) + j;
+ }
req->fmr = ib_fmr_pool_map_phys(dev->fmr_pool,
dma_pages, page_cnt, io_addr);
@@ -644,7 +650,8 @@ static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
goto out;
}
- buf->va = cpu_to_be64(sg_dma_address(&scat[0]) & ~dev->fmr_page_mask);
+ buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, &scat[0]) &
+ ~dev->fmr_page_mask);
buf->key = cpu_to_be32(req->fmr->fmr->rkey);
buf->len = cpu_to_be32(len);
@@ -663,6 +670,8 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
struct srp_cmd *cmd = req->cmd->buf;
int len, nents, count;
u8 fmt = SRP_DATA_DESC_DIRECT;
+ struct srp_device *dev;
+ struct ib_device *ibdev;
if (!scmnd->request_buffer || scmnd->sc_data_direction == DMA_NONE)
return sizeof (struct srp_cmd);
@@ -687,8 +696,10 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
sg_init_one(scat, scmnd->request_buffer, scmnd->request_bufflen);
}
- count = dma_map_sg(target->srp_host->dev->dev->dma_device,
- scat, nents, scmnd->sc_data_direction);
+ dev = target->srp_host->dev;
+ ibdev = dev->dev;
+
+ count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction);
fmt = SRP_DATA_DESC_DIRECT;
len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf);
@@ -702,9 +713,9 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
*/
struct srp_direct_buf *buf = (void *) cmd->add_data;
- buf->va = cpu_to_be64(sg_dma_address(scat));
- buf->key = cpu_to_be32(target->srp_host->dev->mr->rkey);
- buf->len = cpu_to_be32(sg_dma_len(scat));
+ buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, scat));
+ buf->key = cpu_to_be32(dev->mr->rkey);
+ buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat));
} else if (srp_map_fmr(target, scat, count, req,
(void *) cmd->add_data)) {
/*
@@ -722,13 +733,14 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
count * sizeof (struct srp_direct_buf);
for (i = 0; i < count; ++i) {
+ unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+
buf->desc_list[i].va =
- cpu_to_be64(sg_dma_address(&scat[i]));
+ cpu_to_be64(ib_sg_dma_address(ibdev, &scat[i]));
buf->desc_list[i].key =
- cpu_to_be32(target->srp_host->dev->mr->rkey);
- buf->desc_list[i].len =
- cpu_to_be32(sg_dma_len(&scat[i]));
- datalen += sg_dma_len(&scat[i]);
+ cpu_to_be32(dev->mr->rkey);
+ buf->desc_list[i].len = cpu_to_be32(dma_len);
+ datalen += dma_len;
}
if (scmnd->sc_data_direction == DMA_TO_DEVICE)
@@ -808,13 +820,15 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
{
+ struct ib_device *dev;
struct srp_iu *iu;
u8 opcode;
iu = target->rx_ring[wc->wr_id & ~SRP_OP_RECV];
- dma_sync_single_for_cpu(target->srp_host->dev->dev->dma_device, iu->dma,
- target->max_ti_iu_len, DMA_FROM_DEVICE);
+ dev = target->srp_host->dev->dev;
+ ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len,
+ DMA_FROM_DEVICE);
opcode = *(u8 *) iu->buf;
@@ -850,8 +864,8 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
break;
}
- dma_sync_single_for_device(target->srp_host->dev->dev->dma_device, iu->dma,
- target->max_ti_iu_len, DMA_FROM_DEVICE);
+ ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len,
+ DMA_FROM_DEVICE);
}
static void srp_completion(struct ib_cq *cq, void *target_ptr)
@@ -865,6 +879,7 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
printk(KERN_ERR PFX "failed %s status %d\n",
wc.wr_id & SRP_OP_RECV ? "receive" : "send",
wc.status);
+ target->qp_in_error = 1;
break;
}
@@ -969,6 +984,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
struct srp_request *req;
struct srp_iu *iu;
struct srp_cmd *cmd;
+ struct ib_device *dev;
int len;
if (target->state == SRP_TARGET_CONNECTING)
@@ -985,8 +1001,9 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
if (!iu)
goto err;
- dma_sync_single_for_cpu(target->srp_host->dev->dev->dma_device, iu->dma,
- srp_max_iu_len, DMA_TO_DEVICE);
+ dev = target->srp_host->dev->dev;
+ ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len,
+ DMA_TO_DEVICE);
req = list_entry(target->free_reqs.next, struct srp_request, list);
@@ -1018,8 +1035,8 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
goto err_unmap;
}
- dma_sync_single_for_device(target->srp_host->dev->dev->dma_device, iu->dma,
- srp_max_iu_len, DMA_TO_DEVICE);
+ ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len,
+ DMA_TO_DEVICE);
if (__srp_post_send(target, iu, len)) {
printk(KERN_ERR PFX "Send failed\n");
@@ -1322,6 +1339,8 @@ static int srp_abort(struct scsi_cmnd *scmnd)
printk(KERN_ERR "SRP abort called\n");
+ if (target->qp_in_error)
+ return FAILED;
if (srp_find_req(target, scmnd, &req))
return FAILED;
if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK))
@@ -1350,6 +1369,8 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
printk(KERN_ERR "SRP reset_device called\n");
+ if (target->qp_in_error)
+ return FAILED;
if (srp_find_req(target, scmnd, &req))
return FAILED;
if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET))
@@ -1606,18 +1627,30 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
switch (token) {
case SRP_OPT_ID_EXT:
p = match_strdup(args);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out;
+ }
target->id_ext = cpu_to_be64(simple_strtoull(p, NULL, 16));
kfree(p);
break;
case SRP_OPT_IOC_GUID:
p = match_strdup(args);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out;
+ }
target->ioc_guid = cpu_to_be64(simple_strtoull(p, NULL, 16));
kfree(p);
break;
case SRP_OPT_DGID:
p = match_strdup(args);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out;
+ }
if (strlen(p) != 32) {
printk(KERN_WARNING PFX "bad dest GID parameter '%s'\n", p);
kfree(p);
@@ -1641,6 +1674,10 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
case SRP_OPT_SERVICE_ID:
p = match_strdup(args);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out;
+ }
target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16));
kfree(p);
break;
@@ -1678,6 +1715,10 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
case SRP_OPT_INITIATOR_EXT:
p = match_strdup(args);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out;
+ }
target->initiator_ext = cpu_to_be64(simple_strtoull(p, NULL, 16));
kfree(p);
break;
@@ -1766,6 +1807,7 @@ static ssize_t srp_create_target(struct class_device *class_dev,
goto err_free;
}
+ target->qp_in_error = 0;
ret = srp_connect_target(target);
if (ret) {
printk(KERN_ERR PFX "Connection failed\n");
@@ -1883,7 +1925,7 @@ static void srp_add_one(struct ib_device *device)
*/
srp_dev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1);
srp_dev->fmr_page_size = 1 << srp_dev->fmr_page_shift;
- srp_dev->fmr_page_mask = ~((unsigned long) srp_dev->fmr_page_size - 1);
+ srp_dev->fmr_page_mask = ~((u64) srp_dev->fmr_page_size - 1);
INIT_LIST_HEAD(&srp_dev->dev_list);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index d4e35ef5137..2f3319c719a 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -87,7 +87,7 @@ struct srp_device {
struct ib_fmr_pool *fmr_pool;
int fmr_page_shift;
int fmr_page_size;
- unsigned long fmr_page_mask;
+ u64 fmr_page_mask;
};
struct srp_host {
@@ -158,10 +158,11 @@ struct srp_target_port {
struct completion done;
int status;
enum srp_target_state state;
+ int qp_in_error;
};
struct srp_iu {
- dma_addr_t dma;
+ u64 dma;
void *buf;
size_t size;
enum dma_data_direction direction;
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index a005b1df5f1..da575deb3c7 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_INPUT_MOUSE) += mouse/
obj-$(CONFIG_INPUT_JOYSTICK) += joystick/
obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_MISC) += misc/
+
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
index 16583d71753..c67e84ec2d6 100644
--- a/drivers/input/keyboard/amikbd.c
+++ b/drivers/input/keyboard/amikbd.c
@@ -187,7 +187,7 @@ static irqreturn_t amikbd_interrupt(int irq, void *dummy)
static int __init amikbd_init(void)
{
- int i, j;
+ int i, j, err;
if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
return -ENODEV;
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index 54bc569db4b..35461eab2fa 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -23,7 +23,12 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hil.h>
+#include <linux/io.h>
#include <linux/spinlock.h>
+#include <asm/irq.h>
+#ifdef CONFIG_HP300
+#include <asm/hwtest.h>
+#endif
MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller");
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index 3826db9403e..cc023836641 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -225,7 +225,7 @@ static void sunkbd_reinit(struct work_struct *work)
static void sunkbd_enable(struct sunkbd *sunkbd, int enable)
{
serio_pause_rx(sunkbd->serio);
- sunkbd->enabled = 1;
+ sunkbd->enabled = enable;
serio_continue_rx(sunkbd->serio);
}
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
index 54adba2d8ed..d9ca55891cd 100644
--- a/drivers/input/serio/i8042-sparcio.h
+++ b/drivers/input/serio/i8042-sparcio.h
@@ -16,6 +16,7 @@ static int i8042_aux_irq = -1;
#define I8042_MUX_PHYS_DESC "sparcps2/serio%d"
static void __iomem *kbd_iobase;
+static struct resource *kbd_res;
#define I8042_COMMAND_REG (kbd_iobase + 0x64UL)
#define I8042_DATA_REG (kbd_iobase + 0x60UL)
@@ -60,6 +61,7 @@ static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_dev
i8042_kbd_irq = irq;
kbd_iobase = of_ioremap(&kbd->resource[0],
0, 8, "kbd");
+ kbd_res = &kbd->resource[0];
} else if (!strcmp(dp->name, OBP_PS2MS_NAME1) ||
!strcmp(dp->name, OBP_PS2MS_NAME2)) {
struct of_device *ms = of_find_device_by_node(dp);
@@ -77,7 +79,7 @@ static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_dev
static int __devexit sparc_i8042_remove(struct of_device *op)
{
- of_iounmap(kbd_iobase, 8);
+ of_iounmap(kbd_res, kbd_iobase, 8);
return 0;
}
@@ -119,7 +121,7 @@ static int __init i8042_platform_init(void)
if (i8042_kbd_irq == -1 ||
i8042_aux_irq == -1) {
if (kbd_iobase) {
- of_iounmap(kbd_iobase, 8);
+ of_iounmap(kbd_res, kbd_iobase, 8);
kbd_iobase = (void __iomem *) NULL;
}
return -ENODEV;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index f0ce822c102..17c8c63cbe1 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -45,7 +45,7 @@ EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_unregister_child_port);
-EXPORT_SYMBOL(serio_register_driver);
+EXPORT_SYMBOL(__serio_register_driver);
EXPORT_SYMBOL(serio_unregister_driver);
EXPORT_SYMBOL(serio_open);
EXPORT_SYMBOL(serio_close);
@@ -789,12 +789,14 @@ static void serio_attach_driver(struct serio_driver *drv)
drv->driver.name, error);
}
-int serio_register_driver(struct serio_driver *drv)
+int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)
{
int manual_bind = drv->manual_bind;
int error;
drv->driver.bus = &serio_bus;
+ drv->driver.owner = owner;
+ drv->driver.mod_name = mod_name;
/*
* Temporarily disable automatic binding because probing
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 4bec8422821..971618059a6 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -151,7 +151,7 @@ config TOUCHSCREEN_TOUCHWIN
config TOUCHSCREEN_UCB1400
tristate "Philips UCB1400 touchscreen"
- select SND_AC97_BUS
+ select AC97_BUS
help
This enables support for the Philips UCB1400 touchscreen interface.
The UCB1400 is an AC97 audio codec. The touchscreen interface
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 4358a0a78ea..c7db4032ef0 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -83,7 +83,7 @@
struct ucb1400 {
- ac97_t *ac97;
+ struct snd_ac97 *ac97;
struct input_dev *ts_idev;
int irq;
diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
index 3cac2373934..09ea50dd345 100644
--- a/drivers/isdn/act2000/act2000_isa.c
+++ b/drivers/isdn/act2000/act2000_isa.c
@@ -408,7 +408,7 @@ act2000_isa_download(act2000_card * card, act2000_ddef __user * cb)
p = cblock.buffer;
if (!access_ok(VERIFY_READ, p, length))
return -EFAULT;
- buf = (u_char *) kmalloc(1024, GFP_KERNEL);
+ buf = kmalloc(1024, GFP_KERNEL);
if (!buf)
return -ENOMEM;
timeout = 0;
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
index 90593e2ef87..e3e5c139907 100644
--- a/drivers/isdn/act2000/module.c
+++ b/drivers/isdn/act2000/module.c
@@ -573,12 +573,11 @@ act2000_alloccard(int bus, int port, int irq, char *id)
{
int i;
act2000_card *card;
- if (!(card = (act2000_card *) kmalloc(sizeof(act2000_card), GFP_KERNEL))) {
+ if (!(card = kzalloc(sizeof(act2000_card), GFP_KERNEL))) {
printk(KERN_WARNING
"act2000: (%s) Could not allocate card-struct.\n", id);
return;
}
- memset((char *) card, 0, sizeof(act2000_card));
spin_lock_init(&card->lock);
spin_lock_init(&card->mnlock);
skb_queue_head_init(&card->sndq);
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 11844bbfe93..d22c0224fde 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -215,13 +215,12 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
unsigned int minor = 0;
unsigned long flags;
- mp = kmalloc(sizeof(*mp), GFP_ATOMIC);
+ mp = kzalloc(sizeof(*mp), GFP_ATOMIC);
if (!mp) {
printk(KERN_ERR "capi: can't alloc capiminor\n");
return NULL;
}
- memset(mp, 0, sizeof(struct capiminor));
mp->ap = ap;
mp->ncci = ncci;
mp->msgid = 0;
@@ -304,10 +303,9 @@ static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci)
struct capiminor *mp = NULL;
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- np = kmalloc(sizeof(*np), GFP_ATOMIC);
+ np = kzalloc(sizeof(*np), GFP_ATOMIC);
if (!np)
return NULL;
- memset(np, 0, sizeof(struct capincci));
np->ncci = ncci;
np->cdev = cdev;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -384,10 +382,9 @@ static struct capidev *capidev_alloc(void)
struct capidev *cdev;
unsigned long flags;
- cdev = kmalloc(sizeof(*cdev), GFP_KERNEL);
+ cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return NULL;
- memset(cdev, 0, sizeof(struct capidev));
init_MUTEX(&cdev->ncci_list_sem);
skb_queue_head_init(&cdev->recvqueue);
@@ -1010,7 +1007,7 @@ static int capinc_tty_open(struct tty_struct * tty, struct file * file)
{
struct capiminor *mp;
- if ((mp = capiminor_find(iminor(file->f_dentry->d_inode))) == 0)
+ if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == 0)
return -ENXIO;
if (mp->nccip == 0)
return -ENXIO;
@@ -1203,7 +1200,7 @@ static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
return error;
}
-static void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old)
+static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios * old)
{
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_set_termios\n");
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index b6f9476c050..c4d438c17da 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -334,12 +334,11 @@ static capidrv_plci *new_plci(capidrv_contr * card, int chan)
{
capidrv_plci *plcip;
- plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC);
+ plcip = kzalloc(sizeof(capidrv_plci), GFP_ATOMIC);
if (plcip == 0)
return NULL;
- memset(plcip, 0, sizeof(capidrv_plci));
plcip->state = ST_PLCI_NONE;
plcip->plci = 0;
plcip->msgid = 0;
@@ -404,12 +403,11 @@ static inline capidrv_ncci *new_ncci(capidrv_contr * card,
{
capidrv_ncci *nccip;
- nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
+ nccip = kzalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
if (nccip == 0)
return NULL;
- memset(nccip, 0, sizeof(capidrv_ncci));
nccip->ncci = ncci;
nccip->state = ST_NCCI_NONE;
nccip->plcip = plcip;
@@ -2005,18 +2003,17 @@ static int capidrv_addcontr(u16 contr, struct capi_profile *profp)
printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id);
return -1;
}
- if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
+ if (!(card = kzalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
printk(KERN_WARNING
"capidrv: (%s) Could not allocate contr-struct.\n", id);
return -1;
}
- memset(card, 0, sizeof(capidrv_contr));
card->owner = THIS_MODULE;
init_timer(&card->listentimer);
strcpy(card->name, id);
card->contrnr = contr;
card->nbchan = profp->nbchannel;
- card->bchans = (capidrv_bchan *) kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
+ card->bchans = kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
if (!card->bchans) {
printk(KERN_WARNING
"capidrv: (%s) Could not allocate bchan-structs.\n", id);
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 399b316111f..06967da7c4a 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -45,7 +45,7 @@ put_info_buffer(char *cp)
return;
if (!*cp)
return;
- if (!(ib = (struct divert_info *) kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC)))
+ if (!(ib = kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC)))
return; /* no memory */
strcpy(ib->info_start, cp); /* set output string */
ib->next = NULL;
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
index 03319ea5aa0..7d97d54588d 100644
--- a/drivers/isdn/divert/isdn_divert.c
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -153,7 +153,7 @@ int cf_command(int drvid, int mode,
*ielenp = p - ielenp - 1; /* set total IE length */
/* allocate mem for information struct */
- if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
+ if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
return(-ENOMEM); /* no memory */
init_timer(&cs->timer);
cs->info[0] = '\0';
@@ -276,7 +276,7 @@ int insertrule(int idx, divert_rule *newrule)
{ struct deflect_struc *ds,*ds1=NULL;
unsigned long flags;
- if (!(ds = (struct deflect_struc *) kmalloc(sizeof(struct deflect_struc),
+ if (!(ds = kmalloc(sizeof(struct deflect_struc),
GFP_KERNEL)))
return(-ENOMEM); /* no memory */
@@ -451,7 +451,7 @@ static int isdn_divert_icall(isdn_ctrl *ic)
if (dv->rule.action == DEFLECT_PROCEED)
if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
return(0); /* no external deflection needed */
- if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
+ if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
return(0); /* no memory */
init_timer(&cs->timer);
cs->info[0] = '\0';
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
index 5b203fe21dc..708d47a6484 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/isdn/gigaset/Kconfig
@@ -5,6 +5,7 @@ config ISDN_DRV_GIGASET
tristate "Siemens Gigaset support (isdn)"
depends on ISDN_I4L
select CRC_CCITT
+ select BITREVERSE
help
Say m here if you have a Gigaset or Sinus isdn device.
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c
index ce3cd77094b..88e958f176d 100644
--- a/drivers/isdn/gigaset/asyncdata.c
+++ b/drivers/isdn/gigaset/asyncdata.c
@@ -15,6 +15,7 @@
#include "gigaset.h"
#include <linux/crc-ccitt.h>
+#include <linux/bitrev.h>
//#define GIG_M10x_STUFF_VOICE_DATA
@@ -302,7 +303,7 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
inputstate |= INS_skip_frame;
break;
}
- *__skb_put(skb, 1) = gigaset_invtab[c];
+ *__skb_put(skb, 1) = bitrev8(c);
}
if (unlikely(!numbytes))
@@ -543,7 +544,7 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
cp = skb->data;
len = skb->len;
while (len--) {
- c = gigaset_invtab[*cp++];
+ c = bitrev8(*cp++);
if (c == DLE_FLAG)
*(skb_put(iraw_skb, 1)) = c;
*(skb_put(iraw_skb, 1)) = c;
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 63b629b1cdb..b5e7f9c7d74 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -1853,20 +1853,24 @@ static int gigaset_write_cmd(struct cardstate *cs,
{
struct cmdbuf_t *cb;
unsigned long flags;
- int status;
+ int rc;
gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
"CMD Transmit", len, buf);
- if (len <= 0)
- return 0; /* nothing to do */
+ if (len <= 0) {
+ /* nothing to do */
+ rc = 0;
+ goto notqueued;
+ }
if (len > IF_WRITEBUF)
len = IF_WRITEBUF;
if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) {
dev_err(cs->dev, "%s: out of memory\n", __func__);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto notqueued;
}
memcpy(cb->buf, buf, len);
@@ -1891,11 +1895,21 @@ static int gigaset_write_cmd(struct cardstate *cs,
if (unlikely(!cs->connected)) {
spin_unlock_irqrestore(&cs->lock, flags);
gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
+ /* flush command queue */
+ spin_lock_irqsave(&cs->cmdlock, flags);
+ while (cs->cmdbuf != NULL)
+ complete_cb(cs);
+ spin_unlock_irqrestore(&cs->cmdlock, flags);
return -ENODEV;
}
- status = start_cbsend(cs);
+ rc = start_cbsend(cs);
spin_unlock_irqrestore(&cs->lock, flags);
- return status < 0 ? status : len;
+ return rc < 0 ? rc : len;
+
+notqueued: /* request handled without queuing */
+ if (wake_tasklet)
+ tasklet_schedule(wake_tasklet);
+ return rc;
}
/* gigaset_write_room
@@ -1964,20 +1978,15 @@ static int gigaset_freebcshw(struct bc_state *bcs)
/* kill URBs and tasklets before freeing - better safe than sorry */
atomic_set(&ubc->running, 0);
- for (i = 0; i < BAS_OUTURBS; ++i)
- if (ubc->isoouturbs[i].urb) {
- gig_dbg(DEBUG_INIT, "%s: killing iso out URB %d",
- __func__, i);
- usb_kill_urb(ubc->isoouturbs[i].urb);
- usb_free_urb(ubc->isoouturbs[i].urb);
- }
- for (i = 0; i < BAS_INURBS; ++i)
- if (ubc->isoinurbs[i]) {
- gig_dbg(DEBUG_INIT, "%s: killing iso in URB %d",
- __func__, i);
- usb_kill_urb(ubc->isoinurbs[i]);
- usb_free_urb(ubc->isoinurbs[i]);
- }
+ gig_dbg(DEBUG_INIT, "%s: killing iso URBs", __func__);
+ for (i = 0; i < BAS_OUTURBS; ++i) {
+ usb_kill_urb(ubc->isoouturbs[i].urb);
+ usb_free_urb(ubc->isoouturbs[i].urb);
+ }
+ for (i = 0; i < BAS_INURBS; ++i) {
+ usb_kill_urb(ubc->isoinurbs[i]);
+ usb_free_urb(ubc->isoinurbs[i]);
+ }
tasklet_kill(&ubc->sent_tasklet);
tasklet_kill(&ubc->rcvd_tasklet);
kfree(ubc->isooutbuf);
@@ -2099,55 +2108,32 @@ static void freeurbs(struct cardstate *cs)
struct bas_bc_state *ubc;
int i, j;
+ gig_dbg(DEBUG_INIT, "%s: killing URBs", __func__);
for (j = 0; j < 2; ++j) {
ubc = cs->bcs[j].hw.bas;
- for (i = 0; i < BAS_OUTURBS; ++i)
- if (ubc->isoouturbs[i].urb) {
- usb_kill_urb(ubc->isoouturbs[i].urb);
- gig_dbg(DEBUG_INIT,
- "%s: isoc output URB %d/%d unlinked",
- __func__, j, i);
- usb_free_urb(ubc->isoouturbs[i].urb);
- ubc->isoouturbs[i].urb = NULL;
- }
- for (i = 0; i < BAS_INURBS; ++i)
- if (ubc->isoinurbs[i]) {
- usb_kill_urb(ubc->isoinurbs[i]);
- gig_dbg(DEBUG_INIT,
- "%s: isoc input URB %d/%d unlinked",
- __func__, j, i);
- usb_free_urb(ubc->isoinurbs[i]);
- ubc->isoinurbs[i] = NULL;
- }
- }
- if (ucs->urb_int_in) {
- usb_kill_urb(ucs->urb_int_in);
- gig_dbg(DEBUG_INIT, "%s: interrupt input URB unlinked",
- __func__);
- usb_free_urb(ucs->urb_int_in);
- ucs->urb_int_in = NULL;
- }
- if (ucs->urb_cmd_out) {
- usb_kill_urb(ucs->urb_cmd_out);
- gig_dbg(DEBUG_INIT, "%s: command output URB unlinked",
- __func__);
- usb_free_urb(ucs->urb_cmd_out);
- ucs->urb_cmd_out = NULL;
- }
- if (ucs->urb_cmd_in) {
- usb_kill_urb(ucs->urb_cmd_in);
- gig_dbg(DEBUG_INIT, "%s: command input URB unlinked",
- __func__);
- usb_free_urb(ucs->urb_cmd_in);
- ucs->urb_cmd_in = NULL;
- }
- if (ucs->urb_ctrl) {
- usb_kill_urb(ucs->urb_ctrl);
- gig_dbg(DEBUG_INIT, "%s: control output URB unlinked",
- __func__);
- usb_free_urb(ucs->urb_ctrl);
- ucs->urb_ctrl = NULL;
+ for (i = 0; i < BAS_OUTURBS; ++i) {
+ usb_kill_urb(ubc->isoouturbs[i].urb);
+ usb_free_urb(ubc->isoouturbs[i].urb);
+ ubc->isoouturbs[i].urb = NULL;
+ }
+ for (i = 0; i < BAS_INURBS; ++i) {
+ usb_kill_urb(ubc->isoinurbs[i]);
+ usb_free_urb(ubc->isoinurbs[i]);
+ ubc->isoinurbs[i] = NULL;
+ }
}
+ usb_kill_urb(ucs->urb_int_in);
+ usb_free_urb(ucs->urb_int_in);
+ ucs->urb_int_in = NULL;
+ usb_kill_urb(ucs->urb_cmd_out);
+ usb_free_urb(ucs->urb_cmd_out);
+ ucs->urb_cmd_out = NULL;
+ usb_kill_urb(ucs->urb_cmd_in);
+ usb_free_urb(ucs->urb_cmd_in);
+ ucs->urb_cmd_in = NULL;
+ usb_kill_urb(ucs->urb_ctrl);
+ usb_free_urb(ucs->urb_ctrl);
+ ucs->urb_ctrl = NULL;
}
/* gigaset_probe
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index defd5743dba..4f75cce6fdf 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -33,43 +33,6 @@ MODULE_PARM_DESC(debug, "debug level");
#define VALID_ID 0x02
#define ASSIGNED 0x04
-/* bitwise byte inversion table */
-__u8 gigaset_invtab[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
-};
-EXPORT_SYMBOL_GPL(gigaset_invtab);
-
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
size_t len, const unsigned char *buf)
{
@@ -393,16 +356,17 @@ static struct cardstate *alloc_cs(struct gigaset_driver *drv)
{
unsigned long flags;
unsigned i;
- static struct cardstate *ret = NULL;
+ struct cardstate *ret = NULL;
spin_lock_irqsave(&drv->lock, flags);
for (i = 0; i < drv->minors; ++i) {
if (!(drv->flags[i] & VALID_MINOR)) {
- drv->flags[i] = VALID_MINOR;
- ret = drv->cs + i;
- }
- if (ret)
+ if (try_module_get(drv->owner)) {
+ drv->flags[i] = VALID_MINOR;
+ ret = drv->cs + i;
+ }
break;
+ }
}
spin_unlock_irqrestore(&drv->lock, flags);
return ret;
@@ -413,6 +377,8 @@ static void free_cs(struct cardstate *cs)
unsigned long flags;
struct gigaset_driver *drv = cs->driver;
spin_lock_irqsave(&drv->lock, flags);
+ if (drv->flags[cs->minor_index] & VALID_MINOR)
+ module_put(drv->owner);
drv->flags[cs->minor_index] = 0;
spin_unlock_irqrestore(&drv->lock, flags);
}
@@ -616,7 +582,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
} else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
skb_reserve(bcs->skb, HW_HDR_LEN);
else {
- warn("could not allocate skb\n");
+ warn("could not allocate skb");
bcs->inputstate |= INS_skip_frame;
}
@@ -669,17 +635,25 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
int i;
gig_dbg(DEBUG_INIT, "allocating cs");
- cs = alloc_cs(drv);
- if (!cs)
- goto error;
+ if (!(cs = alloc_cs(drv))) {
+ err("maximum number of devices exceeded");
+ return NULL;
+ }
+ mutex_init(&cs->mutex);
+ mutex_lock(&cs->mutex);
+
gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
- if (!cs->bcs)
+ if (!cs->bcs) {
+ err("out of memory");
goto error;
+ }
gig_dbg(DEBUG_INIT, "allocating inbuf");
cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
- if (!cs->inbuf)
+ if (!cs->inbuf) {
+ err("out of memory");
goto error;
+ }
cs->cs_init = 0;
cs->channels = channels;
@@ -691,8 +665,6 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
spin_lock_init(&cs->ev_lock);
cs->ev_tail = 0;
cs->ev_head = 0;
- mutex_init(&cs->mutex);
- mutex_lock(&cs->mutex);
tasklet_init(&cs->event_tasklet, &gigaset_handle_event,
(unsigned long) cs);
@@ -721,8 +693,10 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
for (i = 0; i < channels; ++i) {
gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
- if (!gigaset_initbcs(cs->bcs + i, cs, i))
+ if (!gigaset_initbcs(cs->bcs + i, cs, i)) {
+ err("could not allocate channel %d data", i);
goto error;
+ }
}
++cs->cs_init;
@@ -757,8 +731,10 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
make_valid(cs, VALID_ID);
++cs->cs_init;
gig_dbg(DEBUG_INIT, "setting up hw");
- if (!cs->ops->initcshw(cs))
+ if (!cs->ops->initcshw(cs)) {
+ err("could not allocate device specific data");
goto error;
+ }
++cs->cs_init;
@@ -780,8 +756,8 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
mutex_unlock(&cs->mutex);
return cs;
-error: if (cs)
- mutex_unlock(&cs->mutex);
+error:
+ mutex_unlock(&cs->mutex);
gig_dbg(DEBUG_INIT, "failed");
gigaset_freecs(cs);
return NULL;
@@ -1077,7 +1053,6 @@ void gigaset_freedriver(struct gigaset_driver *drv)
spin_unlock_irqrestore(&driver_lock, flags);
gigaset_if_freedriver(drv);
- module_put(drv->owner);
kfree(drv->cs);
kfree(drv->flags);
@@ -1109,10 +1084,6 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
if (!drv)
return NULL;
- if (!try_module_get(owner))
- goto out1;
-
- drv->cs = NULL;
drv->have_tty = 0;
drv->minor = minor;
drv->minors = minors;
@@ -1124,11 +1095,11 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL);
if (!drv->cs)
- goto out2;
+ goto error;
drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL);
if (!drv->flags)
- goto out3;
+ goto error;
for (i = 0; i < minors; ++i) {
drv->flags[i] = 0;
@@ -1145,11 +1116,8 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
return drv;
-out3:
+error:
kfree(drv->cs);
-out2:
- module_put(owner);
-out1:
kfree(drv);
return NULL;
}
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 06298cc52bf..a0317abaeb1 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -876,10 +876,6 @@ static inline void gigaset_rcv_error(struct sk_buff *procskb,
}
}
-
-/* bitwise byte inversion table */
-extern __u8 gigaset_invtab[]; /* in common.c */
-
/* append received bytes to inbuf */
int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
unsigned numbytes);
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index 7edea015867..458b6462f93 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -127,7 +127,7 @@ static int if_write_room(struct tty_struct *tty);
static int if_chars_in_buffer(struct tty_struct *tty);
static void if_throttle(struct tty_struct *tty);
static void if_unthrottle(struct tty_struct *tty);
-static void if_set_termios(struct tty_struct *tty, struct termios *old);
+static void if_set_termios(struct tty_struct *tty, struct ktermios *old);
static int if_tiocmget(struct tty_struct *tty, struct file *file);
static int if_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
@@ -490,7 +490,7 @@ static void if_unthrottle(struct tty_struct *tty)
mutex_unlock(&cs->mutex);
}
-static void if_set_termios(struct tty_struct *tty, struct termios *old)
+static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
{
struct cardstate *cs;
unsigned int iflag;
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index 8667daaa1a8..df988eb0e36 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -14,6 +14,7 @@
#include "gigaset.h"
#include <linux/crc-ccitt.h>
+#include <linux/bitrev.h>
/* access methods for isowbuf_t */
/* ============================ */
@@ -487,7 +488,7 @@ static inline int trans_buildframe(struct isowbuf_t *iwb,
gig_dbg(DEBUG_STREAM, "put %d bytes", count);
write = atomic_read(&iwb->write);
do {
- c = gigaset_invtab[*in++];
+ c = bitrev8(*in++);
iwb->data[write++] = c;
write %= BAS_OUTBUFSIZE;
} while (--count > 0);
@@ -876,7 +877,7 @@ static inline void trans_receive(unsigned char *src, unsigned count,
while (count > 0) {
dst = skb_put(skb, count < dobytes ? count : dobytes);
while (count > 0 && dobytes > 0) {
- *dst++ = gigaset_invtab[*src++];
+ *dst++ = bitrev8(*src++);
count--;
dobytes--;
}
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index fd5d7364a48..eba10466ccc 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -121,10 +121,9 @@ static int avmcs_probe(struct pcmcia_device *p_dev)
p_dev->conf.Present = PRESENT_OPTION;
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local)
goto err;
- memset(local, 0, sizeof(local_info_t));
p_dev->priv = local;
return avmcs_config(p_dev);
diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
index da272924771..7a69a18d07e 100644
--- a/drivers/isdn/hardware/avm/b1.c
+++ b/drivers/isdn/hardware/avm/b1.c
@@ -65,18 +65,15 @@ avmcard *b1_alloc_card(int nr_controllers)
avmctrl_info *cinfo;
int i;
- card = kmalloc(sizeof(*card), GFP_KERNEL);
+ card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card)
return NULL;
- memset(card, 0, sizeof(*card));
-
- cinfo = kmalloc(sizeof(*cinfo) * nr_controllers, GFP_KERNEL);
+ cinfo = kzalloc(sizeof(*cinfo) * nr_controllers, GFP_KERNEL);
if (!cinfo) {
kfree(card);
return NULL;
}
- memset(cinfo, 0, sizeof(*cinfo) * nr_controllers);
card->ctrlinfo = cinfo;
for (i = 0; i < nr_controllers; i++) {
@@ -718,12 +715,11 @@ avmcard_dma_alloc(char *name, struct pci_dev *pdev, long rsize, long ssize)
avmcard_dmainfo *p;
void *buf;
- p = kmalloc(sizeof(avmcard_dmainfo), GFP_KERNEL);
+ p = kzalloc(sizeof(avmcard_dmainfo), GFP_KERNEL);
if (!p) {
printk(KERN_WARNING "%s: no memory.\n", name);
goto err;
}
- memset(p, 0, sizeof(avmcard_dmainfo));
p->recvbuf.size = rsize;
buf = pci_alloc_consistent(pdev, rsize, &p->recvbuf.dmaaddr);
diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
index e47c60b0a8e..c925020fe9b 100644
--- a/drivers/isdn/hardware/avm/t1isa.c
+++ b/drivers/isdn/hardware/avm/t1isa.c
@@ -584,6 +584,7 @@ static void __exit t1isa_exit(void)
{
int i;
+ unregister_capi_driver(&capi_driver_t1isa);
for (i = 0; i < MAX_CARDS; i++) {
if (!io[i])
break;
diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c
index 6851c6270ce..d835e74ecf1 100644
--- a/drivers/isdn/hardware/eicon/debug.c
+++ b/drivers/isdn/hardware/eicon/debug.c
@@ -756,14 +756,14 @@ int diva_get_driver_info (dword id, byte* data, int data_length) {
data_length -= 9;
- if ((to_copy = MIN(strlen(clients[id].drvName), data_length-1))) {
+ if ((to_copy = min(strlen(clients[id].drvName), (size_t)(data_length-1)))) {
memcpy (p, clients[id].drvName, to_copy);
p += to_copy;
data_length -= to_copy;
if ((data_length >= 4) && clients[id].hDbg->drvTag[0]) {
*p++ = '(';
data_length -= 1;
- if ((to_copy = MIN(strlen(clients[id].hDbg->drvTag), data_length-2))) {
+ if ((to_copy = min(strlen(clients[id].hDbg->drvTag), (size_t)(data_length-2)))) {
memcpy (p, clients[id].hDbg->drvTag, to_copy);
p += to_copy;
data_length -= to_copy;
diff --git a/drivers/isdn/hardware/eicon/di.c b/drivers/isdn/hardware/eicon/di.c
index 0617d7cabf0..e1df8d98c31 100644
--- a/drivers/isdn/hardware/eicon/di.c
+++ b/drivers/isdn/hardware/eicon/di.c
@@ -133,7 +133,7 @@ void pr_out(ADAPTER * a)
i = this->XCurrent;
X = PTR_X(a,this);
while(i<this->XNum && length<270) {
- clength = MIN((word)(270-length),X[i].PLength-this->XOffset);
+ clength = min((word)(270-length),(word)(X[i].PLength-this->XOffset));
a->ram_out_buffer(a,
&ReqOut->XBuffer.P[length],
PTR_P(a,this,&X[i].P[this->XOffset]),
@@ -622,7 +622,7 @@ byte isdn_ind(ADAPTER * a,
sizeof(a->stream_buffer),
&final, NULL, NULL);
}
- IoAdapter->RBuffer.length = MIN(MLength, 270);
+ IoAdapter->RBuffer.length = min(MLength, (word)270);
if (IoAdapter->RBuffer.length != MLength) {
this->complete = 0;
} else {
@@ -676,9 +676,9 @@ byte isdn_ind(ADAPTER * a,
this->RCurrent++;
}
if (cma) {
- clength = MIN(MLength, R[this->RCurrent].PLength-this->ROffset);
+ clength = min(MLength, (word)(R[this->RCurrent].PLength-this->ROffset));
} else {
- clength = MIN(a->ram_inw(a, &RBuffer->length)-offset,
+ clength = min(a->ram_inw(a, &RBuffer->length)-offset,
R[this->RCurrent].PLength-this->ROffset);
}
if(R[this->RCurrent].P) {
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
index dae2e83dd5e..91fc92c01af 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -185,7 +185,7 @@ void diva_log_info(unsigned char *format, ...)
unsigned char line[160];
va_start(args, format);
- vsprintf(line, format, args);
+ vsnprintf(line, sizeof(line), format, args);
va_end(args);
printk(KERN_INFO "%s: %s\n", DRIVERLNAME, line);
diff --git a/drivers/isdn/hardware/eicon/io.c b/drivers/isdn/hardware/eicon/io.c
index 4a27e230b0a..6fd9b007417 100644
--- a/drivers/isdn/hardware/eicon/io.c
+++ b/drivers/isdn/hardware/eicon/io.c
@@ -262,7 +262,7 @@ void request(PISDN_ADAPTER IoAdapter, ENTITY * e)
case IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS: {
diva_xdi_get_capi_parameters_t prms, *pI = &syncReq->xdi_capi_prms.info;
memset (&prms, 0x00, sizeof(prms));
- prms.structure_length = MIN(sizeof(prms), pI->structure_length);
+ prms.structure_length = min_t(size_t, sizeof(prms), pI->structure_length);
memset (pI, 0x00, pI->structure_length);
prms.flag_dynamic_l1_down = (IoAdapter->capi_cfg.cfg_1 & \
DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? 1 : 0;
diff --git a/drivers/isdn/hardware/eicon/istream.c b/drivers/isdn/hardware/eicon/istream.c
index 23139668d9b..18f8798442f 100644
--- a/drivers/isdn/hardware/eicon/istream.c
+++ b/drivers/isdn/hardware/eicon/istream.c
@@ -92,7 +92,7 @@ int diva_istream_write (void* context,
return (-1); /* was not able to write */
break; /* only part of message was written */
}
- to_write = MIN(length, DIVA_DFIFO_DATA_SZ);
+ to_write = min(length, DIVA_DFIFO_DATA_SZ);
if (to_write) {
a->ram_out_buffer (a,
#ifdef PLATFORM_GT_32BIT
@@ -176,7 +176,7 @@ int diva_istream_read (void* context,
return (-1); /* was not able to read */
break;
}
- to_read = MIN(max_length, tmp[1]);
+ to_read = min(max_length, (int)tmp[1]);
if (to_read) {
a->ram_in_buffer(a,
#ifdef PLATFORM_GT_32BIT
diff --git a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h
index a66836cf756..2444811e0b3 100644
--- a/drivers/isdn/hardware/eicon/platform.h
+++ b/drivers/isdn/hardware/eicon/platform.h
@@ -83,14 +83,6 @@
#define NULL ((void *) 0)
#endif
-#ifndef MIN
-#define MIN(a,b) ((a)>(b) ? (b) : (a))
-#endif
-
-#ifndef MAX
-#define MAX(a,b) ((a)>(b) ? (a) : (b))
-#endif
-
#ifndef far
#define far
#endif
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index cfd2718a490..34ab5f7dcab 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -110,7 +110,7 @@ config HISAX_16_3
config HISAX_TELESPCI
bool "Teles PCI"
- depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
+ depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the Teles PCI.
See <file:Documentation/isdn/README.HiSax> on how to configure it.
@@ -238,7 +238,7 @@ config HISAX_MIC
config HISAX_NETJET
bool "NETjet card"
- depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
+ depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the NetJet from Traverse
Technologies.
@@ -249,7 +249,7 @@ config HISAX_NETJET
config HISAX_NETJET_U
bool "NETspider U card"
- depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
+ depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the Netspider U interface ISDN card
from Traverse Technologies.
@@ -317,7 +317,7 @@ config HISAX_GAZEL
config HISAX_HFC_PCI
bool "HFC PCI-Bus cards"
- depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
+ depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
@@ -344,18 +344,11 @@ config HISAX_HFC_SX
config HISAX_ENTERNOW_PCI
bool "Formula-n enter:now PCI card"
- depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
+ depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the Formula-n enter:now PCI
ISDN card.
-config HISAX_AMD7930
- bool "Am7930 (EXPERIMENTAL)"
- depends on EXPERIMENTAL && SPARC && BROKEN
- help
- This enables HiSax support for the AMD7930 chips on some SPARCs.
- This code is not finished yet.
-
endif
if ISDN_DRV_HISAX
@@ -402,6 +395,7 @@ config HISAX_ST5481
tristate "ST5481 USB ISDN modem (EXPERIMENTAL)"
depends on USB && EXPERIMENTAL
select CRC_CCITT
+ select BITREVERSE
help
This enables the driver for ST5481 based USB ISDN adapters,
e.g. the BeWan Gazel 128 USB
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 876fec6c6be..9e70c206779 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -123,11 +123,10 @@ static int avma1cs_probe(struct pcmcia_device *p_dev)
DEBUG(0, "avma1cs_attach()\n");
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local)
return -ENOMEM;
- memset(local, 0, sizeof(local_info_t));
p_dev->priv = local;
/* The io structure describes IO port mapping */
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index cede72cdbb3..17ec0b70ba1 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -227,14 +227,6 @@ const char *CardType[] = {
#define DEFAULT_CFG {5,0x2E0,0,0}
#endif
-
-#ifdef CONFIG_HISAX_AMD7930
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_AMD7930
-#define DEFAULT_CFG {12,0x3e0,0,0}
-#endif
-
#ifdef CONFIG_HISAX_NICCY
#undef DEFAULT_CARD
#undef DEFAULT_CFG
@@ -545,10 +537,6 @@ extern int setup_hfcpci(struct IsdnCard *card);
extern int setup_hfcsx(struct IsdnCard *card);
#endif
-#if CARD_AMD7930
-extern int setup_amd7930(struct IsdnCard *card);
-#endif
-
#if CARD_NICCY
extern int setup_niccy(struct IsdnCard *card);
#endif
@@ -869,14 +857,13 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
struct IsdnCard *card = cards + cardnr;
struct IsdnCardState *cs;
- cs = kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
+ cs = kzalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
if (!cs) {
printk(KERN_WARNING
"HiSax: No memory for IsdnCardState(card %d)\n",
cardnr + 1);
goto out;
}
- memset(cs, 0, sizeof(struct IsdnCardState));
card->cs = cs;
spin_lock_init(&cs->statlock);
spin_lock_init(&cs->lock);
@@ -1064,11 +1051,6 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
ret = setup_niccy(card);
break;
#endif
-#if CARD_AMD7930
- case ISDN_CTYPE_AMD7930:
- ret = setup_amd7930(card);
- break;
-#endif
#if CARD_ISURF
case ISDN_CTYPE_ISURF:
ret = setup_isurf(card);
@@ -1437,7 +1419,6 @@ static int __init HiSax_init(void)
break;
case ISDN_CTYPE_ELSA_PCI:
case ISDN_CTYPE_NETJET_S:
- case ISDN_CTYPE_AMD7930:
case ISDN_CTYPE_TELESPCI:
case ISDN_CTYPE_W6692:
case ISDN_CTYPE_NETJET_U:
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 3dacfff93f5..6eebeb441bf 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -1121,7 +1121,11 @@ setup_diva(struct IsdnCard *card)
bytecnt = 32;
}
}
+
+#ifdef __ISAPNP__
ready:
+#endif
+
printk(KERN_INFO
"Diva: %s card configured at %#lx IRQ %d\n",
(cs->subtyp == DIVA_PCI) ? "PCI" :
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index 4e180d210fa..79ab9dda7d0 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -146,9 +146,8 @@ static int elsa_cs_probe(struct pcmcia_device *link)
DEBUG(0, "elsa_cs_attach()\n");
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) return -ENOMEM;
- memset(local, 0, sizeof(local_info_t));
local->p_dev = link;
link->priv = local;
diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c
index 0d44a3f480a..34fade96a58 100644
--- a/drivers/isdn/hisax/fsm.c
+++ b/drivers/isdn/hisax/fsm.c
@@ -26,12 +26,10 @@ FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
int i;
fsm->jumpmatrix = (FSMFNPTR *)
- kmalloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL);
+ kzalloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL);
if (!fsm->jumpmatrix)
return -ENOMEM;
- memset(fsm->jumpmatrix, 0, sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count);
-
for (i = 0; i < fncount; i++)
if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) {
printk(KERN_ERR "FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n",
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c
index de9b1a4d6ba..a2fa4ecb8c8 100644
--- a/drivers/isdn/hisax/hfc4s8s_l1.c
+++ b/drivers/isdn/hisax/hfc4s8s_l1.c
@@ -1591,11 +1591,10 @@ hfc4s8s_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hfc4s8s_param *driver_data = (hfc4s8s_param *) ent->driver_data;
hfc4s8s_hw *hw;
- if (!(hw = kmalloc(sizeof(hfc4s8s_hw), GFP_ATOMIC))) {
+ if (!(hw = kzalloc(sizeof(hfc4s8s_hw), GFP_ATOMIC))) {
printk(KERN_ERR "No kmem for HFC-4S/8S card\n");
return (err);
}
- memset(hw, 0, sizeof(hfc4s8s_hw));
hw->pdev = pdev;
err = pci_enable_device(pdev);
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 5db0a85b827..8a48a3ce0a5 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1211,7 +1211,7 @@ HFCPCI_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, HFCPCI_B1_SSL, 0x80); /* tx slot */
Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* rx slot */
@@ -1229,7 +1229,7 @@ HFCPCI_l1hw(struct PStack *st, int pr, void *arg)
default:
spin_unlock_irqrestore(&cs->lock, flags);
if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcpci_l1hw loop invalid %4x", (int) arg);
+ debugl1(cs, "hfcpci_l1hw loop invalid %4lx", (long) arg);
return;
}
cs->hw.hfcpci.trm |= 0x80; /* enable IOM-loop */
@@ -1711,9 +1711,9 @@ setup_hfcpci(struct IsdnCard *card)
pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
printk(KERN_INFO
- "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
- (u_int) cs->hw.hfcpci.pci_io,
- (u_int) cs->hw.hfcpci.fifos,
+ "HFC-PCI: defined at mem %p fifo %p(%#x) IRQ %d HZ %d\n",
+ cs->hw.hfcpci.pci_io,
+ cs->hw.hfcpci.fifos,
(u_int) virt_to_bus(cs->hw.hfcpci.fifos),
cs->irq, HZ);
spin_lock_irqsave(&cs->lock, flags);
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 7105b043add..5a6989f23fc 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1481,9 +1481,8 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
iface = iface_used;
if (!
(context =
- kmalloc(sizeof(hfcusb_data), GFP_KERNEL)))
+ kzalloc(sizeof(hfcusb_data), GFP_KERNEL)))
return (-ENOMEM); /* got no mem */
- memset(context, 0, sizeof(hfcusb_data));
ep = iface->endpoint;
vcf = validconf[small_match];
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 159c5896061..3f1137e3467 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1139,12 +1139,6 @@ struct IsdnCardState {
#define CARD_HFC_SX 0
#endif
-#ifdef CONFIG_HISAX_AMD7930
-#define CARD_AMD7930 1
-#else
-#define CARD_AMD7930 0
-#endif
-
#ifdef CONFIG_HISAX_NICCY
#define CARD_NICCY 1
#ifndef ISDN_CHIP_ISAC
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
index f6db55a752c..9e088fce8c3 100644
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -841,12 +841,10 @@ new_adapter(void)
struct hisax_b_if *b_if[2];
int i;
- adapter = kmalloc(sizeof(struct fritz_adapter), GFP_KERNEL);
+ adapter = kzalloc(sizeof(struct fritz_adapter), GFP_KERNEL);
if (!adapter)
return NULL;
- memset(adapter, 0, sizeof(struct fritz_adapter));
-
adapter->isac.hisax_d_if.owner = THIS_MODULE;
adapter->isac.hisax_d_if.ifc.priv = &adapter->isac;
adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1;
diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c
index 81eac344bb0..d0fefcf999c 100644
--- a/drivers/isdn/hisax/hisax_isac.c
+++ b/drivers/isdn/hisax/hisax_isac.c
@@ -433,7 +433,7 @@ static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
char buf[256];
va_start(args, fmt);
- vsprintf(buf, fmt, args);
+ vsnprintf(buf, sizeof(buf), fmt, args);
DBG(DBG_L1M, "%s", buf);
va_end(args);
}
diff --git a/drivers/isdn/hisax/isdnhdlc.c b/drivers/isdn/hisax/isdnhdlc.c
index cbdf54c5af8..268dced6c34 100644
--- a/drivers/isdn/hisax/isdnhdlc.c
+++ b/drivers/isdn/hisax/isdnhdlc.c
@@ -35,30 +35,6 @@ MODULE_LICENSE("GPL");
/*-------------------------------------------------------------------*/
-/* bit swap table.
- * Very handy for devices with different bit order,
- * and neccessary for each transparent B-channel access for all
- * devices which works with this HDLC decoder without bit reversal.
- */
-const unsigned char isdnhdlc_bit_rev_tab[256] = {
- 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
- 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
- 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
- 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
- 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
- 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
- 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
- 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
- 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
- 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
- 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
- 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
- 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
- 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
- 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
- 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
-};
-
enum {
HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
HDLC_GET_DATA,HDLC_FAST_FLAG
@@ -621,7 +597,6 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
return len;
}
-EXPORT_SYMBOL(isdnhdlc_bit_rev_tab);
EXPORT_SYMBOL(isdnhdlc_rcv_init);
EXPORT_SYMBOL(isdnhdlc_decode);
EXPORT_SYMBOL(isdnhdlc_out_init);
diff --git a/drivers/isdn/hisax/isdnhdlc.h b/drivers/isdn/hisax/isdnhdlc.h
index 5655b5f9c48..45167d2f8fb 100644
--- a/drivers/isdn/hisax/isdnhdlc.h
+++ b/drivers/isdn/hisax/isdnhdlc.h
@@ -57,8 +57,6 @@ struct isdnhdlc_vars {
#define HDLC_CRC_ERROR 2
#define HDLC_LENGTH_ERROR 3
-extern const unsigned char isdnhdlc_bit_rev_tab[256];
-
extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56);
extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index 9522141f435..030d1625c5c 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -677,7 +677,11 @@ setup_sedlbauer(struct IsdnCard *card)
return (0);
#endif /* CONFIG_PCI */
}
+
+#ifdef __ISAPNP__
ready:
+#endif
+
/* In case of the sedlbauer pcmcia card, this region is in use,
* reserved for us by the card manager. So we do not check it
* here, it would fail.
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 46ed65334c5..45debde05fb 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -155,9 +155,8 @@ static int sedlbauer_probe(struct pcmcia_device *link)
DEBUG(0, "sedlbauer_attach()\n");
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) return -ENOMEM;
- memset(local, 0, sizeof(local_info_t));
local->cardnr = -1;
local->p_dev = link;
diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
index 75d0f248e4e..fa64115cd7c 100644
--- a/drivers/isdn/hisax/st5481_b.c
+++ b/drivers/isdn/hisax/st5481_b.c
@@ -14,6 +14,7 @@
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
+#include <linux/bitrev.h>
#include "st5481.h"
static inline void B_L1L2(struct st5481_bcs *bcs, int pr, void *arg)
@@ -72,7 +73,7 @@ static void usb_b_out(struct st5481_bcs *bcs,int buf_nr)
register unsigned char *dest = urb->transfer_buffer+len;
register unsigned int count;
for (count = 0; count < bytes_sent; count++)
- *dest++ = isdnhdlc_bit_rev_tab[*src++];
+ *dest++ = bitrev8(*src++);
}
len += bytes_sent;
} else {
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
index 1d8c2618366..b8c4855cc88 100644
--- a/drivers/isdn/hisax/st5481_d.c
+++ b/drivers/isdn/hisax/st5481_d.c
@@ -173,7 +173,7 @@ static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
char buf[256];
va_start(args, fmt);
- vsprintf(buf, fmt, args);
+ vsnprintf(buf, sizeof(buf), fmt, args);
DBG(8, "%s", buf);
va_end(args);
}
@@ -275,7 +275,7 @@ static void dout_debug(struct FsmInst *fi, char *fmt, ...)
char buf[256];
va_start(args, fmt);
- vsprintf(buf, fmt, args);
+ vsnprintf(buf, sizeof(buf), fmt, args);
DBG(0x2, "%s", buf);
va_end(args);
}
diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
index 2716aa5c60f..bb3a28a53ff 100644
--- a/drivers/isdn/hisax/st5481_init.c
+++ b/drivers/isdn/hisax/st5481_init.c
@@ -69,12 +69,10 @@ static int probe_st5481(struct usb_interface *intf,
le16_to_cpu(dev->descriptor.idProduct),
number_of_leds);
- adapter = kmalloc(sizeof(struct st5481_adapter), GFP_KERNEL);
+ adapter = kzalloc(sizeof(struct st5481_adapter), GFP_KERNEL);
if (!adapter)
return -ENOMEM;
- memset(adapter, 0, sizeof(struct st5481_adapter));
-
adapter->number_of_leds = number_of_leds;
adapter->usb_dev = dev;
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index 6b754f18379..3e3e18239ec 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -137,9 +137,8 @@ static int teles_probe(struct pcmcia_device *link)
DEBUG(0, "teles_attach()\n");
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) return -ENOMEM;
- memset(local, 0, sizeof(local_info_t));
local->cardnr = -1;
local->p_dev = link;
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
index 6bac43cc91b..b2ae4ec1e49 100644
--- a/drivers/isdn/hysdn/hycapi.c
+++ b/drivers/isdn/hysdn/hycapi.c
@@ -745,12 +745,11 @@ hycapi_capi_create(hysdn_card *card)
return 1;
}
if (!card->hyctrlinfo) {
- cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC);
+ cinfo = kzalloc(sizeof(hycapictrl_info), GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "HYSDN: no memory for capi-ctrl.\n");
return -ENOMEM;
}
- memset(cinfo, 0, sizeof(hycapictrl_info));
card->hyctrlinfo = cinfo;
cinfo->card = card;
spin_lock_init(&cinfo->lock);
diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c
index 6d0eb0f42fc..be787e16bb7 100644
--- a/drivers/isdn/hysdn/hysdn_boot.c
+++ b/drivers/isdn/hysdn/hysdn_boot.c
@@ -278,14 +278,13 @@ pof_write_open(hysdn_card * card, unsigned char **bufp)
return (-ERR_ALREADY_BOOT); /* boot already active */
}
/* error no mem available */
- if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) {
+ if (!(boot = kzalloc(sizeof(struct boot_data), GFP_KERNEL))) {
if (card->debug_flags & LOG_MEM_ERR)
hysdn_addlog(card, "POF open: unable to allocate mem");
return (-EFAULT);
}
card->boot = boot;
card->state = CARD_STATE_BOOTING;
- memset(boot, 0, sizeof(struct boot_data));
card->stopcard(card); /* first stop the card */
if (card->testram(card)) {
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index b702ed27252..9e01748a176 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -81,11 +81,10 @@ search_cards(void)
if (pci_enable_device(akt_pcidev))
continue;
- if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+ if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
return;
}
- memset(card, 0, sizeof(hysdn_card));
card->myid = cardmax; /* set own id */
card->bus = akt_pcidev->bus->number;
card->devfn = akt_pcidev->devfn; /* slot + function */
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
index d205249a124..557d96c78a6 100644
--- a/drivers/isdn/hysdn/hysdn_net.c
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -278,11 +278,10 @@ hysdn_net_create(hysdn_card * card)
return (-ENOMEM);
}
hysdn_net_release(card); /* release an existing net device */
- if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
+ if ((dev = kzalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
return (-ENOMEM);
}
- memset(dev, 0, sizeof(struct net_local)); /* clean the structure */
spin_lock_init(&((struct net_local *) dev)->lock);
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 8e2b03889f3..94a93508911 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -275,7 +275,7 @@ hysdn_conf_open(struct inode *ino, struct file *filep)
} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
/* read access -> output card info data */
- if (!(tmp = (char *) kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) {
+ if (!(tmp = kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) {
unlock_kernel();
return (-EFAULT); /* out of memory */
}
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index fcd49920b22..375d956884d 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -111,7 +111,7 @@ put_log_buffer(hysdn_card * card, char *cp)
if (pd->if_used <= 0)
return; /* no open file for read */
- if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
+ if (!(ib = kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
return; /* no memory */
strcpy(ib->log_start, cp); /* set output string */
ib->next = NULL;
@@ -204,7 +204,7 @@ hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t * off)
{
struct log_data *inf;
int len;
- struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
struct procdata *pd = NULL;
hysdn_card *card;
@@ -354,7 +354,7 @@ static unsigned int
hysdn_log_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
- struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
hysdn_card *card;
struct procdata *pd = NULL;
@@ -405,8 +405,7 @@ hysdn_proclog_init(hysdn_card * card)
/* create a cardlog proc entry */
- if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
- memset(pd, 0, sizeof(struct procdata));
+ if ((pd = kzalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) {
pd->log->proc_fops = &log_fops;
diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c
index 2cc56d6a9fa..fb350c567c6 100644
--- a/drivers/isdn/i4l/isdn_audio.c
+++ b/drivers/isdn/i4l/isdn_audio.c
@@ -328,7 +328,7 @@ adpcm_state *
isdn_audio_adpcm_init(adpcm_state * s, int nbits)
{
if (!s)
- s = (adpcm_state *) kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
+ s = kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
if (s) {
s->a = 0;
s->d = 5;
@@ -343,7 +343,7 @@ dtmf_state *
isdn_audio_dtmf_init(dtmf_state * s)
{
if (!s)
- s = (dtmf_state *) kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
+ s = kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
if (s) {
s->idx = 0;
s->last = ' ';
@@ -621,7 +621,7 @@ silence_state *
isdn_audio_silence_init(silence_state * s)
{
if (!s)
- s = (silence_state *) kmalloc(sizeof(silence_state), GFP_ATOMIC);
+ s = kmalloc(sizeof(silence_state), GFP_ATOMIC);
if (s) {
s->idx = 0;
s->state = 0;
diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c
index 0afe442db3b..a20f33b4a22 100644
--- a/drivers/isdn/i4l/isdn_bsdcomp.c
+++ b/drivers/isdn/i4l/isdn_bsdcomp.c
@@ -331,12 +331,10 @@ static void *bsd_alloc (struct isdn_ppp_comp_data *data)
* Allocate the main control structure for this instance.
*/
maxmaxcode = MAXCODE(bits);
- db = (struct bsd_db *) kmalloc (sizeof (struct bsd_db),GFP_KERNEL);
+ db = kzalloc (sizeof (struct bsd_db),GFP_KERNEL);
if (!db)
return NULL;
- memset (db, 0, sizeof(struct bsd_db));
-
db->xmit = data->flags & IPPP_COMP_FLAG_XMIT;
decomp = db->xmit ? 0 : 1;
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 69aee2602aa..6a2ef0a87ed 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1059,7 +1059,7 @@ isdn_info_update(void)
static ssize_t
isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
{
- uint minor = iminor(file->f_dentry->d_inode);
+ uint minor = iminor(file->f_path.dentry->d_inode);
int len = 0;
int drvidx;
int chidx;
@@ -1166,7 +1166,7 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
static ssize_t
isdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
{
- uint minor = iminor(file->f_dentry->d_inode);
+ uint minor = iminor(file->f_path.dentry->d_inode);
int drvidx;
int chidx;
int retval;
@@ -1228,7 +1228,7 @@ static unsigned int
isdn_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
- unsigned int minor = iminor(file->f_dentry->d_inode);
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
lock_kernel();
@@ -2072,21 +2072,19 @@ isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding)
if ((adding) && (d->rcverr))
kfree(d->rcverr);
- if (!(d->rcverr = kmalloc(sizeof(int) * m, GFP_ATOMIC))) {
+ if (!(d->rcverr = kzalloc(sizeof(int) * m, GFP_ATOMIC))) {
printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
return -1;
}
- memset((char *) d->rcverr, 0, sizeof(int) * m);
if ((adding) && (d->rcvcount))
kfree(d->rcvcount);
- if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_ATOMIC))) {
+ if (!(d->rcvcount = kzalloc(sizeof(int) * m, GFP_ATOMIC))) {
printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
if (!adding)
kfree(d->rcverr);
return -1;
}
- memset((char *) d->rcvcount, 0, sizeof(int) * m);
if ((adding) && (d->rpqueue)) {
for (j = 0; j < d->channels; j++)
@@ -2226,11 +2224,10 @@ register_isdn(isdn_if * i)
printk(KERN_WARNING "register_isdn: No write routine given.\n");
return 0;
}
- if (!(d = kmalloc(sizeof(isdn_driver_t), GFP_KERNEL))) {
+ if (!(d = kzalloc(sizeof(isdn_driver_t), GFP_KERNEL))) {
printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
return 0;
}
- memset((char *) d, 0, sizeof(isdn_driver_t));
d->maxbufsize = i->maxbufsize;
d->pktcount = 0;
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 2e4daebfb7e..838b3734e2b 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -2542,17 +2542,15 @@ isdn_net_new(char *name, struct net_device *master)
printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
return NULL;
}
- if (!(netdev = (isdn_net_dev *) kmalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
+ if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
return NULL;
}
- memset(netdev, 0, sizeof(isdn_net_dev));
- if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
+ if (!(netdev->local = kzalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
kfree(netdev);
return NULL;
}
- memset(netdev->local, 0, sizeof(isdn_net_local));
if (name == NULL)
strcpy(netdev->local->name, " ");
else
@@ -2950,7 +2948,7 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone)
isdn_net_phone *n;
if (p) {
- if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
+ if (!(n = kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
return -ENOMEM;
strcpy(n->num, phone->phone);
n->next = p->local->phone[phone->outgoing & 1];
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 119412d6bd1..4e3f127e400 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -667,7 +667,7 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
if (is->debug & 0x2)
printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
- iminor(file->f_dentry->d_inode));
+ iminor(file->f_path.dentry->d_inode));
/* just registers wait_queue hook. This doesn't really wait. */
poll_wait(file, &is->wq, wait);
@@ -717,7 +717,7 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
printk(KERN_DEBUG "ippp: device not activated.\n");
return 0;
}
- nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC);
+ nbuf = kmalloc(len + 4, GFP_ATOMIC);
if (!nbuf) {
printk(KERN_WARNING "ippp: Can't alloc buf\n");
return 0;
@@ -876,14 +876,12 @@ isdn_ppp_init(void)
#endif /* CONFIG_ISDN_MPP */
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (!(ippp_table[i] = (struct ippp_struct *)
- kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
+ if (!(ippp_table[i] = kzalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
for (j = 0; j < i; j++)
kfree(ippp_table[j]);
return -1;
}
- memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
spin_lock_init(&ippp_table[i]->buflock);
ippp_table[i]->state = 0;
ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
@@ -1529,10 +1527,8 @@ static int isdn_ppp_mp_bundle_array_init(void)
{
int i;
int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
- if( (isdn_ppp_bundle_arr = (ippp_bundle*)kmalloc(sz,
- GFP_KERNEL)) == NULL )
+ if( (isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL )
return -ENOMEM;
- memset(isdn_ppp_bundle_arr, 0, sz);
for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
return 0;
@@ -2246,13 +2242,12 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
{
struct ippp_ccp_reset *r;
- r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
+ r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
if(!r) {
printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
" structure - no mem\n");
return NULL;
}
- memset(r, 0, sizeof(struct ippp_ccp_reset));
printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
is->reset = r;
return r;
@@ -2338,13 +2333,13 @@ static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_s
id);
return NULL;
} else {
- rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
+ rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
if(!rs)
return NULL;
- memset(rs, 0, sizeof(struct ippp_ccp_reset_state));
rs->state = CCPResetIdle;
rs->is = is;
rs->id = id;
+ init_timer(&rs->timer);
rs->timer.data = (unsigned long)rs;
rs->timer.function = isdn_ppp_ccp_timer_callback;
is->reset->rs[id] = rs;
@@ -2536,6 +2531,11 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc
rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
+ if (!skb_out) {
+ kfree_skb(skb);
+ printk(KERN_ERR "ippp: decomp memory allocation failure\n");
+ return NULL;
+ }
len = ipc->decompress(stat, skb, skb_out, &rsparm);
kfree_skb(skb);
if (len <= 0) {
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 2b91bb07fc7..fc80afe555b 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1464,7 +1464,7 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
}
static void
-isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
+isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
modem_info *info = (modem_info *) tty->driver_data;
diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c
index 38619e8cd82..5484d3c38a5 100644
--- a/drivers/isdn/i4l/isdn_v110.c
+++ b/drivers/isdn/i4l/isdn_v110.c
@@ -92,9 +92,8 @@ isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
int i;
isdn_v110_stream *v;
- if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
+ if ((v = kzalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
return NULL;
- memset(v, 0, sizeof(isdn_v110_stream));
v->key = key;
v->nbits = 0;
for (i = 0; key & (1 << i); i++)
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index 730bbd07ebc..1e699bcaba0 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -1519,12 +1519,11 @@ icn_initcard(int port, char *id)
icn_card *card;
int i;
- if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) {
+ if (!(card = kzalloc(sizeof(icn_card), GFP_KERNEL))) {
printk(KERN_WARNING
"icn: (%s) Could not allocate card-struct.\n", id);
return (icn_card *) 0;
}
- memset((char *) card, 0, sizeof(icn_card));
spin_lock_init(&card->lock);
card->port = port;
card->interface.owner = THIS_MODULE;
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
index c3ae2edaf6f..e3add27dd0e 100644
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -1430,12 +1430,11 @@ isdnloop_initcard(char *id)
isdnloop_card *card;
int i;
- if (!(card = (isdnloop_card *) kmalloc(sizeof(isdnloop_card), GFP_KERNEL))) {
+ if (!(card = kzalloc(sizeof(isdnloop_card), GFP_KERNEL))) {
printk(KERN_WARNING
"isdnloop: (%s) Could not allocate card-struct.\n", id);
return (isdnloop_card *) 0;
}
- memset((char *) card, 0, sizeof(isdnloop_card));
card->interface.owner = THIS_MODULE;
card->interface.channels = ISDNLOOP_BCH;
card->interface.hl_hdrlen = 1; /* scratch area for storing ack flag*/
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index 1966f3410a1..11c1b0b6e39 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -73,14 +73,13 @@ int pcbit_init_dev(int board, int mem_base, int irq)
struct pcbit_dev *dev;
isdn_if *dev_if;
- if ((dev=kmalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL)
+ if ((dev=kzalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL)
{
printk("pcbit_init: couldn't malloc pcbit_dev struct\n");
return -ENOMEM;
}
dev_pcbit[board] = dev;
- memset(dev, 0, sizeof(struct pcbit_dev));
init_waitqueue_head(&dev->set_running_wq);
spin_lock_init(&dev->lock);
@@ -104,7 +103,7 @@ int pcbit_init_dev(int board, int mem_base, int irq)
return -EACCES;
}
- dev->b1 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
+ dev->b1 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
if (!dev->b1) {
printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
iounmap(dev->sh_mem);
@@ -113,7 +112,7 @@ int pcbit_init_dev(int board, int mem_base, int irq)
return -ENOMEM;
}
- dev->b2 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
+ dev->b2 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
if (!dev->b2) {
printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
kfree(dev->b1);
@@ -123,8 +122,6 @@ int pcbit_init_dev(int board, int mem_base, int irq)
return -ENOMEM;
}
- memset(dev->b1, 0, sizeof(struct pcbit_chan));
- memset(dev->b2, 0, sizeof(struct pcbit_chan));
dev->b2->id = 1;
INIT_WORK(&dev->qdelivery, pcbit_deliver);
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
index 0c9f6df873f..eafcce5e656 100644
--- a/drivers/isdn/pcbit/layer2.c
+++ b/drivers/isdn/pcbit/layer2.c
@@ -100,7 +100,7 @@ pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
dev_kfree_skb(skb);
return -1;
}
- if ((frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf),
+ if ((frame = kmalloc(sizeof(struct frame_buf),
GFP_ATOMIC)) == NULL) {
printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n");
dev_kfree_skb(skb);
@@ -369,13 +369,12 @@ pcbit_receive(struct pcbit_dev *dev)
kfree(dev->read_frame);
dev->read_frame = NULL;
}
- frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC);
+ frame = kzalloc(sizeof(struct frame_buf), GFP_ATOMIC);
if (frame == NULL) {
printk(KERN_WARNING "kmalloc failed\n");
return;
}
- memset(frame, 0, sizeof(struct frame_buf));
cpu = pcbit_readb(dev);
proc = pcbit_readb(dev);
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index 06c9872e8c6..150759a5cdd 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -271,14 +271,13 @@ static int __init sc_init(void)
* Horray! We found a board, Make sure we can register
* it with ISDN4Linux
*/
- interface = kmalloc(sizeof(isdn_if), GFP_KERNEL);
+ interface = kzalloc(sizeof(isdn_if), GFP_KERNEL);
if (interface == NULL) {
/*
* Oops, can't malloc isdn_if
*/
continue;
}
- memset(interface, 0, sizeof(isdn_if));
interface->owner = THIS_MODULE;
interface->hl_hdrlen = 0;
@@ -294,7 +293,7 @@ static int __init sc_init(void)
/*
* Allocate the board structure
*/
- sc_adapter[cinst] = kmalloc(sizeof(board), GFP_KERNEL);
+ sc_adapter[cinst] = kzalloc(sizeof(board), GFP_KERNEL);
if (sc_adapter[cinst] == NULL) {
/*
* Oops, can't alloc memory for the board
@@ -302,7 +301,6 @@ static int __init sc_init(void)
kfree(interface);
continue;
}
- memset(sc_adapter[cinst], 0, sizeof(board));
spin_lock_init(&sc_adapter[cinst]->lock);
if(!register_isdn(interface)) {
@@ -326,7 +324,7 @@ static int __init sc_init(void)
/*
* Allocate channels status structures
*/
- sc_adapter[cinst]->channel = kmalloc(sizeof(bchan) * channels, GFP_KERNEL);
+ sc_adapter[cinst]->channel = kzalloc(sizeof(bchan) * channels, GFP_KERNEL);
if (sc_adapter[cinst]->channel == NULL) {
/*
* Oops, can't alloc memory for the channels
@@ -336,7 +334,6 @@ static int __init sc_init(void)
kfree(sc_adapter[cinst]);
continue;
}
- memset(sc_adapter[cinst]->channel, 0, sizeof(bchan) * channels);
/*
* Lock down the hardware resources
diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
new file mode 100644
index 00000000000..703cc88d1ef
--- /dev/null
+++ b/drivers/kvm/Kconfig
@@ -0,0 +1,37 @@
+#
+# KVM configuration
+#
+menu "Virtualization"
+
+config KVM
+ tristate "Kernel-based Virtual Machine (KVM) support"
+ depends on X86 && EXPERIMENTAL
+ ---help---
+ Support hosting fully virtualized guest machines using hardware
+ virtualization extensions. You will need a fairly recent
+ processor equipped with virtualization extensions. You will also
+ need to select one or more of the processor modules below.
+
+ This module provides access to the hardware capabilities through
+ a character device node named /dev/kvm.
+
+ To compile this as a module, choose M here: the module
+ will be called kvm.
+
+ If unsure, say N.
+
+config KVM_INTEL
+ tristate "KVM for Intel processors support"
+ depends on KVM
+ ---help---
+ Provides support for KVM on Intel processors equipped with the VT
+ extensions.
+
+config KVM_AMD
+ tristate "KVM for AMD processors support"
+ depends on KVM
+ ---help---
+ Provides support for KVM on AMD processors equipped with the AMD-V
+ (SVM) extensions.
+
+endmenu
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile
new file mode 100644
index 00000000000..c0a789fa9d6
--- /dev/null
+++ b/drivers/kvm/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for Kernel-based Virtual Machine module
+#
+
+kvm-objs := kvm_main.o mmu.o x86_emulate.o
+obj-$(CONFIG_KVM) += kvm.o
+kvm-intel-objs = vmx.o
+obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
+kvm-amd-objs = svm.o
+obj-$(CONFIG_KVM_AMD) += kvm-amd.o
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
new file mode 100644
index 00000000000..2db1ca4c680
--- /dev/null
+++ b/drivers/kvm/kvm.h
@@ -0,0 +1,630 @@
+#ifndef __KVM_H
+#define __KVM_H
+
+/*
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+
+#include "vmx.h"
+#include <linux/kvm.h>
+
+#define CR0_PE_MASK (1ULL << 0)
+#define CR0_TS_MASK (1ULL << 3)
+#define CR0_NE_MASK (1ULL << 5)
+#define CR0_WP_MASK (1ULL << 16)
+#define CR0_NW_MASK (1ULL << 29)
+#define CR0_CD_MASK (1ULL << 30)
+#define CR0_PG_MASK (1ULL << 31)
+
+#define CR3_WPT_MASK (1ULL << 3)
+#define CR3_PCD_MASK (1ULL << 4)
+
+#define CR3_RESEVED_BITS 0x07ULL
+#define CR3_L_MODE_RESEVED_BITS (~((1ULL << 40) - 1) | 0x0fe7ULL)
+#define CR3_FLAGS_MASK ((1ULL << 5) - 1)
+
+#define CR4_VME_MASK (1ULL << 0)
+#define CR4_PSE_MASK (1ULL << 4)
+#define CR4_PAE_MASK (1ULL << 5)
+#define CR4_PGE_MASK (1ULL << 7)
+#define CR4_VMXE_MASK (1ULL << 13)
+
+#define KVM_GUEST_CR0_MASK \
+ (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK \
+ | CR0_NW_MASK | CR0_CD_MASK)
+#define KVM_VM_CR0_ALWAYS_ON \
+ (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK)
+#define KVM_GUEST_CR4_MASK \
+ (CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK)
+#define KVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK)
+#define KVM_RMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK | CR4_VME_MASK)
+
+#define INVALID_PAGE (~(hpa_t)0)
+#define UNMAPPED_GVA (~(gpa_t)0)
+
+#define KVM_MAX_VCPUS 1
+#define KVM_MEMORY_SLOTS 4
+#define KVM_NUM_MMU_PAGES 256
+#define KVM_MIN_FREE_MMU_PAGES 5
+#define KVM_REFILL_PAGES 25
+
+#define FX_IMAGE_SIZE 512
+#define FX_IMAGE_ALIGN 16
+#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
+
+#define DE_VECTOR 0
+#define DF_VECTOR 8
+#define TS_VECTOR 10
+#define NP_VECTOR 11
+#define SS_VECTOR 12
+#define GP_VECTOR 13
+#define PF_VECTOR 14
+
+#define SELECTOR_TI_MASK (1 << 2)
+#define SELECTOR_RPL_MASK 0x03
+
+#define IOPL_SHIFT 12
+
+/*
+ * Address types:
+ *
+ * gva - guest virtual address
+ * gpa - guest physical address
+ * gfn - guest frame number
+ * hva - host virtual address
+ * hpa - host physical address
+ * hfn - host frame number
+ */
+
+typedef unsigned long gva_t;
+typedef u64 gpa_t;
+typedef unsigned long gfn_t;
+
+typedef unsigned long hva_t;
+typedef u64 hpa_t;
+typedef unsigned long hfn_t;
+
+#define NR_PTE_CHAIN_ENTRIES 5
+
+struct kvm_pte_chain {
+ u64 *parent_ptes[NR_PTE_CHAIN_ENTRIES];
+ struct hlist_node link;
+};
+
+/*
+ * kvm_mmu_page_role, below, is defined as:
+ *
+ * bits 0:3 - total guest paging levels (2-4, or zero for real mode)
+ * bits 4:7 - page table level for this shadow (1-4)
+ * bits 8:9 - page table quadrant for 2-level guests
+ * bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode)
+ */
+union kvm_mmu_page_role {
+ unsigned word;
+ struct {
+ unsigned glevels : 4;
+ unsigned level : 4;
+ unsigned quadrant : 2;
+ unsigned pad_for_nice_hex_output : 6;
+ unsigned metaphysical : 1;
+ };
+};
+
+struct kvm_mmu_page {
+ struct list_head link;
+ struct hlist_node hash_link;
+
+ /*
+ * The following two entries are used to key the shadow page in the
+ * hash table.
+ */
+ gfn_t gfn;
+ union kvm_mmu_page_role role;
+
+ hpa_t page_hpa;
+ unsigned long slot_bitmap; /* One bit set per slot which has memory
+ * in this shadow page.
+ */
+ int global; /* Set if all ptes in this page are global */
+ int multimapped; /* More than one parent_pte? */
+ int root_count; /* Currently serving as active root */
+ union {
+ u64 *parent_pte; /* !multimapped */
+ struct hlist_head parent_ptes; /* multimapped, kvm_pte_chain */
+ };
+};
+
+struct vmcs {
+ u32 revision_id;
+ u32 abort;
+ char data[0];
+};
+
+#define vmx_msr_entry kvm_msr_entry
+
+struct kvm_vcpu;
+
+/*
+ * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level
+ * 32-bit). The kvm_mmu structure abstracts the details of the current mmu
+ * mode.
+ */
+struct kvm_mmu {
+ void (*new_cr3)(struct kvm_vcpu *vcpu);
+ int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err);
+ void (*free)(struct kvm_vcpu *vcpu);
+ gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva);
+ hpa_t root_hpa;
+ int root_level;
+ int shadow_root_level;
+
+ u64 *pae_root;
+};
+
+#define KVM_NR_MEM_OBJS 20
+
+struct kvm_mmu_memory_cache {
+ int nobjs;
+ void *objects[KVM_NR_MEM_OBJS];
+};
+
+/*
+ * We don't want allocation failures within the mmu code, so we preallocate
+ * enough memory for a single page fault in a cache.
+ */
+struct kvm_guest_debug {
+ int enabled;
+ unsigned long bp[4];
+ int singlestep;
+};
+
+enum {
+ VCPU_REGS_RAX = 0,
+ VCPU_REGS_RCX = 1,
+ VCPU_REGS_RDX = 2,
+ VCPU_REGS_RBX = 3,
+ VCPU_REGS_RSP = 4,
+ VCPU_REGS_RBP = 5,
+ VCPU_REGS_RSI = 6,
+ VCPU_REGS_RDI = 7,
+#ifdef CONFIG_X86_64
+ VCPU_REGS_R8 = 8,
+ VCPU_REGS_R9 = 9,
+ VCPU_REGS_R10 = 10,
+ VCPU_REGS_R11 = 11,
+ VCPU_REGS_R12 = 12,
+ VCPU_REGS_R13 = 13,
+ VCPU_REGS_R14 = 14,
+ VCPU_REGS_R15 = 15,
+#endif
+ NR_VCPU_REGS
+};
+
+enum {
+ VCPU_SREG_CS,
+ VCPU_SREG_DS,
+ VCPU_SREG_ES,
+ VCPU_SREG_FS,
+ VCPU_SREG_GS,
+ VCPU_SREG_SS,
+ VCPU_SREG_TR,
+ VCPU_SREG_LDTR,
+};
+
+struct kvm_vcpu {
+ struct kvm *kvm;
+ union {
+ struct vmcs *vmcs;
+ struct vcpu_svm *svm;
+ };
+ struct mutex mutex;
+ int cpu;
+ int launched;
+ int interrupt_window_open;
+ unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
+#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
+ unsigned long irq_pending[NR_IRQ_WORDS];
+ unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
+ unsigned long rip; /* needs vcpu_load_rsp_rip() */
+
+ unsigned long cr0;
+ unsigned long cr2;
+ unsigned long cr3;
+ unsigned long cr4;
+ unsigned long cr8;
+ u64 pdptrs[4]; /* pae */
+ u64 shadow_efer;
+ u64 apic_base;
+ u64 ia32_misc_enable_msr;
+ int nmsrs;
+ struct vmx_msr_entry *guest_msrs;
+ struct vmx_msr_entry *host_msrs;
+
+ struct list_head free_pages;
+ struct kvm_mmu_page page_header_buf[KVM_NUM_MMU_PAGES];
+ struct kvm_mmu mmu;
+
+ struct kvm_mmu_memory_cache mmu_pte_chain_cache;
+ struct kvm_mmu_memory_cache mmu_rmap_desc_cache;
+
+ gfn_t last_pt_write_gfn;
+ int last_pt_write_count;
+
+ struct kvm_guest_debug guest_debug;
+
+ char fx_buf[FX_BUF_SIZE];
+ char *host_fx_image;
+ char *guest_fx_image;
+
+ int mmio_needed;
+ int mmio_read_completed;
+ int mmio_is_write;
+ int mmio_size;
+ unsigned char mmio_data[8];
+ gpa_t mmio_phys_addr;
+
+ struct {
+ int active;
+ u8 save_iopl;
+ struct kvm_save_segment {
+ u16 selector;
+ unsigned long base;
+ u32 limit;
+ u32 ar;
+ } tr, es, ds, fs, gs;
+ } rmode;
+};
+
+struct kvm_memory_slot {
+ gfn_t base_gfn;
+ unsigned long npages;
+ unsigned long flags;
+ struct page **phys_mem;
+ unsigned long *dirty_bitmap;
+};
+
+struct kvm {
+ spinlock_t lock; /* protects everything except vcpus */
+ int nmemslots;
+ struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS];
+ /*
+ * Hash table of struct kvm_mmu_page.
+ */
+ struct list_head active_mmu_pages;
+ int n_free_mmu_pages;
+ struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
+ struct kvm_vcpu vcpus[KVM_MAX_VCPUS];
+ int memory_config_version;
+ int busy;
+ unsigned long rmap_overflow;
+};
+
+struct kvm_stat {
+ u32 pf_fixed;
+ u32 pf_guest;
+ u32 tlb_flush;
+ u32 invlpg;
+
+ u32 exits;
+ u32 io_exits;
+ u32 mmio_exits;
+ u32 signal_exits;
+ u32 irq_window_exits;
+ u32 halt_exits;
+ u32 request_irq_exits;
+ u32 irq_exits;
+};
+
+struct descriptor_table {
+ u16 limit;
+ unsigned long base;
+} __attribute__((packed));
+
+struct kvm_arch_ops {
+ int (*cpu_has_kvm_support)(void); /* __init */
+ int (*disabled_by_bios)(void); /* __init */
+ void (*hardware_enable)(void *dummy); /* __init */
+ void (*hardware_disable)(void *dummy);
+ int (*hardware_setup)(void); /* __init */
+ void (*hardware_unsetup)(void); /* __exit */
+
+ int (*vcpu_create)(struct kvm_vcpu *vcpu);
+ void (*vcpu_free)(struct kvm_vcpu *vcpu);
+
+ struct kvm_vcpu *(*vcpu_load)(struct kvm_vcpu *vcpu);
+ void (*vcpu_put)(struct kvm_vcpu *vcpu);
+
+ int (*set_guest_debug)(struct kvm_vcpu *vcpu,
+ struct kvm_debug_guest *dbg);
+ int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
+ int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
+ u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
+ void (*get_segment)(struct kvm_vcpu *vcpu,
+ struct kvm_segment *var, int seg);
+ void (*set_segment)(struct kvm_vcpu *vcpu,
+ struct kvm_segment *var, int seg);
+ void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
+ void (*decache_cr0_cr4_guest_bits)(struct kvm_vcpu *vcpu);
+ void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
+ void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu,
+ unsigned long cr0);
+ void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
+ void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
+ void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer);
+ void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+ void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+ void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+ void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+ unsigned long (*get_dr)(struct kvm_vcpu *vcpu, int dr);
+ void (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value,
+ int *exception);
+ void (*cache_regs)(struct kvm_vcpu *vcpu);
+ void (*decache_regs)(struct kvm_vcpu *vcpu);
+ unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
+ void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
+
+ void (*invlpg)(struct kvm_vcpu *vcpu, gva_t addr);
+ void (*tlb_flush)(struct kvm_vcpu *vcpu);
+ void (*inject_page_fault)(struct kvm_vcpu *vcpu,
+ unsigned long addr, u32 err_code);
+
+ void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code);
+
+ int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
+ int (*vcpu_setup)(struct kvm_vcpu *vcpu);
+ void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
+};
+
+extern struct kvm_stat kvm_stat;
+extern struct kvm_arch_ops *kvm_arch_ops;
+
+#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
+#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
+
+int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module);
+void kvm_exit_arch(void);
+
+void kvm_mmu_destroy(struct kvm_vcpu *vcpu);
+int kvm_mmu_create(struct kvm_vcpu *vcpu);
+int kvm_mmu_setup(struct kvm_vcpu *vcpu);
+
+int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
+void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot);
+
+hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
+#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
+#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
+static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
+hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva);
+
+void kvm_emulator_want_group7_invlpg(void);
+
+extern hpa_t bad_page_address;
+
+static inline struct page *gfn_to_page(struct kvm_memory_slot *slot, gfn_t gfn)
+{
+ return slot->phys_mem[gfn - slot->base_gfn];
+}
+
+struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
+void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
+
+enum emulation_result {
+ EMULATE_DONE, /* no further processing */
+ EMULATE_DO_MMIO, /* kvm_run filled with mmio request */
+ EMULATE_FAIL, /* can't emulate this instruction */
+};
+
+int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ unsigned long cr2, u16 error_code);
+void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
+void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
+void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
+ unsigned long *rflags);
+
+unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
+void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
+ unsigned long *rflags);
+
+struct x86_emulate_ctxt;
+
+int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
+int emulate_clts(struct kvm_vcpu *vcpu);
+int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr,
+ unsigned long *dest);
+int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr,
+ unsigned long value);
+
+void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
+void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0);
+void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0);
+void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0);
+void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
+
+int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
+int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data);
+
+void fx_init(struct kvm_vcpu *vcpu);
+
+void load_msrs(struct vmx_msr_entry *e, int n);
+void save_msrs(struct vmx_msr_entry *e, int n);
+void kvm_resched(struct kvm_vcpu *vcpu);
+
+int kvm_read_guest(struct kvm_vcpu *vcpu,
+ gva_t addr,
+ unsigned long size,
+ void *dest);
+
+int kvm_write_guest(struct kvm_vcpu *vcpu,
+ gva_t addr,
+ unsigned long size,
+ void *data);
+
+unsigned long segment_base(u16 selector);
+
+void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes);
+void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes);
+int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
+void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
+
+static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
+ u32 error_code)
+{
+ if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
+ kvm_mmu_free_some_pages(vcpu);
+ return vcpu->mmu.page_fault(vcpu, gva, error_code);
+}
+
+static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn)
+{
+ struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
+ return (slot) ? slot->phys_mem[gfn - slot->base_gfn] : NULL;
+}
+
+static inline int is_long_mode(struct kvm_vcpu *vcpu)
+{
+#ifdef CONFIG_X86_64
+ return vcpu->shadow_efer & EFER_LME;
+#else
+ return 0;
+#endif
+}
+
+static inline int is_pae(struct kvm_vcpu *vcpu)
+{
+ return vcpu->cr4 & CR4_PAE_MASK;
+}
+
+static inline int is_pse(struct kvm_vcpu *vcpu)
+{
+ return vcpu->cr4 & CR4_PSE_MASK;
+}
+
+static inline int is_paging(struct kvm_vcpu *vcpu)
+{
+ return vcpu->cr0 & CR0_PG_MASK;
+}
+
+static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot)
+{
+ return slot - kvm->memslots;
+}
+
+static inline struct kvm_mmu_page *page_header(hpa_t shadow_page)
+{
+ struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT);
+
+ return (struct kvm_mmu_page *)page->private;
+}
+
+static inline u16 read_fs(void)
+{
+ u16 seg;
+ asm ("mov %%fs, %0" : "=g"(seg));
+ return seg;
+}
+
+static inline u16 read_gs(void)
+{
+ u16 seg;
+ asm ("mov %%gs, %0" : "=g"(seg));
+ return seg;
+}
+
+static inline u16 read_ldt(void)
+{
+ u16 ldt;
+ asm ("sldt %0" : "=g"(ldt));
+ return ldt;
+}
+
+static inline void load_fs(u16 sel)
+{
+ asm ("mov %0, %%fs" : : "rm"(sel));
+}
+
+static inline void load_gs(u16 sel)
+{
+ asm ("mov %0, %%gs" : : "rm"(sel));
+}
+
+#ifndef load_ldt
+static inline void load_ldt(u16 sel)
+{
+ asm ("lldt %0" : : "g"(sel));
+}
+#endif
+
+static inline void get_idt(struct descriptor_table *table)
+{
+ asm ("sidt %0" : "=m"(*table));
+}
+
+static inline void get_gdt(struct descriptor_table *table)
+{
+ asm ("sgdt %0" : "=m"(*table));
+}
+
+static inline unsigned long read_tr_base(void)
+{
+ u16 tr;
+ asm ("str %0" : "=g"(tr));
+ return segment_base(tr);
+}
+
+#ifdef CONFIG_X86_64
+static inline unsigned long read_msr(unsigned long msr)
+{
+ u64 value;
+
+ rdmsrl(msr, value);
+ return value;
+}
+#endif
+
+static inline void fx_save(void *image)
+{
+ asm ("fxsave (%0)":: "r" (image));
+}
+
+static inline void fx_restore(void *image)
+{
+ asm ("fxrstor (%0)":: "r" (image));
+}
+
+static inline void fpu_init(void)
+{
+ asm ("finit");
+}
+
+static inline u32 get_rdx_init_val(void)
+{
+ return 0x600; /* P6 family */
+}
+
+#define ASM_VMX_VMCLEAR_RAX ".byte 0x66, 0x0f, 0xc7, 0x30"
+#define ASM_VMX_VMLAUNCH ".byte 0x0f, 0x01, 0xc2"
+#define ASM_VMX_VMRESUME ".byte 0x0f, 0x01, 0xc3"
+#define ASM_VMX_VMPTRLD_RAX ".byte 0x0f, 0xc7, 0x30"
+#define ASM_VMX_VMREAD_RDX_RAX ".byte 0x0f, 0x78, 0xd0"
+#define ASM_VMX_VMWRITE_RAX_RDX ".byte 0x0f, 0x79, 0xd0"
+#define ASM_VMX_VMWRITE_RSP_RDX ".byte 0x0f, 0x79, 0xd4"
+#define ASM_VMX_VMXOFF ".byte 0x0f, 0x01, 0xc4"
+#define ASM_VMX_VMXON_RAX ".byte 0xf3, 0x0f, 0xc7, 0x30"
+
+#define MSR_IA32_TIME_STAMP_COUNTER 0x010
+
+#define TSS_IOPB_BASE_OFFSET 0x66
+#define TSS_BASE_SIZE 0x68
+#define TSS_IOPB_SIZE (65536 / 8)
+#define TSS_REDIRECTION_SIZE (256 / 8)
+#define RMODE_TSS_SIZE (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1)
+
+#endif
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
new file mode 100644
index 00000000000..099f0afd394
--- /dev/null
+++ b/drivers/kvm/kvm_main.c
@@ -0,0 +1,2137 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This module enables machines with Intel VT-x extensions to run virtual
+ * machines without emulation or binary translation.
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ * Avi Kivity <avi@qumranet.com>
+ * Yaniv Kamay <yaniv@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "kvm.h"
+
+#include <linux/kvm.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <asm/processor.h>
+#include <linux/percpu.h>
+#include <linux/gfp.h>
+#include <asm/msr.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include <linux/reboot.h>
+#include <asm/io.h>
+#include <linux/debugfs.h>
+#include <linux/highmem.h>
+#include <linux/file.h>
+#include <asm/desc.h>
+
+#include "x86_emulate.h"
+#include "segment_descriptor.h"
+
+MODULE_AUTHOR("Qumranet");
+MODULE_LICENSE("GPL");
+
+struct kvm_arch_ops *kvm_arch_ops;
+struct kvm_stat kvm_stat;
+EXPORT_SYMBOL_GPL(kvm_stat);
+
+static struct kvm_stats_debugfs_item {
+ const char *name;
+ u32 *data;
+ struct dentry *dentry;
+} debugfs_entries[] = {
+ { "pf_fixed", &kvm_stat.pf_fixed },
+ { "pf_guest", &kvm_stat.pf_guest },
+ { "tlb_flush", &kvm_stat.tlb_flush },
+ { "invlpg", &kvm_stat.invlpg },
+ { "exits", &kvm_stat.exits },
+ { "io_exits", &kvm_stat.io_exits },
+ { "mmio_exits", &kvm_stat.mmio_exits },
+ { "signal_exits", &kvm_stat.signal_exits },
+ { "irq_window", &kvm_stat.irq_window_exits },
+ { "halt_exits", &kvm_stat.halt_exits },
+ { "request_irq", &kvm_stat.request_irq_exits },
+ { "irq_exits", &kvm_stat.irq_exits },
+ { NULL, NULL }
+};
+
+static struct dentry *debugfs_dir;
+
+#define MAX_IO_MSRS 256
+
+#define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL
+#define LMSW_GUEST_MASK 0x0eULL
+#define CR4_RESEVED_BITS (~((1ULL << 11) - 1))
+#define CR8_RESEVED_BITS (~0x0fULL)
+#define EFER_RESERVED_BITS 0xfffffffffffff2fe
+
+#ifdef CONFIG_X86_64
+// LDT or TSS descriptor in the GDT. 16 bytes.
+struct segment_descriptor_64 {
+ struct segment_descriptor s;
+ u32 base_higher;
+ u32 pad_zero;
+};
+
+#endif
+
+unsigned long segment_base(u16 selector)
+{
+ struct descriptor_table gdt;
+ struct segment_descriptor *d;
+ unsigned long table_base;
+ typedef unsigned long ul;
+ unsigned long v;
+
+ if (selector == 0)
+ return 0;
+
+ asm ("sgdt %0" : "=m"(gdt));
+ table_base = gdt.base;
+
+ if (selector & 4) { /* from ldt */
+ u16 ldt_selector;
+
+ asm ("sldt %0" : "=g"(ldt_selector));
+ table_base = segment_base(ldt_selector);
+ }
+ d = (struct segment_descriptor *)(table_base + (selector & ~7));
+ v = d->base_low | ((ul)d->base_mid << 16) | ((ul)d->base_high << 24);
+#ifdef CONFIG_X86_64
+ if (d->system == 0
+ && (d->type == 2 || d->type == 9 || d->type == 11))
+ v |= ((ul)((struct segment_descriptor_64 *)d)->base_higher) << 32;
+#endif
+ return v;
+}
+EXPORT_SYMBOL_GPL(segment_base);
+
+static inline int valid_vcpu(int n)
+{
+ return likely(n >= 0 && n < KVM_MAX_VCPUS);
+}
+
+int kvm_read_guest(struct kvm_vcpu *vcpu,
+ gva_t addr,
+ unsigned long size,
+ void *dest)
+{
+ unsigned char *host_buf = dest;
+ unsigned long req_size = size;
+
+ while (size) {
+ hpa_t paddr;
+ unsigned now;
+ unsigned offset;
+ hva_t guest_buf;
+
+ paddr = gva_to_hpa(vcpu, addr);
+
+ if (is_error_hpa(paddr))
+ break;
+
+ guest_buf = (hva_t)kmap_atomic(
+ pfn_to_page(paddr >> PAGE_SHIFT),
+ KM_USER0);
+ offset = addr & ~PAGE_MASK;
+ guest_buf |= offset;
+ now = min(size, PAGE_SIZE - offset);
+ memcpy(host_buf, (void*)guest_buf, now);
+ host_buf += now;
+ addr += now;
+ size -= now;
+ kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
+ }
+ return req_size - size;
+}
+EXPORT_SYMBOL_GPL(kvm_read_guest);
+
+int kvm_write_guest(struct kvm_vcpu *vcpu,
+ gva_t addr,
+ unsigned long size,
+ void *data)
+{
+ unsigned char *host_buf = data;
+ unsigned long req_size = size;
+
+ while (size) {
+ hpa_t paddr;
+ unsigned now;
+ unsigned offset;
+ hva_t guest_buf;
+
+ paddr = gva_to_hpa(vcpu, addr);
+
+ if (is_error_hpa(paddr))
+ break;
+
+ guest_buf = (hva_t)kmap_atomic(
+ pfn_to_page(paddr >> PAGE_SHIFT), KM_USER0);
+ offset = addr & ~PAGE_MASK;
+ guest_buf |= offset;
+ now = min(size, PAGE_SIZE - offset);
+ memcpy((void*)guest_buf, host_buf, now);
+ host_buf += now;
+ addr += now;
+ size -= now;
+ kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
+ }
+ return req_size - size;
+}
+EXPORT_SYMBOL_GPL(kvm_write_guest);
+
+static int vcpu_slot(struct kvm_vcpu *vcpu)
+{
+ return vcpu - vcpu->kvm->vcpus;
+}
+
+/*
+ * Switches to specified vcpu, until a matching vcpu_put()
+ */
+static struct kvm_vcpu *vcpu_load(struct kvm *kvm, int vcpu_slot)
+{
+ struct kvm_vcpu *vcpu = &kvm->vcpus[vcpu_slot];
+
+ mutex_lock(&vcpu->mutex);
+ if (unlikely(!vcpu->vmcs)) {
+ mutex_unlock(&vcpu->mutex);
+ return NULL;
+ }
+ return kvm_arch_ops->vcpu_load(vcpu);
+}
+
+static void vcpu_put(struct kvm_vcpu *vcpu)
+{
+ kvm_arch_ops->vcpu_put(vcpu);
+ mutex_unlock(&vcpu->mutex);
+}
+
+static int kvm_dev_open(struct inode *inode, struct file *filp)
+{
+ struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
+ int i;
+
+ if (!kvm)
+ return -ENOMEM;
+
+ spin_lock_init(&kvm->lock);
+ INIT_LIST_HEAD(&kvm->active_mmu_pages);
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ struct kvm_vcpu *vcpu = &kvm->vcpus[i];
+
+ mutex_init(&vcpu->mutex);
+ vcpu->kvm = kvm;
+ vcpu->mmu.root_hpa = INVALID_PAGE;
+ INIT_LIST_HEAD(&vcpu->free_pages);
+ }
+ filp->private_data = kvm;
+ return 0;
+}
+
+/*
+ * Free any memory in @free but not in @dont.
+ */
+static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
+ struct kvm_memory_slot *dont)
+{
+ int i;
+
+ if (!dont || free->phys_mem != dont->phys_mem)
+ if (free->phys_mem) {
+ for (i = 0; i < free->npages; ++i)
+ if (free->phys_mem[i])
+ __free_page(free->phys_mem[i]);
+ vfree(free->phys_mem);
+ }
+
+ if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
+ vfree(free->dirty_bitmap);
+
+ free->phys_mem = NULL;
+ free->npages = 0;
+ free->dirty_bitmap = NULL;
+}
+
+static void kvm_free_physmem(struct kvm *kvm)
+{
+ int i;
+
+ for (i = 0; i < kvm->nmemslots; ++i)
+ kvm_free_physmem_slot(&kvm->memslots[i], NULL);
+}
+
+static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
+{
+ vcpu_load(vcpu->kvm, vcpu_slot(vcpu));
+ kvm_mmu_destroy(vcpu);
+ vcpu_put(vcpu);
+ kvm_arch_ops->vcpu_free(vcpu);
+}
+
+static void kvm_free_vcpus(struct kvm *kvm)
+{
+ unsigned int i;
+
+ for (i = 0; i < KVM_MAX_VCPUS; ++i)
+ kvm_free_vcpu(&kvm->vcpus[i]);
+}
+
+static int kvm_dev_release(struct inode *inode, struct file *filp)
+{
+ struct kvm *kvm = filp->private_data;
+
+ kvm_free_vcpus(kvm);
+ kvm_free_physmem(kvm);
+ kfree(kvm);
+ return 0;
+}
+
+static void inject_gp(struct kvm_vcpu *vcpu)
+{
+ kvm_arch_ops->inject_gp(vcpu, 0);
+}
+
+/*
+ * Load the pae pdptrs. Return true is they are all valid.
+ */
+static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
+{
+ gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
+ unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
+ int i;
+ u64 pdpte;
+ u64 *pdpt;
+ int ret;
+ struct kvm_memory_slot *memslot;
+
+ spin_lock(&vcpu->kvm->lock);
+ memslot = gfn_to_memslot(vcpu->kvm, pdpt_gfn);
+ /* FIXME: !memslot - emulate? 0xff? */
+ pdpt = kmap_atomic(gfn_to_page(memslot, pdpt_gfn), KM_USER0);
+
+ ret = 1;
+ for (i = 0; i < 4; ++i) {
+ pdpte = pdpt[offset + i];
+ if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) {
+ ret = 0;
+ goto out;
+ }
+ }
+
+ for (i = 0; i < 4; ++i)
+ vcpu->pdptrs[i] = pdpt[offset + i];
+
+out:
+ kunmap_atomic(pdpt, KM_USER0);
+ spin_unlock(&vcpu->kvm->lock);
+
+ return ret;
+}
+
+void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+{
+ if (cr0 & CR0_RESEVED_BITS) {
+ printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
+ cr0, vcpu->cr0);
+ inject_gp(vcpu);
+ return;
+ }
+
+ if ((cr0 & CR0_NW_MASK) && !(cr0 & CR0_CD_MASK)) {
+ printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n");
+ inject_gp(vcpu);
+ return;
+ }
+
+ if ((cr0 & CR0_PG_MASK) && !(cr0 & CR0_PE_MASK)) {
+ printk(KERN_DEBUG "set_cr0: #GP, set PG flag "
+ "and a clear PE flag\n");
+ inject_gp(vcpu);
+ return;
+ }
+
+ if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
+#ifdef CONFIG_X86_64
+ if ((vcpu->shadow_efer & EFER_LME)) {
+ int cs_db, cs_l;
+
+ if (!is_pae(vcpu)) {
+ printk(KERN_DEBUG "set_cr0: #GP, start paging "
+ "in long mode while PAE is disabled\n");
+ inject_gp(vcpu);
+ return;
+ }
+ kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+ if (cs_l) {
+ printk(KERN_DEBUG "set_cr0: #GP, start paging "
+ "in long mode while CS.L == 1\n");
+ inject_gp(vcpu);
+ return;
+
+ }
+ } else
+#endif
+ if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->cr3)) {
+ printk(KERN_DEBUG "set_cr0: #GP, pdptrs "
+ "reserved bits\n");
+ inject_gp(vcpu);
+ return;
+ }
+
+ }
+
+ kvm_arch_ops->set_cr0(vcpu, cr0);
+ vcpu->cr0 = cr0;
+
+ spin_lock(&vcpu->kvm->lock);
+ kvm_mmu_reset_context(vcpu);
+ spin_unlock(&vcpu->kvm->lock);
+ return;
+}
+EXPORT_SYMBOL_GPL(set_cr0);
+
+void lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
+{
+ kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
+ set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f));
+}
+EXPORT_SYMBOL_GPL(lmsw);
+
+void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+{
+ if (cr4 & CR4_RESEVED_BITS) {
+ printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n");
+ inject_gp(vcpu);
+ return;
+ }
+
+ if (is_long_mode(vcpu)) {
+ if (!(cr4 & CR4_PAE_MASK)) {
+ printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while "
+ "in long mode\n");
+ inject_gp(vcpu);
+ return;
+ }
+ } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK)
+ && !load_pdptrs(vcpu, vcpu->cr3)) {
+ printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n");
+ inject_gp(vcpu);
+ }
+
+ if (cr4 & CR4_VMXE_MASK) {
+ printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n");
+ inject_gp(vcpu);
+ return;
+ }
+ kvm_arch_ops->set_cr4(vcpu, cr4);
+ spin_lock(&vcpu->kvm->lock);
+ kvm_mmu_reset_context(vcpu);
+ spin_unlock(&vcpu->kvm->lock);
+}
+EXPORT_SYMBOL_GPL(set_cr4);
+
+void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
+{
+ if (is_long_mode(vcpu)) {
+ if ( cr3 & CR3_L_MODE_RESEVED_BITS) {
+ printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
+ inject_gp(vcpu);
+ return;
+ }
+ } else {
+ if (cr3 & CR3_RESEVED_BITS) {
+ printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
+ inject_gp(vcpu);
+ return;
+ }
+ if (is_paging(vcpu) && is_pae(vcpu) &&
+ !load_pdptrs(vcpu, cr3)) {
+ printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
+ "reserved bits\n");
+ inject_gp(vcpu);
+ return;
+ }
+ }
+
+ vcpu->cr3 = cr3;
+ spin_lock(&vcpu->kvm->lock);
+ /*
+ * Does the new cr3 value map to physical memory? (Note, we
+ * catch an invalid cr3 even in real-mode, because it would
+ * cause trouble later on when we turn on paging anyway.)
+ *
+ * A real CPU would silently accept an invalid cr3 and would
+ * attempt to use it - with largely undefined (and often hard
+ * to debug) behavior on the guest side.
+ */
+ if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT)))
+ inject_gp(vcpu);
+ else
+ vcpu->mmu.new_cr3(vcpu);
+ spin_unlock(&vcpu->kvm->lock);
+}
+EXPORT_SYMBOL_GPL(set_cr3);
+
+void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
+{
+ if ( cr8 & CR8_RESEVED_BITS) {
+ printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8);
+ inject_gp(vcpu);
+ return;
+ }
+ vcpu->cr8 = cr8;
+}
+EXPORT_SYMBOL_GPL(set_cr8);
+
+void fx_init(struct kvm_vcpu *vcpu)
+{
+ struct __attribute__ ((__packed__)) fx_image_s {
+ u16 control; //fcw
+ u16 status; //fsw
+ u16 tag; // ftw
+ u16 opcode; //fop
+ u64 ip; // fpu ip
+ u64 operand;// fpu dp
+ u32 mxcsr;
+ u32 mxcsr_mask;
+
+ } *fx_image;
+
+ fx_save(vcpu->host_fx_image);
+ fpu_init();
+ fx_save(vcpu->guest_fx_image);
+ fx_restore(vcpu->host_fx_image);
+
+ fx_image = (struct fx_image_s *)vcpu->guest_fx_image;
+ fx_image->mxcsr = 0x1f80;
+ memset(vcpu->guest_fx_image + sizeof(struct fx_image_s),
+ 0, FX_IMAGE_SIZE - sizeof(struct fx_image_s));
+}
+EXPORT_SYMBOL_GPL(fx_init);
+
+/*
+ * Creates some virtual cpus. Good luck creating more than one.
+ */
+static int kvm_dev_ioctl_create_vcpu(struct kvm *kvm, int n)
+{
+ int r;
+ struct kvm_vcpu *vcpu;
+
+ r = -EINVAL;
+ if (!valid_vcpu(n))
+ goto out;
+
+ vcpu = &kvm->vcpus[n];
+
+ mutex_lock(&vcpu->mutex);
+
+ if (vcpu->vmcs) {
+ mutex_unlock(&vcpu->mutex);
+ return -EEXIST;
+ }
+
+ vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
+ FX_IMAGE_ALIGN);
+ vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
+
+ vcpu->cpu = -1; /* First load will set up TR */
+ r = kvm_arch_ops->vcpu_create(vcpu);
+ if (r < 0)
+ goto out_free_vcpus;
+
+ r = kvm_mmu_create(vcpu);
+ if (r < 0)
+ goto out_free_vcpus;
+
+ kvm_arch_ops->vcpu_load(vcpu);
+ r = kvm_mmu_setup(vcpu);
+ if (r >= 0)
+ r = kvm_arch_ops->vcpu_setup(vcpu);
+ vcpu_put(vcpu);
+
+ if (r < 0)
+ goto out_free_vcpus;
+
+ return 0;
+
+out_free_vcpus:
+ kvm_free_vcpu(vcpu);
+ mutex_unlock(&vcpu->mutex);
+out:
+ return r;
+}
+
+/*
+ * Allocate some memory and give it an address in the guest physical address
+ * space.
+ *
+ * Discontiguous memory is allowed, mostly for framebuffers.
+ */
+static int kvm_dev_ioctl_set_memory_region(struct kvm *kvm,
+ struct kvm_memory_region *mem)
+{
+ int r;
+ gfn_t base_gfn;
+ unsigned long npages;
+ unsigned long i;
+ struct kvm_memory_slot *memslot;
+ struct kvm_memory_slot old, new;
+ int memory_config_version;
+
+ r = -EINVAL;
+ /* General sanity checks */
+ if (mem->memory_size & (PAGE_SIZE - 1))
+ goto out;
+ if (mem->guest_phys_addr & (PAGE_SIZE - 1))
+ goto out;
+ if (mem->slot >= KVM_MEMORY_SLOTS)
+ goto out;
+ if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr)
+ goto out;
+
+ memslot = &kvm->memslots[mem->slot];
+ base_gfn = mem->guest_phys_addr >> PAGE_SHIFT;
+ npages = mem->memory_size >> PAGE_SHIFT;
+
+ if (!npages)
+ mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES;
+
+raced:
+ spin_lock(&kvm->lock);
+
+ memory_config_version = kvm->memory_config_version;
+ new = old = *memslot;
+
+ new.base_gfn = base_gfn;
+ new.npages = npages;
+ new.flags = mem->flags;
+
+ /* Disallow changing a memory slot's size. */
+ r = -EINVAL;
+ if (npages && old.npages && npages != old.npages)
+ goto out_unlock;
+
+ /* Check for overlaps */
+ r = -EEXIST;
+ for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
+ struct kvm_memory_slot *s = &kvm->memslots[i];
+
+ if (s == memslot)
+ continue;
+ if (!((base_gfn + npages <= s->base_gfn) ||
+ (base_gfn >= s->base_gfn + s->npages)))
+ goto out_unlock;
+ }
+ /*
+ * Do memory allocations outside lock. memory_config_version will
+ * detect any races.
+ */
+ spin_unlock(&kvm->lock);
+
+ /* Deallocate if slot is being removed */
+ if (!npages)
+ new.phys_mem = NULL;
+
+ /* Free page dirty bitmap if unneeded */
+ if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES))
+ new.dirty_bitmap = NULL;
+
+ r = -ENOMEM;
+
+ /* Allocate if a slot is being created */
+ if (npages && !new.phys_mem) {
+ new.phys_mem = vmalloc(npages * sizeof(struct page *));
+
+ if (!new.phys_mem)
+ goto out_free;
+
+ memset(new.phys_mem, 0, npages * sizeof(struct page *));
+ for (i = 0; i < npages; ++i) {
+ new.phys_mem[i] = alloc_page(GFP_HIGHUSER
+ | __GFP_ZERO);
+ if (!new.phys_mem[i])
+ goto out_free;
+ new.phys_mem[i]->private = 0;
+ }
+ }
+
+ /* Allocate page dirty bitmap if needed */
+ if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) {
+ unsigned dirty_bytes = ALIGN(npages, BITS_PER_LONG) / 8;
+
+ new.dirty_bitmap = vmalloc(dirty_bytes);
+ if (!new.dirty_bitmap)
+ goto out_free;
+ memset(new.dirty_bitmap, 0, dirty_bytes);
+ }
+
+ spin_lock(&kvm->lock);
+
+ if (memory_config_version != kvm->memory_config_version) {
+ spin_unlock(&kvm->lock);
+ kvm_free_physmem_slot(&new, &old);
+ goto raced;
+ }
+
+ r = -EAGAIN;
+ if (kvm->busy)
+ goto out_unlock;
+
+ if (mem->slot >= kvm->nmemslots)
+ kvm->nmemslots = mem->slot + 1;
+
+ *memslot = new;
+ ++kvm->memory_config_version;
+
+ spin_unlock(&kvm->lock);
+
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ struct kvm_vcpu *vcpu;
+
+ vcpu = vcpu_load(kvm, i);
+ if (!vcpu)
+ continue;
+ kvm_mmu_reset_context(vcpu);
+ vcpu_put(vcpu);
+ }
+
+ kvm_free_physmem_slot(&old, &new);
+ return 0;
+
+out_unlock:
+ spin_unlock(&kvm->lock);
+out_free:
+ kvm_free_physmem_slot(&new, &old);
+out:
+ return r;
+}
+
+static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot)
+{
+ spin_lock(&vcpu->kvm->lock);
+ kvm_mmu_slot_remove_write_access(vcpu, slot);
+ spin_unlock(&vcpu->kvm->lock);
+}
+
+/*
+ * Get (and clear) the dirty memory log for a memory slot.
+ */
+static int kvm_dev_ioctl_get_dirty_log(struct kvm *kvm,
+ struct kvm_dirty_log *log)
+{
+ struct kvm_memory_slot *memslot;
+ int r, i;
+ int n;
+ int cleared;
+ unsigned long any = 0;
+
+ spin_lock(&kvm->lock);
+
+ /*
+ * Prevent changes to guest memory configuration even while the lock
+ * is not taken.
+ */
+ ++kvm->busy;
+ spin_unlock(&kvm->lock);
+ r = -EINVAL;
+ if (log->slot >= KVM_MEMORY_SLOTS)
+ goto out;
+
+ memslot = &kvm->memslots[log->slot];
+ r = -ENOENT;
+ if (!memslot->dirty_bitmap)
+ goto out;
+
+ n = ALIGN(memslot->npages, 8) / 8;
+
+ for (i = 0; !any && i < n; ++i)
+ any = memslot->dirty_bitmap[i];
+
+ r = -EFAULT;
+ if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
+ goto out;
+
+
+ if (any) {
+ cleared = 0;
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ struct kvm_vcpu *vcpu = vcpu_load(kvm, i);
+
+ if (!vcpu)
+ continue;
+ if (!cleared) {
+ do_remove_write_access(vcpu, log->slot);
+ memset(memslot->dirty_bitmap, 0, n);
+ cleared = 1;
+ }
+ kvm_arch_ops->tlb_flush(vcpu);
+ vcpu_put(vcpu);
+ }
+ }
+
+ r = 0;
+
+out:
+ spin_lock(&kvm->lock);
+ --kvm->busy;
+ spin_unlock(&kvm->lock);
+ return r;
+}
+
+struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
+{
+ int i;
+
+ for (i = 0; i < kvm->nmemslots; ++i) {
+ struct kvm_memory_slot *memslot = &kvm->memslots[i];
+
+ if (gfn >= memslot->base_gfn
+ && gfn < memslot->base_gfn + memslot->npages)
+ return memslot;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(gfn_to_memslot);
+
+void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
+{
+ int i;
+ struct kvm_memory_slot *memslot = NULL;
+ unsigned long rel_gfn;
+
+ for (i = 0; i < kvm->nmemslots; ++i) {
+ memslot = &kvm->memslots[i];
+
+ if (gfn >= memslot->base_gfn
+ && gfn < memslot->base_gfn + memslot->npages) {
+
+ if (!memslot || !memslot->dirty_bitmap)
+ return;
+
+ rel_gfn = gfn - memslot->base_gfn;
+
+ /* avoid RMW */
+ if (!test_bit(rel_gfn, memslot->dirty_bitmap))
+ set_bit(rel_gfn, memslot->dirty_bitmap);
+ return;
+ }
+ }
+}
+
+static int emulator_read_std(unsigned long addr,
+ unsigned long *val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct kvm_vcpu *vcpu = ctxt->vcpu;
+ void *data = val;
+
+ while (bytes) {
+ gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+ unsigned offset = addr & (PAGE_SIZE-1);
+ unsigned tocopy = min(bytes, (unsigned)PAGE_SIZE - offset);
+ unsigned long pfn;
+ struct kvm_memory_slot *memslot;
+ void *page;
+
+ if (gpa == UNMAPPED_GVA)
+ return X86EMUL_PROPAGATE_FAULT;
+ pfn = gpa >> PAGE_SHIFT;
+ memslot = gfn_to_memslot(vcpu->kvm, pfn);
+ if (!memslot)
+ return X86EMUL_UNHANDLEABLE;
+ page = kmap_atomic(gfn_to_page(memslot, pfn), KM_USER0);
+
+ memcpy(data, page + offset, tocopy);
+
+ kunmap_atomic(page, KM_USER0);
+
+ bytes -= tocopy;
+ data += tocopy;
+ addr += tocopy;
+ }
+
+ return X86EMUL_CONTINUE;
+}
+
+static int emulator_write_std(unsigned long addr,
+ unsigned long val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ printk(KERN_ERR "emulator_write_std: addr %lx n %d\n",
+ addr, bytes);
+ return X86EMUL_UNHANDLEABLE;
+}
+
+static int emulator_read_emulated(unsigned long addr,
+ unsigned long *val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct kvm_vcpu *vcpu = ctxt->vcpu;
+
+ if (vcpu->mmio_read_completed) {
+ memcpy(val, vcpu->mmio_data, bytes);
+ vcpu->mmio_read_completed = 0;
+ return X86EMUL_CONTINUE;
+ } else if (emulator_read_std(addr, val, bytes, ctxt)
+ == X86EMUL_CONTINUE)
+ return X86EMUL_CONTINUE;
+ else {
+ gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+ if (gpa == UNMAPPED_GVA)
+ return vcpu_printf(vcpu, "not present\n"), X86EMUL_PROPAGATE_FAULT;
+ vcpu->mmio_needed = 1;
+ vcpu->mmio_phys_addr = gpa;
+ vcpu->mmio_size = bytes;
+ vcpu->mmio_is_write = 0;
+
+ return X86EMUL_UNHANDLEABLE;
+ }
+}
+
+static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
+ unsigned long val, int bytes)
+{
+ struct kvm_memory_slot *m;
+ struct page *page;
+ void *virt;
+
+ if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT))
+ return 0;
+ m = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT);
+ if (!m)
+ return 0;
+ page = gfn_to_page(m, gpa >> PAGE_SHIFT);
+ kvm_mmu_pre_write(vcpu, gpa, bytes);
+ virt = kmap_atomic(page, KM_USER0);
+ memcpy(virt + offset_in_page(gpa), &val, bytes);
+ kunmap_atomic(virt, KM_USER0);
+ kvm_mmu_post_write(vcpu, gpa, bytes);
+ return 1;
+}
+
+static int emulator_write_emulated(unsigned long addr,
+ unsigned long val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct kvm_vcpu *vcpu = ctxt->vcpu;
+ gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+
+ if (gpa == UNMAPPED_GVA)
+ return X86EMUL_PROPAGATE_FAULT;
+
+ if (emulator_write_phys(vcpu, gpa, val, bytes))
+ return X86EMUL_CONTINUE;
+
+ vcpu->mmio_needed = 1;
+ vcpu->mmio_phys_addr = gpa;
+ vcpu->mmio_size = bytes;
+ vcpu->mmio_is_write = 1;
+ memcpy(vcpu->mmio_data, &val, bytes);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int emulator_cmpxchg_emulated(unsigned long addr,
+ unsigned long old,
+ unsigned long new,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ static int reported;
+
+ if (!reported) {
+ reported = 1;
+ printk(KERN_WARNING "kvm: emulating exchange as write\n");
+ }
+ return emulator_write_emulated(addr, new, bytes, ctxt);
+}
+
+#ifdef CONFIG_X86_32
+
+static int emulator_cmpxchg8b_emulated(unsigned long addr,
+ unsigned long old_lo,
+ unsigned long old_hi,
+ unsigned long new_lo,
+ unsigned long new_hi,
+ struct x86_emulate_ctxt *ctxt)
+{
+ static int reported;
+ int r;
+
+ if (!reported) {
+ reported = 1;
+ printk(KERN_WARNING "kvm: emulating exchange8b as write\n");
+ }
+ r = emulator_write_emulated(addr, new_lo, 4, ctxt);
+ if (r != X86EMUL_CONTINUE)
+ return r;
+ return emulator_write_emulated(addr+4, new_hi, 4, ctxt);
+}
+
+#endif
+
+static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
+{
+ return kvm_arch_ops->get_segment_base(vcpu, seg);
+}
+
+int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
+{
+ return X86EMUL_CONTINUE;
+}
+
+int emulate_clts(struct kvm_vcpu *vcpu)
+{
+ unsigned long cr0;
+
+ kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
+ cr0 = vcpu->cr0 & ~CR0_TS_MASK;
+ kvm_arch_ops->set_cr0(vcpu, cr0);
+ return X86EMUL_CONTINUE;
+}
+
+int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, unsigned long *dest)
+{
+ struct kvm_vcpu *vcpu = ctxt->vcpu;
+
+ switch (dr) {
+ case 0 ... 3:
+ *dest = kvm_arch_ops->get_dr(vcpu, dr);
+ return X86EMUL_CONTINUE;
+ default:
+ printk(KERN_DEBUG "%s: unexpected dr %u\n",
+ __FUNCTION__, dr);
+ return X86EMUL_UNHANDLEABLE;
+ }
+}
+
+int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
+{
+ unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
+ int exception;
+
+ kvm_arch_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
+ if (exception) {
+ /* FIXME: better handling */
+ return X86EMUL_UNHANDLEABLE;
+ }
+ return X86EMUL_CONTINUE;
+}
+
+static void report_emulation_failure(struct x86_emulate_ctxt *ctxt)
+{
+ static int reported;
+ u8 opcodes[4];
+ unsigned long rip = ctxt->vcpu->rip;
+ unsigned long rip_linear;
+
+ rip_linear = rip + get_segment_base(ctxt->vcpu, VCPU_SREG_CS);
+
+ if (reported)
+ return;
+
+ emulator_read_std(rip_linear, (void *)opcodes, 4, ctxt);
+
+ printk(KERN_ERR "emulation failed but !mmio_needed?"
+ " rip %lx %02x %02x %02x %02x\n",
+ rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
+ reported = 1;
+}
+
+struct x86_emulate_ops emulate_ops = {
+ .read_std = emulator_read_std,
+ .write_std = emulator_write_std,
+ .read_emulated = emulator_read_emulated,
+ .write_emulated = emulator_write_emulated,
+ .cmpxchg_emulated = emulator_cmpxchg_emulated,
+#ifdef CONFIG_X86_32
+ .cmpxchg8b_emulated = emulator_cmpxchg8b_emulated,
+#endif
+};
+
+int emulate_instruction(struct kvm_vcpu *vcpu,
+ struct kvm_run *run,
+ unsigned long cr2,
+ u16 error_code)
+{
+ struct x86_emulate_ctxt emulate_ctxt;
+ int r;
+ int cs_db, cs_l;
+
+ kvm_arch_ops->cache_regs(vcpu);
+
+ kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+
+ emulate_ctxt.vcpu = vcpu;
+ emulate_ctxt.eflags = kvm_arch_ops->get_rflags(vcpu);
+ emulate_ctxt.cr2 = cr2;
+ emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM)
+ ? X86EMUL_MODE_REAL : cs_l
+ ? X86EMUL_MODE_PROT64 : cs_db
+ ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+
+ if (emulate_ctxt.mode == X86EMUL_MODE_PROT64) {
+ emulate_ctxt.cs_base = 0;
+ emulate_ctxt.ds_base = 0;
+ emulate_ctxt.es_base = 0;
+ emulate_ctxt.ss_base = 0;
+ } else {
+ emulate_ctxt.cs_base = get_segment_base(vcpu, VCPU_SREG_CS);
+ emulate_ctxt.ds_base = get_segment_base(vcpu, VCPU_SREG_DS);
+ emulate_ctxt.es_base = get_segment_base(vcpu, VCPU_SREG_ES);
+ emulate_ctxt.ss_base = get_segment_base(vcpu, VCPU_SREG_SS);
+ }
+
+ emulate_ctxt.gs_base = get_segment_base(vcpu, VCPU_SREG_GS);
+ emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS);
+
+ vcpu->mmio_is_write = 0;
+ r = x86_emulate_memop(&emulate_ctxt, &emulate_ops);
+
+ if ((r || vcpu->mmio_is_write) && run) {
+ run->mmio.phys_addr = vcpu->mmio_phys_addr;
+ memcpy(run->mmio.data, vcpu->mmio_data, 8);
+ run->mmio.len = vcpu->mmio_size;
+ run->mmio.is_write = vcpu->mmio_is_write;
+ }
+
+ if (r) {
+ if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
+ return EMULATE_DONE;
+ if (!vcpu->mmio_needed) {
+ report_emulation_failure(&emulate_ctxt);
+ return EMULATE_FAIL;
+ }
+ return EMULATE_DO_MMIO;
+ }
+
+ kvm_arch_ops->decache_regs(vcpu);
+ kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags);
+
+ if (vcpu->mmio_is_write)
+ return EMULATE_DO_MMIO;
+
+ return EMULATE_DONE;
+}
+EXPORT_SYMBOL_GPL(emulate_instruction);
+
+static u64 mk_cr_64(u64 curr_cr, u32 new_val)
+{
+ return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
+}
+
+void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
+{
+ struct descriptor_table dt = { limit, base };
+
+ kvm_arch_ops->set_gdt(vcpu, &dt);
+}
+
+void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
+{
+ struct descriptor_table dt = { limit, base };
+
+ kvm_arch_ops->set_idt(vcpu, &dt);
+}
+
+void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
+ unsigned long *rflags)
+{
+ lmsw(vcpu, msw);
+ *rflags = kvm_arch_ops->get_rflags(vcpu);
+}
+
+unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
+{
+ kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
+ switch (cr) {
+ case 0:
+ return vcpu->cr0;
+ case 2:
+ return vcpu->cr2;
+ case 3:
+ return vcpu->cr3;
+ case 4:
+ return vcpu->cr4;
+ default:
+ vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr);
+ return 0;
+ }
+}
+
+void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
+ unsigned long *rflags)
+{
+ switch (cr) {
+ case 0:
+ set_cr0(vcpu, mk_cr_64(vcpu->cr0, val));
+ *rflags = kvm_arch_ops->get_rflags(vcpu);
+ break;
+ case 2:
+ vcpu->cr2 = val;
+ break;
+ case 3:
+ set_cr3(vcpu, val);
+ break;
+ case 4:
+ set_cr4(vcpu, mk_cr_64(vcpu->cr4, val));
+ break;
+ default:
+ vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr);
+ }
+}
+
+int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
+{
+ u64 data;
+
+ switch (msr) {
+ case 0xc0010010: /* SYSCFG */
+ case 0xc0010015: /* HWCR */
+ case MSR_IA32_PLATFORM_ID:
+ case MSR_IA32_P5_MC_ADDR:
+ case MSR_IA32_P5_MC_TYPE:
+ case MSR_IA32_MC0_CTL:
+ case MSR_IA32_MCG_STATUS:
+ case MSR_IA32_MCG_CAP:
+ case MSR_IA32_MC0_MISC:
+ case MSR_IA32_MC0_MISC+4:
+ case MSR_IA32_MC0_MISC+8:
+ case MSR_IA32_MC0_MISC+12:
+ case MSR_IA32_MC0_MISC+16:
+ case MSR_IA32_UCODE_REV:
+ case MSR_IA32_PERF_STATUS:
+ /* MTRR registers */
+ case 0xfe:
+ case 0x200 ... 0x2ff:
+ data = 0;
+ break;
+ case 0xcd: /* fsb frequency */
+ data = 3;
+ break;
+ case MSR_IA32_APICBASE:
+ data = vcpu->apic_base;
+ break;
+ case MSR_IA32_MISC_ENABLE:
+ data = vcpu->ia32_misc_enable_msr;
+ break;
+#ifdef CONFIG_X86_64
+ case MSR_EFER:
+ data = vcpu->shadow_efer;
+ break;
+#endif
+ default:
+ printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", msr);
+ return 1;
+ }
+ *pdata = data;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_get_msr_common);
+
+/*
+ * Reads an msr value (of 'msr_index') into 'pdata'.
+ * Returns 0 on success, non-0 otherwise.
+ * Assumes vcpu_load() was already called.
+ */
+static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+{
+ return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
+}
+
+#ifdef CONFIG_X86_64
+
+static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
+{
+ if (efer & EFER_RESERVED_BITS) {
+ printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n",
+ efer);
+ inject_gp(vcpu);
+ return;
+ }
+
+ if (is_paging(vcpu)
+ && (vcpu->shadow_efer & EFER_LME) != (efer & EFER_LME)) {
+ printk(KERN_DEBUG "set_efer: #GP, change LME while paging\n");
+ inject_gp(vcpu);
+ return;
+ }
+
+ kvm_arch_ops->set_efer(vcpu, efer);
+
+ efer &= ~EFER_LMA;
+ efer |= vcpu->shadow_efer & EFER_LMA;
+
+ vcpu->shadow_efer = efer;
+}
+
+#endif
+
+int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+{
+ switch (msr) {
+#ifdef CONFIG_X86_64
+ case MSR_EFER:
+ set_efer(vcpu, data);
+ break;
+#endif
+ case MSR_IA32_MC0_STATUS:
+ printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
+ __FUNCTION__, data);
+ break;
+ case MSR_IA32_UCODE_REV:
+ case MSR_IA32_UCODE_WRITE:
+ case 0x200 ... 0x2ff: /* MTRRs */
+ break;
+ case MSR_IA32_APICBASE:
+ vcpu->apic_base = data;
+ break;
+ case MSR_IA32_MISC_ENABLE:
+ vcpu->ia32_misc_enable_msr = data;
+ break;
+ default:
+ printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr);
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_set_msr_common);
+
+/*
+ * Writes msr value into into the appropriate "register".
+ * Returns 0 on success, non-0 otherwise.
+ * Assumes vcpu_load() was already called.
+ */
+static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+{
+ return kvm_arch_ops->set_msr(vcpu, msr_index, data);
+}
+
+void kvm_resched(struct kvm_vcpu *vcpu)
+{
+ vcpu_put(vcpu);
+ cond_resched();
+ /* Cannot fail - no vcpu unplug yet. */
+ vcpu_load(vcpu->kvm, vcpu_slot(vcpu));
+}
+EXPORT_SYMBOL_GPL(kvm_resched);
+
+void load_msrs(struct vmx_msr_entry *e, int n)
+{
+ int i;
+
+ for (i = 0; i < n; ++i)
+ wrmsrl(e[i].index, e[i].data);
+}
+EXPORT_SYMBOL_GPL(load_msrs);
+
+void save_msrs(struct vmx_msr_entry *e, int n)
+{
+ int i;
+
+ for (i = 0; i < n; ++i)
+ rdmsrl(e[i].index, e[i].data);
+}
+EXPORT_SYMBOL_GPL(save_msrs);
+
+static int kvm_dev_ioctl_run(struct kvm *kvm, struct kvm_run *kvm_run)
+{
+ struct kvm_vcpu *vcpu;
+ int r;
+
+ if (!valid_vcpu(kvm_run->vcpu))
+ return -EINVAL;
+
+ vcpu = vcpu_load(kvm, kvm_run->vcpu);
+ if (!vcpu)
+ return -ENOENT;
+
+ if (kvm_run->emulated) {
+ kvm_arch_ops->skip_emulated_instruction(vcpu);
+ kvm_run->emulated = 0;
+ }
+
+ if (kvm_run->mmio_completed) {
+ memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
+ vcpu->mmio_read_completed = 1;
+ }
+
+ vcpu->mmio_needed = 0;
+
+ r = kvm_arch_ops->run(vcpu, kvm_run);
+
+ vcpu_put(vcpu);
+ return r;
+}
+
+static int kvm_dev_ioctl_get_regs(struct kvm *kvm, struct kvm_regs *regs)
+{
+ struct kvm_vcpu *vcpu;
+
+ if (!valid_vcpu(regs->vcpu))
+ return -EINVAL;
+
+ vcpu = vcpu_load(kvm, regs->vcpu);
+ if (!vcpu)
+ return -ENOENT;
+
+ kvm_arch_ops->cache_regs(vcpu);
+
+ regs->rax = vcpu->regs[VCPU_REGS_RAX];
+ regs->rbx = vcpu->regs[VCPU_REGS_RBX];
+ regs->rcx = vcpu->regs[VCPU_REGS_RCX];
+ regs->rdx = vcpu->regs[VCPU_REGS_RDX];
+ regs->rsi = vcpu->regs[VCPU_REGS_RSI];
+ regs->rdi = vcpu->regs[VCPU_REGS_RDI];
+ regs->rsp = vcpu->regs[VCPU_REGS_RSP];
+ regs->rbp = vcpu->regs[VCPU_REGS_RBP];
+#ifdef CONFIG_X86_64
+ regs->r8 = vcpu->regs[VCPU_REGS_R8];
+ regs->r9 = vcpu->regs[VCPU_REGS_R9];
+ regs->r10 = vcpu->regs[VCPU_REGS_R10];
+ regs->r11 = vcpu->regs[VCPU_REGS_R11];
+ regs->r12 = vcpu->regs[VCPU_REGS_R12];
+ regs->r13 = vcpu->regs[VCPU_REGS_R13];
+ regs->r14 = vcpu->regs[VCPU_REGS_R14];
+ regs->r15 = vcpu->regs[VCPU_REGS_R15];
+#endif
+
+ regs->rip = vcpu->rip;
+ regs->rflags = kvm_arch_ops->get_rflags(vcpu);
+
+ /*
+ * Don't leak debug flags in case they were set for guest debugging
+ */
+ if (vcpu->guest_debug.enabled && vcpu->guest_debug.singlestep)
+ regs->rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
+
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
+static int kvm_dev_ioctl_set_regs(struct kvm *kvm, struct kvm_regs *regs)
+{
+ struct kvm_vcpu *vcpu;
+
+ if (!valid_vcpu(regs->vcpu))
+ return -EINVAL;
+
+ vcpu = vcpu_load(kvm, regs->vcpu);
+ if (!vcpu)
+ return -ENOENT;
+
+ vcpu->regs[VCPU_REGS_RAX] = regs->rax;
+ vcpu->regs[VCPU_REGS_RBX] = regs->rbx;
+ vcpu->regs[VCPU_REGS_RCX] = regs->rcx;
+ vcpu->regs[VCPU_REGS_RDX] = regs->rdx;
+ vcpu->regs[VCPU_REGS_RSI] = regs->rsi;
+ vcpu->regs[VCPU_REGS_RDI] = regs->rdi;
+ vcpu->regs[VCPU_REGS_RSP] = regs->rsp;
+ vcpu->regs[VCPU_REGS_RBP] = regs->rbp;
+#ifdef CONFIG_X86_64
+ vcpu->regs[VCPU_REGS_R8] = regs->r8;
+ vcpu->regs[VCPU_REGS_R9] = regs->r9;
+ vcpu->regs[VCPU_REGS_R10] = regs->r10;
+ vcpu->regs[VCPU_REGS_R11] = regs->r11;
+ vcpu->regs[VCPU_REGS_R12] = regs->r12;
+ vcpu->regs[VCPU_REGS_R13] = regs->r13;
+ vcpu->regs[VCPU_REGS_R14] = regs->r14;
+ vcpu->regs[VCPU_REGS_R15] = regs->r15;
+#endif
+
+ vcpu->rip = regs->rip;
+ kvm_arch_ops->set_rflags(vcpu, regs->rflags);
+
+ kvm_arch_ops->decache_regs(vcpu);
+
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
+static void get_segment(struct kvm_vcpu *vcpu,
+ struct kvm_segment *var, int seg)
+{
+ return kvm_arch_ops->get_segment(vcpu, var, seg);
+}
+
+static int kvm_dev_ioctl_get_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
+{
+ struct kvm_vcpu *vcpu;
+ struct descriptor_table dt;
+
+ if (!valid_vcpu(sregs->vcpu))
+ return -EINVAL;
+ vcpu = vcpu_load(kvm, sregs->vcpu);
+ if (!vcpu)
+ return -ENOENT;
+
+ get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
+ get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
+ get_segment(vcpu, &sregs->es, VCPU_SREG_ES);
+ get_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
+ get_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
+ get_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
+
+ get_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
+ get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
+
+ kvm_arch_ops->get_idt(vcpu, &dt);
+ sregs->idt.limit = dt.limit;
+ sregs->idt.base = dt.base;
+ kvm_arch_ops->get_gdt(vcpu, &dt);
+ sregs->gdt.limit = dt.limit;
+ sregs->gdt.base = dt.base;
+
+ kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
+ sregs->cr0 = vcpu->cr0;
+ sregs->cr2 = vcpu->cr2;
+ sregs->cr3 = vcpu->cr3;
+ sregs->cr4 = vcpu->cr4;
+ sregs->cr8 = vcpu->cr8;
+ sregs->efer = vcpu->shadow_efer;
+ sregs->apic_base = vcpu->apic_base;
+
+ memcpy(sregs->interrupt_bitmap, vcpu->irq_pending,
+ sizeof sregs->interrupt_bitmap);
+
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
+static void set_segment(struct kvm_vcpu *vcpu,
+ struct kvm_segment *var, int seg)
+{
+ return kvm_arch_ops->set_segment(vcpu, var, seg);
+}
+
+static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
+{
+ struct kvm_vcpu *vcpu;
+ int mmu_reset_needed = 0;
+ int i;
+ struct descriptor_table dt;
+
+ if (!valid_vcpu(sregs->vcpu))
+ return -EINVAL;
+ vcpu = vcpu_load(kvm, sregs->vcpu);
+ if (!vcpu)
+ return -ENOENT;
+
+ set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
+ set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
+ set_segment(vcpu, &sregs->es, VCPU_SREG_ES);
+ set_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
+ set_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
+ set_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
+
+ set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
+ set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
+
+ dt.limit = sregs->idt.limit;
+ dt.base = sregs->idt.base;
+ kvm_arch_ops->set_idt(vcpu, &dt);
+ dt.limit = sregs->gdt.limit;
+ dt.base = sregs->gdt.base;
+ kvm_arch_ops->set_gdt(vcpu, &dt);
+
+ vcpu->cr2 = sregs->cr2;
+ mmu_reset_needed |= vcpu->cr3 != sregs->cr3;
+ vcpu->cr3 = sregs->cr3;
+
+ vcpu->cr8 = sregs->cr8;
+
+ mmu_reset_needed |= vcpu->shadow_efer != sregs->efer;
+#ifdef CONFIG_X86_64
+ kvm_arch_ops->set_efer(vcpu, sregs->efer);
+#endif
+ vcpu->apic_base = sregs->apic_base;
+
+ kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
+
+ mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
+ kvm_arch_ops->set_cr0_no_modeswitch(vcpu, sregs->cr0);
+
+ mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
+ kvm_arch_ops->set_cr4(vcpu, sregs->cr4);
+ if (!is_long_mode(vcpu) && is_pae(vcpu))
+ load_pdptrs(vcpu, vcpu->cr3);
+
+ if (mmu_reset_needed)
+ kvm_mmu_reset_context(vcpu);
+
+ memcpy(vcpu->irq_pending, sregs->interrupt_bitmap,
+ sizeof vcpu->irq_pending);
+ vcpu->irq_summary = 0;
+ for (i = 0; i < NR_IRQ_WORDS; ++i)
+ if (vcpu->irq_pending[i])
+ __set_bit(i, &vcpu->irq_summary);
+
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
+/*
+ * List of msr numbers which we expose to userspace through KVM_GET_MSRS
+ * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST.
+ *
+ * This list is modified at module load time to reflect the
+ * capabilities of the host cpu.
+ */
+static u32 msrs_to_save[] = {
+ MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
+ MSR_K6_STAR,
+#ifdef CONFIG_X86_64
+ MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
+#endif
+ MSR_IA32_TIME_STAMP_COUNTER,
+};
+
+static unsigned num_msrs_to_save;
+
+static u32 emulated_msrs[] = {
+ MSR_IA32_MISC_ENABLE,
+};
+
+static __init void kvm_init_msr_list(void)
+{
+ u32 dummy[2];
+ unsigned i, j;
+
+ for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) {
+ if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0)
+ continue;
+ if (j < i)
+ msrs_to_save[j] = msrs_to_save[i];
+ j++;
+ }
+ num_msrs_to_save = j;
+}
+
+/*
+ * Adapt set_msr() to msr_io()'s calling convention
+ */
+static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
+{
+ return set_msr(vcpu, index, *data);
+}
+
+/*
+ * Read or write a bunch of msrs. All parameters are kernel addresses.
+ *
+ * @return number of msrs set successfully.
+ */
+static int __msr_io(struct kvm *kvm, struct kvm_msrs *msrs,
+ struct kvm_msr_entry *entries,
+ int (*do_msr)(struct kvm_vcpu *vcpu,
+ unsigned index, u64 *data))
+{
+ struct kvm_vcpu *vcpu;
+ int i;
+
+ if (!valid_vcpu(msrs->vcpu))
+ return -EINVAL;
+
+ vcpu = vcpu_load(kvm, msrs->vcpu);
+ if (!vcpu)
+ return -ENOENT;
+
+ for (i = 0; i < msrs->nmsrs; ++i)
+ if (do_msr(vcpu, entries[i].index, &entries[i].data))
+ break;
+
+ vcpu_put(vcpu);
+
+ return i;
+}
+
+/*
+ * Read or write a bunch of msrs. Parameters are user addresses.
+ *
+ * @return number of msrs set successfully.
+ */
+static int msr_io(struct kvm *kvm, struct kvm_msrs __user *user_msrs,
+ int (*do_msr)(struct kvm_vcpu *vcpu,
+ unsigned index, u64 *data),
+ int writeback)
+{
+ struct kvm_msrs msrs;
+ struct kvm_msr_entry *entries;
+ int r, n;
+ unsigned size;
+
+ r = -EFAULT;
+ if (copy_from_user(&msrs, user_msrs, sizeof msrs))
+ goto out;
+
+ r = -E2BIG;
+ if (msrs.nmsrs >= MAX_IO_MSRS)
+ goto out;
+
+ r = -ENOMEM;
+ size = sizeof(struct kvm_msr_entry) * msrs.nmsrs;
+ entries = vmalloc(size);
+ if (!entries)
+ goto out;
+
+ r = -EFAULT;
+ if (copy_from_user(entries, user_msrs->entries, size))
+ goto out_free;
+
+ r = n = __msr_io(kvm, &msrs, entries, do_msr);
+ if (r < 0)
+ goto out_free;
+
+ r = -EFAULT;
+ if (writeback && copy_to_user(user_msrs->entries, entries, size))
+ goto out_free;
+
+ r = n;
+
+out_free:
+ vfree(entries);
+out:
+ return r;
+}
+
+/*
+ * Translate a guest virtual address to a guest physical address.
+ */
+static int kvm_dev_ioctl_translate(struct kvm *kvm, struct kvm_translation *tr)
+{
+ unsigned long vaddr = tr->linear_address;
+ struct kvm_vcpu *vcpu;
+ gpa_t gpa;
+
+ vcpu = vcpu_load(kvm, tr->vcpu);
+ if (!vcpu)
+ return -ENOENT;
+ spin_lock(&kvm->lock);
+ gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr);
+ tr->physical_address = gpa;
+ tr->valid = gpa != UNMAPPED_GVA;
+ tr->writeable = 1;
+ tr->usermode = 0;
+ spin_unlock(&kvm->lock);
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
+static int kvm_dev_ioctl_interrupt(struct kvm *kvm, struct kvm_interrupt *irq)
+{
+ struct kvm_vcpu *vcpu;
+
+ if (!valid_vcpu(irq->vcpu))
+ return -EINVAL;
+ if (irq->irq < 0 || irq->irq >= 256)
+ return -EINVAL;
+ vcpu = vcpu_load(kvm, irq->vcpu);
+ if (!vcpu)
+ return -ENOENT;
+
+ set_bit(irq->irq, vcpu->irq_pending);
+ set_bit(irq->irq / BITS_PER_LONG, &vcpu->irq_summary);
+
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
+static int kvm_dev_ioctl_debug_guest(struct kvm *kvm,
+ struct kvm_debug_guest *dbg)
+{
+ struct kvm_vcpu *vcpu;
+ int r;
+
+ if (!valid_vcpu(dbg->vcpu))
+ return -EINVAL;
+ vcpu = vcpu_load(kvm, dbg->vcpu);
+ if (!vcpu)
+ return -ENOENT;
+
+ r = kvm_arch_ops->set_guest_debug(vcpu, dbg);
+
+ vcpu_put(vcpu);
+
+ return r;
+}
+
+static long kvm_dev_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm *kvm = filp->private_data;
+ void __user *argp = (void __user *)arg;
+ int r = -EINVAL;
+
+ switch (ioctl) {
+ case KVM_GET_API_VERSION:
+ r = KVM_API_VERSION;
+ break;
+ case KVM_CREATE_VCPU: {
+ r = kvm_dev_ioctl_create_vcpu(kvm, arg);
+ if (r)
+ goto out;
+ break;
+ }
+ case KVM_RUN: {
+ struct kvm_run kvm_run;
+
+ r = -EFAULT;
+ if (copy_from_user(&kvm_run, argp, sizeof kvm_run))
+ goto out;
+ r = kvm_dev_ioctl_run(kvm, &kvm_run);
+ if (r < 0 && r != -EINTR)
+ goto out;
+ if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) {
+ r = -EFAULT;
+ goto out;
+ }
+ break;
+ }
+ case KVM_GET_REGS: {
+ struct kvm_regs kvm_regs;
+
+ r = -EFAULT;
+ if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
+ goto out;
+ r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &kvm_regs, sizeof kvm_regs))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_REGS: {
+ struct kvm_regs kvm_regs;
+
+ r = -EFAULT;
+ if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
+ goto out;
+ r = kvm_dev_ioctl_set_regs(kvm, &kvm_regs);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_GET_SREGS: {
+ struct kvm_sregs kvm_sregs;
+
+ r = -EFAULT;
+ if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
+ goto out;
+ r = kvm_dev_ioctl_get_sregs(kvm, &kvm_sregs);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_SREGS: {
+ struct kvm_sregs kvm_sregs;
+
+ r = -EFAULT;
+ if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
+ goto out;
+ r = kvm_dev_ioctl_set_sregs(kvm, &kvm_sregs);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_TRANSLATE: {
+ struct kvm_translation tr;
+
+ r = -EFAULT;
+ if (copy_from_user(&tr, argp, sizeof tr))
+ goto out;
+ r = kvm_dev_ioctl_translate(kvm, &tr);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &tr, sizeof tr))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_INTERRUPT: {
+ struct kvm_interrupt irq;
+
+ r = -EFAULT;
+ if (copy_from_user(&irq, argp, sizeof irq))
+ goto out;
+ r = kvm_dev_ioctl_interrupt(kvm, &irq);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_DEBUG_GUEST: {
+ struct kvm_debug_guest dbg;
+
+ r = -EFAULT;
+ if (copy_from_user(&dbg, argp, sizeof dbg))
+ goto out;
+ r = kvm_dev_ioctl_debug_guest(kvm, &dbg);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_MEMORY_REGION: {
+ struct kvm_memory_region kvm_mem;
+
+ r = -EFAULT;
+ if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
+ goto out;
+ r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem);
+ if (r)
+ goto out;
+ break;
+ }
+ case KVM_GET_DIRTY_LOG: {
+ struct kvm_dirty_log log;
+
+ r = -EFAULT;
+ if (copy_from_user(&log, argp, sizeof log))
+ goto out;
+ r = kvm_dev_ioctl_get_dirty_log(kvm, &log);
+ if (r)
+ goto out;
+ break;
+ }
+ case KVM_GET_MSRS:
+ r = msr_io(kvm, argp, get_msr, 1);
+ break;
+ case KVM_SET_MSRS:
+ r = msr_io(kvm, argp, do_set_msr, 0);
+ break;
+ case KVM_GET_MSR_INDEX_LIST: {
+ struct kvm_msr_list __user *user_msr_list = argp;
+ struct kvm_msr_list msr_list;
+ unsigned n;
+
+ r = -EFAULT;
+ if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list))
+ goto out;
+ n = msr_list.nmsrs;
+ msr_list.nmsrs = num_msrs_to_save + ARRAY_SIZE(emulated_msrs);
+ if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list))
+ goto out;
+ r = -E2BIG;
+ if (n < num_msrs_to_save)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(user_msr_list->indices, &msrs_to_save,
+ num_msrs_to_save * sizeof(u32)))
+ goto out;
+ if (copy_to_user(user_msr_list->indices
+ + num_msrs_to_save * sizeof(u32),
+ &emulated_msrs,
+ ARRAY_SIZE(emulated_msrs) * sizeof(u32)))
+ goto out;
+ r = 0;
+ break;
+ }
+ default:
+ ;
+ }
+out:
+ return r;
+}
+
+static struct page *kvm_dev_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int *type)
+{
+ struct kvm *kvm = vma->vm_file->private_data;
+ unsigned long pgoff;
+ struct kvm_memory_slot *slot;
+ struct page *page;
+
+ *type = VM_FAULT_MINOR;
+ pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+ slot = gfn_to_memslot(kvm, pgoff);
+ if (!slot)
+ return NOPAGE_SIGBUS;
+ page = gfn_to_page(slot, pgoff);
+ if (!page)
+ return NOPAGE_SIGBUS;
+ get_page(page);
+ return page;
+}
+
+static struct vm_operations_struct kvm_dev_vm_ops = {
+ .nopage = kvm_dev_nopage,
+};
+
+static int kvm_dev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ vma->vm_ops = &kvm_dev_vm_ops;
+ return 0;
+}
+
+static struct file_operations kvm_chardev_ops = {
+ .open = kvm_dev_open,
+ .release = kvm_dev_release,
+ .unlocked_ioctl = kvm_dev_ioctl,
+ .compat_ioctl = kvm_dev_ioctl,
+ .mmap = kvm_dev_mmap,
+};
+
+static struct miscdevice kvm_dev = {
+ MISC_DYNAMIC_MINOR,
+ "kvm",
+ &kvm_chardev_ops,
+};
+
+static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
+ void *v)
+{
+ if (val == SYS_RESTART) {
+ /*
+ * Some (well, at least mine) BIOSes hang on reboot if
+ * in vmx root mode.
+ */
+ printk(KERN_INFO "kvm: exiting hardware virtualization\n");
+ on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block kvm_reboot_notifier = {
+ .notifier_call = kvm_reboot,
+ .priority = 0,
+};
+
+static __init void kvm_init_debug(void)
+{
+ struct kvm_stats_debugfs_item *p;
+
+ debugfs_dir = debugfs_create_dir("kvm", NULL);
+ for (p = debugfs_entries; p->name; ++p)
+ p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir,
+ p->data);
+}
+
+static void kvm_exit_debug(void)
+{
+ struct kvm_stats_debugfs_item *p;
+
+ for (p = debugfs_entries; p->name; ++p)
+ debugfs_remove(p->dentry);
+ debugfs_remove(debugfs_dir);
+}
+
+hpa_t bad_page_address;
+
+int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
+{
+ int r;
+
+ if (kvm_arch_ops) {
+ printk(KERN_ERR "kvm: already loaded the other module\n");
+ return -EEXIST;
+ }
+
+ if (!ops->cpu_has_kvm_support()) {
+ printk(KERN_ERR "kvm: no hardware support\n");
+ return -EOPNOTSUPP;
+ }
+ if (ops->disabled_by_bios()) {
+ printk(KERN_ERR "kvm: disabled by bios\n");
+ return -EOPNOTSUPP;
+ }
+
+ kvm_arch_ops = ops;
+
+ r = kvm_arch_ops->hardware_setup();
+ if (r < 0)
+ return r;
+
+ on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
+ register_reboot_notifier(&kvm_reboot_notifier);
+
+ kvm_chardev_ops.owner = module;
+
+ r = misc_register(&kvm_dev);
+ if (r) {
+ printk (KERN_ERR "kvm: misc device register failed\n");
+ goto out_free;
+ }
+
+ return r;
+
+out_free:
+ unregister_reboot_notifier(&kvm_reboot_notifier);
+ on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
+ kvm_arch_ops->hardware_unsetup();
+ return r;
+}
+
+void kvm_exit_arch(void)
+{
+ misc_deregister(&kvm_dev);
+
+ unregister_reboot_notifier(&kvm_reboot_notifier);
+ on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
+ kvm_arch_ops->hardware_unsetup();
+ kvm_arch_ops = NULL;
+}
+
+static __init int kvm_init(void)
+{
+ static struct page *bad_page;
+ int r = 0;
+
+ kvm_init_debug();
+
+ kvm_init_msr_list();
+
+ if ((bad_page = alloc_page(GFP_KERNEL)) == NULL) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ bad_page_address = page_to_pfn(bad_page) << PAGE_SHIFT;
+ memset(__va(bad_page_address), 0, PAGE_SIZE);
+
+ return r;
+
+out:
+ kvm_exit_debug();
+ return r;
+}
+
+static __exit void kvm_exit(void)
+{
+ kvm_exit_debug();
+ __free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT));
+}
+
+module_init(kvm_init)
+module_exit(kvm_exit)
+
+EXPORT_SYMBOL_GPL(kvm_init_arch);
+EXPORT_SYMBOL_GPL(kvm_exit_arch);
diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h
new file mode 100644
index 00000000000..74cc862f493
--- /dev/null
+++ b/drivers/kvm/kvm_svm.h
@@ -0,0 +1,44 @@
+#ifndef __KVM_SVM_H
+#define __KVM_SVM_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <asm/msr.h>
+
+#include "svm.h"
+#include "kvm.h"
+
+static const u32 host_save_msrs[] = {
+#ifdef CONFIG_X86_64
+ MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
+ MSR_FS_BASE, MSR_GS_BASE,
+#endif
+ MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
+ MSR_IA32_DEBUGCTLMSR, /*MSR_IA32_LASTBRANCHFROMIP,
+ MSR_IA32_LASTBRANCHTOIP, MSR_IA32_LASTINTFROMIP,MSR_IA32_LASTINTTOIP,*/
+};
+
+#define NR_HOST_SAVE_MSRS (sizeof(host_save_msrs) / sizeof(*host_save_msrs))
+#define NUM_DB_REGS 4
+
+struct vcpu_svm {
+ struct vmcb *vmcb;
+ unsigned long vmcb_pa;
+ struct svm_cpu_data *svm_data;
+ uint64_t asid_generation;
+
+ unsigned long cr0;
+ unsigned long cr4;
+ unsigned long db_regs[NUM_DB_REGS];
+
+ u64 next_rip;
+
+ u64 host_msrs[NR_HOST_SAVE_MSRS];
+ unsigned long host_cr2;
+ unsigned long host_db_regs[NUM_DB_REGS];
+ unsigned long host_dr6;
+ unsigned long host_dr7;
+};
+
+#endif
+
diff --git a/drivers/kvm/kvm_vmx.h b/drivers/kvm/kvm_vmx.h
new file mode 100644
index 00000000000..d139f73fb6e
--- /dev/null
+++ b/drivers/kvm/kvm_vmx.h
@@ -0,0 +1,14 @@
+#ifndef __KVM_VMX_H
+#define __KVM_VMX_H
+
+#ifdef CONFIG_X86_64
+/*
+ * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt
+ * mechanism (cpu bug AA24)
+ */
+#define NR_BAD_MSRS 2
+#else
+#define NR_BAD_MSRS 0
+#endif
+
+#endif
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
new file mode 100644
index 00000000000..be793770f31
--- /dev/null
+++ b/drivers/kvm/mmu.c
@@ -0,0 +1,1454 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This module enables machines with Intel VT-x extensions to run virtual
+ * machines without emulation or binary translation.
+ *
+ * MMU support
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ * Yaniv Kamay <yaniv@qumranet.com>
+ * Avi Kivity <avi@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/page.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/module.h>
+
+#include "vmx.h"
+#include "kvm.h"
+
+#undef MMU_DEBUG
+
+#undef AUDIT
+
+#ifdef AUDIT
+static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg);
+#else
+static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {}
+#endif
+
+#ifdef MMU_DEBUG
+
+#define pgprintk(x...) do { if (dbg) printk(x); } while (0)
+#define rmap_printk(x...) do { if (dbg) printk(x); } while (0)
+
+#else
+
+#define pgprintk(x...) do { } while (0)
+#define rmap_printk(x...) do { } while (0)
+
+#endif
+
+#if defined(MMU_DEBUG) || defined(AUDIT)
+static int dbg = 1;
+#endif
+
+#define ASSERT(x) \
+ if (!(x)) { \
+ printk(KERN_WARNING "assertion failed %s:%d: %s\n", \
+ __FILE__, __LINE__, #x); \
+ }
+
+#define PT64_PT_BITS 9
+#define PT64_ENT_PER_PAGE (1 << PT64_PT_BITS)
+#define PT32_PT_BITS 10
+#define PT32_ENT_PER_PAGE (1 << PT32_PT_BITS)
+
+#define PT_WRITABLE_SHIFT 1
+
+#define PT_PRESENT_MASK (1ULL << 0)
+#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
+#define PT_USER_MASK (1ULL << 2)
+#define PT_PWT_MASK (1ULL << 3)
+#define PT_PCD_MASK (1ULL << 4)
+#define PT_ACCESSED_MASK (1ULL << 5)
+#define PT_DIRTY_MASK (1ULL << 6)
+#define PT_PAGE_SIZE_MASK (1ULL << 7)
+#define PT_PAT_MASK (1ULL << 7)
+#define PT_GLOBAL_MASK (1ULL << 8)
+#define PT64_NX_MASK (1ULL << 63)
+
+#define PT_PAT_SHIFT 7
+#define PT_DIR_PAT_SHIFT 12
+#define PT_DIR_PAT_MASK (1ULL << PT_DIR_PAT_SHIFT)
+
+#define PT32_DIR_PSE36_SIZE 4
+#define PT32_DIR_PSE36_SHIFT 13
+#define PT32_DIR_PSE36_MASK (((1ULL << PT32_DIR_PSE36_SIZE) - 1) << PT32_DIR_PSE36_SHIFT)
+
+
+#define PT32_PTE_COPY_MASK \
+ (PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK | PT_GLOBAL_MASK)
+
+#define PT64_PTE_COPY_MASK (PT64_NX_MASK | PT32_PTE_COPY_MASK)
+
+#define PT_FIRST_AVAIL_BITS_SHIFT 9
+#define PT64_SECOND_AVAIL_BITS_SHIFT 52
+
+#define PT_SHADOW_PS_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
+#define PT_SHADOW_IO_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
+
+#define PT_SHADOW_WRITABLE_SHIFT (PT_FIRST_AVAIL_BITS_SHIFT + 1)
+#define PT_SHADOW_WRITABLE_MASK (1ULL << PT_SHADOW_WRITABLE_SHIFT)
+
+#define PT_SHADOW_USER_SHIFT (PT_SHADOW_WRITABLE_SHIFT + 1)
+#define PT_SHADOW_USER_MASK (1ULL << (PT_SHADOW_USER_SHIFT))
+
+#define PT_SHADOW_BITS_OFFSET (PT_SHADOW_WRITABLE_SHIFT - PT_WRITABLE_SHIFT)
+
+#define VALID_PAGE(x) ((x) != INVALID_PAGE)
+
+#define PT64_LEVEL_BITS 9
+
+#define PT64_LEVEL_SHIFT(level) \
+ ( PAGE_SHIFT + (level - 1) * PT64_LEVEL_BITS )
+
+#define PT64_LEVEL_MASK(level) \
+ (((1ULL << PT64_LEVEL_BITS) - 1) << PT64_LEVEL_SHIFT(level))
+
+#define PT64_INDEX(address, level)\
+ (((address) >> PT64_LEVEL_SHIFT(level)) & ((1 << PT64_LEVEL_BITS) - 1))
+
+
+#define PT32_LEVEL_BITS 10
+
+#define PT32_LEVEL_SHIFT(level) \
+ ( PAGE_SHIFT + (level - 1) * PT32_LEVEL_BITS )
+
+#define PT32_LEVEL_MASK(level) \
+ (((1ULL << PT32_LEVEL_BITS) - 1) << PT32_LEVEL_SHIFT(level))
+
+#define PT32_INDEX(address, level)\
+ (((address) >> PT32_LEVEL_SHIFT(level)) & ((1 << PT32_LEVEL_BITS) - 1))
+
+
+#define PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & PAGE_MASK)
+#define PT64_DIR_BASE_ADDR_MASK \
+ (PT64_BASE_ADDR_MASK & ~((1ULL << (PAGE_SHIFT + PT64_LEVEL_BITS)) - 1))
+
+#define PT32_BASE_ADDR_MASK PAGE_MASK
+#define PT32_DIR_BASE_ADDR_MASK \
+ (PAGE_MASK & ~((1ULL << (PAGE_SHIFT + PT32_LEVEL_BITS)) - 1))
+
+
+#define PFERR_PRESENT_MASK (1U << 0)
+#define PFERR_WRITE_MASK (1U << 1)
+#define PFERR_USER_MASK (1U << 2)
+#define PFERR_FETCH_MASK (1U << 4)
+
+#define PT64_ROOT_LEVEL 4
+#define PT32_ROOT_LEVEL 2
+#define PT32E_ROOT_LEVEL 3
+
+#define PT_DIRECTORY_LEVEL 2
+#define PT_PAGE_TABLE_LEVEL 1
+
+#define RMAP_EXT 4
+
+struct kvm_rmap_desc {
+ u64 *shadow_ptes[RMAP_EXT];
+ struct kvm_rmap_desc *more;
+};
+
+static int is_write_protection(struct kvm_vcpu *vcpu)
+{
+ return vcpu->cr0 & CR0_WP_MASK;
+}
+
+static int is_cpuid_PSE36(void)
+{
+ return 1;
+}
+
+static int is_nx(struct kvm_vcpu *vcpu)
+{
+ return vcpu->shadow_efer & EFER_NX;
+}
+
+static int is_present_pte(unsigned long pte)
+{
+ return pte & PT_PRESENT_MASK;
+}
+
+static int is_writeble_pte(unsigned long pte)
+{
+ return pte & PT_WRITABLE_MASK;
+}
+
+static int is_io_pte(unsigned long pte)
+{
+ return pte & PT_SHADOW_IO_MARK;
+}
+
+static int is_rmap_pte(u64 pte)
+{
+ return (pte & (PT_WRITABLE_MASK | PT_PRESENT_MASK))
+ == (PT_WRITABLE_MASK | PT_PRESENT_MASK);
+}
+
+static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
+ size_t objsize, int min)
+{
+ void *obj;
+
+ if (cache->nobjs >= min)
+ return 0;
+ while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
+ obj = kzalloc(objsize, GFP_NOWAIT);
+ if (!obj)
+ return -ENOMEM;
+ cache->objects[cache->nobjs++] = obj;
+ }
+ return 0;
+}
+
+static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
+{
+ while (mc->nobjs)
+ kfree(mc->objects[--mc->nobjs]);
+}
+
+static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
+{
+ int r;
+
+ r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache,
+ sizeof(struct kvm_pte_chain), 4);
+ if (r)
+ goto out;
+ r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache,
+ sizeof(struct kvm_rmap_desc), 1);
+out:
+ return r;
+}
+
+static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
+{
+ mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
+ mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache);
+}
+
+static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
+ size_t size)
+{
+ void *p;
+
+ BUG_ON(!mc->nobjs);
+ p = mc->objects[--mc->nobjs];
+ memset(p, 0, size);
+ return p;
+}
+
+static void mmu_memory_cache_free(struct kvm_mmu_memory_cache *mc, void *obj)
+{
+ if (mc->nobjs < KVM_NR_MEM_OBJS)
+ mc->objects[mc->nobjs++] = obj;
+ else
+ kfree(obj);
+}
+
+static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu)
+{
+ return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache,
+ sizeof(struct kvm_pte_chain));
+}
+
+static void mmu_free_pte_chain(struct kvm_vcpu *vcpu,
+ struct kvm_pte_chain *pc)
+{
+ mmu_memory_cache_free(&vcpu->mmu_pte_chain_cache, pc);
+}
+
+static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
+{
+ return mmu_memory_cache_alloc(&vcpu->mmu_rmap_desc_cache,
+ sizeof(struct kvm_rmap_desc));
+}
+
+static void mmu_free_rmap_desc(struct kvm_vcpu *vcpu,
+ struct kvm_rmap_desc *rd)
+{
+ mmu_memory_cache_free(&vcpu->mmu_rmap_desc_cache, rd);
+}
+
+/*
+ * Reverse mapping data structures:
+ *
+ * If page->private bit zero is zero, then page->private points to the
+ * shadow page table entry that points to page_address(page).
+ *
+ * If page->private bit zero is one, (then page->private & ~1) points
+ * to a struct kvm_rmap_desc containing more mappings.
+ */
+static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte)
+{
+ struct page *page;
+ struct kvm_rmap_desc *desc;
+ int i;
+
+ if (!is_rmap_pte(*spte))
+ return;
+ page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT);
+ if (!page->private) {
+ rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte);
+ page->private = (unsigned long)spte;
+ } else if (!(page->private & 1)) {
+ rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte);
+ desc = mmu_alloc_rmap_desc(vcpu);
+ desc->shadow_ptes[0] = (u64 *)page->private;
+ desc->shadow_ptes[1] = spte;
+ page->private = (unsigned long)desc | 1;
+ } else {
+ rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte);
+ desc = (struct kvm_rmap_desc *)(page->private & ~1ul);
+ while (desc->shadow_ptes[RMAP_EXT-1] && desc->more)
+ desc = desc->more;
+ if (desc->shadow_ptes[RMAP_EXT-1]) {
+ desc->more = mmu_alloc_rmap_desc(vcpu);
+ desc = desc->more;
+ }
+ for (i = 0; desc->shadow_ptes[i]; ++i)
+ ;
+ desc->shadow_ptes[i] = spte;
+ }
+}
+
+static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
+ struct page *page,
+ struct kvm_rmap_desc *desc,
+ int i,
+ struct kvm_rmap_desc *prev_desc)
+{
+ int j;
+
+ for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j)
+ ;
+ desc->shadow_ptes[i] = desc->shadow_ptes[j];
+ desc->shadow_ptes[j] = NULL;
+ if (j != 0)
+ return;
+ if (!prev_desc && !desc->more)
+ page->private = (unsigned long)desc->shadow_ptes[0];
+ else
+ if (prev_desc)
+ prev_desc->more = desc->more;
+ else
+ page->private = (unsigned long)desc->more | 1;
+ mmu_free_rmap_desc(vcpu, desc);
+}
+
+static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
+{
+ struct page *page;
+ struct kvm_rmap_desc *desc;
+ struct kvm_rmap_desc *prev_desc;
+ int i;
+
+ if (!is_rmap_pte(*spte))
+ return;
+ page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT);
+ if (!page->private) {
+ printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte);
+ BUG();
+ } else if (!(page->private & 1)) {
+ rmap_printk("rmap_remove: %p %llx 1->0\n", spte, *spte);
+ if ((u64 *)page->private != spte) {
+ printk(KERN_ERR "rmap_remove: %p %llx 1->BUG\n",
+ spte, *spte);
+ BUG();
+ }
+ page->private = 0;
+ } else {
+ rmap_printk("rmap_remove: %p %llx many->many\n", spte, *spte);
+ desc = (struct kvm_rmap_desc *)(page->private & ~1ul);
+ prev_desc = NULL;
+ while (desc) {
+ for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
+ if (desc->shadow_ptes[i] == spte) {
+ rmap_desc_remove_entry(vcpu, page,
+ desc, i,
+ prev_desc);
+ return;
+ }
+ prev_desc = desc;
+ desc = desc->more;
+ }
+ BUG();
+ }
+}
+
+static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
+{
+ struct kvm *kvm = vcpu->kvm;
+ struct page *page;
+ struct kvm_memory_slot *slot;
+ struct kvm_rmap_desc *desc;
+ u64 *spte;
+
+ slot = gfn_to_memslot(kvm, gfn);
+ BUG_ON(!slot);
+ page = gfn_to_page(slot, gfn);
+
+ while (page->private) {
+ if (!(page->private & 1))
+ spte = (u64 *)page->private;
+ else {
+ desc = (struct kvm_rmap_desc *)(page->private & ~1ul);
+ spte = desc->shadow_ptes[0];
+ }
+ BUG_ON(!spte);
+ BUG_ON((*spte & PT64_BASE_ADDR_MASK) !=
+ page_to_pfn(page) << PAGE_SHIFT);
+ BUG_ON(!(*spte & PT_PRESENT_MASK));
+ BUG_ON(!(*spte & PT_WRITABLE_MASK));
+ rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
+ rmap_remove(vcpu, spte);
+ kvm_arch_ops->tlb_flush(vcpu);
+ *spte &= ~(u64)PT_WRITABLE_MASK;
+ }
+}
+
+static int is_empty_shadow_page(hpa_t page_hpa)
+{
+ u64 *pos;
+ u64 *end;
+
+ for (pos = __va(page_hpa), end = pos + PAGE_SIZE / sizeof(u64);
+ pos != end; pos++)
+ if (*pos != 0) {
+ printk(KERN_ERR "%s: %p %llx\n", __FUNCTION__,
+ pos, *pos);
+ return 0;
+ }
+ return 1;
+}
+
+static void kvm_mmu_free_page(struct kvm_vcpu *vcpu, hpa_t page_hpa)
+{
+ struct kvm_mmu_page *page_head = page_header(page_hpa);
+
+ ASSERT(is_empty_shadow_page(page_hpa));
+ list_del(&page_head->link);
+ page_head->page_hpa = page_hpa;
+ list_add(&page_head->link, &vcpu->free_pages);
+ ++vcpu->kvm->n_free_mmu_pages;
+}
+
+static unsigned kvm_page_table_hashfn(gfn_t gfn)
+{
+ return gfn;
+}
+
+static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
+ u64 *parent_pte)
+{
+ struct kvm_mmu_page *page;
+
+ if (list_empty(&vcpu->free_pages))
+ return NULL;
+
+ page = list_entry(vcpu->free_pages.next, struct kvm_mmu_page, link);
+ list_del(&page->link);
+ list_add(&page->link, &vcpu->kvm->active_mmu_pages);
+ ASSERT(is_empty_shadow_page(page->page_hpa));
+ page->slot_bitmap = 0;
+ page->global = 1;
+ page->multimapped = 0;
+ page->parent_pte = parent_pte;
+ --vcpu->kvm->n_free_mmu_pages;
+ return page;
+}
+
+static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *page, u64 *parent_pte)
+{
+ struct kvm_pte_chain *pte_chain;
+ struct hlist_node *node;
+ int i;
+
+ if (!parent_pte)
+ return;
+ if (!page->multimapped) {
+ u64 *old = page->parent_pte;
+
+ if (!old) {
+ page->parent_pte = parent_pte;
+ return;
+ }
+ page->multimapped = 1;
+ pte_chain = mmu_alloc_pte_chain(vcpu);
+ INIT_HLIST_HEAD(&page->parent_ptes);
+ hlist_add_head(&pte_chain->link, &page->parent_ptes);
+ pte_chain->parent_ptes[0] = old;
+ }
+ hlist_for_each_entry(pte_chain, node, &page->parent_ptes, link) {
+ if (pte_chain->parent_ptes[NR_PTE_CHAIN_ENTRIES-1])
+ continue;
+ for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i)
+ if (!pte_chain->parent_ptes[i]) {
+ pte_chain->parent_ptes[i] = parent_pte;
+ return;
+ }
+ }
+ pte_chain = mmu_alloc_pte_chain(vcpu);
+ BUG_ON(!pte_chain);
+ hlist_add_head(&pte_chain->link, &page->parent_ptes);
+ pte_chain->parent_ptes[0] = parent_pte;
+}
+
+static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *page,
+ u64 *parent_pte)
+{
+ struct kvm_pte_chain *pte_chain;
+ struct hlist_node *node;
+ int i;
+
+ if (!page->multimapped) {
+ BUG_ON(page->parent_pte != parent_pte);
+ page->parent_pte = NULL;
+ return;
+ }
+ hlist_for_each_entry(pte_chain, node, &page->parent_ptes, link)
+ for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) {
+ if (!pte_chain->parent_ptes[i])
+ break;
+ if (pte_chain->parent_ptes[i] != parent_pte)
+ continue;
+ while (i + 1 < NR_PTE_CHAIN_ENTRIES
+ && pte_chain->parent_ptes[i + 1]) {
+ pte_chain->parent_ptes[i]
+ = pte_chain->parent_ptes[i + 1];
+ ++i;
+ }
+ pte_chain->parent_ptes[i] = NULL;
+ if (i == 0) {
+ hlist_del(&pte_chain->link);
+ mmu_free_pte_chain(vcpu, pte_chain);
+ if (hlist_empty(&page->parent_ptes)) {
+ page->multimapped = 0;
+ page->parent_pte = NULL;
+ }
+ }
+ return;
+ }
+ BUG();
+}
+
+static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm_vcpu *vcpu,
+ gfn_t gfn)
+{
+ unsigned index;
+ struct hlist_head *bucket;
+ struct kvm_mmu_page *page;
+ struct hlist_node *node;
+
+ pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn);
+ index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
+ bucket = &vcpu->kvm->mmu_page_hash[index];
+ hlist_for_each_entry(page, node, bucket, hash_link)
+ if (page->gfn == gfn && !page->role.metaphysical) {
+ pgprintk("%s: found role %x\n",
+ __FUNCTION__, page->role.word);
+ return page;
+ }
+ return NULL;
+}
+
+static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
+ gfn_t gfn,
+ gva_t gaddr,
+ unsigned level,
+ int metaphysical,
+ u64 *parent_pte)
+{
+ union kvm_mmu_page_role role;
+ unsigned index;
+ unsigned quadrant;
+ struct hlist_head *bucket;
+ struct kvm_mmu_page *page;
+ struct hlist_node *node;
+
+ role.word = 0;
+ role.glevels = vcpu->mmu.root_level;
+ role.level = level;
+ role.metaphysical = metaphysical;
+ if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) {
+ quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
+ quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
+ role.quadrant = quadrant;
+ }
+ pgprintk("%s: looking gfn %lx role %x\n", __FUNCTION__,
+ gfn, role.word);
+ index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
+ bucket = &vcpu->kvm->mmu_page_hash[index];
+ hlist_for_each_entry(page, node, bucket, hash_link)
+ if (page->gfn == gfn && page->role.word == role.word) {
+ mmu_page_add_parent_pte(vcpu, page, parent_pte);
+ pgprintk("%s: found\n", __FUNCTION__);
+ return page;
+ }
+ page = kvm_mmu_alloc_page(vcpu, parent_pte);
+ if (!page)
+ return page;
+ pgprintk("%s: adding gfn %lx role %x\n", __FUNCTION__, gfn, role.word);
+ page->gfn = gfn;
+ page->role = role;
+ hlist_add_head(&page->hash_link, bucket);
+ if (!metaphysical)
+ rmap_write_protect(vcpu, gfn);
+ return page;
+}
+
+static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *page)
+{
+ unsigned i;
+ u64 *pt;
+ u64 ent;
+
+ pt = __va(page->page_hpa);
+
+ if (page->role.level == PT_PAGE_TABLE_LEVEL) {
+ for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
+ if (pt[i] & PT_PRESENT_MASK)
+ rmap_remove(vcpu, &pt[i]);
+ pt[i] = 0;
+ }
+ kvm_arch_ops->tlb_flush(vcpu);
+ return;
+ }
+
+ for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
+ ent = pt[i];
+
+ pt[i] = 0;
+ if (!(ent & PT_PRESENT_MASK))
+ continue;
+ ent &= PT64_BASE_ADDR_MASK;
+ mmu_page_remove_parent_pte(vcpu, page_header(ent), &pt[i]);
+ }
+}
+
+static void kvm_mmu_put_page(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *page,
+ u64 *parent_pte)
+{
+ mmu_page_remove_parent_pte(vcpu, page, parent_pte);
+}
+
+static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *page)
+{
+ u64 *parent_pte;
+
+ while (page->multimapped || page->parent_pte) {
+ if (!page->multimapped)
+ parent_pte = page->parent_pte;
+ else {
+ struct kvm_pte_chain *chain;
+
+ chain = container_of(page->parent_ptes.first,
+ struct kvm_pte_chain, link);
+ parent_pte = chain->parent_ptes[0];
+ }
+ BUG_ON(!parent_pte);
+ kvm_mmu_put_page(vcpu, page, parent_pte);
+ *parent_pte = 0;
+ }
+ kvm_mmu_page_unlink_children(vcpu, page);
+ if (!page->root_count) {
+ hlist_del(&page->hash_link);
+ kvm_mmu_free_page(vcpu, page->page_hpa);
+ } else {
+ list_del(&page->link);
+ list_add(&page->link, &vcpu->kvm->active_mmu_pages);
+ }
+}
+
+static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
+{
+ unsigned index;
+ struct hlist_head *bucket;
+ struct kvm_mmu_page *page;
+ struct hlist_node *node, *n;
+ int r;
+
+ pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn);
+ r = 0;
+ index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
+ bucket = &vcpu->kvm->mmu_page_hash[index];
+ hlist_for_each_entry_safe(page, node, n, bucket, hash_link)
+ if (page->gfn == gfn && !page->role.metaphysical) {
+ pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn,
+ page->role.word);
+ kvm_mmu_zap_page(vcpu, page);
+ r = 1;
+ }
+ return r;
+}
+
+static void page_header_update_slot(struct kvm *kvm, void *pte, gpa_t gpa)
+{
+ int slot = memslot_id(kvm, gfn_to_memslot(kvm, gpa >> PAGE_SHIFT));
+ struct kvm_mmu_page *page_head = page_header(__pa(pte));
+
+ __set_bit(slot, &page_head->slot_bitmap);
+}
+
+hpa_t safe_gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa)
+{
+ hpa_t hpa = gpa_to_hpa(vcpu, gpa);
+
+ return is_error_hpa(hpa) ? bad_page_address | (gpa & ~PAGE_MASK): hpa;
+}
+
+hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa)
+{
+ struct kvm_memory_slot *slot;
+ struct page *page;
+
+ ASSERT((gpa & HPA_ERR_MASK) == 0);
+ slot = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT);
+ if (!slot)
+ return gpa | HPA_ERR_MASK;
+ page = gfn_to_page(slot, gpa >> PAGE_SHIFT);
+ return ((hpa_t)page_to_pfn(page) << PAGE_SHIFT)
+ | (gpa & (PAGE_SIZE-1));
+}
+
+hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva)
+{
+ gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva);
+
+ if (gpa == UNMAPPED_GVA)
+ return UNMAPPED_GVA;
+ return gpa_to_hpa(vcpu, gpa);
+}
+
+static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
+{
+}
+
+static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p)
+{
+ int level = PT32E_ROOT_LEVEL;
+ hpa_t table_addr = vcpu->mmu.root_hpa;
+
+ for (; ; level--) {
+ u32 index = PT64_INDEX(v, level);
+ u64 *table;
+ u64 pte;
+
+ ASSERT(VALID_PAGE(table_addr));
+ table = __va(table_addr);
+
+ if (level == 1) {
+ pte = table[index];
+ if (is_present_pte(pte) && is_writeble_pte(pte))
+ return 0;
+ mark_page_dirty(vcpu->kvm, v >> PAGE_SHIFT);
+ page_header_update_slot(vcpu->kvm, table, v);
+ table[index] = p | PT_PRESENT_MASK | PT_WRITABLE_MASK |
+ PT_USER_MASK;
+ rmap_add(vcpu, &table[index]);
+ return 0;
+ }
+
+ if (table[index] == 0) {
+ struct kvm_mmu_page *new_table;
+ gfn_t pseudo_gfn;
+
+ pseudo_gfn = (v & PT64_DIR_BASE_ADDR_MASK)
+ >> PAGE_SHIFT;
+ new_table = kvm_mmu_get_page(vcpu, pseudo_gfn,
+ v, level - 1,
+ 1, &table[index]);
+ if (!new_table) {
+ pgprintk("nonpaging_map: ENOMEM\n");
+ return -ENOMEM;
+ }
+
+ table[index] = new_table->page_hpa | PT_PRESENT_MASK
+ | PT_WRITABLE_MASK | PT_USER_MASK;
+ }
+ table_addr = table[index] & PT64_BASE_ADDR_MASK;
+ }
+}
+
+static void mmu_free_roots(struct kvm_vcpu *vcpu)
+{
+ int i;
+ struct kvm_mmu_page *page;
+
+#ifdef CONFIG_X86_64
+ if (vcpu->mmu.shadow_root_level == PT64_ROOT_LEVEL) {
+ hpa_t root = vcpu->mmu.root_hpa;
+
+ ASSERT(VALID_PAGE(root));
+ page = page_header(root);
+ --page->root_count;
+ vcpu->mmu.root_hpa = INVALID_PAGE;
+ return;
+ }
+#endif
+ for (i = 0; i < 4; ++i) {
+ hpa_t root = vcpu->mmu.pae_root[i];
+
+ ASSERT(VALID_PAGE(root));
+ root &= PT64_BASE_ADDR_MASK;
+ page = page_header(root);
+ --page->root_count;
+ vcpu->mmu.pae_root[i] = INVALID_PAGE;
+ }
+ vcpu->mmu.root_hpa = INVALID_PAGE;
+}
+
+static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
+{
+ int i;
+ gfn_t root_gfn;
+ struct kvm_mmu_page *page;
+
+ root_gfn = vcpu->cr3 >> PAGE_SHIFT;
+
+#ifdef CONFIG_X86_64
+ if (vcpu->mmu.shadow_root_level == PT64_ROOT_LEVEL) {
+ hpa_t root = vcpu->mmu.root_hpa;
+
+ ASSERT(!VALID_PAGE(root));
+ page = kvm_mmu_get_page(vcpu, root_gfn, 0,
+ PT64_ROOT_LEVEL, 0, NULL);
+ root = page->page_hpa;
+ ++page->root_count;
+ vcpu->mmu.root_hpa = root;
+ return;
+ }
+#endif
+ for (i = 0; i < 4; ++i) {
+ hpa_t root = vcpu->mmu.pae_root[i];
+
+ ASSERT(!VALID_PAGE(root));
+ if (vcpu->mmu.root_level == PT32E_ROOT_LEVEL)
+ root_gfn = vcpu->pdptrs[i] >> PAGE_SHIFT;
+ else if (vcpu->mmu.root_level == 0)
+ root_gfn = 0;
+ page = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
+ PT32_ROOT_LEVEL, !is_paging(vcpu),
+ NULL);
+ root = page->page_hpa;
+ ++page->root_count;
+ vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK;
+ }
+ vcpu->mmu.root_hpa = __pa(vcpu->mmu.pae_root);
+}
+
+static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr)
+{
+ return vaddr;
+}
+
+static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
+ u32 error_code)
+{
+ gpa_t addr = gva;
+ hpa_t paddr;
+ int r;
+
+ r = mmu_topup_memory_caches(vcpu);
+ if (r)
+ return r;
+
+ ASSERT(vcpu);
+ ASSERT(VALID_PAGE(vcpu->mmu.root_hpa));
+
+
+ paddr = gpa_to_hpa(vcpu , addr & PT64_BASE_ADDR_MASK);
+
+ if (is_error_hpa(paddr))
+ return 1;
+
+ return nonpaging_map(vcpu, addr & PAGE_MASK, paddr);
+}
+
+static void nonpaging_free(struct kvm_vcpu *vcpu)
+{
+ mmu_free_roots(vcpu);
+}
+
+static int nonpaging_init_context(struct kvm_vcpu *vcpu)
+{
+ struct kvm_mmu *context = &vcpu->mmu;
+
+ context->new_cr3 = nonpaging_new_cr3;
+ context->page_fault = nonpaging_page_fault;
+ context->gva_to_gpa = nonpaging_gva_to_gpa;
+ context->free = nonpaging_free;
+ context->root_level = 0;
+ context->shadow_root_level = PT32E_ROOT_LEVEL;
+ mmu_alloc_roots(vcpu);
+ ASSERT(VALID_PAGE(context->root_hpa));
+ kvm_arch_ops->set_cr3(vcpu, context->root_hpa);
+ return 0;
+}
+
+static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
+{
+ ++kvm_stat.tlb_flush;
+ kvm_arch_ops->tlb_flush(vcpu);
+}
+
+static void paging_new_cr3(struct kvm_vcpu *vcpu)
+{
+ pgprintk("%s: cr3 %lx\n", __FUNCTION__, vcpu->cr3);
+ mmu_free_roots(vcpu);
+ if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
+ kvm_mmu_free_some_pages(vcpu);
+ mmu_alloc_roots(vcpu);
+ kvm_mmu_flush_tlb(vcpu);
+ kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
+}
+
+static void mark_pagetable_nonglobal(void *shadow_pte)
+{
+ page_header(__pa(shadow_pte))->global = 0;
+}
+
+static inline void set_pte_common(struct kvm_vcpu *vcpu,
+ u64 *shadow_pte,
+ gpa_t gaddr,
+ int dirty,
+ u64 access_bits,
+ gfn_t gfn)
+{
+ hpa_t paddr;
+
+ *shadow_pte |= access_bits << PT_SHADOW_BITS_OFFSET;
+ if (!dirty)
+ access_bits &= ~PT_WRITABLE_MASK;
+
+ paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK);
+
+ *shadow_pte |= access_bits;
+
+ if (!(*shadow_pte & PT_GLOBAL_MASK))
+ mark_pagetable_nonglobal(shadow_pte);
+
+ if (is_error_hpa(paddr)) {
+ *shadow_pte |= gaddr;
+ *shadow_pte |= PT_SHADOW_IO_MARK;
+ *shadow_pte &= ~PT_PRESENT_MASK;
+ return;
+ }
+
+ *shadow_pte |= paddr;
+
+ if (access_bits & PT_WRITABLE_MASK) {
+ struct kvm_mmu_page *shadow;
+
+ shadow = kvm_mmu_lookup_page(vcpu, gfn);
+ if (shadow) {
+ pgprintk("%s: found shadow page for %lx, marking ro\n",
+ __FUNCTION__, gfn);
+ access_bits &= ~PT_WRITABLE_MASK;
+ if (is_writeble_pte(*shadow_pte)) {
+ *shadow_pte &= ~PT_WRITABLE_MASK;
+ kvm_arch_ops->tlb_flush(vcpu);
+ }
+ }
+ }
+
+ if (access_bits & PT_WRITABLE_MASK)
+ mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT);
+
+ page_header_update_slot(vcpu->kvm, shadow_pte, gaddr);
+ rmap_add(vcpu, shadow_pte);
+}
+
+static void inject_page_fault(struct kvm_vcpu *vcpu,
+ u64 addr,
+ u32 err_code)
+{
+ kvm_arch_ops->inject_page_fault(vcpu, addr, err_code);
+}
+
+static inline int fix_read_pf(u64 *shadow_ent)
+{
+ if ((*shadow_ent & PT_SHADOW_USER_MASK) &&
+ !(*shadow_ent & PT_USER_MASK)) {
+ /*
+ * If supervisor write protect is disabled, we shadow kernel
+ * pages as user pages so we can trap the write access.
+ */
+ *shadow_ent |= PT_USER_MASK;
+ *shadow_ent &= ~PT_WRITABLE_MASK;
+
+ return 1;
+
+ }
+ return 0;
+}
+
+static void paging_free(struct kvm_vcpu *vcpu)
+{
+ nonpaging_free(vcpu);
+}
+
+#define PTTYPE 64
+#include "paging_tmpl.h"
+#undef PTTYPE
+
+#define PTTYPE 32
+#include "paging_tmpl.h"
+#undef PTTYPE
+
+static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level)
+{
+ struct kvm_mmu *context = &vcpu->mmu;
+
+ ASSERT(is_pae(vcpu));
+ context->new_cr3 = paging_new_cr3;
+ context->page_fault = paging64_page_fault;
+ context->gva_to_gpa = paging64_gva_to_gpa;
+ context->free = paging_free;
+ context->root_level = level;
+ context->shadow_root_level = level;
+ mmu_alloc_roots(vcpu);
+ ASSERT(VALID_PAGE(context->root_hpa));
+ kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
+ (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
+ return 0;
+}
+
+static int paging64_init_context(struct kvm_vcpu *vcpu)
+{
+ return paging64_init_context_common(vcpu, PT64_ROOT_LEVEL);
+}
+
+static int paging32_init_context(struct kvm_vcpu *vcpu)
+{
+ struct kvm_mmu *context = &vcpu->mmu;
+
+ context->new_cr3 = paging_new_cr3;
+ context->page_fault = paging32_page_fault;
+ context->gva_to_gpa = paging32_gva_to_gpa;
+ context->free = paging_free;
+ context->root_level = PT32_ROOT_LEVEL;
+ context->shadow_root_level = PT32E_ROOT_LEVEL;
+ mmu_alloc_roots(vcpu);
+ ASSERT(VALID_PAGE(context->root_hpa));
+ kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
+ (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
+ return 0;
+}
+
+static int paging32E_init_context(struct kvm_vcpu *vcpu)
+{
+ return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL);
+}
+
+static int init_kvm_mmu(struct kvm_vcpu *vcpu)
+{
+ ASSERT(vcpu);
+ ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
+
+ if (!is_paging(vcpu))
+ return nonpaging_init_context(vcpu);
+ else if (is_long_mode(vcpu))
+ return paging64_init_context(vcpu);
+ else if (is_pae(vcpu))
+ return paging32E_init_context(vcpu);
+ else
+ return paging32_init_context(vcpu);
+}
+
+static void destroy_kvm_mmu(struct kvm_vcpu *vcpu)
+{
+ ASSERT(vcpu);
+ if (VALID_PAGE(vcpu->mmu.root_hpa)) {
+ vcpu->mmu.free(vcpu);
+ vcpu->mmu.root_hpa = INVALID_PAGE;
+ }
+}
+
+int kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
+{
+ int r;
+
+ destroy_kvm_mmu(vcpu);
+ r = init_kvm_mmu(vcpu);
+ if (r < 0)
+ goto out;
+ r = mmu_topup_memory_caches(vcpu);
+out:
+ return r;
+}
+
+void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
+{
+ gfn_t gfn = gpa >> PAGE_SHIFT;
+ struct kvm_mmu_page *page;
+ struct kvm_mmu_page *child;
+ struct hlist_node *node, *n;
+ struct hlist_head *bucket;
+ unsigned index;
+ u64 *spte;
+ u64 pte;
+ unsigned offset = offset_in_page(gpa);
+ unsigned pte_size;
+ unsigned page_offset;
+ unsigned misaligned;
+ int level;
+ int flooded = 0;
+
+ pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes);
+ if (gfn == vcpu->last_pt_write_gfn) {
+ ++vcpu->last_pt_write_count;
+ if (vcpu->last_pt_write_count >= 3)
+ flooded = 1;
+ } else {
+ vcpu->last_pt_write_gfn = gfn;
+ vcpu->last_pt_write_count = 1;
+ }
+ index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
+ bucket = &vcpu->kvm->mmu_page_hash[index];
+ hlist_for_each_entry_safe(page, node, n, bucket, hash_link) {
+ if (page->gfn != gfn || page->role.metaphysical)
+ continue;
+ pte_size = page->role.glevels == PT32_ROOT_LEVEL ? 4 : 8;
+ misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1);
+ if (misaligned || flooded) {
+ /*
+ * Misaligned accesses are too much trouble to fix
+ * up; also, they usually indicate a page is not used
+ * as a page table.
+ *
+ * If we're seeing too many writes to a page,
+ * it may no longer be a page table, or we may be
+ * forking, in which case it is better to unmap the
+ * page.
+ */
+ pgprintk("misaligned: gpa %llx bytes %d role %x\n",
+ gpa, bytes, page->role.word);
+ kvm_mmu_zap_page(vcpu, page);
+ continue;
+ }
+ page_offset = offset;
+ level = page->role.level;
+ if (page->role.glevels == PT32_ROOT_LEVEL) {
+ page_offset <<= 1; /* 32->64 */
+ page_offset &= ~PAGE_MASK;
+ }
+ spte = __va(page->page_hpa);
+ spte += page_offset / sizeof(*spte);
+ pte = *spte;
+ if (is_present_pte(pte)) {
+ if (level == PT_PAGE_TABLE_LEVEL)
+ rmap_remove(vcpu, spte);
+ else {
+ child = page_header(pte & PT64_BASE_ADDR_MASK);
+ mmu_page_remove_parent_pte(vcpu, child, spte);
+ }
+ }
+ *spte = 0;
+ }
+}
+
+void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
+{
+}
+
+int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
+{
+ gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva);
+
+ return kvm_mmu_unprotect_page(vcpu, gpa >> PAGE_SHIFT);
+}
+
+void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
+{
+ while (vcpu->kvm->n_free_mmu_pages < KVM_REFILL_PAGES) {
+ struct kvm_mmu_page *page;
+
+ page = container_of(vcpu->kvm->active_mmu_pages.prev,
+ struct kvm_mmu_page, link);
+ kvm_mmu_zap_page(vcpu, page);
+ }
+}
+EXPORT_SYMBOL_GPL(kvm_mmu_free_some_pages);
+
+static void free_mmu_pages(struct kvm_vcpu *vcpu)
+{
+ struct kvm_mmu_page *page;
+
+ while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
+ page = container_of(vcpu->kvm->active_mmu_pages.next,
+ struct kvm_mmu_page, link);
+ kvm_mmu_zap_page(vcpu, page);
+ }
+ while (!list_empty(&vcpu->free_pages)) {
+ page = list_entry(vcpu->free_pages.next,
+ struct kvm_mmu_page, link);
+ list_del(&page->link);
+ __free_page(pfn_to_page(page->page_hpa >> PAGE_SHIFT));
+ page->page_hpa = INVALID_PAGE;
+ }
+ free_page((unsigned long)vcpu->mmu.pae_root);
+}
+
+static int alloc_mmu_pages(struct kvm_vcpu *vcpu)
+{
+ struct page *page;
+ int i;
+
+ ASSERT(vcpu);
+
+ for (i = 0; i < KVM_NUM_MMU_PAGES; i++) {
+ struct kvm_mmu_page *page_header = &vcpu->page_header_buf[i];
+
+ INIT_LIST_HEAD(&page_header->link);
+ if ((page = alloc_page(GFP_KERNEL)) == NULL)
+ goto error_1;
+ page->private = (unsigned long)page_header;
+ page_header->page_hpa = (hpa_t)page_to_pfn(page) << PAGE_SHIFT;
+ memset(__va(page_header->page_hpa), 0, PAGE_SIZE);
+ list_add(&page_header->link, &vcpu->free_pages);
+ ++vcpu->kvm->n_free_mmu_pages;
+ }
+
+ /*
+ * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64.
+ * Therefore we need to allocate shadow page tables in the first
+ * 4GB of memory, which happens to fit the DMA32 zone.
+ */
+ page = alloc_page(GFP_KERNEL | __GFP_DMA32);
+ if (!page)
+ goto error_1;
+ vcpu->mmu.pae_root = page_address(page);
+ for (i = 0; i < 4; ++i)
+ vcpu->mmu.pae_root[i] = INVALID_PAGE;
+
+ return 0;
+
+error_1:
+ free_mmu_pages(vcpu);
+ return -ENOMEM;
+}
+
+int kvm_mmu_create(struct kvm_vcpu *vcpu)
+{
+ ASSERT(vcpu);
+ ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
+ ASSERT(list_empty(&vcpu->free_pages));
+
+ return alloc_mmu_pages(vcpu);
+}
+
+int kvm_mmu_setup(struct kvm_vcpu *vcpu)
+{
+ ASSERT(vcpu);
+ ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
+ ASSERT(!list_empty(&vcpu->free_pages));
+
+ return init_kvm_mmu(vcpu);
+}
+
+void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
+{
+ ASSERT(vcpu);
+
+ destroy_kvm_mmu(vcpu);
+ free_mmu_pages(vcpu);
+ mmu_free_memory_caches(vcpu);
+}
+
+void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
+{
+ struct kvm *kvm = vcpu->kvm;
+ struct kvm_mmu_page *page;
+
+ list_for_each_entry(page, &kvm->active_mmu_pages, link) {
+ int i;
+ u64 *pt;
+
+ if (!test_bit(slot, &page->slot_bitmap))
+ continue;
+
+ pt = __va(page->page_hpa);
+ for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
+ /* avoid RMW */
+ if (pt[i] & PT_WRITABLE_MASK) {
+ rmap_remove(vcpu, &pt[i]);
+ pt[i] &= ~PT_WRITABLE_MASK;
+ }
+ }
+}
+
+#ifdef AUDIT
+
+static const char *audit_msg;
+
+static gva_t canonicalize(gva_t gva)
+{
+#ifdef CONFIG_X86_64
+ gva = (long long)(gva << 16) >> 16;
+#endif
+ return gva;
+}
+
+static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
+ gva_t va, int level)
+{
+ u64 *pt = __va(page_pte & PT64_BASE_ADDR_MASK);
+ int i;
+ gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1));
+
+ for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) {
+ u64 ent = pt[i];
+
+ if (!ent & PT_PRESENT_MASK)
+ continue;
+
+ va = canonicalize(va);
+ if (level > 1)
+ audit_mappings_page(vcpu, ent, va, level - 1);
+ else {
+ gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, va);
+ hpa_t hpa = gpa_to_hpa(vcpu, gpa);
+
+ if ((ent & PT_PRESENT_MASK)
+ && (ent & PT64_BASE_ADDR_MASK) != hpa)
+ printk(KERN_ERR "audit error: (%s) levels %d"
+ " gva %lx gpa %llx hpa %llx ent %llx\n",
+ audit_msg, vcpu->mmu.root_level,
+ va, gpa, hpa, ent);
+ }
+ }
+}
+
+static void audit_mappings(struct kvm_vcpu *vcpu)
+{
+ int i;
+
+ if (vcpu->mmu.root_level == 4)
+ audit_mappings_page(vcpu, vcpu->mmu.root_hpa, 0, 4);
+ else
+ for (i = 0; i < 4; ++i)
+ if (vcpu->mmu.pae_root[i] & PT_PRESENT_MASK)
+ audit_mappings_page(vcpu,
+ vcpu->mmu.pae_root[i],
+ i << 30,
+ 2);
+}
+
+static int count_rmaps(struct kvm_vcpu *vcpu)
+{
+ int nmaps = 0;
+ int i, j, k;
+
+ for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
+ struct kvm_memory_slot *m = &vcpu->kvm->memslots[i];
+ struct kvm_rmap_desc *d;
+
+ for (j = 0; j < m->npages; ++j) {
+ struct page *page = m->phys_mem[j];
+
+ if (!page->private)
+ continue;
+ if (!(page->private & 1)) {
+ ++nmaps;
+ continue;
+ }
+ d = (struct kvm_rmap_desc *)(page->private & ~1ul);
+ while (d) {
+ for (k = 0; k < RMAP_EXT; ++k)
+ if (d->shadow_ptes[k])
+ ++nmaps;
+ else
+ break;
+ d = d->more;
+ }
+ }
+ }
+ return nmaps;
+}
+
+static int count_writable_mappings(struct kvm_vcpu *vcpu)
+{
+ int nmaps = 0;
+ struct kvm_mmu_page *page;
+ int i;
+
+ list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) {
+ u64 *pt = __va(page->page_hpa);
+
+ if (page->role.level != PT_PAGE_TABLE_LEVEL)
+ continue;
+
+ for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
+ u64 ent = pt[i];
+
+ if (!(ent & PT_PRESENT_MASK))
+ continue;
+ if (!(ent & PT_WRITABLE_MASK))
+ continue;
+ ++nmaps;
+ }
+ }
+ return nmaps;
+}
+
+static void audit_rmap(struct kvm_vcpu *vcpu)
+{
+ int n_rmap = count_rmaps(vcpu);
+ int n_actual = count_writable_mappings(vcpu);
+
+ if (n_rmap != n_actual)
+ printk(KERN_ERR "%s: (%s) rmap %d actual %d\n",
+ __FUNCTION__, audit_msg, n_rmap, n_actual);
+}
+
+static void audit_write_protection(struct kvm_vcpu *vcpu)
+{
+ struct kvm_mmu_page *page;
+
+ list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) {
+ hfn_t hfn;
+ struct page *pg;
+
+ if (page->role.metaphysical)
+ continue;
+
+ hfn = gpa_to_hpa(vcpu, (gpa_t)page->gfn << PAGE_SHIFT)
+ >> PAGE_SHIFT;
+ pg = pfn_to_page(hfn);
+ if (pg->private)
+ printk(KERN_ERR "%s: (%s) shadow page has writable"
+ " mappings: gfn %lx role %x\n",
+ __FUNCTION__, audit_msg, page->gfn,
+ page->role.word);
+ }
+}
+
+static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg)
+{
+ int olddbg = dbg;
+
+ dbg = 0;
+ audit_msg = msg;
+ audit_rmap(vcpu);
+ audit_write_protection(vcpu);
+ audit_mappings(vcpu);
+ dbg = olddbg;
+}
+
+#endif
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
new file mode 100644
index 00000000000..149fa45fd9a
--- /dev/null
+++ b/drivers/kvm/paging_tmpl.h
@@ -0,0 +1,484 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This module enables machines with Intel VT-x extensions to run virtual
+ * machines without emulation or binary translation.
+ *
+ * MMU support
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ * Yaniv Kamay <yaniv@qumranet.com>
+ * Avi Kivity <avi@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+/*
+ * We need the mmu code to access both 32-bit and 64-bit guest ptes,
+ * so the code in this file is compiled twice, once per pte size.
+ */
+
+#if PTTYPE == 64
+ #define pt_element_t u64
+ #define guest_walker guest_walker64
+ #define FNAME(name) paging##64_##name
+ #define PT_BASE_ADDR_MASK PT64_BASE_ADDR_MASK
+ #define PT_DIR_BASE_ADDR_MASK PT64_DIR_BASE_ADDR_MASK
+ #define PT_INDEX(addr, level) PT64_INDEX(addr, level)
+ #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
+ #define PT_LEVEL_MASK(level) PT64_LEVEL_MASK(level)
+ #define PT_PTE_COPY_MASK PT64_PTE_COPY_MASK
+ #ifdef CONFIG_X86_64
+ #define PT_MAX_FULL_LEVELS 4
+ #else
+ #define PT_MAX_FULL_LEVELS 2
+ #endif
+#elif PTTYPE == 32
+ #define pt_element_t u32
+ #define guest_walker guest_walker32
+ #define FNAME(name) paging##32_##name
+ #define PT_BASE_ADDR_MASK PT32_BASE_ADDR_MASK
+ #define PT_DIR_BASE_ADDR_MASK PT32_DIR_BASE_ADDR_MASK
+ #define PT_INDEX(addr, level) PT32_INDEX(addr, level)
+ #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
+ #define PT_LEVEL_MASK(level) PT32_LEVEL_MASK(level)
+ #define PT_PTE_COPY_MASK PT32_PTE_COPY_MASK
+ #define PT_MAX_FULL_LEVELS 2
+#else
+ #error Invalid PTTYPE value
+#endif
+
+/*
+ * The guest_walker structure emulates the behavior of the hardware page
+ * table walker.
+ */
+struct guest_walker {
+ int level;
+ gfn_t table_gfn[PT_MAX_FULL_LEVELS];
+ pt_element_t *table;
+ pt_element_t *ptep;
+ pt_element_t inherited_ar;
+ gfn_t gfn;
+ u32 error_code;
+};
+
+/*
+ * Fetch a guest pte for a guest virtual address
+ */
+static int FNAME(walk_addr)(struct guest_walker *walker,
+ struct kvm_vcpu *vcpu, gva_t addr,
+ int write_fault, int user_fault, int fetch_fault)
+{
+ hpa_t hpa;
+ struct kvm_memory_slot *slot;
+ pt_element_t *ptep;
+ pt_element_t root;
+ gfn_t table_gfn;
+
+ pgprintk("%s: addr %lx\n", __FUNCTION__, addr);
+ walker->level = vcpu->mmu.root_level;
+ walker->table = NULL;
+ root = vcpu->cr3;
+#if PTTYPE == 64
+ if (!is_long_mode(vcpu)) {
+ walker->ptep = &vcpu->pdptrs[(addr >> 30) & 3];
+ root = *walker->ptep;
+ if (!(root & PT_PRESENT_MASK))
+ goto not_present;
+ --walker->level;
+ }
+#endif
+ table_gfn = (root & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
+ walker->table_gfn[walker->level - 1] = table_gfn;
+ pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__,
+ walker->level - 1, table_gfn);
+ slot = gfn_to_memslot(vcpu->kvm, table_gfn);
+ hpa = safe_gpa_to_hpa(vcpu, root & PT64_BASE_ADDR_MASK);
+ walker->table = kmap_atomic(pfn_to_page(hpa >> PAGE_SHIFT), KM_USER0);
+
+ ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) ||
+ (vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) == 0);
+
+ walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK;
+
+ for (;;) {
+ int index = PT_INDEX(addr, walker->level);
+ hpa_t paddr;
+
+ ptep = &walker->table[index];
+ ASSERT(((unsigned long)walker->table & PAGE_MASK) ==
+ ((unsigned long)ptep & PAGE_MASK));
+
+ if (!is_present_pte(*ptep))
+ goto not_present;
+
+ if (write_fault && !is_writeble_pte(*ptep))
+ if (user_fault || is_write_protection(vcpu))
+ goto access_error;
+
+ if (user_fault && !(*ptep & PT_USER_MASK))
+ goto access_error;
+
+#if PTTYPE == 64
+ if (fetch_fault && is_nx(vcpu) && (*ptep & PT64_NX_MASK))
+ goto access_error;
+#endif
+
+ if (!(*ptep & PT_ACCESSED_MASK))
+ *ptep |= PT_ACCESSED_MASK; /* avoid rmw */
+
+ if (walker->level == PT_PAGE_TABLE_LEVEL) {
+ walker->gfn = (*ptep & PT_BASE_ADDR_MASK)
+ >> PAGE_SHIFT;
+ break;
+ }
+
+ if (walker->level == PT_DIRECTORY_LEVEL
+ && (*ptep & PT_PAGE_SIZE_MASK)
+ && (PTTYPE == 64 || is_pse(vcpu))) {
+ walker->gfn = (*ptep & PT_DIR_BASE_ADDR_MASK)
+ >> PAGE_SHIFT;
+ walker->gfn += PT_INDEX(addr, PT_PAGE_TABLE_LEVEL);
+ break;
+ }
+
+ if (walker->level != 3 || is_long_mode(vcpu))
+ walker->inherited_ar &= walker->table[index];
+ table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT;
+ paddr = safe_gpa_to_hpa(vcpu, *ptep & PT_BASE_ADDR_MASK);
+ kunmap_atomic(walker->table, KM_USER0);
+ walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT),
+ KM_USER0);
+ --walker->level;
+ walker->table_gfn[walker->level - 1 ] = table_gfn;
+ pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__,
+ walker->level - 1, table_gfn);
+ }
+ walker->ptep = ptep;
+ pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)*ptep);
+ return 1;
+
+not_present:
+ walker->error_code = 0;
+ goto err;
+
+access_error:
+ walker->error_code = PFERR_PRESENT_MASK;
+
+err:
+ if (write_fault)
+ walker->error_code |= PFERR_WRITE_MASK;
+ if (user_fault)
+ walker->error_code |= PFERR_USER_MASK;
+ if (fetch_fault)
+ walker->error_code |= PFERR_FETCH_MASK;
+ return 0;
+}
+
+static void FNAME(release_walker)(struct guest_walker *walker)
+{
+ if (walker->table)
+ kunmap_atomic(walker->table, KM_USER0);
+}
+
+static void FNAME(set_pte)(struct kvm_vcpu *vcpu, u64 guest_pte,
+ u64 *shadow_pte, u64 access_bits, gfn_t gfn)
+{
+ ASSERT(*shadow_pte == 0);
+ access_bits &= guest_pte;
+ *shadow_pte = (guest_pte & PT_PTE_COPY_MASK);
+ set_pte_common(vcpu, shadow_pte, guest_pte & PT_BASE_ADDR_MASK,
+ guest_pte & PT_DIRTY_MASK, access_bits, gfn);
+}
+
+static void FNAME(set_pde)(struct kvm_vcpu *vcpu, u64 guest_pde,
+ u64 *shadow_pte, u64 access_bits, gfn_t gfn)
+{
+ gpa_t gaddr;
+
+ ASSERT(*shadow_pte == 0);
+ access_bits &= guest_pde;
+ gaddr = (gpa_t)gfn << PAGE_SHIFT;
+ if (PTTYPE == 32 && is_cpuid_PSE36())
+ gaddr |= (guest_pde & PT32_DIR_PSE36_MASK) <<
+ (32 - PT32_DIR_PSE36_SHIFT);
+ *shadow_pte = guest_pde & PT_PTE_COPY_MASK;
+ set_pte_common(vcpu, shadow_pte, gaddr,
+ guest_pde & PT_DIRTY_MASK, access_bits, gfn);
+}
+
+/*
+ * Fetch a shadow pte for a specific level in the paging hierarchy.
+ */
+static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
+ struct guest_walker *walker)
+{
+ hpa_t shadow_addr;
+ int level;
+ u64 *prev_shadow_ent = NULL;
+ pt_element_t *guest_ent = walker->ptep;
+
+ if (!is_present_pte(*guest_ent))
+ return NULL;
+
+ shadow_addr = vcpu->mmu.root_hpa;
+ level = vcpu->mmu.shadow_root_level;
+ if (level == PT32E_ROOT_LEVEL) {
+ shadow_addr = vcpu->mmu.pae_root[(addr >> 30) & 3];
+ shadow_addr &= PT64_BASE_ADDR_MASK;
+ --level;
+ }
+
+ for (; ; level--) {
+ u32 index = SHADOW_PT_INDEX(addr, level);
+ u64 *shadow_ent = ((u64 *)__va(shadow_addr)) + index;
+ struct kvm_mmu_page *shadow_page;
+ u64 shadow_pte;
+ int metaphysical;
+ gfn_t table_gfn;
+
+ if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) {
+ if (level == PT_PAGE_TABLE_LEVEL)
+ return shadow_ent;
+ shadow_addr = *shadow_ent & PT64_BASE_ADDR_MASK;
+ prev_shadow_ent = shadow_ent;
+ continue;
+ }
+
+ if (level == PT_PAGE_TABLE_LEVEL) {
+
+ if (walker->level == PT_DIRECTORY_LEVEL) {
+ if (prev_shadow_ent)
+ *prev_shadow_ent |= PT_SHADOW_PS_MARK;
+ FNAME(set_pde)(vcpu, *guest_ent, shadow_ent,
+ walker->inherited_ar,
+ walker->gfn);
+ } else {
+ ASSERT(walker->level == PT_PAGE_TABLE_LEVEL);
+ FNAME(set_pte)(vcpu, *guest_ent, shadow_ent,
+ walker->inherited_ar,
+ walker->gfn);
+ }
+ return shadow_ent;
+ }
+
+ if (level - 1 == PT_PAGE_TABLE_LEVEL
+ && walker->level == PT_DIRECTORY_LEVEL) {
+ metaphysical = 1;
+ table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
+ >> PAGE_SHIFT;
+ } else {
+ metaphysical = 0;
+ table_gfn = walker->table_gfn[level - 2];
+ }
+ shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1,
+ metaphysical, shadow_ent);
+ shadow_addr = shadow_page->page_hpa;
+ shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK
+ | PT_WRITABLE_MASK | PT_USER_MASK;
+ *shadow_ent = shadow_pte;
+ prev_shadow_ent = shadow_ent;
+ }
+}
+
+/*
+ * The guest faulted for write. We need to
+ *
+ * - check write permissions
+ * - update the guest pte dirty bit
+ * - update our own dirty page tracking structures
+ */
+static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu,
+ u64 *shadow_ent,
+ struct guest_walker *walker,
+ gva_t addr,
+ int user,
+ int *write_pt)
+{
+ pt_element_t *guest_ent;
+ int writable_shadow;
+ gfn_t gfn;
+ struct kvm_mmu_page *page;
+
+ if (is_writeble_pte(*shadow_ent))
+ return !user || (*shadow_ent & PT_USER_MASK);
+
+ writable_shadow = *shadow_ent & PT_SHADOW_WRITABLE_MASK;
+ if (user) {
+ /*
+ * User mode access. Fail if it's a kernel page or a read-only
+ * page.
+ */
+ if (!(*shadow_ent & PT_SHADOW_USER_MASK) || !writable_shadow)
+ return 0;
+ ASSERT(*shadow_ent & PT_USER_MASK);
+ } else
+ /*
+ * Kernel mode access. Fail if it's a read-only page and
+ * supervisor write protection is enabled.
+ */
+ if (!writable_shadow) {
+ if (is_write_protection(vcpu))
+ return 0;
+ *shadow_ent &= ~PT_USER_MASK;
+ }
+
+ guest_ent = walker->ptep;
+
+ if (!is_present_pte(*guest_ent)) {
+ *shadow_ent = 0;
+ return 0;
+ }
+
+ gfn = walker->gfn;
+
+ if (user) {
+ /*
+ * Usermode page faults won't be for page table updates.
+ */
+ while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
+ pgprintk("%s: zap %lx %x\n",
+ __FUNCTION__, gfn, page->role.word);
+ kvm_mmu_zap_page(vcpu, page);
+ }
+ } else if (kvm_mmu_lookup_page(vcpu, gfn)) {
+ pgprintk("%s: found shadow page for %lx, marking ro\n",
+ __FUNCTION__, gfn);
+ *guest_ent |= PT_DIRTY_MASK;
+ *write_pt = 1;
+ return 0;
+ }
+ mark_page_dirty(vcpu->kvm, gfn);
+ *shadow_ent |= PT_WRITABLE_MASK;
+ *guest_ent |= PT_DIRTY_MASK;
+ rmap_add(vcpu, shadow_ent);
+
+ return 1;
+}
+
+/*
+ * Page fault handler. There are several causes for a page fault:
+ * - there is no shadow pte for the guest pte
+ * - write access through a shadow pte marked read only so that we can set
+ * the dirty bit
+ * - write access to a shadow pte marked read only so we can update the page
+ * dirty bitmap, when userspace requests it
+ * - mmio access; in this case we will never install a present shadow pte
+ * - normal guest page fault due to the guest pte marked not present, not
+ * writable, or not executable
+ *
+ * Returns: 1 if we need to emulate the instruction, 0 otherwise, or
+ * a negative value on error.
+ */
+static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
+ u32 error_code)
+{
+ int write_fault = error_code & PFERR_WRITE_MASK;
+ int user_fault = error_code & PFERR_USER_MASK;
+ int fetch_fault = error_code & PFERR_FETCH_MASK;
+ struct guest_walker walker;
+ u64 *shadow_pte;
+ int fixed;
+ int write_pt = 0;
+ int r;
+
+ pgprintk("%s: addr %lx err %x\n", __FUNCTION__, addr, error_code);
+ kvm_mmu_audit(vcpu, "pre page fault");
+
+ r = mmu_topup_memory_caches(vcpu);
+ if (r)
+ return r;
+
+ /*
+ * Look up the shadow pte for the faulting address.
+ */
+ r = FNAME(walk_addr)(&walker, vcpu, addr, write_fault, user_fault,
+ fetch_fault);
+
+ /*
+ * The page is not mapped by the guest. Let the guest handle it.
+ */
+ if (!r) {
+ pgprintk("%s: guest page fault\n", __FUNCTION__);
+ inject_page_fault(vcpu, addr, walker.error_code);
+ FNAME(release_walker)(&walker);
+ return 0;
+ }
+
+ shadow_pte = FNAME(fetch)(vcpu, addr, &walker);
+ pgprintk("%s: shadow pte %p %llx\n", __FUNCTION__,
+ shadow_pte, *shadow_pte);
+
+ /*
+ * Update the shadow pte.
+ */
+ if (write_fault)
+ fixed = FNAME(fix_write_pf)(vcpu, shadow_pte, &walker, addr,
+ user_fault, &write_pt);
+ else
+ fixed = fix_read_pf(shadow_pte);
+
+ pgprintk("%s: updated shadow pte %p %llx\n", __FUNCTION__,
+ shadow_pte, *shadow_pte);
+
+ FNAME(release_walker)(&walker);
+
+ /*
+ * mmio: emulate if accessible, otherwise its a guest fault.
+ */
+ if (is_io_pte(*shadow_pte)) {
+ return 1;
+ }
+
+ ++kvm_stat.pf_fixed;
+ kvm_mmu_audit(vcpu, "post page fault (fixed)");
+
+ return write_pt;
+}
+
+static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr)
+{
+ struct guest_walker walker;
+ pt_element_t guest_pte;
+ gpa_t gpa;
+
+ FNAME(walk_addr)(&walker, vcpu, vaddr, 0, 0, 0);
+ guest_pte = *walker.ptep;
+ FNAME(release_walker)(&walker);
+
+ if (!is_present_pte(guest_pte))
+ return UNMAPPED_GVA;
+
+ if (walker.level == PT_DIRECTORY_LEVEL) {
+ ASSERT((guest_pte & PT_PAGE_SIZE_MASK));
+ ASSERT(PTTYPE == 64 || is_pse(vcpu));
+
+ gpa = (guest_pte & PT_DIR_BASE_ADDR_MASK) | (vaddr &
+ (PT_LEVEL_MASK(PT_PAGE_TABLE_LEVEL) | ~PAGE_MASK));
+
+ if (PTTYPE == 32 && is_cpuid_PSE36())
+ gpa |= (guest_pte & PT32_DIR_PSE36_MASK) <<
+ (32 - PT32_DIR_PSE36_SHIFT);
+ } else {
+ gpa = (guest_pte & PT_BASE_ADDR_MASK);
+ gpa |= (vaddr & ~PAGE_MASK);
+ }
+
+ return gpa;
+}
+
+#undef pt_element_t
+#undef guest_walker
+#undef FNAME
+#undef PT_BASE_ADDR_MASK
+#undef PT_INDEX
+#undef SHADOW_PT_INDEX
+#undef PT_LEVEL_MASK
+#undef PT_PTE_COPY_MASK
+#undef PT_NON_PTE_COPY_MASK
+#undef PT_DIR_BASE_ADDR_MASK
+#undef PT_MAX_FULL_LEVELS
diff --git a/drivers/kvm/segment_descriptor.h b/drivers/kvm/segment_descriptor.h
new file mode 100644
index 00000000000..71fdf458619
--- /dev/null
+++ b/drivers/kvm/segment_descriptor.h
@@ -0,0 +1,17 @@
+struct segment_descriptor {
+ u16 limit_low;
+ u16 base_low;
+ u8 base_mid;
+ u8 type : 4;
+ u8 system : 1;
+ u8 dpl : 2;
+ u8 present : 1;
+ u8 limit_high : 4;
+ u8 avl : 1;
+ u8 long_mode : 1;
+ u8 default_op : 1;
+ u8 granularity : 1;
+ u8 base_high;
+} __attribute__((packed));
+
+
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
new file mode 100644
index 00000000000..85f61dd1e93
--- /dev/null
+++ b/drivers/kvm/svm.c
@@ -0,0 +1,1721 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * AMD SVM support
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ * Yaniv Kamay <yaniv@qumranet.com>
+ * Avi Kivity <avi@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/highmem.h>
+#include <linux/profile.h>
+#include <asm/desc.h>
+
+#include "kvm_svm.h"
+#include "x86_emulate.h"
+
+MODULE_AUTHOR("Qumranet");
+MODULE_LICENSE("GPL");
+
+#define IOPM_ALLOC_ORDER 2
+#define MSRPM_ALLOC_ORDER 1
+
+#define DB_VECTOR 1
+#define UD_VECTOR 6
+#define GP_VECTOR 13
+
+#define DR7_GD_MASK (1 << 13)
+#define DR6_BD_MASK (1 << 13)
+#define CR4_DE_MASK (1UL << 3)
+
+#define SEG_TYPE_LDT 2
+#define SEG_TYPE_BUSY_TSS16 3
+
+#define KVM_EFER_LMA (1 << 10)
+#define KVM_EFER_LME (1 << 8)
+
+unsigned long iopm_base;
+unsigned long msrpm_base;
+
+struct kvm_ldttss_desc {
+ u16 limit0;
+ u16 base0;
+ unsigned base1 : 8, type : 5, dpl : 2, p : 1;
+ unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8;
+ u32 base3;
+ u32 zero1;
+} __attribute__((packed));
+
+struct svm_cpu_data {
+ int cpu;
+
+ uint64_t asid_generation;
+ uint32_t max_asid;
+ uint32_t next_asid;
+ struct kvm_ldttss_desc *tss_desc;
+
+ struct page *save_area;
+};
+
+static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
+
+struct svm_init_data {
+ int cpu;
+ int r;
+};
+
+static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000};
+
+#define NUM_MSR_MAPS (sizeof(msrpm_ranges) / sizeof(*msrpm_ranges))
+#define MSRS_RANGE_SIZE 2048
+#define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2)
+
+#define MAX_INST_SIZE 15
+
+static unsigned get_addr_size(struct kvm_vcpu *vcpu)
+{
+ struct vmcb_save_area *sa = &vcpu->svm->vmcb->save;
+ u16 cs_attrib;
+
+ if (!(sa->cr0 & CR0_PE_MASK) || (sa->rflags & X86_EFLAGS_VM))
+ return 2;
+
+ cs_attrib = sa->cs.attrib;
+
+ return (cs_attrib & SVM_SELECTOR_L_MASK) ? 8 :
+ (cs_attrib & SVM_SELECTOR_DB_MASK) ? 4 : 2;
+}
+
+static inline u8 pop_irq(struct kvm_vcpu *vcpu)
+{
+ int word_index = __ffs(vcpu->irq_summary);
+ int bit_index = __ffs(vcpu->irq_pending[word_index]);
+ int irq = word_index * BITS_PER_LONG + bit_index;
+
+ clear_bit(bit_index, &vcpu->irq_pending[word_index]);
+ if (!vcpu->irq_pending[word_index])
+ clear_bit(word_index, &vcpu->irq_summary);
+ return irq;
+}
+
+static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq)
+{
+ set_bit(irq, vcpu->irq_pending);
+ set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
+}
+
+static inline void clgi(void)
+{
+ asm volatile (SVM_CLGI);
+}
+
+static inline void stgi(void)
+{
+ asm volatile (SVM_STGI);
+}
+
+static inline void invlpga(unsigned long addr, u32 asid)
+{
+ asm volatile (SVM_INVLPGA :: "a"(addr), "c"(asid));
+}
+
+static inline unsigned long kvm_read_cr2(void)
+{
+ unsigned long cr2;
+
+ asm volatile ("mov %%cr2, %0" : "=r" (cr2));
+ return cr2;
+}
+
+static inline void kvm_write_cr2(unsigned long val)
+{
+ asm volatile ("mov %0, %%cr2" :: "r" (val));
+}
+
+static inline unsigned long read_dr6(void)
+{
+ unsigned long dr6;
+
+ asm volatile ("mov %%dr6, %0" : "=r" (dr6));
+ return dr6;
+}
+
+static inline void write_dr6(unsigned long val)
+{
+ asm volatile ("mov %0, %%dr6" :: "r" (val));
+}
+
+static inline unsigned long read_dr7(void)
+{
+ unsigned long dr7;
+
+ asm volatile ("mov %%dr7, %0" : "=r" (dr7));
+ return dr7;
+}
+
+static inline void write_dr7(unsigned long val)
+{
+ asm volatile ("mov %0, %%dr7" :: "r" (val));
+}
+
+static inline void force_new_asid(struct kvm_vcpu *vcpu)
+{
+ vcpu->svm->asid_generation--;
+}
+
+static inline void flush_guest_tlb(struct kvm_vcpu *vcpu)
+{
+ force_new_asid(vcpu);
+}
+
+static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
+{
+ if (!(efer & KVM_EFER_LMA))
+ efer &= ~KVM_EFER_LME;
+
+ vcpu->svm->vmcb->save.efer = efer | MSR_EFER_SVME_MASK;
+ vcpu->shadow_efer = efer;
+}
+
+static void svm_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
+{
+ vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ SVM_EVTINJ_VALID_ERR |
+ SVM_EVTINJ_TYPE_EXEPT |
+ GP_VECTOR;
+ vcpu->svm->vmcb->control.event_inj_err = error_code;
+}
+
+static void inject_ud(struct kvm_vcpu *vcpu)
+{
+ vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ SVM_EVTINJ_TYPE_EXEPT |
+ UD_VECTOR;
+}
+
+static void inject_db(struct kvm_vcpu *vcpu)
+{
+ vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ SVM_EVTINJ_TYPE_EXEPT |
+ DB_VECTOR;
+}
+
+static int is_page_fault(uint32_t info)
+{
+ info &= SVM_EVTINJ_VEC_MASK | SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
+ return info == (PF_VECTOR | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_EXEPT);
+}
+
+static int is_external_interrupt(u32 info)
+{
+ info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
+ return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR);
+}
+
+static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
+{
+ if (!vcpu->svm->next_rip) {
+ printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__);
+ return;
+ }
+ if (vcpu->svm->next_rip - vcpu->svm->vmcb->save.rip > 15) {
+ printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n",
+ __FUNCTION__,
+ vcpu->svm->vmcb->save.rip,
+ vcpu->svm->next_rip);
+ }
+
+ vcpu->rip = vcpu->svm->vmcb->save.rip = vcpu->svm->next_rip;
+ vcpu->svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
+
+ vcpu->interrupt_window_open = 1;
+}
+
+static int has_svm(void)
+{
+ uint32_t eax, ebx, ecx, edx;
+
+ if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
+ printk(KERN_INFO "has_svm: not amd\n");
+ return 0;
+ }
+
+ cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
+ if (eax < SVM_CPUID_FUNC) {
+ printk(KERN_INFO "has_svm: can't execute cpuid_8000000a\n");
+ return 0;
+ }
+
+ cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+ if (!(ecx & (1 << SVM_CPUID_FEATURE_SHIFT))) {
+ printk(KERN_DEBUG "has_svm: svm not available\n");
+ return 0;
+ }
+ return 1;
+}
+
+static void svm_hardware_disable(void *garbage)
+{
+ struct svm_cpu_data *svm_data
+ = per_cpu(svm_data, raw_smp_processor_id());
+
+ if (svm_data) {
+ uint64_t efer;
+
+ wrmsrl(MSR_VM_HSAVE_PA, 0);
+ rdmsrl(MSR_EFER, efer);
+ wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK);
+ per_cpu(svm_data, raw_smp_processor_id()) = NULL;
+ __free_page(svm_data->save_area);
+ kfree(svm_data);
+ }
+}
+
+static void svm_hardware_enable(void *garbage)
+{
+
+ struct svm_cpu_data *svm_data;
+ uint64_t efer;
+#ifdef CONFIG_X86_64
+ struct desc_ptr gdt_descr;
+#else
+ struct Xgt_desc_struct gdt_descr;
+#endif
+ struct desc_struct *gdt;
+ int me = raw_smp_processor_id();
+
+ if (!has_svm()) {
+ printk(KERN_ERR "svm_cpu_init: err EOPNOTSUPP on %d\n", me);
+ return;
+ }
+ svm_data = per_cpu(svm_data, me);
+
+ if (!svm_data) {
+ printk(KERN_ERR "svm_cpu_init: svm_data is NULL on %d\n",
+ me);
+ return;
+ }
+
+ svm_data->asid_generation = 1;
+ svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
+ svm_data->next_asid = svm_data->max_asid + 1;
+
+ asm volatile ( "sgdt %0" : "=m"(gdt_descr) );
+ gdt = (struct desc_struct *)gdt_descr.address;
+ svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS);
+
+ rdmsrl(MSR_EFER, efer);
+ wrmsrl(MSR_EFER, efer | MSR_EFER_SVME_MASK);
+
+ wrmsrl(MSR_VM_HSAVE_PA,
+ page_to_pfn(svm_data->save_area) << PAGE_SHIFT);
+}
+
+static int svm_cpu_init(int cpu)
+{
+ struct svm_cpu_data *svm_data;
+ int r;
+
+ svm_data = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL);
+ if (!svm_data)
+ return -ENOMEM;
+ svm_data->cpu = cpu;
+ svm_data->save_area = alloc_page(GFP_KERNEL);
+ r = -ENOMEM;
+ if (!svm_data->save_area)
+ goto err_1;
+
+ per_cpu(svm_data, cpu) = svm_data;
+
+ return 0;
+
+err_1:
+ kfree(svm_data);
+ return r;
+
+}
+
+static int set_msr_interception(u32 *msrpm, unsigned msr,
+ int read, int write)
+{
+ int i;
+
+ for (i = 0; i < NUM_MSR_MAPS; i++) {
+ if (msr >= msrpm_ranges[i] &&
+ msr < msrpm_ranges[i] + MSRS_IN_RANGE) {
+ u32 msr_offset = (i * MSRS_IN_RANGE + msr -
+ msrpm_ranges[i]) * 2;
+
+ u32 *base = msrpm + (msr_offset / 32);
+ u32 msr_shift = msr_offset % 32;
+ u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1);
+ *base = (*base & ~(0x3 << msr_shift)) |
+ (mask << msr_shift);
+ return 1;
+ }
+ }
+ printk(KERN_DEBUG "%s: not found 0x%x\n", __FUNCTION__, msr);
+ return 0;
+}
+
+static __init int svm_hardware_setup(void)
+{
+ int cpu;
+ struct page *iopm_pages;
+ struct page *msrpm_pages;
+ void *msrpm_va;
+ int r;
+
+ kvm_emulator_want_group7_invlpg();
+
+ iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER);
+
+ if (!iopm_pages)
+ return -ENOMEM;
+ memset(page_address(iopm_pages), 0xff,
+ PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
+ iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT;
+
+
+ msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER);
+
+ r = -ENOMEM;
+ if (!msrpm_pages)
+ goto err_1;
+
+ msrpm_va = page_address(msrpm_pages);
+ memset(msrpm_va, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER));
+ msrpm_base = page_to_pfn(msrpm_pages) << PAGE_SHIFT;
+
+#ifdef CONFIG_X86_64
+ set_msr_interception(msrpm_va, MSR_GS_BASE, 1, 1);
+ set_msr_interception(msrpm_va, MSR_FS_BASE, 1, 1);
+ set_msr_interception(msrpm_va, MSR_KERNEL_GS_BASE, 1, 1);
+ set_msr_interception(msrpm_va, MSR_LSTAR, 1, 1);
+ set_msr_interception(msrpm_va, MSR_CSTAR, 1, 1);
+ set_msr_interception(msrpm_va, MSR_SYSCALL_MASK, 1, 1);
+#endif
+ set_msr_interception(msrpm_va, MSR_K6_STAR, 1, 1);
+ set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_CS, 1, 1);
+ set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_ESP, 1, 1);
+ set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_EIP, 1, 1);
+
+ for_each_online_cpu(cpu) {
+ r = svm_cpu_init(cpu);
+ if (r)
+ goto err_2;
+ }
+ return 0;
+
+err_2:
+ __free_pages(msrpm_pages, MSRPM_ALLOC_ORDER);
+ msrpm_base = 0;
+err_1:
+ __free_pages(iopm_pages, IOPM_ALLOC_ORDER);
+ iopm_base = 0;
+ return r;
+}
+
+static __exit void svm_hardware_unsetup(void)
+{
+ __free_pages(pfn_to_page(msrpm_base >> PAGE_SHIFT), MSRPM_ALLOC_ORDER);
+ __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
+ iopm_base = msrpm_base = 0;
+}
+
+static void init_seg(struct vmcb_seg *seg)
+{
+ seg->selector = 0;
+ seg->attrib = SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK |
+ SVM_SELECTOR_WRITE_MASK; /* Read/Write Data Segment */
+ seg->limit = 0xffff;
+ seg->base = 0;
+}
+
+static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
+{
+ seg->selector = 0;
+ seg->attrib = SVM_SELECTOR_P_MASK | type;
+ seg->limit = 0xffff;
+ seg->base = 0;
+}
+
+static int svm_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+static void init_vmcb(struct vmcb *vmcb)
+{
+ struct vmcb_control_area *control = &vmcb->control;
+ struct vmcb_save_area *save = &vmcb->save;
+ u64 tsc;
+
+ control->intercept_cr_read = INTERCEPT_CR0_MASK |
+ INTERCEPT_CR3_MASK |
+ INTERCEPT_CR4_MASK;
+
+ control->intercept_cr_write = INTERCEPT_CR0_MASK |
+ INTERCEPT_CR3_MASK |
+ INTERCEPT_CR4_MASK;
+
+ control->intercept_dr_read = INTERCEPT_DR0_MASK |
+ INTERCEPT_DR1_MASK |
+ INTERCEPT_DR2_MASK |
+ INTERCEPT_DR3_MASK;
+
+ control->intercept_dr_write = INTERCEPT_DR0_MASK |
+ INTERCEPT_DR1_MASK |
+ INTERCEPT_DR2_MASK |
+ INTERCEPT_DR3_MASK |
+ INTERCEPT_DR5_MASK |
+ INTERCEPT_DR7_MASK;
+
+ control->intercept_exceptions = 1 << PF_VECTOR;
+
+
+ control->intercept = (1ULL << INTERCEPT_INTR) |
+ (1ULL << INTERCEPT_NMI) |
+ /*
+ * selective cr0 intercept bug?
+ * 0: 0f 22 d8 mov %eax,%cr3
+ * 3: 0f 20 c0 mov %cr0,%eax
+ * 6: 0d 00 00 00 80 or $0x80000000,%eax
+ * b: 0f 22 c0 mov %eax,%cr0
+ * set cr3 ->interception
+ * get cr0 ->interception
+ * set cr0 -> no interception
+ */
+ /* (1ULL << INTERCEPT_SELECTIVE_CR0) | */
+ (1ULL << INTERCEPT_CPUID) |
+ (1ULL << INTERCEPT_HLT) |
+ (1ULL << INTERCEPT_INVLPGA) |
+ (1ULL << INTERCEPT_IOIO_PROT) |
+ (1ULL << INTERCEPT_MSR_PROT) |
+ (1ULL << INTERCEPT_TASK_SWITCH) |
+ (1ULL << INTERCEPT_SHUTDOWN) |
+ (1ULL << INTERCEPT_VMRUN) |
+ (1ULL << INTERCEPT_VMMCALL) |
+ (1ULL << INTERCEPT_VMLOAD) |
+ (1ULL << INTERCEPT_VMSAVE) |
+ (1ULL << INTERCEPT_STGI) |
+ (1ULL << INTERCEPT_CLGI) |
+ (1ULL << INTERCEPT_SKINIT);
+
+ control->iopm_base_pa = iopm_base;
+ control->msrpm_base_pa = msrpm_base;
+ rdtscll(tsc);
+ control->tsc_offset = -tsc;
+ control->int_ctl = V_INTR_MASKING_MASK;
+
+ init_seg(&save->es);
+ init_seg(&save->ss);
+ init_seg(&save->ds);
+ init_seg(&save->fs);
+ init_seg(&save->gs);
+
+ save->cs.selector = 0xf000;
+ /* Executable/Readable Code Segment */
+ save->cs.attrib = SVM_SELECTOR_READ_MASK | SVM_SELECTOR_P_MASK |
+ SVM_SELECTOR_S_MASK | SVM_SELECTOR_CODE_MASK;
+ save->cs.limit = 0xffff;
+ save->cs.base = 0xffff0000;
+
+ save->gdtr.limit = 0xffff;
+ save->idtr.limit = 0xffff;
+
+ init_sys_seg(&save->ldtr, SEG_TYPE_LDT);
+ init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16);
+
+ save->efer = MSR_EFER_SVME_MASK;
+
+ save->dr6 = 0xffff0ff0;
+ save->dr7 = 0x400;
+ save->rflags = 2;
+ save->rip = 0x0000fff0;
+
+ /*
+ * cr0 val on cpu init should be 0x60000010, we enable cpu
+ * cache by default. the orderly way is to enable cache in bios.
+ */
+ save->cr0 = 0x00000010 | CR0_PG_MASK;
+ save->cr4 = CR4_PAE_MASK;
+ /* rdx = ?? */
+}
+
+static int svm_create_vcpu(struct kvm_vcpu *vcpu)
+{
+ struct page *page;
+ int r;
+
+ r = -ENOMEM;
+ vcpu->svm = kzalloc(sizeof *vcpu->svm, GFP_KERNEL);
+ if (!vcpu->svm)
+ goto out1;
+ page = alloc_page(GFP_KERNEL);
+ if (!page)
+ goto out2;
+
+ vcpu->svm->vmcb = page_address(page);
+ memset(vcpu->svm->vmcb, 0, PAGE_SIZE);
+ vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
+ vcpu->svm->cr0 = 0x00000010;
+ vcpu->svm->asid_generation = 0;
+ memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs));
+ init_vmcb(vcpu->svm->vmcb);
+
+ fx_init(vcpu);
+
+ return 0;
+
+out2:
+ kfree(vcpu->svm);
+out1:
+ return r;
+}
+
+static void svm_free_vcpu(struct kvm_vcpu *vcpu)
+{
+ if (!vcpu->svm)
+ return;
+ if (vcpu->svm->vmcb)
+ __free_page(pfn_to_page(vcpu->svm->vmcb_pa >> PAGE_SHIFT));
+ kfree(vcpu->svm);
+}
+
+static struct kvm_vcpu *svm_vcpu_load(struct kvm_vcpu *vcpu)
+{
+ get_cpu();
+ return vcpu;
+}
+
+static void svm_vcpu_put(struct kvm_vcpu *vcpu)
+{
+ put_cpu();
+}
+
+static void svm_cache_regs(struct kvm_vcpu *vcpu)
+{
+ vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax;
+ vcpu->regs[VCPU_REGS_RSP] = vcpu->svm->vmcb->save.rsp;
+ vcpu->rip = vcpu->svm->vmcb->save.rip;
+}
+
+static void svm_decache_regs(struct kvm_vcpu *vcpu)
+{
+ vcpu->svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX];
+ vcpu->svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP];
+ vcpu->svm->vmcb->save.rip = vcpu->rip;
+}
+
+static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
+{
+ return vcpu->svm->vmcb->save.rflags;
+}
+
+static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
+{
+ vcpu->svm->vmcb->save.rflags = rflags;
+}
+
+static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg)
+{
+ struct vmcb_save_area *save = &vcpu->svm->vmcb->save;
+
+ switch (seg) {
+ case VCPU_SREG_CS: return &save->cs;
+ case VCPU_SREG_DS: return &save->ds;
+ case VCPU_SREG_ES: return &save->es;
+ case VCPU_SREG_FS: return &save->fs;
+ case VCPU_SREG_GS: return &save->gs;
+ case VCPU_SREG_SS: return &save->ss;
+ case VCPU_SREG_TR: return &save->tr;
+ case VCPU_SREG_LDTR: return &save->ldtr;
+ }
+ BUG();
+ return NULL;
+}
+
+static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg)
+{
+ struct vmcb_seg *s = svm_seg(vcpu, seg);
+
+ return s->base;
+}
+
+static void svm_get_segment(struct kvm_vcpu *vcpu,
+ struct kvm_segment *var, int seg)
+{
+ struct vmcb_seg *s = svm_seg(vcpu, seg);
+
+ var->base = s->base;
+ var->limit = s->limit;
+ var->selector = s->selector;
+ var->type = s->attrib & SVM_SELECTOR_TYPE_MASK;
+ var->s = (s->attrib >> SVM_SELECTOR_S_SHIFT) & 1;
+ var->dpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3;
+ var->present = (s->attrib >> SVM_SELECTOR_P_SHIFT) & 1;
+ var->avl = (s->attrib >> SVM_SELECTOR_AVL_SHIFT) & 1;
+ var->l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1;
+ var->db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1;
+ var->g = (s->attrib >> SVM_SELECTOR_G_SHIFT) & 1;
+ var->unusable = !var->present;
+}
+
+static void svm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
+{
+ struct vmcb_seg *s = svm_seg(vcpu, VCPU_SREG_CS);
+
+ *db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1;
+ *l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1;
+}
+
+static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+ dt->limit = vcpu->svm->vmcb->save.idtr.limit;
+ dt->base = vcpu->svm->vmcb->save.idtr.base;
+}
+
+static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+ vcpu->svm->vmcb->save.idtr.limit = dt->limit;
+ vcpu->svm->vmcb->save.idtr.base = dt->base ;
+}
+
+static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+ dt->limit = vcpu->svm->vmcb->save.gdtr.limit;
+ dt->base = vcpu->svm->vmcb->save.gdtr.base;
+}
+
+static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+ vcpu->svm->vmcb->save.gdtr.limit = dt->limit;
+ vcpu->svm->vmcb->save.gdtr.base = dt->base ;
+}
+
+static void svm_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu)
+{
+}
+
+static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+{
+#ifdef CONFIG_X86_64
+ if (vcpu->shadow_efer & KVM_EFER_LME) {
+ if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
+ vcpu->shadow_efer |= KVM_EFER_LMA;
+ vcpu->svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME;
+ }
+
+ if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK) ) {
+ vcpu->shadow_efer &= ~KVM_EFER_LMA;
+ vcpu->svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME);
+ }
+ }
+#endif
+ vcpu->svm->cr0 = cr0;
+ vcpu->svm->vmcb->save.cr0 = cr0 | CR0_PG_MASK;
+ vcpu->cr0 = cr0;
+}
+
+static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+{
+ vcpu->cr4 = cr4;
+ vcpu->svm->vmcb->save.cr4 = cr4 | CR4_PAE_MASK;
+}
+
+static void svm_set_segment(struct kvm_vcpu *vcpu,
+ struct kvm_segment *var, int seg)
+{
+ struct vmcb_seg *s = svm_seg(vcpu, seg);
+
+ s->base = var->base;
+ s->limit = var->limit;
+ s->selector = var->selector;
+ if (var->unusable)
+ s->attrib = 0;
+ else {
+ s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
+ s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
+ s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
+ s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT;
+ s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
+ s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
+ s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
+ s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
+ }
+ if (seg == VCPU_SREG_CS)
+ vcpu->svm->vmcb->save.cpl
+ = (vcpu->svm->vmcb->save.cs.attrib
+ >> SVM_SELECTOR_DPL_SHIFT) & 3;
+
+}
+
+/* FIXME:
+
+ vcpu->svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
+ vcpu->svm->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK);
+
+*/
+
+static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
+{
+ return -EOPNOTSUPP;
+}
+
+static void load_host_msrs(struct kvm_vcpu *vcpu)
+{
+ int i;
+
+ for ( i = 0; i < NR_HOST_SAVE_MSRS; i++)
+ wrmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]);
+}
+
+static void save_host_msrs(struct kvm_vcpu *vcpu)
+{
+ int i;
+
+ for ( i = 0; i < NR_HOST_SAVE_MSRS; i++)
+ rdmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]);
+}
+
+static void new_asid(struct kvm_vcpu *vcpu, struct svm_cpu_data *svm_data)
+{
+ if (svm_data->next_asid > svm_data->max_asid) {
+ ++svm_data->asid_generation;
+ svm_data->next_asid = 1;
+ vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
+ }
+
+ vcpu->cpu = svm_data->cpu;
+ vcpu->svm->asid_generation = svm_data->asid_generation;
+ vcpu->svm->vmcb->control.asid = svm_data->next_asid++;
+}
+
+static void svm_invlpg(struct kvm_vcpu *vcpu, gva_t address)
+{
+ invlpga(address, vcpu->svm->vmcb->control.asid); // is needed?
+}
+
+static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
+{
+ return vcpu->svm->db_regs[dr];
+}
+
+static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
+ int *exception)
+{
+ *exception = 0;
+
+ if (vcpu->svm->vmcb->save.dr7 & DR7_GD_MASK) {
+ vcpu->svm->vmcb->save.dr7 &= ~DR7_GD_MASK;
+ vcpu->svm->vmcb->save.dr6 |= DR6_BD_MASK;
+ *exception = DB_VECTOR;
+ return;
+ }
+
+ switch (dr) {
+ case 0 ... 3:
+ vcpu->svm->db_regs[dr] = value;
+ return;
+ case 4 ... 5:
+ if (vcpu->cr4 & CR4_DE_MASK) {
+ *exception = UD_VECTOR;
+ return;
+ }
+ case 7: {
+ if (value & ~((1ULL << 32) - 1)) {
+ *exception = GP_VECTOR;
+ return;
+ }
+ vcpu->svm->vmcb->save.dr7 = value;
+ return;
+ }
+ default:
+ printk(KERN_DEBUG "%s: unexpected dr %u\n",
+ __FUNCTION__, dr);
+ *exception = UD_VECTOR;
+ return;
+ }
+}
+
+static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u32 exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
+ u64 fault_address;
+ u32 error_code;
+ enum emulation_result er;
+ int r;
+
+ if (is_external_interrupt(exit_int_info))
+ push_irq(vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
+
+ spin_lock(&vcpu->kvm->lock);
+
+ fault_address = vcpu->svm->vmcb->control.exit_info_2;
+ error_code = vcpu->svm->vmcb->control.exit_info_1;
+ r = kvm_mmu_page_fault(vcpu, fault_address, error_code);
+ if (r < 0) {
+ spin_unlock(&vcpu->kvm->lock);
+ return r;
+ }
+ if (!r) {
+ spin_unlock(&vcpu->kvm->lock);
+ return 1;
+ }
+ er = emulate_instruction(vcpu, kvm_run, fault_address, error_code);
+ spin_unlock(&vcpu->kvm->lock);
+
+ switch (er) {
+ case EMULATE_DONE:
+ return 1;
+ case EMULATE_DO_MMIO:
+ ++kvm_stat.mmio_exits;
+ kvm_run->exit_reason = KVM_EXIT_MMIO;
+ return 0;
+ case EMULATE_FAIL:
+ vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
+ break;
+ default:
+ BUG();
+ }
+
+ kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+ return 0;
+}
+
+static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ /*
+ * VMCB is undefined after a SHUTDOWN intercept
+ * so reinitialize it.
+ */
+ memset(vcpu->svm->vmcb, 0, PAGE_SIZE);
+ init_vmcb(vcpu->svm->vmcb);
+
+ kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
+ return 0;
+}
+
+static int io_get_override(struct kvm_vcpu *vcpu,
+ struct vmcb_seg **seg,
+ int *addr_override)
+{
+ u8 inst[MAX_INST_SIZE];
+ unsigned ins_length;
+ gva_t rip;
+ int i;
+
+ rip = vcpu->svm->vmcb->save.rip;
+ ins_length = vcpu->svm->next_rip - rip;
+ rip += vcpu->svm->vmcb->save.cs.base;
+
+ if (ins_length > MAX_INST_SIZE)
+ printk(KERN_DEBUG
+ "%s: inst length err, cs base 0x%llx rip 0x%llx "
+ "next rip 0x%llx ins_length %u\n",
+ __FUNCTION__,
+ vcpu->svm->vmcb->save.cs.base,
+ vcpu->svm->vmcb->save.rip,
+ vcpu->svm->vmcb->control.exit_info_2,
+ ins_length);
+
+ if (kvm_read_guest(vcpu, rip, ins_length, inst) != ins_length)
+ /* #PF */
+ return 0;
+
+ *addr_override = 0;
+ *seg = NULL;
+ for (i = 0; i < ins_length; i++)
+ switch (inst[i]) {
+ case 0xf0:
+ case 0xf2:
+ case 0xf3:
+ case 0x66:
+ continue;
+ case 0x67:
+ *addr_override = 1;
+ continue;
+ case 0x2e:
+ *seg = &vcpu->svm->vmcb->save.cs;
+ continue;
+ case 0x36:
+ *seg = &vcpu->svm->vmcb->save.ss;
+ continue;
+ case 0x3e:
+ *seg = &vcpu->svm->vmcb->save.ds;
+ continue;
+ case 0x26:
+ *seg = &vcpu->svm->vmcb->save.es;
+ continue;
+ case 0x64:
+ *seg = &vcpu->svm->vmcb->save.fs;
+ continue;
+ case 0x65:
+ *seg = &vcpu->svm->vmcb->save.gs;
+ continue;
+ default:
+ return 1;
+ }
+ printk(KERN_DEBUG "%s: unexpected\n", __FUNCTION__);
+ return 0;
+}
+
+static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, u64 *address)
+{
+ unsigned long addr_mask;
+ unsigned long *reg;
+ struct vmcb_seg *seg;
+ int addr_override;
+ struct vmcb_save_area *save_area = &vcpu->svm->vmcb->save;
+ u16 cs_attrib = save_area->cs.attrib;
+ unsigned addr_size = get_addr_size(vcpu);
+
+ if (!io_get_override(vcpu, &seg, &addr_override))
+ return 0;
+
+ if (addr_override)
+ addr_size = (addr_size == 2) ? 4: (addr_size >> 1);
+
+ if (ins) {
+ reg = &vcpu->regs[VCPU_REGS_RDI];
+ seg = &vcpu->svm->vmcb->save.es;
+ } else {
+ reg = &vcpu->regs[VCPU_REGS_RSI];
+ seg = (seg) ? seg : &vcpu->svm->vmcb->save.ds;
+ }
+
+ addr_mask = ~0ULL >> (64 - (addr_size * 8));
+
+ if ((cs_attrib & SVM_SELECTOR_L_MASK) &&
+ !(vcpu->svm->vmcb->save.rflags & X86_EFLAGS_VM)) {
+ *address = (*reg & addr_mask);
+ return addr_mask;
+ }
+
+ if (!(seg->attrib & SVM_SELECTOR_P_SHIFT)) {
+ svm_inject_gp(vcpu, 0);
+ return 0;
+ }
+
+ *address = (*reg & addr_mask) + seg->base;
+ return addr_mask;
+}
+
+static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug?
+ int _in = io_info & SVM_IOIO_TYPE_MASK;
+
+ ++kvm_stat.io_exits;
+
+ vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2;
+
+ kvm_run->exit_reason = KVM_EXIT_IO;
+ kvm_run->io.port = io_info >> 16;
+ kvm_run->io.direction = (_in) ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
+ kvm_run->io.size = ((io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT);
+ kvm_run->io.string = (io_info & SVM_IOIO_STR_MASK) != 0;
+ kvm_run->io.rep = (io_info & SVM_IOIO_REP_MASK) != 0;
+
+ if (kvm_run->io.string) {
+ unsigned addr_mask;
+
+ addr_mask = io_adress(vcpu, _in, &kvm_run->io.address);
+ if (!addr_mask) {
+ printk(KERN_DEBUG "%s: get io address failed\n", __FUNCTION__);
+ return 1;
+ }
+
+ if (kvm_run->io.rep) {
+ kvm_run->io.count = vcpu->regs[VCPU_REGS_RCX] & addr_mask;
+ kvm_run->io.string_down = (vcpu->svm->vmcb->save.rflags
+ & X86_EFLAGS_DF) != 0;
+ }
+ } else {
+ kvm_run->io.value = vcpu->svm->vmcb->save.rax;
+ }
+ return 0;
+}
+
+
+static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ return 1;
+}
+
+static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1;
+ skip_emulated_instruction(vcpu);
+ if (vcpu->irq_summary)
+ return 1;
+
+ kvm_run->exit_reason = KVM_EXIT_HLT;
+ ++kvm_stat.halt_exits;
+ return 0;
+}
+
+static int invalid_op_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ inject_ud(vcpu);
+ return 1;
+}
+
+static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ printk(KERN_DEBUG "%s: task swiche is unsupported\n", __FUNCTION__);
+ kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+ return 0;
+}
+
+static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
+ kvm_run->exit_reason = KVM_EXIT_CPUID;
+ return 0;
+}
+
+static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE)
+ printk(KERN_ERR "%s: failed\n", __FUNCTION__);
+ return 1;
+}
+
+static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
+{
+ switch (ecx) {
+ case MSR_IA32_TIME_STAMP_COUNTER: {
+ u64 tsc;
+
+ rdtscll(tsc);
+ *data = vcpu->svm->vmcb->control.tsc_offset + tsc;
+ break;
+ }
+ case MSR_K6_STAR:
+ *data = vcpu->svm->vmcb->save.star;
+ break;
+#ifdef CONFIG_X86_64
+ case MSR_LSTAR:
+ *data = vcpu->svm->vmcb->save.lstar;
+ break;
+ case MSR_CSTAR:
+ *data = vcpu->svm->vmcb->save.cstar;
+ break;
+ case MSR_KERNEL_GS_BASE:
+ *data = vcpu->svm->vmcb->save.kernel_gs_base;
+ break;
+ case MSR_SYSCALL_MASK:
+ *data = vcpu->svm->vmcb->save.sfmask;
+ break;
+#endif
+ case MSR_IA32_SYSENTER_CS:
+ *data = vcpu->svm->vmcb->save.sysenter_cs;
+ break;
+ case MSR_IA32_SYSENTER_EIP:
+ *data = vcpu->svm->vmcb->save.sysenter_eip;
+ break;
+ case MSR_IA32_SYSENTER_ESP:
+ *data = vcpu->svm->vmcb->save.sysenter_esp;
+ break;
+ default:
+ return kvm_get_msr_common(vcpu, ecx, data);
+ }
+ return 0;
+}
+
+static int rdmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u32 ecx = vcpu->regs[VCPU_REGS_RCX];
+ u64 data;
+
+ if (svm_get_msr(vcpu, ecx, &data))
+ svm_inject_gp(vcpu, 0);
+ else {
+ vcpu->svm->vmcb->save.rax = data & 0xffffffff;
+ vcpu->regs[VCPU_REGS_RDX] = data >> 32;
+ vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
+ skip_emulated_instruction(vcpu);
+ }
+ return 1;
+}
+
+static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
+{
+ switch (ecx) {
+ case MSR_IA32_TIME_STAMP_COUNTER: {
+ u64 tsc;
+
+ rdtscll(tsc);
+ vcpu->svm->vmcb->control.tsc_offset = data - tsc;
+ break;
+ }
+ case MSR_K6_STAR:
+ vcpu->svm->vmcb->save.star = data;
+ break;
+#ifdef CONFIG_X86_64
+ case MSR_LSTAR:
+ vcpu->svm->vmcb->save.lstar = data;
+ break;
+ case MSR_CSTAR:
+ vcpu->svm->vmcb->save.cstar = data;
+ break;
+ case MSR_KERNEL_GS_BASE:
+ vcpu->svm->vmcb->save.kernel_gs_base = data;
+ break;
+ case MSR_SYSCALL_MASK:
+ vcpu->svm->vmcb->save.sfmask = data;
+ break;
+#endif
+ case MSR_IA32_SYSENTER_CS:
+ vcpu->svm->vmcb->save.sysenter_cs = data;
+ break;
+ case MSR_IA32_SYSENTER_EIP:
+ vcpu->svm->vmcb->save.sysenter_eip = data;
+ break;
+ case MSR_IA32_SYSENTER_ESP:
+ vcpu->svm->vmcb->save.sysenter_esp = data;
+ break;
+ default:
+ return kvm_set_msr_common(vcpu, ecx, data);
+ }
+ return 0;
+}
+
+static int wrmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u32 ecx = vcpu->regs[VCPU_REGS_RCX];
+ u64 data = (vcpu->svm->vmcb->save.rax & -1u)
+ | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32);
+ vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
+ if (svm_set_msr(vcpu, ecx, data))
+ svm_inject_gp(vcpu, 0);
+ else
+ skip_emulated_instruction(vcpu);
+ return 1;
+}
+
+static int msr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ if (vcpu->svm->vmcb->control.exit_info_1)
+ return wrmsr_interception(vcpu, kvm_run);
+ else
+ return rdmsr_interception(vcpu, kvm_run);
+}
+
+static int interrupt_window_interception(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ /*
+ * If the user space waits to inject interrupts, exit as soon as
+ * possible
+ */
+ if (kvm_run->request_interrupt_window &&
+ !vcpu->irq_summary) {
+ ++kvm_stat.irq_window_exits;
+ kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run) = {
+ [SVM_EXIT_READ_CR0] = emulate_on_interception,
+ [SVM_EXIT_READ_CR3] = emulate_on_interception,
+ [SVM_EXIT_READ_CR4] = emulate_on_interception,
+ /* for now: */
+ [SVM_EXIT_WRITE_CR0] = emulate_on_interception,
+ [SVM_EXIT_WRITE_CR3] = emulate_on_interception,
+ [SVM_EXIT_WRITE_CR4] = emulate_on_interception,
+ [SVM_EXIT_READ_DR0] = emulate_on_interception,
+ [SVM_EXIT_READ_DR1] = emulate_on_interception,
+ [SVM_EXIT_READ_DR2] = emulate_on_interception,
+ [SVM_EXIT_READ_DR3] = emulate_on_interception,
+ [SVM_EXIT_WRITE_DR0] = emulate_on_interception,
+ [SVM_EXIT_WRITE_DR1] = emulate_on_interception,
+ [SVM_EXIT_WRITE_DR2] = emulate_on_interception,
+ [SVM_EXIT_WRITE_DR3] = emulate_on_interception,
+ [SVM_EXIT_WRITE_DR5] = emulate_on_interception,
+ [SVM_EXIT_WRITE_DR7] = emulate_on_interception,
+ [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception,
+ [SVM_EXIT_INTR] = nop_on_interception,
+ [SVM_EXIT_NMI] = nop_on_interception,
+ [SVM_EXIT_SMI] = nop_on_interception,
+ [SVM_EXIT_INIT] = nop_on_interception,
+ [SVM_EXIT_VINTR] = interrupt_window_interception,
+ /* [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, */
+ [SVM_EXIT_CPUID] = cpuid_interception,
+ [SVM_EXIT_HLT] = halt_interception,
+ [SVM_EXIT_INVLPG] = emulate_on_interception,
+ [SVM_EXIT_INVLPGA] = invalid_op_interception,
+ [SVM_EXIT_IOIO] = io_interception,
+ [SVM_EXIT_MSR] = msr_interception,
+ [SVM_EXIT_TASK_SWITCH] = task_switch_interception,
+ [SVM_EXIT_SHUTDOWN] = shutdown_interception,
+ [SVM_EXIT_VMRUN] = invalid_op_interception,
+ [SVM_EXIT_VMMCALL] = invalid_op_interception,
+ [SVM_EXIT_VMLOAD] = invalid_op_interception,
+ [SVM_EXIT_VMSAVE] = invalid_op_interception,
+ [SVM_EXIT_STGI] = invalid_op_interception,
+ [SVM_EXIT_CLGI] = invalid_op_interception,
+ [SVM_EXIT_SKINIT] = invalid_op_interception,
+};
+
+
+static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u32 exit_code = vcpu->svm->vmcb->control.exit_code;
+
+ kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT;
+
+ if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) &&
+ exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR)
+ printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
+ "exit_code 0x%x\n",
+ __FUNCTION__, vcpu->svm->vmcb->control.exit_int_info,
+ exit_code);
+
+ if (exit_code >= sizeof(svm_exit_handlers) / sizeof(*svm_exit_handlers)
+ || svm_exit_handlers[exit_code] == 0) {
+ kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+ printk(KERN_ERR "%s: 0x%x @ 0x%llx cr0 0x%lx rflags 0x%llx\n",
+ __FUNCTION__,
+ exit_code,
+ vcpu->svm->vmcb->save.rip,
+ vcpu->cr0,
+ vcpu->svm->vmcb->save.rflags);
+ return 0;
+ }
+
+ return svm_exit_handlers[exit_code](vcpu, kvm_run);
+}
+
+static void reload_tss(struct kvm_vcpu *vcpu)
+{
+ int cpu = raw_smp_processor_id();
+
+ struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
+ svm_data->tss_desc->type = 9; //available 32/64-bit TSS
+ load_TR_desc();
+}
+
+static void pre_svm_run(struct kvm_vcpu *vcpu)
+{
+ int cpu = raw_smp_processor_id();
+
+ struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
+
+ vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
+ if (vcpu->cpu != cpu ||
+ vcpu->svm->asid_generation != svm_data->asid_generation)
+ new_asid(vcpu, svm_data);
+}
+
+
+static inline void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
+{
+ struct vmcb_control_area *control;
+
+ control = &vcpu->svm->vmcb->control;
+ control->int_vector = pop_irq(vcpu);
+ control->int_ctl &= ~V_INTR_PRIO_MASK;
+ control->int_ctl |= V_IRQ_MASK |
+ ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
+}
+
+static void kvm_reput_irq(struct kvm_vcpu *vcpu)
+{
+ struct vmcb_control_area *control = &vcpu->svm->vmcb->control;
+
+ if (control->int_ctl & V_IRQ_MASK) {
+ control->int_ctl &= ~V_IRQ_MASK;
+ push_irq(vcpu, control->int_vector);
+ }
+
+ vcpu->interrupt_window_open =
+ !(control->int_state & SVM_INTERRUPT_SHADOW_MASK);
+}
+
+static void do_interrupt_requests(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ struct vmcb_control_area *control = &vcpu->svm->vmcb->control;
+
+ vcpu->interrupt_window_open =
+ (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) &&
+ (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
+
+ if (vcpu->interrupt_window_open && vcpu->irq_summary)
+ /*
+ * If interrupts enabled, and not blocked by sti or mov ss. Good.
+ */
+ kvm_do_inject_irq(vcpu);
+
+ /*
+ * Interrupts blocked. Wait for unblock.
+ */
+ if (!vcpu->interrupt_window_open &&
+ (vcpu->irq_summary || kvm_run->request_interrupt_window)) {
+ control->intercept |= 1ULL << INTERCEPT_VINTR;
+ } else
+ control->intercept &= ~(1ULL << INTERCEPT_VINTR);
+}
+
+static void post_kvm_run_save(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
+ vcpu->irq_summary == 0);
+ kvm_run->if_flag = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0;
+ kvm_run->cr8 = vcpu->cr8;
+ kvm_run->apic_base = vcpu->apic_base;
+}
+
+/*
+ * Check if userspace requested an interrupt window, and that the
+ * interrupt window is open.
+ *
+ * No need to exit to userspace if we already have an interrupt queued.
+ */
+static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ return (!vcpu->irq_summary &&
+ kvm_run->request_interrupt_window &&
+ vcpu->interrupt_window_open &&
+ (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
+}
+
+static void save_db_regs(unsigned long *db_regs)
+{
+ asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0]));
+ asm volatile ("mov %%dr1, %0" : "=r"(db_regs[1]));
+ asm volatile ("mov %%dr2, %0" : "=r"(db_regs[2]));
+ asm volatile ("mov %%dr3, %0" : "=r"(db_regs[3]));
+}
+
+static void load_db_regs(unsigned long *db_regs)
+{
+ asm volatile ("mov %0, %%dr0" : : "r"(db_regs[0]));
+ asm volatile ("mov %0, %%dr1" : : "r"(db_regs[1]));
+ asm volatile ("mov %0, %%dr2" : : "r"(db_regs[2]));
+ asm volatile ("mov %0, %%dr3" : : "r"(db_regs[3]));
+}
+
+static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u16 fs_selector;
+ u16 gs_selector;
+ u16 ldt_selector;
+ int r;
+
+again:
+ if (!vcpu->mmio_read_completed)
+ do_interrupt_requests(vcpu, kvm_run);
+
+ clgi();
+
+ pre_svm_run(vcpu);
+
+ save_host_msrs(vcpu);
+ fs_selector = read_fs();
+ gs_selector = read_gs();
+ ldt_selector = read_ldt();
+ vcpu->svm->host_cr2 = kvm_read_cr2();
+ vcpu->svm->host_dr6 = read_dr6();
+ vcpu->svm->host_dr7 = read_dr7();
+ vcpu->svm->vmcb->save.cr2 = vcpu->cr2;
+
+ if (vcpu->svm->vmcb->save.dr7 & 0xff) {
+ write_dr7(0);
+ save_db_regs(vcpu->svm->host_db_regs);
+ load_db_regs(vcpu->svm->db_regs);
+ }
+
+ fx_save(vcpu->host_fx_image);
+ fx_restore(vcpu->guest_fx_image);
+
+ asm volatile (
+#ifdef CONFIG_X86_64
+ "push %%rbx; push %%rcx; push %%rdx;"
+ "push %%rsi; push %%rdi; push %%rbp;"
+ "push %%r8; push %%r9; push %%r10; push %%r11;"
+ "push %%r12; push %%r13; push %%r14; push %%r15;"
+#else
+ "push %%ebx; push %%ecx; push %%edx;"
+ "push %%esi; push %%edi; push %%ebp;"
+#endif
+
+#ifdef CONFIG_X86_64
+ "mov %c[rbx](%[vcpu]), %%rbx \n\t"
+ "mov %c[rcx](%[vcpu]), %%rcx \n\t"
+ "mov %c[rdx](%[vcpu]), %%rdx \n\t"
+ "mov %c[rsi](%[vcpu]), %%rsi \n\t"
+ "mov %c[rdi](%[vcpu]), %%rdi \n\t"
+ "mov %c[rbp](%[vcpu]), %%rbp \n\t"
+ "mov %c[r8](%[vcpu]), %%r8 \n\t"
+ "mov %c[r9](%[vcpu]), %%r9 \n\t"
+ "mov %c[r10](%[vcpu]), %%r10 \n\t"
+ "mov %c[r11](%[vcpu]), %%r11 \n\t"
+ "mov %c[r12](%[vcpu]), %%r12 \n\t"
+ "mov %c[r13](%[vcpu]), %%r13 \n\t"
+ "mov %c[r14](%[vcpu]), %%r14 \n\t"
+ "mov %c[r15](%[vcpu]), %%r15 \n\t"
+#else
+ "mov %c[rbx](%[vcpu]), %%ebx \n\t"
+ "mov %c[rcx](%[vcpu]), %%ecx \n\t"
+ "mov %c[rdx](%[vcpu]), %%edx \n\t"
+ "mov %c[rsi](%[vcpu]), %%esi \n\t"
+ "mov %c[rdi](%[vcpu]), %%edi \n\t"
+ "mov %c[rbp](%[vcpu]), %%ebp \n\t"
+#endif
+
+#ifdef CONFIG_X86_64
+ /* Enter guest mode */
+ "push %%rax \n\t"
+ "mov %c[svm](%[vcpu]), %%rax \n\t"
+ "mov %c[vmcb](%%rax), %%rax \n\t"
+ SVM_VMLOAD "\n\t"
+ SVM_VMRUN "\n\t"
+ SVM_VMSAVE "\n\t"
+ "pop %%rax \n\t"
+#else
+ /* Enter guest mode */
+ "push %%eax \n\t"
+ "mov %c[svm](%[vcpu]), %%eax \n\t"
+ "mov %c[vmcb](%%eax), %%eax \n\t"
+ SVM_VMLOAD "\n\t"
+ SVM_VMRUN "\n\t"
+ SVM_VMSAVE "\n\t"
+ "pop %%eax \n\t"
+#endif
+
+ /* Save guest registers, load host registers */
+#ifdef CONFIG_X86_64
+ "mov %%rbx, %c[rbx](%[vcpu]) \n\t"
+ "mov %%rcx, %c[rcx](%[vcpu]) \n\t"
+ "mov %%rdx, %c[rdx](%[vcpu]) \n\t"
+ "mov %%rsi, %c[rsi](%[vcpu]) \n\t"
+ "mov %%rdi, %c[rdi](%[vcpu]) \n\t"
+ "mov %%rbp, %c[rbp](%[vcpu]) \n\t"
+ "mov %%r8, %c[r8](%[vcpu]) \n\t"
+ "mov %%r9, %c[r9](%[vcpu]) \n\t"
+ "mov %%r10, %c[r10](%[vcpu]) \n\t"
+ "mov %%r11, %c[r11](%[vcpu]) \n\t"
+ "mov %%r12, %c[r12](%[vcpu]) \n\t"
+ "mov %%r13, %c[r13](%[vcpu]) \n\t"
+ "mov %%r14, %c[r14](%[vcpu]) \n\t"
+ "mov %%r15, %c[r15](%[vcpu]) \n\t"
+
+ "pop %%r15; pop %%r14; pop %%r13; pop %%r12;"
+ "pop %%r11; pop %%r10; pop %%r9; pop %%r8;"
+ "pop %%rbp; pop %%rdi; pop %%rsi;"
+ "pop %%rdx; pop %%rcx; pop %%rbx; \n\t"
+#else
+ "mov %%ebx, %c[rbx](%[vcpu]) \n\t"
+ "mov %%ecx, %c[rcx](%[vcpu]) \n\t"
+ "mov %%edx, %c[rdx](%[vcpu]) \n\t"
+ "mov %%esi, %c[rsi](%[vcpu]) \n\t"
+ "mov %%edi, %c[rdi](%[vcpu]) \n\t"
+ "mov %%ebp, %c[rbp](%[vcpu]) \n\t"
+
+ "pop %%ebp; pop %%edi; pop %%esi;"
+ "pop %%edx; pop %%ecx; pop %%ebx; \n\t"
+#endif
+ :
+ : [vcpu]"a"(vcpu),
+ [svm]"i"(offsetof(struct kvm_vcpu, svm)),
+ [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)),
+ [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
+ [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])),
+ [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])),
+ [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])),
+ [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])),
+ [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP]))
+#ifdef CONFIG_X86_64
+ ,[r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])),
+ [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])),
+ [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])),
+ [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])),
+ [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])),
+ [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])),
+ [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])),
+ [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15]))
+#endif
+ : "cc", "memory" );
+
+ fx_save(vcpu->guest_fx_image);
+ fx_restore(vcpu->host_fx_image);
+
+ if ((vcpu->svm->vmcb->save.dr7 & 0xff))
+ load_db_regs(vcpu->svm->host_db_regs);
+
+ vcpu->cr2 = vcpu->svm->vmcb->save.cr2;
+
+ write_dr6(vcpu->svm->host_dr6);
+ write_dr7(vcpu->svm->host_dr7);
+ kvm_write_cr2(vcpu->svm->host_cr2);
+
+ load_fs(fs_selector);
+ load_gs(gs_selector);
+ load_ldt(ldt_selector);
+ load_host_msrs(vcpu);
+
+ reload_tss(vcpu);
+
+ /*
+ * Profile KVM exit RIPs:
+ */
+ if (unlikely(prof_on == KVM_PROFILING))
+ profile_hit(KVM_PROFILING,
+ (void *)(unsigned long)vcpu->svm->vmcb->save.rip);
+
+ stgi();
+
+ kvm_reput_irq(vcpu);
+
+ vcpu->svm->next_rip = 0;
+
+ if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
+ kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY;
+ kvm_run->exit_reason = vcpu->svm->vmcb->control.exit_code;
+ post_kvm_run_save(vcpu, kvm_run);
+ return 0;
+ }
+
+ r = handle_exit(vcpu, kvm_run);
+ if (r > 0) {
+ if (signal_pending(current)) {
+ ++kvm_stat.signal_exits;
+ post_kvm_run_save(vcpu, kvm_run);
+ return -EINTR;
+ }
+
+ if (dm_request_for_irq_injection(vcpu, kvm_run)) {
+ ++kvm_stat.request_irq_exits;
+ post_kvm_run_save(vcpu, kvm_run);
+ return -EINTR;
+ }
+ kvm_resched(vcpu);
+ goto again;
+ }
+ post_kvm_run_save(vcpu, kvm_run);
+ return r;
+}
+
+static void svm_flush_tlb(struct kvm_vcpu *vcpu)
+{
+ force_new_asid(vcpu);
+}
+
+static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
+{
+ vcpu->svm->vmcb->save.cr3 = root;
+ force_new_asid(vcpu);
+}
+
+static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
+ unsigned long addr,
+ uint32_t err_code)
+{
+ uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
+
+ ++kvm_stat.pf_guest;
+
+ if (is_page_fault(exit_int_info)) {
+
+ vcpu->svm->vmcb->control.event_inj_err = 0;
+ vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ SVM_EVTINJ_VALID_ERR |
+ SVM_EVTINJ_TYPE_EXEPT |
+ DF_VECTOR;
+ return;
+ }
+ vcpu->cr2 = addr;
+ vcpu->svm->vmcb->save.cr2 = addr;
+ vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ SVM_EVTINJ_VALID_ERR |
+ SVM_EVTINJ_TYPE_EXEPT |
+ PF_VECTOR;
+ vcpu->svm->vmcb->control.event_inj_err = err_code;
+}
+
+
+static int is_disabled(void)
+{
+ return 0;
+}
+
+static struct kvm_arch_ops svm_arch_ops = {
+ .cpu_has_kvm_support = has_svm,
+ .disabled_by_bios = is_disabled,
+ .hardware_setup = svm_hardware_setup,
+ .hardware_unsetup = svm_hardware_unsetup,
+ .hardware_enable = svm_hardware_enable,
+ .hardware_disable = svm_hardware_disable,
+
+ .vcpu_create = svm_create_vcpu,
+ .vcpu_free = svm_free_vcpu,
+
+ .vcpu_load = svm_vcpu_load,
+ .vcpu_put = svm_vcpu_put,
+
+ .set_guest_debug = svm_guest_debug,
+ .get_msr = svm_get_msr,
+ .set_msr = svm_set_msr,
+ .get_segment_base = svm_get_segment_base,
+ .get_segment = svm_get_segment,
+ .set_segment = svm_set_segment,
+ .get_cs_db_l_bits = svm_get_cs_db_l_bits,
+ .decache_cr0_cr4_guest_bits = svm_decache_cr0_cr4_guest_bits,
+ .set_cr0 = svm_set_cr0,
+ .set_cr0_no_modeswitch = svm_set_cr0,
+ .set_cr3 = svm_set_cr3,
+ .set_cr4 = svm_set_cr4,
+ .set_efer = svm_set_efer,
+ .get_idt = svm_get_idt,
+ .set_idt = svm_set_idt,
+ .get_gdt = svm_get_gdt,
+ .set_gdt = svm_set_gdt,
+ .get_dr = svm_get_dr,
+ .set_dr = svm_set_dr,
+ .cache_regs = svm_cache_regs,
+ .decache_regs = svm_decache_regs,
+ .get_rflags = svm_get_rflags,
+ .set_rflags = svm_set_rflags,
+
+ .invlpg = svm_invlpg,
+ .tlb_flush = svm_flush_tlb,
+ .inject_page_fault = svm_inject_page_fault,
+
+ .inject_gp = svm_inject_gp,
+
+ .run = svm_vcpu_run,
+ .skip_emulated_instruction = skip_emulated_instruction,
+ .vcpu_setup = svm_vcpu_setup,
+};
+
+static int __init svm_init(void)
+{
+ return kvm_init_arch(&svm_arch_ops, THIS_MODULE);
+}
+
+static void __exit svm_exit(void)
+{
+ kvm_exit_arch();
+}
+
+module_init(svm_init)
+module_exit(svm_exit)
diff --git a/drivers/kvm/svm.h b/drivers/kvm/svm.h
new file mode 100644
index 00000000000..df731c3fb58
--- /dev/null
+++ b/drivers/kvm/svm.h
@@ -0,0 +1,315 @@
+#ifndef __SVM_H
+#define __SVM_H
+
+enum {
+ INTERCEPT_INTR,
+ INTERCEPT_NMI,
+ INTERCEPT_SMI,
+ INTERCEPT_INIT,
+ INTERCEPT_VINTR,
+ INTERCEPT_SELECTIVE_CR0,
+ INTERCEPT_STORE_IDTR,
+ INTERCEPT_STORE_GDTR,
+ INTERCEPT_STORE_LDTR,
+ INTERCEPT_STORE_TR,
+ INTERCEPT_LOAD_IDTR,
+ INTERCEPT_LOAD_GDTR,
+ INTERCEPT_LOAD_LDTR,
+ INTERCEPT_LOAD_TR,
+ INTERCEPT_RDTSC,
+ INTERCEPT_RDPMC,
+ INTERCEPT_PUSHF,
+ INTERCEPT_POPF,
+ INTERCEPT_CPUID,
+ INTERCEPT_RSM,
+ INTERCEPT_IRET,
+ INTERCEPT_INTn,
+ INTERCEPT_INVD,
+ INTERCEPT_PAUSE,
+ INTERCEPT_HLT,
+ INTERCEPT_INVLPG,
+ INTERCEPT_INVLPGA,
+ INTERCEPT_IOIO_PROT,
+ INTERCEPT_MSR_PROT,
+ INTERCEPT_TASK_SWITCH,
+ INTERCEPT_FERR_FREEZE,
+ INTERCEPT_SHUTDOWN,
+ INTERCEPT_VMRUN,
+ INTERCEPT_VMMCALL,
+ INTERCEPT_VMLOAD,
+ INTERCEPT_VMSAVE,
+ INTERCEPT_STGI,
+ INTERCEPT_CLGI,
+ INTERCEPT_SKINIT,
+ INTERCEPT_RDTSCP,
+ INTERCEPT_ICEBP,
+ INTERCEPT_WBINVD,
+};
+
+
+struct __attribute__ ((__packed__)) vmcb_control_area {
+ u16 intercept_cr_read;
+ u16 intercept_cr_write;
+ u16 intercept_dr_read;
+ u16 intercept_dr_write;
+ u32 intercept_exceptions;
+ u64 intercept;
+ u8 reserved_1[44];
+ u64 iopm_base_pa;
+ u64 msrpm_base_pa;
+ u64 tsc_offset;
+ u32 asid;
+ u8 tlb_ctl;
+ u8 reserved_2[3];
+ u32 int_ctl;
+ u32 int_vector;
+ u32 int_state;
+ u8 reserved_3[4];
+ u32 exit_code;
+ u32 exit_code_hi;
+ u64 exit_info_1;
+ u64 exit_info_2;
+ u32 exit_int_info;
+ u32 exit_int_info_err;
+ u64 nested_ctl;
+ u8 reserved_4[16];
+ u32 event_inj;
+ u32 event_inj_err;
+ u64 nested_cr3;
+ u64 lbr_ctl;
+ u8 reserved_5[832];
+};
+
+
+#define TLB_CONTROL_DO_NOTHING 0
+#define TLB_CONTROL_FLUSH_ALL_ASID 1
+
+#define V_TPR_MASK 0x0f
+
+#define V_IRQ_SHIFT 8
+#define V_IRQ_MASK (1 << V_IRQ_SHIFT)
+
+#define V_INTR_PRIO_SHIFT 16
+#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT)
+
+#define V_IGN_TPR_SHIFT 20
+#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT)
+
+#define V_INTR_MASKING_SHIFT 24
+#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
+
+#define SVM_INTERRUPT_SHADOW_MASK 1
+
+#define SVM_IOIO_STR_SHIFT 2
+#define SVM_IOIO_REP_SHIFT 3
+#define SVM_IOIO_SIZE_SHIFT 4
+#define SVM_IOIO_ASIZE_SHIFT 7
+
+#define SVM_IOIO_TYPE_MASK 1
+#define SVM_IOIO_STR_MASK (1 << SVM_IOIO_STR_SHIFT)
+#define SVM_IOIO_REP_MASK (1 << SVM_IOIO_REP_SHIFT)
+#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT)
+#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT)
+
+struct __attribute__ ((__packed__)) vmcb_seg {
+ u16 selector;
+ u16 attrib;
+ u32 limit;
+ u64 base;
+};
+
+struct __attribute__ ((__packed__)) vmcb_save_area {
+ struct vmcb_seg es;
+ struct vmcb_seg cs;
+ struct vmcb_seg ss;
+ struct vmcb_seg ds;
+ struct vmcb_seg fs;
+ struct vmcb_seg gs;
+ struct vmcb_seg gdtr;
+ struct vmcb_seg ldtr;
+ struct vmcb_seg idtr;
+ struct vmcb_seg tr;
+ u8 reserved_1[43];
+ u8 cpl;
+ u8 reserved_2[4];
+ u64 efer;
+ u8 reserved_3[112];
+ u64 cr4;
+ u64 cr3;
+ u64 cr0;
+ u64 dr7;
+ u64 dr6;
+ u64 rflags;
+ u64 rip;
+ u8 reserved_4[88];
+ u64 rsp;
+ u8 reserved_5[24];
+ u64 rax;
+ u64 star;
+ u64 lstar;
+ u64 cstar;
+ u64 sfmask;
+ u64 kernel_gs_base;
+ u64 sysenter_cs;
+ u64 sysenter_esp;
+ u64 sysenter_eip;
+ u64 cr2;
+ u8 reserved_6[32];
+ u64 g_pat;
+ u64 dbgctl;
+ u64 br_from;
+ u64 br_to;
+ u64 last_excp_from;
+ u64 last_excp_to;
+};
+
+struct __attribute__ ((__packed__)) vmcb {
+ struct vmcb_control_area control;
+ struct vmcb_save_area save;
+};
+
+#define SVM_CPUID_FEATURE_SHIFT 2
+#define SVM_CPUID_FUNC 0x8000000a
+
+#define MSR_EFER_SVME_MASK (1ULL << 12)
+#define MSR_VM_HSAVE_PA 0xc0010117ULL
+
+#define SVM_SELECTOR_S_SHIFT 4
+#define SVM_SELECTOR_DPL_SHIFT 5
+#define SVM_SELECTOR_P_SHIFT 7
+#define SVM_SELECTOR_AVL_SHIFT 8
+#define SVM_SELECTOR_L_SHIFT 9
+#define SVM_SELECTOR_DB_SHIFT 10
+#define SVM_SELECTOR_G_SHIFT 11
+
+#define SVM_SELECTOR_TYPE_MASK (0xf)
+#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT)
+#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT)
+#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT)
+#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT)
+#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT)
+#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT)
+#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT)
+
+#define SVM_SELECTOR_WRITE_MASK (1 << 1)
+#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK
+#define SVM_SELECTOR_CODE_MASK (1 << 3)
+
+#define INTERCEPT_CR0_MASK 1
+#define INTERCEPT_CR3_MASK (1 << 3)
+#define INTERCEPT_CR4_MASK (1 << 4)
+
+#define INTERCEPT_DR0_MASK 1
+#define INTERCEPT_DR1_MASK (1 << 1)
+#define INTERCEPT_DR2_MASK (1 << 2)
+#define INTERCEPT_DR3_MASK (1 << 3)
+#define INTERCEPT_DR4_MASK (1 << 4)
+#define INTERCEPT_DR5_MASK (1 << 5)
+#define INTERCEPT_DR6_MASK (1 << 6)
+#define INTERCEPT_DR7_MASK (1 << 7)
+
+#define SVM_EVTINJ_VEC_MASK 0xff
+
+#define SVM_EVTINJ_TYPE_SHIFT 8
+#define SVM_EVTINJ_TYPE_MASK (7 << SVM_EVTINJ_TYPE_SHIFT)
+
+#define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT)
+
+#define SVM_EVTINJ_VALID (1 << 31)
+#define SVM_EVTINJ_VALID_ERR (1 << 11)
+
+#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK
+
+#define SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR
+#define SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI
+#define SVM_EXITINTINFO_TYPE_EXEPT SVM_EVTINJ_TYPE_EXEPT
+#define SVM_EXITINTINFO_TYPE_SOFT SVM_EVTINJ_TYPE_SOFT
+
+#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID
+#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR
+
+#define SVM_EXIT_READ_CR0 0x000
+#define SVM_EXIT_READ_CR3 0x003
+#define SVM_EXIT_READ_CR4 0x004
+#define SVM_EXIT_READ_CR8 0x008
+#define SVM_EXIT_WRITE_CR0 0x010
+#define SVM_EXIT_WRITE_CR3 0x013
+#define SVM_EXIT_WRITE_CR4 0x014
+#define SVM_EXIT_WRITE_CR8 0x018
+#define SVM_EXIT_READ_DR0 0x020
+#define SVM_EXIT_READ_DR1 0x021
+#define SVM_EXIT_READ_DR2 0x022
+#define SVM_EXIT_READ_DR3 0x023
+#define SVM_EXIT_READ_DR4 0x024
+#define SVM_EXIT_READ_DR5 0x025
+#define SVM_EXIT_READ_DR6 0x026
+#define SVM_EXIT_READ_DR7 0x027
+#define SVM_EXIT_WRITE_DR0 0x030
+#define SVM_EXIT_WRITE_DR1 0x031
+#define SVM_EXIT_WRITE_DR2 0x032
+#define SVM_EXIT_WRITE_DR3 0x033
+#define SVM_EXIT_WRITE_DR4 0x034
+#define SVM_EXIT_WRITE_DR5 0x035
+#define SVM_EXIT_WRITE_DR6 0x036
+#define SVM_EXIT_WRITE_DR7 0x037
+#define SVM_EXIT_EXCP_BASE 0x040
+#define SVM_EXIT_INTR 0x060
+#define SVM_EXIT_NMI 0x061
+#define SVM_EXIT_SMI 0x062
+#define SVM_EXIT_INIT 0x063
+#define SVM_EXIT_VINTR 0x064
+#define SVM_EXIT_CR0_SEL_WRITE 0x065
+#define SVM_EXIT_IDTR_READ 0x066
+#define SVM_EXIT_GDTR_READ 0x067
+#define SVM_EXIT_LDTR_READ 0x068
+#define SVM_EXIT_TR_READ 0x069
+#define SVM_EXIT_IDTR_WRITE 0x06a
+#define SVM_EXIT_GDTR_WRITE 0x06b
+#define SVM_EXIT_LDTR_WRITE 0x06c
+#define SVM_EXIT_TR_WRITE 0x06d
+#define SVM_EXIT_RDTSC 0x06e
+#define SVM_EXIT_RDPMC 0x06f
+#define SVM_EXIT_PUSHF 0x070
+#define SVM_EXIT_POPF 0x071
+#define SVM_EXIT_CPUID 0x072
+#define SVM_EXIT_RSM 0x073
+#define SVM_EXIT_IRET 0x074
+#define SVM_EXIT_SWINT 0x075
+#define SVM_EXIT_INVD 0x076
+#define SVM_EXIT_PAUSE 0x077
+#define SVM_EXIT_HLT 0x078
+#define SVM_EXIT_INVLPG 0x079
+#define SVM_EXIT_INVLPGA 0x07a
+#define SVM_EXIT_IOIO 0x07b
+#define SVM_EXIT_MSR 0x07c
+#define SVM_EXIT_TASK_SWITCH 0x07d
+#define SVM_EXIT_FERR_FREEZE 0x07e
+#define SVM_EXIT_SHUTDOWN 0x07f
+#define SVM_EXIT_VMRUN 0x080
+#define SVM_EXIT_VMMCALL 0x081
+#define SVM_EXIT_VMLOAD 0x082
+#define SVM_EXIT_VMSAVE 0x083
+#define SVM_EXIT_STGI 0x084
+#define SVM_EXIT_CLGI 0x085
+#define SVM_EXIT_SKINIT 0x086
+#define SVM_EXIT_RDTSCP 0x087
+#define SVM_EXIT_ICEBP 0x088
+#define SVM_EXIT_WBINVD 0x089
+#define SVM_EXIT_NPF 0x400
+
+#define SVM_EXIT_ERR -1
+
+#define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) // TS and MP
+
+#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda"
+#define SVM_VMRUN ".byte 0x0f, 0x01, 0xd8"
+#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb"
+#define SVM_CLGI ".byte 0x0f, 0x01, 0xdd"
+#define SVM_STGI ".byte 0x0f, 0x01, 0xdc"
+#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf"
+
+#endif
+
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
new file mode 100644
index 00000000000..27e05a77e21
--- /dev/null
+++ b/drivers/kvm/vmx.c
@@ -0,0 +1,2061 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This module enables machines with Intel VT-x extensions to run virtual
+ * machines without emulation or binary translation.
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ * Avi Kivity <avi@qumranet.com>
+ * Yaniv Kamay <yaniv@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "kvm.h"
+#include "vmx.h"
+#include "kvm_vmx.h"
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/profile.h>
+#include <asm/io.h>
+#include <asm/desc.h>
+
+#include "segment_descriptor.h"
+
+
+MODULE_AUTHOR("Qumranet");
+MODULE_LICENSE("GPL");
+
+static DEFINE_PER_CPU(struct vmcs *, vmxarea);
+static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
+
+#ifdef CONFIG_X86_64
+#define HOST_IS_64 1
+#else
+#define HOST_IS_64 0
+#endif
+
+static struct vmcs_descriptor {
+ int size;
+ int order;
+ u32 revision_id;
+} vmcs_descriptor;
+
+#define VMX_SEGMENT_FIELD(seg) \
+ [VCPU_SREG_##seg] = { \
+ .selector = GUEST_##seg##_SELECTOR, \
+ .base = GUEST_##seg##_BASE, \
+ .limit = GUEST_##seg##_LIMIT, \
+ .ar_bytes = GUEST_##seg##_AR_BYTES, \
+ }
+
+static struct kvm_vmx_segment_field {
+ unsigned selector;
+ unsigned base;
+ unsigned limit;
+ unsigned ar_bytes;
+} kvm_vmx_segment_fields[] = {
+ VMX_SEGMENT_FIELD(CS),
+ VMX_SEGMENT_FIELD(DS),
+ VMX_SEGMENT_FIELD(ES),
+ VMX_SEGMENT_FIELD(FS),
+ VMX_SEGMENT_FIELD(GS),
+ VMX_SEGMENT_FIELD(SS),
+ VMX_SEGMENT_FIELD(TR),
+ VMX_SEGMENT_FIELD(LDTR),
+};
+
+static const u32 vmx_msr_index[] = {
+#ifdef CONFIG_X86_64
+ MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, MSR_KERNEL_GS_BASE,
+#endif
+ MSR_EFER, MSR_K6_STAR,
+};
+#define NR_VMX_MSR (sizeof(vmx_msr_index) / sizeof(*vmx_msr_index))
+
+static inline int is_page_fault(u32 intr_info)
+{
+ return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
+ INTR_INFO_VALID_MASK)) ==
+ (INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
+}
+
+static inline int is_external_interrupt(u32 intr_info)
+{
+ return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
+ == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+}
+
+static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
+{
+ int i;
+
+ for (i = 0; i < vcpu->nmsrs; ++i)
+ if (vcpu->guest_msrs[i].index == msr)
+ return &vcpu->guest_msrs[i];
+ return NULL;
+}
+
+static void vmcs_clear(struct vmcs *vmcs)
+{
+ u64 phys_addr = __pa(vmcs);
+ u8 error;
+
+ asm volatile (ASM_VMX_VMCLEAR_RAX "; setna %0"
+ : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
+ : "cc", "memory");
+ if (error)
+ printk(KERN_ERR "kvm: vmclear fail: %p/%llx\n",
+ vmcs, phys_addr);
+}
+
+static void __vcpu_clear(void *arg)
+{
+ struct kvm_vcpu *vcpu = arg;
+ int cpu = raw_smp_processor_id();
+
+ if (vcpu->cpu == cpu)
+ vmcs_clear(vcpu->vmcs);
+ if (per_cpu(current_vmcs, cpu) == vcpu->vmcs)
+ per_cpu(current_vmcs, cpu) = NULL;
+}
+
+static unsigned long vmcs_readl(unsigned long field)
+{
+ unsigned long value;
+
+ asm volatile (ASM_VMX_VMREAD_RDX_RAX
+ : "=a"(value) : "d"(field) : "cc");
+ return value;
+}
+
+static u16 vmcs_read16(unsigned long field)
+{
+ return vmcs_readl(field);
+}
+
+static u32 vmcs_read32(unsigned long field)
+{
+ return vmcs_readl(field);
+}
+
+static u64 vmcs_read64(unsigned long field)
+{
+#ifdef CONFIG_X86_64
+ return vmcs_readl(field);
+#else
+ return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32);
+#endif
+}
+
+static noinline void vmwrite_error(unsigned long field, unsigned long value)
+{
+ printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n",
+ field, value, vmcs_read32(VM_INSTRUCTION_ERROR));
+ dump_stack();
+}
+
+static void vmcs_writel(unsigned long field, unsigned long value)
+{
+ u8 error;
+
+ asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0"
+ : "=q"(error) : "a"(value), "d"(field) : "cc" );
+ if (unlikely(error))
+ vmwrite_error(field, value);
+}
+
+static void vmcs_write16(unsigned long field, u16 value)
+{
+ vmcs_writel(field, value);
+}
+
+static void vmcs_write32(unsigned long field, u32 value)
+{
+ vmcs_writel(field, value);
+}
+
+static void vmcs_write64(unsigned long field, u64 value)
+{
+#ifdef CONFIG_X86_64
+ vmcs_writel(field, value);
+#else
+ vmcs_writel(field, value);
+ asm volatile ("");
+ vmcs_writel(field+1, value >> 32);
+#endif
+}
+
+/*
+ * Switches to specified vcpu, until a matching vcpu_put(), but assumes
+ * vcpu mutex is already taken.
+ */
+static struct kvm_vcpu *vmx_vcpu_load(struct kvm_vcpu *vcpu)
+{
+ u64 phys_addr = __pa(vcpu->vmcs);
+ int cpu;
+
+ cpu = get_cpu();
+
+ if (vcpu->cpu != cpu) {
+ smp_call_function(__vcpu_clear, vcpu, 0, 1);
+ vcpu->launched = 0;
+ }
+
+ if (per_cpu(current_vmcs, cpu) != vcpu->vmcs) {
+ u8 error;
+
+ per_cpu(current_vmcs, cpu) = vcpu->vmcs;
+ asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0"
+ : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
+ : "cc");
+ if (error)
+ printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n",
+ vcpu->vmcs, phys_addr);
+ }
+
+ if (vcpu->cpu != cpu) {
+ struct descriptor_table dt;
+ unsigned long sysenter_esp;
+
+ vcpu->cpu = cpu;
+ /*
+ * Linux uses per-cpu TSS and GDT, so set these when switching
+ * processors.
+ */
+ vmcs_writel(HOST_TR_BASE, read_tr_base()); /* 22.2.4 */
+ get_gdt(&dt);
+ vmcs_writel(HOST_GDTR_BASE, dt.base); /* 22.2.4 */
+
+ rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
+ vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
+ }
+ return vcpu;
+}
+
+static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
+{
+ put_cpu();
+}
+
+static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
+{
+ return vmcs_readl(GUEST_RFLAGS);
+}
+
+static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
+{
+ vmcs_writel(GUEST_RFLAGS, rflags);
+}
+
+static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
+{
+ unsigned long rip;
+ u32 interruptibility;
+
+ rip = vmcs_readl(GUEST_RIP);
+ rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+ vmcs_writel(GUEST_RIP, rip);
+
+ /*
+ * We emulated an instruction, so temporary interrupt blocking
+ * should be removed, if set.
+ */
+ interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
+ if (interruptibility & 3)
+ vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
+ interruptibility & ~3);
+ vcpu->interrupt_window_open = 1;
+}
+
+static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
+{
+ printk(KERN_DEBUG "inject_general_protection: rip 0x%lx\n",
+ vmcs_readl(GUEST_RIP));
+ vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+ GP_VECTOR |
+ INTR_TYPE_EXCEPTION |
+ INTR_INFO_DELIEVER_CODE_MASK |
+ INTR_INFO_VALID_MASK);
+}
+
+/*
+ * reads and returns guest's timestamp counter "register"
+ * guest_tsc = host_tsc + tsc_offset -- 21.3
+ */
+static u64 guest_read_tsc(void)
+{
+ u64 host_tsc, tsc_offset;
+
+ rdtscll(host_tsc);
+ tsc_offset = vmcs_read64(TSC_OFFSET);
+ return host_tsc + tsc_offset;
+}
+
+/*
+ * writes 'guest_tsc' into guest's timestamp counter "register"
+ * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc
+ */
+static void guest_write_tsc(u64 guest_tsc)
+{
+ u64 host_tsc;
+
+ rdtscll(host_tsc);
+ vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
+}
+
+static void reload_tss(void)
+{
+#ifndef CONFIG_X86_64
+
+ /*
+ * VT restores TR but not its size. Useless.
+ */
+ struct descriptor_table gdt;
+ struct segment_descriptor *descs;
+
+ get_gdt(&gdt);
+ descs = (void *)gdt.base;
+ descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
+ load_TR_desc();
+#endif
+}
+
+/*
+ * Reads an msr value (of 'msr_index') into 'pdata'.
+ * Returns 0 on success, non-0 otherwise.
+ * Assumes vcpu_load() was already called.
+ */
+static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+{
+ u64 data;
+ struct vmx_msr_entry *msr;
+
+ if (!pdata) {
+ printk(KERN_ERR "BUG: get_msr called with NULL pdata\n");
+ return -EINVAL;
+ }
+
+ switch (msr_index) {
+#ifdef CONFIG_X86_64
+ case MSR_FS_BASE:
+ data = vmcs_readl(GUEST_FS_BASE);
+ break;
+ case MSR_GS_BASE:
+ data = vmcs_readl(GUEST_GS_BASE);
+ break;
+ case MSR_EFER:
+ return kvm_get_msr_common(vcpu, msr_index, pdata);
+#endif
+ case MSR_IA32_TIME_STAMP_COUNTER:
+ data = guest_read_tsc();
+ break;
+ case MSR_IA32_SYSENTER_CS:
+ data = vmcs_read32(GUEST_SYSENTER_CS);
+ break;
+ case MSR_IA32_SYSENTER_EIP:
+ data = vmcs_read32(GUEST_SYSENTER_EIP);
+ break;
+ case MSR_IA32_SYSENTER_ESP:
+ data = vmcs_read32(GUEST_SYSENTER_ESP);
+ break;
+ default:
+ msr = find_msr_entry(vcpu, msr_index);
+ if (msr) {
+ data = msr->data;
+ break;
+ }
+ return kvm_get_msr_common(vcpu, msr_index, pdata);
+ }
+
+ *pdata = data;
+ return 0;
+}
+
+/*
+ * Writes msr value into into the appropriate "register".
+ * Returns 0 on success, non-0 otherwise.
+ * Assumes vcpu_load() was already called.
+ */
+static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+{
+ struct vmx_msr_entry *msr;
+ switch (msr_index) {
+#ifdef CONFIG_X86_64
+ case MSR_EFER:
+ return kvm_set_msr_common(vcpu, msr_index, data);
+ case MSR_FS_BASE:
+ vmcs_writel(GUEST_FS_BASE, data);
+ break;
+ case MSR_GS_BASE:
+ vmcs_writel(GUEST_GS_BASE, data);
+ break;
+#endif
+ case MSR_IA32_SYSENTER_CS:
+ vmcs_write32(GUEST_SYSENTER_CS, data);
+ break;
+ case MSR_IA32_SYSENTER_EIP:
+ vmcs_write32(GUEST_SYSENTER_EIP, data);
+ break;
+ case MSR_IA32_SYSENTER_ESP:
+ vmcs_write32(GUEST_SYSENTER_ESP, data);
+ break;
+ case MSR_IA32_TIME_STAMP_COUNTER: {
+ guest_write_tsc(data);
+ break;
+ }
+ default:
+ msr = find_msr_entry(vcpu, msr_index);
+ if (msr) {
+ msr->data = data;
+ break;
+ }
+ return kvm_set_msr_common(vcpu, msr_index, data);
+ msr->data = data;
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Sync the rsp and rip registers into the vcpu structure. This allows
+ * registers to be accessed by indexing vcpu->regs.
+ */
+static void vcpu_load_rsp_rip(struct kvm_vcpu *vcpu)
+{
+ vcpu->regs[VCPU_REGS_RSP] = vmcs_readl(GUEST_RSP);
+ vcpu->rip = vmcs_readl(GUEST_RIP);
+}
+
+/*
+ * Syncs rsp and rip back into the vmcs. Should be called after possible
+ * modification.
+ */
+static void vcpu_put_rsp_rip(struct kvm_vcpu *vcpu)
+{
+ vmcs_writel(GUEST_RSP, vcpu->regs[VCPU_REGS_RSP]);
+ vmcs_writel(GUEST_RIP, vcpu->rip);
+}
+
+static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
+{
+ unsigned long dr7 = 0x400;
+ u32 exception_bitmap;
+ int old_singlestep;
+
+ exception_bitmap = vmcs_read32(EXCEPTION_BITMAP);
+ old_singlestep = vcpu->guest_debug.singlestep;
+
+ vcpu->guest_debug.enabled = dbg->enabled;
+ if (vcpu->guest_debug.enabled) {
+ int i;
+
+ dr7 |= 0x200; /* exact */
+ for (i = 0; i < 4; ++i) {
+ if (!dbg->breakpoints[i].enabled)
+ continue;
+ vcpu->guest_debug.bp[i] = dbg->breakpoints[i].address;
+ dr7 |= 2 << (i*2); /* global enable */
+ dr7 |= 0 << (i*4+16); /* execution breakpoint */
+ }
+
+ exception_bitmap |= (1u << 1); /* Trap debug exceptions */
+
+ vcpu->guest_debug.singlestep = dbg->singlestep;
+ } else {
+ exception_bitmap &= ~(1u << 1); /* Ignore debug exceptions */
+ vcpu->guest_debug.singlestep = 0;
+ }
+
+ if (old_singlestep && !vcpu->guest_debug.singlestep) {
+ unsigned long flags;
+
+ flags = vmcs_readl(GUEST_RFLAGS);
+ flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
+ vmcs_writel(GUEST_RFLAGS, flags);
+ }
+
+ vmcs_write32(EXCEPTION_BITMAP, exception_bitmap);
+ vmcs_writel(GUEST_DR7, dr7);
+
+ return 0;
+}
+
+static __init int cpu_has_kvm_support(void)
+{
+ unsigned long ecx = cpuid_ecx(1);
+ return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */
+}
+
+static __init int vmx_disabled_by_bios(void)
+{
+ u64 msr;
+
+ rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
+ return (msr & 5) == 1; /* locked but not enabled */
+}
+
+static __init void hardware_enable(void *garbage)
+{
+ int cpu = raw_smp_processor_id();
+ u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
+ u64 old;
+
+ rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
+ if ((old & 5) != 5)
+ /* enable and lock */
+ wrmsrl(MSR_IA32_FEATURE_CONTROL, old | 5);
+ write_cr4(read_cr4() | CR4_VMXE); /* FIXME: not cpu hotplug safe */
+ asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr)
+ : "memory", "cc");
+}
+
+static void hardware_disable(void *garbage)
+{
+ asm volatile (ASM_VMX_VMXOFF : : : "cc");
+}
+
+static __init void setup_vmcs_descriptor(void)
+{
+ u32 vmx_msr_low, vmx_msr_high;
+
+ rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high);
+ vmcs_descriptor.size = vmx_msr_high & 0x1fff;
+ vmcs_descriptor.order = get_order(vmcs_descriptor.size);
+ vmcs_descriptor.revision_id = vmx_msr_low;
+}
+
+static struct vmcs *alloc_vmcs_cpu(int cpu)
+{
+ int node = cpu_to_node(cpu);
+ struct page *pages;
+ struct vmcs *vmcs;
+
+ pages = alloc_pages_node(node, GFP_KERNEL, vmcs_descriptor.order);
+ if (!pages)
+ return NULL;
+ vmcs = page_address(pages);
+ memset(vmcs, 0, vmcs_descriptor.size);
+ vmcs->revision_id = vmcs_descriptor.revision_id; /* vmcs revision id */
+ return vmcs;
+}
+
+static struct vmcs *alloc_vmcs(void)
+{
+ return alloc_vmcs_cpu(raw_smp_processor_id());
+}
+
+static void free_vmcs(struct vmcs *vmcs)
+{
+ free_pages((unsigned long)vmcs, vmcs_descriptor.order);
+}
+
+static __exit void free_kvm_area(void)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ free_vmcs(per_cpu(vmxarea, cpu));
+}
+
+extern struct vmcs *alloc_vmcs_cpu(int cpu);
+
+static __init int alloc_kvm_area(void)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu) {
+ struct vmcs *vmcs;
+
+ vmcs = alloc_vmcs_cpu(cpu);
+ if (!vmcs) {
+ free_kvm_area();
+ return -ENOMEM;
+ }
+
+ per_cpu(vmxarea, cpu) = vmcs;
+ }
+ return 0;
+}
+
+static __init int hardware_setup(void)
+{
+ setup_vmcs_descriptor();
+ return alloc_kvm_area();
+}
+
+static __exit void hardware_unsetup(void)
+{
+ free_kvm_area();
+}
+
+static void update_exception_bitmap(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->rmode.active)
+ vmcs_write32(EXCEPTION_BITMAP, ~0);
+ else
+ vmcs_write32(EXCEPTION_BITMAP, 1 << PF_VECTOR);
+}
+
+static void fix_pmode_dataseg(int seg, struct kvm_save_segment *save)
+{
+ struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+
+ if (vmcs_readl(sf->base) == save->base) {
+ vmcs_write16(sf->selector, save->selector);
+ vmcs_writel(sf->base, save->base);
+ vmcs_write32(sf->limit, save->limit);
+ vmcs_write32(sf->ar_bytes, save->ar);
+ } else {
+ u32 dpl = (vmcs_read16(sf->selector) & SELECTOR_RPL_MASK)
+ << AR_DPL_SHIFT;
+ vmcs_write32(sf->ar_bytes, 0x93 | dpl);
+ }
+}
+
+static void enter_pmode(struct kvm_vcpu *vcpu)
+{
+ unsigned long flags;
+
+ vcpu->rmode.active = 0;
+
+ vmcs_writel(GUEST_TR_BASE, vcpu->rmode.tr.base);
+ vmcs_write32(GUEST_TR_LIMIT, vcpu->rmode.tr.limit);
+ vmcs_write32(GUEST_TR_AR_BYTES, vcpu->rmode.tr.ar);
+
+ flags = vmcs_readl(GUEST_RFLAGS);
+ flags &= ~(IOPL_MASK | X86_EFLAGS_VM);
+ flags |= (vcpu->rmode.save_iopl << IOPL_SHIFT);
+ vmcs_writel(GUEST_RFLAGS, flags);
+
+ vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~CR4_VME_MASK) |
+ (vmcs_readl(CR4_READ_SHADOW) & CR4_VME_MASK));
+
+ update_exception_bitmap(vcpu);
+
+ fix_pmode_dataseg(VCPU_SREG_ES, &vcpu->rmode.es);
+ fix_pmode_dataseg(VCPU_SREG_DS, &vcpu->rmode.ds);
+ fix_pmode_dataseg(VCPU_SREG_GS, &vcpu->rmode.gs);
+ fix_pmode_dataseg(VCPU_SREG_FS, &vcpu->rmode.fs);
+
+ vmcs_write16(GUEST_SS_SELECTOR, 0);
+ vmcs_write32(GUEST_SS_AR_BYTES, 0x93);
+
+ vmcs_write16(GUEST_CS_SELECTOR,
+ vmcs_read16(GUEST_CS_SELECTOR) & ~SELECTOR_RPL_MASK);
+ vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
+}
+
+static int rmode_tss_base(struct kvm* kvm)
+{
+ gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3;
+ return base_gfn << PAGE_SHIFT;
+}
+
+static void fix_rmode_seg(int seg, struct kvm_save_segment *save)
+{
+ struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+
+ save->selector = vmcs_read16(sf->selector);
+ save->base = vmcs_readl(sf->base);
+ save->limit = vmcs_read32(sf->limit);
+ save->ar = vmcs_read32(sf->ar_bytes);
+ vmcs_write16(sf->selector, vmcs_readl(sf->base) >> 4);
+ vmcs_write32(sf->limit, 0xffff);
+ vmcs_write32(sf->ar_bytes, 0xf3);
+}
+
+static void enter_rmode(struct kvm_vcpu *vcpu)
+{
+ unsigned long flags;
+
+ vcpu->rmode.active = 1;
+
+ vcpu->rmode.tr.base = vmcs_readl(GUEST_TR_BASE);
+ vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm));
+
+ vcpu->rmode.tr.limit = vmcs_read32(GUEST_TR_LIMIT);
+ vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1);
+
+ vcpu->rmode.tr.ar = vmcs_read32(GUEST_TR_AR_BYTES);
+ vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
+
+ flags = vmcs_readl(GUEST_RFLAGS);
+ vcpu->rmode.save_iopl = (flags & IOPL_MASK) >> IOPL_SHIFT;
+
+ flags |= IOPL_MASK | X86_EFLAGS_VM;
+
+ vmcs_writel(GUEST_RFLAGS, flags);
+ vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | CR4_VME_MASK);
+ update_exception_bitmap(vcpu);
+
+ vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4);
+ vmcs_write32(GUEST_SS_LIMIT, 0xffff);
+ vmcs_write32(GUEST_SS_AR_BYTES, 0xf3);
+
+ vmcs_write32(GUEST_CS_AR_BYTES, 0xf3);
+ vmcs_write32(GUEST_CS_LIMIT, 0xffff);
+ vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4);
+
+ fix_rmode_seg(VCPU_SREG_ES, &vcpu->rmode.es);
+ fix_rmode_seg(VCPU_SREG_DS, &vcpu->rmode.ds);
+ fix_rmode_seg(VCPU_SREG_GS, &vcpu->rmode.gs);
+ fix_rmode_seg(VCPU_SREG_FS, &vcpu->rmode.fs);
+}
+
+#ifdef CONFIG_X86_64
+
+static void enter_lmode(struct kvm_vcpu *vcpu)
+{
+ u32 guest_tr_ar;
+
+ guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES);
+ if ((guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) {
+ printk(KERN_DEBUG "%s: tss fixup for long mode. \n",
+ __FUNCTION__);
+ vmcs_write32(GUEST_TR_AR_BYTES,
+ (guest_tr_ar & ~AR_TYPE_MASK)
+ | AR_TYPE_BUSY_64_TSS);
+ }
+
+ vcpu->shadow_efer |= EFER_LMA;
+
+ find_msr_entry(vcpu, MSR_EFER)->data |= EFER_LMA | EFER_LME;
+ vmcs_write32(VM_ENTRY_CONTROLS,
+ vmcs_read32(VM_ENTRY_CONTROLS)
+ | VM_ENTRY_CONTROLS_IA32E_MASK);
+}
+
+static void exit_lmode(struct kvm_vcpu *vcpu)
+{
+ vcpu->shadow_efer &= ~EFER_LMA;
+
+ vmcs_write32(VM_ENTRY_CONTROLS,
+ vmcs_read32(VM_ENTRY_CONTROLS)
+ & ~VM_ENTRY_CONTROLS_IA32E_MASK);
+}
+
+#endif
+
+static void vmx_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu)
+{
+ vcpu->cr0 &= KVM_GUEST_CR0_MASK;
+ vcpu->cr0 |= vmcs_readl(GUEST_CR0) & ~KVM_GUEST_CR0_MASK;
+
+ vcpu->cr4 &= KVM_GUEST_CR4_MASK;
+ vcpu->cr4 |= vmcs_readl(GUEST_CR4) & ~KVM_GUEST_CR4_MASK;
+}
+
+static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+{
+ if (vcpu->rmode.active && (cr0 & CR0_PE_MASK))
+ enter_pmode(vcpu);
+
+ if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK))
+ enter_rmode(vcpu);
+
+#ifdef CONFIG_X86_64
+ if (vcpu->shadow_efer & EFER_LME) {
+ if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK))
+ enter_lmode(vcpu);
+ if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK))
+ exit_lmode(vcpu);
+ }
+#endif
+
+ vmcs_writel(CR0_READ_SHADOW, cr0);
+ vmcs_writel(GUEST_CR0,
+ (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
+ vcpu->cr0 = cr0;
+}
+
+/*
+ * Used when restoring the VM to avoid corrupting segment registers
+ */
+static void vmx_set_cr0_no_modeswitch(struct kvm_vcpu *vcpu, unsigned long cr0)
+{
+ vcpu->rmode.active = ((cr0 & CR0_PE_MASK) == 0);
+ update_exception_bitmap(vcpu);
+ vmcs_writel(CR0_READ_SHADOW, cr0);
+ vmcs_writel(GUEST_CR0,
+ (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
+ vcpu->cr0 = cr0;
+}
+
+static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
+{
+ vmcs_writel(GUEST_CR3, cr3);
+}
+
+static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+{
+ vmcs_writel(CR4_READ_SHADOW, cr4);
+ vmcs_writel(GUEST_CR4, cr4 | (vcpu->rmode.active ?
+ KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON));
+ vcpu->cr4 = cr4;
+}
+
+#ifdef CONFIG_X86_64
+
+static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
+{
+ struct vmx_msr_entry *msr = find_msr_entry(vcpu, MSR_EFER);
+
+ vcpu->shadow_efer = efer;
+ if (efer & EFER_LMA) {
+ vmcs_write32(VM_ENTRY_CONTROLS,
+ vmcs_read32(VM_ENTRY_CONTROLS) |
+ VM_ENTRY_CONTROLS_IA32E_MASK);
+ msr->data = efer;
+
+ } else {
+ vmcs_write32(VM_ENTRY_CONTROLS,
+ vmcs_read32(VM_ENTRY_CONTROLS) &
+ ~VM_ENTRY_CONTROLS_IA32E_MASK);
+
+ msr->data = efer & ~EFER_LME;
+ }
+}
+
+#endif
+
+static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
+{
+ struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+
+ return vmcs_readl(sf->base);
+}
+
+static void vmx_get_segment(struct kvm_vcpu *vcpu,
+ struct kvm_segment *var, int seg)
+{
+ struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+ u32 ar;
+
+ var->base = vmcs_readl(sf->base);
+ var->limit = vmcs_read32(sf->limit);
+ var->selector = vmcs_read16(sf->selector);
+ ar = vmcs_read32(sf->ar_bytes);
+ if (ar & AR_UNUSABLE_MASK)
+ ar = 0;
+ var->type = ar & 15;
+ var->s = (ar >> 4) & 1;
+ var->dpl = (ar >> 5) & 3;
+ var->present = (ar >> 7) & 1;
+ var->avl = (ar >> 12) & 1;
+ var->l = (ar >> 13) & 1;
+ var->db = (ar >> 14) & 1;
+ var->g = (ar >> 15) & 1;
+ var->unusable = (ar >> 16) & 1;
+}
+
+static void vmx_set_segment(struct kvm_vcpu *vcpu,
+ struct kvm_segment *var, int seg)
+{
+ struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+ u32 ar;
+
+ vmcs_writel(sf->base, var->base);
+ vmcs_write32(sf->limit, var->limit);
+ vmcs_write16(sf->selector, var->selector);
+ if (var->unusable)
+ ar = 1 << 16;
+ else {
+ ar = var->type & 15;
+ ar |= (var->s & 1) << 4;
+ ar |= (var->dpl & 3) << 5;
+ ar |= (var->present & 1) << 7;
+ ar |= (var->avl & 1) << 12;
+ ar |= (var->l & 1) << 13;
+ ar |= (var->db & 1) << 14;
+ ar |= (var->g & 1) << 15;
+ }
+ if (ar == 0) /* a 0 value means unusable */
+ ar = AR_UNUSABLE_MASK;
+ vmcs_write32(sf->ar_bytes, ar);
+}
+
+static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
+{
+ u32 ar = vmcs_read32(GUEST_CS_AR_BYTES);
+
+ *db = (ar >> 14) & 1;
+ *l = (ar >> 13) & 1;
+}
+
+static void vmx_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+ dt->limit = vmcs_read32(GUEST_IDTR_LIMIT);
+ dt->base = vmcs_readl(GUEST_IDTR_BASE);
+}
+
+static void vmx_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+ vmcs_write32(GUEST_IDTR_LIMIT, dt->limit);
+ vmcs_writel(GUEST_IDTR_BASE, dt->base);
+}
+
+static void vmx_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+ dt->limit = vmcs_read32(GUEST_GDTR_LIMIT);
+ dt->base = vmcs_readl(GUEST_GDTR_BASE);
+}
+
+static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+ vmcs_write32(GUEST_GDTR_LIMIT, dt->limit);
+ vmcs_writel(GUEST_GDTR_BASE, dt->base);
+}
+
+static int init_rmode_tss(struct kvm* kvm)
+{
+ struct page *p1, *p2, *p3;
+ gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT;
+ char *page;
+
+ p1 = _gfn_to_page(kvm, fn++);
+ p2 = _gfn_to_page(kvm, fn++);
+ p3 = _gfn_to_page(kvm, fn);
+
+ if (!p1 || !p2 || !p3) {
+ kvm_printf(kvm,"%s: gfn_to_page failed\n", __FUNCTION__);
+ return 0;
+ }
+
+ page = kmap_atomic(p1, KM_USER0);
+ memset(page, 0, PAGE_SIZE);
+ *(u16*)(page + 0x66) = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE;
+ kunmap_atomic(page, KM_USER0);
+
+ page = kmap_atomic(p2, KM_USER0);
+ memset(page, 0, PAGE_SIZE);
+ kunmap_atomic(page, KM_USER0);
+
+ page = kmap_atomic(p3, KM_USER0);
+ memset(page, 0, PAGE_SIZE);
+ *(page + RMODE_TSS_SIZE - 2 * PAGE_SIZE - 1) = ~0;
+ kunmap_atomic(page, KM_USER0);
+
+ return 1;
+}
+
+static void vmcs_write32_fixedbits(u32 msr, u32 vmcs_field, u32 val)
+{
+ u32 msr_high, msr_low;
+
+ rdmsr(msr, msr_low, msr_high);
+
+ val &= msr_high;
+ val |= msr_low;
+ vmcs_write32(vmcs_field, val);
+}
+
+static void seg_setup(int seg)
+{
+ struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+
+ vmcs_write16(sf->selector, 0);
+ vmcs_writel(sf->base, 0);
+ vmcs_write32(sf->limit, 0xffff);
+ vmcs_write32(sf->ar_bytes, 0x93);
+}
+
+/*
+ * Sets up the vmcs for emulated real mode.
+ */
+static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+ u32 host_sysenter_cs;
+ u32 junk;
+ unsigned long a;
+ struct descriptor_table dt;
+ int i;
+ int ret = 0;
+ int nr_good_msrs;
+ extern asmlinkage void kvm_vmx_return(void);
+
+ if (!init_rmode_tss(vcpu->kvm)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(vcpu->regs, 0, sizeof(vcpu->regs));
+ vcpu->regs[VCPU_REGS_RDX] = get_rdx_init_val();
+ vcpu->cr8 = 0;
+ vcpu->apic_base = 0xfee00000 |
+ /*for vcpu 0*/ MSR_IA32_APICBASE_BSP |
+ MSR_IA32_APICBASE_ENABLE;
+
+ fx_init(vcpu);
+
+ /*
+ * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode
+ * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4. Sigh.
+ */
+ vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
+ vmcs_writel(GUEST_CS_BASE, 0x000f0000);
+ vmcs_write32(GUEST_CS_LIMIT, 0xffff);
+ vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
+
+ seg_setup(VCPU_SREG_DS);
+ seg_setup(VCPU_SREG_ES);
+ seg_setup(VCPU_SREG_FS);
+ seg_setup(VCPU_SREG_GS);
+ seg_setup(VCPU_SREG_SS);
+
+ vmcs_write16(GUEST_TR_SELECTOR, 0);
+ vmcs_writel(GUEST_TR_BASE, 0);
+ vmcs_write32(GUEST_TR_LIMIT, 0xffff);
+ vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
+
+ vmcs_write16(GUEST_LDTR_SELECTOR, 0);
+ vmcs_writel(GUEST_LDTR_BASE, 0);
+ vmcs_write32(GUEST_LDTR_LIMIT, 0xffff);
+ vmcs_write32(GUEST_LDTR_AR_BYTES, 0x00082);
+
+ vmcs_write32(GUEST_SYSENTER_CS, 0);
+ vmcs_writel(GUEST_SYSENTER_ESP, 0);
+ vmcs_writel(GUEST_SYSENTER_EIP, 0);
+
+ vmcs_writel(GUEST_RFLAGS, 0x02);
+ vmcs_writel(GUEST_RIP, 0xfff0);
+ vmcs_writel(GUEST_RSP, 0);
+
+ //todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0
+ vmcs_writel(GUEST_DR7, 0x400);
+
+ vmcs_writel(GUEST_GDTR_BASE, 0);
+ vmcs_write32(GUEST_GDTR_LIMIT, 0xffff);
+
+ vmcs_writel(GUEST_IDTR_BASE, 0);
+ vmcs_write32(GUEST_IDTR_LIMIT, 0xffff);
+
+ vmcs_write32(GUEST_ACTIVITY_STATE, 0);
+ vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
+ vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
+
+ /* I/O */
+ vmcs_write64(IO_BITMAP_A, 0);
+ vmcs_write64(IO_BITMAP_B, 0);
+
+ guest_write_tsc(0);
+
+ vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
+
+ /* Special registers */
+ vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
+
+ /* Control */
+ vmcs_write32_fixedbits(MSR_IA32_VMX_PINBASED_CTLS,
+ PIN_BASED_VM_EXEC_CONTROL,
+ PIN_BASED_EXT_INTR_MASK /* 20.6.1 */
+ | PIN_BASED_NMI_EXITING /* 20.6.1 */
+ );
+ vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS,
+ CPU_BASED_VM_EXEC_CONTROL,
+ CPU_BASED_HLT_EXITING /* 20.6.2 */
+ | CPU_BASED_CR8_LOAD_EXITING /* 20.6.2 */
+ | CPU_BASED_CR8_STORE_EXITING /* 20.6.2 */
+ | CPU_BASED_UNCOND_IO_EXITING /* 20.6.2 */
+ | CPU_BASED_MOV_DR_EXITING
+ | CPU_BASED_USE_TSC_OFFSETING /* 21.3 */
+ );
+
+ vmcs_write32(EXCEPTION_BITMAP, 1 << PF_VECTOR);
+ vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
+ vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0);
+ vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */
+
+ vmcs_writel(HOST_CR0, read_cr0()); /* 22.2.3 */
+ vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */
+ vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */
+
+ vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */
+ vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */
+ vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */
+ vmcs_write16(HOST_FS_SELECTOR, read_fs()); /* 22.2.4 */
+ vmcs_write16(HOST_GS_SELECTOR, read_gs()); /* 22.2.4 */
+ vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */
+#ifdef CONFIG_X86_64
+ rdmsrl(MSR_FS_BASE, a);
+ vmcs_writel(HOST_FS_BASE, a); /* 22.2.4 */
+ rdmsrl(MSR_GS_BASE, a);
+ vmcs_writel(HOST_GS_BASE, a); /* 22.2.4 */
+#else
+ vmcs_writel(HOST_FS_BASE, 0); /* 22.2.4 */
+ vmcs_writel(HOST_GS_BASE, 0); /* 22.2.4 */
+#endif
+
+ vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8); /* 22.2.4 */
+
+ get_idt(&dt);
+ vmcs_writel(HOST_IDTR_BASE, dt.base); /* 22.2.4 */
+
+
+ vmcs_writel(HOST_RIP, (unsigned long)kvm_vmx_return); /* 22.2.5 */
+
+ rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk);
+ vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs);
+ rdmsrl(MSR_IA32_SYSENTER_ESP, a);
+ vmcs_writel(HOST_IA32_SYSENTER_ESP, a); /* 22.2.3 */
+ rdmsrl(MSR_IA32_SYSENTER_EIP, a);
+ vmcs_writel(HOST_IA32_SYSENTER_EIP, a); /* 22.2.3 */
+
+ for (i = 0; i < NR_VMX_MSR; ++i) {
+ u32 index = vmx_msr_index[i];
+ u32 data_low, data_high;
+ u64 data;
+ int j = vcpu->nmsrs;
+
+ if (rdmsr_safe(index, &data_low, &data_high) < 0)
+ continue;
+ if (wrmsr_safe(index, data_low, data_high) < 0)
+ continue;
+ data = data_low | ((u64)data_high << 32);
+ vcpu->host_msrs[j].index = index;
+ vcpu->host_msrs[j].reserved = 0;
+ vcpu->host_msrs[j].data = data;
+ vcpu->guest_msrs[j] = vcpu->host_msrs[j];
+ ++vcpu->nmsrs;
+ }
+ printk(KERN_DEBUG "kvm: msrs: %d\n", vcpu->nmsrs);
+
+ nr_good_msrs = vcpu->nmsrs - NR_BAD_MSRS;
+ vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR,
+ virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS));
+ vmcs_writel(VM_EXIT_MSR_STORE_ADDR,
+ virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS));
+ vmcs_writel(VM_EXIT_MSR_LOAD_ADDR,
+ virt_to_phys(vcpu->host_msrs + NR_BAD_MSRS));
+ vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS,
+ (HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */
+ vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */
+ vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
+ vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
+
+
+ /* 22.2.1, 20.8.1 */
+ vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS,
+ VM_ENTRY_CONTROLS, 0);
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */
+
+#ifdef CONFIG_X86_64
+ vmcs_writel(VIRTUAL_APIC_PAGE_ADDR, 0);
+ vmcs_writel(TPR_THRESHOLD, 0);
+#endif
+
+ vmcs_writel(CR0_GUEST_HOST_MASK, KVM_GUEST_CR0_MASK);
+ vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
+
+ vcpu->cr0 = 0x60000010;
+ vmx_set_cr0(vcpu, vcpu->cr0); // enter rmode
+ vmx_set_cr4(vcpu, 0);
+#ifdef CONFIG_X86_64
+ vmx_set_efer(vcpu, 0);
+#endif
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
+{
+ u16 ent[2];
+ u16 cs;
+ u16 ip;
+ unsigned long flags;
+ unsigned long ss_base = vmcs_readl(GUEST_SS_BASE);
+ u16 sp = vmcs_readl(GUEST_RSP);
+ u32 ss_limit = vmcs_read32(GUEST_SS_LIMIT);
+
+ if (sp > ss_limit || sp - 6 > sp) {
+ vcpu_printf(vcpu, "%s: #SS, rsp 0x%lx ss 0x%lx limit 0x%x\n",
+ __FUNCTION__,
+ vmcs_readl(GUEST_RSP),
+ vmcs_readl(GUEST_SS_BASE),
+ vmcs_read32(GUEST_SS_LIMIT));
+ return;
+ }
+
+ if (kvm_read_guest(vcpu, irq * sizeof(ent), sizeof(ent), &ent) !=
+ sizeof(ent)) {
+ vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__);
+ return;
+ }
+
+ flags = vmcs_readl(GUEST_RFLAGS);
+ cs = vmcs_readl(GUEST_CS_BASE) >> 4;
+ ip = vmcs_readl(GUEST_RIP);
+
+
+ if (kvm_write_guest(vcpu, ss_base + sp - 2, 2, &flags) != 2 ||
+ kvm_write_guest(vcpu, ss_base + sp - 4, 2, &cs) != 2 ||
+ kvm_write_guest(vcpu, ss_base + sp - 6, 2, &ip) != 2) {
+ vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__);
+ return;
+ }
+
+ vmcs_writel(GUEST_RFLAGS, flags &
+ ~( X86_EFLAGS_IF | X86_EFLAGS_AC | X86_EFLAGS_TF));
+ vmcs_write16(GUEST_CS_SELECTOR, ent[1]) ;
+ vmcs_writel(GUEST_CS_BASE, ent[1] << 4);
+ vmcs_writel(GUEST_RIP, ent[0]);
+ vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6));
+}
+
+static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
+{
+ int word_index = __ffs(vcpu->irq_summary);
+ int bit_index = __ffs(vcpu->irq_pending[word_index]);
+ int irq = word_index * BITS_PER_LONG + bit_index;
+
+ clear_bit(bit_index, &vcpu->irq_pending[word_index]);
+ if (!vcpu->irq_pending[word_index])
+ clear_bit(word_index, &vcpu->irq_summary);
+
+ if (vcpu->rmode.active) {
+ inject_rmode_irq(vcpu, irq);
+ return;
+ }
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+ irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+}
+
+
+static void do_interrupt_requests(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ u32 cpu_based_vm_exec_control;
+
+ vcpu->interrupt_window_open =
+ ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
+ (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
+
+ if (vcpu->interrupt_window_open &&
+ vcpu->irq_summary &&
+ !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK))
+ /*
+ * If interrupts enabled, and not blocked by sti or mov ss. Good.
+ */
+ kvm_do_inject_irq(vcpu);
+
+ cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ if (!vcpu->interrupt_window_open &&
+ (vcpu->irq_summary || kvm_run->request_interrupt_window))
+ /*
+ * Interrupts blocked. Wait for unblock.
+ */
+ cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
+ else
+ cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+}
+
+static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu)
+{
+ struct kvm_guest_debug *dbg = &vcpu->guest_debug;
+
+ set_debugreg(dbg->bp[0], 0);
+ set_debugreg(dbg->bp[1], 1);
+ set_debugreg(dbg->bp[2], 2);
+ set_debugreg(dbg->bp[3], 3);
+
+ if (dbg->singlestep) {
+ unsigned long flags;
+
+ flags = vmcs_readl(GUEST_RFLAGS);
+ flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
+ vmcs_writel(GUEST_RFLAGS, flags);
+ }
+}
+
+static int handle_rmode_exception(struct kvm_vcpu *vcpu,
+ int vec, u32 err_code)
+{
+ if (!vcpu->rmode.active)
+ return 0;
+
+ if (vec == GP_VECTOR && err_code == 0)
+ if (emulate_instruction(vcpu, NULL, 0, 0) == EMULATE_DONE)
+ return 1;
+ return 0;
+}
+
+static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u32 intr_info, error_code;
+ unsigned long cr2, rip;
+ u32 vect_info;
+ enum emulation_result er;
+ int r;
+
+ vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+ intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+
+ if ((vect_info & VECTORING_INFO_VALID_MASK) &&
+ !is_page_fault(intr_info)) {
+ printk(KERN_ERR "%s: unexpected, vectoring info 0x%x "
+ "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info);
+ }
+
+ if (is_external_interrupt(vect_info)) {
+ int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
+ set_bit(irq, vcpu->irq_pending);
+ set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
+ }
+
+ if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */
+ asm ("int $2");
+ return 1;
+ }
+ error_code = 0;
+ rip = vmcs_readl(GUEST_RIP);
+ if (intr_info & INTR_INFO_DELIEVER_CODE_MASK)
+ error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
+ if (is_page_fault(intr_info)) {
+ cr2 = vmcs_readl(EXIT_QUALIFICATION);
+
+ spin_lock(&vcpu->kvm->lock);
+ r = kvm_mmu_page_fault(vcpu, cr2, error_code);
+ if (r < 0) {
+ spin_unlock(&vcpu->kvm->lock);
+ return r;
+ }
+ if (!r) {
+ spin_unlock(&vcpu->kvm->lock);
+ return 1;
+ }
+
+ er = emulate_instruction(vcpu, kvm_run, cr2, error_code);
+ spin_unlock(&vcpu->kvm->lock);
+
+ switch (er) {
+ case EMULATE_DONE:
+ return 1;
+ case EMULATE_DO_MMIO:
+ ++kvm_stat.mmio_exits;
+ kvm_run->exit_reason = KVM_EXIT_MMIO;
+ return 0;
+ case EMULATE_FAIL:
+ vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
+ break;
+ default:
+ BUG();
+ }
+ }
+
+ if (vcpu->rmode.active &&
+ handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK,
+ error_code))
+ return 1;
+
+ if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) == (INTR_TYPE_EXCEPTION | 1)) {
+ kvm_run->exit_reason = KVM_EXIT_DEBUG;
+ return 0;
+ }
+ kvm_run->exit_reason = KVM_EXIT_EXCEPTION;
+ kvm_run->ex.exception = intr_info & INTR_INFO_VECTOR_MASK;
+ kvm_run->ex.error_code = error_code;
+ return 0;
+}
+
+static int handle_external_interrupt(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ ++kvm_stat.irq_exits;
+ return 1;
+}
+
+
+static int get_io_count(struct kvm_vcpu *vcpu, u64 *count)
+{
+ u64 inst;
+ gva_t rip;
+ int countr_size;
+ int i, n;
+
+ if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_VM)) {
+ countr_size = 2;
+ } else {
+ u32 cs_ar = vmcs_read32(GUEST_CS_AR_BYTES);
+
+ countr_size = (cs_ar & AR_L_MASK) ? 8:
+ (cs_ar & AR_DB_MASK) ? 4: 2;
+ }
+
+ rip = vmcs_readl(GUEST_RIP);
+ if (countr_size != 8)
+ rip += vmcs_readl(GUEST_CS_BASE);
+
+ n = kvm_read_guest(vcpu, rip, sizeof(inst), &inst);
+
+ for (i = 0; i < n; i++) {
+ switch (((u8*)&inst)[i]) {
+ case 0xf0:
+ case 0xf2:
+ case 0xf3:
+ case 0x2e:
+ case 0x36:
+ case 0x3e:
+ case 0x26:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ break;
+ case 0x67:
+ countr_size = (countr_size == 2) ? 4: (countr_size >> 1);
+ default:
+ goto done;
+ }
+ }
+ return 0;
+done:
+ countr_size *= 8;
+ *count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size));
+ return 1;
+}
+
+static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u64 exit_qualification;
+
+ ++kvm_stat.io_exits;
+ exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+ kvm_run->exit_reason = KVM_EXIT_IO;
+ if (exit_qualification & 8)
+ kvm_run->io.direction = KVM_EXIT_IO_IN;
+ else
+ kvm_run->io.direction = KVM_EXIT_IO_OUT;
+ kvm_run->io.size = (exit_qualification & 7) + 1;
+ kvm_run->io.string = (exit_qualification & 16) != 0;
+ kvm_run->io.string_down
+ = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0;
+ kvm_run->io.rep = (exit_qualification & 32) != 0;
+ kvm_run->io.port = exit_qualification >> 16;
+ if (kvm_run->io.string) {
+ if (!get_io_count(vcpu, &kvm_run->io.count))
+ return 1;
+ kvm_run->io.address = vmcs_readl(GUEST_LINEAR_ADDRESS);
+ } else
+ kvm_run->io.value = vcpu->regs[VCPU_REGS_RAX]; /* rax */
+ return 0;
+}
+
+static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u64 exit_qualification;
+ int cr;
+ int reg;
+
+ exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+ cr = exit_qualification & 15;
+ reg = (exit_qualification >> 8) & 15;
+ switch ((exit_qualification >> 4) & 3) {
+ case 0: /* mov to cr */
+ switch (cr) {
+ case 0:
+ vcpu_load_rsp_rip(vcpu);
+ set_cr0(vcpu, vcpu->regs[reg]);
+ skip_emulated_instruction(vcpu);
+ return 1;
+ case 3:
+ vcpu_load_rsp_rip(vcpu);
+ set_cr3(vcpu, vcpu->regs[reg]);
+ skip_emulated_instruction(vcpu);
+ return 1;
+ case 4:
+ vcpu_load_rsp_rip(vcpu);
+ set_cr4(vcpu, vcpu->regs[reg]);
+ skip_emulated_instruction(vcpu);
+ return 1;
+ case 8:
+ vcpu_load_rsp_rip(vcpu);
+ set_cr8(vcpu, vcpu->regs[reg]);
+ skip_emulated_instruction(vcpu);
+ return 1;
+ };
+ break;
+ case 1: /*mov from cr*/
+ switch (cr) {
+ case 3:
+ vcpu_load_rsp_rip(vcpu);
+ vcpu->regs[reg] = vcpu->cr3;
+ vcpu_put_rsp_rip(vcpu);
+ skip_emulated_instruction(vcpu);
+ return 1;
+ case 8:
+ printk(KERN_DEBUG "handle_cr: read CR8 "
+ "cpu erratum AA15\n");
+ vcpu_load_rsp_rip(vcpu);
+ vcpu->regs[reg] = vcpu->cr8;
+ vcpu_put_rsp_rip(vcpu);
+ skip_emulated_instruction(vcpu);
+ return 1;
+ }
+ break;
+ case 3: /* lmsw */
+ lmsw(vcpu, (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f);
+
+ skip_emulated_instruction(vcpu);
+ return 1;
+ default:
+ break;
+ }
+ kvm_run->exit_reason = 0;
+ printk(KERN_ERR "kvm: unhandled control register: op %d cr %d\n",
+ (int)(exit_qualification >> 4) & 3, cr);
+ return 0;
+}
+
+static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u64 exit_qualification;
+ unsigned long val;
+ int dr, reg;
+
+ /*
+ * FIXME: this code assumes the host is debugging the guest.
+ * need to deal with guest debugging itself too.
+ */
+ exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+ dr = exit_qualification & 7;
+ reg = (exit_qualification >> 8) & 15;
+ vcpu_load_rsp_rip(vcpu);
+ if (exit_qualification & 16) {
+ /* mov from dr */
+ switch (dr) {
+ case 6:
+ val = 0xffff0ff0;
+ break;
+ case 7:
+ val = 0x400;
+ break;
+ default:
+ val = 0;
+ }
+ vcpu->regs[reg] = val;
+ } else {
+ /* mov to dr */
+ }
+ vcpu_put_rsp_rip(vcpu);
+ skip_emulated_instruction(vcpu);
+ return 1;
+}
+
+static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ kvm_run->exit_reason = KVM_EXIT_CPUID;
+ return 0;
+}
+
+static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u32 ecx = vcpu->regs[VCPU_REGS_RCX];
+ u64 data;
+
+ if (vmx_get_msr(vcpu, ecx, &data)) {
+ vmx_inject_gp(vcpu, 0);
+ return 1;
+ }
+
+ /* FIXME: handling of bits 32:63 of rax, rdx */
+ vcpu->regs[VCPU_REGS_RAX] = data & -1u;
+ vcpu->regs[VCPU_REGS_RDX] = (data >> 32) & -1u;
+ skip_emulated_instruction(vcpu);
+ return 1;
+}
+
+static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u32 ecx = vcpu->regs[VCPU_REGS_RCX];
+ u64 data = (vcpu->regs[VCPU_REGS_RAX] & -1u)
+ | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32);
+
+ if (vmx_set_msr(vcpu, ecx, data) != 0) {
+ vmx_inject_gp(vcpu, 0);
+ return 1;
+ }
+
+ skip_emulated_instruction(vcpu);
+ return 1;
+}
+
+static void post_kvm_run_save(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0;
+ kvm_run->cr8 = vcpu->cr8;
+ kvm_run->apic_base = vcpu->apic_base;
+ kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
+ vcpu->irq_summary == 0);
+}
+
+static int handle_interrupt_window(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ /*
+ * If the user space waits to inject interrupts, exit as soon as
+ * possible
+ */
+ if (kvm_run->request_interrupt_window &&
+ !vcpu->irq_summary) {
+ kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
+ ++kvm_stat.irq_window_exits;
+ return 0;
+ }
+ return 1;
+}
+
+static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ skip_emulated_instruction(vcpu);
+ if (vcpu->irq_summary)
+ return 1;
+
+ kvm_run->exit_reason = KVM_EXIT_HLT;
+ ++kvm_stat.halt_exits;
+ return 0;
+}
+
+/*
+ * The exit handlers return 1 if the exit was handled fully and guest execution
+ * may resume. Otherwise they set the kvm_run parameter to indicate what needs
+ * to be done to userspace and return 0.
+ */
+static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run) = {
+ [EXIT_REASON_EXCEPTION_NMI] = handle_exception,
+ [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt,
+ [EXIT_REASON_IO_INSTRUCTION] = handle_io,
+ [EXIT_REASON_CR_ACCESS] = handle_cr,
+ [EXIT_REASON_DR_ACCESS] = handle_dr,
+ [EXIT_REASON_CPUID] = handle_cpuid,
+ [EXIT_REASON_MSR_READ] = handle_rdmsr,
+ [EXIT_REASON_MSR_WRITE] = handle_wrmsr,
+ [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window,
+ [EXIT_REASON_HLT] = handle_halt,
+};
+
+static const int kvm_vmx_max_exit_handlers =
+ sizeof(kvm_vmx_exit_handlers) / sizeof(*kvm_vmx_exit_handlers);
+
+/*
+ * The guest has exited. See if we can fix it or if we need userspace
+ * assistance.
+ */
+static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
+{
+ u32 vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+ u32 exit_reason = vmcs_read32(VM_EXIT_REASON);
+
+ if ( (vectoring_info & VECTORING_INFO_VALID_MASK) &&
+ exit_reason != EXIT_REASON_EXCEPTION_NMI )
+ printk(KERN_WARNING "%s: unexpected, valid vectoring info and "
+ "exit reason is 0x%x\n", __FUNCTION__, exit_reason);
+ kvm_run->instruction_length = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+ if (exit_reason < kvm_vmx_max_exit_handlers
+ && kvm_vmx_exit_handlers[exit_reason])
+ return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run);
+ else {
+ kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+ kvm_run->hw.hardware_exit_reason = exit_reason;
+ }
+ return 0;
+}
+
+/*
+ * Check if userspace requested an interrupt window, and that the
+ * interrupt window is open.
+ *
+ * No need to exit to userspace if we already have an interrupt queued.
+ */
+static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ return (!vcpu->irq_summary &&
+ kvm_run->request_interrupt_window &&
+ vcpu->interrupt_window_open &&
+ (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF));
+}
+
+static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ u8 fail;
+ u16 fs_sel, gs_sel, ldt_sel;
+ int fs_gs_ldt_reload_needed;
+ int r;
+
+again:
+ /*
+ * Set host fs and gs selectors. Unfortunately, 22.2.3 does not
+ * allow segment selectors with cpl > 0 or ti == 1.
+ */
+ fs_sel = read_fs();
+ gs_sel = read_gs();
+ ldt_sel = read_ldt();
+ fs_gs_ldt_reload_needed = (fs_sel & 7) | (gs_sel & 7) | ldt_sel;
+ if (!fs_gs_ldt_reload_needed) {
+ vmcs_write16(HOST_FS_SELECTOR, fs_sel);
+ vmcs_write16(HOST_GS_SELECTOR, gs_sel);
+ } else {
+ vmcs_write16(HOST_FS_SELECTOR, 0);
+ vmcs_write16(HOST_GS_SELECTOR, 0);
+ }
+
+#ifdef CONFIG_X86_64
+ vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
+ vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
+#else
+ vmcs_writel(HOST_FS_BASE, segment_base(fs_sel));
+ vmcs_writel(HOST_GS_BASE, segment_base(gs_sel));
+#endif
+
+ if (!vcpu->mmio_read_completed)
+ do_interrupt_requests(vcpu, kvm_run);
+
+ if (vcpu->guest_debug.enabled)
+ kvm_guest_debug_pre(vcpu);
+
+ fx_save(vcpu->host_fx_image);
+ fx_restore(vcpu->guest_fx_image);
+
+ save_msrs(vcpu->host_msrs, vcpu->nmsrs);
+ load_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
+
+ asm (
+ /* Store host registers */
+ "pushf \n\t"
+#ifdef CONFIG_X86_64
+ "push %%rax; push %%rbx; push %%rdx;"
+ "push %%rsi; push %%rdi; push %%rbp;"
+ "push %%r8; push %%r9; push %%r10; push %%r11;"
+ "push %%r12; push %%r13; push %%r14; push %%r15;"
+ "push %%rcx \n\t"
+ ASM_VMX_VMWRITE_RSP_RDX "\n\t"
+#else
+ "pusha; push %%ecx \n\t"
+ ASM_VMX_VMWRITE_RSP_RDX "\n\t"
+#endif
+ /* Check if vmlaunch of vmresume is needed */
+ "cmp $0, %1 \n\t"
+ /* Load guest registers. Don't clobber flags. */
+#ifdef CONFIG_X86_64
+ "mov %c[cr2](%3), %%rax \n\t"
+ "mov %%rax, %%cr2 \n\t"
+ "mov %c[rax](%3), %%rax \n\t"
+ "mov %c[rbx](%3), %%rbx \n\t"
+ "mov %c[rdx](%3), %%rdx \n\t"
+ "mov %c[rsi](%3), %%rsi \n\t"
+ "mov %c[rdi](%3), %%rdi \n\t"
+ "mov %c[rbp](%3), %%rbp \n\t"
+ "mov %c[r8](%3), %%r8 \n\t"
+ "mov %c[r9](%3), %%r9 \n\t"
+ "mov %c[r10](%3), %%r10 \n\t"
+ "mov %c[r11](%3), %%r11 \n\t"
+ "mov %c[r12](%3), %%r12 \n\t"
+ "mov %c[r13](%3), %%r13 \n\t"
+ "mov %c[r14](%3), %%r14 \n\t"
+ "mov %c[r15](%3), %%r15 \n\t"
+ "mov %c[rcx](%3), %%rcx \n\t" /* kills %3 (rcx) */
+#else
+ "mov %c[cr2](%3), %%eax \n\t"
+ "mov %%eax, %%cr2 \n\t"
+ "mov %c[rax](%3), %%eax \n\t"
+ "mov %c[rbx](%3), %%ebx \n\t"
+ "mov %c[rdx](%3), %%edx \n\t"
+ "mov %c[rsi](%3), %%esi \n\t"
+ "mov %c[rdi](%3), %%edi \n\t"
+ "mov %c[rbp](%3), %%ebp \n\t"
+ "mov %c[rcx](%3), %%ecx \n\t" /* kills %3 (ecx) */
+#endif
+ /* Enter guest mode */
+ "jne launched \n\t"
+ ASM_VMX_VMLAUNCH "\n\t"
+ "jmp kvm_vmx_return \n\t"
+ "launched: " ASM_VMX_VMRESUME "\n\t"
+ ".globl kvm_vmx_return \n\t"
+ "kvm_vmx_return: "
+ /* Save guest registers, load host registers, keep flags */
+#ifdef CONFIG_X86_64
+ "xchg %3, 0(%%rsp) \n\t"
+ "mov %%rax, %c[rax](%3) \n\t"
+ "mov %%rbx, %c[rbx](%3) \n\t"
+ "pushq 0(%%rsp); popq %c[rcx](%3) \n\t"
+ "mov %%rdx, %c[rdx](%3) \n\t"
+ "mov %%rsi, %c[rsi](%3) \n\t"
+ "mov %%rdi, %c[rdi](%3) \n\t"
+ "mov %%rbp, %c[rbp](%3) \n\t"
+ "mov %%r8, %c[r8](%3) \n\t"
+ "mov %%r9, %c[r9](%3) \n\t"
+ "mov %%r10, %c[r10](%3) \n\t"
+ "mov %%r11, %c[r11](%3) \n\t"
+ "mov %%r12, %c[r12](%3) \n\t"
+ "mov %%r13, %c[r13](%3) \n\t"
+ "mov %%r14, %c[r14](%3) \n\t"
+ "mov %%r15, %c[r15](%3) \n\t"
+ "mov %%cr2, %%rax \n\t"
+ "mov %%rax, %c[cr2](%3) \n\t"
+ "mov 0(%%rsp), %3 \n\t"
+
+ "pop %%rcx; pop %%r15; pop %%r14; pop %%r13; pop %%r12;"
+ "pop %%r11; pop %%r10; pop %%r9; pop %%r8;"
+ "pop %%rbp; pop %%rdi; pop %%rsi;"
+ "pop %%rdx; pop %%rbx; pop %%rax \n\t"
+#else
+ "xchg %3, 0(%%esp) \n\t"
+ "mov %%eax, %c[rax](%3) \n\t"
+ "mov %%ebx, %c[rbx](%3) \n\t"
+ "pushl 0(%%esp); popl %c[rcx](%3) \n\t"
+ "mov %%edx, %c[rdx](%3) \n\t"
+ "mov %%esi, %c[rsi](%3) \n\t"
+ "mov %%edi, %c[rdi](%3) \n\t"
+ "mov %%ebp, %c[rbp](%3) \n\t"
+ "mov %%cr2, %%eax \n\t"
+ "mov %%eax, %c[cr2](%3) \n\t"
+ "mov 0(%%esp), %3 \n\t"
+
+ "pop %%ecx; popa \n\t"
+#endif
+ "setbe %0 \n\t"
+ "popf \n\t"
+ : "=q" (fail)
+ : "r"(vcpu->launched), "d"((unsigned long)HOST_RSP),
+ "c"(vcpu),
+ [rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])),
+ [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
+ [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])),
+ [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])),
+ [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])),
+ [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])),
+ [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP])),
+#ifdef CONFIG_X86_64
+ [r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])),
+ [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])),
+ [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])),
+ [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])),
+ [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])),
+ [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])),
+ [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])),
+ [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15])),
+#endif
+ [cr2]"i"(offsetof(struct kvm_vcpu, cr2))
+ : "cc", "memory" );
+
+ ++kvm_stat.exits;
+
+ save_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
+ load_msrs(vcpu->host_msrs, NR_BAD_MSRS);
+
+ fx_save(vcpu->guest_fx_image);
+ fx_restore(vcpu->host_fx_image);
+ vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
+
+#ifndef CONFIG_X86_64
+ asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
+#endif
+
+ /*
+ * Profile KVM exit RIPs:
+ */
+ if (unlikely(prof_on == KVM_PROFILING))
+ profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
+
+ kvm_run->exit_type = 0;
+ if (fail) {
+ kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY;
+ kvm_run->exit_reason = vmcs_read32(VM_INSTRUCTION_ERROR);
+ r = 0;
+ } else {
+ if (fs_gs_ldt_reload_needed) {
+ load_ldt(ldt_sel);
+ load_fs(fs_sel);
+ /*
+ * If we have to reload gs, we must take care to
+ * preserve our gs base.
+ */
+ local_irq_disable();
+ load_gs(gs_sel);
+#ifdef CONFIG_X86_64
+ wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
+#endif
+ local_irq_enable();
+
+ reload_tss();
+ }
+ vcpu->launched = 1;
+ kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT;
+ r = kvm_handle_exit(kvm_run, vcpu);
+ if (r > 0) {
+ /* Give scheduler a change to reschedule. */
+ if (signal_pending(current)) {
+ ++kvm_stat.signal_exits;
+ post_kvm_run_save(vcpu, kvm_run);
+ return -EINTR;
+ }
+
+ if (dm_request_for_irq_injection(vcpu, kvm_run)) {
+ ++kvm_stat.request_irq_exits;
+ post_kvm_run_save(vcpu, kvm_run);
+ return -EINTR;
+ }
+
+ kvm_resched(vcpu);
+ goto again;
+ }
+ }
+
+ post_kvm_run_save(vcpu, kvm_run);
+ return r;
+}
+
+static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
+{
+ vmcs_writel(GUEST_CR3, vmcs_readl(GUEST_CR3));
+}
+
+static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
+ unsigned long addr,
+ u32 err_code)
+{
+ u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+
+ ++kvm_stat.pf_guest;
+
+ if (is_page_fault(vect_info)) {
+ printk(KERN_DEBUG "inject_page_fault: "
+ "double fault 0x%lx @ 0x%lx\n",
+ addr, vmcs_readl(GUEST_RIP));
+ vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, 0);
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+ DF_VECTOR |
+ INTR_TYPE_EXCEPTION |
+ INTR_INFO_DELIEVER_CODE_MASK |
+ INTR_INFO_VALID_MASK);
+ return;
+ }
+ vcpu->cr2 = addr;
+ vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, err_code);
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+ PF_VECTOR |
+ INTR_TYPE_EXCEPTION |
+ INTR_INFO_DELIEVER_CODE_MASK |
+ INTR_INFO_VALID_MASK);
+
+}
+
+static void vmx_free_vmcs(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->vmcs) {
+ on_each_cpu(__vcpu_clear, vcpu, 0, 1);
+ free_vmcs(vcpu->vmcs);
+ vcpu->vmcs = NULL;
+ }
+}
+
+static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
+{
+ vmx_free_vmcs(vcpu);
+}
+
+static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
+{
+ struct vmcs *vmcs;
+
+ vcpu->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!vcpu->guest_msrs)
+ return -ENOMEM;
+
+ vcpu->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!vcpu->host_msrs)
+ goto out_free_guest_msrs;
+
+ vmcs = alloc_vmcs();
+ if (!vmcs)
+ goto out_free_msrs;
+
+ vmcs_clear(vmcs);
+ vcpu->vmcs = vmcs;
+ vcpu->launched = 0;
+
+ return 0;
+
+out_free_msrs:
+ kfree(vcpu->host_msrs);
+ vcpu->host_msrs = NULL;
+
+out_free_guest_msrs:
+ kfree(vcpu->guest_msrs);
+ vcpu->guest_msrs = NULL;
+
+ return -ENOMEM;
+}
+
+static struct kvm_arch_ops vmx_arch_ops = {
+ .cpu_has_kvm_support = cpu_has_kvm_support,
+ .disabled_by_bios = vmx_disabled_by_bios,
+ .hardware_setup = hardware_setup,
+ .hardware_unsetup = hardware_unsetup,
+ .hardware_enable = hardware_enable,
+ .hardware_disable = hardware_disable,
+
+ .vcpu_create = vmx_create_vcpu,
+ .vcpu_free = vmx_free_vcpu,
+
+ .vcpu_load = vmx_vcpu_load,
+ .vcpu_put = vmx_vcpu_put,
+
+ .set_guest_debug = set_guest_debug,
+ .get_msr = vmx_get_msr,
+ .set_msr = vmx_set_msr,
+ .get_segment_base = vmx_get_segment_base,
+ .get_segment = vmx_get_segment,
+ .set_segment = vmx_set_segment,
+ .get_cs_db_l_bits = vmx_get_cs_db_l_bits,
+ .decache_cr0_cr4_guest_bits = vmx_decache_cr0_cr4_guest_bits,
+ .set_cr0 = vmx_set_cr0,
+ .set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch,
+ .set_cr3 = vmx_set_cr3,
+ .set_cr4 = vmx_set_cr4,
+#ifdef CONFIG_X86_64
+ .set_efer = vmx_set_efer,
+#endif
+ .get_idt = vmx_get_idt,
+ .set_idt = vmx_set_idt,
+ .get_gdt = vmx_get_gdt,
+ .set_gdt = vmx_set_gdt,
+ .cache_regs = vcpu_load_rsp_rip,
+ .decache_regs = vcpu_put_rsp_rip,
+ .get_rflags = vmx_get_rflags,
+ .set_rflags = vmx_set_rflags,
+
+ .tlb_flush = vmx_flush_tlb,
+ .inject_page_fault = vmx_inject_page_fault,
+
+ .inject_gp = vmx_inject_gp,
+
+ .run = vmx_vcpu_run,
+ .skip_emulated_instruction = skip_emulated_instruction,
+ .vcpu_setup = vmx_vcpu_setup,
+};
+
+static int __init vmx_init(void)
+{
+ return kvm_init_arch(&vmx_arch_ops, THIS_MODULE);
+}
+
+static void __exit vmx_exit(void)
+{
+ kvm_exit_arch();
+}
+
+module_init(vmx_init)
+module_exit(vmx_exit)
diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h
new file mode 100644
index 00000000000..4c0ab151836
--- /dev/null
+++ b/drivers/kvm/vmx.h
@@ -0,0 +1,296 @@
+#ifndef VMX_H
+#define VMX_H
+
+/*
+ * vmx.h: VMX Architecture related definitions
+ * Copyright (c) 2004, 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.
+ *
+ * A few random additions are:
+ * Copyright (C) 2006 Qumranet
+ * Avi Kivity <avi@qumranet.com>
+ * Yaniv Kamay <yaniv@qumranet.com>
+ *
+ */
+
+#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004
+#define CPU_BASED_USE_TSC_OFFSETING 0x00000008
+#define CPU_BASED_HLT_EXITING 0x00000080
+#define CPU_BASED_INVDPG_EXITING 0x00000200
+#define CPU_BASED_MWAIT_EXITING 0x00000400
+#define CPU_BASED_RDPMC_EXITING 0x00000800
+#define CPU_BASED_RDTSC_EXITING 0x00001000
+#define CPU_BASED_CR8_LOAD_EXITING 0x00080000
+#define CPU_BASED_CR8_STORE_EXITING 0x00100000
+#define CPU_BASED_TPR_SHADOW 0x00200000
+#define CPU_BASED_MOV_DR_EXITING 0x00800000
+#define CPU_BASED_UNCOND_IO_EXITING 0x01000000
+#define CPU_BASED_ACTIVATE_IO_BITMAP 0x02000000
+#define CPU_BASED_MSR_BITMAPS 0x10000000
+#define CPU_BASED_MONITOR_EXITING 0x20000000
+#define CPU_BASED_PAUSE_EXITING 0x40000000
+
+#define PIN_BASED_EXT_INTR_MASK 0x1
+#define PIN_BASED_NMI_EXITING 0x8
+
+#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000
+#define VM_EXIT_HOST_ADD_SPACE_SIZE 0x00000200
+
+
+/* VMCS Encodings */
+enum vmcs_field {
+ GUEST_ES_SELECTOR = 0x00000800,
+ GUEST_CS_SELECTOR = 0x00000802,
+ GUEST_SS_SELECTOR = 0x00000804,
+ GUEST_DS_SELECTOR = 0x00000806,
+ GUEST_FS_SELECTOR = 0x00000808,
+ GUEST_GS_SELECTOR = 0x0000080a,
+ GUEST_LDTR_SELECTOR = 0x0000080c,
+ GUEST_TR_SELECTOR = 0x0000080e,
+ HOST_ES_SELECTOR = 0x00000c00,
+ HOST_CS_SELECTOR = 0x00000c02,
+ HOST_SS_SELECTOR = 0x00000c04,
+ HOST_DS_SELECTOR = 0x00000c06,
+ HOST_FS_SELECTOR = 0x00000c08,
+ HOST_GS_SELECTOR = 0x00000c0a,
+ HOST_TR_SELECTOR = 0x00000c0c,
+ IO_BITMAP_A = 0x00002000,
+ IO_BITMAP_A_HIGH = 0x00002001,
+ IO_BITMAP_B = 0x00002002,
+ IO_BITMAP_B_HIGH = 0x00002003,
+ MSR_BITMAP = 0x00002004,
+ MSR_BITMAP_HIGH = 0x00002005,
+ VM_EXIT_MSR_STORE_ADDR = 0x00002006,
+ VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007,
+ VM_EXIT_MSR_LOAD_ADDR = 0x00002008,
+ VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009,
+ VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a,
+ VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b,
+ TSC_OFFSET = 0x00002010,
+ TSC_OFFSET_HIGH = 0x00002011,
+ VIRTUAL_APIC_PAGE_ADDR = 0x00002012,
+ VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013,
+ VMCS_LINK_POINTER = 0x00002800,
+ VMCS_LINK_POINTER_HIGH = 0x00002801,
+ GUEST_IA32_DEBUGCTL = 0x00002802,
+ GUEST_IA32_DEBUGCTL_HIGH = 0x00002803,
+ PIN_BASED_VM_EXEC_CONTROL = 0x00004000,
+ CPU_BASED_VM_EXEC_CONTROL = 0x00004002,
+ EXCEPTION_BITMAP = 0x00004004,
+ PAGE_FAULT_ERROR_CODE_MASK = 0x00004006,
+ PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008,
+ CR3_TARGET_COUNT = 0x0000400a,
+ VM_EXIT_CONTROLS = 0x0000400c,
+ VM_EXIT_MSR_STORE_COUNT = 0x0000400e,
+ VM_EXIT_MSR_LOAD_COUNT = 0x00004010,
+ VM_ENTRY_CONTROLS = 0x00004012,
+ VM_ENTRY_MSR_LOAD_COUNT = 0x00004014,
+ VM_ENTRY_INTR_INFO_FIELD = 0x00004016,
+ VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018,
+ VM_ENTRY_INSTRUCTION_LEN = 0x0000401a,
+ TPR_THRESHOLD = 0x0000401c,
+ SECONDARY_VM_EXEC_CONTROL = 0x0000401e,
+ VM_INSTRUCTION_ERROR = 0x00004400,
+ VM_EXIT_REASON = 0x00004402,
+ VM_EXIT_INTR_INFO = 0x00004404,
+ VM_EXIT_INTR_ERROR_CODE = 0x00004406,
+ IDT_VECTORING_INFO_FIELD = 0x00004408,
+ IDT_VECTORING_ERROR_CODE = 0x0000440a,
+ VM_EXIT_INSTRUCTION_LEN = 0x0000440c,
+ VMX_INSTRUCTION_INFO = 0x0000440e,
+ GUEST_ES_LIMIT = 0x00004800,
+ GUEST_CS_LIMIT = 0x00004802,
+ GUEST_SS_LIMIT = 0x00004804,
+ GUEST_DS_LIMIT = 0x00004806,
+ GUEST_FS_LIMIT = 0x00004808,
+ GUEST_GS_LIMIT = 0x0000480a,
+ GUEST_LDTR_LIMIT = 0x0000480c,
+ GUEST_TR_LIMIT = 0x0000480e,
+ GUEST_GDTR_LIMIT = 0x00004810,
+ GUEST_IDTR_LIMIT = 0x00004812,
+ GUEST_ES_AR_BYTES = 0x00004814,
+ GUEST_CS_AR_BYTES = 0x00004816,
+ GUEST_SS_AR_BYTES = 0x00004818,
+ GUEST_DS_AR_BYTES = 0x0000481a,
+ GUEST_FS_AR_BYTES = 0x0000481c,
+ GUEST_GS_AR_BYTES = 0x0000481e,
+ GUEST_LDTR_AR_BYTES = 0x00004820,
+ GUEST_TR_AR_BYTES = 0x00004822,
+ GUEST_INTERRUPTIBILITY_INFO = 0x00004824,
+ GUEST_ACTIVITY_STATE = 0X00004826,
+ GUEST_SYSENTER_CS = 0x0000482A,
+ HOST_IA32_SYSENTER_CS = 0x00004c00,
+ CR0_GUEST_HOST_MASK = 0x00006000,
+ CR4_GUEST_HOST_MASK = 0x00006002,
+ CR0_READ_SHADOW = 0x00006004,
+ CR4_READ_SHADOW = 0x00006006,
+ CR3_TARGET_VALUE0 = 0x00006008,
+ CR3_TARGET_VALUE1 = 0x0000600a,
+ CR3_TARGET_VALUE2 = 0x0000600c,
+ CR3_TARGET_VALUE3 = 0x0000600e,
+ EXIT_QUALIFICATION = 0x00006400,
+ GUEST_LINEAR_ADDRESS = 0x0000640a,
+ GUEST_CR0 = 0x00006800,
+ GUEST_CR3 = 0x00006802,
+ GUEST_CR4 = 0x00006804,
+ GUEST_ES_BASE = 0x00006806,
+ GUEST_CS_BASE = 0x00006808,
+ GUEST_SS_BASE = 0x0000680a,
+ GUEST_DS_BASE = 0x0000680c,
+ GUEST_FS_BASE = 0x0000680e,
+ GUEST_GS_BASE = 0x00006810,
+ GUEST_LDTR_BASE = 0x00006812,
+ GUEST_TR_BASE = 0x00006814,
+ GUEST_GDTR_BASE = 0x00006816,
+ GUEST_IDTR_BASE = 0x00006818,
+ GUEST_DR7 = 0x0000681a,
+ GUEST_RSP = 0x0000681c,
+ GUEST_RIP = 0x0000681e,
+ GUEST_RFLAGS = 0x00006820,
+ GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822,
+ GUEST_SYSENTER_ESP = 0x00006824,
+ GUEST_SYSENTER_EIP = 0x00006826,
+ HOST_CR0 = 0x00006c00,
+ HOST_CR3 = 0x00006c02,
+ HOST_CR4 = 0x00006c04,
+ HOST_FS_BASE = 0x00006c06,
+ HOST_GS_BASE = 0x00006c08,
+ HOST_TR_BASE = 0x00006c0a,
+ HOST_GDTR_BASE = 0x00006c0c,
+ HOST_IDTR_BASE = 0x00006c0e,
+ HOST_IA32_SYSENTER_ESP = 0x00006c10,
+ HOST_IA32_SYSENTER_EIP = 0x00006c12,
+ HOST_RSP = 0x00006c14,
+ HOST_RIP = 0x00006c16,
+};
+
+#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000
+
+#define EXIT_REASON_EXCEPTION_NMI 0
+#define EXIT_REASON_EXTERNAL_INTERRUPT 1
+
+#define EXIT_REASON_PENDING_INTERRUPT 7
+
+#define EXIT_REASON_TASK_SWITCH 9
+#define EXIT_REASON_CPUID 10
+#define EXIT_REASON_HLT 12
+#define EXIT_REASON_INVLPG 14
+#define EXIT_REASON_RDPMC 15
+#define EXIT_REASON_RDTSC 16
+#define EXIT_REASON_VMCALL 18
+#define EXIT_REASON_VMCLEAR 19
+#define EXIT_REASON_VMLAUNCH 20
+#define EXIT_REASON_VMPTRLD 21
+#define EXIT_REASON_VMPTRST 22
+#define EXIT_REASON_VMREAD 23
+#define EXIT_REASON_VMRESUME 24
+#define EXIT_REASON_VMWRITE 25
+#define EXIT_REASON_VMOFF 26
+#define EXIT_REASON_VMON 27
+#define EXIT_REASON_CR_ACCESS 28
+#define EXIT_REASON_DR_ACCESS 29
+#define EXIT_REASON_IO_INSTRUCTION 30
+#define EXIT_REASON_MSR_READ 31
+#define EXIT_REASON_MSR_WRITE 32
+#define EXIT_REASON_MWAIT_INSTRUCTION 36
+
+/*
+ * Interruption-information format
+ */
+#define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */
+#define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */
+#define INTR_INFO_DELIEVER_CODE_MASK 0x800 /* 11 */
+#define INTR_INFO_VALID_MASK 0x80000000 /* 31 */
+
+#define VECTORING_INFO_VECTOR_MASK INTR_INFO_VECTOR_MASK
+#define VECTORING_INFO_TYPE_MASK INTR_INFO_INTR_TYPE_MASK
+#define VECTORING_INFO_DELIEVER_CODE_MASK INTR_INFO_DELIEVER_CODE_MASK
+#define VECTORING_INFO_VALID_MASK INTR_INFO_VALID_MASK
+
+#define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */
+#define INTR_TYPE_EXCEPTION (3 << 8) /* processor exception */
+
+/*
+ * Exit Qualifications for MOV for Control Register Access
+ */
+#define CONTROL_REG_ACCESS_NUM 0x7 /* 2:0, number of control register */
+#define CONTROL_REG_ACCESS_TYPE 0x30 /* 5:4, access type */
+#define CONTROL_REG_ACCESS_REG 0xf00 /* 10:8, general purpose register */
+#define LMSW_SOURCE_DATA_SHIFT 16
+#define LMSW_SOURCE_DATA (0xFFFF << LMSW_SOURCE_DATA_SHIFT) /* 16:31 lmsw source */
+#define REG_EAX (0 << 8)
+#define REG_ECX (1 << 8)
+#define REG_EDX (2 << 8)
+#define REG_EBX (3 << 8)
+#define REG_ESP (4 << 8)
+#define REG_EBP (5 << 8)
+#define REG_ESI (6 << 8)
+#define REG_EDI (7 << 8)
+#define REG_R8 (8 << 8)
+#define REG_R9 (9 << 8)
+#define REG_R10 (10 << 8)
+#define REG_R11 (11 << 8)
+#define REG_R12 (12 << 8)
+#define REG_R13 (13 << 8)
+#define REG_R14 (14 << 8)
+#define REG_R15 (15 << 8)
+
+/*
+ * Exit Qualifications for MOV for Debug Register Access
+ */
+#define DEBUG_REG_ACCESS_NUM 0x7 /* 2:0, number of debug register */
+#define DEBUG_REG_ACCESS_TYPE 0x10 /* 4, direction of access */
+#define TYPE_MOV_TO_DR (0 << 4)
+#define TYPE_MOV_FROM_DR (1 << 4)
+#define DEBUG_REG_ACCESS_REG 0xf00 /* 11:8, general purpose register */
+
+
+/* segment AR */
+#define SEGMENT_AR_L_MASK (1 << 13)
+
+/* entry controls */
+#define VM_ENTRY_CONTROLS_IA32E_MASK (1 << 9)
+
+#define AR_TYPE_ACCESSES_MASK 1
+#define AR_TYPE_READABLE_MASK (1 << 1)
+#define AR_TYPE_WRITEABLE_MASK (1 << 2)
+#define AR_TYPE_CODE_MASK (1 << 3)
+#define AR_TYPE_MASK 0x0f
+#define AR_TYPE_BUSY_64_TSS 11
+#define AR_TYPE_BUSY_32_TSS 11
+#define AR_TYPE_BUSY_16_TSS 3
+#define AR_TYPE_LDT 2
+
+#define AR_UNUSABLE_MASK (1 << 16)
+#define AR_S_MASK (1 << 4)
+#define AR_P_MASK (1 << 7)
+#define AR_L_MASK (1 << 13)
+#define AR_DB_MASK (1 << 14)
+#define AR_G_MASK (1 << 15)
+#define AR_DPL_SHIFT 5
+#define AR_DPL(ar) (((ar) >> AR_DPL_SHIFT) & 3)
+
+#define AR_RESERVD_MASK 0xfffe0f00
+
+#define CR4_VMXE 0x2000
+
+#define MSR_IA32_VMX_BASIC 0x480
+#define MSR_IA32_FEATURE_CONTROL 0x03a
+#define MSR_IA32_VMX_PINBASED_CTLS 0x481
+#define MSR_IA32_VMX_PROCBASED_CTLS 0x482
+#define MSR_IA32_VMX_EXIT_CTLS 0x483
+#define MSR_IA32_VMX_ENTRY_CTLS 0x484
+
+#endif
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
new file mode 100644
index 00000000000..7513cddb929
--- /dev/null
+++ b/drivers/kvm/x86_emulate.c
@@ -0,0 +1,1415 @@
+/******************************************************************************
+ * x86_emulate.c
+ *
+ * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
+ *
+ * Copyright (c) 2005 Keir Fraser
+ *
+ * Linux coding style, mod r/m decoder, segment base fixes, real-mode
+ * privieged instructions:
+ *
+ * Copyright (C) 2006 Qumranet
+ *
+ * Avi Kivity <avi@qumranet.com>
+ * Yaniv Kamay <yaniv@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4
+ */
+
+#ifndef __KERNEL__
+#include <stdio.h>
+#include <stdint.h>
+#include <public/xen.h>
+#define DPRINTF(_f, _a ...) printf( _f , ## _a )
+#else
+#include "kvm.h"
+#define DPRINTF(x...) do {} while (0)
+#endif
+#include "x86_emulate.h"
+#include <linux/module.h>
+
+/*
+ * Opcode effective-address decode tables.
+ * Note that we only emulate instructions that have at least one memory
+ * operand (excluding implicit stack references). We assume that stack
+ * references and instruction fetches will never occur in special memory
+ * areas that require emulation. So, for example, 'mov <imm>,<reg>' need
+ * not be handled.
+ */
+
+/* Operand sizes: 8-bit operands or specified/overridden size. */
+#define ByteOp (1<<0) /* 8-bit operands. */
+/* Destination operand type. */
+#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */
+#define DstReg (2<<1) /* Register operand. */
+#define DstMem (3<<1) /* Memory operand. */
+#define DstMask (3<<1)
+/* Source operand type. */
+#define SrcNone (0<<3) /* No source operand. */
+#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */
+#define SrcReg (1<<3) /* Register operand. */
+#define SrcMem (2<<3) /* Memory operand. */
+#define SrcMem16 (3<<3) /* Memory operand (16-bit). */
+#define SrcMem32 (4<<3) /* Memory operand (32-bit). */
+#define SrcImm (5<<3) /* Immediate operand. */
+#define SrcImmByte (6<<3) /* 8-bit sign-extended immediate operand. */
+#define SrcMask (7<<3)
+/* Generic ModRM decode. */
+#define ModRM (1<<6)
+/* Destination is only written; never read. */
+#define Mov (1<<7)
+#define BitOp (1<<8)
+
+static u8 opcode_table[256] = {
+ /* 0x00 - 0x07 */
+ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+ ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+ 0, 0, 0, 0,
+ /* 0x08 - 0x0F */
+ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+ ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+ 0, 0, 0, 0,
+ /* 0x10 - 0x17 */
+ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+ ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+ 0, 0, 0, 0,
+ /* 0x18 - 0x1F */
+ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+ ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+ 0, 0, 0, 0,
+ /* 0x20 - 0x27 */
+ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+ ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+ 0, 0, 0, 0,
+ /* 0x28 - 0x2F */
+ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+ ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+ 0, 0, 0, 0,
+ /* 0x30 - 0x37 */
+ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+ ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+ 0, 0, 0, 0,
+ /* 0x38 - 0x3F */
+ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+ ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+ 0, 0, 0, 0,
+ /* 0x40 - 0x4F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x50 - 0x5F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x60 - 0x6F */
+ 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x70 - 0x7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x80 - 0x87 */
+ ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
+ ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
+ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+ /* 0x88 - 0x8F */
+ ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
+ ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+ 0, 0, 0, DstMem | SrcNone | ModRM | Mov,
+ /* 0x90 - 0x9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xA0 - 0xA7 */
+ ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov,
+ ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov,
+ ByteOp | ImplicitOps | Mov, ImplicitOps | Mov,
+ ByteOp | ImplicitOps, ImplicitOps,
+ /* 0xA8 - 0xAF */
+ 0, 0, ByteOp | ImplicitOps | Mov, ImplicitOps | Mov,
+ ByteOp | ImplicitOps | Mov, ImplicitOps | Mov,
+ ByteOp | ImplicitOps, ImplicitOps,
+ /* 0xB0 - 0xBF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xC0 - 0xC7 */
+ ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, 0, 0,
+ 0, 0, ByteOp | DstMem | SrcImm | ModRM | Mov,
+ DstMem | SrcImm | ModRM | Mov,
+ /* 0xC8 - 0xCF */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xD0 - 0xD7 */
+ ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
+ ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
+ 0, 0, 0, 0,
+ /* 0xD8 - 0xDF */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xE0 - 0xEF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xF0 - 0xF7 */
+ 0, 0, 0, 0,
+ 0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
+ /* 0xF8 - 0xFF */
+ 0, 0, 0, 0,
+ 0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM
+};
+
+static u16 twobyte_table[256] = {
+ /* 0x00 - 0x0F */
+ 0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0,
+ 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
+ /* 0x10 - 0x1F */
+ 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x20 - 0x2F */
+ ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x30 - 0x3F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x40 - 0x47 */
+ DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+ DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+ DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+ DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+ /* 0x48 - 0x4F */
+ DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+ DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+ DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+ DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+ /* 0x50 - 0x5F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x60 - 0x6F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x70 - 0x7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x80 - 0x8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x90 - 0x9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xA0 - 0xA7 */
+ 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0,
+ /* 0xA8 - 0xAF */
+ 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0,
+ /* 0xB0 - 0xB7 */
+ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, 0,
+ DstMem | SrcReg | ModRM | BitOp,
+ 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
+ DstReg | SrcMem16 | ModRM | Mov,
+ /* 0xB8 - 0xBF */
+ 0, 0, DstMem | SrcImmByte | ModRM, DstMem | SrcReg | ModRM | BitOp,
+ 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
+ DstReg | SrcMem16 | ModRM | Mov,
+ /* 0xC0 - 0xCF */
+ 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xD0 - 0xDF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xE0 - 0xEF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xF0 - 0xFF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * Tell the emulator that of the Group 7 instructions (sgdt, lidt, etc.) we
+ * are interested only in invlpg and not in any of the rest.
+ *
+ * invlpg is a special instruction in that the data it references may not
+ * be mapped.
+ */
+void kvm_emulator_want_group7_invlpg(void)
+{
+ twobyte_table[1] &= ~SrcMem;
+}
+EXPORT_SYMBOL_GPL(kvm_emulator_want_group7_invlpg);
+
+/* Type, address-of, and value of an instruction's operand. */
+struct operand {
+ enum { OP_REG, OP_MEM, OP_IMM } type;
+ unsigned int bytes;
+ unsigned long val, orig_val, *ptr;
+};
+
+/* EFLAGS bit definitions. */
+#define EFLG_OF (1<<11)
+#define EFLG_DF (1<<10)
+#define EFLG_SF (1<<7)
+#define EFLG_ZF (1<<6)
+#define EFLG_AF (1<<4)
+#define EFLG_PF (1<<2)
+#define EFLG_CF (1<<0)
+
+/*
+ * Instruction emulation:
+ * Most instructions are emulated directly via a fragment of inline assembly
+ * code. This allows us to save/restore EFLAGS and thus very easily pick up
+ * any modified flags.
+ */
+
+#if defined(CONFIG_X86_64)
+#define _LO32 "k" /* force 32-bit operand */
+#define _STK "%%rsp" /* stack pointer */
+#elif defined(__i386__)
+#define _LO32 "" /* force 32-bit operand */
+#define _STK "%%esp" /* stack pointer */
+#endif
+
+/*
+ * These EFLAGS bits are restored from saved value during emulation, and
+ * any changes are written back to the saved value after emulation.
+ */
+#define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF)
+
+/* Before executing instruction: restore necessary bits in EFLAGS. */
+#define _PRE_EFLAGS(_sav, _msk, _tmp) \
+ /* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); */ \
+ "push %"_sav"; " \
+ "movl %"_msk",%"_LO32 _tmp"; " \
+ "andl %"_LO32 _tmp",("_STK"); " \
+ "pushf; " \
+ "notl %"_LO32 _tmp"; " \
+ "andl %"_LO32 _tmp",("_STK"); " \
+ "pop %"_tmp"; " \
+ "orl %"_LO32 _tmp",("_STK"); " \
+ "popf; " \
+ /* _sav &= ~msk; */ \
+ "movl %"_msk",%"_LO32 _tmp"; " \
+ "notl %"_LO32 _tmp"; " \
+ "andl %"_LO32 _tmp",%"_sav"; "
+
+/* After executing instruction: write-back necessary bits in EFLAGS. */
+#define _POST_EFLAGS(_sav, _msk, _tmp) \
+ /* _sav |= EFLAGS & _msk; */ \
+ "pushf; " \
+ "pop %"_tmp"; " \
+ "andl %"_msk",%"_LO32 _tmp"; " \
+ "orl %"_LO32 _tmp",%"_sav"; "
+
+/* Raw emulation: instruction has two explicit operands. */
+#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy) \
+ do { \
+ unsigned long _tmp; \
+ \
+ switch ((_dst).bytes) { \
+ case 2: \
+ __asm__ __volatile__ ( \
+ _PRE_EFLAGS("0","4","2") \
+ _op"w %"_wx"3,%1; " \
+ _POST_EFLAGS("0","4","2") \
+ : "=m" (_eflags), "=m" ((_dst).val), \
+ "=&r" (_tmp) \
+ : _wy ((_src).val), "i" (EFLAGS_MASK) ); \
+ break; \
+ case 4: \
+ __asm__ __volatile__ ( \
+ _PRE_EFLAGS("0","4","2") \
+ _op"l %"_lx"3,%1; " \
+ _POST_EFLAGS("0","4","2") \
+ : "=m" (_eflags), "=m" ((_dst).val), \
+ "=&r" (_tmp) \
+ : _ly ((_src).val), "i" (EFLAGS_MASK) ); \
+ break; \
+ case 8: \
+ __emulate_2op_8byte(_op, _src, _dst, \
+ _eflags, _qx, _qy); \
+ break; \
+ } \
+ } while (0)
+
+#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \
+ do { \
+ unsigned long _tmp; \
+ switch ( (_dst).bytes ) \
+ { \
+ case 1: \
+ __asm__ __volatile__ ( \
+ _PRE_EFLAGS("0","4","2") \
+ _op"b %"_bx"3,%1; " \
+ _POST_EFLAGS("0","4","2") \
+ : "=m" (_eflags), "=m" ((_dst).val), \
+ "=&r" (_tmp) \
+ : _by ((_src).val), "i" (EFLAGS_MASK) ); \
+ break; \
+ default: \
+ __emulate_2op_nobyte(_op, _src, _dst, _eflags, \
+ _wx, _wy, _lx, _ly, _qx, _qy); \
+ break; \
+ } \
+ } while (0)
+
+/* Source operand is byte-sized and may be restricted to just %cl. */
+#define emulate_2op_SrcB(_op, _src, _dst, _eflags) \
+ __emulate_2op(_op, _src, _dst, _eflags, \
+ "b", "c", "b", "c", "b", "c", "b", "c")
+
+/* Source operand is byte, word, long or quad sized. */
+#define emulate_2op_SrcV(_op, _src, _dst, _eflags) \
+ __emulate_2op(_op, _src, _dst, _eflags, \
+ "b", "q", "w", "r", _LO32, "r", "", "r")
+
+/* Source operand is word, long or quad sized. */
+#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags) \
+ __emulate_2op_nobyte(_op, _src, _dst, _eflags, \
+ "w", "r", _LO32, "r", "", "r")
+
+/* Instruction has only one explicit operand (no source operand). */
+#define emulate_1op(_op, _dst, _eflags) \
+ do { \
+ unsigned long _tmp; \
+ \
+ switch ( (_dst).bytes ) \
+ { \
+ case 1: \
+ __asm__ __volatile__ ( \
+ _PRE_EFLAGS("0","3","2") \
+ _op"b %1; " \
+ _POST_EFLAGS("0","3","2") \
+ : "=m" (_eflags), "=m" ((_dst).val), \
+ "=&r" (_tmp) \
+ : "i" (EFLAGS_MASK) ); \
+ break; \
+ case 2: \
+ __asm__ __volatile__ ( \
+ _PRE_EFLAGS("0","3","2") \
+ _op"w %1; " \
+ _POST_EFLAGS("0","3","2") \
+ : "=m" (_eflags), "=m" ((_dst).val), \
+ "=&r" (_tmp) \
+ : "i" (EFLAGS_MASK) ); \
+ break; \
+ case 4: \
+ __asm__ __volatile__ ( \
+ _PRE_EFLAGS("0","3","2") \
+ _op"l %1; " \
+ _POST_EFLAGS("0","3","2") \
+ : "=m" (_eflags), "=m" ((_dst).val), \
+ "=&r" (_tmp) \
+ : "i" (EFLAGS_MASK) ); \
+ break; \
+ case 8: \
+ __emulate_1op_8byte(_op, _dst, _eflags); \
+ break; \
+ } \
+ } while (0)
+
+/* Emulate an instruction with quadword operands (x86/64 only). */
+#if defined(CONFIG_X86_64)
+#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) \
+ do { \
+ __asm__ __volatile__ ( \
+ _PRE_EFLAGS("0","4","2") \
+ _op"q %"_qx"3,%1; " \
+ _POST_EFLAGS("0","4","2") \
+ : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
+ : _qy ((_src).val), "i" (EFLAGS_MASK) ); \
+ } while (0)
+
+#define __emulate_1op_8byte(_op, _dst, _eflags) \
+ do { \
+ __asm__ __volatile__ ( \
+ _PRE_EFLAGS("0","3","2") \
+ _op"q %1; " \
+ _POST_EFLAGS("0","3","2") \
+ : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
+ : "i" (EFLAGS_MASK) ); \
+ } while (0)
+
+#elif defined(__i386__)
+#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)
+#define __emulate_1op_8byte(_op, _dst, _eflags)
+#endif /* __i386__ */
+
+/* Fetch next part of the instruction being emulated. */
+#define insn_fetch(_type, _size, _eip) \
+({ unsigned long _x; \
+ rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x, \
+ (_size), ctxt); \
+ if ( rc != 0 ) \
+ goto done; \
+ (_eip) += (_size); \
+ (_type)_x; \
+})
+
+/* Access/update address held in a register, based on addressing mode. */
+#define register_address(base, reg) \
+ ((base) + ((ad_bytes == sizeof(unsigned long)) ? (reg) : \
+ ((reg) & ((1UL << (ad_bytes << 3)) - 1))))
+
+#define register_address_increment(reg, inc) \
+ do { \
+ /* signed type ensures sign extension to long */ \
+ int _inc = (inc); \
+ if ( ad_bytes == sizeof(unsigned long) ) \
+ (reg) += _inc; \
+ else \
+ (reg) = ((reg) & ~((1UL << (ad_bytes << 3)) - 1)) | \
+ (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \
+ } while (0)
+
+void *decode_register(u8 modrm_reg, unsigned long *regs,
+ int highbyte_regs)
+{
+ void *p;
+
+ p = &regs[modrm_reg];
+ if (highbyte_regs && modrm_reg >= 4 && modrm_reg < 8)
+ p = (unsigned char *)&regs[modrm_reg & 3] + 1;
+ return p;
+}
+
+static int read_descriptor(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ void *ptr,
+ u16 *size, unsigned long *address, int op_bytes)
+{
+ int rc;
+
+ if (op_bytes == 2)
+ op_bytes = 3;
+ *address = 0;
+ rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, ctxt);
+ if (rc)
+ return rc;
+ rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, ctxt);
+ return rc;
+}
+
+int
+x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
+{
+ unsigned d;
+ u8 b, sib, twobyte = 0, rex_prefix = 0;
+ u8 modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
+ unsigned long *override_base = NULL;
+ unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
+ int rc = 0;
+ struct operand src, dst;
+ unsigned long cr2 = ctxt->cr2;
+ int mode = ctxt->mode;
+ unsigned long modrm_ea;
+ int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
+
+ /* Shadow copy of register state. Committed on successful emulation. */
+ unsigned long _regs[NR_VCPU_REGS];
+ unsigned long _eip = ctxt->vcpu->rip, _eflags = ctxt->eflags;
+ unsigned long modrm_val = 0;
+
+ memcpy(_regs, ctxt->vcpu->regs, sizeof _regs);
+
+ switch (mode) {
+ case X86EMUL_MODE_REAL:
+ case X86EMUL_MODE_PROT16:
+ op_bytes = ad_bytes = 2;
+ break;
+ case X86EMUL_MODE_PROT32:
+ op_bytes = ad_bytes = 4;
+ break;
+#ifdef CONFIG_X86_64
+ case X86EMUL_MODE_PROT64:
+ op_bytes = 4;
+ ad_bytes = 8;
+ break;
+#endif
+ default:
+ return -1;
+ }
+
+ /* Legacy prefixes. */
+ for (i = 0; i < 8; i++) {
+ switch (b = insn_fetch(u8, 1, _eip)) {
+ case 0x66: /* operand-size override */
+ op_bytes ^= 6; /* switch between 2/4 bytes */
+ break;
+ case 0x67: /* address-size override */
+ if (mode == X86EMUL_MODE_PROT64)
+ ad_bytes ^= 12; /* switch between 4/8 bytes */
+ else
+ ad_bytes ^= 6; /* switch between 2/4 bytes */
+ break;
+ case 0x2e: /* CS override */
+ override_base = &ctxt->cs_base;
+ break;
+ case 0x3e: /* DS override */
+ override_base = &ctxt->ds_base;
+ break;
+ case 0x26: /* ES override */
+ override_base = &ctxt->es_base;
+ break;
+ case 0x64: /* FS override */
+ override_base = &ctxt->fs_base;
+ break;
+ case 0x65: /* GS override */
+ override_base = &ctxt->gs_base;
+ break;
+ case 0x36: /* SS override */
+ override_base = &ctxt->ss_base;
+ break;
+ case 0xf0: /* LOCK */
+ lock_prefix = 1;
+ break;
+ case 0xf3: /* REP/REPE/REPZ */
+ rep_prefix = 1;
+ break;
+ case 0xf2: /* REPNE/REPNZ */
+ break;
+ default:
+ goto done_prefixes;
+ }
+ }
+
+done_prefixes:
+
+ /* REX prefix. */
+ if ((mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40)) {
+ rex_prefix = b;
+ if (b & 8)
+ op_bytes = 8; /* REX.W */
+ modrm_reg = (b & 4) << 1; /* REX.R */
+ index_reg = (b & 2) << 2; /* REX.X */
+ modrm_rm = base_reg = (b & 1) << 3; /* REG.B */
+ b = insn_fetch(u8, 1, _eip);
+ }
+
+ /* Opcode byte(s). */
+ d = opcode_table[b];
+ if (d == 0) {
+ /* Two-byte opcode? */
+ if (b == 0x0f) {
+ twobyte = 1;
+ b = insn_fetch(u8, 1, _eip);
+ d = twobyte_table[b];
+ }
+
+ /* Unrecognised? */
+ if (d == 0)
+ goto cannot_emulate;
+ }
+
+ /* ModRM and SIB bytes. */
+ if (d & ModRM) {
+ modrm = insn_fetch(u8, 1, _eip);
+ modrm_mod |= (modrm & 0xc0) >> 6;
+ modrm_reg |= (modrm & 0x38) >> 3;
+ modrm_rm |= (modrm & 0x07);
+ modrm_ea = 0;
+ use_modrm_ea = 1;
+
+ if (modrm_mod == 3) {
+ modrm_val = *(unsigned long *)
+ decode_register(modrm_rm, _regs, d & ByteOp);
+ goto modrm_done;
+ }
+
+ if (ad_bytes == 2) {
+ unsigned bx = _regs[VCPU_REGS_RBX];
+ unsigned bp = _regs[VCPU_REGS_RBP];
+ unsigned si = _regs[VCPU_REGS_RSI];
+ unsigned di = _regs[VCPU_REGS_RDI];
+
+ /* 16-bit ModR/M decode. */
+ switch (modrm_mod) {
+ case 0:
+ if (modrm_rm == 6)
+ modrm_ea += insn_fetch(u16, 2, _eip);
+ break;
+ case 1:
+ modrm_ea += insn_fetch(s8, 1, _eip);
+ break;
+ case 2:
+ modrm_ea += insn_fetch(u16, 2, _eip);
+ break;
+ }
+ switch (modrm_rm) {
+ case 0:
+ modrm_ea += bx + si;
+ break;
+ case 1:
+ modrm_ea += bx + di;
+ break;
+ case 2:
+ modrm_ea += bp + si;
+ break;
+ case 3:
+ modrm_ea += bp + di;
+ break;
+ case 4:
+ modrm_ea += si;
+ break;
+ case 5:
+ modrm_ea += di;
+ break;
+ case 6:
+ if (modrm_mod != 0)
+ modrm_ea += bp;
+ break;
+ case 7:
+ modrm_ea += bx;
+ break;
+ }
+ if (modrm_rm == 2 || modrm_rm == 3 ||
+ (modrm_rm == 6 && modrm_mod != 0))
+ if (!override_base)
+ override_base = &ctxt->ss_base;
+ modrm_ea = (u16)modrm_ea;
+ } else {
+ /* 32/64-bit ModR/M decode. */
+ switch (modrm_rm) {
+ case 4:
+ case 12:
+ sib = insn_fetch(u8, 1, _eip);
+ index_reg |= (sib >> 3) & 7;
+ base_reg |= sib & 7;
+ scale = sib >> 6;
+
+ switch (base_reg) {
+ case 5:
+ if (modrm_mod != 0)
+ modrm_ea += _regs[base_reg];
+ else
+ modrm_ea += insn_fetch(s32, 4, _eip);
+ break;
+ default:
+ modrm_ea += _regs[base_reg];
+ }
+ switch (index_reg) {
+ case 4:
+ break;
+ default:
+ modrm_ea += _regs[index_reg] << scale;
+
+ }
+ break;
+ case 5:
+ if (modrm_mod != 0)
+ modrm_ea += _regs[modrm_rm];
+ else if (mode == X86EMUL_MODE_PROT64)
+ rip_relative = 1;
+ break;
+ default:
+ modrm_ea += _regs[modrm_rm];
+ break;
+ }
+ switch (modrm_mod) {
+ case 0:
+ if (modrm_rm == 5)
+ modrm_ea += insn_fetch(s32, 4, _eip);
+ break;
+ case 1:
+ modrm_ea += insn_fetch(s8, 1, _eip);
+ break;
+ case 2:
+ modrm_ea += insn_fetch(s32, 4, _eip);
+ break;
+ }
+ }
+ if (!override_base)
+ override_base = &ctxt->ds_base;
+ if (mode == X86EMUL_MODE_PROT64 &&
+ override_base != &ctxt->fs_base &&
+ override_base != &ctxt->gs_base)
+ override_base = NULL;
+
+ if (override_base)
+ modrm_ea += *override_base;
+
+ if (rip_relative) {
+ modrm_ea += _eip;
+ switch (d & SrcMask) {
+ case SrcImmByte:
+ modrm_ea += 1;
+ break;
+ case SrcImm:
+ if (d & ByteOp)
+ modrm_ea += 1;
+ else
+ if (op_bytes == 8)
+ modrm_ea += 4;
+ else
+ modrm_ea += op_bytes;
+ }
+ }
+ if (ad_bytes != 8)
+ modrm_ea = (u32)modrm_ea;
+ cr2 = modrm_ea;
+ modrm_done:
+ ;
+ }
+
+ /*
+ * Decode and fetch the source operand: register, memory
+ * or immediate.
+ */
+ switch (d & SrcMask) {
+ case SrcNone:
+ break;
+ case SrcReg:
+ src.type = OP_REG;
+ if (d & ByteOp) {
+ src.ptr = decode_register(modrm_reg, _regs,
+ (rex_prefix == 0));
+ src.val = src.orig_val = *(u8 *) src.ptr;
+ src.bytes = 1;
+ } else {
+ src.ptr = decode_register(modrm_reg, _regs, 0);
+ switch ((src.bytes = op_bytes)) {
+ case 2:
+ src.val = src.orig_val = *(u16 *) src.ptr;
+ break;
+ case 4:
+ src.val = src.orig_val = *(u32 *) src.ptr;
+ break;
+ case 8:
+ src.val = src.orig_val = *(u64 *) src.ptr;
+ break;
+ }
+ }
+ break;
+ case SrcMem16:
+ src.bytes = 2;
+ goto srcmem_common;
+ case SrcMem32:
+ src.bytes = 4;
+ goto srcmem_common;
+ case SrcMem:
+ src.bytes = (d & ByteOp) ? 1 : op_bytes;
+ srcmem_common:
+ src.type = OP_MEM;
+ src.ptr = (unsigned long *)cr2;
+ if ((rc = ops->read_emulated((unsigned long)src.ptr,
+ &src.val, src.bytes, ctxt)) != 0)
+ goto done;
+ src.orig_val = src.val;
+ break;
+ case SrcImm:
+ src.type = OP_IMM;
+ src.ptr = (unsigned long *)_eip;
+ src.bytes = (d & ByteOp) ? 1 : op_bytes;
+ if (src.bytes == 8)
+ src.bytes = 4;
+ /* NB. Immediates are sign-extended as necessary. */
+ switch (src.bytes) {
+ case 1:
+ src.val = insn_fetch(s8, 1, _eip);
+ break;
+ case 2:
+ src.val = insn_fetch(s16, 2, _eip);
+ break;
+ case 4:
+ src.val = insn_fetch(s32, 4, _eip);
+ break;
+ }
+ break;
+ case SrcImmByte:
+ src.type = OP_IMM;
+ src.ptr = (unsigned long *)_eip;
+ src.bytes = 1;
+ src.val = insn_fetch(s8, 1, _eip);
+ break;
+ }
+
+ /* Decode and fetch the destination operand: register or memory. */
+ switch (d & DstMask) {
+ case ImplicitOps:
+ /* Special instructions do their own operand decoding. */
+ goto special_insn;
+ case DstReg:
+ dst.type = OP_REG;
+ if ((d & ByteOp)
+ && !(twobyte_table && (b == 0xb6 || b == 0xb7))) {
+ dst.ptr = decode_register(modrm_reg, _regs,
+ (rex_prefix == 0));
+ dst.val = *(u8 *) dst.ptr;
+ dst.bytes = 1;
+ } else {
+ dst.ptr = decode_register(modrm_reg, _regs, 0);
+ switch ((dst.bytes = op_bytes)) {
+ case 2:
+ dst.val = *(u16 *)dst.ptr;
+ break;
+ case 4:
+ dst.val = *(u32 *)dst.ptr;
+ break;
+ case 8:
+ dst.val = *(u64 *)dst.ptr;
+ break;
+ }
+ }
+ break;
+ case DstMem:
+ dst.type = OP_MEM;
+ dst.ptr = (unsigned long *)cr2;
+ dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+ if (d & BitOp) {
+ dst.ptr += src.val / BITS_PER_LONG;
+ dst.bytes = sizeof(long);
+ }
+ if (!(d & Mov) && /* optimisation - avoid slow emulated read */
+ ((rc = ops->read_emulated((unsigned long)dst.ptr,
+ &dst.val, dst.bytes, ctxt)) != 0))
+ goto done;
+ break;
+ }
+ dst.orig_val = dst.val;
+
+ if (twobyte)
+ goto twobyte_insn;
+
+ switch (b) {
+ case 0x00 ... 0x05:
+ add: /* add */
+ emulate_2op_SrcV("add", src, dst, _eflags);
+ break;
+ case 0x08 ... 0x0d:
+ or: /* or */
+ emulate_2op_SrcV("or", src, dst, _eflags);
+ break;
+ case 0x10 ... 0x15:
+ adc: /* adc */
+ emulate_2op_SrcV("adc", src, dst, _eflags);
+ break;
+ case 0x18 ... 0x1d:
+ sbb: /* sbb */
+ emulate_2op_SrcV("sbb", src, dst, _eflags);
+ break;
+ case 0x20 ... 0x25:
+ and: /* and */
+ emulate_2op_SrcV("and", src, dst, _eflags);
+ break;
+ case 0x28 ... 0x2d:
+ sub: /* sub */
+ emulate_2op_SrcV("sub", src, dst, _eflags);
+ break;
+ case 0x30 ... 0x35:
+ xor: /* xor */
+ emulate_2op_SrcV("xor", src, dst, _eflags);
+ break;
+ case 0x38 ... 0x3d:
+ cmp: /* cmp */
+ emulate_2op_SrcV("cmp", src, dst, _eflags);
+ break;
+ case 0x63: /* movsxd */
+ if (mode != X86EMUL_MODE_PROT64)
+ goto cannot_emulate;
+ dst.val = (s32) src.val;
+ break;
+ case 0x80 ... 0x83: /* Grp1 */
+ switch (modrm_reg) {
+ case 0:
+ goto add;
+ case 1:
+ goto or;
+ case 2:
+ goto adc;
+ case 3:
+ goto sbb;
+ case 4:
+ goto and;
+ case 5:
+ goto sub;
+ case 6:
+ goto xor;
+ case 7:
+ goto cmp;
+ }
+ break;
+ case 0x84 ... 0x85:
+ test: /* test */
+ emulate_2op_SrcV("test", src, dst, _eflags);
+ break;
+ case 0x86 ... 0x87: /* xchg */
+ /* Write back the register source. */
+ switch (dst.bytes) {
+ case 1:
+ *(u8 *) src.ptr = (u8) dst.val;
+ break;
+ case 2:
+ *(u16 *) src.ptr = (u16) dst.val;
+ break;
+ case 4:
+ *src.ptr = (u32) dst.val;
+ break; /* 64b reg: zero-extend */
+ case 8:
+ *src.ptr = dst.val;
+ break;
+ }
+ /*
+ * Write back the memory destination with implicit LOCK
+ * prefix.
+ */
+ dst.val = src.val;
+ lock_prefix = 1;
+ break;
+ case 0xa0 ... 0xa1: /* mov */
+ dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
+ dst.val = src.val;
+ _eip += ad_bytes; /* skip src displacement */
+ break;
+ case 0xa2 ... 0xa3: /* mov */
+ dst.val = (unsigned long)_regs[VCPU_REGS_RAX];
+ _eip += ad_bytes; /* skip dst displacement */
+ break;
+ case 0x88 ... 0x8b: /* mov */
+ case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
+ dst.val = src.val;
+ break;
+ case 0x8f: /* pop (sole member of Grp1a) */
+ /* 64-bit mode: POP always pops a 64-bit operand. */
+ if (mode == X86EMUL_MODE_PROT64)
+ dst.bytes = 8;
+ if ((rc = ops->read_std(register_address(ctxt->ss_base,
+ _regs[VCPU_REGS_RSP]),
+ &dst.val, dst.bytes, ctxt)) != 0)
+ goto done;
+ register_address_increment(_regs[VCPU_REGS_RSP], dst.bytes);
+ break;
+ case 0xc0 ... 0xc1:
+ grp2: /* Grp2 */
+ switch (modrm_reg) {
+ case 0: /* rol */
+ emulate_2op_SrcB("rol", src, dst, _eflags);
+ break;
+ case 1: /* ror */
+ emulate_2op_SrcB("ror", src, dst, _eflags);
+ break;
+ case 2: /* rcl */
+ emulate_2op_SrcB("rcl", src, dst, _eflags);
+ break;
+ case 3: /* rcr */
+ emulate_2op_SrcB("rcr", src, dst, _eflags);
+ break;
+ case 4: /* sal/shl */
+ case 6: /* sal/shl */
+ emulate_2op_SrcB("sal", src, dst, _eflags);
+ break;
+ case 5: /* shr */
+ emulate_2op_SrcB("shr", src, dst, _eflags);
+ break;
+ case 7: /* sar */
+ emulate_2op_SrcB("sar", src, dst, _eflags);
+ break;
+ }
+ break;
+ case 0xd0 ... 0xd1: /* Grp2 */
+ src.val = 1;
+ goto grp2;
+ case 0xd2 ... 0xd3: /* Grp2 */
+ src.val = _regs[VCPU_REGS_RCX];
+ goto grp2;
+ case 0xf6 ... 0xf7: /* Grp3 */
+ switch (modrm_reg) {
+ case 0 ... 1: /* test */
+ /*
+ * Special case in Grp3: test has an immediate
+ * source operand.
+ */
+ src.type = OP_IMM;
+ src.ptr = (unsigned long *)_eip;
+ src.bytes = (d & ByteOp) ? 1 : op_bytes;
+ if (src.bytes == 8)
+ src.bytes = 4;
+ switch (src.bytes) {
+ case 1:
+ src.val = insn_fetch(s8, 1, _eip);
+ break;
+ case 2:
+ src.val = insn_fetch(s16, 2, _eip);
+ break;
+ case 4:
+ src.val = insn_fetch(s32, 4, _eip);
+ break;
+ }
+ goto test;
+ case 2: /* not */
+ dst.val = ~dst.val;
+ break;
+ case 3: /* neg */
+ emulate_1op("neg", dst, _eflags);
+ break;
+ default:
+ goto cannot_emulate;
+ }
+ break;
+ case 0xfe ... 0xff: /* Grp4/Grp5 */
+ switch (modrm_reg) {
+ case 0: /* inc */
+ emulate_1op("inc", dst, _eflags);
+ break;
+ case 1: /* dec */
+ emulate_1op("dec", dst, _eflags);
+ break;
+ case 6: /* push */
+ /* 64-bit mode: PUSH always pushes a 64-bit operand. */
+ if (mode == X86EMUL_MODE_PROT64) {
+ dst.bytes = 8;
+ if ((rc = ops->read_std((unsigned long)dst.ptr,
+ &dst.val, 8,
+ ctxt)) != 0)
+ goto done;
+ }
+ register_address_increment(_regs[VCPU_REGS_RSP],
+ -dst.bytes);
+ if ((rc = ops->write_std(
+ register_address(ctxt->ss_base,
+ _regs[VCPU_REGS_RSP]),
+ dst.val, dst.bytes, ctxt)) != 0)
+ goto done;
+ dst.val = dst.orig_val; /* skanky: disable writeback */
+ break;
+ default:
+ goto cannot_emulate;
+ }
+ break;
+ }
+
+writeback:
+ if ((d & Mov) || (dst.orig_val != dst.val)) {
+ switch (dst.type) {
+ case OP_REG:
+ /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
+ switch (dst.bytes) {
+ case 1:
+ *(u8 *)dst.ptr = (u8)dst.val;
+ break;
+ case 2:
+ *(u16 *)dst.ptr = (u16)dst.val;
+ break;
+ case 4:
+ *dst.ptr = (u32)dst.val;
+ break; /* 64b: zero-ext */
+ case 8:
+ *dst.ptr = dst.val;
+ break;
+ }
+ break;
+ case OP_MEM:
+ if (lock_prefix)
+ rc = ops->cmpxchg_emulated((unsigned long)dst.
+ ptr, dst.orig_val,
+ dst.val, dst.bytes,
+ ctxt);
+ else
+ rc = ops->write_emulated((unsigned long)dst.ptr,
+ dst.val, dst.bytes,
+ ctxt);
+ if (rc != 0)
+ goto done;
+ default:
+ break;
+ }
+ }
+
+ /* Commit shadow register state. */
+ memcpy(ctxt->vcpu->regs, _regs, sizeof _regs);
+ ctxt->eflags = _eflags;
+ ctxt->vcpu->rip = _eip;
+
+done:
+ return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+
+special_insn:
+ if (twobyte)
+ goto twobyte_special_insn;
+ if (rep_prefix) {
+ if (_regs[VCPU_REGS_RCX] == 0) {
+ ctxt->vcpu->rip = _eip;
+ goto done;
+ }
+ _regs[VCPU_REGS_RCX]--;
+ _eip = ctxt->vcpu->rip;
+ }
+ switch (b) {
+ case 0xa4 ... 0xa5: /* movs */
+ dst.type = OP_MEM;
+ dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+ dst.ptr = (unsigned long *)register_address(ctxt->es_base,
+ _regs[VCPU_REGS_RDI]);
+ if ((rc = ops->read_emulated(register_address(
+ override_base ? *override_base : ctxt->ds_base,
+ _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt)) != 0)
+ goto done;
+ register_address_increment(_regs[VCPU_REGS_RSI],
+ (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+ register_address_increment(_regs[VCPU_REGS_RDI],
+ (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+ break;
+ case 0xa6 ... 0xa7: /* cmps */
+ DPRINTF("Urk! I don't handle CMPS.\n");
+ goto cannot_emulate;
+ case 0xaa ... 0xab: /* stos */
+ dst.type = OP_MEM;
+ dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+ dst.ptr = (unsigned long *)cr2;
+ dst.val = _regs[VCPU_REGS_RAX];
+ register_address_increment(_regs[VCPU_REGS_RDI],
+ (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+ break;
+ case 0xac ... 0xad: /* lods */
+ dst.type = OP_REG;
+ dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+ dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
+ if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt)) != 0)
+ goto done;
+ register_address_increment(_regs[VCPU_REGS_RSI],
+ (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+ break;
+ case 0xae ... 0xaf: /* scas */
+ DPRINTF("Urk! I don't handle SCAS.\n");
+ goto cannot_emulate;
+ }
+ goto writeback;
+
+twobyte_insn:
+ switch (b) {
+ case 0x01: /* lgdt, lidt, lmsw */
+ switch (modrm_reg) {
+ u16 size;
+ unsigned long address;
+
+ case 2: /* lgdt */
+ rc = read_descriptor(ctxt, ops, src.ptr,
+ &size, &address, op_bytes);
+ if (rc)
+ goto done;
+ realmode_lgdt(ctxt->vcpu, size, address);
+ break;
+ case 3: /* lidt */
+ rc = read_descriptor(ctxt, ops, src.ptr,
+ &size, &address, op_bytes);
+ if (rc)
+ goto done;
+ realmode_lidt(ctxt->vcpu, size, address);
+ break;
+ case 4: /* smsw */
+ if (modrm_mod != 3)
+ goto cannot_emulate;
+ *(u16 *)&_regs[modrm_rm]
+ = realmode_get_cr(ctxt->vcpu, 0);
+ break;
+ case 6: /* lmsw */
+ if (modrm_mod != 3)
+ goto cannot_emulate;
+ realmode_lmsw(ctxt->vcpu, (u16)modrm_val, &_eflags);
+ break;
+ case 7: /* invlpg*/
+ emulate_invlpg(ctxt->vcpu, cr2);
+ break;
+ default:
+ goto cannot_emulate;
+ }
+ break;
+ case 0x21: /* mov from dr to reg */
+ if (modrm_mod != 3)
+ goto cannot_emulate;
+ rc = emulator_get_dr(ctxt, modrm_reg, &_regs[modrm_rm]);
+ break;
+ case 0x23: /* mov from reg to dr */
+ if (modrm_mod != 3)
+ goto cannot_emulate;
+ rc = emulator_set_dr(ctxt, modrm_reg, _regs[modrm_rm]);
+ break;
+ case 0x40 ... 0x4f: /* cmov */
+ dst.val = dst.orig_val = src.val;
+ d &= ~Mov; /* default to no move */
+ /*
+ * First, assume we're decoding an even cmov opcode
+ * (lsb == 0).
+ */
+ switch ((b & 15) >> 1) {
+ case 0: /* cmovo */
+ d |= (_eflags & EFLG_OF) ? Mov : 0;
+ break;
+ case 1: /* cmovb/cmovc/cmovnae */
+ d |= (_eflags & EFLG_CF) ? Mov : 0;
+ break;
+ case 2: /* cmovz/cmove */
+ d |= (_eflags & EFLG_ZF) ? Mov : 0;
+ break;
+ case 3: /* cmovbe/cmovna */
+ d |= (_eflags & (EFLG_CF | EFLG_ZF)) ? Mov : 0;
+ break;
+ case 4: /* cmovs */
+ d |= (_eflags & EFLG_SF) ? Mov : 0;
+ break;
+ case 5: /* cmovp/cmovpe */
+ d |= (_eflags & EFLG_PF) ? Mov : 0;
+ break;
+ case 7: /* cmovle/cmovng */
+ d |= (_eflags & EFLG_ZF) ? Mov : 0;
+ /* fall through */
+ case 6: /* cmovl/cmovnge */
+ d |= (!(_eflags & EFLG_SF) !=
+ !(_eflags & EFLG_OF)) ? Mov : 0;
+ break;
+ }
+ /* Odd cmov opcodes (lsb == 1) have inverted sense. */
+ d ^= (b & 1) ? Mov : 0;
+ break;
+ case 0xb0 ... 0xb1: /* cmpxchg */
+ /*
+ * Save real source value, then compare EAX against
+ * destination.
+ */
+ src.orig_val = src.val;
+ src.val = _regs[VCPU_REGS_RAX];
+ emulate_2op_SrcV("cmp", src, dst, _eflags);
+ /* Always write back. The question is: where to? */
+ d |= Mov;
+ if (_eflags & EFLG_ZF) {
+ /* Success: write back to memory. */
+ dst.val = src.orig_val;
+ } else {
+ /* Failure: write the value we saw to EAX. */
+ dst.type = OP_REG;
+ dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
+ }
+ break;
+ case 0xa3:
+ bt: /* bt */
+ src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+ emulate_2op_SrcV_nobyte("bt", src, dst, _eflags);
+ break;
+ case 0xb3:
+ btr: /* btr */
+ src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+ emulate_2op_SrcV_nobyte("btr", src, dst, _eflags);
+ break;
+ case 0xab:
+ bts: /* bts */
+ src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+ emulate_2op_SrcV_nobyte("bts", src, dst, _eflags);
+ break;
+ case 0xb6 ... 0xb7: /* movzx */
+ dst.bytes = op_bytes;
+ dst.val = (d & ByteOp) ? (u8) src.val : (u16) src.val;
+ break;
+ case 0xbb:
+ btc: /* btc */
+ src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+ emulate_2op_SrcV_nobyte("btc", src, dst, _eflags);
+ break;
+ case 0xba: /* Grp8 */
+ switch (modrm_reg & 3) {
+ case 0:
+ goto bt;
+ case 1:
+ goto bts;
+ case 2:
+ goto btr;
+ case 3:
+ goto btc;
+ }
+ break;
+ case 0xbe ... 0xbf: /* movsx */
+ dst.bytes = op_bytes;
+ dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val;
+ break;
+ }
+ goto writeback;
+
+twobyte_special_insn:
+ /* Disable writeback. */
+ dst.orig_val = dst.val;
+ switch (b) {
+ case 0x0d: /* GrpP (prefetch) */
+ case 0x18: /* Grp16 (prefetch/nop) */
+ break;
+ case 0x06:
+ emulate_clts(ctxt->vcpu);
+ break;
+ case 0x20: /* mov cr, reg */
+ if (modrm_mod != 3)
+ goto cannot_emulate;
+ _regs[modrm_rm] = realmode_get_cr(ctxt->vcpu, modrm_reg);
+ break;
+ case 0x22: /* mov reg, cr */
+ if (modrm_mod != 3)
+ goto cannot_emulate;
+ realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
+ break;
+ case 0xc7: /* Grp9 (cmpxchg8b) */
+#if defined(__i386__)
+ {
+ unsigned long old_lo, old_hi;
+ if (((rc = ops->read_emulated(cr2 + 0, &old_lo, 4,
+ ctxt)) != 0)
+ || ((rc = ops->read_emulated(cr2 + 4, &old_hi, 4,
+ ctxt)) != 0))
+ goto done;
+ if ((old_lo != _regs[VCPU_REGS_RAX])
+ || (old_hi != _regs[VCPU_REGS_RDX])) {
+ _regs[VCPU_REGS_RAX] = old_lo;
+ _regs[VCPU_REGS_RDX] = old_hi;
+ _eflags &= ~EFLG_ZF;
+ } else if (ops->cmpxchg8b_emulated == NULL) {
+ rc = X86EMUL_UNHANDLEABLE;
+ goto done;
+ } else {
+ if ((rc = ops->cmpxchg8b_emulated(cr2, old_lo,
+ old_hi,
+ _regs[VCPU_REGS_RBX],
+ _regs[VCPU_REGS_RCX],
+ ctxt)) != 0)
+ goto done;
+ _eflags |= EFLG_ZF;
+ }
+ break;
+ }
+#elif defined(CONFIG_X86_64)
+ {
+ unsigned long old, new;
+ if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0)
+ goto done;
+ if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) ||
+ ((u32) (old >> 32) != (u32) _regs[VCPU_REGS_RDX])) {
+ _regs[VCPU_REGS_RAX] = (u32) (old >> 0);
+ _regs[VCPU_REGS_RDX] = (u32) (old >> 32);
+ _eflags &= ~EFLG_ZF;
+ } else {
+ new = (_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX];
+ if ((rc = ops->cmpxchg_emulated(cr2, old,
+ new, 8, ctxt)) != 0)
+ goto done;
+ _eflags |= EFLG_ZF;
+ }
+ break;
+ }
+#endif
+ }
+ goto writeback;
+
+cannot_emulate:
+ DPRINTF("Cannot emulate %02x\n", b);
+ return -1;
+}
+
+#ifdef __XEN__
+
+#include <asm/mm.h>
+#include <asm/uaccess.h>
+
+int
+x86_emulate_read_std(unsigned long addr,
+ unsigned long *val,
+ unsigned int bytes, struct x86_emulate_ctxt *ctxt)
+{
+ unsigned int rc;
+
+ *val = 0;
+
+ if ((rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0) {
+ propagate_page_fault(addr + bytes - rc, 0); /* read fault */
+ return X86EMUL_PROPAGATE_FAULT;
+ }
+
+ return X86EMUL_CONTINUE;
+}
+
+int
+x86_emulate_write_std(unsigned long addr,
+ unsigned long val,
+ unsigned int bytes, struct x86_emulate_ctxt *ctxt)
+{
+ unsigned int rc;
+
+ if ((rc = copy_to_user((void *)addr, (void *)&val, bytes)) != 0) {
+ propagate_page_fault(addr + bytes - rc, PGERR_write_access);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
+
+ return X86EMUL_CONTINUE;
+}
+
+#endif
diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h
new file mode 100644
index 00000000000..5d41bd55125
--- /dev/null
+++ b/drivers/kvm/x86_emulate.h
@@ -0,0 +1,185 @@
+/******************************************************************************
+ * x86_emulate.h
+ *
+ * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
+ *
+ * Copyright (c) 2005 Keir Fraser
+ *
+ * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4
+ */
+
+#ifndef __X86_EMULATE_H__
+#define __X86_EMULATE_H__
+
+struct x86_emulate_ctxt;
+
+/*
+ * x86_emulate_ops:
+ *
+ * These operations represent the instruction emulator's interface to memory.
+ * There are two categories of operation: those that act on ordinary memory
+ * regions (*_std), and those that act on memory regions known to require
+ * special treatment or emulation (*_emulated).
+ *
+ * The emulator assumes that an instruction accesses only one 'emulated memory'
+ * location, that this location is the given linear faulting address (cr2), and
+ * that this is one of the instruction's data operands. Instruction fetches and
+ * stack operations are assumed never to access emulated memory. The emulator
+ * automatically deduces which operand of a string-move operation is accessing
+ * emulated memory, and assumes that the other operand accesses normal memory.
+ *
+ * NOTES:
+ * 1. The emulator isn't very smart about emulated vs. standard memory.
+ * 'Emulated memory' access addresses should be checked for sanity.
+ * 'Normal memory' accesses may fault, and the caller must arrange to
+ * detect and handle reentrancy into the emulator via recursive faults.
+ * Accesses may be unaligned and may cross page boundaries.
+ * 2. If the access fails (cannot emulate, or a standard access faults) then
+ * it is up to the memop to propagate the fault to the guest VM via
+ * some out-of-band mechanism, unknown to the emulator. The memop signals
+ * failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will
+ * then immediately bail.
+ * 3. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only
+ * cmpxchg8b_emulated need support 8-byte accesses.
+ * 4. The emulator cannot handle 64-bit mode emulation on an x86/32 system.
+ */
+/* Access completed successfully: continue emulation as normal. */
+#define X86EMUL_CONTINUE 0
+/* Access is unhandleable: bail from emulation and return error to caller. */
+#define X86EMUL_UNHANDLEABLE 1
+/* Terminate emulation but return success to the caller. */
+#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */
+#define X86EMUL_RETRY_INSTR 2 /* retry the instruction for some reason */
+#define X86EMUL_CMPXCHG_FAILED 2 /* cmpxchg did not see expected value */
+struct x86_emulate_ops {
+ /*
+ * read_std: Read bytes of standard (non-emulated/special) memory.
+ * Used for instruction fetch, stack operations, and others.
+ * @addr: [IN ] Linear address from which to read.
+ * @val: [OUT] Value read from memory, zero-extended to 'u_long'.
+ * @bytes: [IN ] Number of bytes to read from memory.
+ */
+ int (*read_std)(unsigned long addr,
+ unsigned long *val,
+ unsigned int bytes, struct x86_emulate_ctxt * ctxt);
+
+ /*
+ * write_std: Write bytes of standard (non-emulated/special) memory.
+ * Used for stack operations, and others.
+ * @addr: [IN ] Linear address to which to write.
+ * @val: [IN ] Value to write to memory (low-order bytes used as
+ * required).
+ * @bytes: [IN ] Number of bytes to write to memory.
+ */
+ int (*write_std)(unsigned long addr,
+ unsigned long val,
+ unsigned int bytes, struct x86_emulate_ctxt * ctxt);
+
+ /*
+ * read_emulated: Read bytes from emulated/special memory area.
+ * @addr: [IN ] Linear address from which to read.
+ * @val: [OUT] Value read from memory, zero-extended to 'u_long'.
+ * @bytes: [IN ] Number of bytes to read from memory.
+ */
+ int (*read_emulated) (unsigned long addr,
+ unsigned long *val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt * ctxt);
+
+ /*
+ * write_emulated: Read bytes from emulated/special memory area.
+ * @addr: [IN ] Linear address to which to write.
+ * @val: [IN ] Value to write to memory (low-order bytes used as
+ * required).
+ * @bytes: [IN ] Number of bytes to write to memory.
+ */
+ int (*write_emulated) (unsigned long addr,
+ unsigned long val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt * ctxt);
+
+ /*
+ * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an
+ * emulated/special memory area.
+ * @addr: [IN ] Linear address to access.
+ * @old: [IN ] Value expected to be current at @addr.
+ * @new: [IN ] Value to write to @addr.
+ * @bytes: [IN ] Number of bytes to access using CMPXCHG.
+ */
+ int (*cmpxchg_emulated) (unsigned long addr,
+ unsigned long old,
+ unsigned long new,
+ unsigned int bytes,
+ struct x86_emulate_ctxt * ctxt);
+
+ /*
+ * cmpxchg8b_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an
+ * emulated/special memory area.
+ * @addr: [IN ] Linear address to access.
+ * @old: [IN ] Value expected to be current at @addr.
+ * @new: [IN ] Value to write to @addr.
+ * NOTES:
+ * 1. This function is only ever called when emulating a real CMPXCHG8B.
+ * 2. This function is *never* called on x86/64 systems.
+ * 2. Not defining this function (i.e., specifying NULL) is equivalent
+ * to defining a function that always returns X86EMUL_UNHANDLEABLE.
+ */
+ int (*cmpxchg8b_emulated) (unsigned long addr,
+ unsigned long old_lo,
+ unsigned long old_hi,
+ unsigned long new_lo,
+ unsigned long new_hi,
+ struct x86_emulate_ctxt * ctxt);
+};
+
+struct cpu_user_regs;
+
+struct x86_emulate_ctxt {
+ /* Register state before/after emulation. */
+ struct kvm_vcpu *vcpu;
+
+ /* Linear faulting address (if emulating a page-faulting instruction). */
+ unsigned long eflags;
+ unsigned long cr2;
+
+ /* Emulated execution mode, represented by an X86EMUL_MODE value. */
+ int mode;
+
+ unsigned long cs_base;
+ unsigned long ds_base;
+ unsigned long es_base;
+ unsigned long ss_base;
+ unsigned long gs_base;
+ unsigned long fs_base;
+};
+
+/* Execution mode, passed to the emulator. */
+#define X86EMUL_MODE_REAL 0 /* Real mode. */
+#define X86EMUL_MODE_PROT16 2 /* 16-bit protected mode. */
+#define X86EMUL_MODE_PROT32 4 /* 32-bit protected mode. */
+#define X86EMUL_MODE_PROT64 8 /* 64-bit (long) mode. */
+
+/* Host execution mode. */
+#if defined(__i386__)
+#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32
+#elif defined(CONFIG_X86_64)
+#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64
+#endif
+
+/*
+ * x86_emulate_memop: Emulate an instruction that faulted attempting to
+ * read/write a 'special' memory area.
+ * Returns -1 on failure, 0 on success.
+ */
+int x86_emulate_memop(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops);
+
+/*
+ * Given the 'reg' portion of a ModRM byte, and a register block, return a
+ * pointer into the block that addresses the relevant register.
+ * @highbyte_regs specifies whether to decode AH,CH,DH,BH.
+ */
+void *decode_register(u8 modrm_reg, unsigned long *regs,
+ int highbyte_regs);
+
+#endif /* __X86_EMULATE_H__ */
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 176142c6149..7399ba79111 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -12,7 +12,7 @@ config NEW_LEDS
config LEDS_CLASS
tristate "LED Class Support"
- depends NEW_LEDS
+ depends on NEW_LEDS
help
This option enables the led sysfs class in /sys/class/leds. You'll
need this to do anything useful with LEDs. If unsure, say N.
@@ -21,28 +21,28 @@ comment "LED drivers"
config LEDS_CORGI
tristate "LED Support for the Sharp SL-C7x0 series"
- depends LEDS_CLASS && PXA_SHARP_C7xx
+ depends on LEDS_CLASS && PXA_SHARP_C7xx
help
This option enables support for the LEDs on Sharp Zaurus
SL-C7x0 series (C700, C750, C760, C860).
config LEDS_LOCOMO
tristate "LED Support for Locomo device"
- depends LEDS_CLASS && SHARP_LOCOMO
+ depends on LEDS_CLASS && SHARP_LOCOMO
help
This option enables support for the LEDs on Sharp Locomo.
Zaurus models SL-5500 and SL-5600.
config LEDS_SPITZ
tristate "LED Support for the Sharp SL-Cxx00 series"
- depends LEDS_CLASS && PXA_SHARP_Cxx00
+ depends on LEDS_CLASS && PXA_SHARP_Cxx00
help
This option enables support for the LEDs on Sharp Zaurus
SL-Cxx00 series (C1000, C3000, C3100).
config LEDS_IXP4XX
tristate "LED Support for GPIO connected LEDs on IXP4XX processors"
- depends LEDS_CLASS && ARCH_IXP4XX
+ depends on LEDS_CLASS && ARCH_IXP4XX
help
This option enables support for the LEDs connected to GPIO
outputs of the Intel IXP4XX processors. To be useful the
@@ -51,7 +51,7 @@ config LEDS_IXP4XX
config LEDS_TOSA
tristate "LED Support for the Sharp SL-6000 series"
- depends LEDS_CLASS && PXA_SHARPSL
+ depends on LEDS_CLASS && PXA_SHARPSL
help
This option enables support for the LEDs on Sharp Zaurus
SL-6000 series.
@@ -65,7 +65,7 @@ config LEDS_S3C24XX
config LEDS_AMS_DELTA
tristate "LED Support for the Amstrad Delta (E3)"
- depends LEDS_CLASS && MACH_AMS_DELTA
+ depends on LEDS_CLASS && MACH_AMS_DELTA
help
This option enables support for the LEDs on Amstrad Delta (E3).
@@ -86,7 +86,7 @@ comment "LED Triggers"
config LEDS_TRIGGERS
bool "LED Trigger support"
- depends NEW_LEDS
+ depends on NEW_LEDS
help
This option enables trigger support for the leds class.
These triggers allow kernel events to drive the LEDs and can
@@ -94,21 +94,21 @@ config LEDS_TRIGGERS
config LEDS_TRIGGER_TIMER
tristate "LED Timer Trigger"
- depends LEDS_TRIGGERS
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be controlled by a programmable timer
via sysfs. If unsure, say Y.
config LEDS_TRIGGER_IDE_DISK
bool "LED IDE Disk Trigger"
- depends LEDS_TRIGGERS && BLK_DEV_IDEDISK
+ depends on LEDS_TRIGGERS && BLK_DEV_IDEDISK
help
This allows LEDs to be controlled by IDE disk activity.
If unsure, say Y.
config LEDS_TRIGGER_HEARTBEAT
tristate "LED Heartbeat Trigger"
- depends LEDS_TRIGGERS
+ depends on LEDS_TRIGGERS
help
This allows LEDs to be controlled by a CPU load average.
The flash frequency is a hyperbolic function of the 1-minute
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index fb1edc1c9ed..50914439d86 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -16,7 +16,7 @@
#include <linux/platform_device.h>
#include <linux/leds.h>
-#include <asm/arch/hardware.h>
+#include <asm/hardware.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/leds-gpio.h>
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index a9e747c3979..1a86387e23b 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -1,6 +1,6 @@
menu "Macintosh device drivers"
- depends on PPC || MAC
+ depends on PPC || MAC || X86
config ADB
bool "Apple Desktop Bus (ADB) support"
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index d43ea81d6df..7cec6de5e2b 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -828,7 +828,7 @@ static ssize_t adb_write(struct file *file, const char __user *buf,
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
- req = (struct adb_request *) kmalloc(sizeof(struct adb_request),
+ req = kmalloc(sizeof(struct adb_request),
GFP_KERNEL);
if (req == NULL)
return -ENOMEM;
diff --git a/drivers/macintosh/apm_emu.c b/drivers/macintosh/apm_emu.c
index 8862a83b8d8..4300c628f8a 100644
--- a/drivers/macintosh/apm_emu.c
+++ b/drivers/macintosh/apm_emu.c
@@ -321,7 +321,7 @@ static int do_open(struct inode * inode, struct file * filp)
{
struct apm_user * as;
- as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
+ as = kmalloc(sizeof(*as), GFP_KERNEL);
if (as == NULL) {
printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
sizeof(*as));
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 5ed41fe84e5..f83fad2a3ff 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -171,11 +171,11 @@ static void rackmeter_setup_dbdma(struct rackmeter *rm)
/* Make sure dbdma is reset */
DBDMA_DO_RESET(rm->dma_regs);
- pr_debug("rackmeter: mark offset=0x%lx\n",
+ pr_debug("rackmeter: mark offset=0x%zx\n",
offsetof(struct rackmeter_dma, mark));
- pr_debug("rackmeter: buf1 offset=0x%lx\n",
+ pr_debug("rackmeter: buf1 offset=0x%zx\n",
offsetof(struct rackmeter_dma, buf1));
- pr_debug("rackmeter: buf2 offset=0x%lx\n",
+ pr_debug("rackmeter: buf2 offset=0x%zx\n",
offsetof(struct rackmeter_dma, buf2));
/* Prepare 4 dbdma commands for the 2 buffers */
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 6dde27ab79a..6f30459b938 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -945,7 +945,7 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id)
*/
tlen = sizeof(struct property) + len + 18;
- prop = kcalloc(tlen, 1, GFP_KERNEL);
+ prop = kzalloc(tlen, GFP_KERNEL);
if (prop == NULL)
return NULL;
hdr = (struct smu_sdbp_header *)(prop + 1);
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
index 6c29fe727c0..801a974342f 100644
--- a/drivers/macintosh/via-pmu-backlight.c
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -147,7 +147,7 @@ void __init pmu_backlight_init()
snprintf(name, sizeof(name), "pmubl");
- bd = backlight_device_register(name, NULL, &pmu_backlight_data);
+ bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data);
if (IS_ERR(bd)) {
printk("pmubl: Backlight registration failed\n");
goto error;
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index c8558d4ed50..8ca75e52f63 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -44,6 +44,7 @@
#include <linux/sysdev.h>
#include <linux/freezer.h>
#include <linux/syscalls.h>
+#include <linux/suspend.h>
#include <linux/cpu.h>
#include <asm/prom.h>
#include <asm/machdep.h>
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index d9986f3a3fb..93e6ef9233f 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -847,7 +847,7 @@ pbook_pci_save(void)
n_pbook_pci_saves = npci;
if (npci == 0)
return;
- ps = (struct pci_save *) kmalloc(npci * sizeof(*ps), GFP_KERNEL);
+ ps = kmalloc(npci * sizeof(*ps), GFP_KERNEL);
pbook_pci_saves = ps;
if (ps == NULL)
return;
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index e947af982f9..94c117ef20c 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -94,8 +94,6 @@ static int wf_thread_func(void *data)
DBG("wf: thread started\n");
while(!kthread_should_stop()) {
- try_to_freeze();
-
if (time_after_eq(jiffies, next)) {
wf_notify(WF_EVENT_TICK, NULL);
if (wf_overtemp) {
@@ -118,8 +116,8 @@ static int wf_thread_func(void *data)
if (delay <= HZ)
schedule_timeout_interruptible(delay);
- /* there should be no signal, but oh well */
- if (signal_pending(current)) {
+ /* there should be no non-suspend signal, but oh well */
+ if (signal_pending(current) && !try_to_freeze()) {
printk(KERN_WARNING "windfarm: thread got sigl !\n");
break;
}
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index c92c1521546..4540ade6b6b 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -215,6 +215,7 @@ config DM_CRYPT
tristate "Crypt target support"
depends on BLK_DEV_DM && EXPERIMENTAL
select CRYPTO
+ select CRYPTO_CBC
---help---
This device-mapper target allows you to create a device that
transparently encrypts the data on it. You'll need to activate
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index d6f614738bb..059704fbb75 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -212,8 +212,8 @@ char *file_path(struct file *file, char *buf, int count)
if (!buf)
return NULL;
- d = file->f_dentry;
- v = file->f_vfsmnt;
+ d = file->f_path.dentry;
+ v = file->f_path.mnt;
buf = d_path(d, v, buf, count);
@@ -349,7 +349,7 @@ static struct page *read_page(struct file *file, unsigned long index,
unsigned long count)
{
struct page *page = NULL;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct buffer_head *bh;
sector_t block;
@@ -479,9 +479,12 @@ static int bitmap_read_sb(struct bitmap *bitmap)
int err = -EINVAL;
/* page 0 is the superblock, read it... */
- if (bitmap->file)
- bitmap->sb_page = read_page(bitmap->file, 0, bitmap, PAGE_SIZE);
- else {
+ if (bitmap->file) {
+ loff_t isize = i_size_read(bitmap->file->f_mapping->host);
+ int bytes = isize > PAGE_SIZE ? PAGE_SIZE : isize;
+
+ bitmap->sb_page = read_page(bitmap->file, 0, bitmap, bytes);
+ } else {
bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0);
}
if (IS_ERR(bitmap->sb_page)) {
@@ -662,7 +665,7 @@ static void bitmap_file_put(struct bitmap *bitmap)
bitmap_file_unmap(bitmap);
if (file) {
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
invalidate_inode_pages(inode->i_mapping);
fput(file);
}
@@ -877,7 +880,8 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
int count;
/* unmap the old page, we're done with it */
if (index == num_pages-1)
- count = bytes - index * PAGE_SIZE;
+ count = bytes + sizeof(bitmap_super_t)
+ - index * PAGE_SIZE;
else
count = PAGE_SIZE;
if (index == 0) {
@@ -1156,6 +1160,22 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
return 0;
}
+ if (unlikely((*bmc & COUNTER_MAX) == COUNTER_MAX)) {
+ DEFINE_WAIT(__wait);
+ /* note that it is safe to do the prepare_to_wait
+ * after the test as long as we do it before dropping
+ * the spinlock.
+ */
+ prepare_to_wait(&bitmap->overflow_wait, &__wait,
+ TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&bitmap->lock);
+ bitmap->mddev->queue
+ ->unplug_fn(bitmap->mddev->queue);
+ schedule();
+ finish_wait(&bitmap->overflow_wait, &__wait);
+ continue;
+ }
+
switch(*bmc) {
case 0:
bitmap_file_set_bit(bitmap, offset);
@@ -1165,7 +1185,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
case 1:
*bmc = 2;
}
- BUG_ON((*bmc & COUNTER_MAX) == COUNTER_MAX);
+
(*bmc)++;
spin_unlock_irq(&bitmap->lock);
@@ -1203,6 +1223,9 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
if (!success && ! (*bmc & NEEDED_MASK))
*bmc |= NEEDED_MASK;
+ if ((*bmc & COUNTER_MAX) == COUNTER_MAX)
+ wake_up(&bitmap->overflow_wait);
+
(*bmc)--;
if (*bmc <= 2) {
set_page_attr(bitmap,
@@ -1427,6 +1450,7 @@ int bitmap_create(mddev_t *mddev)
spin_lock_init(&bitmap->lock);
atomic_set(&bitmap->pending_writes, 0);
init_waitqueue_head(&bitmap->write_wait);
+ init_waitqueue_head(&bitmap->overflow_wait);
bitmap->mddev = mddev;
diff --git a/drivers/md/dm-bio-list.h b/drivers/md/dm-bio-list.h
index bbf4615f0e3..da4349649f7 100644
--- a/drivers/md/dm-bio-list.h
+++ b/drivers/md/dm-bio-list.h
@@ -44,6 +44,20 @@ static inline void bio_list_merge(struct bio_list *bl, struct bio_list *bl2)
bl->tail = bl2->tail;
}
+static inline void bio_list_merge_head(struct bio_list *bl,
+ struct bio_list *bl2)
+{
+ if (!bl2->head)
+ return;
+
+ if (bl->head)
+ bl2->tail->bi_next = bl->head;
+ else
+ bl->tail = bl2->tail;
+
+ bl->head = bl2->head;
+}
+
static inline struct bio *bio_list_pop(struct bio_list *bl)
{
struct bio *bio = bl->head;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index a1086ee8ccc..4c2471ee054 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -220,7 +220,7 @@ static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti,
const char *opts)
{
unsigned int bs = crypto_blkcipher_blocksize(cc->tfm);
- int log = long_log2(bs);
+ int log = ilog2(bs);
/* we need to calculate how far we must shift the sector count
* to get the cipher block count, we use this shift in _gen */
@@ -962,7 +962,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
atomic_set(&io->pending, 0);
kcryptd_queue_io(io);
- return 0;
+ return DM_MAPIO_SUBMITTED;
}
static int crypt_status(struct dm_target *ti, status_type_t type,
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
index 2b2d45d7baa..265c467854d 100644
--- a/drivers/md/dm-emc.c
+++ b/drivers/md/dm-emc.c
@@ -40,7 +40,7 @@ static inline void free_bio(struct bio *bio)
static int emc_endio(struct bio *bio, unsigned int bytes_done, int error)
{
- struct path *path = bio->bi_private;
+ struct dm_path *path = bio->bi_private;
if (bio->bi_size)
return 1;
@@ -61,7 +61,7 @@ static int emc_endio(struct bio *bio, unsigned int bytes_done, int error)
return 0;
}
-static struct bio *get_failover_bio(struct path *path, unsigned data_size)
+static struct bio *get_failover_bio(struct dm_path *path, unsigned data_size)
{
struct bio *bio;
struct page *page;
@@ -96,7 +96,7 @@ static struct bio *get_failover_bio(struct path *path, unsigned data_size)
}
static struct request *get_failover_req(struct emc_handler *h,
- struct bio *bio, struct path *path)
+ struct bio *bio, struct dm_path *path)
{
struct request *rq;
struct block_device *bdev = bio->bi_bdev;
@@ -133,7 +133,7 @@ static struct request *get_failover_req(struct emc_handler *h,
}
static struct request *emc_trespass_get(struct emc_handler *h,
- struct path *path)
+ struct dm_path *path)
{
struct bio *bio;
struct request *rq;
@@ -191,7 +191,7 @@ static struct request *emc_trespass_get(struct emc_handler *h,
}
static void emc_pg_init(struct hw_handler *hwh, unsigned bypassed,
- struct path *path)
+ struct dm_path *path)
{
struct request *rq;
struct request_queue *q = bdev_get_queue(path->dev->bdev);
diff --git a/drivers/md/dm-hw-handler.h b/drivers/md/dm-hw-handler.h
index 15f5629e231..32eff28e4ad 100644
--- a/drivers/md/dm-hw-handler.h
+++ b/drivers/md/dm-hw-handler.h
@@ -32,7 +32,7 @@ struct hw_handler_type {
void (*destroy) (struct hw_handler *hwh);
void (*pg_init) (struct hw_handler *hwh, unsigned bypassed,
- struct path *path);
+ struct dm_path *path);
unsigned (*error) (struct hw_handler *hwh, struct bio *bio);
int (*status) (struct hw_handler *hwh, status_type_t type,
char *result, unsigned int maxlen);
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index da663d2ff55..4eb73d39521 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -92,12 +92,12 @@ void dm_io_put(unsigned int num_pages)
*---------------------------------------------------------------*/
static inline void bio_set_region(struct bio *bio, unsigned region)
{
- bio->bi_io_vec[bio->bi_max_vecs - 1].bv_len = region;
+ bio->bi_io_vec[bio->bi_max_vecs].bv_len = region;
}
static inline unsigned bio_get_region(struct bio *bio)
{
- return bio->bi_io_vec[bio->bi_max_vecs - 1].bv_len;
+ return bio->bi_io_vec[bio->bi_max_vecs].bv_len;
}
/*-----------------------------------------------------------------
@@ -136,6 +136,7 @@ static int endio(struct bio *bio, unsigned int done, int error)
zero_fill_bio(bio);
dec_count(io, bio_get_region(bio), error);
+ bio->bi_max_vecs++;
bio_put(bio);
return 0;
@@ -250,16 +251,18 @@ static void do_region(int rw, unsigned int region, struct io_region *where,
while (remaining) {
/*
- * Allocate a suitably sized bio, we add an extra
- * bvec for bio_get/set_region().
+ * Allocate a suitably sized-bio: we add an extra
+ * bvec for bio_get/set_region() and decrement bi_max_vecs
+ * to hide it from bio_add_page().
*/
- num_bvecs = (remaining / (PAGE_SIZE >> 9)) + 2;
+ num_bvecs = (remaining / (PAGE_SIZE >> SECTOR_SHIFT)) + 2;
bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, _bios);
bio->bi_sector = where->sector + (where->count - remaining);
bio->bi_bdev = where->bdev;
bio->bi_end_io = endio;
bio->bi_private = io;
bio->bi_destructor = dm_bio_destructor;
+ bio->bi_max_vecs--;
bio_set_region(bio, region);
/*
@@ -302,7 +305,7 @@ static void dispatch_io(int rw, unsigned int num_regions,
}
/*
- * Drop the extra refence that we were holding to avoid
+ * Drop the extra reference that we were holding to avoid
* the io being completed too early.
*/
dec_count(io, 0, 0);
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 4510ad8f971..cd6a184536a 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -765,7 +765,7 @@ out:
static int do_suspend(struct dm_ioctl *param)
{
int r = 0;
- int do_lockfs = 1;
+ unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
struct mapped_device *md;
md = find_device(param);
@@ -773,10 +773,12 @@ static int do_suspend(struct dm_ioctl *param)
return -ENXIO;
if (param->flags & DM_SKIP_LOCKFS_FLAG)
- do_lockfs = 0;
+ suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
+ if (param->flags & DM_NOFLUSH_FLAG)
+ suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
if (!dm_suspended(md))
- r = dm_suspend(md, do_lockfs);
+ r = dm_suspend(md, suspend_flags);
if (!r)
r = __dev_status(md, param);
@@ -788,7 +790,7 @@ static int do_suspend(struct dm_ioctl *param)
static int do_resume(struct dm_ioctl *param)
{
int r = 0;
- int do_lockfs = 1;
+ unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
struct hash_cell *hc;
struct mapped_device *md;
struct dm_table *new_map;
@@ -814,9 +816,11 @@ static int do_resume(struct dm_ioctl *param)
if (new_map) {
/* Suspend if it isn't already suspended */
if (param->flags & DM_SKIP_LOCKFS_FLAG)
- do_lockfs = 0;
+ suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
+ if (param->flags & DM_NOFLUSH_FLAG)
+ suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
if (!dm_suspended(md))
- dm_suspend(md, do_lockfs);
+ dm_suspend(md, suspend_flags);
r = dm_swap_table(md, new_map);
if (r) {
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 00234909b3d..17753d80ad2 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -77,7 +77,7 @@ static int linear_map(struct dm_target *ti, struct bio *bio,
bio->bi_bdev = lc->dev->bdev;
bio->bi_sector = lc->start + (bio->bi_sector - ti->begin);
- return 1;
+ return DM_MAPIO_REMAPPED;
}
static int linear_status(struct dm_target *ti, status_type_t type,
@@ -108,7 +108,7 @@ static int linear_ioctl(struct dm_target *ti, struct inode *inode,
struct dentry fake_dentry = {};
fake_file.f_mode = lc->dev->mode;
- fake_file.f_dentry = &fake_dentry;
+ fake_file.f_path.dentry = &fake_dentry;
fake_dentry.d_inode = bdev->bd_inode;
return blkdev_driver_ioctl(bdev->bd_inode, &fake_file, bdev->bd_disk, cmd, arg);
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 64b764bd02c..6a926135184 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -466,6 +466,7 @@ static int disk_resume(struct dirty_log *log)
/* copy clean across to sync */
memcpy(lc->sync_bits, lc->clean_bits, size);
lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count);
+ lc->sync_search = 0;
/* set the correct number of regions in the header */
lc->header.nr_regions = lc->region_count;
@@ -480,6 +481,13 @@ static uint32_t core_get_region_size(struct dirty_log *log)
return lc->region_size;
}
+static int core_resume(struct dirty_log *log)
+{
+ struct log_c *lc = (struct log_c *) log->context;
+ lc->sync_search = 0;
+ return 0;
+}
+
static int core_is_clean(struct dirty_log *log, region_t region)
{
struct log_c *lc = (struct log_c *) log->context;
@@ -549,16 +557,19 @@ static int core_get_resync_work(struct dirty_log *log, region_t *region)
return 1;
}
-static void core_complete_resync_work(struct dirty_log *log, region_t region,
- int success)
+static void core_set_region_sync(struct dirty_log *log, region_t region,
+ int in_sync)
{
struct log_c *lc = (struct log_c *) log->context;
log_clear_bit(lc, lc->recovering_bits, region);
- if (success) {
+ if (in_sync) {
log_set_bit(lc, lc->sync_bits, region);
lc->sync_count++;
- }
+ } else if (log_test_bit(lc->sync_bits, region)) {
+ lc->sync_count--;
+ log_clear_bit(lc, lc->sync_bits, region);
+ }
}
static region_t core_get_sync_count(struct dirty_log *log)
@@ -618,6 +629,7 @@ static struct dirty_log_type _core_type = {
.module = THIS_MODULE,
.ctr = core_ctr,
.dtr = core_dtr,
+ .resume = core_resume,
.get_region_size = core_get_region_size,
.is_clean = core_is_clean,
.in_sync = core_in_sync,
@@ -625,7 +637,7 @@ static struct dirty_log_type _core_type = {
.mark_region = core_mark_region,
.clear_region = core_clear_region,
.get_resync_work = core_get_resync_work,
- .complete_resync_work = core_complete_resync_work,
+ .set_region_sync = core_set_region_sync,
.get_sync_count = core_get_sync_count,
.status = core_status,
};
@@ -644,7 +656,7 @@ static struct dirty_log_type _disk_type = {
.mark_region = core_mark_region,
.clear_region = core_clear_region,
.get_resync_work = core_get_resync_work,
- .complete_resync_work = core_complete_resync_work,
+ .set_region_sync = core_set_region_sync,
.get_sync_count = core_get_sync_count,
.status = disk_status,
};
diff --git a/drivers/md/dm-log.h b/drivers/md/dm-log.h
index 5ae5309ebf2..86a301c8daf 100644
--- a/drivers/md/dm-log.h
+++ b/drivers/md/dm-log.h
@@ -90,12 +90,12 @@ struct dirty_log_type {
int (*get_resync_work)(struct dirty_log *log, region_t *region);
/*
- * This notifies the log that the resync of an area has
- * been completed. The log should then mark this region
- * as CLEAN.
+ * This notifies the log that the resync status of a region
+ * has changed. It also clears the region from the recovering
+ * list (if present).
*/
- void (*complete_resync_work)(struct dirty_log *log,
- region_t region, int success);
+ void (*set_region_sync)(struct dirty_log *log,
+ region_t region, int in_sync);
/*
* Returns the number of regions that are in sync.
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index cf8bf052138..3aa01350696 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -31,7 +31,7 @@ struct pgpath {
struct priority_group *pg; /* Owning PG */
unsigned fail_count; /* Cumulative failure count */
- struct path path;
+ struct dm_path path;
};
#define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path)
@@ -229,7 +229,7 @@ static void __switch_pg(struct multipath *m, struct pgpath *pgpath)
static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg)
{
- struct path *path;
+ struct dm_path *path;
path = pg->ps.type->select_path(&pg->ps, &m->repeat_count);
if (!path)
@@ -282,10 +282,27 @@ failed:
m->current_pg = NULL;
}
+/*
+ * Check whether bios must be queued in the device-mapper core rather
+ * than here in the target.
+ *
+ * m->lock must be held on entry.
+ *
+ * If m->queue_if_no_path and m->saved_queue_if_no_path hold the
+ * same value then we are not between multipath_presuspend()
+ * and multipath_resume() calls and we have no need to check
+ * for the DMF_NOFLUSH_SUSPENDING flag.
+ */
+static int __must_push_back(struct multipath *m)
+{
+ return (m->queue_if_no_path != m->saved_queue_if_no_path &&
+ dm_noflush_suspending(m->ti));
+}
+
static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio,
unsigned was_queued)
{
- int r = 1;
+ int r = DM_MAPIO_REMAPPED;
unsigned long flags;
struct pgpath *pgpath;
@@ -310,11 +327,13 @@ static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio,
!m->queue_io)
queue_work(kmultipathd, &m->process_queued_ios);
pgpath = NULL;
- r = 0;
- } else if (!pgpath)
- r = -EIO; /* Failed */
- else
+ r = DM_MAPIO_SUBMITTED;
+ } else if (pgpath)
bio->bi_bdev = pgpath->path.dev->bdev;
+ else if (__must_push_back(m))
+ r = DM_MAPIO_REQUEUE;
+ else
+ r = -EIO; /* Failed */
mpio->pgpath = pgpath;
@@ -372,8 +391,10 @@ static void dispatch_queued_ios(struct multipath *m)
r = map_io(m, bio, mpio, 1);
if (r < 0)
bio_endio(bio, bio->bi_size, r);
- else if (r == 1)
+ else if (r == DM_MAPIO_REMAPPED)
generic_make_request(bio);
+ else if (r == DM_MAPIO_REQUEUE)
+ bio_endio(bio, bio->bi_size, -EIO);
bio = next;
}
@@ -783,7 +804,7 @@ static int multipath_map(struct dm_target *ti, struct bio *bio,
map_context->ptr = mpio;
bio->bi_rw |= (1 << BIO_RW_FAILFAST);
r = map_io(m, bio, mpio, 0);
- if (r < 0)
+ if (r < 0 || r == DM_MAPIO_REQUEUE)
mempool_free(mpio, m->mpio_pool);
return r;
@@ -957,7 +978,7 @@ static int bypass_pg_num(struct multipath *m, const char *pgstr, int bypassed)
/*
* pg_init must call this when it has completed its initialisation
*/
-void dm_pg_init_complete(struct path *path, unsigned err_flags)
+void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
{
struct pgpath *pgpath = path_to_pgpath(path);
struct priority_group *pg = pgpath->pg;
@@ -1007,7 +1028,10 @@ static int do_end_io(struct multipath *m, struct bio *bio,
spin_lock_irqsave(&m->lock, flags);
if (!m->nr_valid_paths) {
- if (!m->queue_if_no_path) {
+ if (__must_push_back(m)) {
+ spin_unlock_irqrestore(&m->lock, flags);
+ return DM_ENDIO_REQUEUE;
+ } else if (!m->queue_if_no_path) {
spin_unlock_irqrestore(&m->lock, flags);
return -EIO;
} else {
@@ -1042,7 +1066,7 @@ static int do_end_io(struct multipath *m, struct bio *bio,
queue_work(kmultipathd, &m->process_queued_ios);
spin_unlock_irqrestore(&m->lock, flags);
- return 1; /* io not complete */
+ return DM_ENDIO_INCOMPLETE; /* io not complete */
}
static int multipath_end_io(struct dm_target *ti, struct bio *bio,
@@ -1060,7 +1084,7 @@ static int multipath_end_io(struct dm_target *ti, struct bio *bio,
if (ps->type->end_io)
ps->type->end_io(ps, &pgpath->path);
}
- if (r <= 0)
+ if (r != DM_ENDIO_INCOMPLETE)
mempool_free(mpio, m->mpio_pool);
return r;
@@ -1272,7 +1296,7 @@ static int multipath_ioctl(struct dm_target *ti, struct inode *inode,
struct dentry fake_dentry = {};
int r = 0;
- fake_file.f_dentry = &fake_dentry;
+ fake_file.f_path.dentry = &fake_dentry;
spin_lock_irqsave(&m->lock, flags);
diff --git a/drivers/md/dm-mpath.h b/drivers/md/dm-mpath.h
index 8a4bf2b6d52..b9cdcbb3ed5 100644
--- a/drivers/md/dm-mpath.h
+++ b/drivers/md/dm-mpath.h
@@ -11,7 +11,7 @@
struct dm_dev;
-struct path {
+struct dm_path {
struct dm_dev *dev; /* Read-only */
unsigned is_active; /* Read-only */
@@ -20,6 +20,6 @@ struct path {
};
/* Callback for hwh_pg_init_fn to use when complete */
-void dm_pg_init_complete(struct path *path, unsigned err_flags);
+void dm_pg_init_complete(struct dm_path *path, unsigned err_flags);
#endif
diff --git a/drivers/md/dm-path-selector.h b/drivers/md/dm-path-selector.h
index 732d06a84f8..27357b85d73 100644
--- a/drivers/md/dm-path-selector.h
+++ b/drivers/md/dm-path-selector.h
@@ -44,7 +44,7 @@ struct path_selector_type {
* Add an opaque path object, along with some selector specific
* path args (eg, path priority).
*/
- int (*add_path) (struct path_selector *ps, struct path *path,
+ int (*add_path) (struct path_selector *ps, struct dm_path *path,
int argc, char **argv, char **error);
/*
@@ -55,27 +55,27 @@ struct path_selector_type {
* calling the function again. 0 means don't call it again unless
* the path fails.
*/
- struct path *(*select_path) (struct path_selector *ps,
+ struct dm_path *(*select_path) (struct path_selector *ps,
unsigned *repeat_count);
/*
* Notify the selector that a path has failed.
*/
- void (*fail_path) (struct path_selector *ps, struct path *p);
+ void (*fail_path) (struct path_selector *ps, struct dm_path *p);
/*
* Ask selector to reinstate a path.
*/
- int (*reinstate_path) (struct path_selector *ps, struct path *p);
+ int (*reinstate_path) (struct path_selector *ps, struct dm_path *p);
/*
* Table content based on parameters added in ps_add_path_fn
* or path selector status
*/
- int (*status) (struct path_selector *ps, struct path *path,
+ int (*status) (struct path_selector *ps, struct dm_path *path,
status_type_t type, char *result, unsigned int maxlen);
- int (*end_io) (struct path_selector *ps, struct path *path);
+ int (*end_io) (struct path_selector *ps, struct dm_path *path);
};
/* Register a path selector */
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index fc8cbb168e3..23a642619be 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -344,6 +344,17 @@ static void dispatch_bios(struct mirror_set *ms, struct bio_list *bio_list)
}
}
+static void complete_resync_work(struct region *reg, int success)
+{
+ struct region_hash *rh = reg->rh;
+
+ rh->log->type->set_region_sync(rh->log, reg->key, success);
+ dispatch_bios(rh->ms, &reg->delayed_bios);
+ if (atomic_dec_and_test(&rh->recovery_in_flight))
+ wake_up_all(&_kmirrord_recovery_stopped);
+ up(&rh->recovery_count);
+}
+
static void rh_update_states(struct region_hash *rh)
{
struct region *reg, *next;
@@ -383,11 +394,7 @@ static void rh_update_states(struct region_hash *rh)
*/
list_for_each_entry_safe (reg, next, &recovered, list) {
rh->log->type->clear_region(rh->log, reg->key);
- rh->log->type->complete_resync_work(rh->log, reg->key, 1);
- dispatch_bios(rh->ms, &reg->delayed_bios);
- if (atomic_dec_and_test(&rh->recovery_in_flight))
- wake_up_all(&_kmirrord_recovery_stopped);
- up(&rh->recovery_count);
+ complete_resync_work(reg, 1);
mempool_free(reg, rh->region_pool);
}
@@ -1137,7 +1144,7 @@ static int mirror_map(struct dm_target *ti, struct bio *bio,
if (rw == WRITE) {
queue_bio(ms, bio, rw);
- return 0;
+ return DM_MAPIO_SUBMITTED;
}
r = ms->rh.log->type->in_sync(ms->rh.log,
@@ -1146,7 +1153,7 @@ static int mirror_map(struct dm_target *ti, struct bio *bio,
return r;
if (r == -EWOULDBLOCK) /* FIXME: ugly */
- r = 0;
+ r = DM_MAPIO_SUBMITTED;
/*
* We don't want to fast track a recovery just for a read
@@ -1159,7 +1166,7 @@ static int mirror_map(struct dm_target *ti, struct bio *bio,
if (!r) {
/* Pass this io over to the daemon */
queue_bio(ms, bio, rw);
- return 0;
+ return DM_MAPIO_SUBMITTED;
}
m = choose_mirror(ms, bio->bi_sector);
@@ -1167,7 +1174,7 @@ static int mirror_map(struct dm_target *ti, struct bio *bio,
return -EIO;
map_bio(ms, m, bio);
- return 1;
+ return DM_MAPIO_REMAPPED;
}
static int mirror_end_io(struct dm_target *ti, struct bio *bio,
diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c
index 6f9fcd4db9b..a348a97b65a 100644
--- a/drivers/md/dm-round-robin.c
+++ b/drivers/md/dm-round-robin.c
@@ -21,7 +21,7 @@
*---------------------------------------------------------------*/
struct path_info {
struct list_head list;
- struct path *path;
+ struct dm_path *path;
unsigned repeat_count;
};
@@ -80,7 +80,7 @@ static void rr_destroy(struct path_selector *ps)
ps->context = NULL;
}
-static int rr_status(struct path_selector *ps, struct path *path,
+static int rr_status(struct path_selector *ps, struct dm_path *path,
status_type_t type, char *result, unsigned int maxlen)
{
struct path_info *pi;
@@ -106,7 +106,7 @@ static int rr_status(struct path_selector *ps, struct path *path,
* Called during initialisation to register each path with an
* optional repeat_count.
*/
-static int rr_add_path(struct path_selector *ps, struct path *path,
+static int rr_add_path(struct path_selector *ps, struct dm_path *path,
int argc, char **argv, char **error)
{
struct selector *s = (struct selector *) ps->context;
@@ -141,7 +141,7 @@ static int rr_add_path(struct path_selector *ps, struct path *path,
return 0;
}
-static void rr_fail_path(struct path_selector *ps, struct path *p)
+static void rr_fail_path(struct path_selector *ps, struct dm_path *p)
{
struct selector *s = (struct selector *) ps->context;
struct path_info *pi = p->pscontext;
@@ -149,7 +149,7 @@ static void rr_fail_path(struct path_selector *ps, struct path *p)
list_move(&pi->list, &s->invalid_paths);
}
-static int rr_reinstate_path(struct path_selector *ps, struct path *p)
+static int rr_reinstate_path(struct path_selector *ps, struct dm_path *p)
{
struct selector *s = (struct selector *) ps->context;
struct path_info *pi = p->pscontext;
@@ -159,7 +159,7 @@ static int rr_reinstate_path(struct path_selector *ps, struct path *p)
return 0;
}
-static struct path *rr_select_path(struct path_selector *ps,
+static struct dm_path *rr_select_path(struct path_selector *ps,
unsigned *repeat_count)
{
struct selector *s = (struct selector *) ps->context;
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index b0ce2ce8227..0821a2b68a7 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -39,7 +39,7 @@
*/
#define SNAPSHOT_PAGES 256
-struct workqueue_struct *ksnapd;
+static struct workqueue_struct *ksnapd;
static void flush_queued_bios(struct work_struct *work);
struct pending_exception {
@@ -564,6 +564,17 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
return r;
}
+static void __free_exceptions(struct dm_snapshot *s)
+{
+ kcopyd_client_destroy(s->kcopyd_client);
+ s->kcopyd_client = NULL;
+
+ exit_exception_table(&s->pending, pending_cache);
+ exit_exception_table(&s->complete, exception_cache);
+
+ s->store.destroy(&s->store);
+}
+
static void snapshot_dtr(struct dm_target *ti)
{
struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
@@ -574,13 +585,7 @@ static void snapshot_dtr(struct dm_target *ti)
/* After this returns there can be no new kcopyd jobs. */
unregister_snapshot(s);
- kcopyd_client_destroy(s->kcopyd_client);
-
- exit_exception_table(&s->pending, pending_cache);
- exit_exception_table(&s->complete, exception_cache);
-
- /* Deallocate memory used */
- s->store.destroy(&s->store);
+ __free_exceptions(s);
dm_put_device(ti, s->origin);
dm_put_device(ti, s->cow);
@@ -868,7 +873,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
{
struct exception *e;
struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
- int r = 1;
+ int r = DM_MAPIO_REMAPPED;
chunk_t chunk;
struct pending_exception *pe = NULL;
@@ -914,7 +919,7 @@ 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;
+ r = DM_MAPIO_SUBMITTED;
if (!pe->started) {
/* this is protected by snap->lock */
@@ -992,7 +997,7 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
*---------------------------------------------------------------*/
static int __origin_write(struct list_head *snapshots, struct bio *bio)
{
- int r = 1, first = 0;
+ int r = DM_MAPIO_REMAPPED, first = 0;
struct dm_snapshot *snap;
struct exception *e;
struct pending_exception *pe, *next_pe, *primary_pe = NULL;
@@ -1050,7 +1055,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
bio_list_add(&primary_pe->origin_bios, bio);
- r = 0;
+ r = DM_MAPIO_SUBMITTED;
}
if (!pe->primary_pe) {
@@ -1099,7 +1104,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
static int do_origin(struct dm_dev *origin, struct bio *bio)
{
struct origin *o;
- int r = 1;
+ int r = DM_MAPIO_REMAPPED;
down_read(&_origins_lock);
o = __lookup_origin(origin->bdev);
@@ -1156,7 +1161,7 @@ static int origin_map(struct dm_target *ti, struct bio *bio,
return -EOPNOTSUPP;
/* Only tell snapshots if this is a write */
- return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : 1;
+ return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : DM_MAPIO_REMAPPED;
}
#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 6c29fcecd89..51f5e076001 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -186,7 +186,7 @@ static int stripe_map(struct dm_target *ti, struct bio *bio,
bio->bi_bdev = sc->stripe[stripe].dev->bdev;
bio->bi_sector = sc->stripe[stripe].physical_start +
(chunk << sc->chunk_shift) + (offset & sc->chunk_mask);
- return 1;
+ return DM_MAPIO_REMAPPED;
}
static int stripe_status(struct dm_target *ti,
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c
index ea569f7348d..f314d7dc9c2 100644
--- a/drivers/md/dm-zero.c
+++ b/drivers/md/dm-zero.c
@@ -46,7 +46,7 @@ static int zero_map(struct dm_target *ti, struct bio *bio,
bio_endio(bio, bio->bi_size, 0);
/* accepted bio, don't make new request */
- return 0;
+ return DM_MAPIO_SUBMITTED;
}
static struct target_type zero_target = {
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 7ec1b112a6d..3668b170ea6 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -68,10 +68,12 @@ union map_info *dm_get_mapinfo(struct bio *bio)
#define DMF_FROZEN 2
#define DMF_FREEING 3
#define DMF_DELETING 4
+#define DMF_NOFLUSH_SUSPENDING 5
struct mapped_device {
struct rw_semaphore io_lock;
struct semaphore suspend_lock;
+ spinlock_t pushback_lock;
rwlock_t map_lock;
atomic_t holders;
atomic_t open_count;
@@ -89,7 +91,8 @@ struct mapped_device {
*/
atomic_t pending;
wait_queue_head_t wait;
- struct bio_list deferred;
+ struct bio_list deferred;
+ struct bio_list pushback;
/*
* The current mapping.
@@ -444,23 +447,50 @@ int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo)
* you this clearly demarcated crap.
*---------------------------------------------------------------*/
+static int __noflush_suspending(struct mapped_device *md)
+{
+ return test_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
+}
+
/*
* Decrements the number of outstanding ios that a bio has been
* cloned into, completing the original io if necc.
*/
static void dec_pending(struct dm_io *io, int error)
{
- if (error)
+ unsigned long flags;
+
+ /* Push-back supersedes any I/O errors */
+ if (error && !(io->error > 0 && __noflush_suspending(io->md)))
io->error = error;
if (atomic_dec_and_test(&io->io_count)) {
+ if (io->error == DM_ENDIO_REQUEUE) {
+ /*
+ * Target requested pushing back the I/O.
+ * This must be handled before the sleeper on
+ * suspend queue merges the pushback list.
+ */
+ spin_lock_irqsave(&io->md->pushback_lock, flags);
+ if (__noflush_suspending(io->md))
+ bio_list_add(&io->md->pushback, io->bio);
+ else
+ /* noflush suspend was interrupted. */
+ io->error = -EIO;
+ spin_unlock_irqrestore(&io->md->pushback_lock, flags);
+ }
+
if (end_io_acct(io))
/* nudge anyone waiting on suspend queue */
wake_up(&io->md->wait);
- blk_add_trace_bio(io->md->queue, io->bio, BLK_TA_COMPLETE);
+ if (io->error != DM_ENDIO_REQUEUE) {
+ blk_add_trace_bio(io->md->queue, io->bio,
+ BLK_TA_COMPLETE);
+
+ bio_endio(io->bio, io->bio->bi_size, io->error);
+ }
- bio_endio(io->bio, io->bio->bi_size, io->error);
free_io(io->md, io);
}
}
@@ -480,12 +510,19 @@ static int clone_endio(struct bio *bio, unsigned int done, int error)
if (endio) {
r = endio(tio->ti, bio, error, &tio->info);
- if (r < 0)
+ if (r < 0 || r == DM_ENDIO_REQUEUE)
+ /*
+ * error and requeue request are handled
+ * in dec_pending().
+ */
error = r;
-
- else if (r > 0)
- /* the target wants another shot at the io */
+ else if (r == DM_ENDIO_INCOMPLETE)
+ /* The target will handle the io */
return 1;
+ else if (r) {
+ DMWARN("unimplemented target endio return value: %d", r);
+ BUG();
+ }
}
dec_pending(tio->io, error);
@@ -543,7 +580,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
atomic_inc(&tio->io->io_count);
sector = clone->bi_sector;
r = ti->type->map(ti, clone, &tio->info);
- if (r > 0) {
+ if (r == DM_MAPIO_REMAPPED) {
/* the bio has been remapped so dispatch it */
blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone,
@@ -551,10 +588,8 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
clone->bi_sector);
generic_make_request(clone);
- }
-
- else if (r < 0) {
- /* error the io and bail out */
+ } else if (r < 0 || r == DM_MAPIO_REQUEUE) {
+ /* error the io and bail out, or requeue it if needed */
md = tio->io->md;
dec_pending(tio->io, r);
/*
@@ -563,6 +598,9 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
clone->bi_private = md->bs;
bio_put(clone);
free_tio(md, tio);
+ } else if (r) {
+ DMWARN("unimplemented target map return value: %d", r);
+ BUG();
}
}
@@ -948,6 +986,7 @@ static struct mapped_device *alloc_dev(int minor)
memset(md, 0, sizeof(*md));
init_rwsem(&md->io_lock);
init_MUTEX(&md->suspend_lock);
+ spin_lock_init(&md->pushback_lock);
rwlock_init(&md->map_lock);
atomic_set(&md->holders, 1);
atomic_set(&md->open_count, 0);
@@ -966,8 +1005,8 @@ static struct mapped_device *alloc_dev(int minor)
md->queue->issue_flush_fn = dm_flush_all;
md->io_pool = mempool_create_slab_pool(MIN_IOS, _io_cache);
- if (!md->io_pool)
- goto bad2;
+ if (!md->io_pool)
+ goto bad2;
md->tio_pool = mempool_create_slab_pool(MIN_IOS, _tio_cache);
if (!md->tio_pool)
@@ -1077,7 +1116,8 @@ static int __bind(struct mapped_device *md, struct dm_table *t)
if (size != get_capacity(md->disk))
memset(&md->geometry, 0, sizeof(md->geometry));
- __set_size(md, size);
+ if (md->suspended_bdev)
+ __set_size(md, size);
if (size == 0)
return 0;
@@ -1225,6 +1265,11 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table)
if (!dm_suspended(md))
goto out;
+ /* without bdev, the device size cannot be changed */
+ if (!md->suspended_bdev)
+ if (get_capacity(md->disk) != dm_table_get_size(table))
+ goto out;
+
__unbind(md);
r = __bind(md, table);
@@ -1275,12 +1320,15 @@ static void unlock_fs(struct mapped_device *md)
* dm_bind_table, dm_suspend must be called to flush any in
* flight bios and ensure that any further io gets deferred.
*/
-int dm_suspend(struct mapped_device *md, int do_lockfs)
+int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
{
struct dm_table *map = NULL;
+ unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
struct bio *def;
int r = -EINVAL;
+ int do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG ? 1 : 0;
+ int noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG ? 1 : 0;
down(&md->suspend_lock);
@@ -1289,18 +1337,31 @@ int dm_suspend(struct mapped_device *md, int do_lockfs)
map = dm_get_table(md);
+ /*
+ * DMF_NOFLUSH_SUSPENDING must be set before presuspend.
+ * This flag is cleared before dm_suspend returns.
+ */
+ if (noflush)
+ set_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
+
/* This does not get reverted if there's an error later. */
dm_table_presuspend_targets(map);
- md->suspended_bdev = bdget_disk(md->disk, 0);
- if (!md->suspended_bdev) {
- DMWARN("bdget failed in dm_suspend");
- r = -ENOMEM;
- goto out;
+ /* bdget() can stall if the pending I/Os are not flushed */
+ if (!noflush) {
+ md->suspended_bdev = bdget_disk(md->disk, 0);
+ if (!md->suspended_bdev) {
+ DMWARN("bdget failed in dm_suspend");
+ r = -ENOMEM;
+ goto flush_and_out;
+ }
}
- /* Flush I/O to the device. */
- if (do_lockfs) {
+ /*
+ * Flush I/O to the device.
+ * noflush supersedes do_lockfs, because lock_fs() needs to flush I/Os.
+ */
+ if (do_lockfs && !noflush) {
r = lock_fs(md);
if (r)
goto out;
@@ -1336,6 +1397,14 @@ int dm_suspend(struct mapped_device *md, int do_lockfs)
down_write(&md->io_lock);
remove_wait_queue(&md->wait, &wait);
+ if (noflush) {
+ spin_lock_irqsave(&md->pushback_lock, flags);
+ clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
+ bio_list_merge_head(&md->deferred, &md->pushback);
+ bio_list_init(&md->pushback);
+ spin_unlock_irqrestore(&md->pushback_lock, flags);
+ }
+
/* were we interrupted ? */
r = -EINTR;
if (atomic_read(&md->pending)) {
@@ -1344,7 +1413,7 @@ int dm_suspend(struct mapped_device *md, int do_lockfs)
__flush_deferred_io(md, def);
up_write(&md->io_lock);
unlock_fs(md);
- goto out;
+ goto out; /* pushback list is already flushed, so skip flush */
}
up_write(&md->io_lock);
@@ -1354,6 +1423,25 @@ int dm_suspend(struct mapped_device *md, int do_lockfs)
r = 0;
+flush_and_out:
+ if (r && noflush) {
+ /*
+ * Because there may be already I/Os in the pushback list,
+ * flush them before return.
+ */
+ down_write(&md->io_lock);
+
+ spin_lock_irqsave(&md->pushback_lock, flags);
+ clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
+ bio_list_merge_head(&md->deferred, &md->pushback);
+ bio_list_init(&md->pushback);
+ spin_unlock_irqrestore(&md->pushback_lock, flags);
+
+ def = bio_list_get(&md->deferred);
+ __flush_deferred_io(md, def);
+ up_write(&md->io_lock);
+ }
+
out:
if (r && md->suspended_bdev) {
bdput(md->suspended_bdev);
@@ -1394,8 +1482,10 @@ int dm_resume(struct mapped_device *md)
unlock_fs(md);
- bdput(md->suspended_bdev);
- md->suspended_bdev = NULL;
+ if (md->suspended_bdev) {
+ bdput(md->suspended_bdev);
+ md->suspended_bdev = NULL;
+ }
clear_bit(DMF_SUSPENDED, &md->flags);
@@ -1440,6 +1530,17 @@ int dm_suspended(struct mapped_device *md)
return test_bit(DMF_SUSPENDED, &md->flags);
}
+int dm_noflush_suspending(struct dm_target *ti)
+{
+ struct mapped_device *md = dm_table_get_md(ti->table);
+ int r = __noflush_suspending(md);
+
+ dm_put(md);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(dm_noflush_suspending);
+
static struct block_device_operations dm_blk_dops = {
.open = dm_blk_open,
.release = dm_blk_close,
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index a48ec5e3c1f..2f796b1436b 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -33,6 +33,25 @@
#define SECTOR_SHIFT 9
/*
+ * Definitions of return values from target end_io function.
+ */
+#define DM_ENDIO_INCOMPLETE 1
+#define DM_ENDIO_REQUEUE 2
+
+/*
+ * Definitions of return values from target map function.
+ */
+#define DM_MAPIO_SUBMITTED 0
+#define DM_MAPIO_REMAPPED 1
+#define DM_MAPIO_REQUEUE DM_ENDIO_REQUEUE
+
+/*
+ * Suspend feature flags
+ */
+#define DM_SUSPEND_LOCKFS_FLAG (1 << 0)
+#define DM_SUSPEND_NOFLUSH_FLAG (1 << 1)
+
+/*
* List of devices that a metadevice uses and should open/close.
*/
struct dm_dev {
diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
index a7a5ab55433..4ebd0f2a75e 100644
--- a/drivers/md/faulty.c
+++ b/drivers/md/faulty.c
@@ -173,7 +173,7 @@ static int make_request(request_queue_t *q, struct bio *bio)
conf_t *conf = (conf_t*)mddev->private;
int failit = 0;
- if (bio->bi_rw & 1) {
+ if (bio_data_dir(bio) == WRITE) {
/* write request */
if (atomic_read(&conf->counters[WriteAll])) {
/* special case - don't decrement, don't generic_make_request,
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 6c4345bde07..e8807ea5377 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1413,7 +1413,7 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
struct block_device *bdev;
char b[BDEVNAME_SIZE];
- bdev = open_partition_by_devnum(dev, FMODE_READ|FMODE_WRITE);
+ bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
if (IS_ERR(bdev)) {
printk(KERN_ERR "md: could not open %s.\n",
__bdevname(dev, b));
@@ -1423,7 +1423,7 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
if (err) {
printk(KERN_ERR "md: could not bd_claim %s.\n",
bdevname(bdev, b));
- blkdev_put_partition(bdev);
+ blkdev_put(bdev);
return err;
}
rdev->bdev = bdev;
@@ -1437,7 +1437,7 @@ static void unlock_rdev(mdk_rdev_t *rdev)
if (!bdev)
MD_BUG();
bd_release(bdev);
- blkdev_put_partition(bdev);
+ blkdev_put(bdev);
}
void md_autodetect_dev(dev_t dev);
@@ -1633,7 +1633,8 @@ repeat:
* and 'events' is odd, we can roll back to the previous clean state */
if (nospares
&& (mddev->in_sync && mddev->recovery_cp == MaxSector)
- && (mddev->events & 1))
+ && (mddev->events & 1)
+ && mddev->events != 1)
mddev->events--;
else {
/* otherwise we have to go forward and ... */
@@ -1792,7 +1793,8 @@ 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, 1);
+ if (mddev->pers)
+ md_update_sb(mddev, 1);
md_new_event(mddev);
err = 0;
}
@@ -2004,6 +2006,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
rdev->desc_nr = -1;
rdev->saved_raid_disk = -1;
+ rdev->raid_disk = -1;
rdev->flags = 0;
rdev->data_offset = 0;
rdev->sb_events = 0;
@@ -2233,7 +2236,6 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks);
static ssize_t
raid_disks_store(mddev_t *mddev, const char *buf, size_t len)
{
- /* can only set raid_disks if array is not yet active */
char *e;
int rv = 0;
unsigned long n = simple_strtoul(buf, &e, 10);
@@ -2631,7 +2633,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
return -EINVAL;
buf = e+1;
minor = simple_strtoul(buf, &e, 10);
- if (e==buf || *e != '\n')
+ if (e==buf || (*e && *e != '\n') )
return -EINVAL;
if (major >= sizeof(super_types)/sizeof(super_types[0]) ||
super_types[major].name == NULL)
@@ -3314,6 +3316,10 @@ static int do_md_stop(mddev_t * mddev, int mode)
module_put(mddev->pers->owner);
mddev->pers = NULL;
+
+ set_capacity(disk, 0);
+ mddev->changed = 1;
+
if (mddev->ro)
mddev->ro = 0;
}
@@ -3333,7 +3339,7 @@ static int do_md_stop(mddev_t * mddev, int mode)
if (mode == 0) {
mdk_rdev_t *rdev;
struct list_head *tmp;
- struct gendisk *disk;
+
printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
bitmap_destroy(mddev);
@@ -3358,10 +3364,6 @@ static int do_md_stop(mddev_t * mddev, int mode)
mddev->raid_disks = 0;
mddev->recovery_cp = 0;
- disk = mddev->gendisk;
- if (disk)
- set_capacity(disk, 0);
- mddev->changed = 1;
} else if (mddev->pers)
printk(KERN_INFO "md: %s switched to read-only mode.\n",
mdname(mddev));
@@ -3371,6 +3373,7 @@ out:
return err;
}
+#ifndef MODULE
static void autorun_array(mddev_t *mddev)
{
mdk_rdev_t *rdev;
@@ -3485,6 +3488,7 @@ static void autorun_devices(int part)
}
printk(KERN_INFO "md: ... autorun DONE.\n");
}
+#endif /* !MODULE */
static int get_version(void __user * arg)
{
@@ -3560,6 +3564,8 @@ static int get_bitmap_file(mddev_t * mddev, void __user * arg)
char *ptr, *buf = NULL;
int err = -ENOMEM;
+ md_allow_write(mddev);
+
file = kmalloc(sizeof(*file), GFP_KERNEL);
if (!file)
goto out;
@@ -3722,6 +3728,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
if (err)
export_rdev(rdev);
+ md_update_sb(mddev, 1);
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
return err;
@@ -3977,6 +3984,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
mddev->major_version = info->major_version;
mddev->minor_version = info->minor_version;
mddev->patch_version = info->patch_version;
+ mddev->persistent = !info->not_persistent;
return 0;
}
mddev->major_version = MD_MAJOR_VERSION;
@@ -4301,9 +4309,10 @@ static int md_ioctl(struct inode *inode, struct file *file,
* Commands querying/configuring an existing array:
*/
/* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
- * RUN_ARRAY, and SET_BITMAP_FILE are allowed */
+ * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
- && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE) {
+ && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
+ && cmd != GET_BITMAP_FILE) {
err = -ENODEV;
goto abort_unlock;
}
@@ -4423,7 +4432,7 @@ static int md_open(struct inode *inode, struct file *file)
mddev_t *mddev = inode->i_bdev->bd_disk->private_data;
int err;
- if ((err = mddev_lock(mddev)))
+ if ((err = mutex_lock_interruptible_nested(&mddev->reconfig_mutex, 1)))
goto out;
err = 0;
@@ -4846,8 +4855,8 @@ static int md_seq_show(struct seq_file *seq, void *v)
chunk_kb ? "KB" : "B");
if (bitmap->file) {
seq_printf(seq, ", file: ");
- seq_path(seq, bitmap->file->f_vfsmnt,
- bitmap->file->f_dentry," \t\n");
+ seq_path(seq, bitmap->file->f_path.mnt,
+ bitmap->file->f_path.dentry," \t\n");
}
seq_printf(seq, "\n");
@@ -5025,6 +5034,33 @@ void md_write_end(mddev_t *mddev)
}
}
+/* md_allow_write(mddev)
+ * Calling this ensures that the array is marked 'active' so that writes
+ * may proceed without blocking. It is important to call this before
+ * attempting a GFP_KERNEL allocation while holding the mddev lock.
+ * Must be called with mddev_lock held.
+ */
+void md_allow_write(mddev_t *mddev)
+{
+ if (!mddev->pers)
+ return;
+ if (mddev->ro)
+ return;
+
+ spin_lock_irq(&mddev->write_lock);
+ if (mddev->in_sync) {
+ mddev->in_sync = 0;
+ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ if (mddev->safemode_delay &&
+ mddev->safemode == 0)
+ mddev->safemode = 1;
+ spin_unlock_irq(&mddev->write_lock);
+ md_update_sb(mddev, 0);
+ } else
+ spin_unlock_irq(&mddev->write_lock);
+}
+EXPORT_SYMBOL_GPL(md_allow_write);
+
static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
#define SYNC_MARKS 10
@@ -5273,7 +5309,6 @@ void md_do_sync(mddev_t *mddev)
mddev->pers->sync_request(mddev, max_sectors, &skipped, 1);
if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
- test_bit(MD_RECOVERY_SYNC, &mddev->recovery) &&
!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
mddev->curr_resync > 2) {
if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
@@ -5297,6 +5332,7 @@ void md_do_sync(mddev_t *mddev)
rdev->recovery_offset = mddev->curr_resync;
}
}
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
skip:
mddev->curr_resync = 0;
@@ -5593,7 +5629,7 @@ static void autostart_arrays(int part)
autorun_devices(part);
}
-#endif
+#endif /* !MODULE */
static __exit void md_exit(void)
{
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 656fae912fe..97ee870b265 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -775,6 +775,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
struct bio_list bl;
struct page **behind_pages = NULL;
const int rw = bio_data_dir(bio);
+ const int do_sync = bio_sync(bio);
int do_barriers;
/*
@@ -835,7 +836,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
read_bio->bi_sector = r1_bio->sector + mirror->rdev->data_offset;
read_bio->bi_bdev = mirror->rdev->bdev;
read_bio->bi_end_io = raid1_end_read_request;
- read_bio->bi_rw = READ;
+ read_bio->bi_rw = READ | do_sync;
read_bio->bi_private = r1_bio;
generic_make_request(read_bio);
@@ -906,7 +907,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
mbio->bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset;
mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
mbio->bi_end_io = raid1_end_write_request;
- mbio->bi_rw = WRITE | do_barriers;
+ mbio->bi_rw = WRITE | do_barriers | do_sync;
mbio->bi_private = r1_bio;
if (behind_pages) {
@@ -941,6 +942,8 @@ static int make_request(request_queue_t *q, struct bio * bio)
blk_plug_device(mddev->queue);
spin_unlock_irqrestore(&conf->device_lock, flags);
+ if (do_sync)
+ md_wakeup_thread(mddev->thread);
#if 0
while ((bio = bio_list_pop(&bl)) != NULL)
generic_make_request(bio);
@@ -1263,6 +1266,11 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
sbio->bi_sector = r1_bio->sector +
conf->mirrors[i].rdev->data_offset;
sbio->bi_bdev = conf->mirrors[i].rdev->bdev;
+ for (j = 0; j < vcnt ; j++)
+ memcpy(page_address(sbio->bi_io_vec[j].bv_page),
+ page_address(pbio->bi_io_vec[j].bv_page),
+ PAGE_SIZE);
+
}
}
}
@@ -1541,6 +1549,7 @@ static void raid1d(mddev_t *mddev)
* We already have a nr_pending reference on these rdevs.
*/
int i;
+ const int do_sync = bio_sync(r1_bio->master_bio);
clear_bit(R1BIO_BarrierRetry, &r1_bio->state);
clear_bit(R1BIO_Barrier, &r1_bio->state);
for (i=0; i < conf->raid_disks; i++)
@@ -1561,7 +1570,7 @@ static void raid1d(mddev_t *mddev)
conf->mirrors[i].rdev->data_offset;
bio->bi_bdev = conf->mirrors[i].rdev->bdev;
bio->bi_end_io = raid1_end_write_request;
- bio->bi_rw = WRITE;
+ bio->bi_rw = WRITE | do_sync;
bio->bi_private = r1_bio;
r1_bio->bios[i] = bio;
generic_make_request(bio);
@@ -1593,6 +1602,7 @@ static void raid1d(mddev_t *mddev)
(unsigned long long)r1_bio->sector);
raid_end_bio_io(r1_bio);
} else {
+ const int do_sync = bio_sync(r1_bio->master_bio);
r1_bio->bios[r1_bio->read_disk] =
mddev->ro ? IO_BLOCKED : NULL;
r1_bio->read_disk = disk;
@@ -1608,7 +1618,7 @@ static void raid1d(mddev_t *mddev)
bio->bi_sector = r1_bio->sector + rdev->data_offset;
bio->bi_bdev = rdev->bdev;
bio->bi_end_io = raid1_end_read_request;
- bio->bi_rw = READ;
+ bio->bi_rw = READ | do_sync;
bio->bi_private = r1_bio;
unplug = 1;
generic_make_request(bio);
@@ -1736,7 +1746,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
/* take from bio_init */
bio->bi_next = NULL;
bio->bi_flags |= 1 << BIO_UPTODATE;
- bio->bi_rw = 0;
+ bio->bi_rw = READ;
bio->bi_vcnt = 0;
bio->bi_idx = 0;
bio->bi_phys_segments = 0;
@@ -1951,6 +1961,7 @@ static int run(mddev_t *mddev)
!test_bit(In_sync, &disk->rdev->flags)) {
disk->head_position = 0;
mddev->degraded++;
+ conf->fullsync = 1;
}
}
if (mddev->degraded == conf->raid_disks) {
@@ -2093,6 +2104,8 @@ static int raid1_reshape(mddev_t *mddev)
return -EINVAL;
}
+ md_allow_write(mddev);
+
raid_disks = mddev->raid_disks + mddev->delta_disks;
if (raid_disks < conf->raid_disks) {
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 7492d6033ac..a9401c017e3 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -782,6 +782,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
int i;
int chunk_sects = conf->chunk_mask + 1;
const int rw = bio_data_dir(bio);
+ const int do_sync = bio_sync(bio);
struct bio_list bl;
unsigned long flags;
@@ -863,7 +864,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
mirror->rdev->data_offset;
read_bio->bi_bdev = mirror->rdev->bdev;
read_bio->bi_end_io = raid10_end_read_request;
- read_bio->bi_rw = READ;
+ read_bio->bi_rw = READ | do_sync;
read_bio->bi_private = r10_bio;
generic_make_request(read_bio);
@@ -909,7 +910,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
conf->mirrors[d].rdev->data_offset;
mbio->bi_bdev = conf->mirrors[d].rdev->bdev;
mbio->bi_end_io = raid10_end_write_request;
- mbio->bi_rw = WRITE;
+ mbio->bi_rw = WRITE | do_sync;
mbio->bi_private = r10_bio;
atomic_inc(&r10_bio->remaining);
@@ -922,6 +923,9 @@ static int make_request(request_queue_t *q, struct bio * bio)
blk_plug_device(mddev->queue);
spin_unlock_irqrestore(&conf->device_lock, flags);
+ if (do_sync)
+ md_wakeup_thread(mddev->thread);
+
return 0;
}
@@ -1563,6 +1567,7 @@ static void raid10d(mddev_t *mddev)
(unsigned long long)r10_bio->sector);
raid_end_bio_io(r10_bio);
} else {
+ const int do_sync = bio_sync(r10_bio->master_bio);
rdev = conf->mirrors[mirror].rdev;
if (printk_ratelimit())
printk(KERN_ERR "raid10: %s: redirecting sector %llu to"
@@ -1574,7 +1579,7 @@ static void raid10d(mddev_t *mddev)
bio->bi_sector = r10_bio->devs[r10_bio->read_slot].addr
+ rdev->data_offset;
bio->bi_bdev = rdev->bdev;
- bio->bi_rw = READ;
+ bio->bi_rw = READ | do_sync;
bio->bi_private = r10_bio;
bio->bi_end_io = raid10_end_read_request;
unplug = 1;
@@ -1785,7 +1790,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
biolist = bio;
bio->bi_private = r10_bio;
bio->bi_end_io = end_sync_read;
- bio->bi_rw = 0;
+ bio->bi_rw = READ;
bio->bi_sector = r10_bio->devs[j].addr +
conf->mirrors[d].rdev->data_offset;
bio->bi_bdev = conf->mirrors[d].rdev->bdev;
@@ -1801,7 +1806,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
biolist = bio;
bio->bi_private = r10_bio;
bio->bi_end_io = end_sync_write;
- bio->bi_rw = 1;
+ bio->bi_rw = WRITE;
bio->bi_sector = r10_bio->devs[k].addr +
conf->mirrors[i].rdev->data_offset;
bio->bi_bdev = conf->mirrors[i].rdev->bdev;
@@ -1870,7 +1875,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
biolist = bio;
bio->bi_private = r10_bio;
bio->bi_end_io = end_sync_read;
- bio->bi_rw = 0;
+ bio->bi_rw = READ;
bio->bi_sector = r10_bio->devs[i].addr +
conf->mirrors[d].rdev->data_offset;
bio->bi_bdev = conf->mirrors[d].rdev->bdev;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 52914d5cec7..11c3d7bfa79 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -134,6 +134,8 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
if (!test_bit(STRIPE_EXPANDING, &sh->state)) {
list_add_tail(&sh->lru, &conf->inactive_list);
wake_up(&conf->wait_for_stripe);
+ if (conf->retry_read_aligned)
+ md_wakeup_thread(conf->mddev->thread);
}
}
}
@@ -403,6 +405,8 @@ static int resize_stripes(raid5_conf_t *conf, int newsize)
if (newsize <= conf->pool_size)
return 0; /* never bother to shrink */
+ md_allow_write(conf->mddev);
+
/* Step 1 */
sc = kmem_cache_create(conf->cache_name[1-conf->active_name],
sizeof(struct stripe_head)+(newsize-1)*sizeof(struct r5dev),
@@ -542,35 +546,7 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
}
if (uptodate) {
-#if 0
- struct bio *bio;
- unsigned long flags;
- spin_lock_irqsave(&conf->device_lock, flags);
- /* we can return a buffer if we bypassed the cache or
- * if the top buffer is not in highmem. If there are
- * multiple buffers, leave the extra work to
- * handle_stripe
- */
- buffer = sh->bh_read[i];
- if (buffer &&
- (!PageHighMem(buffer->b_page)
- || buffer->b_page == bh->b_page )
- ) {
- sh->bh_read[i] = buffer->b_reqnext;
- buffer->b_reqnext = NULL;
- } else
- buffer = NULL;
- spin_unlock_irqrestore(&conf->device_lock, flags);
- if (sh->bh_page[i]==bh->b_page)
- set_buffer_uptodate(bh);
- if (buffer) {
- if (buffer->b_page != bh->b_page)
- memcpy(buffer->b_data, bh->b_data, bh->b_size);
- buffer->b_end_io(buffer, 1);
- }
-#else
set_bit(R5_UPTODATE, &sh->dev[i].flags);
-#endif
if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
rdev = conf->disks[i].rdev;
printk(KERN_INFO "raid5:%s: read error corrected (%lu sectors at %llu on %s)\n",
@@ -616,14 +592,6 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
}
}
rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
-#if 0
- /* must restore b_page before unlocking buffer... */
- if (sh->bh_page[i] != bh->b_page) {
- bh->b_page = sh->bh_page[i];
- bh->b_data = page_address(bh->b_page);
- clear_buffer_uptodate(bh);
- }
-#endif
clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state);
release_stripe(sh);
@@ -821,7 +789,8 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks,
static sector_t compute_blocknr(struct stripe_head *sh, int i)
{
raid5_conf_t *conf = sh->raid_conf;
- int raid_disks = sh->disks, data_disks = raid_disks - 1;
+ int raid_disks = sh->disks;
+ int data_disks = raid_disks - conf->max_degraded;
sector_t new_sector = sh->sector, check;
int sectors_per_chunk = conf->chunk_size >> 9;
sector_t stripe;
@@ -857,7 +826,6 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i)
}
break;
case 6:
- data_disks = raid_disks - 2;
if (i == raid6_next_disk(sh->pd_idx, raid_disks))
return 0; /* It is the Q disk */
switch (conf->algorithm) {
@@ -1353,8 +1321,10 @@ static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks)
int pd_idx, dd_idx;
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);
+ raid5_compute_sector(stripe * (disks - conf->max_degraded)
+ *sectors_per_chunk + chunk_offset,
+ disks, disks - conf->max_degraded,
+ &dd_idx, &pd_idx, conf);
return pd_idx;
}
@@ -1615,15 +1585,6 @@ static void handle_stripe5(struct stripe_head *sh)
} else if (test_bit(R5_Insync, &dev->flags)) {
set_bit(R5_LOCKED, &dev->flags);
set_bit(R5_Wantread, &dev->flags);
-#if 0
- /* if I am just reading this block and we don't have
- a failed drive, or any pending writes then sidestep the cache */
- if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext &&
- ! syncing && !failed && !to_write) {
- sh->bh_cache[i]->b_page = sh->bh_read[i]->b_page;
- sh->bh_cache[i]->b_data = sh->bh_read[i]->b_data;
- }
-#endif
locked++;
PRINTK("Reading block %d (sync=%d)\n",
i, syncing);
@@ -1641,9 +1602,6 @@ static void handle_stripe5(struct stripe_head *sh)
dev = &sh->dev[i];
if ((dev->towrite || i == sh->pd_idx) &&
(!test_bit(R5_LOCKED, &dev->flags)
-#if 0
-|| sh->bh_page[i]!=bh->b_page
-#endif
) &&
!test_bit(R5_UPTODATE, &dev->flags)) {
if (test_bit(R5_Insync, &dev->flags)
@@ -1655,9 +1613,6 @@ static void handle_stripe5(struct stripe_head *sh)
/* Would I have to read this buffer for reconstruct_write */
if (!test_bit(R5_OVERWRITE, &dev->flags) && i != sh->pd_idx &&
(!test_bit(R5_LOCKED, &dev->flags)
-#if 0
-|| sh->bh_page[i] != bh->b_page
-#endif
) &&
!test_bit(R5_UPTODATE, &dev->flags)) {
if (test_bit(R5_Insync, &dev->flags)) rcw++;
@@ -1865,23 +1820,25 @@ static void handle_stripe5(struct stripe_head *sh)
return_bi = bi->bi_next;
bi->bi_next = NULL;
bi->bi_size = 0;
- bi->bi_end_io(bi, bytes, 0);
+ bi->bi_end_io(bi, bytes,
+ test_bit(BIO_UPTODATE, &bi->bi_flags)
+ ? 0 : -EIO);
}
for (i=disks; i-- ;) {
int rw;
struct bio *bi;
mdk_rdev_t *rdev;
if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags))
- rw = 1;
+ rw = WRITE;
else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags))
- rw = 0;
+ rw = READ;
else
continue;
bi = &sh->dev[i].req;
bi->bi_rw = rw;
- if (rw)
+ if (rw == WRITE)
bi->bi_end_io = raid5_end_write_request;
else
bi->bi_end_io = raid5_end_read_request;
@@ -1917,7 +1874,7 @@ static void handle_stripe5(struct stripe_head *sh)
atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
generic_make_request(bi);
} else {
- if (rw == 1)
+ if (rw == WRITE)
set_bit(STRIPE_DEGRADED, &sh->state);
PRINTK("skip op %ld on disc %d for sector %llu\n",
bi->bi_rw, i, (unsigned long long)sh->sector);
@@ -2193,15 +2150,6 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
} else if (test_bit(R5_Insync, &dev->flags)) {
set_bit(R5_LOCKED, &dev->flags);
set_bit(R5_Wantread, &dev->flags);
-#if 0
- /* if I am just reading this block and we don't have
- a failed drive, or any pending writes then sidestep the cache */
- if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext &&
- ! syncing && !failed && !to_write) {
- sh->bh_cache[i]->b_page = sh->bh_read[i]->b_page;
- sh->bh_cache[i]->b_data = sh->bh_read[i]->b_data;
- }
-#endif
locked++;
PRINTK("Reading block %d (sync=%d)\n",
i, syncing);
@@ -2220,9 +2168,6 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
if (!test_bit(R5_OVERWRITE, &dev->flags)
&& i != pd_idx && i != qd_idx
&& (!test_bit(R5_LOCKED, &dev->flags)
-#if 0
- || sh->bh_page[i] != bh->b_page
-#endif
) &&
!test_bit(R5_UPTODATE, &dev->flags)) {
if (test_bit(R5_Insync, &dev->flags)) rcw++;
@@ -2418,23 +2363,25 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
return_bi = bi->bi_next;
bi->bi_next = NULL;
bi->bi_size = 0;
- bi->bi_end_io(bi, bytes, 0);
+ bi->bi_end_io(bi, bytes,
+ test_bit(BIO_UPTODATE, &bi->bi_flags)
+ ? 0 : -EIO);
}
for (i=disks; i-- ;) {
int rw;
struct bio *bi;
mdk_rdev_t *rdev;
if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags))
- rw = 1;
+ rw = WRITE;
else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags))
- rw = 0;
+ rw = READ;
else
continue;
bi = &sh->dev[i].req;
bi->bi_rw = rw;
- if (rw)
+ if (rw == WRITE)
bi->bi_end_io = raid5_end_write_request;
else
bi->bi_end_io = raid5_end_read_request;
@@ -2470,7 +2417,7 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
generic_make_request(bi);
} else {
- if (rw == 1)
+ if (rw == WRITE)
set_bit(STRIPE_DEGRADED, &sh->state);
PRINTK("skip op %ld on disc %d for sector %llu\n",
bi->bi_rw, i, (unsigned long long)sh->sector);
@@ -2611,6 +2558,208 @@ static int raid5_congested(void *data, int bits)
return 0;
}
+/* We want read requests to align with chunks where possible,
+ * but write requests don't need to.
+ */
+static int raid5_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec)
+{
+ mddev_t *mddev = q->queuedata;
+ sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+ int max;
+ unsigned int chunk_sectors = mddev->chunk_size >> 9;
+ unsigned int bio_sectors = bio->bi_size >> 9;
+
+ if (bio_data_dir(bio) == WRITE)
+ return biovec->bv_len; /* always allow writes to be mergeable */
+
+ max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
+ if (max < 0) max = 0;
+ if (max <= biovec->bv_len && bio_sectors == 0)
+ return biovec->bv_len;
+ else
+ return max;
+}
+
+
+static int in_chunk_boundary(mddev_t *mddev, struct bio *bio)
+{
+ sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+ unsigned int chunk_sectors = mddev->chunk_size >> 9;
+ unsigned int bio_sectors = bio->bi_size >> 9;
+
+ return chunk_sectors >=
+ ((sector & (chunk_sectors - 1)) + bio_sectors);
+}
+
+/*
+ * add bio to the retry LIFO ( in O(1) ... we are in interrupt )
+ * later sampled by raid5d.
+ */
+static void add_bio_to_retry(struct bio *bi,raid5_conf_t *conf)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&conf->device_lock, flags);
+
+ bi->bi_next = conf->retry_read_aligned_list;
+ conf->retry_read_aligned_list = bi;
+
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+ md_wakeup_thread(conf->mddev->thread);
+}
+
+
+static struct bio *remove_bio_from_retry(raid5_conf_t *conf)
+{
+ struct bio *bi;
+
+ bi = conf->retry_read_aligned;
+ if (bi) {
+ conf->retry_read_aligned = NULL;
+ return bi;
+ }
+ bi = conf->retry_read_aligned_list;
+ if(bi) {
+ conf->retry_read_aligned_list = bi->bi_next;
+ bi->bi_next = NULL;
+ bi->bi_phys_segments = 1; /* biased count of active stripes */
+ bi->bi_hw_segments = 0; /* count of processed stripes */
+ }
+
+ return bi;
+}
+
+
+/*
+ * The "raid5_align_endio" should check if the read succeeded and if it
+ * did, call bio_endio on the original bio (having bio_put the new bio
+ * first).
+ * If the read failed..
+ */
+static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
+{
+ struct bio* raid_bi = bi->bi_private;
+ mddev_t *mddev;
+ raid5_conf_t *conf;
+ int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
+ mdk_rdev_t *rdev;
+
+ if (bi->bi_size)
+ return 1;
+ bio_put(bi);
+
+ mddev = raid_bi->bi_bdev->bd_disk->queue->queuedata;
+ conf = mddev_to_conf(mddev);
+ rdev = (void*)raid_bi->bi_next;
+ raid_bi->bi_next = NULL;
+
+ rdev_dec_pending(rdev, conf->mddev);
+
+ if (!error && uptodate) {
+ bio_endio(raid_bi, bytes, 0);
+ if (atomic_dec_and_test(&conf->active_aligned_reads))
+ wake_up(&conf->wait_for_stripe);
+ return 0;
+ }
+
+
+ PRINTK("raid5_align_endio : io error...handing IO for a retry\n");
+
+ add_bio_to_retry(raid_bi, conf);
+ return 0;
+}
+
+static int bio_fits_rdev(struct bio *bi)
+{
+ request_queue_t *q = bdev_get_queue(bi->bi_bdev);
+
+ if ((bi->bi_size>>9) > q->max_sectors)
+ return 0;
+ blk_recount_segments(q, bi);
+ if (bi->bi_phys_segments > q->max_phys_segments ||
+ bi->bi_hw_segments > q->max_hw_segments)
+ return 0;
+
+ if (q->merge_bvec_fn)
+ /* it's too hard to apply the merge_bvec_fn at this stage,
+ * just just give up
+ */
+ return 0;
+
+ return 1;
+}
+
+
+static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
+{
+ mddev_t *mddev = q->queuedata;
+ raid5_conf_t *conf = mddev_to_conf(mddev);
+ const unsigned int raid_disks = conf->raid_disks;
+ const unsigned int data_disks = raid_disks - conf->max_degraded;
+ unsigned int dd_idx, pd_idx;
+ struct bio* align_bi;
+ mdk_rdev_t *rdev;
+
+ if (!in_chunk_boundary(mddev, raid_bio)) {
+ PRINTK("chunk_aligned_read : non aligned\n");
+ return 0;
+ }
+ /*
+ * use bio_clone to make a copy of the bio
+ */
+ align_bi = bio_clone(raid_bio, GFP_NOIO);
+ if (!align_bi)
+ return 0;
+ /*
+ * set bi_end_io to a new function, and set bi_private to the
+ * original bio.
+ */
+ align_bi->bi_end_io = raid5_align_endio;
+ align_bi->bi_private = raid_bio;
+ /*
+ * compute position
+ */
+ align_bi->bi_sector = raid5_compute_sector(raid_bio->bi_sector,
+ raid_disks,
+ data_disks,
+ &dd_idx,
+ &pd_idx,
+ conf);
+
+ rcu_read_lock();
+ rdev = rcu_dereference(conf->disks[dd_idx].rdev);
+ if (rdev && test_bit(In_sync, &rdev->flags)) {
+ atomic_inc(&rdev->nr_pending);
+ rcu_read_unlock();
+ raid_bio->bi_next = (void*)rdev;
+ align_bi->bi_bdev = rdev->bdev;
+ align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
+ align_bi->bi_sector += rdev->data_offset;
+
+ if (!bio_fits_rdev(align_bi)) {
+ /* too big in some way */
+ bio_put(align_bi);
+ rdev_dec_pending(rdev, mddev);
+ return 0;
+ }
+
+ spin_lock_irq(&conf->device_lock);
+ wait_event_lock_irq(conf->wait_for_stripe,
+ conf->quiesce == 0,
+ conf->device_lock, /* nothing */);
+ atomic_inc(&conf->active_aligned_reads);
+ spin_unlock_irq(&conf->device_lock);
+
+ generic_make_request(align_bi);
+ return 1;
+ } else {
+ rcu_read_unlock();
+ bio_put(align_bi);
+ return 0;
+ }
+}
+
+
static int make_request(request_queue_t *q, struct bio * bi)
{
mddev_t *mddev = q->queuedata;
@@ -2632,6 +2781,11 @@ static int make_request(request_queue_t *q, struct bio * bi)
disk_stat_inc(mddev->gendisk, ios[rw]);
disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bi));
+ if (rw == READ &&
+ mddev->reshape_position == MaxSector &&
+ chunk_aligned_read(q,bi))
+ return 0;
+
logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
last_sector = bi->bi_sector + (bi->bi_size>>9);
bi->bi_next = NULL;
@@ -2739,7 +2893,9 @@ static int make_request(request_queue_t *q, struct bio * bi)
if ( rw == WRITE )
md_write_end(mddev);
bi->bi_size = 0;
- bi->bi_end_io(bi, bytes, 0);
+ bi->bi_end_io(bi, bytes,
+ test_bit(BIO_UPTODATE, &bi->bi_flags)
+ ? 0 : -EIO);
}
return 0;
}
@@ -2950,6 +3106,82 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
return STRIPE_SECTORS;
}
+static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
+{
+ /* We may not be able to submit a whole bio at once as there
+ * may not be enough stripe_heads available.
+ * We cannot pre-allocate enough stripe_heads as we may need
+ * more than exist in the cache (if we allow ever large chunks).
+ * So we do one stripe head at a time and record in
+ * ->bi_hw_segments how many have been done.
+ *
+ * We *know* that this entire raid_bio is in one chunk, so
+ * it will be only one 'dd_idx' and only need one call to raid5_compute_sector.
+ */
+ struct stripe_head *sh;
+ int dd_idx, pd_idx;
+ sector_t sector, logical_sector, last_sector;
+ int scnt = 0;
+ int remaining;
+ int handled = 0;
+
+ logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
+ sector = raid5_compute_sector( logical_sector,
+ conf->raid_disks,
+ conf->raid_disks - conf->max_degraded,
+ &dd_idx,
+ &pd_idx,
+ conf);
+ last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9);
+
+ for (; logical_sector < last_sector;
+ logical_sector += STRIPE_SECTORS,
+ sector += STRIPE_SECTORS,
+ scnt++) {
+
+ if (scnt < raid_bio->bi_hw_segments)
+ /* already done this stripe */
+ continue;
+
+ sh = get_active_stripe(conf, sector, conf->raid_disks, pd_idx, 1);
+
+ if (!sh) {
+ /* failed to get a stripe - must wait */
+ raid_bio->bi_hw_segments = scnt;
+ conf->retry_read_aligned = raid_bio;
+ return handled;
+ }
+
+ set_bit(R5_ReadError, &sh->dev[dd_idx].flags);
+ if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) {
+ release_stripe(sh);
+ raid_bio->bi_hw_segments = scnt;
+ conf->retry_read_aligned = raid_bio;
+ return handled;
+ }
+
+ handle_stripe(sh, NULL);
+ release_stripe(sh);
+ handled++;
+ }
+ spin_lock_irq(&conf->device_lock);
+ remaining = --raid_bio->bi_phys_segments;
+ spin_unlock_irq(&conf->device_lock);
+ if (remaining == 0) {
+ int bytes = raid_bio->bi_size;
+
+ raid_bio->bi_size = 0;
+ raid_bio->bi_end_io(raid_bio, bytes,
+ test_bit(BIO_UPTODATE, &raid_bio->bi_flags)
+ ? 0 : -EIO);
+ }
+ if (atomic_dec_and_test(&conf->active_aligned_reads))
+ wake_up(&conf->wait_for_stripe);
+ return handled;
+}
+
+
+
/*
* This is our raid5 kernel thread.
*
@@ -2971,6 +3203,7 @@ static void raid5d (mddev_t *mddev)
spin_lock_irq(&conf->device_lock);
while (1) {
struct list_head *first;
+ struct bio *bio;
if (conf->seq_flush != conf->seq_write) {
int seq = conf->seq_flush;
@@ -2987,6 +3220,16 @@ static void raid5d (mddev_t *mddev)
!list_empty(&conf->delayed_list))
raid5_activate_delayed(conf);
+ while ((bio = remove_bio_from_retry(conf))) {
+ int ok;
+ spin_unlock_irq(&conf->device_lock);
+ ok = retry_aligned_read(conf, bio);
+ spin_lock_irq(&conf->device_lock);
+ if (!ok)
+ break;
+ handled++;
+ }
+
if (list_empty(&conf->handle_list))
break;
@@ -3045,6 +3288,7 @@ raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
else
break;
}
+ md_allow_write(mddev);
while (new > conf->max_nr_stripes) {
if (grow_one_stripe(conf))
conf->max_nr_stripes++;
@@ -3174,6 +3418,7 @@ static int run(mddev_t *mddev)
INIT_LIST_HEAD(&conf->inactive_list);
atomic_set(&conf->active_stripes, 0);
atomic_set(&conf->preread_active_stripes, 0);
+ atomic_set(&conf->active_aligned_reads, 0);
PRINTK("raid5: run(%s) called.\n", mdname(mddev));
@@ -3320,6 +3565,8 @@ static int run(mddev_t *mddev)
mddev->array_size = mddev->size * (conf->previous_raid_disks -
conf->max_degraded);
+ blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec);
+
return 0;
abort:
if (conf) {
@@ -3694,7 +3941,8 @@ static void raid5_quiesce(mddev_t *mddev, int state)
spin_lock_irq(&conf->device_lock);
conf->quiesce = 1;
wait_event_lock_irq(conf->wait_for_stripe,
- atomic_read(&conf->active_stripes) == 0,
+ atomic_read(&conf->active_stripes) == 0 &&
+ atomic_read(&conf->active_aligned_reads) == 0,
conf->device_lock, /* nothing */);
spin_unlock_irq(&conf->device_lock);
break;
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 9f7e1fe8c97..87410dbd3df 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -67,6 +67,7 @@ source "drivers/media/common/Kconfig"
config VIDEO_TUNER
tristate
+ depends on I2C
config VIDEO_BUF
tristate
@@ -82,6 +83,7 @@ config VIDEO_IR
config VIDEO_TVEEPROM
tristate
+ depends on I2C
config USB_DABUSB
tristate "DABUSB driver"
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index 8eaa88fd8b9..9a8dd8764c9 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/string.h>
+#include <linux/jiffies.h>
#include <media/ir-common.h>
/* -------------------------------------------------------------------------- */
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index db753443587..0e948a5c5a0 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -698,7 +698,6 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
[ 0x29 ] = KEY_TEXT,
[ 0x2a ] = KEY_MEDIA,
[ 0x18 ] = KEY_EPG,
- [ 0x27 ] = KEY_RECORD,
};
EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
@@ -1552,3 +1551,58 @@ IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_norwood);
+
+/* From reading the following remotes:
+ * Zenith Universal 7 / TV Mode 807 / VCR Mode 837
+ * Hauppauge (from NOVA-CI-s box product)
+ * This is a "middle of the road" approach, differences are noted
+ */
+IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE] = {
+ [ 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,
+ [ 0x0a ] = KEY_ENTER,
+ [ 0x0b ] = KEY_RED,
+ [ 0x0c ] = KEY_POWER, /* RADIO on Hauppauge */
+ [ 0x0d ] = KEY_MUTE,
+ [ 0x0f ] = KEY_A, /* TV on Hauppauge */
+ [ 0x10 ] = KEY_VOLUMEUP,
+ [ 0x11 ] = KEY_VOLUMEDOWN,
+ [ 0x14 ] = KEY_B,
+ [ 0x1c ] = KEY_UP,
+ [ 0x1d ] = KEY_DOWN,
+ [ 0x1e ] = KEY_OPTION, /* RESERVED on Hauppauge */
+ [ 0x1f ] = KEY_BREAK,
+ [ 0x20 ] = KEY_CHANNELUP,
+ [ 0x21 ] = KEY_CHANNELDOWN,
+ [ 0x22 ] = KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
+ [ 0x24 ] = KEY_RESTART,
+ [ 0x25 ] = KEY_OK,
+ [ 0x26 ] = KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
+ [ 0x28 ] = KEY_ENTER, /* VCR mode on Zenith */
+ [ 0x29 ] = KEY_PAUSE,
+ [ 0x2b ] = KEY_RIGHT,
+ [ 0x2c ] = KEY_LEFT,
+ [ 0x2e ] = KEY_MENU, /* FULL SCREEN on Hauppauge */
+ [ 0x30 ] = KEY_SLOW,
+ [ 0x31 ] = KEY_PREVIOUS, /* VCR mode on Zenith */
+ [ 0x32 ] = KEY_REWIND,
+ [ 0x34 ] = KEY_FASTFORWARD,
+ [ 0x35 ] = KEY_PLAY,
+ [ 0x36 ] = KEY_STOP,
+ [ 0x37 ] = KEY_RECORD,
+ [ 0x38 ] = KEY_TUNER, /* TV/VCR on Zenith */
+ [ 0x3a ] = KEY_C,
+ [ 0x3c ] = KEY_EXIT,
+ [ 0x3d ] = KEY_POWER2,
+ [ 0x3e ] = KEY_TUNER,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_budget_ci_old);
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 5297a365c92..8c85efc2652 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -189,13 +189,21 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
saa7146_write(dev, I2C_TRANSFER, *dword);
dev->i2c_op = 1;
+ SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
SAA7146_IER_ENABLE(dev, MASK_16|MASK_17);
saa7146_write(dev, MC2, (MASK_00 | MASK_16));
- wait_event_interruptible(dev->i2c_wq, dev->i2c_op == 0);
- if (signal_pending (current)) {
- /* a signal arrived */
- return -ERESTARTSYS;
+ timeout = HZ/100 + 1; /* 10ms */
+ timeout = wait_event_interruptible_timeout(dev->i2c_wq, dev->i2c_op == 0, timeout);
+ if (timeout == -ERESTARTSYS || dev->i2c_op) {
+ SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
+ SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
+ if (timeout == -ERESTARTSYS)
+ /* a signal arrived */
+ return -ERESTARTSYS;
+
+ printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for end of xfer\n");
+ return -EIO;
}
status = saa7146_read(dev, I2C_STATUS);
} else {
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index a0dcd59da76..79875958930 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -9,6 +9,7 @@ config DVB_B2C2_FLEXCOP
select DVB_STV0297 if !DVB_FE_CUSTOMISE
select DVB_BCM3510 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_LGH06XF 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 b8ba8786345..c2b35e36624 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -14,7 +14,7 @@
#include "stv0297.h"
#include "mt312.h"
#include "lgdt330x.h"
-#include "lg_h06xf.h"
+#include "lgh06xf.h"
#include "dvb-pll.h"
/* lnb control */
@@ -303,12 +303,6 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir
return request_firmware(fw, name, fc->dev);
}
-static int lgdt3303_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
-{
- struct flexcop_device *fc = fe->dvb->priv;
- return lg_h06xf_pll_set(fe, &fc->i2c_adap, params);
-}
-
static struct lgdt330x_config air2pc_atsc_hd5000_config = {
.demod_address = 0x59,
.demod_chip = LGDT3303,
@@ -533,7 +527,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* try the air atsc 3nd generation (lgdt3303) */
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;
+ dvb_attach(lgh06xf_attach, fc->fe, &fc->i2c_adap);
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 */
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index ae2ff5dc238..dd66b60fbc9 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -1,13 +1,13 @@
config DVB_BT8XX
tristate "BT8xx based PCI cards"
depends on DVB_CORE && PCI && I2C && VIDEO_BT848
- select DVB_PLL
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_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select FW_LOADER
help
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index 240ad084fa7..50bc32a8bd5 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -480,7 +480,7 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
struct ca_msg *hw_buffer;
int result = 0;
- if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
+ if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
return -ENOMEM;
}
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 14e69a736ed..3e35931af35 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -34,7 +34,6 @@
#include "dvb_frontend.h"
#include "dvb-bt8xx.h"
#include "bt878.h"
-#include "dvb-pll.h"
static int debug;
@@ -568,12 +567,6 @@ static struct mt352_config digitv_alps_tded4_config = {
.demod_init = digitv_alps_tded4_demod_init,
};
-static int tdvs_tua6034_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
- struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
- return lg_h06xf_pll_set(fe, card->i2c_adapter, params);
-}
-
static struct lgdt330x_config tdvs_tua6034_config = {
.demod_address = 0x0e,
.demod_chip = LGDT3303,
@@ -616,7 +609,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
lgdt330x_reset(card);
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;
+ dvb_attach(lgh06xf_attach, card->fe, card->i2c_adapter);
dprintk ("dvb_bt8xx: lgdt330x detected\n");
}
break;
@@ -664,7 +657,7 @@ 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);
+ state = kmalloc(sizeof (struct dst_state), GFP_KERNEL);
if (!state) {
printk("dvb_bt8xx: No memory\n");
break;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index 4745a9017a1..e75f4173c05 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -37,7 +37,7 @@
#include "cx24110.h"
#include "or51211.h"
#include "lgdt330x.h"
-#include "lg_h06xf.h"
+#include "lgh06xf.h"
#include "zl10353.h"
struct dvb_bt8xx_card {
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 9123147e376..d64b96cb0c4 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -746,6 +746,7 @@ static void cinergyt2_query_rc (struct work_struct *work)
dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event);
input_report_key(cinergyt2->rc_input_dev,
cinergyt2->rc_input_event, 0);
+ input_sync(cinergyt2->rc_input_dev);
cinergyt2->rc_input_event = KEY_MAX;
}
cinergyt2->rc_last_code = ~0;
@@ -783,6 +784,7 @@ static void cinergyt2_query_rc (struct work_struct *work)
dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event);
input_report_key(cinergyt2->rc_input_dev,
cinergyt2->rc_input_event, 1);
+ input_sync(cinergyt2->rc_input_dev);
cinergyt2->rc_last_code = rc_events[n].value;
}
}
@@ -798,8 +800,9 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
{
struct input_dev *input_dev;
int i;
+ int err;
- cinergyt2->rc_input_dev = input_dev = input_allocate_device();
+ input_dev = input_allocate_device();
if (!input_dev)
return -ENOMEM;
@@ -817,7 +820,13 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
input_dev->keycodesize = 0;
input_dev->keycodemax = 0;
- input_register_device(cinergyt2->rc_input_dev);
+ err = input_register_device(input_dev);
+ if (err) {
+ input_free_device(input_dev);
+ return err;
+ }
+
+ cinergyt2->rc_input_dev = input_dev;
schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
return 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index ebf4dc5190f..76e9c36597e 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -605,7 +605,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
{ &utype, sizeof utype },
{ priv->ule_skb->data, priv->ule_skb->len - 4 }
};
- unsigned long ule_crc = ~0L, expected_crc;
+ u32 ule_crc = ~0L, expected_crc;
if (priv->ule_dbit) {
/* Set D-bit for CRC32 verification,
* if it was set originally. */
@@ -618,7 +618,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
*((u8 *)priv->ule_skb->tail - 2) << 8 |
*((u8 *)priv->ule_skb->tail - 1);
if (ule_crc != expected_crc) {
- printk(KERN_WARNING "%lu: CRC32 check FAILED: %#lx / %#lx, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n",
+ printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n",
priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0);
#ifdef ULE_DEBUG
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index a263b3f3c21..ad52143602c 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -69,6 +69,8 @@ config DVB_USB_DIBUSB_MC
config DVB_USB_DIB0700
tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)"
depends on DVB_USB
+ select DVB_DIB7000P
+ select DVB_DIB7000M
select DVB_DIB3000MC
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
@@ -96,6 +98,7 @@ config DVB_USB_CXUSB
depends on DVB_USB
select DVB_CX22702 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
help
@@ -157,6 +160,17 @@ config DVB_USB_NOVA_T_USB2
help
Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
+config DVB_USB_TTUSB2
+ tristate "Pinnacle 400e DVB-S USB2.0 support"
+ depends on DVB_USB
+ select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_TDA826X if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The
+ firmware protocol used by this module is similar to the one used by the
+ old ttusb-driver - that's why the module is called dvb-usb-ttusb2.ko.
+
config DVB_USB_DTT200U
tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
depends on DVB_USB
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index e239107998e..154d593bbb0 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -36,6 +36,9 @@ 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-ttusb2-objs = ttusb2.o
+obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o
+
dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o
obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index 2ed3eb62d78..a6c5f19f680 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -116,24 +116,24 @@ static struct dvb_usb_device_properties a800_properties = {
{
.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,
-
- .frontend_attach = dibusb_dib3000mc_frontend_attach,
- .tuner_attach = dibusb_dib3000mc_tuner_attach,
-
- /* parameter for the MPEG2-data transfer */
- .stream = {
- .type = USB_BULK,
- .count = 7,
- .endpoint = 0x06,
- .u = {
- .bulk = {
- .buffersize = 4096,
- }
- }
- },
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+
+ .frontend_attach = dibusb_dib3000mc_frontend_attach,
+ .tuner_attach = dibusb_dib3000mc_tuner_attach,
+
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
.size_of_priv = sizeof(struct dibusb_state),
},
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 43f39069ef3..15d12fce34d 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -14,12 +14,12 @@
* TODO: Use the cx25840-driver for the analogue part
*
* Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
- * Copyright (C) 2005 Michael Krufky (mkrufky@m1k.net)
+ * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org)
* Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au)
*
- * This program is free software; 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 program is free software; 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.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
@@ -27,29 +27,29 @@
#include "cx22702.h"
#include "lgdt330x.h"
-#include "lg_h06xf.h"
+#include "lgh06xf.h"
#include "mt352.h"
#include "mt352_priv.h"
#include "zl10353.h"
/* debug */
int dvb_usb_cxusb_debug;
-module_param_named(debug,dvb_usb_cxusb_debug, int, 0644);
+module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
static int cxusb_ctrl_msg(struct dvb_usb_device *d,
- u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+ u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
{
int wo = (rbuf == NULL || rlen == 0); /* write-only */
u8 sndbuf[1+wlen];
- memset(sndbuf,0,1+wlen);
+ memset(sndbuf, 0, 1+wlen);
sndbuf[0] = cmd;
- memcpy(&sndbuf[1],wbuf,wlen);
+ memcpy(&sndbuf[1], wbuf, wlen);
if (wo)
- dvb_usb_generic_write(d,sndbuf,1+wlen);
+ dvb_usb_generic_write(d, sndbuf, 1+wlen);
else
- dvb_usb_generic_rw(d,sndbuf,1+wlen,rbuf,rlen,0);
+ dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
return 0;
}
@@ -58,14 +58,14 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d,
static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
{
struct cxusb_state *st = d->priv;
- u8 o[2],i;
+ u8 o[2], i;
if (st->gpio_write_state[GPIO_TUNER] == onoff)
return;
o[0] = GPIO_TUNER;
o[1] = onoff;
- cxusb_ctrl_msg(d,CMD_GPIO_WRITE,o,2,&i,1);
+ cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
if (i != 0x01)
deb_info("gpio_write failed.\n");
@@ -74,7 +74,8 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
}
/* I2C */
-static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int i;
@@ -89,12 +90,12 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
if (d->udev->descriptor.idVendor == USB_VID_MEDION)
switch (msg[i].addr) {
- case 0x63:
- cxusb_gpio_tuner(d,0);
- break;
- default:
- cxusb_gpio_tuner(d,1);
- break;
+ case 0x63:
+ cxusb_gpio_tuner(d, 0);
+ break;
+ default:
+ cxusb_gpio_tuner(d, 1);
+ break;
}
/* read request */
@@ -103,26 +104,27 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
obuf[0] = msg[i].len;
obuf[1] = msg[i+1].len;
obuf[2] = msg[i].addr;
- memcpy(&obuf[3],msg[i].buf,msg[i].len);
+ memcpy(&obuf[3], msg[i].buf, msg[i].len);
if (cxusb_ctrl_msg(d, CMD_I2C_READ,
- obuf, 3+msg[i].len,
- ibuf, 1+msg[i+1].len) < 0)
+ obuf, 3+msg[i].len,
+ ibuf, 1+msg[i+1].len) < 0)
break;
if (ibuf[0] != 0x08)
deb_i2c("i2c read may have failed\n");
- memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len);
+ memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
i++;
} else { /* write */
u8 obuf[2+msg[i].len], ibuf;
obuf[0] = msg[i].addr;
obuf[1] = msg[i].len;
- memcpy(&obuf[2],msg[i].buf,msg[i].len);
+ memcpy(&obuf[2], msg[i].buf, msg[i].len);
- if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0)
+ if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf,
+ 2+msg[i].len, &ibuf,1) < 0)
break;
if (ibuf != 0x08)
deb_i2c("i2c write may have failed\n");
@@ -324,16 +326,8 @@ static int cxusb_mt352_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *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 = {
.demod_address = 0x63,
-
.output_mode = CX22702_PARALLEL_OUTPUT,
};
@@ -374,31 +368,27 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x61;
- adap->pll_desc = &dvb_pll_thomson_dtt7579;
- adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61,
+ NULL, &dvb_pll_thomson_dtt7579);
return 0;
}
static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x61;
- adap->pll_desc = &dvb_pll_lg_z201;
- adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, &dvb_pll_lg_z201);
return 0;
}
static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x60;
- adap->pll_desc = &dvb_pll_thomson_dtt7579;
- adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ dvb_attach(dvb_pll_attach, adap->fe, 0x60,
+ NULL, &dvb_pll_thomson_dtt7579);
return 0;
}
-static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_adapter *adap)
+static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
{
- adap->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
+ dvb_attach(lgh06xf_attach, adap->fe, &adap->dev->i2c_adap);
return 0;
}
@@ -410,7 +400,8 @@ static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1);
- if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, &adap->dev->i2c_adap)) != NULL)
+ if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config,
+ &adap->dev->i2c_adap)) != NULL)
return 0;
return -EIO;
@@ -423,7 +414,8 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
- if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, &adap->dev->i2c_adap)) != NULL)
+ if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config,
+ &adap->dev->i2c_adap)) != NULL)
return 0;
return -EIO;
@@ -437,7 +429,8 @@ static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
- if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config, &adap->dev->i2c_adap)) != NULL)
+ if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config,
+ &adap->dev->i2c_adap)) != NULL)
return 0;
return -EIO;
@@ -450,8 +443,11 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
- 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))
+ 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;
@@ -463,7 +459,8 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
*/
#define BLUEBIRD_01_ID_OFFSET 6638
-static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw)
+static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
+ const struct firmware *fw)
{
if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
return -EINVAL;
@@ -471,10 +468,12 @@ static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const
if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
- fw->data[BLUEBIRD_01_ID_OFFSET + 2] = udev->descriptor.idProduct + 1;
- fw->data[BLUEBIRD_01_ID_OFFSET + 3] = udev->descriptor.idProduct >> 8;
+ fw->data[BLUEBIRD_01_ID_OFFSET + 2] =
+ udev->descriptor.idProduct + 1;
+ fw->data[BLUEBIRD_01_ID_OFFSET + 3] =
+ udev->descriptor.idProduct >> 8;
- return usb_cypress_load_firmware(udev,fw,CYPRESS_FX2);
+ return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
}
return -EINVAL;
@@ -488,7 +487,7 @@ 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)
+ const struct usb_device_id *id)
{
if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 ||
dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
@@ -502,20 +501,20 @@ static int cxusb_probe(struct usb_interface *intf,
}
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_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_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 */
+ { 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_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_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);
@@ -529,20 +528,20 @@ static struct dvb_usb_device_properties cxusb_medion_properties = {
.num_adapters = 1,
.adapter = {
{
- .streaming_ctrl = cxusb_streaming_ctrl,
- .frontend_attach = cxusb_cx22702_frontend_attach,
- .tuner_attach = cxusb_fmd1216me_tuner_attach,
- /* parameter for the MPEG2-data transfer */
- .stream = {
- .type = USB_BULK,
- .count = 5,
- .endpoint = 0x02,
- .u = {
- .bulk = {
- .buffersize = 8192,
- }
- }
- },
+ .streaming_ctrl = cxusb_streaming_ctrl,
+ .frontend_attach = cxusb_cx22702_frontend_attach,
+ .tuner_attach = cxusb_fmd1216me_tuner_attach,
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 5,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
},
},
@@ -575,21 +574,21 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
.num_adapters = 1,
.adapter = {
{
- .streaming_ctrl = cxusb_streaming_ctrl,
- .frontend_attach = cxusb_lgdt3303_frontend_attach,
- .tuner_attach = cxusb_lgdt3303_tuner_attach,
-
- /* parameter for the MPEG2-data transfer */
- .stream = {
- .type = USB_BULK,
- .count = 5,
- .endpoint = 0x02,
- .u = {
- .bulk = {
- .buffersize = 8192,
- }
- }
- },
+ .streaming_ctrl = cxusb_streaming_ctrl,
+ .frontend_attach = cxusb_lgdt3303_frontend_attach,
+ .tuner_attach = cxusb_lgh064f_tuner_attach,
+
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 5,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
},
},
@@ -627,20 +626,20 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
.num_adapters = 1,
.adapter = {
{
- .streaming_ctrl = cxusb_streaming_ctrl,
- .frontend_attach = cxusb_dee1601_frontend_attach,
- .tuner_attach = cxusb_dee1601_tuner_attach,
- /* parameter for the MPEG2-data transfer */
+ .streaming_ctrl = cxusb_streaming_ctrl,
+ .frontend_attach = cxusb_dee1601_frontend_attach,
+ .tuner_attach = cxusb_dee1601_tuner_attach,
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 5,
- .endpoint = 0x04,
- .u = {
- .bulk = {
- .buffersize = 8192,
- }
- }
- },
+ .count = 5,
+ .endpoint = 0x04,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
},
},
@@ -686,21 +685,21 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
.num_adapters = 2,
.adapter = {
{
- .streaming_ctrl = cxusb_streaming_ctrl,
- .frontend_attach = cxusb_mt352_frontend_attach,
- .tuner_attach = cxusb_lgz201_tuner_attach,
+ .streaming_ctrl = cxusb_streaming_ctrl,
+ .frontend_attach = cxusb_mt352_frontend_attach,
+ .tuner_attach = cxusb_lgz201_tuner_attach,
- /* parameter for the MPEG2-data transfer */
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 5,
- .endpoint = 0x04,
- .u = {
- .bulk = {
- .buffersize = 8192,
- }
- }
- },
+ .count = 5,
+ .endpoint = 0x04,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
},
},
.power_ctrl = cxusb_bluebird_power_ctrl,
@@ -736,21 +735,21 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
.num_adapters = 1,
.adapter = {
{
- .streaming_ctrl = cxusb_streaming_ctrl,
- .frontend_attach = cxusb_mt352_frontend_attach,
- .tuner_attach = cxusb_dtt7579_tuner_attach,
+ .streaming_ctrl = cxusb_streaming_ctrl,
+ .frontend_attach = cxusb_mt352_frontend_attach,
+ .tuner_attach = cxusb_dtt7579_tuner_attach,
- /* parameter for the MPEG2-data transfer */
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 5,
- .endpoint = 0x04,
- .u = {
- .bulk = {
- .buffersize = 8192,
- }
- }
- },
+ .count = 5,
+ .endpoint = 0x04,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
},
},
.power_ctrl = cxusb_bluebird_power_ctrl,
@@ -776,7 +775,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
static struct usb_driver cxusb_driver = {
.name = "dvb_usb_cxusb",
.probe = cxusb_probe,
- .disconnect = dvb_usb_device_exit,
+ .disconnect = dvb_usb_device_exit,
.id_table = cxusb_table,
};
@@ -802,7 +801,7 @@ module_init (cxusb_module_init);
module_exit (cxusb_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_AUTHOR("Michael Krufky <mkrufky@m1k.net>");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
MODULE_VERSION("1.0-alpha");
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index ac84347f9d4..cda3adea24f 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -24,18 +24,23 @@ extern int dvb_usb_dib0700_debug;
#define REQUEST_I2C_WRITE 0x3
#define REQUEST_POLL_RC 0x4
#define REQUEST_JUMPRAM 0x8
+#define REQUEST_SET_CLOCK 0xB
#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( " " )
+#define REQUEST_GET_VERSION 0x15
struct dib0700_state {
u8 channel_state;
u16 mt2060_if1[2];
+
+ u8 is_dib7000pc;
};
extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
+extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
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;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index dca6c698566..6a4d150784a 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -135,14 +135,46 @@ struct i2c_algorithm dib0700_i2c_algo = {
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;
+ u8 b[16];
+ s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
+ REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
+
+ deb_info("FW GET_VERSION length: %d\n",ret);
+
+ *cold = ret <= 0;
deb_info("cold: %d\n", *cold);
return 0;
}
+static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
+ u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
+ u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
+{
+ u8 b[10];
+ b[0] = REQUEST_SET_CLOCK;
+ b[1] = (en_pll << 7) | (pll_src << 6) | (pll_range << 5) | (clock_gpio3 << 4);
+ b[2] = (pll_prediv >> 8) & 0xff; // MSB
+ b[3] = pll_prediv & 0xff; // LSB
+ b[4] = (pll_loopdiv >> 8) & 0xff; // MSB
+ b[5] = pll_loopdiv & 0xff; // LSB
+ b[6] = (free_div >> 8) & 0xff; // MSB
+ b[7] = free_div & 0xff; // LSB
+ b[8] = (dsuScaler >> 8) & 0xff; // MSB
+ b[9] = dsuScaler & 0xff; // LSB
+
+ return dib0700_ctrl_wr(d, b, 10);
+}
+
+int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
+{
+ switch (clk_MHz) {
+ case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break;
+ default: return -EINVAL;
+ }
+ return 0;
+}
+
static int dib0700_jumpram(struct usb_device *udev, u32 address)
{
int ret, actlen;
@@ -197,7 +229,7 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
/* start the firmware */
if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) {
info("firmware started successfully.");
- msleep(100);
+ msleep(500);
}
} else
ret = -EIO;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index e473bfed226..2208757d901 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -9,6 +9,8 @@
#include "dib0700.h"
#include "dib3000mc.h"
+#include "dib7000m.h"
+#include "dib7000p.h"
#include "mt2060.h"
static int force_lna_activation;
@@ -95,37 +97,189 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
}
/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
-/*
-static struct mt2060_config stk7000p_mt2060_config = {
- 0x60
+static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
+ BAND_UHF | BAND_VHF, // band_caps
+
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
+
+ 712, // inv_gain
+ 41, // time_stabiliz
+
+ 0, // alpha_level
+ 118, // thlock
+
+ 0, // wbd_inv
+ 4095, // wbd_ref
+ 0, // wbd_sel
+ 0, // wbd_alpha
+
+ 42598, // agc1_max
+ 17694, // agc1_min
+ 45875, // agc2_max
+ 2621, // agc2_min
+ 0, // agc1_pt1
+ 76, // agc1_pt2
+ 139, // agc1_pt3
+ 52, // agc1_slope1
+ 59, // agc1_slope2
+ 107, // agc2_pt1
+ 172, // agc2_pt2
+ 57, // agc2_slope1
+ 70, // agc2_slope2
+
+ 21, // alpha_mant
+ 25, // alpha_exp
+ 28, // beta_mant
+ 48, // beta_exp
+
+ 1, // perform_agc_softsplit
+ { 0, // split_min
+ 107, // split_max
+ 51800, // global_split_min
+ 24700 // global_split_max
+ },
+};
+
+static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = {
+ BAND_UHF | BAND_VHF,
+
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
+
+ 712, // inv_gain
+ 41, // time_stabiliz
+
+ 0, // alpha_level
+ 118, // thlock
+
+ 0, // wbd_inv
+ 4095, // wbd_ref
+ 0, // wbd_sel
+ 0, // wbd_alpha
+
+ 42598, // agc1_max
+ 16384, // agc1_min
+ 42598, // agc2_max
+ 0, // agc2_min
+
+ 0, // agc1_pt1
+ 137, // agc1_pt2
+ 255, // agc1_pt3
+
+ 0, // agc1_slope1
+ 255, // agc1_slope2
+
+ 0, // agc2_pt1
+ 0, // agc2_pt2
+
+ 0, // agc2_slope1
+ 41, // agc2_slope2
+
+ 15, // alpha_mant
+ 25, // alpha_exp
+
+ 28, // beta_mant
+ 48, // beta_exp
+
+ 0, // perform_agc_softsplit
+};
+
+static struct dibx000_bandwidth_config stk7700p_pll_config = {
+ 60000, 30000, // internal, sampling
+ 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+ 0, 0, 1, 1, 0, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+ (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+ 60258167, // ifreq
+ 20452225, // timf
+};
+
+static struct dib7000m_config stk7700p_dib7000m_config = {
+ .dvbt_mode = 1,
+ .output_mpeg2_in_188_bytes = 1,
+ .quartz_direct = 1,
+
+ .agc_config_count = 1,
+ .agc = &stk7700p_7000m_mt2060_agc_config,
+ .bw = &stk7700p_pll_config,
+
+ .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
+};
+
+static struct dib7000p_config stk7700p_dib7000p_config = {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc = &stk7700p_7000p_mt2060_agc_config,
+ .bw = &stk7700p_pll_config,
+
+ .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
};
-*/
static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct dib0700_state *st = adap->dev->priv;
/* 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);
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(50);
+
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
+ dib0700_ctrl_clock(adap->dev, 72, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100);
+
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ st->mt2060_if1[0] = 1220;
+
+ if (dib7000pc_detection(&adap->dev->i2c_adap)) {
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config);
+ st->is_dib7000pc = 1;
+ } else
+ adap->fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config);
-// adap->fe = dib7000m_attach(&adap->dev->i2c_adap, &stk7700p_dib7000m_config, 18);
- return 0;
+ return adap->fe == NULL ? -ENODEV : 0;
}
+static struct mt2060_config stk7700p_mt2060_config = {
+ 0x60
+};
+
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 dib0700_state *st = adap->dev->priv;
+ struct i2c_adapter *tun_i2c;
+
+ if (st->is_dib7000pc)
+ tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+ else
+ tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+ return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config,
+ st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
}
struct usb_device_id dib0700_usb_id_table[] = {
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) },
+
{ 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) },
+ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) },
+ { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) },
+ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
+ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -167,20 +321,32 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .num_device_descs = 3,
+ .num_device_descs = 6,
.devices = {
{ "DiBcom STK7700P reference design",
- { &dib0700_usb_id_table[0], NULL },
+ { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
{ NULL },
},
{ "Hauppauge Nova-T Stick",
- { &dib0700_usb_id_table[3], NULL },
+ { &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL },
{ NULL },
},
{ "AVerMedia AVerTV DVB-T Volar",
- { &dib0700_usb_id_table[4], NULL },
+ { &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] },
{ NULL },
},
+ { "Compro Videomate U500",
+ { &dib0700_usb_id_table[6], NULL },
+ { NULL },
+ },
+ { "Uniwill STK7700P based (Hama and others)",
+ { &dib0700_usb_id_table[7], NULL },
+ { NULL },
+ },
+ { "Leadtek Winfast DTV Dongle (STK7700P based)",
+ { &dib0700_usb_id_table[8], NULL },
+ { NULL },
+ }
}
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -202,7 +368,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.num_device_descs = 1,
.devices = {
{ "Hauppauge Nova-T 500 Dual DVB-T",
- { &dib0700_usb_id_table[1], &dib0700_usb_id_table[2], NULL },
+ { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL },
{ NULL },
},
}
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 4fe363e4835..7a6ae8f482e 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -163,23 +163,23 @@ static struct dvb_usb_device_properties dibusb1_1_properties = {
.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,
- .frontend_attach = dibusb_dib3000mb_frontend_attach,
- .tuner_attach = dibusb_tuner_probe_and_attach,
+ .streaming_ctrl = dibusb_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .frontend_attach = dibusb_dib3000mb_frontend_attach,
+ .tuner_attach = dibusb_tuner_probe_and_attach,
- /* parameter for the MPEG2-data transfer */
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 7,
- .endpoint = 0x02,
- .u = {
- .bulk = {
- .buffersize = 4096,
- }
- }
- },
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
.size_of_priv = sizeof(struct dibusb_state),
}
},
@@ -248,23 +248,23 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
.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,
- .frontend_attach = dibusb_dib3000mb_frontend_attach,
- .tuner_attach = dibusb_tuner_probe_and_attach,
+ .streaming_ctrl = dibusb_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .frontend_attach = dibusb_dib3000mb_frontend_attach,
+ .tuner_attach = dibusb_tuner_probe_and_attach,
- /* parameter for the MPEG2-data transfer */
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 7,
- .endpoint = 0x02,
- .u = {
- .bulk = {
- .buffersize = 4096,
- }
- }
- },
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
.size_of_priv = sizeof(struct dibusb_state),
},
},
@@ -312,22 +312,23 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = {
.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,
- .frontend_attach = dibusb_dib3000mb_frontend_attach,
- .tuner_attach = dibusb_thomson_tuner_attach,
- /* parameter for the MPEG2-data transfer */
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .frontend_attach = dibusb_dib3000mb_frontend_attach,
+ .tuner_attach = dibusb_thomson_tuner_attach,
+
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 7,
- .endpoint = 0x06,
- .u = {
- .bulk = {
- .buffersize = 4096,
- }
- }
- },
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
.size_of_priv = sizeof(struct dibusb_state),
}
},
@@ -369,22 +370,22 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = {
.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,
- .frontend_attach = dibusb_dib3000mb_frontend_attach,
- .tuner_attach = dibusb_tuner_probe_and_attach,
- /* parameter for the MPEG2-data transfer */
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .frontend_attach = dibusb_dib3000mb_frontend_attach,
+ .tuner_attach = dibusb_tuner_probe_and_attach,
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 7,
- .endpoint = 0x06,
- .u = {
- .bulk = {
- .buffersize = 4096,
- }
- }
- },
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
.size_of_priv = sizeof(struct dibusb_state),
}
},
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
index a0fd37efc04..e7ea3e753d6 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -54,23 +54,23 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
{
.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,
- .frontend_attach = dibusb_dib3000mc_frontend_attach,
- .tuner_attach = dibusb_dib3000mc_tuner_attach,
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .frontend_attach = dibusb_dib3000mc_frontend_attach,
+ .tuner_attach = dibusb_dib3000mc_tuner_attach,
/* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 7,
- .endpoint = 0x06,
- .u = {
- .bulk = {
- .buffersize = 4096,
- }
- }
- },
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
.size_of_priv = sizeof(struct dibusb_state),
}
},
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 8fb34375c1f..4a198d4755b 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -274,20 +274,20 @@ static struct dvb_usb_device_properties digitv_properties = {
.num_adapters = 1,
.adapter = {
{
- .frontend_attach = digitv_frontend_attach,
- .tuner_attach = digitv_tuner_attach,
+ .frontend_attach = digitv_frontend_attach,
+ .tuner_attach = digitv_tuner_attach,
- /* parameter for the MPEG2-data transfer */
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 7,
- .endpoint = 0x02,
- .u = {
- .bulk = {
- .buffersize = 4096,
- }
- }
- },
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
}
},
.identify_state = digitv_identify_state,
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index fa43a41d753..7dbe1432101 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -268,20 +268,20 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
.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 */
+ .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 = 0x02,
- .u = {
- .bulk = {
- .buffersize = 4096,
- }
- }
- },
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
}
},
.power_ctrl = dtt200u_power_ctrl,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 4d6b069536c..299382dcb81 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -33,6 +33,7 @@
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
+#define USB_VID_UNIWILL 0x1584
#define USB_VID_WIDEVIEW 0x14aa
/* Product IDs */
@@ -46,6 +47,7 @@
#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_COMPRO_VIDEOMATE_U500 0x1e78
#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
@@ -53,7 +55,9 @@
#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6
#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
#define USB_PID_DIBCOM_STK7700P 0x1e14
+#define USB_PID_DIBCOM_STK7700P_PC 0x1e78
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
+#define USB_PID_UNIWILL_STK7700P 0x6003
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
@@ -97,7 +101,9 @@
#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_HAUPPAUGE_NOVA_T_STICK_2 0x7060
+#define USB_PID_AVERMEDIA_VOLAR 0xa807
+#define USB_PID_AVERMEDIA_VOLAR_2 0xb808
#define USB_PID_NEBULA_DIGITV 0x0201
#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500
@@ -110,8 +116,8 @@
#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_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
@@ -125,7 +131,9 @@
#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_WINFAST_DTV_DONGLE_STK7700P 0x6f00
#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-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 794e4471561..19ff5978bc9 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -90,7 +90,9 @@ schedule:
int dvb_usb_remote_init(struct dvb_usb_device *d)
{
+ struct input_dev *input_dev;
int i;
+ int err;
if (d->props.rc_key_map == NULL ||
d->props.rc_query == NULL ||
@@ -100,23 +102,24 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
usb_make_path(d->udev, d->rc_phys, 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)
+ input_dev = input_allocate_device();
+ if (!input_dev)
return -ENOMEM;
- d->rc_input_dev->evbit[0] = BIT(EV_KEY);
- d->rc_input_dev->keycodesize = sizeof(unsigned char);
- 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;
+ input_dev->evbit[0] = BIT(EV_KEY);
+ input_dev->keycodesize = sizeof(unsigned char);
+ input_dev->keycodemax = KEY_MAX;
+ input_dev->name = "IR-receiver inside an USB DVB receiver";
+ input_dev->phys = d->rc_phys;
+ usb_to_input_id(d->udev, &input_dev->id);
+ 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);
for (i = 0; i < d->props.rc_key_map_size; i++) {
- deb_rc("setting bit for event %d item %d\n",d->props.rc_key_map[i].event, i);
- set_bit(d->props.rc_key_map[i].event, d->rc_input_dev->keybit);
+ deb_rc("setting bit for event %d item %d\n",
+ d->props.rc_key_map[i].event, i);
+ set_bit(d->props.rc_key_map[i].event, input_dev->keybit);
}
/* Start the remote-control polling. */
@@ -124,10 +127,16 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
d->props.rc_interval = 100; /* default */
/* setting these two values to non-zero, we have to manage key repeats */
- d->rc_input_dev->rep[REP_PERIOD] = d->props.rc_interval;
- d->rc_input_dev->rep[REP_DELAY] = d->props.rc_interval + 150;
+ input_dev->rep[REP_PERIOD] = d->props.rc_interval;
+ input_dev->rep[REP_DELAY] = d->props.rc_interval + 150;
- input_register_device(d->rc_input_dev);
+ err = input_register_device(input_dev);
+ if (err) {
+ input_free_device(input_dev);
+ return err;
+ }
+
+ d->rc_input_dev = input_dev;
INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index 7375eb20166..518d67fca5e 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -194,19 +194,19 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.num_adapters = 1,
.adapter = {
{
- .streaming_ctrl = gp8psk_streaming_ctrl,
- .frontend_attach = gp8psk_frontend_attach,
- /* parameter for the MPEG2-data transfer */
+ .streaming_ctrl = gp8psk_streaming_ctrl,
+ .frontend_attach = gp8psk_frontend_attach,
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 7,
- .endpoint = 0x82,
- .u = {
- .bulk = {
- .buffersize = 8192,
- }
- }
- },
+ .count = 7,
+ .endpoint = 0x82,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
}
},
.power_ctrl = gp8psk_power_ctrl,
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index a58874c790b..badc468170e 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -90,9 +90,11 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
for (i = 0; i < ARRAY_SIZE(haupp_rc_keys); i++) {
- deb_rc("c: %x, d: %x\n",haupp_rc_keys[i].data,haupp_rc_keys[i].custom);
if (haupp_rc_keys[i].data == data &&
haupp_rc_keys[i].custom == custom) {
+
+ deb_rc("c: %x, d: %x\n",haupp_rc_keys[i].data,haupp_rc_keys[i].custom);
+
*event = haupp_rc_keys[i].event;
*state = REMOTE_KEY_PRESSED;
if (st->old_toggle == toggle) {
@@ -163,23 +165,23 @@ static struct dvb_usb_device_properties nova_t_properties = {
.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,
- .frontend_attach = dibusb_dib3000mc_frontend_attach,
- .tuner_attach = dibusb_dib3000mc_tuner_attach,
-
- /* parameter for the MPEG2-data transfer */
- .stream = {
- .type = USB_BULK,
- .count = 7,
- .endpoint = 0x06,
- .u = {
- .bulk = {
- .buffersize = 4096,
- }
- }
- },
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .frontend_attach = dibusb_dib3000mc_frontend_attach,
+ .tuner_attach = dibusb_dib3000mc_tuner_attach,
+
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
.size_of_priv = sizeof(struct dibusb_state),
}
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
new file mode 100644
index 00000000000..95d29976ed7
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -0,0 +1,270 @@
+/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
+ * (e.g. Pinnacle 400e DVB-S USB2.0).
+ *
+ * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes.
+ *
+ * TDA8263 + TDA10086
+ *
+ * I2C addresses:
+ * 0x08 - LNBP21PD - LNB power supply
+ * 0x0e - TDA10086 - Demodulator
+ * 0x50 - FX2 eeprom
+ * 0x60 - TDA8263 - Tuner
+ * 0x78 ???
+ *
+ * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
+ * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
+ * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#define DVB_USB_LOG_PREFIX "ttusb2"
+#include "dvb-usb.h"
+
+#include "ttusb2.h"
+
+#include "tda826x.h"
+#include "tda10086.h"
+#include "lnbp21.h"
+
+/* debug */
+static int dvb_usb_ttusb2_debug;
+#define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args)
+module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS);
+
+struct ttusb2_state {
+ u8 id;
+};
+
+static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
+ u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ struct ttusb2_state *st = d->priv;
+ u8 s[wlen+4],r[64] = { 0 };
+ int ret = 0;
+
+ memset(s,0,wlen+4);
+
+ s[0] = 0xaa;
+ s[1] = ++st->id;
+ s[2] = cmd;
+ s[3] = wlen;
+ memcpy(&s[4],wbuf,wlen);
+
+ ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0);
+
+ if (ret != 0 ||
+ r[0] != 0x55 ||
+ r[1] != s[1] ||
+ r[2] != cmd ||
+ (rlen > 0 && r[3] != rlen)) {
+ warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]);
+ return -EIO;
+ }
+
+ if (rlen > 0)
+ memcpy(rbuf, &r[4], rlen);
+
+ return 0;
+}
+
+static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ static u8 obuf[60], ibuf[60];
+ int i,read;
+
+ 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++) {
+ read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+
+ obuf[0] = (msg[i].addr << 1) | read;
+ obuf[1] = msg[i].len;
+
+ /* read request */
+ if (read)
+ obuf[2] = msg[i+1].len;
+ else
+ obuf[2] = 0;
+
+ memcpy(&obuf[3],msg[i].buf,msg[i].len);
+
+ if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) {
+ err("i2c transfer failed.");
+ break;
+ }
+
+ if (read) {
+ memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len);
+ i++;
+ }
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+static u32 ttusb2_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm ttusb2_i2c_algo = {
+ .master_xfer = ttusb2_i2c_xfer,
+ .functionality = ttusb2_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int ttusb2_identify_state (struct usb_device *udev, struct
+ dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
+ return 0;
+}
+
+static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 b = onoff;
+ ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0);
+ return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0);
+}
+
+
+static struct tda10086_config tda10086_config = {
+ .demod_address = 0x0e,
+ .invert = 0,
+};
+
+static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ if (usb_set_interface(adap->dev->udev,0,3) < 0)
+ err("set interface to alts=3 failed");
+
+ if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
+ deb_info("TDA10086 attach failed\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
+ deb_info("TDA8263 attach failed\n");
+ return -ENODEV;
+ }
+
+ if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
+ deb_info("LNBP21 attach failed\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties ttusb2_properties;
+
+static int ttusb2_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,&ttusb2_properties,THIS_MODULE,NULL);
+}
+
+static struct usb_device_id ttusb2_table [] = {
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
+ {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, ttusb2_table);
+
+static struct dvb_usb_device_properties ttusb2_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-pctv-400e-01.fw",
+
+ .size_of_priv = sizeof(struct ttusb2_state),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .streaming_ctrl = NULL, // ttusb2_streaming_ctrl,
+
+ .frontend_attach = ttusb2_frontend_attach,
+ .tuner_attach = ttusb2_tuner_attach,
+
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_ISOC,
+ .count = 5,
+ .endpoint = 0x02,
+ .u = {
+ .isoc = {
+ .framesperurb = 4,
+ .framesize = 940,
+ .interval = 1,
+ }
+ }
+ }
+ }
+ },
+
+ .power_ctrl = ttusb2_power_ctrl,
+ .identify_state = ttusb2_identify_state,
+
+ .i2c_algo = &ttusb2_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Pinnacle 400e DVB-S USB2.0",
+ { &ttusb2_table[0], NULL },
+ { NULL },
+ },
+ }
+};
+
+static struct usb_driver ttusb2_driver = {
+ .name = "dvb_usb_ttusb2",
+ .probe = ttusb2_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = ttusb2_table,
+};
+
+/* module stuff */
+static int __init ttusb2_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&ttusb2_driver))) {
+ err("usb_register failed. Error number %d",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit ttusb2_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&ttusb2_driver);
+}
+
+module_init (ttusb2_module_init);
+module_exit (ttusb2_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.h b/drivers/media/dvb/dvb-usb/ttusb2.h
new file mode 100644
index 00000000000..52a63af4089
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/ttusb2.h
@@ -0,0 +1,70 @@
+/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
+ * (e.g. Pinnacle 400e DVB-S USB2.0).
+ *
+ * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
+ * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
+ * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_TTUSB2_H_
+#define _DVB_USB_TTUSB2_H_
+
+/* TTUSB protocol
+ *
+ * always to messages (out/in)
+ * out message:
+ * 0xaa <id> <cmdbyte> <datalen> <data...>
+ *
+ * in message (complete block is always 0x40 bytes long)
+ * 0x55 <id> <cmdbyte> <datalen> <data...>
+ *
+ * id is incremented for each transaction
+ */
+
+#define CMD_DSP_DOWNLOAD 0x13
+/* out data: <byte>[28]
+ * last block must be empty */
+
+#define CMD_DSP_BOOT 0x14
+/* out data: nothing */
+
+#define CMD_POWER 0x15
+/* out data: <on=1/off=0> */
+
+#define CMD_LNB 0x16
+/* out data: <power=1> <18V=0,13V=1> <tone> <??=1> <??=1> */
+
+#define CMD_GET_VERSION 0x17
+/* in data: <version_byte>[5] */
+
+#define CMD_DISEQC 0x18
+/* out data: <master=0xff/burst=??> <cmdlen> <cmdbytes>[cmdlen] */
+
+#define CMD_PID_ENABLE 0x22
+/* out data: <index> <type: ts=1/sec=2> <pid msb> <pid lsb> */
+
+#define CMD_PID_DISABLE 0x23
+/* out data: <index> */
+
+#define CMD_FILTER_ENABLE 0x24
+/* out data: <index> <pid_idx> <filter>[12] <mask>[12] */
+
+#define CMD_FILTER_DISABLE 0x25
+/* out data: <index> */
+
+#define CMD_GET_DSP_VERSION 0x26
+/* in data: <version_byte>[28] */
+
+#define CMD_I2C_XFER 0x31
+/* out data: <addr << 1> <sndlen> <rcvlen> <data>[sndlen]
+ * in data: <addr << 1> <sndlen> <rcvlen> <data>[rcvlen] */
+
+#define CMD_I2C_BITRATE 0x32
+/* out data: <default=0> */
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index f9941ea88b3..f77b48f7658 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -99,21 +99,21 @@ static struct dvb_usb_device_properties umt_properties = {
.num_adapters = 1,
.adapter = {
{
- .streaming_ctrl = dibusb2_0_streaming_ctrl,
- .frontend_attach = umt_mt352_frontend_attach,
- .tuner_attach = umt_tuner_attach,
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .frontend_attach = umt_mt352_frontend_attach,
+ .tuner_attach = umt_tuner_attach,
- /* parameter for the MPEG2-data transfer */
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 20,
- .endpoint = 0x06,
- .u = {
- .bulk = {
- .buffersize = 512,
- }
- }
- },
+ .count = 20,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 512,
+ }
+ }
+ },
.size_of_priv = sizeof(struct dibusb_state),
}
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index 02bd61aaac6..16533b31a82 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -275,22 +275,22 @@ static struct dvb_usb_device_properties vp702x_properties = {
.caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
.streaming_ctrl = vp702x_streaming_ctrl,
- .frontend_attach = vp702x_frontend_attach,
+ .frontend_attach = vp702x_frontend_attach,
- /* parameter for the MPEG2-data transfer */
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
.count = 10,
- .endpoint = 0x02,
- .u = {
- .bulk = {
- .buffersize = 4096,
- }
- }
- },
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
.size_of_priv = sizeof(struct vp702x_state),
}
- },
+ },
.read_mac_address = vp702x_read_mac_addr,
.rc_key_map = vp702x_rc_keys,
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index b4cf002703a..69a46b3607a 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -125,7 +125,25 @@ static struct dvb_usb_rc_key vp7045_rc_keys[] = {
{ 0x00, 0x00, KEY_TAB }, /* Tab */
{ 0x00, 0x48, KEY_INFO }, /* Preview */
{ 0x00, 0x04, KEY_LIST }, /* RecordList */
- { 0x00, 0x0f, KEY_TEXT } /* Teletext */
+ { 0x00, 0x0f, KEY_TEXT }, /* Teletext */
+ { 0x00, 0x41, KEY_PREVIOUSSONG },
+ { 0x00, 0x42, KEY_NEXTSONG },
+ { 0x00, 0x4b, KEY_UP },
+ { 0x00, 0x51, KEY_DOWN },
+ { 0x00, 0x4e, KEY_LEFT },
+ { 0x00, 0x52, KEY_RIGHT },
+ { 0x00, 0x4f, KEY_ENTER },
+ { 0x00, 0x13, KEY_CANCEL },
+ { 0x00, 0x4a, KEY_CLEAR },
+ { 0x00, 0x54, KEY_PRINT }, /* Capture */
+ { 0x00, 0x43, KEY_SUBTITLE }, /* Subtitle/CC */
+ { 0x00, 0x08, KEY_VIDEO }, /* A/V */
+ { 0x00, 0x07, KEY_SLEEP }, /* Hibernate */
+ { 0x00, 0x45, KEY_ZOOM }, /* Zoom+ */
+ { 0x00, 0x18, KEY_RED},
+ { 0x00, 0x53, KEY_GREEN},
+ { 0x00, 0x5e, KEY_YELLOW},
+ { 0x00, 0x5f, KEY_BLUE}
};
static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
@@ -217,18 +235,18 @@ static struct dvb_usb_device_properties vp7045_properties = {
.num_adapters = 1,
.adapter = {
{
- .frontend_attach = vp7045_frontend_attach,
- /* parameter for the MPEG2-data transfer */
+ .frontend_attach = vp7045_frontend_attach,
+ /* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 7,
- .endpoint = 0x02,
- .u = {
- .bulk = {
- .buffersize = 4096,
- }
- }
- },
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
}
},
.power_ctrl = vp7045_power_ctrl,
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index aebb8d6f26f..af314bb1dca 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -172,6 +172,22 @@ config DVB_DIB3000MC
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
+config DVB_DIB7000M
+ tristate "DiBcom 7000MA/MB/PA/PB/MC"
+ 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.
+
+config DVB_DIB7000P
+ tristate "DiBcom 7000PC"
+ 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.
+
comment "DVB-C (cable) frontends"
depends on DVB_CORE
@@ -281,6 +297,14 @@ config DVB_TUNER_MT2060
help
A driver for the silicon IF tuner MT2060 from Microtune.
+config DVB_TUNER_LGH06XF
+ tristate "LG TDVS-H06xF ATSC tuner"
+ depends on DVB_CORE && I2C
+ select DVB_PLL
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the LG TDVS-H06xF ATSC tuner family.
+
comment "Miscellaneous devices"
depends on DVB_CORE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index dce9cf0c75c..3fa6e5d32a9 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -13,6 +13,8 @@ obj-$(CONFIG_DVB_TDA8083) += tda8083.o
obj-$(CONFIG_DVB_L64781) += l64781.o
obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o
obj-$(CONFIG_DVB_MT312) += mt312.o
obj-$(CONFIG_DVB_VES1820) += ves1820.o
obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
@@ -37,3 +39,4 @@ 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
+obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 3561a777568..23aa75a27c1 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -511,16 +511,11 @@ static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000
/* 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;
-
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;
- dib3000mc_set_channel_cfg(state, &fchan, reg);
+ dib3000mc_set_channel_cfg(state, &fchan, 11);
reg = dib3000mc_read_word(state, 0);
dib3000mc_write_word(state, 0, reg | (1 << 8));
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
new file mode 100644
index 00000000000..f5d40aa3d27
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -0,0 +1,1191 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB7000M and
+ * first generation DiB7000P-demodulator-family.
+ *
+ * Copyright (C) 2005-6 DiBcom (http://www.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.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "dib7000m.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 "DiB7000M:"); printk(args); } } while (0)
+
+struct dib7000m_state {
+ struct dvb_frontend demod;
+ struct dib7000m_config cfg;
+
+ u8 i2c_addr;
+ struct i2c_adapter *i2c_adap;
+
+ struct dibx000_i2c_master i2c_master;
+
+/* offset is 1 in case of the 7000MC */
+ u8 reg_offs;
+
+ u16 wbd_ref;
+
+ u8 current_band;
+ fe_bandwidth_t current_bandwidth;
+ struct dibx000_agc_config *current_agc;
+ u32 timf;
+
+ u16 revision;
+};
+
+enum dib7000m_power_mode {
+ DIB7000M_POWER_ALL = 0,
+
+ DIB7000M_POWER_NO,
+ DIB7000M_POWER_INTERF_ANALOG_AGC,
+ DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
+ DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD,
+ DIB7000M_POWER_INTERFACE_ONLY,
+};
+
+static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
+{
+ 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 },
+ };
+
+ if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+ dprintk("i2c read error on %d\n",reg);
+
+ return (rb[0] << 8) | rb[1];
+}
+
+static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
+{
+ 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;
+}
+static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
+{
+ int ret = 0;
+ u16 outreg, fifo_threshold, smo_mode,
+ sram = 0x0005; /* by default SRAM output is disabled */
+
+ outreg = 0;
+ fifo_threshold = 1792;
+ smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
+
+ dprintk("-I- Setting output mode for demod %p to %d\n",
+ &state->demod, mode);
+
+ switch (mode) {
+ case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
+ outreg = (1 << 10); /* 0x0400 */
+ break;
+ case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
+ outreg = (1 << 10) | (1 << 6); /* 0x0440 */
+ break;
+ case OUTMODE_MPEG2_SERIAL: // STBs with serial input
+ outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
+ break;
+ case OUTMODE_DIVERSITY:
+ if (state->cfg.hostbus_diversity)
+ outreg = (1 << 10) | (4 << 6); /* 0x0500 */
+ else
+ sram |= 0x0c00;
+ break;
+ case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
+ smo_mode |= (3 << 1);
+ fifo_threshold = 512;
+ outreg = (1 << 10) | (5 << 6);
+ break;
+ case OUTMODE_HIGH_Z: // disable
+ outreg = 0;
+ break;
+ default:
+ dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+ break;
+ }
+
+ if (state->cfg.output_mpeg2_in_188_bytes)
+ smo_mode |= (1 << 5) ;
+
+ ret |= dib7000m_write_word(state, 294 + state->reg_offs, smo_mode);
+ ret |= dib7000m_write_word(state, 295 + state->reg_offs, fifo_threshold); /* synchronous fread */
+ ret |= dib7000m_write_word(state, 1795, outreg);
+ ret |= dib7000m_write_word(state, 1805, sram);
+
+ return ret;
+}
+
+static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
+{
+ /* by default everything is going to be powered off */
+ u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff;
+
+ /* now, depending on the requested mode, we power on */
+ switch (mode) {
+ /* power up everything in the demod */
+ case DIB7000M_POWER_ALL:
+ reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000;
+ break;
+
+ /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
+ case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */
+ reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
+ break;
+
+ case DIB7000M_POWER_INTERF_ANALOG_AGC:
+ reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
+ reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
+ reg_906 &= ~((1 << 0));
+ break;
+
+ case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
+ reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000;
+ break;
+
+ case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD:
+ reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000;
+ break;
+ case DIB7000M_POWER_NO:
+ break;
+ }
+
+ /* always power down unused parts */
+ if (!state->cfg.mobile_mode)
+ reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
+
+ /* P_sdio_select_clk = 0 on MC */
+ if (state->revision != 0x4000)
+ reg_906 <<= 1;
+
+ dib7000m_write_word(state, 903, reg_903);
+ dib7000m_write_word(state, 904, reg_904);
+ dib7000m_write_word(state, 905, reg_905);
+ dib7000m_write_word(state, 906, reg_906);
+
+ return 0;
+}
+
+static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
+{
+ int ret = 0;
+ u16 reg_913 = dib7000m_read_word(state, 913),
+ reg_914 = dib7000m_read_word(state, 914);
+
+ switch (no) {
+ case DIBX000_SLOW_ADC_ON:
+ reg_914 |= (1 << 1) | (1 << 0);
+ ret |= dib7000m_write_word(state, 914, reg_914);
+ reg_914 &= ~(1 << 1);
+ break;
+
+ case DIBX000_SLOW_ADC_OFF:
+ reg_914 |= (1 << 1) | (1 << 0);
+ break;
+
+ case DIBX000_ADC_ON:
+ if (state->revision == 0x4000) { // workaround for PA/MA
+ // power-up ADC
+ dib7000m_write_word(state, 913, 0);
+ dib7000m_write_word(state, 914, reg_914 & 0x3);
+ // power-down bandgag
+ dib7000m_write_word(state, 913, (1 << 15));
+ dib7000m_write_word(state, 914, reg_914 & 0x3);
+ }
+
+ reg_913 &= 0x0fff;
+ reg_914 &= 0x0003;
+ break;
+
+ case DIBX000_ADC_OFF: // leave the VBG voltage on
+ reg_913 |= (1 << 14) | (1 << 13) | (1 << 12);
+ reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
+ break;
+
+ case DIBX000_VBG_ENABLE:
+ reg_913 &= ~(1 << 15);
+ break;
+
+ case DIBX000_VBG_DISABLE:
+ reg_913 |= (1 << 15);
+ break;
+
+ default:
+ break;
+ }
+
+// dprintk("-D- 913: %x, 914: %x\n", reg_913, reg_914);
+
+ ret |= dib7000m_write_word(state, 913, reg_913);
+ ret |= dib7000m_write_word(state, 914, reg_914);
+
+ return ret;
+}
+
+static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx)
+{
+ struct dib7000m_state *state = demod->demodulator_priv;
+ u32 timf;
+
+ // store the current bandwidth for later use
+ state->current_bandwidth = bw_idx;
+
+ if (state->timf == 0) {
+ dprintk("-D- Using default timf\n");
+ timf = state->cfg.bw->timf;
+ } else {
+ dprintk("-D- Using updated timf\n");
+ timf = state->timf;
+ }
+
+ timf = timf * (BW_INDEX_TO_KHZ(bw_idx) / 100) / 80;
+
+ dib7000m_write_word(state, 23, (timf >> 16) & 0xffff);
+ dib7000m_write_word(state, 24, (timf ) & 0xffff);
+
+ return 0;
+}
+
+static int dib7000m_sad_calib(struct dib7000m_state *state)
+{
+
+/* internal */
+// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+ dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
+ dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
+
+ /* do the calibration */
+ dib7000m_write_word(state, 929, (1 << 0));
+ dib7000m_write_word(state, 929, (0 << 0));
+
+ msleep(1);
+
+ return 0;
+}
+
+static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
+{
+ dib7000m_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
+ dib7000m_write_word(state, 19, (bw->internal*1000) & 0xffff);
+ dib7000m_write_word(state, 21, (bw->ifreq >> 16) & 0xffff);
+ dib7000m_write_word(state, 22, bw->ifreq & 0xffff);
+
+ dib7000m_write_word(state, 928, bw->sad_cfg);
+}
+
+static void dib7000m_reset_pll(struct dib7000m_state *state)
+{
+ const struct dibx000_bandwidth_config *bw = state->cfg.bw;
+ u16 reg_907,reg_910;
+
+ /* default */
+ reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) |
+ (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) |
+ (bw->enable_refdiv << 1) | (0 << 0);
+ reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset;
+
+ // for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value)
+ // this is only working only for 30 MHz crystals
+ if (!state->cfg.quartz_direct) {
+ reg_910 |= (1 << 5); // forcing the predivider to 1
+
+ // if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2)
+ if(state->cfg.input_clk_is_div_2)
+ reg_907 |= (16 << 9);
+ else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary
+ reg_907 |= (8 << 9);
+ } else {
+ reg_907 |= (bw->pll_ratio & 0x3f) << 9;
+ reg_910 |= (bw->pll_prediv << 5);
+ }
+
+ dib7000m_write_word(state, 910, reg_910); // pll cfg
+ dib7000m_write_word(state, 907, reg_907); // clk cfg0
+ dib7000m_write_word(state, 908, 0x0006); // clk_cfg1
+
+ dib7000m_reset_pll_common(state, bw);
+}
+
+static void dib7000mc_reset_pll(struct dib7000m_state *state)
+{
+ const struct dibx000_bandwidth_config *bw = state->cfg.bw;
+
+ // clk_cfg0
+ dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
+
+ // clk_cfg1
+ //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
+ dib7000m_write_word(state, 908, (0 << 14) | (3 << 12) |(0 << 11) |
+ (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
+ (bw->pll_bypass << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0));
+
+ // smpl_cfg
+ dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
+
+ dib7000m_reset_pll_common(state, bw);
+}
+
+static int dib7000m_reset_gpio(struct dib7000m_state *st)
+{
+ /* reset the GPIOs */
+ dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",
+ st->cfg.gpio_dir, st->cfg.gpio_val,st->cfg.gpio_pwm_pos);
+
+ dib7000m_write_word(st, 773, st->cfg.gpio_dir);
+ dib7000m_write_word(st, 774, st->cfg.gpio_val);
+
+ /* TODO 782 is P_gpio_od */
+
+ dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos);
+
+ dib7000m_write_word(st, 780, st->cfg.pwm_freq_div);
+ return 0;
+}
+
+static int dib7000m_demod_reset(struct dib7000m_state *state)
+{
+ dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
+
+ /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
+ dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE);
+
+ /* restart all parts */
+ dib7000m_write_word(state, 898, 0xffff);
+ dib7000m_write_word(state, 899, 0xffff);
+ dib7000m_write_word(state, 900, 0xff0f);
+ dib7000m_write_word(state, 901, 0xfffc);
+
+ dib7000m_write_word(state, 898, 0);
+ dib7000m_write_word(state, 899, 0);
+ dib7000m_write_word(state, 900, 0);
+ dib7000m_write_word(state, 901, 0);
+
+ if (state->revision == 0x4000)
+ dib7000m_reset_pll(state);
+ else
+ dib7000mc_reset_pll(state);
+
+ if (dib7000m_reset_gpio(state) != 0)
+ dprintk("-E- GPIO reset was not successful.\n");
+
+ if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
+ dprintk("-E- OUTPUT_MODE could not be resetted.\n");
+
+ /* unforce divstr regardless whether i2c enumeration was done or not */
+ dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
+
+ dib7000m_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+
+ dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+ dib7000m_sad_calib(state);
+ dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+
+ dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
+
+ return 0;
+}
+
+static void dib7000m_restart_agc(struct dib7000m_state *state)
+{
+ // P_restart_iqc & P_restart_agc
+ dib7000m_write_word(state, 898, 0x0c00);
+ dib7000m_write_word(state, 898, 0x0000);
+}
+
+static int dib7000m_agc_soft_split(struct dib7000m_state *state)
+{
+ u16 agc,split_offset;
+
+ if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
+ return 0;
+
+ // n_agc_global
+ agc = dib7000m_read_word(state, 390);
+
+ if (agc > state->current_agc->split.min_thres)
+ split_offset = state->current_agc->split.min;
+ else if (agc < state->current_agc->split.max_thres)
+ split_offset = state->current_agc->split.max;
+ else
+ split_offset = state->current_agc->split.max *
+ (agc - state->current_agc->split.min_thres) /
+ (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
+
+ dprintk("AGC split_offset: %d\n",split_offset);
+
+ // P_agc_force_split and P_agc_split_offset
+ return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
+}
+
+static int dib7000m_update_lna(struct dib7000m_state *state)
+{
+ int i;
+ u16 dyn_gain;
+
+ // when there is no LNA to program return immediatly
+ if (state->cfg.update_lna == NULL)
+ return 0;
+
+ msleep(60);
+ for (i = 0; i < 20; i++) {
+ // read dyn_gain here (because it is demod-dependent and not tuner)
+ dyn_gain = dib7000m_read_word(state, 390);
+
+ dprintk("agc global: %d\n", dyn_gain);
+
+ if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
+ dib7000m_restart_agc(state);
+ msleep(60);
+ } else
+ break;
+ }
+ return 0;
+}
+
+static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
+{
+ struct dibx000_agc_config *agc = NULL;
+ int i;
+ if (state->current_band == band)
+ return;
+ state->current_band = band;
+
+ for (i = 0; i < state->cfg.agc_config_count; i++)
+ if (state->cfg.agc[i].band_caps & band) {
+ agc = &state->cfg.agc[i];
+ break;
+ }
+
+ if (agc == NULL) {
+ dprintk("-E- No valid AGC configuration found for band 0x%02x\n",band);
+ return;
+ }
+
+ state->current_agc = agc;
+
+ /* AGC */
+ dib7000m_write_word(state, 72 , agc->setup);
+ dib7000m_write_word(state, 73 , agc->inv_gain);
+ dib7000m_write_word(state, 74 , agc->time_stabiliz);
+ dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock);
+
+ // Demod AGC loop configuration
+ dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
+ dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp);
+
+ dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
+ state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
+
+ /* AGC continued */
+ if (state->wbd_ref != 0)
+ dib7000m_write_word(state, 102, state->wbd_ref);
+ else // use default
+ dib7000m_write_word(state, 102, agc->wbd_ref);
+
+ dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
+ dib7000m_write_word(state, 104, agc->agc1_max);
+ dib7000m_write_word(state, 105, agc->agc1_min);
+ dib7000m_write_word(state, 106, agc->agc2_max);
+ dib7000m_write_word(state, 107, agc->agc2_min);
+ dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
+ dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+ dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+ dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+
+ if (state->revision > 0x4000) { // settings for the MC
+ dib7000m_write_word(state, 71, agc->agc1_pt3);
+// dprintk("-D- 929: %x %d %d\n",
+// (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
+ dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
+ } else {
+ // wrong default values
+ u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 };
+ for (i = 0; i < 9; i++)
+ dib7000m_write_word(state, 88 + i, b[i]);
+ }
+}
+
+static void dib7000m_update_timf_freq(struct dib7000m_state *state)
+{
+ u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
+ state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
+ dib7000m_write_word(state, 23, (u16) (timf >> 16));
+ dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
+ dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+}
+
+static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+{
+ u16 value, est[4];
+
+ dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->RF_kHz));
+
+ /* nfft, guard, qam, alpha */
+ dib7000m_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+ dib7000m_write_word(state, 5, (seq << 4));
+
+ /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
+ value = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
+ if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
+ value |= (ch->vit_code_rate_hp << 1);
+ else
+ value |= (ch->vit_code_rate_lp << 1);
+ dib7000m_write_word(state, 267 + state->reg_offs, value);
+
+ /* offset loop parameters */
+
+ /* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */
+ dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80);
+
+ /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=1, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
+ dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3));
+
+ /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */
+ dib7000m_write_word(state, 32, (0 << 4) | 0x3);
+
+ /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */
+ dib7000m_write_word(state, 33, (0 << 4) | 0x5);
+
+ /* P_dvsy_sync_wait */
+ switch (ch->nfft) {
+ case 1: value = 256; break;
+ case 2: value = 128; break;
+ case 0:
+ default: value = 64; break;
+ }
+ value *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
+ value <<= 4;
+
+ /* deactive the possibility of diversity reception if extended interleave - not for 7000MC */
+ /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
+ if (ch->intlv_native || state->revision > 0x4000)
+ value |= (1 << 2) | (2 << 0);
+ else
+ value |= 0;
+ dib7000m_write_word(state, 266 + state->reg_offs, value);
+
+ /* channel estimation fine configuration */
+ switch (ch->nqam) {
+ case 2:
+ est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
+ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
+ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
+ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
+ break;
+ case 1:
+ est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
+ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
+ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
+ est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
+ break;
+ default:
+ est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
+ est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
+ est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
+ est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
+ break;
+ }
+ for (value = 0; value < 4; value++)
+ dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
+
+ // set power-up level: interf+analog+AGC
+ dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
+ dib7000m_set_adc_state(state, DIBX000_ADC_ON);
+
+ msleep(7);
+
+ //AGC initialization
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 1);
+
+ dib7000m_restart_agc(state);
+
+ // wait AGC rough lock time
+ msleep(5);
+
+ dib7000m_update_lna(state);
+ dib7000m_agc_soft_split(state);
+
+ // wait AGC accurate lock time
+ msleep(7);
+
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 0);
+
+ // set power-up level: autosearch
+ dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
+}
+
+static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+{
+ struct dib7000m_state *state = demod->demodulator_priv;
+ struct dibx000_ofdm_channel auto_ch;
+ int ret = 0;
+ u32 value;
+
+ INIT_OFDM_CHANNEL(&auto_ch);
+ auto_ch.RF_kHz = ch->RF_kHz;
+ auto_ch.Bw = ch->Bw;
+ auto_ch.nqam = 2;
+ auto_ch.guard = 0;
+ auto_ch.nfft = 1;
+ auto_ch.vit_alpha = 1;
+ auto_ch.vit_select_hp = 1;
+ auto_ch.vit_code_rate_hp = 2;
+ auto_ch.vit_code_rate_lp = 3;
+ auto_ch.vit_hrch = 0;
+ auto_ch.intlv_native = 1;
+
+ dib7000m_set_channel(state, &auto_ch, 7);
+
+ // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
+ value = 30 * state->cfg.bw->internal;
+ ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
+ ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
+ value = 100 * state->cfg.bw->internal;
+ ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
+ ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
+ value = 500 * state->cfg.bw->internal;
+ ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
+ ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
+
+ // start search
+ value = dib7000m_read_word(state, 0);
+ ret |= dib7000m_write_word(state, 0, value | (1 << 9));
+
+ /* clear n_irq_pending */
+ if (state->revision == 0x4000)
+ dib7000m_write_word(state, 1793, 0);
+ else
+ dib7000m_read_word(state, 537);
+
+ ret |= dib7000m_write_word(state, 0, (u16) value);
+
+ return ret;
+}
+
+static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg)
+{
+ u16 irq_pending = dib7000m_read_word(state, reg);
+
+ if (irq_pending & 0x1) { // failed
+ dprintk("#\n");
+ return 1;
+ }
+
+ if (irq_pending & 0x2) { // succeeded
+ dprintk("!\n");
+ return 2;
+ }
+ return 0; // still pending
+}
+
+static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
+{
+ struct dib7000m_state *state = demod->demodulator_priv;
+ if (state->revision == 0x4000)
+ return dib7000m_autosearch_irq(state, 1793);
+ else
+ return dib7000m_autosearch_irq(state, 537);
+}
+
+static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+{
+ struct dib7000m_state *state = demod->demodulator_priv;
+ int ret = 0;
+ u16 value;
+
+ // we are already tuned - just resuming from suspend
+ if (ch != NULL)
+ dib7000m_set_channel(state, ch, 0);
+ else
+ return -EINVAL;
+
+ // restart demod
+ ret |= dib7000m_write_word(state, 898, 0x4000);
+ ret |= dib7000m_write_word(state, 898, 0x0000);
+ msleep(45);
+
+ ret |= dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
+ /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
+ ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
+
+ // never achieved a lock with that bandwidth so far - wait for timfreq to update
+ if (state->timf == 0)
+ msleep(200);
+
+ //dump_reg(state);
+ /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
+ value = (6 << 8) | 0x80;
+ switch (ch->nfft) {
+ case 0: value |= (7 << 12); break;
+ case 1: value |= (9 << 12); break;
+ case 2: value |= (8 << 12); break;
+ }
+ ret |= dib7000m_write_word(state, 26, value);
+
+ /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
+ value = (0 << 4);
+ switch (ch->nfft) {
+ case 0: value |= 0x6; break;
+ case 1: value |= 0x8; break;
+ case 2: value |= 0x7; break;
+ }
+ ret |= dib7000m_write_word(state, 32, value);
+
+ /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
+ value = (0 << 4);
+ switch (ch->nfft) {
+ case 0: value |= 0x6; break;
+ case 1: value |= 0x8; break;
+ case 2: value |= 0x7; break;
+ }
+ ret |= dib7000m_write_word(state, 33, value);
+
+ // we achieved a lock - it's time to update the osc freq
+ if ((dib7000m_read_word(state, 535) >> 6) & 0x1)
+ dib7000m_update_timf_freq(state);
+
+ return ret;
+}
+
+static int dib7000m_init(struct dvb_frontend *demod)
+{
+ struct dib7000m_state *state = demod->demodulator_priv;
+ int ret = 0;
+ u8 o = state->reg_offs;
+
+ dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
+
+ if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
+ dprintk("-E- could not start Slow ADC\n");
+
+ if (state->cfg.dvbt_mode)
+ dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
+
+ if (state->cfg.mobile_mode)
+ ret |= dib7000m_write_word(state, 261 + o, 2);
+ else
+ ret |= dib7000m_write_word(state, 224 + o, 1);
+
+ ret |= dib7000m_write_word(state, 173 + o, 0);
+ ret |= dib7000m_write_word(state, 174 + o, 0);
+ ret |= dib7000m_write_word(state, 175 + o, 0);
+ ret |= dib7000m_write_word(state, 176 + o, 0);
+ ret |= dib7000m_write_word(state, 177 + o, 0);
+ ret |= dib7000m_write_word(state, 178 + o, 0);
+ ret |= dib7000m_write_word(state, 179 + o, 0);
+ ret |= dib7000m_write_word(state, 180 + o, 0);
+
+ // P_corm_thres Lock algorithms configuration
+ ret |= dib7000m_write_word(state, 26, 0x6680);
+
+ // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
+ ret |= dib7000m_write_word(state, 170 + o, 0x0410);
+ // P_fft_nb_to_cut
+ ret |= dib7000m_write_word(state, 182 + o, 8192);
+ // P_pha3_thres
+ ret |= dib7000m_write_word(state, 195 + o, 0x0ccd);
+ // P_cti_use_cpe, P_cti_use_prog
+ ret |= dib7000m_write_word(state, 196 + o, 0);
+ // P_cspu_regul, P_cspu_win_cut
+ ret |= dib7000m_write_word(state, 205 + o, 0x200f);
+ // P_adp_regul_cnt
+ ret |= dib7000m_write_word(state, 214 + o, 0x023d);
+ // P_adp_noise_cnt
+ ret |= dib7000m_write_word(state, 215 + o, 0x00a4);
+ // P_adp_regul_ext
+ ret |= dib7000m_write_word(state, 216 + o, 0x00a4);
+ // P_adp_noise_ext
+ ret |= dib7000m_write_word(state, 217 + o, 0x7ff0);
+ // P_adp_fil
+ ret |= dib7000m_write_word(state, 218 + o, 0x3ccc);
+
+ // P_2d_byp_ti_num
+ ret |= dib7000m_write_word(state, 226 + o, 0);
+
+ // P_fec_*
+ ret |= dib7000m_write_word(state, 281 + o, 0x0010);
+ // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+ ret |= dib7000m_write_word(state, 294 + o,0x0062);
+
+ // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
+ if(state->cfg.tuner_is_baseband)
+ ret |= dib7000m_write_word(state, 36, 0x0755);
+ else
+ ret |= dib7000m_write_word(state, 36, 0x1f55);
+
+ // auto search configuration
+ ret |= dib7000m_write_word(state, 2, 0x0004);
+ ret |= dib7000m_write_word(state, 3, 0x1000);
+ ret |= dib7000m_write_word(state, 4, 0x0814);
+ ret |= dib7000m_write_word(state, 6, 0x001b);
+ ret |= dib7000m_write_word(state, 7, 0x7740);
+ ret |= dib7000m_write_word(state, 8, 0x005b);
+ ret |= dib7000m_write_word(state, 9, 0x8d80);
+ ret |= dib7000m_write_word(state, 10, 0x01c9);
+ ret |= dib7000m_write_word(state, 11, 0xc380);
+ ret |= dib7000m_write_word(state, 12, 0x0000);
+ ret |= dib7000m_write_word(state, 13, 0x0080);
+ ret |= dib7000m_write_word(state, 14, 0x0000);
+ ret |= dib7000m_write_word(state, 15, 0x0090);
+ ret |= dib7000m_write_word(state, 16, 0x0001);
+ ret |= dib7000m_write_word(state, 17, 0xd4c0);
+ ret |= dib7000m_write_word(state, 263 + o,0x0001);
+
+ // P_divclksel=3 P_divbitsel=1
+ if (state->revision == 0x4000)
+ dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
+ else
+ dib7000m_write_word(state, 909, (3 << 4) | 1);
+
+ // Tuner IO bank: max drive (14mA)
+ ret |= dib7000m_write_word(state, 912 ,0x2c8a);
+
+ ret |= dib7000m_write_word(state, 1817, 1);
+
+ return ret;
+}
+
+static int dib7000m_sleep(struct dvb_frontend *demod)
+{
+ struct dib7000m_state *st = demod->demodulator_priv;
+ dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
+ return dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY) |
+ dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
+ dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
+}
+
+static int dib7000m_identify(struct dib7000m_state *state)
+{
+ u16 value;
+ if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
+ dprintk("-E- DiB7000M: wrong Vendor ID (read=0x%x)\n",value);
+ return -EREMOTEIO;
+ }
+
+ state->revision = dib7000m_read_word(state, 897);
+ if (state->revision != 0x4000 &&
+ state->revision != 0x4001 &&
+ state->revision != 0x4002) {
+ dprintk("-E- DiB7000M: wrong Device ID (%x)\n",value);
+ return -EREMOTEIO;
+ }
+
+ /* protect this driver to be used with 7000PC */
+ if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
+ dprintk("-E- DiB7000M: this driver does not work with DiB7000PC\n");
+ return -EREMOTEIO;
+ }
+
+ switch (state->revision) {
+ case 0x4000: dprintk("-I- found DiB7000MA/PA/MB/PB\n"); break;
+ case 0x4001: state->reg_offs = 1; dprintk("-I- found DiB7000HC\n"); break;
+ case 0x4002: state->reg_offs = 1; dprintk("-I- found DiB7000MC\n"); break;
+ }
+
+ return 0;
+}
+
+
+static int dib7000m_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct dib7000m_state *state = fe->demodulator_priv;
+ u16 tps = dib7000m_read_word(state,480);
+
+ fep->inversion = INVERSION_AUTO;
+
+ fep->u.ofdm.bandwidth = state->current_bandwidth;
+
+ switch ((tps >> 8) & 0x3) {
+ case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
+ case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
+ /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
+ }
+
+ 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;
+ }
+
+ switch ((tps >> 14) & 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;
+ }
+
+ /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
+ /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
+
+ 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;
+
+ }
+
+ 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;
+ }
+
+ /* native interleaver: (dib7000m_read_word(state, 481) >> 5) & 0x1 */
+
+ return 0;
+}
+
+static int dib7000m_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct dib7000m_state *state = fe->demodulator_priv;
+ struct dibx000_ofdm_channel ch;
+
+ INIT_OFDM_CHANNEL(&ch);
+ FEP2DIB(fep,&ch);
+
+ state->current_bandwidth = fep->u.ofdm.bandwidth;
+ dib7000m_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe, fep);
+
+ 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 = 800, found;
+
+ dib7000m_autosearch_start(fe, &ch);
+ do {
+ msleep(1);
+ found = dib7000m_autosearch_is_irq(fe);
+ } while (found == 0 && i--);
+
+ dprintk("autosearch returns: %d\n",found);
+ if (found == 0 || found == 1)
+ return 0; // no channel found
+
+ dib7000m_get_frontend(fe, fep);
+ FEP2DIB(fep, &ch);
+ }
+
+ /* make this a config parameter */
+ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+
+ return dib7000m_tune(fe, &ch);
+}
+
+static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+ struct dib7000m_state *state = fe->demodulator_priv;
+ u16 lock = dib7000m_read_word(state, 535);
+
+ *stat = 0;
+
+ if (lock & 0x8000)
+ *stat |= FE_HAS_SIGNAL;
+ if (lock & 0x3000)
+ *stat |= FE_HAS_CARRIER;
+ if (lock & 0x0100)
+ *stat |= FE_HAS_VITERBI;
+ if (lock & 0x0010)
+ *stat |= FE_HAS_SYNC;
+ if (lock & 0x0008)
+ *stat |= FE_HAS_LOCK;
+
+ return 0;
+}
+
+static int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct dib7000m_state *state = fe->demodulator_priv;
+ *ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527);
+ return 0;
+}
+
+static int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+{
+ struct dib7000m_state *state = fe->demodulator_priv;
+ *unc = dib7000m_read_word(state, 534);
+ return 0;
+}
+
+static int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct dib7000m_state *state = fe->demodulator_priv;
+ u16 val = dib7000m_read_word(state, 390);
+ *strength = 65535 - val;
+ return 0;
+}
+
+static int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+ *snr = 0x0000;
+ return 0;
+}
+
+static int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
+static void dib7000m_release(struct dvb_frontend *demod)
+{
+ struct dib7000m_state *st = demod->demodulator_priv;
+ dibx000_exit_i2c_master(&st->i2c_master);
+ kfree(st);
+}
+
+struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
+{
+ struct dib7000m_state *st = demod->demodulator_priv;
+ return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
+}
+EXPORT_SYMBOL(dib7000m_get_i2c_master);
+
+int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000m_config cfg[])
+{
+ struct dib7000m_state st = { .i2c_adap = i2c };
+ int k = 0;
+ u8 new_addr = 0;
+
+ for (k = no_of_demods-1; k >= 0; k--) {
+ st.cfg = cfg[k];
+
+ /* designated i2c address */
+ new_addr = (0x40 + k) << 1;
+ st.i2c_addr = new_addr;
+ if (dib7000m_identify(&st) != 0) {
+ st.i2c_addr = default_addr;
+ if (dib7000m_identify(&st) != 0) {
+ dprintk("DiB7000M #%d: not identified\n", k);
+ return -EIO;
+ }
+ }
+
+ /* start diversity to pull_down div_str - just for i2c-enumeration */
+ dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY);
+
+ dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output
+
+ /* set new i2c address and force divstart */
+ dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
+
+ dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+ }
+
+ for (k = 0; k < no_of_demods; k++) {
+ st.cfg = cfg[k];
+ st.i2c_addr = (0x40 + k) << 1;
+
+ // unforce divstr
+ dib7000m_write_word(&st,1794, st.i2c_addr << 2);
+
+ /* deactivate div - it was just for i2c-enumeration */
+ dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(dib7000m_i2c_enumeration);
+
+static struct dvb_frontend_ops dib7000m_ops;
+struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg)
+{
+ struct dvb_frontend *demod;
+ struct dib7000m_state *st;
+ st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL);
+ if (st == NULL)
+ return NULL;
+
+ memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config));
+ st->i2c_adap = i2c_adap;
+ st->i2c_addr = i2c_addr;
+
+ demod = &st->demod;
+ demod->demodulator_priv = st;
+ memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
+
+ if (dib7000m_identify(st) != 0)
+ goto error;
+
+ if (st->revision == 0x4000)
+ dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr);
+ else
+ dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr);
+
+ dib7000m_demod_reset(st);
+
+ return demod;
+
+error:
+ kfree(st);
+ return NULL;
+}
+EXPORT_SYMBOL(dib7000m_attach);
+
+static struct dvb_frontend_ops dib7000m_ops = {
+ .info = {
+ .name = "DiBcom 7000MA/MB/PA/PB/MC",
+ .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,
+ },
+
+ .release = dib7000m_release,
+
+ .init = dib7000m_init,
+ .sleep = dib7000m_sleep,
+
+ .set_frontend = dib7000m_set_frontend,
+ .get_tune_settings = dib7000m_fe_get_tune_settings,
+ .get_frontend = dib7000m_get_frontend,
+
+ .read_status = dib7000m_read_status,
+ .read_ber = dib7000m_read_ber,
+ .read_signal_strength = dib7000m_read_signal_strength,
+ .read_snr = dib7000m_read_snr,
+ .read_ucblocks = dib7000m_read_unc_blocks,
+};
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib7000m.h b/drivers/media/dvb/frontends/dib7000m.h
new file mode 100644
index 00000000000..597e9cc2da6
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib7000m.h
@@ -0,0 +1,51 @@
+#ifndef DIB7000M_H
+#define DIB7000M_H
+
+#include "dibx000_common.h"
+
+struct dib7000m_config {
+ u8 dvbt_mode;
+ u8 output_mpeg2_in_188_bytes;
+ u8 hostbus_diversity;
+ u8 tuner_is_baseband;
+ u8 mobile_mode;
+ int (*update_lna) (struct dvb_frontend *, u16 agc_global);
+
+ u8 agc_config_count;
+ struct dibx000_agc_config *agc;
+
+ struct dibx000_bandwidth_config *bw;
+
+#define DIB7000M_GPIO_DEFAULT_DIRECTIONS 0xffff
+ u16 gpio_dir;
+#define DIB7000M_GPIO_DEFAULT_VALUES 0x0000
+ u16 gpio_val;
+#define DIB7000M_GPIO_PWM_POS0(v) ((v & 0xf) << 12)
+#define DIB7000M_GPIO_PWM_POS1(v) ((v & 0xf) << 8 )
+#define DIB7000M_GPIO_PWM_POS2(v) ((v & 0xf) << 4 )
+#define DIB7000M_GPIO_PWM_POS3(v) (v & 0xf)
+#define DIB7000M_GPIO_DEFAULT_PWM_POS 0xffff
+ u16 gpio_pwm_pos;
+
+ u16 pwm_freq_div;
+
+ u8 quartz_direct;
+
+ u8 input_clk_is_div_2;
+
+ int (*agc_control) (struct dvb_frontend *, u8 before);
+};
+
+#define DEFAULT_DIB7000M_I2C_ADDRESS 18
+
+extern struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg);
+extern struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
+
+/* TODO
+extern INT dib7000m_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
+extern INT dib7000m_enable_vbg_voltage(struct dibDemod *demod);
+extern void dib7000m_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff);
+extern USHORT dib7000m_get_current_agc_global(struct dibDemod *demod);
+*/
+
+#endif
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
new file mode 100644
index 00000000000..0349a4b5da3
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -0,0 +1,1019 @@
+/*
+ * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
+ *
+ * Copyright (C) 2005-6 DiBcom (http://www.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.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "dib7000p.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 "DiB7000P:"); printk(args); } } while (0)
+
+struct dib7000p_state {
+ struct dvb_frontend demod;
+ struct dib7000p_config cfg;
+
+ u8 i2c_addr;
+ struct i2c_adapter *i2c_adap;
+
+ struct dibx000_i2c_master i2c_master;
+
+ u16 wbd_ref;
+
+ u8 current_band;
+ fe_bandwidth_t current_bandwidth;
+ struct dibx000_agc_config *current_agc;
+ u32 timf;
+
+ u16 gpio_dir;
+ u16 gpio_val;
+};
+
+enum dib7000p_power_mode {
+ DIB7000P_POWER_ALL = 0,
+ DIB7000P_POWER_INTERFACE_ONLY,
+};
+
+static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
+{
+ u8 wb[2] = { reg >> 8, 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 },
+ };
+
+ if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+ dprintk("i2c read error on %d\n",reg);
+
+ return (rb[0] << 8) | rb[1];
+}
+
+static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
+{
+ 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;
+}
+static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
+{
+ int ret = 0;
+ u16 outreg, fifo_threshold, smo_mode;
+
+ outreg = 0;
+ fifo_threshold = 1792;
+ smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1);
+
+ dprintk("-I- Setting output mode for demod %p to %d\n",
+ &state->demod, mode);
+
+ switch (mode) {
+ case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
+ outreg = (1 << 10); /* 0x0400 */
+ break;
+ case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
+ outreg = (1 << 10) | (1 << 6); /* 0x0440 */
+ break;
+ case OUTMODE_MPEG2_SERIAL: // STBs with serial input
+ outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
+ break;
+ case OUTMODE_DIVERSITY:
+ if (state->cfg.hostbus_diversity)
+ outreg = (1 << 10) | (4 << 6); /* 0x0500 */
+ else
+ outreg = (1 << 11);
+ break;
+ case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
+ smo_mode |= (3 << 1);
+ fifo_threshold = 512;
+ outreg = (1 << 10) | (5 << 6);
+ break;
+ case OUTMODE_HIGH_Z: // disable
+ outreg = 0;
+ break;
+ default:
+ dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+ break;
+ }
+
+ if (state->cfg.output_mpeg2_in_188_bytes)
+ smo_mode |= (1 << 5) ;
+
+ ret |= dib7000p_write_word(state, 235, smo_mode);
+ ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
+ ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
+
+ return ret;
+}
+
+static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
+{
+ /* by default everything is powered off */
+ u16 reg_774 = 0xffff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003,
+ reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
+
+ /* now, depending on the requested mode, we power on */
+ switch (mode) {
+ /* power up everything in the demod */
+ case DIB7000P_POWER_ALL:
+ reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;
+ break;
+ /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
+ case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
+ reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
+ break;
+/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
+ }
+
+ dib7000p_write_word(state, 774, reg_774);
+ dib7000p_write_word(state, 775, reg_775);
+ dib7000p_write_word(state, 776, reg_776);
+ dib7000p_write_word(state, 899, reg_899);
+ dib7000p_write_word(state, 1280, reg_1280);
+
+ return 0;
+}
+
+static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
+{
+ u16 reg_908 = dib7000p_read_word(state, 908),
+ reg_909 = dib7000p_read_word(state, 909);
+
+ switch (no) {
+ case DIBX000_SLOW_ADC_ON:
+ reg_909 |= (1 << 1) | (1 << 0);
+ dib7000p_write_word(state, 909, reg_909);
+ reg_909 &= ~(1 << 1);
+ break;
+
+ case DIBX000_SLOW_ADC_OFF:
+ reg_909 |= (1 << 1) | (1 << 0);
+ break;
+
+ case DIBX000_ADC_ON:
+ reg_908 &= 0x0fff;
+ reg_909 &= 0x0003;
+ break;
+
+ case DIBX000_ADC_OFF: // leave the VBG voltage on
+ reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
+ reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
+ break;
+
+ case DIBX000_VBG_ENABLE:
+ reg_908 &= ~(1 << 15);
+ break;
+
+ case DIBX000_VBG_DISABLE:
+ reg_908 |= (1 << 15);
+ break;
+
+ default:
+ break;
+ }
+
+// dprintk("908: %x, 909: %x\n", reg_908, reg_909);
+
+ dib7000p_write_word(state, 908, reg_908);
+ dib7000p_write_word(state, 909, reg_909);
+}
+
+static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ u32 timf;
+
+ // store the current bandwidth for later use
+ state->current_bandwidth = BW_Idx;
+
+ if (state->timf == 0) {
+ dprintk("-D- Using default timf\n");
+ timf = state->cfg.bw->timf;
+ } else {
+ dprintk("-D- Using updated timf\n");
+ timf = state->timf;
+ }
+
+ timf = timf * (BW_INDEX_TO_KHZ(BW_Idx) / 100) / 80;
+
+ dprintk("timf: %d\n",timf);
+
+ dib7000p_write_word(state, 23, (timf >> 16) & 0xffff);
+ dib7000p_write_word(state, 24, (timf ) & 0xffff);
+
+ return 0;
+}
+
+static int dib7000p_sad_calib(struct dib7000p_state *state)
+{
+/* internal */
+// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+ dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
+ dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
+
+ /* do the calibration */
+ dib7000p_write_word(state, 73, (1 << 0));
+ dib7000p_write_word(state, 73, (0 << 0));
+
+ msleep(1);
+
+ return 0;
+}
+
+static void dib7000p_reset_pll(struct dib7000p_state *state)
+{
+ struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
+
+ dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
+ dib7000p_write_word(state, 900, ((bw->pll_ratio & 0x3f) << 9) | (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) |
+ (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0));
+
+ dib7000p_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
+ dib7000p_write_word(state, 19, (bw->internal*1000 ) & 0xffff);
+ dib7000p_write_word(state, 21, (bw->ifreq >> 16) & 0xffff);
+ dib7000p_write_word(state, 22, (bw->ifreq ) & 0xffff);
+
+ dib7000p_write_word(state, 72, bw->sad_cfg);
+}
+
+static int dib7000p_reset_gpio(struct dib7000p_state *st)
+{
+ /* reset the GPIOs */
+ dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
+
+ dib7000p_write_word(st, 1029, st->gpio_dir);
+ dib7000p_write_word(st, 1030, st->gpio_val);
+
+ /* TODO 1031 is P_gpio_od */
+
+ dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
+
+ dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
+ return 0;
+}
+
+static int dib7000p_demod_reset(struct dib7000p_state *state)
+{
+ dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+
+ dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
+
+ /* restart all parts */
+ dib7000p_write_word(state, 770, 0xffff);
+ dib7000p_write_word(state, 771, 0xffff);
+ dib7000p_write_word(state, 772, 0x001f);
+ dib7000p_write_word(state, 898, 0x0003);
+ /* except i2c, sdio, gpio - control interfaces */
+ dib7000p_write_word(state, 1280, 0x01fc - ((1 << 7) | (1 << 6) | (1 << 5)) );
+
+ dib7000p_write_word(state, 770, 0);
+ dib7000p_write_word(state, 771, 0);
+ dib7000p_write_word(state, 772, 0);
+ dib7000p_write_word(state, 898, 0);
+ dib7000p_write_word(state, 1280, 0);
+
+ /* default */
+ dib7000p_reset_pll(state);
+
+ if (dib7000p_reset_gpio(state) != 0)
+ dprintk("-E- GPIO reset was not successful.\n");
+
+ if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
+ dprintk("-E- OUTPUT_MODE could not be resetted.\n");
+
+ /* unforce divstr regardless whether i2c enumeration was done or not */
+ dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
+
+ dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+
+ return 0;
+}
+
+static void dib7000p_restart_agc(struct dib7000p_state *state)
+{
+ // P_restart_iqc & P_restart_agc
+ dib7000p_write_word(state, 770, 0x0c00);
+ dib7000p_write_word(state, 770, 0x0000);
+}
+
+static void dib7000p_update_lna(struct dib7000p_state *state)
+{
+ int i;
+ u16 dyn_gain;
+
+ // when there is no LNA to program return immediatly
+ if (state->cfg.update_lna == NULL)
+ return;
+
+ for (i = 0; i < 5; i++) {
+ // read dyn_gain here (because it is demod-dependent and not tuner)
+ dyn_gain = dib7000p_read_word(state, 394);
+
+ if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
+ dib7000p_restart_agc(state);
+ msleep(5);
+ } else
+ break;
+ }
+}
+
+static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
+{
+ u16 tmp = 0;
+ tmp = dib7000p_read_word(state, 903);
+ dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
+ tmp = dib7000p_read_word(state, 900);
+ dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
+}
+
+static void dib7000p_update_timf_freq(struct dib7000p_state *state)
+{
+ u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
+ state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
+ dib7000p_write_word(state, 23, (u16) (timf >> 16));
+ dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
+ dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+}
+
+static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+{
+ u16 tmp, est[4]; // reg_26, reg_32, reg_33, reg_187, reg_188, reg_189, reg_190, reg_207, reg_208;
+
+ /* nfft, guard, qam, alpha */
+ dib7000p_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+ dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
+
+ /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
+ tmp = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
+ if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
+ tmp |= (ch->vit_code_rate_hp << 1);
+ else
+ tmp |= (ch->vit_code_rate_lp << 1);
+ dib7000p_write_word(state, 208, tmp);
+
+ /* P_dvsy_sync_wait */
+ switch (ch->nfft) {
+ case 1: tmp = 256; break;
+ case 2: tmp = 128; break;
+ case 0:
+ default: tmp = 64; break;
+ }
+ tmp *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
+ tmp <<= 4;
+
+ /* deactive the possibility of diversity reception if extended interleave */
+ /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
+ if (ch->intlv_native || ch->nfft == 1)
+ tmp |= (1 << 2) | (2 << 0);
+ dib7000p_write_word(state, 207, tmp);
+
+ dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
+ dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073
+ dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
+ dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
+
+ /* channel estimation fine configuration */
+ switch (ch->nqam) {
+ case 2:
+ est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
+ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
+ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
+ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
+ break;
+ case 1:
+ est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
+ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
+ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
+ est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
+ break;
+ default:
+ est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
+ est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
+ est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
+ est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
+ break;
+ }
+ for (tmp = 0; tmp < 4; tmp++)
+ dib7000p_write_word(state, 187 + tmp, est[tmp]);
+
+ // set power-up level: interf+analog+AGC
+ dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+ dib7000p_set_adc_state(state, DIBX000_ADC_ON);
+ dib7000p_pll_clk_cfg(state);
+ msleep(7);
+
+ // AGC initialization
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 1);
+
+ dib7000p_restart_agc(state);
+
+ // wait AGC rough lock time
+ msleep(5);
+
+ dib7000p_update_lna(state);
+
+ // wait AGC accurate lock time
+ msleep(7);
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 0);
+}
+
+static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ struct dibx000_ofdm_channel auto_ch;
+ u32 value;
+
+ INIT_OFDM_CHANNEL(&auto_ch);
+ auto_ch.RF_kHz = ch->RF_kHz;
+ auto_ch.Bw = ch->Bw;
+ auto_ch.nqam = 2;
+ auto_ch.guard = 0;
+ auto_ch.nfft = 1;
+ auto_ch.vit_alpha = 1;
+ auto_ch.vit_select_hp = 1;
+ auto_ch.vit_code_rate_hp = 2;
+ auto_ch.vit_code_rate_lp = 3;
+ auto_ch.vit_hrch = 0;
+ auto_ch.intlv_native = 1;
+
+ dib7000p_set_channel(state, &auto_ch, 7);
+
+ // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
+ value = 30 * state->cfg.bw->internal;
+ dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
+ dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
+ value = 100 * state->cfg.bw->internal;
+ dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
+ dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
+ value = 500 * state->cfg.bw->internal;
+ dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
+ dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
+
+ value = dib7000p_read_word(state, 0);
+ dib7000p_write_word(state, 0, (1 << 9) | value);
+ dib7000p_read_word(state, 1284);
+ dib7000p_write_word(state, 0, (u16) value);
+
+ return 0;
+}
+
+static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ u16 irq_pending = dib7000p_read_word(state, 1284);
+
+ if (irq_pending & 0x1) // failed
+ return 1;
+
+ if (irq_pending & 0x2) // succeeded
+ return 2;
+
+ return 0; // still pending
+}
+
+static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ u16 tmp = 0;
+
+ if (ch != NULL)
+ dib7000p_set_channel(state, ch, 0);
+ else
+ return -EINVAL;
+
+ // restart demod
+ dib7000p_write_word(state, 770, 0x4000);
+ dib7000p_write_word(state, 770, 0x0000);
+ msleep(45);
+
+ /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
+ dib7000p_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
+
+ // never achieved a lock with that bandwidth so far - wait for osc-freq to update
+ if (state->timf == 0)
+ msleep(200);
+
+ /* offset loop parameters */
+
+ /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
+ tmp = (6 << 8) | 0x80;
+ switch (ch->nfft) {
+ case 0: tmp |= (7 << 12); break;
+ case 1: tmp |= (9 << 12); break;
+ case 2: tmp |= (8 << 12); break;
+ }
+ dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
+
+ /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
+ tmp = (0 << 4);
+ switch (ch->nfft) {
+ case 0: tmp |= 0x6; break;
+ case 1: tmp |= 0x8; break;
+ case 2: tmp |= 0x7; break;
+ }
+ dib7000p_write_word(state, 32, tmp);
+
+ /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
+ tmp = (0 << 4);
+ switch (ch->nfft) {
+ case 0: tmp |= 0x6; break;
+ case 1: tmp |= 0x8; break;
+ case 2: tmp |= 0x7; break;
+ }
+ dib7000p_write_word(state, 33, tmp);
+
+ tmp = dib7000p_read_word(state,509);
+ if (!((tmp >> 6) & 0x1)) {
+ /* restart the fec */
+ tmp = dib7000p_read_word(state,771);
+ dib7000p_write_word(state, 771, tmp | (1 << 1));
+ dib7000p_write_word(state, 771, tmp);
+ msleep(10);
+ tmp = dib7000p_read_word(state,509);
+ }
+
+ // we achieved a lock - it's time to update the osc freq
+ if ((tmp >> 6) & 0x1)
+ dib7000p_update_timf_freq(state);
+
+ return 0;
+}
+
+static int dib7000p_init(struct dvb_frontend *demod)
+{
+ struct dibx000_agc_config *agc;
+ struct dib7000p_state *state = demod->demodulator_priv;
+ int ret = 0;
+
+ // Demodulator default configuration
+ agc = state->cfg.agc;
+
+ dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+ dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+
+ /* AGC */
+ ret |= dib7000p_write_word(state, 75 , agc->setup );
+ ret |= dib7000p_write_word(state, 76 , agc->inv_gain );
+ ret |= dib7000p_write_word(state, 77 , agc->time_stabiliz );
+ ret |= dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
+
+ // Demod AGC loop configuration
+ ret |= dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
+ ret |= dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
+
+ /* AGC continued */
+ dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
+ state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
+
+ if (state->wbd_ref != 0)
+ ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
+ else
+ ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
+
+ ret |= dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
+
+ ret |= dib7000p_write_word(state, 107, agc->agc1_max);
+ ret |= dib7000p_write_word(state, 108, agc->agc1_min);
+ ret |= dib7000p_write_word(state, 109, agc->agc2_max);
+ ret |= dib7000p_write_word(state, 110, agc->agc2_min);
+ ret |= dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
+ ret |= dib7000p_write_word(state, 112, agc->agc1_pt3);
+ ret |= dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+ ret |= dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+ ret |= dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+
+ /* disable power smoothing */
+ ret |= dib7000p_write_word(state, 145, 0);
+ ret |= dib7000p_write_word(state, 146, 0);
+ ret |= dib7000p_write_word(state, 147, 0);
+ ret |= dib7000p_write_word(state, 148, 0);
+ ret |= dib7000p_write_word(state, 149, 0);
+ ret |= dib7000p_write_word(state, 150, 0);
+ ret |= dib7000p_write_word(state, 151, 0);
+ ret |= dib7000p_write_word(state, 152, 0);
+
+ // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
+ ret |= dib7000p_write_word(state, 26 ,0x6680);
+
+ // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
+ ret |= dib7000p_write_word(state, 142,0x0410);
+ // P_fft_freq_dir=1, P_fft_nb_to_cut=0
+ ret |= dib7000p_write_word(state, 154,1 << 13);
+ // P_pha3_thres, default 0x3000
+ ret |= dib7000p_write_word(state, 168,0x0ccd);
+ // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
+ //ret |= dib7000p_write_word(state, 169,0x0010);
+ // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
+ ret |= dib7000p_write_word(state, 183,0x200f);
+ // P_adp_regul_cnt=573, default: 410
+ ret |= dib7000p_write_word(state, 187,0x023d);
+ // P_adp_noise_cnt=
+ ret |= dib7000p_write_word(state, 188,0x00a4);
+ // P_adp_regul_ext
+ ret |= dib7000p_write_word(state, 189,0x00a4);
+ // P_adp_noise_ext
+ ret |= dib7000p_write_word(state, 190,0x7ff0);
+ // P_adp_fil
+ ret |= dib7000p_write_word(state, 191,0x3ccc);
+
+ ret |= dib7000p_write_word(state, 222,0x0010);
+ // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+ ret |= dib7000p_write_word(state, 235,0x0062);
+
+ // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
+ if(state->cfg.tuner_is_baseband)
+ ret |= dib7000p_write_word(state, 36,0x0755);
+ else
+ ret |= dib7000p_write_word(state, 36,0x1f55);
+
+ // auto search configuration
+ ret |= dib7000p_write_word(state, 2 ,0x0004);
+ ret |= dib7000p_write_word(state, 3 ,0x1000);
+
+ /* Equal Lock */
+ ret |= dib7000p_write_word(state, 4 ,0x0814);
+
+ ret |= dib7000p_write_word(state, 6 ,0x001b);
+ ret |= dib7000p_write_word(state, 7 ,0x7740);
+ ret |= dib7000p_write_word(state, 8 ,0x005b);
+ ret |= dib7000p_write_word(state, 9 ,0x8d80);
+ ret |= dib7000p_write_word(state, 10 ,0x01c9);
+ ret |= dib7000p_write_word(state, 11 ,0xc380);
+ ret |= dib7000p_write_word(state, 12 ,0x0000);
+ ret |= dib7000p_write_word(state, 13 ,0x0080);
+ ret |= dib7000p_write_word(state, 14 ,0x0000);
+ ret |= dib7000p_write_word(state, 15 ,0x0090);
+ ret |= dib7000p_write_word(state, 16 ,0x0001);
+ ret |= dib7000p_write_word(state, 17 ,0xd4c0);
+
+ // P_clk_cfg1
+ ret |= dib7000p_write_word(state, 901, 0x0006);
+
+ // P_divclksel=3 P_divbitsel=1
+ ret |= dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
+
+ // Tuner IO bank: max drive (14mA) + divout pads max drive
+ ret |= dib7000p_write_word(state, 905, 0x2c8e);
+
+ ret |= dib7000p_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+ dib7000p_sad_calib(state);
+
+ return ret;
+}
+
+static int dib7000p_sleep(struct dvb_frontend *demod)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+}
+
+static int dib7000p_identify(struct dib7000p_state *st)
+{
+ u16 value;
+ dprintk("-I- DiB7000PC: checking demod on I2C address: %d (%x)\n",
+ st->i2c_addr, st->i2c_addr);
+
+ if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
+ dprintk("-E- DiB7000PC: wrong Vendor ID (read=0x%x)\n",value);
+ return -EREMOTEIO;
+ }
+
+ if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
+ dprintk("-E- DiB7000PC: wrong Device ID (%x)\n",value);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+
+static int dib7000p_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct dib7000p_state *state = fe->demodulator_priv;
+ u16 tps = dib7000p_read_word(state,463);
+
+ fep->inversion = INVERSION_AUTO;
+
+ fep->u.ofdm.bandwidth = state->current_bandwidth;
+
+ switch ((tps >> 8) & 0x3) {
+ case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
+ case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
+ /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
+ }
+
+ 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;
+ }
+
+ switch ((tps >> 14) & 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;
+ }
+
+ /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
+ /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
+
+ 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;
+
+ }
+
+ 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;
+ }
+
+ /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
+
+ return 0;
+}
+
+static int dib7000p_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct dib7000p_state *state = fe->demodulator_priv;
+ struct dibx000_ofdm_channel ch;
+
+ INIT_OFDM_CHANNEL(&ch);
+ FEP2DIB(fep,&ch);
+
+ state->current_bandwidth = fep->u.ofdm.bandwidth;
+ dib7000p_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe, fep);
+
+ 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 = 800, found;
+
+ dib7000p_autosearch_start(fe, &ch);
+ do {
+ msleep(1);
+ found = dib7000p_autosearch_is_irq(fe);
+ } while (found == 0 && i--);
+
+ dprintk("autosearch returns: %d\n",found);
+ if (found == 0 || found == 1)
+ return 0; // no channel found
+
+ dib7000p_get_frontend(fe, fep);
+ FEP2DIB(fep, &ch);
+ }
+
+ /* make this a config parameter */
+ dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+
+ return dib7000p_tune(fe, &ch);
+}
+
+static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+ struct dib7000p_state *state = fe->demodulator_priv;
+ u16 lock = dib7000p_read_word(state, 509);
+
+ *stat = 0;
+
+ if (lock & 0x8000)
+ *stat |= FE_HAS_SIGNAL;
+ if (lock & 0x3000)
+ *stat |= FE_HAS_CARRIER;
+ if (lock & 0x0100)
+ *stat |= FE_HAS_VITERBI;
+ if (lock & 0x0010)
+ *stat |= FE_HAS_SYNC;
+ if (lock & 0x0008)
+ *stat |= FE_HAS_LOCK;
+
+ return 0;
+}
+
+static int dib7000p_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct dib7000p_state *state = fe->demodulator_priv;
+ *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
+ return 0;
+}
+
+static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+{
+ struct dib7000p_state *state = fe->demodulator_priv;
+ *unc = dib7000p_read_word(state, 506);
+ return 0;
+}
+
+static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct dib7000p_state *state = fe->demodulator_priv;
+ u16 val = dib7000p_read_word(state, 394);
+ *strength = 65535 - val;
+ return 0;
+}
+
+static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+ *snr = 0x0000;
+ return 0;
+}
+
+static int dib7000p_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
+static void dib7000p_release(struct dvb_frontend *demod)
+{
+ struct dib7000p_state *st = demod->demodulator_priv;
+ dibx000_exit_i2c_master(&st->i2c_master);
+ kfree(st);
+}
+
+int dib7000pc_detection(struct i2c_adapter *i2c_adap)
+{
+ u8 tx[2], rx[2];
+ struct i2c_msg msg[2] = {
+ { .addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2 },
+ { .addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2 },
+ };
+
+ tx[0] = 0x03;
+ tx[1] = 0x00;
+
+ if (i2c_transfer(i2c_adap, msg, 2) == 2)
+ if (rx[0] == 0x01 && rx[1] == 0xb3) {
+ dprintk("-D- DiB7000PC detected\n");
+ return 1;
+ }
+
+ msg[0].addr = msg[1].addr = 0x40;
+
+ if (i2c_transfer(i2c_adap, msg, 2) == 2)
+ if (rx[0] == 0x01 && rx[1] == 0xb3) {
+ dprintk("-D- DiB7000PC detected\n");
+ return 1;
+ }
+
+ dprintk("-D- DiB7000PC not detected\n");
+ return 0;
+}
+EXPORT_SYMBOL(dib7000pc_detection);
+
+struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
+{
+ struct dib7000p_state *st = demod->demodulator_priv;
+ return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
+}
+EXPORT_SYMBOL(dib7000p_get_i2c_master);
+
+int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
+{
+ struct dib7000p_state st = { .i2c_adap = i2c };
+ int k = 0;
+ u8 new_addr = 0;
+
+ for (k = no_of_demods-1; k >= 0; k--) {
+ st.cfg = cfg[k];
+
+ /* designated i2c address */
+ new_addr = (0x40 + k) << 1;
+ st.i2c_addr = new_addr;
+ if (dib7000p_identify(&st) != 0) {
+ st.i2c_addr = default_addr;
+ if (dib7000p_identify(&st) != 0) {
+ dprintk("DiB7000P #%d: not identified\n", k);
+ return -EIO;
+ }
+ }
+
+ /* start diversity to pull_down div_str - just for i2c-enumeration */
+ dib7000p_set_output_mode(&st, OUTMODE_DIVERSITY);
+
+ /* set new i2c address and force divstart */
+ dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2);
+
+ dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+ }
+
+ for (k = 0; k < no_of_demods; k++) {
+ st.cfg = cfg[k];
+ st.i2c_addr = (0x40 + k) << 1;
+
+ // unforce divstr
+ dib7000p_write_word(&st, 1285, st.i2c_addr << 2);
+
+ /* deactivate div - it was just for i2c-enumeration */
+ dib7000p_set_output_mode(&st, OUTMODE_HIGH_Z);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(dib7000p_i2c_enumeration);
+
+static struct dvb_frontend_ops dib7000p_ops;
+struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
+{
+ struct dvb_frontend *demod;
+ struct dib7000p_state *st;
+ st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
+ if (st == NULL)
+ return NULL;
+
+ memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
+ st->i2c_adap = i2c_adap;
+ st->i2c_addr = i2c_addr;
+ st->gpio_val = cfg->gpio_val;
+ st->gpio_dir = cfg->gpio_dir;
+
+ demod = &st->demod;
+ demod->demodulator_priv = st;
+ memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
+
+ if (dib7000p_identify(st) != 0)
+ goto error;
+
+ dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
+
+ dib7000p_demod_reset(st);
+
+ return demod;
+
+error:
+ kfree(st);
+ return NULL;
+}
+EXPORT_SYMBOL(dib7000p_attach);
+
+static struct dvb_frontend_ops dib7000p_ops = {
+ .info = {
+ .name = "DiBcom 7000PC",
+ .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,
+ },
+
+ .release = dib7000p_release,
+
+ .init = dib7000p_init,
+ .sleep = dib7000p_sleep,
+
+ .set_frontend = dib7000p_set_frontend,
+ .get_tune_settings = dib7000p_fe_get_tune_settings,
+ .get_frontend = dib7000p_get_frontend,
+
+ .read_status = dib7000p_read_status,
+ .read_ber = dib7000p_read_ber,
+ .read_signal_strength = dib7000p_read_signal_strength,
+ .read_snr = dib7000p_read_snr,
+ .read_ucblocks = dib7000p_read_unc_blocks,
+};
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
new file mode 100644
index 00000000000..79465cf1ace
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib7000p.h
@@ -0,0 +1,46 @@
+#ifndef DIB7000P_H
+#define DIB7000P_H
+
+#include "dibx000_common.h"
+
+struct dib7000p_config {
+ u8 output_mpeg2_in_188_bytes;
+ u8 hostbus_diversity;
+ u8 tuner_is_baseband;
+ int (*update_lna) (struct dvb_frontend *, u16 agc_global);
+
+ struct dibx000_agc_config *agc;
+ struct dibx000_bandwidth_config *bw;
+
+#define DIB7000P_GPIO_DEFAULT_DIRECTIONS 0xffff
+ u16 gpio_dir;
+#define DIB7000P_GPIO_DEFAULT_VALUES 0x0000
+ u16 gpio_val;
+#define DIB7000P_GPIO_PWM_POS0(v) ((v & 0xf) << 12)
+#define DIB7000P_GPIO_PWM_POS1(v) ((v & 0xf) << 8 )
+#define DIB7000P_GPIO_PWM_POS2(v) ((v & 0xf) << 4 )
+#define DIB7000P_GPIO_PWM_POS3(v) (v & 0xf)
+#define DIB7000P_GPIO_DEFAULT_PWM_POS 0xffff
+ u16 gpio_pwm_pos;
+
+ u16 pwm_freq_div;
+
+ u8 quartz_direct;
+
+ int (*agc_control) (struct dvb_frontend *, u8 before);
+};
+
+#define DEFAULT_DIB7000P_I2C_ADDRESS 18
+
+extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
+extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
+
+/* TODO
+extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
+extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod);
+extern void dib7000p_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff);
+extern USHORT dib7000p_get_current_agc_global(struct dibDemod *demod);
+*/
+
+#endif
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
index bb0c65f8aee..a1df604366c 100644
--- a/drivers/media/dvb/frontends/dibx000_common.h
+++ b/drivers/media/dvb/frontends/dibx000_common.h
@@ -32,6 +32,13 @@ extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
#define BAND_LBAND 0x01
#define BAND_UHF 0x02
#define BAND_VHF 0x04
+#define BAND_SBAND 0x08
+#define BAND_FM 0x10
+
+#define BAND_OF_FREQUENCY(freq_kHz) ( (freq_kHz) <= 115000 ? BAND_FM : \
+ (freq_kHz) <= 250000 ? BAND_VHF : \
+ (freq_kHz) <= 863000 ? BAND_UHF : \
+ (freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND )
struct dibx000_agc_config {
/* defines the capabilities of this AGC-setting - using the BAND_-defines*/
@@ -129,6 +136,7 @@ enum dibx000_adc_states {
/* I hope I can get rid of the following kludge in the near future */
struct dibx000_ofdm_channel {
+ u32 RF_kHz;
u8 Bw;
s16 nfft;
s16 guard;
@@ -138,9 +146,11 @@ struct dibx000_ofdm_channel {
s16 vit_alpha;
s16 vit_code_rate_hp;
s16 vit_code_rate_lp;
+ u8 intlv_native;
};
#define FEP2DIB(fep,ch) \
+ (ch)->RF_kHz = (fep)->frequency / 1000; \
(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; \
@@ -149,7 +159,8 @@ struct dibx000_ofdm_channel {
(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;
+ (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \
+ (ch)->intlv_native = 1;
#define INIT_OFDM_CHANNEL(ch) do {\
(ch)->Bw = 0; \
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index b7e7108ee5b..62de760c844 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -472,14 +472,14 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
desc->name, div, buf[0], buf[1], buf[2], buf[3]);
- return 0;
+ // calculate the frequency we set it to
+ return (div * desc->entries[i].stepsize) - desc->entries[i].offset;
}
EXPORT_SYMBOL(dvb_pll_configure);
static int dvb_pll_release(struct dvb_frontend *fe)
{
- if (fe->tuner_priv)
- kfree(fe->tuner_priv);
+ kfree(fe->tuner_priv);
fe->tuner_priv = NULL;
return 0;
}
@@ -489,7 +489,8 @@ static int dvb_pll_sleep(struct dvb_frontend *fe)
struct dvb_pll_priv *priv = fe->tuner_priv;
u8 buf[4];
struct i2c_msg msg =
- { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ { .addr = priv->pll_i2c_address, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
int i;
int result;
@@ -517,16 +518,16 @@ static int dvb_pll_sleep(struct dvb_frontend *fe)
return 0;
}
-static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int dvb_pll_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
struct dvb_pll_priv *priv = fe->tuner_priv;
u8 buf[4];
struct i2c_msg msg =
- { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ { .addr = priv->pll_i2c_address, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
int result;
- u32 div;
- int i;
- u32 bandwidth = 0;
+ u32 bandwidth = 0, frequency = 0;
if (priv->i2c == NULL)
return -EINVAL;
@@ -536,8 +537,11 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_param
bandwidth = params->u.ofdm.bandwidth;
}
- if ((result = dvb_pll_configure(priv->pll_desc, buf, params->frequency, bandwidth)) != 0)
+ if ((result = dvb_pll_configure(priv->pll_desc, buf,
+ params->frequency, bandwidth)) < 0)
return result;
+ else
+ frequency = result;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -545,26 +549,19 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_param
return result;
}
- // calculate the frequency we set it to
- for (i = 0; i < priv->pll_desc->count; i++) {
- if (params->frequency > priv->pll_desc->entries[i].limit)
- continue;
- break;
- }
- div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
- priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+ priv->frequency = frequency;
priv->bandwidth = bandwidth;
return 0;
}
-static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len)
+static int dvb_pll_calc_regs(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params,
+ u8 *buf, int buf_len)
{
struct dvb_pll_priv *priv = fe->tuner_priv;
int result;
- u32 div;
- int i;
- u32 bandwidth = 0;
+ u32 bandwidth = 0, frequency = 0;
if (buf_len < 5)
return -EINVAL;
@@ -574,18 +571,15 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parame
bandwidth = params->u.ofdm.bandwidth;
}
- if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params->frequency, bandwidth)) != 0)
+ if ((result = dvb_pll_configure(priv->pll_desc, buf+1,
+ params->frequency, bandwidth)) < 0)
return result;
+ else
+ frequency = result;
+
buf[0] = priv->pll_i2c_address;
- // calculate the frequency we set it to
- for (i = 0; i < priv->pll_desc->count; i++) {
- if (params->frequency > priv->pll_desc->entries[i].limit)
- continue;
- break;
- }
- div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
- priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+ priv->frequency = frequency;
priv->bandwidth = bandwidth;
return 5;
@@ -614,10 +608,13 @@ static struct dvb_tuner_ops dvb_pll_tuner_ops = {
.get_bandwidth = dvb_pll_get_bandwidth,
};
-struct dvb_frontend *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 };
+ struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
+ .buf = b1, .len = 1 };
struct dvb_pll_priv *priv = NULL;
int ret;
@@ -640,7 +637,9 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struc
priv->i2c = i2c;
priv->pll_desc = desc;
- memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops));
+ memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
strncpy(fe->ops.tuner_ops.info.name, desc->name, 128);
fe->ops.tuner_ops.info.frequency_min = desc->min;
fe->ops.tuner_ops.info.frequency_min = desc->max;
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index ed5ac5a361a..681186a5e5e 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -48,7 +48,7 @@ extern struct dvb_pll_desc dvb_pll_philips_td1316;
extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
- u32 freq, int bandwidth);
+ u32 freq, int bandwidth);
/**
* Attach a dvb-pll to the supplied frontend structure.
@@ -59,6 +59,9 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
* @param desc dvb_pll_desc to use.
* @return Frontend pointer on success, NULL on failure
*/
-extern struct dvb_frontend *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/lg_h06xf.h b/drivers/media/dvb/frontends/lg_h06xf.h
deleted file mode 100644
index 754d51d1112..00000000000
--- a/drivers/media/dvb/frontends/lg_h06xf.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * lg_h06xf.h - ATSC Tuner support for LG TDVS-H06xF
- *
- * This program is free software; you can redistribute it and/or modify
- * 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 _LG_H06XF_H_
-#define _LG_H06XF_H_
-#include "dvb-pll.h"
-
-static int lg_h06xf_pll_set(struct dvb_frontend* fe, struct i2c_adapter* i2c_adap,
- struct dvb_frontend_parameters* params)
-{
- u8 buf[4];
- struct i2c_msg msg = { .addr = 0x61, .flags = 0,
- .buf = buf, .len = sizeof(buf) };
- int err;
-
- dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, params->frequency, 0);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
- printk(KERN_WARNING "lg_h06xf: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, buf[0], buf[1], err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- /* Set the Auxiliary Byte. */
- buf[0] = buf[2];
- buf[0] &= ~0x20;
- buf[0] |= 0x18;
- buf[1] = 0x50;
- msg.len = 2;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
- printk(KERN_WARNING "lg_h06xf: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, buf[0], buf[1], err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
-}
-#endif
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 9a354708bd2..68aad0f6519 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -31,9 +31,6 @@
* Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
* pcHDTV HD5500
*
- * TODO:
- * signal strength always returns 0.
- *
*/
#include <linux/kernel.h>
@@ -46,9 +43,13 @@
#include <asm/byteorder.h>
#include "dvb_frontend.h"
+#include "dvb_math.h"
#include "lgdt330x_priv.h"
#include "lgdt330x.h"
+/* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */
+/* #define USE_EQMSE */
+
static int debug = 0;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off).");
@@ -68,6 +69,7 @@ struct lgdt330x_state
/* Demodulator private data */
fe_modulation_t current_modulation;
+ u32 snr; /* Result of last SNR calculation */
/* Tuner private data */
u32 current_frequency;
@@ -302,10 +304,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
static u8 lgdt3303_8vsb_44_data[] = {
0x04, 0x00,
0x0d, 0x40,
- 0x0e, 0x87,
- 0x0f, 0x8e,
- 0x10, 0x01,
- 0x47, 0x8b };
+ 0x0e, 0x87,
+ 0x0f, 0x8e,
+ 0x10, 0x01,
+ 0x47, 0x8b };
/*
* Array of byte pairs <address, value>
@@ -435,9 +437,6 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status)
/* Test signal does not exist flag */
/* as well as the AGC lock flag. */
*status |= FE_HAS_SIGNAL;
- } else {
- /* Without a signal all other status bits are meaningless */
- return 0;
}
/*
@@ -500,9 +499,6 @@ static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status)
/* Test input signal does not exist flag */
/* as well as the AGC lock flag. */
*status |= FE_HAS_SIGNAL;
- } else {
- /* Without a signal all other status bits are meaningless */
- return 0;
}
/* Carrier Recovery Lock Status Register */
@@ -543,151 +539,150 @@ static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status)
return 0;
}
-static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+/* Calculate SNR estimation (scaled by 2^24)
+
+ 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM
+ equations from LGDT3303 datasheet. VSB is the same between the '02
+ and '03, so maybe QAM is too? Perhaps someone with a newer datasheet
+ that has QAM information could verify?
+
+ For 8-VSB: (two ways, take your pick)
+ LGDT3302:
+ SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE)
+ LGDT3303:
+ SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE)
+ LGDT3302 & LGDT3303:
+ SNR_PT = 10 * log10(25 * 32^2 / PT_MSE) (we use this one)
+ For 64-QAM:
+ SNR = 10 * log10( 688128 / MSEQAM)
+ For 256-QAM:
+ SNR = 10 * log10( 696320 / MSEQAM)
+
+ We re-write the snr equation as:
+ SNR * 2^24 = 10*(c - intlog10(MSE))
+ Where for 256-QAM, c = log10(696320) * 2^24, and so on. */
+
+static u32 calculate_snr(u32 mse, u32 c)
{
- /* not directly available. */
- *strength = 0;
- return 0;
+ if (mse == 0) /* No signal */
+ return 0;
+
+ mse = intlog10(mse);
+ if (mse > c) {
+ /* Negative SNR, which is possible, but realisticly the
+ demod will lose lock before the signal gets this bad. The
+ API only allows for unsigned values, so just return 0 */
+ return 0;
+ }
+ return 10*(c - mse);
}
static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr)
{
-#ifdef SNR_IN_DB
- /*
- * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise)
- * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker
- * respectively. The following tables are built on these formulas.
- * The usual definition is SNR = 20 log10(signal/noise)
- * If the specification is wrong the value retuned is 1/2 the actual SNR in db.
- *
- * This table is a an ordered list of noise values computed by the
- * formula from the spec sheet such that the index into the table
- * starting at 43 or 45 is the SNR value in db. There are duplicate noise
- * value entries at the beginning because the SNR varies more than
- * 1 db for a change of 1 digit in noise at very small values of noise.
- *
- * Examples from SNR_EQ table:
- * noise SNR
- * 0 43
- * 1 42
- * 2 39
- * 3 37
- * 4 36
- * 5 35
- * 6 34
- * 7 33
- * 8 33
- * 9 32
- * 10 32
- * 11 31
- * 12 31
- * 13 30
- */
-
- static const u32 SNR_EQ[] =
- { 1, 2, 2, 2, 3, 3, 4, 4, 5, 7,
- 9, 11, 13, 17, 21, 26, 33, 41, 52, 65,
- 81, 102, 129, 162, 204, 257, 323, 406, 511, 644,
- 810, 1020, 1284, 1616, 2035, 2561, 3224, 4059, 5110, 6433,
- 8098, 10195, 12835, 16158, 20341, 25608, 32238, 40585, 51094, 64323,
- 80978, 101945, 128341, 161571, 203406, 256073, 0x40000
- };
-
- static const u32 SNR_PH[] =
- { 1, 2, 2, 2, 3, 3, 4, 5, 6, 8,
- 10, 12, 15, 19, 23, 29, 37, 46, 58, 73,
- 91, 115, 144, 182, 229, 288, 362, 456, 574, 722,
- 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216,
- 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151,
- 90833, 114351, 143960, 181235, 228161, 0x080000
- };
-
- static u8 buf[5];/* read data buffer */
- static u32 noise; /* noise value */
- static u32 snr_db; /* index into SNR_EQ[] */
struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+ u8 buf[5]; /* read data buffer */
+ u32 noise; /* noise value */
+ u32 c; /* per-modulation SNR calculation constant */
- /* read both equalizer and phase tracker noise data */
- i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf));
-
- if (state->current_modulation == VSB_8) {
- /* Equalizer Mean-Square Error Register for VSB */
+ switch(state->current_modulation) {
+ case VSB_8:
+ i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5);
+#ifdef USE_EQMSE
+ /* Use Equalizer Mean-Square Error Register */
+ /* SNR for ranges from -15.61 to +41.58 */
noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
-
- /*
- * Look up noise value in table.
- * A better search algorithm could be used...
- * watch out there are duplicate entries.
- */
- for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) {
- if (noise < SNR_EQ[snr_db]) {
- *snr = 43 - snr_db;
- break;
- }
- }
- } else {
- /* Phase Tracker Mean-Square Error Register for QAM */
- noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
-
- /* Look up noise value in table. */
- for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) {
- if (noise < SNR_PH[snr_db]) {
- *snr = 45 - snr_db;
- break;
- }
- }
- }
+ c = 69765745; /* log10(25*24^2)*2^24 */
#else
- /* Return the raw noise value */
- static u8 buf[5];/* read data buffer */
- static u32 noise; /* noise value */
- struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
-
- /* read both equalizer and pase tracker noise data */
- i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf));
-
- if (state->current_modulation == VSB_8) {
- /* Phase Tracker Mean-Square Error Register for VSB */
+ /* Use Phase Tracker Mean-Square Error Register */
+ /* SNR for ranges from -13.11 to +44.08 */
noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
- } else {
-
- /* Carrier Recovery Mean-Square Error for QAM */
- i2c_read_demod_bytes(state, 0x1a, buf, 2);
+ c = 73957994; /* log10(25*32^2)*2^24 */
+#endif
+ break;
+ case QAM_64:
+ case QAM_256:
+ i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
noise = ((buf[0] & 3) << 8) | buf[1];
+ c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
+ /* log10(688128)*2^24 and log10(696320)*2^24 */
+ break;
+ default:
+ printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
+ __FUNCTION__);
+ return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
}
- /* Small values for noise mean signal is better so invert noise */
- *snr = ~noise;
-#endif
+ state->snr = calculate_snr(noise, c);
+ *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
- dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr);
+ dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise,
+ state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
return 0;
}
static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr)
{
- /* Return the raw noise value */
- static u8 buf[5];/* read data buffer */
- static u32 noise; /* noise value */
struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+ u8 buf[5]; /* read data buffer */
+ u32 noise; /* noise value */
+ u32 c; /* per-modulation SNR calculation constant */
- if (state->current_modulation == VSB_8) {
-
- i2c_read_demod_bytes(state, 0x6e, buf, 5);
- /* Phase Tracker Mean-Square Error Register for VSB */
+ switch(state->current_modulation) {
+ case VSB_8:
+ i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5);
+#ifdef USE_EQMSE
+ /* Use Equalizer Mean-Square Error Register */
+ /* SNR for ranges from -16.12 to +44.08 */
+ noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2];
+ c = 73957994; /* log10(25*32^2)*2^24 */
+#else
+ /* Use Phase Tracker Mean-Square Error Register */
+ /* SNR for ranges from -13.11 to +44.08 */
noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
- } else {
-
- /* Carrier Recovery Mean-Square Error for QAM */
- i2c_read_demod_bytes(state, 0x1a, buf, 2);
+ c = 73957994; /* log10(25*32^2)*2^24 */
+#endif
+ break;
+ case QAM_64:
+ case QAM_256:
+ i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
noise = (buf[0] << 8) | buf[1];
+ c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
+ /* log10(688128)*2^24 and log10(696320)*2^24 */
+ break;
+ default:
+ printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
+ __FUNCTION__);
+ return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
}
- /* Small values for noise mean signal is better so invert noise */
- *snr = ~noise;
+ state->snr = calculate_snr(noise, c);
+ *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
+
+ dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise,
+ state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
+
+ return 0;
+}
+
+static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ /* Calculate Strength from SNR up to 35dB */
+ /* Even though the SNR can go higher than 35dB, there is some comfort */
+ /* factor in having a range of strong signals that can show at 100% */
+ struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+ u16 snr;
+ int ret;
- dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr);
+ ret = fe->ops.read_snr(fe, &snr);
+ if (ret != 0)
+ return ret;
+ /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+ /* scale the range 0 - 35*2^24 into 0 - 65535 */
+ if (state->snr >= 8960 * 0x10000)
+ *strength = 0xffff;
+ else
+ *strength = state->snr / 8960;
return 0;
}
diff --git a/drivers/media/dvb/frontends/lgdt330x_priv.h b/drivers/media/dvb/frontends/lgdt330x_priv.h
index 59b7c5b9012..38c76695abf 100644
--- a/drivers/media/dvb/frontends/lgdt330x_priv.h
+++ b/drivers/media/dvb/frontends/lgdt330x_priv.h
@@ -51,14 +51,19 @@ enum I2C_REG {
AGC_RFIF_ACC2= 0x3b,
AGC_STATUS= 0x3f,
SYNC_STATUS_VSB= 0x43,
- EQPH_ERR0= 0x47,
- EQ_ERR1= 0x48,
- EQ_ERR2= 0x49,
- PH_ERR1= 0x4a,
- PH_ERR2= 0x4b,
DEMUX_CONTROL= 0x66,
+ LGDT3302_EQPH_ERR0= 0x47,
+ LGDT3302_EQ_ERR1= 0x48,
+ LGDT3302_EQ_ERR2= 0x49,
+ LGDT3302_PH_ERR1= 0x4a,
+ LGDT3302_PH_ERR2= 0x4b,
LGDT3302_PACKET_ERR_COUNTER1= 0x6a,
LGDT3302_PACKET_ERR_COUNTER2= 0x6b,
+ LGDT3303_EQPH_ERR0= 0x6e,
+ LGDT3303_EQ_ERR1= 0x6f,
+ LGDT3303_EQ_ERR2= 0x70,
+ LGDT3303_PH_ERR1= 0x71,
+ LGDT3303_PH_ERR2= 0x72,
LGDT3303_PACKET_ERR_COUNTER1= 0x8b,
LGDT3303_PACKET_ERR_COUNTER2= 0x8c,
};
diff --git a/drivers/media/dvb/frontends/lgh06xf.c b/drivers/media/dvb/frontends/lgh06xf.c
new file mode 100644
index 00000000000..2202d0cc878
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgh06xf.c
@@ -0,0 +1,134 @@
+/*
+ * lgh06xf.c - ATSC Tuner support for LG TDVS-H06xF
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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 "dvb-pll.h"
+#include "lgh06xf.h"
+
+#define LG_H06XF_PLL_I2C_ADDR 0x61
+
+struct lgh06xf_priv {
+ struct i2c_adapter *i2c;
+ u32 frequency;
+};
+
+static int lgh06xf_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int lgh06xf_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
+{
+ struct lgh06xf_priv *priv = fe->tuner_priv;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = LG_H06XF_PLL_I2C_ADDR, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
+ u32 frequency;
+ int result;
+
+ if ((result = dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf,
+ params->frequency, 0)) < 0)
+ return result;
+ else
+ frequency = result;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lgh06xf: %s error "
+ "(addr %02x <- %02x, result = %i)\n",
+ __FUNCTION__, buf[0], buf[1], result);
+ if (result < 0)
+ return result;
+ else
+ return -EREMOTEIO;
+ }
+
+ /* Set the Auxiliary Byte. */
+ buf[0] = buf[2];
+ buf[0] &= ~0x20;
+ buf[0] |= 0x18;
+ buf[1] = 0x50;
+ msg.len = 2;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lgh06xf: %s error "
+ "(addr %02x <- %02x, result = %i)\n",
+ __FUNCTION__, buf[0], buf[1], result);
+ if (result < 0)
+ return result;
+ else
+ return -EREMOTEIO;
+ }
+
+ priv->frequency = frequency;
+
+ return 0;
+}
+
+static int lgh06xf_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct lgh06xf_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static struct dvb_tuner_ops lgh06xf_tuner_ops = {
+ .release = lgh06xf_release,
+ .set_params = lgh06xf_set_params,
+ .get_frequency = lgh06xf_get_frequency,
+};
+
+struct dvb_frontend* lgh06xf_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c)
+{
+ struct lgh06xf_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct lgh06xf_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->i2c = i2c;
+
+ memcpy(&fe->ops.tuner_ops, &lgh06xf_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ strlcpy(fe->ops.tuner_ops.info.name, dvb_pll_lg_tdvs_h06xf.name,
+ sizeof(fe->ops.tuner_ops.info.name));
+
+ fe->ops.tuner_ops.info.frequency_min = dvb_pll_lg_tdvs_h06xf.min;
+ fe->ops.tuner_ops.info.frequency_max = dvb_pll_lg_tdvs_h06xf.max;
+
+ fe->tuner_priv = priv;
+ return fe;
+}
+
+EXPORT_SYMBOL(lgh06xf_attach);
+
+MODULE_DESCRIPTION("LG TDVS-H06xF ATSC Tuner support");
+MODULE_AUTHOR("Michael Krufky");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/lgh06xf.h b/drivers/media/dvb/frontends/lgh06xf.h
new file mode 100644
index 00000000000..510b4bedfb2
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgh06xf.h
@@ -0,0 +1,35 @@
+/*
+ * lgh06xf.h - ATSC Tuner support for LG TDVS-H06xF
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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 _LGH06XF_H_
+#define _LGH06XF_H_
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_DVB_TUNER_LGH06XF) || (defined(CONFIG_DVB_TUNER_LGH06XF_MODULE) && defined(MODULE))
+extern struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_TUNER_LGH06XF */
+
+#endif /* _LGH06XF_H_ */
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index d20ab30c1e8..5a3a6e53cda 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -40,6 +40,7 @@
#include <linux/slab.h>
#include <asm/byteorder.h>
+#include "dvb_math.h"
#include "dvb_frontend.h"
#include "dvb-pll.h"
#include "or51132.h"
@@ -62,6 +63,7 @@ struct or51132_state
/* Demodulator private data */
fe_modulation_t current_modulation;
+ u32 snr; /* Result of last SNR calculation */
/* Tuner private data */
u32 current_frequency;
@@ -465,124 +467,128 @@ static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
return 0;
}
-/* log10-1 table at .5 increments from 1 to 100.5 */
-static unsigned int i100x20log10[] = {
- 0, 352, 602, 795, 954, 1088, 1204, 1306, 1397, 1480,
- 1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042,
- 2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380,
- 2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623,
- 2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813,
- 2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968,
- 2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100,
- 3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214,
- 3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316,
- 3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406,
- 3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488,
- 3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563,
- 3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632,
- 3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696,
- 3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755,
- 3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811,
- 3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863,
- 3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913,
- 3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960,
- 3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004,
-};
+/* Calculate SNR estimation (scaled by 2^24)
-static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000};
+ 8-VSB SNR and QAM equations from Oren datasheets
-static unsigned int i20Log10(unsigned short val)
-{
- unsigned int rntval = 100;
- unsigned int tmp = val;
- unsigned int exp = 1;
+ For 8-VSB:
+ SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) - K
+
+ Where K = 0 if NTSC rejection filter is OFF; and
+ K = 3 if NTSC rejection filter is ON
+
+ For QAM64:
+ SNR[dB] = 10 * log10(897152044.8282 / MSE^2 )
- while(tmp > 100) {tmp /= 100; exp++;}
+ For QAM256:
+ SNR[dB] = 10 * log10(907832426.314266 / MSE^2 )
- val = (2 * val)/denom[exp];
- if (exp > 1) rntval = 2000*exp;
+ We re-write the snr equation as:
+ SNR * 2^24 = 10*(c - 2*intlog10(MSE))
+ Where for QAM256, c = log10(907832426.314266) * 2^24
+ and for 8-VSB and QAM64, c = log10(897152044.8282) * 2^24 */
- rntval += i100x20log10[val];
- return rntval;
+static u32 calculate_snr(u32 mse, u32 c)
+{
+ if (mse == 0) /* No signal */
+ return 0;
+
+ mse = 2*intlog10(mse);
+ if (mse > c) {
+ /* Negative SNR, which is possible, but realisticly the
+ demod will lose lock before the signal gets this bad. The
+ API only allows for unsigned values, so just return 0 */
+ return 0;
+ }
+ return 10*(c - mse);
}
-static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+static int or51132_read_snr(struct dvb_frontend* fe, u16* snr)
{
struct or51132_state* state = fe->demodulator_priv;
- unsigned char rec_buf[2];
- unsigned char snd_buf[2];
- u8 rcvr_stat;
- u16 snr_equ;
- u32 signal_strength;
- int usK;
+ u8 rec_buf[2];
+ u8 snd_buf[2];
+ u32 noise;
+ u32 c;
+ u32 usK;
+ /* Register is same for VSB or QAM firmware */
snd_buf[0]=0x04;
snd_buf[1]=0x02; /* SNR after Equalizer */
msleep(30); /* 30ms */
if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
- printk(KERN_WARNING "or51132: read_status write error\n");
- return -1;
+ printk(KERN_WARNING "or51132: snr write error\n");
+ return -EREMOTEIO;
}
msleep(30); /* 30ms */
if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
- printk(KERN_WARNING "or51132: read_status read error\n");
- return -1;
+ printk(KERN_WARNING "or51132: snr read error\n");
+ return -EREMOTEIO;
}
- snr_equ = rec_buf[0] | (rec_buf[1] << 8);
- dprintk("read_signal_strength snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ);
+ noise = rec_buf[0] | (rec_buf[1] << 8);
+ dprintk("read_snr noise %x %x (%i)\n",rec_buf[0],rec_buf[1],noise);
- /* Receiver Status */
+ /* Read status, contains modulation type for QAM_AUTO and
+ NTSC filter for VSB */
snd_buf[0]=0x04;
- snd_buf[1]=0x00;
+ snd_buf[1]=0x00; /* Status register */
msleep(30); /* 30ms */
if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
- printk(KERN_WARNING "or51132: read_signal_strength read_status write error\n");
- return -1;
+ printk(KERN_WARNING "or51132: status write error\n");
+ return -EREMOTEIO;
}
msleep(30); /* 30ms */
if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
- printk(KERN_WARNING "or51132: read_signal_strength read_status read error\n");
- return -1;
+ printk(KERN_WARNING "or51132: status read error\n");
+ return -EREMOTEIO;
}
- dprintk("read_signal_strength read_status %x %x\n",rec_buf[0],rec_buf[1]);
- rcvr_stat = rec_buf[1];
- usK = (rcvr_stat & 0x10) ? 3 : 0;
- /* The value reported back from the frontend will be FFFF=100% 0000=0% */
- signal_strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000;
- if (signal_strength > 0xffff)
- *strength = 0xffff;
- else
- *strength = signal_strength;
- dprintk("read_signal_strength %i\n",*strength);
+ usK = 0;
+ switch (rec_buf[0]) {
+ case 0x06:
+ usK = (rec_buf[1] & 0x10) ? 0x03000000 : 0;
+ /* Fall through to QAM64 case */
+ case 0x43:
+ c = 150204167;
+ break;
+ case 0x45:
+ c = 150290396;
+ break;
+ default:
+ printk(KERN_ERR "or51132: unknown status 0x%02x\n", rec_buf[0]);
+ return -EREMOTEIO;
+ }
+ dprintk("%s: modulation %02x, NTSC rej O%s\n", __FUNCTION__,
+ rec_buf[0], rec_buf[1]&0x10?"n":"ff");
+
+ /* Calculate SNR using noise, c, and NTSC rejection correction */
+ state->snr = calculate_snr(noise, c) - usK;
+ *snr = (state->snr) >> 16;
+
+ dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise,
+ state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
return 0;
}
-static int or51132_read_snr(struct dvb_frontend* fe, u16* snr)
+static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength)
{
- struct or51132_state* state = fe->demodulator_priv;
- unsigned char rec_buf[2];
- unsigned char snd_buf[2];
- u16 snr_equ;
-
- snd_buf[0]=0x04;
- snd_buf[1]=0x02; /* SNR after Equalizer */
- msleep(30); /* 30ms */
- if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
- printk(KERN_WARNING "or51132: read_snr write error\n");
- return -1;
- }
- msleep(30); /* 30ms */
- if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
- printk(KERN_WARNING "or51132: read_snr dvr read error\n");
- return -1;
- }
- snr_equ = rec_buf[0] | (rec_buf[1] << 8);
- dprintk("read_snr snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ);
+ /* Calculate Strength from SNR up to 35dB */
+ /* Even though the SNR can go higher than 35dB, there is some comfort */
+ /* factor in having a range of strong signals that can show at 100% */
+ struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv;
+ u16 snr;
+ int ret;
- *snr = 0xFFFF - snr_equ;
- dprintk("read_snr %i\n",*snr);
+ ret = fe->ops.read_snr(fe, &snr);
+ if (ret != 0)
+ return ret;
+ /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+ /* scale the range 0 - 35*2^24 into 0 - 65535 */
+ if (state->snr >= 8960 * 0x10000)
+ *strength = 0xffff;
+ else
+ *strength = state->snr / 8960;
return 0;
}
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 2bf124b5368..048d7cfe12d 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -39,6 +39,7 @@
#include <linux/slab.h>
#include <asm/byteorder.h>
+#include "dvb_math.h"
#include "dvb_frontend.h"
#include "or51211.h"
@@ -63,6 +64,7 @@ struct or51211_state {
/* Demodulator private data */
u8 initialized:1;
+ u32 snr; /* Result of last SNR claculation */
/* Tuner private data */
u32 current_frequency;
@@ -292,107 +294,81 @@ static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status)
return 0;
}
-/* log10-1 table at .5 increments from 1 to 100.5 */
-static unsigned int i100x20log10[] = {
- 0, 352, 602, 795, 954, 1088, 1204, 1306, 1397, 1480,
- 1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042,
- 2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380,
- 2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623,
- 2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813,
- 2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968,
- 2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100,
- 3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214,
- 3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316,
- 3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406,
- 3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488,
- 3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563,
- 3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632,
- 3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696,
- 3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755,
- 3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811,
- 3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863,
- 3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913,
- 3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960,
- 3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004,
-};
-
-static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000};
+/* Calculate SNR estimation (scaled by 2^24)
-static unsigned int i20Log10(unsigned short val)
-{
- unsigned int rntval = 100;
- unsigned int tmp = val;
- unsigned int exp = 1;
+ 8-VSB SNR equation from Oren datasheets
- while(tmp > 100) {tmp /= 100; exp++;}
+ For 8-VSB:
+ SNR[dB] = 10 * log10(219037.9454 / MSE^2 )
- val = (2 * val)/denom[exp];
- if (exp > 1) rntval = 2000*exp;
+ We re-write the snr equation as:
+ SNR * 2^24 = 10*(c - 2*intlog10(MSE))
+ Where for 8-VSB, c = log10(219037.9454) * 2^24 */
- rntval += i100x20log10[val];
- return rntval;
+static u32 calculate_snr(u32 mse, u32 c)
+{
+ if (mse == 0) /* No signal */
+ return 0;
+
+ mse = 2*intlog10(mse);
+ if (mse > c) {
+ /* Negative SNR, which is possible, but realisticly the
+ demod will lose lock before the signal gets this bad. The
+ API only allows for unsigned values, so just return 0 */
+ return 0;
+ }
+ return 10*(c - mse);
}
-static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
{
struct or51211_state* state = fe->demodulator_priv;
u8 rec_buf[2];
- u8 snd_buf[4];
- u8 snr_equ;
- u32 signal_strength;
+ u8 snd_buf[3];
/* SNR after Equalizer */
snd_buf[0] = 0x04;
snd_buf[1] = 0x00;
snd_buf[2] = 0x04;
- snd_buf[3] = 0x00;
if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
- printk(KERN_WARNING "or51211: read_status write error\n");
+ printk(KERN_WARNING "%s: error writing snr reg\n",
+ __FUNCTION__);
return -1;
}
- msleep(3);
if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
- printk(KERN_WARNING "or51211: read_status read error\n");
+ printk(KERN_WARNING "%s: read_status read error\n",
+ __FUNCTION__);
return -1;
}
- snr_equ = rec_buf[0] & 0xff;
- /* The value reported back from the frontend will be FFFF=100% 0000=0% */
- signal_strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
- if (signal_strength > 0xffff)
- *strength = 0xffff;
- else
- *strength = signal_strength;
- dprintk("read_signal_strength %i\n",*strength);
+ state->snr = calculate_snr(rec_buf[0], 89599047);
+ *snr = (state->snr) >> 16;
+
+ dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __FUNCTION__, rec_buf[0],
+ state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
return 0;
}
-static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
+static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
{
- struct or51211_state* state = fe->demodulator_priv;
- u8 rec_buf[2];
- u8 snd_buf[4];
-
- /* SNR after Equalizer */
- snd_buf[0] = 0x04;
- snd_buf[1] = 0x00;
- snd_buf[2] = 0x04;
- snd_buf[3] = 0x00;
-
- if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
- printk(KERN_WARNING "or51211: read_status write error\n");
- return -1;
- }
- msleep(3);
- if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
- printk(KERN_WARNING "or51211: read_status read error\n");
- return -1;
- }
- *snr = rec_buf[0] & 0xff;
-
- dprintk("read_snr %i\n",*snr);
+ /* Calculate Strength from SNR up to 35dB */
+ /* Even though the SNR can go higher than 35dB, there is some comfort */
+ /* factor in having a range of strong signals that can show at 100% */
+ struct or51211_state* state = (struct or51211_state*)fe->demodulator_priv;
+ u16 snr;
+ int ret;
+
+ ret = fe->ops.read_snr(fe, &snr);
+ if (ret != 0)
+ return ret;
+ /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+ /* scale the range 0 - 35*2^24 into 0 - 65535 */
+ if (state->snr >= 8960 * 0x10000)
+ *strength = 0xffff;
+ else
+ *strength = state->snr / 8960;
return 0;
}
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 11e0dca9a2d..00e4bcd9f1a 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -648,18 +648,24 @@ static int tda10046_init(struct dvb_frontend* fe)
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities
break;
- case TDA10046_AGC_TDA827X:
+ case TDA10046_AGC_TDA827X_GP11:
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
break;
- case TDA10046_AGC_TDA827X_GPL:
+ case TDA10046_AGC_TDA827X_GP00:
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
break;
+ case TDA10046_AGC_TDA827X_GP01:
+ tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
+ tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
+ tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
+ tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x62); // set AGC polarities
+ break;
}
tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index 605ad2dfc09..ec502d71b83 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -35,8 +35,9 @@ enum tda10046_agc {
TDA10046_AGC_DEFAULT, /* original configuration */
TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */
TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */
- TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */
- TDA10046_AGC_TDA827X_GPL, /* same as above, but GPIOs 0 */
+ TDA10046_AGC_TDA827X_GP11, /* IF AGC only, special setup for tda827x */
+ TDA10046_AGC_TDA827X_GP00, /* same as above, but GPIOs 0 */
+ TDA10046_AGC_TDA827X_GP01, /* same as above, but GPIO3=0 GPIO1=1*/
};
enum tda10046_if {
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
index 3aa45ebbac3..67415c9db6f 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -262,12 +262,29 @@ static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status)
if (sync & 0x10)
*status |= FE_HAS_SYNC;
+ if (sync & 0x20) /* frontend can not lock */
+ *status |= FE_TIMEDOUT;
+
if ((sync & 0x1f) == 0x1f)
*status |= FE_HAS_LOCK;
return 0;
}
+static int tda8083_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct tda8083_state* state = fe->demodulator_priv;
+ int ret;
+ u8 buf[3];
+
+ if ((ret = tda8083_readregs(state, 0x0b, buf, sizeof(buf))))
+ return ret;
+
+ *ber = ((buf[0] & 0x1f) << 16) | (buf[1] << 8) | buf[2];
+
+ return 0;
+}
+
static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength)
{
struct tda8083_state* state = fe->demodulator_priv;
@@ -288,6 +305,17 @@ static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr)
return 0;
}
+static int tda8083_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct tda8083_state* state = fe->demodulator_priv;
+
+ *ucblocks = tda8083_readreg(state, 0x0f);
+ if (*ucblocks == 0xff)
+ *ucblocks = 0xffffffff;
+
+ return 0;
+}
+
static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
struct tda8083_state* state = fe->demodulator_priv;
@@ -440,6 +468,8 @@ static struct dvb_frontend_ops tda8083_ops = {
.read_status = tda8083_read_status,
.read_signal_strength = tda8083_read_signal_strength,
.read_snr = tda8083_read_snr,
+ .read_ber = tda8083_read_ber,
+ .read_ucblocks = tda8083_read_ucblocks,
.diseqc_send_master_cmd = tda8083_send_diseqc_msg,
.diseqc_send_burst = tda8083_diseqc_send_burst,
diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb/frontends/tda826x.c
index 34815b0b97e..79f971dc52b 100644
--- a/drivers/media/dvb/frontends/tda826x.c
+++ b/drivers/media/dvb/frontends/tda826x.c
@@ -42,8 +42,7 @@ struct tda826x_priv {
static int tda826x_release(struct dvb_frontend *fe)
{
- if (fe->tuner_priv)
- kfree(fe->tuner_priv);
+ kfree(fe->tuner_priv);
fe->tuner_priv = NULL;
return 0;
}
@@ -133,18 +132,21 @@ struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2
{
struct tda826x_priv *priv = NULL;
u8 b1 [] = { 0, 0 };
- struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 };
+ struct i2c_msg msg[2] = {
+ { .addr = addr, .flags = 0, .buf = NULL, .len = 0 },
+ { .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);
+ ret = i2c_transfer (i2c, msg, 2);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
- if (ret != 1)
+ if (ret != 2)
return NULL;
if (!(b1[1] & 0x80))
return NULL;
diff --git a/drivers/media/dvb/frontends/tua6100.c b/drivers/media/dvb/frontends/tua6100.c
index 88554393a9b..6ba0029dcf2 100644
--- a/drivers/media/dvb/frontends/tua6100.c
+++ b/drivers/media/dvb/frontends/tua6100.c
@@ -43,8 +43,7 @@ struct tua6100_priv {
static int tua6100_release(struct dvb_frontend *fe)
{
- if (fe->tuner_priv)
- kfree(fe->tuner_priv);
+ kfree(fe->tuner_priv);
fe->tuner_priv = NULL;
return 0;
}
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 8e4ce101eb2..ffda71dfdd6 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -650,7 +650,7 @@ static int __devinit pluto2_probe(struct pci_dev *pdev,
/* dvb */
ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE, &pdev->dev);
if (ret < 0)
- goto err_i2c_bit_del_bus;
+ goto err_i2c_del_adapter;
dvb_adapter = &pluto->dvb_adapter;
@@ -712,8 +712,8 @@ err_dvb_dmx_release:
dvb_dmx_release(dvbdemux);
err_dvb_unregister_adapter:
dvb_unregister_adapter(dvb_adapter);
-err_i2c_bit_del_bus:
- i2c_bit_del_bus(&pluto->i2c_adap);
+err_i2c_del_adapter:
+ i2c_del_adapter(&pluto->i2c_adap);
err_pluto_hw_exit:
pluto_hw_exit(pluto);
err_free_irq:
@@ -748,7 +748,7 @@ static void __devexit pluto2_remove(struct pci_dev *pdev)
dvb_dmxdev_release(&pluto->dmxdev);
dvb_dmx_release(dvbdemux);
dvb_unregister_adapter(dvb_adapter);
- i2c_bit_del_bus(&pluto->i2c_adap);
+ i2c_del_adapter(&pluto->i2c_adap);
pluto_hw_exit(pluto);
free_irq(pdev->irq, pluto);
pci_iounmap(pdev, pluto->io_mem);
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 95531a62499..eec7ccf41f8 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -92,6 +92,7 @@ config DVB_BUDGET_CI
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select VIDEO_IR
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index bba23bcd1b1..366c1371ee9 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -2828,7 +2828,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct saa7146_extension av7110_extension = {
.name = "dvb",
- .flags = SAA7146_I2C_SHORT_DELAY,
+ .flags = SAA7146_USE_I2C_IRQ,
.module = THIS_MODULE,
.pci_tbl = &pci_tbl[0],
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index d54bbcdde2c..e4544ea2b89 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -48,7 +48,8 @@ static void av7110_emit_keyup(unsigned long data)
if (!data || !test_bit(data, input_dev->key))
return;
- input_event(input_dev, EV_KEY, data, !!0);
+ input_report_key(input_dev, data, 0);
+ input_sync(input_dev);
}
@@ -115,14 +116,17 @@ static void av7110_emit_key(unsigned long parm)
del_timer(&keyup_timer);
if (keyup_timer.data != keycode || new_toggle != old_toggle) {
delay_timer_finished = 0;
- input_event(input_dev, EV_KEY, keyup_timer.data, !!0);
- input_event(input_dev, EV_KEY, keycode, !0);
- } else
- if (delay_timer_finished)
- input_event(input_dev, EV_KEY, keycode, 2);
+ input_event(input_dev, EV_KEY, keyup_timer.data, 0);
+ input_event(input_dev, EV_KEY, keycode, 1);
+ input_sync(input_dev);
+ } else if (delay_timer_finished) {
+ input_event(input_dev, EV_KEY, keycode, 2);
+ input_sync(input_dev);
+ }
} else {
delay_timer_finished = 0;
- input_event(input_dev, EV_KEY, keycode, !0);
+ input_event(input_dev, EV_KEY, keycode, 1);
+ input_sync(input_dev);
}
keyup_timer.expires = jiffies + UP_TIMEOUT;
@@ -211,6 +215,7 @@ static void ir_handler(struct av7110 *av7110, u32 ircom)
int __devinit av7110_ir_init(struct av7110 *av7110)
{
static struct proc_dir_entry *e;
+ int err;
if (av_cnt >= sizeof av_list/sizeof av_list[0])
return -ENOSPC;
@@ -231,7 +236,11 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
set_bit(EV_KEY, input_dev->evbit);
set_bit(EV_REP, input_dev->evbit);
input_register_keys();
- input_register_device(input_dev);
+ err = input_register_device(input_dev);
+ if (err) {
+ input_free_device(input_dev);
+ return err;
+ }
input_dev->timer.function = input_repeat_key;
e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL);
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 2235ff8b8a1..89ab4b59155 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -360,7 +360,7 @@ static int ciintf_init(struct budget_av *budget_av)
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
/* Enable DEBI pins */
- saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
+ saa7146_write(saa, MC1, MASK_27 | MASK_11);
/* register CI interface */
budget_av->ca.owner = THIS_MODULE;
@@ -386,7 +386,7 @@ static int ciintf_init(struct budget_av *budget_av)
return 0;
error:
- saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
+ saa7146_write(saa, MC1, MASK_27);
return result;
}
@@ -403,7 +403,7 @@ static void ciintf_deinit(struct budget_av *budget_av)
dvb_ca_en50221_release(&budget_av->ca);
/* disable DEBI pins */
- saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
+ saa7146_write(saa, MC1, MASK_27);
}
@@ -655,6 +655,10 @@ static struct tda10021_config philips_cu1216_config = {
.demod_address = 0x0c,
};
+static struct tda10021_config philips_cu1216_config_altaddress = {
+ .demod_address = 0x0d,
+};
+
@@ -831,7 +835,7 @@ static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
return -EINVAL;
rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf,
- params->frequency, 0);
+ params->frequency, 0);
if(rc < 0) return rc;
if (fe->ops.i2c_gate_ctrl)
@@ -914,6 +918,7 @@ static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBS_TV_STAR_CI 0x0016
#define SUBID_DVBS_EASYWATCH_1 0x001a
#define SUBID_DVBS_EASYWATCH 0x001e
+#define SUBID_DVBC_EASYWATCH 0x002a
#define SUBID_DVBC_KNC1 0x0020
#define SUBID_DVBC_KNC1_PLUS 0x0021
#define SUBID_DVBC_CINERGY1200 0x1156
@@ -947,11 +952,15 @@ static void frontend_init(struct budget_av *budget_av)
/* Enable / PowerON Frontend */
saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+ /* Wait for PowerON */
+ msleep(100);
+
/* additional setup necessary for the PLUS cards */
switch (saa->pci->subsystem_device) {
case SUBID_DVBS_KNC1_PLUS:
case SUBID_DVBC_KNC1_PLUS:
case SUBID_DVBT_KNC1_PLUS:
+ case SUBID_DVBC_EASYWATCH:
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
break;
}
@@ -1006,10 +1015,15 @@ static void frontend_init(struct budget_av *budget_av)
case SUBID_DVBC_KNC1:
case SUBID_DVBC_KNC1_PLUS:
case SUBID_DVBC_CINERGY1200:
+ case SUBID_DVBC_EASYWATCH:
budget_av->reinitialise_demod = 1;
fe = dvb_attach(tda10021_attach, &philips_cu1216_config,
&budget_av->budget.i2c_adap,
read_pwm(budget_av));
+ if (fe == NULL)
+ fe = dvb_attach(tda10021_attach, &philips_cu1216_config_altaddress,
+ &budget_av->budget.i2c_adap,
+ read_pwm(budget_av));
if (fe) {
budget_av->tda10021_poclkp = 1;
budget_av->tda10021_set_frontend = fe->ops.set_frontend;
@@ -1242,6 +1256,7 @@ MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
@@ -1260,6 +1275,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
+ MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
@@ -1277,7 +1293,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct saa7146_extension budget_extension = {
.name = "budget_av",
- .flags = SAA7146_I2C_SHORT_DELAY,
+ .flags = SAA7146_USE_I2C_IRQ,
.pci_tbl = pci_tbl,
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index cd5ec489af1..f2066b47bae 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -37,6 +37,7 @@
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/spinlock.h>
+#include <media/ir-common.h>
#include "dvb_ca_en50221.h"
#include "stv0299.h"
@@ -72,162 +73,218 @@
#define SLOTSTATUS_READY 8
#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
+/* Milliseconds during which key presses are regarded as key repeat and during
+ * which the debounce logic is active
+ */
+#define IR_REPEAT_TIMEOUT 350
+
+/* RC5 device wildcard */
+#define IR_DEVICE_ANY 255
+
+/* Some remotes sends multiple sequences per keypress (e.g. Zenith sends two),
+ * this setting allows the superflous sequences to be ignored
+ */
+static int debounce = 0;
+module_param(debounce, int, 0644);
+MODULE_PARM_DESC(debounce, "ignore repeated IR sequences (default: 0 = ignore no sequences)");
+
+static int rc5_device = -1;
+module_param(rc5_device, int, 0644);
+MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
+
+static int ir_debug = 0;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
+
+struct budget_ci_ir {
+ struct input_dev *dev;
+ struct tasklet_struct msp430_irq_tasklet;
+ char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
+ char phys[32];
+ struct ir_input_state state;
+ int rc5_device;
+};
+
struct budget_ci {
struct budget budget;
- struct input_dev *input_dev;
- struct tasklet_struct msp430_irq_tasklet;
struct tasklet_struct ciintf_irq_tasklet;
int slot_status;
int ci_irq;
struct dvb_ca_en50221 ca;
- char ir_dev_name[50];
+ struct budget_ci_ir ir;
u8 tuner_pll_address; /* used for philips_tdm1316l configs */
};
-/* from reading the following remotes:
- Zenith Universal 7 / TV Mode 807 / VCR Mode 837
- Hauppauge (from NOVA-CI-s box product)
- i've taken a "middle of the road" approach and note the differences
-*/
-static u16 key_map[64] = {
- /* 0x0X */
- KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
- KEY_9,
- KEY_ENTER,
- KEY_RED,
- KEY_POWER, /* RADIO on Hauppauge */
- KEY_MUTE,
- 0,
- KEY_A, /* TV on Hauppauge */
- /* 0x1X */
- KEY_VOLUMEUP, KEY_VOLUMEDOWN,
- 0, 0,
- KEY_B,
- 0, 0, 0, 0, 0, 0, 0,
- KEY_UP, KEY_DOWN,
- KEY_OPTION, /* RESERVED on Hauppauge */
- KEY_BREAK,
- /* 0x2X */
- KEY_CHANNELUP, KEY_CHANNELDOWN,
- KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
- 0, KEY_RESTART, KEY_OK,
- KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
- 0,
- KEY_ENTER, /* VCR mode on Zenith */
- KEY_PAUSE,
- 0,
- KEY_RIGHT, KEY_LEFT,
- 0,
- KEY_MENU, /* FULL SCREEN on Hauppauge */
- 0,
- /* 0x3X */
- KEY_SLOW,
- KEY_PREVIOUS, /* VCR mode on Zenith */
- KEY_REWIND,
- 0,
- KEY_FASTFORWARD,
- KEY_PLAY, KEY_STOP,
- KEY_RECORD,
- KEY_TUNER, /* TV/VCR on Zenith */
- 0,
- KEY_C,
- 0,
- KEY_EXIT,
- KEY_POWER2,
- KEY_TUNER, /* VCR mode on Zenith */
- 0,
-};
-
-static void msp430_ir_debounce(unsigned long data)
+static void msp430_ir_keyup(unsigned long data)
{
- struct input_dev *dev = (struct input_dev *) data;
-
- if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
- input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
- return;
- }
-
- dev->rep[0] = 0;
- dev->timer.expires = jiffies + HZ * 350 / 1000;
- add_timer(&dev->timer);
- input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
+ struct budget_ci_ir *ir = (struct budget_ci_ir *) data;
+ ir_input_nokey(ir->dev, &ir->state);
}
static void msp430_ir_interrupt(unsigned long data)
{
struct budget_ci *budget_ci = (struct budget_ci *) data;
- struct input_dev *dev = budget_ci->input_dev;
- unsigned int code =
- ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
+ struct input_dev *dev = budget_ci->ir.dev;
+ static int bounces = 0;
+ int device;
+ int toggle;
+ static int prev_toggle = -1;
+ static u32 ir_key;
+ u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
+
+ /*
+ * The msp430 chip can generate two different bytes, command and device
+ *
+ * type1: X1CCCCCC, C = command bits (0 - 63)
+ * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
+ *
+ * More than one command byte may be generated before the device byte
+ * Only when we have both, a correct keypress is generated
+ */
+
+ /* Is this a RC5 command byte? */
+ if (command & 0x40) {
+ if (ir_debug)
+ printk("budget_ci: received command byte 0x%02x\n", command);
+ ir_key = command & 0x3f;
+ return;
+ }
- if (code & 0x40) {
- code &= 0x3f;
+ /* It's a RC5 device byte */
+ if (ir_debug)
+ printk("budget_ci: received device byte 0x%02x\n", command);
+ device = command & 0x1f;
+ toggle = command & 0x20;
- if (timer_pending(&dev->timer)) {
- if (code == dev->repeat_key) {
- ++dev->rep[0];
- return;
- }
- del_timer(&dev->timer);
- input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
- }
+ if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && budget_ci->ir.rc5_device != device)
+ return;
- if (!key_map[code]) {
- printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
- return;
- }
+ /* Ignore repeated key sequences if requested */
+ if (toggle == prev_toggle && ir_key == dev->repeat_key &&
+ bounces > 0 && timer_pending(&dev->timer)) {
+ if (ir_debug)
+ printk("budget_ci: debounce logic ignored IR command\n");
+ bounces--;
+ return;
+ }
+ prev_toggle = toggle;
- /* initialize debounce and repeat */
- dev->repeat_key = code;
- /* Zenith remote _always_ sends 2 sequences */
- dev->rep[0] = ~0;
- /* 350 milliseconds */
- dev->timer.expires = jiffies + HZ * 350 / 1000;
- /* MAKE */
- input_event(dev, EV_KEY, key_map[code], !0);
- add_timer(&dev->timer);
+ /* Are we still waiting for a keyup event? */
+ if (del_timer(&dev->timer))
+ ir_input_nokey(dev, &budget_ci->ir.state);
+
+ /* Generate keypress */
+ if (ir_debug)
+ printk("budget_ci: generating keypress 0x%02x\n", ir_key);
+ ir_input_keydown(dev, &budget_ci->ir.state, ir_key, (ir_key & (command << 8)));
+
+ /* Do we want to delay the keyup event? */
+ if (debounce) {
+ bounces = debounce;
+ mod_timer(&dev->timer, jiffies + msecs_to_jiffies(IR_REPEAT_TIMEOUT));
+ } else {
+ ir_input_nokey(dev, &budget_ci->ir.state);
}
}
static int msp430_ir_init(struct budget_ci *budget_ci)
{
struct saa7146_dev *saa = budget_ci->budget.dev;
- struct input_dev *input_dev;
- int i;
+ struct input_dev *input_dev = budget_ci->ir.dev;
+ int error;
+
+ budget_ci->ir.dev = input_dev = input_allocate_device();
+ if (!input_dev) {
+ printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
+ error = -ENOMEM;
+ goto out1;
+ }
+
+ snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
+ "Budget-CI dvb ir receiver %s", saa->name);
+ snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
+ "pci-%s/ir0", pci_name(saa->pci));
- budget_ci->input_dev = input_dev = input_allocate_device();
- if (!input_dev)
- return -ENOMEM;
+ input_dev->name = budget_ci->ir.name;
- sprintf(budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name);
+ input_dev->phys = budget_ci->ir.phys;
+ input_dev->id.bustype = BUS_PCI;
+ input_dev->id.version = 1;
+ if (saa->pci->subsystem_vendor) {
+ input_dev->id.vendor = saa->pci->subsystem_vendor;
+ input_dev->id.product = saa->pci->subsystem_device;
+ } else {
+ input_dev->id.vendor = saa->pci->vendor;
+ input_dev->id.product = saa->pci->device;
+ }
+ input_dev->cdev.dev = &saa->pci->dev;
- input_dev->name = budget_ci->ir_dev_name;
+ /* Select keymap and address */
+ switch (budget_ci->budget.dev->pci->subsystem_device) {
+ case 0x100c:
+ case 0x100f:
+ case 0x1010:
+ case 0x1011:
+ case 0x1012:
+ case 0x1017:
+ /* The hauppauge keymap is a superset of these remotes */
+ ir_input_init(input_dev, &budget_ci->ir.state,
+ IR_TYPE_RC5, ir_codes_hauppauge_new);
+
+ if (rc5_device < 0)
+ budget_ci->ir.rc5_device = 0x1f;
+ else
+ budget_ci->ir.rc5_device = rc5_device;
+ break;
+ default:
+ /* unknown remote */
+ ir_input_init(input_dev, &budget_ci->ir.state,
+ IR_TYPE_RC5, ir_codes_budget_ci_old);
+
+ if (rc5_device < 0)
+ budget_ci->ir.rc5_device = IR_DEVICE_ANY;
+ else
+ budget_ci->ir.rc5_device = rc5_device;
+ break;
+ }
- set_bit(EV_KEY, input_dev->evbit);
- for (i = 0; i < ARRAY_SIZE(key_map); i++)
- if (key_map[i])
- set_bit(key_map[i], input_dev->keybit);
+ /* initialise the key-up debounce timeout handler */
+ input_dev->timer.function = msp430_ir_keyup;
+ input_dev->timer.data = (unsigned long) &budget_ci->ir;
- input_register_device(budget_ci->input_dev);
+ error = input_register_device(input_dev);
+ if (error) {
+ printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
+ goto out2;
+ }
- input_dev->timer.function = msp430_ir_debounce;
+ tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
+ (unsigned long) budget_ci);
- saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
+ SAA7146_IER_ENABLE(saa, MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
return 0;
+
+out2:
+ input_free_device(input_dev);
+out1:
+ return error;
}
static void msp430_ir_deinit(struct budget_ci *budget_ci)
{
struct saa7146_dev *saa = budget_ci->budget.dev;
- struct input_dev *dev = budget_ci->input_dev;
+ struct input_dev *dev = budget_ci->ir.dev;
- saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
+ SAA7146_IER_DISABLE(saa, MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
+ tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
- if (del_timer(&dev->timer))
- input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
+ if (del_timer(&dev->timer)) {
+ ir_input_nokey(dev, &budget_ci->ir.state);
+ input_sync(dev);
+ }
input_unregister_device(dev);
}
@@ -428,7 +485,7 @@ static int ciintf_init(struct budget_ci *budget_ci)
memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
// enable DEBI pins
- saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
+ saa7146_write(saa, MC1, MASK_27 | MASK_11);
// test if it is there
ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
@@ -480,7 +537,7 @@ static int ciintf_init(struct budget_ci *budget_ci)
} else {
saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
}
- saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
+ SAA7146_IER_ENABLE(saa, MASK_03);
}
// enable interface
@@ -502,7 +559,7 @@ static int ciintf_init(struct budget_ci *budget_ci)
return 0;
error:
- saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
+ saa7146_write(saa, MC1, MASK_27);
return result;
}
@@ -512,7 +569,7 @@ static void ciintf_deinit(struct budget_ci *budget_ci)
// disable CI interrupts
if (budget_ci->ci_irq) {
- saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
+ SAA7146_IER_DISABLE(saa, MASK_03);
saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
tasklet_kill(&budget_ci->ciintf_irq_tasklet);
}
@@ -530,7 +587,7 @@ static void ciintf_deinit(struct budget_ci *budget_ci)
dvb_ca_en50221_release(&budget_ci->ca);
// disable DEBI pins
- saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
+ saa7146_write(saa, MC1, MASK_27);
}
static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
@@ -540,7 +597,7 @@ static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
if (*isr & MASK_06)
- tasklet_schedule(&budget_ci->msp430_irq_tasklet);
+ tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
if (*isr & MASK_10)
ttpci_budget_irq10_handler(dev, isr);
@@ -835,7 +892,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc
band = 1;
} else if (tuner_frequency < 200000000) {
cp = 6;
- band = 1;
+ band = 2;
} else if (tuner_frequency < 290000000) {
cp = 3;
band = 2;
@@ -1083,24 +1140,23 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
struct budget_ci *budget_ci;
int err;
- if (!(budget_ci = kmalloc(sizeof(struct budget_ci), GFP_KERNEL)))
- return -ENOMEM;
+ budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
+ if (!budget_ci) {
+ err = -ENOMEM;
+ goto out1;
+ }
dprintk(2, "budget_ci: %p\n", budget_ci);
- budget_ci->budget.ci_present = 0;
-
dev->ext_priv = budget_ci;
- if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
- kfree(budget_ci);
- return err;
- }
-
- tasklet_init(&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
- (unsigned long) budget_ci);
+ err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
+ if (err)
+ goto out2;
- msp430_ir_init(budget_ci);
+ err = msp430_ir_init(budget_ci);
+ if (err)
+ goto out3;
ciintf_init(budget_ci);
@@ -1110,6 +1166,13 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
ttpci_budget_init_hooks(&budget_ci->budget);
return 0;
+
+out3:
+ ttpci_budget_deinit(&budget_ci->budget);
+out2:
+ kfree(budget_ci);
+out1:
+ return err;
}
static int budget_ci_detach(struct saa7146_dev *dev)
@@ -1120,16 +1183,13 @@ static int budget_ci_detach(struct saa7146_dev *dev)
if (budget_ci->budget.ci_present)
ciintf_deinit(budget_ci);
+ msp430_ir_deinit(budget_ci);
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);
-
- msp430_ir_deinit(budget_ci);
-
// disable frontend and CI interface
saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
@@ -1162,7 +1222,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct saa7146_extension budget_extension = {
.name = "budget_ci dvb",
- .flags = SAA7146_I2C_SHORT_DELAY,
+ .flags = SAA7146_USE_I2C_IRQ,
.module = THIS_MODULE,
.pci_tbl = &pci_tbl[0],
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 56f1c80defc..9268a82bada 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -555,7 +555,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct saa7146_extension budget_extension = {
.name = "budget dvb",
- .flags = SAA7146_I2C_SHORT_DELAY,
+ .flags = SAA7146_USE_I2C_IRQ,
.module = THIS_MODULE,
.pci_tbl = pci_tbl,
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 10b121ada83..bd6e7baae2e 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -238,6 +238,7 @@ static void ttusb_dec_handle_irq( struct urb *urb)
* for now lets report each signal as a key down and up*/
dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]);
input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1);
+ input_sync(dec->rc_input_dev);
input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0);
input_sync(dec->rc_input_dev);
}
@@ -1187,11 +1188,12 @@ static int ttusb_init_rc( struct ttusb_dec *dec)
struct input_dev *input_dev;
u8 b[] = { 0x00, 0x01 };
int i;
+ int err;
usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys));
strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys));
- dec->rc_input_dev = input_dev = input_allocate_device();
+ input_dev = input_allocate_device();
if (!input_dev)
return -ENOMEM;
@@ -1205,8 +1207,13 @@ static int ttusb_init_rc( struct ttusb_dec *dec)
for (i = 0; i < ARRAY_SIZE(rc_keys); i++)
set_bit(rc_keys[i], input_dev->keybit);
- input_register_device(input_dev);
+ err = input_register_device(input_dev);
+ if (err) {
+ input_free_device(input_dev);
+ return err;
+ }
+ dec->rc_input_dev = input_dev;
if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))
printk("%s: usb_submit_urb failed\n",__FUNCTION__);
/* enable irq pipe */
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index 42f39a89bc4..a6fb1d6a7b5 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -195,7 +195,7 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf
struct ttusbdecfe_state* state = NULL;
/* allocate memory for the internal state */
- state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
+ state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
if (state == NULL)
return NULL;
@@ -215,7 +215,7 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf
struct ttusbdecfe_state* state = NULL;
/* allocate memory for the internal state */
- state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
+ state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
if (state == NULL)
return NULL;
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index b8fde5cf473..57357db31b8 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -184,6 +184,14 @@ config VIDEO_KS0127
To compile this driver as a module, choose M here: the
module will be called ks0127.
+config VIDEO_OV7670
+ tristate "OmniVision OV7670 sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV7670 VGA camera. It currently only works with the M88ALP01
+ controller.
+
config VIDEO_SAA7110
tristate "Philips SAA7110 video decoder"
depends on VIDEO_V4L1 && I2C
@@ -567,18 +575,6 @@ config VIDEO_ZORAN_AVS6EYES
help
Support for the AverMedia 6 Eyes video surveillance card.
-config VIDEO_ZR36120
- tristate "Zoran ZR36120/36125 Video For Linux"
- depends on PCI && I2C && VIDEO_V4L1 && BROKEN
- help
- Support for ZR36120/ZR36125 based frame grabber/overlay boards.
- This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV,
- and Buster boards. Please read the material in
- <file:Documentation/video4linux/zr36120.txt> for more information.
-
- To compile this driver as a module, choose M here: the
- module will be called zr36120.
-
config VIDEO_MEYE
tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
depends on PCI && SONYPI && VIDEO_V4L1
@@ -670,6 +666,15 @@ config VIDEO_M32R_AR_M64278
To compile this driver as a module, choose M here: the
module will be called arv.
+config VIDEO_CAFE_CCIC
+ tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
+ depends on PCI && I2C && VIDEO_V4L2
+ select VIDEO_OV7670
+ ---help---
+ This is a video4linux2 driver for the Marvell 88ALP01 integrated
+ CMOS camera controller. This is the controller found on first-
+ generation OLPC systems.
+
#
# USB Multimedia device configuration
#
@@ -681,6 +686,8 @@ source "drivers/media/video/pvrusb2/Kconfig"
source "drivers/media/video/em28xx/Kconfig"
+source "drivers/media/video/usbvision/Kconfig"
+
source "drivers/media/video/usbvideo/Kconfig"
source "drivers/media/video/et61x251/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index af57abce8a6..9b1f3f06bb7 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -2,7 +2,6 @@
# Makefile for the video capture/playback device drivers.
#
-zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \
@@ -23,7 +22,6 @@ obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
-obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
@@ -64,6 +62,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_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
@@ -92,6 +91,9 @@ obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
+obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
+obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
obj-$(CONFIG_USB_SE401) += se401.o
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 6e1ddad9f0c..ab8f970760f 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -1793,7 +1793,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
memset(i,0,sizeof(*i));
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
- i->audioset = 0;
+ i->audioset = 1;
if (i->index == bttv_tvcards[btv->c.type].tuner) {
sprintf(i->name, "Television");
i->type = V4L2_INPUT_TYPE_TUNER;
@@ -4050,8 +4050,8 @@ static int __devinit bttv_probe(struct pci_dev *dev,
(unsigned long long)pci_resource_start(dev,0));
schedule();
- btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
- if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) {
+ btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
+ if (NULL == btv->bt848_mmio) {
printk("bttv%d: ioremap() failed\n", btv->c.nr);
result = -EIO;
goto fail1;
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 70de6c96e20..62b873076e0 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -479,11 +479,7 @@ int __devexit fini_bttv_i2c(struct bttv *btv)
if (0 != btv->i2c_rc)
return 0;
- if (btv->use_i2c_hw) {
- return i2c_del_adapter(&btv->c.i2c_adap);
- } else {
- return i2c_bit_del_bus(&btv->c.i2c_adap);
- }
+ return i2c_del_adapter(&btv->c.i2c_adap);
}
/*
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 933d6db09ac..cbc012f71f5 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -259,24 +259,59 @@ static void bttv_rc5_timer_keyup(unsigned long data)
/* ---------------------------------------------------------------------- */
+static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
+{
+ if (ir->polling) {
+ init_timer(&ir->timer);
+ ir->timer.function = bttv_input_timer;
+ ir->timer.data = (unsigned long)btv;
+ ir->timer.expires = jiffies + HZ;
+ add_timer(&ir->timer);
+ } else if (ir->rc5_gpio) {
+ /* set timer_end for code completion */
+ init_timer(&ir->timer_end);
+ ir->timer_end.function = bttv_rc5_timer_end;
+ ir->timer_end.data = (unsigned long)ir;
+
+ init_timer(&ir->timer_keyup);
+ ir->timer_keyup.function = bttv_rc5_timer_keyup;
+ ir->timer_keyup.data = (unsigned long)ir;
+ }
+}
+
+static void bttv_ir_stop(struct bttv *btv)
+{
+ if (btv->remote->polling) {
+ del_timer_sync(&btv->remote->timer);
+ flush_scheduled_work();
+ }
+
+ if (btv->remote->rc5_gpio) {
+ u32 gpio;
+
+ del_timer_sync(&btv->remote->timer_end);
+ flush_scheduled_work();
+
+ gpio = bttv_gpio_read(&btv->c);
+ bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+ }
+}
+
int bttv_input_init(struct bttv *btv)
{
struct bttv_ir *ir;
IR_KEYTAB_TYPE *ir_codes = NULL;
struct input_dev *input_dev;
int ir_type = IR_TYPE_OTHER;
+ int err = -ENOMEM;
if (!btv->has_remote)
return -ENODEV;
ir = kzalloc(sizeof(*ir),GFP_KERNEL);
input_dev = input_allocate_device();
- if (!ir || !input_dev) {
- kfree(ir);
- input_free_device(input_dev);
- return -ENOMEM;
- }
- memset(ir,0,sizeof(*ir));
+ if (!ir || !input_dev)
+ goto err_out_free;
/* detect & configure */
switch (btv->c.type) {
@@ -348,10 +383,9 @@ int bttv_input_init(struct bttv *btv)
break;
}
if (NULL == ir_codes) {
- dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type);
- kfree(ir);
- input_free_device(input_dev);
- return -ENODEV;
+ dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type);
+ err = -ENODEV;
+ goto err_out_free;
}
if (ir->rc5_gpio) {
@@ -389,32 +423,26 @@ int bttv_input_init(struct bttv *btv)
input_dev->cdev.dev = &btv->c.pci->dev;
btv->remote = ir;
- if (ir->polling) {
- init_timer(&ir->timer);
- ir->timer.function = bttv_input_timer;
- ir->timer.data = (unsigned long)btv;
- ir->timer.expires = jiffies + HZ;
- add_timer(&ir->timer);
- } else if (ir->rc5_gpio) {
- /* set timer_end for code completion */
- init_timer(&ir->timer_end);
- ir->timer_end.function = bttv_rc5_timer_end;
- ir->timer_end.data = (unsigned long)ir;
-
- init_timer(&ir->timer_keyup);
- ir->timer_keyup.function = bttv_rc5_timer_keyup;
- ir->timer_keyup.data = (unsigned long)ir;
- }
+ bttv_ir_start(btv, ir);
/* all done */
- input_register_device(btv->remote->dev);
- printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
+ err = input_register_device(btv->remote->dev);
+ if (err)
+ goto err_out_stop;
/* the remote isn't as bouncy as a keyboard */
ir->dev->rep[REP_DELAY] = repeat_delay;
ir->dev->rep[REP_PERIOD] = repeat_period;
return 0;
+
+ err_out_stop:
+ bttv_ir_stop(btv);
+ btv->remote = NULL;
+ err_out_free:
+ input_free_device(input_dev);
+ kfree(ir);
+ return err;
}
void bttv_input_fini(struct bttv *btv)
@@ -422,22 +450,7 @@ void bttv_input_fini(struct bttv *btv)
if (btv->remote == NULL)
return;
- if (btv->remote->polling) {
- del_timer_sync(&btv->remote->timer);
- flush_scheduled_work();
- }
-
-
- if (btv->remote->rc5_gpio) {
- u32 gpio;
-
- del_timer_sync(&btv->remote->timer_end);
- flush_scheduled_work();
-
- gpio = bttv_gpio_read(&btv->c);
- bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
- }
-
+ bttv_ir_stop(btv);
input_unregister_device(btv->remote->dev);
kfree(btv->remote);
btv->remote = NULL;
diff --git a/drivers/media/video/cafe_ccic-regs.h b/drivers/media/video/cafe_ccic-regs.h
new file mode 100644
index 00000000000..b2c22a0d664
--- /dev/null
+++ b/drivers/media/video/cafe_ccic-regs.h
@@ -0,0 +1,160 @@
+/*
+ * Register definitions for the m88alp01 camera interface. Offsets in bytes
+ * as given in the spec.
+ *
+ * Copyright 2006 One Laptop Per Child Association, Inc.
+ *
+ * Written by Jonathan Corbet, corbet@lwn.net.
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+#define REG_Y0BAR 0x00
+#define REG_Y1BAR 0x04
+#define REG_Y2BAR 0x08
+/* ... */
+
+#define REG_IMGPITCH 0x24 /* Image pitch register */
+#define IMGP_YP_SHFT 2 /* Y pitch params */
+#define IMGP_YP_MASK 0x00003ffc /* Y pitch field */
+#define IMGP_UVP_SHFT 18 /* UV pitch (planar) */
+#define IMGP_UVP_MASK 0x3ffc0000
+#define REG_IRQSTATRAW 0x28 /* RAW IRQ Status */
+#define IRQ_EOF0 0x00000001 /* End of frame 0 */
+#define IRQ_EOF1 0x00000002 /* End of frame 1 */
+#define IRQ_EOF2 0x00000004 /* End of frame 2 */
+#define IRQ_SOF0 0x00000008 /* Start of frame 0 */
+#define IRQ_SOF1 0x00000010 /* Start of frame 1 */
+#define IRQ_SOF2 0x00000020 /* Start of frame 2 */
+#define IRQ_OVERFLOW 0x00000040 /* FIFO overflow */
+#define IRQ_TWSIW 0x00010000 /* TWSI (smbus) write */
+#define IRQ_TWSIR 0x00020000 /* TWSI read */
+#define IRQ_TWSIE 0x00040000 /* TWSI error */
+#define TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE)
+#define FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2)
+#define ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW)
+#define REG_IRQMASK 0x2c /* IRQ mask - same bits as IRQSTAT */
+#define REG_IRQSTAT 0x30 /* IRQ status / clear */
+
+#define REG_IMGSIZE 0x34 /* Image size */
+#define IMGSZ_V_MASK 0x1fff0000
+#define IMGSZ_V_SHIFT 16
+#define IMGSZ_H_MASK 0x00003fff
+#define REG_IMGOFFSET 0x38 /* IMage offset */
+
+#define REG_CTRL0 0x3c /* Control 0 */
+#define C0_ENABLE 0x00000001 /* Makes the whole thing go */
+
+/* Mask for all the format bits */
+#define C0_DF_MASK 0x00fffffc /* Bits 2-23 */
+
+/* RGB ordering */
+#define C0_RGB4_RGBX 0x00000000
+#define C0_RGB4_XRGB 0x00000004
+#define C0_RGB4_BGRX 0x00000008
+#define C0_RGB4_XBGR 0x0000000c
+#define C0_RGB5_RGGB 0x00000000
+#define C0_RGB5_GRBG 0x00000004
+#define C0_RGB5_GBRG 0x00000008
+#define C0_RGB5_BGGR 0x0000000c
+
+/* Spec has two fields for DIN and DOUT, but they must match, so
+ combine them here. */
+#define C0_DF_YUV 0x00000000 /* Data is YUV */
+#define C0_DF_RGB 0x000000a0 /* ... RGB */
+#define C0_DF_BAYER 0x00000140 /* ... Bayer */
+/* 8-8-8 must be missing from the below - ask */
+#define C0_RGBF_565 0x00000000
+#define C0_RGBF_444 0x00000800
+#define C0_RGB_BGR 0x00001000 /* Blue comes first */
+#define C0_YUV_PLANAR 0x00000000 /* YUV 422 planar format */
+#define C0_YUV_PACKED 0x00008000 /* YUV 422 packed */
+#define C0_YUV_420PL 0x0000a000 /* YUV 420 planar */
+/* Think that 420 packed must be 111 - ask */
+#define C0_YUVE_YUYV 0x00000000 /* Y1CbY0Cr */
+#define C0_YUVE_YVYU 0x00010000 /* Y1CrY0Cb */
+#define C0_YUVE_VYUY 0x00020000 /* CrY1CbY0 */
+#define C0_YUVE_UYVY 0x00030000 /* CbY1CrY0 */
+#define C0_YUVE_XYUV 0x00000000 /* 420: .YUV */
+#define C0_YUVE_XYVU 0x00010000 /* 420: .YVU */
+#define C0_YUVE_XUVY 0x00020000 /* 420: .UVY */
+#define C0_YUVE_XVUY 0x00030000 /* 420: .VUY */
+/* Bayer bits 18,19 if needed */
+#define C0_HPOL_LOW 0x01000000 /* HSYNC polarity active low */
+#define C0_VPOL_LOW 0x02000000 /* VSYNC polarity active low */
+#define C0_VCLK_LOW 0x04000000 /* VCLK on falling edge */
+#define C0_DOWNSCALE 0x08000000 /* Enable downscaler */
+#define C0_SIFM_MASK 0xc0000000 /* SIF mode bits */
+#define C0_SIF_HVSYNC 0x00000000 /* Use H/VSYNC */
+#define CO_SOF_NOSYNC 0x40000000 /* Use inband active signaling */
+
+
+#define REG_CTRL1 0x40 /* Control 1 */
+#define C1_444ALPHA 0x00f00000 /* Alpha field in RGB444 */
+#define C1_ALPHA_SHFT 20
+#define C1_DMAB32 0x00000000 /* 32-byte DMA burst */
+#define C1_DMAB16 0x02000000 /* 16-byte DMA burst */
+#define C1_DMAB64 0x04000000 /* 64-byte DMA burst */
+#define C1_DMAB_MASK 0x06000000
+#define C1_TWOBUFS 0x08000000 /* Use only two DMA buffers */
+#define C1_PWRDWN 0x10000000 /* Power down */
+
+#define REG_CLKCTRL 0x88 /* Clock control */
+#define CLK_DIV_MASK 0x0000ffff /* Upper bits RW "reserved" */
+
+#define REG_GPR 0xb4 /* General purpose register. This
+ controls inputs to the power and reset
+ pins on the OV7670 used with OLPC;
+ other deployments could differ. */
+#define GPR_C1EN 0x00000020 /* Pad 1 (power down) enable */
+#define GPR_C0EN 0x00000010 /* Pad 0 (reset) enable */
+#define GPR_C1 0x00000002 /* Control 1 value */
+/*
+ * Control 0 is wired to reset on OLPC machines. For ov7x sensors,
+ * it is active low, for 0v6x, instead, it's active high. What
+ * fun.
+ */
+#define GPR_C0 0x00000001 /* Control 0 value */
+
+#define REG_TWSIC0 0xb8 /* TWSI (smbus) control 0 */
+#define TWSIC0_EN 0x00000001 /* TWSI enable */
+#define TWSIC0_MODE 0x00000002 /* 1 = 16-bit, 0 = 8-bit */
+#define TWSIC0_SID 0x000003fc /* Slave ID */
+#define TWSIC0_SID_SHIFT 2
+#define TWSIC0_CLKDIV 0x0007fc00 /* Clock divider */
+#define TWSIC0_MASKACK 0x00400000 /* Mask ack from sensor */
+#define TWSIC0_OVMAGIC 0x00800000 /* Make it work on OV sensors */
+
+#define REG_TWSIC1 0xbc /* TWSI control 1 */
+#define TWSIC1_DATA 0x0000ffff /* Data to/from camchip */
+#define TWSIC1_ADDR 0x00ff0000 /* Address (register) */
+#define TWSIC1_ADDR_SHIFT 16
+#define TWSIC1_READ 0x01000000 /* Set for read op */
+#define TWSIC1_WSTAT 0x02000000 /* Write status */
+#define TWSIC1_RVALID 0x04000000 /* Read data valid */
+#define TWSIC1_ERROR 0x08000000 /* Something screwed up */
+
+
+#define REG_UBAR 0xc4 /* Upper base address register */
+
+/*
+ * Here's the weird global control registers which are said to live
+ * way up here.
+ */
+#define REG_GL_CSR 0x3004 /* Control/status register */
+#define GCSR_SRS 0x00000001 /* SW Reset set */
+#define GCSR_SRC 0x00000002 /* SW Reset clear */
+#define GCSR_MRS 0x00000004 /* Master reset set */
+#define GCSR_MRC 0x00000008 /* HW Reset clear */
+#define GCSR_CCIC_EN 0x00004000 /* CCIC Clock enable */
+#define REG_GL_IMASK 0x300c /* Interrupt mask register */
+#define GIMSK_CCIC_EN 0x00000004 /* CCIC Interrupt enable */
+
+#define REG_LEN REG_GL_IMASK + 4
+
+
+/*
+ * Useful stuff that probably belongs somewhere global.
+ */
+#define VGA_WIDTH 640
+#define VGA_HEIGHT 480
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
new file mode 100644
index 00000000000..3083c8075d1
--- /dev/null
+++ b/drivers/media/video/cafe_ccic.c
@@ -0,0 +1,2228 @@
+/*
+ * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe"
+ * multifunction chip. Currently works with the Omnivision OV7670
+ * sensor.
+ *
+ * Copyright 2006 One Laptop Per Child Association, Inc.
+ *
+ * Written by Jonathan Corbet, corbet@lwn.net.
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/jiffies.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include "cafe_ccic-regs.h"
+
+#define CAFE_VERSION 0x000001
+
+
+/*
+ * Parameters.
+ */
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("Video");
+
+/*
+ * Internal DMA buffer management. Since the controller cannot do S/G I/O,
+ * we must have physically contiguous buffers to bring frames into.
+ * These parameters control how many buffers we use, whether we
+ * allocate them at load time (better chance of success, but nails down
+ * memory) or when somebody tries to use the camera (riskier), and,
+ * for load-time allocation, how big they should be.
+ *
+ * The controller can cycle through three buffers. We could use
+ * more by flipping pointers around, but it probably makes little
+ * sense.
+ */
+
+#define MAX_DMA_BUFS 3
+static int alloc_bufs_at_load = 0;
+module_param(alloc_bufs_at_load, bool, 0444);
+MODULE_PARM_DESC(alloc_bufs_at_load,
+ "Non-zero value causes DMA buffers to be allocated at module "
+ "load time. This increases the chances of successfully getting "
+ "those buffers, but at the cost of nailing down the memory from "
+ "the outset.");
+
+static int n_dma_bufs = 3;
+module_param(n_dma_bufs, uint, 0644);
+MODULE_PARM_DESC(n_dma_bufs,
+ "The number of DMA buffers to allocate. Can be either two "
+ "(saves memory, makes timing tighter) or three.");
+
+static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2; /* Worst case */
+module_param(dma_buf_size, uint, 0444);
+MODULE_PARM_DESC(dma_buf_size,
+ "The size of the allocated DMA buffers. If actual operating "
+ "parameters require larger buffers, an attempt to reallocate "
+ "will be made.");
+
+static int min_buffers = 1;
+module_param(min_buffers, uint, 0644);
+MODULE_PARM_DESC(min_buffers,
+ "The minimum number of streaming I/O buffers we are willing "
+ "to work with.");
+
+static int max_buffers = 10;
+module_param(max_buffers, uint, 0644);
+MODULE_PARM_DESC(max_buffers,
+ "The maximum number of streaming I/O buffers an application "
+ "will be allowed to allocate. These buffers are big and live "
+ "in vmalloc space.");
+
+static int flip = 0;
+module_param(flip, bool, 0444);
+MODULE_PARM_DESC(flip,
+ "If set, the sensor will be instructed to flip the image "
+ "vertically.");
+
+
+enum cafe_state {
+ S_NOTREADY, /* Not yet initialized */
+ S_IDLE, /* Just hanging around */
+ S_FLAKED, /* Some sort of problem */
+ S_SINGLEREAD, /* In read() */
+ S_SPECREAD, /* Speculative read (for future read()) */
+ S_STREAMING /* Streaming data */
+};
+
+/*
+ * Tracking of streaming I/O buffers.
+ */
+struct cafe_sio_buffer {
+ struct list_head list;
+ struct v4l2_buffer v4lbuf;
+ char *buffer; /* Where it lives in kernel space */
+ int mapcount;
+ struct cafe_camera *cam;
+};
+
+/*
+ * A description of one of our devices.
+ * Locking: controlled by s_mutex. Certain fields, however, require
+ * the dev_lock spinlock; they are marked as such by comments.
+ * dev_lock is also required for access to device registers.
+ */
+struct cafe_camera
+{
+ enum cafe_state state;
+ unsigned long flags; /* Buffer status, mainly (dev_lock) */
+ int users; /* How many open FDs */
+ struct file *owner; /* Who has data access (v4l2) */
+
+ /*
+ * Subsystem structures.
+ */
+ struct pci_dev *pdev;
+ struct video_device v4ldev;
+ struct i2c_adapter i2c_adapter;
+ struct i2c_client *sensor;
+
+ unsigned char __iomem *regs;
+ struct list_head dev_list; /* link to other devices */
+
+ /* DMA buffers */
+ unsigned int nbufs; /* How many are alloc'd */
+ int next_buf; /* Next to consume (dev_lock) */
+ unsigned int dma_buf_size; /* allocated size */
+ void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */
+ dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
+ unsigned int specframes; /* Unconsumed spec frames (dev_lock) */
+ unsigned int sequence; /* Frame sequence number */
+ unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual buffers */
+
+ /* Streaming buffers */
+ unsigned int n_sbufs; /* How many we have */
+ struct cafe_sio_buffer *sb_bufs; /* The array of housekeeping structs */
+ struct list_head sb_avail; /* Available for data (we own) (dev_lock) */
+ struct list_head sb_full; /* With data (user space owns) (dev_lock) */
+ struct tasklet_struct s_tasklet;
+
+ /* Current operating parameters */
+ enum v4l2_chip_ident sensor_type; /* Currently ov7670 only */
+ struct v4l2_pix_format pix_format;
+
+ /* Locks */
+ struct mutex s_mutex; /* Access to this structure */
+ spinlock_t dev_lock; /* Access to device */
+
+ /* Misc */
+ wait_queue_head_t smbus_wait; /* Waiting on i2c events */
+ wait_queue_head_t iowait; /* Waiting on frame data */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ struct dentry *dfs_regs;
+ struct dentry *dfs_cam_regs;
+#endif
+};
+
+/*
+ * Status flags. Always manipulated with bit operations.
+ */
+#define CF_BUF0_VALID 0 /* Buffers valid - first three */
+#define CF_BUF1_VALID 1
+#define CF_BUF2_VALID 2
+#define CF_DMA_ACTIVE 3 /* A frame is incoming */
+#define CF_CONFIG_NEEDED 4 /* Must configure hardware */
+
+
+
+/*
+ * Start over with DMA buffers - dev_lock needed.
+ */
+static void cafe_reset_buffers(struct cafe_camera *cam)
+{
+ int i;
+
+ cam->next_buf = -1;
+ for (i = 0; i < cam->nbufs; i++)
+ clear_bit(i, &cam->flags);
+ cam->specframes = 0;
+}
+
+static inline int cafe_needs_config(struct cafe_camera *cam)
+{
+ return test_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+static void cafe_set_config_needed(struct cafe_camera *cam, int needed)
+{
+ if (needed)
+ set_bit(CF_CONFIG_NEEDED, &cam->flags);
+ else
+ clear_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+
+
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+ dev_err(&(cam)->pdev->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+ dev_warn(&(cam)->pdev->dev, fmt, ##arg);
+#define cam_dbg(cam, fmt, arg...) \
+ dev_dbg(&(cam)->pdev->dev, fmt, ##arg);
+
+
+/* ---------------------------------------------------------------------*/
+/*
+ * We keep a simple list of known devices to search at open time.
+ */
+static LIST_HEAD(cafe_dev_list);
+static DEFINE_MUTEX(cafe_dev_list_lock);
+
+static void cafe_add_dev(struct cafe_camera *cam)
+{
+ mutex_lock(&cafe_dev_list_lock);
+ list_add_tail(&cam->dev_list, &cafe_dev_list);
+ mutex_unlock(&cafe_dev_list_lock);
+}
+
+static void cafe_remove_dev(struct cafe_camera *cam)
+{
+ mutex_lock(&cafe_dev_list_lock);
+ list_del(&cam->dev_list);
+ mutex_unlock(&cafe_dev_list_lock);
+}
+
+static struct cafe_camera *cafe_find_dev(int minor)
+{
+ struct cafe_camera *cam;
+
+ mutex_lock(&cafe_dev_list_lock);
+ list_for_each_entry(cam, &cafe_dev_list, dev_list) {
+ if (cam->v4ldev.minor == minor)
+ goto done;
+ }
+ cam = NULL;
+ done:
+ mutex_unlock(&cafe_dev_list_lock);
+ return cam;
+}
+
+
+static struct cafe_camera *cafe_find_by_pdev(struct pci_dev *pdev)
+{
+ struct cafe_camera *cam;
+
+ mutex_lock(&cafe_dev_list_lock);
+ list_for_each_entry(cam, &cafe_dev_list, dev_list) {
+ if (cam->pdev == pdev)
+ goto done;
+ }
+ cam = NULL;
+ done:
+ mutex_unlock(&cafe_dev_list_lock);
+ return cam;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/*
+ * Device register I/O
+ */
+static inline void cafe_reg_write(struct cafe_camera *cam, unsigned int reg,
+ unsigned int val)
+{
+ iowrite32(val, cam->regs + reg);
+}
+
+static inline unsigned int cafe_reg_read(struct cafe_camera *cam,
+ unsigned int reg)
+{
+ return ioread32(cam->regs + reg);
+}
+
+
+static inline void cafe_reg_write_mask(struct cafe_camera *cam, unsigned int reg,
+ unsigned int val, unsigned int mask)
+{
+ unsigned int v = cafe_reg_read(cam, reg);
+
+ v = (v & ~mask) | (val & mask);
+ cafe_reg_write(cam, reg, v);
+}
+
+static inline void cafe_reg_clear_bit(struct cafe_camera *cam,
+ unsigned int reg, unsigned int val)
+{
+ cafe_reg_write_mask(cam, reg, 0, val);
+}
+
+static inline void cafe_reg_set_bit(struct cafe_camera *cam,
+ unsigned int reg, unsigned int val)
+{
+ cafe_reg_write_mask(cam, reg, val, val);
+}
+
+
+
+/* -------------------------------------------------------------------- */
+/*
+ * The I2C/SMBUS interface to the camera itself starts here. The
+ * controller handles SMBUS itself, presenting a relatively simple register
+ * interface; all we have to do is to tell it where to route the data.
+ */
+#define CAFE_SMBUS_TIMEOUT (HZ) /* generous */
+
+static int cafe_smbus_write_done(struct cafe_camera *cam)
+{
+ unsigned long flags;
+ int c1;
+
+ /*
+ * We must delay after the interrupt, or the controller gets confused
+ * and never does give us good status. Fortunately, we don't do this
+ * often.
+ */
+ udelay(20);
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ c1 = cafe_reg_read(cam, REG_TWSIC1);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT;
+}
+
+static int cafe_smbus_write_data(struct cafe_camera *cam,
+ u16 addr, u8 command, u8 value)
+{
+ unsigned int rval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+ rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */
+ /*
+ * Marvell sez set clkdiv to all 1's for now.
+ */
+ rval |= TWSIC0_CLKDIV;
+ cafe_reg_write(cam, REG_TWSIC0, rval);
+ (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
+ rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+ cafe_reg_write(cam, REG_TWSIC1, rval);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ msleep(2); /* Required or things flake */
+
+ wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
+ CAFE_SMBUS_TIMEOUT);
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ rval = cafe_reg_read(cam, REG_TWSIC1);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+
+ if (rval & TWSIC1_WSTAT) {
+ cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr,
+ command, value);
+ return -EIO;
+ }
+ if (rval & TWSIC1_ERROR) {
+ cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr,
+ command, value);
+ return -EIO;
+ }
+ return 0;
+}
+
+
+
+static int cafe_smbus_read_done(struct cafe_camera *cam)
+{
+ unsigned long flags;
+ int c1;
+
+ /*
+ * We must delay after the interrupt, or the controller gets confused
+ * and never does give us good status. Fortunately, we don't do this
+ * often.
+ */
+ udelay(20);
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ c1 = cafe_reg_read(cam, REG_TWSIC1);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ return c1 & (TWSIC1_RVALID|TWSIC1_ERROR);
+}
+
+
+
+static int cafe_smbus_read_data(struct cafe_camera *cam,
+ u16 addr, u8 command, u8 *value)
+{
+ unsigned int rval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+ rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */
+ /*
+ * Marvel sez set clkdiv to all 1's for now.
+ */
+ rval |= TWSIC0_CLKDIV;
+ cafe_reg_write(cam, REG_TWSIC0, rval);
+ (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
+ rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+ cafe_reg_write(cam, REG_TWSIC1, rval);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+
+ wait_event_timeout(cam->smbus_wait,
+ cafe_smbus_read_done(cam), CAFE_SMBUS_TIMEOUT);
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ rval = cafe_reg_read(cam, REG_TWSIC1);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+
+ if (rval & TWSIC1_ERROR) {
+ cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command);
+ return -EIO;
+ }
+ if (! (rval & TWSIC1_RVALID)) {
+ cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr,
+ command);
+ return -EIO;
+ }
+ *value = rval & 0xff;
+ return 0;
+}
+
+/*
+ * Perform a transfer over SMBUS. This thing is called under
+ * the i2c bus lock, so we shouldn't race with ourselves...
+ */
+static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char rw, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ struct cafe_camera *cam = i2c_get_adapdata(adapter);
+ int ret = -EINVAL;
+
+ /*
+ * Refuse to talk to anything but OV cam chips. We should
+ * never even see an attempt to do so, but one never knows.
+ */
+ if (cam->sensor && addr != cam->sensor->addr) {
+ cam_err(cam, "funky smbus addr %d\n", addr);
+ return -EINVAL;
+ }
+ /*
+ * This interface would appear to only do byte data ops. OK
+ * it can do word too, but the cam chip has no use for that.
+ */
+ if (size != I2C_SMBUS_BYTE_DATA) {
+ cam_err(cam, "funky xfer size %d\n", size);
+ return -EINVAL;
+ }
+
+ if (rw == I2C_SMBUS_WRITE)
+ ret = cafe_smbus_write_data(cam, addr, command, data->byte);
+ else if (rw == I2C_SMBUS_READ)
+ ret = cafe_smbus_read_data(cam, addr, command, &data->byte);
+ return ret;
+}
+
+
+static void cafe_smbus_enable_irq(struct cafe_camera *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ cafe_reg_set_bit(cam, REG_IRQMASK, TWSIIRQS);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+static u32 cafe_smbus_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_READ_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
+}
+
+static struct i2c_algorithm cafe_smbus_algo = {
+ .smbus_xfer = cafe_smbus_xfer,
+ .functionality = cafe_smbus_func
+};
+
+/* Somebody is on the bus */
+static int cafe_cam_init(struct cafe_camera *cam);
+static void cafe_ctlr_stop_dma(struct cafe_camera *cam);
+static void cafe_ctlr_power_down(struct cafe_camera *cam);
+
+static int cafe_smbus_attach(struct i2c_client *client)
+{
+ struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
+
+ /*
+ * Don't talk to chips we don't recognize.
+ */
+ if (client->driver->id == I2C_DRIVERID_OV7670) {
+ cam->sensor = client;
+ return cafe_cam_init(cam);
+ }
+ return -EINVAL;
+}
+
+static int cafe_smbus_detach(struct i2c_client *client)
+{
+ struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
+
+ if (cam->sensor == client) {
+ cafe_ctlr_stop_dma(cam);
+ cafe_ctlr_power_down(cam);
+ cam_err(cam, "lost the sensor!\n");
+ cam->sensor = NULL; /* Bummer, no camera */
+ cam->state = S_NOTREADY;
+ }
+ return 0;
+}
+
+static int cafe_smbus_setup(struct cafe_camera *cam)
+{
+ struct i2c_adapter *adap = &cam->i2c_adapter;
+ int ret;
+
+ cafe_smbus_enable_irq(cam);
+ adap->id = I2C_HW_SMBUS_CAFE;
+ adap->class = I2C_CLASS_CAM_DIGITAL;
+ adap->owner = THIS_MODULE;
+ adap->client_register = cafe_smbus_attach;
+ adap->client_unregister = cafe_smbus_detach;
+ adap->algo = &cafe_smbus_algo;
+ strcpy(adap->name, "cafe_ccic");
+ i2c_set_adapdata(adap, cam);
+ ret = i2c_add_adapter(adap);
+ if (ret)
+ printk(KERN_ERR "Unable to register cafe i2c adapter\n");
+ return ret;
+}
+
+static void cafe_smbus_shutdown(struct cafe_camera *cam)
+{
+ i2c_del_adapter(&cam->i2c_adapter);
+}
+
+
+/* ------------------------------------------------------------------- */
+/*
+ * Deal with the controller.
+ */
+
+/*
+ * Do everything we think we need to have the interface operating
+ * according to the desired format.
+ */
+static void cafe_ctlr_dma(struct cafe_camera *cam)
+{
+ /*
+ * Store the first two Y buffers (we aren't supporting
+ * planar formats for now, so no UV bufs). Then either
+ * set the third if it exists, or tell the controller
+ * to just use two.
+ */
+ cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]);
+ cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]);
+ if (cam->nbufs > 2) {
+ cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]);
+ cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS);
+ }
+ else
+ cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
+ cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */
+}
+
+static void cafe_ctlr_image(struct cafe_camera *cam)
+{
+ int imgsz;
+ struct v4l2_pix_format *fmt = &cam->pix_format;
+
+ imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
+ (fmt->bytesperline & IMGSZ_H_MASK);
+ cafe_reg_write(cam, REG_IMGSIZE, imgsz);
+ cafe_reg_write(cam, REG_IMGOFFSET, 0);
+ /* YPITCH just drops the last two bits */
+ cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline,
+ IMGP_YP_MASK);
+ /*
+ * Tell the controller about the image format we are using.
+ */
+ switch (cam->pix_format.pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ cafe_reg_write_mask(cam, REG_CTRL0,
+ C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV,
+ C0_DF_MASK);
+ break;
+
+ case V4L2_PIX_FMT_RGB444:
+ cafe_reg_write_mask(cam, REG_CTRL0,
+ C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
+ C0_DF_MASK);
+ /* Alpha value? */
+ break;
+
+ case V4L2_PIX_FMT_RGB565:
+ cafe_reg_write_mask(cam, REG_CTRL0,
+ C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR,
+ C0_DF_MASK);
+ break;
+
+ default:
+ cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat);
+ break;
+ }
+ /*
+ * Make sure it knows we want to use hsync/vsync.
+ */
+ cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC,
+ C0_SIFM_MASK);
+}
+
+
+/*
+ * Configure the controller for operation; caller holds the
+ * device mutex.
+ */
+static int cafe_ctlr_configure(struct cafe_camera *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ cafe_ctlr_dma(cam);
+ cafe_ctlr_image(cam);
+ cafe_set_config_needed(cam, 0);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ return 0;
+}
+
+static void cafe_ctlr_irq_enable(struct cafe_camera *cam)
+{
+ /*
+ * Clear any pending interrupts, since we do not
+ * expect to have I/O active prior to enabling.
+ */
+ cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS);
+ cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+static void cafe_ctlr_irq_disable(struct cafe_camera *cam)
+{
+ cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+/*
+ * Make the controller start grabbing images. Everything must
+ * be set up before doing this.
+ */
+static void cafe_ctlr_start(struct cafe_camera *cam)
+{
+ /* set_bit performs a read, so no other barrier should be
+ needed here */
+ cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+static void cafe_ctlr_stop(struct cafe_camera *cam)
+{
+ cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+static void cafe_ctlr_init(struct cafe_camera *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ /*
+ * Added magic to bring up the hardware on the B-Test board
+ */
+ cafe_reg_write(cam, 0x3038, 0x8);
+ cafe_reg_write(cam, 0x315c, 0x80008);
+ /*
+ * Go through the dance needed to wake the device up.
+ * Note that these registers are global and shared
+ * with the NAND and SD devices. Interaction between the
+ * three still needs to be examined.
+ */
+ cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
+ cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
+ cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
+ mdelay(5); /* FIXME revisit this */
+ cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
+ cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN);
+ /*
+ * Make sure it's not powered down.
+ */
+ cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+ /*
+ * Turn off the enable bit. It sure should be off anyway,
+ * but it's good to be sure.
+ */
+ cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+ /*
+ * Mask all interrupts.
+ */
+ cafe_reg_write(cam, REG_IRQMASK, 0);
+ /*
+ * Clock the sensor appropriately. Controller clock should
+ * be 48MHz, sensor "typical" value is half that.
+ */
+ cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+/*
+ * Stop the controller, and don't return until we're really sure that no
+ * further DMA is going on.
+ */
+static void cafe_ctlr_stop_dma(struct cafe_camera *cam)
+{
+ unsigned long flags;
+
+ /*
+ * Theory: stop the camera controller (whether it is operating
+ * or not). Delay briefly just in case we race with the SOF
+ * interrupt, then wait until no DMA is active.
+ */
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ cafe_ctlr_stop(cam);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ mdelay(1);
+ wait_event_timeout(cam->iowait,
+ !test_bit(CF_DMA_ACTIVE, &cam->flags), HZ);
+ if (test_bit(CF_DMA_ACTIVE, &cam->flags))
+ cam_err(cam, "Timeout waiting for DMA to end\n");
+ /* This would be bad news - what now? */
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ cam->state = S_IDLE;
+ cafe_ctlr_irq_disable(cam);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+/*
+ * Power up and down.
+ */
+static void cafe_ctlr_power_up(struct cafe_camera *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+ /*
+ * Put the sensor into operational mode (assumes OLPC-style
+ * wiring). Control 0 is reset - set to 1 to operate.
+ * Control 1 is power down, set to 0 to operate.
+ */
+ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
+ mdelay(1); /* Marvell says 1ms will do it */
+ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
+ mdelay(1); /* Enough? */
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+static void cafe_ctlr_power_down(struct cafe_camera *cam)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
+ cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+/* -------------------------------------------------------------------- */
+/*
+ * Communications with the sensor.
+ */
+
+static int __cafe_cam_cmd(struct cafe_camera *cam, int cmd, void *arg)
+{
+ struct i2c_client *sc = cam->sensor;
+ int ret;
+
+ if (sc == NULL || sc->driver == NULL || sc->driver->command == NULL)
+ return -EINVAL;
+ ret = sc->driver->command(sc, cmd, arg);
+ if (ret == -EPERM) /* Unsupported command */
+ return 0;
+ return ret;
+}
+
+static int __cafe_cam_reset(struct cafe_camera *cam)
+{
+ int zero = 0;
+ return __cafe_cam_cmd(cam, VIDIOC_INT_RESET, &zero);
+}
+
+/*
+ * We have found the sensor on the i2c. Let's try to have a
+ * conversation.
+ */
+static int cafe_cam_init(struct cafe_camera *cam)
+{
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ if (cam->state != S_NOTREADY)
+ cam_warn(cam, "Cam init with device in funky state %d",
+ cam->state);
+ ret = __cafe_cam_reset(cam);
+ if (ret)
+ goto out;
+ ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type);
+ if (ret)
+ goto out;
+// if (cam->sensor->addr != OV7xx0_SID) {
+ if (cam->sensor_type != V4L2_IDENT_OV7670) {
+ cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr);
+ ret = -EINVAL;
+ goto out;
+ }
+/* Get/set parameters? */
+ ret = 0;
+ cam->state = S_IDLE;
+ out:
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+/*
+ * Configure the sensor to match the parameters we have. Caller should
+ * hold s_mutex
+ */
+static int cafe_cam_set_flip(struct cafe_camera *cam)
+{
+ struct v4l2_control ctrl;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_VFLIP;
+ ctrl.value = flip;
+ return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl);
+}
+
+
+static int cafe_cam_configure(struct cafe_camera *cam)
+{
+ struct v4l2_format fmt;
+ int ret, zero = 0;
+
+ if (cam->state != S_IDLE)
+ return -EINVAL;
+ fmt.fmt.pix = cam->pix_format;
+ ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero);
+ if (ret == 0)
+ ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt);
+ /*
+ * OV7670 does weird things if flip is set *before* format...
+ */
+ ret += cafe_cam_set_flip(cam);
+ return ret;
+}
+
+/* -------------------------------------------------------------------- */
+/*
+ * DMA buffer management. These functions need s_mutex held.
+ */
+
+/* FIXME: this is inefficient as hell, since dma_alloc_coherent just
+ * does a get_free_pages() call, and we waste a good chunk of an orderN
+ * allocation. Should try to allocate the whole set in one chunk.
+ */
+static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime)
+{
+ int i;
+
+ cafe_set_config_needed(cam, 1);
+ if (loadtime)
+ cam->dma_buf_size = dma_buf_size;
+ else
+ cam->dma_buf_size = cam->pix_format.sizeimage;
+ if (n_dma_bufs > 3)
+ n_dma_bufs = 3;
+
+ cam->nbufs = 0;
+ for (i = 0; i < n_dma_bufs; i++) {
+ cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev,
+ cam->dma_buf_size, cam->dma_handles + i,
+ GFP_KERNEL);
+ if (cam->dma_bufs[i] == NULL) {
+ cam_warn(cam, "Failed to allocate DMA buffer\n");
+ break;
+ }
+ /* For debug, remove eventually */
+ memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size);
+ (cam->nbufs)++;
+ }
+
+ switch (cam->nbufs) {
+ case 1:
+ dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
+ cam->dma_bufs[0], cam->dma_handles[0]);
+ cam->nbufs = 0;
+ case 0:
+ cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
+ return -ENOMEM;
+
+ case 2:
+ if (n_dma_bufs > 2)
+ cam_warn(cam, "Will limp along with only 2 buffers\n");
+ break;
+ }
+ return 0;
+}
+
+static void cafe_free_dma_bufs(struct cafe_camera *cam)
+{
+ int i;
+
+ for (i = 0; i < cam->nbufs; i++) {
+ dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
+ cam->dma_bufs[i], cam->dma_handles[i]);
+ cam->dma_bufs[i] = NULL;
+ }
+ cam->nbufs = 0;
+}
+
+
+
+
+
+/* ----------------------------------------------------------------------- */
+/*
+ * Here starts the V4L2 interface code.
+ */
+
+/*
+ * Read an image from the device.
+ */
+static ssize_t cafe_deliver_buffer(struct cafe_camera *cam,
+ char __user *buffer, size_t len, loff_t *pos)
+{
+ int bufno;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ if (cam->next_buf < 0) {
+ cam_err(cam, "deliver_buffer: No next buffer\n");
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ return -EIO;
+ }
+ bufno = cam->next_buf;
+ clear_bit(bufno, &cam->flags);
+ if (++(cam->next_buf) >= cam->nbufs)
+ cam->next_buf = 0;
+ if (! test_bit(cam->next_buf, &cam->flags))
+ cam->next_buf = -1;
+ cam->specframes = 0;
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+
+ if (len > cam->pix_format.sizeimage)
+ len = cam->pix_format.sizeimage;
+ if (copy_to_user(buffer, cam->dma_bufs[bufno], len))
+ return -EFAULT;
+ (*pos) += len;
+ return len;
+}
+
+/*
+ * Get everything ready, and start grabbing frames.
+ */
+static int cafe_read_setup(struct cafe_camera *cam, enum cafe_state state)
+{
+ int ret;
+ unsigned long flags;
+
+ /*
+ * Configuration. If we still don't have DMA buffers,
+ * make one last, desperate attempt.
+ */
+ if (cam->nbufs == 0)
+ if (cafe_alloc_dma_bufs(cam, 0))
+ return -ENOMEM;
+
+ if (cafe_needs_config(cam)) {
+ cafe_cam_configure(cam);
+ ret = cafe_ctlr_configure(cam);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Turn it loose.
+ */
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ cafe_reset_buffers(cam);
+ cafe_ctlr_irq_enable(cam);
+ cam->state = state;
+ cafe_ctlr_start(cam);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ return 0;
+}
+
+
+static ssize_t cafe_v4l_read(struct file *filp,
+ char __user *buffer, size_t len, loff_t *pos)
+{
+ struct cafe_camera *cam = filp->private_data;
+ int ret;
+
+ /*
+ * Perhaps we're in speculative read mode and already
+ * have data?
+ */
+ mutex_lock(&cam->s_mutex);
+ if (cam->state == S_SPECREAD) {
+ if (cam->next_buf >= 0) {
+ ret = cafe_deliver_buffer(cam, buffer, len, pos);
+ if (ret != 0)
+ goto out_unlock;
+ }
+ } else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) {
+ ret = -EIO;
+ goto out_unlock;
+ } else if (cam->state != S_IDLE) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
+ /*
+ * v4l2: multiple processes can open the device, but only
+ * one gets to grab data from it.
+ */
+ if (cam->owner && cam->owner != filp) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+ cam->owner = filp;
+
+ /*
+ * Do setup if need be.
+ */
+ if (cam->state != S_SPECREAD) {
+ ret = cafe_read_setup(cam, S_SINGLEREAD);
+ if (ret)
+ goto out_unlock;
+ }
+ /*
+ * Wait for something to happen. This should probably
+ * be interruptible (FIXME).
+ */
+ wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ);
+ if (cam->next_buf < 0) {
+ cam_err(cam, "read() operation timed out\n");
+ cafe_ctlr_stop_dma(cam);
+ ret = -EIO;
+ goto out_unlock;
+ }
+ /*
+ * Give them their data and we should be done.
+ */
+ ret = cafe_deliver_buffer(cam, buffer, len, pos);
+
+ out_unlock:
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+
+
+
+
+
+
+
+/*
+ * Streaming I/O support.
+ */
+
+
+
+static int cafe_vidioc_streamon(struct file *filp, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cafe_camera *cam = filp->private_data;
+ int ret = -EINVAL;
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ goto out;
+ mutex_lock(&cam->s_mutex);
+ if (cam->state != S_IDLE || cam->n_sbufs == 0)
+ goto out_unlock;
+
+ cam->sequence = 0;
+ ret = cafe_read_setup(cam, S_STREAMING);
+
+ out_unlock:
+ mutex_unlock(&cam->s_mutex);
+ out:
+ return ret;
+}
+
+
+static int cafe_vidioc_streamoff(struct file *filp, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cafe_camera *cam = filp->private_data;
+ int ret = -EINVAL;
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ goto out;
+ mutex_lock(&cam->s_mutex);
+ if (cam->state != S_STREAMING)
+ goto out_unlock;
+
+ cafe_ctlr_stop_dma(cam);
+ ret = 0;
+
+ out_unlock:
+ mutex_unlock(&cam->s_mutex);
+ out:
+ return ret;
+}
+
+
+
+static int cafe_setup_siobuf(struct cafe_camera *cam, int index)
+{
+ struct cafe_sio_buffer *buf = cam->sb_bufs + index;
+
+ INIT_LIST_HEAD(&buf->list);
+ buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage);
+ buf->buffer = vmalloc_user(buf->v4lbuf.length);
+ if (buf->buffer == NULL)
+ return -ENOMEM;
+ buf->mapcount = 0;
+ buf->cam = cam;
+
+ buf->v4lbuf.index = index;
+ buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf->v4lbuf.field = V4L2_FIELD_NONE;
+ buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
+ /*
+ * Offset: must be 32-bit even on a 64-bit system. video-buf
+ * just uses the length times the index, but the spec warns
+ * against doing just that - vma merging problems. So we
+ * leave a gap between each pair of buffers.
+ */
+ buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
+ return 0;
+}
+
+static int cafe_free_sio_buffers(struct cafe_camera *cam)
+{
+ int i;
+
+ /*
+ * If any buffers are mapped, we cannot free them at all.
+ */
+ for (i = 0; i < cam->n_sbufs; i++)
+ if (cam->sb_bufs[i].mapcount > 0)
+ return -EBUSY;
+ /*
+ * OK, let's do it.
+ */
+ for (i = 0; i < cam->n_sbufs; i++)
+ vfree(cam->sb_bufs[i].buffer);
+ cam->n_sbufs = 0;
+ kfree(cam->sb_bufs);
+ cam->sb_bufs = NULL;
+ INIT_LIST_HEAD(&cam->sb_avail);
+ INIT_LIST_HEAD(&cam->sb_full);
+ return 0;
+}
+
+
+
+static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
+ struct v4l2_requestbuffers *req)
+{
+ struct cafe_camera *cam = filp->private_data;
+ int ret;
+
+ /*
+ * Make sure it's something we can do. User pointers could be
+ * implemented without great pain, but that's not been done yet.
+ */
+ if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (req->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+ /*
+ * If they ask for zero buffers, they really want us to stop streaming
+ * (if it's happening) and free everything. Should we check owner?
+ */
+ mutex_lock(&cam->s_mutex);
+ if (req->count == 0) {
+ if (cam->state == S_STREAMING)
+ cafe_ctlr_stop_dma(cam);
+ ret = cafe_free_sio_buffers (cam);
+ goto out;
+ }
+ /*
+ * Device needs to be idle and working. We *could* try to do the
+ * right thing in S_SPECREAD by shutting things down, but it
+ * probably doesn't matter.
+ */
+ if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ cam->owner = filp;
+
+ if (req->count < min_buffers)
+ req->count = min_buffers;
+ else if (req->count > max_buffers)
+ req->count = max_buffers;
+ if (cam->n_sbufs > 0) {
+ ret = cafe_free_sio_buffers(cam);
+ if (ret)
+ goto out;
+ }
+
+ cam->sb_bufs = kzalloc(req->count*sizeof(struct cafe_sio_buffer),
+ GFP_KERNEL);
+ if (cam->sb_bufs == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) {
+ ret = cafe_setup_siobuf(cam, cam->n_sbufs);
+ if (ret)
+ break;
+ }
+
+ if (cam->n_sbufs == 0) /* no luck at all - ret already set */
+ kfree(cam->sb_bufs);
+ else
+ ret = 0;
+ req->count = cam->n_sbufs; /* In case of partial success */
+
+ out:
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+
+static int cafe_vidioc_querybuf(struct file *filp, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct cafe_camera *cam = filp->private_data;
+ int ret = -EINVAL;
+
+ mutex_lock(&cam->s_mutex);
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ goto out;
+ if (buf->index < 0 || buf->index >= cam->n_sbufs)
+ goto out;
+ *buf = cam->sb_bufs[buf->index].v4lbuf;
+ ret = 0;
+ out:
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+static int cafe_vidioc_qbuf(struct file *filp, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct cafe_camera *cam = filp->private_data;
+ struct cafe_sio_buffer *sbuf;
+ int ret = -EINVAL;
+ unsigned long flags;
+
+ mutex_lock(&cam->s_mutex);
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ goto out;
+ if (buf->index < 0 || buf->index >= cam->n_sbufs)
+ goto out;
+ sbuf = cam->sb_bufs + buf->index;
+ if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) {
+ ret = 0; /* Already queued?? */
+ goto out;
+ }
+ if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) {
+ /* Spec doesn't say anything, seems appropriate tho */
+ ret = -EBUSY;
+ goto out;
+ }
+ sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ list_add(&sbuf->list, &cam->sb_avail);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ ret = 0;
+ out:
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+static int cafe_vidioc_dqbuf(struct file *filp, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct cafe_camera *cam = filp->private_data;
+ struct cafe_sio_buffer *sbuf;
+ int ret = -EINVAL;
+ unsigned long flags;
+
+ mutex_lock(&cam->s_mutex);
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ goto out_unlock;
+ if (cam->state != S_STREAMING)
+ goto out_unlock;
+ if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+
+ while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) {
+ mutex_unlock(&cam->s_mutex);
+ if (wait_event_interruptible(cam->iowait,
+ !list_empty(&cam->sb_full))) {
+ ret = -ERESTARTSYS;
+ goto out;
+ }
+ mutex_lock(&cam->s_mutex);
+ }
+
+ if (cam->state != S_STREAMING)
+ ret = -EINTR;
+ else {
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ /* Should probably recheck !list_empty() here */
+ sbuf = list_entry(cam->sb_full.next,
+ struct cafe_sio_buffer, list);
+ list_del_init(&sbuf->list);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
+ *buf = sbuf->v4lbuf;
+ ret = 0;
+ }
+
+ out_unlock:
+ mutex_unlock(&cam->s_mutex);
+ out:
+ return ret;
+}
+
+
+
+static void cafe_v4l_vm_open(struct vm_area_struct *vma)
+{
+ struct cafe_sio_buffer *sbuf = vma->vm_private_data;
+ /*
+ * Locking: done under mmap_sem, so we don't need to
+ * go back to the camera lock here.
+ */
+ sbuf->mapcount++;
+}
+
+
+static void cafe_v4l_vm_close(struct vm_area_struct *vma)
+{
+ struct cafe_sio_buffer *sbuf = vma->vm_private_data;
+
+ mutex_lock(&sbuf->cam->s_mutex);
+ sbuf->mapcount--;
+ /* Docs say we should stop I/O too... */
+ if (sbuf->mapcount == 0)
+ sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
+ mutex_unlock(&sbuf->cam->s_mutex);
+}
+
+static struct vm_operations_struct cafe_v4l_vm_ops = {
+ .open = cafe_v4l_vm_open,
+ .close = cafe_v4l_vm_close
+};
+
+
+static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct cafe_camera *cam = filp->private_data;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ int ret = -EINVAL;
+ int i;
+ struct cafe_sio_buffer *sbuf = NULL;
+
+ if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+ /*
+ * Find the buffer they are looking for.
+ */
+ mutex_lock(&cam->s_mutex);
+ for (i = 0; i < cam->n_sbufs; i++)
+ if (cam->sb_bufs[i].v4lbuf.m.offset == offset) {
+ sbuf = cam->sb_bufs + i;
+ break;
+ }
+ if (sbuf == NULL)
+ goto out;
+
+ ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
+ if (ret)
+ goto out;
+ vma->vm_flags |= VM_DONTEXPAND;
+ vma->vm_private_data = sbuf;
+ vma->vm_ops = &cafe_v4l_vm_ops;
+ sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
+ cafe_v4l_vm_open(vma);
+ ret = 0;
+ out:
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+
+
+static int cafe_v4l_open(struct inode *inode, struct file *filp)
+{
+ struct cafe_camera *cam;
+
+ cam = cafe_find_dev(iminor(inode));
+ if (cam == NULL)
+ return -ENODEV;
+ filp->private_data = cam;
+
+ mutex_lock(&cam->s_mutex);
+ if (cam->users == 0) {
+ cafe_ctlr_power_up(cam);
+ __cafe_cam_reset(cam);
+ cafe_set_config_needed(cam, 1);
+ /* FIXME make sure this is complete */
+ }
+ (cam->users)++;
+ mutex_unlock(&cam->s_mutex);
+ return 0;
+}
+
+
+static int cafe_v4l_release(struct inode *inode, struct file *filp)
+{
+ struct cafe_camera *cam = filp->private_data;
+
+ mutex_lock(&cam->s_mutex);
+ (cam->users)--;
+ if (filp == cam->owner) {
+ cafe_ctlr_stop_dma(cam);
+ cafe_free_sio_buffers(cam);
+ cam->owner = NULL;
+ }
+ if (cam->users == 0) {
+ cafe_ctlr_power_down(cam);
+ if (! alloc_bufs_at_load)
+ cafe_free_dma_bufs(cam);
+ }
+ mutex_unlock(&cam->s_mutex);
+ return 0;
+}
+
+
+
+static unsigned int cafe_v4l_poll(struct file *filp,
+ struct poll_table_struct *pt)
+{
+ struct cafe_camera *cam = filp->private_data;
+
+ poll_wait(filp, &cam->iowait, pt);
+ if (cam->next_buf >= 0)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+
+
+static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct cafe_camera *cam = filp->private_data;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+
+static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct cafe_camera *cam = filp->private_data;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+
+static int cafe_vidioc_s_ctrl(struct file *filp, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct cafe_camera *cam = filp->private_data;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+
+
+
+
+static int cafe_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strcpy(cap->driver, "cafe_ccic");
+ strcpy(cap->card, "cafe_ccic");
+ cap->version = CAFE_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ return 0;
+}
+
+
+/*
+ * The default format we use until somebody says otherwise.
+ */
+static struct v4l2_pix_format cafe_def_pix_format = {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .field = V4L2_FIELD_NONE,
+ .bytesperline = VGA_WIDTH*2,
+ .sizeimage = VGA_WIDTH*VGA_HEIGHT*2,
+};
+
+static int cafe_vidioc_enum_fmt_cap(struct file *filp,
+ void *priv, struct v4l2_fmtdesc *fmt)
+{
+ struct cafe_camera *cam = priv;
+ int ret;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ mutex_lock(&cam->s_mutex);
+ ret = __cafe_cam_cmd(cam, VIDIOC_ENUM_FMT, fmt);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+
+static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct cafe_camera *cam = priv;
+ int ret;
+
+ /*
+ * Can't do anything if the device is not idle
+ * Also can't if there are streaming buffers in place.
+ */
+ if (cam->state != S_IDLE || cam->n_sbufs > 0)
+ return -EBUSY;
+ /*
+ * See if the formatting works in principle.
+ */
+ ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt);
+ if (ret)
+ return ret;
+ /*
+ * Now we start to change things for real, so let's do it
+ * under lock.
+ */
+ mutex_lock(&cam->s_mutex);
+ cam->pix_format = fmt->fmt.pix;
+ /*
+ * Make sure we have appropriate DMA buffers.
+ */
+ ret = -ENOMEM;
+ if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage)
+ cafe_free_dma_bufs(cam);
+ if (cam->nbufs == 0) {
+ if (cafe_alloc_dma_bufs(cam, 0))
+ goto out;
+ }
+ /*
+ * It looks like this might work, so let's program the sensor.
+ */
+ ret = cafe_cam_configure(cam);
+ if (! ret)
+ ret = cafe_ctlr_configure(cam);
+ out:
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+/*
+ * Return our stored notion of how the camera is/should be configured.
+ * The V4l2 spec wants us to be smarter, and actually get this from
+ * the camera (and not mess with it at open time). Someday.
+ */
+static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv,
+ struct v4l2_format *f)
+{
+ struct cafe_camera *cam = priv;
+
+ f->fmt.pix = cam->pix_format;
+ return 0;
+}
+
+/*
+ * We only have one input - the sensor - so minimize the nonsense here.
+ */
+static int cafe_vidioc_enum_input(struct file *filp, void *priv,
+ struct v4l2_input *input)
+{
+ if (input->index != 0)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ input->std = V4L2_STD_ALL; /* Not sure what should go here */
+ strcpy(input->name, "Camera");
+ return 0;
+}
+
+static int cafe_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
+ return 0;
+}
+
+/* from vivi.c */
+static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
+{
+ return 0;
+}
+
+/*
+ * G/S_PARM. Most of this is done by the sensor, but we are
+ * the level which controls the number of read buffers.
+ */
+static int cafe_vidioc_g_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parms)
+{
+ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms);
+ mutex_unlock(&cam->s_mutex);
+ parms->parm.capture.readbuffers = n_dma_bufs;
+ return ret;
+}
+
+static int cafe_vidioc_s_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parms)
+{
+ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms);
+ mutex_unlock(&cam->s_mutex);
+ parms->parm.capture.readbuffers = n_dma_bufs;
+ return ret;
+}
+
+
+static void cafe_v4l_dev_release(struct video_device *vd)
+{
+ struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);
+
+ kfree(cam);
+}
+
+
+/*
+ * This template device holds all of those v4l2 methods; we
+ * clone it for specific real devices.
+ */
+
+static struct file_operations cafe_v4l_fops = {
+ .owner = THIS_MODULE,
+ .open = cafe_v4l_open,
+ .release = cafe_v4l_release,
+ .read = cafe_v4l_read,
+ .poll = cafe_v4l_poll,
+ .mmap = cafe_v4l_mmap,
+ .ioctl = video_ioctl2,
+ .llseek = no_llseek,
+};
+
+static struct video_device cafe_v4l_template = {
+ .name = "cafe",
+ .type = VFL_TYPE_GRABBER,
+ .type2 = VID_TYPE_CAPTURE,
+ .minor = -1, /* Get one dynamically */
+ .tvnorms = V4L2_STD_NTSC_M,
+ .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */
+
+ .fops = &cafe_v4l_fops,
+ .release = cafe_v4l_dev_release,
+
+ .vidioc_querycap = cafe_vidioc_querycap,
+ .vidioc_enum_fmt_cap = cafe_vidioc_enum_fmt_cap,
+ .vidioc_try_fmt_cap = cafe_vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = cafe_vidioc_s_fmt_cap,
+ .vidioc_g_fmt_cap = cafe_vidioc_g_fmt_cap,
+ .vidioc_enum_input = cafe_vidioc_enum_input,
+ .vidioc_g_input = cafe_vidioc_g_input,
+ .vidioc_s_input = cafe_vidioc_s_input,
+ .vidioc_s_std = cafe_vidioc_s_std,
+ .vidioc_reqbufs = cafe_vidioc_reqbufs,
+ .vidioc_querybuf = cafe_vidioc_querybuf,
+ .vidioc_qbuf = cafe_vidioc_qbuf,
+ .vidioc_dqbuf = cafe_vidioc_dqbuf,
+ .vidioc_streamon = cafe_vidioc_streamon,
+ .vidioc_streamoff = cafe_vidioc_streamoff,
+ .vidioc_queryctrl = cafe_vidioc_queryctrl,
+ .vidioc_g_ctrl = cafe_vidioc_g_ctrl,
+ .vidioc_s_ctrl = cafe_vidioc_s_ctrl,
+ .vidioc_g_parm = cafe_vidioc_g_parm,
+ .vidioc_s_parm = cafe_vidioc_s_parm,
+};
+
+
+
+
+
+
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Interrupt handler stuff
+ */
+
+
+
+static void cafe_frame_tasklet(unsigned long data)
+{
+ struct cafe_camera *cam = (struct cafe_camera *) data;
+ int i;
+ unsigned long flags;
+ struct cafe_sio_buffer *sbuf;
+
+ spin_lock_irqsave(&cam->dev_lock, flags);
+ for (i = 0; i < cam->nbufs; i++) {
+ int bufno = cam->next_buf;
+ if (bufno < 0) { /* "will never happen" */
+ cam_err(cam, "No valid bufs in tasklet!\n");
+ break;
+ }
+ if (++(cam->next_buf) >= cam->nbufs)
+ cam->next_buf = 0;
+ if (! test_bit(bufno, &cam->flags))
+ continue;
+ if (list_empty(&cam->sb_avail))
+ break; /* Leave it valid, hope for better later */
+ clear_bit(bufno, &cam->flags);
+ /*
+ * We could perhaps drop the spinlock during this
+ * big copy. Something to consider.
+ */
+ sbuf = list_entry(cam->sb_avail.next,
+ struct cafe_sio_buffer, list);
+ memcpy(sbuf->buffer, cam->dma_bufs[bufno],
+ cam->pix_format.sizeimage);
+ sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage;
+ sbuf->v4lbuf.sequence = cam->buf_seq[bufno];
+ sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
+ sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
+ list_move_tail(&sbuf->list, &cam->sb_full);
+ }
+ if (! list_empty(&cam->sb_full))
+ wake_up(&cam->iowait);
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+
+static void cafe_frame_complete(struct cafe_camera *cam, int frame)
+{
+ /*
+ * Basic frame housekeeping.
+ */
+ if (test_bit(frame, &cam->flags) && printk_ratelimit())
+ cam_err(cam, "Frame overrun on %d, frames lost\n", frame);
+ set_bit(frame, &cam->flags);
+ clear_bit(CF_DMA_ACTIVE, &cam->flags);
+ if (cam->next_buf < 0)
+ cam->next_buf = frame;
+ cam->buf_seq[frame] = ++(cam->sequence);
+
+ switch (cam->state) {
+ /*
+ * If in single read mode, try going speculative.
+ */
+ case S_SINGLEREAD:
+ cam->state = S_SPECREAD;
+ cam->specframes = 0;
+ wake_up(&cam->iowait);
+ break;
+
+ /*
+ * If we are already doing speculative reads, and nobody is
+ * reading them, just stop.
+ */
+ case S_SPECREAD:
+ if (++(cam->specframes) >= cam->nbufs) {
+ cafe_ctlr_stop(cam);
+ cafe_ctlr_irq_disable(cam);
+ cam->state = S_IDLE;
+ }
+ wake_up(&cam->iowait);
+ break;
+ /*
+ * For the streaming case, we defer the real work to the
+ * camera tasklet.
+ *
+ * FIXME: if the application is not consuming the buffers,
+ * we should eventually put things on hold and restart in
+ * vidioc_dqbuf().
+ */
+ case S_STREAMING:
+ tasklet_schedule(&cam->s_tasklet);
+ break;
+
+ default:
+ cam_err(cam, "Frame interrupt in non-operational state\n");
+ break;
+ }
+}
+
+
+
+
+static void cafe_frame_irq(struct cafe_camera *cam, unsigned int irqs)
+{
+ unsigned int frame;
+
+ cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */
+ /*
+ * Handle any frame completions. There really should
+ * not be more than one of these, or we have fallen
+ * far behind.
+ */
+ for (frame = 0; frame < cam->nbufs; frame++)
+ if (irqs & (IRQ_EOF0 << frame))
+ cafe_frame_complete(cam, frame);
+ /*
+ * If a frame starts, note that we have DMA active. This
+ * code assumes that we won't get multiple frame interrupts
+ * at once; may want to rethink that.
+ */
+ if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2))
+ set_bit(CF_DMA_ACTIVE, &cam->flags);
+}
+
+
+
+static irqreturn_t cafe_irq(int irq, void *data)
+{
+ struct cafe_camera *cam = data;
+ unsigned int irqs;
+
+ spin_lock(&cam->dev_lock);
+ irqs = cafe_reg_read(cam, REG_IRQSTAT);
+ if ((irqs & ALLIRQS) == 0) {
+ spin_unlock(&cam->dev_lock);
+ return IRQ_NONE;
+ }
+ if (irqs & FRAMEIRQS)
+ cafe_frame_irq(cam, irqs);
+ if (irqs & TWSIIRQS) {
+ cafe_reg_write(cam, REG_IRQSTAT, TWSIIRQS);
+ wake_up(&cam->smbus_wait);
+ }
+ spin_unlock(&cam->dev_lock);
+ return IRQ_HANDLED;
+}
+
+
+/* -------------------------------------------------------------------------- */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * Debugfs stuff.
+ */
+
+static char cafe_debug_buf[1024];
+static struct dentry *cafe_dfs_root;
+
+static void cafe_dfs_setup(void)
+{
+ cafe_dfs_root = debugfs_create_dir("cafe_ccic", NULL);
+ if (IS_ERR(cafe_dfs_root)) {
+ cafe_dfs_root = NULL; /* Never mind */
+ printk(KERN_NOTICE "cafe_ccic unable to set up debugfs\n");
+ }
+}
+
+static void cafe_dfs_shutdown(void)
+{
+ if (cafe_dfs_root)
+ debugfs_remove(cafe_dfs_root);
+}
+
+static int cafe_dfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t cafe_dfs_read_regs(struct file *file,
+ char __user *buf, size_t count, loff_t *ppos)
+{
+ struct cafe_camera *cam = file->private_data;
+ char *s = cafe_debug_buf;
+ int offset;
+
+ for (offset = 0; offset < 0x44; offset += 4)
+ s += sprintf(s, "%02x: %08x\n", offset,
+ cafe_reg_read(cam, offset));
+ for (offset = 0x88; offset <= 0x90; offset += 4)
+ s += sprintf(s, "%02x: %08x\n", offset,
+ cafe_reg_read(cam, offset));
+ for (offset = 0xb4; offset <= 0xbc; offset += 4)
+ s += sprintf(s, "%02x: %08x\n", offset,
+ cafe_reg_read(cam, offset));
+ for (offset = 0x3000; offset <= 0x300c; offset += 4)
+ s += sprintf(s, "%04x: %08x\n", offset,
+ cafe_reg_read(cam, offset));
+ return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
+ s - cafe_debug_buf);
+}
+
+static struct file_operations cafe_dfs_reg_ops = {
+ .owner = THIS_MODULE,
+ .read = cafe_dfs_read_regs,
+ .open = cafe_dfs_open
+};
+
+static ssize_t cafe_dfs_read_cam(struct file *file,
+ char __user *buf, size_t count, loff_t *ppos)
+{
+ struct cafe_camera *cam = file->private_data;
+ char *s = cafe_debug_buf;
+ int offset;
+
+ if (! cam->sensor)
+ return -EINVAL;
+ for (offset = 0x0; offset < 0x8a; offset++)
+ {
+ u8 v;
+
+ cafe_smbus_read_data(cam, cam->sensor->addr, offset, &v);
+ s += sprintf(s, "%02x: %02x\n", offset, v);
+ }
+ return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
+ s - cafe_debug_buf);
+}
+
+static struct file_operations cafe_dfs_cam_ops = {
+ .owner = THIS_MODULE,
+ .read = cafe_dfs_read_cam,
+ .open = cafe_dfs_open
+};
+
+
+
+static void cafe_dfs_cam_setup(struct cafe_camera *cam)
+{
+ char fname[40];
+
+ if (!cafe_dfs_root)
+ return;
+ sprintf(fname, "regs-%d", cam->v4ldev.minor);
+ cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
+ cam, &cafe_dfs_reg_ops);
+ sprintf(fname, "cam-%d", cam->v4ldev.minor);
+ cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
+ cam, &cafe_dfs_cam_ops);
+}
+
+
+static void cafe_dfs_cam_shutdown(struct cafe_camera *cam)
+{
+ if (! IS_ERR(cam->dfs_regs))
+ debugfs_remove(cam->dfs_regs);
+ if (! IS_ERR(cam->dfs_cam_regs))
+ debugfs_remove(cam->dfs_cam_regs);
+}
+
+#else
+
+#define cafe_dfs_setup()
+#define cafe_dfs_shutdown()
+#define cafe_dfs_cam_setup(cam)
+#define cafe_dfs_cam_shutdown(cam)
+#endif /* CONFIG_VIDEO_ADV_DEBUG */
+
+
+
+
+/* ------------------------------------------------------------------------*/
+/*
+ * PCI interface stuff.
+ */
+
+static int cafe_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int ret;
+ u16 classword;
+ struct cafe_camera *cam;
+ /*
+ * Make sure we have a camera here - we'll get calls for
+ * the other cafe devices as well.
+ */
+ pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword);
+ if (classword != PCI_CLASS_MULTIMEDIA_VIDEO)
+ return -ENODEV;
+ /*
+ * Start putting together one of our big camera structures.
+ */
+ ret = -ENOMEM;
+ cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
+ if (cam == NULL)
+ goto out;
+ mutex_init(&cam->s_mutex);
+ mutex_lock(&cam->s_mutex);
+ spin_lock_init(&cam->dev_lock);
+ cam->state = S_NOTREADY;
+ cafe_set_config_needed(cam, 1);
+ init_waitqueue_head(&cam->smbus_wait);
+ init_waitqueue_head(&cam->iowait);
+ cam->pdev = pdev;
+ cam->pix_format = cafe_def_pix_format;
+ INIT_LIST_HEAD(&cam->dev_list);
+ INIT_LIST_HEAD(&cam->sb_avail);
+ INIT_LIST_HEAD(&cam->sb_full);
+ tasklet_init(&cam->s_tasklet, cafe_frame_tasklet, (unsigned long) cam);
+ /*
+ * Get set up on the PCI bus.
+ */
+ ret = pci_enable_device(pdev);
+ if (ret)
+ goto out_free;
+ pci_set_master(pdev);
+
+ ret = -EIO;
+ cam->regs = pci_iomap(pdev, 0, 0);
+ if (! cam->regs) {
+ printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
+ goto out_free;
+ }
+ ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
+ if (ret)
+ goto out_iounmap;
+ cafe_ctlr_init(cam);
+ cafe_ctlr_power_up(cam);
+ /*
+ * Set up I2C/SMBUS communications
+ */
+ mutex_unlock(&cam->s_mutex); /* attach can deadlock */
+ ret = cafe_smbus_setup(cam);
+ if (ret)
+ goto out_freeirq;
+ /*
+ * Get the v4l2 setup done.
+ */
+ mutex_lock(&cam->s_mutex);
+ cam->v4ldev = cafe_v4l_template;
+ cam->v4ldev.debug = 0;
+// cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG;
+ ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ goto out_smbus;
+ /*
+ * If so requested, try to get our DMA buffers now.
+ */
+ if (alloc_bufs_at_load) {
+ if (cafe_alloc_dma_bufs(cam, 1))
+ cam_warn(cam, "Unable to alloc DMA buffers at load"
+ " will try again later.");
+ }
+
+ cafe_dfs_cam_setup(cam);
+ mutex_unlock(&cam->s_mutex);
+ cafe_add_dev(cam);
+ return 0;
+
+ out_smbus:
+ cafe_smbus_shutdown(cam);
+ out_freeirq:
+ cafe_ctlr_power_down(cam);
+ free_irq(pdev->irq, cam);
+ out_iounmap:
+ pci_iounmap(pdev, cam->regs);
+ out_free:
+ kfree(cam);
+ out:
+ return ret;
+}
+
+
+/*
+ * Shut down an initialized device
+ */
+static void cafe_shutdown(struct cafe_camera *cam)
+{
+/* FIXME: Make sure we take care of everything here */
+ cafe_dfs_cam_shutdown(cam);
+ if (cam->n_sbufs > 0)
+ /* What if they are still mapped? Shouldn't be, but... */
+ cafe_free_sio_buffers(cam);
+ cafe_remove_dev(cam);
+ cafe_ctlr_stop_dma(cam);
+ cafe_ctlr_power_down(cam);
+ cafe_smbus_shutdown(cam);
+ cafe_free_dma_bufs(cam);
+ free_irq(cam->pdev->irq, cam);
+ pci_iounmap(cam->pdev, cam->regs);
+ video_unregister_device(&cam->v4ldev);
+ /* kfree(cam); done in v4l_release () */
+}
+
+
+static void cafe_pci_remove(struct pci_dev *pdev)
+{
+ struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+
+ if (cam == NULL) {
+ printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);
+ return;
+ }
+ mutex_lock(&cam->s_mutex);
+ if (cam->users > 0)
+ cam_warn(cam, "Removing a device with users!\n");
+ cafe_shutdown(cam);
+/* No unlock - it no longer exists */
+}
+
+
+
+
+static struct pci_device_id cafe_ids[] = {
+ { PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */
+ { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */
+ { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, cafe_ids);
+
+static struct pci_driver cafe_pci_driver = {
+ .name = "cafe1000-ccic",
+ .id_table = cafe_ids,
+ .probe = cafe_pci_probe,
+ .remove = cafe_pci_remove,
+};
+
+
+
+
+static int __init cafe_init(void)
+{
+ int ret;
+
+ printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
+ CAFE_VERSION);
+ cafe_dfs_setup();
+ ret = pci_register_driver(&cafe_pci_driver);
+ if (ret) {
+ printk(KERN_ERR "Unable to register cafe_ccic driver\n");
+ goto out;
+ }
+ request_module("ov7670"); /* FIXME want something more general */
+ ret = 0;
+
+ out:
+ return ret;
+}
+
+
+static void __exit cafe_exit(void)
+{
+ pci_unregister_driver(&cafe_pci_driver);
+ cafe_dfs_shutdown();
+}
+
+module_init(cafe_init);
+module_exit(cafe_exit);
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index d82a488f12a..f065ad12cc6 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -118,7 +118,7 @@ static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = file->f_op->unlocked_ioctl(file, cmd, arg);
else if (file->f_op->ioctl) {
lock_kernel();
- ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg);
+ ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
unlock_kernel();
}
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
index 28dc6a1a1e4..d8e929863a8 100644
--- a/drivers/media/video/cpia2/cpia2_usb.c
+++ b/drivers/media/video/cpia2/cpia2_usb.c
@@ -640,6 +640,10 @@ static int submit_urbs(struct camera_data *cam)
cam->sbuf[i].data =
kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
if (!cam->sbuf[i].data) {
+ while (--i >= 0) {
+ kfree(cam->sbuf[i].data);
+ cam->sbuf[i].data = NULL;
+ }
return -ENOMEM;
}
}
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index 657e0b96914..2f5ca71e026 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -742,7 +742,6 @@ 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;
@@ -752,20 +751,18 @@ 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;
+ }
+ if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
/* 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.
+ a ghosting effect). So if the capture window is scaled, then
+ force the filter to 0.
- For full resolution a setting of 8 really improves the video
+ For full resolution the filter 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;
- }
+ temporal = 0;
}
if (old == NULL || old->stream_type != new->stream_type) {
@@ -866,6 +863,7 @@ invalid:
void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
{
int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ int temporal = p->video_temporal_filter;
/* Stream */
printk(KERN_INFO "%s: Stream: %s\n",
@@ -922,10 +920,13 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
p->video_spatial_filter);
+ if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) {
+ temporal = 0;
+ }
printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
prefix,
cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
- p->video_temporal_filter);
+ temporal);
printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
prefix,
cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index f85f2084324..ced13febed8 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -128,7 +128,14 @@ void cx25840_vbi_setup(struct i2c_client *client)
uv_lpf=1;
src_decimation=0x21f;
- if (std == V4L2_STD_PAL_M) {
+ if (std == V4L2_STD_PAL_60) {
+ vblank=26;
+ vblank656=26;
+ burst=0x5b;
+ luma_lpf=2;
+ comb=0x20;
+ sc=0x0a8263;
+ } else if (std == V4L2_STD_PAL_M) {
vblank=20;
vblank656=24;
burst=0x61;
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 0f9d9696361..b2a66ba625f 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -53,6 +53,7 @@ config VIDEO_CX88_DVB
select DVB_OR51132 if !DVB_FE_CUSTOMISE
select DVB_CX22702 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_LGH06XF 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
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 46738321ada..0cf0360588e 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -50,7 +50,6 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
#define dprintk(level,fmt, arg...) if (debug >= level) \
printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg)
-static LIST_HEAD(cx8802_devlist);
/* ------------------------------------------------------------------ */
@@ -882,7 +881,7 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
BLACKBIRD_MPEG_CAPTURE,
BLACKBIRD_RAW_BITS_NONE);
- cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
+ cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
blackbird_initialize_codec(dev);
cx88_set_scale(dev->core, dev->width, dev->height,
@@ -914,11 +913,15 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
}
default:
- return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
+ return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
}
return 0;
}
+int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg);
+unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+
static unsigned int mpeg_translate_ioctl(unsigned int cmd)
{
return cmd;
@@ -927,33 +930,49 @@ static unsigned int mpeg_translate_ioctl(unsigned int cmd)
static int mpeg_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- cmd = mpeg_translate_ioctl( cmd );
- return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl);
+ cmd = cx88_ioctl_translator( cmd );
+ return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook);
}
static int mpeg_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct cx8802_dev *h,*dev = NULL;
+ struct cx8802_dev *dev = NULL;
struct cx8802_fh *fh;
- struct list_head *list;
+ struct cx8802_driver *drv = NULL;
+ int err;
- list_for_each(list,&cx8802_devlist) {
- h = list_entry(list, struct cx8802_dev, devlist);
- if (h->mpeg_dev->minor == minor)
- dev = h;
- }
- if (NULL == dev)
+ dev = cx8802_get_device(inode);
+
+ dprintk( 1, "%s\n", __FUNCTION__);
+
+ if (dev == NULL)
return -ENODEV;
- if (blackbird_initialize_codec(dev) < 0)
+ /* Make sure we can acquire the hardware */
+ drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
+ if (drv) {
+ err = drv->request_acquire(drv);
+ if(err != 0) {
+ dprintk(1,"%s: Unable to acquire hardware, %d\n", __FUNCTION__, err);
+ return err;
+ }
+ }
+
+ if (blackbird_initialize_codec(dev) < 0) {
+ if (drv)
+ drv->request_release(drv);
return -EINVAL;
+ }
dprintk(1,"open minor=%d\n",minor);
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
- if (NULL == fh)
+ if (NULL == fh) {
+ if (drv)
+ drv->request_release(drv);
return -ENOMEM;
+ }
file->private_data = fh;
fh->dev = dev;
@@ -974,6 +993,8 @@ static int mpeg_open(struct inode *inode, struct file *file)
static int mpeg_release(struct inode *inode, struct file *file)
{
struct cx8802_fh *fh = file->private_data;
+ struct cx8802_dev *dev = NULL;
+ struct cx8802_driver *drv = NULL;
/* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
@@ -992,6 +1013,16 @@ static int mpeg_release(struct inode *inode, struct file *file)
videobuf_mmap_free(&fh->mpegq);
file->private_data = NULL;
kfree(fh);
+
+ /* Make sure we release the hardware */
+ dev = cx8802_get_device(inode);
+ if (dev == NULL)
+ return -ENODEV;
+
+ drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
+ if (drv)
+ drv->request_release(drv);
+
return 0;
}
@@ -1043,6 +1074,44 @@ static struct video_device cx8802_mpeg_template =
/* ------------------------------------------------------------------ */
+/* The CX8802 MPEG API will call this when we can use the hardware */
+static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv)
+{
+ struct cx88_core *core = drv->core;
+ int err = 0;
+
+ switch (core->board) {
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ /* By default, core setup will leave the cx22702 out of reset, on the bus.
+ * We left the hardware on power up with the cx22702 active.
+ * We're being given access to re-arrange the GPIOs.
+ * Take the bus off the cx22702 and put the cx23416 on it.
+ */
+ cx_clear(MO_GP0_IO, 0x00000080); /* cx22702 in reset */
+ cx_set(MO_GP0_IO, 0x00000004); /* Disable the cx22702 */
+ break;
+ default:
+ err = -ENODEV;
+ }
+ return err;
+}
+
+/* The CX8802 MPEG API will call this when we need to release the hardware */
+static int cx8802_blackbird_advise_release(struct cx8802_driver *drv)
+{
+ struct cx88_core *core = drv->core;
+ int err = 0;
+
+ switch (core->board) {
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ /* Exit leaving the cx23416 on the bus */
+ break;
+ default:
+ err = -ENODEV;
+ }
+ return err;
+}
+
static void blackbird_unregister_video(struct cx8802_dev *dev)
{
if (dev->mpeg_dev) {
@@ -1073,28 +1142,23 @@ static int blackbird_register_video(struct cx8802_dev *dev)
/* ----------------------------------------------------------- */
-static int __devinit blackbird_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *pci_id)
+static int cx8802_blackbird_probe(struct cx8802_driver *drv)
{
- struct cx8802_dev *dev;
- struct cx88_core *core;
+ struct cx88_core *core = drv->core;
+ struct cx8802_dev *dev = core->dvbdev;
int err;
- /* general setup */
- core = cx88_core_get(pci_dev);
- if (NULL == core)
- return -EINVAL;
+ dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
+ core->board,
+ core->name,
+ core->pci_bus,
+ core->pci_slot);
err = -ENODEV;
if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))
goto fail_core;
- err = -ENOMEM;
- dev = kzalloc(sizeof(*dev),GFP_KERNEL);
- if (NULL == dev)
- goto fail_core;
- dev->pci = pci_dev;
- dev->core = core;
dev->width = 720;
dev->height = 576;
cx2341x_fill_defaults(&dev->params);
@@ -1106,64 +1170,36 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
dev->height = 576;
}
- err = cx8802_init_common(dev);
- if (0 != err)
- goto fail_free;
-
/* blackbird stuff */
printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n",
core->name);
host_setup(dev->core);
- list_add_tail(&dev->devlist,&cx8802_devlist);
blackbird_register_video(dev);
/* initial device configuration: needed ? */
return 0;
- fail_free:
- kfree(dev);
fail_core:
- cx88_core_put(core,pci_dev);
return err;
}
-static void __devexit blackbird_remove(struct pci_dev *pci_dev)
+static int cx8802_blackbird_remove(struct cx8802_driver *drv)
{
- struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
-
/* blackbird */
- blackbird_unregister_video(dev);
- list_del(&dev->devlist);
+ blackbird_unregister_video(drv->core->dvbdev);
- /* common */
- cx8802_fini_common(dev);
- cx88_core_put(dev->core,dev->pci);
- kfree(dev);
+ return 0;
}
-static struct pci_device_id cx8802_pci_tbl[] = {
- {
- .vendor = 0x14f1,
- .device = 0x8802,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },{
- /* --- end of list --- */
- }
-};
-MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
-
-static struct pci_driver blackbird_pci_driver = {
- .name = "cx88-blackbird",
- .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 struct cx8802_driver cx8802_blackbird_driver = {
+ .type_id = CX88_MPEG_BLACKBIRD,
+ .hw_access = CX8802_DRVCTL_SHARED,
+ .probe = cx8802_blackbird_probe,
+ .remove = cx8802_blackbird_remove,
+ .advise_acquire = cx8802_blackbird_advise_acquire,
+ .advise_release = cx8802_blackbird_advise_release,
};
static int blackbird_init(void)
@@ -1176,17 +1212,22 @@ static int blackbird_init(void)
printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
#endif
- return pci_register_driver(&blackbird_pci_driver);
+ cx88_ioctl_hook = mpeg_do_ioctl;
+ cx88_ioctl_translator = mpeg_translate_ioctl;
+ return cx8802_register_driver(&cx8802_blackbird_driver);
}
static void blackbird_fini(void)
{
- pci_unregister_driver(&blackbird_pci_driver);
+ cx8802_unregister_driver(&cx8802_blackbird_driver);
}
module_init(blackbird_init);
module_exit(blackbird_fini);
+EXPORT_SYMBOL(cx88_ioctl_hook);
+EXPORT_SYMBOL(cx88_ioctl_translator);
+
/* ----------------------------------------------------------- */
/*
* Local variables:
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index f764a57c56b..434b78ab37d 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -281,18 +281,22 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0000bde2,
+ .extadc = 1,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x0000bde6,
+ .extadc = 1,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0000bde6,
+ .extadc = 1,
}},
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x0000bd62,
+ .extadc = 1,
},
.mpeg = CX88_MPEG_BLACKBIRD,
},
@@ -353,6 +357,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
+ .extadc = 1,
}},
.radio = {
.type = CX88_RADIO,
@@ -523,6 +528,7 @@ struct cx88_board cx88_boards[] = {
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
+ .extadc = 1,
}},
.mpeg = CX88_MPEG_BLACKBIRD,
},
@@ -646,18 +652,22 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00009d80,
+ .extadc = 1,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00009d76,
+ .extadc = 1,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00009d76,
+ .extadc = 1,
}},
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x00009d00,
+ .extadc = 1,
},
.mpeg = CX88_MPEG_BLACKBIRD,
},
@@ -786,25 +796,29 @@ struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .mpeg = CX88_MPEG_BLACKBIRD,
.input = {{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 0,
.gpio0 = 0x0000cd73,
+ .extadc = 1,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 1,
.gpio0 = 0x0000cd73,
+ .extadc = 1,
},{
.type = CX88_VMUX_TELEVISION,
.vmux = 3,
.gpio0 = 0x0000cdb3,
+ .extadc = 1,
}},
.radio = {
.type = CX88_RADIO,
.vmux = 2,
.gpio0 = 0x0000cdf3,
+ .extadc = 1,
},
+ .mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD] = {
/* Alexander Wold <awold@bigfoot.com> */
@@ -1050,7 +1064,6 @@ struct cx88_board cx88_boards[] = {
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
- /* FIXME: Audio not working for s-video / composite inputs. */
.name = "KWorld HardwareMpegTV XPert",
.tuner_type = TUNER_PHILIPS_TDA8290,
.radio_type = UNSET,
@@ -1065,10 +1078,12 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x3de6,
+ .extadc = 1,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x3de6,
+ .extadc = 1,
}},
.radio = {
.type = CX88_RADIO,
@@ -1252,35 +1267,35 @@ struct cx88_board cx88_boards[] = {
.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_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,
@@ -1293,17 +1308,20 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xe780,
+ .extadc = 1,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0xe780,
+ .extadc = 1,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0xe780,
+ .extadc = 1,
}},
/* fixme: Add radio support */
- .mpeg = CX88_MPEG_DVB,
+ .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
},
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -1513,6 +1531,10 @@ struct cx88_subid cx88_subids[] = {
},{
.subvendor = 0x17de,
.subdevice = 0x0840,
+ .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
+ },{
+ .subvendor = 0x1421,
+ .subdevice = 0x0305,
.card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
},{
.subvendor = 0x18ac,
@@ -1610,7 +1632,7 @@ const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
/* ----------------------------------------------------------------------- */
/* some leadtek specific stuff */
-static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
+static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
{
/* This is just for the "Winfast 2000XP Expert" board ATM; I don't have data on
* any others.
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 4b655f2ef27..18997361c75 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -633,12 +633,12 @@ int cx88_reset(struct cx88_core *core)
static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
{
- return (norm->id & V4L2_STD_625_50) ? 922 : 754;
+ return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
}
static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
{
- return (norm->id & V4L2_STD_625_50) ? 186 : 135;
+ return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
}
static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
@@ -648,24 +648,33 @@ static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
{
- static const unsigned int ntsc = 28636360;
- static const unsigned int pal = 35468950;
- static const unsigned int palm = 28604892;
-
if (norm->id & V4L2_STD_PAL_M)
- return palm;
+ return 28604892; // 3.575611 MHz
+
+ if (norm->id & (V4L2_STD_PAL_Nc))
+ return 28656448; // 3.582056 MHz
+
+ if (norm->id & V4L2_STD_NTSC) // All NTSC/M and variants
+ return 28636360; // 3.57954545 MHz +/- 10 Hz
- return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
+ /* SECAM have also different sub carrier for chroma,
+ but step_db and step_dr, at cx88_set_tvnorm already handles that.
+
+ The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N
+ */
+
+ return 35468950; // 4.43361875 MHz +/- 5 Hz
}
static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
{
- /* Should always be Line Draw Time / (4*FSC) */
- if (norm->id & V4L2_STD_PAL_M)
- return 909;
+ unsigned int fsc4=norm_fsc8(norm)/2;
- return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
+ /* returns 4*FSC / vtotal / frames per seconds */
+ return (norm->id & V4L2_STD_625_50) ?
+ ((fsc4+312)/625+12)/25 :
+ ((fsc4+262)/525*1001+15000)/30000;
}
static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
@@ -692,7 +701,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
value &= 0x3fe;
cx_write(MO_HDELAY_EVEN, value);
cx_write(MO_HDELAY_ODD, value);
- dprintk(1,"set_scale: hdelay 0x%04x\n", value);
+ dprintk(1,"set_scale: hdelay 0x%04x (width %d)\n", value,swidth);
value = (swidth * 4096 / width) - 4096;
cx_write(MO_HSCALE_EVEN, value);
@@ -1153,7 +1162,7 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
mutex_lock(&devlist);
cx88_ir_fini(core);
if (0 == core->i2c_rc)
- i2c_bit_del_bus(&core->i2c_adap);
+ i2c_del_adapter(&core->i2c_adap);
list_del(&core->devlist);
iounmap(core->lmmio);
cx88_devcount--;
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 0ef13e7efa2..8b203354fcc 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -42,7 +42,7 @@
#include "cx22702.h"
#include "or51132.h"
#include "lgdt330x.h"
-#include "lg_h06xf.h"
+#include "lgh06xf.h"
#include "nxt200x.h"
#include "cx24123.h"
#include "isl6421.h"
@@ -57,7 +57,7 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
#define dprintk(level,fmt, arg...) if (debug >= level) \
- printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->core->name , ## arg)
+ printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg)
/* ------------------------------------------------------------------ */
@@ -74,8 +74,8 @@ static int dvb_buf_setup(struct videobuf_queue *q,
return 0;
}
-static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int dvb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
{
struct cx8802_dev *dev = q->priv_data;
return cx8802_buf_prepare(q, dev, (struct cx88_buffer*)vb,field);
@@ -87,7 +87,8 @@ static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
cx8802_buf_queue(dev, (struct cx88_buffer*)vb);
}
-static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void dvb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
{
cx88_free_buffer(q, (struct cx88_buffer*)vb);
}
@@ -100,6 +101,26 @@ static struct videobuf_queue_ops dvb_qops = {
};
/* ------------------------------------------------------------------ */
+
+static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx8802_driver *drv = NULL;
+ int ret = 0;
+
+ drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
+ if (drv) {
+ if (acquire)
+ ret = drv->request_acquire(drv);
+ else
+ ret = drv->request_release(drv);
+ }
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
{
static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 };
@@ -268,35 +289,6 @@ static struct mt352_config dntv_live_dvbt_pro_config = {
};
#endif
-static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- u8 pllbuf[4];
- struct cx8802_dev *dev= fe->dvb->priv;
- struct i2c_msg msg =
- { .addr = dev->core->pll_addr, .flags = 0,
- .buf = pllbuf, .len = 4 };
- int err;
-
- dvb_pll_configure(dev->core->pll_desc, pllbuf,
- params->frequency,
- params->u.ofdm.bandwidth);
-
- if (fe->ops.i2c_gate_ctrl)
- 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);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
static struct zl10353_config dvico_fusionhdtv_hybrid = {
.demod_address = 0x0f,
.no_tuner = 1,
@@ -311,28 +303,12 @@ static struct cx22702_config connexant_refboard_config = {
.output_mode = CX22702_SERIAL_OUTPUT,
};
-static struct cx22702_config hauppauge_novat_config = {
- .demod_address = 0x43,
- .output_mode = CX22702_SERIAL_OUTPUT,
-};
-
-static struct cx22702_config hauppauge_hvr1100_config = {
+static struct cx22702_config hauppauge_hvr_config = {
.demod_address = 0x63,
.output_mode = CX22702_SERIAL_OUTPUT,
};
-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)
+static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured)
{
struct cx8802_dev *dev= fe->dvb->priv;
dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
@@ -344,50 +320,6 @@ static struct or51132_config pchdtv_hd3000 = {
.set_ts_params = or51132_set_ts_param,
};
-static int lgdt3302_tuner_set_params(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
-{
- /* FIXME make this routine use the tuner-simple code.
- * It could probably be shared with a number of ATSC
- * frontends. Many share the same tuner with analog TV. */
-
- struct cx8802_dev *dev= fe->dvb->priv;
- struct cx88_core *core = dev->core;
- u8 buf[4];
- struct i2c_msg msg =
- { .addr = dev->core->pll_addr, .flags = 0, .buf = buf, .len = 4 };
- int err;
-
- 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]);
-
- 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);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
- return 0;
-}
-
-static int lgdt3303_tuner_set_params(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- struct cx88_core *core = dev->core;
-
- /* Put the analog decoder in standby to keep it quiet */
- cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
-
- return lg_h06xf_pll_set(fe, &core->i2c_adap, params);
-}
-
static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
{
struct cx8802_dev *dev= fe->dvb->priv;
@@ -432,8 +364,7 @@ static struct lgdt330x_config pchdtv_hd5500 = {
.set_ts_params = lgdt330x_set_ts_param,
};
-static int nxt200x_set_ts_param(struct dvb_frontend* fe,
- int is_punctured)
+static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
{
struct cx8802_dev *dev= fe->dvb->priv;
dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
@@ -469,11 +400,10 @@ static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe,
struct cx8802_dev *dev= fe->dvb->priv;
struct cx88_core *core = dev->core;
- if (voltage == SEC_VOLTAGE_OFF) {
+ if (voltage == SEC_VOLTAGE_OFF)
cx_write(MO_GP0_IO, 0x000006fb);
- } else {
+ else
cx_write(MO_GP0_IO, 0x000006f9);
- }
if (core->prev_set_voltage)
return core->prev_set_voltage(fe, voltage);
@@ -522,7 +452,7 @@ static int dvb_register(struct cx8802_dev *dev)
switch (dev->core->board) {
case CX88_BOARD_HAUPPAUGE_DVB_T1:
dev->dvb.frontend = dvb_attach(cx22702_attach,
- &hauppauge_novat_config,
+ &connexant_refboard_config,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
@@ -547,32 +477,11 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_HAUPPAUGE_HVR1100:
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
dev->dvb.frontend = dvb_attach(cx22702_attach,
- &hauppauge_hvr1100_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_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,
+ &hauppauge_hvr_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);
+ &dev->core->i2c_adap, &dvb_pll_fmd1216me);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
@@ -647,18 +556,17 @@ static int dvb_register(struct cx8802_dev *dev)
#endif
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_thomson_fe6600;
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;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_fe6600);
}
break;
case CX88_BOARD_PCHDTV_HD3000:
- dev->dvb.frontend = dvb_attach(or51132_attach,
- &pchdtv_hd3000,
+ dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
@@ -679,13 +587,13 @@ static int dvb_register(struct cx8802_dev *dev)
/* Select RF connector callback */
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 = 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;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_microtune_4042);
}
}
break;
@@ -699,13 +607,13 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(100);
cx_set(MO_GP0_IO, 9);
mdelay(200);
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
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;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt761x);
}
}
break;
@@ -723,7 +631,8 @@ static int dvb_register(struct cx8802_dev *dev)
&fusionhdtv_5_gold,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+ dvb_attach(lgh06xf_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap);
}
}
break;
@@ -741,7 +650,8 @@ static int dvb_register(struct cx8802_dev *dev)
&pchdtv_hd5500,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+ dvb_attach(lgh06xf_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap);
}
}
break;
@@ -782,6 +692,24 @@ static int dvb_register(struct cx8802_dev *dev)
dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
}
break;
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ dev->dvb.frontend = dvb_attach(cx22702_attach,
+ &hauppauge_hvr_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_hvr_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;
default:
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);
@@ -796,6 +724,8 @@ static int dvb_register(struct cx8802_dev *dev)
dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
}
+ /* Ensure all frontends negotiate bus access */
+ dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
/* Put the analog decoder in standby to keep it quiet */
cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
@@ -806,37 +736,67 @@ static int dvb_register(struct cx8802_dev *dev)
/* ----------------------------------------------------------- */
-static int __devinit dvb_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *pci_id)
+/* CX8802 MPEG -> mini driver - We have been given the hardware */
+static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
{
- struct cx8802_dev *dev;
- struct cx88_core *core;
+ struct cx88_core *core = drv->core;
+ int err = 0;
+ dprintk( 1, "%s\n", __FUNCTION__);
+
+ switch (core->board) {
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ /* We arrive here with either the cx23416 or the cx22702
+ * on the bus. Take the bus from the cx23416 and enable the
+ * cx22702 demod
+ */
+ cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset and enable */
+ cx_clear(MO_GP0_IO, 0x00000004);
+ udelay(1000);
+ break;
+ default:
+ err = -ENODEV;
+ }
+ return err;
+}
+
+/* CX8802 MPEG -> mini driver - We no longer have the hardware */
+static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
+{
+ struct cx88_core *core = drv->core;
+ int err = 0;
+ dprintk( 1, "%s\n", __FUNCTION__);
+
+ switch (core->board) {
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ /* Do Nothing, leave the cx22702 on the bus. */
+ break;
+ default:
+ err = -ENODEV;
+ }
+ return err;
+}
+
+static int cx8802_dvb_probe(struct cx8802_driver *drv)
+{
+ struct cx88_core *core = drv->core;
+ struct cx8802_dev *dev = drv->core->dvbdev;
int err;
- /* general setup */
- core = cx88_core_get(pci_dev);
- if (NULL == core)
- return -EINVAL;
+ dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
+ core->board,
+ core->name,
+ core->pci_bus,
+ core->pci_slot);
err = -ENODEV;
if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
goto fail_core;
- err = -ENOMEM;
- dev = kzalloc(sizeof(*dev),GFP_KERNEL);
- if (NULL == dev)
- goto fail_core;
- dev->pci = pci_dev;
- dev->core = core;
-
- err = cx8802_init_common(dev);
- if (0 != err)
- goto fail_free;
-
#ifdef HAVE_VP3054_I2C
err = vp3054_i2c_probe(dev);
if (0 != err)
- goto fail_free;
+ goto fail_core;
#endif
/* dvb stuff */
@@ -848,28 +808,16 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
sizeof(struct cx88_buffer),
dev);
err = dvb_register(dev);
- if (0 != err)
- goto fail_fini;
+ if (err != 0)
+ printk("%s dvb_register failed err = %d\n", __FUNCTION__, err);
- /* Maintain a reference to cx88-video can query the 8802 device. */
- core->dvbdev = dev;
- return 0;
-
- fail_fini:
- cx8802_fini_common(dev);
- fail_free:
- kfree(dev);
fail_core:
- cx88_core_put(core,pci_dev);
return err;
}
-static void __devexit dvb_remove(struct pci_dev *pci_dev)
+static int cx8802_dvb_remove(struct cx8802_driver *drv)
{
- struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
-
- /* Destroy any 8802 reference. */
- dev->core->dvbdev = NULL;
+ struct cx8802_dev *dev = drv->core->dvbdev;
/* dvb */
videobuf_dvb_unregister(&dev->dvb);
@@ -878,33 +826,16 @@ static void __devexit dvb_remove(struct pci_dev *pci_dev)
vp3054_i2c_remove(dev);
#endif
- /* common */
- cx8802_fini_common(dev);
- cx88_core_put(dev->core,dev->pci);
- kfree(dev);
+ return 0;
}
-static struct pci_device_id cx8802_pci_tbl[] = {
- {
- .vendor = 0x14f1,
- .device = 0x8802,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },{
- /* --- end of list --- */
- }
-};
-MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
-
-static struct pci_driver dvb_pci_driver = {
- .name = "cx88-dvb",
- .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 struct cx8802_driver cx8802_dvb_driver = {
+ .type_id = CX88_MPEG_DVB,
+ .hw_access = CX8802_DRVCTL_SHARED,
+ .probe = cx8802_dvb_probe,
+ .remove = cx8802_dvb_remove,
+ .advise_acquire = cx8802_dvb_advise_acquire,
+ .advise_release = cx8802_dvb_advise_release,
};
static int dvb_init(void)
@@ -917,12 +848,12 @@ static int dvb_init(void)
printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
#endif
- return pci_register_driver(&dvb_pci_driver);
+ return cx8802_register_driver(&cx8802_dvb_driver);
}
static void dvb_fini(void)
{
- pci_unregister_driver(&dvb_pci_driver);
+ cx8802_unregister_driver(&cx8802_dvb_driver);
}
module_init(dvb_init);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index e60a0a52e4b..8136673fe9e 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -155,6 +155,35 @@ static void cx88_ir_work(struct work_struct *work)
mod_timer(&ir->timer, timeout);
}
+static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
+{
+ if (ir->polling) {
+ INIT_WORK(&ir->work, cx88_ir_work);
+ init_timer(&ir->timer);
+ ir->timer.function = ir_timer;
+ ir->timer.data = (unsigned long)ir;
+ schedule_work(&ir->work);
+ }
+ if (ir->sampling) {
+ core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */
+ cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */
+ cx_write(MO_DDSCFG_IO, 0x5); /* enable */
+ }
+}
+
+static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
+{
+ if (ir->sampling) {
+ cx_write(MO_DDSCFG_IO, 0x0);
+ core->pci_irqmask &= ~(1 << 18);
+ }
+
+ if (ir->polling) {
+ del_timer_sync(&ir->timer);
+ flush_scheduled_work();
+ }
+}
+
/* ---------------------------------------------------------------------- */
int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
@@ -163,14 +192,12 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
struct input_dev *input_dev;
IR_KEYTAB_TYPE *ir_codes = NULL;
int ir_type = IR_TYPE_OTHER;
+ int err = -ENOMEM;
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
input_dev = input_allocate_device();
- if (!ir || !input_dev) {
- kfree(ir);
- input_free_device(input_dev);
- return -ENOMEM;
- }
+ if (!ir || !input_dev)
+ goto err_out_free;
ir->input = input_dev;
@@ -280,9 +307,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
}
if (NULL == ir_codes) {
- kfree(ir);
- input_free_device(input_dev);
- return -ENODEV;
+ err = -ENODEV;
+ goto err_out_free;
}
/* init input device */
@@ -307,23 +333,22 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->core = core;
core->ir = ir;
- if (ir->polling) {
- INIT_WORK(&ir->work, cx88_ir_work);
- init_timer(&ir->timer);
- ir->timer.function = ir_timer;
- ir->timer.data = (unsigned long)ir;
- schedule_work(&ir->work);
- }
- if (ir->sampling) {
- core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */
- cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */
- cx_write(MO_DDSCFG_IO, 0x5); /* enable */
- }
+ cx88_ir_start(core, ir);
/* all done */
- input_register_device(ir->input);
+ err = input_register_device(ir->input);
+ if (err)
+ goto err_out_stop;
return 0;
+
+ err_out_stop:
+ cx88_ir_stop(core, ir);
+ core->ir = NULL;
+ err_out_free:
+ input_free_device(input_dev);
+ kfree(ir);
+ return err;
}
int cx88_ir_fini(struct cx88_core *core)
@@ -334,15 +359,7 @@ int cx88_ir_fini(struct cx88_core *core)
if (NULL == ir)
return 0;
- if (ir->sampling) {
- cx_write(MO_DDSCFG_IO, 0x0);
- core->pci_irqmask &= ~(1 << 18);
- }
- if (ir->polling) {
- del_timer(&ir->timer);
- flush_scheduled_work();
- }
-
+ cx88_ir_stop(core, ir);
input_unregister_device(ir->input);
kfree(ir);
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 6b23a4e6f66..1fe1a833c7c 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -44,8 +44,12 @@ module_param(debug,int,0644);
MODULE_PARM_DESC(debug,"enable debug messages [mpeg]");
#define dprintk(level,fmt, arg...) if (debug >= level) \
- printk(KERN_DEBUG "%s/2: " fmt, dev->core->name , ## arg)
+ printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg)
+#define mpeg_dbg(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg)
+
+static LIST_HEAD(cx8802_devlist);
/* ------------------------------------------------------------------ */
static int cx8802_start_dma(struct cx8802_dev *dev,
@@ -65,17 +69,13 @@ 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].mpeg & CX88_MPEG_DVB) {
+ dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id);
+
+ if ( (core->active_type_id == CX88_MPEG_DVB) &&
+ (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) {
+
+ dprintk( 1, "cx8802_start_dma doing .dvb\n");
/* negedge driven & software reset */
cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
udelay(100);
@@ -93,15 +93,17 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */
udelay(100);
break;
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ break;
default:
cx_write(TS_SOP_STAT, 0x00);
break;
}
cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
udelay(100);
- }
-
- if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+ } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) &&
+ (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) {
+ dprintk( 1, "cx8802_start_dma doing .blackbird\n");
cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */
@@ -112,6 +114,10 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */
udelay(100);
+ } else {
+ printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__,
+ cx88_boards[core->board].mpeg );
+ return -EINVAL;
}
/* reset counter */
@@ -542,8 +548,315 @@ int cx8802_resume_common(struct pci_dev *pci_dev)
return 0;
}
+struct cx8802_dev * cx8802_get_device(struct inode *inode)
+{
+ int minor = iminor(inode);
+ struct cx8802_dev *h = NULL;
+ struct list_head *list;
+
+ list_for_each(list,&cx8802_devlist) {
+ h = list_entry(list, struct cx8802_dev, devlist);
+ if (h->mpeg_dev->minor == minor)
+ return h;
+ }
+
+ return NULL;
+}
+
+struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype)
+{
+ struct cx8802_dev *h = NULL;
+ struct cx8802_driver *d = NULL;
+ struct list_head *list;
+ struct list_head *list2;
+
+ list_for_each(list,&cx8802_devlist) {
+ h = list_entry(list, struct cx8802_dev, devlist);
+ if (h != dev)
+ continue;
+
+ list_for_each(list2, &h->drvlist.devlist) {
+ d = list_entry(list2, struct cx8802_driver, devlist);
+
+ /* only unregister the correct driver type */
+ if (d->type_id == btype) {
+ return d;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* Driver asked for hardware access. */
+int cx8802_request_acquire(struct cx8802_driver *drv)
+{
+ struct cx88_core *core = drv->core;
+
+ /* Fail a request for hardware if the device is busy. */
+ if (core->active_type_id != CX88_BOARD_NONE)
+ return -EBUSY;
+
+ if (drv->advise_acquire)
+ {
+ core->active_type_id = drv->type_id;
+ drv->advise_acquire(drv);
+
+ mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
+ }
+
+ return 0;
+}
+
+/* Driver asked to release hardware. */
+int cx8802_request_release(struct cx8802_driver *drv)
+{
+ struct cx88_core *core = drv->core;
+
+ if (drv->advise_release)
+ {
+ drv->advise_release(drv);
+ core->active_type_id = CX88_BOARD_NONE;
+ mpeg_dbg(1,"%s() Post release GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
+ }
+
+ return 0;
+}
+
+static int cx8802_check_driver(struct cx8802_driver *drv)
+{
+ if (drv == NULL)
+ return -ENODEV;
+
+ if ((drv->type_id != CX88_MPEG_DVB) &&
+ (drv->type_id != CX88_MPEG_BLACKBIRD))
+ return -EINVAL;
+
+ if ((drv->hw_access != CX8802_DRVCTL_SHARED) &&
+ (drv->hw_access != CX8802_DRVCTL_EXCLUSIVE))
+ return -EINVAL;
+
+ if ((drv->probe == NULL) ||
+ (drv->remove == NULL) ||
+ (drv->advise_acquire == NULL) ||
+ (drv->advise_release == NULL))
+ return -EINVAL;
+
+ return 0;
+}
+
+int cx8802_register_driver(struct cx8802_driver *drv)
+{
+ struct cx8802_dev *h;
+ struct cx8802_driver *driver;
+ struct list_head *list;
+ int err = 0, i = 0;
+
+ printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ ,
+ drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
+ drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
+
+ if ((err = cx8802_check_driver(drv)) != 0) {
+ printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ );
+ return err;
+ }
+
+ list_for_each(list,&cx8802_devlist) {
+ h = list_entry(list, struct cx8802_dev, devlist);
+
+ printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
+ h->core->name,h->pci->subsystem_vendor,
+ h->pci->subsystem_device,cx88_boards[h->core->board].name,
+ h->core->board);
+
+ /* Bring up a new struct for each driver instance */
+ driver = kzalloc(sizeof(*drv),GFP_KERNEL);
+ if (driver == NULL)
+ return -ENOMEM;
+
+ /* Snapshot of the driver registration data */
+ drv->core = h->core;
+ drv->suspend = cx8802_suspend_common;
+ drv->resume = cx8802_resume_common;
+ drv->request_acquire = cx8802_request_acquire;
+ drv->request_release = cx8802_request_release;
+ memcpy(driver, drv, sizeof(*driver));
+
+ err = drv->probe(driver);
+ if (err == 0) {
+ i++;
+ mutex_lock(&drv->core->lock);
+ list_add_tail(&driver->devlist,&h->drvlist.devlist);
+ mutex_unlock(&drv->core->lock);
+ } else {
+ printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err);
+ }
+
+ }
+ if (i == 0)
+ err = -ENODEV;
+ else
+ err = 0;
+
+ return err;
+}
+
+int cx8802_unregister_driver(struct cx8802_driver *drv)
+{
+ struct cx8802_dev *h;
+ struct cx8802_driver *d;
+ struct list_head *list;
+ struct list_head *list2, *q;
+ int err = 0, i = 0;
+
+ printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ ,
+ drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird");
+
+ list_for_each(list,&cx8802_devlist) {
+ i++;
+ h = list_entry(list, struct cx8802_dev, devlist);
+
+ printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
+ h->core->name,h->pci->subsystem_vendor,
+ h->pci->subsystem_device,cx88_boards[h->core->board].name,
+ h->core->board);
+
+ list_for_each_safe(list2, q, &h->drvlist.devlist) {
+ d = list_entry(list2, struct cx8802_driver, devlist);
+
+ /* only unregister the correct driver type */
+ if (d->type_id != drv->type_id)
+ continue;
+
+ err = d->remove(d);
+ if (err == 0) {
+ mutex_lock(&drv->core->lock);
+ list_del(list2);
+ mutex_unlock(&drv->core->lock);
+ } else
+ printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err);
+
+ }
+
+ }
+
+ return err;
+}
+
/* ----------------------------------------------------------- */
+static int __devinit cx8802_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ struct cx8802_dev *dev;
+ struct cx88_core *core;
+ int err;
+
+ /* general setup */
+ core = cx88_core_get(pci_dev);
+ if (NULL == core)
+ return -EINVAL;
+ printk("%s/2: cx2388x 8802 Driver Manager\n", core->name);
+
+ err = -ENODEV;
+ if (!cx88_boards[core->board].mpeg)
+ goto fail_core;
+
+ err = -ENOMEM;
+ dev = kzalloc(sizeof(*dev),GFP_KERNEL);
+ if (NULL == dev)
+ goto fail_core;
+ dev->pci = pci_dev;
+ dev->core = core;
+
+ err = cx8802_init_common(dev);
+ if (err != 0)
+ goto fail_free;
+
+ INIT_LIST_HEAD(&dev->drvlist.devlist);
+ list_add_tail(&dev->devlist,&cx8802_devlist);
+
+ /* Maintain a reference so cx88-video can query the 8802 device. */
+ core->dvbdev = dev;
+ return 0;
+
+ fail_free:
+ kfree(dev);
+ fail_core:
+ cx88_core_put(core,pci_dev);
+ return err;
+}
+
+static void __devexit cx8802_remove(struct pci_dev *pci_dev)
+{
+ struct cx8802_dev *dev;
+ struct cx8802_driver *h;
+ struct list_head *list;
+
+ dev = pci_get_drvdata(pci_dev);
+
+ dprintk( 1, "%s\n", __FUNCTION__);
+
+ list_for_each(list,&dev->drvlist.devlist) {
+ h = list_entry(list, struct cx8802_driver, devlist);
+ dprintk( 1, " ->driver\n");
+ if (h->remove == NULL) {
+ printk(KERN_ERR "%s .. skipping driver, no probe function\n", __FUNCTION__);
+ continue;
+ }
+ printk(KERN_INFO "%s .. Removing driver type %d\n", __FUNCTION__, h->type_id);
+ cx8802_unregister_driver(h);
+ list_del(&dev->drvlist.devlist);
+ }
+
+ /* Destroy any 8802 reference. */
+ dev->core->dvbdev = NULL;
+
+ /* common */
+ cx8802_fini_common(dev);
+ cx88_core_put(dev->core,dev->pci);
+ kfree(dev);
+}
+
+static struct pci_device_id cx8802_pci_tbl[] = {
+ {
+ .vendor = 0x14f1,
+ .device = 0x8802,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },{
+ /* --- end of list --- */
+ }
+};
+MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
+
+static struct pci_driver cx8802_pci_driver = {
+ .name = "cx88-mpeg driver manager",
+ .id_table = cx8802_pci_tbl,
+ .probe = cx8802_probe,
+ .remove = __devexit_p(cx8802_remove),
+};
+
+static int cx8802_init(void)
+{
+ printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n",
+ (CX88_VERSION_CODE >> 16) & 0xff,
+ (CX88_VERSION_CODE >> 8) & 0xff,
+ CX88_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+ printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
+ SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+ return pci_register_driver(&cx8802_pci_driver);
+}
+
+static void cx8802_fini(void)
+{
+ pci_unregister_driver(&cx8802_pci_driver);
+}
+
+module_init(cx8802_init);
+module_exit(cx8802_fini);
EXPORT_SYMBOL(cx8802_buf_prepare);
EXPORT_SYMBOL(cx8802_buf_queue);
EXPORT_SYMBOL(cx8802_cancel_buffers);
@@ -551,9 +864,10 @@ EXPORT_SYMBOL(cx8802_cancel_buffers);
EXPORT_SYMBOL(cx8802_init_common);
EXPORT_SYMBOL(cx8802_fini_common);
-EXPORT_SYMBOL(cx8802_suspend_common);
-EXPORT_SYMBOL(cx8802_resume_common);
-
+EXPORT_SYMBOL(cx8802_register_driver);
+EXPORT_SYMBOL(cx8802_unregister_driver);
+EXPORT_SYMBOL(cx8802_get_device);
+EXPORT_SYMBOL(cx8802_get_driver);
/* ----------------------------------------------------------- */
/*
* Local variables:
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 58ba9f77352..2bd84d351a1 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -38,6 +38,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
+#include <linux/freezer.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
@@ -143,19 +144,6 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
cx88_start_audio_dma(core);
if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
- /* sets sound input from external adc */
- switch (core->board) {
- case CX88_BOARD_HAUPPAUGE_ROSLYN:
- case CX88_BOARD_KWORLD_MCE200_DELUXE:
- case CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT:
- case CX88_BOARD_PIXELVIEW_PLAYTV_P7000:
- case CX88_BOARD_ASUS_PVR_416:
- cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
- break;
- default:
- cx_set(AUD_CTL, EN_I2SIN_ENABLE);
- }
-
cx_write(AUD_I2SINPUTCNTL, 4);
cx_write(AUD_BAUDRATE, 1);
/* 'pass-thru mode': this enables the i2s output to the mpeg encoder */
@@ -974,6 +962,7 @@ int cx88_audio_thread(void *data)
msleep_interruptible(1000);
if (kthread_should_stop())
break;
+ try_to_freeze();
/* just monitor the audio status for now ... */
memset(&t, 0, sizeof(t));
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 90e298d074d..8613378428f 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -454,6 +454,14 @@ static int video_mux(struct cx88_core *core, unsigned int input)
cx_clear(MO_FILTER_ODD, 0x00002020);
break;
}
+
+ if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+ /* sets sound input from external adc */
+ if (INPUT(input)->extadc)
+ cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+ else
+ cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
+ }
return 0;
}
@@ -1490,6 +1498,30 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
mutex_unlock(&core->lock);
return 0;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ /* ioctls to allow direct acces to the cx2388x registers */
+ case VIDIOC_INT_G_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != 0)
+ return -EINVAL;
+ /* cx2388x has a 24-bit register space */
+ reg->val = cx_read(reg->reg&0xffffff);
+ return 0;
+ }
+ case VIDIOC_INT_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != 0)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ cx_write(reg->reg&0xffffff, reg->val);
+ return 0;
+ }
+#endif
default:
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
index 2b4f1970c7d..6068c9bf82c 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -168,7 +168,7 @@ void vp3054_i2c_remove(struct cx8802_dev *dev)
dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
return;
- i2c_bit_del_bus(&vp3054_i2c->adap);
+ i2c_del_adapter(&vp3054_i2c->adap);
kfree(vp3054_i2c);
}
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 3bc91aad4fe..a9575ad8ca2 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -74,6 +74,11 @@ enum cx88_board_type {
CX88_MPEG_BLACKBIRD
};
+enum cx8802_board_access {
+ CX8802_DRVCTL_SHARED = 1,
+ CX8802_DRVCTL_EXCLUSIVE = 2,
+};
+
/* ----------------------------------------------------------- */
/* tv norms */
@@ -86,7 +91,7 @@ struct cx88_tvnorm {
static unsigned int inline norm_maxw(struct cx88_tvnorm *norm)
{
- return (norm->id & V4L2_STD_625_50) ? 768 : 640;
+ return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
}
@@ -220,6 +225,7 @@ struct cx88_input {
enum cx88_itype type;
unsigned int vmux;
u32 gpio0, gpio1, gpio2, gpio3;
+ unsigned int extadc:1;
};
struct cx88_board {
@@ -330,6 +336,7 @@ struct cx88_core {
/* cx88-video needs to access cx8802 for hybrid tuner pll access. */
struct cx8802_dev *dvbdev;
+ enum cx88_board_type active_type_id;
};
struct cx8800_dev;
@@ -405,6 +412,31 @@ struct cx8802_suspend_state {
int disabled;
};
+struct cx8802_driver {
+ struct cx88_core *core;
+ struct list_head devlist;
+
+ /* Type of driver and access required */
+ enum cx88_board_type type_id;
+ enum cx8802_board_access hw_access;
+
+ /* MPEG 8802 internal only */
+ int (*suspend)(struct pci_dev *pci_dev, pm_message_t state);
+ int (*resume)(struct pci_dev *pci_dev);
+
+ /* MPEG 8802 -> mini driver - Driver probe and configuration */
+ int (*probe)(struct cx8802_driver *drv);
+ int (*remove)(struct cx8802_driver *drv);
+
+ /* MPEG 8802 -> mini driver - Access for hardware control */
+ int (*advise_acquire)(struct cx8802_driver *drv);
+ int (*advise_release)(struct cx8802_driver *drv);
+
+ /* MPEG 8802 <- mini driver - Access for hardware control */
+ int (*request_acquire)(struct cx8802_driver *drv);
+ int (*request_release)(struct cx8802_driver *drv);
+};
+
struct cx8802_dev {
struct cx88_core *core;
spinlock_t slock;
@@ -439,6 +471,9 @@ struct cx8802_dev {
/* mpeg params */
struct cx2341x_mpeg_params params;
+
+ /* List of attached drivers */
+ struct cx8802_driver drvlist;
};
/* ----------------------------------------------------------- */
@@ -571,6 +606,11 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
int cx88_audio_thread(void *data);
+int cx8802_register_driver(struct cx8802_driver *drv);
+int cx8802_unregister_driver(struct cx8802_driver *drv);
+struct cx8802_dev * cx8802_get_device(struct inode *inode);
+struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
+
/* ----------------------------------------------------------- */
/* cx88-input.c */
@@ -600,6 +640,13 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
extern const u32 cx88_user_ctrls[];
extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl);
+/* ----------------------------------------------------------- */
+/* cx88-blackbird.c */
+/* used by cx88-ivtv ioctl emulation layer */
+extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg);
+extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index b1012e92ee0..917021fc299 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -218,7 +218,7 @@ static int dabusb_alloc_buffers (pdabusb_t s)
pipesize, packets, transfer_buffer_length);
while (buffers < (s->total_buffer_size << 10)) {
- b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL);
+ b = kzalloc(sizeof (buff_t), GFP_KERNEL);
if (!b) {
err("kzalloc(sizeof(buff_t))==NULL");
goto err;
@@ -659,7 +659,7 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
switch (cmd) {
case IOCTL_DAB_BULK:
- pbulk = (pbulk_transfer_t) kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
+ pbulk = kmalloc(sizeof (bulk_transfer_t), GFP_KERNEL);
if (!pbulk) {
ret = -ENOMEM;
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 2a461dde480..36e72c207a8 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1674,9 +1674,9 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
if (dev->has_msp34xx) {
/* Send a reset to other chips via gpio */
em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
- udelay(2500);
+ msleep(3);
em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
- udelay(2500);
+ msleep(3);
}
video_mux(dev, 0);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index ab87e7bfe84..59edf58204d 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -305,15 +305,14 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
int ir_type;
struct IR_i2c *ir;
struct input_dev *input_dev;
+ int err;
ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
input_dev = input_allocate_device();
if (!ir || !input_dev) {
- input_free_device(input_dev);
- kfree(ir);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto err_out_free;
}
- memset(ir,0,sizeof(*ir));
ir->c = client_template;
ir->input = input_dev;
@@ -355,32 +354,34 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
break;
case 0x7a:
case 0x47:
+ case 0x71:
/* Handled by saa7134-input */
name = "SAA713x remote";
ir_type = IR_TYPE_OTHER;
break;
default:
/* shouldn't happen */
- printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n",addr);
- kfree(ir);
- return -1;
+ printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n", addr);
+ err = -ENODEV;
+ goto err_out_free;
}
/* Sets name */
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
- ir->ir_codes=ir_codes;
+ ir->ir_codes = ir_codes;
/* register i2c device
* At device register, IR codes may be changed to be
* board dependent.
*/
- i2c_attach_client(&ir->c);
+ err = i2c_attach_client(&ir->c);
+ if (err)
+ goto err_out_free;
/* If IR not supported or disabled, unregisters driver */
if (ir->get_key == NULL) {
- i2c_detach_client(&ir->c);
- kfree(ir);
- return -1;
+ err = -ENODEV;
+ goto err_out_detach;
}
/* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */
@@ -389,15 +390,17 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
ir->c.dev.bus_id);
/* init + register input device */
- ir_input_init(input_dev,&ir->ir,ir_type,ir->ir_codes);
+ ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes);
input_dev->id.bustype = BUS_I2C;
input_dev->name = ir->c.name;
input_dev->phys = ir->phys;
- /* register event device */
- input_register_device(ir->input);
+ err = input_register_device(ir->input);
+ if (err)
+ goto err_out_detach;
+
printk(DEVNAME ": %s detected at %s [%s]\n",
- ir->input->name,ir->input->phys,adap->name);
+ ir->input->name, ir->input->phys, adap->name);
/* start polling via eventd */
INIT_WORK(&ir->work, ir_work);
@@ -407,6 +410,13 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
schedule_work(&ir->work);
return 0;
+
+ err_out_detach:
+ i2c_detach_client(&ir->c);
+ err_out_free:
+ input_free_device(input_dev);
+ kfree(ir);
+ return err;
}
static int ir_detach(struct i2c_client *client)
@@ -414,7 +424,7 @@ static int ir_detach(struct i2c_client *client)
struct IR_i2c *ir = i2c_get_clientdata(client);
/* kill outstanding polls */
- del_timer(&ir->timer);
+ del_timer_sync(&ir->timer);
flush_scheduled_work();
/* unregister devices */
@@ -439,7 +449,7 @@ static int ir_probe(struct i2c_adapter *adap)
*/
static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
- static const int probe_saa7134[] = { 0x7a, 0x47, -1 };
+ static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
static const int probe_em28XX[] = { 0x30, 0x47, -1 };
const int *probe = NULL;
struct i2c_client c;
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
index c1a377f797d..b6cd21e6dab 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/video/ks0127.c
@@ -712,13 +712,13 @@ static int ks0127_command(struct i2c_client *client,
*iarg = 0;
status = ks0127_read(ks, KS_STAT);
if (!(status & 0x20)) /* NOVID not set */
- *iarg = (*iarg & DECODER_STATUS_GOOD);
+ *iarg = (*iarg | DECODER_STATUS_GOOD);
if ((status & 0x01)) /* CLOCK set */
- *iarg = (*iarg & DECODER_STATUS_COLOR);
+ *iarg = (*iarg | DECODER_STATUS_COLOR);
if ((status & 0x08)) /* PALDET set */
- *iarg = (*iarg & DECODER_STATUS_PAL);
+ *iarg = (*iarg | DECODER_STATUS_PAL);
else
- *iarg = (*iarg & DECODER_STATUS_NTSC);
+ *iarg = (*iarg | DECODER_STATUS_NTSC);
break;
//Catch any unknown command
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index b083338823d..616a35da191 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -923,7 +923,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
struct video_picture *p = arg;
if (p->depth != 16)
return -EINVAL;
- if (p->palette != VIDEO_PALETTE_YUV422)
+ if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV)
return -EINVAL;
mutex_lock(&meye.lock);
sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS,
@@ -978,7 +978,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
if (vm->frame >= gbuffers || vm->frame < 0)
return -EINVAL;
- if (vm->format != VIDEO_PALETTE_YUV422)
+ if (vm->format != VIDEO_PALETTE_YUV422 && vm->format != VIDEO_PALETTE_YUYV)
return -EINVAL;
if (vm->height * vm->width * 2 > gbufsize)
return -EINVAL;
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index e1b56dc13c3..2fb9fe6a1ae 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -633,10 +633,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (((rt->input >> (4 + i * 4)) & 0xf) == 0)
extern_input = 0;
}
- if (extern_input)
- state->mode = MSP_MODE_EXTERN;
- else
- state->mode = MSP_MODE_AM_DETECT;
+ state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT;
+ state->rxsubchans = V4L2_TUNER_SUB_STEREO;
msp_set_scart(client, sc_in, 0);
msp_set_scart(client, sc1_out, 1);
msp_set_scart(client, sc2_out, 2);
@@ -951,7 +949,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
if (thread_func) {
state->kthread = kthread_run(thread_func, client, "msp34xx");
- if (state->kthread == NULL)
+ if (IS_ERR(state->kthread))
v4l_warn(client, "kernel_thread() failed\n");
msp_wake_thread(client);
}
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index 4c7f85b566a..e1821eb82fb 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -483,7 +483,6 @@ int msp3400c_thread(void *data)
/* no carrier scan, just unmute */
v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
state->scan_in_progress = 0;
- state->rxsubchans = V4L2_TUNER_SUB_STEREO;
msp_set_audio(client);
continue;
}
@@ -851,12 +850,15 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
source = 1; /* stereo or A|B */
matrix = 0x20;
break;
- case V4L2_TUNER_MODE_STEREO:
case V4L2_TUNER_MODE_LANG1:
- default:
source = 3; /* stereo or A */
matrix = 0x00;
break;
+ case V4L2_TUNER_MODE_STEREO:
+ default:
+ source = 3; /* stereo or A */
+ matrix = 0x20;
+ break;
}
if (in == MSP_DSP_IN_TUNER)
@@ -1030,6 +1032,9 @@ static int msp34xxg_detect_stereo(struct i2c_client *client)
int is_stereo = status & 0x40;
int oldrx = state->rxsubchans;
+ if (state->mode == MSP_MODE_EXTERN)
+ return 0;
+
state->rxsubchans = 0;
if (is_stereo)
state->rxsubchans = V4L2_TUNER_SUB_STEREO;
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index b0aea4002d1..152cc6b3e15 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -160,10 +160,6 @@ static int mxb_probe(struct saa7146_dev* dev)
printk("mxb: saa7111 i2c module not available.\n");
return -ENODEV;
}
- if ((result = request_module("tuner")) < 0) {
- printk("mxb: tuner i2c module not available.\n");
- return -ENODEV;
- }
if ((result = request_module("tea6420")) < 0) {
printk("mxb: tea6420 i2c module not available.\n");
return -ENODEV;
@@ -176,6 +172,10 @@ static int mxb_probe(struct saa7146_dev* dev)
printk("mxb: tda9840 i2c module not available.\n");
return -ENODEV;
}
+ if ((result = request_module("tuner")) < 0) {
+ printk("mxb: tuner i2c module not available.\n");
+ return -ENODEV;
+ }
mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
if( NULL == mxb ) {
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
new file mode 100644
index 00000000000..5ed0adc4ca2
--- /dev/null
+++ b/drivers/media/video/ov7670.c
@@ -0,0 +1,1333 @@
+/*
+ * A V4L2 driver for OmniVision OV7670 cameras.
+ *
+ * Copyright 2006 One Laptop Per Child Association, Inc. Written
+ * by Jonathan Corbet with substantial inspiration from Mark
+ * McClelland's ovcamchip code.
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <linux/i2c.h>
+
+
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
+MODULE_LICENSE("GPL");
+
+/*
+ * Basic window sizes. These probably belong somewhere more globally
+ * useful.
+ */
+#define VGA_WIDTH 640
+#define VGA_HEIGHT 480
+#define QVGA_WIDTH 320
+#define QVGA_HEIGHT 240
+#define CIF_WIDTH 352
+#define CIF_HEIGHT 288
+#define QCIF_WIDTH 176
+#define QCIF_HEIGHT 144
+
+/*
+ * Our nominal (default) frame rate.
+ */
+#define OV7670_FRAME_RATE 30
+
+/*
+ * The 7670 sits on i2c with ID 0x42
+ */
+#define OV7670_I2C_ADDR 0x42
+
+/* Registers */
+#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
+#define REG_BLUE 0x01 /* blue gain */
+#define REG_RED 0x02 /* red gain */
+#define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */
+#define REG_COM1 0x04 /* Control 1 */
+#define COM1_CCIR656 0x40 /* CCIR656 enable */
+#define REG_BAVE 0x05 /* U/B Average level */
+#define REG_GbAVE 0x06 /* Y/Gb Average level */
+#define REG_AECHH 0x07 /* AEC MS 5 bits */
+#define REG_RAVE 0x08 /* V/R Average level */
+#define REG_COM2 0x09 /* Control 2 */
+#define COM2_SSLEEP 0x10 /* Soft sleep mode */
+#define REG_PID 0x0a /* Product ID MSB */
+#define REG_VER 0x0b /* Product ID LSB */
+#define REG_COM3 0x0c /* Control 3 */
+#define COM3_SWAP 0x40 /* Byte swap */
+#define COM3_SCALEEN 0x08 /* Enable scaling */
+#define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */
+#define REG_COM4 0x0d /* Control 4 */
+#define REG_COM5 0x0e /* All "reserved" */
+#define REG_COM6 0x0f /* Control 6 */
+#define REG_AECH 0x10 /* More bits of AEC value */
+#define REG_CLKRC 0x11 /* Clocl control */
+#define CLK_EXT 0x40 /* Use external clock directly */
+#define CLK_SCALE 0x3f /* Mask for internal clock scale */
+#define REG_COM7 0x12 /* Control 7 */
+#define COM7_RESET 0x80 /* Register reset */
+#define COM7_FMT_MASK 0x38
+#define COM7_FMT_VGA 0x00
+#define COM7_FMT_CIF 0x20 /* CIF format */
+#define COM7_FMT_QVGA 0x10 /* QVGA format */
+#define COM7_FMT_QCIF 0x08 /* QCIF format */
+#define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */
+#define COM7_YUV 0x00 /* YUV */
+#define COM7_BAYER 0x01 /* Bayer format */
+#define COM7_PBAYER 0x05 /* "Processed bayer" */
+#define REG_COM8 0x13 /* Control 8 */
+#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
+#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */
+#define COM8_BFILT 0x20 /* Band filter enable */
+#define COM8_AGC 0x04 /* Auto gain enable */
+#define COM8_AWB 0x02 /* White balance enable */
+#define COM8_AEC 0x01 /* Auto exposure enable */
+#define REG_COM9 0x14 /* Control 9 - gain ceiling */
+#define REG_COM10 0x15 /* Control 10 */
+#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */
+#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */
+#define COM10_HREF_REV 0x08 /* Reverse HREF */
+#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */
+#define COM10_VS_NEG 0x02 /* VSYNC negative */
+#define COM10_HS_NEG 0x01 /* HSYNC negative */
+#define REG_HSTART 0x17 /* Horiz start high bits */
+#define REG_HSTOP 0x18 /* Horiz stop high bits */
+#define REG_VSTART 0x19 /* Vert start high bits */
+#define REG_VSTOP 0x1a /* Vert stop high bits */
+#define REG_PSHFT 0x1b /* Pixel delay after HREF */
+#define REG_MIDH 0x1c /* Manuf. ID high */
+#define REG_MIDL 0x1d /* Manuf. ID low */
+#define REG_MVFP 0x1e /* Mirror / vflip */
+#define MVFP_MIRROR 0x20 /* Mirror image */
+#define MVFP_FLIP 0x10 /* Vertical flip */
+
+#define REG_AEW 0x24 /* AGC upper limit */
+#define REG_AEB 0x25 /* AGC lower limit */
+#define REG_VPT 0x26 /* AGC/AEC fast mode op region */
+#define REG_HSYST 0x30 /* HSYNC rising edge delay */
+#define REG_HSYEN 0x31 /* HSYNC falling edge delay */
+#define REG_HREF 0x32 /* HREF pieces */
+#define REG_TSLB 0x3a /* lots of stuff */
+#define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */
+#define REG_COM11 0x3b /* Control 11 */
+#define COM11_NIGHT 0x80 /* NIght mode enable */
+#define COM11_NMFR 0x60 /* Two bit NM frame rate */
+#define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
+#define COM11_50HZ 0x08 /* Manual 50Hz select */
+#define COM11_EXP 0x02
+#define REG_COM12 0x3c /* Control 12 */
+#define COM12_HREF 0x80 /* HREF always */
+#define REG_COM13 0x3d /* Control 13 */
+#define COM13_GAMMA 0x80 /* Gamma enable */
+#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */
+#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */
+#define REG_COM14 0x3e /* Control 14 */
+#define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */
+#define REG_EDGE 0x3f /* Edge enhancement factor */
+#define REG_COM15 0x40 /* Control 15 */
+#define COM15_R10F0 0x00 /* Data range 10 to F0 */
+#define COM15_R01FE 0x80 /* 01 to FE */
+#define COM15_R00FF 0xc0 /* 00 to FF */
+#define COM15_RGB565 0x10 /* RGB565 output */
+#define COM15_RGB555 0x30 /* RGB555 output */
+#define REG_COM16 0x41 /* Control 16 */
+#define COM16_AWBGAIN 0x08 /* AWB gain enable */
+#define REG_COM17 0x42 /* Control 17 */
+#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */
+#define COM17_CBAR 0x08 /* DSP Color bar */
+
+/*
+ * This matrix defines how the colors are generated, must be
+ * tweaked to adjust hue and saturation.
+ *
+ * Order: v-red, v-green, v-blue, u-red, u-green, u-blue
+ *
+ * They are nine-bit signed quantities, with the sign bit
+ * stored in 0x58. Sign for v-red is bit 0, and up from there.
+ */
+#define REG_CMATRIX_BASE 0x4f
+#define CMATRIX_LEN 6
+#define REG_CMATRIX_SIGN 0x58
+
+
+#define REG_BRIGHT 0x55 /* Brightness */
+#define REG_CONTRAS 0x56 /* Contrast control */
+
+#define REG_GFIX 0x69 /* Fix gain control */
+
+#define REG_RGB444 0x8c /* RGB 444 control */
+#define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */
+#define R444_RGBX 0x01 /* Empty nibble at end */
+
+#define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */
+#define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */
+
+#define REG_BD50MAX 0xa5 /* 50hz banding step limit */
+#define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */
+#define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */
+#define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */
+#define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */
+#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */
+#define REG_BD60MAX 0xab /* 60hz banding step limit */
+
+
+/*
+ * Information we maintain about a known sensor.
+ */
+struct ov7670_format_struct; /* coming later */
+struct ov7670_info {
+ struct ov7670_format_struct *fmt; /* Current format */
+ unsigned char sat; /* Saturation value */
+ int hue; /* Hue value */
+};
+
+
+
+
+/*
+ * The default register settings, as obtained from OmniVision. There
+ * is really no making sense of most of these - lots of "reserved" values
+ * and such.
+ *
+ * These settings give VGA YUYV.
+ */
+
+struct regval_list {
+ unsigned char reg_num;
+ unsigned char value;
+};
+
+static struct regval_list ov7670_default_regs[] = {
+ { REG_COM7, COM7_RESET },
+/*
+ * Clock scale: 3 = 15fps
+ * 2 = 20fps
+ * 1 = 30fps
+ */
+ { REG_CLKRC, 0x1 }, /* OV: clock scale (30 fps) */
+ { REG_TSLB, 0x04 }, /* OV */
+ { REG_COM7, 0 }, /* VGA */
+ /*
+ * Set the hardware window. These values from OV don't entirely
+ * make sense - hstop is less than hstart. But they work...
+ */
+ { REG_HSTART, 0x13 }, { REG_HSTOP, 0x01 },
+ { REG_HREF, 0xb6 }, { REG_VSTART, 0x02 },
+ { REG_VSTOP, 0x7a }, { REG_VREF, 0x0a },
+
+ { REG_COM3, 0 }, { REG_COM14, 0 },
+ /* Mystery scaling numbers */
+ { 0x70, 0x3a }, { 0x71, 0x35 },
+ { 0x72, 0x11 }, { 0x73, 0xf0 },
+ { 0xa2, 0x02 }, { REG_COM10, 0x0 },
+
+ /* Gamma curve values */
+ { 0x7a, 0x20 }, { 0x7b, 0x10 },
+ { 0x7c, 0x1e }, { 0x7d, 0x35 },
+ { 0x7e, 0x5a }, { 0x7f, 0x69 },
+ { 0x80, 0x76 }, { 0x81, 0x80 },
+ { 0x82, 0x88 }, { 0x83, 0x8f },
+ { 0x84, 0x96 }, { 0x85, 0xa3 },
+ { 0x86, 0xaf }, { 0x87, 0xc4 },
+ { 0x88, 0xd7 }, { 0x89, 0xe8 },
+
+ /* AGC and AEC parameters. Note we start by disabling those features,
+ then turn them only after tweaking the values. */
+ { REG_COM8, COM8_FASTAEC | COM8_AECSTEP | COM8_BFILT },
+ { REG_GAIN, 0 }, { REG_AECH, 0 },
+ { REG_COM4, 0x40 }, /* magic reserved bit */
+ { REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+ { REG_BD50MAX, 0x05 }, { REG_BD60MAX, 0x07 },
+ { REG_AEW, 0x95 }, { REG_AEB, 0x33 },
+ { REG_VPT, 0xe3 }, { REG_HAECC1, 0x78 },
+ { REG_HAECC2, 0x68 }, { 0xa1, 0x03 }, /* magic */
+ { REG_HAECC3, 0xd8 }, { REG_HAECC4, 0xd8 },
+ { REG_HAECC5, 0xf0 }, { REG_HAECC6, 0x90 },
+ { REG_HAECC7, 0x94 },
+ { REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC },
+
+ /* Almost all of these are magic "reserved" values. */
+ { REG_COM5, 0x61 }, { REG_COM6, 0x4b },
+ { 0x16, 0x02 }, { REG_MVFP, 0x07|MVFP_MIRROR },
+ { 0x21, 0x02 }, { 0x22, 0x91 },
+ { 0x29, 0x07 }, { 0x33, 0x0b },
+ { 0x35, 0x0b }, { 0x37, 0x1d },
+ { 0x38, 0x71 }, { 0x39, 0x2a },
+ { REG_COM12, 0x78 }, { 0x4d, 0x40 },
+ { 0x4e, 0x20 }, { REG_GFIX, 0 },
+ { 0x6b, 0x4a }, { 0x74, 0x10 },
+ { 0x8d, 0x4f }, { 0x8e, 0 },
+ { 0x8f, 0 }, { 0x90, 0 },
+ { 0x91, 0 }, { 0x96, 0 },
+ { 0x9a, 0 }, { 0xb0, 0x84 },
+ { 0xb1, 0x0c }, { 0xb2, 0x0e },
+ { 0xb3, 0x82 }, { 0xb8, 0x0a },
+
+ /* More reserved magic, some of which tweaks white balance */
+ { 0x43, 0x0a }, { 0x44, 0xf0 },
+ { 0x45, 0x34 }, { 0x46, 0x58 },
+ { 0x47, 0x28 }, { 0x48, 0x3a },
+ { 0x59, 0x88 }, { 0x5a, 0x88 },
+ { 0x5b, 0x44 }, { 0x5c, 0x67 },
+ { 0x5d, 0x49 }, { 0x5e, 0x0e },
+ { 0x6c, 0x0a }, { 0x6d, 0x55 },
+ { 0x6e, 0x11 }, { 0x6f, 0x9f }, /* "9e for advance AWB" */
+ { 0x6a, 0x40 }, { REG_BLUE, 0x40 },
+ { REG_RED, 0x60 },
+ { REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC|COM8_AWB },
+
+ /* Matrix coefficients */
+ { 0x4f, 0x80 }, { 0x50, 0x80 },
+ { 0x51, 0 }, { 0x52, 0x22 },
+ { 0x53, 0x5e }, { 0x54, 0x80 },
+ { 0x58, 0x9e },
+
+ { REG_COM16, COM16_AWBGAIN }, { REG_EDGE, 0 },
+ { 0x75, 0x05 }, { 0x76, 0xe1 },
+ { 0x4c, 0 }, { 0x77, 0x01 },
+ { REG_COM13, 0xc3 }, { 0x4b, 0x09 },
+ { 0xc9, 0x60 }, { REG_COM16, 0x38 },
+ { 0x56, 0x40 },
+
+ { 0x34, 0x11 }, { REG_COM11, COM11_EXP|COM11_HZAUTO },
+ { 0xa4, 0x88 }, { 0x96, 0 },
+ { 0x97, 0x30 }, { 0x98, 0x20 },
+ { 0x99, 0x30 }, { 0x9a, 0x84 },
+ { 0x9b, 0x29 }, { 0x9c, 0x03 },
+ { 0x9d, 0x4c }, { 0x9e, 0x3f },
+ { 0x78, 0x04 },
+
+ /* Extra-weird stuff. Some sort of multiplexor register */
+ { 0x79, 0x01 }, { 0xc8, 0xf0 },
+ { 0x79, 0x0f }, { 0xc8, 0x00 },
+ { 0x79, 0x10 }, { 0xc8, 0x7e },
+ { 0x79, 0x0a }, { 0xc8, 0x80 },
+ { 0x79, 0x0b }, { 0xc8, 0x01 },
+ { 0x79, 0x0c }, { 0xc8, 0x0f },
+ { 0x79, 0x0d }, { 0xc8, 0x20 },
+ { 0x79, 0x09 }, { 0xc8, 0x80 },
+ { 0x79, 0x02 }, { 0xc8, 0xc0 },
+ { 0x79, 0x03 }, { 0xc8, 0x40 },
+ { 0x79, 0x05 }, { 0xc8, 0x30 },
+ { 0x79, 0x26 },
+
+ { 0xff, 0xff }, /* END MARKER */
+};
+
+
+/*
+ * Here we'll try to encapsulate the changes for just the output
+ * video format.
+ *
+ * RGB656 and YUV422 come from OV; RGB444 is homebrewed.
+ *
+ * IMPORTANT RULE: the first entry must be for COM7, see ov7670_s_fmt for why.
+ */
+
+
+static struct regval_list ov7670_fmt_yuv422[] = {
+ { REG_COM7, 0x0 }, /* Selects YUV mode */
+ { REG_RGB444, 0 }, /* No RGB444 please */
+ { REG_COM1, 0 },
+ { REG_COM15, COM15_R00FF },
+ { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */
+ { 0x4f, 0x80 }, /* "matrix coefficient 1" */
+ { 0x50, 0x80 }, /* "matrix coefficient 2" */
+ { 0x51, 0 }, /* vb */
+ { 0x52, 0x22 }, /* "matrix coefficient 4" */
+ { 0x53, 0x5e }, /* "matrix coefficient 5" */
+ { 0x54, 0x80 }, /* "matrix coefficient 6" */
+ { REG_COM13, COM13_GAMMA|COM13_UVSAT },
+ { 0xff, 0xff },
+};
+
+static struct regval_list ov7670_fmt_rgb565[] = {
+ { REG_COM7, COM7_RGB }, /* Selects RGB mode */
+ { REG_RGB444, 0 }, /* No RGB444 please */
+ { REG_COM1, 0x0 },
+ { REG_COM15, COM15_RGB565 },
+ { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */
+ { 0x4f, 0xb3 }, /* "matrix coefficient 1" */
+ { 0x50, 0xb3 }, /* "matrix coefficient 2" */
+ { 0x51, 0 }, /* vb */
+ { 0x52, 0x3d }, /* "matrix coefficient 4" */
+ { 0x53, 0xa7 }, /* "matrix coefficient 5" */
+ { 0x54, 0xe4 }, /* "matrix coefficient 6" */
+ { REG_COM13, COM13_GAMMA|COM13_UVSAT },
+ { 0xff, 0xff },
+};
+
+static struct regval_list ov7670_fmt_rgb444[] = {
+ { REG_COM7, COM7_RGB }, /* Selects RGB mode */
+ { REG_RGB444, R444_ENABLE }, /* Enable xxxxrrrr ggggbbbb */
+ { REG_COM1, 0x40 }, /* Magic reserved bit */
+ { REG_COM15, COM15_R01FE|COM15_RGB565 }, /* Data range needed? */
+ { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */
+ { 0x4f, 0xb3 }, /* "matrix coefficient 1" */
+ { 0x50, 0xb3 }, /* "matrix coefficient 2" */
+ { 0x51, 0 }, /* vb */
+ { 0x52, 0x3d }, /* "matrix coefficient 4" */
+ { 0x53, 0xa7 }, /* "matrix coefficient 5" */
+ { 0x54, 0xe4 }, /* "matrix coefficient 6" */
+ { REG_COM13, COM13_GAMMA|COM13_UVSAT|0x2 }, /* Magic rsvd bit */
+ { 0xff, 0xff },
+};
+
+
+
+
+/*
+ * Low-level register I/O.
+ */
+
+static int ov7670_read(struct i2c_client *c, unsigned char reg,
+ unsigned char *value)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(c, reg);
+ if (ret >= 0)
+ *value = (unsigned char) ret;
+ return ret;
+}
+
+
+static int ov7670_write(struct i2c_client *c, unsigned char reg,
+ unsigned char value)
+{
+ return i2c_smbus_write_byte_data(c, reg, value);
+}
+
+
+/*
+ * Write a list of register settings; ff/ff stops the process.
+ */
+static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals)
+{
+ while (vals->reg_num != 0xff || vals->value != 0xff) {
+ int ret = ov7670_write(c, vals->reg_num, vals->value);
+ if (ret < 0)
+ return ret;
+ vals++;
+ }
+ return 0;
+}
+
+
+/*
+ * Stuff that knows about the sensor.
+ */
+static void ov7670_reset(struct i2c_client *client)
+{
+ ov7670_write(client, REG_COM7, COM7_RESET);
+ msleep(1);
+}
+
+
+static int ov7670_init(struct i2c_client *client)
+{
+ return ov7670_write_array(client, ov7670_default_regs);
+}
+
+
+
+static int ov7670_detect(struct i2c_client *client)
+{
+ unsigned char v;
+ int ret;
+
+ ret = ov7670_init(client);
+ if (ret < 0)
+ return ret;
+ ret = ov7670_read(client, REG_MIDH, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0x7f) /* OV manuf. id. */
+ return -ENODEV;
+ ret = ov7670_read(client, REG_MIDL, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0xa2)
+ return -ENODEV;
+ /*
+ * OK, we know we have an OmniVision chip...but which one?
+ */
+ ret = ov7670_read(client, REG_PID, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0x76) /* PID + VER = 0x76 / 0x73 */
+ return -ENODEV;
+ ret = ov7670_read(client, REG_VER, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0x73) /* PID + VER = 0x76 / 0x73 */
+ return -ENODEV;
+ return 0;
+}
+
+
+/*
+ * Store information about the video data format. The color matrix
+ * is deeply tied into the format, so keep the relevant values here.
+ * The magic matrix nubmers come from OmniVision.
+ */
+static struct ov7670_format_struct {
+ __u8 *desc;
+ __u32 pixelformat;
+ struct regval_list *regs;
+ int cmatrix[CMATRIX_LEN];
+} ov7670_formats[] = {
+ {
+ .desc = "YUYV 4:2:2",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .regs = ov7670_fmt_yuv422,
+ .cmatrix = { 128, -128, 0, -34, -94, 128 },
+ },
+ {
+ .desc = "RGB 444",
+ .pixelformat = V4L2_PIX_FMT_RGB444,
+ .regs = ov7670_fmt_rgb444,
+ .cmatrix = { 179, -179, 0, -61, -176, 228 },
+ },
+ {
+ .desc = "RGB 565",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .regs = ov7670_fmt_rgb565,
+ .cmatrix = { 179, -179, 0, -61, -176, 228 },
+ },
+};
+#define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0]))
+
+/*
+ * All formats we support are 2 bytes/pixel.
+ */
+#define BYTES_PER_PIXEL 2
+
+/*
+ * Then there is the issue of window sizes. Try to capture the info here.
+ */
+
+/*
+ * QCIF mode is done (by OV) in a very strange way - it actually looks like
+ * VGA with weird scaling options - they do *not* use the canned QCIF mode
+ * which is allegedly provided by the sensor. So here's the weird register
+ * settings.
+ */
+static struct regval_list ov7670_qcif_regs[] = {
+ { REG_COM3, COM3_SCALEEN|COM3_DCWEN },
+ { REG_COM3, COM3_DCWEN },
+ { REG_COM14, COM14_DCWEN | 0x01},
+ { 0x73, 0xf1 },
+ { 0xa2, 0x52 },
+ { 0x7b, 0x1c },
+ { 0x7c, 0x28 },
+ { 0x7d, 0x3c },
+ { 0x7f, 0x69 },
+ { REG_COM9, 0x38 },
+ { 0xa1, 0x0b },
+ { 0x74, 0x19 },
+ { 0x9a, 0x80 },
+ { 0x43, 0x14 },
+ { REG_COM13, 0xc0 },
+ { 0xff, 0xff },
+};
+
+static struct ov7670_win_size {
+ int width;
+ int height;
+ unsigned char com7_bit;
+ int hstart; /* Start/stop values for the camera. Note */
+ int hstop; /* that they do not always make complete */
+ int vstart; /* sense to humans, but evidently the sensor */
+ int vstop; /* will do the right thing... */
+ struct regval_list *regs; /* Regs to tweak */
+/* h/vref stuff */
+} ov7670_win_sizes[] = {
+ /* VGA */
+ {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .com7_bit = COM7_FMT_VGA,
+ .hstart = 158, /* These values from */
+ .hstop = 14, /* Omnivision */
+ .vstart = 10,
+ .vstop = 490,
+ .regs = NULL,
+ },
+ /* CIF */
+ {
+ .width = CIF_WIDTH,
+ .height = CIF_HEIGHT,
+ .com7_bit = COM7_FMT_CIF,
+ .hstart = 170, /* Empirically determined */
+ .hstop = 90,
+ .vstart = 14,
+ .vstop = 494,
+ .regs = NULL,
+ },
+ /* QVGA */
+ {
+ .width = QVGA_WIDTH,
+ .height = QVGA_HEIGHT,
+ .com7_bit = COM7_FMT_QVGA,
+ .hstart = 164, /* Empirically determined */
+ .hstop = 20,
+ .vstart = 14,
+ .vstop = 494,
+ .regs = NULL,
+ },
+ /* QCIF */
+ {
+ .width = QCIF_WIDTH,
+ .height = QCIF_HEIGHT,
+ .com7_bit = COM7_FMT_VGA, /* see comment above */
+ .hstart = 456, /* Empirically determined */
+ .hstop = 24,
+ .vstart = 14,
+ .vstop = 494,
+ .regs = ov7670_qcif_regs,
+ },
+};
+
+#define N_WIN_SIZES (sizeof(ov7670_win_sizes)/sizeof(ov7670_win_sizes[0]))
+
+
+/*
+ * Store a set of start/stop values into the camera.
+ */
+static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop,
+ int vstart, int vstop)
+{
+ int ret;
+ unsigned char v;
+/*
+ * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of
+ * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is
+ * a mystery "edge offset" value in the top two bits of href.
+ */
+ ret = ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff);
+ ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff);
+ ret += ov7670_read(client, REG_HREF, &v);
+ v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
+ msleep(10);
+ ret += ov7670_write(client, REG_HREF, v);
+/*
+ * Vertical: similar arrangement, but only 10 bits.
+ */
+ ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff);
+ ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff);
+ ret += ov7670_read(client, REG_VREF, &v);
+ v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3);
+ msleep(10);
+ ret += ov7670_write(client, REG_VREF, v);
+ return ret;
+}
+
+
+static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt)
+{
+ struct ov7670_format_struct *ofmt;
+
+ if (fmt->index >= N_OV7670_FMTS)
+ return -EINVAL;
+
+ ofmt = ov7670_formats + fmt->index;
+ fmt->flags = 0;
+ strcpy(fmt->description, ofmt->desc);
+ fmt->pixelformat = ofmt->pixelformat;
+ return 0;
+}
+
+
+static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
+ struct ov7670_format_struct **ret_fmt,
+ struct ov7670_win_size **ret_wsize)
+{
+ int index;
+ struct ov7670_win_size *wsize;
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+ for (index = 0; index < N_OV7670_FMTS; index++)
+ if (ov7670_formats[index].pixelformat == pix->pixelformat)
+ break;
+ if (index >= N_OV7670_FMTS)
+ return -EINVAL;
+ if (ret_fmt != NULL)
+ *ret_fmt = ov7670_formats + index;
+ /*
+ * Fields: the OV devices claim to be progressive.
+ */
+ if (pix->field == V4L2_FIELD_ANY)
+ pix->field = V4L2_FIELD_NONE;
+ else if (pix->field != V4L2_FIELD_NONE)
+ return -EINVAL;
+ /*
+ * Round requested image size down to the nearest
+ * we support, but not below the smallest.
+ */
+ for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES;
+ wsize++)
+ if (pix->width >= wsize->width && pix->height >= wsize->height)
+ break;
+ if (wsize >= ov7670_win_sizes + N_WIN_SIZES)
+ wsize--; /* Take the smallest one */
+ if (ret_wsize != NULL)
+ *ret_wsize = wsize;
+ /*
+ * Note the size we'll actually handle.
+ */
+ pix->width = wsize->width;
+ pix->height = wsize->height;
+ pix->bytesperline = pix->width*BYTES_PER_PIXEL;
+ pix->sizeimage = pix->height*pix->bytesperline;
+ return 0;
+}
+
+/*
+ * Set a format.
+ */
+static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
+{
+ int ret;
+ struct ov7670_format_struct *ovfmt;
+ struct ov7670_win_size *wsize;
+ struct ov7670_info *info = i2c_get_clientdata(c);
+ unsigned char com7;
+
+ ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize);
+ if (ret)
+ return ret;
+ /*
+ * COM7 is a pain in the ass, it doesn't like to be read then
+ * quickly written afterward. But we have everything we need
+ * to set it absolutely here, as long as the format-specific
+ * register sets list it first.
+ */
+ com7 = ovfmt->regs[0].value;
+ com7 |= wsize->com7_bit;
+ ov7670_write(c, REG_COM7, com7);
+ /*
+ * Now write the rest of the array. Also store start/stops
+ */
+ ov7670_write_array(c, ovfmt->regs + 1);
+ ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart,
+ wsize->vstop);
+ ret = 0;
+ if (wsize->regs)
+ ret = ov7670_write_array(c, wsize->regs);
+ info->fmt = ovfmt;
+ return 0;
+}
+
+/*
+ * Implement G/S_PARM. There is a "high quality" mode we could try
+ * to do someday; for now, we just do the frame rate tweak.
+ */
+static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+{
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ unsigned char clkrc;
+ int ret;
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ ret = ov7670_read(c, REG_CLKRC, &clkrc);
+ if (ret < 0)
+ return ret;
+ memset(cp, 0, sizeof(struct v4l2_captureparm));
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe.numerator = 1;
+ cp->timeperframe.denominator = OV7670_FRAME_RATE;
+ if ((clkrc & CLK_EXT) == 0 && (clkrc & CLK_SCALE) > 1)
+ cp->timeperframe.denominator /= (clkrc & CLK_SCALE);
+ return 0;
+}
+
+static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+{
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ struct v4l2_fract *tpf = &cp->timeperframe;
+ unsigned char clkrc;
+ int ret, div;
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (cp->extendedmode != 0)
+ return -EINVAL;
+ /*
+ * CLKRC has a reserved bit, so let's preserve it.
+ */
+ ret = ov7670_read(c, REG_CLKRC, &clkrc);
+ if (ret < 0)
+ return ret;
+ if (tpf->numerator == 0 || tpf->denominator == 0)
+ div = 1; /* Reset to full rate */
+ else
+ div = (tpf->numerator*OV7670_FRAME_RATE)/tpf->denominator;
+ if (div == 0)
+ div = 1;
+ else if (div > CLK_SCALE)
+ div = CLK_SCALE;
+ clkrc = (clkrc & 0x80) | div;
+ tpf->numerator = 1;
+ tpf->denominator = OV7670_FRAME_RATE/div;
+ return ov7670_write(c, REG_CLKRC, clkrc);
+}
+
+
+
+/*
+ * Code for dealing with controls.
+ */
+
+
+
+
+
+static int ov7670_store_cmatrix(struct i2c_client *client,
+ int matrix[CMATRIX_LEN])
+{
+ int i, ret;
+ unsigned char signbits;
+
+ /*
+ * Weird crap seems to exist in the upper part of
+ * the sign bits register, so let's preserve it.
+ */
+ ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits);
+ signbits &= 0xc0;
+
+ for (i = 0; i < CMATRIX_LEN; i++) {
+ unsigned char raw;
+
+ if (matrix[i] < 0) {
+ signbits |= (1 << i);
+ if (matrix[i] < -255)
+ raw = 0xff;
+ else
+ raw = (-1 * matrix[i]) & 0xff;
+ }
+ else {
+ if (matrix[i] > 255)
+ raw = 0xff;
+ else
+ raw = matrix[i] & 0xff;
+ }
+ ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw);
+ }
+ ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits);
+ return ret;
+}
+
+
+/*
+ * Hue also requires messing with the color matrix. It also requires
+ * trig functions, which tend not to be well supported in the kernel.
+ * So here is a simple table of sine values, 0-90 degrees, in steps
+ * of five degrees. Values are multiplied by 1000.
+ *
+ * The following naive approximate trig functions require an argument
+ * carefully limited to -180 <= theta <= 180.
+ */
+#define SIN_STEP 5
+static const int ov7670_sin_table[] = {
+ 0, 87, 173, 258, 342, 422,
+ 499, 573, 642, 707, 766, 819,
+ 866, 906, 939, 965, 984, 996,
+ 1000
+};
+
+static int ov7670_sine(int theta)
+{
+ int chs = 1;
+ int sine;
+
+ if (theta < 0) {
+ theta = -theta;
+ chs = -1;
+ }
+ if (theta <= 90)
+ sine = ov7670_sin_table[theta/SIN_STEP];
+ else {
+ theta -= 90;
+ sine = 1000 - ov7670_sin_table[theta/SIN_STEP];
+ }
+ return sine*chs;
+}
+
+static int ov7670_cosine(int theta)
+{
+ theta = 90 - theta;
+ if (theta > 180)
+ theta -= 360;
+ else if (theta < -180)
+ theta += 360;
+ return ov7670_sine(theta);
+}
+
+
+
+
+static void ov7670_calc_cmatrix(struct ov7670_info *info,
+ int matrix[CMATRIX_LEN])
+{
+ int i;
+ /*
+ * Apply the current saturation setting first.
+ */
+ for (i = 0; i < CMATRIX_LEN; i++)
+ matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7;
+ /*
+ * Then, if need be, rotate the hue value.
+ */
+ if (info->hue != 0) {
+ int sinth, costh, tmpmatrix[CMATRIX_LEN];
+
+ memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int));
+ sinth = ov7670_sine(info->hue);
+ costh = ov7670_cosine(info->hue);
+
+ matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000;
+ matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000;
+ matrix[2] = (matrix[5]*sinth + matrix[2]*costh)/1000;
+ matrix[3] = (matrix[3]*costh - matrix[0]*sinth)/1000;
+ matrix[4] = (matrix[4]*costh - matrix[1]*sinth)/1000;
+ matrix[5] = (matrix[5]*costh - matrix[2]*sinth)/1000;
+ }
+}
+
+
+
+static int ov7670_t_sat(struct i2c_client *client, int value)
+{
+ struct ov7670_info *info = i2c_get_clientdata(client);
+ int matrix[CMATRIX_LEN];
+ int ret;
+
+ info->sat = value;
+ ov7670_calc_cmatrix(info, matrix);
+ ret = ov7670_store_cmatrix(client, matrix);
+ return ret;
+}
+
+static int ov7670_q_sat(struct i2c_client *client, __s32 *value)
+{
+ struct ov7670_info *info = i2c_get_clientdata(client);
+
+ *value = info->sat;
+ return 0;
+}
+
+static int ov7670_t_hue(struct i2c_client *client, int value)
+{
+ struct ov7670_info *info = i2c_get_clientdata(client);
+ int matrix[CMATRIX_LEN];
+ int ret;
+
+ if (value < -180 || value > 180)
+ return -EINVAL;
+ info->hue = value;
+ ov7670_calc_cmatrix(info, matrix);
+ ret = ov7670_store_cmatrix(client, matrix);
+ return ret;
+}
+
+
+static int ov7670_q_hue(struct i2c_client *client, __s32 *value)
+{
+ struct ov7670_info *info = i2c_get_clientdata(client);
+
+ *value = info->hue;
+ return 0;
+}
+
+
+/*
+ * Some weird registers seem to store values in a sign/magnitude format!
+ */
+static unsigned char ov7670_sm_to_abs(unsigned char v)
+{
+ if ((v & 0x80) == 0)
+ return v + 128;
+ else
+ return 128 - (v & 0x7f);
+}
+
+
+static unsigned char ov7670_abs_to_sm(unsigned char v)
+{
+ if (v > 127)
+ return v & 0x7f;
+ else
+ return (128 - v) | 0x80;
+}
+
+static int ov7670_t_brightness(struct i2c_client *client, int value)
+{
+ unsigned char com8, v;
+ int ret;
+
+ ov7670_read(client, REG_COM8, &com8);
+ com8 &= ~COM8_AEC;
+ ov7670_write(client, REG_COM8, com8);
+ v = ov7670_abs_to_sm(value);
+ ret = ov7670_write(client, REG_BRIGHT, v);
+ return ret;
+}
+
+static int ov7670_q_brightness(struct i2c_client *client, __s32 *value)
+{
+ unsigned char v;
+ int ret = ov7670_read(client, REG_BRIGHT, &v);
+
+ *value = ov7670_sm_to_abs(v);
+ return ret;
+}
+
+static int ov7670_t_contrast(struct i2c_client *client, int value)
+{
+ return ov7670_write(client, REG_CONTRAS, (unsigned char) value);
+}
+
+static int ov7670_q_contrast(struct i2c_client *client, __s32 *value)
+{
+ unsigned char v;
+ int ret = ov7670_read(client, REG_CONTRAS, &v);
+
+ *value = v;
+ return ret;
+}
+
+static int ov7670_q_hflip(struct i2c_client *client, __s32 *value)
+{
+ int ret;
+ unsigned char v;
+
+ ret = ov7670_read(client, REG_MVFP, &v);
+ *value = (v & MVFP_MIRROR) == MVFP_MIRROR;
+ return ret;
+}
+
+
+static int ov7670_t_hflip(struct i2c_client *client, int value)
+{
+ unsigned char v;
+ int ret;
+
+ ret = ov7670_read(client, REG_MVFP, &v);
+ if (value)
+ v |= MVFP_MIRROR;
+ else
+ v &= ~MVFP_MIRROR;
+ msleep(10); /* FIXME */
+ ret += ov7670_write(client, REG_MVFP, v);
+ return ret;
+}
+
+
+
+static int ov7670_q_vflip(struct i2c_client *client, __s32 *value)
+{
+ int ret;
+ unsigned char v;
+
+ ret = ov7670_read(client, REG_MVFP, &v);
+ *value = (v & MVFP_FLIP) == MVFP_FLIP;
+ return ret;
+}
+
+
+static int ov7670_t_vflip(struct i2c_client *client, int value)
+{
+ unsigned char v;
+ int ret;
+
+ ret = ov7670_read(client, REG_MVFP, &v);
+ if (value)
+ v |= MVFP_FLIP;
+ else
+ v &= ~MVFP_FLIP;
+ msleep(10); /* FIXME */
+ ret += ov7670_write(client, REG_MVFP, v);
+ return ret;
+}
+
+
+static struct ov7670_control {
+ struct v4l2_queryctrl qc;
+ int (*query)(struct i2c_client *c, __s32 *value);
+ int (*tweak)(struct i2c_client *c, int value);
+} ov7670_controls[] =
+{
+ {
+ .qc = {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0x80,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .tweak = ov7670_t_brightness,
+ .query = ov7670_q_brightness,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0x40, /* XXX ov7670 spec */
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .tweak = ov7670_t_contrast,
+ .query = ov7670_q_contrast,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0x80,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .tweak = ov7670_t_sat,
+ .query = ov7670_q_sat,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HUE",
+ .minimum = -180,
+ .maximum = 180,
+ .step = 5,
+ .default_value = 0,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .tweak = ov7670_t_hue,
+ .query = ov7670_q_hue,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .tweak = ov7670_t_vflip,
+ .query = ov7670_q_vflip,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Horizontal mirror",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .tweak = ov7670_t_hflip,
+ .query = ov7670_q_hflip,
+ },
+};
+#define N_CONTROLS (sizeof(ov7670_controls)/sizeof(ov7670_controls[0]))
+
+static struct ov7670_control *ov7670_find_control(__u32 id)
+{
+ int i;
+
+ for (i = 0; i < N_CONTROLS; i++)
+ if (ov7670_controls[i].qc.id == id)
+ return ov7670_controls + i;
+ return NULL;
+}
+
+
+static int ov7670_queryctrl(struct i2c_client *client,
+ struct v4l2_queryctrl *qc)
+{
+ struct ov7670_control *ctrl = ov7670_find_control(qc->id);
+
+ if (ctrl == NULL)
+ return -EINVAL;
+ *qc = ctrl->qc;
+ return 0;
+}
+
+static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
+ int ret;
+
+ if (octrl == NULL)
+ return -EINVAL;
+ ret = octrl->query(client, &ctrl->value);
+ if (ret >= 0)
+ return 0;
+ return ret;
+}
+
+static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
+ int ret;
+
+ if (octrl == NULL)
+ return -EINVAL;
+ ret = octrl->tweak(client, ctrl->value);
+ if (ret >= 0)
+ return 0;
+ return ret;
+}
+
+
+
+
+
+
+/*
+ * Basic i2c stuff.
+ */
+static struct i2c_driver ov7670_driver;
+
+static int ov7670_attach(struct i2c_adapter *adapter)
+{
+ int ret;
+ struct i2c_client *client;
+ struct ov7670_info *info;
+
+ /*
+ * For now: only deal with adapters we recognize.
+ */
+ if (adapter->id != I2C_HW_SMBUS_CAFE)
+ return -ENODEV;
+
+ client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL);
+ if (! client)
+ return -ENOMEM;
+ client->adapter = adapter;
+ client->addr = OV7670_I2C_ADDR;
+ client->driver = &ov7670_driver,
+ strcpy(client->name, "OV7670");
+ /*
+ * Set up our info structure.
+ */
+ info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL);
+ if (! info) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+ info->fmt = &ov7670_formats[0];
+ info->sat = 128; /* Review this */
+ i2c_set_clientdata(client, info);
+
+ /*
+ * Make sure it's an ov7670
+ */
+ ret = ov7670_detect(client);
+ if (ret)
+ goto out_free_info;
+ i2c_attach_client(client);
+ return 0;
+
+ out_free_info:
+ kfree(info);
+ out_free:
+ kfree(client);
+ return ret;
+}
+
+
+static int ov7670_detach(struct i2c_client *client)
+{
+ i2c_detach_client(client);
+ kfree(i2c_get_clientdata(client));
+ kfree(client);
+ return 0;
+}
+
+
+static int ov7670_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ switch (cmd) {
+ case VIDIOC_INT_G_CHIP_IDENT:
+ * (enum v4l2_chip_ident *) arg = V4L2_IDENT_OV7670;
+ return 0;
+
+ case VIDIOC_INT_RESET:
+ ov7670_reset(client);
+ return 0;
+
+ case VIDIOC_INT_INIT:
+ return ov7670_init(client);
+
+ case VIDIOC_ENUM_FMT:
+ return ov7670_enum_fmt(client, (struct v4l2_fmtdesc *) arg);
+ case VIDIOC_TRY_FMT:
+ return ov7670_try_fmt(client, (struct v4l2_format *) arg, NULL, NULL);
+ case VIDIOC_S_FMT:
+ return ov7670_s_fmt(client, (struct v4l2_format *) arg);
+ case VIDIOC_QUERYCTRL:
+ return ov7670_queryctrl(client, (struct v4l2_queryctrl *) arg);
+ case VIDIOC_S_CTRL:
+ return ov7670_s_ctrl(client, (struct v4l2_control *) arg);
+ case VIDIOC_G_CTRL:
+ return ov7670_g_ctrl(client, (struct v4l2_control *) arg);
+ case VIDIOC_S_PARM:
+ return ov7670_s_parm(client, (struct v4l2_streamparm *) arg);
+ case VIDIOC_G_PARM:
+ return ov7670_g_parm(client, (struct v4l2_streamparm *) arg);
+ }
+ return -EINVAL;
+}
+
+
+
+static struct i2c_driver ov7670_driver = {
+ .driver = {
+ .name = "ov7670",
+ },
+ .id = I2C_DRIVERID_OV7670,
+ .class = I2C_CLASS_CAM_DIGITAL,
+ .attach_adapter = ov7670_attach,
+ .detach_client = ov7670_detach,
+ .command = ov7670_command,
+};
+
+
+/*
+ * Module initialization
+ */
+static int __init ov7670_mod_init(void)
+{
+ printk(KERN_NOTICE "OmniVision ov7670 sensor driver, at your service\n");
+ return i2c_add_driver(&ov7670_driver);
+}
+
+static void __exit ov7670_mod_exit(void)
+{
+ i2c_del_driver(&ov7670_driver);
+}
+
+module_init(ov7670_mod_init);
+module_exit(ov7670_mod_exit);
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index 368d6e219fa..86d2884e16c 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -138,7 +138,7 @@ static int grabbuf_alloc(struct planb *pb)
+ MAX_LNUM
#endif /* PLANB_GSCANLINE */
);
- if ((pb->rawbuf = (unsigned char**) kmalloc (npage
+ if ((pb->rawbuf = kmalloc(npage
* sizeof(unsigned long), GFP_KERNEL)) == 0)
return -ENOMEM;
for (i = 0; i < npage; i++) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index c80c26be6e4..848fb233d80 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -260,6 +260,22 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
sizeof(decoder_ops[0]))) - 1;
hdw->decoder_ctrl = &ctxt->ctrl;
cp->handler = &ctxt->handler;
+ {
+ /*
+ Mike Isely <isely@pobox.com> 19-Nov-2006 - This bit
+ of nuttiness for cx25840 causes that module to
+ correctly set up its video scaling. This is really
+ a problem in the cx25840 module itself, but we work
+ around it here. The problem has not been seen in
+ ivtv because there VBI is supported and set up. We
+ don't do VBI here (at least not yet) and thus we
+ never attempted to even set it up.
+ */
+ struct v4l2_format fmt;
+ memset(&fmt,0,sizeof(fmt));
+ fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_FMT,&fmt);
+ }
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x cx2584x V4L2 handler set up",
cp->client->addr);
return !0;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 1f787333d18..d2004965187 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -356,28 +356,6 @@ 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. */
@@ -758,10 +736,6 @@ static const struct pvr2_ctl_info control_defs[] = {
.default_value = 720,
DEFREF(res_hor),
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",
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 3b9012f8e38..f9bb41d8f4f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -185,6 +185,79 @@ static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
}
}
+
+/* This is a special entry point for cases of I2C transaction attempts to
+ the IR receiver. The implementation here simulates the IR receiver by
+ issuing a command to the FX2 firmware and using that response to return
+ what the real I2C receiver would have returned. We use this for 24xxx
+ devices, where the IR receiver chip has been removed and replaced with
+ FX2 related logic. */
+static int i2c_24xxx_ir(struct pvr2_hdw *hdw,
+ u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
+{
+ u8 dat[4];
+ unsigned int stat;
+
+ if (!(rlen || wlen)) {
+ /* This is a probe attempt. Just let it succeed. */
+ return 0;
+ }
+
+ /* We don't understand this kind of transaction */
+ if ((wlen != 0) || (rlen == 0)) return -EIO;
+
+ if (rlen < 3) {
+ /* Mike Isely <isely@pobox.com> Appears to be a probe
+ attempt from lirc. Just fill in zeroes and return. If
+ we try instead to do the full transaction here, then bad
+ things seem to happen within the lirc driver module
+ (version 0.8.0-7 sources from Debian, when run under
+ vanilla 2.6.17.6 kernel) - and I don't have the patience
+ to chase it down. */
+ if (rlen > 0) rdata[0] = 0;
+ if (rlen > 1) rdata[1] = 0;
+ return 0;
+ }
+
+ /* Issue a command to the FX2 to read the IR receiver. */
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = 0xec;
+ stat = pvr2_send_request(hdw,
+ hdw->cmd_buffer,1,
+ hdw->cmd_buffer,4);
+ dat[0] = hdw->cmd_buffer[0];
+ dat[1] = hdw->cmd_buffer[1];
+ dat[2] = hdw->cmd_buffer[2];
+ dat[3] = hdw->cmd_buffer[3];
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
+
+ /* Give up if that operation failed. */
+ if (stat != 0) return stat;
+
+ /* Mangle the results into something that looks like the real IR
+ receiver. */
+ rdata[2] = 0xc1;
+ if (dat[0] != 1) {
+ /* No code received. */
+ rdata[0] = 0;
+ rdata[1] = 0;
+ } else {
+ u16 val;
+ /* Mash the FX2 firmware-provided IR code into something
+ that the normal i2c chip-level driver expects. */
+ val = dat[1];
+ val <<= 8;
+ val |= dat[2];
+ val >>= 1;
+ val &= ~0x0003;
+ val |= 0x8000;
+ rdata[0] = (val >> 8) & 0xffu;
+ rdata[1] = val & 0xffu;
+ }
+
+ return 0;
+}
+
/* 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
@@ -887,17 +960,17 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
{
unsigned int idx;
- // The default action for all possible I2C addresses is just to do
- // the transfer normally.
+ /* The default action for all possible I2C addresses is just to do
+ the transfer normally. */
for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
hdw->i2c_func[idx] = pvr2_i2c_basic_op;
}
- // If however we're dealing with new hardware, insert some hacks in
- // the I2C transfer stack to let things work better.
+ /* However, deal with various special cases for 24xxx hardware. */
if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
hdw->i2c_func[0x1b] = i2c_hack_wm8775;
hdw->i2c_func[0x44] = i2c_hack_cx25840;
+ hdw->i2c_func[0x18] = i2c_24xxx_ir;
}
// Configure the adapter and set up everything else related to it.
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index f28398dd9d9..c2374ed7ba9 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -851,7 +851,7 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
/* On 60Hz, it is using a higher Vertical Output Size */
if (!is_50hz)
- res+=(VRES_60HZ-480)>>1;
+ res += (VRES_60HZ - 480) >> 1;
/* height */
saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
@@ -907,7 +907,7 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
/* Activates task "B" */
saa711x_write(client, R_80_GLOBAL_CNTL_1,
- saa711x_read(client,R_80_GLOBAL_CNTL_1)|0x20);
+ saa711x_read(client,R_80_GLOBAL_CNTL_1) | 0x20);
return 0;
}
@@ -932,11 +932,11 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
if (std & V4L2_STD_525_60) {
v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
saa711x_writeregs(client, saa7115_cfg_60hz_video);
- saa711x_set_size(client,720,480);
+ saa711x_set_size(client, 720, 480);
} else {
v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
saa711x_writeregs(client, saa7115_cfg_50hz_video);
- saa711x_set_size(client,720,576);
+ saa711x_set_size(client, 720, 576);
}
/* Register 0E - Bits D6-D4 on NO-AUTO mode
@@ -1464,13 +1464,13 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
client->driver = &i2c_driver_saa711x;
snprintf(client->name, sizeof(client->name) - 1, "saa7115");
- for (i=0;i<0x0f;i++) {
+ 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] = (saa711x_read(client, 0) & 0x0f) + '0';
+ if (name[i] > '9')
+ name[i] += 'a' - '9' - 1;
}
- name[i]='\0';
+ name[i] = '\0';
saa711x_write(client, 0, 5);
chip_id = saa711x_read(client, 0) & 0x0f;
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 4abf5c03a74..ffb0f647a86 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -1,10 +1,6 @@
/*
* SAA713x ALSA support for V4L
*
- *
- * Caveats:
- * - Volume doesn't work (it's always at max)
- *
* This program is free software; 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
@@ -614,13 +610,18 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
snd_card_saa7134_pcm_t *pcm;
snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
struct saa7134_dev *dev = saa7134->dev;
- int err;
+ int amux, err;
mutex_lock(&dev->dmasound.lock);
dev->dmasound.read_count = 0;
dev->dmasound.read_offset = 0;
+ amux = dev->input->amux;
+ if ((amux < 1) || (amux > 3))
+ amux = 1;
+ dev->dmasound.input = amux - 1;
+
mutex_unlock(&dev->dmasound.lock);
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
@@ -713,6 +714,8 @@ static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol,
struct snd_ctl_elem_value * ucontrol)
{
snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ struct saa7134_dev *dev = chip->dev;
+
int change, addr = kcontrol->private_value;
int left, right;
@@ -727,10 +730,52 @@ static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol,
if (right > 20)
right = 20;
spin_lock_irq(&chip->mixer_lock);
- change = chip->mixer_volume[addr][0] != left ||
- chip->mixer_volume[addr][1] != right;
- chip->mixer_volume[addr][0] = left;
- chip->mixer_volume[addr][1] = right;
+ change = 0;
+ if (chip->mixer_volume[addr][0] != left) {
+ change = 1;
+ right = left;
+ }
+ if (chip->mixer_volume[addr][1] != right) {
+ change = 1;
+ left = right;
+ }
+ if (change) {
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ left = 20;
+ break;
+ case MIXER_ADDR_LINE1:
+ saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x10,
+ (left > 10) ? 0x00 : 0x10);
+ break;
+ case MIXER_ADDR_LINE2:
+ saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20,
+ (left > 10) ? 0x00 : 0x20);
+ break;
+ }
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ left = 20;
+ break;
+ case MIXER_ADDR_LINE1:
+ saa_andorb(0x0594, 0x10,
+ (left > 10) ? 0x00 : 0x10);
+ break;
+ case MIXER_ADDR_LINE2:
+ saa_andorb(0x0594, 0x20,
+ (left > 10) ? 0x00 : 0x20);
+ break;
+ }
+ break;
+ }
+ chip->mixer_volume[addr][0] = left;
+ chip->mixer_volume[addr][1] = right;
+ }
spin_unlock_irq(&chip->mixer_lock);
return change;
}
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 51f0cfdcb68..ae984bbe36b 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -2462,14 +2462,17 @@ struct saa7134_board saa7134_boards[] = {
.vmux = 1,
.amux = TV,
.tv = 1,
+ .gpio = 0x0000000,
},{
.name = name_comp1,
.vmux = 3,
.amux = LINE2,
+ .gpio = 0x0200000,
},{
.name = name_svideo,
.vmux = 8,
.amux = LINE2,
+ .gpio = 0x0200000,
}},
.radio = {
.name = name_radio,
@@ -2567,6 +2570,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .gpiomask = 1 << 21,
.inputs = {{
.name = name_tv,
.vmux = 1,
@@ -2575,15 +2579,20 @@ struct saa7134_board saa7134_boards[] = {
},{
.name = name_comp1,
.vmux = 3,
- .amux = LINE1,
+ .amux = LINE2, /* unconfirmed, taken from Philips driver */
+ },{
+ .name = name_comp2,
+ .vmux = 0, /* untested, Composite over S-Video */
+ .amux = LINE2,
},{
.name = name_svideo,
- .vmux = 0,
- .amux = LINE1,
+ .vmux = 8,
+ .amux = LINE2,
}},
.radio = {
.name = name_radio,
- .amux = LINE1,
+ .amux = TV,
+ .gpio = 0x0200000,
},
},
[SAA7134_BOARD_CINERGY250PCI] = {
@@ -3022,6 +3031,158 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
},
},
+ [SAA7134_BOARD_PINNACLE_PCTV_310i] = {
+ .name = "Pinnacle PCTV 310i",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x000200000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 4,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = name_comp2,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_STUDIO_507] = {
+ /* Mikhail Fedotov <mo_fedotov@mail.ru> */
+ .name = "Avermedia AVerTV Studio 507",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1256_IH3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x03,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x00,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x00,
+ },{
+ .name = name_comp2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x00,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x00,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ .gpio = 0x01,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ .gpio = 0x00,
+ },
+ },
+ [SAA7134_BOARD_VIDEOMATE_DVBT_200A] = {
+ /* Francis Barber <fedora@barber-family.id.au> */
+ .name = "Compro Videomate DVB-T200A",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_HAUPPAUGE_HVR1110] = {
+ /* Thomas Genty <tomlohave@gmail.com> */
+ .name = "Hauppauge WinTV-HVR1110 DVB-T/Hybrid",
+ .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 = 3,
+ .amux = LINE2, /* FIXME: audio doesn't work on svideo/composite */
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2, /* FIXME: audio doesn't work on svideo/composite */
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_CINERGY_HT_PCMCIA] = {
+ .name = "Terratec Cinergy HT PCMCIA",
+ .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 = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE1,
+ }},
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -3631,6 +3792,36 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x4860,
.driver_data = SAA7134_BOARD_ASUS_EUROPA2_HYBRID,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x11bd,
+ .subdevice = 0x002f,
+ .driver_data = SAA7134_BOARD_PINNACLE_PCTV_310i,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x9715,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1043,
+ .subdevice = 0x4876,
+ .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6701,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x153b,
+ .subdevice = 0x1172,
+ .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA,
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3717,6 +3908,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_305:
case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
case SAA7134_BOARD_AVERMEDIA_307:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
case SAA7134_BOARD_AVERMEDIA_777:
/* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */
@@ -3725,6 +3917,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
case SAA7134_BOARD_MANLI_MTV001:
case SAA7134_BOARD_MANLI_MTV002:
case SAA7134_BOARD_BEHOLD_409FM:
@@ -3793,7 +3986,9 @@ int saa7134_board_init1(struct saa7134_dev *dev)
break;
/* i2c remotes */
case SAA7134_BOARD_PINNACLE_PCTV_110i:
+ case SAA7134_BOARD_PINNACLE_PCTV_310i:
case SAA7134_BOARD_UPMOST_PURPLE_TV:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110:
dev->has_remote = SAA7134_REMOTE_I2C;
break;
case SAA7134_BOARD_AVERMEDIA_A169_B:
@@ -3924,9 +4119,11 @@ int saa7134_board_init2(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_PHILIPS_TIGER:
+ case SAA7134_BOARD_PINNACLE_PCTV_310i:
case SAA7134_BOARD_TEVION_DVBT_220RF:
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
case SAA7134_BOARD_MEDION_MD8800_QUADRO:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110:
/* this is a hybrid board, initialize to analog mode
* and configure firmware eeprom address
*/
@@ -3952,6 +4149,14 @@ int saa7134_board_init2(struct saa7134_dev *dev)
i2c_transfer(&dev->i2c_adap, &msg, 1);
}
break;
+ case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+ /* make the tda10046 find its eeprom */
+ {
+ u8 data[] = { 0x3c, 0x33, 0x60};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ }
+ break;
case SAA7134_BOARD_KWORLD_ATSC110:
{
/* enable tuner */
@@ -3964,6 +4169,29 @@ int saa7134_board_init2(struct saa7134_dev *dev)
dev->name, i);
}
break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+ /* The T200 and the T200A share the same pci id. Consequently,
+ * we are going to query eeprom to try to find out which one we
+ * are actually looking at. */
+
+ /* Don't do this if the board was specifically selected with an
+ * insmod option or if we have the default configuration T200*/
+ if(!dev->autodetected || (dev->eedata[0x41] == 0xd0))
+ break;
+ if(dev->eedata[0x41] == 0x02) {
+ /* Reconfigure board as T200A */
+ dev->board = SAA7134_BOARD_VIDEOMATE_DVBT_200A;
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+ dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
+ printk(KERN_INFO "%s: Reconfigured board as %s\n",
+ dev->name, saa7134_boards[dev->board].name);
+ } else {
+ printk(KERN_WARNING "%s: Unexpected tuner type info: %x in eeprom\n",
+ dev->name, dev->eedata[0x41]);
+ break;
+ }
+ break;
}
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 5c9e63dfbea..ed038fff3b4 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -889,15 +889,16 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
must_configure_manually();
dev->board = SAA7134_BOARD_UNKNOWN;
}
+ dev->autodetected = card[dev->nr] != dev->board;
dev->tuner_type = saa7134_boards[dev->board].tuner_type;
dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
if (UNSET != tuner[dev->nr])
dev->tuner_type = tuner[dev->nr];
- printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
- dev->name,pci_dev->subsystem_vendor,
- pci_dev->subsystem_device,saa7134_boards[dev->board].name,
- dev->board, card[dev->nr] == dev->board ?
- "insmod option" : "autodetected");
+ printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ dev->name,pci_dev->subsystem_vendor,
+ pci_dev->subsystem_device,saa7134_boards[dev->board].name,
+ dev->board, dev->autodetected ?
+ "autodetected" : "insmod option");
/* get mmio */
if (!request_mem_region(pci_resource_start(pci_dev,0),
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 6b61d9b2fcb..c33f6a69a24 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -50,6 +50,10 @@ static unsigned int antenna_pwr = 0;
module_param(antenna_pwr, int, 0444);
MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
+static int use_frontend = 0;
+module_param(use_frontend, int, 0644);
+MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)");
+
/* ------------------------------------------------------------------ */
static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
{
@@ -293,7 +297,7 @@ static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dv
return philips_tda6651_pll_set(0x60, fe, params);
}
-static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
+static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
const struct firmware **fw, char *name)
{
struct saa7134_dev *dev = fe->dvb->priv;
@@ -308,7 +312,7 @@ static struct tda1004x_config philips_tu1216_60_config = {
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .request_firmware = philips_tu1216_request_firmware,
+ .request_firmware = philips_tda1004x_request_firmware,
};
/* ------------------------------------------------------------------ */
@@ -331,12 +335,12 @@ static struct tda1004x_config philips_tu1216_61_config = {
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .request_firmware = philips_tu1216_request_firmware,
+ .request_firmware = philips_tda1004x_request_firmware,
};
/* ------------------------------------------------------------------ */
-static int philips_europa_tuner_init(struct dvb_frontend *fe)
+static int philips_td1316_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
@@ -347,18 +351,8 @@ static int philips_europa_tuner_init(struct dvb_frontend *fe)
fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
return -EIO;
- msleep(1);
-
- /* switch the board to dvb mode */
- init_msg.addr = 0x43;
- init_msg.len = 0x02;
- msg[0] = 0x00;
- msg[1] = 0x40;
if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
- return -EIO;
-
+ fe->ops.i2c_gate_ctrl(fe, 0);
return 0;
}
@@ -367,6 +361,22 @@ static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
return philips_tda6651_pll_set(0x61, fe, params);
}
+static int philips_europa_tuner_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 msg[] = { 0x00, 0x40};
+ struct i2c_msg init_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+
+ if (philips_td1316_tuner_init(fe))
+ return -EIO;
+ msleep(1);
+ if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
@@ -671,7 +681,7 @@ static struct tda1004x_config tda827x_lifeview_config = {
.invert = 1,
.invert_oclk = 0,
.xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
+ .agc_config = TDA10046_AGC_TDA827X_GP11,
.if_freq = TDA10046_FREQ_045,
.request_firmware = NULL,
};
@@ -812,32 +822,40 @@ static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe)
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
return 0;
}
/* ------------------------------------------------------------------ */
-static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tda8290_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
{
- 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)
+ if (enable) {
+ tda8290_msg.buf = tda8290_close;
+ } else {
+ tda8290_msg.buf = tda8290_open;
+ }
+ if (i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1) != 1)
return -EIO;
msleep(20);
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ int ret;
+
ret = philips_tda827xa_pll_set(0x61, 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;
+ return 0;
}
static int philips_tiger_tuner_init(struct dvb_frontend *fe)
@@ -867,13 +885,80 @@ static struct tda1004x_config philips_tiger_config = {
.invert = 1,
.invert_oclk = 0,
.xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
+ .agc_config = TDA10046_AGC_TDA827X_GP11,
+ .if_freq = TDA10046_FREQ_045,
+ .request_firmware = NULL,
+};
+/* ------------------------------------------------------------------ */
+
+static int cinergy_ht_tuner_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 data[] = { 0x3c, 0x33, 0x62};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static int cinergy_ht_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 data[] = { 0x3c, 0x33, 0x60};
+ 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 struct tda1004x_config cinergy_ht_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X_GP01,
.if_freq = TDA10046_FREQ_045,
.request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
+static struct tda1004x_config pinnacle_pctv_310i_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X_GP11,
+ .if_freq = TDA10046_FREQ_045,
+ .request_firmware = philips_tda1004x_request_firmware,
+};
+
+/* ------------------------------------------------------------------ */
+
+static struct tda1004x_config hauppauge_hvr_1110_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X_GP11,
+ .if_freq = TDA10046_FREQ_045,
+ .request_firmware = philips_tda1004x_request_firmware,
+};
+
+/* ------------------------------------------------------------------ */
+
+static struct tda1004x_config asus_p7131_dual_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X_GP11,
+ .if_freq = TDA10046_FREQ_045,
+ .request_firmware = philips_tda1004x_request_firmware,
+};
+
static int asus_p7131_dual_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
@@ -921,7 +1006,7 @@ static struct tda1004x_config lifeview_trio_config = {
.invert = 1,
.invert_oclk = 0,
.xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X_GPL,
+ .agc_config = TDA10046_AGC_TDA827X_GP00,
.if_freq = TDA10046_FREQ_045,
.request_firmware = NULL,
};
@@ -958,7 +1043,7 @@ static struct tda1004x_config ads_tech_duo_config = {
.invert = 1,
.invert_oclk = 0,
.xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X_GPL,
+ .agc_config = TDA10046_AGC_TDA827X_GP00,
.if_freq = TDA10046_FREQ_045,
.request_firmware = NULL,
};
@@ -983,7 +1068,7 @@ static struct tda1004x_config tevion_dvbt220rf_config = {
.invert = 1,
.invert_oclk = 0,
.xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
+ .agc_config = TDA10046_AGC_TDA827X_GP11,
.if_freq = TDA10046_FREQ_045,
.request_firmware = NULL,
};
@@ -1028,7 +1113,7 @@ static struct tda1004x_config md8800_dvbt_config = {
.invert = 1,
.invert_oclk = 0,
.xtal_freq = TDA10046_XTAL_16M,
- .agc_config = TDA10046_AGC_TDA827X,
+ .agc_config = TDA10046_AGC_TDA827X_GP11,
.if_freq = TDA10046_FREQ_045,
.request_firmware = NULL,
};
@@ -1168,6 +1253,29 @@ static int dvb_init(struct saa7134_dev *dev)
&philips_tiger_config,
&dev->i2c_adap);
if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+ 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.set_params = philips_tiger_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_PINNACLE_PCTV_310i:
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &pinnacle_pctv_310i_config,
+ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+ 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.set_params = philips_tiger_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &hauppauge_hvr_1110_config,
+ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
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.set_params = philips_tiger_tuner_set_params;
@@ -1175,9 +1283,10 @@ static int dvb_init(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
dev->dvb.frontend = dvb_attach(tda10046_attach,
- &philips_tiger_config,
+ &asus_p7131_dual_config,
&dev->i2c_adap);
if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
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;
@@ -1194,12 +1303,27 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_FLYDVB_TRIO:
- 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;
+ if(! use_frontend) { //terrestrial
+ 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;
+ }
+ } else { //satellite
+ dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
+ &dev->i2c_adap, 0) == NULL) {
+ printk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__);
+ }
+ if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
+ 0x08, 0, 0) == NULL) {
+ printk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__);
+ }
+ }
}
break;
case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
@@ -1281,7 +1405,27 @@ static int dvb_init(struct saa7134_dev *dev)
dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
}
break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+ 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_td1316_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &cinergy_ht_config,
+ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+ dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+ }
+ break;
default:
printk("%s: Huh? unknown DVB card?\n",dev->name);
break;
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 6162550c413..6f9fe86fed9 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -341,6 +341,7 @@ static int attach_inform(struct i2c_client *client)
switch (client->addr) {
case 0x7a:
case 0x47:
+ case 0x71:
{
struct IR_i2c *ir = i2c_get_clientdata(client);
d1printk("%s i2c IR detected (%s).\n",
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index dee83552e68..60b38defd9b 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -112,6 +112,27 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
+static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char buf[5], cod4, code3, code4;
+
+ /* poll IR chip */
+ if (5 != i2c_master_recv(&ir->c,buf,5))
+ return -EIO;
+
+ cod4 = buf[4];
+ code4 = (cod4 >> 2);
+ code3 = buf[3];
+ if (code3 == 0)
+ /* no key pressed */
+ return 0;
+
+ /* return key */
+ *ir_key = code4;
+ *ir_raw = code4;
+ return 1;
+}
+
void saa7134_input_irq(struct saa7134_dev *dev)
{
struct saa7134_ir *ir = dev->remote;
@@ -131,6 +152,23 @@ static void saa7134_input_timer(unsigned long data)
mod_timer(&ir->timer, timeout);
}
+static void saa7134_ir_start(struct saa7134_dev *dev, struct saa7134_ir *ir)
+{
+ if (ir->polling) {
+ init_timer(&ir->timer);
+ ir->timer.function = saa7134_input_timer;
+ ir->timer.data = (unsigned long)dev;
+ ir->timer.expires = jiffies + HZ;
+ add_timer(&ir->timer);
+ }
+}
+
+static void saa7134_ir_stop(struct saa7134_dev *dev)
+{
+ if (dev->remote->polling)
+ del_timer_sync(&dev->remote->timer);
+}
+
int saa7134_input_init1(struct saa7134_dev *dev)
{
struct saa7134_ir *ir;
@@ -141,6 +179,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
u32 mask_keyup = 0;
int polling = 0;
int ir_type = IR_TYPE_OTHER;
+ int err;
if (dev->has_remote != SAA7134_REMOTE_GPIO)
return -ENODEV;
@@ -184,6 +223,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_307:
case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
ir_codes = ir_codes_avermedia;
mask_keycode = 0x0007C8;
@@ -266,9 +306,8 @@ int saa7134_input_init1(struct saa7134_dev *dev)
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ir || !input_dev) {
- kfree(ir);
- input_free_device(input_dev);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto err_out_free;
}
ir->dev = input_dev;
@@ -299,18 +338,22 @@ int saa7134_input_init1(struct saa7134_dev *dev)
}
input_dev->cdev.dev = &dev->pci->dev;
- /* all done */
dev->remote = ir;
- if (ir->polling) {
- init_timer(&ir->timer);
- ir->timer.function = saa7134_input_timer;
- ir->timer.data = (unsigned long)dev;
- ir->timer.expires = jiffies + HZ;
- add_timer(&ir->timer);
- }
+ saa7134_ir_start(dev, ir);
+
+ err = input_register_device(ir->dev);
+ if (err)
+ goto err_out_stop;
- input_register_device(ir->dev);
return 0;
+
+ err_out_stop:
+ saa7134_ir_stop(dev);
+ dev->remote = NULL;
+ err_out_free:
+ input_free_device(input_dev);
+ kfree(ir);
+ return err;
}
void saa7134_input_fini(struct saa7134_dev *dev)
@@ -318,8 +361,7 @@ void saa7134_input_fini(struct saa7134_dev *dev)
if (NULL == dev->remote)
return;
- if (dev->remote->polling)
- del_timer_sync(&dev->remote->timer);
+ saa7134_ir_stop(dev);
input_unregister_device(dev->remote->dev);
kfree(dev->remote);
dev->remote = NULL;
@@ -335,6 +377,7 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_PCTV_110i:
+ case SAA7134_BOARD_PINNACLE_PCTV_310i:
snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
if (pinnacle_remote == 0) {
ir->get_key = get_key_pinnacle_color;
@@ -349,6 +392,11 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
ir->get_key = get_key_purpletv;
ir->ir_codes = ir_codes_purpletv;
break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+ snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110");
+ ir->get_key = get_key_hvr1110;
+ ir->ir_codes = ir_codes_hauppauge_new;
+ break;
default:
dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
break;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 7cf96b43025..e88ad7b40c4 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -227,6 +227,11 @@ struct saa7134_format {
#define SAA7134_BOARD_PROTEUS_2309 98
#define SAA7134_BOARD_AVERMEDIA_A16AR 99
#define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100
+#define SAA7134_BOARD_PINNACLE_PCTV_310i 101
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_507 102
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200A 103
+#define SAA7134_BOARD_HAUPPAUGE_HVR1110 104
+#define SAA7134_BOARD_CINERGY_HT_PCMCIA 105
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -446,6 +451,9 @@ struct saa7134_dev {
struct v4l2_prio_state prio;
#endif
+ /* insmod option/autodetected */
+ int autodetected;
+
/* various device info */
unsigned int resources;
struct video_device *video_dev;
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index 6d1ef1e2e8e..a1ec3aca3f9 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -687,7 +687,7 @@ static int stv680_start_stream (struct usb_stv *stv680)
stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
if (stv680->sbuf[i].data == NULL) {
PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
- return -1;
+ goto nomem_err;
}
}
@@ -698,7 +698,7 @@ static int stv680_start_stream (struct usb_stv *stv680)
stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
if (stv680->scratch[i].data == NULL) {
PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
- return -1;
+ goto nomem_err;
}
stv680->scratch[i].state = BUFFER_UNUSED;
}
@@ -706,7 +706,7 @@ static int stv680_start_stream (struct usb_stv *stv680)
for (i = 0; i < STV680_NUMSBUF; i++) {
urb = usb_alloc_urb (0, GFP_KERNEL);
if (!urb)
- return -ENOMEM;
+ goto nomem_err;
/* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
usb_fill_bulk_urb (urb, stv680->udev,
@@ -721,6 +721,21 @@ static int stv680_start_stream (struct usb_stv *stv680)
stv680->framecount = 0;
return 0;
+
+ nomem_err:
+ for (i = 0; i < STV680_NUMSCRATCH; i++) {
+ kfree(stv680->scratch[i].data);
+ stv680->scratch[i].data = NULL;
+ }
+ for (i = 0; i < STV680_NUMSBUF; i++) {
+ usb_kill_urb(stv680->urb[i]);
+ usb_free_urb(stv680->urb[i]);
+ stv680->urb[i] = NULL;
+ kfree(stv680->sbuf[i].data);
+ stv680->sbuf[i].data = NULL;
+ }
+ return -ENOMEM;
+
}
static int stv680_stop_stream (struct usb_stv *stv680)
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 87ffb0e84a7..fde576f1101 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -482,6 +482,12 @@ static int tda9887_set_config(struct tuner *t, char *buf)
buf[1] &= ~cQSS;
if (t->tda9887_config & TDA9887_GATING_18)
buf[3] &= ~cGating_36;
+
+ if (t->tda9887_config & TDA9887_GAIN_NORMAL) {
+ radio_stereo.e &= ~cTunerGainLow;
+ radio_mono.e &= ~cTunerGainLow;
+ }
+
return 0;
}
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 40590bae5ff..ee4a493032d 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -267,6 +267,10 @@ static int tuner_fixup_std(struct tuner *t)
{
if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
switch (pal[0]) {
+ case '6':
+ tuner_dbg ("insmod fixup: PAL => PAL-60\n");
+ t->std = V4L2_STD_PAL_60;
+ break;
case 'b':
case 'B':
case 'g':
@@ -443,6 +447,10 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
printk("%02x ",buffer[i]);
printk("\n");
}
+ /* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */
+ if (adap->id == I2C_HW_SAA7146 && addr < 0x4a)
+ return -ENODEV;
+
/* autodetection code based on the i2c addr */
if (!no_autodetect) {
switch (addr) {
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 63db4e97ae6..1b9b0742f75 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -108,6 +108,7 @@ static int tuner_stereo(struct i2c_client *c)
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FM1256_IH3:
+ case TUNER_LG_NTSC_TAPE:
stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
break;
default:
@@ -421,6 +422,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FMD1216ME_MK3:
+ case TUNER_LG_NTSC_TAPE:
buffer[3] = 0x19;
break;
case TUNER_TNF_5335MF:
@@ -465,6 +467,8 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
config |= TDA9887_INTERCARRIER;
/* if (params->port1_set_for_fm_mono)
config &= ~TDA9887_PORT1_ACTIVE;*/
+ if (params->fm_gain_normal)
+ config |= TDA9887_GAIN_NORMAL;
i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
}
if (4 != (rc = i2c_master_send(c,buffer,4)))
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 781682373b6..74c3e6f96f1 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -651,6 +651,7 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = {
.has_tda9887 = 1,
.port1_invert_for_secam_lc = 1,
.default_pll_gating_18 = 1,
+ .fm_gain_normal=1,
},
};
@@ -672,16 +673,6 @@ static struct tuner_params tuner_panasonic_vp27_params[] = {
},
};
-/* ------------ TUNER_LG_NTSC_TAPE - LGINNOTEK NTSC ------------ */
-
-static struct tuner_params tuner_lg_ntsc_tape_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_fm1236_mk3_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
- },
-};
-
/* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */
static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = {
@@ -1331,8 +1322,8 @@ struct tunertype tuners[] = {
},
[TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */
.name = "LG NTSC (TAPE series)",
- .params = tuner_lg_ntsc_tape_params,
- .count = ARRAY_SIZE(tuner_lg_ntsc_tape_params),
+ .params = tuner_fm1236_mk3_params,
+ .count = ARRAY_SIZE(tuner_fm1236_mk3_params),
},
[TUNER_TNF_8831BGFF] = { /* Philips PAL */
.name = "Tenna TNF 8831 BGFF)",
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 6b9ef731b83..4e7c1fa668d 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -184,7 +184,7 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Thompson DTT757"},
/* 80-89 */
{ TUNER_ABSENT, "Philips FQ1216LME MK3"},
- { TUNER_ABSENT, "LG TAPC G701D"},
+ { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
{ TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
@@ -430,7 +430,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tvee->has_radio = eeprom_data[i+len-1];
/* old style tag, don't know how to detect
IR presence, mark as unknown. */
- tvee->has_ir = 2;
+ tvee->has_ir = -1;
tvee->model =
eeprom_data[i+8] +
(eeprom_data[i+9] << 8);
@@ -653,13 +653,14 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
STRM(decoderIC, tvee->decoder_processor),
tvee->decoder_processor);
}
- if (tvee->has_ir == 2)
+ if (tvee->has_ir == -1)
tveeprom_info("has %sradio\n",
tvee->has_radio ? "" : "no ");
else
- tveeprom_info("has %sradio, has %sIR remote\n",
+ tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n",
tvee->has_radio ? "" : "no ",
- tvee->has_ir ? "" : "no ");
+ (tvee->has_ir & 1) ? "" : "no ",
+ (tvee->has_ir & 2) ? "" : "no ");
}
EXPORT_SYMBOL(tveeprom_hauppauge_analog);
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index bbf2beeeb44..ec0ff2247f0 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -86,6 +86,7 @@ MODULE_DEVICE_TABLE(usb, qcm_table);
static void qcm_register_input(struct qcm *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));
@@ -106,7 +107,13 @@ static void qcm_register_input(struct qcm *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 qcm_unregister_input(struct qcm *cam)
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.h b/drivers/media/video/usbvideo/quickcam_messenger.h
index baab9c081b5..17ace394d98 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.h
+++ b/drivers/media/video/usbvideo/quickcam_messenger.h
@@ -35,27 +35,13 @@ struct rgb {
};
struct bayL0 {
-#ifdef __BIG_ENDIAN
- u8 r;
- u8 g;
-#elif __LITTLE_ENDIAN
u8 g;
u8 r;
-#else
-#error not byte order defined
-#endif
};
struct bayL1 {
-#ifdef __BIG_ENDIAN
- u8 g;
- u8 b;
-#elif __LITTLE_ENDIAN
u8 b;
u8 g;
-#else
-#error not byte order defined
-#endif
};
struct cam_size {
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
index d8b88024bc2..b560c9d7c51 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/media/video/usbvideo/usbvideo.c
@@ -690,7 +690,7 @@ int usbvideo_register(
}
base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
- cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL);
+ cams = kzalloc(base_size, GFP_KERNEL);
if (cams == NULL) {
err("Failed to allocate %d. bytes for usbvideo struct", base_size);
return -ENOMEM;
diff --git a/drivers/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig
new file mode 100644
index 00000000000..fc24ef05b3f
--- /dev/null
+++ b/drivers/media/video/usbvision/Kconfig
@@ -0,0 +1,12 @@
+config VIDEO_USBVISION
+ tristate "USB video devices based on Nogatech NT1003/1004/1005"
+ depends on I2C && VIDEO_V4L2
+ select VIDEO_TUNER
+ select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
+ ---help---
+ There are more than 50 different USB video devices based on
+ NT1003/1004/1005 USB Bridges. This driver enables using those
+ devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbvision.
diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile
new file mode 100644
index 00000000000..9ac92a80c64
--- /dev/null
+++ b/drivers/media/video/usbvision/Makefile
@@ -0,0 +1,5 @@
+usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision-cards.o
+
+obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
new file mode 100644
index 00000000000..a40e5838515
--- /dev/null
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -0,0 +1,156 @@
+/*
+ * USBVISION.H
+ * usbvision header file
+ *
+ * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ *
+ * This module is part of usbvision driver project.
+ * Updates to driver completed by Dwaine P. Garden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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/list.h>
+#include <linux/i2c.h>
+#include <media/v4l2-dev.h>
+#include <media/tuner.h>
+#include "usbvision.h"
+
+/* Supported Devices: A table for usbvision.c*/
+struct usbvision_device_data_st usbvision_device_data[] = {
+ {0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"},
+ {0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "Xanboo"},
+ {0x050D, 0x0208, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Belkin USBView II"},
+ {0x0571, 0x0002, 0, CODEC_SAA7111, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, -1, -1, 7, "echoFX InterView Lite"},
+ {0x0573, 0x0003, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "USBGear USBG-V1 resp. HAMA USB"},
+ {0x0573, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "D-Link V100"},
+ {0x0573, 0x2000, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "X10 USB Camera"},
+ {0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, -1, 3, 7, "Osprey 50"},
+ {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Hauppauge USB-Live Model 600"},
+ {0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 2, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"},
+ {0x0573, 0x4100, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Nogatech USB-TV (NTSC) FM"},
+ {0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"},
+ {0x0573, 0x4450, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "PixelView PlayTv-USB PRO (PAL) FM"},
+ {0x0573, 0x4550, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "ZTV ZT-721 2.4GHz USB A/V Receiver"},
+ {0x0573, 0x4d00, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Hauppauge WinTv-USB USA"},
+ {0x0573, 0x4d01, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"},
+ {0x0573, 0x4d02, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC)"},
+ {0x0573, 0x4d03, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (SECAM) "},
+ {0x0573, 0x4d10, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC) FM"},
+ {0x0573, 0x4d11, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"},
+ {0x0573, 0x4d12, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"},
+ {0x0573, 0x4d2a, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B285"},
+ {0x0573, 0x4d2b, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B282"},
+ {0x0573, 0x4d2c, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (PAL/SECAM) 40209 Rev E1A5"},
+ {0x0573, 0x4d20, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226"},
+ {0x0573, 0x4d21, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL)"},
+ {0x0573, 0x4d22, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) MODEL 566"},
+ {0x0573, 0x4d23, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) 4D23"},
+ {0x0573, 0x4d25, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B234"},
+ {0x0573, 0x4d26, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B243"},
+ {0x0573, 0x4d27, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B281"},
+ {0x0573, 0x4d28, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B283"},
+ {0x0573, 0x4d29, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40205 Rev B298"},
+ {0x0573, 0x4d30, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB FM Model 40211 Rev B123"},
+ {0x0573, 0x4d31, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 568"},
+ {0x0573, 0x4d32, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 573"},
+ {0x0573, 0x4d35, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 40219 Rev B252"},
+ {0x0573, 0x4d37, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTV USB device Model 40219 Rev E189"},
+ {0x0768, 0x0006, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 5, 5, -1, "Camtel Technology USB TV Genie Pro FM Model TVB330"},
+ {0x07d0, 0x0001, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Digital Video Creator I"},
+ {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 82, 20, 7, "Global Village GV-007 (NTSC)"},
+ {0x07d0, 0x0003, 0, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)"},
+ {0x07d0, 0x0004, 0, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-80 Rev 1 (PAL)"},
+ {0x07d0, 0x0005, 0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"},
+ {0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"},
+ {0x2304, 0x0109, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (SECAM)"},
+ {0x2304, 0x0110, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1,128, 23, -1, "Pinnacle Studio PCTV USB (PAL) FM"},
+ {0x2304, 0x0111, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Miro PCTV USB"},
+ {0x2304, 0x0112, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (NTSC) FM"},
+ {0x2304, 0x0210, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"},
+ {0x2304, 0x0212, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_TEMIC_4039FR5_NTSC, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (NTSC) FM"},
+ {0x2304, 0x0214, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"},
+ {0x2304, 0x0300, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (NTSC)"},
+ {0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (PAL)"},
+ {0x2304, 0x0419, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle PCTV Bungee USB (PAL) FM"},
+ {0x2400, 0x4200, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"},
+ {} /* Terminating entry */
+};
+
+/* Supported Devices */
+
+struct usb_device_id usbvision_table [] = {
+ { USB_DEVICE(0xFFF0, 0xFFF0) }, /* Custom Dummy USBVision Device */
+ { USB_DEVICE(0x0A6F, 0x0400) }, /* Xanboo */
+ { USB_DEVICE(0x050d, 0x0208) }, /* Belkin USBView II */
+ { USB_DEVICE(0x0571, 0x0002) }, /* echoFX InterView Lite */
+ { USB_DEVICE(0x0573, 0x0003) }, /* USBGear USBG-V1 */
+ { USB_DEVICE(0x0573, 0x0400) }, /* D-Link V100 */
+ { USB_DEVICE(0x0573, 0x2000) }, /* X10 USB Camera */
+ { USB_DEVICE(0x0573, 0x2d00) }, /* Osprey 50 */
+ { USB_DEVICE(0x0573, 0x2d01) }, /* Hauppauge USB-Live Model 600 */
+ { USB_DEVICE(0x0573, 0x2101) }, /* Zoran Co. PMD (Nogatech) AV-grabber Manhattan */
+ { USB_DEVICE(0x0573, 0x4100) }, /* Nogatech USB-TV FM (NTSC) */
+ { USB_DEVICE(0x0573, 0x4110) }, /* PNY USB-TV (NTSC) FM */
+ { USB_DEVICE(0x0573, 0x4450) }, /* PixelView PlayTv-USB PRO (PAL) FM */
+ { USB_DEVICE(0x0573, 0x4550) }, /* ZTV ZT-721 2.4GHz USB A/V Receiver */
+ { USB_DEVICE(0x0573, 0x4d00) }, /* Hauppauge WinTv-USB USA */
+ { USB_DEVICE(0x0573, 0x4d01) }, /* Hauppauge WinTv-USB */
+ { USB_DEVICE(0x0573, 0x4d02) }, /* Hauppauge WinTv-USB UK */
+ { USB_DEVICE(0x0573, 0x4d03) }, /* Hauppauge WinTv-USB France */
+ { USB_DEVICE(0x0573, 0x4d10) }, /* Hauppauge WinTv-USB with FM USA radio */
+ { USB_DEVICE(0x0573, 0x4d11) }, /* Hauppauge WinTv-USB (PAL) with FM radio */
+ { USB_DEVICE(0x0573, 0x4d12) }, /* Hauppauge WinTv-USB UK with FM Radio */
+ { USB_DEVICE(0x0573, 0x4d2a) }, /* Hauppague WinTv USB Model 602 40201 Rev B285 */
+ { USB_DEVICE(0x0573, 0x4d2b) }, /* Hauppague WinTv USB Model 602 40201 Rev B282 */
+ { USB_DEVICE(0x0573, 0x4d2c) }, /* Hauppague WinTv USB Model 40209 Rev. E1A5 PAL*/
+ { USB_DEVICE(0x0573, 0x4d20) }, /* Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226 */
+ { USB_DEVICE(0x0573, 0x4d21) }, /* Hauppauge WinTv-USB II (PAL) with FM radio*/
+ { USB_DEVICE(0x0573, 0x4d22) }, /* Hauppauge WinTv-USB II (PAL) Model 566 */
+ { USB_DEVICE(0x0573, 0x4d23) }, /* Hauppauge WinTv-USB France 4D23*/
+ { USB_DEVICE(0x0573, 0x4d25) }, /* Hauppauge WinTv-USB Model 40209 rev B234 */
+ { USB_DEVICE(0x0573, 0x4d26) }, /* Hauppauge WinTv-USB Model 40209 Rev B243 */
+ { USB_DEVICE(0x0573, 0x4d27) }, /* Hauppauge WinTv-USB Model 40204 Rev B281 */
+ { USB_DEVICE(0x0573, 0x4d28) }, /* Hauppauge WinTv-USB Model 40204 Rev B283 */
+ { USB_DEVICE(0x0573, 0x4d29) }, /* Hauppauge WinTv-USB Model 40205 Rev B298 */
+ { USB_DEVICE(0x0573, 0x4d30) }, /* Hauppauge WinTv-USB FM Model 40211 Rev B123 */
+ { USB_DEVICE(0x0573, 0x4d31) }, /* Hauppauge WinTv-USB III (PAL) with FM radio Model 568 */
+ { USB_DEVICE(0x0573, 0x4d32) }, /* Hauppauge WinTv-USB III (PAL) FM Model 573 */
+ { USB_DEVICE(0x0573, 0x4d35) }, /* Hauppauge WinTv-USB III (SECAM) FM Model 40219 Rev B252 */
+ { USB_DEVICE(0x0573, 0x4d37) }, /* Hauppauge WinTv-USB Model 40219 Rev E189 */
+ { USB_DEVICE(0x0768, 0x0006) }, /* Camtel Technology USB TV Genie Pro FM Model TVB330 */
+ { USB_DEVICE(0x07d0, 0x0001) }, /* Digital Video Creator I */
+ { USB_DEVICE(0x07d0, 0x0002) }, /* Global Village GV-007 (NTSC) */
+ { USB_DEVICE(0x07d0, 0x0003) }, /* Dazzle Fusion Model DVC-50 Rev 1 (NTSC) */
+ { USB_DEVICE(0x07d0, 0x0004) }, /* Dazzle Fusion Model DVC-80 Rev 1 (PAL) */
+ { USB_DEVICE(0x07d0, 0x0005) }, /* Dazzle Fusion Model DVC-90 Rev 1 (SECAM) */
+ { USB_DEVICE(0x2304, 0x010d) }, /* Pinnacle Studio PCTV USB (PAL) */
+ { USB_DEVICE(0x2304, 0x0109) }, /* Pinnacle Studio PCTV USB (SECAM) */
+ { USB_DEVICE(0x2304, 0x0110) }, /* Pinnacle Studio PCTV USB (PAL) */
+ { USB_DEVICE(0x2304, 0x0111) }, /* Miro PCTV USB */
+ { USB_DEVICE(0x2304, 0x0112) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */
+ { USB_DEVICE(0x2304, 0x0210) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */
+ { USB_DEVICE(0x2304, 0x0212) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */
+ { USB_DEVICE(0x2304, 0x0214) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */
+ { USB_DEVICE(0x2304, 0x0300) }, /* Pinnacle Studio Linx Video input cable (NTSC) */
+ { USB_DEVICE(0x2304, 0x0301) }, /* Pinnacle Studio Linx Video input cable (PAL) */
+ { USB_DEVICE(0x2304, 0x0419) }, /* Pinnacle PCTV Bungee USB (PAL) FM */
+ { USB_DEVICE(0x2400, 0x4200) }, /* Hauppauge WinTv-USB2 Model 42012 */
+
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usbvision_table);
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
new file mode 100644
index 00000000000..a807d971e27
--- /dev/null
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -0,0 +1,2535 @@
+/*
+ * usbvision-core.c - driver for NT100x USB video capture devices
+ *
+ *
+ * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ * Dwaine Garden <dwainegarden@rogers.com>
+ *
+ * This module is part of usbvision driver project.
+ * Updates to driver completed by Dwaine P. Garden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/utsname.h>
+#include <linux/highmem.h>
+#include <linux/smp_lock.h>
+#include <linux/videodev.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <linux/videodev2.h>
+#include <linux/video_decoder.h>
+#include <linux/i2c.h>
+
+#include <media/saa7115.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/audiochip.h>
+
+#include <linux/moduleparam.h>
+#include <linux/workqueue.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include "usbvision.h"
+
+static unsigned int core_debug = 0;
+module_param(core_debug,int,0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+static unsigned int force_testpattern = 0;
+module_param(force_testpattern,int,0644);
+MODULE_PARM_DESC(force_testpattern,"enable test pattern display [core]");
+
+static int adjustCompression = 1; // Set the compression to be adaptive
+module_param(adjustCompression, int, 0444);
+MODULE_PARM_DESC(adjustCompression, " Set the ADPCM compression for the device. Default: 1 (On)");
+
+static int SwitchSVideoInput = 0; // To help people with Black and White output with using s-video input. Some cables and input device are wired differently.
+module_param(SwitchSVideoInput, int, 0444);
+MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)");
+
+#define ENABLE_HEXDUMP 0 /* Enable if you need it */
+
+
+#ifdef USBVISION_DEBUG
+ #define PDEBUG(level, fmt, args...) \
+ if (core_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+#else
+ #define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+#define DBG_HEADER 1<<0
+#define DBG_IRQ 1<<1
+#define DBG_ISOC 1<<2
+#define DBG_PARSE 1<<3
+#define DBG_SCRATCH 1<<4
+#define DBG_FUNC 1<<5
+
+static const int max_imgwidth = MAX_FRAME_WIDTH;
+static const int max_imgheight = MAX_FRAME_HEIGHT;
+static const int min_imgwidth = MIN_FRAME_WIDTH;
+static const int min_imgheight = MIN_FRAME_HEIGHT;
+
+/* The value of 'scratch_buf_size' affects quality of the picture
+ * in many ways. Shorter buffers may cause loss of data when client
+ * is too slow. Larger buffers are memory-consuming and take longer
+ * to work with. This setting can be adjusted, but the default value
+ * should be OK for most desktop users.
+ */
+#define DEFAULT_SCRATCH_BUF_SIZE (0x20000) // 128kB memory scratch buffer
+static const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE;
+
+// Function prototypes
+static int usbvision_request_intra (struct usb_usbvision *usbvision);
+static int usbvision_unrequest_intra (struct usb_usbvision *usbvision);
+static int usbvision_adjust_compression (struct usb_usbvision *usbvision);
+static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision);
+
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+/*
+ * Here we want the physical address of the memory.
+ * This is used when initializing the contents of the area.
+ */
+
+static void *usbvision_rvmalloc(unsigned long size)
+{
+ void *mem;
+ unsigned long adr;
+
+ size = PAGE_ALIGN(size);
+ mem = vmalloc_32(size);
+ if (!mem)
+ return NULL;
+
+ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+ adr = (unsigned long) mem;
+ while (size > 0) {
+ SetPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ return mem;
+}
+
+void usbvision_rvfree(void *mem, unsigned long size)
+{
+ unsigned long adr;
+
+ if (!mem)
+ return;
+
+ size = PAGE_ALIGN(size);
+
+ adr = (unsigned long) mem;
+ while ((long) size > 0) {
+ ClearPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vfree(mem);
+}
+
+
+
+#if ENABLE_HEXDUMP
+static void usbvision_hexdump(const unsigned char *data, int len)
+{
+ char tmp[80];
+ int i, k;
+
+ for (i = k = 0; len > 0; i++, len--) {
+ if (i > 0 && (i % 16 == 0)) {
+ printk("%s\n", tmp);
+ k = 0;
+ }
+ k += sprintf(&tmp[k], "%02x ", data[i]);
+ }
+ if (k > 0)
+ printk("%s\n", tmp);
+}
+#endif
+
+/********************************
+ * scratch ring buffer handling
+ ********************************/
+static int scratch_len(struct usb_usbvision *usbvision) /*This returns the amount of data actually in the buffer */
+{
+ int len = usbvision->scratch_write_ptr - usbvision->scratch_read_ptr;
+ if (len < 0) {
+ len += scratch_buf_size;
+ }
+ PDEBUG(DBG_SCRATCH, "scratch_len() = %d\n", len);
+
+ return len;
+}
+
+
+/* This returns the free space left in the buffer */
+static int scratch_free(struct usb_usbvision *usbvision)
+{
+ int free = usbvision->scratch_read_ptr - usbvision->scratch_write_ptr;
+ if (free <= 0) {
+ free += scratch_buf_size;
+ }
+ if (free) {
+ free -= 1; /* at least one byte in the buffer must */
+ /* left blank, otherwise there is no chance to differ between full and empty */
+ }
+ PDEBUG(DBG_SCRATCH, "return %d\n", free);
+
+ return free;
+}
+
+
+/* This puts data into the buffer */
+static int scratch_put(struct usb_usbvision *usbvision, unsigned char *data,
+ int len)
+{
+ int len_part;
+
+ if (usbvision->scratch_write_ptr + len < scratch_buf_size) {
+ memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len);
+ usbvision->scratch_write_ptr += len;
+ }
+ else {
+ len_part = scratch_buf_size - usbvision->scratch_write_ptr;
+ memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len_part);
+ if (len == len_part) {
+ usbvision->scratch_write_ptr = 0; /* just set write_ptr to zero */
+ }
+ else {
+ memcpy(usbvision->scratch, data + len_part, len - len_part);
+ usbvision->scratch_write_ptr = len - len_part;
+ }
+ }
+
+ PDEBUG(DBG_SCRATCH, "len=%d, new write_ptr=%d\n", len, usbvision->scratch_write_ptr);
+
+ return len;
+}
+
+/* This marks the write_ptr as position of new frame header */
+static void scratch_mark_header(struct usb_usbvision *usbvision)
+{
+ PDEBUG(DBG_SCRATCH, "header at write_ptr=%d\n", usbvision->scratch_headermarker_write_ptr);
+
+ usbvision->scratch_headermarker[usbvision->scratch_headermarker_write_ptr] =
+ usbvision->scratch_write_ptr;
+ usbvision->scratch_headermarker_write_ptr += 1;
+ usbvision->scratch_headermarker_write_ptr %= USBVISION_NUM_HEADERMARKER;
+}
+
+/* This gets data from the buffer at the given "ptr" position */
+static int scratch_get_extra(struct usb_usbvision *usbvision,
+ unsigned char *data, int *ptr, int len)
+{
+ int len_part;
+ if (*ptr + len < scratch_buf_size) {
+ memcpy(data, usbvision->scratch + *ptr, len);
+ *ptr += len;
+ }
+ else {
+ len_part = scratch_buf_size - *ptr;
+ memcpy(data, usbvision->scratch + *ptr, len_part);
+ if (len == len_part) {
+ *ptr = 0; /* just set the y_ptr to zero */
+ }
+ else {
+ memcpy(data + len_part, usbvision->scratch, len - len_part);
+ *ptr = len - len_part;
+ }
+ }
+
+ PDEBUG(DBG_SCRATCH, "len=%d, new ptr=%d\n", len, *ptr);
+
+ return len;
+}
+
+
+/* This sets the scratch extra read pointer */
+static void scratch_set_extra_ptr(struct usb_usbvision *usbvision, int *ptr,
+ int len)
+{
+ *ptr = (usbvision->scratch_read_ptr + len)%scratch_buf_size;
+
+ PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr);
+}
+
+
+/*This increments the scratch extra read pointer */
+static void scratch_inc_extra_ptr(int *ptr, int len)
+{
+ *ptr = (*ptr + len) % scratch_buf_size;
+
+ PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr);
+}
+
+
+/* This gets data from the buffer */
+static int scratch_get(struct usb_usbvision *usbvision, unsigned char *data,
+ int len)
+{
+ int len_part;
+ if (usbvision->scratch_read_ptr + len < scratch_buf_size) {
+ memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len);
+ usbvision->scratch_read_ptr += len;
+ }
+ else {
+ len_part = scratch_buf_size - usbvision->scratch_read_ptr;
+ memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len_part);
+ if (len == len_part) {
+ usbvision->scratch_read_ptr = 0; /* just set the read_ptr to zero */
+ }
+ else {
+ memcpy(data + len_part, usbvision->scratch, len - len_part);
+ usbvision->scratch_read_ptr = len - len_part;
+ }
+ }
+
+ PDEBUG(DBG_SCRATCH, "len=%d, new read_ptr=%d\n", len, usbvision->scratch_read_ptr);
+
+ return len;
+}
+
+
+/* This sets read pointer to next header and returns it */
+static int scratch_get_header(struct usb_usbvision *usbvision,
+ struct usbvision_frame_header *header)
+{
+ int errCode = 0;
+
+ PDEBUG(DBG_SCRATCH, "from read_ptr=%d", usbvision->scratch_headermarker_read_ptr);
+
+ while (usbvision->scratch_headermarker_write_ptr -
+ usbvision->scratch_headermarker_read_ptr != 0) {
+ usbvision->scratch_read_ptr =
+ usbvision->scratch_headermarker[usbvision->scratch_headermarker_read_ptr];
+ usbvision->scratch_headermarker_read_ptr += 1;
+ usbvision->scratch_headermarker_read_ptr %= USBVISION_NUM_HEADERMARKER;
+ scratch_get(usbvision, (unsigned char *)header, USBVISION_HEADER_LENGTH);
+ if ((header->magic_1 == USBVISION_MAGIC_1)
+ && (header->magic_2 == USBVISION_MAGIC_2)
+ && (header->headerLength == USBVISION_HEADER_LENGTH)) {
+ errCode = USBVISION_HEADER_LENGTH;
+ header->frameWidth = header->frameWidthLo + (header->frameWidthHi << 8);
+ header->frameHeight = header->frameHeightLo + (header->frameHeightHi << 8);
+ break;
+ }
+ }
+
+ return errCode;
+}
+
+
+/*This removes len bytes of old data from the buffer */
+static void scratch_rm_old(struct usb_usbvision *usbvision, int len)
+{
+
+ usbvision->scratch_read_ptr += len;
+ usbvision->scratch_read_ptr %= scratch_buf_size;
+ PDEBUG(DBG_SCRATCH, "read_ptr is now %d\n", usbvision->scratch_read_ptr);
+}
+
+
+/*This resets the buffer - kills all data in it too */
+static void scratch_reset(struct usb_usbvision *usbvision)
+{
+ PDEBUG(DBG_SCRATCH, "\n");
+
+ usbvision->scratch_read_ptr = 0;
+ usbvision->scratch_write_ptr = 0;
+ usbvision->scratch_headermarker_read_ptr = 0;
+ usbvision->scratch_headermarker_write_ptr = 0;
+ usbvision->isocstate = IsocState_NoFrame;
+}
+
+int usbvision_scratch_alloc(struct usb_usbvision *usbvision)
+{
+ usbvision->scratch = vmalloc_32(scratch_buf_size);
+ scratch_reset(usbvision);
+ if(usbvision->scratch == NULL) {
+ err("%s: unable to allocate %d bytes for scratch",
+ __FUNCTION__, scratch_buf_size);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void usbvision_scratch_free(struct usb_usbvision *usbvision)
+{
+ if (usbvision->scratch != NULL) {
+ vfree(usbvision->scratch);
+ usbvision->scratch = NULL;
+ }
+}
+
+/*
+ * usbvision_testpattern()
+ *
+ * Procedure forms a test pattern (yellow grid on blue background).
+ *
+ * Parameters:
+ * fullframe: if TRUE then entire frame is filled, otherwise the procedure
+ * continues from the current scanline.
+ * pmode 0: fill the frame with solid blue color (like on VCR or TV)
+ * 1: Draw a colored grid
+ *
+ */
+static void usbvision_testpattern(struct usb_usbvision *usbvision,
+ int fullframe, int pmode)
+{
+ static const char proc[] = "usbvision_testpattern";
+ struct usbvision_frame *frame;
+ unsigned char *f;
+ int num_cell = 0;
+ int scan_length = 0;
+ static int num_pass = 0;
+
+ if (usbvision == NULL) {
+ printk(KERN_ERR "%s: usbvision == NULL\n", proc);
+ return;
+ }
+ if (usbvision->curFrame == NULL) {
+ printk(KERN_ERR "%s: usbvision->curFrame is NULL.\n", proc);
+ return;
+ }
+
+ /* Grab the current frame */
+ frame = usbvision->curFrame;
+
+ /* Optionally start at the beginning */
+ if (fullframe) {
+ frame->curline = 0;
+ frame->scanlength = 0;
+ }
+
+ /* Form every scan line */
+ for (; frame->curline < frame->frmheight; frame->curline++) {
+ int i;
+
+ f = frame->data + (usbvision->curwidth * 3 * frame->curline);
+ for (i = 0; i < usbvision->curwidth; i++) {
+ unsigned char cb = 0x80;
+ unsigned char cg = 0;
+ unsigned char cr = 0;
+
+ if (pmode == 1) {
+ if (frame->curline % 32 == 0)
+ cb = 0, cg = cr = 0xFF;
+ else if (i % 32 == 0) {
+ if (frame->curline % 32 == 1)
+ num_cell++;
+ cb = 0, cg = cr = 0xFF;
+ } else {
+ cb =
+ ((num_cell * 7) +
+ num_pass) & 0xFF;
+ cg =
+ ((num_cell * 5) +
+ num_pass * 2) & 0xFF;
+ cr =
+ ((num_cell * 3) +
+ num_pass * 3) & 0xFF;
+ }
+ } else {
+ /* Just the blue screen */
+ }
+
+ *f++ = cb;
+ *f++ = cg;
+ *f++ = cr;
+ scan_length += 3;
+ }
+ }
+
+ frame->grabstate = FrameState_Done;
+ frame->scanlength += scan_length;
+ ++num_pass;
+
+}
+
+/*
+ * usbvision_decompress_alloc()
+ *
+ * allocates intermediate buffer for decompression
+ */
+int usbvision_decompress_alloc(struct usb_usbvision *usbvision)
+{
+ int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2;
+ usbvision->IntraFrameBuffer = vmalloc_32(IFB_size);
+ if (usbvision->IntraFrameBuffer == NULL) {
+ err("%s: unable to allocate %d for compr. frame buffer", __FUNCTION__, IFB_size);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ * usbvision_decompress_free()
+ *
+ * frees intermediate buffer for decompression
+ */
+void usbvision_decompress_free(struct usb_usbvision *usbvision)
+{
+ if (usbvision->IntraFrameBuffer != NULL) {
+ vfree(usbvision->IntraFrameBuffer);
+ usbvision->IntraFrameBuffer = NULL;
+ }
+}
+
+/************************************************************
+ * Here comes the data parsing stuff that is run as interrupt
+ ************************************************************/
+/*
+ * usbvision_find_header()
+ *
+ * Locate one of supported header markers in the scratch buffer.
+ */
+static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision)
+{
+ struct usbvision_frame *frame;
+ int foundHeader = 0;
+
+ frame = usbvision->curFrame;
+
+ while (scratch_get_header(usbvision, &frame->isocHeader) == USBVISION_HEADER_LENGTH) {
+ // found header in scratch
+ PDEBUG(DBG_HEADER, "found header: 0x%02x%02x %d %d %d %d %#x 0x%02x %u %u",
+ frame->isocHeader.magic_2,
+ frame->isocHeader.magic_1,
+ frame->isocHeader.headerLength,
+ frame->isocHeader.frameNum,
+ frame->isocHeader.framePhase,
+ frame->isocHeader.frameLatency,
+ frame->isocHeader.dataFormat,
+ frame->isocHeader.formatParam,
+ frame->isocHeader.frameWidth,
+ frame->isocHeader.frameHeight);
+
+ if (usbvision->requestIntra) {
+ if (frame->isocHeader.formatParam & 0x80) {
+ foundHeader = 1;
+ usbvision->lastIsocFrameNum = -1; // do not check for lost frames this time
+ usbvision_unrequest_intra(usbvision);
+ break;
+ }
+ }
+ else {
+ foundHeader = 1;
+ break;
+ }
+ }
+
+ if (foundHeader) {
+ frame->frmwidth = frame->isocHeader.frameWidth * usbvision->stretch_width;
+ frame->frmheight = frame->isocHeader.frameHeight * usbvision->stretch_height;
+ frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth)>> 3;
+ }
+ else { // no header found
+ PDEBUG(DBG_HEADER, "skipping scratch data, no header");
+ scratch_reset(usbvision);
+ return ParseState_EndParse;
+ }
+
+ // found header
+ if (frame->isocHeader.dataFormat==ISOC_MODE_COMPRESS) {
+ //check isocHeader.frameNum for lost frames
+ if (usbvision->lastIsocFrameNum >= 0) {
+ if (((usbvision->lastIsocFrameNum + 1) % 32) != frame->isocHeader.frameNum) {
+ // unexpected frame drop: need to request new intra frame
+ PDEBUG(DBG_HEADER, "Lost frame before %d on USB", frame->isocHeader.frameNum);
+ usbvision_request_intra(usbvision);
+ return ParseState_NextFrame;
+ }
+ }
+ usbvision->lastIsocFrameNum = frame->isocHeader.frameNum;
+ }
+ usbvision->header_count++;
+ frame->scanstate = ScanState_Lines;
+ frame->curline = 0;
+
+ if (force_testpattern) {
+ usbvision_testpattern(usbvision, 1, 1);
+ return ParseState_NextFrame;
+ }
+ return ParseState_Continue;
+}
+
+static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision,
+ long *pcopylen)
+{
+ volatile struct usbvision_frame *frame;
+ unsigned char *f;
+ int len;
+ int i;
+ unsigned char yuyv[4]={180, 128, 10, 128}; // YUV components
+ unsigned char rv, gv, bv; // RGB components
+ int clipmask_index, bytes_per_pixel;
+ int stretch_bytes, clipmask_add;
+
+ frame = usbvision->curFrame;
+ f = frame->data + (frame->v4l2_linesize * frame->curline);
+
+ /* Make sure there's enough data for the entire line */
+ len = (frame->isocHeader.frameWidth * 2)+5;
+ if (scratch_len(usbvision) < len) {
+ PDEBUG(DBG_PARSE, "out of data in line %d, need %u.\n", frame->curline, len);
+ return ParseState_Out;
+ }
+
+ if ((frame->curline + 1) >= frame->frmheight) {
+ return ParseState_NextFrame;
+ }
+
+ bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
+ stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel;
+ clipmask_index = frame->curline * MAX_FRAME_WIDTH;
+ clipmask_add = usbvision->stretch_width;
+
+ for (i = 0; i < frame->frmwidth; i+=(2 * usbvision->stretch_width)) {
+
+ scratch_get(usbvision, &yuyv[0], 4);
+
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ *f++ = yuyv[0]; // Y
+ *f++ = yuyv[3]; // U
+ }
+ else {
+
+ YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv);
+ switch (frame->v4l2_format.format) {
+ case V4L2_PIX_FMT_RGB565:
+ *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
+ *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv);
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ *f++ = bv;
+ *f++ = gv;
+ *f++ = rv;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ *f++ = bv;
+ *f++ = gv;
+ *f++ = rv;
+ f++;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
+ *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
+ break;
+ }
+ }
+ clipmask_index += clipmask_add;
+ f += stretch_bytes;
+
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ *f++ = yuyv[2]; // Y
+ *f++ = yuyv[1]; // V
+ }
+ else {
+
+ YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv);
+ switch (frame->v4l2_format.format) {
+ case V4L2_PIX_FMT_RGB565:
+ *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
+ *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv);
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ *f++ = bv;
+ *f++ = gv;
+ *f++ = rv;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ *f++ = bv;
+ *f++ = gv;
+ *f++ = rv;
+ f++;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
+ *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
+ break;
+ }
+ }
+ clipmask_index += clipmask_add;
+ f += stretch_bytes;
+ }
+
+ frame->curline += usbvision->stretch_height;
+ *pcopylen += frame->v4l2_linesize * usbvision->stretch_height;
+
+ if (frame->curline >= frame->frmheight) {
+ return ParseState_NextFrame;
+ }
+ else {
+ return ParseState_Continue;
+ }
+}
+
+/* The decompression routine */
+static int usbvision_decompress(struct usb_usbvision *usbvision,unsigned char *Compressed,
+ unsigned char *Decompressed, int *StartPos,
+ int *BlockTypeStartPos, int Len)
+{
+ int RestPixel, Idx, MaxPos, Pos, ExtraPos, BlockLen, BlockTypePos, BlockTypeLen;
+ unsigned char BlockByte, BlockCode, BlockType, BlockTypeByte, Integrator;
+
+ Integrator = 0;
+ Pos = *StartPos;
+ BlockTypePos = *BlockTypeStartPos;
+ MaxPos = 396; //Pos + Len;
+ ExtraPos = Pos;
+ BlockLen = 0;
+ BlockByte = 0;
+ BlockCode = 0;
+ BlockType = 0;
+ BlockTypeByte = 0;
+ BlockTypeLen = 0;
+ RestPixel = Len;
+
+ for (Idx = 0; Idx < Len; Idx++) {
+
+ if (BlockLen == 0) {
+ if (BlockTypeLen==0) {
+ BlockTypeByte = Compressed[BlockTypePos];
+ BlockTypePos++;
+ BlockTypeLen = 4;
+ }
+ BlockType = (BlockTypeByte & 0xC0) >> 6;
+
+ //statistic:
+ usbvision->ComprBlockTypes[BlockType]++;
+
+ Pos = ExtraPos;
+ if (BlockType == 0) {
+ if(RestPixel >= 24) {
+ Idx += 23;
+ RestPixel -= 24;
+ Integrator = Decompressed[Idx];
+ } else {
+ Idx += RestPixel - 1;
+ RestPixel = 0;
+ }
+ } else {
+ BlockCode = Compressed[Pos];
+ Pos++;
+ if (RestPixel >= 24) {
+ BlockLen = 24;
+ } else {
+ BlockLen = RestPixel;
+ }
+ RestPixel -= BlockLen;
+ ExtraPos = Pos + (BlockLen / 4);
+ }
+ BlockTypeByte <<= 2;
+ BlockTypeLen -= 1;
+ }
+ if (BlockLen > 0) {
+ if ((BlockLen%4) == 0) {
+ BlockByte = Compressed[Pos];
+ Pos++;
+ }
+ if (BlockType == 1) { //inter Block
+ Integrator = Decompressed[Idx];
+ }
+ switch (BlockByte & 0xC0) {
+ case 0x03<<6:
+ Integrator += Compressed[ExtraPos];
+ ExtraPos++;
+ break;
+ case 0x02<<6:
+ Integrator += BlockCode;
+ break;
+ case 0x00:
+ Integrator -= BlockCode;
+ break;
+ }
+ Decompressed[Idx] = Integrator;
+ BlockByte <<= 2;
+ BlockLen -= 1;
+ }
+ }
+ *StartPos = ExtraPos;
+ *BlockTypeStartPos = BlockTypePos;
+ return Idx;
+}
+
+
+/*
+ * usbvision_parse_compress()
+ *
+ * Parse compressed frame from the scratch buffer, put
+ * decoded RGB value into the current frame buffer and add the written
+ * number of bytes (RGB) to the *pcopylen.
+ *
+ */
+static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
+ long *pcopylen)
+{
+#define USBVISION_STRIP_MAGIC 0x5A
+#define USBVISION_STRIP_LEN_MAX 400
+#define USBVISION_STRIP_HEADER_LEN 3
+
+ struct usbvision_frame *frame;
+ unsigned char *f,*u = NULL ,*v = NULL;
+ unsigned char StripData[USBVISION_STRIP_LEN_MAX];
+ unsigned char StripHeader[USBVISION_STRIP_HEADER_LEN];
+ int Idx, IdxEnd, StripLen, StripPtr, StartBlockPos, BlockPos, BlockTypePos;
+ int clipmask_index, bytes_per_pixel, rc;
+ int imageSize;
+ unsigned char rv, gv, bv;
+ static unsigned char *Y, *U, *V;
+
+ frame = usbvision->curFrame;
+ imageSize = frame->frmwidth * frame->frmheight;
+ if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) ||
+ (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) { // this is a planar format
+ //... v4l2_linesize not used here.
+ f = frame->data + (frame->width * frame->curline);
+ } else
+ f = frame->data + (frame->v4l2_linesize * frame->curline);
+
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV){ //initialise u and v pointers
+ // get base of u and b planes add halfoffset
+
+ u = frame->data
+ + imageSize
+ + (frame->frmwidth >>1) * frame->curline ;
+ v = u + (imageSize >>1 );
+
+ } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420){
+
+ v = frame->data + imageSize + ((frame->curline* (frame->width))>>2) ;
+ u = v + (imageSize >>2) ;
+ }
+
+ if (frame->curline == 0) {
+ usbvision_adjust_compression(usbvision);
+ }
+
+ if (scratch_len(usbvision) < USBVISION_STRIP_HEADER_LEN) {
+ return ParseState_Out;
+ }
+
+ //get strip header without changing the scratch_read_ptr
+ scratch_set_extra_ptr(usbvision, &StripPtr, 0);
+ scratch_get_extra(usbvision, &StripHeader[0], &StripPtr,
+ USBVISION_STRIP_HEADER_LEN);
+
+ if (StripHeader[0] != USBVISION_STRIP_MAGIC) {
+ // wrong strip magic
+ usbvision->stripMagicErrors++;
+ return ParseState_NextFrame;
+ }
+
+ if (frame->curline != (int)StripHeader[2]) {
+ //line number missmatch error
+ usbvision->stripLineNumberErrors++;
+ }
+
+ StripLen = 2 * (unsigned int)StripHeader[1];
+ if (StripLen > USBVISION_STRIP_LEN_MAX) {
+ // strip overrun
+ // I think this never happens
+ usbvision_request_intra(usbvision);
+ }
+
+ if (scratch_len(usbvision) < StripLen) {
+ //there is not enough data for the strip
+ return ParseState_Out;
+ }
+
+ if (usbvision->IntraFrameBuffer) {
+ Y = usbvision->IntraFrameBuffer + frame->frmwidth * frame->curline;
+ U = usbvision->IntraFrameBuffer + imageSize + (frame->frmwidth / 2) * (frame->curline / 2);
+ V = usbvision->IntraFrameBuffer + imageSize / 4 * 5 + (frame->frmwidth / 2) * (frame->curline / 2);
+ }
+ else {
+ return ParseState_NextFrame;
+ }
+
+ bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
+ clipmask_index = frame->curline * MAX_FRAME_WIDTH;
+
+ scratch_get(usbvision, StripData, StripLen);
+
+ IdxEnd = frame->frmwidth;
+ BlockTypePos = USBVISION_STRIP_HEADER_LEN;
+ StartBlockPos = BlockTypePos + (IdxEnd - 1) / 96 + (IdxEnd / 2 - 1) / 96 + 2;
+ BlockPos = StartBlockPos;
+
+ usbvision->BlockPos = BlockPos;
+
+ if ((rc = usbvision_decompress(usbvision, StripData, Y, &BlockPos, &BlockTypePos, IdxEnd)) != IdxEnd) {
+ //return ParseState_Continue;
+ }
+ if (StripLen > usbvision->maxStripLen) {
+ usbvision->maxStripLen = StripLen;
+ }
+
+ if (frame->curline%2) {
+ if ((rc = usbvision_decompress(usbvision, StripData, V, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) {
+ //return ParseState_Continue;
+ }
+ }
+ else {
+ if ((rc = usbvision_decompress(usbvision, StripData, U, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) {
+ //return ParseState_Continue;
+ }
+ }
+
+ if (BlockPos > usbvision->comprBlockPos) {
+ usbvision->comprBlockPos = BlockPos;
+ }
+ if (BlockPos > StripLen) {
+ usbvision->stripLenErrors++;
+ }
+
+ for (Idx = 0; Idx < IdxEnd; Idx++) {
+ if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ *f++ = Y[Idx];
+ *f++ = Idx & 0x01 ? U[Idx/2] : V[Idx/2];
+ }
+ else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) {
+ *f++ = Y[Idx];
+ if ( Idx & 0x01)
+ *u++ = U[Idx>>1] ;
+ else
+ *v++ = V[Idx>>1];
+ }
+ else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) {
+ *f++ = Y [Idx];
+ if ( !(( Idx & 0x01 ) | ( frame->curline & 0x01 )) ){
+
+/* only need do this for 1 in 4 pixels */
+/* intraframe buffer is YUV420 format */
+
+ *u++ = U[Idx >>1];
+ *v++ = V[Idx >>1];
+ }
+
+ }
+ else {
+ YUV_TO_RGB_BY_THE_BOOK(Y[Idx], U[Idx/2], V[Idx/2], rv, gv, bv);
+ switch (frame->v4l2_format.format) {
+ case V4L2_PIX_FMT_GREY:
+ *f++ = Y[Idx];
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
+ *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
+ *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv);
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ *f++ = bv;
+ *f++ = gv;
+ *f++ = rv;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ *f++ = bv;
+ *f++ = gv;
+ *f++ = rv;
+ f++;
+ break;
+ }
+ }
+ clipmask_index++;
+ }
+ /* Deal with non-integer no. of bytes for YUV420P */
+ if (frame->v4l2_format.format != V4L2_PIX_FMT_YVU420 )
+ *pcopylen += frame->v4l2_linesize;
+ else
+ *pcopylen += frame->curline & 0x01 ? frame->v4l2_linesize : frame->v4l2_linesize << 1;
+
+ frame->curline += 1;
+
+ if (frame->curline >= frame->frmheight) {
+ return ParseState_NextFrame;
+ }
+ else {
+ return ParseState_Continue;
+ }
+
+}
+
+
+/*
+ * usbvision_parse_lines_420()
+ *
+ * Parse two lines from the scratch buffer, put
+ * decoded RGB value into the current frame buffer and add the written
+ * number of bytes (RGB) to the *pcopylen.
+ *
+ */
+static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision,
+ long *pcopylen)
+{
+ struct usbvision_frame *frame;
+ unsigned char *f_even = NULL, *f_odd = NULL;
+ unsigned int pixel_per_line, block;
+ int pixel, block_split;
+ int y_ptr, u_ptr, v_ptr, y_odd_offset;
+ const int y_block_size = 128;
+ const int uv_block_size = 64;
+ const int sub_block_size = 32;
+ const int y_step[] = { 0, 0, 0, 2 }, y_step_size = 4;
+ const int uv_step[]= { 0, 0, 0, 4 }, uv_step_size = 4;
+ unsigned char y[2], u, v; /* YUV components */
+ int y_, u_, v_, vb, uvg, ur;
+ int r_, g_, b_; /* RGB components */
+ unsigned char g;
+ int clipmask_even_index, clipmask_odd_index, bytes_per_pixel;
+ int clipmask_add, stretch_bytes;
+
+ frame = usbvision->curFrame;
+ f_even = frame->data + (frame->v4l2_linesize * frame->curline);
+ f_odd = f_even + frame->v4l2_linesize * usbvision->stretch_height;
+
+ /* Make sure there's enough data for the entire line */
+ /* In this mode usbvision transfer 3 bytes for every 2 pixels */
+ /* I need two lines to decode the color */
+ bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
+ stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel;
+ clipmask_even_index = frame->curline * MAX_FRAME_WIDTH;
+ clipmask_odd_index = clipmask_even_index + MAX_FRAME_WIDTH;
+ clipmask_add = usbvision->stretch_width;
+ pixel_per_line = frame->isocHeader.frameWidth;
+
+ if (scratch_len(usbvision) < (int)pixel_per_line * 3) {
+ //printk(KERN_DEBUG "out of data, need %d\n", len);
+ return ParseState_Out;
+ }
+
+ if ((frame->curline + 1) >= frame->frmheight) {
+ return ParseState_NextFrame;
+ }
+
+ block_split = (pixel_per_line%y_block_size) ? 1 : 0; //are some blocks splitted into different lines?
+
+ y_odd_offset = (pixel_per_line / y_block_size) * (y_block_size + uv_block_size)
+ + block_split * uv_block_size;
+
+ scratch_set_extra_ptr(usbvision, &y_ptr, y_odd_offset);
+ scratch_set_extra_ptr(usbvision, &u_ptr, y_block_size);
+ scratch_set_extra_ptr(usbvision, &v_ptr, y_odd_offset
+ + (4 - block_split) * sub_block_size);
+
+ for (block = 0; block < (pixel_per_line / sub_block_size);
+ block++) {
+
+
+ for (pixel = 0; pixel < sub_block_size; pixel +=2) {
+ scratch_get(usbvision, &y[0], 2);
+ scratch_get_extra(usbvision, &u, &u_ptr, 1);
+ scratch_get_extra(usbvision, &v, &v_ptr, 1);
+
+ //I don't use the YUV_TO_RGB macro for better performance
+ v_ = v - 128;
+ u_ = u - 128;
+ vb = 132252 * v_;
+ uvg= -53281 * u_ - 25625 * v_;
+ ur = 104595 * u_;
+
+ if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ *f_even++ = y[0];
+ *f_even++ = v;
+ }
+ else {
+ y_ = 76284 * (y[0] - 16);
+
+ b_ = (y_ + vb) >> 16;
+ g_ = (y_ + uvg)>> 16;
+ r_ = (y_ + ur) >> 16;
+
+ switch (frame->v4l2_format.format) {
+ case V4L2_PIX_FMT_RGB565:
+ g = LIMIT_RGB(g_);
+ *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+ *f_even++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_));
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ *f_even++ = LIMIT_RGB(b_);
+ *f_even++ = LIMIT_RGB(g_);
+ *f_even++ = LIMIT_RGB(r_);
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ *f_even++ = LIMIT_RGB(b_);
+ *f_even++ = LIMIT_RGB(g_);
+ *f_even++ = LIMIT_RGB(r_);
+ f_even++;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ g = LIMIT_RGB(g_);
+ *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+ *f_even++ = (0x03 & ( g >> 6)) |
+ (0x7C & (LIMIT_RGB(r_) >> 1));
+ break;
+ }
+ }
+ clipmask_even_index += clipmask_add;
+ f_even += stretch_bytes;
+
+ if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ *f_even++ = y[1];
+ *f_even++ = u;
+ }
+ else {
+ y_ = 76284 * (y[1] - 16);
+
+ b_ = (y_ + vb) >> 16;
+ g_ = (y_ + uvg)>> 16;
+ r_ = (y_ + ur) >> 16;
+
+ switch (frame->v4l2_format.format) {
+ case V4L2_PIX_FMT_RGB565:
+ g = LIMIT_RGB(g_);
+ *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+ *f_even++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_));
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ *f_even++ = LIMIT_RGB(b_);
+ *f_even++ = LIMIT_RGB(g_);
+ *f_even++ = LIMIT_RGB(r_);
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ *f_even++ = LIMIT_RGB(b_);
+ *f_even++ = LIMIT_RGB(g_);
+ *f_even++ = LIMIT_RGB(r_);
+ f_even++;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ g = LIMIT_RGB(g_);
+ *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+ *f_even++ = (0x03 & ( g >> 6)) |
+ (0x7C & (LIMIT_RGB(r_) >> 1));
+ break;
+ }
+ }
+ clipmask_even_index += clipmask_add;
+ f_even += stretch_bytes;
+
+ scratch_get_extra(usbvision, &y[0], &y_ptr, 2);
+
+ if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ *f_odd++ = y[0];
+ *f_odd++ = v;
+ }
+ else {
+ y_ = 76284 * (y[0] - 16);
+
+ b_ = (y_ + vb) >> 16;
+ g_ = (y_ + uvg)>> 16;
+ r_ = (y_ + ur) >> 16;
+
+ switch (frame->v4l2_format.format) {
+ case V4L2_PIX_FMT_RGB565:
+ g = LIMIT_RGB(g_);
+ *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+ *f_odd++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_));
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ *f_odd++ = LIMIT_RGB(b_);
+ *f_odd++ = LIMIT_RGB(g_);
+ *f_odd++ = LIMIT_RGB(r_);
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ *f_odd++ = LIMIT_RGB(b_);
+ *f_odd++ = LIMIT_RGB(g_);
+ *f_odd++ = LIMIT_RGB(r_);
+ f_odd++;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ g = LIMIT_RGB(g_);
+ *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+ *f_odd++ = (0x03 & ( g >> 6)) |
+ (0x7C & (LIMIT_RGB(r_) >> 1));
+ break;
+ }
+ }
+ clipmask_odd_index += clipmask_add;
+ f_odd += stretch_bytes;
+
+ if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ *f_odd++ = y[1];
+ *f_odd++ = u;
+ }
+ else {
+ y_ = 76284 * (y[1] - 16);
+
+ b_ = (y_ + vb) >> 16;
+ g_ = (y_ + uvg)>> 16;
+ r_ = (y_ + ur) >> 16;
+
+ switch (frame->v4l2_format.format) {
+ case V4L2_PIX_FMT_RGB565:
+ g = LIMIT_RGB(g_);
+ *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+ *f_odd++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_));
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ *f_odd++ = LIMIT_RGB(b_);
+ *f_odd++ = LIMIT_RGB(g_);
+ *f_odd++ = LIMIT_RGB(r_);
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ *f_odd++ = LIMIT_RGB(b_);
+ *f_odd++ = LIMIT_RGB(g_);
+ *f_odd++ = LIMIT_RGB(r_);
+ f_odd++;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ g = LIMIT_RGB(g_);
+ *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+ *f_odd++ = (0x03 & ( g >> 6)) |
+ (0x7C & (LIMIT_RGB(r_) >> 1));
+ break;
+ }
+ }
+ clipmask_odd_index += clipmask_add;
+ f_odd += stretch_bytes;
+ }
+
+ scratch_rm_old(usbvision,y_step[block % y_step_size] * sub_block_size);
+ scratch_inc_extra_ptr(&y_ptr, y_step[(block + 2 * block_split) % y_step_size]
+ * sub_block_size);
+ scratch_inc_extra_ptr(&u_ptr, uv_step[block % uv_step_size]
+ * sub_block_size);
+ scratch_inc_extra_ptr(&v_ptr, uv_step[(block + 2 * block_split) % uv_step_size]
+ * sub_block_size);
+ }
+
+ scratch_rm_old(usbvision, pixel_per_line * 3 / 2
+ + block_split * sub_block_size);
+
+ frame->curline += 2 * usbvision->stretch_height;
+ *pcopylen += frame->v4l2_linesize * 2 * usbvision->stretch_height;
+
+ if (frame->curline >= frame->frmheight)
+ return ParseState_NextFrame;
+ else
+ return ParseState_Continue;
+}
+
+/*
+ * usbvision_parse_data()
+ *
+ * Generic routine to parse the scratch buffer. It employs either
+ * usbvision_find_header() or usbvision_parse_lines() to do most
+ * of work.
+ *
+ */
+static void usbvision_parse_data(struct usb_usbvision *usbvision)
+{
+ struct usbvision_frame *frame;
+ enum ParseState newstate;
+ long copylen = 0;
+ unsigned long lock_flags;
+
+ frame = usbvision->curFrame;
+
+ PDEBUG(DBG_PARSE, "parsing len=%d\n", scratch_len(usbvision));
+
+ while (1) {
+
+ newstate = ParseState_Out;
+ if (scratch_len(usbvision)) {
+ if (frame->scanstate == ScanState_Scanning) {
+ newstate = usbvision_find_header(usbvision);
+ }
+ else if (frame->scanstate == ScanState_Lines) {
+ if (usbvision->isocMode == ISOC_MODE_YUV420) {
+ newstate = usbvision_parse_lines_420(usbvision, &copylen);
+ }
+ else if (usbvision->isocMode == ISOC_MODE_YUV422) {
+ newstate = usbvision_parse_lines_422(usbvision, &copylen);
+ }
+ else if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+ newstate = usbvision_parse_compress(usbvision, &copylen);
+ }
+
+ }
+ }
+ if (newstate == ParseState_Continue) {
+ continue;
+ }
+ else if ((newstate == ParseState_NextFrame) || (newstate == ParseState_Out)) {
+ break;
+ }
+ else {
+ return; /* ParseState_EndParse */
+ }
+ }
+
+ if (newstate == ParseState_NextFrame) {
+ frame->grabstate = FrameState_Done;
+ do_gettimeofday(&(frame->timestamp));
+ frame->sequence = usbvision->frame_num;
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ list_move_tail(&(frame->frame), &usbvision->outqueue);
+ usbvision->curFrame = NULL;
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ usbvision->frame_num++;
+
+ /* This will cause the process to request another frame. */
+ if (waitqueue_active(&usbvision->wait_frame)) {
+ PDEBUG(DBG_PARSE, "Wake up !");
+ wake_up_interruptible(&usbvision->wait_frame);
+ }
+ }
+ else
+ frame->grabstate = FrameState_Grabbing;
+
+
+ /* Update the frame's uncompressed length. */
+ frame->scanlength += copylen;
+}
+
+
+/*
+ * Make all of the blocks of data contiguous
+ */
+static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
+ struct urb *urb)
+{
+ unsigned char *packet_data;
+ int i, totlen = 0;
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int packet_len = urb->iso_frame_desc[i].actual_length;
+ int packet_stat = urb->iso_frame_desc[i].status;
+
+ packet_data = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+ /* Detect and ignore errored packets */
+ if (packet_stat) { // packet_stat != 0 ?????????????
+ PDEBUG(DBG_ISOC, "data error: [%d] len=%d, status=%X", i, packet_len, packet_stat);
+ usbvision->isocErrCount++;
+ continue;
+ }
+
+ /* Detect and ignore empty packets */
+ if (packet_len < 0) {
+ PDEBUG(DBG_ISOC, "error packet [%d]", i);
+ usbvision->isocSkipCount++;
+ continue;
+ }
+ else if (packet_len == 0) { /* Frame end ????? */
+ PDEBUG(DBG_ISOC, "null packet [%d]", i);
+ usbvision->isocstate=IsocState_NoFrame;
+ usbvision->isocSkipCount++;
+ continue;
+ }
+ else if (packet_len > usbvision->isocPacketSize) {
+ PDEBUG(DBG_ISOC, "packet[%d] > isocPacketSize", i);
+ usbvision->isocSkipCount++;
+ continue;
+ }
+
+ PDEBUG(DBG_ISOC, "packet ok [%d] len=%d", i, packet_len);
+
+ if (usbvision->isocstate==IsocState_NoFrame) { //new frame begins
+ usbvision->isocstate=IsocState_InFrame;
+ scratch_mark_header(usbvision);
+ usbvision_measure_bandwidth(usbvision);
+ PDEBUG(DBG_ISOC, "packet with header");
+ }
+
+ /*
+ * If usbvision continues to feed us with data but there is no
+ * consumption (if, for example, V4L client fell asleep) we
+ * may overflow the buffer. We have to move old data over to
+ * free room for new data. This is bad for old data. If we
+ * just drop new data then it's bad for new data... choose
+ * your favorite evil here.
+ */
+ if (scratch_free(usbvision) < packet_len) {
+
+ usbvision->scratch_ovf_count++;
+ PDEBUG(DBG_ISOC, "scratch buf overflow! scr_len: %d, n: %d",
+ scratch_len(usbvision), packet_len);
+ scratch_rm_old(usbvision, packet_len - scratch_free(usbvision));
+ }
+
+ /* Now we know that there is enough room in scratch buffer */
+ scratch_put(usbvision, packet_data, packet_len);
+ totlen += packet_len;
+ usbvision->isocDataCount += packet_len;
+ usbvision->isocPacketCount++;
+ }
+#if ENABLE_HEXDUMP
+ if (totlen > 0) {
+ static int foo = 0;
+ if (foo < 1) {
+ printk(KERN_DEBUG "+%d.\n", usbvision->scratchlen);
+ usbvision_hexdump(data0, (totlen > 64) ? 64 : totlen);
+ ++foo;
+ }
+ }
+#endif
+ return totlen;
+}
+
+static void usbvision_isocIrq(struct urb *urb)
+{
+ int errCode = 0;
+ int len;
+ struct usb_usbvision *usbvision = urb->context;
+ int i;
+ unsigned long startTime = jiffies;
+ struct usbvision_frame **f;
+
+ /* We don't want to do anything if we are about to be removed! */
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return;
+
+ f = &usbvision->curFrame;
+
+ /* Manage streaming interruption */
+ if (usbvision->streaming == Stream_Interrupt) {
+ usbvision->streaming = Stream_Idle;
+ if ((*f)) {
+ (*f)->grabstate = FrameState_Ready;
+ (*f)->scanstate = ScanState_Scanning;
+ }
+ PDEBUG(DBG_IRQ, "stream interrupted");
+ wake_up_interruptible(&usbvision->wait_stream);
+ }
+
+ /* Copy the data received into our scratch buffer */
+ len = usbvision_compress_isochronous(usbvision, urb);
+
+ usbvision->isocUrbCount++;
+ usbvision->urb_length = len;
+
+ if (usbvision->streaming == Stream_On) {
+
+ /* If we collected enough data let's parse! */
+ if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH) { /* 12 == header_length */
+ /*If we don't have a frame we're current working on, complain */
+ if(!list_empty(&(usbvision->inqueue))) {
+ if (!(*f)) {
+ (*f) = list_entry(usbvision->inqueue.next,struct usbvision_frame, frame);
+ }
+ usbvision_parse_data(usbvision);
+ }
+ else {
+ PDEBUG(DBG_IRQ, "received data, but no one needs it");
+ scratch_reset(usbvision);
+ }
+ }
+ }
+ else {
+ PDEBUG(DBG_IRQ, "received data, but no one needs it");
+ scratch_reset(usbvision);
+ }
+
+ usbvision->timeInIrq += jiffies - startTime;
+
+ for (i = 0; i < USBVISION_URB_FRAMES; i++) {
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+
+ urb->status = 0;
+ urb->dev = usbvision->dev;
+ errCode = usb_submit_urb (urb, GFP_ATOMIC);
+
+ /* Disable this warning. By design of the driver. */
+ // if(errCode) {
+ // err("%s: usb_submit_urb failed: error %d", __FUNCTION__, errCode);
+ // }
+
+ return;
+}
+
+/*************************************/
+/* Low level usbvision access functions */
+/*************************************/
+
+/*
+ * usbvision_read_reg()
+ *
+ * return < 0 -> Error
+ * >= 0 -> Data
+ */
+
+int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg)
+{
+ int errCode = 0;
+ unsigned char buffer[1];
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return -1;
+
+ errCode = usb_control_msg(usbvision->dev, usb_rcvctrlpipe(usbvision->dev, 1),
+ USBVISION_OP_CODE,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+ 0, (__u16) reg, buffer, 1, HZ);
+
+ if (errCode < 0) {
+ err("%s: failed: error %d", __FUNCTION__, errCode);
+ return errCode;
+ }
+ return buffer[0];
+}
+
+/*
+ * usbvision_write_reg()
+ *
+ * return 1 -> Reg written
+ * 0 -> usbvision is not yet ready
+ * -1 -> Something went wrong
+ */
+
+int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
+ unsigned char value)
+{
+ int errCode = 0;
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return 0;
+
+ errCode = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ USBVISION_OP_CODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_ENDPOINT, 0, (__u16) reg, &value, 1, HZ);
+
+ if (errCode < 0) {
+ err("%s: failed: error %d", __FUNCTION__, errCode);
+ }
+ return errCode;
+}
+
+
+static void usbvision_ctrlUrb_complete(struct urb *urb)
+{
+ struct usb_usbvision *usbvision = (struct usb_usbvision *)urb->context;
+
+ PDEBUG(DBG_IRQ, "");
+ usbvision->ctrlUrbBusy = 0;
+ if (waitqueue_active(&usbvision->ctrlUrb_wq)) {
+ wake_up_interruptible(&usbvision->ctrlUrb_wq);
+ }
+}
+
+
+static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address,
+ unsigned char *data, int len)
+{
+ int errCode = 0;
+
+ PDEBUG(DBG_IRQ, "");
+ if (len > 8) {
+ return -EFAULT;
+ }
+// down(&usbvision->ctrlUrbLock);
+ if (usbvision->ctrlUrbBusy) {
+// up(&usbvision->ctrlUrbLock);
+ return -EBUSY;
+ }
+ usbvision->ctrlUrbBusy = 1;
+// up(&usbvision->ctrlUrbLock);
+
+ usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
+ usbvision->ctrlUrbSetup.bRequest = USBVISION_OP_CODE;
+ usbvision->ctrlUrbSetup.wValue = 0;
+ usbvision->ctrlUrbSetup.wIndex = cpu_to_le16(address);
+ usbvision->ctrlUrbSetup.wLength = cpu_to_le16(len);
+ usb_fill_control_urb (usbvision->ctrlUrb, usbvision->dev,
+ usb_sndctrlpipe(usbvision->dev, 1),
+ (unsigned char *)&usbvision->ctrlUrbSetup,
+ (void *)usbvision->ctrlUrbBuffer, len,
+ usbvision_ctrlUrb_complete,
+ (void *)usbvision);
+
+ memcpy(usbvision->ctrlUrbBuffer, data, len);
+
+ errCode = usb_submit_urb(usbvision->ctrlUrb, GFP_ATOMIC);
+ if (errCode < 0) {
+ // error in usb_submit_urb()
+ usbvision->ctrlUrbBusy = 0;
+ }
+ PDEBUG(DBG_IRQ, "submit %d byte: error %d", len, errCode);
+ return errCode;
+}
+
+
+static int usbvision_init_compression(struct usb_usbvision *usbvision)
+{
+ int errCode = 0;
+
+ usbvision->lastIsocFrameNum = -1;
+ usbvision->isocDataCount = 0;
+ usbvision->isocPacketCount = 0;
+ usbvision->isocSkipCount = 0;
+ usbvision->comprLevel = 50;
+ usbvision->lastComprLevel = -1;
+ usbvision->isocUrbCount = 0;
+ usbvision->requestIntra = 1;
+ usbvision->isocMeasureBandwidthCount = 0;
+
+ return errCode;
+}
+
+/* this function measures the used bandwidth since last call
+ * return: 0 : no error
+ * sets usedBandwidth to 1-100 : 1-100% of full bandwidth resp. to isocPacketSize
+ */
+static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision)
+{
+ int errCode = 0;
+
+ if (usbvision->isocMeasureBandwidthCount < 2) { // this gives an average bandwidth of 3 frames
+ usbvision->isocMeasureBandwidthCount++;
+ return errCode;
+ }
+ if ((usbvision->isocPacketSize > 0) && (usbvision->isocPacketCount > 0)) {
+ usbvision->usedBandwidth = usbvision->isocDataCount /
+ (usbvision->isocPacketCount + usbvision->isocSkipCount) *
+ 100 / usbvision->isocPacketSize;
+ }
+ usbvision->isocMeasureBandwidthCount = 0;
+ usbvision->isocDataCount = 0;
+ usbvision->isocPacketCount = 0;
+ usbvision->isocSkipCount = 0;
+ return errCode;
+}
+
+static int usbvision_adjust_compression (struct usb_usbvision *usbvision)
+{
+ int errCode = 0;
+ unsigned char buffer[6];
+
+ PDEBUG(DBG_IRQ, "");
+ if ((adjustCompression) && (usbvision->usedBandwidth > 0)) {
+ usbvision->comprLevel += (usbvision->usedBandwidth - 90) / 2;
+ RESTRICT_TO_RANGE(usbvision->comprLevel, 0, 100);
+ if (usbvision->comprLevel != usbvision->lastComprLevel) {
+ int distorsion;
+ if (usbvision->bridgeType == BRIDGE_NT1004 || usbvision->bridgeType == BRIDGE_NT1005) {
+ buffer[0] = (unsigned char)(4 + 16 * usbvision->comprLevel / 100); // PCM Threshold 1
+ buffer[1] = (unsigned char)(4 + 8 * usbvision->comprLevel / 100); // PCM Threshold 2
+ distorsion = 7 + 248 * usbvision->comprLevel / 100;
+ buffer[2] = (unsigned char)(distorsion & 0xFF); // Average distorsion Threshold (inter)
+ buffer[3] = (unsigned char)(distorsion & 0xFF); // Average distorsion Threshold (intra)
+ distorsion = 1 + 42 * usbvision->comprLevel / 100;
+ buffer[4] = (unsigned char)(distorsion & 0xFF); // Maximum distorsion Threshold (inter)
+ buffer[5] = (unsigned char)(distorsion & 0xFF); // Maximum distorsion Threshold (intra)
+ }
+ else { //BRIDGE_NT1003
+ buffer[0] = (unsigned char)(4 + 16 * usbvision->comprLevel / 100); // PCM threshold 1
+ buffer[1] = (unsigned char)(4 + 8 * usbvision->comprLevel / 100); // PCM threshold 2
+ distorsion = 2 + 253 * usbvision->comprLevel / 100;
+ buffer[2] = (unsigned char)(distorsion & 0xFF); // distorsion threshold bit0-7
+ buffer[3] = 0; //(unsigned char)((distorsion >> 8) & 0x0F); // distorsion threshold bit 8-11
+ distorsion = 0 + 43 * usbvision->comprLevel / 100;
+ buffer[4] = (unsigned char)(distorsion & 0xFF); // maximum distorsion bit0-7
+ buffer[5] = 0; //(unsigned char)((distorsion >> 8) & 0x01); // maximum distorsion bit 8
+ }
+ errCode = usbvision_write_reg_irq(usbvision, USBVISION_PCM_THR1, buffer, 6);
+ if (errCode == 0){
+ PDEBUG(DBG_IRQ, "new compr params %#02x %#02x %#02x %#02x %#02x %#02x", buffer[0],
+ buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
+ usbvision->lastComprLevel = usbvision->comprLevel;
+ }
+ }
+ }
+ return errCode;
+}
+
+static int usbvision_request_intra (struct usb_usbvision *usbvision)
+{
+ int errCode = 0;
+ unsigned char buffer[1];
+
+ PDEBUG(DBG_IRQ, "");
+ usbvision->requestIntra = 1;
+ buffer[0] = 1;
+ usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1);
+ return errCode;
+}
+
+static int usbvision_unrequest_intra (struct usb_usbvision *usbvision)
+{
+ int errCode = 0;
+ unsigned char buffer[1];
+
+ PDEBUG(DBG_IRQ, "");
+ usbvision->requestIntra = 0;
+ buffer[0] = 0;
+ usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1);
+ return errCode;
+}
+
+/*******************************
+ * usbvision utility functions
+ *******************************/
+
+int usbvision_power_off(struct usb_usbvision *usbvision)
+{
+ int errCode = 0;
+
+ PDEBUG(DBG_FUNC, "");
+
+ errCode = usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN);
+ if (errCode == 1) {
+ usbvision->power = 0;
+ }
+ PDEBUG(DBG_FUNC, "%s: errCode %d", (errCode!=1)?"ERROR":"power is off", errCode);
+ return errCode;
+}
+
+/*
+ * usbvision_set_video_format()
+ *
+ */
+static int usbvision_set_video_format(struct usb_usbvision *usbvision, int format)
+{
+ static const char proc[] = "usbvision_set_video_format";
+ int rc;
+ unsigned char value[2];
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return 0;
+
+ PDEBUG(DBG_FUNC, "isocMode %#02x", format);
+
+ if ((format != ISOC_MODE_YUV422)
+ && (format != ISOC_MODE_YUV420)
+ && (format != ISOC_MODE_COMPRESS)) {
+ printk(KERN_ERR "usbvision: unknown video format %02x, using default YUV420",
+ format);
+ format = ISOC_MODE_YUV420;
+ }
+ value[0] = 0x0A; //TODO: See the effect of the filter
+ value[1] = format;
+ rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ USBVISION_OP_CODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_ENDPOINT, 0,
+ (__u16) USBVISION_FILT_CONT, value, 2, HZ);
+
+ if (rc < 0) {
+ printk(KERN_ERR "%s: ERROR=%d. USBVISION stopped - "
+ "reconnect or reload driver.\n", proc, rc);
+ }
+ usbvision->isocMode = format;
+ return rc;
+}
+
+/*
+ * usbvision_set_output()
+ *
+ */
+
+int usbvision_set_output(struct usb_usbvision *usbvision, int width,
+ int height)
+{
+ int errCode = 0;
+ int UsbWidth, UsbHeight;
+ unsigned int frameRate=0, frameDrop=0;
+ unsigned char value[4];
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision)) {
+ return 0;
+ }
+
+ if (width > MAX_USB_WIDTH) {
+ UsbWidth = width / 2;
+ usbvision->stretch_width = 2;
+ }
+ else {
+ UsbWidth = width;
+ usbvision->stretch_width = 1;
+ }
+
+ if (height > MAX_USB_HEIGHT) {
+ UsbHeight = height / 2;
+ usbvision->stretch_height = 2;
+ }
+ else {
+ UsbHeight = height;
+ usbvision->stretch_height = 1;
+ }
+
+ RESTRICT_TO_RANGE(UsbWidth, MIN_FRAME_WIDTH, MAX_USB_WIDTH);
+ UsbWidth &= ~(MIN_FRAME_WIDTH-1);
+ RESTRICT_TO_RANGE(UsbHeight, MIN_FRAME_HEIGHT, MAX_USB_HEIGHT);
+ UsbHeight &= ~(1);
+
+ PDEBUG(DBG_FUNC, "usb %dx%d; screen %dx%d; stretch %dx%d",
+ UsbWidth, UsbHeight, width, height,
+ usbvision->stretch_width, usbvision->stretch_height);
+
+ /* I'll not rewrite the same values */
+ if ((UsbWidth != usbvision->curwidth) || (UsbHeight != usbvision->curheight)) {
+ value[0] = UsbWidth & 0xff; //LSB
+ value[1] = (UsbWidth >> 8) & 0x03; //MSB
+ value[2] = UsbHeight & 0xff; //LSB
+ value[3] = (UsbHeight >> 8) & 0x03; //MSB
+
+ errCode = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ USBVISION_OP_CODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+ 0, (__u16) USBVISION_LXSIZE_O, value, 4, HZ);
+
+ if (errCode < 0) {
+ err("%s failed: error %d", __FUNCTION__, errCode);
+ return errCode;
+ }
+ usbvision->curwidth = usbvision->stretch_width * UsbWidth;
+ usbvision->curheight = usbvision->stretch_height * UsbHeight;
+ }
+
+ if (usbvision->isocMode == ISOC_MODE_YUV422) {
+ frameRate = (usbvision->isocPacketSize * 1000) / (UsbWidth * UsbHeight * 2);
+ }
+ else if (usbvision->isocMode == ISOC_MODE_YUV420) {
+ frameRate = (usbvision->isocPacketSize * 1000) / ((UsbWidth * UsbHeight * 12) / 8);
+ }
+ else {
+ frameRate = FRAMERATE_MAX;
+ }
+
+ if (usbvision->tvnorm->id & V4L2_STD_625_50) {
+ frameDrop = frameRate * 32 / 25 - 1;
+ }
+ else if (usbvision->tvnorm->id & V4L2_STD_525_60) {
+ frameDrop = frameRate * 32 / 30 - 1;
+ }
+
+ RESTRICT_TO_RANGE(frameDrop, FRAMERATE_MIN, FRAMERATE_MAX);
+
+ PDEBUG(DBG_FUNC, "frameRate %d fps, frameDrop %d", frameRate, frameDrop);
+
+ frameDrop = FRAMERATE_MAX; // We can allow the maximum here, because dropping is controlled
+
+ /* frameDrop = 7; => framePhase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ...
+ => frameSkip = 4;
+ => frameRate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
+
+ frameDrop = 9; => framePhase = 1, 5, 8, 11, 14, 17, 21, 24, 27, 1, 4, 8, ...
+ => frameSkip = 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, ...
+ => frameRate = (9 + 1) * 25 / 32 = 250 / 32 = 7.8125;
+ */
+ errCode = usbvision_write_reg(usbvision, USBVISION_FRM_RATE, frameDrop);
+ return errCode;
+}
+
+
+/*
+ * usbvision_frames_alloc
+ * allocate the maximum frames this driver can manage
+ */
+int usbvision_frames_alloc(struct usb_usbvision *usbvision)
+{
+ int i;
+
+ /* Allocate memory for the frame buffers */
+ usbvision->max_frame_size = MAX_FRAME_SIZE;
+ usbvision->fbuf_size = USBVISION_NUMFRAMES * usbvision->max_frame_size;
+ usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size);
+
+ if(usbvision->fbuf == NULL) {
+ err("%s: unable to allocate %d bytes for fbuf ",
+ __FUNCTION__, usbvision->fbuf_size);
+ return -ENOMEM;
+ }
+ spin_lock_init(&usbvision->queue_lock);
+ init_waitqueue_head(&usbvision->wait_frame);
+ init_waitqueue_head(&usbvision->wait_stream);
+
+ /* Allocate all buffers */
+ for (i = 0; i < USBVISION_NUMFRAMES; i++) {
+ usbvision->frame[i].index = i;
+ usbvision->frame[i].grabstate = FrameState_Unused;
+ usbvision->frame[i].data = usbvision->fbuf +
+ i * usbvision->max_frame_size;
+ /*
+ * Set default sizes for read operation.
+ */
+ usbvision->stretch_width = 1;
+ usbvision->stretch_height = 1;
+ usbvision->frame[i].width = usbvision->curwidth;
+ usbvision->frame[i].height = usbvision->curheight;
+ usbvision->frame[i].bytes_read = 0;
+ }
+ return 0;
+}
+
+/*
+ * usbvision_frames_free
+ * frees memory allocated for the frames
+ */
+void usbvision_frames_free(struct usb_usbvision *usbvision)
+{
+ /* Have to free all that memory */
+ if (usbvision->fbuf != NULL) {
+ usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size);
+ usbvision->fbuf = NULL;
+ }
+}
+/*
+ * usbvision_empty_framequeues()
+ * prepare queues for incoming and outgoing frames
+ */
+void usbvision_empty_framequeues(struct usb_usbvision *usbvision)
+{
+ u32 i;
+
+ INIT_LIST_HEAD(&(usbvision->inqueue));
+ INIT_LIST_HEAD(&(usbvision->outqueue));
+
+ for (i = 0; i < USBVISION_NUMFRAMES; i++) {
+ usbvision->frame[i].grabstate = FrameState_Unused;
+ usbvision->frame[i].bytes_read = 0;
+ }
+}
+
+/*
+ * usbvision_stream_interrupt()
+ * stops streaming
+ */
+int usbvision_stream_interrupt(struct usb_usbvision *usbvision)
+{
+ int ret = 0;
+
+ /* stop reading from the device */
+
+ usbvision->streaming = Stream_Interrupt;
+ ret = wait_event_timeout(usbvision->wait_stream,
+ (usbvision->streaming == Stream_Idle),
+ msecs_to_jiffies(USBVISION_NUMSBUF*USBVISION_URB_FRAMES));
+ return ret;
+}
+
+/*
+ * usbvision_set_compress_params()
+ *
+ */
+
+static int usbvision_set_compress_params(struct usb_usbvision *usbvision)
+{
+ static const char proc[] = "usbvision_set_compresion_params: ";
+ int rc;
+ unsigned char value[6];
+
+ value[0] = 0x0F; // Intra-Compression cycle
+ value[1] = 0x01; // Reg.45 one line per strip
+ value[2] = 0x00; // Reg.46 Force intra mode on all new frames
+ value[3] = 0x00; // Reg.47 FORCE_UP <- 0 normal operation (not force)
+ value[4] = 0xA2; // Reg.48 BUF_THR I'm not sure if this does something in not compressed mode.
+ value[5] = 0x00; // Reg.49 DVI_YUV This has nothing to do with compression
+
+ //catched values for NT1004
+ // value[0] = 0xFF; // Never apply intra mode automatically
+ // value[1] = 0xF1; // Use full frame height for virtual strip width; One line per strip
+ // value[2] = 0x01; // Force intra mode on all new frames
+ // value[3] = 0x00; // Strip size 400 Bytes; do not force up
+ // value[4] = 0xA2; //
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return 0;
+
+ rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ USBVISION_OP_CODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_ENDPOINT, 0,
+ (__u16) USBVISION_INTRA_CYC, value, 5, HZ);
+
+ if (rc < 0) {
+ printk(KERN_ERR "%sERROR=%d. USBVISION stopped - "
+ "reconnect or reload driver.\n", proc, rc);
+ return rc;
+ }
+
+ if (usbvision->bridgeType == BRIDGE_NT1004) {
+ value[0] = 20; // PCM Threshold 1
+ value[1] = 12; // PCM Threshold 2
+ value[2] = 255; // Distorsion Threshold inter
+ value[3] = 255; // Distorsion Threshold intra
+ value[4] = 43; // Max Distorsion inter
+ value[5] = 43; // Max Distorsion intra
+ }
+ else {
+ value[0] = 20; // PCM Threshold 1
+ value[1] = 12; // PCM Threshold 2
+ value[2] = 255; // Distorsion Threshold d7-d0
+ value[3] = 0; // Distorsion Threshold d11-d8
+ value[4] = 43; // Max Distorsion d7-d0
+ value[5] = 0; // Max Distorsion d8
+ }
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return 0;
+
+ rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ USBVISION_OP_CODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_ENDPOINT, 0,
+ (__u16) USBVISION_PCM_THR1, value, 6, HZ);
+
+ if (rc < 0) {
+ printk(KERN_ERR "%sERROR=%d. USBVISION stopped - "
+ "reconnect or reload driver.\n", proc, rc);
+ return rc;
+ }
+
+
+ return rc;
+}
+
+
+/*
+ * usbvision_set_input()
+ *
+ * Set the input (saa711x, ...) size x y and other misc input params
+ * I've no idea if this parameters are right
+ *
+ */
+int usbvision_set_input(struct usb_usbvision *usbvision)
+{
+ static const char proc[] = "usbvision_set_input: ";
+ int rc;
+ unsigned char value[8];
+ unsigned char dvi_yuv_value;
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return 0;
+
+ /* Set input format expected from decoder*/
+ if (usbvision_device_data[usbvision->DevModel].Vin_Reg1 >= 0) {
+ value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1 & 0xff;
+ } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) {
+ /* SAA7113 uses 8 bit output */
+ value[0] = USBVISION_8_422_SYNC;
+ } else {
+ /* I'm sure only about d2-d0 [010] 16 bit 4:2:2 usin sync pulses
+ * as that is how saa7111 is configured */
+ value[0] = USBVISION_16_422_SYNC;
+ /* | USBVISION_VSNC_POL | USBVISION_VCLK_POL);*/
+ }
+
+ rc = usbvision_write_reg(usbvision, USBVISION_VIN_REG1, value[0]);
+ if (rc < 0) {
+ printk(KERN_ERR "%sERROR=%d. USBVISION stopped - "
+ "reconnect or reload driver.\n", proc, rc);
+ return rc;
+ }
+
+
+ if (usbvision->tvnorm->id & V4L2_STD_PAL) {
+ value[0] = 0xC0;
+ value[1] = 0x02; //0x02C0 -> 704 Input video line length
+ value[2] = 0x20;
+ value[3] = 0x01; //0x0120 -> 288 Input video n. of lines
+ value[4] = 0x60;
+ value[5] = 0x00; //0x0060 -> 96 Input video h offset
+ value[6] = 0x16;
+ value[7] = 0x00; //0x0016 -> 22 Input video v offset
+ } else if (usbvision->tvnorm->id & V4L2_STD_SECAM) {
+ value[0] = 0xC0;
+ value[1] = 0x02; //0x02C0 -> 704 Input video line length
+ value[2] = 0x20;
+ value[3] = 0x01; //0x0120 -> 288 Input video n. of lines
+ value[4] = 0x01;
+ value[5] = 0x00; //0x0001 -> 01 Input video h offset
+ value[6] = 0x01;
+ value[7] = 0x00; //0x0001 -> 01 Input video v offset
+ } else { /* V4L2_STD_NTSC */
+ value[0] = 0xD0;
+ value[1] = 0x02; //0x02D0 -> 720 Input video line length
+ value[2] = 0xF0;
+ value[3] = 0x00; //0x00F0 -> 240 Input video number of lines
+ value[4] = 0x50;
+ value[5] = 0x00; //0x0050 -> 80 Input video h offset
+ value[6] = 0x10;
+ value[7] = 0x00; //0x0010 -> 16 Input video v offset
+ }
+
+ if (usbvision_device_data[usbvision->DevModel].X_Offset >= 0) {
+ value[4]=usbvision_device_data[usbvision->DevModel].X_Offset & 0xff;
+ value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8;
+ }
+
+ if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) {
+ value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff;
+ value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8;
+ }
+
+ rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ USBVISION_OP_CODE, /* USBVISION specific code */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0,
+ (__u16) USBVISION_LXSIZE_I, value, 8, HZ);
+ if (rc < 0) {
+ printk(KERN_ERR "%sERROR=%d. USBVISION stopped - "
+ "reconnect or reload driver.\n", proc, rc);
+ return rc;
+ }
+
+
+ dvi_yuv_value = 0x00; /* U comes after V, Ya comes after U/V, Yb comes after Yb */
+
+ if(usbvision_device_data[usbvision->DevModel].Dvi_yuv >= 0){
+ dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv & 0xff;
+ }
+ else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) {
+ /* This changes as the fine sync control changes. Further investigation necessary */
+ dvi_yuv_value = 0x06;
+ }
+
+ return (usbvision_write_reg(usbvision, USBVISION_DVI_YUV, dvi_yuv_value));
+}
+
+
+/*
+ * usbvision_set_dram_settings()
+ *
+ * Set the buffer address needed by the usbvision dram to operate
+ * This values has been taken with usbsnoop.
+ *
+ */
+
+static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
+{
+ int rc;
+ unsigned char value[8];
+
+ if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+ value[0] = 0x42;
+ value[1] = 0x71;
+ value[2] = 0xff;
+ value[3] = 0x00;
+ value[4] = 0x98;
+ value[5] = 0xe0;
+ value[6] = 0x71;
+ value[7] = 0xff;
+ // UR: 0x0E200-0x3FFFF = 204288 Words (1 Word = 2 Byte)
+ // FDL: 0x00000-0x0E099 = 57498 Words
+ // VDW: 0x0E3FF-0x3FFFF
+ }
+ else {
+ value[0] = 0x42;
+ value[1] = 0x00;
+ value[2] = 0xff;
+ value[3] = 0x00;
+ value[4] = 0x00;
+ value[5] = 0x00;
+ value[6] = 0x00;
+ value[7] = 0xff;
+ }
+ /* These are the values of the address of the video buffer,
+ * they have to be loaded into the USBVISION_DRM_PRM1-8
+ *
+ * Start address of video output buffer for read: drm_prm1-2 -> 0x00000
+ * End address of video output buffer for read: drm_prm1-3 -> 0x1ffff
+ * Start address of video frame delay buffer: drm_prm1-4 -> 0x20000
+ * Only used in compressed mode
+ * End address of video frame delay buffer: drm_prm1-5-6 -> 0x3ffff
+ * Only used in compressed mode
+ * Start address of video output buffer for write: drm_prm1-7 -> 0x00000
+ * End address of video output buffer for write: drm_prm1-8 -> 0x1ffff
+ */
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return 0;
+
+ rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ USBVISION_OP_CODE, /* USBVISION specific code */
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_ENDPOINT, 0,
+ (__u16) USBVISION_DRM_PRM1, value, 8, HZ);
+
+ if (rc < 0) {
+ err("%sERROR=%d", __FUNCTION__, rc);
+ return rc;
+ }
+
+ /* Restart the video buffer logic */
+ if ((rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, USBVISION_RES_UR |
+ USBVISION_RES_FDL | USBVISION_RES_VDW)) < 0)
+ return rc;
+ rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, 0x00);
+
+ return rc;
+}
+
+/*
+ * ()
+ *
+ * Power on the device, enables suspend-resume logic
+ * & reset the isoc End-Point
+ *
+ */
+
+int usbvision_power_on(struct usb_usbvision *usbvision)
+{
+ int errCode = 0;
+
+ PDEBUG(DBG_FUNC, "");
+
+ usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN);
+ usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+ USBVISION_SSPND_EN | USBVISION_RES2);
+
+ usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+ USBVISION_SSPND_EN | USBVISION_PWR_VID);
+ errCode = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+ USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
+ if (errCode == 1) {
+ usbvision->power = 1;
+ }
+ PDEBUG(DBG_FUNC, "%s: errCode %d", (errCode<0)?"ERROR":"power is on", errCode);
+ return errCode;
+}
+
+
+/*
+ * usbvision timer stuff
+ */
+
+// to call usbvision_power_off from task queue
+static void call_usbvision_power_off(struct work_struct *work)
+{
+ struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork);
+
+ PDEBUG(DBG_FUNC, "");
+ down_interruptible(&usbvision->lock);
+ if(usbvision->user == 0) {
+ usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+
+ usbvision_power_off(usbvision);
+ usbvision->initialized = 0;
+ }
+ up(&usbvision->lock);
+}
+
+static void usbvision_powerOffTimer(unsigned long data)
+{
+ struct usb_usbvision *usbvision = (void *) data;
+
+ PDEBUG(DBG_FUNC, "");
+ del_timer(&usbvision->powerOffTimer);
+ INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off);
+ (void) schedule_work(&usbvision->powerOffWork);
+
+}
+
+void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision)
+{
+ init_timer(&usbvision->powerOffTimer);
+ usbvision->powerOffTimer.data = (long) usbvision;
+ usbvision->powerOffTimer.function = usbvision_powerOffTimer;
+}
+
+void usbvision_set_powerOffTimer(struct usb_usbvision *usbvision)
+{
+ mod_timer(&usbvision->powerOffTimer, jiffies + USBVISION_POWEROFF_TIME);
+}
+
+void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision)
+{
+ if (timer_pending(&usbvision->powerOffTimer)) {
+ del_timer(&usbvision->powerOffTimer);
+ }
+}
+
+/*
+ * usbvision_begin_streaming()
+ * Sure you have to put bit 7 to 0, if not incoming frames are droped, but no
+ * idea about the rest
+ */
+int usbvision_begin_streaming(struct usb_usbvision *usbvision)
+{
+ int errCode = 0;
+
+ if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+ usbvision_init_compression(usbvision);
+ }
+ errCode = usbvision_write_reg(usbvision, USBVISION_VIN_REG2, USBVISION_NOHVALID |
+ usbvision->Vin_Reg2_Preset);
+ return errCode;
+}
+
+/*
+ * usbvision_restart_isoc()
+ * Not sure yet if touching here PWR_REG make loose the config
+ */
+
+int usbvision_restart_isoc(struct usb_usbvision *usbvision)
+{
+ int ret;
+
+ if (
+ (ret =
+ usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+ USBVISION_SSPND_EN | USBVISION_PWR_VID)) < 0)
+ return ret;
+ if (
+ (ret =
+ usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+ USBVISION_SSPND_EN | USBVISION_PWR_VID |
+ USBVISION_RES2)) < 0)
+ return ret;
+ if (
+ (ret =
+ usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
+ USBVISION_KEEP_BLANK | USBVISION_NOHVALID |
+ usbvision->Vin_Reg2_Preset)) < 0) return ret;
+
+ /* TODO: schedule timeout */
+ while ((usbvision_read_reg(usbvision, USBVISION_STATUS_REG) & 0x01) != 1);
+
+ return 0;
+}
+
+int usbvision_audio_off(struct usb_usbvision *usbvision)
+{
+ if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_AUDIO_MUTE) < 0) {
+ printk(KERN_ERR "usbvision_audio_off: can't wirte reg\n");
+ return -1;
+ }
+ usbvision->AudioMute = 0;
+ usbvision->AudioChannel = USBVISION_AUDIO_MUTE;
+ return 0;
+}
+
+int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel)
+{
+ if (!usbvision->AudioMute) {
+ if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, AudioChannel) < 0) {
+ printk(KERN_ERR "usbvision_set_audio: can't write iopin register for audio switching\n");
+ return -1;
+ }
+ }
+ usbvision->AudioChannel = AudioChannel;
+ return 0;
+}
+
+int usbvision_setup(struct usb_usbvision *usbvision,int format)
+{
+ usbvision_set_video_format(usbvision, format);
+ usbvision_set_dram_settings(usbvision);
+ usbvision_set_compress_params(usbvision);
+ usbvision_set_input(usbvision);
+ usbvision_set_output(usbvision, MAX_USB_WIDTH, MAX_USB_HEIGHT);
+ usbvision_restart_isoc(usbvision);
+
+ /* cosas del PCM */
+ return USBVISION_IS_OPERATIONAL(usbvision);
+}
+
+/*
+ * usbvision_init_isoc()
+ *
+ */
+int usbvision_init_isoc(struct usb_usbvision *usbvision)
+{
+ struct usb_device *dev = usbvision->dev;
+ int bufIdx, errCode, regValue;
+ const int sb_size = USBVISION_URB_FRAMES * USBVISION_MAX_ISOC_PACKET_SIZE;
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return -EFAULT;
+
+ usbvision->curFrame = NULL;
+ scratch_reset(usbvision);
+
+ /* Alternate interface 1 is is the biggest frame size */
+ errCode = usb_set_interface(dev, usbvision->iface, usbvision->ifaceAltActive);
+ if (errCode < 0) {
+ usbvision->last_error = errCode;
+ return -EBUSY;
+ }
+
+ regValue = (16 - usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
+ usbvision->isocPacketSize = (regValue == 0) ? 0 : (regValue * 64) - 1;
+ PDEBUG(DBG_ISOC, "ISO Packet Length:%d", usbvision->isocPacketSize);
+
+ usbvision->usb_bandwidth = regValue >> 1;
+ PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec", usbvision->usb_bandwidth);
+
+
+
+ /* We double buffer the Iso lists */
+
+ for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
+ int j, k;
+ struct urb *urb;
+
+ urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
+ if (urb == NULL) {
+ err("%s: usb_alloc_urb() failed", __FUNCTION__);
+ return -ENOMEM;
+ }
+ usbvision->sbuf[bufIdx].urb = urb;
+ usbvision->sbuf[bufIdx].data = usb_buffer_alloc(usbvision->dev, sb_size, GFP_KERNEL,&urb->transfer_dma);
+ urb->dev = dev;
+ urb->context = usbvision;
+ urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->interval = 1;
+ urb->transfer_buffer = usbvision->sbuf[bufIdx].data;
+ urb->complete = usbvision_isocIrq;
+ urb->number_of_packets = USBVISION_URB_FRAMES;
+ urb->transfer_buffer_length =
+ usbvision->isocPacketSize * USBVISION_URB_FRAMES;
+ for (j = k = 0; j < USBVISION_URB_FRAMES; j++,
+ k += usbvision->isocPacketSize) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length = usbvision->isocPacketSize;
+ }
+ }
+
+
+ /* Submit all URBs */
+ for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
+ errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb, GFP_KERNEL);
+ if (errCode) {
+ err("%s: usb_submit_urb(%d) failed: error %d", __FUNCTION__, bufIdx, errCode);
+ }
+ }
+
+ usbvision->streaming = Stream_Idle;
+ PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x", __FUNCTION__, usbvision->video_endp);
+ return 0;
+}
+
+/*
+ * usbvision_stop_isoc()
+ *
+ * This procedure stops streaming and deallocates URBs. Then it
+ * activates zero-bandwidth alt. setting of the video interface.
+ *
+ */
+void usbvision_stop_isoc(struct usb_usbvision *usbvision)
+{
+ int bufIdx, errCode, regValue;
+ const int sb_size = USBVISION_URB_FRAMES * USBVISION_MAX_ISOC_PACKET_SIZE;
+
+ if ((usbvision->streaming == Stream_Off) || (usbvision->dev == NULL))
+ return;
+
+ /* Unschedule all of the iso td's */
+ for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
+ usb_kill_urb(usbvision->sbuf[bufIdx].urb);
+ if (usbvision->sbuf[bufIdx].data){
+ usb_buffer_free(usbvision->dev,
+ sb_size,
+ usbvision->sbuf[bufIdx].data,
+ usbvision->sbuf[bufIdx].urb->transfer_dma);
+ }
+ usb_free_urb(usbvision->sbuf[bufIdx].urb);
+ usbvision->sbuf[bufIdx].urb = NULL;
+ }
+
+
+ PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __FUNCTION__);
+ usbvision->streaming = Stream_Off;
+
+ if (!usbvision->remove_pending) {
+
+ /* Set packet size to 0 */
+ errCode = usb_set_interface(usbvision->dev, usbvision->iface,
+ usbvision->ifaceAltInactive);
+ if (errCode < 0) {
+ err("%s: usb_set_interface() failed: error %d", __FUNCTION__, errCode);
+ usbvision->last_error = errCode;
+ }
+ regValue = (16 - usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
+ usbvision->isocPacketSize = (regValue == 0) ? 0 : (regValue * 64) - 1;
+ PDEBUG(DBG_ISOC, "ISO Packet Length:%d", usbvision->isocPacketSize);
+
+ usbvision->usb_bandwidth = regValue >> 1;
+ PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec", usbvision->usb_bandwidth);
+ }
+}
+
+int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
+{
+ int mode[4];
+ int audio[]= {1, 0, 0, 0};
+ struct v4l2_routing route;
+ //channel 0 is TV with audiochannel 1 (tuner mono)
+ //channel 1 is Composite with audio channel 0 (line in)
+ //channel 2 is S-Video with audio channel 0 (line in)
+ //channel 3 is additional video inputs to the device with audio channel 0 (line in)
+
+ RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
+ usbvision->ctl_input = channel;
+ route.input = SAA7115_COMPOSITE1;
+ call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
+ call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
+
+ // set the new channel
+ // Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video
+ // Four video input devices -> channel: 0 = Chan White, 1 = Chan Green, 2 = Chan Yellow, 3 = Chan Red
+
+ switch (usbvision_device_data[usbvision->DevModel].Codec) {
+ case CODEC_SAA7113:
+ if (SwitchSVideoInput) { // To handle problems with S-Video Input for some devices. Use SwitchSVideoInput parameter when loading the module.
+ mode[2] = 1;
+ }
+ else {
+ mode[2] = 7;
+ }
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ mode[0] = 0; mode[1] = 2; mode[3] = 3; // Special for four input devices
+ }
+ else {
+ mode[0] = 0; mode[1] = 2; //modes for regular saa7113 devices
+ }
+ break;
+ case CODEC_SAA7111:
+ mode[0] = 0; mode[1] = 1; mode[2] = 7; //modes for saa7111
+ break;
+ default:
+ mode[0] = 0; mode[1] = 1; mode[2] = 7; //default modes
+ }
+ route.input = mode[channel];
+ call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
+ usbvision->channel = channel;
+ usbvision_set_audio(usbvision, audio[channel]);
+ return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
new file mode 100644
index 00000000000..858252c1508
--- /dev/null
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -0,0 +1,552 @@
+/*
+ * I2C_ALGO_USB.C
+ * i2c algorithm for USB-I2C Bridges
+ *
+ * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ * Dwaine Garden <dwainegarden@rogers.com>
+ *
+ * This module is part of usbvision driver project.
+ * Updates to driver completed by Dwaine P. Garden
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/utsname.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include "usbvision.h"
+
+#define DBG_I2C 1<<0
+#define DBG_ALGO 1<<1
+
+static int i2c_debug = 0;
+
+module_param (i2c_debug, int, 0644); // debug_i2c_usb mode of the device driver
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define PDEBUG(level, fmt, args...) \
+ if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+
+static int usbvision_i2c_write(void *data, unsigned char addr, char *buf,
+ short len);
+static int usbvision_i2c_read(void *data, unsigned char addr, char *buf,
+ short len);
+
+static inline int try_write_address(struct i2c_adapter *i2c_adap,
+ unsigned char addr, int retries)
+{
+ void *data;
+ int i, ret = -1;
+ char buf[4];
+
+ data = i2c_get_adapdata(i2c_adap);
+ buf[0] = 0x00;
+ for (i = 0; i <= retries; i++) {
+ ret = (usbvision_i2c_write(data, addr, buf, 1));
+ if (ret == 1)
+ break; /* success! */
+ udelay(5);
+ if (i == retries) /* no success */
+ break;
+ udelay(10);
+ }
+ if (i) {
+ PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr);
+ PDEBUG(DBG_ALGO,"Maybe there's no device at this address");
+ }
+ return ret;
+}
+
+static inline int try_read_address(struct i2c_adapter *i2c_adap,
+ unsigned char addr, int retries)
+{
+ void *data;
+ int i, ret = -1;
+ char buf[4];
+
+ data = i2c_get_adapdata(i2c_adap);
+ for (i = 0; i <= retries; i++) {
+ ret = (usbvision_i2c_read(data, addr, buf, 1));
+ if (ret == 1)
+ break; /* success! */
+ udelay(5);
+ if (i == retries) /* no success */
+ break;
+ udelay(10);
+ }
+ if (i) {
+ PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr);
+ PDEBUG(DBG_ALGO,"Maybe there's no device at this address");
+ }
+ return ret;
+}
+
+static inline int usb_find_address(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msg, int retries,
+ unsigned char *add)
+{
+ unsigned short flags = msg->flags;
+
+ unsigned char addr;
+ int ret;
+ if ((flags & I2C_M_TEN)) {
+ /* a ten bit address */
+ addr = 0xf0 | ((msg->addr >> 7) & 0x03);
+ /* try extended address code... */
+ ret = try_write_address(i2c_adap, addr, retries);
+ if (ret != 1) {
+ err("died at extended address code, while writing");
+ return -EREMOTEIO;
+ }
+ add[0] = addr;
+ if (flags & I2C_M_RD) {
+ /* okay, now switch into reading mode */
+ addr |= 0x01;
+ ret = try_read_address(i2c_adap, addr, retries);
+ if (ret != 1) {
+ err("died at extended address code, while reading");
+ return -EREMOTEIO;
+ }
+ }
+
+ } else { /* normal 7bit address */
+ addr = (msg->addr << 1);
+ if (flags & I2C_M_RD)
+ addr |= 1;
+ if (flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+
+ add[0] = addr;
+ if (flags & I2C_M_RD)
+ ret = try_read_address(i2c_adap, addr, retries);
+ else
+ ret = try_write_address(i2c_adap, addr, retries);
+
+ if (ret != 1) {
+ return -EREMOTEIO;
+ }
+ }
+ return 0;
+}
+
+static int
+usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
+{
+ struct i2c_msg *pmsg;
+ void *data;
+ int i, ret;
+ unsigned char addr;
+
+ data = i2c_get_adapdata(i2c_adap);
+
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr);
+ if (ret != 0) {
+ PDEBUG(DBG_ALGO,"got NAK from device, message #%d", i);
+ return (ret < 0) ? ret : -EREMOTEIO;
+ }
+
+ if (pmsg->flags & I2C_M_RD) {
+ /* read bytes into buffer */
+ ret = (usbvision_i2c_read(data, addr, pmsg->buf, pmsg->len));
+ if (ret < pmsg->len) {
+ return (ret < 0) ? ret : -EREMOTEIO;
+ }
+ } else {
+ /* write bytes from buffer */
+ ret = (usbvision_i2c_write(data, addr, pmsg->buf, pmsg->len));
+ if (ret < pmsg->len) {
+ return (ret < 0) ? ret : -EREMOTEIO;
+ }
+ }
+ }
+ return num;
+}
+
+static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned long arg)
+{
+ return 0;
+}
+
+static u32 usb_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static struct i2c_algorithm i2c_usb_algo = {
+ .master_xfer = usb_xfer,
+ .smbus_xfer = NULL,
+ .algo_control = algo_control,
+ .functionality = usb_func,
+};
+
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap)
+{
+ PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]");
+ PDEBUG(DBG_ALGO, "ALGO debugging is enabled [i2c]");
+
+ /* register new adapter to i2c module... */
+
+ adap->algo = &i2c_usb_algo;
+
+ adap->timeout = 100; /* default values, should */
+ adap->retries = 3; /* be replaced by defines */
+
+ i2c_add_adapter(adap);
+
+ PDEBUG(DBG_ALGO,"i2c bus for %s registered", adap->name);
+
+ return 0;
+}
+
+
+int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap)
+{
+
+ i2c_del_adapter(adap);
+
+ PDEBUG(DBG_ALGO,"i2c bus for %s unregistered", adap->name);
+
+ return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* usbvision specific I2C functions */
+/* ----------------------------------------------------------------------- */
+static struct i2c_adapter i2c_adap_template;
+static struct i2c_client i2c_client_template;
+
+int usbvision_init_i2c(struct usb_usbvision *usbvision)
+{
+ memcpy(&usbvision->i2c_adap, &i2c_adap_template,
+ sizeof(struct i2c_adapter));
+ memcpy(&usbvision->i2c_client, &i2c_client_template,
+ sizeof(struct i2c_client));
+
+ sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name),
+ " #%d", usbvision->vdev->minor & 0x1f);
+ PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name);
+
+ i2c_set_adapdata(&usbvision->i2c_adap, usbvision);
+ i2c_set_clientdata(&usbvision->i2c_client, usbvision);
+
+ usbvision->i2c_client.adapter = &usbvision->i2c_adap;
+
+ if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) {
+ printk(KERN_ERR "usbvision_init_i2c: can't write reg\n");
+ return -EBUSY;
+ }
+
+#ifdef CONFIG_MODULES
+ /* Request the load of the i2c modules we need */
+ switch (usbvision_device_data[usbvision->DevModel].Codec) {
+ case CODEC_SAA7113:
+ request_module("saa7115");
+ break;
+ case CODEC_SAA7111:
+ request_module("saa7115");
+ break;
+ }
+ if (usbvision_device_data[usbvision->DevModel].Tuner == 1) {
+ request_module("tuner");
+ }
+#endif
+
+ return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap);
+}
+
+void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,
+ void *arg)
+{
+ i2c_clients_command(&usbvision->i2c_adap, cmd, arg);
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+ struct usb_usbvision *usbvision;
+
+ usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter);
+
+ switch (client->addr << 1) {
+ case 0x43:
+ case 0x4b:
+ {
+ struct tuner_setup tun_setup;
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = TUNER_TDA9887;
+ tun_setup.addr = client->addr;
+
+ call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup);
+
+ break;
+ }
+ case 0x42:
+ PDEBUG(DBG_I2C,"attach_inform: saa7114 detected.");
+ break;
+ case 0x4a:
+ PDEBUG(DBG_I2C,"attach_inform: saa7113 detected.");
+ break;
+ case 0x48:
+ PDEBUG(DBG_I2C,"attach_inform: saa7111 detected.");
+ break;
+ case 0xa0:
+ PDEBUG(DBG_I2C,"attach_inform: eeprom detected.");
+ break;
+
+ default:
+ {
+ struct tuner_setup tun_setup;
+
+ PDEBUG(DBG_I2C,"attach inform: detected I2C address %x", client->addr << 1);
+ usbvision->tuner_addr = client->addr;
+
+ if ((usbvision->have_tuner) && (usbvision->tuner_type != -1)) {
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = usbvision->tuner_type;
+ tun_setup.addr = usbvision->tuner_addr;
+ call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+ struct usb_usbvision *usbvision;
+
+ usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter);
+
+ PDEBUG(DBG_I2C,"usbvision[%d] detaches %s", usbvision->nr, client->name);
+ return 0;
+}
+
+static int
+usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr,
+ char *buf, short len)
+{
+ int rc, retries;
+
+ for (retries = 5;;) {
+ rc = usbvision_write_reg(usbvision, USBVISION_SER_ADRS, addr);
+ if (rc < 0)
+ return rc;
+
+ /* Initiate byte read cycle */
+ /* USBVISION_SER_CONT <- d0-d2 n. of bytes to r/w */
+ /* d3 0=Wr 1=Rd */
+ rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT,
+ (len & 0x07) | 0x18);
+ if (rc < 0)
+ return rc;
+
+ /* Test for Busy and ACK */
+ do {
+ /* USBVISION_SER_CONT -> d4 == 0 busy */
+ rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT);
+ } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */
+ if (rc < 0)
+ return rc;
+
+ /* USBVISION_SER_CONT -> d5 == 1 Not ack */
+ if ((rc & 0x20) == 0) /* Ack? */
+ break;
+
+ /* I2C abort */
+ rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00);
+ if (rc < 0)
+ return rc;
+
+ if (--retries < 0)
+ return -1;
+ }
+
+ switch (len) {
+ case 4:
+ buf[3] = usbvision_read_reg(usbvision, USBVISION_SER_DAT4);
+ case 3:
+ buf[2] = usbvision_read_reg(usbvision, USBVISION_SER_DAT3);
+ case 2:
+ buf[1] = usbvision_read_reg(usbvision, USBVISION_SER_DAT2);
+ case 1:
+ buf[0] = usbvision_read_reg(usbvision, USBVISION_SER_DAT1);
+ break;
+ default:
+ printk(KERN_ERR
+ "usbvision_i2c_read_max4: buffer length > 4\n");
+ }
+
+ if (i2c_debug & DBG_I2C) {
+ int idx;
+ for (idx = 0; idx < len; idx++) {
+ PDEBUG(DBG_I2C,"read %x from address %x", (unsigned char)buf[idx], addr);
+ }
+ }
+ return len;
+}
+
+
+static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision,
+ unsigned char addr, const char *buf,
+ short len)
+{
+ int rc, retries;
+ int i;
+ unsigned char value[6];
+ unsigned char ser_cont;
+
+ ser_cont = (len & 0x07) | 0x10;
+
+ value[0] = addr;
+ value[1] = ser_cont;
+ for (i = 0; i < len; i++)
+ value[i + 2] = buf[i];
+
+ for (retries = 5;;) {
+ rc = usb_control_msg(usbvision->dev,
+ usb_sndctrlpipe(usbvision->dev, 1),
+ USBVISION_OP_CODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_ENDPOINT, 0,
+ (__u16) USBVISION_SER_ADRS, value,
+ len + 2, HZ);
+
+ if (rc < 0)
+ return rc;
+
+ rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT,
+ (len & 0x07) | 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* Test for Busy and ACK */
+ do {
+ rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT);
+ } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */
+ if (rc < 0)
+ return rc;
+
+ if ((rc & 0x20) == 0) /* Ack? */
+ break;
+
+ /* I2C abort */
+ usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00);
+
+ if (--retries < 0)
+ return -1;
+
+ }
+
+ if (i2c_debug & DBG_I2C) {
+ int idx;
+ for (idx = 0; idx < len; idx++) {
+ PDEBUG(DBG_I2C,"wrote %x at address %x", (unsigned char)buf[idx], addr);
+ }
+ }
+ return len;
+}
+
+static int usbvision_i2c_write(void *data, unsigned char addr, char *buf,
+ short len)
+{
+ char *bufPtr = buf;
+ int retval;
+ int wrcount = 0;
+ int count;
+ int maxLen = 4;
+ struct usb_usbvision *usbvision = (struct usb_usbvision *) data;
+
+ while (len > 0) {
+ count = (len > maxLen) ? maxLen : len;
+ retval = usbvision_i2c_write_max4(usbvision, addr, bufPtr, count);
+ if (retval > 0) {
+ len -= count;
+ bufPtr += count;
+ wrcount += count;
+ } else
+ return (retval < 0) ? retval : -EFAULT;
+ }
+ return wrcount;
+}
+
+static int usbvision_i2c_read(void *data, unsigned char addr, char *buf,
+ short len)
+{
+ char temp[4];
+ int retval, i;
+ int rdcount = 0;
+ int count;
+ struct usb_usbvision *usbvision = (struct usb_usbvision *) data;
+
+ while (len > 0) {
+ count = (len > 3) ? 4 : len;
+ retval = usbvision_i2c_read_max4(usbvision, addr, temp, count);
+ if (retval > 0) {
+ for (i = 0; i < len; i++)
+ buf[rdcount + i] = temp[i];
+ len -= count;
+ rdcount += count;
+ } else
+ return (retval < 0) ? retval : -EFAULT;
+ }
+ return rdcount;
+}
+
+static struct i2c_adapter i2c_adap_template = {
+ .owner = THIS_MODULE,
+ .name = "usbvision",
+ .id = I2C_HW_B_BT848, /* FIXME */
+ .client_register = attach_inform,
+ .client_unregister = detach_inform,
+#ifdef I2C_ADAP_CLASS_TV_ANALOG
+ .class = I2C_ADAP_CLASS_TV_ANALOG,
+#else
+ .class = I2C_CLASS_TV_ANALOG,
+#endif
+};
+
+static struct i2c_client i2c_client_template = {
+ .name = "usbvision internal",
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
new file mode 100644
index 00000000000..bdd6301d2a4
--- /dev/null
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -0,0 +1,2088 @@
+/*
+ * USB USBVISION Video device driver 0.9.9
+ *
+ *
+ *
+ * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ *
+ * This module is part of usbvision driver project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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.
+ *
+ * Let's call the version 0.... until compression decoding is completely
+ * implemented.
+ *
+ * This driver is written by Jose Ignacio Gijon and Joerg Heckenbach.
+ * It was based on USB CPiA driver written by Peter Pregler,
+ * Scott J. Bertin and Johannes Erdfelt
+ * Ideas are taken from bttv driver by Ralph Metzler, Marcus Metzler &
+ * Gerd Knorr and zoran 36120/36125 driver by Pauline Middelink
+ * Updates to driver completed by Dwaine P. Garden
+ *
+ *
+ * TODO:
+ * - use submit_urb for all setup packets
+ * - Fix memory settings for nt1004. It is 4 times as big as the
+ * nt1003 memory.
+ * - Add audio on endpoint 3 for nt1004 chip. Seems impossible, needs a codec interface. Which one?
+ * - Clean up the driver.
+ * - optimization for performance.
+ * - Add Videotext capability (VBI). Working on it.....
+ * - Check audio for other devices
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/utsname.h>
+#include <linux/highmem.h>
+#include <linux/smp_lock.h>
+#include <linux/videodev.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <linux/videodev2.h>
+#include <linux/video_decoder.h>
+#include <linux/i2c.h>
+
+#include <media/saa7115.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/audiochip.h>
+
+#include <linux/moduleparam.h>
+#include <linux/workqueue.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include "usbvision.h"
+
+#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_NAME "usbvision"
+#define DRIVER_ALIAS "USBVision"
+#define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
+#define DRIVER_LICENSE "GPL"
+#define USBVISION_DRIVER_VERSION_MAJOR 0
+#define USBVISION_DRIVER_VERSION_MINOR 9
+#define USBVISION_DRIVER_VERSION_PATCHLEVEL 9
+#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+
+#define ENABLE_HEXDUMP 0 /* Enable if you need it */
+
+
+#ifdef USBVISION_DEBUG
+ #define PDEBUG(level, fmt, args...) \
+ if (video_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+#else
+ #define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+#define DBG_IOCTL 1<<0
+#define DBG_IO 1<<1
+#define DBG_PROBE 1<<2
+#define DBG_MMAP 1<<3
+
+//String operations
+#define rmspace(str) while(*str==' ') str++;
+#define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++;
+
+
+static int usbvision_nr = 0; // sequential number of usbvision device
+
+static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
+ { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" },
+ { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" },
+ { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" },
+ { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" },
+ { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" },
+ { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" },
+ { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, // 1.5 !
+ { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
+};
+
+/* supported tv norms */
+static struct usbvision_tvnorm tvnorms[] = {
+ {
+ .name = "PAL",
+ .id = V4L2_STD_PAL,
+ }, {
+ .name = "NTSC",
+ .id = V4L2_STD_NTSC,
+ }, {
+ .name = "SECAM",
+ .id = V4L2_STD_SECAM,
+ }, {
+ .name = "PAL-M",
+ .id = V4L2_STD_PAL_M,
+ }
+};
+
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+// Function prototypes
+static void usbvision_release(struct usb_usbvision *usbvision);
+
+// Default initalization of device driver parameters
+static int isocMode = ISOC_MODE_COMPRESS; // Set the default format for ISOC endpoint
+static int video_debug = 0; // Set the default Debug Mode of the device driver
+static int PowerOnAtOpen = 1; // Set the default device to power on at startup
+static int video_nr = -1; // Sequential Number of Video Device
+static int radio_nr = -1; // Sequential Number of Radio Device
+static int vbi_nr = -1; // Sequential Number of VBI Device
+static char *CustomDevice=NULL; // Set as nothing....
+
+// Grab parameters for the device driver
+
+#if defined(module_param) // Showing parameters under SYSFS
+module_param(isocMode, int, 0444);
+module_param(video_debug, int, 0444);
+module_param(PowerOnAtOpen, int, 0444);
+module_param(video_nr, int, 0444);
+module_param(radio_nr, int, 0444);
+module_param(vbi_nr, int, 0444);
+module_param(CustomDevice, charp, 0444);
+#else // Old Style
+MODULE_PARAM(isocMode, "i");
+MODULE_PARM(video_debug, "i"); // Grab the Debug Mode of the device driver
+MODULE_PARM(adjustCompression, "i"); // Grab the compression to be adaptive
+MODULE_PARM(PowerOnAtOpen, "i"); // Grab the device to power on at startup
+MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White output with using s-video input. Some cables and input device are wired differently.
+MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...)
+MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...)
+MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...)
+MODULE_PARM(CustomDevice, "s"); // .... CustomDevice
+#endif
+
+MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)");
+MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)");
+MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device is opened. Default: 1 (On)");
+MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)");
+MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)");
+MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX). Default: -1 (autodetect)");
+MODULE_PARM_DESC(CustomDevice, " Define the fine tuning parameters for the device. Default: null");
+
+
+// Misc stuff
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+MODULE_VERSION(USBVISION_VERSION_STRING);
+MODULE_ALIAS(DRIVER_ALIAS);
+
+
+/****************************************************************************************/
+/* SYSFS Code - Copied from the stv680.c usb module. */
+/* Device information is located at /sys/class/video4linux/video0 */
+/* Device parameters information is located at /sys/module/usbvision */
+/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber */
+/****************************************************************************************/
+
+
+#define YES_NO(x) ((x) ? "Yes" : "No")
+
+static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd)
+{
+ struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ return video_get_drvdata(vdev);
+}
+
+static ssize_t show_version(struct class_device *cd, char *buf)
+{
+ return sprintf(buf, "%s\n", USBVISION_VERSION_STRING);
+}
+static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+
+static ssize_t show_model(struct class_device *cd, char *buf)
+{
+ struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString);
+}
+static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+
+static ssize_t show_hue(struct class_device *cd, char *buf)
+{
+ struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ struct v4l2_control ctrl;
+ ctrl.id = V4L2_CID_HUE;
+ ctrl.value = 0;
+ if(usbvision->user)
+ call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value >> 8);
+}
+static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+
+static ssize_t show_contrast(struct class_device *cd, char *buf)
+{
+ struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ struct v4l2_control ctrl;
+ ctrl.id = V4L2_CID_CONTRAST;
+ ctrl.value = 0;
+ if(usbvision->user)
+ call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value >> 8);
+}
+static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+
+static ssize_t show_brightness(struct class_device *cd, char *buf)
+{
+ struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ struct v4l2_control ctrl;
+ ctrl.id = V4L2_CID_BRIGHTNESS;
+ ctrl.value = 0;
+ if(usbvision->user)
+ call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value >> 8);
+}
+static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+
+static ssize_t show_saturation(struct class_device *cd, char *buf)
+{
+ struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ struct v4l2_control ctrl;
+ ctrl.id = V4L2_CID_SATURATION;
+ ctrl.value = 0;
+ if(usbvision->user)
+ call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+ return sprintf(buf, "%d\n", ctrl.value >> 8);
+}
+static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+
+static ssize_t show_streaming(struct class_device *cd, char *buf)
+{
+ struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0));
+}
+static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
+
+static ssize_t show_compression(struct class_device *cd, char *buf)
+{
+ struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
+}
+static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
+
+static ssize_t show_device_bridge(struct class_device *cd, char *buf)
+{
+ struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+ return sprintf(buf, "%d\n", usbvision->bridgeType);
+}
+static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
+
+static void usbvision_create_sysfs(struct video_device *vdev)
+{
+ int res;
+ if (!vdev)
+ return;
+ do {
+ res=class_device_create_file(&vdev->class_dev,
+ &class_device_attr_version);
+ if (res<0)
+ break;
+ res=class_device_create_file(&vdev->class_dev,
+ &class_device_attr_model);
+ if (res<0)
+ break;
+ res=class_device_create_file(&vdev->class_dev,
+ &class_device_attr_hue);
+ if (res<0)
+ break;
+ res=class_device_create_file(&vdev->class_dev,
+ &class_device_attr_contrast);
+ if (res<0)
+ break;
+ res=class_device_create_file(&vdev->class_dev,
+ &class_device_attr_brightness);
+ if (res<0)
+ break;
+ res=class_device_create_file(&vdev->class_dev,
+ &class_device_attr_saturation);
+ if (res<0)
+ break;
+ res=class_device_create_file(&vdev->class_dev,
+ &class_device_attr_streaming);
+ if (res<0)
+ break;
+ res=class_device_create_file(&vdev->class_dev,
+ &class_device_attr_compression);
+ if (res<0)
+ break;
+ res=class_device_create_file(&vdev->class_dev,
+ &class_device_attr_bridge);
+ if (res>=0)
+ return;
+ } while (0);
+
+ err("%s error: %d\n", __FUNCTION__, res);
+}
+
+static void usbvision_remove_sysfs(struct video_device *vdev)
+{
+ if (vdev) {
+ class_device_remove_file(&vdev->class_dev,
+ &class_device_attr_version);
+ class_device_remove_file(&vdev->class_dev,
+ &class_device_attr_model);
+ class_device_remove_file(&vdev->class_dev,
+ &class_device_attr_hue);
+ class_device_remove_file(&vdev->class_dev,
+ &class_device_attr_contrast);
+ class_device_remove_file(&vdev->class_dev,
+ &class_device_attr_brightness);
+ class_device_remove_file(&vdev->class_dev,
+ &class_device_attr_saturation);
+ class_device_remove_file(&vdev->class_dev,
+ &class_device_attr_streaming);
+ class_device_remove_file(&vdev->class_dev,
+ &class_device_attr_compression);
+ class_device_remove_file(&vdev->class_dev,
+ &class_device_attr_bridge);
+ }
+}
+
+
+/*
+ * usbvision_open()
+ *
+ * This is part of Video 4 Linux API. The driver can be opened by one
+ * client only (checks internal counter 'usbvision->user'). The procedure
+ * then allocates buffers needed for video processing.
+ *
+ */
+static int usbvision_v4l2_open(struct inode *inode, struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ int errCode = 0;
+
+ PDEBUG(DBG_IO, "open");
+
+
+ usbvision_reset_powerOffTimer(usbvision);
+
+ if (usbvision->user)
+ errCode = -EBUSY;
+ else {
+ /* Allocate memory for the frame buffers */
+ errCode = usbvision_frames_alloc(usbvision);
+ if(!errCode) {
+ /* Allocate memory for the scratch ring buffer */
+ errCode = usbvision_scratch_alloc(usbvision);
+ if ((!errCode) && (isocMode==ISOC_MODE_COMPRESS)) {
+ /* Allocate intermediate decompression buffers only if needed */
+ errCode = usbvision_decompress_alloc(usbvision);
+ }
+ }
+ if (errCode) {
+ /* Deallocate all buffers if trouble */
+ usbvision_frames_free(usbvision);
+ usbvision_scratch_free(usbvision);
+ usbvision_decompress_free(usbvision);
+ }
+ }
+
+ /* If so far no errors then we shall start the camera */
+ if (!errCode) {
+ down(&usbvision->lock);
+ if (usbvision->power == 0) {
+ usbvision_power_on(usbvision);
+ usbvision_init_i2c(usbvision);
+ }
+
+ /* Send init sequence only once, it's large! */
+ if (!usbvision->initialized) {
+ int setup_ok = 0;
+ setup_ok = usbvision_setup(usbvision,isocMode);
+ if (setup_ok)
+ usbvision->initialized = 1;
+ else
+ errCode = -EBUSY;
+ }
+
+ if (!errCode) {
+ usbvision_begin_streaming(usbvision);
+ errCode = usbvision_init_isoc(usbvision);
+ /* device needs to be initialized before isoc transfer */
+ usbvision_muxsel(usbvision,0);
+ usbvision->user++;
+ }
+ else {
+ if (PowerOnAtOpen) {
+ usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+ usbvision_power_off(usbvision);
+ usbvision->initialized = 0;
+ }
+ }
+ up(&usbvision->lock);
+ }
+
+ if (errCode) {
+ }
+
+ /* prepare queues */
+ usbvision_empty_framequeues(usbvision);
+
+ PDEBUG(DBG_IO, "success");
+ return errCode;
+}
+
+/*
+ * usbvision_v4l2_close()
+ *
+ * This is part of Video 4 Linux API. The procedure
+ * stops streaming and deallocates all buffers that were earlier
+ * allocated in usbvision_v4l2_open().
+ *
+ */
+static int usbvision_v4l2_close(struct inode *inode, struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+
+ PDEBUG(DBG_IO, "close");
+ down(&usbvision->lock);
+
+ usbvision_audio_off(usbvision);
+ usbvision_restart_isoc(usbvision);
+ usbvision_stop_isoc(usbvision);
+
+ usbvision_decompress_free(usbvision);
+ usbvision_frames_free(usbvision);
+ usbvision_scratch_free(usbvision);
+
+ usbvision->user--;
+
+ if (PowerOnAtOpen) {
+ /* power off in a little while to avoid off/on every close/open short sequences */
+ usbvision_set_powerOffTimer(usbvision);
+ usbvision->initialized = 0;
+ }
+
+ up(&usbvision->lock);
+
+ if (usbvision->remove_pending) {
+ info("%s: Final disconnect", __FUNCTION__);
+ usbvision_release(usbvision);
+ }
+
+ PDEBUG(DBG_IO, "success");
+
+
+ return 0;
+}
+
+
+/*
+ * usbvision_ioctl()
+ *
+ * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
+ *
+ */
+static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return -EFAULT;
+
+ switch (cmd) {
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ /* ioctls to allow direct acces to the NT100x registers */
+ case VIDIOC_INT_G_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+ int errCode;
+
+ if (reg->i2c_id != 0)
+ return -EINVAL;
+ /* NT100x has a 8-bit register space */
+ errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+ if (errCode < 0) {
+ err("%s: VIDIOC_INT_G_REGISTER failed: error %d", __FUNCTION__, errCode);
+ }
+ else {
+ reg->val=(unsigned char)errCode;
+ PDEBUG(DBG_IOCTL, "VIDIOC_INT_G_REGISTER reg=0x%02X, value=0x%02X",
+ (unsigned int)reg->reg, reg->val);
+ errCode = 0; // No error
+ }
+ return errCode;
+ }
+ case VIDIOC_INT_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+ int errCode;
+
+ if (reg->i2c_id != 0)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+ if (errCode < 0) {
+ err("%s: VIDIOC_INT_S_REGISTER failed: error %d", __FUNCTION__, errCode);
+ }
+ else {
+ PDEBUG(DBG_IOCTL, "VIDIOC_INT_S_REGISTER reg=0x%02X, value=0x%02X",
+ (unsigned int)reg->reg, reg->val);
+ errCode = 0;
+ }
+ return 0;
+ }
+#endif
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *vc=arg;
+
+ memset(vc, 0, sizeof(*vc));
+ strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
+ strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
+ sizeof(vc->card));
+ strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
+ sizeof(vc->bus_info));
+ vc->version = USBVISION_DRIVER_VERSION;
+ vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+ PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP");
+ return 0;
+ }
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *vi = arg;
+ int chan;
+
+ if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
+ return -EINVAL;
+ if (usbvision->have_tuner) {
+ chan = vi->index;
+ }
+ else {
+ chan = vi->index + 1; //skip Television string
+ }
+ switch(chan) {
+ case 0:
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "White Video Input");
+ }
+ else {
+ strcpy(vi->name, "Television");
+ vi->type = V4L2_INPUT_TYPE_TUNER;
+ vi->audioset = 1;
+ vi->tuner = chan;
+ vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM;
+ }
+ break;
+ case 1:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "Green Video Input");
+ }
+ else {
+ strcpy(vi->name, "Composite Video Input");
+ }
+ vi->std = V4L2_STD_PAL;
+ break;
+ case 2:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "Yellow Video Input");
+ }
+ else {
+ strcpy(vi->name, "S-Video Input");
+ }
+ vi->std = V4L2_STD_PAL;
+ break;
+ case 3:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(vi->name, "Red Video Input");
+ vi->std = V4L2_STD_PAL;
+ break;
+ }
+ PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x",
+ vi->name, vi->index, vi->tuner,vi->type,(int)vi->std);
+ return 0;
+ }
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *e = arg;
+ unsigned int i;
+ int ret;
+
+ i = e->index;
+ if (i >= TVNORMS)
+ return -EINVAL;
+ ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
+ tvnorms[e->index].name);
+ e->index = i;
+ if (ret < 0)
+ return ret;
+ return 0;
+ }
+ case VIDIOC_G_INPUT:
+ {
+ int *input = arg;
+ *input = usbvision->ctl_input;
+ return 0;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ int *input = arg;
+ if ((*input >= usbvision->video_inputs) || (*input < 0) )
+ return -EINVAL;
+ usbvision->ctl_input = *input;
+
+ down(&usbvision->lock);
+ usbvision_muxsel(usbvision, usbvision->ctl_input);
+ usbvision_set_input(usbvision);
+ usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight);
+ up(&usbvision->lock);
+ return 0;
+ }
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *id = arg;
+
+ *id = usbvision->tvnorm->id;
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name);
+ return 0;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *id = arg;
+ unsigned int i;
+
+ for (i = 0; i < TVNORMS; i++)
+ if (*id == tvnorms[i].id)
+ break;
+ if (i == TVNORMS)
+ for (i = 0; i < TVNORMS; i++)
+ if (*id & tvnorms[i].id)
+ break;
+ if (i == TVNORMS)
+ return -EINVAL;
+
+ down(&usbvision->lock);
+ usbvision->tvnorm = &tvnorms[i];
+
+ call_i2c_clients(usbvision, VIDIOC_S_STD,
+ &usbvision->tvnorm->id);
+
+ up(&usbvision->lock);
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name);
+ return 0;
+ }
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *vt = arg;
+
+ if (!usbvision->have_tuner || vt->index) // Only tuner 0
+ return -EINVAL;
+ strcpy(vt->name, "Television");
+ /* Let clients fill in the remainder of this struct */
+ call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc);
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *vt = arg;
+
+ // Only no or one tuner for now
+ if (!usbvision->have_tuner || vt->index)
+ return -EINVAL;
+ /* let clients handle this */
+ call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER");
+ return 0;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *freq = arg;
+
+ freq->tuner = 0; // Only one tuner
+ freq->type = V4L2_TUNER_ANALOG_TV;
+ freq->frequency = usbvision->freq;
+ PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
+ return 0;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *freq = arg;
+
+ // Only no or one tuner for now
+ if (!usbvision->have_tuner || freq->tuner)
+ return -EINVAL;
+
+ usbvision->freq = freq->frequency;
+ call_i2c_clients(usbvision, cmd, freq);
+ PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
+ return 0;
+ }
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *v = arg;
+ memset(v,0, sizeof(v));
+ strcpy(v->name, "TV");
+ PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO");
+ return 0;
+ }
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *v = arg;
+ if(v->index) {
+ return -EINVAL;
+ }
+ PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO");
+ return 0;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *ctrl = arg;
+ int id=ctrl->id;
+
+ memset(ctrl,0,sizeof(*ctrl));
+ ctrl->id=id;
+
+ call_i2c_clients(usbvision, cmd, arg);
+
+ if (ctrl->type)
+ return 0;
+ else
+ return -EINVAL;
+
+ PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
+ call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+ return 0;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
+ call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+ return 0;
+ }
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *vr = arg;
+ int ret;
+
+ RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+
+ // Check input validity : the user must do a VIDEO CAPTURE and MMAP method.
+ if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+ (vr->memory != V4L2_MEMORY_MMAP))
+ return -EINVAL;
+
+ if(usbvision->streaming == Stream_On) {
+ if ((ret = usbvision_stream_interrupt(usbvision)))
+ return ret;
+ }
+
+ usbvision_empty_framequeues(usbvision);
+
+ usbvision->curFrame = NULL;
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count);
+ return 0;
+ }
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *vb = arg;
+ struct usbvision_frame *frame;
+
+ // FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called)
+
+ if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+ return -EINVAL;
+ }
+ if(vb->index>=USBVISION_NUMFRAMES) {
+ return -EINVAL;
+ }
+ // Updating the corresponding frame state
+ vb->flags = 0;
+ frame = &usbvision->frame[vb->index];
+ if(frame->grabstate >= FrameState_Ready)
+ vb->flags |= V4L2_BUF_FLAG_QUEUED;
+ if(frame->grabstate >= FrameState_Done)
+ vb->flags |= V4L2_BUF_FLAG_DONE;
+ if(frame->grabstate == FrameState_Unused)
+ vb->flags |= V4L2_BUF_FLAG_MAPPED;
+ vb->memory = V4L2_MEMORY_MMAP;
+
+ vb->m.offset = vb->index*usbvision->max_frame_size;
+
+ vb->memory = V4L2_MEMORY_MMAP;
+ vb->field = V4L2_FIELD_NONE;
+ vb->length = usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel;
+ vb->timestamp = usbvision->frame[vb->index].timestamp;
+ vb->sequence = usbvision->frame[vb->index].sequence;
+ return 0;
+ }
+ case VIDIOC_QBUF:
+ {
+ struct v4l2_buffer *vb = arg;
+ struct usbvision_frame *frame;
+ unsigned long lock_flags;
+
+ // FIXME : works only on VIDEO_CAPTURE MODE, MMAP.
+ if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+ return -EINVAL;
+ }
+ if(vb->index>=USBVISION_NUMFRAMES) {
+ return -EINVAL;
+ }
+
+ frame = &usbvision->frame[vb->index];
+
+ if (frame->grabstate != FrameState_Unused) {
+ return -EAGAIN;
+ }
+
+ /* Mark it as ready and enqueue frame */
+ frame->grabstate = FrameState_Ready;
+ frame->scanstate = ScanState_Scanning;
+ frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
+
+ vb->flags &= ~V4L2_BUF_FLAG_DONE;
+
+ /* set v4l2_format index */
+ frame->v4l2_format = usbvision->palette;
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index);
+ return 0;
+ }
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *vb = arg;
+ int ret;
+ struct usbvision_frame *f;
+ unsigned long lock_flags;
+
+ if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (list_empty(&(usbvision->outqueue))) {
+ if (usbvision->streaming == Stream_Idle)
+ return -EINVAL;
+ ret = wait_event_interruptible
+ (usbvision->wait_frame,
+ !list_empty(&(usbvision->outqueue)));
+ if (ret)
+ return ret;
+ }
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ f = list_entry(usbvision->outqueue.next,
+ struct usbvision_frame, frame);
+ list_del(usbvision->outqueue.next);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ f->grabstate = FrameState_Unused;
+
+ vb->memory = V4L2_MEMORY_MMAP;
+ vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE;
+ vb->index = f->index;
+ vb->sequence = f->sequence;
+ vb->timestamp = f->timestamp;
+ vb->field = V4L2_FIELD_NONE;
+ vb->bytesused = f->scanlength;
+
+ return 0;
+ }
+ case VIDIOC_STREAMON:
+ {
+ int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ usbvision->streaming = Stream_On;
+
+ call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON");
+
+ return 0;
+ }
+ case VIDIOC_STREAMOFF:
+ {
+ int *type = arg;
+ int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if(usbvision->streaming == Stream_On) {
+ usbvision_stream_interrupt(usbvision);
+ // Stop all video streamings
+ call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
+ }
+ usbvision_empty_framequeues(usbvision);
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF");
+ return 0;
+ }
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *vfd = arg;
+
+ if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
+ return -EINVAL;
+ }
+ vfd->flags = 0;
+ vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
+ vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
+ memset(vfd->reserved, 0, sizeof(vfd->reserved));
+ return 0;
+ }
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *vf = arg;
+
+ switch (vf->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ vf->fmt.pix.width = usbvision->curwidth;
+ vf->fmt.pix.height = usbvision->curheight;
+ vf->fmt.pix.pixelformat = usbvision->palette.format;
+ vf->fmt.pix.bytesperline = usbvision->curwidth*usbvision->palette.bytes_per_pixel;
+ vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
+ vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
+ PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d, format=%s",
+ vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
+ return 0;
+ }
+ default:
+ PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type);
+ return -EINVAL;
+ }
+ return 0;
+ }
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *vf = arg;
+ int formatIdx,ret;
+
+ switch(vf->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ /* Find requested format in available ones */
+ for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
+ if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) {
+ usbvision->palette = usbvision_v4l2_format[formatIdx];
+ break;
+ }
+ }
+ /* robustness */
+ if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
+ return -EINVAL;
+ }
+ RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
+ RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
+
+ vf->fmt.pix.bytesperline = vf->fmt.pix.width*usbvision->palette.bytes_per_pixel;
+ vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
+
+ if(cmd == VIDIOC_TRY_FMT) {
+ PDEBUG(DBG_IOCTL, "VIDIOC_TRY_FMT grabdisplay w=%d, h=%d, format=%s",
+ vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
+ return 0;
+ }
+
+ /* stop io in case it is already in progress */
+ if(usbvision->streaming == Stream_On) {
+ if ((ret = usbvision_stream_interrupt(usbvision)))
+ return ret;
+ }
+ usbvision_empty_framequeues(usbvision);
+
+ usbvision->curFrame = NULL;
+
+ // by now we are committed to the new data...
+ down(&usbvision->lock);
+ usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
+ up(&usbvision->lock);
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s",
+ vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl);
+}
+
+
+static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ int noblock = file->f_flags & O_NONBLOCK;
+ unsigned long lock_flags;
+
+ int ret,i;
+ struct usbvision_frame *frame;
+
+ PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock);
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
+ return -EFAULT;
+
+ /* no stream is running, make it running ! */
+ usbvision->streaming = Stream_On;
+ call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+
+ /* First, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+ for(i=0;i<USBVISION_NUMFRAMES;i++) {
+ frame = &usbvision->frame[i];
+ if(frame->grabstate == FrameState_Unused) {
+ /* Mark it as ready and enqueue frame */
+ frame->grabstate = FrameState_Ready;
+ frame->scanstate = ScanState_Scanning;
+ frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
+
+ /* set v4l2_format index */
+ frame->v4l2_format = usbvision->palette;
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ list_add_tail(&frame->frame, &usbvision->inqueue);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+ }
+ }
+
+ /* Then try to steal a frame (like a VIDIOC_DQBUF would do) */
+ if (list_empty(&(usbvision->outqueue))) {
+ if(noblock)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible
+ (usbvision->wait_frame,
+ !list_empty(&(usbvision->outqueue)));
+ if (ret)
+ return ret;
+ }
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ frame = list_entry(usbvision->outqueue.next,
+ struct usbvision_frame, frame);
+ list_del(usbvision->outqueue.next);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ /* An error returns an empty frame */
+ if (frame->grabstate == FrameState_Error) {
+ frame->bytes_read = 0;
+ return 0;
+ }
+
+ PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__,
+ frame->index, frame->bytes_read, frame->scanlength);
+
+ /* copy bytes to user space; we allow for partials reads */
+ if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
+ count = frame->scanlength - frame->bytes_read;
+
+ if (copy_to_user(buf, frame->data + frame->bytes_read, count)) {
+ return -EFAULT;
+ }
+
+ frame->bytes_read += count;
+ PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__,
+ (unsigned long)count, frame->bytes_read);
+
+ // For now, forget the frame if it has not been read in one shot.
+/* if (frame->bytes_read >= frame->scanlength) {// All data has been read */
+ frame->bytes_read = 0;
+
+ /* Mark it as available to be used again. */
+ frame->grabstate = FrameState_Unused;
+/* } */
+
+ return count;
+}
+
+static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned long size = vma->vm_end - vma->vm_start,
+ start = vma->vm_start;
+ void *pos;
+ u32 i;
+
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+
+ down(&usbvision->lock);
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision)) {
+ up(&usbvision->lock);
+ return -EFAULT;
+ }
+
+ if (!(vma->vm_flags & VM_WRITE) ||
+ size != PAGE_ALIGN(usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel)) {
+ up(&usbvision->lock);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < USBVISION_NUMFRAMES; i++) {
+ if (((usbvision->max_frame_size*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+ if (i == USBVISION_NUMFRAMES) {
+ PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
+ up(&usbvision->lock);
+ return -EINVAL;
+ }
+
+ /* VM_IO is eventually going to replace PageReserved altogether */
+ vma->vm_flags |= VM_IO;
+ vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+
+ pos = usbvision->frame[i].data;
+ while (size > 0) {
+
+ if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+ PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed");
+ up(&usbvision->lock);
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ up(&usbvision->lock);
+ return 0;
+}
+
+
+/*
+ * Here comes the stuff for radio on usbvision based devices
+ *
+ */
+static int usbvision_radio_open(struct inode *inode, struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct v4l2_frequency freq;
+ int errCode = 0;
+
+ PDEBUG(DBG_IO, "%s:", __FUNCTION__);
+
+ down(&usbvision->lock);
+
+ if (usbvision->user) {
+ err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__);
+ errCode = -EBUSY;
+ }
+ else {
+ if(PowerOnAtOpen) {
+ usbvision_reset_powerOffTimer(usbvision);
+ if (usbvision->power == 0) {
+ usbvision_power_on(usbvision);
+ usbvision_init_i2c(usbvision);
+ }
+ }
+
+ // If so far no errors then we shall start the radio
+ usbvision->radio = 1;
+ call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
+ freq.frequency = 1517; //SWR3 @ 94.8MHz
+ call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq);
+ usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
+ usbvision->user++;
+ }
+
+ if (errCode) {
+ if (PowerOnAtOpen) {
+ usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+ usbvision_power_off(usbvision);
+ usbvision->initialized = 0;
+ }
+ }
+ up(&usbvision->lock);
+ return errCode;
+}
+
+
+static int usbvision_radio_close(struct inode *inode, struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ int errCode = 0;
+
+ PDEBUG(DBG_IO, "");
+
+ down(&usbvision->lock);
+
+ usbvision_audio_off(usbvision);
+ usbvision->radio=0;
+ usbvision->user--;
+
+ if (PowerOnAtOpen) {
+ usbvision_set_powerOffTimer(usbvision);
+ usbvision->initialized = 0;
+ }
+
+ up(&usbvision->lock);
+
+ if (usbvision->remove_pending) {
+ info("%s: Final disconnect", __FUNCTION__);
+ usbvision_release(usbvision);
+ }
+
+
+ PDEBUG(DBG_IO, "success");
+
+ return errCode;
+}
+
+static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
+ return -EIO;
+
+ switch (cmd) {
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *vc=arg;
+
+ memset(vc, 0, sizeof(*vc));
+ strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
+ strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
+ sizeof(vc->card));
+ strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
+ sizeof(vc->bus_info));
+ vc->version = USBVISION_DRIVER_VERSION;
+ vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+ PDEBUG(DBG_IO, "VIDIOC_QUERYCAP");
+ return 0;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *ctrl = arg;
+ int id=ctrl->id;
+
+ memset(ctrl,0,sizeof(*ctrl));
+ ctrl->id=id;
+
+ call_i2c_clients(usbvision, cmd, arg);
+ PDEBUG(DBG_IO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
+
+ if (ctrl->type)
+ return 0;
+ else
+ return -EINVAL;
+
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+ PDEBUG(DBG_IO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
+ return 0;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+ PDEBUG(DBG_IO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
+ return 0;
+ }
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ if (t->index > 0)
+ return -EINVAL;
+
+ memset(t,0,sizeof(*t));
+ strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
+
+ /* Let clients fill in the remainder of this struct */
+ call_i2c_clients(usbvision,VIDIOC_G_TUNER,t);
+ PDEBUG(DBG_IO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc);
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *vt = arg;
+
+ // Only no or one tuner for now
+ if (!usbvision->have_tuner || vt->index)
+ return -EINVAL;
+ /* let clients handle this */
+ call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
+
+ PDEBUG(DBG_IO, "VIDIOC_S_TUNER");
+ return 0;
+ }
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *a = arg;
+
+ memset(a,0,sizeof(*a));
+ strcpy(a->name,"Radio");
+ PDEBUG(DBG_IO, "VIDIOC_G_AUDIO");
+ return 0;
+ }
+ case VIDIOC_S_AUDIO:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_STD:
+ return 0;
+
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ memset(f,0,sizeof(*f));
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = usbvision->freq;
+ call_i2c_clients(usbvision, cmd, f);
+ PDEBUG(DBG_IO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency);
+
+ return 0;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ if (f->tuner != 0)
+ return -EINVAL;
+ usbvision->freq = f->frequency;
+ call_i2c_clients(usbvision, cmd, f);
+ PDEBUG(DBG_IO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency);
+
+ return 0;
+ }
+ default:
+ {
+ PDEBUG(DBG_IO, "%s: Unknown command %x", __FUNCTION__, cmd);
+ return -ENOIOCTLCMD;
+ }
+ }
+ return 0;
+}
+
+
+static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl);
+}
+
+
+/*
+ * Here comes the stuff for vbi on usbvision based devices
+ *
+ */
+static int usbvision_vbi_open(struct inode *inode, struct file *file)
+{
+ /* TODO */
+ return -EINVAL;
+
+}
+
+static int usbvision_vbi_close(struct inode *inode, struct file *file)
+{
+ /* TODO */
+ return -EINVAL;
+}
+
+static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ /* TODO */
+ return -EINVAL;
+}
+
+static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return video_usercopy(inode, file, cmd, arg, usbvision_do_vbi_ioctl);
+}
+
+
+//
+// Video registration stuff
+//
+
+// Video template
+static struct file_operations usbvision_fops = {
+ .owner = THIS_MODULE,
+ .open = usbvision_v4l2_open,
+ .release = usbvision_v4l2_close,
+ .read = usbvision_v4l2_read,
+ .mmap = usbvision_v4l2_mmap,
+ .ioctl = usbvision_v4l2_ioctl,
+ .llseek = no_llseek,
+};
+static struct video_device usbvision_video_template = {
+ .owner = THIS_MODULE,
+ .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE,
+ .hardware = VID_HARDWARE_USBVISION,
+ .fops = &usbvision_fops,
+ .name = "usbvision-video",
+ .release = video_device_release,
+ .minor = -1,
+};
+
+
+// Radio template
+static struct file_operations usbvision_radio_fops = {
+ .owner = THIS_MODULE,
+ .open = usbvision_radio_open,
+ .release = usbvision_radio_close,
+ .ioctl = usbvision_radio_ioctl,
+ .llseek = no_llseek,
+};
+
+static struct video_device usbvision_radio_template=
+{
+ .owner = THIS_MODULE,
+ .type = VID_TYPE_TUNER,
+ .hardware = VID_HARDWARE_USBVISION,
+ .fops = &usbvision_radio_fops,
+ .release = video_device_release,
+ .name = "usbvision-radio",
+ .minor = -1,
+};
+
+
+// vbi template
+static struct file_operations usbvision_vbi_fops = {
+ .owner = THIS_MODULE,
+ .open = usbvision_vbi_open,
+ .release = usbvision_vbi_close,
+ .ioctl = usbvision_vbi_ioctl,
+ .llseek = no_llseek,
+};
+
+static struct video_device usbvision_vbi_template=
+{
+ .owner = THIS_MODULE,
+ .type = VID_TYPE_TUNER,
+ .hardware = VID_HARDWARE_USBVISION,
+ .fops = &usbvision_vbi_fops,
+ .release = video_device_release,
+ .name = "usbvision-vbi",
+ .minor = -1,
+};
+
+
+static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
+ struct video_device *vdev_template,
+ char *name)
+{
+ struct usb_device *usb_dev = usbvision->dev;
+ struct video_device *vdev;
+
+ if (usb_dev == NULL) {
+ err("%s: usbvision->dev is not set", __FUNCTION__);
+ return NULL;
+ }
+
+ vdev = video_device_alloc();
+ if (NULL == vdev) {
+ return NULL;
+ }
+ *vdev = *vdev_template;
+// vdev->minor = -1;
+ vdev->dev = &usb_dev->dev;
+ snprintf(vdev->name, sizeof(vdev->name), "%s", name);
+ video_set_drvdata(vdev, usbvision);
+ return vdev;
+}
+
+// unregister video4linux devices
+static void usbvision_unregister_video(struct usb_usbvision *usbvision)
+{
+ // vbi Device:
+ if (usbvision->vbi) {
+ PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f);
+ if (usbvision->vbi->minor != -1) {
+ video_unregister_device(usbvision->vbi);
+ }
+ else {
+ video_device_release(usbvision->vbi);
+ }
+ usbvision->vbi = NULL;
+ }
+
+ // Radio Device:
+ if (usbvision->rdev) {
+ PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f);
+ if (usbvision->rdev->minor != -1) {
+ video_unregister_device(usbvision->rdev);
+ }
+ else {
+ video_device_release(usbvision->rdev);
+ }
+ usbvision->rdev = NULL;
+ }
+
+ // Video Device:
+ if (usbvision->vdev) {
+ PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f);
+ if (usbvision->vdev->minor != -1) {
+ video_unregister_device(usbvision->vdev);
+ }
+ else {
+ video_device_release(usbvision->vdev);
+ }
+ usbvision->vdev = NULL;
+ }
+}
+
+// register video4linux devices
+static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
+{
+ // Video Device:
+ usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video");
+ if (usbvision->vdev == NULL) {
+ goto err_exit;
+ }
+ if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) {
+ goto err_exit;
+ }
+ info("USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]", usbvision->nr,usbvision->vdev->minor & 0x1f);
+
+ // Radio Device:
+ if (usbvision_device_data[usbvision->DevModel].Radio) {
+ // usbvision has radio
+ usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio");
+ if (usbvision->rdev == NULL) {
+ goto err_exit;
+ }
+ if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) {
+ goto err_exit;
+ }
+ info("USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]", usbvision->nr, usbvision->rdev->minor & 0x1f);
+ }
+ // vbi Device:
+ if (usbvision_device_data[usbvision->DevModel].vbi) {
+ usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI");
+ if (usbvision->vdev == NULL) {
+ goto err_exit;
+ }
+ if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) {
+ goto err_exit;
+ }
+ info("USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)", usbvision->nr,usbvision->vbi->minor & 0x1f);
+ }
+ // all done
+ return 0;
+
+ err_exit:
+ err("USBVision[%d]: video_register_device() failed", usbvision->nr);
+ usbvision_unregister_video(usbvision);
+ return -1;
+}
+
+/*
+ * usbvision_alloc()
+ *
+ * This code allocates the struct usb_usbvision. It is filled with default values.
+ *
+ * Returns NULL on error, a pointer to usb_usbvision else.
+ *
+ */
+static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
+{
+ struct usb_usbvision *usbvision;
+
+ if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) {
+ goto err_exit;
+ }
+
+ usbvision->dev = dev;
+
+ init_MUTEX(&usbvision->lock); /* to 1 == available */
+
+ // prepare control urb for control messages during interrupts
+ usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
+ if (usbvision->ctrlUrb == NULL) {
+ goto err_exit;
+ }
+ init_waitqueue_head(&usbvision->ctrlUrb_wq);
+ init_MUTEX(&usbvision->ctrlUrbLock); /* to 1 == available */
+
+ usbvision_init_powerOffTimer(usbvision);
+
+ return usbvision;
+
+err_exit:
+ if (usbvision && usbvision->ctrlUrb) {
+ usb_free_urb(usbvision->ctrlUrb);
+ }
+ if (usbvision) {
+ kfree(usbvision);
+ }
+ return NULL;
+}
+
+/*
+ * usbvision_release()
+ *
+ * This code does final release of struct usb_usbvision. This happens
+ * after the device is disconnected -and- all clients closed their files.
+ *
+ */
+static void usbvision_release(struct usb_usbvision *usbvision)
+{
+ PDEBUG(DBG_PROBE, "");
+
+ down(&usbvision->lock);
+
+ usbvision_reset_powerOffTimer(usbvision);
+
+ usbvision->initialized = 0;
+
+ up(&usbvision->lock);
+
+ usbvision_remove_sysfs(usbvision->vdev);
+ usbvision_unregister_video(usbvision);
+
+ if (usbvision->ctrlUrb) {
+ usb_free_urb(usbvision->ctrlUrb);
+ }
+
+ kfree(usbvision);
+
+ PDEBUG(DBG_PROBE, "success");
+}
+
+
+/******************************** usb interface *****************************************/
+
+static void usbvision_configure_video(struct usb_usbvision *usbvision)
+{
+ int model,i;
+
+ if (usbvision == NULL)
+ return;
+
+ model = usbvision->DevModel;
+ usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24;
+
+ if (usbvision_device_data[usbvision->DevModel].Vin_Reg2 >= 0) {
+ usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2 & 0xff;
+ } else {
+ usbvision->Vin_Reg2_Preset = 0;
+ }
+
+ for (i = 0; i < TVNORMS; i++)
+ if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode)
+ break;
+ if (i == TVNORMS)
+ i = 0;
+ usbvision->tvnorm = &tvnorms[i]; /* set default norm */
+
+ usbvision->video_inputs = usbvision_device_data[model].VideoChannels;
+ usbvision->ctl_input = 0;
+
+ /* This should be here to make i2c clients to be able to register */
+ usbvision_audio_off(usbvision); //first switch off audio
+ if (!PowerOnAtOpen) {
+ usbvision_power_on(usbvision); //and then power up the noisy tuner
+ usbvision_init_i2c(usbvision);
+ }
+}
+
+/*
+ * usbvision_probe()
+ *
+ * This procedure queries device descriptor and accepts the interface
+ * if it looks like USBVISION video device
+ *
+ */
+static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ __u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
+ const struct usb_host_interface *interface;
+ struct usb_usbvision *usbvision = NULL;
+ const struct usb_endpoint_descriptor *endpoint;
+ int model;
+
+ PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
+ dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+ /* Is it an USBVISION video dev? */
+ model = 0;
+ for(model = 0; usbvision_device_data[model].idVendor; model++) {
+ if (le16_to_cpu(dev->descriptor.idVendor) != usbvision_device_data[model].idVendor) {
+ continue;
+ }
+ if (le16_to_cpu(dev->descriptor.idProduct) != usbvision_device_data[model].idProduct) {
+ continue;
+ }
+
+ info("%s: %s found", __FUNCTION__, usbvision_device_data[model].ModelString);
+ break;
+ }
+
+ if (usbvision_device_data[model].idVendor == 0) {
+ return -ENODEV; //no matching device
+ }
+ if (usbvision_device_data[model].Interface >= 0) {
+ interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0];
+ }
+ else {
+ interface = &dev->actconfig->interface[ifnum]->altsetting[0];
+ }
+ endpoint = &interface->endpoint[1].desc;
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) {
+ err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum);
+ err("%s: Endpoint attribures %d", __FUNCTION__, endpoint->bmAttributes);
+ return -ENODEV;
+ }
+ if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+ err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum);
+ return -ENODEV;
+ }
+
+ usb_get_dev(dev);
+
+ if ((usbvision = usbvision_alloc(dev)) == NULL) {
+ err("%s: couldn't allocate USBVision struct", __FUNCTION__);
+ return -ENOMEM;
+ }
+ if (dev->descriptor.bNumConfigurations > 1) {
+ usbvision->bridgeType = BRIDGE_NT1004;
+ }
+ else if (usbvision_device_data[model].ModelString == "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)") {
+ usbvision->bridgeType = BRIDGE_NT1005;
+ }
+ else {
+ usbvision->bridgeType = BRIDGE_NT1003;
+ }
+ PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
+
+ down(&usbvision->lock);
+
+ usbvision->nr = usbvision_nr++;
+
+ usbvision->have_tuner = usbvision_device_data[model].Tuner;
+ if (usbvision->have_tuner) {
+ usbvision->tuner_type = usbvision_device_data[model].TunerType;
+ }
+
+ usbvision->tuner_addr = ADDR_UNSET;
+
+ usbvision->DevModel = model;
+ usbvision->remove_pending = 0;
+ usbvision->iface = ifnum;
+ usbvision->ifaceAltInactive = 0;
+ usbvision->ifaceAltActive = 1;
+ usbvision->video_endp = endpoint->bEndpointAddress;
+ usbvision->isocPacketSize = 0;
+ usbvision->usb_bandwidth = 0;
+ usbvision->user = 0;
+ usbvision->streaming = Stream_Off;
+ usbvision_register_video(usbvision);
+ usbvision_configure_video(usbvision);
+ up(&usbvision->lock);
+
+
+ usb_set_intfdata (intf, usbvision);
+ usbvision_create_sysfs(usbvision->vdev);
+
+ PDEBUG(DBG_PROBE, "success");
+ return 0;
+}
+
+
+/*
+ * usbvision_disconnect()
+ *
+ * This procedure stops all driver activity, deallocates interface-private
+ * structure (pointed by 'ptr') and after that driver should be removable
+ * with no ill consequences.
+ *
+ */
+static void __devexit usbvision_disconnect(struct usb_interface *intf)
+{
+ struct usb_usbvision *usbvision = usb_get_intfdata(intf);
+
+ PDEBUG(DBG_PROBE, "");
+
+ if (usbvision == NULL) {
+ err("%s: usb_get_intfdata() failed", __FUNCTION__);
+ return;
+ }
+ usb_set_intfdata (intf, NULL);
+
+ down(&usbvision->lock);
+
+ // At this time we ask to cancel outstanding URBs
+ usbvision_stop_isoc(usbvision);
+
+ if (usbvision->power) {
+ usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+ usbvision_power_off(usbvision);
+ }
+ usbvision->remove_pending = 1; // Now all ISO data will be ignored
+
+ usb_put_dev(usbvision->dev);
+ usbvision->dev = NULL; // USB device is no more
+
+ up(&usbvision->lock);
+
+ if (usbvision->user) {
+ info("%s: In use, disconnect pending", __FUNCTION__);
+ wake_up_interruptible(&usbvision->wait_frame);
+ wake_up_interruptible(&usbvision->wait_stream);
+ }
+ else {
+ usbvision_release(usbvision);
+ }
+
+ PDEBUG(DBG_PROBE, "success");
+
+}
+
+static struct usb_driver usbvision_driver = {
+ .name = "usbvision",
+ .id_table = usbvision_table,
+ .probe = usbvision_probe,
+ .disconnect = usbvision_disconnect
+};
+
+/*
+ * customdevice_process()
+ *
+ * This procedure preprocesses CustomDevice parameter if any
+ *
+ */
+static void customdevice_process(void)
+{
+ usbvision_device_data[0]=usbvision_device_data[1];
+ usbvision_table[0]=usbvision_table[1];
+
+ if(CustomDevice)
+ {
+ char *parse=CustomDevice;
+
+ PDEBUG(DBG_PROBE, "CustomDevide=%s", CustomDevice);
+
+ /*format is CustomDevice="0x0573 0x4D31 0 7113 3 PAL 1 1 1 5 -1 -1 -1 -1 -1"
+ usbvision_device_data[0].idVendor;
+ usbvision_device_data[0].idProduct;
+ usbvision_device_data[0].Interface;
+ usbvision_device_data[0].Codec;
+ usbvision_device_data[0].VideoChannels;
+ usbvision_device_data[0].VideoNorm;
+ usbvision_device_data[0].AudioChannels;
+ usbvision_device_data[0].Radio;
+ usbvision_device_data[0].Tuner;
+ usbvision_device_data[0].TunerType;
+ usbvision_device_data[0].Vin_Reg1;
+ usbvision_device_data[0].Vin_Reg2;
+ usbvision_device_data[0].X_Offset;
+ usbvision_device_data[0].Y_Offset;
+ usbvision_device_data[0].Dvi_yuv;
+ usbvision_device_data[0].ModelString;
+ */
+
+ rmspace(parse);
+ usbvision_device_data[0].ModelString="USBVISION Custom Device";
+
+ parse+=2;
+ sscanf(parse,"%x",&usbvision_device_data[0].idVendor);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "idVendor=0x%.4X", usbvision_device_data[0].idVendor);
+ parse+=2;
+ sscanf(parse,"%x",&usbvision_device_data[0].idProduct);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "idProduct=0x%.4X", usbvision_device_data[0].idProduct);
+ sscanf(parse,"%d",&usbvision_device_data[0].Interface);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "Interface=%d", usbvision_device_data[0].Interface);
+ sscanf(parse,"%d",&usbvision_device_data[0].Codec);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "Codec=%d", usbvision_device_data[0].Codec);
+ sscanf(parse,"%d",&usbvision_device_data[0].VideoChannels);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "VideoChannels=%d", usbvision_device_data[0].VideoChannels);
+
+ switch(*parse)
+ {
+ case 'P':
+ PDEBUG(DBG_PROBE, "VideoNorm=PAL");
+ usbvision_device_data[0].VideoNorm=V4L2_STD_PAL;
+ break;
+
+ case 'S':
+ PDEBUG(DBG_PROBE, "VideoNorm=SECAM");
+ usbvision_device_data[0].VideoNorm=V4L2_STD_SECAM;
+ break;
+
+ case 'N':
+ PDEBUG(DBG_PROBE, "VideoNorm=NTSC");
+ usbvision_device_data[0].VideoNorm=V4L2_STD_NTSC;
+ break;
+
+ default:
+ PDEBUG(DBG_PROBE, "VideoNorm=PAL (by default)");
+ usbvision_device_data[0].VideoNorm=V4L2_STD_PAL;
+ break;
+ }
+ goto2next(parse);
+
+ sscanf(parse,"%d",&usbvision_device_data[0].AudioChannels);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "AudioChannels=%d", usbvision_device_data[0].AudioChannels);
+ sscanf(parse,"%d",&usbvision_device_data[0].Radio);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "Radio=%d", usbvision_device_data[0].Radio);
+ sscanf(parse,"%d",&usbvision_device_data[0].Tuner);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "Tuner=%d", usbvision_device_data[0].Tuner);
+ sscanf(parse,"%d",&usbvision_device_data[0].TunerType);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "TunerType=%d", usbvision_device_data[0].TunerType);
+ sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg1);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "Vin_Reg1=%d", usbvision_device_data[0].Vin_Reg1);
+ sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg2);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "Vin_Reg2=%d", usbvision_device_data[0].Vin_Reg2);
+ sscanf(parse,"%d",&usbvision_device_data[0].X_Offset);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "X_Offset=%d", usbvision_device_data[0].X_Offset);
+ sscanf(parse,"%d",&usbvision_device_data[0].Y_Offset);
+ goto2next(parse);
+ PDEBUG(DBG_PROBE, "Y_Offset=%d", usbvision_device_data[0].Y_Offset);
+ sscanf(parse,"%d",&usbvision_device_data[0].Dvi_yuv);
+ PDEBUG(DBG_PROBE, "Dvi_yuv=%d", usbvision_device_data[0].Dvi_yuv);
+
+ //add to usbvision_table also
+ usbvision_table[0].match_flags=USB_DEVICE_ID_MATCH_DEVICE;
+ usbvision_table[0].idVendor=usbvision_device_data[0].idVendor;
+ usbvision_table[0].idProduct=usbvision_device_data[0].idProduct;
+
+ }
+}
+
+
+
+/*
+ * usbvision_init()
+ *
+ * This code is run to initialize the driver.
+ *
+ */
+static int __init usbvision_init(void)
+{
+ int errCode;
+
+ PDEBUG(DBG_PROBE, "");
+
+ PDEBUG(DBG_IOCTL, "IOCTL debugging is enabled [video]");
+ PDEBUG(DBG_IO, "IO debugging is enabled [video]");
+ PDEBUG(DBG_PROBE, "PROBE debugging is enabled [video]");
+ PDEBUG(DBG_MMAP, "MMAP debugging is enabled [video]");
+
+ /* disable planar mode support unless compression enabled */
+ if (isocMode != ISOC_MODE_COMPRESS ) {
+ // FIXME : not the right way to set supported flag
+ usbvision_v4l2_format[6].supported = 0; // V4L2_PIX_FMT_YVU420
+ usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P
+ }
+
+ customdevice_process();
+
+ errCode = usb_register(&usbvision_driver);
+
+ if (errCode == 0) {
+ info(DRIVER_DESC " : " USBVISION_VERSION_STRING);
+ PDEBUG(DBG_PROBE, "success");
+ }
+ return errCode;
+}
+
+static void __exit usbvision_exit(void)
+{
+ PDEBUG(DBG_PROBE, "");
+
+ usb_deregister(&usbvision_driver);
+ PDEBUG(DBG_PROBE, "success");
+}
+
+module_init(usbvision_init);
+module_exit(usbvision_exit);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
new file mode 100644
index 00000000000..e2bcaba9387
--- /dev/null
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -0,0 +1,531 @@
+/*
+ * USBVISION.H
+ * usbvision header file
+ *
+ * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ * Dwaine Garden <dwainegarden@rogers.com>
+ *
+ *
+ * Report problems to v4l MailingList : http://www.redhat.com/mailman/listinfo/video4linux-list
+ *
+ * This module is part of usbvision driver project.
+ * Updates to driver completed by Dwaine P. Garden
+ * v4l2 conversion by Thierry Merle <thierry.merle@free.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; 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 __LINUX_USBVISION_H
+#define __LINUX_USBVISION_H
+
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <linux/videodev2.h>
+
+#define USBVISION_DEBUG /* Turn on debug messages */
+
+#ifndef VID_HARDWARE_USBVISION
+ #define VID_HARDWARE_USBVISION 34 /* USBVision Video Grabber */
+#endif
+
+#define USBVISION_PWR_REG 0x00
+ #define USBVISION_SSPND_EN (1 << 1)
+ #define USBVISION_RES2 (1 << 2)
+ #define USBVISION_PWR_VID (1 << 5)
+ #define USBVISION_E2_EN (1 << 7)
+#define USBVISION_CONFIG_REG 0x01
+#define USBVISION_ADRS_REG 0x02
+#define USBVISION_ALTER_REG 0x03
+#define USBVISION_FORCE_ALTER_REG 0x04
+#define USBVISION_STATUS_REG 0x05
+#define USBVISION_IOPIN_REG 0x06
+ #define USBVISION_IO_1 (1 << 0)
+ #define USBVISION_IO_2 (1 << 1)
+ #define USBVISION_AUDIO_IN 0
+ #define USBVISION_AUDIO_TV 1
+ #define USBVISION_AUDIO_RADIO 2
+ #define USBVISION_AUDIO_MUTE 3
+#define USBVISION_SER_MODE 0x07
+#define USBVISION_SER_ADRS 0x08
+#define USBVISION_SER_CONT 0x09
+#define USBVISION_SER_DAT1 0x0A
+#define USBVISION_SER_DAT2 0x0B
+#define USBVISION_SER_DAT3 0x0C
+#define USBVISION_SER_DAT4 0x0D
+#define USBVISION_EE_DATA 0x0E
+#define USBVISION_EE_LSBAD 0x0F
+#define USBVISION_EE_CONT 0x10
+#define USBVISION_DRM_CONT 0x12
+ #define USBVISION_REF (1 << 0)
+ #define USBVISION_RES_UR (1 << 2)
+ #define USBVISION_RES_FDL (1 << 3)
+ #define USBVISION_RES_VDW (1 << 4)
+#define USBVISION_DRM_PRM1 0x13
+#define USBVISION_DRM_PRM2 0x14
+#define USBVISION_DRM_PRM3 0x15
+#define USBVISION_DRM_PRM4 0x16
+#define USBVISION_DRM_PRM5 0x17
+#define USBVISION_DRM_PRM6 0x18
+#define USBVISION_DRM_PRM7 0x19
+#define USBVISION_DRM_PRM8 0x1A
+#define USBVISION_VIN_REG1 0x1B
+ #define USBVISION_8_422_SYNC 0x01
+ #define USBVISION_16_422_SYNC 0x02
+ #define USBVISION_VSNC_POL (1 << 3)
+ #define USBVISION_HSNC_POL (1 << 4)
+ #define USBVISION_FID_POL (1 << 5)
+ #define USBVISION_HVALID_PO (1 << 6)
+ #define USBVISION_VCLK_POL (1 << 7)
+#define USBVISION_VIN_REG2 0x1C
+ #define USBVISION_AUTO_FID (1 << 0)
+ #define USBVISION_NONE_INTER (1 << 1)
+ #define USBVISION_NOHVALID (1 << 2)
+ #define USBVISION_UV_ID (1 << 3)
+ #define USBVISION_FIX_2C (1 << 4)
+ #define USBVISION_SEND_FID (1 << 5)
+ #define USBVISION_KEEP_BLANK (1 << 7)
+#define USBVISION_LXSIZE_I 0x1D
+#define USBVISION_MXSIZE_I 0x1E
+#define USBVISION_LYSIZE_I 0x1F
+#define USBVISION_MYSIZE_I 0x20
+#define USBVISION_LX_OFFST 0x21
+#define USBVISION_MX_OFFST 0x22
+#define USBVISION_LY_OFFST 0x23
+#define USBVISION_MY_OFFST 0x24
+#define USBVISION_FRM_RATE 0x25
+#define USBVISION_LXSIZE_O 0x26
+#define USBVISION_MXSIZE_O 0x27
+#define USBVISION_LYSIZE_O 0x28
+#define USBVISION_MYSIZE_O 0x29
+#define USBVISION_FILT_CONT 0x2A
+#define USBVISION_VO_MODE 0x2B
+#define USBVISION_INTRA_CYC 0x2C
+#define USBVISION_STRIP_SZ 0x2D
+#define USBVISION_FORCE_INTRA 0x2E
+#define USBVISION_FORCE_UP 0x2F
+#define USBVISION_BUF_THR 0x30
+#define USBVISION_DVI_YUV 0x31
+#define USBVISION_AUDIO_CONT 0x32
+#define USBVISION_AUD_PK_LEN 0x33
+#define USBVISION_BLK_PK_LEN 0x34
+#define USBVISION_PCM_THR1 0x38
+#define USBVISION_PCM_THR2 0x39
+#define USBVISION_DIST_THR_L 0x3A
+#define USBVISION_DIST_THR_H 0x3B
+#define USBVISION_MAX_DIST_L 0x3C
+#define USBVISION_MAX_DIST_H 0x3D
+#define USBVISION_OP_CODE 0x33
+
+#define MAX_BYTES_PER_PIXEL 4
+
+#define MIN_FRAME_WIDTH 64
+#define MAX_USB_WIDTH 320 //384
+#define MAX_FRAME_WIDTH 320 //384 /*streching sometimes causes crashes*/
+
+#define MIN_FRAME_HEIGHT 48
+#define MAX_USB_HEIGHT 240 //288
+#define MAX_FRAME_HEIGHT 240 //288 /*Streching sometimes causes crashes*/
+
+#define MAX_FRAME_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * MAX_BYTES_PER_PIXEL)
+#define USBVISION_CLIPMASK_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT / 8) //bytesize of clipmask
+
+#define USBVISION_URB_FRAMES 32
+#define USBVISION_MAX_ISOC_PACKET_SIZE 959 // NT1003 Specs Document says 1023
+
+#define USBVISION_NUM_HEADERMARKER 20
+#define USBVISION_NUMFRAMES 3 /* Maximum number of frames an application can get */
+#define USBVISION_NUMSBUF 2 /* Dimensioning the USB S buffering */
+
+#define USBVISION_POWEROFF_TIME 3 * (HZ) // 3 seconds
+
+
+#define FRAMERATE_MIN 0
+#define FRAMERATE_MAX 31
+
+enum {
+ ISOC_MODE_YUV422 = 0x03,
+ ISOC_MODE_YUV420 = 0x14,
+ ISOC_MODE_COMPRESS = 0x60,
+};
+
+/* This macro restricts an int variable to an inclusive range */
+#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
+
+/*
+ * We use macros to do YUV -> RGB conversion because this is
+ * very important for speed and totally unimportant for size.
+ *
+ * YUV -> RGB Conversion
+ * ---------------------
+ *
+ * B = 1.164*(Y-16) + 2.018*(V-128)
+ * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128)
+ * R = 1.164*(Y-16) + 1.596*(U-128)
+ *
+ * If you fancy integer arithmetics (as you should), hear this:
+ *
+ * 65536*B = 76284*(Y-16) + 132252*(V-128)
+ * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128)
+ * 65536*R = 76284*(Y-16) + 104595*(U-128)
+ *
+ * Make sure the output values are within [0..255] range.
+ */
+#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
+#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
+ int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
+ mm_y = (my) - 16; \
+ mm_u = (mu) - 128; \
+ mm_v = (mv) - 128; \
+ mm_yc= mm_y * 76284; \
+ mm_b = (mm_yc + 132252*mm_v ) >> 16; \
+ mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \
+ mm_r = (mm_yc + 104595*mm_u ) >> 16; \
+ mb = LIMIT_RGB(mm_b); \
+ mg = LIMIT_RGB(mm_g); \
+ mr = LIMIT_RGB(mm_r); \
+}
+
+/* Debugging aid */
+#define USBVISION_SAY_AND_WAIT(what) { \
+ wait_queue_head_t wq; \
+ init_waitqueue_head(&wq); \
+ printk(KERN_INFO "Say: %s\n", what); \
+ interruptible_sleep_on_timeout (&wq, HZ*3); \
+}
+
+/*
+ * This macro checks if usbvision is still operational. The 'usbvision'
+ * pointer must be valid, usbvision->dev must be valid, we are not
+ * removing the device and the device has not erred on us.
+ */
+#define USBVISION_IS_OPERATIONAL(udevice) (\
+ (udevice != NULL) && \
+ ((udevice)->dev != NULL) && \
+ ((udevice)->last_error == 0) && \
+ (!(udevice)->remove_pending))
+
+#define I2C_USB_ADAP_MAX 16
+
+/* ----------------------------------------------------------------- */
+/* usbvision video structures */
+/* ----------------------------------------------------------------- */
+enum ScanState {
+ ScanState_Scanning, /* Scanning for header */
+ ScanState_Lines /* Parsing lines */
+};
+
+/* Completion states of the data parser */
+enum ParseState {
+ ParseState_Continue, /* Just parse next item */
+ ParseState_NextFrame, /* Frame done, send it to V4L */
+ ParseState_Out, /* Not enough data for frame */
+ ParseState_EndParse /* End parsing */
+};
+
+enum FrameState {
+ FrameState_Unused, /* Unused (no MCAPTURE) */
+ FrameState_Ready, /* Ready to start grabbing */
+ FrameState_Grabbing, /* In the process of being grabbed into */
+ FrameState_Done, /* Finished grabbing, but not been synced yet */
+ FrameState_DoneHold, /* Are syncing or reading */
+ FrameState_Error, /* Something bad happened while processing */
+};
+
+/* stream states */
+enum StreamState {
+ Stream_Off, /* Driver streaming is completely OFF */
+ Stream_Idle, /* Driver streaming is ready to be put ON by the application */
+ Stream_Interrupt, /* Driver streaming must be interrupted */
+ Stream_On, /* Driver streaming is put ON by the application */
+};
+
+enum IsocState {
+ IsocState_InFrame, /* Isoc packet is member of frame */
+ IsocState_NoFrame, /* Isoc packet is not member of any frame */
+};
+
+struct usb_device;
+
+struct usbvision_sbuf {
+ char *data;
+ struct urb *urb;
+};
+
+#define USBVISION_MAGIC_1 0x55
+#define USBVISION_MAGIC_2 0xAA
+#define USBVISION_HEADER_LENGTH 0x0c
+#define USBVISION_SAA7111_ADDR 0x48
+#define USBVISION_SAA7113_ADDR 0x4a
+#define USBVISION_IIC_LRACK 0x20
+#define USBVISION_IIC_LRNACK 0x30
+#define USBVISION_FRAME_FORMAT_PARAM_INTRA (1<<7)
+
+struct usbvision_v4l2_format_st {
+ int supported;
+ int bytes_per_pixel;
+ int depth;
+ int format;
+ char *desc;
+};
+#define USBVISION_SUPPORTED_PALETTES ARRAY_SIZE(usbvision_v4l2_format)
+
+struct usbvision_frame_header {
+ unsigned char magic_1; /* 0 magic */
+ unsigned char magic_2; /* 1 magic */
+ unsigned char headerLength; /* 2 */
+ unsigned char frameNum; /* 3 */
+ unsigned char framePhase; /* 4 */
+ unsigned char frameLatency; /* 5 */
+ unsigned char dataFormat; /* 6 */
+ unsigned char formatParam; /* 7 */
+ unsigned char frameWidthLo; /* 8 */
+ unsigned char frameWidthHi; /* 9 */
+ unsigned char frameHeightLo; /* 10 */
+ unsigned char frameHeightHi; /* 11 */
+ __u16 frameWidth; /* 8 - 9 after endian correction*/
+ __u16 frameHeight; /* 10 - 11 after endian correction*/
+};
+
+/* tvnorms */
+struct usbvision_tvnorm {
+ char *name;
+ v4l2_std_id id;
+ /* mode for saa7113h */
+ int mode;
+};
+
+struct usbvision_frame {
+ char *data; /* Frame buffer */
+ struct usbvision_frame_header isocHeader; /* Header from stream */
+
+ int width; /* Width application is expecting */
+ int height; /* Height */
+ int index; /* Frame index */
+ int frmwidth; /* Width the frame actually is */
+ int frmheight; /* Height */
+
+ volatile int grabstate; /* State of grabbing */
+ int scanstate; /* State of scanning */
+
+ struct list_head frame;
+
+ int curline; /* Line of frame we're working on */
+
+ long scanlength; /* uncompressed, raw data length of frame */
+ long bytes_read; /* amount of scanlength that has been read from data */
+ struct usbvision_v4l2_format_st v4l2_format; /* format the user needs*/
+ int v4l2_linesize; /* bytes for one videoline*/
+ struct timeval timestamp;
+ int sequence; // How many video frames we send to user
+};
+
+#define CODEC_SAA7113 7113
+#define CODEC_SAA7111 7111
+#define BRIDGE_NT1003 1003
+#define BRIDGE_NT1004 1004
+#define BRIDGE_NT1005 1005
+
+struct usbvision_device_data_st {
+ int idVendor;
+ int idProduct;
+ int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */
+ int Codec;
+ int VideoChannels;
+ __u64 VideoNorm;
+ int AudioChannels;
+ int Radio;
+ int vbi;
+ int Tuner;
+ int TunerType;
+ int Vin_Reg1;
+ int Vin_Reg2;
+ int X_Offset;
+ int Y_Offset;
+ int Dvi_yuv;
+ char *ModelString;
+};
+
+/* Declared on usbvision-cards.c */
+extern struct usbvision_device_data_st usbvision_device_data[];
+extern struct usb_device_id usbvision_table[];
+
+struct usb_usbvision {
+ struct video_device *vdev; /* Video Device */
+ struct video_device *rdev; /* Radio Device */
+ struct video_device *vbi; /* VBI Device */
+
+ /* i2c Declaration Section*/
+ struct i2c_adapter i2c_adap;
+ struct i2c_client i2c_client;
+
+ struct urb *ctrlUrb;
+ unsigned char ctrlUrbBuffer[8];
+ int ctrlUrbBusy;
+ struct usb_ctrlrequest ctrlUrbSetup;
+ wait_queue_head_t ctrlUrb_wq; // Processes waiting
+ struct semaphore ctrlUrbLock;
+
+ /* configuration part */
+ int have_tuner;
+ int tuner_type;
+ int tuner_addr;
+ int bridgeType; // NT1003, NT1004, NT1005
+ int channel;
+ int radio;
+ int video_inputs; // # of inputs
+ unsigned long freq;
+ int AudioMute;
+ int AudioChannel;
+ int isocMode; // format of video data for the usb isoc-transfer
+ unsigned int nr; // Number of the device
+
+ /* Device structure */
+ struct usb_device *dev;
+ unsigned char iface; /* Video interface number */
+ unsigned char ifaceAltActive, ifaceAltInactive; /* Alt settings */
+ unsigned char Vin_Reg2_Preset;
+ struct semaphore lock;
+ struct timer_list powerOffTimer;
+ struct work_struct powerOffWork;
+ int power; /* is the device powered on? */
+ int user; /* user count for exclusive use */
+ int initialized; /* Had we already sent init sequence? */
+ int DevModel; /* What type of USBVISION device we got? */
+ enum StreamState streaming; /* Are we streaming Isochronous? */
+ int last_error; /* What calamity struck us? */
+ int curwidth; /* width of the frame the device is currently set to*/
+ int curheight; /* height of the frame the device is currently set to*/
+ int stretch_width; /* stretch-factor for frame width (from usb to screen)*/
+ int stretch_height; /* stretch-factor for frame height (from usb to screen)*/
+ char *fbuf; /* Videodev buffer area for mmap*/
+ int max_frame_size; /* Bytes in one video frame */
+ int fbuf_size; /* Videodev buffer size */
+ spinlock_t queue_lock; /* spinlock for protecting mods on inqueue and outqueue */
+ struct list_head inqueue, outqueue; /* queued frame list and ready to dequeue frame list */
+ wait_queue_head_t wait_frame; /* Processes waiting */
+ wait_queue_head_t wait_stream; /* Processes waiting */
+ struct usbvision_frame *curFrame; // pointer to current frame, set by usbvision_find_header
+ struct usbvision_frame frame[USBVISION_NUMFRAMES]; // frame buffer
+ struct usbvision_sbuf sbuf[USBVISION_NUMSBUF]; // S buffering
+ volatile int remove_pending; /* If set then about to exit */
+
+ /* Scratch space from the Isochronous Pipe.*/
+ unsigned char *scratch;
+ int scratch_read_ptr;
+ int scratch_write_ptr;
+ int scratch_headermarker[USBVISION_NUM_HEADERMARKER];
+ int scratch_headermarker_read_ptr;
+ int scratch_headermarker_write_ptr;
+ enum IsocState isocstate;
+ struct usbvision_v4l2_format_st palette;
+
+ struct v4l2_capability vcap; /* Video capabilities */
+ unsigned int ctl_input; /* selected input */
+ struct usbvision_tvnorm *tvnorm; /* selected tv norm */
+ unsigned char video_endp; /* 0x82 for USBVISION devices based */
+
+ // Decompression stuff:
+ unsigned char *IntraFrameBuffer; /* Buffer for reference frame */
+ int BlockPos; //for test only
+ int requestIntra; // 0 = normal; 1 = intra frame is requested;
+ int lastIsocFrameNum; // check for lost isoc frames
+ int isocPacketSize; // need to calculate usedBandwidth
+ int usedBandwidth; // used bandwidth 0-100%, need to set comprLevel
+ int comprLevel; // How strong (100) or weak (0) is compression
+ int lastComprLevel; // How strong (100) or weak (0) was compression
+ int usb_bandwidth; /* Mbit/s */
+
+ /* Statistics that can be overlayed on the screen */
+ unsigned long isocUrbCount; // How many URBs we received so far
+ unsigned long urb_length; /* Length of last URB */
+ unsigned long isocDataCount; /* How many bytes we received */
+ unsigned long header_count; /* How many frame headers we found */
+ unsigned long scratch_ovf_count; /* How many times we overflowed scratch */
+ unsigned long isocSkipCount; /* How many empty ISO packets received */
+ unsigned long isocErrCount; /* How many bad ISO packets received */
+ unsigned long isocPacketCount; // How many packets we totally got
+ unsigned long timeInIrq; // How long do we need for interrupt
+ int isocMeasureBandwidthCount;
+ int frame_num; // How many video frames we send to user
+ int maxStripLen; // How big is the biggest strip
+ int comprBlockPos;
+ int stripLenErrors; // How many times was BlockPos greater than StripLen
+ int stripMagicErrors;
+ int stripLineNumberErrors;
+ int ComprBlockTypes[4];
+};
+
+
+/* --------------------------------------------------------------- */
+/* defined in usbvision-i2c.c */
+/* i2c-algo-usb declaration */
+/* --------------------------------------------------------------- */
+
+int usbvision_i2c_usb_del_bus(struct i2c_adapter *);
+
+
+/* ----------------------------------------------------------------------- */
+/* usbvision specific I2C functions */
+/* ----------------------------------------------------------------------- */
+int usbvision_init_i2c(struct usb_usbvision *usbvision);
+void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg);
+
+/* defined in usbvision-core.c */
+void usbvision_rvfree(void *mem, unsigned long size);
+int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg);
+int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
+ unsigned char value);
+
+int usbvision_frames_alloc(struct usb_usbvision *usbvision);
+void usbvision_frames_free(struct usb_usbvision *usbvision);
+int usbvision_scratch_alloc(struct usb_usbvision *usbvision);
+void usbvision_scratch_free(struct usb_usbvision *usbvision);
+int usbvision_decompress_alloc(struct usb_usbvision *usbvision);
+void usbvision_decompress_free(struct usb_usbvision *usbvision);
+
+int usbvision_setup(struct usb_usbvision *usbvision,int format);
+int usbvision_init_isoc(struct usb_usbvision *usbvision);
+int usbvision_restart_isoc(struct usb_usbvision *usbvision);
+void usbvision_stop_isoc(struct usb_usbvision *usbvision);
+
+int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel);
+int usbvision_audio_off(struct usb_usbvision *usbvision);
+
+int usbvision_begin_streaming(struct usb_usbvision *usbvision);
+void usbvision_empty_framequeues(struct usb_usbvision *dev);
+int usbvision_stream_interrupt(struct usb_usbvision *dev);
+
+int usbvision_muxsel(struct usb_usbvision *usbvision, int channel);
+int usbvision_set_input(struct usb_usbvision *usbvision);
+int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height);
+
+void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision);
+void usbvision_set_powerOffTimer(struct usb_usbvision *usbvision);
+void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision);
+int usbvision_power_off(struct usb_usbvision *usbvision);
+int usbvision_power_on(struct usb_usbvision *usbvision);
+
+#endif /* __LINUX_USBVISION_H */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 1d899e2db39..8a13e595304 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -350,6 +350,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
struct video_buffer *buffer = arg;
memset(buffer, 0, sizeof(*buffer));
+ memset(&fbuf2, 0, sizeof(fbuf2));
err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
if (err < 0) {
@@ -616,6 +617,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
case VIDIOCSPICT: /* set tone controls & partial capture format */
{
struct video_picture *pict = arg;
+ memset(&fbuf2, 0, sizeof(fbuf2));
set_v4l_control(inode, file,
V4L2_CID_BRIGHTNESS, pict->brightness, drv);
@@ -708,12 +710,22 @@ v4l_compat_translate_ioctl(struct inode *inode,
}
case VIDIOCSTUNER: /* select a tuner input */
{
- err = 0;
+ struct video_tuner *tun = arg;
+ struct v4l2_tuner t;
+ memset(&t,0,sizeof(t));
+
+ t.index=tun->tuner;
+
+ err = drv(inode, file, VIDIOC_S_INPUT, &t);
+ if (err < 0)
+ dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n",err);
+
break;
}
case VIDIOCGFREQ: /* get frequency */
{
unsigned long *freq = arg;
+ memset(&freq2,0,sizeof(freq2));
freq2.tuner = 0;
err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
@@ -726,8 +738,8 @@ v4l_compat_translate_ioctl(struct inode *inode,
case VIDIOCSFREQ: /* set frequency */
{
unsigned long *freq = arg;
+ memset(&freq2,0,sizeof(freq2));
- freq2.tuner = 0;
drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
freq2.frequency = *freq;
err = drv(inode, file, VIDIOC_S_FREQUENCY, &freq2);
@@ -738,6 +750,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
case VIDIOCGAUDIO: /* get audio properties/controls */
{
struct video_audio *aud = arg;
+ memset(&aud2,0,sizeof(aud2));
err = drv(inode, file, VIDIOC_G_AUDIO, &aud2);
if (err < 0) {
@@ -898,6 +911,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
{
int *i = arg;
+ memset(&buf2,0,sizeof(buf2));
buf2.index = *i;
buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
err = drv(inode, file, VIDIOC_QUERYBUF, &buf2);
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 78d28b03ec9..b87d571e046 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -87,6 +87,85 @@ MODULE_LICENSE("GPL");
*/
+char *v4l2_norm_to_name(v4l2_std_id id)
+{
+ char *name;
+ u32 myid = id;
+
+ /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle
+ 64 bit comparations. So, on that architecture, with some gcc variants,
+ compilation fails. Currently, the max value is 30bit wide.
+ */
+ BUG_ON(myid != id);
+
+ switch (myid) {
+ case V4L2_STD_PAL:
+ name="PAL"; break;
+ case V4L2_STD_PAL_BG:
+ name="PAL-BG"; break;
+ case V4L2_STD_PAL_DK:
+ name="PAL-DK"; break;
+ case V4L2_STD_PAL_B:
+ name="PAL-B"; break;
+ case V4L2_STD_PAL_B1:
+ name="PAL-B1"; break;
+ case V4L2_STD_PAL_G:
+ name="PAL-G"; break;
+ case V4L2_STD_PAL_H:
+ name="PAL-H"; break;
+ case V4L2_STD_PAL_I:
+ name="PAL-I"; break;
+ case V4L2_STD_PAL_D:
+ name="PAL-D"; break;
+ case V4L2_STD_PAL_D1:
+ name="PAL-D1"; break;
+ case V4L2_STD_PAL_K:
+ name="PAL-K"; break;
+ case V4L2_STD_PAL_M:
+ name="PAL-M"; break;
+ case V4L2_STD_PAL_N:
+ name="PAL-N"; break;
+ case V4L2_STD_PAL_Nc:
+ name="PAL-Nc"; break;
+ case V4L2_STD_PAL_60:
+ name="PAL-60"; break;
+ case V4L2_STD_NTSC:
+ name="NTSC"; break;
+ case V4L2_STD_NTSC_M:
+ name="NTSC-M"; break;
+ case V4L2_STD_NTSC_M_JP:
+ name="NTSC-M-JP"; break;
+ case V4L2_STD_NTSC_443:
+ name="NTSC-443"; break;
+ case V4L2_STD_NTSC_M_KR:
+ name="NTSC-M-KR"; break;
+ case V4L2_STD_SECAM:
+ name="SECAM"; break;
+ case V4L2_STD_SECAM_DK:
+ name="SECAM-DK"; break;
+ case V4L2_STD_SECAM_B:
+ name="SECAM-B"; break;
+ case V4L2_STD_SECAM_D:
+ name="SECAM-D"; break;
+ case V4L2_STD_SECAM_G:
+ name="SECAM-G"; break;
+ case V4L2_STD_SECAM_H:
+ name="SECAM-H"; break;
+ case V4L2_STD_SECAM_K:
+ name="SECAM-K"; break;
+ case V4L2_STD_SECAM_K1:
+ name="SECAM-K1"; break;
+ case V4L2_STD_SECAM_L:
+ name="SECAM-L"; break;
+ case V4L2_STD_SECAM_LC:
+ name="SECAM-LC"; break;
+ default:
+ name="Unknown"; break;
+ }
+
+ return name;
+}
+
/* Fill in the fields of a v4l2_standard structure according to the
'id' and 'transmission' parameters. Returns negative on error. */
int v4l2_video_std_construct(struct v4l2_standard *vs,
@@ -184,11 +263,13 @@ char *v4l2_field_names[] = {
};
char *v4l2_type_names[] = {
- [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
- [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
- [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
- [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
- [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
+ [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
+ [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
+ [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
+ [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
+ [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
+ [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
+ [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "slicec-vbi-out",
};
static char *v4l2_memory_names[] = {
@@ -1451,6 +1532,7 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
/* ----------------------------------------------------------------- */
+EXPORT_SYMBOL(v4l2_norm_to_name);
EXPORT_SYMBOL(v4l2_video_std_construct);
EXPORT_SYMBOL(v4l2_prio_init);
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
index f429f49901b..6504a586684 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -700,6 +700,7 @@ videobuf_qbuf(struct videobuf_queue *q,
goto done;
}
if (buf->state == STATE_QUEUED ||
+ buf->state == STATE_PREPARED ||
buf->state == STATE_ACTIVE) {
dprintk(1,"qbuf: buffer is already queued or active.\n");
goto done;
@@ -1229,7 +1230,7 @@ videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
vaddr,vma->vm_start,vma->vm_end);
if (vaddr > vma->vm_end)
return NOPAGE_SIGBUS;
- page = alloc_page(GFP_USER);
+ page = alloc_page(GFP_USER | __GFP_DMA32);
if (!page)
return NOPAGE_OOM;
clear_user_page(page_address(page), vaddr, page);
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c
index 2ae3fb25063..290e6413565 100644
--- a/drivers/media/video/videocodec.c
+++ b/drivers/media/video/videocodec.c
@@ -346,7 +346,7 @@ videocodec_build_table (void)
size);
kfree(videocodec_buf);
- videocodec_buf = (char *) kmalloc(size, GFP_KERNEL);
+ videocodec_buf = kmalloc(size, GFP_KERNEL);
i = 0;
i += scnprintf(videocodec_buf + i, size - 1,
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index d424a4129d6..6a0e8ca7294 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -105,7 +105,7 @@ static DEFINE_MUTEX(videodev_lock);
struct video_device* video_devdata(struct file *file)
{
- return video_device[iminor(file->f_dentry->d_inode)];
+ return video_device[iminor(file->f_path.dentry->d_inode)];
}
/*
@@ -342,7 +342,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
"bytesused=%d, flags=0x%08d, "
- "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
+ "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n",
(p->timestamp.tv_sec/3600),
(int)(p->timestamp.tv_sec/60)%60,
(int)(p->timestamp.tv_sec%60),
@@ -352,7 +352,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
p->bytesused,p->flags,
p->field,p->sequence,
prt_names(p->memory,v4l2_memory_names),
- p->m.userptr);
+ p->m.userptr, p->length);
dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
"flags=0x%08d, frames=%d, userbits=0x%08x\n",
tc->hours,tc->minutes,tc->seconds,
@@ -369,9 +369,13 @@ static inline void dbgrect(struct video_device *vfd, char *s,
static inline void v4l_print_pix_fmt (struct video_device *vfd,
struct v4l2_pix_format *fmt)
{
- dbgarg2 ("width=%d, height=%d, format=0x%08x, field=%s, "
+ dbgarg2 ("width=%d, height=%d, format=%c%c%c%c, field=%s, "
"bytesperline=%d sizeimage=%d, colorspace=%d\n",
- fmt->width,fmt->height,fmt->pixelformat,
+ fmt->width,fmt->height,
+ (fmt->pixelformat & 0xff),
+ (fmt->pixelformat >> 8) & 0xff,
+ (fmt->pixelformat >> 16) & 0xff,
+ (fmt->pixelformat >> 24) & 0xff,
prt_names(fmt->field,v4l2_field_names_FIXME),
fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
};
@@ -428,6 +432,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
v4l_print_ioctl(vfd->name, cmd);
}
+ if (_IOC_TYPE(cmd)=='v')
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ __video_do_ioctl);
+
switch(cmd) {
/* --- capabilities ------------------------------------------ */
case VIDIOC_QUERYCAP:
@@ -526,12 +534,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
}
if (!ret)
dbgarg (cmd, "index=%d, type=%d, flags=%d, "
- "description=%s,"
- " pixelformat=0x%8x\n",
+ "pixelformat=%c%c%c%c, description='%s'\n",
f->index, f->type, f->flags,
- f->description,
- f->pixelformat);
-
+ (f->pixelformat & 0xff),
+ (f->pixelformat >> 8) & 0xff,
+ (f->pixelformat >> 16) & 0xff,
+ (f->pixelformat >> 24) & 0xff,
+ f->description);
break;
}
case VIDIOC_G_FMT:
@@ -829,20 +838,85 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_ENUMSTD:
{
struct v4l2_standard *p = arg;
- unsigned int index = p->index;
+ v4l2_std_id id = vfd->tvnorms,curr_id=0;
+ unsigned int index = p->index,i;
- if (!vfd->tvnormsize) {
- printk (KERN_WARNING "%s: no TV norms defined!\n",
- vfd->name);
+ if (index<0) {
+ ret=-EINVAL;
break;
}
- if (index<0 || index >= vfd->tvnormsize) {
- ret=-EINVAL;
- break;
+ /* Return norm array on a canonical way */
+ for (i=0;i<= index && id; i++) {
+ if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
+ curr_id = V4L2_STD_PAL;
+ } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
+ curr_id = V4L2_STD_PAL_BG;
+ } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
+ curr_id = V4L2_STD_PAL_DK;
+ } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
+ curr_id = V4L2_STD_PAL_B;
+ } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
+ curr_id = V4L2_STD_PAL_B1;
+ } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
+ curr_id = V4L2_STD_PAL_G;
+ } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
+ curr_id = V4L2_STD_PAL_H;
+ } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
+ curr_id = V4L2_STD_PAL_I;
+ } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
+ curr_id = V4L2_STD_PAL_D;
+ } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
+ curr_id = V4L2_STD_PAL_D1;
+ } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
+ curr_id = V4L2_STD_PAL_K;
+ } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
+ curr_id = V4L2_STD_PAL_M;
+ } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
+ curr_id = V4L2_STD_PAL_N;
+ } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
+ curr_id = V4L2_STD_PAL_Nc;
+ } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
+ curr_id = V4L2_STD_PAL_60;
+ } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+ curr_id = V4L2_STD_NTSC;
+ } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
+ curr_id = V4L2_STD_NTSC_M;
+ } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
+ curr_id = V4L2_STD_NTSC_M_JP;
+ } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
+ curr_id = V4L2_STD_NTSC_443;
+ } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
+ curr_id = V4L2_STD_NTSC_M_KR;
+ } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
+ curr_id = V4L2_STD_SECAM;
+ } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
+ curr_id = V4L2_STD_SECAM_DK;
+ } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
+ curr_id = V4L2_STD_SECAM_B;
+ } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
+ curr_id = V4L2_STD_SECAM_D;
+ } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
+ curr_id = V4L2_STD_SECAM_G;
+ } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
+ curr_id = V4L2_STD_SECAM_H;
+ } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
+ curr_id = V4L2_STD_SECAM_K;
+ } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
+ curr_id = V4L2_STD_SECAM_K1;
+ } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
+ curr_id = V4L2_STD_SECAM_L;
+ } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
+ curr_id = V4L2_STD_SECAM_LC;
+ } else {
+ break;
+ }
+ id &= ~curr_id;
}
- v4l2_video_std_construct(p, vfd->tvnorms[p->index].id,
- vfd->tvnorms[p->index].name);
+ if (i<=index)
+ return -EINVAL;
+
+ v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id));
p->index = index;
dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
@@ -868,39 +942,23 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
}
case VIDIOC_S_STD:
{
- v4l2_std_id *id = arg;
- unsigned int i;
-
- if (!vfd->tvnormsize) {
- printk (KERN_WARNING "%s: no TV norms defined!\n",
- vfd->name);
- break;
- }
+ v4l2_std_id *id = arg,norm;
dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
- /* First search for exact match */
- for (i = 0; i < vfd->tvnormsize; i++)
- if (*id == vfd->tvnorms[i].id)
- break;
- /* Then for a generic video std that contains desired std */
- if (i == vfd->tvnormsize)
- for (i = 0; i < vfd->tvnormsize; i++)
- if (*id & vfd->tvnorms[i].id)
- break;
- if (i == vfd->tvnormsize) {
+ norm = (*id) & vfd->tvnorms;
+ if ( vfd->tvnorms && !norm) /* Check if std is supported */
break;
- }
/* Calls the specific handler */
if (vfd->vidioc_s_std)
- ret=vfd->vidioc_s_std(file, fh, i);
+ ret=vfd->vidioc_s_std(file, fh, &norm);
else
ret=-EINVAL;
/* Updates standard information */
- if (!ret)
- vfd->current_norm=*id;
+ if (ret>=0)
+ vfd->current_norm=norm;
break;
}
@@ -1088,9 +1146,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_AUDIO:
{
struct v4l2_audio *p=arg;
+ __u32 index=p->index;
if (!vfd->vidioc_g_audio)
break;
+
+ memset(p,0,sizeof(*p));
+ p->index=index;
dbgarg(cmd, "Get for index=%d\n", p->index);
ret=vfd->vidioc_g_audio(file, fh, p);
if (!ret)
@@ -1288,25 +1350,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
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);
+ v4l2_norm_to_name(vfd->current_norm));
memset(p,0,sizeof(*p));
@@ -1329,8 +1378,14 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *p=arg;
+ __u32 index=p->index;
+
if (!vfd->vidioc_g_tuner)
break;
+
+ memset(p,0,sizeof(*p));
+ p->index=index;
+
ret=vfd->vidioc_g_tuner(file, fh, p);
if (!ret)
dbgarg (cmd, "index=%d, name=%s, type=%d, "
@@ -1363,6 +1418,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_frequency *p=arg;
if (!vfd->vidioc_g_frequency)
break;
+
+ memset(p,0,sizeof(*p));
+
ret=vfd->vidioc_g_frequency(file, fh, p);
if (!ret)
dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
@@ -1396,12 +1454,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
ret=vfd->vidioc_log_status(file, fh);
break;
}
-
- /* --- Others --------------------------------------------- */
-
- default:
- ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,__video_do_ioctl);
- }
+ } /* switch */
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
if (ret<0) {
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 6b6dff4d236..a373c142e74 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -782,7 +782,7 @@ static int vino_i2c_add_bus(void)
static int vino_i2c_del_bus(void)
{
- return i2c_sgi_del_bus(&vino_i2c_adapter);
+ return i2c_del_adapter(&vino_i2c_adapter);
}
static int i2c_camera_command(unsigned int cmd, void *arg)
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 9986de5cb3d..d4cf5566673 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -270,10 +270,15 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
char *p,*s,*basep;
struct page *pg;
u8 chr,r,g,b,color;
+ unsigned long flags;
+ spinlock_t spinlock;
+
+ spin_lock_init(&spinlock);
/* Get first addr pointed to pixel position */
oldpg=get_addr_pos(pos,pages,to_addr);
pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
+ spin_lock_irqsave(&spinlock,flags);
basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
/* We will just duplicate the second pixel at the packet */
@@ -376,6 +381,8 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
end:
kunmap_atomic(basep, KM_BOUNCE_READ);
+ spin_unlock_irqrestore(&spinlock,flags);
+
}
static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
{
@@ -535,9 +542,9 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q)
dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
- if (dma_q->kthread == NULL) {
+ if (IS_ERR(dma_q->kthread)) {
printk(KERN_ERR "vivi: kernel_thread() failed\n");
- return -EINVAL;
+ return PTR_ERR(dma_q->kthread);
}
dprintk(1,"returning from %s\n",__FUNCTION__);
return 0;
@@ -1044,16 +1051,8 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
return (0);
}
-static struct v4l2_tvnorm tvnorms[] = {
- {
- .name = "NTSC-M",
- .id = V4L2_STD_NTSC_M,
- }
-};
-
-static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id a)
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
{
-
return 0;
}
@@ -1333,8 +1332,8 @@ static struct video_device vivi = {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
.vidiocgmbuf = vidiocgmbuf,
#endif
- .tvnorms = tvnorms,
- .tvnormsize = ARRAY_SIZE(tvnorms),
+ .tvnorms = V4L2_STD_NTSC_M,
+ .current_norm = V4L2_STD_NTSC_M,
};
/* -----------------------------------------------------------------
Initialization and module stuff
@@ -1361,8 +1360,6 @@ 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;
@@ -1373,7 +1370,9 @@ static void __exit vivi_exit(void)
struct vivi_dev *h;
struct list_head *list;
- list_for_each(list,&vivi_devlist) {
+ while (!list_empty(&vivi_devlist)) {
+ list = vivi_devlist.next;
+ list_del(list);
h = list_entry(list, struct vivi_dev, vivi_devlist);
kfree (h);
}
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 4bdc886abc4..8d14f308f17 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -789,7 +789,7 @@ static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCSPICT:
{
struct video_picture *vpic = arg;
- if (vpic->depth != 16 || vpic->palette != VIDEO_PALETTE_YUV422)
+ if (vpic->depth != 16 || (vpic->palette != VIDEO_PALETTE_YUV422 && vpic->palette != VIDEO_PALETTE_YUYV))
return -EINVAL;
cam->brightness = vpic->brightness >> 8;
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index ddce2fb8342..9f403af7b04 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -1827,8 +1827,8 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
int err = 0;
/* Work around to avoid FP arithmetics */
- #define __SC(x) ((x) << 10)
- #define __UNSC(x) ((x) >> 10)
+ #define SC(x) ((x) << 10)
+ #define UNSC(x) ((x) >> 10)
/* Make sure we are using a supported resolution */
if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
@@ -1836,15 +1836,15 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
goto error;
/* Scaling factors */
- fw = __SC(win.width) / cam->maxwidth;
- fh = __SC(win.height) / cam->maxheight;
+ fw = SC(win.width) / cam->maxwidth;
+ fh = SC(win.height) / cam->maxheight;
/* Set up the width and height values used by the chip */
if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) {
cam->vpp_flag |= VPP_UPSCALE;
/* Calculate largest w,h mantaining the same w/h ratio */
- w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
- h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
+ w = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh;
+ h = (fw >= fh) ? SC(win.height)/fw : cam->maxheight;
if (w < cam->minwidth) /* just in case */
w = cam->minwidth;
if (h < cam->minheight) /* just in case */
@@ -1861,8 +1861,8 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
/* Calculate cropped area manteining the right w/h ratio */
if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) {
- cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
- ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
+ cw = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh;
+ ch = (fw >= fh) ? SC(win.height)/fw : cam->maxheight;
} else {
cw = w;
ch = h;
@@ -1901,8 +1901,8 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
/* We have to scale win.x and win.y offsets */
if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
|| (cam->vpp_flag & VPP_UPSCALE) ) {
- ax = __SC(win.x)/fw;
- ay = __SC(win.y)/fh;
+ ax = SC(win.x)/fw;
+ ay = SC(win.y)/fh;
} else {
ax = win.x;
ay = win.y;
@@ -1917,8 +1917,8 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
/* Adjust win.x, win.y */
if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
|| (cam->vpp_flag & VPP_UPSCALE) ) {
- win.x = __UNSC(ax*fw);
- win.y = __UNSC(ay*fh);
+ win.x = UNSC(ax*fw);
+ win.y = UNSC(ay*fh);
} else {
win.x = ax;
win.y = ay;
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 4363a915b1f..3daf049a288 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -75,7 +75,6 @@ static const struct usb_device_id zc0301_id_table[] = { \
{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \
{ ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \
{ ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 653822ce391..4d1eb2fba34 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -849,7 +849,7 @@ zoran_register_i2c (struct zoran *zr)
static void
zoran_unregister_i2c (struct zoran *zr)
{
- i2c_bit_del_bus((&zr->i2c_adapter));
+ i2c_del_adapter(&zr->i2c_adapter);
}
/* Check a zoran_params struct for correctness, insert default params */
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index 168e431d7c7..b0752767ee4 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -429,7 +429,7 @@ zr36057_set_vfe (struct zoran *zr,
reg |= (HorDcm << ZR36057_VFESPFR_HorDcm);
reg |= (VerDcm << ZR36057_VFESPFR_VerDcm);
reg |= (DispMode << ZR36057_VFESPFR_DispMode);
- if (format->palette != VIDEO_PALETTE_YUV422)
+ if (format->palette != VIDEO_PALETTE_YUV422 && format->palette != VIDEO_PALETTE_YUYV)
reg |= ZR36057_VFESPFR_LittleEndian;
/* RJ: I don't know, why the following has to be the opposite
* of the corresponding ZR36060 setting, but only this way
@@ -441,6 +441,7 @@ zr36057_set_vfe (struct zoran *zr,
reg |= ZR36057_VFESPFR_TopField;
switch (format->palette) {
+ case VIDEO_PALETTE_YUYV:
case VIDEO_PALETTE_YUV422:
reg |= ZR36057_VFESPFR_YUV422;
break;
diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
index c7f6f648836..c374c76b375 100644
--- a/drivers/media/video/zoran_procfs.c
+++ b/drivers/media/video/zoran_procfs.c
@@ -144,7 +144,7 @@ static int zoran_open(struct inode *inode, struct file *file)
static ssize_t zoran_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
- struct zoran *zr = PDE(file->f_dentry->d_inode)->data;
+ struct zoran *zr = PDE(file->f_path.dentry->d_inode)->data;
char *string, *sp;
char *line, *ldelim, *varname, *svar, *tdelim;
@@ -165,7 +165,7 @@ static ssize_t zoran_write(struct file *file, const char __user *buffer,
}
string[count] = 0;
dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n",
- ZR_DEVNAME(zr), file->f_dentry->d_name.name, count, zr);
+ ZR_DEVNAME(zr), file->f_path.dentry->d_name.name, count, zr);
ldelim = " \t\n";
tdelim = "=";
line = strpbrk(sp, ldelim);
diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
deleted file mode 100644
index 0cbf564388a..00000000000
--- a/drivers/media/video/zr36120.c
+++ /dev/null
@@ -1,2079 +0,0 @@
-/*
- zr36120.c - Zoran 36120/36125 based framegrabbers
-
- Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.nl>
-
- This program is free software; you can redistribute it and/or modify
- 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/init.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/signal.h>
-#include <linux/wait.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <linux/video_decoder.h>
-
-#include <asm/uaccess.h>
-
-#include "tuner.h"
-#include "zr36120.h"
-#include "zr36120_mem.h"
-
-/* mark an required function argument unused - lintism */
-#define UNUSED(x) (void)(x)
-
-/* sensible default */
-#ifndef CARDTYPE
-#define CARDTYPE 0
-#endif
-
-/* Anybody who uses more than four? */
-#define ZORAN_MAX 4
-
-static unsigned int triton1=0; /* triton1 chipset? */
-static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE };
-static int video_nr = -1;
-static int vbi_nr = -1;
-
-static struct pci_device_id zr36120_pci_tbl[] = {
- { PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, zr36120_pci_tbl);
-
-MODULE_AUTHOR("Pauline Middelink <middelin@polyware.nl>");
-MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber");
-MODULE_LICENSE("GPL");
-
-module_param(triton1, uint, 0);
-module_param_array(cardtype, uint, NULL, 0);
-module_param(video_nr, int, 0);
-module_param(vbi_nr, int, 0);
-
-static int zoran_cards;
-static struct zoran zorans[ZORAN_MAX];
-
-/*
- * the meaning of each element can be found in zr36120.h
- * Determining the value of gpdir/gpval can be tricky. The
- * best way is to run the card under the original software
- * and read the values from the general purpose registers
- * 0x28 and 0x2C. How you do that is left as an exercise
- * to the impatient reader :)
- */
-#define T 1 /* to separate the bools from the ints */
-#define F 0
-static struct tvcard tvcards[] = {
- /* reported working by <middelin@polyware.nl> */
-/*0*/ { "Trust Victor II",
- 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } },
- /* reported working by <Michael.Paxton@aihw.gov.au> */
-/*1*/ { "Aitech WaveWatcher TV-PCI",
- 3, 0, T, F, T, T, 0x7F, 0x80, { 1, TUNER(3), SVHS(6) }, { 0 } },
- /* reported working by ? */
-/*2*/ { "Genius Video Wonder PCI Video Capture Card",
- 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } },
- /* reported working by <Pascal.Gabriel@wanadoo.fr> */
-/*3*/ { "Guillemot Maxi-TV PCI",
- 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } },
- /* reported working by "Craig Whitmore <lennon@igrin.co.nz> */
-/*4*/ { "Quadrant Buster",
- 3, 3, T, F, T, T, 0x7F, 0x80, { SVHS(1), TUNER(2), 3 }, { 1, 2, 3 } },
- /* a debug entry which has all inputs mapped */
-/*5*/ { "ZR36120 based framegrabber (all inputs enabled)",
- 6, 0, T, T, T, T, 0x7F, 0x80, { 1, 2, 3, 4, 5, 6 }, { 0 } }
-};
-#undef T
-#undef F
-#define NRTVCARDS (sizeof(tvcards)/sizeof(tvcards[0]))
-
-#ifdef __sparc__
-#define ENDIANESS 0
-#else
-#define ENDIANESS ZORAN_VFEC_LE
-#endif
-
-static struct { const char name[8]; uint mode; uint bpp; } palette2fmt[] = {
-/* n/a */ { "n/a", 0, 0 },
-/* GREY */ { "GRAY", 0, 0 },
-/* HI240 */ { "HI240", 0, 0 },
-/* RGB565 */ { "RGB565", ZORAN_VFEC_RGB_RGB565|ENDIANESS, 2 },
-/* RGB24 */ { "RGB24", ZORAN_VFEC_RGB_RGB888|ENDIANESS|ZORAN_VFEC_PACK24, 3 },
-/* RGB32 */ { "RGB32", ZORAN_VFEC_RGB_RGB888|ENDIANESS, 4 },
-/* RGB555 */ { "RGB555", ZORAN_VFEC_RGB_RGB555|ENDIANESS, 2 },
-/* YUV422 */ { "YUV422", ZORAN_VFEC_RGB_YUV422|ENDIANESS, 2 },
-/* YUYV */ { "YUYV", 0, 0 },
-/* UYVY */ { "UYVY", 0, 0 },
-/* YUV420 */ { "YUV420", 0, 0 },
-/* YUV411 */ { "YUV411", 0, 0 },
-/* RAW */ { "RAW", 0, 0 },
-/* YUV422P */ { "YUV422P", 0, 0 },
-/* YUV411P */ { "YUV411P", 0, 0 }};
-#define NRPALETTES (sizeof(palette2fmt)/sizeof(palette2fmt[0]))
-#undef ENDIANESS
-
-/* ----------------------------------------------------------------------- */
-/* ZORAN chipset detector */
-/* shamelessly stolen from bttv.c */
-/* Reason for beeing here: we need to detect if we are running on a */
-/* Triton based chipset, and if so, enable a certain bit */
-/* ----------------------------------------------------------------------- */
-static
-void __init handle_chipset(void)
-{
- /* Just in case some nut set this to something dangerous */
- if (triton1)
- triton1 = ZORAN_VDC_TRICOM;
-
- if (pci_pci_problems & PCIPCI_TRITON) {
- printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n");
- triton1 = ZORAN_VDC_TRICOM;
- }
-}
-
-/* ----------------------------------------------------------------------- */
-/* ZORAN functions */
-/* ----------------------------------------------------------------------- */
-
-static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i);
-
-#if 0 /* unused */
-static
-void zoran_dump(struct zoran *ztv)
-{
- char str[256];
- char *p=str; /* shut up, gcc! */
- int i;
-
- for (i=0; i<0x60; i+=4) {
- if ((i % 16) == 0) {
- if (i) printk("%s\n",str);
- p = str;
- p+= sprintf(str, KERN_DEBUG " %04x: ",i);
- }
- p += sprintf(p, "%08x ",zrread(i));
- }
-}
-#endif /* unused */
-
-static
-void reap_states(struct zoran* ztv)
-{
- /* count frames */
- ztv->fieldnr++;
-
- /*
- * Are we busy at all?
- * This depends on if there is a workqueue AND the
- * videotransfer is enabled on the chip...
- */
- if (ztv->workqueue && (zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN))
- {
- struct vidinfo* newitem;
-
- /* did we get a complete frame? */
- if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB)
- return;
-
-DEBUG(printk(CARD_DEBUG "completed %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue));
-
- /* we are done with this buffer, tell everyone */
- ztv->workqueue->status = FBUFFER_DONE;
- ztv->workqueue->fieldnr = ztv->fieldnr;
- /* not good, here for BTTV_FIELDNR reasons */
- ztv->lastfieldnr = ztv->fieldnr;
-
- switch (ztv->workqueue->kindof) {
- case FBUFFER_GRAB:
- wake_up_interruptible(&ztv->grabq);
- break;
- case FBUFFER_VBI:
- wake_up_interruptible(&ztv->vbiq);
- break;
- default:
- printk(CARD_INFO "somebody killed the workqueue (kindof=%d)!\n",CARD,ztv->workqueue->kindof);
- }
-
- /* item completed, skip to next item in queue */
- write_lock(&ztv->lock);
- newitem = ztv->workqueue->next;
- ztv->workqueue->next = 0; /* mark completed */
- ztv->workqueue = newitem;
- write_unlock(&ztv->lock);
- }
-
- /*
- * ok, so it seems we have nothing in progress right now.
- * Lets see if we can find some work.
- */
- if (ztv->workqueue)
- {
- struct vidinfo* newitem;
-again:
-
-DEBUG(printk(CARD_DEBUG "starting %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue));
-
- /* loadup the frame settings */
- read_lock(&ztv->lock);
- zoran_set_geo(ztv,ztv->workqueue);
- read_unlock(&ztv->lock);
-
- switch (ztv->workqueue->kindof) {
- case FBUFFER_GRAB:
- case FBUFFER_VBI:
- zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR);
- zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
- zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
-
- /* start single-shot grab */
- zror(ZORAN_VSTR_GRAB, ZORAN_VSTR);
- break;
- default:
- printk(CARD_INFO "what is this doing on the queue? (kindof=%d)\n",CARD,ztv->workqueue->kindof);
- write_lock(&ztv->lock);
- newitem = ztv->workqueue->next;
- ztv->workqueue->next = 0;
- ztv->workqueue = newitem;
- write_unlock(&ztv->lock);
- if (newitem)
- goto again; /* yeah, sure.. */
- }
- /* bye for now */
- return;
- }
-DEBUG(printk(CARD_DEBUG "nothing in queue\n",CARD));
-
- /*
- * What? Even the workqueue is empty? Am i really here
- * for nothing? Did i come all that way to... do nothing?
- */
-
- /* do we need to overlay? */
- if (test_bit(STATE_OVERLAY, &ztv->state))
- {
- /* are we already overlaying? */
- if (!(zrread(ZORAN_OCR) & ZORAN_OCR_OVLEN) ||
- !(zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN))
- {
-DEBUG(printk(CARD_DEBUG "starting overlay\n",CARD));
-
- read_lock(&ztv->lock);
- zoran_set_geo(ztv,&ztv->overinfo);
- read_unlock(&ztv->lock);
-
- zror(ZORAN_OCR_OVLEN, ZORAN_OCR);
- zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
- zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
- }
-
- /*
- * leave overlaying on, but turn interrupts off.
- */
- zrand(~ZORAN_ICR_EN,ZORAN_ICR);
- return;
- }
-
- /* do we have any VBI idle time processing? */
- if (test_bit(STATE_VBI, &ztv->state))
- {
- struct vidinfo* item;
- struct vidinfo* lastitem;
-
- /* protect the workqueue */
- write_lock(&ztv->lock);
- lastitem = ztv->workqueue;
- if (lastitem)
- while (lastitem->next) lastitem = lastitem->next;
- for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
- if (item->next == 0 && item->status == FBUFFER_FREE)
- {
-DEBUG(printk(CARD_DEBUG "%p added to queue\n",CARD,item));
- item->status = FBUFFER_BUSY;
- if (!lastitem)
- ztv->workqueue = item;
- else
- lastitem->next = item;
- lastitem = item;
- }
- write_unlock(&ztv->lock);
- if (ztv->workqueue)
- goto again; /* hey, _i_ graduated :) */
- }
-
- /*
- * Then we must be realy IDLE
- */
-DEBUG(printk(CARD_DEBUG "turning off\n",CARD));
- /* nothing further to do, disable DMA and further IRQs */
- zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
- zrand(~ZORAN_ICR_EN,ZORAN_ICR);
-}
-
-static
-void zoran_irq(int irq, void *dev_id)
-{
- u32 stat,estat;
- int count = 0;
- struct zoran *ztv = dev_id;
-
- UNUSED(irq);
- for (;;) {
- /* get/clear interrupt status bits */
- stat=zrread(ZORAN_ISR);
- estat=stat & zrread(ZORAN_ICR);
- if (!estat)
- return;
- zrwrite(estat,ZORAN_ISR);
- IDEBUG(printk(CARD_DEBUG "estat %08x\n",CARD,estat));
- IDEBUG(printk(CARD_DEBUG " stat %08x\n",CARD,stat));
-
- if (estat & ZORAN_ISR_CODE)
- {
- IDEBUG(printk(CARD_DEBUG "CodReplIRQ\n",CARD));
- }
- if (estat & ZORAN_ISR_GIRQ0)
- {
- IDEBUG(printk(CARD_DEBUG "GIRQ0\n",CARD));
- if (!ztv->card->usegirq1)
- reap_states(ztv);
- }
- if (estat & ZORAN_ISR_GIRQ1)
- {
- IDEBUG(printk(CARD_DEBUG "GIRQ1\n",CARD));
- if (ztv->card->usegirq1)
- reap_states(ztv);
- }
-
- count++;
- if (count > 10)
- printk(CARD_ERR "irq loop %d (%x)\n",CARD,count,estat);
- if (count > 20)
- {
- zrwrite(0, ZORAN_ICR);
- printk(CARD_ERR "IRQ lockup, cleared int mask\n",CARD);
- }
- }
-}
-
-static
-int zoran_muxsel(struct zoran* ztv, int channel, int norm)
-{
- int rv;
-
- /* set the new video norm */
- rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
- if (rv)
- return rv;
- ztv->norm = norm;
-
- /* map the given channel to the cards decoder's channel */
- channel = ztv->card->video_mux[channel] & CHANNEL_MASK;
-
- /* set the new channel */
- rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &channel);
- return rv;
-}
-
-/* Tell the interrupt handler what to to. */
-static
-void zoran_cap(struct zoran* ztv, int on)
-{
-DEBUG(printk(CARD_DEBUG "zoran_cap(%d) state=%x\n",CARD,on,ztv->state));
-
- if (on) {
- ztv->running = 1;
-
- /*
- * turn interrupts (back) on. The DMA will be enabled
- * inside the irq handler when it detects a restart.
- */
- zror(ZORAN_ICR_EN,ZORAN_ICR);
- }
- else {
- /*
- * turn both interrupts and DMA off
- */
- zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
- zrand(~ZORAN_ICR_EN,ZORAN_ICR);
-
- ztv->running = 0;
- }
-}
-
-static ulong dmask[] = {
- 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8,
- 0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80,
- 0xFFFFFF00, 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800,
- 0xFFFFF000, 0xFFFFE000, 0xFFFFC000, 0xFFFF8000,
- 0xFFFF0000, 0xFFFE0000, 0xFFFC0000, 0xFFF80000,
- 0xFFF00000, 0xFFE00000, 0xFFC00000, 0xFF800000,
- 0xFF000000, 0xFE000000, 0xFC000000, 0xF8000000,
- 0xF0000000, 0xE0000000, 0xC0000000, 0x80000000
-};
-
-static
-void zoran_built_overlay(struct zoran* ztv, int count, struct video_clip *vcp)
-{
- ulong* mtop;
- int ystep = (ztv->vidXshift + ztv->vidWidth+31)/32; /* next DWORD */
- int i;
-
-DEBUG(printk(KERN_DEBUG " overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count));
-
- for (i=0; i<count; i++) {
- struct video_clip *vp = vcp+i;
- UNUSED(vp);
-DEBUG(printk(KERN_DEBUG " %d: clip(%d,%d,%d,%d)\n", i,vp->x,vp->y,vp->width,vp->height));
- }
-
- /*
- * activate the visible portion of the screen
- * Note we take some shortcuts here, because we
- * know the width can never be < 32. (I.e. a DWORD)
- * We also assume the overlay starts somewhere in
- * the FIRST dword.
- */
- {
- int start = ztv->vidXshift;
- ulong firstd = dmask[start];
- ulong lastd = ~dmask[(start + ztv->overinfo.w) & 31];
- mtop = ztv->overinfo.overlay;
- for (i=0; i<ztv->overinfo.h; i++) {
- int w = ztv->vidWidth;
- ulong* line = mtop;
- if (start & 31) {
- *line++ = firstd;
- w -= 32-(start&31);
- }
- memset(line, ~0, w/8);
- if (w & 31)
- line[w/32] = lastd;
- mtop += ystep;
- }
- }
-
- /* process clipping regions */
- for (i=0; i<count; i++) {
- int h;
- if (vcp->x < 0 || (uint)vcp->x > ztv->overinfo.w ||
- vcp->y < 0 || vcp->y > ztv->overinfo.h ||
- vcp->width < 0 || (uint)(vcp->x+vcp->width) > ztv->overinfo.w ||
- vcp->height < 0 || (vcp->y+vcp->height) > ztv->overinfo.h)
- {
- DEBUG(printk(CARD_DEBUG "invalid clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h));
- if (vcp->x < 0) vcp->x = 0;
- if ((uint)vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w;
- if (vcp->y < 0) vcp->y = 0;
- if (vcp->y > ztv->overinfo.h) vcp->y = ztv->overinfo.h;
- if (vcp->width < 0) vcp->width = 0;
- if ((uint)(vcp->x+vcp->width) > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x;
- if (vcp->height < 0) vcp->height = 0;
- if (vcp->y+vcp->height > ztv->overinfo.h) vcp->height = ztv->overinfo.h - vcp->y;
-// continue;
- }
-
- mtop = &ztv->overinfo.overlay[vcp->y*ystep];
- for (h=0; h<=vcp->height; h++) {
- int w;
- int x = ztv->vidXshift + vcp->x;
- for (w=0; w<=vcp->width; w++) {
- clear_bit(x&31, &mtop[x/32]);
- x++;
- }
- mtop += ystep;
- }
- ++vcp;
- }
-
- mtop = ztv->overinfo.overlay;
- zrwrite(virt_to_bus(mtop), ZORAN_MTOP);
- zrwrite(virt_to_bus(mtop+ystep), ZORAN_MBOT);
- zraor((ztv->vidInterlace*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR);
-}
-
-struct tvnorm
-{
- u16 Wt, Wa, Ht, Ha, HStart, VStart;
-};
-
-static struct tvnorm tvnorms[] = {
- /* PAL-BDGHI */
-/* { 864, 720, 625, 576, 131, 21 },*/
-/*00*/ { 864, 768, 625, 576, 81, 17 },
- /* NTSC */
-/*01*/ { 858, 720, 525, 480, 121, 10 },
- /* SECAM */
-/*02*/ { 864, 720, 625, 576, 131, 21 },
- /* BW50 */
-/*03*/ { 864, 720, 625, 576, 131, 21 },
- /* BW60 */
-/*04*/ { 858, 720, 525, 480, 121, 10 }
-};
-#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
-
-/*
- * Program the chip for a setup as described in the vidinfo struct.
- *
- * Side-effects: calculates vidXshift, vidInterlace,
- * vidHeight, vidWidth which are used in a later stage
- * to calculate the overlay mask
- *
- * This is an internal function, as such it does not check the
- * validity of the struct members... Spectaculair crashes will
- * follow /very/ quick when you're wrong and the chip right :)
- */
-static
-void zoran_set_geo(struct zoran* ztv, struct vidinfo* i)
-{
- ulong top, bot;
- int stride;
- int winWidth, winHeight;
- int maxWidth, maxHeight, maxXOffset, maxYOffset;
- long vfec;
-
-DEBUG(printk(CARD_DEBUG "set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, busadr=%lx, overlay=%p)\n",CARD,i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->busadr,i->overlay));
-
- /*
- * make sure the DMA transfers are inhibited during our
- * reprogramming of the chip
- */
- zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
-
- maxWidth = tvnorms[ztv->norm].Wa;
- maxHeight = tvnorms[ztv->norm].Ha/2;
- maxXOffset = tvnorms[ztv->norm].HStart;
- maxYOffset = tvnorms[ztv->norm].VStart;
-
- /* setup vfec register (keep ExtFl,TopField and VCLKPol settings) */
- vfec = (zrread(ZORAN_VFEC) & (ZORAN_VFEC_EXTFL|ZORAN_VFEC_TOPFIELD|ZORAN_VFEC_VCLKPOL)) |
- (palette2fmt[i->format].mode & (ZORAN_VFEC_RGB|ZORAN_VFEC_ERRDIF|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24));
-
- /*
- * Set top, bottom ptrs. Since these must be DWORD aligned,
- * possible adjust the x and the width of the window.
- * so the endposition stay the same. The vidXshift will make
- * sure we are not writing pixels before the requested x.
- */
- ztv->vidXshift = 0;
- winWidth = i->w;
- if (winWidth < 0)
- winWidth = -winWidth;
- top = i->busadr + i->x*i->bpp + i->y*i->bpl;
- if (top & 3) {
- ztv->vidXshift = (top & 3) / i->bpp;
- winWidth += ztv->vidXshift;
- DEBUG(printk(KERN_DEBUG " window-x shifted %d pixels left\n",ztv->vidXshift));
- top &= ~3;
- }
-
- /*
- * bottom points to next frame but in interleaved mode we want
- * to 'mix' the 2 frames to one capture, so 'bot' points to one
- * (physical) line below the top line.
- */
- bot = top + i->bpl;
- zrwrite(top,ZORAN_VTOP);
- zrwrite(bot,ZORAN_VBOT);
-
- /*
- * Make sure the winWidth is DWORD aligned too,
- * thereby automaticly making sure the stride to the
- * next line is DWORD aligned too (as required by spec).
- */
- if ((winWidth*i->bpp) & 3) {
-DEBUG(printk(KERN_DEBUG " window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3));
- winWidth += (winWidth*i->bpp) & 3;
- }
-
- /* determine the DispMode and stride */
- if (i->h >= 0 && i->h <= maxHeight) {
- /* single frame grab suffices for this height. */
- vfec |= ZORAN_VFEC_DISPMOD;
- ztv->vidInterlace = 0;
- stride = i->bpl - (winWidth*i->bpp);
- winHeight = i->h;
- }
- else {
- /* interleaving needed for this height */
- ztv->vidInterlace = 1;
- stride = i->bpl*2 - (winWidth*i->bpp);
- winHeight = i->h/2;
- }
- if (winHeight < 0) /* can happen for VBI! */
- winHeight = -winHeight;
-
- /* safety net, sometimes bpl is too short??? */
- if (stride<0) {
-DEBUG(printk(CARD_DEBUG "WARNING stride = %d\n",CARD,stride));
- stride = 0;
- }
-
- zraor((winHeight<<12)|(winWidth<<0),~(ZORAN_VDC_VIDWINHT|ZORAN_VDC_VIDWINWID), ZORAN_VDC);
- zraor(stride<<16,~ZORAN_VSTR_DISPSTRIDE,ZORAN_VSTR);
-
- /* remember vidWidth, vidHeight for overlay calculations */
- ztv->vidWidth = winWidth;
- ztv->vidHeight = winHeight;
-DEBUG(printk(KERN_DEBUG " top=%08lx, bottom=%08lx\n",top,bot));
-DEBUG(printk(KERN_DEBUG " winWidth=%d, winHeight=%d\n",winWidth,winHeight));
-DEBUG(printk(KERN_DEBUG " maxWidth=%d, maxHeight=%d\n",maxWidth,maxHeight));
-DEBUG(printk(KERN_DEBUG " stride=%d\n",stride));
-
- /*
- * determine horizontal scales and crops
- */
- if (i->w < 0) {
- int Hstart = 1;
- int Hend = Hstart + winWidth;
-DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Hstart, Hend));
- zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH);
- }
- else {
- int Wa = maxWidth;
- int X = (winWidth*64+Wa-1)/Wa;
- int We = winWidth*64/X;
- int HorDcm = 64-X;
- int hcrop1 = 2*(Wa-We)/4;
- /*
- * BUGFIX: Juha Nurmela <junki@qn-lpr2-165.quicknet.inet.fi>
- * found the solution to the color phase shift.
- * See ChangeLog for the full explanation)
- */
- int Hstart = (maxXOffset + hcrop1) | 1;
- int Hend = Hstart + We - 1;
-
-DEBUG(printk(KERN_DEBUG " X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend));
-
- zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH);
- vfec |= HorDcm<<14;
-
- if (HorDcm<16)
- vfec |= ZORAN_VFEC_HFILTER_1; /* no filter */
- else if (HorDcm<32)
- vfec |= ZORAN_VFEC_HFILTER_3; /* 3 tap filter */
- else if (HorDcm<48)
- vfec |= ZORAN_VFEC_HFILTER_4; /* 4 tap filter */
- else vfec |= ZORAN_VFEC_HFILTER_5; /* 5 tap filter */
- }
-
- /*
- * Determine vertical scales and crops
- *
- * when height is negative, we want to read starting at line 0
- * One day someone might need access to these lines...
- */
- if (i->h < 0) {
- int Vstart = 0;
- int Vend = Vstart + winHeight;
-DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Vstart, Vend));
- zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV);
- }
- else {
- int Ha = maxHeight;
- int Y = (winHeight*64+Ha-1)/Ha;
- int He = winHeight*64/Y;
- int VerDcm = 64-Y;
- int vcrop1 = 2*(Ha-He)/4;
- int Vstart = maxYOffset + vcrop1;
- int Vend = Vstart + He - 1;
-
-DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend));
- zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV);
- vfec |= VerDcm<<8;
- }
-
-DEBUG(printk(KERN_DEBUG " F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name));
-
- /* setup the requested format */
- zrwrite(vfec, ZORAN_VFEC);
-}
-
-static
-void zoran_common_open(struct zoran* ztv, int flags)
-{
- UNUSED(flags);
-
- /* already opened? */
- if (ztv->users++ != 0)
- return;
-
- /* unmute audio */
- /* /what/ audio? */
-
- ztv->state = 0;
-
- /* setup the encoder to the initial values */
- ztv->picture.colour=254<<7;
- ztv->picture.brightness=128<<8;
- ztv->picture.hue=128<<8;
- ztv->picture.contrast=216<<7;
- i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture);
-
- /* default to the composite input since my camera is there */
- zoran_muxsel(ztv, 0, VIDEO_MODE_PAL);
-}
-
-static
-void zoran_common_close(struct zoran* ztv)
-{
- if (--ztv->users != 0)
- return;
-
- /* mute audio */
- /* /what/ audio? */
-
- /* stop the chip */
- zoran_cap(ztv, 0);
-}
-
-/*
- * Open a zoran card. Right now the flags are just a hack
- */
-static int zoran_open(struct video_device *dev, int flags)
-{
- struct zoran *ztv = (struct zoran*)dev;
- struct vidinfo* item;
- char* pos;
-
- DEBUG(printk(CARD_DEBUG "open(dev,%d)\n",CARD,flags));
-
- /*********************************************
- * We really should be doing lazy allocing...
- *********************************************/
- /* allocate a frame buffer */
- if (!ztv->fbuffer)
- ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE);
- if (!ztv->fbuffer) {
- /* could not get a buffer, bail out */
- return -ENOBUFS;
- }
- /* at this time we _always_ have a framebuffer */
- memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE);
-
- if (!ztv->overinfo.overlay)
- ztv->overinfo.overlay = kmalloc(1024*1024/8, GFP_KERNEL);
- if (!ztv->overinfo.overlay) {
- /* could not get an overlay buffer, bail out */
- bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE);
- return -ENOBUFS;
- }
- /* at this time we _always_ have a overlay */
-
- /* clear buffer status, and give them a DMAable address */
- pos = ztv->fbuffer;
- for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
- {
- item->status = FBUFFER_FREE;
- item->memadr = pos;
- item->busadr = virt_to_bus(pos);
- pos += ZORAN_MAX_FBUFFER;
- }
-
- /* do the common part of all open's */
- zoran_common_open(ztv, flags);
-
- return 0;
-}
-
-static
-void zoran_close(struct video_device* dev)
-{
- struct zoran *ztv = (struct zoran*)dev;
-
- DEBUG(printk(CARD_DEBUG "close(dev)\n",CARD));
-
- /* driver specific closure */
- clear_bit(STATE_OVERLAY, &ztv->state);
-
- zoran_common_close(ztv);
-
- /*
- * This is sucky but right now I can't find a good way to
- * be sure its safe to free the buffer. We wait 5-6 fields
- * which is more than sufficient to be sure.
- */
- msleep(100); /* Wait 1/10th of a second */
-
- /* free the allocated framebuffer */
- bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE);
- ztv->fbuffer = 0;
- kfree(ztv->overinfo.overlay);
- ztv->overinfo.overlay = 0;
-
-}
-
-/*
- * This read function could be used reentrant in a SMP situation.
- *
- * This is made possible by the spinlock which is kept till we
- * found and marked a buffer for our own use. The lock must
- * be released as soon as possible to prevent lock contention.
- */
-static
-long zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock)
-{
- struct zoran *ztv = (struct zoran*)dev;
- unsigned long max;
- struct vidinfo* unused = 0;
- struct vidinfo* done = 0;
-
- DEBUG(printk(CARD_DEBUG "zoran_read(%p,%ld,%d)\n",CARD,buf,count,nonblock));
-
- /* find ourself a free or completed buffer */
- for (;;) {
- struct vidinfo* item;
-
- write_lock_irq(&ztv->lock);
- for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
- {
- if (!unused && item->status == FBUFFER_FREE)
- unused = item;
- if (!done && item->status == FBUFFER_DONE)
- done = item;
- }
- if (done || unused)
- break;
-
- /* no more free buffers, wait for them. */
- write_unlock_irq(&ztv->lock);
- if (nonblock)
- return -EWOULDBLOCK;
- interruptible_sleep_on(&ztv->grabq);
- if (signal_pending(current))
- return -EINTR;
- }
-
- /* Do we have 'ready' data? */
- if (!done) {
- /* no? than this will take a while... */
- if (nonblock) {
- write_unlock_irq(&ztv->lock);
- return -EWOULDBLOCK;
- }
-
- /* mark the unused buffer as wanted */
- unused->status = FBUFFER_BUSY;
- unused->w = 320;
- unused->h = 240;
- unused->format = VIDEO_PALETTE_RGB24;
- unused->bpp = palette2fmt[unused->format].bpp;
- unused->bpl = unused->w * unused->bpp;
- unused->next = 0;
- { /* add to tail of queue */
- struct vidinfo* oldframe = ztv->workqueue;
- if (!oldframe) ztv->workqueue = unused;
- else {
- while (oldframe->next) oldframe = oldframe->next;
- oldframe->next = unused;
- }
- }
- write_unlock_irq(&ztv->lock);
-
- /* tell the state machine we want it filled /NOW/ */
- zoran_cap(ztv, 1);
-
- /* wait till this buffer gets grabbed */
- wait_event_interruptible(ztv->grabq,
- (unused->status != FBUFFER_BUSY));
- /* see if a signal did it */
- if (signal_pending(current))
- return -EINTR;
- done = unused;
- }
- else
- write_unlock_irq(&ztv->lock);
-
- /* Yes! we got data! */
- max = done->bpl * done->h;
- if (count > max)
- count = max;
- if (copy_to_user((void*)buf, done->memadr, count))
- count = -EFAULT;
-
- /* keep the engine running */
- done->status = FBUFFER_FREE;
-// zoran_cap(ztv,1);
-
- /* tell listeners this buffer became free */
- wake_up_interruptible(&ztv->grabq);
-
- /* goodbye */
- DEBUG(printk(CARD_DEBUG "zoran_read() returns %lu\n",CARD,count));
- return count;
-}
-
-static
-long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock)
-{
- struct zoran *ztv = (struct zoran *)dev;
- UNUSED(ztv); UNUSED(dev); UNUSED(buf); UNUSED(count); UNUSED(nonblock);
- DEBUG(printk(CARD_DEBUG "zoran_write\n",CARD));
- return -EINVAL;
-}
-
-static
-unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait)
-{
- struct zoran *ztv = (struct zoran *)dev;
- struct vidinfo* item;
- unsigned int mask = 0;
-
- poll_wait(file, &ztv->grabq, wait);
-
- for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
- if (item->status == FBUFFER_DONE)
- {
- mask |= (POLLIN | POLLRDNORM);
- break;
- }
-
- DEBUG(printk(CARD_DEBUG "zoran_poll()=%x\n",CARD,mask));
-
- return mask;
-}
-
-/* append a new clipregion to the vector of video_clips */
-static
-void new_clip(struct video_window* vw, struct video_clip* vcp, int x, int y, int w, int h)
-{
- vcp[vw->clipcount].x = x;
- vcp[vw->clipcount].y = y;
- vcp[vw->clipcount].width = w;
- vcp[vw->clipcount].height = h;
- vw->clipcount++;
-}
-
-static
-int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
-{
- struct zoran* ztv = (struct zoran*)dev;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability c;
- DEBUG(printk(CARD_DEBUG "VIDIOCGCAP\n",CARD));
-
- strcpy(c.name,ztv->video_dev.name);
- c.type = VID_TYPE_CAPTURE|
- VID_TYPE_OVERLAY|
- VID_TYPE_CLIPPING|
- VID_TYPE_FRAMERAM|
- 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;
- } else
- /* no decoder -> no channels */
- c.channels = c.audios = 0;
- c.maxwidth = 768;
- c.maxheight = 576;
- c.minwidth = 32;
- c.minheight = 32;
- if (copy_to_user(arg,&c,sizeof(c)))
- return -EFAULT;
- break;
- }
-
- case VIDIOCGCHAN:
- {
- struct video_channel v;
- int mux;
- if (copy_from_user(&v, arg,sizeof(v)))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDIOCGCHAN(%d)\n",CARD,v.channel));
- v.flags=VIDEO_VC_AUDIO
-#ifdef VIDEO_VC_NORM
- |VIDEO_VC_NORM
-#endif
- ;
- v.tuners=0;
- v.type=VIDEO_TYPE_CAMERA;
-#ifdef I_EXPECT_POSSIBLE_NORMS_IN_THE_API
- v.norm=VIDEO_MODE_PAL|
- VIDEO_MODE_NTSC|
- VIDEO_MODE_SECAM;
-#else
- v.norm=VIDEO_MODE_PAL;
-#endif
- /* too many inputs? no decoder -> no channels */
- if (!ztv->have_decoder || v.channel < 0 || v.channel >= ztv->card->video_inputs)
- return -EINVAL;
-
- /* now determine the name of the channel */
- mux = ztv->card->video_mux[v.channel];
- if (mux & IS_TUNER) {
- /* lets assume only one tuner, yes? */
- strcpy(v.name,"Television");
- v.type = VIDEO_TYPE_TV;
- if (ztv->have_tuner) {
- v.flags |= VIDEO_VC_TUNER;
- v.tuners = 1;
- }
- }
- else if (mux & IS_SVHS)
- sprintf(v.name,"S-Video-%d",v.channel);
- else
- sprintf(v.name,"CVBS-%d",v.channel);
-
- if (copy_to_user(arg,&v,sizeof(v)))
- return -EFAULT;
- break;
- }
- case VIDIOCSCHAN:
- { /* set video channel */
- struct video_channel v;
- if (copy_from_user(&v, arg,sizeof(v)))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm));
-
- /* too many inputs? no decoder -> no channels */
- if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs || v.channel < 0)
- return -EINVAL;
-
- if (v.norm != VIDEO_MODE_PAL &&
- v.norm != VIDEO_MODE_NTSC &&
- v.norm != VIDEO_MODE_SECAM &&
- v.norm != VIDEO_MODE_AUTO)
- return -EOPNOTSUPP;
-
- /* make it happen, nr1! */
- return zoran_muxsel(ztv,v.channel,v.norm);
- }
-
- case VIDIOCGTUNER:
- {
- struct video_tuner v;
- if (copy_from_user(&v, arg,sizeof(v)))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDIOCGTUNER(%d)\n",CARD,v.tuner));
-
- /* Only no or one tuner for now */
- if (!ztv->have_tuner || v.tuner)
- return -EINVAL;
-
- strcpy(v.name,"Television");
- v.rangelow = 0;
- v.rangehigh = ~0;
- v.flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
- v.mode = ztv->norm;
- v.signal = 0xFFFF; /* unknown */
-
- if (copy_to_user(arg,&v,sizeof(v)))
- return -EFAULT;
- break;
- }
- case VIDIOCSTUNER:
- {
- struct video_tuner v;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDIOCSTUNER(%d,%d)\n",CARD,v.tuner,v.mode));
-
- /* Only no or one tuner for now */
- if (!ztv->have_tuner || v.tuner)
- return -EINVAL;
-
- /* and it only has certain valid modes */
- if( v.mode != VIDEO_MODE_PAL &&
- v.mode != VIDEO_MODE_NTSC &&
- v.mode != VIDEO_MODE_SECAM)
- return -EOPNOTSUPP;
-
- /* engage! */
- return zoran_muxsel(ztv,v.tuner,v.mode);
- }
-
- case VIDIOCGPICT:
- {
- struct video_picture p = ztv->picture;
- DEBUG(printk(CARD_DEBUG "VIDIOCGPICT\n",CARD));
- p.depth = ztv->depth;
- switch (p.depth) {
- case 8: p.palette=VIDEO_PALETTE_YUV422;
- break;
- case 15: p.palette=VIDEO_PALETTE_RGB555;
- break;
- case 16: p.palette=VIDEO_PALETTE_RGB565;
- break;
- case 24: p.palette=VIDEO_PALETTE_RGB24;
- break;
- case 32: p.palette=VIDEO_PALETTE_RGB32;
- break;
- }
- if (copy_to_user(arg, &p, sizeof(p)))
- return -EFAULT;
- break;
- }
- case VIDIOCSPICT:
- {
- struct video_picture p;
- if (copy_from_user(&p, arg,sizeof(p)))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d)\n",CARD,p.brightness,p.hue,p.colour,p.contrast,p.whiteness,p.depth,p.palette));
-
- /* depth must match with framebuffer */
- if (p.depth != ztv->depth)
- return -EINVAL;
-
- /* check if palette matches this bpp */
- if (p.palette>NRPALETTES ||
- palette2fmt[p.palette].bpp != ztv->overinfo.bpp)
- return -EINVAL;
-
- write_lock_irq(&ztv->lock);
- ztv->overinfo.format = p.palette;
- ztv->picture = p;
- write_unlock_irq(&ztv->lock);
-
- /* tell the decoder */
- i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p);
- break;
- }
-
- case VIDIOCGWIN:
- {
- struct video_window vw;
- DEBUG(printk(CARD_DEBUG "VIDIOCGWIN\n",CARD));
- read_lock(&ztv->lock);
- vw.x = ztv->overinfo.x;
- vw.y = ztv->overinfo.y;
- vw.width = ztv->overinfo.w;
- vw.height = ztv->overinfo.h;
- vw.chromakey= 0;
- vw.flags = 0;
- if (ztv->vidInterlace)
- vw.flags|=VIDEO_WINDOW_INTERLACE;
- read_unlock(&ztv->lock);
- if (copy_to_user(arg,&vw,sizeof(vw)))
- return -EFAULT;
- break;
- }
- case VIDIOCSWIN:
- {
- struct video_window vw;
- struct video_clip *vcp;
- int on;
- if (copy_from_user(&vw,arg,sizeof(vw)))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDIOCSWIN(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount));
-
- if (vw.flags)
- return -EINVAL;
-
- if (vw.clipcount <0 || vw.clipcount>256)
- return -EDOM; /* Too many! */
-
- /*
- * Do any clips.
- */
- vcp = vmalloc(sizeof(struct video_clip)*(vw.clipcount+4));
- if (vcp==NULL)
- return -ENOMEM;
- if (vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount)) {
- vfree(vcp);
- return -EFAULT;
- }
-
- on = ztv->running;
- if (on)
- zoran_cap(ztv, 0);
-
- /*
- * strange, it seems xawtv sometimes calls us with 0
- * width and/or height. Ignore these values
- */
- if (vw.x == 0)
- vw.x = ztv->overinfo.x;
- if (vw.y == 0)
- vw.y = ztv->overinfo.y;
-
- /* by now we are committed to the new data... */
- write_lock_irq(&ztv->lock);
- ztv->overinfo.x = vw.x;
- ztv->overinfo.y = vw.y;
- ztv->overinfo.w = vw.width;
- ztv->overinfo.h = vw.height;
- write_unlock_irq(&ztv->lock);
-
- /*
- * Impose display clips
- */
- if (vw.x+vw.width > ztv->swidth)
- new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1);
- if (vw.y+vw.height > ztv->sheight)
- new_clip(&vw, vcp, 0, ztv->sheight-vw.y, vw.width-1, vw.height-1);
-
- /* built the requested clipping zones */
- zoran_set_geo(ztv, &ztv->overinfo);
- zoran_built_overlay(ztv, vw.clipcount, vcp);
- vfree(vcp);
-
- /* if we were on, restart the video engine */
- if (on)
- zoran_cap(ztv, 1);
- break;
- }
-
- case VIDIOCCAPTURE:
- {
- int v;
- if (get_user(v, (int *)arg))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v));
-
- if (v==0) {
- clear_bit(STATE_OVERLAY, &ztv->state);
- zoran_cap(ztv, 1);
- }
- else {
- /* is VIDIOCSFBUF, VIDIOCSWIN done? */
- if (ztv->overinfo.busadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0)
- return -EINVAL;
-
- set_bit(STATE_OVERLAY, &ztv->state);
- zoran_cap(ztv, 1);
- }
- break;
- }
-
- case VIDIOCGFBUF:
- {
- struct video_buffer v;
- DEBUG(printk(CARD_DEBUG "VIDIOCGFBUF\n",CARD));
- read_lock(&ztv->lock);
- v.base = (void *)ztv->overinfo.busadr;
- v.height = ztv->sheight;
- v.width = ztv->swidth;
- v.depth = ztv->depth;
- v.bytesperline = ztv->overinfo.bpl;
- read_unlock(&ztv->lock);
- if(copy_to_user(arg, &v,sizeof(v)))
- return -EFAULT;
- break;
- }
- case VIDIOCSFBUF:
- {
- 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));
-
- if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32)
- return -EINVAL;
- if (v.bytesperline<1)
- return -EINVAL;
- if (ztv->running)
- return -EBUSY;
- write_lock_irq(&ztv->lock);
- ztv->overinfo.busadr = (ulong)v.base;
- ztv->sheight = v.height;
- ztv->swidth = v.width;
- ztv->depth = v.depth; /* bits per pixel */
- ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */
- ztv->overinfo.bpl = v.bytesperline; /* bytes per line */
- write_unlock_irq(&ztv->lock);
- break;
- }
-
- case VIDIOCKEY:
- {
- /* Will be handled higher up .. */
- break;
- }
-
- case VIDIOCSYNC:
- {
- int i;
- if (get_user(i, (int *) arg))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i));
- if (i<0 || i>ZORAN_MAX_FBUFFERS)
- return -EINVAL;
- switch (ztv->grabinfo[i].status) {
- case FBUFFER_FREE:
- return -EINVAL;
- case FBUFFER_BUSY:
- /* wait till this buffer gets grabbed */
- wait_event_interruptible(ztv->grabq,
- (ztv->grabinfo[i].status != FBUFFER_BUSY));
- /* see if a signal did it */
- if (signal_pending(current))
- return -EINTR;
- /* don't fall through; a DONE buffer is not UNUSED */
- break;
- case FBUFFER_DONE:
- ztv->grabinfo[i].status = FBUFFER_FREE;
- /* tell ppl we have a spare buffer */
- wake_up_interruptible(&ztv->grabq);
- break;
- }
- DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d) returns\n",CARD,i));
- break;
- }
-
- case VIDIOCMCAPTURE:
- {
- struct video_mmap vm;
- struct vidinfo* frame;
- if (copy_from_user(&vm,arg,sizeof(vm)))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDIOCMCAPTURE(%d,(%d,%d),%d)\n",CARD,vm.frame,vm.width,vm.height,vm.format));
- if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS ||
- vm.width<32 || vm.width>768 ||
- vm.height<32 || vm.height>576 ||
- vm.format>NRPALETTES ||
- palette2fmt[vm.format].mode == 0)
- return -EINVAL;
-
- /* we are allowed to take over UNUSED and DONE buffers */
- frame = &ztv->grabinfo[vm.frame];
- if (frame->status == FBUFFER_BUSY)
- return -EBUSY;
-
- /* setup the other parameters if they are given */
- write_lock_irq(&ztv->lock);
- frame->w = vm.width;
- frame->h = vm.height;
- frame->format = vm.format;
- frame->bpp = palette2fmt[frame->format].bpp;
- frame->bpl = frame->w*frame->bpp;
- frame->status = FBUFFER_BUSY;
- frame->next = 0;
- { /* add to tail of queue */
- struct vidinfo* oldframe = ztv->workqueue;
- if (!oldframe) ztv->workqueue = frame;
- else {
- while (oldframe->next) oldframe = oldframe->next;
- oldframe->next = frame;
- }
- }
- write_unlock_irq(&ztv->lock);
- zoran_cap(ztv, 1);
- break;
- }
-
- case VIDIOCGMBUF:
- {
- struct video_mbuf mb;
- int i;
- DEBUG(printk(CARD_DEBUG "VIDIOCGMBUF\n",CARD));
- mb.size = ZORAN_MAX_FBUFSIZE;
- mb.frames = ZORAN_MAX_FBUFFERS;
- for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
- mb.offsets[i] = i*ZORAN_MAX_FBUFFER;
- if(copy_to_user(arg, &mb,sizeof(mb)))
- return -EFAULT;
- break;
- }
-
- case VIDIOCGUNIT:
- {
- struct video_unit vu;
- DEBUG(printk(CARD_DEBUG "VIDIOCGUNIT\n",CARD));
- vu.video = ztv->video_dev.minor;
- vu.vbi = ztv->vbi_dev.minor;
- vu.radio = VIDEO_NO_UNIT;
- vu.audio = VIDEO_NO_UNIT;
- vu.teletext = VIDEO_NO_UNIT;
- if(copy_to_user(arg, &vu,sizeof(vu)))
- return -EFAULT;
- break;
- }
-
- case VIDIOCGFREQ:
- {
- unsigned long v = ztv->tuner_freq;
- if (copy_to_user(arg,&v,sizeof(v)))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDIOCGFREQ\n",CARD));
- break;
- }
- case VIDIOCSFREQ:
- {
- unsigned long v;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDIOCSFREQ\n",CARD));
-
- if (ztv->have_tuner) {
- int fixme = v;
- if (i2c_control_device(&(ztv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_TVFREQ, &fixme) < 0)
- return -EAGAIN;
- }
- ztv->tuner_freq = v;
- break;
- }
-
- /* Why isn't this in the API?
- * And why doesn't it take a buffer number?
- case BTTV_FIELDNR:
- {
- unsigned long v = ztv->lastfieldnr;
- if (copy_to_user(arg,&v,sizeof(v)))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "BTTV_FIELDNR\n",CARD));
- break;
- }
- */
-
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static
-int zoran_mmap(struct vm_area_struct *vma, struct video_device* dev, const char* adr, unsigned long size)
-{
- struct zoran* ztv = (struct zoran*)dev;
- unsigned long start = (unsigned long)adr;
- unsigned long pos;
-
- DEBUG(printk(CARD_DEBUG "zoran_mmap(0x%p,%ld)\n",CARD,adr,size));
-
- /* sanity checks */
- if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer)
- return -EINVAL;
-
- /* start mapping the whole shabang to user memory */
- pos = (unsigned long)ztv->fbuffer;
- while (size>0) {
- unsigned long pfn = virt_to_phys((void*)pos) >> PAGE_SHIFT;
- if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- return 0;
-}
-
-static struct video_device zr36120_template=
-{
- .owner = THIS_MODULE,
- .name = "UNSET",
- .type = VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY,
- .hardware = VID_HARDWARE_ZR36120,
- .open = zoran_open,
- .close = zoran_close,
- .read = zoran_read,
- .write = zoran_write,
- .poll = zoran_poll,
- .ioctl = zoran_ioctl,
- .compat_ioctl = v4l_compat_ioctl32,
- .mmap = zoran_mmap,
- .minor = -1,
-};
-
-static
-int vbi_open(struct video_device *dev, int flags)
-{
- struct zoran *ztv = dev->priv;
- struct vidinfo* item;
-
- DEBUG(printk(CARD_DEBUG "vbi_open(dev,%d)\n",CARD,flags));
-
- /*
- * During VBI device open, we continiously grab VBI-like
- * data in the vbi buffer when we have nothing to do.
- * Only when there is an explicit request for VBI data
- * (read call) we /force/ a read.
- */
-
- /* allocate buffers */
- for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
- {
- item->status = FBUFFER_FREE;
-
- /* alloc */
- if (!item->memadr) {
- item->memadr = bmalloc(ZORAN_VBI_BUFSIZE);
- if (!item->memadr) {
- /* could not get a buffer, bail out */
- while (item != ztv->readinfo) {
- item--;
- bfree(item->memadr, ZORAN_VBI_BUFSIZE);
- item->memadr = 0;
- item->busadr = 0;
- }
- return -ENOBUFS;
- }
- }
-
- /* determine the DMAable address */
- item->busadr = virt_to_bus(item->memadr);
- }
-
- /* do the common part of all open's */
- zoran_common_open(ztv, flags);
-
- set_bit(STATE_VBI, &ztv->state);
- /* start read-ahead */
- zoran_cap(ztv, 1);
-
- return 0;
-}
-
-static
-void vbi_close(struct video_device *dev)
-{
- struct zoran *ztv = dev->priv;
- struct vidinfo* item;
-
- DEBUG(printk(CARD_DEBUG "vbi_close(dev)\n",CARD));
-
- /* driver specific closure */
- clear_bit(STATE_VBI, &ztv->state);
-
- zoran_common_close(ztv);
-
- /*
- * This is sucky but right now I can't find a good way to
- * be sure its safe to free the buffer. We wait 5-6 fields
- * which is more than sufficient to be sure.
- */
- msleep(100); /* Wait 1/10th of a second */
-
- for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
- {
- if (item->memadr)
- bfree(item->memadr, ZORAN_VBI_BUFSIZE);
- item->memadr = 0;
- }
-
-}
-
-/*
- * This read function could be used reentrant in a SMP situation.
- *
- * This is made possible by the spinlock which is kept till we
- * found and marked a buffer for our own use. The lock must
- * be released as soon as possible to prevent lock contention.
- */
-static
-long vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonblock)
-{
- struct zoran *ztv = dev->priv;
- unsigned long max;
- struct vidinfo* unused = 0;
- struct vidinfo* done = 0;
-
- DEBUG(printk(CARD_DEBUG "vbi_read(0x%p,%ld,%d)\n",CARD,buf,count,nonblock));
-
- /* find ourself a free or completed buffer */
- for (;;) {
- struct vidinfo* item;
-
- write_lock_irq(&ztv->lock);
- for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) {
- if (!unused && item->status == FBUFFER_FREE)
- unused = item;
- if (!done && item->status == FBUFFER_DONE)
- done = item;
- }
- if (done || unused)
- break;
-
- /* no more free buffers, wait for them. */
- write_unlock_irq(&ztv->lock);
- if (nonblock)
- return -EWOULDBLOCK;
- interruptible_sleep_on(&ztv->vbiq);
- if (signal_pending(current))
- return -EINTR;
- }
-
- /* Do we have 'ready' data? */
- if (!done) {
- /* no? than this will take a while... */
- if (nonblock) {
- write_unlock_irq(&ztv->lock);
- return -EWOULDBLOCK;
- }
-
- /* mark the unused buffer as wanted */
- unused->status = FBUFFER_BUSY;
- unused->next = 0;
- { /* add to tail of queue */
- struct vidinfo* oldframe = ztv->workqueue;
- if (!oldframe) ztv->workqueue = unused;
- else {
- while (oldframe->next) oldframe = oldframe->next;
- oldframe->next = unused;
- }
- }
- write_unlock_irq(&ztv->lock);
-
- /* tell the state machine we want it filled /NOW/ */
- zoran_cap(ztv, 1);
-
- /* wait till this buffer gets grabbed */
- wait_event_interruptible(ztv->vbiq,
- (unused->status != FBUFFER_BUSY));
- /* see if a signal did it */
- if (signal_pending(current))
- return -EINTR;
- done = unused;
- }
- else
- write_unlock_irq(&ztv->lock);
-
- /* Yes! we got data! */
- max = done->bpl * -done->h;
- if (count > max)
- count = max;
-
- /* check if the user gave us enough room to write the data */
- if (!access_ok(VERIFY_WRITE, buf, count)) {
- count = -EFAULT;
- goto out;
- }
-
- /*
- * Now transform/strip the data from YUV to Y-only
- * NB. Assume the Y is in the LSB of the YUV data.
- */
- {
- unsigned char* optr = buf;
- unsigned char* eptr = buf+count;
-
- /* are we beeing accessed from an old driver? */
- if (count == 2*19*2048) {
- /*
- * Extreme HACK, old VBI programs expect 2048 points
- * of data, and we only got 864 orso. Double each
- * datapoint and clear the rest of the line.
- * This way we have appear to have a
- * sample_frequency of 29.5 Mc.
- */
- int x,y;
- unsigned char* iptr = done->memadr+1;
- for (y=done->h; optr<eptr && y<0; y++)
- {
- /* copy to doubled data to userland */
- for (x=0; optr+1<eptr && x<-done->w; x++)
- {
- unsigned char a = iptr[x*2];
- __put_user(a, optr++);
- __put_user(a, optr++);
- }
- /* and clear the rest of the line */
- for (x*=2; optr<eptr && x<done->bpl; x++)
- __put_user(0, optr++);
- /* next line */
- iptr += done->bpl;
- }
- }
- else {
- /*
- * Other (probably newer) programs asked
- * us what geometry we are using, and are
- * reading the correct size.
- */
- int x,y;
- unsigned char* iptr = done->memadr+1;
- for (y=done->h; optr<eptr && y<0; y++)
- {
- /* copy to doubled data to userland */
- for (x=0; optr<eptr && x<-done->w; x++)
- __put_user(iptr[x*2], optr++);
- /* and clear the rest of the line */
- for (;optr<eptr && x<done->bpl; x++)
- __put_user(0, optr++);
- /* next line */
- iptr += done->bpl;
- }
- }
-
- /* API compliance:
- * place the framenumber (half fieldnr) in the last long
- */
- __put_user(done->fieldnr/2, ((ulong*)eptr)[-1]);
- }
-
- /* keep the engine running */
- done->status = FBUFFER_FREE;
- zoran_cap(ztv, 1);
-
- /* tell listeners this buffer just became free */
- wake_up_interruptible(&ztv->vbiq);
-
- /* goodbye */
-out:
- DEBUG(printk(CARD_DEBUG "vbi_read() returns %lu\n",CARD,count));
- return count;
-}
-
-static
-unsigned int vbi_poll(struct video_device *dev, struct file *file, poll_table *wait)
-{
- struct zoran *ztv = dev->priv;
- struct vidinfo* item;
- unsigned int mask = 0;
-
- poll_wait(file, &ztv->vbiq, wait);
-
- for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
- if (item->status == FBUFFER_DONE)
- {
- mask |= (POLLIN | POLLRDNORM);
- break;
- }
-
- DEBUG(printk(CARD_DEBUG "vbi_poll()=%x\n",CARD,mask));
-
- return mask;
-}
-
-static
-int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
-{
- struct zoran* ztv = dev->priv;
-
- switch (cmd) {
- case VIDIOCGVBIFMT:
- {
- struct vbi_format f;
- DEBUG(printk(CARD_DEBUG "VIDIOCGVBIINFO\n",CARD));
- f.sampling_rate = 14750000UL;
- f.samples_per_line = -ztv->readinfo[0].w;
- f.sample_format = VIDEO_PALETTE_RAW;
- f.start[0] = f.start[1] = ztv->readinfo[0].y;
- f.start[1] += 312;
- f.count[0] = f.count[1] = -ztv->readinfo[0].h;
- f.flags = VBI_INTERLACED;
- if (copy_to_user(arg,&f,sizeof(f)))
- return -EFAULT;
- break;
- }
- case VIDIOCSVBIFMT:
- {
- struct vbi_format f;
- int i;
- if (copy_from_user(&f, arg,sizeof(f)))
- return -EFAULT;
- DEBUG(printk(CARD_DEBUG "VIDIOCSVBIINFO(%d,%d,%d,%d,%d,%d,%d,%x)\n",CARD,f.sampling_rate,f.samples_per_line,f.sample_format,f.start[0],f.start[1],f.count[0],f.count[1],f.flags));
-
- /* lots of parameters are fixed... (PAL) */
- if (f.sampling_rate != 14750000UL ||
- f.samples_per_line > 864 ||
- f.sample_format != VIDEO_PALETTE_RAW ||
- f.start[0] < 0 ||
- f.start[0] != f.start[1]-312 ||
- f.count[0] != f.count[1] ||
- f.start[0]+f.count[0] >= 288 ||
- f.flags != VBI_INTERLACED)
- return -EINVAL;
-
- write_lock_irq(&ztv->lock);
- ztv->readinfo[0].y = f.start[0];
- ztv->readinfo[0].w = -f.samples_per_line;
- ztv->readinfo[0].h = -f.count[0];
- ztv->readinfo[0].bpl = f.samples_per_line*ztv->readinfo[0].bpp;
- for (i=1; i<ZORAN_VBI_BUFFERS; i++)
- ztv->readinfo[i] = ztv->readinfo[i];
- write_unlock_irq(&ztv->lock);
- break;
- }
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static struct video_device vbi_template=
-{
- .owner = THIS_MODULE,
- .name = "UNSET",
- .type = VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
- .hardware = VID_HARDWARE_ZR36120,
- .open = vbi_open,
- .close = vbi_close,
- .read = vbi_read,
- .write = zoran_write,
- .poll = vbi_poll,
- .ioctl = vbi_ioctl,
- .minor = -1,
-};
-
-/*
- * Scan for a Zoran chip, request the irq and map the io memory
- */
-static
-int __init find_zoran(void)
-{
- int result;
- struct zoran *ztv;
- struct pci_dev *dev = NULL;
- unsigned char revision;
- int zoran_num = 0;
-
- 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))
- continue;
-
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision);
- printk(KERN_INFO "zoran: Zoran %x (rev %d) ",
- dev->device, revision);
- printk("bus: %d, devfn: %d, irq: %d, ",
- dev->bus->number, dev->devfn, dev->irq);
- printk("memory: 0x%08lx.\n", ztv->zoran_adr);
-
- ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000);
- DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem));
-
- result = request_irq(dev->irq, zoran_irq,
- IRQF_SHARED|IRQF_DISABLED,"zoran", ztv);
- if (result==-EINVAL)
- {
- iounmap(ztv->zoran_mem);
- printk(KERN_ERR "zoran: Bad irq number or handler\n");
- 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);
- continue;
- }
- /* Enable bus-mastering */
- pci_set_master(dev);
- /* Keep a reference */
- pci_dev_get(dev);
- zoran_num++;
- }
- if(zoran_num)
- printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num);
- return zoran_num;
-}
-
-static
-int __init init_zoran(int card)
-{
- struct zoran *ztv = &zorans[card];
- int i;
-
- /* if the given cardtype valid? */
- if (cardtype[card]>=NRTVCARDS) {
- printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]);
- return -1;
- }
-
- /* reset the zoran */
- zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI);
- udelay(10);
- zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI);
- udelay(10);
-
- /* zoran chip specific details */
- ztv->card = tvcards+cardtype[card]; /* point to the selected card */
- ztv->norm = 0; /* PAL */
- ztv->tuner_freq = 0;
-
- /* videocard details */
- ztv->swidth = 800;
- ztv->sheight = 600;
- ztv->depth = 16;
-
- /* State details */
- ztv->fbuffer = 0;
- ztv->overinfo.kindof = FBUFFER_OVERLAY;
- ztv->overinfo.status = FBUFFER_FREE;
- ztv->overinfo.x = 0;
- ztv->overinfo.y = 0;
- ztv->overinfo.w = 768; /* 640 */
- ztv->overinfo.h = 576; /* 480 */
- ztv->overinfo.format = VIDEO_PALETTE_RGB565;
- ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp;
- ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth;
- ztv->overinfo.busadr = 0;
- ztv->overinfo.memadr = 0;
- ztv->overinfo.overlay = 0;
- for (i=0; i<ZORAN_MAX_FBUFFERS; i++) {
- ztv->grabinfo[i] = ztv->overinfo;
- ztv->grabinfo[i].kindof = FBUFFER_GRAB;
- }
- init_waitqueue_head(&ztv->grabq);
-
- /* VBI details */
- ztv->readinfo[0] = ztv->overinfo;
- ztv->readinfo[0].kindof = FBUFFER_VBI;
- ztv->readinfo[0].w = -864;
- ztv->readinfo[0].h = -38;
- ztv->readinfo[0].format = VIDEO_PALETTE_YUV422;
- ztv->readinfo[0].bpp = palette2fmt[ztv->readinfo[0].format].bpp;
- ztv->readinfo[0].bpl = 1024*ztv->readinfo[0].bpp;
- for (i=1; i<ZORAN_VBI_BUFFERS; i++)
- ztv->readinfo[i] = ztv->readinfo[0];
- init_waitqueue_head(&ztv->vbiq);
-
- /* maintenance data */
- ztv->have_decoder = 0;
- ztv->have_tuner = 0;
- ztv->tuner_type = 0;
- ztv->running = 0;
- ztv->users = 0;
- rwlock_init(&ztv->lock);
- ztv->workqueue = 0;
- ztv->fieldnr = 0;
- ztv->lastfieldnr = 0;
-
- if (triton1)
- zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC);
-
- /* external FL determines TOP frame */
- zror(ZORAN_VFEC_EXTFL, ZORAN_VFEC);
-
- /* set HSpol */
- if (ztv->card->hsync_pos)
- zrwrite(ZORAN_VFEH_HSPOL, ZORAN_VFEH);
- /* set VSpol */
- if (ztv->card->vsync_pos)
- zrwrite(ZORAN_VFEV_VSPOL, ZORAN_VFEV);
-
- /* Set the proper General Purpuse register bits */
- /* implicit: no softreset, 0 waitstates */
- zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI);
- /* implicit: 3 duration and recovery PCI clocks on guest 0-3 */
- zrwrite(ztv->card->gpval<<24,ZORAN_GUEST);
-
- /* clear interrupt status */
- zrwrite(~0, ZORAN_ISR);
-
- /*
- * i2c template
- */
- ztv->i2c = zoran_i2c_bus_template;
- sprintf(ztv->i2c.name,"zoran-%d",card);
- ztv->i2c.data = ztv;
-
- /*
- * Now add the template and register the device unit
- */
- ztv->video_dev = zr36120_template;
- strcpy(ztv->video_dev.name, ztv->i2c.name);
- ztv->video_dev.priv = ztv;
- if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER, video_nr) < 0)
- return -1;
-
- ztv->vbi_dev = vbi_template;
- strcpy(ztv->vbi_dev.name, ztv->i2c.name);
- ztv->vbi_dev.priv = ztv;
- if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI, vbi_nr) < 0) {
- video_unregister_device(&ztv->video_dev);
- return -1;
- }
- i2c_register_bus(&ztv->i2c);
-
- /* set interrupt mask - the PIN enable will be set later */
- zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR);
-
- printk(KERN_INFO "%s: installed %s\n",ztv->i2c.name,ztv->card->name);
- return 0;
-}
-
-static
-void release_zoran(int max)
-{
- struct zoran *ztv;
- int i;
-
- for (i=0;i<max; i++)
- {
- ztv = &zorans[i];
-
- /* turn off all capturing, DMA and IRQs */
- /* reset the zoran */
- zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI);
- udelay(10);
- zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI);
- udelay(10);
-
- /* first disable interrupts before unmapping the memory! */
- zrwrite(0, ZORAN_ICR);
- zrwrite(0xffffffffUL,ZORAN_ISR);
-
- /* free it */
- free_irq(ztv->dev->irq,ztv);
-
- /* 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);
- }
-}
-
-void __exit zr36120_exit(void)
-{
- release_zoran(zoran_cards);
-}
-
-int __init zr36120_init(void)
-{
- int card;
-
- handle_chipset();
- zoran_cards = find_zoran();
- if (zoran_cards <= 0)
- return -EIO;
-
- /* initialize Zorans */
- for (card=0; card<zoran_cards; card++) {
- if (init_zoran(card) < 0) {
- /* only release the zorans we have registered */
- release_zoran(card);
- return -EIO;
- }
- }
- return 0;
-}
-
-module_init(zr36120_init);
-module_exit(zr36120_exit);
diff --git a/drivers/media/video/zr36120.h b/drivers/media/video/zr36120.h
deleted file mode 100644
index a71e485b0f9..00000000000
--- a/drivers/media/video/zr36120.h
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- zr36120.h - Zoran 36120/36125 based framegrabbers
-
- Copyright (C) 1998-1999 Pauline Middelink (middelin@polyware.nl)
-
- This program is free software; you can redistribute it and/or modify
- 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 _ZR36120_H
-#define _ZR36120_H
-
-#ifdef __KERNEL__
-
-#include <linux/types.h>
-#include <linux/wait.h>
-
-#include <linux/i2c-old.h>
-#include <linux/videodev.h>
-
-#include <asm/io.h>
-
-/*
- * Debug macro's, place an x behind the ) for actual debug-compilation
- * E.g. #define DEBUG(x...) x
- */
-#define DEBUG(x...) /* Debug driver */
-#define IDEBUG(x...) /* Debug interrupt handler */
-#define PDEBUG 0 /* Debug PCI writes */
-
-/* defined in zr36120_i2c */
-extern struct i2c_bus zoran_i2c_bus_template;
-
-#define ZORAN_MAX_FBUFFERS 2
-#define ZORAN_MAX_FBUFFER (768*576*2)
-#define ZORAN_MAX_FBUFSIZE (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER)
-
-#define ZORAN_VBI_BUFFERS 2
-#define ZORAN_VBI_BUFSIZE (22*1024*2)
-
-struct tvcard {
- char* name; /* name of the cardtype */
- int video_inputs; /* number of channels defined in video_mux */
- int audio_inputs; /* number of channels defined in audio_mux */
- __u32 swapi2c:1, /* need to swap i2c wires SDA/SCL? */
- usegirq1:1, /* VSYNC at GIRQ1 instead of GIRQ0? */
- vsync_pos:1, /* positive VSYNC signal? */
- hsync_pos:1, /* positive HSYNC signal? */
- gpdir:8, /* General Purpose Direction register */
- gpval:8; /* General Purpose Value register */
- int video_mux[6]; /* mapping channel number to physical input */
-#define IS_TUNER 0x80
-#define IS_SVHS 0x40
-#define CHANNEL_MASK 0x3F
- int audio_mux[6]; /* mapping channel number to physical input */
-};
-#define TUNER(x) ((x)|IS_TUNER)
-#define SVHS(x) ((x)|IS_SVHS)
-
-struct vidinfo {
- struct vidinfo* next; /* next active buffer */
- uint kindof;
-#define FBUFFER_OVERLAY 0
-#define FBUFFER_GRAB 1
-#define FBUFFER_VBI 2
- uint status;
-#define FBUFFER_FREE 0
-#define FBUFFER_BUSY 1
-#define FBUFFER_DONE 2
- ulong fieldnr; /* # of field, not framer! */
- uint x,y;
- int w,h; /* w,h can be negative! */
- uint format; /* index in palette2fmt[] */
- uint bpp; /* lookup from palette2fmt[] */
- uint bpl; /* calc: width * bpp */
- ulong busadr; /* bus addr for DMA engine */
- char* memadr; /* kernel addr for making copies */
- ulong* overlay; /* kernel addr of overlay mask */
-};
-
-struct zoran
-{
- struct video_device video_dev;
-#define CARD_DEBUG KERN_DEBUG "%s(%lu): "
-#define CARD_INFO KERN_INFO "%s(%lu): "
-#define CARD_ERR KERN_ERR "%s(%lu): "
-#define CARD ztv->video_dev.name,ztv->fieldnr
-
- /* zoran chip specific details */
- struct i2c_bus i2c; /* i2c registration data */
- struct pci_dev* dev; /* ptr to PCI device */
- ulong zoran_adr; /* bus address of IO memory */
- char* zoran_mem; /* kernel address of IO memory */
- struct tvcard* card; /* the cardtype */
- uint norm; /* 0=PAL, 1=NTSC, 2=SECAM */
- uint tuner_freq; /* Current freq in kHz */
- struct video_picture picture; /* Current picture params */
-
- /* videocard details */
- uint swidth; /* screen width */
- uint sheight; /* screen height */
- uint depth; /* depth in bits */
-
- /* State details */
- char* fbuffer; /* framebuffers for mmap */
- struct vidinfo overinfo; /* overlay data */
- struct vidinfo grabinfo[ZORAN_MAX_FBUFFERS]; /* grabbing data*/
- wait_queue_head_t grabq; /* grabbers queue */
-
- /* VBI details */
- struct video_device vbi_dev;
- struct vidinfo readinfo[2]; /* VBI data - flip buffers */
- wait_queue_head_t vbiq; /* vbi queue */
-
- /* maintenance data */
- int have_decoder; /* did we detect a mux? */
- int have_tuner; /* did we detect a tuner? */
- int users; /* howmany video/vbi open? */
- int tuner_type; /* tuner type, when found */
- int running; /* are we rolling? */
- rwlock_t lock;
- long state; /* what is requested of us? */
-#define STATE_OVERLAY 0
-#define STATE_VBI 1
- struct vidinfo* workqueue; /* buffers to grab, head is active */
- ulong fieldnr; /* #field, ticked every VSYNC */
- ulong lastfieldnr; /* #field, ticked every GRAB */
-
- int vidInterlace; /* calculated */
- int vidXshift; /* calculated */
- uint vidWidth; /* calculated */
- uint vidHeight; /* calculated */
-};
-
-#define zrwrite(dat,adr) writel((dat),(char *) (ztv->zoran_mem+(adr)))
-#define zrread(adr) readl(ztv->zoran_mem+(adr))
-
-#if PDEBUG == 0
-#define zrand(dat,adr) zrwrite((dat) & zrread(adr), adr)
-#define zror(dat,adr) zrwrite((dat) | zrread(adr), adr)
-#define zraor(dat,mask,adr) zrwrite( ((dat)&~(mask)) | ((mask)&zrread(adr)), adr)
-#else
-#define zrand(dat, adr) \
-do { \
- ulong data = (dat) & zrread((adr)); \
- zrwrite(data, (adr)); \
- if (0 != (~(dat) & zrread((adr)))) \
- printk(KERN_DEBUG "zoran: zrand at %d(%d) detected set bits(%x)\n", __LINE__, (adr), (dat)); \
-} while(0)
-
-#define zror(dat, adr) \
-do { \
- ulong data = (dat) | zrread((adr)); \
- zrwrite(data, (adr)); \
- if ((dat) != ((dat) & zrread(adr))) \
- printk(KERN_DEBUG "zoran: zror at %d(%d) detected unset bits(%x)\n", __LINE__, (adr), (dat)); \
-} while(0)
-
-#define zraor(dat, mask, adr) \
-do { \
- ulong data; \
- if ((dat) & (mask)) \
- printk(KERN_DEBUG "zoran: zraor at %d(%d) detected bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \
- data = ((dat)&~(mask)) | ((mask) & zrread((adr))); \
- zrwrite(data,(adr)); \
- if ( (dat) != (~(mask) & zrread((adr))) ) \
- printk(KERN_DEBUG "zoran: zraor at %d(%d) could not set all bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \
-} while(0)
-#endif
-
-#endif
-
-/* zoran PCI address space */
-#define ZORAN_VFEH 0x000 /* Video Front End Horizontal Conf. */
-#define ZORAN_VFEH_HSPOL (1<<30)
-#define ZORAN_VFEH_HSTART (0x3FF<<10)
-#define ZORAN_VFEH_HEND (0x3FF<<0)
-
-#define ZORAN_VFEV 0x004 /* Video Front End Vertical Conf. */
-#define ZORAN_VFEV_VSPOL (1<<30)
-#define ZORAN_VFEV_VSTART (0x3FF<<10)
-#define ZORAN_VFEV_VEND (0x3FF<<0)
-
-#define ZORAN_VFEC 0x008 /* Video Front End Scaler and Pixel */
-#define ZORAN_VFEC_EXTFL (1<<26)
-#define ZORAN_VFEC_TOPFIELD (1<<25)
-#define ZORAN_VFEC_VCLKPOL (1<<24)
-#define ZORAN_VFEC_HFILTER (7<<21)
-#define ZORAN_VFEC_HFILTER_1 (0<<21) /* no lumi, 3-tap chromo */
-#define ZORAN_VFEC_HFILTER_2 (1<<21) /* 3-tap lumi, 3-tap chromo */
-#define ZORAN_VFEC_HFILTER_3 (2<<21) /* 4-tap lumi, 4-tap chromo */
-#define ZORAN_VFEC_HFILTER_4 (3<<21) /* 5-tap lumi, 4-tap chromo */
-#define ZORAN_VFEC_HFILTER_5 (4<<21) /* 4-tap lumi, 4-tap chromo */
-#define ZORAN_VFEC_DUPFLD (1<<20)
-#define ZORAN_VFEC_HORDCM (63<<14)
-#define ZORAN_VFEC_VERDCM (63<<8)
-#define ZORAN_VFEC_DISPMOD (1<<6)
-#define ZORAN_VFEC_RGB (3<<3)
-#define ZORAN_VFEC_RGB_YUV422 (0<<3)
-#define ZORAN_VFEC_RGB_RGB888 (1<<3)
-#define ZORAN_VFEC_RGB_RGB565 (2<<3)
-#define ZORAN_VFEC_RGB_RGB555 (3<<3)
-#define ZORAN_VFEC_ERRDIF (1<<2)
-#define ZORAN_VFEC_PACK24 (1<<1)
-#define ZORAN_VFEC_LE (1<<0)
-
-#define ZORAN_VTOP 0x00C /* Video Display "Top" */
-
-#define ZORAN_VBOT 0x010 /* Video Display "Bottom" */
-
-#define ZORAN_VSTR 0x014 /* Video Display Stride */
-#define ZORAN_VSTR_DISPSTRIDE (0xFFFF<<16)
-#define ZORAN_VSTR_VIDOVF (1<<8)
-#define ZORAN_VSTR_SNAPSHOT (1<<1)
-#define ZORAN_VSTR_GRAB (1<<0)
-
-#define ZORAN_VDC 0x018 /* Video Display Conf. */
-#define ZORAN_VDC_VIDEN (1<<31)
-#define ZORAN_VDC_MINPIX (0x1F<<25)
-#define ZORAN_VDC_TRICOM (1<<24)
-#define ZORAN_VDC_VIDWINHT (0x3FF<<12)
-#define ZORAN_VDC_VIDWINWID (0x3FF<<0)
-
-#define ZORAN_MTOP 0x01C /* Masking Map "Top" */
-
-#define ZORAN_MBOT 0x020 /* Masking Map "Bottom" */
-
-#define ZORAN_OCR 0x024 /* Overlay Control */
-#define ZORAN_OCR_OVLEN (1<<15)
-#define ZORAN_OCR_MASKSTRIDE (0xFF<<0)
-
-#define ZORAN_PCI 0x028 /* System, PCI and GPP Control */
-#define ZORAN_PCI_SOFTRESET (1<<24)
-#define ZORAN_PCI_WAITSTATE (3<<16)
-#define ZORAN_PCI_GENPURDIR (0xFF<<0)
-
-#define ZORAN_GUEST 0x02C /* GuestBus Control */
-
-#define ZORAN_CSOURCE 0x030 /* Code Source Address */
-
-#define ZORAN_CTRANS 0x034 /* Code Transfer Control */
-
-#define ZORAN_CMEM 0x038 /* Code Memory Pointer */
-
-#define ZORAN_ISR 0x03C /* Interrupt Status Register */
-#define ZORAN_ISR_CODE (1<<28)
-#define ZORAN_ISR_GIRQ0 (1<<29)
-#define ZORAN_ISR_GIRQ1 (1<<30)
-
-#define ZORAN_ICR 0x040 /* Interrupt Control Register */
-#define ZORAN_ICR_EN (1<<24)
-#define ZORAN_ICR_CODE (1<<28)
-#define ZORAN_ICR_GIRQ0 (1<<29)
-#define ZORAN_ICR_GIRQ1 (1<<30)
-
-#define ZORAN_I2C 0x044 /* I2C-Bus */
-#define ZORAN_I2C_SCL (1<<1)
-#define ZORAN_I2C_SDA (1<<0)
-
-#define ZORAN_POST 0x48 /* PostOffice */
-#define ZORAN_POST_PEN (1<<25)
-#define ZORAN_POST_TIME (1<<24)
-#define ZORAN_POST_DIR (1<<23)
-#define ZORAN_POST_GUESTID (3<<20)
-#define ZORAN_POST_GUEST (7<<16)
-#define ZORAN_POST_DATA (0xFF<<0)
-
-#endif
diff --git a/drivers/media/video/zr36120_i2c.c b/drivers/media/video/zr36120_i2c.c
deleted file mode 100644
index 21fde43a6ae..00000000000
--- a/drivers/media/video/zr36120_i2c.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- zr36120_i2c.c - Zoran 36120/36125 based framegrabbers
-
- Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.nl>
-
- This program is free software; you can redistribute it and/or modify
- 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/types.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-
-#include <linux/video_decoder.h>
-#include <asm/uaccess.h>
-
-#include "tuner.h"
-#include "zr36120.h"
-
-/* ----------------------------------------------------------------------- */
-/* I2C functions */
-/* ----------------------------------------------------------------------- */
-
-/* software I2C functions */
-
-#define I2C_DELAY 10
-
-static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data)
-{
- struct zoran *ztv = (struct zoran*)bus->data;
- unsigned int b = 0;
- if (data) b |= ztv->card->swapi2c ? ZORAN_I2C_SCL : ZORAN_I2C_SDA;
- if (ctrl) b |= ztv->card->swapi2c ? ZORAN_I2C_SDA : ZORAN_I2C_SCL;
- zrwrite(b, ZORAN_I2C);
- udelay(I2C_DELAY);
-}
-
-static int i2c_getdataline(struct i2c_bus *bus)
-{
- struct zoran *ztv = (struct zoran*)bus->data;
- if (ztv->card->swapi2c)
- return zrread(ZORAN_I2C) & ZORAN_I2C_SCL;
- return zrread(ZORAN_I2C) & ZORAN_I2C_SDA;
-}
-
-static
-void attach_inform(struct i2c_bus *bus, int id)
-{
- struct zoran *ztv = (struct zoran*)bus->data;
- struct video_decoder_capability dc;
- int rv;
-
- switch (id) {
- case I2C_DRIVERID_VIDEODECODER:
- DEBUG(printk(CARD_INFO "decoder attached\n",CARD));
-
- /* fetch the capabilities of the decoder */
- rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc);
- if (rv) {
- DEBUG(printk(CARD_DEBUG "decoder is not V4L aware!\n",CARD));
- break;
- }
- DEBUG(printk(CARD_DEBUG "capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs));
-
- /* Test if the decoder can de VBI transfers */
- if (dc.flags & 16 /*VIDEO_DECODER_VBI*/)
- ztv->have_decoder = 2;
- else
- ztv->have_decoder = 1;
- break;
- case I2C_DRIVERID_TUNER:
- ztv->have_tuner = 1;
- DEBUG(printk(CARD_INFO "tuner attached\n",CARD));
- if (ztv->tuner_type >= 0)
- {
- if (i2c_control_device(&ztv->i2c,I2C_DRIVERID_TUNER,TUNER_SET_TYPE,&ztv->tuner_type)<0)
- DEBUG(printk(CARD_INFO "attach_inform; tuner won't be set to type %d\n",CARD,ztv->tuner_type));
- }
- break;
- default:
- DEBUG(printk(CARD_INFO "attach_inform; unknown device id=%d\n",CARD,id));
- break;
- }
-}
-
-static
-void detach_inform(struct i2c_bus *bus, int id)
-{
- struct zoran *ztv = (struct zoran*)bus->data;
-
- switch (id) {
- case I2C_DRIVERID_VIDEODECODER:
- ztv->have_decoder = 0;
- DEBUG(printk(CARD_INFO "decoder detached\n",CARD));
- break;
- case I2C_DRIVERID_TUNER:
- ztv->have_tuner = 0;
- DEBUG(printk(CARD_INFO "tuner detached\n",CARD));
- break;
- default:
- DEBUG(printk(CARD_INFO "detach_inform; unknown device id=%d\n",CARD,id));
- break;
- }
-}
-
-struct i2c_bus zoran_i2c_bus_template =
-{
- "ZR36120",
- I2C_BUSID_ZORAN,
- NULL,
-
- SPIN_LOCK_UNLOCKED,
-
- attach_inform,
- detach_inform,
-
- i2c_setlines,
- i2c_getdataline,
- NULL,
- NULL
-};
diff --git a/drivers/media/video/zr36120_mem.c b/drivers/media/video/zr36120_mem.c
deleted file mode 100644
index 416eaa93b8a..00000000000
--- a/drivers/media/video/zr36120_mem.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- zr36120_mem.c - Zoran 36120/36125 based framegrabbers
-
- Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.nl>
-
- This program is free software; you can redistribute it and/or modify
- 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/mm.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <asm/io.h>
-#ifdef CONFIG_BIGPHYS_AREA
-#include <linux/bigphysarea.h>
-#endif
-
-#include "zr36120.h"
-#include "zr36120_mem.h"
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-void* bmalloc(unsigned long size)
-{
- void* mem;
-#ifdef CONFIG_BIGPHYS_AREA
- mem = bigphysarea_alloc_pages(size/PAGE_SIZE, 1, GFP_KERNEL);
-#else
- /*
- * The following function got a lot of memory at boottime,
- * so we know its always there...
- */
- mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,get_order(size));
-#endif
- if (mem) {
- unsigned long adr = (unsigned long)mem;
- while (size > 0) {
- SetPageReserved(virt_to_page(phys_to_virt(adr)));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- }
- return mem;
-}
-
-void bfree(void* mem, unsigned long size)
-{
- if (mem) {
- unsigned long adr = (unsigned long)mem;
- unsigned long siz = size;
- while (siz > 0) {
- ClearPageReserved(virt_to_page(phys_to_virt(adr)));
- adr += PAGE_SIZE;
- siz -= PAGE_SIZE;
- }
-#ifdef CONFIG_BIGPHYS_AREA
- bigphysarea_free_pages(mem);
-#else
- free_pages((unsigned long)mem,get_order(size));
-#endif
- }
-}
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/zr36120_mem.h b/drivers/media/video/zr36120_mem.h
deleted file mode 100644
index aad117acc91..00000000000
--- a/drivers/media/video/zr36120_mem.h
+++ /dev/null
@@ -1,3 +0,0 @@
-/* either kmalloc() or bigphysarea() alloced memory - continuous */
-void* bmalloc(unsigned long size);
-void bfree(void* mem, unsigned long size);
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 6e068cf1049..b3f28a03b6a 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -5,7 +5,7 @@
* For use with LSI Logic PCI chip/adapter(s)
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2005 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Logic Corporation
* (mailto:mpt_linux_developer@lsil.com)
*
*/
@@ -73,6 +73,7 @@
MODULE_AUTHOR(MODULEAUTHOR);
MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
+MODULE_VERSION(my_VERSION);
/*
* cmd line parameters
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index a4afad4ecab..e316708f76b 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -5,7 +5,7 @@
* LSIFC9xx/LSI409xx Fibre Channel
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2005 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Logic Corporation
* (mailto:mpt_linux_developer@lsil.com)
*
*/
@@ -72,11 +72,11 @@
#endif
#ifndef COPYRIGHT
-#define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR
+#define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.02"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.02"
+#define MPT_LINUX_VERSION_COMMON "3.04.03"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.03"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
@@ -1059,7 +1059,7 @@ extern int mpt_stm_index; /* needed by mptstm.c */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#endif /* } __KERNEL__ */
-#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__)
+#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__) || defined(__powerpc__)
#define CAST_U32_TO_PTR(x) ((void *)(u64)x)
#define CAST_PTR_TO_U32(x) ((u32)(u64)x)
#else
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 30975ccd994..504632da434 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -4,7 +4,7 @@
* For use with LSI Logic PCI chip/adapters
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2005 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Logic Corporation
* (mailto:mpt_linux_developer@lsil.com)
*
*/
@@ -66,7 +66,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
-#define COPYRIGHT "Copyright (c) 1999-2005 LSI Logic Corporation"
+#define COPYRIGHT "Copyright (c) 1999-2007 LSI Logic Corporation"
#define MODULEAUTHOR "LSI Logic Corporation"
#include "mptbase.h"
#include "mptctl.h"
@@ -79,6 +79,7 @@
MODULE_AUTHOR(MODULEAUTHOR);
MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
+MODULE_VERSION(my_VERSION);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
index 043941882c6..e65a1cf5eb0 100644
--- a/drivers/message/fusion/mptctl.h
+++ b/drivers/message/fusion/mptctl.h
@@ -5,7 +5,7 @@
* LSIFC9xx/LSI409xx Fibre Channel
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2005 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Logic Corporation
* (mailto:mpt_linux_developer@lsil.com)
*
*/
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index ca2f9107f14..c819c23b55b 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -3,7 +3,7 @@
* For use with LSI Logic PCI chip/adapter(s)
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2005 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Logic Corporation
* (mailto:mpt_linux_developer@lsil.com)
*
*/
@@ -75,6 +75,7 @@
MODULE_AUTHOR(MODULEAUTHOR);
MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
+MODULE_VERSION(my_VERSION);
/* Command line args */
#define MPTFC_DEV_LOSS_TMO (60)
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index b7c4407c5e3..2936204d8ad 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -4,7 +4,7 @@
* For use with LSI Logic Fibre Channel PCI chip/adapters
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 2000-2005 LSI Logic Corporation
+ * Copyright (c) 2000-2007 LSI Logic Corporation
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -56,9 +56,11 @@
#include <linux/module.h>
#include <linux/fs.h>
+#define my_VERSION MPT_LINUX_VERSION_COMMON
#define MYNAM "mptlan"
MODULE_LICENSE("GPL");
+MODULE_VERSION(my_VERSION);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h
index 3726ecba570..70ab75e7c26 100644
--- a/drivers/message/fusion/mptlan.h
+++ b/drivers/message/fusion/mptlan.h
@@ -4,7 +4,7 @@
* For use with LSI Logic Fibre Channel PCI chip/adapters
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 2000-2005 LSI Logic Corporation
+ * Copyright (c) 2000-2007 LSI Logic Corporation
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 4f0c530e47b..09e9a9d9641 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -3,9 +3,9 @@
* For use with LSI Logic PCI chip/adapter(s)
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2005 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Logic Corporation
* (mailto:mpt_linux_developer@lsil.com)
- * Copyright (c) 2005-2006 Dell
+ * Copyright (c) 2005-2007 Dell
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
@@ -75,6 +75,7 @@
MODULE_AUTHOR(MODULEAUTHOR);
MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
+MODULE_VERSION(my_VERSION);
static int mpt_pt_clear;
module_param(mpt_pt_clear, int, 0);
@@ -245,7 +246,8 @@ static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
- printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address));
+ printk("SAS Address=0x%llX\n", (unsigned long long)
+ le64_to_cpu(sas_address));
printk("Target ID=0x%X\n", pg0->TargetID);
printk("Bus=0x%X\n", pg0->Bus);
/* The PhyNum field specifies the PHY number of the parent
@@ -349,9 +351,9 @@ mptsas_port_delete(struct mptsas_portinfo_details * port_details)
phy_info = port_info->phy_info;
dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d "
- "bitmask=0x%016llX\n",
- __FUNCTION__, port_details, port_details->num_phys,
- port_details->phy_bitmask));
+ "bitmask=0x%016llX\n", __FUNCTION__, port_details,
+ port_details->num_phys, (unsigned long long)
+ port_details->phy_bitmask));
for (i = 0; i < port_info->num_phys; i++, phy_info++) {
if(phy_info->port_details != port_details)
@@ -476,7 +478,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
sas_address = phy_info->attached.sas_address;
dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
- i, sas_address));
+ i, (unsigned long long)sas_address));
if (!sas_address)
continue;
port_details = phy_info->port_details;
@@ -495,8 +497,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
(1 << phy_info->phy_id);
phy_info->sas_port_add_phy=1;
dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t"
- "phy_id=%d sas_address=0x%018llX\n",
- i, sas_address));
+ "phy_id=%d sas_address=0x%018llX\n",
+ i, (unsigned long long)sas_address));
phy_info->port_details = port_details;
}
@@ -512,8 +514,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
if (phy_info_cmp->port_details == port_details )
continue;
dsaswideprintk((KERN_DEBUG
- "\t\tphy_id=%d sas_address=0x%018llX\n",
- j, phy_info_cmp->attached.sas_address));
+ "\t\tphy_id=%d sas_address=0x%018llX\n",
+ j, (unsigned long long)
+ phy_info_cmp->attached.sas_address));
if (phy_info_cmp->port_details) {
port_details->rphy =
mptsas_get_rphy(phy_info_cmp);
@@ -546,11 +549,10 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
if (!port_details)
continue;
dsaswideprintk((KERN_DEBUG
- "%s: [%p]: phy_id=%02d num_phys=%02d "
- "bitmask=0x%016llX\n",
- __FUNCTION__,
- port_details, i, port_details->num_phys,
- port_details->phy_bitmask));
+ "%s: [%p]: phy_id=%02d num_phys=%02d "
+ "bitmask=0x%016llX\n", __FUNCTION__,
+ port_details, i, port_details->num_phys,
+ (unsigned long long)port_details->phy_bitmask));
dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n",
port_details->port, port_details->rphy));
}
@@ -2079,8 +2081,10 @@ mptsas_persist_clear_table(struct work_struct *work)
static void
mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
{
+ int rc;
+
sdev->no_uld_attach = data ? 1 : 0;
- scsi_device_reprobe(sdev);
+ rc = scsi_device_reprobe(sdev);
}
static void
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 2c72c36b817..f0cca3ea93b 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -3,7 +3,7 @@
* For use with LSI Logic PCI chip/adapter(s)
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2005 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Logic Corporation
* (mailto:mpt_linux_developer@lsil.com)
*
*/
@@ -76,6 +76,7 @@
MODULE_AUTHOR(MODULEAUTHOR);
MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
+MODULE_VERSION(my_VERSION);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -701,6 +702,17 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
break;
}
}
+ } else if (ioc->bus_type == FC) {
+ /*
+ * The FC IOC may kill a request for variety of
+ * reasons, some of which may be recovered by a
+ * retry, some which are unlikely to be
+ * recovered. Return DID_ERROR instead of
+ * DID_RESET to permit retry of the command,
+ * just not an infinite number of them
+ */
+ sc->result = DID_ERROR << 16;
+ break;
}
/*
@@ -2688,7 +2700,8 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
struct scsi_device *sdev)
{
dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
- hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
+ hd->ioc->name, vtarget->bus_id, vtarget->target_id,
+ sdev->lun, hd));
/* Is LUN supported? If so, upper 2 bits will be 0
* in first byte of inquiry data.
@@ -2770,7 +2783,7 @@ mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
else {
factor = MPT_ULTRA320;
if (scsi_device_qas(sdev)) {
- ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
+ ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
noQas = 0;
}
if (sdev->type == TYPE_TAPE &&
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index 14a5b6c2e2b..187c8af0890 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -5,7 +5,7 @@
* LSIFC9xx/LSI409xx Fibre Channel
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2005 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Logic Corporation
* (mailto:mpt_linux_developer@lsil.com)
*
*/
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 36641da5928..203c661d2c7 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -3,7 +3,7 @@
* For use with LSI Logic PCI chip/adapter(s)
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2005 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Logic Corporation
* (mailto:mpt_linux_developer@lsil.com)
*
*/
@@ -77,6 +77,7 @@
MODULE_AUTHOR(MODULEAUTHOR);
MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
+MODULE_VERSION(my_VERSION);
/* Command line args */
static int mpt_saf_te = MPTSCSIH_SAF_TE;
diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h
index dc388a3ff5e..cbe384fb848 100644
--- a/drivers/message/i2o/core.h
+++ b/drivers/message/i2o/core.h
@@ -18,7 +18,7 @@ extern struct i2o_driver i2o_exec_driver;
extern int i2o_exec_lct_get(struct i2o_controller *);
extern int __init i2o_exec_init(void);
-extern void __exit i2o_exec_exit(void);
+extern void i2o_exec_exit(void);
/* driver */
extern struct bus_type i2o_bus_type;
@@ -26,7 +26,7 @@ extern struct bus_type i2o_bus_type;
extern int i2o_driver_dispatch(struct i2o_controller *, u32);
extern int __init i2o_driver_init(void);
-extern void __exit i2o_driver_exit(void);
+extern void i2o_driver_exit(void);
/* PCI */
extern int __init i2o_pci_init(void);
diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c
index 9104b65ff70..d3235f213c8 100644
--- a/drivers/message/i2o/driver.c
+++ b/drivers/message/i2o/driver.c
@@ -362,7 +362,7 @@ int __init i2o_driver_init(void)
*
* Unregisters the I2O bus and frees driver array.
*/
-void __exit i2o_driver_exit(void)
+void i2o_driver_exit(void)
{
bus_unregister(&i2o_bus_type);
kfree(i2o_drivers);
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
index 902753b2c66..5278aad92bc 100644
--- a/drivers/message/i2o/exec-osm.c
+++ b/drivers/message/i2o/exec-osm.c
@@ -367,7 +367,7 @@ static int i2o_exec_remove(struct device *dev)
/**
* i2o_exec_lct_modified - Called on LCT NOTIFY reply
- * @work: work struct for a specific controller
+ * @_work: work struct for a specific controller
*
* This function handles asynchronus LCT NOTIFY replies. It parses the
* new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY
@@ -595,7 +595,7 @@ int __init i2o_exec_init(void)
*
* Unregisters the Exec OSM from the I2O core.
*/
-void __exit i2o_exec_exit(void)
+void i2o_exec_exit(void)
{
i2o_driver_unregister(&i2o_exec_driver);
};
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index 1de30d71167..e33d446e749 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -186,7 +186,7 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type)
if (!dev)
return -ENXIO;
- ops = (u8 *) kmalloc(kcmd.oplen, GFP_KERNEL);
+ ops = kmalloc(kcmd.oplen, GFP_KERNEL);
if (!ops)
return -ENOMEM;
@@ -199,7 +199,7 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type)
* It's possible to have a _very_ large table
* and that the user asks for all of it at once...
*/
- res = (u8 *) kmalloc(65536, GFP_KERNEL);
+ res = kmalloc(65536, GFP_KERNEL);
if (!res) {
kfree(ops);
return -ENOMEM;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 00db31c314e..bedae4ad3f7 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -42,7 +42,7 @@ config SGI_IOC4
config TIFM_CORE
tristate "TI Flash Media interface support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ depends on EXPERIMENTAL && PCI
help
If you want support for Texas Instruments(R) Flash Media adapters
you should select this option and then also choose an appropriate
@@ -69,6 +69,25 @@ config TIFM_7XX1
To compile this driver as a module, choose M here: the module will
be called tifm_7xx1.
+config ASUS_LAPTOP
+ tristate "Asus Laptop Extras (EXPERIMENTAL)"
+ depends on X86
+ depends on ACPI
+ depends on EXPERIMENTAL && !ACPI_ASUS
+ depends on LEDS_CLASS
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This is the new Linux driver for Asus laptops. It may also support some
+ MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
+ standard ACPI events that go through /proc/acpi/events. It also adds
+ support for video output switching, LCD backlight control, Bluetooth and
+ Wlan control, and most importantly, allows you to blink those fancy LEDs.
+
+ For more information and a userspace daemon for handling the extra
+ buttons see <http://acpi4asus.sf.net/>.
+
+ If you have an ACPI-compatible ASUS laptop, say Y or M here.
+
config MSI_LAPTOP
tristate "MSI Laptop Extras"
depends on X86
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c9e98ab021c..35da53c409c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -6,6 +6,7 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
+obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
new file mode 100644
index 00000000000..861c39935f9
--- /dev/null
+++ b/drivers/misc/asus-laptop.c
@@ -0,0 +1,1165 @@
+/*
+ * asus-laptop.c - Asus Laptop Support
+ *
+ *
+ * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
+ * Copyright (C) 2006 Corentin Chary
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * The development page for this driver is located at
+ * http://sourceforge.net/projects/acpi4asus/
+ *
+ * Credits:
+ * Pontus Fuchs - Helper functions, cleanup
+ * Johann Wiesner - Small compile fixes
+ * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
+ * Eric Burghard - LED display support for W1N
+ * Josh Green - Light Sens support
+ * Thomas Tuttle - His first patch for led support was very helpfull
+ *
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/proc_fs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <asm/uaccess.h>
+
+#define ASUS_LAPTOP_VERSION "0.40"
+
+#define ASUS_HOTK_NAME "Asus Laptop Support"
+#define ASUS_HOTK_CLASS "hotkey"
+#define ASUS_HOTK_DEVICE_NAME "Hotkey"
+#define ASUS_HOTK_HID "ATK0100"
+#define ASUS_HOTK_FILE "asus-laptop"
+#define ASUS_HOTK_PREFIX "\\_SB.ATKD."
+
+/*
+ * Some events we use, same for all Asus
+ */
+#define ATKD_BR_UP 0x10
+#define ATKD_BR_DOWN 0x20
+#define ATKD_LCD_ON 0x33
+#define ATKD_LCD_OFF 0x34
+
+/*
+ * Known bits returned by \_SB.ATKD.HWRS
+ */
+#define WL_HWRS 0x80
+#define BT_HWRS 0x100
+
+/*
+ * Flags for hotk status
+ * WL_ON and BT_ON are also used for wireless_status()
+ */
+#define WL_ON 0x01 //internal Wifi
+#define BT_ON 0x02 //internal Bluetooth
+#define MLED_ON 0x04 //mail LED
+#define TLED_ON 0x08 //touchpad LED
+#define RLED_ON 0x10 //Record LED
+#define PLED_ON 0x20 //Phone LED
+#define LCD_ON 0x40 //LCD backlight
+
+#define ASUS_LOG ASUS_HOTK_FILE ": "
+#define ASUS_ERR KERN_ERR ASUS_LOG
+#define ASUS_WARNING KERN_WARNING ASUS_LOG
+#define ASUS_NOTICE KERN_NOTICE ASUS_LOG
+#define ASUS_INFO KERN_INFO ASUS_LOG
+#define ASUS_DEBUG KERN_DEBUG ASUS_LOG
+
+MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
+MODULE_DESCRIPTION(ASUS_HOTK_NAME);
+MODULE_LICENSE("GPL");
+
+#define ASUS_HANDLE(object, paths...) \
+ static acpi_handle object##_handle = NULL; \
+ static char *object##_paths[] = { paths }
+
+/* LED */
+ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED");
+ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");
+ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */
+ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */
+
+/* LEDD */
+ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
+
+/* Bluetooth and WLAN
+ * WLED and BLED are not handled like other XLED, because in some dsdt
+ * they also control the WLAN/Bluetooth device.
+ */
+ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED");
+ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED");
+ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS"); /* All new models */
+
+/* Brightness */
+ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV");
+ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV");
+
+/* Backlight */
+ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
+ "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */
+ "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
+ "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
+ "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
+ "\\_SB.PCI0.PX40.Q10", /* S1x */
+ "\\Q10"); /* A2x, L2D, L3D, M2E */
+
+/* Display */
+ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
+ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G
+ M6A M6V VX-1 V6J V6V W3Z */
+ "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V
+ S5A M5A z33A W1Jc W2V */
+ "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */
+ "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */
+ "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */
+ "\\_SB.PCI0.VGA.GETD", /* Z96F */
+ "\\ACTD", /* A2D */
+ "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
+ "\\DNXT", /* P30 */
+ "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
+ "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */
+
+ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */
+ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */
+
+/*
+ * This is the main structure, we can use it to store anything interesting
+ * about the hotk device
+ */
+struct asus_hotk {
+ char *name; //laptop name
+ struct acpi_device *device; //the device we are in
+ acpi_handle handle; //the handle of the hotk device
+ char status; //status of the hotk, for LEDs, ...
+ u32 ledd_status; //status of the LED display
+ u8 light_level; //light sensor level
+ u8 light_switch; //light sensor switch value
+ u16 event_count[128]; //count for each event TODO make this better
+};
+
+/*
+ * This header is made available to allow proper configuration given model,
+ * revision number , ... this info cannot go in struct asus_hotk because it is
+ * available before the hotk
+ */
+static struct acpi_table_header *asus_info;
+
+/* The actual device the driver binds to */
+static struct asus_hotk *hotk;
+
+/*
+ * The hotkey driver declaration
+ */
+static int asus_hotk_add(struct acpi_device *device);
+static int asus_hotk_remove(struct acpi_device *device, int type);
+static struct acpi_driver asus_hotk_driver = {
+ .name = ASUS_HOTK_NAME,
+ .class = ASUS_HOTK_CLASS,
+ .ids = ASUS_HOTK_HID,
+ .ops = {
+ .add = asus_hotk_add,
+ .remove = asus_hotk_remove,
+ },
+};
+
+/* The backlight device /sys/class/backlight */
+static struct backlight_device *asus_backlight_device;
+
+/*
+ * The backlight class declaration
+ */
+static int read_brightness(struct backlight_device *bd);
+static int update_bl_status(struct backlight_device *bd);
+static struct backlight_properties asusbl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = read_brightness,
+ .update_status = update_bl_status,
+ .max_brightness = 15,
+};
+
+/* These functions actually update the LED's, and are called from a
+ * workqueue. By doing this as separate work rather than when the LED
+ * subsystem asks, we avoid messing with the Asus ACPI stuff during a
+ * potentially bad time, such as a timer interrupt. */
+static struct workqueue_struct *led_workqueue;
+
+#define ASUS_LED(object, ledname) \
+ static void object##_led_set(struct led_classdev *led_cdev, \
+ enum led_brightness value); \
+ static void object##_led_update(struct work_struct *ignored); \
+ static int object##_led_wk; \
+ DECLARE_WORK(object##_led_work, object##_led_update); \
+ static struct led_classdev object##_led = { \
+ .name = "asus:" ledname, \
+ .brightness_set = object##_led_set, \
+ }
+
+ASUS_LED(mled, "mail");
+ASUS_LED(tled, "touchpad");
+ASUS_LED(rled, "record");
+ASUS_LED(pled, "phone");
+
+/*
+ * This function evaluates an ACPI method, given an int as parameter, the
+ * method is searched within the scope of the handle, can be NULL. The output
+ * of the method is written is output, which can also be NULL
+ *
+ * returns 1 if write is successful, 0 else.
+ */
+static int write_acpi_int(acpi_handle handle, const char *method, int val,
+ struct acpi_buffer *output)
+{
+ struct acpi_object_list params; //list of input parameters (an int here)
+ union acpi_object in_obj; //the only param we use
+ acpi_status status;
+
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = val;
+
+ status = acpi_evaluate_object(handle, (char *)method, &params, output);
+ return (status == AE_OK);
+}
+
+static int read_acpi_int(acpi_handle handle, const char *method, int *val,
+ struct acpi_object_list *params)
+{
+ struct acpi_buffer output;
+ union acpi_object out_obj;
+ acpi_status status;
+
+ output.length = sizeof(out_obj);
+ output.pointer = &out_obj;
+
+ status = acpi_evaluate_object(handle, (char *)method, params, &output);
+ *val = out_obj.integer.value;
+ return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
+}
+
+static int read_wireless_status(int mask)
+{
+ int status;
+
+ if (!wireless_status_handle)
+ return (hotk->status & mask) ? 1 : 0;
+
+ if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) {
+ return (status & mask) ? 1 : 0;
+ } else
+ printk(ASUS_WARNING "Error reading Wireless status\n");
+
+ return (hotk->status & mask) ? 1 : 0;
+}
+
+/* Generic LED functions */
+static int read_status(int mask)
+{
+ /* There is a special method for both wireless devices */
+ if (mask == BT_ON || mask == WL_ON)
+ return read_wireless_status(mask);
+
+ return (hotk->status & mask) ? 1 : 0;
+}
+
+static void write_status(acpi_handle handle, int out, int mask, int invert)
+{
+ hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
+
+ if (invert) /* invert target value */
+ out = !out & 0x1;
+
+ if (handle && !write_acpi_int(handle, NULL, out, NULL))
+ printk(ASUS_WARNING " write failed\n");
+}
+
+/* /sys/class/led handlers */
+#define ASUS_LED_HANDLER(object, mask, invert) \
+ static void object##_led_set(struct led_classdev *led_cdev, \
+ enum led_brightness value) \
+ { \
+ object##_led_wk = value; \
+ queue_work(led_workqueue, &object##_led_work); \
+ } \
+ static void object##_led_update(struct work_struct *ignored) \
+ { \
+ int value = object##_led_wk; \
+ write_status(object##_set_handle, value, (mask), (invert)); \
+ }
+
+ASUS_LED_HANDLER(mled, MLED_ON, 1);
+ASUS_LED_HANDLER(pled, PLED_ON, 0);
+ASUS_LED_HANDLER(rled, RLED_ON, 0);
+ASUS_LED_HANDLER(tled, TLED_ON, 0);
+
+static int get_lcd_state(void)
+{
+ return read_status(LCD_ON);
+}
+
+static int set_lcd_state(int value)
+{
+ int lcd = 0;
+ acpi_status status = 0;
+
+ lcd = value ? 1 : 0;
+
+ if (lcd == get_lcd_state())
+ return 0;
+
+ if (lcd_switch_handle) {
+ status = acpi_evaluate_object(lcd_switch_handle,
+ NULL, NULL, NULL);
+
+ if (ACPI_FAILURE(status))
+ printk(ASUS_WARNING "Error switching LCD\n");
+ }
+
+ write_status(NULL, lcd, LCD_ON, 0);
+ return 0;
+}
+
+static void lcd_blank(int blank)
+{
+ struct backlight_device *bd = asus_backlight_device;
+
+ if (bd) {
+ down(&bd->sem);
+ if (likely(bd->props)) {
+ bd->props->power = blank;
+ if (likely(bd->props->update_status))
+ bd->props->update_status(bd);
+ }
+ up(&bd->sem);
+ }
+}
+
+static int read_brightness(struct backlight_device *bd)
+{
+ int value;
+
+ if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL))
+ printk(ASUS_WARNING "Error reading brightness\n");
+
+ return value;
+}
+
+static int set_brightness(struct backlight_device *bd, int value)
+{
+ int ret = 0;
+
+ value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+ /* 0 <= value <= 15 */
+
+ if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
+ printk(ASUS_WARNING "Error changing brightness\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+ int rv;
+ int value = bd->props->brightness;
+
+ rv = set_brightness(bd, value);
+ if (rv)
+ return rv;
+
+ value = (bd->props->power == FB_BLANK_UNBLANK) ? 1 : 0;
+ return set_lcd_state(value);
+}
+
+/*
+ * Platform device handlers
+ */
+
+/*
+ * We write our info in page, we begin at offset off and cannot write more
+ * than count bytes. We set eof to 1 if we handle those 2 values. We return the
+ * number of bytes written in page
+ */
+static ssize_t show_infos(struct device *dev,
+ struct device_attribute *attr, char *page)
+{
+ int len = 0;
+ int temp;
+ char buf[16]; //enough for all info
+ /*
+ * We use the easy way, we don't care of off and count, so we don't set eof
+ * to 1
+ */
+
+ len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n");
+ len += sprintf(page + len, "Model reference : %s\n", hotk->name);
+ /*
+ * The SFUN method probably allows the original driver to get the list
+ * of features supported by a given model. For now, 0x0100 or 0x0800
+ * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
+ * The significance of others is yet to be found.
+ */
+ if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL))
+ len +=
+ sprintf(page + len, "SFUN value : 0x%04x\n", temp);
+ /*
+ * Another value for userspace: the ASYM method returns 0x02 for
+ * battery low and 0x04 for battery critical, its readings tend to be
+ * more accurate than those provided by _BST.
+ * Note: since not all the laptops provide this method, errors are
+ * silently ignored.
+ */
+ if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL))
+ len +=
+ sprintf(page + len, "ASYM value : 0x%04x\n", temp);
+ if (asus_info) {
+ snprintf(buf, 16, "%d", asus_info->length);
+ len += sprintf(page + len, "DSDT length : %s\n", buf);
+ snprintf(buf, 16, "%d", asus_info->checksum);
+ len += sprintf(page + len, "DSDT checksum : %s\n", buf);
+ snprintf(buf, 16, "%d", asus_info->revision);
+ len += sprintf(page + len, "DSDT revision : %s\n", buf);
+ snprintf(buf, 7, "%s", asus_info->oem_id);
+ len += sprintf(page + len, "OEM id : %s\n", buf);
+ snprintf(buf, 9, "%s", asus_info->oem_table_id);
+ len += sprintf(page + len, "OEM table id : %s\n", buf);
+ snprintf(buf, 16, "%x", asus_info->oem_revision);
+ len += sprintf(page + len, "OEM revision : 0x%s\n", buf);
+ snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
+ len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
+ snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
+ len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf);
+ }
+
+ return len;
+}
+
+static int parse_arg(const char *buf, unsigned long count, int *val)
+{
+ if (!count)
+ return 0;
+ if (count > 31)
+ return -EINVAL;
+ if (sscanf(buf, "%i", val) != 1)
+ return -EINVAL;
+ return count;
+}
+
+static ssize_t store_status(const char *buf, size_t count,
+ acpi_handle handle, int mask, int invert)
+{
+ int rv, value;
+ int out = 0;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ out = value ? 1 : 0;
+
+ write_status(handle, out, mask, invert);
+
+ return rv;
+}
+
+/*
+ * LEDD display
+ */
+static ssize_t show_ledd(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "0x%08x\n", hotk->ledd_status);
+}
+
+static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0) {
+ if (!write_acpi_int(ledd_set_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "LED display write failed\n");
+ else
+ hotk->ledd_status = (u32) value;
+ }
+ return rv;
+}
+
+/*
+ * WLAN
+ */
+static ssize_t show_wlan(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", read_status(WL_ON));
+}
+
+static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return store_status(buf, count, wl_switch_handle, WL_ON, 0);
+}
+
+/*
+ * Bluetooth
+ */
+static ssize_t show_bluetooth(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", read_status(BT_ON));
+}
+
+static ssize_t store_bluetooth(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ return store_status(buf, count, bt_switch_handle, BT_ON, 0);
+}
+
+/*
+ * Display
+ */
+static void set_display(int value)
+{
+ /* no sanity check needed for now */
+ if (!write_acpi_int(display_set_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "Error setting display\n");
+ return;
+}
+
+static int read_display(void)
+{
+ int value = 0;
+
+ /* In most of the case, we know how to set the display, but sometime
+ we can't read it */
+ if (display_get_handle) {
+ if (!read_acpi_int(display_get_handle, NULL, &value, NULL))
+ printk(ASUS_WARNING "Error reading display status\n");
+ }
+
+ value &= 0x0F; /* needed for some models, shouldn't hurt others */
+
+ return value;
+}
+
+/*
+ * Now, *this* one could be more user-friendly, but so far, no-one has
+ * complained. The significance of bits is the same as in store_disp()
+ */
+static ssize_t show_disp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", read_display());
+}
+
+/*
+ * Experimental support for display switching. As of now: 1 should activate
+ * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
+ * Any combination (bitwise) of these will suffice. I never actually tested 4
+ * displays hooked up simultaneously, so be warned. See the acpi4asus README
+ * for more info.
+ */
+static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set_display(value);
+ return rv;
+}
+
+/*
+ * Light Sens
+ */
+static void set_light_sens_switch(int value)
+{
+ if (!write_acpi_int(ls_switch_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "Error setting light sensor switch\n");
+ hotk->light_switch = value;
+}
+
+static ssize_t show_lssw(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", hotk->light_switch);
+}
+
+static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set_light_sens_switch(value ? 1 : 0);
+
+ return rv;
+}
+
+static void set_light_sens_level(int value)
+{
+ if (!write_acpi_int(ls_level_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "Error setting light sensor level\n");
+ hotk->light_level = value;
+}
+
+static ssize_t show_lslvl(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", hotk->light_level);
+}
+
+static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0) {
+ value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+ /* 0 <= value <= 15 */
+ set_light_sens_level(value);
+ }
+
+ return rv;
+}
+
+static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
+{
+ /* TODO Find a better way to handle events count. */
+ if (!hotk)
+ return;
+
+ /*
+ * We need to tell the backlight device when the backlight power is
+ * switched
+ */
+ if (event == ATKD_LCD_ON) {
+ write_status(NULL, 1, LCD_ON, 0);
+ lcd_blank(FB_BLANK_UNBLANK);
+ } else if (event == ATKD_LCD_OFF) {
+ write_status(NULL, 0, LCD_ON, 0);
+ lcd_blank(FB_BLANK_POWERDOWN);
+ }
+
+ acpi_bus_generate_event(hotk->device, event,
+ hotk->event_count[event % 128]++);
+
+ return;
+}
+
+#define ASUS_CREATE_DEVICE_ATTR(_name) \
+ struct device_attribute dev_attr_##_name = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0, \
+ .owner = THIS_MODULE }, \
+ .show = NULL, \
+ .store = NULL, \
+ }
+
+#define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store) \
+ do { \
+ dev_attr_##_name.attr.mode = _mode; \
+ dev_attr_##_name.show = _show; \
+ dev_attr_##_name.store = _store; \
+ } while(0)
+
+static ASUS_CREATE_DEVICE_ATTR(infos);
+static ASUS_CREATE_DEVICE_ATTR(wlan);
+static ASUS_CREATE_DEVICE_ATTR(bluetooth);
+static ASUS_CREATE_DEVICE_ATTR(display);
+static ASUS_CREATE_DEVICE_ATTR(ledd);
+static ASUS_CREATE_DEVICE_ATTR(ls_switch);
+static ASUS_CREATE_DEVICE_ATTR(ls_level);
+
+static struct attribute *asuspf_attributes[] = {
+ &dev_attr_infos.attr,
+ &dev_attr_wlan.attr,
+ &dev_attr_bluetooth.attr,
+ &dev_attr_display.attr,
+ &dev_attr_ledd.attr,
+ &dev_attr_ls_switch.attr,
+ &dev_attr_ls_level.attr,
+ NULL
+};
+
+static struct attribute_group asuspf_attribute_group = {
+ .attrs = asuspf_attributes
+};
+
+static struct platform_driver asuspf_driver = {
+ .driver = {
+ .name = ASUS_HOTK_FILE,
+ .owner = THIS_MODULE,
+ }
+};
+
+static struct platform_device *asuspf_device;
+
+static void asus_hotk_add_fs(void)
+{
+ ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL);
+
+ if (wl_switch_handle)
+ ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan);
+
+ if (bt_switch_handle)
+ ASUS_SET_DEVICE_ATTR(bluetooth, 0644,
+ show_bluetooth, store_bluetooth);
+
+ if (display_set_handle && display_get_handle)
+ ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp);
+ else if (display_set_handle)
+ ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp);
+
+ if (ledd_set_handle)
+ ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd);
+
+ if (ls_switch_handle && ls_level_handle) {
+ ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl);
+ ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw);
+ }
+}
+
+static int asus_handle_init(char *name, acpi_handle * handle,
+ char **paths, int num_paths)
+{
+ int i;
+ acpi_status status;
+
+ for (i = 0; i < num_paths; i++) {
+ status = acpi_get_handle(NULL, paths[i], handle);
+ if (ACPI_SUCCESS(status))
+ return 0;
+ }
+
+ *handle = NULL;
+ return -ENODEV;
+}
+
+#define ASUS_HANDLE_INIT(object) \
+ asus_handle_init(#object, &object##_handle, object##_paths, \
+ ARRAY_SIZE(object##_paths))
+
+/*
+ * This function is used to initialize the hotk with right values. In this
+ * method, we can make all the detection we want, and modify the hotk struct
+ */
+static int asus_hotk_get_info(void)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *model = NULL;
+ int bsts_result, hwrs_result;
+ char *string = NULL;
+ acpi_status status;
+
+ /*
+ * Get DSDT headers early enough to allow for differentiating between
+ * models, but late enough to allow acpi_bus_register_driver() to fail
+ * before doing anything ACPI-specific. Should we encounter a machine,
+ * which needs special handling (i.e. its hotkey device has a different
+ * HID), this bit will be moved. A global variable asus_info contains
+ * the DSDT header.
+ */
+ status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
+ if (ACPI_FAILURE(status))
+ printk(ASUS_WARNING "Couldn't get the DSDT table header\n");
+
+ /* We have to write 0 on init this far for all ASUS models */
+ if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
+ printk(ASUS_ERR "Hotkey initialization failed\n");
+ return -ENODEV;
+ }
+
+ /* This needs to be called for some laptops to init properly */
+ if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL))
+ printk(ASUS_WARNING "Error calling BSTS\n");
+ else if (bsts_result)
+ printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n",
+ bsts_result);
+
+ /*
+ * Try to match the object returned by INIT to the specific model.
+ * Handle every possible object (or the lack of thereof) the DSDT
+ * writers might throw at us. When in trouble, we pass NULL to
+ * asus_model_match() and try something completely different.
+ */
+ if (buffer.pointer) {
+ model = buffer.pointer;
+ switch (model->type) {
+ case ACPI_TYPE_STRING:
+ string = model->string.pointer;
+ break;
+ case ACPI_TYPE_BUFFER:
+ string = model->buffer.pointer;
+ break;
+ default:
+ string = "";
+ break;
+ }
+ }
+ hotk->name = kstrdup(string, GFP_KERNEL);
+ if (!hotk->name)
+ return -ENOMEM;
+
+ if (*string)
+ printk(ASUS_NOTICE " %s model detected\n", string);
+
+ ASUS_HANDLE_INIT(mled_set);
+ ASUS_HANDLE_INIT(tled_set);
+ ASUS_HANDLE_INIT(rled_set);
+ ASUS_HANDLE_INIT(pled_set);
+
+ ASUS_HANDLE_INIT(ledd_set);
+
+ /*
+ * The HWRS method return informations about the hardware.
+ * 0x80 bit is for WLAN, 0x100 for Bluetooth.
+ * The significance of others is yet to be found.
+ * If we don't find the method, we assume the device are present.
+ */
+ if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL))
+ hwrs_result = WL_HWRS | BT_HWRS;
+
+ if (hwrs_result & WL_HWRS)
+ ASUS_HANDLE_INIT(wl_switch);
+ if (hwrs_result & BT_HWRS)
+ ASUS_HANDLE_INIT(bt_switch);
+
+ ASUS_HANDLE_INIT(wireless_status);
+
+ ASUS_HANDLE_INIT(brightness_set);
+ ASUS_HANDLE_INIT(brightness_get);
+
+ ASUS_HANDLE_INIT(lcd_switch);
+
+ ASUS_HANDLE_INIT(display_set);
+ ASUS_HANDLE_INIT(display_get);
+
+ /* There is a lot of models with "ALSL", but a few get
+ a real light sens, so we need to check it. */
+ if (ASUS_HANDLE_INIT(ls_switch))
+ ASUS_HANDLE_INIT(ls_level);
+
+ kfree(model);
+
+ return AE_OK;
+}
+
+static int asus_hotk_check(void)
+{
+ int result = 0;
+
+ result = acpi_bus_get_status(hotk->device);
+ if (result)
+ return result;
+
+ if (hotk->device->status.present) {
+ result = asus_hotk_get_info();
+ } else {
+ printk(ASUS_ERR "Hotkey device not present, aborting\n");
+ return -EINVAL;
+ }
+
+ return result;
+}
+
+static int asus_hotk_found;
+
+static int asus_hotk_add(struct acpi_device *device)
+{
+ acpi_status status = AE_OK;
+ int result;
+
+ if (!device)
+ return -EINVAL;
+
+ printk(ASUS_NOTICE "Asus Laptop Support version %s\n",
+ ASUS_LAPTOP_VERSION);
+
+ hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+ if (!hotk)
+ return -ENOMEM;
+ memset(hotk, 0, sizeof(struct asus_hotk));
+
+ hotk->handle = device->handle;
+ strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
+ acpi_driver_data(device) = hotk;
+ hotk->device = device;
+
+ result = asus_hotk_check();
+ if (result)
+ goto end;
+
+ asus_hotk_add_fs();
+
+ /*
+ * We install the handler, it will receive the hotk in parameter, so, we
+ * could add other data to the hotk struct
+ */
+ status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+ asus_hotk_notify, hotk);
+ if (ACPI_FAILURE(status))
+ printk(ASUS_ERR "Error installing notify handler\n");
+
+ asus_hotk_found = 1;
+
+ /* WLED and BLED are on by default */
+ write_status(bt_switch_handle, 1, BT_ON, 0);
+ write_status(wl_switch_handle, 1, WL_ON, 0);
+
+ /* LCD Backlight is on by default */
+ write_status(NULL, 1, LCD_ON, 0);
+
+ /* LED display is off by default */
+ hotk->ledd_status = 0xFFF;
+
+ /* Set initial values of light sensor and level */
+ hotk->light_switch = 1; /* Default to light sensor disabled */
+ hotk->light_level = 0; /* level 5 for sensor sensitivity */
+
+ if (ls_switch_handle)
+ set_light_sens_switch(hotk->light_switch);
+
+ if (ls_level_handle)
+ set_light_sens_level(hotk->light_level);
+
+ end:
+ if (result) {
+ kfree(hotk->name);
+ kfree(hotk);
+ }
+
+ return result;
+}
+
+static int asus_hotk_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = 0;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+ asus_hotk_notify);
+ if (ACPI_FAILURE(status))
+ printk(ASUS_ERR "Error removing notify handler\n");
+
+ kfree(hotk->name);
+ kfree(hotk);
+
+ return 0;
+}
+
+static void asus_backlight_exit(void)
+{
+ if (asus_backlight_device)
+ backlight_device_unregister(asus_backlight_device);
+}
+
+#define ASUS_LED_UNREGISTER(object) \
+ if(object##_led.class_dev \
+ && !IS_ERR(object##_led.class_dev)) \
+ led_classdev_unregister(&object##_led)
+
+static void asus_led_exit(void)
+{
+ ASUS_LED_UNREGISTER(mled);
+ ASUS_LED_UNREGISTER(tled);
+ ASUS_LED_UNREGISTER(pled);
+ ASUS_LED_UNREGISTER(rled);
+
+ destroy_workqueue(led_workqueue);
+}
+
+static void __exit asus_laptop_exit(void)
+{
+ asus_backlight_exit();
+ asus_led_exit();
+
+ acpi_bus_unregister_driver(&asus_hotk_driver);
+ sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group);
+ platform_device_unregister(asuspf_device);
+ platform_driver_unregister(&asuspf_driver);
+}
+
+static int asus_backlight_init(struct device *dev)
+{
+ struct backlight_device *bd;
+
+ if (brightness_set_handle && lcd_switch_handle) {
+ bd = backlight_device_register(ASUS_HOTK_FILE, dev,
+ NULL, &asusbl_data);
+ if (IS_ERR(bd)) {
+ printk(ASUS_ERR
+ "Could not register asus backlight device\n");
+ asus_backlight_device = NULL;
+ return PTR_ERR(bd);
+ }
+
+ asus_backlight_device = bd;
+
+ down(&bd->sem);
+ if (likely(bd->props)) {
+ bd->props->brightness = read_brightness(NULL);
+ bd->props->power = FB_BLANK_UNBLANK;
+ if (likely(bd->props->update_status))
+ bd->props->update_status(bd);
+ }
+ up(&bd->sem);
+ }
+ return 0;
+}
+
+static int asus_led_register(acpi_handle handle,
+ struct led_classdev *ldev, struct device *dev)
+{
+ if (!handle)
+ return 0;
+
+ return led_classdev_register(dev, ldev);
+}
+
+#define ASUS_LED_REGISTER(object, device) \
+ asus_led_register(object##_set_handle, &object##_led, device)
+
+static int asus_led_init(struct device *dev)
+{
+ int rv;
+
+ rv = ASUS_LED_REGISTER(mled, dev);
+ if (rv)
+ return rv;
+
+ rv = ASUS_LED_REGISTER(tled, dev);
+ if (rv)
+ return rv;
+
+ rv = ASUS_LED_REGISTER(rled, dev);
+ if (rv)
+ return rv;
+
+ rv = ASUS_LED_REGISTER(pled, dev);
+ if (rv)
+ return rv;
+
+ led_workqueue = create_singlethread_workqueue("led_workqueue");
+ if (!led_workqueue)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int __init asus_laptop_init(void)
+{
+ struct device *dev;
+ int result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ if (!acpi_specific_hotkey_enabled) {
+ printk(ASUS_ERR "Using generic hotkey driver\n");
+ return -ENODEV;
+ }
+
+ result = acpi_bus_register_driver(&asus_hotk_driver);
+ if (result < 0)
+ return result;
+
+ /*
+ * This is a bit of a kludge. We only want this module loaded
+ * for ASUS systems, but there's currently no way to probe the
+ * ACPI namespace for ASUS HIDs. So we just return failure if
+ * we didn't find one, which will cause the module to be
+ * unloaded.
+ */
+ if (!asus_hotk_found) {
+ acpi_bus_unregister_driver(&asus_hotk_driver);
+ return -ENODEV;
+ }
+
+ dev = acpi_get_physical_device(hotk->device->handle);
+
+ result = asus_backlight_init(dev);
+ if (result)
+ goto fail_backlight;
+
+ result = asus_led_init(dev);
+ if (result)
+ goto fail_led;
+
+ /* Register platform stuff */
+ result = platform_driver_register(&asuspf_driver);
+ if (result)
+ goto fail_platform_driver;
+
+ asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1);
+ if (!asuspf_device) {
+ result = -ENOMEM;
+ goto fail_platform_device1;
+ }
+
+ result = platform_device_add(asuspf_device);
+ if (result)
+ goto fail_platform_device2;
+
+ result = sysfs_create_group(&asuspf_device->dev.kobj,
+ &asuspf_attribute_group);
+ if (result)
+ goto fail_sysfs;
+
+ return 0;
+
+ fail_sysfs:
+ platform_device_del(asuspf_device);
+
+ fail_platform_device2:
+ platform_device_put(asuspf_device);
+
+ fail_platform_device1:
+ platform_driver_unregister(&asuspf_driver);
+
+ fail_platform_driver:
+ asus_led_exit();
+
+ fail_led:
+ asus_backlight_exit();
+
+ fail_backlight:
+
+ return result;
+}
+
+module_init(asus_laptop_init);
+module_exit(asus_laptop_exit);
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index db9d7df75ae..552b7957a92 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -108,8 +108,8 @@ 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 char* cpoint_name;
+static char* cpoint_type;
static int cpoint_count = DEFAULT_COUNT;
static int recur_count = REC_NUM_DEFAULT;
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index fdb7153f442..8e5e07e4c1c 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -317,7 +317,8 @@ static int __init msi_init(void)
/* Register backlight stuff */
- msibl_device = backlight_device_register("msi-laptop-bl", NULL, &msibl_props);
+ msibl_device = backlight_device_register("msi-laptop-bl", NULL, NULL,
+ &msibl_props);
if (IS_ERR(msibl_device))
return PTR_ERR(msibl_device);
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 2ab7add78f9..e21e490fedb 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -11,66 +11,25 @@
#include <linux/tifm.h>
#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
#define DRIVER_NAME "tifm_7xx1"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
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(struct work_struct *work)
-{
- struct tifm_adapter *fm =
- container_of(work, struct tifm_adapter, media_remover);
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);
- }
- }
+ fm->socket_change_set |= 1 << sock->socket_id;
+ wake_up_all(&fm->change_set_notify);
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;
+ struct tifm_dev *sock;
unsigned int irq_status;
unsigned int sock_irq_status, cnt;
@@ -84,42 +43,32 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
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);
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ sock = fm->sockets[cnt];
+ sock_irq_status = (irq_status >> cnt)
+ & (TIFM_IRQ_FIFOMASK(1)
+ | TIFM_IRQ_CARDMASK(1));
- if (irq_status & (1 << cnt))
- fm->remove_mask |= 1 << cnt;
- } else {
- if (irq_status & (1 << cnt))
- fm->insert_mask |= 1 << cnt;
- }
+ if (sock && sock_irq_status)
+ sock->signal_irq(sock, sock_irq_status);
}
+
+ fm->socket_change_set |= irq_status
+ & ((1 << fm->num_sockets) - 1);
}
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);
- }
- }
+ if (!fm->socket_change_set)
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+ else
+ wake_up_all(&fm->change_set_notify);
spin_unlock(&fm->lock);
return IRQ_HANDLED;
}
-static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2)
+static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr,
+ int is_x2)
{
unsigned int s_state;
int cnt;
@@ -127,8 +76,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
writel(0x0e00, sock_addr + SOCK_CONTROL);
for (cnt = 0; cnt < 100; cnt++) {
- if (!(TIFM_SOCK_STATE_POWERED &
- readl(sock_addr + SOCK_PRESENT_STATE)))
+ if (!(TIFM_SOCK_STATE_POWERED
+ & readl(sock_addr + SOCK_PRESENT_STATE)))
break;
msleep(10);
}
@@ -151,8 +100,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
}
for (cnt = 0; cnt < 100; cnt++) {
- if ((TIFM_SOCK_STATE_POWERED &
- readl(sock_addr + SOCK_PRESENT_STATE)))
+ if ((TIFM_SOCK_STATE_POWERED
+ & readl(sock_addr + SOCK_PRESENT_STATE)))
break;
msleep(10);
}
@@ -170,130 +119,209 @@ 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(struct work_struct *work)
+static int tifm_7xx1_switch_media(void *data)
{
- struct tifm_adapter *fm =
- container_of(work, struct tifm_adapter, media_inserter);
+ struct tifm_adapter *fm = data;
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;
+ int cnt, rc;
+ struct tifm_dev *sock;
+ unsigned int socket_change_set;
- 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) {
+ while (1) {
+ rc = wait_event_interruptible(fm->change_set_notify,
+ fm->socket_change_set);
+ if (rc == -ERESTARTSYS)
+ try_to_freeze();
+
+ spin_lock_irqsave(&fm->lock, flags);
+ socket_change_set = fm->socket_change_set;
+ fm->socket_change_set = 0;
+
+ dev_dbg(fm->dev, "checking media set %x\n",
+ socket_change_set);
+
+ if (kthread_should_stop())
+ socket_change_set = (1 << fm->num_sockets) - 1;
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)))
+ if (!socket_change_set)
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);
+ spin_lock_irqsave(&fm->lock, flags);
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (!(socket_change_set & (1 << cnt)))
+ continue;
+ sock = fm->sockets[cnt];
+ if (sock) {
printk(KERN_INFO DRIVER_NAME
- ": %s card detected in socket %d\n",
- card_name, cnt);
+ ": demand removing card from socket %d\n",
+ cnt);
+ fm->sockets[cnt] = NULL;
+ spin_unlock_irqrestore(&fm->lock, flags);
+ device_unregister(&sock->dev);
spin_lock_irqsave(&fm->lock, flags);
- if (!fm->sockets[cnt]) {
- fm->sockets[cnt] = new_sock;
- ok_to_register = 1;
+ writel(0x0e00,
+ tifm_7xx1_sock_addr(fm->addr, cnt)
+ + SOCK_CONTROL);
+ }
+ if (kthread_should_stop())
+ continue;
+
+ spin_unlock_irqrestore(&fm->lock, flags);
+ media_id = tifm_7xx1_toggle_sock_power(
+ tifm_7xx1_sock_addr(fm->addr, cnt),
+ fm->num_sockets == 2);
+ if (media_id) {
+ sock = tifm_alloc_device(fm);
+ if (sock) {
+ sock->addr = tifm_7xx1_sock_addr(fm->addr,
+ cnt);
+ sock->media_id = media_id;
+ sock->socket_id = cnt;
+ switch (media_id) {
+ case 1:
+ card_name = "xd";
+ break;
+ case 2:
+ card_name = "ms";
+ break;
+ case 3:
+ card_name = "sd";
+ break;
+ default:
+ tifm_free_device(&sock->dev);
+ spin_lock_irqsave(&fm->lock, flags);
+ continue;
+ }
+ snprintf(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);
+ if (!device_register(&sock->dev)) {
+ spin_lock_irqsave(&fm->lock, flags);
+ if (!fm->sockets[cnt]) {
+ fm->sockets[cnt] = sock;
+ sock = NULL;
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+ }
+ if (sock)
+ tifm_free_device(&sock->dev);
}
+ spin_lock_irqsave(&fm->lock, flags);
+ }
+ }
+
+ if (!kthread_should_stop()) {
+ writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+ | TIFM_IRQ_CARDMASK(socket_change_set),
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+ | TIFM_IRQ_CARDMASK(socket_change_set),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ spin_unlock_irqrestore(&fm->lock, flags);
+ } else {
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (fm->sockets[cnt])
+ fm->socket_change_set |= 1 << cnt;
+ }
+ if (!fm->socket_change_set) {
+ spin_unlock_irqrestore(&fm->lock, flags);
+ return 0;
+ } else {
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);
+ return 0;
}
+#ifdef CONFIG_PM
+
static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
{
- struct tifm_adapter *fm = pci_get_drvdata(dev);
- unsigned long flags;
+ dev_dbg(&dev->dev, "suspending host\n");
- 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->media_remover);
-
- pci_set_power_state(dev, PCI_D3hot);
- pci_disable_device(dev);
- pci_save_state(dev);
+ pci_save_state(dev);
+ pci_enable_wake(dev, pci_choose_state(dev, state), 0);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
}
static int tifm_7xx1_resume(struct pci_dev *dev)
{
struct tifm_adapter *fm = pci_get_drvdata(dev);
+ int cnt, rc;
unsigned long flags;
+ tifm_media_id new_ids[fm->num_sockets];
+ pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
- pci_enable_device(dev);
- pci_set_power_state(dev, PCI_D0);
- pci_set_master(dev);
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+ pci_set_master(dev);
+ dev_dbg(&dev->dev, "resuming host\n");
+
+ for (cnt = 0; cnt < fm->num_sockets; cnt++)
+ new_ids[cnt] = tifm_7xx1_toggle_sock_power(
+ tifm_7xx1_sock_addr(fm->addr, cnt),
+ fm->num_sockets == 2);
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;
+ fm->socket_change_set = 0;
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (fm->sockets[cnt]) {
+ if (fm->sockets[cnt]->media_id == new_ids[cnt])
+ fm->socket_change_set |= 1 << cnt;
+
+ fm->sockets[cnt]->media_id = new_ids[cnt];
+ }
+ }
+
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ if (!fm->socket_change_set) {
+ spin_unlock_irqrestore(&fm->lock, flags);
+ return 0;
+ } else {
+ fm->socket_change_set = 0;
+ spin_unlock_irqrestore(&fm->lock, flags);
+ }
+
+ wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
+
+ spin_lock_irqsave(&fm->lock, flags);
+ writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+ | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+ | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ fm->socket_change_set = 0;
+
spin_unlock_irqrestore(&fm->lock, flags);
return 0;
}
+#else
+
+#define tifm_7xx1_suspend NULL
+#define tifm_7xx1_resume NULL
+
+#endif /* CONFIG_PM */
+
static int tifm_7xx1_probe(struct pci_dev *dev,
- const struct pci_device_id *dev_id)
+ const struct pci_device_id *dev_id)
{
struct tifm_adapter *fm;
int pci_dev_busy = 0;
@@ -324,19 +352,18 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
}
fm->dev = &dev->dev;
- fm->max_sockets = (dev->device == 0x803B) ? 2 : 4;
- fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets,
- GFP_KERNEL);
+ fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
+ ? 4 : 2;
+ fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
+ GFP_KERNEL);
if (!fm->sockets)
goto err_out_free;
- INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media);
- INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media);
fm->eject = tifm_7xx1_eject;
pci_set_drvdata(dev, fm);
fm->addr = ioremap(pci_resource_start(dev, 0),
- pci_resource_len(dev, 0));
+ pci_resource_len(dev, 0));
if (!fm->addr)
goto err_out_free;
@@ -344,16 +371,15 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
if (rc)
goto err_out_unmap;
- rc = tifm_add_adapter(fm);
+ init_waitqueue_head(&fm->change_set_notify);
+ rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
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;
-
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ wake_up_process(fm->media_switcher);
return 0;
err_out_irq:
@@ -377,19 +403,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
struct tifm_adapter *fm = pci_get_drvdata(dev);
unsigned long flags;
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ mmiowb();
+ free_irq(dev->irq, fm);
+
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);
+ fm->socket_change_set = (1 << fm->num_sockets) - 1;
spin_unlock_irqrestore(&fm->lock, flags);
- flush_workqueue(fm->wq);
-
- tifm_7xx1_remove_media(&fm->media_remover);
-
- writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- free_irq(dev->irq, fm);
+ kthread_stop(fm->media_switcher);
tifm_remove_adapter(fm);
@@ -404,10 +426,12 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
}
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 */
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
{ }
};
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index d61df5c3ac3..6b10ebe9d93 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -14,7 +14,7 @@
#include <linux/idr.h>
#define DRIVER_NAME "tifm_core"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
static DEFINE_IDR(tifm_adapter_idr);
static DEFINE_SPINLOCK(tifm_adapter_lock);
@@ -60,10 +60,41 @@ static int tifm_uevent(struct device *dev, char **envp, int num_envp,
return 0;
}
+#ifdef CONFIG_PM
+
+static int tifm_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = fm_dev->drv;
+
+ if (drv && drv->suspend)
+ return drv->suspend(fm_dev, state);
+ return 0;
+}
+
+static int tifm_device_resume(struct device *dev)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = fm_dev->drv;
+
+ if (drv && drv->resume)
+ return drv->resume(fm_dev);
+ return 0;
+}
+
+#else
+
+#define tifm_device_suspend NULL
+#define tifm_device_resume NULL
+
+#endif /* CONFIG_PM */
+
static struct bus_type tifm_bus_type = {
.name = "tifm",
.match = tifm_match,
.uevent = tifm_uevent,
+ .suspend = tifm_device_suspend,
+ .resume = tifm_device_resume
};
static void tifm_free(struct class_device *cdev)
@@ -71,8 +102,6 @@ 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);
}
@@ -101,7 +130,8 @@ void tifm_free_adapter(struct tifm_adapter *fm)
}
EXPORT_SYMBOL(tifm_free_adapter);
-int tifm_add_adapter(struct tifm_adapter *fm)
+int tifm_add_adapter(struct tifm_adapter *fm,
+ int (*mediathreadfn)(void *data))
{
int rc;
@@ -113,10 +143,10 @@ int tifm_add_adapter(struct tifm_adapter *fm)
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->media_switcher = kthread_create(mediathreadfn,
+ fm, "tifm/%u", fm->id);
- fm->wq = create_singlethread_workqueue(fm->wq_name);
- if (fm->wq)
+ if (!IS_ERR(fm->media_switcher))
return class_device_add(&fm->cdev);
spin_lock(&tifm_adapter_lock);
@@ -141,27 +171,27 @@ 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)
+static void tifm_dummy_signal_irq(struct tifm_dev *sock,
+ unsigned int sock_irq_status)
+{
+ return;
+}
+
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm)
{
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;
+ dev->signal_irq = tifm_dummy_signal_irq;
}
return dev;
}
@@ -219,6 +249,7 @@ static int tifm_device_remove(struct device *dev)
struct tifm_driver *drv = fm_dev->drv;
if (drv) {
+ fm_dev->signal_irq = tifm_dummy_signal_irq;
if (drv->remove)
drv->remove(fm_dev);
fm_dev->drv = NULL;
@@ -233,6 +264,8 @@ 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;
+ drv->driver.suspend = tifm_device_suspend;
+ drv->driver.resume = tifm_device_resume;
return driver_register(&drv->driver);
}
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 4224686fdf2..12af9c71876 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -111,7 +111,7 @@ config MMC_IMX
config MMC_TIFM_SD
tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
- depends on MMC && EXPERIMENTAL
+ depends on MMC && EXPERIMENTAL && PCI
select TIFM_CORE
help
Say Y here if you want to be able to access MMC/SD cards with
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
index 4633dbc9a90..2ce50f38e3c 100644
--- a/drivers/mmc/at91_mci.c
+++ b/drivers/mmc/at91_mci.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/at91_mci.c - ATMEL AT91RM9200 MCI Driver
+ * linux/drivers/mmc/at91_mci.c - ATMEL AT91 MCI Driver
*
* Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
*
@@ -11,7 +11,7 @@
*/
/*
- This is the AT91RM9200 MCI driver that has been tested with both MMC cards
+ This is the AT91 MCI driver that has been tested with both MMC cards
and SD-cards. Boards that support write protect are now supported.
The CCAT91SBC001 board does not support SD cards.
@@ -38,8 +38,8 @@
controller to manage the transfers.
A read is done from the controller directly to the scatterlist passed in from the request.
- Due to a bug in the controller, when a read is completed, all the words are byte
- swapped in the scatterlist buffers.
+ Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
+ swapped in the scatterlist buffers. AT91SAM926x are not affected by this bug.
The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
@@ -72,6 +72,7 @@
#include <asm/irq.h>
#include <asm/mach/mmc.h>
#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
#include <asm/arch/gpio.h>
#include <asm/arch/at91_mci.h>
#include <asm/arch/at91_pdc.h>
@@ -80,34 +81,18 @@
#undef SUPPORT_4WIRE
-static struct clk *mci_clk;
+#define FL_SENT_COMMAND (1 << 0)
+#define FL_SENT_STOP (1 << 1)
-#define FL_SENT_COMMAND (1 << 0)
-#define FL_SENT_STOP (1 << 1)
+#define AT91_MCI_ERRORS (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE \
+ | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE \
+ | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)
+#define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg))
+#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg))
/*
- * Read from a MCI register.
- */
-static inline unsigned long at91_mci_read(unsigned int reg)
-{
- void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI;
-
- return __raw_readl(mci_base + reg);
-}
-
-/*
- * Write to a MCI register.
- */
-static inline void at91_mci_write(unsigned int reg, unsigned long value)
-{
- void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI;
-
- __raw_writel(value, mci_base + reg);
-}
-
-/*
* Low level type for this driver
*/
struct at91mci_host
@@ -116,9 +101,14 @@ struct at91mci_host
struct mmc_command *cmd;
struct mmc_request *request;
+ void __iomem *baseaddr;
+ int irq;
+
struct at91_mmc_data *board;
int present;
+ struct clk *mci_clk;
+
/*
* Flag indicating when the command has been sent. This is used to
* work out whether or not to send the stop
@@ -158,7 +148,6 @@ static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
for (i = 0; i < len; i++) {
struct scatterlist *sg;
int amount;
- int index;
unsigned int *sgbuffer;
sg = &data->sg[i];
@@ -166,10 +155,15 @@ static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
amount = min(size, sg->length);
size -= amount;
- amount /= 4;
- for (index = 0; index < amount; index++)
- *dmabuf++ = swab32(sgbuffer[index]);
+ if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
+ int index;
+
+ for (index = 0; index < (amount / 4); index++)
+ *dmabuf++ = swab32(sgbuffer[index]);
+ }
+ else
+ memcpy(dmabuf, sgbuffer, amount);
kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
@@ -217,13 +211,13 @@ static void at91mci_pre_dma_read(struct at91mci_host *host)
/* Check to see if this needs filling */
if (i == 0) {
- if (at91_mci_read(AT91_PDC_RCR) != 0) {
+ if (at91_mci_read(host, AT91_PDC_RCR) != 0) {
pr_debug("Transfer active in current\n");
continue;
}
}
else {
- if (at91_mci_read(AT91_PDC_RNCR) != 0) {
+ if (at91_mci_read(host, AT91_PDC_RNCR) != 0) {
pr_debug("Transfer active in next\n");
continue;
}
@@ -240,12 +234,12 @@ static void at91mci_pre_dma_read(struct at91mci_host *host)
pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
if (i == 0) {
- at91_mci_write(AT91_PDC_RPR, sg->dma_address);
- at91_mci_write(AT91_PDC_RCR, sg->length / 4);
+ at91_mci_write(host, AT91_PDC_RPR, sg->dma_address);
+ at91_mci_write(host, AT91_PDC_RCR, sg->length / 4);
}
else {
- at91_mci_write(AT91_PDC_RNPR, sg->dma_address);
- at91_mci_write(AT91_PDC_RNCR, sg->length / 4);
+ at91_mci_write(host, AT91_PDC_RNPR, sg->dma_address);
+ at91_mci_write(host, AT91_PDC_RNCR, sg->length / 4);
}
}
@@ -276,8 +270,6 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
while (host->in_use_index < host->transfer_index) {
unsigned int *buffer;
- int index;
- int len;
struct scatterlist *sg;
@@ -295,11 +287,13 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
data->bytes_xfered += sg->length;
- len = sg->length / 4;
+ if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
+ int index;
- for (index = 0; index < len; index++) {
- buffer[index] = swab32(buffer[index]);
+ for (index = 0; index < (sg->length / 4); index++)
+ buffer[index] = swab32(buffer[index]);
}
+
kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
flush_dcache_page(sg->page);
}
@@ -308,8 +302,8 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
if (host->transfer_index < data->sg_len)
at91mci_pre_dma_read(host);
else {
- at91_mci_write(AT91_MCI_IER, AT91_MCI_RXBUFF);
- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
}
pr_debug("post dma read done\n");
@@ -326,11 +320,11 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
pr_debug("Handling the transmit\n");
/* Disable the transfer */
- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
/* Now wait for cmd ready */
- at91_mci_write(AT91_MCI_IDR, AT91_MCI_TXBUFE);
- at91_mci_write(AT91_MCI_IER, AT91_MCI_NOTBUSY);
+ at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
cmd = host->cmd;
if (!cmd) return;
@@ -344,21 +338,23 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
/*
* Enable the controller
*/
-static void at91_mci_enable(void)
+static void at91_mci_enable(struct at91mci_host *host)
{
- at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN);
- at91_mci_write(AT91_MCI_IDR, 0xFFFFFFFF);
- at91_mci_write(AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
- at91_mci_write(AT91_MCI_MR, 0x834A);
- at91_mci_write(AT91_MCI_SDCR, 0x0);
+ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
+ at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
+ at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
+ at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a);
+
+ /* use Slot A or B (only one at same time) */
+ at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
}
/*
* Disable the controller
*/
-static void at91_mci_disable(void)
+static void at91_mci_disable(struct at91mci_host *host)
{
- at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
+ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
}
/*
@@ -378,13 +374,13 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
/* Not sure if this is needed */
#if 0
- if ((at91_mci_read(AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
+ if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
pr_debug("Clearing timeout\n");
- at91_mci_write(AT91_MCI_ARGR, 0);
- at91_mci_write(AT91_MCI_CMDR, AT91_MCI_OPDCMD);
- while (!(at91_mci_read(AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
+ at91_mci_write(host, AT91_MCI_ARGR, 0);
+ at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
+ while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
/* spin */
- pr_debug("Clearing: SR = %08X\n", at91_mci_read(AT91_MCI_SR));
+ pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
}
}
#endif
@@ -431,32 +427,32 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
/*
* Set the arguments and send the command
*/
- pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08lX)\n",
- cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(AT91_MCI_MR));
+ pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
+ cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
if (!data) {
- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS);
- at91_mci_write(AT91_PDC_RPR, 0);
- at91_mci_write(AT91_PDC_RCR, 0);
- at91_mci_write(AT91_PDC_RNPR, 0);
- at91_mci_write(AT91_PDC_RNCR, 0);
- at91_mci_write(AT91_PDC_TPR, 0);
- at91_mci_write(AT91_PDC_TCR, 0);
- at91_mci_write(AT91_PDC_TNPR, 0);
- at91_mci_write(AT91_PDC_TNCR, 0);
-
- at91_mci_write(AT91_MCI_ARGR, cmd->arg);
- at91_mci_write(AT91_MCI_CMDR, cmdr);
+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS);
+ at91_mci_write(host, AT91_PDC_RPR, 0);
+ at91_mci_write(host, AT91_PDC_RCR, 0);
+ at91_mci_write(host, AT91_PDC_RNPR, 0);
+ at91_mci_write(host, AT91_PDC_RNCR, 0);
+ at91_mci_write(host, AT91_PDC_TPR, 0);
+ at91_mci_write(host, AT91_PDC_TCR, 0);
+ at91_mci_write(host, AT91_PDC_TNPR, 0);
+ at91_mci_write(host, AT91_PDC_TNCR, 0);
+
+ at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
+ at91_mci_write(host, AT91_MCI_CMDR, cmdr);
return AT91_MCI_CMDRDY;
}
- mr = at91_mci_read(AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */
- at91_mci_write(AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
+ mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */
+ at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
/*
* Disable the PDC controller
*/
- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
if (cmdr & AT91_MCI_TRCMD_START) {
data->bytes_xfered = 0;
@@ -485,8 +481,8 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
pr_debug("Transmitting %d bytes\n", host->total_length);
- at91_mci_write(AT91_PDC_TPR, host->physical_address);
- at91_mci_write(AT91_PDC_TCR, host->total_length / 4);
+ at91_mci_write(host, AT91_PDC_TPR, host->physical_address);
+ at91_mci_write(host, AT91_PDC_TCR, host->total_length / 4);
ier = AT91_MCI_TXBUFE;
}
}
@@ -496,14 +492,14 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
* the data sheet says
*/
- at91_mci_write(AT91_MCI_ARGR, cmd->arg);
- at91_mci_write(AT91_MCI_CMDR, cmdr);
+ at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
+ at91_mci_write(host, AT91_MCI_CMDR, cmdr);
if (cmdr & AT91_MCI_TRCMD_START) {
if (cmdr & AT91_MCI_TRDIR)
- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTEN);
+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTEN);
else
- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTEN);
+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN);
}
return ier;
}
@@ -520,7 +516,7 @@ static void at91mci_process_command(struct at91mci_host *host, struct mmc_comman
pr_debug("setting ier to %08X\n", ier);
/* Stop on errors or the required value */
- at91_mci_write(AT91_MCI_IER, 0xffff0000 | ier);
+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
}
/*
@@ -548,19 +544,19 @@ static void at91mci_completed_command(struct at91mci_host *host)
struct mmc_command *cmd = host->cmd;
unsigned int status;
- at91_mci_write(AT91_MCI_IDR, 0xffffffff);
+ at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
- cmd->resp[0] = at91_mci_read(AT91_MCI_RSPR(0));
- cmd->resp[1] = at91_mci_read(AT91_MCI_RSPR(1));
- cmd->resp[2] = at91_mci_read(AT91_MCI_RSPR(2));
- cmd->resp[3] = at91_mci_read(AT91_MCI_RSPR(3));
+ cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
+ cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
+ cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
+ cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
if (host->buffer) {
dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);
host->buffer = NULL;
}
- status = at91_mci_read(AT91_MCI_SR);
+ status = at91_mci_read(host, AT91_MCI_SR);
pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
@@ -611,18 +607,18 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
int clkdiv;
struct at91mci_host *host = mmc_priv(mmc);
- unsigned long at91_master_clock = clk_get_rate(mci_clk);
+ unsigned long at91_master_clock = clk_get_rate(host->mci_clk);
host->bus_mode = ios->bus_mode;
if (ios->clock == 0) {
/* Disable the MCI controller */
- at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS);
+ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);
clkdiv = 0;
}
else {
/* Enable the MCI controller */
- at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN);
+ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
if ((at91_master_clock % (ios->clock * 2)) == 0)
clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
@@ -634,25 +630,25 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
pr_debug("MMC: Setting controller bus width to 4\n");
- at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
+ at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
}
else {
pr_debug("MMC: Setting controller bus width to 1\n");
- at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
+ at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
}
/* Set the clock divider */
- at91_mci_write(AT91_MCI_MR, (at91_mci_read(AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
+ at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
/* maybe switch power to the card */
if (host->board->vcc_pin) {
switch (ios->power_mode) {
case MMC_POWER_OFF:
- at91_set_gpio_output(host->board->vcc_pin, 0);
+ at91_set_gpio_value(host->board->vcc_pin, 0);
break;
case MMC_POWER_UP:
case MMC_POWER_ON:
- at91_set_gpio_output(host->board->vcc_pin, 1);
+ at91_set_gpio_value(host->board->vcc_pin, 1);
break;
}
}
@@ -665,39 +661,40 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
{
struct at91mci_host *host = devid;
int completed = 0;
+ unsigned int int_status, int_mask;
- unsigned int int_status;
+ int_status = at91_mci_read(host, AT91_MCI_SR);
+ int_mask = at91_mci_read(host, AT91_MCI_IMR);
+
+ pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
+ int_status & int_mask);
+
+ int_status = int_status & int_mask;
- int_status = at91_mci_read(AT91_MCI_SR);
- pr_debug("MCI irq: status = %08X, %08lX, %08lX\n", int_status, at91_mci_read(AT91_MCI_IMR),
- int_status & at91_mci_read(AT91_MCI_IMR));
-
- if ((int_status & at91_mci_read(AT91_MCI_IMR)) & 0xffff0000)
+ if (int_status & AT91_MCI_ERRORS) {
completed = 1;
+
+ if (int_status & AT91_MCI_UNRE)
+ pr_debug("MMC: Underrun error\n");
+ if (int_status & AT91_MCI_OVRE)
+ pr_debug("MMC: Overrun error\n");
+ if (int_status & AT91_MCI_DTOE)
+ pr_debug("MMC: Data timeout\n");
+ if (int_status & AT91_MCI_DCRCE)
+ pr_debug("MMC: CRC error in data\n");
+ if (int_status & AT91_MCI_RTOE)
+ pr_debug("MMC: Response timeout\n");
+ if (int_status & AT91_MCI_RENDE)
+ pr_debug("MMC: Response end bit error\n");
+ if (int_status & AT91_MCI_RCRCE)
+ pr_debug("MMC: Response CRC error\n");
+ if (int_status & AT91_MCI_RDIRE)
+ pr_debug("MMC: Response direction error\n");
+ if (int_status & AT91_MCI_RINDE)
+ pr_debug("MMC: Response index error\n");
+ } else {
+ /* Only continue processing if no errors */
- int_status &= at91_mci_read(AT91_MCI_IMR);
-
- if (int_status & AT91_MCI_UNRE)
- pr_debug("MMC: Underrun error\n");
- if (int_status & AT91_MCI_OVRE)
- pr_debug("MMC: Overrun error\n");
- if (int_status & AT91_MCI_DTOE)
- pr_debug("MMC: Data timeout\n");
- if (int_status & AT91_MCI_DCRCE)
- pr_debug("MMC: CRC error in data\n");
- if (int_status & AT91_MCI_RTOE)
- pr_debug("MMC: Response timeout\n");
- if (int_status & AT91_MCI_RENDE)
- pr_debug("MMC: Response end bit error\n");
- if (int_status & AT91_MCI_RCRCE)
- pr_debug("MMC: Response CRC error\n");
- if (int_status & AT91_MCI_RDIRE)
- pr_debug("MMC: Response direction error\n");
- if (int_status & AT91_MCI_RINDE)
- pr_debug("MMC: Response index error\n");
-
- /* Only continue processing if no errors */
- if (!completed) {
if (int_status & AT91_MCI_TXBUFE) {
pr_debug("TX buffer empty\n");
at91_mci_handle_transmitted(host);
@@ -705,12 +702,11 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
if (int_status & AT91_MCI_RXBUFF) {
pr_debug("RX buffer full\n");
- at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
}
- if (int_status & AT91_MCI_ENDTX) {
+ if (int_status & AT91_MCI_ENDTX)
pr_debug("Transmit has ended\n");
- }
if (int_status & AT91_MCI_ENDRX) {
pr_debug("Receive has ended\n");
@@ -719,37 +715,33 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
if (int_status & AT91_MCI_NOTBUSY) {
pr_debug("Card is ready\n");
- at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
}
- if (int_status & AT91_MCI_DTIP) {
+ if (int_status & AT91_MCI_DTIP)
pr_debug("Data transfer in progress\n");
- }
- if (int_status & AT91_MCI_BLKE) {
+ if (int_status & AT91_MCI_BLKE)
pr_debug("Block transfer has ended\n");
- }
- if (int_status & AT91_MCI_TXRDY) {
+ if (int_status & AT91_MCI_TXRDY)
pr_debug("Ready to transmit\n");
- }
- if (int_status & AT91_MCI_RXRDY) {
+ if (int_status & AT91_MCI_RXRDY)
pr_debug("Ready to receive\n");
- }
if (int_status & AT91_MCI_CMDRDY) {
pr_debug("Command ready\n");
completed = 1;
}
}
- at91_mci_write(AT91_MCI_IDR, int_status);
if (completed) {
pr_debug("Completed command\n");
- at91_mci_write(AT91_MCI_IDR, 0xffffffff);
+ at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
at91mci_completed_command(host);
- }
+ } else
+ at91_mci_write(host, AT91_MCI_IDR, int_status);
return IRQ_HANDLED;
}
@@ -769,14 +761,14 @@ static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
present ? "insert" : "remove");
if (!present) {
pr_debug("****** Resetting SD-card bus width ******\n");
- at91_mci_write(AT91_MCI_SDCR, 0);
+ at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
}
mmc_detect_change(host->mmc, msecs_to_jiffies(100));
}
return IRQ_HANDLED;
}
-int at91_mci_get_ro(struct mmc_host *mmc)
+static int at91_mci_get_ro(struct mmc_host *mmc)
{
int read_only = 0;
struct at91mci_host *host = mmc_priv(mmc);
@@ -802,19 +794,26 @@ static const struct mmc_host_ops at91_mci_ops = {
/*
* Probe for the device
*/
-static int at91_mci_probe(struct platform_device *pdev)
+static int __init at91_mci_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
struct at91mci_host *host;
+ struct resource *res;
int ret;
pr_debug("Probe MCI devices\n");
- at91_mci_disable();
- at91_mci_enable();
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
+ return -EBUSY;
mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
if (!mmc) {
pr_debug("Failed to allocate mmc host\n");
+ release_mem_region(res->start, res->end - res->start + 1);
return -ENOMEM;
}
@@ -824,6 +823,9 @@ static int at91_mci_probe(struct platform_device *pdev)
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps = MMC_CAP_BYTEBLOCK;
+ mmc->max_blk_size = 4095;
+ mmc->max_blk_count = mmc->max_req_size;
+
host = mmc_priv(mmc);
host->mmc = mmc;
host->buffer = NULL;
@@ -833,30 +835,51 @@ static int at91_mci_probe(struct platform_device *pdev)
#ifdef SUPPORT_4WIRE
mmc->caps |= MMC_CAP_4_BIT_DATA;
#else
- printk("MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
+ printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
#endif
}
/*
* Get Clock
*/
- mci_clk = clk_get(&pdev->dev, "mci_clk");
- if (IS_ERR(mci_clk)) {
+ host->mci_clk = clk_get(&pdev->dev, "mci_clk");
+ if (IS_ERR(host->mci_clk)) {
printk(KERN_ERR "AT91 MMC: no clock defined.\n");
mmc_free_host(mmc);
+ release_mem_region(res->start, res->end - res->start + 1);
return -ENODEV;
}
- clk_enable(mci_clk); /* Enable the peripheral clock */
+
+ /*
+ * Map I/O region
+ */
+ host->baseaddr = ioremap(res->start, res->end - res->start + 1);
+ if (!host->baseaddr) {
+ clk_put(host->mci_clk);
+ mmc_free_host(mmc);
+ release_mem_region(res->start, res->end - res->start + 1);
+ return -ENOMEM;
+ }
+
+ /*
+ * Reset hardware
+ */
+ clk_enable(host->mci_clk); /* Enable the peripheral clock */
+ at91_mci_disable(host);
+ at91_mci_enable(host);
/*
* Allocate the MCI interrupt
*/
- ret = request_irq(AT91RM9200_ID_MCI, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
+ host->irq = platform_get_irq(pdev, 0);
+ ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
if (ret) {
- printk(KERN_ERR "Failed to request MCI interrupt\n");
- clk_disable(mci_clk);
- clk_put(mci_clk);
+ printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n");
+ clk_disable(host->mci_clk);
+ clk_put(host->mci_clk);
mmc_free_host(mmc);
+ iounmap(host->baseaddr);
+ release_mem_region(res->start, res->end - res->start + 1);
return ret;
}
@@ -879,10 +902,10 @@ static int at91_mci_probe(struct platform_device *pdev)
ret = request_irq(host->board->det_pin, at91_mmc_det_irq,
0, DRIVER_NAME, host);
if (ret)
- printk(KERN_ERR "couldn't allocate MMC detect irq\n");
+ printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n");
}
- pr_debug(KERN_INFO "Added MCI driver\n");
+ pr_debug("Added MCI driver\n");
return 0;
}
@@ -890,10 +913,11 @@ static int at91_mci_probe(struct platform_device *pdev)
/*
* Remove a device
*/
-static int at91_mci_remove(struct platform_device *pdev)
+static int __exit at91_mci_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct at91mci_host *host;
+ struct resource *res;
if (!mmc)
return -1;
@@ -905,16 +929,19 @@ static int at91_mci_remove(struct platform_device *pdev)
cancel_delayed_work(&host->mmc->detect);
}
+ at91_mci_disable(host);
mmc_remove_host(mmc);
- at91_mci_disable();
- free_irq(AT91RM9200_ID_MCI, host);
- mmc_free_host(mmc);
+ free_irq(host->irq, host);
- clk_disable(mci_clk); /* Disable the peripheral clock */
- clk_put(mci_clk);
+ clk_disable(host->mci_clk); /* Disable the peripheral clock */
+ clk_put(host->mci_clk);
- platform_set_drvdata(pdev, NULL);
+ iounmap(host->baseaddr);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+ mmc_free_host(mmc);
+ platform_set_drvdata(pdev, NULL);
pr_debug("MCI Removed\n");
return 0;
@@ -948,8 +975,7 @@ static int at91_mci_resume(struct platform_device *pdev)
#endif
static struct platform_driver at91_mci_driver = {
- .probe = at91_mci_probe,
- .remove = at91_mci_remove,
+ .remove = __exit_p(at91_mci_remove),
.suspend = at91_mci_suspend,
.resume = at91_mci_resume,
.driver = {
@@ -960,7 +986,7 @@ static struct platform_driver at91_mci_driver = {
static int __init at91_mci_init(void)
{
- return platform_driver_register(&at91_mci_driver);
+ return platform_driver_probe(&at91_mci_driver, at91_mci_probe);
}
static void __exit at91_mci_exit(void)
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index 447fba5825f..b834be261ab 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -152,8 +152,9 @@ static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
? 1 : 0;
}
-static inline int au1xmmc_card_readonly(struct au1xmmc_host *host)
+static int au1xmmc_card_readonly(struct mmc_host *mmc)
{
+ struct au1xmmc_host *host = mmc_priv(mmc);
return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
? 1 : 0;
}
@@ -193,6 +194,8 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_NONE:
+ break;
case MMC_RSP_R1:
mmccmd |= SD_CMD_RT_1;
break;
@@ -205,6 +208,10 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
case MMC_RSP_R3:
mmccmd |= SD_CMD_RT_3;
break;
+ default:
+ printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
+ mmc_resp_type(cmd));
+ return MMC_ERR_INVALID;
}
switch(cmd->opcode) {
@@ -875,9 +882,10 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)
host->rx_chan = rxchan;
}
-struct const mmc_host_ops au1xmmc_ops = {
+static const struct mmc_host_ops au1xmmc_ops = {
.request = au1xmmc_request,
.set_ios = au1xmmc_set_ios,
+ .get_ro = au1xmmc_card_readonly,
};
static int __devinit au1xmmc_probe(struct platform_device *pdev)
@@ -914,6 +922,9 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
+ mmc->max_blk_size = 2048;
+ mmc->max_blk_count = 512;
+
mmc->ocr_avail = AU1XMMC_OCR;
host = mmc_priv(mmc);
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
index 06e7fcd1922..b060d4bfba2 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/imxmmc.c
@@ -351,9 +351,6 @@ static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd,
case MMC_RSP_R3: /* short */
cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3;
break;
- case MMC_RSP_R6: /* short CRC */
- cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R6;
- break;
default:
break;
}
@@ -961,8 +958,10 @@ static int imxmci_probe(struct platform_device *pdev)
/* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64;
mmc->max_phys_segs = 64;
- mmc->max_sectors = 64; /* default 1 << (PAGE_CACHE_SHIFT - 9) */
mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */
+ mmc->max_req_size = 64*512; /* default PAGE_CACHE_SIZE */
+ mmc->max_blk_size = 2048;
+ mmc->max_blk_count = 65535;
host = mmc_priv(mmc);
host->mmc = mmc;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6f2a282e2b9..5046a166134 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -103,11 +103,16 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->cmd->opcode,
mrq->cmd->arg, mrq->cmd->flags);
- WARN_ON(host->card_busy == NULL);
+ WARN_ON(!host->claimed);
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
if (mrq->data) {
+ BUG_ON(mrq->data->blksz > host->max_blk_size);
+ BUG_ON(mrq->data->blocks > host->max_blk_count);
+ BUG_ON(mrq->data->blocks * mrq->data->blksz >
+ host->max_req_size);
+
mrq->cmd->data = mrq->data;
mrq->data->error = 0;
mrq->data->mrq = mrq;
@@ -157,7 +162,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
{
struct mmc_request mrq;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
memset(&mrq, 0, sizeof(struct mmc_request));
@@ -195,7 +200,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
int i, err;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
BUG_ON(retries < 0);
err = MMC_ERR_INVALID;
@@ -289,7 +294,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
else
limit_us = 100000;
- if (timeout_us > limit_us) {
+ /*
+ * SDHC cards always use these fixed values.
+ */
+ if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
data->timeout_ns = limit_us * 1000;
data->timeout_clks = 0;
}
@@ -320,14 +328,14 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
spin_lock_irqsave(&host->lock, flags);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
- if (host->card_busy == NULL)
+ if (!host->claimed)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
- host->card_busy = card;
+ host->claimed = 1;
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
@@ -353,10 +361,10 @@ void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
- host->card_busy = NULL;
+ host->claimed = 0;
spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq);
@@ -372,7 +380,7 @@ static inline void mmc_set_ios(struct mmc_host *host)
mmc_hostname(host), ios->clock, ios->bus_mode,
ios->power_mode, ios->chip_select, ios->vdd,
ios->bus_width);
-
+
host->ops->set_ios(host, ios);
}
@@ -381,7 +389,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
int err;
struct mmc_command cmd;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
if (host->card_selected == card)
return MMC_ERR_NONE;
@@ -588,34 +596,65 @@ static void mmc_decode_csd(struct mmc_card *card)
if (mmc_card_sd(card)) {
csd_struct = UNSTUFF_BITS(resp, 126, 2);
- if (csd_struct != 0) {
+
+ switch (csd_struct) {
+ case 0:
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
+ csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+ csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+ csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+ break;
+ case 1:
+ /*
+ * This is a block-addressed SDHC card. Most
+ * interesting fields are unused and have fixed
+ * values. To avoid getting tripped by buggy cards,
+ * we assume those fixed values ourselves.
+ */
+ mmc_card_set_blockaddr(card);
+
+ csd->tacc_ns = 0; /* Unused */
+ csd->tacc_clks = 0; /* Unused */
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ m = UNSTUFF_BITS(resp, 48, 22);
+ csd->capacity = (1 + m) << 10;
+
+ csd->read_blkbits = 9;
+ csd->read_partial = 0;
+ csd->write_misalign = 0;
+ csd->read_misalign = 0;
+ csd->r2w_factor = 4; /* Unused */
+ csd->write_blkbits = 9;
+ csd->write_partial = 0;
+ break;
+ default:
printk("%s: unrecognised CSD structure version %d\n",
mmc_hostname(card->host), csd_struct);
mmc_card_set_bad(card);
return;
}
-
- m = UNSTUFF_BITS(resp, 115, 4);
- e = UNSTUFF_BITS(resp, 112, 3);
- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
-
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
- csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
-
- e = UNSTUFF_BITS(resp, 47, 3);
- m = UNSTUFF_BITS(resp, 62, 12);
- csd->capacity = (1 + m) << (e + 2);
-
- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
- csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
} else {
/*
* We only understand CSD structure v1.1 and v1.2.
@@ -848,6 +887,41 @@ static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return err;
}
+static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
+{
+ struct mmc_command cmd;
+ int err, sd2;
+ static const u8 test_pattern = 0xAA;
+
+ /*
+ * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+ * before SD_APP_OP_COND. This command will harmlessly fail for
+ * SD 1.0 cards.
+ */
+ cmd.opcode = SD_SEND_IF_COND;
+ cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+ cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err == MMC_ERR_NONE) {
+ if ((cmd.resp[0] & 0xFF) == test_pattern) {
+ sd2 = 1;
+ } else {
+ sd2 = 0;
+ err = MMC_ERR_FAILED;
+ }
+ } else {
+ /*
+ * Treat errors as SD 1.0 card.
+ */
+ sd2 = 0;
+ err = MMC_ERR_NONE;
+ }
+ if (rsd2)
+ *rsd2 = sd2;
+ return err;
+}
+
/*
* Discover cards by requesting their CID. If this command
* times out, it is not an error; there are no further cards
@@ -1018,7 +1092,8 @@ static void mmc_process_ext_csds(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
+ printk("%s: unable to read EXT_CSD, performance "
+ "might suffer.\n", mmc_hostname(card->host));
continue;
}
@@ -1034,7 +1109,6 @@ static void mmc_process_ext_csds(struct mmc_host *host)
printk("%s: card is mmc v4 but doesn't support "
"any high-speed modes.\n",
mmc_hostname(card->host));
- mmc_card_set_bad(card);
continue;
}
@@ -1215,7 +1289,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
+ printk("%s: unable to read switch capabilities, "
+ "performance might suffer.\n",
+ mmc_hostname(card->host));
continue;
}
@@ -1247,12 +1323,8 @@ static void mmc_read_switch_caps(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
-
- if ((status[16] & 0xF) != 1) {
+ if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
+ (status[16] & 0xF) != 1) {
printk(KERN_WARNING "%s: Problem switching card "
"into high-speed mode!\n",
mmc_hostname(host));
@@ -1334,6 +1406,10 @@ static void mmc_setup(struct mmc_host *host)
mmc_power_up(host);
mmc_idle_cards(host);
+ err = mmc_send_if_cond(host, host->ocr_avail, NULL);
+ if (err != MMC_ERR_NONE) {
+ return;
+ }
err = mmc_send_app_op_cond(host, 0, &ocr);
/*
@@ -1386,10 +1462,21 @@ static void mmc_setup(struct mmc_host *host)
* all get the idea that they should be ready for CMD2.
* (My SanDisk card seems to need this.)
*/
- if (host->mode == MMC_MODE_SD)
- mmc_send_app_op_cond(host, host->ocr, NULL);
- else
+ if (host->mode == MMC_MODE_SD) {
+ int err, sd2;
+ err = mmc_send_if_cond(host, host->ocr, &sd2);
+ if (err == MMC_ERR_NONE) {
+ /*
+ * If SD_SEND_IF_COND indicates an SD 2.0
+ * compliant card and we should set bit 30
+ * of the ocr to indicate that we can handle
+ * block-addressed SDHC cards.
+ */
+ mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
+ }
+ } else {
mmc_send_op_cond(host, host->ocr, NULL);
+ }
mmc_discover_cards(host);
@@ -1519,8 +1606,11 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
*/
host->max_hw_segs = 1;
host->max_phys_segs = 1;
- host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
host->max_seg_size = PAGE_CACHE_SIZE;
+
+ host->max_req_size = PAGE_CACHE_SIZE;
+ host->max_blk_size = 512;
+ host->max_blk_count = PAGE_CACHE_SIZE / 512;
}
return host;
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index 87713572293..05ba8ace70e 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -237,13 +237,17 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.mrq.cmd = &brq.cmd;
brq.mrq.data = &brq.data;
- brq.cmd.arg = req->sector << 9;
+ brq.cmd.arg = req->sector;
+ if (!mmc_card_blockaddr(card))
+ brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
brq.data.blksz = 1 << md->block_bits;
- brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
+ if (brq.data.blocks > card->host->max_blk_count)
+ brq.data.blocks = card->host->max_blk_count;
mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
@@ -375,9 +379,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
}
+flush_queue:
+
mmc_card_release_host(card);
-flush_queue:
spin_lock_irq(&md->lock);
while (ret) {
ret = end_that_request_chunk(req, 0,
@@ -494,6 +499,10 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
struct mmc_command cmd;
int err;
+ /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
+ if (mmc_card_blockaddr(card))
+ return 0;
+
mmc_card_claim_host(card);
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 1 << md->block_bits;
diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c
index a17423a4ed8..c27e42645cd 100644
--- a/drivers/mmc/mmc_queue.c
+++ b/drivers/mmc/mmc_queue.c
@@ -78,8 +78,10 @@ static int mmc_queue_thread(void *d)
spin_unlock_irq(q->queue_lock);
if (!req) {
- if (kthread_should_stop())
+ if (kthread_should_stop()) {
+ set_current_state(TASK_RUNNING);
break;
+ }
up(&mq->thread_sem);
schedule();
down(&mq->thread_sem);
@@ -145,7 +147,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_queue_prep_rq(mq->queue, mmc_prep_request);
blk_queue_bounce_limit(mq->queue, limit);
- blk_queue_max_sectors(mq->queue, host->max_sectors);
+ blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index e334acd045b..d32698b02d7 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -199,7 +199,7 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
memset(card, 0, sizeof(struct mmc_card));
card->host = host;
device_initialize(&card->dev);
- card->dev.parent = mmc_dev(host);
+ card->dev.parent = mmc_classdev(host);
card->dev.bus = &mmc_bus_type;
card->dev.release = mmc_release_card;
}
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index e9b80e92026..5941dd951e8 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -42,6 +42,8 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
{
writel(0, host->base + MMCICOMMAND);
+ BUG_ON(host->data);
+
host->mrq = NULL;
host->cmd = NULL;
@@ -198,6 +200,8 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
}
if (!cmd->data || cmd->error != MMC_ERR_NONE) {
+ if (host->data)
+ mmci_stop_data(host);
mmci_request_end(host, cmd->mrq);
} else if (!(cmd->data->flags & MMC_DATA_READ)) {
mmci_start_data(host, cmd->data);
@@ -520,15 +524,24 @@ static int mmci_probe(struct amba_device *dev, void *id)
/*
* Since we only have a 16-bit data length register, we must
* ensure that we don't exceed 2^16-1 bytes in a single request.
- * Choose 64 (512-byte) sectors as the limit.
*/
- mmc->max_sectors = 64;
+ mmc->max_req_size = 65535;
/*
* Set the maximum segment size. Since we aren't doing DMA
* (yet) we are only limited by the data length register.
*/
- mmc->max_seg_size = mmc->max_sectors << 9;
+ mmc->max_seg_size = mmc->max_req_size;
+
+ /*
+ * Block size can be up to 2048 bytes, but must be a power of two.
+ */
+ mmc->max_blk_size = 2048;
+
+ /*
+ * No limit on the number of blocks transferred.
+ */
+ mmc->max_blk_count = mmc->max_req_size;
spin_lock_init(&host->lock);
diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c
index 435d331e772..1e96a2f6502 100644
--- a/drivers/mmc/omap.c
+++ b/drivers/mmc/omap.c
@@ -91,7 +91,6 @@
#define DRIVER_NAME "mmci-omap"
-#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
/* Specifies how often in millisecs to poll for card status changes
* when the cover switch is open */
@@ -204,18 +203,22 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
cmdtype = 0;
/* Our hardware needs to know exact type */
- switch (RSP_TYPE(mmc_resp_type(cmd))) {
- case RSP_TYPE(MMC_RSP_R1):
- /* resp 1, resp 1b */
+ switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_NONE:
+ break;
+ case MMC_RSP_R1:
+ case MMC_RSP_R1B:
+ /* resp 1, 1b, 6, 7 */
resptype = 1;
break;
- case RSP_TYPE(MMC_RSP_R2):
+ case MMC_RSP_R2:
resptype = 2;
break;
- case RSP_TYPE(MMC_RSP_R3):
+ case MMC_RSP_R3:
resptype = 3;
break;
default:
+ dev_err(mmc_dev(host->mmc), "Invalid response type: %04x\n", mmc_resp_type(cmd));
break;
}
@@ -581,9 +584,9 @@ static void mmc_omap_switch_timer(unsigned long arg)
schedule_work(&host->switch_work);
}
-static void mmc_omap_switch_handler(void *data)
+static void mmc_omap_switch_handler(struct work_struct *work)
{
- struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+ struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, switch_work);
struct mmc_card *card;
static int complained = 0;
int cards = 0, cover_open;
@@ -1096,8 +1099,10 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
*/
mmc->max_phys_segs = 32;
mmc->max_hw_segs = 32;
- mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */
- mmc->max_seg_size = mmc->max_sectors * 512;
+ mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */
+ mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */
+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_seg_size = mmc->max_req_size;
if (host->power_pin >= 0) {
if ((ret = omap_request_gpio(host->power_pin)) != 0) {
@@ -1116,7 +1121,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, host);
if (host->switch_pin >= 0) {
- INIT_WORK(&host->switch_work, mmc_omap_switch_handler, host);
+ INIT_WORK(&host->switch_work, mmc_omap_switch_handler);
init_timer(&host->switch_timer);
host->switch_timer.function = mmc_omap_switch_timer;
host->switch_timer.data = (unsigned long) host;
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index 471e9f4e053..9774fc68b61 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -171,7 +171,7 @@ static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd,
#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
switch (RSP_TYPE(mmc_resp_type(cmd))) {
- case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6 */
+ case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
cmdat |= CMDAT_RESP_SHORT;
break;
case RSP_TYPE(MMC_RSP_R3):
@@ -355,7 +355,7 @@ static int pxamci_get_ro(struct mmc_host *mmc)
struct pxamci_host *host = mmc_priv(mmc);
if (host->pdata && host->pdata->get_ro)
- return host->pdata->get_ro(mmc->dev);
+ return host->pdata->get_ro(mmc_dev(mmc));
/* Host doesn't support read only detection so assume writeable */
return 0;
}
@@ -383,7 +383,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->power_mode = ios->power_mode;
if (host->pdata && host->pdata->setpower)
- host->pdata->setpower(mmc->dev, ios->vdd);
+ host->pdata->setpower(mmc_dev(mmc), ios->vdd);
if (ios->power_mode == MMC_POWER_ON)
host->cmdat |= CMDAT_INIT;
@@ -450,6 +450,16 @@ static int pxamci_probe(struct platform_device *pdev)
*/
mmc->max_seg_size = PAGE_SIZE;
+ /*
+ * Block length register is 10 bits.
+ */
+ mmc->max_blk_size = 1023;
+
+ /*
+ * Block count register is 16 bits.
+ */
+ mmc->max_blk_count = 65535;
+
host = mmc_priv(mmc);
host->mmc = mmc;
host->dma = -1;
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index cd98117632d..4bf1fea5e2c 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -37,6 +37,7 @@ static unsigned int debug_quirks = 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)
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
static const struct pci_device_id pci_ids[] __devinitdata = {
{
@@ -65,6 +66,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.driver_data = SDHCI_QUIRK_FORCE_DMA,
},
+ {
+ .vendor = PCI_VENDOR_ID_ENE,
+ .device = PCI_DEVICE_ID_ENE_CB712_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+ },
+
{ /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
},
@@ -197,15 +206,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
* *
\*****************************************************************************/
-static inline char* sdhci_kmap_sg(struct sdhci_host* host)
+static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
{
- host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ);
- return host->mapped_sg + host->cur_sg->offset;
-}
-
-static inline void sdhci_kunmap_sg(struct sdhci_host* host)
-{
- kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+ return page_address(host->cur_sg->page) + host->cur_sg->offset;
}
static inline int sdhci_next_sg(struct sdhci_host* host)
@@ -240,7 +243,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
chunk_remain = 0;
data = 0;
- buffer = sdhci_kmap_sg(host) + host->offset;
+ buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
if (chunk_remain == 0) {
@@ -264,16 +267,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
}
if (host->remain == 0) {
- sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0);
return;
}
- buffer = sdhci_kmap_sg(host);
+ buffer = sdhci_sg_to_buffer(host);
}
}
-
- sdhci_kunmap_sg(host);
}
static void sdhci_write_block_pio(struct sdhci_host *host)
@@ -290,7 +290,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
data = 0;
bytes = 0;
- buffer = sdhci_kmap_sg(host) + host->offset;
+ buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
size = min(host->size, host->remain);
@@ -314,16 +314,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
}
if (host->remain == 0) {
- sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0);
return;
}
- buffer = sdhci_kmap_sg(host);
+ buffer = sdhci_sg_to_buffer(host);
}
}
-
- sdhci_kunmap_sg(host);
}
static void sdhci_transfer_pio(struct sdhci_host *host)
@@ -372,7 +369,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
/* Sanity checks */
BUG_ON(data->blksz * data->blocks > 524288);
- BUG_ON(data->blksz > host->max_block);
+ BUG_ON(data->blksz > host->mmc->max_blk_size);
BUG_ON(data->blocks > 65535);
/* timeout in us */
@@ -674,10 +671,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
if (host->power == power)
return;
- writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
-
- if (power == (unsigned short)-1)
+ if (power == (unsigned short)-1) {
+ writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
goto out;
+ }
+
+ /*
+ * Spec says that we should clear the power reg before setting
+ * a new value. Some controllers don't seem to like this though.
+ */
+ if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+ writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
pwr = SDHCI_POWER_ON;
@@ -1109,7 +1113,9 @@ static int sdhci_resume (struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
for (i = 0;i < chip->num_slots;i++) {
if (!chip->hosts[i])
@@ -1170,8 +1176,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
}
if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
- printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. Aborting.\n");
- return -ENODEV;
+ printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
+ "You may experience problems.\n");
}
if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
@@ -1274,15 +1280,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
if (caps & SDHCI_TIMEOUT_CLK_UNIT)
host->timeout_clk *= 1000;
- host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
- if (host->max_block >= 3) {
- printk(KERN_ERR "%s: Invalid maximum block size.\n",
- host->slot_descr);
- ret = -ENODEV;
- goto unmap;
- }
- host->max_block = 512 << host->max_block;
-
/*
* Set host parameters.
*/
@@ -1294,9 +1291,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330)
mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
- else if (caps & SDHCI_CAN_VDD_300)
+ if (caps & SDHCI_CAN_VDD_300)
mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
- else if (caps & SDHCI_CAN_VDD_180)
+ if (caps & SDHCI_CAN_VDD_180)
mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) {
@@ -1326,15 +1323,33 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
/*
* Maximum number of sectors in one transfer. Limited by DMA boundary
- * size (512KiB), which means (512 KiB/512=) 1024 entries.
+ * size (512KiB).
*/
- mmc->max_sectors = 1024;
+ mmc->max_req_size = 524288;
/*
* Maximum segment size. Could be one segment with the maximum number
- * of sectors.
+ * of bytes.
+ */
+ mmc->max_seg_size = mmc->max_req_size;
+
+ /*
+ * Maximum block size. This varies from controller to controller and
+ * is specified in the capabilities register.
+ */
+ mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+ if (mmc->max_blk_size >= 3) {
+ printk(KERN_ERR "%s: Invalid maximum block size.\n",
+ host->slot_descr);
+ ret = -ENODEV;
+ goto unmap;
+ }
+ mmc->max_blk_size = 512 << mmc->max_blk_size;
+
+ /*
+ * Maximum block count.
*/
- mmc->max_seg_size = mmc->max_sectors * 512;
+ mmc->max_blk_count = 65535;
/*
* Init tasklets.
diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h
index f9d1a0a6f03..e324f0a623d 100644
--- a/drivers/mmc/sdhci.h
+++ b/drivers/mmc/sdhci.h
@@ -174,7 +174,6 @@ struct sdhci_host {
unsigned int max_clk; /* Max possible freq (MHz) */
unsigned int timeout_clk; /* Timeout freq (KHz) */
- unsigned int max_block; /* Max block size (bytes) */
unsigned int clock; /* Current clock (MHz) */
unsigned short power; /* Current voltage */
@@ -184,7 +183,6 @@ struct sdhci_host {
struct mmc_data *data; /* Current data request */
struct scatterlist *cur_sg; /* We're working on this */
- char *mapped_sg; /* This is where it's mapped */
int num_sg; /* Entries left */
int offset; /* Offset into current sg */
int remain; /* Bytes left in current */
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
index e846499a004..e65f8a0a934 100644
--- a/drivers/mmc/tifm_sd.c
+++ b/drivers/mmc/tifm_sd.c
@@ -17,7 +17,7 @@
#include <asm/io.h>
#define DRIVER_NAME "tifm_sd"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
static int no_dma = 0;
static int fixed_timeout = 0;
@@ -79,7 +79,6 @@ typedef enum {
enum {
FIFO_RDY = 0x0001, /* hardware dependent value */
- HOST_REG = 0x0002,
EJECT = 0x0004,
EJECT_DONE = 0x0008,
CARD_BUSY = 0x0010,
@@ -95,46 +94,53 @@ struct tifm_sd {
card_state_t state;
unsigned int clk_freq;
unsigned int clk_div;
- unsigned long timeout_jiffies; // software timeout - 2 sec
+ unsigned long timeout_jiffies;
+ struct tasklet_struct finish_tasklet;
+ struct timer_list timer;
struct mmc_request *req;
- struct work_struct cmd_handler;
- struct delayed_work abort_handler;
- wait_queue_head_t can_eject;
+ wait_queue_head_t notify;
size_t written_blocks;
- char *buffer;
size_t buffer_size;
size_t buffer_pos;
};
+static char* tifm_sd_data_buffer(struct mmc_data *data)
+{
+ return page_address(data->sg->page) + data->sg->offset;
+}
+
static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
- unsigned int host_status)
+ unsigned int host_status)
{
struct mmc_command *cmd = host->req->cmd;
unsigned int t_val = 0, cnt = 0;
+ char *buffer;
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)) {
+ if (no_dma && (cmd->data->flags & MMC_DATA_READ)) {
+ buffer = tifm_sd_data_buffer(host->req->data);
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++] =
+ buffer[host->buffer_pos++] = t_val & 0xff;
+ buffer[host->buffer_pos++] =
(t_val >> 8) & 0xff;
}
}
return 1;
- } else if (host->buffer) {
+ } else if (no_dma) {
+ buffer = tifm_sd_data_buffer(host->req->data);
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++] =
+ buffer[host->buffer_pos++] =
t_val & 0xff;
- host->buffer[host->buffer_pos++] =
+ buffer[host->buffer_pos++] =
(t_val >> 8) & 0xff;
}
}
@@ -142,11 +148,12 @@ static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
&& (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;
+ t_val = buffer[host->buffer_pos++]
+ & 0x00ff;
+ t_val |= ((buffer[host->buffer_pos++])
+ << 8) & 0xff00;
writel(t_val,
- sock->addr + SOCK_MMCSD_DATA);
+ sock->addr + SOCK_MMCSD_DATA);
}
}
}
@@ -173,9 +180,6 @@ static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
case MMC_RSP_R3:
rc |= TIFM_MMCSD_RSP_R3;
break;
- case MMC_RSP_R6:
- rc |= TIFM_MMCSD_RSP_R6;
- break;
default:
BUG();
}
@@ -209,7 +213,7 @@ static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
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);
+ 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);
@@ -242,65 +246,78 @@ change_state:
tifm_sd_fetch_resp(cmd, sock);
if (cmd->data) {
host->state = BRS;
- } else
+ } 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;
+ if (cmd->data->flags & MMC_DATA_WRITE) {
+ host->state = CARD;
+ } else {
+ if (no_dma) {
+ if (host->req->stop) {
+ tifm_sd_exec(host, host->req->stop);
+ host->state = SCMD;
+ } else {
+ host->state = READY;
+ }
} else {
- host->state =
- host->buffer ? READY : FIFO;
+ host->state = FIFO;
}
- goto change_state;
}
- tifm_sd_exec(host, host->req->stop);
- host->state = SCMD;
+ goto change_state;
}
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;
- }
+ host->state = READY;
goto change_state;
}
break;
case CARD:
+ dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n",
+ host->written_blocks);
if (!(host->flags & CARD_BUSY)
&& (host->written_blocks == cmd->data->blocks)) {
- host->state = host->buffer ? READY : FIFO;
+ if (no_dma) {
+ if (host->req->stop) {
+ tifm_sd_exec(host, host->req->stop);
+ host->state = SCMD;
+ } else {
+ host->state = READY;
+ }
+ } else {
+ host->state = FIFO;
+ }
goto change_state;
}
break;
case FIFO:
if (host->flags & FIFO_RDY) {
- host->state = READY;
host->flags &= ~FIFO_RDY;
+ if (host->req->stop) {
+ tifm_sd_exec(host, host->req->stop);
+ host->state = SCMD;
+ } else {
+ host->state = READY;
+ }
goto change_state;
}
break;
case READY:
- queue_work(sock->wq, &host->cmd_handler);
+ tasklet_schedule(&host->finish_tasklet);
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)
+static void 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;
@@ -308,7 +325,6 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
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);
@@ -321,19 +337,17 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
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))
+ 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))
+ else if (host_status
+ & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
error_code = MMC_ERR_BADCRC;
writel(TIFM_FIFO_INT_SETALL,
@@ -343,12 +357,11 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
if (host->req->stop) {
if (host->state == SCMD) {
host->req->stop->error = error_code;
- } else if(host->state == BRS) {
+ } else if (host->state == BRS
+ || host->state == CARD
+ || host->state == FIFO) {
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 {
@@ -362,8 +375,8 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
if (host_status & TIFM_MMCSD_CB)
host->flags |= CARD_BUSY;
- if ((host_status & TIFM_MMCSD_EOFB) &&
- (host->flags & CARD_BUSY)) {
+ if ((host_status & TIFM_MMCSD_EOFB)
+ && (host->flags & CARD_BUSY)) {
host->written_blocks++;
host->flags &= ~CARD_BUSY;
}
@@ -373,22 +386,22 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
tifm_sd_process_cmd(sock, host, host_status);
done:
dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
- host_status, fifo_status);
+ 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)
+static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd)
{
- struct tifm_dev *sock = card->dev;
+ struct tifm_dev *sock = host->dev;
unsigned int dest_cnt;
/* DMA style IO */
-
+ dev_dbg(&sock->dev, "setting dma for %d blocks\n",
+ cmd->data->blocks);
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);
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(ilog2(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);
@@ -402,7 +415,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
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);
+ 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);
@@ -410,7 +423,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
}
static void tifm_sd_set_data_timeout(struct tifm_sd *host,
- struct mmc_data *data)
+ struct mmc_data *data)
{
struct tifm_dev *sock = host->dev;
unsigned int data_timeout = data->timeout_clks;
@@ -419,22 +432,21 @@ static void tifm_sd_set_data_timeout(struct tifm_sd *host,
return;
data_timeout += data->timeout_ns /
- ((1000000000 / host->clk_freq) * host->clk_div);
- data_timeout *= 10; // call it fudge factor for now
+ ((1000000000UL / host->clk_freq) * host->clk_div);
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);
+ writel((~TIFM_MMCSD_DPE)
+ & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
} 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)
+ if (data_timeout > 0xffff)
data_timeout = 0; /* set to unlimited */
writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+ writel(TIFM_MMCSD_DPE
+ | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
}
}
@@ -477,11 +489,10 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
}
host->req = mrq;
+ mod_timer(&host->timer, jiffies + host->timeout_jiffies);
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);
+ sock->addr + SOCK_CONTROL);
tifm_sd_exec(host, mrq->cmd);
spin_unlock_irqrestore(&sock->lock, flags);
return;
@@ -496,9 +507,9 @@ err_out:
mmc_request_done(mmc, mrq);
}
-static void tifm_sd_end_cmd(struct work_struct *work)
+static void tifm_sd_end_cmd(unsigned long data)
{
- struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+ 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;
@@ -507,6 +518,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
spin_lock_irqsave(&sock->lock, flags);
+ del_timer(&host->timer);
mrq = host->req;
host->req = NULL;
host->state = IDLE;
@@ -520,8 +532,8 @@ static void tifm_sd_end_cmd(struct work_struct *work)
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;
+ 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;
@@ -535,7 +547,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
}
writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ sock->addr + SOCK_CONTROL);
spin_unlock_irqrestore(&sock->lock, flags);
mmc_request_done(mmc, mrq);
@@ -547,15 +559,6 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
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) {
@@ -572,15 +575,14 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
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;
+ host->buffer_size = mrq->cmd->data->blocks
+ * mrq->cmd->data->blksz;
- writel(TIFM_MMCSD_BUFINT |
- readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+ 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),
+ writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
+ | (TIFM_MMCSD_FIFO_SIZE - 1),
sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
host->written_blocks = 0;
@@ -591,26 +593,22 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
}
host->req = mrq;
+ mod_timer(&host->timer, jiffies + host->timeout_jiffies);
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);
+ 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(struct work_struct *work)
+static void tifm_sd_end_cmd_nodma(unsigned long data)
{
- struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+ 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;
@@ -619,6 +617,7 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
spin_lock_irqsave(&sock->lock, flags);
+ del_timer(&host->timer);
mrq = host->req;
host->req = NULL;
host->state = IDLE;
@@ -636,8 +635,8 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
sock->addr + SOCK_MMCSD_INT_ENABLE);
if (r_data->flags & MMC_DATA_WRITE) {
- r_data->bytes_xfered = host->written_blocks *
- r_data->blksz;
+ 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;
@@ -645,29 +644,44 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
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);
+ 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(struct work_struct *work)
+static void tifm_sd_terminate(struct tifm_sd *host)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned long flags;
+
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+ spin_lock_irqsave(&sock->lock, flags);
+ host->flags |= EJECT;
+ if (host->req) {
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+ tasklet_schedule(&host->finish_tasklet);
+ }
+ spin_unlock_irqrestore(&sock->lock, flags);
+}
+
+static void tifm_sd_abort(unsigned long data)
{
- struct tifm_sd *host =
- container_of(work, struct tifm_sd, abort_handler.work);
+ struct tifm_sd *host = (struct tifm_sd*)data;
printk(KERN_ERR DRIVER_NAME
- ": card failed to respond for a long period of time");
+ ": card failed to respond for a long period of time");
+
+ tifm_sd_terminate(host);
tifm_eject(host->dev);
}
@@ -686,9 +700,9 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
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);
+ writel((~TIFM_MMCSD_4BBUS)
+ & readl(sock->addr + SOCK_MMCSD_CONFIG),
+ sock->addr + SOCK_MMCSD_CONFIG);
}
if (ios->clock) {
@@ -707,23 +721,24 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
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);
+ 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);
+ 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);
+ 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;
@@ -737,7 +752,7 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
// allow removal.
if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
host->flags |= EJECT_DONE;
- wake_up_all(&host->can_eject);
+ wake_up_all(&host->notify);
}
spin_unlock_irqrestore(&sock->lock, flags);
@@ -765,20 +780,67 @@ static struct mmc_host_ops tifm_sd_ops = {
.get_ro = tifm_sd_ro
};
-static void tifm_sd_register_host(struct work_struct *work)
+static int tifm_sd_initialize_host(struct tifm_sd *host)
{
- struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+ int rc;
+ unsigned int host_status = 0;
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);
- spin_unlock_irqrestore(&sock->lock, flags);
- dev_dbg(&sock->dev, "adding host\n");
- mmc_add_host(mmc);
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+ host->clk_div = 61;
+ host->clk_freq = 20000000;
+ writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+
+ /* wait up to 0.51 sec for reset */
+ for (rc = 2; rc <= 256; rc <<= 1) {
+ if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
+ rc = 0;
+ break;
+ }
+ msleep(rc);
+ }
+
+ if (rc) {
+ printk(KERN_ERR DRIVER_NAME
+ ": controller failed to reset\n");
+ 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);
+
+ // command timeout fixed to 64 clocks for now
+ writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
+ writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
+
+ /* INAB should take much less than reset */
+ for (rc = 1; rc <= 16; rc <<= 1) {
+ host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+ writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+ if (!(host_status & TIFM_MMCSD_ERRMASK)
+ && (host_status & TIFM_MMCSD_EOC)) {
+ rc = 0;
+ break;
+ }
+ msleep(rc);
+ }
+
+ if (rc) {
+ printk(KERN_ERR DRIVER_NAME
+ ": card not ready - probe failed on initialization\n");
+ return -ENODEV;
+ }
+
+ writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+
+ return 0;
}
static int tifm_sd_probe(struct tifm_dev *sock)
@@ -787,8 +849,8 @@ static int tifm_sd_probe(struct tifm_dev *sock)
struct tifm_sd *host;
int rc = -EIO;
- if (!(TIFM_SOCK_STATE_OCCUPIED &
- readl(sock->addr + SOCK_PRESENT_STATE))) {
+ if (!(TIFM_SOCK_STATE_OCCUPIED
+ & readl(sock->addr + SOCK_PRESENT_STATE))) {
printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
return rc;
}
@@ -798,109 +860,99 @@ static int tifm_sd_probe(struct tifm_dev *sock)
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);
- INIT_DELAYED_WORK(&host->abort_handler, tifm_sd_abort);
-
tifm_set_drvdata(sock, mmc);
- sock->signal_irq = tifm_sd_signal_irq;
-
- host->clk_freq = 20000000;
+ host->dev = sock;
host->timeout_jiffies = msecs_to_jiffies(1000);
+ init_waitqueue_head(&host->notify);
+ tasklet_init(&host->finish_tasklet,
+ no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
+ (unsigned long)host);
+ setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
+
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->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
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);
+ // limited by DMA counter - it's safer to stick with
+ // block counter has 11 bits though
+ mmc->max_blk_count = 256;
+ // 2k maximum hw block length
+ mmc->max_blk_size = 2048;
+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_seg_size = mmc->max_req_size;
+ sock->signal_irq = tifm_sd_signal_irq;
+ rc = tifm_sd_initialize_host(host);
- 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)
+ rc = mmc_add_host(mmc);
+ if (rc)
+ goto out_free_mmc;
- if (rc) {
- printk(KERN_ERR DRIVER_NAME
- ": card not ready - probe failed\n");
- mmc_free_host(mmc);
- return -ENODEV;
- }
+ return 0;
+out_free_mmc:
+ mmc_free_host(mmc);
+ return rc;
+}
- 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);
+static void tifm_sd_remove(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct tifm_sd *host = mmc_priv(mmc);
- 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);
+ del_timer_sync(&host->timer);
+ tifm_sd_terminate(host);
+ wait_event_timeout(host->notify, host->flags & EJECT_DONE,
+ host->timeout_jiffies);
+ tasklet_kill(&host->finish_tasklet);
+ mmc_remove_host(mmc);
- queue_delayed_work(sock->wq, &host->abort_handler,
- host->timeout_jiffies);
+ /* The meaning of the bit majority in this constant is unknown. */
+ writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
- return 0;
+ tifm_set_drvdata(sock, NULL);
+ mmc_free_host(mmc);
}
-static int tifm_sd_host_is_down(struct tifm_dev *sock)
+#ifdef CONFIG_PM
+
+static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
{
struct mmc_host *mmc = tifm_get_drvdata(sock);
- struct tifm_sd *host = mmc_priv(mmc);
- unsigned long flags;
- int rc = 0;
+ int rc;
- spin_lock_irqsave(&sock->lock, flags);
- rc = (host->flags & EJECT_DONE);
- spin_unlock_irqrestore(&sock->lock, flags);
+ rc = mmc_suspend_host(mmc, state);
+ /* The meaning of the bit majority in this constant is unknown. */
+ writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
return rc;
}
-static void tifm_sd_remove(struct tifm_dev *sock)
+static int tifm_sd_resume(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 (sock->media_id != FM_SD
+ || tifm_sd_initialize_host(host)) {
+ tifm_eject(sock);
+ return 0;
+ } else {
+ return mmc_resume_host(mmc);
+ }
+}
- if (host->flags & HOST_REG)
- mmc_remove_host(mmc);
+#else
- /* 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);
+#define tifm_sd_suspend NULL
+#define tifm_sd_resume NULL
- tifm_set_drvdata(sock, NULL);
- mmc_free_host(mmc);
-}
+#endif /* CONFIG_PM */
static tifm_media_id tifm_sd_id_tbl[] = {
FM_SD, 0
@@ -913,7 +965,9 @@ static struct tifm_driver tifm_sd_driver = {
},
.id_table = tifm_sd_id_tbl,
.probe = tifm_sd_probe,
- .remove = tifm_sd_remove
+ .remove = tifm_sd_remove,
+ .suspend = tifm_sd_suspend,
+ .resume = tifm_sd_resume
};
static int __init tifm_sd_init(void)
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 7a282672f8e..a44d8777ab9 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
*
- * Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
+ * Copyright (C) 2004-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 as published by
@@ -272,16 +272,9 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
return host->num_sg;
}
-static inline char *wbsd_kmap_sg(struct wbsd_host *host)
+static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
{
- host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) +
- host->cur_sg->offset;
- return host->mapped_sg;
-}
-
-static inline void wbsd_kunmap_sg(struct wbsd_host *host)
-{
- kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+ return page_address(host->cur_sg->page) + host->cur_sg->offset;
}
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
@@ -302,12 +295,11 @@ static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
* we do not transfer too much.
*/
for (i = 0; i < len; i++) {
- sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+ sgbuf = page_address(sg[i].page) + sg[i].offset;
if (size < sg[i].length)
memcpy(dmabuf, sgbuf, size);
else
memcpy(dmabuf, sgbuf, sg[i].length);
- kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
dmabuf += sg[i].length;
if (size < sg[i].length)
@@ -347,7 +339,7 @@ static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
* we do not transfer too much.
*/
for (i = 0; i < len; i++) {
- sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+ sgbuf = page_address(sg[i].page) + sg[i].offset;
if (size < sg[i].length)
memcpy(sgbuf, dmabuf, size);
else
@@ -497,7 +489,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size)
return;
- buffer = wbsd_kmap_sg(host) + host->offset;
+ buffer = wbsd_sg_to_buffer(host) + host->offset;
/*
* Drain the fifo. This has a tendency to loop longer
@@ -526,17 +518,13 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
/*
* Transfer done?
*/
- if (data->bytes_xfered == host->size) {
- wbsd_kunmap_sg(host);
+ if (data->bytes_xfered == host->size)
return;
- }
/*
* End of scatter list entry?
*/
if (host->remain == 0) {
- wbsd_kunmap_sg(host);
-
/*
* Get next entry. Check if last.
*/
@@ -554,13 +542,11 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
return;
}
- buffer = wbsd_kmap_sg(host);
+ buffer = wbsd_sg_to_buffer(host);
}
}
}
- wbsd_kunmap_sg(host);
-
/*
* This is a very dirty hack to solve a
* hardware problem. The chip doesn't trigger
@@ -583,7 +569,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size)
return;
- buffer = wbsd_kmap_sg(host) + host->offset;
+ buffer = wbsd_sg_to_buffer(host) + host->offset;
/*
* Fill the fifo. This has a tendency to loop longer
@@ -612,17 +598,13 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
/*
* Transfer done?
*/
- if (data->bytes_xfered == host->size) {
- wbsd_kunmap_sg(host);
+ if (data->bytes_xfered == host->size)
return;
- }
/*
* End of scatter list entry?
*/
if (host->remain == 0) {
- wbsd_kunmap_sg(host);
-
/*
* Get next entry. Check if last.
*/
@@ -640,13 +622,11 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
return;
}
- buffer = wbsd_kmap_sg(host);
+ buffer = wbsd_sg_to_buffer(host);
}
}
}
- wbsd_kunmap_sg(host);
-
/*
* The controller stops sending interrupts for
* 'FIFO empty' under certain conditions. So we
@@ -910,6 +890,45 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
*/
if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
/*
+ * The hardware is so delightfully stupid that it has a list
+ * of "data" commands. If a command isn't on this list, it'll
+ * just go back to the idle state and won't send any data
+ * interrupts.
+ */
+ switch (cmd->opcode) {
+ case 11:
+ case 17:
+ case 18:
+ case 20:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 30:
+ case 42:
+ case 56:
+ break;
+
+ /* ACMDs. We don't keep track of state, so we just treat them
+ * like any other command. */
+ case 51:
+ break;
+
+ default:
+#ifdef CONFIG_MMC_DEBUG
+ printk(KERN_WARNING "%s: Data command %d is not "
+ "supported by this controller.\n",
+ mmc_hostname(host->mmc), cmd->opcode);
+#endif
+ cmd->data->error = MMC_ERR_INVALID;
+
+ if (cmd->data->stop)
+ wbsd_send_command(host, cmd->data->stop);
+
+ goto done;
+ };
+
+ /*
* Dirty fix for hardware bug.
*/
if (host->dma == -1)
@@ -1343,16 +1362,27 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
mmc->max_phys_segs = 128;
/*
- * Maximum number of sectors in one transfer. Also limited by 64kB
- * buffer.
+ * Maximum request size. Also limited by 64KiB buffer.
*/
- mmc->max_sectors = 128;
+ mmc->max_req_size = 65536;
/*
* Maximum segment size. Could be one segment with the maximum number
- * of segments.
+ * of bytes.
+ */
+ mmc->max_seg_size = mmc->max_req_size;
+
+ /*
+ * Maximum block size. We have 12 bits (= 4095) but have to subtract
+ * space for CRC. So the maximum is 4095 - 4*2 = 4087.
+ */
+ mmc->max_blk_size = 4087;
+
+ /*
+ * Maximum block count. There is no real limit so the maximum
+ * request size will be the only restriction.
*/
- mmc->max_seg_size = mmc->max_sectors * 512;
+ mmc->max_blk_count = mmc->max_req_size;
dev_set_drvdata(dev, mmc);
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
index 6072993f01e..d06718b0e2a 100644
--- a/drivers/mmc/wbsd.h
+++ b/drivers/mmc/wbsd.h
@@ -154,7 +154,6 @@ struct wbsd_host
struct scatterlist* cur_sg; /* Current SG entry */
unsigned int num_sg; /* Number of entries left */
- void* mapped_sg; /* vaddr of mapped sg */
unsigned int offset; /* Offset into current entry */
unsigned int remain; /* Data left in curren entry */
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index a304b34c263..26f75c29944 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -164,9 +164,15 @@ config MTD_CHAR
memory chips, and also use ioctl() to obtain information about
the device, or to erase parts of it.
+config MTD_BLKDEVS
+ tristate "Common interface to block layer for MTD 'translation layers'"
+ depends on MTD && BLOCK
+ default n
+
config MTD_BLOCK
tristate "Caching block device access to MTD devices"
depends on MTD && BLOCK
+ select MTD_BLKDEVS
---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
@@ -189,6 +195,7 @@ config MTD_BLOCK
config MTD_BLOCK_RO
tristate "Readonly block device access to MTD devices"
depends on MTD_BLOCK!=y && MTD && BLOCK
+ select MTD_BLKDEVS
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
@@ -200,6 +207,7 @@ config MTD_BLOCK_RO
config FTL
tristate "FTL (Flash Translation Layer) support"
depends on MTD && BLOCK
+ select MTD_BLKDEVS
---help---
This provides support for the original Flash Translation Layer which
is part of the PCMCIA specification. It uses a kind of pseudo-
@@ -216,6 +224,7 @@ config FTL
config NFTL
tristate "NFTL (NAND Flash Translation Layer) support"
depends on MTD && BLOCK
+ select MTD_BLKDEVS
---help---
This provides support for the NAND Flash Translation Layer which is
used on M-Systems' DiskOnChip devices. It uses a kind of pseudo-
@@ -239,6 +248,7 @@ config NFTL_RW
config INFTL
tristate "INFTL (Inverse NAND Flash Translation Layer) support"
depends on MTD && BLOCK
+ select MTD_BLKDEVS
---help---
This provides support for the Inverse NAND Flash Translation
Layer which is used on M-Systems' newer DiskOnChip devices. It
@@ -256,6 +266,7 @@ config INFTL
config RFD_FTL
tristate "Resident Flash Disk (Flash Translation Layer) support"
depends on MTD && BLOCK
+ select MTD_BLKDEVS
---help---
This provides support for the flash translation layer known
as the Resident Flash Disk (RFD), as used by the Embedded BIOS
@@ -265,8 +276,8 @@ config RFD_FTL
config SSFDC
tristate "NAND SSFDC (SmartMedia) read only translation layer"
- depends on MTD
- default n
+ depends on MTD && BLOCK
+ select MTD_BLKDEVS
help
This enables read only access to SmartMedia formatted NAND
flash. You can mount it with FAT file system.
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 1e36b9aed98..c130e6261ad 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -15,13 +15,14 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o
-obj-$(CONFIG_MTD_BLOCK) += mtdblock.o mtd_blkdevs.o
-obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs.o
-obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o
-obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o
-obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o
-obj-$(CONFIG_RFD_FTL) += rfd_ftl.o mtd_blkdevs.o
-obj-$(CONFIG_SSFDC) += ssfdc.o mtd_blkdevs.o
+obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
+obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
+obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o
+obj-$(CONFIG_FTL) += ftl.o
+obj-$(CONFIG_NFTL) += nftl.o
+obj-$(CONFIG_INFTL) += inftl.o
+obj-$(CONFIG_RFD_FTL) += rfd_ftl.o
+obj-$(CONFIG_SSFDC) += ssfdc.o
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c
index 6a45be04564..52d51eb91c1 100644
--- a/drivers/mtd/afs.c
+++ b/drivers/mtd/afs.c
@@ -207,11 +207,10 @@ static int parse_afs_partitions(struct mtd_info *mtd,
if (!sz)
return ret;
- parts = kmalloc(sz, GFP_KERNEL);
+ parts = kzalloc(sz, GFP_KERNEL);
if (!parts)
return -ENOMEM;
- memset(parts, 0, sz);
str = (char *)(parts + idx);
/*
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
index 16eaca69fb5..e7999f15d85 100644
--- a/drivers/mtd/chips/amd_flash.c
+++ b/drivers/mtd/chips/amd_flash.c
@@ -643,13 +643,12 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
int reg_idx;
int offset;
- mtd = (struct mtd_info*)kmalloc(sizeof(*mtd), GFP_KERNEL);
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd) {
printk(KERN_WARNING
"%s: kmalloc failed for info structure\n", map->name);
return NULL;
}
- memset(mtd, 0, sizeof(*mtd));
mtd->priv = map;
memset(&temp, 0, sizeof(temp));
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 296159ec518..f69184a92eb 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -337,12 +337,11 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
struct mtd_info *mtd;
int i;
- mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd) {
printk(KERN_ERR "Failed to allocate memory for MTD device\n");
return NULL;
}
- memset(mtd, 0, sizeof(*mtd));
mtd->priv = map;
mtd->type = MTD_NORFLASH;
@@ -2224,6 +2223,8 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
case FL_CFI_QUERY:
case FL_JEDEC_QUERY:
if (chip->oldstate == FL_READY) {
+ /* place the chip in a known state before suspend */
+ map_write(map, CMD(0xFF), cfi->chips[i].start);
chip->oldstate = chip->state;
chip->state = FL_PM_SUSPENDED;
/* No need to wake_up() on this state change -
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 702ae4cd869..e3acd398fb3 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -48,6 +48,7 @@
#define MANUFACTURER_ATMEL 0x001F
#define MANUFACTURER_SST 0x00BF
#define SST49LF004B 0x0060
+#define SST49LF040B 0x0050
#define SST49LF008A 0x005a
#define AT49BV6416 0x00d6
@@ -233,6 +234,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
};
static struct cfi_fixup jedec_fixup_table[] = {
{ MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },
+ { MANUFACTURER_SST, SST49LF040B, fixup_use_fwh_lock, NULL, },
{ MANUFACTURER_SST, SST49LF008A, fixup_use_fwh_lock, NULL, },
{ 0, 0, NULL, NULL }
};
@@ -255,12 +257,11 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
struct mtd_info *mtd;
int i;
- mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd) {
printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
return NULL;
}
- memset(mtd, 0, sizeof(*mtd));
mtd->priv = map;
mtd->type = MTD_NORFLASH;
@@ -519,10 +520,12 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
goto sleep;
- if (!(mode == FL_READY || mode == FL_POINT
+ if (!( mode == FL_READY
+ || mode == FL_POINT
|| !cfip
|| (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))
- || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1))))
+ || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1)
+ )))
goto sleep;
/* We could check to see if we're trying to access the sector
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index fae70a5db54..d56849f5f10 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -172,7 +172,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
int i,j;
unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
- mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
//printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);
if (!mtd) {
@@ -181,7 +181,6 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
return NULL;
}
- memset(mtd, 0, sizeof(*mtd));
mtd->priv = map;
mtd->type = MTD_NORFLASH;
mtd->size = devsize * cfi->numchips;
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c
index cdb0f590b40..2eb696d7b97 100644
--- a/drivers/mtd/chips/gen_probe.c
+++ b/drivers/mtd/chips/gen_probe.c
@@ -40,7 +40,7 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
if (mtd) {
if (mtd->size > map->size) {
printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n",
- (unsigned long)mtd->size >> 10,
+ (unsigned long)mtd->size >> 10,
(unsigned long)map->size >> 10);
mtd->size = map->size;
}
@@ -113,13 +113,12 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
}
mapsize = (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG;
- chip_map = kmalloc(mapsize, GFP_KERNEL);
+ chip_map = kzalloc(mapsize, GFP_KERNEL);
if (!chip_map) {
printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
kfree(cfi.cfiq);
return NULL;
}
- memset (chip_map, 0, mapsize);
set_bit(0, chip_map); /* Mark first chip valid */
diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c
index 2c3f019197c..14e57b2bf84 100644
--- a/drivers/mtd/chips/jedec.c
+++ b/drivers/mtd/chips/jedec.c
@@ -116,11 +116,10 @@ static struct mtd_info *jedec_probe(struct map_info *map)
char Part[200];
memset(&priv,0,sizeof(priv));
- MTD = kmalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL);
+ MTD = kzalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL);
if (!MTD)
return NULL;
- memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private));
priv = (struct jedec_private *)&MTD[1];
my_bank_size = map->size;
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 1154dac715a..58e561e8769 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -154,6 +154,7 @@
#define SST39SF010A 0x00B5
#define SST39SF020A 0x00B6
#define SST49LF004B 0x0060
+#define SST49LF040B 0x0050
#define SST49LF008A 0x005a
#define SST49LF030A 0x001C
#define SST49LF040A 0x0051
@@ -1401,6 +1402,20 @@ static const struct amd_flash_info jedec_table[] = {
}
}, {
.mfr_id = MANUFACTURER_SST,
+ .dev_id = SST49LF040B,
+ .name = "SST 49LF040B",
+ .uaddr = {
+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+ },
+ .DevSize = SIZE_512KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 1,
+ .regions = {
+ ERASEINFO(0x01000,128),
+ }
+ }, {
+
+ .mfr_id = MANUFACTURER_SST,
.dev_id = SST49LF004B,
.name = "SST 49LF004B",
.uaddr = {
@@ -1874,7 +1889,7 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
/*
- * There is a BIG problem properly ID'ing the JEDEC devic and guaranteeing
+ * There is a BIG problem properly ID'ing the JEDEC device and guaranteeing
* the mapped address, unlock addresses, and proper chip ID. This function
* attempts to minimize errors. It is doubtfull that this probe will ever
* be perfect - consequently there should be some module parameters that
diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c
index ac01a949b68..fc478c0f93f 100644
--- a/drivers/mtd/chips/map_absent.c
+++ b/drivers/mtd/chips/map_absent.c
@@ -47,13 +47,11 @@ static struct mtd_info *map_absent_probe(struct map_info *map)
{
struct mtd_info *mtd;
- mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd) {
return NULL;
}
- memset(mtd, 0, sizeof(*mtd));
-
map->fldrv = &map_absent_chipdrv;
mtd->priv = map;
mtd->name = map->name;
diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c
index 3a66680abfd..5cb6d526366 100644
--- a/drivers/mtd/chips/map_ram.c
+++ b/drivers/mtd/chips/map_ram.c
@@ -55,12 +55,10 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
#endif
/* OK. It seems to be RAM. */
- mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd)
return NULL;
- memset(mtd, 0, sizeof(*mtd));
-
map->fldrv = &mapram_chipdrv;
mtd->priv = map;
mtd->name = map->name;
diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c
index 1b328b1378f..cb27f855074 100644
--- a/drivers/mtd/chips/map_rom.c
+++ b/drivers/mtd/chips/map_rom.c
@@ -31,12 +31,10 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
{
struct mtd_info *mtd;
- mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd)
return NULL;
- memset(mtd, 0, sizeof(*mtd));
-
map->fldrv = &maprom_chipdrv;
mtd->priv = map;
mtd->name = map->name;
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
index 967abbecdff..c9cd3d21ccf 100644
--- a/drivers/mtd/chips/sharp.c
+++ b/drivers/mtd/chips/sharp.c
@@ -112,18 +112,16 @@ static struct mtd_info *sharp_probe(struct map_info *map)
struct sharp_info *sharp = NULL;
int width;
- mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if(!mtd)
return NULL;
- sharp = kmalloc(sizeof(*sharp), GFP_KERNEL);
+ sharp = kzalloc(sizeof(*sharp), GFP_KERNEL);
if(!sharp) {
kfree(mtd);
return NULL;
}
- memset(mtd, 0, sizeof(*mtd));
-
width = sharp_probe_map(map,mtd);
if(!width){
kfree(mtd);
@@ -143,7 +141,6 @@ static struct mtd_info *sharp_probe(struct map_info *map)
mtd->writesize = 1;
mtd->name = map->name;
- memset(sharp, 0, sizeof(*sharp));
sharp->chipshift = 23;
sharp->numchips = 1;
sharp->chips[0].start = 0;
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
index a7a7bfe3387..23fab14f163 100644
--- a/drivers/mtd/cmdlinepart.c
+++ b/drivers/mtd/cmdlinepart.c
@@ -163,13 +163,12 @@ static struct mtd_partition * newpart(char *s,
*num_parts = this_part + 1;
alloc_size = *num_parts * sizeof(struct mtd_partition) +
extra_mem_size;
- parts = kmalloc(alloc_size, GFP_KERNEL);
+ parts = kzalloc(alloc_size, GFP_KERNEL);
if (!parts)
{
printk(KERN_ERR ERRP "out of memory\n");
return NULL;
}
- memset(parts, 0, alloc_size);
extra_mem = (unsigned char *)(parts + *num_parts);
}
/* enter this partition (offset will be calculated later if it is zero at this point) */
@@ -346,7 +345,7 @@ static int parse_cmdline_partitions(struct mtd_info *master,
*
* This function needs to be visible for bootloaders.
*/
-int mtdpart_setup(char *s)
+static int mtdpart_setup(char *s)
{
cmdline = s;
return 1;
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 401c6a294ba..6d917a4daa9 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -295,10 +295,9 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
if (!devname)
return NULL;
- dev = kmalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
if (!dev)
return NULL;
- memset(dev, 0, sizeof(*dev));
/* Get a handle on the device */
bdev = open_bdev_excl(devname, O_RDWR, NULL);
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 334e078ffaf..78c2511ae9e 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -437,7 +437,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
* or JEDEC get-id commands. Try them ...
*/
DEBUG(MTD_DEBUG_LEVEL1, "%s: no chip id\n",
- flash->spi->dev.bus_id);
+ spi->dev.bus_id);
return -ENODEV;
}
@@ -447,7 +447,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
}
if (i == ARRAY_SIZE(m25p_data)) {
DEBUG(MTD_DEBUG_LEVEL1, "%s: unrecognized id %s\n",
- flash->spi->dev.bus_id, data->type);
+ spi->dev.bus_id, data->type);
return -ENODEV;
}
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c
index 08dfb899b27..9cff119a202 100644
--- a/drivers/mtd/devices/ms02-nv.c
+++ b/drivers/mtd/devices/ms02-nv.c
@@ -131,11 +131,10 @@ static int __init ms02nv_init_one(ulong addr)
int ret = -ENODEV;
/* The module decodes 8MiB of address space. */
- mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL);
+ mod_res = kzalloc(sizeof(*mod_res), GFP_KERNEL);
if (!mod_res)
return -ENOMEM;
- memset(mod_res, 0, sizeof(*mod_res));
mod_res->name = ms02nv_name;
mod_res->start = addr;
mod_res->end = addr + MS02NV_SLOT_SIZE - 1;
@@ -153,24 +152,21 @@ static int __init ms02nv_init_one(ulong addr)
}
ret = -ENOMEM;
- mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd)
goto err_out_mod_res_rel;
- memset(mtd, 0, sizeof(*mtd));
- mp = kmalloc(sizeof(*mp), GFP_KERNEL);
+ mp = kzalloc(sizeof(*mp), GFP_KERNEL);
if (!mp)
goto err_out_mtd;
- memset(mp, 0, sizeof(*mp));
mtd->priv = mp;
mp->resource.module = mod_res;
/* Firmware's diagnostic NVRAM area. */
- diag_res = kmalloc(sizeof(*diag_res), GFP_KERNEL);
+ diag_res = kzalloc(sizeof(*diag_res), GFP_KERNEL);
if (!diag_res)
goto err_out_mp;
- memset(diag_res, 0, sizeof(*diag_res));
diag_res->name = ms02nv_res_diag_ram;
diag_res->start = addr;
diag_res->end = addr + MS02NV_RAM - 1;
@@ -180,11 +176,10 @@ static int __init ms02nv_init_one(ulong addr)
mp->resource.diag_ram = diag_res;
/* User-available general-purpose NVRAM area. */
- user_res = kmalloc(sizeof(*user_res), GFP_KERNEL);
+ user_res = kzalloc(sizeof(*user_res), GFP_KERNEL);
if (!user_res)
goto err_out_diag_res;
- memset(user_res, 0, sizeof(*user_res));
user_res->name = ms02nv_res_user_ram;
user_res->start = addr + MS02NV_RAM;
user_res->end = addr + size - 1;
@@ -194,11 +189,10 @@ static int __init ms02nv_init_one(ulong addr)
mp->resource.user_ram = user_res;
/* Control and status register. */
- csr_res = kmalloc(sizeof(*csr_res), GFP_KERNEL);
+ csr_res = kzalloc(sizeof(*csr_res), GFP_KERNEL);
if (!csr_res)
goto err_out_user_res;
- memset(csr_res, 0, sizeof(*csr_res));
csr_res->name = ms02nv_res_csr;
csr_res->start = addr + MS02NV_CSR;
csr_res->end = addr + MS02NV_CSR + 3;
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index 5db71604592..a987e917f4e 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -459,7 +459,7 @@ add_dataflash(struct spi_device *spi, char *name,
struct mtd_info *device;
struct flash_platform_data *pdata = spi->dev.platform_data;
- priv = (struct dataflash *) kzalloc(sizeof *priv, GFP_KERNEL);
+ priv = kzalloc(sizeof *priv, GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -480,7 +480,7 @@ add_dataflash(struct spi_device *spi, char *name,
device->writesize = pagesize;
device->owner = THIS_MODULE;
device->type = MTD_DATAFLASH;
- device->flags = MTD_CAP_NORFLASH;
+ device->flags = MTD_WRITEABLE;
device->erase = dataflash_erase;
device->read = dataflash_read;
device->write = dataflash_write;
@@ -536,7 +536,7 @@ static int __devinit dataflash_probe(struct spi_device *spi)
if (status <= 0 || status == 0xff) {
DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n",
spi->dev.bus_id, status);
- if (status == 0xff)
+ if (status == 0 || status == 0xff)
status = -ENODEV;
return status;
}
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 6c7337f9ebb..56cc1ca7ffd 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -126,12 +126,10 @@ static int register_device(char *name, unsigned long start, unsigned long len)
struct phram_mtd_list *new;
int ret = -ENOMEM;
- new = kmalloc(sizeof(*new), GFP_KERNEL);
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
if (!new)
goto out0;
- memset(new, 0, sizeof(*new));
-
ret = -EIO;
new->mtd.priv = ioremap(start, len);
if (!new->mtd.priv) {
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index 542a0c00900..5f49248a485 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -168,19 +168,16 @@ static int register_device(char *name, unsigned long start, unsigned long length
E("slram: Cannot allocate new MTD device.\n");
return(-ENOMEM);
}
- (*curmtd)->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+ (*curmtd)->mtdinfo = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
(*curmtd)->next = NULL;
if ((*curmtd)->mtdinfo) {
- memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info));
(*curmtd)->mtdinfo->priv =
- kmalloc(sizeof(slram_priv_t), GFP_KERNEL);
+ kzalloc(sizeof(slram_priv_t), GFP_KERNEL);
if (!(*curmtd)->mtdinfo->priv) {
kfree((*curmtd)->mtdinfo);
(*curmtd)->mtdinfo = NULL;
- } else {
- memset((*curmtd)->mtdinfo->priv,0,sizeof(slram_priv_t));
}
}
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 8a878b34eca..24235d4f1d2 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -1033,7 +1033,7 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
partition_t *partition;
- partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
+ partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
if (!partition) {
printk(KERN_WARNING "No memory to scan for FTL on %s\n",
@@ -1041,8 +1041,6 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
return;
}
- memset(partition, 0, sizeof(partition_t));
-
partition->mbd.mtd = mtd;
if ((scan_header(partition) == 0) &&
@@ -1054,7 +1052,7 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
le32_to_cpu(partition->header.FormattedSize) >> 10);
#endif
partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
- partition->mbd.blksize = SECTOR_SIZE;
+
partition->mbd.tr = tr;
partition->mbd.devnum = -1;
if (!add_mtd_blktrans_dev((void *)partition))
@@ -1076,6 +1074,7 @@ struct mtd_blktrans_ops ftl_tr = {
.name = "ftl",
.major = FTL_MAJOR,
.part_bits = PART_BITS,
+ .blksize = SECTOR_SIZE,
.readsect = ftl_readsect,
.writesect = ftl_writesect,
.getgeo = ftl_getgeo,
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 4116535805f..b0e396504e6 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -67,17 +67,16 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name);
- inftl = kmalloc(sizeof(*inftl), GFP_KERNEL);
+ inftl = kzalloc(sizeof(*inftl), GFP_KERNEL);
if (!inftl) {
printk(KERN_WARNING "INFTL: Out of memory for data structures\n");
return;
}
- memset(inftl, 0, sizeof(*inftl));
inftl->mbd.mtd = mtd;
inftl->mbd.devnum = -1;
- inftl->mbd.blksize = 512;
+
inftl->mbd.tr = tr;
if (INFTL_mount(inftl) < 0) {
@@ -163,10 +162,9 @@ int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
- ops.len = len;
res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
- *retlen = ops.retlen;
+ *retlen = ops.oobretlen;
return res;
}
@@ -184,10 +182,9 @@ int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
- ops.len = len;
res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
- *retlen = ops.retlen;
+ *retlen = ops.oobretlen;
return res;
}
@@ -945,6 +942,7 @@ static struct mtd_blktrans_ops inftl_tr = {
.name = "inftl",
.major = INFTL_MAJOR,
.part_bits = INFTL_PARTN_BITS,
+ .blksize = 512,
.getgeo = inftl_getgeo,
.readsect = inftl_readblock,
.writesect = inftl_writeblock,
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index d132ed571f1..f457315579d 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -60,6 +60,15 @@ config MTD_PHYSMAP_BANKWIDTH
Ignore this option if you use run-time physmap configuration
(i.e., run-time calling physmap_configure()).
+config MTD_PHYSMAP_OF
+ tristate "Flash device in physical memory map based on OF descirption"
+ depends on PPC_OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
+ help
+ This provides a 'mapping' driver which allows the NOR Flash and
+ ROM driver code to communicate with chips which are mapped
+ physically into the CPU's memory. The mapping description here is
+ taken from OF device tree.
+
config MTD_SUN_UFLASH
tristate "Sun Microsystems userflash support"
depends on SPARC && MTD_CFI
@@ -184,6 +193,24 @@ config MTD_ICHXROM
BE VERY CAREFUL.
+config MTD_ESB2ROM
+ tristate "BIOS flash chip on Intel ESB Controller Hub 2"
+ depends on X86 && MTD_JEDECPROBE && PCI
+ help
+ Support for treating the BIOS flash chip on ESB2 motherboards
+ as an MTD device - with this you can reprogram your BIOS.
+
+ BE VERY CAREFUL.
+
+config MTD_CK804XROM
+ tristate "BIOS flash chip on Nvidia CK804"
+ depends on X86 && MTD_JEDECPROBE
+ help
+ Support for treating the BIOS flash chip on nvidia motherboards
+ as an MTD device - with this you can reprogram your BIOS.
+
+ BE VERY CAREFUL.
+
config MTD_SCB2_FLASH
tristate "BIOS flash chip on Intel SCB2 boards"
depends on X86 && MTD_JEDECPROBE
@@ -355,50 +382,6 @@ config MTD_TQM834x
TQ Components TQM834x boards. If you have one of these boards
and would like to use the flash chips on it, say 'Y'.
-config MTD_CSTM_MIPS_IXX
- tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board"
- depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS
- help
- This provides a mapping driver for the Integrated Technology
- Express, Inc (ITE) QED-4N-S01B eval board and the Globespan IVR
- Reference Board. It provides the necessary addressing, length,
- buswidth, vpp code and addition setup of the flash device for
- these boards. In addition, this mapping driver can be used for
- other boards via setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/
- LEN/BUSWIDTH parameters. This mapping will provide one mtd device
- using one partition. The start address can be offset from the
- beginning of flash and the len can be less than the total flash
- device size to allow a window into the flash. Both CFI and JEDEC
- probes are called.
-
-config MTD_CSTM_MIPS_IXX_START
- hex "Physical start address of flash mapping"
- depends on MTD_CSTM_MIPS_IXX
- default "0x8000000"
- help
- This is the physical memory location that the MTD driver will
- use for the flash chips on your particular target board.
- Refer to the memory map which should hopefully be in the
- documentation for your board.
-
-config MTD_CSTM_MIPS_IXX_LEN
- hex "Physical length of flash mapping"
- depends on MTD_CSTM_MIPS_IXX
- default "0x4000000"
- help
- This is the total length that the MTD driver will use for the
- flash chips on your particular board. Refer to the memory
- map which should hopefully be in the documentation for your
- board.
-
-config MTD_CSTM_MIPS_IXX_BUSWIDTH
- int "Bus width in octets"
- depends on MTD_CSTM_MIPS_IXX
- default "2"
- help
- This is the total bus width of the mapping of the flash chips
- on your particular board.
-
config MTD_OCELOT
tristate "Momenco Ocelot boot flash device"
depends on MIPS && MOMENCO_OCELOT
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 191c1928bbe..071d0bf922b 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -12,12 +12,13 @@ obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
obj-$(CONFIG_MTD_BAST) += bast-flash.o
obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
-obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
obj-$(CONFIG_MTD_DC21285) += dc21285.o
obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
obj-$(CONFIG_MTD_L440GX) += l440gx.o
obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
+obj-$(CONFIG_MTD_ESB2ROM) += esb2rom.o
obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
+obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o
obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o
obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_MTD_MBX860) += mbx860.o
obj-$(CONFIG_MTD_CEIVA) += ceiva.o
obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
+obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o
obj-$(CONFIG_MTD_PNC2000) += pnc2000.o
obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
index 797caffb20b..78b671172bb 100644
--- a/drivers/mtd/maps/amd76xrom.c
+++ b/drivers/mtd/maps/amd76xrom.c
@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
@@ -44,6 +45,23 @@ struct amd76xrom_map_info {
char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
};
+/* The 2 bits controlling the window size are often set to allow reading
+ * the BIOS, but too small to allow writing, since the lock registers are
+ * 4MiB lower in the address space than the data.
+ *
+ * This is intended to prevent flashing the bios, perhaps accidentally.
+ *
+ * This parameter allows the normal driver to over-ride the BIOS settings.
+ *
+ * The bits are 6 and 7. If both bits are set, it is a 5MiB window.
+ * If only the 7 Bit is set, it is a 4MiB window. Otherwise, a
+ * 64KiB window.
+ *
+ */
+static uint win_size_bits;
+module_param(win_size_bits, uint, 0);
+MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x43 byte, normally set by BIOS.");
+
static struct amd76xrom_window amd76xrom_window = {
.maps = LIST_HEAD_INIT(amd76xrom_window.maps),
};
@@ -95,6 +113,16 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
/* Remember the pci dev I find the window in - already have a ref */
window->pdev = pdev;
+ /* Enable the selected rom window. This is often incorrectly
+ * set up by the BIOS, and the 4MiB offset for the lock registers
+ * requires the full 5MiB of window space.
+ *
+ * This 'write, then read' approach leaves the bits for
+ * other uses of the hardware info.
+ */
+ pci_read_config_byte(pdev, 0x43, &byte);
+ pci_write_config_byte(pdev, 0x43, byte | win_size_bits );
+
/* Assume the rom window is properly setup, and find it's size */
pci_read_config_byte(pdev, 0x43, &byte);
if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) {
@@ -129,12 +157,6 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
(unsigned long long)window->rsrc.end);
}
-#if 0
-
- /* Enable the selected rom window */
- pci_read_config_byte(pdev, 0x43, &byte);
- pci_write_config_byte(pdev, 0x43, byte | rwindow->segen_bits);
-#endif
/* Enable writes through the rom window */
pci_read_config_byte(pdev, 0x40, &byte);
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c
index e074bb6787d..fc3b2672d1e 100644
--- a/drivers/mtd/maps/bast-flash.c
+++ b/drivers/mtd/maps/bast-flash.c
@@ -131,7 +131,7 @@ static int bast_flash_probe(struct platform_device *pdev)
info->map.phys = res->start;
info->map.size = res->end - res->start + 1;
- info->map.name = pdev->dev.bus_id;
+ info->map.name = pdev->dev.bus_id;
info->map.bankwidth = 2;
if (info->map.size > AREA_MAXSIZE)
diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c
index 0402c21e291..629e6e2641a 100644
--- a/drivers/mtd/maps/ceiva.c
+++ b/drivers/mtd/maps/ceiva.c
@@ -122,10 +122,9 @@ static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info
/*
* Allocate the map_info structs in one go.
*/
- maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
+ maps = kzalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
if (!maps)
return -ENOMEM;
- memset(maps, 0, sizeof(struct map_info) * nr);
/*
* Claim and then map the memory regions.
*/
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
new file mode 100644
index 00000000000..238d42e88ec
--- /dev/null
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -0,0 +1,356 @@
+/*
+ * ck804xrom.c
+ *
+ * Normal mappings of chips in physical memory
+ *
+ * Dave Olsen <dolsen@lnxi.com>
+ * Ryan Jackson <rjackson@lnxi.com>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/flashchip.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/list.h>
+
+
+#define MOD_NAME KBUILD_BASENAME
+
+#define ADDRESS_NAME_LEN 18
+
+#define ROM_PROBE_STEP_SIZE (64*1024)
+
+struct ck804xrom_window {
+ void __iomem *virt;
+ unsigned long phys;
+ unsigned long size;
+ struct list_head maps;
+ struct resource rsrc;
+ struct pci_dev *pdev;
+};
+
+struct ck804xrom_map_info {
+ struct list_head list;
+ struct map_info map;
+ struct mtd_info *mtd;
+ struct resource rsrc;
+ char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
+};
+
+
+/* The 2 bits controlling the window size are often set to allow reading
+ * the BIOS, but too small to allow writing, since the lock registers are
+ * 4MiB lower in the address space than the data.
+ *
+ * This is intended to prevent flashing the bios, perhaps accidentally.
+ *
+ * This parameter allows the normal driver to override the BIOS settings.
+ *
+ * The bits are 6 and 7. If both bits are set, it is a 5MiB window.
+ * If only the 7 Bit is set, it is a 4MiB window. Otherwise, a
+ * 64KiB window.
+ *
+ */
+static uint win_size_bits = 0;
+module_param(win_size_bits, uint, 0);
+MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x88 byte, normally set by BIOS.");
+
+static struct ck804xrom_window ck804xrom_window = {
+ .maps = LIST_HEAD_INIT(ck804xrom_window.maps),
+};
+
+static void ck804xrom_cleanup(struct ck804xrom_window *window)
+{
+ struct ck804xrom_map_info *map, *scratch;
+ u8 byte;
+
+ if (window->pdev) {
+ /* Disable writes through the rom window */
+ pci_read_config_byte(window->pdev, 0x6d, &byte);
+ pci_write_config_byte(window->pdev, 0x6d, byte & ~1);
+ }
+
+ /* Free all of the mtd devices */
+ list_for_each_entry_safe(map, scratch, &window->maps, list) {
+ if (map->rsrc.parent)
+ release_resource(&map->rsrc);
+
+ del_mtd_device(map->mtd);
+ map_destroy(map->mtd);
+ list_del(&map->list);
+ kfree(map);
+ }
+ if (window->rsrc.parent)
+ release_resource(&window->rsrc);
+
+ if (window->virt) {
+ iounmap(window->virt);
+ window->virt = NULL;
+ window->phys = 0;
+ window->size = 0;
+ }
+ pci_dev_put(window->pdev);
+}
+
+
+static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
+ u8 byte;
+ struct ck804xrom_window *window = &ck804xrom_window;
+ struct ck804xrom_map_info *map = NULL;
+ unsigned long map_top;
+
+ /* Remember the pci dev I find the window in */
+ window->pdev = pci_dev_get(pdev);
+
+ /* Enable the selected rom window. This is often incorrectly
+ * set up by the BIOS, and the 4MiB offset for the lock registers
+ * requires the full 5MiB of window space.
+ *
+ * This 'write, then read' approach leaves the bits for
+ * other uses of the hardware info.
+ */
+ pci_read_config_byte(pdev, 0x88, &byte);
+ pci_write_config_byte(pdev, 0x88, byte | win_size_bits );
+
+
+ /* Assume the rom window is properly setup, and find it's size */
+ pci_read_config_byte(pdev, 0x88, &byte);
+
+ if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6)))
+ window->phys = 0xffb00000; /* 5MiB */
+ else if ((byte & (1<<7)) == (1<<7))
+ window->phys = 0xffc00000; /* 4MiB */
+ else
+ window->phys = 0xffff0000; /* 64KiB */
+
+ window->size = 0xffffffffUL - window->phys + 1UL;
+
+ /*
+ * Try to reserve the window mem region. If this fails then
+ * it is likely due to a fragment of the window being
+ * "reserved" by the BIOS. In the case that the
+ * request_mem_region() fails then once the rom size is
+ * discovered we will try to reserve the unreserved fragment.
+ */
+ window->rsrc.name = MOD_NAME;
+ window->rsrc.start = window->phys;
+ window->rsrc.end = window->phys + window->size - 1;
+ window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ if (request_resource(&iomem_resource, &window->rsrc)) {
+ window->rsrc.parent = NULL;
+ printk(KERN_ERR MOD_NAME
+ " %s(): Unable to register resource"
+ " 0x%.016llx-0x%.016llx - kernel bug?\n",
+ __func__,
+ (unsigned long long)window->rsrc.start,
+ (unsigned long long)window->rsrc.end);
+ }
+
+
+ /* Enable writes through the rom window */
+ pci_read_config_byte(pdev, 0x6d, &byte);
+ pci_write_config_byte(pdev, 0x6d, byte | 1);
+
+ /* FIXME handle registers 0x80 - 0x8C the bios region locks */
+
+ /* For write accesses caches are useless */
+ window->virt = ioremap_nocache(window->phys, window->size);
+ if (!window->virt) {
+ printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
+ window->phys, window->size);
+ goto out;
+ }
+
+ /* Get the first address to look for a rom chip at */
+ map_top = window->phys;
+#if 1
+ /* The probe sequence run over the firmware hub lock
+ * registers sets them to 0x7 (no access).
+ * Probe at most the last 4MiB of the address space.
+ */
+ if (map_top < 0xffc00000)
+ map_top = 0xffc00000;
+#endif
+ /* Loop through and look for rom chips. Since we don't know the
+ * starting address for each chip, probe every ROM_PROBE_STEP_SIZE
+ * bytes from the starting address of the window.
+ */
+ while((map_top - 1) < 0xffffffffUL) {
+ struct cfi_private *cfi;
+ unsigned long offset;
+ int i;
+
+ if (!map)
+ map = kmalloc(sizeof(*map), GFP_KERNEL);
+
+ if (!map) {
+ printk(KERN_ERR MOD_NAME ": kmalloc failed");
+ goto out;
+ }
+ memset(map, 0, sizeof(*map));
+ INIT_LIST_HEAD(&map->list);
+ map->map.name = map->map_name;
+ map->map.phys = map_top;
+ offset = map_top - window->phys;
+ map->map.virt = (void __iomem *)
+ (((unsigned long)(window->virt)) + offset);
+ map->map.size = 0xffffffffUL - map_top + 1UL;
+ /* Set the name of the map to the address I am trying */
+ sprintf(map->map_name, "%s @%08lx",
+ MOD_NAME, map->map.phys);
+
+ /* There is no generic VPP support */
+ for(map->map.bankwidth = 32; map->map.bankwidth;
+ map->map.bankwidth >>= 1)
+ {
+ char **probe_type;
+ /* Skip bankwidths that are not supported */
+ if (!map_bankwidth_supported(map->map.bankwidth))
+ continue;
+
+ /* Setup the map methods */
+ simple_map_init(&map->map);
+
+ /* Try all of the probe methods */
+ probe_type = rom_probe_types;
+ for(; *probe_type; probe_type++) {
+ map->mtd = do_map_probe(*probe_type, &map->map);
+ if (map->mtd)
+ goto found;
+ }
+ }
+ map_top += ROM_PROBE_STEP_SIZE;
+ continue;
+ found:
+ /* Trim the size if we are larger than the map */
+ if (map->mtd->size > map->map.size) {
+ printk(KERN_WARNING MOD_NAME
+ " rom(%u) larger than window(%lu). fixing...\n",
+ map->mtd->size, map->map.size);
+ map->mtd->size = map->map.size;
+ }
+ if (window->rsrc.parent) {
+ /*
+ * Registering the MTD device in iomem may not be possible
+ * if there is a BIOS "reserved" and BUSY range. If this
+ * fails then continue anyway.
+ */
+ map->rsrc.name = map->map_name;
+ map->rsrc.start = map->map.phys;
+ map->rsrc.end = map->map.phys + map->mtd->size - 1;
+ map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ if (request_resource(&window->rsrc, &map->rsrc)) {
+ printk(KERN_ERR MOD_NAME
+ ": cannot reserve MTD resource\n");
+ map->rsrc.parent = NULL;
+ }
+ }
+
+ /* Make the whole region visible in the map */
+ map->map.virt = window->virt;
+ map->map.phys = window->phys;
+ cfi = map->map.fldrv_priv;
+ for(i = 0; i < cfi->numchips; i++)
+ cfi->chips[i].start += offset;
+
+ /* Now that the mtd devices is complete claim and export it */
+ map->mtd->owner = THIS_MODULE;
+ if (add_mtd_device(map->mtd)) {
+ map_destroy(map->mtd);
+ map->mtd = NULL;
+ goto out;
+ }
+
+
+ /* Calculate the new value of map_top */
+ map_top += map->mtd->size;
+
+ /* File away the map structure */
+ list_add(&map->list, &window->maps);
+ map = NULL;
+ }
+
+ out:
+ /* Free any left over map structures */
+ if (map)
+ kfree(map);
+
+ /* See if I have any map structures */
+ if (list_empty(&window->maps)) {
+ ck804xrom_cleanup(window);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+
+static void __devexit ck804xrom_remove_one (struct pci_dev *pdev)
+{
+ struct ck804xrom_window *window = &ck804xrom_window;
+
+ ck804xrom_cleanup(window);
+}
+
+static struct pci_device_id ck804xrom_pci_tbl[] = {
+ { PCI_VENDOR_ID_NVIDIA, 0x0051,
+ PCI_ANY_ID, PCI_ANY_ID, }, /* nvidia ck804 */
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, ck804xrom_pci_tbl);
+
+#if 0
+static struct pci_driver ck804xrom_driver = {
+ .name = MOD_NAME,
+ .id_table = ck804xrom_pci_tbl,
+ .probe = ck804xrom_init_one,
+ .remove = ck804xrom_remove_one,
+};
+#endif
+
+static int __init init_ck804xrom(void)
+{
+ struct pci_dev *pdev;
+ struct pci_device_id *id;
+ int retVal;
+ pdev = NULL;
+
+ for(id = ck804xrom_pci_tbl; id->vendor; id++) {
+ pdev = pci_find_device(id->vendor, id->device, NULL);
+ if (pdev)
+ break;
+ }
+ if (pdev) {
+ retVal = ck804xrom_init_one(pdev, &ck804xrom_pci_tbl[0]);
+ pci_dev_put(pdev);
+ return retVal;
+ }
+ return -ENXIO;
+#if 0
+ return pci_module_init(&ck804xrom_driver);
+#endif
+}
+
+static void __exit cleanup_ck804xrom(void)
+{
+ ck804xrom_remove_one(ck804xrom_window.pdev);
+}
+
+module_init(init_ck804xrom);
+module_exit(cleanup_ck804xrom);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>, Dave Olsen <dolsen@lnxi.com>");
+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the Nvidia ck804 southbridge");
+
diff --git a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c
deleted file mode 100644
index df2c38ef105..00000000000
--- a/drivers/mtd/maps/cstm_mips_ixx.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * $Id: cstm_mips_ixx.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $
- *
- * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
- * Config with both CFI and JEDEC device support.
- *
- * Basically physmap.c with the addition of partitions and
- * an array of mapping info to accomodate more than one flash type per board.
- *
- * Copyright 2000 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/init.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/delay.h>
-
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-#define CC_GCR 0xB4013818
-#define CC_GPBCR 0xB401380A
-#define CC_GPBDR 0xB4013808
-#define CC_M68K_DEVICE 1
-#define CC_M68K_FUNCTION 6
-#define CC_CONFADDR 0xB8004000
-#define CC_CONFDATA 0xB8004004
-#define CC_FC_FCR 0xB8002004
-#define CC_FC_DCR 0xB8002008
-#define CC_GPACR 0xB4013802
-#define CC_GPAICR 0xB4013804
-#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
-
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp)
-{
- static DEFINE_SPINLOCK(vpp_lock);
- static int vpp_count = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&vpp_lock, flags);
-
- if (vpp) {
- if (!vpp_count++) {
- __u16 data;
- __u8 data1;
- static u8 first = 1;
-
- // Set GPIO port B pin3 to high
- data = *(__u16 *)(CC_GPBCR);
- data = (data & 0xff0f) | 0x0040;
- *(__u16 *)CC_GPBCR = data;
- *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) | 0x08;
- if (first) {
- first = 0;
- /* need to have this delay for first
- enabling vpp after powerup */
- udelay(40);
- }
- }
- } else {
- if (!--vpp_count) {
- __u16 data;
-
- // Set GPIO port B pin3 to high
- data = *(__u16 *)(CC_GPBCR);
- data = (data & 0xff3f) | 0x0040;
- *(__u16 *)CC_GPBCR = data;
- *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7;
- }
- }
- spin_unlock_irqrestore(&vpp_lock, flags);
-}
-#endif
-
-/* board and partition description */
-
-#define MAX_PHYSMAP_PARTITIONS 8
-struct cstm_mips_ixx_info {
- char *name;
- unsigned long window_addr;
- unsigned long window_size;
- int bankwidth;
- int num_partitions;
-};
-
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-#define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type
-const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] =
-{
- { // 28F128J3A in 2x16 configuration
- "big flash", // name
- 0x08000000, // window_addr
- 0x02000000, // window_size
- 4, // bankwidth
- 1, // num_partitions
- }
-
-};
-static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
-{ // 28F128J3A in 2x16 configuration
- {
- .name = "main partition ",
- .size = 0x02000000, // 128 x 2 x 128k byte sectors
- .offset = 0,
- },
-},
-};
-#else /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
-#define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type
-const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] =
-{
- {
- "MTD flash", // name
- CONFIG_MTD_CSTM_MIPS_IXX_START, // window_addr
- CONFIG_MTD_CSTM_MIPS_IXX_LEN, // window_size
- CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH, // bankwidth
- 1, // num_partitions
- },
-
-};
-static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
-{
- {
- .name = "main partition",
- .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN,
- .offset = 0,
- },
-},
-};
-#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
-
-struct map_info cstm_mips_ixx_map[PHYSMAP_NUMBER];
-
-int __init init_cstm_mips_ixx(void)
-{
- int i;
- int jedec;
- struct mtd_info *mymtd;
- struct mtd_partition *parts;
-
- /* Initialize mapping */
- for (i=0;i<PHYSMAP_NUMBER;i++) {
- printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n",
- cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr);
-
-
- cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr;
- cstm_mips_ixx_map[i].virt = ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
- if (!cstm_mips_ixx_map[i].virt) {
- int j = 0;
- printk(KERN_WARNING "Failed to ioremap\n");
- for (j = 0; j < i; j++) {
- if (cstm_mips_ixx_map[j].virt) {
- iounmap(cstm_mips_ixx_map[j].virt);
- cstm_mips_ixx_map[j].virt = NULL;
- }
- }
- return -EIO;
- }
- cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
- cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size;
- cstm_mips_ixx_map[i].bankwidth = cstm_mips_ixx_board_desc[i].bankwidth;
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
- cstm_mips_ixx_map[i].set_vpp = cstm_mips_ixx_set_vpp;
-#endif
- simple_map_init(&cstm_mips_ixx_map[i]);
- //printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].virt));
- }
-
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
- setup_ITE_IVR_flash();
-#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
-
- for (i=0;i<PHYSMAP_NUMBER;i++) {
- parts = &cstm_mips_ixx_partitions[i][0];
- jedec = 0;
- mymtd = (struct mtd_info *)do_map_probe("cfi_probe", &cstm_mips_ixx_map[i]);
- //printk(KERN_NOTICE "phymap %d cfi_probe: mymtd is %x\n",i,(unsigned int)mymtd);
- if (!mymtd) {
- jedec = 1;
- mymtd = (struct mtd_info *)do_map_probe("jedec", &cstm_mips_ixx_map[i]);
- printk(KERN_NOTICE "cstm_mips_ixx %d jedec: mymtd is %x\n",i,(unsigned int)mymtd);
- }
- if (mymtd) {
- mymtd->owner = THIS_MODULE;
-
- cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd;
- add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions);
- }
- else {
- for (i = 0; i < PHYSMAP_NUMBER; i++) {
- if (cstm_mips_ixx_map[i].virt) {
- iounmap(cstm_mips_ixx_map[i].virt);
- cstm_mips_ixx_map[i].virt = NULL;
- }
- }
- return -ENXIO;
- }
- }
- return 0;
-}
-
-static void __exit cleanup_cstm_mips_ixx(void)
-{
- int i;
- struct mtd_info *mymtd;
-
- for (i=0;i<PHYSMAP_NUMBER;i++) {
- mymtd = (struct mtd_info *)cstm_mips_ixx_map[i].map_priv_2;
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
- if (cstm_mips_ixx_map[i].virt) {
- iounmap((void *)cstm_mips_ixx_map[i].virt);
- cstm_mips_ixx_map[i].virt = 0;
- }
- }
-}
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-void PCISetULongByOffset(__u32 DevNumber, __u32 FuncNumber, __u32 Offset, __u32 data)
-{
- __u32 offset;
-
- offset = ( unsigned long )( 0x80000000 | ( DevNumber << 11 ) + ( FuncNumber << 8 ) + Offset) ;
-
- *(__u32 *)CC_CONFADDR = offset;
- *(__u32 *)CC_CONFDATA = data;
-}
-void setup_ITE_IVR_flash()
-{
- __u32 size, base;
-
- size = 0x0e000000; // 32MiB
- base = (0x08000000) >> 8 >>1; // Bug: we must shift one more bit
-
- /* need to set ITE flash to 32 bits instead of default 8 */
-#ifdef CONFIG_MIPS_IVR
- *(__u32 *)CC_FC_FCR = 0x55;
- *(__u32 *)CC_GPACR = 0xfffc;
-#else
- *(__u32 *)CC_FC_FCR = 0x77;
-#endif
- /* turn bursting off */
- *(__u32 *)CC_FC_DCR = 0x0;
-
- /* setup for one chip 4 byte PCI access */
- PCISetULongByOffset(CC_M68K_DEVICE, CC_M68K_FUNCTION, 0x60, size | base);
- PCISetULongByOffset(CC_M68K_DEVICE, CC_M68K_FUNCTION, 0x64, 0x02);
-}
-#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
-
-module_init(init_cstm_mips_ixx);
-module_exit(cleanup_cstm_mips_ixx);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
-MODULE_DESCRIPTION("MTD map driver for ITE 8172G and Globespan IVR boards");
diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c
new file mode 100644
index 00000000000..a9d808a617c
--- /dev/null
+++ b/drivers/mtd/maps/esb2rom.c
@@ -0,0 +1,450 @@
+/*
+ * esb2rom.c
+ *
+ * Normal mappings of flash chips in physical memory
+ * through the Intel ESB2 Southbridge.
+ *
+ * This was derived from ichxrom.c in May 2006 by
+ * Lew Glendenning <lglendenning@lnxi.com>
+ *
+ * Eric Biederman, of course, was a major help in this effort.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/flashchip.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/list.h>
+
+#define MOD_NAME KBUILD_BASENAME
+
+#define ADDRESS_NAME_LEN 18
+
+#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
+
+#define BIOS_CNTL 0xDC
+#define BIOS_LOCK_ENABLE 0x02
+#define BIOS_WRITE_ENABLE 0x01
+
+/* This became a 16-bit register, and EN2 has disappeared */
+#define FWH_DEC_EN1 0xD8
+#define FWH_F8_EN 0x8000
+#define FWH_F0_EN 0x4000
+#define FWH_E8_EN 0x2000
+#define FWH_E0_EN 0x1000
+#define FWH_D8_EN 0x0800
+#define FWH_D0_EN 0x0400
+#define FWH_C8_EN 0x0200
+#define FWH_C0_EN 0x0100
+#define FWH_LEGACY_F_EN 0x0080
+#define FWH_LEGACY_E_EN 0x0040
+/* reserved 0x0020 and 0x0010 */
+#define FWH_70_EN 0x0008
+#define FWH_60_EN 0x0004
+#define FWH_50_EN 0x0002
+#define FWH_40_EN 0x0001
+
+/* these are 32-bit values */
+#define FWH_SEL1 0xD0
+#define FWH_SEL2 0xD4
+
+#define FWH_8MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+ FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
+ FWH_70_EN | FWH_60_EN | FWH_50_EN | FWH_40_EN)
+
+#define FWH_7MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+ FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
+ FWH_70_EN | FWH_60_EN | FWH_50_EN)
+
+#define FWH_6MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+ FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
+ FWH_70_EN | FWH_60_EN)
+
+#define FWH_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+ FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
+ FWH_70_EN)
+
+#define FWH_4MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+ FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN)
+
+#define FWH_3_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+ FWH_D8_EN | FWH_D0_EN | FWH_C8_EN)
+
+#define FWH_3MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+ FWH_D8_EN | FWH_D0_EN)
+
+#define FWH_2_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+ FWH_D8_EN)
+
+#define FWH_2MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN)
+
+#define FWH_1_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN)
+
+#define FWH_1MiB (FWH_F8_EN | FWH_F0_EN)
+
+#define FWH_0_5MiB (FWH_F8_EN)
+
+
+struct esb2rom_window {
+ void __iomem* virt;
+ unsigned long phys;
+ unsigned long size;
+ struct list_head maps;
+ struct resource rsrc;
+ struct pci_dev *pdev;
+};
+
+struct esb2rom_map_info {
+ struct list_head list;
+ struct map_info map;
+ struct mtd_info *mtd;
+ struct resource rsrc;
+ char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
+};
+
+static struct esb2rom_window esb2rom_window = {
+ .maps = LIST_HEAD_INIT(esb2rom_window.maps),
+};
+
+static void esb2rom_cleanup(struct esb2rom_window *window)
+{
+ struct esb2rom_map_info *map, *scratch;
+ u8 byte;
+
+ /* Disable writes through the rom window */
+ pci_read_config_byte(window->pdev, BIOS_CNTL, &byte);
+ pci_write_config_byte(window->pdev, BIOS_CNTL,
+ byte & ~BIOS_WRITE_ENABLE);
+
+ /* Free all of the mtd devices */
+ list_for_each_entry_safe(map, scratch, &window->maps, list) {
+ if (map->rsrc.parent)
+ release_resource(&map->rsrc);
+ del_mtd_device(map->mtd);
+ map_destroy(map->mtd);
+ list_del(&map->list);
+ kfree(map);
+ }
+ if (window->rsrc.parent)
+ release_resource(&window->rsrc);
+ if (window->virt) {
+ iounmap(window->virt);
+ window->virt = NULL;
+ window->phys = 0;
+ window->size = 0;
+ }
+ pci_dev_put(window->pdev);
+}
+
+static int __devinit esb2rom_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
+ struct esb2rom_window *window = &esb2rom_window;
+ struct esb2rom_map_info *map = NULL;
+ unsigned long map_top;
+ u8 byte;
+ u16 word;
+
+ /* For now I just handle the ecb2 and I assume there
+ * are not a lot of resources up at the top of the address
+ * space. It is possible to handle other devices in the
+ * top 16MiB but it is very painful. Also since
+ * you can only really attach a FWH to an ICHX there
+ * a number of simplifications you can make.
+ *
+ * Also you can page firmware hubs if an 8MiB window isn't enough
+ * but don't currently handle that case either.
+ */
+ window->pdev = pci_dev_get(pdev);
+
+ /* RLG: experiment 2. Force the window registers to the widest values */
+
+/*
+ pci_read_config_word(pdev, FWH_DEC_EN1, &word);
+ printk(KERN_DEBUG "Original FWH_DEC_EN1 : %x\n", word);
+ pci_write_config_byte(pdev, FWH_DEC_EN1, 0xff);
+ pci_read_config_byte(pdev, FWH_DEC_EN1, &byte);
+ printk(KERN_DEBUG "New FWH_DEC_EN1 : %x\n", byte);
+
+ pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
+ printk(KERN_DEBUG "Original FWH_DEC_EN2 : %x\n", byte);
+ pci_write_config_byte(pdev, FWH_DEC_EN2, 0x0f);
+ pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
+ printk(KERN_DEBUG "New FWH_DEC_EN2 : %x\n", byte);
+*/
+
+ /* Find a region continuous to the end of the ROM window */
+ window->phys = 0;
+ pci_read_config_word(pdev, FWH_DEC_EN1, &word);
+ printk(KERN_DEBUG "pci_read_config_byte : %x\n", word);
+
+ if ((word & FWH_8MiB) == FWH_8MiB)
+ window->phys = 0xff400000;
+ else if ((word & FWH_7MiB) == FWH_7MiB)
+ window->phys = 0xff500000;
+ else if ((word & FWH_6MiB) == FWH_6MiB)
+ window->phys = 0xff600000;
+ else if ((word & FWH_5MiB) == FWH_5MiB)
+ window->phys = 0xFF700000;
+ else if ((word & FWH_4MiB) == FWH_4MiB)
+ window->phys = 0xffc00000;
+ else if ((word & FWH_3_5MiB) == FWH_3_5MiB)
+ window->phys = 0xffc80000;
+ else if ((word & FWH_3MiB) == FWH_3MiB)
+ window->phys = 0xffd00000;
+ else if ((word & FWH_2_5MiB) == FWH_2_5MiB)
+ window->phys = 0xffd80000;
+ else if ((word & FWH_2MiB) == FWH_2MiB)
+ window->phys = 0xffe00000;
+ else if ((word & FWH_1_5MiB) == FWH_1_5MiB)
+ window->phys = 0xffe80000;
+ else if ((word & FWH_1MiB) == FWH_1MiB)
+ window->phys = 0xfff00000;
+ else if ((word & FWH_0_5MiB) == FWH_0_5MiB)
+ window->phys = 0xfff80000;
+
+ /* reserved 0x0020 and 0x0010 */
+ window->phys -= 0x400000UL;
+ window->size = (0xffffffffUL - window->phys) + 1UL;
+
+ /* Enable writes through the rom window */
+ pci_read_config_byte(pdev, BIOS_CNTL, &byte);
+ if (!(byte & BIOS_WRITE_ENABLE) && (byte & (BIOS_LOCK_ENABLE))) {
+ /* The BIOS will generate an error if I enable
+ * this device, so don't even try.
+ */
+ printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n");
+ goto out;
+ }
+ pci_write_config_byte(pdev, BIOS_CNTL, byte | BIOS_WRITE_ENABLE);
+
+ /*
+ * Try to reserve the window mem region. If this fails then
+ * it is likely due to the window being "reseved" by the BIOS.
+ */
+ window->rsrc.name = MOD_NAME;
+ window->rsrc.start = window->phys;
+ window->rsrc.end = window->phys + window->size - 1;
+ window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ if (request_resource(&iomem_resource, &window->rsrc)) {
+ window->rsrc.parent = NULL;
+ printk(KERN_DEBUG MOD_NAME
+ ": %s(): Unable to register resource"
+ " 0x%.08llx-0x%.08llx - kernel bug?\n",
+ __func__,
+ (unsigned long long)window->rsrc.start,
+ (unsigned long long)window->rsrc.end);
+ }
+
+ /* Map the firmware hub into my address space. */
+ window->virt = ioremap_nocache(window->phys, window->size);
+ if (!window->virt) {
+ printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
+ window->phys, window->size);
+ goto out;
+ }
+
+ /* Get the first address to look for an rom chip at */
+ map_top = window->phys;
+ if ((window->phys & 0x3fffff) != 0) {
+ /* if not aligned on 4MiB, look 4MiB lower in address space */
+ map_top = window->phys + 0x400000;
+ }
+#if 1
+ /* The probe sequence run over the firmware hub lock
+ * registers sets them to 0x7 (no access).
+ * (Insane hardware design, but most copied Intel's.)
+ * ==> Probe at most the last 4M of the address space.
+ */
+ if (map_top < 0xffc00000)
+ map_top = 0xffc00000;
+#endif
+ /* Loop through and look for rom chips */
+ while ((map_top - 1) < 0xffffffffUL) {
+ struct cfi_private *cfi;
+ unsigned long offset;
+ int i;
+
+ if (!map)
+ map = kmalloc(sizeof(*map), GFP_KERNEL);
+ if (!map) {
+ printk(KERN_ERR MOD_NAME ": kmalloc failed");
+ goto out;
+ }
+ memset(map, 0, sizeof(*map));
+ INIT_LIST_HEAD(&map->list);
+ map->map.name = map->map_name;
+ map->map.phys = map_top;
+ offset = map_top - window->phys;
+ map->map.virt = (void __iomem *)
+ (((unsigned long)(window->virt)) + offset);
+ map->map.size = 0xffffffffUL - map_top + 1UL;
+ /* Set the name of the map to the address I am trying */
+ sprintf(map->map_name, "%s @%08lx",
+ MOD_NAME, map->map.phys);
+
+ /* Firmware hubs only use vpp when being programmed
+ * in a factory setting. So in-place programming
+ * needs to use a different method.
+ */
+ for(map->map.bankwidth = 32; map->map.bankwidth;
+ map->map.bankwidth >>= 1) {
+ char **probe_type;
+ /* Skip bankwidths that are not supported */
+ if (!map_bankwidth_supported(map->map.bankwidth))
+ continue;
+
+ /* Setup the map methods */
+ simple_map_init(&map->map);
+
+ /* Try all of the probe methods */
+ probe_type = rom_probe_types;
+ for(; *probe_type; probe_type++) {
+ map->mtd = do_map_probe(*probe_type, &map->map);
+ if (map->mtd)
+ goto found;
+ }
+ }
+ map_top += ROM_PROBE_STEP_SIZE;
+ continue;
+ found:
+ /* Trim the size if we are larger than the map */
+ if (map->mtd->size > map->map.size) {
+ printk(KERN_WARNING MOD_NAME
+ " rom(%u) larger than window(%lu). fixing...\n",
+ map->mtd->size, map->map.size);
+ map->mtd->size = map->map.size;
+ }
+ if (window->rsrc.parent) {
+ /*
+ * Registering the MTD device in iomem may not be possible
+ * if there is a BIOS "reserved" and BUSY range. If this
+ * fails then continue anyway.
+ */
+ map->rsrc.name = map->map_name;
+ map->rsrc.start = map->map.phys;
+ map->rsrc.end = map->map.phys + map->mtd->size - 1;
+ map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ if (request_resource(&window->rsrc, &map->rsrc)) {
+ printk(KERN_ERR MOD_NAME
+ ": cannot reserve MTD resource\n");
+ map->rsrc.parent = NULL;
+ }
+ }
+
+ /* Make the whole region visible in the map */
+ map->map.virt = window->virt;
+ map->map.phys = window->phys;
+ cfi = map->map.fldrv_priv;
+ for(i = 0; i < cfi->numchips; i++)
+ cfi->chips[i].start += offset;
+
+ /* Now that the mtd devices is complete claim and export it */
+ map->mtd->owner = THIS_MODULE;
+ if (add_mtd_device(map->mtd)) {
+ map_destroy(map->mtd);
+ map->mtd = NULL;
+ goto out;
+ }
+
+ /* Calculate the new value of map_top */
+ map_top += map->mtd->size;
+
+ /* File away the map structure */
+ list_add(&map->list, &window->maps);
+ map = NULL;
+ }
+
+ out:
+ /* Free any left over map structures */
+ kfree(map);
+
+ /* See if I have any map structures */
+ if (list_empty(&window->maps)) {
+ esb2rom_cleanup(window);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __devexit esb2rom_remove_one (struct pci_dev *pdev)
+{
+ struct esb2rom_window *window = &esb2rom_window;
+ esb2rom_cleanup(window);
+}
+
+static struct pci_device_id esb2rom_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
+ 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_82801DB_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, },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { 0, },
+};
+
+#if 0
+MODULE_DEVICE_TABLE(pci, esb2rom_pci_tbl);
+
+static struct pci_driver esb2rom_driver = {
+ .name = MOD_NAME,
+ .id_table = esb2rom_pci_tbl,
+ .probe = esb2rom_init_one,
+ .remove = esb2rom_remove_one,
+};
+#endif
+
+static int __init init_esb2rom(void)
+{
+ struct pci_dev *pdev;
+ struct pci_device_id *id;
+ int retVal;
+
+ pdev = NULL;
+ for (id = esb2rom_pci_tbl; id->vendor; id++) {
+ printk(KERN_DEBUG "device id = %x\n", id->device);
+ pdev = pci_get_device(id->vendor, id->device, NULL);
+ if (pdev) {
+ printk(KERN_DEBUG "matched device = %x\n", id->device);
+ break;
+ }
+ }
+ if (pdev) {
+ printk(KERN_DEBUG "matched device id %x\n", id->device);
+ retVal = esb2rom_init_one(pdev, &esb2rom_pci_tbl[0]);
+ pci_dev_put(pdev);
+ printk(KERN_DEBUG "retVal = %d\n", retVal);
+ return retVal;
+ }
+ return -ENXIO;
+#if 0
+ return pci_register_driver(&esb2rom_driver);
+#endif
+}
+
+static void __exit cleanup_esb2rom(void)
+{
+ esb2rom_remove_one(esb2rom_window.pdev);
+}
+
+module_init(init_esb2rom);
+module_exit(cleanup_esb2rom);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lew Glendenning <lglendenning@lnxi.com>");
+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ESB2 southbridge");
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c
index c8db01b3e45..6946d802e6f 100644
--- a/drivers/mtd/maps/integrator-flash.c
+++ b/drivers/mtd/maps/integrator-flash.c
@@ -75,14 +75,12 @@ static int armflash_probe(struct platform_device *dev)
int err;
void __iomem *base;
- info = kmalloc(sizeof(struct armflash_info), GFP_KERNEL);
+ info = kzalloc(sizeof(struct armflash_info), GFP_KERNEL);
if (!info) {
err = -ENOMEM;
goto out;
}
- memset(info, 0, sizeof(struct armflash_info));
-
info->plat = plat;
if (plat && plat->init) {
err = plat->init();
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index f9e8e5bcbc3..9f53c655af3 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -20,6 +20,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/cfi.h>
#include <linux/reboot.h>
+#include <linux/err.h>
#include <linux/kdev_t.h>
#include <linux/root_dev.h>
#include <asm/io.h>
@@ -178,7 +179,7 @@ int nettel_eraseconfig(void)
init_waitqueue_head(&wait_q);
mtd = get_mtd_device(NULL, 2);
- if (mtd) {
+ if (!IS_ERR(mtd)) {
nettel_erase.mtd = mtd;
nettel_erase.callback = nettel_erasecallback;
nettel_erase.callback = NULL;
@@ -471,7 +472,7 @@ out_unmap2:
iounmap(nettel_amd_map.virt);
return(rc);
-
+
}
/****************************************************************************/
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c
index 418afffb2d8..e8d9ae53567 100644
--- a/drivers/mtd/maps/omap_nor.c
+++ b/drivers/mtd/maps/omap_nor.c
@@ -78,12 +78,10 @@ static int __devinit omapflash_probe(struct platform_device *pdev)
struct resource *res = pdev->resource;
unsigned long size = res->end - res->start + 1;
- info = kmalloc(sizeof(struct omapflash_info), GFP_KERNEL);
+ info = kzalloc(sizeof(struct omapflash_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- memset(info, 0, sizeof(struct omapflash_info));
-
if (!request_mem_region(res->start, size, "flash")) {
err = -EBUSY;
goto out_free_info;
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index 995347b1beb..eaeb56a4070 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -735,11 +735,10 @@ static int pcmciamtd_probe(struct pcmcia_device *link)
struct pcmciamtd_dev *dev;
/* Create new memory card device */
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) return -ENOMEM;
DEBUG(1, "dev=0x%p", dev);
- memset(dev, 0, sizeof(*dev));
dev->p_dev = link;
link->priv = dev;
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index d1717763f71..28c5ffd7523 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -89,15 +89,14 @@ static int physmap_flash_probe(struct platform_device *dev)
return -ENODEV;
printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
- (unsigned long long)dev->resource->end - dev->resource->start + 1,
+ (unsigned long long)(dev->resource->end - dev->resource->start + 1),
(unsigned long long)dev->resource->start);
- info = kmalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
+ info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
if (info == NULL) {
err = -ENOMEM;
goto err_out;
}
- memset(info, 0, sizeof(*info));
platform_set_drvdata(dev, info);
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
new file mode 100644
index 00000000000..7efe744ad31
--- /dev/null
+++ b/drivers/mtd/maps/physmap_of.c
@@ -0,0 +1,255 @@
+/*
+ * Normal mappings of chips in physical memory for OF devices
+ *
+ * Copyright (C) 2006 MontaVista Software Inc.
+ * Author: Vitaly Wool <vwool@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.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+
+struct physmap_flash_info {
+ struct mtd_info *mtd;
+ struct map_info map;
+ struct resource *res;
+#ifdef CONFIG_MTD_PARTITIONS
+ int nr_parts;
+ struct mtd_partition *parts;
+#endif
+};
+
+static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
+#endif
+
+#ifdef CONFIG_MTD_PARTITIONS
+static int parse_flash_partitions(struct device_node *node,
+ struct mtd_partition **parts)
+{
+ int i, plen, retval = -ENOMEM;
+ const u32 *part;
+ const char *name;
+
+ part = get_property(node, "partitions", &plen);
+ if (part == NULL)
+ goto err;
+
+ retval = plen / (2 * sizeof(u32));
+ *parts = kzalloc(retval * sizeof(struct mtd_partition), GFP_KERNEL);
+ if (*parts == NULL) {
+ printk(KERN_ERR "Can't allocate the flash partition data!\n");
+ goto err;
+ }
+
+ name = get_property(node, "partition-names", &plen);
+
+ for (i = 0; i < retval; i++) {
+ (*parts)[i].offset = *part++;
+ (*parts)[i].size = *part & ~1;
+ if (*part++ & 1) /* bit 0 set signifies read only partition */
+ (*parts)[i].mask_flags = MTD_WRITEABLE;
+
+ if (name != NULL && plen > 0) {
+ int len = strlen(name) + 1;
+
+ (*parts)[i].name = (char *)name;
+ plen -= len;
+ name += len;
+ } else
+ (*parts)[i].name = "unnamed";
+ }
+err:
+ return retval;
+}
+#endif
+
+static int of_physmap_remove(struct of_device *dev)
+{
+ struct physmap_flash_info *info;
+
+ info = dev_get_drvdata(&dev->dev);
+ if (info == NULL)
+ return 0;
+ dev_set_drvdata(&dev->dev, NULL);
+
+ if (info->mtd != NULL) {
+#ifdef CONFIG_MTD_PARTITIONS
+ if (info->nr_parts) {
+ del_mtd_partitions(info->mtd);
+ kfree(info->parts);
+ } else {
+ del_mtd_device(info->mtd);
+ }
+#else
+ del_mtd_device(info->mtd);
+#endif
+ map_destroy(info->mtd);
+ }
+
+ if (info->map.virt != NULL)
+ iounmap(info->map.virt);
+
+ if (info->res != NULL) {
+ release_resource(info->res);
+ kfree(info->res);
+ }
+
+ return 0;
+}
+
+static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct device_node *dp = dev->node;
+ struct resource res;
+ struct physmap_flash_info *info;
+ const char **probe_type;
+ const char *of_probe;
+ const u32 *width;
+ int err;
+
+
+ if (of_address_to_resource(dp, 0, &res)) {
+ dev_err(&dev->dev, "Can't get the flash mapping!\n");
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ dev_dbg(&dev->dev, "physmap flash device: %.8llx at %.8llx\n",
+ (unsigned long long)res.end - res.start + 1,
+ (unsigned long long)res.start);
+
+ info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
+ if (info == NULL) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ memset(info, 0, sizeof(*info));
+
+ dev_set_drvdata(&dev->dev, info);
+
+ info->res = request_mem_region(res.start, res.end - res.start + 1,
+ dev->dev.bus_id);
+ if (info->res == NULL) {
+ dev_err(&dev->dev, "Could not reserve memory region\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ width = get_property(dp, "bank-width", NULL);
+ if (width == NULL) {
+ dev_err(&dev->dev, "Can't get the flash bank width!\n");
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ info->map.name = dev->dev.bus_id;
+ info->map.phys = res.start;
+ info->map.size = res.end - res.start + 1;
+ info->map.bankwidth = *width;
+
+ info->map.virt = ioremap(info->map.phys, info->map.size);
+ if (info->map.virt == NULL) {
+ dev_err(&dev->dev, "Failed to ioremap flash region\n");
+ err = EIO;
+ goto err_out;
+ }
+
+ simple_map_init(&info->map);
+
+ of_probe = get_property(dp, "probe-type", NULL);
+ if (of_probe == NULL) {
+ probe_type = rom_probe_types;
+ for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
+ info->mtd = do_map_probe(*probe_type, &info->map);
+ } else if (!strcmp(of_probe, "CFI"))
+ info->mtd = do_map_probe("cfi_probe", &info->map);
+ else if (!strcmp(of_probe, "JEDEC"))
+ info->mtd = do_map_probe("jedec_probe", &info->map);
+ else {
+ if (strcmp(of_probe, "ROM"))
+ dev_dbg(&dev->dev, "map_probe: don't know probe type "
+ "'%s', mapping as rom\n");
+ info->mtd = do_map_probe("mtd_rom", &info->map);
+ }
+ if (info->mtd == NULL) {
+ dev_err(&dev->dev, "map_probe failed\n");
+ err = -ENXIO;
+ goto err_out;
+ }
+ info->mtd->owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0);
+ if (err > 0) {
+ add_mtd_partitions(info->mtd, info->parts, err);
+ } else if ((err = parse_flash_partitions(dp, &info->parts)) > 0) {
+ dev_info(&dev->dev, "Using OF partition information\n");
+ add_mtd_partitions(info->mtd, info->parts, err);
+ info->nr_parts = err;
+ } else
+#endif
+
+ add_mtd_device(info->mtd);
+ return 0;
+
+err_out:
+ of_physmap_remove(dev);
+ return err;
+
+ return 0;
+
+
+}
+
+static struct of_device_id of_physmap_match[] = {
+ {
+ .type = "rom",
+ .compatible = "direct-mapped"
+ },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, of_physmap_match);
+
+
+static struct of_platform_driver of_physmap_flash_driver = {
+ .name = "physmap-flash",
+ .match_table = of_physmap_match,
+ .probe = of_physmap_probe,
+ .remove = of_physmap_remove,
+};
+
+static int __init of_physmap_init(void)
+{
+ return of_register_platform_driver(&of_physmap_flash_driver);
+}
+
+static void __exit of_physmap_exit(void)
+{
+ of_unregister_platform_driver(&of_physmap_flash_driver);
+}
+
+module_init(of_physmap_init);
+module_exit(of_physmap_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
+MODULE_DESCRIPTION("Configurable MTD map driver for OF");
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
index 5d3c75451ca..2b6504ecbbd 100644
--- a/drivers/mtd/maps/plat-ram.c
+++ b/drivers/mtd/maps/plat-ram.c
@@ -147,14 +147,13 @@ static int platram_probe(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL) {
dev_err(&pdev->dev, "no memory for flash info\n");
err = -ENOMEM;
goto exit_error;
}
- memset(info, 0, sizeof(*info));
platform_set_drvdata(pdev, info);
info->dev = &pdev->dev;
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index 950bf1c5784..f904e6bd02e 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -273,14 +273,12 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
/*
* Allocate the map_info structs in one go.
*/
- info = kmalloc(size, GFP_KERNEL);
+ info = kzalloc(size, GFP_KERNEL);
if (!info) {
ret = -ENOMEM;
goto out;
}
- memset(info, 0, size);
-
if (plat->init) {
ret = plat->init();
if (ret)
diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c
index 58e5912bd38..9adc970e55e 100644
--- a/drivers/mtd/maps/tqm834x.c
+++ b/drivers/mtd/maps/tqm834x.c
@@ -132,20 +132,16 @@ static int __init init_tqm834x_mtd(void)
pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx);
- map_banks[idx] =
- (struct map_info *)kmalloc(sizeof(struct map_info),
- GFP_KERNEL);
+ map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL);
if (map_banks[idx] == NULL) {
ret = -ENOMEM;
goto error_mem;
}
- memset((void *)map_banks[idx], 0, sizeof(struct map_info));
- map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
+ map_banks[idx]->name = kzalloc(16, GFP_KERNEL);
if (map_banks[idx]->name == NULL) {
ret = -ENOMEM;
goto error_mem;
}
- memset((void *)map_banks[idx]->name, 0, 16);
sprintf(map_banks[idx]->name, "TQM834x-%d", idx);
map_banks[idx]->size = flash_size;
diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c
index 19578ba84ee..37e4ded9b60 100644
--- a/drivers/mtd/maps/tqm8xxl.c
+++ b/drivers/mtd/maps/tqm8xxl.c
@@ -134,14 +134,13 @@ int __init init_tqm_mtd(void)
printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx);
- map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL);
+ map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL);
if(map_banks[idx] == NULL) {
ret = -ENOMEM;
/* FIXME: What if some MTD devices were probed already? */
goto error_mem;
}
- memset((void *)map_banks[idx], 0, sizeof(struct map_info));
map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
if (!map_banks[idx]->name) {
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 178b53b56be..b879a66daa9 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -42,19 +42,20 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
unsigned long block, nsect;
char *buf;
- block = req->sector;
- nsect = req->current_nr_sectors;
+ block = req->sector << 9 >> tr->blkshift;
+ nsect = req->current_nr_sectors << 9 >> tr->blkshift;
+
buf = req->buffer;
if (!blk_fs_request(req))
return 0;
- if (block + nsect > get_capacity(req->rq_disk))
+ if (req->sector + req->current_nr_sectors > get_capacity(req->rq_disk))
return 0;
switch(rq_data_dir(req)) {
case READ:
- for (; nsect > 0; nsect--, block++, buf += 512)
+ for (; nsect > 0; nsect--, block++, buf += tr->blksize)
if (tr->readsect(dev, block, buf))
return 0;
return 1;
@@ -63,7 +64,7 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
if (!tr->writesect)
return 0;
- for (; nsect > 0; nsect--, block++, buf += 512)
+ for (; nsect > 0; nsect--, block++, buf += tr->blksize)
if (tr->writesect(dev, block, buf))
return 0;
return 1;
@@ -297,7 +298,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
/* 2.5 has capacity in units of 512 bytes while still
having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */
- set_capacity(gd, (new->size * new->blksize) >> 9);
+ set_capacity(gd, (new->size * tr->blksize) >> 9);
gd->private_data = new;
new->blkcore_priv = gd;
@@ -372,12 +373,10 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
if (!blktrans_notifier.list.next)
register_mtd_user(&blktrans_notifier);
- tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
+ tr->blkcore_priv = kzalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
if (!tr->blkcore_priv)
return -ENOMEM;
- memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
-
mutex_lock(&mtd_table_mutex);
ret = register_blkdev(tr->major, tr->name);
@@ -401,6 +400,8 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
}
tr->blkcore_priv->rq->queuedata = tr;
+ blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize);
+ tr->blkshift = ffs(tr->blksize) - 1;
ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL);
if (ret < 0) {
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 04ed34694b1..952da30b174 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -278,11 +278,10 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
}
/* OK, it's not open. Create cache info for it */
- mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
+ mtdblk = kzalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
if (!mtdblk)
return -ENOMEM;
- memset(mtdblk, 0, sizeof(*mtdblk));
mtdblk->count = 1;
mtdblk->mtd = mtd;
@@ -339,16 +338,14 @@ static int mtdblock_flush(struct mtd_blktrans_dev *dev)
static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
- struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ struct mtd_blktrans_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return;
- memset(dev, 0, sizeof(*dev));
-
dev->mtd = mtd;
dev->devnum = mtd->index;
- dev->blksize = 512;
+
dev->size = mtd->size >> 9;
dev->tr = tr;
@@ -368,6 +365,7 @@ static struct mtd_blktrans_ops mtdblock_tr = {
.name = "mtdblock",
.major = 31,
.part_bits = 0,
+ .blksize = 512,
.open = mtdblock_open,
.flush = mtdblock_flush,
.release = mtdblock_release,
diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
index 29563ed258a..f79dbb49b1a 100644
--- a/drivers/mtd/mtdblock_ro.c
+++ b/drivers/mtd/mtdblock_ro.c
@@ -33,16 +33,14 @@ static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
- struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ struct mtd_blktrans_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return;
- memset(dev, 0, sizeof(*dev));
-
dev->mtd = mtd;
dev->devnum = mtd->index;
- dev->blksize = 512;
+
dev->size = mtd->size >> 9;
dev->tr = tr;
dev->readonly = 1;
@@ -60,6 +58,7 @@ static struct mtd_blktrans_ops mtdblock_tr = {
.name = "mtdblock",
.major = 31,
.part_bits = 0,
+ .blksize = 512,
.readsect = mtdblock_readsect,
.writesect = mtdblock_writesect,
.add_mtd = mtdblock_add_mtd,
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 5b6acfcb2b8..3013d0883b9 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -7,6 +7,7 @@
#include <linux/device.h>
#include <linux/fs.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -100,8 +101,8 @@ static int mtd_open(struct inode *inode, struct file *file)
mtd = get_mtd_device(NULL, devnum);
- if (!mtd)
- return -ENODEV;
+ if (IS_ERR(mtd))
+ return PTR_ERR(mtd);
if (MTD_ABSENT == mtd->type) {
put_mtd_device(mtd);
@@ -431,7 +432,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if(!(file->f_mode & 2))
return -EPERM;
- erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL);
+ erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL);
if (!erase)
ret = -ENOMEM;
else {
@@ -440,7 +441,6 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
init_waitqueue_head(&waitq);
- memset (erase,0,sizeof(struct erase_info));
if (copy_from_user(&erase->addr, argp,
sizeof(struct erase_info_user))) {
kfree(erase);
@@ -499,13 +499,12 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (ret)
return ret;
- ops.len = buf.length;
ops.ooblen = buf.length;
ops.ooboffs = buf.start & (mtd->oobsize - 1);
ops.datbuf = NULL;
ops.mode = MTD_OOB_PLACE;
- if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
+ if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
return -EINVAL;
ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
@@ -520,7 +519,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
buf.start &= ~(mtd->oobsize - 1);
ret = mtd->write_oob(mtd, buf.start, &ops);
- if (copy_to_user(argp + sizeof(uint32_t), &ops.retlen,
+ if (copy_to_user(argp + sizeof(uint32_t), &ops.oobretlen,
sizeof(uint32_t)))
ret = -EFAULT;
@@ -548,7 +547,6 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (ret)
return ret;
- ops.len = buf.length;
ops.ooblen = buf.length;
ops.ooboffs = buf.start & (mtd->oobsize - 1);
ops.datbuf = NULL;
@@ -564,10 +562,10 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
buf.start &= ~(mtd->oobsize - 1);
ret = mtd->read_oob(mtd, buf.start, &ops);
- if (put_user(ops.retlen, (uint32_t __user *)argp))
+ if (put_user(ops.oobretlen, (uint32_t __user *)argp))
ret = -EFAULT;
- else if (ops.retlen && copy_to_user(buf.ptr, ops.oobbuf,
- ops.retlen))
+ else if (ops.oobretlen && copy_to_user(buf.ptr, ops.oobbuf,
+ ops.oobretlen))
ret = -EFAULT;
kfree(ops.oobbuf);
@@ -616,6 +614,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos));
memcpy(&oi.oobfree, mtd->ecclayout->oobfree,
sizeof(oi.oobfree));
+ oi.eccbytes = mtd->ecclayout->eccbytes;
if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo)))
return -EFAULT;
@@ -715,7 +714,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (!mtd->ecclayout)
return -EOPNOTSUPP;
- if (copy_to_user(argp, &mtd->ecclayout,
+ if (copy_to_user(argp, mtd->ecclayout,
sizeof(struct nand_ecclayout)))
return -EFAULT;
break;
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 1fea631b585..06902683bc2 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -247,7 +247,7 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
struct mtd_oob_ops devops = *ops;
int i, err, ret = 0;
- ops->retlen = 0;
+ ops->retlen = ops->oobretlen = 0;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
@@ -263,6 +263,7 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
err = subdev->read_oob(subdev, from, &devops);
ops->retlen += devops.retlen;
+ ops->oobretlen += devops.oobretlen;
/* Save information about bitflips! */
if (unlikely(err)) {
@@ -278,14 +279,18 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
return err;
}
- devops.len = ops->len - ops->retlen;
- if (!devops.len)
- return ret;
-
- if (devops.datbuf)
+ if (devops.datbuf) {
+ devops.len = ops->len - ops->retlen;
+ if (!devops.len)
+ return ret;
devops.datbuf += devops.retlen;
- if (devops.oobbuf)
- devops.oobbuf += devops.ooblen;
+ }
+ if (devops.oobbuf) {
+ devops.ooblen = ops->ooblen - ops->oobretlen;
+ if (!devops.ooblen)
+ return ret;
+ devops.oobbuf += ops->oobretlen;
+ }
from = 0;
}
@@ -321,14 +326,18 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
if (err)
return err;
- devops.len = ops->len - ops->retlen;
- if (!devops.len)
- return 0;
-
- if (devops.datbuf)
+ if (devops.datbuf) {
+ devops.len = ops->len - ops->retlen;
+ if (!devops.len)
+ return 0;
devops.datbuf += devops.retlen;
- if (devops.oobbuf)
- devops.oobbuf += devops.ooblen;
+ }
+ if (devops.oobbuf) {
+ devops.ooblen = ops->ooblen - ops->oobretlen;
+ if (!devops.ooblen)
+ return 0;
+ devops.oobbuf += devops.oobretlen;
+ }
to = 0;
}
return -EINVAL;
@@ -699,14 +708,13 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
/* allocate the device structure */
size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
- concat = kmalloc(size, GFP_KERNEL);
+ concat = kzalloc(size, GFP_KERNEL);
if (!concat) {
printk
("memory allocation error while creating concatenated device \"%s\"\n",
name);
return NULL;
}
- memset(concat, 0, size);
concat->subdev = (struct mtd_info **) (concat + 1);
/*
@@ -764,6 +772,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.ecc_stats.badblocks +=
subdev[i]->ecc_stats.badblocks;
if (concat->mtd.writesize != subdev[i]->writesize ||
+ concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
concat->mtd.oobsize != subdev[i]->oobsize ||
concat->mtd.ecctype != subdev[i]->ecctype ||
concat->mtd.eccsize != subdev[i]->eccsize ||
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index c4d26de7434..7070110aba2 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -15,6 +15,7 @@
#include <linux/timer.h>
#include <linux/major.h>
#include <linux/fs.h>
+#include <linux/err.h>
#include <linux/ioctl.h>
#include <linux/init.h>
#include <linux/mtd/compatmac.h>
@@ -192,14 +193,14 @@ int unregister_mtd_user (struct mtd_notifier *old)
* Given a number and NULL address, return the num'th entry in the device
* table, if any. Given an address and num == -1, search the device table
* for a device with that address and return if it's still present. Given
- * both, return the num'th driver only if its address matches. Return NULL
- * if not.
+ * both, return the num'th driver only if its address matches. Return
+ * error code if not.
*/
struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
{
struct mtd_info *ret = NULL;
- int i;
+ int i, err = -ENODEV;
mutex_lock(&mtd_table_mutex);
@@ -213,14 +214,73 @@ struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
ret = NULL;
}
- if (ret && !try_module_get(ret->owner))
- ret = NULL;
+ if (!ret)
+ goto out_unlock;
+
+ if (!try_module_get(ret->owner))
+ goto out_unlock;
- if (ret)
- ret->usecount++;
+ if (ret->get_device) {
+ err = ret->get_device(ret);
+ if (err)
+ goto out_put;
+ }
+ ret->usecount++;
mutex_unlock(&mtd_table_mutex);
return ret;
+
+out_put:
+ module_put(ret->owner);
+out_unlock:
+ mutex_unlock(&mtd_table_mutex);
+ return ERR_PTR(err);
+}
+
+/**
+ * get_mtd_device_nm - obtain a validated handle for an MTD device by
+ * device name
+ * @name: MTD device name to open
+ *
+ * This function returns MTD device description structure in case of
+ * success and an error code in case of failure.
+ */
+
+struct mtd_info *get_mtd_device_nm(const char *name)
+{
+ int i, err = -ENODEV;
+ struct mtd_info *mtd = NULL;
+
+ mutex_lock(&mtd_table_mutex);
+
+ for (i = 0; i < MAX_MTD_DEVICES; i++) {
+ if (mtd_table[i] && !strcmp(name, mtd_table[i]->name)) {
+ mtd = mtd_table[i];
+ break;
+ }
+ }
+
+ if (!mtd)
+ goto out_unlock;
+
+ if (!try_module_get(mtd->owner))
+ goto out_unlock;
+
+ if (mtd->get_device) {
+ err = mtd->get_device(mtd);
+ if (err)
+ goto out_put;
+ }
+
+ mtd->usecount++;
+ mutex_unlock(&mtd_table_mutex);
+ return mtd;
+
+out_put:
+ module_put(mtd->owner);
+out_unlock:
+ mutex_unlock(&mtd_table_mutex);
+ return ERR_PTR(err);
}
void put_mtd_device(struct mtd_info *mtd)
@@ -229,6 +289,8 @@ void put_mtd_device(struct mtd_info *mtd)
mutex_lock(&mtd_table_mutex);
c = --mtd->usecount;
+ if (mtd->put_device)
+ mtd->put_device(mtd);
mutex_unlock(&mtd_table_mutex);
BUG_ON(c < 0);
@@ -236,7 +298,7 @@ void put_mtd_device(struct mtd_info *mtd)
}
/* default_mtd_writev - default mtd writev method for MTD devices that
- * dont implement their own
+ * don't implement their own
*/
int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
@@ -264,13 +326,14 @@ int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
return ret;
}
-EXPORT_SYMBOL(add_mtd_device);
-EXPORT_SYMBOL(del_mtd_device);
-EXPORT_SYMBOL(get_mtd_device);
-EXPORT_SYMBOL(put_mtd_device);
-EXPORT_SYMBOL(register_mtd_user);
-EXPORT_SYMBOL(unregister_mtd_user);
-EXPORT_SYMBOL(default_mtd_writev);
+EXPORT_SYMBOL_GPL(add_mtd_device);
+EXPORT_SYMBOL_GPL(del_mtd_device);
+EXPORT_SYMBOL_GPL(get_mtd_device);
+EXPORT_SYMBOL_GPL(get_mtd_device_nm);
+EXPORT_SYMBOL_GPL(put_mtd_device);
+EXPORT_SYMBOL_GPL(register_mtd_user);
+EXPORT_SYMBOL_GPL(unregister_mtd_user);
+EXPORT_SYMBOL_GPL(default_mtd_writev);
#ifdef CONFIG_PROC_FS
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 06a930372b7..bafd2fba87b 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -94,7 +94,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
if (from >= mtd->size)
return -EINVAL;
- if (from + ops->len > mtd->size)
+ if (ops->datbuf && from + ops->len > mtd->size)
return -EINVAL;
res = part->master->read_oob(part->master, from + part->offset, ops);
@@ -161,7 +161,7 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to,
if (to >= mtd->size)
return -EINVAL;
- if (to + ops->len > mtd->size)
+ if (ops->datbuf && to + ops->len > mtd->size)
return -EINVAL;
return part->master->write_oob(part->master, to + part->offset, ops);
}
@@ -323,14 +323,13 @@ int add_mtd_partitions(struct mtd_info *master,
for (i = 0; i < nbparts; i++) {
/* allocate the partition structure */
- slave = kmalloc (sizeof(*slave), GFP_KERNEL);
+ slave = kzalloc (sizeof(*slave), GFP_KERNEL);
if (!slave) {
printk ("memory allocation error while creating partitions for \"%s\"\n",
master->name);
del_mtd_partitions(master);
return -ENOMEM;
}
- memset(slave, 0, sizeof(*slave));
list_add(&slave->list, &mtd_partitions);
/* set up the MTD object for this partition */
@@ -341,6 +340,7 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.oobsize = master->oobsize;
slave->mtd.ecctype = master->ecctype;
slave->mtd.eccsize = master->eccsize;
+ slave->mtd.subpage_sft = master->subpage_sft;
slave->mtd.name = parts[i].name;
slave->mtd.bank_size = master->bank_size;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 1831340e5f5..358f55a82db 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -90,6 +90,7 @@ config MTD_NAND_RTC_FROM4
depends on MTD_NAND && SH_SOLUTION_ENGINE
select REED_SOLOMON
select REED_SOLOMON_DEC8
+ select BITREVERSE
help
This enables the driver for the Renesas Technology AG-AND
flash interface board (FROM_BOARD4)
@@ -132,6 +133,7 @@ config MTD_NAND_S3C2410_HWECC
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
depends on MTD_NAND && 44x
+ select MTD_NAND_ECC_SMC
help
NDFC Nand Flash Controllers are integrated in EP44x SoCs
@@ -219,6 +221,13 @@ config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on MTD_NAND && ARCH_PXA
+config MTD_NAND_CAFE
+ tristate "NAND support for OLPC CAFÉ chip"
+ depends on PCI
+ help
+ Use NAND flash attached to the CAFÉ chip designed for the $100
+ laptop.
+
config MTD_NAND_CS553X
tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
depends on MTD_NAND && X86_32 && (X86_PC || X86_GENERICARCH)
@@ -232,6 +241,13 @@ config MTD_NAND_CS553X
If you say "m", the module will be called "cs553x_nand.ko".
+config MTD_NAND_AT91
+ bool "Support for NAND Flash / SmartMedia on AT91"
+ depends on MTD_NAND && ARCH_AT91
+ help
+ Enables support for NAND Flash / Smart Media Card interface
+ on Atmel AT91 processors.
+
config MTD_NAND_NANDSIM
tristate "Support for NAND Flash Simulator"
depends on MTD_NAND && MTD_PARTITIONS
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index f74759351c9..f7a53f0b701 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
+obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
@@ -22,5 +23,7 @@ obj-$(CONFIG_MTD_NAND_TS7250) += ts7250.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
+obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
-nand-objs = nand_base.o nand_bbt.o
+nand-objs := nand_base.o nand_bbt.o
+cafe_nand-objs := cafe.o cafe_ecc.o
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
new file mode 100644
index 00000000000..14b80cc90a7
--- /dev/null
+++ b/drivers/mtd/nand/at91_nand.c
@@ -0,0 +1,223 @@
+/*
+ * drivers/mtd/nand/at91_nand.c
+ *
+ * Copyright (C) 2003 Rick Bronson
+ *
+ * Derived from drivers/mtd/nand/autcpu12.c
+ * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * Derived from drivers/mtd/spia.c
+ * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.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/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+
+struct at91_nand_host {
+ struct nand_chip nand_chip;
+ struct mtd_info mtd;
+ void __iomem *io_base;
+ struct at91_nand_data *board;
+};
+
+/*
+ * Hardware specific access to control-lines
+ */
+static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct at91_nand_host *host = nand_chip->priv;
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ if (ctrl & NAND_CLE)
+ writeb(cmd, host->io_base + (1 << host->board->cle));
+ else
+ writeb(cmd, host->io_base + (1 << host->board->ale));
+}
+
+/*
+ * Read the Device Ready pin.
+ */
+static int at91_nand_device_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct at91_nand_host *host = nand_chip->priv;
+
+ return at91_get_gpio_value(host->board->rdy_pin);
+}
+
+/*
+ * Enable NAND.
+ */
+static void at91_nand_enable(struct at91_nand_host *host)
+{
+ if (host->board->enable_pin)
+ at91_set_gpio_value(host->board->enable_pin, 0);
+}
+
+/*
+ * Disable NAND.
+ */
+static void at91_nand_disable(struct at91_nand_host *host)
+{
+ if (host->board->enable_pin)
+ at91_set_gpio_value(host->board->enable_pin, 1);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int __init at91_nand_probe(struct platform_device *pdev)
+{
+ struct at91_nand_host *host;
+ struct mtd_info *mtd;
+ struct nand_chip *nand_chip;
+ int res;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *partitions = NULL;
+ int num_partitions = 0;
+#endif
+
+ /* Allocate memory for the device structure (and zero it) */
+ host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL);
+ if (!host) {
+ printk(KERN_ERR "at91_nand: failed to allocate device structure.\n");
+ return -ENOMEM;
+ }
+
+ host->io_base = ioremap(pdev->resource[0].start,
+ pdev->resource[0].end - pdev->resource[0].start + 1);
+ if (host->io_base == NULL) {
+ printk(KERN_ERR "at91_nand: ioremap failed\n");
+ kfree(host);
+ return -EIO;
+ }
+
+ mtd = &host->mtd;
+ nand_chip = &host->nand_chip;
+ host->board = pdev->dev.platform_data;
+
+ nand_chip->priv = host; /* link the private data structures */
+ mtd->priv = nand_chip;
+ mtd->owner = THIS_MODULE;
+
+ /* Set address of NAND IO lines */
+ nand_chip->IO_ADDR_R = host->io_base;
+ nand_chip->IO_ADDR_W = host->io_base;
+ nand_chip->cmd_ctrl = at91_nand_cmd_ctrl;
+ nand_chip->dev_ready = at91_nand_device_ready;
+ nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
+ nand_chip->chip_delay = 20; /* 20us command delay time */
+
+ if (host->board->bus_width_16) /* 16-bit bus width */
+ nand_chip->options |= NAND_BUSWIDTH_16;
+
+ platform_set_drvdata(pdev, host);
+ at91_nand_enable(host);
+
+ if (host->board->det_pin) {
+ if (at91_get_gpio_value(host->board->det_pin)) {
+ printk ("No SmartMedia card inserted.\n");
+ res = ENXIO;
+ goto out;
+ }
+ }
+
+ /* Scan to find existance of the device */
+ if (nand_scan(mtd, 1)) {
+ res = -ENXIO;
+ goto out;
+ }
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (host->board->partition_info)
+ partitions = host->board->partition_info(mtd->size, &num_partitions);
+
+ if ((!partitions) || (num_partitions == 0)) {
+ printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n");
+ res = ENXIO;
+ goto release;
+ }
+
+ res = add_mtd_partitions(mtd, partitions, num_partitions);
+#else
+ res = add_mtd_device(mtd);
+#endif
+
+ if (!res)
+ return res;
+
+release:
+ nand_release(mtd);
+out:
+ at91_nand_disable(host);
+ platform_set_drvdata(pdev, NULL);
+ iounmap(host->io_base);
+ kfree(host);
+ return res;
+}
+
+/*
+ * Remove a NAND device.
+ */
+static int __devexit at91_nand_remove(struct platform_device *pdev)
+{
+ struct at91_nand_host *host = platform_get_drvdata(pdev);
+ struct mtd_info *mtd = &host->mtd;
+
+ nand_release(mtd);
+
+ at91_nand_disable(host);
+
+ iounmap(host->io_base);
+ kfree(host);
+
+ return 0;
+}
+
+static struct platform_driver at91_nand_driver = {
+ .probe = at91_nand_probe,
+ .remove = at91_nand_remove,
+ .driver = {
+ .name = "at91_nand",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at91_nand_init(void)
+{
+ return platform_driver_register(&at91_nand_driver);
+}
+
+
+static void __exit at91_nand_exit(void)
+{
+ platform_driver_unregister(&at91_nand_driver);
+}
+
+
+module_init(at91_nand_init);
+module_exit(at91_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200");
diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe.c
new file mode 100644
index 00000000000..65f9bd3ceeb
--- /dev/null
+++ b/drivers/mtd/nand/cafe.c
@@ -0,0 +1,771 @@
+/*
+ * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
+ *
+ * Copyright © 2006 Red Hat, Inc.
+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
+ */
+
+#define DEBUG
+
+#include <linux/device.h>
+#undef DEBUG
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+
+#define CAFE_NAND_CTRL1 0x00
+#define CAFE_NAND_CTRL2 0x04
+#define CAFE_NAND_CTRL3 0x08
+#define CAFE_NAND_STATUS 0x0c
+#define CAFE_NAND_IRQ 0x10
+#define CAFE_NAND_IRQ_MASK 0x14
+#define CAFE_NAND_DATA_LEN 0x18
+#define CAFE_NAND_ADDR1 0x1c
+#define CAFE_NAND_ADDR2 0x20
+#define CAFE_NAND_TIMING1 0x24
+#define CAFE_NAND_TIMING2 0x28
+#define CAFE_NAND_TIMING3 0x2c
+#define CAFE_NAND_NONMEM 0x30
+#define CAFE_NAND_ECC_RESULT 0x3C
+#define CAFE_NAND_DMA_CTRL 0x40
+#define CAFE_NAND_DMA_ADDR0 0x44
+#define CAFE_NAND_DMA_ADDR1 0x48
+#define CAFE_NAND_ECC_SYN01 0x50
+#define CAFE_NAND_ECC_SYN23 0x54
+#define CAFE_NAND_ECC_SYN45 0x58
+#define CAFE_NAND_ECC_SYN67 0x5c
+#define CAFE_NAND_READ_DATA 0x1000
+#define CAFE_NAND_WRITE_DATA 0x2000
+
+#define CAFE_GLOBAL_CTRL 0x3004
+#define CAFE_GLOBAL_IRQ 0x3008
+#define CAFE_GLOBAL_IRQ_MASK 0x300c
+#define CAFE_NAND_RESET 0x3034
+
+int cafe_correct_ecc(unsigned char *buf,
+ unsigned short *chk_syndrome_list);
+
+struct cafe_priv {
+ struct nand_chip nand;
+ struct pci_dev *pdev;
+ void __iomem *mmio;
+ uint32_t ctl1;
+ uint32_t ctl2;
+ int datalen;
+ int nr_data;
+ int data_pos;
+ int page_addr;
+ dma_addr_t dmaaddr;
+ unsigned char *dmabuf;
+};
+
+static int usedma = 1;
+module_param(usedma, int, 0644);
+
+static int skipbbt = 0;
+module_param(skipbbt, int, 0644);
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+static int regdebug = 0;
+module_param(regdebug, int, 0644);
+
+static int checkecc = 1;
+module_param(checkecc, int, 0644);
+
+static int slowtiming = 0;
+module_param(slowtiming, int, 0644);
+
+/* Hrm. Why isn't this already conditional on something in the struct device? */
+#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
+
+/* Make it easier to switch to PIO if we need to */
+#define cafe_readl(cafe, addr) readl((cafe)->mmio + CAFE_##addr)
+#define cafe_writel(cafe, datum, addr) writel(datum, (cafe)->mmio + CAFE_##addr)
+
+static int cafe_device_ready(struct mtd_info *mtd)
+{
+ struct cafe_priv *cafe = mtd->priv;
+ int result = !!(cafe_readl(cafe, NAND_STATUS) | 0x40000000);
+ uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
+
+ cafe_writel(cafe, irqs, NAND_IRQ);
+
+ cafe_dev_dbg(&cafe->pdev->dev, "NAND device is%s ready, IRQ %x (%x) (%x,%x)\n",
+ result?"":" not", irqs, cafe_readl(cafe, NAND_IRQ),
+ cafe_readl(cafe, GLOBAL_IRQ), cafe_readl(cafe, GLOBAL_IRQ_MASK));
+
+ return result;
+}
+
+
+static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ struct cafe_priv *cafe = mtd->priv;
+
+ if (usedma)
+ memcpy(cafe->dmabuf + cafe->datalen, buf, len);
+ else
+ memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len);
+
+ cafe->datalen += len;
+
+ cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes to write buffer. datalen 0x%x\n",
+ len, cafe->datalen);
+}
+
+static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct cafe_priv *cafe = mtd->priv;
+
+ if (usedma)
+ memcpy(buf, cafe->dmabuf + cafe->datalen, len);
+ else
+ memcpy_fromio(buf, cafe->mmio + CAFE_NAND_READ_DATA + cafe->datalen, len);
+
+ cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes from position 0x%x in read buffer.\n",
+ len, cafe->datalen);
+ cafe->datalen += len;
+}
+
+static uint8_t cafe_read_byte(struct mtd_info *mtd)
+{
+ struct cafe_priv *cafe = mtd->priv;
+ uint8_t d;
+
+ cafe_read_buf(mtd, &d, 1);
+ cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d);
+
+ return d;
+}
+
+static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+ int column, int page_addr)
+{
+ struct cafe_priv *cafe = mtd->priv;
+ int adrbytes = 0;
+ uint32_t ctl1;
+ uint32_t doneint = 0x80000000;
+
+ cafe_dev_dbg(&cafe->pdev->dev, "cmdfunc %02x, 0x%x, 0x%x\n",
+ command, column, page_addr);
+
+ if (command == NAND_CMD_ERASE2 || command == NAND_CMD_PAGEPROG) {
+ /* Second half of a command we already calculated */
+ cafe_writel(cafe, cafe->ctl2 | 0x100 | command, NAND_CTRL2);
+ ctl1 = cafe->ctl1;
+ cafe->ctl2 &= ~(1<<30);
+ cafe_dev_dbg(&cafe->pdev->dev, "Continue command, ctl1 %08x, #data %d\n",
+ cafe->ctl1, cafe->nr_data);
+ goto do_command;
+ }
+ /* Reset ECC engine */
+ cafe_writel(cafe, 0, NAND_CTRL2);
+
+ /* Emulate NAND_CMD_READOOB on large-page chips */
+ if (mtd->writesize > 512 &&
+ command == NAND_CMD_READOOB) {
+ column += mtd->writesize;
+ command = NAND_CMD_READ0;
+ }
+
+ /* FIXME: Do we need to send read command before sending data
+ for small-page chips, to position the buffer correctly? */
+
+ if (column != -1) {
+ cafe_writel(cafe, column, NAND_ADDR1);
+ adrbytes = 2;
+ if (page_addr != -1)
+ goto write_adr2;
+ } else if (page_addr != -1) {
+ cafe_writel(cafe, page_addr & 0xffff, NAND_ADDR1);
+ page_addr >>= 16;
+ write_adr2:
+ cafe_writel(cafe, page_addr, NAND_ADDR2);
+ adrbytes += 2;
+ if (mtd->size > mtd->writesize << 16)
+ adrbytes++;
+ }
+
+ cafe->data_pos = cafe->datalen = 0;
+
+ /* Set command valid bit */
+ ctl1 = 0x80000000 | command;
+
+ /* Set RD or WR bits as appropriate */
+ if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) {
+ ctl1 |= (1<<26); /* rd */
+ /* Always 5 bytes, for now */
+ cafe->datalen = 4;
+ /* And one address cycle -- even for STATUS, since the controller doesn't work without */
+ adrbytes = 1;
+ } else if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
+ command == NAND_CMD_READOOB || command == NAND_CMD_RNDOUT) {
+ ctl1 |= 1<<26; /* rd */
+ /* For now, assume just read to end of page */
+ cafe->datalen = mtd->writesize + mtd->oobsize - column;
+ } else if (command == NAND_CMD_SEQIN)
+ ctl1 |= 1<<25; /* wr */
+
+ /* Set number of address bytes */
+ if (adrbytes)
+ ctl1 |= ((adrbytes-1)|8) << 27;
+
+ if (command == NAND_CMD_SEQIN || command == NAND_CMD_ERASE1) {
+ /* Ignore the first command of a pair; the hardware
+ deals with them both at once, later */
+ cafe->ctl1 = ctl1;
+ cafe_dev_dbg(&cafe->pdev->dev, "Setup for delayed command, ctl1 %08x, dlen %x\n",
+ cafe->ctl1, cafe->datalen);
+ return;
+ }
+ /* RNDOUT and READ0 commands need a following byte */
+ if (command == NAND_CMD_RNDOUT)
+ cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_RNDOUTSTART, NAND_CTRL2);
+ else if (command == NAND_CMD_READ0 && mtd->writesize > 512)
+ cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_READSTART, NAND_CTRL2);
+
+ do_command:
+ cafe_dev_dbg(&cafe->pdev->dev, "dlen %x, ctl1 %x, ctl2 %x\n",
+ cafe->datalen, ctl1, cafe_readl(cafe, NAND_CTRL2));
+
+ /* NB: The datasheet lies -- we really should be subtracting 1 here */
+ cafe_writel(cafe, cafe->datalen, NAND_DATA_LEN);
+ cafe_writel(cafe, 0x90000000, NAND_IRQ);
+ if (usedma && (ctl1 & (3<<25))) {
+ uint32_t dmactl = 0xc0000000 + cafe->datalen;
+ /* If WR or RD bits set, set up DMA */
+ if (ctl1 & (1<<26)) {
+ /* It's a read */
+ dmactl |= (1<<29);
+ /* ... so it's done when the DMA is done, not just
+ the command. */
+ doneint = 0x10000000;
+ }
+ cafe_writel(cafe, dmactl, NAND_DMA_CTRL);
+ }
+ cafe->datalen = 0;
+
+ if (unlikely(regdebug)) {
+ int i;
+ printk("About to write command %08x to register 0\n", ctl1);
+ for (i=4; i< 0x5c; i+=4)
+ printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
+ }
+
+ cafe_writel(cafe, ctl1, NAND_CTRL1);
+ /* Apply this short delay always to ensure that we do wait tWB in
+ * any case on any machine. */
+ ndelay(100);
+
+ if (1) {
+ int c = 500000;
+ uint32_t irqs;
+
+ while (c--) {
+ irqs = cafe_readl(cafe, NAND_IRQ);
+ if (irqs & doneint)
+ break;
+ udelay(1);
+ if (!(c % 100000))
+ cafe_dev_dbg(&cafe->pdev->dev, "Wait for ready, IRQ %x\n", irqs);
+ cpu_relax();
+ }
+ cafe_writel(cafe, doneint, NAND_IRQ);
+ cafe_dev_dbg(&cafe->pdev->dev, "Command %x completed after %d usec, irqs %x (%x)\n",
+ command, 500000-c, irqs, cafe_readl(cafe, NAND_IRQ));
+ }
+
+ WARN_ON(cafe->ctl2 & (1<<30));
+
+ switch (command) {
+
+ case NAND_CMD_CACHEDPROG:
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_ERASE2:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_RNDIN:
+ case NAND_CMD_STATUS:
+ case NAND_CMD_DEPLETE1:
+ case NAND_CMD_RNDOUT:
+ case NAND_CMD_STATUS_ERROR:
+ case NAND_CMD_STATUS_ERROR0:
+ case NAND_CMD_STATUS_ERROR1:
+ case NAND_CMD_STATUS_ERROR2:
+ case NAND_CMD_STATUS_ERROR3:
+ cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
+ return;
+ }
+ nand_wait_ready(mtd);
+ cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
+}
+
+static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
+{
+ //struct cafe_priv *cafe = mtd->priv;
+ // cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
+}
+
+static int cafe_nand_interrupt(int irq, void *id)
+{
+ struct mtd_info *mtd = id;
+ struct cafe_priv *cafe = mtd->priv;
+ uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
+ cafe_writel(cafe, irqs & ~0x90000000, NAND_IRQ);
+ if (!irqs)
+ return IRQ_NONE;
+
+ cafe_dev_dbg(&cafe->pdev->dev, "irq, bits %x (%x)\n", irqs, cafe_readl(cafe, NAND_IRQ));
+ return IRQ_HANDLED;
+}
+
+static void cafe_nand_bug(struct mtd_info *mtd)
+{
+ BUG();
+}
+
+static int cafe_nand_write_oob(struct mtd_info *mtd,
+ struct nand_chip *chip, int page)
+{
+ int status = 0;
+
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ status = chip->waitfunc(mtd, chip);
+
+ return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+/* Don't use -- use nand_read_oob_std for now */
+static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int sndcmd)
+{
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ return 1;
+}
+/**
+ * cafe_nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ *
+ * The hw generator calculates the error syndrome automatically. Therefor
+ * we need a special oob layout and handling.
+ */
+static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
+{
+ struct cafe_priv *cafe = mtd->priv;
+
+ cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n",
+ cafe_readl(cafe, NAND_ECC_RESULT),
+ cafe_readl(cafe, NAND_ECC_SYN01));
+
+ chip->read_buf(mtd, buf, mtd->writesize);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
+ unsigned short syn[8];
+ int i;
+
+ for (i=0; i<8; i+=2) {
+ uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
+ syn[i] = tmp & 0xfff;
+ syn[i+1] = (tmp >> 16) & 0xfff;
+ }
+
+ if ((i = cafe_correct_ecc(buf, syn)) < 0) {
+ dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
+ cafe_readl(cafe, NAND_ADDR2) * 2048);
+ for (i=0; i< 0x5c; i+=4)
+ printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
+ mtd->ecc_stats.failed++;
+ } else {
+ dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", i);
+ mtd->ecc_stats.corrected += i;
+ }
+ }
+
+
+ return 0;
+}
+
+static struct nand_ecclayout cafe_oobinfo_2048 = {
+ .eccbytes = 14,
+ .eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
+ .oobfree = {{14, 50}}
+};
+
+/* Ick. The BBT code really ought to be able to work this bit out
+ for itself from the above, at least for the 2KiB case */
+static uint8_t cafe_bbt_pattern_2048[] = { 'B', 'b', 't', '0' };
+static uint8_t cafe_mirror_pattern_2048[] = { '1', 't', 'b', 'B' };
+
+static uint8_t cafe_bbt_pattern_512[] = { 0xBB };
+static uint8_t cafe_mirror_pattern_512[] = { 0xBC };
+
+
+static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 14,
+ .len = 4,
+ .veroffs = 18,
+ .maxblocks = 4,
+ .pattern = cafe_bbt_pattern_2048
+};
+
+static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 14,
+ .len = 4,
+ .veroffs = 18,
+ .maxblocks = 4,
+ .pattern = cafe_mirror_pattern_2048
+};
+
+static struct nand_ecclayout cafe_oobinfo_512 = {
+ .eccbytes = 14,
+ .eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
+ .oobfree = {{14, 2}}
+};
+
+static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 14,
+ .len = 1,
+ .veroffs = 15,
+ .maxblocks = 4,
+ .pattern = cafe_bbt_pattern_512
+};
+
+static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 14,
+ .len = 1,
+ .veroffs = 15,
+ .maxblocks = 4,
+ .pattern = cafe_mirror_pattern_512
+};
+
+
+static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf)
+{
+ struct cafe_priv *cafe = mtd->priv;
+
+ chip->write_buf(mtd, buf, mtd->writesize);
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ /* Set up ECC autogeneration */
+ cafe->ctl2 |= (1<<30);
+}
+
+static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int page, int cached, int raw)
+{
+ int status;
+
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+
+ 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
+ * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
+ */
+ cached = 0;
+
+ if (!cached || !(chip->options & NAND_CACHEPRG)) {
+
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ status = chip->waitfunc(mtd, chip);
+ /*
+ * See if operation failed and additional status checks are
+ * available
+ */
+ if ((status & NAND_STATUS_FAIL) && (chip->errstat))
+ status = chip->errstat(mtd, chip, FL_WRITING, status,
+ page);
+
+ if (status & NAND_STATUS_FAIL)
+ return -EIO;
+ } else {
+ chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
+ status = chip->waitfunc(mtd, chip);
+ }
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+ /* Send command to read back the data */
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+ if (chip->verify_buf(mtd, buf, mtd->writesize))
+ return -EIO;
+#endif
+ return 0;
+}
+
+static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+{
+ return 0;
+}
+
+static int __devinit cafe_nand_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct mtd_info *mtd;
+ struct cafe_priv *cafe;
+ uint32_t ctrl;
+ int err = 0;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ pci_set_master(pdev);
+
+ mtd = kzalloc(sizeof(*mtd) + sizeof(struct cafe_priv), GFP_KERNEL);
+ if (!mtd) {
+ dev_warn(&pdev->dev, "failed to alloc mtd_info\n");
+ return -ENOMEM;
+ }
+ cafe = (void *)(&mtd[1]);
+
+ mtd->priv = cafe;
+ mtd->owner = THIS_MODULE;
+
+ cafe->pdev = pdev;
+ cafe->mmio = pci_iomap(pdev, 0, 0);
+ if (!cafe->mmio) {
+ dev_warn(&pdev->dev, "failed to iomap\n");
+ err = -ENOMEM;
+ goto out_free_mtd;
+ }
+ cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112 + sizeof(struct nand_buffers),
+ &cafe->dmaaddr, GFP_KERNEL);
+ if (!cafe->dmabuf) {
+ err = -ENOMEM;
+ goto out_ior;
+ }
+ cafe->nand.buffers = (void *)cafe->dmabuf + 2112;
+
+ cafe->nand.cmdfunc = cafe_nand_cmdfunc;
+ cafe->nand.dev_ready = cafe_device_ready;
+ cafe->nand.read_byte = cafe_read_byte;
+ cafe->nand.read_buf = cafe_read_buf;
+ cafe->nand.write_buf = cafe_write_buf;
+ cafe->nand.select_chip = cafe_select_chip;
+
+ cafe->nand.chip_delay = 0;
+
+ /* Enable the following for a flash based bad block table */
+ cafe->nand.options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR | NAND_OWN_BUFFERS;
+
+ if (skipbbt) {
+ cafe->nand.options |= NAND_SKIP_BBTSCAN;
+ cafe->nand.block_bad = cafe_nand_block_bad;
+ }
+
+ /* Start off by resetting the NAND controller completely */
+ cafe_writel(cafe, 1, NAND_RESET);
+ cafe_writel(cafe, 0, NAND_RESET);
+
+ cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
+
+ /* Timings from Marvell's test code (not verified or calculated by us) */
+ if (!slowtiming) {
+ cafe_writel(cafe, 0x01010a0a, NAND_TIMING1);
+ cafe_writel(cafe, 0x24121212, NAND_TIMING2);
+ cafe_writel(cafe, 0x11000000, NAND_TIMING3);
+ } else {
+ cafe_writel(cafe, 0xffffffff, NAND_TIMING1);
+ cafe_writel(cafe, 0xffffffff, NAND_TIMING2);
+ cafe_writel(cafe, 0xffffffff, NAND_TIMING3);
+ }
+ cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
+ err = request_irq(pdev->irq, &cafe_nand_interrupt, SA_SHIRQ, "CAFE NAND", mtd);
+ if (err) {
+ dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
+
+ goto out_free_dma;
+ }
+#if 1
+ /* Disable master reset, enable NAND clock */
+ ctrl = cafe_readl(cafe, GLOBAL_CTRL);
+ ctrl &= 0xffffeff0;
+ ctrl |= 0x00007000;
+ cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
+ cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
+ cafe_writel(cafe, 0, NAND_DMA_CTRL);
+
+ cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
+ cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
+
+ /* Set up DMA address */
+ cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
+ if (sizeof(cafe->dmaaddr) > 4)
+ /* Shift in two parts to shut the compiler up */
+ cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
+ else
+ cafe_writel(cafe, 0, NAND_DMA_ADDR1);
+
+ cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
+ cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
+
+ /* Enable NAND IRQ in global IRQ mask register */
+ cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
+ cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
+ cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK));
+#endif
+#if 1
+ mtd->writesize=2048;
+ mtd->oobsize = 0x40;
+ memset(cafe->dmabuf, 0x5a, 2112);
+ cafe->nand.cmdfunc(mtd, NAND_CMD_READID, 0, -1);
+ cafe->nand.read_byte(mtd);
+ cafe->nand.read_byte(mtd);
+ cafe->nand.read_byte(mtd);
+ cafe->nand.read_byte(mtd);
+ cafe->nand.read_byte(mtd);
+#endif
+#if 0
+ cafe->nand.cmdfunc(mtd, NAND_CMD_READ0, 0, 0);
+ // nand_wait_ready(mtd);
+ cafe->nand.read_byte(mtd);
+ cafe->nand.read_byte(mtd);
+ cafe->nand.read_byte(mtd);
+ cafe->nand.read_byte(mtd);
+#endif
+#if 0
+ writel(0x84600070, cafe->mmio);
+ udelay(10);
+ cafe_dev_dbg(&cafe->pdev->dev, "Status %x\n", cafe_readl(cafe, NAND_NONMEM));
+#endif
+ /* Scan to find existance of the device */
+ if (nand_scan_ident(mtd, 1)) {
+ err = -ENXIO;
+ goto out_irq;
+ }
+
+ cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
+ if (mtd->writesize == 2048)
+ cafe->ctl2 |= 1<<29; /* 2KiB page size */
+
+ /* Set up ECC according to the type of chip we found */
+ if (mtd->writesize == 2048) {
+ cafe->nand.ecc.layout = &cafe_oobinfo_2048;
+ cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
+ cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
+ } else if (mtd->writesize == 512) {
+ cafe->nand.ecc.layout = &cafe_oobinfo_512;
+ cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
+ cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
+ } else {
+ printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n",
+ mtd->writesize);
+ goto out_irq;
+ }
+ cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
+ cafe->nand.ecc.size = mtd->writesize;
+ cafe->nand.ecc.bytes = 14;
+ cafe->nand.ecc.hwctl = (void *)cafe_nand_bug;
+ cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
+ cafe->nand.ecc.correct = (void *)cafe_nand_bug;
+ cafe->nand.write_page = cafe_nand_write_page;
+ cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
+ cafe->nand.ecc.write_oob = cafe_nand_write_oob;
+ cafe->nand.ecc.read_page = cafe_nand_read_page;
+ cafe->nand.ecc.read_oob = cafe_nand_read_oob;
+
+ err = nand_scan_tail(mtd);
+ if (err)
+ goto out_irq;
+
+ pci_set_drvdata(pdev, mtd);
+ add_mtd_device(mtd);
+ goto out;
+
+ out_irq:
+ /* Disable NAND IRQ in global IRQ mask register */
+ cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
+ free_irq(pdev->irq, mtd);
+ out_free_dma:
+ dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+ out_ior:
+ pci_iounmap(pdev, cafe->mmio);
+ out_free_mtd:
+ kfree(mtd);
+ out:
+ return err;
+}
+
+static void __devexit cafe_nand_remove(struct pci_dev *pdev)
+{
+ struct mtd_info *mtd = pci_get_drvdata(pdev);
+ struct cafe_priv *cafe = mtd->priv;
+
+ del_mtd_device(mtd);
+ /* Disable NAND IRQ in global IRQ mask register */
+ cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
+ free_irq(pdev->irq, mtd);
+ nand_release(mtd);
+ pci_iounmap(pdev, cafe->mmio);
+ dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+ kfree(mtd);
+}
+
+static struct pci_device_id cafe_nand_tbl[] = {
+ { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 }
+};
+
+MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
+
+static struct pci_driver cafe_nand_pci_driver = {
+ .name = "CAFÉ NAND",
+ .id_table = cafe_nand_tbl,
+ .probe = cafe_nand_probe,
+ .remove = __devexit_p(cafe_nand_remove),
+#ifdef CONFIG_PMx
+ .suspend = cafe_nand_suspend,
+ .resume = cafe_nand_resume,
+#endif
+};
+
+static int cafe_nand_init(void)
+{
+ return pci_register_driver(&cafe_nand_pci_driver);
+}
+
+static void cafe_nand_exit(void)
+{
+ pci_unregister_driver(&cafe_nand_pci_driver);
+}
+module_init(cafe_nand_init);
+module_exit(cafe_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("NAND flash driver for OLPC CAFE chip");
+
+/* Correct ECC for 2048 bytes of 0xff:
+ 41 a0 71 65 54 27 f3 93 ec a9 be ed 0b a1 */
+
+/* dwmw2's B-test board, in case of completely screwing it:
+Bad eraseblock 2394 at 0x12b40000
+Bad eraseblock 2627 at 0x14860000
+Bad eraseblock 3349 at 0x1a2a0000
+*/
diff --git a/drivers/mtd/nand/cafe_ecc.c b/drivers/mtd/nand/cafe_ecc.c
new file mode 100644
index 00000000000..1b9fa05a447
--- /dev/null
+++ b/drivers/mtd/nand/cafe_ecc.c
@@ -0,0 +1,1381 @@
+/* Error correction for CAFÉ NAND controller
+ *
+ * © 2006 Marvell, Inc.
+ * Author: Tom Chiou
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+
+static unsigned short gf4096_mul(unsigned short, unsigned short);
+static unsigned short gf64_mul(unsigned short, unsigned short);
+static unsigned short gf4096_inv(unsigned short);
+static unsigned short err_pos(unsigned short);
+static void find_4bit_err_coefs(unsigned short, unsigned short, unsigned short,
+ unsigned short, unsigned short, unsigned short,
+ unsigned short, unsigned short, unsigned short *);
+static void zero_4x5_col3(unsigned short[4][5]);
+static void zero_4x5_col2(unsigned short[4][5]);
+static void zero_4x5_col1(unsigned short[4][5]);
+static void swap_4x5_rows(unsigned short[4][5], int, int, int);
+static void swap_2x3_rows(unsigned short m[2][3]);
+static void solve_4x5(unsigned short m[4][5], unsigned short *, int *);
+static void sort_coefs(int *, unsigned short *, int);
+static void find_4bit_err_pats(unsigned short, unsigned short, unsigned short,
+ unsigned short, unsigned short, unsigned short,
+ unsigned short, unsigned short, unsigned short *);
+static void find_3bit_err_coefs(unsigned short, unsigned short, unsigned short,
+ unsigned short, unsigned short, unsigned short,
+ unsigned short *);
+static void zero_3x4_col2(unsigned short[3][4]);
+static void zero_3x4_col1(unsigned short[3][4]);
+static void swap_3x4_rows(unsigned short[3][4], int, int, int);
+static void solve_3x4(unsigned short[3][4], unsigned short *, int *);
+static void find_3bit_err_pats(unsigned short, unsigned short, unsigned short,
+ unsigned short, unsigned short, unsigned short,
+ unsigned short *);
+
+static void find_2bit_err_pats(unsigned short, unsigned short, unsigned short,
+ unsigned short, unsigned short *);
+static void find_2x2_soln(unsigned short, unsigned short, unsigned short,
+ unsigned short, unsigned short, unsigned short,
+ unsigned short *);
+static void solve_2x3(unsigned short[2][3], unsigned short *);
+static int chk_no_err_only(unsigned short *, unsigned short *);
+static int chk_1_err_only(unsigned short *, unsigned short *);
+static int chk_2_err_only(unsigned short *, unsigned short *);
+static int chk_3_err_only(unsigned short *, unsigned short *);
+static int chk_4_err_only(unsigned short *, unsigned short *);
+
+static unsigned short gf64_mul(unsigned short a, unsigned short b)
+{
+ unsigned short tmp1, tmp2, tmp3, tmp4, tmp5;
+ unsigned short c_bit0, c_bit1, c_bit2, c_bit3, c_bit4, c_bit5, c;
+
+ tmp1 = ((a) ^ (a >> 5));
+ tmp2 = ((a >> 4) ^ (a >> 5));
+ tmp3 = ((a >> 3) ^ (a >> 4));
+ tmp4 = ((a >> 2) ^ (a >> 3));
+ tmp5 = ((a >> 1) ^ (a >> 2));
+
+ c_bit0 = ((a & b) ^ ((a >> 5) & (b >> 1)) ^ ((a >> 4) & (b >> 2)) ^
+ ((a >> 3) & (b >> 3)) ^ ((a >> 2) & (b >> 4)) ^ ((a >> 1) & (b >> 5))) & 0x1;
+
+ c_bit1 = (((a >> 1) & b) ^ (tmp1 & (b >> 1)) ^ (tmp2 & (b >> 2)) ^
+ (tmp3 & (b >> 3)) ^ (tmp4 & (b >> 4)) ^ (tmp5 & (b >> 5))) & 0x1;
+
+ c_bit2 = (((a >> 2) & b) ^ ((a >> 1) & (b >> 1)) ^ (tmp1 & (b >> 2)) ^
+ (tmp2 & (b >> 3)) ^ (tmp3 & (b >> 4)) ^ (tmp4 & (b >> 5))) & 0x1;
+
+ c_bit3 = (((a >> 3) & b) ^ ((a >> 2) & (b >> 1)) ^ ((a >> 1) & (b >> 2)) ^
+ (tmp1 & (b >> 3)) ^ (tmp2 & (b >> 4)) ^ (tmp3 & (b >> 5))) & 0x1;
+
+ c_bit4 = (((a >> 4) & b) ^ ((a >> 3) & (b >> 1)) ^ ((a >> 2) & (b >> 2)) ^
+ ((a >> 1) & (b >> 3)) ^ (tmp1 & (b >> 4)) ^ (tmp2 & (b >> 5))) & 0x1;
+
+ c_bit5 = (((a >> 5) & b) ^ ((a >> 4) & (b >> 1)) ^ ((a >> 3) & (b >> 2)) ^
+ ((a >> 2) & (b >> 3)) ^ ((a >> 1) & (b >> 4)) ^ (tmp1 & (b >> 5))) & 0x1;
+
+ c = c_bit0 | (c_bit1 << 1) | (c_bit2 << 2) | (c_bit3 << 3) | (c_bit4 << 4) | (c_bit5 << 5);
+
+ return c;
+}
+
+static unsigned short gf4096_mul(unsigned short a, unsigned short b)
+{
+ unsigned short ah, al, bh, bl, alxah, blxbh, ablh, albl, ahbh, ahbhB, c;
+
+ ah = (a >> 6) & 0x3f;
+ al = a & 0x3f;
+ bh = (b >> 6) & 0x3f;
+ bl = b & 0x3f;
+ alxah = al ^ ah;
+ blxbh = bl ^ bh;
+
+ ablh = gf64_mul(alxah, blxbh);
+ albl = gf64_mul(al, bl);
+ ahbh = gf64_mul(ah, bh);
+
+ ahbhB = ((ahbh & 0x1) << 5) |
+ ((ahbh & 0x20) >> 1) |
+ ((ahbh & 0x10) >> 1) | ((ahbh & 0x8) >> 1) | ((ahbh & 0x4) >> 1) | (((ahbh >> 1) ^ ahbh) & 0x1);
+
+ c = ((ablh ^ albl) << 6) | (ahbhB ^ albl);
+ return c;
+}
+
+static void find_2bit_err_pats(unsigned short s0, unsigned short s1, unsigned short r0, unsigned short r1, unsigned short *pats)
+{
+ find_2x2_soln(0x1, 0x1, r0, r1, s0, s1, pats);
+}
+
+static void find_3bit_err_coefs(unsigned short s0, unsigned short s1,
+ unsigned short s2, unsigned short s3, unsigned short s4, unsigned short s5, unsigned short *coefs)
+{
+ unsigned short m[3][4];
+ int row_order[3];
+
+ row_order[0] = 0;
+ row_order[1] = 1;
+ row_order[2] = 2;
+ m[0][0] = s2;
+ m[0][1] = s1;
+ m[0][2] = s0;
+ m[0][3] = s3;
+ m[1][0] = s3;
+ m[1][1] = s2;
+ m[1][2] = s1;
+ m[1][3] = s4;
+ m[2][0] = s4;
+ m[2][1] = s3;
+ m[2][2] = s2;
+ m[2][3] = s5;
+
+ if (m[0][2] != 0x0) {
+ zero_3x4_col2(m);
+ } else if (m[1][2] != 0x0) {
+ swap_3x4_rows(m, 0, 1, 4);
+ zero_3x4_col2(m);
+ } else if (m[2][2] != 0x0) {
+ swap_3x4_rows(m, 0, 2, 4);
+ zero_3x4_col2(m);
+ } else {
+ printk(KERN_ERR "Error: find_3bit_err_coefs, s0,s1,s2 all zeros!\n");
+ }
+
+ if (m[1][1] != 0x0) {
+ zero_3x4_col1(m);
+ } else if (m[2][1] != 0x0) {
+ swap_3x4_rows(m, 1, 2, 4);
+ zero_3x4_col1(m);
+ } else {
+ printk(KERN_ERR "Error: find_3bit_err_coefs, cannot resolve col 1!\n");
+ }
+
+ /* solve coefs */
+ solve_3x4(m, coefs, row_order);
+}
+
+static void zero_3x4_col2(unsigned short m[3][4])
+{
+ unsigned short minv1, minv2;
+
+ minv1 = gf4096_mul(m[1][2], gf4096_inv(m[0][2]));
+ minv2 = gf4096_mul(m[2][2], gf4096_inv(m[0][2]));
+ m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1);
+ m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1);
+ m[1][3] = m[1][3] ^ gf4096_mul(m[0][3], minv1);
+ m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2);
+ m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2);
+ m[2][3] = m[2][3] ^ gf4096_mul(m[0][3], minv2);
+}
+
+static void zero_3x4_col1(unsigned short m[3][4])
+{
+ unsigned short minv;
+ minv = gf4096_mul(m[2][1], gf4096_inv(m[1][1]));
+ m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv);
+ m[2][3] = m[2][3] ^ gf4096_mul(m[1][3], minv);
+}
+
+static void swap_3x4_rows(unsigned short m[3][4], int i, int j, int col_width)
+{
+ unsigned short tmp0;
+ int cnt;
+ for (cnt = 0; cnt < col_width; cnt++) {
+ tmp0 = m[i][cnt];
+ m[i][cnt] = m[j][cnt];
+ m[j][cnt] = tmp0;
+ }
+}
+
+static void solve_3x4(unsigned short m[3][4], unsigned short *coefs, int *row_order)
+{
+ unsigned short tmp[3];
+ tmp[0] = gf4096_mul(m[2][3], gf4096_inv(m[2][0]));
+ tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ m[1][3]), gf4096_inv(m[1][1]));
+ tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^ gf4096_mul(tmp[1], m[0][1]) ^ m[0][3]), gf4096_inv(m[0][2]));
+ sort_coefs(row_order, tmp, 3);
+ coefs[0] = tmp[0];
+ coefs[1] = tmp[1];
+ coefs[2] = tmp[2];
+}
+
+static void find_3bit_err_pats(unsigned short s0, unsigned short s1,
+ unsigned short s2, unsigned short r0,
+ unsigned short r1, unsigned short r2,
+ unsigned short *pats)
+{
+ find_2x2_soln(r0 ^ r2, r1 ^ r2,
+ gf4096_mul(r0, r0 ^ r2), gf4096_mul(r1, r1 ^ r2),
+ gf4096_mul(s0, r2) ^ s1, gf4096_mul(s1, r2) ^ s2, pats);
+ pats[2] = s0 ^ pats[0] ^ pats[1];
+}
+
+static void find_4bit_err_coefs(unsigned short s0, unsigned short s1,
+ unsigned short s2, unsigned short s3,
+ unsigned short s4, unsigned short s5,
+ unsigned short s6, unsigned short s7,
+ unsigned short *coefs)
+{
+ unsigned short m[4][5];
+ int row_order[4];
+
+ row_order[0] = 0;
+ row_order[1] = 1;
+ row_order[2] = 2;
+ row_order[3] = 3;
+
+ m[0][0] = s3;
+ m[0][1] = s2;
+ m[0][2] = s1;
+ m[0][3] = s0;
+ m[0][4] = s4;
+ m[1][0] = s4;
+ m[1][1] = s3;
+ m[1][2] = s2;
+ m[1][3] = s1;
+ m[1][4] = s5;
+ m[2][0] = s5;
+ m[2][1] = s4;
+ m[2][2] = s3;
+ m[2][3] = s2;
+ m[2][4] = s6;
+ m[3][0] = s6;
+ m[3][1] = s5;
+ m[3][2] = s4;
+ m[3][3] = s3;
+ m[3][4] = s7;
+
+ if (m[0][3] != 0x0) {
+ zero_4x5_col3(m);
+ } else if (m[1][3] != 0x0) {
+ swap_4x5_rows(m, 0, 1, 5);
+ zero_4x5_col3(m);
+ } else if (m[2][3] != 0x0) {
+ swap_4x5_rows(m, 0, 2, 5);
+ zero_4x5_col3(m);
+ } else if (m[3][3] != 0x0) {
+ swap_4x5_rows(m, 0, 3, 5);
+ zero_4x5_col3(m);
+ } else {
+ printk(KERN_ERR "Error: find_4bit_err_coefs, s0,s1,s2,s3 all zeros!\n");
+ }
+
+ if (m[1][2] != 0x0) {
+ zero_4x5_col2(m);
+ } else if (m[2][2] != 0x0) {
+ swap_4x5_rows(m, 1, 2, 5);
+ zero_4x5_col2(m);
+ } else if (m[3][2] != 0x0) {
+ swap_4x5_rows(m, 1, 3, 5);
+ zero_4x5_col2(m);
+ } else {
+ printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 2!\n");
+ }
+
+ if (m[2][1] != 0x0) {
+ zero_4x5_col1(m);
+ } else if (m[3][1] != 0x0) {
+ swap_4x5_rows(m, 2, 3, 5);
+ zero_4x5_col1(m);
+ } else {
+ printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 1!\n");
+ }
+
+ solve_4x5(m, coefs, row_order);
+}
+
+static void zero_4x5_col3(unsigned short m[4][5])
+{
+ unsigned short minv1, minv2, minv3;
+
+ minv1 = gf4096_mul(m[1][3], gf4096_inv(m[0][3]));
+ minv2 = gf4096_mul(m[2][3], gf4096_inv(m[0][3]));
+ minv3 = gf4096_mul(m[3][3], gf4096_inv(m[0][3]));
+
+ m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1);
+ m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1);
+ m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv1);
+ m[1][4] = m[1][4] ^ gf4096_mul(m[0][4], minv1);
+ m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2);
+ m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2);
+ m[2][2] = m[2][2] ^ gf4096_mul(m[0][2], minv2);
+ m[2][4] = m[2][4] ^ gf4096_mul(m[0][4], minv2);
+ m[3][0] = m[3][0] ^ gf4096_mul(m[0][0], minv3);
+ m[3][1] = m[3][1] ^ gf4096_mul(m[0][1], minv3);
+ m[3][2] = m[3][2] ^ gf4096_mul(m[0][2], minv3);
+ m[3][4] = m[3][4] ^ gf4096_mul(m[0][4], minv3);
+}
+
+static void zero_4x5_col2(unsigned short m[4][5])
+{
+ unsigned short minv2, minv3;
+
+ minv2 = gf4096_mul(m[2][2], gf4096_inv(m[1][2]));
+ minv3 = gf4096_mul(m[3][2], gf4096_inv(m[1][2]));
+
+ m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv2);
+ m[2][1] = m[2][1] ^ gf4096_mul(m[1][1], minv2);
+ m[2][4] = m[2][4] ^ gf4096_mul(m[1][4], minv2);
+ m[3][0] = m[3][0] ^ gf4096_mul(m[1][0], minv3);
+ m[3][1] = m[3][1] ^ gf4096_mul(m[1][1], minv3);
+ m[3][4] = m[3][4] ^ gf4096_mul(m[1][4], minv3);
+}
+
+static void zero_4x5_col1(unsigned short m[4][5])
+{
+ unsigned short minv;
+
+ minv = gf4096_mul(m[3][1], gf4096_inv(m[2][1]));
+
+ m[3][0] = m[3][0] ^ gf4096_mul(m[2][0], minv);
+ m[3][4] = m[3][4] ^ gf4096_mul(m[2][4], minv);
+}
+
+static void swap_4x5_rows(unsigned short m[4][5], int i, int j, int col_width)
+{
+ unsigned short tmp0;
+ int cnt;
+
+ for (cnt = 0; cnt < col_width; cnt++) {
+ tmp0 = m[i][cnt];
+ m[i][cnt] = m[j][cnt];
+ m[j][cnt] = tmp0;
+ }
+}
+
+static void solve_4x5(unsigned short m[4][5], unsigned short *coefs, int *row_order)
+{
+ unsigned short tmp[4];
+
+ tmp[0] = gf4096_mul(m[3][4], gf4096_inv(m[3][0]));
+ tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[2][0]) ^ m[2][4]), gf4096_inv(m[2][1]));
+ tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ gf4096_mul(tmp[1], m[1][1]) ^ m[1][4]), gf4096_inv(m[1][2]));
+ tmp[3] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^
+ gf4096_mul(tmp[1], m[0][1]) ^ gf4096_mul(tmp[2], m[0][2]) ^ m[0][4]), gf4096_inv(m[0][3]));
+ sort_coefs(row_order, tmp, 4);
+ coefs[0] = tmp[0];
+ coefs[1] = tmp[1];
+ coefs[2] = tmp[2];
+ coefs[3] = tmp[3];
+}
+
+static void sort_coefs(int *order, unsigned short *soln, int len)
+{
+ int cnt, start_cnt, least_ord, least_cnt;
+ unsigned short tmp0;
+ for (start_cnt = 0; start_cnt < len; start_cnt++) {
+ for (cnt = start_cnt; cnt < len; cnt++) {
+ if (cnt == start_cnt) {
+ least_ord = order[cnt];
+ least_cnt = start_cnt;
+ } else {
+ if (least_ord > order[cnt]) {
+ least_ord = order[cnt];
+ least_cnt = cnt;
+ }
+ }
+ }
+ if (least_cnt != start_cnt) {
+ tmp0 = order[least_cnt];
+ order[least_cnt] = order[start_cnt];
+ order[start_cnt] = tmp0;
+ tmp0 = soln[least_cnt];
+ soln[least_cnt] = soln[start_cnt];
+ soln[start_cnt] = tmp0;
+ }
+ }
+}
+
+static void find_4bit_err_pats(unsigned short s0, unsigned short s1,
+ unsigned short s2, unsigned short s3,
+ unsigned short z1, unsigned short z2,
+ unsigned short z3, unsigned short z4,
+ unsigned short *pats)
+{
+ unsigned short z4_z1, z3z4_z3z3, z4_z2, s0z4_s1, z1z4_z1z1,
+ z4_z3, z2z4_z2z2, s1z4_s2, z3z3z4_z3z3z3, z1z1z4_z1z1z1, z2z2z4_z2z2z2, s2z4_s3;
+ unsigned short tmp0, tmp1, tmp2, tmp3;
+
+ z4_z1 = z4 ^ z1;
+ z3z4_z3z3 = gf4096_mul(z3, z4) ^ gf4096_mul(z3, z3);
+ z4_z2 = z4 ^ z2;
+ s0z4_s1 = gf4096_mul(s0, z4) ^ s1;
+ z1z4_z1z1 = gf4096_mul(z1, z4) ^ gf4096_mul(z1, z1);
+ z4_z3 = z4 ^ z3;
+ z2z4_z2z2 = gf4096_mul(z2, z4) ^ gf4096_mul(z2, z2);
+ s1z4_s2 = gf4096_mul(s1, z4) ^ s2;
+ z3z3z4_z3z3z3 = gf4096_mul(gf4096_mul(z3, z3), z4) ^ gf4096_mul(gf4096_mul(z3, z3), z3);
+ z1z1z4_z1z1z1 = gf4096_mul(gf4096_mul(z1, z1), z4) ^ gf4096_mul(gf4096_mul(z1, z1), z1);
+ z2z2z4_z2z2z2 = gf4096_mul(gf4096_mul(z2, z2), z4) ^ gf4096_mul(gf4096_mul(z2, z2), z2);
+ s2z4_s3 = gf4096_mul(s2, z4) ^ s3;
+
+ //find err pat 0,1
+ find_2x2_soln(gf4096_mul(z4_z1, z3z4_z3z3) ^
+ gf4096_mul(z1z4_z1z1, z4_z3), gf4096_mul(z4_z2,
+ z3z4_z3z3) ^
+ gf4096_mul(z2z4_z2z2, z4_z3), gf4096_mul(z1z4_z1z1,
+ z3z3z4_z3z3z3) ^
+ gf4096_mul(z1z1z4_z1z1z1, z3z4_z3z3),
+ gf4096_mul(z2z4_z2z2,
+ z3z3z4_z3z3z3) ^ gf4096_mul(z2z2z4_z2z2z2,
+ z3z4_z3z3),
+ gf4096_mul(s0z4_s1, z3z4_z3z3) ^ gf4096_mul(s1z4_s2,
+ z4_z3),
+ gf4096_mul(s1z4_s2, z3z3z4_z3z3z3) ^ gf4096_mul(s2z4_s3, z3z4_z3z3), pats);
+ tmp0 = pats[0];
+ tmp1 = pats[1];
+ tmp2 = pats[0] ^ pats[1] ^ s0;
+ tmp3 = gf4096_mul(pats[0], z1) ^ gf4096_mul(pats[1], z2) ^ s1;
+
+ //find err pat 2,3
+ find_2x2_soln(0x1, 0x1, z3, z4, tmp2, tmp3, pats);
+ pats[2] = pats[0];
+ pats[3] = pats[1];
+ pats[0] = tmp0;
+ pats[1] = tmp1;
+}
+
+static void find_2x2_soln(unsigned short c00, unsigned short c01,
+ unsigned short c10, unsigned short c11,
+ unsigned short lval0, unsigned short lval1,
+ unsigned short *soln)
+{
+ unsigned short m[2][3];
+ m[0][0] = c00;
+ m[0][1] = c01;
+ m[0][2] = lval0;
+ m[1][0] = c10;
+ m[1][1] = c11;
+ m[1][2] = lval1;
+
+ if (m[0][1] != 0x0) {
+ /* */
+ } else if (m[1][1] != 0x0) {
+ swap_2x3_rows(m);
+ } else {
+ printk(KERN_ERR "Warning: find_2bit_err_coefs, s0,s1 all zeros!\n");
+ }
+
+ solve_2x3(m, soln);
+}
+
+static void swap_2x3_rows(unsigned short m[2][3])
+{
+ unsigned short tmp0;
+ int cnt;
+
+ for (cnt = 0; cnt < 3; cnt++) {
+ tmp0 = m[0][cnt];
+ m[0][cnt] = m[1][cnt];
+ m[1][cnt] = tmp0;
+ }
+}
+
+static void solve_2x3(unsigned short m[2][3], unsigned short *coefs)
+{
+ unsigned short minv;
+
+ minv = gf4096_mul(m[1][1], gf4096_inv(m[0][1]));
+ m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv);
+ m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv);
+ coefs[0] = gf4096_mul(m[1][2], gf4096_inv(m[1][0]));
+ coefs[1] = gf4096_mul((gf4096_mul(coefs[0], m[0][0]) ^ m[0][2]), gf4096_inv(m[0][1]));
+}
+
+static unsigned char gf64_inv[64] = {
+ 0, 1, 33, 62, 49, 43, 31, 44, 57, 37, 52, 28, 46, 40, 22, 25,
+ 61, 54, 51, 39, 26, 35, 14, 24, 23, 15, 20, 34, 11, 53, 45, 6,
+ 63, 2, 27, 21, 56, 9, 50, 19, 13, 47, 48, 5, 7, 30, 12, 41,
+ 42, 4, 38, 18, 10, 29, 17, 60, 36, 8, 59, 58, 55, 16, 3, 32
+};
+
+static unsigned short gf4096_inv(unsigned short din)
+{
+ unsigned short alahxal, ah2B, deno, inv, bl, bh;
+ unsigned short ah, al, ahxal;
+ unsigned short dout;
+
+ ah = (din >> 6) & 0x3f;
+ al = din & 0x3f;
+ ahxal = ah ^ al;
+ ah2B = (((ah ^ (ah >> 3)) & 0x1) << 5) |
+ ((ah >> 1) & 0x10) |
+ ((((ah >> 5) ^ (ah >> 2)) & 0x1) << 3) |
+ ((ah >> 2) & 0x4) | ((((ah >> 4) ^ (ah >> 1)) & 0x1) << 1) | (ah & 0x1);
+ alahxal = gf64_mul(ahxal, al);
+ deno = alahxal ^ ah2B;
+ inv = gf64_inv[deno];
+ bl = gf64_mul(inv, ahxal);
+ bh = gf64_mul(inv, ah);
+ dout = ((bh & 0x3f) << 6) | (bl & 0x3f);
+ return (((bh & 0x3f) << 6) | (bl & 0x3f));
+}
+
+static unsigned short err_pos_lut[4096] = {
+ 0xfff, 0x000, 0x451, 0xfff, 0xfff, 0x3cf, 0xfff, 0x041,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x28a, 0xfff, 0x492, 0xfff,
+ 0x145, 0xfff, 0xfff, 0x514, 0xfff, 0x082, 0xfff, 0xfff,
+ 0xfff, 0x249, 0x38e, 0x410, 0xfff, 0x104, 0x208, 0x1c7,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x2cb, 0xfff, 0xfff, 0xfff,
+ 0x0c3, 0x34d, 0x4d3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x186, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x30c, 0x555, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x166, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x385, 0x14e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e1,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x538, 0xfff, 0x16d, 0xfff,
+ 0xfff, 0xfff, 0x45b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x29c, 0x2cc, 0x30b, 0x2b3, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0b3, 0xfff, 0x2f7,
+ 0xfff, 0x32b, 0xfff, 0xfff, 0xfff, 0xfff, 0x0a7, 0xfff,
+ 0xfff, 0x2da, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x07e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x11c, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x22f, 0xfff, 0x1f4, 0xfff, 0xfff,
+ 0x2b0, 0x504, 0xfff, 0x114, 0xfff, 0xfff, 0xfff, 0x21d,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x00d, 0x3c4, 0x340, 0x10f,
+ 0xfff, 0xfff, 0x266, 0x02e, 0xfff, 0xfff, 0xfff, 0x4f8,
+ 0x337, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x07b, 0x168, 0xfff, 0xfff, 0x0fe,
+ 0xfff, 0xfff, 0x51a, 0xfff, 0x458, 0xfff, 0x36d, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x073, 0x37d, 0x415, 0x550, 0xfff,
+ 0xfff, 0xfff, 0x23b, 0x4b4, 0xfff, 0xfff, 0xfff, 0x1a1,
+ 0xfff, 0xfff, 0x3aa, 0xfff, 0x117, 0x04d, 0x341, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x518, 0x03e, 0x0f2, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x363, 0xfff, 0x0b9, 0xfff, 0xfff,
+ 0x241, 0xfff, 0xfff, 0x049, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x15f, 0x52d, 0xfff, 0xfff, 0xfff, 0x29e, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x4cf, 0x0fc, 0xfff, 0x36f, 0x3d3, 0xfff,
+ 0x228, 0xfff, 0xfff, 0x45e, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x238, 0xfff, 0xfff, 0xfff, 0xfff, 0x47f, 0xfff, 0xfff,
+ 0x43a, 0x265, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e8,
+ 0xfff, 0xfff, 0x01a, 0xfff, 0xfff, 0xfff, 0xfff, 0x21e,
+ 0x1fc, 0x40b, 0xfff, 0xfff, 0xfff, 0x2d0, 0x159, 0xfff,
+ 0xfff, 0x313, 0xfff, 0xfff, 0x05c, 0x4cc, 0xfff, 0xfff,
+ 0x0f6, 0x3d5, 0xfff, 0xfff, 0xfff, 0x54f, 0xfff, 0xfff,
+ 0xfff, 0x172, 0x1e4, 0x07c, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x53c, 0x1ad, 0x535,
+ 0x19b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x092, 0xfff, 0x2be, 0xfff, 0xfff, 0x482,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0e6, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x476, 0xfff, 0x51d, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x342, 0x2b5, 0x22e, 0x09a, 0xfff, 0x08d,
+ 0x44f, 0x3ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d1, 0xfff,
+ 0xfff, 0x543, 0xfff, 0x48f, 0xfff, 0x3d2, 0xfff, 0x0d5,
+ 0x113, 0x0ec, 0x427, 0xfff, 0xfff, 0xfff, 0x4c4, 0xfff,
+ 0xfff, 0x50a, 0xfff, 0x144, 0xfff, 0x105, 0x39f, 0x294,
+ 0x164, 0xfff, 0x31a, 0xfff, 0xfff, 0x49a, 0xfff, 0x130,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x1be, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x49e, 0x371, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x0e8, 0x49c, 0x0f4, 0xfff,
+ 0x338, 0x1a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x36c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x1ae, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x31b, 0xfff, 0xfff, 0x2dd, 0x522, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f4,
+ 0x3c6, 0x30d, 0xfff, 0xfff, 0xfff, 0xfff, 0x34c, 0x18f,
+ 0x30a, 0xfff, 0x01f, 0x079, 0xfff, 0xfff, 0x54d, 0x46b,
+ 0x28c, 0x37f, 0xfff, 0xfff, 0xfff, 0xfff, 0x355, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x14f, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x359, 0x3fe, 0x3c5, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x423, 0xfff, 0xfff, 0x34a, 0x22c, 0xfff,
+ 0x25a, 0xfff, 0xfff, 0x4ad, 0xfff, 0x28d, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x547, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x2e2, 0xfff, 0xfff, 0x1d5, 0xfff, 0x2a8, 0xfff, 0xfff,
+ 0x03f, 0xfff, 0xfff, 0xfff, 0xfff, 0x3eb, 0x0fa, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x55b, 0xfff,
+ 0x08e, 0xfff, 0x3ae, 0xfff, 0x3a4, 0xfff, 0x282, 0x158,
+ 0xfff, 0x382, 0xfff, 0xfff, 0x499, 0xfff, 0xfff, 0x08a,
+ 0xfff, 0xfff, 0xfff, 0x456, 0x3be, 0xfff, 0x1e2, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x559, 0xfff, 0x1a0, 0xfff,
+ 0xfff, 0x0b4, 0xfff, 0xfff, 0xfff, 0x2df, 0xfff, 0xfff,
+ 0xfff, 0x07f, 0x4f5, 0xfff, 0xfff, 0x27c, 0x133, 0x017,
+ 0xfff, 0x3fd, 0xfff, 0xfff, 0xfff, 0x44d, 0x4cd, 0x17a,
+ 0x0d7, 0x537, 0xfff, 0xfff, 0x353, 0xfff, 0xfff, 0x351,
+ 0x366, 0xfff, 0x44a, 0xfff, 0x1a6, 0xfff, 0xfff, 0xfff,
+ 0x291, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1e3,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x389, 0xfff, 0x07a, 0xfff,
+ 0x1b6, 0x2ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x24e, 0x074,
+ 0xfff, 0xfff, 0x3dc, 0xfff, 0x4e3, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x4eb, 0xfff, 0xfff, 0x3b8, 0x4de, 0xfff, 0x19c,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x262,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x076, 0x4e8, 0x3da,
+ 0xfff, 0x531, 0xfff, 0xfff, 0x14a, 0xfff, 0x0a2, 0x433,
+ 0x3df, 0x1e9, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e7, 0x285,
+ 0x2d8, 0xfff, 0xfff, 0xfff, 0x349, 0x18d, 0x098, 0xfff,
+ 0x0df, 0x4bf, 0xfff, 0xfff, 0x0b2, 0xfff, 0x346, 0x24d,
+ 0xfff, 0xfff, 0xfff, 0x24f, 0x4fa, 0x2f9, 0xfff, 0xfff,
+ 0x3c9, 0xfff, 0x2b4, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x056, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x179, 0xfff, 0x0e9, 0x3f0, 0x33d, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x1fd, 0xfff, 0xfff, 0x526, 0xfff,
+ 0xfff, 0xfff, 0x53d, 0xfff, 0xfff, 0xfff, 0x170, 0x331,
+ 0xfff, 0x068, 0xfff, 0xfff, 0xfff, 0x3f7, 0xfff, 0x3d8,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x09f, 0x556, 0xfff, 0xfff, 0x02d, 0xfff, 0xfff,
+ 0x553, 0xfff, 0xfff, 0xfff, 0x1f0, 0xfff, 0xfff, 0x4d6,
+ 0x41e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d5, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x248, 0xfff, 0xfff, 0xfff, 0x0a3,
+ 0xfff, 0x217, 0xfff, 0xfff, 0xfff, 0x4f1, 0x209, 0xfff,
+ 0xfff, 0x475, 0x234, 0x52b, 0x398, 0xfff, 0x08b, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x2c2, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x268, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x4a3, 0xfff, 0x0aa, 0xfff, 0x1d9, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x155, 0xfff, 0xfff, 0xfff, 0xfff, 0x0bf,
+ 0x539, 0xfff, 0xfff, 0x2f1, 0x545, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x2a7, 0x06f, 0xfff, 0x378, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x25e, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x15d, 0x02a, 0xfff, 0xfff, 0x0bc,
+ 0x235, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x150, 0xfff, 0x1a9, 0xfff, 0xfff, 0xfff, 0xfff, 0x381,
+ 0xfff, 0x04e, 0x270, 0x13f, 0xfff, 0xfff, 0x405, 0xfff,
+ 0x3cd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x2ef, 0xfff, 0x06a, 0xfff, 0xfff, 0xfff, 0x34f,
+ 0x212, 0xfff, 0xfff, 0x0e2, 0xfff, 0x083, 0x298, 0xfff,
+ 0xfff, 0xfff, 0x0c2, 0xfff, 0xfff, 0x52e, 0xfff, 0x488,
+ 0xfff, 0xfff, 0xfff, 0x36b, 0xfff, 0xfff, 0xfff, 0x442,
+ 0x091, 0xfff, 0x41c, 0xfff, 0xfff, 0x3a5, 0xfff, 0x4e6,
+ 0xfff, 0xfff, 0x40d, 0x31d, 0xfff, 0xfff, 0xfff, 0x4c1,
+ 0x053, 0xfff, 0x418, 0x13c, 0xfff, 0x350, 0xfff, 0x0ae,
+ 0xfff, 0xfff, 0x41f, 0xfff, 0x470, 0xfff, 0x4ca, 0xfff,
+ 0xfff, 0xfff, 0x02b, 0x450, 0xfff, 0x1f8, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x293, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x411, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x0b8, 0xfff, 0xfff, 0xfff,
+ 0x3e1, 0xfff, 0xfff, 0xfff, 0xfff, 0x43c, 0xfff, 0x2b2,
+ 0x2ab, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ec,
+ 0xfff, 0xfff, 0xfff, 0x3f8, 0x034, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x11a, 0xfff, 0x541, 0x45c, 0x134,
+ 0x1cc, 0xfff, 0xfff, 0xfff, 0x469, 0xfff, 0xfff, 0x44b,
+ 0x161, 0xfff, 0xfff, 0xfff, 0x055, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x307, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d1, 0xfff,
+ 0xfff, 0xfff, 0x124, 0x37b, 0x26b, 0x336, 0xfff, 0xfff,
+ 0x2e4, 0x3cb, 0xfff, 0xfff, 0x0f8, 0x3c8, 0xfff, 0xfff,
+ 0xfff, 0x461, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4b5,
+ 0x2cf, 0xfff, 0xfff, 0xfff, 0x20f, 0xfff, 0x35a, 0xfff,
+ 0x490, 0xfff, 0x185, 0xfff, 0xfff, 0xfff, 0xfff, 0x42e,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x54b, 0xfff, 0xfff, 0xfff,
+ 0x146, 0xfff, 0x412, 0xfff, 0xfff, 0xfff, 0x1ff, 0xfff,
+ 0xfff, 0x3e0, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d5, 0xfff,
+ 0x4df, 0x505, 0xfff, 0x413, 0xfff, 0x1a5, 0xfff, 0x3b2,
+ 0xfff, 0xfff, 0xfff, 0x35b, 0xfff, 0x116, 0xfff, 0xfff,
+ 0x171, 0x4d0, 0xfff, 0x154, 0x12d, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x468, 0x4db, 0xfff,
+ 0xfff, 0x1df, 0xfff, 0xfff, 0xfff, 0xfff, 0x05a, 0xfff,
+ 0x0f1, 0x403, 0xfff, 0x22b, 0x2e0, 0xfff, 0xfff, 0xfff,
+ 0x2b7, 0x373, 0xfff, 0xfff, 0xfff, 0xfff, 0x13e, 0xfff,
+ 0xfff, 0xfff, 0x0d0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x329, 0x1d2, 0x3fa, 0x047, 0xfff, 0x2f2, 0xfff, 0xfff,
+ 0x141, 0x0ac, 0x1d7, 0xfff, 0x07d, 0xfff, 0xfff, 0xfff,
+ 0x1c1, 0xfff, 0x487, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x045, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x288, 0x0cd, 0xfff, 0xfff, 0xfff, 0xfff, 0x226, 0x1d8,
+ 0xfff, 0x153, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4cb,
+ 0x528, 0xfff, 0xfff, 0xfff, 0x20a, 0x343, 0x3a1, 0xfff,
+ 0xfff, 0xfff, 0x2d7, 0x2d3, 0x1aa, 0x4c5, 0xfff, 0xfff,
+ 0xfff, 0x42b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x3e9, 0xfff, 0x20b, 0x260,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x37c, 0x2fd,
+ 0xfff, 0xfff, 0x2c8, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x31e, 0xfff, 0x335, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x135, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x35c, 0x4dd, 0x129, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x1ef, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x34e, 0xfff, 0xfff, 0xfff, 0xfff, 0x407, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x3ad, 0xfff, 0xfff, 0xfff,
+ 0x379, 0xfff, 0xfff, 0x1d0, 0x38d, 0xfff, 0xfff, 0x1e8,
+ 0x184, 0x3c1, 0x1c4, 0xfff, 0x1f9, 0xfff, 0xfff, 0x424,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x1d3, 0x0d4, 0xfff, 0x4e9,
+ 0xfff, 0xfff, 0xfff, 0x530, 0x107, 0xfff, 0x106, 0x04f,
+ 0xfff, 0xfff, 0x4c7, 0x503, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x15c, 0xfff, 0x23f, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x4f3, 0xfff, 0xfff, 0x3c7,
+ 0xfff, 0x278, 0xfff, 0xfff, 0x0a6, 0xfff, 0xfff, 0xfff,
+ 0x122, 0x1cf, 0xfff, 0x327, 0xfff, 0x2e5, 0xfff, 0x29d,
+ 0xfff, 0xfff, 0x3f1, 0xfff, 0xfff, 0x48d, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x054, 0xfff, 0xfff, 0xfff, 0xfff, 0x178,
+ 0x27e, 0x4e0, 0x352, 0x02f, 0x09c, 0xfff, 0x2a0, 0xfff,
+ 0xfff, 0x46a, 0x457, 0xfff, 0xfff, 0x501, 0xfff, 0x2ba,
+ 0xfff, 0xfff, 0xfff, 0x54e, 0x2e7, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x551, 0xfff, 0xfff, 0x1db, 0x2aa, 0xfff,
+ 0xfff, 0x4bc, 0xfff, 0xfff, 0x395, 0xfff, 0x0de, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x455, 0xfff, 0x17e,
+ 0xfff, 0x221, 0x4a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x388, 0xfff, 0xfff, 0xfff, 0x308, 0xfff, 0xfff, 0xfff,
+ 0x20e, 0x4b9, 0xfff, 0x273, 0x20c, 0x09e, 0xfff, 0x057,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x3f2, 0xfff, 0x1a8, 0x3a6,
+ 0x14c, 0xfff, 0xfff, 0x071, 0xfff, 0xfff, 0x53a, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x109, 0xfff, 0xfff, 0x399, 0xfff,
+ 0x061, 0x4f0, 0x39e, 0x244, 0xfff, 0x035, 0xfff, 0xfff,
+ 0x305, 0x47e, 0x297, 0xfff, 0xfff, 0x2b8, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1bc, 0xfff, 0x2fc,
+ 0xfff, 0xfff, 0x554, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b6,
+ 0xfff, 0xfff, 0xfff, 0x515, 0x397, 0xfff, 0xfff, 0x12f,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e5,
+ 0xfff, 0x4fc, 0xfff, 0xfff, 0x05e, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x0a8, 0x3af, 0x015, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x138, 0xfff, 0xfff, 0xfff, 0x540, 0xfff, 0xfff,
+ 0xfff, 0x027, 0x523, 0x2f0, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x16c, 0xfff, 0x27d, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x04c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4dc,
+ 0xfff, 0xfff, 0x059, 0x301, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x1a3, 0xfff, 0x15a, 0xfff, 0xfff,
+ 0x0a5, 0xfff, 0x435, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x051, 0xfff, 0xfff, 0x131, 0xfff, 0x4f4, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x441, 0xfff, 0x4fb, 0xfff, 0x03b,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ed, 0x274,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d3, 0x55e, 0x1b3,
+ 0xfff, 0x0bd, 0xfff, 0xfff, 0xfff, 0xfff, 0x225, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x4b7, 0xfff, 0xfff, 0x2ff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c3, 0xfff,
+ 0x383, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f6,
+ 0xfff, 0xfff, 0x1ee, 0xfff, 0x03d, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x26f, 0x1dc, 0xfff, 0x0db, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x0ce, 0xfff, 0xfff, 0x127, 0x03a,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x311, 0xfff,
+ 0xfff, 0x13d, 0x09d, 0x47b, 0x2a6, 0x50d, 0x510, 0x19a,
+ 0xfff, 0x354, 0x414, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x44c, 0x3b0, 0xfff, 0x23d, 0x429, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x4c0, 0x416, 0xfff, 0x05b, 0xfff, 0xfff, 0x137, 0xfff,
+ 0x25f, 0x49f, 0xfff, 0x279, 0x013, 0xfff, 0xfff, 0xfff,
+ 0x269, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d0, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x077, 0xfff, 0xfff, 0x3fb,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x271, 0x3a0, 0xfff, 0xfff,
+ 0x40f, 0xfff, 0xfff, 0x3de, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ab, 0x26a,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x489, 0xfff, 0xfff,
+ 0x252, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b7, 0x42f, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b7,
+ 0xfff, 0x2bb, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x0f7, 0x01d, 0xfff, 0x067, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x4e2, 0xfff, 0xfff, 0x4bb, 0xfff,
+ 0xfff, 0xfff, 0x17b, 0xfff, 0x0ee, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x36e, 0xfff, 0xfff, 0xfff, 0x533, 0xfff,
+ 0xfff, 0xfff, 0x4d4, 0x356, 0xfff, 0xfff, 0x375, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x4a4, 0x513, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4ff, 0xfff, 0x2af,
+ 0xfff, 0xfff, 0x026, 0xfff, 0x0ad, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x26e, 0xfff, 0xfff, 0xfff, 0xfff, 0x493, 0xfff,
+ 0x463, 0x4d2, 0x4be, 0xfff, 0xfff, 0xfff, 0xfff, 0x4f2,
+ 0x0b6, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x32d, 0x315, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x13a, 0x4a1, 0xfff, 0x27a, 0xfff, 0xfff, 0xfff,
+ 0x47a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x334, 0xfff, 0xfff, 0xfff, 0xfff, 0x54c, 0xfff, 0xfff,
+ 0xfff, 0x0c9, 0x007, 0xfff, 0xfff, 0x12e, 0xfff, 0x0ff,
+ 0xfff, 0xfff, 0x3f5, 0x509, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x1c3, 0x2ad, 0xfff, 0xfff, 0x47c, 0x261, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x152, 0xfff, 0xfff, 0xfff, 0x339,
+ 0xfff, 0x243, 0x1c0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x063, 0xfff, 0xfff, 0x254, 0xfff, 0xfff, 0x173, 0xfff,
+ 0x0c7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x362, 0x259, 0x485, 0x374, 0x0dc, 0x3ab, 0xfff,
+ 0x1c5, 0x534, 0x544, 0xfff, 0xfff, 0x508, 0xfff, 0x402,
+ 0x408, 0xfff, 0x0e7, 0xfff, 0xfff, 0x00a, 0x205, 0xfff,
+ 0xfff, 0x2b9, 0xfff, 0xfff, 0xfff, 0x465, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x23a, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x147, 0x19d, 0x115, 0x214, 0xfff, 0x090, 0x368,
+ 0xfff, 0x210, 0xfff, 0xfff, 0x280, 0x52a, 0x163, 0x148,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x326, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x2de, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x206, 0x2c1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x189, 0xfff, 0xfff, 0xfff, 0xfff, 0x367, 0xfff, 0x1a4,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x443, 0xfff, 0x27b,
+ 0xfff, 0xfff, 0x251, 0x549, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x188, 0x04b, 0xfff, 0xfff, 0xfff, 0x31f,
+ 0x4a6, 0xfff, 0x246, 0x1de, 0x156, 0xfff, 0xfff, 0xfff,
+ 0x3a9, 0xfff, 0xfff, 0xfff, 0x2fa, 0xfff, 0x128, 0x0d1,
+ 0x449, 0x255, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x258, 0xfff, 0xfff, 0xfff,
+ 0x532, 0xfff, 0xfff, 0xfff, 0x303, 0x517, 0xfff, 0xfff,
+ 0x2a9, 0x24a, 0xfff, 0xfff, 0x231, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x4b6, 0x516, 0xfff, 0xfff, 0x0e4, 0x0eb,
+ 0xfff, 0x4e4, 0xfff, 0x275, 0xfff, 0xfff, 0x031, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x025, 0x21a, 0xfff, 0x0cc,
+ 0x45f, 0x3d9, 0x289, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x23e, 0xfff, 0xfff, 0xfff, 0x438, 0x097,
+ 0x419, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x0a9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x37e, 0x0e0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x431,
+ 0x372, 0xfff, 0xfff, 0xfff, 0x1ba, 0x06e, 0xfff, 0x1b1,
+ 0xfff, 0xfff, 0x12a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x193, 0xfff, 0xfff, 0xfff, 0xfff, 0x10a,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x048, 0x1b4,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x295, 0x140, 0x108, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x16f, 0xfff, 0x0a4, 0x37a, 0xfff,
+ 0x29a, 0xfff, 0x284, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c6,
+ 0x2a2, 0x3a3, 0xfff, 0x201, 0xfff, 0xfff, 0xfff, 0x4bd,
+ 0x005, 0x54a, 0x3b5, 0x204, 0x2ee, 0x11d, 0x436, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x3ec, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x11f, 0x498, 0x21c, 0xfff,
+ 0xfff, 0xfff, 0x3d6, 0xfff, 0x4ab, 0xfff, 0x432, 0x2eb,
+ 0x542, 0x4fd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x4ce, 0xfff, 0xfff, 0x2fb, 0xfff,
+ 0xfff, 0x2e1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b9, 0x037, 0x0dd,
+ 0xfff, 0xfff, 0xfff, 0x2bf, 0x521, 0x496, 0x095, 0xfff,
+ 0xfff, 0x328, 0x070, 0x1bf, 0xfff, 0x393, 0xfff, 0xfff,
+ 0x102, 0xfff, 0xfff, 0x21b, 0xfff, 0x142, 0x263, 0x519,
+ 0xfff, 0x2a5, 0x177, 0xfff, 0x14d, 0x471, 0x4ae, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x1f6, 0xfff, 0x481, 0xfff, 0xfff, 0xfff, 0x151, 0xfff,
+ 0xfff, 0xfff, 0x085, 0x33f, 0xfff, 0xfff, 0xfff, 0x084,
+ 0xfff, 0xfff, 0xfff, 0x345, 0x3a2, 0xfff, 0xfff, 0x0a0,
+ 0x0da, 0x024, 0xfff, 0xfff, 0xfff, 0x1bd, 0xfff, 0x55c,
+ 0x467, 0x445, 0xfff, 0xfff, 0xfff, 0x052, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x51e, 0xfff, 0xfff, 0x39d, 0xfff, 0x35f,
+ 0xfff, 0x376, 0x3ee, 0xfff, 0xfff, 0xfff, 0xfff, 0x448,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x16a,
+ 0xfff, 0x036, 0x38f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x211,
+ 0xfff, 0xfff, 0xfff, 0x230, 0xfff, 0xfff, 0x3ba, 0xfff,
+ 0xfff, 0xfff, 0x3ce, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x229, 0xfff, 0x176, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x00b, 0xfff, 0x162, 0x018, 0xfff,
+ 0xfff, 0x233, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x400, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x12b, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x3f4, 0xfff, 0x0f0, 0xfff, 0x1ac, 0xfff, 0xfff,
+ 0x119, 0xfff, 0x2c0, 0xfff, 0xfff, 0xfff, 0x49b, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x23c, 0xfff,
+ 0x4b3, 0x010, 0x064, 0xfff, 0xfff, 0x4ba, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x3c2, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x006, 0x196, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x100, 0x191, 0xfff,
+ 0x1ea, 0x29f, 0xfff, 0xfff, 0xfff, 0x276, 0xfff, 0xfff,
+ 0x2b1, 0x3b9, 0xfff, 0x03c, 0xfff, 0xfff, 0xfff, 0x180,
+ 0xfff, 0x08f, 0xfff, 0xfff, 0x19e, 0x019, 0xfff, 0x0b0,
+ 0x0fd, 0x332, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x06b, 0x2e8, 0xfff, 0x446, 0xfff, 0xfff, 0x004,
+ 0x247, 0x197, 0xfff, 0x112, 0x169, 0x292, 0xfff, 0x302,
+ 0xfff, 0xfff, 0x33b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x287, 0x21f, 0xfff, 0x3ea, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e7, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x3a8, 0xfff, 0xfff, 0x2bc, 0xfff,
+ 0x484, 0x296, 0xfff, 0x1c9, 0x08c, 0x1e5, 0x48a, 0xfff,
+ 0x360, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x1ca, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x10d, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x066, 0x2ea, 0x28b, 0x25b, 0xfff, 0x072,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x2b6, 0xfff, 0xfff, 0x272,
+ 0xfff, 0xfff, 0x525, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x2ca, 0xfff, 0xfff, 0xfff, 0x299, 0xfff, 0xfff, 0xfff,
+ 0x558, 0x41a, 0xfff, 0x4f7, 0x557, 0xfff, 0x4a0, 0x344,
+ 0x12c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x125,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x40e, 0xfff, 0xfff, 0x502, 0xfff, 0x103, 0x3e6, 0xfff,
+ 0x527, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x45d, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x44e, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d2, 0x4c9, 0x35e,
+ 0x459, 0x2d9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x17d,
+ 0x0c4, 0xfff, 0xfff, 0xfff, 0x3ac, 0x390, 0x094, 0xfff,
+ 0x483, 0x0ab, 0xfff, 0x253, 0xfff, 0x391, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x123, 0x0ef, 0xfff, 0xfff, 0xfff, 0x330,
+ 0x38c, 0xfff, 0xfff, 0x2ae, 0xfff, 0xfff, 0xfff, 0x042,
+ 0x012, 0x06d, 0xfff, 0xfff, 0xfff, 0x32a, 0x3db, 0x364,
+ 0x2dc, 0xfff, 0x30f, 0x3d7, 0x4a5, 0x050, 0xfff, 0xfff,
+ 0x029, 0xfff, 0xfff, 0xfff, 0xfff, 0x1d1, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x480, 0xfff,
+ 0x4ed, 0x081, 0x0a1, 0xfff, 0xfff, 0xfff, 0x30e, 0x52f,
+ 0x257, 0xfff, 0xfff, 0x447, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x401, 0x3cc, 0xfff, 0xfff, 0x0fb,
+ 0x2c9, 0x42a, 0x314, 0x33e, 0x3bd, 0x318, 0xfff, 0x10e,
+ 0x2a1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x24c,
+ 0x506, 0xfff, 0x267, 0xfff, 0xfff, 0x219, 0xfff, 0x1eb,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x309, 0x3e2, 0x46c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x384, 0xfff, 0xfff, 0xfff, 0xfff, 0x50c, 0xfff, 0x24b,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x038,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x194,
+ 0x143, 0x3e3, 0xfff, 0xfff, 0xfff, 0x4c2, 0xfff, 0xfff,
+ 0x0e1, 0x25c, 0xfff, 0x237, 0xfff, 0x1fe, 0xfff, 0xfff,
+ 0xfff, 0x065, 0x2a4, 0xfff, 0x386, 0x55a, 0x11b, 0xfff,
+ 0xfff, 0x192, 0xfff, 0x183, 0x00e, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x4b2, 0x18e, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x486, 0x4ef, 0x0c6, 0x380, 0xfff, 0x4a8, 0xfff,
+ 0x0c5, 0xfff, 0xfff, 0xfff, 0xfff, 0x093, 0x1b8, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e6,
+ 0xfff, 0x0f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x28e, 0xfff, 0x53b, 0x420, 0x22a, 0x33a, 0xfff, 0x387,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2a3, 0xfff, 0xfff,
+ 0xfff, 0x428, 0x500, 0xfff, 0xfff, 0x120, 0x2c6, 0x290,
+ 0x2f5, 0x0e3, 0xfff, 0x0b7, 0xfff, 0x319, 0x474, 0xfff,
+ 0xfff, 0xfff, 0x529, 0x014, 0xfff, 0x41b, 0x40a, 0x18b,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d9,
+ 0xfff, 0x38a, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ce, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x3b1, 0xfff, 0xfff, 0x05d,
+ 0x2c4, 0xfff, 0xfff, 0x4af, 0xfff, 0x030, 0xfff, 0xfff,
+ 0x203, 0xfff, 0x277, 0x256, 0xfff, 0xfff, 0xfff, 0x4f9,
+ 0xfff, 0x2c7, 0xfff, 0x466, 0x016, 0x1cd, 0xfff, 0x167,
+ 0xfff, 0xfff, 0x0c8, 0xfff, 0x43d, 0xfff, 0xfff, 0x020,
+ 0xfff, 0xfff, 0x232, 0x1cb, 0x1e0, 0xfff, 0xfff, 0x347,
+ 0xfff, 0x478, 0xfff, 0x365, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x358, 0xfff, 0x10b, 0xfff, 0x35d, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x452, 0x22d, 0xfff, 0xfff, 0x47d, 0xfff,
+ 0x2f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x460, 0xfff,
+ 0xfff, 0xfff, 0x50b, 0xfff, 0xfff, 0xfff, 0x2ec, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x4b1, 0x422, 0xfff, 0xfff,
+ 0xfff, 0x2d4, 0xfff, 0x239, 0xfff, 0xfff, 0xfff, 0x439,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x491, 0x075, 0xfff, 0xfff, 0xfff, 0x06c, 0xfff,
+ 0xfff, 0x0f9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x139, 0xfff, 0x4f6, 0xfff, 0xfff, 0x409, 0xfff,
+ 0xfff, 0x15b, 0xfff, 0xfff, 0x348, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x4a2, 0x49d, 0xfff, 0x033, 0x175, 0xfff, 0x039,
+ 0xfff, 0x312, 0x40c, 0xfff, 0xfff, 0x325, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x4aa, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0x165, 0x3bc, 0x48c, 0x310, 0x096,
+ 0xfff, 0xfff, 0x250, 0x1a2, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x20d, 0x2ac, 0xfff, 0xfff, 0x39b, 0xfff, 0x377, 0xfff,
+ 0x512, 0x495, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x357, 0x4ea, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x198, 0xfff, 0xfff, 0xfff, 0x434, 0x04a,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x062, 0xfff, 0x1d6, 0x1c8,
+ 0xfff, 0x1f3, 0x281, 0xfff, 0x462, 0xfff, 0xfff, 0xfff,
+ 0x4b0, 0xfff, 0x207, 0xfff, 0xfff, 0xfff, 0xfff, 0x3dd,
+ 0xfff, 0xfff, 0x55d, 0xfff, 0x552, 0x494, 0x1af, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x227, 0xfff, 0xfff, 0x069,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x43e,
+ 0x0b5, 0xfff, 0x524, 0x2d2, 0xfff, 0xfff, 0xfff, 0x28f,
+ 0xfff, 0x01b, 0x50e, 0xfff, 0xfff, 0x1bb, 0xfff, 0xfff,
+ 0x41d, 0xfff, 0x32e, 0x48e, 0xfff, 0x1f7, 0x224, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x394, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x52c, 0xfff, 0xfff, 0xfff, 0x392, 0xfff, 0x1e7,
+ 0xfff, 0xfff, 0x3f9, 0x3a7, 0xfff, 0x51f, 0xfff, 0x0bb,
+ 0x118, 0x3ca, 0xfff, 0x1dd, 0xfff, 0x48b, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x50f, 0xfff, 0x0d6, 0xfff, 0x1fa, 0xfff,
+ 0x11e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d7, 0xfff, 0x078,
+ 0x008, 0xfff, 0x25d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x032, 0x33c, 0xfff, 0x4d9, 0x160, 0xfff, 0xfff, 0x300,
+ 0x0b1, 0xfff, 0x322, 0xfff, 0x4ec, 0xfff, 0xfff, 0x200,
+ 0x00c, 0x369, 0x473, 0xfff, 0xfff, 0x32c, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x53e, 0x3d4, 0x417, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x34b, 0x001, 0x39a, 0x02c, 0xfff, 0xfff, 0x2ce, 0x00f,
+ 0xfff, 0x0ba, 0xfff, 0xfff, 0xfff, 0xfff, 0x060, 0xfff,
+ 0x406, 0xfff, 0xfff, 0xfff, 0x4ee, 0x4ac, 0xfff, 0x43f,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x29b, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x216,
+ 0x190, 0xfff, 0x396, 0x464, 0xfff, 0xfff, 0x323, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e9, 0xfff, 0x26d,
+ 0x2cd, 0x040, 0xfff, 0xfff, 0xfff, 0xfff, 0x38b, 0x3c0,
+ 0xfff, 0xfff, 0xfff, 0x1f2, 0xfff, 0x0ea, 0xfff, 0xfff,
+ 0x472, 0xfff, 0x1fb, 0xfff, 0xfff, 0x0af, 0x27f, 0xfff,
+ 0xfff, 0xfff, 0x479, 0x023, 0xfff, 0x0d8, 0x3b3, 0xfff,
+ 0xfff, 0xfff, 0x121, 0xfff, 0xfff, 0x3bf, 0xfff, 0xfff,
+ 0x16b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x45a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x0be, 0xfff, 0xfff, 0xfff, 0x111, 0xfff, 0x220,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x09b, 0x218, 0xfff, 0x022, 0x202, 0xfff,
+ 0x4c8, 0xfff, 0x0ed, 0xfff, 0xfff, 0x182, 0xfff, 0xfff,
+ 0xfff, 0x17f, 0x213, 0xfff, 0x321, 0x36a, 0xfff, 0x086,
+ 0xfff, 0xfff, 0xfff, 0x43b, 0x088, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x26c, 0xfff, 0x2f8, 0x3b4, 0xfff, 0xfff, 0xfff,
+ 0x132, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x333, 0x444,
+ 0x0c1, 0x4d8, 0x46d, 0x264, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x426, 0xfff, 0xfff, 0xfff, 0xfff, 0x2fe, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x011, 0xfff, 0x05f, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0x10c, 0x101, 0xfff, 0xfff, 0xfff, 0xfff, 0x110,
+ 0xfff, 0x044, 0x304, 0x361, 0x404, 0xfff, 0x51b, 0x099,
+ 0xfff, 0x440, 0xfff, 0xfff, 0xfff, 0x222, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0x1b5, 0xfff, 0x136, 0x430, 0xfff, 0x1da,
+ 0xfff, 0xfff, 0xfff, 0x043, 0xfff, 0x17c, 0xfff, 0xfff,
+ 0xfff, 0x01c, 0xfff, 0xfff, 0xfff, 0x425, 0x236, 0xfff,
+ 0x317, 0xfff, 0xfff, 0x437, 0x3fc, 0xfff, 0x1f1, 0xfff,
+ 0x324, 0xfff, 0xfff, 0x0ca, 0x306, 0xfff, 0x548, 0xfff,
+ 0x46e, 0xfff, 0xfff, 0xfff, 0x4b8, 0x1c2, 0x286, 0xfff,
+ 0xfff, 0x087, 0x18a, 0x19f, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x18c, 0xfff, 0x215, 0xfff, 0xfff, 0xfff, 0xfff, 0x283,
+ 0xfff, 0xfff, 0xfff, 0x126, 0xfff, 0xfff, 0x370, 0xfff,
+ 0x53f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x31c, 0xfff,
+ 0x4d1, 0xfff, 0xfff, 0xfff, 0x021, 0xfff, 0x157, 0xfff,
+ 0xfff, 0x028, 0x16e, 0xfff, 0x421, 0xfff, 0x1c6, 0xfff,
+ 0xfff, 0x511, 0xfff, 0xfff, 0x39c, 0x46f, 0x1b2, 0xfff,
+ 0xfff, 0x316, 0xfff, 0xfff, 0x009, 0xfff, 0xfff, 0x195,
+ 0xfff, 0x240, 0x546, 0xfff, 0xfff, 0x520, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x454, 0xfff, 0xfff, 0xfff,
+ 0x3f3, 0xfff, 0xfff, 0x187, 0xfff, 0x4a9, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x51c, 0x453, 0x1e6, 0xfff,
+ 0xfff, 0xfff, 0x1b0, 0xfff, 0x477, 0xfff, 0xfff, 0xfff,
+ 0x4fe, 0xfff, 0x32f, 0xfff, 0xfff, 0x15e, 0x1d4, 0xfff,
+ 0x0e5, 0xfff, 0xfff, 0xfff, 0x242, 0x14b, 0x046, 0xfff,
+ 0x3f6, 0x3bb, 0x3e4, 0xfff, 0xfff, 0x2e3, 0xfff, 0x245,
+ 0xfff, 0x149, 0xfff, 0xfff, 0xfff, 0x2db, 0xfff, 0xfff,
+ 0x181, 0xfff, 0x089, 0x2c5, 0xfff, 0x1f5, 0xfff, 0x2d6,
+ 0x507, 0xfff, 0x42d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0x080, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
+ 0xfff, 0xfff, 0xfff, 0xfff, 0x3c3, 0x320, 0xfff, 0x1e1,
+ 0xfff, 0x0f5, 0x13b, 0xfff, 0xfff, 0xfff, 0x003, 0x4da,
+ 0xfff, 0xfff, 0xfff, 0x42c, 0xfff, 0xfff, 0x0cb, 0xfff,
+ 0x536, 0x2c3, 0xfff, 0xfff, 0xfff, 0xfff, 0x199, 0xfff,
+ 0xfff, 0x0c0, 0xfff, 0x01e, 0x497, 0xfff, 0xfff, 0x3e5,
+ 0xfff, 0xfff, 0xfff, 0x0cf, 0xfff, 0x2bd, 0xfff, 0x223,
+ 0xfff, 0x3ff, 0xfff, 0x058, 0x174, 0x3ef, 0xfff, 0x002
+};
+
+static unsigned short err_pos(unsigned short din)
+{
+ BUG_ON(din > 4096);
+ return err_pos_lut[din];
+}
+static int chk_no_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
+{
+ if ((chk_syndrome_list[0] | chk_syndrome_list[1] |
+ chk_syndrome_list[2] | chk_syndrome_list[3] |
+ chk_syndrome_list[4] | chk_syndrome_list[5] |
+ chk_syndrome_list[6] | chk_syndrome_list[7]) != 0x0) {
+ return -EINVAL;
+ } else {
+ err_info[0] = 0x0;
+ return 0;
+ }
+}
+static int chk_1_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
+{
+ unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+ tmp0 = gf4096_mul(chk_syndrome_list[1], gf4096_inv(chk_syndrome_list[0]));
+ tmp1 = gf4096_mul(chk_syndrome_list[2], gf4096_inv(chk_syndrome_list[1]));
+ tmp2 = gf4096_mul(chk_syndrome_list[3], gf4096_inv(chk_syndrome_list[2]));
+ tmp3 = gf4096_mul(chk_syndrome_list[4], gf4096_inv(chk_syndrome_list[3]));
+ tmp4 = gf4096_mul(chk_syndrome_list[5], gf4096_inv(chk_syndrome_list[4]));
+ tmp5 = gf4096_mul(chk_syndrome_list[6], gf4096_inv(chk_syndrome_list[5]));
+ tmp6 = gf4096_mul(chk_syndrome_list[7], gf4096_inv(chk_syndrome_list[6]));
+ if ((tmp0 == tmp1) & (tmp1 == tmp2) & (tmp2 == tmp3) & (tmp3 == tmp4) & (tmp4 == tmp5) & (tmp5 == tmp6)) {
+ err_info[0] = 0x1; // encode 1-symbol error as 0x1
+ err_info[1] = err_pos(tmp0);
+ err_info[1] = (unsigned short)(0x55e - err_info[1]);
+ err_info[5] = chk_syndrome_list[0];
+ return 0;
+ } else
+ return -EINVAL;
+}
+static int chk_2_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
+{
+ unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ unsigned short coefs[4];
+ unsigned short err_pats[4];
+ int found_num_root = 0;
+ unsigned short bit2_root0, bit2_root1;
+ unsigned short bit2_root0_inv, bit2_root1_inv;
+ unsigned short err_loc_eqn, test_root;
+ unsigned short bit2_loc0, bit2_loc1;
+ unsigned short bit2_pat0, bit2_pat1;
+
+ find_2x2_soln(chk_syndrome_list[1],
+ chk_syndrome_list[0],
+ chk_syndrome_list[2], chk_syndrome_list[1], chk_syndrome_list[2], chk_syndrome_list[3], coefs);
+ for (test_root = 0x1; test_root < 0xfff; test_root++) {
+ err_loc_eqn =
+ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root) ^ 0x1;
+ if (err_loc_eqn == 0x0) {
+ if (found_num_root == 0) {
+ bit2_root0 = test_root;
+ found_num_root = 1;
+ } else if (found_num_root == 1) {
+ bit2_root1 = test_root;
+ found_num_root = 2;
+ break;
+ }
+ }
+ }
+ if (found_num_root != 2)
+ return -EINVAL;
+ else {
+ bit2_root0_inv = gf4096_inv(bit2_root0);
+ bit2_root1_inv = gf4096_inv(bit2_root1);
+ find_2bit_err_pats(chk_syndrome_list[0],
+ chk_syndrome_list[1], bit2_root0_inv, bit2_root1_inv, err_pats);
+ bit2_pat0 = err_pats[0];
+ bit2_pat1 = err_pats[1];
+ //for(x+1)
+ tmp0 = gf4096_mul(gf4096_mul(bit2_root0_inv, bit2_root0_inv), gf4096_mul(bit2_root0_inv, bit2_root0_inv)); //rinv0^4
+ tmp1 = gf4096_mul(bit2_root0_inv, tmp0); //rinv0^5
+ tmp2 = gf4096_mul(bit2_root0_inv, tmp1); //rinv0^6
+ tmp3 = gf4096_mul(bit2_root0_inv, tmp2); //rinv0^7
+ tmp4 = gf4096_mul(gf4096_mul(bit2_root1_inv, bit2_root1_inv), gf4096_mul(bit2_root1_inv, bit2_root1_inv)); //rinv1^4
+ tmp5 = gf4096_mul(bit2_root1_inv, tmp4); //rinv1^5
+ tmp6 = gf4096_mul(bit2_root1_inv, tmp5); //rinv1^6
+ tmp7 = gf4096_mul(bit2_root1_inv, tmp6); //rinv1^7
+ //check if only 2-bit error
+ if ((chk_syndrome_list[4] ==
+ (gf4096_mul(bit2_pat0, tmp0) ^
+ gf4096_mul(bit2_pat1,
+ tmp4))) & (chk_syndrome_list[5] ==
+ (gf4096_mul(bit2_pat0, tmp1) ^
+ gf4096_mul(bit2_pat1,
+ tmp5))) &
+ (chk_syndrome_list[6] ==
+ (gf4096_mul(bit2_pat0, tmp2) ^
+ gf4096_mul(bit2_pat1,
+ tmp6))) & (chk_syndrome_list[7] ==
+ (gf4096_mul(bit2_pat0, tmp3) ^ gf4096_mul(bit2_pat1, tmp7)))) {
+ if ((err_pos(bit2_root0_inv) == 0xfff) | (err_pos(bit2_root1_inv) == 0xfff)) {
+ return -EINVAL;
+ } else {
+ bit2_loc0 = 0x55e - err_pos(bit2_root0_inv);
+ bit2_loc1 = 0x55e - err_pos(bit2_root1_inv);
+ err_info[0] = 0x2; // encode 2-symbol error as 0x2
+ err_info[1] = bit2_loc0;
+ err_info[2] = bit2_loc1;
+ err_info[5] = bit2_pat0;
+ err_info[6] = bit2_pat1;
+ return 0;
+ }
+ } else
+ return -EINVAL;
+ }
+}
+static int chk_3_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
+{
+ unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+ unsigned short coefs[4];
+ unsigned short err_pats[4];
+ int found_num_root = 0;
+ unsigned short bit3_root0, bit3_root1, bit3_root2;
+ unsigned short bit3_root0_inv, bit3_root1_inv, bit3_root2_inv;
+ unsigned short err_loc_eqn, test_root;
+
+ find_3bit_err_coefs(chk_syndrome_list[0], chk_syndrome_list[1],
+ chk_syndrome_list[2], chk_syndrome_list[3],
+ chk_syndrome_list[4], chk_syndrome_list[5], coefs);
+
+ for (test_root = 0x1; test_root < 0xfff; test_root++) {
+ err_loc_eqn = gf4096_mul(coefs[2],
+ gf4096_mul(gf4096_mul(test_root, test_root),
+ test_root)) ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root))
+ ^ gf4096_mul(coefs[0], test_root) ^ 0x1;
+
+ if (err_loc_eqn == 0x0) {
+ if (found_num_root == 0) {
+ bit3_root0 = test_root;
+ found_num_root = 1;
+ } else if (found_num_root == 1) {
+ bit3_root1 = test_root;
+ found_num_root = 2;
+ } else if (found_num_root == 2) {
+ bit3_root2 = test_root;
+ found_num_root = 3;
+ break;
+ }
+ }
+ }
+ if (found_num_root != 3)
+ return -EINVAL;
+ else {
+ bit3_root0_inv = gf4096_inv(bit3_root0);
+ bit3_root1_inv = gf4096_inv(bit3_root1);
+ bit3_root2_inv = gf4096_inv(bit3_root2);
+
+ find_3bit_err_pats(chk_syndrome_list[0], chk_syndrome_list[1],
+ chk_syndrome_list[2], bit3_root0_inv,
+ bit3_root1_inv, bit3_root2_inv, err_pats);
+
+ //check if only 3-bit error
+ tmp0 = gf4096_mul(bit3_root0_inv, bit3_root0_inv);
+ tmp0 = gf4096_mul(tmp0, tmp0);
+ tmp0 = gf4096_mul(tmp0, bit3_root0_inv);
+ tmp0 = gf4096_mul(tmp0, bit3_root0_inv); //rinv0^6
+ tmp1 = gf4096_mul(tmp0, bit3_root0_inv); //rinv0^7
+ tmp2 = gf4096_mul(bit3_root1_inv, bit3_root1_inv);
+ tmp2 = gf4096_mul(tmp2, tmp2);
+ tmp2 = gf4096_mul(tmp2, bit3_root1_inv);
+ tmp2 = gf4096_mul(tmp2, bit3_root1_inv); //rinv1^6
+ tmp3 = gf4096_mul(tmp2, bit3_root1_inv); //rinv1^7
+ tmp4 = gf4096_mul(bit3_root2_inv, bit3_root2_inv);
+ tmp4 = gf4096_mul(tmp4, tmp4);
+ tmp4 = gf4096_mul(tmp4, bit3_root2_inv);
+ tmp4 = gf4096_mul(tmp4, bit3_root2_inv); //rinv2^6
+ tmp5 = gf4096_mul(tmp4, bit3_root2_inv); //rinv2^7
+
+ //check if only 3 errors
+ if ((chk_syndrome_list[6] == (gf4096_mul(err_pats[0], tmp0) ^
+ gf4096_mul(err_pats[1], tmp2) ^
+ gf4096_mul(err_pats[2], tmp4))) &
+ (chk_syndrome_list[7] == (gf4096_mul(err_pats[0], tmp1) ^
+ gf4096_mul(err_pats[1], tmp3) ^ gf4096_mul(err_pats[2], tmp5)))) {
+ if ((err_pos(bit3_root0_inv) == 0xfff) |
+ (err_pos(bit3_root1_inv) == 0xfff) | (err_pos(bit3_root2_inv) == 0xfff)) {
+ return -EINVAL;
+ } else {
+ err_info[0] = 0x3;
+ err_info[1] = (0x55e - err_pos(bit3_root0_inv));
+ err_info[2] = (0x55e - err_pos(bit3_root1_inv));
+ err_info[3] = (0x55e - err_pos(bit3_root2_inv));
+ err_info[5] = err_pats[0];
+ err_info[6] = err_pats[1];
+ err_info[7] = err_pats[2];
+ return 0;
+ }
+ } else
+ return -EINVAL;
+ }
+}
+static int chk_4_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
+{
+ unsigned short coefs[4];
+ unsigned short err_pats[4];
+ int found_num_root = 0;
+ unsigned short bit4_root0, bit4_root1, bit4_root2, bit4_root3;
+ unsigned short bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv;
+ unsigned short err_loc_eqn, test_root;
+
+ find_4bit_err_coefs(chk_syndrome_list[0],
+ chk_syndrome_list[1],
+ chk_syndrome_list[2],
+ chk_syndrome_list[3],
+ chk_syndrome_list[4],
+ chk_syndrome_list[5], chk_syndrome_list[6], chk_syndrome_list[7], coefs);
+
+ for (test_root = 0x1; test_root < 0xfff; test_root++) {
+ err_loc_eqn =
+ gf4096_mul(coefs[3],
+ gf4096_mul(gf4096_mul
+ (gf4096_mul(test_root, test_root),
+ test_root),
+ test_root)) ^ gf4096_mul(coefs[2],
+ gf4096_mul
+ (gf4096_mul(test_root, test_root), test_root))
+ ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root)
+ ^ 0x1;
+ if (err_loc_eqn == 0x0) {
+ if (found_num_root == 0) {
+ bit4_root0 = test_root;
+ found_num_root = 1;
+ } else if (found_num_root == 1) {
+ bit4_root1 = test_root;
+ found_num_root = 2;
+ } else if (found_num_root == 2) {
+ bit4_root2 = test_root;
+ found_num_root = 3;
+ } else {
+ found_num_root = 4;
+ bit4_root3 = test_root;
+ break;
+ }
+ }
+ }
+ if (found_num_root != 4) {
+ return -EINVAL;
+ } else {
+ bit4_root0_inv = gf4096_inv(bit4_root0);
+ bit4_root1_inv = gf4096_inv(bit4_root1);
+ bit4_root2_inv = gf4096_inv(bit4_root2);
+ bit4_root3_inv = gf4096_inv(bit4_root3);
+ find_4bit_err_pats(chk_syndrome_list[0],
+ chk_syndrome_list[1],
+ chk_syndrome_list[2],
+ chk_syndrome_list[3],
+ bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv, err_pats);
+ err_info[0] = 0x4;
+ err_info[1] = (0x55e - err_pos(bit4_root0_inv));
+ err_info[2] = (0x55e - err_pos(bit4_root1_inv));
+ err_info[3] = (0x55e - err_pos(bit4_root2_inv));
+ err_info[4] = (0x55e - err_pos(bit4_root3_inv));
+ err_info[5] = err_pats[0];
+ err_info[6] = err_pats[1];
+ err_info[7] = err_pats[2];
+ err_info[8] = err_pats[3];
+ return 0;
+ }
+}
+
+void correct_12bit_symbol(unsigned char *buf, unsigned short sym,
+ unsigned short val)
+{
+ if (unlikely(sym > 1366)) {
+ printk(KERN_ERR "Error: symbol %d out of range; cannot correct\n", sym);
+ } else if (sym == 0) {
+ buf[0] ^= val;
+ } else if (sym & 1) {
+ buf[1+(3*(sym-1))/2] ^= (val >> 4);
+ buf[2+(3*(sym-1))/2] ^= ((val & 0xf) << 4);
+ } else {
+ buf[2+(3*(sym-2))/2] ^= (val >> 8);
+ buf[3+(3*(sym-2))/2] ^= (val & 0xff);
+ }
+}
+
+static int debugecc = 0;
+module_param(debugecc, int, 0644);
+
+int cafe_correct_ecc(unsigned char *buf,
+ unsigned short *chk_syndrome_list)
+{
+ unsigned short err_info[9];
+ int i;
+
+ if (debugecc) {
+ printk(KERN_WARNING "cafe_correct_ecc invoked. Syndromes %x %x %x %x %x %x %x %x\n",
+ chk_syndrome_list[0], chk_syndrome_list[1],
+ chk_syndrome_list[2], chk_syndrome_list[3],
+ chk_syndrome_list[4], chk_syndrome_list[5],
+ chk_syndrome_list[6], chk_syndrome_list[7]);
+ for (i=0; i < 2048; i+=16) {
+ printk(KERN_WARNING "D %04x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ i,
+ buf[i], buf[i+1], buf[i+2], buf[i+3],
+ buf[i+4], buf[i+5], buf[i+6], buf[i+7],
+ buf[i+8], buf[i+9], buf[i+10], buf[i+11],
+ buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
+ }
+ for ( ; i < 2112; i+=16) {
+ printk(KERN_WARNING "O %02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ i - 2048,
+ buf[i], buf[i+1], buf[i+2], buf[i+3],
+ buf[i+4], buf[i+5], buf[i+6], buf[i+7],
+ buf[i+8], buf[i+9], buf[i+10], buf[i+11],
+ buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
+ }
+ }
+
+
+
+ if (chk_no_err_only(chk_syndrome_list, err_info) &&
+ chk_1_err_only(chk_syndrome_list, err_info) &&
+ chk_2_err_only(chk_syndrome_list, err_info) &&
+ chk_3_err_only(chk_syndrome_list, err_info) &&
+ chk_4_err_only(chk_syndrome_list, err_info)) {
+ return -EIO;
+ }
+
+ for (i=0; i < err_info[0]; i++) {
+ if (debugecc)
+ printk(KERN_WARNING "Correct symbol %d with 0x%03x\n",
+ err_info[1+i], err_info[5+i]);
+
+ correct_12bit_symbol(buf, err_info[1+i], err_info[5+i]);
+ }
+
+ return err_info[0];
+}
+
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
index 94924d52a9b..8296305c829 100644
--- a/drivers/mtd/nand/cs553x_nand.c
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -11,7 +11,7 @@
* published by the Free Software Foundation.
*
* Overview:
- * This is a device driver for the NAND flash controller found on
+ * This is a device driver for the NAND flash controller found on
* the AMD CS5535/CS5536 companion chipsets for the Geode processor.
*
*/
@@ -303,7 +303,7 @@ static int __init cs553x_init(void)
err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF);
}
- /* Register all devices together here. This means we can easily hack it to
+ /* Register all devices together here. This means we can easily hack it to
do mtdconcat etc. if we want to. */
for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
if (cs553x_mtd[i]) {
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 6107f532855..12608c13cce 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -1635,13 +1635,12 @@ static int __init doc_probe(unsigned long physadr)
len = sizeof(struct mtd_info) +
sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr));
- mtd = kmalloc(len, GFP_KERNEL);
+ mtd = kzalloc(len, GFP_KERNEL);
if (!mtd) {
printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
ret = -ENOMEM;
goto fail;
}
- memset(mtd, 0, len);
nand = (struct nand_chip *) (mtd + 1);
doc = (struct doc_priv *) (nand + 1);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 41bfcae1fbf..dfe56e03e48 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -362,7 +362,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
* access
*/
ofs += mtd->oobsize;
- chip->ops.len = 2;
+ chip->ops.len = chip->ops.ooblen = 2;
chip->ops.datbuf = NULL;
chip->ops.oobbuf = buf;
chip->ops.ooboffs = chip->badblockpos & ~0x01;
@@ -755,7 +755,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
- * nand_read_page_swecc - {REPLACABLE] software ecc based page read function
+ * nand_read_page_swecc - [REPLACABLE] software ecc based page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
@@ -795,7 +795,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
- * nand_read_page_hwecc - {REPLACABLE] hardware ecc based page read function
+ * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
@@ -839,7 +839,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
- * nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read
+ * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
@@ -897,12 +897,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
* @chip: nand chip structure
* @oob: oob destination address
* @ops: oob ops structure
+ * @len: size of oob to transfer
*/
static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
- struct mtd_oob_ops *ops)
+ struct mtd_oob_ops *ops, size_t len)
{
- size_t len = ops->ooblen;
-
switch(ops->mode) {
case MTD_OOB_PLACE:
@@ -960,6 +959,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
int sndcmd = 1;
int ret = 0;
uint32_t readlen = ops->len;
+ uint32_t oobreadlen = ops->ooblen;
uint8_t *bufpoi, *oob, *buf;
stats = mtd->ecc_stats;
@@ -971,7 +971,6 @@ 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;
buf = ops->datbuf;
oob = ops->oobbuf;
@@ -1007,10 +1006,17 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
if (unlikely(oob)) {
/* Raw mode does data:oob:data:oob */
- if (ops->mode != MTD_OOB_RAW)
- oob = nand_transfer_oob(chip, oob, ops);
- else
- buf = nand_transfer_oob(chip, buf, ops);
+ if (ops->mode != MTD_OOB_RAW) {
+ int toread = min(oobreadlen,
+ chip->ecc.layout->oobavail);
+ if (toread) {
+ oob = nand_transfer_oob(chip,
+ oob, ops, toread);
+ oobreadlen -= toread;
+ }
+ } else
+ buf = nand_transfer_oob(chip,
+ buf, ops, mtd->oobsize);
}
if (!(chip->options & NAND_NO_READRDY)) {
@@ -1057,6 +1063,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
}
ops->retlen = ops->len - (size_t) readlen;
+ if (oob)
+ ops->oobretlen = ops->ooblen - oobreadlen;
if (ret)
return ret;
@@ -1257,12 +1265,18 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
int page, realpage, chipnr, sndcmd = 1;
struct nand_chip *chip = mtd->priv;
int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
- int readlen = ops->len;
+ int readlen = ops->ooblen;
+ int len;
uint8_t *buf = ops->oobbuf;
DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
(unsigned long long)from, readlen);
+ if (ops->mode == MTD_OOB_RAW)
+ len = mtd->oobsize;
+ else
+ len = chip->ecc.layout->oobavail;
+
chipnr = (int)(from >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
@@ -1270,11 +1284,11 @@ 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;
-
while(1) {
sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
- buf = nand_transfer_oob(chip, buf, ops);
+
+ len = min(len, readlen);
+ buf = nand_transfer_oob(chip, buf, ops, len);
if (!(chip->options & NAND_NO_READRDY)) {
/*
@@ -1289,7 +1303,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
nand_wait_ready(mtd);
}
- readlen -= ops->ooblen;
+ readlen -= len;
if (!readlen)
break;
@@ -1311,7 +1325,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
sndcmd = 1;
}
- ops->retlen = ops->len;
+ ops->oobretlen = ops->ooblen;
return 0;
}
@@ -1332,7 +1346,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
ops->retlen = 0;
/* Do not allow reads past end of device */
- if ((from + ops->len) > mtd->size) {
+ if (ops->datbuf && (from + ops->len) > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
"Attempt read beyond end of device\n");
return -EINVAL;
@@ -1375,7 +1389,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
- * nand_write_page_swecc - {REPLACABLE] software ecc based page write function
+ * nand_write_page_swecc - [REPLACABLE] software ecc based page write function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
@@ -1401,7 +1415,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
- * nand_write_page_hwecc - {REPLACABLE] hardware ecc based page write function
+ * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
@@ -1429,7 +1443,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
- * nand_write_page_syndrome - {REPLACABLE] hardware ecc syndrom based page write
+ * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
@@ -1577,7 +1591,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
return NULL;
}
-#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
+#define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0
/**
* nand_do_write_ops - [Internal] NAND write with ECC
@@ -1590,15 +1604,16 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
- int chipnr, realpage, page, blockmask;
+ int chipnr, realpage, page, blockmask, column;
struct nand_chip *chip = mtd->priv;
uint32_t writelen = ops->len;
uint8_t *oob = ops->oobbuf;
uint8_t *buf = ops->datbuf;
- int bytes = mtd->writesize;
- int ret;
+ int ret, subpage;
ops->retlen = 0;
+ if (!writelen)
+ return 0;
/* reject writes, which are not page aligned */
if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
@@ -1607,8 +1622,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
return -EINVAL;
}
- if (!writelen)
- return 0;
+ column = to & (mtd->writesize - 1);
+ subpage = column || (writelen & (mtd->writesize - 1));
+
+ if (subpage && oob)
+ return -EINVAL;
chipnr = (int)(to >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
@@ -1626,15 +1644,29 @@ 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;
+ /* If we're not given explicit OOB data, let it be 0xFF */
+ if (likely(!oob))
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
while(1) {
+ int bytes = mtd->writesize;
int cached = writelen > bytes && page != blockmask;
+ uint8_t *wbuf = buf;
+
+ /* Partial page write ? */
+ if (unlikely(column || writelen < (mtd->writesize - 1))) {
+ cached = 0;
+ bytes = min_t(int, bytes - column, (int) writelen);
+ chip->pagebuf = -1;
+ memset(chip->buffers->databuf, 0xff, mtd->writesize);
+ memcpy(&chip->buffers->databuf[column], buf, bytes);
+ wbuf = chip->buffers->databuf;
+ }
if (unlikely(oob))
oob = nand_fill_oob(chip, oob, ops);
- ret = chip->write_page(mtd, chip, buf, page, cached,
+ ret = chip->write_page(mtd, chip, wbuf, page, cached,
(ops->mode == MTD_OOB_RAW));
if (ret)
break;
@@ -1643,6 +1675,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
if (!writelen)
break;
+ column = 0;
buf += bytes;
realpage++;
@@ -1655,10 +1688,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
}
}
- if (unlikely(oob))
- memset(chip->oob_poi, 0xff, mtd->oobsize);
-
ops->retlen = ops->len - writelen;
+ if (unlikely(oob))
+ ops->oobretlen = ops->ooblen;
return ret;
}
@@ -1714,10 +1746,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
struct nand_chip *chip = mtd->priv;
DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
- (unsigned int)to, (int)ops->len);
+ (unsigned int)to, (int)ops->ooblen);
/* Do not allow write past end of page */
- if ((ops->ooboffs + ops->len) > mtd->oobsize) {
+ if ((ops->ooboffs + ops->ooblen) > mtd->oobsize) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
"Attempt to write past end of page\n");
return -EINVAL;
@@ -1745,7 +1777,6 @@ 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;
memset(chip->oob_poi, 0xff, mtd->oobsize);
nand_fill_oob(chip, ops->oobbuf, ops);
status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
@@ -1754,7 +1785,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
if (status)
return status;
- ops->retlen = ops->len;
+ ops->oobretlen = ops->ooblen;
return 0;
}
@@ -1774,7 +1805,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
ops->retlen = 0;
/* Do not allow writes past end of device */
- if ((to + ops->len) > mtd->size) {
+ if (ops->datbuf && (to + ops->len) > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
"Attempt read beyond end of device\n");
return -EINVAL;
@@ -2188,8 +2219,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
/* Newer devices have all the information in additional id bytes */
if (!type->pagesize) {
int extid;
- /* The 3rd id byte contains non relevant data ATM */
- extid = chip->read_byte(mtd);
+ /* The 3rd id byte holds MLC / multichip data */
+ chip->cellinfo = chip->read_byte(mtd);
/* The 4th id byte is the important one */
extid = chip->read_byte(mtd);
/* Calc pagesize */
@@ -2349,8 +2380,8 @@ int nand_scan_tail(struct mtd_info *mtd)
if (!chip->buffers)
return -ENOMEM;
- /* Preset the internal oob write buffer */
- memset(chip->buffers->oobwbuf, 0xff, mtd->oobsize);
+ /* Set the internal oob buffer location, just after the page data */
+ chip->oob_poi = chip->buffers->databuf + mtd->writesize;
/*
* If no default placement scheme is given, select an appropriate one
@@ -2469,6 +2500,24 @@ int nand_scan_tail(struct mtd_info *mtd)
}
chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
+ /*
+ * Allow subpage writes up to ecc.steps. Not possible for MLC
+ * FLASH.
+ */
+ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
+ !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
+ switch(chip->ecc.steps) {
+ case 2:
+ mtd->subpage_sft = 1;
+ break;
+ case 4:
+ case 8:
+ mtd->subpage_sft = 2;
+ break;
+ }
+ }
+ chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
+
/* Initialize state */
chip->state = FL_READY;
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 9402653eb09..5e121ceaa59 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -333,7 +333,6 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
struct mtd_oob_ops ops;
int j, ret;
- ops.len = mtd->oobsize;
ops.ooblen = mtd->oobsize;
ops.oobbuf = buf;
ops.ooboffs = 0;
@@ -676,10 +675,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
"bad block table\n");
}
/* Read oob data */
- ops.len = (len >> this->page_shift) * mtd->oobsize;
+ ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
ops.oobbuf = &buf[len];
res = mtd->read_oob(mtd, to + mtd->writesize, &ops);
- if (res < 0 || ops.retlen != ops.len)
+ if (res < 0 || ops.oobretlen != ops.ooblen)
goto outerr;
/* Calc the byte offset in the buffer */
@@ -961,14 +960,12 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
struct nand_bbt_descr *md = this->bbt_md;
len = mtd->size >> (this->bbt_erase_shift + 2);
- /* Allocate memory (2bit per block) */
- this->bbt = kmalloc(len, GFP_KERNEL);
+ /* Allocate memory (2bit per block) and clear the memory bad block table */
+ this->bbt = kzalloc(len, GFP_KERNEL);
if (!this->bbt) {
printk(KERN_ERR "nand_scan_bbt: Out of memory\n");
return -ENOMEM;
}
- /* Clear the memory bad block table */
- memset(this->bbt, 0x00, len);
/* If no primary table decriptor is given, scan the device
* to build a memory based bad block table
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index dd438ca47d9..fde593e5e63 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -112,7 +112,7 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
/* Calculate final ECC code */
-#ifdef CONFIG_NAND_ECC_SMC
+#ifdef CONFIG_MTD_NAND_ECC_SMC
ecc_code[0] = ~tmp2;
ecc_code[1] = ~tmp1;
#else
@@ -148,7 +148,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat,
{
uint8_t s0, s1, s2;
-#ifdef CONFIG_NAND_ECC_SMC
+#ifdef CONFIG_MTD_NAND_ECC_SMC
s0 = calc_ecc[0] ^ read_ecc[0];
s1 = calc_ecc[1] ^ read_ecc[1];
s2 = calc_ecc[2] ^ read_ecc[2];
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 545ff252d81..c3bca9590ad 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -37,10 +37,6 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
-#ifdef CONFIG_NS_ABS_POS
-#include <asm/io.h>
-#endif
-
/* Default simulator parameters values */
#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
@@ -164,7 +160,7 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero");
/* After a command is input, the simulator goes to one of the following states */
#define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */
#define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */
-#define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */
+#define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */
#define STATE_CMD_PAGEPROG 0x00000004 /* start page programm */
#define STATE_CMD_READOOB 0x00000005 /* read OOB area */
#define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */
@@ -231,6 +227,14 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero");
#define NS_MAX_PREVSTATES 1
/*
+ * A union to represent flash memory contents and flash buffer.
+ */
+union ns_mem {
+ u_char *byte; /* for byte access */
+ uint16_t *word; /* for 16-bit word access */
+};
+
+/*
* The structure which describes all the internal simulator data.
*/
struct nandsim {
@@ -247,17 +251,11 @@ struct nandsim {
uint16_t npstates; /* number of previous states saved */
uint16_t stateidx; /* current state index */
- /* The simulated NAND flash image */
- union flash_media {
- u_char *byte;
- uint16_t *word;
- } mem;
+ /* The simulated NAND flash pages array */
+ union ns_mem *pages;
/* Internal buffer of page + OOB size bytes */
- union internal_buffer {
- u_char *byte; /* for byte access */
- uint16_t *word; /* for 16-bit word access */
- } buf;
+ union ns_mem buf;
/* NAND flash "geometry" */
struct nandsin_geometry {
@@ -346,12 +344,49 @@ static struct mtd_info *nsmtd;
static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];
/*
+ * Allocate array of page pointers and initialize the array to NULL
+ * pointers.
+ *
+ * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
+ */
+static int alloc_device(struct nandsim *ns)
+{
+ int i;
+
+ ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
+ if (!ns->pages) {
+ NS_ERR("alloc_map: unable to allocate page array\n");
+ return -ENOMEM;
+ }
+ for (i = 0; i < ns->geom.pgnum; i++) {
+ ns->pages[i].byte = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * Free any allocated pages, and free the array of page pointers.
+ */
+static void free_device(struct nandsim *ns)
+{
+ int i;
+
+ if (ns->pages) {
+ for (i = 0; i < ns->geom.pgnum; i++) {
+ if (ns->pages[i].byte)
+ kfree(ns->pages[i].byte);
+ }
+ vfree(ns->pages);
+ }
+}
+
+/*
* Initialize the nandsim structure.
*
* RETURNS: 0 if success, -ERRNO if failure.
*/
-static int
-init_nandsim(struct mtd_info *mtd)
+static int init_nandsim(struct mtd_info *mtd)
{
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
struct nandsim *ns = (struct nandsim *)(chip->priv);
@@ -405,7 +440,7 @@ init_nandsim(struct mtd_info *mtd)
}
} else {
if (ns->geom.totsz <= (128 << 20)) {
- ns->geom.pgaddrbytes = 5;
+ ns->geom.pgaddrbytes = 4;
ns->geom.secaddrbytes = 2;
} else {
ns->geom.pgaddrbytes = 5;
@@ -439,23 +474,8 @@ init_nandsim(struct mtd_info *mtd)
printk("sector address bytes: %u\n", ns->geom.secaddrbytes);
printk("options: %#x\n", ns->options);
- /* Map / allocate and initialize the flash image */
-#ifdef CONFIG_NS_ABS_POS
- ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob);
- if (!ns->mem.byte) {
- NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n",
- (void *)CONFIG_NS_ABS_POS);
- return -ENOMEM;
- }
-#else
- ns->mem.byte = vmalloc(ns->geom.totszoob);
- if (!ns->mem.byte) {
- NS_ERR("init_nandsim: unable to allocate %u bytes for flash image\n",
- ns->geom.totszoob);
- return -ENOMEM;
- }
- memset(ns->mem.byte, 0xFF, ns->geom.totszoob);
-#endif
+ if (alloc_device(ns) != 0)
+ goto error;
/* Allocate / initialize the internal buffer */
ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
@@ -474,11 +494,7 @@ init_nandsim(struct mtd_info *mtd)
return 0;
error:
-#ifdef CONFIG_NS_ABS_POS
- iounmap(ns->mem.byte);
-#else
- vfree(ns->mem.byte);
-#endif
+ free_device(ns);
return -ENOMEM;
}
@@ -486,16 +502,10 @@ error:
/*
* Free the nandsim structure.
*/
-static void
-free_nandsim(struct nandsim *ns)
+static void free_nandsim(struct nandsim *ns)
{
kfree(ns->buf.byte);
-
-#ifdef CONFIG_NS_ABS_POS
- iounmap(ns->mem.byte);
-#else
- vfree(ns->mem.byte);
-#endif
+ free_device(ns);
return;
}
@@ -503,8 +513,7 @@ free_nandsim(struct nandsim *ns)
/*
* Returns the string representation of 'state' state.
*/
-static char *
-get_state_name(uint32_t state)
+static char *get_state_name(uint32_t state)
{
switch (NS_STATE(state)) {
case STATE_CMD_READ0:
@@ -562,8 +571,7 @@ get_state_name(uint32_t state)
*
* RETURNS: 1 if wrong command, 0 if right.
*/
-static int
-check_command(int cmd)
+static int check_command(int cmd)
{
switch (cmd) {
@@ -589,8 +597,7 @@ check_command(int cmd)
/*
* Returns state after command is accepted by command number.
*/
-static uint32_t
-get_state_by_command(unsigned command)
+static uint32_t get_state_by_command(unsigned command)
{
switch (command) {
case NAND_CMD_READ0:
@@ -626,8 +633,7 @@ get_state_by_command(unsigned command)
/*
* Move an address byte to the correspondent internal register.
*/
-static inline void
-accept_addr_byte(struct nandsim *ns, u_char bt)
+static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
{
uint byte = (uint)bt;
@@ -645,8 +651,7 @@ accept_addr_byte(struct nandsim *ns, u_char bt)
/*
* Switch to STATE_READY state.
*/
-static inline void
-switch_to_ready_state(struct nandsim *ns, u_char status)
+static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
{
NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
@@ -705,8 +710,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status)
* -1 - several matches.
* 0 - operation is found.
*/
-static int
-find_operation(struct nandsim *ns, uint32_t flag)
+static int find_operation(struct nandsim *ns, uint32_t flag)
{
int opsfound = 0;
int i, j, idx = 0;
@@ -791,14 +795,93 @@ find_operation(struct nandsim *ns, uint32_t flag)
}
/*
+ * Returns a pointer to the current page.
+ */
+static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
+{
+ return &(ns->pages[ns->regs.row]);
+}
+
+/*
+ * Retuns a pointer to the current byte, within the current page.
+ */
+static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
+{
+ return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
+}
+
+/*
+ * Fill the NAND buffer with data read from the specified page.
+ */
+static void read_page(struct nandsim *ns, int num)
+{
+ union ns_mem *mypage;
+
+ mypage = NS_GET_PAGE(ns);
+ if (mypage->byte == NULL) {
+ NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
+ memset(ns->buf.byte, 0xFF, num);
+ } else {
+ NS_DBG("read_page: page %d allocated, reading from %d\n",
+ ns->regs.row, ns->regs.column + ns->regs.off);
+ memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
+ }
+}
+
+/*
+ * Erase all pages in the specified sector.
+ */
+static void erase_sector(struct nandsim *ns)
+{
+ union ns_mem *mypage;
+ int i;
+
+ mypage = NS_GET_PAGE(ns);
+ for (i = 0; i < ns->geom.pgsec; i++) {
+ if (mypage->byte != NULL) {
+ NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
+ kfree(mypage->byte);
+ mypage->byte = NULL;
+ }
+ mypage++;
+ }
+}
+
+/*
+ * Program the specified page with the contents from the NAND buffer.
+ */
+static int prog_page(struct nandsim *ns, int num)
+{
+ int i;
+ union ns_mem *mypage;
+ u_char *pg_off;
+
+ mypage = NS_GET_PAGE(ns);
+ if (mypage->byte == NULL) {
+ NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
+ mypage->byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+ if (mypage->byte == NULL) {
+ NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
+ return -1;
+ }
+ memset(mypage->byte, 0xFF, ns->geom.pgszoob);
+ }
+
+ pg_off = NS_PAGE_BYTE_OFF(ns);
+ for (i = 0; i < num; i++)
+ pg_off[i] &= ns->buf.byte[i];
+
+ return 0;
+}
+
+/*
* If state has any action bit, perform this action.
*
* RETURNS: 0 if success, -1 if error.
*/
-static int
-do_state_action(struct nandsim *ns, uint32_t action)
+static int do_state_action(struct nandsim *ns, uint32_t action)
{
- int i, num;
+ int num;
int busdiv = ns->busw == 8 ? 1 : 2;
action &= ACTION_MASK;
@@ -822,7 +905,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
break;
}
num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
- memcpy(ns->buf.byte, ns->mem.byte + NS_RAW_OFFSET(ns) + ns->regs.off, num);
+ read_page(ns, num);
NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
num, NS_RAW_OFFSET(ns) + ns->regs.off);
@@ -863,7 +946,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
ns->regs.row, NS_RAW_OFFSET(ns));
NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift));
- memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob);
+ erase_sector(ns);
NS_MDELAY(erase_delay);
@@ -886,8 +969,8 @@ do_state_action(struct nandsim *ns, uint32_t action)
return -1;
}
- for (i = 0; i < num; i++)
- ns->mem.byte[NS_RAW_OFFSET(ns) + ns->regs.off + i] &= ns->buf.byte[i];
+ if (prog_page(ns, num) == -1)
+ return -1;
NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
@@ -928,8 +1011,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
/*
* Switch simulator's state.
*/
-static void
-switch_state(struct nandsim *ns)
+static void switch_state(struct nandsim *ns)
{
if (ns->op) {
/*
@@ -1070,8 +1152,7 @@ switch_state(struct nandsim *ns)
}
}
-static u_char
-ns_nand_read_byte(struct mtd_info *mtd)
+static u_char ns_nand_read_byte(struct mtd_info *mtd)
{
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
u_char outb = 0x00;
@@ -1144,8 +1225,7 @@ ns_nand_read_byte(struct mtd_info *mtd)
return outb;
}
-static void
-ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
+static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
{
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
@@ -1308,15 +1388,13 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
ns_nand_write_byte(mtd, cmd);
}
-static int
-ns_device_ready(struct mtd_info *mtd)
+static int ns_device_ready(struct mtd_info *mtd)
{
NS_DBG("device_ready\n");
return 1;
}
-static uint16_t
-ns_nand_read_word(struct mtd_info *mtd)
+static uint16_t ns_nand_read_word(struct mtd_info *mtd)
{
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
@@ -1325,8 +1403,7 @@ ns_nand_read_word(struct mtd_info *mtd)
return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
}
-static void
-ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
@@ -1353,8 +1430,7 @@ ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
}
}
-static void
-ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
@@ -1407,8 +1483,7 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
return;
}
-static int
-ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static int ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len);
@@ -1436,14 +1511,12 @@ static int __init ns_init_module(void)
}
/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
- nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
+ nsmtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
+ sizeof(struct nandsim), GFP_KERNEL);
if (!nsmtd) {
NS_ERR("unable to allocate core structures.\n");
return -ENOMEM;
}
- memset(nsmtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip) +
- sizeof(struct nandsim));
chip = (struct nand_chip *)(nsmtd + 1);
nsmtd->priv = (void *)chip;
nand = (struct nandsim *)(chip + 1);
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 039c759cfbf..fd7a8d5ba29 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -56,7 +56,7 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
ccr |= NDFC_CCR_BS(chip + pchip->chip_offset);
} else
ccr |= NDFC_CCR_RESET_CE;
- writel(ccr, ndfc->ndfcbase + NDFC_CCR);
+ __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
}
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c
index f8c49645324..9189ec8f243 100644
--- a/drivers/mtd/nand/rtc_from4.c
+++ b/drivers/mtd/nand/rtc_from4.c
@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/rslib.h>
+#include <linux/bitrev.h>
#include <linux/module.h>
#include <linux/mtd/compatmac.h>
#include <linux/mtd/mtd.h>
@@ -152,47 +153,6 @@ static struct nand_ecclayout rtc_from4_nand_oobinfo = {
.oobfree = {{32, 32}}
};
-/* Aargh. I missed the reversed bit order, when I
- * was talking to Renesas about the FPGA.
- *
- * The table is used for bit reordering and inversion
- * of the ecc byte which we get from the FPGA
- */
-static uint8_t revbits[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
-};
-
#endif
/*
@@ -397,7 +357,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
/* Read the syndrom pattern from the FPGA and correct the bitorder */
rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC);
for (i = 0; i < 8; i++) {
- ecc[i] = revbits[(*rs_ecc) & 0xFF];
+ ecc[i] = bitrev8(*rs_ecc);
rs_ecc++;
}
@@ -496,7 +456,7 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this,
rtn = nand_do_read(mtd, page, len, &retlen, buf);
/* if read failed or > 1-bit error corrected */
- if (rtn || (mtd->ecc_stats.corrected - corrected) > 1) {
+ if (rtn || (mtd->ecc_stats.corrected - corrected) > 1)
er_stat |= 1 << 1;
kfree(buf);
}
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index ff5cef24d5b..8b3203571ee 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -283,7 +283,7 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-
+
if (cmd == NAND_CMD_NONE)
return;
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index b5a5f8da472..4b1ba4fcfcd 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -57,17 +57,16 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
- nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
+ nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
if (!nftl) {
printk(KERN_WARNING "NFTL: out of memory for data structures\n");
return;
}
- memset(nftl, 0, sizeof(*nftl));
nftl->mbd.mtd = mtd;
nftl->mbd.devnum = -1;
- nftl->mbd.blksize = 512;
+
nftl->mbd.tr = tr;
if (NFTL_mount(nftl) < 0) {
@@ -147,10 +146,9 @@ int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
- ops.len = len;
res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
- *retlen = ops.retlen;
+ *retlen = ops.oobretlen;
return res;
}
@@ -168,10 +166,9 @@ int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
- ops.len = len;
res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
- *retlen = ops.retlen;
+ *retlen = ops.oobretlen;
return res;
}
@@ -797,6 +794,7 @@ static struct mtd_blktrans_ops nftl_tr = {
.name = "nftl",
.major = NFTL_MAJOR,
.part_bits = NFTL_PARTN_BITS,
+ .blksize = 512,
.getgeo = nftl_getgeo,
.readsect = nftl_readblock,
#ifdef CONFIG_NFTL_RW
diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c
index af06a80f44d..3d44d040a47 100644
--- a/drivers/mtd/onenand/generic.c
+++ b/drivers/mtd/onenand/generic.c
@@ -45,12 +45,10 @@ static int __devinit generic_onenand_probe(struct device *dev)
unsigned long size = res->end - res->start + 1;
int err;
- info = kmalloc(sizeof(struct onenand_info), GFP_KERNEL);
+ info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- memset(info, 0, sizeof(struct onenand_info));
-
if (!request_mem_region(res->start, size, dev->driver->name)) {
err = -EBUSY;
goto out_free_info;
@@ -63,6 +61,7 @@ static int __devinit generic_onenand_probe(struct device *dev)
}
info->onenand.mmcontrol = pdata->mmcontrol;
+ info->onenand.irq = platform_get_irq(pdev, 0);
info->mtd.name = pdev->dev.bus_id;
info->mtd.priv = &info->onenand;
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 8ed68b28afe..2da6bb26353 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
+#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/onenand.h>
@@ -191,8 +192,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
struct onenand_chip *this = mtd->priv;
int value, readcmd = 0, block_cmd = 0;
int block, page;
- /* Now we use page size operation */
- int sectors = 4, count = 4;
/* Address translation */
switch (cmd) {
@@ -244,6 +243,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
}
if (page != -1) {
+ /* Now we use page size operation */
+ int sectors = 4, count = 4;
int dataram;
switch (cmd) {
@@ -297,7 +298,7 @@ static int onenand_wait(struct mtd_info *mtd, int state)
unsigned long timeout;
unsigned int flags = ONENAND_INT_MASTER;
unsigned int interrupt = 0;
- unsigned int ctrl, ecc;
+ unsigned int ctrl;
/* The 20 msec is enough */
timeout = jiffies + msecs_to_jiffies(20);
@@ -309,7 +310,6 @@ static int onenand_wait(struct mtd_info *mtd, int state)
if (state != FL_READING)
cond_resched();
- touch_softlockup_watchdog();
}
/* To get correct interrupt status in timeout case */
interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
@@ -317,28 +317,126 @@ static int onenand_wait(struct mtd_info *mtd, int state)
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
if (ctrl & ONENAND_CTRL_ERROR) {
- /* It maybe occur at initial bad block */
DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl);
- /* Clear other interrupt bits for preventing ECC error */
- interrupt &= ONENAND_INT_MASTER;
- }
-
- if (ctrl & ONENAND_CTRL_LOCK) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error = 0x%04x\n", ctrl);
- return -EACCES;
+ if (ctrl & ONENAND_CTRL_LOCK)
+ DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error.\n");
+ return ctrl;
}
if (interrupt & ONENAND_INT_READ) {
- ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
- if (ecc & ONENAND_ECC_2BIT_ALL) {
+ int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
+ if (ecc) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc);
- return -EBADMSG;
+ if (ecc & ONENAND_ECC_2BIT_ALL) {
+ mtd->ecc_stats.failed++;
+ return ecc;
+ } else if (ecc & ONENAND_ECC_1BIT_ALL)
+ mtd->ecc_stats.corrected++;
}
}
return 0;
}
+/*
+ * onenand_interrupt - [DEFAULT] onenand interrupt handler
+ * @param irq onenand interrupt number
+ * @param dev_id interrupt data
+ *
+ * complete the work
+ */
+static irqreturn_t onenand_interrupt(int irq, void *data)
+{
+ struct onenand_chip *this = (struct onenand_chip *) data;
+
+ /* To handle shared interrupt */
+ if (!this->complete.done)
+ complete(&this->complete);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * onenand_interrupt_wait - [DEFAULT] wait until the command is done
+ * @param mtd MTD device structure
+ * @param state state to select the max. timeout value
+ *
+ * Wait for command done.
+ */
+static int onenand_interrupt_wait(struct mtd_info *mtd, int state)
+{
+ struct onenand_chip *this = mtd->priv;
+
+ wait_for_completion(&this->complete);
+
+ return onenand_wait(mtd, state);
+}
+
+/*
+ * onenand_try_interrupt_wait - [DEFAULT] try interrupt wait
+ * @param mtd MTD device structure
+ * @param state state to select the max. timeout value
+ *
+ * Try interrupt based wait (It is used one-time)
+ */
+static int onenand_try_interrupt_wait(struct mtd_info *mtd, int state)
+{
+ struct onenand_chip *this = mtd->priv;
+ unsigned long remain, timeout;
+
+ /* We use interrupt wait first */
+ this->wait = onenand_interrupt_wait;
+
+ timeout = msecs_to_jiffies(100);
+ remain = wait_for_completion_timeout(&this->complete, timeout);
+ if (!remain) {
+ printk(KERN_INFO "OneNAND: There's no interrupt. "
+ "We use the normal wait\n");
+
+ /* Release the irq */
+ free_irq(this->irq, this);
+
+ this->wait = onenand_wait;
+ }
+
+ return onenand_wait(mtd, state);
+}
+
+/*
+ * onenand_setup_wait - [OneNAND Interface] setup onenand wait method
+ * @param mtd MTD device structure
+ *
+ * There's two method to wait onenand work
+ * 1. polling - read interrupt status register
+ * 2. interrupt - use the kernel interrupt method
+ */
+static void onenand_setup_wait(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+ int syscfg;
+
+ init_completion(&this->complete);
+
+ if (this->irq <= 0) {
+ this->wait = onenand_wait;
+ return;
+ }
+
+ if (request_irq(this->irq, &onenand_interrupt,
+ IRQF_SHARED, "onenand", this)) {
+ /* If we can't get irq, use the normal wait */
+ this->wait = onenand_wait;
+ return;
+ }
+
+ /* Enable interrupt */
+ syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
+ syscfg |= ONENAND_SYS_CFG1_IOBE;
+ this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
+
+ this->wait = onenand_try_interrupt_wait;
+}
+
/**
* onenand_bufferram_offset - [DEFAULT] BufferRAM offset
* @param mtd MTD data structure
@@ -609,9 +707,10 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct onenand_chip *this = mtd->priv;
+ struct mtd_ecc_stats stats;
int read = 0, column;
int thislen;
- int ret = 0;
+ int ret = 0, boundary = 0;
DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
@@ -627,38 +726,61 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
/* TODO handling oob */
- while (read < len) {
- thislen = min_t(int, mtd->writesize, len - read);
-
- column = from & (mtd->writesize - 1);
- if (column + thislen > mtd->writesize)
- thislen = mtd->writesize - column;
-
- if (!onenand_check_bufferram(mtd, from)) {
- this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
-
- ret = this->wait(mtd, FL_READING);
- /* First copy data and check return value for ECC handling */
- onenand_update_bufferram(mtd, from, 1);
- }
-
- this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
-
- read += thislen;
-
- if (read == len)
- break;
-
- if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret);
- goto out;
- }
-
- from += thislen;
- buf += thislen;
- }
+ stats = mtd->ecc_stats;
+
+ /* Read-while-load method */
+
+ /* Do first load to bufferRAM */
+ if (read < len) {
+ if (!onenand_check_bufferram(mtd, from)) {
+ this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
+ ret = this->wait(mtd, FL_READING);
+ onenand_update_bufferram(mtd, from, !ret);
+ }
+ }
+
+ thislen = min_t(int, mtd->writesize, len - read);
+ column = from & (mtd->writesize - 1);
+ if (column + thislen > mtd->writesize)
+ thislen = mtd->writesize - column;
+
+ while (!ret) {
+ /* If there is more to load then start next load */
+ from += thislen;
+ if (read + thislen < len) {
+ this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
+ /*
+ * Chip boundary handling in DDP
+ * Now we issued chip 1 read and pointed chip 1
+ * bufferam so we have to point chip 0 bufferam.
+ */
+ if (this->device_id & ONENAND_DEVICE_IS_DDP &&
+ unlikely(from == (this->chipsize >> 1))) {
+ this->write_word(0, this->base + ONENAND_REG_START_ADDRESS2);
+ boundary = 1;
+ } else
+ boundary = 0;
+ ONENAND_SET_PREV_BUFFERRAM(this);
+ }
+ /* While load is going, read from last bufferRAM */
+ this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
+ /* See if we are done */
+ read += thislen;
+ if (read == len)
+ break;
+ /* Set up for next read from bufferRAM */
+ if (unlikely(boundary))
+ this->write_word(0x8000, this->base + ONENAND_REG_START_ADDRESS2);
+ ONENAND_SET_NEXT_BUFFERRAM(this);
+ buf += thislen;
+ thislen = min_t(int, mtd->writesize, len - read);
+ column = 0;
+ cond_resched();
+ /* Now wait for load */
+ ret = this->wait(mtd, FL_READING);
+ onenand_update_bufferram(mtd, from, !ret);
+ }
-out:
/* Deselect and wake up anyone waiting on the device */
onenand_release_device(mtd);
@@ -668,7 +790,14 @@ out:
* retlen == desired len and result == -EBADMSG
*/
*retlen = read;
- return ret;
+
+ if (mtd->ecc_stats.failed - stats.failed)
+ return -EBADMSG;
+
+ if (ret)
+ return ret;
+
+ return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
}
/**
@@ -705,6 +834,8 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
column = from & (mtd->oobsize - 1);
while (read < len) {
+ cond_resched();
+
thislen = mtd->oobsize - column;
thislen = min_t(int, thislen, len);
@@ -717,16 +848,16 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
+ if (ret) {
+ DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = 0x%x\n", ret);
+ goto out;
+ }
+
read += thislen;
if (read == len)
break;
- if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = %d\n", ret);
- goto out;
- }
-
buf += thislen;
/* Read more? */
@@ -756,8 +887,8 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
{
BUG_ON(ops->mode != MTD_OOB_PLACE);
- return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->len,
- &ops->retlen, ops->oobbuf);
+ return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen,
+ &ops->oobretlen, ops->oobbuf);
}
#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
@@ -804,6 +935,10 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
void __iomem *dataram0, *dataram1;
int ret = 0;
+ /* In partial page write, just skip it */
+ if ((addr & (mtd->writesize - 1)) != 0)
+ return 0;
+
this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);
ret = this->wait(mtd, FL_READING);
@@ -826,7 +961,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
#define onenand_verify_oob(...) (0)
#endif
-#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0)
+#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
/**
* onenand_write - [MTD Interface] write buffer to FLASH
@@ -844,6 +979,7 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
struct onenand_chip *this = mtd->priv;
int written = 0;
int ret = 0;
+ int column, subpage;
DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
@@ -862,45 +998,63 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
return -EINVAL;
}
+ column = to & (mtd->writesize - 1);
+ subpage = column || (len & (mtd->writesize - 1));
+
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_WRITING);
/* Loop until all data write */
while (written < len) {
- int thislen = min_t(int, mtd->writesize, len - written);
-
- this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize);
+ int bytes = mtd->writesize;
+ int thislen = min_t(int, bytes, len - written);
+ u_char *wbuf = (u_char *) buf;
+
+ cond_resched();
+
+ this->command(mtd, ONENAND_CMD_BUFFERRAM, to, bytes);
+
+ /* Partial page write */
+ if (subpage) {
+ bytes = min_t(int, bytes - column, (int) len);
+ memset(this->page_buf, 0xff, mtd->writesize);
+ memcpy(this->page_buf + column, buf, bytes);
+ wbuf = this->page_buf;
+ /* Even though partial write, we need page size */
+ thislen = mtd->writesize;
+ }
- this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen);
+ this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, thislen);
this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
- onenand_update_bufferram(mtd, to, 1);
+ /* In partial page write we don't update bufferram */
+ onenand_update_bufferram(mtd, to, !subpage);
ret = this->wait(mtd, FL_WRITING);
if (ret) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret);
- goto out;
+ break;
}
- written += thislen;
-
/* Only check verify write turn on */
- ret = onenand_verify_page(mtd, (u_char *) buf, to);
+ ret = onenand_verify_page(mtd, (u_char *) wbuf, to);
if (ret) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret);
- goto out;
+ break;
}
+ written += thislen;
+
if (written == len)
break;
+ column = 0;
to += thislen;
buf += thislen;
}
-out:
/* Deselect and wake up anyone waiting on the device */
onenand_release_device(mtd);
@@ -944,6 +1098,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
while (written < len) {
int thislen = min_t(int, mtd->oobsize, len - written);
+ cond_resched();
+
column = to & (mtd->oobsize - 1);
this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
@@ -999,8 +1155,8 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
{
BUG_ON(ops->mode != MTD_OOB_PLACE);
- return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->len,
- &ops->retlen, ops->oobbuf);
+ return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen,
+ &ops->oobretlen, ops->oobbuf);
}
/**
@@ -1071,6 +1227,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
instr->state = MTD_ERASING;
while (len) {
+ cond_resched();
/* Check if we have a bad block, we do not erase bad blocks */
if (onenand_block_checkbad(mtd, addr, 0, 0)) {
@@ -1084,10 +1241,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
ret = this->wait(mtd, FL_ERASING);
/* Check, if it is write protected */
if (ret) {
- if (ret == -EPERM)
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Device is write protected!!!\n");
- else
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift));
+ DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift));
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = addr;
goto erase_exit;
@@ -1129,7 +1283,6 @@ static void onenand_sync(struct mtd_info *mtd)
onenand_release_device(mtd);
}
-
/**
* onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
* @param mtd MTD device structure
@@ -1196,32 +1349,38 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
}
/**
- * onenand_unlock - [MTD Interface] Unlock block(s)
+ * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s)
* @param mtd MTD device structure
* @param ofs offset relative to mtd start
- * @param len number of bytes to unlock
+ * @param len number of bytes to lock or unlock
*
- * Unlock one or more blocks
+ * Lock or unlock one or more blocks
*/
-static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd)
{
struct onenand_chip *this = mtd->priv;
int start, end, block, value, status;
+ int wp_status_mask;
start = ofs >> this->erase_shift;
end = len >> this->erase_shift;
+ if (cmd == ONENAND_CMD_LOCK)
+ wp_status_mask = ONENAND_WP_LS;
+ else
+ wp_status_mask = ONENAND_WP_US;
+
/* Continuous lock scheme */
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(start + end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
- /* Write unlock command */
- this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
+ /* Write lock command */
+ this->command(mtd, cmd, 0, 0);
/* There's no return value */
- this->wait(mtd, FL_UNLOCKING);
+ this->wait(mtd, FL_LOCKING);
/* Sanity check */
while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
@@ -1230,7 +1389,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
/* Check lock status */
status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
- if (!(status & ONENAND_WP_US))
+ if (!(status & wp_status_mask))
printk(KERN_ERR "wp status = 0x%x\n", status);
return 0;
@@ -1246,11 +1405,11 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
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);
- /* Write unlock command */
- this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
+ /* Write lock command */
+ this->command(mtd, cmd, 0, 0);
/* There's no return value */
- this->wait(mtd, FL_UNLOCKING);
+ this->wait(mtd, FL_LOCKING);
/* Sanity check */
while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
@@ -1259,7 +1418,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
/* Check lock status */
status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
- if (!(status & ONENAND_WP_US))
+ if (!(status & wp_status_mask))
printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
}
@@ -1267,6 +1426,32 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
}
/**
+ * onenand_lock - [MTD Interface] Lock block(s)
+ * @param mtd MTD device structure
+ * @param ofs offset relative to mtd start
+ * @param len number of bytes to unlock
+ *
+ * Lock one or more blocks
+ */
+static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
+}
+
+/**
+ * onenand_unlock - [MTD Interface] Unlock block(s)
+ * @param mtd MTD device structure
+ * @param ofs offset relative to mtd start
+ * @param len number of bytes to unlock
+ *
+ * Unlock one or more blocks
+ */
+static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+}
+
+/**
* onenand_check_lock_status - [OneNAND Interface] Check lock status
* @param this onenand chip data structure
*
@@ -1310,7 +1495,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
/* There's no return value */
- this->wait(mtd, FL_UNLOCKING);
+ this->wait(mtd, FL_LOCKING);
/* Sanity check */
while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
@@ -1334,7 +1519,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
return 0;
}
- mtd->unlock(mtd, 0x0, this->chipsize);
+ onenand_unlock(mtd, 0x0, this->chipsize);
return 0;
}
@@ -1762,7 +1947,7 @@ static int onenand_probe(struct mtd_info *mtd)
/* 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);
+ 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)
@@ -1846,7 +2031,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
if (!this->command)
this->command = onenand_command;
if (!this->wait)
- this->wait = onenand_wait;
+ onenand_setup_wait(mtd);
if (!this->read_bufferram)
this->read_bufferram = onenand_read_bufferram;
@@ -1883,23 +2068,30 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
init_waitqueue_head(&this->wq);
spin_lock_init(&this->chip_lock);
+ /*
+ * Allow subpage writes up to oobsize.
+ */
switch (mtd->oobsize) {
case 64:
this->ecclayout = &onenand_oob_64;
+ mtd->subpage_sft = 2;
break;
case 32:
this->ecclayout = &onenand_oob_32;
+ mtd->subpage_sft = 1;
break;
default:
printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n",
mtd->oobsize);
+ mtd->subpage_sft = 0;
/* To prevent kernel oops */
this->ecclayout = &onenand_oob_32;
break;
}
+ this->subpagesize = mtd->writesize >> mtd->subpage_sft;
mtd->ecclayout = this->ecclayout;
/* Fill in remaining MTD driver data */
@@ -1922,7 +2114,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd->lock_user_prot_reg = onenand_lock_user_prot_reg;
#endif
mtd->sync = onenand_sync;
- mtd->lock = NULL;
+ mtd->lock = onenand_lock;
mtd->unlock = onenand_unlock;
mtd->suspend = onenand_suspend;
mtd->resume = onenand_resume;
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index 1b00dac3d7d..98f8fd1c637 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -93,13 +93,15 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs,
readlen, &retlen, &buf[0]);
- if (ret)
+ /* If it is a initial bad block, just ignore it */
+ if (ret && !(ret & ONENAND_CTRL_LOAD))
return ret;
if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
i >> 1, (unsigned int) from);
+ mtd->ecc_stats.badblocks++;
break;
}
}
@@ -177,14 +179,12 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
int len, ret = 0;
len = mtd->size >> (this->erase_shift + 2);
- /* Allocate memory (2bit per block) */
- bbm->bbt = kmalloc(len, GFP_KERNEL);
+ /* Allocate memory (2bit per block) and clear the memory bad block table */
+ bbm->bbt = kzalloc(len, GFP_KERNEL);
if (!bbm->bbt) {
printk(KERN_ERR "onenand_scan_bbt: Out of memory\n");
return -ENOMEM;
}
- /* Clear the memory bad block table */
- memset(bbm->bbt, 0x00, len);
/* Set the bad block position */
bbm->badblockpos = ONENAND_BADBLOCK_POS;
@@ -230,14 +230,12 @@ int onenand_default_bbt(struct mtd_info *mtd)
struct onenand_chip *this = mtd->priv;
struct bbm_info *bbm;
- this->bbm = kmalloc(sizeof(struct bbm_info), GFP_KERNEL);
+ this->bbm = kzalloc(sizeof(struct bbm_info), GFP_KERNEL);
if (!this->bbm)
return -ENOMEM;
bbm = this->bbm;
- memset(bbm, 0, sizeof(struct bbm_info));
-
/* 1KB page has same configuration as 2KB page */
if (!bbm->badblock_pattern)
bbm->badblock_pattern = &largepage_memorybased;
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
index 5b58523e4d4..035cd9b0cc0 100644
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -96,7 +96,19 @@ static int parse_redboot_partitions(struct mtd_info *master,
*/
if (swab32(buf[i].size) == master->erasesize) {
int j;
- for (j = 0; j < numslots && buf[j].name[0] != 0xff; ++j) {
+ for (j = 0; j < numslots; ++j) {
+
+ /* A single 0xff denotes a deleted entry.
+ * Two of them in a row is the end of the table.
+ */
+ if (buf[j].name[0] == 0xff) {
+ if (buf[j].name[1] == 0xff) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
/* The unsigned long fields were written with the
* wrong byte sex, name and pad have no byte sex.
*/
@@ -110,6 +122,9 @@ static int parse_redboot_partitions(struct mtd_info *master,
}
}
break;
+ } else {
+ /* re-calculate of real numslots */
+ numslots = buf[i].size / sizeof(struct fis_image_desc);
}
}
if (i == numslots) {
@@ -123,8 +138,13 @@ static int parse_redboot_partitions(struct mtd_info *master,
for (i = 0; i < numslots; i++) {
struct fis_list *new_fl, **prev;
- if (buf[i].name[0] == 0xff)
- continue;
+ if (buf[i].name[0] == 0xff) {
+ if (buf[i].name[1] == 0xff) {
+ break;
+ } else {
+ continue;
+ }
+ }
if (!redboot_checksum(&buf[i]))
break;
@@ -165,15 +185,13 @@ static int parse_redboot_partitions(struct mtd_info *master,
}
}
#endif
- parts = kmalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
+ parts = kzalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
if (!parts) {
ret = -ENOMEM;
goto out;
}
- memset(parts, 0, sizeof(*parts)*nrparts + nulllen + namelen);
-
nullname = (char *)&parts[nrparts];
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
if (nulllen > 0) {
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index fa4362fb4dd..d4b1ba8f23e 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -768,7 +768,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
if (mtd->type != MTD_NORFLASH)
return;
- part = kcalloc(1, sizeof(struct partition), GFP_KERNEL);
+ part = kzalloc(sizeof(struct partition), GFP_KERNEL);
if (!part)
return;
@@ -787,7 +787,6 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
if (scan_header(part) == 0) {
part->mbd.size = part->sector_count;
- part->mbd.blksize = SECTOR_SIZE;
part->mbd.tr = tr;
part->mbd.devnum = -1;
if (!(mtd->flags & MTD_WRITEABLE))
@@ -829,6 +828,8 @@ struct mtd_blktrans_ops rfd_ftl_tr = {
.name = "rfd",
.major = RFD_FTL_MAJOR,
.part_bits = PART_BITS,
+ .blksize = SECTOR_SIZE,
+
.readsect = rfd_ftl_readsect,
.writesect = rfd_ftl_writesect,
.getgeo = rfd_ftl_getgeo,
diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c
index 79d3bb659bf..a5f3d60047d 100644
--- a/drivers/mtd/ssfdc.c
+++ b/drivers/mtd/ssfdc.c
@@ -172,13 +172,12 @@ static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf)
ops.mode = MTD_OOB_RAW;
ops.ooboffs = 0;
- ops.ooblen = mtd->oobsize;
- ops.len = OOB_SIZE;
+ ops.ooblen = OOB_SIZE;
ops.oobbuf = buf;
ops.datbuf = NULL;
ret = mtd->read_oob(mtd, offs, &ops);
- if (ret < 0 || ops.retlen != OOB_SIZE)
+ if (ret < 0 || ops.oobretlen != OOB_SIZE)
return -1;
return 0;
@@ -312,7 +311,6 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
ssfdc->mbd.mtd = mtd;
ssfdc->mbd.devnum = -1;
- ssfdc->mbd.blksize = SECTOR_SIZE;
ssfdc->mbd.tr = tr;
ssfdc->mbd.readonly = 1;
@@ -447,6 +445,7 @@ static struct mtd_blktrans_ops ssfdcr_tr = {
.name = "ssfdc",
.major = SSFDCR_MAJOR,
.part_bits = SSFDCR_PARTN_BITS,
+ .blksize = SECTOR_SIZE,
.getgeo = ssfdcr_getgeo,
.readsect = ssfdcr_readsect,
.add_mtd = ssfdcr_add_mtd,
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 7e34c4f07b7..bc7e906571d 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -600,8 +600,7 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
count -= semi_count;
memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, base + ring_offset, count, 0);
+ memcpy_fromio(skb->data, base + ring_offset, count);
}
return;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 80bdcf84623..716a47210aa 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -792,8 +792,7 @@ static void poll_vortex(struct net_device *dev)
{
struct vortex_private *vp = netdev_priv(dev);
unsigned long flags;
- local_save_flags(flags);
- local_irq_disable();
+ local_irq_save(flags);
(vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev);
local_irq_restore(flags);
}
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index 7733697f777..2d5ba076471 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -500,7 +500,7 @@ int lance_open (struct net_device *dev)
int res;
/* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
- if (request_irq(lp->irq, lance_interrupt, 0, lp->name, dev))
+ if (request_irq(lp->irq, lance_interrupt, SA_SHIRQ, lp->name, dev))
return -EAGAIN;
res = lance_reset(dev);
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 458dd9f830c..6f93a765e56 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -617,13 +617,15 @@ rx_next:
* this round of polling
*/
if (rx_work) {
+ unsigned long flags;
+
if (cpr16(IntrStatus) & cp_rx_intr_mask)
goto rx_status_loop;
- local_irq_disable();
+ local_irq_save(flags);
cpw16_f(IntrMask, cp_intr_mask);
__netif_rx_complete(dev);
- local_irq_enable();
+ local_irq_restore(flags);
return 0; /* done */
}
@@ -763,17 +765,18 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
struct cp_private *cp = netdev_priv(dev);
unsigned entry;
u32 eor, flags;
+ unsigned long intr_flags;
#if CP_VLAN_TAG_USED
u32 vlan_tag = 0;
#endif
int mss = 0;
- spin_lock_irq(&cp->lock);
+ spin_lock_irqsave(&cp->lock, intr_flags);
/* This is a hard error, log it. */
if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
- spin_unlock_irq(&cp->lock);
+ spin_unlock_irqrestore(&cp->lock, intr_flags);
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
dev->name);
return 1;
@@ -906,7 +909,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
- spin_unlock_irq(&cp->lock);
+ spin_unlock_irqrestore(&cp->lock, intr_flags);
cpw8(TxPoll, NormalTxPoll);
dev->trans_start = jiffies;
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 931028f672d..35ad5cff18e 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -2131,14 +2131,15 @@ static int rtl8139_poll(struct net_device *dev, int *budget)
}
if (done) {
+ unsigned long flags;
/*
* Order is important since data can get interrupted
* again when we think we are done.
*/
- local_irq_disable();
+ local_irq_save(flags);
RTL_W16_F(IntrMask, rtl8139_intr_mask);
__netif_rx_complete(dev);
- local_irq_enable();
+ local_irq_restore(flags);
}
spin_unlock(&tp->rx_lock);
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 8236f26ffd4..640d7ca2ebc 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -1066,8 +1066,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
short length = skb->len;
dev->trans_start = jiffies;
- DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%x) called\n", dev->name,
- skb->len, (unsigned int)skb->data));
+ DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%p) called\n",
+ dev->name, skb->len, skb->data));
if (skb->len < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
@@ -1246,7 +1246,8 @@ struct net_device * __init i82596_probe(int unit)
dev->priv = (void *)(dev->mem_start);
lp = dev->priv;
- DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
+ DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%zd bytes), "
+ "lp->scb at 0x%08lx\n",
dev->name, (unsigned long)lp,
sizeof(struct i596_private), (unsigned long)&lp->scb));
memset((void *) lp, 0, sizeof(struct i596_private));
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 9de0eed6755..38f41a593b1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -190,7 +190,7 @@ config MII
config MACB
tristate "Atmel MACB support"
- depends on NET_ETHERNET && AVR32
+ depends on NET_ETHERNET && (AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263)
select MII
help
The Atmel MACB ethernet interface is found on many AT32 and AT91
@@ -235,16 +235,6 @@ config BMAC
To compile this driver as a module, choose M here: the module
will be called bmac.
-config OAKNET
- tristate "National DP83902AV (Oak ethernet) support"
- depends on NET_ETHERNET && PPC && BROKEN
- select CRC32
- help
- Say Y if your machine has this type of Ethernet network card.
-
- To compile this driver as a module, choose M here: the module
- will be called oaknet.
-
config ARIADNE
tristate "Ariadne support"
depends on NET_ETHERNET && ZORRO
@@ -1155,21 +1145,6 @@ config SEEQ8005
<file:Documentation/networking/net-modules.txt>. The module
will be called seeq8005.
-config SKMC
- tristate "SKnet MCA support"
- depends on NET_ETHERNET && MCA && BROKEN
- ---help---
- These are Micro Channel Ethernet adapters. You need to say Y to "MCA
- support" in order to use this driver. Supported cards are the SKnet
- Junior MC2 and the SKnet MC2(+). The driver automatically
- distinguishes between the two cards. Note that using multiple boards
- of different type hasn't been tested with this driver. Say Y if you
- have one of these Ethernet adapters.
-
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
- will be called sk_mca.
-
config NE2_MCA
tristate "NE/2 (ne2000 MCA version) support"
depends on NET_ETHERNET && MCA_LEGACY
@@ -1788,6 +1763,18 @@ config LAN_SAA9730
workstations.
See <http://www.semiconductors.philips.com/pip/SAA9730_flyer_1>.
+config SC92031
+ tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)"
+ depends on NET_PCI && PCI && EXPERIMENTAL
+ select CRC32
+ ---help---
+ This is a driver for the Fast Ethernet PCI network cards based on
+ the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you
+ have one of these, say Y here.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sc92031. This is recommended.
+
config NET_POCKET
bool "Pocket and portable adapters"
depends on NET_ETHERNET && PARPORT
@@ -2348,6 +2335,17 @@ config QLA3XXX
To compile this driver as a module, choose M here: the module
will be called qla3xxx.
+config ATL1
+ tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)"
+ depends on NET_PCI && PCI && EXPERIMENTAL
+ select CRC32
+ select MII
+ help
+ This driver supports the Attansic L1 gigabit ethernet adapter.
+
+ To compile this driver as a module, choose M here. The module
+ will be called atl1.
+
endmenu
#
@@ -2384,6 +2382,32 @@ config CHELSIO_T1_1G
Enables support for Chelsio's gigabit Ethernet PCI cards. If you
are using only 10G cards say 'N' here.
+config CHELSIO_T1_NAPI
+ bool "Use Rx Polling (NAPI)"
+ depends on CHELSIO_T1
+ default y
+ help
+ NAPI is a driver API designed to reduce CPU and interrupt load
+ when the driver is receiving lots of packets from the card.
+
+config CHELSIO_T3
+ tristate "Chelsio Communications T3 10Gb Ethernet support"
+ depends on PCI
+ help
+ This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
+ adapters.
+
+ For general information about Chelsio and our products, visit
+ our website at <http://www.chelsio.com>.
+
+ For customer support, please visit our customer support page at
+ <http://www.chelsio.com/support.htm>.
+
+ Please send feedback to <linux-bugs@chelsio.com>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called cxgb3.
+
config EHEA
tristate "eHEA Ethernet support"
depends on IBMEBUS
@@ -2480,6 +2504,13 @@ config NETXEN_NIC
help
This enables the support for NetXen's Gigabit Ethernet card.
+config PASEMI_MAC
+ tristate "PA Semi 1/10Gbit MAC"
+ depends on PPC64 && PCI
+ help
+ This driver supports the on-chip 1/10Gbit Ethernet controller on
+ PA Semi's PWRficient line of chips.
+
endmenu
source "drivers/net/tokenring/Kconfig"
@@ -2514,7 +2545,7 @@ config RIONET_RX_SIZE
config FDDI
bool "FDDI driver support"
- depends on (PCI || EISA)
+ depends on (PCI || EISA || TC)
help
Fiber Distributed Data Interface is a high speed local area network
design; essentially a replacement for high speed Ethernet. FDDI can
@@ -2524,15 +2555,36 @@ config FDDI
will say N.
config DEFXX
- tristate "Digital DEFEA and DEFPA adapter support"
- depends on FDDI && (PCI || EISA)
- help
- This is support for the DIGITAL series of EISA (DEFEA) and PCI
- (DEFPA) controllers which can connect you to a local FDDI network.
+ tristate "Digital DEFTA/DEFEA/DEFPA adapter support"
+ depends on FDDI && (PCI || EISA || TC)
+ ---help---
+ This is support for the DIGITAL series of TURBOchannel (DEFTA),
+ EISA (DEFEA) and PCI (DEFPA) controllers which can connect you
+ to a local FDDI network.
+
+ To compile this driver as a module, choose M here: the module
+ will be called defxx. If unsure, say N.
+
+config DEFXX_MMIO
+ bool
+ prompt "Use MMIO instead of PIO" if PCI || EISA
+ depends on DEFXX
+ default n if PCI || EISA
+ default y
+ ---help---
+ This instructs the driver to use EISA or PCI memory-mapped I/O
+ (MMIO) as appropriate instead of programmed I/O ports (PIO).
+ Enabling this gives an improvement in processing time in parts
+ of the driver, but it may cause problems with EISA (DEFEA)
+ adapters. TURBOchannel does not have the concept of I/O ports,
+ so MMIO is always used for these (DEFTA) adapters.
+
+ If unsure, say N.
config SKFP
tristate "SysKonnect FDDI PCI support"
depends on FDDI && PCI
+ select BITREVERSE
---help---
Say Y here if you have a SysKonnect FDDI PCI adapter.
The following adapters are supported by this driver:
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 4c0d4e5ce42..33af833667d 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -6,8 +6,10 @@ obj-$(CONFIG_E1000) += e1000/
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
obj-$(CONFIG_IXGB) += ixgb/
obj-$(CONFIG_CHELSIO_T1) += chelsio/
+obj-$(CONFIG_CHELSIO_T3) += cxgb3/
obj-$(CONFIG_EHEA) += ehea/
obj-$(CONFIG_BONDING) += bonding/
+obj-$(CONFIG_ATL1) += atl1/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
gianfar_driver-objs := gianfar.o \
@@ -36,8 +38,6 @@ obj-$(CONFIG_CASSINI) += cassini.o
obj-$(CONFIG_MACE) += mace.o
obj-$(CONFIG_BMAC) += bmac.o
-obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
-
obj-$(CONFIG_DGRS) += dgrs.o
obj-$(CONFIG_VORTEX) += 3c59x.o
obj-$(CONFIG_TYPHOON) += typhoon.o
@@ -137,7 +137,6 @@ obj-$(CONFIG_AT1700) += at1700.o
obj-$(CONFIG_EL1) += 3c501.o
obj-$(CONFIG_EL16) += 3c507.o
obj-$(CONFIG_ELMC) += 3c523.o
-obj-$(CONFIG_SKMC) += sk_mca.o
obj-$(CONFIG_IBMLANA) += ibmlana.o
obj-$(CONFIG_ELMC_II) += 3c527.o
obj-$(CONFIG_EL3) += 3c509.o
@@ -160,6 +159,7 @@ obj-$(CONFIG_APRICOT) += 82596.o
obj-$(CONFIG_LASI_82596) += lasi_82596.o
obj-$(CONFIG_MVME16x_NET) += 82596.o
obj-$(CONFIG_BVME6000_NET) += 82596.o
+obj-$(CONFIG_SC92031) += sc92031.o
# This is also a 82596 and should probably be merged
obj-$(CONFIG_LP486E) += lp486e.o
@@ -196,6 +196,7 @@ obj-$(CONFIG_SMC91X) += smc91x.o
obj-$(CONFIG_SMC911X) += smc911x.o
obj-$(CONFIG_DM9000) += dm9000.o
obj-$(CONFIG_FEC_8XX) += fec_8xx/
+obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
obj-$(CONFIG_MACB) += macb.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 602ed31a5dd..dd8ed456c8b 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -59,7 +59,6 @@ extern struct net_device *wavelan_probe(int unit);
extern struct net_device *arlan_probe(int unit);
extern struct net_device *el16_probe(int unit);
extern struct net_device *elmc_probe(int unit);
-extern struct net_device *skmca_probe(int unit);
extern struct net_device *elplus_probe(int unit);
extern struct net_device *ac3200_probe(int unit);
extern struct net_device *es_probe(int unit);
@@ -153,9 +152,6 @@ static struct devprobe2 mca_probes[] __initdata = {
#ifdef CONFIG_ELMC_II /* 3c527 */
{mc32_probe, 0},
#endif
-#ifdef CONFIG_SKMC /* SKnet Microchannel */
- {skmca_probe, 0},
-#endif
{NULL, 0},
};
@@ -349,22 +345,11 @@ static void __init trif_probe2(int unit)
#endif
-/*
- * The loopback device is global so it can be directly referenced
- * by the network code. Also, it must be first on device list.
- */
-extern int loopback_init(void);
-
/* Statically configured drivers -- order matters here. */
static int __init net_olddevs_init(void)
{
int num;
- if (loopback_init()) {
- printk(KERN_ERR "Network loopback device setup failed\n");
- }
-
-
#ifdef CONFIG_SBNI
for (num = 0; num < 8; ++num)
sbni_probe(num);
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index c01f87f5bed..644c408515d 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -327,8 +327,7 @@ static void ac_block_input(struct net_device *dev, int count, struct sk_buff *sk
memcpy_fromio(skb->data + semi_count,
ei_status.mem + TX_PAGES*256, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, start, count, 0);
+ memcpy_fromio(skb->data, start, count);
}
}
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 18896f24d40..9c399aaefbd 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1334,8 +1334,7 @@ err_no_interrupt:
static void amd8111e_poll(struct net_device *dev)
{
unsigned long flags;
- local_save_flags(flags);
- local_irq_disable();
+ local_irq_save(flags);
amd8111e_interrupt(0, dev);
local_irq_restore(flags);
}
diff --git a/drivers/net/apne.c b/drivers/net/apne.c
index d4e40816907..954191119d3 100644
--- a/drivers/net/apne.c
+++ b/drivers/net/apne.c
@@ -311,9 +311,10 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
#endif
dev->base_addr = ioaddr;
+ dev->irq = IRQ_AMIGA_PORTS;
/* Install the Interrupt handler */
- i = request_irq(IRQ_AMIGA_PORTS, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
+ i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
if (i) return i;
for(i = 0; i < ETHER_ADDR_LEN; i++) {
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index b98592a8bac..f22e46dfd77 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -186,7 +186,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
*/
static int ipddp_create(struct ipddp_route *new_rt)
{
- struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL);
+ struct ipddp_route *rt = kmalloc(sizeof(*rt), GFP_KERNEL);
if (rt == NULL)
return -ENOMEM;
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index fada15d959d..1621b8fe35c 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -641,7 +641,7 @@ static void at91ether_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo
{
strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
- strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+ strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
}
static const struct ethtool_ops at91ether_ethtool_ops = {
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index 8ebd68e2af9..dd698b033a6 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -780,12 +780,10 @@ static struct ethtool_ops ep93xx_ethtool_ops = {
struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data)
{
struct net_device *dev;
- struct ep93xx_priv *ep;
dev = alloc_etherdev(sizeof(struct ep93xx_priv));
if (dev == NULL)
return NULL;
- ep = netdev_priv(dev);
memcpy(dev->dev_addr, data->dev_addr, ETH_ALEN);
@@ -840,9 +838,9 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
struct ep93xx_priv *ep;
int err;
- data = pdev->dev.platform_data;
if (pdev == NULL)
return -ENODEV;
+ data = pdev->dev.platform_data;
dev = ep93xx_dev_alloc(data);
if (dev == NULL) {
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index f3faa4fe58e..72c41f5907f 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -587,7 +587,7 @@ static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
{
strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
- strlcpy(info->bus_info, dev->class_dev.dev->bus_id,
+ strlcpy(info->bus_info, dev->dev.parent->bus_id,
sizeof(info->bus_info));
}
diff --git a/drivers/net/atl1/Makefile b/drivers/net/atl1/Makefile
new file mode 100644
index 00000000000..a6b707e4e69
--- /dev/null
+++ b/drivers/net/atl1/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ATL1) += atl1.o
+atl1-y += atl1_main.o atl1_hw.o atl1_ethtool.o atl1_param.o
diff --git a/drivers/net/atl1/atl1.h b/drivers/net/atl1/atl1.h
new file mode 100644
index 00000000000..b1c6034e68f
--- /dev/null
+++ b/drivers/net/atl1/atl1.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 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
+ * 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 _ATL1_H_
+#define _ATL1_H_
+
+#include <linux/types.h>
+#include <linux/if_vlan.h>
+
+#include "atl1_hw.h"
+
+/* function prototypes needed by multiple files */
+s32 atl1_up(struct atl1_adapter *adapter);
+void atl1_down(struct atl1_adapter *adapter);
+int atl1_reset(struct atl1_adapter *adapter);
+s32 atl1_setup_ring_resources(struct atl1_adapter *adapter);
+void atl1_free_ring_resources(struct atl1_adapter *adapter);
+
+extern char atl1_driver_name[];
+extern char atl1_driver_version[];
+extern const struct ethtool_ops atl1_ethtool_ops;
+
+struct atl1_adapter;
+
+#define ATL1_MAX_INTR 3
+
+#define ATL1_DEFAULT_TPD 256
+#define ATL1_MAX_TPD 1024
+#define ATL1_MIN_TPD 64
+#define ATL1_DEFAULT_RFD 512
+#define ATL1_MIN_RFD 128
+#define ATL1_MAX_RFD 2048
+
+#define ATL1_GET_DESC(R, i, type) (&(((type *)((R)->desc))[i]))
+#define ATL1_RFD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_free_desc)
+#define ATL1_TPD_DESC(R, i) ATL1_GET_DESC(R, i, struct tx_packet_desc)
+#define ATL1_RRD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_return_desc)
+
+/*
+ * Some workarounds require millisecond delays and are run during interrupt
+ * context. Most notably, when establishing link, the phy may need tweaking
+ * but cannot process phy register reads/writes faster than millisecond
+ * intervals...and we establish link due to a "link status change" interrupt.
+ */
+
+/*
+ * wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct atl1_buffer {
+ struct sk_buff *skb;
+ u16 length;
+ u16 alloced;
+ dma_addr_t dma;
+};
+
+#define MAX_TX_BUF_LEN 0x3000 /* 12KB */
+
+struct atl1_tpd_ring {
+ void *desc; /* pointer to the descriptor ring memory */
+ dma_addr_t dma; /* physical adress of the descriptor ring */
+ u16 size; /* length of descriptor ring in bytes */
+ u16 count; /* number of descriptors in the ring */
+ u16 hw_idx; /* hardware index */
+ atomic_t next_to_clean;
+ atomic_t next_to_use;
+ struct atl1_buffer *buffer_info;
+};
+
+struct atl1_rfd_ring {
+ void *desc;
+ dma_addr_t dma;
+ u16 size;
+ u16 count;
+ atomic_t next_to_use;
+ u16 next_to_clean;
+ struct atl1_buffer *buffer_info;
+};
+
+struct atl1_rrd_ring {
+ void *desc;
+ dma_addr_t dma;
+ unsigned int size;
+ u16 count;
+ u16 next_to_use;
+ atomic_t next_to_clean;
+};
+
+struct atl1_ring_header {
+ void *desc; /* pointer to the descriptor ring memory */
+ dma_addr_t dma; /* physical adress of the descriptor ring */
+ unsigned int size; /* length of descriptor ring in bytes */
+};
+
+struct atl1_cmb {
+ struct coals_msg_block *cmb;
+ dma_addr_t dma;
+};
+
+struct atl1_smb {
+ struct stats_msg_block *smb;
+ dma_addr_t dma;
+};
+
+/* Statistics counters */
+struct atl1_sft_stats {
+ u64 rx_packets;
+ u64 tx_packets;
+ u64 rx_bytes;
+ u64 tx_bytes;
+ u64 multicast;
+ u64 collisions;
+ u64 rx_errors;
+ u64 rx_length_errors;
+ u64 rx_crc_errors;
+ u64 rx_frame_errors;
+ u64 rx_fifo_errors;
+ u64 rx_missed_errors;
+ u64 tx_errors;
+ u64 tx_fifo_errors;
+ u64 tx_aborted_errors;
+ u64 tx_window_errors;
+ u64 tx_carrier_errors;
+
+ u64 tx_pause; /* num Pause packet transmitted. */
+ u64 excecol; /* num tx packets aborted due to excessive collisions. */
+ u64 deffer; /* num deferred tx packets */
+ u64 scc; /* num packets subsequently transmitted successfully w/ single prior collision. */
+ u64 mcc; /* num packets subsequently transmitted successfully w/ multiple prior collisions. */
+ u64 latecol; /* num tx packets w/ late collisions. */
+ u64 tx_underun; /* num tx packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
+ u64 tx_trunc; /* num tx packets truncated due to size exceeding MTU, regardless whether truncated by Selene or not. (The name doesn't really reflect the meaning in this case.) */
+ u64 rx_pause; /* num Pause packets received. */
+ u64 rx_rrd_ov;
+ u64 rx_trunc;
+};
+
+/* board specific private data structure */
+#define ATL1_REGS_LEN 8
+
+/* Structure containing variables used by the shared code */
+struct atl1_hw {
+ u8 __iomem *hw_addr;
+ struct atl1_adapter *back;
+ enum atl1_dma_order dma_ord;
+ enum atl1_dma_rcb rcb_value;
+ enum atl1_dma_req_block dmar_block;
+ enum atl1_dma_req_block dmaw_block;
+ u8 preamble_len;
+ u8 max_retry; /* Retransmission maximum, after which the packet will be discarded */
+ u8 jam_ipg; /* IPG to start JAM for collision based flow control in half-duplex mode. In units of 8-bit time */
+ u8 ipgt; /* Desired back to back inter-packet gap. The default is 96-bit time */
+ u8 min_ifg; /* Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped */
+ u8 ipgr1; /* 64bit Carrier-Sense window */
+ u8 ipgr2; /* 96-bit IPG window */
+ u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. Each TPD is 16 bytes long */
+ u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned burst. Each RFD is 12 bytes long */
+ u8 rfd_fetch_gap;
+ u8 rrd_burst; /* Threshold number of RRDs that can be retired in a burst. Each RRD is 16 bytes long */
+ u8 tpd_fetch_th;
+ u8 tpd_fetch_gap;
+ u16 tx_jumbo_task_th;
+ u16 txf_burst; /* Number of data bytes to read in a cache-aligned burst. Each SRAM entry is
+ 8 bytes long */
+ u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN packets should add 4 bytes */
+ u16 rx_jumbo_lkah;
+ u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after every 512ns passes. */
+ u16 lcol; /* Collision Window */
+
+ u16 cmb_tpd;
+ u16 cmb_rrd;
+ u16 cmb_rx_timer;
+ u16 cmb_tx_timer;
+ u32 smb_timer;
+ u16 media_type;
+ u16 autoneg_advertised;
+ u16 pci_cmd_word;
+
+ u16 mii_autoneg_adv_reg;
+ u16 mii_1000t_ctrl_reg;
+
+ u32 mem_rang;
+ u32 txcw;
+ u32 max_frame_size;
+ u32 min_frame_size;
+ u32 mc_filter_type;
+ u32 num_mc_addrs;
+ u32 collision_delta;
+ u32 tx_packet_delta;
+ u16 phy_spd_default;
+
+ u16 dev_rev;
+ u8 revision_id;
+
+ /* spi flash */
+ u8 flash_vendor;
+
+ u8 dma_fairness;
+ u8 mac_addr[ETH_ALEN];
+ u8 perm_mac_addr[ETH_ALEN];
+
+ /* bool phy_preamble_sup; */
+ bool phy_configured;
+};
+
+struct atl1_adapter {
+ /* OS defined structs */
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct net_device_stats net_stats;
+ struct atl1_sft_stats soft_stats;
+
+ struct vlan_group *vlgrp;
+ u32 rx_buffer_len;
+ u32 wol;
+ u16 link_speed;
+ u16 link_duplex;
+ spinlock_t lock;
+ atomic_t irq_sem;
+ struct work_struct tx_timeout_task;
+ struct work_struct link_chg_task;
+ struct work_struct pcie_dma_to_rst_task;
+ struct timer_list watchdog_timer;
+ struct timer_list phy_config_timer;
+ bool phy_timer_pending;
+
+ bool mac_disabled;
+
+ /* All descriptor rings' memory */
+ struct atl1_ring_header ring_header;
+
+ /* TX */
+ struct atl1_tpd_ring tpd_ring;
+ spinlock_t mb_lock;
+
+ /* RX */
+ struct atl1_rfd_ring rfd_ring;
+ struct atl1_rrd_ring rrd_ring;
+ u64 hw_csum_err;
+ u64 hw_csum_good;
+
+ u32 gorcl;
+ u64 gorcl_old;
+
+ /* Interrupt Moderator timer ( 2us resolution) */
+ u16 imt;
+ /* Interrupt Clear timer (2us resolution) */
+ u16 ict;
+
+ /* MII interface info */
+ struct mii_if_info mii;
+
+ /* structs defined in atl1_hw.h */
+ u32 bd_number; /* board number */
+ bool pci_using_64;
+ struct atl1_hw hw;
+ struct atl1_smb smb;
+ struct atl1_cmb cmb;
+
+ u32 pci_state[16];
+};
+
+#endif /* _ATL1_H_ */
diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c
new file mode 100644
index 00000000000..c11c27798e5
--- /dev/null
+++ b/drivers/net/atl1/atl1_ethtool.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 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
+ * 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/types.h>
+#include <linux/pci.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <asm/uaccess.h>
+
+#include "atl1.h"
+
+struct atl1_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define ATL1_STAT(m) sizeof(((struct atl1_adapter *)0)->m), \
+ offsetof(struct atl1_adapter, m)
+
+static struct atl1_stats atl1_gstrings_stats[] = {
+ {"rx_packets", ATL1_STAT(soft_stats.rx_packets)},
+ {"tx_packets", ATL1_STAT(soft_stats.tx_packets)},
+ {"rx_bytes", ATL1_STAT(soft_stats.rx_bytes)},
+ {"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)},
+ {"rx_errors", ATL1_STAT(soft_stats.rx_errors)},
+ {"tx_errors", ATL1_STAT(soft_stats.tx_errors)},
+ {"rx_dropped", ATL1_STAT(net_stats.rx_dropped)},
+ {"tx_dropped", ATL1_STAT(net_stats.tx_dropped)},
+ {"multicast", ATL1_STAT(soft_stats.multicast)},
+ {"collisions", ATL1_STAT(soft_stats.collisions)},
+ {"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)},
+ {"rx_over_errors", ATL1_STAT(soft_stats.rx_missed_errors)},
+ {"rx_crc_errors", ATL1_STAT(soft_stats.rx_crc_errors)},
+ {"rx_frame_errors", ATL1_STAT(soft_stats.rx_frame_errors)},
+ {"rx_fifo_errors", ATL1_STAT(soft_stats.rx_fifo_errors)},
+ {"rx_missed_errors", ATL1_STAT(soft_stats.rx_missed_errors)},
+ {"tx_aborted_errors", ATL1_STAT(soft_stats.tx_aborted_errors)},
+ {"tx_carrier_errors", ATL1_STAT(soft_stats.tx_carrier_errors)},
+ {"tx_fifo_errors", ATL1_STAT(soft_stats.tx_fifo_errors)},
+ {"tx_window_errors", ATL1_STAT(soft_stats.tx_window_errors)},
+ {"tx_abort_exce_coll", ATL1_STAT(soft_stats.excecol)},
+ {"tx_abort_late_coll", ATL1_STAT(soft_stats.latecol)},
+ {"tx_deferred_ok", ATL1_STAT(soft_stats.deffer)},
+ {"tx_single_coll_ok", ATL1_STAT(soft_stats.scc)},
+ {"tx_multi_coll_ok", ATL1_STAT(soft_stats.mcc)},
+ {"tx_underun", ATL1_STAT(soft_stats.tx_underun)},
+ {"tx_trunc", ATL1_STAT(soft_stats.tx_trunc)},
+ {"tx_pause", ATL1_STAT(soft_stats.tx_pause)},
+ {"rx_pause", ATL1_STAT(soft_stats.rx_pause)},
+ {"rx_rrd_ov", ATL1_STAT(soft_stats.rx_rrd_ov)},
+ {"rx_trunc", ATL1_STAT(soft_stats.rx_trunc)}
+};
+
+static void atl1_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int i;
+ char *p;
+
+ for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) {
+ p = (char *)adapter+atl1_gstrings_stats[i].stat_offset;
+ data[i] = (atl1_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+
+}
+
+static int atl1_get_stats_count(struct net_device *netdev)
+{
+ return ARRAY_SIZE(atl1_gstrings_stats);
+}
+
+static int atl1_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ ecmd->supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg | SUPPORTED_TP);
+ ecmd->advertising = ADVERTISED_TP;
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR) {
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ ecmd->advertising |=
+ (ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Full);
+ }
+ else
+ ecmd->advertising |= (ADVERTISED_1000baseT_Full);
+ }
+ ecmd->port = PORT_TP;
+ ecmd->phy_address = 0;
+ ecmd->transceiver = XCVR_INTERNAL;
+
+ if (netif_carrier_ok(adapter->netdev)) {
+ u16 link_speed, link_duplex;
+ atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex);
+ ecmd->speed = link_speed;
+ if (link_duplex == FULL_DUPLEX)
+ ecmd->duplex = DUPLEX_FULL;
+ else
+ ecmd->duplex = DUPLEX_HALF;
+ } else {
+ ecmd->speed = -1;
+ ecmd->duplex = -1;
+ }
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL)
+ ecmd->autoneg = AUTONEG_ENABLE;
+ else
+ ecmd->autoneg = AUTONEG_DISABLE;
+
+ return 0;
+}
+
+static int atl1_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+ u16 phy_data;
+ int ret_val = 0;
+ u16 old_media_type = hw->media_type;
+
+ if (netif_running(adapter->netdev)) {
+ printk(KERN_DEBUG "%s: ethtool shutting down adapter\n",
+ atl1_driver_name);
+ atl1_down(adapter);
+ }
+
+ if (ecmd->autoneg == AUTONEG_ENABLE)
+ hw->media_type = MEDIA_TYPE_AUTO_SENSOR;
+ else {
+ if (ecmd->speed == SPEED_1000) {
+ if (ecmd->duplex != DUPLEX_FULL) {
+ printk(KERN_WARNING
+ "%s: can't force to 1000M half duplex\n",
+ atl1_driver_name);
+ ret_val = -EINVAL;
+ goto exit_sset;
+ }
+ hw->media_type = MEDIA_TYPE_1000M_FULL;
+ } else if (ecmd->speed == SPEED_100) {
+ if (ecmd->duplex == DUPLEX_FULL) {
+ hw->media_type = MEDIA_TYPE_100M_FULL;
+ } else
+ hw->media_type = MEDIA_TYPE_100M_HALF;
+ } else {
+ if (ecmd->duplex == DUPLEX_FULL)
+ hw->media_type = MEDIA_TYPE_10M_FULL;
+ else
+ hw->media_type = MEDIA_TYPE_10M_HALF;
+ }
+ }
+ switch (hw->media_type) {
+ case MEDIA_TYPE_AUTO_SENSOR:
+ ecmd->advertising =
+ ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_Autoneg | ADVERTISED_TP;
+ break;
+ case MEDIA_TYPE_1000M_FULL:
+ ecmd->advertising =
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_Autoneg | ADVERTISED_TP;
+ break;
+ default:
+ ecmd->advertising = 0;
+ break;
+ }
+ if (atl1_phy_setup_autoneg_adv(hw)) {
+ ret_val = -EINVAL;
+ printk(KERN_WARNING
+ "%s: invalid ethtool speed/duplex setting\n",
+ atl1_driver_name);
+ goto exit_sset;
+ }
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL)
+ phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+ else {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+ MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF: */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ }
+ }
+ atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+exit_sset:
+ if (ret_val)
+ hw->media_type = old_media_type;
+
+ if (netif_running(adapter->netdev)) {
+ printk(KERN_DEBUG "%s: ethtool starting adapter\n",
+ atl1_driver_name);
+ atl1_up(adapter);
+ } else if (!ret_val) {
+ printk(KERN_DEBUG "%s: ethtool resetting adapter\n",
+ atl1_driver_name);
+ atl1_reset(adapter);
+ }
+ return ret_val;
+}
+
+static void atl1_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ strncpy(drvinfo->driver, atl1_driver_name, sizeof(drvinfo->driver));
+ strncpy(drvinfo->version, atl1_driver_version,
+ sizeof(drvinfo->version));
+ strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
+ sizeof(drvinfo->bus_info));
+ drvinfo->eedump_len = ATL1_EEDUMP_LEN;
+}
+
+static void atl1_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
+ wol->wolopts = 0;
+ if (adapter->wol & ATL1_WUFC_EX)
+ wol->wolopts |= WAKE_UCAST;
+ if (adapter->wol & ATL1_WUFC_MC)
+ wol->wolopts |= WAKE_MCAST;
+ if (adapter->wol & ATL1_WUFC_BC)
+ wol->wolopts |= WAKE_BCAST;
+ if (adapter->wol & ATL1_WUFC_MAG)
+ wol->wolopts |= WAKE_MAGIC;
+ return;
+}
+
+static int atl1_set_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+ return -EOPNOTSUPP;
+ adapter->wol = 0;
+ if (wol->wolopts & WAKE_UCAST)
+ adapter->wol |= ATL1_WUFC_EX;
+ if (wol->wolopts & WAKE_MCAST)
+ adapter->wol |= ATL1_WUFC_MC;
+ if (wol->wolopts & WAKE_BCAST)
+ adapter->wol |= ATL1_WUFC_BC;
+ if (wol->wolopts & WAKE_MAGIC)
+ adapter->wol |= ATL1_WUFC_MAG;
+ return 0;
+}
+
+static void atl1_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_tpd_ring *txdr = &adapter->tpd_ring;
+ struct atl1_rfd_ring *rxdr = &adapter->rfd_ring;
+
+ ring->rx_max_pending = ATL1_MAX_RFD;
+ ring->tx_max_pending = ATL1_MAX_TPD;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->rx_pending = rxdr->count;
+ ring->tx_pending = txdr->count;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+}
+
+static int atl1_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_tpd_ring *tpdr = &adapter->tpd_ring;
+ struct atl1_rrd_ring *rrdr = &adapter->rrd_ring;
+ struct atl1_rfd_ring *rfdr = &adapter->rfd_ring;
+
+ struct atl1_tpd_ring tpd_old, tpd_new;
+ struct atl1_rfd_ring rfd_old, rfd_new;
+ struct atl1_rrd_ring rrd_old, rrd_new;
+ struct atl1_ring_header rhdr_old, rhdr_new;
+ int err;
+
+ tpd_old = adapter->tpd_ring;
+ rfd_old = adapter->rfd_ring;
+ rrd_old = adapter->rrd_ring;
+ rhdr_old = adapter->ring_header;
+
+ if (netif_running(adapter->netdev))
+ atl1_down(adapter);
+
+ rfdr->count = (u16) max(ring->rx_pending, (u32) ATL1_MIN_RFD);
+ rfdr->count = rfdr->count > ATL1_MAX_RFD ? ATL1_MAX_RFD :
+ rfdr->count;
+ rfdr->count = (rfdr->count + 3) & ~3;
+ rrdr->count = rfdr->count;
+
+ tpdr->count = (u16) max(ring->tx_pending, (u32) ATL1_MIN_TPD);
+ tpdr->count = tpdr->count > ATL1_MAX_TPD ? ATL1_MAX_TPD :
+ tpdr->count;
+ tpdr->count = (tpdr->count + 3) & ~3;
+
+ if (netif_running(adapter->netdev)) {
+ /* try to get new resources before deleting old */
+ err = atl1_setup_ring_resources(adapter);
+ if (err)
+ goto err_setup_ring;
+
+ /*
+ * save the new, restore the old in order to free it,
+ * then restore the new back again
+ */
+
+ rfd_new = adapter->rfd_ring;
+ rrd_new = adapter->rrd_ring;
+ tpd_new = adapter->tpd_ring;
+ rhdr_new = adapter->ring_header;
+ adapter->rfd_ring = rfd_old;
+ adapter->rrd_ring = rrd_old;
+ adapter->tpd_ring = tpd_old;
+ adapter->ring_header = rhdr_old;
+ atl1_free_ring_resources(adapter);
+ adapter->rfd_ring = rfd_new;
+ adapter->rrd_ring = rrd_new;
+ adapter->tpd_ring = tpd_new;
+ adapter->ring_header = rhdr_new;
+
+ err = atl1_up(adapter);
+ if (err)
+ return err;
+ }
+ return 0;
+
+err_setup_ring:
+ adapter->rfd_ring = rfd_old;
+ adapter->rrd_ring = rrd_old;
+ adapter->tpd_ring = tpd_old;
+ adapter->ring_header = rhdr_old;
+ atl1_up(adapter);
+ return err;
+}
+
+static void atl1_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *epause)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ epause->autoneg = AUTONEG_ENABLE;
+ } else {
+ epause->autoneg = AUTONEG_DISABLE;
+ }
+ epause->rx_pause = 1;
+ epause->tx_pause = 1;
+}
+
+static int atl1_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *epause)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ epause->autoneg = AUTONEG_ENABLE;
+ } else {
+ epause->autoneg = AUTONEG_DISABLE;
+ }
+
+ epause->rx_pause = 1;
+ epause->tx_pause = 1;
+
+ return 0;
+}
+
+static u32 atl1_get_rx_csum(struct net_device *netdev)
+{
+ return 1;
+}
+
+static void atl1_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) {
+ memcpy(p, atl1_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+static int atl1_nway_reset(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ if (netif_running(netdev)) {
+ u16 phy_data;
+ atl1_down(adapter);
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+ } else {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data = MII_CR_FULL_DUPLEX |
+ MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data = MII_CR_FULL_DUPLEX |
+ MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ }
+ }
+ atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+ atl1_up(adapter);
+ }
+ return 0;
+}
+
+const struct ethtool_ops atl1_ethtool_ops = {
+ .get_settings = atl1_get_settings,
+ .set_settings = atl1_set_settings,
+ .get_drvinfo = atl1_get_drvinfo,
+ .get_wol = atl1_get_wol,
+ .set_wol = atl1_set_wol,
+ .get_ringparam = atl1_get_ringparam,
+ .set_ringparam = atl1_set_ringparam,
+ .get_pauseparam = atl1_get_pauseparam,
+ .set_pauseparam = atl1_set_pauseparam,
+ .get_rx_csum = atl1_get_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_hw_csum,
+ .get_link = ethtool_op_get_link,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_strings = atl1_get_strings,
+ .nway_reset = atl1_nway_reset,
+ .get_ethtool_stats = atl1_get_ethtool_stats,
+ .get_stats_count = atl1_get_stats_count,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+};
diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c
new file mode 100644
index 00000000000..08b2d785469
--- /dev/null
+++ b/drivers/net/atl1/atl1_hw.c
@@ -0,0 +1,718 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 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
+ * 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/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/if_vlan.h>
+#include <linux/etherdevice.h>
+#include <linux/crc32.h>
+#include <asm/byteorder.h>
+
+#include "atl1.h"
+
+/*
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ * hw - Struct containing variables accessed by shared code
+ * return : ATL1_SUCCESS or idle status (if error)
+ */
+s32 atl1_reset_hw(struct atl1_hw *hw)
+{
+ u32 icr;
+ int i;
+
+ /*
+ * Clear Interrupt mask to stop board from generating
+ * interrupts & Clear any pending interrupt events
+ */
+ /*
+ * iowrite32(0, hw->hw_addr + REG_IMR);
+ * iowrite32(0xffffffff, hw->hw_addr + REG_ISR);
+ */
+
+ /*
+ * Issue Soft Reset to the MAC. This will reset the chip's
+ * transmit, receive, DMA. It will not effect
+ * the current PCI configuration. The global reset bit is self-
+ * clearing, and should clear within a microsecond.
+ */
+ iowrite32(MASTER_CTRL_SOFT_RST, hw->hw_addr + REG_MASTER_CTRL);
+ ioread32(hw->hw_addr + REG_MASTER_CTRL);
+
+ iowrite16(1, hw->hw_addr + REG_GPHY_ENABLE);
+ ioread16(hw->hw_addr + REG_GPHY_ENABLE);
+
+ msleep(1); /* delay about 1ms */
+
+ /* Wait at least 10ms for All module to be Idle */
+ for (i = 0; i < 10; i++) {
+ icr = ioread32(hw->hw_addr + REG_IDLE_STATUS);
+ if (!icr)
+ break;
+ msleep(1); /* delay 1 ms */
+ cpu_relax(); /* FIXME: is this still the right way to do this? */
+ }
+
+ if (icr) {
+ printk (KERN_DEBUG "icr = %x\n", icr);
+ return icr;
+ }
+
+ return ATL1_SUCCESS;
+}
+
+/* function about EEPROM
+ *
+ * check_eeprom_exist
+ * return 0 if eeprom exist
+ */
+static int atl1_check_eeprom_exist(struct atl1_hw *hw)
+{
+ u32 value;
+ value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+ if (value & SPI_FLASH_CTRL_EN_VPD) {
+ value &= ~SPI_FLASH_CTRL_EN_VPD;
+ iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+ }
+
+ value = ioread16(hw->hw_addr + REG_PCIE_CAP_LIST);
+ return ((value & 0xFF00) == 0x6C00) ? 0 : 1;
+}
+
+static bool atl1_read_eeprom(struct atl1_hw *hw, u32 offset, u32 *p_value)
+{
+ int i;
+ u32 control;
+
+ if (offset & 3)
+ return false; /* address do not align */
+
+ iowrite32(0, hw->hw_addr + REG_VPD_DATA);
+ control = (offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT;
+ iowrite32(control, hw->hw_addr + REG_VPD_CAP);
+ ioread32(hw->hw_addr + REG_VPD_CAP);
+
+ for (i = 0; i < 10; i++) {
+ msleep(2);
+ control = ioread32(hw->hw_addr + REG_VPD_CAP);
+ if (control & VPD_CAP_VPD_FLAG)
+ break;
+ }
+ if (control & VPD_CAP_VPD_FLAG) {
+ *p_value = ioread32(hw->hw_addr + REG_VPD_DATA);
+ return true;
+ }
+ return false; /* timeout */
+}
+
+/*
+ * Reads the value from a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to read
+ */
+s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data)
+{
+ u32 val;
+ int i;
+
+ val = ((u32) (reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT |
+ MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 <<
+ MDIO_CLK_SEL_SHIFT;
+ iowrite32(val, hw->hw_addr + REG_MDIO_CTRL);
+ ioread32(hw->hw_addr + REG_MDIO_CTRL);
+
+ for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+ udelay(2);
+ val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ break;
+ }
+ if (!(val & (MDIO_START | MDIO_BUSY))) {
+ *phy_data = (u16) val;
+ return ATL1_SUCCESS;
+ }
+ return ATL1_ERR_PHY;
+}
+
+#define CUSTOM_SPI_CS_SETUP 2
+#define CUSTOM_SPI_CLK_HI 2
+#define CUSTOM_SPI_CLK_LO 2
+#define CUSTOM_SPI_CS_HOLD 2
+#define CUSTOM_SPI_CS_HI 3
+
+static bool atl1_spi_read(struct atl1_hw *hw, u32 addr, u32 *buf)
+{
+ int i;
+ u32 value;
+
+ iowrite32(0, hw->hw_addr + REG_SPI_DATA);
+ iowrite32(addr, hw->hw_addr + REG_SPI_ADDR);
+
+ value = SPI_FLASH_CTRL_WAIT_READY |
+ (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) <<
+ SPI_FLASH_CTRL_CS_SETUP_SHIFT | (CUSTOM_SPI_CLK_HI &
+ SPI_FLASH_CTRL_CLK_HI_MASK) <<
+ SPI_FLASH_CTRL_CLK_HI_SHIFT | (CUSTOM_SPI_CLK_LO &
+ SPI_FLASH_CTRL_CLK_LO_MASK) <<
+ SPI_FLASH_CTRL_CLK_LO_SHIFT | (CUSTOM_SPI_CS_HOLD &
+ SPI_FLASH_CTRL_CS_HOLD_MASK) <<
+ SPI_FLASH_CTRL_CS_HOLD_SHIFT | (CUSTOM_SPI_CS_HI &
+ SPI_FLASH_CTRL_CS_HI_MASK) <<
+ SPI_FLASH_CTRL_CS_HI_SHIFT | (1 & SPI_FLASH_CTRL_INS_MASK) <<
+ SPI_FLASH_CTRL_INS_SHIFT;
+
+ iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+
+ value |= SPI_FLASH_CTRL_START;
+ iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+ ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+
+ for (i = 0; i < 10; i++) {
+ msleep(1); /* 1ms */
+ value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+ if (!(value & SPI_FLASH_CTRL_START))
+ break;
+ }
+
+ if (value & SPI_FLASH_CTRL_START)
+ return false;
+
+ *buf = ioread32(hw->hw_addr + REG_SPI_DATA);
+
+ return true;
+}
+
+/*
+ * get_permanent_address
+ * return 0 if get valid mac address,
+ */
+static int atl1_get_permanent_address(struct atl1_hw *hw)
+{
+ u32 addr[2];
+ u32 i, control;
+ u16 reg;
+ u8 eth_addr[ETH_ALEN];
+ bool key_valid;
+
+ if (is_valid_ether_addr(hw->perm_mac_addr))
+ return 0;
+
+ /* init */
+ addr[0] = addr[1] = 0;
+
+ if (!atl1_check_eeprom_exist(hw)) { /* eeprom exist */
+ reg = 0;
+ key_valid = false;
+ /* Read out all EEPROM content */
+ i = 0;
+ while (1) {
+ if (atl1_read_eeprom(hw, i + 0x100, &control)) {
+ if (key_valid) {
+ if (reg == REG_MAC_STA_ADDR)
+ addr[0] = control;
+ else if (reg == (REG_MAC_STA_ADDR + 4))
+ addr[1] = control;
+ key_valid = false;
+ } else if ((control & 0xff) == 0x5A) {
+ key_valid = true;
+ reg = (u16) (control >> 16);
+ } else
+ break; /* assume data end while encount an invalid KEYWORD */
+ } else
+ break; /* read error */
+ i += 4;
+ }
+
+/*
+ * The following 2 lines are the Attansic originals. Saving for posterity.
+ * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]);
+ * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]);
+ */
+ *(u32 *) & eth_addr[2] = swab32(addr[0]);
+ *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]);
+
+ if (is_valid_ether_addr(eth_addr)) {
+ memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+ return 0;
+ }
+ return 1;
+ }
+
+ /* see if SPI FLAGS exist ? */
+ addr[0] = addr[1] = 0;
+ reg = 0;
+ key_valid = false;
+ i = 0;
+ while (1) {
+ if (atl1_spi_read(hw, i + 0x1f000, &control)) {
+ if (key_valid) {
+ if (reg == REG_MAC_STA_ADDR)
+ addr[0] = control;
+ else if (reg == (REG_MAC_STA_ADDR + 4))
+ addr[1] = control;
+ key_valid = false;
+ } else if ((control & 0xff) == 0x5A) {
+ key_valid = true;
+ reg = (u16) (control >> 16);
+ } else
+ break; /* data end */
+ } else
+ break; /* read error */
+ i += 4;
+ }
+
+/*
+ * The following 2 lines are the Attansic originals. Saving for posterity.
+ * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]);
+ * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]);
+ */
+ *(u32 *) & eth_addr[2] = swab32(addr[0]);
+ *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]);
+ if (is_valid_ether_addr(eth_addr)) {
+ memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Reads the adapter's MAC address from the EEPROM
+ * hw - Struct containing variables accessed by shared code
+ */
+s32 atl1_read_mac_addr(struct atl1_hw *hw)
+{
+ u16 i;
+
+ if (atl1_get_permanent_address(hw))
+ random_ether_addr(hw->perm_mac_addr);
+
+ for (i = 0; i < ETH_ALEN; i++)
+ hw->mac_addr[i] = hw->perm_mac_addr[i];
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Hashes an address to determine its location in the multicast table
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash
+ *
+ * atl1_hash_mc_addr
+ * purpose
+ * set hash value for a multicast address
+ * hash calcu processing :
+ * 1. calcu 32bit CRC for multicast address
+ * 2. reverse crc with MSB to LSB
+ */
+u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr)
+{
+ u32 crc32, value = 0;
+ int i;
+
+ crc32 = ether_crc_le(6, mc_addr);
+ crc32 = ~crc32;
+ for (i = 0; i < 32; i++)
+ value |= (((crc32 >> i) & 1) << (31 - i));
+
+ return value;
+}
+
+/*
+ * Sets the bit in the multicast table corresponding to the hash value.
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ */
+void atl1_hash_set(struct atl1_hw *hw, u32 hash_value)
+{
+ u32 hash_bit, hash_reg;
+ u32 mta;
+
+ /*
+ * The HASH Table is a register array of 2 32-bit registers.
+ * It is treated like an array of 64 bits. We want to set
+ * bit BitArray[hash_value]. So we figure out what register
+ * the bit is in, read it, OR in the new bit, then write
+ * back the new value. The register is determined by the
+ * upper 7 bits of the hash value and the bit within that
+ * register are determined by the lower 5 bits of the value.
+ */
+ hash_reg = (hash_value >> 31) & 0x1;
+ hash_bit = (hash_value >> 26) & 0x1F;
+ mta = ioread32((hw + REG_RX_HASH_TABLE) + (hash_reg << 2));
+ mta |= (1 << hash_bit);
+ iowrite32(mta, (hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2));
+}
+
+/*
+ * Writes a value to a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to write
+ * data - data to write to the PHY
+ */
+s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data)
+{
+ int i;
+ u32 val;
+
+ val = ((u32) (phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT |
+ (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT |
+ MDIO_SUP_PREAMBLE |
+ MDIO_START | MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
+ iowrite32(val, hw->hw_addr + REG_MDIO_CTRL);
+ ioread32(hw->hw_addr + REG_MDIO_CTRL);
+
+ for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+ udelay(2);
+ val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ break;
+ }
+
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ return ATL1_SUCCESS;
+
+ return ATL1_ERR_PHY;
+}
+
+/*
+ * Make L001's PHY out of Power Saving State (bug)
+ * hw - Struct containing variables accessed by shared code
+ * when power on, L001's PHY always on Power saving State
+ * (Gigabit Link forbidden)
+ */
+static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw)
+{
+ s32 ret;
+ ret = atl1_write_phy_reg(hw, 29, 0x0029);
+ if (ret)
+ return ret;
+ return atl1_write_phy_reg(hw, 30, 0);
+}
+
+/*
+ *TODO: do something or get rid of this
+ */
+s32 atl1_phy_enter_power_saving(struct atl1_hw *hw)
+{
+/* s32 ret_val;
+ * u16 phy_data;
+ */
+
+/*
+ ret_val = atl1_write_phy_reg(hw, ...);
+ ret_val = atl1_write_phy_reg(hw, ...);
+ ....
+*/
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Resets the PHY and make all config validate
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets bit 15 and 12 of the MII Control regiser (for F001 bug)
+ */
+static s32 atl1_phy_reset(struct atl1_hw *hw)
+{
+ s32 ret_val;
+ u16 phy_data;
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL)
+ phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+ else {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+ MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF: */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ }
+ }
+
+ ret_val = atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+ if (ret_val) {
+ u32 val;
+ int i;
+ /* pcie serdes link may be down! */
+ printk(KERN_DEBUG "%s: autoneg caused pcie phy link down\n",
+ atl1_driver_name);
+
+ for (i = 0; i < 25; i++) {
+ msleep(1);
+ val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ break;
+ }
+
+ if ((val & (MDIO_START | MDIO_BUSY)) != 0) {
+ printk(KERN_WARNING
+ "%s: pcie link down at least for 25ms\n",
+ atl1_driver_name);
+ return ret_val;
+ }
+ }
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Configures PHY autoneg and flow control advertisement settings
+ * hw - Struct containing variables accessed by shared code
+ */
+s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw)
+{
+ s32 ret_val;
+ s16 mii_autoneg_adv_reg;
+ s16 mii_1000t_ctrl_reg;
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK;
+
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK;
+
+ /*
+ * First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK;
+ mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK;
+
+ /*
+ * Need to parse media_type and set up
+ * the appropriate PHY registers.
+ */
+ switch (hw->media_type) {
+ case MEDIA_TYPE_AUTO_SENSOR:
+ mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS |
+ MII_AR_10T_FD_CAPS |
+ MII_AR_100TX_HD_CAPS |
+ MII_AR_100TX_FD_CAPS);
+ mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
+ break;
+
+ case MEDIA_TYPE_1000M_FULL:
+ mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
+ break;
+
+ case MEDIA_TYPE_100M_FULL:
+ mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS;
+ break;
+
+ case MEDIA_TYPE_100M_HALF:
+ mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS;
+ break;
+
+ case MEDIA_TYPE_10M_FULL:
+ mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS;
+ break;
+
+ default:
+ mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS;
+ break;
+ }
+
+ /* flow control fixed to enable all */
+ mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE);
+
+ hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg;
+ hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg;
+
+ ret_val = atl1_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = atl1_write_phy_reg(hw, MII_AT001_CR, mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Configures link settings.
+ * hw - Struct containing variables accessed by shared code
+ * Assumes the hardware has previously been reset and the
+ * transmitter and receiver are not enabled.
+ */
+static s32 atl1_setup_link(struct atl1_hw *hw)
+{
+ s32 ret_val;
+
+ /*
+ * Options:
+ * PHY will advertise value(s) parsed from
+ * autoneg_advertised and fc
+ * no matter what autoneg is , We will not wait link result.
+ */
+ ret_val = atl1_phy_setup_autoneg_adv(hw);
+ if (ret_val) {
+ printk(KERN_DEBUG "%s: error setting up autonegotiation\n",
+ atl1_driver_name);
+ return ret_val;
+ }
+ /* SW.Reset , En-Auto-Neg if needed */
+ ret_val = atl1_phy_reset(hw);
+ if (ret_val) {
+ printk(KERN_DEBUG "%s: error resetting the phy\n",
+ atl1_driver_name);
+ return ret_val;
+ }
+ hw->phy_configured = true;
+ return ret_val;
+}
+
+static struct atl1_spi_flash_dev flash_table[] = {
+/* MFR_NAME WRSR READ PRGM WREN WRDI RDSR RDID SECTOR_ERASE CHIP_ERASE */
+ {"Atmel", 0x00, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52, 0x62},
+ {"SST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0x90, 0x20, 0x60},
+ {"ST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0xAB, 0xD8, 0xC7},
+};
+
+static void atl1_init_flash_opcode(struct atl1_hw *hw)
+{
+ if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0]))
+ hw->flash_vendor = 0; /* ATMEL */
+
+ /* Init OP table */
+ iowrite8(flash_table[hw->flash_vendor].cmd_program,
+ hw->hw_addr + REG_SPI_FLASH_OP_PROGRAM);
+ iowrite8(flash_table[hw->flash_vendor].cmd_sector_erase,
+ hw->hw_addr + REG_SPI_FLASH_OP_SC_ERASE);
+ iowrite8(flash_table[hw->flash_vendor].cmd_chip_erase,
+ hw->hw_addr + REG_SPI_FLASH_OP_CHIP_ERASE);
+ iowrite8(flash_table[hw->flash_vendor].cmd_rdid,
+ hw->hw_addr + REG_SPI_FLASH_OP_RDID);
+ iowrite8(flash_table[hw->flash_vendor].cmd_wren,
+ hw->hw_addr + REG_SPI_FLASH_OP_WREN);
+ iowrite8(flash_table[hw->flash_vendor].cmd_rdsr,
+ hw->hw_addr + REG_SPI_FLASH_OP_RDSR);
+ iowrite8(flash_table[hw->flash_vendor].cmd_wrsr,
+ hw->hw_addr + REG_SPI_FLASH_OP_WRSR);
+ iowrite8(flash_table[hw->flash_vendor].cmd_read,
+ hw->hw_addr + REG_SPI_FLASH_OP_READ);
+}
+
+/*
+ * Performs basic configuration of the adapter.
+ * hw - Struct containing variables accessed by shared code
+ * Assumes that the controller has previously been reset and is in a
+ * post-reset uninitialized state. Initializes multicast table,
+ * and Calls routines to setup link
+ * Leaves the transmit and receive units disabled and uninitialized.
+ */
+s32 atl1_init_hw(struct atl1_hw *hw)
+{
+ u32 ret_val = 0;
+
+ /* Zero out the Multicast HASH table */
+ iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE);
+ /* clear the old settings from the multicast hash table */
+ iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2));
+
+ atl1_init_flash_opcode(hw);
+
+ if (!hw->phy_configured) {
+ /* enable GPHY LinkChange Interrrupt */
+ ret_val = atl1_write_phy_reg(hw, 18, 0xC00);
+ if (ret_val)
+ return ret_val;
+ /* make PHY out of power-saving state */
+ ret_val = atl1_phy_leave_power_saving(hw);
+ if (ret_val)
+ return ret_val;
+ /* Call a subroutine to configure the link */
+ ret_val = atl1_setup_link(hw);
+ }
+ return ret_val;
+}
+
+/*
+ * Detects the current speed and duplex settings of the hardware.
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ */
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex)
+{
+ s32 ret_val;
+ u16 phy_data;
+
+ /* ; --- Read PHY Specific Status Register (17) */
+ ret_val = atl1_read_phy_reg(hw, MII_AT001_PSSR, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED))
+ return ATL1_ERR_PHY_RES;
+
+ switch (phy_data & MII_AT001_PSSR_SPEED) {
+ case MII_AT001_PSSR_1000MBS:
+ *speed = SPEED_1000;
+ break;
+ case MII_AT001_PSSR_100MBS:
+ *speed = SPEED_100;
+ break;
+ case MII_AT001_PSSR_10MBS:
+ *speed = SPEED_10;
+ break;
+ default:
+ printk(KERN_DEBUG "%s: error getting speed\n",
+ atl1_driver_name);
+ return ATL1_ERR_PHY_SPEED;
+ break;
+ }
+ if (phy_data & MII_AT001_PSSR_DPLX)
+ *duplex = FULL_DUPLEX;
+ else
+ *duplex = HALF_DUPLEX;
+
+ return ATL1_SUCCESS;
+}
+
+void atl1_set_mac_addr(struct atl1_hw *hw)
+{
+ u32 value;
+ /*
+ * 00-0B-6A-F6-00-DC
+ * 0: 6AF600DC 1: 000B
+ * low dword
+ */
+ value = (((u32) hw->mac_addr[2]) << 24) |
+ (((u32) hw->mac_addr[3]) << 16) |
+ (((u32) hw->mac_addr[4]) << 8) | (((u32) hw->mac_addr[5]));
+ iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR);
+ /* high dword */
+ value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1]));
+ iowrite32(value, (hw->hw_addr + REG_MAC_STA_ADDR) + (1 << 2));
+}
diff --git a/drivers/net/atl1/atl1_hw.h b/drivers/net/atl1/atl1_hw.h
new file mode 100644
index 00000000000..100c09c66e6
--- /dev/null
+++ b/drivers/net/atl1/atl1_hw.h
@@ -0,0 +1,951 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 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
+ * 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.
+ *
+ * There are a lot of defines in here that are unused and/or have cryptic
+ * names. Please leave them alone, as they're the closest thing we have
+ * to a spec from Attansic at present. *ahem* -- CHS
+ */
+
+#ifndef _ATL1_HW_H_
+#define _ATL1_HW_H_
+
+#include <linux/types.h>
+#include <linux/mii.h>
+
+struct atl1_adapter;
+struct atl1_hw;
+
+/* function prototypes needed by multiple files */
+s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw);
+s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data);
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex);
+s32 atl1_read_mac_addr(struct atl1_hw *hw);
+s32 atl1_init_hw(struct atl1_hw *hw);
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex);
+s32 atl1_set_speed_and_duplex(struct atl1_hw *hw, u16 speed, u16 duplex);
+u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr);
+void atl1_hash_set(struct atl1_hw *hw, u32 hash_value);
+s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data);
+void atl1_set_mac_addr(struct atl1_hw *hw);
+s32 atl1_phy_enter_power_saving(struct atl1_hw *hw);
+s32 atl1_reset_hw(struct atl1_hw *hw);
+void atl1_check_options(struct atl1_adapter *adapter);
+
+/* register definitions */
+#define REG_PCIE_CAP_LIST 0x58
+
+#define REG_VPD_CAP 0x6C
+#define VPD_CAP_ID_MASK 0xff
+#define VPD_CAP_ID_SHIFT 0
+#define VPD_CAP_NEXT_PTR_MASK 0xFF
+#define VPD_CAP_NEXT_PTR_SHIFT 8
+#define VPD_CAP_VPD_ADDR_MASK 0x7FFF
+#define VPD_CAP_VPD_ADDR_SHIFT 16
+#define VPD_CAP_VPD_FLAG 0x80000000
+
+#define REG_VPD_DATA 0x70
+
+#define REG_SPI_FLASH_CTRL 0x200
+#define SPI_FLASH_CTRL_STS_NON_RDY 0x1
+#define SPI_FLASH_CTRL_STS_WEN 0x2
+#define SPI_FLASH_CTRL_STS_WPEN 0x80
+#define SPI_FLASH_CTRL_DEV_STS_MASK 0xFF
+#define SPI_FLASH_CTRL_DEV_STS_SHIFT 0
+#define SPI_FLASH_CTRL_INS_MASK 0x7
+#define SPI_FLASH_CTRL_INS_SHIFT 8
+#define SPI_FLASH_CTRL_START 0x800
+#define SPI_FLASH_CTRL_EN_VPD 0x2000
+#define SPI_FLASH_CTRL_LDSTART 0x8000
+#define SPI_FLASH_CTRL_CS_HI_MASK 0x3
+#define SPI_FLASH_CTRL_CS_HI_SHIFT 16
+#define SPI_FLASH_CTRL_CS_HOLD_MASK 0x3
+#define SPI_FLASH_CTRL_CS_HOLD_SHIFT 18
+#define SPI_FLASH_CTRL_CLK_LO_MASK 0x3
+#define SPI_FLASH_CTRL_CLK_LO_SHIFT 20
+#define SPI_FLASH_CTRL_CLK_HI_MASK 0x3
+#define SPI_FLASH_CTRL_CLK_HI_SHIFT 22
+#define SPI_FLASH_CTRL_CS_SETUP_MASK 0x3
+#define SPI_FLASH_CTRL_CS_SETUP_SHIFT 24
+#define SPI_FLASH_CTRL_EROM_PGSZ_MASK 0x3
+#define SPI_FLASH_CTRL_EROM_PGSZ_SHIFT 26
+#define SPI_FLASH_CTRL_WAIT_READY 0x10000000
+
+#define REG_SPI_ADDR 0x204
+
+#define REG_SPI_DATA 0x208
+
+#define REG_SPI_FLASH_CONFIG 0x20C
+#define SPI_FLASH_CONFIG_LD_ADDR_MASK 0xFFFFFF
+#define SPI_FLASH_CONFIG_LD_ADDR_SHIFT 0
+#define SPI_FLASH_CONFIG_VPD_ADDR_MASK 0x3
+#define SPI_FLASH_CONFIG_VPD_ADDR_SHIFT 24
+#define SPI_FLASH_CONFIG_LD_EXIST 0x4000000
+
+#define REG_SPI_FLASH_OP_PROGRAM 0x210
+#define REG_SPI_FLASH_OP_SC_ERASE 0x211
+#define REG_SPI_FLASH_OP_CHIP_ERASE 0x212
+#define REG_SPI_FLASH_OP_RDID 0x213
+#define REG_SPI_FLASH_OP_WREN 0x214
+#define REG_SPI_FLASH_OP_RDSR 0x215
+#define REG_SPI_FLASH_OP_WRSR 0x216
+#define REG_SPI_FLASH_OP_READ 0x217
+
+#define REG_TWSI_CTRL 0x218
+#define TWSI_CTRL_LD_OFFSET_MASK 0xFF
+#define TWSI_CTRL_LD_OFFSET_SHIFT 0
+#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7
+#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8
+#define TWSI_CTRL_SW_LDSTART 0x800
+#define TWSI_CTRL_HW_LDSTART 0x1000
+#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x7F
+#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15
+#define TWSI_CTRL_LD_EXIST 0x400000
+#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3
+#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23
+#define TWSI_CTRL_FREQ_SEL_100K 0
+#define TWSI_CTRL_FREQ_SEL_200K 1
+#define TWSI_CTRL_FREQ_SEL_300K 2
+#define TWSI_CTRL_FREQ_SEL_400K 3
+#define TWSI_CTRL_SMB_SLV_ADDR
+#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3
+#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24
+
+#define REG_PCIE_DEV_MISC_CTRL 0x21C
+#define PCIE_DEV_MISC_CTRL_EXT_PIPE 0x2
+#define PCIE_DEV_MISC_CTRL_RETRY_BUFDIS 0x1
+#define PCIE_DEV_MISC_CTRL_SPIROM_EXIST 0x4
+#define PCIE_DEV_MISC_CTRL_SERDES_ENDIAN 0x8
+#define PCIE_DEV_MISC_CTRL_SERDES_SEL_DIN 0x10
+
+/* Selene Master Control Register */
+#define REG_MASTER_CTRL 0x1400
+#define MASTER_CTRL_SOFT_RST 0x1
+#define MASTER_CTRL_MTIMER_EN 0x2
+#define MASTER_CTRL_ITIMER_EN 0x4
+#define MASTER_CTRL_MANUAL_INT 0x8
+#define MASTER_CTRL_REV_NUM_SHIFT 16
+#define MASTER_CTRL_REV_NUM_MASK 0xff
+#define MASTER_CTRL_DEV_ID_SHIFT 24
+#define MASTER_CTRL_DEV_ID_MASK 0xff
+
+/* Timer Initial Value Register */
+#define REG_MANUAL_TIMER_INIT 0x1404
+
+/* IRQ ModeratorTimer Initial Value Register */
+#define REG_IRQ_MODU_TIMER_INIT 0x1408
+
+#define REG_GPHY_ENABLE 0x140C
+
+/* IRQ Anti-Lost Timer Initial Value Register */
+#define REG_CMBDISDMA_TIMER 0x140E
+
+/* Block IDLE Status Register */
+#define REG_IDLE_STATUS 0x1410
+#define IDLE_STATUS_RXMAC 1
+#define IDLE_STATUS_TXMAC 2
+#define IDLE_STATUS_RXQ 4
+#define IDLE_STATUS_TXQ 8
+#define IDLE_STATUS_DMAR 0x10
+#define IDLE_STATUS_DMAW 0x20
+#define IDLE_STATUS_SMB 0x40
+#define IDLE_STATUS_CMB 0x80
+
+/* MDIO Control Register */
+#define REG_MDIO_CTRL 0x1414
+#define MDIO_DATA_MASK 0xffff
+#define MDIO_DATA_SHIFT 0
+#define MDIO_REG_ADDR_MASK 0x1f
+#define MDIO_REG_ADDR_SHIFT 16
+#define MDIO_RW 0x200000
+#define MDIO_SUP_PREAMBLE 0x400000
+#define MDIO_START 0x800000
+#define MDIO_CLK_SEL_SHIFT 24
+#define MDIO_CLK_25_4 0
+#define MDIO_CLK_25_6 2
+#define MDIO_CLK_25_8 3
+#define MDIO_CLK_25_10 4
+#define MDIO_CLK_25_14 5
+#define MDIO_CLK_25_20 6
+#define MDIO_CLK_25_28 7
+#define MDIO_BUSY 0x8000000
+#define MDIO_WAIT_TIMES 30
+
+/* MII PHY Status Register */
+#define REG_PHY_STATUS 0x1418
+
+/* BIST Control and Status Register0 (for the Packet Memory) */
+#define REG_BIST0_CTRL 0x141c
+#define BIST0_NOW 0x1
+#define BIST0_SRAM_FAIL 0x2
+#define BIST0_FUSE_FLAG 0x4
+#define REG_BIST1_CTRL 0x1420
+#define BIST1_NOW 0x1
+#define BIST1_SRAM_FAIL 0x2
+#define BIST1_FUSE_FLAG 0x4
+
+/* MAC Control Register */
+#define REG_MAC_CTRL 0x1480
+#define MAC_CTRL_TX_EN 1
+#define MAC_CTRL_RX_EN 2
+#define MAC_CTRL_TX_FLOW 4
+#define MAC_CTRL_RX_FLOW 8
+#define MAC_CTRL_LOOPBACK 0x10
+#define MAC_CTRL_DUPLX 0x20
+#define MAC_CTRL_ADD_CRC 0x40
+#define MAC_CTRL_PAD 0x80
+#define MAC_CTRL_LENCHK 0x100
+#define MAC_CTRL_HUGE_EN 0x200
+#define MAC_CTRL_PRMLEN_SHIFT 10
+#define MAC_CTRL_PRMLEN_MASK 0xf
+#define MAC_CTRL_RMV_VLAN 0x4000
+#define MAC_CTRL_PROMIS_EN 0x8000
+#define MAC_CTRL_TX_PAUSE 0x10000
+#define MAC_CTRL_SCNT 0x20000
+#define MAC_CTRL_SRST_TX 0x40000
+#define MAC_CTRL_TX_SIMURST 0x80000
+#define MAC_CTRL_SPEED_SHIFT 20
+#define MAC_CTRL_SPEED_MASK 0x300000
+#define MAC_CTRL_SPEED_1000 2
+#define MAC_CTRL_SPEED_10_100 1
+#define MAC_CTRL_DBG_TX_BKPRESURE 0x400000
+#define MAC_CTRL_TX_HUGE 0x800000
+#define MAC_CTRL_RX_CHKSUM_EN 0x1000000
+#define MAC_CTRL_MC_ALL_EN 0x2000000
+#define MAC_CTRL_BC_EN 0x4000000
+#define MAC_CTRL_DBG 0x8000000
+
+/* MAC IPG/IFG Control Register */
+#define REG_MAC_IPG_IFG 0x1484
+#define MAC_IPG_IFG_IPGT_SHIFT 0
+#define MAC_IPG_IFG_IPGT_MASK 0x7f
+#define MAC_IPG_IFG_MIFG_SHIFT 8
+#define MAC_IPG_IFG_MIFG_MASK 0xff
+#define MAC_IPG_IFG_IPGR1_SHIFT 16
+#define MAC_IPG_IFG_IPGR1_MASK 0x7f
+#define MAC_IPG_IFG_IPGR2_SHIFT 24
+#define MAC_IPG_IFG_IPGR2_MASK 0x7f
+
+/* MAC STATION ADDRESS */
+#define REG_MAC_STA_ADDR 0x1488
+
+/* Hash table for multicast address */
+#define REG_RX_HASH_TABLE 0x1490
+
+/* MAC Half-Duplex Control Register */
+#define REG_MAC_HALF_DUPLX_CTRL 0x1498
+#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT 0
+#define MAC_HALF_DUPLX_CTRL_LCOL_MASK 0x3ff
+#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12
+#define MAC_HALF_DUPLX_CTRL_RETRY_MASK 0xf
+#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN 0x10000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_C 0x20000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_P 0x40000
+#define MAC_HALF_DUPLX_CTRL_ABEBE 0x80000
+#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT 20
+#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK 0xf
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK 0xf
+
+/* Maximum Frame Length Control Register */
+#define REG_MTU 0x149c
+
+/* Wake-On-Lan control register */
+#define REG_WOL_CTRL 0x14a0
+#define WOL_PATTERN_EN 0x00000001
+#define WOL_PATTERN_PME_EN 0x00000002
+#define WOL_MAGIC_EN 0x00000004
+#define WOL_MAGIC_PME_EN 0x00000008
+#define WOL_LINK_CHG_EN 0x00000010
+#define WOL_LINK_CHG_PME_EN 0x00000020
+#define WOL_PATTERN_ST 0x00000100
+#define WOL_MAGIC_ST 0x00000200
+#define WOL_LINKCHG_ST 0x00000400
+#define WOL_CLK_SWITCH_EN 0x00008000
+#define WOL_PT0_EN 0x00010000
+#define WOL_PT1_EN 0x00020000
+#define WOL_PT2_EN 0x00040000
+#define WOL_PT3_EN 0x00080000
+#define WOL_PT4_EN 0x00100000
+#define WOL_PT5_EN 0x00200000
+#define WOL_PT6_EN 0x00400000
+
+/* WOL Length ( 2 DWORD ) */
+#define REG_WOL_PATTERN_LEN 0x14a4
+#define WOL_PT_LEN_MASK 0x7f
+#define WOL_PT0_LEN_SHIFT 0
+#define WOL_PT1_LEN_SHIFT 8
+#define WOL_PT2_LEN_SHIFT 16
+#define WOL_PT3_LEN_SHIFT 24
+#define WOL_PT4_LEN_SHIFT 0
+#define WOL_PT5_LEN_SHIFT 8
+#define WOL_PT6_LEN_SHIFT 16
+
+/* Internal SRAM Partition Register */
+#define REG_SRAM_RFD_ADDR 0x1500
+#define REG_SRAM_RFD_LEN (REG_SRAM_RFD_ADDR+ 4)
+#define REG_SRAM_RRD_ADDR (REG_SRAM_RFD_ADDR+ 8)
+#define REG_SRAM_RRD_LEN (REG_SRAM_RFD_ADDR+12)
+#define REG_SRAM_TPD_ADDR (REG_SRAM_RFD_ADDR+16)
+#define REG_SRAM_TPD_LEN (REG_SRAM_RFD_ADDR+20)
+#define REG_SRAM_TRD_ADDR (REG_SRAM_RFD_ADDR+24)
+#define REG_SRAM_TRD_LEN (REG_SRAM_RFD_ADDR+28)
+#define REG_SRAM_RXF_ADDR (REG_SRAM_RFD_ADDR+32)
+#define REG_SRAM_RXF_LEN (REG_SRAM_RFD_ADDR+36)
+#define REG_SRAM_TXF_ADDR (REG_SRAM_RFD_ADDR+40)
+#define REG_SRAM_TXF_LEN (REG_SRAM_RFD_ADDR+44)
+#define REG_SRAM_TCPH_PATH_ADDR (REG_SRAM_RFD_ADDR+48)
+#define SRAM_TCPH_ADDR_MASK 0x0fff
+#define SRAM_TCPH_ADDR_SHIFT 0
+#define SRAM_PATH_ADDR_MASK 0x0fff
+#define SRAM_PATH_ADDR_SHIFT 16
+
+/* Load Ptr Register */
+#define REG_LOAD_PTR (REG_SRAM_RFD_ADDR+52)
+
+/* Descriptor Control register */
+#define REG_DESC_BASE_ADDR_HI 0x1540
+#define REG_DESC_RFD_ADDR_LO (REG_DESC_BASE_ADDR_HI+4)
+#define REG_DESC_RRD_ADDR_LO (REG_DESC_BASE_ADDR_HI+8)
+#define REG_DESC_TPD_ADDR_LO (REG_DESC_BASE_ADDR_HI+12)
+#define REG_DESC_CMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+16)
+#define REG_DESC_SMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+20)
+#define REG_DESC_RFD_RRD_RING_SIZE (REG_DESC_BASE_ADDR_HI+24)
+#define DESC_RFD_RING_SIZE_MASK 0x7ff
+#define DESC_RFD_RING_SIZE_SHIFT 0
+#define DESC_RRD_RING_SIZE_MASK 0x7ff
+#define DESC_RRD_RING_SIZE_SHIFT 16
+#define REG_DESC_TPD_RING_SIZE (REG_DESC_BASE_ADDR_HI+28)
+#define DESC_TPD_RING_SIZE_MASK 0x3ff
+#define DESC_TPD_RING_SIZE_SHIFT 0
+
+/* TXQ Control Register */
+#define REG_TXQ_CTRL 0x1580
+#define TXQ_CTRL_TPD_BURST_NUM_SHIFT 0
+#define TXQ_CTRL_TPD_BURST_NUM_MASK 0x1f
+#define TXQ_CTRL_EN 0x20
+#define TXQ_CTRL_ENH_MODE 0x40
+#define TXQ_CTRL_TPD_FETCH_TH_SHIFT 8
+#define TXQ_CTRL_TPD_FETCH_TH_MASK 0x3f
+#define TXQ_CTRL_TXF_BURST_NUM_SHIFT 16
+#define TXQ_CTRL_TXF_BURST_NUM_MASK 0xffff
+
+/* Jumbo packet Threshold for task offload */
+#define REG_TX_JUMBO_TASK_TH_TPD_IPG 0x1584
+#define TX_JUMBO_TASK_TH_MASK 0x7ff
+#define TX_JUMBO_TASK_TH_SHIFT 0
+#define TX_TPD_MIN_IPG_MASK 0x1f
+#define TX_TPD_MIN_IPG_SHIFT 16
+
+/* RXQ Control Register */
+#define REG_RXQ_CTRL 0x15a0
+#define RXQ_CTRL_RFD_BURST_NUM_SHIFT 0
+#define RXQ_CTRL_RFD_BURST_NUM_MASK 0xff
+#define RXQ_CTRL_RRD_BURST_THRESH_SHIFT 8
+#define RXQ_CTRL_RRD_BURST_THRESH_MASK 0xff
+#define RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT 16
+#define RXQ_CTRL_RFD_PREF_MIN_IPG_MASK 0x1f
+#define RXQ_CTRL_CUT_THRU_EN 0x40000000
+#define RXQ_CTRL_EN 0x80000000
+
+/* Rx jumbo packet threshold and rrd retirement timer */
+#define REG_RXQ_JMBOSZ_RRDTIM (REG_RXQ_CTRL+ 4)
+#define RXQ_JMBOSZ_TH_MASK 0x7ff
+#define RXQ_JMBOSZ_TH_SHIFT 0
+#define RXQ_JMBO_LKAH_MASK 0xf
+#define RXQ_JMBO_LKAH_SHIFT 11
+#define RXQ_RRD_TIMER_MASK 0xffff
+#define RXQ_RRD_TIMER_SHIFT 16
+
+/* RFD flow control register */
+#define REG_RXQ_RXF_PAUSE_THRESH (REG_RXQ_CTRL+ 8)
+#define RXQ_RXF_PAUSE_TH_HI_SHIFT 16
+#define RXQ_RXF_PAUSE_TH_HI_MASK 0xfff
+#define RXQ_RXF_PAUSE_TH_LO_SHIFT 0
+#define RXQ_RXF_PAUSE_TH_LO_MASK 0xfff
+
+/* RRD flow control register */
+#define REG_RXQ_RRD_PAUSE_THRESH (REG_RXQ_CTRL+12)
+#define RXQ_RRD_PAUSE_TH_HI_SHIFT 0
+#define RXQ_RRD_PAUSE_TH_HI_MASK 0xfff
+#define RXQ_RRD_PAUSE_TH_LO_SHIFT 16
+#define RXQ_RRD_PAUSE_TH_LO_MASK 0xfff
+
+/* DMA Engine Control Register */
+#define REG_DMA_CTRL 0x15c0
+#define DMA_CTRL_DMAR_IN_ORDER 0x1
+#define DMA_CTRL_DMAR_ENH_ORDER 0x2
+#define DMA_CTRL_DMAR_OUT_ORDER 0x4
+#define DMA_CTRL_RCB_VALUE 0x8
+#define DMA_CTRL_DMAR_BURST_LEN_SHIFT 4
+#define DMA_CTRL_DMAR_BURST_LEN_MASK 7
+#define DMA_CTRL_DMAW_BURST_LEN_SHIFT 7
+#define DMA_CTRL_DMAW_BURST_LEN_MASK 7
+#define DMA_CTRL_DMAR_EN 0x400
+#define DMA_CTRL_DMAW_EN 0x800
+
+/* CMB/SMB Control Register */
+#define REG_CSMB_CTRL 0x15d0
+#define CSMB_CTRL_CMB_NOW 1
+#define CSMB_CTRL_SMB_NOW 2
+#define CSMB_CTRL_CMB_EN 4
+#define CSMB_CTRL_SMB_EN 8
+
+/* CMB DMA Write Threshold Register */
+#define REG_CMB_WRITE_TH (REG_CSMB_CTRL+ 4)
+#define CMB_RRD_TH_SHIFT 0
+#define CMB_RRD_TH_MASK 0x7ff
+#define CMB_TPD_TH_SHIFT 16
+#define CMB_TPD_TH_MASK 0x7ff
+
+/* RX/TX count-down timer to trigger CMB-write. 2us resolution. */
+#define REG_CMB_WRITE_TIMER (REG_CSMB_CTRL+ 8)
+#define CMB_RX_TM_SHIFT 0
+#define CMB_RX_TM_MASK 0xffff
+#define CMB_TX_TM_SHIFT 16
+#define CMB_TX_TM_MASK 0xffff
+
+/* Number of packet received since last CMB write */
+#define REG_CMB_RX_PKT_CNT (REG_CSMB_CTRL+12)
+
+/* Number of packet transmitted since last CMB write */
+#define REG_CMB_TX_PKT_CNT (REG_CSMB_CTRL+16)
+
+/* SMB auto DMA timer register */
+#define REG_SMB_TIMER (REG_CSMB_CTRL+20)
+
+/* Mailbox Register */
+#define REG_MAILBOX 0x15f0
+#define MB_RFD_PROD_INDX_SHIFT 0
+#define MB_RFD_PROD_INDX_MASK 0x7ff
+#define MB_RRD_CONS_INDX_SHIFT 11
+#define MB_RRD_CONS_INDX_MASK 0x7ff
+#define MB_TPD_PROD_INDX_SHIFT 22
+#define MB_TPD_PROD_INDX_MASK 0x3ff
+
+/* Interrupt Status Register */
+#define REG_ISR 0x1600
+#define ISR_SMB 1
+#define ISR_TIMER 2
+#define ISR_MANUAL 4
+#define ISR_RXF_OV 8
+#define ISR_RFD_UNRUN 0x10
+#define ISR_RRD_OV 0x20
+#define ISR_TXF_UNRUN 0x40
+#define ISR_LINK 0x80
+#define ISR_HOST_RFD_UNRUN 0x100
+#define ISR_HOST_RRD_OV 0x200
+#define ISR_DMAR_TO_RST 0x400
+#define ISR_DMAW_TO_RST 0x800
+#define ISR_GPHY 0x1000
+#define ISR_RX_PKT 0x10000
+#define ISR_TX_PKT 0x20000
+#define ISR_TX_DMA 0x40000
+#define ISR_RX_DMA 0x80000
+#define ISR_CMB_RX 0x100000
+#define ISR_CMB_TX 0x200000
+#define ISR_MAC_RX 0x400000
+#define ISR_MAC_TX 0x800000
+#define ISR_UR_DETECTED 0x1000000
+#define ISR_FERR_DETECTED 0x2000000
+#define ISR_NFERR_DETECTED 0x4000000
+#define ISR_CERR_DETECTED 0x8000000
+#define ISR_PHY_LINKDOWN 0x10000000
+#define ISR_DIS_SMB 0x20000000
+#define ISR_DIS_DMA 0x40000000
+#define ISR_DIS_INT 0x80000000
+
+/* Interrupt Mask Register */
+#define REG_IMR 0x1604
+
+/* Normal Interrupt mask */
+#define IMR_NORMAL_MASK (\
+ ISR_SMB |\
+ ISR_GPHY |\
+ ISR_PHY_LINKDOWN|\
+ ISR_DMAR_TO_RST |\
+ ISR_DMAW_TO_RST |\
+ ISR_CMB_TX |\
+ ISR_CMB_RX )
+
+/* Debug Interrupt Mask (enable all interrupt) */
+#define IMR_DEBUG_MASK (\
+ ISR_SMB |\
+ ISR_TIMER |\
+ ISR_MANUAL |\
+ ISR_RXF_OV |\
+ ISR_RFD_UNRUN |\
+ ISR_RRD_OV |\
+ ISR_TXF_UNRUN |\
+ ISR_LINK |\
+ ISR_CMB_TX |\
+ ISR_CMB_RX |\
+ ISR_RX_PKT |\
+ ISR_TX_PKT |\
+ ISR_MAC_RX |\
+ ISR_MAC_TX )
+
+/* Interrupt Status Register */
+#define REG_RFD_RRD_IDX 0x1800
+#define REG_TPD_IDX 0x1804
+
+/* MII definition */
+/* PHY Common Register */
+#define MII_AT001_CR 0x09
+#define MII_AT001_SR 0x0A
+#define MII_AT001_ESR 0x0F
+#define MII_AT001_PSCR 0x10
+#define MII_AT001_PSSR 0x11
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_MASK 0x2040
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Link partner ability register. */
+#define MII_LPA_SLCT 0x001f /* Same as advertise selector */
+#define MII_LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
+#define MII_LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
+#define MII_LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
+#define MII_LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
+#define MII_LPA_100BASE4 0x0200 /* 100BASE-T4 */
+#define MII_LPA_PAUSE 0x0400 /* PAUSE */
+#define MII_LPA_ASYPAUSE 0x0800 /* Asymmetrical PAUSE */
+#define MII_LPA_RFAULT 0x2000 /* Link partner faulted */
+#define MII_LPA_LPACK 0x4000 /* Link partner acked us */
+#define MII_LPA_NPAGE 0x8000 /* Next page bit */
+
+/* Autoneg Advertisement Register */
+#define MII_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
+#define MII_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define MII_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define MII_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define MII_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define MII_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
+#define MII_AR_PAUSE 0x0400 /* Pause operation desired */
+#define MII_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+#define MII_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
+#define MII_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+#define MII_AR_SPEED_MASK 0x01E0
+#define MII_AR_DEFAULT_CAP_MASK 0x0DE0
+
+/* 1000BASE-T Control Register */
+#define MII_AT001_CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define MII_AT001_CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+#define MII_AT001_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port, 0=DTE device */
+#define MII_AT001_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master, 0=Configure PHY as Slave */
+#define MII_AT001_CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value, 0=Automatic Master/Slave config */
+#define MII_AT001_CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define MII_AT001_CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
+#define MII_AT001_CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
+#define MII_AT001_CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
+#define MII_AT001_CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
+#define MII_AT001_CR_1000T_SPEED_MASK 0x0300
+#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK 0x0300
+
+/* 1000BASE-T Status Register */
+#define MII_AT001_SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
+#define MII_AT001_SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
+#define MII_AT001_SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define MII_AT001_SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+#define MII_AT001_SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */
+#define MII_AT001_SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
+#define MII_AT001_SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define MII_AT001_SR_1000T_LOCAL_RX_STATUS_SHIFT 13
+
+/* Extended Status Register */
+#define MII_AT001_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define MII_AT001_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define MII_AT001_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define MII_AT001_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+/* AT001 PHY Specific Control Register */
+#define MII_AT001_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */
+#define MII_AT001_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define MII_AT001_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */
+#define MII_AT001_PSCR_MAC_POWERDOWN 0x0008
+#define MII_AT001_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, 0=CLK125 toggling */
+#define MII_AT001_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5, Manual MDI configuration */
+#define MII_AT001_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
+#define MII_AT001_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define MII_AT001_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled all speeds. */
+#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE 0x0080 /* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold), 0=Normal 10BASE-T RX Threshold */
+#define MII_AT001_PSCR_MII_5BIT_ENABLE 0x0100 /* 1=5-Bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define MII_AT001_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */
+#define MII_AT001_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */
+#define MII_AT001_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
+#define MII_AT001_PSCR_POLARITY_REVERSAL_SHIFT 1
+#define MII_AT001_PSCR_AUTO_X_MODE_SHIFT 5
+#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* AT001 PHY Specific Status Register */
+#define MII_AT001_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
+#define MII_AT001_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
+#define MII_AT001_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
+#define MII_AT001_PSSR_10MBS 0x0000 /* 00=10Mbs */
+#define MII_AT001_PSSR_100MBS 0x4000 /* 01=100Mbs */
+#define MII_AT001_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+
+/* PCI Command Register Bit Definitions */
+#define PCI_REG_COMMAND 0x04 /* PCI Command Register */
+#define CMD_IO_SPACE 0x0001
+#define CMD_MEMORY_SPACE 0x0002
+#define CMD_BUS_MASTER 0x0004
+
+/* Wake Up Filter Control */
+#define ATL1_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define ATL1_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
+#define ATL1_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
+#define ATL1_WUFC_MC 0x00000008 /* Multicast Wakeup Enable */
+#define ATL1_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
+
+/* Error Codes */
+#define ATL1_SUCCESS 0
+#define ATL1_ERR_EEPROM 1
+#define ATL1_ERR_PHY 2
+#define ATL1_ERR_CONFIG 3
+#define ATL1_ERR_PARAM 4
+#define ATL1_ERR_MAC_TYPE 5
+#define ATL1_ERR_PHY_TYPE 6
+#define ATL1_ERR_PHY_SPEED 7
+#define ATL1_ERR_PHY_RES 8
+
+#define SPEED_0 0xffff
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+#define MEDIA_TYPE_AUTO_SENSOR 0
+#define MEDIA_TYPE_1000M_FULL 1
+#define MEDIA_TYPE_100M_FULL 2
+#define MEDIA_TYPE_100M_HALF 3
+#define MEDIA_TYPE_10M_FULL 4
+#define MEDIA_TYPE_10M_HALF 5
+
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
+#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds */
+#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds */
+
+/* The size (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE 14
+#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */
+#define ETHERNET_FCS_SIZE 4
+#define MAX_JUMBO_FRAME_SIZE 0x2800
+
+#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */
+#define PHY_FORCE_TIME 20 /* 2.0 Seconds */
+
+/* For checksumming , the sum of all words in the EEPROM should equal 0xBABA */
+#define EEPROM_SUM 0xBABA
+
+#define ATL1_EEDUMP_LEN 48
+
+/* Statistics counters collected by the MAC */
+struct stats_msg_block {
+ /* rx */
+ u32 rx_ok; /* The number of good packet received. */
+ u32 rx_bcast; /* The number of good broadcast packet received. */
+ u32 rx_mcast; /* The number of good multicast packet received. */
+ u32 rx_pause; /* The number of Pause packet received. */
+ u32 rx_ctrl; /* The number of Control packet received other than Pause frame. */
+ u32 rx_fcs_err; /* The number of packets with bad FCS. */
+ u32 rx_len_err; /* The number of packets with mismatch of length field and actual size. */
+ u32 rx_byte_cnt; /* The number of bytes of good packet received. FCS is NOT included. */
+ u32 rx_runt; /* The number of packets received that are less than 64 byte long and with good FCS. */
+ u32 rx_frag; /* The number of packets received that are less than 64 byte long and with bad FCS. */
+ u32 rx_sz_64; /* The number of good and bad packets received that are 64 byte long. */
+ u32 rx_sz_65_127; /* The number of good and bad packets received that are between 65 and 127-byte long. */
+ u32 rx_sz_128_255; /* The number of good and bad packets received that are between 128 and 255-byte long. */
+ u32 rx_sz_256_511; /* The number of good and bad packets received that are between 256 and 511-byte long. */
+ u32 rx_sz_512_1023; /* The number of good and bad packets received that are between 512 and 1023-byte long. */
+ u32 rx_sz_1024_1518; /* The number of good and bad packets received that are between 1024 and 1518-byte long. */
+ u32 rx_sz_1519_max; /* The number of good and bad packets received that are between 1519-byte and MTU. */
+ u32 rx_sz_ov; /* The number of good and bad packets received that are more than MTU size Å¡C truncated by Selene. */
+ u32 rx_rxf_ov; /* The number of frame dropped due to occurrence of RX FIFO overflow. */
+ u32 rx_rrd_ov; /* The number of frame dropped due to occurrence of RRD overflow. */
+ u32 rx_align_err; /* Alignment Error */
+ u32 rx_bcast_byte_cnt; /* The byte count of broadcast packet received, excluding FCS. */
+ u32 rx_mcast_byte_cnt; /* The byte count of multicast packet received, excluding FCS. */
+ u32 rx_err_addr; /* The number of packets dropped due to address filtering. */
+
+ /* tx */
+ u32 tx_ok; /* The number of good packet transmitted. */
+ u32 tx_bcast; /* The number of good broadcast packet transmitted. */
+ u32 tx_mcast; /* The number of good multicast packet transmitted. */
+ u32 tx_pause; /* The number of Pause packet transmitted. */
+ u32 tx_exc_defer; /* The number of packets transmitted with excessive deferral. */
+ u32 tx_ctrl; /* The number of packets transmitted is a control frame, excluding Pause frame. */
+ u32 tx_defer; /* The number of packets transmitted that is deferred. */
+ u32 tx_byte_cnt; /* The number of bytes of data transmitted. FCS is NOT included. */
+ u32 tx_sz_64; /* The number of good and bad packets transmitted that are 64 byte long. */
+ u32 tx_sz_65_127; /* The number of good and bad packets transmitted that are between 65 and 127-byte long. */
+ u32 tx_sz_128_255; /* The number of good and bad packets transmitted that are between 128 and 255-byte long. */
+ u32 tx_sz_256_511; /* The number of good and bad packets transmitted that are between 256 and 511-byte long. */
+ u32 tx_sz_512_1023; /* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */
+ u32 tx_sz_1024_1518; /* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */
+ u32 tx_sz_1519_max; /* The number of good and bad packets transmitted that are between 1519-byte and MTU. */
+ u32 tx_1_col; /* The number of packets subsequently transmitted successfully with a single prior collision. */
+ u32 tx_2_col; /* The number of packets subsequently transmitted successfully with multiple prior collisions. */
+ u32 tx_late_col; /* The number of packets transmitted with late collisions. */
+ u32 tx_abort_col; /* The number of transmit packets aborted due to excessive collisions. */
+ u32 tx_underrun; /* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
+ u32 tx_rd_eop; /* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */
+ u32 tx_len_err; /* The number of transmit packets with length field does NOT match the actual frame size. */
+ u32 tx_trunc; /* The number of transmit packets truncated due to size exceeding MTU. */
+ u32 tx_bcast_byte; /* The byte count of broadcast packet transmitted, excluding FCS. */
+ u32 tx_mcast_byte; /* The byte count of multicast packet transmitted, excluding FCS. */
+ u32 smb_updated; /* 1: SMB Updated. This is used by software as the indication of the statistics update.
+ * Software should clear this bit as soon as retrieving the statistics information. */
+};
+
+/* Coalescing Message Block */
+struct coals_msg_block {
+ u32 int_stats; /* interrupt status */
+ u16 rrd_prod_idx; /* TRD Producer Index. */
+ u16 rfd_cons_idx; /* RFD Consumer Index. */
+ u16 update; /* Selene sets this bit every time it DMA the CMB to host memory.
+ * Software supposes to clear this bit when CMB information is processed. */
+ u16 tpd_cons_idx; /* TPD Consumer Index. */
+};
+
+/* RRD descriptor */
+struct rx_return_desc {
+ u8 num_buf; /* Number of RFD buffers used by the received packet */
+ u8 resved;
+ u16 buf_indx; /* RFD Index of the first buffer */
+ union {
+ u32 valid;
+ struct {
+ u16 rx_chksum;
+ u16 pkt_size;
+ } xsum_sz;
+ } xsz;
+
+ u16 pkt_flg; /* Packet flags */
+ u16 err_flg; /* Error flags */
+ u16 resved2;
+ u16 vlan_tag; /* VLAN TAG */
+};
+
+#define PACKET_FLAG_ETH_TYPE 0x0080
+#define PACKET_FLAG_VLAN_INS 0x0100
+#define PACKET_FLAG_ERR 0x0200
+#define PACKET_FLAG_IPV4 0x0400
+#define PACKET_FLAG_UDP 0x0800
+#define PACKET_FLAG_TCP 0x1000
+#define PACKET_FLAG_BCAST 0x2000
+#define PACKET_FLAG_MCAST 0x4000
+#define PACKET_FLAG_PAUSE 0x8000
+
+#define ERR_FLAG_CRC 0x0001
+#define ERR_FLAG_CODE 0x0002
+#define ERR_FLAG_DRIBBLE 0x0004
+#define ERR_FLAG_RUNT 0x0008
+#define ERR_FLAG_OV 0x0010
+#define ERR_FLAG_TRUNC 0x0020
+#define ERR_FLAG_IP_CHKSUM 0x0040
+#define ERR_FLAG_L4_CHKSUM 0x0080
+#define ERR_FLAG_LEN 0x0100
+#define ERR_FLAG_DES_ADDR 0x0200
+
+/* RFD descriptor */
+struct rx_free_desc {
+ __le64 buffer_addr; /* Address of the descriptor's data buffer */
+ __le16 buf_len; /* Size of the receive buffer in host memory, in byte */
+ u16 coalese; /* Update consumer index to host after the reception of this frame */
+ /* __attribute__ ((packed)) is required */
+} __attribute__ ((packed));
+
+/* tsopu defines */
+#define TSO_PARAM_BUFLEN_MASK 0x3FFF
+#define TSO_PARAM_BUFLEN_SHIFT 0
+#define TSO_PARAM_DMAINT_MASK 0x0001
+#define TSO_PARAM_DMAINT_SHIFT 14
+#define TSO_PARAM_PKTNT_MASK 0x0001
+#define TSO_PARAM_PKTINT_SHIFT 15
+#define TSO_PARAM_VLANTAG_MASK 0xFFFF
+#define TSO_PARAM_VLAN_SHIFT 16
+
+/* tsopl defines */
+#define TSO_PARAM_EOP_MASK 0x0001
+#define TSO_PARAM_EOP_SHIFT 0
+#define TSO_PARAM_COALESCE_MASK 0x0001
+#define TSO_PARAM_COALESCE_SHIFT 1
+#define TSO_PARAM_INSVLAG_MASK 0x0001
+#define TSO_PARAM_INSVLAG_SHIFT 2
+#define TSO_PARAM_CUSTOMCKSUM_MASK 0x0001
+#define TSO_PARAM_CUSTOMCKSUM_SHIFT 3
+#define TSO_PARAM_SEGMENT_MASK 0x0001
+#define TSO_PARAM_SEGMENT_SHIFT 4
+#define TSO_PARAM_IPCKSUM_MASK 0x0001
+#define TSO_PARAM_IPCKSUM_SHIFT 5
+#define TSO_PARAM_TCPCKSUM_MASK 0x0001
+#define TSO_PARAM_TCPCKSUM_SHIFT 6
+#define TSO_PARAM_UDPCKSUM_MASK 0x0001
+#define TSO_PARAM_UDPCKSUM_SHIFT 7
+#define TSO_PARAM_VLANTAGGED_MASK 0x0001
+#define TSO_PARAM_VLANTAGGED_SHIFT 8
+#define TSO_PARAM_ETHTYPE_MASK 0x0001
+#define TSO_PARAM_ETHTYPE_SHIFT 9
+#define TSO_PARAM_IPHL_MASK 0x000F
+#define TSO_PARAM_IPHL_SHIFT 10
+#define TSO_PARAM_TCPHDRLEN_MASK 0x000F
+#define TSO_PARAM_TCPHDRLEN_SHIFT 14
+#define TSO_PARAM_HDRFLAG_MASK 0x0001
+#define TSO_PARAM_HDRFLAG_SHIFT 18
+#define TSO_PARAM_MSS_MASK 0x1FFF
+#define TSO_PARAM_MSS_SHIFT 19
+
+/* csumpu defines */
+#define CSUM_PARAM_BUFLEN_MASK 0x3FFF
+#define CSUM_PARAM_BUFLEN_SHIFT 0
+#define CSUM_PARAM_DMAINT_MASK 0x0001
+#define CSUM_PARAM_DMAINT_SHIFT 14
+#define CSUM_PARAM_PKTINT_MASK 0x0001
+#define CSUM_PARAM_PKTINT_SHIFT 15
+#define CSUM_PARAM_VALANTAG_MASK 0xFFFF
+#define CSUM_PARAM_VALAN_SHIFT 16
+
+/* csumpl defines*/
+#define CSUM_PARAM_EOP_MASK 0x0001
+#define CSUM_PARAM_EOP_SHIFT 0
+#define CSUM_PARAM_COALESCE_MASK 0x0001
+#define CSUM_PARAM_COALESCE_SHIFT 1
+#define CSUM_PARAM_INSVLAG_MASK 0x0001
+#define CSUM_PARAM_INSVLAG_SHIFT 2
+#define CSUM_PARAM_CUSTOMCKSUM_MASK 0x0001
+#define CSUM_PARAM_CUSTOMCKSUM_SHIFT 3
+#define CSUM_PARAM_SEGMENT_MASK 0x0001
+#define CSUM_PARAM_SEGMENT_SHIFT 4
+#define CSUM_PARAM_IPCKSUM_MASK 0x0001
+#define CSUM_PARAM_IPCKSUM_SHIFT 5
+#define CSUM_PARAM_TCPCKSUM_MASK 0x0001
+#define CSUM_PARAM_TCPCKSUM_SHIFT 6
+#define CSUM_PARAM_UDPCKSUM_MASK 0x0001
+#define CSUM_PARAM_UDPCKSUM_SHIFT 7
+#define CSUM_PARAM_VLANTAGGED_MASK 0x0001
+#define CSUM_PARAM_VLANTAGGED_SHIFT 8
+#define CSUM_PARAM_ETHTYPE_MASK 0x0001
+#define CSUM_PARAM_ETHTYPE_SHIFT 9
+#define CSUM_PARAM_IPHL_MASK 0x000F
+#define CSUM_PARAM_IPHL_SHIFT 10
+#define CSUM_PARAM_PLOADOFFSET_MASK 0x00FF
+#define CSUM_PARAM_PLOADOFFSET_SHIFT 16
+#define CSUM_PARAM_XSUMOFFSET_MASK 0x00FF
+#define CSUM_PARAM_XSUMOFFSET_SHIFT 24
+
+/* TPD descriptor */
+struct tso_param {
+ /* The order of these declarations is important -- don't change it */
+ u32 tsopu; /* tso_param upper word */
+ u32 tsopl; /* tso_param lower word */
+};
+
+struct csum_param {
+ /* The order of these declarations is important -- don't change it */
+ u32 csumpu; /* csum_param upper word */
+ u32 csumpl; /* csum_param lower word */
+};
+
+union tpd_descr {
+ u64 data;
+ struct csum_param csum;
+ struct tso_param tso;
+};
+
+struct tx_packet_desc {
+ __le64 buffer_addr;
+ union tpd_descr desc;
+};
+
+/* DMA Order Settings */
+enum atl1_dma_order {
+ atl1_dma_ord_in = 1,
+ atl1_dma_ord_enh = 2,
+ atl1_dma_ord_out = 4
+};
+
+enum atl1_dma_rcb {
+ atl1_rcb_64 = 0,
+ atl1_rcb_128 = 1
+};
+
+enum atl1_dma_req_block {
+ atl1_dma_req_128 = 0,
+ atl1_dma_req_256 = 1,
+ atl1_dma_req_512 = 2,
+ atl1_dam_req_1024 = 3,
+ atl1_dam_req_2048 = 4,
+ atl1_dma_req_4096 = 5
+};
+
+struct atl1_spi_flash_dev {
+ const char *manu_name; /* manufacturer id */
+ /* op-code */
+ u8 cmd_wrsr;
+ u8 cmd_read;
+ u8 cmd_program;
+ u8 cmd_wren;
+ u8 cmd_wrdi;
+ u8 cmd_rdsr;
+ u8 cmd_rdid;
+ u8 cmd_sector_erase;
+ u8 cmd_chip_erase;
+};
+
+#endif /* _ATL1_HW_H_ */
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
new file mode 100644
index 00000000000..6655640eb4c
--- /dev/null
+++ b/drivers/net/atl1/atl1_main.c
@@ -0,0 +1,2468 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 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
+ * 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 COPYING.
+ *
+ * Contact Information:
+ * Xiong Huang <xiong_huang@attansic.com>
+ * Attansic Technology Corp. 3F 147, Xianzheng 9th Road, Zhubei,
+ * Xinzhu 302, TAIWAN, REPUBLIC OF CHINA
+ *
+ * Chris Snook <csnook@redhat.com>
+ * Jay Cliburn <jcliburn@gmail.com>
+ *
+ * This version is adapted from the Attansic reference driver for
+ * inclusion in the Linux kernel. It is currently under heavy development.
+ * A very incomplete list of things that need to be dealt with:
+ *
+ * TODO:
+ * Fix TSO; tx performance is horrible with TSO enabled.
+ * Wake on LAN.
+ * Add more ethtool functions, including set ring parameters.
+ * Fix abstruse irq enable/disable condition described here:
+ * http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2
+ *
+ * NEEDS TESTING:
+ * VLAN
+ * multicast
+ * promiscuous mode
+ * interrupt coalescing
+ * SMP torture testing
+ */
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/irqreturn.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
+#include <linux/irqflags.h>
+#include <linux/dma-mapping.h>
+#include <linux/net.h>
+#include <linux/pm.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include <net/checksum.h>
+
+#include <asm/atomic.h>
+#include <asm/byteorder.h>
+
+#include "atl1.h"
+
+#define RUN_REALTIME 0
+#define DRIVER_VERSION "2.0.6"
+
+char atl1_driver_name[] = "atl1";
+static const char atl1_driver_string[] = "Attansic L1 Ethernet Network Driver";
+static const char atl1_copyright[] = "Copyright(c) 2005-2006 Attansic Corporation.";
+char atl1_driver_version[] = DRIVER_VERSION;
+
+MODULE_AUTHOR
+ ("Attansic Corporation <xiong_huang@attansic.com>, Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>");
+MODULE_DESCRIPTION("Attansic 1000M Ethernet Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+/*
+ * atl1_pci_tbl - PCI Device ID Table
+ */
+static const struct pci_device_id atl1_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1048)},
+ /* required last entry */
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, atl1_pci_tbl);
+
+/*
+ * atl1_sw_init - Initialize general software structures (struct atl1_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * atl1_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ */
+static int __devinit atl1_sw_init(struct atl1_adapter *adapter)
+{
+ struct atl1_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+
+ /* PCI config space info */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+
+ hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+ hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
+
+ adapter->wol = 0;
+ adapter->rx_buffer_len = (hw->max_frame_size + 7) & ~7;
+ adapter->ict = 50000; /* 100ms */
+ adapter->link_speed = SPEED_0; /* hardware init */
+ adapter->link_duplex = FULL_DUPLEX;
+
+ hw->phy_configured = false;
+ hw->preamble_len = 7;
+ hw->ipgt = 0x60;
+ hw->min_ifg = 0x50;
+ hw->ipgr1 = 0x40;
+ hw->ipgr2 = 0x60;
+ hw->max_retry = 0xf;
+ hw->lcol = 0x37;
+ hw->jam_ipg = 7;
+ hw->rfd_burst = 8;
+ hw->rrd_burst = 8;
+ hw->rfd_fetch_gap = 1;
+ hw->rx_jumbo_th = adapter->rx_buffer_len / 8;
+ hw->rx_jumbo_lkah = 1;
+ hw->rrd_ret_timer = 16;
+ hw->tpd_burst = 4;
+ hw->tpd_fetch_th = 16;
+ hw->txf_burst = 0x100;
+ hw->tx_jumbo_task_th = (hw->max_frame_size + 7) >> 3;
+ hw->tpd_fetch_gap = 1;
+ hw->rcb_value = atl1_rcb_64;
+ hw->dma_ord = atl1_dma_ord_enh;
+ hw->dmar_block = atl1_dma_req_256;
+ hw->dmaw_block = atl1_dma_req_256;
+ hw->cmb_rrd = 4;
+ hw->cmb_tpd = 4;
+ hw->cmb_rx_timer = 1; /* about 2us */
+ hw->cmb_tx_timer = 1; /* about 2us */
+ hw->smb_timer = 100000; /* about 200ms */
+
+ atomic_set(&adapter->irq_sem, 0);
+ spin_lock_init(&adapter->lock);
+ spin_lock_init(&adapter->mb_lock);
+
+ return 0;
+}
+
+/*
+ * atl1_setup_mem_resources - allocate Tx / RX descriptor resources
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
+{
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_ring_header *ring_header = &adapter->ring_header;
+ struct pci_dev *pdev = adapter->pdev;
+ int size;
+ u8 offset = 0;
+
+ size = sizeof(struct atl1_buffer) * (tpd_ring->count + rfd_ring->count);
+ tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
+ if (unlikely(!tpd_ring->buffer_info)) {
+ printk(KERN_WARNING "%s: kzalloc failed , size = D%d\n",
+ atl1_driver_name, size);
+ goto err_nomem;
+ }
+ rfd_ring->buffer_info =
+ (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count);
+
+ /* real ring DMA buffer */
+ ring_header->size = size = sizeof(struct tx_packet_desc) *
+ tpd_ring->count
+ + sizeof(struct rx_free_desc) * rfd_ring->count
+ + sizeof(struct rx_return_desc) * rrd_ring->count
+ + sizeof(struct coals_msg_block)
+ + sizeof(struct stats_msg_block)
+ + 40; /* "40: for 8 bytes align" huh? -- CHS */
+
+ ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
+ &ring_header->dma);
+ if (unlikely(!ring_header->desc)) {
+ printk(KERN_WARNING
+ "%s: pci_alloc_consistent failed, size = D%d\n",
+ atl1_driver_name, size);
+ goto err_nomem;
+ }
+
+ memset(ring_header->desc, 0, ring_header->size);
+
+ /* init TPD ring */
+ tpd_ring->dma = ring_header->dma;
+ offset = (tpd_ring->dma & 0x7) ? (8 - (ring_header->dma & 0x7)) : 0;
+ tpd_ring->dma += offset;
+ tpd_ring->desc = (u8 *) ring_header->desc + offset;
+ tpd_ring->size = sizeof(struct tx_packet_desc) * tpd_ring->count;
+ atomic_set(&tpd_ring->next_to_use, 0);
+ atomic_set(&tpd_ring->next_to_clean, 0);
+
+ /* init RFD ring */
+ rfd_ring->dma = tpd_ring->dma + tpd_ring->size;
+ offset = (rfd_ring->dma & 0x7) ? (8 - (rfd_ring->dma & 0x7)) : 0;
+ rfd_ring->dma += offset;
+ rfd_ring->desc = (u8 *) tpd_ring->desc + (tpd_ring->size + offset);
+ rfd_ring->size = sizeof(struct rx_free_desc) * rfd_ring->count;
+ rfd_ring->next_to_clean = 0;
+ /* rfd_ring->next_to_use = rfd_ring->count - 1; */
+ atomic_set(&rfd_ring->next_to_use, 0);
+
+ /* init RRD ring */
+ rrd_ring->dma = rfd_ring->dma + rfd_ring->size;
+ offset = (rrd_ring->dma & 0x7) ? (8 - (rrd_ring->dma & 0x7)) : 0;
+ rrd_ring->dma += offset;
+ rrd_ring->desc = (u8 *) rfd_ring->desc + (rfd_ring->size + offset);
+ rrd_ring->size = sizeof(struct rx_return_desc) * rrd_ring->count;
+ rrd_ring->next_to_use = 0;
+ atomic_set(&rrd_ring->next_to_clean, 0);
+
+ /* init CMB */
+ adapter->cmb.dma = rrd_ring->dma + rrd_ring->size;
+ offset = (adapter->cmb.dma & 0x7) ? (8 - (adapter->cmb.dma & 0x7)) : 0;
+ adapter->cmb.dma += offset;
+ adapter->cmb.cmb =
+ (struct coals_msg_block *) ((u8 *) rrd_ring->desc +
+ (rrd_ring->size + offset));
+
+ /* init SMB */
+ adapter->smb.dma = adapter->cmb.dma + sizeof(struct coals_msg_block);
+ offset = (adapter->smb.dma & 0x7) ? (8 - (adapter->smb.dma & 0x7)) : 0;
+ adapter->smb.dma += offset;
+ adapter->smb.smb = (struct stats_msg_block *)
+ ((u8 *) adapter->cmb.cmb + (sizeof(struct coals_msg_block) + offset));
+
+ return ATL1_SUCCESS;
+
+err_nomem:
+ kfree(tpd_ring->buffer_info);
+ return -ENOMEM;
+}
+
+/*
+ * atl1_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ */
+static void atl1_irq_enable(struct atl1_adapter *adapter)
+{
+ if (likely(!atomic_dec_and_test(&adapter->irq_sem)))
+ iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR);
+}
+
+static void atl1_clear_phy_int(struct atl1_adapter *adapter)
+{
+ u16 phy_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ atl1_read_phy_reg(&adapter->hw, 19, &phy_data);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+static void atl1_inc_smb(struct atl1_adapter *adapter)
+{
+ struct stats_msg_block *smb = adapter->smb.smb;
+
+ /* Fill out the OS statistics structure */
+ adapter->soft_stats.rx_packets += smb->rx_ok;
+ adapter->soft_stats.tx_packets += smb->tx_ok;
+ adapter->soft_stats.rx_bytes += smb->rx_byte_cnt;
+ adapter->soft_stats.tx_bytes += smb->tx_byte_cnt;
+ adapter->soft_stats.multicast += smb->rx_mcast;
+ adapter->soft_stats.collisions += (smb->tx_1_col +
+ smb->tx_2_col * 2 +
+ smb->tx_late_col +
+ smb->tx_abort_col *
+ adapter->hw.max_retry);
+
+ /* Rx Errors */
+ adapter->soft_stats.rx_errors += (smb->rx_frag +
+ smb->rx_fcs_err +
+ smb->rx_len_err +
+ smb->rx_sz_ov +
+ smb->rx_rxf_ov +
+ smb->rx_rrd_ov + smb->rx_align_err);
+ adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov;
+ adapter->soft_stats.rx_length_errors += smb->rx_len_err;
+ adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err;
+ adapter->soft_stats.rx_frame_errors += smb->rx_align_err;
+ adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov +
+ smb->rx_rxf_ov);
+
+ adapter->soft_stats.rx_pause += smb->rx_pause;
+ adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov;
+ adapter->soft_stats.rx_trunc += smb->rx_sz_ov;
+
+ /* Tx Errors */
+ adapter->soft_stats.tx_errors += (smb->tx_late_col +
+ smb->tx_abort_col +
+ smb->tx_underrun + smb->tx_trunc);
+ adapter->soft_stats.tx_fifo_errors += smb->tx_underrun;
+ adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col;
+ adapter->soft_stats.tx_window_errors += smb->tx_late_col;
+
+ adapter->soft_stats.excecol += smb->tx_abort_col;
+ adapter->soft_stats.deffer += smb->tx_defer;
+ adapter->soft_stats.scc += smb->tx_1_col;
+ adapter->soft_stats.mcc += smb->tx_2_col;
+ adapter->soft_stats.latecol += smb->tx_late_col;
+ adapter->soft_stats.tx_underun += smb->tx_underrun;
+ adapter->soft_stats.tx_trunc += smb->tx_trunc;
+ adapter->soft_stats.tx_pause += smb->tx_pause;
+
+ adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets;
+ adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets;
+ adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes;
+ adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes;
+ adapter->net_stats.multicast = adapter->soft_stats.multicast;
+ adapter->net_stats.collisions = adapter->soft_stats.collisions;
+ adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors;
+ adapter->net_stats.rx_over_errors =
+ adapter->soft_stats.rx_missed_errors;
+ adapter->net_stats.rx_length_errors =
+ adapter->soft_stats.rx_length_errors;
+ adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors;
+ adapter->net_stats.rx_frame_errors =
+ adapter->soft_stats.rx_frame_errors;
+ adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors;
+ adapter->net_stats.rx_missed_errors =
+ adapter->soft_stats.rx_missed_errors;
+ adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors;
+ adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors;
+ adapter->net_stats.tx_aborted_errors =
+ adapter->soft_stats.tx_aborted_errors;
+ adapter->net_stats.tx_window_errors =
+ adapter->soft_stats.tx_window_errors;
+ adapter->net_stats.tx_carrier_errors =
+ adapter->soft_stats.tx_carrier_errors;
+}
+
+static void atl1_rx_checksum(struct atl1_adapter *adapter,
+ struct rx_return_desc *rrd,
+ struct sk_buff *skb)
+{
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
+ if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC |
+ ERR_FLAG_CODE | ERR_FLAG_OV)) {
+ adapter->hw_csum_err++;
+ printk(KERN_DEBUG "%s: rx checksum error\n",
+ atl1_driver_name);
+ return;
+ }
+ }
+
+ /* not IPv4 */
+ if (!(rrd->pkt_flg & PACKET_FLAG_IPV4))
+ /* checksum is invalid, but it's not an IPv4 pkt, so ok */
+ return;
+
+ /* IPv4 packet */
+ if (likely(!(rrd->err_flg &
+ (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM)))) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ adapter->hw_csum_good++;
+ return;
+ }
+
+ /* IPv4, but hardware thinks its checksum is wrong */
+ printk(KERN_DEBUG "%s: hw csum wrong pkt_flag:%x, err_flag:%x\n",
+ atl1_driver_name, rrd->pkt_flg, rrd->err_flg);
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum);
+ adapter->hw_csum_err++;
+ return;
+}
+
+/*
+ * atl1_alloc_rx_buffers - Replace used receive buffers
+ * @adapter: address of board private structure
+ */
+static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
+{
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct page *page;
+ unsigned long offset;
+ struct atl1_buffer *buffer_info, *next_info;
+ struct sk_buff *skb;
+ u16 num_alloc = 0;
+ u16 rfd_next_to_use, next_next;
+ struct rx_free_desc *rfd_desc;
+
+ next_next = rfd_next_to_use = atomic_read(&rfd_ring->next_to_use);
+ if (++next_next == rfd_ring->count)
+ next_next = 0;
+ buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+ next_info = &rfd_ring->buffer_info[next_next];
+
+ while (!buffer_info->alloced && !next_info->alloced) {
+ if (buffer_info->skb) {
+ buffer_info->alloced = 1;
+ goto next;
+ }
+
+ rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use);
+
+ skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);
+ if (unlikely(!skb)) { /* Better luck next round */
+ adapter->net_stats.rx_dropped++;
+ break;
+ }
+
+ /*
+ * Make buffer alignment 2 beyond a 16 byte boundary
+ * this will result in a 16 byte aligned IP header after
+ * the 14 byte MAC header is removed
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb->dev = netdev;
+
+ buffer_info->alloced = 1;
+ buffer_info->skb = skb;
+ buffer_info->length = (u16) adapter->rx_buffer_len;
+ page = virt_to_page(skb->data);
+ offset = (unsigned long)skb->data & ~PAGE_MASK;
+ buffer_info->dma = pci_map_page(pdev, page, offset,
+ adapter->rx_buffer_len,
+ PCI_DMA_FROMDEVICE);
+ rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+ rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len);
+ rfd_desc->coalese = 0;
+
+next:
+ rfd_next_to_use = next_next;
+ if (unlikely(++next_next == rfd_ring->count))
+ next_next = 0;
+
+ buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+ next_info = &rfd_ring->buffer_info[next_next];
+ num_alloc++;
+ }
+
+ if (num_alloc) {
+ /*
+ * Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64).
+ */
+ wmb();
+ atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use);
+ }
+ return num_alloc;
+}
+
+static void atl1_intr_rx(struct atl1_adapter *adapter)
+{
+ int i, count;
+ u16 length;
+ u16 rrd_next_to_clean;
+ u32 value;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_buffer *buffer_info;
+ struct rx_return_desc *rrd;
+ struct sk_buff *skb;
+
+ count = 0;
+
+ rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean);
+
+ while (1) {
+ rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean);
+ i = 1;
+ if (likely(rrd->xsz.valid)) { /* packet valid */
+chk_rrd:
+ /* check rrd status */
+ if (likely(rrd->num_buf == 1))
+ goto rrd_ok;
+
+ /* rrd seems to be bad */
+ if (unlikely(i-- > 0)) {
+ /* rrd may not be DMAed completely */
+ printk(KERN_DEBUG
+ "%s: RRD may not be DMAed completely\n",
+ atl1_driver_name);
+ udelay(1);
+ goto chk_rrd;
+ }
+ /* bad rrd */
+ printk(KERN_DEBUG "%s: bad RRD\n", atl1_driver_name);
+ /* see if update RFD index */
+ if (rrd->num_buf > 1) {
+ u16 num_buf;
+ num_buf =
+ (rrd->xsz.xsum_sz.pkt_size +
+ adapter->rx_buffer_len -
+ 1) / adapter->rx_buffer_len;
+ if (rrd->num_buf == num_buf) {
+ /* clean alloc flag for bad rrd */
+ while (rfd_ring->next_to_clean !=
+ (rrd->buf_indx + num_buf)) {
+ rfd_ring->buffer_info[rfd_ring->
+ next_to_clean].alloced = 0;
+ if (++rfd_ring->next_to_clean ==
+ rfd_ring->count) {
+ rfd_ring->
+ next_to_clean = 0;
+ }
+ }
+ }
+ }
+
+ /* update rrd */
+ rrd->xsz.valid = 0;
+ if (++rrd_next_to_clean == rrd_ring->count)
+ rrd_next_to_clean = 0;
+ count++;
+ continue;
+ } else { /* current rrd still not be updated */
+
+ break;
+ }
+rrd_ok:
+ /* clean alloc flag for bad rrd */
+ while (rfd_ring->next_to_clean != rrd->buf_indx) {
+ rfd_ring->buffer_info[rfd_ring->next_to_clean].alloced =
+ 0;
+ if (++rfd_ring->next_to_clean == rfd_ring->count)
+ rfd_ring->next_to_clean = 0;
+ }
+
+ buffer_info = &rfd_ring->buffer_info[rrd->buf_indx];
+ if (++rfd_ring->next_to_clean == rfd_ring->count)
+ rfd_ring->next_to_clean = 0;
+
+ /* update rrd next to clean */
+ if (++rrd_next_to_clean == rrd_ring->count)
+ rrd_next_to_clean = 0;
+ count++;
+
+ if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
+ if (!(rrd->err_flg &
+ (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM
+ | ERR_FLAG_LEN))) {
+ /* packet error, don't need upstream */
+ buffer_info->alloced = 0;
+ rrd->xsz.valid = 0;
+ continue;
+ }
+ }
+
+ /* Good Receive */
+ pci_unmap_page(adapter->pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_FROMDEVICE);
+ skb = buffer_info->skb;
+ length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size);
+
+ skb_put(skb, length - ETHERNET_FCS_SIZE);
+
+ /* Receive Checksum Offload */
+ atl1_rx_checksum(adapter, rrd, skb);
+ skb->protocol = eth_type_trans(skb, adapter->netdev);
+
+ if (adapter->vlgrp && (rrd->pkt_flg & PACKET_FLAG_VLAN_INS)) {
+ u16 vlan_tag = (rrd->vlan_tag >> 4) |
+ ((rrd->vlan_tag & 7) << 13) |
+ ((rrd->vlan_tag & 8) << 9);
+ vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag);
+ } else
+ netif_rx(skb);
+
+ /* let protocol layer free skb */
+ buffer_info->skb = NULL;
+ buffer_info->alloced = 0;
+ rrd->xsz.valid = 0;
+
+ adapter->netdev->last_rx = jiffies;
+ }
+
+ atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean);
+
+ atl1_alloc_rx_buffers(adapter);
+
+ /* update mailbox ? */
+ if (count) {
+ u32 tpd_next_to_use;
+ u32 rfd_next_to_use;
+ u32 rrd_next_to_clean;
+
+ spin_lock(&adapter->mb_lock);
+
+ tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
+ rfd_next_to_use =
+ atomic_read(&adapter->rfd_ring.next_to_use);
+ rrd_next_to_clean =
+ atomic_read(&adapter->rrd_ring.next_to_clean);
+ value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
+ MB_RFD_PROD_INDX_SHIFT) |
+ ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
+ MB_RRD_CONS_INDX_SHIFT) |
+ ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
+ MB_TPD_PROD_INDX_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
+ spin_unlock(&adapter->mb_lock);
+ }
+}
+
+static void atl1_intr_tx(struct atl1_adapter *adapter)
+{
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_buffer *buffer_info;
+ u16 sw_tpd_next_to_clean;
+ u16 cmb_tpd_next_to_clean;
+ u8 update = 0;
+
+ sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+ cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx);
+
+ while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) {
+ struct tx_packet_desc *tpd;
+ update = 1;
+ tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean);
+ buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean];
+ if (buffer_info->dma) {
+ pci_unmap_page(adapter->pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_TODEVICE);
+ buffer_info->dma = 0;
+ }
+
+ if (buffer_info->skb) {
+ dev_kfree_skb_irq(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+ tpd->buffer_addr = 0;
+ tpd->desc.data = 0;
+
+ if (++sw_tpd_next_to_clean == tpd_ring->count)
+ sw_tpd_next_to_clean = 0;
+ }
+ atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean);
+
+ if (netif_queue_stopped(adapter->netdev)
+ && netif_carrier_ok(adapter->netdev))
+ netif_wake_queue(adapter->netdev);
+}
+
+static void atl1_check_for_link(struct atl1_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u16 phy_data = 0;
+
+ spin_lock(&adapter->lock);
+ adapter->phy_timer_pending = false;
+ atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+ atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+ spin_unlock(&adapter->lock);
+
+ /* notify upper layer link down ASAP */
+ if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */
+ if (netif_carrier_ok(netdev)) { /* old link state: Up */
+ printk(KERN_INFO "%s: %s link is down\n",
+ atl1_driver_name, netdev->name);
+ adapter->link_speed = SPEED_0;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ }
+ schedule_work(&adapter->link_chg_task);
+}
+
+/*
+ * atl1_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ */
+static irqreturn_t atl1_intr(int irq, void *data)
+{
+ /*struct atl1_adapter *adapter = ((struct net_device *)data)->priv;*/
+ struct atl1_adapter *adapter = netdev_priv(data);
+ u32 status;
+ u8 update_rx;
+ int max_ints = 10;
+
+ status = adapter->cmb.cmb->int_stats;
+ if (!status)
+ return IRQ_NONE;
+
+ update_rx = 0;
+
+ do {
+ /* clear CMB interrupt status at once */
+ adapter->cmb.cmb->int_stats = 0;
+
+ if (status & ISR_GPHY) /* clear phy status */
+ atl1_clear_phy_int(adapter);
+
+ /* clear ISR status, and Enable CMB DMA/Disable Interrupt */
+ iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR);
+
+ /* check if SMB intr */
+ if (status & ISR_SMB)
+ atl1_inc_smb(adapter);
+
+ /* check if PCIE PHY Link down */
+ if (status & ISR_PHY_LINKDOWN) {
+ printk(KERN_DEBUG "%s: pcie phy link down %x\n",
+ atl1_driver_name, status);
+ if (netif_running(adapter->netdev)) { /* reset MAC */
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ schedule_work(&adapter->pcie_dma_to_rst_task);
+ return IRQ_HANDLED;
+ }
+ }
+
+ /* check if DMA read/write error ? */
+ if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
+ printk(KERN_DEBUG
+ "%s: pcie DMA r/w error (status = 0x%x)\n",
+ atl1_driver_name, status);
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ schedule_work(&adapter->pcie_dma_to_rst_task);
+ return IRQ_HANDLED;
+ }
+
+ /* link event */
+ if (status & ISR_GPHY) {
+ adapter->soft_stats.tx_carrier_errors++;
+ atl1_check_for_link(adapter);
+ }
+
+ /* transmit event */
+ if (status & ISR_CMB_TX)
+ atl1_intr_tx(adapter);
+
+ /* rx exception */
+ if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN |
+ ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
+ ISR_HOST_RRD_OV | ISR_CMB_RX))) {
+ if (status &
+ (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV |
+ ISR_HOST_RFD_UNRUN | ISR_HOST_RRD_OV))
+ printk(KERN_INFO
+ "%s: rx exception: status = 0x%x\n",
+ atl1_driver_name, status);
+ atl1_intr_rx(adapter);
+ }
+
+ if (--max_ints < 0)
+ break;
+
+ } while ((status = adapter->cmb.cmb->int_stats));
+
+ /* re-enable Interrupt */
+ iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR);
+ return IRQ_HANDLED;
+}
+
+/*
+ * atl1_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ */
+static void atl1_set_multi(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+ struct dev_mc_list *mc_ptr;
+ u32 rctl;
+ u32 hash_value;
+
+ /* Check for Promiscuous and All Multicast modes */
+ rctl = ioread32(hw->hw_addr + REG_MAC_CTRL);
+ if (netdev->flags & IFF_PROMISC)
+ rctl |= MAC_CTRL_PROMIS_EN;
+ else if (netdev->flags & IFF_ALLMULTI) {
+ rctl |= MAC_CTRL_MC_ALL_EN;
+ rctl &= ~MAC_CTRL_PROMIS_EN;
+ } else
+ rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
+
+ iowrite32(rctl, hw->hw_addr + REG_MAC_CTRL);
+
+ /* clear the old settings from the multicast hash table */
+ iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE);
+ iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2));
+
+ /* compute mc addresses' hash value ,and put it into hash table */
+ for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+ hash_value = atl1_hash_mc_addr(hw, mc_ptr->dmi_addr);
+ atl1_hash_set(hw, hash_value);
+ }
+}
+
+static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter)
+{
+ u32 value;
+ struct atl1_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ /* Config MAC CTRL Register */
+ value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN;
+ /* duplex */
+ if (FULL_DUPLEX == adapter->link_duplex)
+ value |= MAC_CTRL_DUPLX;
+ /* speed */
+ value |= ((u32) ((SPEED_1000 == adapter->link_speed) ?
+ MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100) <<
+ MAC_CTRL_SPEED_SHIFT);
+ /* flow control */
+ value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW);
+ /* PAD & CRC */
+ value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD);
+ /* preamble length */
+ value |= (((u32) adapter->hw.preamble_len
+ & MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT);
+ /* vlan */
+ if (adapter->vlgrp)
+ value |= MAC_CTRL_RMV_VLAN;
+ /* rx checksum
+ if (adapter->rx_csum)
+ value |= MAC_CTRL_RX_CHKSUM_EN;
+ */
+ /* filter mode */
+ value |= MAC_CTRL_BC_EN;
+ if (netdev->flags & IFF_PROMISC)
+ value |= MAC_CTRL_PROMIS_EN;
+ else if (netdev->flags & IFF_ALLMULTI)
+ value |= MAC_CTRL_MC_ALL_EN;
+ /* value |= MAC_CTRL_LOOPBACK; */
+ iowrite32(value, hw->hw_addr + REG_MAC_CTRL);
+}
+
+static u32 atl1_check_link(struct atl1_adapter *adapter)
+{
+ struct atl1_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ u32 ret_val;
+ u16 speed, duplex, phy_data;
+ int reconfig = 0;
+
+ /* MII_BMSR must read twice */
+ atl1_read_phy_reg(hw, MII_BMSR, &phy_data);
+ atl1_read_phy_reg(hw, MII_BMSR, &phy_data);
+ if (!(phy_data & BMSR_LSTATUS)) { /* link down */
+ if (netif_carrier_ok(netdev)) { /* old link state: Up */
+ printk(KERN_INFO "%s: link is down\n",
+ atl1_driver_name);
+ adapter->link_speed = SPEED_0;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ return ATL1_SUCCESS;
+ }
+
+ /* Link Up */
+ ret_val = atl1_get_speed_and_duplex(hw, &speed, &duplex);
+ if (ret_val)
+ return ret_val;
+
+ switch (hw->media_type) {
+ case MEDIA_TYPE_1000M_FULL:
+ if (speed != SPEED_1000 || duplex != FULL_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_100M_FULL:
+ if (speed != SPEED_100 || duplex != FULL_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ if (speed != SPEED_100 || duplex != HALF_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ if (speed != SPEED_10 || duplex != FULL_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_10M_HALF:
+ if (speed != SPEED_10 || duplex != HALF_DUPLEX)
+ reconfig = 1;
+ break;
+ }
+
+ /* link result is our setting */
+ if (!reconfig) {
+ if (adapter->link_speed != speed
+ || adapter->link_duplex != duplex) {
+ adapter->link_speed = speed;
+ adapter->link_duplex = duplex;
+ atl1_setup_mac_ctrl(adapter);
+ printk(KERN_INFO "%s: %s link is up %d Mbps %s\n",
+ atl1_driver_name, netdev->name,
+ adapter->link_speed,
+ adapter->link_duplex ==
+ FULL_DUPLEX ? "full duplex" : "half duplex");
+ }
+ if (!netif_carrier_ok(netdev)) { /* Link down -> Up */
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+ }
+ return ATL1_SUCCESS;
+ }
+
+ /* change orignal link status */
+ if (netif_carrier_ok(netdev)) {
+ adapter->link_speed = SPEED_0;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+
+ if (hw->media_type != MEDIA_TYPE_AUTO_SENSOR &&
+ hw->media_type != MEDIA_TYPE_1000M_FULL) {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data = MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+ MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF: */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ }
+ atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+ return ATL1_SUCCESS;
+ }
+
+ /* auto-neg, insert timer to re-config phy */
+ if (!adapter->phy_timer_pending) {
+ adapter->phy_timer_pending = true;
+ mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ);
+ }
+
+ return ATL1_SUCCESS;
+}
+
+static void set_flow_ctrl_old(struct atl1_adapter *adapter)
+{
+ u32 hi, lo, value;
+
+ /* RFD Flow Control */
+ value = adapter->rfd_ring.count;
+ hi = value / 16;
+ if (hi < 2)
+ hi = 2;
+ lo = value * 7 / 8;
+
+ value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RXF_PAUSE_THRESH);
+
+ /* RRD Flow Control */
+ value = adapter->rrd_ring.count;
+ lo = value / 16;
+ hi = value * 7 / 8;
+ if (lo < 2)
+ lo = 2;
+ value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RRD_PAUSE_THRESH);
+}
+
+static void set_flow_ctrl_new(struct atl1_hw *hw)
+{
+ u32 hi, lo, value;
+
+ /* RXF Flow Control */
+ value = ioread32(hw->hw_addr + REG_SRAM_RXF_LEN);
+ lo = value / 16;
+ if (lo < 192)
+ lo = 192;
+ hi = value * 7 / 8;
+ if (hi < lo)
+ hi = lo + 16;
+ value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_RXQ_RXF_PAUSE_THRESH);
+
+ /* RRD Flow Control */
+ value = ioread32(hw->hw_addr + REG_SRAM_RRD_LEN);
+ lo = value / 8;
+ hi = value * 7 / 8;
+ if (lo < 2)
+ lo = 2;
+ if (hi < lo)
+ hi = lo + 3;
+ value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_RXQ_RRD_PAUSE_THRESH);
+}
+
+/*
+ * atl1_configure - Configure Transmit&Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx /Rx unit of the MAC after a reset.
+ */
+static u32 atl1_configure(struct atl1_adapter *adapter)
+{
+ struct atl1_hw *hw = &adapter->hw;
+ u32 value;
+
+ /* clear interrupt status */
+ iowrite32(0xffffffff, adapter->hw.hw_addr + REG_ISR);
+
+ /* set MAC Address */
+ value = (((u32) hw->mac_addr[2]) << 24) |
+ (((u32) hw->mac_addr[3]) << 16) |
+ (((u32) hw->mac_addr[4]) << 8) |
+ (((u32) hw->mac_addr[5]));
+ iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR);
+ value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1]));
+ iowrite32(value, hw->hw_addr + (REG_MAC_STA_ADDR + 4));
+
+ /* tx / rx ring */
+
+ /* HI base address */
+ iowrite32((u32) ((adapter->tpd_ring.dma & 0xffffffff00000000ULL) >> 32),
+ hw->hw_addr + REG_DESC_BASE_ADDR_HI);
+ /* LO base address */
+ iowrite32((u32) (adapter->rfd_ring.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_RFD_ADDR_LO);
+ iowrite32((u32) (adapter->rrd_ring.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_RRD_ADDR_LO);
+ iowrite32((u32) (adapter->tpd_ring.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_TPD_ADDR_LO);
+ iowrite32((u32) (adapter->cmb.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_CMB_ADDR_LO);
+ iowrite32((u32) (adapter->smb.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_SMB_ADDR_LO);
+
+ /* element count */
+ value = adapter->rrd_ring.count;
+ value <<= 16;
+ value += adapter->rfd_ring.count;
+ iowrite32(value, hw->hw_addr + REG_DESC_RFD_RRD_RING_SIZE);
+ iowrite32(adapter->tpd_ring.count, hw->hw_addr + REG_DESC_TPD_RING_SIZE);
+
+ /* Load Ptr */
+ iowrite32(1, hw->hw_addr + REG_LOAD_PTR);
+
+ /* config Mailbox */
+ value = ((atomic_read(&adapter->tpd_ring.next_to_use)
+ & MB_TPD_PROD_INDX_MASK) << MB_TPD_PROD_INDX_SHIFT) |
+ ((atomic_read(&adapter->rrd_ring.next_to_clean)
+ & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) |
+ ((atomic_read(&adapter->rfd_ring.next_to_use)
+ & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_MAILBOX);
+
+ /* config IPG/IFG */
+ value = (((u32) hw->ipgt & MAC_IPG_IFG_IPGT_MASK)
+ << MAC_IPG_IFG_IPGT_SHIFT) |
+ (((u32) hw->min_ifg & MAC_IPG_IFG_MIFG_MASK)
+ << MAC_IPG_IFG_MIFG_SHIFT) |
+ (((u32) hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK)
+ << MAC_IPG_IFG_IPGR1_SHIFT) |
+ (((u32) hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK)
+ << MAC_IPG_IFG_IPGR2_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_MAC_IPG_IFG);
+
+ /* config Half-Duplex Control */
+ value = ((u32) hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) |
+ (((u32) hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK)
+ << MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) |
+ MAC_HALF_DUPLX_CTRL_EXC_DEF_EN |
+ (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) |
+ (((u32) hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK)
+ << MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_MAC_HALF_DUPLX_CTRL);
+
+ /* set Interrupt Moderator Timer */
+ iowrite16(adapter->imt, hw->hw_addr + REG_IRQ_MODU_TIMER_INIT);
+ iowrite32(MASTER_CTRL_ITIMER_EN, hw->hw_addr + REG_MASTER_CTRL);
+
+ /* set Interrupt Clear Timer */
+ iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER);
+
+ /* set MTU, 4 : VLAN */
+ iowrite32(hw->max_frame_size + 4, hw->hw_addr + REG_MTU);
+
+ /* jumbo size & rrd retirement timer */
+ value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK)
+ << RXQ_JMBOSZ_TH_SHIFT) |
+ (((u32) hw->rx_jumbo_lkah & RXQ_JMBO_LKAH_MASK)
+ << RXQ_JMBO_LKAH_SHIFT) |
+ (((u32) hw->rrd_ret_timer & RXQ_RRD_TIMER_MASK)
+ << RXQ_RRD_TIMER_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_RXQ_JMBOSZ_RRDTIM);
+
+ /* Flow Control */
+ switch (hw->dev_rev) {
+ case 0x8001:
+ case 0x9001:
+ case 0x9002:
+ case 0x9003:
+ set_flow_ctrl_old(adapter);
+ break;
+ default:
+ set_flow_ctrl_new(hw);
+ break;
+ }
+
+ /* config TXQ */
+ value = (((u32) hw->tpd_burst & TXQ_CTRL_TPD_BURST_NUM_MASK)
+ << TXQ_CTRL_TPD_BURST_NUM_SHIFT) |
+ (((u32) hw->txf_burst & TXQ_CTRL_TXF_BURST_NUM_MASK)
+ << TXQ_CTRL_TXF_BURST_NUM_SHIFT) |
+ (((u32) hw->tpd_fetch_th & TXQ_CTRL_TPD_FETCH_TH_MASK)
+ << TXQ_CTRL_TPD_FETCH_TH_SHIFT) | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN;
+ iowrite32(value, hw->hw_addr + REG_TXQ_CTRL);
+
+ /* min tpd fetch gap & tx jumbo packet size threshold for taskoffload */
+ value = (((u32) hw->tx_jumbo_task_th & TX_JUMBO_TASK_TH_MASK)
+ << TX_JUMBO_TASK_TH_SHIFT) |
+ (((u32) hw->tpd_fetch_gap & TX_TPD_MIN_IPG_MASK)
+ << TX_TPD_MIN_IPG_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_TX_JUMBO_TASK_TH_TPD_IPG);
+
+ /* config RXQ */
+ value = (((u32) hw->rfd_burst & RXQ_CTRL_RFD_BURST_NUM_MASK)
+ << RXQ_CTRL_RFD_BURST_NUM_SHIFT) |
+ (((u32) hw->rrd_burst & RXQ_CTRL_RRD_BURST_THRESH_MASK)
+ << RXQ_CTRL_RRD_BURST_THRESH_SHIFT) |
+ (((u32) hw->rfd_fetch_gap & RXQ_CTRL_RFD_PREF_MIN_IPG_MASK)
+ << RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT) |
+ RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN;
+ iowrite32(value, hw->hw_addr + REG_RXQ_CTRL);
+
+ /* config DMA Engine */
+ value = ((((u32) hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
+ << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
+ ((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
+ << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
+ DMA_CTRL_DMAR_EN | DMA_CTRL_DMAW_EN;
+ value |= (u32) hw->dma_ord;
+ if (atl1_rcb_128 == hw->rcb_value)
+ value |= DMA_CTRL_RCB_VALUE;
+ iowrite32(value, hw->hw_addr + REG_DMA_CTRL);
+
+ /* config CMB / SMB */
+ value = hw->cmb_rrd | ((u32) hw->cmb_tpd << 16);
+ iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TH);
+ value = hw->cmb_rx_timer | ((u32) hw->cmb_tx_timer << 16);
+ iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TIMER);
+ iowrite32(hw->smb_timer, hw->hw_addr + REG_SMB_TIMER);
+
+ /* --- enable CMB / SMB */
+ value = CSMB_CTRL_CMB_EN | CSMB_CTRL_SMB_EN;
+ iowrite32(value, hw->hw_addr + REG_CSMB_CTRL);
+
+ value = ioread32(adapter->hw.hw_addr + REG_ISR);
+ if (unlikely((value & ISR_PHY_LINKDOWN) != 0))
+ value = 1; /* config failed */
+ else
+ value = 0;
+
+ /* clear all interrupt status */
+ iowrite32(0x3fffffff, adapter->hw.hw_addr + REG_ISR);
+ iowrite32(0, adapter->hw.hw_addr + REG_ISR);
+ return value;
+}
+
+/*
+ * atl1_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ */
+static void atl1_irq_disable(struct atl1_adapter *adapter)
+{
+ atomic_inc(&adapter->irq_sem);
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ ioread32(adapter->hw.hw_addr + REG_IMR);
+ synchronize_irq(adapter->pdev->irq);
+}
+
+static void atl1_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+ u32 ctrl;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ /* atl1_irq_disable(adapter); */
+ adapter->vlgrp = grp;
+
+ if (grp) {
+ /* enable VLAN tag insert/strip */
+ ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
+ ctrl |= MAC_CTRL_RMV_VLAN;
+ iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
+ } else {
+ /* disable VLAN tag insert/strip */
+ ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
+ ctrl &= ~MAC_CTRL_RMV_VLAN;
+ iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
+ }
+
+ /* atl1_irq_enable(adapter); */
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+/* FIXME: justify or remove -- CHS */
+static void atl1_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+ /* We don't do Vlan filtering */
+ return;
+}
+
+/* FIXME: this looks wrong too -- CHS */
+static void atl1_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ /* atl1_irq_disable(adapter); */
+ if (adapter->vlgrp)
+ adapter->vlgrp->vlan_devices[vid] = NULL;
+ /* atl1_irq_enable(adapter); */
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ /* We don't do Vlan filtering */
+ return;
+}
+
+static void atl1_restore_vlan(struct atl1_adapter *adapter)
+{
+ atl1_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+ if (adapter->vlgrp) {
+ u16 vid;
+ for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ if (!adapter->vlgrp->vlan_devices[vid])
+ continue;
+ atl1_vlan_rx_add_vid(adapter->netdev, vid);
+ }
+ }
+}
+
+static u16 tpd_avail(struct atl1_tpd_ring *tpd_ring)
+{
+ u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+ u16 next_to_use = atomic_read(&tpd_ring->next_to_use);
+ return ((next_to_clean >
+ next_to_use) ? next_to_clean - next_to_use -
+ 1 : tpd_ring->count + next_to_clean - next_to_use - 1);
+}
+
+static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
+ struct tso_param *tso)
+{
+ /* We enter this function holding a spinlock. */
+ u8 ipofst;
+ int err;
+
+ if (skb_shinfo(skb)->gso_size) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (unlikely(err))
+ return err;
+ }
+
+ if (skb->protocol == ntohs(ETH_P_IP)) {
+ skb->nh.iph->tot_len = 0;
+ skb->nh.iph->check = 0;
+ skb->h.th->check =
+ ~csum_tcpudp_magic(skb->nh.iph->saddr,
+ skb->nh.iph->daddr, 0,
+ IPPROTO_TCP, 0);
+ ipofst = skb->nh.raw - skb->data;
+ if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */
+ tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT;
+
+ tso->tsopl |= (skb->nh.iph->ihl &
+ CSUM_PARAM_IPHL_MASK) << CSUM_PARAM_IPHL_SHIFT;
+ tso->tsopl |= ((skb->h.th->doff << 2) &
+ TSO_PARAM_TCPHDRLEN_MASK) << TSO_PARAM_TCPHDRLEN_SHIFT;
+ tso->tsopl |= (skb_shinfo(skb)->gso_size &
+ TSO_PARAM_MSS_MASK) << TSO_PARAM_MSS_SHIFT;
+ tso->tsopl |= 1 << TSO_PARAM_IPCKSUM_SHIFT;
+ tso->tsopl |= 1 << TSO_PARAM_TCPCKSUM_SHIFT;
+ tso->tsopl |= 1 << TSO_PARAM_SEGMENT_SHIFT;
+ return true;
+ }
+ }
+ return false;
+}
+
+static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
+ struct csum_param *csum)
+{
+ u8 css, cso;
+
+ if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+ cso = skb->h.raw - skb->data;
+ css = (skb->h.raw + skb->csum) - skb->data;
+ if (unlikely(cso & 0x1)) {
+ printk(KERN_DEBUG "%s: payload offset != even number\n",
+ atl1_driver_name);
+ return -1;
+ }
+ csum->csumpl |= (cso & CSUM_PARAM_PLOADOFFSET_MASK) <<
+ CSUM_PARAM_PLOADOFFSET_SHIFT;
+ csum->csumpl |= (css & CSUM_PARAM_XSUMOFFSET_MASK) <<
+ CSUM_PARAM_XSUMOFFSET_SHIFT;
+ csum->csumpl |= 1 << CSUM_PARAM_CUSTOMCKSUM_SHIFT;
+ return true;
+ }
+
+ return true;
+}
+
+static void atl1_tx_map(struct atl1_adapter *adapter,
+ struct sk_buff *skb, bool tcp_seg)
+{
+ /* We enter this function holding a spinlock. */
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_buffer *buffer_info;
+ struct page *page;
+ int first_buf_len = skb->len;
+ unsigned long offset;
+ unsigned int nr_frags;
+ unsigned int f;
+ u16 tpd_next_to_use;
+ u16 proto_hdr_len;
+ u16 i, m, len12;
+
+ first_buf_len -= skb->data_len;
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ tpd_next_to_use = atomic_read(&tpd_ring->next_to_use);
+ buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+ if (unlikely(buffer_info->skb))
+ BUG();
+ buffer_info->skb = NULL; /* put skb in last TPD */
+
+ if (tcp_seg) {
+ /* TSO/GSO */
+ proto_hdr_len =
+ ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+ buffer_info->length = proto_hdr_len;
+ page = virt_to_page(skb->data);
+ offset = (unsigned long)skb->data & ~PAGE_MASK;
+ buffer_info->dma = pci_map_page(adapter->pdev, page,
+ offset, proto_hdr_len,
+ PCI_DMA_TODEVICE);
+
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+
+ if (first_buf_len > proto_hdr_len) {
+ len12 = first_buf_len - proto_hdr_len;
+ m = (len12 + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ for (i = 0; i < m; i++) {
+ buffer_info =
+ &tpd_ring->buffer_info[tpd_next_to_use];
+ buffer_info->skb = NULL;
+ buffer_info->length =
+ (MAX_TX_BUF_LEN >=
+ len12) ? MAX_TX_BUF_LEN : len12;
+ len12 -= buffer_info->length;
+ page = virt_to_page(skb->data +
+ (proto_hdr_len +
+ i * MAX_TX_BUF_LEN));
+ offset = (unsigned long)(skb->data +
+ (proto_hdr_len +
+ i * MAX_TX_BUF_LEN)) &
+ ~PAGE_MASK;
+ buffer_info->dma =
+ pci_map_page(adapter->pdev, page, offset,
+ buffer_info->length,
+ PCI_DMA_TODEVICE);
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+ }
+ } else {
+ /* not TSO/GSO */
+ buffer_info->length = first_buf_len;
+ page = virt_to_page(skb->data);
+ offset = (unsigned long)skb->data & ~PAGE_MASK;
+ buffer_info->dma = pci_map_page(adapter->pdev, page,
+ offset, first_buf_len,
+ PCI_DMA_TODEVICE);
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+
+ for (f = 0; f < nr_frags; f++) {
+ struct skb_frag_struct *frag;
+ u16 lenf, i, m;
+
+ frag = &skb_shinfo(skb)->frags[f];
+ lenf = frag->size;
+
+ m = (lenf + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ for (i = 0; i < m; i++) {
+ buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+ if (unlikely(buffer_info->skb))
+ BUG();
+ buffer_info->skb = NULL;
+ buffer_info->length =
+ (lenf > MAX_TX_BUF_LEN) ? MAX_TX_BUF_LEN : lenf;
+ lenf -= buffer_info->length;
+ buffer_info->dma =
+ pci_map_page(adapter->pdev, frag->page,
+ frag->page_offset + i * MAX_TX_BUF_LEN,
+ buffer_info->length, PCI_DMA_TODEVICE);
+
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+ }
+
+ /* last tpd's buffer-info */
+ buffer_info->skb = skb;
+}
+
+static void atl1_tx_queue(struct atl1_adapter *adapter, int count,
+ union tpd_descr *descr)
+{
+ /* We enter this function holding a spinlock. */
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ int j;
+ u32 val;
+ struct atl1_buffer *buffer_info;
+ struct tx_packet_desc *tpd;
+ u16 tpd_next_to_use = atomic_read(&tpd_ring->next_to_use);
+
+ for (j = 0; j < count; j++) {
+ buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+ tpd = ATL1_TPD_DESC(&adapter->tpd_ring, tpd_next_to_use);
+ tpd->desc.csum.csumpu = descr->csum.csumpu;
+ tpd->desc.csum.csumpl = descr->csum.csumpl;
+ tpd->desc.tso.tsopu = descr->tso.tsopu;
+ tpd->desc.tso.tsopl = descr->tso.tsopl;
+ tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
+ tpd->desc.data = descr->data;
+ tpd->desc.csum.csumpu |= (cpu_to_le16(buffer_info->length) &
+ CSUM_PARAM_BUFLEN_MASK) << CSUM_PARAM_BUFLEN_SHIFT;
+
+ val = (descr->tso.tsopl >> TSO_PARAM_SEGMENT_SHIFT) &
+ TSO_PARAM_SEGMENT_MASK;
+ if (val && !j)
+ tpd->desc.tso.tsopl |= 1 << TSO_PARAM_HDRFLAG_SHIFT;
+
+ if (j == (count - 1))
+ tpd->desc.csum.csumpl |= 1 << CSUM_PARAM_EOP_SHIFT;
+
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+ /*
+ * Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64).
+ */
+ wmb();
+
+ atomic_set(&tpd_ring->next_to_use, (int)tpd_next_to_use);
+}
+
+static void atl1_update_mailbox(struct atl1_adapter *adapter)
+{
+ unsigned long flags;
+ u32 tpd_next_to_use;
+ u32 rfd_next_to_use;
+ u32 rrd_next_to_clean;
+ u32 value;
+
+ spin_lock_irqsave(&adapter->mb_lock, flags);
+
+ tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
+ rfd_next_to_use = atomic_read(&adapter->rfd_ring.next_to_use);
+ rrd_next_to_clean = atomic_read(&adapter->rrd_ring.next_to_clean);
+
+ value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
+ MB_RFD_PROD_INDX_SHIFT) |
+ ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
+ MB_RRD_CONS_INDX_SHIFT) |
+ ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
+ MB_TPD_PROD_INDX_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
+
+ spin_unlock_irqrestore(&adapter->mb_lock, flags);
+}
+
+static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int len = skb->len;
+ int tso;
+ int count = 1;
+ int ret_val;
+ u32 val;
+ union tpd_descr param;
+ u16 frag_size;
+ u16 vlan_tag;
+ unsigned long flags;
+ unsigned int nr_frags = 0;
+ unsigned int mss = 0;
+ unsigned int f;
+ unsigned int proto_hdr_len;
+
+ len -= skb->data_len;
+
+ if (unlikely(skb->len == 0)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ param.data = 0;
+ param.tso.tsopu = 0;
+ param.tso.tsopl = 0;
+ param.csum.csumpu = 0;
+ param.csum.csumpl = 0;
+
+ /* nr_frags will be nonzero if we're doing scatter/gather (SG) */
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ for (f = 0; f < nr_frags; f++) {
+ frag_size = skb_shinfo(skb)->frags[f].size;
+ if (frag_size)
+ count +=
+ (frag_size + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ }
+
+ /* mss will be nonzero if we're doing segment offload (TSO/GSO) */
+ mss = skb_shinfo(skb)->gso_size;
+ if (mss) {
+ if (skb->protocol == ntohs(ETH_P_IP)) {
+ proto_hdr_len = ((skb->h.raw - skb->data) +
+ (skb->h.th->doff << 2));
+ if (unlikely(proto_hdr_len > len)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ /* need additional TPD ? */
+ if (proto_hdr_len != len)
+ count += (len - proto_hdr_len +
+ MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ }
+ }
+
+ local_irq_save(flags);
+ if (!spin_trylock(&adapter->lock)) {
+ /* Can't get lock - tell upper layer to requeue */
+ local_irq_restore(flags);
+ printk(KERN_DEBUG "%s: TX locked\n", atl1_driver_name);
+ return NETDEV_TX_LOCKED;
+ }
+
+ if (tpd_avail(&adapter->tpd_ring) < count) {
+ /* not enough descriptors */
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ printk(KERN_DEBUG "%s: TX busy\n", atl1_driver_name);
+ return NETDEV_TX_BUSY;
+ }
+
+ param.data = 0;
+
+ if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ vlan_tag = vlan_tx_tag_get(skb);
+ vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) |
+ ((vlan_tag >> 9) & 0x8);
+ param.csum.csumpl |= 1 << CSUM_PARAM_INSVLAG_SHIFT;
+ param.csum.csumpu |= (vlan_tag & CSUM_PARAM_VALANTAG_MASK) <<
+ CSUM_PARAM_VALAN_SHIFT;
+ }
+
+ tso = atl1_tso(adapter, skb, &param.tso);
+ if (tso < 0) {
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (!tso) {
+ ret_val = atl1_tx_csum(adapter, skb, &param.csum);
+ if (ret_val < 0) {
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ }
+
+ val = (param.csum.csumpl >> CSUM_PARAM_SEGMENT_SHIFT) &
+ CSUM_PARAM_SEGMENT_MASK;
+ atl1_tx_map(adapter, skb, 1 == val);
+ atl1_tx_queue(adapter, count, &param);
+ netdev->trans_start = jiffies;
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ atl1_update_mailbox(adapter);
+ return NETDEV_TX_OK;
+}
+
+/*
+ * atl1_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ */
+static struct net_device_stats *atl1_get_stats(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ return &adapter->net_stats;
+}
+
+/*
+ * atl1_clean_rx_ring - Free RFD Buffers
+ * @adapter: board private structure
+ */
+static void atl1_clean_rx_ring(struct atl1_adapter *adapter)
+{
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_buffer *buffer_info;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Rx ring sk_buffs */
+ for (i = 0; i < rfd_ring->count; i++) {
+ buffer_info = &rfd_ring->buffer_info[i];
+ if (buffer_info->dma) {
+ pci_unmap_page(pdev,
+ buffer_info->dma,
+ buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+ }
+ if (buffer_info->skb) {
+ dev_kfree_skb(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+ }
+
+ size = sizeof(struct atl1_buffer) * rfd_ring->count;
+ memset(rfd_ring->buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(rfd_ring->desc, 0, rfd_ring->size);
+
+ rfd_ring->next_to_clean = 0;
+ atomic_set(&rfd_ring->next_to_use, 0);
+
+ rrd_ring->next_to_use = 0;
+ atomic_set(&rrd_ring->next_to_clean, 0);
+}
+
+/*
+ * atl1_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ */
+static void atl1_clean_tx_ring(struct atl1_adapter *adapter)
+{
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_buffer *buffer_info;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Tx ring sk_buffs */
+ for (i = 0; i < tpd_ring->count; i++) {
+ buffer_info = &tpd_ring->buffer_info[i];
+ if (buffer_info->dma) {
+ pci_unmap_page(pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_TODEVICE);
+ buffer_info->dma = 0;
+ }
+ }
+
+ for (i = 0; i < tpd_ring->count; i++) {
+ buffer_info = &tpd_ring->buffer_info[i];
+ if (buffer_info->skb) {
+ dev_kfree_skb_any(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+ }
+
+ size = sizeof(struct atl1_buffer) * tpd_ring->count;
+ memset(tpd_ring->buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(tpd_ring->desc, 0, tpd_ring->size);
+
+ atomic_set(&tpd_ring->next_to_use, 0);
+ atomic_set(&tpd_ring->next_to_clean, 0);
+}
+
+/*
+ * atl1_free_ring_resources - Free Tx / RX descriptor Resources
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ */
+void atl1_free_ring_resources(struct atl1_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_ring_header *ring_header = &adapter->ring_header;
+
+ atl1_clean_tx_ring(adapter);
+ atl1_clean_rx_ring(adapter);
+
+ kfree(tpd_ring->buffer_info);
+ pci_free_consistent(pdev, ring_header->size, ring_header->desc,
+ ring_header->dma);
+
+ tpd_ring->buffer_info = NULL;
+ tpd_ring->desc = NULL;
+ tpd_ring->dma = 0;
+
+ rfd_ring->buffer_info = NULL;
+ rfd_ring->desc = NULL;
+ rfd_ring->dma = 0;
+
+ rrd_ring->desc = NULL;
+ rrd_ring->dma = 0;
+}
+
+s32 atl1_up(struct atl1_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int err;
+ int irq_flags = IRQF_SAMPLE_RANDOM;
+
+ /* hardware has been reset, we need to reload some things */
+ atl1_set_multi(netdev);
+ atl1_restore_vlan(adapter);
+ err = atl1_alloc_rx_buffers(adapter);
+ if (unlikely(!err)) /* no RX BUFFER allocated */
+ return -ENOMEM;
+
+ if (unlikely(atl1_configure(adapter))) {
+ err = -EIO;
+ goto err_up;
+ }
+
+ err = pci_enable_msi(adapter->pdev);
+ if (err) {
+ dev_info(&adapter->pdev->dev,
+ "Unable to enable MSI: %d\n", err);
+ irq_flags |= IRQF_SHARED;
+ }
+
+ err = request_irq(adapter->pdev->irq, &atl1_intr, irq_flags,
+ netdev->name, netdev);
+ if (unlikely(err))
+ goto err_up;
+
+ mod_timer(&adapter->watchdog_timer, jiffies);
+ atl1_irq_enable(adapter);
+ atl1_check_link(adapter);
+ return 0;
+
+ /* FIXME: unreachable code! -- CHS */
+ /* free irq disable any interrupt */
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ free_irq(adapter->pdev->irq, netdev);
+
+err_up:
+ pci_disable_msi(adapter->pdev);
+ /* free rx_buffers */
+ atl1_clean_rx_ring(adapter);
+ return err;
+}
+
+void atl1_down(struct atl1_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ del_timer_sync(&adapter->watchdog_timer);
+ del_timer_sync(&adapter->phy_config_timer);
+ adapter->phy_timer_pending = false;
+
+ atl1_irq_disable(adapter);
+ free_irq(adapter->pdev->irq, netdev);
+ pci_disable_msi(adapter->pdev);
+ atl1_reset_hw(&adapter->hw);
+ adapter->cmb.cmb->int_stats = 0;
+
+ adapter->link_speed = SPEED_0;
+ adapter->link_duplex = -1;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ atl1_clean_tx_ring(adapter);
+ atl1_clean_rx_ring(adapter);
+}
+
+/*
+ * atl1_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int old_mtu = netdev->mtu;
+ int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+
+ if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+ (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+ printk(KERN_WARNING "%s: invalid MTU setting\n",
+ atl1_driver_name);
+ return -EINVAL;
+ }
+
+ adapter->hw.max_frame_size = max_frame;
+ adapter->hw.tx_jumbo_task_th = (max_frame + 7) >> 3;
+ adapter->rx_buffer_len = (max_frame + 7) & ~7;
+ adapter->hw.rx_jumbo_th = adapter->rx_buffer_len / 8;
+
+ netdev->mtu = new_mtu;
+ if ((old_mtu != new_mtu) && netif_running(netdev)) {
+ atl1_down(adapter);
+ atl1_up(adapter);
+ }
+
+ return 0;
+}
+
+/*
+ * atl1_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1_set_mac(struct net_device *netdev, void *p)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+
+ if (netif_running(netdev))
+ return -EBUSY;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
+
+ atl1_set_mac_addr(&adapter->hw);
+ return 0;
+}
+
+/*
+ * atl1_watchdog - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl1_watchdog(unsigned long data)
+{
+ struct atl1_adapter *adapter = (struct atl1_adapter *)data;
+
+ /* Reset the timer */
+ mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+}
+
+static int mdio_read(struct net_device *netdev, int phy_id, int reg_num)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ u16 result;
+
+ atl1_read_phy_reg(&adapter->hw, reg_num & 0x1f, &result);
+
+ return result;
+}
+
+static void mdio_write(struct net_device *netdev, int phy_id, int reg_num, int val)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ atl1_write_phy_reg(&adapter->hw, reg_num, val);
+}
+
+/*
+ * atl1_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+ int retval;
+
+ if (!netif_running(netdev))
+ return -EINVAL;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ retval = generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+
+ return retval;
+}
+
+/*
+ * atl1_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ return atl1_mii_ioctl(netdev, ifr, cmd);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+/*
+ * atl1_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ */
+static void atl1_tx_timeout(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ /* Do the reset outside of interrupt context */
+ schedule_work(&adapter->tx_timeout_task);
+}
+
+/*
+ * atl1_phy_config - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl1_phy_config(unsigned long data)
+{
+ struct atl1_adapter *adapter = (struct atl1_adapter *)data;
+ struct atl1_hw *hw = &adapter->hw;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ adapter->phy_timer_pending = false;
+ atl1_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg);
+ atl1_write_phy_reg(hw, MII_AT001_CR, hw->mii_1000t_ctrl_reg);
+ atl1_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+int atl1_reset(struct atl1_adapter *adapter)
+{
+ int ret;
+
+ ret = atl1_reset_hw(&adapter->hw);
+ if (ret != ATL1_SUCCESS)
+ return ret;
+ return atl1_init_hw(&adapter->hw);
+}
+
+/*
+ * atl1_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ */
+static int atl1_open(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int err;
+
+ /* allocate transmit descriptors */
+ err = atl1_setup_ring_resources(adapter);
+ if (err)
+ return err;
+
+ err = atl1_up(adapter);
+ if (err)
+ goto err_up;
+
+ return 0;
+
+err_up:
+ atl1_reset(adapter);
+ return err;
+}
+
+/*
+ * atl1_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the drivers control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ */
+static int atl1_close(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ atl1_down(adapter);
+ atl1_free_ring_resources(adapter);
+ return 0;
+}
+
+/*
+ * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT
+ * will assert. We do soft reset <0x1400=1> according
+ * with the SPEC. BUT, it seemes that PCIE or DMA
+ * state-machine will not be reset. DMAR_TO_INT will
+ * assert again and again.
+ */
+static void atl1_tx_timeout_task(struct work_struct *work)
+{
+ struct atl1_adapter *adapter =
+ container_of(work, struct atl1_adapter, tx_timeout_task);
+ struct net_device *netdev = adapter->netdev;
+
+ netif_device_detach(netdev);
+ atl1_down(adapter);
+ atl1_up(adapter);
+ netif_device_attach(netdev);
+}
+
+/*
+ * atl1_link_chg_task - deal with link change event Out of interrupt context
+ */
+static void atl1_link_chg_task(struct work_struct *work)
+{
+ struct atl1_adapter *adapter =
+ container_of(work, struct atl1_adapter, link_chg_task);
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ atl1_check_link(adapter);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+/*
+ * atl1_pcie_patch - Patch for PCIE module
+ */
+static void atl1_pcie_patch(struct atl1_adapter *adapter)
+{
+ u32 value;
+ value = 0x6500;
+ iowrite32(value, adapter->hw.hw_addr + 0x12FC);
+ /* pcie flow control mode change */
+ value = ioread32(adapter->hw.hw_addr + 0x1008);
+ value |= 0x8000;
+ iowrite32(value, adapter->hw.hw_addr + 0x1008);
+}
+
+/*
+ * When ACPI resume on some VIA MotherBoard, the Interrupt Disable bit/0x400
+ * on PCI Command register is disable.
+ * The function enable this bit.
+ * Brackett, 2006/03/15
+ */
+static void atl1_via_workaround(struct atl1_adapter *adapter)
+{
+ unsigned long value;
+
+ value = ioread16(adapter->hw.hw_addr + PCI_COMMAND);
+ if (value & PCI_COMMAND_INTX_DISABLE)
+ value &= ~PCI_COMMAND_INTX_DISABLE;
+ iowrite32(value, adapter->hw.hw_addr + PCI_COMMAND);
+}
+
+/*
+ * atl1_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in atl1_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * atl1_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ */
+static int __devinit atl1_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *netdev;
+ struct atl1_adapter *adapter;
+ static int cards_found = 0;
+ bool pci_using_64 = true;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (err) {
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ printk(KERN_DEBUG
+ "%s: no usable DMA configuration, aborting\n",
+ atl1_driver_name);
+ goto err_dma;
+ }
+ pci_using_64 = false;
+ }
+ /* Mark all PCI regions associated with PCI device
+ * pdev as being reserved by owner atl1_driver_name
+ */
+ err = pci_request_regions(pdev, atl1_driver_name);
+ if (err)
+ goto err_request_regions;
+
+ /* Enables bus-mastering on the device and calls
+ * pcibios_set_master to do the needed arch specific settings
+ */
+ pci_set_master(pdev);
+
+ netdev = alloc_etherdev(sizeof(struct atl1_adapter));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_alloc_etherdev;
+ }
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ adapter->hw.back = adapter;
+
+ adapter->hw.hw_addr = pci_iomap(pdev, 0, 0);
+ if (!adapter->hw.hw_addr) {
+ err = -EIO;
+ goto err_pci_iomap;
+ }
+ /* get device revision number */
+ adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2));
+
+ /* set default ring resource counts */
+ adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD;
+ adapter->tpd_ring.count = ATL1_DEFAULT_TPD;
+
+ adapter->mii.dev = netdev;
+ adapter->mii.mdio_read = mdio_read;
+ adapter->mii.mdio_write = mdio_write;
+ adapter->mii.phy_id_mask = 0x1f;
+ adapter->mii.reg_num_mask = 0x1f;
+
+ netdev->open = &atl1_open;
+ netdev->stop = &atl1_close;
+ netdev->hard_start_xmit = &atl1_xmit_frame;
+ netdev->get_stats = &atl1_get_stats;
+ netdev->set_multicast_list = &atl1_set_multi;
+ netdev->set_mac_address = &atl1_set_mac;
+ netdev->change_mtu = &atl1_change_mtu;
+ netdev->do_ioctl = &atl1_ioctl;
+ netdev->tx_timeout = &atl1_tx_timeout;
+ netdev->watchdog_timeo = 5 * HZ;
+ netdev->vlan_rx_register = atl1_vlan_rx_register;
+ netdev->vlan_rx_add_vid = atl1_vlan_rx_add_vid;
+ netdev->vlan_rx_kill_vid = atl1_vlan_rx_kill_vid;
+ netdev->ethtool_ops = &atl1_ethtool_ops;
+ adapter->bd_number = cards_found;
+ adapter->pci_using_64 = pci_using_64;
+
+ /* setup the private structure */
+ err = atl1_sw_init(adapter);
+ if (err)
+ goto err_common;
+
+ netdev->features = NETIF_F_HW_CSUM;
+ netdev->features |= NETIF_F_SG;
+ netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
+
+ /*
+ * FIXME - Until tso performance gets fixed, disable the feature.
+ * Enable it with ethtool -K if desired.
+ */
+ /* netdev->features |= NETIF_F_TSO; */
+
+ if (pci_using_64)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ netdev->features |= NETIF_F_LLTX;
+
+ /*
+ * patch for some L1 of old version,
+ * the final version of L1 may not need these
+ * patches
+ */
+ /* atl1_pcie_patch(adapter); */
+
+ /* really reset GPHY core */
+ iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE);
+
+ /*
+ * reset the controller to
+ * put the device in a known good starting state
+ */
+ if (atl1_reset_hw(&adapter->hw)) {
+ err = -EIO;
+ goto err_common;
+ }
+
+ /* copy the MAC address out of the EEPROM */
+ atl1_read_mac_addr(&adapter->hw);
+ memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ err = -EIO;
+ goto err_common;
+ }
+
+ atl1_check_options(adapter);
+
+ /* pre-init the MAC, and setup link */
+ err = atl1_init_hw(&adapter->hw);
+ if (err) {
+ err = -EIO;
+ goto err_common;
+ }
+
+ atl1_pcie_patch(adapter);
+ /* assume we have no link for now */
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &atl1_watchdog;
+ adapter->watchdog_timer.data = (unsigned long)adapter;
+
+ init_timer(&adapter->phy_config_timer);
+ adapter->phy_config_timer.function = &atl1_phy_config;
+ adapter->phy_config_timer.data = (unsigned long)adapter;
+ adapter->phy_timer_pending = false;
+
+ INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task);
+
+ INIT_WORK(&adapter->link_chg_task, atl1_link_chg_task);
+
+ INIT_WORK(&adapter->pcie_dma_to_rst_task, atl1_tx_timeout_task);
+
+ err = register_netdev(netdev);
+ if (err)
+ goto err_common;
+
+ cards_found++;
+ atl1_via_workaround(adapter);
+ return 0;
+
+err_common:
+ pci_iounmap(pdev, adapter->hw.hw_addr);
+err_pci_iomap:
+ free_netdev(netdev);
+err_alloc_etherdev:
+ pci_release_regions(pdev);
+err_dma:
+err_request_regions:
+ pci_disable_device(pdev);
+ return err;
+}
+
+/*
+ * atl1_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * atl1_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ */
+static void __devexit atl1_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1_adapter *adapter;
+ /* Device not available. Return. */
+ if (!netdev)
+ return;
+
+ adapter = netdev_priv(netdev);
+ iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE);
+ unregister_netdev(netdev);
+ pci_iounmap(pdev, adapter->hw.hw_addr);
+ pci_release_regions(pdev);
+ free_netdev(netdev);
+ pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int atl1_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+ u32 ctrl = 0;
+ u32 wufc = adapter->wol;
+
+ netif_device_detach(netdev);
+ if (netif_running(netdev))
+ atl1_down(adapter);
+
+ atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
+ atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
+ if (ctrl & BMSR_LSTATUS)
+ wufc &= ~ATL1_WUFC_LNKC;
+
+ /* reduce speed to 10/100M */
+ if (wufc) {
+ atl1_phy_enter_power_saving(hw);
+ /* if resume, let driver to re- setup link */
+ hw->phy_configured = false;
+ atl1_set_mac_addr(hw);
+ atl1_set_multi(netdev);
+
+ ctrl = 0;
+ /* turn on magic packet wol */
+ if (wufc & ATL1_WUFC_MAG)
+ ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
+
+ /* turn on Link change WOL */
+ if (wufc & ATL1_WUFC_LNKC)
+ ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN);
+ iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL);
+
+ /* turn on all-multi mode if wake on multicast is enabled */
+ ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL);
+ ctrl &= ~MAC_CTRL_DBG;
+ ctrl &= ~MAC_CTRL_PROMIS_EN;
+ if (wufc & ATL1_WUFC_MC)
+ ctrl |= MAC_CTRL_MC_ALL_EN;
+ else
+ ctrl &= ~MAC_CTRL_MC_ALL_EN;
+
+ /* turn on broadcast mode if wake on-BC is enabled */
+ if (wufc & ATL1_WUFC_BC)
+ ctrl |= MAC_CTRL_BC_EN;
+ else
+ ctrl &= ~MAC_CTRL_BC_EN;
+
+ /* enable RX */
+ ctrl |= MAC_CTRL_RX_EN;
+ iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1); /* 4 == D3 cold */
+ } else {
+ iowrite32(0, hw->hw_addr + REG_WOL_CTRL);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0); /* 4 == D3 cold */
+ }
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+
+static int atl1_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ u32 ret_val;
+
+ pci_set_power_state(pdev, 0);
+ pci_restore_state(pdev);
+
+ ret_val = pci_enable_device(pdev);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL);
+ atl1_reset(adapter);
+
+ if (netif_running(netdev))
+ atl1_up(adapter);
+ netif_device_attach(netdev);
+
+ atl1_via_workaround(adapter);
+
+ return 0;
+}
+#else
+#define atl1_suspend NULL
+#define atl1_resume NULL
+#endif
+
+static struct pci_driver atl1_driver = {
+ .name = atl1_driver_name,
+ .id_table = atl1_pci_tbl,
+ .probe = atl1_probe,
+ .remove = __devexit_p(atl1_remove),
+ /* Power Managment Hooks */
+ /* probably broken right now -- CHS */
+ .suspend = atl1_suspend,
+ .resume = atl1_resume
+};
+
+/*
+ * atl1_exit_module - Driver Exit Cleanup Routine
+ *
+ * atl1_exit_module is called just before the driver is removed
+ * from memory.
+ */
+static void __exit atl1_exit_module(void)
+{
+ pci_unregister_driver(&atl1_driver);
+}
+
+/*
+ * atl1_init_module - Driver Registration Routine
+ *
+ * atl1_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ */
+static int __init atl1_init_module(void)
+{
+ printk(KERN_INFO "%s - version %s\n", atl1_driver_string, DRIVER_VERSION);
+ printk(KERN_INFO "%s\n", atl1_copyright);
+ return pci_register_driver(&atl1_driver);
+}
+
+module_init(atl1_init_module);
+module_exit(atl1_exit_module);
diff --git a/drivers/net/atl1/atl1_param.c b/drivers/net/atl1/atl1_param.c
new file mode 100644
index 00000000000..c407214339f
--- /dev/null
+++ b/drivers/net/atl1/atl1_param.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 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
+ * 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/types.h>
+#include <linux/pci.h>
+#include <linux/moduleparam.h>
+#include "atl1.h"
+
+/*
+ * This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+#define ATL1_MAX_NIC 4
+
+#define OPTION_UNSET -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED 1
+
+#define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET }
+
+/*
+ * Interrupt Moderate Timer in units of 2 us
+ *
+ * Valid Range: 10-65535
+ *
+ * Default Value: 100 (200us)
+ */
+static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT;
+static int num_int_mod_timer = 0;
+module_param_array_named(int_mod_timer, int_mod_timer, int, &num_int_mod_timer, 0);
+MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer");
+
+/*
+ * flash_vendor
+ *
+ * Valid Range: 0-2
+ *
+ * 0 - Atmel
+ * 1 - SST
+ * 2 - ST
+ *
+ * Default Value: 0
+ */
+static int __devinitdata flash_vendor[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT;
+static int num_flash_vendor = 0;
+module_param_array_named(flash_vendor, flash_vendor, int, &num_flash_vendor, 0);
+MODULE_PARM_DESC(flash_vendor, "SPI flash vendor");
+
+#define DEFAULT_INT_MOD_CNT 100 /* 200us */
+#define MAX_INT_MOD_CNT 65000
+#define MIN_INT_MOD_CNT 50
+
+#define FLASH_VENDOR_DEFAULT 0
+#define FLASH_VENDOR_MIN 0
+#define FLASH_VENDOR_MAX 2
+
+struct atl1_option {
+ enum { enable_option, range_option, list_option } type;
+ char *name;
+ char *err;
+ int def;
+ union {
+ struct { /* range_option info */
+ int min;
+ int max;
+ } r;
+ struct { /* list_option info */
+ int nr;
+ struct atl1_opt_list {
+ int i;
+ char *str;
+ } *p;
+ } l;
+ } arg;
+};
+
+static int __devinit atl1_validate_option(int *value, struct atl1_option *opt)
+{
+ if (*value == OPTION_UNSET) {
+ *value = opt->def;
+ return 0;
+ }
+
+ switch (opt->type) {
+ case enable_option:
+ switch (*value) {
+ case OPTION_ENABLED:
+ printk(KERN_INFO "%s: %s Enabled\n", atl1_driver_name,
+ opt->name);
+ return 0;
+ case OPTION_DISABLED:
+ printk(KERN_INFO "%s: %s Disabled\n", atl1_driver_name,
+ opt->name);
+ return 0;
+ }
+ break;
+ case range_option:
+ if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+ printk(KERN_INFO "%s: %s set to %i\n",
+ atl1_driver_name, opt->name, *value);
+ return 0;
+ }
+ break;
+ case list_option:{
+ int i;
+ struct atl1_opt_list *ent;
+
+ for (i = 0; i < opt->arg.l.nr; i++) {
+ ent = &opt->arg.l.p[i];
+ if (*value == ent->i) {
+ if (ent->str[0] != '\0')
+ printk(KERN_INFO "%s: %s\n",
+ atl1_driver_name, ent->str);
+ return 0;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ printk(KERN_INFO "%s: invalid %s specified (%i) %s\n",
+ atl1_driver_name, opt->name, *value, opt->err);
+ *value = opt->def;
+ return -1;
+}
+
+/*
+ * atl1_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input. If an invalid value is given, or if no user specified
+ * value exists, a default value is used. The final value is stored
+ * in a variable in the adapter structure.
+ */
+void __devinit atl1_check_options(struct atl1_adapter *adapter)
+{
+ int bd = adapter->bd_number;
+ if (bd >= ATL1_MAX_NIC) {
+ printk(KERN_NOTICE "%s: warning: no configuration for board #%i\n",
+ atl1_driver_name, bd);
+ printk(KERN_NOTICE "%s: using defaults for all values\n",
+ atl1_driver_name);
+ }
+ { /* Interrupt Moderate Timer */
+ struct atl1_option opt = {
+ .type = range_option,
+ .name = "Interrupt Moderator Timer",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_INT_MOD_CNT),
+ .def = DEFAULT_INT_MOD_CNT,
+ .arg = {.r =
+ {.min = MIN_INT_MOD_CNT,.max = MAX_INT_MOD_CNT}}
+ };
+ int val;
+ if (num_int_mod_timer > bd) {
+ val = int_mod_timer[bd];
+ atl1_validate_option(&val, &opt);
+ adapter->imt = (u16) val;
+ } else
+ adapter->imt = (u16) (opt.def);
+ }
+
+ { /* Flash Vendor */
+ struct atl1_option opt = {
+ .type = range_option,
+ .name = "SPI Flash Vendor",
+ .err = "using default of "
+ __MODULE_STRING(FLASH_VENDOR_DEFAULT),
+ .def = DEFAULT_INT_MOD_CNT,
+ .arg = {.r =
+ {.min = FLASH_VENDOR_MIN,.max =
+ FLASH_VENDOR_MAX}}
+ };
+ int val;
+ if (num_flash_vendor > bd) {
+ val = flash_vendor[bd];
+ atl1_validate_option(&val, &opt);
+ adapter->hw.flash_vendor = (u8) val;
+ } else
+ adapter->hw.flash_vendor = (u8) (opt.def);
+ }
+}
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 474a4e3438d..5ff7882297d 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -110,6 +110,11 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
static void b44_halt(struct b44 *);
static void b44_init_rings(struct b44 *);
+
+#define B44_FULL_RESET 1
+#define B44_FULL_RESET_SKIP_PHY 2
+#define B44_PARTIAL_RESET 3
+
static void b44_init_hw(struct b44 *, int);
static int dma_desc_align_mask;
@@ -716,7 +721,7 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
struct ring_info *src_map, *dest_map;
struct rx_header *rh;
int dest_idx;
- u32 ctrl;
+ __le32 ctrl;
dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
dest_desc = &bp->rx_ring[dest_idx];
@@ -752,7 +757,7 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
dest_idx * sizeof(dest_desc),
DMA_BIDIRECTIONAL);
- pci_dma_sync_single_for_device(bp->pdev, src_desc->addr,
+ pci_dma_sync_single_for_device(bp->pdev, le32_to_cpu(src_desc->addr),
RX_PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
}
@@ -778,7 +783,7 @@ static int b44_rx(struct b44 *bp, int budget)
RX_PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
rh = (struct rx_header *) skb->data;
- len = cpu_to_le16(rh->len);
+ len = le16_to_cpu(rh->len);
if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) ||
(rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
drop_it:
@@ -794,7 +799,7 @@ static int b44_rx(struct b44 *bp, int budget)
do {
udelay(2);
barrier();
- len = cpu_to_le16(rh->len);
+ len = le16_to_cpu(rh->len);
} while (len == 0 && i++ < 5);
if (len == 0)
goto drop_it;
@@ -879,12 +884,14 @@ static int b44_poll(struct net_device *netdev, int *budget)
}
if (bp->istat & ISTAT_ERRORS) {
- spin_lock_irq(&bp->lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bp->lock, flags);
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp, 1);
+ b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY);
netif_wake_queue(bp->dev);
- spin_unlock_irq(&bp->lock);
+ spin_unlock_irqrestore(&bp->lock, flags);
done = 1;
}
@@ -952,7 +959,7 @@ static void b44_tx_timeout(struct net_device *dev)
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp, 1);
+ b44_init_hw(bp, B44_FULL_RESET);
spin_unlock_irq(&bp->lock);
@@ -1069,7 +1076,7 @@ static int b44_change_mtu(struct net_device *dev, int new_mtu)
b44_halt(bp);
dev->mtu = new_mtu;
b44_init_rings(bp);
- b44_init_hw(bp, 1);
+ b44_init_hw(bp, B44_FULL_RESET);
spin_unlock_irq(&bp->lock);
b44_enable_ints(bp);
@@ -1366,12 +1373,12 @@ static int b44_set_mac_addr(struct net_device *dev, void *p)
* packet processing. Invoked with bp->lock held.
*/
static void __b44_set_rx_mode(struct net_device *);
-static void b44_init_hw(struct b44 *bp, int full_reset)
+static void b44_init_hw(struct b44 *bp, int reset_kind)
{
u32 val;
b44_chip_reset(bp);
- if (full_reset) {
+ if (reset_kind == B44_FULL_RESET) {
b44_phy_reset(bp);
b44_setup_phy(bp);
}
@@ -1388,7 +1395,10 @@ static void b44_init_hw(struct b44 *bp, int full_reset)
bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
bw32(bp, B44_TX_WMARK, 56); /* XXX magic */
- if (full_reset) {
+ if (reset_kind == B44_PARTIAL_RESET) {
+ bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
+ (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+ } else {
bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
@@ -1399,9 +1409,6 @@ static void b44_init_hw(struct b44 *bp, int full_reset)
bp->rx_prod = bp->rx_pending;
bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
- } else {
- bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
- (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
}
val = br32(bp, B44_ENET_CTRL);
@@ -1418,7 +1425,7 @@ static int b44_open(struct net_device *dev)
goto out;
b44_init_rings(bp);
- b44_init_hw(bp, 1);
+ b44_init_hw(bp, B44_FULL_RESET);
b44_check_phy(bp);
@@ -1627,7 +1634,7 @@ static int b44_close(struct net_device *dev)
netif_poll_enable(dev);
if (bp->flags & B44_FLAG_WOL_ENABLE) {
- b44_init_hw(bp, 0);
+ b44_init_hw(bp, B44_PARTIAL_RESET);
b44_setup_wol(bp);
}
@@ -1903,7 +1910,7 @@ static int b44_set_ringparam(struct net_device *dev,
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp, 1);
+ b44_init_hw(bp, B44_FULL_RESET);
netif_wake_queue(bp->dev);
spin_unlock_irq(&bp->lock);
@@ -1946,7 +1953,7 @@ static int b44_set_pauseparam(struct net_device *dev,
if (bp->flags & B44_FLAG_PAUSE_AUTO) {
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp, 1);
+ b44_init_hw(bp, B44_FULL_RESET);
} else {
__b44_set_flow_ctrl(bp, bp->flags);
}
@@ -2054,7 +2061,7 @@ out:
static int b44_read_eeprom(struct b44 *bp, u8 *data)
{
long i;
- u16 *ptr = (u16 *) data;
+ __le16 *ptr = (__le16 *) data;
for (i = 0; i < 128; i += 2)
ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
@@ -2302,7 +2309,7 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
free_irq(dev->irq, dev);
if (bp->flags & B44_FLAG_WOL_ENABLE) {
- b44_init_hw(bp, 0);
+ b44_init_hw(bp, B44_PARTIAL_RESET);
b44_setup_wol(bp);
}
pci_disable_device(pdev);
@@ -2313,21 +2320,32 @@ static int b44_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct b44 *bp = netdev_priv(dev);
+ int rc = 0;
pci_restore_state(pdev);
- pci_enable_device(pdev);
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ printk(KERN_ERR PFX "%s: pci_enable_device failed\n",
+ dev->name);
+ return rc;
+ }
+
pci_set_master(pdev);
if (!netif_running(dev))
return 0;
- if (request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev))
+ rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
+ if (rc) {
printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name);
+ pci_disable_device(pdev);
+ return rc;
+ }
spin_lock_irq(&bp->lock);
b44_init_rings(bp);
- b44_init_hw(bp, 1);
+ b44_init_hw(bp, B44_FULL_RESET);
netif_device_attach(bp->dev);
spin_unlock_irq(&bp->lock);
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 4944507fad2..18fc1333662 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -308,8 +308,8 @@
#define MII_TLEDCTRL_ENABLE 0x0040
struct dma_desc {
- u32 ctrl;
- u32 addr;
+ __le32 ctrl;
+ __le32 addr;
};
/* There are only 12 bits in the DMA engine for descriptor offsetting
@@ -327,9 +327,9 @@ struct dma_desc {
#define RX_COPY_THRESHOLD 256
struct rx_header {
- u16 len;
- u16 flags;
- u16 pad[12];
+ __le16 len;
+ __le16 flags;
+ __le16 pad[12];
};
#define RX_HEADER_LEN 28
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 4528ce9c4e4..c143304dcff 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/crc32.h>
+#include <linux/bitrev.h>
#include <asm/prom.h>
#include <asm/dbdma.h>
#include <asm/io.h>
@@ -140,7 +141,6 @@ static unsigned char *bmac_emergency_rxbuf;
+ (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
+ sizeof(struct sk_buff_head))
-static unsigned char bitrev(unsigned char b);
static int bmac_open(struct net_device *dev);
static int bmac_close(struct net_device *dev);
static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
@@ -586,18 +586,6 @@ bmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp)
virt_to_bus(addr), 0);
}
-/* Bit-reverse one byte of an ethernet hardware address. */
-static unsigned char
-bitrev(unsigned char b)
-{
- int d = 0, i;
-
- for (i = 0; i < 8; ++i, b >>= 1)
- d = (d << 1) | (b & 1);
- return d;
-}
-
-
static void
bmac_init_tx_ring(struct bmac_data *bp)
{
@@ -1224,8 +1212,8 @@ bmac_get_station_address(struct net_device *dev, unsigned char *ea)
{
reset_and_select_srom(dev);
data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
- ea[2*i] = bitrev(data & 0x0ff);
- ea[2*i+1] = bitrev((data >> 8) & 0x0ff);
+ ea[2*i] = bitrev8(data & 0x0ff);
+ ea[2*i+1] = bitrev8((data >> 8) & 0x0ff);
}
}
@@ -1315,7 +1303,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
rev = addr[0] == 0 && addr[1] == 0xA0;
for (j = 0; j < 6; ++j)
- dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+ dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
/* Enable chip without interrupts for now */
bmac_enable_and_reset_chip(dev);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 5bacb7587df..5a96d7611af 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -39,12 +39,9 @@
#include <linux/if_vlan.h>
#define BCM_VLAN 1
#endif
-#ifdef NETIF_F_TSO
#include <net/ip.h>
#include <net/tcp.h>
#include <net/checksum.h>
-#define BCM_TSO 1
-#endif
#include <linux/workqueue.h>
#include <linux/crc32.h>
#include <linux/prefetch.h>
@@ -57,8 +54,8 @@
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.5.1"
-#define DRV_MODULE_RELDATE "November 15, 2006"
+#define DRV_MODULE_VERSION "1.5.5"
+#define DRV_MODULE_RELDATE "February 1, 2007"
#define RUN_AT(x) (jiffies + (x))
@@ -217,9 +214,16 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp)
u32 diff;
smp_mb();
- diff = TX_RING_IDX(bp->tx_prod) - TX_RING_IDX(bp->tx_cons);
- if (diff > MAX_TX_DESC_CNT)
- diff = (diff & MAX_TX_DESC_CNT) - 1;
+
+ /* The ring uses 256 indices for 255 entries, one of them
+ * needs to be skipped.
+ */
+ diff = bp->tx_prod - bp->tx_cons;
+ if (unlikely(diff >= TX_DESC_CNT)) {
+ diff &= 0xffff;
+ if (diff == TX_DESC_CNT)
+ diff = MAX_TX_DESC_CNT;
+ }
return (bp->tx_ring_size - diff);
}
@@ -1338,8 +1342,6 @@ bnx2_init_copper_phy(struct bnx2 *bp)
{
u32 val;
- bp->phy_flags |= PHY_CRC_FIX_FLAG;
-
if (bp->phy_flags & PHY_CRC_FIX_FLAG) {
bnx2_write_phy(bp, 0x18, 0x0c00);
bnx2_write_phy(bp, 0x17, 0x000a);
@@ -1351,6 +1353,14 @@ bnx2_init_copper_phy(struct bnx2 *bp)
bnx2_write_phy(bp, 0x18, 0x0400);
}
+ if (bp->phy_flags & PHY_DIS_EARLY_DAC_FLAG) {
+ bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
+ MII_BNX2_DSP_EXPAND_REG | 0x8);
+ bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
+ val &= ~(1 << 8);
+ bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
+ }
+
if (bp->dev->mtu > 1500) {
/* Set extended packet length bit */
bnx2_write_phy(bp, 0x18, 0x7);
@@ -1715,7 +1725,7 @@ bnx2_tx_int(struct bnx2 *bp)
tx_buf = &bp->tx_buf_ring[sw_ring_cons];
skb = tx_buf->skb;
-#ifdef BCM_TSO
+
/* partial BD completions possible with TSO packets */
if (skb_is_gso(skb)) {
u16 last_idx, last_ring_idx;
@@ -1731,7 +1741,7 @@ bnx2_tx_int(struct bnx2 *bp)
break;
}
}
-#endif
+
pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
skb_headlen(skb), PCI_DMA_TODEVICE);
@@ -2510,7 +2520,7 @@ bnx2_init_cpus(struct bnx2 *bp)
if (CHIP_NUM(bp) == CHIP_NUM_5709) {
fw = &bnx2_cp_fw_09;
- load_cpu_fw(bp, &cpu_reg, fw);
+ rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc)
goto init_cpu_err;
}
@@ -3078,7 +3088,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
int buf_size)
{
u32 written, offset32, len32;
- u8 *buf, start[4], end[4], *flash_buffer = NULL;
+ u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
int rc = 0;
int align_start, align_end;
@@ -3089,7 +3099,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
if ((align_start = (offset32 & 3))) {
offset32 &= ~3;
- len32 += align_start;
+ len32 += (4 - align_start);
if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
return rc;
}
@@ -3106,16 +3116,17 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
}
if (align_start || align_end) {
- buf = kmalloc(len32, GFP_KERNEL);
- if (buf == 0)
+ align_buf = kmalloc(len32, GFP_KERNEL);
+ if (align_buf == NULL)
return -ENOMEM;
if (align_start) {
- memcpy(buf, start, 4);
+ memcpy(align_buf, start, 4);
}
if (align_end) {
- memcpy(buf + len32 - 4, end, 4);
+ memcpy(align_buf + len32 - 4, end, 4);
}
- memcpy(buf + align_start, data_buf, buf_size);
+ memcpy(align_buf + align_start, data_buf, buf_size);
+ buf = align_buf;
}
if (bp->flash_info->buffered == 0) {
@@ -3249,11 +3260,8 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
}
nvram_write_end:
- if (bp->flash_info->buffered == 0)
- kfree(flash_buffer);
-
- if (align_start || align_end)
- kfree(buf);
+ kfree(flash_buffer);
+ kfree(align_buf);
return rc;
}
@@ -3998,7 +4006,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
if (!skb)
return -ENOMEM;
packet = skb_put(skb, pkt_size);
- memcpy(packet, bp->mac_addr, 6);
+ memcpy(packet, bp->dev->dev_addr, 6);
memset(packet + 6, 0x0, 8);
for (i = 14; i < pkt_size; i++)
packet[i] = (unsigned char) (i & 0xff);
@@ -4503,7 +4511,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
vlan_tag_flags |=
(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
}
-#ifdef BCM_TSO
if ((mss = skb_shinfo(skb)->gso_size) &&
(skb->len > (bp->dev->mtu + ETH_HLEN))) {
u32 tcp_opt_len, ip_tcp_len;
@@ -4536,7 +4543,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
else
-#endif
{
mss = 0;
}
@@ -5533,10 +5539,8 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
.set_tx_csum = ethtool_op_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#ifdef BCM_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = bnx2_set_tso,
-#endif
.self_test_count = bnx2_self_test_count,
.self_test = bnx2_self_test,
.get_strings = bnx2_get_strings,
@@ -5638,6 +5642,44 @@ poll_bnx2(struct net_device *dev)
}
#endif
+static void __devinit
+bnx2_get_5709_media(struct bnx2 *bp)
+{
+ u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
+ u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
+ u32 strap;
+
+ if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
+ return;
+ else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
+ bp->phy_flags |= PHY_SERDES_FLAG;
+ return;
+ }
+
+ if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
+ strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
+ else
+ strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
+
+ if (PCI_FUNC(bp->pdev->devfn) == 0) {
+ switch (strap) {
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ bp->phy_flags |= PHY_SERDES_FLAG;
+ return;
+ }
+ } else {
+ switch (strap) {
+ case 0x1:
+ case 0x2:
+ case 0x4:
+ bp->phy_flags |= PHY_SERDES_FLAG;
+ return;
+ }
+ }
+}
+
static int __devinit
bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
{
@@ -5804,9 +5846,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
reg = REG_RD_IND(bp, BNX2_SHM_HDR_SIGNATURE);
if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
- BNX2_SHM_HDR_SIGNATURE_SIG)
- bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0);
- else
+ BNX2_SHM_HDR_SIGNATURE_SIG) {
+ u32 off = PCI_FUNC(pdev->devfn) << 2;
+
+ bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0 + off);
+ } else
bp->shmem_base = HOST_VIEW_SHMEM_BASE;
/* Get the permanent MAC address. First we need to make sure the
@@ -5858,10 +5902,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->phy_addr = 1;
/* Disable WOL support if we are running on a SERDES chip. */
- if (CHIP_NUM(bp) == CHIP_NUM_5709) {
- if (CHIP_BOND_ID(bp) != BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
- bp->phy_flags |= PHY_SERDES_FLAG;
- } else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bnx2_get_5709_media(bp);
+ else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
bp->phy_flags |= PHY_SERDES_FLAG;
if (bp->phy_flags & PHY_SERDES_FLAG) {
@@ -5873,7 +5916,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
}
- }
+ } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
+ CHIP_NUM(bp) == CHIP_NUM_5708)
+ bp->phy_flags |= PHY_CRC_FIX_FLAG;
+ else if (CHIP_ID(bp) == CHIP_ID_5709_A0)
+ bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG;
if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
(CHIP_ID(bp) == CHIP_ID_5708_B0) ||
@@ -5900,8 +5947,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
* 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.
+ * prefers to locally disable MSI rather than globally disabling it.
*/
if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
struct pci_dev *amd_8132 = NULL;
@@ -6050,9 +6096,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef BCM_VLAN
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
-#ifdef BCM_TSO
dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-#endif
netif_carrier_off(bp->dev);
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 13b6f9b11e0..ccbdf81c659 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6288,6 +6288,10 @@ struct l2_fhdr {
#define BCM5708S_TX_ACTL3 0x17
+#define MII_BNX2_DSP_RW_PORT 0x15
+#define MII_BNX2_DSP_ADDRESS 0x17
+#define MII_BNX2_DSP_EXPAND_REG 0x0f00
+
#define MIN_ETHERNET_PACKET_SIZE 60
#define MAX_ETHERNET_PACKET_SIZE 1514
#define MAX_ETHERNET_JUMBO_PACKET_SIZE 9014
@@ -6489,6 +6493,7 @@ struct bnx2 {
#define PHY_INT_MODE_MASK_FLAG 0x300
#define PHY_INT_MODE_AUTO_POLLING_FLAG 0x100
#define PHY_INT_MODE_LINK_READY_FLAG 0x200
+#define PHY_DIS_EARLY_DAC_FLAG 0x400
u32 chip_id;
/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
@@ -6512,6 +6517,7 @@ struct bnx2 {
#define CHIP_ID_5708_A0 0x57080000
#define CHIP_ID_5708_B0 0x57081000
#define CHIP_ID_5708_B1 0x57081010
+#define CHIP_ID_5709_A0 0x57090000
#define CHIP_BOND_ID(bp) (((bp)->chip_id) & 0xf)
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 32923162179..217a2eedee0 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -184,7 +184,7 @@ static int tlb_initialize(struct bonding *bond)
spin_lock_init(&(bond_info->tx_hashtbl_lock));
- new_hashtbl = kmalloc(size, GFP_KERNEL);
+ new_hashtbl = kzalloc(size, GFP_KERNEL);
if (!new_hashtbl) {
printk(KERN_ERR DRV_NAME
": %s: Error: Failed to allocate TLB hash table\n",
@@ -195,8 +195,6 @@ static int tlb_initialize(struct bonding *bond)
bond_info->tx_hashtbl = new_hashtbl;
- memset(bond_info->tx_hashtbl, 0, size);
-
for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) {
tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1);
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 6482aed4bb7..8ce8fec615b 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1343,14 +1343,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
"inaccurate.\n", bond_dev->name, slave_dev->name);
}
- new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL);
+ new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
if (!new_slave) {
res = -ENOMEM;
goto err_undo_flags;
}
- memset(new_slave, 0, sizeof(struct slave));
-
/* save slave's original flags before calling
* netdev_set_master and dev_open
*/
@@ -4704,6 +4702,7 @@ static int bond_check_params(struct bond_params *params)
static struct lock_class_key bonding_netdev_xmit_lock_key;
/* Create a new bond based on the specified name and bonding parameters.
+ * If name is NULL, obtain a suitable "bond%d" name for us.
* Caller must NOT hold rtnl_lock; we need to release it here before we
* set up our sysfs entries.
*/
@@ -4713,7 +4712,8 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
int res;
rtnl_lock();
- bond_dev = alloc_netdev(sizeof(struct bonding), name, ether_setup);
+ bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
+ ether_setup);
if (!bond_dev) {
printk(KERN_ERR DRV_NAME
": %s: eek! can't alloc netdev!\n",
@@ -4722,6 +4722,12 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
goto out_rtnl;
}
+ if (!name) {
+ res = dev_alloc_name(bond_dev, "bond%d");
+ if (res < 0)
+ goto out_netdev;
+ }
+
/* bond_init() must be called after dev_alloc_name() (for the
* /proc files), but before register_netdevice(), because we
* need to set function pointers.
@@ -4748,14 +4754,19 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
rtnl_unlock(); /* allows sysfs registration of net device */
res = bond_create_sysfs_entry(bond_dev->priv);
- goto done;
+ if (res < 0) {
+ rtnl_lock();
+ goto out_bond;
+ }
+
+ return 0;
+
out_bond:
bond_deinit(bond_dev);
out_netdev:
free_netdev(bond_dev);
out_rtnl:
rtnl_unlock();
-done:
return res;
}
@@ -4763,7 +4774,6 @@ static int __init bonding_init(void)
{
int i;
int res;
- char new_bond_name[8]; /* Enough room for 999 bonds at init. */
printk(KERN_INFO "%s", version);
@@ -4776,8 +4786,7 @@ static int __init bonding_init(void)
bond_create_proc_dir();
#endif
for (i = 0; i < max_bonds; i++) {
- sprintf(new_bond_name, "bond%d",i);
- res = bond_create(new_bond_name,&bonding_defaults, NULL);
+ res = bond_create(NULL, &bonding_defaults, NULL);
if (res)
goto err;
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index ced9ed8f995..878f7aabeea 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -39,8 +39,7 @@
/* #define BONDING_DEBUG 1 */
#include "bonding.h"
-#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
+#define to_dev(obj) container_of(obj,struct device,kobj)
#define to_bond(cd) ((struct bonding *)(to_net_dev(cd)->priv))
/*---------------------------- Declarations -------------------------------*/
@@ -154,7 +153,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
* If it's > expected, then there's a file open,
* and we have to fail.
*/
- if (atomic_read(&bond->dev->class_dev.kobj.kref.refcount)
+ if (atomic_read(&bond->dev->dev.kobj.kref.refcount)
> expected_refcount){
rtnl_unlock();
printk(KERN_INFO DRV_NAME
@@ -201,13 +200,13 @@ int bond_create_slave_symlinks(struct net_device *master, struct net_device *sla
int ret = 0;
/* first, create a link from the slave back to the master */
- ret = sysfs_create_link(&(slave->class_dev.kobj), &(master->class_dev.kobj),
+ ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj),
"master");
if (ret)
return ret;
/* next, create a link from the master to the slave */
sprintf(linkname,"slave_%s",slave->name);
- ret = sysfs_create_link(&(master->class_dev.kobj), &(slave->class_dev.kobj),
+ ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
linkname);
return ret;
@@ -217,20 +216,21 @@ void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *s
{
char linkname[IFNAMSIZ+7];
- sysfs_remove_link(&(slave->class_dev.kobj), "master");
+ sysfs_remove_link(&(slave->dev.kobj), "master");
sprintf(linkname,"slave_%s",slave->name);
- sysfs_remove_link(&(master->class_dev.kobj), linkname);
+ sysfs_remove_link(&(master->dev.kobj), linkname);
}
/*
* Show the slaves in the current bond.
*/
-static ssize_t bonding_show_slaves(struct class_device *cd, char *buf)
+static ssize_t bonding_show_slaves(struct device *d,
+ struct device_attribute *attr, char *buf)
{
struct slave *slave;
int i, res = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
read_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i) {
@@ -254,14 +254,16 @@ static ssize_t bonding_show_slaves(struct class_device *cd, char *buf)
* up for this to succeed.
* This function is largely the same flow as bonding_update_bonds().
*/
-static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, size_t count)
+static ssize_t bonding_store_slaves(struct device *d,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
{
char command[IFNAMSIZ + 1] = { 0, };
char *ifname;
int i, res, found, ret = count;
struct slave *slave;
struct net_device *dev = NULL;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
/* Quick sanity check -- is the bond interface up? */
if (!(bond->dev->flags & IFF_UP)) {
@@ -387,25 +389,28 @@ out:
return ret;
}
-static CLASS_DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves);
+static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves);
/*
* Show and set the bonding mode. The bond interface must be down to
* change the mode.
*/
-static ssize_t bonding_show_mode(struct class_device *cd, char *buf)
+static ssize_t bonding_show_mode(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%s %d\n",
bond_mode_tbl[bond->params.mode].modename,
bond->params.mode) + 1;
}
-static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_mode(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->dev->flags & IFF_UP) {
printk(KERN_ERR DRV_NAME
@@ -438,16 +443,18 @@ static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size
out:
return ret;
}
-static CLASS_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode);
/*
* Show and set the bonding transmit hash method. The bond interface must be down to
* change the xmit hash policy.
*/
-static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf)
+static ssize_t bonding_show_xmit_hash(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if ((bond->params.mode != BOND_MODE_XOR) &&
(bond->params.mode != BOND_MODE_8023AD)) {
@@ -462,10 +469,12 @@ static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf)
return count;
}
-static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_xmit_hash(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->dev->flags & IFF_UP) {
printk(KERN_ERR DRV_NAME
@@ -501,24 +510,28 @@ static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf,
out:
return ret;
}
-static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
+static 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)
+static ssize_t bonding_show_arp_validate(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
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)
+static ssize_t bonding_store_arp_validate(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
if (new_value < 0) {
@@ -548,7 +561,7 @@ static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *b
return count;
}
-static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
+static 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
@@ -556,17 +569,21 @@ static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_valid
* MII monitoring. Second, if the ARP timer isn't running, we must
* start it.
*/
-static ssize_t bonding_show_arp_interval(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_interval(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.arp_interval) + 1;
}
-static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_interval(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (sscanf(buf, "%d", &new_value) != 1) {
printk(KERN_ERR DRV_NAME
@@ -638,15 +655,17 @@ static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *b
out:
return ret;
}
-static CLASS_DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval);
+static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval);
/*
* Show and set the arp targets.
*/
-static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_targets(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int i, res = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
if (bond->params.arp_targets[i])
@@ -660,11 +679,13 @@ static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf)
return res;
}
-static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_targets(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
u32 newtarget;
int i = 0, done = 0, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
u32 *targets;
targets = bond->params.arp_targets;
@@ -742,24 +763,28 @@ static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *bu
out:
return ret;
}
-static CLASS_DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
+static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
/*
* Show and set the up and down delays. These must be multiples of the
* MII monitoring value, and are stored internally as the multiplier.
* Thus, we must translate to MS for the real world.
*/
-static ssize_t bonding_show_downdelay(struct class_device *cd, char *buf)
+static ssize_t bonding_show_downdelay(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon) + 1;
}
-static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_downdelay(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (!(bond->params.miimon)) {
printk(KERN_ERR DRV_NAME
@@ -800,20 +825,24 @@ static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf,
out:
return ret;
}
-static CLASS_DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay);
+static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay);
-static ssize_t bonding_show_updelay(struct class_device *cd, char *buf)
+static ssize_t bonding_show_updelay(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon) + 1;
}
-static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_updelay(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (!(bond->params.miimon)) {
printk(KERN_ERR DRV_NAME
@@ -854,25 +883,29 @@ static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, s
out:
return ret;
}
-static CLASS_DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay);
+static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay);
/*
* Show and set the LACP interval. Interface must be down, and the mode
* must be set to 802.3ad mode.
*/
-static ssize_t bonding_show_lacp(struct class_device *cd, char *buf)
+static ssize_t bonding_show_lacp(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%s %d\n",
bond_lacp_tbl[bond->params.lacp_fast].modename,
bond->params.lacp_fast) + 1;
}
-static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_lacp(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->dev->flags & IFF_UP) {
printk(KERN_ERR DRV_NAME
@@ -906,7 +939,7 @@ static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size
out:
return ret;
}
-static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
+static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
/*
* Show and set the MII monitor interval. There are two tricky bits
@@ -914,17 +947,21 @@ static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bondin
* ARP monitoring. Second, if the timer isn't running, we must
* start it.
*/
-static ssize_t bonding_show_miimon(struct class_device *cd, char *buf)
+static ssize_t bonding_show_miimon(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.miimon) + 1;
}
-static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_miimon(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (sscanf(buf, "%d", &new_value) != 1) {
printk(KERN_ERR DRV_NAME
@@ -1000,7 +1037,7 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si
out:
return ret;
}
-static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon);
+static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon);
/*
* Show and set the primary slave. The store function is much
@@ -1009,10 +1046,12 @@ static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding
* The bond must be a mode that supports a primary for this be
* set.
*/
-static ssize_t bonding_show_primary(struct class_device *cd, char *buf)
+static ssize_t bonding_show_primary(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->primary_slave)
count = sprintf(buf, "%s\n", bond->primary_slave->dev->name) + 1;
@@ -1022,11 +1061,13 @@ static ssize_t bonding_show_primary(struct class_device *cd, char *buf)
return count;
}
-static ssize_t bonding_store_primary(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_primary(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int i;
struct slave *slave;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
write_lock_bh(&bond->lock);
if (!USES_PRIMARY(bond->params.mode)) {
@@ -1065,22 +1106,26 @@ out:
write_unlock_bh(&bond->lock);
return count;
}
-static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
+static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
/*
* Show and set the use_carrier flag.
*/
-static ssize_t bonding_show_carrier(struct class_device *cd, char *buf)
+static ssize_t bonding_show_carrier(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.use_carrier) + 1;
}
-static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_carrier(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (sscanf(buf, "%d", &new_value) != 1) {
@@ -1102,16 +1147,18 @@ static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, s
out:
return count;
}
-static CLASS_DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier);
+static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier);
/*
* Show and set currently active_slave.
*/
-static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf)
+static ssize_t bonding_show_active_slave(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
struct slave *curr;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
int count;
@@ -1126,13 +1173,15 @@ static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf)
return count;
}
-static ssize_t bonding_store_active_slave(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_active_slave(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int i;
struct slave *slave;
struct slave *old_active = NULL;
struct slave *new_active = NULL;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
write_lock_bh(&bond->lock);
if (!USES_PRIMARY(bond->params.mode)) {
@@ -1194,16 +1243,18 @@ out:
return count;
}
-static CLASS_DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave);
+static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave);
/*
* Show link status of the bond interface.
*/
-static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf)
+static ssize_t bonding_show_mii_status(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
struct slave *curr;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
read_lock(&bond->curr_slave_lock);
curr = bond->curr_active_slave;
@@ -1211,16 +1262,18 @@ static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf)
return sprintf(buf, "%s\n", (curr) ? "up" : "down") + 1;
}
-static CLASS_DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
+static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
/*
* Show current 802.3ad aggregator ID.
*/
-static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_aggregator(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1231,16 +1284,18 @@ static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL);
+static DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL);
/*
* Show number of active 802.3ad ports.
*/
-static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_num_ports(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1251,16 +1306,18 @@ static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL);
+static DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL);
/*
* Show current 802.3ad actor key.
*/
-static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_actor_key(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1271,16 +1328,18 @@ static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL);
+static DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL);
/*
* Show current 802.3ad partner key.
*/
-static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_partner_key(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1291,16 +1350,18 @@ static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL);
+static DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL);
/*
* Show current 802.3ad partner mac.
*/
-static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_partner_mac(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1319,30 +1380,30 @@ static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
+static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
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,
- &class_device_attr_updelay.attr,
- &class_device_attr_lacp_rate.attr,
- &class_device_attr_xmit_hash_policy.attr,
- &class_device_attr_miimon.attr,
- &class_device_attr_primary.attr,
- &class_device_attr_use_carrier.attr,
- &class_device_attr_active_slave.attr,
- &class_device_attr_mii_status.attr,
- &class_device_attr_ad_aggregator.attr,
- &class_device_attr_ad_num_ports.attr,
- &class_device_attr_ad_actor_key.attr,
- &class_device_attr_ad_partner_key.attr,
- &class_device_attr_ad_partner_mac.attr,
+ &dev_attr_slaves.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_arp_validate.attr,
+ &dev_attr_arp_interval.attr,
+ &dev_attr_arp_ip_target.attr,
+ &dev_attr_downdelay.attr,
+ &dev_attr_updelay.attr,
+ &dev_attr_lacp_rate.attr,
+ &dev_attr_xmit_hash_policy.attr,
+ &dev_attr_miimon.attr,
+ &dev_attr_primary.attr,
+ &dev_attr_use_carrier.attr,
+ &dev_attr_active_slave.attr,
+ &dev_attr_mii_status.attr,
+ &dev_attr_ad_aggregator.attr,
+ &dev_attr_ad_num_ports.attr,
+ &dev_attr_ad_actor_key.attr,
+ &dev_attr_ad_partner_key.attr,
+ &dev_attr_ad_partner_mac.attr,
NULL,
};
@@ -1367,11 +1428,26 @@ int bond_create_sysfs(void)
if (!firstbond)
return -ENODEV;
- netdev_class = firstbond->dev->class_dev.class;
+ netdev_class = firstbond->dev->dev.class;
if (!netdev_class)
return -ENODEV;
ret = class_create_file(netdev_class, &class_attr_bonding_masters);
+ /*
+ * Permit multiple loads of the module by ignoring failures to
+ * create the bonding_masters sysfs file. Bonding devices
+ * created by second or subsequent loads of the module will
+ * not be listed in, or controllable by, bonding_masters, but
+ * will have the usual "bonding" sysfs directory.
+ *
+ * This is done to preserve backwards compatibility for
+ * initscripts/sysconfig, which load bonding multiple times to
+ * configure multiple bonding devices.
+ */
+ if (ret == -EEXIST) {
+ netdev_class = NULL;
+ return 0;
+ }
return ret;
@@ -1395,13 +1471,13 @@ int bond_create_sysfs_entry(struct bonding *bond)
struct net_device *dev = bond->dev;
int err;
- err = sysfs_create_group(&(dev->class_dev.kobj), &bonding_group);
+ err = sysfs_create_group(&(dev->dev.kobj), &bonding_group);
if (err) {
printk(KERN_EMERG "eek! didn't create group!\n");
}
if (expected_refcount < 1)
- expected_refcount = atomic_read(&bond->dev->class_dev.kobj.kref.refcount);
+ expected_refcount = atomic_read(&bond->dev->dev.kobj.kref.refcount);
return err;
}
@@ -1412,6 +1488,6 @@ void bond_destroy_sysfs_entry(struct bonding *bond)
{
struct net_device *dev = bond->dev;
- sysfs_remove_group(&(dev->class_dev.kobj), &bonding_group);
+ sysfs_remove_group(&(dev->dev.kobj), &bonding_group);
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index dc434fb6da8..41aa78bf1f7 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.1.1"
-#define DRV_RELDATE "September 26, 2006"
+#define DRV_VERSION "3.1.2"
+#define DRV_RELDATE "January 20, 2007"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -151,8 +151,8 @@ struct slave {
struct slave *next;
struct slave *prev;
int delay;
- u32 jiffies;
- u32 last_arp_rx;
+ unsigned long jiffies;
+ unsigned long last_arp_rx;
s8 link; /* one of BOND_LINK_XXXX */
s8 state; /* one of BOND_STATE_XXXX */
u32 original_flags;
@@ -237,12 +237,14 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
#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)
+static 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)
+static inline unsigned long slave_last_rx(struct bonding *bond,
+ struct slave *slave)
{
if (slave_do_arp_validate(bond, slave))
return slave->last_arp_rx;
diff --git a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c
index bae1de1e780..7845eaf6f29 100644
--- a/drivers/net/bsd_comp.c
+++ b/drivers/net/bsd_comp.c
@@ -395,7 +395,7 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp)
* Allocate the main control structure for this instance.
*/
maxmaxcode = MAXCODE(bits);
- db = (struct bsd_db *) kmalloc (sizeof (struct bsd_db),
+ db = kmalloc(sizeof (struct bsd_db),
GFP_KERNEL);
if (!db)
{
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 74758d2c7af..787f2f2820f 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -324,7 +324,7 @@ struct board_info {
unsigned char mdio_phybaseaddr;
struct gmac *gmac;
struct gphy *gphy;
- struct mdio_ops *mdio_ops;
+ struct mdio_ops *mdio_ops;
const char *desc;
};
diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/chelsio/cpl5_cmd.h
index 35f565be4fd..e36d45b78cc 100644
--- a/drivers/net/chelsio/cpl5_cmd.h
+++ b/drivers/net/chelsio/cpl5_cmd.h
@@ -103,7 +103,7 @@ enum CPL_opcode {
CPL_MIGRATE_C2T_RPL = 0xDD,
CPL_ERROR = 0xD7,
- /* internal: driver -> TOM */
+ /* internal: driver -> TOM */
CPL_MSS_CHANGE = 0xE1
};
@@ -159,8 +159,8 @@ enum { // TX_PKT_LSO ethernet types
};
union opcode_tid {
- u32 opcode_tid;
- u8 opcode;
+ u32 opcode_tid;
+ u8 opcode;
};
#define S_OPCODE 24
@@ -234,7 +234,7 @@ struct cpl_pass_accept_req {
u32 local_ip;
u32 peer_ip;
u32 tos_tid;
- struct tcp_options tcp_options;
+ struct tcp_options tcp_options;
u8 dst_mac[6];
u16 vlan_tag;
u8 src_mac[6];
@@ -250,12 +250,12 @@ struct cpl_pass_accept_rpl {
u32 peer_ip;
u32 opt0h;
union {
- u32 opt0l;
- struct {
- u8 rsvd[3];
- u8 status;
+ u32 opt0l;
+ struct {
+ u8 rsvd[3];
+ u8 status;
+ };
};
- };
};
struct cpl_act_open_req {
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index de48eadddbc..7d0f24f6977 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -69,14 +69,14 @@ static inline void cancel_mac_stats_update(struct adapter *ap)
cancel_delayed_work(&ap->stats_update_task);
}
-#define MAX_CMDQ_ENTRIES 16384
-#define MAX_CMDQ1_ENTRIES 1024
-#define MAX_RX_BUFFERS 16384
-#define MAX_RX_JUMBO_BUFFERS 16384
+#define MAX_CMDQ_ENTRIES 16384
+#define MAX_CMDQ1_ENTRIES 1024
+#define MAX_RX_BUFFERS 16384
+#define MAX_RX_JUMBO_BUFFERS 16384
#define MAX_TX_BUFFERS_HIGH 16384U
#define MAX_TX_BUFFERS_LOW 1536U
#define MAX_TX_BUFFERS 1460U
-#define MIN_FL_ENTRIES 32
+#define MIN_FL_ENTRIES 32
#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
@@ -143,7 +143,7 @@ static void link_report(struct port_info *p)
case SPEED_100: s = "100Mbps"; break;
}
- printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
+ printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
p->dev->name, s,
p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
}
@@ -220,9 +220,8 @@ static int cxgb_up(struct adapter *adapter)
t1_interrupts_clear(adapter);
- adapter->params.has_msi = !disable_msi && pci_enable_msi(adapter->pdev) == 0;
- err = request_irq(adapter->pdev->irq,
- t1_select_intr_handler(adapter),
+ adapter->params.has_msi = !disable_msi && !pci_enable_msi(adapter->pdev);
+ err = request_irq(adapter->pdev->irq, t1_interrupt,
adapter->params.has_msi ? 0 : IRQF_SHARED,
adapter->name, adapter);
if (err) {
@@ -234,7 +233,7 @@ static int cxgb_up(struct adapter *adapter)
t1_sge_start(adapter->sge);
t1_interrupts_enable(adapter);
- out_err:
+out_err:
return err;
}
@@ -455,51 +454,21 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
const struct cmac_statistics *s;
const struct sge_intr_counts *t;
struct sge_port_stats ss;
+ unsigned int len;
s = mac->ops->statistics_update(mac, MAC_STATS_UPDATE_FULL);
- *data++ = s->TxOctetsOK;
- *data++ = s->TxOctetsBad;
- *data++ = s->TxUnicastFramesOK;
- *data++ = s->TxMulticastFramesOK;
- *data++ = s->TxBroadcastFramesOK;
- *data++ = s->TxPauseFrames;
- *data++ = s->TxFramesWithDeferredXmissions;
- *data++ = s->TxLateCollisions;
- *data++ = s->TxTotalCollisions;
- *data++ = s->TxFramesAbortedDueToXSCollisions;
- *data++ = s->TxUnderrun;
- *data++ = s->TxLengthErrors;
- *data++ = s->TxInternalMACXmitError;
- *data++ = s->TxFramesWithExcessiveDeferral;
- *data++ = s->TxFCSErrors;
-
- *data++ = s->RxOctetsOK;
- *data++ = s->RxOctetsBad;
- *data++ = s->RxUnicastFramesOK;
- *data++ = s->RxMulticastFramesOK;
- *data++ = s->RxBroadcastFramesOK;
- *data++ = s->RxPauseFrames;
- *data++ = s->RxFCSErrors;
- *data++ = s->RxAlignErrors;
- *data++ = s->RxSymbolErrors;
- *data++ = s->RxDataErrors;
- *data++ = s->RxSequenceErrors;
- *data++ = s->RxRuntErrors;
- *data++ = s->RxJabberErrors;
- *data++ = s->RxInternalMACRcvError;
- *data++ = s->RxInRangeLengthErrors;
- *data++ = s->RxOutOfRangeLengthField;
- *data++ = s->RxFrameTooLongErrors;
+ len = sizeof(u64)*(&s->TxFCSErrors + 1 - &s->TxOctetsOK);
+ memcpy(data, &s->TxOctetsOK, len);
+ data += len;
+
+ len = sizeof(u64)*(&s->RxFrameTooLongErrors + 1 - &s->RxOctetsOK);
+ memcpy(data, &s->RxOctetsOK, len);
+ data += len;
t1_sge_get_port_stats(adapter->sge, dev->if_port, &ss);
- *data++ = ss.rx_packets;
- *data++ = ss.rx_cso_good;
- *data++ = ss.tx_packets;
- *data++ = ss.tx_cso;
- *data++ = ss.tx_tso;
- *data++ = ss.vlan_xtract;
- *data++ = ss.vlan_insert;
+ memcpy(data, &ss, sizeof(ss));
+ data += sizeof(ss);
t = t1_sge_get_intr_counts(adapter->sge);
*data++ = t->rx_drops;
@@ -750,7 +719,7 @@ static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
return -EINVAL;
if (adapter->flags & FULL_INIT_DONE)
- return -EBUSY;
+ return -EBUSY;
adapter->params.sge.freelQ_size[!jumbo_fl] = e->rx_pending;
adapter->params.sge.freelQ_size[jumbo_fl] = e->rx_jumbo_pending;
@@ -764,19 +733,8 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
{
struct adapter *adapter = dev->priv;
- /*
- * If RX coalescing is requested we use NAPI, otherwise interrupts.
- * This choice can be made only when all ports and the TOE are off.
- */
- if (adapter->open_device_map == 0)
- adapter->params.sge.polling = c->use_adaptive_rx_coalesce;
-
- if (adapter->params.sge.polling) {
- adapter->params.sge.rx_coalesce_usecs = 0;
- } else {
- adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs;
- }
- adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
+ adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs;
+ adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
adapter->params.sge.sample_interval_usecs = c->rate_sample_interval;
t1_sge_set_coalesce_params(adapter->sge, &adapter->params.sge);
return 0;
@@ -794,9 +752,9 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
static int get_eeprom_len(struct net_device *dev)
{
- struct adapter *adapter = dev->priv;
+ struct adapter *adapter = dev->priv;
- return t1_is_asic(adapter) ? EEPROM_SIZE : 0;
+ return t1_is_asic(adapter) ? EEPROM_SIZE : 0;
}
#define EEPROM_MAGIC(ap) \
@@ -860,7 +818,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
u32 val;
if (!phy->mdio_read)
- return -EOPNOTSUPP;
+ return -EOPNOTSUPP;
phy->mdio_read(adapter, data->phy_id, 0, data->reg_num & 0x1f,
&val);
data->val_out = val;
@@ -872,7 +830,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (!phy->mdio_write)
- return -EOPNOTSUPP;
+ return -EOPNOTSUPP;
phy->mdio_write(adapter, data->phy_id, 0, data->reg_num & 0x1f,
data->val_in);
break;
@@ -891,9 +849,9 @@ static int t1_change_mtu(struct net_device *dev, int new_mtu)
struct cmac *mac = adapter->port[dev->if_port].mac;
if (!mac->ops->set_mtu)
- return -EOPNOTSUPP;
+ return -EOPNOTSUPP;
if (new_mtu < 68)
- return -EINVAL;
+ return -EINVAL;
if ((ret = mac->ops->set_mtu(mac, new_mtu)))
return ret;
dev->mtu = new_mtu;
@@ -944,7 +902,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);
+ t1_interrupt(adapter->pdev->irq, adapter);
local_irq_restore(flags);
}
#endif
@@ -1165,7 +1123,10 @@ static int __devinit init_one(struct pci_dev *pdev,
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = t1_netpoll;
#endif
+#ifdef CONFIG_CHELSIO_T1_NAPI
netdev->weight = 64;
+ netdev->poll = t1_poll;
+#endif
SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops);
}
@@ -1220,9 +1181,9 @@ static int __devinit init_one(struct pci_dev *pdev,
return 0;
- out_release_adapter_res:
+out_release_adapter_res:
t1_free_sw_modules(adapter);
- out_free_dev:
+out_free_dev:
if (adapter) {
if (adapter->regs)
iounmap(adapter->regs);
@@ -1231,7 +1192,7 @@ static int __devinit init_one(struct pci_dev *pdev,
free_netdev(adapter->port[i].dev);
}
pci_release_regions(pdev);
- out_disable_pdev:
+out_disable_pdev:
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
return err;
@@ -1282,28 +1243,27 @@ static int t1_clock(struct adapter *adapter, int mode)
int M_MEM_VAL;
enum {
- M_CORE_BITS = 9,
- T_CORE_VAL = 0,
- T_CORE_BITS = 2,
- N_CORE_VAL = 0,
- N_CORE_BITS = 2,
- M_MEM_BITS = 9,
- T_MEM_VAL = 0,
- T_MEM_BITS = 2,
- N_MEM_VAL = 0,
- N_MEM_BITS = 2,
- NP_LOAD = 1 << 17,
- S_LOAD_MEM = 1 << 5,
- S_LOAD_CORE = 1 << 6,
- S_CLOCK = 1 << 3
+ M_CORE_BITS = 9,
+ T_CORE_VAL = 0,
+ T_CORE_BITS = 2,
+ N_CORE_VAL = 0,
+ N_CORE_BITS = 2,
+ M_MEM_BITS = 9,
+ T_MEM_VAL = 0,
+ T_MEM_BITS = 2,
+ N_MEM_VAL = 0,
+ N_MEM_BITS = 2,
+ NP_LOAD = 1 << 17,
+ S_LOAD_MEM = 1 << 5,
+ S_LOAD_CORE = 1 << 6,
+ S_CLOCK = 1 << 3
};
if (!t1_is_T1B(adapter))
return -ENODEV; /* Can't re-clock this chip. */
- if (mode & 2) {
+ if (mode & 2)
return 0; /* show current mode. */
- }
if ((adapter->t1powersave & 1) == (mode & 1))
return -EALREADY; /* ASIC already running in mode. */
@@ -1395,26 +1355,26 @@ static inline void t1_sw_reset(struct pci_dev *pdev)
static void __devexit remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct adapter *adapter = dev->priv;
+ int i;
- if (dev) {
- int i;
- struct adapter *adapter = dev->priv;
-
- for_each_port(adapter, i)
- if (test_bit(i, &adapter->registered_device_map))
- unregister_netdev(adapter->port[i].dev);
+ for_each_port(adapter, i) {
+ if (test_bit(i, &adapter->registered_device_map))
+ unregister_netdev(adapter->port[i].dev);
+ }
- t1_free_sw_modules(adapter);
- iounmap(adapter->regs);
- while (--i >= 0)
- if (adapter->port[i].dev)
- free_netdev(adapter->port[i].dev);
+ t1_free_sw_modules(adapter);
+ iounmap(adapter->regs);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
- t1_sw_reset(pdev);
+ while (--i >= 0) {
+ if (adapter->port[i].dev)
+ free_netdev(adapter->port[i].dev);
}
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ t1_sw_reset(pdev);
}
static struct pci_driver driver = {
diff --git a/drivers/net/chelsio/elmer0.h b/drivers/net/chelsio/elmer0.h
index 9ebecaa97d3..eef655c827d 100644
--- a/drivers/net/chelsio/elmer0.h
+++ b/drivers/net/chelsio/elmer0.h
@@ -46,14 +46,14 @@ enum {
};
/* ELMER0 registers */
-#define A_ELMER0_VERSION 0x100000
-#define A_ELMER0_PHY_CFG 0x100004
-#define A_ELMER0_INT_ENABLE 0x100008
-#define A_ELMER0_INT_CAUSE 0x10000c
-#define A_ELMER0_GPI_CFG 0x100010
-#define A_ELMER0_GPI_STAT 0x100014
-#define A_ELMER0_GPO 0x100018
-#define A_ELMER0_PORT0_MI1_CFG 0x400000
+#define A_ELMER0_VERSION 0x100000
+#define A_ELMER0_PHY_CFG 0x100004
+#define A_ELMER0_INT_ENABLE 0x100008
+#define A_ELMER0_INT_CAUSE 0x10000c
+#define A_ELMER0_GPI_CFG 0x100010
+#define A_ELMER0_GPI_STAT 0x100014
+#define A_ELMER0_GPO 0x100018
+#define A_ELMER0_PORT0_MI1_CFG 0x400000
#define S_MI1_MDI_ENABLE 0
#define V_MI1_MDI_ENABLE(x) ((x) << S_MI1_MDI_ENABLE)
@@ -111,18 +111,18 @@ enum {
#define V_MI1_OP_BUSY(x) ((x) << S_MI1_OP_BUSY)
#define F_MI1_OP_BUSY V_MI1_OP_BUSY(1U)
-#define A_ELMER0_PORT1_MI1_CFG 0x500000
-#define A_ELMER0_PORT1_MI1_ADDR 0x500004
-#define A_ELMER0_PORT1_MI1_DATA 0x500008
-#define A_ELMER0_PORT1_MI1_OP 0x50000c
-#define A_ELMER0_PORT2_MI1_CFG 0x600000
-#define A_ELMER0_PORT2_MI1_ADDR 0x600004
-#define A_ELMER0_PORT2_MI1_DATA 0x600008
-#define A_ELMER0_PORT2_MI1_OP 0x60000c
-#define A_ELMER0_PORT3_MI1_CFG 0x700000
-#define A_ELMER0_PORT3_MI1_ADDR 0x700004
-#define A_ELMER0_PORT3_MI1_DATA 0x700008
-#define A_ELMER0_PORT3_MI1_OP 0x70000c
+#define A_ELMER0_PORT1_MI1_CFG 0x500000
+#define A_ELMER0_PORT1_MI1_ADDR 0x500004
+#define A_ELMER0_PORT1_MI1_DATA 0x500008
+#define A_ELMER0_PORT1_MI1_OP 0x50000c
+#define A_ELMER0_PORT2_MI1_CFG 0x600000
+#define A_ELMER0_PORT2_MI1_ADDR 0x600004
+#define A_ELMER0_PORT2_MI1_DATA 0x600008
+#define A_ELMER0_PORT2_MI1_OP 0x60000c
+#define A_ELMER0_PORT3_MI1_CFG 0x700000
+#define A_ELMER0_PORT3_MI1_ADDR 0x700004
+#define A_ELMER0_PORT3_MI1_DATA 0x700008
+#define A_ELMER0_PORT3_MI1_OP 0x70000c
/* Simple bit definition for GPI and GP0 registers. */
#define ELMER0_GP_BIT0 0x0001
diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c
index 4192f0f5b3e..d7c5406a6c3 100644
--- a/drivers/net/chelsio/espi.c
+++ b/drivers/net/chelsio/espi.c
@@ -202,9 +202,9 @@ static void espi_setup_for_pm3393(adapter_t *adapter)
static void espi_setup_for_vsc7321(adapter_t *adapter)
{
- writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
- writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
- writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
+ writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
+ writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
+ writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH);
@@ -247,10 +247,10 @@ int t1_espi_init(struct peespi *espi, int mac_type, int nports)
writel(V_OUT_OF_SYNC_COUNT(4) |
V_DIP2_PARITY_ERR_THRES(3) |
V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL);
- writel(nports == 4 ? 0x200040 : 0x1000080,
+ writel(nports == 4 ? 0x200040 : 0x1000080,
adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
} else
- writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
+ writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
if (mac_type == CHBT_MAC_PM3393)
espi_setup_for_pm3393(adapter);
@@ -301,7 +301,8 @@ void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
{
struct peespi *espi = adapter->espi;
- if (!is_T2(adapter)) return;
+ if (!is_T2(adapter))
+ return;
spin_lock(&espi->lock);
espi->misc_ctrl = (val & ~MON_MASK) |
(espi->misc_ctrl & MON_MASK);
@@ -340,32 +341,31 @@ u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait)
* compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in
* one shot, since there is no per port counter on the out side.
*/
-int
-t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
+int t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
{
- struct peespi *espi = adapter->espi;
+ struct peespi *espi = adapter->espi;
u8 i, nport = (u8)adapter->params.nports;
- if (!wait) {
- if (!spin_trylock(&espi->lock))
- return -1;
- } else
- spin_lock(&espi->lock);
+ if (!wait) {
+ if (!spin_trylock(&espi->lock))
+ return -1;
+ } else
+ spin_lock(&espi->lock);
- if ( (espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION ) {
+ if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION) {
espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) |
F_MONITORED_DIRECTION;
- writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
- }
+ writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+ }
for (i = 0 ; i < nport; i++, valp++) {
if (i) {
writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i),
adapter->regs + A_ESPI_MISC_CONTROL);
}
- *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
- }
+ *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
+ }
- writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
- spin_unlock(&espi->lock);
- return 0;
+ writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+ spin_unlock(&espi->lock);
+ return 0;
}
diff --git a/drivers/net/chelsio/fpga_defs.h b/drivers/net/chelsio/fpga_defs.h
index 17a3c2ba36a..ccdb2bc9ae9 100644
--- a/drivers/net/chelsio/fpga_defs.h
+++ b/drivers/net/chelsio/fpga_defs.h
@@ -98,9 +98,9 @@
#define A_MI0_DATA_INT 0xb10
/* GMAC registers */
-#define A_GMAC_MACID_LO 0x28
-#define A_GMAC_MACID_HI 0x2c
-#define A_GMAC_CSR 0x30
+#define A_GMAC_MACID_LO 0x28
+#define A_GMAC_MACID_HI 0x2c
+#define A_GMAC_CSR 0x30
#define S_INTERFACE 0
#define M_INTERFACE 0x3
diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h
index a2b8ad9b553..006a2eb2d36 100644
--- a/drivers/net/chelsio/gmac.h
+++ b/drivers/net/chelsio/gmac.h
@@ -42,8 +42,15 @@
#include "common.h"
-enum { MAC_STATS_UPDATE_FAST, MAC_STATS_UPDATE_FULL };
-enum { MAC_DIRECTION_RX = 1, MAC_DIRECTION_TX = 2 };
+enum {
+ MAC_STATS_UPDATE_FAST,
+ MAC_STATS_UPDATE_FULL
+};
+
+enum {
+ MAC_DIRECTION_RX = 1,
+ MAC_DIRECTION_TX = 2
+};
struct cmac_statistics {
/* Transmit */
diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c
index 5b8f144e83d..10b2a9a1900 100644
--- a/drivers/net/chelsio/ixf1010.c
+++ b/drivers/net/chelsio/ixf1010.c
@@ -145,48 +145,61 @@ static void disable_port(struct cmac *mac)
t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val);
}
-#define RMON_UPDATE(mac, name, stat_name) \
- t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
- (mac)->stats.stat_name += val;
-
/*
* Read the current values of the RMON counters and add them to the cumulative
* port statistics. The HW RMON counters are cleared by this operation.
*/
static void port_stats_update(struct cmac *mac)
{
- u32 val;
+ static struct {
+ unsigned int reg;
+ unsigned int offset;
+ } hw_stats[] = {
+
+#define HW_STAT(name, stat_name) \
+ { REG_##name, \
+ (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+ /* Rx stats */
+ HW_STAT(RxOctetsTotalOK, RxOctetsOK),
+ HW_STAT(RxOctetsBad, RxOctetsBad),
+ HW_STAT(RxUCPkts, RxUnicastFramesOK),
+ HW_STAT(RxMCPkts, RxMulticastFramesOK),
+ HW_STAT(RxBCPkts, RxBroadcastFramesOK),
+ HW_STAT(RxJumboPkts, RxJumboFramesOK),
+ HW_STAT(RxFCSErrors, RxFCSErrors),
+ HW_STAT(RxAlignErrors, RxAlignErrors),
+ HW_STAT(RxLongErrors, RxFrameTooLongErrors),
+ HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors),
+ HW_STAT(RxPauseMacControlCounter, RxPauseFrames),
+ HW_STAT(RxDataErrors, RxDataErrors),
+ HW_STAT(RxJabberErrors, RxJabberErrors),
+ HW_STAT(RxRuntErrors, RxRuntErrors),
+ HW_STAT(RxShortErrors, RxRuntErrors),
+ HW_STAT(RxSequenceErrors, RxSequenceErrors),
+ HW_STAT(RxSymbolErrors, RxSymbolErrors),
+
+ /* Tx stats (skip collision stats as we are full-duplex only) */
+ HW_STAT(TxOctetsTotalOK, TxOctetsOK),
+ HW_STAT(TxOctetsBad, TxOctetsBad),
+ HW_STAT(TxUCPkts, TxUnicastFramesOK),
+ HW_STAT(TxMCPkts, TxMulticastFramesOK),
+ HW_STAT(TxBCPkts, TxBroadcastFramesOK),
+ HW_STAT(TxJumboPkts, TxJumboFramesOK),
+ HW_STAT(TxPauseFrames, TxPauseFrames),
+ HW_STAT(TxExcessiveLengthDrop, TxLengthErrors),
+ HW_STAT(TxUnderrun, TxUnderrun),
+ HW_STAT(TxCRCErrors, TxFCSErrors)
+ }, *p = hw_stats;
+ u64 *stats = (u64 *) &mac->stats;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
+ u32 val;
- /* Rx stats */
- RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK);
- RMON_UPDATE(mac, RxOctetsBad, RxOctetsBad);
- RMON_UPDATE(mac, RxUCPkts, RxUnicastFramesOK);
- RMON_UPDATE(mac, RxMCPkts, RxMulticastFramesOK);
- RMON_UPDATE(mac, RxBCPkts, RxBroadcastFramesOK);
- RMON_UPDATE(mac, RxJumboPkts, RxJumboFramesOK);
- RMON_UPDATE(mac, RxFCSErrors, RxFCSErrors);
- RMON_UPDATE(mac, RxAlignErrors, RxAlignErrors);
- RMON_UPDATE(mac, RxLongErrors, RxFrameTooLongErrors);
- RMON_UPDATE(mac, RxVeryLongErrors, RxFrameTooLongErrors);
- RMON_UPDATE(mac, RxPauseMacControlCounter, RxPauseFrames);
- RMON_UPDATE(mac, RxDataErrors, RxDataErrors);
- RMON_UPDATE(mac, RxJabberErrors, RxJabberErrors);
- RMON_UPDATE(mac, RxRuntErrors, RxRuntErrors);
- RMON_UPDATE(mac, RxShortErrors, RxRuntErrors);
- RMON_UPDATE(mac, RxSequenceErrors, RxSequenceErrors);
- RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
-
- /* Tx stats (skip collision stats as we are full-duplex only) */
- RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK);
- RMON_UPDATE(mac, TxOctetsBad, TxOctetsBad);
- RMON_UPDATE(mac, TxUCPkts, TxUnicastFramesOK);
- RMON_UPDATE(mac, TxMCPkts, TxMulticastFramesOK);
- RMON_UPDATE(mac, TxBCPkts, TxBroadcastFramesOK);
- RMON_UPDATE(mac, TxJumboPkts, TxJumboFramesOK);
- RMON_UPDATE(mac, TxPauseFrames, TxPauseFrames);
- RMON_UPDATE(mac, TxExcessiveLengthDrop, TxLengthErrors);
- RMON_UPDATE(mac, TxUnderrun, TxUnderrun);
- RMON_UPDATE(mac, TxCRCErrors, TxFCSErrors);
+ t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val);
+ stats[p->offset] += val;
+ }
}
/* No-op interrupt operation as this MAC does not support interrupts */
@@ -273,7 +286,8 @@ static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
static int mac_set_mtu(struct cmac *mac, int mtu)
{
/* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */
- if (mtu > (MAX_FRAME_SIZE - 14 - 4)) return -EINVAL;
+ if (mtu > (MAX_FRAME_SIZE - 14 - 4))
+ return -EINVAL;
t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE),
mtu + 14 + 4);
return 0;
@@ -357,8 +371,8 @@ static void enable_port(struct cmac *mac)
val |= (1 << index);
t1_tpi_write(adapter, REG_PORT_ENABLE, val);
- index <<= 2;
- if (is_T2(adapter)) {
+ index <<= 2;
+ if (is_T2(adapter)) {
/* T204: set the Fifo water level & threshold */
t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740);
t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730);
@@ -389,6 +403,10 @@ static int mac_disable(struct cmac *mac, int which)
return 0;
}
+#define RMON_UPDATE(mac, name, stat_name) \
+ t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
+ (mac)->stats.stat_name += val;
+
/*
* This function is called periodically to accumulate the current values of the
* RMON counters into the port statistics. Since the counters are only 32 bits
@@ -460,10 +478,12 @@ static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index)
struct cmac *mac;
u32 val;
- if (index > 9) return NULL;
+ if (index > 9)
+ return NULL;
mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
- if (!mac) return NULL;
+ if (!mac)
+ return NULL;
mac->ops = &ixf1010_ops;
mac->instance = (cmac_instance *)(mac + 1);
diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c
index 28ac93ff7c4..5867e3b0a88 100644
--- a/drivers/net/chelsio/mv88e1xxx.c
+++ b/drivers/net/chelsio/mv88e1xxx.c
@@ -73,9 +73,8 @@ static int mv88e1xxx_interrupt_enable(struct cphy *cphy)
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
- elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
+ if (is_T2(cphy->adapter))
+ elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4;
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
return 0;
@@ -92,9 +91,8 @@ static int mv88e1xxx_interrupt_disable(struct cphy *cphy)
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer &= ~ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
return 0;
@@ -112,9 +110,8 @@ static int mv88e1xxx_interrupt_clear(struct cphy *cphy)
if (t1_is_asic(cphy->adapter)) {
t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
}
return 0;
@@ -300,7 +297,7 @@ static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
/*
* Loop until cause reads zero. Need to handle bouncing interrupts.
- */
+ */
while (1) {
u32 cause;
@@ -308,15 +305,16 @@ static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
MV88E1XXX_INTERRUPT_STATUS_REGISTER,
&cause);
cause &= INTR_ENABLE_MASK;
- if (!cause) break;
+ if (!cause)
+ break;
if (cause & MV88E1XXX_INTR_LINK_CHNG) {
(void) simple_mdio_read(cphy,
MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
- if (status & MV88E1XXX_INTR_LINK_CHNG) {
+ if (status & MV88E1XXX_INTR_LINK_CHNG)
cphy->state |= PHY_LINK_UP;
- } else {
+ else {
cphy->state &= ~PHY_LINK_UP;
if (cphy->state & PHY_AUTONEG_EN)
cphy->state &= ~PHY_AUTONEG_RDY;
@@ -360,7 +358,8 @@ static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
{
struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
- if (!cphy) return NULL;
+ if (!cphy)
+ return NULL;
cphy_init(cphy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops);
@@ -377,11 +376,11 @@ static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
}
(void) mv88e1xxx_downshift_set(cphy, 1); /* Enable downshift */
- /* LED */
+ /* LED */
if (is_T2(adapter)) {
(void) simple_mdio_write(cphy,
MV88E1XXX_LED_CONTROL_REGISTER, 0x1);
- }
+ }
return cphy;
}
diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c
index c7731b6f9de..87dde3e6004 100644
--- a/drivers/net/chelsio/my3126.c
+++ b/drivers/net/chelsio/my3126.c
@@ -10,25 +10,25 @@ static int my3126_reset(struct cphy *cphy, int wait)
* This can be done through registers. It is not required since
* a full chip reset is used.
*/
- return (0);
+ return 0;
}
static int my3126_interrupt_enable(struct cphy *cphy)
{
schedule_delayed_work(&cphy->phy_update, HZ/30);
t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo);
- return (0);
+ return 0;
}
static int my3126_interrupt_disable(struct cphy *cphy)
{
cancel_rearming_delayed_work(&cphy->phy_update);
- return (0);
+ return 0;
}
static int my3126_interrupt_clear(struct cphy *cphy)
{
- return (0);
+ return 0;
}
#define OFFSET(REG_ADDR) (REG_ADDR << 2)
@@ -102,7 +102,7 @@ static void my3216_poll(struct work_struct *work)
static int my3126_set_loopback(struct cphy *cphy, int on)
{
- return (0);
+ return 0;
}
/* To check the activity LED */
@@ -146,7 +146,7 @@ static int my3126_get_link_status(struct cphy *cphy,
if (fc)
*fc = PAUSE_RX | PAUSE_TX;
- return (0);
+ return 0;
}
static void my3126_destroy(struct cphy *cphy)
@@ -170,13 +170,14 @@ static struct cphy *my3126_phy_create(adapter_t *adapter,
{
struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL);
- if (cphy)
- cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops);
+ if (!cphy)
+ return NULL;
+ cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops);
INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll);
cphy->bmsr = 0;
- return (cphy);
+ return cphy;
}
/* Chip Reset */
@@ -197,7 +198,7 @@ static int my3126_phy_reset(adapter_t * adapter)
val |= 0x8000;
t1_tpi_write(adapter, A_ELMER0_GPO, val);
udelay(100);
- return (0);
+ return 0;
}
struct gphy t1_my3126_ops = {
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c
index 63cabeb98af..69129edeefd 100644
--- a/drivers/net/chelsio/pm3393.c
+++ b/drivers/net/chelsio/pm3393.c
@@ -446,17 +446,51 @@ static void pm3393_rmon_update(struct adapter *adapter, u32 offs, u64 *val,
*val += 1ull << 40;
}
-#define RMON_UPDATE(mac, name, stat_name) \
- pm3393_rmon_update((mac)->adapter, OFFSET(name), \
- &(mac)->stats.stat_name, \
- (ro &((name - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2)))
-
-
static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
int flag)
{
- u64 ro;
- u32 val0, val1, val2, val3;
+ static struct {
+ unsigned int reg;
+ unsigned int offset;
+ } hw_stats [] = {
+
+#define HW_STAT(name, stat_name) \
+ { name, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+ /* Rx stats */
+ HW_STAT(RxOctetsReceivedOK, RxOctetsOK),
+ HW_STAT(RxUnicastFramesReceivedOK, RxUnicastFramesOK),
+ HW_STAT(RxMulticastFramesReceivedOK, RxMulticastFramesOK),
+ HW_STAT(RxBroadcastFramesReceivedOK, RxBroadcastFramesOK),
+ HW_STAT(RxPAUSEMACCtrlFramesReceived, RxPauseFrames),
+ HW_STAT(RxFrameCheckSequenceErrors, RxFCSErrors),
+ HW_STAT(RxFramesLostDueToInternalMACErrors,
+ RxInternalMACRcvError),
+ HW_STAT(RxSymbolErrors, RxSymbolErrors),
+ HW_STAT(RxInRangeLengthErrors, RxInRangeLengthErrors),
+ HW_STAT(RxFramesTooLongErrors , RxFrameTooLongErrors),
+ HW_STAT(RxJabbers, RxJabberErrors),
+ HW_STAT(RxFragments, RxRuntErrors),
+ HW_STAT(RxUndersizedFrames, RxRuntErrors),
+ HW_STAT(RxJumboFramesReceivedOK, RxJumboFramesOK),
+ HW_STAT(RxJumboOctetsReceivedOK, RxJumboOctetsOK),
+
+ /* Tx stats */
+ HW_STAT(TxOctetsTransmittedOK, TxOctetsOK),
+ HW_STAT(TxFramesLostDueToInternalMACTransmissionError,
+ TxInternalMACXmitError),
+ HW_STAT(TxTransmitSystemError, TxFCSErrors),
+ HW_STAT(TxUnicastFramesTransmittedOK, TxUnicastFramesOK),
+ HW_STAT(TxMulticastFramesTransmittedOK, TxMulticastFramesOK),
+ HW_STAT(TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK),
+ HW_STAT(TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames),
+ HW_STAT(TxJumboFramesReceivedOK, TxJumboFramesOK),
+ HW_STAT(TxJumboOctetsReceivedOK, TxJumboOctetsOK)
+ }, *p = hw_stats;
+ u64 ro;
+ u32 val0, val1, val2, val3;
+ u64 *stats = (u64 *) &mac->stats;
+ unsigned int i;
/* Snap the counters */
pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
@@ -470,35 +504,14 @@ static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) |
(((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48);
- /* Rx stats */
- RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK);
- RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK);
- RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK);
- RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK);
- RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames);
- RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors);
- RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors,
- RxInternalMACRcvError);
- RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
- RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors);
- RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors);
- RMON_UPDATE(mac, RxJabbers, RxJabberErrors);
- RMON_UPDATE(mac, RxFragments, RxRuntErrors);
- RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors);
- RMON_UPDATE(mac, RxJumboFramesReceivedOK, RxJumboFramesOK);
- RMON_UPDATE(mac, RxJumboOctetsReceivedOK, RxJumboOctetsOK);
-
- /* Tx stats */
- RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK);
- RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError,
- TxInternalMACXmitError);
- RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors);
- RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK);
- RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK);
- RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK);
- RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames);
- RMON_UPDATE(mac, TxJumboFramesReceivedOK, TxJumboFramesOK);
- RMON_UPDATE(mac, TxJumboOctetsReceivedOK, TxJumboOctetsOK);
+ for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
+ unsigned reg = p->reg - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW;
+
+ pm3393_rmon_update((mac)->adapter, OFFSET(p->reg),
+ stats + p->offset, ro & (reg >> 2));
+ }
+
+
return &mac->stats;
}
@@ -534,9 +547,9 @@ static int pm3393_macaddress_set(struct cmac *cmac, u8 ma[6])
/* Store local copy */
memcpy(cmac->instance->mac_addr, ma, 6);
- lo = ((u32) ma[1] << 8) | (u32) ma[0];
+ lo = ((u32) ma[1] << 8) | (u32) ma[0];
mid = ((u32) ma[3] << 8) | (u32) ma[2];
- hi = ((u32) ma[5] << 8) | (u32) ma[4];
+ hi = ((u32) ma[5] << 8) | (u32) ma[4];
/* Disable Rx/Tx MAC before configuring it. */
if (enabled)
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 0ca8d876e16..89a682702fa 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -71,12 +71,9 @@
#define SGE_FREEL_REFILL_THRESH 16
#define SGE_RESPQ_E_N 1024
#define SGE_INTRTIMER_NRES 1000
-#define SGE_RX_COPY_THRES 256
#define SGE_RX_SM_BUF_SIZE 1536
#define SGE_TX_DESC_MAX_PLEN 16384
-# define SGE_RX_DROP_THRES 2
-
#define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4)
/*
@@ -85,10 +82,6 @@
*/
#define TX_RECLAIM_PERIOD (HZ / 4)
-#ifndef NET_IP_ALIGN
-# define NET_IP_ALIGN 2
-#endif
-
#define M_CMD_LEN 0x7fffffff
#define V_CMD_LEN(v) (v)
#define G_CMD_LEN(v) ((v) & M_CMD_LEN)
@@ -195,7 +188,7 @@ struct cmdQ {
struct cmdQ_e *entries; /* HW command descriptor Q */
struct cmdQ_ce *centries; /* SW command context descriptor Q */
dma_addr_t dma_addr; /* DMA addr HW command descriptor Q */
- spinlock_t lock; /* Lock to protect cmdQ enqueuing */
+ spinlock_t lock; /* Lock to protect cmdQ enqueuing */
};
struct freelQ {
@@ -241,9 +234,9 @@ struct sched_port {
/* Per T204 device */
struct sched {
ktime_t last_updated; /* last time quotas were computed */
- unsigned int max_avail; /* max bits to be sent to any port */
- unsigned int port; /* port index (round robin ports) */
- unsigned int num; /* num skbs in per port queues */
+ unsigned int max_avail; /* max bits to be sent to any port */
+ unsigned int port; /* port index (round robin ports) */
+ unsigned int num; /* num skbs in per port queues */
struct sched_port p[MAX_NPORTS];
struct tasklet_struct sched_tsk;/* tasklet used to run scheduler */
};
@@ -259,10 +252,10 @@ static void restart_sched(unsigned long);
* contention.
*/
struct sge {
- struct adapter *adapter; /* adapter backpointer */
+ struct adapter *adapter; /* adapter backpointer */
struct net_device *netdev; /* netdevice backpointer */
- struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */
- struct respQ respQ; /* response Q */
+ struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */
+ struct respQ respQ; /* response Q */
unsigned long stopped_tx_queues; /* bitmap of suspended Tx queues */
unsigned int rx_pkt_pad; /* RX padding for L2 packets */
unsigned int jumbo_fl; /* jumbo freelist Q index */
@@ -460,7 +453,7 @@ static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb,
if (credits < MAX_SKB_FRAGS + 1)
goto out;
- again:
+again:
for (i = 0; i < MAX_NPORTS; i++) {
s->port = ++s->port & (MAX_NPORTS - 1);
skbq = &s->p[s->port].skbq;
@@ -483,8 +476,8 @@ static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb,
if (update-- && sched_update_avail(sge))
goto again;
- out:
- /* If there are more pending skbs, we use the hardware to schedule us
+out:
+ /* If there are more pending skbs, we use the hardware to schedule us
* again.
*/
if (s->num && !skb) {
@@ -575,11 +568,10 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p)
q->size = p->freelQ_size[i];
q->dma_offset = sge->rx_pkt_pad ? 0 : NET_IP_ALIGN;
size = sizeof(struct freelQ_e) * q->size;
- q->entries = (struct freelQ_e *)
- pci_alloc_consistent(pdev, size, &q->dma_addr);
+ q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr);
if (!q->entries)
goto err_no_mem;
- memset(q->entries, 0, size);
+
size = sizeof(struct freelQ_ce) * q->size;
q->centries = kzalloc(size, GFP_KERNEL);
if (!q->centries)
@@ -613,11 +605,10 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p)
sge->respQ.size = SGE_RESPQ_E_N;
sge->respQ.credits = 0;
size = sizeof(struct respQ_e) * sge->respQ.size;
- sge->respQ.entries = (struct respQ_e *)
+ sge->respQ.entries =
pci_alloc_consistent(pdev, size, &sge->respQ.dma_addr);
if (!sge->respQ.entries)
goto err_no_mem;
- memset(sge->respQ.entries, 0, size);
return 0;
err_no_mem:
@@ -637,20 +628,12 @@ static void free_cmdQ_buffers(struct sge *sge, struct cmdQ *q, unsigned int n)
q->in_use -= n;
ce = &q->centries[cidx];
while (n--) {
- if (q->sop) {
- if (likely(pci_unmap_len(ce, dma_len))) {
- pci_unmap_single(pdev,
- pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_TODEVICE);
+ if (likely(pci_unmap_len(ce, dma_len))) {
+ pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
+ pci_unmap_len(ce, dma_len),
+ PCI_DMA_TODEVICE);
+ if (q->sop)
q->sop = 0;
- }
- } else {
- if (likely(pci_unmap_len(ce, dma_len))) {
- pci_unmap_page(pdev, pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_TODEVICE);
- }
}
if (ce->skb) {
dev_kfree_skb_any(ce->skb);
@@ -711,11 +694,10 @@ static int alloc_tx_resources(struct sge *sge, struct sge_params *p)
q->stop_thres = 0;
spin_lock_init(&q->lock);
size = sizeof(struct cmdQ_e) * q->size;
- q->entries = (struct cmdQ_e *)
- pci_alloc_consistent(pdev, size, &q->dma_addr);
+ q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr);
if (!q->entries)
goto err_no_mem;
- memset(q->entries, 0, size);
+
size = sizeof(struct cmdQ_ce) * q->size;
q->centries = kzalloc(size, GFP_KERNEL);
if (!q->centries)
@@ -770,7 +752,7 @@ void t1_set_vlan_accel(struct adapter *adapter, int on_off)
static void configure_sge(struct sge *sge, struct sge_params *p)
{
struct adapter *ap = sge->adapter;
-
+
writel(0, ap->regs + A_SG_CONTROL);
setup_ring_params(ap, sge->cmdQ[0].dma_addr, sge->cmdQ[0].size,
A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE);
@@ -850,7 +832,6 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
struct freelQ_e *e = &q->entries[q->pidx];
unsigned int dma_len = q->rx_buffer_size - q->dma_offset;
-
while (q->credits < q->size) {
struct sk_buff *skb;
dma_addr_t mapping;
@@ -862,6 +843,8 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
skb_reserve(skb, q->dma_offset);
mapping = pci_map_single(pdev, skb->data, dma_len,
PCI_DMA_FROMDEVICE);
+ skb_reserve(skb, sge->rx_pkt_pad);
+
ce->skb = skb;
pci_unmap_addr_set(ce, dma_addr, mapping);
pci_unmap_len_set(ce, dma_len, dma_len);
@@ -881,7 +864,6 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
}
q->credits++;
}
-
}
/*
@@ -1041,6 +1023,10 @@ static void recycle_fl_buf(struct freelQ *fl, int idx)
}
}
+static int copybreak __read_mostly = 256;
+module_param(copybreak, int, 0);
+MODULE_PARM_DESC(copybreak, "Receive copy threshold");
+
/**
* get_packet - return the next ingress packet buffer
* @pdev: the PCI device that received the packet
@@ -1060,45 +1046,42 @@ static void recycle_fl_buf(struct freelQ *fl, int idx)
* be copied but there is no memory for the copy.
*/
static inline struct sk_buff *get_packet(struct pci_dev *pdev,
- struct freelQ *fl, unsigned int len,
- int dma_pad, int skb_pad,
- unsigned int copy_thres,
- unsigned int drop_thres)
+ struct freelQ *fl, unsigned int len)
{
struct sk_buff *skb;
- struct freelQ_ce *ce = &fl->centries[fl->cidx];
+ const struct freelQ_ce *ce = &fl->centries[fl->cidx];
- if (len < copy_thres) {
- skb = alloc_skb(len + skb_pad, GFP_ATOMIC);
- if (likely(skb != NULL)) {
- skb_reserve(skb, skb_pad);
- skb_put(skb, len);
- pci_dma_sync_single_for_cpu(pdev,
- pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_FROMDEVICE);
- memcpy(skb->data, ce->skb->data + dma_pad, len);
- pci_dma_sync_single_for_device(pdev,
- pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_FROMDEVICE);
- } else if (!drop_thres)
+ if (len < copybreak) {
+ skb = alloc_skb(len + 2, GFP_ATOMIC);
+ if (!skb)
goto use_orig_buf;
+ skb_reserve(skb, 2); /* align IP header */
+ skb_put(skb, len);
+ pci_dma_sync_single_for_cpu(pdev,
+ pci_unmap_addr(ce, dma_addr),
+ pci_unmap_len(ce, dma_len),
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, ce->skb->data, len);
+ pci_dma_sync_single_for_device(pdev,
+ pci_unmap_addr(ce, dma_addr),
+ pci_unmap_len(ce, dma_len),
+ PCI_DMA_FROMDEVICE);
recycle_fl_buf(fl, fl->cidx);
return skb;
}
- if (fl->credits < drop_thres) {
+use_orig_buf:
+ if (fl->credits < 2) {
recycle_fl_buf(fl, fl->cidx);
return NULL;
}
-use_orig_buf:
pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
skb = ce->skb;
- skb_reserve(skb, dma_pad);
+ prefetch(skb->data);
+
skb_put(skb, len);
return skb;
}
@@ -1137,6 +1120,7 @@ static void unexpected_offload(struct adapter *adapter, struct freelQ *fl)
static inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb)
{
unsigned int count = 0;
+
if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) {
unsigned int nfrags = skb_shinfo(skb)->nr_frags;
unsigned int i, len = skb->len - skb->data_len;
@@ -1343,7 +1327,7 @@ static void restart_sched(unsigned long arg)
while ((skb = sched_skb(sge, NULL, credits)) != NULL) {
unsigned int genbit, pidx, count;
count = 1 + skb_shinfo(skb)->nr_frags;
- count += compute_large_page_tx_descs(skb);
+ count += compute_large_page_tx_descs(skb);
q->in_use += count;
genbit = q->genbit;
pidx = q->pidx;
@@ -1375,27 +1359,25 @@ static void restart_sched(unsigned long arg)
*
* Process an ingress ethernet pakcet and deliver it to the stack.
*/
-static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
+static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
{
struct sk_buff *skb;
- struct cpl_rx_pkt *p;
+ const struct cpl_rx_pkt *p;
struct adapter *adapter = sge->adapter;
struct sge_port_stats *st;
- skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad,
- sge->rx_pkt_pad, 2, SGE_RX_COPY_THRES,
- SGE_RX_DROP_THRES);
+ skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad);
if (unlikely(!skb)) {
sge->stats.rx_drops++;
- return 0;
+ return;
}
- p = (struct cpl_rx_pkt *)skb->data;
- skb_pull(skb, sizeof(*p));
+ p = (const struct cpl_rx_pkt *) skb->data;
if (p->iff >= adapter->params.nports) {
kfree_skb(skb);
- return 0;
+ return;
}
+ __skb_pull(skb, sizeof(*p));
skb->dev = adapter->port[p->iff].dev;
skb->dev->last_rx = jiffies;
@@ -1413,17 +1395,20 @@ static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
if (unlikely(adapter->vlan_grp && p->vlan_valid)) {
st->vlan_xtract++;
- if (adapter->params.sge.polling)
+#ifdef CONFIG_CHELSIO_T1_NAPI
vlan_hwaccel_receive_skb(skb, adapter->vlan_grp,
ntohs(p->vlan));
- else
+#else
vlan_hwaccel_rx(skb, adapter->vlan_grp,
ntohs(p->vlan));
- } else if (adapter->params.sge.polling)
+#endif
+ } else {
+#ifdef CONFIG_CHELSIO_T1_NAPI
netif_receive_skb(skb);
- else
+#else
netif_rx(skb);
- return 0;
+#endif
+ }
}
/*
@@ -1444,29 +1429,28 @@ static inline int enough_free_Tx_descs(const struct cmdQ *q)
static void restart_tx_queues(struct sge *sge)
{
struct adapter *adap = sge->adapter;
+ int i;
- if (enough_free_Tx_descs(&sge->cmdQ[0])) {
- int i;
+ if (!enough_free_Tx_descs(&sge->cmdQ[0]))
+ return;
- for_each_port(adap, i) {
- struct net_device *nd = adap->port[i].dev;
+ for_each_port(adap, i) {
+ struct net_device *nd = adap->port[i].dev;
- if (test_and_clear_bit(nd->if_port,
- &sge->stopped_tx_queues) &&
- netif_running(nd)) {
- sge->stats.cmdQ_restarted[2]++;
- netif_wake_queue(nd);
- }
+ if (test_and_clear_bit(nd->if_port, &sge->stopped_tx_queues) &&
+ netif_running(nd)) {
+ sge->stats.cmdQ_restarted[2]++;
+ netif_wake_queue(nd);
}
}
}
/*
- * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0
+ * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0
* information.
*/
-static unsigned int update_tx_info(struct adapter *adapter,
- unsigned int flags,
+static unsigned int update_tx_info(struct adapter *adapter,
+ unsigned int flags,
unsigned int pr0)
{
struct sge *sge = adapter->sge;
@@ -1506,29 +1490,30 @@ static int process_responses(struct adapter *adapter, int budget)
struct sge *sge = adapter->sge;
struct respQ *q = &sge->respQ;
struct respQ_e *e = &q->entries[q->cidx];
- int budget_left = budget;
+ int done = 0;
unsigned int flags = 0;
unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
-
- while (likely(budget_left && e->GenerationBit == q->genbit)) {
+ while (done < budget && e->GenerationBit == q->genbit) {
flags |= e->Qsleeping;
-
+
cmdq_processed[0] += e->Cmdq0CreditReturn;
cmdq_processed[1] += e->Cmdq1CreditReturn;
-
+
/* We batch updates to the TX side to avoid cacheline
* ping-pong of TX state information on MP where the sender
* might run on a different CPU than this function...
*/
- if (unlikely(flags & F_CMDQ0_ENABLE || cmdq_processed[0] > 64)) {
+ if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) {
flags = update_tx_info(adapter, flags, cmdq_processed[0]);
cmdq_processed[0] = 0;
}
+
if (unlikely(cmdq_processed[1] > 16)) {
sge->cmdQ[1].processed += cmdq_processed[1];
cmdq_processed[1] = 0;
}
+
if (likely(e->DataValid)) {
struct freelQ *fl = &sge->freelQ[e->FreelistQid];
@@ -1538,12 +1523,16 @@ static int process_responses(struct adapter *adapter, int budget)
else
sge_rx(sge, fl, e->BufferLength);
+ ++done;
+
/*
* Note: this depends on each packet consuming a
* single free-list buffer; cf. the BUG above.
*/
if (++fl->cidx == fl->size)
fl->cidx = 0;
+ prefetch(fl->centries[fl->cidx].skb);
+
if (unlikely(--fl->credits <
fl->size - SGE_FREEL_REFILL_THRESH))
refill_free_list(sge, fl);
@@ -1562,16 +1551,23 @@ static int process_responses(struct adapter *adapter, int budget)
writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT);
q->credits = 0;
}
- --budget_left;
}
- flags = update_tx_info(adapter, flags, cmdq_processed[0]);
+ flags = update_tx_info(adapter, flags, cmdq_processed[0]);
sge->cmdQ[1].processed += cmdq_processed[1];
- budget -= budget_left;
- return budget;
+ return done;
}
+static inline int responses_pending(const struct adapter *adapter)
+{
+ const struct respQ *Q = &adapter->sge->respQ;
+ const struct respQ_e *e = &Q->entries[Q->cidx];
+
+ return (e->GenerationBit == Q->genbit);
+}
+
+#ifdef CONFIG_CHELSIO_T1_NAPI
/*
* A simpler version of process_responses() that handles only pure (i.e.,
* non data-carrying) responses. Such respones are too light-weight to justify
@@ -1580,19 +1576,25 @@ static int process_responses(struct adapter *adapter, int budget)
* which the caller must ensure is a valid pure response. Returns 1 if it
* encounters a valid data-carrying response, 0 otherwise.
*/
-static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
+static int process_pure_responses(struct adapter *adapter)
{
struct sge *sge = adapter->sge;
struct respQ *q = &sge->respQ;
+ struct respQ_e *e = &q->entries[q->cidx];
+ const struct freelQ *fl = &sge->freelQ[e->FreelistQid];
unsigned int flags = 0;
unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
+ prefetch(fl->centries[fl->cidx].skb);
+ if (e->DataValid)
+ return 1;
+
do {
flags |= e->Qsleeping;
cmdq_processed[0] += e->Cmdq0CreditReturn;
cmdq_processed[1] += e->Cmdq1CreditReturn;
-
+
e++;
if (unlikely(++q->cidx == q->size)) {
q->cidx = 0;
@@ -1608,7 +1610,7 @@ static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
sge->stats.pure_rsps++;
} while (e->GenerationBit == q->genbit && !e->DataValid);
- flags = update_tx_info(adapter, flags, cmdq_processed[0]);
+ flags = update_tx_info(adapter, flags, cmdq_processed[0]);
sge->cmdQ[1].processed += cmdq_processed[1];
return e->GenerationBit == q->genbit;
@@ -1619,92 +1621,62 @@ static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
* or protection from interrupts as data interrupts are off at this point and
* other adapter interrupts do not interfere.
*/
-static int t1_poll(struct net_device *dev, int *budget)
+int t1_poll(struct net_device *dev, int *budget)
{
struct adapter *adapter = dev->priv;
- int effective_budget = min(*budget, dev->quota);
+ int work_done;
- int work_done = process_responses(adapter, effective_budget);
+ work_done = process_responses(adapter, min(*budget, dev->quota));
*budget -= work_done;
dev->quota -= work_done;
- if (work_done >= effective_budget)
+ if (unlikely(responses_pending(adapter)))
return 1;
- __netif_rx_complete(dev);
-
- /*
- * Because we don't atomically flush the following write it is
- * possible that in very rare cases it can reach the device in a way
- * that races with a new response being written plus an error interrupt
- * causing the NAPI interrupt handler below to return unhandled status
- * to the OS. To protect against this would require flushing the write
- * and doing both the write and the flush with interrupts off. Way too
- * expensive and unjustifiable given the rarity of the race.
- */
+ netif_rx_complete(dev);
writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
+
return 0;
-}
-/*
- * Returns true if the device is already scheduled for polling.
- */
-static inline int napi_is_scheduled(struct net_device *dev)
-{
- return test_bit(__LINK_STATE_RX_SCHED, &dev->state);
}
/*
* NAPI version of the main interrupt handler.
*/
-static irqreturn_t t1_interrupt_napi(int irq, void *data)
+irqreturn_t t1_interrupt(int irq, void *data)
{
- int handled;
struct adapter *adapter = data;
struct sge *sge = adapter->sge;
- struct respQ *q = &adapter->sge->respQ;
+ int handled;
- /*
- * Clear the SGE_DATA interrupt first thing. Normally the NAPI
- * handler has control of the response queue and the interrupt handler
- * can look at the queue reliably only once it knows NAPI is off.
- * We can't wait that long to clear the SGE_DATA interrupt because we
- * could race with t1_poll rearming the SGE interrupt, so we need to
- * clear the interrupt speculatively and really early on.
- */
- writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
+ if (likely(responses_pending(adapter))) {
+ struct net_device *dev = sge->netdev;
- spin_lock(&adapter->async_lock);
- if (!napi_is_scheduled(sge->netdev)) {
- struct respQ_e *e = &q->entries[q->cidx];
-
- if (e->GenerationBit == q->genbit) {
- if (e->DataValid ||
- process_pure_responses(adapter, e)) {
- if (likely(__netif_rx_schedule_prep(sge->netdev)))
- __netif_rx_schedule(sge->netdev);
- else if (net_ratelimit())
- printk(KERN_INFO
- "NAPI schedule failure!\n");
- } else
- writel(q->cidx, adapter->regs + A_SG_SLEEPING);
-
- handled = 1;
- goto unlock;
- } else
- writel(q->cidx, adapter->regs + A_SG_SLEEPING);
- } else if (readl(adapter->regs + A_PL_CAUSE) & F_PL_INTR_SGE_DATA) {
- printk(KERN_ERR "data interrupt while NAPI running\n");
+ writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
+
+ if (__netif_rx_schedule_prep(dev)) {
+ if (process_pure_responses(adapter))
+ __netif_rx_schedule(dev);
+ else {
+ /* no data, no NAPI needed */
+ writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
+ netif_poll_enable(dev); /* undo schedule_prep */
+ }
+ }
+ return IRQ_HANDLED;
}
-
+
+ spin_lock(&adapter->async_lock);
handled = t1_slow_intr_handler(adapter);
+ spin_unlock(&adapter->async_lock);
+
if (!handled)
sge->stats.unhandled_irqs++;
- unlock:
- spin_unlock(&adapter->async_lock);
+
return IRQ_RETVAL(handled != 0);
}
+#else
/*
* Main interrupt handler, optimized assuming that we took a 'DATA'
* interrupt.
@@ -1720,20 +1692,16 @@ static irqreturn_t t1_interrupt_napi(int irq, void *data)
* 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)
+irqreturn_t t1_interrupt(int irq, void *cookie)
{
int work_done;
- struct respQ_e *e;
struct adapter *adapter = cookie;
- struct respQ *Q = &adapter->sge->respQ;
spin_lock(&adapter->async_lock);
- e = &Q->entries[Q->cidx];
- prefetch(e);
writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
- if (likely(e->GenerationBit == Q->genbit))
+ if (likely(responses_pending(adapter)))
work_done = process_responses(adapter, -1);
else
work_done = t1_slow_intr_handler(adapter);
@@ -1752,11 +1720,7 @@ static irqreturn_t t1_interrupt(int irq, void *cookie)
spin_unlock(&adapter->async_lock);
return IRQ_RETVAL(work_done != 0);
}
-
-irq_handler_t t1_select_intr_handler(adapter_t *adapter)
-{
- return adapter->params.sge.polling ? t1_interrupt_napi : t1_interrupt;
-}
+#endif
/*
* Enqueues the sk_buff onto the cmdQ[qid] and has hardware fetch it.
@@ -1811,7 +1775,7 @@ static int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
* through the scheduler.
*/
if (sge->tx_sched && !qid && skb->dev) {
- use_sched:
+use_sched:
use_sched_skb = 1;
/* Note that the scheduler might return a different skb than
* the one passed in.
@@ -1915,7 +1879,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
cpl = (struct cpl_tx_pkt *)hdr;
} else {
/*
- * Packets shorter than ETH_HLEN can break the MAC, drop them
+ * Packets shorter than ETH_HLEN can break the MAC, drop them
* early. Also, we may get oversized packets because some
* parts of the kernel don't handle our unusual hard_header_len
* right, drop those too.
@@ -1999,9 +1963,9 @@ send:
* then silently discard to avoid leak.
*/
if (unlikely(ret != NETDEV_TX_OK && skb != orig_skb)) {
- dev_kfree_skb_any(skb);
+ dev_kfree_skb_any(skb);
ret = NETDEV_TX_OK;
- }
+ }
return ret;
}
@@ -2033,7 +1997,6 @@ static void sge_tx_reclaim_cb(unsigned long data)
*/
int t1_sge_set_coalesce_params(struct sge *sge, struct sge_params *p)
{
- sge->netdev->poll = t1_poll;
sge->fixed_intrtimer = p->rx_coalesce_usecs *
core_ticks_per_usec(sge->adapter);
writel(sge->fixed_intrtimer, sge->adapter->regs + A_SG_INTRTIMER);
@@ -2115,31 +2078,35 @@ static void espibug_workaround_t204(unsigned long data)
if (adapter->open_device_map & PORT_MASK) {
int i;
- if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) {
+
+ if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0)
return;
- }
+
for (i = 0; i < nports; i++) {
- struct sk_buff *skb = sge->espibug_skb[i];
- if ( (netif_running(adapter->port[i].dev)) &&
- !(netif_queue_stopped(adapter->port[i].dev)) &&
- (seop[i] && ((seop[i] & 0xfff) == 0)) &&
- skb ) {
- if (!skb->cb[0]) {
- u8 ch_mac_addr[ETH_ALEN] =
- {0x0, 0x7, 0x43, 0x0, 0x0, 0x0};
- memcpy(skb->data + sizeof(struct cpl_tx_pkt),
- ch_mac_addr, ETH_ALEN);
- memcpy(skb->data + skb->len - 10,
- ch_mac_addr, ETH_ALEN);
- skb->cb[0] = 0xff;
- }
-
- /* bump the reference count to avoid freeing of
- * the skb once the DMA has completed.
- */
- skb = skb_get(skb);
- t1_sge_tx(skb, adapter, 0, adapter->port[i].dev);
+ struct sk_buff *skb = sge->espibug_skb[i];
+
+ if (!netif_running(adapter->port[i].dev) ||
+ netif_queue_stopped(adapter->port[i].dev) ||
+ !seop[i] || ((seop[i] & 0xfff) != 0) || !skb)
+ continue;
+
+ if (!skb->cb[0]) {
+ u8 ch_mac_addr[ETH_ALEN] = {
+ 0x0, 0x7, 0x43, 0x0, 0x0, 0x0
+ };
+
+ memcpy(skb->data + sizeof(struct cpl_tx_pkt),
+ ch_mac_addr, ETH_ALEN);
+ memcpy(skb->data + skb->len - 10,
+ ch_mac_addr, ETH_ALEN);
+ skb->cb[0] = 0xff;
}
+
+ /* bump the reference count to avoid freeing of
+ * the skb once the DMA has completed.
+ */
+ skb = skb_get(skb);
+ t1_sge_tx(skb, adapter, 0, adapter->port[i].dev);
}
}
mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout);
@@ -2208,9 +2175,8 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter,
if (adapter->params.nports > 1) {
tx_sched_init(sge);
sge->espibug_timer.function = espibug_workaround_t204;
- } else {
+ } else
sge->espibug_timer.function = espibug_workaround;
- }
sge->espibug_timer.data = (unsigned long)sge->adapter;
sge->espibug_timeout = 1;
@@ -2218,7 +2184,7 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter,
if (adapter->params.nports > 1)
sge->espibug_timeout = HZ/100;
}
-
+
p->cmdQ_size[0] = SGE_CMDQ0_E_N;
p->cmdQ_size[1] = SGE_CMDQ1_E_N;
@@ -2234,7 +2200,6 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter,
p->coalesce_enable = 0;
p->sample_interval_usecs = 0;
- p->polling = 0;
return sge;
nomem_port:
diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h
index 7ceb0117d03..d132a0ef2a2 100644
--- a/drivers/net/chelsio/sge.h
+++ b/drivers/net/chelsio/sge.h
@@ -76,7 +76,9 @@ 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 *);
-irq_handler_t t1_select_intr_handler(adapter_t *adapter);
+irqreturn_t t1_interrupt(int irq, void *cookie);
+int t1_poll(struct net_device *, int *);
+
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/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 22ed9a383c0..c2522cdfab3 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -223,13 +223,13 @@ static int fpga_slow_intr(adapter_t *adapter)
t1_sge_intr_error_handler(adapter->sge);
if (cause & FPGA_PCIX_INTERRUPT_GMAC)
- fpga_phy_intr_handler(adapter);
+ fpga_phy_intr_handler(adapter);
if (cause & FPGA_PCIX_INTERRUPT_TP) {
- /*
+ /*
* FPGA doesn't support MC4 interrupts and it requires
* this odd layer of indirection for MC5.
- */
+ */
u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
/* Clear TP interrupt */
@@ -262,8 +262,7 @@ static int mi1_wait_until_ready(adapter_t *adapter, int mi1_reg)
udelay(10);
} while (busy && --attempts);
if (busy)
- CH_ALERT("%s: MDIO operation timed out\n",
- adapter->name);
+ CH_ALERT("%s: MDIO operation timed out\n", adapter->name);
return busy;
}
@@ -605,22 +604,23 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
switch (board_info(adapter)->board) {
#ifdef CONFIG_CHELSIO_T1_1G
- case CHBT_BOARD_CHT204:
- case CHBT_BOARD_CHT204E:
- case CHBT_BOARD_CHN204:
- case CHBT_BOARD_CHT204V: {
- int i, port_bit;
+ case CHBT_BOARD_CHT204:
+ case CHBT_BOARD_CHT204E:
+ case CHBT_BOARD_CHN204:
+ case CHBT_BOARD_CHT204V: {
+ int i, port_bit;
for_each_port(adapter, i) {
port_bit = i + 1;
- if (!(cause & (1 << port_bit))) continue;
+ if (!(cause & (1 << port_bit)))
+ continue;
- phy = adapter->port[i].phy;
+ phy = adapter->port[i].phy;
phy_cause = phy->ops->interrupt_handler(phy);
if (phy_cause & cphy_cause_link_change)
t1_link_changed(adapter, i);
}
- break;
- }
+ break;
+ }
case CHBT_BOARD_CHT101:
if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */
phy = adapter->port[0].phy;
@@ -631,13 +631,13 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
break;
case CHBT_BOARD_7500: {
int p;
- /*
+ /*
* Elmer0's interrupt cause isn't useful here because there is
* only one bit that can be set for all 4 ports. This means
* we are forced to check every PHY's interrupt status
* register to see who initiated the interrupt.
- */
- for_each_port(adapter, p) {
+ */
+ for_each_port(adapter, p) {
phy = adapter->port[p].phy;
phy_cause = phy->ops->interrupt_handler(phy);
if (phy_cause & cphy_cause_link_change)
@@ -658,7 +658,7 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
break;
case CHBT_BOARD_8000:
case CHBT_BOARD_CHT110:
- CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
+ CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
cause);
if (cause & ELMER0_GP_BIT1) { /* PMC3393 INTB */
struct cmac *mac = adapter->port[0].mac;
@@ -670,9 +670,9 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
t1_tpi_read(adapter,
A_ELMER0_GPI_STAT, &mod_detect);
- CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
+ CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
mod_detect ? "removed" : "inserted");
- }
+ }
break;
#ifdef CONFIG_CHELSIO_T1_COUGAR
case CHBT_BOARD_COUGAR:
@@ -688,7 +688,8 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
for_each_port(adapter, i) {
port_bit = i ? i + 1 : 0;
- if (!(cause & (1 << port_bit))) continue;
+ if (!(cause & (1 << port_bit)))
+ continue;
phy = adapter->port[i].phy;
phy_cause = phy->ops->interrupt_handler(phy);
@@ -755,7 +756,7 @@ void t1_interrupts_disable(adapter_t* adapter)
/* Disable PCIX & external chip interrupts. */
if (t1_is_asic(adapter))
- writel(0, adapter->regs + A_PL_ENABLE);
+ writel(0, adapter->regs + A_PL_ENABLE);
/* PCI-X interrupts */
pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0);
@@ -830,11 +831,11 @@ int t1_slow_intr_handler(adapter_t *adapter)
/* Power sequencing is a work-around for Intel's XPAKs. */
static void power_sequence_xpak(adapter_t* adapter)
{
- u32 mod_detect;
- u32 gpo;
+ u32 mod_detect;
+ u32 gpo;
- /* Check for XPAK */
- t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
+ /* Check for XPAK */
+ t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
if (!(ELMER0_GP_BIT5 & mod_detect)) {
/* XPAK is present */
t1_tpi_read(adapter, A_ELMER0_GPO, &gpo);
@@ -877,31 +878,31 @@ static int board_init(adapter_t *adapter, const struct board_info *bi)
case CHBT_BOARD_N210:
case CHBT_BOARD_CHT210:
case CHBT_BOARD_COUGAR:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
break;
case CHBT_BOARD_CHT110:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
- /* TBD XXX Might not need. This fixes a problem
- * described in the Intel SR XPAK errata.
- */
- power_sequence_xpak(adapter);
+ /* TBD XXX Might not need. This fixes a problem
+ * described in the Intel SR XPAK errata.
+ */
+ power_sequence_xpak(adapter);
break;
#ifdef CONFIG_CHELSIO_T1_1G
- case CHBT_BOARD_CHT204E:
- /* add config space write here */
+ case CHBT_BOARD_CHT204E:
+ /* add config space write here */
case CHBT_BOARD_CHT204:
case CHBT_BOARD_CHT204V:
case CHBT_BOARD_CHN204:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
- break;
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
+ break;
case CHBT_BOARD_CHT101:
case CHBT_BOARD_7500:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
break;
#endif
}
@@ -941,7 +942,7 @@ int t1_init_hw_modules(adapter_t *adapter)
goto out_err;
err = 0;
- out_err:
+out_err:
return err;
}
@@ -983,7 +984,7 @@ void t1_free_sw_modules(adapter_t *adapter)
if (adapter->espi)
t1_espi_destroy(adapter->espi);
#ifdef CONFIG_CHELSIO_T1_COUGAR
- if (adapter->cspi)
+ if (adapter->cspi)
t1_cspi_destroy(adapter->cspi);
#endif
}
@@ -1010,7 +1011,7 @@ static void __devinit init_link_config(struct link_config *lc,
CH_ERR("%s: CSPI initialization failed\n",
adapter->name);
goto error;
- }
+ }
#endif
/*
diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c
index 0ca0b6e19e4..6222d585e44 100644
--- a/drivers/net/chelsio/tp.c
+++ b/drivers/net/chelsio/tp.c
@@ -17,39 +17,36 @@ struct petp {
static void tp_init(adapter_t * ap, const struct tp_params *p,
unsigned int tp_clk)
{
- if (t1_is_asic(ap)) {
- u32 val;
-
- val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
- F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
- if (!p->pm_size)
- val |= F_OFFLOAD_DISABLE;
- else
- val |= F_TP_IN_ESPI_CHECK_IP_CSUM |
- F_TP_IN_ESPI_CHECK_TCP_CSUM;
- writel(val, ap->regs + A_TP_IN_CONFIG);
- writel(F_TP_OUT_CSPI_CPL |
- F_TP_OUT_ESPI_ETHERNET |
- F_TP_OUT_ESPI_GENERATE_IP_CSUM |
- F_TP_OUT_ESPI_GENERATE_TCP_CSUM,
- ap->regs + A_TP_OUT_CONFIG);
- writel(V_IP_TTL(64) |
- F_PATH_MTU /* IP DF bit */ |
- V_5TUPLE_LOOKUP(p->use_5tuple_mode) |
- V_SYN_COOKIE_PARAMETER(29),
- ap->regs + A_TP_GLOBAL_CONFIG);
- /*
- * Enable pause frame deadlock prevention.
- */
- if (is_T2(ap) && ap->params.nports > 1) {
- u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
-
- writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
- V_DROP_TICKS_CNT(drop_ticks) |
- V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
- ap->regs + A_TP_TX_DROP_CONFIG);
- }
+ u32 val;
+ if (!t1_is_asic(ap))
+ return;
+
+ val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
+ F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
+ if (!p->pm_size)
+ val |= F_OFFLOAD_DISABLE;
+ else
+ val |= F_TP_IN_ESPI_CHECK_IP_CSUM | F_TP_IN_ESPI_CHECK_TCP_CSUM;
+ writel(val, ap->regs + A_TP_IN_CONFIG);
+ writel(F_TP_OUT_CSPI_CPL |
+ F_TP_OUT_ESPI_ETHERNET |
+ F_TP_OUT_ESPI_GENERATE_IP_CSUM |
+ F_TP_OUT_ESPI_GENERATE_TCP_CSUM, ap->regs + A_TP_OUT_CONFIG);
+ writel(V_IP_TTL(64) |
+ F_PATH_MTU /* IP DF bit */ |
+ V_5TUPLE_LOOKUP(p->use_5tuple_mode) |
+ V_SYN_COOKIE_PARAMETER(29), ap->regs + A_TP_GLOBAL_CONFIG);
+ /*
+ * Enable pause frame deadlock prevention.
+ */
+ if (is_T2(ap) && ap->params.nports > 1) {
+ u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
+
+ writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
+ V_DROP_TICKS_CNT(drop_ticks) |
+ V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
+ ap->regs + A_TP_TX_DROP_CONFIG);
}
}
@@ -61,6 +58,7 @@ void t1_tp_destroy(struct petp *tp)
struct petp *__devinit t1_tp_create(adapter_t * adapter, struct tp_params *p)
{
struct petp *tp = kzalloc(sizeof(*tp), GFP_KERNEL);
+
if (!tp)
return NULL;
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c
index 85dc3b1dc30..534ffa0f616 100644
--- a/drivers/net/chelsio/vsc7326.c
+++ b/drivers/net/chelsio/vsc7326.c
@@ -226,22 +226,21 @@ static void run_table(adapter_t *adapter, struct init_table *ib, int len)
if (ib[i].addr == INITBLOCK_SLEEP) {
udelay( ib[i].data );
CH_ERR("sleep %d us\n",ib[i].data);
- } else {
+ } else
vsc_write( adapter, ib[i].addr, ib[i].data );
- }
}
}
static int bist_rd(adapter_t *adapter, int moduleid, int address)
{
- int data=0;
- u32 result=0;
-
- if( (address != 0x0) &&
- (address != 0x1) &&
- (address != 0x2) &&
- (address != 0xd) &&
- (address != 0xe))
+ int data = 0;
+ u32 result = 0;
+
+ if ((address != 0x0) &&
+ (address != 0x1) &&
+ (address != 0x2) &&
+ (address != 0xd) &&
+ (address != 0xe))
CH_ERR("No bist address: 0x%x\n", address);
data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) |
@@ -251,27 +250,27 @@ static int bist_rd(adapter_t *adapter, int moduleid, int address)
udelay(10);
vsc_read(adapter, REG_RAM_BIST_RESULT, &result);
- if((result & (1<<9)) != 0x0)
+ if ((result & (1 << 9)) != 0x0)
CH_ERR("Still in bist read: 0x%x\n", result);
- else if((result & (1<<8)) != 0x0)
+ else if ((result & (1 << 8)) != 0x0)
CH_ERR("bist read error: 0x%x\n", result);
- return(result & 0xff);
+ return (result & 0xff);
}
static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
{
- int data=0;
- u32 result=0;
-
- if( (address != 0x0) &&
- (address != 0x1) &&
- (address != 0x2) &&
- (address != 0xd) &&
- (address != 0xe))
+ int data = 0;
+ u32 result = 0;
+
+ if ((address != 0x0) &&
+ (address != 0x1) &&
+ (address != 0x2) &&
+ (address != 0xd) &&
+ (address != 0xe))
CH_ERR("No bist address: 0x%x\n", address);
- if( value>255 )
+ if (value > 255)
CH_ERR("Suspicious write out of range value: 0x%x\n", value);
data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) |
@@ -281,12 +280,12 @@ static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
udelay(5);
vsc_read(adapter, REG_RAM_BIST_CMD, &result);
- if((result & (1<<27)) != 0x0)
+ if ((result & (1 << 27)) != 0x0)
CH_ERR("Still in bist write: 0x%x\n", result);
- else if((result & (1<<26)) != 0x0)
+ else if ((result & (1 << 26)) != 0x0)
CH_ERR("bist write error: 0x%x\n", result);
- return(0);
+ return 0;
}
static int run_bist(adapter_t *adapter, int moduleid)
@@ -295,7 +294,7 @@ static int run_bist(adapter_t *adapter, int moduleid)
(void) bist_wr(adapter,moduleid, 0x00, 0x02);
(void) bist_wr(adapter,moduleid, 0x01, 0x01);
- return(0);
+ return 0;
}
static int check_bist(adapter_t *adapter, int moduleid)
@@ -309,27 +308,26 @@ static int check_bist(adapter_t *adapter, int moduleid)
if ((result & 3) != 0x3)
CH_ERR("Result: 0x%x BIST error in ram %d, column: 0x%04x\n",
result, moduleid, column);
- return(0);
+ return 0;
}
static int enable_mem(adapter_t *adapter, int moduleid)
{
/*enable mem*/
(void) bist_wr(adapter,moduleid, 0x00, 0x00);
- return(0);
+ return 0;
}
static int run_bist_all(adapter_t *adapter)
{
- int port=0;
- u32 val=0;
+ int port = 0;
+ u32 val = 0;
vsc_write(adapter, REG_MEM_BIST, 0x5);
vsc_read(adapter, REG_MEM_BIST, &val);
- for(port=0; port<12; port++){
+ for (port = 0; port < 12; port++)
vsc_write(adapter, REG_DEV_SETUP(port), 0x0);
- }
udelay(300);
vsc_write(adapter, REG_SPI4_MISC, 0x00040409);
@@ -352,13 +350,13 @@ static int run_bist_all(adapter_t *adapter)
udelay(300);
vsc_write(adapter, REG_SPI4_MISC, 0x60040400);
udelay(300);
- for(port=0; port<12; port++){
+ for (port = 0; port < 12; port++)
vsc_write(adapter, REG_DEV_SETUP(port), 0x1);
- }
+
udelay(300);
vsc_write(adapter, REG_MEM_BIST, 0x0);
mdelay(10);
- return(0);
+ return 0;
}
static int mac_intr_handler(struct cmac *mac)
@@ -591,40 +589,46 @@ static void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat)
static void port_stats_update(struct cmac *mac)
{
- int port = mac->instance->index;
+ struct {
+ unsigned int reg;
+ unsigned int offset;
+ } hw_stats[] = {
+
+#define HW_STAT(reg, stat_name) \
+ { reg, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+ /* Rx stats */
+ HW_STAT(RxUnicast, RxUnicastFramesOK),
+ HW_STAT(RxMulticast, RxMulticastFramesOK),
+ HW_STAT(RxBroadcast, RxBroadcastFramesOK),
+ HW_STAT(Crc, RxFCSErrors),
+ HW_STAT(RxAlignment, RxAlignErrors),
+ HW_STAT(RxOversize, RxFrameTooLongErrors),
+ HW_STAT(RxPause, RxPauseFrames),
+ HW_STAT(RxJabbers, RxJabberErrors),
+ HW_STAT(RxFragments, RxRuntErrors),
+ HW_STAT(RxUndersize, RxRuntErrors),
+ HW_STAT(RxSymbolCarrier, RxSymbolErrors),
+ HW_STAT(RxSize1519ToMax, RxJumboFramesOK),
+
+ /* Tx stats (skip collision stats as we are full-duplex only) */
+ HW_STAT(TxUnicast, TxUnicastFramesOK),
+ HW_STAT(TxMulticast, TxMulticastFramesOK),
+ HW_STAT(TxBroadcast, TxBroadcastFramesOK),
+ HW_STAT(TxPause, TxPauseFrames),
+ HW_STAT(TxUnderrun, TxUnderrun),
+ HW_STAT(TxSize1519ToMax, TxJumboFramesOK),
+ }, *p = hw_stats;
+ unsigned int port = mac->instance->index;
+ u64 *stats = (u64 *)&mac->stats;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_stats); i++)
+ rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset);
- /* Rx stats */
+ rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK);
rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad);
- rmon_update(mac, REG_RX_UNICAST(port), &mac->stats.RxUnicastFramesOK);
- rmon_update(mac, REG_RX_MULTICAST(port),
- &mac->stats.RxMulticastFramesOK);
- rmon_update(mac, REG_RX_BROADCAST(port),
- &mac->stats.RxBroadcastFramesOK);
- rmon_update(mac, REG_CRC(port), &mac->stats.RxFCSErrors);
- rmon_update(mac, REG_RX_ALIGNMENT(port), &mac->stats.RxAlignErrors);
- rmon_update(mac, REG_RX_OVERSIZE(port),
- &mac->stats.RxFrameTooLongErrors);
- rmon_update(mac, REG_RX_PAUSE(port), &mac->stats.RxPauseFrames);
- rmon_update(mac, REG_RX_JABBERS(port), &mac->stats.RxJabberErrors);
- rmon_update(mac, REG_RX_FRAGMENTS(port), &mac->stats.RxRuntErrors);
- rmon_update(mac, REG_RX_UNDERSIZE(port), &mac->stats.RxRuntErrors);
- rmon_update(mac, REG_RX_SYMBOL_CARRIER(port),
- &mac->stats.RxSymbolErrors);
- rmon_update(mac, REG_RX_SIZE_1519_TO_MAX(port),
- &mac->stats.RxJumboFramesOK);
-
- /* Tx stats (skip collision stats as we are full-duplex only) */
- rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
- rmon_update(mac, REG_TX_UNICAST(port), &mac->stats.TxUnicastFramesOK);
- rmon_update(mac, REG_TX_MULTICAST(port),
- &mac->stats.TxMulticastFramesOK);
- rmon_update(mac, REG_TX_BROADCAST(port),
- &mac->stats.TxBroadcastFramesOK);
- rmon_update(mac, REG_TX_PAUSE(port), &mac->stats.TxPauseFrames);
- rmon_update(mac, REG_TX_UNDERRUN(port), &mac->stats.TxUnderrun);
- rmon_update(mac, REG_TX_SIZE_1519_TO_MAX(port),
- &mac->stats.TxJumboFramesOK);
}
/*
@@ -686,7 +690,8 @@ static struct cmac *vsc7326_mac_create(adapter_t *adapter, int index)
int i;
mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
- if (!mac) return NULL;
+ if (!mac)
+ return NULL;
mac->ops = &vsc7326_ops;
mac->instance = (cmac_instance *)(mac + 1);
diff --git a/drivers/net/chelsio/vsc7326_reg.h b/drivers/net/chelsio/vsc7326_reg.h
index 491bcf75c4f..479edbcabe6 100644
--- a/drivers/net/chelsio/vsc7326_reg.h
+++ b/drivers/net/chelsio/vsc7326_reg.h
@@ -192,73 +192,84 @@
#define REG_HDX(pn) CRA(0x1,pn,0x19) /* Half-duplex config */
/* Statistics */
+/* CRA(0x4,pn,reg) */
+/* reg below */
/* pn = port number, 0-a, a = 10GbE */
-#define REG_RX_IN_BYTES(pn) CRA(0x4,pn,0x00) /* # Rx in octets */
-#define REG_RX_SYMBOL_CARRIER(pn) CRA(0x4,pn,0x01) /* Frames w/ symbol errors */
-#define REG_RX_PAUSE(pn) CRA(0x4,pn,0x02) /* # pause frames received */
-#define REG_RX_UNSUP_OPCODE(pn) CRA(0x4,pn,0x03) /* # control frames with unsupported opcode */
-#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,0x04) /* # octets in good frames */
-#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,0x05) /* # octets in bad frames */
-#define REG_RX_UNICAST(pn) CRA(0x4,pn,0x06) /* # good unicast frames */
-#define REG_RX_MULTICAST(pn) CRA(0x4,pn,0x07) /* # good multicast frames */
-#define REG_RX_BROADCAST(pn) CRA(0x4,pn,0x08) /* # good broadcast frames */
-#define REG_CRC(pn) CRA(0x4,pn,0x09) /* # frames w/ bad CRC only */
-#define REG_RX_ALIGNMENT(pn) CRA(0x4,pn,0x0a) /* # frames w/ alignment err */
-#define REG_RX_UNDERSIZE(pn) CRA(0x4,pn,0x0b) /* # frames undersize */
-#define REG_RX_FRAGMENTS(pn) CRA(0x4,pn,0x0c) /* # frames undersize w/ crc err */
-#define REG_RX_IN_RANGE_LENGTH_ERROR(pn) CRA(0x4,pn,0x0d) /* # frames with length error */
-#define REG_RX_OUT_OF_RANGE_ERROR(pn) CRA(0x4,pn,0x0e) /* # frames with illegal length field */
-#define REG_RX_OVERSIZE(pn) CRA(0x4,pn,0x0f) /* # frames oversize */
-#define REG_RX_JABBERS(pn) CRA(0x4,pn,0x10) /* # frames oversize w/ crc err */
-#define REG_RX_SIZE_64(pn) CRA(0x4,pn,0x11) /* # frames 64 octets long */
-#define REG_RX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x12) /* # frames 65-127 octets */
-#define REG_RX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x13) /* # frames 128-255 */
-#define REG_RX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x14) /* # frames 256-511 */
-#define REG_RX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x15) /* # frames 512-1023 */
-#define REG_RX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x16) /* # frames 1024-1518 */
-#define REG_RX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x17) /* # frames 1519-max */
-#define REG_TX_OUT_BYTES(pn) CRA(0x4,pn,0x18) /* # octets tx */
-#define REG_TX_PAUSE(pn) CRA(0x4,pn,0x19) /* # pause frames sent */
-#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,0x1a) /* # octets tx OK */
-#define REG_TX_UNICAST(pn) CRA(0x4,pn,0x1b) /* # frames unicast */
-#define REG_TX_MULTICAST(pn) CRA(0x4,pn,0x1c) /* # frames multicast */
-#define REG_TX_BROADCAST(pn) CRA(0x4,pn,0x1d) /* # frames broadcast */
-#define REG_TX_MULTIPLE_COLL(pn) CRA(0x4,pn,0x1e) /* # frames tx after multiple collisions */
-#define REG_TX_LATE_COLL(pn) CRA(0x4,pn,0x1f) /* # late collisions detected */
-#define REG_TX_XCOLL(pn) CRA(0x4,pn,0x20) /* # frames lost, excessive collisions */
-#define REG_TX_DEFER(pn) CRA(0x4,pn,0x21) /* # frames deferred on first tx attempt */
-#define REG_TX_XDEFER(pn) CRA(0x4,pn,0x22) /* # frames excessively deferred */
-#define REG_TX_CSENSE(pn) CRA(0x4,pn,0x23) /* carrier sense errors at frame end */
-#define REG_TX_SIZE_64(pn) CRA(0x4,pn,0x24) /* # frames 64 octets long */
-#define REG_TX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x25) /* # frames 65-127 octets */
-#define REG_TX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x26) /* # frames 128-255 */
-#define REG_TX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x27) /* # frames 256-511 */
-#define REG_TX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x28) /* # frames 512-1023 */
-#define REG_TX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x29) /* # frames 1024-1518 */
-#define REG_TX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x2a) /* # frames 1519-max */
-#define REG_TX_SINGLE_COLL(pn) CRA(0x4,pn,0x2b) /* # frames tx after single collision */
-#define REG_TX_BACKOFF2(pn) CRA(0x4,pn,0x2c) /* # frames tx ok after 2 backoffs/collisions */
-#define REG_TX_BACKOFF3(pn) CRA(0x4,pn,0x2d) /* after 3 backoffs/collisions */
-#define REG_TX_BACKOFF4(pn) CRA(0x4,pn,0x2e) /* after 4 */
-#define REG_TX_BACKOFF5(pn) CRA(0x4,pn,0x2f) /* after 5 */
-#define REG_TX_BACKOFF6(pn) CRA(0x4,pn,0x30) /* after 6 */
-#define REG_TX_BACKOFF7(pn) CRA(0x4,pn,0x31) /* after 7 */
-#define REG_TX_BACKOFF8(pn) CRA(0x4,pn,0x32) /* after 8 */
-#define REG_TX_BACKOFF9(pn) CRA(0x4,pn,0x33) /* after 9 */
-#define REG_TX_BACKOFF10(pn) CRA(0x4,pn,0x34) /* after 10 */
-#define REG_TX_BACKOFF11(pn) CRA(0x4,pn,0x35) /* after 11 */
-#define REG_TX_BACKOFF12(pn) CRA(0x4,pn,0x36) /* after 12 */
-#define REG_TX_BACKOFF13(pn) CRA(0x4,pn,0x37) /* after 13 */
-#define REG_TX_BACKOFF14(pn) CRA(0x4,pn,0x38) /* after 14 */
-#define REG_TX_BACKOFF15(pn) CRA(0x4,pn,0x39) /* after 15 */
-#define REG_TX_UNDERRUN(pn) CRA(0x4,pn,0x3a) /* # frames dropped from underrun */
-#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */
-#define REG_RX_IPG_SHRINK(pn) CRA(0x4,pn,0x3c) /* # of IPG shrinks detected */
+enum {
+ RxInBytes = 0x00, // # Rx in octets
+ RxSymbolCarrier = 0x01, // Frames w/ symbol errors
+ RxPause = 0x02, // # pause frames received
+ RxUnsupOpcode = 0x03, // # control frames with unsupported opcode
+ RxOkBytes = 0x04, // # octets in good frames
+ RxBadBytes = 0x05, // # octets in bad frames
+ RxUnicast = 0x06, // # good unicast frames
+ RxMulticast = 0x07, // # good multicast frames
+ RxBroadcast = 0x08, // # good broadcast frames
+ Crc = 0x09, // # frames w/ bad CRC only
+ RxAlignment = 0x0a, // # frames w/ alignment err
+ RxUndersize = 0x0b, // # frames undersize
+ RxFragments = 0x0c, // # frames undersize w/ crc err
+ RxInRangeLengthError = 0x0d, // # frames with length error
+ RxOutOfRangeError = 0x0e, // # frames with illegal length field
+ RxOversize = 0x0f, // # frames oversize
+ RxJabbers = 0x10, // # frames oversize w/ crc err
+ RxSize64 = 0x11, // # frames 64 octets long
+ RxSize65To127 = 0x12, // # frames 65-127 octets
+ RxSize128To255 = 0x13, // # frames 128-255
+ RxSize256To511 = 0x14, // # frames 256-511
+ RxSize512To1023 = 0x15, // # frames 512-1023
+ RxSize1024To1518 = 0x16, // # frames 1024-1518
+ RxSize1519ToMax = 0x17, // # frames 1519-max
-#define REG_STAT_STICKY1G(pn) CRA(0x4,pn,0x3e) /* tri-speed sticky bits */
-#define REG_STAT_STICKY10G CRA(0x4,0xa,0x3e) /* 10GbE sticky bits */
-#define REG_STAT_INIT(pn) CRA(0x4,pn,0x3f) /* Clear all statistics */
+ TxOutBytes = 0x18, // # octets tx
+ TxPause = 0x19, // # pause frames sent
+ TxOkBytes = 0x1a, // # octets tx OK
+ TxUnicast = 0x1b, // # frames unicast
+ TxMulticast = 0x1c, // # frames multicast
+ TxBroadcast = 0x1d, // # frames broadcast
+ TxMultipleColl = 0x1e, // # frames tx after multiple collisions
+ TxLateColl = 0x1f, // # late collisions detected
+ TxXcoll = 0x20, // # frames lost, excessive collisions
+ TxDefer = 0x21, // # frames deferred on first tx attempt
+ TxXdefer = 0x22, // # frames excessively deferred
+ TxCsense = 0x23, // carrier sense errors at frame end
+ TxSize64 = 0x24, // # frames 64 octets long
+ TxSize65To127 = 0x25, // # frames 65-127 octets
+ TxSize128To255 = 0x26, // # frames 128-255
+ TxSize256To511 = 0x27, // # frames 256-511
+ TxSize512To1023 = 0x28, // # frames 512-1023
+ TxSize1024To1518 = 0x29, // # frames 1024-1518
+ TxSize1519ToMax = 0x2a, // # frames 1519-max
+ TxSingleColl = 0x2b, // # frames tx after single collision
+ TxBackoff2 = 0x2c, // # frames tx ok after 2 backoffs/collisions
+ TxBackoff3 = 0x2d, // after 3 backoffs/collisions
+ TxBackoff4 = 0x2e, // after 4
+ TxBackoff5 = 0x2f, // after 5
+ TxBackoff6 = 0x30, // after 6
+ TxBackoff7 = 0x31, // after 7
+ TxBackoff8 = 0x32, // after 8
+ TxBackoff9 = 0x33, // after 9
+ TxBackoff10 = 0x34, // after 10
+ TxBackoff11 = 0x35, // after 11
+ TxBackoff12 = 0x36, // after 12
+ TxBackoff13 = 0x37, // after 13
+ TxBackoff14 = 0x38, // after 14
+ TxBackoff15 = 0x39, // after 15
+ TxUnderrun = 0x3a, // # frames dropped from underrun
+ // Hole. See REG_RX_XGMII_PROT_ERR below.
+ RxIpgShrink = 0x3c, // # of IPG shrinks detected
+ // Duplicate. See REG_STAT_STICKY10G below.
+ StatSticky1G = 0x3e, // tri-speed sticky bits
+ StatInit = 0x3f // Clear all statistics
+};
+
+#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */
+#define REG_STAT_STICKY10G CRA(0x4,0xa,StatSticky1G) /* 10GbE sticky bits */
+
+#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,RxOkBytes)
+#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,RxBadBytes)
+#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,TxOkBytes)
/* MII-Management Block registers */
/* These are for MII-M interface 0, which is the bidirectional LVTTL one. If
diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c
index c493e783d45..251d4859c91 100644
--- a/drivers/net/chelsio/vsc8244.c
+++ b/drivers/net/chelsio/vsc8244.c
@@ -54,7 +54,7 @@ enum {
};
#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
- VSC_INTR_NEG_DONE)
+ VSC_INTR_NEG_DONE)
#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
VSC_INTR_ENABLE)
@@ -94,19 +94,18 @@ static int vsc8244_intr_enable(struct cphy *cphy)
{
simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK);
- /* Enable interrupts through Elmer */
+ /* Enable interrupts through Elmer */
if (t1_is_asic(cphy->adapter)) {
u32 elmer;
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
- return 0;
+ return 0;
}
static int vsc8244_intr_disable(struct cphy *cphy)
@@ -118,19 +117,18 @@ static int vsc8244_intr_disable(struct cphy *cphy)
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer &= ~ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
- return 0;
+ return 0;
}
static int vsc8244_intr_clear(struct cphy *cphy)
{
u32 val;
- u32 elmer;
+ u32 elmer;
/* Clear PHY interrupts by reading the register. */
simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val);
@@ -138,13 +136,12 @@ static int vsc8244_intr_clear(struct cphy *cphy)
if (t1_is_asic(cphy->adapter)) {
t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
}
- return 0;
+ return 0;
}
/*
@@ -179,13 +176,13 @@ static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex)
int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits)
{
- int ret;
- unsigned int val;
+ int ret;
+ unsigned int val;
- ret = mdio_read(phy, mmd, reg, &val);
- if (!ret)
- ret = mdio_write(phy, mmd, reg, val | bits);
- return ret;
+ ret = mdio_read(phy, mmd, reg, &val);
+ if (!ret)
+ ret = mdio_write(phy, mmd, reg, val | bits);
+ return ret;
}
static int vsc8244_autoneg_enable(struct cphy *cphy)
@@ -235,7 +232,7 @@ static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map)
}
static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok,
- int *speed, int *duplex, int *fc)
+ int *speed, int *duplex, int *fc)
{
unsigned int bmcr, status, lpa, adv;
int err, sp = -1, dplx = -1, pause = 0;
@@ -343,11 +340,13 @@ static struct cphy_ops vsc8244_ops = {
.get_link_status = vsc8244_get_link_status
};
-static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, struct mdio_ops *mdio_ops)
+static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr,
+ struct mdio_ops *mdio_ops)
{
struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
- if (!cphy) return NULL;
+ if (!cphy)
+ return NULL;
cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops);
diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/cxgb3/Makefile
new file mode 100644
index 00000000000..34346798532
--- /dev/null
+++ b/drivers/net/cxgb3/Makefile
@@ -0,0 +1,8 @@
+#
+# Chelsio T3 driver
+#
+
+obj-$(CONFIG_CHELSIO_T3) += cxgb3.o
+
+cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \
+ xgmac.o sge.o l2t.o cxgb3_offload.o
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
new file mode 100644
index 00000000000..5c97a64451c
--- /dev/null
+++ b/drivers/net/cxgb3/adapter.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* This file should not be included directly. Include common.h instead. */
+
+#ifndef __T3_ADAPTER_H__
+#define __T3_ADAPTER_H__
+
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/cache.h>
+#include <linux/mutex.h>
+#include "t3cdev.h"
+#include <asm/semaphore.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+typedef irqreturn_t(*intr_handler_t) (int, void *);
+
+struct vlan_group;
+
+struct port_info {
+ struct vlan_group *vlan_grp;
+ const struct port_type_info *port_type;
+ u8 port_id;
+ u8 rx_csum_offload;
+ u8 nqsets;
+ u8 first_qset;
+ struct cphy phy;
+ struct cmac mac;
+ struct link_config link_config;
+ struct net_device_stats netstats;
+ int activity;
+};
+
+enum { /* adapter flags */
+ FULL_INIT_DONE = (1 << 0),
+ USING_MSI = (1 << 1),
+ USING_MSIX = (1 << 2),
+ QUEUES_BOUND = (1 << 3),
+};
+
+struct rx_desc;
+struct rx_sw_desc;
+
+struct sge_fl { /* SGE per free-buffer list state */
+ unsigned int buf_size; /* size of each Rx buffer */
+ unsigned int credits; /* # of available Rx buffers */
+ unsigned int size; /* capacity of free list */
+ unsigned int cidx; /* consumer index */
+ unsigned int pidx; /* producer index */
+ unsigned int gen; /* free list generation */
+ struct rx_desc *desc; /* address of HW Rx descriptor ring */
+ struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */
+ dma_addr_t phys_addr; /* physical address of HW ring start */
+ unsigned int cntxt_id; /* SGE context id for the free list */
+ unsigned long empty; /* # of times queue ran out of buffers */
+};
+
+/*
+ * Bundle size for grouping offload RX packets for delivery to the stack.
+ * Don't make this too big as we do prefetch on each packet in a bundle.
+ */
+# define RX_BUNDLE_SIZE 8
+
+struct rsp_desc;
+
+struct sge_rspq { /* state for an SGE response queue */
+ unsigned int credits; /* # of pending response credits */
+ unsigned int size; /* capacity of response queue */
+ unsigned int cidx; /* consumer index */
+ unsigned int gen; /* current generation bit */
+ unsigned int polling; /* is the queue serviced through NAPI? */
+ unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */
+ unsigned int next_holdoff; /* holdoff time for next interrupt */
+ struct rsp_desc *desc; /* address of HW response ring */
+ dma_addr_t phys_addr; /* physical address of the ring */
+ unsigned int cntxt_id; /* SGE context id for the response q */
+ spinlock_t lock; /* guards response processing */
+ struct sk_buff *rx_head; /* offload packet receive queue head */
+ struct sk_buff *rx_tail; /* offload packet receive queue tail */
+
+ unsigned long offload_pkts;
+ unsigned long offload_bundles;
+ unsigned long eth_pkts; /* # of ethernet packets */
+ unsigned long pure_rsps; /* # of pure (non-data) responses */
+ unsigned long imm_data; /* responses with immediate data */
+ unsigned long rx_drops; /* # of packets dropped due to no mem */
+ unsigned long async_notif; /* # of asynchronous notification events */
+ unsigned long empty; /* # of times queue ran out of credits */
+ unsigned long nomem; /* # of responses deferred due to no mem */
+ unsigned long unhandled_irqs; /* # of spurious intrs */
+};
+
+struct tx_desc;
+struct tx_sw_desc;
+
+struct sge_txq { /* state for an SGE Tx queue */
+ unsigned long flags; /* HW DMA fetch status */
+ unsigned int in_use; /* # of in-use Tx descriptors */
+ unsigned int size; /* # of descriptors */
+ unsigned int processed; /* total # of descs HW has processed */
+ unsigned int cleaned; /* total # of descs SW has reclaimed */
+ unsigned int stop_thres; /* SW TX queue suspend threshold */
+ unsigned int cidx; /* consumer index */
+ unsigned int pidx; /* producer index */
+ unsigned int gen; /* current value of generation bit */
+ unsigned int unacked; /* Tx descriptors used since last COMPL */
+ struct tx_desc *desc; /* address of HW Tx descriptor ring */
+ struct tx_sw_desc *sdesc; /* address of SW Tx descriptor ring */
+ spinlock_t lock; /* guards enqueueing of new packets */
+ unsigned int token; /* WR token */
+ dma_addr_t phys_addr; /* physical address of the ring */
+ struct sk_buff_head sendq; /* List of backpressured offload packets */
+ struct tasklet_struct qresume_tsk; /* restarts the queue */
+ unsigned int cntxt_id; /* SGE context id for the Tx q */
+ unsigned long stops; /* # of times q has been stopped */
+ unsigned long restarts; /* # of queue restarts */
+};
+
+enum { /* per port SGE statistics */
+ SGE_PSTAT_TSO, /* # of TSO requests */
+ SGE_PSTAT_RX_CSUM_GOOD, /* # of successful RX csum offloads */
+ SGE_PSTAT_TX_CSUM, /* # of TX checksum offloads */
+ SGE_PSTAT_VLANEX, /* # of VLAN tag extractions */
+ SGE_PSTAT_VLANINS, /* # of VLAN tag insertions */
+
+ SGE_PSTAT_MAX /* must be last */
+};
+
+struct sge_qset { /* an SGE queue set */
+ struct sge_rspq rspq;
+ struct sge_fl fl[SGE_RXQ_PER_SET];
+ struct sge_txq txq[SGE_TXQ_PER_SET];
+ struct net_device *netdev; /* associated net device */
+ unsigned long txq_stopped; /* which Tx queues are stopped */
+ struct timer_list tx_reclaim_timer; /* reclaims TX buffers */
+ unsigned long port_stats[SGE_PSTAT_MAX];
+} ____cacheline_aligned;
+
+struct sge {
+ struct sge_qset qs[SGE_QSETS];
+ spinlock_t reg_lock; /* guards non-atomic SGE registers (eg context) */
+};
+
+struct adapter {
+ struct t3cdev tdev;
+ struct list_head adapter_list;
+ void __iomem *regs;
+ struct pci_dev *pdev;
+ unsigned long registered_device_map;
+ unsigned long open_device_map;
+ unsigned long flags;
+
+ const char *name;
+ int msg_enable;
+ unsigned int mmio_len;
+
+ struct adapter_params params;
+ unsigned int slow_intr_mask;
+ unsigned long irq_stats[IRQ_NUM_STATS];
+
+ struct {
+ unsigned short vec;
+ char desc[22];
+ } msix_info[SGE_QSETS + 1];
+
+ /* T3 modules */
+ struct sge sge;
+ struct mc7 pmrx;
+ struct mc7 pmtx;
+ struct mc7 cm;
+ struct mc5 mc5;
+
+ struct net_device *port[MAX_NPORTS];
+ unsigned int check_task_cnt;
+ struct delayed_work adap_check_task;
+ struct work_struct ext_intr_handler_task;
+
+ /*
+ * Dummy netdevices are needed when using multiple receive queues with
+ * NAPI as each netdevice can service only one queue.
+ */
+ struct net_device *dummy_netdev[SGE_QSETS - 1];
+
+ struct dentry *debugfs_root;
+
+ struct mutex mdio_lock;
+ spinlock_t stats_lock;
+ spinlock_t work_lock;
+};
+
+static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr)
+{
+ u32 val = readl(adapter->regs + reg_addr);
+
+ CH_DBG(adapter, MMIO, "read register 0x%x value 0x%x\n", reg_addr, val);
+ return val;
+}
+
+static inline void t3_write_reg(struct adapter *adapter, u32 reg_addr, u32 val)
+{
+ CH_DBG(adapter, MMIO, "setting register 0x%x to 0x%x\n", reg_addr, val);
+ writel(val, adapter->regs + reg_addr);
+}
+
+static inline struct port_info *adap2pinfo(struct adapter *adap, int idx)
+{
+ return netdev_priv(adap->port[idx]);
+}
+
+/*
+ * We use the spare atalk_ptr to map a net device to its SGE queue set.
+ * This is a macro so it can be used as l-value.
+ */
+#define dev2qset(netdev) ((netdev)->atalk_ptr)
+
+#define OFFLOAD_DEVMAP_BIT 15
+
+#define tdev2adap(d) container_of(d, struct adapter, tdev)
+
+static inline int offload_running(struct adapter *adapter)
+{
+ return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+}
+
+int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb);
+
+void t3_os_ext_intr_handler(struct adapter *adapter);
+void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status,
+ int speed, int duplex, int fc);
+
+void t3_sge_start(struct adapter *adap);
+void t3_sge_stop(struct adapter *adap);
+void t3_free_sge_resources(struct adapter *adap);
+void t3_sge_err_intr_handler(struct adapter *adapter);
+intr_handler_t t3_intr_handler(struct adapter *adap, int polling);
+int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev);
+int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb);
+void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p);
+int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
+ int irq_vec_idx, const struct qset_params *p,
+ int ntxq, struct net_device *netdev);
+int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
+ unsigned char *data);
+irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
+
+#endif /* __T3_ADAPTER_H__ */
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
new file mode 100644
index 00000000000..73a41e6a5bf
--- /dev/null
+++ b/drivers/net/cxgb3/ael1002.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+enum {
+ AEL100X_TX_DISABLE = 9,
+ AEL100X_TX_CONFIG1 = 0xc002,
+ AEL1002_PWR_DOWN_HI = 0xc011,
+ AEL1002_PWR_DOWN_LO = 0xc012,
+ AEL1002_XFI_EQL = 0xc015,
+ AEL1002_LB_EN = 0xc017,
+
+ LASI_CTRL = 0x9002,
+ LASI_STAT = 0x9005
+};
+
+static void ael100x_txon(struct cphy *phy)
+{
+ int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
+
+ msleep(100);
+ t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
+ msleep(30);
+}
+
+static int ael1002_power_down(struct cphy *phy, int enable)
+{
+ int err;
+
+ err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
+ if (!err)
+ err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
+ BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
+ return err;
+}
+
+static int ael1002_reset(struct cphy *phy, int wait)
+{
+ int err;
+
+ if ((err = ael1002_power_down(phy, 0)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
+ (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
+ 0, 1 << 5)))
+ return err;
+ return 0;
+}
+
+static int ael1002_intr_noop(struct cphy *phy)
+{
+ return 0;
+}
+
+static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
+ int *speed, int *duplex, int *fc)
+{
+ if (link_ok) {
+ unsigned int status;
+ int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
+
+ /*
+ * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
+ * once more to get the current link state.
+ */
+ if (!err && !(status & BMSR_LSTATUS))
+ err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
+ &status);
+ if (err)
+ return err;
+ *link_ok = !!(status & BMSR_LSTATUS);
+ }
+ if (speed)
+ *speed = SPEED_10000;
+ if (duplex)
+ *duplex = DUPLEX_FULL;
+ return 0;
+}
+
+static struct cphy_ops ael1002_ops = {
+ .reset = ael1002_reset,
+ .intr_enable = ael1002_intr_noop,
+ .intr_disable = ael1002_intr_noop,
+ .intr_clear = ael1002_intr_noop,
+ .intr_handler = ael1002_intr_noop,
+ .get_link_status = ael100x_get_link_status,
+ .power_down = ael1002_power_down,
+};
+
+void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
+ ael100x_txon(phy);
+}
+
+static int ael1006_reset(struct cphy *phy, int wait)
+{
+ return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
+}
+
+static int ael1006_intr_enable(struct cphy *phy)
+{
+ return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
+}
+
+static int ael1006_intr_disable(struct cphy *phy)
+{
+ return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
+}
+
+static int ael1006_intr_clear(struct cphy *phy)
+{
+ u32 val;
+
+ return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
+}
+
+static int ael1006_intr_handler(struct cphy *phy)
+{
+ unsigned int status;
+ int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
+
+ if (err)
+ return err;
+ return (status & 1) ? cphy_cause_link_change : 0;
+}
+
+static int ael1006_power_down(struct cphy *phy, int enable)
+{
+ return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
+ BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
+}
+
+static struct cphy_ops ael1006_ops = {
+ .reset = ael1006_reset,
+ .intr_enable = ael1006_intr_enable,
+ .intr_disable = ael1006_intr_disable,
+ .intr_clear = ael1006_intr_clear,
+ .intr_handler = ael1006_intr_handler,
+ .get_link_status = ael100x_get_link_status,
+ .power_down = ael1006_power_down,
+};
+
+void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
+ ael100x_txon(phy);
+}
+
+static struct cphy_ops qt2045_ops = {
+ .reset = ael1006_reset,
+ .intr_enable = ael1006_intr_enable,
+ .intr_disable = ael1006_intr_disable,
+ .intr_clear = ael1006_intr_clear,
+ .intr_handler = ael1006_intr_handler,
+ .get_link_status = ael100x_get_link_status,
+ .power_down = ael1006_power_down,
+};
+
+void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ unsigned int stat;
+
+ cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
+
+ /*
+ * Some cards where the PHY is supposed to be at address 0 actually
+ * have it at 1.
+ */
+ if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
+ stat == 0xffff)
+ phy->addr = 1;
+}
+
+static int xaui_direct_reset(struct cphy *phy, int wait)
+{
+ return 0;
+}
+
+static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
+ int *speed, int *duplex, int *fc)
+{
+ if (link_ok) {
+ unsigned int status;
+
+ status = t3_read_reg(phy->adapter,
+ XGM_REG(A_XGM_SERDES_STAT0, phy->addr));
+ *link_ok = !(status & F_LOWSIG0);
+ }
+ if (speed)
+ *speed = SPEED_10000;
+ if (duplex)
+ *duplex = DUPLEX_FULL;
+ return 0;
+}
+
+static int xaui_direct_power_down(struct cphy *phy, int enable)
+{
+ return 0;
+}
+
+static struct cphy_ops xaui_direct_ops = {
+ .reset = xaui_direct_reset,
+ .intr_enable = ael1002_intr_noop,
+ .intr_disable = ael1002_intr_noop,
+ .intr_clear = ael1002_intr_noop,
+ .intr_handler = ael1002_intr_noop,
+ .get_link_status = xaui_direct_get_link_status,
+ .power_down = xaui_direct_power_down,
+};
+
+void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops);
+}
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
new file mode 100644
index 00000000000..e23deeb7d06
--- /dev/null
+++ b/drivers/net/cxgb3/common.h
@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CHELSIO_COMMON_H
+#define __CHELSIO_COMMON_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include "version.h"
+
+#define CH_ERR(adap, fmt, ...) dev_err(&adap->pdev->dev, fmt, ## __VA_ARGS__)
+#define CH_WARN(adap, fmt, ...) dev_warn(&adap->pdev->dev, fmt, ## __VA_ARGS__)
+#define CH_ALERT(adap, fmt, ...) \
+ dev_printk(KERN_ALERT, &adap->pdev->dev, fmt, ## __VA_ARGS__)
+
+/*
+ * More powerful macro that selectively prints messages based on msg_enable.
+ * For info and debugging messages.
+ */
+#define CH_MSG(adapter, level, category, fmt, ...) do { \
+ if ((adapter)->msg_enable & NETIF_MSG_##category) \
+ dev_printk(KERN_##level, &adapter->pdev->dev, fmt, \
+ ## __VA_ARGS__); \
+} while (0)
+
+#ifdef DEBUG
+# define CH_DBG(adapter, category, fmt, ...) \
+ CH_MSG(adapter, DEBUG, category, fmt, ## __VA_ARGS__)
+#else
+# define CH_DBG(adapter, category, fmt, ...)
+#endif
+
+/* Additional NETIF_MSG_* categories */
+#define NETIF_MSG_MMIO 0x8000000
+
+struct t3_rx_mode {
+ struct net_device *dev;
+ struct dev_mc_list *mclist;
+ unsigned int idx;
+};
+
+static inline void init_rx_mode(struct t3_rx_mode *p, struct net_device *dev,
+ struct dev_mc_list *mclist)
+{
+ p->dev = dev;
+ p->mclist = mclist;
+ p->idx = 0;
+}
+
+static inline u8 *t3_get_next_mcaddr(struct t3_rx_mode *rm)
+{
+ u8 *addr = NULL;
+
+ if (rm->mclist && rm->idx < rm->dev->mc_count) {
+ addr = rm->mclist->dmi_addr;
+ rm->mclist = rm->mclist->next;
+ rm->idx++;
+ }
+ return addr;
+}
+
+enum {
+ MAX_NPORTS = 2, /* max # of ports */
+ MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */
+ EEPROMSIZE = 8192, /* Serial EEPROM size */
+ RSS_TABLE_SIZE = 64, /* size of RSS lookup and mapping tables */
+ TCB_SIZE = 128, /* TCB size */
+ NMTUS = 16, /* size of MTU table */
+ NCCTRL_WIN = 32, /* # of congestion control windows */
+};
+
+#define MAX_RX_COALESCING_LEN 16224U
+
+enum {
+ PAUSE_RX = 1 << 0,
+ PAUSE_TX = 1 << 1,
+ PAUSE_AUTONEG = 1 << 2
+};
+
+enum {
+ SUPPORTED_OFFLOAD = 1 << 24,
+ SUPPORTED_IRQ = 1 << 25
+};
+
+enum { /* adapter interrupt-maintained statistics */
+ STAT_ULP_CH0_PBL_OOB,
+ STAT_ULP_CH1_PBL_OOB,
+ STAT_PCI_CORR_ECC,
+
+ IRQ_NUM_STATS /* keep last */
+};
+
+enum {
+ SGE_QSETS = 8, /* # of SGE Tx/Rx/RspQ sets */
+ SGE_RXQ_PER_SET = 2, /* # of Rx queues per set */
+ SGE_TXQ_PER_SET = 3 /* # of Tx queues per set */
+};
+
+enum sge_context_type { /* SGE egress context types */
+ SGE_CNTXT_RDMA = 0,
+ SGE_CNTXT_ETH = 2,
+ SGE_CNTXT_OFLD = 4,
+ SGE_CNTXT_CTRL = 5
+};
+
+enum {
+ AN_PKT_SIZE = 32, /* async notification packet size */
+ IMMED_PKT_SIZE = 48 /* packet size for immediate data */
+};
+
+struct sg_ent { /* SGE scatter/gather entry */
+ u32 len[2];
+ u64 addr[2];
+};
+
+#ifndef SGE_NUM_GENBITS
+/* Must be 1 or 2 */
+# define SGE_NUM_GENBITS 2
+#endif
+
+#define TX_DESC_FLITS 16U
+#define WR_FLITS (TX_DESC_FLITS + 1 - SGE_NUM_GENBITS)
+
+struct cphy;
+struct adapter;
+
+struct mdio_ops {
+ int (*read)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *val);
+ int (*write)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val);
+};
+
+struct adapter_info {
+ unsigned char nports; /* # of ports */
+ unsigned char phy_base_addr; /* MDIO PHY base address */
+ unsigned char mdien;
+ unsigned char mdiinv;
+ unsigned int gpio_out; /* GPIO output settings */
+ unsigned int gpio_intr; /* GPIO IRQ enable mask */
+ unsigned long caps; /* adapter capabilities */
+ const struct mdio_ops *mdio_ops; /* MDIO operations */
+ const char *desc; /* product description */
+};
+
+struct port_type_info {
+ void (*phy_prep)(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *ops);
+ unsigned int caps;
+ const char *desc;
+};
+
+struct mc5_stats {
+ unsigned long parity_err;
+ unsigned long active_rgn_full;
+ unsigned long nfa_srch_err;
+ unsigned long unknown_cmd;
+ unsigned long reqq_parity_err;
+ unsigned long dispq_parity_err;
+ unsigned long del_act_empty;
+};
+
+struct mc7_stats {
+ unsigned long corr_err;
+ unsigned long uncorr_err;
+ unsigned long parity_err;
+ unsigned long addr_err;
+};
+
+struct mac_stats {
+ u64 tx_octets; /* total # of octets in good frames */
+ u64 tx_octets_bad; /* total # of octets in error frames */
+ u64 tx_frames; /* all good frames */
+ u64 tx_mcast_frames; /* good multicast frames */
+ u64 tx_bcast_frames; /* good broadcast frames */
+ u64 tx_pause; /* # of transmitted pause frames */
+ u64 tx_deferred; /* frames with deferred transmissions */
+ u64 tx_late_collisions; /* # of late collisions */
+ u64 tx_total_collisions; /* # of total collisions */
+ u64 tx_excess_collisions; /* frame errors from excessive collissions */
+ u64 tx_underrun; /* # of Tx FIFO underruns */
+ u64 tx_len_errs; /* # of Tx length errors */
+ u64 tx_mac_internal_errs; /* # of internal MAC errors on Tx */
+ u64 tx_excess_deferral; /* # of frames with excessive deferral */
+ u64 tx_fcs_errs; /* # of frames with bad FCS */
+
+ u64 tx_frames_64; /* # of Tx frames in a particular range */
+ u64 tx_frames_65_127;
+ u64 tx_frames_128_255;
+ u64 tx_frames_256_511;
+ u64 tx_frames_512_1023;
+ u64 tx_frames_1024_1518;
+ u64 tx_frames_1519_max;
+
+ u64 rx_octets; /* total # of octets in good frames */
+ u64 rx_octets_bad; /* total # of octets in error frames */
+ u64 rx_frames; /* all good frames */
+ u64 rx_mcast_frames; /* good multicast frames */
+ u64 rx_bcast_frames; /* good broadcast frames */
+ u64 rx_pause; /* # of received pause frames */
+ u64 rx_fcs_errs; /* # of received frames with bad FCS */
+ u64 rx_align_errs; /* alignment errors */
+ u64 rx_symbol_errs; /* symbol errors */
+ u64 rx_data_errs; /* data errors */
+ u64 rx_sequence_errs; /* sequence errors */
+ u64 rx_runt; /* # of runt frames */
+ u64 rx_jabber; /* # of jabber frames */
+ u64 rx_short; /* # of short frames */
+ u64 rx_too_long; /* # of oversized frames */
+ u64 rx_mac_internal_errs; /* # of internal MAC errors on Rx */
+
+ u64 rx_frames_64; /* # of Rx frames in a particular range */
+ u64 rx_frames_65_127;
+ u64 rx_frames_128_255;
+ u64 rx_frames_256_511;
+ u64 rx_frames_512_1023;
+ u64 rx_frames_1024_1518;
+ u64 rx_frames_1519_max;
+
+ u64 rx_cong_drops; /* # of Rx drops due to SGE congestion */
+
+ unsigned long tx_fifo_parity_err;
+ unsigned long rx_fifo_parity_err;
+ unsigned long tx_fifo_urun;
+ unsigned long rx_fifo_ovfl;
+ unsigned long serdes_signal_loss;
+ unsigned long xaui_pcs_ctc_err;
+ unsigned long xaui_pcs_align_change;
+};
+
+struct tp_mib_stats {
+ u32 ipInReceive_hi;
+ u32 ipInReceive_lo;
+ u32 ipInHdrErrors_hi;
+ u32 ipInHdrErrors_lo;
+ u32 ipInAddrErrors_hi;
+ u32 ipInAddrErrors_lo;
+ u32 ipInUnknownProtos_hi;
+ u32 ipInUnknownProtos_lo;
+ u32 ipInDiscards_hi;
+ u32 ipInDiscards_lo;
+ u32 ipInDelivers_hi;
+ u32 ipInDelivers_lo;
+ u32 ipOutRequests_hi;
+ u32 ipOutRequests_lo;
+ u32 ipOutDiscards_hi;
+ u32 ipOutDiscards_lo;
+ u32 ipOutNoRoutes_hi;
+ u32 ipOutNoRoutes_lo;
+ u32 ipReasmTimeout;
+ u32 ipReasmReqds;
+ u32 ipReasmOKs;
+ u32 ipReasmFails;
+
+ u32 reserved[8];
+
+ u32 tcpActiveOpens;
+ u32 tcpPassiveOpens;
+ u32 tcpAttemptFails;
+ u32 tcpEstabResets;
+ u32 tcpOutRsts;
+ u32 tcpCurrEstab;
+ u32 tcpInSegs_hi;
+ u32 tcpInSegs_lo;
+ u32 tcpOutSegs_hi;
+ u32 tcpOutSegs_lo;
+ u32 tcpRetransSeg_hi;
+ u32 tcpRetransSeg_lo;
+ u32 tcpInErrs_hi;
+ u32 tcpInErrs_lo;
+ u32 tcpRtoMin;
+ u32 tcpRtoMax;
+};
+
+struct tp_params {
+ unsigned int nchan; /* # of channels */
+ unsigned int pmrx_size; /* total PMRX capacity */
+ unsigned int pmtx_size; /* total PMTX capacity */
+ unsigned int cm_size; /* total CM capacity */
+ unsigned int chan_rx_size; /* per channel Rx size */
+ unsigned int chan_tx_size; /* per channel Tx size */
+ unsigned int rx_pg_size; /* Rx page size */
+ unsigned int tx_pg_size; /* Tx page size */
+ unsigned int rx_num_pgs; /* # of Rx pages */
+ unsigned int tx_num_pgs; /* # of Tx pages */
+ unsigned int ntimer_qs; /* # of timer queues */
+};
+
+struct qset_params { /* SGE queue set parameters */
+ unsigned int polling; /* polling/interrupt service for rspq */
+ unsigned int coalesce_usecs; /* irq coalescing timer */
+ unsigned int rspq_size; /* # of entries in response queue */
+ unsigned int fl_size; /* # of entries in regular free list */
+ unsigned int jumbo_size; /* # of entries in jumbo free list */
+ unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */
+ unsigned int cong_thres; /* FL congestion threshold */
+};
+
+struct sge_params {
+ unsigned int max_pkt_size; /* max offload pkt size */
+ struct qset_params qset[SGE_QSETS];
+};
+
+struct mc5_params {
+ unsigned int mode; /* selects MC5 width */
+ unsigned int nservers; /* size of server region */
+ unsigned int nfilters; /* size of filter region */
+ unsigned int nroutes; /* size of routing region */
+};
+
+/* Default MC5 region sizes */
+enum {
+ DEFAULT_NSERVERS = 512,
+ DEFAULT_NFILTERS = 128
+};
+
+/* MC5 modes, these must be non-0 */
+enum {
+ MC5_MODE_144_BIT = 1,
+ MC5_MODE_72_BIT = 2
+};
+
+struct vpd_params {
+ unsigned int cclk;
+ unsigned int mclk;
+ unsigned int uclk;
+ unsigned int mdc;
+ unsigned int mem_timing;
+ u8 eth_base[6];
+ u8 port_type[MAX_NPORTS];
+ unsigned short xauicfg[2];
+};
+
+struct pci_params {
+ unsigned int vpd_cap_addr;
+ unsigned int pcie_cap_addr;
+ unsigned short speed;
+ unsigned char width;
+ unsigned char variant;
+};
+
+enum {
+ PCI_VARIANT_PCI,
+ PCI_VARIANT_PCIX_MODE1_PARITY,
+ PCI_VARIANT_PCIX_MODE1_ECC,
+ PCI_VARIANT_PCIX_266_MODE2,
+ PCI_VARIANT_PCIE
+};
+
+struct adapter_params {
+ struct sge_params sge;
+ struct mc5_params mc5;
+ struct tp_params tp;
+ struct vpd_params vpd;
+ struct pci_params pci;
+
+ const struct adapter_info *info;
+
+ unsigned short mtus[NMTUS];
+ unsigned short a_wnd[NCCTRL_WIN];
+ unsigned short b_wnd[NCCTRL_WIN];
+
+ unsigned int nports; /* # of ethernet ports */
+ unsigned int stats_update_period; /* MAC stats accumulation period */
+ unsigned int linkpoll_period; /* link poll period in 0.1s */
+ unsigned int rev; /* chip revision */
+};
+
+struct trace_params {
+ u32 sip;
+ u32 sip_mask;
+ u32 dip;
+ u32 dip_mask;
+ u16 sport;
+ u16 sport_mask;
+ u16 dport;
+ u16 dport_mask;
+ u32 vlan:12;
+ u32 vlan_mask:12;
+ u32 intf:4;
+ u32 intf_mask:4;
+ u8 proto;
+ u8 proto_mask;
+};
+
+struct link_config {
+ unsigned int supported; /* link capabilities */
+ unsigned int advertising; /* advertised capabilities */
+ unsigned short requested_speed; /* speed user has requested */
+ unsigned short speed; /* actual link speed */
+ unsigned char requested_duplex; /* duplex user has requested */
+ unsigned char duplex; /* actual link duplex */
+ unsigned char requested_fc; /* flow control user has requested */
+ unsigned char fc; /* actual link flow control */
+ unsigned char autoneg; /* autonegotiating? */
+ unsigned int link_ok; /* link up? */
+};
+
+#define SPEED_INVALID 0xffff
+#define DUPLEX_INVALID 0xff
+
+struct mc5 {
+ struct adapter *adapter;
+ unsigned int tcam_size;
+ unsigned char part_type;
+ unsigned char parity_enabled;
+ unsigned char mode;
+ struct mc5_stats stats;
+};
+
+static inline unsigned int t3_mc5_size(const struct mc5 *p)
+{
+ return p->tcam_size;
+}
+
+struct mc7 {
+ struct adapter *adapter; /* backpointer to adapter */
+ unsigned int size; /* memory size in bytes */
+ unsigned int width; /* MC7 interface width */
+ unsigned int offset; /* register address offset for MC7 instance */
+ const char *name; /* name of MC7 instance */
+ struct mc7_stats stats; /* MC7 statistics */
+};
+
+static inline unsigned int t3_mc7_size(const struct mc7 *p)
+{
+ return p->size;
+}
+
+struct cmac {
+ struct adapter *adapter;
+ unsigned int offset;
+ unsigned int nucast; /* # of address filters for unicast MACs */
+ struct mac_stats stats;
+};
+
+enum {
+ MAC_DIRECTION_RX = 1,
+ MAC_DIRECTION_TX = 2,
+ MAC_RXFIFO_SIZE = 32768
+};
+
+/* IEEE 802.3ae specified MDIO devices */
+enum {
+ MDIO_DEV_PMA_PMD = 1,
+ MDIO_DEV_WIS = 2,
+ MDIO_DEV_PCS = 3,
+ MDIO_DEV_XGXS = 4
+};
+
+/* PHY loopback direction */
+enum {
+ PHY_LOOPBACK_TX = 1,
+ PHY_LOOPBACK_RX = 2
+};
+
+/* PHY interrupt types */
+enum {
+ cphy_cause_link_change = 1,
+ cphy_cause_fifo_error = 2
+};
+
+/* PHY operations */
+struct cphy_ops {
+ void (*destroy)(struct cphy *phy);
+ int (*reset)(struct cphy *phy, int wait);
+
+ int (*intr_enable)(struct cphy *phy);
+ int (*intr_disable)(struct cphy *phy);
+ int (*intr_clear)(struct cphy *phy);
+ int (*intr_handler)(struct cphy *phy);
+
+ int (*autoneg_enable)(struct cphy *phy);
+ int (*autoneg_restart)(struct cphy *phy);
+
+ int (*advertise)(struct cphy *phy, unsigned int advertise_map);
+ int (*set_loopback)(struct cphy *phy, int mmd, int dir, int enable);
+ int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex);
+ int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed,
+ int *duplex, int *fc);
+ int (*power_down)(struct cphy *phy, int enable);
+};
+
+/* A PHY instance */
+struct cphy {
+ int addr; /* PHY address */
+ struct adapter *adapter; /* associated adapter */
+ unsigned long fifo_errors; /* FIFO over/under-flows */
+ const struct cphy_ops *ops; /* PHY operations */
+ int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *val);
+ int (*mdio_write)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val);
+};
+
+/* Convenience MDIO read/write wrappers */
+static inline int mdio_read(struct cphy *phy, int mmd, int reg,
+ unsigned int *valp)
+{
+ return phy->mdio_read(phy->adapter, phy->addr, mmd, reg, valp);
+}
+
+static inline int mdio_write(struct cphy *phy, int mmd, int reg,
+ unsigned int val)
+{
+ return phy->mdio_write(phy->adapter, phy->addr, mmd, reg, val);
+}
+
+/* Convenience initializer */
+static inline void cphy_init(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, struct cphy_ops *phy_ops,
+ const struct mdio_ops *mdio_ops)
+{
+ phy->adapter = adapter;
+ phy->addr = phy_addr;
+ phy->ops = phy_ops;
+ if (mdio_ops) {
+ phy->mdio_read = mdio_ops->read;
+ phy->mdio_write = mdio_ops->write;
+ }
+}
+
+/* Accumulate MAC statistics every 180 seconds. For 1G we multiply by 10. */
+#define MAC_STATS_ACCUM_SECS 180
+
+#define XGM_REG(reg_addr, idx) \
+ ((reg_addr) + (idx) * (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR))
+
+struct addr_val_pair {
+ unsigned int reg_addr;
+ unsigned int val;
+};
+
+#include "adapter.h"
+
+#ifndef PCI_VENDOR_ID_CHELSIO
+# define PCI_VENDOR_ID_CHELSIO 0x1425
+#endif
+
+#define for_each_port(adapter, iter) \
+ for (iter = 0; iter < (adapter)->params.nports; ++iter)
+
+#define adapter_info(adap) ((adap)->params.info)
+
+static inline int uses_xaui(const struct adapter *adap)
+{
+ return adapter_info(adap)->caps & SUPPORTED_AUI;
+}
+
+static inline int is_10G(const struct adapter *adap)
+{
+ return adapter_info(adap)->caps & SUPPORTED_10000baseT_Full;
+}
+
+static inline int is_offload(const struct adapter *adap)
+{
+ return adapter_info(adap)->caps & SUPPORTED_OFFLOAD;
+}
+
+static inline unsigned int core_ticks_per_usec(const struct adapter *adap)
+{
+ return adap->params.vpd.cclk / 1000;
+}
+
+static inline unsigned int is_pcie(const struct adapter *adap)
+{
+ return adap->params.pci.variant == PCI_VARIANT_PCIE;
+}
+
+void t3_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask,
+ u32 val);
+void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
+ int n, unsigned int offset);
+int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
+ int polarity, int attempts, int delay, u32 *valp);
+static inline int t3_wait_op_done(struct adapter *adapter, int reg, u32 mask,
+ int polarity, int attempts, int delay)
+{
+ return t3_wait_op_done_val(adapter, reg, mask, polarity, attempts,
+ delay, NULL);
+}
+int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
+ unsigned int set);
+int t3_phy_reset(struct cphy *phy, int mmd, int wait);
+int t3_phy_advertise(struct cphy *phy, unsigned int advert);
+int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex);
+
+void t3_intr_enable(struct adapter *adapter);
+void t3_intr_disable(struct adapter *adapter);
+void t3_intr_clear(struct adapter *adapter);
+void t3_port_intr_enable(struct adapter *adapter, int idx);
+void t3_port_intr_disable(struct adapter *adapter, int idx);
+void t3_port_intr_clear(struct adapter *adapter, int idx);
+int t3_slow_intr_handler(struct adapter *adapter);
+int t3_phy_intr_handler(struct adapter *adapter);
+
+void t3_link_changed(struct adapter *adapter, int port_id);
+int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
+const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
+int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data);
+int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data);
+int t3_seeprom_wp(struct adapter *adapter, int enable);
+int t3_read_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int nwords, u32 *data, int byte_oriented);
+int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
+int t3_get_fw_version(struct adapter *adapter, u32 *vers);
+int t3_check_fw_version(struct adapter *adapter);
+int t3_init_hw(struct adapter *adapter, u32 fw_params);
+void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
+void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
+int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
+ int reset);
+void t3_led_ready(struct adapter *adapter);
+void t3_fatal_err(struct adapter *adapter);
+void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on);
+void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
+ const u8 * cpus, const u16 *rspq);
+int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map);
+int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask);
+int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
+ unsigned int n, unsigned int *valp);
+int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
+ u64 *buf);
+
+int t3_mac_reset(struct cmac *mac);
+void t3b_pcs_reset(struct cmac *mac);
+int t3_mac_enable(struct cmac *mac, int which);
+int t3_mac_disable(struct cmac *mac, int which);
+int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu);
+int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm);
+int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]);
+int t3_mac_set_num_ucast(struct cmac *mac, int n);
+const struct mac_stats *t3_mac_update_stats(struct cmac *mac);
+int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc);
+
+void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode);
+int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
+ unsigned int nroutes);
+void t3_mc5_intr_handler(struct mc5 *mc5);
+int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start, unsigned int n,
+ u32 *buf);
+
+int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh);
+void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size);
+void t3_tp_set_offload_mode(struct adapter *adap, int enable);
+void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps);
+void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
+ unsigned short alpha[NCCTRL_WIN],
+ unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap);
+void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS]);
+void t3_get_cong_cntl_tab(struct adapter *adap,
+ unsigned short incr[NMTUS][NCCTRL_WIN]);
+void t3_config_trace_filter(struct adapter *adapter,
+ const struct trace_params *tp, int filter_index,
+ int invert, int enable);
+int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched);
+
+void t3_sge_prep(struct adapter *adap, struct sge_params *p);
+void t3_sge_init(struct adapter *adap, struct sge_params *p);
+int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
+ enum sge_context_type type, int respq, u64 base_addr,
+ unsigned int size, unsigned int token, int gen,
+ unsigned int cidx);
+int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
+ int gts_enable, u64 base_addr, unsigned int size,
+ unsigned int esize, unsigned int cong_thres, int gen,
+ unsigned int cidx);
+int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
+ int irq_vec_idx, u64 base_addr, unsigned int size,
+ unsigned int fl_thres, int gen, unsigned int cidx);
+int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
+ unsigned int size, int rspq, int ovfl_mode,
+ unsigned int credits, unsigned int credit_thres);
+int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable);
+int t3_sge_disable_fl(struct adapter *adapter, unsigned int id);
+int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id);
+int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id);
+int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
+ unsigned int credits);
+
+void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
+ const struct mdio_ops *mdio_ops);
+void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+#endif /* __CHELSIO_COMMON_H */
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
new file mode 100644
index 00000000000..2095ddacff7
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CXGB3_OFFLOAD_CTL_DEFS_H
+#define _CXGB3_OFFLOAD_CTL_DEFS_H
+
+enum {
+ GET_MAX_OUTSTANDING_WR,
+ GET_TX_MAX_CHUNK,
+ GET_TID_RANGE,
+ GET_STID_RANGE,
+ GET_RTBL_RANGE,
+ GET_L2T_CAPACITY,
+ GET_MTUS,
+ GET_WR_LEN,
+ GET_IFF_FROM_MAC,
+ GET_DDP_PARAMS,
+ GET_PORTS,
+
+ ULP_ISCSI_GET_PARAMS,
+ ULP_ISCSI_SET_PARAMS,
+
+ RDMA_GET_PARAMS,
+ RDMA_CQ_OP,
+ RDMA_CQ_SETUP,
+ RDMA_CQ_DISABLE,
+ RDMA_CTRL_QP_SETUP,
+ RDMA_GET_MEM,
+};
+
+/*
+ * Structure used to describe a TID range. Valid TIDs are [base, base+num).
+ */
+struct tid_range {
+ unsigned int base; /* first TID */
+ unsigned int num; /* number of TIDs in range */
+};
+
+/*
+ * Structure used to request the size and contents of the MTU table.
+ */
+struct mtutab {
+ unsigned int size; /* # of entries in the MTU table */
+ const unsigned short *mtus; /* the MTU table values */
+};
+
+struct net_device;
+
+/*
+ * Structure used to request the adapter net_device owning a given MAC address.
+ */
+struct iff_mac {
+ struct net_device *dev; /* the net_device */
+ const unsigned char *mac_addr; /* MAC address to lookup */
+ u16 vlan_tag;
+};
+
+struct pci_dev;
+
+/*
+ * Structure used to request the TCP DDP parameters.
+ */
+struct ddp_params {
+ unsigned int llimit; /* TDDP region start address */
+ unsigned int ulimit; /* TDDP region end address */
+ unsigned int tag_mask; /* TDDP tag mask */
+ struct pci_dev *pdev;
+};
+
+struct adap_ports {
+ unsigned int nports; /* number of ports on this adapter */
+ struct net_device *lldevs[2];
+};
+
+/*
+ * Structure used to return information to the iscsi layer.
+ */
+struct ulp_iscsi_info {
+ unsigned int offset;
+ unsigned int llimit;
+ unsigned int ulimit;
+ unsigned int tagmask;
+ unsigned int pgsz3;
+ unsigned int pgsz2;
+ unsigned int pgsz1;
+ unsigned int pgsz0;
+ unsigned int max_rxsz;
+ unsigned int max_txsz;
+ struct pci_dev *pdev;
+};
+
+/*
+ * Structure used to return information to the RDMA layer.
+ */
+struct rdma_info {
+ unsigned int tpt_base; /* TPT base address */
+ unsigned int tpt_top; /* TPT last entry address */
+ unsigned int pbl_base; /* PBL base address */
+ unsigned int pbl_top; /* PBL last entry address */
+ unsigned int rqt_base; /* RQT base address */
+ unsigned int rqt_top; /* RQT last entry address */
+ unsigned int udbell_len; /* user doorbell region length */
+ unsigned long udbell_physbase; /* user doorbell physical start addr */
+ void __iomem *kdb_addr; /* kernel doorbell register address */
+ struct pci_dev *pdev; /* associated PCI device */
+};
+
+/*
+ * Structure used to request an operation on an RDMA completion queue.
+ */
+struct rdma_cq_op {
+ unsigned int id;
+ unsigned int op;
+ unsigned int credits;
+};
+
+/*
+ * Structure used to setup RDMA completion queues.
+ */
+struct rdma_cq_setup {
+ unsigned int id;
+ unsigned long long base_addr;
+ unsigned int size;
+ unsigned int credits;
+ unsigned int credit_thres;
+ unsigned int ovfl_mode;
+};
+
+/*
+ * Structure used to setup the RDMA control egress context.
+ */
+struct rdma_ctrlqp_setup {
+ unsigned long long base_addr;
+ unsigned int size;
+};
+#endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
new file mode 100644
index 00000000000..16e004990c5
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_defs.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CHELSIO_DEFS_H
+#define _CHELSIO_DEFS_H
+
+#include <linux/skbuff.h>
+#include <net/tcp.h>
+
+#include "t3cdev.h"
+
+#include "cxgb3_offload.h"
+
+#define VALIDATE_TID 1
+
+void *cxgb_alloc_mem(unsigned long size);
+void cxgb_free_mem(void *addr);
+void cxgb_neigh_update(struct neighbour *neigh);
+void cxgb_redirect(struct dst_entry *old, struct dst_entry *new);
+
+/*
+ * Map an ATID or STID to their entries in the corresponding TID tables.
+ */
+static inline union active_open_entry *atid2entry(const struct tid_info *t,
+ unsigned int atid)
+{
+ return &t->atid_tab[atid - t->atid_base];
+}
+
+static inline union listen_entry *stid2entry(const struct tid_info *t,
+ unsigned int stid)
+{
+ return &t->stid_tab[stid - t->stid_base];
+}
+
+/*
+ * Find the connection corresponding to a TID.
+ */
+static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t,
+ unsigned int tid)
+{
+ return tid < t->ntids ? &(t->tid_tab[tid]) : NULL;
+}
+
+/*
+ * Find the connection corresponding to a server TID.
+ */
+static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t,
+ unsigned int tid)
+{
+ if (tid < t->stid_base || tid >= t->stid_base + t->nstids)
+ return NULL;
+ return &(stid2entry(t, tid)->t3c_tid);
+}
+
+/*
+ * Find the connection corresponding to an active-open TID.
+ */
+static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t,
+ unsigned int tid)
+{
+ if (tid < t->atid_base || tid >= t->atid_base + t->natids)
+ return NULL;
+ return &(atid2entry(t, tid)->t3c_tid);
+}
+
+int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n);
+int attach_t3cdev(struct t3cdev *dev);
+void detach_t3cdev(struct t3cdev *dev);
+#endif
diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h
new file mode 100644
index 00000000000..a94281861a6
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_ioctl.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CHIOCTL_H__
+#define __CHIOCTL_H__
+
+/*
+ * Ioctl commands specific to this driver.
+ */
+enum {
+ CHELSIO_SETREG = 1024,
+ CHELSIO_GETREG,
+ CHELSIO_SETTPI,
+ CHELSIO_GETTPI,
+ CHELSIO_GETMTUTAB,
+ CHELSIO_SETMTUTAB,
+ CHELSIO_GETMTU,
+ CHELSIO_SET_PM,
+ CHELSIO_GET_PM,
+ CHELSIO_GET_TCAM,
+ CHELSIO_SET_TCAM,
+ CHELSIO_GET_TCB,
+ CHELSIO_GET_MEM,
+ CHELSIO_LOAD_FW,
+ CHELSIO_GET_PROTO,
+ CHELSIO_SET_PROTO,
+ CHELSIO_SET_TRACE_FILTER,
+ CHELSIO_SET_QSET_PARAMS,
+ CHELSIO_GET_QSET_PARAMS,
+ CHELSIO_SET_QSET_NUM,
+ CHELSIO_GET_QSET_NUM,
+ CHELSIO_SET_PKTSCHED,
+};
+
+struct ch_reg {
+ uint32_t cmd;
+ uint32_t addr;
+ uint32_t val;
+};
+
+struct ch_cntxt {
+ uint32_t cmd;
+ uint32_t cntxt_type;
+ uint32_t cntxt_id;
+ uint32_t data[4];
+};
+
+/* context types */
+enum { CNTXT_TYPE_EGRESS, CNTXT_TYPE_FL, CNTXT_TYPE_RSP, CNTXT_TYPE_CQ };
+
+struct ch_desc {
+ uint32_t cmd;
+ uint32_t queue_num;
+ uint32_t idx;
+ uint32_t size;
+ uint8_t data[128];
+};
+
+struct ch_mem_range {
+ uint32_t cmd;
+ uint32_t mem_id;
+ uint32_t addr;
+ uint32_t len;
+ uint32_t version;
+ uint8_t buf[0];
+};
+
+struct ch_qset_params {
+ uint32_t cmd;
+ uint32_t qset_idx;
+ int32_t txq_size[3];
+ int32_t rspq_size;
+ int32_t fl_size[2];
+ int32_t intr_lat;
+ int32_t polling;
+ int32_t cong_thres;
+};
+
+struct ch_pktsched_params {
+ uint32_t cmd;
+ uint8_t sched;
+ uint8_t idx;
+ uint8_t min;
+ uint8_t max;
+ uint8_t binding;
+};
+
+#ifndef TCB_SIZE
+# define TCB_SIZE 128
+#endif
+
+/* TCB size in 32-bit words */
+#define TCB_WORDS (TCB_SIZE / 4)
+
+enum { MEM_CM, MEM_PMRX, MEM_PMTX }; /* ch_mem_range.mem_id values */
+
+struct ch_mtus {
+ uint32_t cmd;
+ uint32_t nmtus;
+ uint16_t mtus[NMTUS];
+};
+
+struct ch_pm {
+ uint32_t cmd;
+ uint32_t tx_pg_sz;
+ uint32_t tx_num_pg;
+ uint32_t rx_pg_sz;
+ uint32_t rx_num_pg;
+ uint32_t pm_total;
+};
+
+struct ch_tcam {
+ uint32_t cmd;
+ uint32_t tcam_size;
+ uint32_t nservers;
+ uint32_t nroutes;
+ uint32_t nfilters;
+};
+
+struct ch_tcb {
+ uint32_t cmd;
+ uint32_t tcb_index;
+ uint32_t tcb_data[TCB_WORDS];
+};
+
+struct ch_tcam_word {
+ uint32_t cmd;
+ uint32_t addr;
+ uint32_t buf[3];
+};
+
+struct ch_trace {
+ uint32_t cmd;
+ uint32_t sip;
+ uint32_t sip_mask;
+ uint32_t dip;
+ uint32_t dip_mask;
+ uint16_t sport;
+ uint16_t sport_mask;
+ uint16_t dport;
+ uint16_t dport_mask;
+ uint32_t vlan:12;
+ uint32_t vlan_mask:12;
+ uint32_t intf:4;
+ uint32_t intf_mask:4;
+ uint8_t proto;
+ uint8_t proto_mask;
+ uint8_t invert_match:1;
+ uint8_t config_tx:1;
+ uint8_t config_rx:1;
+ uint8_t trace_tx:1;
+ uint8_t trace_rx:1;
+};
+
+#define SIOCCHIOCTL SIOCDEVPRIVATE
+
+#endif
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
new file mode 100644
index 00000000000..c67f7d3c2f9
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -0,0 +1,2519 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/mii.h>
+#include <linux/sockios.h>
+#include <linux/workqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/rtnetlink.h>
+#include <asm/uaccess.h>
+
+#include "common.h"
+#include "cxgb3_ioctl.h"
+#include "regs.h"
+#include "cxgb3_offload.h"
+#include "version.h"
+
+#include "cxgb3_ctl_defs.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+enum {
+ MAX_TXQ_ENTRIES = 16384,
+ MAX_CTRL_TXQ_ENTRIES = 1024,
+ MAX_RSPQ_ENTRIES = 16384,
+ MAX_RX_BUFFERS = 16384,
+ MAX_RX_JUMBO_BUFFERS = 16384,
+ MIN_TXQ_ENTRIES = 4,
+ MIN_CTRL_TXQ_ENTRIES = 4,
+ MIN_RSPQ_ENTRIES = 32,
+ MIN_FL_ENTRIES = 32
+};
+
+#define PORT_MASK ((1 << MAX_NPORTS) - 1)
+
+#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
+ NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
+
+#define EEPROM_MAGIC 0x38E2F10C
+
+#define CH_DEVICE(devid, ssid, idx) \
+ { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx }
+
+static const struct pci_device_id cxgb3_pci_tbl[] = {
+ CH_DEVICE(0x20, 1, 0), /* PE9000 */
+ CH_DEVICE(0x21, 1, 1), /* T302E */
+ CH_DEVICE(0x22, 1, 2), /* T310E */
+ CH_DEVICE(0x23, 1, 3), /* T320X */
+ CH_DEVICE(0x24, 1, 1), /* T302X */
+ CH_DEVICE(0x25, 1, 3), /* T320E */
+ CH_DEVICE(0x26, 1, 2), /* T310X */
+ CH_DEVICE(0x30, 1, 2), /* T3B10 */
+ CH_DEVICE(0x31, 1, 3), /* T3B20 */
+ CH_DEVICE(0x32, 1, 1), /* T3B02 */
+ {0,}
+};
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_AUTHOR("Chelsio Communications");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
+
+static int dflt_msg_enable = DFLT_MSG_ENABLE;
+
+module_param(dflt_msg_enable, int, 0644);
+MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap");
+
+/*
+ * The driver uses the best interrupt scheme available on a platform in the
+ * order MSI-X, MSI, legacy pin interrupts. This parameter determines which
+ * of these schemes the driver may consider as follows:
+ *
+ * msi = 2: choose from among all three options
+ * msi = 1: only consider MSI and pin interrupts
+ * msi = 0: force pin interrupts
+ */
+static int msi = 2;
+
+module_param(msi, int, 0644);
+MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X");
+
+/*
+ * The driver enables offload as a default.
+ * To disable it, use ofld_disable = 1.
+ */
+
+static int ofld_disable = 0;
+
+module_param(ofld_disable, int, 0644);
+MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
+
+/*
+ * We have work elements that we need to cancel when an interface is taken
+ * down. Normally the work elements would be executed by keventd but that
+ * can deadlock because of linkwatch. If our close method takes the rtnl
+ * lock and linkwatch is ahead of our work elements in keventd, linkwatch
+ * will block keventd as it needs the rtnl lock, and we'll deadlock waiting
+ * for our work to complete. Get our own work queue to solve this.
+ */
+static struct workqueue_struct *cxgb3_wq;
+
+/**
+ * link_report - show link status and link speed/duplex
+ * @p: the port whose settings are to be reported
+ *
+ * Shows the link status, speed, and duplex of a port.
+ */
+static void link_report(struct net_device *dev)
+{
+ if (!netif_carrier_ok(dev))
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ else {
+ const char *s = "10Mbps";
+ const struct port_info *p = netdev_priv(dev);
+
+ switch (p->link_config.speed) {
+ case SPEED_10000:
+ s = "10Gbps";
+ break;
+ case SPEED_1000:
+ s = "1000Mbps";
+ break;
+ case SPEED_100:
+ s = "100Mbps";
+ break;
+ }
+
+ printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
+ p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+ }
+}
+
+/**
+ * t3_os_link_changed - handle link status changes
+ * @adapter: the adapter associated with the link change
+ * @port_id: the port index whose limk status has changed
+ * @link_stat: the new status of the link
+ * @speed: the new speed setting
+ * @duplex: the new duplex setting
+ * @pause: the new flow-control setting
+ *
+ * This is the OS-dependent handler for link status changes. The OS
+ * neutral handler takes care of most of the processing for these events,
+ * then calls this handler for any OS-specific processing.
+ */
+void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
+ int speed, int duplex, int pause)
+{
+ struct net_device *dev = adapter->port[port_id];
+
+ /* Skip changes from disabled ports. */
+ if (!netif_running(dev))
+ return;
+
+ if (link_stat != netif_carrier_ok(dev)) {
+ if (link_stat)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
+ link_report(dev);
+ }
+}
+
+static void cxgb_set_rxmode(struct net_device *dev)
+{
+ struct t3_rx_mode rm;
+ struct port_info *pi = netdev_priv(dev);
+
+ init_rx_mode(&rm, dev, dev->mc_list);
+ t3_mac_set_rx_mode(&pi->mac, &rm);
+}
+
+/**
+ * link_start - enable a port
+ * @dev: the device to enable
+ *
+ * Performs the MAC and PHY actions needed to enable a port.
+ */
+static void link_start(struct net_device *dev)
+{
+ struct t3_rx_mode rm;
+ struct port_info *pi = netdev_priv(dev);
+ struct cmac *mac = &pi->mac;
+
+ init_rx_mode(&rm, dev, dev->mc_list);
+ t3_mac_reset(mac);
+ t3_mac_set_mtu(mac, dev->mtu);
+ t3_mac_set_address(mac, 0, dev->dev_addr);
+ t3_mac_set_rx_mode(mac, &rm);
+ t3_link_start(&pi->phy, mac, &pi->link_config);
+ t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
+}
+
+static inline void cxgb_disable_msi(struct adapter *adapter)
+{
+ if (adapter->flags & USING_MSIX) {
+ pci_disable_msix(adapter->pdev);
+ adapter->flags &= ~USING_MSIX;
+ } else if (adapter->flags & USING_MSI) {
+ pci_disable_msi(adapter->pdev);
+ adapter->flags &= ~USING_MSI;
+ }
+}
+
+/*
+ * Interrupt handler for asynchronous events used with MSI-X.
+ */
+static irqreturn_t t3_async_intr_handler(int irq, void *cookie)
+{
+ t3_slow_intr_handler(cookie);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Name the MSI-X interrupts.
+ */
+static void name_msix_vecs(struct adapter *adap)
+{
+ int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
+
+ snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
+ adap->msix_info[0].desc[n] = 0;
+
+ for_each_port(adap, j) {
+ struct net_device *d = adap->port[j];
+ const struct port_info *pi = netdev_priv(d);
+
+ for (i = 0; i < pi->nqsets; i++, msi_idx++) {
+ snprintf(adap->msix_info[msi_idx].desc, n,
+ "%s (queue %d)", d->name, i);
+ adap->msix_info[msi_idx].desc[n] = 0;
+ }
+ }
+}
+
+static int request_msix_data_irqs(struct adapter *adap)
+{
+ int i, j, err, qidx = 0;
+
+ for_each_port(adap, i) {
+ int nqsets = adap2pinfo(adap, i)->nqsets;
+
+ for (j = 0; j < nqsets; ++j) {
+ err = request_irq(adap->msix_info[qidx + 1].vec,
+ t3_intr_handler(adap,
+ adap->sge.qs[qidx].
+ rspq.polling), 0,
+ adap->msix_info[qidx + 1].desc,
+ &adap->sge.qs[qidx]);
+ if (err) {
+ while (--qidx >= 0)
+ free_irq(adap->msix_info[qidx + 1].vec,
+ &adap->sge.qs[qidx]);
+ return err;
+ }
+ qidx++;
+ }
+ }
+ return 0;
+}
+
+/**
+ * setup_rss - configure RSS
+ * @adap: the adapter
+ *
+ * Sets up RSS to distribute packets to multiple receive queues. We
+ * configure the RSS CPU lookup table to distribute to the number of HW
+ * receive queues, and the response queue lookup table to narrow that
+ * down to the response queues actually configured for each port.
+ * We always configure the RSS mapping for two ports since the mapping
+ * table has plenty of entries.
+ */
+static void setup_rss(struct adapter *adap)
+{
+ int i;
+ unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
+ unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
+ u8 cpus[SGE_QSETS + 1];
+ u16 rspq_map[RSS_TABLE_SIZE];
+
+ for (i = 0; i < SGE_QSETS; ++i)
+ cpus[i] = i;
+ cpus[SGE_QSETS] = 0xff; /* terminator */
+
+ for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
+ rspq_map[i] = i % nq0;
+ rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
+ }
+
+ t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
+ F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
+ V_RRCPLCPUSIZE(6), cpus, rspq_map);
+}
+
+/*
+ * If we have multiple receive queues per port serviced by NAPI we need one
+ * netdevice per queue as NAPI operates on netdevices. We already have one
+ * netdevice, namely the one associated with the interface, so we use dummy
+ * ones for any additional queues. Note that these netdevices exist purely
+ * so that NAPI has something to work with, they do not represent network
+ * ports and are not registered.
+ */
+static int init_dummy_netdevs(struct adapter *adap)
+{
+ int i, j, dummy_idx = 0;
+ struct net_device *nd;
+
+ for_each_port(adap, i) {
+ struct net_device *dev = adap->port[i];
+ const struct port_info *pi = netdev_priv(dev);
+
+ for (j = 0; j < pi->nqsets - 1; j++) {
+ if (!adap->dummy_netdev[dummy_idx]) {
+ nd = alloc_netdev(0, "", ether_setup);
+ if (!nd)
+ goto free_all;
+
+ nd->priv = adap;
+ nd->weight = 64;
+ set_bit(__LINK_STATE_START, &nd->state);
+ adap->dummy_netdev[dummy_idx] = nd;
+ }
+ strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name);
+ dummy_idx++;
+ }
+ }
+ return 0;
+
+free_all:
+ while (--dummy_idx >= 0) {
+ free_netdev(adap->dummy_netdev[dummy_idx]);
+ adap->dummy_netdev[dummy_idx] = NULL;
+ }
+ return -ENOMEM;
+}
+
+/*
+ * Wait until all NAPI handlers are descheduled. This includes the handlers of
+ * both netdevices representing interfaces and the dummy ones for the extra
+ * queues.
+ */
+static void quiesce_rx(struct adapter *adap)
+{
+ int i;
+ struct net_device *dev;
+
+ for_each_port(adap, i) {
+ dev = adap->port[i];
+ while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
+ msleep(1);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) {
+ dev = adap->dummy_netdev[i];
+ if (dev)
+ while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
+ msleep(1);
+ }
+}
+
+/**
+ * setup_sge_qsets - configure SGE Tx/Rx/response queues
+ * @adap: the adapter
+ *
+ * Determines how many sets of SGE queues to use and initializes them.
+ * We support multiple queue sets per port if we have MSI-X, otherwise
+ * just one queue set per port.
+ */
+static int setup_sge_qsets(struct adapter *adap)
+{
+ int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0;
+ unsigned int ntxq = is_offload(adap) ? SGE_TXQ_PER_SET : 1;
+
+ if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
+ irq_idx = -1;
+
+ for_each_port(adap, i) {
+ struct net_device *dev = adap->port[i];
+ const struct port_info *pi = netdev_priv(dev);
+
+ for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
+ err = t3_sge_alloc_qset(adap, qset_idx, 1,
+ (adap->flags & USING_MSIX) ? qset_idx + 1 :
+ irq_idx,
+ &adap->params.sge.qset[qset_idx], ntxq,
+ j == 0 ? dev :
+ adap-> dummy_netdev[dummy_dev_idx++]);
+ if (err) {
+ t3_free_sge_resources(adap);
+ return err;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t attr_show(struct device *d, struct device_attribute *attr,
+ char *buf,
+ ssize_t(*format) (struct adapter *, char *))
+{
+ ssize_t len;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ /* Synchronize with ioctls that may shut down the device */
+ rtnl_lock();
+ len = (*format) (adap, buf);
+ rtnl_unlock();
+ return len;
+}
+
+static ssize_t attr_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len,
+ ssize_t(*set) (struct adapter *, unsigned int),
+ unsigned int min_val, unsigned int max_val)
+{
+ char *endp;
+ ssize_t ret;
+ unsigned int val;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ val = simple_strtoul(buf, &endp, 0);
+ if (endp == buf || val < min_val || val > max_val)
+ return -EINVAL;
+
+ rtnl_lock();
+ ret = (*set) (adap, val);
+ if (!ret)
+ ret = len;
+ rtnl_unlock();
+ return ret;
+}
+
+#define CXGB3_SHOW(name, val_expr) \
+static ssize_t format_##name(struct adapter *adap, char *buf) \
+{ \
+ return sprintf(buf, "%u\n", val_expr); \
+} \
+static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return attr_show(d, attr, buf, format_##name); \
+}
+
+static ssize_t set_nfilters(struct adapter *adap, unsigned int val)
+{
+ if (adap->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (val && adap->params.rev == 0)
+ return -EINVAL;
+ if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers)
+ return -EINVAL;
+ adap->params.mc5.nfilters = val;
+ return 0;
+}
+
+static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return attr_store(d, attr, buf, len, set_nfilters, 0, ~0);
+}
+
+static ssize_t set_nservers(struct adapter *adap, unsigned int val)
+{
+ if (adap->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters)
+ return -EINVAL;
+ adap->params.mc5.nservers = val;
+ return 0;
+}
+
+static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return attr_store(d, attr, buf, len, set_nservers, 0, ~0);
+}
+
+#define CXGB3_ATTR_R(name, val_expr) \
+CXGB3_SHOW(name, val_expr) \
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+
+#define CXGB3_ATTR_RW(name, val_expr, store_method) \
+CXGB3_SHOW(name, val_expr) \
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
+
+CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
+CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
+CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
+
+static struct attribute *cxgb3_attrs[] = {
+ &dev_attr_cam_size.attr,
+ &dev_attr_nfilters.attr,
+ &dev_attr_nservers.attr,
+ NULL
+};
+
+static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
+
+static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
+ char *buf, int sched)
+{
+ ssize_t len;
+ unsigned int v, addr, bpt, cpt;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
+ rtnl_lock();
+ t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
+ v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
+ if (sched & 1)
+ v >>= 16;
+ bpt = (v >> 8) & 0xff;
+ cpt = v & 0xff;
+ if (!cpt)
+ len = sprintf(buf, "disabled\n");
+ else {
+ v = (adap->params.vpd.cclk * 1000) / cpt;
+ len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
+ }
+ rtnl_unlock();
+ return len;
+}
+
+static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len, int sched)
+{
+ char *endp;
+ ssize_t ret;
+ unsigned int val;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ val = simple_strtoul(buf, &endp, 0);
+ if (endp == buf || val > 10000000)
+ return -EINVAL;
+
+ rtnl_lock();
+ ret = t3_config_sched(adap, val, sched);
+ if (!ret)
+ ret = len;
+ rtnl_unlock();
+ return ret;
+}
+
+#define TM_ATTR(name, sched) \
+static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return tm_attr_show(d, attr, buf, sched); \
+} \
+static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ return tm_attr_store(d, attr, buf, len, sched); \
+} \
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
+
+TM_ATTR(sched0, 0);
+TM_ATTR(sched1, 1);
+TM_ATTR(sched2, 2);
+TM_ATTR(sched3, 3);
+TM_ATTR(sched4, 4);
+TM_ATTR(sched5, 5);
+TM_ATTR(sched6, 6);
+TM_ATTR(sched7, 7);
+
+static struct attribute *offload_attrs[] = {
+ &dev_attr_sched0.attr,
+ &dev_attr_sched1.attr,
+ &dev_attr_sched2.attr,
+ &dev_attr_sched3.attr,
+ &dev_attr_sched4.attr,
+ &dev_attr_sched5.attr,
+ &dev_attr_sched6.attr,
+ &dev_attr_sched7.attr,
+ NULL
+};
+
+static struct attribute_group offload_attr_group = {.attrs = offload_attrs };
+
+/*
+ * Sends an sk_buff to an offload queue driver
+ * after dealing with any active network taps.
+ */
+static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
+{
+ int ret;
+
+ local_bh_disable();
+ ret = t3_offload_tx(tdev, skb);
+ local_bh_enable();
+ return ret;
+}
+
+static int write_smt_entry(struct adapter *adapter, int idx)
+{
+ struct cpl_smt_write_req *req;
+ struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
+
+ if (!skb)
+ return -ENOMEM;
+
+ req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
+ req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */
+ req->iff = idx;
+ memset(req->src_mac1, 0, sizeof(req->src_mac1));
+ memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
+ skb->priority = 1;
+ offload_tx(&adapter->tdev, skb);
+ return 0;
+}
+
+static int init_smt(struct adapter *adapter)
+{
+ int i;
+
+ for_each_port(adapter, i)
+ write_smt_entry(adapter, i);
+ return 0;
+}
+
+static void init_port_mtus(struct adapter *adapter)
+{
+ unsigned int mtus = adapter->port[0]->mtu;
+
+ if (adapter->port[1])
+ mtus |= adapter->port[1]->mtu << 16;
+ t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
+}
+
+static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
+ int hi, int port)
+{
+ struct sk_buff *skb;
+ struct mngt_pktsched_wr *req;
+
+ skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+ req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
+ req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
+ req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
+ req->sched = sched;
+ req->idx = qidx;
+ req->min = lo;
+ req->max = hi;
+ req->binding = port;
+ t3_mgmt_tx(adap, skb);
+}
+
+static void bind_qsets(struct adapter *adap)
+{
+ int i, j;
+
+ for_each_port(adap, i) {
+ const struct port_info *pi = adap2pinfo(adap, i);
+
+ for (j = 0; j < pi->nqsets; ++j)
+ send_pktsched_cmd(adap, 1, pi->first_qset + j, -1,
+ -1, i);
+ }
+}
+
+/**
+ * cxgb_up - enable the adapter
+ * @adapter: adapter being enabled
+ *
+ * Called when the first port is enabled, this function performs the
+ * actions necessary to make an adapter operational, such as completing
+ * the initialization of HW modules, and enabling interrupts.
+ *
+ * Must be called with the rtnl lock held.
+ */
+static int cxgb_up(struct adapter *adap)
+{
+ int err = 0;
+
+ if (!(adap->flags & FULL_INIT_DONE)) {
+ err = t3_check_fw_version(adap);
+ if (err)
+ goto out;
+
+ err = init_dummy_netdevs(adap);
+ if (err)
+ goto out;
+
+ err = t3_init_hw(adap, 0);
+ if (err)
+ goto out;
+
+ err = setup_sge_qsets(adap);
+ if (err)
+ goto out;
+
+ setup_rss(adap);
+ adap->flags |= FULL_INIT_DONE;
+ }
+
+ t3_intr_clear(adap);
+
+ if (adap->flags & USING_MSIX) {
+ name_msix_vecs(adap);
+ err = request_irq(adap->msix_info[0].vec,
+ t3_async_intr_handler, 0,
+ adap->msix_info[0].desc, adap);
+ if (err)
+ goto irq_err;
+
+ if (request_msix_data_irqs(adap)) {
+ free_irq(adap->msix_info[0].vec, adap);
+ goto irq_err;
+ }
+ } else if ((err = request_irq(adap->pdev->irq,
+ t3_intr_handler(adap,
+ adap->sge.qs[0].rspq.
+ polling),
+ (adap->flags & USING_MSI) ? 0 : SA_SHIRQ,
+ adap->name, adap)))
+ goto irq_err;
+
+ t3_sge_start(adap);
+ t3_intr_enable(adap);
+
+ if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
+ bind_qsets(adap);
+ adap->flags |= QUEUES_BOUND;
+
+out:
+ return err;
+irq_err:
+ CH_ERR(adap, "request_irq failed, err %d\n", err);
+ goto out;
+}
+
+/*
+ * Release resources when all the ports and offloading have been stopped.
+ */
+static void cxgb_down(struct adapter *adapter)
+{
+ t3_sge_stop(adapter);
+ spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */
+ t3_intr_disable(adapter);
+ spin_unlock_irq(&adapter->work_lock);
+
+ if (adapter->flags & USING_MSIX) {
+ int i, n = 0;
+
+ free_irq(adapter->msix_info[0].vec, adapter);
+ for_each_port(adapter, i)
+ n += adap2pinfo(adapter, i)->nqsets;
+
+ for (i = 0; i < n; ++i)
+ free_irq(adapter->msix_info[i + 1].vec,
+ &adapter->sge.qs[i]);
+ } else
+ free_irq(adapter->pdev->irq, adapter);
+
+ flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
+ quiesce_rx(adapter);
+}
+
+static void schedule_chk_task(struct adapter *adap)
+{
+ unsigned int timeo;
+
+ timeo = adap->params.linkpoll_period ?
+ (HZ * adap->params.linkpoll_period) / 10 :
+ adap->params.stats_update_period * HZ;
+ if (timeo)
+ queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
+}
+
+static int offload_open(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct t3cdev *tdev = T3CDEV(dev);
+ int adap_up = adapter->open_device_map & PORT_MASK;
+ int err = 0;
+
+ if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+ return 0;
+
+ if (!adap_up && (err = cxgb_up(adapter)) < 0)
+ return err;
+
+ t3_tp_set_offload_mode(adapter, 1);
+ tdev->lldev = adapter->port[0];
+ err = cxgb3_offload_activate(adapter);
+ if (err)
+ goto out;
+
+ init_port_mtus(adapter);
+ t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
+ adapter->params.b_wnd,
+ adapter->params.rev == 0 ?
+ adapter->port[0]->mtu : 0xffff);
+ init_smt(adapter);
+
+ /* Never mind if the next step fails */
+ sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group);
+
+ /* Call back all registered clients */
+ cxgb3_add_clients(tdev);
+
+out:
+ /* restore them in case the offload module has changed them */
+ if (err) {
+ t3_tp_set_offload_mode(adapter, 0);
+ clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+ cxgb3_set_dummy_ops(tdev);
+ }
+ return err;
+}
+
+static int offload_close(struct t3cdev *tdev)
+{
+ struct adapter *adapter = tdev2adap(tdev);
+
+ if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+ return 0;
+
+ /* Call back all registered clients */
+ cxgb3_remove_clients(tdev);
+
+ sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
+
+ tdev->lldev = NULL;
+ cxgb3_set_dummy_ops(tdev);
+ t3_tp_set_offload_mode(adapter, 0);
+ clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+
+ if (!adapter->open_device_map)
+ cxgb_down(adapter);
+
+ cxgb3_offload_deactivate(adapter);
+ return 0;
+}
+
+static int cxgb_open(struct net_device *dev)
+{
+ int err;
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ int other_ports = adapter->open_device_map & PORT_MASK;
+
+ if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+ return err;
+
+ set_bit(pi->port_id, &adapter->open_device_map);
+ if (!ofld_disable) {
+ err = offload_open(dev);
+ if (err)
+ printk(KERN_WARNING
+ "Could not initialize offload capabilities\n");
+ }
+
+ link_start(dev);
+ t3_port_intr_enable(adapter, pi->port_id);
+ netif_start_queue(dev);
+ if (!other_ports)
+ schedule_chk_task(adapter);
+
+ return 0;
+}
+
+static int cxgb_close(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *p = netdev_priv(dev);
+
+ t3_port_intr_disable(adapter, p->port_id);
+ netif_stop_queue(dev);
+ p->phy.ops->power_down(&p->phy, 1);
+ netif_carrier_off(dev);
+ t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
+
+ spin_lock(&adapter->work_lock); /* sync with update task */
+ clear_bit(p->port_id, &adapter->open_device_map);
+ spin_unlock(&adapter->work_lock);
+
+ if (!(adapter->open_device_map & PORT_MASK))
+ cancel_rearming_delayed_workqueue(cxgb3_wq,
+ &adapter->adap_check_task);
+
+ if (!adapter->open_device_map)
+ cxgb_down(adapter);
+
+ return 0;
+}
+
+static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *p = netdev_priv(dev);
+ struct net_device_stats *ns = &p->netstats;
+ const struct mac_stats *pstats;
+
+ spin_lock(&adapter->stats_lock);
+ pstats = t3_mac_update_stats(&p->mac);
+ spin_unlock(&adapter->stats_lock);
+
+ ns->tx_bytes = pstats->tx_octets;
+ ns->tx_packets = pstats->tx_frames;
+ ns->rx_bytes = pstats->rx_octets;
+ ns->rx_packets = pstats->rx_frames;
+ ns->multicast = pstats->rx_mcast_frames;
+
+ ns->tx_errors = pstats->tx_underrun;
+ ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
+ pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
+ pstats->rx_fifo_ovfl;
+
+ /* detailed rx_errors */
+ ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
+ ns->rx_over_errors = 0;
+ ns->rx_crc_errors = pstats->rx_fcs_errs;
+ ns->rx_frame_errors = pstats->rx_symbol_errs;
+ ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
+ ns->rx_missed_errors = pstats->rx_cong_drops;
+
+ /* detailed tx_errors */
+ ns->tx_aborted_errors = 0;
+ ns->tx_carrier_errors = 0;
+ ns->tx_fifo_errors = pstats->tx_underrun;
+ ns->tx_heartbeat_errors = 0;
+ ns->tx_window_errors = 0;
+ return ns;
+}
+
+static u32 get_msglevel(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+
+ return adapter->msg_enable;
+}
+
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+ struct adapter *adapter = dev->priv;
+
+ adapter->msg_enable = val;
+}
+
+static char stats_strings[][ETH_GSTRING_LEN] = {
+ "TxOctetsOK ",
+ "TxFramesOK ",
+ "TxMulticastFramesOK",
+ "TxBroadcastFramesOK",
+ "TxPauseFrames ",
+ "TxUnderrun ",
+ "TxExtUnderrun ",
+
+ "TxFrames64 ",
+ "TxFrames65To127 ",
+ "TxFrames128To255 ",
+ "TxFrames256To511 ",
+ "TxFrames512To1023 ",
+ "TxFrames1024To1518 ",
+ "TxFrames1519ToMax ",
+
+ "RxOctetsOK ",
+ "RxFramesOK ",
+ "RxMulticastFramesOK",
+ "RxBroadcastFramesOK",
+ "RxPauseFrames ",
+ "RxFCSErrors ",
+ "RxSymbolErrors ",
+ "RxShortErrors ",
+ "RxJabberErrors ",
+ "RxLengthErrors ",
+ "RxFIFOoverflow ",
+
+ "RxFrames64 ",
+ "RxFrames65To127 ",
+ "RxFrames128To255 ",
+ "RxFrames256To511 ",
+ "RxFrames512To1023 ",
+ "RxFrames1024To1518 ",
+ "RxFrames1519ToMax ",
+
+ "PhyFIFOErrors ",
+ "TSO ",
+ "VLANextractions ",
+ "VLANinsertions ",
+ "TxCsumOffload ",
+ "RxCsumGood ",
+ "RxDrops "
+};
+
+static int get_stats_count(struct net_device *dev)
+{
+ return ARRAY_SIZE(stats_strings);
+}
+
+#define T3_REGMAP_SIZE (3 * 1024)
+
+static int get_regs_len(struct net_device *dev)
+{
+ return T3_REGMAP_SIZE;
+}
+
+static int get_eeprom_len(struct net_device *dev)
+{
+ return EEPROMSIZE;
+}
+
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ u32 fw_vers = 0;
+ struct adapter *adapter = dev->priv;
+
+ t3_get_fw_version(adapter, &fw_vers);
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(adapter->pdev));
+ if (!fw_vers)
+ strcpy(info->fw_version, "N/A");
+ else {
+ snprintf(info->fw_version, sizeof(info->fw_version),
+ "%s %u.%u.%u",
+ G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
+ G_FW_VERSION_MAJOR(fw_vers),
+ G_FW_VERSION_MINOR(fw_vers),
+ G_FW_VERSION_MICRO(fw_vers));
+ }
+}
+
+static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
+{
+ if (stringset == ETH_SS_STATS)
+ memcpy(data, stats_strings, sizeof(stats_strings));
+}
+
+static unsigned long collect_sge_port_stats(struct adapter *adapter,
+ struct port_info *p, int idx)
+{
+ int i;
+ unsigned long tot = 0;
+
+ for (i = 0; i < p->nqsets; ++i)
+ tot += adapter->sge.qs[i + p->first_qset].port_stats[idx];
+ return tot;
+}
+
+static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ const struct mac_stats *s;
+
+ spin_lock(&adapter->stats_lock);
+ s = t3_mac_update_stats(&pi->mac);
+ spin_unlock(&adapter->stats_lock);
+
+ *data++ = s->tx_octets;
+ *data++ = s->tx_frames;
+ *data++ = s->tx_mcast_frames;
+ *data++ = s->tx_bcast_frames;
+ *data++ = s->tx_pause;
+ *data++ = s->tx_underrun;
+ *data++ = s->tx_fifo_urun;
+
+ *data++ = s->tx_frames_64;
+ *data++ = s->tx_frames_65_127;
+ *data++ = s->tx_frames_128_255;
+ *data++ = s->tx_frames_256_511;
+ *data++ = s->tx_frames_512_1023;
+ *data++ = s->tx_frames_1024_1518;
+ *data++ = s->tx_frames_1519_max;
+
+ *data++ = s->rx_octets;
+ *data++ = s->rx_frames;
+ *data++ = s->rx_mcast_frames;
+ *data++ = s->rx_bcast_frames;
+ *data++ = s->rx_pause;
+ *data++ = s->rx_fcs_errs;
+ *data++ = s->rx_symbol_errs;
+ *data++ = s->rx_short;
+ *data++ = s->rx_jabber;
+ *data++ = s->rx_too_long;
+ *data++ = s->rx_fifo_ovfl;
+
+ *data++ = s->rx_frames_64;
+ *data++ = s->rx_frames_65_127;
+ *data++ = s->rx_frames_128_255;
+ *data++ = s->rx_frames_256_511;
+ *data++ = s->rx_frames_512_1023;
+ *data++ = s->rx_frames_1024_1518;
+ *data++ = s->rx_frames_1519_max;
+
+ *data++ = pi->phy.fifo_errors;
+
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
+ *data++ = s->rx_cong_drops;
+}
+
+static inline void reg_block_dump(struct adapter *ap, void *buf,
+ unsigned int start, unsigned int end)
+{
+ u32 *p = buf + start;
+
+ for (; start <= end; start += sizeof(u32))
+ *p++ = t3_read_reg(ap, start);
+}
+
+static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *buf)
+{
+ struct adapter *ap = dev->priv;
+
+ /*
+ * Version scheme:
+ * bits 0..9: chip version
+ * bits 10..15: chip revision
+ * bit 31: set for PCIe cards
+ */
+ regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
+
+ /*
+ * We skip the MAC statistics registers because they are clear-on-read.
+ * Also reading multi-register stats would need to synchronize with the
+ * periodic mac stats accumulation. Hard to justify the complexity.
+ */
+ memset(buf, 0, T3_REGMAP_SIZE);
+ reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
+ reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
+ reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
+ reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
+ reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
+ reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
+ XGM_REG(A_XGM_SERDES_STAT3, 1));
+ reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
+ XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
+}
+
+static int restart_autoneg(struct net_device *dev)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ return -EAGAIN;
+ if (p->link_config.autoneg != AUTONEG_ENABLE)
+ return -EINVAL;
+ p->phy.ops->autoneg_restart(&p->phy);
+ return 0;
+}
+
+static int cxgb3_phys_id(struct net_device *dev, u32 data)
+{
+ int i;
+ struct adapter *adapter = dev->priv;
+
+ if (data == 0)
+ data = 2;
+
+ for (i = 0; i < data * 2; i++) {
+ t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+ (i & 1) ? F_GPIO0_OUT_VAL : 0);
+ if (msleep_interruptible(500))
+ break;
+ }
+ t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+ F_GPIO0_OUT_VAL);
+ return 0;
+}
+
+static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ cmd->supported = p->link_config.supported;
+ cmd->advertising = p->link_config.advertising;
+
+ if (netif_carrier_ok(dev)) {
+ cmd->speed = p->link_config.speed;
+ cmd->duplex = p->link_config.duplex;
+ } else {
+ cmd->speed = -1;
+ cmd->duplex = -1;
+ }
+
+ cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+ cmd->phy_address = p->phy.addr;
+ cmd->transceiver = XCVR_EXTERNAL;
+ cmd->autoneg = p->link_config.autoneg;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+ return 0;
+}
+
+static int speed_duplex_to_caps(int speed, int duplex)
+{
+ int cap = 0;
+
+ switch (speed) {
+ case SPEED_10:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_10baseT_Full;
+ else
+ cap = SUPPORTED_10baseT_Half;
+ break;
+ case SPEED_100:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_100baseT_Full;
+ else
+ cap = SUPPORTED_100baseT_Half;
+ break;
+ case SPEED_1000:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_1000baseT_Full;
+ else
+ cap = SUPPORTED_1000baseT_Half;
+ break;
+ case SPEED_10000:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_10000baseT_Full;
+ }
+ return cap;
+}
+
+#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
+ ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
+ ADVERTISED_10000baseT_Full)
+
+static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct port_info *p = netdev_priv(dev);
+ struct link_config *lc = &p->link_config;
+
+ if (!(lc->supported & SUPPORTED_Autoneg))
+ return -EOPNOTSUPP; /* can't change speed/duplex */
+
+ if (cmd->autoneg == AUTONEG_DISABLE) {
+ int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
+
+ if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
+ return -EINVAL;
+ lc->requested_speed = cmd->speed;
+ lc->requested_duplex = cmd->duplex;
+ lc->advertising = 0;
+ } else {
+ cmd->advertising &= ADVERTISED_MASK;
+ cmd->advertising &= lc->supported;
+ if (!cmd->advertising)
+ return -EINVAL;
+ lc->requested_speed = SPEED_INVALID;
+ lc->requested_duplex = DUPLEX_INVALID;
+ lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
+ }
+ lc->autoneg = cmd->autoneg;
+ if (netif_running(dev))
+ t3_link_start(&p->phy, &p->mac, lc);
+ return 0;
+}
+
+static void get_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *epause)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
+ epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
+ epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
+}
+
+static int set_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *epause)
+{
+ struct port_info *p = netdev_priv(dev);
+ struct link_config *lc = &p->link_config;
+
+ if (epause->autoneg == AUTONEG_DISABLE)
+ lc->requested_fc = 0;
+ else if (lc->supported & SUPPORTED_Autoneg)
+ lc->requested_fc = PAUSE_AUTONEG;
+ else
+ return -EINVAL;
+
+ if (epause->rx_pause)
+ lc->requested_fc |= PAUSE_RX;
+ if (epause->tx_pause)
+ lc->requested_fc |= PAUSE_TX;
+ if (lc->autoneg == AUTONEG_ENABLE) {
+ if (netif_running(dev))
+ t3_link_start(&p->phy, &p->mac, lc);
+ } else {
+ lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+ if (netif_running(dev))
+ t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
+ }
+ return 0;
+}
+
+static u32 get_rx_csum(struct net_device *dev)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ return p->rx_csum_offload;
+}
+
+static int set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ p->rx_csum_offload = data;
+ return 0;
+}
+
+static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+ struct adapter *adapter = dev->priv;
+
+ e->rx_max_pending = MAX_RX_BUFFERS;
+ e->rx_mini_max_pending = 0;
+ e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
+ e->tx_max_pending = MAX_TXQ_ENTRIES;
+
+ e->rx_pending = adapter->params.sge.qset[0].fl_size;
+ e->rx_mini_pending = adapter->params.sge.qset[0].rspq_size;
+ e->rx_jumbo_pending = adapter->params.sge.qset[0].jumbo_size;
+ e->tx_pending = adapter->params.sge.qset[0].txq_size[0];
+}
+
+static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+ int i;
+ struct adapter *adapter = dev->priv;
+
+ if (e->rx_pending > MAX_RX_BUFFERS ||
+ e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
+ e->tx_pending > MAX_TXQ_ENTRIES ||
+ e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
+ e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
+ e->rx_pending < MIN_FL_ENTRIES ||
+ e->rx_jumbo_pending < MIN_FL_ENTRIES ||
+ e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
+ return -EINVAL;
+
+ if (adapter->flags & FULL_INIT_DONE)
+ return -EBUSY;
+
+ for (i = 0; i < SGE_QSETS; ++i) {
+ struct qset_params *q = &adapter->params.sge.qset[i];
+
+ q->rspq_size = e->rx_mini_pending;
+ q->fl_size = e->rx_pending;
+ q->jumbo_size = e->rx_jumbo_pending;
+ q->txq_size[0] = e->tx_pending;
+ q->txq_size[1] = e->tx_pending;
+ q->txq_size[2] = e->tx_pending;
+ }
+ return 0;
+}
+
+static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+ struct adapter *adapter = dev->priv;
+ struct qset_params *qsp = &adapter->params.sge.qset[0];
+ struct sge_qset *qs = &adapter->sge.qs[0];
+
+ if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
+ return -EINVAL;
+
+ qsp->coalesce_usecs = c->rx_coalesce_usecs;
+ t3_update_qset_coalesce(qs, qsp);
+ return 0;
+}
+
+static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+ struct adapter *adapter = dev->priv;
+ struct qset_params *q = adapter->params.sge.qset;
+
+ c->rx_coalesce_usecs = q->coalesce_usecs;
+ return 0;
+}
+
+static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
+ u8 * data)
+{
+ int i, err = 0;
+ struct adapter *adapter = dev->priv;
+
+ u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ e->magic = EEPROM_MAGIC;
+ for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
+ err = t3_seeprom_read(adapter, i, (u32 *) & buf[i]);
+
+ if (!err)
+ memcpy(data, buf + e->offset, e->len);
+ kfree(buf);
+ return err;
+}
+
+static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+ u8 * data)
+{
+ u8 *buf;
+ int err = 0;
+ u32 aligned_offset, aligned_len, *p;
+ struct adapter *adapter = dev->priv;
+
+ if (eeprom->magic != EEPROM_MAGIC)
+ return -EINVAL;
+
+ aligned_offset = eeprom->offset & ~3;
+ aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
+
+ if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
+ buf = kmalloc(aligned_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ err = t3_seeprom_read(adapter, aligned_offset, (u32 *) buf);
+ if (!err && aligned_len > 4)
+ err = t3_seeprom_read(adapter,
+ aligned_offset + aligned_len - 4,
+ (u32 *) & buf[aligned_len - 4]);
+ if (err)
+ goto out;
+ memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
+ } else
+ buf = data;
+
+ err = t3_seeprom_wp(adapter, 0);
+ if (err)
+ goto out;
+
+ for (p = (u32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
+ err = t3_seeprom_write(adapter, aligned_offset, *p);
+ aligned_offset += 4;
+ }
+
+ if (!err)
+ err = t3_seeprom_wp(adapter, 1);
+out:
+ if (buf != data)
+ kfree(buf);
+ return err;
+}
+
+static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ wol->supported = 0;
+ wol->wolopts = 0;
+ memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static const struct ethtool_ops cxgb_ethtool_ops = {
+ .get_settings = get_settings,
+ .set_settings = set_settings,
+ .get_drvinfo = get_drvinfo,
+ .get_msglevel = get_msglevel,
+ .set_msglevel = set_msglevel,
+ .get_ringparam = get_sge_param,
+ .set_ringparam = set_sge_param,
+ .get_coalesce = get_coalesce,
+ .set_coalesce = set_coalesce,
+ .get_eeprom_len = get_eeprom_len,
+ .get_eeprom = get_eeprom,
+ .set_eeprom = set_eeprom,
+ .get_pauseparam = get_pauseparam,
+ .set_pauseparam = set_pauseparam,
+ .get_rx_csum = get_rx_csum,
+ .set_rx_csum = set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_link = ethtool_op_get_link,
+ .get_strings = get_strings,
+ .phys_id = cxgb3_phys_id,
+ .nway_reset = restart_autoneg,
+ .get_stats_count = get_stats_count,
+ .get_ethtool_stats = get_stats,
+ .get_regs_len = get_regs_len,
+ .get_regs = get_regs,
+ .get_wol = get_wol,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+ .get_perm_addr = ethtool_op_get_perm_addr
+};
+
+static int in_range(int val, int lo, int hi)
+{
+ return val < 0 || (val <= hi && val >= lo);
+}
+
+static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
+{
+ int ret;
+ u32 cmd;
+ struct adapter *adapter = dev->priv;
+
+ if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case CHELSIO_SETREG:{
+ struct ch_reg edata;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if ((edata.addr & 3) != 0
+ || edata.addr >= adapter->mmio_len)
+ return -EINVAL;
+ writel(edata.val, adapter->regs + edata.addr);
+ break;
+ }
+ case CHELSIO_GETREG:{
+ struct ch_reg edata;
+
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if ((edata.addr & 3) != 0
+ || edata.addr >= adapter->mmio_len)
+ return -EINVAL;
+ edata.val = readl(adapter->regs + edata.addr);
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_SET_QSET_PARAMS:{
+ int i;
+ struct qset_params *q;
+ struct ch_qset_params t;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+ if (t.qset_idx >= SGE_QSETS)
+ return -EINVAL;
+ if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
+ !in_range(t.cong_thres, 0, 255) ||
+ !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
+ MAX_TXQ_ENTRIES) ||
+ !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
+ MAX_TXQ_ENTRIES) ||
+ !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
+ MAX_CTRL_TXQ_ENTRIES) ||
+ !in_range(t.fl_size[0], MIN_FL_ENTRIES,
+ MAX_RX_BUFFERS)
+ || !in_range(t.fl_size[1], MIN_FL_ENTRIES,
+ MAX_RX_JUMBO_BUFFERS)
+ || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
+ MAX_RSPQ_ENTRIES))
+ return -EINVAL;
+ if ((adapter->flags & FULL_INIT_DONE) &&
+ (t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
+ t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
+ t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
+ t.polling >= 0 || t.cong_thres >= 0))
+ return -EBUSY;
+
+ q = &adapter->params.sge.qset[t.qset_idx];
+
+ if (t.rspq_size >= 0)
+ q->rspq_size = t.rspq_size;
+ if (t.fl_size[0] >= 0)
+ q->fl_size = t.fl_size[0];
+ if (t.fl_size[1] >= 0)
+ q->jumbo_size = t.fl_size[1];
+ if (t.txq_size[0] >= 0)
+ q->txq_size[0] = t.txq_size[0];
+ if (t.txq_size[1] >= 0)
+ q->txq_size[1] = t.txq_size[1];
+ if (t.txq_size[2] >= 0)
+ q->txq_size[2] = t.txq_size[2];
+ if (t.cong_thres >= 0)
+ q->cong_thres = t.cong_thres;
+ if (t.intr_lat >= 0) {
+ struct sge_qset *qs =
+ &adapter->sge.qs[t.qset_idx];
+
+ q->coalesce_usecs = t.intr_lat;
+ t3_update_qset_coalesce(qs, q);
+ }
+ if (t.polling >= 0) {
+ if (adapter->flags & USING_MSIX)
+ q->polling = t.polling;
+ else {
+ /* No polling with INTx for T3A */
+ if (adapter->params.rev == 0 &&
+ !(adapter->flags & USING_MSI))
+ t.polling = 0;
+
+ for (i = 0; i < SGE_QSETS; i++) {
+ q = &adapter->params.sge.
+ qset[i];
+ q->polling = t.polling;
+ }
+ }
+ }
+ break;
+ }
+ case CHELSIO_GET_QSET_PARAMS:{
+ struct qset_params *q;
+ struct ch_qset_params t;
+
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+ if (t.qset_idx >= SGE_QSETS)
+ return -EINVAL;
+
+ q = &adapter->params.sge.qset[t.qset_idx];
+ t.rspq_size = q->rspq_size;
+ t.txq_size[0] = q->txq_size[0];
+ t.txq_size[1] = q->txq_size[1];
+ t.txq_size[2] = q->txq_size[2];
+ t.fl_size[0] = q->fl_size;
+ t.fl_size[1] = q->jumbo_size;
+ t.polling = q->polling;
+ t.intr_lat = q->coalesce_usecs;
+ t.cong_thres = q->cong_thres;
+
+ if (copy_to_user(useraddr, &t, sizeof(t)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_SET_QSET_NUM:{
+ struct ch_reg edata;
+ struct port_info *pi = netdev_priv(dev);
+ unsigned int i, first_qset = 0, other_qsets = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (adapter->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if (edata.val < 1 ||
+ (edata.val > 1 && !(adapter->flags & USING_MSIX)))
+ return -EINVAL;
+
+ for_each_port(adapter, i)
+ if (adapter->port[i] && adapter->port[i] != dev)
+ other_qsets += adap2pinfo(adapter, i)->nqsets;
+
+ if (edata.val + other_qsets > SGE_QSETS)
+ return -EINVAL;
+
+ pi->nqsets = edata.val;
+
+ for_each_port(adapter, i)
+ if (adapter->port[i]) {
+ pi = adap2pinfo(adapter, i);
+ pi->first_qset = first_qset;
+ first_qset += pi->nqsets;
+ }
+ break;
+ }
+ case CHELSIO_GET_QSET_NUM:{
+ struct ch_reg edata;
+ struct port_info *pi = netdev_priv(dev);
+
+ edata.cmd = CHELSIO_GET_QSET_NUM;
+ edata.val = pi->nqsets;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_LOAD_FW:{
+ u8 *fw_data;
+ struct ch_mem_range t;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+
+ fw_data = kmalloc(t.len, GFP_KERNEL);
+ if (!fw_data)
+ return -ENOMEM;
+
+ if (copy_from_user
+ (fw_data, useraddr + sizeof(t), t.len)) {
+ kfree(fw_data);
+ return -EFAULT;
+ }
+
+ ret = t3_load_fw(adapter, fw_data, t.len);
+ kfree(fw_data);
+ if (ret)
+ return ret;
+ break;
+ }
+ case CHELSIO_SETMTUTAB:{
+ struct ch_mtus m;
+ int i;
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (offload_running(adapter))
+ return -EBUSY;
+ if (copy_from_user(&m, useraddr, sizeof(m)))
+ return -EFAULT;
+ if (m.nmtus != NMTUS)
+ return -EINVAL;
+ if (m.mtus[0] < 81) /* accommodate SACK */
+ return -EINVAL;
+
+ /* MTUs must be in ascending order */
+ for (i = 1; i < NMTUS; ++i)
+ if (m.mtus[i] < m.mtus[i - 1])
+ return -EINVAL;
+
+ memcpy(adapter->params.mtus, m.mtus,
+ sizeof(adapter->params.mtus));
+ break;
+ }
+ case CHELSIO_GET_PM:{
+ struct tp_params *p = &adapter->params.tp;
+ struct ch_pm m = {.cmd = CHELSIO_GET_PM };
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ m.tx_pg_sz = p->tx_pg_size;
+ m.tx_num_pg = p->tx_num_pgs;
+ m.rx_pg_sz = p->rx_pg_size;
+ m.rx_num_pg = p->rx_num_pgs;
+ m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
+ if (copy_to_user(useraddr, &m, sizeof(m)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_SET_PM:{
+ struct ch_pm m;
+ struct tp_params *p = &adapter->params.tp;
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (adapter->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (copy_from_user(&m, useraddr, sizeof(m)))
+ return -EFAULT;
+ if (!m.rx_pg_sz || (m.rx_pg_sz & (m.rx_pg_sz - 1)) ||
+ !m.tx_pg_sz || (m.tx_pg_sz & (m.tx_pg_sz - 1)))
+ return -EINVAL; /* not power of 2 */
+ if (!(m.rx_pg_sz & 0x14000))
+ return -EINVAL; /* not 16KB or 64KB */
+ if (!(m.tx_pg_sz & 0x1554000))
+ return -EINVAL;
+ if (m.tx_num_pg == -1)
+ m.tx_num_pg = p->tx_num_pgs;
+ if (m.rx_num_pg == -1)
+ m.rx_num_pg = p->rx_num_pgs;
+ if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
+ return -EINVAL;
+ if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
+ m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
+ return -EINVAL;
+ p->rx_pg_size = m.rx_pg_sz;
+ p->tx_pg_size = m.tx_pg_sz;
+ p->rx_num_pgs = m.rx_num_pg;
+ p->tx_num_pgs = m.tx_num_pg;
+ break;
+ }
+ case CHELSIO_GET_MEM:{
+ struct ch_mem_range t;
+ struct mc7 *mem;
+ u64 buf[32];
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ if (!(adapter->flags & FULL_INIT_DONE))
+ return -EIO; /* need the memory controllers */
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+ if ((t.addr & 7) || (t.len & 7))
+ return -EINVAL;
+ if (t.mem_id == MEM_CM)
+ mem = &adapter->cm;
+ else if (t.mem_id == MEM_PMRX)
+ mem = &adapter->pmrx;
+ else if (t.mem_id == MEM_PMTX)
+ mem = &adapter->pmtx;
+ else
+ return -EINVAL;
+
+ /*
+ * Version scheme:
+ * bits 0..9: chip version
+ * bits 10..15: chip revision
+ */
+ t.version = 3 | (adapter->params.rev << 10);
+ if (copy_to_user(useraddr, &t, sizeof(t)))
+ return -EFAULT;
+
+ /*
+ * Read 256 bytes at a time as len can be large and we don't
+ * want to use huge intermediate buffers.
+ */
+ useraddr += sizeof(t); /* advance to start of buffer */
+ while (t.len) {
+ unsigned int chunk =
+ min_t(unsigned int, t.len, sizeof(buf));
+
+ ret =
+ t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
+ buf);
+ if (ret)
+ return ret;
+ if (copy_to_user(useraddr, buf, chunk))
+ return -EFAULT;
+ useraddr += chunk;
+ t.addr += chunk;
+ t.len -= chunk;
+ }
+ break;
+ }
+ case CHELSIO_SET_TRACE_FILTER:{
+ struct ch_trace t;
+ const struct trace_params *tp;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (!offload_running(adapter))
+ return -EAGAIN;
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+
+ tp = (const struct trace_params *)&t.sip;
+ if (t.config_tx)
+ t3_config_trace_filter(adapter, tp, 0,
+ t.invert_match,
+ t.trace_tx);
+ if (t.config_rx)
+ t3_config_trace_filter(adapter, tp, 1,
+ t.invert_match,
+ t.trace_rx);
+ break;
+ }
+ case CHELSIO_SET_PKTSCHED:{
+ struct ch_pktsched_params p;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (!adapter->open_device_map)
+ return -EAGAIN; /* uP and SGE must be running */
+ if (copy_from_user(&p, useraddr, sizeof(p)))
+ return -EFAULT;
+ send_pktsched_cmd(adapter, p.sched, p.idx, p.min, p.max,
+ p.binding);
+ break;
+
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int ret, mmd;
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct mii_ioctl_data *data = if_mii(req);
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ data->phy_id = pi->phy.addr;
+ /* FALLTHRU */
+ case SIOCGMIIREG:{
+ u32 val;
+ struct cphy *phy = &pi->phy;
+
+ if (!phy->mdio_read)
+ return -EOPNOTSUPP;
+ if (is_10G(adapter)) {
+ mmd = data->phy_id >> 8;
+ if (!mmd)
+ mmd = MDIO_DEV_PCS;
+ else if (mmd > MDIO_DEV_XGXS)
+ return -EINVAL;
+
+ ret =
+ phy->mdio_read(adapter, data->phy_id & 0x1f,
+ mmd, data->reg_num, &val);
+ } else
+ ret =
+ phy->mdio_read(adapter, data->phy_id & 0x1f,
+ 0, data->reg_num & 0x1f,
+ &val);
+ if (!ret)
+ data->val_out = val;
+ break;
+ }
+ case SIOCSMIIREG:{
+ struct cphy *phy = &pi->phy;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (!phy->mdio_write)
+ return -EOPNOTSUPP;
+ if (is_10G(adapter)) {
+ mmd = data->phy_id >> 8;
+ if (!mmd)
+ mmd = MDIO_DEV_PCS;
+ else if (mmd > MDIO_DEV_XGXS)
+ return -EINVAL;
+
+ ret =
+ phy->mdio_write(adapter,
+ data->phy_id & 0x1f, mmd,
+ data->reg_num,
+ data->val_in);
+ } else
+ ret =
+ phy->mdio_write(adapter,
+ data->phy_id & 0x1f, 0,
+ data->reg_num & 0x1f,
+ data->val_in);
+ break;
+ }
+ case SIOCCHIOCTL:
+ return cxgb_extension_ioctl(dev, req->ifr_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
+{
+ int ret;
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+
+ if (new_mtu < 81) /* accommodate SACK */
+ return -EINVAL;
+ if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
+ return ret;
+ dev->mtu = new_mtu;
+ init_port_mtus(adapter);
+ if (adapter->params.rev == 0 && offload_running(adapter))
+ t3_load_mtus(adapter, adapter->params.mtus,
+ adapter->params.a_wnd, adapter->params.b_wnd,
+ adapter->port[0]->mtu);
+ return 0;
+}
+
+static int cxgb_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ t3_mac_set_address(&pi->mac, 0, dev->dev_addr);
+ if (offload_running(adapter))
+ write_smt_entry(adapter, pi->port_id);
+ return 0;
+}
+
+/**
+ * t3_synchronize_rx - wait for current Rx processing on a port to complete
+ * @adap: the adapter
+ * @p: the port
+ *
+ * Ensures that current Rx processing on any of the queues associated with
+ * the given port completes before returning. We do this by acquiring and
+ * releasing the locks of the response queues associated with the port.
+ */
+static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
+{
+ int i;
+
+ for (i = 0; i < p->nqsets; i++) {
+ struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq;
+
+ spin_lock_irq(&q->lock);
+ spin_unlock_irq(&q->lock);
+ }
+}
+
+static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+
+ pi->vlan_grp = grp;
+ if (adapter->params.rev > 0)
+ t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL);
+ else {
+ /* single control for all ports */
+ unsigned int i, have_vlans = 0;
+ for_each_port(adapter, i)
+ have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL;
+
+ t3_set_vlan_accel(adapter, 1, have_vlans);
+ }
+ t3_synchronize_rx(adapter, pi);
+}
+
+static void vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+ /* nothing */
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void cxgb_netpoll(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+
+ t3_intr_handler(adapter, qs->rspq.polling) (adapter->pdev->irq,
+ adapter);
+}
+#endif
+
+/*
+ * Periodic accumulation of MAC statistics.
+ */
+static void mac_stats_update(struct adapter *adapter)
+{
+ int i;
+
+ for_each_port(adapter, i) {
+ struct net_device *dev = adapter->port[i];
+ struct port_info *p = netdev_priv(dev);
+
+ if (netif_running(dev)) {
+ spin_lock(&adapter->stats_lock);
+ t3_mac_update_stats(&p->mac);
+ spin_unlock(&adapter->stats_lock);
+ }
+ }
+}
+
+static void check_link_status(struct adapter *adapter)
+{
+ int i;
+
+ for_each_port(adapter, i) {
+ struct net_device *dev = adapter->port[i];
+ struct port_info *p = netdev_priv(dev);
+
+ if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev))
+ t3_link_changed(adapter, i);
+ }
+}
+
+static void t3_adap_check_task(struct work_struct *work)
+{
+ struct adapter *adapter = container_of(work, struct adapter,
+ adap_check_task.work);
+ const struct adapter_params *p = &adapter->params;
+
+ adapter->check_task_cnt++;
+
+ /* Check link status for PHYs without interrupts */
+ if (p->linkpoll_period)
+ check_link_status(adapter);
+
+ /* Accumulate MAC stats if needed */
+ if (!p->linkpoll_period ||
+ (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
+ p->stats_update_period) {
+ mac_stats_update(adapter);
+ adapter->check_task_cnt = 0;
+ }
+
+ /* Schedule the next check update if any port is active. */
+ spin_lock(&adapter->work_lock);
+ if (adapter->open_device_map & PORT_MASK)
+ schedule_chk_task(adapter);
+ spin_unlock(&adapter->work_lock);
+}
+
+/*
+ * Processes external (PHY) interrupts in process context.
+ */
+static void ext_intr_task(struct work_struct *work)
+{
+ struct adapter *adapter = container_of(work, struct adapter,
+ ext_intr_handler_task);
+
+ t3_phy_intr_handler(adapter);
+
+ /* Now reenable external interrupts */
+ spin_lock_irq(&adapter->work_lock);
+ if (adapter->slow_intr_mask) {
+ adapter->slow_intr_mask |= F_T3DBG;
+ t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
+ t3_write_reg(adapter, A_PL_INT_ENABLE0,
+ adapter->slow_intr_mask);
+ }
+ spin_unlock_irq(&adapter->work_lock);
+}
+
+/*
+ * Interrupt-context handler for external (PHY) interrupts.
+ */
+void t3_os_ext_intr_handler(struct adapter *adapter)
+{
+ /*
+ * Schedule a task to handle external interrupts as they may be slow
+ * and we use a mutex to protect MDIO registers. We disable PHY
+ * interrupts in the meantime and let the task reenable them when
+ * it's done.
+ */
+ spin_lock(&adapter->work_lock);
+ if (adapter->slow_intr_mask) {
+ adapter->slow_intr_mask &= ~F_T3DBG;
+ t3_write_reg(adapter, A_PL_INT_ENABLE0,
+ adapter->slow_intr_mask);
+ queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
+ }
+ spin_unlock(&adapter->work_lock);
+}
+
+void t3_fatal_err(struct adapter *adapter)
+{
+ unsigned int fw_status[4];
+
+ if (adapter->flags & FULL_INIT_DONE) {
+ t3_sge_stop(adapter);
+ t3_intr_disable(adapter);
+ }
+ CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
+ if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
+ CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
+ fw_status[0], fw_status[1],
+ fw_status[2], fw_status[3]);
+
+}
+
+static int __devinit cxgb_enable_msix(struct adapter *adap)
+{
+ struct msix_entry entries[SGE_QSETS + 1];
+ int i, err;
+
+ for (i = 0; i < ARRAY_SIZE(entries); ++i)
+ entries[i].entry = i;
+
+ err = pci_enable_msix(adap->pdev, entries, ARRAY_SIZE(entries));
+ if (!err) {
+ for (i = 0; i < ARRAY_SIZE(entries); ++i)
+ adap->msix_info[i].vec = entries[i].vector;
+ } else if (err > 0)
+ dev_info(&adap->pdev->dev,
+ "only %d MSI-X vectors left, not using MSI-X\n", err);
+ return err;
+}
+
+static void __devinit print_port_info(struct adapter *adap,
+ const struct adapter_info *ai)
+{
+ static const char *pci_variant[] = {
+ "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
+ };
+
+ int i;
+ char buf[80];
+
+ if (is_pcie(adap))
+ snprintf(buf, sizeof(buf), "%s x%d",
+ pci_variant[adap->params.pci.variant],
+ adap->params.pci.width);
+ else
+ snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
+ pci_variant[adap->params.pci.variant],
+ adap->params.pci.speed, adap->params.pci.width);
+
+ for_each_port(adap, i) {
+ struct net_device *dev = adap->port[i];
+ const struct port_info *pi = netdev_priv(dev);
+
+ if (!test_bit(i, &adap->registered_device_map))
+ continue;
+ printk(KERN_INFO "%s: %s %s RNIC (rev %d) %s%s\n",
+ dev->name, ai->desc, pi->port_type->desc,
+ adap->params.rev, buf,
+ (adap->flags & USING_MSIX) ? " MSI-X" :
+ (adap->flags & USING_MSI) ? " MSI" : "");
+ if (adap->name == dev->name && adap->params.vpd.mclk)
+ printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n",
+ adap->name, t3_mc7_size(&adap->cm) >> 20,
+ t3_mc7_size(&adap->pmtx) >> 20,
+ t3_mc7_size(&adap->pmrx) >> 20);
+ }
+}
+
+static int __devinit init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int version_printed;
+
+ int i, err, pci_using_dac = 0;
+ unsigned long mmio_start, mmio_len;
+ const struct adapter_info *ai;
+ struct adapter *adapter = NULL;
+ struct port_info *pi;
+
+ if (!version_printed) {
+ printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
+ ++version_printed;
+ }
+
+ if (!cxgb3_wq) {
+ cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
+ if (!cxgb3_wq) {
+ printk(KERN_ERR DRV_NAME
+ ": cannot initialize work queue\n");
+ return -ENOMEM;
+ }
+ }
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err) {
+ /* Just info, some other driver may have claimed the device. */
+ dev_info(&pdev->dev, "cannot obtain PCI resources\n");
+ return err;
+ }
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "cannot enable PCI device\n");
+ goto out_release_regions;
+ }
+
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ pci_using_dac = 1;
+ err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (err) {
+ dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
+ "coherent allocations\n");
+ goto out_disable_device;
+ }
+ } else if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
+ goto out_disable_device;
+ }
+
+ pci_set_master(pdev);
+
+ mmio_start = pci_resource_start(pdev, 0);
+ mmio_len = pci_resource_len(pdev, 0);
+ ai = t3_get_adapter_info(ent->driver_data);
+
+ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ if (!adapter) {
+ err = -ENOMEM;
+ goto out_disable_device;
+ }
+
+ adapter->regs = ioremap_nocache(mmio_start, mmio_len);
+ if (!adapter->regs) {
+ dev_err(&pdev->dev, "cannot map device registers\n");
+ err = -ENOMEM;
+ goto out_free_adapter;
+ }
+
+ adapter->pdev = pdev;
+ adapter->name = pci_name(pdev);
+ adapter->msg_enable = dflt_msg_enable;
+ adapter->mmio_len = mmio_len;
+
+ mutex_init(&adapter->mdio_lock);
+ spin_lock_init(&adapter->work_lock);
+ spin_lock_init(&adapter->stats_lock);
+
+ INIT_LIST_HEAD(&adapter->adapter_list);
+ INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
+ INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
+
+ for (i = 0; i < ai->nports; ++i) {
+ struct net_device *netdev;
+
+ netdev = alloc_etherdev(sizeof(struct port_info));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto out_free_dev;
+ }
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ adapter->port[i] = netdev;
+ pi = netdev_priv(netdev);
+ pi->rx_csum_offload = 1;
+ pi->nqsets = 1;
+ pi->first_qset = i;
+ pi->activity = 0;
+ pi->port_id = i;
+ netif_carrier_off(netdev);
+ netdev->irq = pdev->irq;
+ netdev->mem_start = mmio_start;
+ netdev->mem_end = mmio_start + mmio_len - 1;
+ netdev->priv = adapter;
+ netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
+ netdev->features |= NETIF_F_LLTX;
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ netdev->vlan_rx_register = vlan_rx_register;
+ netdev->vlan_rx_kill_vid = vlan_rx_kill_vid;
+
+ netdev->open = cxgb_open;
+ netdev->stop = cxgb_close;
+ netdev->hard_start_xmit = t3_eth_xmit;
+ netdev->get_stats = cxgb_get_stats;
+ netdev->set_multicast_list = cxgb_set_rxmode;
+ netdev->do_ioctl = cxgb_ioctl;
+ netdev->change_mtu = cxgb_change_mtu;
+ netdev->set_mac_address = cxgb_set_mac_addr;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = cxgb_netpoll;
+#endif
+ netdev->weight = 64;
+
+ SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
+ }
+
+ pci_set_drvdata(pdev, adapter->port[0]);
+ if (t3_prep_adapter(adapter, ai, 1) < 0) {
+ err = -ENODEV;
+ goto out_free_dev;
+ }
+
+ /*
+ * The card is now ready to go. If any errors occur during device
+ * registration we do not fail the whole card but rather proceed only
+ * with the ports we manage to register successfully. However we must
+ * register at least one net device.
+ */
+ for_each_port(adapter, i) {
+ err = register_netdev(adapter->port[i]);
+ if (err)
+ dev_warn(&pdev->dev,
+ "cannot register net device %s, skipping\n",
+ adapter->port[i]->name);
+ else {
+ /*
+ * Change the name we use for messages to the name of
+ * the first successfully registered interface.
+ */
+ if (!adapter->registered_device_map)
+ adapter->name = adapter->port[i]->name;
+
+ __set_bit(i, &adapter->registered_device_map);
+ }
+ }
+ if (!adapter->registered_device_map) {
+ dev_err(&pdev->dev, "could not register any net devices\n");
+ goto out_free_dev;
+ }
+
+ /* Driver's ready. Reflect it on LEDs */
+ t3_led_ready(adapter);
+
+ if (is_offload(adapter)) {
+ __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
+ cxgb3_adapter_ofld(adapter);
+ }
+
+ /* See what interrupts we'll be using */
+ if (msi > 1 && cxgb_enable_msix(adapter) == 0)
+ adapter->flags |= USING_MSIX;
+ else if (msi > 0 && pci_enable_msi(pdev) == 0)
+ adapter->flags |= USING_MSI;
+
+ err = sysfs_create_group(&adapter->port[0]->dev.kobj,
+ &cxgb3_attr_group);
+
+ print_port_info(adapter, ai);
+ return 0;
+
+out_free_dev:
+ iounmap(adapter->regs);
+ for (i = ai->nports - 1; i >= 0; --i)
+ if (adapter->port[i])
+ free_netdev(adapter->port[i]);
+
+out_free_adapter:
+ kfree(adapter);
+
+out_disable_device:
+ pci_disable_device(pdev);
+out_release_regions:
+ pci_release_regions(pdev);
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void __devexit remove_one(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ if (dev) {
+ int i;
+ struct adapter *adapter = dev->priv;
+
+ t3_sge_stop(adapter);
+ sysfs_remove_group(&adapter->port[0]->dev.kobj,
+ &cxgb3_attr_group);
+
+ for_each_port(adapter, i)
+ if (test_bit(i, &adapter->registered_device_map))
+ unregister_netdev(adapter->port[i]);
+
+ if (is_offload(adapter)) {
+ cxgb3_adapter_unofld(adapter);
+ if (test_bit(OFFLOAD_DEVMAP_BIT,
+ &adapter->open_device_map))
+ offload_close(&adapter->tdev);
+ }
+
+ t3_free_sge_resources(adapter);
+ cxgb_disable_msi(adapter);
+
+ for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++)
+ if (adapter->dummy_netdev[i]) {
+ free_netdev(adapter->dummy_netdev[i]);
+ adapter->dummy_netdev[i] = NULL;
+ }
+
+ for_each_port(adapter, i)
+ if (adapter->port[i])
+ free_netdev(adapter->port[i]);
+
+ iounmap(adapter->regs);
+ kfree(adapter);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ }
+}
+
+static struct pci_driver driver = {
+ .name = DRV_NAME,
+ .id_table = cxgb3_pci_tbl,
+ .probe = init_one,
+ .remove = __devexit_p(remove_one),
+};
+
+static int __init cxgb3_init_module(void)
+{
+ int ret;
+
+ cxgb3_offload_init();
+
+ ret = pci_register_driver(&driver);
+ return ret;
+}
+
+static void __exit cxgb3_cleanup_module(void)
+{
+ pci_unregister_driver(&driver);
+ if (cxgb3_wq)
+ destroy_workqueue(cxgb3_wq);
+}
+
+module_init(cxgb3_init_module);
+module_exit(cxgb3_cleanup_module);
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
new file mode 100644
index 00000000000..c6b72664318
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -0,0 +1,1222 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/list.h>
+#include <net/neighbour.h>
+#include <linux/notifier.h>
+#include <asm/atomic.h>
+#include <linux/proc_fs.h>
+#include <linux/if_vlan.h>
+#include <net/netevent.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+
+#include "common.h"
+#include "regs.h"
+#include "cxgb3_ioctl.h"
+#include "cxgb3_ctl_defs.h"
+#include "cxgb3_defs.h"
+#include "l2t.h"
+#include "firmware_exports.h"
+#include "cxgb3_offload.h"
+
+static LIST_HEAD(client_list);
+static LIST_HEAD(ofld_dev_list);
+static DEFINE_MUTEX(cxgb3_db_lock);
+
+static DEFINE_RWLOCK(adapter_list_lock);
+static LIST_HEAD(adapter_list);
+
+static const unsigned int MAX_ATIDS = 64 * 1024;
+static const unsigned int ATID_BASE = 0x100000;
+
+static inline int offload_activated(struct t3cdev *tdev)
+{
+ const struct adapter *adapter = tdev2adap(tdev);
+
+ return (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map));
+}
+
+/**
+ * cxgb3_register_client - register an offload client
+ * @client: the client
+ *
+ * Add the client to the client list,
+ * and call backs the client for each activated offload device
+ */
+void cxgb3_register_client(struct cxgb3_client *client)
+{
+ struct t3cdev *tdev;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_add_tail(&client->client_list, &client_list);
+
+ if (client->add) {
+ list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
+ if (offload_activated(tdev))
+ client->add(tdev);
+ }
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_register_client);
+
+/**
+ * cxgb3_unregister_client - unregister an offload client
+ * @client: the client
+ *
+ * Remove the client to the client list,
+ * and call backs the client for each activated offload device.
+ */
+void cxgb3_unregister_client(struct cxgb3_client *client)
+{
+ struct t3cdev *tdev;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_del(&client->client_list);
+
+ if (client->remove) {
+ list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
+ if (offload_activated(tdev))
+ client->remove(tdev);
+ }
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_unregister_client);
+
+/**
+ * cxgb3_add_clients - activate registered clients for an offload device
+ * @tdev: the offload device
+ *
+ * Call backs all registered clients once a offload device is activated
+ */
+void cxgb3_add_clients(struct t3cdev *tdev)
+{
+ struct cxgb3_client *client;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_for_each_entry(client, &client_list, client_list) {
+ if (client->add)
+ client->add(tdev);
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+/**
+ * cxgb3_remove_clients - deactivates registered clients
+ * for an offload device
+ * @tdev: the offload device
+ *
+ * Call backs all registered clients once a offload device is deactivated
+ */
+void cxgb3_remove_clients(struct t3cdev *tdev)
+{
+ struct cxgb3_client *client;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_for_each_entry(client, &client_list, client_list) {
+ if (client->remove)
+ client->remove(tdev);
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+static struct net_device *get_iff_from_mac(struct adapter *adapter,
+ const unsigned char *mac,
+ unsigned int vlan)
+{
+ int i;
+
+ for_each_port(adapter, i) {
+ const struct vlan_group *grp;
+ struct net_device *dev = adapter->port[i];
+ const struct port_info *p = netdev_priv(dev);
+
+ if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
+ if (vlan && vlan != VLAN_VID_MASK) {
+ grp = p->vlan_grp;
+ dev = grp ? grp->vlan_devices[vlan] : NULL;
+ } else
+ while (dev->master)
+ dev = dev->master;
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
+ void *data)
+{
+ int ret = 0;
+ struct ulp_iscsi_info *uiip = data;
+
+ switch (req) {
+ case ULP_ISCSI_GET_PARAMS:
+ uiip->pdev = adapter->pdev;
+ uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT);
+ uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT);
+ uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK);
+ /*
+ * On tx, the iscsi pdu has to be <= tx page size and has to
+ * fit into the Tx PM FIFO.
+ */
+ uiip->max_txsz = min(adapter->params.tp.tx_pg_size,
+ t3_read_reg(adapter, A_PM1_TX_CFG) >> 17);
+ /* on rx, the iscsi pdu has to be < rx page size and the
+ whole pdu + cpl headers has to fit into one sge buffer */
+ uiip->max_rxsz = min_t(unsigned int,
+ adapter->params.tp.rx_pg_size,
+ (adapter->sge.qs[0].fl[1].buf_size -
+ sizeof(struct cpl_rx_data) * 2 -
+ sizeof(struct cpl_rx_data_ddp)));
+ break;
+ case ULP_ISCSI_SET_PARAMS:
+ t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+/* Response queue used for RDMA events. */
+#define ASYNC_NOTIF_RSPQ 0
+
+static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
+{
+ int ret = 0;
+
+ switch (req) {
+ case RDMA_GET_PARAMS:{
+ struct rdma_info *req = data;
+ struct pci_dev *pdev = adapter->pdev;
+
+ req->udbell_physbase = pci_resource_start(pdev, 2);
+ req->udbell_len = pci_resource_len(pdev, 2);
+ req->tpt_base =
+ t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT);
+ req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
+ req->pbl_base =
+ t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT);
+ req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
+ req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
+ req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
+ req->kdb_addr = adapter->regs + A_SG_KDOORBELL;
+ req->pdev = pdev;
+ break;
+ }
+ case RDMA_CQ_OP:{
+ unsigned long flags;
+ struct rdma_cq_op *req = data;
+
+ /* may be called in any context */
+ spin_lock_irqsave(&adapter->sge.reg_lock, flags);
+ ret = t3_sge_cqcntxt_op(adapter, req->id, req->op,
+ req->credits);
+ spin_unlock_irqrestore(&adapter->sge.reg_lock, flags);
+ break;
+ }
+ case RDMA_GET_MEM:{
+ struct ch_mem_range *t = data;
+ struct mc7 *mem;
+
+ if ((t->addr & 7) || (t->len & 7))
+ return -EINVAL;
+ if (t->mem_id == MEM_CM)
+ mem = &adapter->cm;
+ else if (t->mem_id == MEM_PMRX)
+ mem = &adapter->pmrx;
+ else if (t->mem_id == MEM_PMTX)
+ mem = &adapter->pmtx;
+ else
+ return -EINVAL;
+
+ ret =
+ t3_mc7_bd_read(mem, t->addr / 8, t->len / 8,
+ (u64 *) t->buf);
+ if (ret)
+ return ret;
+ break;
+ }
+ case RDMA_CQ_SETUP:{
+ struct rdma_cq_setup *req = data;
+
+ spin_lock_irq(&adapter->sge.reg_lock);
+ ret =
+ t3_sge_init_cqcntxt(adapter, req->id,
+ req->base_addr, req->size,
+ ASYNC_NOTIF_RSPQ,
+ req->ovfl_mode, req->credits,
+ req->credit_thres);
+ spin_unlock_irq(&adapter->sge.reg_lock);
+ break;
+ }
+ case RDMA_CQ_DISABLE:
+ spin_lock_irq(&adapter->sge.reg_lock);
+ ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data);
+ spin_unlock_irq(&adapter->sge.reg_lock);
+ break;
+ case RDMA_CTRL_QP_SETUP:{
+ struct rdma_ctrlqp_setup *req = data;
+
+ spin_lock_irq(&adapter->sge.reg_lock);
+ ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0,
+ SGE_CNTXT_RDMA,
+ ASYNC_NOTIF_RSPQ,
+ req->base_addr, req->size,
+ FW_RI_TID_START, 1, 0);
+ spin_unlock_irq(&adapter->sge.reg_lock);
+ break;
+ }
+ default:
+ ret = -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
+{
+ struct adapter *adapter = tdev2adap(tdev);
+ struct tid_range *tid;
+ struct mtutab *mtup;
+ struct iff_mac *iffmacp;
+ struct ddp_params *ddpp;
+ struct adap_ports *ports;
+ int i;
+
+ switch (req) {
+ case GET_MAX_OUTSTANDING_WR:
+ *(unsigned int *)data = FW_WR_NUM;
+ break;
+ case GET_WR_LEN:
+ *(unsigned int *)data = WR_FLITS;
+ break;
+ case GET_TX_MAX_CHUNK:
+ *(unsigned int *)data = 1 << 20; /* 1MB */
+ break;
+ case GET_TID_RANGE:
+ tid = data;
+ tid->num = t3_mc5_size(&adapter->mc5) -
+ adapter->params.mc5.nroutes -
+ adapter->params.mc5.nfilters - adapter->params.mc5.nservers;
+ tid->base = 0;
+ break;
+ case GET_STID_RANGE:
+ tid = data;
+ tid->num = adapter->params.mc5.nservers;
+ tid->base = t3_mc5_size(&adapter->mc5) - tid->num -
+ adapter->params.mc5.nfilters - adapter->params.mc5.nroutes;
+ break;
+ case GET_L2T_CAPACITY:
+ *(unsigned int *)data = 2048;
+ break;
+ case GET_MTUS:
+ mtup = data;
+ mtup->size = NMTUS;
+ mtup->mtus = adapter->params.mtus;
+ break;
+ case GET_IFF_FROM_MAC:
+ iffmacp = data;
+ iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr,
+ iffmacp->vlan_tag &
+ VLAN_VID_MASK);
+ break;
+ case GET_DDP_PARAMS:
+ ddpp = data;
+ ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT);
+ ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT);
+ ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK);
+ break;
+ case GET_PORTS:
+ ports = data;
+ ports->nports = adapter->params.nports;
+ for_each_port(adapter, i)
+ ports->lldevs[i] = adapter->port[i];
+ break;
+ case ULP_ISCSI_GET_PARAMS:
+ case ULP_ISCSI_SET_PARAMS:
+ if (!offload_running(adapter))
+ return -EAGAIN;
+ return cxgb_ulp_iscsi_ctl(adapter, req, data);
+ case RDMA_GET_PARAMS:
+ case RDMA_CQ_OP:
+ case RDMA_CQ_SETUP:
+ case RDMA_CQ_DISABLE:
+ case RDMA_CTRL_QP_SETUP:
+ case RDMA_GET_MEM:
+ if (!offload_running(adapter))
+ return -EAGAIN;
+ return cxgb_rdma_ctl(adapter, req, data);
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+/*
+ * Dummy handler for Rx offload packets in case we get an offload packet before
+ * proper processing is setup. This complains and drops the packet as it isn't
+ * normal to get offload packets at this stage.
+ */
+static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs,
+ int n)
+{
+ CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n",
+ n, ntohl(*(__be32 *)skbs[0]->data));
+ while (n--)
+ dev_kfree_skb_any(skbs[n]);
+ return 0;
+}
+
+static void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh)
+{
+}
+
+void cxgb3_set_dummy_ops(struct t3cdev *dev)
+{
+ dev->recv = rx_offload_blackhole;
+ dev->neigh_update = dummy_neigh_update;
+}
+
+/*
+ * Free an active-open TID.
+ */
+void *cxgb3_free_atid(struct t3cdev *tdev, int atid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+ union active_open_entry *p = atid2entry(t, atid);
+ void *ctx = p->t3c_tid.ctx;
+
+ spin_lock_bh(&t->atid_lock);
+ p->next = t->afree;
+ t->afree = p;
+ t->atids_in_use--;
+ spin_unlock_bh(&t->atid_lock);
+
+ return ctx;
+}
+
+EXPORT_SYMBOL(cxgb3_free_atid);
+
+/*
+ * Free a server TID and return it to the free pool.
+ */
+void cxgb3_free_stid(struct t3cdev *tdev, int stid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+ union listen_entry *p = stid2entry(t, stid);
+
+ spin_lock_bh(&t->stid_lock);
+ p->next = t->sfree;
+ t->sfree = p;
+ t->stids_in_use--;
+ spin_unlock_bh(&t->stid_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_free_stid);
+
+void cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client,
+ void *ctx, unsigned int tid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ t->tid_tab[tid].client = client;
+ t->tid_tab[tid].ctx = ctx;
+ atomic_inc(&t->tids_in_use);
+}
+
+EXPORT_SYMBOL(cxgb3_insert_tid);
+
+/*
+ * Populate a TID_RELEASE WR. The skb must be already propely sized.
+ */
+static inline void mk_tid_release(struct sk_buff *skb, unsigned int tid)
+{
+ struct cpl_tid_release *req;
+
+ skb->priority = CPL_PRIORITY_SETUP;
+ req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid));
+}
+
+static void t3_process_tid_release_list(struct work_struct *work)
+{
+ struct t3c_data *td = container_of(work, struct t3c_data,
+ tid_release_task);
+ struct sk_buff *skb;
+ struct t3cdev *tdev = td->dev;
+
+
+ spin_lock_bh(&td->tid_release_lock);
+ while (td->tid_release_list) {
+ struct t3c_tid_entry *p = td->tid_release_list;
+
+ td->tid_release_list = (struct t3c_tid_entry *)p->ctx;
+ spin_unlock_bh(&td->tid_release_lock);
+
+ skb = alloc_skb(sizeof(struct cpl_tid_release),
+ GFP_KERNEL | __GFP_NOFAIL);
+ mk_tid_release(skb, p - td->tid_maps.tid_tab);
+ cxgb3_ofld_send(tdev, skb);
+ p->ctx = NULL;
+ spin_lock_bh(&td->tid_release_lock);
+ }
+ spin_unlock_bh(&td->tid_release_lock);
+}
+
+/* use ctx as a next pointer in the tid release list */
+void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid)
+{
+ struct t3c_data *td = T3C_DATA(tdev);
+ struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid];
+
+ spin_lock_bh(&td->tid_release_lock);
+ p->ctx = (void *)td->tid_release_list;
+ td->tid_release_list = p;
+ if (!p->ctx)
+ schedule_work(&td->tid_release_task);
+ spin_unlock_bh(&td->tid_release_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_queue_tid_release);
+
+/*
+ * Remove a tid from the TID table. A client may defer processing its last
+ * CPL message if it is locked at the time it arrives, and while the message
+ * sits in the client's backlog the TID may be reused for another connection.
+ * To handle this we atomically switch the TID association if it still points
+ * to the original client context.
+ */
+void cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ BUG_ON(tid >= t->ntids);
+ if (tdev->type == T3A)
+ (void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL);
+ else {
+ struct sk_buff *skb;
+
+ skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC);
+ if (likely(skb)) {
+ mk_tid_release(skb, tid);
+ cxgb3_ofld_send(tdev, skb);
+ t->tid_tab[tid].ctx = NULL;
+ } else
+ cxgb3_queue_tid_release(tdev, tid);
+ }
+ atomic_dec(&t->tids_in_use);
+}
+
+EXPORT_SYMBOL(cxgb3_remove_tid);
+
+int cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client,
+ void *ctx)
+{
+ int atid = -1;
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ spin_lock_bh(&t->atid_lock);
+ if (t->afree) {
+ union active_open_entry *p = t->afree;
+
+ atid = (p - t->atid_tab) + t->atid_base;
+ t->afree = p->next;
+ p->t3c_tid.ctx = ctx;
+ p->t3c_tid.client = client;
+ t->atids_in_use++;
+ }
+ spin_unlock_bh(&t->atid_lock);
+ return atid;
+}
+
+EXPORT_SYMBOL(cxgb3_alloc_atid);
+
+int cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client,
+ void *ctx)
+{
+ int stid = -1;
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ spin_lock_bh(&t->stid_lock);
+ if (t->sfree) {
+ union listen_entry *p = t->sfree;
+
+ stid = (p - t->stid_tab) + t->stid_base;
+ t->sfree = p->next;
+ p->t3c_tid.ctx = ctx;
+ p->t3c_tid.client = client;
+ t->stids_in_use++;
+ }
+ spin_unlock_bh(&t->stid_lock);
+ return stid;
+}
+
+EXPORT_SYMBOL(cxgb3_alloc_stid);
+
+static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_smt_write_rpl *rpl = cplhdr(skb);
+
+ if (rpl->status != CPL_ERR_NONE)
+ printk(KERN_ERR
+ "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
+ rpl->status, GET_TID(rpl));
+
+ return CPL_RET_BUF_DONE;
+}
+
+static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_l2t_write_rpl *rpl = cplhdr(skb);
+
+ if (rpl->status != CPL_ERR_NONE)
+ printk(KERN_ERR
+ "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
+ rpl->status, GET_TID(rpl));
+
+ return CPL_RET_BUF_DONE;
+}
+
+static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_act_open_rpl *rpl = cplhdr(skb);
+ unsigned int atid = G_TID(ntohl(rpl->atid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+ if (t3c_tid->ctx && t3c_tid->client && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) {
+ return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb,
+ t3c_tid->
+ ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, CPL_ACT_OPEN_RPL);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ union opcode_tid *p = cplhdr(skb);
+ unsigned int stid = G_TID(ntohl(p->opcode_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[p->opcode]) {
+ return t3c_tid->client->handlers[p->opcode] (dev, skb,
+ t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, p->opcode);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ union opcode_tid *p = cplhdr(skb);
+ unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[p->opcode]) {
+ return t3c_tid->client->handlers[p->opcode]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, p->opcode);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_pass_accept_req *req = cplhdr(skb);
+ unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) {
+ return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, CPL_PASS_ACCEPT_REQ);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb)
+{
+ union opcode_tid *p = cplhdr(skb);
+ unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[p->opcode]) {
+ return t3c_tid->client->handlers[p->opcode]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ struct cpl_abort_req_rss *req = cplhdr(skb);
+ struct cpl_abort_rpl *rpl;
+
+ struct sk_buff *skb =
+ alloc_skb(sizeof(struct cpl_abort_rpl), GFP_ATOMIC);
+ if (!skb) {
+ printk("do_abort_req_rss: couldn't get skb!\n");
+ goto out;
+ }
+ skb->priority = CPL_PRIORITY_DATA;
+ __skb_put(skb, sizeof(struct cpl_abort_rpl));
+ rpl = cplhdr(skb);
+ rpl->wr.wr_hi =
+ htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
+ rpl->wr.wr_lo = htonl(V_WR_TID(GET_TID(req)));
+ OPCODE_TID(rpl) =
+ htonl(MK_OPCODE_TID(CPL_ABORT_RPL, GET_TID(req)));
+ rpl->cmd = req->status;
+ cxgb3_ofld_send(dev, skb);
+out:
+ return CPL_RET_BUF_DONE;
+ }
+}
+
+static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_act_establish *req = cplhdr(skb);
+ unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
+ return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, CPL_PASS_ACCEPT_REQ);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_set_tcb_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_set_tcb_rpl *rpl = cplhdr(skb);
+
+ if (rpl->status != CPL_ERR_NONE)
+ printk(KERN_ERR
+ "Unexpected SET_TCB_RPL status %u for tid %u\n",
+ rpl->status, GET_TID(rpl));
+ return CPL_RET_BUF_DONE;
+}
+
+static int do_trace(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_trace_pkt *p = cplhdr(skb);
+
+ skb->protocol = htons(0xffff);
+ skb->dev = dev->lldev;
+ skb_pull(skb, sizeof(*p));
+ skb->mac.raw = skb->data;
+ netif_receive_skb(skb);
+ return 0;
+}
+
+static int do_term(struct t3cdev *dev, struct sk_buff *skb)
+{
+ unsigned int hwtid = ntohl(skb->priority) >> 8 & 0xfffff;
+ unsigned int opcode = G_OPCODE(ntohl(skb->csum));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[opcode]) {
+ return t3c_tid->client->handlers[opcode] (dev, skb,
+ t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, opcode);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int nb_callback(struct notifier_block *self, unsigned long event,
+ void *ctx)
+{
+ switch (event) {
+ case (NETEVENT_NEIGH_UPDATE):{
+ cxgb_neigh_update((struct neighbour *)ctx);
+ break;
+ }
+ case (NETEVENT_PMTU_UPDATE):
+ break;
+ case (NETEVENT_REDIRECT):{
+ struct netevent_redirect *nr = ctx;
+ cxgb_redirect(nr->old, nr->new);
+ cxgb_neigh_update(nr->new->neighbour);
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block nb = {
+ .notifier_call = nb_callback
+};
+
+/*
+ * Process a received packet with an unknown/unexpected CPL opcode.
+ */
+static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name,
+ *skb->data);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+}
+
+/*
+ * Handlers for each CPL opcode
+ */
+static cpl_handler_func cpl_handlers[NUM_CPL_CMDS];
+
+/*
+ * Add a new handler to the CPL dispatch table. A NULL handler may be supplied
+ * to unregister an existing handler.
+ */
+void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h)
+{
+ if (opcode < NUM_CPL_CMDS)
+ cpl_handlers[opcode] = h ? h : do_bad_cpl;
+ else
+ printk(KERN_ERR "T3C: handler registration for "
+ "opcode %x failed\n", opcode);
+}
+
+EXPORT_SYMBOL(t3_register_cpl_handler);
+
+/*
+ * T3CDEV's receive method.
+ */
+int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n)
+{
+ while (n--) {
+ struct sk_buff *skb = *skbs++;
+ unsigned int opcode = G_OPCODE(ntohl(skb->csum));
+ int ret = cpl_handlers[opcode] (dev, skb);
+
+#if VALIDATE_TID
+ if (ret & CPL_RET_UNKNOWN_TID) {
+ union opcode_tid *p = cplhdr(skb);
+
+ printk(KERN_ERR "%s: CPL message (opcode %u) had "
+ "unknown TID %u\n", dev->name, opcode,
+ G_TID(ntohl(p->opcode_tid)));
+ }
+#endif
+ if (ret & CPL_RET_BUF_DONE)
+ kfree_skb(skb);
+ }
+ return 0;
+}
+
+/*
+ * Sends an sk_buff to a T3C driver after dealing with any active network taps.
+ */
+int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb)
+{
+ int r;
+
+ local_bh_disable();
+ r = dev->send(dev, skb);
+ local_bh_enable();
+ return r;
+}
+
+EXPORT_SYMBOL(cxgb3_ofld_send);
+
+static int is_offloading(struct net_device *dev)
+{
+ struct adapter *adapter;
+ int i;
+
+ read_lock_bh(&adapter_list_lock);
+ list_for_each_entry(adapter, &adapter_list, adapter_list) {
+ for_each_port(adapter, i) {
+ if (dev == adapter->port[i]) {
+ read_unlock_bh(&adapter_list_lock);
+ return 1;
+ }
+ }
+ }
+ read_unlock_bh(&adapter_list_lock);
+ return 0;
+}
+
+void cxgb_neigh_update(struct neighbour *neigh)
+{
+ struct net_device *dev = neigh->dev;
+
+ if (dev && (is_offloading(dev))) {
+ struct t3cdev *tdev = T3CDEV(dev);
+
+ BUG_ON(!tdev);
+ t3_l2t_update(tdev, neigh);
+ }
+}
+
+static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
+{
+ struct sk_buff *skb;
+ struct cpl_set_tcb_field *req;
+
+ skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_ERR "%s: cannot allocate skb!\n", __FUNCTION__);
+ return;
+ }
+ skb->priority = CPL_PRIORITY_CONTROL;
+ req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
+ req->reply = 0;
+ req->cpu_idx = 0;
+ req->word = htons(W_TCB_L2T_IX);
+ req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX));
+ req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx));
+ tdev->send(tdev, skb);
+}
+
+void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
+{
+ struct net_device *olddev, *newdev;
+ struct tid_info *ti;
+ struct t3cdev *tdev;
+ u32 tid;
+ int update_tcb;
+ struct l2t_entry *e;
+ struct t3c_tid_entry *te;
+
+ olddev = old->neighbour->dev;
+ newdev = new->neighbour->dev;
+ if (!is_offloading(olddev))
+ return;
+ if (!is_offloading(newdev)) {
+ printk(KERN_WARNING "%s: Redirect to non-offload"
+ "device ignored.\n", __FUNCTION__);
+ return;
+ }
+ tdev = T3CDEV(olddev);
+ BUG_ON(!tdev);
+ if (tdev != T3CDEV(newdev)) {
+ printk(KERN_WARNING "%s: Redirect to different "
+ "offload device ignored.\n", __FUNCTION__);
+ return;
+ }
+
+ /* Add new L2T entry */
+ e = t3_l2t_get(tdev, new->neighbour, newdev);
+ if (!e) {
+ printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
+ __FUNCTION__);
+ return;
+ }
+
+ /* Walk tid table and notify clients of dst change. */
+ ti = &(T3C_DATA(tdev))->tid_maps;
+ for (tid = 0; tid < ti->ntids; tid++) {
+ te = lookup_tid(ti, tid);
+ BUG_ON(!te);
+ if (te->ctx && te->client && te->client->redirect) {
+ update_tcb = te->client->redirect(te->ctx, old, new, e);
+ if (update_tcb) {
+ l2t_hold(L2DATA(tdev), e);
+ set_l2t_ix(tdev, tid, e);
+ }
+ }
+ }
+ l2t_release(L2DATA(tdev), e);
+}
+
+/*
+ * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc.
+ * The allocated memory is cleared.
+ */
+void *cxgb_alloc_mem(unsigned long size)
+{
+ void *p = kmalloc(size, GFP_KERNEL);
+
+ if (!p)
+ p = vmalloc(size);
+ if (p)
+ memset(p, 0, size);
+ return p;
+}
+
+/*
+ * Free memory allocated through t3_alloc_mem().
+ */
+void cxgb_free_mem(void *addr)
+{
+ unsigned long p = (unsigned long)addr;
+
+ if (p >= VMALLOC_START && p < VMALLOC_END)
+ vfree(addr);
+ else
+ kfree(addr);
+}
+
+/*
+ * Allocate and initialize the TID tables. Returns 0 on success.
+ */
+static int init_tid_tabs(struct tid_info *t, unsigned int ntids,
+ unsigned int natids, unsigned int nstids,
+ unsigned int atid_base, unsigned int stid_base)
+{
+ unsigned long size = ntids * sizeof(*t->tid_tab) +
+ natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab);
+
+ t->tid_tab = cxgb_alloc_mem(size);
+ if (!t->tid_tab)
+ return -ENOMEM;
+
+ t->stid_tab = (union listen_entry *)&t->tid_tab[ntids];
+ t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids];
+ t->ntids = ntids;
+ t->nstids = nstids;
+ t->stid_base = stid_base;
+ t->sfree = NULL;
+ t->natids = natids;
+ t->atid_base = atid_base;
+ t->afree = NULL;
+ t->stids_in_use = t->atids_in_use = 0;
+ atomic_set(&t->tids_in_use, 0);
+ spin_lock_init(&t->stid_lock);
+ spin_lock_init(&t->atid_lock);
+
+ /*
+ * Setup the free lists for stid_tab and atid_tab.
+ */
+ if (nstids) {
+ while (--nstids)
+ t->stid_tab[nstids - 1].next = &t->stid_tab[nstids];
+ t->sfree = t->stid_tab;
+ }
+ if (natids) {
+ while (--natids)
+ t->atid_tab[natids - 1].next = &t->atid_tab[natids];
+ t->afree = t->atid_tab;
+ }
+ return 0;
+}
+
+static void free_tid_maps(struct tid_info *t)
+{
+ cxgb_free_mem(t->tid_tab);
+}
+
+static inline void add_adapter(struct adapter *adap)
+{
+ write_lock_bh(&adapter_list_lock);
+ list_add_tail(&adap->adapter_list, &adapter_list);
+ write_unlock_bh(&adapter_list_lock);
+}
+
+static inline void remove_adapter(struct adapter *adap)
+{
+ write_lock_bh(&adapter_list_lock);
+ list_del(&adap->adapter_list);
+ write_unlock_bh(&adapter_list_lock);
+}
+
+int cxgb3_offload_activate(struct adapter *adapter)
+{
+ struct t3cdev *dev = &adapter->tdev;
+ int natids, err;
+ struct t3c_data *t;
+ struct tid_range stid_range, tid_range;
+ struct mtutab mtutab;
+ unsigned int l2t_capacity;
+
+ t = kcalloc(1, sizeof(*t), GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
+
+ err = -EOPNOTSUPP;
+ if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 ||
+ dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 ||
+ dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 ||
+ dev->ctl(dev, GET_MTUS, &mtutab) < 0 ||
+ dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 ||
+ dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0)
+ goto out_free;
+
+ err = -ENOMEM;
+ L2DATA(dev) = t3_init_l2t(l2t_capacity);
+ if (!L2DATA(dev))
+ goto out_free;
+
+ natids = min(tid_range.num / 2, MAX_ATIDS);
+ err = init_tid_tabs(&t->tid_maps, tid_range.num, natids,
+ stid_range.num, ATID_BASE, stid_range.base);
+ if (err)
+ goto out_free_l2t;
+
+ t->mtus = mtutab.mtus;
+ t->nmtus = mtutab.size;
+
+ INIT_WORK(&t->tid_release_task, t3_process_tid_release_list);
+ spin_lock_init(&t->tid_release_lock);
+ INIT_LIST_HEAD(&t->list_node);
+ t->dev = dev;
+
+ T3C_DATA(dev) = t;
+ dev->recv = process_rx;
+ dev->neigh_update = t3_l2t_update;
+
+ /* Register netevent handler once */
+ if (list_empty(&adapter_list))
+ register_netevent_notifier(&nb);
+
+ add_adapter(adapter);
+ return 0;
+
+out_free_l2t:
+ t3_free_l2t(L2DATA(dev));
+ L2DATA(dev) = NULL;
+out_free:
+ kfree(t);
+ return err;
+}
+
+void cxgb3_offload_deactivate(struct adapter *adapter)
+{
+ struct t3cdev *tdev = &adapter->tdev;
+ struct t3c_data *t = T3C_DATA(tdev);
+
+ remove_adapter(adapter);
+ if (list_empty(&adapter_list))
+ unregister_netevent_notifier(&nb);
+
+ free_tid_maps(&t->tid_maps);
+ T3C_DATA(tdev) = NULL;
+ t3_free_l2t(L2DATA(tdev));
+ L2DATA(tdev) = NULL;
+ kfree(t);
+}
+
+static inline void register_tdev(struct t3cdev *tdev)
+{
+ static int unit;
+
+ mutex_lock(&cxgb3_db_lock);
+ snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++);
+ list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list);
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+static inline void unregister_tdev(struct t3cdev *tdev)
+{
+ mutex_lock(&cxgb3_db_lock);
+ list_del(&tdev->ofld_dev_list);
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+void __devinit cxgb3_adapter_ofld(struct adapter *adapter)
+{
+ struct t3cdev *tdev = &adapter->tdev;
+
+ INIT_LIST_HEAD(&tdev->ofld_dev_list);
+
+ cxgb3_set_dummy_ops(tdev);
+ tdev->send = t3_offload_tx;
+ tdev->ctl = cxgb_offload_ctl;
+ tdev->type = adapter->params.rev == 0 ? T3A : T3B;
+
+ register_tdev(tdev);
+}
+
+void __devexit cxgb3_adapter_unofld(struct adapter *adapter)
+{
+ struct t3cdev *tdev = &adapter->tdev;
+
+ tdev->recv = NULL;
+ tdev->neigh_update = NULL;
+
+ unregister_tdev(tdev);
+}
+
+void __init cxgb3_offload_init(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_CPL_CMDS; ++i)
+ cpl_handlers[i] = do_bad_cpl;
+
+ t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl);
+ t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl);
+ t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl);
+ t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl);
+ t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr);
+ t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl);
+ t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss);
+ t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish);
+ t3_register_cpl_handler(CPL_SET_TCB_RPL, do_set_tcb_rpl);
+ t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term);
+ t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_TRACE_PKT, do_trace);
+ t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl);
+}
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h
new file mode 100644
index 00000000000..0e6beb69ba1
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_offload.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CXGB3_OFFLOAD_H
+#define _CXGB3_OFFLOAD_H
+
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+#include "l2t.h"
+
+#include "t3cdev.h"
+#include "t3_cpl.h"
+
+struct adapter;
+
+void cxgb3_offload_init(void);
+
+void cxgb3_adapter_ofld(struct adapter *adapter);
+void cxgb3_adapter_unofld(struct adapter *adapter);
+int cxgb3_offload_activate(struct adapter *adapter);
+void cxgb3_offload_deactivate(struct adapter *adapter);
+
+void cxgb3_set_dummy_ops(struct t3cdev *dev);
+
+/*
+ * Client registration. Users of T3 driver must register themselves.
+ * The T3 driver will call the add function of every client for each T3
+ * adapter activated, passing up the t3cdev ptr. Each client fills out an
+ * array of callback functions to process CPL messages.
+ */
+
+void cxgb3_register_client(struct cxgb3_client *client);
+void cxgb3_unregister_client(struct cxgb3_client *client);
+void cxgb3_add_clients(struct t3cdev *tdev);
+void cxgb3_remove_clients(struct t3cdev *tdev);
+
+typedef int (*cxgb3_cpl_handler_func)(struct t3cdev *dev,
+ struct sk_buff *skb, void *ctx);
+
+struct cxgb3_client {
+ char *name;
+ void (*add) (struct t3cdev *);
+ void (*remove) (struct t3cdev *);
+ cxgb3_cpl_handler_func *handlers;
+ int (*redirect)(void *ctx, struct dst_entry *old,
+ struct dst_entry *new, struct l2t_entry *l2t);
+ struct list_head client_list;
+};
+
+/*
+ * TID allocation services.
+ */
+int cxgb3_alloc_atid(struct t3cdev *dev, struct cxgb3_client *client,
+ void *ctx);
+int cxgb3_alloc_stid(struct t3cdev *dev, struct cxgb3_client *client,
+ void *ctx);
+void *cxgb3_free_atid(struct t3cdev *dev, int atid);
+void cxgb3_free_stid(struct t3cdev *dev, int stid);
+void cxgb3_insert_tid(struct t3cdev *dev, struct cxgb3_client *client,
+ void *ctx, unsigned int tid);
+void cxgb3_queue_tid_release(struct t3cdev *dev, unsigned int tid);
+void cxgb3_remove_tid(struct t3cdev *dev, void *ctx, unsigned int tid);
+
+struct t3c_tid_entry {
+ struct cxgb3_client *client;
+ void *ctx;
+};
+
+/* CPL message priority levels */
+enum {
+ CPL_PRIORITY_DATA = 0, /* data messages */
+ CPL_PRIORITY_SETUP = 1, /* connection setup messages */
+ CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */
+ CPL_PRIORITY_LISTEN = 1, /* listen start/stop messages */
+ CPL_PRIORITY_ACK = 1, /* RX ACK messages */
+ CPL_PRIORITY_CONTROL = 1 /* offload control messages */
+};
+
+/* Flags for return value of CPL message handlers */
+enum {
+ CPL_RET_BUF_DONE = 1, /* buffer processing done, buffer may be freed */
+ CPL_RET_BAD_MSG = 2, /* bad CPL message (e.g., unknown opcode) */
+ CPL_RET_UNKNOWN_TID = 4 /* unexpected unknown TID */
+};
+
+typedef int (*cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb);
+
+/*
+ * Returns a pointer to the first byte of the CPL header in an sk_buff that
+ * contains a CPL message.
+ */
+static inline void *cplhdr(struct sk_buff *skb)
+{
+ return skb->data;
+}
+
+void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h);
+
+union listen_entry {
+ struct t3c_tid_entry t3c_tid;
+ union listen_entry *next;
+};
+
+union active_open_entry {
+ struct t3c_tid_entry t3c_tid;
+ union active_open_entry *next;
+};
+
+/*
+ * Holds the size, base address, free list start, etc of the TID, server TID,
+ * and active-open TID tables for a offload device.
+ * The tables themselves are allocated dynamically.
+ */
+struct tid_info {
+ struct t3c_tid_entry *tid_tab;
+ unsigned int ntids;
+ atomic_t tids_in_use;
+
+ union listen_entry *stid_tab;
+ unsigned int nstids;
+ unsigned int stid_base;
+
+ union active_open_entry *atid_tab;
+ unsigned int natids;
+ unsigned int atid_base;
+
+ /*
+ * The following members are accessed R/W so we put them in their own
+ * cache lines.
+ *
+ * XXX We could combine the atid fields above with the lock here since
+ * atids are use once (unlike other tids). OTOH the above fields are
+ * usually in cache due to tid_tab.
+ */
+ spinlock_t atid_lock ____cacheline_aligned_in_smp;
+ union active_open_entry *afree;
+ unsigned int atids_in_use;
+
+ spinlock_t stid_lock ____cacheline_aligned;
+ union listen_entry *sfree;
+ unsigned int stids_in_use;
+};
+
+struct t3c_data {
+ struct list_head list_node;
+ struct t3cdev *dev;
+ unsigned int tx_max_chunk; /* max payload for TX_DATA */
+ unsigned int max_wrs; /* max in-flight WRs per connection */
+ unsigned int nmtus;
+ const unsigned short *mtus;
+ struct tid_info tid_maps;
+
+ struct t3c_tid_entry *tid_release_list;
+ spinlock_t tid_release_lock;
+ struct work_struct tid_release_task;
+};
+
+/*
+ * t3cdev -> t3c_data accessor
+ */
+#define T3C_DATA(dev) (*(struct t3c_data **)&(dev)->l4opt)
+
+#endif
diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h
new file mode 100644
index 00000000000..6a835f6a262
--- /dev/null
+++ b/drivers/net/cxgb3/firmware_exports.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _FIRMWARE_EXPORTS_H_
+#define _FIRMWARE_EXPORTS_H_
+
+/* WR OPCODES supported by the firmware.
+ */
+#define FW_WROPCODE_FORWARD 0x01
+#define FW_WROPCODE_BYPASS 0x05
+
+#define FW_WROPCODE_TUNNEL_TX_PKT 0x03
+
+#define FW_WROPOCDE_ULPTX_DATA_SGL 0x00
+#define FW_WROPCODE_ULPTX_MEM_READ 0x02
+#define FW_WROPCODE_ULPTX_PKT 0x04
+#define FW_WROPCODE_ULPTX_INVALIDATE 0x06
+
+#define FW_WROPCODE_TUNNEL_RX_PKT 0x07
+
+#define FW_WROPCODE_OFLD_GETTCB_RPL 0x08
+#define FW_WROPCODE_OFLD_CLOSE_CON 0x09
+#define FW_WROPCODE_OFLD_TP_ABORT_CON_REQ 0x0A
+#define FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL 0x0F
+#define FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ 0x0B
+#define FW_WROPCODE_OFLD_TP_ABORT_CON_RPL 0x0C
+#define FW_WROPCODE_OFLD_TX_DATA 0x0D
+#define FW_WROPCODE_OFLD_TX_DATA_ACK 0x0E
+
+#define FW_WROPCODE_RI_RDMA_INIT 0x10
+#define FW_WROPCODE_RI_RDMA_WRITE 0x11
+#define FW_WROPCODE_RI_RDMA_READ_REQ 0x12
+#define FW_WROPCODE_RI_RDMA_READ_RESP 0x13
+#define FW_WROPCODE_RI_SEND 0x14
+#define FW_WROPCODE_RI_TERMINATE 0x15
+#define FW_WROPCODE_RI_RDMA_READ 0x16
+#define FW_WROPCODE_RI_RECEIVE 0x17
+#define FW_WROPCODE_RI_BIND_MW 0x18
+#define FW_WROPCODE_RI_FASTREGISTER_MR 0x19
+#define FW_WROPCODE_RI_LOCAL_INV 0x1A
+#define FW_WROPCODE_RI_MODIFY_QP 0x1B
+#define FW_WROPCODE_RI_BYPASS 0x1C
+
+#define FW_WROPOCDE_RSVD 0x1E
+
+#define FW_WROPCODE_SGE_EGRESSCONTEXT_RR 0x1F
+
+#define FW_WROPCODE_MNGT 0x1D
+#define FW_MNGTOPCODE_PKTSCHED_SET 0x00
+
+/* Maximum size of a WR sent from the host, limited by the SGE.
+ *
+ * Note: WR coming from ULP or TP are only limited by CIM.
+ */
+#define FW_WR_SIZE 128
+
+/* Maximum number of outstanding WRs sent from the host. Value must be
+ * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by
+ * offload modules to limit the number of WRs per connection.
+ */
+#define FW_T3_WR_NUM 16
+#define FW_N3_WR_NUM 7
+
+#ifndef N3
+# define FW_WR_NUM FW_T3_WR_NUM
+#else
+# define FW_WR_NUM FW_N3_WR_NUM
+#endif
+
+/* FW_TUNNEL_NUM corresponds to the number of supported TUNNEL Queues. These
+ * queues must start at SGE Egress Context FW_TUNNEL_SGEEC_START and must
+ * start at 'TID' (or 'uP Token') FW_TUNNEL_TID_START.
+ *
+ * Ingress Traffic (e.g. DMA completion credit) for TUNNEL Queue[i] is sent
+ * to RESP Queue[i].
+ */
+#define FW_TUNNEL_NUM 8
+#define FW_TUNNEL_SGEEC_START 8
+#define FW_TUNNEL_TID_START 65544
+
+/* FW_CTRL_NUM corresponds to the number of supported CTRL Queues. These queues
+ * must start at SGE Egress Context FW_CTRL_SGEEC_START and must start at 'TID'
+ * (or 'uP Token') FW_CTRL_TID_START.
+ *
+ * Ingress Traffic for CTRL Queue[i] is sent to RESP Queue[i].
+ */
+#define FW_CTRL_NUM 8
+#define FW_CTRL_SGEEC_START 65528
+#define FW_CTRL_TID_START 65536
+
+/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These
+ * queues must start at SGE Egress Context FW_OFLD_SGEEC_START.
+ *
+ * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for
+ * OFFLOAD Queues, as the host is responsible for providing the correct TID in
+ * every WR.
+ *
+ * Ingress Trafffic for OFFLOAD Queue[i] is sent to RESP Queue[i].
+ */
+#define FW_OFLD_NUM 8
+#define FW_OFLD_SGEEC_START 0
+
+/*
+ *
+ */
+#define FW_RI_NUM 1
+#define FW_RI_SGEEC_START 65527
+#define FW_RI_TID_START 65552
+
+/*
+ * The RX_PKT_TID
+ */
+#define FW_RX_PKT_NUM 1
+#define FW_RX_PKT_TID_START 65553
+
+/* FW_WRC_NUM corresponds to the number of Work Request Context that supported
+ * by the firmware.
+ */
+#define FW_WRC_NUM \
+ (65536 + FW_TUNNEL_NUM + FW_CTRL_NUM + FW_RI_NUM + FW_RX_PKT_NUM)
+
+/*
+ * FW type and version.
+ */
+#define S_FW_VERSION_TYPE 28
+#define M_FW_VERSION_TYPE 0xF
+#define V_FW_VERSION_TYPE(x) ((x) << S_FW_VERSION_TYPE)
+#define G_FW_VERSION_TYPE(x) \
+ (((x) >> S_FW_VERSION_TYPE) & M_FW_VERSION_TYPE)
+
+#define S_FW_VERSION_MAJOR 16
+#define M_FW_VERSION_MAJOR 0xFFF
+#define V_FW_VERSION_MAJOR(x) ((x) << S_FW_VERSION_MAJOR)
+#define G_FW_VERSION_MAJOR(x) \
+ (((x) >> S_FW_VERSION_MAJOR) & M_FW_VERSION_MAJOR)
+
+#define S_FW_VERSION_MINOR 8
+#define M_FW_VERSION_MINOR 0xFF
+#define V_FW_VERSION_MINOR(x) ((x) << S_FW_VERSION_MINOR)
+#define G_FW_VERSION_MINOR(x) \
+ (((x) >> S_FW_VERSION_MINOR) & M_FW_VERSION_MINOR)
+
+#define S_FW_VERSION_MICRO 0
+#define M_FW_VERSION_MICRO 0xFF
+#define V_FW_VERSION_MICRO(x) ((x) << S_FW_VERSION_MICRO)
+#define G_FW_VERSION_MICRO(x) \
+ (((x) >> S_FW_VERSION_MICRO) & M_FW_VERSION_MICRO)
+
+#endif /* _FIRMWARE_EXPORTS_H_ */
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c
new file mode 100644
index 00000000000..3c0cb855705
--- /dev/null
+++ b/drivers/net/cxgb3/l2t.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <linux/jhash.h>
+#include <net/neighbour.h>
+#include "common.h"
+#include "t3cdev.h"
+#include "cxgb3_defs.h"
+#include "l2t.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+#define VLAN_NONE 0xfff
+
+/*
+ * Module locking notes: There is a RW lock protecting the L2 table as a
+ * whole plus a spinlock per L2T entry. Entry lookups and allocations happen
+ * under the protection of the table lock, individual entry changes happen
+ * while holding that entry's spinlock. The table lock nests outside the
+ * entry locks. Allocations of new entries take the table lock as writers so
+ * no other lookups can happen while allocating new entries. Entry updates
+ * take the table lock as readers so multiple entries can be updated in
+ * parallel. An L2T entry can be dropped by decrementing its reference count
+ * and therefore can happen in parallel with entry allocation but no entry
+ * can change state or increment its ref count during allocation as both of
+ * these perform lookups.
+ */
+
+static inline unsigned int vlan_prio(const struct l2t_entry *e)
+{
+ return e->vlan >> 13;
+}
+
+static inline unsigned int arp_hash(u32 key, int ifindex,
+ const struct l2t_data *d)
+{
+ return jhash_2words(key, ifindex, 0) & (d->nentries - 1);
+}
+
+static inline void neigh_replace(struct l2t_entry *e, struct neighbour *n)
+{
+ neigh_hold(n);
+ if (e->neigh)
+ neigh_release(e->neigh);
+ e->neigh = n;
+}
+
+/*
+ * Set up an L2T entry and send any packets waiting in the arp queue. The
+ * supplied skb is used for the CPL_L2T_WRITE_REQ. Must be called with the
+ * entry locked.
+ */
+static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e)
+{
+ struct cpl_l2t_write_req *req;
+
+ if (!skb) {
+ skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+ }
+
+ req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx));
+ req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) |
+ V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) |
+ V_L2T_W_PRIO(vlan_prio(e)));
+ memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac));
+ memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
+ skb->priority = CPL_PRIORITY_CONTROL;
+ cxgb3_ofld_send(dev, skb);
+ while (e->arpq_head) {
+ skb = e->arpq_head;
+ e->arpq_head = skb->next;
+ skb->next = NULL;
+ cxgb3_ofld_send(dev, skb);
+ }
+ e->arpq_tail = NULL;
+ e->state = L2T_STATE_VALID;
+
+ return 0;
+}
+
+/*
+ * Add a packet to the an L2T entry's queue of packets awaiting resolution.
+ * Must be called with the entry's lock held.
+ */
+static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb)
+{
+ skb->next = NULL;
+ if (e->arpq_head)
+ e->arpq_tail->next = skb;
+ else
+ e->arpq_head = skb;
+ e->arpq_tail = skb;
+}
+
+int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e)
+{
+again:
+ switch (e->state) {
+ case L2T_STATE_STALE: /* entry is stale, kick off revalidation */
+ neigh_event_send(e->neigh, NULL);
+ spin_lock_bh(&e->lock);
+ if (e->state == L2T_STATE_STALE)
+ e->state = L2T_STATE_VALID;
+ spin_unlock_bh(&e->lock);
+ case L2T_STATE_VALID: /* fast-path, send the packet on */
+ return cxgb3_ofld_send(dev, skb);
+ case L2T_STATE_RESOLVING:
+ spin_lock_bh(&e->lock);
+ if (e->state != L2T_STATE_RESOLVING) {
+ /* ARP already completed */
+ spin_unlock_bh(&e->lock);
+ goto again;
+ }
+ arpq_enqueue(e, skb);
+ spin_unlock_bh(&e->lock);
+
+ /*
+ * Only the first packet added to the arpq should kick off
+ * resolution. However, because the alloc_skb below can fail,
+ * we allow each packet added to the arpq to retry resolution
+ * as a way of recovering from transient memory exhaustion.
+ * A better way would be to use a work request to retry L2T
+ * entries when there's no memory.
+ */
+ if (!neigh_event_send(e->neigh, NULL)) {
+ skb = alloc_skb(sizeof(struct cpl_l2t_write_req),
+ GFP_ATOMIC);
+ if (!skb)
+ break;
+
+ spin_lock_bh(&e->lock);
+ if (e->arpq_head)
+ setup_l2e_send_pending(dev, skb, e);
+ else /* we lost the race */
+ __kfree_skb(skb);
+ spin_unlock_bh(&e->lock);
+ }
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(t3_l2t_send_slow);
+
+void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e)
+{
+again:
+ switch (e->state) {
+ case L2T_STATE_STALE: /* entry is stale, kick off revalidation */
+ neigh_event_send(e->neigh, NULL);
+ spin_lock_bh(&e->lock);
+ if (e->state == L2T_STATE_STALE) {
+ e->state = L2T_STATE_VALID;
+ }
+ spin_unlock_bh(&e->lock);
+ return;
+ case L2T_STATE_VALID: /* fast-path, send the packet on */
+ return;
+ case L2T_STATE_RESOLVING:
+ spin_lock_bh(&e->lock);
+ if (e->state != L2T_STATE_RESOLVING) {
+ /* ARP already completed */
+ spin_unlock_bh(&e->lock);
+ goto again;
+ }
+ spin_unlock_bh(&e->lock);
+
+ /*
+ * Only the first packet added to the arpq should kick off
+ * resolution. However, because the alloc_skb below can fail,
+ * we allow each packet added to the arpq to retry resolution
+ * as a way of recovering from transient memory exhaustion.
+ * A better way would be to use a work request to retry L2T
+ * entries when there's no memory.
+ */
+ neigh_event_send(e->neigh, NULL);
+ }
+ return;
+}
+
+EXPORT_SYMBOL(t3_l2t_send_event);
+
+/*
+ * Allocate a free L2T entry. Must be called with l2t_data.lock held.
+ */
+static struct l2t_entry *alloc_l2e(struct l2t_data *d)
+{
+ struct l2t_entry *end, *e, **p;
+
+ if (!atomic_read(&d->nfree))
+ return NULL;
+
+ /* there's definitely a free entry */
+ for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e)
+ if (atomic_read(&e->refcnt) == 0)
+ goto found;
+
+ for (e = &d->l2tab[1]; atomic_read(&e->refcnt); ++e) ;
+found:
+ d->rover = e + 1;
+ atomic_dec(&d->nfree);
+
+ /*
+ * The entry we found may be an inactive entry that is
+ * presently in the hash table. We need to remove it.
+ */
+ if (e->state != L2T_STATE_UNUSED) {
+ int hash = arp_hash(e->addr, e->ifindex, d);
+
+ for (p = &d->l2tab[hash].first; *p; p = &(*p)->next)
+ if (*p == e) {
+ *p = e->next;
+ break;
+ }
+ e->state = L2T_STATE_UNUSED;
+ }
+ return e;
+}
+
+/*
+ * Called when an L2T entry has no more users. The entry is left in the hash
+ * table since it is likely to be reused but we also bump nfree to indicate
+ * that the entry can be reallocated for a different neighbor. We also drop
+ * the existing neighbor reference in case the neighbor is going away and is
+ * waiting on our reference.
+ *
+ * Because entries can be reallocated to other neighbors once their ref count
+ * drops to 0 we need to take the entry's lock to avoid races with a new
+ * incarnation.
+ */
+void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e)
+{
+ spin_lock_bh(&e->lock);
+ if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */
+ if (e->neigh) {
+ neigh_release(e->neigh);
+ e->neigh = NULL;
+ }
+ }
+ spin_unlock_bh(&e->lock);
+ atomic_inc(&d->nfree);
+}
+
+EXPORT_SYMBOL(t3_l2e_free);
+
+/*
+ * Update an L2T entry that was previously used for the same next hop as neigh.
+ * Must be called with softirqs disabled.
+ */
+static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh)
+{
+ unsigned int nud_state;
+
+ spin_lock(&e->lock); /* avoid race with t3_l2t_free */
+
+ if (neigh != e->neigh)
+ neigh_replace(e, neigh);
+ nud_state = neigh->nud_state;
+ if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) ||
+ !(nud_state & NUD_VALID))
+ e->state = L2T_STATE_RESOLVING;
+ else if (nud_state & NUD_CONNECTED)
+ e->state = L2T_STATE_VALID;
+ else
+ e->state = L2T_STATE_STALE;
+ spin_unlock(&e->lock);
+}
+
+struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
+ struct net_device *dev)
+{
+ struct l2t_entry *e;
+ struct l2t_data *d = L2DATA(cdev);
+ u32 addr = *(u32 *) neigh->primary_key;
+ int ifidx = neigh->dev->ifindex;
+ int hash = arp_hash(addr, ifidx, d);
+ struct port_info *p = netdev_priv(dev);
+ int smt_idx = p->port_id;
+
+ write_lock_bh(&d->lock);
+ for (e = d->l2tab[hash].first; e; e = e->next)
+ if (e->addr == addr && e->ifindex == ifidx &&
+ e->smt_idx == smt_idx) {
+ l2t_hold(d, e);
+ if (atomic_read(&e->refcnt) == 1)
+ reuse_entry(e, neigh);
+ goto done;
+ }
+
+ /* Need to allocate a new entry */
+ e = alloc_l2e(d);
+ if (e) {
+ spin_lock(&e->lock); /* avoid race with t3_l2t_free */
+ e->next = d->l2tab[hash].first;
+ d->l2tab[hash].first = e;
+ e->state = L2T_STATE_RESOLVING;
+ e->addr = addr;
+ e->ifindex = ifidx;
+ e->smt_idx = smt_idx;
+ atomic_set(&e->refcnt, 1);
+ neigh_replace(e, neigh);
+ if (neigh->dev->priv_flags & IFF_802_1Q_VLAN)
+ e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id;
+ else
+ e->vlan = VLAN_NONE;
+ spin_unlock(&e->lock);
+ }
+done:
+ write_unlock_bh(&d->lock);
+ return e;
+}
+
+EXPORT_SYMBOL(t3_l2t_get);
+
+/*
+ * Called when address resolution fails for an L2T entry to handle packets
+ * on the arpq head. If a packet specifies a failure handler it is invoked,
+ * otherwise the packets is sent to the offload device.
+ *
+ * XXX: maybe we should abandon the latter behavior and just require a failure
+ * handler.
+ */
+static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq)
+{
+ while (arpq) {
+ struct sk_buff *skb = arpq;
+ struct l2t_skb_cb *cb = L2T_SKB_CB(skb);
+
+ arpq = skb->next;
+ skb->next = NULL;
+ if (cb->arp_failure_handler)
+ cb->arp_failure_handler(dev, skb);
+ else
+ cxgb3_ofld_send(dev, skb);
+ }
+}
+
+/*
+ * Called when the host's ARP layer makes a change to some entry that is
+ * loaded into the HW L2 table.
+ */
+void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh)
+{
+ struct l2t_entry *e;
+ struct sk_buff *arpq = NULL;
+ struct l2t_data *d = L2DATA(dev);
+ u32 addr = *(u32 *) neigh->primary_key;
+ int ifidx = neigh->dev->ifindex;
+ int hash = arp_hash(addr, ifidx, d);
+
+ read_lock_bh(&d->lock);
+ for (e = d->l2tab[hash].first; e; e = e->next)
+ if (e->addr == addr && e->ifindex == ifidx) {
+ spin_lock(&e->lock);
+ goto found;
+ }
+ read_unlock_bh(&d->lock);
+ return;
+
+found:
+ read_unlock(&d->lock);
+ if (atomic_read(&e->refcnt)) {
+ if (neigh != e->neigh)
+ neigh_replace(e, neigh);
+
+ if (e->state == L2T_STATE_RESOLVING) {
+ if (neigh->nud_state & NUD_FAILED) {
+ arpq = e->arpq_head;
+ e->arpq_head = e->arpq_tail = NULL;
+ } else if (neigh_is_connected(neigh))
+ setup_l2e_send_pending(dev, NULL, e);
+ } else {
+ e->state = neigh_is_connected(neigh) ?
+ L2T_STATE_VALID : L2T_STATE_STALE;
+ if (memcmp(e->dmac, neigh->ha, 6))
+ setup_l2e_send_pending(dev, NULL, e);
+ }
+ }
+ spin_unlock_bh(&e->lock);
+
+ if (arpq)
+ handle_failed_resolution(dev, arpq);
+}
+
+struct l2t_data *t3_init_l2t(unsigned int l2t_capacity)
+{
+ struct l2t_data *d;
+ int i, size = sizeof(*d) + l2t_capacity * sizeof(struct l2t_entry);
+
+ d = cxgb_alloc_mem(size);
+ if (!d)
+ return NULL;
+
+ d->nentries = l2t_capacity;
+ d->rover = &d->l2tab[1]; /* entry 0 is not used */
+ atomic_set(&d->nfree, l2t_capacity - 1);
+ rwlock_init(&d->lock);
+
+ for (i = 0; i < l2t_capacity; ++i) {
+ d->l2tab[i].idx = i;
+ d->l2tab[i].state = L2T_STATE_UNUSED;
+ spin_lock_init(&d->l2tab[i].lock);
+ atomic_set(&d->l2tab[i].refcnt, 0);
+ }
+ return d;
+}
+
+void t3_free_l2t(struct l2t_data *d)
+{
+ cxgb_free_mem(d);
+}
+
diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h
new file mode 100644
index 00000000000..ba5d2cbd724
--- /dev/null
+++ b/drivers/net/cxgb3/l2t.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CHELSIO_L2T_H
+#define _CHELSIO_L2T_H
+
+#include <linux/spinlock.h>
+#include "t3cdev.h"
+#include <asm/atomic.h>
+
+enum {
+ L2T_STATE_VALID, /* entry is up to date */
+ L2T_STATE_STALE, /* entry may be used but needs revalidation */
+ L2T_STATE_RESOLVING, /* entry needs address resolution */
+ L2T_STATE_UNUSED /* entry not in use */
+};
+
+struct neighbour;
+struct sk_buff;
+
+/*
+ * Each L2T entry plays multiple roles. First of all, it keeps state for the
+ * corresponding entry of the HW L2 table and maintains a queue of offload
+ * packets awaiting address resolution. Second, it is a node of a hash table
+ * chain, where the nodes of the chain are linked together through their next
+ * pointer. Finally, each node is a bucket of a hash table, pointing to the
+ * first element in its chain through its first pointer.
+ */
+struct l2t_entry {
+ u16 state; /* entry state */
+ u16 idx; /* entry index */
+ u32 addr; /* dest IP address */
+ int ifindex; /* neighbor's net_device's ifindex */
+ u16 smt_idx; /* SMT index */
+ u16 vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */
+ struct neighbour *neigh; /* associated neighbour */
+ struct l2t_entry *first; /* start of hash chain */
+ struct l2t_entry *next; /* next l2t_entry on chain */
+ struct sk_buff *arpq_head; /* queue of packets awaiting resolution */
+ struct sk_buff *arpq_tail;
+ spinlock_t lock;
+ atomic_t refcnt; /* entry reference count */
+ u8 dmac[6]; /* neighbour's MAC address */
+};
+
+struct l2t_data {
+ unsigned int nentries; /* number of entries */
+ struct l2t_entry *rover; /* starting point for next allocation */
+ atomic_t nfree; /* number of free entries */
+ rwlock_t lock;
+ struct l2t_entry l2tab[0];
+};
+
+typedef void (*arp_failure_handler_func)(struct t3cdev * dev,
+ struct sk_buff * skb);
+
+/*
+ * Callback stored in an skb to handle address resolution failure.
+ */
+struct l2t_skb_cb {
+ arp_failure_handler_func arp_failure_handler;
+};
+
+#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb)
+
+static inline void set_arp_failure_handler(struct sk_buff *skb,
+ arp_failure_handler_func hnd)
+{
+ L2T_SKB_CB(skb)->arp_failure_handler = hnd;
+}
+
+/*
+ * Getting to the L2 data from an offload device.
+ */
+#define L2DATA(dev) ((dev)->l2opt)
+
+#define W_TCB_L2T_IX 0
+#define S_TCB_L2T_IX 7
+#define M_TCB_L2T_IX 0x7ffULL
+#define V_TCB_L2T_IX(x) ((x) << S_TCB_L2T_IX)
+
+void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e);
+void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh);
+struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
+ struct net_device *dev);
+int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e);
+void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e);
+struct l2t_data *t3_init_l2t(unsigned int l2t_capacity);
+void t3_free_l2t(struct l2t_data *d);
+
+int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb);
+
+static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e)
+{
+ if (likely(e->state == L2T_STATE_VALID))
+ return cxgb3_ofld_send(dev, skb);
+ return t3_l2t_send_slow(dev, skb, e);
+}
+
+static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e)
+{
+ if (atomic_dec_and_test(&e->refcnt))
+ t3_l2e_free(d, e);
+}
+
+static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
+{
+ if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */
+ atomic_dec(&d->nfree);
+}
+
+#endif
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c
new file mode 100644
index 00000000000..644d62ea86a
--- /dev/null
+++ b/drivers/net/cxgb3/mc5.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+enum {
+ IDT75P52100 = 4,
+ IDT75N43102 = 5
+};
+
+/* DBGI command mode */
+enum {
+ DBGI_MODE_MBUS = 0,
+ DBGI_MODE_IDT52100 = 5
+};
+
+/* IDT 75P52100 commands */
+#define IDT_CMD_READ 0
+#define IDT_CMD_WRITE 1
+#define IDT_CMD_SEARCH 2
+#define IDT_CMD_LEARN 3
+
+/* IDT LAR register address and value for 144-bit mode (low 32 bits) */
+#define IDT_LAR_ADR0 0x180006
+#define IDT_LAR_MODE144 0xffff0000
+
+/* IDT SCR and SSR addresses (low 32 bits) */
+#define IDT_SCR_ADR0 0x180000
+#define IDT_SSR0_ADR0 0x180002
+#define IDT_SSR1_ADR0 0x180004
+
+/* IDT GMR base address (low 32 bits) */
+#define IDT_GMR_BASE_ADR0 0x180020
+
+/* IDT data and mask array base addresses (low 32 bits) */
+#define IDT_DATARY_BASE_ADR0 0
+#define IDT_MSKARY_BASE_ADR0 0x80000
+
+/* IDT 75N43102 commands */
+#define IDT4_CMD_SEARCH144 3
+#define IDT4_CMD_WRITE 4
+#define IDT4_CMD_READ 5
+
+/* IDT 75N43102 SCR address (low 32 bits) */
+#define IDT4_SCR_ADR0 0x3
+
+/* IDT 75N43102 GMR base addresses (low 32 bits) */
+#define IDT4_GMR_BASE0 0x10
+#define IDT4_GMR_BASE1 0x20
+#define IDT4_GMR_BASE2 0x30
+
+/* IDT 75N43102 data and mask array base addresses (low 32 bits) */
+#define IDT4_DATARY_BASE_ADR0 0x1000000
+#define IDT4_MSKARY_BASE_ADR0 0x2000000
+
+#define MAX_WRITE_ATTEMPTS 5
+
+#define MAX_ROUTES 2048
+
+/*
+ * Issue a command to the TCAM and wait for its completion. The address and
+ * any data required by the command must have been setup by the caller.
+ */
+static int mc5_cmd_write(struct adapter *adapter, u32 cmd)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd);
+ return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS,
+ F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1);
+}
+
+static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2,
+ u32 v3)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3);
+}
+
+static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2,
+ u32 v3)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3);
+}
+
+static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2,
+ u32 *v3)
+{
+ *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0);
+ *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1);
+ *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2);
+}
+
+/*
+ * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM
+ * command cmd. The data to be written must have been set up by the caller.
+ * Returns -1 on failure, 0 on success.
+ */
+static int mc5_write(struct adapter *adapter, u32 addr_lo, u32 cmd)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo);
+ if (mc5_cmd_write(adapter, cmd) == 0)
+ return 0;
+ CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n",
+ addr_lo);
+ return -1;
+}
+
+static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base,
+ u32 data_array_base, u32 write_cmd,
+ int addr_shift)
+{
+ unsigned int i;
+ struct adapter *adap = mc5->adapter;
+
+ /*
+ * We need the size of the TCAM data and mask arrays in terms of
+ * 72-bit entries.
+ */
+ unsigned int size72 = mc5->tcam_size;
+ unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX);
+
+ if (mc5->mode == MC5_MODE_144_BIT) {
+ size72 *= 2; /* 1 144-bit entry is 2 72-bit entries */
+ server_base *= 2;
+ }
+
+ /* Clear the data array */
+ dbgi_wr_data3(adap, 0, 0, 0);
+ for (i = 0; i < size72; i++)
+ if (mc5_write(adap, data_array_base + (i << addr_shift),
+ write_cmd))
+ return -1;
+
+ /* Initialize the mask array. */
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+ for (i = 0; i < size72; i++) {
+ if (i == server_base) /* entering server or routing region */
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_DATA0,
+ mc5->mode == MC5_MODE_144_BIT ?
+ 0xfffffff9 : 0xfffffffd);
+ if (mc5_write(adap, mask_array_base + (i << addr_shift),
+ write_cmd))
+ return -1;
+ }
+ return 0;
+}
+
+static int init_idt52100(struct mc5 *mc5)
+{
+ int i;
+ struct adapter *adap = mc5->adapter;
+
+ t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
+ V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15));
+ t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2);
+
+ /*
+ * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and
+ * GMRs 8-9 for ACK- and AOPEN searches.
+ */
+ t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH);
+ t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN);
+ t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000);
+ t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN);
+ t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH);
+ t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN);
+ t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH);
+ t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000);
+ t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ);
+
+ /* Set DBGI command mode for IDT TCAM. */
+ t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
+
+ /* Set up LAR */
+ dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0);
+ if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE))
+ goto err;
+
+ /* Set up SSRs */
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0);
+ if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) ||
+ mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE))
+ goto err;
+
+ /* Set up GMRs */
+ for (i = 0; i < 32; ++i) {
+ if (i >= 12 && i < 15)
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
+ else if (i == 15)
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
+ else
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+
+ if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE))
+ goto err;
+ }
+
+ /* Set up SCR */
+ dbgi_wr_data3(adap, 1, 0, 0);
+ if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE))
+ goto err;
+
+ return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0,
+ IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0);
+err:
+ return -EIO;
+}
+
+static int init_idt43102(struct mc5 *mc5)
+{
+ int i;
+ struct adapter *adap = mc5->adapter;
+
+ t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
+ adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) :
+ V_RDLAT(0xd) | V_SRCHLAT(0x12));
+
+ /*
+ * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask
+ * for ACK- and AOPEN searches.
+ */
+ t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD,
+ IDT4_CMD_SEARCH144 | 0x3800);
+ t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144);
+ t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800);
+ t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800);
+ t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800);
+ t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ);
+
+ t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3);
+
+ /* Set DBGI command mode for IDT TCAM. */
+ t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
+
+ /* Set up GMRs */
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+ for (i = 0; i < 7; ++i)
+ if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE))
+ goto err;
+
+ for (i = 0; i < 4; ++i)
+ if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE))
+ goto err;
+
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
+ if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) ||
+ mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) ||
+ mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE))
+ goto err;
+
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
+ if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE))
+ goto err;
+
+ /* Set up SCR */
+ dbgi_wr_data3(adap, 0xf0000000, 0, 0);
+ if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE))
+ goto err;
+
+ return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0,
+ IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1);
+err:
+ return -EIO;
+}
+
+/* Put MC5 in DBGI mode. */
+static inline void mc5_dbgi_mode_enable(const struct mc5 *mc5)
+{
+ t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
+ V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_DBGIEN);
+}
+
+/* Put MC5 in M-Bus mode. */
+static void mc5_dbgi_mode_disable(const struct mc5 *mc5)
+{
+ t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
+ V_TMMODE(mc5->mode == MC5_MODE_72_BIT) |
+ V_COMPEN(mc5->mode == MC5_MODE_72_BIT) |
+ V_PRTYEN(mc5->parity_enabled) | F_MBUSEN);
+}
+
+/*
+ * Initialization that requires the OS and protocol layers to already
+ * be intialized goes here.
+ */
+int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
+ unsigned int nroutes)
+{
+ u32 cfg;
+ int err;
+ unsigned int tcam_size = mc5->tcam_size;
+ struct adapter *adap = mc5->adapter;
+
+ if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size)
+ return -EINVAL;
+
+ /* Reset the TCAM */
+ cfg = t3_read_reg(adap, A_MC5_DB_CONFIG) & ~F_TMMODE;
+ cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST;
+ t3_write_reg(adap, A_MC5_DB_CONFIG, cfg);
+ if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) {
+ CH_ERR(adap, "TCAM reset timed out\n");
+ return -1;
+ }
+
+ t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes);
+ t3_write_reg(adap, A_MC5_DB_FILTER_TABLE,
+ tcam_size - nroutes - nfilters);
+ t3_write_reg(adap, A_MC5_DB_SERVER_INDEX,
+ tcam_size - nroutes - nfilters - nservers);
+
+ mc5->parity_enabled = 1;
+
+ /* All the TCAM addresses we access have only the low 32 bits non 0 */
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0);
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0);
+
+ mc5_dbgi_mode_enable(mc5);
+
+ switch (mc5->part_type) {
+ case IDT75P52100:
+ err = init_idt52100(mc5);
+ break;
+ case IDT75N43102:
+ err = init_idt43102(mc5);
+ break;
+ default:
+ CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type);
+ err = -EINVAL;
+ break;
+ }
+
+ mc5_dbgi_mode_disable(mc5);
+ return err;
+}
+
+/*
+ * read_mc5_range - dump a part of the memory managed by MC5
+ * @mc5: the MC5 handle
+ * @start: the start address for the dump
+ * @n: number of 72-bit words to read
+ * @buf: result buffer
+ *
+ * Read n 72-bit words from MC5 memory from the given start location.
+ */
+int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start,
+ unsigned int n, u32 *buf)
+{
+ u32 read_cmd;
+ int err = 0;
+ struct adapter *adap = mc5->adapter;
+
+ if (mc5->part_type == IDT75P52100)
+ read_cmd = IDT_CMD_READ;
+ else if (mc5->part_type == IDT75N43102)
+ read_cmd = IDT4_CMD_READ;
+ else
+ return -EINVAL;
+
+ mc5_dbgi_mode_enable(mc5);
+
+ while (n--) {
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR0, start++);
+ if (mc5_cmd_write(adap, read_cmd)) {
+ err = -EIO;
+ break;
+ }
+ dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf);
+ buf += 3;
+ }
+
+ mc5_dbgi_mode_disable(mc5);
+ return 0;
+}
+
+#define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR)
+
+/*
+ * MC5 interrupt handler
+ */
+void t3_mc5_intr_handler(struct mc5 *mc5)
+{
+ struct adapter *adap = mc5->adapter;
+ u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE);
+
+ if ((cause & F_PARITYERR) && mc5->parity_enabled) {
+ CH_ALERT(adap, "MC5 parity error\n");
+ mc5->stats.parity_err++;
+ }
+
+ if (cause & F_REQQPARERR) {
+ CH_ALERT(adap, "MC5 request queue parity error\n");
+ mc5->stats.reqq_parity_err++;
+ }
+
+ if (cause & F_DISPQPARERR) {
+ CH_ALERT(adap, "MC5 dispatch queue parity error\n");
+ mc5->stats.dispq_parity_err++;
+ }
+
+ if (cause & F_ACTRGNFULL)
+ mc5->stats.active_rgn_full++;
+ if (cause & F_NFASRCHFAIL)
+ mc5->stats.nfa_srch_err++;
+ if (cause & F_UNKNOWNCMD)
+ mc5->stats.unknown_cmd++;
+ if (cause & F_DELACTEMPTY)
+ mc5->stats.del_act_empty++;
+ if (cause & MC5_INT_FATAL)
+ t3_fatal_err(adap);
+
+ t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause);
+}
+
+void __devinit t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode)
+{
+#define K * 1024
+
+ static unsigned int tcam_part_size[] = { /* in K 72-bit entries */
+ 64 K, 128 K, 256 K, 32 K
+ };
+
+#undef K
+
+ u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG);
+
+ mc5->adapter = adapter;
+ mc5->mode = (unsigned char)mode;
+ mc5->part_type = (unsigned char)G_TMTYPE(cfg);
+ if (cfg & F_TMTYPEHI)
+ mc5->part_type |= 4;
+
+ mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)];
+ if (mode == MC5_MODE_144_BIT)
+ mc5->tcam_size /= 2;
+}
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
new file mode 100644
index 00000000000..b56c5f52bcd
--- /dev/null
+++ b/drivers/net/cxgb3/regs.h
@@ -0,0 +1,2195 @@
+#define A_SG_CONTROL 0x0
+
+#define S_DROPPKT 20
+#define V_DROPPKT(x) ((x) << S_DROPPKT)
+#define F_DROPPKT V_DROPPKT(1U)
+
+#define S_EGRGENCTRL 19
+#define V_EGRGENCTRL(x) ((x) << S_EGRGENCTRL)
+#define F_EGRGENCTRL V_EGRGENCTRL(1U)
+
+#define S_USERSPACESIZE 14
+#define M_USERSPACESIZE 0x1f
+#define V_USERSPACESIZE(x) ((x) << S_USERSPACESIZE)
+
+#define S_HOSTPAGESIZE 11
+#define M_HOSTPAGESIZE 0x7
+#define V_HOSTPAGESIZE(x) ((x) << S_HOSTPAGESIZE)
+
+#define S_FLMODE 9
+#define V_FLMODE(x) ((x) << S_FLMODE)
+#define F_FLMODE V_FLMODE(1U)
+
+#define S_PKTSHIFT 6
+#define M_PKTSHIFT 0x7
+#define V_PKTSHIFT(x) ((x) << S_PKTSHIFT)
+
+#define S_ONEINTMULTQ 5
+#define V_ONEINTMULTQ(x) ((x) << S_ONEINTMULTQ)
+#define F_ONEINTMULTQ V_ONEINTMULTQ(1U)
+
+#define S_BIGENDIANINGRESS 2
+#define V_BIGENDIANINGRESS(x) ((x) << S_BIGENDIANINGRESS)
+#define F_BIGENDIANINGRESS V_BIGENDIANINGRESS(1U)
+
+#define S_ISCSICOALESCING 1
+#define V_ISCSICOALESCING(x) ((x) << S_ISCSICOALESCING)
+#define F_ISCSICOALESCING V_ISCSICOALESCING(1U)
+
+#define S_GLOBALENABLE 0
+#define V_GLOBALENABLE(x) ((x) << S_GLOBALENABLE)
+#define F_GLOBALENABLE V_GLOBALENABLE(1U)
+
+#define S_AVOIDCQOVFL 24
+#define V_AVOIDCQOVFL(x) ((x) << S_AVOIDCQOVFL)
+#define F_AVOIDCQOVFL V_AVOIDCQOVFL(1U)
+
+#define S_OPTONEINTMULTQ 23
+#define V_OPTONEINTMULTQ(x) ((x) << S_OPTONEINTMULTQ)
+#define F_OPTONEINTMULTQ V_OPTONEINTMULTQ(1U)
+
+#define S_CQCRDTCTRL 22
+#define V_CQCRDTCTRL(x) ((x) << S_CQCRDTCTRL)
+#define F_CQCRDTCTRL V_CQCRDTCTRL(1U)
+
+#define A_SG_KDOORBELL 0x4
+
+#define S_SELEGRCNTX 31
+#define V_SELEGRCNTX(x) ((x) << S_SELEGRCNTX)
+#define F_SELEGRCNTX V_SELEGRCNTX(1U)
+
+#define S_EGRCNTX 0
+#define M_EGRCNTX 0xffff
+#define V_EGRCNTX(x) ((x) << S_EGRCNTX)
+
+#define A_SG_GTS 0x8
+
+#define S_RSPQ 29
+#define M_RSPQ 0x7
+#define V_RSPQ(x) ((x) << S_RSPQ)
+#define G_RSPQ(x) (((x) >> S_RSPQ) & M_RSPQ)
+
+#define S_NEWTIMER 16
+#define M_NEWTIMER 0x1fff
+#define V_NEWTIMER(x) ((x) << S_NEWTIMER)
+
+#define S_NEWINDEX 0
+#define M_NEWINDEX 0xffff
+#define V_NEWINDEX(x) ((x) << S_NEWINDEX)
+
+#define A_SG_CONTEXT_CMD 0xc
+
+#define S_CONTEXT_CMD_OPCODE 28
+#define M_CONTEXT_CMD_OPCODE 0xf
+#define V_CONTEXT_CMD_OPCODE(x) ((x) << S_CONTEXT_CMD_OPCODE)
+
+#define S_CONTEXT_CMD_BUSY 27
+#define V_CONTEXT_CMD_BUSY(x) ((x) << S_CONTEXT_CMD_BUSY)
+#define F_CONTEXT_CMD_BUSY V_CONTEXT_CMD_BUSY(1U)
+
+#define S_CQ_CREDIT 20
+
+#define M_CQ_CREDIT 0x7f
+
+#define V_CQ_CREDIT(x) ((x) << S_CQ_CREDIT)
+
+#define G_CQ_CREDIT(x) (((x) >> S_CQ_CREDIT) & M_CQ_CREDIT)
+
+#define S_CQ 19
+
+#define V_CQ(x) ((x) << S_CQ)
+#define F_CQ V_CQ(1U)
+
+#define S_RESPONSEQ 18
+#define V_RESPONSEQ(x) ((x) << S_RESPONSEQ)
+#define F_RESPONSEQ V_RESPONSEQ(1U)
+
+#define S_EGRESS 17
+#define V_EGRESS(x) ((x) << S_EGRESS)
+#define F_EGRESS V_EGRESS(1U)
+
+#define S_FREELIST 16
+#define V_FREELIST(x) ((x) << S_FREELIST)
+#define F_FREELIST V_FREELIST(1U)
+
+#define S_CONTEXT 0
+#define M_CONTEXT 0xffff
+#define V_CONTEXT(x) ((x) << S_CONTEXT)
+
+#define G_CONTEXT(x) (((x) >> S_CONTEXT) & M_CONTEXT)
+
+#define A_SG_CONTEXT_DATA0 0x10
+
+#define A_SG_CONTEXT_DATA1 0x14
+
+#define A_SG_CONTEXT_DATA2 0x18
+
+#define A_SG_CONTEXT_DATA3 0x1c
+
+#define A_SG_CONTEXT_MASK0 0x20
+
+#define A_SG_CONTEXT_MASK1 0x24
+
+#define A_SG_CONTEXT_MASK2 0x28
+
+#define A_SG_CONTEXT_MASK3 0x2c
+
+#define A_SG_RSPQ_CREDIT_RETURN 0x30
+
+#define S_CREDITS 0
+#define M_CREDITS 0xffff
+#define V_CREDITS(x) ((x) << S_CREDITS)
+
+#define A_SG_DATA_INTR 0x34
+
+#define S_ERRINTR 31
+#define V_ERRINTR(x) ((x) << S_ERRINTR)
+#define F_ERRINTR V_ERRINTR(1U)
+
+#define A_SG_HI_DRB_HI_THRSH 0x38
+
+#define A_SG_HI_DRB_LO_THRSH 0x3c
+
+#define A_SG_LO_DRB_HI_THRSH 0x40
+
+#define A_SG_LO_DRB_LO_THRSH 0x44
+
+#define A_SG_RSPQ_FL_STATUS 0x4c
+
+#define S_RSPQ0DISABLED 8
+
+#define A_SG_EGR_RCQ_DRB_THRSH 0x54
+
+#define S_HIRCQDRBTHRSH 16
+#define M_HIRCQDRBTHRSH 0x7ff
+#define V_HIRCQDRBTHRSH(x) ((x) << S_HIRCQDRBTHRSH)
+
+#define S_LORCQDRBTHRSH 0
+#define M_LORCQDRBTHRSH 0x7ff
+#define V_LORCQDRBTHRSH(x) ((x) << S_LORCQDRBTHRSH)
+
+#define A_SG_EGR_CNTX_BADDR 0x58
+
+#define A_SG_INT_CAUSE 0x5c
+
+#define S_RSPQDISABLED 3
+#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED)
+#define F_RSPQDISABLED V_RSPQDISABLED(1U)
+
+#define S_RSPQCREDITOVERFOW 2
+#define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW)
+#define F_RSPQCREDITOVERFOW V_RSPQCREDITOVERFOW(1U)
+
+#define A_SG_INT_ENABLE 0x60
+
+#define A_SG_CMDQ_CREDIT_TH 0x64
+
+#define S_TIMEOUT 8
+#define M_TIMEOUT 0xffffff
+#define V_TIMEOUT(x) ((x) << S_TIMEOUT)
+
+#define S_THRESHOLD 0
+#define M_THRESHOLD 0xff
+#define V_THRESHOLD(x) ((x) << S_THRESHOLD)
+
+#define A_SG_TIMER_TICK 0x68
+
+#define A_SG_CQ_CONTEXT_BADDR 0x6c
+
+#define A_SG_OCO_BASE 0x70
+
+#define S_BASE1 16
+#define M_BASE1 0xffff
+#define V_BASE1(x) ((x) << S_BASE1)
+
+#define A_SG_DRB_PRI_THRESH 0x74
+
+#define A_PCIX_INT_ENABLE 0x80
+
+#define S_MSIXPARERR 22
+#define M_MSIXPARERR 0x7
+
+#define V_MSIXPARERR(x) ((x) << S_MSIXPARERR)
+
+#define S_CFPARERR 18
+#define M_CFPARERR 0xf
+
+#define V_CFPARERR(x) ((x) << S_CFPARERR)
+
+#define S_RFPARERR 14
+#define M_RFPARERR 0xf
+
+#define V_RFPARERR(x) ((x) << S_RFPARERR)
+
+#define S_WFPARERR 12
+#define M_WFPARERR 0x3
+
+#define V_WFPARERR(x) ((x) << S_WFPARERR)
+
+#define S_PIOPARERR 11
+#define V_PIOPARERR(x) ((x) << S_PIOPARERR)
+#define F_PIOPARERR V_PIOPARERR(1U)
+
+#define S_DETUNCECCERR 10
+#define V_DETUNCECCERR(x) ((x) << S_DETUNCECCERR)
+#define F_DETUNCECCERR V_DETUNCECCERR(1U)
+
+#define S_DETCORECCERR 9
+#define V_DETCORECCERR(x) ((x) << S_DETCORECCERR)
+#define F_DETCORECCERR V_DETCORECCERR(1U)
+
+#define S_RCVSPLCMPERR 8
+#define V_RCVSPLCMPERR(x) ((x) << S_RCVSPLCMPERR)
+#define F_RCVSPLCMPERR V_RCVSPLCMPERR(1U)
+
+#define S_UNXSPLCMP 7
+#define V_UNXSPLCMP(x) ((x) << S_UNXSPLCMP)
+#define F_UNXSPLCMP V_UNXSPLCMP(1U)
+
+#define S_SPLCMPDIS 6
+#define V_SPLCMPDIS(x) ((x) << S_SPLCMPDIS)
+#define F_SPLCMPDIS V_SPLCMPDIS(1U)
+
+#define S_DETPARERR 5
+#define V_DETPARERR(x) ((x) << S_DETPARERR)
+#define F_DETPARERR V_DETPARERR(1U)
+
+#define S_SIGSYSERR 4
+#define V_SIGSYSERR(x) ((x) << S_SIGSYSERR)
+#define F_SIGSYSERR V_SIGSYSERR(1U)
+
+#define S_RCVMSTABT 3
+#define V_RCVMSTABT(x) ((x) << S_RCVMSTABT)
+#define F_RCVMSTABT V_RCVMSTABT(1U)
+
+#define S_RCVTARABT 2
+#define V_RCVTARABT(x) ((x) << S_RCVTARABT)
+#define F_RCVTARABT V_RCVTARABT(1U)
+
+#define S_SIGTARABT 1
+#define V_SIGTARABT(x) ((x) << S_SIGTARABT)
+#define F_SIGTARABT V_SIGTARABT(1U)
+
+#define S_MSTDETPARERR 0
+#define V_MSTDETPARERR(x) ((x) << S_MSTDETPARERR)
+#define F_MSTDETPARERR V_MSTDETPARERR(1U)
+
+#define A_PCIX_INT_CAUSE 0x84
+
+#define A_PCIX_CFG 0x88
+
+#define S_CLIDECEN 18
+#define V_CLIDECEN(x) ((x) << S_CLIDECEN)
+#define F_CLIDECEN V_CLIDECEN(1U)
+
+#define A_PCIX_MODE 0x8c
+
+#define S_PCLKRANGE 6
+#define M_PCLKRANGE 0x3
+#define V_PCLKRANGE(x) ((x) << S_PCLKRANGE)
+#define G_PCLKRANGE(x) (((x) >> S_PCLKRANGE) & M_PCLKRANGE)
+
+#define S_PCIXINITPAT 2
+#define M_PCIXINITPAT 0xf
+#define V_PCIXINITPAT(x) ((x) << S_PCIXINITPAT)
+#define G_PCIXINITPAT(x) (((x) >> S_PCIXINITPAT) & M_PCIXINITPAT)
+
+#define S_64BIT 0
+#define V_64BIT(x) ((x) << S_64BIT)
+#define F_64BIT V_64BIT(1U)
+
+#define A_PCIE_INT_ENABLE 0x80
+
+#define S_BISTERR 15
+#define M_BISTERR 0xff
+
+#define V_BISTERR(x) ((x) << S_BISTERR)
+
+#define S_PCIE_MSIXPARERR 12
+#define M_PCIE_MSIXPARERR 0x7
+
+#define V_PCIE_MSIXPARERR(x) ((x) << S_PCIE_MSIXPARERR)
+
+#define S_PCIE_CFPARERR 11
+#define V_PCIE_CFPARERR(x) ((x) << S_PCIE_CFPARERR)
+#define F_PCIE_CFPARERR V_PCIE_CFPARERR(1U)
+
+#define S_PCIE_RFPARERR 10
+#define V_PCIE_RFPARERR(x) ((x) << S_PCIE_RFPARERR)
+#define F_PCIE_RFPARERR V_PCIE_RFPARERR(1U)
+
+#define S_PCIE_WFPARERR 9
+#define V_PCIE_WFPARERR(x) ((x) << S_PCIE_WFPARERR)
+#define F_PCIE_WFPARERR V_PCIE_WFPARERR(1U)
+
+#define S_PCIE_PIOPARERR 8
+#define V_PCIE_PIOPARERR(x) ((x) << S_PCIE_PIOPARERR)
+#define F_PCIE_PIOPARERR V_PCIE_PIOPARERR(1U)
+
+#define S_UNXSPLCPLERRC 7
+#define V_UNXSPLCPLERRC(x) ((x) << S_UNXSPLCPLERRC)
+#define F_UNXSPLCPLERRC V_UNXSPLCPLERRC(1U)
+
+#define S_UNXSPLCPLERRR 6
+#define V_UNXSPLCPLERRR(x) ((x) << S_UNXSPLCPLERRR)
+#define F_UNXSPLCPLERRR V_UNXSPLCPLERRR(1U)
+
+#define S_PEXERR 0
+#define V_PEXERR(x) ((x) << S_PEXERR)
+#define F_PEXERR V_PEXERR(1U)
+
+#define A_PCIE_INT_CAUSE 0x84
+
+#define A_PCIE_CFG 0x88
+
+#define S_PCIE_CLIDECEN 16
+#define V_PCIE_CLIDECEN(x) ((x) << S_PCIE_CLIDECEN)
+#define F_PCIE_CLIDECEN V_PCIE_CLIDECEN(1U)
+
+#define S_CRSTWRMMODE 0
+#define V_CRSTWRMMODE(x) ((x) << S_CRSTWRMMODE)
+#define F_CRSTWRMMODE V_CRSTWRMMODE(1U)
+
+#define A_PCIE_MODE 0x8c
+
+#define S_NUMFSTTRNSEQRX 10
+#define M_NUMFSTTRNSEQRX 0xff
+#define V_NUMFSTTRNSEQRX(x) ((x) << S_NUMFSTTRNSEQRX)
+#define G_NUMFSTTRNSEQRX(x) (((x) >> S_NUMFSTTRNSEQRX) & M_NUMFSTTRNSEQRX)
+
+#define A_PCIE_PEX_CTRL0 0x98
+
+#define S_NUMFSTTRNSEQ 22
+#define M_NUMFSTTRNSEQ 0xff
+#define V_NUMFSTTRNSEQ(x) ((x) << S_NUMFSTTRNSEQ)
+#define G_NUMFSTTRNSEQ(x) (((x) >> S_NUMFSTTRNSEQ) & M_NUMFSTTRNSEQ)
+
+#define S_REPLAYLMT 2
+#define M_REPLAYLMT 0xfffff
+
+#define V_REPLAYLMT(x) ((x) << S_REPLAYLMT)
+
+#define A_PCIE_PEX_CTRL1 0x9c
+
+#define S_T3A_ACKLAT 0
+#define M_T3A_ACKLAT 0x7ff
+
+#define V_T3A_ACKLAT(x) ((x) << S_T3A_ACKLAT)
+
+#define S_ACKLAT 0
+#define M_ACKLAT 0x1fff
+
+#define V_ACKLAT(x) ((x) << S_ACKLAT)
+
+#define A_PCIE_PEX_ERR 0xa4
+
+#define A_T3DBG_GPIO_EN 0xd0
+
+#define S_GPIO11_OEN 27
+#define V_GPIO11_OEN(x) ((x) << S_GPIO11_OEN)
+#define F_GPIO11_OEN V_GPIO11_OEN(1U)
+
+#define S_GPIO10_OEN 26
+#define V_GPIO10_OEN(x) ((x) << S_GPIO10_OEN)
+#define F_GPIO10_OEN V_GPIO10_OEN(1U)
+
+#define S_GPIO7_OEN 23
+#define V_GPIO7_OEN(x) ((x) << S_GPIO7_OEN)
+#define F_GPIO7_OEN V_GPIO7_OEN(1U)
+
+#define S_GPIO6_OEN 22
+#define V_GPIO6_OEN(x) ((x) << S_GPIO6_OEN)
+#define F_GPIO6_OEN V_GPIO6_OEN(1U)
+
+#define S_GPIO5_OEN 21
+#define V_GPIO5_OEN(x) ((x) << S_GPIO5_OEN)
+#define F_GPIO5_OEN V_GPIO5_OEN(1U)
+
+#define S_GPIO4_OEN 20
+#define V_GPIO4_OEN(x) ((x) << S_GPIO4_OEN)
+#define F_GPIO4_OEN V_GPIO4_OEN(1U)
+
+#define S_GPIO2_OEN 18
+#define V_GPIO2_OEN(x) ((x) << S_GPIO2_OEN)
+#define F_GPIO2_OEN V_GPIO2_OEN(1U)
+
+#define S_GPIO1_OEN 17
+#define V_GPIO1_OEN(x) ((x) << S_GPIO1_OEN)
+#define F_GPIO1_OEN V_GPIO1_OEN(1U)
+
+#define S_GPIO0_OEN 16
+#define V_GPIO0_OEN(x) ((x) << S_GPIO0_OEN)
+#define F_GPIO0_OEN V_GPIO0_OEN(1U)
+
+#define S_GPIO10_OUT_VAL 10
+#define V_GPIO10_OUT_VAL(x) ((x) << S_GPIO10_OUT_VAL)
+#define F_GPIO10_OUT_VAL V_GPIO10_OUT_VAL(1U)
+
+#define S_GPIO7_OUT_VAL 7
+#define V_GPIO7_OUT_VAL(x) ((x) << S_GPIO7_OUT_VAL)
+#define F_GPIO7_OUT_VAL V_GPIO7_OUT_VAL(1U)
+
+#define S_GPIO6_OUT_VAL 6
+#define V_GPIO6_OUT_VAL(x) ((x) << S_GPIO6_OUT_VAL)
+#define F_GPIO6_OUT_VAL V_GPIO6_OUT_VAL(1U)
+
+#define S_GPIO5_OUT_VAL 5
+#define V_GPIO5_OUT_VAL(x) ((x) << S_GPIO5_OUT_VAL)
+#define F_GPIO5_OUT_VAL V_GPIO5_OUT_VAL(1U)
+
+#define S_GPIO4_OUT_VAL 4
+#define V_GPIO4_OUT_VAL(x) ((x) << S_GPIO4_OUT_VAL)
+#define F_GPIO4_OUT_VAL V_GPIO4_OUT_VAL(1U)
+
+#define S_GPIO2_OUT_VAL 2
+#define V_GPIO2_OUT_VAL(x) ((x) << S_GPIO2_OUT_VAL)
+#define F_GPIO2_OUT_VAL V_GPIO2_OUT_VAL(1U)
+
+#define S_GPIO1_OUT_VAL 1
+#define V_GPIO1_OUT_VAL(x) ((x) << S_GPIO1_OUT_VAL)
+#define F_GPIO1_OUT_VAL V_GPIO1_OUT_VAL(1U)
+
+#define S_GPIO0_OUT_VAL 0
+#define V_GPIO0_OUT_VAL(x) ((x) << S_GPIO0_OUT_VAL)
+#define F_GPIO0_OUT_VAL V_GPIO0_OUT_VAL(1U)
+
+#define A_T3DBG_INT_ENABLE 0xd8
+
+#define S_GPIO11 11
+#define V_GPIO11(x) ((x) << S_GPIO11)
+#define F_GPIO11 V_GPIO11(1U)
+
+#define S_GPIO10 10
+#define V_GPIO10(x) ((x) << S_GPIO10)
+#define F_GPIO10 V_GPIO10(1U)
+
+#define S_GPIO7 7
+#define V_GPIO7(x) ((x) << S_GPIO7)
+#define F_GPIO7 V_GPIO7(1U)
+
+#define S_GPIO6 6
+#define V_GPIO6(x) ((x) << S_GPIO6)
+#define F_GPIO6 V_GPIO6(1U)
+
+#define S_GPIO5 5
+#define V_GPIO5(x) ((x) << S_GPIO5)
+#define F_GPIO5 V_GPIO5(1U)
+
+#define S_GPIO4 4
+#define V_GPIO4(x) ((x) << S_GPIO4)
+#define F_GPIO4 V_GPIO4(1U)
+
+#define S_GPIO3 3
+#define V_GPIO3(x) ((x) << S_GPIO3)
+#define F_GPIO3 V_GPIO3(1U)
+
+#define S_GPIO2 2
+#define V_GPIO2(x) ((x) << S_GPIO2)
+#define F_GPIO2 V_GPIO2(1U)
+
+#define S_GPIO1 1
+#define V_GPIO1(x) ((x) << S_GPIO1)
+#define F_GPIO1 V_GPIO1(1U)
+
+#define S_GPIO0 0
+#define V_GPIO0(x) ((x) << S_GPIO0)
+#define F_GPIO0 V_GPIO0(1U)
+
+#define A_T3DBG_INT_CAUSE 0xdc
+
+#define A_T3DBG_GPIO_ACT_LOW 0xf0
+
+#define MC7_PMRX_BASE_ADDR 0x100
+
+#define A_MC7_CFG 0x100
+
+#define S_IFEN 13
+#define V_IFEN(x) ((x) << S_IFEN)
+#define F_IFEN V_IFEN(1U)
+
+#define S_TERM150 11
+#define V_TERM150(x) ((x) << S_TERM150)
+#define F_TERM150 V_TERM150(1U)
+
+#define S_SLOW 10
+#define V_SLOW(x) ((x) << S_SLOW)
+#define F_SLOW V_SLOW(1U)
+
+#define S_WIDTH 8
+#define M_WIDTH 0x3
+#define V_WIDTH(x) ((x) << S_WIDTH)
+#define G_WIDTH(x) (((x) >> S_WIDTH) & M_WIDTH)
+
+#define S_BKS 6
+#define V_BKS(x) ((x) << S_BKS)
+#define F_BKS V_BKS(1U)
+
+#define S_ORG 5
+#define V_ORG(x) ((x) << S_ORG)
+#define F_ORG V_ORG(1U)
+
+#define S_DEN 2
+#define M_DEN 0x7
+#define V_DEN(x) ((x) << S_DEN)
+#define G_DEN(x) (((x) >> S_DEN) & M_DEN)
+
+#define S_RDY 1
+#define V_RDY(x) ((x) << S_RDY)
+#define F_RDY V_RDY(1U)
+
+#define S_CLKEN 0
+#define V_CLKEN(x) ((x) << S_CLKEN)
+#define F_CLKEN V_CLKEN(1U)
+
+#define A_MC7_MODE 0x104
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define A_MC7_EXT_MODE1 0x108
+
+#define A_MC7_EXT_MODE2 0x10c
+
+#define A_MC7_EXT_MODE3 0x110
+
+#define A_MC7_PRE 0x114
+
+#define A_MC7_REF 0x118
+
+#define S_PREREFDIV 1
+#define M_PREREFDIV 0x3fff
+#define V_PREREFDIV(x) ((x) << S_PREREFDIV)
+
+#define S_PERREFEN 0
+#define V_PERREFEN(x) ((x) << S_PERREFEN)
+#define F_PERREFEN V_PERREFEN(1U)
+
+#define A_MC7_DLL 0x11c
+
+#define S_DLLENB 1
+#define V_DLLENB(x) ((x) << S_DLLENB)
+#define F_DLLENB V_DLLENB(1U)
+
+#define S_DLLRST 0
+#define V_DLLRST(x) ((x) << S_DLLRST)
+#define F_DLLRST V_DLLRST(1U)
+
+#define A_MC7_PARM 0x120
+
+#define S_ACTTOPREDLY 26
+#define M_ACTTOPREDLY 0xf
+#define V_ACTTOPREDLY(x) ((x) << S_ACTTOPREDLY)
+
+#define S_ACTTORDWRDLY 23
+#define M_ACTTORDWRDLY 0x7
+#define V_ACTTORDWRDLY(x) ((x) << S_ACTTORDWRDLY)
+
+#define S_PRECYC 20
+#define M_PRECYC 0x7
+#define V_PRECYC(x) ((x) << S_PRECYC)
+
+#define S_REFCYC 13
+#define M_REFCYC 0x7f
+#define V_REFCYC(x) ((x) << S_REFCYC)
+
+#define S_BKCYC 8
+#define M_BKCYC 0x1f
+#define V_BKCYC(x) ((x) << S_BKCYC)
+
+#define S_WRTORDDLY 4
+#define M_WRTORDDLY 0xf
+#define V_WRTORDDLY(x) ((x) << S_WRTORDDLY)
+
+#define S_RDTOWRDLY 0
+#define M_RDTOWRDLY 0xf
+#define V_RDTOWRDLY(x) ((x) << S_RDTOWRDLY)
+
+#define A_MC7_CAL 0x128
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define S_CAL_FAULT 30
+#define V_CAL_FAULT(x) ((x) << S_CAL_FAULT)
+#define F_CAL_FAULT V_CAL_FAULT(1U)
+
+#define S_SGL_CAL_EN 20
+#define V_SGL_CAL_EN(x) ((x) << S_SGL_CAL_EN)
+#define F_SGL_CAL_EN V_SGL_CAL_EN(1U)
+
+#define A_MC7_ERR_ADDR 0x12c
+
+#define A_MC7_ECC 0x130
+
+#define S_ECCCHKEN 1
+#define V_ECCCHKEN(x) ((x) << S_ECCCHKEN)
+#define F_ECCCHKEN V_ECCCHKEN(1U)
+
+#define S_ECCGENEN 0
+#define V_ECCGENEN(x) ((x) << S_ECCGENEN)
+#define F_ECCGENEN V_ECCGENEN(1U)
+
+#define A_MC7_CE_ADDR 0x134
+
+#define A_MC7_CE_DATA0 0x138
+
+#define A_MC7_CE_DATA1 0x13c
+
+#define A_MC7_CE_DATA2 0x140
+
+#define S_DATA 0
+#define M_DATA 0xff
+
+#define G_DATA(x) (((x) >> S_DATA) & M_DATA)
+
+#define A_MC7_UE_ADDR 0x144
+
+#define A_MC7_UE_DATA0 0x148
+
+#define A_MC7_UE_DATA1 0x14c
+
+#define A_MC7_UE_DATA2 0x150
+
+#define A_MC7_BD_ADDR 0x154
+
+#define S_ADDR 3
+
+#define M_ADDR 0x1fffffff
+
+#define A_MC7_BD_DATA0 0x158
+
+#define A_MC7_BD_DATA1 0x15c
+
+#define A_MC7_BD_OP 0x164
+
+#define S_OP 0
+
+#define V_OP(x) ((x) << S_OP)
+#define F_OP V_OP(1U)
+
+#define F_OP V_OP(1U)
+#define A_SF_OP 0x6dc
+
+#define A_MC7_BIST_ADDR_BEG 0x168
+
+#define A_MC7_BIST_ADDR_END 0x16c
+
+#define A_MC7_BIST_DATA 0x170
+
+#define A_MC7_BIST_OP 0x174
+
+#define S_CONT 3
+#define V_CONT(x) ((x) << S_CONT)
+#define F_CONT V_CONT(1U)
+
+#define F_CONT V_CONT(1U)
+
+#define A_MC7_INT_ENABLE 0x178
+
+#define S_AE 17
+#define V_AE(x) ((x) << S_AE)
+#define F_AE V_AE(1U)
+
+#define S_PE 2
+#define M_PE 0x7fff
+
+#define V_PE(x) ((x) << S_PE)
+
+#define G_PE(x) (((x) >> S_PE) & M_PE)
+
+#define S_UE 1
+#define V_UE(x) ((x) << S_UE)
+#define F_UE V_UE(1U)
+
+#define S_CE 0
+#define V_CE(x) ((x) << S_CE)
+#define F_CE V_CE(1U)
+
+#define A_MC7_INT_CAUSE 0x17c
+
+#define MC7_PMTX_BASE_ADDR 0x180
+
+#define MC7_CM_BASE_ADDR 0x200
+
+#define A_CIM_BOOT_CFG 0x280
+
+#define S_BOOTADDR 2
+#define M_BOOTADDR 0x3fffffff
+#define V_BOOTADDR(x) ((x) << S_BOOTADDR)
+
+#define A_CIM_SDRAM_BASE_ADDR 0x28c
+
+#define A_CIM_SDRAM_ADDR_SIZE 0x290
+
+#define A_CIM_HOST_INT_ENABLE 0x298
+
+#define A_CIM_HOST_INT_CAUSE 0x29c
+
+#define S_BLKWRPLINT 12
+#define V_BLKWRPLINT(x) ((x) << S_BLKWRPLINT)
+#define F_BLKWRPLINT V_BLKWRPLINT(1U)
+
+#define S_BLKRDPLINT 11
+#define V_BLKRDPLINT(x) ((x) << S_BLKRDPLINT)
+#define F_BLKRDPLINT V_BLKRDPLINT(1U)
+
+#define S_BLKWRCTLINT 10
+#define V_BLKWRCTLINT(x) ((x) << S_BLKWRCTLINT)
+#define F_BLKWRCTLINT V_BLKWRCTLINT(1U)
+
+#define S_BLKRDCTLINT 9
+#define V_BLKRDCTLINT(x) ((x) << S_BLKRDCTLINT)
+#define F_BLKRDCTLINT V_BLKRDCTLINT(1U)
+
+#define S_BLKWRFLASHINT 8
+#define V_BLKWRFLASHINT(x) ((x) << S_BLKWRFLASHINT)
+#define F_BLKWRFLASHINT V_BLKWRFLASHINT(1U)
+
+#define S_BLKRDFLASHINT 7
+#define V_BLKRDFLASHINT(x) ((x) << S_BLKRDFLASHINT)
+#define F_BLKRDFLASHINT V_BLKRDFLASHINT(1U)
+
+#define S_SGLWRFLASHINT 6
+#define V_SGLWRFLASHINT(x) ((x) << S_SGLWRFLASHINT)
+#define F_SGLWRFLASHINT V_SGLWRFLASHINT(1U)
+
+#define S_WRBLKFLASHINT 5
+#define V_WRBLKFLASHINT(x) ((x) << S_WRBLKFLASHINT)
+#define F_WRBLKFLASHINT V_WRBLKFLASHINT(1U)
+
+#define S_BLKWRBOOTINT 4
+#define V_BLKWRBOOTINT(x) ((x) << S_BLKWRBOOTINT)
+#define F_BLKWRBOOTINT V_BLKWRBOOTINT(1U)
+
+#define S_FLASHRANGEINT 2
+#define V_FLASHRANGEINT(x) ((x) << S_FLASHRANGEINT)
+#define F_FLASHRANGEINT V_FLASHRANGEINT(1U)
+
+#define S_SDRAMRANGEINT 1
+#define V_SDRAMRANGEINT(x) ((x) << S_SDRAMRANGEINT)
+#define F_SDRAMRANGEINT V_SDRAMRANGEINT(1U)
+
+#define S_RSVDSPACEINT 0
+#define V_RSVDSPACEINT(x) ((x) << S_RSVDSPACEINT)
+#define F_RSVDSPACEINT V_RSVDSPACEINT(1U)
+
+#define A_CIM_HOST_ACC_CTRL 0x2b0
+
+#define S_HOSTBUSY 17
+#define V_HOSTBUSY(x) ((x) << S_HOSTBUSY)
+#define F_HOSTBUSY V_HOSTBUSY(1U)
+
+#define A_CIM_HOST_ACC_DATA 0x2b4
+
+#define A_TP_IN_CONFIG 0x300
+
+#define S_NICMODE 14
+#define V_NICMODE(x) ((x) << S_NICMODE)
+#define F_NICMODE V_NICMODE(1U)
+
+#define F_NICMODE V_NICMODE(1U)
+
+#define S_IPV6ENABLE 15
+#define V_IPV6ENABLE(x) ((x) << S_IPV6ENABLE)
+#define F_IPV6ENABLE V_IPV6ENABLE(1U)
+
+#define A_TP_OUT_CONFIG 0x304
+
+#define S_VLANEXTRACTIONENABLE 12
+
+#define A_TP_GLOBAL_CONFIG 0x308
+
+#define S_TXPACINGENABLE 24
+#define V_TXPACINGENABLE(x) ((x) << S_TXPACINGENABLE)
+#define F_TXPACINGENABLE V_TXPACINGENABLE(1U)
+
+#define S_PATHMTU 15
+#define V_PATHMTU(x) ((x) << S_PATHMTU)
+#define F_PATHMTU V_PATHMTU(1U)
+
+#define S_IPCHECKSUMOFFLOAD 13
+#define V_IPCHECKSUMOFFLOAD(x) ((x) << S_IPCHECKSUMOFFLOAD)
+#define F_IPCHECKSUMOFFLOAD V_IPCHECKSUMOFFLOAD(1U)
+
+#define S_UDPCHECKSUMOFFLOAD 12
+#define V_UDPCHECKSUMOFFLOAD(x) ((x) << S_UDPCHECKSUMOFFLOAD)
+#define F_UDPCHECKSUMOFFLOAD V_UDPCHECKSUMOFFLOAD(1U)
+
+#define S_TCPCHECKSUMOFFLOAD 11
+#define V_TCPCHECKSUMOFFLOAD(x) ((x) << S_TCPCHECKSUMOFFLOAD)
+#define F_TCPCHECKSUMOFFLOAD V_TCPCHECKSUMOFFLOAD(1U)
+
+#define S_IPTTL 0
+#define M_IPTTL 0xff
+#define V_IPTTL(x) ((x) << S_IPTTL)
+
+#define A_TP_CMM_MM_BASE 0x314
+
+#define A_TP_CMM_TIMER_BASE 0x318
+
+#define S_CMTIMERMAXNUM 28
+#define M_CMTIMERMAXNUM 0x3
+#define V_CMTIMERMAXNUM(x) ((x) << S_CMTIMERMAXNUM)
+
+#define A_TP_PMM_SIZE 0x31c
+
+#define A_TP_PMM_TX_BASE 0x320
+
+#define A_TP_PMM_RX_BASE 0x328
+
+#define A_TP_PMM_RX_PAGE_SIZE 0x32c
+
+#define A_TP_PMM_RX_MAX_PAGE 0x330
+
+#define A_TP_PMM_TX_PAGE_SIZE 0x334
+
+#define A_TP_PMM_TX_MAX_PAGE 0x338
+
+#define A_TP_TCP_OPTIONS 0x340
+
+#define S_MTUDEFAULT 16
+#define M_MTUDEFAULT 0xffff
+#define V_MTUDEFAULT(x) ((x) << S_MTUDEFAULT)
+
+#define S_MTUENABLE 10
+#define V_MTUENABLE(x) ((x) << S_MTUENABLE)
+#define F_MTUENABLE V_MTUENABLE(1U)
+
+#define S_SACKRX 8
+#define V_SACKRX(x) ((x) << S_SACKRX)
+#define F_SACKRX V_SACKRX(1U)
+
+#define S_SACKMODE 4
+
+#define M_SACKMODE 0x3
+
+#define V_SACKMODE(x) ((x) << S_SACKMODE)
+
+#define S_WINDOWSCALEMODE 2
+#define M_WINDOWSCALEMODE 0x3
+#define V_WINDOWSCALEMODE(x) ((x) << S_WINDOWSCALEMODE)
+
+#define S_TIMESTAMPSMODE 0
+
+#define M_TIMESTAMPSMODE 0x3
+
+#define V_TIMESTAMPSMODE(x) ((x) << S_TIMESTAMPSMODE)
+
+#define A_TP_DACK_CONFIG 0x344
+
+#define S_AUTOSTATE3 30
+#define M_AUTOSTATE3 0x3
+#define V_AUTOSTATE3(x) ((x) << S_AUTOSTATE3)
+
+#define S_AUTOSTATE2 28
+#define M_AUTOSTATE2 0x3
+#define V_AUTOSTATE2(x) ((x) << S_AUTOSTATE2)
+
+#define S_AUTOSTATE1 26
+#define M_AUTOSTATE1 0x3
+#define V_AUTOSTATE1(x) ((x) << S_AUTOSTATE1)
+
+#define S_BYTETHRESHOLD 5
+#define M_BYTETHRESHOLD 0xfffff
+#define V_BYTETHRESHOLD(x) ((x) << S_BYTETHRESHOLD)
+
+#define S_MSSTHRESHOLD 3
+#define M_MSSTHRESHOLD 0x3
+#define V_MSSTHRESHOLD(x) ((x) << S_MSSTHRESHOLD)
+
+#define S_AUTOCAREFUL 2
+#define V_AUTOCAREFUL(x) ((x) << S_AUTOCAREFUL)
+#define F_AUTOCAREFUL V_AUTOCAREFUL(1U)
+
+#define S_AUTOENABLE 1
+#define V_AUTOENABLE(x) ((x) << S_AUTOENABLE)
+#define F_AUTOENABLE V_AUTOENABLE(1U)
+
+#define S_DACK_MODE 0
+#define V_DACK_MODE(x) ((x) << S_DACK_MODE)
+#define F_DACK_MODE V_DACK_MODE(1U)
+
+#define A_TP_PC_CONFIG 0x348
+
+#define S_TXTOSQUEUEMAPMODE 26
+#define V_TXTOSQUEUEMAPMODE(x) ((x) << S_TXTOSQUEUEMAPMODE)
+#define F_TXTOSQUEUEMAPMODE V_TXTOSQUEUEMAPMODE(1U)
+
+#define S_ENABLEEPCMDAFULL 23
+#define V_ENABLEEPCMDAFULL(x) ((x) << S_ENABLEEPCMDAFULL)
+#define F_ENABLEEPCMDAFULL V_ENABLEEPCMDAFULL(1U)
+
+#define S_MODULATEUNIONMODE 22
+#define V_MODULATEUNIONMODE(x) ((x) << S_MODULATEUNIONMODE)
+#define F_MODULATEUNIONMODE V_MODULATEUNIONMODE(1U)
+
+#define S_TXDEFERENABLE 20
+#define V_TXDEFERENABLE(x) ((x) << S_TXDEFERENABLE)
+#define F_TXDEFERENABLE V_TXDEFERENABLE(1U)
+
+#define S_RXCONGESTIONMODE 19
+#define V_RXCONGESTIONMODE(x) ((x) << S_RXCONGESTIONMODE)
+#define F_RXCONGESTIONMODE V_RXCONGESTIONMODE(1U)
+
+#define S_HEARBEATDACK 16
+#define V_HEARBEATDACK(x) ((x) << S_HEARBEATDACK)
+#define F_HEARBEATDACK V_HEARBEATDACK(1U)
+
+#define S_TXCONGESTIONMODE 15
+#define V_TXCONGESTIONMODE(x) ((x) << S_TXCONGESTIONMODE)
+#define F_TXCONGESTIONMODE V_TXCONGESTIONMODE(1U)
+
+#define S_ENABLEOCSPIFULL 30
+#define V_ENABLEOCSPIFULL(x) ((x) << S_ENABLEOCSPIFULL)
+#define F_ENABLEOCSPIFULL V_ENABLEOCSPIFULL(1U)
+
+#define S_LOCKTID 28
+#define V_LOCKTID(x) ((x) << S_LOCKTID)
+#define F_LOCKTID V_LOCKTID(1U)
+
+#define A_TP_PC_CONFIG2 0x34c
+
+#define S_CHDRAFULL 4
+#define V_CHDRAFULL(x) ((x) << S_CHDRAFULL)
+#define F_CHDRAFULL V_CHDRAFULL(1U)
+
+#define A_TP_TCP_BACKOFF_REG0 0x350
+
+#define A_TP_TCP_BACKOFF_REG1 0x354
+
+#define A_TP_TCP_BACKOFF_REG2 0x358
+
+#define A_TP_TCP_BACKOFF_REG3 0x35c
+
+#define A_TP_PARA_REG2 0x368
+
+#define S_MAXRXDATA 16
+#define M_MAXRXDATA 0xffff
+#define V_MAXRXDATA(x) ((x) << S_MAXRXDATA)
+
+#define S_RXCOALESCESIZE 0
+#define M_RXCOALESCESIZE 0xffff
+#define V_RXCOALESCESIZE(x) ((x) << S_RXCOALESCESIZE)
+
+#define A_TP_PARA_REG3 0x36c
+
+#define S_TXDATAACKIDX 16
+#define M_TXDATAACKIDX 0xf
+
+#define V_TXDATAACKIDX(x) ((x) << S_TXDATAACKIDX)
+
+#define S_TXPACEAUTOSTRICT 10
+#define V_TXPACEAUTOSTRICT(x) ((x) << S_TXPACEAUTOSTRICT)
+#define F_TXPACEAUTOSTRICT V_TXPACEAUTOSTRICT(1U)
+
+#define S_TXPACEFIXED 9
+#define V_TXPACEFIXED(x) ((x) << S_TXPACEFIXED)
+#define F_TXPACEFIXED V_TXPACEFIXED(1U)
+
+#define S_TXPACEAUTO 8
+#define V_TXPACEAUTO(x) ((x) << S_TXPACEAUTO)
+#define F_TXPACEAUTO V_TXPACEAUTO(1U)
+
+#define S_RXCOALESCEENABLE 1
+#define V_RXCOALESCEENABLE(x) ((x) << S_RXCOALESCEENABLE)
+#define F_RXCOALESCEENABLE V_RXCOALESCEENABLE(1U)
+
+#define S_RXCOALESCEPSHEN 0
+#define V_RXCOALESCEPSHEN(x) ((x) << S_RXCOALESCEPSHEN)
+#define F_RXCOALESCEPSHEN V_RXCOALESCEPSHEN(1U)
+
+#define A_TP_PARA_REG4 0x370
+
+#define A_TP_PARA_REG6 0x378
+
+#define S_T3A_ENABLEESND 13
+#define V_T3A_ENABLEESND(x) ((x) << S_T3A_ENABLEESND)
+#define F_T3A_ENABLEESND V_T3A_ENABLEESND(1U)
+
+#define S_ENABLEESND 11
+#define V_ENABLEESND(x) ((x) << S_ENABLEESND)
+#define F_ENABLEESND V_ENABLEESND(1U)
+
+#define A_TP_PARA_REG7 0x37c
+
+#define S_PMMAXXFERLEN1 16
+#define M_PMMAXXFERLEN1 0xffff
+#define V_PMMAXXFERLEN1(x) ((x) << S_PMMAXXFERLEN1)
+
+#define S_PMMAXXFERLEN0 0
+#define M_PMMAXXFERLEN0 0xffff
+#define V_PMMAXXFERLEN0(x) ((x) << S_PMMAXXFERLEN0)
+
+#define A_TP_TIMER_RESOLUTION 0x390
+
+#define S_TIMERRESOLUTION 16
+#define M_TIMERRESOLUTION 0xff
+#define V_TIMERRESOLUTION(x) ((x) << S_TIMERRESOLUTION)
+
+#define S_TIMESTAMPRESOLUTION 8
+#define M_TIMESTAMPRESOLUTION 0xff
+#define V_TIMESTAMPRESOLUTION(x) ((x) << S_TIMESTAMPRESOLUTION)
+
+#define S_DELAYEDACKRESOLUTION 0
+#define M_DELAYEDACKRESOLUTION 0xff
+#define V_DELAYEDACKRESOLUTION(x) ((x) << S_DELAYEDACKRESOLUTION)
+
+#define A_TP_MSL 0x394
+
+#define A_TP_RXT_MIN 0x398
+
+#define A_TP_RXT_MAX 0x39c
+
+#define A_TP_PERS_MIN 0x3a0
+
+#define A_TP_PERS_MAX 0x3a4
+
+#define A_TP_KEEP_IDLE 0x3a8
+
+#define A_TP_KEEP_INTVL 0x3ac
+
+#define A_TP_INIT_SRTT 0x3b0
+
+#define A_TP_DACK_TIMER 0x3b4
+
+#define A_TP_FINWAIT2_TIMER 0x3b8
+
+#define A_TP_SHIFT_CNT 0x3c0
+
+#define S_SYNSHIFTMAX 24
+
+#define M_SYNSHIFTMAX 0xff
+
+#define V_SYNSHIFTMAX(x) ((x) << S_SYNSHIFTMAX)
+
+#define S_RXTSHIFTMAXR1 20
+
+#define M_RXTSHIFTMAXR1 0xf
+
+#define V_RXTSHIFTMAXR1(x) ((x) << S_RXTSHIFTMAXR1)
+
+#define S_RXTSHIFTMAXR2 16
+
+#define M_RXTSHIFTMAXR2 0xf
+
+#define V_RXTSHIFTMAXR2(x) ((x) << S_RXTSHIFTMAXR2)
+
+#define S_PERSHIFTBACKOFFMAX 12
+#define M_PERSHIFTBACKOFFMAX 0xf
+#define V_PERSHIFTBACKOFFMAX(x) ((x) << S_PERSHIFTBACKOFFMAX)
+
+#define S_PERSHIFTMAX 8
+#define M_PERSHIFTMAX 0xf
+#define V_PERSHIFTMAX(x) ((x) << S_PERSHIFTMAX)
+
+#define S_KEEPALIVEMAX 0
+
+#define M_KEEPALIVEMAX 0xff
+
+#define V_KEEPALIVEMAX(x) ((x) << S_KEEPALIVEMAX)
+
+#define A_TP_MTU_PORT_TABLE 0x3d0
+
+#define A_TP_CCTRL_TABLE 0x3dc
+
+#define A_TP_MTU_TABLE 0x3e4
+
+#define A_TP_RSS_MAP_TABLE 0x3e8
+
+#define A_TP_RSS_LKP_TABLE 0x3ec
+
+#define A_TP_RSS_CONFIG 0x3f0
+
+#define S_TNL4TUPEN 29
+#define V_TNL4TUPEN(x) ((x) << S_TNL4TUPEN)
+#define F_TNL4TUPEN V_TNL4TUPEN(1U)
+
+#define S_TNL2TUPEN 28
+#define V_TNL2TUPEN(x) ((x) << S_TNL2TUPEN)
+#define F_TNL2TUPEN V_TNL2TUPEN(1U)
+
+#define S_TNLPRTEN 26
+#define V_TNLPRTEN(x) ((x) << S_TNLPRTEN)
+#define F_TNLPRTEN V_TNLPRTEN(1U)
+
+#define S_TNLMAPEN 25
+#define V_TNLMAPEN(x) ((x) << S_TNLMAPEN)
+#define F_TNLMAPEN V_TNLMAPEN(1U)
+
+#define S_TNLLKPEN 24
+#define V_TNLLKPEN(x) ((x) << S_TNLLKPEN)
+#define F_TNLLKPEN V_TNLLKPEN(1U)
+
+#define S_RRCPLCPUSIZE 4
+#define M_RRCPLCPUSIZE 0x7
+#define V_RRCPLCPUSIZE(x) ((x) << S_RRCPLCPUSIZE)
+
+#define S_RQFEEDBACKENABLE 3
+#define V_RQFEEDBACKENABLE(x) ((x) << S_RQFEEDBACKENABLE)
+#define F_RQFEEDBACKENABLE V_RQFEEDBACKENABLE(1U)
+
+#define S_DISABLE 0
+
+#define A_TP_TM_PIO_ADDR 0x418
+
+#define A_TP_TM_PIO_DATA 0x41c
+
+#define A_TP_TX_MOD_QUE_TABLE 0x420
+
+#define A_TP_TX_RESOURCE_LIMIT 0x424
+
+#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x428
+
+#define S_TX_MOD_QUEUE_REQ_MAP 0
+#define M_TX_MOD_QUEUE_REQ_MAP 0xff
+#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP)
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT1 0x42c
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x430
+
+#define A_TP_MOD_CHANNEL_WEIGHT 0x434
+
+#define A_TP_PIO_ADDR 0x440
+
+#define A_TP_PIO_DATA 0x444
+
+#define A_TP_RESET 0x44c
+
+#define S_FLSTINITENABLE 1
+#define V_FLSTINITENABLE(x) ((x) << S_FLSTINITENABLE)
+#define F_FLSTINITENABLE V_FLSTINITENABLE(1U)
+
+#define S_TPRESET 0
+#define V_TPRESET(x) ((x) << S_TPRESET)
+#define F_TPRESET V_TPRESET(1U)
+
+#define A_TP_CMM_MM_RX_FLST_BASE 0x460
+
+#define A_TP_CMM_MM_TX_FLST_BASE 0x464
+
+#define A_TP_CMM_MM_PS_FLST_BASE 0x468
+
+#define A_TP_MIB_INDEX 0x450
+
+#define A_TP_MIB_RDATA 0x454
+
+#define A_TP_CMM_MM_MAX_PSTRUCT 0x46c
+
+#define A_TP_INT_ENABLE 0x470
+
+#define A_TP_INT_CAUSE 0x474
+
+#define A_TP_TX_MOD_Q1_Q0_RATE_LIMIT 0x8
+
+#define A_TP_TX_DROP_CFG_CH0 0x12b
+
+#define A_TP_TX_DROP_MODE 0x12f
+
+#define A_TP_EGRESS_CONFIG 0x145
+
+#define S_REWRITEFORCETOSIZE 0
+#define V_REWRITEFORCETOSIZE(x) ((x) << S_REWRITEFORCETOSIZE)
+#define F_REWRITEFORCETOSIZE V_REWRITEFORCETOSIZE(1U)
+
+#define A_TP_TX_TRC_KEY0 0x20
+
+#define A_TP_RX_TRC_KEY0 0x120
+
+#define A_ULPRX_CTL 0x500
+
+#define S_ROUND_ROBIN 4
+#define V_ROUND_ROBIN(x) ((x) << S_ROUND_ROBIN)
+#define F_ROUND_ROBIN V_ROUND_ROBIN(1U)
+
+#define A_ULPRX_INT_ENABLE 0x504
+
+#define S_PARERR 0
+#define V_PARERR(x) ((x) << S_PARERR)
+#define F_PARERR V_PARERR(1U)
+
+#define A_ULPRX_INT_CAUSE 0x508
+
+#define A_ULPRX_ISCSI_LLIMIT 0x50c
+
+#define A_ULPRX_ISCSI_ULIMIT 0x510
+
+#define A_ULPRX_ISCSI_TAGMASK 0x514
+
+#define A_ULPRX_TDDP_LLIMIT 0x51c
+
+#define A_ULPRX_TDDP_ULIMIT 0x520
+
+#define A_ULPRX_STAG_LLIMIT 0x52c
+
+#define A_ULPRX_STAG_ULIMIT 0x530
+
+#define A_ULPRX_RQ_LLIMIT 0x534
+#define A_ULPRX_RQ_LLIMIT 0x534
+
+#define A_ULPRX_RQ_ULIMIT 0x538
+#define A_ULPRX_RQ_ULIMIT 0x538
+
+#define A_ULPRX_PBL_LLIMIT 0x53c
+
+#define A_ULPRX_PBL_ULIMIT 0x540
+#define A_ULPRX_PBL_ULIMIT 0x540
+
+#define A_ULPRX_TDDP_TAGMASK 0x524
+
+#define A_ULPRX_RQ_LLIMIT 0x534
+#define A_ULPRX_RQ_LLIMIT 0x534
+
+#define A_ULPRX_RQ_ULIMIT 0x538
+#define A_ULPRX_RQ_ULIMIT 0x538
+
+#define A_ULPRX_PBL_ULIMIT 0x540
+#define A_ULPRX_PBL_ULIMIT 0x540
+
+#define A_ULPTX_CONFIG 0x580
+
+#define S_CFG_RR_ARB 0
+#define V_CFG_RR_ARB(x) ((x) << S_CFG_RR_ARB)
+#define F_CFG_RR_ARB V_CFG_RR_ARB(1U)
+
+#define A_ULPTX_INT_ENABLE 0x584
+
+#define S_PBL_BOUND_ERR_CH1 1
+#define V_PBL_BOUND_ERR_CH1(x) ((x) << S_PBL_BOUND_ERR_CH1)
+#define F_PBL_BOUND_ERR_CH1 V_PBL_BOUND_ERR_CH1(1U)
+
+#define S_PBL_BOUND_ERR_CH0 0
+#define V_PBL_BOUND_ERR_CH0(x) ((x) << S_PBL_BOUND_ERR_CH0)
+#define F_PBL_BOUND_ERR_CH0 V_PBL_BOUND_ERR_CH0(1U)
+
+#define A_ULPTX_INT_CAUSE 0x588
+
+#define A_ULPTX_TPT_LLIMIT 0x58c
+
+#define A_ULPTX_TPT_ULIMIT 0x590
+
+#define A_ULPTX_PBL_LLIMIT 0x594
+
+#define A_ULPTX_PBL_ULIMIT 0x598
+
+#define A_ULPTX_DMA_WEIGHT 0x5ac
+
+#define S_D1_WEIGHT 16
+#define M_D1_WEIGHT 0xffff
+#define V_D1_WEIGHT(x) ((x) << S_D1_WEIGHT)
+
+#define S_D0_WEIGHT 0
+#define M_D0_WEIGHT 0xffff
+#define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT)
+
+#define A_PM1_RX_CFG 0x5c0
+
+#define A_PM1_RX_INT_ENABLE 0x5d8
+
+#define S_ZERO_E_CMD_ERROR 18
+#define V_ZERO_E_CMD_ERROR(x) ((x) << S_ZERO_E_CMD_ERROR)
+#define F_ZERO_E_CMD_ERROR V_ZERO_E_CMD_ERROR(1U)
+
+#define S_IESPI0_FIFO2X_RX_FRAMING_ERROR 17
+#define V_IESPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_FIFO2X_RX_FRAMING_ERROR)
+#define F_IESPI0_FIFO2X_RX_FRAMING_ERROR V_IESPI0_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_FIFO2X_RX_FRAMING_ERROR 16
+#define V_IESPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_FIFO2X_RX_FRAMING_ERROR)
+#define F_IESPI1_FIFO2X_RX_FRAMING_ERROR V_IESPI1_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI0_RX_FRAMING_ERROR 15
+#define V_IESPI0_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_RX_FRAMING_ERROR)
+#define F_IESPI0_RX_FRAMING_ERROR V_IESPI0_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_RX_FRAMING_ERROR 14
+#define V_IESPI1_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_RX_FRAMING_ERROR)
+#define F_IESPI1_RX_FRAMING_ERROR V_IESPI1_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI0_TX_FRAMING_ERROR 13
+#define V_IESPI0_TX_FRAMING_ERROR(x) ((x) << S_IESPI0_TX_FRAMING_ERROR)
+#define F_IESPI0_TX_FRAMING_ERROR V_IESPI0_TX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_TX_FRAMING_ERROR 12
+#define V_IESPI1_TX_FRAMING_ERROR(x) ((x) << S_IESPI1_TX_FRAMING_ERROR)
+#define F_IESPI1_TX_FRAMING_ERROR V_IESPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_RX_FRAMING_ERROR 11
+#define V_OCSPI0_RX_FRAMING_ERROR(x) ((x) << S_OCSPI0_RX_FRAMING_ERROR)
+#define F_OCSPI0_RX_FRAMING_ERROR V_OCSPI0_RX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_RX_FRAMING_ERROR 10
+#define V_OCSPI1_RX_FRAMING_ERROR(x) ((x) << S_OCSPI1_RX_FRAMING_ERROR)
+#define F_OCSPI1_RX_FRAMING_ERROR V_OCSPI1_RX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_TX_FRAMING_ERROR 9
+#define V_OCSPI0_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_TX_FRAMING_ERROR)
+#define F_OCSPI0_TX_FRAMING_ERROR V_OCSPI0_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_TX_FRAMING_ERROR 8
+#define V_OCSPI1_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_TX_FRAMING_ERROR)
+#define F_OCSPI1_TX_FRAMING_ERROR V_OCSPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR 7
+#define V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR 6
+#define V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_IESPI_PAR_ERROR 3
+#define M_IESPI_PAR_ERROR 0x7
+
+#define V_IESPI_PAR_ERROR(x) ((x) << S_IESPI_PAR_ERROR)
+
+#define S_OCSPI_PAR_ERROR 0
+#define M_OCSPI_PAR_ERROR 0x7
+
+#define V_OCSPI_PAR_ERROR(x) ((x) << S_OCSPI_PAR_ERROR)
+
+#define A_PM1_RX_INT_CAUSE 0x5dc
+
+#define A_PM1_TX_CFG 0x5e0
+
+#define A_PM1_TX_INT_ENABLE 0x5f8
+
+#define S_ZERO_C_CMD_ERROR 18
+#define V_ZERO_C_CMD_ERROR(x) ((x) << S_ZERO_C_CMD_ERROR)
+#define F_ZERO_C_CMD_ERROR V_ZERO_C_CMD_ERROR(1U)
+
+#define S_ICSPI0_FIFO2X_RX_FRAMING_ERROR 17
+#define V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_FIFO2X_RX_FRAMING_ERROR)
+#define F_ICSPI0_FIFO2X_RX_FRAMING_ERROR V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_FIFO2X_RX_FRAMING_ERROR 16
+#define V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_FIFO2X_RX_FRAMING_ERROR)
+#define F_ICSPI1_FIFO2X_RX_FRAMING_ERROR V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI0_RX_FRAMING_ERROR 15
+#define V_ICSPI0_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_RX_FRAMING_ERROR)
+#define F_ICSPI0_RX_FRAMING_ERROR V_ICSPI0_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_RX_FRAMING_ERROR 14
+#define V_ICSPI1_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_RX_FRAMING_ERROR)
+#define F_ICSPI1_RX_FRAMING_ERROR V_ICSPI1_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI0_TX_FRAMING_ERROR 13
+#define V_ICSPI0_TX_FRAMING_ERROR(x) ((x) << S_ICSPI0_TX_FRAMING_ERROR)
+#define F_ICSPI0_TX_FRAMING_ERROR V_ICSPI0_TX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_TX_FRAMING_ERROR 12
+#define V_ICSPI1_TX_FRAMING_ERROR(x) ((x) << S_ICSPI1_TX_FRAMING_ERROR)
+#define F_ICSPI1_TX_FRAMING_ERROR V_ICSPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_RX_FRAMING_ERROR 11
+#define V_OESPI0_RX_FRAMING_ERROR(x) ((x) << S_OESPI0_RX_FRAMING_ERROR)
+#define F_OESPI0_RX_FRAMING_ERROR V_OESPI0_RX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_RX_FRAMING_ERROR 10
+#define V_OESPI1_RX_FRAMING_ERROR(x) ((x) << S_OESPI1_RX_FRAMING_ERROR)
+#define F_OESPI1_RX_FRAMING_ERROR V_OESPI1_RX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_TX_FRAMING_ERROR 9
+#define V_OESPI0_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_TX_FRAMING_ERROR)
+#define F_OESPI0_TX_FRAMING_ERROR V_OESPI0_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_TX_FRAMING_ERROR 8
+#define V_OESPI1_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_TX_FRAMING_ERROR)
+#define F_OESPI1_TX_FRAMING_ERROR V_OESPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_OFIFO2X_TX_FRAMING_ERROR 7
+#define V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OESPI0_OFIFO2X_TX_FRAMING_ERROR V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_OFIFO2X_TX_FRAMING_ERROR 6
+#define V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OESPI1_OFIFO2X_TX_FRAMING_ERROR V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_ICSPI_PAR_ERROR 3
+#define M_ICSPI_PAR_ERROR 0x7
+
+#define V_ICSPI_PAR_ERROR(x) ((x) << S_ICSPI_PAR_ERROR)
+
+#define S_OESPI_PAR_ERROR 0
+#define M_OESPI_PAR_ERROR 0x7
+
+#define V_OESPI_PAR_ERROR(x) ((x) << S_OESPI_PAR_ERROR)
+
+#define A_PM1_TX_INT_CAUSE 0x5fc
+
+#define A_MPS_CFG 0x600
+
+#define S_TPRXPORTEN 4
+#define V_TPRXPORTEN(x) ((x) << S_TPRXPORTEN)
+#define F_TPRXPORTEN V_TPRXPORTEN(1U)
+
+#define S_TPTXPORT1EN 3
+#define V_TPTXPORT1EN(x) ((x) << S_TPTXPORT1EN)
+#define F_TPTXPORT1EN V_TPTXPORT1EN(1U)
+
+#define S_TPTXPORT0EN 2
+#define V_TPTXPORT0EN(x) ((x) << S_TPTXPORT0EN)
+#define F_TPTXPORT0EN V_TPTXPORT0EN(1U)
+
+#define S_PORT1ACTIVE 1
+#define V_PORT1ACTIVE(x) ((x) << S_PORT1ACTIVE)
+#define F_PORT1ACTIVE V_PORT1ACTIVE(1U)
+
+#define S_PORT0ACTIVE 0
+#define V_PORT0ACTIVE(x) ((x) << S_PORT0ACTIVE)
+#define F_PORT0ACTIVE V_PORT0ACTIVE(1U)
+
+#define S_ENFORCEPKT 11
+#define V_ENFORCEPKT(x) ((x) << S_ENFORCEPKT)
+#define F_ENFORCEPKT V_ENFORCEPKT(1U)
+
+#define A_MPS_INT_ENABLE 0x61c
+
+#define S_MCAPARERRENB 6
+#define M_MCAPARERRENB 0x7
+
+#define V_MCAPARERRENB(x) ((x) << S_MCAPARERRENB)
+
+#define S_RXTPPARERRENB 4
+#define M_RXTPPARERRENB 0x3
+
+#define V_RXTPPARERRENB(x) ((x) << S_RXTPPARERRENB)
+
+#define S_TX1TPPARERRENB 2
+#define M_TX1TPPARERRENB 0x3
+
+#define V_TX1TPPARERRENB(x) ((x) << S_TX1TPPARERRENB)
+
+#define S_TX0TPPARERRENB 0
+#define M_TX0TPPARERRENB 0x3
+
+#define V_TX0TPPARERRENB(x) ((x) << S_TX0TPPARERRENB)
+
+#define A_MPS_INT_CAUSE 0x620
+
+#define S_MCAPARERR 6
+#define M_MCAPARERR 0x7
+
+#define V_MCAPARERR(x) ((x) << S_MCAPARERR)
+
+#define S_RXTPPARERR 4
+#define M_RXTPPARERR 0x3
+
+#define V_RXTPPARERR(x) ((x) << S_RXTPPARERR)
+
+#define S_TX1TPPARERR 2
+#define M_TX1TPPARERR 0x3
+
+#define V_TX1TPPARERR(x) ((x) << S_TX1TPPARERR)
+
+#define S_TX0TPPARERR 0
+#define M_TX0TPPARERR 0x3
+
+#define V_TX0TPPARERR(x) ((x) << S_TX0TPPARERR)
+
+#define A_CPL_SWITCH_CNTRL 0x640
+
+#define A_CPL_INTR_ENABLE 0x650
+
+#define S_CIM_OVFL_ERROR 4
+#define V_CIM_OVFL_ERROR(x) ((x) << S_CIM_OVFL_ERROR)
+#define F_CIM_OVFL_ERROR V_CIM_OVFL_ERROR(1U)
+
+#define S_TP_FRAMING_ERROR 3
+#define V_TP_FRAMING_ERROR(x) ((x) << S_TP_FRAMING_ERROR)
+#define F_TP_FRAMING_ERROR V_TP_FRAMING_ERROR(1U)
+
+#define S_SGE_FRAMING_ERROR 2
+#define V_SGE_FRAMING_ERROR(x) ((x) << S_SGE_FRAMING_ERROR)
+#define F_SGE_FRAMING_ERROR V_SGE_FRAMING_ERROR(1U)
+
+#define S_CIM_FRAMING_ERROR 1
+#define V_CIM_FRAMING_ERROR(x) ((x) << S_CIM_FRAMING_ERROR)
+#define F_CIM_FRAMING_ERROR V_CIM_FRAMING_ERROR(1U)
+
+#define S_ZERO_SWITCH_ERROR 0
+#define V_ZERO_SWITCH_ERROR(x) ((x) << S_ZERO_SWITCH_ERROR)
+#define F_ZERO_SWITCH_ERROR V_ZERO_SWITCH_ERROR(1U)
+
+#define A_CPL_INTR_CAUSE 0x654
+
+#define A_CPL_MAP_TBL_DATA 0x65c
+
+#define A_SMB_GLOBAL_TIME_CFG 0x660
+
+#define A_I2C_CFG 0x6a0
+
+#define S_I2C_CLKDIV 0
+#define M_I2C_CLKDIV 0xfff
+#define V_I2C_CLKDIV(x) ((x) << S_I2C_CLKDIV)
+
+#define A_MI1_CFG 0x6b0
+
+#define S_CLKDIV 5
+#define M_CLKDIV 0xff
+#define V_CLKDIV(x) ((x) << S_CLKDIV)
+
+#define S_ST 3
+
+#define M_ST 0x3
+
+#define V_ST(x) ((x) << S_ST)
+
+#define G_ST(x) (((x) >> S_ST) & M_ST)
+
+#define S_PREEN 2
+#define V_PREEN(x) ((x) << S_PREEN)
+#define F_PREEN V_PREEN(1U)
+
+#define S_MDIINV 1
+#define V_MDIINV(x) ((x) << S_MDIINV)
+#define F_MDIINV V_MDIINV(1U)
+
+#define S_MDIEN 0
+#define V_MDIEN(x) ((x) << S_MDIEN)
+#define F_MDIEN V_MDIEN(1U)
+
+#define A_MI1_ADDR 0x6b4
+
+#define S_PHYADDR 5
+#define M_PHYADDR 0x1f
+#define V_PHYADDR(x) ((x) << S_PHYADDR)
+
+#define S_REGADDR 0
+#define M_REGADDR 0x1f
+#define V_REGADDR(x) ((x) << S_REGADDR)
+
+#define A_MI1_DATA 0x6b8
+
+#define A_MI1_OP 0x6bc
+
+#define S_MDI_OP 0
+#define M_MDI_OP 0x3
+#define V_MDI_OP(x) ((x) << S_MDI_OP)
+
+#define A_SF_DATA 0x6d8
+
+#define A_SF_OP 0x6dc
+
+#define S_BYTECNT 1
+#define M_BYTECNT 0x3
+#define V_BYTECNT(x) ((x) << S_BYTECNT)
+
+#define A_PL_INT_ENABLE0 0x6e0
+
+#define S_T3DBG 23
+#define V_T3DBG(x) ((x) << S_T3DBG)
+#define F_T3DBG V_T3DBG(1U)
+
+#define S_XGMAC0_1 20
+#define V_XGMAC0_1(x) ((x) << S_XGMAC0_1)
+#define F_XGMAC0_1 V_XGMAC0_1(1U)
+
+#define S_XGMAC0_0 19
+#define V_XGMAC0_0(x) ((x) << S_XGMAC0_0)
+#define F_XGMAC0_0 V_XGMAC0_0(1U)
+
+#define S_MC5A 18
+#define V_MC5A(x) ((x) << S_MC5A)
+#define F_MC5A V_MC5A(1U)
+
+#define S_CPL_SWITCH 12
+#define V_CPL_SWITCH(x) ((x) << S_CPL_SWITCH)
+#define F_CPL_SWITCH V_CPL_SWITCH(1U)
+
+#define S_MPS0 11
+#define V_MPS0(x) ((x) << S_MPS0)
+#define F_MPS0 V_MPS0(1U)
+
+#define S_PM1_TX 10
+#define V_PM1_TX(x) ((x) << S_PM1_TX)
+#define F_PM1_TX V_PM1_TX(1U)
+
+#define S_PM1_RX 9
+#define V_PM1_RX(x) ((x) << S_PM1_RX)
+#define F_PM1_RX V_PM1_RX(1U)
+
+#define S_ULP2_TX 8
+#define V_ULP2_TX(x) ((x) << S_ULP2_TX)
+#define F_ULP2_TX V_ULP2_TX(1U)
+
+#define S_ULP2_RX 7
+#define V_ULP2_RX(x) ((x) << S_ULP2_RX)
+#define F_ULP2_RX V_ULP2_RX(1U)
+
+#define S_TP1 6
+#define V_TP1(x) ((x) << S_TP1)
+#define F_TP1 V_TP1(1U)
+
+#define S_CIM 5
+#define V_CIM(x) ((x) << S_CIM)
+#define F_CIM V_CIM(1U)
+
+#define S_MC7_CM 4
+#define V_MC7_CM(x) ((x) << S_MC7_CM)
+#define F_MC7_CM V_MC7_CM(1U)
+
+#define S_MC7_PMTX 3
+#define V_MC7_PMTX(x) ((x) << S_MC7_PMTX)
+#define F_MC7_PMTX V_MC7_PMTX(1U)
+
+#define S_MC7_PMRX 2
+#define V_MC7_PMRX(x) ((x) << S_MC7_PMRX)
+#define F_MC7_PMRX V_MC7_PMRX(1U)
+
+#define S_PCIM0 1
+#define V_PCIM0(x) ((x) << S_PCIM0)
+#define F_PCIM0 V_PCIM0(1U)
+
+#define S_SGE3 0
+#define V_SGE3(x) ((x) << S_SGE3)
+#define F_SGE3 V_SGE3(1U)
+
+#define A_PL_INT_CAUSE0 0x6e4
+
+#define A_PL_RST 0x6f0
+
+#define S_CRSTWRM 1
+#define V_CRSTWRM(x) ((x) << S_CRSTWRM)
+#define F_CRSTWRM V_CRSTWRM(1U)
+
+#define A_PL_REV 0x6f4
+
+#define A_PL_CLI 0x6f8
+
+#define A_MC5_DB_CONFIG 0x704
+
+#define S_TMTYPEHI 30
+#define V_TMTYPEHI(x) ((x) << S_TMTYPEHI)
+#define F_TMTYPEHI V_TMTYPEHI(1U)
+
+#define S_TMPARTSIZE 28
+#define M_TMPARTSIZE 0x3
+#define V_TMPARTSIZE(x) ((x) << S_TMPARTSIZE)
+#define G_TMPARTSIZE(x) (((x) >> S_TMPARTSIZE) & M_TMPARTSIZE)
+
+#define S_TMTYPE 26
+#define M_TMTYPE 0x3
+#define V_TMTYPE(x) ((x) << S_TMTYPE)
+#define G_TMTYPE(x) (((x) >> S_TMTYPE) & M_TMTYPE)
+
+#define S_COMPEN 17
+#define V_COMPEN(x) ((x) << S_COMPEN)
+#define F_COMPEN V_COMPEN(1U)
+
+#define S_PRTYEN 6
+#define V_PRTYEN(x) ((x) << S_PRTYEN)
+#define F_PRTYEN V_PRTYEN(1U)
+
+#define S_MBUSEN 5
+#define V_MBUSEN(x) ((x) << S_MBUSEN)
+#define F_MBUSEN V_MBUSEN(1U)
+
+#define S_DBGIEN 4
+#define V_DBGIEN(x) ((x) << S_DBGIEN)
+#define F_DBGIEN V_DBGIEN(1U)
+
+#define S_TMRDY 2
+#define V_TMRDY(x) ((x) << S_TMRDY)
+#define F_TMRDY V_TMRDY(1U)
+
+#define S_TMRST 1
+#define V_TMRST(x) ((x) << S_TMRST)
+#define F_TMRST V_TMRST(1U)
+
+#define S_TMMODE 0
+#define V_TMMODE(x) ((x) << S_TMMODE)
+#define F_TMMODE V_TMMODE(1U)
+
+#define F_TMMODE V_TMMODE(1U)
+
+#define A_MC5_DB_ROUTING_TABLE_INDEX 0x70c
+
+#define A_MC5_DB_FILTER_TABLE 0x710
+
+#define A_MC5_DB_SERVER_INDEX 0x714
+
+#define A_MC5_DB_RSP_LATENCY 0x720
+
+#define S_RDLAT 16
+#define M_RDLAT 0x1f
+#define V_RDLAT(x) ((x) << S_RDLAT)
+
+#define S_LRNLAT 8
+#define M_LRNLAT 0x1f
+#define V_LRNLAT(x) ((x) << S_LRNLAT)
+
+#define S_SRCHLAT 0
+#define M_SRCHLAT 0x1f
+#define V_SRCHLAT(x) ((x) << S_SRCHLAT)
+
+#define A_MC5_DB_PART_ID_INDEX 0x72c
+
+#define A_MC5_DB_INT_ENABLE 0x740
+
+#define S_DELACTEMPTY 18
+#define V_DELACTEMPTY(x) ((x) << S_DELACTEMPTY)
+#define F_DELACTEMPTY V_DELACTEMPTY(1U)
+
+#define S_DISPQPARERR 17
+#define V_DISPQPARERR(x) ((x) << S_DISPQPARERR)
+#define F_DISPQPARERR V_DISPQPARERR(1U)
+
+#define S_REQQPARERR 16
+#define V_REQQPARERR(x) ((x) << S_REQQPARERR)
+#define F_REQQPARERR V_REQQPARERR(1U)
+
+#define S_UNKNOWNCMD 15
+#define V_UNKNOWNCMD(x) ((x) << S_UNKNOWNCMD)
+#define F_UNKNOWNCMD V_UNKNOWNCMD(1U)
+
+#define S_NFASRCHFAIL 8
+#define V_NFASRCHFAIL(x) ((x) << S_NFASRCHFAIL)
+#define F_NFASRCHFAIL V_NFASRCHFAIL(1U)
+
+#define S_ACTRGNFULL 7
+#define V_ACTRGNFULL(x) ((x) << S_ACTRGNFULL)
+#define F_ACTRGNFULL V_ACTRGNFULL(1U)
+
+#define S_PARITYERR 6
+#define V_PARITYERR(x) ((x) << S_PARITYERR)
+#define F_PARITYERR V_PARITYERR(1U)
+
+#define A_MC5_DB_INT_CAUSE 0x744
+
+#define A_MC5_DB_DBGI_CONFIG 0x774
+
+#define A_MC5_DB_DBGI_REQ_CMD 0x778
+
+#define A_MC5_DB_DBGI_REQ_ADDR0 0x77c
+
+#define A_MC5_DB_DBGI_REQ_ADDR1 0x780
+
+#define A_MC5_DB_DBGI_REQ_ADDR2 0x784
+
+#define A_MC5_DB_DBGI_REQ_DATA0 0x788
+
+#define A_MC5_DB_DBGI_REQ_DATA1 0x78c
+
+#define A_MC5_DB_DBGI_REQ_DATA2 0x790
+
+#define A_MC5_DB_DBGI_RSP_STATUS 0x7b0
+
+#define S_DBGIRSPVALID 0
+#define V_DBGIRSPVALID(x) ((x) << S_DBGIRSPVALID)
+#define F_DBGIRSPVALID V_DBGIRSPVALID(1U)
+
+#define A_MC5_DB_DBGI_RSP_DATA0 0x7b4
+
+#define A_MC5_DB_DBGI_RSP_DATA1 0x7b8
+
+#define A_MC5_DB_DBGI_RSP_DATA2 0x7bc
+
+#define A_MC5_DB_POPEN_DATA_WR_CMD 0x7cc
+
+#define A_MC5_DB_POPEN_MASK_WR_CMD 0x7d0
+
+#define A_MC5_DB_AOPEN_SRCH_CMD 0x7d4
+
+#define A_MC5_DB_AOPEN_LRN_CMD 0x7d8
+
+#define A_MC5_DB_SYN_SRCH_CMD 0x7dc
+
+#define A_MC5_DB_SYN_LRN_CMD 0x7e0
+
+#define A_MC5_DB_ACK_SRCH_CMD 0x7e4
+
+#define A_MC5_DB_ACK_LRN_CMD 0x7e8
+
+#define A_MC5_DB_ILOOKUP_CMD 0x7ec
+
+#define A_MC5_DB_ELOOKUP_CMD 0x7f0
+
+#define A_MC5_DB_DATA_WRITE_CMD 0x7f4
+
+#define A_MC5_DB_DATA_READ_CMD 0x7f8
+
+#define XGMAC0_0_BASE_ADDR 0x800
+
+#define A_XGM_TX_CTRL 0x800
+
+#define S_TXEN 0
+#define V_TXEN(x) ((x) << S_TXEN)
+#define F_TXEN V_TXEN(1U)
+
+#define A_XGM_TX_CFG 0x804
+
+#define S_TXPAUSEEN 0
+#define V_TXPAUSEEN(x) ((x) << S_TXPAUSEEN)
+#define F_TXPAUSEEN V_TXPAUSEEN(1U)
+
+#define A_XGM_RX_CTRL 0x80c
+
+#define S_RXEN 0
+#define V_RXEN(x) ((x) << S_RXEN)
+#define F_RXEN V_RXEN(1U)
+
+#define A_XGM_RX_CFG 0x810
+
+#define S_DISPAUSEFRAMES 9
+#define V_DISPAUSEFRAMES(x) ((x) << S_DISPAUSEFRAMES)
+#define F_DISPAUSEFRAMES V_DISPAUSEFRAMES(1U)
+
+#define S_EN1536BFRAMES 8
+#define V_EN1536BFRAMES(x) ((x) << S_EN1536BFRAMES)
+#define F_EN1536BFRAMES V_EN1536BFRAMES(1U)
+
+#define S_ENJUMBO 7
+#define V_ENJUMBO(x) ((x) << S_ENJUMBO)
+#define F_ENJUMBO V_ENJUMBO(1U)
+
+#define S_RMFCS 6
+#define V_RMFCS(x) ((x) << S_RMFCS)
+#define F_RMFCS V_RMFCS(1U)
+
+#define S_ENHASHMCAST 2
+#define V_ENHASHMCAST(x) ((x) << S_ENHASHMCAST)
+#define F_ENHASHMCAST V_ENHASHMCAST(1U)
+
+#define S_COPYALLFRAMES 0
+#define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES)
+#define F_COPYALLFRAMES V_COPYALLFRAMES(1U)
+
+#define A_XGM_RX_HASH_LOW 0x814
+
+#define A_XGM_RX_HASH_HIGH 0x818
+
+#define A_XGM_RX_EXACT_MATCH_LOW_1 0x81c
+
+#define A_XGM_RX_EXACT_MATCH_HIGH_1 0x820
+
+#define A_XGM_RX_EXACT_MATCH_LOW_2 0x824
+
+#define A_XGM_RX_EXACT_MATCH_LOW_3 0x82c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_4 0x834
+
+#define A_XGM_RX_EXACT_MATCH_LOW_5 0x83c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_6 0x844
+
+#define A_XGM_RX_EXACT_MATCH_LOW_7 0x84c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854
+
+#define A_XGM_STAT_CTRL 0x880
+
+#define S_CLRSTATS 2
+#define V_CLRSTATS(x) ((x) << S_CLRSTATS)
+#define F_CLRSTATS V_CLRSTATS(1U)
+
+#define A_XGM_RXFIFO_CFG 0x884
+
+#define S_RXFIFOPAUSEHWM 17
+#define M_RXFIFOPAUSEHWM 0xfff
+
+#define V_RXFIFOPAUSEHWM(x) ((x) << S_RXFIFOPAUSEHWM)
+
+#define G_RXFIFOPAUSEHWM(x) (((x) >> S_RXFIFOPAUSEHWM) & M_RXFIFOPAUSEHWM)
+
+#define S_RXFIFOPAUSELWM 5
+#define M_RXFIFOPAUSELWM 0xfff
+
+#define V_RXFIFOPAUSELWM(x) ((x) << S_RXFIFOPAUSELWM)
+
+#define G_RXFIFOPAUSELWM(x) (((x) >> S_RXFIFOPAUSELWM) & M_RXFIFOPAUSELWM)
+
+#define S_RXSTRFRWRD 1
+#define V_RXSTRFRWRD(x) ((x) << S_RXSTRFRWRD)
+#define F_RXSTRFRWRD V_RXSTRFRWRD(1U)
+
+#define S_DISERRFRAMES 0
+#define V_DISERRFRAMES(x) ((x) << S_DISERRFRAMES)
+#define F_DISERRFRAMES V_DISERRFRAMES(1U)
+
+#define A_XGM_TXFIFO_CFG 0x888
+
+#define S_TXFIFOTHRESH 4
+#define M_TXFIFOTHRESH 0x1ff
+
+#define V_TXFIFOTHRESH(x) ((x) << S_TXFIFOTHRESH)
+
+#define A_XGM_SERDES_CTRL 0x890
+#define A_XGM_SERDES_CTRL0 0x8e0
+
+#define S_SERDESRESET_ 24
+#define V_SERDESRESET_(x) ((x) << S_SERDESRESET_)
+#define F_SERDESRESET_ V_SERDESRESET_(1U)
+
+#define S_RXENABLE 4
+#define V_RXENABLE(x) ((x) << S_RXENABLE)
+#define F_RXENABLE V_RXENABLE(1U)
+
+#define S_TXENABLE 3
+#define V_TXENABLE(x) ((x) << S_TXENABLE)
+#define F_TXENABLE V_TXENABLE(1U)
+
+#define A_XGM_PAUSE_TIMER 0x890
+
+#define A_XGM_RGMII_IMP 0x89c
+
+#define S_XGM_IMPSETUPDATE 6
+#define V_XGM_IMPSETUPDATE(x) ((x) << S_XGM_IMPSETUPDATE)
+#define F_XGM_IMPSETUPDATE V_XGM_IMPSETUPDATE(1U)
+
+#define S_RGMIIIMPPD 3
+#define M_RGMIIIMPPD 0x7
+#define V_RGMIIIMPPD(x) ((x) << S_RGMIIIMPPD)
+
+#define S_RGMIIIMPPU 0
+#define M_RGMIIIMPPU 0x7
+#define V_RGMIIIMPPU(x) ((x) << S_RGMIIIMPPU)
+
+#define S_CALRESET 8
+#define V_CALRESET(x) ((x) << S_CALRESET)
+#define F_CALRESET V_CALRESET(1U)
+
+#define S_CALUPDATE 7
+#define V_CALUPDATE(x) ((x) << S_CALUPDATE)
+#define F_CALUPDATE V_CALUPDATE(1U)
+
+#define A_XGM_XAUI_IMP 0x8a0
+
+#define S_CALBUSY 31
+#define V_CALBUSY(x) ((x) << S_CALBUSY)
+#define F_CALBUSY V_CALBUSY(1U)
+
+#define S_XGM_CALFAULT 29
+#define V_XGM_CALFAULT(x) ((x) << S_XGM_CALFAULT)
+#define F_XGM_CALFAULT V_XGM_CALFAULT(1U)
+
+#define S_CALIMP 24
+#define M_CALIMP 0x1f
+#define V_CALIMP(x) ((x) << S_CALIMP)
+#define G_CALIMP(x) (((x) >> S_CALIMP) & M_CALIMP)
+
+#define S_XAUIIMP 0
+#define M_XAUIIMP 0x7
+#define V_XAUIIMP(x) ((x) << S_XAUIIMP)
+
+#define A_XGM_RX_MAX_PKT_SIZE 0x8a8
+#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4
+
+#define A_XGM_RESET_CTRL 0x8ac
+
+#define S_XG2G_RESET_ 3
+#define V_XG2G_RESET_(x) ((x) << S_XG2G_RESET_)
+#define F_XG2G_RESET_ V_XG2G_RESET_(1U)
+
+#define S_RGMII_RESET_ 2
+#define V_RGMII_RESET_(x) ((x) << S_RGMII_RESET_)
+#define F_RGMII_RESET_ V_RGMII_RESET_(1U)
+
+#define S_PCS_RESET_ 1
+#define V_PCS_RESET_(x) ((x) << S_PCS_RESET_)
+#define F_PCS_RESET_ V_PCS_RESET_(1U)
+
+#define S_MAC_RESET_ 0
+#define V_MAC_RESET_(x) ((x) << S_MAC_RESET_)
+#define F_MAC_RESET_ V_MAC_RESET_(1U)
+
+#define A_XGM_PORT_CFG 0x8b8
+
+#define S_CLKDIVRESET_ 3
+#define V_CLKDIVRESET_(x) ((x) << S_CLKDIVRESET_)
+#define F_CLKDIVRESET_ V_CLKDIVRESET_(1U)
+
+#define S_PORTSPEED 1
+#define M_PORTSPEED 0x3
+
+#define V_PORTSPEED(x) ((x) << S_PORTSPEED)
+
+#define S_ENRGMII 0
+#define V_ENRGMII(x) ((x) << S_ENRGMII)
+#define F_ENRGMII V_ENRGMII(1U)
+
+#define A_XGM_INT_ENABLE 0x8d4
+
+#define S_TXFIFO_PRTY_ERR 17
+#define M_TXFIFO_PRTY_ERR 0x7
+
+#define V_TXFIFO_PRTY_ERR(x) ((x) << S_TXFIFO_PRTY_ERR)
+
+#define S_RXFIFO_PRTY_ERR 14
+#define M_RXFIFO_PRTY_ERR 0x7
+
+#define V_RXFIFO_PRTY_ERR(x) ((x) << S_RXFIFO_PRTY_ERR)
+
+#define S_TXFIFO_UNDERRUN 13
+#define V_TXFIFO_UNDERRUN(x) ((x) << S_TXFIFO_UNDERRUN)
+#define F_TXFIFO_UNDERRUN V_TXFIFO_UNDERRUN(1U)
+
+#define S_RXFIFO_OVERFLOW 12
+#define V_RXFIFO_OVERFLOW(x) ((x) << S_RXFIFO_OVERFLOW)
+#define F_RXFIFO_OVERFLOW V_RXFIFO_OVERFLOW(1U)
+
+#define S_SERDES_LOS 4
+#define M_SERDES_LOS 0xf
+
+#define V_SERDES_LOS(x) ((x) << S_SERDES_LOS)
+
+#define S_XAUIPCSCTCERR 3
+#define V_XAUIPCSCTCERR(x) ((x) << S_XAUIPCSCTCERR)
+#define F_XAUIPCSCTCERR V_XAUIPCSCTCERR(1U)
+
+#define S_XAUIPCSALIGNCHANGE 2
+#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE)
+#define F_XAUIPCSALIGNCHANGE V_XAUIPCSALIGNCHANGE(1U)
+
+#define A_XGM_INT_CAUSE 0x8d8
+
+#define A_XGM_XAUI_ACT_CTRL 0x8dc
+
+#define S_TXACTENABLE 1
+#define V_TXACTENABLE(x) ((x) << S_TXACTENABLE)
+#define F_TXACTENABLE V_TXACTENABLE(1U)
+
+#define A_XGM_SERDES_CTRL0 0x8e0
+
+#define S_RESET3 23
+#define V_RESET3(x) ((x) << S_RESET3)
+#define F_RESET3 V_RESET3(1U)
+
+#define S_RESET2 22
+#define V_RESET2(x) ((x) << S_RESET2)
+#define F_RESET2 V_RESET2(1U)
+
+#define S_RESET1 21
+#define V_RESET1(x) ((x) << S_RESET1)
+#define F_RESET1 V_RESET1(1U)
+
+#define S_RESET0 20
+#define V_RESET0(x) ((x) << S_RESET0)
+#define F_RESET0 V_RESET0(1U)
+
+#define S_PWRDN3 19
+#define V_PWRDN3(x) ((x) << S_PWRDN3)
+#define F_PWRDN3 V_PWRDN3(1U)
+
+#define S_PWRDN2 18
+#define V_PWRDN2(x) ((x) << S_PWRDN2)
+#define F_PWRDN2 V_PWRDN2(1U)
+
+#define S_PWRDN1 17
+#define V_PWRDN1(x) ((x) << S_PWRDN1)
+#define F_PWRDN1 V_PWRDN1(1U)
+
+#define S_PWRDN0 16
+#define V_PWRDN0(x) ((x) << S_PWRDN0)
+#define F_PWRDN0 V_PWRDN0(1U)
+
+#define S_RESETPLL23 15
+#define V_RESETPLL23(x) ((x) << S_RESETPLL23)
+#define F_RESETPLL23 V_RESETPLL23(1U)
+
+#define S_RESETPLL01 14
+#define V_RESETPLL01(x) ((x) << S_RESETPLL01)
+#define F_RESETPLL01 V_RESETPLL01(1U)
+
+#define A_XGM_SERDES_STAT0 0x8f0
+
+#define S_LOWSIG0 0
+#define V_LOWSIG0(x) ((x) << S_LOWSIG0)
+#define F_LOWSIG0 V_LOWSIG0(1U)
+
+#define A_XGM_SERDES_STAT3 0x8fc
+
+#define A_XGM_STAT_TX_BYTE_LOW 0x900
+
+#define A_XGM_STAT_TX_BYTE_HIGH 0x904
+
+#define A_XGM_STAT_TX_FRAME_LOW 0x908
+
+#define A_XGM_STAT_TX_FRAME_HIGH 0x90c
+
+#define A_XGM_STAT_TX_BCAST 0x910
+
+#define A_XGM_STAT_TX_MCAST 0x914
+
+#define A_XGM_STAT_TX_PAUSE 0x918
+
+#define A_XGM_STAT_TX_64B_FRAMES 0x91c
+
+#define A_XGM_STAT_TX_65_127B_FRAMES 0x920
+
+#define A_XGM_STAT_TX_128_255B_FRAMES 0x924
+
+#define A_XGM_STAT_TX_256_511B_FRAMES 0x928
+
+#define A_XGM_STAT_TX_512_1023B_FRAMES 0x92c
+
+#define A_XGM_STAT_TX_1024_1518B_FRAMES 0x930
+
+#define A_XGM_STAT_TX_1519_MAXB_FRAMES 0x934
+
+#define A_XGM_STAT_TX_ERR_FRAMES 0x938
+
+#define A_XGM_STAT_RX_BYTES_LOW 0x93c
+
+#define A_XGM_STAT_RX_BYTES_HIGH 0x940
+
+#define A_XGM_STAT_RX_FRAMES_LOW 0x944
+
+#define A_XGM_STAT_RX_FRAMES_HIGH 0x948
+
+#define A_XGM_STAT_RX_BCAST_FRAMES 0x94c
+
+#define A_XGM_STAT_RX_MCAST_FRAMES 0x950
+
+#define A_XGM_STAT_RX_PAUSE_FRAMES 0x954
+
+#define A_XGM_STAT_RX_64B_FRAMES 0x958
+
+#define A_XGM_STAT_RX_65_127B_FRAMES 0x95c
+
+#define A_XGM_STAT_RX_128_255B_FRAMES 0x960
+
+#define A_XGM_STAT_RX_256_511B_FRAMES 0x964
+
+#define A_XGM_STAT_RX_512_1023B_FRAMES 0x968
+
+#define A_XGM_STAT_RX_1024_1518B_FRAMES 0x96c
+
+#define A_XGM_STAT_RX_1519_MAXB_FRAMES 0x970
+
+#define A_XGM_STAT_RX_SHORT_FRAMES 0x974
+
+#define A_XGM_STAT_RX_OVERSIZE_FRAMES 0x978
+
+#define A_XGM_STAT_RX_JABBER_FRAMES 0x97c
+
+#define A_XGM_STAT_RX_CRC_ERR_FRAMES 0x980
+
+#define A_XGM_STAT_RX_LENGTH_ERR_FRAMES 0x984
+
+#define A_XGM_STAT_RX_SYM_CODE_ERR_FRAMES 0x988
+
+#define A_XGM_SERDES_STATUS0 0x98c
+
+#define A_XGM_SERDES_STATUS1 0x990
+
+#define S_CMULOCK 31
+#define V_CMULOCK(x) ((x) << S_CMULOCK)
+#define F_CMULOCK V_CMULOCK(1U)
+
+#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4
+
+#define A_XGM_RX_SPI4_SOP_EOP_CNT 0x9ac
+
+#define XGMAC0_1_BASE_ADDR 0xa00
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
new file mode 100644
index 00000000000..3f2cf8a07c6
--- /dev/null
+++ b/drivers/net/cxgb3/sge.c
@@ -0,0 +1,2681 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/dma-mapping.h>
+#include "common.h"
+#include "regs.h"
+#include "sge_defs.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+#define USE_GTS 0
+
+#define SGE_RX_SM_BUF_SIZE 1536
+#define SGE_RX_COPY_THRES 256
+
+# define SGE_RX_DROP_THRES 16
+
+/*
+ * Period of the Tx buffer reclaim timer. This timer does not need to run
+ * frequently as Tx buffers are usually reclaimed by new Tx packets.
+ */
+#define TX_RECLAIM_PERIOD (HZ / 4)
+
+/* WR size in bytes */
+#define WR_LEN (WR_FLITS * 8)
+
+/*
+ * Types of Tx queues in each queue set. Order here matters, do not change.
+ */
+enum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL };
+
+/* Values for sge_txq.flags */
+enum {
+ TXQ_RUNNING = 1 << 0, /* fetch engine is running */
+ TXQ_LAST_PKT_DB = 1 << 1, /* last packet rang the doorbell */
+};
+
+struct tx_desc {
+ u64 flit[TX_DESC_FLITS];
+};
+
+struct rx_desc {
+ __be32 addr_lo;
+ __be32 len_gen;
+ __be32 gen2;
+ __be32 addr_hi;
+};
+
+struct tx_sw_desc { /* SW state per Tx descriptor */
+ struct sk_buff *skb;
+};
+
+struct rx_sw_desc { /* SW state per Rx descriptor */
+ struct sk_buff *skb;
+ DECLARE_PCI_UNMAP_ADDR(dma_addr);
+};
+
+struct rsp_desc { /* response queue descriptor */
+ struct rss_header rss_hdr;
+ __be32 flags;
+ __be32 len_cq;
+ u8 imm_data[47];
+ u8 intr_gen;
+};
+
+struct unmap_info { /* packet unmapping info, overlays skb->cb */
+ int sflit; /* start flit of first SGL entry in Tx descriptor */
+ u16 fragidx; /* first page fragment in current Tx descriptor */
+ u16 addr_idx; /* buffer index of first SGL entry in descriptor */
+ u32 len; /* mapped length of skb main body */
+};
+
+/*
+ * Maps a number of flits to the number of Tx descriptors that can hold them.
+ * The formula is
+ *
+ * desc = 1 + (flits - 2) / (WR_FLITS - 1).
+ *
+ * HW allows up to 4 descriptors to be combined into a WR.
+ */
+static u8 flit_desc_map[] = {
+ 0,
+#if SGE_NUM_GENBITS == 1
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+#elif SGE_NUM_GENBITS == 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+#else
+# error "SGE_NUM_GENBITS must be 1 or 2"
+#endif
+};
+
+static inline struct sge_qset *fl_to_qset(const struct sge_fl *q, int qidx)
+{
+ return container_of(q, struct sge_qset, fl[qidx]);
+}
+
+static inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q)
+{
+ return container_of(q, struct sge_qset, rspq);
+}
+
+static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx)
+{
+ return container_of(q, struct sge_qset, txq[qidx]);
+}
+
+/**
+ * refill_rspq - replenish an SGE response queue
+ * @adapter: the adapter
+ * @q: the response queue to replenish
+ * @credits: how many new responses to make available
+ *
+ * Replenishes a response queue by making the supplied number of responses
+ * available to HW.
+ */
+static inline void refill_rspq(struct adapter *adapter,
+ const struct sge_rspq *q, unsigned int credits)
+{
+ t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN,
+ V_RSPQ(q->cntxt_id) | V_CREDITS(credits));
+}
+
+/**
+ * need_skb_unmap - does the platform need unmapping of sk_buffs?
+ *
+ * Returns true if the platfrom needs sk_buff unmapping. The compiler
+ * optimizes away unecessary code if this returns true.
+ */
+static inline int need_skb_unmap(void)
+{
+ /*
+ * This structure is used to tell if the platfrom needs buffer
+ * unmapping by checking if DECLARE_PCI_UNMAP_ADDR defines anything.
+ */
+ struct dummy {
+ DECLARE_PCI_UNMAP_ADDR(addr);
+ };
+
+ return sizeof(struct dummy) != 0;
+}
+
+/**
+ * unmap_skb - unmap a packet main body and its page fragments
+ * @skb: the packet
+ * @q: the Tx queue containing Tx descriptors for the packet
+ * @cidx: index of Tx descriptor
+ * @pdev: the PCI device
+ *
+ * Unmap the main body of an sk_buff and its page fragments, if any.
+ * Because of the fairly complicated structure of our SGLs and the desire
+ * to conserve space for metadata, we keep the information necessary to
+ * unmap an sk_buff partly in the sk_buff itself (in its cb), and partly
+ * in the Tx descriptors (the physical addresses of the various data
+ * buffers). The send functions initialize the state in skb->cb so we
+ * can unmap the buffers held in the first Tx descriptor here, and we
+ * have enough information at this point to update the state for the next
+ * Tx descriptor.
+ */
+static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q,
+ unsigned int cidx, struct pci_dev *pdev)
+{
+ const struct sg_ent *sgp;
+ struct unmap_info *ui = (struct unmap_info *)skb->cb;
+ int nfrags, frag_idx, curflit, j = ui->addr_idx;
+
+ sgp = (struct sg_ent *)&q->desc[cidx].flit[ui->sflit];
+
+ if (ui->len) {
+ pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), ui->len,
+ PCI_DMA_TODEVICE);
+ ui->len = 0; /* so we know for next descriptor for this skb */
+ j = 1;
+ }
+
+ frag_idx = ui->fragidx;
+ curflit = ui->sflit + 1 + j;
+ nfrags = skb_shinfo(skb)->nr_frags;
+
+ while (frag_idx < nfrags && curflit < WR_FLITS) {
+ pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]),
+ skb_shinfo(skb)->frags[frag_idx].size,
+ PCI_DMA_TODEVICE);
+ j ^= 1;
+ if (j == 0) {
+ sgp++;
+ curflit++;
+ }
+ curflit++;
+ frag_idx++;
+ }
+
+ if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */
+ ui->fragidx = frag_idx;
+ ui->addr_idx = j;
+ ui->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */
+ }
+}
+
+/**
+ * free_tx_desc - reclaims Tx descriptors and their buffers
+ * @adapter: the adapter
+ * @q: the Tx queue to reclaim descriptors from
+ * @n: the number of descriptors to reclaim
+ *
+ * Reclaims Tx descriptors from an SGE Tx queue and frees the associated
+ * Tx buffers. Called with the Tx queue lock held.
+ */
+static void free_tx_desc(struct adapter *adapter, struct sge_txq *q,
+ unsigned int n)
+{
+ struct tx_sw_desc *d;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned int cidx = q->cidx;
+
+ d = &q->sdesc[cidx];
+ while (n--) {
+ if (d->skb) { /* an SGL is present */
+ if (need_skb_unmap())
+ unmap_skb(d->skb, q, cidx, pdev);
+ if (d->skb->priority == cidx)
+ kfree_skb(d->skb);
+ }
+ ++d;
+ if (++cidx == q->size) {
+ cidx = 0;
+ d = q->sdesc;
+ }
+ }
+ q->cidx = cidx;
+}
+
+/**
+ * reclaim_completed_tx - reclaims completed Tx descriptors
+ * @adapter: the adapter
+ * @q: the Tx queue to reclaim completed descriptors from
+ *
+ * Reclaims Tx descriptors that the SGE has indicated it has processed,
+ * and frees the associated buffers if possible. Called with the Tx
+ * queue's lock held.
+ */
+static inline void reclaim_completed_tx(struct adapter *adapter,
+ struct sge_txq *q)
+{
+ unsigned int reclaim = q->processed - q->cleaned;
+
+ if (reclaim) {
+ free_tx_desc(adapter, q, reclaim);
+ q->cleaned += reclaim;
+ q->in_use -= reclaim;
+ }
+}
+
+/**
+ * should_restart_tx - are there enough resources to restart a Tx queue?
+ * @q: the Tx queue
+ *
+ * Checks if there are enough descriptors to restart a suspended Tx queue.
+ */
+static inline int should_restart_tx(const struct sge_txq *q)
+{
+ unsigned int r = q->processed - q->cleaned;
+
+ return q->in_use - r < (q->size >> 1);
+}
+
+/**
+ * free_rx_bufs - free the Rx buffers on an SGE free list
+ * @pdev: the PCI device associated with the adapter
+ * @rxq: the SGE free list to clean up
+ *
+ * Release the buffers on an SGE free-buffer Rx queue. HW fetching from
+ * this queue should be stopped before calling this function.
+ */
+static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
+{
+ unsigned int cidx = q->cidx;
+
+ while (q->credits--) {
+ struct rx_sw_desc *d = &q->sdesc[cidx];
+
+ pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
+ q->buf_size, PCI_DMA_FROMDEVICE);
+ kfree_skb(d->skb);
+ d->skb = NULL;
+ if (++cidx == q->size)
+ cidx = 0;
+ }
+}
+
+/**
+ * add_one_rx_buf - add a packet buffer to a free-buffer list
+ * @skb: the buffer to add
+ * @len: the buffer length
+ * @d: the HW Rx descriptor to write
+ * @sd: the SW Rx descriptor to write
+ * @gen: the generation bit value
+ * @pdev: the PCI device associated with the adapter
+ *
+ * Add a buffer of the given length to the supplied HW and SW Rx
+ * descriptors.
+ */
+static inline void add_one_rx_buf(struct sk_buff *skb, unsigned int len,
+ struct rx_desc *d, struct rx_sw_desc *sd,
+ unsigned int gen, struct pci_dev *pdev)
+{
+ dma_addr_t mapping;
+
+ sd->skb = skb;
+ mapping = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE);
+ pci_unmap_addr_set(sd, dma_addr, mapping);
+
+ d->addr_lo = cpu_to_be32(mapping);
+ d->addr_hi = cpu_to_be32((u64) mapping >> 32);
+ wmb();
+ d->len_gen = cpu_to_be32(V_FLD_GEN1(gen));
+ d->gen2 = cpu_to_be32(V_FLD_GEN2(gen));
+}
+
+/**
+ * refill_fl - refill an SGE free-buffer list
+ * @adapter: the adapter
+ * @q: the free-list to refill
+ * @n: the number of new buffers to allocate
+ * @gfp: the gfp flags for allocating new buffers
+ *
+ * (Re)populate an SGE free-buffer list with up to @n new packet buffers,
+ * allocated with the supplied gfp flags. The caller must assure that
+ * @n does not exceed the queue's capacity.
+ */
+static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
+{
+ struct rx_sw_desc *sd = &q->sdesc[q->pidx];
+ struct rx_desc *d = &q->desc[q->pidx];
+
+ while (n--) {
+ struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
+
+ if (!skb)
+ break;
+
+ add_one_rx_buf(skb, q->buf_size, d, sd, q->gen, adap->pdev);
+ d++;
+ sd++;
+ if (++q->pidx == q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ sd = q->sdesc;
+ d = q->desc;
+ }
+ q->credits++;
+ }
+
+ t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+}
+
+static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
+{
+ refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC);
+}
+
+/**
+ * recycle_rx_buf - recycle a receive buffer
+ * @adapter: the adapter
+ * @q: the SGE free list
+ * @idx: index of buffer to recycle
+ *
+ * Recycles the specified buffer on the given free list by adding it at
+ * the next available slot on the list.
+ */
+static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q,
+ unsigned int idx)
+{
+ struct rx_desc *from = &q->desc[idx];
+ struct rx_desc *to = &q->desc[q->pidx];
+
+ q->sdesc[q->pidx] = q->sdesc[idx];
+ to->addr_lo = from->addr_lo; /* already big endian */
+ to->addr_hi = from->addr_hi; /* likewise */
+ wmb();
+ to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen));
+ to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen));
+ q->credits++;
+
+ if (++q->pidx == q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ }
+ t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+}
+
+/**
+ * alloc_ring - allocate resources for an SGE descriptor ring
+ * @pdev: the PCI device
+ * @nelem: the number of descriptors
+ * @elem_size: the size of each descriptor
+ * @sw_size: the size of the SW state associated with each ring element
+ * @phys: the physical address of the allocated ring
+ * @metadata: address of the array holding the SW state for the ring
+ *
+ * Allocates resources for an SGE descriptor ring, such as Tx queues,
+ * free buffer lists, or response queues. Each SGE ring requires
+ * space for its HW descriptors plus, optionally, space for the SW state
+ * associated with each HW entry (the metadata). The function returns
+ * three values: the virtual address for the HW ring (the return value
+ * of the function), the physical address of the HW ring, and the address
+ * of the SW ring.
+ */
+static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size,
+ size_t sw_size, dma_addr_t *phys, void *metadata)
+{
+ size_t len = nelem * elem_size;
+ void *s = NULL;
+ void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL);
+
+ if (!p)
+ return NULL;
+ if (sw_size) {
+ s = kcalloc(nelem, sw_size, GFP_KERNEL);
+
+ if (!s) {
+ dma_free_coherent(&pdev->dev, len, p, *phys);
+ return NULL;
+ }
+ }
+ if (metadata)
+ *(void **)metadata = s;
+ memset(p, 0, len);
+ return p;
+}
+
+/**
+ * free_qset - free the resources of an SGE queue set
+ * @adapter: the adapter owning the queue set
+ * @q: the queue set
+ *
+ * Release the HW and SW resources associated with an SGE queue set, such
+ * as HW contexts, packet buffers, and descriptor rings. Traffic to the
+ * queue set must be quiesced prior to calling this.
+ */
+void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
+{
+ int i;
+ struct pci_dev *pdev = adapter->pdev;
+
+ if (q->tx_reclaim_timer.function)
+ del_timer_sync(&q->tx_reclaim_timer);
+
+ for (i = 0; i < SGE_RXQ_PER_SET; ++i)
+ if (q->fl[i].desc) {
+ spin_lock(&adapter->sge.reg_lock);
+ t3_sge_disable_fl(adapter, q->fl[i].cntxt_id);
+ spin_unlock(&adapter->sge.reg_lock);
+ free_rx_bufs(pdev, &q->fl[i]);
+ kfree(q->fl[i].sdesc);
+ dma_free_coherent(&pdev->dev,
+ q->fl[i].size *
+ sizeof(struct rx_desc), q->fl[i].desc,
+ q->fl[i].phys_addr);
+ }
+
+ for (i = 0; i < SGE_TXQ_PER_SET; ++i)
+ if (q->txq[i].desc) {
+ spin_lock(&adapter->sge.reg_lock);
+ t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0);
+ spin_unlock(&adapter->sge.reg_lock);
+ if (q->txq[i].sdesc) {
+ free_tx_desc(adapter, &q->txq[i],
+ q->txq[i].in_use);
+ kfree(q->txq[i].sdesc);
+ }
+ dma_free_coherent(&pdev->dev,
+ q->txq[i].size *
+ sizeof(struct tx_desc),
+ q->txq[i].desc, q->txq[i].phys_addr);
+ __skb_queue_purge(&q->txq[i].sendq);
+ }
+
+ if (q->rspq.desc) {
+ spin_lock(&adapter->sge.reg_lock);
+ t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id);
+ spin_unlock(&adapter->sge.reg_lock);
+ dma_free_coherent(&pdev->dev,
+ q->rspq.size * sizeof(struct rsp_desc),
+ q->rspq.desc, q->rspq.phys_addr);
+ }
+
+ if (q->netdev)
+ q->netdev->atalk_ptr = NULL;
+
+ memset(q, 0, sizeof(*q));
+}
+
+/**
+ * init_qset_cntxt - initialize an SGE queue set context info
+ * @qs: the queue set
+ * @id: the queue set id
+ *
+ * Initializes the TIDs and context ids for the queues of a queue set.
+ */
+static void init_qset_cntxt(struct sge_qset *qs, unsigned int id)
+{
+ qs->rspq.cntxt_id = id;
+ qs->fl[0].cntxt_id = 2 * id;
+ qs->fl[1].cntxt_id = 2 * id + 1;
+ qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id;
+ qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id;
+ qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id;
+ qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id;
+ qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id;
+}
+
+/**
+ * sgl_len - calculates the size of an SGL of the given capacity
+ * @n: the number of SGL entries
+ *
+ * Calculates the number of flits needed for a scatter/gather list that
+ * can hold the given number of entries.
+ */
+static inline unsigned int sgl_len(unsigned int n)
+{
+ /* alternatively: 3 * (n / 2) + 2 * (n & 1) */
+ return (3 * n) / 2 + (n & 1);
+}
+
+/**
+ * flits_to_desc - returns the num of Tx descriptors for the given flits
+ * @n: the number of flits
+ *
+ * Calculates the number of Tx descriptors needed for the supplied number
+ * of flits.
+ */
+static inline unsigned int flits_to_desc(unsigned int n)
+{
+ BUG_ON(n >= ARRAY_SIZE(flit_desc_map));
+ return flit_desc_map[n];
+}
+
+/**
+ * get_packet - return the next ingress packet buffer from a free list
+ * @adap: the adapter that received the packet
+ * @fl: the SGE free list holding the packet
+ * @len: the packet length including any SGE padding
+ * @drop_thres: # of remaining buffers before we start dropping packets
+ *
+ * Get the next packet from a free list and complete setup of the
+ * sk_buff. If the packet is small we make a copy and recycle the
+ * original buffer, otherwise we use the original buffer itself. If a
+ * positive drop threshold is supplied packets are dropped and their
+ * buffers recycled if (a) the number of remaining buffers is under the
+ * threshold and the packet is too big to copy, or (b) the packet should
+ * be copied but there is no memory for the copy.
+ */
+static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
+ unsigned int len, unsigned int drop_thres)
+{
+ struct sk_buff *skb = NULL;
+ struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+
+ prefetch(sd->skb->data);
+
+ if (len <= SGE_RX_COPY_THRES) {
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (likely(skb != NULL)) {
+ __skb_put(skb, len);
+ pci_dma_sync_single_for_cpu(adap->pdev,
+ pci_unmap_addr(sd,
+ dma_addr),
+ len, PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, sd->skb->data, len);
+ pci_dma_sync_single_for_device(adap->pdev,
+ pci_unmap_addr(sd,
+ dma_addr),
+ len, PCI_DMA_FROMDEVICE);
+ } else if (!drop_thres)
+ goto use_orig_buf;
+ recycle:
+ recycle_rx_buf(adap, fl, fl->cidx);
+ return skb;
+ }
+
+ if (unlikely(fl->credits < drop_thres))
+ goto recycle;
+
+ use_orig_buf:
+ pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+ fl->buf_size, PCI_DMA_FROMDEVICE);
+ skb = sd->skb;
+ skb_put(skb, len);
+ __refill_fl(adap, fl);
+ return skb;
+}
+
+/**
+ * get_imm_packet - return the next ingress packet buffer from a response
+ * @resp: the response descriptor containing the packet data
+ *
+ * Return a packet containing the immediate data of the given response.
+ */
+static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp)
+{
+ struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC);
+
+ if (skb) {
+ __skb_put(skb, IMMED_PKT_SIZE);
+ memcpy(skb->data, resp->imm_data, IMMED_PKT_SIZE);
+ }
+ return skb;
+}
+
+/**
+ * calc_tx_descs - calculate the number of Tx descriptors for a packet
+ * @skb: the packet
+ *
+ * Returns the number of Tx descriptors needed for the given Ethernet
+ * packet. Ethernet packets require addition of WR and CPL headers.
+ */
+static inline unsigned int calc_tx_descs(const struct sk_buff *skb)
+{
+ unsigned int flits;
+
+ if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt))
+ return 1;
+
+ flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2;
+ if (skb_shinfo(skb)->gso_size)
+ flits++;
+ return flits_to_desc(flits);
+}
+
+/**
+ * make_sgl - populate a scatter/gather list for a packet
+ * @skb: the packet
+ * @sgp: the SGL to populate
+ * @start: start address of skb main body data to include in the SGL
+ * @len: length of skb main body data to include in the SGL
+ * @pdev: the PCI device
+ *
+ * Generates a scatter/gather list for the buffers that make up a packet
+ * and returns the SGL size in 8-byte words. The caller must size the SGL
+ * appropriately.
+ */
+static inline unsigned int make_sgl(const struct sk_buff *skb,
+ struct sg_ent *sgp, unsigned char *start,
+ unsigned int len, struct pci_dev *pdev)
+{
+ dma_addr_t mapping;
+ unsigned int i, j = 0, nfrags;
+
+ if (len) {
+ mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE);
+ sgp->len[0] = cpu_to_be32(len);
+ sgp->addr[0] = cpu_to_be64(mapping);
+ j = 1;
+ }
+
+ nfrags = skb_shinfo(skb)->nr_frags;
+ for (i = 0; i < nfrags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ mapping = pci_map_page(pdev, frag->page, frag->page_offset,
+ frag->size, PCI_DMA_TODEVICE);
+ sgp->len[j] = cpu_to_be32(frag->size);
+ sgp->addr[j] = cpu_to_be64(mapping);
+ j ^= 1;
+ if (j == 0)
+ ++sgp;
+ }
+ if (j)
+ sgp->len[j] = 0;
+ return ((nfrags + (len != 0)) * 3) / 2 + j;
+}
+
+/**
+ * check_ring_tx_db - check and potentially ring a Tx queue's doorbell
+ * @adap: the adapter
+ * @q: the Tx queue
+ *
+ * Ring the doorbel if a Tx queue is asleep. There is a natural race,
+ * where the HW is going to sleep just after we checked, however,
+ * then the interrupt handler will detect the outstanding TX packet
+ * and ring the doorbell for us.
+ *
+ * When GTS is disabled we unconditionally ring the doorbell.
+ */
+static inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q)
+{
+#if USE_GTS
+ clear_bit(TXQ_LAST_PKT_DB, &q->flags);
+ if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) {
+ set_bit(TXQ_LAST_PKT_DB, &q->flags);
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+ }
+#else
+ wmb(); /* write descriptors before telling HW */
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+#endif
+}
+
+static inline void wr_gen2(struct tx_desc *d, unsigned int gen)
+{
+#if SGE_NUM_GENBITS == 2
+ d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen);
+#endif
+}
+
+/**
+ * write_wr_hdr_sgl - write a WR header and, optionally, SGL
+ * @ndesc: number of Tx descriptors spanned by the SGL
+ * @skb: the packet corresponding to the WR
+ * @d: first Tx descriptor to be written
+ * @pidx: index of above descriptors
+ * @q: the SGE Tx queue
+ * @sgl: the SGL
+ * @flits: number of flits to the start of the SGL in the first descriptor
+ * @sgl_flits: the SGL size in flits
+ * @gen: the Tx descriptor generation
+ * @wr_hi: top 32 bits of WR header based on WR type (big endian)
+ * @wr_lo: low 32 bits of WR header based on WR type (big endian)
+ *
+ * Write a work request header and an associated SGL. If the SGL is
+ * small enough to fit into one Tx descriptor it has already been written
+ * and we just need to write the WR header. Otherwise we distribute the
+ * SGL across the number of descriptors it spans.
+ */
+static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb,
+ struct tx_desc *d, unsigned int pidx,
+ const struct sge_txq *q,
+ const struct sg_ent *sgl,
+ unsigned int flits, unsigned int sgl_flits,
+ unsigned int gen, unsigned int wr_hi,
+ unsigned int wr_lo)
+{
+ struct work_request_hdr *wrp = (struct work_request_hdr *)d;
+ struct tx_sw_desc *sd = &q->sdesc[pidx];
+
+ sd->skb = skb;
+ if (need_skb_unmap()) {
+ struct unmap_info *ui = (struct unmap_info *)skb->cb;
+
+ ui->fragidx = 0;
+ ui->addr_idx = 0;
+ ui->sflit = flits;
+ }
+
+ if (likely(ndesc == 1)) {
+ skb->priority = pidx;
+ wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) |
+ V_WR_SGLSFLT(flits)) | wr_hi;
+ wmb();
+ wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) |
+ V_WR_GEN(gen)) | wr_lo;
+ wr_gen2(d, gen);
+ } else {
+ unsigned int ogen = gen;
+ const u64 *fp = (const u64 *)sgl;
+ struct work_request_hdr *wp = wrp;
+
+ wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) |
+ V_WR_SGLSFLT(flits)) | wr_hi;
+
+ while (sgl_flits) {
+ unsigned int avail = WR_FLITS - flits;
+
+ if (avail > sgl_flits)
+ avail = sgl_flits;
+ memcpy(&d->flit[flits], fp, avail * sizeof(*fp));
+ sgl_flits -= avail;
+ ndesc--;
+ if (!sgl_flits)
+ break;
+
+ fp += avail;
+ d++;
+ sd++;
+ if (++pidx == q->size) {
+ pidx = 0;
+ gen ^= 1;
+ d = q->desc;
+ sd = q->sdesc;
+ }
+
+ sd->skb = skb;
+ wrp = (struct work_request_hdr *)d;
+ wrp->wr_hi = htonl(V_WR_DATATYPE(1) |
+ V_WR_SGLSFLT(1)) | wr_hi;
+ wrp->wr_lo = htonl(V_WR_LEN(min(WR_FLITS,
+ sgl_flits + 1)) |
+ V_WR_GEN(gen)) | wr_lo;
+ wr_gen2(d, gen);
+ flits = 1;
+ }
+ skb->priority = pidx;
+ wrp->wr_hi |= htonl(F_WR_EOP);
+ wmb();
+ wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo;
+ wr_gen2((struct tx_desc *)wp, ogen);
+ WARN_ON(ndesc != 0);
+ }
+}
+
+/**
+ * write_tx_pkt_wr - write a TX_PKT work request
+ * @adap: the adapter
+ * @skb: the packet to send
+ * @pi: the egress interface
+ * @pidx: index of the first Tx descriptor to write
+ * @gen: the generation value to use
+ * @q: the Tx queue
+ * @ndesc: number of descriptors the packet will occupy
+ * @compl: the value of the COMPL bit to use
+ *
+ * Generate a TX_PKT work request to send the supplied packet.
+ */
+static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
+ const struct port_info *pi,
+ unsigned int pidx, unsigned int gen,
+ struct sge_txq *q, unsigned int ndesc,
+ unsigned int compl)
+{
+ unsigned int flits, sgl_flits, cntrl, tso_info;
+ struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
+ struct tx_desc *d = &q->desc[pidx];
+ struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)d;
+
+ cpl->len = htonl(skb->len | 0x80000000);
+ cntrl = V_TXPKT_INTF(pi->port_id);
+
+ if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+ cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb));
+
+ tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size);
+ if (tso_info) {
+ int eth_type;
+ struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)cpl;
+
+ d->flit[2] = 0;
+ cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO);
+ hdr->cntrl = htonl(cntrl);
+ eth_type = skb->nh.raw - skb->data == ETH_HLEN ?
+ CPL_ETH_II : CPL_ETH_II_VLAN;
+ tso_info |= V_LSO_ETH_TYPE(eth_type) |
+ V_LSO_IPHDR_WORDS(skb->nh.iph->ihl) |
+ V_LSO_TCPHDR_WORDS(skb->h.th->doff);
+ hdr->lso_info = htonl(tso_info);
+ flits = 3;
+ } else {
+ cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT);
+ cntrl |= F_TXPKT_IPCSUM_DIS; /* SW calculates IP csum */
+ cntrl |= V_TXPKT_L4CSUM_DIS(skb->ip_summed != CHECKSUM_PARTIAL);
+ cpl->cntrl = htonl(cntrl);
+
+ if (skb->len <= WR_LEN - sizeof(*cpl)) {
+ q->sdesc[pidx].skb = NULL;
+ if (!skb->data_len)
+ memcpy(&d->flit[2], skb->data, skb->len);
+ else
+ skb_copy_bits(skb, 0, &d->flit[2], skb->len);
+
+ flits = (skb->len + 7) / 8 + 2;
+ cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) |
+ V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT)
+ | F_WR_SOP | F_WR_EOP | compl);
+ wmb();
+ cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) |
+ V_WR_TID(q->token));
+ wr_gen2(d, gen);
+ kfree_skb(skb);
+ return;
+ }
+
+ flits = 2;
+ }
+
+ sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+ sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev);
+ if (need_skb_unmap())
+ ((struct unmap_info *)skb->cb)->len = skb_headlen(skb);
+
+ write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen,
+ htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl),
+ htonl(V_WR_TID(q->token)));
+}
+
+/**
+ * eth_xmit - add a packet to the Ethernet Tx queue
+ * @skb: the packet
+ * @dev: the egress net device
+ *
+ * Add a packet to an SGE Tx queue. Runs with softirqs disabled.
+ */
+int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned int ndesc, pidx, credits, gen, compl;
+ const struct port_info *pi = netdev_priv(dev);
+ struct adapter *adap = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+ struct sge_txq *q = &qs->txq[TXQ_ETH];
+
+ /*
+ * The chip min packet length is 9 octets but play safe and reject
+ * anything shorter than an Ethernet header.
+ */
+ if (unlikely(skb->len < ETH_HLEN)) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ spin_lock(&q->lock);
+ reclaim_completed_tx(adap, q);
+
+ credits = q->size - q->in_use;
+ ndesc = calc_tx_descs(skb);
+
+ if (unlikely(credits < ndesc)) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+ set_bit(TXQ_ETH, &qs->txq_stopped);
+ q->stops++;
+ dev_err(&adap->pdev->dev,
+ "%s: Tx ring %u full while queue awake!\n",
+ dev->name, q->cntxt_id & 7);
+ }
+ spin_unlock(&q->lock);
+ return NETDEV_TX_BUSY;
+ }
+
+ q->in_use += ndesc;
+ if (unlikely(credits - ndesc < q->stop_thres)) {
+ q->stops++;
+ netif_stop_queue(dev);
+ set_bit(TXQ_ETH, &qs->txq_stopped);
+#if !USE_GTS
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
+ q->restarts++;
+ netif_wake_queue(dev);
+ }
+#endif
+ }
+
+ gen = q->gen;
+ q->unacked += ndesc;
+ compl = (q->unacked & 8) << (S_WR_COMPL - 3);
+ q->unacked &= 7;
+ pidx = q->pidx;
+ q->pidx += ndesc;
+ if (q->pidx >= q->size) {
+ q->pidx -= q->size;
+ q->gen ^= 1;
+ }
+
+ /* update port statistics */
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ qs->port_stats[SGE_PSTAT_TX_CSUM]++;
+ if (skb_shinfo(skb)->gso_size)
+ qs->port_stats[SGE_PSTAT_TSO]++;
+ if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+ qs->port_stats[SGE_PSTAT_VLANINS]++;
+
+ dev->trans_start = jiffies;
+ spin_unlock(&q->lock);
+
+ /*
+ * We do not use Tx completion interrupts to free DMAd Tx packets.
+ * This is good for performamce but means that we rely on new Tx
+ * packets arriving to run the destructors of completed packets,
+ * which open up space in their sockets' send queues. Sometimes
+ * we do not get such new packets causing Tx to stall. A single
+ * UDP transmitter is a good example of this situation. We have
+ * a clean up timer that periodically reclaims completed packets
+ * but it doesn't run often enough (nor do we want it to) to prevent
+ * lengthy stalls. A solution to this problem is to run the
+ * destructor early, after the packet is queued but before it's DMAd.
+ * A cons is that we lie to socket memory accounting, but the amount
+ * of extra memory is reasonable (limited by the number of Tx
+ * descriptors), the packets do actually get freed quickly by new
+ * packets almost always, and for protocols like TCP that wait for
+ * acks to really free up the data the extra memory is even less.
+ * On the positive side we run the destructors on the sending CPU
+ * rather than on a potentially different completing CPU, usually a
+ * good thing. We also run them without holding our Tx queue lock,
+ * unlike what reclaim_completed_tx() would otherwise do.
+ *
+ * Run the destructor before telling the DMA engine about the packet
+ * to make sure it doesn't complete and get freed prematurely.
+ */
+ if (likely(!skb_shared(skb)))
+ skb_orphan(skb);
+
+ write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl);
+ check_ring_tx_db(adap, q);
+ return NETDEV_TX_OK;
+}
+
+/**
+ * write_imm - write a packet into a Tx descriptor as immediate data
+ * @d: the Tx descriptor to write
+ * @skb: the packet
+ * @len: the length of packet data to write as immediate data
+ * @gen: the generation bit value to write
+ *
+ * Writes a packet as immediate data into a Tx descriptor. The packet
+ * contains a work request at its beginning. We must write the packet
+ * carefully so the SGE doesn't read accidentally before it's written in
+ * its entirety.
+ */
+static inline void write_imm(struct tx_desc *d, struct sk_buff *skb,
+ unsigned int len, unsigned int gen)
+{
+ struct work_request_hdr *from = (struct work_request_hdr *)skb->data;
+ struct work_request_hdr *to = (struct work_request_hdr *)d;
+
+ memcpy(&to[1], &from[1], len - sizeof(*from));
+ to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP |
+ V_WR_BCNTLFLT(len & 7));
+ wmb();
+ to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) |
+ V_WR_LEN((len + 7) / 8));
+ wr_gen2(d, gen);
+ kfree_skb(skb);
+}
+
+/**
+ * check_desc_avail - check descriptor availability on a send queue
+ * @adap: the adapter
+ * @q: the send queue
+ * @skb: the packet needing the descriptors
+ * @ndesc: the number of Tx descriptors needed
+ * @qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL)
+ *
+ * Checks if the requested number of Tx descriptors is available on an
+ * SGE send queue. If the queue is already suspended or not enough
+ * descriptors are available the packet is queued for later transmission.
+ * Must be called with the Tx queue locked.
+ *
+ * Returns 0 if enough descriptors are available, 1 if there aren't
+ * enough descriptors and the packet has been queued, and 2 if the caller
+ * needs to retry because there weren't enough descriptors at the
+ * beginning of the call but some freed up in the mean time.
+ */
+static inline int check_desc_avail(struct adapter *adap, struct sge_txq *q,
+ struct sk_buff *skb, unsigned int ndesc,
+ unsigned int qid)
+{
+ if (unlikely(!skb_queue_empty(&q->sendq))) {
+ addq_exit:__skb_queue_tail(&q->sendq, skb);
+ return 1;
+ }
+ if (unlikely(q->size - q->in_use < ndesc)) {
+ struct sge_qset *qs = txq_to_qset(q, qid);
+
+ set_bit(qid, &qs->txq_stopped);
+ smp_mb__after_clear_bit();
+
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(qid, &qs->txq_stopped))
+ return 2;
+
+ q->stops++;
+ goto addq_exit;
+ }
+ return 0;
+}
+
+/**
+ * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs
+ * @q: the SGE control Tx queue
+ *
+ * This is a variant of reclaim_completed_tx() that is used for Tx queues
+ * that send only immediate data (presently just the control queues) and
+ * thus do not have any sk_buffs to release.
+ */
+static inline void reclaim_completed_tx_imm(struct sge_txq *q)
+{
+ unsigned int reclaim = q->processed - q->cleaned;
+
+ q->in_use -= reclaim;
+ q->cleaned += reclaim;
+}
+
+static inline int immediate(const struct sk_buff *skb)
+{
+ return skb->len <= WR_LEN && !skb->data_len;
+}
+
+/**
+ * ctrl_xmit - send a packet through an SGE control Tx queue
+ * @adap: the adapter
+ * @q: the control queue
+ * @skb: the packet
+ *
+ * Send a packet through an SGE control Tx queue. Packets sent through
+ * a control queue must fit entirely as immediate data in a single Tx
+ * descriptor and have no page fragments.
+ */
+static int ctrl_xmit(struct adapter *adap, struct sge_txq *q,
+ struct sk_buff *skb)
+{
+ int ret;
+ struct work_request_hdr *wrp = (struct work_request_hdr *)skb->data;
+
+ if (unlikely(!immediate(skb))) {
+ WARN_ON(1);
+ dev_kfree_skb(skb);
+ return NET_XMIT_SUCCESS;
+ }
+
+ wrp->wr_hi |= htonl(F_WR_SOP | F_WR_EOP);
+ wrp->wr_lo = htonl(V_WR_TID(q->token));
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx_imm(q);
+
+ ret = check_desc_avail(adap, q, skb, 1, TXQ_CTRL);
+ if (unlikely(ret)) {
+ if (ret == 1) {
+ spin_unlock(&q->lock);
+ return NET_XMIT_CN;
+ }
+ goto again;
+ }
+
+ write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
+
+ q->in_use++;
+ if (++q->pidx >= q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ }
+ spin_unlock(&q->lock);
+ wmb();
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+ return NET_XMIT_SUCCESS;
+}
+
+/**
+ * restart_ctrlq - restart a suspended control queue
+ * @qs: the queue set cotaining the control queue
+ *
+ * Resumes transmission on a suspended Tx control queue.
+ */
+static void restart_ctrlq(unsigned long data)
+{
+ struct sk_buff *skb;
+ struct sge_qset *qs = (struct sge_qset *)data;
+ struct sge_txq *q = &qs->txq[TXQ_CTRL];
+ struct adapter *adap = qs->netdev->priv;
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx_imm(q);
+
+ while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) {
+
+ write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
+
+ if (++q->pidx >= q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ }
+ q->in_use++;
+ }
+
+ if (!skb_queue_empty(&q->sendq)) {
+ set_bit(TXQ_CTRL, &qs->txq_stopped);
+ smp_mb__after_clear_bit();
+
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped))
+ goto again;
+ q->stops++;
+ }
+
+ spin_unlock(&q->lock);
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+}
+
+/*
+ * Send a management message through control queue 0
+ */
+int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb)
+{
+ return ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb);
+}
+
+/**
+ * write_ofld_wr - write an offload work request
+ * @adap: the adapter
+ * @skb: the packet to send
+ * @q: the Tx queue
+ * @pidx: index of the first Tx descriptor to write
+ * @gen: the generation value to use
+ * @ndesc: number of descriptors the packet will occupy
+ *
+ * Write an offload work request to send the supplied packet. The packet
+ * data already carry the work request with most fields populated.
+ */
+static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
+ struct sge_txq *q, unsigned int pidx,
+ unsigned int gen, unsigned int ndesc)
+{
+ unsigned int sgl_flits, flits;
+ struct work_request_hdr *from;
+ struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
+ struct tx_desc *d = &q->desc[pidx];
+
+ if (immediate(skb)) {
+ q->sdesc[pidx].skb = NULL;
+ write_imm(d, skb, skb->len, gen);
+ return;
+ }
+
+ /* Only TX_DATA builds SGLs */
+
+ from = (struct work_request_hdr *)skb->data;
+ memcpy(&d->flit[1], &from[1], skb->h.raw - skb->data - sizeof(*from));
+
+ flits = (skb->h.raw - skb->data) / 8;
+ sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+ sgl_flits = make_sgl(skb, sgp, skb->h.raw, skb->tail - skb->h.raw,
+ adap->pdev);
+ if (need_skb_unmap())
+ ((struct unmap_info *)skb->cb)->len = skb->tail - skb->h.raw;
+
+ write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits,
+ gen, from->wr_hi, from->wr_lo);
+}
+
+/**
+ * calc_tx_descs_ofld - calculate # of Tx descriptors for an offload packet
+ * @skb: the packet
+ *
+ * Returns the number of Tx descriptors needed for the given offload
+ * packet. These packets are already fully constructed.
+ */
+static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb)
+{
+ unsigned int flits, cnt = skb_shinfo(skb)->nr_frags;
+
+ if (skb->len <= WR_LEN && cnt == 0)
+ return 1; /* packet fits as immediate data */
+
+ flits = (skb->h.raw - skb->data) / 8; /* headers */
+ if (skb->tail != skb->h.raw)
+ cnt++;
+ return flits_to_desc(flits + sgl_len(cnt));
+}
+
+/**
+ * ofld_xmit - send a packet through an offload queue
+ * @adap: the adapter
+ * @q: the Tx offload queue
+ * @skb: the packet
+ *
+ * Send an offload packet through an SGE offload queue.
+ */
+static int ofld_xmit(struct adapter *adap, struct sge_txq *q,
+ struct sk_buff *skb)
+{
+ int ret;
+ unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen;
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx(adap, q);
+
+ ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD);
+ if (unlikely(ret)) {
+ if (ret == 1) {
+ skb->priority = ndesc; /* save for restart */
+ spin_unlock(&q->lock);
+ return NET_XMIT_CN;
+ }
+ goto again;
+ }
+
+ gen = q->gen;
+ q->in_use += ndesc;
+ pidx = q->pidx;
+ q->pidx += ndesc;
+ if (q->pidx >= q->size) {
+ q->pidx -= q->size;
+ q->gen ^= 1;
+ }
+ spin_unlock(&q->lock);
+
+ write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+ check_ring_tx_db(adap, q);
+ return NET_XMIT_SUCCESS;
+}
+
+/**
+ * restart_offloadq - restart a suspended offload queue
+ * @qs: the queue set cotaining the offload queue
+ *
+ * Resumes transmission on a suspended Tx offload queue.
+ */
+static void restart_offloadq(unsigned long data)
+{
+ struct sk_buff *skb;
+ struct sge_qset *qs = (struct sge_qset *)data;
+ struct sge_txq *q = &qs->txq[TXQ_OFLD];
+ struct adapter *adap = qs->netdev->priv;
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx(adap, q);
+
+ while ((skb = skb_peek(&q->sendq)) != NULL) {
+ unsigned int gen, pidx;
+ unsigned int ndesc = skb->priority;
+
+ if (unlikely(q->size - q->in_use < ndesc)) {
+ set_bit(TXQ_OFLD, &qs->txq_stopped);
+ smp_mb__after_clear_bit();
+
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped))
+ goto again;
+ q->stops++;
+ break;
+ }
+
+ gen = q->gen;
+ q->in_use += ndesc;
+ pidx = q->pidx;
+ q->pidx += ndesc;
+ if (q->pidx >= q->size) {
+ q->pidx -= q->size;
+ q->gen ^= 1;
+ }
+ __skb_unlink(skb, &q->sendq);
+ spin_unlock(&q->lock);
+
+ write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+ spin_lock(&q->lock);
+ }
+ spin_unlock(&q->lock);
+
+#if USE_GTS
+ set_bit(TXQ_RUNNING, &q->flags);
+ set_bit(TXQ_LAST_PKT_DB, &q->flags);
+#endif
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+}
+
+/**
+ * queue_set - return the queue set a packet should use
+ * @skb: the packet
+ *
+ * Maps a packet to the SGE queue set it should use. The desired queue
+ * set is carried in bits 1-3 in the packet's priority.
+ */
+static inline int queue_set(const struct sk_buff *skb)
+{
+ return skb->priority >> 1;
+}
+
+/**
+ * is_ctrl_pkt - return whether an offload packet is a control packet
+ * @skb: the packet
+ *
+ * Determines whether an offload packet should use an OFLD or a CTRL
+ * Tx queue. This is indicated by bit 0 in the packet's priority.
+ */
+static inline int is_ctrl_pkt(const struct sk_buff *skb)
+{
+ return skb->priority & 1;
+}
+
+/**
+ * t3_offload_tx - send an offload packet
+ * @tdev: the offload device to send to
+ * @skb: the packet
+ *
+ * Sends an offload packet. We use the packet priority to select the
+ * appropriate Tx queue as follows: bit 0 indicates whether the packet
+ * should be sent as regular or control, bits 1-3 select the queue set.
+ */
+int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
+{
+ struct adapter *adap = tdev2adap(tdev);
+ struct sge_qset *qs = &adap->sge.qs[queue_set(skb)];
+
+ if (unlikely(is_ctrl_pkt(skb)))
+ return ctrl_xmit(adap, &qs->txq[TXQ_CTRL], skb);
+
+ return ofld_xmit(adap, &qs->txq[TXQ_OFLD], skb);
+}
+
+/**
+ * offload_enqueue - add an offload packet to an SGE offload receive queue
+ * @q: the SGE response queue
+ * @skb: the packet
+ *
+ * Add a new offload packet to an SGE response queue's offload packet
+ * queue. If the packet is the first on the queue it schedules the RX
+ * softirq to process the queue.
+ */
+static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb)
+{
+ skb->next = skb->prev = NULL;
+ if (q->rx_tail)
+ q->rx_tail->next = skb;
+ else {
+ struct sge_qset *qs = rspq_to_qset(q);
+
+ if (__netif_rx_schedule_prep(qs->netdev))
+ __netif_rx_schedule(qs->netdev);
+ q->rx_head = skb;
+ }
+ q->rx_tail = skb;
+}
+
+/**
+ * deliver_partial_bundle - deliver a (partial) bundle of Rx offload pkts
+ * @tdev: the offload device that will be receiving the packets
+ * @q: the SGE response queue that assembled the bundle
+ * @skbs: the partial bundle
+ * @n: the number of packets in the bundle
+ *
+ * Delivers a (partial) bundle of Rx offload packets to an offload device.
+ */
+static inline void deliver_partial_bundle(struct t3cdev *tdev,
+ struct sge_rspq *q,
+ struct sk_buff *skbs[], int n)
+{
+ if (n) {
+ q->offload_bundles++;
+ tdev->recv(tdev, skbs, n);
+ }
+}
+
+/**
+ * ofld_poll - NAPI handler for offload packets in interrupt mode
+ * @dev: the network device doing the polling
+ * @budget: polling budget
+ *
+ * The NAPI handler for offload packets when a response queue is serviced
+ * by the hard interrupt handler, i.e., when it's operating in non-polling
+ * mode. Creates small packet batches and sends them through the offload
+ * receive handler. Batches need to be of modest size as we do prefetches
+ * on the packets in each.
+ */
+static int ofld_poll(struct net_device *dev, int *budget)
+{
+ struct adapter *adapter = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+ struct sge_rspq *q = &qs->rspq;
+ int work_done, limit = min(*budget, dev->quota), avail = limit;
+
+ while (avail) {
+ struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE];
+ int ngathered;
+
+ spin_lock_irq(&q->lock);
+ head = q->rx_head;
+ if (!head) {
+ work_done = limit - avail;
+ *budget -= work_done;
+ dev->quota -= work_done;
+ __netif_rx_complete(dev);
+ spin_unlock_irq(&q->lock);
+ return 0;
+ }
+
+ tail = q->rx_tail;
+ q->rx_head = q->rx_tail = NULL;
+ spin_unlock_irq(&q->lock);
+
+ for (ngathered = 0; avail && head; avail--) {
+ prefetch(head->data);
+ skbs[ngathered] = head;
+ head = head->next;
+ skbs[ngathered]->next = NULL;
+ if (++ngathered == RX_BUNDLE_SIZE) {
+ q->offload_bundles++;
+ adapter->tdev.recv(&adapter->tdev, skbs,
+ ngathered);
+ ngathered = 0;
+ }
+ }
+ if (head) { /* splice remaining packets back onto Rx queue */
+ spin_lock_irq(&q->lock);
+ tail->next = q->rx_head;
+ if (!q->rx_head)
+ q->rx_tail = tail;
+ q->rx_head = head;
+ spin_unlock_irq(&q->lock);
+ }
+ deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered);
+ }
+ work_done = limit - avail;
+ *budget -= work_done;
+ dev->quota -= work_done;
+ return 1;
+}
+
+/**
+ * rx_offload - process a received offload packet
+ * @tdev: the offload device receiving the packet
+ * @rq: the response queue that received the packet
+ * @skb: the packet
+ * @rx_gather: a gather list of packets if we are building a bundle
+ * @gather_idx: index of the next available slot in the bundle
+ *
+ * Process an ingress offload pakcet and add it to the offload ingress
+ * queue. Returns the index of the next available slot in the bundle.
+ */
+static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq,
+ struct sk_buff *skb, struct sk_buff *rx_gather[],
+ unsigned int gather_idx)
+{
+ rq->offload_pkts++;
+ skb->mac.raw = skb->nh.raw = skb->h.raw = skb->data;
+
+ if (rq->polling) {
+ rx_gather[gather_idx++] = skb;
+ if (gather_idx == RX_BUNDLE_SIZE) {
+ tdev->recv(tdev, rx_gather, RX_BUNDLE_SIZE);
+ gather_idx = 0;
+ rq->offload_bundles++;
+ }
+ } else
+ offload_enqueue(rq, skb);
+
+ return gather_idx;
+}
+
+/**
+ * restart_tx - check whether to restart suspended Tx queues
+ * @qs: the queue set to resume
+ *
+ * Restarts suspended Tx queues of an SGE queue set if they have enough
+ * free resources to resume operation.
+ */
+static void restart_tx(struct sge_qset *qs)
+{
+ if (test_bit(TXQ_ETH, &qs->txq_stopped) &&
+ should_restart_tx(&qs->txq[TXQ_ETH]) &&
+ test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
+ qs->txq[TXQ_ETH].restarts++;
+ if (netif_running(qs->netdev))
+ netif_wake_queue(qs->netdev);
+ }
+
+ if (test_bit(TXQ_OFLD, &qs->txq_stopped) &&
+ should_restart_tx(&qs->txq[TXQ_OFLD]) &&
+ test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) {
+ qs->txq[TXQ_OFLD].restarts++;
+ tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk);
+ }
+ if (test_bit(TXQ_CTRL, &qs->txq_stopped) &&
+ should_restart_tx(&qs->txq[TXQ_CTRL]) &&
+ test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) {
+ qs->txq[TXQ_CTRL].restarts++;
+ tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk);
+ }
+}
+
+/**
+ * rx_eth - process an ingress ethernet packet
+ * @adap: the adapter
+ * @rq: the response queue that received the packet
+ * @skb: the packet
+ * @pad: amount of padding at the start of the buffer
+ *
+ * Process an ingress ethernet pakcet and deliver it to the stack.
+ * The padding is 2 if the packet was delivered in an Rx buffer and 0
+ * if it was immediate data in a response.
+ */
+static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
+ struct sk_buff *skb, int pad)
+{
+ struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad);
+ struct port_info *pi;
+
+ rq->eth_pkts++;
+ skb_pull(skb, sizeof(*p) + pad);
+ skb->dev = adap->port[p->iff];
+ skb->dev->last_rx = jiffies;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ pi = netdev_priv(skb->dev);
+ if (pi->rx_csum_offload && p->csum_valid && p->csum == 0xffff &&
+ !p->fragment) {
+ rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (unlikely(p->vlan_valid)) {
+ struct vlan_group *grp = pi->vlan_grp;
+
+ rspq_to_qset(rq)->port_stats[SGE_PSTAT_VLANEX]++;
+ if (likely(grp))
+ __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan),
+ rq->polling);
+ else
+ dev_kfree_skb_any(skb);
+ } else if (rq->polling)
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
+}
+
+/**
+ * handle_rsp_cntrl_info - handles control information in a response
+ * @qs: the queue set corresponding to the response
+ * @flags: the response control flags
+ *
+ * Handles the control information of an SGE response, such as GTS
+ * indications and completion credits for the queue set's Tx queues.
+ * HW coalesces credits, we don't do any extra SW coalescing.
+ */
+static inline void handle_rsp_cntrl_info(struct sge_qset *qs, u32 flags)
+{
+ unsigned int credits;
+
+#if USE_GTS
+ if (flags & F_RSPD_TXQ0_GTS)
+ clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags);
+#endif
+
+ credits = G_RSPD_TXQ0_CR(flags);
+ if (credits)
+ qs->txq[TXQ_ETH].processed += credits;
+
+ credits = G_RSPD_TXQ2_CR(flags);
+ if (credits)
+ qs->txq[TXQ_CTRL].processed += credits;
+
+# if USE_GTS
+ if (flags & F_RSPD_TXQ1_GTS)
+ clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags);
+# endif
+ credits = G_RSPD_TXQ1_CR(flags);
+ if (credits)
+ qs->txq[TXQ_OFLD].processed += credits;
+}
+
+/**
+ * check_ring_db - check if we need to ring any doorbells
+ * @adapter: the adapter
+ * @qs: the queue set whose Tx queues are to be examined
+ * @sleeping: indicates which Tx queue sent GTS
+ *
+ * Checks if some of a queue set's Tx queues need to ring their doorbells
+ * to resume transmission after idling while they still have unprocessed
+ * descriptors.
+ */
+static void check_ring_db(struct adapter *adap, struct sge_qset *qs,
+ unsigned int sleeping)
+{
+ if (sleeping & F_RSPD_TXQ0_GTS) {
+ struct sge_txq *txq = &qs->txq[TXQ_ETH];
+
+ if (txq->cleaned + txq->in_use != txq->processed &&
+ !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) {
+ set_bit(TXQ_RUNNING, &txq->flags);
+ t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX |
+ V_EGRCNTX(txq->cntxt_id));
+ }
+ }
+
+ if (sleeping & F_RSPD_TXQ1_GTS) {
+ struct sge_txq *txq = &qs->txq[TXQ_OFLD];
+
+ if (txq->cleaned + txq->in_use != txq->processed &&
+ !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) {
+ set_bit(TXQ_RUNNING, &txq->flags);
+ t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX |
+ V_EGRCNTX(txq->cntxt_id));
+ }
+ }
+}
+
+/**
+ * is_new_response - check if a response is newly written
+ * @r: the response descriptor
+ * @q: the response queue
+ *
+ * Returns true if a response descriptor contains a yet unprocessed
+ * response.
+ */
+static inline int is_new_response(const struct rsp_desc *r,
+ const struct sge_rspq *q)
+{
+ return (r->intr_gen & F_RSPD_GEN2) == q->gen;
+}
+
+#define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS)
+#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \
+ V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \
+ V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \
+ V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR))
+
+/* How long to delay the next interrupt in case of memory shortage, in 0.1us. */
+#define NOMEM_INTR_DELAY 2500
+
+/**
+ * process_responses - process responses from an SGE response queue
+ * @adap: the adapter
+ * @qs: the queue set to which the response queue belongs
+ * @budget: how many responses can be processed in this round
+ *
+ * Process responses from an SGE response queue up to the supplied budget.
+ * Responses include received packets as well as credits and other events
+ * for the queues that belong to the response queue's queue set.
+ * A negative budget is effectively unlimited.
+ *
+ * Additionally choose the interrupt holdoff time for the next interrupt
+ * on this queue. If the system is under memory shortage use a fairly
+ * long delay to help recovery.
+ */
+static int process_responses(struct adapter *adap, struct sge_qset *qs,
+ int budget)
+{
+ struct sge_rspq *q = &qs->rspq;
+ struct rsp_desc *r = &q->desc[q->cidx];
+ int budget_left = budget;
+ unsigned int sleeping = 0;
+ struct sk_buff *offload_skbs[RX_BUNDLE_SIZE];
+ int ngathered = 0;
+
+ q->next_holdoff = q->holdoff_tmr;
+
+ while (likely(budget_left && is_new_response(r, q))) {
+ int eth, ethpad = 0;
+ struct sk_buff *skb = NULL;
+ u32 len, flags = ntohl(r->flags);
+ u32 rss_hi = *(const u32 *)r, rss_lo = r->rss_hdr.rss_hash_val;
+
+ eth = r->rss_hdr.opcode == CPL_RX_PKT;
+
+ if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) {
+ skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC);
+ if (!skb)
+ goto no_mem;
+
+ memcpy(__skb_put(skb, AN_PKT_SIZE), r, AN_PKT_SIZE);
+ skb->data[0] = CPL_ASYNC_NOTIF;
+ rss_hi = htonl(CPL_ASYNC_NOTIF << 24);
+ q->async_notif++;
+ } else if (flags & F_RSPD_IMM_DATA_VALID) {
+ skb = get_imm_packet(r);
+ if (unlikely(!skb)) {
+ no_mem:
+ q->next_holdoff = NOMEM_INTR_DELAY;
+ q->nomem++;
+ /* consume one credit since we tried */
+ budget_left--;
+ break;
+ }
+ q->imm_data++;
+ } else if ((len = ntohl(r->len_cq)) != 0) {
+ struct sge_fl *fl;
+
+ fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+ fl->credits--;
+ skb = get_packet(adap, fl, G_RSPD_LEN(len),
+ eth ? SGE_RX_DROP_THRES : 0);
+ if (!skb)
+ q->rx_drops++;
+ else if (r->rss_hdr.opcode == CPL_TRACE_PKT)
+ __skb_pull(skb, 2);
+ ethpad = 2;
+ if (++fl->cidx == fl->size)
+ fl->cidx = 0;
+ } else
+ q->pure_rsps++;
+
+ if (flags & RSPD_CTRL_MASK) {
+ sleeping |= flags & RSPD_GTS_MASK;
+ handle_rsp_cntrl_info(qs, flags);
+ }
+
+ r++;
+ if (unlikely(++q->cidx == q->size)) {
+ q->cidx = 0;
+ q->gen ^= 1;
+ r = q->desc;
+ }
+ prefetch(r);
+
+ if (++q->credits >= (q->size / 4)) {
+ refill_rspq(adap, q, q->credits);
+ q->credits = 0;
+ }
+
+ if (likely(skb != NULL)) {
+ if (eth)
+ rx_eth(adap, q, skb, ethpad);
+ else {
+ /* Preserve the RSS info in csum & priority */
+ skb->csum = rss_hi;
+ skb->priority = rss_lo;
+ ngathered = rx_offload(&adap->tdev, q, skb,
+ offload_skbs, ngathered);
+ }
+ }
+
+ --budget_left;
+ }
+
+ deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered);
+ if (sleeping)
+ check_ring_db(adap, qs, sleeping);
+
+ smp_mb(); /* commit Tx queue .processed updates */
+ if (unlikely(qs->txq_stopped != 0))
+ restart_tx(qs);
+
+ budget -= budget_left;
+ return budget;
+}
+
+static inline int is_pure_response(const struct rsp_desc *r)
+{
+ u32 n = ntohl(r->flags) & (F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID);
+
+ return (n | r->len_cq) == 0;
+}
+
+/**
+ * napi_rx_handler - the NAPI handler for Rx processing
+ * @dev: the net device
+ * @budget: how many packets we can process in this round
+ *
+ * Handler for new data events when using NAPI.
+ */
+static int napi_rx_handler(struct net_device *dev, int *budget)
+{
+ struct adapter *adap = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+ int effective_budget = min(*budget, dev->quota);
+
+ int work_done = process_responses(adap, qs, effective_budget);
+ *budget -= work_done;
+ dev->quota -= work_done;
+
+ if (work_done >= effective_budget)
+ return 1;
+
+ netif_rx_complete(dev);
+
+ /*
+ * Because we don't atomically flush the following write it is
+ * possible that in very rare cases it can reach the device in a way
+ * that races with a new response being written plus an error interrupt
+ * causing the NAPI interrupt handler below to return unhandled status
+ * to the OS. To protect against this would require flushing the write
+ * and doing both the write and the flush with interrupts off. Way too
+ * expensive and unjustifiable given the rarity of the race.
+ *
+ * The race cannot happen at all with MSI-X.
+ */
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
+ V_NEWTIMER(qs->rspq.next_holdoff) |
+ V_NEWINDEX(qs->rspq.cidx));
+ return 0;
+}
+
+/*
+ * Returns true if the device is already scheduled for polling.
+ */
+static inline int napi_is_scheduled(struct net_device *dev)
+{
+ return test_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+
+/**
+ * process_pure_responses - process pure responses from a response queue
+ * @adap: the adapter
+ * @qs: the queue set owning the response queue
+ * @r: the first pure response to process
+ *
+ * A simpler version of process_responses() that handles only pure (i.e.,
+ * non data-carrying) responses. Such respones are too light-weight to
+ * justify calling a softirq under NAPI, so we handle them specially in
+ * the interrupt handler. The function is called with a pointer to a
+ * response, which the caller must ensure is a valid pure response.
+ *
+ * Returns 1 if it encounters a valid data-carrying response, 0 otherwise.
+ */
+static int process_pure_responses(struct adapter *adap, struct sge_qset *qs,
+ struct rsp_desc *r)
+{
+ struct sge_rspq *q = &qs->rspq;
+ unsigned int sleeping = 0;
+
+ do {
+ u32 flags = ntohl(r->flags);
+
+ r++;
+ if (unlikely(++q->cidx == q->size)) {
+ q->cidx = 0;
+ q->gen ^= 1;
+ r = q->desc;
+ }
+ prefetch(r);
+
+ if (flags & RSPD_CTRL_MASK) {
+ sleeping |= flags & RSPD_GTS_MASK;
+ handle_rsp_cntrl_info(qs, flags);
+ }
+
+ q->pure_rsps++;
+ if (++q->credits >= (q->size / 4)) {
+ refill_rspq(adap, q, q->credits);
+ q->credits = 0;
+ }
+ } while (is_new_response(r, q) && is_pure_response(r));
+
+ if (sleeping)
+ check_ring_db(adap, qs, sleeping);
+
+ smp_mb(); /* commit Tx queue .processed updates */
+ if (unlikely(qs->txq_stopped != 0))
+ restart_tx(qs);
+
+ return is_new_response(r, q);
+}
+
+/**
+ * handle_responses - decide what to do with new responses in NAPI mode
+ * @adap: the adapter
+ * @q: the response queue
+ *
+ * This is used by the NAPI interrupt handlers to decide what to do with
+ * new SGE responses. If there are no new responses it returns -1. If
+ * there are new responses and they are pure (i.e., non-data carrying)
+ * it handles them straight in hard interrupt context as they are very
+ * cheap and don't deliver any packets. Finally, if there are any data
+ * signaling responses it schedules the NAPI handler. Returns 1 if it
+ * schedules NAPI, 0 if all new responses were pure.
+ *
+ * The caller must ascertain NAPI is not already running.
+ */
+static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
+{
+ struct sge_qset *qs = rspq_to_qset(q);
+ struct rsp_desc *r = &q->desc[q->cidx];
+
+ if (!is_new_response(r, q))
+ return -1;
+ if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) {
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+ V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx));
+ return 0;
+ }
+ if (likely(__netif_rx_schedule_prep(qs->netdev)))
+ __netif_rx_schedule(qs->netdev);
+ return 1;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the non-NAPI case
+ * (i.e., response queue serviced in hard interrupt).
+ */
+irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
+{
+ struct sge_qset *qs = cookie;
+ struct adapter *adap = qs->netdev->priv;
+ struct sge_rspq *q = &qs->rspq;
+
+ spin_lock(&q->lock);
+ if (process_responses(adap, qs, -1) == 0)
+ q->unhandled_irqs++;
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+ V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx));
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the NAPI case
+ * (i.e., response queue serviced by NAPI polling).
+ */
+irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie)
+{
+ struct sge_qset *qs = cookie;
+ struct adapter *adap = qs->netdev->priv;
+ struct sge_rspq *q = &qs->rspq;
+
+ spin_lock(&q->lock);
+ BUG_ON(napi_is_scheduled(qs->netdev));
+
+ if (handle_responses(adap, q) < 0)
+ q->unhandled_irqs++;
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * The non-NAPI MSI interrupt handler. This needs to handle data events from
+ * SGE response queues as well as error and other async events as they all use
+ * the same MSI vector. We use one SGE response queue per port in this mode
+ * and protect all response queues with queue 0's lock.
+ */
+static irqreturn_t t3_intr_msi(int irq, void *cookie)
+{
+ int new_packets = 0;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q = &adap->sge.qs[0].rspq;
+
+ spin_lock(&q->lock);
+
+ if (process_responses(adap, &adap->sge.qs[0], -1)) {
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+ V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx));
+ new_packets = 1;
+ }
+
+ if (adap->params.nports == 2 &&
+ process_responses(adap, &adap->sge.qs[1], -1)) {
+ struct sge_rspq *q1 = &adap->sge.qs[1].rspq;
+
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(q1->cntxt_id) |
+ V_NEWTIMER(q1->next_holdoff) |
+ V_NEWINDEX(q1->cidx));
+ new_packets = 1;
+ }
+
+ if (!new_packets && t3_slow_intr_handler(adap) == 0)
+ q->unhandled_irqs++;
+
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q)
+{
+ if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) {
+ if (likely(__netif_rx_schedule_prep(dev)))
+ __netif_rx_schedule(dev);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * The MSI interrupt handler for the NAPI case (i.e., response queues serviced
+ * by NAPI polling). Handles data events from SGE response queues as well as
+ * error and other async events as they all use the same MSI vector. We use
+ * one SGE response queue per port in this mode and protect all response
+ * queues with queue 0's lock.
+ */
+irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
+{
+ int new_packets;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q = &adap->sge.qs[0].rspq;
+
+ spin_lock(&q->lock);
+
+ new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q);
+ if (adap->params.nports == 2)
+ new_packets += rspq_check_napi(adap->sge.qs[1].netdev,
+ &adap->sge.qs[1].rspq);
+ if (!new_packets && t3_slow_intr_handler(adap) == 0)
+ q->unhandled_irqs++;
+
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * A helper function that processes responses and issues GTS.
+ */
+static inline int process_responses_gts(struct adapter *adap,
+ struct sge_rspq *rq)
+{
+ int work;
+
+ work = process_responses(adap, rspq_to_qset(rq), -1);
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) |
+ V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx));
+ return work;
+}
+
+/*
+ * The legacy INTx interrupt handler. This needs to handle data events from
+ * SGE response queues as well as error and other async events as they all use
+ * the same interrupt pin. We use one SGE response queue per port in this mode
+ * and protect all response queues with queue 0's lock.
+ */
+static irqreturn_t t3_intr(int irq, void *cookie)
+{
+ int work_done, w0, w1;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+ struct sge_rspq *q1 = &adap->sge.qs[1].rspq;
+
+ spin_lock(&q0->lock);
+
+ w0 = is_new_response(&q0->desc[q0->cidx], q0);
+ w1 = adap->params.nports == 2 &&
+ is_new_response(&q1->desc[q1->cidx], q1);
+
+ if (likely(w0 | w1)) {
+ t3_write_reg(adap, A_PL_CLI, 0);
+ t3_read_reg(adap, A_PL_CLI); /* flush */
+
+ if (likely(w0))
+ process_responses_gts(adap, q0);
+
+ if (w1)
+ process_responses_gts(adap, q1);
+
+ work_done = w0 | w1;
+ } else
+ work_done = t3_slow_intr_handler(adap);
+
+ spin_unlock(&q0->lock);
+ return IRQ_RETVAL(work_done != 0);
+}
+
+/*
+ * Interrupt handler for legacy INTx interrupts for T3B-based cards.
+ * Handles data events from SGE response queues as well as error and other
+ * async events as they all use the same interrupt pin. We use one SGE
+ * response queue per port in this mode and protect all response queues with
+ * queue 0's lock.
+ */
+static irqreturn_t t3b_intr(int irq, void *cookie)
+{
+ u32 map;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+
+ t3_write_reg(adap, A_PL_CLI, 0);
+ map = t3_read_reg(adap, A_SG_DATA_INTR);
+
+ if (unlikely(!map)) /* shared interrupt, most likely */
+ return IRQ_NONE;
+
+ spin_lock(&q0->lock);
+
+ if (unlikely(map & F_ERRINTR))
+ t3_slow_intr_handler(adap);
+
+ if (likely(map & 1))
+ process_responses_gts(adap, q0);
+
+ if (map & 2)
+ process_responses_gts(adap, &adap->sge.qs[1].rspq);
+
+ spin_unlock(&q0->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * NAPI interrupt handler for legacy INTx interrupts for T3B-based cards.
+ * Handles data events from SGE response queues as well as error and other
+ * async events as they all use the same interrupt pin. We use one SGE
+ * response queue per port in this mode and protect all response queues with
+ * queue 0's lock.
+ */
+static irqreturn_t t3b_intr_napi(int irq, void *cookie)
+{
+ u32 map;
+ struct net_device *dev;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+
+ t3_write_reg(adap, A_PL_CLI, 0);
+ map = t3_read_reg(adap, A_SG_DATA_INTR);
+
+ if (unlikely(!map)) /* shared interrupt, most likely */
+ return IRQ_NONE;
+
+ spin_lock(&q0->lock);
+
+ if (unlikely(map & F_ERRINTR))
+ t3_slow_intr_handler(adap);
+
+ if (likely(map & 1)) {
+ dev = adap->sge.qs[0].netdev;
+
+ if (likely(__netif_rx_schedule_prep(dev)))
+ __netif_rx_schedule(dev);
+ }
+ if (map & 2) {
+ dev = adap->sge.qs[1].netdev;
+
+ if (likely(__netif_rx_schedule_prep(dev)))
+ __netif_rx_schedule(dev);
+ }
+
+ spin_unlock(&q0->lock);
+ return IRQ_HANDLED;
+}
+
+/**
+ * t3_intr_handler - select the top-level interrupt handler
+ * @adap: the adapter
+ * @polling: whether using NAPI to service response queues
+ *
+ * Selects the top-level interrupt handler based on the type of interrupts
+ * (MSI-X, MSI, or legacy) and whether NAPI will be used to service the
+ * response queues.
+ */
+intr_handler_t t3_intr_handler(struct adapter *adap, int polling)
+{
+ if (adap->flags & USING_MSIX)
+ return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix;
+ if (adap->flags & USING_MSI)
+ return polling ? t3_intr_msi_napi : t3_intr_msi;
+ if (adap->params.rev > 0)
+ return polling ? t3b_intr_napi : t3b_intr;
+ return t3_intr;
+}
+
+/**
+ * t3_sge_err_intr_handler - SGE async event interrupt handler
+ * @adapter: the adapter
+ *
+ * Interrupt handler for SGE asynchronous (non-data) events.
+ */
+void t3_sge_err_intr_handler(struct adapter *adapter)
+{
+ unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE);
+
+ if (status & F_RSPQCREDITOVERFOW)
+ CH_ALERT(adapter, "SGE response queue credit overflow\n");
+
+ if (status & F_RSPQDISABLED) {
+ v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS);
+
+ CH_ALERT(adapter,
+ "packet delivered to disabled response queue "
+ "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff);
+ }
+
+ t3_write_reg(adapter, A_SG_INT_CAUSE, status);
+ if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED))
+ t3_fatal_err(adapter);
+}
+
+/**
+ * sge_timer_cb - perform periodic maintenance of an SGE qset
+ * @data: the SGE queue set to maintain
+ *
+ * Runs periodically from a timer to perform maintenance of an SGE queue
+ * set. It performs two tasks:
+ *
+ * a) Cleans up any completed Tx descriptors that may still be pending.
+ * Normal descriptor cleanup happens when new packets are added to a Tx
+ * queue so this timer is relatively infrequent and does any cleanup only
+ * if the Tx queue has not seen any new packets in a while. We make a
+ * best effort attempt to reclaim descriptors, in that we don't wait
+ * around if we cannot get a queue's lock (which most likely is because
+ * someone else is queueing new packets and so will also handle the clean
+ * up). Since control queues use immediate data exclusively we don't
+ * bother cleaning them up here.
+ *
+ * b) Replenishes Rx queues that have run out due to memory shortage.
+ * Normally new Rx buffers are added when existing ones are consumed but
+ * when out of memory a queue can become empty. We try to add only a few
+ * buffers here, the queue will be replenished fully as these new buffers
+ * are used up if memory shortage has subsided.
+ */
+static void sge_timer_cb(unsigned long data)
+{
+ spinlock_t *lock;
+ struct sge_qset *qs = (struct sge_qset *)data;
+ struct adapter *adap = qs->netdev->priv;
+
+ if (spin_trylock(&qs->txq[TXQ_ETH].lock)) {
+ reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]);
+ spin_unlock(&qs->txq[TXQ_ETH].lock);
+ }
+ if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) {
+ reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD]);
+ spin_unlock(&qs->txq[TXQ_OFLD].lock);
+ }
+ lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock :
+ &adap->sge.qs[0].rspq.lock;
+ if (spin_trylock_irq(lock)) {
+ if (!napi_is_scheduled(qs->netdev)) {
+ if (qs->fl[0].credits < qs->fl[0].size)
+ __refill_fl(adap, &qs->fl[0]);
+ if (qs->fl[1].credits < qs->fl[1].size)
+ __refill_fl(adap, &qs->fl[1]);
+ }
+ spin_unlock_irq(lock);
+ }
+ mod_timer(&qs->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+}
+
+/**
+ * t3_update_qset_coalesce - update coalescing settings for a queue set
+ * @qs: the SGE queue set
+ * @p: new queue set parameters
+ *
+ * Update the coalescing settings for an SGE queue set. Nothing is done
+ * if the queue set is not initialized yet.
+ */
+void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p)
+{
+ if (!qs->netdev)
+ return;
+
+ qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */
+ qs->rspq.polling = p->polling;
+ qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll;
+}
+
+/**
+ * t3_sge_alloc_qset - initialize an SGE queue set
+ * @adapter: the adapter
+ * @id: the queue set id
+ * @nports: how many Ethernet ports will be using this queue set
+ * @irq_vec_idx: the IRQ vector index for response queue interrupts
+ * @p: configuration parameters for this queue set
+ * @ntxq: number of Tx queues for the queue set
+ * @netdev: net device associated with this queue set
+ *
+ * Allocate resources and initialize an SGE queue set. A queue set
+ * comprises a response queue, two Rx free-buffer queues, and up to 3
+ * Tx queues. The Tx queues are assigned roles in the order Ethernet
+ * queue, offload queue, and control queue.
+ */
+int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
+ int irq_vec_idx, const struct qset_params *p,
+ int ntxq, struct net_device *netdev)
+{
+ int i, ret = -ENOMEM;
+ struct sge_qset *q = &adapter->sge.qs[id];
+
+ init_qset_cntxt(q, id);
+ init_timer(&q->tx_reclaim_timer);
+ q->tx_reclaim_timer.data = (unsigned long)q;
+ q->tx_reclaim_timer.function = sge_timer_cb;
+
+ q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size,
+ sizeof(struct rx_desc),
+ sizeof(struct rx_sw_desc),
+ &q->fl[0].phys_addr, &q->fl[0].sdesc);
+ if (!q->fl[0].desc)
+ goto err;
+
+ q->fl[1].desc = alloc_ring(adapter->pdev, p->jumbo_size,
+ sizeof(struct rx_desc),
+ sizeof(struct rx_sw_desc),
+ &q->fl[1].phys_addr, &q->fl[1].sdesc);
+ if (!q->fl[1].desc)
+ goto err;
+
+ q->rspq.desc = alloc_ring(adapter->pdev, p->rspq_size,
+ sizeof(struct rsp_desc), 0,
+ &q->rspq.phys_addr, NULL);
+ if (!q->rspq.desc)
+ goto err;
+
+ for (i = 0; i < ntxq; ++i) {
+ /*
+ * The control queue always uses immediate data so does not
+ * need to keep track of any sk_buffs.
+ */
+ size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc);
+
+ q->txq[i].desc = alloc_ring(adapter->pdev, p->txq_size[i],
+ sizeof(struct tx_desc), sz,
+ &q->txq[i].phys_addr,
+ &q->txq[i].sdesc);
+ if (!q->txq[i].desc)
+ goto err;
+
+ q->txq[i].gen = 1;
+ q->txq[i].size = p->txq_size[i];
+ spin_lock_init(&q->txq[i].lock);
+ skb_queue_head_init(&q->txq[i].sendq);
+ }
+
+ tasklet_init(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq,
+ (unsigned long)q);
+ tasklet_init(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq,
+ (unsigned long)q);
+
+ q->fl[0].gen = q->fl[1].gen = 1;
+ q->fl[0].size = p->fl_size;
+ q->fl[1].size = p->jumbo_size;
+
+ q->rspq.gen = 1;
+ q->rspq.size = p->rspq_size;
+ spin_lock_init(&q->rspq.lock);
+
+ q->txq[TXQ_ETH].stop_thres = nports *
+ flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3);
+
+ if (ntxq == 1) {
+ q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 +
+ sizeof(struct cpl_rx_pkt);
+ q->fl[1].buf_size = MAX_FRAME_SIZE + 2 +
+ sizeof(struct cpl_rx_pkt);
+ } else {
+ q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE +
+ sizeof(struct cpl_rx_data);
+ q->fl[1].buf_size = (16 * 1024) -
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ }
+
+ spin_lock(&adapter->sge.reg_lock);
+
+ /* FL threshold comparison uses < */
+ ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx,
+ q->rspq.phys_addr, q->rspq.size,
+ q->fl[0].buf_size, 1, 0);
+ if (ret)
+ goto err_unlock;
+
+ for (i = 0; i < SGE_RXQ_PER_SET; ++i) {
+ ret = t3_sge_init_flcntxt(adapter, q->fl[i].cntxt_id, 0,
+ q->fl[i].phys_addr, q->fl[i].size,
+ q->fl[i].buf_size, p->cong_thres, 1,
+ 0);
+ if (ret)
+ goto err_unlock;
+ }
+
+ ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_ETH].cntxt_id, USE_GTS,
+ SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr,
+ q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token,
+ 1, 0);
+ if (ret)
+ goto err_unlock;
+
+ if (ntxq > 1) {
+ ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_OFLD].cntxt_id,
+ USE_GTS, SGE_CNTXT_OFLD, id,
+ q->txq[TXQ_OFLD].phys_addr,
+ q->txq[TXQ_OFLD].size, 0, 1, 0);
+ if (ret)
+ goto err_unlock;
+ }
+
+ if (ntxq > 2) {
+ ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_CTRL].cntxt_id, 0,
+ SGE_CNTXT_CTRL, id,
+ q->txq[TXQ_CTRL].phys_addr,
+ q->txq[TXQ_CTRL].size,
+ q->txq[TXQ_CTRL].token, 1, 0);
+ if (ret)
+ goto err_unlock;
+ }
+
+ spin_unlock(&adapter->sge.reg_lock);
+ q->netdev = netdev;
+ t3_update_qset_coalesce(q, p);
+
+ /*
+ * We use atalk_ptr as a backpointer to a qset. In case a device is
+ * associated with multiple queue sets only the first one sets
+ * atalk_ptr.
+ */
+ if (netdev->atalk_ptr == NULL)
+ netdev->atalk_ptr = q;
+
+ refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL);
+ refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL);
+ refill_rspq(adapter, &q->rspq, q->rspq.size - 1);
+
+ t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) |
+ V_NEWTIMER(q->rspq.holdoff_tmr));
+
+ mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+ return 0;
+
+ err_unlock:
+ spin_unlock(&adapter->sge.reg_lock);
+ err:
+ t3_free_qset(adapter, q);
+ return ret;
+}
+
+/**
+ * t3_free_sge_resources - free SGE resources
+ * @adap: the adapter
+ *
+ * Frees resources used by the SGE queue sets.
+ */
+void t3_free_sge_resources(struct adapter *adap)
+{
+ int i;
+
+ for (i = 0; i < SGE_QSETS; ++i)
+ t3_free_qset(adap, &adap->sge.qs[i]);
+}
+
+/**
+ * t3_sge_start - enable SGE
+ * @adap: the adapter
+ *
+ * Enables the SGE for DMAs. This is the last step in starting packet
+ * transfers.
+ */
+void t3_sge_start(struct adapter *adap)
+{
+ t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE);
+}
+
+/**
+ * t3_sge_stop - disable SGE operation
+ * @adap: the adapter
+ *
+ * Disables the DMA engine. This can be called in emeregencies (e.g.,
+ * from error interrupts) or from normal process context. In the latter
+ * case it also disables any pending queue restart tasklets. Note that
+ * if it is called in interrupt context it cannot disable the restart
+ * tasklets as it cannot wait, however the tasklets will have no effect
+ * since the doorbells are disabled and the driver will call this again
+ * later from process context, at which time the tasklets will be stopped
+ * if they are still running.
+ */
+void t3_sge_stop(struct adapter *adap)
+{
+ t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, 0);
+ if (!in_interrupt()) {
+ int i;
+
+ for (i = 0; i < SGE_QSETS; ++i) {
+ struct sge_qset *qs = &adap->sge.qs[i];
+
+ tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk);
+ tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk);
+ }
+ }
+}
+
+/**
+ * t3_sge_init - initialize SGE
+ * @adap: the adapter
+ * @p: the SGE parameters
+ *
+ * Performs SGE initialization needed every time after a chip reset.
+ * We do not initialize any of the queue sets here, instead the driver
+ * top-level must request those individually. We also do not enable DMA
+ * here, that should be done after the queues have been set up.
+ */
+void t3_sge_init(struct adapter *adap, struct sge_params *p)
+{
+ unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12);
+
+ ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL |
+ F_CQCRDTCTRL |
+ V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS |
+ V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING;
+#if SGE_NUM_GENBITS == 1
+ ctrl |= F_EGRGENCTRL;
+#endif
+ if (adap->params.rev > 0) {
+ if (!(adap->flags & (USING_MSIX | USING_MSI)))
+ ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ;
+ ctrl |= F_CQCRDTCTRL | F_AVOIDCQOVFL;
+ }
+ t3_write_reg(adap, A_SG_CONTROL, ctrl);
+ t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) |
+ V_LORCQDRBTHRSH(512));
+ t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10);
+ t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) |
+ V_TIMEOUT(200 * core_ticks_per_usec(adap)));
+ t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, 1000);
+ t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256);
+ t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000);
+ t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256);
+ t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff));
+ t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024);
+}
+
+/**
+ * t3_sge_prep - one-time SGE initialization
+ * @adap: the associated adapter
+ * @p: SGE parameters
+ *
+ * Performs one-time initialization of SGE SW state. Includes determining
+ * defaults for the assorted SGE parameters, which admins can change until
+ * they are used to initialize the SGE.
+ */
+void __devinit t3_sge_prep(struct adapter *adap, struct sge_params *p)
+{
+ int i;
+
+ p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) -
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ for (i = 0; i < SGE_QSETS; ++i) {
+ struct qset_params *q = p->qset + i;
+
+ q->polling = adap->params.rev > 0;
+ q->coalesce_usecs = 5;
+ q->rspq_size = 1024;
+ q->fl_size = 4096;
+ q->jumbo_size = 512;
+ q->txq_size[TXQ_ETH] = 1024;
+ q->txq_size[TXQ_OFLD] = 1024;
+ q->txq_size[TXQ_CTRL] = 256;
+ q->cong_thres = 0;
+ }
+
+ spin_lock_init(&adap->sge.reg_lock);
+}
+
+/**
+ * t3_get_desc - dump an SGE descriptor for debugging purposes
+ * @qs: the queue set
+ * @qnum: identifies the specific queue (0..2: Tx, 3:response, 4..5: Rx)
+ * @idx: the descriptor index in the queue
+ * @data: where to dump the descriptor contents
+ *
+ * Dumps the contents of a HW descriptor of an SGE queue. Returns the
+ * size of the descriptor.
+ */
+int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
+ unsigned char *data)
+{
+ if (qnum >= 6)
+ return -EINVAL;
+
+ if (qnum < 3) {
+ if (!qs->txq[qnum].desc || idx >= qs->txq[qnum].size)
+ return -EINVAL;
+ memcpy(data, &qs->txq[qnum].desc[idx], sizeof(struct tx_desc));
+ return sizeof(struct tx_desc);
+ }
+
+ if (qnum == 3) {
+ if (!qs->rspq.desc || idx >= qs->rspq.size)
+ return -EINVAL;
+ memcpy(data, &qs->rspq.desc[idx], sizeof(struct rsp_desc));
+ return sizeof(struct rsp_desc);
+ }
+
+ qnum -= 4;
+ if (!qs->fl[qnum].desc || idx >= qs->fl[qnum].size)
+ return -EINVAL;
+ memcpy(data, &qs->fl[qnum].desc[idx], sizeof(struct rx_desc));
+ return sizeof(struct rx_desc);
+}
diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h
new file mode 100644
index 00000000000..514869e26a7
--- /dev/null
+++ b/drivers/net/cxgb3/sge_defs.h
@@ -0,0 +1,251 @@
+/*
+ * This file is automatically generated --- any changes will be lost.
+ */
+
+#ifndef _SGE_DEFS_H
+#define _SGE_DEFS_H
+
+#define S_EC_CREDITS 0
+#define M_EC_CREDITS 0x7FFF
+#define V_EC_CREDITS(x) ((x) << S_EC_CREDITS)
+#define G_EC_CREDITS(x) (((x) >> S_EC_CREDITS) & M_EC_CREDITS)
+
+#define S_EC_GTS 15
+#define V_EC_GTS(x) ((x) << S_EC_GTS)
+#define F_EC_GTS V_EC_GTS(1U)
+
+#define S_EC_INDEX 16
+#define M_EC_INDEX 0xFFFF
+#define V_EC_INDEX(x) ((x) << S_EC_INDEX)
+#define G_EC_INDEX(x) (((x) >> S_EC_INDEX) & M_EC_INDEX)
+
+#define S_EC_SIZE 0
+#define M_EC_SIZE 0xFFFF
+#define V_EC_SIZE(x) ((x) << S_EC_SIZE)
+#define G_EC_SIZE(x) (((x) >> S_EC_SIZE) & M_EC_SIZE)
+
+#define S_EC_BASE_LO 16
+#define M_EC_BASE_LO 0xFFFF
+#define V_EC_BASE_LO(x) ((x) << S_EC_BASE_LO)
+#define G_EC_BASE_LO(x) (((x) >> S_EC_BASE_LO) & M_EC_BASE_LO)
+
+#define S_EC_BASE_HI 0
+#define M_EC_BASE_HI 0xF
+#define V_EC_BASE_HI(x) ((x) << S_EC_BASE_HI)
+#define G_EC_BASE_HI(x) (((x) >> S_EC_BASE_HI) & M_EC_BASE_HI)
+
+#define S_EC_RESPQ 4
+#define M_EC_RESPQ 0x7
+#define V_EC_RESPQ(x) ((x) << S_EC_RESPQ)
+#define G_EC_RESPQ(x) (((x) >> S_EC_RESPQ) & M_EC_RESPQ)
+
+#define S_EC_TYPE 7
+#define M_EC_TYPE 0x7
+#define V_EC_TYPE(x) ((x) << S_EC_TYPE)
+#define G_EC_TYPE(x) (((x) >> S_EC_TYPE) & M_EC_TYPE)
+
+#define S_EC_GEN 10
+#define V_EC_GEN(x) ((x) << S_EC_GEN)
+#define F_EC_GEN V_EC_GEN(1U)
+
+#define S_EC_UP_TOKEN 11
+#define M_EC_UP_TOKEN 0xFFFFF
+#define V_EC_UP_TOKEN(x) ((x) << S_EC_UP_TOKEN)
+#define G_EC_UP_TOKEN(x) (((x) >> S_EC_UP_TOKEN) & M_EC_UP_TOKEN)
+
+#define S_EC_VALID 31
+#define V_EC_VALID(x) ((x) << S_EC_VALID)
+#define F_EC_VALID V_EC_VALID(1U)
+
+#define S_RQ_MSI_VEC 20
+#define M_RQ_MSI_VEC 0x3F
+#define V_RQ_MSI_VEC(x) ((x) << S_RQ_MSI_VEC)
+#define G_RQ_MSI_VEC(x) (((x) >> S_RQ_MSI_VEC) & M_RQ_MSI_VEC)
+
+#define S_RQ_INTR_EN 26
+#define V_RQ_INTR_EN(x) ((x) << S_RQ_INTR_EN)
+#define F_RQ_INTR_EN V_RQ_INTR_EN(1U)
+
+#define S_RQ_GEN 28
+#define V_RQ_GEN(x) ((x) << S_RQ_GEN)
+#define F_RQ_GEN V_RQ_GEN(1U)
+
+#define S_CQ_INDEX 0
+#define M_CQ_INDEX 0xFFFF
+#define V_CQ_INDEX(x) ((x) << S_CQ_INDEX)
+#define G_CQ_INDEX(x) (((x) >> S_CQ_INDEX) & M_CQ_INDEX)
+
+#define S_CQ_SIZE 16
+#define M_CQ_SIZE 0xFFFF
+#define V_CQ_SIZE(x) ((x) << S_CQ_SIZE)
+#define G_CQ_SIZE(x) (((x) >> S_CQ_SIZE) & M_CQ_SIZE)
+
+#define S_CQ_BASE_HI 0
+#define M_CQ_BASE_HI 0xFFFFF
+#define V_CQ_BASE_HI(x) ((x) << S_CQ_BASE_HI)
+#define G_CQ_BASE_HI(x) (((x) >> S_CQ_BASE_HI) & M_CQ_BASE_HI)
+
+#define S_CQ_RSPQ 20
+#define M_CQ_RSPQ 0x3F
+#define V_CQ_RSPQ(x) ((x) << S_CQ_RSPQ)
+#define G_CQ_RSPQ(x) (((x) >> S_CQ_RSPQ) & M_CQ_RSPQ)
+
+#define S_CQ_ASYNC_NOTIF 26
+#define V_CQ_ASYNC_NOTIF(x) ((x) << S_CQ_ASYNC_NOTIF)
+#define F_CQ_ASYNC_NOTIF V_CQ_ASYNC_NOTIF(1U)
+
+#define S_CQ_ARMED 27
+#define V_CQ_ARMED(x) ((x) << S_CQ_ARMED)
+#define F_CQ_ARMED V_CQ_ARMED(1U)
+
+#define S_CQ_ASYNC_NOTIF_SOL 28
+#define V_CQ_ASYNC_NOTIF_SOL(x) ((x) << S_CQ_ASYNC_NOTIF_SOL)
+#define F_CQ_ASYNC_NOTIF_SOL V_CQ_ASYNC_NOTIF_SOL(1U)
+
+#define S_CQ_GEN 29
+#define V_CQ_GEN(x) ((x) << S_CQ_GEN)
+#define F_CQ_GEN V_CQ_GEN(1U)
+
+#define S_CQ_OVERFLOW_MODE 31
+#define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE)
+#define F_CQ_OVERFLOW_MODE V_CQ_OVERFLOW_MODE(1U)
+
+#define S_CQ_CREDITS 0
+#define M_CQ_CREDITS 0xFFFF
+#define V_CQ_CREDITS(x) ((x) << S_CQ_CREDITS)
+#define G_CQ_CREDITS(x) (((x) >> S_CQ_CREDITS) & M_CQ_CREDITS)
+
+#define S_CQ_CREDIT_THRES 16
+#define M_CQ_CREDIT_THRES 0x1FFF
+#define V_CQ_CREDIT_THRES(x) ((x) << S_CQ_CREDIT_THRES)
+#define G_CQ_CREDIT_THRES(x) (((x) >> S_CQ_CREDIT_THRES) & M_CQ_CREDIT_THRES)
+
+#define S_FL_BASE_HI 0
+#define M_FL_BASE_HI 0xFFFFF
+#define V_FL_BASE_HI(x) ((x) << S_FL_BASE_HI)
+#define G_FL_BASE_HI(x) (((x) >> S_FL_BASE_HI) & M_FL_BASE_HI)
+
+#define S_FL_INDEX_LO 20
+#define M_FL_INDEX_LO 0xFFF
+#define V_FL_INDEX_LO(x) ((x) << S_FL_INDEX_LO)
+#define G_FL_INDEX_LO(x) (((x) >> S_FL_INDEX_LO) & M_FL_INDEX_LO)
+
+#define S_FL_INDEX_HI 0
+#define M_FL_INDEX_HI 0xF
+#define V_FL_INDEX_HI(x) ((x) << S_FL_INDEX_HI)
+#define G_FL_INDEX_HI(x) (((x) >> S_FL_INDEX_HI) & M_FL_INDEX_HI)
+
+#define S_FL_SIZE 4
+#define M_FL_SIZE 0xFFFF
+#define V_FL_SIZE(x) ((x) << S_FL_SIZE)
+#define G_FL_SIZE(x) (((x) >> S_FL_SIZE) & M_FL_SIZE)
+
+#define S_FL_GEN 20
+#define V_FL_GEN(x) ((x) << S_FL_GEN)
+#define F_FL_GEN V_FL_GEN(1U)
+
+#define S_FL_ENTRY_SIZE_LO 21
+#define M_FL_ENTRY_SIZE_LO 0x7FF
+#define V_FL_ENTRY_SIZE_LO(x) ((x) << S_FL_ENTRY_SIZE_LO)
+#define G_FL_ENTRY_SIZE_LO(x) (((x) >> S_FL_ENTRY_SIZE_LO) & M_FL_ENTRY_SIZE_LO)
+
+#define S_FL_ENTRY_SIZE_HI 0
+#define M_FL_ENTRY_SIZE_HI 0x1FFFFF
+#define V_FL_ENTRY_SIZE_HI(x) ((x) << S_FL_ENTRY_SIZE_HI)
+#define G_FL_ENTRY_SIZE_HI(x) (((x) >> S_FL_ENTRY_SIZE_HI) & M_FL_ENTRY_SIZE_HI)
+
+#define S_FL_CONG_THRES 21
+#define M_FL_CONG_THRES 0x3FF
+#define V_FL_CONG_THRES(x) ((x) << S_FL_CONG_THRES)
+#define G_FL_CONG_THRES(x) (((x) >> S_FL_CONG_THRES) & M_FL_CONG_THRES)
+
+#define S_FL_GTS 31
+#define V_FL_GTS(x) ((x) << S_FL_GTS)
+#define F_FL_GTS V_FL_GTS(1U)
+
+#define S_FLD_GEN1 31
+#define V_FLD_GEN1(x) ((x) << S_FLD_GEN1)
+#define F_FLD_GEN1 V_FLD_GEN1(1U)
+
+#define S_FLD_GEN2 0
+#define V_FLD_GEN2(x) ((x) << S_FLD_GEN2)
+#define F_FLD_GEN2 V_FLD_GEN2(1U)
+
+#define S_RSPD_TXQ1_CR 0
+#define M_RSPD_TXQ1_CR 0x7F
+#define V_RSPD_TXQ1_CR(x) ((x) << S_RSPD_TXQ1_CR)
+#define G_RSPD_TXQ1_CR(x) (((x) >> S_RSPD_TXQ1_CR) & M_RSPD_TXQ1_CR)
+
+#define S_RSPD_TXQ1_GTS 7
+#define V_RSPD_TXQ1_GTS(x) ((x) << S_RSPD_TXQ1_GTS)
+#define F_RSPD_TXQ1_GTS V_RSPD_TXQ1_GTS(1U)
+
+#define S_RSPD_TXQ2_CR 8
+#define M_RSPD_TXQ2_CR 0x7F
+#define V_RSPD_TXQ2_CR(x) ((x) << S_RSPD_TXQ2_CR)
+#define G_RSPD_TXQ2_CR(x) (((x) >> S_RSPD_TXQ2_CR) & M_RSPD_TXQ2_CR)
+
+#define S_RSPD_TXQ2_GTS 15
+#define V_RSPD_TXQ2_GTS(x) ((x) << S_RSPD_TXQ2_GTS)
+#define F_RSPD_TXQ2_GTS V_RSPD_TXQ2_GTS(1U)
+
+#define S_RSPD_TXQ0_CR 16
+#define M_RSPD_TXQ0_CR 0x7F
+#define V_RSPD_TXQ0_CR(x) ((x) << S_RSPD_TXQ0_CR)
+#define G_RSPD_TXQ0_CR(x) (((x) >> S_RSPD_TXQ0_CR) & M_RSPD_TXQ0_CR)
+
+#define S_RSPD_TXQ0_GTS 23
+#define V_RSPD_TXQ0_GTS(x) ((x) << S_RSPD_TXQ0_GTS)
+#define F_RSPD_TXQ0_GTS V_RSPD_TXQ0_GTS(1U)
+
+#define S_RSPD_EOP 24
+#define V_RSPD_EOP(x) ((x) << S_RSPD_EOP)
+#define F_RSPD_EOP V_RSPD_EOP(1U)
+
+#define S_RSPD_SOP 25
+#define V_RSPD_SOP(x) ((x) << S_RSPD_SOP)
+#define F_RSPD_SOP V_RSPD_SOP(1U)
+
+#define S_RSPD_ASYNC_NOTIF 26
+#define V_RSPD_ASYNC_NOTIF(x) ((x) << S_RSPD_ASYNC_NOTIF)
+#define F_RSPD_ASYNC_NOTIF V_RSPD_ASYNC_NOTIF(1U)
+
+#define S_RSPD_FL0_GTS 27
+#define V_RSPD_FL0_GTS(x) ((x) << S_RSPD_FL0_GTS)
+#define F_RSPD_FL0_GTS V_RSPD_FL0_GTS(1U)
+
+#define S_RSPD_FL1_GTS 28
+#define V_RSPD_FL1_GTS(x) ((x) << S_RSPD_FL1_GTS)
+#define F_RSPD_FL1_GTS V_RSPD_FL1_GTS(1U)
+
+#define S_RSPD_IMM_DATA_VALID 29
+#define V_RSPD_IMM_DATA_VALID(x) ((x) << S_RSPD_IMM_DATA_VALID)
+#define F_RSPD_IMM_DATA_VALID V_RSPD_IMM_DATA_VALID(1U)
+
+#define S_RSPD_OFFLOAD 30
+#define V_RSPD_OFFLOAD(x) ((x) << S_RSPD_OFFLOAD)
+#define F_RSPD_OFFLOAD V_RSPD_OFFLOAD(1U)
+
+#define S_RSPD_GEN1 31
+#define V_RSPD_GEN1(x) ((x) << S_RSPD_GEN1)
+#define F_RSPD_GEN1 V_RSPD_GEN1(1U)
+
+#define S_RSPD_LEN 0
+#define M_RSPD_LEN 0x7FFFFFFF
+#define V_RSPD_LEN(x) ((x) << S_RSPD_LEN)
+#define G_RSPD_LEN(x) (((x) >> S_RSPD_LEN) & M_RSPD_LEN)
+
+#define S_RSPD_FLQ 31
+#define V_RSPD_FLQ(x) ((x) << S_RSPD_FLQ)
+#define F_RSPD_FLQ V_RSPD_FLQ(1U)
+
+#define S_RSPD_GEN2 0
+#define V_RSPD_GEN2(x) ((x) << S_RSPD_GEN2)
+#define F_RSPD_GEN2 V_RSPD_GEN2(1U)
+
+#define S_RSPD_INR_VEC 1
+#define M_RSPD_INR_VEC 0x7F
+#define V_RSPD_INR_VEC(x) ((x) << S_RSPD_INR_VEC)
+#define G_RSPD_INR_VEC(x) (((x) >> S_RSPD_INR_VEC) & M_RSPD_INR_VEC)
+
+#endif /* _SGE_DEFS_H */
diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h
new file mode 100644
index 00000000000..b7a1a310dfd
--- /dev/null
+++ b/drivers/net/cxgb3/t3_cpl.h
@@ -0,0 +1,1444 @@
+/*
+ * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef T3_CPL_H
+#define T3_CPL_H
+
+#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD)
+# include <asm/byteorder.h>
+#endif
+
+enum CPL_opcode {
+ CPL_PASS_OPEN_REQ = 0x1,
+ CPL_PASS_ACCEPT_RPL = 0x2,
+ CPL_ACT_OPEN_REQ = 0x3,
+ CPL_SET_TCB = 0x4,
+ CPL_SET_TCB_FIELD = 0x5,
+ CPL_GET_TCB = 0x6,
+ CPL_PCMD = 0x7,
+ CPL_CLOSE_CON_REQ = 0x8,
+ CPL_CLOSE_LISTSRV_REQ = 0x9,
+ CPL_ABORT_REQ = 0xA,
+ CPL_ABORT_RPL = 0xB,
+ CPL_TX_DATA = 0xC,
+ CPL_RX_DATA_ACK = 0xD,
+ CPL_TX_PKT = 0xE,
+ CPL_RTE_DELETE_REQ = 0xF,
+ CPL_RTE_WRITE_REQ = 0x10,
+ CPL_RTE_READ_REQ = 0x11,
+ CPL_L2T_WRITE_REQ = 0x12,
+ CPL_L2T_READ_REQ = 0x13,
+ CPL_SMT_WRITE_REQ = 0x14,
+ CPL_SMT_READ_REQ = 0x15,
+ CPL_TX_PKT_LSO = 0x16,
+ CPL_PCMD_READ = 0x17,
+ CPL_BARRIER = 0x18,
+ CPL_TID_RELEASE = 0x1A,
+
+ CPL_CLOSE_LISTSRV_RPL = 0x20,
+ CPL_ERROR = 0x21,
+ CPL_GET_TCB_RPL = 0x22,
+ CPL_L2T_WRITE_RPL = 0x23,
+ CPL_PCMD_READ_RPL = 0x24,
+ CPL_PCMD_RPL = 0x25,
+ CPL_PEER_CLOSE = 0x26,
+ CPL_RTE_DELETE_RPL = 0x27,
+ CPL_RTE_WRITE_RPL = 0x28,
+ CPL_RX_DDP_COMPLETE = 0x29,
+ CPL_RX_PHYS_ADDR = 0x2A,
+ CPL_RX_PKT = 0x2B,
+ CPL_RX_URG_NOTIFY = 0x2C,
+ CPL_SET_TCB_RPL = 0x2D,
+ CPL_SMT_WRITE_RPL = 0x2E,
+ CPL_TX_DATA_ACK = 0x2F,
+
+ CPL_ABORT_REQ_RSS = 0x30,
+ CPL_ABORT_RPL_RSS = 0x31,
+ CPL_CLOSE_CON_RPL = 0x32,
+ CPL_ISCSI_HDR = 0x33,
+ CPL_L2T_READ_RPL = 0x34,
+ CPL_RDMA_CQE = 0x35,
+ CPL_RDMA_CQE_READ_RSP = 0x36,
+ CPL_RDMA_CQE_ERR = 0x37,
+ CPL_RTE_READ_RPL = 0x38,
+ CPL_RX_DATA = 0x39,
+
+ CPL_ACT_OPEN_RPL = 0x40,
+ CPL_PASS_OPEN_RPL = 0x41,
+ CPL_RX_DATA_DDP = 0x42,
+ CPL_SMT_READ_RPL = 0x43,
+
+ CPL_ACT_ESTABLISH = 0x50,
+ CPL_PASS_ESTABLISH = 0x51,
+
+ CPL_PASS_ACCEPT_REQ = 0x70,
+
+ CPL_ASYNC_NOTIF = 0x80, /* fake opcode for async notifications */
+
+ CPL_TX_DMA_ACK = 0xA0,
+ CPL_RDMA_READ_REQ = 0xA1,
+ CPL_RDMA_TERMINATE = 0xA2,
+ CPL_TRACE_PKT = 0xA3,
+ CPL_RDMA_EC_STATUS = 0xA5,
+
+ NUM_CPL_CMDS /* must be last and previous entries must be sorted */
+};
+
+enum CPL_error {
+ CPL_ERR_NONE = 0,
+ CPL_ERR_TCAM_PARITY = 1,
+ CPL_ERR_TCAM_FULL = 3,
+ CPL_ERR_CONN_RESET = 20,
+ CPL_ERR_CONN_EXIST = 22,
+ CPL_ERR_ARP_MISS = 23,
+ CPL_ERR_BAD_SYN = 24,
+ CPL_ERR_CONN_TIMEDOUT = 30,
+ CPL_ERR_XMIT_TIMEDOUT = 31,
+ CPL_ERR_PERSIST_TIMEDOUT = 32,
+ CPL_ERR_FINWAIT2_TIMEDOUT = 33,
+ CPL_ERR_KEEPALIVE_TIMEDOUT = 34,
+ CPL_ERR_RTX_NEG_ADVICE = 35,
+ CPL_ERR_PERSIST_NEG_ADVICE = 36,
+ CPL_ERR_ABORT_FAILED = 42,
+ CPL_ERR_GENERAL = 99
+};
+
+enum {
+ CPL_CONN_POLICY_AUTO = 0,
+ CPL_CONN_POLICY_ASK = 1,
+ CPL_CONN_POLICY_DENY = 3
+};
+
+enum {
+ ULP_MODE_NONE = 0,
+ ULP_MODE_ISCSI = 2,
+ ULP_MODE_RDMA = 4,
+ ULP_MODE_TCPDDP = 5
+};
+
+enum {
+ ULP_CRC_HEADER = 1 << 0,
+ ULP_CRC_DATA = 1 << 1
+};
+
+enum {
+ CPL_PASS_OPEN_ACCEPT,
+ CPL_PASS_OPEN_REJECT
+};
+
+enum {
+ CPL_ABORT_SEND_RST = 0,
+ CPL_ABORT_NO_RST,
+ CPL_ABORT_POST_CLOSE_REQ = 2
+};
+
+enum { /* TX_PKT_LSO ethernet types */
+ CPL_ETH_II,
+ CPL_ETH_II_VLAN,
+ CPL_ETH_802_3,
+ CPL_ETH_802_3_VLAN
+};
+
+enum { /* TCP congestion control algorithms */
+ CONG_ALG_RENO,
+ CONG_ALG_TAHOE,
+ CONG_ALG_NEWRENO,
+ CONG_ALG_HIGHSPEED
+};
+
+union opcode_tid {
+ __be32 opcode_tid;
+ __u8 opcode;
+};
+
+#define S_OPCODE 24
+#define V_OPCODE(x) ((x) << S_OPCODE)
+#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF)
+#define G_TID(x) ((x) & 0xFFFFFF)
+
+/* tid is assumed to be 24-bits */
+#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid))
+
+#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid)
+
+/* extract the TID from a CPL command */
+#define GET_TID(cmd) (G_TID(ntohl(OPCODE_TID(cmd))))
+
+struct tcp_options {
+ __be16 mss;
+ __u8 wsf;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:5;
+ __u8 ecn:1;
+ __u8 sack:1;
+ __u8 tstamp:1;
+#else
+ __u8 tstamp:1;
+ __u8 sack:1;
+ __u8 ecn:1;
+ __u8:5;
+#endif
+};
+
+struct rss_header {
+ __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 cpu_idx:6;
+ __u8 hash_type:2;
+#else
+ __u8 hash_type:2;
+ __u8 cpu_idx:6;
+#endif
+ __be16 cq_idx;
+ __be32 rss_hash_val;
+};
+
+#ifndef CHELSIO_FW
+struct work_request_hdr {
+ __be32 wr_hi;
+ __be32 wr_lo;
+};
+
+/* wr_hi fields */
+#define S_WR_SGE_CREDITS 0
+#define M_WR_SGE_CREDITS 0xFF
+#define V_WR_SGE_CREDITS(x) ((x) << S_WR_SGE_CREDITS)
+#define G_WR_SGE_CREDITS(x) (((x) >> S_WR_SGE_CREDITS) & M_WR_SGE_CREDITS)
+
+#define S_WR_SGLSFLT 8
+#define M_WR_SGLSFLT 0xFF
+#define V_WR_SGLSFLT(x) ((x) << S_WR_SGLSFLT)
+#define G_WR_SGLSFLT(x) (((x) >> S_WR_SGLSFLT) & M_WR_SGLSFLT)
+
+#define S_WR_BCNTLFLT 16
+#define M_WR_BCNTLFLT 0xF
+#define V_WR_BCNTLFLT(x) ((x) << S_WR_BCNTLFLT)
+#define G_WR_BCNTLFLT(x) (((x) >> S_WR_BCNTLFLT) & M_WR_BCNTLFLT)
+
+#define S_WR_DATATYPE 20
+#define V_WR_DATATYPE(x) ((x) << S_WR_DATATYPE)
+#define F_WR_DATATYPE V_WR_DATATYPE(1U)
+
+#define S_WR_COMPL 21
+#define V_WR_COMPL(x) ((x) << S_WR_COMPL)
+#define F_WR_COMPL V_WR_COMPL(1U)
+
+#define S_WR_EOP 22
+#define V_WR_EOP(x) ((x) << S_WR_EOP)
+#define F_WR_EOP V_WR_EOP(1U)
+
+#define S_WR_SOP 23
+#define V_WR_SOP(x) ((x) << S_WR_SOP)
+#define F_WR_SOP V_WR_SOP(1U)
+
+#define S_WR_OP 24
+#define M_WR_OP 0xFF
+#define V_WR_OP(x) ((x) << S_WR_OP)
+#define G_WR_OP(x) (((x) >> S_WR_OP) & M_WR_OP)
+
+/* wr_lo fields */
+#define S_WR_LEN 0
+#define M_WR_LEN 0xFF
+#define V_WR_LEN(x) ((x) << S_WR_LEN)
+#define G_WR_LEN(x) (((x) >> S_WR_LEN) & M_WR_LEN)
+
+#define S_WR_TID 8
+#define M_WR_TID 0xFFFFF
+#define V_WR_TID(x) ((x) << S_WR_TID)
+#define G_WR_TID(x) (((x) >> S_WR_TID) & M_WR_TID)
+
+#define S_WR_CR_FLUSH 30
+#define V_WR_CR_FLUSH(x) ((x) << S_WR_CR_FLUSH)
+#define F_WR_CR_FLUSH V_WR_CR_FLUSH(1U)
+
+#define S_WR_GEN 31
+#define V_WR_GEN(x) ((x) << S_WR_GEN)
+#define F_WR_GEN V_WR_GEN(1U)
+
+# define WR_HDR struct work_request_hdr wr
+# define RSS_HDR
+#else
+# define WR_HDR
+# define RSS_HDR struct rss_header rss_hdr;
+#endif
+
+/* option 0 lower-half fields */
+#define S_CPL_STATUS 0
+#define M_CPL_STATUS 0xFF
+#define V_CPL_STATUS(x) ((x) << S_CPL_STATUS)
+#define G_CPL_STATUS(x) (((x) >> S_CPL_STATUS) & M_CPL_STATUS)
+
+#define S_INJECT_TIMER 6
+#define V_INJECT_TIMER(x) ((x) << S_INJECT_TIMER)
+#define F_INJECT_TIMER V_INJECT_TIMER(1U)
+
+#define S_NO_OFFLOAD 7
+#define V_NO_OFFLOAD(x) ((x) << S_NO_OFFLOAD)
+#define F_NO_OFFLOAD V_NO_OFFLOAD(1U)
+
+#define S_ULP_MODE 8
+#define M_ULP_MODE 0xF
+#define V_ULP_MODE(x) ((x) << S_ULP_MODE)
+#define G_ULP_MODE(x) (((x) >> S_ULP_MODE) & M_ULP_MODE)
+
+#define S_RCV_BUFSIZ 12
+#define M_RCV_BUFSIZ 0x3FFF
+#define V_RCV_BUFSIZ(x) ((x) << S_RCV_BUFSIZ)
+#define G_RCV_BUFSIZ(x) (((x) >> S_RCV_BUFSIZ) & M_RCV_BUFSIZ)
+
+#define S_TOS 26
+#define M_TOS 0x3F
+#define V_TOS(x) ((x) << S_TOS)
+#define G_TOS(x) (((x) >> S_TOS) & M_TOS)
+
+/* option 0 upper-half fields */
+#define S_DELACK 0
+#define V_DELACK(x) ((x) << S_DELACK)
+#define F_DELACK V_DELACK(1U)
+
+#define S_NO_CONG 1
+#define V_NO_CONG(x) ((x) << S_NO_CONG)
+#define F_NO_CONG V_NO_CONG(1U)
+
+#define S_SRC_MAC_SEL 2
+#define M_SRC_MAC_SEL 0x3
+#define V_SRC_MAC_SEL(x) ((x) << S_SRC_MAC_SEL)
+#define G_SRC_MAC_SEL(x) (((x) >> S_SRC_MAC_SEL) & M_SRC_MAC_SEL)
+
+#define S_L2T_IDX 4
+#define M_L2T_IDX 0x7FF
+#define V_L2T_IDX(x) ((x) << S_L2T_IDX)
+#define G_L2T_IDX(x) (((x) >> S_L2T_IDX) & M_L2T_IDX)
+
+#define S_TX_CHANNEL 15
+#define V_TX_CHANNEL(x) ((x) << S_TX_CHANNEL)
+#define F_TX_CHANNEL V_TX_CHANNEL(1U)
+
+#define S_TCAM_BYPASS 16
+#define V_TCAM_BYPASS(x) ((x) << S_TCAM_BYPASS)
+#define F_TCAM_BYPASS V_TCAM_BYPASS(1U)
+
+#define S_NAGLE 17
+#define V_NAGLE(x) ((x) << S_NAGLE)
+#define F_NAGLE V_NAGLE(1U)
+
+#define S_WND_SCALE 18
+#define M_WND_SCALE 0xF
+#define V_WND_SCALE(x) ((x) << S_WND_SCALE)
+#define G_WND_SCALE(x) (((x) >> S_WND_SCALE) & M_WND_SCALE)
+
+#define S_KEEP_ALIVE 22
+#define V_KEEP_ALIVE(x) ((x) << S_KEEP_ALIVE)
+#define F_KEEP_ALIVE V_KEEP_ALIVE(1U)
+
+#define S_MAX_RETRANS 23
+#define M_MAX_RETRANS 0xF
+#define V_MAX_RETRANS(x) ((x) << S_MAX_RETRANS)
+#define G_MAX_RETRANS(x) (((x) >> S_MAX_RETRANS) & M_MAX_RETRANS)
+
+#define S_MAX_RETRANS_OVERRIDE 27
+#define V_MAX_RETRANS_OVERRIDE(x) ((x) << S_MAX_RETRANS_OVERRIDE)
+#define F_MAX_RETRANS_OVERRIDE V_MAX_RETRANS_OVERRIDE(1U)
+
+#define S_MSS_IDX 28
+#define M_MSS_IDX 0xF
+#define V_MSS_IDX(x) ((x) << S_MSS_IDX)
+#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX)
+
+/* option 1 fields */
+#define S_RSS_ENABLE 0
+#define V_RSS_ENABLE(x) ((x) << S_RSS_ENABLE)
+#define F_RSS_ENABLE V_RSS_ENABLE(1U)
+
+#define S_RSS_MASK_LEN 1
+#define M_RSS_MASK_LEN 0x7
+#define V_RSS_MASK_LEN(x) ((x) << S_RSS_MASK_LEN)
+#define G_RSS_MASK_LEN(x) (((x) >> S_RSS_MASK_LEN) & M_RSS_MASK_LEN)
+
+#define S_CPU_IDX 4
+#define M_CPU_IDX 0x3F
+#define V_CPU_IDX(x) ((x) << S_CPU_IDX)
+#define G_CPU_IDX(x) (((x) >> S_CPU_IDX) & M_CPU_IDX)
+
+#define S_MAC_MATCH_VALID 18
+#define V_MAC_MATCH_VALID(x) ((x) << S_MAC_MATCH_VALID)
+#define F_MAC_MATCH_VALID V_MAC_MATCH_VALID(1U)
+
+#define S_CONN_POLICY 19
+#define M_CONN_POLICY 0x3
+#define V_CONN_POLICY(x) ((x) << S_CONN_POLICY)
+#define G_CONN_POLICY(x) (((x) >> S_CONN_POLICY) & M_CONN_POLICY)
+
+#define S_SYN_DEFENSE 21
+#define V_SYN_DEFENSE(x) ((x) << S_SYN_DEFENSE)
+#define F_SYN_DEFENSE V_SYN_DEFENSE(1U)
+
+#define S_VLAN_PRI 22
+#define M_VLAN_PRI 0x3
+#define V_VLAN_PRI(x) ((x) << S_VLAN_PRI)
+#define G_VLAN_PRI(x) (((x) >> S_VLAN_PRI) & M_VLAN_PRI)
+
+#define S_VLAN_PRI_VALID 24
+#define V_VLAN_PRI_VALID(x) ((x) << S_VLAN_PRI_VALID)
+#define F_VLAN_PRI_VALID V_VLAN_PRI_VALID(1U)
+
+#define S_PKT_TYPE 25
+#define M_PKT_TYPE 0x3
+#define V_PKT_TYPE(x) ((x) << S_PKT_TYPE)
+#define G_PKT_TYPE(x) (((x) >> S_PKT_TYPE) & M_PKT_TYPE)
+
+#define S_MAC_MATCH 27
+#define M_MAC_MATCH 0x1F
+#define V_MAC_MATCH(x) ((x) << S_MAC_MATCH)
+#define G_MAC_MATCH(x) (((x) >> S_MAC_MATCH) & M_MAC_MATCH)
+
+/* option 2 fields */
+#define S_CPU_INDEX 0
+#define M_CPU_INDEX 0x7F
+#define V_CPU_INDEX(x) ((x) << S_CPU_INDEX)
+#define G_CPU_INDEX(x) (((x) >> S_CPU_INDEX) & M_CPU_INDEX)
+
+#define S_CPU_INDEX_VALID 7
+#define V_CPU_INDEX_VALID(x) ((x) << S_CPU_INDEX_VALID)
+#define F_CPU_INDEX_VALID V_CPU_INDEX_VALID(1U)
+
+#define S_RX_COALESCE 8
+#define M_RX_COALESCE 0x3
+#define V_RX_COALESCE(x) ((x) << S_RX_COALESCE)
+#define G_RX_COALESCE(x) (((x) >> S_RX_COALESCE) & M_RX_COALESCE)
+
+#define S_RX_COALESCE_VALID 10
+#define V_RX_COALESCE_VALID(x) ((x) << S_RX_COALESCE_VALID)
+#define F_RX_COALESCE_VALID V_RX_COALESCE_VALID(1U)
+
+#define S_CONG_CONTROL_FLAVOR 11
+#define M_CONG_CONTROL_FLAVOR 0x3
+#define V_CONG_CONTROL_FLAVOR(x) ((x) << S_CONG_CONTROL_FLAVOR)
+#define G_CONG_CONTROL_FLAVOR(x) (((x) >> S_CONG_CONTROL_FLAVOR) & M_CONG_CONTROL_FLAVOR)
+
+#define S_PACING_FLAVOR 13
+#define M_PACING_FLAVOR 0x3
+#define V_PACING_FLAVOR(x) ((x) << S_PACING_FLAVOR)
+#define G_PACING_FLAVOR(x) (((x) >> S_PACING_FLAVOR) & M_PACING_FLAVOR)
+
+#define S_FLAVORS_VALID 15
+#define V_FLAVORS_VALID(x) ((x) << S_FLAVORS_VALID)
+#define F_FLAVORS_VALID V_FLAVORS_VALID(1U)
+
+#define S_RX_FC_DISABLE 16
+#define V_RX_FC_DISABLE(x) ((x) << S_RX_FC_DISABLE)
+#define F_RX_FC_DISABLE V_RX_FC_DISABLE(1U)
+
+#define S_RX_FC_VALID 17
+#define V_RX_FC_VALID(x) ((x) << S_RX_FC_VALID)
+#define F_RX_FC_VALID V_RX_FC_VALID(1U)
+
+struct cpl_pass_open_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 opt0h;
+ __be32 opt0l;
+ __be32 peer_netmask;
+ __be32 opt1;
+};
+
+struct cpl_pass_open_rpl {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __u8 resvd[7];
+ __u8 status;
+};
+
+struct cpl_pass_establish {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 tos_tid;
+ __be16 l2t_idx;
+ __be16 tcp_opt;
+ __be32 snd_isn;
+ __be32 rcv_isn;
+};
+
+/* cpl_pass_establish.tos_tid fields */
+#define S_PASS_OPEN_TID 0
+#define M_PASS_OPEN_TID 0xFFFFFF
+#define V_PASS_OPEN_TID(x) ((x) << S_PASS_OPEN_TID)
+#define G_PASS_OPEN_TID(x) (((x) >> S_PASS_OPEN_TID) & M_PASS_OPEN_TID)
+
+#define S_PASS_OPEN_TOS 24
+#define M_PASS_OPEN_TOS 0xFF
+#define V_PASS_OPEN_TOS(x) ((x) << S_PASS_OPEN_TOS)
+#define G_PASS_OPEN_TOS(x) (((x) >> S_PASS_OPEN_TOS) & M_PASS_OPEN_TOS)
+
+/* cpl_pass_establish.l2t_idx fields */
+#define S_L2T_IDX16 5
+#define M_L2T_IDX16 0x7FF
+#define V_L2T_IDX16(x) ((x) << S_L2T_IDX16)
+#define G_L2T_IDX16(x) (((x) >> S_L2T_IDX16) & M_L2T_IDX16)
+
+/* cpl_pass_establish.tcp_opt fields (also applies act_open_establish) */
+#define G_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1)
+#define G_TCPOPT_SACK(x) (((x) >> 6) & 1)
+#define G_TCPOPT_TSTAMP(x) (((x) >> 7) & 1)
+#define G_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf)
+#define G_TCPOPT_MSS(x) (((x) >> 12) & 0xf)
+
+struct cpl_pass_accept_req {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 tos_tid;
+ struct tcp_options tcp_options;
+ __u8 dst_mac[6];
+ __be16 vlan_tag;
+ __u8 src_mac[6];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:3;
+ __u8 addr_idx:3;
+ __u8 port_idx:1;
+ __u8 exact_match:1;
+#else
+ __u8 exact_match:1;
+ __u8 port_idx:1;
+ __u8 addr_idx:3;
+ __u8:3;
+#endif
+ __u8 rsvd;
+ __be32 rcv_isn;
+ __be32 rsvd2;
+};
+
+struct cpl_pass_accept_rpl {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 opt2;
+ __be32 rsvd;
+ __be32 peer_ip;
+ __be32 opt0h;
+ __be32 opt0l_status;
+};
+
+struct cpl_act_open_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 opt0h;
+ __be32 opt0l;
+ __be32 params;
+ __be32 opt2;
+};
+
+/* cpl_act_open_req.params fields */
+#define S_AOPEN_VLAN_PRI 9
+#define M_AOPEN_VLAN_PRI 0x3
+#define V_AOPEN_VLAN_PRI(x) ((x) << S_AOPEN_VLAN_PRI)
+#define G_AOPEN_VLAN_PRI(x) (((x) >> S_AOPEN_VLAN_PRI) & M_AOPEN_VLAN_PRI)
+
+#define S_AOPEN_VLAN_PRI_VALID 11
+#define V_AOPEN_VLAN_PRI_VALID(x) ((x) << S_AOPEN_VLAN_PRI_VALID)
+#define F_AOPEN_VLAN_PRI_VALID V_AOPEN_VLAN_PRI_VALID(1U)
+
+#define S_AOPEN_PKT_TYPE 12
+#define M_AOPEN_PKT_TYPE 0x3
+#define V_AOPEN_PKT_TYPE(x) ((x) << S_AOPEN_PKT_TYPE)
+#define G_AOPEN_PKT_TYPE(x) (((x) >> S_AOPEN_PKT_TYPE) & M_AOPEN_PKT_TYPE)
+
+#define S_AOPEN_MAC_MATCH 14
+#define M_AOPEN_MAC_MATCH 0x1F
+#define V_AOPEN_MAC_MATCH(x) ((x) << S_AOPEN_MAC_MATCH)
+#define G_AOPEN_MAC_MATCH(x) (((x) >> S_AOPEN_MAC_MATCH) & M_AOPEN_MAC_MATCH)
+
+#define S_AOPEN_MAC_MATCH_VALID 19
+#define V_AOPEN_MAC_MATCH_VALID(x) ((x) << S_AOPEN_MAC_MATCH_VALID)
+#define F_AOPEN_MAC_MATCH_VALID V_AOPEN_MAC_MATCH_VALID(1U)
+
+#define S_AOPEN_IFF_VLAN 20
+#define M_AOPEN_IFF_VLAN 0xFFF
+#define V_AOPEN_IFF_VLAN(x) ((x) << S_AOPEN_IFF_VLAN)
+#define G_AOPEN_IFF_VLAN(x) (((x) >> S_AOPEN_IFF_VLAN) & M_AOPEN_IFF_VLAN)
+
+struct cpl_act_open_rpl {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 atid;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct cpl_act_establish {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 tos_tid;
+ __be16 l2t_idx;
+ __be16 tcp_opt;
+ __be32 snd_isn;
+ __be32 rcv_isn;
+};
+
+struct cpl_get_tcb {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 cpuno;
+ __be16 rsvd;
+};
+
+struct cpl_get_tcb_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd;
+ __u8 status;
+ __be16 len;
+};
+
+struct cpl_set_tcb {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 reply;
+ __u8 cpu_idx;
+ __be16 len;
+};
+
+/* cpl_set_tcb.reply fields */
+#define S_NO_REPLY 7
+#define V_NO_REPLY(x) ((x) << S_NO_REPLY)
+#define F_NO_REPLY V_NO_REPLY(1U)
+
+struct cpl_set_tcb_field {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 reply;
+ __u8 cpu_idx;
+ __be16 word;
+ __be64 mask;
+ __be64 val;
+};
+
+struct cpl_set_tcb_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct cpl_pcmd {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd[3];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 src:1;
+ __u8 bundle:1;
+ __u8 channel:1;
+ __u8:5;
+#else
+ __u8:5;
+ __u8 channel:1;
+ __u8 bundle:1;
+ __u8 src:1;
+#endif
+ __be32 pcmd_parm[2];
+};
+
+struct cpl_pcmd_reply {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd;
+ __be16 len;
+};
+
+struct cpl_close_con_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd;
+};
+
+struct cpl_close_con_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+ __be32 snd_nxt;
+ __be32 rcv_nxt;
+};
+
+struct cpl_close_listserv_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd0;
+ __u8 cpu_idx;
+ __be16 rsvd1;
+};
+
+struct cpl_close_listserv_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct cpl_abort_req_rss {
+ RSS_HDR union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 status;
+ __u8 rsvd2[6];
+};
+
+struct cpl_abort_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 cmd;
+ __u8 rsvd2[6];
+};
+
+struct cpl_abort_rpl_rss {
+ RSS_HDR union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 status;
+ __u8 rsvd2[6];
+};
+
+struct cpl_abort_rpl {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 cmd;
+ __u8 rsvd2[6];
+};
+
+struct cpl_peer_close {
+ RSS_HDR union opcode_tid ot;
+ __be32 rcv_nxt;
+};
+
+struct tx_data_wr {
+ __be32 wr_hi;
+ __be32 wr_lo;
+ __be32 len;
+ __be32 flags;
+ __be32 sndseq;
+ __be32 param;
+};
+
+/* tx_data_wr.param fields */
+#define S_TX_PORT 0
+#define M_TX_PORT 0x7
+#define V_TX_PORT(x) ((x) << S_TX_PORT)
+#define G_TX_PORT(x) (((x) >> S_TX_PORT) & M_TX_PORT)
+
+#define S_TX_MSS 4
+#define M_TX_MSS 0xF
+#define V_TX_MSS(x) ((x) << S_TX_MSS)
+#define G_TX_MSS(x) (((x) >> S_TX_MSS) & M_TX_MSS)
+
+#define S_TX_QOS 8
+#define M_TX_QOS 0xFF
+#define V_TX_QOS(x) ((x) << S_TX_QOS)
+#define G_TX_QOS(x) (((x) >> S_TX_QOS) & M_TX_QOS)
+
+#define S_TX_SNDBUF 16
+#define M_TX_SNDBUF 0xFFFF
+#define V_TX_SNDBUF(x) ((x) << S_TX_SNDBUF)
+#define G_TX_SNDBUF(x) (((x) >> S_TX_SNDBUF) & M_TX_SNDBUF)
+
+struct cpl_tx_data {
+ union opcode_tid ot;
+ __be32 len;
+ __be32 rsvd;
+ __be16 urg;
+ __be16 flags;
+};
+
+/* cpl_tx_data.flags fields */
+#define S_TX_ULP_SUBMODE 6
+#define M_TX_ULP_SUBMODE 0xF
+#define V_TX_ULP_SUBMODE(x) ((x) << S_TX_ULP_SUBMODE)
+#define G_TX_ULP_SUBMODE(x) (((x) >> S_TX_ULP_SUBMODE) & M_TX_ULP_SUBMODE)
+
+#define S_TX_ULP_MODE 10
+#define M_TX_ULP_MODE 0xF
+#define V_TX_ULP_MODE(x) ((x) << S_TX_ULP_MODE)
+#define G_TX_ULP_MODE(x) (((x) >> S_TX_ULP_MODE) & M_TX_ULP_MODE)
+
+#define S_TX_SHOVE 14
+#define V_TX_SHOVE(x) ((x) << S_TX_SHOVE)
+#define F_TX_SHOVE V_TX_SHOVE(1U)
+
+#define S_TX_MORE 15
+#define V_TX_MORE(x) ((x) << S_TX_MORE)
+#define F_TX_MORE V_TX_MORE(1U)
+
+/* additional tx_data_wr.flags fields */
+#define S_TX_CPU_IDX 0
+#define M_TX_CPU_IDX 0x3F
+#define V_TX_CPU_IDX(x) ((x) << S_TX_CPU_IDX)
+#define G_TX_CPU_IDX(x) (((x) >> S_TX_CPU_IDX) & M_TX_CPU_IDX)
+
+#define S_TX_URG 16
+#define V_TX_URG(x) ((x) << S_TX_URG)
+#define F_TX_URG V_TX_URG(1U)
+
+#define S_TX_CLOSE 17
+#define V_TX_CLOSE(x) ((x) << S_TX_CLOSE)
+#define F_TX_CLOSE V_TX_CLOSE(1U)
+
+#define S_TX_INIT 18
+#define V_TX_INIT(x) ((x) << S_TX_INIT)
+#define F_TX_INIT V_TX_INIT(1U)
+
+#define S_TX_IMM_ACK 19
+#define V_TX_IMM_ACK(x) ((x) << S_TX_IMM_ACK)
+#define F_TX_IMM_ACK V_TX_IMM_ACK(1U)
+
+#define S_TX_IMM_DMA 20
+#define V_TX_IMM_DMA(x) ((x) << S_TX_IMM_DMA)
+#define F_TX_IMM_DMA V_TX_IMM_DMA(1U)
+
+struct cpl_tx_data_ack {
+ RSS_HDR union opcode_tid ot;
+ __be32 ack_seq;
+};
+
+struct cpl_wr_ack {
+ RSS_HDR union opcode_tid ot;
+ __be16 credits;
+ __be16 rsvd;
+ __be32 snd_nxt;
+ __be32 snd_una;
+};
+
+struct cpl_rdma_ec_status {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct mngt_pktsched_wr {
+ __be32 wr_hi;
+ __be32 wr_lo;
+ __u8 mngt_opcode;
+ __u8 rsvd[7];
+ __u8 sched;
+ __u8 idx;
+ __u8 min;
+ __u8 max;
+ __u8 binding;
+ __u8 rsvd1[3];
+};
+
+struct cpl_iscsi_hdr {
+ RSS_HDR union opcode_tid ot;
+ __be16 pdu_len_ddp;
+ __be16 len;
+ __be32 seq;
+ __be16 urg;
+ __u8 rsvd;
+ __u8 status;
+};
+
+/* cpl_iscsi_hdr.pdu_len_ddp fields */
+#define S_ISCSI_PDU_LEN 0
+#define M_ISCSI_PDU_LEN 0x7FFF
+#define V_ISCSI_PDU_LEN(x) ((x) << S_ISCSI_PDU_LEN)
+#define G_ISCSI_PDU_LEN(x) (((x) >> S_ISCSI_PDU_LEN) & M_ISCSI_PDU_LEN)
+
+#define S_ISCSI_DDP 15
+#define V_ISCSI_DDP(x) ((x) << S_ISCSI_DDP)
+#define F_ISCSI_DDP V_ISCSI_DDP(1U)
+
+struct cpl_rx_data {
+ RSS_HDR union opcode_tid ot;
+ __be16 rsvd;
+ __be16 len;
+ __be32 seq;
+ __be16 urg;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 dack_mode:2;
+ __u8 psh:1;
+ __u8 heartbeat:1;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 heartbeat:1;
+ __u8 psh:1;
+ __u8 dack_mode:2;
+#endif
+ __u8 status;
+};
+
+struct cpl_rx_data_ack {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 credit_dack;
+};
+
+/* cpl_rx_data_ack.ack_seq fields */
+#define S_RX_CREDITS 0
+#define M_RX_CREDITS 0x7FFFFFF
+#define V_RX_CREDITS(x) ((x) << S_RX_CREDITS)
+#define G_RX_CREDITS(x) (((x) >> S_RX_CREDITS) & M_RX_CREDITS)
+
+#define S_RX_MODULATE 27
+#define V_RX_MODULATE(x) ((x) << S_RX_MODULATE)
+#define F_RX_MODULATE V_RX_MODULATE(1U)
+
+#define S_RX_FORCE_ACK 28
+#define V_RX_FORCE_ACK(x) ((x) << S_RX_FORCE_ACK)
+#define F_RX_FORCE_ACK V_RX_FORCE_ACK(1U)
+
+#define S_RX_DACK_MODE 29
+#define M_RX_DACK_MODE 0x3
+#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE)
+#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE)
+
+#define S_RX_DACK_CHANGE 31
+#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE)
+#define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U)
+
+struct cpl_rx_urg_notify {
+ RSS_HDR union opcode_tid ot;
+ __be32 seq;
+};
+
+struct cpl_rx_ddp_complete {
+ RSS_HDR union opcode_tid ot;
+ __be32 ddp_report;
+};
+
+struct cpl_rx_data_ddp {
+ RSS_HDR union opcode_tid ot;
+ __be16 urg;
+ __be16 len;
+ __be32 seq;
+ union {
+ __be32 nxt_seq;
+ __be32 ddp_report;
+ };
+ __be32 ulp_crc;
+ __be32 ddpvld_status;
+};
+
+/* cpl_rx_data_ddp.ddpvld_status fields */
+#define S_DDP_STATUS 0
+#define M_DDP_STATUS 0xFF
+#define V_DDP_STATUS(x) ((x) << S_DDP_STATUS)
+#define G_DDP_STATUS(x) (((x) >> S_DDP_STATUS) & M_DDP_STATUS)
+
+#define S_DDP_VALID 15
+#define M_DDP_VALID 0x1FFFF
+#define V_DDP_VALID(x) ((x) << S_DDP_VALID)
+#define G_DDP_VALID(x) (((x) >> S_DDP_VALID) & M_DDP_VALID)
+
+#define S_DDP_PPOD_MISMATCH 15
+#define V_DDP_PPOD_MISMATCH(x) ((x) << S_DDP_PPOD_MISMATCH)
+#define F_DDP_PPOD_MISMATCH V_DDP_PPOD_MISMATCH(1U)
+
+#define S_DDP_PDU 16
+#define V_DDP_PDU(x) ((x) << S_DDP_PDU)
+#define F_DDP_PDU V_DDP_PDU(1U)
+
+#define S_DDP_LLIMIT_ERR 17
+#define V_DDP_LLIMIT_ERR(x) ((x) << S_DDP_LLIMIT_ERR)
+#define F_DDP_LLIMIT_ERR V_DDP_LLIMIT_ERR(1U)
+
+#define S_DDP_PPOD_PARITY_ERR 18
+#define V_DDP_PPOD_PARITY_ERR(x) ((x) << S_DDP_PPOD_PARITY_ERR)
+#define F_DDP_PPOD_PARITY_ERR V_DDP_PPOD_PARITY_ERR(1U)
+
+#define S_DDP_PADDING_ERR 19
+#define V_DDP_PADDING_ERR(x) ((x) << S_DDP_PADDING_ERR)
+#define F_DDP_PADDING_ERR V_DDP_PADDING_ERR(1U)
+
+#define S_DDP_HDRCRC_ERR 20
+#define V_DDP_HDRCRC_ERR(x) ((x) << S_DDP_HDRCRC_ERR)
+#define F_DDP_HDRCRC_ERR V_DDP_HDRCRC_ERR(1U)
+
+#define S_DDP_DATACRC_ERR 21
+#define V_DDP_DATACRC_ERR(x) ((x) << S_DDP_DATACRC_ERR)
+#define F_DDP_DATACRC_ERR V_DDP_DATACRC_ERR(1U)
+
+#define S_DDP_INVALID_TAG 22
+#define V_DDP_INVALID_TAG(x) ((x) << S_DDP_INVALID_TAG)
+#define F_DDP_INVALID_TAG V_DDP_INVALID_TAG(1U)
+
+#define S_DDP_ULIMIT_ERR 23
+#define V_DDP_ULIMIT_ERR(x) ((x) << S_DDP_ULIMIT_ERR)
+#define F_DDP_ULIMIT_ERR V_DDP_ULIMIT_ERR(1U)
+
+#define S_DDP_OFFSET_ERR 24
+#define V_DDP_OFFSET_ERR(x) ((x) << S_DDP_OFFSET_ERR)
+#define F_DDP_OFFSET_ERR V_DDP_OFFSET_ERR(1U)
+
+#define S_DDP_COLOR_ERR 25
+#define V_DDP_COLOR_ERR(x) ((x) << S_DDP_COLOR_ERR)
+#define F_DDP_COLOR_ERR V_DDP_COLOR_ERR(1U)
+
+#define S_DDP_TID_MISMATCH 26
+#define V_DDP_TID_MISMATCH(x) ((x) << S_DDP_TID_MISMATCH)
+#define F_DDP_TID_MISMATCH V_DDP_TID_MISMATCH(1U)
+
+#define S_DDP_INVALID_PPOD 27
+#define V_DDP_INVALID_PPOD(x) ((x) << S_DDP_INVALID_PPOD)
+#define F_DDP_INVALID_PPOD V_DDP_INVALID_PPOD(1U)
+
+#define S_DDP_ULP_MODE 28
+#define M_DDP_ULP_MODE 0xF
+#define V_DDP_ULP_MODE(x) ((x) << S_DDP_ULP_MODE)
+#define G_DDP_ULP_MODE(x) (((x) >> S_DDP_ULP_MODE) & M_DDP_ULP_MODE)
+
+/* cpl_rx_data_ddp.ddp_report fields */
+#define S_DDP_OFFSET 0
+#define M_DDP_OFFSET 0x3FFFFF
+#define V_DDP_OFFSET(x) ((x) << S_DDP_OFFSET)
+#define G_DDP_OFFSET(x) (((x) >> S_DDP_OFFSET) & M_DDP_OFFSET)
+
+#define S_DDP_URG 24
+#define V_DDP_URG(x) ((x) << S_DDP_URG)
+#define F_DDP_URG V_DDP_URG(1U)
+
+#define S_DDP_PSH 25
+#define V_DDP_PSH(x) ((x) << S_DDP_PSH)
+#define F_DDP_PSH V_DDP_PSH(1U)
+
+#define S_DDP_BUF_COMPLETE 26
+#define V_DDP_BUF_COMPLETE(x) ((x) << S_DDP_BUF_COMPLETE)
+#define F_DDP_BUF_COMPLETE V_DDP_BUF_COMPLETE(1U)
+
+#define S_DDP_BUF_TIMED_OUT 27
+#define V_DDP_BUF_TIMED_OUT(x) ((x) << S_DDP_BUF_TIMED_OUT)
+#define F_DDP_BUF_TIMED_OUT V_DDP_BUF_TIMED_OUT(1U)
+
+#define S_DDP_BUF_IDX 28
+#define V_DDP_BUF_IDX(x) ((x) << S_DDP_BUF_IDX)
+#define F_DDP_BUF_IDX V_DDP_BUF_IDX(1U)
+
+struct cpl_tx_pkt {
+ WR_HDR;
+ __be32 cntrl;
+ __be32 len;
+};
+
+struct cpl_tx_pkt_lso {
+ WR_HDR;
+ __be32 cntrl;
+ __be32 len;
+
+ __be32 rsvd;
+ __be32 lso_info;
+};
+
+/* cpl_tx_pkt*.cntrl fields */
+#define S_TXPKT_VLAN 0
+#define M_TXPKT_VLAN 0xFFFF
+#define V_TXPKT_VLAN(x) ((x) << S_TXPKT_VLAN)
+#define G_TXPKT_VLAN(x) (((x) >> S_TXPKT_VLAN) & M_TXPKT_VLAN)
+
+#define S_TXPKT_INTF 16
+#define M_TXPKT_INTF 0xF
+#define V_TXPKT_INTF(x) ((x) << S_TXPKT_INTF)
+#define G_TXPKT_INTF(x) (((x) >> S_TXPKT_INTF) & M_TXPKT_INTF)
+
+#define S_TXPKT_IPCSUM_DIS 20
+#define V_TXPKT_IPCSUM_DIS(x) ((x) << S_TXPKT_IPCSUM_DIS)
+#define F_TXPKT_IPCSUM_DIS V_TXPKT_IPCSUM_DIS(1U)
+
+#define S_TXPKT_L4CSUM_DIS 21
+#define V_TXPKT_L4CSUM_DIS(x) ((x) << S_TXPKT_L4CSUM_DIS)
+#define F_TXPKT_L4CSUM_DIS V_TXPKT_L4CSUM_DIS(1U)
+
+#define S_TXPKT_VLAN_VLD 22
+#define V_TXPKT_VLAN_VLD(x) ((x) << S_TXPKT_VLAN_VLD)
+#define F_TXPKT_VLAN_VLD V_TXPKT_VLAN_VLD(1U)
+
+#define S_TXPKT_LOOPBACK 23
+#define V_TXPKT_LOOPBACK(x) ((x) << S_TXPKT_LOOPBACK)
+#define F_TXPKT_LOOPBACK V_TXPKT_LOOPBACK(1U)
+
+#define S_TXPKT_OPCODE 24
+#define M_TXPKT_OPCODE 0xFF
+#define V_TXPKT_OPCODE(x) ((x) << S_TXPKT_OPCODE)
+#define G_TXPKT_OPCODE(x) (((x) >> S_TXPKT_OPCODE) & M_TXPKT_OPCODE)
+
+/* cpl_tx_pkt_lso.lso_info fields */
+#define S_LSO_MSS 0
+#define M_LSO_MSS 0x3FFF
+#define V_LSO_MSS(x) ((x) << S_LSO_MSS)
+#define G_LSO_MSS(x) (((x) >> S_LSO_MSS) & M_LSO_MSS)
+
+#define S_LSO_ETH_TYPE 14
+#define M_LSO_ETH_TYPE 0x3
+#define V_LSO_ETH_TYPE(x) ((x) << S_LSO_ETH_TYPE)
+#define G_LSO_ETH_TYPE(x) (((x) >> S_LSO_ETH_TYPE) & M_LSO_ETH_TYPE)
+
+#define S_LSO_TCPHDR_WORDS 16
+#define M_LSO_TCPHDR_WORDS 0xF
+#define V_LSO_TCPHDR_WORDS(x) ((x) << S_LSO_TCPHDR_WORDS)
+#define G_LSO_TCPHDR_WORDS(x) (((x) >> S_LSO_TCPHDR_WORDS) & M_LSO_TCPHDR_WORDS)
+
+#define S_LSO_IPHDR_WORDS 20
+#define M_LSO_IPHDR_WORDS 0xF
+#define V_LSO_IPHDR_WORDS(x) ((x) << S_LSO_IPHDR_WORDS)
+#define G_LSO_IPHDR_WORDS(x) (((x) >> S_LSO_IPHDR_WORDS) & M_LSO_IPHDR_WORDS)
+
+#define S_LSO_IPV6 24
+#define V_LSO_IPV6(x) ((x) << S_LSO_IPV6)
+#define F_LSO_IPV6 V_LSO_IPV6(1U)
+
+struct cpl_trace_pkt {
+#ifdef CHELSIO_FW
+ __u8 rss_opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 err:1;
+ __u8:7;
+#else
+ __u8:7;
+ __u8 err:1;
+#endif
+ __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 qid:4;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 qid:4;
+#endif
+ __be32 tstamp;
+#endif /* CHELSIO_FW */
+
+ __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 iff:4;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 iff:4;
+#endif
+ __u8 rsvd[4];
+ __be16 len;
+};
+
+struct cpl_rx_pkt {
+ RSS_HDR __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 iff:4;
+ __u8 csum_valid:1;
+ __u8 ipmi_pkt:1;
+ __u8 vlan_valid:1;
+ __u8 fragment:1;
+#else
+ __u8 fragment:1;
+ __u8 vlan_valid:1;
+ __u8 ipmi_pkt:1;
+ __u8 csum_valid:1;
+ __u8 iff:4;
+#endif
+ __be16 csum;
+ __be16 vlan;
+ __be16 len;
+};
+
+struct cpl_l2t_write_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 params;
+ __u8 rsvd[2];
+ __u8 dst_mac[6];
+};
+
+/* cpl_l2t_write_req.params fields */
+#define S_L2T_W_IDX 0
+#define M_L2T_W_IDX 0x7FF
+#define V_L2T_W_IDX(x) ((x) << S_L2T_W_IDX)
+#define G_L2T_W_IDX(x) (((x) >> S_L2T_W_IDX) & M_L2T_W_IDX)
+
+#define S_L2T_W_VLAN 11
+#define M_L2T_W_VLAN 0xFFF
+#define V_L2T_W_VLAN(x) ((x) << S_L2T_W_VLAN)
+#define G_L2T_W_VLAN(x) (((x) >> S_L2T_W_VLAN) & M_L2T_W_VLAN)
+
+#define S_L2T_W_IFF 23
+#define M_L2T_W_IFF 0xF
+#define V_L2T_W_IFF(x) ((x) << S_L2T_W_IFF)
+#define G_L2T_W_IFF(x) (((x) >> S_L2T_W_IFF) & M_L2T_W_IFF)
+
+#define S_L2T_W_PRIO 27
+#define M_L2T_W_PRIO 0x7
+#define V_L2T_W_PRIO(x) ((x) << S_L2T_W_PRIO)
+#define G_L2T_W_PRIO(x) (((x) >> S_L2T_W_PRIO) & M_L2T_W_PRIO)
+
+struct cpl_l2t_write_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_l2t_read_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 rsvd;
+ __be16 l2t_idx;
+};
+
+struct cpl_l2t_read_rpl {
+ RSS_HDR union opcode_tid ot;
+ __be32 params;
+ __u8 rsvd[2];
+ __u8 dst_mac[6];
+};
+
+/* cpl_l2t_read_rpl.params fields */
+#define S_L2T_R_PRIO 0
+#define M_L2T_R_PRIO 0x7
+#define V_L2T_R_PRIO(x) ((x) << S_L2T_R_PRIO)
+#define G_L2T_R_PRIO(x) (((x) >> S_L2T_R_PRIO) & M_L2T_R_PRIO)
+
+#define S_L2T_R_VLAN 8
+#define M_L2T_R_VLAN 0xFFF
+#define V_L2T_R_VLAN(x) ((x) << S_L2T_R_VLAN)
+#define G_L2T_R_VLAN(x) (((x) >> S_L2T_R_VLAN) & M_L2T_R_VLAN)
+
+#define S_L2T_R_IFF 20
+#define M_L2T_R_IFF 0xF
+#define V_L2T_R_IFF(x) ((x) << S_L2T_R_IFF)
+#define G_L2T_R_IFF(x) (((x) >> S_L2T_R_IFF) & M_L2T_R_IFF)
+
+#define S_L2T_STATUS 24
+#define M_L2T_STATUS 0xFF
+#define V_L2T_STATUS(x) ((x) << S_L2T_STATUS)
+#define G_L2T_STATUS(x) (((x) >> S_L2T_STATUS) & M_L2T_STATUS)
+
+struct cpl_smt_write_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 mtu_idx:4;
+ __u8 iff:4;
+#else
+ __u8 iff:4;
+ __u8 mtu_idx:4;
+#endif
+ __be16 rsvd2;
+ __be16 rsvd3;
+ __u8 src_mac1[6];
+ __be16 rsvd4;
+ __u8 src_mac0[6];
+};
+
+struct cpl_smt_write_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_smt_read_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:4;
+ __u8 iff:4;
+#else
+ __u8 iff:4;
+ __u8:4;
+#endif
+ __be16 rsvd2;
+};
+
+struct cpl_smt_read_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 mtu_idx:4;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 mtu_idx:4;
+#endif
+ __be16 rsvd2;
+ __be16 rsvd3;
+ __u8 src_mac1[6];
+ __be16 rsvd4;
+ __u8 src_mac0[6];
+};
+
+struct cpl_rte_delete_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 params;
+};
+
+/* { cpl_rte_delete_req, cpl_rte_read_req }.params fields */
+#define S_RTE_REQ_LUT_IX 8
+#define M_RTE_REQ_LUT_IX 0x7FF
+#define V_RTE_REQ_LUT_IX(x) ((x) << S_RTE_REQ_LUT_IX)
+#define G_RTE_REQ_LUT_IX(x) (((x) >> S_RTE_REQ_LUT_IX) & M_RTE_REQ_LUT_IX)
+
+#define S_RTE_REQ_LUT_BASE 19
+#define M_RTE_REQ_LUT_BASE 0x7FF
+#define V_RTE_REQ_LUT_BASE(x) ((x) << S_RTE_REQ_LUT_BASE)
+#define G_RTE_REQ_LUT_BASE(x) (((x) >> S_RTE_REQ_LUT_BASE) & M_RTE_REQ_LUT_BASE)
+
+#define S_RTE_READ_REQ_SELECT 31
+#define V_RTE_READ_REQ_SELECT(x) ((x) << S_RTE_READ_REQ_SELECT)
+#define F_RTE_READ_REQ_SELECT V_RTE_READ_REQ_SELECT(1U)
+
+struct cpl_rte_delete_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_rte_write_req {
+ WR_HDR;
+ union opcode_tid ot;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:6;
+ __u8 write_tcam:1;
+ __u8 write_l2t_lut:1;
+#else
+ __u8 write_l2t_lut:1;
+ __u8 write_tcam:1;
+ __u8:6;
+#endif
+ __u8 rsvd[3];
+ __be32 lut_params;
+ __be16 rsvd2;
+ __be16 l2t_idx;
+ __be32 netmask;
+ __be32 faddr;
+};
+
+/* cpl_rte_write_req.lut_params fields */
+#define S_RTE_WRITE_REQ_LUT_IX 10
+#define M_RTE_WRITE_REQ_LUT_IX 0x7FF
+#define V_RTE_WRITE_REQ_LUT_IX(x) ((x) << S_RTE_WRITE_REQ_LUT_IX)
+#define G_RTE_WRITE_REQ_LUT_IX(x) (((x) >> S_RTE_WRITE_REQ_LUT_IX) & M_RTE_WRITE_REQ_LUT_IX)
+
+#define S_RTE_WRITE_REQ_LUT_BASE 21
+#define M_RTE_WRITE_REQ_LUT_BASE 0x7FF
+#define V_RTE_WRITE_REQ_LUT_BASE(x) ((x) << S_RTE_WRITE_REQ_LUT_BASE)
+#define G_RTE_WRITE_REQ_LUT_BASE(x) (((x) >> S_RTE_WRITE_REQ_LUT_BASE) & M_RTE_WRITE_REQ_LUT_BASE)
+
+struct cpl_rte_write_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_rte_read_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 params;
+};
+
+struct cpl_rte_read_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd0;
+ __be16 l2t_idx;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:7;
+ __u8 select:1;
+#else
+ __u8 select:1;
+ __u8:7;
+#endif
+ __u8 rsvd2[3];
+ __be32 addr;
+};
+
+struct cpl_tid_release {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd;
+};
+
+struct cpl_barrier {
+ WR_HDR;
+ __u8 opcode;
+ __u8 rsvd[7];
+};
+
+struct cpl_rdma_read_req {
+ __u8 opcode;
+ __u8 rsvd[15];
+};
+
+struct cpl_rdma_terminate {
+#ifdef CHELSIO_FW
+ __u8 opcode;
+ __u8 rsvd[2];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 rspq:3;
+ __u8:5;
+#else
+ __u8:5;
+ __u8 rspq:3;
+#endif
+ __be32 tid_len;
+#endif
+ __be32 msn;
+ __be32 mo;
+ __u8 data[0];
+};
+
+/* cpl_rdma_terminate.tid_len fields */
+#define S_FLIT_CNT 0
+#define M_FLIT_CNT 0xFF
+#define V_FLIT_CNT(x) ((x) << S_FLIT_CNT)
+#define G_FLIT_CNT(x) (((x) >> S_FLIT_CNT) & M_FLIT_CNT)
+
+#define S_TERM_TID 8
+#define M_TERM_TID 0xFFFFF
+#define V_TERM_TID(x) ((x) << S_TERM_TID)
+#define G_TERM_TID(x) (((x) >> S_TERM_TID) & M_TERM_TID)
+#endif /* T3_CPL_H */
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
new file mode 100644
index 00000000000..365a7f5b1f9
--- /dev/null
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -0,0 +1,3375 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+#include "sge_defs.h"
+#include "firmware_exports.h"
+
+/**
+ * t3_wait_op_done_val - wait until an operation is completed
+ * @adapter: the adapter performing the operation
+ * @reg: the register to check for completion
+ * @mask: a single-bit field within @reg that indicates completion
+ * @polarity: the value of the field when the operation is completed
+ * @attempts: number of check iterations
+ * @delay: delay in usecs between iterations
+ * @valp: where to store the value of the register at completion time
+ *
+ * Wait until an operation is completed by checking a bit in a register
+ * up to @attempts times. If @valp is not NULL the value of the register
+ * at the time it indicated completion is stored there. Returns 0 if the
+ * operation completes and -EAGAIN otherwise.
+ */
+
+int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
+ int polarity, int attempts, int delay, u32 *valp)
+{
+ while (1) {
+ u32 val = t3_read_reg(adapter, reg);
+
+ if (!!(val & mask) == polarity) {
+ if (valp)
+ *valp = val;
+ return 0;
+ }
+ if (--attempts == 0)
+ return -EAGAIN;
+ if (delay)
+ udelay(delay);
+ }
+}
+
+/**
+ * t3_write_regs - write a bunch of registers
+ * @adapter: the adapter to program
+ * @p: an array of register address/register value pairs
+ * @n: the number of address/value pairs
+ * @offset: register address offset
+ *
+ * Takes an array of register address/register value pairs and writes each
+ * value to the corresponding register. Register addresses are adjusted
+ * by the supplied offset.
+ */
+void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
+ int n, unsigned int offset)
+{
+ while (n--) {
+ t3_write_reg(adapter, p->reg_addr + offset, p->val);
+ p++;
+ }
+}
+
+/**
+ * t3_set_reg_field - set a register field to a value
+ * @adapter: the adapter to program
+ * @addr: the register address
+ * @mask: specifies the portion of the register to modify
+ * @val: the new value for the register field
+ *
+ * Sets a register field specified by the supplied mask to the
+ * given value.
+ */
+void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
+ u32 val)
+{
+ u32 v = t3_read_reg(adapter, addr) & ~mask;
+
+ t3_write_reg(adapter, addr, v | val);
+ t3_read_reg(adapter, addr); /* flush */
+}
+
+/**
+ * t3_read_indirect - read indirectly addressed registers
+ * @adap: the adapter
+ * @addr_reg: register holding the indirect address
+ * @data_reg: register holding the value of the indirect register
+ * @vals: where the read register values are stored
+ * @start_idx: index of first indirect register to read
+ * @nregs: how many indirect registers to read
+ *
+ * Reads registers that are accessed indirectly through an address/data
+ * register pair.
+ */
+void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
+ unsigned int data_reg, u32 *vals, unsigned int nregs,
+ unsigned int start_idx)
+{
+ while (nregs--) {
+ t3_write_reg(adap, addr_reg, start_idx);
+ *vals++ = t3_read_reg(adap, data_reg);
+ start_idx++;
+ }
+}
+
+/**
+ * t3_mc7_bd_read - read from MC7 through backdoor accesses
+ * @mc7: identifies MC7 to read from
+ * @start: index of first 64-bit word to read
+ * @n: number of 64-bit words to read
+ * @buf: where to store the read result
+ *
+ * Read n 64-bit words from MC7 starting at word start, using backdoor
+ * accesses.
+ */
+int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
+ u64 *buf)
+{
+ static const int shift[] = { 0, 0, 16, 24 };
+ static const int step[] = { 0, 32, 16, 8 };
+
+ unsigned int size64 = mc7->size / 8; /* # of 64-bit words */
+ struct adapter *adap = mc7->adapter;
+
+ if (start >= size64 || start + n > size64)
+ return -EINVAL;
+
+ start *= (8 << mc7->width);
+ while (n--) {
+ int i;
+ u64 val64 = 0;
+
+ for (i = (1 << mc7->width) - 1; i >= 0; --i) {
+ int attempts = 10;
+ u32 val;
+
+ t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, start);
+ t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0);
+ val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP);
+ while ((val & F_BUSY) && attempts--)
+ val = t3_read_reg(adap,
+ mc7->offset + A_MC7_BD_OP);
+ if (val & F_BUSY)
+ return -EIO;
+
+ val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1);
+ if (mc7->width == 0) {
+ val64 = t3_read_reg(adap,
+ mc7->offset +
+ A_MC7_BD_DATA0);
+ val64 |= (u64) val << 32;
+ } else {
+ if (mc7->width > 1)
+ val >>= shift[mc7->width];
+ val64 |= (u64) val << (step[mc7->width] * i);
+ }
+ start += 8;
+ }
+ *buf++ = val64;
+ }
+ return 0;
+}
+
+/*
+ * Initialize MI1.
+ */
+static void mi1_init(struct adapter *adap, const struct adapter_info *ai)
+{
+ u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1;
+ u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) |
+ V_CLKDIV(clkdiv);
+
+ if (!(ai->caps & SUPPORTED_10000baseT_Full))
+ val |= V_ST(1);
+ t3_write_reg(adap, A_MI1_CFG, val);
+}
+
+#define MDIO_ATTEMPTS 10
+
+/*
+ * MI1 read/write operations for direct-addressed PHYs.
+ */
+static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *valp)
+{
+ int ret;
+ u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
+
+ if (mmd_addr)
+ return -EINVAL;
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ if (!ret)
+ *valp = t3_read_reg(adapter, A_MI1_DATA);
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val)
+{
+ int ret;
+ u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
+
+ if (mmd_addr)
+ return -EINVAL;
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_DATA, val);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static const struct mdio_ops mi1_mdio_ops = {
+ mi1_read,
+ mi1_write
+};
+
+/*
+ * MI1 read/write operations for indirect-addressed PHYs.
+ */
+static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *valp)
+{
+ int ret;
+ u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_DATA, reg_addr);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ if (!ret) {
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
+ MDIO_ATTEMPTS, 20);
+ if (!ret)
+ *valp = t3_read_reg(adapter, A_MI1_DATA);
+ }
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val)
+{
+ int ret;
+ u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_DATA, reg_addr);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ if (!ret) {
+ t3_write_reg(adapter, A_MI1_DATA, val);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
+ MDIO_ATTEMPTS, 20);
+ }
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static const struct mdio_ops mi1_mdio_ext_ops = {
+ mi1_ext_read,
+ mi1_ext_write
+};
+
+/**
+ * t3_mdio_change_bits - modify the value of a PHY register
+ * @phy: the PHY to operate on
+ * @mmd: the device address
+ * @reg: the register address
+ * @clear: what part of the register value to mask off
+ * @set: what part of the register value to set
+ *
+ * Changes the value of a PHY register by applying a mask to its current
+ * value and ORing the result with a new value.
+ */
+int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
+ unsigned int set)
+{
+ int ret;
+ unsigned int val;
+
+ ret = mdio_read(phy, mmd, reg, &val);
+ if (!ret) {
+ val &= ~clear;
+ ret = mdio_write(phy, mmd, reg, val | set);
+ }
+ return ret;
+}
+
+/**
+ * t3_phy_reset - reset a PHY block
+ * @phy: the PHY to operate on
+ * @mmd: the device address of the PHY block to reset
+ * @wait: how long to wait for the reset to complete in 1ms increments
+ *
+ * Resets a PHY block and optionally waits for the reset to complete.
+ * @mmd should be 0 for 10/100/1000 PHYs and the device address to reset
+ * for 10G PHYs.
+ */
+int t3_phy_reset(struct cphy *phy, int mmd, int wait)
+{
+ int err;
+ unsigned int ctl;
+
+ err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET);
+ if (err || !wait)
+ return err;
+
+ do {
+ err = mdio_read(phy, mmd, MII_BMCR, &ctl);
+ if (err)
+ return err;
+ ctl &= BMCR_RESET;
+ if (ctl)
+ msleep(1);
+ } while (ctl && --wait);
+
+ return ctl ? -1 : 0;
+}
+
+/**
+ * t3_phy_advertise - set the PHY advertisement registers for autoneg
+ * @phy: the PHY to operate on
+ * @advert: bitmap of capabilities the PHY should advertise
+ *
+ * Sets a 10/100/1000 PHY's advertisement registers to advertise the
+ * requested capabilities.
+ */
+int t3_phy_advertise(struct cphy *phy, unsigned int advert)
+{
+ int err;
+ unsigned int val = 0;
+
+ err = mdio_read(phy, 0, MII_CTRL1000, &val);
+ if (err)
+ return err;
+
+ val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+ if (advert & ADVERTISED_1000baseT_Half)
+ val |= ADVERTISE_1000HALF;
+ if (advert & ADVERTISED_1000baseT_Full)
+ val |= ADVERTISE_1000FULL;
+
+ err = mdio_write(phy, 0, MII_CTRL1000, val);
+ if (err)
+ return err;
+
+ val = 1;
+ if (advert & ADVERTISED_10baseT_Half)
+ val |= ADVERTISE_10HALF;
+ if (advert & ADVERTISED_10baseT_Full)
+ val |= ADVERTISE_10FULL;
+ if (advert & ADVERTISED_100baseT_Half)
+ val |= ADVERTISE_100HALF;
+ if (advert & ADVERTISED_100baseT_Full)
+ val |= ADVERTISE_100FULL;
+ if (advert & ADVERTISED_Pause)
+ val |= ADVERTISE_PAUSE_CAP;
+ if (advert & ADVERTISED_Asym_Pause)
+ val |= ADVERTISE_PAUSE_ASYM;
+ return mdio_write(phy, 0, MII_ADVERTISE, val);
+}
+
+/**
+ * t3_set_phy_speed_duplex - force PHY speed and duplex
+ * @phy: the PHY to operate on
+ * @speed: requested PHY speed
+ * @duplex: requested PHY duplex
+ *
+ * Force a 10/100/1000 PHY's speed and duplex. This also disables
+ * auto-negotiation except for GigE, where auto-negotiation is mandatory.
+ */
+int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
+{
+ int err;
+ unsigned int ctl;
+
+ err = mdio_read(phy, 0, MII_BMCR, &ctl);
+ if (err)
+ return err;
+
+ if (speed >= 0) {
+ ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+ if (speed == SPEED_100)
+ ctl |= BMCR_SPEED100;
+ else if (speed == SPEED_1000)
+ ctl |= BMCR_SPEED1000;
+ }
+ if (duplex >= 0) {
+ ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
+ if (duplex == DUPLEX_FULL)
+ ctl |= BMCR_FULLDPLX;
+ }
+ if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */
+ ctl |= BMCR_ANENABLE;
+ return mdio_write(phy, 0, MII_BMCR, ctl);
+}
+
+static const struct adapter_info t3_adap_info[] = {
+ {2, 0, 0, 0,
+ F_GPIO2_OEN | F_GPIO4_OEN |
+ F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
+ SUPPORTED_OFFLOAD,
+ &mi1_mdio_ops, "Chelsio PE9000"},
+ {2, 0, 0, 0,
+ F_GPIO2_OEN | F_GPIO4_OEN |
+ F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
+ SUPPORTED_OFFLOAD,
+ &mi1_mdio_ops, "Chelsio T302"},
+ {1, 0, 0, 0,
+ F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
+ F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
+ SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
+ &mi1_mdio_ext_ops, "Chelsio T310"},
+ {2, 0, 0, 0,
+ F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
+ F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
+ F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
+ SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
+ &mi1_mdio_ext_ops, "Chelsio T320"},
+};
+
+/*
+ * Return the adapter_info structure with a given index. Out-of-range indices
+ * return NULL.
+ */
+const struct adapter_info *t3_get_adapter_info(unsigned int id)
+{
+ return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
+}
+
+#define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \
+ SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII)
+#define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI)
+
+static const struct port_type_info port_types[] = {
+ {NULL},
+ {t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
+ "10GBASE-XR"},
+ {t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
+ "10/100/1000BASE-T"},
+ {NULL, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
+ "10/100/1000BASE-T"},
+ {t3_xaui_direct_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+ {NULL, CAPS_10G, "10GBASE-KX4"},
+ {t3_qt2045_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+ {t3_ael1006_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
+ "10GBASE-SR"},
+ {NULL, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+};
+
+#undef CAPS_1G
+#undef CAPS_10G
+
+#define VPD_ENTRY(name, len) \
+ u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
+
+/*
+ * Partial EEPROM Vital Product Data structure. Includes only the ID and
+ * VPD-R sections.
+ */
+struct t3_vpd {
+ u8 id_tag;
+ u8 id_len[2];
+ u8 id_data[16];
+ u8 vpdr_tag;
+ u8 vpdr_len[2];
+ VPD_ENTRY(pn, 16); /* part number */
+ VPD_ENTRY(ec, 16); /* EC level */
+ VPD_ENTRY(sn, 16); /* serial number */
+ VPD_ENTRY(na, 12); /* MAC address base */
+ VPD_ENTRY(cclk, 6); /* core clock */
+ VPD_ENTRY(mclk, 6); /* mem clock */
+ VPD_ENTRY(uclk, 6); /* uP clk */
+ VPD_ENTRY(mdc, 6); /* MDIO clk */
+ VPD_ENTRY(mt, 2); /* mem timing */
+ VPD_ENTRY(xaui0cfg, 6); /* XAUI0 config */
+ VPD_ENTRY(xaui1cfg, 6); /* XAUI1 config */
+ VPD_ENTRY(port0, 2); /* PHY0 complex */
+ VPD_ENTRY(port1, 2); /* PHY1 complex */
+ VPD_ENTRY(port2, 2); /* PHY2 complex */
+ VPD_ENTRY(port3, 2); /* PHY3 complex */
+ VPD_ENTRY(rv, 1); /* csum */
+ u32 pad; /* for multiple-of-4 sizing and alignment */
+};
+
+#define EEPROM_MAX_POLL 4
+#define EEPROM_STAT_ADDR 0x4000
+#define VPD_BASE 0xc00
+
+/**
+ * t3_seeprom_read - read a VPD EEPROM location
+ * @adapter: adapter to read
+ * @addr: EEPROM address
+ * @data: where to store the read data
+ *
+ * Read a 32-bit word from a location in VPD EEPROM using the card's PCI
+ * VPD ROM capability. A zero is written to the flag bit when the
+ * addres is written to the control register. The hardware device will
+ * set the flag to 1 when 4 bytes have been read into the data register.
+ */
+int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data)
+{
+ u16 val;
+ int attempts = EEPROM_MAX_POLL;
+ unsigned int base = adapter->params.pci.vpd_cap_addr;
+
+ if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
+ return -EINVAL;
+
+ pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr);
+ do {
+ udelay(10);
+ pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
+ } while (!(val & PCI_VPD_ADDR_F) && --attempts);
+
+ if (!(val & PCI_VPD_ADDR_F)) {
+ CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
+ return -EIO;
+ }
+ pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, data);
+ *data = le32_to_cpu(*data);
+ return 0;
+}
+
+/**
+ * t3_seeprom_write - write a VPD EEPROM location
+ * @adapter: adapter to write
+ * @addr: EEPROM address
+ * @data: value to write
+ *
+ * Write a 32-bit word to a location in VPD EEPROM using the card's PCI
+ * VPD ROM capability.
+ */
+int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data)
+{
+ u16 val;
+ int attempts = EEPROM_MAX_POLL;
+ unsigned int base = adapter->params.pci.vpd_cap_addr;
+
+ if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
+ return -EINVAL;
+
+ pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA,
+ cpu_to_le32(data));
+ pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR,
+ addr | PCI_VPD_ADDR_F);
+ do {
+ msleep(1);
+ pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
+ } while ((val & PCI_VPD_ADDR_F) && --attempts);
+
+ if (val & PCI_VPD_ADDR_F) {
+ CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * t3_seeprom_wp - enable/disable EEPROM write protection
+ * @adapter: the adapter
+ * @enable: 1 to enable write protection, 0 to disable it
+ *
+ * Enables or disables write protection on the serial EEPROM.
+ */
+int t3_seeprom_wp(struct adapter *adapter, int enable)
+{
+ return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
+}
+
+/*
+ * Convert a character holding a hex digit to a number.
+ */
+static unsigned int hex2int(unsigned char c)
+{
+ return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
+}
+
+/**
+ * get_vpd_params - read VPD parameters from VPD EEPROM
+ * @adapter: adapter to read
+ * @p: where to store the parameters
+ *
+ * Reads card parameters stored in VPD EEPROM.
+ */
+static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
+{
+ int i, addr, ret;
+ struct t3_vpd vpd;
+
+ /*
+ * Card information is normally at VPD_BASE but some early cards had
+ * it at 0.
+ */
+ ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd);
+ if (ret)
+ return ret;
+ addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
+
+ for (i = 0; i < sizeof(vpd); i += 4) {
+ ret = t3_seeprom_read(adapter, addr + i,
+ (u32 *)((u8 *)&vpd + i));
+ if (ret)
+ return ret;
+ }
+
+ p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10);
+ p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10);
+ p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10);
+ p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10);
+ p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10);
+
+ /* Old eeproms didn't have port information */
+ if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
+ p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
+ p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
+ } else {
+ p->port_type[0] = hex2int(vpd.port0_data[0]);
+ p->port_type[1] = hex2int(vpd.port1_data[0]);
+ p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16);
+ p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16);
+ }
+
+ for (i = 0; i < 6; i++)
+ p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 +
+ hex2int(vpd.na_data[2 * i + 1]);
+ return 0;
+}
+
+/* serial flash and firmware constants */
+enum {
+ SF_ATTEMPTS = 5, /* max retries for SF1 operations */
+ SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */
+ SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */
+
+ /* flash command opcodes */
+ SF_PROG_PAGE = 2, /* program page */
+ SF_WR_DISABLE = 4, /* disable writes */
+ SF_RD_STATUS = 5, /* read status register */
+ SF_WR_ENABLE = 6, /* enable writes */
+ SF_RD_DATA_FAST = 0xb, /* read flash */
+ SF_ERASE_SECTOR = 0xd8, /* erase sector */
+
+ FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */
+ FW_VERS_ADDR = 0x77ffc /* flash address holding FW version */
+};
+
+/**
+ * sf1_read - read data from the serial flash
+ * @adapter: the adapter
+ * @byte_cnt: number of bytes to read
+ * @cont: whether another operation will be chained
+ * @valp: where to store the read data
+ *
+ * Reads up to 4 bytes of data from the serial flash. The location of
+ * the read needs to be specified prior to calling this by issuing the
+ * appropriate commands to the serial flash.
+ */
+static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
+ u32 *valp)
+{
+ int ret;
+
+ if (!byte_cnt || byte_cnt > 4)
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
+ return -EBUSY;
+ t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
+ ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
+ if (!ret)
+ *valp = t3_read_reg(adapter, A_SF_DATA);
+ return ret;
+}
+
+/**
+ * sf1_write - write data to the serial flash
+ * @adapter: the adapter
+ * @byte_cnt: number of bytes to write
+ * @cont: whether another operation will be chained
+ * @val: value to write
+ *
+ * Writes up to 4 bytes of data to the serial flash. The location of
+ * the write needs to be specified prior to calling this by issuing the
+ * appropriate commands to the serial flash.
+ */
+static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
+ u32 val)
+{
+ if (!byte_cnt || byte_cnt > 4)
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
+ return -EBUSY;
+ t3_write_reg(adapter, A_SF_DATA, val);
+ t3_write_reg(adapter, A_SF_OP,
+ V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
+ return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
+}
+
+/**
+ * flash_wait_op - wait for a flash operation to complete
+ * @adapter: the adapter
+ * @attempts: max number of polls of the status register
+ * @delay: delay between polls in ms
+ *
+ * Wait for a flash operation to complete by polling the status register.
+ */
+static int flash_wait_op(struct adapter *adapter, int attempts, int delay)
+{
+ int ret;
+ u32 status;
+
+ while (1) {
+ if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 ||
+ (ret = sf1_read(adapter, 1, 0, &status)) != 0)
+ return ret;
+ if (!(status & 1))
+ return 0;
+ if (--attempts == 0)
+ return -EAGAIN;
+ if (delay)
+ msleep(delay);
+ }
+}
+
+/**
+ * t3_read_flash - read words from serial flash
+ * @adapter: the adapter
+ * @addr: the start address for the read
+ * @nwords: how many 32-bit words to read
+ * @data: where to store the read data
+ * @byte_oriented: whether to store data as bytes or as words
+ *
+ * Read the specified number of 32-bit words from the serial flash.
+ * If @byte_oriented is set the read data is stored as a byte array
+ * (i.e., big-endian), otherwise as 32-bit words in the platform's
+ * natural endianess.
+ */
+int t3_read_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int nwords, u32 *data, int byte_oriented)
+{
+ int ret;
+
+ if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
+ return -EINVAL;
+
+ addr = swab32(addr) | SF_RD_DATA_FAST;
+
+ if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 ||
+ (ret = sf1_read(adapter, 1, 1, data)) != 0)
+ return ret;
+
+ for (; nwords; nwords--, data++) {
+ ret = sf1_read(adapter, 4, nwords > 1, data);
+ if (ret)
+ return ret;
+ if (byte_oriented)
+ *data = htonl(*data);
+ }
+ return 0;
+}
+
+/**
+ * t3_write_flash - write up to a page of data to the serial flash
+ * @adapter: the adapter
+ * @addr: the start address to write
+ * @n: length of data to write
+ * @data: the data to write
+ *
+ * Writes up to a page of data (256 bytes) to the serial flash starting
+ * at the given address.
+ */
+static int t3_write_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int n, const u8 *data)
+{
+ int ret;
+ u32 buf[64];
+ unsigned int i, c, left, val, offset = addr & 0xff;
+
+ if (addr + n > SF_SIZE || offset + n > 256)
+ return -EINVAL;
+
+ val = swab32(addr) | SF_PROG_PAGE;
+
+ if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
+ (ret = sf1_write(adapter, 4, 1, val)) != 0)
+ return ret;
+
+ for (left = n; left; left -= c) {
+ c = min(left, 4U);
+ for (val = 0, i = 0; i < c; ++i)
+ val = (val << 8) + *data++;
+
+ ret = sf1_write(adapter, c, c != left, val);
+ if (ret)
+ return ret;
+ }
+ if ((ret = flash_wait_op(adapter, 5, 1)) != 0)
+ return ret;
+
+ /* Read the page to verify the write succeeded */
+ ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
+ if (ret)
+ return ret;
+
+ if (memcmp(data - n, (u8 *) buf + offset, n))
+ return -EIO;
+ return 0;
+}
+
+enum fw_version_type {
+ FW_VERSION_N3,
+ FW_VERSION_T3
+};
+
+/**
+ * t3_get_fw_version - read the firmware version
+ * @adapter: the adapter
+ * @vers: where to place the version
+ *
+ * Reads the FW version from flash.
+ */
+int t3_get_fw_version(struct adapter *adapter, u32 *vers)
+{
+ return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0);
+}
+
+/**
+ * t3_check_fw_version - check if the FW is compatible with this driver
+ * @adapter: the adapter
+ *
+ * Checks if an adapter's FW is compatible with the driver. Returns 0
+ * if the versions are compatible, a negative error otherwise.
+ */
+int t3_check_fw_version(struct adapter *adapter)
+{
+ int ret;
+ u32 vers;
+ unsigned int type, major, minor;
+
+ ret = t3_get_fw_version(adapter, &vers);
+ if (ret)
+ return ret;
+
+ type = G_FW_VERSION_TYPE(vers);
+ major = G_FW_VERSION_MAJOR(vers);
+ minor = G_FW_VERSION_MINOR(vers);
+
+ if (type == FW_VERSION_T3 && major == 3 && minor == 1)
+ return 0;
+
+ CH_ERR(adapter, "found wrong FW version(%u.%u), "
+ "driver needs version 3.1\n", major, minor);
+ return -EINVAL;
+}
+
+/**
+ * t3_flash_erase_sectors - erase a range of flash sectors
+ * @adapter: the adapter
+ * @start: the first sector to erase
+ * @end: the last sector to erase
+ *
+ * Erases the sectors in the given range.
+ */
+static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end)
+{
+ while (start <= end) {
+ int ret;
+
+ if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
+ (ret = sf1_write(adapter, 4, 0,
+ SF_ERASE_SECTOR | (start << 8))) != 0 ||
+ (ret = flash_wait_op(adapter, 5, 500)) != 0)
+ return ret;
+ start++;
+ }
+ return 0;
+}
+
+/*
+ * t3_load_fw - download firmware
+ * @adapter: the adapter
+ * @fw_data: the firrware image to write
+ * @size: image size
+ *
+ * Write the supplied firmware image to the card's serial flash.
+ * The FW image has the following sections: @size - 8 bytes of code and
+ * data, followed by 4 bytes of FW version, followed by the 32-bit
+ * 1's complement checksum of the whole image.
+ */
+int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size)
+{
+ u32 csum;
+ unsigned int i;
+ const u32 *p = (const u32 *)fw_data;
+ int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16;
+
+ if (size & 3)
+ return -EINVAL;
+ if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR)
+ return -EFBIG;
+
+ for (csum = 0, i = 0; i < size / sizeof(csum); i++)
+ csum += ntohl(p[i]);
+ if (csum != 0xffffffff) {
+ CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
+ csum);
+ return -EINVAL;
+ }
+
+ ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector);
+ if (ret)
+ goto out;
+
+ size -= 8; /* trim off version and checksum */
+ for (addr = FW_FLASH_BOOT_ADDR; size;) {
+ unsigned int chunk_size = min(size, 256U);
+
+ ret = t3_write_flash(adapter, addr, chunk_size, fw_data);
+ if (ret)
+ goto out;
+
+ addr += chunk_size;
+ fw_data += chunk_size;
+ size -= chunk_size;
+ }
+
+ ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data);
+out:
+ if (ret)
+ CH_ERR(adapter, "firmware download failed, error %d\n", ret);
+ return ret;
+}
+
+#define CIM_CTL_BASE 0x2000
+
+/**
+ * t3_cim_ctl_blk_read - read a block from CIM control region
+ *
+ * @adap: the adapter
+ * @addr: the start address within the CIM control region
+ * @n: number of words to read
+ * @valp: where to store the result
+ *
+ * Reads a block of 4-byte words from the CIM control region.
+ */
+int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
+ unsigned int n, unsigned int *valp)
+{
+ int ret = 0;
+
+ if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
+ return -EBUSY;
+
+ for ( ; !ret && n--; addr += 4) {
+ t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr);
+ ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
+ 0, 5, 2);
+ if (!ret)
+ *valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA);
+ }
+ return ret;
+}
+
+
+/**
+ * t3_link_changed - handle interface link changes
+ * @adapter: the adapter
+ * @port_id: the port index that changed link state
+ *
+ * Called when a port's link settings change to propagate the new values
+ * to the associated PHY and MAC. After performing the common tasks it
+ * invokes an OS-specific handler.
+ */
+void t3_link_changed(struct adapter *adapter, int port_id)
+{
+ int link_ok, speed, duplex, fc;
+ struct port_info *pi = adap2pinfo(adapter, port_id);
+ struct cphy *phy = &pi->phy;
+ struct cmac *mac = &pi->mac;
+ struct link_config *lc = &pi->link_config;
+
+ phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
+
+ if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
+ uses_xaui(adapter)) {
+ if (link_ok)
+ t3b_pcs_reset(mac);
+ t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
+ link_ok ? F_TXACTENABLE | F_RXEN : 0);
+ }
+ lc->link_ok = link_ok;
+ lc->speed = speed < 0 ? SPEED_INVALID : speed;
+ lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
+ if (lc->requested_fc & PAUSE_AUTONEG)
+ fc &= lc->requested_fc;
+ else
+ fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+ if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
+ /* Set MAC speed, duplex, and flow control to match PHY. */
+ t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
+ lc->fc = fc;
+ }
+
+ t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
+}
+
+/**
+ * t3_link_start - apply link configuration to MAC/PHY
+ * @phy: the PHY to setup
+ * @mac: the MAC to setup
+ * @lc: the requested link configuration
+ *
+ * Set up a port's MAC and PHY according to a desired link configuration.
+ * - If the PHY can auto-negotiate first decide what to advertise, then
+ * enable/disable auto-negotiation as desired, and reset.
+ * - If the PHY does not auto-negotiate just reset it.
+ * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
+ * otherwise do it later based on the outcome of auto-negotiation.
+ */
+int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
+{
+ unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+ lc->link_ok = 0;
+ if (lc->supported & SUPPORTED_Autoneg) {
+ lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause);
+ if (fc) {
+ lc->advertising |= ADVERTISED_Asym_Pause;
+ if (fc & PAUSE_RX)
+ lc->advertising |= ADVERTISED_Pause;
+ }
+ phy->ops->advertise(phy, lc->advertising);
+
+ if (lc->autoneg == AUTONEG_DISABLE) {
+ lc->speed = lc->requested_speed;
+ lc->duplex = lc->requested_duplex;
+ lc->fc = (unsigned char)fc;
+ t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex,
+ fc);
+ /* Also disables autoneg */
+ phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
+ phy->ops->reset(phy, 0);
+ } else
+ phy->ops->autoneg_enable(phy);
+ } else {
+ t3_mac_set_speed_duplex_fc(mac, -1, -1, fc);
+ lc->fc = (unsigned char)fc;
+ phy->ops->reset(phy, 0);
+ }
+ return 0;
+}
+
+/**
+ * t3_set_vlan_accel - control HW VLAN extraction
+ * @adapter: the adapter
+ * @ports: bitmap of adapter ports to operate on
+ * @on: enable (1) or disable (0) HW VLAN extraction
+ *
+ * Enables or disables HW extraction of VLAN tags for the given port.
+ */
+void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on)
+{
+ t3_set_reg_field(adapter, A_TP_OUT_CONFIG,
+ ports << S_VLANEXTRACTIONENABLE,
+ on ? (ports << S_VLANEXTRACTIONENABLE) : 0);
+}
+
+struct intr_info {
+ unsigned int mask; /* bits to check in interrupt status */
+ const char *msg; /* message to print or NULL */
+ short stat_idx; /* stat counter to increment or -1 */
+ unsigned short fatal:1; /* whether the condition reported is fatal */
+};
+
+/**
+ * t3_handle_intr_status - table driven interrupt handler
+ * @adapter: the adapter that generated the interrupt
+ * @reg: the interrupt status register to process
+ * @mask: a mask to apply to the interrupt status
+ * @acts: table of interrupt actions
+ * @stats: statistics counters tracking interrupt occurences
+ *
+ * A table driven interrupt handler that applies a set of masks to an
+ * interrupt status word and performs the corresponding actions if the
+ * interrupts described by the mask have occured. The actions include
+ * optionally printing a warning or alert message, and optionally
+ * incrementing a stat counter. The table is terminated by an entry
+ * specifying mask 0. Returns the number of fatal interrupt conditions.
+ */
+static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
+ unsigned int mask,
+ const struct intr_info *acts,
+ unsigned long *stats)
+{
+ int fatal = 0;
+ unsigned int status = t3_read_reg(adapter, reg) & mask;
+
+ for (; acts->mask; ++acts) {
+ if (!(status & acts->mask))
+ continue;
+ if (acts->fatal) {
+ fatal++;
+ CH_ALERT(adapter, "%s (0x%x)\n",
+ acts->msg, status & acts->mask);
+ } else if (acts->msg)
+ CH_WARN(adapter, "%s (0x%x)\n",
+ acts->msg, status & acts->mask);
+ if (acts->stat_idx >= 0)
+ stats[acts->stat_idx]++;
+ }
+ if (status) /* clear processed interrupts */
+ t3_write_reg(adapter, reg, status);
+ return fatal;
+}
+
+#define SGE_INTR_MASK (F_RSPQDISABLED)
+#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
+ F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
+ F_NFASRCHFAIL)
+#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
+#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
+ V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
+ F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW)
+#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
+ F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
+ F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
+ F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
+ V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \
+ V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */)
+#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
+ F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
+ /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
+ V_BISTERR(M_BISTERR) | F_PEXERR)
+#define ULPRX_INTR_MASK F_PARERR
+#define ULPTX_INTR_MASK 0
+#define CPLSW_INTR_MASK (F_TP_FRAMING_ERROR | \
+ F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
+ F_ZERO_SWITCH_ERROR)
+#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
+ F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
+ F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
+ F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT)
+#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
+ V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
+ V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
+#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
+ V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \
+ V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR))
+#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
+ V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
+ V_RXTPPARERRENB(M_RXTPPARERRENB) | \
+ V_MCAPARERRENB(M_MCAPARERRENB))
+#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
+ F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
+ F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
+ F_MPS0 | F_CPL_SWITCH)
+
+/*
+ * Interrupt handler for the PCIX1 module.
+ */
+static void pci_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pcix1_intr_info[] = {
+ {F_MSTDETPARERR, "PCI master detected parity error", -1, 1},
+ {F_SIGTARABT, "PCI signaled target abort", -1, 1},
+ {F_RCVTARABT, "PCI received target abort", -1, 1},
+ {F_RCVMSTABT, "PCI received master abort", -1, 1},
+ {F_SIGSYSERR, "PCI signaled system error", -1, 1},
+ {F_DETPARERR, "PCI detected parity error", -1, 1},
+ {F_SPLCMPDIS, "PCI split completion discarded", -1, 1},
+ {F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1},
+ {F_RCVSPLCMPERR, "PCI received split completion error", -1,
+ 1},
+ {F_DETCORECCERR, "PCI correctable ECC error",
+ STAT_PCI_CORR_ECC, 0},
+ {F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1},
+ {F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
+ {V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1,
+ 1},
+ {V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1,
+ 1},
+ {V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1,
+ 1},
+ {V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity "
+ "error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK,
+ pcix1_intr_info, adapter->irq_stats))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * Interrupt handler for the PCIE module.
+ */
+static void pcie_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pcie_intr_info[] = {
+ {F_PEXERR, "PCI PEX error", -1, 1},
+ {F_UNXSPLCPLERRR,
+ "PCI unexpected split completion DMA read error", -1, 1},
+ {F_UNXSPLCPLERRC,
+ "PCI unexpected split completion DMA command error", -1, 1},
+ {F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
+ {F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1},
+ {F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1},
+ {F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1},
+ {V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
+ "PCI MSI-X table/PBA parity error", -1, 1},
+ {V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
+ pcie_intr_info, adapter->irq_stats))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * TP interrupt handler.
+ */
+static void tp_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info tp_intr_info[] = {
+ {0xffffff, "TP parity error", -1, 1},
+ {0x1000000, "TP out of Rx pages", -1, 1},
+ {0x2000000, "TP out of Tx pages", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
+ tp_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * CIM interrupt handler.
+ */
+static void cim_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info cim_intr_info[] = {
+ {F_RSVDSPACEINT, "CIM reserved space write", -1, 1},
+ {F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1},
+ {F_FLASHRANGEINT, "CIM flash address out of range", -1, 1},
+ {F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1},
+ {F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1},
+ {F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1},
+ {F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1},
+ {F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1},
+ {F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1},
+ {F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1},
+ {F_BLKRDPLINT, "CIM block read from PL space", -1, 1},
+ {F_BLKWRPLINT, "CIM block write to PL space", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff,
+ cim_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * ULP RX interrupt handler.
+ */
+static void ulprx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info ulprx_intr_info[] = {
+ {F_PARERR, "ULP RX parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff,
+ ulprx_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * ULP TX interrupt handler.
+ */
+static void ulptx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info ulptx_intr_info[] = {
+ {F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds",
+ STAT_ULP_CH0_PBL_OOB, 0},
+ {F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
+ STAT_ULP_CH1_PBL_OOB, 0},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff,
+ ulptx_intr_info, adapter->irq_stats))
+ t3_fatal_err(adapter);
+}
+
+#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
+ F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
+ F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
+ F_ICSPI1_TX_FRAMING_ERROR)
+#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
+ F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
+ F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
+ F_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
+
+/*
+ * PM TX interrupt handler.
+ */
+static void pmtx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pmtx_intr_info[] = {
+ {F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1},
+ {ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1},
+ {OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1},
+ {V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR),
+ "PMTX ispi parity error", -1, 1},
+ {V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR),
+ "PMTX ospi parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff,
+ pmtx_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
+ F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
+ F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
+ F_IESPI1_TX_FRAMING_ERROR)
+#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
+ F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
+ F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
+ F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
+
+/*
+ * PM RX interrupt handler.
+ */
+static void pmrx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pmrx_intr_info[] = {
+ {F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1},
+ {IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1},
+ {OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1},
+ {V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR),
+ "PMRX ispi parity error", -1, 1},
+ {V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR),
+ "PMRX ospi parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff,
+ pmrx_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * CPL switch interrupt handler.
+ */
+static void cplsw_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info cplsw_intr_info[] = {
+/* { F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, */
+ {F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1},
+ {F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1},
+ {F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1},
+ {F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff,
+ cplsw_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * MPS interrupt handler.
+ */
+static void mps_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info mps_intr_info[] = {
+ {0x1ff, "MPS parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff,
+ mps_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
+
+/*
+ * MC7 interrupt handler.
+ */
+static void mc7_intr_handler(struct mc7 *mc7)
+{
+ struct adapter *adapter = mc7->adapter;
+ u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE);
+
+ if (cause & F_CE) {
+ mc7->stats.corr_err++;
+ CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, "
+ "data 0x%x 0x%x 0x%x\n", mc7->name,
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR),
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0),
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1),
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2));
+ }
+
+ if (cause & F_UE) {
+ mc7->stats.uncorr_err++;
+ CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, "
+ "data 0x%x 0x%x 0x%x\n", mc7->name,
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR),
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0),
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1),
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2));
+ }
+
+ if (G_PE(cause)) {
+ mc7->stats.parity_err++;
+ CH_ALERT(adapter, "%s MC7 parity error 0x%x\n",
+ mc7->name, G_PE(cause));
+ }
+
+ if (cause & F_AE) {
+ u32 addr = 0;
+
+ if (adapter->params.rev > 0)
+ addr = t3_read_reg(adapter,
+ mc7->offset + A_MC7_ERR_ADDR);
+ mc7->stats.addr_err++;
+ CH_ALERT(adapter, "%s MC7 address error: 0x%x\n",
+ mc7->name, addr);
+ }
+
+ if (cause & MC7_INTR_FATAL)
+ t3_fatal_err(adapter);
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause);
+}
+
+#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
+ V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR))
+/*
+ * XGMAC interrupt handler.
+ */
+static int mac_intr_handler(struct adapter *adap, unsigned int idx)
+{
+ struct cmac *mac = &adap2pinfo(adap, idx)->mac;
+ u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset);
+
+ if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
+ mac->stats.tx_fifo_parity_err++;
+ CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx);
+ }
+ if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) {
+ mac->stats.rx_fifo_parity_err++;
+ CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx);
+ }
+ if (cause & F_TXFIFO_UNDERRUN)
+ mac->stats.tx_fifo_urun++;
+ if (cause & F_RXFIFO_OVERFLOW)
+ mac->stats.rx_fifo_ovfl++;
+ if (cause & V_SERDES_LOS(M_SERDES_LOS))
+ mac->stats.serdes_signal_loss++;
+ if (cause & F_XAUIPCSCTCERR)
+ mac->stats.xaui_pcs_ctc_err++;
+ if (cause & F_XAUIPCSALIGNCHANGE)
+ mac->stats.xaui_pcs_align_change++;
+
+ t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
+ if (cause & XGM_INTR_FATAL)
+ t3_fatal_err(adap);
+ return cause != 0;
+}
+
+/*
+ * Interrupt handler for PHY events.
+ */
+int t3_phy_intr_handler(struct adapter *adapter)
+{
+ static const int intr_gpio_bits[] = { 8, 0x20 };
+
+ u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
+
+ for_each_port(adapter, i) {
+ if (cause & intr_gpio_bits[i]) {
+ struct cphy *phy = &adap2pinfo(adapter, i)->phy;
+ int phy_cause = phy->ops->intr_handler(phy);
+
+ if (phy_cause & cphy_cause_link_change)
+ t3_link_changed(adapter, i);
+ if (phy_cause & cphy_cause_fifo_error)
+ phy->fifo_errors++;
+ }
+ }
+
+ t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause);
+ return 0;
+}
+
+/*
+ * T3 slow path (non-data) interrupt handler.
+ */
+int t3_slow_intr_handler(struct adapter *adapter)
+{
+ u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0);
+
+ cause &= adapter->slow_intr_mask;
+ if (!cause)
+ return 0;
+ if (cause & F_PCIM0) {
+ if (is_pcie(adapter))
+ pcie_intr_handler(adapter);
+ else
+ pci_intr_handler(adapter);
+ }
+ if (cause & F_SGE3)
+ t3_sge_err_intr_handler(adapter);
+ if (cause & F_MC7_PMRX)
+ mc7_intr_handler(&adapter->pmrx);
+ if (cause & F_MC7_PMTX)
+ mc7_intr_handler(&adapter->pmtx);
+ if (cause & F_MC7_CM)
+ mc7_intr_handler(&adapter->cm);
+ if (cause & F_CIM)
+ cim_intr_handler(adapter);
+ if (cause & F_TP1)
+ tp_intr_handler(adapter);
+ if (cause & F_ULP2_RX)
+ ulprx_intr_handler(adapter);
+ if (cause & F_ULP2_TX)
+ ulptx_intr_handler(adapter);
+ if (cause & F_PM1_RX)
+ pmrx_intr_handler(adapter);
+ if (cause & F_PM1_TX)
+ pmtx_intr_handler(adapter);
+ if (cause & F_CPL_SWITCH)
+ cplsw_intr_handler(adapter);
+ if (cause & F_MPS0)
+ mps_intr_handler(adapter);
+ if (cause & F_MC5A)
+ t3_mc5_intr_handler(&adapter->mc5);
+ if (cause & F_XGMAC0_0)
+ mac_intr_handler(adapter, 0);
+ if (cause & F_XGMAC0_1)
+ mac_intr_handler(adapter, 1);
+ if (cause & F_T3DBG)
+ t3_os_ext_intr_handler(adapter);
+
+ /* Clear the interrupts just processed. */
+ t3_write_reg(adapter, A_PL_INT_CAUSE0, cause);
+ t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
+ return 1;
+}
+
+/**
+ * t3_intr_enable - enable interrupts
+ * @adapter: the adapter whose interrupts should be enabled
+ *
+ * Enable interrupts by setting the interrupt enable registers of the
+ * various HW modules and then enabling the top-level interrupt
+ * concentrator.
+ */
+void t3_intr_enable(struct adapter *adapter)
+{
+ static const struct addr_val_pair intr_en_avp[] = {
+ {A_SG_INT_ENABLE, SGE_INTR_MASK},
+ {A_MC7_INT_ENABLE, MC7_INTR_MASK},
+ {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
+ MC7_INTR_MASK},
+ {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
+ MC7_INTR_MASK},
+ {A_MC5_DB_INT_ENABLE, MC5_INTR_MASK},
+ {A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK},
+ {A_TP_INT_ENABLE, 0x3bfffff},
+ {A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK},
+ {A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK},
+ {A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK},
+ {A_MPS_INT_ENABLE, MPS_INTR_MASK},
+ };
+
+ adapter->slow_intr_mask = PL_INTR_MASK;
+
+ t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
+
+ if (adapter->params.rev > 0) {
+ t3_write_reg(adapter, A_CPL_INTR_ENABLE,
+ CPLSW_INTR_MASK | F_CIM_OVFL_ERROR);
+ t3_write_reg(adapter, A_ULPTX_INT_ENABLE,
+ ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
+ F_PBL_BOUND_ERR_CH1);
+ } else {
+ t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK);
+ t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
+ }
+
+ t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW,
+ adapter_info(adapter)->gpio_intr);
+ t3_write_reg(adapter, A_T3DBG_INT_ENABLE,
+ adapter_info(adapter)->gpio_intr);
+ if (is_pcie(adapter))
+ t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
+ else
+ t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK);
+ t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask);
+ t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */
+}
+
+/**
+ * t3_intr_disable - disable a card's interrupts
+ * @adapter: the adapter whose interrupts should be disabled
+ *
+ * Disable interrupts. We only disable the top-level interrupt
+ * concentrator and the SGE data interrupts.
+ */
+void t3_intr_disable(struct adapter *adapter)
+{
+ t3_write_reg(adapter, A_PL_INT_ENABLE0, 0);
+ t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */
+ adapter->slow_intr_mask = 0;
+}
+
+/**
+ * t3_intr_clear - clear all interrupts
+ * @adapter: the adapter whose interrupts should be cleared
+ *
+ * Clears all interrupts.
+ */
+void t3_intr_clear(struct adapter *adapter)
+{
+ static const unsigned int cause_reg_addr[] = {
+ A_SG_INT_CAUSE,
+ A_SG_RSPQ_FL_STATUS,
+ A_PCIX_INT_CAUSE,
+ A_MC7_INT_CAUSE,
+ A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
+ A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
+ A_CIM_HOST_INT_CAUSE,
+ A_TP_INT_CAUSE,
+ A_MC5_DB_INT_CAUSE,
+ A_ULPRX_INT_CAUSE,
+ A_ULPTX_INT_CAUSE,
+ A_CPL_INTR_CAUSE,
+ A_PM1_TX_INT_CAUSE,
+ A_PM1_RX_INT_CAUSE,
+ A_MPS_INT_CAUSE,
+ A_T3DBG_INT_CAUSE,
+ };
+ unsigned int i;
+
+ /* Clear PHY and MAC interrupts for each port. */
+ for_each_port(adapter, i)
+ t3_port_intr_clear(adapter, i);
+
+ for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
+ t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
+
+ t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
+ t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
+}
+
+/**
+ * t3_port_intr_enable - enable port-specific interrupts
+ * @adapter: associated adapter
+ * @idx: index of port whose interrupts should be enabled
+ *
+ * Enable port-specific (i.e., MAC and PHY) interrupts for the given
+ * adapter port.
+ */
+void t3_port_intr_enable(struct adapter *adapter, int idx)
+{
+ struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+ t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK);
+ t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
+ phy->ops->intr_enable(phy);
+}
+
+/**
+ * t3_port_intr_disable - disable port-specific interrupts
+ * @adapter: associated adapter
+ * @idx: index of port whose interrupts should be disabled
+ *
+ * Disable port-specific (i.e., MAC and PHY) interrupts for the given
+ * adapter port.
+ */
+void t3_port_intr_disable(struct adapter *adapter, int idx)
+{
+ struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+ t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0);
+ t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
+ phy->ops->intr_disable(phy);
+}
+
+/**
+ * t3_port_intr_clear - clear port-specific interrupts
+ * @adapter: associated adapter
+ * @idx: index of port whose interrupts to clear
+ *
+ * Clear port-specific (i.e., MAC and PHY) interrupts for the given
+ * adapter port.
+ */
+void t3_port_intr_clear(struct adapter *adapter, int idx)
+{
+ struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+ t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff);
+ t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */
+ phy->ops->intr_clear(phy);
+}
+
+/**
+ * t3_sge_write_context - write an SGE context
+ * @adapter: the adapter
+ * @id: the context id
+ * @type: the context type
+ *
+ * Program an SGE context with the values already loaded in the
+ * CONTEXT_DATA? registers.
+ */
+static int t3_sge_write_context(struct adapter *adapter, unsigned int id,
+ unsigned int type)
+{
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_init_ecntxt - initialize an SGE egress context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @gts_enable: whether to enable GTS for the context
+ * @type: the egress context type
+ * @respq: associated response queue
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @token: uP token
+ * @gen: initial generation value for the context
+ * @cidx: consumer pointer
+ *
+ * Initialize an SGE egress context and make it ready for use. If the
+ * platform allows concurrent context operations, the caller is
+ * responsible for appropriate locking.
+ */
+int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
+ enum sge_context_type type, int respq, u64 base_addr,
+ unsigned int size, unsigned int token, int gen,
+ unsigned int cidx)
+{
+ unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM;
+
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) |
+ V_EC_CREDITS(credits) | V_EC_GTS(gts_enable));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) |
+ V_EC_BASE_LO(base_addr & 0xffff));
+ base_addr >>= 16;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr);
+ base_addr >>= 32;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
+ V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) |
+ V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) |
+ F_EC_VALID);
+ return t3_sge_write_context(adapter, id, F_EGRESS);
+}
+
+/**
+ * t3_sge_init_flcntxt - initialize an SGE free-buffer list context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @gts_enable: whether to enable GTS for the context
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @bsize: size of each buffer for this queue
+ * @cong_thres: threshold to signal congestion to upstream producers
+ * @gen: initial generation value for the context
+ * @cidx: consumer pointer
+ *
+ * Initialize an SGE free list context and make it ready for use. The
+ * caller is responsible for ensuring only one context operation occurs
+ * at a time.
+ */
+int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
+ int gts_enable, u64 base_addr, unsigned int size,
+ unsigned int bsize, unsigned int cong_thres, int gen,
+ unsigned int cidx)
+{
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr);
+ base_addr >>= 32;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1,
+ V_FL_BASE_HI((u32) base_addr) |
+ V_FL_INDEX_LO(cidx & M_FL_INDEX_LO));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) |
+ V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) |
+ V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
+ V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) |
+ V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable));
+ return t3_sge_write_context(adapter, id, F_FREELIST);
+}
+
+/**
+ * t3_sge_init_rspcntxt - initialize an SGE response queue context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @fl_thres: threshold for selecting the normal or jumbo free list
+ * @gen: initial generation value for the context
+ * @cidx: consumer pointer
+ *
+ * Initialize an SGE response queue context and make it ready for use.
+ * The caller is responsible for ensuring only one context operation
+ * occurs at a time.
+ */
+int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
+ int irq_vec_idx, u64 base_addr, unsigned int size,
+ unsigned int fl_thres, int gen, unsigned int cidx)
+{
+ unsigned int intr = 0;
+
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) |
+ V_CQ_INDEX(cidx));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
+ base_addr >>= 32;
+ if (irq_vec_idx >= 0)
+ intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
+ V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres);
+ return t3_sge_write_context(adapter, id, F_RESPONSEQ);
+}
+
+/**
+ * t3_sge_init_cqcntxt - initialize an SGE completion queue context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @rspq: response queue for async notifications
+ * @ovfl_mode: CQ overflow mode
+ * @credits: completion queue credits
+ * @credit_thres: the credit threshold
+ *
+ * Initialize an SGE completion queue context and make it ready for use.
+ * The caller is responsible for ensuring only one context operation
+ * occurs at a time.
+ */
+int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
+ unsigned int size, int rspq, int ovfl_mode,
+ unsigned int credits, unsigned int credit_thres)
+{
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
+ base_addr >>= 32;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
+ V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) |
+ V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
+ V_CQ_CREDIT_THRES(credit_thres));
+ return t3_sge_write_context(adapter, id, F_CQ);
+}
+
+/**
+ * t3_sge_enable_ecntxt - enable/disable an SGE egress context
+ * @adapter: the adapter
+ * @id: the egress context id
+ * @enable: enable (1) or disable (0) the context
+ *
+ * Enable or disable an SGE egress context. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable));
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_disable_fl - disable an SGE free-buffer list
+ * @adapter: the adapter
+ * @id: the free list context id
+ *
+ * Disable an SGE free-buffer list. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_fl(struct adapter *adapter, unsigned int id)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE));
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_disable_rspcntxt - disable an SGE response queue
+ * @adapter: the adapter
+ * @id: the response queue context id
+ *
+ * Disable an SGE response queue. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_disable_cqcntxt - disable an SGE completion queue
+ * @adapter: the adapter
+ * @id: the completion queue context id
+ *
+ * Disable an SGE completion queue. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_cqcntxt_op - perform an operation on a completion queue context
+ * @adapter: the adapter
+ * @id: the context id
+ * @op: the operation to perform
+ *
+ * Perform the selected operation on an SGE completion queue context.
+ * The caller is responsible for ensuring only one context operation
+ * occurs at a time.
+ */
+int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
+ unsigned int credits)
+{
+ u32 val;
+
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
+ V_CONTEXT(id) | F_CQ);
+ if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1, &val))
+ return -EIO;
+
+ if (op >= 2 && op < 7) {
+ if (adapter->params.rev > 0)
+ return G_CQ_INDEX(val);
+
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
+ if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
+ F_CONTEXT_CMD_BUSY, 0, 5, 1))
+ return -EIO;
+ return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
+ }
+ return 0;
+}
+
+/**
+ * t3_sge_read_context - read an SGE context
+ * @type: the context type
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE egress context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+static int t3_sge_read_context(unsigned int type, struct adapter *adapter,
+ unsigned int id, u32 data[4])
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
+ if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
+ 5, 1))
+ return -EIO;
+ data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
+ data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
+ data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2);
+ data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3);
+ return 0;
+}
+
+/**
+ * t3_sge_read_ecntxt - read an SGE egress context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE egress context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= 65536)
+ return -EINVAL;
+ return t3_sge_read_context(F_EGRESS, adapter, id, data);
+}
+
+/**
+ * t3_sge_read_cq - read an SGE CQ context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE CQ context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= 65536)
+ return -EINVAL;
+ return t3_sge_read_context(F_CQ, adapter, id, data);
+}
+
+/**
+ * t3_sge_read_fl - read an SGE free-list context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE free-list context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= SGE_QSETS * 2)
+ return -EINVAL;
+ return t3_sge_read_context(F_FREELIST, adapter, id, data);
+}
+
+/**
+ * t3_sge_read_rspq - read an SGE response queue context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE response queue context. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= SGE_QSETS)
+ return -EINVAL;
+ return t3_sge_read_context(F_RESPONSEQ, adapter, id, data);
+}
+
+/**
+ * t3_config_rss - configure Rx packet steering
+ * @adapter: the adapter
+ * @rss_config: RSS settings (written to TP_RSS_CONFIG)
+ * @cpus: values for the CPU lookup table (0xff terminated)
+ * @rspq: values for the response queue lookup table (0xffff terminated)
+ *
+ * Programs the receive packet steering logic. @cpus and @rspq provide
+ * the values for the CPU and response queue lookup tables. If they
+ * provide fewer values than the size of the tables the supplied values
+ * are used repeatedly until the tables are fully populated.
+ */
+void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
+ const u8 * cpus, const u16 *rspq)
+{
+ int i, j, cpu_idx = 0, q_idx = 0;
+
+ if (cpus)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ u32 val = i << 16;
+
+ for (j = 0; j < 2; ++j) {
+ val |= (cpus[cpu_idx++] & 0x3f) << (8 * j);
+ if (cpus[cpu_idx] == 0xff)
+ cpu_idx = 0;
+ }
+ t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val);
+ }
+
+ if (rspq)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
+ (i << 16) | rspq[q_idx++]);
+ if (rspq[q_idx] == 0xffff)
+ q_idx = 0;
+ }
+
+ t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config);
+}
+
+/**
+ * t3_read_rss - read the contents of the RSS tables
+ * @adapter: the adapter
+ * @lkup: holds the contents of the RSS lookup table
+ * @map: holds the contents of the RSS map table
+ *
+ * Reads the contents of the receive packet steering tables.
+ */
+int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map)
+{
+ int i;
+ u32 val;
+
+ if (lkup)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ t3_write_reg(adapter, A_TP_RSS_LKP_TABLE,
+ 0xffff0000 | i);
+ val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE);
+ if (!(val & 0x80000000))
+ return -EAGAIN;
+ *lkup++ = val;
+ *lkup++ = (val >> 8);
+ }
+
+ if (map)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
+ 0xffff0000 | i);
+ val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE);
+ if (!(val & 0x80000000))
+ return -EAGAIN;
+ *map++ = val;
+ }
+ return 0;
+}
+
+/**
+ * t3_tp_set_offload_mode - put TP in NIC/offload mode
+ * @adap: the adapter
+ * @enable: 1 to select offload mode, 0 for regular NIC
+ *
+ * Switches TP to NIC/offload mode.
+ */
+void t3_tp_set_offload_mode(struct adapter *adap, int enable)
+{
+ if (is_offload(adap) || !enable)
+ t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE,
+ V_NICMODE(!enable));
+}
+
+/**
+ * pm_num_pages - calculate the number of pages of the payload memory
+ * @mem_size: the size of the payload memory
+ * @pg_size: the size of each payload memory page
+ *
+ * Calculate the number of pages, each of the given size, that fit in a
+ * memory of the specified size, respecting the HW requirement that the
+ * number of pages must be a multiple of 24.
+ */
+static inline unsigned int pm_num_pages(unsigned int mem_size,
+ unsigned int pg_size)
+{
+ unsigned int n = mem_size / pg_size;
+
+ return n - n % 24;
+}
+
+#define mem_region(adap, start, size, reg) \
+ t3_write_reg((adap), A_ ## reg, (start)); \
+ start += size
+
+/*
+ * partition_mem - partition memory and configure TP memory settings
+ * @adap: the adapter
+ * @p: the TP parameters
+ *
+ * Partitions context and payload memory and configures TP's memory
+ * registers.
+ */
+static void partition_mem(struct adapter *adap, const struct tp_params *p)
+{
+ unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5);
+ unsigned int timers = 0, timers_shift = 22;
+
+ if (adap->params.rev > 0) {
+ if (tids <= 16 * 1024) {
+ timers = 1;
+ timers_shift = 16;
+ } else if (tids <= 64 * 1024) {
+ timers = 2;
+ timers_shift = 18;
+ } else if (tids <= 256 * 1024) {
+ timers = 3;
+ timers_shift = 20;
+ }
+ }
+
+ t3_write_reg(adap, A_TP_PMM_SIZE,
+ p->chan_rx_size | (p->chan_tx_size >> 16));
+
+ t3_write_reg(adap, A_TP_PMM_TX_BASE, 0);
+ t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size);
+ t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs);
+ t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX),
+ V_TXDATAACKIDX(fls(p->tx_pg_size) - 12));
+
+ t3_write_reg(adap, A_TP_PMM_RX_BASE, 0);
+ t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size);
+ t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs);
+
+ pstructs = p->rx_num_pgs + p->tx_num_pgs;
+ /* Add a bit of headroom and make multiple of 24 */
+ pstructs += 48;
+ pstructs -= pstructs % 24;
+ t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs);
+
+ m = tids * TCB_SIZE;
+ mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR);
+ mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR);
+ t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m);
+ m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22);
+ mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE);
+ mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE);
+ mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE);
+ mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE);
+
+ m = (m + 4095) & ~0xfff;
+ t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m);
+ t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m);
+
+ tids = (p->cm_size - m - (3 << 20)) / 3072 - 32;
+ m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
+ adap->params.mc5.nfilters - adap->params.mc5.nroutes;
+ if (tids < m)
+ adap->params.mc5.nservers += m - tids;
+}
+
+static inline void tp_wr_indirect(struct adapter *adap, unsigned int addr,
+ u32 val)
+{
+ t3_write_reg(adap, A_TP_PIO_ADDR, addr);
+ t3_write_reg(adap, A_TP_PIO_DATA, val);
+}
+
+static void tp_config(struct adapter *adap, const struct tp_params *p)
+{
+ t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU |
+ F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
+ F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
+ t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
+ F_MTUENABLE | V_WINDOWSCALEMODE(1) |
+ V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
+ t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
+ V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
+ V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) |
+ F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
+ t3_set_reg_field(adap, A_TP_IN_CONFIG, F_IPV6ENABLE | F_NICMODE,
+ F_IPV6ENABLE | F_NICMODE);
+ t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
+ t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
+ t3_set_reg_field(adap, A_TP_PARA_REG6,
+ adap->params.rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND,
+ 0);
+
+ t3_set_reg_field(adap, A_TP_PC_CONFIG,
+ F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL,
+ F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE |
+ F_RXCONGESTIONMODE);
+ t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0);
+
+ if (adap->params.rev > 0) {
+ tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
+ t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
+ F_TXPACEAUTO);
+ t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID);
+ t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEAUTOSTRICT);
+ } else
+ t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
+
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0x12121212);
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0x12121212);
+ t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0x1212);
+}
+
+/* Desired TP timer resolution in usec */
+#define TP_TMR_RES 50
+
+/* TCP timer values in ms */
+#define TP_DACK_TIMER 50
+#define TP_RTO_MIN 250
+
+/**
+ * tp_set_timers - set TP timing parameters
+ * @adap: the adapter to set
+ * @core_clk: the core clock frequency in Hz
+ *
+ * Set TP's timing parameters, such as the various timer resolutions and
+ * the TCP timer values.
+ */
+static void tp_set_timers(struct adapter *adap, unsigned int core_clk)
+{
+ unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1;
+ unsigned int dack_re = fls(core_clk / 5000) - 1; /* 200us */
+ unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */
+ unsigned int tps = core_clk >> tre;
+
+ t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) |
+ V_DELAYEDACKRESOLUTION(dack_re) |
+ V_TIMESTAMPRESOLUTION(tstamp_re));
+ t3_write_reg(adap, A_TP_DACK_TIMER,
+ (core_clk >> dack_re) / (1000 / TP_DACK_TIMER));
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100);
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504);
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908);
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c);
+ t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) |
+ V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) |
+ V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
+ V_KEEPALIVEMAX(9));
+
+#define SECONDS * tps
+
+ t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS);
+ t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN));
+ t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS);
+ t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS);
+ t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS);
+ t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS);
+ t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS);
+ t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS);
+ t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS);
+
+#undef SECONDS
+}
+
+/**
+ * t3_tp_set_coalescing_size - set receive coalescing size
+ * @adap: the adapter
+ * @size: the receive coalescing size
+ * @psh: whether a set PSH bit should deliver coalesced data
+ *
+ * Set the receive coalescing size and PSH bit handling.
+ */
+int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh)
+{
+ u32 val;
+
+ if (size > MAX_RX_COALESCING_LEN)
+ return -EINVAL;
+
+ val = t3_read_reg(adap, A_TP_PARA_REG3);
+ val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN);
+
+ if (size) {
+ val |= F_RXCOALESCEENABLE;
+ if (psh)
+ val |= F_RXCOALESCEPSHEN;
+ t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
+ V_MAXRXDATA(MAX_RX_COALESCING_LEN));
+ }
+ t3_write_reg(adap, A_TP_PARA_REG3, val);
+ return 0;
+}
+
+/**
+ * t3_tp_set_max_rxsize - set the max receive size
+ * @adap: the adapter
+ * @size: the max receive size
+ *
+ * Set TP's max receive size. This is the limit that applies when
+ * receive coalescing is disabled.
+ */
+void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size)
+{
+ t3_write_reg(adap, A_TP_PARA_REG7,
+ V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
+}
+
+static void __devinit init_mtus(unsigned short mtus[])
+{
+ /*
+ * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so
+ * it can accomodate max size TCP/IP headers when SACK and timestamps
+ * are enabled and still have at least 8 bytes of payload.
+ */
+ mtus[0] = 88;
+ mtus[1] = 256;
+ mtus[2] = 512;
+ mtus[3] = 576;
+ mtus[4] = 808;
+ mtus[5] = 1024;
+ mtus[6] = 1280;
+ mtus[7] = 1492;
+ mtus[8] = 1500;
+ mtus[9] = 2002;
+ mtus[10] = 2048;
+ mtus[11] = 4096;
+ mtus[12] = 4352;
+ mtus[13] = 8192;
+ mtus[14] = 9000;
+ mtus[15] = 9600;
+}
+
+/*
+ * Initial congestion control parameters.
+ */
+static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
+{
+ a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
+ a[9] = 2;
+ a[10] = 3;
+ a[11] = 4;
+ a[12] = 5;
+ a[13] = 6;
+ a[14] = 7;
+ a[15] = 8;
+ a[16] = 9;
+ a[17] = 10;
+ a[18] = 14;
+ a[19] = 17;
+ a[20] = 21;
+ a[21] = 25;
+ a[22] = 30;
+ a[23] = 35;
+ a[24] = 45;
+ a[25] = 60;
+ a[26] = 80;
+ a[27] = 100;
+ a[28] = 200;
+ a[29] = 300;
+ a[30] = 400;
+ a[31] = 500;
+
+ b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
+ b[9] = b[10] = 1;
+ b[11] = b[12] = 2;
+ b[13] = b[14] = b[15] = b[16] = 3;
+ b[17] = b[18] = b[19] = b[20] = b[21] = 4;
+ b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
+ b[28] = b[29] = 6;
+ b[30] = b[31] = 7;
+}
+
+/* The minimum additive increment value for the congestion control table */
+#define CC_MIN_INCR 2U
+
+/**
+ * t3_load_mtus - write the MTU and congestion control HW tables
+ * @adap: the adapter
+ * @mtus: the unrestricted values for the MTU table
+ * @alphs: the values for the congestion control alpha parameter
+ * @beta: the values for the congestion control beta parameter
+ * @mtu_cap: the maximum permitted effective MTU
+ *
+ * Write the MTU table with the supplied MTUs capping each at &mtu_cap.
+ * Update the high-speed congestion control table with the supplied alpha,
+ * beta, and MTUs.
+ */
+void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
+ unsigned short alpha[NCCTRL_WIN],
+ unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap)
+{
+ static const unsigned int avg_pkts[NCCTRL_WIN] = {
+ 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
+ 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
+ 28672, 40960, 57344, 81920, 114688, 163840, 229376
+ };
+
+ unsigned int i, w;
+
+ for (i = 0; i < NMTUS; ++i) {
+ unsigned int mtu = min(mtus[i], mtu_cap);
+ unsigned int log2 = fls(mtu);
+
+ if (!(mtu & ((1 << log2) >> 2))) /* round */
+ log2--;
+ t3_write_reg(adap, A_TP_MTU_TABLE,
+ (i << 24) | (log2 << 16) | mtu);
+
+ for (w = 0; w < NCCTRL_WIN; ++w) {
+ unsigned int inc;
+
+ inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
+ CC_MIN_INCR);
+
+ t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
+ (w << 16) | (beta[w] << 13) | inc);
+ }
+ }
+}
+
+/**
+ * t3_read_hw_mtus - returns the values in the HW MTU table
+ * @adap: the adapter
+ * @mtus: where to store the HW MTU values
+ *
+ * Reads the HW MTU table.
+ */
+void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS])
+{
+ int i;
+
+ for (i = 0; i < NMTUS; ++i) {
+ unsigned int val;
+
+ t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i);
+ val = t3_read_reg(adap, A_TP_MTU_TABLE);
+ mtus[i] = val & 0x3fff;
+ }
+}
+
+/**
+ * t3_get_cong_cntl_tab - reads the congestion control table
+ * @adap: the adapter
+ * @incr: where to store the alpha values
+ *
+ * Reads the additive increments programmed into the HW congestion
+ * control table.
+ */
+void t3_get_cong_cntl_tab(struct adapter *adap,
+ unsigned short incr[NMTUS][NCCTRL_WIN])
+{
+ unsigned int mtu, w;
+
+ for (mtu = 0; mtu < NMTUS; ++mtu)
+ for (w = 0; w < NCCTRL_WIN; ++w) {
+ t3_write_reg(adap, A_TP_CCTRL_TABLE,
+ 0xffff0000 | (mtu << 5) | w);
+ incr[mtu][w] = t3_read_reg(adap, A_TP_CCTRL_TABLE) &
+ 0x1fff;
+ }
+}
+
+/**
+ * t3_tp_get_mib_stats - read TP's MIB counters
+ * @adap: the adapter
+ * @tps: holds the returned counter values
+ *
+ * Returns the values of TP's MIB counters.
+ */
+void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps)
+{
+ t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps,
+ sizeof(*tps) / sizeof(u32), 0);
+}
+
+#define ulp_region(adap, name, start, len) \
+ t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \
+ t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \
+ (start) + (len) - 1); \
+ start += len
+
+#define ulptx_region(adap, name, start, len) \
+ t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \
+ t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \
+ (start) + (len) - 1)
+
+static void ulp_config(struct adapter *adap, const struct tp_params *p)
+{
+ unsigned int m = p->chan_rx_size;
+
+ ulp_region(adap, ISCSI, m, p->chan_rx_size / 8);
+ ulp_region(adap, TDDP, m, p->chan_rx_size / 8);
+ ulptx_region(adap, TPT, m, p->chan_rx_size / 4);
+ ulp_region(adap, STAG, m, p->chan_rx_size / 4);
+ ulp_region(adap, RQ, m, p->chan_rx_size / 4);
+ ulptx_region(adap, PBL, m, p->chan_rx_size / 4);
+ ulp_region(adap, PBL, m, p->chan_rx_size / 4);
+ t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
+}
+
+void t3_config_trace_filter(struct adapter *adapter,
+ const struct trace_params *tp, int filter_index,
+ int invert, int enable)
+{
+ u32 addr, key[4], mask[4];
+
+ key[0] = tp->sport | (tp->sip << 16);
+ key[1] = (tp->sip >> 16) | (tp->dport << 16);
+ key[2] = tp->dip;
+ key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20);
+
+ mask[0] = tp->sport_mask | (tp->sip_mask << 16);
+ mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16);
+ mask[2] = tp->dip_mask;
+ mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20);
+
+ if (invert)
+ key[3] |= (1 << 29);
+ if (enable)
+ key[3] |= (1 << 28);
+
+ addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
+ tp_wr_indirect(adapter, addr++, key[0]);
+ tp_wr_indirect(adapter, addr++, mask[0]);
+ tp_wr_indirect(adapter, addr++, key[1]);
+ tp_wr_indirect(adapter, addr++, mask[1]);
+ tp_wr_indirect(adapter, addr++, key[2]);
+ tp_wr_indirect(adapter, addr++, mask[2]);
+ tp_wr_indirect(adapter, addr++, key[3]);
+ tp_wr_indirect(adapter, addr, mask[3]);
+ t3_read_reg(adapter, A_TP_PIO_DATA);
+}
+
+/**
+ * t3_config_sched - configure a HW traffic scheduler
+ * @adap: the adapter
+ * @kbps: target rate in Kbps
+ * @sched: the scheduler index
+ *
+ * Configure a HW scheduler for the target rate
+ */
+int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched)
+{
+ unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
+ unsigned int clk = adap->params.vpd.cclk * 1000;
+ unsigned int selected_cpt = 0, selected_bpt = 0;
+
+ if (kbps > 0) {
+ kbps *= 125; /* -> bytes */
+ for (cpt = 1; cpt <= 255; cpt++) {
+ tps = clk / cpt;
+ bpt = (kbps + tps / 2) / tps;
+ if (bpt > 0 && bpt <= 255) {
+ v = bpt * tps;
+ delta = v >= kbps ? v - kbps : kbps - v;
+ if (delta <= mindelta) {
+ mindelta = delta;
+ selected_cpt = cpt;
+ selected_bpt = bpt;
+ }
+ } else if (selected_cpt)
+ break;
+ }
+ if (!selected_cpt)
+ return -EINVAL;
+ }
+ t3_write_reg(adap, A_TP_TM_PIO_ADDR,
+ A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
+ v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
+ if (sched & 1)
+ v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
+ else
+ v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
+ t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
+ return 0;
+}
+
+static int tp_init(struct adapter *adap, const struct tp_params *p)
+{
+ int busy = 0;
+
+ tp_config(adap, p);
+ t3_set_vlan_accel(adap, 3, 0);
+
+ if (is_offload(adap)) {
+ tp_set_timers(adap, adap->params.vpd.cclk * 1000);
+ t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE);
+ busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE,
+ 0, 1000, 5);
+ if (busy)
+ CH_ERR(adap, "TP initialization timed out\n");
+ }
+
+ if (!busy)
+ t3_write_reg(adap, A_TP_RESET, F_TPRESET);
+ return busy;
+}
+
+int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask)
+{
+ if (port_mask & ~((1 << adap->params.nports) - 1))
+ return -EINVAL;
+ t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
+ port_mask << S_PORT0ACTIVE);
+ return 0;
+}
+
+/*
+ * Perform the bits of HW initialization that are dependent on the number
+ * of available ports.
+ */
+static void init_hw_for_avail_ports(struct adapter *adap, int nports)
+{
+ int i;
+
+ if (nports == 1) {
+ t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0);
+ t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
+ t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN |
+ F_PORT0ACTIVE | F_ENFORCEPKT);
+ t3_write_reg(adap, A_PM1_TX_CFG, 0xc000c000);
+ } else {
+ t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
+ t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
+ t3_write_reg(adap, A_ULPTX_DMA_WEIGHT,
+ V_D1_WEIGHT(16) | V_D0_WEIGHT(16));
+ t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN |
+ F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
+ F_ENFORCEPKT);
+ t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000);
+ t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE);
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
+ V_TX_MOD_QUEUE_REQ_MAP(0xaa));
+ for (i = 0; i < 16; i++)
+ t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE,
+ (i << 16) | 0x1010);
+ }
+}
+
+static int calibrate_xgm(struct adapter *adapter)
+{
+ if (uses_xaui(adapter)) {
+ unsigned int v, i;
+
+ for (i = 0; i < 5; ++i) {
+ t3_write_reg(adapter, A_XGM_XAUI_IMP, 0);
+ t3_read_reg(adapter, A_XGM_XAUI_IMP);
+ msleep(1);
+ v = t3_read_reg(adapter, A_XGM_XAUI_IMP);
+ if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) {
+ t3_write_reg(adapter, A_XGM_XAUI_IMP,
+ V_XAUIIMP(G_CALIMP(v) >> 2));
+ return 0;
+ }
+ }
+ CH_ERR(adapter, "MAC calibration failed\n");
+ return -1;
+ } else {
+ t3_write_reg(adapter, A_XGM_RGMII_IMP,
+ V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
+ F_XGM_IMPSETUPDATE);
+ }
+ return 0;
+}
+
+static void calibrate_xgm_t3b(struct adapter *adapter)
+{
+ if (!uses_xaui(adapter)) {
+ t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET |
+ F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0,
+ F_XGM_IMPSETUPDATE);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
+ 0);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE);
+ }
+}
+
+struct mc7_timing_params {
+ unsigned char ActToPreDly;
+ unsigned char ActToRdWrDly;
+ unsigned char PreCyc;
+ unsigned char RefCyc[5];
+ unsigned char BkCyc;
+ unsigned char WrToRdDly;
+ unsigned char RdToWrDly;
+};
+
+/*
+ * Write a value to a register and check that the write completed. These
+ * writes normally complete in a cycle or two, so one read should suffice.
+ * The very first read exists to flush the posted write to the device.
+ */
+static int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val)
+{
+ t3_write_reg(adapter, addr, val);
+ t3_read_reg(adapter, addr); /* flush */
+ if (!(t3_read_reg(adapter, addr) & F_BUSY))
+ return 0;
+ CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr);
+ return -EIO;
+}
+
+static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
+{
+ static const unsigned int mc7_mode[] = {
+ 0x632, 0x642, 0x652, 0x432, 0x442
+ };
+ static const struct mc7_timing_params mc7_timings[] = {
+ {12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4},
+ {12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4},
+ {12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4},
+ {9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4},
+ {9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4}
+ };
+
+ u32 val;
+ unsigned int width, density, slow, attempts;
+ struct adapter *adapter = mc7->adapter;
+ const struct mc7_timing_params *p = &mc7_timings[mem_type];
+
+ val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
+ slow = val & F_SLOW;
+ width = G_WIDTH(val);
+ density = G_DEN(val);
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN);
+ val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */
+ msleep(1);
+
+ if (!slow) {
+ t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN);
+ t3_read_reg(adapter, mc7->offset + A_MC7_CAL);
+ msleep(1);
+ if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) &
+ (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) {
+ CH_ERR(adapter, "%s MC7 calibration timed out\n",
+ mc7->name);
+ goto out_fail;
+ }
+ }
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_PARM,
+ V_ACTTOPREDLY(p->ActToPreDly) |
+ V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) |
+ V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) |
+ V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly));
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_CFG,
+ val | F_CLKEN | F_TERM150);
+ t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */
+
+ if (!slow)
+ t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB,
+ F_DLLENB);
+ udelay(1);
+
+ val = slow ? 3 : 6;
+ if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
+ goto out_fail;
+
+ if (!slow) {
+ t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100);
+ t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0);
+ udelay(5);
+ }
+
+ if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_MODE,
+ mc7_mode[mem_type]) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
+ goto out_fail;
+
+ /* clock value is in KHz */
+ mc7_clock = mc7_clock * 7812 + mc7_clock / 2; /* ns */
+ mc7_clock /= 1000000; /* KHz->MHz, ns->us */
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_REF,
+ F_PERREFEN | V_PREREFDIV(mc7_clock));
+ t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END,
+ (mc7->size << width) - 1);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1));
+ t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */
+
+ attempts = 50;
+ do {
+ msleep(250);
+ val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);
+ } while ((val & F_BUSY) && --attempts);
+ if (val & F_BUSY) {
+ CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name);
+ goto out_fail;
+ }
+
+ /* Enable normal memory accesses. */
+ t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY);
+ return 0;
+
+out_fail:
+ return -1;
+}
+
+static void config_pcie(struct adapter *adap)
+{
+ static const u16 ack_lat[4][6] = {
+ {237, 416, 559, 1071, 2095, 4143},
+ {128, 217, 289, 545, 1057, 2081},
+ {73, 118, 154, 282, 538, 1050},
+ {67, 107, 86, 150, 278, 534}
+ };
+ static const u16 rpl_tmr[4][6] = {
+ {711, 1248, 1677, 3213, 6285, 12429},
+ {384, 651, 867, 1635, 3171, 6243},
+ {219, 354, 462, 846, 1614, 3150},
+ {201, 321, 258, 450, 834, 1602}
+ };
+
+ u16 val;
+ unsigned int log2_width, pldsize;
+ unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
+
+ pci_read_config_word(adap->pdev,
+ adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
+ &val);
+ pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
+ pci_read_config_word(adap->pdev,
+ adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL,
+ &val);
+
+ fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
+ fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
+ G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE));
+ log2_width = fls(adap->params.pci.width) - 1;
+ acklat = ack_lat[log2_width][pldsize];
+ if (val & 1) /* check LOsEnable */
+ acklat += fst_trn_tx * 4;
+ rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4;
+
+ if (adap->params.rev == 0)
+ t3_set_reg_field(adap, A_PCIE_PEX_CTRL1,
+ V_T3A_ACKLAT(M_T3A_ACKLAT),
+ V_T3A_ACKLAT(acklat));
+ else
+ t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT),
+ V_ACKLAT(acklat));
+
+ t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT),
+ V_REPLAYLMT(rpllmt));
+
+ t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
+ t3_set_reg_field(adap, A_PCIE_CFG, F_PCIE_CLIDECEN, F_PCIE_CLIDECEN);
+}
+
+/*
+ * Initialize and configure T3 HW modules. This performs the
+ * initialization steps that need to be done once after a card is reset.
+ * MAC and PHY initialization is handled separarely whenever a port is enabled.
+ *
+ * fw_params are passed to FW and their value is platform dependent. Only the
+ * top 8 bits are available for use, the rest must be 0.
+ */
+int t3_init_hw(struct adapter *adapter, u32 fw_params)
+{
+ int err = -EIO, attempts = 100;
+ const struct vpd_params *vpd = &adapter->params.vpd;
+
+ if (adapter->params.rev > 0)
+ calibrate_xgm_t3b(adapter);
+ else if (calibrate_xgm(adapter))
+ goto out_err;
+
+ if (vpd->mclk) {
+ partition_mem(adapter, &adapter->params.tp);
+
+ if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) ||
+ mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) ||
+ mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) ||
+ t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers,
+ adapter->params.mc5.nfilters,
+ adapter->params.mc5.nroutes))
+ goto out_err;
+ }
+
+ if (tp_init(adapter, &adapter->params.tp))
+ goto out_err;
+
+ t3_tp_set_coalescing_size(adapter,
+ min(adapter->params.sge.max_pkt_size,
+ MAX_RX_COALESCING_LEN), 1);
+ t3_tp_set_max_rxsize(adapter,
+ min(adapter->params.sge.max_pkt_size, 16384U));
+ ulp_config(adapter, &adapter->params.tp);
+
+ if (is_pcie(adapter))
+ config_pcie(adapter);
+ else
+ t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
+
+ t3_write_reg(adapter, A_PM1_RX_CFG, 0xf000f000);
+ init_hw_for_avail_ports(adapter, adapter->params.nports);
+ t3_sge_init(adapter, &adapter->params.sge);
+
+ t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
+ t3_write_reg(adapter, A_CIM_BOOT_CFG,
+ V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
+ t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */
+
+ do { /* wait for uP to initialize */
+ msleep(20);
+ } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
+ if (!attempts)
+ goto out_err;
+
+ err = 0;
+out_err:
+ return err;
+}
+
+/**
+ * get_pci_mode - determine a card's PCI mode
+ * @adapter: the adapter
+ * @p: where to store the PCI settings
+ *
+ * Determines a card's PCI mode and associated parameters, such as speed
+ * and width.
+ */
+static void __devinit get_pci_mode(struct adapter *adapter,
+ struct pci_params *p)
+{
+ static unsigned short speed_map[] = { 33, 66, 100, 133 };
+ u32 pci_mode, pcie_cap;
+
+ pcie_cap = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (pcie_cap) {
+ u16 val;
+
+ p->variant = PCI_VARIANT_PCIE;
+ p->pcie_cap_addr = pcie_cap;
+ pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA,
+ &val);
+ p->width = (val >> 4) & 0x3f;
+ return;
+ }
+
+ pci_mode = t3_read_reg(adapter, A_PCIX_MODE);
+ p->speed = speed_map[G_PCLKRANGE(pci_mode)];
+ p->width = (pci_mode & F_64BIT) ? 64 : 32;
+ pci_mode = G_PCIXINITPAT(pci_mode);
+ if (pci_mode == 0)
+ p->variant = PCI_VARIANT_PCI;
+ else if (pci_mode < 4)
+ p->variant = PCI_VARIANT_PCIX_MODE1_PARITY;
+ else if (pci_mode < 8)
+ p->variant = PCI_VARIANT_PCIX_MODE1_ECC;
+ else
+ p->variant = PCI_VARIANT_PCIX_266_MODE2;
+}
+
+/**
+ * init_link_config - initialize a link's SW state
+ * @lc: structure holding the link state
+ * @ai: information about the current card
+ *
+ * Initializes the SW state maintained for each link, including the link's
+ * capabilities and default speed/duplex/flow-control/autonegotiation
+ * settings.
+ */
+static void __devinit init_link_config(struct link_config *lc,
+ unsigned int caps)
+{
+ lc->supported = caps;
+ lc->requested_speed = lc->speed = SPEED_INVALID;
+ lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
+ lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
+ if (lc->supported & SUPPORTED_Autoneg) {
+ lc->advertising = lc->supported;
+ lc->autoneg = AUTONEG_ENABLE;
+ lc->requested_fc |= PAUSE_AUTONEG;
+ } else {
+ lc->advertising = 0;
+ lc->autoneg = AUTONEG_DISABLE;
+ }
+}
+
+/**
+ * mc7_calc_size - calculate MC7 memory size
+ * @cfg: the MC7 configuration
+ *
+ * Calculates the size of an MC7 memory in bytes from the value of its
+ * configuration register.
+ */
+static unsigned int __devinit mc7_calc_size(u32 cfg)
+{
+ unsigned int width = G_WIDTH(cfg);
+ unsigned int banks = !!(cfg & F_BKS) + 1;
+ unsigned int org = !!(cfg & F_ORG) + 1;
+ unsigned int density = G_DEN(cfg);
+ unsigned int MBs = ((256 << density) * banks) / (org << width);
+
+ return MBs << 20;
+}
+
+static void __devinit mc7_prep(struct adapter *adapter, struct mc7 *mc7,
+ unsigned int base_addr, const char *name)
+{
+ u32 cfg;
+
+ mc7->adapter = adapter;
+ mc7->name = name;
+ mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
+ cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
+ mc7->size = mc7_calc_size(cfg);
+ mc7->width = G_WIDTH(cfg);
+}
+
+void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
+{
+ mac->adapter = adapter;
+ mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
+ mac->nucast = 1;
+
+ if (adapter->params.rev == 0 && uses_xaui(adapter)) {
+ t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset,
+ is_10G(adapter) ? 0x2901c04 : 0x2301c04);
+ t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset,
+ F_ENRGMII, 0);
+ }
+}
+
+void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
+{
+ u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2);
+
+ mi1_init(adapter, ai);
+ t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */
+ V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
+ t3_write_reg(adapter, A_T3DBG_GPIO_EN,
+ ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
+
+ if (adapter->params.rev == 0 || !uses_xaui(adapter))
+ val |= F_ENRGMII;
+
+ /* Enable MAC clocks so we can access the registers */
+ t3_write_reg(adapter, A_XGM_PORT_CFG, val);
+ t3_read_reg(adapter, A_XGM_PORT_CFG);
+
+ val |= F_CLKDIVRESET_;
+ t3_write_reg(adapter, A_XGM_PORT_CFG, val);
+ t3_read_reg(adapter, A_XGM_PORT_CFG);
+ t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val);
+ t3_read_reg(adapter, A_XGM_PORT_CFG);
+}
+
+/*
+ * Reset the adapter. PCIe cards lose their config space during reset, PCI-X
+ * ones don't.
+ */
+int t3_reset_adapter(struct adapter *adapter)
+{
+ int i;
+ uint16_t devid = 0;
+
+ if (is_pcie(adapter))
+ pci_save_state(adapter->pdev);
+ t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE);
+
+ /*
+ * Delay. Give Some time to device to reset fully.
+ * XXX The delay time should be modified.
+ */
+ for (i = 0; i < 10; i++) {
+ msleep(50);
+ pci_read_config_word(adapter->pdev, 0x00, &devid);
+ if (devid == 0x1425)
+ break;
+ }
+
+ if (devid != 0x1425)
+ return -1;
+
+ if (is_pcie(adapter))
+ pci_restore_state(adapter->pdev);
+ return 0;
+}
+
+/*
+ * Initialize adapter SW state for the various HW modules, set initial values
+ * for some adapter tunables, take PHYs out of reset, and initialize the MDIO
+ * interface.
+ */
+int __devinit t3_prep_adapter(struct adapter *adapter,
+ const struct adapter_info *ai, int reset)
+{
+ int ret;
+ unsigned int i, j = 0;
+
+ get_pci_mode(adapter, &adapter->params.pci);
+
+ adapter->params.info = ai;
+ adapter->params.nports = ai->nports;
+ adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
+ adapter->params.linkpoll_period = 0;
+ adapter->params.stats_update_period = is_10G(adapter) ?
+ MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
+ adapter->params.pci.vpd_cap_addr =
+ pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD);
+ ret = get_vpd_params(adapter, &adapter->params.vpd);
+ if (ret < 0)
+ return ret;
+
+ if (reset && t3_reset_adapter(adapter))
+ return -1;
+
+ t3_sge_prep(adapter, &adapter->params.sge);
+
+ if (adapter->params.vpd.mclk) {
+ struct tp_params *p = &adapter->params.tp;
+
+ mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX");
+ mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX");
+ mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM");
+
+ p->nchan = ai->nports;
+ p->pmrx_size = t3_mc7_size(&adapter->pmrx);
+ p->pmtx_size = t3_mc7_size(&adapter->pmtx);
+ p->cm_size = t3_mc7_size(&adapter->cm);
+ p->chan_rx_size = p->pmrx_size / 2; /* only 1 Rx channel */
+ p->chan_tx_size = p->pmtx_size / p->nchan;
+ p->rx_pg_size = 64 * 1024;
+ p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024;
+ p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size);
+ p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size);
+ p->ntimer_qs = p->cm_size >= (128 << 20) ||
+ adapter->params.rev > 0 ? 12 : 6;
+
+ adapter->params.mc5.nservers = DEFAULT_NSERVERS;
+ adapter->params.mc5.nfilters = adapter->params.rev > 0 ?
+ DEFAULT_NFILTERS : 0;
+ adapter->params.mc5.nroutes = 0;
+ t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
+
+ init_mtus(adapter->params.mtus);
+ init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
+ }
+
+ early_hw_init(adapter, ai);
+
+ for_each_port(adapter, i) {
+ u8 hw_addr[6];
+ struct port_info *p = adap2pinfo(adapter, i);
+
+ while (!adapter->params.vpd.port_type[j])
+ ++j;
+
+ p->port_type = &port_types[adapter->params.vpd.port_type[j]];
+ p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
+ ai->mdio_ops);
+ mac_prep(&p->mac, adapter, j);
+ ++j;
+
+ /*
+ * The VPD EEPROM stores the base Ethernet address for the
+ * card. A port's address is derived from the base by adding
+ * the port's index to the base's low octet.
+ */
+ memcpy(hw_addr, adapter->params.vpd.eth_base, 5);
+ hw_addr[5] = adapter->params.vpd.eth_base[5] + i;
+
+ memcpy(adapter->port[i]->dev_addr, hw_addr,
+ ETH_ALEN);
+ memcpy(adapter->port[i]->perm_addr, hw_addr,
+ ETH_ALEN);
+ init_link_config(&p->link_config, p->port_type->caps);
+ p->phy.ops->power_down(&p->phy, 1);
+ if (!(p->port_type->caps & SUPPORTED_IRQ))
+ adapter->params.linkpoll_period = 10;
+ }
+
+ return 0;
+}
+
+void t3_led_ready(struct adapter *adapter)
+{
+ t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+ F_GPIO0_OUT_VAL);
+}
diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h
new file mode 100644
index 00000000000..9af3bcd64b3
--- /dev/null
+++ b/drivers/net/cxgb3/t3cdev.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2006-2007 Chelsio Communications. All rights reserved.
+ * Copyright (C) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _T3CDEV_H_
+#define _T3CDEV_H_
+
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <net/neighbour.h>
+
+#define T3CNAMSIZ 16
+
+/* Get the t3cdev associated with a net_device */
+#define T3CDEV(netdev) (struct t3cdev *)(netdev->priv)
+
+struct cxgb3_client;
+
+enum t3ctype {
+ T3A = 0,
+ T3B
+};
+
+struct t3cdev {
+ char name[T3CNAMSIZ]; /* T3C device name */
+ enum t3ctype type;
+ struct list_head ofld_dev_list; /* for list linking */
+ struct net_device *lldev; /* LL dev associated with T3C messages */
+ struct proc_dir_entry *proc_dir; /* root of proc dir for this T3C */
+ int (*send)(struct t3cdev *dev, struct sk_buff *skb);
+ int (*recv)(struct t3cdev *dev, struct sk_buff **skb, int n);
+ int (*ctl)(struct t3cdev *dev, unsigned int req, void *data);
+ void (*neigh_update)(struct t3cdev *dev, struct neighbour *neigh);
+ void *priv; /* driver private data */
+ void *l2opt; /* optional layer 2 data */
+ void *l3opt; /* optional layer 3 data */
+ void *l4opt; /* optional layer 4 data */
+ void *ulp; /* ulp stuff */
+};
+
+#endif /* _T3CDEV_H_ */
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
new file mode 100644
index 00000000000..2b67dd523cc
--- /dev/null
+++ b/drivers/net/cxgb3/version.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $Date: 2006/10/31 18:57:51 $ $RCSfile: version.h,v $ $Revision: 1.3 $ */
+#ifndef __CHELSIO_VERSION_H
+#define __CHELSIO_VERSION_H
+#define DRV_DESC "Chelsio T3 Network Driver"
+#define DRV_NAME "cxgb3"
+/* Driver version */
+#define DRV_VERSION "1.0"
+#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c
new file mode 100644
index 00000000000..eee4285b31b
--- /dev/null
+++ b/drivers/net/cxgb3/vsc8211.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+
+/* VSC8211 PHY specific registers. */
+enum {
+ VSC8211_INTR_ENABLE = 25,
+ VSC8211_INTR_STATUS = 26,
+ VSC8211_AUX_CTRL_STAT = 28,
+};
+
+enum {
+ VSC_INTR_RX_ERR = 1 << 0,
+ VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */
+ VSC_INTR_CABLE = 1 << 2, /* cable impairment */
+ VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */
+ VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */
+ VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */
+ VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */
+ VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */
+ VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */
+ VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
+ VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
+ VSC_INTR_LINK_CHG = 1 << 13, /* link change */
+ VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
+};
+
+#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
+ VSC_INTR_NEG_DONE)
+#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
+ VSC_INTR_ENABLE)
+
+/* PHY specific auxiliary control & status register fields */
+#define S_ACSR_ACTIPHY_TMR 0
+#define M_ACSR_ACTIPHY_TMR 0x3
+#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
+
+#define S_ACSR_SPEED 3
+#define M_ACSR_SPEED 0x3
+#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
+
+#define S_ACSR_DUPLEX 5
+#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
+
+#define S_ACSR_ACTIPHY 6
+#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
+
+/*
+ * Reset the PHY. This PHY completes reset immediately so we never wait.
+ */
+static int vsc8211_reset(struct cphy *cphy, int wait)
+{
+ return t3_phy_reset(cphy, 0, 0);
+}
+
+static int vsc8211_intr_enable(struct cphy *cphy)
+{
+ return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
+}
+
+static int vsc8211_intr_disable(struct cphy *cphy)
+{
+ return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
+}
+
+static int vsc8211_intr_clear(struct cphy *cphy)
+{
+ u32 val;
+
+ /* Clear PHY interrupts by reading the register. */
+ return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
+}
+
+static int vsc8211_autoneg_enable(struct cphy *cphy)
+{
+ return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
+ BMCR_ANENABLE | BMCR_ANRESTART);
+}
+
+static int vsc8211_autoneg_restart(struct cphy *cphy)
+{
+ return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
+ BMCR_ANRESTART);
+}
+
+static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
+ int *speed, int *duplex, int *fc)
+{
+ unsigned int bmcr, status, lpa, adv;
+ int err, sp = -1, dplx = -1, pause = 0;
+
+ err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
+ if (!err)
+ err = mdio_read(cphy, 0, MII_BMSR, &status);
+ if (err)
+ return err;
+
+ if (link_ok) {
+ /*
+ * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
+ * once more to get the current link state.
+ */
+ if (!(status & BMSR_LSTATUS))
+ err = mdio_read(cphy, 0, MII_BMSR, &status);
+ if (err)
+ return err;
+ *link_ok = (status & BMSR_LSTATUS) != 0;
+ }
+ if (!(bmcr & BMCR_ANENABLE)) {
+ dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+ if (bmcr & BMCR_SPEED1000)
+ sp = SPEED_1000;
+ else if (bmcr & BMCR_SPEED100)
+ sp = SPEED_100;
+ else
+ sp = SPEED_10;
+ } else if (status & BMSR_ANEGCOMPLETE) {
+ err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
+ if (err)
+ return err;
+
+ dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
+ sp = G_ACSR_SPEED(status);
+ if (sp == 0)
+ sp = SPEED_10;
+ else if (sp == 1)
+ sp = SPEED_100;
+ else
+ sp = SPEED_1000;
+
+ if (fc && dplx == DUPLEX_FULL) {
+ err = mdio_read(cphy, 0, MII_LPA, &lpa);
+ if (!err)
+ err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
+ if (err)
+ return err;
+
+ if (lpa & adv & ADVERTISE_PAUSE_CAP)
+ pause = PAUSE_RX | PAUSE_TX;
+ else if ((lpa & ADVERTISE_PAUSE_CAP) &&
+ (lpa & ADVERTISE_PAUSE_ASYM) &&
+ (adv & ADVERTISE_PAUSE_ASYM))
+ pause = PAUSE_TX;
+ else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
+ (adv & ADVERTISE_PAUSE_CAP))
+ pause = PAUSE_RX;
+ }
+ }
+ if (speed)
+ *speed = sp;
+ if (duplex)
+ *duplex = dplx;
+ if (fc)
+ *fc = pause;
+ return 0;
+}
+
+static int vsc8211_power_down(struct cphy *cphy, int enable)
+{
+ return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
+ enable ? BMCR_PDOWN : 0);
+}
+
+static int vsc8211_intr_handler(struct cphy *cphy)
+{
+ unsigned int cause;
+ int err, cphy_cause = 0;
+
+ err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
+ if (err)
+ return err;
+
+ cause &= INTR_MASK;
+ if (cause & CFG_CHG_INTR_MASK)
+ cphy_cause |= cphy_cause_link_change;
+ if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
+ cphy_cause |= cphy_cause_fifo_error;
+ return cphy_cause;
+}
+
+static struct cphy_ops vsc8211_ops = {
+ .reset = vsc8211_reset,
+ .intr_enable = vsc8211_intr_enable,
+ .intr_disable = vsc8211_intr_disable,
+ .intr_clear = vsc8211_intr_clear,
+ .intr_handler = vsc8211_intr_handler,
+ .autoneg_enable = vsc8211_autoneg_enable,
+ .autoneg_restart = vsc8211_autoneg_restart,
+ .advertise = t3_phy_advertise,
+ .set_speed_duplex = t3_set_phy_speed_duplex,
+ .get_link_status = vsc8211_get_link_status,
+ .power_down = vsc8211_power_down,
+};
+
+void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
+}
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
new file mode 100644
index 00000000000..907a272ae32
--- /dev/null
+++ b/drivers/net/cxgb3/xgmac.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+/*
+ * # of exact address filters. The first one is used for the station address,
+ * the rest are available for multicast addresses.
+ */
+#define EXACT_ADDR_FILTERS 8
+
+static inline int macidx(const struct cmac *mac)
+{
+ return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
+}
+
+static void xaui_serdes_reset(struct cmac *mac)
+{
+ static const unsigned int clear[] = {
+ F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,
+ F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3
+ };
+
+ int i;
+ struct adapter *adap = mac->adapter;
+ u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
+
+ t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
+ F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
+ F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
+ F_RESETPLL23 | F_RESETPLL01);
+ t3_read_reg(adap, ctrl);
+ udelay(15);
+
+ for (i = 0; i < ARRAY_SIZE(clear); i++) {
+ t3_set_reg_field(adap, ctrl, clear[i], 0);
+ udelay(15);
+ }
+}
+
+void t3b_pcs_reset(struct cmac *mac)
+{
+ t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
+ F_PCS_RESET_, 0);
+ udelay(20);
+ t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
+ F_PCS_RESET_);
+}
+
+int t3_mac_reset(struct cmac *mac)
+{
+ static const struct addr_val_pair mac_reset_avp[] = {
+ {A_XGM_TX_CTRL, 0},
+ {A_XGM_RX_CTRL, 0},
+ {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
+ F_RMFCS | F_ENJUMBO | F_ENHASHMCAST},
+ {A_XGM_RX_HASH_LOW, 0},
+ {A_XGM_RX_HASH_HIGH, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_1, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_2, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_3, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_4, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_5, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_6, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_7, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_8, 0},
+ {A_XGM_STAT_CTRL, F_CLRSTATS}
+ };
+ u32 val;
+ struct adapter *adap = mac->adapter;
+ unsigned int oft = mac->offset;
+
+ t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
+ t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
+
+ t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
+ t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
+ F_RXSTRFRWRD | F_DISERRFRAMES,
+ uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
+
+ if (uses_xaui(adap)) {
+ if (adap->params.rev == 0) {
+ t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
+ F_RXENABLE | F_TXENABLE);
+ if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
+ F_CMULOCK, 1, 5, 2)) {
+ CH_ERR(adap,
+ "MAC %d XAUI SERDES CMU lock failed\n",
+ macidx(mac));
+ return -1;
+ }
+ t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
+ F_SERDESRESET_);
+ } else
+ xaui_serdes_reset(mac);
+ }
+
+ if (adap->params.rev > 0)
+ t3_write_reg(adap, A_XGM_PAUSE_TIMER + oft, 0xf000);
+
+ val = F_MAC_RESET_;
+ if (is_10G(adap))
+ val |= F_PCS_RESET_;
+ else if (uses_xaui(adap))
+ val |= F_PCS_RESET_ | F_XG2G_RESET_;
+ else
+ val |= F_RGMII_RESET_ | F_XG2G_RESET_;
+ t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
+ t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
+ if ((val & F_PCS_RESET_) && adap->params.rev) {
+ msleep(1);
+ t3b_pcs_reset(mac);
+ }
+
+ memset(&mac->stats, 0, sizeof(mac->stats));
+ return 0;
+}
+
+/*
+ * Set the exact match register 'idx' to recognize the given Ethernet address.
+ */
+static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr)
+{
+ u32 addr_lo, addr_hi;
+ unsigned int oft = mac->offset + idx * 8;
+
+ addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+ addr_hi = (addr[5] << 8) | addr[4];
+
+ t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
+ t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
+}
+
+/* Set one of the station's unicast MAC addresses. */
+int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
+{
+ if (idx >= mac->nucast)
+ return -EINVAL;
+ set_addr_filter(mac, idx, addr);
+ return 0;
+}
+
+/*
+ * Specify the number of exact address filters that should be reserved for
+ * unicast addresses. Caller should reload the unicast and multicast addresses
+ * after calling this.
+ */
+int t3_mac_set_num_ucast(struct cmac *mac, int n)
+{
+ if (n > EXACT_ADDR_FILTERS)
+ return -EINVAL;
+ mac->nucast = n;
+ return 0;
+}
+
+/* Calculate the RX hash filter index of an Ethernet address */
+static int hash_hw_addr(const u8 * addr)
+{
+ int hash = 0, octet, bit, i = 0, c;
+
+ for (octet = 0; octet < 6; ++octet)
+ for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
+ hash ^= (c & 1) << i;
+ if (++i == 6)
+ i = 0;
+ }
+ return hash;
+}
+
+int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
+{
+ u32 val, hash_lo, hash_hi;
+ struct adapter *adap = mac->adapter;
+ unsigned int oft = mac->offset;
+
+ val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES;
+ if (rm->dev->flags & IFF_PROMISC)
+ val |= F_COPYALLFRAMES;
+ t3_write_reg(adap, A_XGM_RX_CFG + oft, val);
+
+ if (rm->dev->flags & IFF_ALLMULTI)
+ hash_lo = hash_hi = 0xffffffff;
+ else {
+ u8 *addr;
+ int exact_addr_idx = mac->nucast;
+
+ hash_lo = hash_hi = 0;
+ while ((addr = t3_get_next_mcaddr(rm)))
+ if (exact_addr_idx < EXACT_ADDR_FILTERS)
+ set_addr_filter(mac, exact_addr_idx++, addr);
+ else {
+ int hash = hash_hw_addr(addr);
+
+ if (hash < 32)
+ hash_lo |= (1 << hash);
+ else
+ hash_hi |= (1 << (hash - 32));
+ }
+ }
+
+ t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
+ t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
+ return 0;
+}
+
+int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
+{
+ int hwm, lwm;
+ unsigned int thres, v;
+ struct adapter *adap = mac->adapter;
+
+ /*
+ * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max
+ * packet size register includes header, but not FCS.
+ */
+ mtu += 14;
+ if (mtu > MAX_FRAME_SIZE - 4)
+ return -EINVAL;
+ t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
+
+ /*
+ * Adjust the PAUSE frame watermarks. We always set the LWM, and the
+ * HWM only if flow-control is enabled.
+ */
+ hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, MAC_RXFIFO_SIZE / 2U);
+ hwm = min(hwm, 3 * MAC_RXFIFO_SIZE / 4 + 1024);
+ lwm = hwm - 1024;
+ v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
+ v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
+ v |= V_RXFIFOPAUSELWM(lwm / 8);
+ if (G_RXFIFOPAUSEHWM(v))
+ v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
+ V_RXFIFOPAUSEHWM(hwm / 8);
+ t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
+
+ /* Adjust the TX FIFO threshold based on the MTU */
+ thres = (adap->params.vpd.cclk * 1000) / 15625;
+ thres = (thres * mtu) / 1000;
+ if (is_10G(adap))
+ thres /= 10;
+ thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
+ thres = max(thres, 8U); /* need at least 8 */
+ t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
+ V_TXFIFOTHRESH(M_TXFIFOTHRESH), V_TXFIFOTHRESH(thres));
+ return 0;
+}
+
+int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
+{
+ u32 val;
+ struct adapter *adap = mac->adapter;
+ unsigned int oft = mac->offset;
+
+ if (duplex >= 0 && duplex != DUPLEX_FULL)
+ return -EINVAL;
+ if (speed >= 0) {
+ if (speed == SPEED_10)
+ val = V_PORTSPEED(0);
+ else if (speed == SPEED_100)
+ val = V_PORTSPEED(1);
+ else if (speed == SPEED_1000)
+ val = V_PORTSPEED(2);
+ else if (speed == SPEED_10000)
+ val = V_PORTSPEED(3);
+ else
+ return -EINVAL;
+
+ t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
+ V_PORTSPEED(M_PORTSPEED), val);
+ }
+
+ val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
+ val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
+ if (fc & PAUSE_TX)
+ val |= V_RXFIFOPAUSEHWM(G_RXFIFOPAUSELWM(val) + 128); /* +1KB */
+ t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
+
+ t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
+ (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
+ return 0;
+}
+
+int t3_mac_enable(struct cmac *mac, int which)
+{
+ int idx = macidx(mac);
+ struct adapter *adap = mac->adapter;
+ unsigned int oft = mac->offset;
+
+ if (which & MAC_DIRECTION_TX) {
+ t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+ t3_write_reg(adap, A_TP_PIO_DATA, 0xbf000001);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
+ t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
+ }
+ if (which & MAC_DIRECTION_RX)
+ t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
+ return 0;
+}
+
+int t3_mac_disable(struct cmac *mac, int which)
+{
+ int idx = macidx(mac);
+ struct adapter *adap = mac->adapter;
+
+ if (which & MAC_DIRECTION_TX) {
+ t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+ t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
+ t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 0);
+ }
+ if (which & MAC_DIRECTION_RX)
+ t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
+ return 0;
+}
+
+/*
+ * This function is called periodically to accumulate the current values of the
+ * RMON counters into the port statistics. Since the packet counters are only
+ * 32 bits they can overflow in ~286 secs at 10G, so the function should be
+ * called more frequently than that. The byte counters are 45-bit wide, they
+ * would overflow in ~7.8 hours.
+ */
+const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
+{
+#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
+#define RMON_UPDATE(mac, name, reg) \
+ (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
+#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
+ (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
+ ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
+
+ u32 v, lo;
+
+ RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
+ RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
+ RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
+ RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
+ RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
+ RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
+ RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
+ RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
+ RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
+
+ RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
+ mac->stats.rx_too_long += RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
+
+ RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);
+
+ RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
+ RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
+ RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
+ RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
+ RMON_UPDATE(mac, tx_pause, TX_PAUSE);
+ /* This counts error frames in general (bad FCS, underrun, etc). */
+ RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
+
+ RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);
+
+ /* The next stat isn't clear-on-read. */
+ t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
+ v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
+ lo = (u32) mac->stats.rx_cong_drops;
+ mac->stats.rx_cong_drops += (u64) (v - lo);
+
+ return &mac->stats;
+}
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 4ae0fed7122..9f7e1db8ce6 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -5,7 +5,7 @@
*
* adopted from sunlance.c by Richard van den Berg
*
- * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki
+ * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki
*
* additional sources:
* - PMAD-AA TURBOchannel Ethernet Module Functional Specification,
@@ -44,6 +44,8 @@
* v0.010: Fixes for the PMAD mapping of the LANCE buffer and for the
* PMAX requirement to only use halfword accesses to the
* buffer. macro
+ *
+ * v0.011: Converted the PMAD to the driver model. macro
*/
#include <linux/crc32.h>
@@ -58,6 +60,7 @@
#include <linux/spinlock.h>
#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/tc.h>
#include <linux/types.h>
#include <asm/addrspace.h>
@@ -69,15 +72,16 @@
#include <asm/dec/kn01.h>
#include <asm/dec/machtype.h>
#include <asm/dec/system.h>
-#include <asm/dec/tc.h>
static char version[] __devinitdata =
-"declance.c: v0.010 by Linux MIPS DECstation task force\n";
+"declance.c: v0.011 by Linux MIPS DECstation task force\n";
MODULE_AUTHOR("Linux MIPS DECstation task force");
MODULE_DESCRIPTION("DEC LANCE (DECstation onboard, PMAD-xx) driver");
MODULE_LICENSE("GPL");
+#define __unused __attribute__ ((unused))
+
/*
* card types
*/
@@ -246,7 +250,6 @@ struct lance_init_block {
struct lance_private {
struct net_device *next;
int type;
- int slot;
int dma_irq;
volatile struct lance_regs *ll;
@@ -288,6 +291,7 @@ struct lance_regs {
int dec_lance_debug = 2;
+static struct tc_driver dec_lance_tc_driver;
static struct net_device *root_lance_dev;
static inline void writereg(volatile unsigned short *regptr, short value)
@@ -1023,7 +1027,7 @@ static void lance_set_multicast_retry(unsigned long _opaque)
lance_set_multicast(dev);
}
-static int __init dec_lance_init(const int type, const int slot)
+static int __init dec_lance_probe(struct device *bdev, const int type)
{
static unsigned version_printed;
static const char fmt[] = "declance%d";
@@ -1031,6 +1035,7 @@ static int __init dec_lance_init(const int type, const int slot)
struct net_device *dev;
struct lance_private *lp;
volatile struct lance_regs *ll;
+ resource_size_t start = 0, len = 0;
int i, ret;
unsigned long esar_base;
unsigned char *esar;
@@ -1038,14 +1043,18 @@ static int __init dec_lance_init(const int type, const int slot)
if (dec_lance_debug && version_printed++ == 0)
printk(version);
- i = 0;
- dev = root_lance_dev;
- while (dev) {
- i++;
- lp = (struct lance_private *)dev->priv;
- dev = lp->next;
+ if (bdev)
+ snprintf(name, sizeof(name), "%s", bdev->bus_id);
+ else {
+ i = 0;
+ dev = root_lance_dev;
+ while (dev) {
+ i++;
+ lp = (struct lance_private *)dev->priv;
+ dev = lp->next;
+ }
+ snprintf(name, sizeof(name), fmt, i);
}
- snprintf(name, sizeof(name), fmt, i);
dev = alloc_etherdev(sizeof(struct lance_private));
if (!dev) {
@@ -1063,7 +1072,6 @@ static int __init dec_lance_init(const int type, const int slot)
spin_lock_init(&lp->lock);
lp->type = type;
- lp->slot = slot;
switch (type) {
case ASIC_LANCE:
dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE);
@@ -1110,12 +1118,22 @@ static int __init dec_lance_init(const int type, const int slot)
break;
#ifdef CONFIG_TC
case PMAD_LANCE:
- claim_tc_card(slot);
+ dev_set_drvdata(bdev, dev);
+
+ start = to_tc_dev(bdev)->resource.start;
+ len = to_tc_dev(bdev)->resource.end - start + 1;
+ if (!request_mem_region(start, len, bdev->bus_id)) {
+ printk(KERN_ERR
+ "%s: Unable to reserve MMIO resource\n",
+ bdev->bus_id);
+ ret = -EBUSY;
+ goto err_out_dev;
+ }
- dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot));
+ dev->mem_start = CKSEG1ADDR(start);
dev->mem_end = dev->mem_start + 0x100000;
dev->base_addr = dev->mem_start + 0x100000;
- dev->irq = get_tc_irq_nr(slot);
+ dev->irq = to_tc_dev(bdev)->interrupt;
esar_base = dev->mem_start + 0x1c0002;
lp->dma_irq = -1;
@@ -1174,7 +1192,7 @@ static int __init dec_lance_init(const int type, const int slot)
printk(KERN_ERR "%s: declance_init called with unknown type\n",
name);
ret = -ENODEV;
- goto err_out_free_dev;
+ goto err_out_dev;
}
ll = (struct lance_regs *) dev->base_addr;
@@ -1188,7 +1206,7 @@ static int __init dec_lance_init(const int type, const int slot)
"%s: Ethernet station address prom not found!\n",
name);
ret = -ENODEV;
- goto err_out_free_dev;
+ goto err_out_resource;
}
/* Check the prom contents */
for (i = 0; i < 8; i++) {
@@ -1198,7 +1216,7 @@ static int __init dec_lance_init(const int type, const int slot)
printk(KERN_ERR "%s: Something is wrong with the "
"ethernet station address prom!\n", name);
ret = -ENODEV;
- goto err_out_free_dev;
+ goto err_out_resource;
}
}
@@ -1255,48 +1273,51 @@ static int __init dec_lance_init(const int type, const int slot)
if (ret) {
printk(KERN_ERR
"%s: Unable to register netdev, aborting.\n", name);
- goto err_out_free_dev;
+ goto err_out_resource;
}
- lp->next = root_lance_dev;
- root_lance_dev = dev;
+ if (!bdev) {
+ lp->next = root_lance_dev;
+ root_lance_dev = dev;
+ }
printk("%s: registered as %s.\n", name, dev->name);
return 0;
-err_out_free_dev:
+err_out_resource:
+ if (bdev)
+ release_mem_region(start, len);
+
+err_out_dev:
free_netdev(dev);
err_out:
return ret;
}
+static void __exit dec_lance_remove(struct device *bdev)
+{
+ struct net_device *dev = dev_get_drvdata(bdev);
+ resource_size_t start, len;
+
+ unregister_netdev(dev);
+ start = to_tc_dev(bdev)->resource.start;
+ len = to_tc_dev(bdev)->resource.end - start + 1;
+ release_mem_region(start, len);
+ free_netdev(dev);
+}
/* Find all the lance cards on the system and initialize them */
-static int __init dec_lance_probe(void)
+static int __init dec_lance_platform_probe(void)
{
int count = 0;
- /* Scan slots for PMAD-AA cards first. */
-#ifdef CONFIG_TC
- if (TURBOCHANNEL) {
- int slot;
-
- while ((slot = search_tc_card("PMAD-AA")) >= 0) {
- if (dec_lance_init(PMAD_LANCE, slot) < 0)
- break;
- count++;
- }
- }
-#endif
-
- /* Then handle onboard devices. */
if (dec_interrupt[DEC_IRQ_LANCE] >= 0) {
if (dec_interrupt[DEC_IRQ_LANCE_MERR] >= 0) {
- if (dec_lance_init(ASIC_LANCE, -1) >= 0)
+ if (dec_lance_probe(NULL, ASIC_LANCE) >= 0)
count++;
} else if (!TURBOCHANNEL) {
- if (dec_lance_init(PMAX_LANCE, -1) >= 0)
+ if (dec_lance_probe(NULL, PMAX_LANCE) >= 0)
count++;
}
}
@@ -1304,21 +1325,70 @@ static int __init dec_lance_probe(void)
return (count > 0) ? 0 : -ENODEV;
}
-static void __exit dec_lance_cleanup(void)
+static void __exit dec_lance_platform_remove(void)
{
while (root_lance_dev) {
struct net_device *dev = root_lance_dev;
struct lance_private *lp = netdev_priv(dev);
unregister_netdev(dev);
-#ifdef CONFIG_TC
- if (lp->slot >= 0)
- release_tc_card(lp->slot);
-#endif
root_lance_dev = lp->next;
free_netdev(dev);
}
}
-module_init(dec_lance_probe);
-module_exit(dec_lance_cleanup);
+#ifdef CONFIG_TC
+static int __init dec_lance_tc_probe(struct device *dev);
+static int __exit dec_lance_tc_remove(struct device *dev);
+
+static const struct tc_device_id dec_lance_tc_table[] = {
+ { "DEC ", "PMAD-AA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, dec_lance_tc_table);
+
+static struct tc_driver dec_lance_tc_driver = {
+ .id_table = dec_lance_tc_table,
+ .driver = {
+ .name = "declance",
+ .bus = &tc_bus_type,
+ .probe = dec_lance_tc_probe,
+ .remove = __exit_p(dec_lance_tc_remove),
+ },
+};
+
+static int __init dec_lance_tc_probe(struct device *dev)
+{
+ int status = dec_lance_probe(dev, PMAD_LANCE);
+ if (!status)
+ get_device(dev);
+ return status;
+}
+
+static int __exit dec_lance_tc_remove(struct device *dev)
+{
+ put_device(dev);
+ dec_lance_remove(dev);
+ return 0;
+}
+#endif
+
+static int __init dec_lance_init(void)
+{
+ int status;
+
+ status = tc_register_driver(&dec_lance_tc_driver);
+ if (!status)
+ dec_lance_platform_probe();
+ return status;
+}
+
+static void __exit dec_lance_exit(void)
+{
+ dec_lance_platform_remove();
+ tc_unregister_driver(&dec_lance_tc_driver);
+}
+
+
+module_init(dec_lance_init);
+module_exit(dec_lance_exit);
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index dc3ab3b5c8c..07d2731c1aa 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -10,10 +10,12 @@
*
* Abstract:
* A Linux device driver supporting the Digital Equipment Corporation
- * FDDI EISA and PCI controller families. Supported adapters include:
+ * FDDI TURBOchannel, EISA and PCI controller families. Supported
+ * adapters include:
*
- * DEC FDDIcontroller/EISA (DEFEA)
- * DEC FDDIcontroller/PCI (DEFPA)
+ * DEC FDDIcontroller/TURBOchannel (DEFTA)
+ * DEC FDDIcontroller/EISA (DEFEA)
+ * DEC FDDIcontroller/PCI (DEFPA)
*
* The original author:
* LVS Lawrence V. Stefani <lstefani@yahoo.com>
@@ -193,24 +195,27 @@
* 14 Aug 2004 macro Fix device names reported.
* 14 Jun 2005 macro Use irqreturn_t.
* 23 Oct 2006 macro Big-endian host support.
+ * 14 Dec 2006 macro TURBOchannel support.
*/
/* Include files */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
+#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/eisa.h>
+#include <linux/errno.h>
+#include <linux/fddidevice.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/netdevice.h>
-#include <linux/fddidevice.h>
+#include <linux/pci.h>
#include <linux/skbuff.h>
-#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tc.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -219,8 +224,8 @@
/* Version information string should be updated prior to each new release! */
#define DRV_NAME "defxx"
-#define DRV_VERSION "v1.09"
-#define DRV_RELDATE "2006/10/23"
+#define DRV_VERSION "v1.10"
+#define DRV_RELDATE "2006/12/14"
static char version[] __devinitdata =
DRV_NAME ": " DRV_VERSION " " DRV_RELDATE
@@ -235,12 +240,41 @@ static char version[] __devinitdata =
*/
#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128)
+#define __unused __attribute__ ((unused))
+
+#ifdef CONFIG_PCI
+#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type)
+#else
+#define DFX_BUS_PCI(dev) 0
+#endif
+
+#ifdef CONFIG_EISA
+#define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type)
+#else
+#define DFX_BUS_EISA(dev) 0
+#endif
+
+#ifdef CONFIG_TC
+#define DFX_BUS_TC(dev) (dev->bus == &tc_bus_type)
+#else
+#define DFX_BUS_TC(dev) 0
+#endif
+
+#ifdef CONFIG_DEFXX_MMIO
+#define DFX_MMIO 1
+#else
+#define DFX_MMIO 0
+#endif
+
/* Define module-wide (static) routines */
static void dfx_bus_init(struct net_device *dev);
+static void dfx_bus_uninit(struct net_device *dev);
static void dfx_bus_config_check(DFX_board_t *bp);
-static int dfx_driver_init(struct net_device *dev, const char *print_name);
+static int dfx_driver_init(struct net_device *dev,
+ const char *print_name,
+ resource_size_t bar_start);
static int dfx_adap_init(DFX_board_t *bp, int get_buffers);
static int dfx_open(struct net_device *dev);
@@ -273,13 +307,13 @@ static void dfx_xmt_flush(DFX_board_t *bp);
/* Define module-wide (static) variables */
-static struct net_device *root_dfx_eisa_dev;
+static struct pci_driver dfx_pci_driver;
+static struct eisa_driver dfx_eisa_driver;
+static struct tc_driver dfx_tc_driver;
/*
* =======================
- * = dfx_port_write_byte =
- * = dfx_port_read_byte =
* = dfx_port_write_long =
* = dfx_port_read_long =
* =======================
@@ -291,12 +325,11 @@ static struct net_device *root_dfx_eisa_dev;
* None
*
* Arguments:
- * bp - pointer to board information
- * offset - register offset from base I/O address
- * data - for dfx_port_write_byte and dfx_port_write_long, this
- * is a value to write.
- * for dfx_port_read_byte and dfx_port_read_byte, this
- * is a pointer to store the read value.
+ * bp - pointer to board information
+ * offset - register offset from base I/O address
+ * data - for dfx_port_write_long, this is a value to write;
+ * for dfx_port_read_long, this is a pointer to store
+ * the read value
*
* Functional Description:
* These routines perform the correct operation to read or write
@@ -310,7 +343,7 @@ static struct net_device *root_dfx_eisa_dev;
* registers using the register offsets defined in DEFXX.H.
*
* PCI port block base addresses are assigned by the PCI BIOS or system
- * firmware. There is one 128 byte port block which can be accessed. It
+ * firmware. There is one 128 byte port block which can be accessed. It
* allows for I/O mapping of both PDQ and PFI registers using the register
* offsets defined in DEFXX.H.
*
@@ -318,7 +351,7 @@ static struct net_device *root_dfx_eisa_dev;
* None
*
* Assumptions:
- * bp->base_addr is a valid base I/O address for this adapter.
+ * bp->base is a valid base I/O address for this adapter.
* offset is a valid register offset for this adapter.
*
* Side Effects:
@@ -329,69 +362,135 @@ static struct net_device *root_dfx_eisa_dev;
* advantage of strict data type checking.
*/
-static inline void dfx_port_write_byte(
- DFX_board_t *bp,
- int offset,
- u8 data
- )
+static inline void dfx_writel(DFX_board_t *bp, int offset, u32 data)
+{
+ writel(data, bp->base.mem + offset);
+ mb();
+}
- {
- u16 port = bp->base_addr + offset;
+static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data)
+{
+ outl(data, bp->base.port + offset);
+}
- outb(data, port);
- }
+static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data)
+{
+ struct device __unused *bdev = bp->bus_dev;
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
-static inline void dfx_port_read_byte(
- DFX_board_t *bp,
- int offset,
- u8 *data
- )
+ if (dfx_use_mmio)
+ dfx_writel(bp, offset, data);
+ else
+ dfx_outl(bp, offset, data);
+}
- {
- u16 port = bp->base_addr + offset;
- *data = inb(port);
- }
+static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data)
+{
+ mb();
+ *data = readl(bp->base.mem + offset);
+}
-static inline void dfx_port_write_long(
- DFX_board_t *bp,
- int offset,
- u32 data
- )
+static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data)
+{
+ *data = inl(bp->base.port + offset);
+}
- {
- u16 port = bp->base_addr + offset;
+static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data)
+{
+ struct device __unused *bdev = bp->bus_dev;
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
- outl(data, port);
- }
+ if (dfx_use_mmio)
+ dfx_readl(bp, offset, data);
+ else
+ dfx_inl(bp, offset, data);
+}
-static inline void dfx_port_read_long(
- DFX_board_t *bp,
- int offset,
- u32 *data
- )
- {
- u16 port = bp->base_addr + offset;
+/*
+ * ================
+ * = dfx_get_bars =
+ * ================
+ *
+ * Overview:
+ * Retrieves the address range used to access control and status
+ * registers.
+ *
+ * Returns:
+ * None
+ *
+ * Arguments:
+ * bdev - pointer to device information
+ * bar_start - pointer to store the start address
+ * bar_len - pointer to store the length of the area
+ *
+ * Assumptions:
+ * I am sure there are some.
+ *
+ * Side Effects:
+ * None
+ */
+static void dfx_get_bars(struct device *bdev,
+ resource_size_t *bar_start, resource_size_t *bar_len)
+{
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
- *data = inl(port);
- }
+ if (dfx_bus_pci) {
+ int num = dfx_use_mmio ? 0 : 1;
+ *bar_start = pci_resource_start(to_pci_dev(bdev), num);
+ *bar_len = pci_resource_len(to_pci_dev(bdev), num);
+ }
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
+ resource_size_t bar;
+
+ if (dfx_use_mmio) {
+ bar = inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_2);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_1);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_0);
+ bar <<= 16;
+ *bar_start = bar;
+ bar = inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_2);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_1);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_0);
+ bar <<= 16;
+ *bar_len = (bar | PI_MEM_ADD_MASK_M) + 1;
+ } else {
+ *bar_start = base_addr;
+ *bar_len = PI_ESIC_K_CSR_IO_LEN;
+ }
+ }
+ if (dfx_bus_tc) {
+ *bar_start = to_tc_dev(bdev)->resource.start +
+ PI_TC_K_CSR_OFFSET;
+ *bar_len = PI_TC_K_CSR_LEN;
+ }
+}
/*
- * =============
- * = dfx_init_one_pci_or_eisa =
- * =============
+ * ================
+ * = dfx_register =
+ * ================
*
* Overview:
- * Initializes a supported FDDI EISA or PCI controller
+ * Initializes a supported FDDI controller
*
* Returns:
* Condition code
*
* Arguments:
- * pdev - pointer to pci device information (NULL for EISA)
- * ioaddr - pointer to port (NULL for PCI)
+ * bdev - pointer to device information
*
* Functional Description:
*
@@ -407,56 +506,74 @@ static inline void dfx_port_read_long(
* initialized and the board resources are read and stored in
* the device structure.
*/
-static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
+static int __devinit dfx_register(struct device *bdev)
{
static int version_disp;
- char *print_name = DRV_NAME;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ char *print_name = bdev->bus_id;
struct net_device *dev;
DFX_board_t *bp; /* board pointer */
+ resource_size_t bar_start = 0; /* pointer to port */
+ resource_size_t bar_len = 0; /* resource length */
int alloc_size; /* total buffer size used */
- int err;
+ struct resource *region;
+ int err = 0;
if (!version_disp) { /* display version info if adapter is found */
version_disp = 1; /* set display flag to TRUE so that */
printk(version); /* we only display this string ONCE */
}
- if (pdev != NULL)
- print_name = pci_name(pdev);
-
dev = alloc_fddidev(sizeof(*bp));
if (!dev) {
- printk(KERN_ERR "%s: unable to allocate fddidev, aborting\n",
+ printk(KERN_ERR "%s: Unable to allocate fddidev, aborting\n",
print_name);
return -ENOMEM;
}
/* Enable PCI device. */
- if (pdev != NULL) {
- err = pci_enable_device (pdev);
- if (err) goto err_out;
- ioaddr = pci_resource_start (pdev, 1);
+ if (dfx_bus_pci && pci_enable_device(to_pci_dev(bdev))) {
+ printk(KERN_ERR "%s: Cannot enable PCI device, aborting\n",
+ print_name);
+ goto err_out;
}
SET_MODULE_OWNER(dev);
- if (pdev != NULL)
- SET_NETDEV_DEV(dev, &pdev->dev);
+ SET_NETDEV_DEV(dev, bdev);
+
+ bp = netdev_priv(dev);
+ bp->bus_dev = bdev;
+ dev_set_drvdata(bdev, dev);
- bp = dev->priv;
+ dfx_get_bars(bdev, &bar_start, &bar_len);
- if (!request_region(ioaddr,
- pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN,
- print_name)) {
+ if (dfx_use_mmio)
+ region = request_mem_region(bar_start, bar_len, print_name);
+ else
+ region = request_region(bar_start, bar_len, print_name);
+ if (!region) {
printk(KERN_ERR "%s: Cannot reserve I/O resource "
- "0x%x @ 0x%lx, aborting\n", print_name,
- pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, ioaddr);
+ "0x%lx @ 0x%lx, aborting\n",
+ print_name, (long)bar_len, (long)bar_start);
err = -EBUSY;
- goto err_out;
+ goto err_out_disable;
}
- /* Initialize new device structure */
+ /* Set up I/O base address. */
+ if (dfx_use_mmio) {
+ bp->base.mem = ioremap_nocache(bar_start, bar_len);
+ if (!bp->base.mem) {
+ printk(KERN_ERR "%s: Cannot map MMIO\n", print_name);
+ goto err_out_region;
+ }
+ } else {
+ bp->base.port = bar_start;
+ dev->base_addr = bar_start;
+ }
- dev->base_addr = ioaddr; /* save port (I/O) base address */
+ /* Initialize new device structure */
dev->get_stats = dfx_ctl_get_stats;
dev->open = dfx_open;
@@ -465,22 +582,12 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
dev->set_multicast_list = dfx_ctl_set_multicast_list;
dev->set_mac_address = dfx_ctl_set_mac_address;
- if (pdev == NULL) {
- /* EISA board */
- bp->bus_type = DFX_BUS_TYPE_EISA;
- bp->next = root_dfx_eisa_dev;
- root_dfx_eisa_dev = dev;
- } else {
- /* PCI board */
- bp->bus_type = DFX_BUS_TYPE_PCI;
- bp->pci_dev = pdev;
- pci_set_drvdata (pdev, dev);
- pci_set_master (pdev);
- }
+ if (dfx_bus_pci)
+ pci_set_master(to_pci_dev(bdev));
- if (dfx_driver_init(dev, print_name) != DFX_K_SUCCESS) {
+ if (dfx_driver_init(dev, print_name, bar_start) != DFX_K_SUCCESS) {
err = -ENODEV;
- goto err_out_region;
+ goto err_out_unmap;
}
err = register_netdev(dev);
@@ -499,44 +606,28 @@ err_out_kfree:
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
if (bp->kmalloced)
- pci_free_consistent(pdev, alloc_size,
- bp->kmalloced, bp->kmalloced_dma);
+ dma_free_coherent(bdev, alloc_size,
+ bp->kmalloced, bp->kmalloced_dma);
+
+err_out_unmap:
+ if (dfx_use_mmio)
+ iounmap(bp->base.mem);
+
err_out_region:
- release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN);
+ if (dfx_use_mmio)
+ release_mem_region(bar_start, bar_len);
+ else
+ release_region(bar_start, bar_len);
+
+err_out_disable:
+ if (dfx_bus_pci)
+ pci_disable_device(to_pci_dev(bdev));
+
err_out:
free_netdev(dev);
return err;
}
-static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- return dfx_init_one_pci_or_eisa(pdev, 0);
-}
-
-static int __init dfx_eisa_init(void)
-{
- int rc = -ENODEV;
- int i; /* used in for loops */
- u16 port; /* temporary I/O (port) address */
- u32 slot_id; /* EISA hardware (slot) ID read from adapter */
-
- DBG_printk("In dfx_eisa_init...\n");
-
- /* Scan for FDDI EISA controllers */
-
- for (i=0; i < DFX_MAX_EISA_SLOTS; i++) /* only scan for up to 16 EISA slots */
- {
- port = (i << 12) + PI_ESIC_K_SLOT_ID; /* port = I/O address for reading slot ID */
- slot_id = inl(port); /* read EISA HW (slot) ID */
- if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID)
- {
- port = (i << 12); /* recalc base addr */
-
- if (dfx_init_one_pci_or_eisa(NULL, port) == 0) rc = 0;
- }
- }
- return rc;
-}
/*
* ================
@@ -544,7 +635,7 @@ static int __init dfx_eisa_init(void)
* ================
*
* Overview:
- * Initializes EISA and PCI controller bus-specific logic.
+ * Initializes the bus-specific controller logic.
*
* Returns:
* None
@@ -560,7 +651,7 @@ static int __init dfx_eisa_init(void)
* None
*
* Assumptions:
- * dev->base_addr has already been set with the proper
+ * bp->base has already been set with the proper
* base I/O address for this device.
*
* Side Effects:
@@ -571,87 +662,103 @@ static int __init dfx_eisa_init(void)
static void __devinit dfx_bus_init(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
- u8 val; /* used for I/O read/writes */
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ u8 val;
DBG_printk("In dfx_bus_init...\n");
- /*
- * Initialize base I/O address field in bp structure
- *
- * Note: bp->base_addr is the same as dev->base_addr.
- * It's useful because often we'll need to read
- * or write registers where we already have the
- * bp pointer instead of the dev pointer. Having
- * the base address in the bp structure will
- * save a pointer dereference.
- *
- * IMPORTANT!! This field must be defined before
- * any of the dfx_port_* inline functions are
- * called.
- */
-
- bp->base_addr = dev->base_addr;
-
- /* And a pointer back to the net_device struct */
+ /* Initialize a pointer back to the net_device struct */
bp->dev = dev;
/* Initialize adapter based on bus type */
- if (bp->bus_type == DFX_BUS_TYPE_EISA)
- {
- /* Get the interrupt level from the ESIC chip */
-
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val);
- switch ((val & PI_CONFIG_STAT_0_M_IRQ) >> PI_CONFIG_STAT_0_V_IRQ)
- {
- case PI_CONFIG_STAT_0_IRQ_K_9:
- dev->irq = 9;
- break;
-
- case PI_CONFIG_STAT_0_IRQ_K_10:
- dev->irq = 10;
- break;
+ if (dfx_bus_tc)
+ dev->irq = to_tc_dev(bdev)->interrupt;
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
- case PI_CONFIG_STAT_0_IRQ_K_11:
- dev->irq = 11;
- break;
+ /* Get the interrupt level from the ESIC chip. */
+ val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+ val &= PI_CONFIG_STAT_0_M_IRQ;
+ val >>= PI_CONFIG_STAT_0_V_IRQ;
- case PI_CONFIG_STAT_0_IRQ_K_15:
- dev->irq = 15;
- break;
- }
-
- /* Enable access to I/O on the board by writing 0x03 to Function Control Register */
+ switch (val) {
+ case PI_CONFIG_STAT_0_IRQ_K_9:
+ dev->irq = 9;
+ break;
- dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB);
+ case PI_CONFIG_STAT_0_IRQ_K_10:
+ dev->irq = 10;
+ break;
- /* Set the I/O decode range of the board */
+ case PI_CONFIG_STAT_0_IRQ_K_11:
+ dev->irq = 11;
+ break;
- val = ((dev->base_addr >> 12) << PI_IO_CMP_V_SLOT);
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_0_1, val);
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_1_1, val);
+ case PI_CONFIG_STAT_0_IRQ_K_15:
+ dev->irq = 15;
+ break;
+ }
- /* Enable access to rest of module (including PDQ and packet memory) */
+ /*
+ * Enable memory decoding (MEMCS0) and/or port decoding
+ * (IOCS1/IOCS0) as appropriate in Function Control
+ * Register. One of the port chip selects seems to be
+ * used for the Burst Holdoff register, but this bit of
+ * documentation is missing and as yet it has not been
+ * determined which of the two. This is also the reason
+ * the size of the decoded port range is twice as large
+ * as one required by the PDQ.
+ */
- dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB);
+ /* Set the decode range of the board. */
+ val = ((bp->base.port >> 12) << PI_IO_CMP_V_SLOT);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_1, val);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_0, 0);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_1, val);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_0, 0);
+ val = PI_ESIC_K_CSR_IO_LEN - 1;
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_1, (val >> 8) & 0xff);
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_0, val & 0xff);
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_1, (val >> 8) & 0xff);
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_0, val & 0xff);
+
+ /* Enable the decoders. */
+ val = PI_FUNCTION_CNTRL_M_IOCS1 | PI_FUNCTION_CNTRL_M_IOCS0;
+ if (dfx_use_mmio)
+ val |= PI_FUNCTION_CNTRL_M_MEMCS0;
+ outb(base_addr + PI_ESIC_K_FUNCTION_CNTRL, val);
/*
- * Map PDQ registers into I/O space. This is done by clearing a bit
- * in Burst Holdoff register.
+ * Enable access to the rest of the module
+ * (including PDQ and packet memory).
*/
+ val = PI_SLOT_CNTRL_M_ENB;
+ outb(base_addr + PI_ESIC_K_SLOT_CNTRL, val);
- dfx_port_read_byte(bp, PI_ESIC_K_BURST_HOLDOFF, &val);
- dfx_port_write_byte(bp, PI_ESIC_K_BURST_HOLDOFF, (val & ~PI_BURST_HOLDOFF_M_MEM_MAP));
+ /*
+ * Map PDQ registers into memory or port space. This is
+ * done with a bit in the Burst Holdoff register.
+ */
+ val = inb(base_addr + PI_DEFEA_K_BURST_HOLDOFF);
+ if (dfx_use_mmio)
+ val |= PI_BURST_HOLDOFF_V_MEM_MAP;
+ else
+ val &= ~PI_BURST_HOLDOFF_V_MEM_MAP;
+ outb(base_addr + PI_DEFEA_K_BURST_HOLDOFF, val);
/* Enable interrupts at EISA bus interface chip (ESIC) */
-
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val);
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, (val | PI_CONFIG_STAT_0_M_INT_ENB));
- }
- else
- {
- struct pci_dev *pdev = bp->pci_dev;
+ val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+ val |= PI_CONFIG_STAT_0_M_INT_ENB;
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val);
+ }
+ if (dfx_bus_pci) {
+ struct pci_dev *pdev = to_pci_dev(bdev);
/* Get the interrupt level from the PCI Configuration Table */
@@ -660,17 +767,70 @@ static void __devinit dfx_bus_init(struct net_device *dev)
/* Check Latency Timer and set if less than minimal */
pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &val);
- if (val < PFI_K_LAT_TIMER_MIN) /* if less than min, override with default */
- {
+ if (val < PFI_K_LAT_TIMER_MIN) {
val = PFI_K_LAT_TIMER_DEF;
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, val);
- }
+ }
/* Enable interrupts at PCI bus interface chip (PFI) */
+ val = PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB;
+ dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, val);
+ }
+}
- dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB));
- }
+/*
+ * ==================
+ * = dfx_bus_uninit =
+ * ==================
+ *
+ * Overview:
+ * Uninitializes the bus-specific controller logic.
+ *
+ * Returns:
+ * None
+ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+ * Functional Description:
+ * Perform bus-specific logic uninitialization.
+ *
+ * Return Codes:
+ * None
+ *
+ * Assumptions:
+ * bp->base has already been set with the proper
+ * base I/O address for this device.
+ *
+ * Side Effects:
+ * Interrupts are disabled at the adapter bus-specific logic.
+ */
+
+static void __devinit dfx_bus_uninit(struct net_device *dev)
+{
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ u8 val;
+
+ DBG_printk("In dfx_bus_uninit...\n");
+
+ /* Uninitialize adapter based on bus type */
+
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
+
+ /* Disable interrupts at EISA bus interface chip (ESIC) */
+ val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+ val &= ~PI_CONFIG_STAT_0_M_INT_ENB;
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val);
+ }
+ if (dfx_bus_pci) {
+ /* Disable interrupts at PCI bus interface chip (PFI) */
+ dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 0);
}
+}
/*
@@ -705,18 +865,16 @@ static void __devinit dfx_bus_init(struct net_device *dev)
static void __devinit dfx_bus_config_check(DFX_board_t *bp)
{
+ struct device __unused *bdev = bp->bus_dev;
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
int status; /* return code from adapter port control call */
- u32 slot_id; /* EISA-bus hardware id (DEC3001, DEC3002,...) */
u32 host_data; /* LW data returned from port control call */
DBG_printk("In dfx_bus_config_check...\n");
/* Configuration check only valid for EISA adapter */
- if (bp->bus_type == DFX_BUS_TYPE_EISA)
- {
- dfx_port_read_long(bp, PI_ESIC_K_SLOT_ID, &slot_id);
-
+ if (dfx_bus_eisa) {
/*
* First check if revision 2 EISA controller. Rev. 1 cards used
* PDQ revision B, so no workaround needed in this case. Rev. 3
@@ -724,14 +882,11 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp)
* case, either. Only Rev. 2 cards used either Rev. D or E
* chips, so we must verify the chip revision on Rev. 2 cards.
*/
-
- if (slot_id == DEFEA_PROD_ID_2)
- {
+ if (to_eisa_device(bdev)->id.driver_data == DEFEA_PROD_ID_2) {
/*
- * Revision 2 FDDI EISA controller found, so let's check PDQ
- * revision of adapter.
+ * Revision 2 FDDI EISA controller found,
+ * so let's check PDQ revision of adapter.
*/
-
status = dfx_hw_port_ctrl_req(bp,
PI_PCTRL_M_SUB_CMD,
PI_SUB_CMD_K_PDQ_REV_GET,
@@ -805,13 +960,20 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp)
*/
static int __devinit dfx_driver_init(struct net_device *dev,
- const char *print_name)
+ const char *print_name,
+ resource_size_t bar_start)
{
- DFX_board_t *bp = dev->priv;
- int alloc_size; /* total buffer size needed */
- char *top_v, *curr_v; /* virtual addrs into memory block */
- dma_addr_t top_p, curr_p; /* physical addrs into memory block */
- u32 data; /* host data register value */
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ int alloc_size; /* total buffer size needed */
+ char *top_v, *curr_v; /* virtual addrs into memory block */
+ dma_addr_t top_p, curr_p; /* physical addrs into memory block */
+ u32 data, le32; /* host data register value */
+ char *board_name = NULL;
DBG_printk("In dfx_driver_init...\n");
@@ -860,8 +1022,8 @@ static int __devinit dfx_driver_init(struct net_device *dev,
print_name);
return(DFX_K_FAILURE);
}
- data = cpu_to_le32(data);
- memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32));
+ le32 = cpu_to_le32(data);
+ memcpy(&bp->factory_mac_addr[0], &le32, sizeof(u32));
if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0,
&data) != DFX_K_SUCCESS) {
@@ -869,8 +1031,8 @@ static int __devinit dfx_driver_init(struct net_device *dev,
print_name);
return(DFX_K_FAILURE);
}
- data = cpu_to_le32(data);
- memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16));
+ le32 = cpu_to_le32(data);
+ memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16));
/*
* Set current address to factory address
@@ -880,20 +1042,18 @@ static int __devinit dfx_driver_init(struct net_device *dev,
*/
memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN);
- if (bp->bus_type == DFX_BUS_TYPE_EISA)
- printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, "
- "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
- print_name, dev->base_addr, dev->irq,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]);
- else
- printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, "
- "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
- print_name, dev->base_addr, dev->irq,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]);
+ if (dfx_bus_tc)
+ board_name = "DEFTA";
+ if (dfx_bus_eisa)
+ board_name = "DEFEA";
+ if (dfx_bus_pci)
+ board_name = "DEFPA";
+ pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, "
+ "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
+ print_name, board_name, dfx_use_mmio ? "" : "I/O ",
+ (long long)bar_start, dev->irq,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
/*
* Get memory for descriptor block, consumer block, and other buffers
@@ -908,8 +1068,9 @@ static int __devinit dfx_driver_init(struct net_device *dev,
#endif
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
- bp->kmalloced = top_v = pci_alloc_consistent(bp->pci_dev, alloc_size,
- &bp->kmalloced_dma);
+ bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size,
+ &bp->kmalloced_dma,
+ GFP_ATOMIC);
if (top_v == NULL) {
printk("%s: Could not allocate memory for host buffers "
"and structures!\n", print_name);
@@ -1219,14 +1380,15 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
static int dfx_open(struct net_device *dev)
{
+ DFX_board_t *bp = netdev_priv(dev);
int ret;
- DFX_board_t *bp = dev->priv;
DBG_printk("In dfx_open...\n");
/* Register IRQ - support shared interrupts by passing device ptr */
- ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, dev);
+ ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name,
+ dev);
if (ret) {
printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
return ret;
@@ -1309,7 +1471,7 @@ static int dfx_open(struct net_device *dev)
static int dfx_close(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
DBG_printk("In dfx_close...\n");
@@ -1645,7 +1807,7 @@ static void dfx_int_type_0_process(DFX_board_t *bp)
static void dfx_int_common(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
PI_UINT32 port_status; /* Port Status register */
/* Process xmt interrupts - frequent case, so always call this routine */
@@ -1715,18 +1877,16 @@ static void dfx_int_common(struct net_device *dev)
static irqreturn_t dfx_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = dev_id;
- DFX_board_t *bp; /* private board structure pointer */
-
- /* Get board pointer only if device structure is valid */
-
- bp = dev->priv;
-
- /* See if we're already servicing an interrupt */
+ struct net_device *dev = dev_id;
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
/* Service adapter interrupts */
- if (bp->bus_type == DFX_BUS_TYPE_PCI) {
+ if (dfx_bus_pci) {
u32 status;
dfx_port_read_long(bp, PFI_K_REG_STATUS, &status);
@@ -1750,10 +1910,12 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id)
PFI_MODE_M_DMA_ENB));
spin_unlock(&bp->lock);
- } else {
+ }
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
u8 status;
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+ status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
if (!(status & PI_CONFIG_STAT_0_M_PEND))
return IRQ_NONE;
@@ -1761,15 +1923,35 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id)
/* Disable interrupts at the ESIC */
status &= ~PI_CONFIG_STAT_0_M_INT_ENB;
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status);
/* Call interrupt service routine for this adapter */
dfx_int_common(dev);
/* Reenable interrupts at the ESIC */
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+ status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
status |= PI_CONFIG_STAT_0_M_INT_ENB;
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status);
+
+ spin_unlock(&bp->lock);
+ }
+ if (dfx_bus_tc) {
+ u32 status;
+
+ dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &status);
+ if (!(status & (PI_PSTATUS_M_RCV_DATA_PENDING |
+ PI_PSTATUS_M_XMT_DATA_PENDING |
+ PI_PSTATUS_M_SMT_HOST_PENDING |
+ PI_PSTATUS_M_UNSOL_PENDING |
+ PI_PSTATUS_M_CMD_RSP_PENDING |
+ PI_PSTATUS_M_CMD_REQ_PENDING |
+ PI_PSTATUS_M_TYPE_0_PENDING)))
+ return IRQ_NONE;
+
+ spin_lock(&bp->lock);
+
+ /* Call interrupt service routine for this adapter */
+ dfx_int_common(dev);
spin_unlock(&bp->lock);
}
@@ -1823,7 +2005,7 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id)
static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
/* Fill the bp->stats structure with driver-maintained counters */
@@ -2009,8 +2191,8 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
*/
static void dfx_ctl_set_multicast_list(struct net_device *dev)
- {
- DFX_board_t *bp = dev->priv;
+{
+ DFX_board_t *bp = netdev_priv(dev);
int i; /* used as index in for loop */
struct dev_mc_list *dmi; /* ptr to multicast addr entry */
@@ -2124,8 +2306,8 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev)
static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr)
{
- DFX_board_t *bp = dev->priv;
struct sockaddr *p_sockaddr = (struct sockaddr *)addr;
+ DFX_board_t *bp = netdev_priv(dev);
/* Copy unicast address to driver-maintained structs and update count */
@@ -2764,9 +2946,9 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers)
my_skb_align(newskb, 128);
bp->descr_block_virt->rcv_data[i + j].long_1 =
- (u32)pci_map_single(bp->pci_dev, newskb->data,
+ (u32)dma_map_single(bp->bus_dev, newskb->data,
NEW_SKB_SIZE,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
/*
* p_rcv_buff_va is only used inside the
* kernel so we put the skb pointer here.
@@ -2880,17 +3062,17 @@ static void dfx_rcv_queue_process(
my_skb_align(newskb, 128);
skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
- pci_unmap_single(bp->pci_dev,
+ dma_unmap_single(bp->bus_dev,
bp->descr_block_virt->rcv_data[entry].long_1,
NEW_SKB_SIZE,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
skb_reserve(skb, RCV_BUFF_K_PADDING);
bp->p_rcv_buff_va[entry] = (char *)newskb;
bp->descr_block_virt->rcv_data[entry].long_1 =
- (u32)pci_map_single(bp->pci_dev,
+ (u32)dma_map_single(bp->bus_dev,
newskb->data,
NEW_SKB_SIZE,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
} else
skb = NULL;
} else
@@ -3010,7 +3192,7 @@ static int dfx_xmt_queue_pkt(
)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
u8 prod; /* local transmit producer index */
PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */
XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */
@@ -3116,8 +3298,8 @@ static int dfx_xmt_queue_pkt(
*/
p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN));
- p_xmt_descr->long_1 = (u32)pci_map_single(bp->pci_dev, skb->data,
- skb->len, PCI_DMA_TODEVICE);
+ p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
/*
* Verify that descriptor is actually available
@@ -3220,10 +3402,10 @@ static int dfx_xmt_done(DFX_board_t *bp)
/* Return skb to operating system */
comp = bp->rcv_xmt_reg.index.xmt_comp;
- pci_unmap_single(bp->pci_dev,
+ dma_unmap_single(bp->bus_dev,
bp->descr_block_virt->xmt_data[comp].long_1,
p_xmt_drv_descr->p_skb->len,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
dev_kfree_skb_irq(p_xmt_drv_descr->p_skb);
/*
@@ -3344,10 +3526,10 @@ static void dfx_xmt_flush( DFX_board_t *bp )
/* Return skb to operating system */
comp = bp->rcv_xmt_reg.index.xmt_comp;
- pci_unmap_single(bp->pci_dev,
+ dma_unmap_single(bp->bus_dev,
bp->descr_block_virt->xmt_data[comp].long_1,
p_xmt_drv_descr->p_skb->len,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
dev_kfree_skb(p_xmt_drv_descr->p_skb);
/* Increment transmit error counter */
@@ -3375,13 +3557,44 @@ static void dfx_xmt_flush( DFX_board_t *bp )
bp->cons_block_virt->xmt_rcv_data = prod_cons;
}
-static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev)
+/*
+ * ==================
+ * = dfx_unregister =
+ * ==================
+ *
+ * Overview:
+ * Shuts down an FDDI controller
+ *
+ * Returns:
+ * Condition code
+ *
+ * Arguments:
+ * bdev - pointer to device information
+ *
+ * Functional Description:
+ *
+ * Return Codes:
+ * None
+ *
+ * Assumptions:
+ * It compiles so it should work :-( (PCI cards do :-)
+ *
+ * Side Effects:
+ * Device structures for FDDI adapters (fddi0, fddi1, etc) are
+ * freed.
+ */
+static void __devexit dfx_unregister(struct device *bdev)
{
- DFX_board_t *bp = dev->priv;
+ struct net_device *dev = dev_get_drvdata(bdev);
+ DFX_board_t *bp = netdev_priv(dev);
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ resource_size_t bar_start = 0; /* pointer to port */
+ resource_size_t bar_len = 0; /* resource length */
int alloc_size; /* total buffer size used */
unregister_netdev(dev);
- release_region(dev->base_addr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN );
alloc_size = sizeof(PI_DESCR_BLOCK) +
PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX +
@@ -3391,78 +3604,141 @@ static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct ne
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
if (bp->kmalloced)
- pci_free_consistent(pdev, alloc_size, bp->kmalloced,
- bp->kmalloced_dma);
+ dma_free_coherent(bdev, alloc_size,
+ bp->kmalloced, bp->kmalloced_dma);
+
+ dfx_bus_uninit(dev);
+
+ dfx_get_bars(bdev, &bar_start, &bar_len);
+ if (dfx_use_mmio) {
+ iounmap(bp->base.mem);
+ release_mem_region(bar_start, bar_len);
+ } else
+ release_region(bar_start, bar_len);
+
+ if (dfx_bus_pci)
+ pci_disable_device(to_pci_dev(bdev));
+
free_netdev(dev);
}
-static void __devexit dfx_remove_one (struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- dfx_remove_one_pci_or_eisa(pdev, dev);
- pci_set_drvdata(pdev, NULL);
-}
+static int __devinit __unused dfx_dev_register(struct device *);
+static int __devexit __unused dfx_dev_unregister(struct device *);
-static struct pci_device_id dfx_pci_tbl[] = {
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, }
+#ifdef CONFIG_PCI
+static int __devinit dfx_pci_register(struct pci_dev *,
+ const struct pci_device_id *);
+static void __devexit dfx_pci_unregister(struct pci_dev *);
+
+static struct pci_device_id dfx_pci_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) },
+ { }
};
-MODULE_DEVICE_TABLE(pci, dfx_pci_tbl);
+MODULE_DEVICE_TABLE(pci, dfx_pci_table);
-static struct pci_driver dfx_driver = {
+static struct pci_driver dfx_pci_driver = {
.name = "defxx",
- .probe = dfx_init_one,
- .remove = __devexit_p(dfx_remove_one),
- .id_table = dfx_pci_tbl,
+ .id_table = dfx_pci_table,
+ .probe = dfx_pci_register,
+ .remove = __devexit_p(dfx_pci_unregister),
};
-static int dfx_have_pci;
-static int dfx_have_eisa;
-
+static __devinit int dfx_pci_register(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ return dfx_register(&pdev->dev);
+}
-static void __exit dfx_eisa_cleanup(void)
+static void __devexit dfx_pci_unregister(struct pci_dev *pdev)
{
- struct net_device *dev = root_dfx_eisa_dev;
+ dfx_unregister(&pdev->dev);
+}
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_EISA
+static struct eisa_device_id dfx_eisa_table[] = {
+ { "DEC3001", DEFEA_PROD_ID_1 },
+ { "DEC3002", DEFEA_PROD_ID_2 },
+ { "DEC3003", DEFEA_PROD_ID_3 },
+ { "DEC3004", DEFEA_PROD_ID_4 },
+ { }
+};
+MODULE_DEVICE_TABLE(eisa, dfx_eisa_table);
+
+static struct eisa_driver dfx_eisa_driver = {
+ .id_table = dfx_eisa_table,
+ .driver = {
+ .name = "defxx",
+ .bus = &eisa_bus_type,
+ .probe = dfx_dev_register,
+ .remove = __devexit_p(dfx_dev_unregister),
+ },
+};
+#endif /* CONFIG_EISA */
+
+#ifdef CONFIG_TC
+static struct tc_device_id const dfx_tc_table[] = {
+ { "DEC ", "PMAF-FA " },
+ { "DEC ", "PMAF-FD " },
+ { "DEC ", "PMAF-FS " },
+ { "DEC ", "PMAF-FU " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, dfx_tc_table);
+
+static struct tc_driver dfx_tc_driver = {
+ .id_table = dfx_tc_table,
+ .driver = {
+ .name = "defxx",
+ .bus = &tc_bus_type,
+ .probe = dfx_dev_register,
+ .remove = __devexit_p(dfx_dev_unregister),
+ },
+};
+#endif /* CONFIG_TC */
- while (dev)
- {
- struct net_device *tmp;
- DFX_board_t *bp;
+static int __devinit __unused dfx_dev_register(struct device *dev)
+{
+ int status;
- bp = (DFX_board_t*)dev->priv;
- tmp = bp->next;
- dfx_remove_one_pci_or_eisa(NULL, dev);
- dev = tmp;
- }
+ status = dfx_register(dev);
+ if (!status)
+ get_device(dev);
+ return status;
}
-static int __init dfx_init(void)
+static int __devexit __unused dfx_dev_unregister(struct device *dev)
{
- int rc_pci, rc_eisa;
-
- rc_pci = pci_register_driver(&dfx_driver);
- if (rc_pci >= 0) dfx_have_pci = 1;
+ put_device(dev);
+ dfx_unregister(dev);
+ return 0;
+}
- rc_eisa = dfx_eisa_init();
- if (rc_eisa >= 0) dfx_have_eisa = 1;
- return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci);
+static int __devinit dfx_init(void)
+{
+ int status;
+
+ status = pci_register_driver(&dfx_pci_driver);
+ if (!status)
+ status = eisa_driver_register(&dfx_eisa_driver);
+ if (!status)
+ status = tc_register_driver(&dfx_tc_driver);
+ return status;
}
-static void __exit dfx_cleanup(void)
+static void __devexit dfx_cleanup(void)
{
- if (dfx_have_pci)
- pci_unregister_driver(&dfx_driver);
- if (dfx_have_eisa)
- dfx_eisa_cleanup();
-
+ tc_unregister_driver(&dfx_tc_driver);
+ eisa_driver_unregister(&dfx_eisa_driver);
+ pci_unregister_driver(&dfx_pci_driver);
}
module_init(dfx_init);
module_exit(dfx_cleanup);
MODULE_AUTHOR("Lawrence V. Stefani");
-MODULE_DESCRIPTION("DEC FDDIcontroller EISA/PCI (DEFEA/DEFPA) driver "
+MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver "
DRV_VERSION " " DRV_RELDATE);
MODULE_LICENSE("GPL");
diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h
index 2ce8f97253e..19a6f64df19 100644
--- a/drivers/net/defxx.h
+++ b/drivers/net/defxx.h
@@ -26,6 +26,7 @@
* 12-Sep-96 LVS Removed packet request header pointers.
* 04 Aug 2003 macro Converted to the DMA API.
* 23 Oct 2006 macro Big-endian host support.
+ * 14 Dec 2006 macro TURBOchannel support.
*/
#ifndef _DEFXX_H_
@@ -1471,9 +1472,17 @@ typedef union
#endif /* __BIG_ENDIAN */
+/* Define TC PDQ CSR offset and length */
+
+#define PI_TC_K_CSR_OFFSET 0x100000
+#define PI_TC_K_CSR_LEN 0x40 /* 64 bytes */
+
/* Define EISA controller register offsets */
-#define PI_ESIC_K_BURST_HOLDOFF 0x040
+#define PI_ESIC_K_CSR_IO_LEN 0x80 /* 128 bytes */
+
+#define PI_DEFEA_K_BURST_HOLDOFF 0x040
+
#define PI_ESIC_K_SLOT_ID 0xC80
#define PI_ESIC_K_SLOT_CNTRL 0xC84
#define PI_ESIC_K_MEM_ADD_CMP_0 0xC85
@@ -1488,14 +1497,14 @@ typedef union
#define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E
#define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F
#define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90
-#define PI_ESIC_K_IO_CMP_0_0 0xC91
-#define PI_ESIC_K_IO_CMP_0_1 0xC92
-#define PI_ESIC_K_IO_CMP_1_0 0xC93
-#define PI_ESIC_K_IO_CMP_1_1 0xC94
-#define PI_ESIC_K_IO_CMP_2_0 0xC95
-#define PI_ESIC_K_IO_CMP_2_1 0xC96
-#define PI_ESIC_K_IO_CMP_3_0 0xC97
-#define PI_ESIC_K_IO_CMP_3_1 0xC98
+#define PI_ESIC_K_IO_ADD_CMP_0_0 0xC91
+#define PI_ESIC_K_IO_ADD_CMP_0_1 0xC92
+#define PI_ESIC_K_IO_ADD_CMP_1_0 0xC93
+#define PI_ESIC_K_IO_ADD_CMP_1_1 0xC94
+#define PI_ESIC_K_IO_ADD_CMP_2_0 0xC95
+#define PI_ESIC_K_IO_ADD_CMP_2_1 0xC96
+#define PI_ESIC_K_IO_ADD_CMP_3_0 0xC97
+#define PI_ESIC_K_IO_ADD_CMP_3_1 0xC98
#define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99
#define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A
#define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B
@@ -1518,11 +1527,16 @@ typedef union
#define PI_ESIC_K_INPUT_PORT 0xCAC
#define PI_ESIC_K_OUTPUT_PORT 0xCAD
#define PI_ESIC_K_FUNCTION_CNTRL 0xCAE
-#define PI_ESIC_K_CSR_IO_LEN PI_ESIC_K_FUNCTION_CNTRL+1 /* always last reg + 1 */
-/* Define the value all drivers must write to the function control register. */
+/* Define the bits in the function control register. */
-#define PI_ESIC_K_FUNCTION_CNTRL_IO_ENB 0x03
+#define PI_FUNCTION_CNTRL_M_IOCS0 0x01
+#define PI_FUNCTION_CNTRL_M_IOCS1 0x02
+#define PI_FUNCTION_CNTRL_M_IOCS2 0x04
+#define PI_FUNCTION_CNTRL_M_IOCS3 0x08
+#define PI_FUNCTION_CNTRL_M_MEMCS0 0x10
+#define PI_FUNCTION_CNTRL_M_MEMCS1 0x20
+#define PI_FUNCTION_CNTRL_M_DMA 0x80
/* Define the bits in the slot control register. */
@@ -1540,6 +1554,10 @@ typedef union
#define PI_BURST_HOLDOFF_V_RESERVED 1
#define PI_BURST_HOLDOFF_V_MEM_MAP 0
+/* Define the implicit mask of the Memory Address Mask Register. */
+
+#define PI_MEM_ADD_MASK_M 0x3ff
+
/*
* Define the fields in the IO Compare registers.
* The driver must initialize the slot field with the slot ID shifted by the
@@ -1577,6 +1595,7 @@ typedef union
#define DEFEA_PROD_ID_1 0x0130A310 /* DEC product 300, rev 1 */
#define DEFEA_PROD_ID_2 0x0230A310 /* DEC product 300, rev 2 */
#define DEFEA_PROD_ID_3 0x0330A310 /* DEC product 300, rev 3 */
+#define DEFEA_PROD_ID_4 0x0430A310 /* DEC product 300, rev 4 */
/**********************************************/
/* Digital PFI Specification v1.0 Definitions */
@@ -1633,12 +1652,6 @@ typedef union
#define PFI_STATUS_V_FIFO_EMPTY 1
#define PFI_STATUS_V_DMA_IN_PROGRESS 0
-#define DFX_MAX_EISA_SLOTS 16 /* maximum number of EISA slots to scan */
-#define DFX_MAX_NUM_BOARDS 8 /* maximum number of adapters supported */
-
-#define DFX_BUS_TYPE_PCI 0 /* type code for DEC FDDIcontroller/PCI */
-#define DFX_BUS_TYPE_EISA 1 /* type code for DEC FDDIcontroller/EISA */
-
#define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */
#define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */
#define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */
@@ -1756,10 +1769,11 @@ typedef struct DFX_board_tag
/* Store device, bus-specific, and parameter information for this adapter */
struct net_device *dev; /* pointer to device structure */
- struct net_device *next;
- u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */
- u16 base_addr; /* base I/O address (same as dev->base_addr) */
- struct pci_dev * pci_dev;
+ union {
+ void __iomem *mem;
+ int port;
+ } base; /* base address */
+ struct device *bus_dev;
u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */
u32 req_ttrt; /* requested TTRT value (in 80ns units) */
u32 burst_size; /* adapter burst size (enumerated) */
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 03bf164f9e8..0cefef5e3f0 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1930,9 +1930,8 @@ static int e100_rx_alloc_list(struct nic *nic)
nic->rx_to_use = nic->rx_to_clean = NULL;
nic->ru_running = RU_UNINITIALIZED;
- if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))
+ if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC)))
return -ENOMEM;
- memset(nic->rxs, 0, sizeof(struct rx) * count);
for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
rx->next = (i + 1 < count) ? rx + 1 : nic->rxs;
@@ -2719,12 +2718,11 @@ 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);
-#ifdef CONFIG_E100_NAPI
if (netif_running(netdev))
netif_poll_disable(nic->netdev);
-#endif
del_timer_sync(&nic->watchdog);
netif_carrier_off(nic->netdev);
+ netif_device_detach(netdev);
pci_save_state(pdev);
@@ -2737,6 +2735,7 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
}
pci_disable_device(pdev);
+ free_irq(pdev->irq, netdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
@@ -2760,16 +2759,13 @@ static int e100_resume(struct pci_dev *pdev)
}
#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);
-#ifdef CONFIG_E100_NAPI
if (netif_running(netdev))
netif_poll_disable(nic->netdev);
-#endif
del_timer_sync(&nic->watchdog);
netif_carrier_off(nic->netdev);
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index f091042b146..689f158a469 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -59,17 +59,13 @@
#include <linux/capability.h>
#include <linux/in.h>
#include <linux/ip.h>
-#ifdef NETIF_F_TSO6
#include <linux/ipv6.h>
-#endif
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <linux/reboot.h>
-#ifdef NETIF_F_TSO
#include <net/checksum.h>
-#endif
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
@@ -257,7 +253,6 @@ struct e1000_adapter {
spinlock_t tx_queue_lock;
#endif
atomic_t irq_sem;
- unsigned int detect_link;
unsigned int total_tx_bytes;
unsigned int total_tx_packets;
unsigned int total_rx_bytes;
@@ -348,9 +343,7 @@ struct e1000_adapter {
boolean_t have_msi;
#endif
/* to not mess up cache alignment, always add to the bottom */
-#ifdef NETIF_F_TSO
boolean_t tso_force;
-#endif
boolean_t smart_power_down; /* phy smart power down */
boolean_t quad_port_a;
unsigned long flags;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index da459f7177c..44ebc72962d 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -100,6 +100,9 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
{ "rx_csum_offload_errors", E1000_STAT(hw_csum_err) },
{ "rx_header_split", E1000_STAT(rx_hdr_split) },
{ "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) },
+ { "tx_smbus", E1000_STAT(stats.mgptc) },
+ { "rx_smbus", E1000_STAT(stats.mgprc) },
+ { "dropped_smbus", E1000_STAT(stats.mgpdc) },
};
#define E1000_QUEUE_STATS_LEN 0
@@ -335,7 +338,6 @@ e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
return 0;
}
-#ifdef NETIF_F_TSO
static int
e1000_set_tso(struct net_device *netdev, uint32_t data)
{
@@ -349,18 +351,15 @@ e1000_set_tso(struct net_device *netdev, uint32_t data)
else
netdev->features &= ~NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
if (data)
netdev->features |= NETIF_F_TSO6;
else
netdev->features &= ~NETIF_F_TSO6;
-#endif
DPRINTK(PROBE, INFO, "TSO is %s\n", data ? "Enabled" : "Disabled");
adapter->tso_force = TRUE;
return 0;
}
-#endif /* NETIF_F_TSO */
static uint32_t
e1000_get_msglevel(struct net_device *netdev)
@@ -1968,10 +1967,8 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.set_tx_csum = e1000_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = e1000_set_tso,
-#endif
.self_test_count = e1000_diag_test_count,
.self_test = e1000_diag_test,
.get_strings = e1000_get_strings,
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 3655d902b0b..9be44699300 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -308,141 +308,160 @@ e1000_phy_init_script(struct e1000_hw *hw)
int32_t
e1000_set_mac_type(struct e1000_hw *hw)
{
- DEBUGFUNC("e1000_set_mac_type");
-
- switch (hw->device_id) {
- case E1000_DEV_ID_82542:
- switch (hw->revision_id) {
- case E1000_82542_2_0_REV_ID:
- hw->mac_type = e1000_82542_rev2_0;
- break;
- case E1000_82542_2_1_REV_ID:
- hw->mac_type = e1000_82542_rev2_1;
- break;
- default:
- /* Invalid 82542 revision ID */
- return -E1000_ERR_MAC_TYPE;
- }
- break;
- case E1000_DEV_ID_82543GC_FIBER:
- case E1000_DEV_ID_82543GC_COPPER:
- hw->mac_type = e1000_82543;
- break;
- case E1000_DEV_ID_82544EI_COPPER:
- case E1000_DEV_ID_82544EI_FIBER:
- case E1000_DEV_ID_82544GC_COPPER:
- case E1000_DEV_ID_82544GC_LOM:
- hw->mac_type = e1000_82544;
- break;
- case E1000_DEV_ID_82540EM:
- case E1000_DEV_ID_82540EM_LOM:
- case E1000_DEV_ID_82540EP:
- case E1000_DEV_ID_82540EP_LOM:
- case E1000_DEV_ID_82540EP_LP:
- hw->mac_type = e1000_82540;
- break;
- case E1000_DEV_ID_82545EM_COPPER:
- case E1000_DEV_ID_82545EM_FIBER:
- hw->mac_type = e1000_82545;
- break;
- case E1000_DEV_ID_82545GM_COPPER:
- case E1000_DEV_ID_82545GM_FIBER:
- case E1000_DEV_ID_82545GM_SERDES:
- hw->mac_type = e1000_82545_rev_3;
- break;
- case E1000_DEV_ID_82546EB_COPPER:
- case E1000_DEV_ID_82546EB_FIBER:
- case E1000_DEV_ID_82546EB_QUAD_COPPER:
- hw->mac_type = e1000_82546;
- break;
- case E1000_DEV_ID_82546GB_COPPER:
- case E1000_DEV_ID_82546GB_FIBER:
- case E1000_DEV_ID_82546GB_SERDES:
- case E1000_DEV_ID_82546GB_PCIE:
- case E1000_DEV_ID_82546GB_QUAD_COPPER:
- case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
- hw->mac_type = e1000_82546_rev_3;
- break;
- case E1000_DEV_ID_82541EI:
- case E1000_DEV_ID_82541EI_MOBILE:
- case E1000_DEV_ID_82541ER_LOM:
- hw->mac_type = e1000_82541;
- break;
- case E1000_DEV_ID_82541ER:
- case E1000_DEV_ID_82541GI:
- case E1000_DEV_ID_82541GI_LF:
- case E1000_DEV_ID_82541GI_MOBILE:
- hw->mac_type = e1000_82541_rev_2;
- break;
- case E1000_DEV_ID_82547EI:
- case E1000_DEV_ID_82547EI_MOBILE:
- hw->mac_type = e1000_82547;
- break;
- case E1000_DEV_ID_82547GI:
- hw->mac_type = e1000_82547_rev_2;
- break;
- case E1000_DEV_ID_82571EB_COPPER:
- case E1000_DEV_ID_82571EB_FIBER:
- case E1000_DEV_ID_82571EB_SERDES:
- case E1000_DEV_ID_82571EB_QUAD_COPPER:
- case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
- hw->mac_type = e1000_82571;
- break;
- case E1000_DEV_ID_82572EI_COPPER:
- case E1000_DEV_ID_82572EI_FIBER:
- case E1000_DEV_ID_82572EI_SERDES:
- case E1000_DEV_ID_82572EI:
- hw->mac_type = e1000_82572;
- break;
- case E1000_DEV_ID_82573E:
- case E1000_DEV_ID_82573E_IAMT:
- case E1000_DEV_ID_82573L:
- hw->mac_type = e1000_82573;
- break;
- case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
- case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
- case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
- case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
- hw->mac_type = e1000_80003es2lan;
- break;
- case E1000_DEV_ID_ICH8_IGP_M_AMT:
- case E1000_DEV_ID_ICH8_IGP_AMT:
- case E1000_DEV_ID_ICH8_IGP_C:
- case E1000_DEV_ID_ICH8_IFE:
- case E1000_DEV_ID_ICH8_IFE_GT:
- case E1000_DEV_ID_ICH8_IFE_G:
- case E1000_DEV_ID_ICH8_IGP_M:
- hw->mac_type = e1000_ich8lan;
- break;
- default:
- /* Should never have loaded on this device */
- return -E1000_ERR_MAC_TYPE;
- }
-
- switch (hw->mac_type) {
- case e1000_ich8lan:
- hw->swfwhw_semaphore_present = TRUE;
- hw->asf_firmware_present = TRUE;
- break;
- case e1000_80003es2lan:
- hw->swfw_sync_present = TRUE;
- /* fall through */
- case e1000_82571:
- case e1000_82572:
- case e1000_82573:
- hw->eeprom_semaphore_present = TRUE;
- /* fall through */
- case e1000_82541:
- case e1000_82547:
- case e1000_82541_rev_2:
- case e1000_82547_rev_2:
- hw->asf_firmware_present = TRUE;
- break;
- default:
- break;
- }
-
- return E1000_SUCCESS;
+ DEBUGFUNC("e1000_set_mac_type");
+
+ switch (hw->device_id) {
+ case E1000_DEV_ID_82542:
+ switch (hw->revision_id) {
+ case E1000_82542_2_0_REV_ID:
+ hw->mac_type = e1000_82542_rev2_0;
+ break;
+ case E1000_82542_2_1_REV_ID:
+ hw->mac_type = e1000_82542_rev2_1;
+ break;
+ default:
+ /* Invalid 82542 revision ID */
+ return -E1000_ERR_MAC_TYPE;
+ }
+ break;
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ hw->mac_type = e1000_82543;
+ break;
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ hw->mac_type = e1000_82544;
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ case E1000_DEV_ID_82540EP:
+ case E1000_DEV_ID_82540EP_LOM:
+ case E1000_DEV_ID_82540EP_LP:
+ hw->mac_type = e1000_82540;
+ break;
+ case E1000_DEV_ID_82545EM_COPPER:
+ case E1000_DEV_ID_82545EM_FIBER:
+ hw->mac_type = e1000_82545;
+ break;
+ case E1000_DEV_ID_82545GM_COPPER:
+ case E1000_DEV_ID_82545GM_FIBER:
+ case E1000_DEV_ID_82545GM_SERDES:
+ hw->mac_type = e1000_82545_rev_3;
+ break;
+ case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82546EB_FIBER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
+ hw->mac_type = e1000_82546;
+ break;
+ case E1000_DEV_ID_82546GB_COPPER:
+ case E1000_DEV_ID_82546GB_FIBER:
+ case E1000_DEV_ID_82546GB_SERDES:
+ case E1000_DEV_ID_82546GB_PCIE:
+ case E1000_DEV_ID_82546GB_QUAD_COPPER:
+ case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+ hw->mac_type = e1000_82546_rev_3;
+ break;
+ case E1000_DEV_ID_82541EI:
+ case E1000_DEV_ID_82541EI_MOBILE:
+ case E1000_DEV_ID_82541ER_LOM:
+ hw->mac_type = e1000_82541;
+ break;
+ case E1000_DEV_ID_82541ER:
+ case E1000_DEV_ID_82541GI:
+ case E1000_DEV_ID_82541GI_LF:
+ case E1000_DEV_ID_82541GI_MOBILE:
+ hw->mac_type = e1000_82541_rev_2;
+ break;
+ case E1000_DEV_ID_82547EI:
+ case E1000_DEV_ID_82547EI_MOBILE:
+ hw->mac_type = e1000_82547;
+ break;
+ case E1000_DEV_ID_82547GI:
+ hw->mac_type = e1000_82547_rev_2;
+ break;
+ case E1000_DEV_ID_82571EB_COPPER:
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
+ hw->mac_type = e1000_82571;
+ break;
+ case E1000_DEV_ID_82572EI_COPPER:
+ case E1000_DEV_ID_82572EI_FIBER:
+ case E1000_DEV_ID_82572EI_SERDES:
+ case E1000_DEV_ID_82572EI:
+ hw->mac_type = e1000_82572;
+ break;
+ case E1000_DEV_ID_82573E:
+ case E1000_DEV_ID_82573E_IAMT:
+ case E1000_DEV_ID_82573L:
+ hw->mac_type = e1000_82573;
+ break;
+ case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
+ case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ hw->mac_type = e1000_80003es2lan;
+ break;
+ case E1000_DEV_ID_ICH8_IGP_M_AMT:
+ case E1000_DEV_ID_ICH8_IGP_AMT:
+ case E1000_DEV_ID_ICH8_IGP_C:
+ case E1000_DEV_ID_ICH8_IFE:
+ case E1000_DEV_ID_ICH8_IFE_GT:
+ case E1000_DEV_ID_ICH8_IFE_G:
+ case E1000_DEV_ID_ICH8_IGP_M:
+ hw->mac_type = e1000_ich8lan;
+ break;
+ default:
+ /* Should never have loaded on this device */
+ return -E1000_ERR_MAC_TYPE;
+ }
+
+ switch (hw->mac_type) {
+ case e1000_ich8lan:
+ hw->swfwhw_semaphore_present = TRUE;
+ hw->asf_firmware_present = TRUE;
+ break;
+ case e1000_80003es2lan:
+ hw->swfw_sync_present = TRUE;
+ /* fall through */
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_82573:
+ hw->eeprom_semaphore_present = TRUE;
+ /* fall through */
+ case e1000_82541:
+ case e1000_82547:
+ case e1000_82541_rev_2:
+ case e1000_82547_rev_2:
+ hw->asf_firmware_present = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ /* The 82543 chip does not count tx_carrier_errors properly in
+ * FD mode
+ */
+ if (hw->mac_type == e1000_82543)
+ hw->bad_tx_carr_stats_fd = TRUE;
+
+ /* capable of receiving management packets to the host */
+ if (hw->mac_type >= e1000_82571)
+ hw->has_manc2h = TRUE;
+
+ /* In rare occasions, ESB2 systems would end up started without
+ * the RX unit being turned on.
+ */
+ if (hw->mac_type == e1000_80003es2lan)
+ hw->rx_needs_kicking = TRUE;
+
+ if (hw->mac_type > e1000_82544)
+ hw->has_smbus = TRUE;
+
+ return E1000_SUCCESS;
}
/*****************************************************************************
@@ -6575,7 +6594,7 @@ e1000_get_bus_info(struct e1000_hw *hw)
switch (hw->mac_type) {
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
- hw->bus_type = e1000_bus_type_unknown;
+ hw->bus_type = e1000_bus_type_pci;
hw->bus_speed = e1000_bus_speed_unknown;
hw->bus_width = e1000_bus_width_unknown;
break;
@@ -7817,9 +7836,8 @@ e1000_enable_mng_pass_thru(struct e1000_hw *hw)
fwsm = E1000_READ_REG(hw, FWSM);
factps = E1000_READ_REG(hw, FACTPS);
- if (((fwsm & E1000_FWSM_MODE_MASK) ==
- (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)) &&
- (factps & E1000_FACTPS_MNGCG))
+ if ((((fwsm & E1000_FWSM_MODE_MASK) >> E1000_FWSM_MODE_SHIFT) ==
+ e1000_mng_mode_pt) && !(factps & E1000_FACTPS_MNGCG))
return TRUE;
} else
if ((manc & E1000_MANC_SMBUS_EN) && !(manc & E1000_MANC_ASF_EN))
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 3321fb13bfa..d6710588334 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -1301,165 +1301,170 @@ struct e1000_ffvt_entry {
#define E1000_82542_RSSIR E1000_RSSIR
#define E1000_82542_KUMCTRLSTA E1000_KUMCTRLSTA
#define E1000_82542_SW_FW_SYNC E1000_SW_FW_SYNC
+#define E1000_82542_MANC2H E1000_MANC2H
/* Statistics counters collected by the MAC */
struct e1000_hw_stats {
- uint64_t crcerrs;
- uint64_t algnerrc;
- uint64_t symerrs;
- uint64_t rxerrc;
- uint64_t txerrc;
- uint64_t mpc;
- uint64_t scc;
- uint64_t ecol;
- uint64_t mcc;
- uint64_t latecol;
- uint64_t colc;
- uint64_t dc;
- uint64_t tncrs;
- uint64_t sec;
- uint64_t cexterr;
- uint64_t rlec;
- uint64_t xonrxc;
- uint64_t xontxc;
- uint64_t xoffrxc;
- uint64_t xofftxc;
- uint64_t fcruc;
- uint64_t prc64;
- uint64_t prc127;
- uint64_t prc255;
- uint64_t prc511;
- uint64_t prc1023;
- uint64_t prc1522;
- uint64_t gprc;
- uint64_t bprc;
- uint64_t mprc;
- uint64_t gptc;
- uint64_t gorcl;
- uint64_t gorch;
- uint64_t gotcl;
- uint64_t gotch;
- uint64_t rnbc;
- uint64_t ruc;
- uint64_t rfc;
- uint64_t roc;
- uint64_t rlerrc;
- uint64_t rjc;
- uint64_t mgprc;
- uint64_t mgpdc;
- uint64_t mgptc;
- uint64_t torl;
- uint64_t torh;
- uint64_t totl;
- uint64_t toth;
- uint64_t tpr;
- uint64_t tpt;
- uint64_t ptc64;
- uint64_t ptc127;
- uint64_t ptc255;
- uint64_t ptc511;
- uint64_t ptc1023;
- uint64_t ptc1522;
- uint64_t mptc;
- uint64_t bptc;
- uint64_t tsctc;
- uint64_t tsctfc;
- uint64_t iac;
- uint64_t icrxptc;
- uint64_t icrxatc;
- uint64_t ictxptc;
- uint64_t ictxatc;
- uint64_t ictxqec;
- uint64_t ictxqmtc;
- uint64_t icrxdmtc;
- uint64_t icrxoc;
+ uint64_t crcerrs;
+ uint64_t algnerrc;
+ uint64_t symerrs;
+ uint64_t rxerrc;
+ uint64_t txerrc;
+ uint64_t mpc;
+ uint64_t scc;
+ uint64_t ecol;
+ uint64_t mcc;
+ uint64_t latecol;
+ uint64_t colc;
+ uint64_t dc;
+ uint64_t tncrs;
+ uint64_t sec;
+ uint64_t cexterr;
+ uint64_t rlec;
+ uint64_t xonrxc;
+ uint64_t xontxc;
+ uint64_t xoffrxc;
+ uint64_t xofftxc;
+ uint64_t fcruc;
+ uint64_t prc64;
+ uint64_t prc127;
+ uint64_t prc255;
+ uint64_t prc511;
+ uint64_t prc1023;
+ uint64_t prc1522;
+ uint64_t gprc;
+ uint64_t bprc;
+ uint64_t mprc;
+ uint64_t gptc;
+ uint64_t gorcl;
+ uint64_t gorch;
+ uint64_t gotcl;
+ uint64_t gotch;
+ uint64_t rnbc;
+ uint64_t ruc;
+ uint64_t rfc;
+ uint64_t roc;
+ uint64_t rlerrc;
+ uint64_t rjc;
+ uint64_t mgprc;
+ uint64_t mgpdc;
+ uint64_t mgptc;
+ uint64_t torl;
+ uint64_t torh;
+ uint64_t totl;
+ uint64_t toth;
+ uint64_t tpr;
+ uint64_t tpt;
+ uint64_t ptc64;
+ uint64_t ptc127;
+ uint64_t ptc255;
+ uint64_t ptc511;
+ uint64_t ptc1023;
+ uint64_t ptc1522;
+ uint64_t mptc;
+ uint64_t bptc;
+ uint64_t tsctc;
+ uint64_t tsctfc;
+ uint64_t iac;
+ uint64_t icrxptc;
+ uint64_t icrxatc;
+ uint64_t ictxptc;
+ uint64_t ictxatc;
+ uint64_t ictxqec;
+ uint64_t ictxqmtc;
+ uint64_t icrxdmtc;
+ uint64_t icrxoc;
};
/* Structure containing variables used by the shared code (e1000_hw.c) */
struct e1000_hw {
- 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;
- e1000_media_type media_type;
- void *back;
- struct e1000_shadow_ram *eeprom_shadow_ram;
- uint32_t flash_bank_size;
- uint32_t flash_base_addr;
- e1000_fc_type fc;
- e1000_bus_speed bus_speed;
- e1000_bus_width bus_width;
- e1000_bus_type bus_type;
- struct e1000_eeprom_info eeprom;
- e1000_ms_type master_slave;
- e1000_ms_type original_master_slave;
- e1000_ffe_config ffe_config_state;
- uint32_t asf_firmware_present;
- uint32_t eeprom_semaphore_present;
- uint32_t swfw_sync_present;
- uint32_t swfwhw_semaphore_present;
- unsigned long io_base;
- uint32_t phy_id;
- uint32_t phy_revision;
- uint32_t phy_addr;
- uint32_t original_fc;
- uint32_t txcw;
- uint32_t autoneg_failed;
- uint32_t max_frame_size;
- uint32_t min_frame_size;
- uint32_t mc_filter_type;
- uint32_t num_mc_addrs;
- uint32_t collision_delta;
- uint32_t tx_packet_delta;
- uint32_t ledctl_default;
- uint32_t ledctl_mode1;
- uint32_t ledctl_mode2;
- boolean_t tx_pkt_filtering;
- struct e1000_host_mng_dhcp_cookie mng_cookie;
- uint16_t phy_spd_default;
- uint16_t autoneg_advertised;
- uint16_t pci_cmd_word;
- uint16_t fc_high_water;
- uint16_t fc_low_water;
- uint16_t fc_pause_time;
- uint16_t current_ifs_val;
- uint16_t ifs_min_val;
- uint16_t ifs_max_val;
- uint16_t ifs_step_size;
- uint16_t ifs_ratio;
- uint16_t device_id;
- uint16_t vendor_id;
- uint16_t subsystem_id;
- uint16_t subsystem_vendor_id;
- uint8_t revision_id;
- uint8_t autoneg;
- uint8_t mdix;
- uint8_t forced_speed_duplex;
- uint8_t wait_autoneg_complete;
- uint8_t dma_fairness;
- uint8_t mac_addr[NODE_ADDRESS_SIZE];
- uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
- boolean_t disable_polarity_correction;
- boolean_t speed_downgraded;
- e1000_smart_speed smart_speed;
- e1000_dsp_config dsp_config_state;
- boolean_t get_link_status;
- boolean_t serdes_link_down;
- boolean_t tbi_compatibility_en;
- 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;
- boolean_t adaptive_ifs;
- boolean_t ifs_params_forced;
- boolean_t in_ifs_mode;
- boolean_t mng_reg_access_disabled;
- boolean_t leave_av_bit_off;
- boolean_t kmrn_lock_loss_workaround_disabled;
+ 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;
+ e1000_media_type media_type;
+ void *back;
+ struct e1000_shadow_ram *eeprom_shadow_ram;
+ uint32_t flash_bank_size;
+ uint32_t flash_base_addr;
+ e1000_fc_type fc;
+ e1000_bus_speed bus_speed;
+ e1000_bus_width bus_width;
+ e1000_bus_type bus_type;
+ struct e1000_eeprom_info eeprom;
+ e1000_ms_type master_slave;
+ e1000_ms_type original_master_slave;
+ e1000_ffe_config ffe_config_state;
+ uint32_t asf_firmware_present;
+ uint32_t eeprom_semaphore_present;
+ uint32_t swfw_sync_present;
+ uint32_t swfwhw_semaphore_present;
+ unsigned long io_base;
+ uint32_t phy_id;
+ uint32_t phy_revision;
+ uint32_t phy_addr;
+ uint32_t original_fc;
+ uint32_t txcw;
+ uint32_t autoneg_failed;
+ uint32_t max_frame_size;
+ uint32_t min_frame_size;
+ uint32_t mc_filter_type;
+ uint32_t num_mc_addrs;
+ uint32_t collision_delta;
+ uint32_t tx_packet_delta;
+ uint32_t ledctl_default;
+ uint32_t ledctl_mode1;
+ uint32_t ledctl_mode2;
+ boolean_t tx_pkt_filtering;
+ struct e1000_host_mng_dhcp_cookie mng_cookie;
+ uint16_t phy_spd_default;
+ uint16_t autoneg_advertised;
+ uint16_t pci_cmd_word;
+ uint16_t fc_high_water;
+ uint16_t fc_low_water;
+ uint16_t fc_pause_time;
+ uint16_t current_ifs_val;
+ uint16_t ifs_min_val;
+ uint16_t ifs_max_val;
+ uint16_t ifs_step_size;
+ uint16_t ifs_ratio;
+ uint16_t device_id;
+ uint16_t vendor_id;
+ uint16_t subsystem_id;
+ uint16_t subsystem_vendor_id;
+ uint8_t revision_id;
+ uint8_t autoneg;
+ uint8_t mdix;
+ uint8_t forced_speed_duplex;
+ uint8_t wait_autoneg_complete;
+ uint8_t dma_fairness;
+ uint8_t mac_addr[NODE_ADDRESS_SIZE];
+ uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
+ boolean_t disable_polarity_correction;
+ boolean_t speed_downgraded;
+ e1000_smart_speed smart_speed;
+ e1000_dsp_config dsp_config_state;
+ boolean_t get_link_status;
+ boolean_t serdes_link_down;
+ boolean_t tbi_compatibility_en;
+ 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;
+ boolean_t adaptive_ifs;
+ boolean_t ifs_params_forced;
+ boolean_t in_ifs_mode;
+ boolean_t mng_reg_access_disabled;
+ boolean_t leave_av_bit_off;
+ boolean_t kmrn_lock_loss_workaround_disabled;
+ boolean_t bad_tx_carr_stats_fd;
+ boolean_t has_manc2h;
+ boolean_t rx_needs_kicking;
+ boolean_t has_smbus;
};
@@ -2418,6 +2423,7 @@ struct e1000_host_command_info {
#define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */
#define E1000_PBA_12K 0x000C /* 12KB, default Rx allocation */
#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */
+#define E1000_PBA_20K 0x0014
#define E1000_PBA_22K 0x0016
#define E1000_PBA_24K 0x0018
#define E1000_PBA_30K 0x001E
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 73f3a85fd23..619c89218b4 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -36,7 +36,7 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "7.3.15-k2"DRIVERNAPI
+#define DRV_VERSION "7.3.20-k2"DRIVERNAPI
char e1000_driver_version[] = DRV_VERSION;
static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
@@ -213,6 +213,12 @@ static void e1000_netpoll (struct net_device *netdev);
extern void e1000_check_options(struct e1000_adapter *adapter);
+#define COPYBREAK_DEFAULT 256
+static unsigned int copybreak __read_mostly = COPYBREAK_DEFAULT;
+module_param(copybreak, uint, 0644);
+MODULE_PARM_DESC(copybreak,
+ "Maximum size of packet that is copied to a new buffer on receive");
+
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);
@@ -264,7 +270,13 @@ e1000_init_module(void)
printk(KERN_INFO "%s\n", e1000_copyright);
ret = pci_register_driver(&e1000_driver);
-
+ if (copybreak != COPYBREAK_DEFAULT) {
+ if (copybreak == 0)
+ printk(KERN_INFO "e1000: copybreak disabled\n");
+ else
+ printk(KERN_INFO "e1000: copybreak enabled for "
+ "packets <= %u bytes\n", copybreak);
+ }
return ret;
}
@@ -464,6 +476,52 @@ e1000_get_hw_control(struct e1000_adapter *adapter)
}
}
+static void
+e1000_init_manageability(struct e1000_adapter *adapter)
+{
+ if (adapter->en_mng_pt) {
+ uint32_t manc = E1000_READ_REG(&adapter->hw, MANC);
+
+ /* disable hardware interception of ARP */
+ manc &= ~(E1000_MANC_ARP_EN);
+
+ /* enable receiving management packets to the host */
+ /* this will probably generate destination unreachable messages
+ * from the host OS, but the packets will be handled on SMBUS */
+ if (adapter->hw.has_manc2h) {
+ uint32_t manc2h = E1000_READ_REG(&adapter->hw, MANC2H);
+
+ manc |= E1000_MANC_EN_MNG2HOST;
+#define E1000_MNG2HOST_PORT_623 (1 << 5)
+#define E1000_MNG2HOST_PORT_664 (1 << 6)
+ manc2h |= E1000_MNG2HOST_PORT_623;
+ manc2h |= E1000_MNG2HOST_PORT_664;
+ E1000_WRITE_REG(&adapter->hw, MANC2H, manc2h);
+ }
+
+ E1000_WRITE_REG(&adapter->hw, MANC, manc);
+ }
+}
+
+static void
+e1000_release_manageability(struct e1000_adapter *adapter)
+{
+ if (adapter->en_mng_pt) {
+ uint32_t manc = E1000_READ_REG(&adapter->hw, MANC);
+
+ /* re-enable hardware interception of ARP */
+ manc |= E1000_MANC_ARP_EN;
+
+ if (adapter->hw.has_manc2h)
+ manc &= ~E1000_MANC_EN_MNG2HOST;
+
+ /* don't explicitly have to mess with MANC2H since
+ * MANC has an enable disable that gates MANC2H */
+
+ E1000_WRITE_REG(&adapter->hw, MANC, manc);
+ }
+}
+
int
e1000_up(struct e1000_adapter *adapter)
{
@@ -475,6 +533,7 @@ e1000_up(struct e1000_adapter *adapter)
e1000_set_multi(netdev);
e1000_restore_vlan(adapter);
+ e1000_init_manageability(adapter);
e1000_configure_tx(adapter);
e1000_setup_rctl(adapter);
@@ -497,7 +556,8 @@ e1000_up(struct e1000_adapter *adapter)
clear_bit(__E1000_DOWN, &adapter->flags);
- mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+ /* fire a link change interrupt to start the watchdog */
+ E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_LSC);
return 0;
}
@@ -614,16 +674,34 @@ e1000_reinit_locked(struct e1000_adapter *adapter)
void
e1000_reset(struct e1000_adapter *adapter)
{
- uint32_t pba, manc;
+ uint32_t pba = 0, tx_space, min_tx_space, min_rx_space;
uint16_t fc_high_water_mark = E1000_FC_HIGH_DIFF;
+ boolean_t legacy_pba_adjust = FALSE;
/* Repartition Pba for greater than 9k mtu
* To take effect CTRL.RST is required.
*/
switch (adapter->hw.mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ case e1000_82543:
+ case e1000_82544:
+ case e1000_82540:
+ case e1000_82541:
+ case e1000_82541_rev_2:
+ legacy_pba_adjust = TRUE;
+ pba = E1000_PBA_48K;
+ break;
+ case e1000_82545:
+ case e1000_82545_rev_3:
+ case e1000_82546:
+ case e1000_82546_rev_3:
+ pba = E1000_PBA_48K;
+ break;
case e1000_82547:
case e1000_82547_rev_2:
+ legacy_pba_adjust = TRUE;
pba = E1000_PBA_30K;
break;
case e1000_82571:
@@ -632,27 +710,80 @@ e1000_reset(struct e1000_adapter *adapter)
pba = E1000_PBA_38K;
break;
case e1000_82573:
- pba = E1000_PBA_12K;
+ pba = E1000_PBA_20K;
break;
case e1000_ich8lan:
pba = E1000_PBA_8K;
- break;
- default:
- pba = E1000_PBA_48K;
+ case e1000_undefined:
+ case e1000_num_macs:
break;
}
- if ((adapter->hw.mac_type != e1000_82573) &&
- (adapter->netdev->mtu > E1000_RXBUFFER_8192))
- pba -= 8; /* allocate more FIFO for Tx */
+ if (legacy_pba_adjust == TRUE) {
+ if (adapter->netdev->mtu > E1000_RXBUFFER_8192)
+ pba -= 8; /* allocate more FIFO for Tx */
+ if (adapter->hw.mac_type == e1000_82547) {
+ adapter->tx_fifo_head = 0;
+ adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT;
+ adapter->tx_fifo_size =
+ (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT;
+ atomic_set(&adapter->tx_fifo_stall, 0);
+ }
+ } else if (adapter->hw.max_frame_size > MAXIMUM_ETHERNET_FRAME_SIZE) {
+ /* adjust PBA for jumbo frames */
+ E1000_WRITE_REG(&adapter->hw, PBA, pba);
+
+ /* To maintain wire speed transmits, the Tx FIFO should be
+ * large enough to accomodate two full transmit packets,
+ * rounded up to the next 1KB and expressed in KB. Likewise,
+ * the Rx FIFO should be large enough to accomodate at least
+ * one full receive packet and is similarly rounded up and
+ * expressed in KB. */
+ pba = E1000_READ_REG(&adapter->hw, PBA);
+ /* upper 16 bits has Tx packet buffer allocation size in KB */
+ tx_space = pba >> 16;
+ /* lower 16 bits has Rx packet buffer allocation size in KB */
+ pba &= 0xffff;
+ /* don't include ethernet FCS because hardware appends/strips */
+ min_rx_space = adapter->netdev->mtu + ENET_HEADER_SIZE +
+ VLAN_TAG_SIZE;
+ min_tx_space = min_rx_space;
+ min_tx_space *= 2;
+ E1000_ROUNDUP(min_tx_space, 1024);
+ min_tx_space >>= 10;
+ E1000_ROUNDUP(min_rx_space, 1024);
+ min_rx_space >>= 10;
+
+ /* If current Tx allocation is less than the min Tx FIFO size,
+ * and the min Tx FIFO size is less than the current Rx FIFO
+ * allocation, take space away from current Rx allocation */
+ if (tx_space < min_tx_space &&
+ ((min_tx_space - tx_space) < pba)) {
+ pba = pba - (min_tx_space - tx_space);
+
+ /* PCI/PCIx hardware has PBA alignment constraints */
+ switch (adapter->hw.mac_type) {
+ case e1000_82545 ... e1000_82546_rev_3:
+ pba &= ~(E1000_PBA_8K - 1);
+ break;
+ default:
+ break;
+ }
- if (adapter->hw.mac_type == e1000_82547) {
- adapter->tx_fifo_head = 0;
- adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT;
- adapter->tx_fifo_size =
- (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT;
- atomic_set(&adapter->tx_fifo_stall, 0);
+ /* if short on rx space, rx wins and must trump tx
+ * adjustment or use Early Receive if available */
+ if (pba < min_rx_space) {
+ switch (adapter->hw.mac_type) {
+ case e1000_82573:
+ /* ERT enabled in e1000_configure_rx */
+ break;
+ default:
+ pba = min_rx_space;
+ break;
+ }
+ }
+ }
}
E1000_WRITE_REG(&adapter->hw, PBA, pba);
@@ -685,6 +816,20 @@ e1000_reset(struct e1000_adapter *adapter)
if (e1000_init_hw(&adapter->hw))
DPRINTK(PROBE, ERR, "Hardware Error\n");
e1000_update_mng_vlan(adapter);
+
+ /* if (adapter->hwflags & HWFLAGS_PHY_PWR_BIT) { */
+ if (adapter->hw.mac_type >= e1000_82544 &&
+ adapter->hw.mac_type <= e1000_82547_rev_2 &&
+ adapter->hw.autoneg == 1 &&
+ adapter->hw.autoneg_advertised == ADVERTISE_1000_FULL) {
+ uint32_t ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+ /* clear phy power management bit if we are in gig only mode,
+ * which if enabled will attempt negotiation to 100Mb, which
+ * can cause a loss of link at power off or driver unload */
+ ctrl &= ~E1000_CTRL_SWDPIN3;
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+ }
+
/* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE);
@@ -705,14 +850,7 @@ e1000_reset(struct e1000_adapter *adapter)
phy_data);
}
- if ((adapter->en_mng_pt) &&
- (adapter->hw.mac_type >= e1000_82540) &&
- (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 | E1000_MANC_EN_MNG2HOST);
- E1000_WRITE_REG(&adapter->hw, MANC, manc);
- }
+ e1000_release_manageability(adapter);
}
/**
@@ -852,16 +990,12 @@ e1000_probe(struct pci_dev *pdev,
netdev->features &= ~NETIF_F_HW_VLAN_FILTER;
}
-#ifdef NETIF_F_TSO
if ((adapter->hw.mac_type >= e1000_82544) &&
(adapter->hw.mac_type != e1000_82547))
netdev->features |= NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
if (adapter->hw.mac_type > e1000_82547_rev_2)
netdev->features |= NETIF_F_TSO6;
-#endif
-#endif
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
@@ -1078,22 +1212,13 @@ e1000_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
- uint32_t manc;
#ifdef CONFIG_E1000_NAPI
int i;
#endif
flush_scheduled_work();
- if (adapter->hw.mac_type >= e1000_82540 &&
- 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) {
- manc |= E1000_MANC_ARP_EN;
- E1000_WRITE_REG(&adapter->hw, MANC, manc);
- }
- }
+ e1000_release_manageability(adapter);
/* Release control of h/w to f/w. If f/w is AMT enabled, this
* would have already happened in close and is redundant. */
@@ -1531,9 +1656,9 @@ e1000_configure_tx(struct e1000_adapter *adapter)
}
/* Set the default values for the Tx Inter Packet Gap timer */
-
- if (hw->media_type == e1000_media_type_fiber ||
- hw->media_type == e1000_media_type_internal_serdes)
+ if (adapter->hw.mac_type <= e1000_82547_rev_2 &&
+ (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes))
tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
else
tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
@@ -2454,15 +2579,22 @@ e1000_watchdog(unsigned long data)
if (link) {
if (!netif_carrier_ok(netdev)) {
+ uint32_t ctrl;
boolean_t txb2b = 1;
e1000_get_speed_and_duplex(&adapter->hw,
&adapter->link_speed,
&adapter->link_duplex);
- DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s\n",
- adapter->link_speed,
- adapter->link_duplex == FULL_DUPLEX ?
- "Full Duplex" : "Half Duplex");
+ ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+ DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s, "
+ "Flow Control: %s\n",
+ adapter->link_speed,
+ adapter->link_duplex == FULL_DUPLEX ?
+ "Full Duplex" : "Half Duplex",
+ ((ctrl & E1000_CTRL_TFCE) && (ctrl &
+ E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl &
+ E1000_CTRL_RFCE) ? "RX" : ((ctrl &
+ E1000_CTRL_TFCE) ? "TX" : "None" )));
/* tweak tx_queue_len according to speed/duplex
* and adjust the timeout factor */
@@ -2490,7 +2622,6 @@ e1000_watchdog(unsigned long data)
E1000_WRITE_REG(&adapter->hw, TARC0, tarc0);
}
-#ifdef NETIF_F_TSO
/* disable TSO for pcie and 10/100 speeds, to avoid
* some hardware issues */
if (!adapter->tso_force &&
@@ -2501,22 +2632,17 @@ e1000_watchdog(unsigned long data)
DPRINTK(PROBE,INFO,
"10/100 speed: disabling TSO\n");
netdev->features &= ~NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
netdev->features &= ~NETIF_F_TSO6;
-#endif
break;
case SPEED_1000:
netdev->features |= NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
netdev->features |= NETIF_F_TSO6;
-#endif
break;
default:
/* oops */
break;
}
}
-#endif
/* enable transmits in the hardware, need to do this
* after setting TARC0 */
@@ -2528,6 +2654,13 @@ e1000_watchdog(unsigned long data)
netif_wake_queue(netdev);
mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
adapter->smartspeed = 0;
+ } else {
+ /* make sure the receive unit is started */
+ if (adapter->hw.rx_needs_kicking) {
+ struct e1000_hw *hw = &adapter->hw;
+ uint32_t rctl = E1000_READ_REG(hw, RCTL);
+ E1000_WRITE_REG(hw, RCTL, rctl | E1000_RCTL_EN);
+ }
}
} else {
if (netif_carrier_ok(netdev)) {
@@ -2628,29 +2761,34 @@ static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
if (packets == 0)
goto update_itr_done;
-
switch (itr_setting) {
case lowest_latency:
- if ((packets < 5) && (bytes > 512))
+ /* jumbo frames get bulk treatment*/
+ if (bytes/packets > 8000)
+ retval = bulk_latency;
+ else if ((packets < 5) && (bytes > 512))
retval = low_latency;
break;
case low_latency: /* 50 usec aka 20000 ints/s */
if (bytes > 10000) {
- if ((packets < 10) ||
- ((bytes/packets) > 1200))
+ /* jumbo frames need bulk latency setting */
+ if (bytes/packets > 8000)
+ retval = bulk_latency;
+ else if ((packets < 10) || ((bytes/packets) > 1200))
retval = bulk_latency;
else if ((packets > 35))
retval = lowest_latency;
- } else if (packets <= 2 && bytes < 512)
+ } else if (bytes/packets > 2000)
+ retval = bulk_latency;
+ else if (packets <= 2 && bytes < 512)
retval = lowest_latency;
break;
case bulk_latency: /* 250 usec aka 4000 ints/s */
if (bytes > 25000) {
if (packets > 35)
retval = low_latency;
- } else {
- if (bytes < 6000)
- retval = low_latency;
+ } else if (bytes < 6000) {
+ retval = low_latency;
}
break;
}
@@ -2679,17 +2817,20 @@ static void e1000_set_itr(struct e1000_adapter *adapter)
adapter->tx_itr,
adapter->total_tx_packets,
adapter->total_tx_bytes);
+ /* conservative mode (itr 3) eliminates the lowest_latency setting */
+ if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency)
+ adapter->tx_itr = low_latency;
+
adapter->rx_itr = e1000_update_itr(adapter,
adapter->rx_itr,
adapter->total_rx_packets,
adapter->total_rx_bytes);
+ /* conservative mode (itr 3) eliminates the lowest_latency setting */
+ if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
+ adapter->rx_itr = low_latency;
current_itr = max(adapter->rx_itr, adapter->tx_itr);
- /* conservative mode eliminates the lowest_latency setting */
- if (current_itr == lowest_latency && (adapter->itr_setting == 3))
- current_itr = low_latency;
-
switch (current_itr) {
/* counts and packets in update_itr are dependent on these numbers */
case lowest_latency:
@@ -2731,7 +2872,6 @@ static int
e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
struct sk_buff *skb)
{
-#ifdef NETIF_F_TSO
struct e1000_context_desc *context_desc;
struct e1000_buffer *buffer_info;
unsigned int i;
@@ -2760,7 +2900,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
0);
cmd_length = E1000_TXD_CMD_IP;
ipcse = skb->h.raw - skb->data - 1;
-#ifdef NETIF_F_TSO6
} else if (skb->protocol == htons(ETH_P_IPV6)) {
skb->nh.ipv6h->payload_len = 0;
skb->h.th->check =
@@ -2770,7 +2909,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
IPPROTO_TCP,
0);
ipcse = 0;
-#endif
}
ipcss = skb->nh.raw - skb->data;
ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data;
@@ -2803,8 +2941,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
return TRUE;
}
-#endif
-
return FALSE;
}
@@ -2824,8 +2960,9 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
buffer_info = &tx_ring->buffer_info[i];
context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+ context_desc->lower_setup.ip_config = 0;
context_desc->upper_setup.tcp_fields.tucss = css;
- context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset;
+ context_desc->upper_setup.tcp_fields.tucso = css + skb->csum;
context_desc->upper_setup.tcp_fields.tucse = 0;
context_desc->tcp_seg_setup.data = 0;
context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
@@ -2861,7 +2998,6 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
while (len) {
buffer_info = &tx_ring->buffer_info[i];
size = min(len, max_per_txd);
-#ifdef NETIF_F_TSO
/* Workaround for Controller erratum --
* descriptor for non-tso packet in a linear SKB that follows a
* tso gets written back prematurely before the data is fully
@@ -2876,7 +3012,6 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
* in TSO mode. Append 4-byte sentinel desc */
if (unlikely(mss && !nr_frags && size == len && size > 8))
size -= 4;
-#endif
/* work-around for errata 10 and it applies
* to all controllers in PCI-X mode
* The fix is to make sure that the first descriptor of a
@@ -2918,12 +3053,10 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
while (len) {
buffer_info = &tx_ring->buffer_info[i];
size = min(len, max_per_txd);
-#ifdef NETIF_F_TSO
/* Workaround for premature desc write-backs
* in TSO mode. Append 4-byte sentinel desc */
if (unlikely(mss && f == (nr_frags-1) && size == len && size > 8))
size -= 4;
-#endif
/* Workaround for potential 82544 hang in PCI-X.
* Avoid terminating buffers within evenly-aligned
* dwords. */
@@ -3148,7 +3281,6 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (adapter->hw.mac_type >= e1000_82571)
max_per_txd = 8192;
-#ifdef NETIF_F_TSO
mss = skb_shinfo(skb)->gso_size;
/* The controller does a simple calculation to
* make sure there is enough room in the FIFO before
@@ -3168,6 +3300,16 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) {
switch (adapter->hw.mac_type) {
unsigned int pull_size;
+ case e1000_82544:
+ /* Make sure we have room to chop off 4 bytes,
+ * and that the end alignment will work out to
+ * this hardware's requirements
+ * NOTE: this is a TSO only workaround
+ * if end byte alignment not correct move us
+ * into the next dword */
+ if ((unsigned long)(skb->tail - 1) & 4)
+ break;
+ /* fall through */
case e1000_82571:
case e1000_82572:
case e1000_82573:
@@ -3192,16 +3334,10 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL))
count++;
count++;
-#else
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- count++;
-#endif
-#ifdef NETIF_F_TSO
/* Controller Erratum workaround */
if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb))
count++;
-#endif
count += TXD_USE_COUNT(len, max_txd_pwr);
@@ -3419,12 +3555,11 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
netdev->mtu = new_mtu;
+ adapter->hw.max_frame_size = max_frame;
if (netif_running(netdev))
e1000_reinit_locked(adapter);
- adapter->hw.max_frame_size = max_frame;
-
return 0;
}
@@ -3449,7 +3584,7 @@ e1000_update_stats(struct e1000_adapter *adapter)
*/
if (adapter->link_speed == 0)
return;
- if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+ if (pci_channel_offline(pdev))
return;
spin_lock_irqsave(&adapter->stats_lock, flags);
@@ -3573,6 +3708,11 @@ e1000_update_stats(struct e1000_adapter *adapter)
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;
+ if (adapter->hw.bad_tx_carr_stats_fd &&
+ adapter->link_duplex == FULL_DUPLEX) {
+ adapter->net_stats.tx_carrier_errors = 0;
+ adapter->stats.tncrs = 0;
+ }
/* Tx Dropped needs to be maintained elsewhere */
@@ -3590,6 +3730,13 @@ e1000_update_stats(struct e1000_adapter *adapter)
adapter->phy_stats.receive_errors += phy_tmp;
}
+ /* Management Stats */
+ if (adapter->hw.has_smbus) {
+ adapter->stats.mgptc += E1000_READ_REG(hw, MGTPTC);
+ adapter->stats.mgprc += E1000_READ_REG(hw, MGTPRC);
+ adapter->stats.mgpdc += E1000_READ_REG(hw, MGTPDC);
+ }
+
spin_unlock_irqrestore(&adapter->stats_lock, flags);
}
#ifdef CONFIG_PCI_MSI
@@ -3600,8 +3747,8 @@ e1000_update_stats(struct e1000_adapter *adapter)
* @data: pointer to a network interface device structure
**/
-static
-irqreturn_t e1000_intr_msi(int irq, void *data)
+static irqreturn_t
+e1000_intr_msi(int irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3609,49 +3756,27 @@ irqreturn_t e1000_intr_msi(int irq, void *data)
#ifndef CONFIG_E1000_NAPI
int i;
#endif
+ uint32_t icr = E1000_READ_REG(hw, ICR);
- /* this code avoids the read of ICR but has to get 1000 interrupts
- * at every link change event before it will notice the change */
- if (++adapter->detect_link >= 1000) {
- uint32_t icr = E1000_READ_REG(hw, ICR);
#ifdef CONFIG_E1000_NAPI
- /* read ICR disables interrupts using IAM, so keep up with our
- * enable/disable accounting */
- atomic_inc(&adapter->irq_sem);
+ /* read ICR disables interrupts using IAM, so keep up with our
+ * enable/disable accounting */
+ atomic_inc(&adapter->irq_sem);
#endif
- adapter->detect_link = 0;
- if ((icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) &&
- (icr & E1000_ICR_INT_ASSERTED)) {
- hw->get_link_status = 1;
- /* 80003ES2LAN workaround--
- * For packet buffer work-around on link down event;
- * disable receives here in the ISR and
- * reset adapter in watchdog
- */
- if (netif_carrier_ok(netdev) &&
- (adapter->hw.mac_type == e1000_80003es2lan)) {
- /* disable receives */
- uint32_t rctl = E1000_READ_REG(hw, RCTL);
- E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
- }
- /* guard against interrupt when we're going down */
- if (!test_bit(__E1000_DOWN, &adapter->flags))
- mod_timer(&adapter->watchdog_timer,
- jiffies + 1);
+ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ hw->get_link_status = 1;
+ /* 80003ES2LAN workaround-- For packet buffer work-around on
+ * link down event; disable receives here in the ISR and reset
+ * adapter in watchdog */
+ if (netif_carrier_ok(netdev) &&
+ (adapter->hw.mac_type == e1000_80003es2lan)) {
+ /* disable receives */
+ uint32_t rctl = E1000_READ_REG(hw, RCTL);
+ E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
}
- } else {
- E1000_WRITE_REG(hw, ICR, (0xffffffff & ~(E1000_ICR_RXSEQ |
- E1000_ICR_LSC)));
- /* bummer we have to flush here, but things break otherwise as
- * some event appears to be lost or delayed and throughput
- * drops. In almost all tests this flush is un-necessary */
- E1000_WRITE_FLUSH(hw);
-#ifdef CONFIG_E1000_NAPI
- /* Interrupt Auto-Mask (IAM)...upon writing ICR, interrupts are
- * masked. No need for the IMC write, but it does mean we
- * should account for it ASAP. */
- atomic_inc(&adapter->irq_sem);
-#endif
+ /* 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
@@ -3671,7 +3796,7 @@ irqreturn_t e1000_intr_msi(int irq, void *data)
for (i = 0; i < E1000_MAX_INTR; i++)
if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
- !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
+ e1000_clean_tx_irq(adapter, adapter->tx_ring)))
break;
if (likely(adapter->itr_setting & 3))
@@ -3774,7 +3899,7 @@ e1000_intr(int irq, void *data)
for (i = 0; i < E1000_MAX_INTR; i++)
if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
- !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
+ e1000_clean_tx_irq(adapter, adapter->tx_ring)))
break;
if (likely(adapter->itr_setting & 3))
@@ -3824,7 +3949,7 @@ e1000_clean(struct net_device *poll_dev, int *budget)
poll_dev->quota -= work_done;
/* If no Tx and not enough Rx work done, exit the polling mode */
- if ((!tx_cleaned && (work_done == 0)) ||
+ if ((tx_cleaned && (work_done < work_to_do)) ||
!netif_running(poll_dev)) {
quit_polling:
if (likely(adapter->itr_setting & 3))
@@ -3854,7 +3979,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
#ifdef CONFIG_E1000_NAPI
unsigned int count = 0;
#endif
- boolean_t cleaned = FALSE;
+ boolean_t cleaned = TRUE;
unsigned int total_tx_bytes=0, total_tx_packets=0;
i = tx_ring->next_to_clean;
@@ -3868,11 +3993,14 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
cleaned = (i == eop);
if (cleaned) {
- /* this packet count is wrong for TSO but has a
- * tendency to make dynamic ITR change more
- * towards bulk */
- total_tx_packets++;
- total_tx_bytes += buffer_info->skb->len;
+ struct sk_buff *skb = buffer_info->skb;
+ unsigned int segs, bytecount;
+ segs = skb_shinfo(skb)->gso_segs ?: 1;
+ /* multiply data chunks by size of headers */
+ bytecount = ((segs - 1) * skb_headlen(skb)) +
+ skb->len;
+ total_tx_packets += segs;
+ total_tx_bytes += bytecount;
}
e1000_unmap_and_free_tx_resource(adapter, buffer_info);
tx_desc->upper.data = 0;
@@ -3885,7 +4013,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
#ifdef CONFIG_E1000_NAPI
#define E1000_TX_WEIGHT 64
/* weight of a sort for tx, to avoid endless transmit cleanup */
- if (count++ == E1000_TX_WEIGHT) break;
+ if (count++ == E1000_TX_WEIGHT) {
+ cleaned = FALSE;
+ break;
+ }
#endif
}
@@ -4094,8 +4225,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter,
/* code added for copybreak, this should improve
* performance for small packets with large amounts
* of reassembly being done in the stack */
-#define E1000_CB_LENGTH 256
- if (length < E1000_CB_LENGTH) {
+ if (length < copybreak) {
struct sk_buff *new_skb =
netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
if (new_skb) {
@@ -4253,7 +4383,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
/* page alloc/put takes too long and effects small packet
* throughput, so unsplit small packets and save the alloc/put*/
- if (l1 && ((length + l1) <= adapter->rx_ps_bsize0)) {
+ if (l1 && (l1 <= copybreak) && ((length + l1) <= adapter->rx_ps_bsize0)) {
u8 *vaddr;
/* there is no documentation about how to call
* kmap_atomic, so we can't hold the mapping
@@ -4998,7 +5128,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
- uint32_t ctrl, ctrl_ext, rctl, manc, status;
+ uint32_t ctrl, ctrl_ext, rctl, status;
uint32_t wufc = adapter->wol;
#ifdef CONFIG_PM
int retval = 0;
@@ -5067,16 +5197,12 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
pci_enable_wake(pdev, PCI_D3cold, 0);
}
- if (adapter->hw.mac_type >= e1000_82540 &&
- 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) {
- manc |= E1000_MANC_ARP_EN;
- E1000_WRITE_REG(&adapter->hw, MANC, manc);
- pci_enable_wake(pdev, PCI_D3hot, 1);
- pci_enable_wake(pdev, PCI_D3cold, 1);
- }
+ e1000_release_manageability(adapter);
+
+ /* make sure adapter isn't asleep if manageability is enabled */
+ if (adapter->en_mng_pt) {
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1);
}
if (adapter->hw.phy_type == e1000_phy_igp_3)
@@ -5102,7 +5228,7 @@ e1000_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
- uint32_t manc, err;
+ uint32_t err;
pci_set_power_state(pdev, PCI_D0);
e1000_pci_restore_state(adapter);
@@ -5122,19 +5248,13 @@ e1000_resume(struct pci_dev *pdev)
e1000_reset(adapter);
E1000_WRITE_REG(&adapter->hw, WUS, ~0);
+ e1000_init_manageability(adapter);
+
if (netif_running(netdev))
e1000_up(adapter);
netif_device_attach(netdev);
- if (adapter->hw.mac_type >= e1000_82540 &&
- 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);
- E1000_WRITE_REG(&adapter->hw, MANC, manc);
- }
-
/* If the controller is 82573 and f/w is AMT, do not set
* DRV_LOAD until the interface is up. For all other cases,
* let the f/w know that the h/w is now under the control
@@ -5235,7 +5355,8 @@ static void e1000_io_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev->priv;
- uint32_t manc, swsm;
+
+ e1000_init_manageability(adapter);
if (netif_running(netdev)) {
if (e1000_up(adapter)) {
@@ -5246,26 +5367,14 @@ static void e1000_io_resume(struct pci_dev *pdev)
netif_device_attach(netdev);
- if (adapter->hw.mac_type >= e1000_82540 &&
- 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);
- E1000_WRITE_REG(&adapter->hw, MANC, manc);
- }
-
- switch (adapter->hw.mac_type) {
- case e1000_82573:
- swsm = E1000_READ_REG(&adapter->hw, SWSM);
- E1000_WRITE_REG(&adapter->hw, SWSM,
- swsm | E1000_SWSM_DRV_LOAD);
- break;
- default:
- break;
- }
+ /* If the controller is 82573 and f/w is AMT, do not set
+ * DRV_LOAD until the interface is up. For all other cases,
+ * let the f/w know that the h/w is now under the control
+ * of the driver. */
+ if (adapter->hw.mac_type != e1000_82573 ||
+ !e1000_check_mng_mode(&adapter->hw))
+ e1000_get_hw_control(adapter);
- if (netif_running(netdev))
- mod_timer(&adapter->watchdog_timer, jiffies);
}
/* e1000_main.c */
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index 18afc0c25da..10af742d8a2 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -48,8 +48,6 @@ typedef enum {
TRUE = 1
} boolean_t;
-#define MSGOUT(S, A, B) printk(KERN_DEBUG S "\n", A, B)
-
#ifdef DBG
#define DEBUGOUT(S) printk(KERN_DEBUG S "\n")
#define DEBUGOUT1(S, A...) printk(KERN_DEBUG S "\n", A)
@@ -58,7 +56,7 @@ typedef enum {
#define DEBUGOUT1(S, A...)
#endif
-#define DEBUGFUNC(F) DEBUGOUT(F)
+#define DEBUGFUNC(F) DEBUGOUT(F "\n")
#define DEBUGOUT2 DEBUGOUT1
#define DEBUGOUT3 DEBUGOUT2
#define DEBUGOUT7 DEBUGOUT3
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index cbfcd7f2889..f8862e203ac 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -487,7 +487,9 @@ e1000_check_options(struct e1000_adapter *adapter)
e1000_validate_option(&adapter->itr, &opt,
adapter);
/* save the setting, because the dynamic bits change itr */
- adapter->itr_setting = adapter->itr;
+ /* clear the lower two bits because they are
+ * used as control */
+ adapter->itr_setting = adapter->itr & ~3;
break;
}
} else {
@@ -758,22 +760,13 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
case SPEED_1000:
DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without "
"Duplex\n");
- DPRINTK(PROBE, INFO,
- "Using Autonegotiation at 1000 Mbps "
- "Full Duplex only\n");
- adapter->hw.autoneg = adapter->fc_autoneg = 1;
- adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
- break;
+ goto full_duplex_only;
case SPEED_1000 + HALF_DUPLEX:
DPRINTK(PROBE, INFO,
"Half Duplex is not supported at 1000 Mbps\n");
- DPRINTK(PROBE, INFO,
- "Using Autonegotiation at 1000 Mbps "
- "Full Duplex only\n");
- adapter->hw.autoneg = adapter->fc_autoneg = 1;
- adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
- break;
+ /* fall through */
case SPEED_1000 + FULL_DUPLEX:
+full_duplex_only:
DPRINTK(PROBE, INFO,
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index c62d9c6363c..b2b0a96218c 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -355,8 +355,7 @@ e21_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
mem_on(ioaddr, shared_mem, (ring_offset>>8));
- /* Packet is always in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, ei_status.mem + (ring_offset & 0xff), count, 0);
+ memcpy_fromio(skb->data, ei_status.mem + (ring_offset & 0xff), count);
mem_off(ioaddr);
}
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 39ad9f73d1e..272e1ec51aa 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_0043"
+#define DRV_VERSION "EHEA_0045"
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 83fa32f7239..9de2d38a532 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -558,12 +558,12 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
u32 qp_token;
eqe = ehea_poll_eq(port->qp_eq);
- ehea_debug("eqe=%p", eqe);
+
while (eqe) {
- ehea_debug("*eqe=%lx", *(u64*)eqe);
- eqe = ehea_poll_eq(port->qp_eq);
qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry);
- ehea_debug("next eqe=%p", eqe);
+ ehea_error("QP aff_err: entry=0x%lx, token=0x%x",
+ eqe->entry, qp_token);
+ eqe = ehea_poll_eq(port->qp_eq);
}
return IRQ_HANDLED;
@@ -575,8 +575,9 @@ static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter,
int i;
for (i = 0; i < adapter->num_ports; i++)
- if (adapter->port[i]->logical_port_id == logical_port)
- return adapter->port[i];
+ if (adapter->port[i])
+ if (adapter->port[i]->logical_port_id == logical_port)
+ return adapter->port[i];
return NULL;
}
@@ -642,6 +643,8 @@ int ehea_sense_port_attr(struct ehea_port *port)
break;
}
+ port->autoneg = 1;
+
/* Number of default QPs */
port->num_def_qps = cb0->num_default_qps;
@@ -728,10 +731,7 @@ int ehea_set_portspeed(struct ehea_port *port, u32 port_speed)
}
} else {
if (hret == H_AUTHORITY) {
- ehea_info("Hypervisor denied setting port speed. Either"
- " this partition is not authorized to set "
- "port speed or another partition has modified"
- " port speed first.");
+ ehea_info("Hypervisor denied setting port speed");
ret = -EPERM;
} else {
ret = -EIO;
@@ -998,7 +998,7 @@ static int ehea_configure_port(struct ehea_port *port)
| EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1);
for (i = 0; i < port->num_def_qps; i++)
- cb0->default_qpn_arr[i] = port->port_res[i].qp->init_attr.qp_nr;
+ cb0->default_qpn_arr[i] = port->port_res[0].qp->init_attr.qp_nr;
if (netif_msg_ifup(port))
ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port");
@@ -1485,11 +1485,12 @@ out:
static void ehea_promiscuous_error(u64 hret, int enable)
{
- ehea_info("Hypervisor denied %sabling promiscuous mode.%s",
- enable == 1 ? "en" : "dis",
- hret != H_AUTHORITY ? "" : " Another partition owning a "
- "logical port on the same physical port might have altered "
- "promiscuous mode first.");
+ if (hret == H_AUTHORITY)
+ ehea_info("Hypervisor denied %sabling promiscuous mode",
+ enable == 1 ? "en" : "dis");
+ else
+ ehea_error("failed %sabling promiscuous mode",
+ enable == 1 ? "en" : "dis");
}
static void ehea_promiscuous(struct net_device *dev, int enable)
@@ -2267,6 +2268,8 @@ static void ehea_tx_watchdog(struct net_device *dev)
int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
{
struct hcp_query_ehea *cb;
+ struct device_node *lhea_dn = NULL;
+ struct device_node *eth_dn = NULL;
u64 hret;
int ret;
@@ -2283,7 +2286,18 @@ int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
goto out_herr;
}
- adapter->num_ports = cb->num_ports;
+ /* Determine the number of available logical ports
+ * by counting the child nodes of the lhea OFDT entry
+ */
+ adapter->num_ports = 0;
+ lhea_dn = of_find_node_by_name(lhea_dn, "lhea");
+ do {
+ eth_dn = of_get_next_child(lhea_dn, eth_dn);
+ if (eth_dn)
+ adapter->num_ports++;
+ } while ( eth_dn );
+ of_node_put(lhea_dn);
+
adapter->max_mc_mac = cb->max_mc_mac - 1;
ret = 0;
@@ -2302,6 +2316,7 @@ static int ehea_setup_single_port(struct ehea_port *port,
struct ehea_adapter *adapter = port->adapter;
struct hcp_ehea_port_cb4 *cb4;
u32 *dn_log_port_id;
+ int jumbo = 0;
sema_init(&port->port_lock, 1);
port->state = EHEA_PORT_DOWN;
@@ -2334,8 +2349,6 @@ static int ehea_setup_single_port(struct ehea_port *port,
INIT_LIST_HEAD(&port->mc_list->list);
- ehea_set_portspeed(port, EHEA_SPEED_AUTONEG);
-
ret = ehea_sense_port_attr(port);
if (ret)
goto out;
@@ -2345,13 +2358,25 @@ static int ehea_setup_single_port(struct ehea_port *port,
if (!cb4) {
ehea_error("no mem for cb4");
} else {
- cb4->jumbo_frame = 1;
- hret = ehea_h_modify_ehea_port(adapter->handle,
- port->logical_port_id,
- H_PORT_CB4, H_PORT_CB4_JUMBO,
- cb4);
- if (hret != H_SUCCESS) {
- ehea_info("Jumbo frames not activated");
+ hret = ehea_h_query_ehea_port(adapter->handle,
+ port->logical_port_id,
+ H_PORT_CB4,
+ H_PORT_CB4_JUMBO, cb4);
+
+ if (hret == H_SUCCESS) {
+ if (cb4->jumbo_frame)
+ jumbo = 1;
+ else {
+ cb4->jumbo_frame = 1;
+ hret = ehea_h_modify_ehea_port(adapter->handle,
+ port->
+ logical_port_id,
+ H_PORT_CB4,
+ H_PORT_CB4_JUMBO,
+ cb4);
+ if (hret == H_SUCCESS)
+ jumbo = 1;
+ }
}
kfree(cb4);
}
@@ -2390,6 +2415,9 @@ static int ehea_setup_single_port(struct ehea_port *port,
goto out_free;
}
+ ehea_info("%s: Jumbo frames are %sabled", dev->name,
+ jumbo == 1 ? "en" : "dis");
+
port->netdev = dev;
ret = 0;
goto out;
@@ -2471,14 +2499,16 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev,
adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle",
NULL);
- if (!adapter_handle) {
+ if (adapter_handle)
+ adapter->handle = *adapter_handle;
+
+ if (!adapter->handle) {
dev_err(&dev->ofdev.dev, "failed getting handle for adapter"
" '%s'\n", dev->ofdev.node->full_name);
ret = -ENODEV;
goto out_free_ad;
}
- adapter->handle = *adapter_handle;
adapter->pd = EHEA_PD_ID;
dev->ofdev.dev.driver_data = adapter;
@@ -2568,6 +2598,7 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev)
destroy_workqueue(adapter->ehea_wq);
ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
+ tasklet_kill(&adapter->neq_tasklet);
ehea_destroy_eq(adapter->neq);
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index 0cfc2bc1a27..37716e05e80 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -94,6 +94,7 @@ static long ehea_plpar_hcall9(unsigned long opcode,
{
long ret;
int i, sleep_msecs;
+ u8 cb_cat;
for (i = 0; i < 5; i++) {
ret = plpar_hcall9(opcode, outs,
@@ -106,7 +107,13 @@ static long ehea_plpar_hcall9(unsigned long opcode,
continue;
}
- if (ret < H_SUCCESS)
+ cb_cat = EHEA_BMASK_GET(H_MEHEAPORT_CAT, arg2);
+
+ if ((ret < H_SUCCESS) && !(((ret == H_AUTHORITY)
+ && (opcode == H_MODIFY_HEA_PORT))
+ && (((cb_cat == H_PORT_CB4) && ((arg3 == H_PORT_CB4_JUMBO)
+ || (arg3 == H_PORT_CB4_SPEED))) || ((cb_cat == H_PORT_CB7)
+ && (arg3 == H_PORT_CB7_DUCQPN)))))
ehea_error("opcode=%lx ret=%lx"
" arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
" arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
@@ -120,7 +127,6 @@ static long ehea_plpar_hcall9(unsigned long opcode,
outs[0], outs[1], outs[2], outs[3],
outs[4], outs[5], outs[6], outs[7],
outs[8]);
-
return ret;
}
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 2d2ea94a00b..822e5bfd1a7 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -375,7 +375,7 @@ static void es_block_input(struct net_device *dev, int count, struct sk_buff *sk
memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
} else {
/* Packet is in one chunk. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
}
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 439f4133829..a363148d019 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -3,8 +3,7 @@
*
* Note: This driver is a cleanroom reimplementation based on reverse
* engineered documentation written by Carl-Daniel Hailfinger
- * and Andrew de Quincey. It's neither supported nor endorsed
- * by NVIDIA Corp. Use at your own risk.
+ * and Andrew de Quincey.
*
* NVIDIA, nForce and other NVIDIA marks are trademarks or registered
* trademarks of NVIDIA Corporation in the United States and other
@@ -14,7 +13,7 @@
* Copyright (C) 2004 Andrew de Quincey (wol support)
* Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane
* IRQ rate fixes, bigendian fixes, cleanups, verification)
- * Copyright (c) 2004 NVIDIA Corporation
+ * Copyright (c) 2004,5,6 NVIDIA 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
@@ -112,6 +111,7 @@
* 0.57: 14 May 2006: Mac address set in probe/remove and order corrections.
* 0.58: 30 Oct 2006: Added support for sideband management unit.
* 0.59: 30 Oct 2006: Added support for recoverable error.
+ * 0.60: 20 Jan 2007: Code optimizations for rings, rx & tx data paths, and stats.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -128,7 +128,7 @@
#else
#define DRIVERNAPI
#endif
-#define FORCEDETH_VERSION "0.59"
+#define FORCEDETH_VERSION "0.60"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -174,9 +174,10 @@
#define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */
#define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */
#define DEV_HAS_PAUSEFRAME_TX 0x0200 /* device supports tx pause frames */
-#define DEV_HAS_STATISTICS 0x0400 /* device supports hw statistics */
-#define DEV_HAS_TEST_EXTENDED 0x0800 /* device supports extended diagnostic test */
-#define DEV_HAS_MGMT_UNIT 0x1000 /* device supports management unit */
+#define DEV_HAS_STATISTICS_V1 0x0400 /* device supports hw statistics version 1 */
+#define DEV_HAS_STATISTICS_V2 0x0800 /* device supports hw statistics version 2 */
+#define DEV_HAS_TEST_EXTENDED 0x1000 /* device supports extended diagnostic test */
+#define DEV_HAS_MGMT_UNIT 0x2000 /* device supports management unit */
enum {
NvRegIrqStatus = 0x000,
@@ -211,7 +212,7 @@ enum {
* NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
*/
NvRegPollingInterval = 0x00c,
-#define NVREG_POLL_DEFAULT_THROUGHPUT 970
+#define NVREG_POLL_DEFAULT_THROUGHPUT 970 /* backup tx cleanup if loop max reached */
#define NVREG_POLL_DEFAULT_CPU 13
NvRegMSIMap0 = 0x020,
NvRegMSIMap1 = 0x024,
@@ -235,6 +236,7 @@ enum {
#define NVREG_XMITCTL_HOST_SEMA_MASK 0x0000f000
#define NVREG_XMITCTL_HOST_SEMA_ACQ 0x0000f000
#define NVREG_XMITCTL_HOST_LOADED 0x00004000
+#define NVREG_XMITCTL_TX_PATH_EN 0x01000000
NvRegTransmitterStatus = 0x088,
#define NVREG_XMITSTAT_BUSY 0x01
@@ -250,6 +252,7 @@ enum {
#define NVREG_OFFLOAD_NORMAL RX_NIC_BUFSIZE
NvRegReceiverControl = 0x094,
#define NVREG_RCVCTL_START 0x01
+#define NVREG_RCVCTL_RX_PATH_EN 0x01000000
NvRegReceiverStatus = 0x98,
#define NVREG_RCVSTAT_BUSY 0x01
@@ -303,8 +306,8 @@ enum {
#define NVREG_TXRXCTL_RESET 0x0010
#define NVREG_TXRXCTL_RXCHECK 0x0400
#define NVREG_TXRXCTL_DESC_1 0
-#define NVREG_TXRXCTL_DESC_2 0x02100
-#define NVREG_TXRXCTL_DESC_3 0x02200
+#define NVREG_TXRXCTL_DESC_2 0x002100
+#define NVREG_TXRXCTL_DESC_3 0xc02200
#define NVREG_TXRXCTL_VLANSTRIP 0x00040
#define NVREG_TXRXCTL_VLANINS 0x00080
NvRegTxRingPhysAddrHigh = 0x148,
@@ -486,7 +489,8 @@ union ring_type {
/* Miscelaneous hardware related defines: */
#define NV_PCI_REGSZ_VER1 0x270
-#define NV_PCI_REGSZ_VER2 0x604
+#define NV_PCI_REGSZ_VER2 0x2d4
+#define NV_PCI_REGSZ_VER3 0x604
/* various timeout delays: all in usec */
#define NV_TXRX_RESET_DELAY 4
@@ -517,12 +521,6 @@ union ring_type {
#define TX_RING_MIN 64
#define RING_MAX_DESC_VER_1 1024
#define RING_MAX_DESC_VER_2_3 16384
-/*
- * Difference between the get and put pointers for the tx ring.
- * This is used to throttle the amount of data outstanding in the
- * tx ring.
- */
-#define TX_LIMIT_DIFFERENCE 1
/* rx/tx mac addr + type + vlan + align + slack*/
#define NV_RX_HEADERS (64)
@@ -610,9 +608,6 @@ static const struct nv_ethtool_str nv_estats_str[] = {
{ "tx_carrier_errors" },
{ "tx_excess_deferral" },
{ "tx_retry_error" },
- { "tx_deferral" },
- { "tx_packets" },
- { "tx_pause" },
{ "rx_frame_error" },
{ "rx_extra_byte" },
{ "rx_late_collision" },
@@ -625,11 +620,17 @@ static const struct nv_ethtool_str nv_estats_str[] = {
{ "rx_unicast" },
{ "rx_multicast" },
{ "rx_broadcast" },
+ { "rx_packets" },
+ { "rx_errors_total" },
+ { "tx_errors_total" },
+
+ /* version 2 stats */
+ { "tx_deferral" },
+ { "tx_packets" },
{ "rx_bytes" },
+ { "tx_pause" },
{ "rx_pause" },
- { "rx_drop_frame" },
- { "rx_packets" },
- { "rx_errors_total" }
+ { "rx_drop_frame" }
};
struct nv_ethtool_stats {
@@ -642,9 +643,6 @@ struct nv_ethtool_stats {
u64 tx_carrier_errors;
u64 tx_excess_deferral;
u64 tx_retry_error;
- u64 tx_deferral;
- u64 tx_packets;
- u64 tx_pause;
u64 rx_frame_error;
u64 rx_extra_byte;
u64 rx_late_collision;
@@ -657,13 +655,22 @@ struct nv_ethtool_stats {
u64 rx_unicast;
u64 rx_multicast;
u64 rx_broadcast;
+ u64 rx_packets;
+ u64 rx_errors_total;
+ u64 tx_errors_total;
+
+ /* version 2 stats */
+ u64 tx_deferral;
+ u64 tx_packets;
u64 rx_bytes;
+ u64 tx_pause;
u64 rx_pause;
u64 rx_drop_frame;
- u64 rx_packets;
- u64 rx_errors_total;
};
+#define NV_DEV_STATISTICS_V2_COUNT (sizeof(struct nv_ethtool_stats)/sizeof(u64))
+#define NV_DEV_STATISTICS_V1_COUNT (NV_DEV_STATISTICS_V2_COUNT - 6)
+
/* diagnostics */
#define NV_TEST_COUNT_BASE 3
#define NV_TEST_COUNT_EXTENDED 4
@@ -690,6 +697,12 @@ static const struct register_test nv_registers_test[] = {
{ 0,0 }
};
+struct nv_skb_map {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ unsigned int dma_len;
+};
+
/*
* SMP locking:
* All hardware access under dev->priv->lock, except the performance
@@ -740,10 +753,12 @@ struct fe_priv {
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
+ union ring_type get_rx, put_rx, first_rx, last_rx;
+ struct nv_skb_map *get_rx_ctx, *put_rx_ctx;
+ struct nv_skb_map *first_rx_ctx, *last_rx_ctx;
+ struct nv_skb_map *rx_skb;
+
union ring_type rx_ring;
- unsigned int cur_rx, refill_rx;
- struct sk_buff **rx_skbuff;
- dma_addr_t *rx_dma;
unsigned int rx_buf_sz;
unsigned int pkt_limit;
struct timer_list oom_kick;
@@ -760,15 +775,15 @@ struct fe_priv {
/*
* tx specific fields.
*/
+ union ring_type get_tx, put_tx, first_tx, last_tx;
+ struct nv_skb_map *get_tx_ctx, *put_tx_ctx;
+ struct nv_skb_map *first_tx_ctx, *last_tx_ctx;
+ struct nv_skb_map *tx_skb;
+
union ring_type tx_ring;
- unsigned int next_tx, nic_tx;
- struct sk_buff **tx_skbuff;
- dma_addr_t *tx_dma;
- unsigned int *tx_dma_len;
u32 tx_flags;
int tx_ring_size;
- int tx_limit_start;
- int tx_limit_stop;
+ int tx_stop;
/* vlan fields */
struct vlan_group *vlangrp;
@@ -920,16 +935,10 @@ static void free_rings(struct net_device *dev)
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size),
np->rx_ring.ex, np->ring_addr);
}
- if (np->rx_skbuff)
- kfree(np->rx_skbuff);
- if (np->rx_dma)
- kfree(np->rx_dma);
- if (np->tx_skbuff)
- kfree(np->tx_skbuff);
- if (np->tx_dma)
- kfree(np->tx_dma);
- if (np->tx_dma_len)
- kfree(np->tx_dma_len);
+ if (np->rx_skb)
+ kfree(np->rx_skb);
+ if (np->tx_skb)
+ kfree(np->tx_skb);
}
static int using_multi_irqs(struct net_device *dev)
@@ -1170,16 +1179,21 @@ static void nv_start_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
+ u32 rx_ctrl = readl(base + NvRegReceiverControl);
dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
/* Already running? Stop it. */
- if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) {
- writel(0, base + NvRegReceiverControl);
+ if ((readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) && !np->mac_in_use) {
+ rx_ctrl &= ~NVREG_RCVCTL_START;
+ writel(rx_ctrl, base + NvRegReceiverControl);
pci_push(base);
}
writel(np->linkspeed, base + NvRegLinkSpeed);
pci_push(base);
- writel(NVREG_RCVCTL_START, base + NvRegReceiverControl);
+ rx_ctrl |= NVREG_RCVCTL_START;
+ if (np->mac_in_use)
+ rx_ctrl &= ~NVREG_RCVCTL_RX_PATH_EN;
+ writel(rx_ctrl, base + NvRegReceiverControl);
dprintk(KERN_DEBUG "%s: nv_start_rx to duplex %d, speed 0x%08x.\n",
dev->name, np->duplex, np->linkspeed);
pci_push(base);
@@ -1187,39 +1201,59 @@ static void nv_start_rx(struct net_device *dev)
static void nv_stop_rx(struct net_device *dev)
{
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
+ u32 rx_ctrl = readl(base + NvRegReceiverControl);
dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name);
- writel(0, base + NvRegReceiverControl);
+ if (!np->mac_in_use)
+ rx_ctrl &= ~NVREG_RCVCTL_START;
+ else
+ rx_ctrl |= NVREG_RCVCTL_RX_PATH_EN;
+ writel(rx_ctrl, base + NvRegReceiverControl);
reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0,
NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX,
KERN_INFO "nv_stop_rx: ReceiverStatus remained busy");
udelay(NV_RXSTOP_DELAY2);
- writel(0, base + NvRegLinkSpeed);
+ if (!np->mac_in_use)
+ writel(0, base + NvRegLinkSpeed);
}
static void nv_start_tx(struct net_device *dev)
{
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
+ u32 tx_ctrl = readl(base + NvRegTransmitterControl);
dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name);
- writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl);
+ tx_ctrl |= NVREG_XMITCTL_START;
+ if (np->mac_in_use)
+ tx_ctrl &= ~NVREG_XMITCTL_TX_PATH_EN;
+ writel(tx_ctrl, base + NvRegTransmitterControl);
pci_push(base);
}
static void nv_stop_tx(struct net_device *dev)
{
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
+ u32 tx_ctrl = readl(base + NvRegTransmitterControl);
dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name);
- writel(0, base + NvRegTransmitterControl);
+ if (!np->mac_in_use)
+ tx_ctrl &= ~NVREG_XMITCTL_START;
+ else
+ tx_ctrl |= NVREG_XMITCTL_TX_PATH_EN;
+ writel(tx_ctrl, base + NvRegTransmitterControl);
reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0,
NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX,
KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
udelay(NV_TXSTOP_DELAY2);
- writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
+ if (!np->mac_in_use)
+ writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV,
+ base + NvRegTransmitPoll);
}
static void nv_txrx_reset(struct net_device *dev)
@@ -1253,6 +1287,61 @@ static void nv_mac_reset(struct net_device *dev)
pci_push(base);
}
+static void nv_get_hw_stats(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+
+ np->estats.tx_bytes += readl(base + NvRegTxCnt);
+ np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
+ np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
+ np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt);
+ np->estats.tx_late_collision += readl(base + NvRegTxLateCol);
+ np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow);
+ np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier);
+ np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef);
+ np->estats.tx_retry_error += readl(base + NvRegTxRetryErr);
+ np->estats.rx_frame_error += readl(base + NvRegRxFrameErr);
+ np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte);
+ np->estats.rx_late_collision += readl(base + NvRegRxLateCol);
+ np->estats.rx_runt += readl(base + NvRegRxRunt);
+ np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong);
+ np->estats.rx_over_errors += readl(base + NvRegRxOverflow);
+ np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr);
+ np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr);
+ np->estats.rx_length_error += readl(base + NvRegRxLenErr);
+ np->estats.rx_unicast += readl(base + NvRegRxUnicast);
+ np->estats.rx_multicast += readl(base + NvRegRxMulticast);
+ np->estats.rx_broadcast += readl(base + NvRegRxBroadcast);
+ np->estats.rx_packets =
+ np->estats.rx_unicast +
+ np->estats.rx_multicast +
+ np->estats.rx_broadcast;
+ np->estats.rx_errors_total =
+ np->estats.rx_crc_errors +
+ np->estats.rx_over_errors +
+ np->estats.rx_frame_error +
+ (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) +
+ np->estats.rx_late_collision +
+ np->estats.rx_runt +
+ np->estats.rx_frame_too_long;
+ np->estats.tx_errors_total =
+ np->estats.tx_late_collision +
+ np->estats.tx_fifo_errors +
+ np->estats.tx_carrier_errors +
+ np->estats.tx_excess_deferral +
+ np->estats.tx_retry_error;
+
+ if (np->driver_data & DEV_HAS_STATISTICS_V2) {
+ np->estats.tx_deferral += readl(base + NvRegTxDef);
+ np->estats.tx_packets += readl(base + NvRegTxFrame);
+ np->estats.rx_bytes += readl(base + NvRegRxCnt);
+ np->estats.tx_pause += readl(base + NvRegTxPause);
+ np->estats.rx_pause += readl(base + NvRegRxPause);
+ np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame);
+ }
+}
+
/*
* nv_get_stats: dev->get_stats function
* Get latest stats value from the nic.
@@ -1263,10 +1352,19 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- /* It seems that the nic always generates interrupts and doesn't
- * accumulate errors internally. Thus the current values in np->stats
- * are already up to date.
- */
+ /* If the nic supports hw counters then retrieve latest values */
+ if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2)) {
+ nv_get_hw_stats(dev);
+
+ /* copy to net_device stats */
+ np->stats.tx_bytes = np->estats.tx_bytes;
+ np->stats.tx_fifo_errors = np->estats.tx_fifo_errors;
+ np->stats.tx_carrier_errors = np->estats.tx_carrier_errors;
+ np->stats.rx_crc_errors = np->estats.rx_crc_errors;
+ np->stats.rx_over_errors = np->estats.rx_over_errors;
+ np->stats.rx_errors = np->estats.rx_errors_total;
+ np->stats.tx_errors = np->estats.tx_errors_total;
+ }
return &np->stats;
}
@@ -1278,43 +1376,63 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
static int nv_alloc_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- unsigned int refill_rx = np->refill_rx;
- int nr;
+ struct ring_desc* less_rx;
- while (np->cur_rx != refill_rx) {
- struct sk_buff *skb;
-
- nr = refill_rx % np->rx_ring_size;
- if (np->rx_skbuff[nr] == NULL) {
-
- skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
- if (!skb)
- break;
+ less_rx = np->get_rx.orig;
+ if (less_rx-- == np->first_rx.orig)
+ less_rx = np->last_rx.orig;
+ while (np->put_rx.orig != less_rx) {
+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+ if (skb) {
skb->dev = dev;
- np->rx_skbuff[nr] = skb;
+ np->put_rx_ctx->skb = skb;
+ np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+ skb->end-skb->data, PCI_DMA_FROMDEVICE);
+ np->put_rx_ctx->dma_len = skb->end-skb->data;
+ np->put_rx.orig->buf = cpu_to_le32(np->put_rx_ctx->dma);
+ wmb();
+ np->put_rx.orig->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+ if (unlikely(np->put_rx.orig++ == np->last_rx.orig))
+ np->put_rx.orig = np->first_rx.orig;
+ if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+ np->put_rx_ctx = np->first_rx_ctx;
} else {
- skb = np->rx_skbuff[nr];
+ return 1;
}
- np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data,
- skb->end-skb->data, PCI_DMA_FROMDEVICE);
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]);
+ }
+ return 0;
+}
+
+static int nv_alloc_rx_optimized(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ struct ring_desc_ex* less_rx;
+
+ less_rx = np->get_rx.ex;
+ if (less_rx-- == np->first_rx.ex)
+ less_rx = np->last_rx.ex;
+
+ while (np->put_rx.ex != less_rx) {
+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+ if (skb) {
+ skb->dev = dev;
+ np->put_rx_ctx->skb = skb;
+ np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+ skb->end-skb->data, PCI_DMA_FROMDEVICE);
+ np->put_rx_ctx->dma_len = skb->end-skb->data;
+ np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32;
+ np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF;
wmb();
- np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+ np->put_rx.ex->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+ if (unlikely(np->put_rx.ex++ == np->last_rx.ex))
+ np->put_rx.ex = np->first_rx.ex;
+ if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+ np->put_rx_ctx = np->first_rx_ctx;
} else {
- np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
- np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
- wmb();
- np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+ return 1;
}
- dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
- dev->name, refill_rx);
- refill_rx++;
}
- np->refill_rx = refill_rx;
- if (np->cur_rx - refill_rx == np->rx_ring_size)
- return 1;
return 0;
}
@@ -1332,6 +1450,7 @@ static void nv_do_rx_refill(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
+ int retcode;
if (!using_multi_irqs(dev)) {
if (np->msi_flags & NV_MSI_X_ENABLED)
@@ -1341,7 +1460,11 @@ static void nv_do_rx_refill(unsigned long data)
} else {
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
- if (nv_alloc_rx(dev)) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ retcode = nv_alloc_rx(dev);
+ else
+ retcode = nv_alloc_rx_optimized(dev);
+ if (retcode) {
spin_lock_irq(&np->lock);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
@@ -1362,56 +1485,81 @@ static void nv_init_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
int i;
+ np->get_rx = np->put_rx = np->first_rx = np->rx_ring;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ np->last_rx.orig = &np->rx_ring.orig[np->rx_ring_size-1];
+ else
+ np->last_rx.ex = &np->rx_ring.ex[np->rx_ring_size-1];
+ np->get_rx_ctx = np->put_rx_ctx = np->first_rx_ctx = np->rx_skb;
+ np->last_rx_ctx = &np->rx_skb[np->rx_ring_size-1];
- np->cur_rx = np->rx_ring_size;
- np->refill_rx = 0;
- for (i = 0; i < np->rx_ring_size; i++)
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ for (i = 0; i < np->rx_ring_size; i++) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig[i].flaglen = 0;
- else
+ np->rx_ring.orig[i].buf = 0;
+ } else {
np->rx_ring.ex[i].flaglen = 0;
+ np->rx_ring.ex[i].txvlan = 0;
+ np->rx_ring.ex[i].bufhigh = 0;
+ np->rx_ring.ex[i].buflow = 0;
+ }
+ np->rx_skb[i].skb = NULL;
+ np->rx_skb[i].dma = 0;
+ }
}
static void nv_init_tx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
int i;
+ np->get_tx = np->put_tx = np->first_tx = np->tx_ring;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ np->last_tx.orig = &np->tx_ring.orig[np->tx_ring_size-1];
+ else
+ np->last_tx.ex = &np->tx_ring.ex[np->tx_ring_size-1];
+ np->get_tx_ctx = np->put_tx_ctx = np->first_tx_ctx = np->tx_skb;
+ np->last_tx_ctx = &np->tx_skb[np->tx_ring_size-1];
- np->next_tx = np->nic_tx = 0;
for (i = 0; i < np->tx_ring_size; i++) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->tx_ring.orig[i].flaglen = 0;
- else
+ np->tx_ring.orig[i].buf = 0;
+ } else {
np->tx_ring.ex[i].flaglen = 0;
- np->tx_skbuff[i] = NULL;
- np->tx_dma[i] = 0;
+ np->tx_ring.ex[i].txvlan = 0;
+ np->tx_ring.ex[i].bufhigh = 0;
+ np->tx_ring.ex[i].buflow = 0;
+ }
+ np->tx_skb[i].skb = NULL;
+ np->tx_skb[i].dma = 0;
}
}
static int nv_init_ring(struct net_device *dev)
{
+ struct fe_priv *np = netdev_priv(dev);
+
nv_init_tx(dev);
nv_init_rx(dev);
- return nv_alloc_rx(dev);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ return nv_alloc_rx(dev);
+ else
+ return nv_alloc_rx_optimized(dev);
}
-static int nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+static int nv_release_txskb(struct net_device *dev, struct nv_skb_map* tx_skb)
{
struct fe_priv *np = netdev_priv(dev);
- dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n",
- dev->name, skbnr);
-
- if (np->tx_dma[skbnr]) {
- pci_unmap_page(np->pci_dev, np->tx_dma[skbnr],
- np->tx_dma_len[skbnr],
+ if (tx_skb->dma) {
+ pci_unmap_page(np->pci_dev, tx_skb->dma,
+ tx_skb->dma_len,
PCI_DMA_TODEVICE);
- np->tx_dma[skbnr] = 0;
+ tx_skb->dma = 0;
}
-
- if (np->tx_skbuff[skbnr]) {
- dev_kfree_skb_any(np->tx_skbuff[skbnr]);
- np->tx_skbuff[skbnr] = NULL;
+ if (tx_skb->skb) {
+ dev_kfree_skb_any(tx_skb->skb);
+ tx_skb->skb = NULL;
return 1;
} else {
return 0;
@@ -1424,11 +1572,16 @@ static void nv_drain_tx(struct net_device *dev)
unsigned int i;
for (i = 0; i < np->tx_ring_size; i++) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->tx_ring.orig[i].flaglen = 0;
- else
+ np->tx_ring.orig[i].buf = 0;
+ } else {
np->tx_ring.ex[i].flaglen = 0;
- if (nv_release_txskb(dev, i))
+ np->tx_ring.ex[i].txvlan = 0;
+ np->tx_ring.ex[i].bufhigh = 0;
+ np->tx_ring.ex[i].buflow = 0;
+ }
+ if (nv_release_txskb(dev, &np->tx_skb[i]))
np->stats.tx_dropped++;
}
}
@@ -1437,18 +1590,24 @@ static void nv_drain_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
int i;
+
for (i = 0; i < np->rx_ring_size; i++) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig[i].flaglen = 0;
- else
+ np->rx_ring.orig[i].buf = 0;
+ } else {
np->rx_ring.ex[i].flaglen = 0;
+ np->rx_ring.ex[i].txvlan = 0;
+ np->rx_ring.ex[i].bufhigh = 0;
+ np->rx_ring.ex[i].buflow = 0;
+ }
wmb();
- if (np->rx_skbuff[i]) {
- pci_unmap_single(np->pci_dev, np->rx_dma[i],
- np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
+ if (np->rx_skb[i].skb) {
+ pci_unmap_single(np->pci_dev, np->rx_skb[i].dma,
+ np->rx_skb[i].skb->end-np->rx_skb[i].skb->data,
PCI_DMA_FROMDEVICE);
- dev_kfree_skb(np->rx_skbuff[i]);
- np->rx_skbuff[i] = NULL;
+ dev_kfree_skb(np->rx_skb[i].skb);
+ np->rx_skb[i].skb = NULL;
}
}
}
@@ -1459,6 +1618,11 @@ static void drain_ring(struct net_device *dev)
nv_drain_rx(dev);
}
+static inline u32 nv_get_empty_tx_slots(struct fe_priv *np)
+{
+ return (u32)(np->tx_ring_size - ((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) % np->tx_ring_size));
+}
+
/*
* nv_start_xmit: dev->hard_start_xmit function
* Called with netif_tx_lock held.
@@ -1469,14 +1633,16 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 tx_flags = 0;
u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
unsigned int fragments = skb_shinfo(skb)->nr_frags;
- unsigned int nr = (np->next_tx - 1) % np->tx_ring_size;
- unsigned int start_nr = np->next_tx % np->tx_ring_size;
unsigned int i;
u32 offset = 0;
u32 bcnt;
u32 size = skb->len-skb->data_len;
u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
- u32 tx_flags_vlan = 0;
+ u32 empty_slots;
+ struct ring_desc* put_tx;
+ struct ring_desc* start_tx;
+ struct ring_desc* prev_tx;
+ struct nv_skb_map* prev_tx_ctx;
/* add fragments to entries count */
for (i = 0; i < fragments; i++) {
@@ -1484,34 +1650,35 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
}
- spin_lock_irq(&np->lock);
-
- if ((np->next_tx - np->nic_tx + entries - 1) > np->tx_limit_stop) {
- spin_unlock_irq(&np->lock);
+ empty_slots = nv_get_empty_tx_slots(np);
+ if (unlikely(empty_slots <= entries)) {
+ spin_lock_irq(&np->lock);
netif_stop_queue(dev);
+ np->tx_stop = 1;
+ spin_unlock_irq(&np->lock);
return NETDEV_TX_BUSY;
}
+ start_tx = put_tx = np->put_tx.orig;
+
/* setup the header buffer */
do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
- nr = (nr + 1) % np->tx_ring_size;
-
- np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+ np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
PCI_DMA_TODEVICE);
- np->tx_dma_len[nr] = bcnt;
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- } else {
- np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- }
tx_flags = np->tx_flags;
offset += bcnt;
size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.orig))
+ put_tx = np->first_tx.orig;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
} while (size);
/* setup the fragments */
@@ -1521,58 +1688,174 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
offset = 0;
do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
- nr = (nr + 1) % np->tx_ring_size;
-
- np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
- PCI_DMA_TODEVICE);
- np->tx_dma_len[nr] = bcnt;
+ np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- } else {
- np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- }
offset += bcnt;
size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.orig))
+ put_tx = np->first_tx.orig;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
} while (size);
}
/* set last fragment flag */
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra);
- } else {
- np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra);
+ prev_tx->flaglen |= cpu_to_le32(tx_flags_extra);
+
+ /* save skb in this slot's context area */
+ prev_tx_ctx->skb = skb;
+
+ if (skb_is_gso(skb))
+ tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
+ else
+ tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+ NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
+
+ spin_lock_irq(&np->lock);
+
+ /* set tx flags */
+ start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->put_tx.orig = put_tx;
+
+ spin_unlock_irq(&np->lock);
+
+ dprintk(KERN_DEBUG "%s: nv_start_xmit: entries %d queued for transmission. tx_flags_extra: %x\n",
+ dev->name, entries, tx_flags_extra);
+ {
+ int j;
+ for (j=0; j<64; j++) {
+ if ((j%16) == 0)
+ dprintk("\n%03x:", j);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+ }
+ dprintk("\n");
}
- np->tx_skbuff[nr] = skb;
+ dev->trans_start = jiffies;
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+ return NETDEV_TX_OK;
+}
+
+static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u32 tx_flags = 0;
+ u32 tx_flags_extra;
+ unsigned int fragments = skb_shinfo(skb)->nr_frags;
+ unsigned int i;
+ u32 offset = 0;
+ u32 bcnt;
+ u32 size = skb->len-skb->data_len;
+ u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ u32 empty_slots;
+ struct ring_desc_ex* put_tx;
+ struct ring_desc_ex* start_tx;
+ struct ring_desc_ex* prev_tx;
+ struct nv_skb_map* prev_tx_ctx;
+
+ /* add fragments to entries count */
+ for (i = 0; i < fragments; i++) {
+ entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
+ ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ }
+
+ empty_slots = nv_get_empty_tx_slots(np);
+ if (unlikely(empty_slots <= entries)) {
+ spin_lock_irq(&np->lock);
+ netif_stop_queue(dev);
+ np->tx_stop = 1;
+ spin_unlock_irq(&np->lock);
+ return NETDEV_TX_BUSY;
+ }
+
+ start_tx = put_tx = np->put_tx.ex;
+
+ /* setup the header buffer */
+ do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
+ put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+
+ tx_flags = NV_TX2_VALID;
+ offset += bcnt;
+ size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.ex))
+ put_tx = np->first_tx.ex;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
+ } while (size);
+
+ /* setup the fragments */
+ for (i = 0; i < fragments; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ u32 size = frag->size;
+ offset = 0;
+
+ do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
+ put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+
+ offset += bcnt;
+ size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.ex))
+ put_tx = np->first_tx.ex;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
+ } while (size);
+ }
+
+ /* set last fragment flag */
+ prev_tx->flaglen |= cpu_to_le32(NV_TX2_LASTPACKET);
+
+ /* save skb in this slot's context area */
+ prev_tx_ctx->skb = skb;
-#ifdef NETIF_F_TSO
if (skb_is_gso(skb))
tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
else
-#endif
- tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+ tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
/* vlan tag */
- if (np->vlangrp && vlan_tx_tag_present(skb)) {
- tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb);
+ if (likely(!np->vlangrp)) {
+ start_tx->txvlan = 0;
+ } else {
+ if (vlan_tx_tag_present(skb))
+ start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb));
+ else
+ start_tx->txvlan = 0;
}
+ spin_lock_irq(&np->lock);
+
/* set tx flags */
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
- } else {
- np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan);
- np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
- }
+ start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->put_tx.ex = put_tx;
+
+ spin_unlock_irq(&np->lock);
- dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
- dev->name, np->next_tx, entries, tx_flags_extra);
+ dprintk(KERN_DEBUG "%s: nv_start_xmit_optimized: entries %d queued for transmission. tx_flags_extra: %x\n",
+ dev->name, entries, tx_flags_extra);
{
int j;
for (j=0; j<64; j++) {
@@ -1583,12 +1866,8 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
dprintk("\n");
}
- np->next_tx += entries;
-
dev->trans_start = jiffies;
- spin_unlock_irq(&np->lock);
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
- pci_push(get_hwbase(dev));
return NETDEV_TX_OK;
}
@@ -1601,26 +1880,22 @@ static void nv_tx_done(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
u32 flags;
- unsigned int i;
- struct sk_buff *skb;
+ struct ring_desc* orig_get_tx = np->get_tx.orig;
- while (np->nic_tx != np->next_tx) {
- i = np->nic_tx % np->tx_ring_size;
+ while ((np->get_tx.orig != np->put_tx.orig) &&
+ !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- flags = le32_to_cpu(np->tx_ring.orig[i].flaglen);
- else
- flags = le32_to_cpu(np->tx_ring.ex[i].flaglen);
+ dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n",
+ dev->name, flags);
+
+ pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
+ np->get_tx_ctx->dma_len,
+ PCI_DMA_TODEVICE);
+ np->get_tx_ctx->dma = 0;
- dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n",
- dev->name, np->nic_tx, flags);
- if (flags & NV_TX_VALID)
- break;
if (np->desc_ver == DESC_VER_1) {
if (flags & NV_TX_LASTPACKET) {
- skb = np->tx_skbuff[i];
- if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
- NV_TX_UNDERFLOW|NV_TX_ERROR)) {
+ if (flags & NV_TX_ERROR) {
if (flags & NV_TX_UNDERFLOW)
np->stats.tx_fifo_errors++;
if (flags & NV_TX_CARRIERLOST)
@@ -1628,14 +1903,14 @@ static void nv_tx_done(struct net_device *dev)
np->stats.tx_errors++;
} else {
np->stats.tx_packets++;
- np->stats.tx_bytes += skb->len;
+ np->stats.tx_bytes += np->get_tx_ctx->skb->len;
}
+ dev_kfree_skb_any(np->get_tx_ctx->skb);
+ np->get_tx_ctx->skb = NULL;
}
} else {
if (flags & NV_TX2_LASTPACKET) {
- skb = np->tx_skbuff[i];
- if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
- NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
+ if (flags & NV_TX2_ERROR) {
if (flags & NV_TX2_UNDERFLOW)
np->stats.tx_fifo_errors++;
if (flags & NV_TX2_CARRIERLOST)
@@ -1643,15 +1918,56 @@ static void nv_tx_done(struct net_device *dev)
np->stats.tx_errors++;
} else {
np->stats.tx_packets++;
- np->stats.tx_bytes += skb->len;
+ np->stats.tx_bytes += np->get_tx_ctx->skb->len;
}
+ dev_kfree_skb_any(np->get_tx_ctx->skb);
+ np->get_tx_ctx->skb = NULL;
}
}
- nv_release_txskb(dev, i);
- np->nic_tx++;
+ if (unlikely(np->get_tx.orig++ == np->last_tx.orig))
+ np->get_tx.orig = np->first_tx.orig;
+ if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
+ np->get_tx_ctx = np->first_tx_ctx;
+ }
+ if (unlikely((np->tx_stop == 1) && (np->get_tx.orig != orig_get_tx))) {
+ np->tx_stop = 0;
+ netif_wake_queue(dev);
+ }
+}
+
+static void nv_tx_done_optimized(struct net_device *dev, int limit)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u32 flags;
+ struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
+
+ while ((np->get_tx.ex != np->put_tx.ex) &&
+ !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) &&
+ (limit-- > 0)) {
+
+ dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
+ dev->name, flags);
+
+ pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
+ np->get_tx_ctx->dma_len,
+ PCI_DMA_TODEVICE);
+ np->get_tx_ctx->dma = 0;
+
+ if (flags & NV_TX2_LASTPACKET) {
+ if (!(flags & NV_TX2_ERROR))
+ np->stats.tx_packets++;
+ dev_kfree_skb_any(np->get_tx_ctx->skb);
+ np->get_tx_ctx->skb = NULL;
+ }
+ if (unlikely(np->get_tx.ex++ == np->last_tx.ex))
+ np->get_tx.ex = np->first_tx.ex;
+ if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
+ np->get_tx_ctx = np->first_tx_ctx;
}
- if (np->next_tx - np->nic_tx < np->tx_limit_start)
+ if (unlikely((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx))) {
+ np->tx_stop = 0;
netif_wake_queue(dev);
+ }
}
/*
@@ -1674,9 +1990,8 @@ static void nv_tx_timeout(struct net_device *dev)
{
int i;
- printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n",
- dev->name, (unsigned long)np->ring_addr,
- np->next_tx, np->nic_tx);
+ printk(KERN_INFO "%s: Ring at %lx\n",
+ dev->name, (unsigned long)np->ring_addr);
printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
for (i=0;i<=np->register_size;i+= 32) {
printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
@@ -1724,13 +2039,16 @@ static void nv_tx_timeout(struct net_device *dev)
nv_stop_tx(dev);
/* 2) check that the packets were not sent already: */
- nv_tx_done(dev);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ nv_tx_done(dev);
+ else
+ nv_tx_done_optimized(dev, np->tx_ring_size);
/* 3) if there are dead entries: clear everything */
- if (np->next_tx != np->nic_tx) {
+ if (np->get_tx_ctx != np->put_tx_ctx) {
printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
nv_drain_tx(dev);
- np->next_tx = np->nic_tx = 0;
+ nv_init_tx(dev);
setup_hw_rings(dev, NV_SETUP_TX_RING);
netif_wake_queue(dev);
}
@@ -1797,40 +2115,27 @@ static int nv_rx_process(struct net_device *dev, int limit)
{
struct fe_priv *np = netdev_priv(dev);
u32 flags;
- u32 vlanflags = 0;
- int count;
-
- for (count = 0; count < limit; ++count) {
- struct sk_buff *skb;
- int len;
- int i;
- if (np->cur_rx - np->refill_rx >= np->rx_ring_size)
- break; /* we scanned the whole ring - do not continue */
-
- i = np->cur_rx % np->rx_ring_size;
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- flags = le32_to_cpu(np->rx_ring.orig[i].flaglen);
- len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
- } else {
- flags = le32_to_cpu(np->rx_ring.ex[i].flaglen);
- len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
- vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow);
- }
+ u32 rx_processed_cnt = 0;
+ struct sk_buff *skb;
+ int len;
- dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n",
- dev->name, np->cur_rx, flags);
+ while((np->get_rx.orig != np->put_rx.orig) &&
+ !((flags = le32_to_cpu(np->get_rx.orig->flaglen)) & NV_RX_AVAIL) &&
+ (rx_processed_cnt++ < limit)) {
- if (flags & NV_RX_AVAIL)
- break; /* still owned by hardware, */
+ dprintk(KERN_DEBUG "%s: nv_rx_process: flags 0x%x.\n",
+ dev->name, flags);
/*
* the packet is for us - immediately tear down the pci mapping.
* TODO: check if a prefetch of the first cacheline improves
* the performance.
*/
- pci_unmap_single(np->pci_dev, np->rx_dma[i],
- np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
+ pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
+ np->get_rx_ctx->dma_len,
PCI_DMA_FROMDEVICE);
+ skb = np->get_rx_ctx->skb;
+ np->get_rx_ctx->skb = NULL;
{
int j;
@@ -1838,123 +2143,228 @@ static int nv_rx_process(struct net_device *dev, int limit)
for (j=0; j<64; j++) {
if ((j%16) == 0)
dprintk("\n%03x:", j);
- dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
}
dprintk("\n");
}
/* look at what we actually got: */
if (np->desc_ver == DESC_VER_1) {
- if (!(flags & NV_RX_DESCRIPTORVALID))
- goto next_pkt;
-
- if (flags & NV_RX_ERROR) {
- if (flags & NV_RX_MISSEDFRAME) {
- np->stats.rx_missed_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX_CRCERR) {
- np->stats.rx_crc_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX_OVERFLOW) {
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
+ if (likely(flags & NV_RX_DESCRIPTORVALID)) {
+ len = flags & LEN_MASK_V1;
+ if (unlikely(flags & NV_RX_ERROR)) {
+ if (flags & NV_RX_ERROR4) {
+ len = nv_getlen(dev, skb->data, len);
+ if (len < 0) {
+ np->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
+ }
+ /* framing errors are soft errors */
+ else if (flags & NV_RX_FRAMINGERR) {
+ if (flags & NV_RX_SUBSTRACT1) {
+ len--;
+ }
+ }
+ /* the rest are hard errors */
+ else {
+ if (flags & NV_RX_MISSEDFRAME)
+ np->stats.rx_missed_errors++;
+ if (flags & NV_RX_CRCERR)
+ np->stats.rx_crc_errors++;
+ if (flags & NV_RX_OVERFLOW)
+ np->stats.rx_over_errors++;
+ np->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
}
- if (flags & NV_RX_ERROR4) {
- len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
- if (len < 0) {
+ } else {
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
+ } else {
+ if (likely(flags & NV_RX2_DESCRIPTORVALID)) {
+ len = flags & LEN_MASK_V2;
+ if (unlikely(flags & NV_RX2_ERROR)) {
+ if (flags & NV_RX2_ERROR4) {
+ len = nv_getlen(dev, skb->data, len);
+ if (len < 0) {
+ np->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
+ }
+ /* framing errors are soft errors */
+ else if (flags & NV_RX2_FRAMINGERR) {
+ if (flags & NV_RX2_SUBSTRACT1) {
+ len--;
+ }
+ }
+ /* the rest are hard errors */
+ else {
+ if (flags & NV_RX2_CRCERR)
+ np->stats.rx_crc_errors++;
+ if (flags & NV_RX2_OVERFLOW)
+ np->stats.rx_over_errors++;
np->stats.rx_errors++;
+ dev_kfree_skb(skb);
goto next_pkt;
}
}
- /* framing errors are soft errors. */
- if (flags & NV_RX_FRAMINGERR) {
- if (flags & NV_RX_SUBSTRACT1) {
- len--;
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
+ (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
}
}
- }
- } else {
- if (!(flags & NV_RX2_DESCRIPTORVALID))
+ } else {
+ dev_kfree_skb(skb);
goto next_pkt;
+ }
+ }
+ /* got a valid packet - forward it to the network core */
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
+ dprintk(KERN_DEBUG "%s: nv_rx_process: %d bytes, proto %d accepted.\n",
+ dev->name, len, skb->protocol);
+#ifdef CONFIG_FORCEDETH_NAPI
+ netif_receive_skb(skb);
+#else
+ netif_rx(skb);
+#endif
+ dev->last_rx = jiffies;
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += len;
+next_pkt:
+ if (unlikely(np->get_rx.orig++ == np->last_rx.orig))
+ np->get_rx.orig = np->first_rx.orig;
+ if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
+ np->get_rx_ctx = np->first_rx_ctx;
+ }
- if (flags & NV_RX2_ERROR) {
- if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX2_CRCERR) {
- np->stats.rx_crc_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX2_OVERFLOW) {
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
+ return rx_processed_cnt;
+}
+
+static int nv_rx_process_optimized(struct net_device *dev, int limit)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u32 flags;
+ u32 vlanflags = 0;
+ u32 rx_processed_cnt = 0;
+ struct sk_buff *skb;
+ int len;
+
+ while((np->get_rx.ex != np->put_rx.ex) &&
+ !((flags = le32_to_cpu(np->get_rx.ex->flaglen)) & NV_RX2_AVAIL) &&
+ (rx_processed_cnt++ < limit)) {
+
+ dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: flags 0x%x.\n",
+ dev->name, flags);
+
+ /*
+ * the packet is for us - immediately tear down the pci mapping.
+ * TODO: check if a prefetch of the first cacheline improves
+ * the performance.
+ */
+ pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
+ np->get_rx_ctx->dma_len,
+ PCI_DMA_FROMDEVICE);
+ skb = np->get_rx_ctx->skb;
+ np->get_rx_ctx->skb = NULL;
+
+ {
+ int j;
+ dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
+ for (j=0; j<64; j++) {
+ if ((j%16) == 0)
+ dprintk("\n%03x:", j);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+ }
+ dprintk("\n");
+ }
+ /* look at what we actually got: */
+ if (likely(flags & NV_RX2_DESCRIPTORVALID)) {
+ len = flags & LEN_MASK_V2;
+ if (unlikely(flags & NV_RX2_ERROR)) {
if (flags & NV_RX2_ERROR4) {
- len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+ len = nv_getlen(dev, skb->data, len);
if (len < 0) {
- np->stats.rx_errors++;
+ dev_kfree_skb(skb);
goto next_pkt;
}
}
/* framing errors are soft errors */
- if (flags & NV_RX2_FRAMINGERR) {
+ else if (flags & NV_RX2_FRAMINGERR) {
if (flags & NV_RX2_SUBSTRACT1) {
len--;
}
}
+ /* the rest are hard errors */
+ else {
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
}
- if (np->rx_csum) {
- flags &= NV_RX2_CHECKSUMMASK;
- if (flags == NV_RX2_CHECKSUMOK1 ||
- flags == NV_RX2_CHECKSUMOK2 ||
- flags == NV_RX2_CHECKSUMOK3) {
- dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
- np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
- } else {
- dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name);
+
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
+ (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
}
}
- }
- /* got a valid packet - forward it to the network core */
- skb = np->rx_skbuff[i];
- np->rx_skbuff[i] = NULL;
- skb_put(skb, len);
- skb->protocol = eth_type_trans(skb, dev);
- dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
- dev->name, np->cur_rx, len, skb->protocol);
+ /* got a valid packet - forward it to the network core */
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
+ prefetch(skb->data);
+
+ dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: %d bytes, proto %d accepted.\n",
+ dev->name, len, skb->protocol);
+
+ if (likely(!np->vlangrp)) {
#ifdef CONFIG_FORCEDETH_NAPI
- if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
- vlan_hwaccel_receive_skb(skb, np->vlangrp,
- vlanflags & NV_RX3_VLAN_TAG_MASK);
- else
- netif_receive_skb(skb);
+ netif_receive_skb(skb);
#else
- if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
- vlan_hwaccel_rx(skb, np->vlangrp,
- vlanflags & NV_RX3_VLAN_TAG_MASK);
- else
- netif_rx(skb);
+ netif_rx(skb);
#endif
- dev->last_rx = jiffies;
- np->stats.rx_packets++;
- np->stats.rx_bytes += len;
+ } else {
+ vlanflags = le32_to_cpu(np->get_rx.ex->buflow);
+ if (vlanflags & NV_RX3_VLAN_TAG_PRESENT) {
+#ifdef CONFIG_FORCEDETH_NAPI
+ vlan_hwaccel_receive_skb(skb, np->vlangrp,
+ vlanflags & NV_RX3_VLAN_TAG_MASK);
+#else
+ vlan_hwaccel_rx(skb, np->vlangrp,
+ vlanflags & NV_RX3_VLAN_TAG_MASK);
+#endif
+ } else {
+#ifdef CONFIG_FORCEDETH_NAPI
+ netif_receive_skb(skb);
+#else
+ netif_rx(skb);
+#endif
+ }
+ }
+
+ dev->last_rx = jiffies;
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += len;
+ } else {
+ dev_kfree_skb(skb);
+ }
next_pkt:
- np->cur_rx++;
+ if (unlikely(np->get_rx.ex++ == np->last_rx.ex))
+ np->get_rx.ex = np->first_rx.ex;
+ if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
+ np->get_rx_ctx = np->first_rx_ctx;
}
- return count;
+ return rx_processed_cnt;
}
static void set_bufsize(struct net_device *dev)
@@ -2430,7 +2840,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
}
- pci_push(base);
dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
@@ -2439,22 +2848,46 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
nv_tx_done(dev);
spin_unlock(&np->lock);
- if (events & NVREG_IRQ_LINK) {
+#ifdef CONFIG_FORCEDETH_NAPI
+ if (events & NVREG_IRQ_RX_ALL) {
+ netif_rx_schedule(dev);
+
+ /* Disable furthur receive irq's */
+ spin_lock(&np->lock);
+ np->irqmask &= ~NVREG_IRQ_RX_ALL;
+
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ spin_unlock(&np->lock);
+ }
+#else
+ if (nv_rx_process(dev, dev->weight)) {
+ if (unlikely(nv_alloc_rx(dev))) {
+ spin_lock(&np->lock);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock(&np->lock);
+ }
+ }
+#endif
+ if (unlikely(events & NVREG_IRQ_LINK)) {
spin_lock(&np->lock);
nv_link_irq(dev);
spin_unlock(&np->lock);
}
- if (np->need_linktimer && time_after(jiffies, np->link_timeout)) {
+ if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
spin_lock(&np->lock);
nv_linkchange(dev);
spin_unlock(&np->lock);
np->link_timeout = jiffies + LINK_TIMEOUT;
}
- if (events & (NVREG_IRQ_TX_ERR)) {
+ if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
dev->name, events);
}
- if (events & (NVREG_IRQ_UNKNOWN)) {
+ if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
dev->name, events);
}
@@ -2475,6 +2908,63 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
spin_unlock(&np->lock);
break;
}
+ if (unlikely(i > max_interrupt_work)) {
+ spin_lock(&np->lock);
+ /* disable interrupts on the nic */
+ if (!(np->msi_flags & NV_MSI_X_ENABLED))
+ writel(0, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ pci_push(base);
+
+ if (!np->in_shutdown) {
+ np->nic_poll_irq = np->irqmask;
+ mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+ }
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
+ spin_unlock(&np->lock);
+ break;
+ }
+
+ }
+ dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
+
+ return IRQ_RETVAL(i);
+}
+
+#define TX_WORK_PER_LOOP 64
+#define RX_WORK_PER_LOOP 64
+/**
+ * All _optimized functions are used to help increase performance
+ * (reduce CPU and increase throughput). They use descripter version 3,
+ * compiler directives, and reduce memory accesses.
+ */
+static irqreturn_t nv_nic_irq_optimized(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;
+
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name);
+
+ for (i=0; ; i++) {
+ if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+ events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
+ writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
+ } else {
+ events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
+ writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
+ }
+ dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
+ if (!(events & np->irqmask))
+ break;
+
+ spin_lock(&np->lock);
+ nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+ spin_unlock(&np->lock);
+
#ifdef CONFIG_FORCEDETH_NAPI
if (events & NVREG_IRQ_RX_ALL) {
netif_rx_schedule(dev);
@@ -2490,15 +2980,53 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
spin_unlock(&np->lock);
}
#else
- nv_rx_process(dev, dev->weight);
- if (nv_alloc_rx(dev)) {
+ if (nv_rx_process_optimized(dev, dev->weight)) {
+ if (unlikely(nv_alloc_rx_optimized(dev))) {
+ spin_lock(&np->lock);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock(&np->lock);
+ }
+ }
+#endif
+ if (unlikely(events & NVREG_IRQ_LINK)) {
spin_lock(&np->lock);
- if (!np->in_shutdown)
- mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ nv_link_irq(dev);
spin_unlock(&np->lock);
}
-#endif
- if (i > max_interrupt_work) {
+ if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+ spin_lock(&np->lock);
+ nv_linkchange(dev);
+ spin_unlock(&np->lock);
+ np->link_timeout = jiffies + LINK_TIMEOUT;
+ }
+ if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
+ dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
+ dev->name, events);
+ }
+ if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
+ printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
+ dev->name, events);
+ }
+ if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) {
+ spin_lock(&np->lock);
+ /* disable interrupts on the nic */
+ if (!(np->msi_flags & NV_MSI_X_ENABLED))
+ writel(0, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ pci_push(base);
+
+ if (!np->in_shutdown) {
+ np->nic_poll_irq = np->irqmask;
+ np->recover_error = 1;
+ mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+ }
+ spin_unlock(&np->lock);
+ break;
+ }
+
+ if (unlikely(i > max_interrupt_work)) {
spin_lock(&np->lock);
/* disable interrupts on the nic */
if (!(np->msi_flags & NV_MSI_X_ENABLED))
@@ -2517,7 +3045,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
}
}
- dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name);
return IRQ_RETVAL(i);
}
@@ -2536,20 +3064,19 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
for (i=0; ; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL;
writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus);
- pci_push(base);
dprintk(KERN_DEBUG "%s: tx irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
spin_lock_irqsave(&np->lock, flags);
- nv_tx_done(dev);
+ nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
spin_unlock_irqrestore(&np->lock, flags);
- if (events & (NVREG_IRQ_TX_ERR)) {
+ if (unlikely(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) {
+ if (unlikely(i > max_interrupt_work)) {
spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask);
@@ -2576,14 +3103,18 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
int pkts, limit = min(*budget, dev->quota);
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
+ unsigned long flags;
- pkts = nv_rx_process(dev, limit);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ pkts = nv_rx_process(dev, limit);
+ else
+ pkts = nv_rx_process_optimized(dev, limit);
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 (pkts < limit) {
@@ -2591,13 +3122,15 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
netif_rx_complete(dev);
/* re-enable receive interrupts */
- spin_lock_irq(&np->lock);
+ spin_lock_irqsave(&np->lock, flags);
+
np->irqmask |= NVREG_IRQ_RX_ALL;
if (np->msi_flags & NV_MSI_X_ENABLED)
writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
else
writel(np->irqmask, base + NvRegIrqMask);
- spin_unlock_irq(&np->lock);
+
+ spin_unlock_irqrestore(&np->lock, flags);
return 0;
} else {
/* used up our quantum, so reschedule */
@@ -2641,20 +3174,20 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
for (i=0; ; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
- pci_push(base);
dprintk(KERN_DEBUG "%s: rx irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
- nv_rx_process(dev, dev->weight);
- if (nv_alloc_rx(dev)) {
- spin_lock_irqsave(&np->lock, flags);
- if (!np->in_shutdown)
- mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
- spin_unlock_irqrestore(&np->lock, flags);
+ if (nv_rx_process_optimized(dev, dev->weight)) {
+ if (unlikely(nv_alloc_rx_optimized(dev))) {
+ spin_lock_irqsave(&np->lock, flags);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock_irqrestore(&np->lock, flags);
+ }
}
- if (i > max_interrupt_work) {
+ if (unlikely(i > max_interrupt_work)) {
spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
@@ -2689,11 +3222,15 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
for (i=0; ; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER;
writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus);
- pci_push(base);
dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
+ /* check tx in case we reached max loop limit in tx isr */
+ spin_lock_irqsave(&np->lock, flags);
+ nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+ spin_unlock_irqrestore(&np->lock, flags);
+
if (events & NVREG_IRQ_LINK) {
spin_lock_irqsave(&np->lock, flags);
nv_link_irq(dev);
@@ -2723,7 +3260,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
dev->name, events);
}
- if (i > max_interrupt_work) {
+ if (unlikely(i > max_interrupt_work)) {
spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_OTHER, base + NvRegIrqMask);
@@ -2806,6 +3343,16 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
u8 __iomem *base = get_hwbase(dev);
int ret = 1;
int i;
+ irqreturn_t (*handler)(int foo, void *data);
+
+ if (intr_test) {
+ handler = nv_nic_irq_test;
+ } else {
+ if (np->desc_ver == DESC_VER_3)
+ handler = nv_nic_irq_optimized;
+ else
+ handler = nv_nic_irq;
+ }
if (np->msi_flags & NV_MSI_X_CAPABLE) {
for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
@@ -2843,10 +3390,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER);
} else {
/* Request irq for all interrupts */
- if ((!intr_test &&
- request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
- (intr_test &&
- request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
+ if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, IRQF_SHARED, dev->name, dev) != 0) {
printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
@@ -2862,8 +3406,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
np->msi_flags |= NV_MSI_ENABLED;
- if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
- (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
+ if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) {
printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
pci_disable_msi(np->pci_dev);
np->msi_flags &= ~NV_MSI_ENABLED;
@@ -2878,8 +3421,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
}
}
if (ret != 0) {
- if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
- (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0))
+ if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0)
goto out_err;
}
@@ -3022,47 +3564,8 @@ static void nv_do_stats_poll(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
- u8 __iomem *base = get_hwbase(dev);
- np->estats.tx_bytes += readl(base + NvRegTxCnt);
- np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
- np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
- np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt);
- np->estats.tx_late_collision += readl(base + NvRegTxLateCol);
- np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow);
- np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier);
- np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef);
- np->estats.tx_retry_error += readl(base + NvRegTxRetryErr);
- np->estats.tx_deferral += readl(base + NvRegTxDef);
- np->estats.tx_packets += readl(base + NvRegTxFrame);
- np->estats.tx_pause += readl(base + NvRegTxPause);
- np->estats.rx_frame_error += readl(base + NvRegRxFrameErr);
- np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte);
- np->estats.rx_late_collision += readl(base + NvRegRxLateCol);
- np->estats.rx_runt += readl(base + NvRegRxRunt);
- np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong);
- np->estats.rx_over_errors += readl(base + NvRegRxOverflow);
- np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr);
- np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr);
- np->estats.rx_length_error += readl(base + NvRegRxLenErr);
- np->estats.rx_unicast += readl(base + NvRegRxUnicast);
- np->estats.rx_multicast += readl(base + NvRegRxMulticast);
- np->estats.rx_broadcast += readl(base + NvRegRxBroadcast);
- np->estats.rx_bytes += readl(base + NvRegRxCnt);
- np->estats.rx_pause += readl(base + NvRegRxPause);
- np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame);
- np->estats.rx_packets =
- np->estats.rx_unicast +
- np->estats.rx_multicast +
- np->estats.rx_broadcast;
- np->estats.rx_errors_total =
- np->estats.rx_crc_errors +
- np->estats.rx_over_errors +
- np->estats.rx_frame_error +
- (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) +
- np->estats.rx_late_collision +
- np->estats.rx_runt +
- np->estats.rx_frame_too_long;
+ nv_get_hw_stats(dev);
if (!np->in_shutdown)
mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
@@ -3436,7 +3939,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
- u8 *rxtx_ring, *rx_skbuff, *tx_skbuff, *rx_dma, *tx_dma, *tx_dma_len;
+ u8 *rxtx_ring, *rx_skbuff, *tx_skbuff;
dma_addr_t ring_addr;
if (ring->rx_pending < RX_RING_MIN ||
@@ -3462,12 +3965,9 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending),
&ring_addr);
}
- rx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->rx_pending, GFP_KERNEL);
- rx_dma = kmalloc(sizeof(dma_addr_t) * ring->rx_pending, GFP_KERNEL);
- tx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->tx_pending, GFP_KERNEL);
- tx_dma = kmalloc(sizeof(dma_addr_t) * ring->tx_pending, GFP_KERNEL);
- tx_dma_len = kmalloc(sizeof(unsigned int) * ring->tx_pending, GFP_KERNEL);
- if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
+ rx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->rx_pending, GFP_KERNEL);
+ tx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->tx_pending, GFP_KERNEL);
+ if (!rxtx_ring || !rx_skbuff || !tx_skbuff) {
/* fall back to old rings */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
if (rxtx_ring)
@@ -3480,14 +3980,8 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
}
if (rx_skbuff)
kfree(rx_skbuff);
- if (rx_dma)
- kfree(rx_dma);
if (tx_skbuff)
kfree(tx_skbuff);
- if (tx_dma)
- kfree(tx_dma);
- if (tx_dma_len)
- kfree(tx_dma_len);
goto exit;
}
@@ -3509,8 +4003,6 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
/* set new values */
np->rx_ring_size = ring->rx_pending;
np->tx_ring_size = ring->tx_pending;
- np->tx_limit_stop = ring->tx_pending - TX_LIMIT_DIFFERENCE;
- np->tx_limit_start = ring->tx_pending - TX_LIMIT_DIFFERENCE - 1;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig = (struct ring_desc*)rxtx_ring;
np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size];
@@ -3518,18 +4010,12 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
np->rx_ring.ex = (struct ring_desc_ex*)rxtx_ring;
np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
}
- np->rx_skbuff = (struct sk_buff**)rx_skbuff;
- np->rx_dma = (dma_addr_t*)rx_dma;
- np->tx_skbuff = (struct sk_buff**)tx_skbuff;
- np->tx_dma = (dma_addr_t*)tx_dma;
- np->tx_dma_len = (unsigned int*)tx_dma_len;
+ np->rx_skb = (struct nv_skb_map*)rx_skbuff;
+ np->tx_skb = (struct nv_skb_map*)tx_skbuff;
np->ring_addr = ring_addr;
- memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
- memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
- memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
- memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
- memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
+ memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
+ memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
if (netif_running(dev)) {
/* reinit driver view of the queues */
@@ -3698,8 +4184,10 @@ static int nv_get_stats_count(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- if (np->driver_data & DEV_HAS_STATISTICS)
- return sizeof(struct nv_ethtool_stats)/sizeof(u64);
+ if (np->driver_data & DEV_HAS_STATISTICS_V1)
+ return NV_DEV_STATISTICS_V1_COUNT;
+ else if (np->driver_data & DEV_HAS_STATISTICS_V2)
+ return NV_DEV_STATISTICS_V2_COUNT;
else
return 0;
}
@@ -3926,7 +4414,7 @@ static int nv_loopback_test(struct net_device *dev)
dprintk(KERN_DEBUG "%s: loopback len mismatch %d vs %d\n",
dev->name, len, pkt_len);
} else {
- rx_skb = np->rx_skbuff[0];
+ rx_skb = np->rx_skb[0].skb;
for (i = 0; i < pkt_len; i++) {
if (rx_skb->data[i] != (u8)(i & 0xff)) {
ret = 0;
@@ -4146,20 +4634,6 @@ static int nv_mgmt_acquire_sema(struct net_device *dev)
return 0;
}
-/* Indicate to mgmt unit whether driver is loaded or not */
-static void nv_mgmt_driver_loaded(struct net_device *dev, int loaded)
-{
- u8 __iomem *base = get_hwbase(dev);
- u32 tx_ctrl;
-
- tx_ctrl = readl(base + NvRegTransmitterControl);
- if (loaded)
- tx_ctrl |= NVREG_XMITCTL_HOST_LOADED;
- else
- tx_ctrl &= ~NVREG_XMITCTL_HOST_LOADED;
- writel(tx_ctrl, base + NvRegTransmitterControl);
-}
-
static int nv_open(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
@@ -4300,7 +4774,7 @@ static int nv_open(struct net_device *dev)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
/* start statistics timer */
- if (np->driver_data & DEV_HAS_STATISTICS)
+ if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2))
mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
spin_unlock_irq(&np->lock);
@@ -4397,7 +4871,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (err < 0)
goto out_disable;
- if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS))
+ if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V2))
+ np->register_size = NV_PCI_REGSZ_VER3;
+ else if (id->driver_data & DEV_HAS_STATISTICS_V1)
np->register_size = NV_PCI_REGSZ_VER2;
else
np->register_size = NV_PCI_REGSZ_VER1;
@@ -4460,10 +4936,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->rx_csum = 1;
np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-#ifdef NETIF_F_TSO
dev->features |= NETIF_F_TSO;
-#endif
- }
+ }
np->vlanctl_bits = 0;
if (id->driver_data & DEV_HAS_VLAN) {
@@ -4497,8 +4971,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->rx_ring_size = RX_RING_DEFAULT;
np->tx_ring_size = TX_RING_DEFAULT;
- np->tx_limit_stop = np->tx_ring_size - TX_LIMIT_DIFFERENCE;
- np->tx_limit_start = np->tx_ring_size - TX_LIMIT_DIFFERENCE - 1;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig = pci_alloc_consistent(pci_dev,
@@ -4515,22 +4987,19 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
goto out_unmap;
np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
}
- np->rx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->rx_ring_size, GFP_KERNEL);
- np->rx_dma = kmalloc(sizeof(dma_addr_t) * np->rx_ring_size, GFP_KERNEL);
- np->tx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->tx_ring_size, GFP_KERNEL);
- np->tx_dma = kmalloc(sizeof(dma_addr_t) * np->tx_ring_size, GFP_KERNEL);
- np->tx_dma_len = kmalloc(sizeof(unsigned int) * np->tx_ring_size, GFP_KERNEL);
- if (!np->rx_skbuff || !np->rx_dma || !np->tx_skbuff || !np->tx_dma || !np->tx_dma_len)
+ np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL);
+ np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL);
+ if (!np->rx_skb || !np->tx_skb)
goto out_freering;
- memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
- memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
- memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
- memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
- memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
+ memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
+ memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
dev->open = nv_open;
dev->stop = nv_close;
- dev->hard_start_xmit = nv_start_xmit;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ dev->hard_start_xmit = nv_start_xmit;
+ else
+ dev->hard_start_xmit = nv_start_xmit_optimized;
dev->get_stats = nv_get_stats;
dev->change_mtu = nv_change_mtu;
dev->set_mac_address = nv_set_mac_address;
@@ -4538,7 +5007,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = nv_poll_controller;
#endif
- dev->weight = 64;
+ dev->weight = RX_WORK_PER_LOOP;
#ifdef CONFIG_FORCEDETH_NAPI
dev->poll = nv_napi_poll;
#endif
@@ -4657,33 +5126,24 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
if (id->driver_data & DEV_HAS_MGMT_UNIT) {
- writel(0x1, base + 0x204); pci_push(base);
- msleep(500);
/* management unit running on the mac? */
- np->mac_in_use = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST;
- if (np->mac_in_use) {
- u32 mgmt_sync;
- /* management unit setup the phy already? */
- mgmt_sync = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK;
- if (mgmt_sync == NVREG_XMITCTL_SYNC_NOT_READY) {
- if (!nv_mgmt_acquire_sema(dev)) {
- for (i = 0; i < 5000; i++) {
- msleep(1);
- mgmt_sync = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK;
- if (mgmt_sync == NVREG_XMITCTL_SYNC_NOT_READY)
- continue;
- if (mgmt_sync == NVREG_XMITCTL_SYNC_PHY_INIT)
- phyinitialized = 1;
- break;
+ if (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_PHY_INIT) {
+ np->mac_in_use = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST;
+ dprintk(KERN_INFO "%s: mgmt unit is running. mac in use %x.\n", pci_name(pci_dev), np->mac_in_use);
+ for (i = 0; i < 5000; i++) {
+ msleep(1);
+ if (nv_mgmt_acquire_sema(dev)) {
+ /* management unit setup the phy already? */
+ if ((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK) ==
+ NVREG_XMITCTL_SYNC_PHY_INIT) {
+ /* phy is inited by mgmt unit */
+ phyinitialized = 1;
+ dprintk(KERN_INFO "%s: Phy already initialized by mgmt unit.\n", pci_name(pci_dev));
+ } else {
+ /* we need to init the phy */
}
- } else {
- /* we need to init the phy */
+ break;
}
- } else if (mgmt_sync == NVREG_XMITCTL_SYNC_PHY_INIT) {
- /* phy is inited by SMU */
- phyinitialized = 1;
- } else {
- /* we need to init the phy */
}
}
}
@@ -4722,10 +5182,12 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (!phyinitialized) {
/* reset it */
phy_init(dev);
- }
-
- if (id->driver_data & DEV_HAS_MGMT_UNIT) {
- nv_mgmt_driver_loaded(dev, 1);
+ } else {
+ /* see if it is a gigabit phy */
+ u32 mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
+ if (mii_status & PHY_GIGABIT) {
+ np->gigabit = PHY_GIGABIT;
+ }
}
/* set default link speed settings */
@@ -4747,8 +5209,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
out_error:
if (phystate_orig)
writel(phystate|NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl);
- if (np->mac_in_use)
- nv_mgmt_driver_loaded(dev, 0);
pci_set_drvdata(pci_dev, NULL);
out_freering:
free_rings(dev);
@@ -4778,9 +5238,6 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
writel(np->orig_mac[0], base + NvRegMacAddrA);
writel(np->orig_mac[1], base + NvRegMacAddrB);
- if (np->mac_in_use)
- nv_mgmt_driver_loaded(dev, 0);
-
/* free all structures */
free_rings(dev);
iounmap(get_hwbase(dev));
@@ -4865,83 +5322,83 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* CK804 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* CK804 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* MCP04 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* MCP04 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{0,},
};
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 92590d8fc24..569be225cd0 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -9,6 +9,7 @@
#include <linux/dma-mapping.h>
#include <linux/fs_enet_pd.h>
+#include <asm/fs_pd.h>
#ifdef CONFIG_CPM1
#include <asm/commproc.h>
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index c2c5fd419bd..ff683947730 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -104,9 +104,9 @@ static int do_pd_setup(struct fs_enet_private *fep)
fep->interrupt = platform_get_irq_byname(pdev,"interrupt");
if (fep->interrupt < 0)
return -EINVAL;
-
+
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
- fep->fec.fecp =(void*)r->start;
+ fep->fec.fecp = ioremap(r->start, r->end - r->start + 1);
if(fep->fec.fecp == NULL)
return -EINVAL;
@@ -319,11 +319,14 @@ static void restart(struct net_device *dev)
* Clear any outstanding interrupt.
*/
FW(fecp, ievent, 0xffc0);
+#ifndef CONFIG_PPC_MERGE
FW(fecp, ivec, (fep->interrupt / 2) << 29);
-
+#else
+ FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29);
+#endif
/*
- * adjust to speed (only for DUET & RMII)
+ * adjust to speed (only for DUET & RMII)
*/
#ifdef CONFIG_DUET
if (fpi->use_rmii) {
@@ -418,6 +421,7 @@ static void stop(struct net_device *dev)
static void pre_request_irq(struct net_device *dev, int irq)
{
+#ifndef CONFIG_PPC_MERGE
immap_t *immap = fs_enet_immap;
u32 siel;
@@ -431,6 +435,7 @@ static void pre_request_irq(struct net_device *dev, int irq)
siel &= ~(0x80000000 >> (irq & ~1));
out_be32(&immap->im_siu_conf.sc_siel, siel);
}
+#endif
}
static void post_free_irq(struct net_device *dev, int irq)
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 95ec5872c50..afd7fca7c6c 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -121,13 +121,13 @@ static int do_pd_setup(struct fs_enet_private *fep)
return -EINVAL;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
- fep->scc.sccp = (void *)r->start;
+ fep->scc.sccp = ioremap(r->start, r->end - r->start + 1);
if (fep->scc.sccp == NULL)
return -EINVAL;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram");
- fep->scc.ep = (void *)r->start;
+ fep->scc.ep = ioremap(r->start, r->end - r->start + 1);
if (fep->scc.ep == NULL)
return -EINVAL;
@@ -397,6 +397,7 @@ static void stop(struct net_device *dev)
static void pre_request_irq(struct net_device *dev, int irq)
{
+#ifndef CONFIG_PPC_MERGE
immap_t *immap = fs_enet_immap;
u32 siel;
@@ -410,6 +411,7 @@ static void pre_request_irq(struct net_device *dev, int irq)
siel &= ~(0x80000000 >> (irq & ~1));
out_be32(&immap->im_siu_conf.sc_siel, siel);
}
+#endif
}
static void post_free_irq(struct net_device *dev, int irq)
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 6d71bea5e90..0d6943d6709 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -42,8 +42,6 @@
#include "gianfar.h"
-#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
-
extern void gfar_start(struct net_device *dev);
extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 92420f007b9..760d04a671f 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -325,11 +325,6 @@ static int sp_rebuild_header(struct sk_buff *skb)
static void sp_setup(struct net_device *dev)
{
- static char ax25_bcast[AX25_ADDR_LEN] =
- {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
- static char ax25_test[AX25_ADDR_LEN] =
- {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
-
/* Finish setting up the DEVICE info. */
dev->mtu = SIXP_MTU;
dev->hard_start_xmit = sp_xmit;
@@ -347,8 +342,8 @@ static void sp_setup(struct net_device *dev)
dev->tx_timeout = NULL;
/* Only activated in AX.25 mode */
- memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
- memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
+ memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
+ memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
SET_MODULE_OWNER(dev);
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
index 896aa02000d..feb0ada7a02 100644
--- a/drivers/net/hamradio/Kconfig
+++ b/drivers/net/hamradio/Kconfig
@@ -113,7 +113,7 @@ config SCC_TRXECHO
config BAYCOM_SER_FDX
tristate "BAYCOM ser12 fullduplex driver for AX.25"
- depends on AX25
+ depends on AX25 && !S390
select CRC_CCITT
---help---
This is one of two drivers for Baycom style simple amateur radio
@@ -133,7 +133,7 @@ config BAYCOM_SER_FDX
config BAYCOM_SER_HDX
tristate "BAYCOM ser12 halfduplex driver for AX.25"
- depends on AX25
+ depends on AX25 && !S390
select CRC_CCITT
---help---
This is one of two drivers for Baycom style simple amateur radio
@@ -181,7 +181,7 @@ config BAYCOM_EPP
config YAM
tristate "YAM driver for AX.25"
- depends on AX25
+ depends on AX25 && !S390
help
The YAM is a modem for packet radio which connects to the serial
port and includes some of the functions of a Terminal Node
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 3c33d6f6a6a..153b6dc80af 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -1141,12 +1141,6 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
*/
static void baycom_probe(struct net_device *dev)
{
- static char ax25_bcast[AX25_ADDR_LEN] = {
- 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1
- };
- static char ax25_nocall[AX25_ADDR_LEN] = {
- 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1
- };
const struct hdlcdrv_channel_params dflt_ch_params = {
20, 2, 10, 40, 0
};
@@ -1182,8 +1176,8 @@ static void baycom_probe(struct net_device *dev)
dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */
dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
- memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
- memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN);
+ memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
+ memcpy(dev->dev_addr, &null_ax25_address, AX25_ADDR_LEN);
dev->tx_queue_len = 16;
/* New style flags */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 889f338132f..5b788d84011 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -88,11 +88,6 @@
static char banner[] __initdata = KERN_INFO "AX.25: bpqether driver version 004\n";
-static unsigned char ax25_bcast[AX25_ADDR_LEN] =
- {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
-static unsigned char ax25_defaddr[AX25_ADDR_LEN] =
- {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
-
static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
static char bpq_eth_addr[6];
@@ -487,8 +482,8 @@ static void bpq_setup(struct net_device *dev)
dev->do_ioctl = bpq_ioctl;
dev->destructor = free_netdev;
- memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
- memcpy(dev->dev_addr, ax25_defaddr, AX25_ADDR_LEN);
+ memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
+ memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
dev->flags = 0;
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index e6e721aff6f..0fbb414b5a4 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -264,12 +264,6 @@ static int io[MAX_NUM_DEVS] __initdata = { 0, };
/* Beware! hw[] is also used in cleanup_module(). */
static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE;
-static char ax25_broadcast[7] __initdata =
- { 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1,
-'0' << 1 };
-static char ax25_test[7] __initdata =
- { 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1,
-'1' << 1 };
/* Global variables */
@@ -443,8 +437,8 @@ static void __init dev_setup(struct net_device *dev)
dev->mtu = 1500;
dev->addr_len = AX25_ADDR_LEN;
dev->tx_queue_len = 64;
- memcpy(dev->broadcast, ax25_broadcast, AX25_ADDR_LEN);
- memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
+ memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
+ memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
}
static int __init setup_adapter(int card_base, int type, int n)
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index dacc7687b97..452873e7c68 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -63,18 +63,6 @@
/* --------------------------------------------------------------------- */
-/*
- * The name of the card. Is used for messages and in the requests for
- * io regions, irqs and dma channels
- */
-
-static char ax25_bcast[AX25_ADDR_LEN] =
-{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
-static char ax25_nocall[AX25_ADDR_LEN] =
-{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
-
-/* --------------------------------------------------------------------- */
-
#define KISS_VERBOSE
/* --------------------------------------------------------------------- */
@@ -709,8 +697,8 @@ static void hdlcdrv_setup(struct net_device *dev)
dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */
dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
- memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
- memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN);
+ memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
+ memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
dev->tx_queue_len = 16;
}
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index d8715b200c1..d08fbc39664 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -672,11 +672,6 @@ static struct net_device_stats *ax_get_stats(struct net_device *dev)
static void ax_setup(struct net_device *dev)
{
- static char ax25_bcast[AX25_ADDR_LEN] =
- {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
- static char ax25_test[AX25_ADDR_LEN] =
- {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
-
/* Finish setting up the DEVICE info. */
dev->mtu = AX_MTU;
dev->hard_start_xmit = ax_xmit;
@@ -691,8 +686,8 @@ static void ax_setup(struct net_device *dev)
dev->hard_header = ax_header;
dev->rebuild_header = ax_rebuild_header;
- memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
- memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
+ memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
+ memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
dev->flags = IFF_BROADCAST | IFF_MULTICAST;
}
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index ec9b6d9b6f0..2ce047e9d26 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1540,11 +1540,6 @@ static int scc_net_alloc(const char *name, struct scc_channel *scc)
/* * Network driver methods * */
/* ******************************************************************** */
-static unsigned char ax25_bcast[AX25_ADDR_LEN] =
-{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
-static unsigned char ax25_nocall[AX25_ADDR_LEN] =
-{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
-
/* ----> Initialize device <----- */
static void scc_net_setup(struct net_device *dev)
@@ -1562,8 +1557,8 @@ static void scc_net_setup(struct net_device *dev)
dev->do_ioctl = scc_net_ioctl;
dev->tx_timeout = NULL;
- memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
- memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN);
+ memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
+ memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
dev->flags = 0;
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 3c4455bd466..6d74f08720d 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -156,11 +156,6 @@ static struct net_device *yam_devs[NR_PORTS];
static struct yam_mcs *yam_data;
-static char ax25_bcast[7] =
-{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
-static char ax25_test[7] =
-{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
-
static DEFINE_TIMER(yam_timer, NULL, 0, 0);
/* --------------------------------------------------------------------- */
@@ -1115,8 +1110,8 @@ static void yam_setup(struct net_device *dev)
dev->hard_header_len = AX25_MAX_HEADER_LEN;
dev->mtu = AX25_MTU;
dev->addr_len = AX25_ADDR_LEN;
- memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
- memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
+ memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
+ memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
}
static int __init yam_init_driver(void)
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 844c136e992..7dc5185aa2c 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -3034,7 +3034,7 @@ static int __init hp100_module_init(void)
goto out2;
#endif
#ifdef CONFIG_PCI
- err = pci_module_init(&hp100_pci_driver);
+ err = pci_register_driver(&hp100_pci_driver);
if (err && err != -ENODEV)
goto out3;
#endif
diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c
index 9c643f2a8d5..c991cb82ff2 100644
--- a/drivers/net/hplance.c
+++ b/drivers/net/hplance.c
@@ -77,6 +77,7 @@ static int __devinit hplance_init_one(struct dio_dev *d,
{
struct net_device *dev;
int err = -ENOMEM;
+ int i;
dev = alloc_etherdev(sizeof(struct hplance_private));
if (!dev)
@@ -93,6 +94,15 @@ static int __devinit hplance_init_one(struct dio_dev *d,
goto out_release_mem_region;
dio_set_drvdata(d, dev);
+
+ printk(KERN_INFO "%s: %s; select code %d, addr %2.2x", dev->name, d->name, d->scode, dev->dev_addr[0]);
+
+ for (i=1; i<6; i++) {
+ printk(":%2.2x", dev->dev_addr[i]);
+ }
+
+ printk(", irq %d\n", d->ipl);
+
return 0;
out_release_mem_region:
@@ -119,8 +129,6 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
struct hplance_private *lp;
int i;
- printk(KERN_INFO "%s: %s; select code %d, addr", dev->name, d->name, d->scode);
-
/* reset the board */
out_8(va+DIO_IDOFF, 0xff);
udelay(100); /* ariba! ariba! udelay! udelay! */
@@ -143,7 +151,6 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
*/
dev->dev_addr[i] = ((in_8(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4)
| (in_8(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
- printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]);
}
lp = netdev_priv(dev);
@@ -160,7 +167,6 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
- printk(", irq %d\n", lp->lance.irq);
}
/* This is disgusting. We have to check the DIO status register for ack every
diff --git a/drivers/net/ibm_emac/ibm_emac_phy.c b/drivers/net/ibm_emac/ibm_emac_phy.c
index 4a97024061e..9074f76ee2b 100644
--- a/drivers/net/ibm_emac/ibm_emac_phy.c
+++ b/drivers/net/ibm_emac/ibm_emac_phy.c
@@ -309,7 +309,7 @@ int mii_phy_probe(struct mii_phy *phy, int address)
{
struct mii_phy_def *def;
int i;
- u32 id;
+ int id;
phy->autoneg = AUTONEG_DISABLE;
phy->advertising = 0;
@@ -324,6 +324,8 @@ int mii_phy_probe(struct mii_phy *phy, int address)
/* Read ID and find matching entry */
id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);
+ if (id < 0)
+ return -ENODEV;
for (i = 0; (def = mii_phy_table[i]) != NULL; i++)
if ((id & def->phy_id_mask) == def->phy_id)
break;
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index c26a4b8e552..ca2b21f9d44 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -154,8 +154,8 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
int ret = 0;
u32 from = G_TC_FROM(skb->tc_verd);
- stats->tx_packets++;
- stats->tx_bytes+=skb->len;
+ stats->rx_packets++;
+ stats->rx_bytes+=skb->len;
if (!from || !skb->input_dev) {
dropped:
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 16620bd97fb..11af0ae7510 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -1603,7 +1603,7 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid)
irda_qos_bits_to_value (&self->qos);
/* Allocate twice the size to guarantee alignment */
- self->ringbuf = (void *) kmalloc (OBOE_RING_LEN << 1, GFP_KERNEL);
+ self->ringbuf = kmalloc(OBOE_RING_LEN << 1, GFP_KERNEL);
if (!self->ringbuf)
{
printk (KERN_ERR DRIVER_NAME ": can't allocate DMA buffers\n");
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 6e95645e724..340ee99652e 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -441,25 +441,13 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
goto drop;
}
- /* Make sure there is room for IrDA-USB header. The actual
- * allocation will be done lower in skb_push().
- * Also, we don't use directly skb_cow(), because it require
- * headroom >= 16, which force unnecessary copies - Jean II */
- if (skb_headroom(skb) < self->header_length) {
- IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__);
- if (skb_cow(skb, self->header_length)) {
- IRDA_WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__);
- goto drop;
- }
- }
+ memcpy(self->tx_buff + self->header_length, skb->data, skb->len);
/* Change setting for next frame */
-
if (self->capability & IUC_STIR421X) {
__u8 turnaround_time;
- __u8* frame;
+ __u8* frame = self->tx_buff;
turnaround_time = get_turnaround_time( skb );
- frame= skb_push(skb, self->header_length);
irda_usb_build_header(self, frame, 0);
frame[2] = turnaround_time;
if ((skb->len != 0) &&
@@ -472,17 +460,17 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
frame[1] = 0;
}
} else {
- irda_usb_build_header(self, skb_push(skb, self->header_length), 0);
+ irda_usb_build_header(self, self->tx_buff, 0);
}
/* FIXME: Make macro out of this one */
((struct irda_skb_cb *)skb->cb)->context = self;
- usb_fill_bulk_urb(urb, self->usbdev,
+ usb_fill_bulk_urb(urb, self->usbdev,
usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
- skb->data, IRDA_SKB_MAX_MTU,
+ self->tx_buff, skb->len + self->header_length,
write_bulk_callback, skb);
- urb->transfer_buffer_length = skb->len;
+
/* This flag (URB_ZERO_PACKET) indicates that what we send is not
* a continuous stream of data but separate packets.
* In this case, the USB layer will insert an empty USB frame (TD)
@@ -1455,6 +1443,9 @@ static inline void irda_usb_close(struct irda_usb_cb *self)
/* Remove the speed buffer */
kfree(self->speed_buff);
self->speed_buff = NULL;
+
+ kfree(self->tx_buff);
+ self->tx_buff = NULL;
}
/********************** USB CONFIG SUBROUTINES **********************/
@@ -1524,8 +1515,6 @@ static inline int irda_usb_parse_endpoints(struct irda_usb_cb *self, struct usb_
IRDA_DEBUG(0, "%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n",
__FUNCTION__, self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep);
- /* Should be 8, 16, 32 or 64 bytes */
- IRDA_ASSERT(self->bulk_out_mtu == 64, ;);
return((self->bulk_in_ep != 0) && (self->bulk_out_ep != 0));
}
@@ -1747,15 +1736,20 @@ static int irda_usb_probe(struct usb_interface *intf,
/* Don't change this buffer size and allocation without doing
* some heavy and complete testing. Don't ask why :-(
* Jean II */
- self->speed_buff = (char *) kmalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL);
+ self->speed_buff = kmalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL);
if (self->speed_buff == NULL)
goto err_out_3;
memset(self->speed_buff, 0, IRDA_USB_SPEED_MTU);
+ self->tx_buff = kzalloc(IRDA_SKB_MAX_MTU + self->header_length,
+ GFP_KERNEL);
+ if (self->tx_buff == NULL)
+ goto err_out_4;
+
ret = irda_usb_open(self);
if (ret)
- goto err_out_4;
+ goto err_out_5;
IRDA_MESSAGE("IrDA: Registered device %s\n", net->name);
usb_set_intfdata(intf, self);
@@ -1766,14 +1760,14 @@ static int irda_usb_probe(struct usb_interface *intf,
self->needspatch = (ret < 0);
if (self->needspatch) {
IRDA_ERROR("STIR421X: Couldn't upload patch\n");
- goto err_out_5;
+ goto err_out_6;
}
/* replace IrDA class descriptor with what patched device is now reporting */
irda_desc = irda_usb_find_class_desc (self->usbintf);
if (irda_desc == NULL) {
ret = -ENODEV;
- goto err_out_5;
+ goto err_out_6;
}
if (self->irda_desc)
kfree (self->irda_desc);
@@ -1782,9 +1776,10 @@ static int irda_usb_probe(struct usb_interface *intf,
}
return 0;
-
-err_out_5:
+err_out_6:
unregister_netdev(self->netdev);
+err_out_5:
+ kfree(self->tx_buff);
err_out_4:
kfree(self->speed_buff);
err_out_3:
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index 6b2271f18e7..e846c38224a 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -156,6 +156,7 @@ struct irda_usb_cb {
struct irlap_cb *irlap; /* The link layer we are binded to */
struct qos_info qos;
char *speed_buff; /* Buffer for speed changes */
+ char *tx_buff;
struct timeval stamp;
struct timeval now;
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index 654a68b490a..3098960dc2a 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -164,7 +164,7 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
/* Allocate memory if needed */
if (self->tx_buff.truesize > 0) {
- self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize,
+ self->tx_buff.head = kmalloc(self->tx_buff.truesize,
GFP_KERNEL);
if (self->tx_buff.head == NULL) {
IRDA_ERROR("%s(), can't allocate memory for "
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 6a98b7ae497..ad1857364d5 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -117,7 +117,7 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
{
struct sirtty_cb *priv = dev->priv;
struct tty_struct *tty;
- struct termios old_termios;
+ struct ktermios old_termios;
int cflag;
IRDA_ASSERT(priv != NULL, return -1;);
@@ -318,7 +318,7 @@ static void irtty_write_wakeup(struct tty_struct *tty)
static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
{
- struct termios old_termios;
+ struct ktermios old_termios;
int cflag;
lock_kernel();
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index c14a74634fd..20d306fea4c 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -59,7 +59,7 @@
#include <asm/byteorder.h>
#include <asm/unaligned.h>
-MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
+MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
MODULE_DESCRIPTION("IrDA-USB Dongle Driver for SigmaTel STIr4200");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 18c68193bf1..e2b1af61845 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -166,7 +166,7 @@ static void vlsi_proc_pdev(struct seq_file *seq, struct pci_dev *pdev)
unsigned i;
seq_printf(seq, "\n%s (vid/did: %04x/%04x)\n",
- PCIDEV_NAME(pdev), (int)pdev->vendor, (int)pdev->device);
+ pci_name(pdev), (int)pdev->vendor, (int)pdev->device);
seq_printf(seq, "pci-power-state: %u\n", (unsigned) pdev->current_state);
seq_printf(seq, "resources: irq=%u / io=0x%04x / dma_mask=0x%016Lx\n",
pdev->irq, (unsigned)pci_resource_start(pdev, 0), (unsigned long long)pdev->dma_mask);
@@ -1401,7 +1401,7 @@ static void vlsi_tx_timeout(struct net_device *ndev)
if (vlsi_start_hw(idev))
IRDA_ERROR("%s: failed to restart hw - %s(%s) unusable!\n",
- __FUNCTION__, PCIDEV_NAME(idev->pdev), ndev->name);
+ __FUNCTION__, pci_name(idev->pdev), ndev->name);
else
netif_start_queue(ndev);
}
@@ -1643,7 +1643,7 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pdev->current_state = 0; /* hw must be running now */
IRDA_MESSAGE("%s: IrDA PCI controller %s detected\n",
- drivername, PCIDEV_NAME(pdev));
+ drivername, pci_name(pdev));
if ( !pci_resource_start(pdev,0)
|| !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) {
@@ -1728,7 +1728,7 @@ static void __devexit vlsi_irda_remove(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
- IRDA_MESSAGE("%s: %s removed\n", drivername, PCIDEV_NAME(pdev));
+ IRDA_MESSAGE("%s: %s removed\n", drivername, pci_name(pdev));
}
#ifdef CONFIG_PM
@@ -1748,7 +1748,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state)
if (!ndev) {
IRDA_ERROR("%s - %s: no netdevice \n",
- __FUNCTION__, PCIDEV_NAME(pdev));
+ __FUNCTION__, pci_name(pdev));
return 0;
}
idev = ndev->priv;
@@ -1759,7 +1759,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state)
pdev->current_state = state.event;
}
else
- IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state.event);
+ IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, pci_name(pdev), pdev->current_state, state.event);
up(&idev->sem);
return 0;
}
@@ -1787,7 +1787,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev)
if (!ndev) {
IRDA_ERROR("%s - %s: no netdevice \n",
- __FUNCTION__, PCIDEV_NAME(pdev));
+ __FUNCTION__, pci_name(pdev));
return 0;
}
idev = ndev->priv;
@@ -1795,7 +1795,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev)
if (pdev->current_state == 0) {
up(&idev->sem);
IRDA_WARNING("%s - %s: already resumed\n",
- __FUNCTION__, PCIDEV_NAME(pdev));
+ __FUNCTION__, pci_name(pdev));
return 0;
}
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index c37f0bc4c7f..2d3b773d8e3 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -41,39 +41,6 @@
#define PCI_CLASS_SUBCLASS_MASK 0xffff
#endif
-/* in recent 2.5 interrupt handlers have non-void return value */
-#ifndef IRQ_RETVAL
-typedef void irqreturn_t;
-#define IRQ_NONE
-#define IRQ_HANDLED
-#define IRQ_RETVAL(x)
-#endif
-
-/* some stuff need to check kernelversion. Not all 2.5 stuff was present
- * in early 2.5.x - the test is merely to separate 2.4 from 2.5
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-
-/* PDE() introduced in 2.5.4 */
-#ifdef CONFIG_PROC_FS
-#define PDE(inode) ((inode)->i_private)
-#endif
-
-/* irda crc16 calculation exported in 2.5.42 */
-#define irda_calc_crc16(fcs,buf,len) (GOOD_FCS)
-
-/* we use this for unified pci device name access */
-#define PCIDEV_NAME(pdev) ((pdev)->name)
-
-#else /* 2.5 or later */
-
-/* whatever we get from the associated struct device - bus:slot:dev.fn id */
-#define PCIDEV_NAME(pdev) (pci_name(pdev))
-
-#endif
-
/* ================================================================ */
/* non-standard PCI registers */
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index d6f4f185bf3..0e9ba3c3faf 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -73,7 +73,7 @@
#include <asm/abs_addr.h>
#include <asm/iseries/mf.h>
#include <asm/uaccess.h>
-
+#include <asm/firmware.h>
#include <asm/iseries/hv_lp_config.h>
#include <asm/iseries/hv_types.h>
#include <asm/iseries/hv_lp_event.h>
@@ -1102,7 +1102,7 @@ static struct net_device * __init veth_probe_one(int vlan,
}
kobject_init(&port->kobject);
- port->kobject.parent = &dev->class_dev.kobj;
+ port->kobject.parent = &dev->dev.kobj;
port->kobject.ktype = &veth_port_ktype;
kobject_set_name(&port->kobject, "veth_port");
if (0 != kobject_add(&port->kobject))
@@ -1668,7 +1668,7 @@ static struct vio_driver veth_driver = {
* Module initialization/cleanup
*/
-void __exit veth_module_cleanup(void)
+static void __exit veth_module_cleanup(void)
{
int i;
struct veth_lpar_connection *cnx;
@@ -1697,11 +1697,14 @@ void __exit veth_module_cleanup(void)
}
module_exit(veth_module_cleanup);
-int __init veth_module_init(void)
+static int __init veth_module_init(void)
{
int i;
int rc;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return -ENODEV;
+
this_lp = HvLpConfig_getLpIndex_outline();
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index 50ffe90488f..cf30a1059ce 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -61,9 +61,7 @@
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <linux/reboot.h>
-#ifdef NETIF_F_TSO
#include <net/checksum.h>
-#endif
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
@@ -171,6 +169,7 @@ struct ixgb_adapter {
/* TX */
struct ixgb_desc_ring tx_ring ____cacheline_aligned_in_smp;
+ unsigned int restart_queue;
unsigned long timeo_start;
uint32_t tx_cmd_type;
uint64_t hw_csum_tx_good;
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index cd22523fb03..d6628bd9590 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -79,12 +79,11 @@ static struct ixgb_stats ixgb_gstrings_stats[] = {
{"tx_window_errors", IXGB_STAT(net_stats.tx_window_errors)},
{"tx_deferred_ok", IXGB_STAT(stats.dc)},
{"tx_timeout_count", IXGB_STAT(tx_timeout_count) },
+ {"tx_restart_queue", IXGB_STAT(restart_queue) },
{"rx_long_length_errors", IXGB_STAT(stats.roc)},
{"rx_short_length_errors", IXGB_STAT(stats.ruc)},
-#ifdef NETIF_F_TSO
{"tx_tcp_seg_good", IXGB_STAT(stats.tsctc)},
{"tx_tcp_seg_failed", IXGB_STAT(stats.tsctfc)},
-#endif
{"rx_flow_control_xon", IXGB_STAT(stats.xonrxc)},
{"rx_flow_control_xoff", IXGB_STAT(stats.xoffrxc)},
{"tx_flow_control_xon", IXGB_STAT(stats.xontxc)},
@@ -239,7 +238,6 @@ ixgb_set_tx_csum(struct net_device *netdev, uint32_t data)
return 0;
}
-#ifdef NETIF_F_TSO
static int
ixgb_set_tso(struct net_device *netdev, uint32_t data)
{
@@ -249,7 +247,6 @@ ixgb_set_tso(struct net_device *netdev, uint32_t data)
netdev->features &= ~NETIF_F_TSO;
return 0;
}
-#endif /* NETIF_F_TSO */
static uint32_t
ixgb_get_msglevel(struct net_device *netdev)
@@ -721,10 +718,8 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
.set_sg = ethtool_op_set_sg,
.get_msglevel = ixgb_get_msglevel,
.set_msglevel = ixgb_set_msglevel,
-#ifdef NETIF_F_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = ixgb_set_tso,
-#endif
.get_strings = ixgb_get_strings,
.phys_id = ixgb_phys_id,
.get_stats_count = ixgb_get_stats_count,
diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c
index 02089b64e42..ecbf45861c6 100644
--- a/drivers/net/ixgb/ixgb_hw.c
+++ b/drivers/net/ixgb/ixgb_hw.c
@@ -399,8 +399,9 @@ ixgb_init_rx_addrs(struct ixgb_hw *hw)
/* Zero out the other 15 receive addresses. */
DEBUGOUT("Clearing RAR[1-15]\n");
for(i = 1; i < IXGB_RAR_ENTRIES; i++) {
- IXGB_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ /* Write high reg first to disable the AV bit first */
IXGB_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ IXGB_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
}
return;
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index e628126c9c4..0c368288934 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -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.117-k2"DRIVERNAPI
+#define DRV_VERSION "1.0.126-k2"DRIVERNAPI
char ixgb_driver_version[] = DRV_VERSION;
static char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
@@ -456,9 +456,7 @@ ixgb_probe(struct pci_dev *pdev,
NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER;
-#ifdef NETIF_F_TSO
netdev->features |= NETIF_F_TSO;
-#endif
#ifdef NETIF_F_LLTX
netdev->features |= NETIF_F_LLTX;
#endif
@@ -1176,7 +1174,6 @@ ixgb_watchdog(unsigned long data)
static int
ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
{
-#ifdef NETIF_F_TSO
struct ixgb_context_desc *context_desc;
unsigned int i;
uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
@@ -1233,7 +1230,6 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
return 1;
}
-#endif
return 0;
}
@@ -1287,6 +1283,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
struct ixgb_buffer *buffer_info;
int len = skb->len;
unsigned int offset = 0, size, count = 0, i;
+ unsigned int mss = skb_shinfo(skb)->gso_size;
unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
unsigned int f;
@@ -1298,6 +1295,11 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
while(len) {
buffer_info = &tx_ring->buffer_info[i];
size = min(len, IXGB_MAX_DATA_PER_TXD);
+ /* Workaround for premature desc write-backs
+ * in TSO mode. Append 4-byte sentinel desc */
+ if (unlikely(mss && !nr_frags && size == len && size > 8))
+ size -= 4;
+
buffer_info->length = size;
WARN_ON(buffer_info->dma != 0);
buffer_info->dma =
@@ -1324,6 +1326,13 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
while(len) {
buffer_info = &tx_ring->buffer_info[i];
size = min(len, IXGB_MAX_DATA_PER_TXD);
+
+ /* Workaround for premature desc write-backs
+ * in TSO mode. Append 4-byte sentinel desc */
+ if (unlikely(mss && !nr_frags && size == len
+ && size > 8))
+ size -= 4;
+
buffer_info->length = size;
buffer_info->dma =
pci_map_page(adapter->pdev,
@@ -1398,11 +1407,43 @@ ixgb_tx_queue(struct ixgb_adapter *adapter, int count, int vlan_id,int tx_flags)
IXGB_WRITE_REG(&adapter->hw, TDT, i);
}
+static int __ixgb_maybe_stop_tx(struct net_device *netdev, int size)
+{
+ struct ixgb_adapter *adapter = netdev_priv(netdev);
+ struct ixgb_desc_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(IXGB_DESC_UNUSED(tx_ring) < size))
+ return -EBUSY;
+
+ /* A reprieve! */
+ netif_start_queue(netdev);
+ ++adapter->restart_queue;
+ return 0;
+}
+
+static int ixgb_maybe_stop_tx(struct net_device *netdev,
+ struct ixgb_desc_ring *tx_ring, int size)
+{
+ if (likely(IXGB_DESC_UNUSED(tx_ring) >= size))
+ return 0;
+ return __ixgb_maybe_stop_tx(netdev, size);
+}
+
+
/* Tx Descriptors needed, worst case */
#define TXD_USE_COUNT(S) (((S) >> IXGB_MAX_TXD_PWR) + \
(((S) & (IXGB_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
-#define DESC_NEEDED TXD_USE_COUNT(IXGB_MAX_DATA_PER_TXD) + \
- MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1
+#define DESC_NEEDED TXD_USE_COUNT(IXGB_MAX_DATA_PER_TXD) /* skb->date */ + \
+ MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1 /* for context */ \
+ + 1 /* one more needed for sentinel TSO workaround */
static int
ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
@@ -1430,7 +1471,8 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
spin_lock_irqsave(&adapter->tx_lock, flags);
#endif
- if(unlikely(IXGB_DESC_UNUSED(&adapter->tx_ring) < DESC_NEEDED)) {
+ if (unlikely(ixgb_maybe_stop_tx(netdev, &adapter->tx_ring,
+ DESC_NEEDED))) {
netif_stop_queue(netdev);
spin_unlock_irqrestore(&adapter->tx_lock, flags);
return NETDEV_TX_BUSY;
@@ -1468,8 +1510,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
#ifdef NETIF_F_LLTX
/* Make sure there is space in the ring for the next send. */
- if(unlikely(IXGB_DESC_UNUSED(&adapter->tx_ring) < DESC_NEEDED))
- netif_stop_queue(netdev);
+ ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, DESC_NEEDED);
spin_unlock_irqrestore(&adapter->tx_lock, flags);
@@ -1564,7 +1605,7 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
/* Prevent stats update while adapter is being reset */
- if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+ if (pci_channel_offline(pdev))
return;
if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) ||
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 82c10dec1b5..2b739fd584f 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -229,9 +229,11 @@ struct net_device loopback_dev = {
};
/* Setup and register the loopback device. */
-int __init loopback_init(void)
+static int __init loopback_init(void)
{
return register_netdev(&loopback_dev);
};
+module_init(loopback_init);
+
EXPORT_SYMBOL(loopback_dev);
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index b833016f182..177c502f738 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -884,7 +884,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
dev->trans_start = jiffies;
- tx_cmd = (struct tx_cmd *) kmalloc ((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
+ tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
if (tx_cmd == NULL) {
printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
lp->stats.tx_dropped++;
@@ -1266,7 +1266,7 @@ static void set_multicast_list(struct net_device *dev) {
if (dev->mc_count > 0) {
struct dev_mc_list *dmi;
char *cp;
- cmd = (struct i596_cmd *)kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, GFP_ATOMIC);
+ cmd = kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, GFP_ATOMIC);
if (cmd == NULL) {
printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name);
return;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index bd0ce98c939..e67361e2bf5 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -27,8 +27,6 @@
#include "macb.h"
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
-
#define RX_BUFFER_SIZE 128
#define RX_RING_SIZE 512
#define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE)
@@ -264,12 +262,12 @@ static void macb_update_stats(struct macb *bp)
WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4);
for(; p < end; p++, reg++)
- *p += readl(reg);
+ *p += __raw_readl(reg);
}
-static void macb_periodic_task(void *arg)
+static void macb_periodic_task(struct work_struct *work)
{
- struct macb *bp = arg;
+ struct macb *bp = container_of(work, struct macb, periodic_task.work);
macb_update_stats(bp);
macb_check_media(bp, 1, 0);
@@ -945,10 +943,10 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return ret;
}
-static ssize_t macb_mii_show(const struct class_device *cd, char *buf,
+static ssize_t macb_mii_show(const struct device *_dev, char *buf,
unsigned long addr)
{
- struct net_device *dev = to_net_dev(cd);
+ struct net_device *dev = to_net_dev(_dev);
struct macb *bp = netdev_priv(dev);
ssize_t ret = -EINVAL;
@@ -962,11 +960,13 @@ static ssize_t macb_mii_show(const struct class_device *cd, char *buf,
}
#define MII_ENTRY(name, addr) \
-static ssize_t show_##name(struct class_device *cd, char *buf) \
+static ssize_t show_##name(struct device *_dev, \
+ struct device_attribute *attr, \
+ char *buf) \
{ \
- return macb_mii_show(cd, buf, addr); \
+ return macb_mii_show(_dev, buf, addr); \
} \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
MII_ENTRY(bmcr, MII_BMCR);
MII_ENTRY(bmsr, MII_BMSR);
@@ -977,13 +977,13 @@ MII_ENTRY(lpa, MII_LPA);
MII_ENTRY(expansion, MII_EXPANSION);
static struct attribute *macb_mii_attrs[] = {
- &class_device_attr_bmcr.attr,
- &class_device_attr_bmsr.attr,
- &class_device_attr_physid1.attr,
- &class_device_attr_physid2.attr,
- &class_device_attr_advertise.attr,
- &class_device_attr_lpa.attr,
- &class_device_attr_expansion.attr,
+ &dev_attr_bmcr.attr,
+ &dev_attr_bmsr.attr,
+ &dev_attr_physid1.attr,
+ &dev_attr_physid2.attr,
+ &dev_attr_advertise.attr,
+ &dev_attr_lpa.attr,
+ &dev_attr_expansion.attr,
NULL,
};
@@ -994,17 +994,17 @@ static struct attribute_group macb_mii_group = {
static void macb_unregister_sysfs(struct net_device *net)
{
- struct class_device *class_dev = &net->class_dev;
+ struct device *_dev = &net->dev;
- sysfs_remove_group(&class_dev->kobj, &macb_mii_group);
+ sysfs_remove_group(&_dev->kobj, &macb_mii_group);
}
static int macb_register_sysfs(struct net_device *net)
{
- struct class_device *class_dev = &net->class_dev;
+ struct device *_dev = &net->dev;
int ret;
- ret = sysfs_create_group(&class_dev->kobj, &macb_mii_group);
+ ret = sysfs_create_group(&_dev->kobj, &macb_mii_group);
if (ret)
printk(KERN_WARNING
"%s: sysfs mii attribute registration failed: %d\n",
@@ -1046,6 +1046,14 @@ static int __devinit macb_probe(struct platform_device *pdev)
spin_lock_init(&bp->lock);
+#if defined(CONFIG_ARCH_AT91)
+ bp->pclk = clk_get(&pdev->dev, "macb_clk");
+ if (IS_ERR(bp->pclk)) {
+ dev_err(&pdev->dev, "failed to get macb_clk\n");
+ goto err_out_free_dev;
+ }
+ clk_enable(bp->pclk);
+#else
bp->pclk = clk_get(&pdev->dev, "pclk");
if (IS_ERR(bp->pclk)) {
dev_err(&pdev->dev, "failed to get pclk\n");
@@ -1059,6 +1067,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
clk_enable(bp->pclk);
clk_enable(bp->hclk);
+#endif
bp->regs = ioremap(regs->start, regs->end - regs->start + 1);
if (!bp->regs) {
@@ -1088,7 +1097,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
dev->base_addr = regs->start;
- INIT_WORK(&bp->periodic_task, macb_periodic_task, bp);
+ INIT_DELAYED_WORK(&bp->periodic_task, macb_periodic_task);
mutex_init(&bp->mdio_mutex);
init_completion(&bp->mdio_complete);
@@ -1119,9 +1128,17 @@ static int __devinit macb_probe(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
if (pdata && pdata->is_rmii)
+#if defined(CONFIG_ARCH_AT91)
+ macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) );
+#else
macb_writel(bp, USRIO, 0);
+#endif
else
+#if defined(CONFIG_ARCH_AT91)
+ macb_writel(bp, USRIO, MACB_BIT(CLKEN));
+#else
macb_writel(bp, USRIO, MACB_BIT(MII));
+#endif
bp->tx_pending = DEF_TX_RING_PENDING;
@@ -1148,9 +1165,11 @@ err_out_free_irq:
err_out_iounmap:
iounmap(bp->regs);
err_out_disable_clocks:
+#ifndef CONFIG_ARCH_AT91
clk_disable(bp->hclk);
- clk_disable(bp->pclk);
clk_put(bp->hclk);
+#endif
+ clk_disable(bp->pclk);
err_out_put_pclk:
clk_put(bp->pclk);
err_out_free_dev:
@@ -1173,9 +1192,11 @@ static int __devexit macb_remove(struct platform_device *pdev)
unregister_netdev(dev);
free_irq(dev->irq, dev);
iounmap(bp->regs);
+#ifndef CONFIG_ARCH_AT91
clk_disable(bp->hclk);
- clk_disable(bp->pclk);
clk_put(bp->hclk);
+#endif
+ clk_disable(bp->pclk);
clk_put(bp->pclk);
free_netdev(dev);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 8c253db6988..b3bb2182edd 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -200,7 +200,7 @@
#define MACB_SOF_OFFSET 30
#define MACB_SOF_SIZE 2
-/* Bitfields in USRIO */
+/* Bitfields in USRIO (AVR32) */
#define MACB_MII_OFFSET 0
#define MACB_MII_SIZE 1
#define MACB_EAM_OFFSET 1
@@ -210,6 +210,12 @@
#define MACB_TX_PAUSE_ZERO_OFFSET 3
#define MACB_TX_PAUSE_ZERO_SIZE 1
+/* Bitfields in USRIO (AT91) */
+#define MACB_RMII_OFFSET 0
+#define MACB_RMII_SIZE 1
+#define MACB_CLKEN_OFFSET 1
+#define MACB_CLKEN_SIZE 1
+
/* Bitfields in WOL */
#define MACB_IP_OFFSET 0
#define MACB_IP_SIZE 16
@@ -250,9 +256,9 @@
/* Register access macros */
#define macb_readl(port,reg) \
- readl((port)->regs + MACB_##reg)
+ __raw_readl((port)->regs + MACB_##reg)
#define macb_writel(port,reg,value) \
- writel((value), (port)->regs + MACB_##reg)
+ __raw_writel((value), (port)->regs + MACB_##reg)
struct dma_desc {
u32 addr;
@@ -377,7 +383,7 @@ struct macb {
unsigned int rx_pending, tx_pending;
- struct work_struct periodic_task;
+ struct delayed_work periodic_task;
struct mutex mdio_mutex;
struct completion mdio_complete;
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 2907cfb12ad..9ec24f0d5d6 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/crc32.h>
#include <linux/spinlock.h>
+#include <linux/bitrev.h>
#include <asm/prom.h>
#include <asm/dbdma.h>
#include <asm/io.h>
@@ -74,7 +75,6 @@ struct mace_data {
#define PRIV_BYTES (sizeof(struct mace_data) \
+ (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
-static int bitrev(int);
static int mace_open(struct net_device *dev);
static int mace_close(struct net_device *dev);
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
@@ -96,18 +96,6 @@ static void __mace_set_address(struct net_device *dev, void *addr);
*/
static unsigned char *dummy_buf;
-/* Bit-reverse one byte of an ethernet hardware address. */
-static inline int
-bitrev(int b)
-{
- int d = 0, i;
-
- for (i = 0; i < 8; ++i, b >>= 1)
- d = (d << 1) | (b & 1);
- return d;
-}
-
-
static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
struct device_node *mace = macio_get_of_node(mdev);
@@ -173,7 +161,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
rev = addr[0] == 0 && addr[1] == 0xA0;
for (j = 0; j < 6; ++j) {
- dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+ dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
}
mp->chipid = (in_8(&mp->mace->chipid_hi) << 8) |
in_8(&mp->mace->chipid_lo);
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 464e4a6f3d5..5d541e87304 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/crc32.h>
+#include <linux/bitrev.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
@@ -81,19 +82,6 @@ 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. */
-
-static int bitrev(int b)
-{
- int d = 0, i;
-
- for (i = 0; i < 8; ++i, b >>= 1) {
- d = (d << 1) | (b & 1);
- }
-
- return d;
-}
-
/*
* Load a receive DMA channel with a base address and ring length
*/
@@ -219,12 +207,12 @@ struct net_device *mace_probe(int unit)
addr = (void *)MACE_PROM;
for (j = 0; j < 6; ++j) {
- u8 v=bitrev(addr[j<<4]);
+ u8 v = bitrev8(addr[j<<4]);
checksum ^= v;
dev->dev_addr[j] = v;
}
for (; j < 8; ++j) {
- checksum ^= bitrev(addr[j<<4]);
+ checksum ^= bitrev8(addr[j<<4]);
}
if (checksum != 0xFF) {
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index 393d995f191..8ca57a0a4c1 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -49,6 +49,7 @@
#include <linux/skbuff.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/bitrev.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
@@ -121,16 +122,12 @@ enum macsonic_type {
* For reversing the PROM address
*/
-static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
- 1, 9, 5, 13, 3, 11, 7, 15};
-
static inline void bit_reverse_addr(unsigned char addr[6])
{
int i;
for(i = 0; i < 6; i++)
- addr[i] = ((nibbletab[addr[i] & 0xf] << 4) |
- nibbletab[(addr[i] >> 4) &0xf]);
+ addr[i] = bitrev8(addr[i]);
}
int __init macsonic_init(struct net_device* dev)
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index c41ae4286ee..d98e53efa2e 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -314,6 +314,13 @@ int mv643xx_eth_free_tx_descs(struct net_device *dev, int force)
while (mp->tx_desc_count > 0) {
spin_lock_irqsave(&mp->lock, flags);
+
+ /* tx_desc_count might have changed before acquiring the lock */
+ if (mp->tx_desc_count <= 0) {
+ spin_unlock_irqrestore(&mp->lock, flags);
+ return released;
+ }
+
tx_index = mp->tx_used_desc_q;
desc = &mp->p_tx_desc_area[tx_index];
cmd_sts = desc->cmd_sts;
@@ -332,13 +339,13 @@ int mv643xx_eth_free_tx_descs(struct net_device *dev, int force)
if (skb)
mp->tx_skb[tx_index] = NULL;
- spin_unlock_irqrestore(&mp->lock, flags);
-
if (cmd_sts & ETH_ERROR_SUMMARY) {
printk("%s: Error in TX\n", dev->name);
mp->stats.tx_errors++;
}
+ spin_unlock_irqrestore(&mp->lock, flags);
+
if (cmd_sts & ETH_TX_FIRST_DESC)
dma_unmap_single(NULL, addr, count, DMA_TO_DEVICE);
else
@@ -2773,7 +2780,6 @@ static const struct ethtool_ops mv643xx_ethtool_ops = {
.get_link = mv643xx_eth_get_link,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_strings = mv643xx_get_strings,
.get_stats_count = mv643xx_get_stats_count,
.get_ethtool_stats = mv643xx_get_ethtool_stats,
.get_strings = mv643xx_get_strings,
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 81f127a78af..030924fb1ab 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -71,7 +71,7 @@
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
-#define MYRI10GE_VERSION_STR "1.0.0"
+#define MYRI10GE_VERSION_STR "1.2.0"
MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -92,8 +92,13 @@ MODULE_LICENSE("Dual BSD/GPL");
#define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff)
#define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff
+#define MYRI10GE_ALLOC_ORDER 0
+#define MYRI10GE_ALLOC_SIZE ((1 << MYRI10GE_ALLOC_ORDER) * PAGE_SIZE)
+#define MYRI10GE_MAX_FRAGS_PER_FRAME (MYRI10GE_MAX_ETHER_MTU/MYRI10GE_ALLOC_SIZE + 1)
+
struct myri10ge_rx_buffer_state {
- struct sk_buff *skb;
+ struct page *page;
+ int page_offset;
DECLARE_PCI_UNMAP_ADDR(bus)
DECLARE_PCI_UNMAP_LEN(len)
};
@@ -116,9 +121,14 @@ struct myri10ge_rx_buf {
u8 __iomem *wc_fifo; /* w/c rx dma addr fifo address */
struct mcp_kreq_ether_recv *shadow; /* host shadow of recv ring */
struct myri10ge_rx_buffer_state *info;
+ struct page *page;
+ dma_addr_t bus;
+ int page_offset;
int cnt;
+ int fill_cnt;
int alloc_fail;
int mask; /* number of rx slots -1 */
+ int watchdog_needed;
};
struct myri10ge_tx_buf {
@@ -150,6 +160,7 @@ struct myri10ge_priv {
struct myri10ge_rx_buf rx_big;
struct myri10ge_rx_done rx_done;
int small_bytes;
+ int big_bytes;
struct net_device *dev;
struct net_device_stats stats;
u8 __iomem *sram;
@@ -188,8 +199,6 @@ struct myri10ge_priv {
unsigned long serial_number;
int vendor_specific_offset;
int fw_multicast_support;
- u32 devctl;
- u16 msi_flags;
u32 read_dma;
u32 write_dma;
u32 read_write_dma;
@@ -217,7 +226,7 @@ module_param(myri10ge_small_bytes, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(myri10ge_small_bytes, "Threshold of small packets\n");
static int myri10ge_msi = 1; /* enable msi by default */
-module_param(myri10ge_msi, int, S_IRUGO);
+module_param(myri10ge_msi, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(myri10ge_msi, "Enable Message Signalled Interrupts\n");
static int myri10ge_intr_coal_delay = 25;
@@ -238,11 +247,6 @@ module_param(myri10ge_force_firmware, int, S_IRUGO);
MODULE_PARM_DESC(myri10ge_force_firmware,
"Force firmware to assume aligned completions\n");
-static int myri10ge_skb_cross_4k = 0;
-module_param(myri10ge_skb_cross_4k, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(myri10ge_skb_cross_4k,
- "Can a small skb cross a 4KB boundary?\n");
-
static int myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;
module_param(myri10ge_initial_mtu, int, S_IRUGO);
MODULE_PARM_DESC(myri10ge_initial_mtu, "Initial MTU\n");
@@ -266,6 +270,14 @@ static int myri10ge_debug = -1; /* defaults above */
module_param(myri10ge_debug, int, 0);
MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
+static int myri10ge_fill_thresh = 256;
+module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n");
+
+static int myri10ge_wcfifo = 1;
+module_param(myri10ge_wcfifo, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n");
+
#define MYRI10GE_FW_OFFSET 1024*1024
#define MYRI10GE_HIGHPART_TO_U32(X) \
(sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0)
@@ -273,9 +285,9 @@ MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
-static inline void put_be32(__be32 val, __be32 __iomem *p)
+static inline void put_be32(__be32 val, __be32 __iomem * p)
{
- __raw_writel((__force __u32)val, (__force void __iomem *)p);
+ __raw_writel((__force __u32) val, (__force void __iomem *)p);
}
static int
@@ -711,12 +723,10 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
status |=
myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0);
mgp->irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0);
- if (!mgp->msi_enabled) {
- status |= myri10ge_send_cmd
- (mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, &cmd, 0);
- mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0);
+ status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET,
+ &cmd, 0);
+ mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0);
- }
status |= myri10ge_send_cmd
(mgp, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd, 0);
mgp->intr_coal_delay_ptr = (__iomem __be32 *) (mgp->sram + cmd.data0);
@@ -804,194 +814,179 @@ myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst,
mb();
}
-/*
- * Set of routines to get a new receive buffer. Any buffer which
- * crosses a 4KB boundary must start on a 4KB boundary due to PCIe
- * wdma restrictions. We also try to align any smaller allocation to
- * at least a 16 byte boundary for efficiency. We assume the linux
- * memory allocator works by powers of 2, and will not return memory
- * smaller than 2KB which crosses a 4KB boundary. If it does, we fall
- * back to allocating 2x as much space as required.
- *
- * We intend to replace large (>4KB) skb allocations by using
- * pages directly and building a fraglist in the near future.
- */
-
-static inline struct sk_buff *myri10ge_alloc_big(struct net_device *dev,
- int bytes)
-{
- struct sk_buff *skb;
- unsigned long data, roundup;
-
- skb = netdev_alloc_skb(dev, bytes + 4096 + MXGEFW_PAD);
- if (skb == NULL)
- return NULL;
-
- /* Correct skb->truesize so that socket buffer
- * accounting is not confused the rounding we must
- * do to satisfy alignment constraints.
- */
- skb->truesize -= 4096;
-
- data = (unsigned long)(skb->data);
- roundup = (-data) & (4095);
- skb_reserve(skb, roundup);
- return skb;
-}
-
-/* Allocate 2x as much space as required and use whichever portion
- * does not cross a 4KB boundary */
-static inline struct sk_buff *myri10ge_alloc_small_safe(struct net_device *dev,
- unsigned int bytes)
+static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, __wsum hw_csum)
{
- struct sk_buff *skb;
- unsigned long data, boundary;
-
- skb = netdev_alloc_skb(dev, 2 * (bytes + MXGEFW_PAD) - 1);
- if (unlikely(skb == NULL))
- return NULL;
-
- /* Correct skb->truesize so that socket buffer
- * accounting is not confused the rounding we must
- * do to satisfy alignment constraints.
- */
- skb->truesize -= bytes + MXGEFW_PAD;
-
- data = (unsigned long)(skb->data);
- boundary = (data + 4095UL) & ~4095UL;
- if ((boundary - data) >= (bytes + MXGEFW_PAD))
- return skb;
+ struct vlan_hdr *vh = (struct vlan_hdr *)(skb->data);
- skb_reserve(skb, boundary - data);
- return skb;
+ if ((skb->protocol == htons(ETH_P_8021Q)) &&
+ (vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) ||
+ vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) {
+ skb->csum = hw_csum;
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ }
}
-/* Allocate just enough space, and verify that the allocated
- * space does not cross a 4KB boundary */
-static inline struct sk_buff *myri10ge_alloc_small(struct net_device *dev,
- int bytes)
+static inline void
+myri10ge_rx_skb_build(struct sk_buff *skb, u8 * va,
+ struct skb_frag_struct *rx_frags, int len, int hlen)
{
- struct sk_buff *skb;
- unsigned long roundup, data, end;
-
- skb = netdev_alloc_skb(dev, bytes + 16 + MXGEFW_PAD);
- if (unlikely(skb == NULL))
- return NULL;
-
- /* Round allocated buffer to 16 byte boundary */
- data = (unsigned long)(skb->data);
- roundup = (-data) & 15UL;
- skb_reserve(skb, roundup);
- /* Verify that the data buffer does not cross a page boundary */
- data = (unsigned long)(skb->data);
- end = data + bytes + MXGEFW_PAD - 1;
- if (unlikely(((end >> 12) != (data >> 12)) && (data & 4095UL))) {
- printk(KERN_NOTICE
- "myri10ge_alloc_small: small skb crossed 4KB boundary\n");
- myri10ge_skb_cross_4k = 1;
- dev_kfree_skb_any(skb);
- skb = myri10ge_alloc_small_safe(dev, bytes);
- }
- return skb;
+ struct skb_frag_struct *skb_frags;
+
+ skb->len = skb->data_len = len;
+ skb->truesize = len + sizeof(struct sk_buff);
+ /* attach the page(s) */
+
+ skb_frags = skb_shinfo(skb)->frags;
+ while (len > 0) {
+ memcpy(skb_frags, rx_frags, sizeof(*skb_frags));
+ len -= rx_frags->size;
+ skb_frags++;
+ rx_frags++;
+ skb_shinfo(skb)->nr_frags++;
+ }
+
+ /* pskb_may_pull is not available in irq context, but
+ * skb_pull() (for ether_pad and eth_type_trans()) requires
+ * the beginning of the packet in skb_headlen(), move it
+ * manually */
+ memcpy(skb->data, va, hlen);
+ skb_shinfo(skb)->frags[0].page_offset += hlen;
+ skb_shinfo(skb)->frags[0].size -= hlen;
+ skb->data_len -= hlen;
+ skb->tail += hlen;
+ skb_pull(skb, MXGEFW_PAD);
}
-static inline int
-myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct myri10ge_priv *mgp,
- int bytes, int idx)
+static void
+myri10ge_alloc_rx_pages(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
+ int bytes, int watchdog)
{
- struct net_device *dev = mgp->dev;
- struct pci_dev *pdev = mgp->pdev;
- struct sk_buff *skb;
- dma_addr_t bus;
- int len, retval = 0;
+ struct page *page;
+ int idx;
- bytes += VLAN_HLEN; /* account for 802.1q vlan tag */
+ if (unlikely(rx->watchdog_needed && !watchdog))
+ return;
- if ((bytes + MXGEFW_PAD) > (4096 - 16) /* linux overhead */ )
- skb = myri10ge_alloc_big(dev, bytes);
- else if (myri10ge_skb_cross_4k)
- skb = myri10ge_alloc_small_safe(dev, bytes);
- else
- skb = myri10ge_alloc_small(dev, bytes);
+ /* try to refill entire ring */
+ while (rx->fill_cnt != (rx->cnt + rx->mask + 1)) {
+ idx = rx->fill_cnt & rx->mask;
- if (unlikely(skb == NULL)) {
- rx->alloc_fail++;
- retval = -ENOBUFS;
- goto done;
- }
-
- /* set len so that it only covers the area we
- * need mapped for DMA */
- len = bytes + MXGEFW_PAD;
-
- bus = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE);
- rx->info[idx].skb = skb;
- pci_unmap_addr_set(&rx->info[idx], bus, bus);
- pci_unmap_len_set(&rx->info[idx], len, len);
- rx->shadow[idx].addr_low = htonl(MYRI10GE_LOWPART_TO_U32(bus));
- rx->shadow[idx].addr_high = htonl(MYRI10GE_HIGHPART_TO_U32(bus));
-
-done:
- /* copy 8 descriptors (64-bytes) to the mcp at a time */
- if ((idx & 7) == 7) {
- if (rx->wc_fifo == NULL)
- myri10ge_submit_8rx(&rx->lanai[idx - 7],
- &rx->shadow[idx - 7]);
- else {
- mb();
- myri10ge_pio_copy(rx->wc_fifo,
- &rx->shadow[idx - 7], 64);
+ if ((bytes < MYRI10GE_ALLOC_SIZE / 2) &&
+ (rx->page_offset + bytes <= MYRI10GE_ALLOC_SIZE)) {
+ /* we can use part of previous page */
+ get_page(rx->page);
+ } else {
+ /* we need a new page */
+ page =
+ alloc_pages(GFP_ATOMIC | __GFP_COMP,
+ MYRI10GE_ALLOC_ORDER);
+ if (unlikely(page == NULL)) {
+ if (rx->fill_cnt - rx->cnt < 16)
+ rx->watchdog_needed = 1;
+ return;
+ }
+ rx->page = page;
+ rx->page_offset = 0;
+ rx->bus = pci_map_page(mgp->pdev, page, 0,
+ MYRI10GE_ALLOC_SIZE,
+ PCI_DMA_FROMDEVICE);
+ }
+ rx->info[idx].page = rx->page;
+ rx->info[idx].page_offset = rx->page_offset;
+ /* note that this is the address of the start of the
+ * page */
+ pci_unmap_addr_set(&rx->info[idx], bus, rx->bus);
+ rx->shadow[idx].addr_low =
+ htonl(MYRI10GE_LOWPART_TO_U32(rx->bus) + rx->page_offset);
+ rx->shadow[idx].addr_high =
+ htonl(MYRI10GE_HIGHPART_TO_U32(rx->bus));
+
+ /* start next packet on a cacheline boundary */
+ rx->page_offset += SKB_DATA_ALIGN(bytes);
+ rx->fill_cnt++;
+
+ /* copy 8 descriptors to the firmware at a time */
+ if ((idx & 7) == 7) {
+ if (rx->wc_fifo == NULL)
+ myri10ge_submit_8rx(&rx->lanai[idx - 7],
+ &rx->shadow[idx - 7]);
+ else {
+ mb();
+ myri10ge_pio_copy(rx->wc_fifo,
+ &rx->shadow[idx - 7], 64);
+ }
}
}
- return retval;
}
-static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, __wsum hw_csum)
+static inline void
+myri10ge_unmap_rx_page(struct pci_dev *pdev,
+ struct myri10ge_rx_buffer_state *info, int bytes)
{
- struct vlan_hdr *vh = (struct vlan_hdr *)(skb->data);
-
- if ((skb->protocol == htons(ETH_P_8021Q)) &&
- (vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) ||
- vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) {
- skb->csum = hw_csum;
- skb->ip_summed = CHECKSUM_COMPLETE;
+ /* unmap the recvd page if we're the only or last user of it */
+ if (bytes >= MYRI10GE_ALLOC_SIZE / 2 ||
+ (info->page_offset + 2 * bytes) > MYRI10GE_ALLOC_SIZE) {
+ pci_unmap_page(pdev, (pci_unmap_addr(info, bus)
+ & ~(MYRI10GE_ALLOC_SIZE - 1)),
+ MYRI10GE_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
}
}
-static inline unsigned long
+#define MYRI10GE_HLEN 64 /* The number of bytes to copy from a
+ * page into an skb */
+
+static inline int
myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
int bytes, int len, __wsum csum)
{
- dma_addr_t bus;
struct sk_buff *skb;
- int idx, unmap_len;
+ struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME];
+ int i, idx, hlen, remainder;
+ struct pci_dev *pdev = mgp->pdev;
+ struct net_device *dev = mgp->dev;
+ u8 *va;
+ len += MXGEFW_PAD;
idx = rx->cnt & rx->mask;
- rx->cnt++;
+ va = page_address(rx->info[idx].page) + rx->info[idx].page_offset;
+ prefetch(va);
+ /* Fill skb_frag_struct(s) with data from our receive */
+ for (i = 0, remainder = len; remainder > 0; i++) {
+ myri10ge_unmap_rx_page(pdev, &rx->info[idx], bytes);
+ rx_frags[i].page = rx->info[idx].page;
+ rx_frags[i].page_offset = rx->info[idx].page_offset;
+ if (remainder < MYRI10GE_ALLOC_SIZE)
+ rx_frags[i].size = remainder;
+ else
+ rx_frags[i].size = MYRI10GE_ALLOC_SIZE;
+ rx->cnt++;
+ idx = rx->cnt & rx->mask;
+ remainder -= MYRI10GE_ALLOC_SIZE;
+ }
+
+ hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN;
- /* save a pointer to the received skb */
- skb = rx->info[idx].skb;
- bus = pci_unmap_addr(&rx->info[idx], bus);
- unmap_len = pci_unmap_len(&rx->info[idx], len);
+ /* allocate an skb to attach the page(s) to. */
- /* try to replace the received skb */
- if (myri10ge_getbuf(rx, mgp, bytes, idx)) {
- /* drop the frame -- the old skbuf is re-cycled */
- mgp->stats.rx_dropped += 1;
+ skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16);
+ if (unlikely(skb == NULL)) {
+ mgp->stats.rx_dropped++;
+ do {
+ i--;
+ put_page(rx_frags[i].page);
+ } while (i != 0);
return 0;
}
- /* unmap the recvd skb */
- pci_unmap_single(mgp->pdev, bus, unmap_len, PCI_DMA_FROMDEVICE);
-
- /* mcp implicitly skips 1st bytes so that packet is properly
- * aligned */
- skb_reserve(skb, MXGEFW_PAD);
-
- /* set the length of the frame */
- skb_put(skb, len);
+ /* Attach the pages to the skb, and trim off any padding */
+ myri10ge_rx_skb_build(skb, va, rx_frags, len, hlen);
+ if (skb_shinfo(skb)->frags[0].size <= 0) {
+ put_page(skb_shinfo(skb)->frags[0].page);
+ skb_shinfo(skb)->nr_frags = 0;
+ }
+ skb->protocol = eth_type_trans(skb, dev);
+ skb->dev = dev;
- skb->protocol = eth_type_trans(skb, mgp->dev);
if (mgp->csum_flag) {
if ((skb->protocol == htons(ETH_P_IP)) ||
(skb->protocol == htons(ETH_P_IPV6))) {
@@ -1000,9 +995,8 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
} else
myri10ge_vlan_ip_csum(skb, csum);
}
-
netif_receive_skb(skb);
- mgp->dev->last_rx = jiffies;
+ dev->last_rx = jiffies;
return 1;
}
@@ -1079,7 +1073,7 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
length, checksum);
else
rx_ok = myri10ge_rx_done(mgp, &mgp->rx_big,
- mgp->dev->mtu + ETH_HLEN,
+ mgp->big_bytes,
length, checksum);
rx_packets += rx_ok;
rx_bytes += rx_ok * (unsigned long)length;
@@ -1094,6 +1088,14 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
rx_done->cnt = cnt;
mgp->stats.rx_packets += rx_packets;
mgp->stats.rx_bytes += rx_bytes;
+
+ /* restock receive rings if needed */
+ if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt < myri10ge_fill_thresh)
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+ mgp->small_bytes + MXGEFW_PAD, 0);
+ if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt < myri10ge_fill_thresh)
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
+
}
static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
@@ -1410,10 +1412,8 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
.set_tx_csum = ethtool_op_set_tx_hw_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
-#endif
.get_strings = myri10ge_get_strings,
.get_stats_count = myri10ge_get_stats_count,
.get_ethtool_stats = myri10ge_get_ethtool_stats,
@@ -1484,56 +1484,48 @@ static int myri10ge_allocate_rings(struct net_device *dev)
goto abort_with_rx_small_info;
/* Fill the receive rings */
+ mgp->rx_big.cnt = 0;
+ mgp->rx_small.cnt = 0;
+ mgp->rx_big.fill_cnt = 0;
+ mgp->rx_small.fill_cnt = 0;
+ mgp->rx_small.page_offset = MYRI10GE_ALLOC_SIZE;
+ mgp->rx_big.page_offset = MYRI10GE_ALLOC_SIZE;
+ mgp->rx_small.watchdog_needed = 0;
+ mgp->rx_big.watchdog_needed = 0;
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+ mgp->small_bytes + MXGEFW_PAD, 0);
- for (i = 0; i <= mgp->rx_small.mask; i++) {
- status = myri10ge_getbuf(&mgp->rx_small, mgp,
- mgp->small_bytes, i);
- if (status) {
- printk(KERN_ERR
- "myri10ge: %s: alloced only %d small bufs\n",
- dev->name, i);
- goto abort_with_rx_small_ring;
- }
+ if (mgp->rx_small.fill_cnt < mgp->rx_small.mask + 1) {
+ printk(KERN_ERR "myri10ge: %s: alloced only %d small bufs\n",
+ dev->name, mgp->rx_small.fill_cnt);
+ goto abort_with_rx_small_ring;
}
- for (i = 0; i <= mgp->rx_big.mask; i++) {
- status =
- myri10ge_getbuf(&mgp->rx_big, mgp, dev->mtu + ETH_HLEN, i);
- if (status) {
- printk(KERN_ERR
- "myri10ge: %s: alloced only %d big bufs\n",
- dev->name, i);
- goto abort_with_rx_big_ring;
- }
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
+ if (mgp->rx_big.fill_cnt < mgp->rx_big.mask + 1) {
+ printk(KERN_ERR "myri10ge: %s: alloced only %d big bufs\n",
+ dev->name, mgp->rx_big.fill_cnt);
+ goto abort_with_rx_big_ring;
}
return 0;
abort_with_rx_big_ring:
- for (i = 0; i <= mgp->rx_big.mask; i++) {
- if (mgp->rx_big.info[i].skb != NULL)
- dev_kfree_skb_any(mgp->rx_big.info[i].skb);
- if (pci_unmap_len(&mgp->rx_big.info[i], len))
- pci_unmap_single(mgp->pdev,
- pci_unmap_addr(&mgp->rx_big.info[i],
- bus),
- pci_unmap_len(&mgp->rx_big.info[i],
- len),
- PCI_DMA_FROMDEVICE);
+ for (i = mgp->rx_big.cnt; i < mgp->rx_big.fill_cnt; i++) {
+ int idx = i & mgp->rx_big.mask;
+ myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_big.info[idx],
+ mgp->big_bytes);
+ put_page(mgp->rx_big.info[idx].page);
}
abort_with_rx_small_ring:
- for (i = 0; i <= mgp->rx_small.mask; i++) {
- if (mgp->rx_small.info[i].skb != NULL)
- dev_kfree_skb_any(mgp->rx_small.info[i].skb);
- if (pci_unmap_len(&mgp->rx_small.info[i], len))
- pci_unmap_single(mgp->pdev,
- pci_unmap_addr(&mgp->rx_small.info[i],
- bus),
- pci_unmap_len(&mgp->rx_small.info[i],
- len),
- PCI_DMA_FROMDEVICE);
+ for (i = mgp->rx_small.cnt; i < mgp->rx_small.fill_cnt; i++) {
+ int idx = i & mgp->rx_small.mask;
+ myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_small.info[idx],
+ mgp->small_bytes + MXGEFW_PAD);
+ put_page(mgp->rx_small.info[idx].page);
}
+
kfree(mgp->rx_big.info);
abort_with_rx_small_info:
@@ -1566,30 +1558,24 @@ static void myri10ge_free_rings(struct net_device *dev)
mgp = netdev_priv(dev);
- for (i = 0; i <= mgp->rx_big.mask; i++) {
- if (mgp->rx_big.info[i].skb != NULL)
- dev_kfree_skb_any(mgp->rx_big.info[i].skb);
- if (pci_unmap_len(&mgp->rx_big.info[i], len))
- pci_unmap_single(mgp->pdev,
- pci_unmap_addr(&mgp->rx_big.info[i],
- bus),
- pci_unmap_len(&mgp->rx_big.info[i],
- len),
- PCI_DMA_FROMDEVICE);
- }
-
- for (i = 0; i <= mgp->rx_small.mask; i++) {
- if (mgp->rx_small.info[i].skb != NULL)
- dev_kfree_skb_any(mgp->rx_small.info[i].skb);
- if (pci_unmap_len(&mgp->rx_small.info[i], len))
- pci_unmap_single(mgp->pdev,
- pci_unmap_addr(&mgp->rx_small.info[i],
- bus),
- pci_unmap_len(&mgp->rx_small.info[i],
- len),
- PCI_DMA_FROMDEVICE);
+ for (i = mgp->rx_big.cnt; i < mgp->rx_big.fill_cnt; i++) {
+ idx = i & mgp->rx_big.mask;
+ if (i == mgp->rx_big.fill_cnt - 1)
+ mgp->rx_big.info[idx].page_offset = MYRI10GE_ALLOC_SIZE;
+ myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_big.info[idx],
+ mgp->big_bytes);
+ put_page(mgp->rx_big.info[idx].page);
}
+ for (i = mgp->rx_small.cnt; i < mgp->rx_small.fill_cnt; i++) {
+ idx = i & mgp->rx_small.mask;
+ if (i == mgp->rx_small.fill_cnt - 1)
+ mgp->rx_small.info[idx].page_offset =
+ MYRI10GE_ALLOC_SIZE;
+ myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_small.info[idx],
+ mgp->small_bytes + MXGEFW_PAD);
+ put_page(mgp->rx_small.info[idx].page);
+ }
tx = &mgp->tx;
while (tx->done != tx->req) {
idx = tx->done & tx->mask;
@@ -1631,6 +1617,41 @@ static void myri10ge_free_rings(struct net_device *dev)
mgp->tx.req_list = NULL;
}
+static int myri10ge_request_irq(struct myri10ge_priv *mgp)
+{
+ struct pci_dev *pdev = mgp->pdev;
+ int status;
+
+ if (myri10ge_msi) {
+ status = pci_enable_msi(pdev);
+ if (status != 0)
+ dev_err(&pdev->dev,
+ "Error %d setting up MSI; falling back to xPIC\n",
+ status);
+ else
+ mgp->msi_enabled = 1;
+ } else {
+ mgp->msi_enabled = 0;
+ }
+ status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED,
+ mgp->dev->name, mgp);
+ if (status != 0) {
+ dev_err(&pdev->dev, "failed to allocate IRQ\n");
+ if (mgp->msi_enabled)
+ pci_disable_msi(pdev);
+ }
+ return status;
+}
+
+static void myri10ge_free_irq(struct myri10ge_priv *mgp)
+{
+ struct pci_dev *pdev = mgp->pdev;
+
+ free_irq(pdev->irq, mgp);
+ if (mgp->msi_enabled)
+ pci_disable_msi(pdev);
+}
+
static int myri10ge_open(struct net_device *dev)
{
struct myri10ge_priv *mgp;
@@ -1646,10 +1667,13 @@ static int myri10ge_open(struct net_device *dev)
status = myri10ge_reset(mgp);
if (status != 0) {
printk(KERN_ERR "myri10ge: %s: failed reset\n", dev->name);
- mgp->running = MYRI10GE_ETH_STOPPED;
- return -ENXIO;
+ goto abort_with_nothing;
}
+ status = myri10ge_request_irq(mgp);
+ if (status != 0)
+ goto abort_with_nothing;
+
/* decide what small buffer size to use. For good TCP rx
* performance, it is important to not receive 1514 byte
* frames into jumbo buffers, as it confuses the socket buffer
@@ -1657,19 +1681,18 @@ static int myri10ge_open(struct net_device *dev)
*/
if (dev->mtu <= ETH_DATA_LEN)
- mgp->small_bytes = 128; /* enough for a TCP header */
+ /* enough for a TCP header */
+ mgp->small_bytes = (128 > SMP_CACHE_BYTES)
+ ? (128 - MXGEFW_PAD)
+ : (SMP_CACHE_BYTES - MXGEFW_PAD);
else
- mgp->small_bytes = ETH_FRAME_LEN; /* enough for an ETH_DATA_LEN frame */
+ /* enough for a vlan encapsulated ETH_DATA_LEN frame */
+ mgp->small_bytes = VLAN_ETH_FRAME_LEN;
/* Override the small buffer size? */
if (myri10ge_small_bytes > 0)
mgp->small_bytes = myri10ge_small_bytes;
- /* If the user sets an obscenely small MTU, adjust the small
- * bytes down to nearly nothing */
- if (mgp->small_bytes >= (dev->mtu + ETH_HLEN))
- mgp->small_bytes = 64;
-
/* get the lanai pointers to the send and receive rings */
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
@@ -1690,10 +1713,10 @@ static int myri10ge_open(struct net_device *dev)
"myri10ge: %s: failed to get ring sizes or locations\n",
dev->name);
mgp->running = MYRI10GE_ETH_STOPPED;
- return -ENXIO;
+ goto abort_with_irq;
}
- if (mgp->mtrr >= 0) {
+ if (myri10ge_wcfifo && mgp->mtrr >= 0) {
mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
mgp->rx_small.wc_fifo =
(u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL;
@@ -1705,17 +1728,23 @@ static int myri10ge_open(struct net_device *dev)
mgp->rx_big.wc_fifo = NULL;
}
- status = myri10ge_allocate_rings(dev);
- if (status != 0)
- goto abort_with_nothing;
-
/* Firmware needs the big buff size as a power of 2. Lie and
* tell him the buffer is larger, because we only use 1
* buffer/pkt, and the mtu will prevent overruns.
*/
- big_pow2 = dev->mtu + ETH_HLEN + MXGEFW_PAD;
- while ((big_pow2 & (big_pow2 - 1)) != 0)
- big_pow2++;
+ big_pow2 = dev->mtu + ETH_HLEN + VLAN_HLEN + MXGEFW_PAD;
+ if (big_pow2 < MYRI10GE_ALLOC_SIZE / 2) {
+ while ((big_pow2 & (big_pow2 - 1)) != 0)
+ big_pow2++;
+ mgp->big_bytes = dev->mtu + ETH_HLEN + VLAN_HLEN + MXGEFW_PAD;
+ } else {
+ big_pow2 = MYRI10GE_ALLOC_SIZE;
+ mgp->big_bytes = big_pow2;
+ }
+
+ status = myri10ge_allocate_rings(dev);
+ if (status != 0)
+ goto abort_with_irq;
/* now give firmware buffers sizes, and MTU */
cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN;
@@ -1778,6 +1807,9 @@ static int myri10ge_open(struct net_device *dev)
abort_with_rings:
myri10ge_free_rings(dev);
+abort_with_irq:
+ myri10ge_free_irq(mgp);
+
abort_with_nothing:
mgp->running = MYRI10GE_ETH_STOPPED;
return -ENOMEM;
@@ -1814,7 +1846,7 @@ static int myri10ge_close(struct net_device *dev)
printk(KERN_ERR "myri10ge: %s never got down irq\n", dev->name);
netif_tx_disable(dev);
-
+ myri10ge_free_irq(mgp);
myri10ge_free_rings(dev);
mgp->running = MYRI10GE_ETH_STOPPED;
@@ -1941,13 +1973,11 @@ again:
mss = 0;
max_segments = MXGEFW_MAX_SEND_DESC;
-#ifdef NETIF_F_TSO
if (skb->len > (dev->mtu + ETH_HLEN)) {
mss = skb_shinfo(skb)->gso_size;
if (mss != 0)
max_segments = MYRI10GE_MAX_SEND_DESC_TSO;
}
-#endif /*NETIF_F_TSO */
if ((unlikely(avail < max_segments))) {
/* we are out of transmit resources */
@@ -1979,7 +2009,6 @@ again:
cum_len = 0;
-#ifdef NETIF_F_TSO
if (mss) { /* TSO */
/* this removes any CKSUM flag from before */
flags = (MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST);
@@ -1995,7 +2024,6 @@ again:
* the checksum by parsing the header. */
pseudo_hdr_offset = mss;
} else
-#endif /*NETIF_F_TSO */
/* Mark small packets, and pad out tiny packets */
if (skb->len <= MXGEFW_SEND_SMALL_SIZE) {
flags |= MXGEFW_FLAGS_SMALL;
@@ -2063,7 +2091,6 @@ again:
seglen = len;
flags_next = flags & ~MXGEFW_FLAGS_FIRST;
cum_len_next = cum_len + seglen;
-#ifdef NETIF_F_TSO
if (mss) { /* TSO */
(req - rdma_count)->rdma_count = rdma_count + 1;
@@ -2090,7 +2117,6 @@ again:
(small * MXGEFW_FLAGS_SMALL);
}
}
-#endif /* NETIF_F_TSO */
req->addr_high = high_swapped;
req->addr_low = htonl(low);
req->pseudo_hdr_offset = htons(pseudo_hdr_offset);
@@ -2127,14 +2153,12 @@ again:
}
(req - rdma_count)->rdma_count = rdma_count;
-#ifdef NETIF_F_TSO
if (mss)
do {
req--;
req->flags |= MXGEFW_FLAGS_TSO_LAST;
} while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP |
MXGEFW_FLAGS_FIRST)));
-#endif
idx = ((count - 1) + tx->req) & tx->mask;
tx->info[idx].last = 1;
if (tx->wc_fifo == NULL)
@@ -2206,7 +2230,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
struct myri10ge_cmd cmd;
struct myri10ge_priv *mgp;
struct dev_mc_list *mc_list;
- __be32 data[2] = {0, 0};
+ __be32 data[2] = { 0, 0 };
int err;
mgp = netdev_priv(dev);
@@ -2488,34 +2512,6 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
}
}
-static void myri10ge_save_state(struct myri10ge_priv *mgp)
-{
- struct pci_dev *pdev = mgp->pdev;
- int cap;
-
- pci_save_state(pdev);
- /* now save PCIe and MSI state that Linux will not
- * save for us */
- cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
- pci_read_config_dword(pdev, cap + PCI_EXP_DEVCTL, &mgp->devctl);
- cap = pci_find_capability(pdev, PCI_CAP_ID_MSI);
- pci_read_config_word(pdev, cap + PCI_MSI_FLAGS, &mgp->msi_flags);
-}
-
-static void myri10ge_restore_state(struct myri10ge_priv *mgp)
-{
- struct pci_dev *pdev = mgp->pdev;
- int cap;
-
- /* restore PCIe and MSI state that linux will not */
- cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
- pci_write_config_dword(pdev, cap + PCI_CAP_ID_EXP, mgp->devctl);
- cap = pci_find_capability(pdev, PCI_CAP_ID_MSI);
- pci_write_config_word(pdev, cap + PCI_MSI_FLAGS, mgp->msi_flags);
-
- pci_restore_state(pdev);
-}
-
#ifdef CONFIG_PM
static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -2536,11 +2532,10 @@ static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state)
rtnl_unlock();
}
myri10ge_dummy_rdma(mgp, 0);
- free_irq(pdev->irq, mgp);
- myri10ge_save_state(mgp);
+ pci_save_state(pdev);
pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- return 0;
+
+ return pci_set_power_state(pdev, pci_choose_state(pdev, state));
}
static int myri10ge_resume(struct pci_dev *pdev)
@@ -2562,34 +2557,33 @@ static int myri10ge_resume(struct pci_dev *pdev)
mgp->dev->name);
return -EIO;
}
- myri10ge_restore_state(mgp);
+
+ status = pci_restore_state(pdev);
+ if (status)
+ return status;
status = pci_enable_device(pdev);
- if (status < 0) {
+ if (status) {
dev_err(&pdev->dev, "failed to enable device\n");
- return -EIO;
+ return status;
}
pci_set_master(pdev);
- status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED,
- netdev->name, mgp);
- if (status != 0) {
- dev_err(&pdev->dev, "failed to allocate IRQ\n");
- goto abort_with_enabled;
- }
-
myri10ge_reset(mgp);
myri10ge_dummy_rdma(mgp, 1);
/* Save configuration space to be restored if the
* nic resets due to a parity error */
- myri10ge_save_state(mgp);
+ pci_save_state(pdev);
if (netif_running(netdev)) {
rtnl_lock();
- myri10ge_open(netdev);
+ status = myri10ge_open(netdev);
rtnl_unlock();
+ if (status != 0)
+ goto abort_with_enabled;
+
}
netif_device_attach(netdev);
@@ -2625,7 +2619,7 @@ static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp)
static void myri10ge_watchdog(struct work_struct *work)
{
struct myri10ge_priv *mgp =
- container_of(work, struct myri10ge_priv, watchdog_work);
+ container_of(work, struct myri10ge_priv, watchdog_work);
u32 reboot;
int status;
u16 cmd, vendor;
@@ -2647,7 +2641,11 @@ static void myri10ge_watchdog(struct work_struct *work)
* when the driver was loaded, or the last time the
* nic was resumed from power saving mode.
*/
- myri10ge_restore_state(mgp);
+ pci_restore_state(mgp->pdev);
+
+ /* save state again for accounting reasons */
+ pci_save_state(mgp->pdev);
+
} else {
/* if we get back -1's from our slot, perhaps somebody
* powered off our card. Don't try to reset it in
@@ -2698,6 +2696,21 @@ static void myri10ge_watchdog_timer(unsigned long arg)
struct myri10ge_priv *mgp;
mgp = (struct myri10ge_priv *)arg;
+
+ if (mgp->rx_small.watchdog_needed) {
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+ mgp->small_bytes + MXGEFW_PAD, 1);
+ if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt >=
+ myri10ge_fill_thresh)
+ mgp->rx_small.watchdog_needed = 0;
+ }
+ if (mgp->rx_big.watchdog_needed) {
+ myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 1);
+ if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt >=
+ myri10ge_fill_thresh)
+ mgp->rx_big.watchdog_needed = 0;
+ }
+
if (mgp->tx.req != mgp->tx.done &&
mgp->tx.done == mgp->watchdog_tx_done &&
mgp->watchdog_tx_req != mgp->watchdog_tx_done)
@@ -2848,23 +2861,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto abort_with_firmware;
}
- if (myri10ge_msi) {
- status = pci_enable_msi(pdev);
- if (status != 0)
- dev_err(&pdev->dev,
- "Error %d setting up MSI; falling back to xPIC\n",
- status);
- else
- mgp->msi_enabled = 1;
- }
-
- status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED,
- netdev->name, mgp);
- if (status != 0) {
- dev_err(&pdev->dev, "failed to allocate IRQ\n");
- goto abort_with_firmware;
- }
-
pci_set_drvdata(pdev, mgp);
if ((myri10ge_initial_mtu + ETH_HLEN) > MYRI10GE_MAX_ETHER_MTU)
myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;
@@ -2876,7 +2872,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->hard_start_xmit = myri10ge_xmit;
netdev->get_stats = myri10ge_get_stats;
netdev->base_addr = mgp->iomem_base;
- netdev->irq = pdev->irq;
netdev->change_mtu = myri10ge_change_mtu;
netdev->set_multicast_list = myri10ge_set_multicast_list;
netdev->set_mac_address = myri10ge_set_mac_address;
@@ -2886,9 +2881,18 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->poll = myri10ge_poll;
netdev->weight = myri10ge_napi_weight;
+ /* make sure we can get an irq, and that MSI can be
+ * setup (if available). Also ensure netdev->irq
+ * is set to correct value if MSI is enabled */
+ status = myri10ge_request_irq(mgp);
+ if (status != 0)
+ goto abort_with_firmware;
+ netdev->irq = pdev->irq;
+ myri10ge_free_irq(mgp);
+
/* Save configuration space to be restored if the
* nic resets due to a parity error */
- myri10ge_save_state(mgp);
+ pci_save_state(pdev);
/* Setup the watchdog timer */
setup_timer(&mgp->watchdog_timer, myri10ge_watchdog_timer,
@@ -2899,19 +2903,17 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
status = register_netdev(netdev);
if (status != 0) {
dev_err(&pdev->dev, "register_netdev failed: %d\n", status);
- goto abort_with_irq;
+ goto abort_with_state;
}
dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
(mgp->msi_enabled ? "MSI" : "xPIC"),
- pdev->irq, mgp->tx.boundary, mgp->fw_name,
+ netdev->irq, mgp->tx.boundary, mgp->fw_name,
(mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
return 0;
-abort_with_irq:
- free_irq(pdev->irq, mgp);
- if (mgp->msi_enabled)
- pci_disable_msi(pdev);
+abort_with_state:
+ pci_restore_state(pdev);
abort_with_firmware:
myri10ge_dummy_rdma(mgp, 0);
@@ -2962,12 +2964,12 @@ static void myri10ge_remove(struct pci_dev *pdev)
flush_scheduled_work();
netdev = mgp->dev;
unregister_netdev(netdev);
- free_irq(pdev->irq, mgp);
- if (mgp->msi_enabled)
- pci_disable_msi(pdev);
myri10ge_dummy_rdma(mgp, 0);
+ /* avoid a memory leak */
+ pci_restore_state(pdev);
+
bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
dma_free_coherent(&pdev->dev, bytes,
mgp->rx_done.entry, mgp->rx_done.bus);
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index b5410bee5f2..3f3896e9887 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -63,12 +63,14 @@
#include "netxen_nic_hw.h"
-#define NETXEN_NIC_BUILD_NO "1"
#define _NETXEN_NIC_LINUX_MAJOR 3
#define _NETXEN_NIC_LINUX_MINOR 3
-#define _NETXEN_NIC_LINUX_SUBVERSION 2
-#define NETXEN_NIC_LINUX_VERSIONID "3.3.2" "-" NETXEN_NIC_BUILD_NO
-#define NETXEN_NIC_FW_VERSIONID "3.3.2"
+#define _NETXEN_NIC_LINUX_SUBVERSION 3
+#define NETXEN_NIC_LINUX_VERSIONID "3.3.3"
+
+#define NUM_FLASH_SECTORS (64)
+#define FLASH_SECTOR_SIZE (64 * 1024)
+#define FLASH_TOTAL_SIZE (NUM_FLASH_SECTORS * FLASH_SECTOR_SIZE)
#define RCV_DESC_RINGSIZE \
(sizeof(struct rcv_desc) * adapter->max_rx_desc_count)
@@ -86,6 +88,7 @@
#define NETXEN_RCV_PRODUCER_OFFSET 0
#define NETXEN_RCV_PEG_DB_ID 2
#define NETXEN_HOST_DUMMY_DMA_SIZE 1024
+#define FLASH_SUCCESS 0
#define ADDR_IN_WINDOW1(off) \
((off > NETXEN_CRB_PCIX_HOST2) && (off < NETXEN_CRB_MAX)) ? 1 : 0
@@ -137,7 +140,7 @@ extern struct workqueue_struct *netxen_workq;
#define THIRD_PAGE_GROUP_SIZE THIRD_PAGE_GROUP_END - THIRD_PAGE_GROUP_START
#define MAX_RX_BUFFER_LENGTH 1760
-#define MAX_RX_JUMBO_BUFFER_LENGTH 9046
+#define MAX_RX_JUMBO_BUFFER_LENGTH 8062
#define MAX_RX_LRO_BUFFER_LENGTH ((48*1024)-512)
#define RX_DMA_MAP_LEN (MAX_RX_BUFFER_LENGTH - 2)
#define RX_JUMBO_DMA_MAP_LEN \
@@ -199,9 +202,9 @@ enum {
(RCV_DESC_NORMAL)))
#define MAX_CMD_DESCRIPTORS 1024
-#define MAX_RCV_DESCRIPTORS 32768
-#define MAX_JUMBO_RCV_DESCRIPTORS 4096
-#define MAX_LRO_RCV_DESCRIPTORS 2048
+#define MAX_RCV_DESCRIPTORS 16384
+#define MAX_JUMBO_RCV_DESCRIPTORS 1024
+#define MAX_LRO_RCV_DESCRIPTORS 64
#define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS
#define MAX_JUMBO_RCV_DESC MAX_JUMBO_RCV_DESCRIPTORS
#define MAX_RCV_DESC MAX_RCV_DESCRIPTORS
@@ -240,49 +243,39 @@ extern unsigned long long netxen_dma_mask;
typedef u32 netxen_ctx_msg;
-#define _netxen_set_bits(config_word, start, bits, val) {\
- unsigned long long mask = (((1ULL << (bits)) - 1) << (start)); \
- unsigned long long value = (val); \
- (config_word) &= ~mask; \
- (config_word) |= (((value) << (start)) & mask); \
-}
-
#define netxen_set_msg_peg_id(config_word, val) \
- _netxen_set_bits(config_word, 0, 2, val)
+ ((config_word) &= ~3, (config_word) |= val & 3)
#define netxen_set_msg_privid(config_word) \
- set_bit(2, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 2)
#define netxen_set_msg_count(config_word, val) \
- _netxen_set_bits(config_word, 3, 15, val)
+ ((config_word) &= ~(0x7fff<<3), (config_word) |= (val & 0x7fff) << 3)
#define netxen_set_msg_ctxid(config_word, val) \
- _netxen_set_bits(config_word, 18, 10, val)
+ ((config_word) &= ~(0x3ff<<18), (config_word) |= (val & 0x3ff) << 18)
#define netxen_set_msg_opcode(config_word, val) \
- _netxen_set_bits(config_word, 28, 4, val)
+ ((config_word) &= ~(0xf<<24), (config_word) |= (val & 0xf) << 24)
struct netxen_rcv_context {
- u32 rcv_ring_addr_lo;
- u32 rcv_ring_addr_hi;
- u32 rcv_ring_size;
- u32 rsrvd;
+ __le64 rcv_ring_addr;
+ __le32 rcv_ring_size;
+ __le32 rsrvd;
};
struct netxen_ring_ctx {
/* one command ring */
- u64 cmd_consumer_offset;
- u32 cmd_ring_addr_lo;
- u32 cmd_ring_addr_hi;
- u32 cmd_ring_size;
- u32 rsrvd;
+ __le64 cmd_consumer_offset;
+ __le64 cmd_ring_addr;
+ __le32 cmd_ring_size;
+ __le32 rsrvd;
/* three receive rings */
struct netxen_rcv_context rcv_ctx[3];
/* one status ring */
- u32 sts_ring_addr_lo;
- u32 sts_ring_addr_hi;
- u32 sts_ring_size;
+ __le64 sts_ring_addr;
+ __le32 sts_ring_size;
- u32 ctx_id;
+ __le32 ctx_id;
} __attribute__ ((aligned(64)));
/*
@@ -306,81 +299,85 @@ struct netxen_ring_ctx {
((cmd_desc)->port_ctxid |= ((var) & 0x0F))
#define netxen_set_cmd_desc_flags(cmd_desc, val) \
- _netxen_set_bits((cmd_desc)->flags_opcode, 0, 7, val)
+ ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x7f), \
+ (cmd_desc)->flags_opcode |= cpu_to_le16((val) & 0x7f))
#define netxen_set_cmd_desc_opcode(cmd_desc, val) \
- _netxen_set_bits((cmd_desc)->flags_opcode, 7, 6, val)
+ ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x3f<<7), \
+ (cmd_desc)->flags_opcode |= cpu_to_le16((val) & (0x3f<<7)))
#define netxen_set_cmd_desc_num_of_buff(cmd_desc, val) \
- _netxen_set_bits((cmd_desc)->num_of_buffers_total_length, 0, 8, val);
+ ((cmd_desc)->num_of_buffers_total_length &= ~cpu_to_le32(0xff), \
+ (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32((val) & 0xff))
#define netxen_set_cmd_desc_totallength(cmd_desc, val) \
- _netxen_set_bits((cmd_desc)->num_of_buffers_total_length, 8, 24, val);
+ ((cmd_desc)->num_of_buffers_total_length &= cpu_to_le32(0xff), \
+ (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32(val << 24))
#define netxen_get_cmd_desc_opcode(cmd_desc) \
- (((cmd_desc)->flags_opcode >> 7) & 0x003F)
+ ((le16_to_cpu((cmd_desc)->flags_opcode) >> 7) & 0x003F)
#define netxen_get_cmd_desc_totallength(cmd_desc) \
- (((cmd_desc)->num_of_buffers_total_length >> 8) & 0x0FFFFFF)
+ (le32_to_cpu((cmd_desc)->num_of_buffers_total_length) >> 8)
struct cmd_desc_type0 {
u8 tcp_hdr_offset; /* For LSO only */
u8 ip_hdr_offset; /* For LSO only */
/* Bit pattern: 0-6 flags, 7-12 opcode, 13-15 unused */
- u16 flags_opcode;
+ __le16 flags_opcode;
/* Bit pattern: 0-7 total number of segments,
8-31 Total size of the packet */
- u32 num_of_buffers_total_length;
+ __le32 num_of_buffers_total_length;
union {
struct {
- u32 addr_low_part2;
- u32 addr_high_part2;
+ __le32 addr_low_part2;
+ __le32 addr_high_part2;
};
- u64 addr_buffer2;
+ __le64 addr_buffer2;
};
- u16 reference_handle; /* changed to u16 to add mss */
- u16 mss; /* passed by NDIS_PACKET for LSO */
+ __le16 reference_handle; /* changed to u16 to add mss */
+ __le16 mss; /* passed by NDIS_PACKET for LSO */
/* Bit pattern 0-3 port, 0-3 ctx id */
u8 port_ctxid;
u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */
- u16 conn_id; /* IPSec offoad only */
+ __le16 conn_id; /* IPSec offoad only */
union {
struct {
- u32 addr_low_part3;
- u32 addr_high_part3;
+ __le32 addr_low_part3;
+ __le32 addr_high_part3;
};
- u64 addr_buffer3;
+ __le64 addr_buffer3;
};
union {
struct {
- u32 addr_low_part1;
- u32 addr_high_part1;
+ __le32 addr_low_part1;
+ __le32 addr_high_part1;
};
- u64 addr_buffer1;
+ __le64 addr_buffer1;
};
- u16 buffer1_length;
- u16 buffer2_length;
- u16 buffer3_length;
- u16 buffer4_length;
+ __le16 buffer1_length;
+ __le16 buffer2_length;
+ __le16 buffer3_length;
+ __le16 buffer4_length;
union {
struct {
- u32 addr_low_part4;
- u32 addr_high_part4;
+ __le32 addr_low_part4;
+ __le32 addr_high_part4;
};
- u64 addr_buffer4;
+ __le64 addr_buffer4;
};
- u64 unused;
+ __le64 unused;
} __attribute__ ((aligned(64)));
/* Note: sizeof(rcv_desc) should always be a mutliple of 2 */
struct rcv_desc {
- u16 reference_handle;
- u16 reserved;
- u32 buffer_length; /* allocated buffer length (usually 2K) */
- u64 addr_buffer;
+ __le16 reference_handle;
+ __le16 reserved;
+ __le32 buffer_length; /* allocated buffer length (usually 2K) */
+ __le64 addr_buffer;
};
/* opcode field in status_desc */
@@ -406,36 +403,36 @@ struct rcv_desc {
(((status_desc)->lro & 0x80) >> 7)
#define netxen_get_sts_port(status_desc) \
- ((status_desc)->status_desc_data & 0x0F)
+ (le64_to_cpu((status_desc)->status_desc_data) & 0x0F)
#define netxen_get_sts_status(status_desc) \
- (((status_desc)->status_desc_data >> 4) & 0x0F)
+ ((le64_to_cpu((status_desc)->status_desc_data) >> 4) & 0x0F)
#define netxen_get_sts_type(status_desc) \
- (((status_desc)->status_desc_data >> 8) & 0x0F)
+ ((le64_to_cpu((status_desc)->status_desc_data) >> 8) & 0x0F)
#define netxen_get_sts_totallength(status_desc) \
- (((status_desc)->status_desc_data >> 12) & 0xFFFF)
+ ((le64_to_cpu((status_desc)->status_desc_data) >> 12) & 0xFFFF)
#define netxen_get_sts_refhandle(status_desc) \
- (((status_desc)->status_desc_data >> 28) & 0xFFFF)
+ ((le64_to_cpu((status_desc)->status_desc_data) >> 28) & 0xFFFF)
#define netxen_get_sts_prot(status_desc) \
- (((status_desc)->status_desc_data >> 44) & 0x0F)
+ ((le64_to_cpu((status_desc)->status_desc_data) >> 44) & 0x0F)
#define netxen_get_sts_owner(status_desc) \
- (((status_desc)->status_desc_data >> 56) & 0x03)
+ ((le64_to_cpu((status_desc)->status_desc_data) >> 56) & 0x03)
#define netxen_get_sts_opcode(status_desc) \
- (((status_desc)->status_desc_data >> 58) & 0x03F)
+ ((le64_to_cpu((status_desc)->status_desc_data) >> 58) & 0x03F)
#define netxen_clear_sts_owner(status_desc) \
((status_desc)->status_desc_data &= \
- ~(((unsigned long long)3) << 56 ))
+ ~cpu_to_le64(((unsigned long long)3) << 56 ))
#define netxen_set_sts_owner(status_desc, val) \
((status_desc)->status_desc_data |= \
- (((unsigned long long)((val) & 0x3)) << 56 ))
+ cpu_to_le64(((unsigned long long)((val) & 0x3)) << 56 ))
struct status_desc {
/* Bit pattern: 0-3 port, 4-7 status, 8-11 type, 12-27 total_length
28-43 reference_handle, 44-47 protocol, 48-52 unused
53-55 desc_cnt, 56-57 owner, 58-63 opcode
*/
- u64 status_desc_data;
- u32 hash_value;
+ __le64 status_desc_data;
+ __le32 hash_value;
u8 hash_type;
u8 msg_type;
u8 unused;
@@ -852,8 +849,6 @@ struct netxen_adapter {
spinlock_t tx_lock;
spinlock_t lock;
struct work_struct watchdog_task;
- struct work_struct tx_timeout_task;
- struct net_device *netdev;
struct timer_list watchdog_timer;
u32 curr_window;
@@ -887,7 +882,6 @@ struct netxen_adapter {
struct netxen_recv_context recv_ctx[MAX_RCV_CTX];
int is_up;
- int number;
struct netxen_dummy_dma dummy_dma;
/* Context interface shared between card and host */
@@ -950,6 +944,7 @@ struct netxen_port {
struct pci_dev *pdev;
struct net_device_stats net_stats;
struct netxen_port_stats stats;
+ struct work_struct tx_timeout_task;
};
#define PCI_OFFSET_FIRST_RANGE(adapter, off) \
@@ -1008,9 +1003,9 @@ void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port,
void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port,
long enable);
int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, long reg,
- __le32 * readval);
+ __u32 * readval);
int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long phy,
- long reg, __le32 val);
+ long reg, __u32 val);
/* Functions available from netxen_nic_hw.c */
int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu);
@@ -1027,14 +1022,6 @@ int netxen_nic_hw_read_wx(struct netxen_adapter *adapter, u64 off, void *data,
int len);
int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data,
int len);
-int netxen_nic_hw_read_ioctl(struct netxen_adapter *adapter, u64 off,
- void *data, int len);
-int netxen_nic_hw_write_ioctl(struct netxen_adapter *adapter, u64 off,
- void *data, int len);
-int netxen_nic_pci_mem_write_ioctl(struct netxen_adapter *adapter,
- u64 off, void *data, int size);
-int netxen_nic_pci_mem_read_ioctl(struct netxen_adapter *adapter,
- u64 off, void *data, int size);
void netxen_crb_writelit_adapter(struct netxen_adapter *adapter,
unsigned long off, int data);
@@ -1045,6 +1032,15 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val);
void netxen_load_firmware(struct netxen_adapter *adapter);
int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose);
int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp);
+int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size);
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size);
+int netxen_flash_unlock(struct netxen_adapter *adapter);
+int netxen_backup_crbinit(struct netxen_adapter *adapter);
+int netxen_flash_erase_secondary(struct netxen_adapter *adapter);
+int netxen_flash_erase_primary(struct netxen_adapter *adapter);
+
int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data);
int netxen_rom_se(struct netxen_adapter *adapter, int addr);
int netxen_do_rom_se(struct netxen_adapter *adapter, int addr);
@@ -1067,9 +1063,6 @@ void netxen_tso_check(struct netxen_adapter *adapter,
struct cmd_desc_type0 *desc, struct sk_buff *skb);
int netxen_nic_hw_resources(struct netxen_adapter *adapter);
void netxen_nic_clear_stats(struct netxen_adapter *adapter);
-int
-netxen_nic_do_ioctl(struct netxen_adapter *adapter, void *u_data,
- struct netxen_port *port);
int netxen_nic_rx_has_work(struct netxen_adapter *adapter);
int netxen_nic_tx_has_work(struct netxen_adapter *adapter);
void netxen_watchdog_task(struct work_struct *work);
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index 2ab4885cc95..cc0efe213e0 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -32,6 +32,7 @@
*/
#include <linux/types.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <asm/io.h>
@@ -42,7 +43,6 @@
#include "netxen_nic_hw.h"
#include "netxen_nic.h"
#include "netxen_nic_phan_reg.h"
-#include "netxen_nic_ioctl.h"
struct netxen_nic_stats {
char stat_string[ETH_GSTRING_LEN];
@@ -79,8 +79,7 @@ static const struct netxen_nic_stats netxen_nic_gstrings_stats[] = {
{"tx_bytes", NETXEN_NIC_STAT(stats.txbytes)},
};
-#define NETXEN_NIC_STATS_LEN \
- sizeof(netxen_nic_gstrings_stats) / sizeof(struct netxen_nic_stats)
+#define NETXEN_NIC_STATS_LEN ARRAY_SIZE(netxen_nic_gstrings_stats)
static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = {
"Register_Test_offline", "EEPROM_Test_offline",
@@ -96,17 +95,7 @@ static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = {
static int netxen_nic_get_eeprom_len(struct net_device *dev)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
- int n;
-
- if ((netxen_rom_fast_read(adapter, 0, &n) == 0)
- && (n & NETXEN_ROM_ROUNDUP)) {
- n &= ~NETXEN_ROM_ROUNDUP;
- if (n < NETXEN_MAX_EEPROM_LEN)
- return n;
- }
- return 0;
+ return FLASH_TOTAL_SIZE;
}
static void
@@ -220,7 +209,7 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
- __le32 status;
+ __u32 status;
/* read which mode */
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
@@ -228,7 +217,7 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (adapter->phy_write
&& adapter->phy_write(adapter, port->portnum,
NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
- (__le32) ecmd->autoneg) != 0)
+ ecmd->autoneg) != 0)
return -EIO;
else
port->link_autoneg = ecmd->autoneg;
@@ -281,7 +270,7 @@ static int netxen_nic_get_regs_len(struct net_device *dev)
}
struct netxen_niu_regs {
- __le32 reg[NETXEN_NIC_REGS_COUNT];
+ __u32 reg[NETXEN_NIC_REGS_COUNT];
};
static struct netxen_niu_regs niu_registers[] = {
@@ -374,7 +363,7 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
{
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
- __le32 mode, *regs_buff = p;
+ __u32 mode, *regs_buff = p;
void __iomem *addr;
int i, window;
@@ -417,7 +406,7 @@ static u32 netxen_nic_get_link(struct net_device *dev)
{
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
- __le32 status;
+ __u32 status;
/* read which mode */
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
@@ -442,18 +431,92 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
int offset;
+ int ret;
if (eeprom->len == 0)
return -EINVAL;
eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16);
- for (offset = 0; offset < eeprom->len; offset++)
- if (netxen_rom_fast_read
- (adapter, (8 * offset) + 8, (int *)eeprom->data) == -1)
- return -EIO;
+ offset = eeprom->offset;
+
+ ret = netxen_rom_fast_read_words(adapter, offset, bytes,
+ eeprom->len);
+ if (ret < 0)
+ return ret;
+
return 0;
}
+static int
+netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+ u8 * bytes)
+{
+ struct netxen_port *port = netdev_priv(dev);
+ struct netxen_adapter *adapter = port->adapter;
+ int offset = eeprom->offset;
+ static int flash_start;
+ static int ready_to_flash;
+ int ret;
+
+ if (flash_start == 0) {
+ ret = netxen_flash_unlock(adapter);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: Flash unlock failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+ printk(KERN_INFO "%s: flash unlocked. \n",
+ netxen_nic_driver_name);
+ ret = netxen_flash_erase_secondary(adapter);
+ if (ret != FLASH_SUCCESS) {
+ printk(KERN_ERR "%s: Flash erase failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+ printk(KERN_INFO "%s: secondary flash erased successfully.\n",
+ netxen_nic_driver_name);
+ flash_start = 1;
+ return 0;
+ }
+
+ if (offset == BOOTLD_START) {
+ ret = netxen_flash_erase_primary(adapter);
+ if (ret != FLASH_SUCCESS) {
+ printk(KERN_ERR "%s: Flash erase failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+
+ ret = netxen_rom_se(adapter, USER_START);
+ if (ret != FLASH_SUCCESS)
+ return ret;
+ ret = netxen_rom_se(adapter, FIXED_START);
+ if (ret != FLASH_SUCCESS)
+ return ret;
+
+ printk(KERN_INFO "%s: primary flash erased successfully\n",
+ netxen_nic_driver_name);
+
+ ret = netxen_backup_crbinit(adapter);
+ if (ret != FLASH_SUCCESS) {
+ printk(KERN_ERR "%s: CRBinit backup failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+ printk(KERN_INFO "%s: CRBinit backup done.\n",
+ netxen_nic_driver_name);
+ ready_to_flash = 1;
+ }
+
+ if (!ready_to_flash) {
+ printk(KERN_ERR "%s: Invalid write sequence, returning...\n",
+ netxen_nic_driver_name);
+ return -EINVAL;
+ }
+
+ return netxen_rom_fast_write_words(adapter, offset, bytes, eeprom->len);
+}
+
static void
netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
{
@@ -484,13 +547,13 @@ netxen_nic_get_pauseparam(struct net_device *dev,
{
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
- __le32 val;
+ __u32 val;
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
/* get flow control settings */
netxen_nic_read_w0(adapter,
NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
- (u32 *) & val);
+ &val);
pause->rx_pause = netxen_gb_get_rx_flowctl(val);
pause->tx_pause = netxen_gb_get_tx_flowctl(val);
/* get autoneg settings */
@@ -504,7 +567,7 @@ netxen_nic_set_pauseparam(struct net_device *dev,
{
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
- __le32 val;
+ __u32 val;
unsigned int autoneg;
/* read mode */
@@ -524,13 +587,13 @@ netxen_nic_set_pauseparam(struct net_device *dev,
netxen_nic_write_w0(adapter,
NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
- *(u32 *) (&val));
+ *&val);
/* set autoneg */
autoneg = pause->autoneg;
if (adapter->phy_write
&& adapter->phy_write(adapter, port->portnum,
NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
- (__le32) autoneg) != 0)
+ autoneg) != 0)
return -EIO;
else {
port->link_autoneg = pause->autoneg;
@@ -545,7 +608,7 @@ static int netxen_nic_reg_test(struct net_device *dev)
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
u32 data_read, data_written, save;
- __le32 mode;
+ __u32 mode;
/*
* first test the "Read Only" registers by writing which mode
@@ -711,7 +774,6 @@ netxen_nic_get_ethtool_stats(struct net_device *dev,
(netxen_nic_gstrings_stats[index].sizeof_stat ==
sizeof(u64)) ? *(u64 *) p : *(u32 *) p;
}
-
}
struct ethtool_ops netxen_nic_ethtool_ops = {
@@ -724,6 +786,7 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
.get_link = netxen_nic_get_link,
.get_eeprom_len = netxen_nic_get_eeprom_len,
.get_eeprom = netxen_nic_get_eeprom,
+ .set_eeprom = netxen_nic_set_eeprom,
.get_ringparam = netxen_nic_get_ringparam,
.get_pauseparam = netxen_nic_get_pauseparam,
.set_pauseparam = netxen_nic_set_pauseparam,
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 9147b6048df..f263232f499 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -95,7 +95,7 @@ void netxen_nic_set_multi(struct net_device *netdev)
struct netxen_port *port = netdev_priv(netdev);
struct netxen_adapter *adapter = port->adapter;
struct dev_mc_list *mc_ptr;
- __le32 netxen_mac_addr_cntl_data = 0;
+ __u32 netxen_mac_addr_cntl_data = 0;
mc_ptr = netdev->mc_list;
if (netdev->flags & IFF_PROMISC) {
@@ -236,8 +236,9 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
}
memset(addr, 0, sizeof(struct netxen_ring_ctx));
adapter->ctx_desc = (struct netxen_ring_ctx *)addr;
- adapter->ctx_desc->cmd_consumer_offset = adapter->ctx_desc_phys_addr
- + sizeof(struct netxen_ring_ctx);
+ adapter->ctx_desc->cmd_consumer_offset =
+ cpu_to_le64(adapter->ctx_desc_phys_addr +
+ sizeof(struct netxen_ring_ctx));
adapter->cmd_consumer = (uint32_t *) (((char *)addr) +
sizeof(struct netxen_ring_ctx));
@@ -253,11 +254,10 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
return -ENOMEM;
}
- adapter->ctx_desc->cmd_ring_addr_lo =
- hw->cmd_desc_phys_addr & 0xffffffffUL;
- adapter->ctx_desc->cmd_ring_addr_hi =
- ((u64) hw->cmd_desc_phys_addr >> 32);
- adapter->ctx_desc->cmd_ring_size = adapter->max_tx_desc_count;
+ adapter->ctx_desc->cmd_ring_addr =
+ cpu_to_le64(hw->cmd_desc_phys_addr);
+ adapter->ctx_desc->cmd_ring_size =
+ cpu_to_le32(adapter->max_tx_desc_count);
hw->cmd_desc_head = (struct cmd_desc_type0 *)addr;
@@ -278,12 +278,10 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
return err;
}
rcv_desc->desc_head = (struct rcv_desc *)addr;
- adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr_lo =
- rcv_desc->phys_addr & 0xffffffffUL;
- adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr_hi =
- ((u64) rcv_desc->phys_addr >> 32);
+ adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr =
+ cpu_to_le64(rcv_desc->phys_addr);
adapter->ctx_desc->rcv_ctx[ring].rcv_ring_size =
- rcv_desc->max_rx_desc_count;
+ cpu_to_le32(rcv_desc->max_rx_desc_count);
}
addr = netxen_alloc(adapter->ahw.pdev, STATUS_DESC_RINGSIZE,
@@ -297,11 +295,10 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
return err;
}
recv_ctx->rcv_status_desc_head = (struct status_desc *)addr;
- adapter->ctx_desc->sts_ring_addr_lo =
- recv_ctx->rcv_status_desc_phys_addr & 0xffffffffUL;
- adapter->ctx_desc->sts_ring_addr_hi =
- ((u64) recv_ctx->rcv_status_desc_phys_addr >> 32);
- adapter->ctx_desc->sts_ring_size = adapter->max_rx_desc_count;
+ adapter->ctx_desc->sts_ring_addr =
+ cpu_to_le64(recv_ctx->rcv_status_desc_phys_addr);
+ adapter->ctx_desc->sts_ring_size =
+ cpu_to_le32(adapter->max_rx_desc_count);
}
/* Window = 1 */
@@ -376,7 +373,7 @@ void netxen_tso_check(struct netxen_adapter *adapter,
((skb->nh.iph)->ihl * sizeof(u32)) +
((skb->h.th)->doff * sizeof(u32));
netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO);
- } else if (skb->ip_summed == CHECKSUM_COMPLETE) {
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (skb->nh.iph->protocol == IPPROTO_TCP) {
netxen_set_cmd_desc_opcode(desc, TX_TCP_PKT);
} else if (skb->nh.iph->protocol == IPPROTO_UDP) {
@@ -387,10 +384,6 @@ void netxen_tso_check(struct netxen_adapter *adapter,
}
adapter->stats.xmitcsummed++;
desc->tcp_hdr_offset = skb->h.raw - skb->data;
- netxen_set_cmd_desc_totallength(desc,
- cpu_to_le32
- (netxen_get_cmd_desc_totallength
- (desc)));
desc->ip_hdr_offset = skb->nh.raw - skb->data;
}
@@ -867,9 +860,9 @@ netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off,
void netxen_nic_set_link_parameters(struct netxen_port *port)
{
struct netxen_adapter *adapter = port->adapter;
- __le32 status;
- __le32 autoneg;
- __le32 mode;
+ __u32 status;
+ __u32 autoneg;
+ __u32 mode;
netxen_nic_read_w0(adapter, NETXEN_NIU_MODE, &mode);
if (netxen_get_niu_enable_ge(mode)) { /* Gb 10/100/1000 Mbps mode */
@@ -984,7 +977,8 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
_NETXEN_NIC_LINUX_MAJOR, fw_major);
adapter->driver_mismatch = 1;
}
- if (fw_minor != _NETXEN_NIC_LINUX_MINOR) {
+ if (fw_minor != _NETXEN_NIC_LINUX_MINOR &&
+ fw_minor != (_NETXEN_NIC_LINUX_MINOR + 1)) {
printk(KERN_ERR "The mismatch in driver version and firmware "
"version minor number\n"
"Driver version minor number = %d \t"
@@ -997,297 +991,3 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
fw_major, fw_minor);
}
-int netxen_crb_read_val(struct netxen_adapter *adapter, unsigned long off)
-{
- int data;
- netxen_nic_hw_read_wx(adapter, off, &data, 4);
- return data;
-}
-
-int netxen_nic_hw_write_ioctl(struct netxen_adapter *adapter, u64 off,
- void *data, int len)
-{
- void *addr;
- u64 offset = off;
- u8 *mem_ptr = NULL;
- unsigned long mem_base;
- unsigned long mem_page;
-
- if (ADDR_IN_WINDOW1(off)) {
- addr = NETXEN_CRB_NORMALIZE(adapter, off);
- if (!addr) {
- mem_base = pci_resource_start(adapter->ahw.pdev, 0);
- offset = NETXEN_CRB_NORMAL(off);
- mem_page = offset & PAGE_MASK;
- if (mem_page != ((offset + len - 1) & PAGE_MASK))
- mem_ptr =
- ioremap(mem_base + mem_page, PAGE_SIZE * 2);
- else
- mem_ptr =
- ioremap(mem_base + mem_page, PAGE_SIZE);
- if (mem_ptr == 0UL) {
- return 1;
- }
- addr = mem_ptr;
- addr += offset & (PAGE_SIZE - 1);
- }
- } else {
- addr = pci_base_offset(adapter, off);
- if (!addr) {
- mem_base = pci_resource_start(adapter->ahw.pdev, 0);
- mem_page = off & PAGE_MASK;
- if (mem_page != ((off + len - 1) & PAGE_MASK))
- mem_ptr =
- ioremap(mem_base + mem_page, PAGE_SIZE * 2);
- else
- mem_ptr =
- ioremap(mem_base + mem_page, PAGE_SIZE);
- if (mem_ptr == 0UL) {
- return 1;
- }
- addr = mem_ptr;
- addr += off & (PAGE_SIZE - 1);
- }
- netxen_nic_pci_change_crbwindow(adapter, 0);
- }
- switch (len) {
- case 1:
- writeb(*(u8 *) data, addr);
- break;
- case 2:
- writew(*(u16 *) data, addr);
- break;
- case 4:
- writel(*(u32 *) data, addr);
- break;
- case 8:
- writeq(*(u64 *) data, addr);
- break;
- default:
- DPRINTK(INFO,
- "writing data %lx to offset %llx, num words=%d\n",
- *(unsigned long *)data, off, (len >> 3));
-
- netxen_nic_hw_block_write64((u64 __iomem *) data, addr,
- (len >> 3));
- break;
- }
-
- if (!ADDR_IN_WINDOW1(off))
- netxen_nic_pci_change_crbwindow(adapter, 1);
- if (mem_ptr)
- iounmap(mem_ptr);
- return 0;
-}
-
-int netxen_nic_hw_read_ioctl(struct netxen_adapter *adapter, u64 off,
- void *data, int len)
-{
- void *addr;
- u64 offset;
- u8 *mem_ptr = NULL;
- unsigned long mem_base;
- unsigned long mem_page;
-
- if (ADDR_IN_WINDOW1(off)) {
- addr = NETXEN_CRB_NORMALIZE(adapter, off);
- if (!addr) {
- mem_base = pci_resource_start(adapter->ahw.pdev, 0);
- offset = NETXEN_CRB_NORMAL(off);
- mem_page = offset & PAGE_MASK;
- if (mem_page != ((offset + len - 1) & PAGE_MASK))
- mem_ptr =
- ioremap(mem_base + mem_page, PAGE_SIZE * 2);
- else
- mem_ptr =
- ioremap(mem_base + mem_page, PAGE_SIZE);
- if (mem_ptr == 0UL) {
- *(u8 *) data = 0;
- return 1;
- }
- addr = mem_ptr;
- addr += offset & (PAGE_SIZE - 1);
- }
- } else {
- addr = pci_base_offset(adapter, off);
- if (!addr) {
- mem_base = pci_resource_start(adapter->ahw.pdev, 0);
- mem_page = off & PAGE_MASK;
- if (mem_page != ((off + len - 1) & PAGE_MASK))
- mem_ptr =
- ioremap(mem_base + mem_page, PAGE_SIZE * 2);
- else
- mem_ptr =
- ioremap(mem_base + mem_page, PAGE_SIZE);
- if (mem_ptr == 0UL)
- return 1;
- addr = mem_ptr;
- addr += off & (PAGE_SIZE - 1);
- }
- netxen_nic_pci_change_crbwindow(adapter, 0);
- }
- switch (len) {
- case 1:
- *(u8 *) data = readb(addr);
- break;
- case 2:
- *(u16 *) data = readw(addr);
- break;
- case 4:
- *(u32 *) data = readl(addr);
- break;
- case 8:
- *(u64 *) data = readq(addr);
- break;
- default:
- netxen_nic_hw_block_read64((u64 __iomem *) data, addr,
- (len >> 3));
- break;
- }
- if (!ADDR_IN_WINDOW1(off))
- netxen_nic_pci_change_crbwindow(adapter, 1);
- if (mem_ptr)
- iounmap(mem_ptr);
- return 0;
-}
-
-int netxen_nic_pci_mem_write_ioctl(struct netxen_adapter *adapter, u64 off,
- void *data, int size)
-{
- void *addr;
- int ret = 0;
- u8 *mem_ptr = NULL;
- unsigned long mem_base;
- unsigned long mem_page;
-
- if (data == NULL || off > (128 * 1024 * 1024)) {
- printk(KERN_ERR "%s: data: %p off:%llx\n",
- netxen_nic_driver_name, data, off);
- return 1;
- }
- off = netxen_nic_pci_set_window(adapter, off);
- /* Corner case : Malicious user tried to break the driver by reading
- last few bytes in ranges and tries to read further addresses.
- */
- if (!pci_base(adapter, off + size - 1) && pci_base(adapter, off)) {
- printk(KERN_ERR "%s: Invalid access to memory address range"
- " 0x%llx - 0x%llx\n", netxen_nic_driver_name, off,
- off + size);
- return 1;
- }
- addr = pci_base_offset(adapter, off);
- DPRINTK(INFO, "writing data %llx to offset %llx\n",
- *(unsigned long long *)data, off);
- if (!addr) {
- mem_base = pci_resource_start(adapter->ahw.pdev, 0);
- mem_page = off & PAGE_MASK;
- /* Map two pages whenever user tries to access addresses in two
- consecutive pages.
- */
- if (mem_page != ((off + size - 1) & PAGE_MASK))
- mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2);
- else
- mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
- if (mem_ptr == 0UL) {
- return 1;
- }
- addr = mem_ptr;
- addr += off & (PAGE_SIZE - 1);
- }
- switch (size) {
- case 1:
- writeb(*(u8 *) data, addr);
- break;
- case 2:
- writew(*(u16 *) data, addr);
- break;
- case 4:
- writel(*(u32 *) data, addr);
- break;
- case 8:
- writeq(*(u64 *) data, addr);
- break;
- default:
- DPRINTK(INFO,
- "writing data %lx to offset %llx, num words=%d\n",
- *(unsigned long *)data, off, (size >> 3));
-
- netxen_nic_hw_block_write64((u64 __iomem *) data, addr,
- (size >> 3));
- break;
- }
-
- if (mem_ptr)
- iounmap(mem_ptr);
- DPRINTK(INFO, "wrote %llx\n", *(unsigned long long *)data);
-
- return ret;
-}
-
-int netxen_nic_pci_mem_read_ioctl(struct netxen_adapter *adapter,
- u64 off, void *data, int size)
-{
- void *addr;
- int ret = 0;
- u8 *mem_ptr = NULL;
- unsigned long mem_base;
- unsigned long mem_page;
-
- if (data == NULL || off > (128 * 1024 * 1024)) {
- printk(KERN_ERR "%s: data: %p off:%llx\n",
- netxen_nic_driver_name, data, off);
- return 1;
- }
- off = netxen_nic_pci_set_window(adapter, off);
- /* Corner case : Malicious user tried to break the driver by reading
- last few bytes in ranges and tries to read further addresses.
- */
- if (!pci_base(adapter, off + size - 1) && pci_base(adapter, off)) {
- printk(KERN_ERR "%s: Invalid access to memory address range"
- " 0x%llx - 0x%llx\n", netxen_nic_driver_name, off,
- off + size);
- return 1;
- }
- addr = pci_base_offset(adapter, off);
- if (!addr) {
- mem_base = pci_resource_start(adapter->ahw.pdev, 0);
- mem_page = off & PAGE_MASK;
- /* Map two pages whenever user tries to access addresses in two
- consecutive pages.
- */
- if (mem_page != ((off + size - 1) & PAGE_MASK))
- mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2);
- else
- mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
- if (mem_ptr == 0UL) {
- *(u8 *) data = 0;
- return 1;
- }
- addr = mem_ptr;
- addr += off & (PAGE_SIZE - 1);
- }
- switch (size) {
- case 1:
- *(u8 *) data = readb(addr);
- break;
- case 2:
- *(u16 *) data = readw(addr);
- break;
- case 4:
- *(u32 *) data = readl(addr);
- break;
- case 8:
- *(u64 *) data = readq(addr);
- break;
- default:
- netxen_nic_hw_block_read64((u64 __iomem *) data, addr,
- (size >> 3));
- break;
- }
-
- if (mem_ptr)
- iounmap(mem_ptr);
- DPRINTK(INFO, "read %llx\n", *(unsigned long long *)data);
-
- return ret;
-}
diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h
index 0685633a9c1..ab1112eb1b0 100644
--- a/drivers/net/netxen/netxen_nic_hw.h
+++ b/drivers/net/netxen/netxen_nic_hw.h
@@ -124,28 +124,28 @@ typedef enum {
*/
#define netxen_gb_enable_tx(config_word) \
- set_bit(0, (unsigned long*)(&config_word))
+ ((config_word) |= 1 << 0)
#define netxen_gb_enable_rx(config_word) \
- set_bit(2, (unsigned long*)(&config_word))
+ ((config_word) |= 1 << 2)
#define netxen_gb_tx_flowctl(config_word) \
- set_bit(4, (unsigned long*)(&config_word))
+ ((config_word) |= 1 << 4)
#define netxen_gb_rx_flowctl(config_word) \
- set_bit(5, (unsigned long*)(&config_word))
+ ((config_word) |= 1 << 5)
#define netxen_gb_tx_reset_pb(config_word) \
- set_bit(16, (unsigned long*)(&config_word))
+ ((config_word) |= 1 << 16)
#define netxen_gb_rx_reset_pb(config_word) \
- set_bit(17, (unsigned long*)(&config_word))
+ ((config_word) |= 1 << 17)
#define netxen_gb_tx_reset_mac(config_word) \
- set_bit(18, (unsigned long*)(&config_word))
+ ((config_word) |= 1 << 18)
#define netxen_gb_rx_reset_mac(config_word) \
- set_bit(19, (unsigned long*)(&config_word))
+ ((config_word) |= 1 << 19)
#define netxen_gb_soft_reset(config_word) \
- set_bit(31, (unsigned long*)(&config_word))
+ ((config_word) |= 1 << 31)
#define netxen_gb_unset_tx_flowctl(config_word) \
- clear_bit(4, (unsigned long *)(&config_word))
+ ((config_word) &= ~(1 << 4))
#define netxen_gb_unset_rx_flowctl(config_word) \
- clear_bit(5, (unsigned long*)(&config_word))
+ ((config_word) &= ~(1 << 5))
#define netxen_gb_get_tx_synced(config_word) \
_netxen_crb_get_bit((config_word), 1)
@@ -171,15 +171,15 @@ typedef enum {
*/
#define netxen_gb_set_duplex(config_word) \
- set_bit(0, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 0)
#define netxen_gb_set_crc_enable(config_word) \
- set_bit(1, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 1)
#define netxen_gb_set_padshort(config_word) \
- set_bit(2, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 2)
#define netxen_gb_set_checklength(config_word) \
- set_bit(4, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 4)
#define netxen_gb_set_hugeframes(config_word) \
- set_bit(5, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 5)
#define netxen_gb_set_preamblelen(config_word, val) \
((config_word) |= ((val) << 12) & 0xF000)
#define netxen_gb_set_intfmode(config_word, val) \
@@ -190,9 +190,9 @@ typedef enum {
#define netxen_gb_set_mii_mgmt_clockselect(config_word, val) \
((config_word) |= ((val) & 0x07))
#define netxen_gb_mii_mgmt_reset(config_word) \
- set_bit(31, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 31)
#define netxen_gb_mii_mgmt_unset(config_word) \
- clear_bit(31, (unsigned long*)&config_word)
+ ((config_word) &= ~(1 << 31))
/*
* NIU GB MII Mgmt Command Register (applies to GB0, GB1, GB2, GB3)
@@ -201,7 +201,7 @@ typedef enum {
*/
#define netxen_gb_mii_mgmt_set_read_cycle(config_word) \
- set_bit(0, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 0)
#define netxen_gb_mii_mgmt_reg_addr(config_word, val) \
((config_word) |= ((val) & 0x1F))
#define netxen_gb_mii_mgmt_phy_addr(config_word, val) \
@@ -274,9 +274,9 @@ typedef enum {
#define netxen_set_phy_speed(config_word, val) \
((config_word) |= ((val & 0x03) << 14))
#define netxen_set_phy_duplex(config_word) \
- set_bit(13, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 13)
#define netxen_clear_phy_duplex(config_word) \
- clear_bit(13, (unsigned long*)&config_word)
+ ((config_word) &= ~(1 << 13))
#define netxen_get_phy_jabber(config_word) \
_netxen_crb_get_bit(config_word, 0)
@@ -350,11 +350,11 @@ typedef enum {
_netxen_crb_get_bit(config_word, 15)
#define netxen_set_phy_int_link_status_changed(config_word) \
- set_bit(10, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 10)
#define netxen_set_phy_int_autoneg_completed(config_word) \
- set_bit(11, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 11)
#define netxen_set_phy_int_speed_changed(config_word) \
- set_bit(14, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 14)
/*
* NIU Mode Register.
@@ -382,22 +382,22 @@ typedef enum {
*/
#define netxen_set_gb_drop_gb0(config_word) \
- set_bit(0, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 0)
#define netxen_set_gb_drop_gb1(config_word) \
- set_bit(1, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 1)
#define netxen_set_gb_drop_gb2(config_word) \
- set_bit(2, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 2)
#define netxen_set_gb_drop_gb3(config_word) \
- set_bit(3, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 3)
#define netxen_clear_gb_drop_gb0(config_word) \
- clear_bit(0, (unsigned long*)&config_word)
+ ((config_word) &= ~(1 << 0))
#define netxen_clear_gb_drop_gb1(config_word) \
- clear_bit(1, (unsigned long*)&config_word)
+ ((config_word) &= ~(1 << 1))
#define netxen_clear_gb_drop_gb2(config_word) \
- clear_bit(2, (unsigned long*)&config_word)
+ ((config_word) &= ~(1 << 2))
#define netxen_clear_gb_drop_gb3(config_word) \
- clear_bit(3, (unsigned long*)&config_word)
+ ((config_word) &= ~(1 << 3))
/*
* NIU XG MAC Config Register
@@ -413,7 +413,7 @@ typedef enum {
*/
#define netxen_xg_soft_reset(config_word) \
- set_bit(4, (unsigned long*)&config_word)
+ ((config_word) |= 1 << 4)
/*
* MAC Control Register
@@ -433,19 +433,19 @@ typedef enum {
#define netxen_nic_mcr_set_id_pool0(config, val) \
((config) |= ((val) &0x03))
#define netxen_nic_mcr_set_enable_xtnd0(config) \
- (set_bit(3, (unsigned long *)&(config)))
+ ((config) |= 1 << 3)
#define netxen_nic_mcr_set_id_pool1(config, val) \
((config) |= (((val) & 0x03) << 4))
#define netxen_nic_mcr_set_enable_xtnd1(config) \
- (set_bit(6, (unsigned long *)&(config)))
+ ((config) |= 1 << 6)
#define netxen_nic_mcr_set_id_pool2(config, val) \
((config) |= (((val) & 0x03) << 8))
#define netxen_nic_mcr_set_enable_xtnd2(config) \
- (set_bit(10, (unsigned long *)&(config)))
+ ((config) |= 1 << 10)
#define netxen_nic_mcr_set_id_pool3(config, val) \
((config) |= (((val) & 0x03) << 12))
#define netxen_nic_mcr_set_enable_xtnd3(config) \
- (set_bit(14, (unsigned long *)&(config)))
+ ((config) |= 1 << 14)
#define netxen_nic_mcr_set_mode_select(config, val) \
((config) |= (((val) & 0x03) << 24))
#define netxen_nic_mcr_set_enable_pool(config, val) \
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 869725f0bb1..f7bb8c90537 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -35,7 +35,6 @@
#include <linux/delay.h>
#include "netxen_nic.h"
#include "netxen_nic_hw.h"
-#include "netxen_nic_ioctl.h"
#include "netxen_nic_phan_reg.h"
struct crb_addr_pair {
@@ -111,6 +110,7 @@ static void crb_addr_transform_setup(void)
crb_addr_transform(CAM);
crb_addr_transform(C2C1);
crb_addr_transform(C2C0);
+ crb_addr_transform(SMB);
}
int netxen_init_firmware(struct netxen_adapter *adapter)
@@ -277,6 +277,7 @@ unsigned long netxen_decode_crb_addr(unsigned long addr)
static long rom_max_timeout = 10000;
static long rom_lock_timeout = 1000000;
+static long rom_write_timeout = 700;
static inline int rom_lock(struct netxen_adapter *adapter)
{
@@ -405,7 +406,7 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
{
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
- udelay(100); /* prevent bursting on CRB */
+ udelay(70); /* prevent bursting on CRB */
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb);
if (netxen_wait_rom_done(adapter)) {
@@ -414,13 +415,46 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
}
/* reset abyte_cnt and dummy_byte_cnt */
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
- udelay(100); /* prevent bursting on CRB */
+ udelay(70); /* prevent bursting on CRB */
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
*valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA);
return 0;
}
+static inline int
+do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size)
+{
+ int addridx;
+ int ret = 0;
+
+ for (addridx = addr; addridx < (addr + size); addridx += 4) {
+ ret = do_rom_fast_read(adapter, addridx, (int *)bytes);
+ if (ret != 0)
+ break;
+ bytes += 4;
+ }
+
+ return ret;
+}
+
+int
+netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size)
+{
+ int ret;
+
+ ret = rom_lock(adapter);
+ if (ret < 0)
+ return ret;
+
+ ret = do_rom_fast_read_words(adapter, addr, bytes, size);
+
+ netxen_rom_unlock(adapter);
+ return ret;
+}
+
int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
{
int ret;
@@ -444,6 +478,152 @@ int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data)
netxen_rom_unlock(adapter);
return ret;
}
+
+static inline int do_rom_fast_write_words(struct netxen_adapter *adapter,
+ int addr, u8 *bytes, size_t size)
+{
+ int addridx = addr;
+ int ret = 0;
+
+ while (addridx < (addr + size)) {
+ int last_attempt = 0;
+ int timeout = 0;
+ int data;
+
+ data = *(u32*)bytes;
+
+ ret = do_rom_fast_write(adapter, addridx, data);
+ if (ret < 0)
+ return ret;
+
+ while(1) {
+ int data1;
+
+ do_rom_fast_read(adapter, addridx, &data1);
+ if (data1 == data)
+ break;
+
+ if (timeout++ >= rom_write_timeout) {
+ if (last_attempt++ < 4) {
+ ret = do_rom_fast_write(adapter,
+ addridx, data);
+ if (ret < 0)
+ return ret;
+ }
+ else {
+ printk(KERN_INFO "Data write did not "
+ "succeed at address 0x%x\n", addridx);
+ break;
+ }
+ }
+ }
+
+ bytes += 4;
+ addridx += 4;
+ }
+
+ return ret;
+}
+
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size)
+{
+ int ret = 0;
+
+ ret = rom_lock(adapter);
+ if (ret < 0)
+ return ret;
+
+ ret = do_rom_fast_write_words(adapter, addr, bytes, size);
+ netxen_rom_unlock(adapter);
+
+ return ret;
+}
+
+int netxen_rom_wrsr(struct netxen_adapter *adapter, int data)
+{
+ int ret;
+
+ ret = netxen_rom_wren(adapter);
+ if (ret < 0)
+ return ret;
+
+ netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_WDATA, data);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0x1);
+
+ ret = netxen_wait_rom_done(adapter);
+ if (ret < 0)
+ return ret;
+
+ return netxen_rom_wip_poll(adapter);
+}
+
+int netxen_rom_rdsr(struct netxen_adapter *adapter)
+{
+ int ret;
+
+ ret = rom_lock(adapter);
+ if (ret < 0)
+ return ret;
+
+ ret = netxen_do_rom_rdsr(adapter);
+ netxen_rom_unlock(adapter);
+ return ret;
+}
+
+int netxen_backup_crbinit(struct netxen_adapter *adapter)
+{
+ int ret = FLASH_SUCCESS;
+ int val;
+ char *buffer = kmalloc(FLASH_SECTOR_SIZE, GFP_KERNEL);
+
+ if (!buffer)
+ return -ENOMEM;
+ /* unlock sector 63 */
+ val = netxen_rom_rdsr(adapter);
+ val = val & 0xe3;
+ ret = netxen_rom_wrsr(adapter, val);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ /* copy sector 0 to sector 63 */
+ ret = netxen_rom_fast_read_words(adapter, CRBINIT_START,
+ buffer, FLASH_SECTOR_SIZE);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ ret = netxen_rom_fast_write_words(adapter, FIXED_START,
+ buffer, FLASH_SECTOR_SIZE);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ /* lock sector 63 */
+ val = netxen_rom_rdsr(adapter);
+ if (!(val & 0x8)) {
+ val |= (0x1 << 2);
+ /* lock sector 63 */
+ if (netxen_rom_wrsr(adapter, val) == 0) {
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ /* lock SR writes */
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+ }
+ }
+
+out_kfree:
+ kfree(buffer);
+ return ret;
+}
+
int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
{
netxen_rom_wren(adapter);
@@ -458,6 +638,27 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
return netxen_rom_wip_poll(adapter);
}
+void check_erased_flash(struct netxen_adapter *adapter, int addr)
+{
+ int i;
+ int val;
+ int count = 0, erased_errors = 0;
+ int range;
+
+ range = (addr == USER_START) ? FIXED_START : addr + FLASH_SECTOR_SIZE;
+
+ for (i = addr; i < range; i += 4) {
+ netxen_rom_fast_read(adapter, i, &val);
+ if (val != 0xffffffff)
+ erased_errors++;
+ count++;
+ }
+
+ if (erased_errors)
+ printk(KERN_INFO "0x%x out of 0x%x words fail to be erased "
+ "for sector address: %x\n", erased_errors, count, addr);
+}
+
int netxen_rom_se(struct netxen_adapter *adapter, int addr)
{
int ret = 0;
@@ -466,6 +667,68 @@ int netxen_rom_se(struct netxen_adapter *adapter, int addr)
}
ret = netxen_do_rom_se(adapter, addr);
netxen_rom_unlock(adapter);
+ msleep(30);
+ check_erased_flash(adapter, addr);
+
+ return ret;
+}
+
+int
+netxen_flash_erase_sections(struct netxen_adapter *adapter, int start, int end)
+{
+ int ret = FLASH_SUCCESS;
+ int i;
+
+ for (i = start; i < end; i++) {
+ ret = netxen_rom_se(adapter, i * FLASH_SECTOR_SIZE);
+ if (ret)
+ break;
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+int
+netxen_flash_erase_secondary(struct netxen_adapter *adapter)
+{
+ int ret = FLASH_SUCCESS;
+ int start, end;
+
+ start = SECONDARY_START / FLASH_SECTOR_SIZE;
+ end = USER_START / FLASH_SECTOR_SIZE;
+ ret = netxen_flash_erase_sections(adapter, start, end);
+
+ return ret;
+}
+
+int
+netxen_flash_erase_primary(struct netxen_adapter *adapter)
+{
+ int ret = FLASH_SUCCESS;
+ int start, end;
+
+ start = PRIMARY_START / FLASH_SECTOR_SIZE;
+ end = SECONDARY_START / FLASH_SECTOR_SIZE;
+ ret = netxen_flash_erase_sections(adapter, start, end);
+
+ return ret;
+}
+
+int netxen_flash_unlock(struct netxen_adapter *adapter)
+{
+ int ret = 0;
+
+ ret = netxen_rom_wrsr(adapter, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = netxen_rom_wren(adapter);
+ if (ret < 0)
+ return ret;
+
return ret;
}
@@ -544,9 +807,13 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
}
for (i = 0; i < n; i++) {
- off =
- netxen_decode_crb_addr((unsigned long)buf[i].addr) +
- NETXEN_PCI_CRBSPACE;
+ off = netxen_decode_crb_addr((unsigned long)buf[i].addr);
+ if (off == NETXEN_ADDR_ERROR) {
+ printk(KERN_ERR"CRB init value out of range %lx\n",
+ buf[i].addr);
+ continue;
+ }
+ off += NETXEN_PCI_CRBSPACE;
/* skipping cold reboot MAGIC */
if (off == NETXEN_CAM_RAM(0x1fc))
continue;
@@ -663,6 +930,7 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
int loops = 0;
if (!pegtune_val) {
+ val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
udelay(100);
schedule();
@@ -691,8 +959,7 @@ int netxen_nic_rx_has_work(struct netxen_adapter *adapter)
desc_head = recv_ctx->rcv_status_desc_head;
desc = &desc_head[consumer];
- if (((le16_to_cpu(netxen_get_sts_owner(desc)))
- & STATUS_OWNER_HOST))
+ if (netxen_get_sts_owner(desc) & STATUS_OWNER_HOST)
return 1;
}
@@ -788,11 +1055,11 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
struct netxen_port *port = adapter->port[netxen_get_sts_port(desc)];
struct pci_dev *pdev = port->pdev;
struct net_device *netdev = port->netdev;
- int index = le16_to_cpu(netxen_get_sts_refhandle(desc));
+ int index = netxen_get_sts_refhandle(desc);
struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]);
struct netxen_rx_buffer *buffer;
struct sk_buff *skb;
- u32 length = le16_to_cpu(netxen_get_sts_totallength(desc));
+ u32 length = netxen_get_sts_totallength(desc);
u32 desc_ctx;
struct netxen_rcv_desc_ctx *rcv_desc;
int ret;
@@ -919,9 +1186,7 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max)
*/
while (count < max) {
desc = &desc_head[consumer];
- if (!
- (le16_to_cpu(netxen_get_sts_owner(desc)) &
- STATUS_OWNER_HOST)) {
+ if (!(netxen_get_sts_owner(desc) & STATUS_OWNER_HOST)) {
DPRINTK(ERR, "desc %p ownedby %x\n", desc,
netxen_get_sts_owner(desc));
break;
@@ -1023,7 +1288,7 @@ int netxen_process_cmd_ring(unsigned long data)
&& netif_carrier_ok(port->netdev))
&& ((jiffies - port->netdev->trans_start) >
port->netdev->watchdog_timeo)) {
- SCHEDULE_WORK(&port->adapter->tx_timeout_task);
+ SCHEDULE_WORK(&port->tx_timeout_task);
}
last_consumer = get_next_index(last_consumer,
@@ -1138,13 +1403,13 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
*/
dma = pci_map_single(pdev, skb->data, rcv_desc->dma_size,
PCI_DMA_FROMDEVICE);
- pdesc->addr_buffer = dma;
+ pdesc->addr_buffer = cpu_to_le64(dma);
buffer->skb = skb;
buffer->state = NETXEN_BUFFER_BUSY;
buffer->dma = dma;
/* make a rcv descriptor */
- pdesc->reference_handle = buffer->ref_handle;
- pdesc->buffer_length = rcv_desc->dma_size;
+ pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+ pdesc->buffer_length = cpu_to_le32(rcv_desc->dma_size);
DPRINTK(INFO, "done writing descripter\n");
producer =
get_next_index(producer, rcv_desc->max_rx_desc_count);
@@ -1232,8 +1497,8 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
PCI_DMA_FROMDEVICE);
/* make a rcv descriptor */
- pdesc->reference_handle = le16_to_cpu(buffer->ref_handle);
- pdesc->buffer_length = le16_to_cpu(rcv_desc->dma_size);
+ pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+ pdesc->buffer_length = cpu_to_le32(rcv_desc->dma_size);
pdesc->addr_buffer = cpu_to_le64(buffer->dma);
DPRINTK(INFO, "done writing descripter\n");
producer =
@@ -1273,52 +1538,6 @@ int netxen_nic_tx_has_work(struct netxen_adapter *adapter)
return 0;
}
-int
-netxen_nic_fill_statistics(struct netxen_adapter *adapter,
- struct netxen_port *port,
- struct netxen_statistics *netxen_stats)
-{
- void __iomem *addr;
-
- if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
- netxen_nic_pci_change_crbwindow(adapter, 0);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_TX_BYTE_CNT,
- &(netxen_stats->tx_bytes));
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_TX_FRAME_CNT,
- &(netxen_stats->tx_packets));
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_RX_BYTE_CNT,
- &(netxen_stats->rx_bytes));
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_RX_FRAME_CNT,
- &(netxen_stats->rx_packets));
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_AGGR_ERROR_CNT,
- &(netxen_stats->rx_errors));
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_CRC_ERROR_CNT,
- &(netxen_stats->rx_crc_errors));
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_OVERSIZE_FRAME_ERR,
- &(netxen_stats->
- rx_long_length_error));
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_UNDERSIZE_FRAME_ERR,
- &(netxen_stats->
- rx_short_length_error));
-
- netxen_nic_pci_change_crbwindow(adapter, 1);
- } else {
- spin_lock_bh(&adapter->tx_lock);
- netxen_stats->tx_bytes = port->stats.txbytes;
- netxen_stats->tx_packets = port->stats.xmitedframes +
- port->stats.xmitfinished;
- netxen_stats->rx_bytes = port->stats.rxbytes;
- netxen_stats->rx_packets = port->stats.no_rcv;
- netxen_stats->rx_errors = port->stats.rcvdbadskb;
- netxen_stats->tx_errors = port->stats.nocmddescriptor;
- netxen_stats->rx_short_length_error = port->stats.uplcong;
- netxen_stats->rx_long_length_error = port->stats.uphcong;
- netxen_stats->rx_crc_errors = 0;
- netxen_stats->rx_mac_errors = 0;
- spin_unlock_bh(&adapter->tx_lock);
- }
- return 0;
-}
void netxen_nic_clear_stats(struct netxen_adapter *adapter)
{
@@ -1332,193 +1551,3 @@ void netxen_nic_clear_stats(struct netxen_adapter *adapter)
}
}
-int
-netxen_nic_clear_statistics(struct netxen_adapter *adapter,
- struct netxen_port *port)
-{
- int data = 0;
-
- netxen_nic_pci_change_crbwindow(adapter, 0);
-
- netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_TX_BYTE_CNT, &data);
- netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_TX_FRAME_CNT,
- &data);
- netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_RX_BYTE_CNT, &data);
- netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_RX_FRAME_CNT,
- &data);
- netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_AGGR_ERROR_CNT,
- &data);
- netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_CRC_ERROR_CNT,
- &data);
- netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_OVERSIZE_FRAME_ERR,
- &data);
- netxen_nic_locked_write_reg(adapter, NETXEN_NIU_XGE_UNDERSIZE_FRAME_ERR,
- &data);
-
- netxen_nic_pci_change_crbwindow(adapter, 1);
- netxen_nic_clear_stats(adapter);
- return 0;
-}
-
-int
-netxen_nic_do_ioctl(struct netxen_adapter *adapter, void *u_data,
- struct netxen_port *port)
-{
- struct netxen_nic_ioctl_data data;
- struct netxen_nic_ioctl_data *up_data;
- int retval = 0;
- struct netxen_statistics netxen_stats;
-
- up_data = (void *)u_data;
-
- DPRINTK(INFO, "doing ioctl for %p\n", adapter);
- if (copy_from_user(&data, (void __user *)up_data, sizeof(data))) {
- /* evil user tried to crash the kernel */
- DPRINTK(ERR, "bad copy from userland: %d\n", (int)sizeof(data));
- retval = -EFAULT;
- goto error_out;
- }
-
- /* Shouldn't access beyond legal limits of "char u[64];" member */
- if (!data.ptr && (data.size > sizeof(data.u))) {
- /* evil user tried to crash the kernel */
- DPRINTK(ERR, "bad size: %d\n", data.size);
- retval = -EFAULT;
- goto error_out;
- }
-
- switch (data.cmd) {
- case netxen_nic_cmd_pci_read:
- if ((retval = netxen_nic_hw_read_ioctl(adapter, data.off,
- &(data.u), data.size)))
- goto error_out;
- if (copy_to_user
- ((void __user *)&(up_data->u), &(data.u), data.size)) {
- DPRINTK(ERR, "bad copy to userland: %d\n",
- (int)sizeof(data));
- retval = -EFAULT;
- goto error_out;
- }
- data.rv = 0;
- break;
-
- case netxen_nic_cmd_pci_write:
- if ((retval = netxen_nic_hw_write_ioctl(adapter, data.off,
- &(data.u), data.size)))
- goto error_out;
- data.rv = 0;
- break;
-
- case netxen_nic_cmd_pci_mem_read:
- if (netxen_nic_pci_mem_read_ioctl(adapter, data.off, &(data.u),
- data.size)) {
- DPRINTK(ERR, "Failed to read the data.\n");
- retval = -EFAULT;
- goto error_out;
- }
- if (copy_to_user
- ((void __user *)&(up_data->u), &(data.u), data.size)) {
- DPRINTK(ERR, "bad copy to userland: %d\n",
- (int)sizeof(data));
- retval = -EFAULT;
- goto error_out;
- }
- data.rv = 0;
- break;
-
- case netxen_nic_cmd_pci_mem_write:
- if ((retval = netxen_nic_pci_mem_write_ioctl(adapter, data.off,
- &(data.u),
- data.size)))
- goto error_out;
- data.rv = 0;
- break;
-
- case netxen_nic_cmd_pci_config_read:
- switch (data.size) {
- case 1:
- data.rv = pci_read_config_byte(adapter->ahw.pdev,
- data.off,
- (char *)&(data.u));
- break;
- case 2:
- data.rv = pci_read_config_word(adapter->ahw.pdev,
- data.off,
- (short *)&(data.u));
- break;
- case 4:
- data.rv = pci_read_config_dword(adapter->ahw.pdev,
- data.off,
- (u32 *) & (data.u));
- break;
- }
- if (copy_to_user
- ((void __user *)&(up_data->u), &(data.u), data.size)) {
- DPRINTK(ERR, "bad copy to userland: %d\n",
- (int)sizeof(data));
- retval = -EFAULT;
- goto error_out;
- }
- break;
-
- case netxen_nic_cmd_pci_config_write:
- switch (data.size) {
- case 1:
- data.rv = pci_write_config_byte(adapter->ahw.pdev,
- data.off,
- *(char *)&(data.u));
- break;
- case 2:
- data.rv = pci_write_config_word(adapter->ahw.pdev,
- data.off,
- *(short *)&(data.u));
- break;
- case 4:
- data.rv = pci_write_config_dword(adapter->ahw.pdev,
- data.off,
- *(u32 *) & (data.u));
- break;
- }
- break;
-
- case netxen_nic_cmd_get_stats:
- data.rv =
- netxen_nic_fill_statistics(adapter, port, &netxen_stats);
- if (copy_to_user
- ((void __user *)(up_data->ptr), (void *)&netxen_stats,
- sizeof(struct netxen_statistics))) {
- DPRINTK(ERR, "bad copy to userland: %d\n",
- (int)sizeof(netxen_stats));
- retval = -EFAULT;
- goto error_out;
- }
- up_data->rv = data.rv;
- break;
-
- case netxen_nic_cmd_clear_stats:
- data.rv = netxen_nic_clear_statistics(adapter, port);
- up_data->rv = data.rv;
- break;
-
- case netxen_nic_cmd_get_version:
- if (copy_to_user
- ((void __user *)&(up_data->u), NETXEN_NIC_LINUX_VERSIONID,
- sizeof(NETXEN_NIC_LINUX_VERSIONID))) {
- DPRINTK(ERR, "bad copy to userland: %d\n",
- (int)sizeof(data));
- retval = -EFAULT;
- goto error_out;
- }
- break;
-
- default:
- DPRINTK(INFO, "bad command %d for %p\n", data.cmd, adapter);
- retval = -EOPNOTSUPP;
- goto error_out;
- }
- put_user(data.rv, (&(up_data->rv)));
- DPRINTK(INFO, "done ioctl for %p well.\n", adapter);
-
- error_out:
- return retval;
-}
diff --git a/drivers/net/netxen/netxen_nic_ioctl.h b/drivers/net/netxen/netxen_nic_ioctl.h
deleted file mode 100644
index 1221fa52755..00000000000
--- a/drivers/net/netxen/netxen_nic_ioctl.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2003 - 2006 NetXen, 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 program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
- *
- * Contact Information:
- * info@netxen.com
- * NetXen,
- * 3965 Freedom Circle, Fourth floor,
- * Santa Clara, CA 95054
- */
-
-#ifndef __NETXEN_NIC_IOCTL_H__
-#define __NETXEN_NIC_IOCTL_H__
-
-#include <linux/sockios.h>
-
-#define NETXEN_CMD_START SIOCDEVPRIVATE
-#define NETXEN_NIC_CMD (NETXEN_CMD_START + 1)
-#define NETXEN_NIC_NAME (NETXEN_CMD_START + 2)
-#define NETXEN_NIC_NAME_LEN 16
-#define NETXEN_NIC_NAME_RSP "NETXEN-UNM"
-
-typedef enum {
- netxen_nic_cmd_none = 0,
- netxen_nic_cmd_pci_read,
- netxen_nic_cmd_pci_write,
- netxen_nic_cmd_pci_mem_read,
- netxen_nic_cmd_pci_mem_write,
- netxen_nic_cmd_pci_config_read,
- netxen_nic_cmd_pci_config_write,
- netxen_nic_cmd_get_stats,
- netxen_nic_cmd_clear_stats,
- netxen_nic_cmd_get_version
-} netxen_nic_ioctl_cmd_t;
-
-struct netxen_nic_ioctl_data {
- u32 cmd;
- u32 unused1;
- u64 off;
- u32 size;
- u32 rv;
- char u[64];
- void *ptr;
-};
-
-struct netxen_statistics {
- u64 rx_packets;
- u64 tx_packets;
- u64 rx_bytes;
- u64 rx_errors;
- u64 tx_bytes;
- u64 tx_errors;
- u64 rx_crc_errors;
- u64 rx_short_length_error;
- u64 rx_long_length_error;
- u64 rx_mac_errors;
-};
-
-#endif /* __NETXEN_NIC_IOCTL_H_ */
diff --git a/drivers/net/netxen/netxen_nic_isr.c b/drivers/net/netxen/netxen_nic_isr.c
index 1b45f50fa6a..be366e48007 100644
--- a/drivers/net/netxen/netxen_nic_isr.c
+++ b/drivers/net/netxen/netxen_nic_isr.c
@@ -79,7 +79,7 @@ void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno,
void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
u32 enable)
{
- __le32 int_src;
+ __u32 int_src;
struct netxen_port *port;
/* This should clear the interrupt source */
@@ -110,7 +110,7 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
/* write it down later.. */
if ((netxen_get_phy_int_speed_changed(int_src))
|| (netxen_get_phy_int_link_status_changed(int_src))) {
- __le32 status;
+ __u32 status;
DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n");
@@ -157,7 +157,8 @@ void netxen_nic_isr_other(struct netxen_adapter *adapter)
for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) {
linkup = val & 1;
if (linkup != (qg_linksup & 1)) {
- printk(KERN_INFO "%s: PORT %d link %s\n",
+ printk(KERN_INFO "%s: %s PORT %d link %s\n",
+ adapter->port[portno]->netdev->name,
netxen_nic_driver_name, portno,
((linkup == 0) ? "down" : "up"));
netxen_indicate_link_status(adapter, portno, linkup);
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 575b71b6720..69c1b9d23a1 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -38,7 +38,6 @@
#include "netxen_nic.h"
#define DEFINE_GLOBAL_RECV_CRB
#include "netxen_nic_phan_reg.h"
-#include "netxen_nic_ioctl.h"
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
@@ -53,8 +52,6 @@ char netxen_nic_driver_name[] = "netxen-nic";
static char netxen_nic_driver_string[] = "NetXen Network Driver version "
NETXEN_NIC_LINUX_VERSIONID;
-struct netxen_adapter *g_adapter = NULL;
-
#define NETXEN_NETDEV_WEIGHT 120
#define NETXEN_ADAPTER_UP_MAGIC 777
#define NETXEN_NIC_PEG_TUNE 0
@@ -75,8 +72,6 @@ static void netxen_tx_timeout(struct net_device *netdev);
static void netxen_tx_timeout_task(struct work_struct *work);
static void netxen_watchdog(unsigned long);
static int netxen_handle_int(struct netxen_adapter *, struct net_device *);
-static int netxen_nic_ioctl(struct net_device *netdev,
- struct ifreq *ifr, int cmd);
static int netxen_nic_poll(struct net_device *dev, int *budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void netxen_nic_poll_controller(struct net_device *netdev);
@@ -90,6 +85,8 @@ static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
{PCI_DEVICE(0x4040, 0x0003)},
{PCI_DEVICE(0x4040, 0x0004)},
{PCI_DEVICE(0x4040, 0x0005)},
+ {PCI_DEVICE(0x4040, 0x0024)},
+ {PCI_DEVICE(0x4040, 0x0025)},
{0,}
};
@@ -120,7 +117,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
void __iomem *mem_ptr1 = NULL;
void __iomem *mem_ptr2 = NULL;
- u8 *db_ptr = NULL;
+ u8 __iomem *db_ptr = NULL;
unsigned long mem_base, mem_len, db_base, db_len;
int pci_using_dac, i, err;
int ring;
@@ -129,7 +126,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct netxen_cmd_buffer *cmd_buf_arr = NULL;
u64 mac_addr[FLASH_NUM_PORTS + 1];
int valid_mac = 0;
- static int netxen_cards_found = 0;
printk(KERN_INFO "%s \n", netxen_nic_driver_string);
/* In current scheme, we use only PCI function 0 */
@@ -195,7 +191,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
db_len);
db_ptr = ioremap(db_base, NETXEN_DB_MAPSIZE_BYTES);
- if (db_ptr == 0UL) {
+ if (!db_ptr) {
printk(KERN_ERR "%s: Failed to allocate doorbell map.",
netxen_nic_driver_name);
err = -EIO;
@@ -220,9 +216,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_dbunmap;
}
- if (netxen_cards_found == 0) {
- g_adapter = adapter;
- }
adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS;
adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS;
@@ -383,7 +376,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->set_multicast_list = netxen_nic_set_multi;
netdev->set_mac_address = netxen_nic_set_mac;
netdev->change_mtu = netxen_nic_change_mtu;
- netdev->do_ioctl = netxen_nic_ioctl;
netdev->tx_timeout = netxen_tx_timeout;
netdev->watchdog_timeo = HZ;
@@ -428,8 +420,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->dev_addr);
}
}
- adapter->netdev = netdev;
- INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task);
+ INIT_WORK(&port->tx_timeout_task, netxen_tx_timeout_task);
netif_carrier_off(netdev);
netif_stop_queue(netdev);
@@ -444,6 +435,11 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->port[i] = port;
}
+ writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
+ netxen_pinit_from_rom(adapter, 0);
+ udelay(500);
+ netxen_load_firmware(adapter);
+ netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
/*
* delay a while to ensure that the Pegs are up & running.
* Otherwise, we might see some flaky behaviour.
@@ -461,7 +457,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
break;
}
- adapter->number = netxen_cards_found;
adapter->driver_mismatch = 0;
return 0;
@@ -531,6 +526,8 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
netxen_nic_stop_all_ports(adapter);
/* leave the hw in the same state as reboot */
+ netxen_pinit_from_rom(adapter, 0);
+ writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
netxen_load_firmware(adapter);
netxen_free_adapter_offload(adapter);
@@ -822,7 +819,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
pbuf = &adapter->cmd_buf_arr[producer];
if ((netdev->features & NETIF_F_TSO) && skb_shinfo(skb)->gso_size > 0) {
pbuf->mss = skb_shinfo(skb)->gso_size;
- hwdesc->mss = skb_shinfo(skb)->gso_size;
+ hwdesc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
} else {
pbuf->mss = 0;
hwdesc->mss = 0;
@@ -885,7 +882,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
hwdesc->addr_buffer3 = cpu_to_le64(temp_dma);
break;
case 3:
- hwdesc->buffer4_length = temp_len;
+ hwdesc->buffer4_length = cpu_to_le16(temp_len);
hwdesc->addr_buffer4 = cpu_to_le64(temp_dma);
break;
}
@@ -956,11 +953,6 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
static void netxen_watchdog(unsigned long v)
{
struct netxen_adapter *adapter = (struct netxen_adapter *)v;
- if (adapter != g_adapter) {
- printk("%s: ***BUG*** adapter[%p] != g_adapter[%p]\n",
- __FUNCTION__, adapter, g_adapter);
- return;
- }
SCHEDULE_WORK(&adapter->watchdog_task);
}
@@ -969,23 +961,23 @@ static void netxen_tx_timeout(struct net_device *netdev)
{
struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
- SCHEDULE_WORK(&port->adapter->tx_timeout_task);
+ SCHEDULE_WORK(&port->tx_timeout_task);
}
static void netxen_tx_timeout_task(struct work_struct *work)
{
- struct netxen_adapter *adapter =
- container_of(work, struct netxen_adapter, tx_timeout_task);
- struct net_device *netdev = adapter->netdev;
+ struct netxen_port *port =
+ container_of(work, struct netxen_port, tx_timeout_task);
+ struct net_device *netdev = port->netdev;
unsigned long flags;
printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
netxen_nic_driver_name, netdev->name);
- spin_lock_irqsave(&adapter->lock, flags);
+ spin_lock_irqsave(&port->adapter->lock, flags);
netxen_nic_close(netdev);
netxen_nic_open(netdev);
- spin_unlock_irqrestore(&adapter->lock, flags);
+ spin_unlock_irqrestore(&port->adapter->lock, flags);
netdev->trans_start = jiffies;
netif_wake_queue(netdev);
}
@@ -1137,47 +1129,6 @@ static void netxen_nic_poll_controller(struct net_device *netdev)
enable_irq(adapter->irq);
}
#endif
-/*
- * netxen_nic_ioctl () We provide the tcl/phanmon support through these
- * ioctls.
- */
-static int
-netxen_nic_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
-{
- int err = 0;
- unsigned long nr_bytes = 0;
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
- char dev_name[NETXEN_NIC_NAME_LEN];
-
- DPRINTK(INFO, "doing ioctl for %s\n", netdev->name);
- switch (cmd) {
- case NETXEN_NIC_CMD:
- err = netxen_nic_do_ioctl(adapter, (void *)ifr->ifr_data, port);
- break;
-
- case NETXEN_NIC_NAME:
- DPRINTK(INFO, "ioctl cmd for NetXen\n");
- if (ifr->ifr_data) {
- sprintf(dev_name, "%s-%d", NETXEN_NIC_NAME_RSP,
- port->portnum);
- nr_bytes =
- copy_to_user((char __user *)ifr->ifr_data, dev_name,
- NETXEN_NIC_NAME_LEN);
- if (nr_bytes)
- err = -EIO;
-
- }
- break;
-
- default:
- DPRINTK(INFO, "ioctl cmd %x not supported\n", cmd);
- err = -EOPNOTSUPP;
- break;
- }
-
- return err;
-}
static struct pci_driver netxen_driver = {
.name = netxen_nic_driver_name,
@@ -1193,7 +1144,7 @@ static int __init netxen_init_module(void)
if ((netxen_workq = create_singlethread_workqueue("netxen")) == 0)
return -ENOMEM;
- return pci_module_init(&netxen_driver);
+ return pci_register_driver(&netxen_driver);
}
module_init(netxen_init_module);
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index 4987dc765d9..40d7003a371 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -89,15 +89,15 @@ static inline int phy_unlock(struct netxen_adapter *adapter)
*
*/
int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy,
- long reg, __le32 * readval)
+ long reg, __u32 * readval)
{
long timeout = 0;
long result = 0;
long restore = 0;
- __le32 address;
- __le32 command;
- __le32 status;
- __le32 mac_cfg0;
+ __u32 address;
+ __u32 command;
+ __u32 status;
+ __u32 mac_cfg0;
if (phy_lock(adapter) != 0) {
return -1;
@@ -112,7 +112,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy,
&mac_cfg0, 4))
return -EIO;
if (netxen_gb_get_soft_reset(mac_cfg0)) {
- __le32 temp;
+ __u32 temp;
temp = 0;
netxen_gb_tx_reset_pb(temp);
netxen_gb_rx_reset_pb(temp);
@@ -184,15 +184,15 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy,
*
*/
int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
- long phy, long reg, __le32 val)
+ long phy, long reg, __u32 val)
{
long timeout = 0;
long result = 0;
long restore = 0;
- __le32 address;
- __le32 command;
- __le32 status;
- __le32 mac_cfg0;
+ __u32 address;
+ __u32 command;
+ __u32 status;
+ __u32 mac_cfg0;
/*
* MII mgmt all goes through port 0 MAC interface, so it
@@ -203,7 +203,7 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
&mac_cfg0, 4))
return -EIO;
if (netxen_gb_get_soft_reset(mac_cfg0)) {
- __le32 temp;
+ __u32 temp;
temp = 0;
netxen_gb_tx_reset_pb(temp);
netxen_gb_rx_reset_pb(temp);
@@ -269,7 +269,7 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
int port)
{
int result = 0;
- __le32 enable = 0;
+ __u32 enable = 0;
netxen_set_phy_int_link_status_changed(enable);
netxen_set_phy_int_autoneg_completed(enable);
netxen_set_phy_int_speed_changed(enable);
@@ -402,7 +402,7 @@ void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter,
int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
{
int result = 0;
- __le32 status;
+ __u32 status;
if (adapter->disable_phy_interrupts)
adapter->disable_phy_interrupts(adapter, port);
mdelay(2);
@@ -410,7 +410,7 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
if (0 ==
netxen_niu_gbe_phy_read(adapter, port,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
- (__le32 *) & status)) {
+ &status)) {
if (netxen_get_phy_link(status)) {
if (netxen_get_phy_speed(status) == 2) {
netxen_niu_gbe_set_gmii_mode(adapter, port, 1);
@@ -489,7 +489,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
int port, long enable)
{
int result = 0;
- __le32 int_src;
+ __u32 int_src;
printk(KERN_INFO PFX "NETXEN: Handling PHY interrupt on port %d"
" (device enable = %d)\n", (int)port, (int)enable);
@@ -530,7 +530,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
printk(KERN_INFO PFX "autoneg_error ");
if ((netxen_get_phy_int_speed_changed(int_src))
|| (netxen_get_phy_int_link_status_changed(int_src))) {
- __le32 status;
+ __u32 status;
printk(KERN_INFO PFX
"speed_changed or link status changed");
@@ -583,9 +583,9 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
int phy, netxen_ethernet_macaddr_t * addr)
{
- u64 result = 0;
- __le32 stationhigh;
- __le32 stationlow;
+ u32 stationhigh;
+ u32 stationlow;
+ u8 val[8];
if (addr == NULL)
return -EINVAL;
@@ -598,10 +598,10 @@ int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy),
&stationlow, 4))
return -EIO;
+ ((__le32 *)val)[1] = cpu_to_le32(stationhigh);
+ ((__le32 *)val)[0] = cpu_to_le32(stationlow);
- result = (u64) netxen_gb_get_stationaddress_low(stationlow);
- result |= (u64) stationhigh << 16;
- memcpy(*addr, &result, sizeof(netxen_ethernet_macaddr_t));
+ memcpy(addr, val + 2, 6);
return 0;
}
@@ -613,24 +613,25 @@ int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
int netxen_niu_macaddr_set(struct netxen_port *port,
netxen_ethernet_macaddr_t addr)
{
- __le32 temp = 0;
+ u8 temp[4];
+ u32 val;
struct netxen_adapter *adapter = port->adapter;
int phy = port->portnum;
unsigned char mac_addr[6];
int i;
for (i = 0; i < 10; i++) {
- memcpy(&temp, addr, 2);
- temp <<= 16;
+ temp[0] = temp[1] = 0;
+ memcpy(temp + 2, addr, 2);
+ val = le32_to_cpu(*(__le32 *)temp);
if (netxen_nic_hw_write_wx
- (adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), &temp, 4))
+ (adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), &val, 4))
return -EIO;
- temp = 0;
-
- memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
+ memcpy(temp, ((u8 *) addr) + 2, sizeof(__le32));
+ val = le32_to_cpu(*(__le32 *)temp);
if (netxen_nic_hw_write_wx
- (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &temp, 4))
+ (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4))
return -2;
netxen_niu_macaddr_get(adapter, phy,
@@ -659,9 +660,9 @@ int netxen_niu_macaddr_set(struct netxen_port *port,
int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter,
int port, netxen_niu_gbe_ifmode_t mode)
{
- __le32 mac_cfg0;
- __le32 mac_cfg1;
- __le32 mii_cfg;
+ __u32 mac_cfg0;
+ __u32 mac_cfg1;
+ __u32 mii_cfg;
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
return -EINVAL;
@@ -736,7 +737,7 @@ int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter,
/* Disable a GbE interface */
int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port)
{
- __le32 mac_cfg0;
+ __u32 mac_cfg0;
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
return -EINVAL;
@@ -752,7 +753,7 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port)
/* Disable an XG interface */
int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port)
{
- __le32 mac_cfg;
+ __u32 mac_cfg;
if (port != 0)
return -EINVAL;
@@ -769,7 +770,7 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port)
int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
netxen_niu_prom_mode_t mode)
{
- __le32 reg;
+ __u32 reg;
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
return -EINVAL;
@@ -826,22 +827,21 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
int netxen_niu_xg_macaddr_set(struct netxen_port *port,
netxen_ethernet_macaddr_t addr)
{
- __le32 temp = 0;
+ u8 temp[4];
+ u32 val;
struct netxen_adapter *adapter = port->adapter;
- memcpy(&temp, addr, 2);
- temp = cpu_to_le32(temp);
- temp <<= 16;
+ temp[0] = temp[1] = 0;
+ memcpy(temp + 2, addr, 2);
+ val = le32_to_cpu(*(__le32 *)temp);
if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
- &temp, 4))
+ &val, 4))
return -EIO;
- temp = 0;
-
memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
- temp = cpu_to_le32(temp);
+ val = le32_to_cpu(*(__le32 *)temp);
if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
- &temp, 4))
+ &val, 4))
return -EIO;
return 0;
@@ -854,9 +854,9 @@ int netxen_niu_xg_macaddr_set(struct netxen_port *port,
int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy,
netxen_ethernet_macaddr_t * addr)
{
- __le32 stationhigh;
- __le32 stationlow;
- u64 result;
+ u32 stationhigh;
+ u32 stationlow;
+ u8 val[8];
if (addr == NULL)
return -EINVAL;
@@ -869,10 +869,10 @@ int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy,
if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
&stationlow, 4))
return -EIO;
+ ((__le32 *)val)[1] = cpu_to_le32(stationhigh);
+ ((__le32 *)val)[0] = cpu_to_le32(stationlow);
- result = ((u64) stationlow) >> 16;
- result |= (u64) stationhigh << 16;
- memcpy(*addr, &result, sizeof(netxen_ethernet_macaddr_t));
+ memcpy(addr, val + 2, 6);
return 0;
}
@@ -880,7 +880,7 @@ int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy,
int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
int port, netxen_niu_prom_mode_t mode)
{
- __le32 reg;
+ __u32 reg;
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
return -EINVAL;
diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c
deleted file mode 100644
index 702e3e95612..00000000000
--- a/drivers/net/oaknet.c
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
- *
- * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- * Module name: oaknet.c
- *
- * Description:
- * Driver for the National Semiconductor DP83902AV Ethernet controller
- * on-board the IBM PowerPC "Oak" evaluation board. Adapted from the
- * various other 8390 drivers written by Donald Becker and Paul Gortmaker.
- *
- * Additional inspiration from the "tcd8390.c" driver from TiVo, Inc.
- * and "enetLib.c" from IBM.
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/jiffies.h>
-
-#include <asm/board.h>
-#include <asm/io.h>
-
-#include "8390.h"
-
-
-/* Preprocessor Defines */
-
-#if !defined(TRUE) || TRUE != 1
-#define TRUE 1
-#endif
-
-#if !defined(FALSE) || FALSE != 0
-#define FALSE 0
-#endif
-
-#define OAKNET_START_PG 0x20 /* First page of TX buffer */
-#define OAKNET_STOP_PG 0x40 /* Last pagge +1 of RX ring */
-
-#define OAKNET_WAIT (2 * HZ / 100) /* 20 ms */
-
-/* Experimenting with some fixes for a broken driver... */
-
-#define OAKNET_DISINT
-#define OAKNET_HEADCHECK
-#define OAKNET_RWFIX
-
-
-/* Global Variables */
-
-static const char *name = "National DP83902AV";
-
-static struct net_device *oaknet_devs;
-
-
-/* Function Prototypes */
-
-static int oaknet_open(struct net_device *dev);
-static int oaknet_close(struct net_device *dev);
-
-static void oaknet_reset_8390(struct net_device *dev);
-static void oaknet_get_8390_hdr(struct net_device *dev,
- struct e8390_pkt_hdr *hdr, int ring_page);
-static void oaknet_block_input(struct net_device *dev, int count,
- struct sk_buff *skb, int ring_offset);
-static void oaknet_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page);
-
-static void oaknet_dma_error(struct net_device *dev, const char *name);
-
-
-/*
- * int oaknet_init()
- *
- * Description:
- * This routine performs all the necessary platform-specific initiali-
- * zation and set-up for the IBM "Oak" evaluation board's National
- * Semiconductor DP83902AV "ST-NIC" Ethernet controller.
- *
- * Input(s):
- * N/A
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * 0 if OK, otherwise system error number on error.
- *
- */
-static int __init oaknet_init(void)
-{
- register int i;
- int reg0, regd;
- int ret = -ENOMEM;
- struct net_device *dev;
-#if 0
- unsigned long ioaddr = OAKNET_IO_BASE;
-#else
- unsigned long ioaddr = ioremap(OAKNET_IO_BASE, OAKNET_IO_SIZE);
-#endif
- bd_t *bip = (bd_t *)__res;
-
- if (!ioaddr)
- return -ENOMEM;
-
- dev = alloc_ei_netdev();
- if (!dev)
- goto out_unmap;
-
- ret = -EBUSY;
- if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name))
- goto out_dev;
-
- /* Quick register check to see if the device is really there. */
-
- ret = -ENODEV;
- if ((reg0 = ei_ibp(ioaddr)) == 0xFF)
- goto out_region;
-
- /*
- * That worked. Now a more thorough check, using the multicast
- * address registers, that the device is definitely out there
- * and semi-functional.
- */
-
- ei_obp(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD);
- regd = ei_ibp(ioaddr + 0x0D);
- ei_obp(0xFF, ioaddr + 0x0D);
- ei_obp(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);
- ei_ibp(ioaddr + EN0_COUNTER0);
-
- /* It's no good. Fix things back up and leave. */
-
- ret = -ENODEV;
- if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) {
- ei_obp(reg0, ioaddr);
- ei_obp(regd, ioaddr + 0x0D);
- goto out_region;
- }
-
- SET_MODULE_OWNER(dev);
-
- /*
- * This controller is on an embedded board, so the base address
- * and interrupt assignments are pre-assigned and unchageable.
- */
-
- dev->base_addr = ioaddr;
- dev->irq = OAKNET_INT;
-
- /*
- * Disable all chip interrupts for now and ACK all pending
- * interrupts.
- */
-
- ei_obp(0x0, ioaddr + EN0_IMR);
- ei_obp(0xFF, ioaddr + EN0_ISR);
-
- /* Attempt to get the interrupt line */
-
- ret = -EAGAIN;
- if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) {
- printk("%s: unable to request interrupt %d.\n",
- name, dev->irq);
- goto out_region;
- }
-
- /* Tell the world about what and where we've found. */
-
- printk("%s: %s at", dev->name, name);
- for (i = 0; i < ETHER_ADDR_LEN; ++i) {
- dev->dev_addr[i] = bip->bi_enetaddr[i];
- printk("%c%.2x", (i ? ':' : ' '), dev->dev_addr[i]);
- }
- printk(", found at %#lx, using IRQ %d.\n", dev->base_addr, dev->irq);
-
- /* Set up some required driver fields and then we're done. */
-
- ei_status.name = name;
- ei_status.word16 = FALSE;
- ei_status.tx_start_page = OAKNET_START_PG;
- ei_status.rx_start_page = OAKNET_START_PG + TX_PAGES;
- ei_status.stop_page = OAKNET_STOP_PG;
-
- ei_status.reset_8390 = &oaknet_reset_8390;
- ei_status.block_input = &oaknet_block_input;
- ei_status.block_output = &oaknet_block_output;
- ei_status.get_8390_hdr = &oaknet_get_8390_hdr;
-
- dev->open = oaknet_open;
- dev->stop = oaknet_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = ei_poll;
-#endif
-
- NS8390_init(dev, FALSE);
- ret = register_netdev(dev);
- if (ret)
- goto out_irq;
-
- oaknet_devs = dev;
- return 0;
-
-out_irq;
- free_irq(dev->irq, dev);
-out_region:
- release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE);
-out_dev:
- free_netdev(dev);
-out_unmap:
- iounmap(ioaddr);
- return ret;
-}
-
-/*
- * static int oaknet_open()
- *
- * Description:
- * This routine is a modest wrapper around ei_open, the 8390-generic,
- * driver open routine. This just increments the module usage count
- * and passes along the status from ei_open.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- * *dev - Pointer to the device structure for this driver, potentially
- * modified by ei_open.
- *
- * Returns:
- * 0 if OK, otherwise < 0 on error.
- *
- */
-static int
-oaknet_open(struct net_device *dev)
-{
- int status = ei_open(dev);
- return (status);
-}
-
-/*
- * static int oaknet_close()
- *
- * Description:
- * This routine is a modest wrapper around ei_close, the 8390-generic,
- * driver close routine. This just decrements the module usage count
- * and passes along the status from ei_close.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- * *dev - Pointer to the device structure for this driver, potentially
- * modified by ei_close.
- *
- * Returns:
- * 0 if OK, otherwise < 0 on error.
- *
- */
-static int
-oaknet_close(struct net_device *dev)
-{
- int status = ei_close(dev);
- return (status);
-}
-
-/*
- * static void oaknet_reset_8390()
- *
- * Description:
- * This routine resets the DP83902 chip.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_reset_8390(struct net_device *dev)
-{
- int base = E8390_BASE;
-
- /*
- * We have no provision of reseting the controller as is done
- * in other drivers, such as "ne.c". However, the following
- * seems to work well enough in the TiVo driver.
- */
-
- printk("Resetting %s...\n", dev->name);
- ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD);
- ei_status.txing = 0;
- ei_status.dmaing = 0;
-}
-
-/*
- * static void oaknet_get_8390_hdr()
- *
- * Description:
- * This routine grabs the 8390-specific header. It's similar to the
- * block input routine, but we don't need to be concerned with ring wrap
- * as the header will be at the start of a page, so we optimize accordingly.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- * *hdr - Pointer to storage for the 8390-specific packet header.
- * ring_page - ?
- *
- * Output(s):
- * *hdr - Pointer to the 8390-specific packet header for the just-
- * received frame.
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page)
-{
- int base = dev->base_addr;
-
- /*
- * This should NOT happen. If it does, it is the LAST thing you'll
- * see.
- */
-
- if (ei_status.dmaing) {
- oaknet_dma_error(dev, "oaknet_get_8390_hdr");
- return;
- }
-
- ei_status.dmaing |= 0x01;
- outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD);
- outb_p(sizeof(struct e8390_pkt_hdr), base + EN0_RCNTLO);
- outb_p(0, base + EN0_RCNTHI);
- outb_p(0, base + EN0_RSARLO); /* On page boundary */
- outb_p(ring_page, base + EN0_RSARHI);
- outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD);
-
- if (ei_status.word16)
- insw(base + OAKNET_DATA, hdr,
- sizeof(struct e8390_pkt_hdr) >> 1);
- else
- insb(base + OAKNET_DATA, hdr,
- sizeof(struct e8390_pkt_hdr));
-
- /* Byte-swap the packet byte count */
-
- hdr->count = le16_to_cpu(hdr->count);
-
- outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */
- ei_status.dmaing &= ~0x01;
-}
-
-/*
- * XXX - Document me.
- */
-static void
-oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb,
- int ring_offset)
-{
- int base = OAKNET_BASE;
- char *buf = skb->data;
-
- /*
- * This should NOT happen. If it does, it is the LAST thing you'll
- * see.
- */
-
- if (ei_status.dmaing) {
- oaknet_dma_error(dev, "oaknet_block_input");
- return;
- }
-
-#ifdef OAKNET_DISINT
- save_flags(flags);
- cli();
-#endif
-
- ei_status.dmaing |= 0x01;
- ei_obp(E8390_NODMA + E8390_PAGE0 + E8390_START, base + E8390_CMD);
- ei_obp(count & 0xff, base + EN0_RCNTLO);
- ei_obp(count >> 8, base + EN0_RCNTHI);
- ei_obp(ring_offset & 0xff, base + EN0_RSARLO);
- ei_obp(ring_offset >> 8, base + EN0_RSARHI);
- ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
- if (ei_status.word16) {
- ei_isw(base + E8390_DATA, buf, count >> 1);
- if (count & 0x01) {
- buf[count - 1] = ei_ib(base + E8390_DATA);
-#ifdef OAKNET_HEADCHECK
- bytes++;
-#endif
- }
- } else {
- ei_isb(base + E8390_DATA, buf, count);
- }
-#ifdef OAKNET_HEADCHECK
- /*
- * This was for the ALPHA version only, but enough people have
- * been encountering problems so it is still here. If you see
- * this message you either 1) have a slightly incompatible clone
- * or 2) have noise/speed problems with your bus.
- */
-
- /* DMA termination address check... */
- {
- int addr, tries = 20;
- do {
- /* DON'T check for 'ei_ibp(EN0_ISR) & ENISR_RDC' here
- -- it's broken for Rx on some cards! */
- int high = ei_ibp(base + EN0_RSARHI);
- int low = ei_ibp(base + EN0_RSARLO);
- addr = (high << 8) + low;
- if (((ring_offset + bytes) & 0xff) == low)
- break;
- } while (--tries > 0);
- if (tries <= 0)
- printk("%s: RX transfer address mismatch,"
- "%#4.4x (expected) vs. %#4.4x (actual).\n",
- dev->name, ring_offset + bytes, addr);
- }
-#endif
- ei_obp(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */
- ei_status.dmaing &= ~0x01;
-
-#ifdef OAKNET_DISINT
- restore_flags(flags);
-#endif
-}
-
-/*
- * static void oaknet_block_output()
- *
- * Description:
- * This routine...
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- * count - Number of bytes to be transferred.
- * *buf -
- * start_page -
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page)
-{
- int base = E8390_BASE;
-#if 0
- int bug;
-#endif
- unsigned long start;
-#ifdef OAKNET_DISINT
- unsigned long flags;
-#endif
-#ifdef OAKNET_HEADCHECK
- int retries = 0;
-#endif
-
- /* Round the count up for word writes. */
-
- if (ei_status.word16 && (count & 0x1))
- count++;
-
- /*
- * This should NOT happen. If it does, it is the LAST thing you'll
- * see.
- */
-
- if (ei_status.dmaing) {
- oaknet_dma_error(dev, "oaknet_block_output");
- return;
- }
-
-#ifdef OAKNET_DISINT
- save_flags(flags);
- cli();
-#endif
-
- ei_status.dmaing |= 0x01;
-
- /* Make sure we are in page 0. */
-
- ei_obp(E8390_PAGE0 + E8390_START + E8390_NODMA, base + E8390_CMD);
-
-#ifdef OAKNET_HEADCHECK
-retry:
-#endif
-
-#if 0
- /*
- * The 83902 documentation states that the processor needs to
- * do a "dummy read" before doing the remote write to work
- * around a chip bug they don't feel like fixing.
- */
-
- bug = 0;
- while (1) {
- unsigned int rdhi;
- unsigned int rdlo;
-
- /* Now the normal output. */
- ei_obp(ENISR_RDC, base + EN0_ISR);
- ei_obp(count & 0xff, base + EN0_RCNTLO);
- ei_obp(count >> 8, base + EN0_RCNTHI);
- ei_obp(0x00, base + EN0_RSARLO);
- ei_obp(start_page, base + EN0_RSARHI);
-
- if (bug++)
- break;
-
- /* Perform the dummy read */
- rdhi = ei_ibp(base + EN0_CRDAHI);
- rdlo = ei_ibp(base + EN0_CRDALO);
- ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
-
- while (1) {
- unsigned int nrdhi;
- unsigned int nrdlo;
- nrdhi = ei_ibp(base + EN0_CRDAHI);
- nrdlo = ei_ibp(base + EN0_CRDALO);
- if ((rdhi != nrdhi) || (rdlo != nrdlo))
- break;
- }
- }
-#else
-#ifdef OAKNET_RWFIX
- /*
- * Handle the read-before-write bug the same way as the
- * Crynwr packet driver -- the Nat'l Semi. method doesn't work.
- * Actually this doesn't always work either, but if you have
- * problems with your 83902 this is better than nothing!
- */
-
- ei_obp(0x42, base + EN0_RCNTLO);
- ei_obp(0x00, base + EN0_RCNTHI);
- ei_obp(0x42, base + EN0_RSARLO);
- ei_obp(0x00, base + EN0_RSARHI);
- ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
- /* Make certain that the dummy read has occurred. */
- udelay(6);
-#endif
-
- ei_obp(ENISR_RDC, base + EN0_ISR);
-
- /* Now the normal output. */
- ei_obp(count & 0xff, base + EN0_RCNTLO);
- ei_obp(count >> 8, base + EN0_RCNTHI);
- ei_obp(0x00, base + EN0_RSARLO);
- ei_obp(start_page, base + EN0_RSARHI);
-#endif /* 0/1 */
-
- ei_obp(E8390_RWRITE + E8390_START, base + E8390_CMD);
- if (ei_status.word16) {
- ei_osw(E8390_BASE + E8390_DATA, buf, count >> 1);
- } else {
- ei_osb(E8390_BASE + E8390_DATA, buf, count);
- }
-
-#ifdef OAKNET_DISINT
- restore_flags(flags);
-#endif
-
- start = jiffies;
-
-#ifdef OAKNET_HEADCHECK
- /*
- * This was for the ALPHA version only, but enough people have
- * been encountering problems so it is still here.
- */
-
- {
- /* DMA termination address check... */
- int addr, tries = 20;
- do {
- int high = ei_ibp(base + EN0_RSARHI);
- int low = ei_ibp(base + EN0_RSARLO);
- addr = (high << 8) + low;
- if ((start_page << 8) + count == addr)
- break;
- } while (--tries > 0);
-
- if (tries <= 0) {
- printk("%s: Tx packet transfer address mismatch,"
- "%#4.4x (expected) vs. %#4.4x (actual).\n",
- dev->name, (start_page << 8) + count, addr);
- if (retries++ == 0)
- goto retry;
- }
- }
-#endif
-
- while ((ei_ibp(base + EN0_ISR) & ENISR_RDC) == 0) {
- if (time_after(jiffies, start + OAKNET_WAIT)) {
- printk("%s: timeout waiting for Tx RDC.\n", dev->name);
- oaknet_reset_8390(dev);
- NS8390_init(dev, TRUE);
- break;
- }
- }
-
- ei_obp(ENISR_RDC, base + EN0_ISR); /* Ack intr. */
- ei_status.dmaing &= ~0x01;
-}
-
-/*
- * static void oaknet_dma_error()
- *
- * Description:
- * This routine prints out a last-ditch informative message to the console
- * indicating that a DMA error occurred. If you see this, it's the last
- * thing you'll see.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- * *name - Informative text (e.g. function name) indicating where the
- * DMA error occurred.
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_dma_error(struct net_device *dev, const char *name)
-{
- printk(KERN_EMERG "%s: DMAing conflict in %s."
- "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
- dev->name, name, ei_status.dmaing, ei_status.irqlock,
- dev->interrupt);
-}
-
-/*
- * Oak Ethernet module unload interface.
- */
-static void __exit oaknet_cleanup_module (void)
-{
- /* Convert to loop once driver supports multiple devices. */
- unregister_netdev(oaknet_dev);
- free_irq(oaknet_devs->irq, oaknet_devs);
- release_region(oaknet_devs->base_addr, OAKNET_IO_SIZE);
- iounmap(ioaddr);
- free_netdev(oaknet_devs);
-}
-
-module_init(oaknet_init);
-module_exit(oaknet_cleanup_module);
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
new file mode 100644
index 00000000000..d670ac74824
--- /dev/null
+++ b/drivers/net/pasemi_mac.c
@@ -0,0 +1,1019 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Driver for the PA Semi PWRficient onchip 1G/10G Ethernet MACs
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <asm/dma-mapping.h>
+#include <linux/in.h>
+#include <linux/skbuff.h>
+
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/checksum.h>
+
+#include "pasemi_mac.h"
+
+
+/* TODO list
+ *
+ * - Get rid of pci_{read,write}_config(), map registers with ioremap
+ * for performance
+ * - PHY support
+ * - Multicast support
+ * - Large MTU support
+ * - Other performance improvements
+ */
+
+
+/* Must be a power of two */
+#define RX_RING_SIZE 512
+#define TX_RING_SIZE 512
+
+#define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)])
+#define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)])
+#define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)])
+#define RX_DESC_INFO(mac, num) ((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)])
+#define RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)])
+
+#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
+
+/* XXXOJN these should come out of the device tree some day */
+#define PAS_DMA_CAP_BASE 0xe00d0040
+#define PAS_DMA_CAP_SIZE 0x100
+#define PAS_DMA_COM_BASE 0xe00d0100
+#define PAS_DMA_COM_SIZE 0x100
+
+static struct pasdma_status *dma_status;
+
+static int pasemi_get_mac_addr(struct pasemi_mac *mac)
+{
+ struct pci_dev *pdev = mac->pdev;
+ struct device_node *dn = pci_device_to_OF_node(pdev);
+ const u8 *maddr;
+ u8 addr[6];
+
+ if (!dn) {
+ dev_dbg(&pdev->dev,
+ "No device node for mac, not configuring\n");
+ return -ENOENT;
+ }
+
+ maddr = get_property(dn, "mac-address", NULL);
+ if (maddr == NULL) {
+ dev_warn(&pdev->dev,
+ "no mac address in device tree, not configuring\n");
+ return -ENOENT;
+ }
+
+ if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0],
+ &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) {
+ dev_warn(&pdev->dev,
+ "can't parse mac address, not configuring\n");
+ return -EINVAL;
+ }
+
+ memcpy(mac->mac_addr, addr, sizeof(addr));
+ return 0;
+}
+
+static int pasemi_mac_setup_rx_resources(struct net_device *dev)
+{
+ struct pasemi_mac_rxring *ring;
+ struct pasemi_mac *mac = netdev_priv(dev);
+ int chan_id = mac->dma_rxch;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+
+ if (!ring)
+ goto out_ring;
+
+ spin_lock_init(&ring->lock);
+
+ ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+ RX_RING_SIZE, GFP_KERNEL);
+
+ if (!ring->desc_info)
+ goto out_desc_info;
+
+ /* Allocate descriptors */
+ ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE *
+ sizeof(struct pas_dma_xct_descr),
+ &ring->dma, GFP_KERNEL);
+
+ if (!ring->desc)
+ goto out_desc;
+
+ memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+
+ ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE * sizeof(u64),
+ &ring->buf_dma, GFP_KERNEL);
+ if (!ring->buffers)
+ goto out_buffers;
+
+ memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEL(chan_id),
+ PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEU(chan_id),
+ PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
+ PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CFG(chan_id),
+ PAS_DMA_RXCHAN_CFG_HBU(1));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEL(mac->dma_if),
+ PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers)));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEU(mac->dma_if),
+ PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) |
+ PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
+
+ ring->next_to_fill = 0;
+ ring->next_to_clean = 0;
+
+ snprintf(ring->irq_name, sizeof(ring->irq_name),
+ "%s rx", dev->name);
+ mac->rx = ring;
+
+ return 0;
+
+out_buffers:
+ dma_free_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+ mac->rx->desc, mac->rx->dma);
+out_desc:
+ kfree(ring->desc_info);
+out_desc_info:
+ kfree(ring);
+out_ring:
+ return -ENOMEM;
+}
+
+
+static int pasemi_mac_setup_tx_resources(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ u32 val;
+ int chan_id = mac->dma_txch;
+ struct pasemi_mac_txring *ring;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ if (!ring)
+ goto out_ring;
+
+ spin_lock_init(&ring->lock);
+
+ ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+ TX_RING_SIZE, GFP_KERNEL);
+ if (!ring->desc_info)
+ goto out_desc_info;
+
+ /* Allocate descriptors */
+ ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
+ TX_RING_SIZE *
+ sizeof(struct pas_dma_xct_descr),
+ &ring->dma, GFP_KERNEL);
+ if (!ring->desc)
+ goto out_desc;
+
+ memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEL(chan_id),
+ PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
+ val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
+ val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2);
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEU(chan_id), val);
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_CFG(chan_id),
+ PAS_DMA_TXCHAN_CFG_TY_IFACE |
+ PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
+ PAS_DMA_TXCHAN_CFG_UP |
+ PAS_DMA_TXCHAN_CFG_WT(2));
+
+ ring->next_to_use = 0;
+ ring->next_to_clean = 0;
+
+ snprintf(ring->irq_name, sizeof(ring->irq_name),
+ "%s tx", dev->name);
+ mac->tx = ring;
+
+ return 0;
+
+out_desc:
+ kfree(ring->desc_info);
+out_desc_info:
+ kfree(ring);
+out_ring:
+ return -ENOMEM;
+}
+
+static void pasemi_mac_free_tx_resources(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int i;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ info = &TX_DESC_INFO(mac, i);
+ dp = &TX_DESC(mac, i);
+ if (info->dma) {
+ if (info->skb) {
+ pci_unmap_single(mac->dma_pdev,
+ info->dma,
+ info->skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(info->skb);
+ }
+ info->dma = 0;
+ info->skb = NULL;
+ dp->mactx = 0;
+ dp->ptr = 0;
+ }
+ }
+
+ dma_free_coherent(&mac->dma_pdev->dev,
+ TX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+ mac->tx->desc, mac->tx->dma);
+
+ kfree(mac->tx->desc_info);
+ kfree(mac->tx);
+ mac->tx = NULL;
+}
+
+static void pasemi_mac_free_rx_resources(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int i;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ info = &RX_DESC_INFO(mac, i);
+ dp = &RX_DESC(mac, i);
+ if (info->dma) {
+ if (info->skb) {
+ pci_unmap_single(mac->dma_pdev,
+ info->dma,
+ info->skb->len,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(info->skb);
+ }
+ info->dma = 0;
+ info->skb = NULL;
+ dp->macrx = 0;
+ dp->ptr = 0;
+ }
+ }
+
+ dma_free_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+ mac->rx->desc, mac->rx->dma);
+
+ dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
+ mac->rx->buffers, mac->rx->buf_dma);
+
+ kfree(mac->rx->desc_info);
+ kfree(mac->rx);
+ mac->rx = NULL;
+}
+
+static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int i;
+ int start = mac->rx->next_to_fill;
+ unsigned int count;
+
+ count = (mac->rx->next_to_clean + RX_RING_SIZE -
+ mac->rx->next_to_fill) & (RX_RING_SIZE - 1);
+
+ /* Check to see if we're doing first-time setup */
+ if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0))
+ count = RX_RING_SIZE;
+
+ if (count <= 0)
+ return;
+
+ for (i = start; i < start + count; i++) {
+ struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i);
+ u64 *buff = &RX_BUFF(mac, i);
+ struct sk_buff *skb;
+ dma_addr_t dma;
+
+ skb = dev_alloc_skb(BUF_SIZE);
+
+ if (!skb) {
+ count = i - start;
+ break;
+ }
+
+ skb->dev = dev;
+
+ dma = pci_map_single(mac->dma_pdev, skb->data, skb->len,
+ PCI_DMA_FROMDEVICE);
+
+ if (dma_mapping_error(dma)) {
+ dev_kfree_skb_irq(info->skb);
+ count = i - start;
+ break;
+ }
+
+ info->skb = skb;
+ info->dma = dma;
+ *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
+ }
+
+ wmb();
+
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_INCR(mac->dma_rxch),
+ count);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_INCR(mac->dma_if),
+ count);
+
+ mac->rx->next_to_fill += count;
+}
+
+static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
+{
+ unsigned int i;
+ int start, count;
+
+ spin_lock(&mac->rx->lock);
+
+ start = mac->rx->next_to_clean;
+ count = 0;
+
+ for (i = start; i < (start + RX_RING_SIZE) && count < limit; i++) {
+ struct pas_dma_xct_descr *dp;
+ struct pasemi_mac_buffer *info;
+ struct sk_buff *skb;
+ unsigned int j, len;
+ dma_addr_t dma;
+
+ rmb();
+
+ dp = &RX_DESC(mac, i);
+
+ if (!(dp->macrx & XCT_MACRX_O))
+ break;
+
+ count++;
+
+ info = NULL;
+
+ /* We have to scan for our skb since there's no way
+ * to back-map them from the descriptor, and if we
+ * have several receive channels then they might not
+ * show up in the same order as they were put on the
+ * interface ring.
+ */
+
+ dma = (dp->ptr & XCT_PTR_ADDR_M);
+ for (j = start; j < (start + RX_RING_SIZE); j++) {
+ info = &RX_DESC_INFO(mac, j);
+ if (info->dma == dma)
+ break;
+ }
+
+ BUG_ON(!info);
+ BUG_ON(info->dma != dma);
+
+ pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len,
+ PCI_DMA_FROMDEVICE);
+
+ skb = info->skb;
+
+ len = (dp->macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
+
+ skb_put(skb, len);
+
+ skb->protocol = eth_type_trans(skb, mac->netdev);
+
+ if ((dp->macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = (dp->macrx & XCT_MACRX_CSUM_M) >>
+ XCT_MACRX_CSUM_S;
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ mac->stats.rx_bytes += len;
+ mac->stats.rx_packets++;
+
+ netif_receive_skb(skb);
+
+ info->dma = 0;
+ info->skb = NULL;
+ dp->ptr = 0;
+ dp->macrx = 0;
+ }
+
+ mac->rx->next_to_clean += count;
+ pasemi_mac_replenish_rx_ring(mac->netdev);
+
+ spin_unlock(&mac->rx->lock);
+
+ return count;
+}
+
+static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
+{
+ int i;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+ int start, count;
+ int flags;
+
+ spin_lock_irqsave(&mac->tx->lock, flags);
+
+ start = mac->tx->next_to_clean;
+ count = 0;
+
+ for (i = start; i < mac->tx->next_to_use; i++) {
+ dp = &TX_DESC(mac, i);
+ if (!dp || (dp->mactx & XCT_MACTX_O))
+ break;
+
+ count++;
+
+ info = &TX_DESC_INFO(mac, i);
+
+ pci_unmap_single(mac->dma_pdev, info->dma,
+ info->skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(info->skb);
+
+ info->skb = NULL;
+ info->dma = 0;
+ dp->mactx = 0;
+ dp->ptr = 0;
+ }
+ mac->tx->next_to_clean += count;
+ spin_unlock_irqrestore(&mac->tx->lock, flags);
+
+ return count;
+}
+
+
+static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
+{
+ struct net_device *dev = data;
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int reg;
+
+ if (!(*mac->rx_status & PAS_STATUS_INT))
+ return IRQ_NONE;
+
+ netif_rx_schedule(dev);
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0));
+
+ reg = PAS_IOB_DMA_RXCH_RESET_PINTC | PAS_IOB_DMA_RXCH_RESET_SINTC |
+ PAS_IOB_DMA_RXCH_RESET_DINTC;
+ if (*mac->rx_status & PAS_STATUS_TIMER)
+ reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
+
+ pci_write_config_dword(mac->iob_pdev,
+ PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
+
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
+{
+ struct net_device *dev = data;
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int reg;
+ int was_full;
+
+ was_full = mac->tx->next_to_clean - mac->tx->next_to_use == TX_RING_SIZE;
+
+ if (!(*mac->tx_status & PAS_STATUS_INT))
+ return IRQ_NONE;
+
+ pasemi_mac_clean_tx(mac);
+
+ reg = PAS_IOB_DMA_TXCH_RESET_PINTC | PAS_IOB_DMA_TXCH_RESET_SINTC;
+ if (*mac->tx_status & PAS_STATUS_TIMER)
+ reg |= PAS_IOB_DMA_TXCH_RESET_TINTC;
+
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch),
+ reg);
+
+ if (was_full)
+ netif_wake_queue(dev);
+
+ return IRQ_HANDLED;
+}
+
+static int pasemi_mac_open(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int flags;
+ int ret;
+
+ /* enable rx section */
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_RXCMD,
+ PAS_DMA_COM_RXCMD_EN);
+
+ /* enable tx section */
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_TXCMD,
+ PAS_DMA_COM_TXCMD_EN);
+
+ flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) |
+ PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) |
+ PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12);
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_CFG_TXP, flags);
+
+ flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
+ PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
+
+ flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
+
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
+ PAS_IOB_DMA_RXCH_CFG_CNTTH(30));
+
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+
+ ret = pasemi_mac_setup_rx_resources(dev);
+ if (ret)
+ goto out_rx_resources;
+
+ ret = pasemi_mac_setup_tx_resources(dev);
+ if (ret)
+ goto out_tx_resources;
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_IPC_CHNL,
+ PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
+ PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
+
+ /* enable rx if */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ PAS_DMA_RXINT_RCMDSTA_EN);
+
+ /* enable rx channel */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+ PAS_DMA_RXCHAN_CCMDSTA_EN |
+ PAS_DMA_RXCHAN_CCMDSTA_DU);
+
+ /* enable tx channel */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+ PAS_DMA_TXCHAN_TCMDSTA_EN);
+
+ pasemi_mac_replenish_rx_ring(dev);
+
+ netif_start_queue(dev);
+ netif_poll_enable(dev);
+
+ ret = request_irq(mac->dma_pdev->irq + mac->dma_txch,
+ &pasemi_mac_tx_intr, IRQF_DISABLED,
+ mac->tx->irq_name, dev);
+ if (ret) {
+ dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
+ mac->dma_pdev->irq + mac->dma_txch, ret);
+ goto out_tx_int;
+ }
+
+ ret = request_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch,
+ &pasemi_mac_rx_intr, IRQF_DISABLED,
+ mac->rx->irq_name, dev);
+ if (ret) {
+ dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
+ mac->dma_pdev->irq + 20 + mac->dma_rxch, ret);
+ goto out_rx_int;
+ }
+
+ return 0;
+
+out_rx_int:
+ free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+out_tx_int:
+ netif_poll_disable(dev);
+ netif_stop_queue(dev);
+ pasemi_mac_free_tx_resources(dev);
+out_tx_resources:
+ pasemi_mac_free_rx_resources(dev);
+out_rx_resources:
+
+ return ret;
+}
+
+#define MAX_RETRIES 5000
+
+static int pasemi_mac_close(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int stat;
+ int retries;
+
+ netif_stop_queue(dev);
+
+ /* Clean out any pending buffers */
+ pasemi_mac_clean_tx(mac);
+ pasemi_mac_clean_rx(mac, RX_RING_SIZE);
+
+ /* Disable interface */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+ PAS_DMA_TXCHAN_TCMDSTA_ST);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ PAS_DMA_RXINT_RCMDSTA_ST);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+ PAS_DMA_RXCHAN_CCMDSTA_ST);
+
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ pci_read_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+ &stat);
+ if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+ break;
+ cond_resched();
+ }
+
+ if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) {
+ dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
+ }
+
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ pci_read_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+ &stat);
+ if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+ break;
+ cond_resched();
+ }
+
+ if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) {
+ dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
+ }
+
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ pci_read_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ &stat);
+ if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
+ break;
+ cond_resched();
+ }
+
+ if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) {
+ dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
+ }
+
+ /* Then, disable the channel. This must be done separately from
+ * stopping, since you can't disable when active.
+ */
+
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+
+ free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+ free_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, dev);
+
+ /* Free resources */
+ pasemi_mac_free_rx_resources(dev);
+ pasemi_mac_free_tx_resources(dev);
+
+ return 0;
+}
+
+static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ struct pasemi_mac_txring *txring;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+ u64 dflags;
+ dma_addr_t map;
+ int flags;
+
+ dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ switch (skb->nh.iph->protocol) {
+ case IPPROTO_TCP:
+ dflags |= XCT_MACTX_CSUM_TCP;
+ dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
+ dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+ break;
+ case IPPROTO_UDP:
+ dflags |= XCT_MACTX_CSUM_UDP;
+ dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
+ dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+ break;
+ }
+ }
+
+ map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+ if (dma_mapping_error(map))
+ return NETDEV_TX_BUSY;
+
+ txring = mac->tx;
+
+ spin_lock_irqsave(&txring->lock, flags);
+
+ if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) {
+ spin_unlock_irqrestore(&txring->lock, flags);
+ pasemi_mac_clean_tx(mac);
+ spin_lock_irqsave(&txring->lock, flags);
+
+ if (txring->next_to_clean - txring->next_to_use ==
+ TX_RING_SIZE) {
+ /* Still no room -- stop the queue and wait for tx
+ * intr when there's room.
+ */
+ netif_stop_queue(dev);
+ goto out_err;
+ }
+ }
+
+
+ dp = &TX_DESC(mac, txring->next_to_use);
+ info = &TX_DESC_INFO(mac, txring->next_to_use);
+
+ dp->mactx = dflags | XCT_MACTX_LLEN(skb->len);
+ dp->ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map);
+ info->dma = map;
+ info->skb = skb;
+
+ txring->next_to_use++;
+ mac->stats.tx_packets++;
+ mac->stats.tx_bytes += skb->len;
+
+ spin_unlock_irqrestore(&txring->lock, flags);
+
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1);
+
+ return NETDEV_TX_OK;
+
+out_err:
+ spin_unlock_irqrestore(&txring->lock, flags);
+ pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE);
+ return NETDEV_TX_BUSY;
+}
+
+static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+
+ return &mac->stats;
+}
+
+static void pasemi_mac_set_rx_mode(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int flags;
+
+ pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+
+ /* Set promiscuous */
+ if (dev->flags & IFF_PROMISC)
+ flags |= PAS_MAC_CFG_PCFG_PR;
+ else
+ flags &= ~PAS_MAC_CFG_PCFG_PR;
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+}
+
+
+static int pasemi_mac_poll(struct net_device *dev, int *budget)
+{
+ int pkts, limit = min(*budget, dev->quota);
+ struct pasemi_mac *mac = netdev_priv(dev);
+
+ pkts = pasemi_mac_clean_rx(mac, limit);
+
+ if (pkts < limit) {
+ /* all done, no more packets present */
+ netif_rx_complete(dev);
+
+ /* re-enable receive interrupts */
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+ return 0;
+ } else {
+ /* used up our quantum, so reschedule */
+ dev->quota -= pkts;
+ *budget -= pkts;
+ return 1;
+ }
+}
+
+static int __devinit
+pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int index = 0;
+ struct net_device *dev;
+ struct pasemi_mac *mac;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ dev = alloc_etherdev(sizeof(struct pasemi_mac));
+ if (dev == NULL) {
+ dev_err(&pdev->dev,
+ "pasemi_mac: Could not allocate ethernet device.\n");
+ err = -ENOMEM;
+ goto out_disable_device;
+ }
+
+ SET_MODULE_OWNER(dev);
+ pci_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ mac = netdev_priv(dev);
+
+ mac->pdev = pdev;
+ mac->netdev = dev;
+ mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
+
+ if (!mac->dma_pdev) {
+ dev_err(&pdev->dev, "Can't find DMA Controller\n");
+ err = -ENODEV;
+ goto out_free_netdev;
+ }
+
+ mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
+
+ if (!mac->iob_pdev) {
+ dev_err(&pdev->dev, "Can't find I/O Bridge\n");
+ err = -ENODEV;
+ goto out_put_dma_pdev;
+ }
+
+ /* These should come out of the device tree eventually */
+ mac->dma_txch = index;
+ mac->dma_rxch = index;
+
+ /* We probe GMAC before XAUI, but the DMA interfaces are
+ * in XAUI, GMAC order.
+ */
+ if (index < 4)
+ mac->dma_if = index + 2;
+ else
+ mac->dma_if = index - 4;
+ index++;
+
+ switch (pdev->device) {
+ case 0xa005:
+ mac->type = MAC_TYPE_GMAC;
+ break;
+ case 0xa006:
+ mac->type = MAC_TYPE_XAUI;
+ break;
+ default:
+ err = -ENODEV;
+ goto out;
+ }
+
+ /* get mac addr from device tree */
+ if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) {
+ err = -ENODEV;
+ goto out;
+ }
+ memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr));
+
+ dev->open = pasemi_mac_open;
+ dev->stop = pasemi_mac_close;
+ dev->hard_start_xmit = pasemi_mac_start_tx;
+ dev->get_stats = pasemi_mac_get_stats;
+ dev->set_multicast_list = pasemi_mac_set_rx_mode;
+ dev->weight = 64;
+ dev->poll = pasemi_mac_poll;
+ dev->features = NETIF_F_HW_CSUM;
+
+ /* The dma status structure is located in the I/O bridge, and
+ * is cache coherent.
+ */
+ if (!dma_status)
+ /* XXXOJN This should come from the device tree */
+ dma_status = __ioremap(0xfd800000, 0x1000, 0);
+
+ mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];
+ mac->tx_status = &dma_status->tx_sta[mac->dma_txch];
+
+ err = register_netdev(dev);
+
+ if (err) {
+ dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n",
+ err);
+ goto out;
+ } else
+ printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, "
+ "hw addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
+ mac->dma_if, mac->dma_txch, mac->dma_rxch,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+ return err;
+
+out:
+ pci_dev_put(mac->iob_pdev);
+out_put_dma_pdev:
+ pci_dev_put(mac->dma_pdev);
+out_free_netdev:
+ free_netdev(dev);
+out_disable_device:
+ pci_disable_device(pdev);
+ return err;
+
+}
+
+static void __devexit pasemi_mac_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct pasemi_mac *mac;
+
+ if (!netdev)
+ return;
+
+ mac = netdev_priv(netdev);
+
+ unregister_netdev(netdev);
+
+ pci_disable_device(pdev);
+ pci_dev_put(mac->dma_pdev);
+ pci_dev_put(mac->iob_pdev);
+
+ pci_set_drvdata(pdev, NULL);
+ free_netdev(netdev);
+}
+
+static struct pci_device_id pasemi_mac_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) },
+ { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) },
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_mac_pci_tbl);
+
+static struct pci_driver pasemi_mac_driver = {
+ .name = "pasemi_mac",
+ .id_table = pasemi_mac_pci_tbl,
+ .probe = pasemi_mac_probe,
+ .remove = __devexit_p(pasemi_mac_remove),
+};
+
+static void __exit pasemi_mac_cleanup_module(void)
+{
+ pci_unregister_driver(&pasemi_mac_driver);
+ __iounmap(dma_status);
+ dma_status = NULL;
+}
+
+int pasemi_mac_init_module(void)
+{
+ return pci_register_driver(&pasemi_mac_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
+
+module_init(pasemi_mac_init_module);
+module_exit(pasemi_mac_cleanup_module);
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
new file mode 100644
index 00000000000..c3e37e46a18
--- /dev/null
+++ b/drivers/net/pasemi_mac.h
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2006 PA Semi, Inc
+ *
+ * Driver for the PA6T-1682M onchip 1G/10G Ethernet MACs, soft state and
+ * hardware register layouts.
+ *
+ * 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
+ */
+
+#ifndef PASEMI_MAC_H
+#define PASEMI_MAC_H
+
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+
+struct pasemi_mac_txring {
+ spinlock_t lock;
+ struct pas_dma_xct_descr *desc;
+ dma_addr_t dma;
+ unsigned int size;
+ unsigned int next_to_use;
+ unsigned int next_to_clean;
+ struct pasemi_mac_buffer *desc_info;
+ char irq_name[10]; /* "eth%d tx" */
+};
+
+struct pasemi_mac_rxring {
+ spinlock_t lock;
+ struct pas_dma_xct_descr *desc; /* RX channel descriptor ring */
+ dma_addr_t dma;
+ u64 *buffers; /* RX interface buffer ring */
+ dma_addr_t buf_dma;
+ unsigned int size;
+ unsigned int next_to_fill;
+ unsigned int next_to_clean;
+ struct pasemi_mac_buffer *desc_info;
+ char irq_name[10]; /* "eth%d rx" */
+};
+
+struct pasemi_mac {
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct pci_dev *dma_pdev;
+ struct pci_dev *iob_pdev;
+ struct net_device_stats stats;
+
+ /* Pointer to the cacheable per-channel status registers */
+ u64 *rx_status;
+ u64 *tx_status;
+
+ u8 type;
+#define MAC_TYPE_GMAC 1
+#define MAC_TYPE_XAUI 2
+ u32 dma_txch;
+ u32 dma_if;
+ u32 dma_rxch;
+
+ u8 mac_addr[6];
+
+ struct timer_list rxtimer;
+
+ struct pasemi_mac_txring *tx;
+ struct pasemi_mac_rxring *rx;
+};
+
+/* Software status descriptor (desc_info) */
+struct pasemi_mac_buffer {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+};
+
+
+/* status register layout in IOB region, at 0xfb800000 */
+struct pasdma_status {
+ u64 rx_sta[64];
+ u64 tx_sta[20];
+};
+
+/* descriptor structure */
+struct pas_dma_xct_descr {
+ union {
+ u64 mactx;
+ u64 macrx;
+ };
+ union {
+ u64 ptr;
+ u64 rxb;
+ };
+};
+
+/* MAC CFG register offsets */
+
+enum {
+ PAS_MAC_CFG_PCFG = 0x80,
+ PAS_MAC_CFG_TXP = 0x98,
+ PAS_MAC_IPC_CHNL = 0x208,
+};
+
+/* MAC CFG register fields */
+#define PAS_MAC_CFG_PCFG_PE 0x80000000
+#define PAS_MAC_CFG_PCFG_CE 0x40000000
+#define PAS_MAC_CFG_PCFG_BU 0x20000000
+#define PAS_MAC_CFG_PCFG_TT 0x10000000
+#define PAS_MAC_CFG_PCFG_TSR_M 0x0c000000
+#define PAS_MAC_CFG_PCFG_TSR_10M 0x00000000
+#define PAS_MAC_CFG_PCFG_TSR_100M 0x04000000
+#define PAS_MAC_CFG_PCFG_TSR_1G 0x08000000
+#define PAS_MAC_CFG_PCFG_TSR_10G 0x0c000000
+#define PAS_MAC_CFG_PCFG_T24 0x02000000
+#define PAS_MAC_CFG_PCFG_PR 0x01000000
+#define PAS_MAC_CFG_PCFG_CRO_M 0x00ff0000
+#define PAS_MAC_CFG_PCFG_CRO_S 16
+#define PAS_MAC_CFG_PCFG_IPO_M 0x0000ff00
+#define PAS_MAC_CFG_PCFG_IPO_S 8
+#define PAS_MAC_CFG_PCFG_S1 0x00000080
+#define PAS_MAC_CFG_PCFG_IO_M 0x00000060
+#define PAS_MAC_CFG_PCFG_IO_MAC 0x00000000
+#define PAS_MAC_CFG_PCFG_IO_OFF 0x00000020
+#define PAS_MAC_CFG_PCFG_IO_IND_ETH 0x00000040
+#define PAS_MAC_CFG_PCFG_IO_IND_IP 0x00000060
+#define PAS_MAC_CFG_PCFG_LP 0x00000010
+#define PAS_MAC_CFG_PCFG_TS 0x00000008
+#define PAS_MAC_CFG_PCFG_HD 0x00000004
+#define PAS_MAC_CFG_PCFG_SPD_M 0x00000003
+#define PAS_MAC_CFG_PCFG_SPD_10M 0x00000000
+#define PAS_MAC_CFG_PCFG_SPD_100M 0x00000001
+#define PAS_MAC_CFG_PCFG_SPD_1G 0x00000002
+#define PAS_MAC_CFG_PCFG_SPD_10G 0x00000003
+#define PAS_MAC_CFG_TXP_FCF 0x01000000
+#define PAS_MAC_CFG_TXP_FCE 0x00800000
+#define PAS_MAC_CFG_TXP_FC 0x00400000
+#define PAS_MAC_CFG_TXP_FPC_M 0x00300000
+#define PAS_MAC_CFG_TXP_FPC_S 20
+#define PAS_MAC_CFG_TXP_FPC(x) (((x) << PAS_MAC_CFG_TXP_FPC_S) & \
+ PAS_MAC_CFG_TXP_FPC_M)
+#define PAS_MAC_CFG_TXP_RT 0x00080000
+#define PAS_MAC_CFG_TXP_BL 0x00040000
+#define PAS_MAC_CFG_TXP_SL_M 0x00030000
+#define PAS_MAC_CFG_TXP_SL_S 16
+#define PAS_MAC_CFG_TXP_SL(x) (((x) << PAS_MAC_CFG_TXP_SL_S) & \
+ PAS_MAC_CFG_TXP_SL_M)
+#define PAS_MAC_CFG_TXP_COB_M 0x0000f000
+#define PAS_MAC_CFG_TXP_COB_S 12
+#define PAS_MAC_CFG_TXP_COB(x) (((x) << PAS_MAC_CFG_TXP_COB_S) & \
+ PAS_MAC_CFG_TXP_COB_M)
+#define PAS_MAC_CFG_TXP_TIFT_M 0x00000f00
+#define PAS_MAC_CFG_TXP_TIFT_S 8
+#define PAS_MAC_CFG_TXP_TIFT(x) (((x) << PAS_MAC_CFG_TXP_TIFT_S) & \
+ PAS_MAC_CFG_TXP_TIFT_M)
+#define PAS_MAC_CFG_TXP_TIFG_M 0x000000ff
+#define PAS_MAC_CFG_TXP_TIFG_S 0
+#define PAS_MAC_CFG_TXP_TIFG(x) (((x) << PAS_MAC_CFG_TXP_TIFG_S) & \
+ PAS_MAC_CFG_TXP_TIFG_M)
+
+#define PAS_MAC_IPC_CHNL_DCHNO_M 0x003f0000
+#define PAS_MAC_IPC_CHNL_DCHNO_S 16
+#define PAS_MAC_IPC_CHNL_DCHNO(x) (((x) << PAS_MAC_IPC_CHNL_DCHNO_S) & \
+ PAS_MAC_IPC_CHNL_DCHNO_M)
+#define PAS_MAC_IPC_CHNL_BCH_M 0x0000003f
+#define PAS_MAC_IPC_CHNL_BCH_S 0
+#define PAS_MAC_IPC_CHNL_BCH(x) (((x) << PAS_MAC_IPC_CHNL_BCH_S) & \
+ PAS_MAC_IPC_CHNL_BCH_M)
+
+/* All these registers live in the PCI configuration space for the DMA PCI
+ * device. Use the normal PCI config access functions for them.
+ */
+enum {
+ PAS_DMA_COM_TXCMD = 0x100, /* Transmit Command Register */
+ PAS_DMA_COM_TXSTA = 0x104, /* Transmit Status Register */
+ PAS_DMA_COM_RXCMD = 0x108, /* Receive Command Register */
+ PAS_DMA_COM_RXSTA = 0x10c, /* Receive Status Register */
+};
+#define PAS_DMA_COM_TXCMD_EN 0x00000001 /* enable */
+#define PAS_DMA_COM_TXSTA_ACT 0x00000001 /* active */
+#define PAS_DMA_COM_RXCMD_EN 0x00000001 /* enable */
+#define PAS_DMA_COM_RXSTA_ACT 0x00000001 /* active */
+
+
+/* Per-interface and per-channel registers */
+#define _PAS_DMA_RXINT_STRIDE 0x20
+#define PAS_DMA_RXINT_RCMDSTA(i) (0x200+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_RCMDSTA_EN 0x00000001
+#define PAS_DMA_RXINT_RCMDSTA_ST 0x00000002
+#define PAS_DMA_RXINT_RCMDSTA_OO 0x00000100
+#define PAS_DMA_RXINT_RCMDSTA_BP 0x00000200
+#define PAS_DMA_RXINT_RCMDSTA_DR 0x00000400
+#define PAS_DMA_RXINT_RCMDSTA_BT 0x00000800
+#define PAS_DMA_RXINT_RCMDSTA_TB 0x00001000
+#define PAS_DMA_RXINT_RCMDSTA_ACT 0x00010000
+#define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000
+#define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17
+#define PAS_DMA_RXINT_INCR(i) (0x210+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_INCR_INCR_M 0x0000ffff
+#define PAS_DMA_RXINT_INCR_INCR_S 0
+#define PAS_DMA_RXINT_INCR_INCR(x) ((x) & 0x0000ffff)
+#define PAS_DMA_RXINT_BASEL(i) (0x218+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_BASEL_BRBL(x) ((x) & ~0x3f)
+#define PAS_DMA_RXINT_BASEU(i) (0x21c+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_BASEU_BRBH(x) ((x) & 0xfff)
+#define PAS_DMA_RXINT_BASEU_SIZ_M 0x3fff0000 /* # of cache lines worth of buffer ring */
+#define PAS_DMA_RXINT_BASEU_SIZ_S 16 /* 0 = 16K */
+#define PAS_DMA_RXINT_BASEU_SIZ(x) (((x) << PAS_DMA_RXINT_BASEU_SIZ_S) & \
+ PAS_DMA_RXINT_BASEU_SIZ_M)
+
+
+#define _PAS_DMA_TXCHAN_STRIDE 0x20 /* Size per channel */
+#define _PAS_DMA_TXCHAN_TCMDSTA 0x300 /* Command / Status */
+#define _PAS_DMA_TXCHAN_CFG 0x304 /* Configuration */
+#define _PAS_DMA_TXCHAN_DSCRBU 0x308 /* Descriptor BU Allocation */
+#define _PAS_DMA_TXCHAN_INCR 0x310 /* Descriptor increment */
+#define _PAS_DMA_TXCHAN_CNT 0x314 /* Descriptor count/offset */
+#define _PAS_DMA_TXCHAN_BASEL 0x318 /* Descriptor ring base (low) */
+#define _PAS_DMA_TXCHAN_BASEU 0x31c /* (high) */
+#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */
+#define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */
+#define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */
+#define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */
+#define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c
+#define PAS_DMA_TXCHAN_CFG_TATTR_S 2
+#define PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \
+ PAS_DMA_TXCHAN_CFG_TATTR_M)
+#define PAS_DMA_TXCHAN_CFG_WT_M 0x000001c0
+#define PAS_DMA_TXCHAN_CFG_WT_S 6
+#define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
+ PAS_DMA_TXCHAN_CFG_WT_M)
+#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */
+#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */
+#define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */
+#define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0
+#define PAS_DMA_TXCHAN_BASEL_BRBL_S 0
+#define PAS_DMA_TXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \
+ PAS_DMA_TXCHAN_BASEL_BRBL_M)
+#define PAS_DMA_TXCHAN_BASEU(c) (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_BASEU_BRBH_M 0x00000fff
+#define PAS_DMA_TXCHAN_BASEU_BRBH_S 0
+#define PAS_DMA_TXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \
+ PAS_DMA_TXCHAN_BASEU_BRBH_M)
+/* # of cache lines worth of buffer ring */
+#define PAS_DMA_TXCHAN_BASEU_SIZ_M 0x3fff0000
+#define PAS_DMA_TXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */
+#define PAS_DMA_TXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \
+ PAS_DMA_TXCHAN_BASEU_SIZ_M)
+
+#define _PAS_DMA_RXCHAN_STRIDE 0x20 /* Size per channel */
+#define _PAS_DMA_RXCHAN_CCMDSTA 0x800 /* Command / Status */
+#define _PAS_DMA_RXCHAN_CFG 0x804 /* Configuration */
+#define _PAS_DMA_RXCHAN_INCR 0x810 /* Descriptor increment */
+#define _PAS_DMA_RXCHAN_CNT 0x814 /* Descriptor count/offset */
+#define _PAS_DMA_RXCHAN_BASEL 0x818 /* Descriptor ring base (low) */
+#define _PAS_DMA_RXCHAN_BASEU 0x81c /* (high) */
+#define PAS_DMA_RXCHAN_CCMDSTA(c) (0x800+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_CCMDSTA_EN 0x00000001 /* Enabled */
+#define PAS_DMA_RXCHAN_CCMDSTA_ST 0x00000002 /* Stop interface */
+#define PAS_DMA_RXCHAN_CCMDSTA_ACT 0x00010000 /* Active */
+#define PAS_DMA_RXCHAN_CCMDSTA_DU 0x00020000
+#define PAS_DMA_RXCHAN_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_CFG_HBU_M 0x00000380
+#define PAS_DMA_RXCHAN_CFG_HBU_S 7
+#define PAS_DMA_RXCHAN_CFG_HBU(x) (((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \
+ PAS_DMA_RXCHAN_CFG_HBU_M)
+#define PAS_DMA_RXCHAN_INCR(c) (0x810+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_BASEL(c) (0x818+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_BASEL_BRBL_M 0xffffffc0
+#define PAS_DMA_RXCHAN_BASEL_BRBL_S 0
+#define PAS_DMA_RXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_RXCHAN_BASEL_BRBL_S) & \
+ PAS_DMA_RXCHAN_BASEL_BRBL_M)
+#define PAS_DMA_RXCHAN_BASEU(c) (0x81c+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_BASEU_BRBH_M 0x00000fff
+#define PAS_DMA_RXCHAN_BASEU_BRBH_S 0
+#define PAS_DMA_RXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_RXCHAN_BASEU_BRBH_S) & \
+ PAS_DMA_RXCHAN_BASEU_BRBH_M)
+/* # of cache lines worth of buffer ring */
+#define PAS_DMA_RXCHAN_BASEU_SIZ_M 0x3fff0000
+#define PAS_DMA_RXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */
+#define PAS_DMA_RXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_RXCHAN_BASEU_SIZ_S) & \
+ PAS_DMA_RXCHAN_BASEU_SIZ_M)
+
+#define PAS_STATUS_PCNT_M 0x000000000000ffffull
+#define PAS_STATUS_PCNT_S 0
+#define PAS_STATUS_DCNT_M 0x00000000ffff0000ull
+#define PAS_STATUS_DCNT_S 16
+#define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull
+#define PAS_STATUS_BPCNT_S 32
+#define PAS_STATUS_TIMER 0x1000000000000000ull
+#define PAS_STATUS_ERROR 0x2000000000000000ull
+#define PAS_STATUS_SOFT 0x4000000000000000ull
+#define PAS_STATUS_INT 0x8000000000000000ull
+
+#define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4)
+#define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff
+#define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0
+#define PAS_IOB_DMA_RXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \
+ PAS_IOB_DMA_RXCH_CFG_CNTTH_M)
+#define PAS_IOB_DMA_TXCH_CFG(i) (0x1200 + (i)*4)
+#define PAS_IOB_DMA_TXCH_CFG_CNTTH_M 0x00000fff
+#define PAS_IOB_DMA_TXCH_CFG_CNTTH_S 0
+#define PAS_IOB_DMA_TXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \
+ PAS_IOB_DMA_TXCH_CFG_CNTTH_M)
+#define PAS_IOB_DMA_RXCH_STAT(i) (0x1300 + (i)*4)
+#define PAS_IOB_DMA_RXCH_STAT_INTGEN 0x00001000
+#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_M 0x00000fff
+#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_S 0
+#define PAS_IOB_DMA_RXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\
+ PAS_IOB_DMA_RXCH_STAT_CNTDEL_M)
+#define PAS_IOB_DMA_TXCH_STAT(i) (0x1400 + (i)*4)
+#define PAS_IOB_DMA_TXCH_STAT_INTGEN 0x00001000
+#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_M 0x00000fff
+#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_S 0
+#define PAS_IOB_DMA_TXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\
+ PAS_IOB_DMA_TXCH_STAT_CNTDEL_M)
+#define PAS_IOB_DMA_RXCH_RESET(i) (0x1500 + (i)*4)
+#define PAS_IOB_DMA_RXCH_RESET_PCNT_M 0xffff0000
+#define PAS_IOB_DMA_RXCH_RESET_PCNT_S 0
+#define PAS_IOB_DMA_RXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \
+ PAS_IOB_DMA_RXCH_RESET_PCNT_M)
+#define PAS_IOB_DMA_RXCH_RESET_PCNTRST 0x00000020
+#define PAS_IOB_DMA_RXCH_RESET_DCNTRST 0x00000010
+#define PAS_IOB_DMA_RXCH_RESET_TINTC 0x00000008
+#define PAS_IOB_DMA_RXCH_RESET_DINTC 0x00000004
+#define PAS_IOB_DMA_RXCH_RESET_SINTC 0x00000002
+#define PAS_IOB_DMA_RXCH_RESET_PINTC 0x00000001
+#define PAS_IOB_DMA_TXCH_RESET(i) (0x1600 + (i)*4)
+#define PAS_IOB_DMA_TXCH_RESET_PCNT_M 0xffff0000
+#define PAS_IOB_DMA_TXCH_RESET_PCNT_S 0
+#define PAS_IOB_DMA_TXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \
+ PAS_IOB_DMA_TXCH_RESET_PCNT_M)
+#define PAS_IOB_DMA_TXCH_RESET_PCNTRST 0x00000020
+#define PAS_IOB_DMA_TXCH_RESET_DCNTRST 0x00000010
+#define PAS_IOB_DMA_TXCH_RESET_TINTC 0x00000008
+#define PAS_IOB_DMA_TXCH_RESET_DINTC 0x00000004
+#define PAS_IOB_DMA_TXCH_RESET_SINTC 0x00000002
+#define PAS_IOB_DMA_TXCH_RESET_PINTC 0x00000001
+
+#define PAS_IOB_DMA_COM_TIMEOUTCFG 0x1700
+#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M 0x00ffffff
+#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S 0
+#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x) (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M)
+
+/* Transmit descriptor fields */
+#define XCT_MACTX_T 0x8000000000000000ull
+#define XCT_MACTX_ST 0x4000000000000000ull
+#define XCT_MACTX_NORES 0x0000000000000000ull
+#define XCT_MACTX_8BRES 0x1000000000000000ull
+#define XCT_MACTX_24BRES 0x2000000000000000ull
+#define XCT_MACTX_40BRES 0x3000000000000000ull
+#define XCT_MACTX_I 0x0800000000000000ull
+#define XCT_MACTX_O 0x0400000000000000ull
+#define XCT_MACTX_E 0x0200000000000000ull
+#define XCT_MACTX_VLAN_M 0x0180000000000000ull
+#define XCT_MACTX_VLAN_NOP 0x0000000000000000ull
+#define XCT_MACTX_VLAN_REMOVE 0x0080000000000000ull
+#define XCT_MACTX_VLAN_INSERT 0x0100000000000000ull
+#define XCT_MACTX_VLAN_REPLACE 0x0180000000000000ull
+#define XCT_MACTX_CRC_M 0x0060000000000000ull
+#define XCT_MACTX_CRC_NOP 0x0000000000000000ull
+#define XCT_MACTX_CRC_INSERT 0x0020000000000000ull
+#define XCT_MACTX_CRC_PAD 0x0040000000000000ull
+#define XCT_MACTX_CRC_REPLACE 0x0060000000000000ull
+#define XCT_MACTX_SS 0x0010000000000000ull
+#define XCT_MACTX_LLEN_M 0x00007fff00000000ull
+#define XCT_MACTX_LLEN_S 32ull
+#define XCT_MACTX_LLEN(x) ((((long)(x)) << XCT_MACTX_LLEN_S) & \
+ XCT_MACTX_LLEN_M)
+#define XCT_MACTX_IPH_M 0x00000000f8000000ull
+#define XCT_MACTX_IPH_S 27ull
+#define XCT_MACTX_IPH(x) ((((long)(x)) << XCT_MACTX_IPH_S) & \
+ XCT_MACTX_IPH_M)
+#define XCT_MACTX_IPO_M 0x0000000007c00000ull
+#define XCT_MACTX_IPO_S 22ull
+#define XCT_MACTX_IPO(x) ((((long)(x)) << XCT_MACTX_IPO_S) & \
+ XCT_MACTX_IPO_M)
+#define XCT_MACTX_CSUM_M 0x0000000000000060ull
+#define XCT_MACTX_CSUM_NOP 0x0000000000000000ull
+#define XCT_MACTX_CSUM_TCP 0x0000000000000040ull
+#define XCT_MACTX_CSUM_UDP 0x0000000000000060ull
+#define XCT_MACTX_V6 0x0000000000000010ull
+#define XCT_MACTX_C 0x0000000000000004ull
+#define XCT_MACTX_AL2 0x0000000000000002ull
+
+/* Receive descriptor fields */
+#define XCT_MACRX_T 0x8000000000000000ull
+#define XCT_MACRX_ST 0x4000000000000000ull
+#define XCT_MACRX_NORES 0x0000000000000000ull
+#define XCT_MACRX_8BRES 0x1000000000000000ull
+#define XCT_MACRX_24BRES 0x2000000000000000ull
+#define XCT_MACRX_40BRES 0x3000000000000000ull
+#define XCT_MACRX_O 0x0400000000000000ull
+#define XCT_MACRX_E 0x0200000000000000ull
+#define XCT_MACRX_FF 0x0100000000000000ull
+#define XCT_MACRX_PF 0x0080000000000000ull
+#define XCT_MACRX_OB 0x0040000000000000ull
+#define XCT_MACRX_OD 0x0020000000000000ull
+#define XCT_MACRX_FS 0x0010000000000000ull
+#define XCT_MACRX_NB_M 0x000fc00000000000ull
+#define XCT_MACRX_NB_S 46ULL
+#define XCT_MACRX_NB(x) ((((long)(x)) << XCT_MACRX_NB_S) & \
+ XCT_MACRX_NB_M)
+#define XCT_MACRX_LLEN_M 0x00003fff00000000ull
+#define XCT_MACRX_LLEN_S 32ULL
+#define XCT_MACRX_LLEN(x) ((((long)(x)) << XCT_MACRX_LLEN_S) & \
+ XCT_MACRX_LLEN_M)
+#define XCT_MACRX_CRC 0x0000000080000000ull
+#define XCT_MACRX_LEN_M 0x0000000060000000ull
+#define XCT_MACRX_LEN_TOOSHORT 0x0000000020000000ull
+#define XCT_MACRX_LEN_BELOWMIN 0x0000000040000000ull
+#define XCT_MACRX_LEN_TRUNC 0x0000000060000000ull
+#define XCT_MACRX_CAST_M 0x0000000018000000ull
+#define XCT_MACRX_CAST_UNI 0x0000000000000000ull
+#define XCT_MACRX_CAST_MULTI 0x0000000008000000ull
+#define XCT_MACRX_CAST_BROAD 0x0000000010000000ull
+#define XCT_MACRX_CAST_PAUSE 0x0000000018000000ull
+#define XCT_MACRX_VLC_M 0x0000000006000000ull
+#define XCT_MACRX_FM 0x0000000001000000ull
+#define XCT_MACRX_HTY_M 0x0000000000c00000ull
+#define XCT_MACRX_HTY_IPV4_OK 0x0000000000000000ull
+#define XCT_MACRX_HTY_IPV6 0x0000000000400000ull
+#define XCT_MACRX_HTY_IPV4_BAD 0x0000000000800000ull
+#define XCT_MACRX_HTY_NONIP 0x0000000000c00000ull
+#define XCT_MACRX_IPP_M 0x00000000003f0000ull
+#define XCT_MACRX_IPP_S 16
+#define XCT_MACRX_CSUM_M 0x000000000000ffffull
+#define XCT_MACRX_CSUM_S 0
+
+#define XCT_PTR_T 0x8000000000000000ull
+#define XCT_PTR_LEN_M 0x7ffff00000000000ull
+#define XCT_PTR_LEN_S 44
+#define XCT_PTR_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & \
+ XCT_PTR_LEN_M)
+#define XCT_PTR_ADDR_M 0x00000fffffffffffull
+#define XCT_PTR_ADDR_S 0
+#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \
+ XCT_PTR_ADDR_M)
+
+/* Receive interface buffer fields */
+#define XCT_RXB_LEN_M 0x0ffff00000000000ull
+#define XCT_RXB_LEN_S 44
+#define XCT_RXB_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & XCT_PTR_LEN_M)
+#define XCT_RXB_ADDR_M 0x00000fffffffffffull
+#define XCT_RXB_ADDR_S 0
+#define XCT_RXB_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & XCT_PTR_ADDR_M)
+
+
+#endif /* PASEMI_MAC_H */
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 794cc61819d..448bf4a7801 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -281,7 +281,6 @@ static int tc574_probe(struct pcmcia_device *link)
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
- link->conf.Present = PRESENT_OPTION;
/* The EL3-specific entries in the device structure. */
dev->hard_start_xmit = &el3_start_xmit;
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 1e73ff7d5d8..461e8274ef6 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -195,7 +195,6 @@ static int tc589_probe(struct pcmcia_device *link)
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
- link->conf.Present = PRESENT_OPTION;
/* The EL3-specific entries in the device structure. */
SET_MODULE_OWNER(dev);
@@ -607,11 +606,14 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
kio_addr_t ioaddr = dev->base_addr;
struct el3_private *priv = netdev_priv(dev);
+ unsigned long flags;
DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
"status %4.4x.\n", dev->name, (long)skb->len,
inw(ioaddr + EL3_STATUS));
+ spin_lock_irqsave(&priv->lock, flags);
+
priv->stats.tx_bytes += skb->len;
/* Put out the doubleword header... */
@@ -629,6 +631,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
pop_tx_status(dev);
+ spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
@@ -730,14 +733,13 @@ static void media_check(unsigned long arg)
if (!netif_device_present(dev)) goto reschedule;
- EL3WINDOW(1);
/* Check for pending interrupt with expired latency timer: with
this, we can limp along even if the interrupt is blocked */
if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
(inb(ioaddr + EL3_TIMER) == 0xff)) {
if (!lp->fast_poll)
printk(KERN_WARNING "%s: interrupt(s) dropped!\n", dev->name);
- el3_interrupt(dev->irq, lp);
+ el3_interrupt(dev->irq, dev);
lp->fast_poll = HZ;
}
if (lp->fast_poll) {
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 91f65e91cd5..0d1c7a41c9c 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -173,7 +173,6 @@ static int com20020_probe(struct pcmcia_device *p_dev)
p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
p_dev->conf.IntType = INT_MEMORY_AND_IO;
- p_dev->conf.Present = PRESENT_OPTION;
p_dev->irq.Instance = info->dev = dev;
p_dev->priv = info;
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 2b1238e2dbd..d88e9b2e93c 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -1617,6 +1617,7 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9),
PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0x9fd2f0a2),
PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0x9fd2f0a2),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "(CG-LAPCCTXD)", 0x5261440f, 0x73ec0d88),
PCMCIA_DEVICE_PROD_ID12("CouplerlessPCMCIA", "100BASE", 0xee5af0ad, 0x7c2add04),
PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-010", 0x77008979, 0x9d8d445d),
PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-110E 10/100M LAN Card", 0x77008979, 0xfd184814),
@@ -1667,6 +1668,7 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TX", 0x88fcdeda, 0x6d772737),
PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TE", 0x88fcdeda, 0x0e714bee),
PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN20T", 0x88fcdeda, 0x81090922),
+ PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN10TE", 0x88fcdeda, 0xc1e2521c),
PCMCIA_DEVICE_PROD_ID12("LONGSHINE", "PCMCIA Ethernet Card", 0xf866b0b0, 0x6f6652e0),
PCMCIA_DEVICE_PROD_ID12("MACNICA", "ME1-JEIDA", 0x20841b68, 0xaf8a3578),
PCMCIA_DEVICE_PROD_ID12("Macsense", "MPC-10", 0xd830297f, 0xd265c307),
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 8478dca3d8d..5879e7c3698 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -576,7 +576,6 @@ xirc2ps_probe(struct pcmcia_device *link)
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
- link->conf.Present = PRESENT_OPTION;
link->irq.Handler = xirc2ps_interrupt;
link->irq.Instance = dev;
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index 096d4a100bf..86135397f43 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -349,7 +349,7 @@ static int __init fixed_init(void)
fixed_mdio_register_device(0, 100, 1);
#endif
-#ifdef CONFIX_FIXED_MII_10_FDX
+#ifdef CONFIG_FIXED_MII_10_FDX
fixed_mdio_register_device(0, 10, 1);
#endif
return 0;
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index e175f3910b1..9765fa66146 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -286,6 +286,7 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
return 0;
}
+EXPORT_SYMBOL(phy_ethtool_sset);
int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
{
@@ -302,7 +303,7 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
return 0;
}
-
+EXPORT_SYMBOL(phy_ethtool_gset);
/* Note that this function is currently incompatible with the
* PHYCONTROL layer. It changes registers without regard to
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index b01fc70a57d..a4d7529ef41 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -50,7 +50,7 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
struct phy_device *dev;
/* We allocate the device, and initialize the
* default values */
- dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (NULL == dev)
return (struct phy_device*) PTR_ERR((void*)-ENOMEM);
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
index f54c55242f4..72c8d6628f5 100644
--- a/drivers/net/ppp_deflate.c
+++ b/drivers/net/ppp_deflate.c
@@ -121,7 +121,7 @@ static void *z_comp_alloc(unsigned char *options, int opt_len)
if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
return NULL;
- state = (struct ppp_deflate_state *) kmalloc(sizeof(*state),
+ state = kmalloc(sizeof(*state),
GFP_KERNEL);
if (state == NULL)
return NULL;
@@ -341,7 +341,7 @@ static void *z_decomp_alloc(unsigned char *options, int opt_len)
if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
return NULL;
- state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL);
+ state = kmalloc(sizeof(*state), GFP_KERNEL);
if (state == NULL)
return NULL;
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c
index f3655fd772f..d5bdd257465 100644
--- a/drivers/net/ppp_mppe.c
+++ b/drivers/net/ppp_mppe.c
@@ -200,7 +200,7 @@ static void *mppe_alloc(unsigned char *options, int optlen)
|| options[0] != CI_MPPE || options[1] != CILEN_MPPE)
goto out;
- state = (struct ppp_mppe_state *) kmalloc(sizeof(*state), GFP_KERNEL);
+ state = kmalloc(sizeof(*state), GFP_KERNEL);
if (state == NULL)
goto out;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index d79d141a601..2429b274f0b 100644..100755
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/ip.h>
+#include <linux/in.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
@@ -63,6 +64,7 @@ MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts.");
static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)},
+ {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3032_DEVICE_ID)},
/* required last entry */
{0,}
};
@@ -208,6 +210,15 @@ static void ql_write_common_reg(struct ql3_adapter *qdev,
return;
}
+static void ql_write_nvram_reg(struct ql3_adapter *qdev,
+ u32 __iomem *reg, u32 value)
+{
+ writel(value, reg);
+ readl(reg);
+ udelay(1);
+ return;
+}
+
static void ql_write_page0_reg(struct ql3_adapter *qdev,
u32 __iomem *reg, u32 value)
{
@@ -336,9 +347,9 @@ static void fm93c56a_select(struct ql3_adapter *qdev)
qdev->mem_map_registers;
qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_1;
- ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
- ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));
}
@@ -355,14 +366,14 @@ static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr)
qdev->mem_map_registers;
/* Clock in a zero, then do the start bit */
- ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
AUBURN_EEPROM_DO_1);
- ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->
eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
AUBURN_EEPROM_CLK_RISE);
- ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->
eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
AUBURN_EEPROM_CLK_FALL);
@@ -378,20 +389,20 @@ static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr)
* If the bit changed, then change the DO state to
* match
*/
- ql_write_common_reg(qdev,
+ ql_write_nvram_reg(qdev,
&port_regs->CommonRegs.
serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->
eeprom_cmd_data | dataBit);
previousBit = dataBit;
}
- ql_write_common_reg(qdev,
+ ql_write_nvram_reg(qdev,
&port_regs->CommonRegs.
serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->
eeprom_cmd_data | dataBit |
AUBURN_EEPROM_CLK_RISE);
- ql_write_common_reg(qdev,
+ ql_write_nvram_reg(qdev,
&port_regs->CommonRegs.
serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->
@@ -412,20 +423,20 @@ static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr)
* If the bit changed, then change the DO state to
* match
*/
- ql_write_common_reg(qdev,
+ ql_write_nvram_reg(qdev,
&port_regs->CommonRegs.
serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->
eeprom_cmd_data | dataBit);
previousBit = dataBit;
}
- ql_write_common_reg(qdev,
+ ql_write_nvram_reg(qdev,
&port_regs->CommonRegs.
serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->
eeprom_cmd_data | dataBit |
AUBURN_EEPROM_CLK_RISE);
- ql_write_common_reg(qdev,
+ ql_write_nvram_reg(qdev,
&port_regs->CommonRegs.
serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->
@@ -443,7 +454,7 @@ static void fm93c56a_deselect(struct ql3_adapter *qdev)
struct ql3xxx_port_registers __iomem *port_regs =
qdev->mem_map_registers;
qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_0;
- ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
}
@@ -461,12 +472,12 @@ static void fm93c56a_datain(struct ql3_adapter *qdev, unsigned short *value)
/* Read the data bits */
/* The first bit is a dummy. Clock right over it. */
for (i = 0; i < dataBits; i++) {
- ql_write_common_reg(qdev,
+ ql_write_nvram_reg(qdev,
&port_regs->CommonRegs.
serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
AUBURN_EEPROM_CLK_RISE);
- ql_write_common_reg(qdev,
+ ql_write_nvram_reg(qdev,
&port_regs->CommonRegs.
serialPortInterfaceReg,
ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
@@ -1466,6 +1477,10 @@ static int ql_mii_setup(struct ql3_adapter *qdev)
2) << 7))
return -1;
+ if (qdev->device_id == QL3032_DEVICE_ID)
+ ql_write_page0_reg(qdev,
+ &port_regs->macMIIMgmtControlReg, 0x0f00000);
+
/* Divide 125MHz clock by 28 to meet PHY timing requirements */
reg = MAC_MII_CONTROL_CLK_SEL_DIV28;
@@ -1697,18 +1712,42 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
struct ob_mac_iocb_rsp *mac_rsp)
{
struct ql_tx_buf_cb *tx_cb;
+ int i;
tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
pci_unmap_single(qdev->pdev,
- pci_unmap_addr(tx_cb, mapaddr),
- pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(tx_cb->skb);
+ pci_unmap_addr(&tx_cb->map[0], mapaddr),
+ pci_unmap_len(&tx_cb->map[0], maplen),
+ PCI_DMA_TODEVICE);
+ tx_cb->seg_count--;
+ if (tx_cb->seg_count) {
+ for (i = 1; i < tx_cb->seg_count; i++) {
+ pci_unmap_page(qdev->pdev,
+ pci_unmap_addr(&tx_cb->map[i],
+ mapaddr),
+ pci_unmap_len(&tx_cb->map[i], maplen),
+ PCI_DMA_TODEVICE);
+ }
+ }
qdev->stats.tx_packets++;
qdev->stats.tx_bytes += tx_cb->skb->len;
+ dev_kfree_skb_irq(tx_cb->skb);
tx_cb->skb = NULL;
atomic_inc(&qdev->tx_count);
}
+/*
+ * The difference between 3022 and 3032 for inbound completions:
+ * 3022 uses two buffers per completion. The first buffer contains
+ * (some) header info, the second the remainder of the headers plus
+ * the data. For this chip we reserve some space at the top of the
+ * receive buffer so that the header info in buffer one can be
+ * prepended to the buffer two. Buffer two is the sent up while
+ * buffer one is returned to the hardware to be reused.
+ * 3032 receives all of it's data and headers in one buffer for a
+ * simpler process. 3032 also supports checksum verification as
+ * can be seen in ql_process_macip_rx_intr().
+ */
static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
struct ib_mac_iocb_rsp *ib_mac_rsp_ptr)
{
@@ -1731,14 +1770,17 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
qdev->small_buf_release_cnt++;
- /* start of first buffer */
- lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
- lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
- qdev->lrg_buf_release_cnt++;
- if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
- qdev->lrg_buf_index = 0;
- curr_ial_ptr++; /* 64-bit pointers require two incs. */
- curr_ial_ptr++;
+ if (qdev->device_id == QL3022_DEVICE_ID) {
+ /* start of first buffer (3022 only) */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) {
+ qdev->lrg_buf_index = 0;
+ }
+ curr_ial_ptr++; /* 64-bit pointers require two incs. */
+ curr_ial_ptr++;
+ }
/* start of second buffer */
lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
@@ -1769,7 +1811,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
qdev->ndev->last_rx = jiffies;
lrg_buf_cb2->skb = NULL;
- ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+ if (qdev->device_id == QL3022_DEVICE_ID)
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
}
@@ -1781,7 +1824,7 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
u32 *curr_ial_ptr;
- struct sk_buff *skb1, *skb2;
+ struct sk_buff *skb1 = NULL, *skb2;
struct net_device *ndev = qdev->ndev;
u16 length = le16_to_cpu(ib_ip_rsp_ptr->length);
u16 size = 0;
@@ -1797,16 +1840,20 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
qdev->small_buf_release_cnt++;
- /* start of first buffer */
- lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
- lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
-
- qdev->lrg_buf_release_cnt++;
- if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
- qdev->lrg_buf_index = 0;
- skb1 = lrg_buf_cb1->skb;
- curr_ial_ptr++; /* 64-bit pointers require two incs. */
- curr_ial_ptr++;
+ if (qdev->device_id == QL3022_DEVICE_ID) {
+ /* start of first buffer on 3022 */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+ qdev->lrg_buf_index = 0;
+ skb1 = lrg_buf_cb1->skb;
+ curr_ial_ptr++; /* 64-bit pointers require two incs. */
+ curr_ial_ptr++;
+ size = ETH_HLEN;
+ if (*((u16 *) skb1->data) != 0xFFFF)
+ size += VLAN_ETH_HLEN - ETH_HLEN;
+ }
/* start of second buffer */
lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
@@ -1816,18 +1863,6 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
qdev->lrg_buf_index = 0;
- qdev->stats.rx_packets++;
- qdev->stats.rx_bytes += length;
-
- /*
- * Copy the ethhdr from first buffer to second. This
- * is necessary for IP completions.
- */
- if (*((u16 *) skb1->data) != 0xFFFF)
- size = VLAN_ETH_HLEN;
- else
- size = ETH_HLEN;
-
skb_put(skb2, length); /* Just the second buffer length here. */
pci_unmap_single(qdev->pdev,
pci_unmap_addr(lrg_buf_cb2, mapaddr),
@@ -1835,16 +1870,40 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
PCI_DMA_FROMDEVICE);
prefetch(skb2->data);
- memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
- skb2->dev = qdev->ndev;
skb2->ip_summed = CHECKSUM_NONE;
+ if (qdev->device_id == QL3022_DEVICE_ID) {
+ /*
+ * Copy the ethhdr from first buffer to second. This
+ * is necessary for 3022 IP completions.
+ */
+ memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
+ } else {
+ u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum);
+ if (checksum &
+ (IB_IP_IOCB_RSP_3032_ICE |
+ IB_IP_IOCB_RSP_3032_CE |
+ IB_IP_IOCB_RSP_3032_NUC)) {
+ printk(KERN_ERR
+ "%s: Bad checksum for this %s packet, checksum = %x.\n",
+ __func__,
+ ((checksum &
+ IB_IP_IOCB_RSP_3032_TCP) ? "TCP" :
+ "UDP"),checksum);
+ } else if (checksum & IB_IP_IOCB_RSP_3032_TCP) {
+ skb2->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+ }
+ skb2->dev = qdev->ndev;
skb2->protocol = eth_type_trans(skb2, qdev->ndev);
netif_receive_skb(skb2);
+ qdev->stats.rx_packets++;
+ qdev->stats.rx_bytes += length;
ndev->last_rx = jiffies;
lrg_buf_cb2->skb = NULL;
- ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+ if (qdev->device_id == QL3022_DEVICE_ID)
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
}
@@ -1871,12 +1930,14 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
break;
case OPCODE_IB_MAC_IOCB:
+ case OPCODE_IB_3032_MAC_IOCB:
ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *)
net_rsp);
(*rx_cleaned)++;
break;
case OPCODE_IB_IP_IOCB:
+ case OPCODE_IB_3032_IP_IOCB:
ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *)
net_rsp);
(*rx_cleaned)++;
@@ -2023,13 +2084,96 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
+/*
+ * Get the total number of segments needed for the
+ * given number of fragments. This is necessary because
+ * outbound address lists (OAL) will be used when more than
+ * two frags are given. Each address list has 5 addr/len
+ * pairs. The 5th pair in each AOL is used to point to
+ * the next AOL if more frags are coming.
+ * That is why the frags:segment count ratio is not linear.
+ */
+static int ql_get_seg_count(unsigned short frags)
+{
+ switch(frags) {
+ case 0: return 1; /* just the skb->data seg */
+ case 1: return 2; /* skb->data + 1 frag */
+ case 2: return 3; /* skb->data + 2 frags */
+ case 3: return 5; /* skb->data + 1 frag + 1 AOL containting 2 frags */
+ case 4: return 6;
+ case 5: return 7;
+ case 6: return 8;
+ case 7: return 10;
+ case 8: return 11;
+ case 9: return 12;
+ case 10: return 13;
+ case 11: return 15;
+ case 12: return 16;
+ case 13: return 17;
+ case 14: return 18;
+ case 15: return 20;
+ case 16: return 21;
+ case 17: return 22;
+ case 18: return 23;
+ }
+ return -1;
+}
+
+static void ql_hw_csum_setup(struct sk_buff *skb,
+ struct ob_mac_iocb_req *mac_iocb_ptr)
+{
+ struct ethhdr *eth;
+ struct iphdr *ip = NULL;
+ u8 offset = ETH_HLEN;
+
+ eth = (struct ethhdr *)(skb->data);
+
+ if (eth->h_proto == __constant_htons(ETH_P_IP)) {
+ ip = (struct iphdr *)&skb->data[ETH_HLEN];
+ } else if (eth->h_proto == htons(ETH_P_8021Q) &&
+ ((struct vlan_ethhdr *)skb->data)->
+ h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP)) {
+ ip = (struct iphdr *)&skb->data[VLAN_ETH_HLEN];
+ offset = VLAN_ETH_HLEN;
+ }
+
+ if (ip) {
+ if (ip->protocol == IPPROTO_TCP) {
+ mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC;
+ mac_iocb_ptr->ip_hdr_off = offset;
+ mac_iocb_ptr->ip_hdr_len = ip->ihl;
+ } else if (ip->protocol == IPPROTO_UDP) {
+ mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC;
+ mac_iocb_ptr->ip_hdr_off = offset;
+ mac_iocb_ptr->ip_hdr_len = ip->ihl;
+ }
+ }
+}
+
+/*
+ * The difference between 3022 and 3032 sends:
+ * 3022 only supports a simple single segment transmission.
+ * 3032 supports checksumming and scatter/gather lists (fragments).
+ * The 3032 supports sglists by using the 3 addr/len pairs (ALP)
+ * in the IOCB plus a chain of outbound address lists (OAL) that
+ * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th)
+ * will used to point to an OAL when more ALP entries are required.
+ * The IOCB is always the top of the chain followed by one or more
+ * OALs (when necessary).
+ */
static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
{
struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
struct ql_tx_buf_cb *tx_cb;
+ u32 tot_len = skb->len;
+ struct oal *oal;
+ struct oal_entry *oal_entry;
+ int len;
struct ob_mac_iocb_req *mac_iocb_ptr;
u64 map;
+ int seg_cnt, seg = 0;
+ int frag_cnt = (int)skb_shinfo(skb)->nr_frags;
if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
if (!netif_queue_stopped(ndev))
@@ -2037,21 +2181,79 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_BUSY;
}
tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
+ seg_cnt = tx_cb->seg_count = ql_get_seg_count((skb_shinfo(skb)->nr_frags));
+ if(seg_cnt == -1) {
+ printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
+ return NETDEV_TX_OK;
+
+ }
mac_iocb_ptr = tx_cb->queue_entry;
memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
mac_iocb_ptr->flags |= qdev->mb_bit_mask;
mac_iocb_ptr->transaction_id = qdev->req_producer_index;
- mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len);
+ mac_iocb_ptr->data_len = cpu_to_le16((u16) tot_len);
tx_cb->skb = skb;
- map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
- mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map));
- mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map));
- mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E);
- pci_unmap_addr_set(tx_cb, mapaddr, map);
- pci_unmap_len_set(tx_cb, maplen, skb->len);
- atomic_dec(&qdev->tx_count);
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ ql_hw_csum_setup(skb, mac_iocb_ptr);
+ len = skb_headlen(skb);
+ map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE);
+ oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
+ oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+ oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+ oal_entry->len = cpu_to_le32(len);
+ pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+ pci_unmap_len_set(&tx_cb->map[seg], maplen, len);
+ seg++;
+
+ if (!skb_shinfo(skb)->nr_frags) {
+ /* Terminate the last segment. */
+ oal_entry->len =
+ cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
+ } else {
+ int i;
+ oal = tx_cb->oal;
+ for (i=0; i<frag_cnt; i++,seg++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ oal_entry++;
+ if ((seg == 2 && seg_cnt > 3) || /* Check for continuation */
+ (seg == 7 && seg_cnt > 8) || /* requirements. It's strange */
+ (seg == 12 && seg_cnt > 13) || /* but necessary. */
+ (seg == 17 && seg_cnt > 18)) {
+ /* Continuation entry points to outbound address list. */
+ map = pci_map_single(qdev->pdev, oal,
+ sizeof(struct oal),
+ PCI_DMA_TODEVICE);
+ oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+ oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+ oal_entry->len =
+ cpu_to_le32(sizeof(struct oal) |
+ OAL_CONT_ENTRY);
+ pci_unmap_addr_set(&tx_cb->map[seg], mapaddr,
+ map);
+ pci_unmap_len_set(&tx_cb->map[seg], maplen,
+ len);
+ oal_entry = (struct oal_entry *)oal;
+ oal++;
+ seg++;
+ }
+ map =
+ pci_map_page(qdev->pdev, frag->page,
+ frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
+ oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+ oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+ oal_entry->len = cpu_to_le32(frag->size);
+ pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+ pci_unmap_len_set(&tx_cb->map[seg], maplen,
+ frag->size);
+ }
+ /* Terminate the last segment. */
+ oal_entry->len =
+ cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
+ }
+ wmb();
qdev->req_producer_index++;
if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
qdev->req_producer_index = 0;
@@ -2065,8 +2267,10 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
ndev->name, qdev->req_producer_index, skb->len);
+ atomic_dec(&qdev->tx_count);
return NETDEV_TX_OK;
}
+
static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
{
qdev->req_q_size =
@@ -2350,7 +2554,22 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
return 0;
}
-static void ql_create_send_free_list(struct ql3_adapter *qdev)
+static void ql_free_send_free_list(struct ql3_adapter *qdev)
+{
+ struct ql_tx_buf_cb *tx_cb;
+ int i;
+
+ tx_cb = &qdev->tx_buf[0];
+ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+ if (tx_cb->oal) {
+ kfree(tx_cb->oal);
+ tx_cb->oal = NULL;
+ }
+ tx_cb++;
+ }
+}
+
+static int ql_create_send_free_list(struct ql3_adapter *qdev)
{
struct ql_tx_buf_cb *tx_cb;
int i;
@@ -2359,11 +2578,16 @@ static void ql_create_send_free_list(struct ql3_adapter *qdev)
/* Create free list of transmit buffers */
for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+
tx_cb = &qdev->tx_buf[i];
tx_cb->skb = NULL;
tx_cb->queue_entry = req_q_curr;
req_q_curr++;
+ tx_cb->oal = kmalloc(512, GFP_KERNEL);
+ if (tx_cb->oal == NULL)
+ return -1;
}
+ return 0;
}
static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
@@ -2438,12 +2662,14 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
/* Initialize the large buffer queue. */
ql_init_large_buffers(qdev);
- ql_create_send_free_list(qdev);
+ if (ql_create_send_free_list(qdev))
+ goto err_free_list;
qdev->rsp_current = qdev->rsp_q_virt_addr;
return 0;
-
+err_free_list:
+ ql_free_send_free_list(qdev);
err_small_buffers:
ql_free_buffer_queues(qdev);
err_buffer_queues:
@@ -2459,6 +2685,7 @@ err_req_rsp:
static void ql_free_mem_resources(struct ql3_adapter *qdev)
{
+ ql_free_send_free_list(qdev);
ql_free_large_buffers(qdev);
ql_free_small_buffers(qdev);
ql_free_buffer_queues(qdev);
@@ -2757,11 +2984,20 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
}
/* Enable Ethernet Function */
- value =
- (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
- PORT_CONTROL_HH);
- ql_write_page0_reg(qdev, &port_regs->portControl,
- ((value << 16) | value));
+ if (qdev->device_id == QL3032_DEVICE_ID) {
+ value =
+ (QL3032_PORT_CONTROL_EF | QL3032_PORT_CONTROL_KIE |
+ QL3032_PORT_CONTROL_EIv6 | QL3032_PORT_CONTROL_EIv4);
+ ql_write_page0_reg(qdev, &port_regs->functionControl,
+ ((value << 16) | value));
+ } else {
+ value =
+ (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
+ PORT_CONTROL_HH);
+ ql_write_page0_reg(qdev, &port_regs->portControl,
+ ((value << 16) | value));
+ }
+
out:
return status;
@@ -2908,8 +3144,10 @@ static void ql_display_dev_info(struct net_device *ndev)
struct pci_dev *pdev = qdev->pdev;
printk(KERN_INFO PFX
- "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n",
- DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot);
+ "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n",
+ DRV_NAME, qdev->index, qdev->chip_rev_id,
+ (qdev->device_id == QL3032_DEVICE_ID) ? "QLA3032" : "QLA3022",
+ qdev->pci_slot);
printk(KERN_INFO PFX
"%s Interface.\n",
test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER");
@@ -3203,15 +3441,22 @@ static void ql_reset_work(struct work_struct *work)
* Loop through the active list and return the skb.
*/
for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+ int j;
tx_cb = &qdev->tx_buf[i];
if (tx_cb->skb) {
-
printk(KERN_DEBUG PFX
"%s: Freeing lost SKB.\n",
qdev->ndev->name);
pci_unmap_single(qdev->pdev,
- pci_unmap_addr(tx_cb, mapaddr),
- pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
+ pci_unmap_addr(&tx_cb->map[0], mapaddr),
+ pci_unmap_len(&tx_cb->map[0], maplen),
+ PCI_DMA_TODEVICE);
+ for(j=1;j<tx_cb->seg_count;j++) {
+ pci_unmap_page(qdev->pdev,
+ pci_unmap_addr(&tx_cb->map[j],mapaddr),
+ pci_unmap_len(&tx_cb->map[j],maplen),
+ PCI_DMA_TODEVICE);
+ }
dev_kfree_skb(tx_cb->skb);
tx_cb->skb = NULL;
}
@@ -3370,22 +3615,24 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
- ndev->features = NETIF_F_LLTX;
- if (pci_using_dac)
- ndev->features |= NETIF_F_HIGHDMA;
-
pci_set_drvdata(pdev, ndev);
qdev = netdev_priv(ndev);
qdev->index = cards_found;
qdev->ndev = ndev;
qdev->pdev = pdev;
+ qdev->device_id = pci_entry->device;
qdev->port_link_state = LS_DOWN;
if (msi)
qdev->msi = 1;
qdev->msg_enable = netif_msg_init(debug, default_msg);
+ if (pci_using_dac)
+ ndev->features |= NETIF_F_HIGHDMA;
+ if (qdev->device_id == QL3032_DEVICE_ID)
+ ndev->features |= (NETIF_F_HW_CSUM | NETIF_F_SG);
+
qdev->mem_map_registers =
ioremap_nocache(pci_resource_start(pdev, 1),
pci_resource_len(qdev->pdev, 1));
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
index ea94de7fd07..b2d76ea6882 100644..100755
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -21,7 +21,9 @@
#define OPCODE_UPDATE_NCB_IOCB 0xF0
#define OPCODE_IB_MAC_IOCB 0xF9
+#define OPCODE_IB_3032_MAC_IOCB 0x09
#define OPCODE_IB_IP_IOCB 0xFA
+#define OPCODE_IB_3032_IP_IOCB 0x0A
#define OPCODE_IB_TCP_IOCB 0xFB
#define OPCODE_DUMP_PROTO_IOCB 0xFE
#define OPCODE_BUFFER_ALERT_IOCB 0xFB
@@ -37,18 +39,23 @@
struct ob_mac_iocb_req {
u8 opcode;
u8 flags;
-#define OB_MAC_IOCB_REQ_MA 0xC0
-#define OB_MAC_IOCB_REQ_F 0x20
-#define OB_MAC_IOCB_REQ_X 0x10
+#define OB_MAC_IOCB_REQ_MA 0xe0
+#define OB_MAC_IOCB_REQ_F 0x10
+#define OB_MAC_IOCB_REQ_X 0x08
#define OB_MAC_IOCB_REQ_D 0x02
#define OB_MAC_IOCB_REQ_I 0x01
- __le16 reserved0;
+ u8 flags1;
+#define OB_3032MAC_IOCB_REQ_IC 0x04
+#define OB_3032MAC_IOCB_REQ_TC 0x02
+#define OB_3032MAC_IOCB_REQ_UC 0x01
+ u8 reserved0;
__le32 transaction_id;
__le16 data_len;
- __le16 reserved1;
+ u8 ip_hdr_off;
+ u8 ip_hdr_len;
+ __le32 reserved1;
__le32 reserved2;
- __le32 reserved3;
__le32 buf_addr0_low;
__le32 buf_addr0_high;
__le32 buf_0_len;
@@ -58,8 +65,8 @@ struct ob_mac_iocb_req {
__le32 buf_addr2_low;
__le32 buf_addr2_high;
__le32 buf_2_len;
+ __le32 reserved3;
__le32 reserved4;
- __le32 reserved5;
};
/*
* The following constants define control bits for buffer
@@ -74,6 +81,7 @@ struct ob_mac_iocb_rsp {
u8 opcode;
u8 flags;
#define OB_MAC_IOCB_RSP_P 0x08
+#define OB_MAC_IOCB_RSP_L 0x04
#define OB_MAC_IOCB_RSP_S 0x02
#define OB_MAC_IOCB_RSP_I 0x01
@@ -85,6 +93,7 @@ struct ob_mac_iocb_rsp {
struct ib_mac_iocb_rsp {
u8 opcode;
+#define IB_MAC_IOCB_RSP_V 0x80
u8 flags;
#define IB_MAC_IOCB_RSP_S 0x80
#define IB_MAC_IOCB_RSP_H1 0x40
@@ -138,6 +147,7 @@ struct ob_ip_iocb_req {
struct ob_ip_iocb_rsp {
u8 opcode;
u8 flags;
+#define OB_MAC_IOCB_RSP_H 0x10
#define OB_MAC_IOCB_RSP_E 0x08
#define OB_MAC_IOCB_RSP_L 0x04
#define OB_MAC_IOCB_RSP_S 0x02
@@ -220,6 +230,10 @@ struct ob_tcp_iocb_rsp {
struct ib_ip_iocb_rsp {
u8 opcode;
+#define IB_IP_IOCB_RSP_3032_V 0x80
+#define IB_IP_IOCB_RSP_3032_O 0x40
+#define IB_IP_IOCB_RSP_3032_I 0x20
+#define IB_IP_IOCB_RSP_3032_R 0x10
u8 flags;
#define IB_IP_IOCB_RSP_S 0x80
#define IB_IP_IOCB_RSP_H1 0x40
@@ -230,6 +244,12 @@ struct ib_ip_iocb_rsp {
__le16 length;
__le16 checksum;
+#define IB_IP_IOCB_RSP_3032_ICE 0x01
+#define IB_IP_IOCB_RSP_3032_CE 0x02
+#define IB_IP_IOCB_RSP_3032_NUC 0x04
+#define IB_IP_IOCB_RSP_3032_UDP 0x08
+#define IB_IP_IOCB_RSP_3032_TCP 0x10
+#define IB_IP_IOCB_RSP_3032_IPE 0x20
__le16 reserved;
#define IB_IP_IOCB_RSP_R 0x01
__le32 ial_low;
@@ -524,6 +544,21 @@ enum {
IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005,
IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006,
IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
+ IP_ADDR_INDEX_REG_6 = 0x0008,
+ IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030,
+ IP_ADDR_INDEX_REG_E = 0x0040,
+};
+enum {
+ QL3032_PORT_CONTROL_DS = 0x0001,
+ QL3032_PORT_CONTROL_HH = 0x0002,
+ QL3032_PORT_CONTROL_EIv6 = 0x0004,
+ QL3032_PORT_CONTROL_EIv4 = 0x0008,
+ QL3032_PORT_CONTROL_ET = 0x0010,
+ QL3032_PORT_CONTROL_EF = 0x0020,
+ QL3032_PORT_CONTROL_DRM = 0x0040,
+ QL3032_PORT_CONTROL_RLB = 0x0080,
+ QL3032_PORT_CONTROL_RCB = 0x0100,
+ QL3032_PORT_CONTROL_KIE = 0x0200,
};
enum {
@@ -657,7 +692,8 @@ struct ql3xxx_port_registers {
u32 internalRamWDataReg;
u32 reclaimedBufferAddrRegLow;
u32 reclaimedBufferAddrRegHigh;
- u32 reserved[2];
+ u32 tcpConfiguration;
+ u32 functionControl;
u32 fpgaRevID;
u32 localRamAddr;
u32 localRamDataAutoIncr;
@@ -963,6 +999,7 @@ struct eeprom_data {
#define QL3XXX_VENDOR_ID 0x1077
#define QL3022_DEVICE_ID 0x3022
+#define QL3032_DEVICE_ID 0x3032
/* MTU & Frame Size stuff */
#define NORMAL_MTU_SIZE ETH_DATA_LEN
@@ -1038,11 +1075,41 @@ struct ql_rcv_buf_cb {
int index;
};
+/*
+ * Original IOCB has 3 sg entries:
+ * first points to skb-data area
+ * second points to first frag
+ * third points to next oal.
+ * OAL has 5 entries:
+ * 1 thru 4 point to frags
+ * fifth points to next oal.
+ */
+#define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1)
+
+struct oal_entry {
+ u32 dma_lo;
+ u32 dma_hi;
+ u32 len;
+#define OAL_LAST_ENTRY 0x80000000 /* Last valid buffer in list. */
+#define OAL_CONT_ENTRY 0x40000000 /* points to an OAL. (continuation) */
+ u32 reserved;
+};
+
+struct oal {
+ struct oal_entry oal_entry[5];
+};
+
+struct map_list {
+ DECLARE_PCI_UNMAP_ADDR(mapaddr);
+ DECLARE_PCI_UNMAP_LEN(maplen);
+};
+
struct ql_tx_buf_cb {
struct sk_buff *skb;
struct ob_mac_iocb_req *queue_entry ;
- DECLARE_PCI_UNMAP_ADDR(mapaddr);
- DECLARE_PCI_UNMAP_LEN(maplen);
+ int seg_count;
+ struct oal *oal;
+ struct map_list map[MAX_SKB_FRAGS+1];
};
/* definitions for type field */
@@ -1189,6 +1256,7 @@ struct ql3_adapter {
struct delayed_work reset_work;
struct delayed_work tx_timeout_work;
u32 max_frame_size;
+ u32 device_id;
};
#endif /* _QLA3XXX_H_ */
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index f83b41d4cb0..5598d86380b 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -225,7 +225,6 @@ MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
static int rx_copybreak = 200;
static int use_dac;
-static int ignore_parity_err;
static struct {
u32 msg_enable;
} debug = { -1 };
@@ -471,8 +470,6 @@ module_param(use_dac, int, 0);
MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot.");
module_param_named(debug, debug.msg_enable, int, 0);
MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");
-module_param_named(ignore_parity_err, ignore_parity_err, bool, 0);
-MODULE_PARM_DESC(ignore_parity_err, "Ignore PCI parity error as target. Default: false");
MODULE_LICENSE("GPL");
MODULE_VERSION(RTL8169_VERSION);
@@ -1885,7 +1882,6 @@ static void rtl8169_hw_start(struct net_device *dev)
(tp->mac_version == RTL_GIGA_MAC_VER_02) ||
(tp->mac_version == RTL_GIGA_MAC_VER_03) ||
(tp->mac_version == RTL_GIGA_MAC_VER_04))
- RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
rtl8169_set_rx_tx_config_registers(tp);
cmd = RTL_R16(CPlusCmd);
@@ -2020,7 +2016,7 @@ static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
if (!skb)
goto err_out;
- skb_reserve(skb, (align - 1) & (u32)skb->data);
+ skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
*sk_buff = skb;
mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
@@ -2388,7 +2384,7 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
*
* Feel free to adjust to your needs.
*/
- if (ignore_parity_err)
+ if (pdev->broken_parity_status)
pci_cmd &= ~PCI_COMMAND_PARITY;
else
pci_cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
@@ -2491,7 +2487,7 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
skb = dev_alloc_skb(pkt_size + align);
if (skb) {
- skb_reserve(skb, (align - 1) & (u32)skb->data);
+ skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
*sk_buff = skb;
rtl8169_mark_to_asic(desc, rx_buf_sz);
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index a914fef4430..0e345cbc2bf 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -15,7 +15,7 @@
#define TBD 0
-typedef struct _XENA_dev_config {
+struct XENA_dev_config {
/* Convention: mHAL_XXX is mask, vHAL_XXX is value */
/* General Control-Status Registers */
@@ -300,6 +300,7 @@ typedef struct _XENA_dev_config {
u64 gpio_control;
#define GPIO_CTRL_GPIO_0 BIT(8)
u64 misc_control;
+#define FAULT_BEHAVIOUR BIT(0)
#define EXT_REQ_EN BIT(1)
#define MISC_LINK_STABILITY_PRD(val) vBIT(val,29,3)
@@ -851,9 +852,9 @@ typedef struct _XENA_dev_config {
#define SPI_CONTROL_DONE BIT(6)
u64 spi_data;
#define SPI_DATA_WRITE(data,len) vBIT(data,0,len)
-} XENA_dev_config_t;
+};
-#define XENA_REG_SPACE sizeof(XENA_dev_config_t)
+#define XENA_REG_SPACE sizeof(struct XENA_dev_config)
#define XENA_EEPROM_SPACE (0x01 << 11)
#endif /* _REGS_H */
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 250cdbeefdf..8646b64994a 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -77,7 +77,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.15.2"
+#define DRV_VERSION "2.0.16.1"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -86,7 +86,7 @@ static char s2io_driver_version[] = DRV_VERSION;
static int rxd_size[4] = {32,48,48,64};
static int rxd_count[4] = {127,85,85,63};
-static inline int RXD_IS_UP2DT(RxD_t *rxdp)
+static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
{
int ret;
@@ -111,9 +111,9 @@ static inline int RXD_IS_UP2DT(RxD_t *rxdp)
#define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
#define PANIC 1
#define LOW 2
-static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring)
+static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring)
{
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
mac_control = &sp->mac_control;
if (rxb_size <= rxd_count[sp->rxd_mode])
@@ -286,7 +286,7 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
static void s2io_vlan_rx_register(struct net_device *dev,
struct vlan_group *grp)
{
- nic_t *nic = dev->priv;
+ struct s2io_nic *nic = dev->priv;
unsigned long flags;
spin_lock_irqsave(&nic->tx_lock, flags);
@@ -297,7 +297,7 @@ static void s2io_vlan_rx_register(struct net_device *dev,
/* Unregister the vlan */
static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
{
- nic_t *nic = dev->priv;
+ struct s2io_nic *nic = dev->priv;
unsigned long flags;
spin_lock_irqsave(&nic->tx_lock, flags);
@@ -401,9 +401,10 @@ S2IO_PARM_INT(lro, 0);
* aggregation happens until we hit max IP pkt size(64K)
*/
S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
-#ifndef CONFIG_S2IO_NAPI
S2IO_PARM_INT(indicate_max_pkts, 0);
-#endif
+
+S2IO_PARM_INT(napi, 1);
+S2IO_PARM_INT(ufo, 0);
static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
{DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
@@ -457,14 +458,14 @@ static int init_shared_mem(struct s2io_nic *nic)
u32 size;
void *tmp_v_addr, *tmp_v_addr_next;
dma_addr_t tmp_p_addr, tmp_p_addr_next;
- RxD_block_t *pre_rxd_blk = NULL;
- int i, j, blk_cnt, rx_sz, tx_sz;
+ struct RxD_block *pre_rxd_blk = NULL;
+ int i, j, blk_cnt;
int lst_size, lst_per_page;
struct net_device *dev = nic->dev;
unsigned long tmp;
- buffAdd_t *ba;
+ struct buffAdd *ba;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &nic->mac_control;
@@ -482,13 +483,12 @@ static int init_shared_mem(struct s2io_nic *nic)
return -EINVAL;
}
- lst_size = (sizeof(TxD_t) * config->max_txds);
- tx_sz = lst_size * size;
+ lst_size = (sizeof(struct TxD) * config->max_txds);
lst_per_page = PAGE_SIZE / lst_size;
for (i = 0; i < config->tx_fifo_num; i++) {
int fifo_len = config->tx_cfg[i].fifo_len;
- int list_holder_size = fifo_len * sizeof(list_info_hold_t);
+ int list_holder_size = fifo_len * sizeof(struct list_info_hold);
mac_control->fifos[i].list_info = kmalloc(list_holder_size,
GFP_KERNEL);
if (!mac_control->fifos[i].list_info) {
@@ -556,10 +556,9 @@ static int init_shared_mem(struct s2io_nic *nic)
}
}
- nic->ufo_in_band_v = kmalloc((sizeof(u64) * size), GFP_KERNEL);
+ nic->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL);
if (!nic->ufo_in_band_v)
return -ENOMEM;
- memset(nic->ufo_in_band_v, 0, size);
/* Allocation and initialization of RXDs in Rings */
size = 0;
@@ -580,10 +579,9 @@ static int init_shared_mem(struct s2io_nic *nic)
mac_control->rings[i].block_count;
}
if (nic->rxd_mode == RXD_MODE_1)
- size = (size * (sizeof(RxD1_t)));
+ size = (size * (sizeof(struct RxD1)));
else
- size = (size * (sizeof(RxD3_t)));
- rx_sz = size;
+ size = (size * (sizeof(struct RxD3)));
for (i = 0; i < config->rx_ring_num; i++) {
mac_control->rings[i].rx_curr_get_info.block_index = 0;
@@ -601,7 +599,7 @@ static int init_shared_mem(struct s2io_nic *nic)
(rxd_count[nic->rxd_mode] + 1);
/* Allocating all the Rx blocks */
for (j = 0; j < blk_cnt; j++) {
- rx_block_info_t *rx_blocks;
+ struct rx_block_info *rx_blocks;
int l;
rx_blocks = &mac_control->rings[i].rx_blocks[j];
@@ -621,9 +619,11 @@ static int init_shared_mem(struct s2io_nic *nic)
memset(tmp_v_addr, 0, size);
rx_blocks->block_virt_addr = tmp_v_addr;
rx_blocks->block_dma_addr = tmp_p_addr;
- rx_blocks->rxds = kmalloc(sizeof(rxd_info_t)*
+ rx_blocks->rxds = kmalloc(sizeof(struct rxd_info)*
rxd_count[nic->rxd_mode],
GFP_KERNEL);
+ if (!rx_blocks->rxds)
+ return -ENOMEM;
for (l=0; l<rxd_count[nic->rxd_mode];l++) {
rx_blocks->rxds[l].virt_addr =
rx_blocks->block_virt_addr +
@@ -646,7 +646,7 @@ static int init_shared_mem(struct s2io_nic *nic)
mac_control->rings[i].rx_blocks[(j + 1) %
blk_cnt].block_dma_addr;
- pre_rxd_blk = (RxD_block_t *) tmp_v_addr;
+ pre_rxd_blk = (struct RxD_block *) tmp_v_addr;
pre_rxd_blk->reserved_2_pNext_RxD_block =
(unsigned long) tmp_v_addr_next;
pre_rxd_blk->pNext_RxD_Blk_physical =
@@ -662,14 +662,14 @@ static int init_shared_mem(struct s2io_nic *nic)
blk_cnt = config->rx_cfg[i].num_rxd /
(rxd_count[nic->rxd_mode]+ 1);
mac_control->rings[i].ba =
- kmalloc((sizeof(buffAdd_t *) * blk_cnt),
+ kmalloc((sizeof(struct buffAdd *) * blk_cnt),
GFP_KERNEL);
if (!mac_control->rings[i].ba)
return -ENOMEM;
for (j = 0; j < blk_cnt; j++) {
int k = 0;
mac_control->rings[i].ba[j] =
- kmalloc((sizeof(buffAdd_t) *
+ kmalloc((sizeof(struct buffAdd) *
(rxd_count[nic->rxd_mode] + 1)),
GFP_KERNEL);
if (!mac_control->rings[i].ba[j])
@@ -701,7 +701,7 @@ static int init_shared_mem(struct s2io_nic *nic)
}
/* Allocation and initialization of Statistics block */
- size = sizeof(StatInfo_t);
+ size = sizeof(struct stat_block);
mac_control->stats_mem = pci_alloc_consistent
(nic->pdev, size, &mac_control->stats_mem_phy);
@@ -716,7 +716,7 @@ static int init_shared_mem(struct s2io_nic *nic)
mac_control->stats_mem_sz = size;
tmp_v_addr = mac_control->stats_mem;
- mac_control->stats_info = (StatInfo_t *) tmp_v_addr;
+ mac_control->stats_info = (struct stat_block *) tmp_v_addr;
memset(tmp_v_addr, 0, size);
DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
(unsigned long long) tmp_p_addr);
@@ -736,7 +736,7 @@ static void free_shared_mem(struct s2io_nic *nic)
int i, j, blk_cnt, size;
void *tmp_v_addr;
dma_addr_t tmp_p_addr;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int lst_size, lst_per_page;
struct net_device *dev = nic->dev;
@@ -747,7 +747,7 @@ static void free_shared_mem(struct s2io_nic *nic)
mac_control = &nic->mac_control;
config = &nic->config;
- lst_size = (sizeof(TxD_t) * config->max_txds);
+ lst_size = (sizeof(struct TxD) * config->max_txds);
lst_per_page = PAGE_SIZE / lst_size;
for (i = 0; i < config->tx_fifo_num; i++) {
@@ -810,7 +810,7 @@ static void free_shared_mem(struct s2io_nic *nic)
if (!mac_control->rings[i].ba[j])
continue;
while (k != rxd_count[nic->rxd_mode]) {
- buffAdd_t *ba =
+ struct buffAdd *ba =
&mac_control->rings[i].ba[j][k];
kfree(ba->ba_0_org);
kfree(ba->ba_1_org);
@@ -836,9 +836,9 @@ static void free_shared_mem(struct s2io_nic *nic)
* s2io_verify_pci_mode -
*/
-static int s2io_verify_pci_mode(nic_t *nic)
+static int s2io_verify_pci_mode(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
int mode;
@@ -869,9 +869,9 @@ static int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266};
/**
* s2io_print_pci_mode -
*/
-static int s2io_print_pci_mode(nic_t *nic)
+static int s2io_print_pci_mode(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
int mode;
struct config_param *config = &nic->config;
@@ -939,13 +939,13 @@ static int s2io_print_pci_mode(nic_t *nic)
static int init_nic(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
struct net_device *dev = nic->dev;
register u64 val64 = 0;
void __iomem *add;
u32 time;
int i, j;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int dtx_cnt = 0;
unsigned long long mem_share;
@@ -1415,7 +1415,7 @@ static int init_nic(struct s2io_nic *nic)
val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
TTI_DATA2_MEM_TX_UFC_B(0x20) |
- TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80);
+ TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80);
writeq(val64, &bar0->tti_data2_mem);
val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
@@ -1611,7 +1611,8 @@ static int init_nic(struct s2io_nic *nic)
* that does not start on an ADB to reduce disconnects.
*/
if (nic->device_type == XFRAME_II_DEVICE) {
- val64 = EXT_REQ_EN | MISC_LINK_STABILITY_PRD(3);
+ val64 = FAULT_BEHAVIOUR | EXT_REQ_EN |
+ MISC_LINK_STABILITY_PRD(3);
writeq(val64, &bar0->misc_control);
val64 = readq(&bar0->pic_control2);
val64 &= ~(BIT(13)|BIT(14)|BIT(15));
@@ -1627,7 +1628,7 @@ static int init_nic(struct s2io_nic *nic)
#define LINK_UP_DOWN_INTERRUPT 1
#define MAC_RMAC_ERR_TIMER 2
-static int s2io_link_fault_indication(nic_t *nic)
+static int s2io_link_fault_indication(struct s2io_nic *nic)
{
if (nic->intr_type != INTA)
return MAC_RMAC_ERR_TIMER;
@@ -1650,14 +1651,14 @@ static int s2io_link_fault_indication(nic_t *nic)
static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0, temp64 = 0;
/* Top level interrupt classification */
/* PIC Interrupts */
if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
/* Enable PIC Intrs in the general intr mask register */
- val64 = TXPIC_INT_M | PIC_RX_INT_M;
+ val64 = TXPIC_INT_M;
if (flag == ENABLE_INTRS) {
temp64 = readq(&bar0->general_int_mask);
temp64 &= ~((u64) val64);
@@ -1695,70 +1696,6 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
}
}
- /* DMA Interrupts */
- /* Enabling/Disabling Tx DMA interrupts */
- if (mask & TX_DMA_INTR) {
- /* Enable TxDMA Intrs in the general intr mask register */
- val64 = TXDMA_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * Keep all interrupts other than PFC interrupt
- * and PCC interrupt disabled in DMA level.
- */
- val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M |
- TXDMA_PCC_INT_M);
- writeq(val64, &bar0->txdma_int_mask);
- /*
- * Enable only the MISC error 1 interrupt in PFC block
- */
- val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1);
- writeq(val64, &bar0->pfc_err_mask);
- /*
- * Enable only the FB_ECC error interrupt in PCC block
- */
- val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR);
- writeq(val64, &bar0->pcc_err_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable TxDMA Intrs in the general intr mask
- * register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask);
- writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
- /* Enabling/Disabling Rx DMA interrupts */
- if (mask & RX_DMA_INTR) {
- /* Enable RxDMA Intrs in the general intr mask register */
- val64 = RXDMA_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * All RxDMA block interrupts are disabled for now
- * TODO
- */
- writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable RxDMA Intrs in the general intr mask
- * register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
/* MAC Interrupts */
/* Enabling/Disabling MAC interrupts */
if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
@@ -1785,53 +1722,6 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
}
}
- /* XGXS Interrupts */
- if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) {
- val64 = TXXGXS_INT_M | RXXGXS_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * All XGXS block error interrupts are disabled for now
- * TODO
- */
- writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable MC Intrs in the general intr mask register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
- /* Memory Controller(MC) interrupts */
- if (mask & MC_INTR) {
- val64 = MC_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * Enable all MC Intrs.
- */
- writeq(0x0, &bar0->mc_int_mask);
- writeq(0x0, &bar0->mc_err_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable MC Intrs in the general intr mask register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
-
/* Tx traffic interrupts */
if (mask & TX_TRAFFIC_INTR) {
val64 = TXTRAFFIC_INT_M;
@@ -1878,41 +1768,36 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
}
}
-static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
+/**
+ * verify_pcc_quiescent- Checks for PCC quiescent state
+ * Return: 1 If PCC is quiescence
+ * 0 If PCC is not quiescence
+ */
+static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
{
- int ret = 0;
+ int ret = 0, herc;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ u64 val64 = readq(&bar0->adapter_status);
+
+ herc = (sp->device_type == XFRAME_II_DEVICE);
if (flag == FALSE) {
- if ((!herc && (rev_id >= 4)) || herc) {
- if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) &&
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+ if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
+ if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
ret = 1;
- }
- }else {
- if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+ } else {
+ if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
ret = 1;
- }
}
} else {
- if ((!herc && (rev_id >= 4)) || herc) {
+ if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
- ADAPTER_STATUS_RMAC_PCC_IDLE) &&
- (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
+ ADAPTER_STATUS_RMAC_PCC_IDLE))
ret = 1;
- }
} else {
if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
- ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
- (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
+ ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
ret = 1;
- }
}
}
@@ -1920,9 +1805,6 @@ static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
}
/**
* verify_xena_quiescence - Checks whether the H/W is ready
- * @val64 : Value read from adapter status register.
- * @flag : indicates if the adapter enable bit was ever written once
- * before.
* Description: Returns whether the H/W is ready to go or not. Depending
* on whether adapter enable bit was written or not the comparison
* differs and the calling function passes the input argument flag to
@@ -1931,24 +1813,63 @@ static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
* 0 If Xena is not quiescence
*/
-static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
+static int verify_xena_quiescence(struct s2io_nic *sp)
{
- int ret = 0, herc;
- u64 tmp64 = ~((u64) val64);
- int rev_id = get_xena_rev_id(sp->pdev);
+ int mode;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ u64 val64 = readq(&bar0->adapter_status);
+ mode = s2io_verify_pci_mode(sp);
- herc = (sp->device_type == XFRAME_II_DEVICE);
- if (!
- (tmp64 &
- (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY |
- ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY |
- ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY |
- ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK |
- ADAPTER_STATUS_P_PLL_LOCK))) {
- ret = check_prc_pcc_state(val64, flag, rev_id, herc);
+ if (!(val64 & ADAPTER_STATUS_TDMA_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_RDMA_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_PFC_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
+ DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) {
+ DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) {
+ DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!");
+ return 0;
}
- return ret;
+ /*
+ * In PCI 33 mode, the P_PLL is not used, and therefore,
+ * the the P_PLL_LOCK bit in the adapter_status register will
+ * not be asserted.
+ */
+ if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) &&
+ sp->device_type == XFRAME_II_DEVICE && mode !=
+ PCI_MODE_PCI_33) {
+ DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!");
+ return 0;
+ }
+ if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
+ ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+ DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!");
+ return 0;
+ }
+ return 1;
}
/**
@@ -1959,9 +1880,9 @@ static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
*
*/
-static void fix_mac_address(nic_t * sp)
+static void fix_mac_address(struct s2io_nic * sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
int i = 0;
@@ -1987,11 +1908,11 @@ static void fix_mac_address(nic_t * sp)
static int start_nic(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
struct net_device *dev = nic->dev;
register u64 val64 = 0;
u16 subid, i;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &nic->mac_control;
@@ -2053,7 +1974,7 @@ static int start_nic(struct s2io_nic *nic)
* it.
*/
val64 = readq(&bar0->adapter_status);
- if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
+ if (!verify_xena_quiescence(nic)) {
DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
(unsigned long long) val64);
@@ -2096,11 +2017,12 @@ static int start_nic(struct s2io_nic *nic)
/**
* s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
*/
-static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off)
+static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \
+ TxD *txdlp, int get_off)
{
- nic_t *nic = fifo_data->nic;
+ struct s2io_nic *nic = fifo_data->nic;
struct sk_buff *skb;
- TxD_t *txds;
+ struct TxD *txds;
u16 j, frg_cnt;
txds = txdlp;
@@ -2114,7 +2036,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in
skb = (struct sk_buff *) ((unsigned long)
txds->Host_Control);
if (!skb) {
- memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds));
+ memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds));
return NULL;
}
pci_unmap_single(nic->pdev, (dma_addr_t)
@@ -2133,7 +2055,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in
frag->size, PCI_DMA_TODEVICE);
}
}
- memset(txdlp,0, (sizeof(TxD_t) * fifo_data->max_txds));
+ memset(txdlp,0, (sizeof(struct TxD) * fifo_data->max_txds));
return(skb);
}
@@ -2149,9 +2071,9 @@ static void free_tx_buffers(struct s2io_nic *nic)
{
struct net_device *dev = nic->dev;
struct sk_buff *skb;
- TxD_t *txdp;
+ struct TxD *txdp;
int i, j;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int cnt = 0;
@@ -2160,7 +2082,7 @@ static void free_tx_buffers(struct s2io_nic *nic)
for (i = 0; i < config->tx_fifo_num; i++) {
for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
- txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
+ txdp = (struct TxD *) mac_control->fifos[i].list_info[j].
list_virt_addr;
skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
if (skb) {
@@ -2188,10 +2110,10 @@ static void free_tx_buffers(struct s2io_nic *nic)
static void stop_nic(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
u16 interruptible;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &nic->mac_control;
@@ -2209,14 +2131,15 @@ static void stop_nic(struct s2io_nic *nic)
writeq(val64, &bar0->adapter_control);
}
-static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
+static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \
+ sk_buff *skb)
{
struct net_device *dev = nic->dev;
struct sk_buff *frag_list;
void *tmp;
/* Buffer-1 receives L3/L4 headers */
- ((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single
+ ((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single
(nic->pdev, skb->data, l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
@@ -2227,13 +2150,14 @@ static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
return -ENOMEM ;
}
frag_list = skb_shinfo(skb)->frag_list;
+ skb->truesize += frag_list->truesize;
frag_list->next = NULL;
tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
frag_list->data = tmp;
frag_list->tail = tmp;
/* Buffer-2 receives L4 data payload */
- ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
+ ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
frag_list->data, dev->mtu,
PCI_DMA_FROMDEVICE);
rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
@@ -2267,18 +2191,16 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
{
struct net_device *dev = nic->dev;
struct sk_buff *skb;
- RxD_t *rxdp;
+ struct RxD_t *rxdp;
int off, off1, size, block_no, block_no1;
u32 alloc_tab = 0;
u32 alloc_cnt;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
u64 tmp;
- buffAdd_t *ba;
-#ifndef CONFIG_S2IO_NAPI
+ struct buffAdd *ba;
unsigned long flags;
-#endif
- RxD_t *first_rxdp = NULL;
+ struct RxD_t *first_rxdp = NULL;
mac_control = &nic->mac_control;
config = &nic->config;
@@ -2321,12 +2243,15 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
dev->name, rxdp);
}
-#ifndef CONFIG_S2IO_NAPI
- spin_lock_irqsave(&nic->put_lock, flags);
- mac_control->rings[ring_no].put_pos =
- (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
- spin_unlock_irqrestore(&nic->put_lock, flags);
-#endif
+ if(!napi) {
+ spin_lock_irqsave(&nic->put_lock, flags);
+ mac_control->rings[ring_no].put_pos =
+ (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
+ spin_unlock_irqrestore(&nic->put_lock, flags);
+ } else {
+ mac_control->rings[ring_no].put_pos =
+ (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
+ }
if ((rxdp->Control_1 & RXD_OWN_XENA) &&
((nic->rxd_mode >= RXD_MODE_3A) &&
(rxdp->Control_2 & BIT(0)))) {
@@ -2357,9 +2282,9 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
}
if (nic->rxd_mode == RXD_MODE_1) {
/* 1 buffer mode - normal operation mode */
- memset(rxdp, 0, sizeof(RxD1_t));
+ memset(rxdp, 0, sizeof(struct RxD1));
skb_reserve(skb, NET_IP_ALIGN);
- ((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single
+ ((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single
(nic->pdev, skb->data, size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
@@ -2376,7 +2301,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* payload
*/
- memset(rxdp, 0, sizeof(RxD3_t));
+ memset(rxdp, 0, sizeof(struct RxD3));
ba = &mac_control->rings[ring_no].ba[block_no][off];
skb_reserve(skb, BUF0_LEN);
tmp = (u64)(unsigned long) skb->data;
@@ -2385,13 +2310,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
skb->data = (void *) (unsigned long)tmp;
skb->tail = (void *) (unsigned long)tmp;
- if (!(((RxD3_t*)rxdp)->Buffer0_ptr))
- ((RxD3_t*)rxdp)->Buffer0_ptr =
+ if (!(((struct RxD3*)rxdp)->Buffer0_ptr))
+ ((struct RxD3*)rxdp)->Buffer0_ptr =
pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
else
pci_dma_sync_single_for_device(nic->pdev,
- (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr,
+ (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
if (nic->rxd_mode == RXD_MODE_3B) {
@@ -2401,13 +2326,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* Buffer2 will have L3/L4 header plus
* L4 payload
*/
- ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
+ ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single
(nic->pdev, skb->data, dev->mtu + 4,
PCI_DMA_FROMDEVICE);
/* Buffer-1 will be dummy buffer. Not used */
- if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) {
- ((RxD3_t*)rxdp)->Buffer1_ptr =
+ if (!(((struct RxD3*)rxdp)->Buffer1_ptr)) {
+ ((struct RxD3*)rxdp)->Buffer1_ptr =
pci_map_single(nic->pdev,
ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
@@ -2467,9 +2392,9 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
struct net_device *dev = sp->dev;
int j;
struct sk_buff *skb;
- RxD_t *rxdp;
- mac_info_t *mac_control;
- buffAdd_t *ba;
+ struct RxD_t *rxdp;
+ struct mac_info *mac_control;
+ struct buffAdd *ba;
mac_control = &sp->mac_control;
for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
@@ -2482,41 +2407,41 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
}
if (sp->rxd_mode == RXD_MODE_1) {
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD1_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD1*)rxdp)->Buffer0_ptr,
dev->mtu +
HEADER_ETHERNET_II_802_3_SIZE
+ HEADER_802_2_SIZE +
HEADER_SNAP_SIZE,
PCI_DMA_FROMDEVICE);
- memset(rxdp, 0, sizeof(RxD1_t));
+ memset(rxdp, 0, sizeof(struct RxD1));
} else if(sp->rxd_mode == RXD_MODE_3B) {
ba = &mac_control->rings[ring_no].
ba[blk][j];
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD3*)rxdp)->Buffer0_ptr,
BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
+ ((struct RxD3*)rxdp)->Buffer1_ptr,
BUF1_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr,
+ ((struct RxD3*)rxdp)->Buffer2_ptr,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
- memset(rxdp, 0, sizeof(RxD3_t));
+ memset(rxdp, 0, sizeof(struct RxD3));
} else {
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
+ ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
+ ((struct RxD3*)rxdp)->Buffer1_ptr,
l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu,
+ ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu,
PCI_DMA_FROMDEVICE);
- memset(rxdp, 0, sizeof(RxD3_t));
+ memset(rxdp, 0, sizeof(struct RxD3));
}
dev_kfree_skb(skb);
atomic_dec(&sp->rx_bufs_left[ring_no]);
@@ -2536,7 +2461,7 @@ static void free_rx_buffers(struct s2io_nic *sp)
{
struct net_device *dev = sp->dev;
int i, blk = 0, buf_cnt = 0;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &sp->mac_control;
@@ -2569,15 +2494,13 @@ static void free_rx_buffers(struct s2io_nic *sp)
* 0 on success and 1 if there are No Rx packets to be processed.
*/
-#if defined(CONFIG_S2IO_NAPI)
static int s2io_poll(struct net_device *dev, int *budget)
{
- nic_t *nic = dev->priv;
+ struct s2io_nic *nic = dev->priv;
int pkt_cnt = 0, org_pkts_to_process;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
- u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
int i;
atomic_inc(&nic->isr_cnt);
@@ -2589,8 +2512,8 @@ static int s2io_poll(struct net_device *dev, int *budget)
nic->pkts_to_process = dev->quota;
org_pkts_to_process = nic->pkts_to_process;
- writeq(val64, &bar0->rx_traffic_int);
- val64 = readl(&bar0->rx_traffic_int);
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+ readl(&bar0->rx_traffic_int);
for (i = 0; i < config->rx_ring_num; i++) {
rx_intr_handler(&mac_control->rings[i]);
@@ -2616,7 +2539,7 @@ static int s2io_poll(struct net_device *dev, int *budget)
}
/* Re enable the Rx interrupts. */
writeq(0x0, &bar0->rx_traffic_mask);
- val64 = readl(&bar0->rx_traffic_mask);
+ readl(&bar0->rx_traffic_mask);
atomic_dec(&nic->isr_cnt);
return 0;
@@ -2634,7 +2557,6 @@ no_rx:
atomic_dec(&nic->isr_cnt);
return 1;
}
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
/**
@@ -2648,10 +2570,10 @@ no_rx:
*/
static void s2io_netpoll(struct net_device *dev)
{
- nic_t *nic = dev->priv;
- mac_info_t *mac_control;
+ struct s2io_nic *nic = dev->priv;
+ struct mac_info *mac_control;
struct config_param *config;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
int i;
@@ -2700,17 +2622,15 @@ static void s2io_netpoll(struct net_device *dev)
* Return Value:
* NONE.
*/
-static void rx_intr_handler(ring_info_t *ring_data)
+static void rx_intr_handler(struct ring_info *ring_data)
{
- nic_t *nic = ring_data->nic;
+ struct s2io_nic *nic = ring_data->nic;
struct net_device *dev = (struct net_device *) nic->dev;
int get_block, put_block, put_offset;
- rx_curr_get_info_t get_info, put_info;
- RxD_t *rxdp;
+ struct rx_curr_get_info get_info, put_info;
+ struct RxD_t *rxdp;
struct sk_buff *skb;
-#ifndef CONFIG_S2IO_NAPI
int pkt_cnt = 0;
-#endif
int i;
spin_lock(&nic->rx_lock);
@@ -2723,19 +2643,21 @@ static void rx_intr_handler(ring_info_t *ring_data)
get_info = ring_data->rx_curr_get_info;
get_block = get_info.block_index;
- put_info = ring_data->rx_curr_put_info;
+ memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
put_block = put_info.block_index;
rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
-#ifndef CONFIG_S2IO_NAPI
- spin_lock(&nic->put_lock);
- put_offset = ring_data->put_pos;
- spin_unlock(&nic->put_lock);
-#else
- put_offset = (put_block * (rxd_count[nic->rxd_mode] + 1)) +
- put_info.offset;
-#endif
+ if (!napi) {
+ spin_lock(&nic->put_lock);
+ put_offset = ring_data->put_pos;
+ spin_unlock(&nic->put_lock);
+ } else
+ put_offset = ring_data->put_pos;
+
while (RXD_IS_UP2DT(rxdp)) {
- /* If your are next to put index then it's FIFO full condition */
+ /*
+ * If your are next to put index then it's
+ * FIFO full condition
+ */
if ((get_block == put_block) &&
(get_info.offset + 1) == put_info.offset) {
DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
@@ -2751,7 +2673,7 @@ static void rx_intr_handler(ring_info_t *ring_data)
}
if (nic->rxd_mode == RXD_MODE_1) {
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD1_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD1*)rxdp)->Buffer0_ptr,
dev->mtu +
HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE +
@@ -2759,22 +2681,22 @@ static void rx_intr_handler(ring_info_t *ring_data)
PCI_DMA_FROMDEVICE);
} else if (nic->rxd_mode == RXD_MODE_3B) {
pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD3*)rxdp)->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr,
+ ((struct RxD3*)rxdp)->Buffer2_ptr,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
} else {
pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
+ ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
+ ((struct RxD3*)rxdp)->Buffer1_ptr,
l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr,
+ ((struct RxD3*)rxdp)->Buffer2_ptr,
dev->mtu, PCI_DMA_FROMDEVICE);
}
prefetch(skb->data);
@@ -2793,20 +2715,17 @@ static void rx_intr_handler(ring_info_t *ring_data)
rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
}
-#ifdef CONFIG_S2IO_NAPI
nic->pkts_to_process -= 1;
- if (!nic->pkts_to_process)
+ if ((napi) && (!nic->pkts_to_process))
break;
-#else
pkt_cnt++;
if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
break;
-#endif
}
if (nic->lro) {
/* Clear all LRO sessions before exiting */
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- lro_t *lro = &nic->lro0_n[i];
+ struct lro *lro = &nic->lro0_n[i];
if (lro->in_use) {
update_L3L4_header(nic, lro);
queue_rx_frame(lro->parent);
@@ -2830,17 +2749,17 @@ static void rx_intr_handler(ring_info_t *ring_data)
* NONE
*/
-static void tx_intr_handler(fifo_info_t *fifo_data)
+static void tx_intr_handler(struct fifo_info *fifo_data)
{
- nic_t *nic = fifo_data->nic;
+ struct s2io_nic *nic = fifo_data->nic;
struct net_device *dev = (struct net_device *) nic->dev;
- tx_curr_get_info_t get_info, put_info;
+ struct tx_curr_get_info get_info, put_info;
struct sk_buff *skb;
- TxD_t *txdlp;
+ struct TxD *txdlp;
get_info = fifo_data->tx_curr_get_info;
- put_info = fifo_data->tx_curr_put_info;
- txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
+ memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info));
+ txdlp = (struct TxD *) fifo_data->list_info[get_info.offset].
list_virt_addr;
while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
(get_info.offset != put_info.offset) &&
@@ -2855,11 +2774,10 @@ static void tx_intr_handler(fifo_info_t *fifo_data)
}
if ((err >> 48) == 0xA) {
DBG_PRINT(TX_DBG, "TxD returned due \
-to loss of link\n");
+ to loss of link\n");
}
else {
- DBG_PRINT(ERR_DBG, "***TxD error \
-%llx\n", err);
+ DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err);
}
}
@@ -2878,7 +2796,7 @@ to loss of link\n");
get_info.offset++;
if (get_info.offset == get_info.fifo_len + 1)
get_info.offset = 0;
- txdlp = (TxD_t *) fifo_data->list_info
+ txdlp = (struct TxD *) fifo_data->list_info
[get_info.offset].list_virt_addr;
fifo_data->tx_curr_get_info.offset =
get_info.offset;
@@ -2903,8 +2821,8 @@ to loss of link\n");
static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
{
u64 val64 = 0x0;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
//address transaction
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -2952,8 +2870,8 @@ 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 __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
/* address transaction */
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -3056,8 +2974,8 @@ static void s2io_updt_xpak_counter(struct net_device *dev)
u64 val64 = 0x0;
u64 addr = 0x0;
- nic_t *sp = dev->priv;
- StatInfo_t *stat_info = sp->mac_control.stats_info;
+ struct s2io_nic *sp = dev->priv;
+ struct stat_block *stat_info = sp->mac_control.stats_info;
/* Check the communication with the MDIO slave */
addr = 0x0000;
@@ -3155,10 +3073,12 @@ static void s2io_updt_xpak_counter(struct net_device *dev)
static void alarm_intr_handler(struct s2io_nic *nic)
{
struct net_device *dev = (struct net_device *) nic->dev;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0, err_reg = 0;
u64 cnt;
int i;
+ if (atomic_read(&nic->card_state) == CARD_DOWN)
+ return;
nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
/* Handling the XPAK counters update */
if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
@@ -3298,6 +3218,25 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
}
return ret;
}
+/*
+ * check_pci_device_id - Checks if the device id is supported
+ * @id : device id
+ * Description: Function to check if the pci device id is supported by driver.
+ * Return value: Actual device id if supported else PCI_ANY_ID
+ */
+static u16 check_pci_device_id(u16 id)
+{
+ switch (id) {
+ case PCI_DEVICE_ID_HERC_WIN:
+ case PCI_DEVICE_ID_HERC_UNI:
+ return XFRAME_II_DEVICE;
+ case PCI_DEVICE_ID_S2IO_UNI:
+ case PCI_DEVICE_ID_S2IO_WIN:
+ return XFRAME_I_DEVICE;
+ default:
+ return PCI_ANY_ID;
+ }
+}
/**
* s2io_reset - Resets the card.
@@ -3309,42 +3248,57 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
* void.
*/
-static void s2io_reset(nic_t * sp)
+static void s2io_reset(struct s2io_nic * sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
u16 subid, pci_cmd;
+ int i;
+ u16 val16;
+ DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
+ __FUNCTION__, sp->dev->name);
/* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
+ if (sp->device_type == XFRAME_II_DEVICE) {
+ int ret;
+ ret = pci_set_power_state(sp->pdev, 3);
+ if (!ret)
+ ret = pci_set_power_state(sp->pdev, 0);
+ else {
+ DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n",
+ __FUNCTION__);
+ goto old_way;
+ }
+ msleep(20);
+ goto new_way;
+ }
+old_way:
val64 = SW_RESET_ALL;
writeq(val64, &bar0->sw_reset);
-
- /*
- * At this stage, if the PCI write is indeed completed, the
- * card is reset and so is the PCI Config space of the device.
- * So a read cannot be issued at this stage on any of the
- * registers to ensure the write into "sw_reset" register
- * has gone through.
- * Question: Is there any system call that will explicitly force
- * all the write commands still pending on the bus to be pushed
- * through?
- * As of now I'am just giving a 250ms delay and hoping that the
- * PCI write to sw_reset register is done by this time.
- */
- msleep(250);
+new_way:
if (strstr(sp->product_name, "CX4")) {
msleep(750);
}
+ msleep(250);
+ for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) {
- /* Restore the PCI state saved during initialization. */
- pci_restore_state(sp->pdev);
- pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
- pci_cmd);
- s2io_init_pci(sp);
+ /* Restore the PCI state saved during initialization. */
+ pci_restore_state(sp->pdev);
+ pci_read_config_word(sp->pdev, 0x2, &val16);
+ if (check_pci_device_id(val16) != (u16)PCI_ANY_ID)
+ break;
+ msleep(200);
+ }
- msleep(250);
+ if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) {
+ DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__);
+ }
+
+ pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd);
+
+ s2io_init_pci(sp);
/* Set swapper to enable I/O register access */
s2io_set_swapper(sp);
@@ -3400,10 +3354,10 @@ static void s2io_reset(nic_t * sp)
* SUCCESS on success and FAILURE on failure.
*/
-static int s2io_set_swapper(nic_t * sp)
+static int s2io_set_swapper(struct s2io_nic * sp)
{
struct net_device *dev = sp->dev;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64, valt, valr;
/*
@@ -3528,9 +3482,9 @@ static int s2io_set_swapper(nic_t * sp)
return SUCCESS;
}
-static int wait_for_msix_trans(nic_t *nic, int i)
+static int wait_for_msix_trans(struct s2io_nic *nic, int i)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64;
int ret = 0, cnt = 0;
@@ -3549,9 +3503,9 @@ static int wait_for_msix_trans(nic_t *nic, int i)
return ret;
}
-static void restore_xmsi_data(nic_t *nic)
+static void restore_xmsi_data(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64;
int i;
@@ -3567,9 +3521,9 @@ static void restore_xmsi_data(nic_t *nic)
}
}
-static void store_xmsi_data(nic_t *nic)
+static void store_xmsi_data(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64, addr, data;
int i;
@@ -3590,9 +3544,9 @@ static void store_xmsi_data(nic_t *nic)
}
}
-int s2io_enable_msi(nic_t *nic)
+int s2io_enable_msi(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u16 msi_ctrl, msg_val;
struct config_param *config = &nic->config;
struct net_device *dev = nic->dev;
@@ -3640,9 +3594,9 @@ int s2io_enable_msi(nic_t *nic)
return 0;
}
-static int s2io_enable_msi_x(nic_t *nic)
+static int s2io_enable_msi_x(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 tx_mat, rx_mat;
u16 msi_control; /* Temp variable */
int ret, i, j, msix_indx = 1;
@@ -3750,7 +3704,7 @@ static int s2io_enable_msi_x(nic_t *nic)
static int s2io_open(struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
int err = 0;
/*
@@ -3803,7 +3757,7 @@ hw_init_failed:
static int s2io_close(struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
flush_scheduled_work();
netif_stop_queue(dev);
@@ -3829,15 +3783,15 @@ static int s2io_close(struct net_device *dev)
static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
register u64 val64;
- TxD_t *txdp;
- TxFIFO_element_t __iomem *tx_fifo;
+ struct TxD *txdp;
+ struct TxFIFO_element __iomem *tx_fifo;
unsigned long flags;
u16 vlan_tag = 0;
int vlan_priority = 0;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int offload_type;
@@ -3865,7 +3819,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
- txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
+ txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off].
list_virt_addr;
queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
@@ -3888,12 +3842,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
}
offload_type = s2io_offload_type(skb);
-#ifdef NETIF_F_TSO
if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
txdp->Control_1 |= TXD_TCP_LSO_EN;
txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
}
-#endif
if (skb->ip_summed == CHECKSUM_PARTIAL) {
txdp->Control_2 |=
(TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
@@ -3994,13 +3946,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
static void
s2io_alarm_handle(unsigned long data)
{
- nic_t *sp = (nic_t *)data;
+ struct s2io_nic *sp = (struct s2io_nic *)data;
alarm_intr_handler(sp);
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
-static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
+static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
{
int rxb_size, level;
@@ -4032,9 +3984,9 @@ static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
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;
+ struct s2io_nic *sp = dev->priv;
int i;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
atomic_inc(&sp->isr_cnt);
@@ -4064,8 +4016,8 @@ static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
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;
+ struct ring_info *ring = (struct ring_info *)dev_id;
+ struct s2io_nic *sp = ring->nic;
atomic_inc(&sp->isr_cnt);
@@ -4078,17 +4030,17 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
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;
+ struct fifo_info *fifo = (struct fifo_info *)dev_id;
+ struct s2io_nic *sp = fifo->nic;
atomic_inc(&sp->isr_cnt);
tx_intr_handler(fifo);
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
-static void s2io_txpic_intr_handle(nic_t *sp)
+static void s2io_txpic_intr_handle(struct s2io_nic *sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
val64 = readq(&bar0->pic_int_status);
@@ -4110,39 +4062,33 @@ static void s2io_txpic_intr_handle(nic_t *sp)
}
else if (val64 & GPIO_INT_REG_LINK_UP) {
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(sp, val64,
- sp->device_enabled_once)) {
/* Enable Adapter */
- val64 = readq(&bar0->adapter_control);
- val64 |= ADAPTER_CNTL_EN;
- writeq(val64, &bar0->adapter_control);
- val64 |= ADAPTER_LED_ON;
- writeq(val64, &bar0->adapter_control);
- if (!sp->device_enabled_once)
- sp->device_enabled_once = 1;
+ val64 = readq(&bar0->adapter_control);
+ val64 |= ADAPTER_CNTL_EN;
+ writeq(val64, &bar0->adapter_control);
+ val64 |= ADAPTER_LED_ON;
+ writeq(val64, &bar0->adapter_control);
+ if (!sp->device_enabled_once)
+ sp->device_enabled_once = 1;
- s2io_link(sp, LINK_UP);
- /*
- * unmask link down interrupt and mask link-up
- * intr
- */
- val64 = readq(&bar0->gpio_int_mask);
- val64 &= ~GPIO_INT_MASK_LINK_DOWN;
- val64 |= GPIO_INT_MASK_LINK_UP;
- writeq(val64, &bar0->gpio_int_mask);
+ s2io_link(sp, LINK_UP);
+ /*
+ * unmask link down interrupt and mask link-up
+ * intr
+ */
+ val64 = readq(&bar0->gpio_int_mask);
+ val64 &= ~GPIO_INT_MASK_LINK_DOWN;
+ val64 |= GPIO_INT_MASK_LINK_UP;
+ writeq(val64, &bar0->gpio_int_mask);
- }
}else if (val64 & GPIO_INT_REG_LINK_DOWN) {
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(sp, val64,
- sp->device_enabled_once)) {
- s2io_link(sp, LINK_DOWN);
- /* Link is down so unmaks link up interrupt */
- val64 = readq(&bar0->gpio_int_mask);
- val64 &= ~GPIO_INT_MASK_LINK_UP;
- val64 |= GPIO_INT_MASK_LINK_DOWN;
- writeq(val64, &bar0->gpio_int_mask);
- }
+ s2io_link(sp, LINK_DOWN);
+ /* Link is down so unmaks link up interrupt */
+ val64 = readq(&bar0->gpio_int_mask);
+ val64 &= ~GPIO_INT_MASK_LINK_UP;
+ val64 |= GPIO_INT_MASK_LINK_DOWN;
+ writeq(val64, &bar0->gpio_int_mask);
}
}
val64 = readq(&bar0->gpio_int_mask);
@@ -4164,11 +4110,11 @@ static void s2io_txpic_intr_handle(nic_t *sp)
static irqreturn_t s2io_isr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
int i;
- u64 reason = 0, val64, org_mask;
- mac_info_t *mac_control;
+ u64 reason = 0;
+ struct mac_info *mac_control;
struct config_param *config;
atomic_inc(&sp->isr_cnt);
@@ -4186,43 +4132,48 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
reason = readq(&bar0->general_int_status);
if (!reason) {
- /* The interrupt was not raised by Xena. */
+ /* The interrupt was not raised by us. */
+ atomic_dec(&sp->isr_cnt);
+ return IRQ_NONE;
+ }
+ else if (unlikely(reason == S2IO_MINUS_ONE) ) {
+ /* Disable device and get out */
atomic_dec(&sp->isr_cnt);
return IRQ_NONE;
}
- val64 = 0xFFFFFFFFFFFFFFFFULL;
- /* Store current mask before masking all interrupts */
- org_mask = readq(&bar0->general_int_mask);
- writeq(val64, &bar0->general_int_mask);
+ if (napi) {
+ if (reason & GEN_INTR_RXTRAFFIC) {
+ if ( likely ( netif_rx_schedule_prep(dev)) ) {
+ __netif_rx_schedule(dev);
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
+ }
+ else
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+ }
+ } else {
+ /*
+ * Rx handler is called by default, without checking for the
+ * cause of interrupt.
+ * rx_traffic_int reg is an R1 register, writing all 1's
+ * will ensure that the actual interrupt causing bit get's
+ * cleared and hence a read can be avoided.
+ */
+ if (reason & GEN_INTR_RXTRAFFIC)
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
-#ifdef CONFIG_S2IO_NAPI
- if (reason & GEN_INTR_RXTRAFFIC) {
- if (netif_rx_schedule_prep(dev)) {
- writeq(val64, &bar0->rx_traffic_mask);
- __netif_rx_schedule(dev);
+ for (i = 0; i < config->rx_ring_num; i++) {
+ rx_intr_handler(&mac_control->rings[i]);
}
}
-#else
- /*
- * Rx handler is called by default, without checking for the
- * cause of interrupt.
- * rx_traffic_int reg is an R1 register, writing all 1's
- * will ensure that the actual interrupt causing bit get's
- * cleared and hence a read can be avoided.
- */
- writeq(val64, &bar0->rx_traffic_int);
- for (i = 0; i < config->rx_ring_num; i++) {
- rx_intr_handler(&mac_control->rings[i]);
- }
-#endif
/*
* tx_traffic_int reg is an R1 register, writing all 1's
* will ensure that the actual interrupt causing bit get's
* cleared and hence a read can be avoided.
*/
- writeq(val64, &bar0->tx_traffic_int);
+ if (reason & GEN_INTR_TXTRAFFIC)
+ writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
for (i = 0; i < config->tx_fifo_num; i++)
tx_intr_handler(&mac_control->fifos[i]);
@@ -4234,11 +4185,14 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
* reallocate the buffers from the interrupt handler itself,
* else schedule a tasklet to reallocate the buffers.
*/
-#ifndef CONFIG_S2IO_NAPI
- for (i = 0; i < config->rx_ring_num; i++)
- s2io_chk_rx_buffers(sp, i);
-#endif
- writeq(org_mask, &bar0->general_int_mask);
+ if (!napi) {
+ for (i = 0; i < config->rx_ring_num; i++)
+ s2io_chk_rx_buffers(sp, i);
+ }
+
+ writeq(0, &bar0->general_int_mask);
+ readl(&bar0->general_int_status);
+
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
@@ -4246,9 +4200,9 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
/**
* s2io_updt_stats -
*/
-static void s2io_updt_stats(nic_t *sp)
+static void s2io_updt_stats(struct s2io_nic *sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
int cnt = 0;
@@ -4267,7 +4221,7 @@ static void s2io_updt_stats(nic_t *sp)
break; /* Updt failed */
} while(1);
} else {
- memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t));
+ memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
}
}
@@ -4283,8 +4237,8 @@ static void s2io_updt_stats(nic_t *sp)
static struct net_device_stats *s2io_get_stats(struct net_device *dev)
{
- nic_t *sp = dev->priv;
- mac_info_t *mac_control;
+ struct s2io_nic *sp = dev->priv;
+ struct mac_info *mac_control;
struct config_param *config;
@@ -4325,8 +4279,8 @@ static void s2io_set_multicast(struct net_device *dev)
{
int i, j, prev_cnt;
struct dev_mc_list *mclist;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
0xfeffffffffffULL;
u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
@@ -4479,8 +4433,8 @@ static void s2io_set_multicast(struct net_device *dev)
static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
{
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
register u64 val64, mac_addr = 0;
int i;
@@ -4526,7 +4480,7 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
static int s2io_ethtool_sset(struct net_device *dev,
struct ethtool_cmd *info)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if ((info->autoneg == AUTONEG_ENABLE) ||
(info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
return -EINVAL;
@@ -4552,7 +4506,7 @@ static int s2io_ethtool_sset(struct net_device *dev,
static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
info->port = PORT_FIBRE;
@@ -4585,7 +4539,7 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
static void s2io_ethtool_gdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
strncpy(info->version, s2io_driver_version, sizeof(info->version));
@@ -4617,7 +4571,7 @@ static void s2io_ethtool_gregs(struct net_device *dev,
int i;
u64 reg;
u8 *reg_space = (u8 *) space;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
regs->len = XENA_REG_SPACE;
regs->version = sp->pdev->subsystem_device;
@@ -4639,8 +4593,8 @@ static void s2io_ethtool_gregs(struct net_device *dev,
*/
static void s2io_phy_id(unsigned long data)
{
- nic_t *sp = (nic_t *) data;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = (struct s2io_nic *) data;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = 0;
u16 subid;
@@ -4677,8 +4631,8 @@ static void s2io_phy_id(unsigned long data)
static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
{
u64 val64 = 0, last_gpio_ctrl_val;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u16 subid;
subid = sp->pdev->subsystem_device;
@@ -4726,8 +4680,8 @@ static void s2io_ethtool_getpause_data(struct net_device *dev,
struct ethtool_pauseparam *ep)
{
u64 val64;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
val64 = readq(&bar0->rmac_pause_cfg);
if (val64 & RMAC_PAUSE_GEN_ENABLE)
@@ -4753,8 +4707,8 @@ static int s2io_ethtool_setpause_data(struct net_device *dev,
struct ethtool_pauseparam *ep)
{
u64 val64;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
val64 = readq(&bar0->rmac_pause_cfg);
if (ep->tx_pause)
@@ -4786,12 +4740,12 @@ static int s2io_ethtool_setpause_data(struct net_device *dev,
*/
#define S2IO_DEV_ID 5
-static int read_eeprom(nic_t * sp, int off, u64 * data)
+static int read_eeprom(struct s2io_nic * sp, int off, u64 * data)
{
int ret = -1;
u32 exit_cnt = 0;
u64 val64;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
if (sp->device_type == XFRAME_I_DEVICE) {
val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
@@ -4851,11 +4805,11 @@ static int read_eeprom(nic_t * sp, int off, u64 * data)
* 0 on success, -1 on failure.
*/
-static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
+static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt)
{
int exit_cnt = 0, ret = -1;
u64 val64;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
if (sp->device_type == XFRAME_I_DEVICE) {
val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
@@ -4900,7 +4854,7 @@ static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
}
return ret;
}
-static void s2io_vpd_read(nic_t *nic)
+static void s2io_vpd_read(struct s2io_nic *nic)
{
u8 *vpd_data;
u8 data;
@@ -4915,6 +4869,7 @@ static void s2io_vpd_read(nic_t *nic)
strcpy(nic->product_name, "Xframe I 10GbE network adapter");
vpd_addr = 0x50;
}
+ strcpy(nic->serial_num, "NOT AVAILABLE");
vpd_data = kmalloc(256, GFP_KERNEL);
if (!vpd_data)
@@ -4938,7 +4893,22 @@ static void s2io_vpd_read(nic_t *nic)
pci_read_config_dword(nic->pdev, (vpd_addr + 4),
(u32 *)&vpd_data[i]);
}
- if ((!fail) && (vpd_data[1] < VPD_PRODUCT_NAME_LEN)) {
+
+ if(!fail) {
+ /* read serial number of adapter */
+ for (cnt = 0; cnt < 256; cnt++) {
+ if ((vpd_data[cnt] == 'S') &&
+ (vpd_data[cnt+1] == 'N') &&
+ (vpd_data[cnt+2] < VPD_STRING_LEN)) {
+ memset(nic->serial_num, 0, VPD_STRING_LEN);
+ memcpy(nic->serial_num, &vpd_data[cnt + 3],
+ vpd_data[cnt+2]);
+ break;
+ }
+ }
+ }
+
+ if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
memset(nic->product_name, 0, vpd_data[1]);
memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
}
@@ -4963,7 +4933,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev,
{
u32 i, valid;
u64 data;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
@@ -5001,7 +4971,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev,
{
int len = eeprom->len, cnt = 0;
u64 valid = 0, data;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
DBG_PRINT(ERR_DBG,
@@ -5045,9 +5015,9 @@ static int s2io_ethtool_seeprom(struct net_device *dev,
* 0 on success.
*/
-static int s2io_register_test(nic_t * sp, uint64_t * data)
+static int s2io_register_test(struct s2io_nic * sp, uint64_t * data)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = 0, exp_val;
int fail = 0;
@@ -5112,7 +5082,7 @@ static int s2io_register_test(nic_t * sp, uint64_t * data)
* 0 on success.
*/
-static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
+static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data)
{
int fail = 0;
u64 ret_data, org_4F0, org_7F0;
@@ -5214,7 +5184,7 @@ static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
* 0 on success and -1 on failure.
*/
-static int s2io_bist_test(nic_t * sp, uint64_t * data)
+static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data)
{
u8 bist = 0;
int cnt = 0, ret = -1;
@@ -5250,9 +5220,9 @@ static int s2io_bist_test(nic_t * sp, uint64_t * data)
* 0 on success.
*/
-static int s2io_link_test(nic_t * sp, uint64_t * data)
+static int s2io_link_test(struct s2io_nic * sp, uint64_t * data)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
val64 = readq(&bar0->adapter_status);
@@ -5277,9 +5247,9 @@ static int s2io_link_test(nic_t * sp, uint64_t * data)
* 0 on success.
*/
-static int s2io_rldram_test(nic_t * sp, uint64_t * data)
+static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
int cnt, iteration = 0, test_fail = 0;
@@ -5381,7 +5351,7 @@ static void s2io_ethtool_test(struct net_device *dev,
struct ethtool_test *ethtest,
uint64_t * data)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
int orig_state = netif_running(sp->dev);
if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
@@ -5437,8 +5407,8 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
u64 * tmp_stats)
{
int i = 0;
- nic_t *sp = dev->priv;
- StatInfo_t *stat_info = sp->mac_control.stats_info;
+ struct s2io_nic *sp = dev->priv;
+ struct stat_block *stat_info = sp->mac_control.stats_info;
s2io_updt_stats(sp);
tmp_stats[i++] =
@@ -5665,14 +5635,14 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev)
static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
return (sp->rx_csum);
}
static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if (data)
sp->rx_csum = 1;
@@ -5751,10 +5721,8 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.set_tx_csum = s2io_ethtool_op_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
.get_tso = s2io_ethtool_op_get_tso,
.set_tso = s2io_ethtool_op_set_tso,
-#endif
.get_ufo = ethtool_op_get_ufo,
.set_ufo = ethtool_op_set_ufo,
.self_test_count = s2io_ethtool_self_test_count,
@@ -5795,7 +5763,7 @@ static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static int s2io_change_mtu(struct net_device *dev, int new_mtu)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
@@ -5814,7 +5782,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
} else { /* Device is down */
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = new_mtu;
writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
@@ -5839,9 +5807,9 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
static void s2io_tasklet(unsigned long dev_addr)
{
struct net_device *dev = (struct net_device *) dev_addr;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
int i, ret;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &sp->mac_control;
@@ -5874,9 +5842,9 @@ static void s2io_tasklet(unsigned long dev_addr)
static void s2io_set_link(struct work_struct *work)
{
- nic_t *nic = container_of(work, nic_t, set_link_task);
+ struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task);
struct net_device *dev = nic->dev;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64;
u16 subid;
@@ -5895,57 +5863,53 @@ static void s2io_set_link(struct work_struct *work)
}
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
- if (LINK_IS_UP(val64)) {
- val64 = readq(&bar0->adapter_control);
- val64 |= ADAPTER_CNTL_EN;
- writeq(val64, &bar0->adapter_control);
- if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
- subid)) {
- val64 = readq(&bar0->gpio_control);
- val64 |= GPIO_CTRL_GPIO_0;
- writeq(val64, &bar0->gpio_control);
- val64 = readq(&bar0->gpio_control);
- } else {
- val64 |= ADAPTER_LED_ON;
+ if (LINK_IS_UP(val64)) {
+ if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) {
+ if (verify_xena_quiescence(nic)) {
+ val64 = readq(&bar0->adapter_control);
+ val64 |= ADAPTER_CNTL_EN;
writeq(val64, &bar0->adapter_control);
- }
- if (s2io_link_fault_indication(nic) ==
- MAC_RMAC_ERR_TIMER) {
- val64 = readq(&bar0->adapter_status);
- if (!LINK_IS_UP(val64)) {
- DBG_PRINT(ERR_DBG, "%s:", dev->name);
- DBG_PRINT(ERR_DBG, " Link down");
- DBG_PRINT(ERR_DBG, "after ");
- DBG_PRINT(ERR_DBG, "enabling ");
- DBG_PRINT(ERR_DBG, "device \n");
+ if (CARDS_WITH_FAULTY_LINK_INDICATORS(
+ nic->device_type, subid)) {
+ val64 = readq(&bar0->gpio_control);
+ val64 |= GPIO_CTRL_GPIO_0;
+ writeq(val64, &bar0->gpio_control);
+ val64 = readq(&bar0->gpio_control);
+ } else {
+ val64 |= ADAPTER_LED_ON;
+ writeq(val64, &bar0->adapter_control);
}
- }
- if (nic->device_enabled_once == FALSE) {
nic->device_enabled_once = TRUE;
+ } else {
+ DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
+ DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
+ netif_stop_queue(dev);
}
+ }
+ val64 = readq(&bar0->adapter_status);
+ if (!LINK_IS_UP(val64)) {
+ DBG_PRINT(ERR_DBG, "%s:", dev->name);
+ DBG_PRINT(ERR_DBG, " Link down after enabling ");
+ DBG_PRINT(ERR_DBG, "device \n");
+ } else
s2io_link(nic, LINK_UP);
- } else {
- if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
- subid)) {
- val64 = readq(&bar0->gpio_control);
- val64 &= ~GPIO_CTRL_GPIO_0;
- writeq(val64, &bar0->gpio_control);
- val64 = readq(&bar0->gpio_control);
- }
- s2io_link(nic, LINK_DOWN);
+ } else {
+ if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
+ subid)) {
+ val64 = readq(&bar0->gpio_control);
+ val64 &= ~GPIO_CTRL_GPIO_0;
+ writeq(val64, &bar0->gpio_control);
+ val64 = readq(&bar0->gpio_control);
}
- } else { /* NIC is not Quiescent. */
- DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
- DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
- netif_stop_queue(dev);
+ s2io_link(nic, LINK_DOWN);
}
clear_bit(0, &(nic->link_state));
}
-static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
- struct sk_buff **skb, u64 *temp0, u64 *temp1,
- u64 *temp2, int size)
+static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
+ struct buffAdd *ba,
+ struct sk_buff **skb, u64 *temp0, u64 *temp1,
+ u64 *temp2, int size)
{
struct net_device *dev = sp->dev;
struct sk_buff *frag_list;
@@ -5959,7 +5923,7 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
* using same mapped address for the Rxd
* buffer pointer
*/
- ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0;
+ ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
@@ -5971,7 +5935,7 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
* such it will be used for next rxd whose
* Host Control is NULL
*/
- ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0 =
+ ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0 =
pci_map_single( sp->pdev, (*skb)->data,
size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
@@ -5980,36 +5944,36 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
} else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
/* Two buffer Mode */
if (*skb) {
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
- dev->name);
+ dev->name);
return -ENOMEM;
}
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
pci_map_single(sp->pdev, (*skb)->data,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
rxdp->Host_Control = (unsigned long) (*skb);
/* Buffer-1 will be dummy buffer not used */
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
}
} else if ((rxdp->Host_Control == 0)) {
/* Three buffer mode */
if (*skb) {
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
@@ -6017,11 +5981,11 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
dev->name);
return -ENOMEM;
}
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
/* Buffer-1 receives L3/L4 headers */
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
pci_map_single( sp->pdev, (*skb)->data,
l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
@@ -6041,14 +6005,15 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
/*
* Buffer-2 receives L4 data payload
*/
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
pci_map_single( sp->pdev, frag_list->data,
dev->mtu, PCI_DMA_FROMDEVICE);
}
}
return 0;
}
-static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
+static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp,
+ int size)
{
struct net_device *dev = sp->dev;
if (sp->rxd_mode == RXD_MODE_1) {
@@ -6064,15 +6029,15 @@ static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
}
}
-static int rxd_owner_bit_reset(nic_t *sp)
+static int rxd_owner_bit_reset(struct s2io_nic *sp)
{
int i, j, k, blk_cnt = 0, size;
- mac_info_t * mac_control = &sp->mac_control;
+ struct mac_info * mac_control = &sp->mac_control;
struct config_param *config = &sp->config;
struct net_device *dev = sp->dev;
- RxD_t *rxdp = NULL;
+ struct RxD_t *rxdp = NULL;
struct sk_buff *skb = NULL;
- buffAdd_t *ba = NULL;
+ struct buffAdd *ba = NULL;
u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
/* Calculate the size based on ring mode */
@@ -6111,7 +6076,7 @@ static int rxd_owner_bit_reset(nic_t *sp)
}
-static int s2io_add_isr(nic_t * sp)
+static int s2io_add_isr(struct s2io_nic * sp)
{
int ret = 0;
struct net_device *dev = sp->dev;
@@ -6126,7 +6091,7 @@ static int s2io_add_isr(nic_t * sp)
sp->intr_type = INTA;
}
- /* Store the values of the MSIX table in the nic_t structure */
+ /* Store the values of the MSIX table in the struct s2io_nic structure */
store_xmsi_data(sp);
/* After proper initialization of H/W, register ISR */
@@ -6181,7 +6146,7 @@ static int s2io_add_isr(nic_t * sp)
}
return 0;
}
-static void s2io_rem_isr(nic_t * sp)
+static void s2io_rem_isr(struct s2io_nic * sp)
{
int cnt = 0;
struct net_device *dev = sp->dev;
@@ -6223,10 +6188,10 @@ static void s2io_rem_isr(nic_t * sp)
} while(cnt < 5);
}
-static void s2io_card_down(nic_t * sp)
+static void s2io_card_down(struct s2io_nic * sp)
{
int cnt = 0;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
unsigned long flags;
register u64 val64 = 0;
@@ -6257,7 +6222,8 @@ static void s2io_card_down(nic_t * sp)
rxd_owner_bit_reset(sp);
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
+ if (verify_xena_quiescence(sp)) {
+ if(verify_pcc_quiescent(sp, sp->device_enabled_once))
break;
}
@@ -6286,10 +6252,10 @@ static void s2io_card_down(nic_t * sp)
clear_bit(0, &(sp->link_state));
}
-static int s2io_card_up(nic_t * sp)
+static int s2io_card_up(struct s2io_nic * sp)
{
int i, ret = 0;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
struct net_device *dev = (struct net_device *) sp->dev;
u16 interruptible;
@@ -6320,6 +6286,13 @@ static int s2io_card_up(nic_t * sp)
DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
atomic_read(&sp->rx_bufs_left[i]));
}
+ /* Maintain the state prior to the open */
+ if (sp->promisc_flg)
+ sp->promisc_flg = 0;
+ if (sp->m_cast_flg) {
+ sp->m_cast_flg = 0;
+ sp->all_multi_pos= 0;
+ }
/* Setting its receive mode */
s2io_set_multicast(dev);
@@ -6381,7 +6354,7 @@ static int s2io_card_up(nic_t * sp)
static void s2io_restart_nic(struct work_struct *work)
{
- nic_t *sp = container_of(work, nic_t, rst_timer_task);
+ struct s2io_nic *sp = container_of(work, struct s2io_nic, rst_timer_task);
struct net_device *dev = sp->dev;
s2io_card_down(sp);
@@ -6410,7 +6383,7 @@ static void s2io_restart_nic(struct work_struct *work)
static void s2io_tx_watchdog(struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if (netif_carrier_ok(dev)) {
schedule_work(&sp->rst_timer_task);
@@ -6435,16 +6408,16 @@ static void s2io_tx_watchdog(struct net_device *dev)
* Return value:
* SUCCESS on success and -1 on failure.
*/
-static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
+static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
{
- nic_t *sp = ring_data->nic;
+ struct s2io_nic *sp = ring_data->nic;
struct net_device *dev = (struct net_device *) sp->dev;
struct sk_buff *skb = (struct sk_buff *)
((unsigned long) rxdp->Host_Control);
int ring_no = ring_data->ring_no;
u16 l3_csum, l4_csum;
unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
- lro_t *lro;
+ struct lro *lro;
skb->dev = dev;
@@ -6489,7 +6462,7 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
unsigned char *buff = skb_push(skb, buf0_len);
- buffAdd_t *ba = &ring_data->ba[get_block][get_off];
+ struct buffAdd *ba = &ring_data->ba[get_block][get_off];
sp->stats.rx_bytes += buf0_len + buf2_len;
memcpy(buff, ba->ba_0, buf0_len);
@@ -6499,7 +6472,6 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
skb_put(skb, buf1_len);
skb->len += buf2_len;
skb->data_len += buf2_len;
- skb->truesize += buf2_len;
skb_put(skb_shinfo(skb)->frag_list, buf2_len);
sp->stats.rx_bytes += buf1_len;
@@ -6583,23 +6555,20 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
if (!sp->lro) {
skb->protocol = eth_type_trans(skb, dev);
-#ifdef CONFIG_S2IO_NAPI
- if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
- /* Queueing the vlan frame to the upper layer */
- vlan_hwaccel_receive_skb(skb, sp->vlgrp,
- RXD_GET_VLAN_TAG(rxdp->Control_2));
- } else {
- netif_receive_skb(skb);
- }
-#else
if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
/* Queueing the vlan frame to the upper layer */
- vlan_hwaccel_rx(skb, sp->vlgrp,
- RXD_GET_VLAN_TAG(rxdp->Control_2));
+ if (napi)
+ vlan_hwaccel_receive_skb(skb, sp->vlgrp,
+ RXD_GET_VLAN_TAG(rxdp->Control_2));
+ else
+ vlan_hwaccel_rx(skb, sp->vlgrp,
+ RXD_GET_VLAN_TAG(rxdp->Control_2));
} else {
- netif_rx(skb);
+ if (napi)
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
}
-#endif
} else {
send_up:
queue_rx_frame(skb);
@@ -6623,7 +6592,7 @@ aggregate:
* void.
*/
-static void s2io_link(nic_t * sp, int link)
+static void s2io_link(struct s2io_nic * sp, int link)
{
struct net_device *dev = (struct net_device *) sp->dev;
@@ -6667,7 +6636,7 @@ static int get_xena_rev_id(struct pci_dev *pdev)
* void
*/
-static void s2io_init_pci(nic_t * sp)
+static void s2io_init_pci(struct s2io_nic * sp)
{
u16 pci_cmd = 0, pcix_cmd = 0;
@@ -6700,13 +6669,9 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
rx_ring_num = 8;
}
-#ifdef CONFIG_S2IO_NAPI
- if (*dev_intr_type != INTA) {
- DBG_PRINT(ERR_DBG, "s2io: NAPI cannot be enabled when "
- "MSI/MSI-X is enabled. Defaulting to INTA\n");
- *dev_intr_type = INTA;
- }
-#endif
+ if (*dev_intr_type != INTA)
+ napi = 0;
+
#ifndef CONFIG_PCI_MSI
if (*dev_intr_type != INTA) {
DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
@@ -6727,6 +6692,8 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
"Defaulting to INTA\n");
*dev_intr_type = INTA;
}
+ if ( (rx_ring_num > 1) && (*dev_intr_type != INTA) )
+ napi = 0;
if (rx_ring_mode > 3) {
DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
@@ -6752,15 +6719,15 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
static int __devinit
s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
{
- nic_t *sp;
+ struct s2io_nic *sp;
struct net_device *dev;
int i, j, ret;
int dma_flag = FALSE;
u32 mac_up, mac_down;
u64 val64 = 0, tmp64 = 0;
- XENA_dev_config_t __iomem *bar0 = NULL;
+ struct XENA_dev_config __iomem *bar0 = NULL;
u16 subid;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int mode;
u8 dev_intr_type = intr_type;
@@ -6815,7 +6782,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
}
}
- dev = alloc_etherdev(sizeof(nic_t));
+ dev = alloc_etherdev(sizeof(struct s2io_nic));
if (dev == NULL) {
DBG_PRINT(ERR_DBG, "Device allocation failed\n");
pci_disable_device(pdev);
@@ -6830,7 +6797,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Private member variable initialized to s2io NIC structure */
sp = dev->priv;
- memset(sp, 0, sizeof(nic_t));
+ memset(sp, 0, sizeof(struct s2io_nic));
sp->dev = dev;
sp->pdev = pdev;
sp->high_dma_flag = dma_flag;
@@ -6926,7 +6893,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
sp->bar0 = ioremap(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (!sp->bar0) {
- DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n",
+ DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
dev->name);
ret = -ENOMEM;
goto bar0_remap_failed;
@@ -6935,7 +6902,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
sp->bar1 = ioremap(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2));
if (!sp->bar1) {
- DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n",
+ DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
dev->name);
ret = -ENOMEM;
goto bar1_remap_failed;
@@ -6946,7 +6913,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Initializing the BAR1 address as the start of the FIFO pointer. */
for (j = 0; j < MAX_TX_FIFOS; j++) {
- mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
+ mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *)
(sp->bar1 + (j * 0x00020000));
}
@@ -6967,10 +6934,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
* will use eth_mac_addr() for dev->set_mac_address
* mac address will be set every time dev->open() is called
*/
-#if defined(CONFIG_S2IO_NAPI)
dev->poll = s2io_poll;
dev->weight = 32;
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = s2io_netpoll;
@@ -6979,13 +6944,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
if (sp->high_dma_flag == TRUE)
dev->features |= NETIF_F_HIGHDMA;
-#ifdef NETIF_F_TSO
dev->features |= NETIF_F_TSO;
-#endif
-#ifdef NETIF_F_TSO6
dev->features |= NETIF_F_TSO6;
-#endif
- if (sp->device_type & XFRAME_II_DEVICE) {
+ if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) {
dev->features |= NETIF_F_UFO;
dev->features |= NETIF_F_HW_CSUM;
}
@@ -7066,9 +7027,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Initialize spinlocks */
spin_lock_init(&sp->tx_lock);
-#ifndef CONFIG_S2IO_NAPI
- spin_lock_init(&sp->put_lock);
-#endif
+
+ if (!napi)
+ spin_lock_init(&sp->put_lock);
spin_lock_init(&sp->rx_lock);
/*
@@ -7099,13 +7060,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
s2io_driver_version);
DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
+ "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
sp->def_mac_addr[0].mac_addr[0],
sp->def_mac_addr[0].mac_addr[1],
sp->def_mac_addr[0].mac_addr[2],
sp->def_mac_addr[0].mac_addr[3],
sp->def_mac_addr[0].mac_addr[4],
sp->def_mac_addr[0].mac_addr[5]);
+ DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
if (sp->device_type & XFRAME_II_DEVICE) {
mode = s2io_print_pci_mode(sp);
if (mode < 0) {
@@ -7129,9 +7091,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->name);
break;
}
-#ifdef CONFIG_S2IO_NAPI
- DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
-#endif
+
+ if (napi)
+ DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
switch(sp->intr_type) {
case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
@@ -7146,7 +7108,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
if (sp->lro)
DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
dev->name);
-
+ if (ufo)
+ DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)"
+ " enabled\n", dev->name);
/* Initialize device name */
sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
@@ -7203,7 +7167,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
{
struct net_device *dev =
(struct net_device *) pci_get_drvdata(pdev);
- nic_t *sp;
+ struct s2io_nic *sp;
if (dev == NULL) {
DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
@@ -7216,7 +7180,6 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
free_shared_mem(sp);
iounmap(sp->bar0);
iounmap(sp->bar1);
- pci_disable_device(pdev);
if (sp->intr_type != MSI_X)
pci_release_regions(pdev);
else {
@@ -7227,6 +7190,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
}
pci_set_drvdata(pdev, NULL);
free_netdev(dev);
+ pci_disable_device(pdev);
}
/**
@@ -7245,7 +7209,7 @@ int __init s2io_starter(void)
* Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
*/
-static void s2io_closer(void)
+static __exit void s2io_closer(void)
{
pci_unregister_driver(&s2io_driver);
DBG_PRINT(INIT_DBG, "cleanup done\n");
@@ -7255,7 +7219,7 @@ module_init(s2io_starter);
module_exit(s2io_closer);
static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
- struct tcphdr **tcp, RxD_t *rxdp)
+ struct tcphdr **tcp, struct RxD_t *rxdp)
{
int ip_off;
u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
@@ -7289,7 +7253,7 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
return 0;
}
-static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
+static int check_for_socket_match(struct lro *lro, struct iphdr *ip,
struct tcphdr *tcp)
{
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7304,7 +7268,7 @@ static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
}
-static void initiate_new_session(lro_t *lro, u8 *l2h,
+static void initiate_new_session(struct lro *lro, u8 *l2h,
struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
{
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7330,12 +7294,12 @@ static void initiate_new_session(lro_t *lro, u8 *l2h,
lro->in_use = 1;
}
-static void update_L3L4_header(nic_t *sp, lro_t *lro)
+static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro)
{
struct iphdr *ip = lro->iph;
struct tcphdr *tcp = lro->tcph;
- u16 nchk;
- StatInfo_t *statinfo = sp->mac_control.stats_info;
+ __sum16 nchk;
+ struct stat_block *statinfo = sp->mac_control.stats_info;
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
/* Update L3 header */
@@ -7361,7 +7325,7 @@ static void update_L3L4_header(nic_t *sp, lro_t *lro)
statinfo->sw_stat.num_aggregations++;
}
-static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
+static void aggregate_new_rx(struct lro *lro, struct iphdr *ip,
struct tcphdr *tcp, u32 l4_pyld)
{
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7383,7 +7347,7 @@ static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
}
}
-static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
+static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
struct tcphdr *tcp, u32 tcp_pyld_len)
{
u8 *ptr;
@@ -7441,8 +7405,8 @@ static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
}
static int
-s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
- RxD_t *rxdp, nic_t *sp)
+s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
+ struct RxD_t *rxdp, struct s2io_nic *sp)
{
struct iphdr *ip;
struct tcphdr *tcph;
@@ -7459,7 +7423,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
tcph = (struct tcphdr *)*tcp;
*tcp_len = get_l4_pyld_length(ip, tcph);
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- lro_t *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &sp->lro0_n[i];
if (l_lro->in_use) {
if (check_for_socket_match(l_lro, ip, tcph))
continue;
@@ -7497,7 +7461,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
}
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- lro_t *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &sp->lro0_n[i];
if (!(l_lro->in_use)) {
*lro = l_lro;
ret = 3; /* Begin anew */
@@ -7536,9 +7500,9 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
return ret;
}
-static void clear_lro_session(lro_t *lro)
+static void clear_lro_session(struct lro *lro)
{
- static u16 lro_struct_size = sizeof(lro_t);
+ static u16 lro_struct_size = sizeof(struct lro);
memset(lro, 0, lro_struct_size);
}
@@ -7548,14 +7512,14 @@ static void queue_rx_frame(struct sk_buff *skb)
struct net_device *dev = skb->dev;
skb->protocol = eth_type_trans(skb, dev);
-#ifdef CONFIG_S2IO_NAPI
- netif_receive_skb(skb);
-#else
- netif_rx(skb);
-#endif
+ if (napi)
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
}
-static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
+static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
+ struct sk_buff *skb,
u32 tcp_len)
{
struct sk_buff *first = lro->parent;
@@ -7567,6 +7531,7 @@ static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
lro->last_frag->next = skb;
else
skb_shinfo(first)->frag_list = skb;
+ first->truesize += skb->truesize;
lro->last_frag = skb;
sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
return;
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 3b0bafd273c..0de0c65f945 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -30,6 +30,8 @@
#undef SUCCESS
#define SUCCESS 0
#define FAILURE -1
+#define S2IO_MINUS_ONE 0xFFFFFFFFFFFFFFFFULL
+#define S2IO_MAX_PCI_CONFIG_SPACE_REINIT 100
#define CHECKBIT(value, nbit) (value & (1 << nbit))
@@ -37,7 +39,7 @@
#define MAX_FLICKER_TIME 60000 /* 60 Secs */
/* Maximum outstanding splits to be configured into xena. */
-typedef enum xena_max_outstanding_splits {
+enum {
XENA_ONE_SPLIT_TRANSACTION = 0,
XENA_TWO_SPLIT_TRANSACTION = 1,
XENA_THREE_SPLIT_TRANSACTION = 2,
@@ -46,7 +48,7 @@ typedef enum xena_max_outstanding_splits {
XENA_TWELVE_SPLIT_TRANSACTION = 5,
XENA_SIXTEEN_SPLIT_TRANSACTION = 6,
XENA_THIRTYTWO_SPLIT_TRANSACTION = 7
-} xena_max_outstanding_splits;
+};
#define XENA_MAX_OUTSTANDING_SPLITS(n) (n << 4)
/* OS concerned variables and constants */
@@ -77,7 +79,7 @@ static int debug_level = ERR_DBG;
#define S2IO_JUMBO_SIZE 9600
/* Driver statistics maintained by driver */
-typedef struct {
+struct swStat {
unsigned long long single_ecc_errs;
unsigned long long double_ecc_errs;
unsigned long long parity_err_cnt;
@@ -92,10 +94,10 @@ typedef struct {
unsigned long long flush_max_pkts;
unsigned long long sum_avg_pkts_aggregated;
unsigned long long num_aggregations;
-} swStat_t;
+};
/* Xpak releated alarm and warnings */
-typedef struct {
+struct xpakStat {
u64 alarm_transceiver_temp_high;
u64 alarm_transceiver_temp_low;
u64 alarm_laser_bias_current_high;
@@ -110,11 +112,11 @@ typedef struct {
u64 warn_laser_output_power_low;
u64 xpak_regs_stat;
u32 xpak_timer_count;
-} xpakStat_t;
+};
/* The statistics block of Xena */
-typedef struct stat_block {
+struct stat_block {
/* Tx MAC statistics counters. */
__le32 tmac_data_octets;
__le32 tmac_frms;
@@ -290,9 +292,9 @@ typedef struct stat_block {
__le32 reserved_14;
__le32 link_fault_cnt;
u8 buffer[20];
- swStat_t sw_stat;
- xpakStat_t xpak_stat;
-} StatInfo_t;
+ struct swStat sw_stat;
+ struct xpakStat xpak_stat;
+};
/*
* Structures representing different init time configuration
@@ -315,7 +317,7 @@ static int fifo_map[][MAX_TX_FIFOS] = {
};
/* Maintains Per FIFO related information. */
-typedef struct tx_fifo_config {
+struct tx_fifo_config {
#define MAX_AVAILABLE_TXDS 8192
u32 fifo_len; /* specifies len of FIFO upto 8192, ie no of TxDLs */
/* Priority definition */
@@ -332,11 +334,11 @@ typedef struct tx_fifo_config {
u8 f_no_snoop;
#define NO_SNOOP_TXD 0x01
#define NO_SNOOP_TXD_BUFFER 0x02
-} tx_fifo_config_t;
+};
/* Maintains per Ring related information */
-typedef struct rx_ring_config {
+struct rx_ring_config {
u32 num_rxd; /*No of RxDs per Rx Ring */
#define RX_RING_PRI_0 0 /* highest */
#define RX_RING_PRI_1 1
@@ -357,7 +359,7 @@ typedef struct rx_ring_config {
u8 f_no_snoop;
#define NO_SNOOP_RXD 0x01
#define NO_SNOOP_RXD_BUFFER 0x02
-} rx_ring_config_t;
+};
/* This structure provides contains values of the tunable parameters
* of the H/W
@@ -367,7 +369,7 @@ struct config_param {
u32 tx_fifo_num; /*Number of Tx FIFOs */
u8 fifo_mapping[MAX_TX_FIFOS];
- tx_fifo_config_t tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */
+ struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */
u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */
u64 tx_intr_type;
/* Specifies if Tx Intr is UTILZ or PER_LIST type. */
@@ -376,7 +378,7 @@ struct config_param {
u32 rx_ring_num; /*Number of receive rings */
#define MAX_RX_BLOCKS_PER_RING 150
- rx_ring_config_t rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */
+ struct rx_ring_config rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */
u8 bimodal; /*Flag for setting bimodal interrupts*/
#define HEADER_ETHERNET_II_802_3_SIZE 14
@@ -395,14 +397,14 @@ struct config_param {
};
/* Structure representing MAC Addrs */
-typedef struct mac_addr {
+struct mac_addr {
u8 mac_addr[ETH_ALEN];
-} macaddr_t;
+};
/* Structure that represent every FIFO element in the BAR1
* Address location.
*/
-typedef struct _TxFIFO_element {
+struct TxFIFO_element {
u64 TxDL_Pointer;
u64 List_Control;
@@ -413,10 +415,10 @@ typedef struct _TxFIFO_element {
#define TX_FIFO_SPECIAL_FUNC BIT(23)
#define TX_FIFO_DS_NO_SNOOP BIT(31)
#define TX_FIFO_BUFF_NO_SNOOP BIT(30)
-} TxFIFO_element_t;
+};
/* Tx descriptor structure */
-typedef struct _TxD {
+struct TxD {
u64 Control_1;
/* bit mask */
#define TXD_LIST_OWN_XENA BIT(7)
@@ -447,16 +449,16 @@ typedef struct _TxD {
u64 Buffer_Pointer;
u64 Host_Control; /* reserved for host */
-} TxD_t;
+};
/* Structure to hold the phy and virt addr of every TxDL. */
-typedef struct list_info_hold {
+struct list_info_hold {
dma_addr_t list_phy_addr;
void *list_virt_addr;
-} list_info_hold_t;
+};
/* Rx descriptor structure for 1 buffer mode */
-typedef struct _RxD_t {
+struct RxD_t {
u64 Host_Control; /* reserved for host */
u64 Control_1;
#define RXD_OWN_XENA BIT(7)
@@ -481,21 +483,21 @@ typedef struct _RxD_t {
#define SET_NUM_TAG(val) vBIT(val,16,32)
-} RxD_t;
+};
/* Rx descriptor structure for 1 buffer mode */
-typedef struct _RxD1_t {
- struct _RxD_t h;
+struct RxD1 {
+ struct RxD_t h;
#define MASK_BUFFER0_SIZE_1 vBIT(0x3FFF,2,14)
#define SET_BUFFER0_SIZE_1(val) vBIT(val,2,14)
#define RXD_GET_BUFFER0_SIZE_1(_Control_2) \
(u16)((_Control_2 & MASK_BUFFER0_SIZE_1) >> 48)
u64 Buffer0_ptr;
-} RxD1_t;
+};
/* Rx descriptor structure for 3 or 2 buffer mode */
-typedef struct _RxD3_t {
- struct _RxD_t h;
+struct RxD3 {
+ struct RxD_t h;
#define MASK_BUFFER0_SIZE_3 vBIT(0xFF,2,14)
#define MASK_BUFFER1_SIZE_3 vBIT(0xFFFF,16,16)
@@ -515,15 +517,15 @@ typedef struct _RxD3_t {
u64 Buffer0_ptr;
u64 Buffer1_ptr;
u64 Buffer2_ptr;
-} RxD3_t;
+};
/* Structure that represents the Rx descriptor block which contains
* 128 Rx descriptors.
*/
-typedef struct _RxD_block {
+struct RxD_block {
#define MAX_RXDS_PER_BLOCK_1 127
- RxD1_t rxd[MAX_RXDS_PER_BLOCK_1];
+ struct RxD1 rxd[MAX_RXDS_PER_BLOCK_1];
u64 reserved_0;
#define END_OF_BLOCK 0xFEFFFFFFFFFFFFFFULL
@@ -533,22 +535,22 @@ typedef struct _RxD_block {
u64 pNext_RxD_Blk_physical; /* Buff0_ptr.In a 32 bit arch
* the upper 32 bits should
* be 0 */
-} RxD_block_t;
+};
#define SIZE_OF_BLOCK 4096
-#define RXD_MODE_1 0
-#define RXD_MODE_3A 1
-#define RXD_MODE_3B 2
+#define RXD_MODE_1 0 /* One Buffer mode */
+#define RXD_MODE_3A 1 /* Three Buffer mode */
+#define RXD_MODE_3B 2 /* Two Buffer mode */
/* Structure to hold virtual addresses of Buf0 and Buf1 in
* 2buf mode. */
-typedef struct bufAdd {
+struct buffAdd {
void *ba_0_org;
void *ba_1_org;
void *ba_0;
void *ba_1;
-} buffAdd_t;
+};
/* Structure which stores all the MAC control parameters */
@@ -556,43 +558,46 @@ typedef struct bufAdd {
* from which the Rx Interrupt processor can start picking
* up the RxDs for processing.
*/
-typedef struct _rx_curr_get_info_t {
+struct rx_curr_get_info {
u32 block_index;
u32 offset;
u32 ring_len;
-} rx_curr_get_info_t;
+};
-typedef rx_curr_get_info_t rx_curr_put_info_t;
+struct rx_curr_put_info {
+ u32 block_index;
+ u32 offset;
+ u32 ring_len;
+};
/* This structure stores the offset of the TxDl in the FIFO
* from which the Tx Interrupt processor can start picking
* up the TxDLs for send complete interrupt processing.
*/
-typedef struct {
+struct tx_curr_get_info {
u32 offset;
u32 fifo_len;
-} tx_curr_get_info_t;
-
-typedef tx_curr_get_info_t tx_curr_put_info_t;
+};
+struct tx_curr_put_info {
+ u32 offset;
+ u32 fifo_len;
+};
-typedef struct rxd_info {
+struct rxd_info {
void *virt_addr;
dma_addr_t dma_addr;
-}rxd_info_t;
+};
/* Structure that holds the Phy and virt addresses of the Blocks */
-typedef struct rx_block_info {
+struct rx_block_info {
void *block_virt_addr;
dma_addr_t block_dma_addr;
- rxd_info_t *rxds;
-} rx_block_info_t;
-
-/* pre declaration of the nic structure */
-typedef struct s2io_nic nic_t;
+ struct rxd_info *rxds;
+};
/* Ring specific structure */
-typedef struct ring_info {
+struct ring_info {
/* The ring number */
int ring_no;
@@ -600,7 +605,7 @@ typedef struct ring_info {
* Place holders for the virtual and physical addresses of
* all the Rx Blocks
*/
- rx_block_info_t rx_blocks[MAX_RX_BLOCKS_PER_RING];
+ struct rx_block_info rx_blocks[MAX_RX_BLOCKS_PER_RING];
int block_count;
int pkt_cnt;
@@ -608,26 +613,24 @@ typedef struct ring_info {
* Put pointer info which indictes which RxD has to be replenished
* with a new buffer.
*/
- rx_curr_put_info_t rx_curr_put_info;
+ struct rx_curr_put_info rx_curr_put_info;
/*
* Get pointer info which indictes which is the last RxD that was
* processed by the driver.
*/
- rx_curr_get_info_t rx_curr_get_info;
+ struct rx_curr_get_info rx_curr_get_info;
-#ifndef CONFIG_S2IO_NAPI
/* Index to the absolute position of the put pointer of Rx ring */
int put_pos;
-#endif
/* Buffer Address store. */
- buffAdd_t **ba;
- nic_t *nic;
-} ring_info_t;
+ struct buffAdd **ba;
+ struct s2io_nic *nic;
+};
/* Fifo specific structure */
-typedef struct fifo_info {
+struct fifo_info {
/* FIFO number */
int fifo_no;
@@ -635,40 +638,40 @@ typedef struct fifo_info {
int max_txds;
/* Place holder of all the TX List's Phy and Virt addresses. */
- list_info_hold_t *list_info;
+ struct list_info_hold *list_info;
/*
* Current offset within the tx FIFO where driver would write
* new Tx frame
*/
- tx_curr_put_info_t tx_curr_put_info;
+ struct tx_curr_put_info tx_curr_put_info;
/*
* Current offset within tx FIFO from where the driver would start freeing
* the buffers
*/
- tx_curr_get_info_t tx_curr_get_info;
+ struct tx_curr_get_info tx_curr_get_info;
- nic_t *nic;
-}fifo_info_t;
+ struct s2io_nic *nic;
+};
/* Information related to the Tx and Rx FIFOs and Rings of Xena
* is maintained in this structure.
*/
-typedef struct mac_info {
+struct mac_info {
/* tx side stuff */
/* logical pointer of start of each Tx FIFO */
- TxFIFO_element_t __iomem *tx_FIFO_start[MAX_TX_FIFOS];
+ struct TxFIFO_element __iomem *tx_FIFO_start[MAX_TX_FIFOS];
/* Fifo specific structure */
- fifo_info_t fifos[MAX_TX_FIFOS];
+ struct fifo_info fifos[MAX_TX_FIFOS];
/* Save virtual address of TxD page with zero DMA addr(if any) */
void *zerodma_virt_addr;
/* rx side stuff */
/* Ring specific structure */
- ring_info_t rings[MAX_RX_RINGS];
+ struct ring_info rings[MAX_RX_RINGS];
u16 rmac_pause_time;
u16 mc_pause_threshold_q0q3;
@@ -677,14 +680,14 @@ typedef struct mac_info {
void *stats_mem; /* orignal pointer to allocated mem */
dma_addr_t stats_mem_phy; /* Physical address of the stat block */
u32 stats_mem_sz;
- StatInfo_t *stats_info; /* Logical address of the stat block */
-} mac_info_t;
+ struct stat_block *stats_info; /* Logical address of the stat block */
+};
/* structure representing the user defined MAC addresses */
-typedef struct {
+struct usr_addr {
char addr[ETH_ALEN];
int usage_cnt;
-} usr_addr_t;
+};
/* Default Tunable parameters of the NIC. */
#define DEFAULT_FIFO_0_LEN 4096
@@ -717,36 +720,34 @@ struct msix_info_st {
};
/* Data structure to represent a LRO session */
-typedef struct lro {
+struct lro {
struct sk_buff *parent;
struct sk_buff *last_frag;
u8 *l2h;
struct iphdr *iph;
struct tcphdr *tcph;
u32 tcp_next_seq;
- u32 tcp_ack;
+ __be32 tcp_ack;
int total_len;
int frags_len;
int sg_num;
int in_use;
- u16 window;
+ __be16 window;
u32 cur_tsval;
u32 cur_tsecr;
u8 saw_ts;
-}lro_t;
+};
/* Structure representing one instance of the NIC */
struct s2io_nic {
int rxd_mode;
-#ifdef CONFIG_S2IO_NAPI
/*
* Count of packets to be processed in a given iteration, it will be indicated
* by the quota field of the device structure when NAPI is enabled.
*/
int pkts_to_process;
-#endif
struct net_device *dev;
- mac_info_t mac_control;
+ struct mac_info mac_control;
struct config_param config;
struct pci_dev *pdev;
void __iomem *bar0;
@@ -754,8 +755,8 @@ struct s2io_nic {
#define MAX_MAC_SUPPORTED 16
#define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
- macaddr_t def_mac_addr[MAX_MAC_SUPPORTED];
- macaddr_t pre_mac_addr[MAX_MAC_SUPPORTED];
+ struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED];
+ struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED];
struct net_device_stats stats;
int high_dma_flag;
@@ -775,9 +776,7 @@ struct s2io_nic {
atomic_t rx_bufs_left[MAX_RX_RINGS];
spinlock_t tx_lock;
-#ifndef CONFIG_S2IO_NAPI
spinlock_t put_lock;
-#endif
#define PROMISC 1
#define ALL_MULTI 2
@@ -785,7 +784,7 @@ struct s2io_nic {
#define MAX_ADDRS_SUPPORTED 64
u16 usr_addr_count;
u16 mc_addr_count;
- usr_addr_t usr_addrs[MAX_ADDRS_SUPPORTED];
+ struct usr_addr usr_addrs[MAX_ADDRS_SUPPORTED];
u16 m_cast_flg;
u16 all_multi_pos;
@@ -841,7 +840,7 @@ struct s2io_nic {
u8 device_type;
#define MAX_LRO_SESSIONS 32
- lro_t lro0_n[MAX_LRO_SESSIONS];
+ struct lro lro0_n[MAX_LRO_SESSIONS];
unsigned long clubbed_frms_cnt;
unsigned long sending_both;
u8 lro;
@@ -855,8 +854,9 @@ struct s2io_nic {
spinlock_t rx_lock;
atomic_t isr_cnt;
u64 *ufo_in_band_v;
-#define VPD_PRODUCT_NAME_LEN 50
- u8 product_name[VPD_PRODUCT_NAME_LEN];
+#define VPD_STRING_LEN 80
+ u8 product_name[VPD_STRING_LEN];
+ u8 serial_num[VPD_STRING_LEN];
};
#define RESET_ERROR 1;
@@ -975,43 +975,50 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev);
static int init_shared_mem(struct s2io_nic *sp);
static void free_shared_mem(struct s2io_nic *sp);
static int init_nic(struct s2io_nic *nic);
-static void rx_intr_handler(ring_info_t *ring_data);
-static void tx_intr_handler(fifo_info_t *fifo_data);
+static void rx_intr_handler(struct ring_info *ring_data);
+static void tx_intr_handler(struct fifo_info *fifo_data);
static void alarm_intr_handler(struct s2io_nic *sp);
static int s2io_starter(void);
+static void s2io_closer(void);
static void s2io_tx_watchdog(struct net_device *dev);
static void s2io_tasklet(unsigned long dev_addr);
static void s2io_set_multicast(struct net_device *dev);
-static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp);
-static void s2io_link(nic_t * sp, int link);
-#if defined(CONFIG_S2IO_NAPI)
+static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp);
+static void s2io_link(struct s2io_nic * sp, int link);
+static void s2io_reset(struct s2io_nic * sp);
static int s2io_poll(struct net_device *dev, int *budget);
-#endif
-static void s2io_init_pci(nic_t * sp);
+static void s2io_init_pci(struct s2io_nic * 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 int s2io_enable_msi(struct s2io_nic *nic);
static irqreturn_t s2io_msi_handle(int irq, void *dev_id);
static irqreturn_t
s2io_msix_ring_handle(int irq, void *dev_id);
static irqreturn_t
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 int verify_xena_quiescence(struct s2io_nic *sp);
static const struct ethtool_ops netdev_ethtool_ops;
static void s2io_set_link(struct work_struct *work);
-static int s2io_set_swapper(nic_t * sp);
-static void s2io_card_down(nic_t *nic);
-static int s2io_card_up(nic_t *nic);
+static int s2io_set_swapper(struct s2io_nic * sp);
+static void s2io_card_down(struct s2io_nic *nic);
+static int s2io_card_up(struct s2io_nic *nic);
static int get_xena_rev_id(struct pci_dev *pdev);
-static void restore_xmsi_data(nic_t *nic);
+static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit);
+static int s2io_add_isr(struct s2io_nic * sp);
+static void s2io_rem_isr(struct s2io_nic * sp);
+
+static void restore_xmsi_data(struct s2io_nic *nic);
-static int s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, RxD_t *rxdp, nic_t *sp);
-static void clear_lro_session(lro_t *lro);
+static int
+s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
+ struct RxD_t *rxdp, struct s2io_nic *sp);
+static void clear_lro_session(struct lro *lro);
static void queue_rx_frame(struct sk_buff *skb);
-static void update_L3L4_header(nic_t *sp, lro_t *lro);
-static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len);
+static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro);
+static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
+ struct sk_buff *skb, u32 tcp_len);
#define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size
#define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
new file mode 100644
index 00000000000..7f800feaa9a
--- /dev/null
+++ b/drivers/net/sc92031.c
@@ -0,0 +1,1620 @@
+/* Silan SC92031 PCI Fast Ethernet Adapter driver
+ *
+ * Based on vendor drivers:
+ * Silan Fast Ethernet Netcard Driver:
+ * MODULE_AUTHOR ("gaoyonghong");
+ * MODULE_DESCRIPTION ("SILAN Fast Ethernet driver");
+ * MODULE_LICENSE("GPL");
+ * 8139D Fast Ethernet driver:
+ * (C) 2002 by gaoyonghong
+ * MODULE_AUTHOR ("gaoyonghong");
+ * MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver");
+ * MODULE_LICENSE("GPL");
+ * Both are almost identical and seem to be based on pci-skeleton.c
+ *
+ * Rewritten for 2.6 by Cesar Eduardo Barros
+ */
+
+/* Note about set_mac_address: I don't know how to change the hardware
+ * matching, so you need to enable IFF_PROMISC when using it.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/crc32.h>
+
+#include <asm/irq.h>
+
+#define PCI_VENDOR_ID_SILAN 0x1904
+#define PCI_DEVICE_ID_SILAN_SC92031 0x2031
+#define PCI_DEVICE_ID_SILAN_8139D 0x8139
+
+#define SC92031_NAME "sc92031"
+#define SC92031_DESCRIPTION "Silan SC92031 PCI Fast Ethernet Adapter driver"
+#define SC92031_VERSION "2.0c"
+
+/* BAR 0 is MMIO, BAR 1 is PIO */
+#ifndef SC92031_USE_BAR
+#define SC92031_USE_BAR 0
+#endif
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */
+static int multicast_filter_limit = 64;
+module_param(multicast_filter_limit, int, 0);
+MODULE_PARM_DESC(multicast_filter_limit,
+ "Maximum number of filtered multicast addresses");
+
+static int media;
+module_param(media, int, 0);
+MODULE_PARM_DESC(media, "Media type (0x00 = autodetect,"
+ " 0x01 = 10M half, 0x02 = 10M full,"
+ " 0x04 = 100M half, 0x08 = 100M full)");
+
+/* Size of the in-memory receive ring. */
+#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+
+/* Number of Tx descriptor registers. */
+#define NUM_TX_DESC 4
+
+/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE 1536
+
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
+#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
+
+/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (4*HZ)
+
+#define SILAN_STATS_NUM 2 /* number of ETHTOOL_GSTATS */
+
+/* media options */
+#define AUTOSELECT 0x00
+#define M10_HALF 0x01
+#define M10_FULL 0x02
+#define M100_HALF 0x04
+#define M100_FULL 0x08
+
+ /* Symbolic offsets to registers. */
+enum silan_registers {
+ Config0 = 0x00, // Config0
+ Config1 = 0x04, // Config1
+ RxBufWPtr = 0x08, // Rx buffer writer poiter
+ IntrStatus = 0x0C, // Interrupt status
+ IntrMask = 0x10, // Interrupt mask
+ RxbufAddr = 0x14, // Rx buffer start address
+ RxBufRPtr = 0x18, // Rx buffer read pointer
+ Txstatusall = 0x1C, // Transmit status of all descriptors
+ TxStatus0 = 0x20, // Transmit status (Four 32bit registers).
+ TxAddr0 = 0x30, // Tx descriptors (also four 32bit).
+ RxConfig = 0x40, // Rx configuration
+ MAC0 = 0x44, // Ethernet hardware address.
+ MAR0 = 0x4C, // Multicast filter.
+ RxStatus0 = 0x54, // Rx status
+ TxConfig = 0x5C, // Tx configuration
+ PhyCtrl = 0x60, // physical control
+ FlowCtrlConfig = 0x64, // flow control
+ Miicmd0 = 0x68, // Mii command0 register
+ Miicmd1 = 0x6C, // Mii command1 register
+ Miistatus = 0x70, // Mii status register
+ Timercnt = 0x74, // Timer counter register
+ TimerIntr = 0x78, // Timer interrupt register
+ PMConfig = 0x7C, // Power Manager configuration
+ CRC0 = 0x80, // Power Manager CRC ( Two 32bit regisers)
+ Wakeup0 = 0x88, // power Manager wakeup( Eight 64bit regiser)
+ LSBCRC0 = 0xC8, // power Manager LSBCRC(Two 32bit regiser)
+ TestD0 = 0xD0,
+ TestD4 = 0xD4,
+ TestD8 = 0xD8,
+};
+
+#define MII_BMCR 0 // Basic mode control register
+#define MII_BMSR 1 // Basic mode status register
+#define MII_JAB 16
+#define MII_OutputStatus 24
+
+#define BMCR_FULLDPLX 0x0100 // Full duplex
+#define BMCR_ANRESTART 0x0200 // Auto negotiation restart
+#define BMCR_ANENABLE 0x1000 // Enable auto negotiation
+#define BMCR_SPEED100 0x2000 // Select 100Mbps
+#define BMSR_LSTATUS 0x0004 // Link status
+#define PHY_16_JAB_ENB 0x1000
+#define PHY_16_PORT_ENB 0x1
+
+enum IntrStatusBits {
+ LinkFail = 0x80000000,
+ LinkOK = 0x40000000,
+ TimeOut = 0x20000000,
+ RxOverflow = 0x0040,
+ RxOK = 0x0020,
+ TxOK = 0x0001,
+ IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK,
+};
+
+enum TxStatusBits {
+ TxCarrierLost = 0x20000000,
+ TxAborted = 0x10000000,
+ TxOutOfWindow = 0x08000000,
+ TxNccShift = 22,
+ EarlyTxThresShift = 16,
+ TxStatOK = 0x8000,
+ TxUnderrun = 0x4000,
+ TxOwn = 0x2000,
+};
+
+enum RxStatusBits {
+ RxStatesOK = 0x80000,
+ RxBadAlign = 0x40000,
+ RxHugeFrame = 0x20000,
+ RxSmallFrame = 0x10000,
+ RxCRCOK = 0x8000,
+ RxCrlFrame = 0x4000,
+ Rx_Broadcast = 0x2000,
+ Rx_Multicast = 0x1000,
+ RxAddrMatch = 0x0800,
+ MiiErr = 0x0400,
+};
+
+enum RxConfigBits {
+ RxFullDx = 0x80000000,
+ RxEnb = 0x40000000,
+ RxSmall = 0x20000000,
+ RxHuge = 0x10000000,
+ RxErr = 0x08000000,
+ RxAllphys = 0x04000000,
+ RxMulticast = 0x02000000,
+ RxBroadcast = 0x01000000,
+ RxLoopBack = (1 << 23) | (1 << 22),
+ LowThresholdShift = 12,
+ HighThresholdShift = 2,
+};
+
+enum TxConfigBits {
+ TxFullDx = 0x80000000,
+ TxEnb = 0x40000000,
+ TxEnbPad = 0x20000000,
+ TxEnbHuge = 0x10000000,
+ TxEnbFCS = 0x08000000,
+ TxNoBackOff = 0x04000000,
+ TxEnbPrem = 0x02000000,
+ TxCareLostCrs = 0x1000000,
+ TxExdCollNum = 0xf00000,
+ TxDataRate = 0x80000,
+};
+
+enum PhyCtrlconfigbits {
+ PhyCtrlAne = 0x80000000,
+ PhyCtrlSpd100 = 0x40000000,
+ PhyCtrlSpd10 = 0x20000000,
+ PhyCtrlPhyBaseAddr = 0x1f000000,
+ PhyCtrlDux = 0x800000,
+ PhyCtrlReset = 0x400000,
+};
+
+enum FlowCtrlConfigBits {
+ FlowCtrlFullDX = 0x80000000,
+ FlowCtrlEnb = 0x40000000,
+};
+
+enum Config0Bits {
+ Cfg0_Reset = 0x80000000,
+ Cfg0_Anaoff = 0x40000000,
+ Cfg0_LDPS = 0x20000000,
+};
+
+enum Config1Bits {
+ Cfg1_EarlyRx = 1 << 31,
+ Cfg1_EarlyTx = 1 << 30,
+
+ //rx buffer size
+ Cfg1_Rcv8K = 0x0,
+ Cfg1_Rcv16K = 0x1,
+ Cfg1_Rcv32K = 0x3,
+ Cfg1_Rcv64K = 0x7,
+ Cfg1_Rcv128K = 0xf,
+};
+
+enum MiiCmd0Bits {
+ Mii_Divider = 0x20000000,
+ Mii_WRITE = 0x400000,
+ Mii_READ = 0x200000,
+ Mii_SCAN = 0x100000,
+ Mii_Tamod = 0x80000,
+ Mii_Drvmod = 0x40000,
+ Mii_mdc = 0x20000,
+ Mii_mdoen = 0x10000,
+ Mii_mdo = 0x8000,
+ Mii_mdi = 0x4000,
+};
+
+enum MiiStatusBits {
+ Mii_StatusBusy = 0x80000000,
+};
+
+enum PMConfigBits {
+ PM_Enable = 1 << 31,
+ PM_LongWF = 1 << 30,
+ PM_Magic = 1 << 29,
+ PM_LANWake = 1 << 28,
+ PM_LWPTN = (1 << 27 | 1<< 26),
+ PM_LinkUp = 1 << 25,
+ PM_WakeUp = 1 << 24,
+};
+
+/* Locking rules:
+ * priv->lock protects most of the fields of priv and most of the
+ * hardware registers. It does not have to protect against softirqs
+ * between sc92031_disable_interrupts and sc92031_enable_interrupts;
+ * it also does not need to be used in ->open and ->stop while the
+ * device interrupts are off.
+ * Not having to protect against softirqs is very useful due to heavy
+ * use of mdelay() at _sc92031_reset.
+ * Functions prefixed with _sc92031_ must be called with the lock held;
+ * functions prefixed with sc92031_ must be called without the lock held.
+ * Use mmiowb() before unlocking if the hardware was written to.
+ */
+
+/* Locking rules for the interrupt:
+ * - the interrupt and the tasklet never run at the same time
+ * - neither run between sc92031_disable_interrupts and
+ * sc92031_enable_interrupt
+ */
+
+struct sc92031_priv {
+ spinlock_t lock;
+ /* iomap.h cookie */
+ void __iomem *port_base;
+ /* pci device structure */
+ struct pci_dev *pdev;
+ /* tasklet */
+ struct tasklet_struct tasklet;
+
+ /* CPU address of rx ring */
+ void *rx_ring;
+ /* PCI address of rx ring */
+ dma_addr_t rx_ring_dma_addr;
+ /* PCI address of rx ring read pointer */
+ dma_addr_t rx_ring_tail;
+
+ /* tx ring write index */
+ unsigned tx_head;
+ /* tx ring read index */
+ unsigned tx_tail;
+ /* CPU address of tx bounce buffer */
+ void *tx_bufs;
+ /* PCI address of tx bounce buffer */
+ dma_addr_t tx_bufs_dma_addr;
+
+ /* copies of some hardware registers */
+ u32 intr_status;
+ atomic_t intr_mask;
+ u32 rx_config;
+ u32 tx_config;
+ u32 pm_config;
+
+ /* copy of some flags from dev->flags */
+ unsigned int mc_flags;
+
+ /* for ETHTOOL_GSTATS */
+ u64 tx_timeouts;
+ u64 rx_loss;
+
+ /* for dev->get_stats */
+ long rx_value;
+ struct net_device_stats stats;
+};
+
+/* I don't know which registers can be safely read; however, I can guess
+ * MAC0 is one of them. */
+static inline void _sc92031_dummy_read(void __iomem *port_base)
+{
+ ioread32(port_base + MAC0);
+}
+
+static u32 _sc92031_mii_wait(void __iomem *port_base)
+{
+ u32 mii_status;
+
+ do {
+ udelay(10);
+ mii_status = ioread32(port_base + Miistatus);
+ } while (mii_status & Mii_StatusBusy);
+
+ return mii_status;
+}
+
+static u32 _sc92031_mii_cmd(void __iomem *port_base, u32 cmd0, u32 cmd1)
+{
+ iowrite32(Mii_Divider, port_base + Miicmd0);
+
+ _sc92031_mii_wait(port_base);
+
+ iowrite32(cmd1, port_base + Miicmd1);
+ iowrite32(Mii_Divider | cmd0, port_base + Miicmd0);
+
+ return _sc92031_mii_wait(port_base);
+}
+
+static void _sc92031_mii_scan(void __iomem *port_base)
+{
+ _sc92031_mii_cmd(port_base, Mii_SCAN, 0x1 << 6);
+}
+
+static u16 _sc92031_mii_read(void __iomem *port_base, unsigned reg)
+{
+ return _sc92031_mii_cmd(port_base, Mii_READ, reg << 6) >> 13;
+}
+
+static void _sc92031_mii_write(void __iomem *port_base, unsigned reg, u16 val)
+{
+ _sc92031_mii_cmd(port_base, Mii_WRITE, (reg << 6) | ((u32)val << 11));
+}
+
+static void sc92031_disable_interrupts(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ /* tell the tasklet/interrupt not to enable interrupts */
+ atomic_set(&priv->intr_mask, 0);
+ wmb();
+
+ /* stop interrupts */
+ iowrite32(0, port_base + IntrMask);
+ _sc92031_dummy_read(port_base);
+ mmiowb();
+
+ /* wait for any concurrent interrupt/tasklet to finish */
+ synchronize_irq(dev->irq);
+ tasklet_disable(&priv->tasklet);
+}
+
+static void sc92031_enable_interrupts(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ tasklet_enable(&priv->tasklet);
+
+ atomic_set(&priv->intr_mask, IntrBits);
+ wmb();
+
+ iowrite32(IntrBits, port_base + IntrMask);
+ mmiowb();
+}
+
+static void _sc92031_disable_tx_rx(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ priv->rx_config &= ~RxEnb;
+ priv->tx_config &= ~TxEnb;
+ iowrite32(priv->rx_config, port_base + RxConfig);
+ iowrite32(priv->tx_config, port_base + TxConfig);
+}
+
+static void _sc92031_enable_tx_rx(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ priv->rx_config |= RxEnb;
+ priv->tx_config |= TxEnb;
+ iowrite32(priv->rx_config, port_base + RxConfig);
+ iowrite32(priv->tx_config, port_base + TxConfig);
+}
+
+static void _sc92031_tx_clear(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ while (priv->tx_head - priv->tx_tail > 0) {
+ priv->tx_tail++;
+ priv->stats.tx_dropped++;
+ }
+ priv->tx_head = priv->tx_tail = 0;
+}
+
+static void _sc92031_set_mar(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 mar0 = 0, mar1 = 0;
+
+ if ((dev->flags & IFF_PROMISC)
+ || dev->mc_count > multicast_filter_limit
+ || (dev->flags & IFF_ALLMULTI))
+ mar0 = mar1 = 0xffffffff;
+ else if (dev->flags & IFF_MULTICAST) {
+ struct dev_mc_list *mc_list;
+
+ for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
+ u32 crc;
+ unsigned bit = 0;
+
+ crc = ~ether_crc(ETH_ALEN, mc_list->dmi_addr);
+ crc >>= 24;
+
+ if (crc & 0x01) bit |= 0x02;
+ if (crc & 0x02) bit |= 0x01;
+ if (crc & 0x10) bit |= 0x20;
+ if (crc & 0x20) bit |= 0x10;
+ if (crc & 0x40) bit |= 0x08;
+ if (crc & 0x80) bit |= 0x04;
+
+ if (bit > 31)
+ mar0 |= 0x1 << (bit - 32);
+ else
+ mar1 |= 0x1 << bit;
+ }
+ }
+
+ iowrite32(mar0, port_base + MAR0);
+ iowrite32(mar1, port_base + MAR0 + 4);
+}
+
+static void _sc92031_set_rx_config(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ unsigned int old_mc_flags;
+ u32 rx_config_bits = 0;
+
+ old_mc_flags = priv->mc_flags;
+
+ if (dev->flags & IFF_PROMISC)
+ rx_config_bits |= RxSmall | RxHuge | RxErr | RxBroadcast
+ | RxMulticast | RxAllphys;
+
+ if (dev->flags & (IFF_ALLMULTI | IFF_MULTICAST))
+ rx_config_bits |= RxMulticast;
+
+ if (dev->flags & IFF_BROADCAST)
+ rx_config_bits |= RxBroadcast;
+
+ priv->rx_config &= ~(RxSmall | RxHuge | RxErr | RxBroadcast
+ | RxMulticast | RxAllphys);
+ priv->rx_config |= rx_config_bits;
+
+ priv->mc_flags = dev->flags & (IFF_PROMISC | IFF_ALLMULTI
+ | IFF_MULTICAST | IFF_BROADCAST);
+
+ if (netif_carrier_ok(dev) && priv->mc_flags != old_mc_flags)
+ iowrite32(priv->rx_config, port_base + RxConfig);
+}
+
+static bool _sc92031_check_media(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u16 bmsr;
+
+ bmsr = _sc92031_mii_read(port_base, MII_BMSR);
+ rmb();
+ if (bmsr & BMSR_LSTATUS) {
+ bool speed_100, duplex_full;
+ u32 flow_ctrl_config = 0;
+ u16 output_status = _sc92031_mii_read(port_base,
+ MII_OutputStatus);
+ _sc92031_mii_scan(port_base);
+
+ speed_100 = output_status & 0x2;
+ duplex_full = output_status & 0x4;
+
+ /* Initial Tx/Rx configuration */
+ priv->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift);
+ priv->tx_config = 0x48800000;
+
+ /* NOTE: vendor driver had dead code here to enable tx padding */
+
+ if (!speed_100)
+ priv->tx_config |= 0x80000;
+
+ // configure rx mode
+ _sc92031_set_rx_config(dev);
+
+ if (duplex_full) {
+ priv->rx_config |= RxFullDx;
+ priv->tx_config |= TxFullDx;
+ flow_ctrl_config = FlowCtrlFullDX | FlowCtrlEnb;
+ } else {
+ priv->rx_config &= ~RxFullDx;
+ priv->tx_config &= ~TxFullDx;
+ }
+
+ _sc92031_set_mar(dev);
+ _sc92031_set_rx_config(dev);
+ _sc92031_enable_tx_rx(dev);
+ iowrite32(flow_ctrl_config, port_base + FlowCtrlConfig);
+
+ netif_carrier_on(dev);
+
+ if (printk_ratelimit())
+ printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n",
+ dev->name,
+ speed_100 ? "100" : "10",
+ duplex_full ? "full" : "half");
+ return true;
+ } else {
+ _sc92031_mii_scan(port_base);
+
+ netif_carrier_off(dev);
+
+ _sc92031_disable_tx_rx(dev);
+
+ if (printk_ratelimit())
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ return false;
+ }
+}
+
+static void _sc92031_phy_reset(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 phy_ctrl;
+
+ phy_ctrl = ioread32(port_base + PhyCtrl);
+ phy_ctrl &= ~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10);
+ phy_ctrl |= PhyCtrlAne | PhyCtrlReset;
+
+ switch (media) {
+ default:
+ case AUTOSELECT:
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
+ break;
+ case M10_HALF:
+ phy_ctrl |= PhyCtrlSpd10;
+ break;
+ case M10_FULL:
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd10;
+ break;
+ case M100_HALF:
+ phy_ctrl |= PhyCtrlSpd100;
+ break;
+ case M100_FULL:
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
+ break;
+ }
+
+ iowrite32(phy_ctrl, port_base + PhyCtrl);
+ mdelay(10);
+
+ phy_ctrl &= ~PhyCtrlReset;
+ iowrite32(phy_ctrl, port_base + PhyCtrl);
+ mdelay(1);
+
+ _sc92031_mii_write(port_base, MII_JAB,
+ PHY_16_JAB_ENB | PHY_16_PORT_ENB);
+ _sc92031_mii_scan(port_base);
+
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+}
+
+static void _sc92031_reset(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ /* disable PM */
+ iowrite32(0, port_base + PMConfig);
+
+ /* soft reset the chip */
+ iowrite32(Cfg0_Reset, port_base + Config0);
+ mdelay(200);
+
+ iowrite32(0, port_base + Config0);
+ mdelay(10);
+
+ /* disable interrupts */
+ iowrite32(0, port_base + IntrMask);
+
+ /* clear multicast address */
+ iowrite32(0, port_base + MAR0);
+ iowrite32(0, port_base + MAR0 + 4);
+
+ /* init rx ring */
+ iowrite32(priv->rx_ring_dma_addr, port_base + RxbufAddr);
+ priv->rx_ring_tail = priv->rx_ring_dma_addr;
+
+ /* init tx ring */
+ _sc92031_tx_clear(dev);
+
+ /* clear old register values */
+ priv->intr_status = 0;
+ atomic_set(&priv->intr_mask, 0);
+ priv->rx_config = 0;
+ priv->tx_config = 0;
+ priv->mc_flags = 0;
+
+ /* configure rx buffer size */
+ /* NOTE: vendor driver had dead code here to enable early tx/rx */
+ iowrite32(Cfg1_Rcv64K, port_base + Config1);
+
+ _sc92031_phy_reset(dev);
+ _sc92031_check_media(dev);
+
+ /* calculate rx fifo overflow */
+ priv->rx_value = 0;
+
+ /* enable PM */
+ iowrite32(priv->pm_config, port_base + PMConfig);
+
+ /* clear intr register */
+ ioread32(port_base + IntrStatus);
+}
+
+static void _sc92031_tx_tasklet(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ unsigned old_tx_tail;
+ unsigned entry;
+ u32 tx_status;
+
+ old_tx_tail = priv->tx_tail;
+ while (priv->tx_head - priv->tx_tail > 0) {
+ entry = priv->tx_tail % NUM_TX_DESC;
+ tx_status = ioread32(port_base + TxStatus0 + entry * 4);
+
+ if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted)))
+ break;
+
+ priv->tx_tail++;
+
+ if (tx_status & TxStatOK) {
+ priv->stats.tx_bytes += tx_status & 0x1fff;
+ priv->stats.tx_packets++;
+ /* Note: TxCarrierLost is always asserted at 100mbps. */
+ priv->stats.collisions += (tx_status >> 22) & 0xf;
+ }
+
+ if (tx_status & (TxOutOfWindow | TxAborted)) {
+ priv->stats.tx_errors++;
+
+ if (tx_status & TxAborted)
+ priv->stats.tx_aborted_errors++;
+
+ if (tx_status & TxCarrierLost)
+ priv->stats.tx_carrier_errors++;
+
+ if (tx_status & TxOutOfWindow)
+ priv->stats.tx_window_errors++;
+ }
+
+ if (tx_status & TxUnderrun)
+ priv->stats.tx_fifo_errors++;
+ }
+
+ if (priv->tx_tail != old_tx_tail)
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+}
+
+static void _sc92031_rx_tasklet_error(u32 rx_status,
+ struct sc92031_priv *priv, unsigned rx_size)
+{
+ if(rx_size > (MAX_ETH_FRAME_SIZE + 4) || rx_size < 16) {
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
+ }
+
+ if (!(rx_status & RxStatesOK)) {
+ priv->stats.rx_errors++;
+
+ if (rx_status & (RxHugeFrame | RxSmallFrame))
+ priv->stats.rx_length_errors++;
+
+ if (rx_status & RxBadAlign)
+ priv->stats.rx_frame_errors++;
+
+ if (!(rx_status & RxCRCOK))
+ priv->stats.rx_crc_errors++;
+ } else
+ priv->rx_loss++;
+}
+
+static void _sc92031_rx_tasklet(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ dma_addr_t rx_ring_head;
+ unsigned rx_len;
+ unsigned rx_ring_offset;
+ void *rx_ring = priv->rx_ring;
+
+ rx_ring_head = ioread32(port_base + RxBufWPtr);
+ rmb();
+
+ /* rx_ring_head is only 17 bits in the RxBufWPtr register.
+ * we need to change it to 32 bits physical address
+ */
+ rx_ring_head &= (dma_addr_t)(RX_BUF_LEN - 1);
+ rx_ring_head |= priv->rx_ring_dma_addr & ~(dma_addr_t)(RX_BUF_LEN - 1);
+ if (rx_ring_head < priv->rx_ring_dma_addr)
+ rx_ring_head += RX_BUF_LEN;
+
+ if (rx_ring_head >= priv->rx_ring_tail)
+ rx_len = rx_ring_head - priv->rx_ring_tail;
+ else
+ rx_len = RX_BUF_LEN - (priv->rx_ring_tail - rx_ring_head);
+
+ if (!rx_len)
+ return;
+
+ if (unlikely(rx_len > RX_BUF_LEN)) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "%s: rx packets length > rx buffer\n",
+ dev->name);
+ return;
+ }
+
+ rx_ring_offset = (priv->rx_ring_tail - priv->rx_ring_dma_addr) % RX_BUF_LEN;
+
+ while (rx_len) {
+ u32 rx_status;
+ unsigned rx_size, rx_size_align, pkt_size;
+ struct sk_buff *skb;
+
+ rx_status = le32_to_cpup((__le32 *)(rx_ring + rx_ring_offset));
+ rmb();
+
+ rx_size = rx_status >> 20;
+ rx_size_align = (rx_size + 3) & ~3; // for 4 bytes aligned
+ pkt_size = rx_size - 4; // Omit the four octet CRC from the length.
+
+ rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN;
+
+ if (unlikely(rx_status == 0
+ || rx_size > (MAX_ETH_FRAME_SIZE + 4)
+ || rx_size < 16
+ || !(rx_status & RxStatesOK))) {
+ _sc92031_rx_tasklet_error(rx_status, priv, rx_size);
+ break;
+ }
+
+ if (unlikely(rx_size_align + 4 > rx_len)) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "%s: rx_len is too small\n", dev->name);
+ break;
+ }
+
+ rx_len -= rx_size_align + 4;
+
+ skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
+ if (unlikely(!skb)) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n",
+ dev->name, pkt_size);
+ goto next;
+ }
+
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) {
+ memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset),
+ rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset);
+ memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)),
+ rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset));
+ } else {
+ memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size);
+ }
+
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ dev->last_rx = jiffies;
+ netif_rx(skb);
+
+ priv->stats.rx_bytes += pkt_size;
+ priv->stats.rx_packets++;
+
+ if (rx_status & Rx_Multicast)
+ priv->stats.multicast++;
+
+ next:
+ rx_ring_offset = (rx_ring_offset + rx_size_align) % RX_BUF_LEN;
+ }
+ mb();
+
+ priv->rx_ring_tail = rx_ring_head;
+ iowrite32(priv->rx_ring_tail, port_base + RxBufRPtr);
+}
+
+static void _sc92031_link_tasklet(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ if (_sc92031_check_media(dev))
+ netif_wake_queue(dev);
+ else {
+ netif_stop_queue(dev);
+ priv->stats.tx_carrier_errors++;
+ }
+}
+
+static void sc92031_tasklet(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 intr_status, intr_mask;
+
+ intr_status = priv->intr_status;
+
+ spin_lock(&priv->lock);
+
+ if (unlikely(!netif_running(dev)))
+ goto out;
+
+ if (intr_status & TxOK)
+ _sc92031_tx_tasklet(dev);
+
+ if (intr_status & RxOK)
+ _sc92031_rx_tasklet(dev);
+
+ if (intr_status & RxOverflow)
+ priv->stats.rx_errors++;
+
+ if (intr_status & TimeOut) {
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
+ }
+
+ if (intr_status & (LinkFail | LinkOK))
+ _sc92031_link_tasklet(dev);
+
+out:
+ intr_mask = atomic_read(&priv->intr_mask);
+ rmb();
+
+ iowrite32(intr_mask, port_base + IntrMask);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+}
+
+static irqreturn_t sc92031_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 intr_status, intr_mask;
+
+ /* mask interrupts before clearing IntrStatus */
+ iowrite32(0, port_base + IntrMask);
+ _sc92031_dummy_read(port_base);
+
+ intr_status = ioread32(port_base + IntrStatus);
+ if (unlikely(intr_status == 0xffffffff))
+ return IRQ_NONE; // hardware has gone missing
+
+ intr_status &= IntrBits;
+ if (!intr_status)
+ goto out_none;
+
+ priv->intr_status = intr_status;
+ tasklet_schedule(&priv->tasklet);
+
+ return IRQ_HANDLED;
+
+out_none:
+ intr_mask = atomic_read(&priv->intr_mask);
+ rmb();
+
+ iowrite32(intr_mask, port_base + IntrMask);
+ mmiowb();
+
+ return IRQ_NONE;
+}
+
+static struct net_device_stats *sc92031_get_stats(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ // FIXME I do not understand what is this trying to do.
+ if (netif_running(dev)) {
+ int temp;
+
+ spin_lock_bh(&priv->lock);
+
+ /* Update the error count. */
+ temp = (ioread32(port_base + RxStatus0) >> 16) & 0xffff;
+
+ if (temp == 0xffff) {
+ priv->rx_value += temp;
+ priv->stats.rx_fifo_errors = priv->rx_value;
+ } else {
+ priv->stats.rx_fifo_errors = temp + priv->rx_value;
+ }
+
+ spin_unlock_bh(&priv->lock);
+ }
+
+ return &priv->stats;
+}
+
+static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int err = 0;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ unsigned len;
+ unsigned entry;
+ u32 tx_status;
+
+ if (unlikely(skb->len > TX_BUF_SIZE)) {
+ err = -EMSGSIZE;
+ priv->stats.tx_dropped++;
+ goto out;
+ }
+
+ spin_lock_bh(&priv->lock);
+
+ if (unlikely(!netif_carrier_ok(dev))) {
+ err = -ENOLINK;
+ priv->stats.tx_dropped++;
+ goto out_unlock;
+ }
+
+ BUG_ON(priv->tx_head - priv->tx_tail >= NUM_TX_DESC);
+
+ entry = priv->tx_head++ % NUM_TX_DESC;
+
+ skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE);
+
+ len = skb->len;
+ if (unlikely(len < ETH_ZLEN)) {
+ memset(priv->tx_bufs + entry * TX_BUF_SIZE + len,
+ 0, ETH_ZLEN - len);
+ len = ETH_ZLEN;
+ }
+
+ wmb();
+
+ if (len < 100)
+ tx_status = len;
+ else if (len < 300)
+ tx_status = 0x30000 | len;
+ else
+ tx_status = 0x50000 | len;
+
+ iowrite32(priv->tx_bufs_dma_addr + entry * TX_BUF_SIZE,
+ port_base + TxAddr0 + entry * 4);
+ iowrite32(tx_status, port_base + TxStatus0 + entry * 4);
+ mmiowb();
+
+ dev->trans_start = jiffies;
+
+ if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC)
+ netif_stop_queue(dev);
+
+out_unlock:
+ spin_unlock_bh(&priv->lock);
+
+out:
+ dev_kfree_skb(skb);
+
+ return err;
+}
+
+static int sc92031_open(struct net_device *dev)
+{
+ int err;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ struct pci_dev *pdev = priv->pdev;
+
+ priv->rx_ring = pci_alloc_consistent(pdev, RX_BUF_LEN,
+ &priv->rx_ring_dma_addr);
+ if (unlikely(!priv->rx_ring)) {
+ err = -ENOMEM;
+ goto out_alloc_rx_ring;
+ }
+
+ priv->tx_bufs = pci_alloc_consistent(pdev, TX_BUF_TOT_LEN,
+ &priv->tx_bufs_dma_addr);
+ if (unlikely(!priv->tx_bufs)) {
+ err = -ENOMEM;
+ goto out_alloc_tx_bufs;
+ }
+ priv->tx_head = priv->tx_tail = 0;
+
+ err = request_irq(pdev->irq, sc92031_interrupt,
+ SA_SHIRQ, dev->name, dev);
+ if (unlikely(err < 0))
+ goto out_request_irq;
+
+ priv->pm_config = 0;
+
+ /* Interrupts already disabled by sc92031_stop or sc92031_probe */
+ spin_lock(&priv->lock);
+
+ _sc92031_reset(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+ sc92031_enable_interrupts(dev);
+
+ if (netif_carrier_ok(dev))
+ netif_start_queue(dev);
+ else
+ netif_tx_disable(dev);
+
+ return 0;
+
+out_request_irq:
+ pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
+ priv->tx_bufs_dma_addr);
+out_alloc_tx_bufs:
+ pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
+ priv->rx_ring_dma_addr);
+out_alloc_rx_ring:
+ return err;
+}
+
+static int sc92031_stop(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ struct pci_dev *pdev = priv->pdev;
+
+ netif_tx_disable(dev);
+
+ /* Disable interrupts, stop Tx and Rx. */
+ sc92031_disable_interrupts(dev);
+
+ spin_lock(&priv->lock);
+
+ _sc92031_disable_tx_rx(dev);
+ _sc92031_tx_clear(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+
+ free_irq(pdev->irq, dev);
+ pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
+ priv->tx_bufs_dma_addr);
+ pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
+ priv->rx_ring_dma_addr);
+
+ return 0;
+}
+
+static void sc92031_set_multicast_list(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ spin_lock_bh(&priv->lock);
+
+ _sc92031_set_mar(dev);
+ _sc92031_set_rx_config(dev);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+}
+
+static void sc92031_tx_timeout(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ /* Disable interrupts by clearing the interrupt mask.*/
+ sc92031_disable_interrupts(dev);
+
+ spin_lock(&priv->lock);
+
+ priv->tx_timeouts++;
+
+ _sc92031_reset(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+
+ /* enable interrupts */
+ sc92031_enable_interrupts(dev);
+
+ if (netif_carrier_ok(dev))
+ netif_wake_queue(dev);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void sc92031_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ if (sc92031_interrupt(dev->irq, dev) != IRQ_NONE)
+ sc92031_tasklet((unsigned long)dev);
+ enable_irq(dev->irq);
+}
+#endif
+
+static int sc92031_ethtool_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u8 phy_address;
+ u32 phy_ctrl;
+ u16 output_status;
+
+ spin_lock_bh(&priv->lock);
+
+ phy_address = ioread32(port_base + Miicmd1) >> 27;
+ phy_ctrl = ioread32(port_base + PhyCtrl);
+
+ output_status = _sc92031_mii_read(port_base, MII_OutputStatus);
+ _sc92031_mii_scan(port_base);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+
+ cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII;
+
+ cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+
+ if ((phy_ctrl & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
+ == (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
+ cmd->advertising |= ADVERTISED_Autoneg;
+
+ if ((phy_ctrl & PhyCtrlSpd10) == PhyCtrlSpd10)
+ cmd->advertising |= ADVERTISED_10baseT_Half;
+
+ if ((phy_ctrl & (PhyCtrlSpd10 | PhyCtrlDux))
+ == (PhyCtrlSpd10 | PhyCtrlDux))
+ cmd->advertising |= ADVERTISED_10baseT_Full;
+
+ if ((phy_ctrl & PhyCtrlSpd100) == PhyCtrlSpd100)
+ cmd->advertising |= ADVERTISED_100baseT_Half;
+
+ if ((phy_ctrl & (PhyCtrlSpd100 | PhyCtrlDux))
+ == (PhyCtrlSpd100 | PhyCtrlDux))
+ cmd->advertising |= ADVERTISED_100baseT_Full;
+
+ if (phy_ctrl & PhyCtrlAne)
+ cmd->advertising |= ADVERTISED_Autoneg;
+
+ cmd->speed = (output_status & 0x2) ? SPEED_100 : SPEED_10;
+ cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF;
+ cmd->port = PORT_MII;
+ cmd->phy_address = phy_address;
+ cmd->transceiver = XCVR_INTERNAL;
+ cmd->autoneg = (phy_ctrl & PhyCtrlAne) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+ return 0;
+}
+
+static int sc92031_ethtool_set_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 phy_ctrl;
+ u32 old_phy_ctrl;
+
+ if (!(cmd->speed == SPEED_10 || cmd->speed == SPEED_100))
+ return -EINVAL;
+ if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL))
+ return -EINVAL;
+ if (!(cmd->port == PORT_MII))
+ return -EINVAL;
+ if (!(cmd->phy_address == 0x1f))
+ return -EINVAL;
+ if (!(cmd->transceiver == XCVR_INTERNAL))
+ return -EINVAL;
+ if (!(cmd->autoneg == AUTONEG_DISABLE || cmd->autoneg == AUTONEG_ENABLE))
+ return -EINVAL;
+
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ if (!(cmd->advertising & (ADVERTISED_Autoneg
+ | ADVERTISED_100baseT_Full
+ | ADVERTISED_100baseT_Half
+ | ADVERTISED_10baseT_Full
+ | ADVERTISED_10baseT_Half)))
+ return -EINVAL;
+
+ phy_ctrl = PhyCtrlAne;
+
+ // FIXME: I'm not sure what the original code was trying to do
+ if (cmd->advertising & ADVERTISED_Autoneg)
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
+ if (cmd->advertising & ADVERTISED_100baseT_Full)
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
+ if (cmd->advertising & ADVERTISED_100baseT_Half)
+ phy_ctrl |= PhyCtrlSpd100;
+ if (cmd->advertising & ADVERTISED_10baseT_Full)
+ phy_ctrl |= PhyCtrlSpd10 | PhyCtrlDux;
+ if (cmd->advertising & ADVERTISED_10baseT_Half)
+ phy_ctrl |= PhyCtrlSpd10;
+ } else {
+ // FIXME: Whole branch guessed
+ phy_ctrl = 0;
+
+ if (cmd->speed == SPEED_10)
+ phy_ctrl |= PhyCtrlSpd10;
+ else /* cmd->speed == SPEED_100 */
+ phy_ctrl |= PhyCtrlSpd100;
+
+ if (cmd->duplex == DUPLEX_FULL)
+ phy_ctrl |= PhyCtrlDux;
+ }
+
+ spin_lock_bh(&priv->lock);
+
+ old_phy_ctrl = ioread32(port_base + PhyCtrl);
+ phy_ctrl |= old_phy_ctrl & ~(PhyCtrlAne | PhyCtrlDux
+ | PhyCtrlSpd100 | PhyCtrlSpd10);
+ if (phy_ctrl != old_phy_ctrl)
+ iowrite32(phy_ctrl, port_base + PhyCtrl);
+
+ spin_unlock_bh(&priv->lock);
+
+ return 0;
+}
+
+static void sc92031_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ struct pci_dev *pdev = priv->pdev;
+
+ strcpy(drvinfo->driver, SC92031_NAME);
+ strcpy(drvinfo->version, SC92031_VERSION);
+ strcpy(drvinfo->bus_info, pci_name(pdev));
+}
+
+static void sc92031_ethtool_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 pm_config;
+
+ spin_lock_bh(&priv->lock);
+ pm_config = ioread32(port_base + PMConfig);
+ spin_unlock_bh(&priv->lock);
+
+ // FIXME: Guessed
+ wolinfo->supported = WAKE_PHY | WAKE_MAGIC
+ | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+ wolinfo->wolopts = 0;
+
+ if (pm_config & PM_LinkUp)
+ wolinfo->wolopts |= WAKE_PHY;
+
+ if (pm_config & PM_Magic)
+ wolinfo->wolopts |= WAKE_MAGIC;
+
+ if (pm_config & PM_WakeUp)
+ // FIXME: Guessed
+ wolinfo->wolopts |= WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+}
+
+static int sc92031_ethtool_set_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 pm_config;
+
+ spin_lock_bh(&priv->lock);
+
+ pm_config = ioread32(port_base + PMConfig)
+ & ~(PM_LinkUp | PM_Magic | PM_WakeUp);
+
+ if (wolinfo->wolopts & WAKE_PHY)
+ pm_config |= PM_LinkUp;
+
+ if (wolinfo->wolopts & WAKE_MAGIC)
+ pm_config |= PM_Magic;
+
+ // FIXME: Guessed
+ if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST))
+ pm_config |= PM_WakeUp;
+
+ priv->pm_config = pm_config;
+ iowrite32(pm_config, port_base + PMConfig);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+
+ return 0;
+}
+
+static int sc92031_ethtool_nway_reset(struct net_device *dev)
+{
+ int err = 0;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u16 bmcr;
+
+ spin_lock_bh(&priv->lock);
+
+ bmcr = _sc92031_mii_read(port_base, MII_BMCR);
+ if (!(bmcr & BMCR_ANENABLE)) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ _sc92031_mii_write(port_base, MII_BMCR, bmcr | BMCR_ANRESTART);
+
+out:
+ _sc92031_mii_scan(port_base);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+
+ return err;
+}
+
+static const char sc92031_ethtool_stats_strings[SILAN_STATS_NUM][ETH_GSTRING_LEN] = {
+ "tx_timeout",
+ "rx_loss",
+};
+
+static void sc92031_ethtool_get_strings(struct net_device *dev,
+ u32 stringset, u8 *data)
+{
+ if (stringset == ETH_SS_STATS)
+ memcpy(data, sc92031_ethtool_stats_strings,
+ SILAN_STATS_NUM * ETH_GSTRING_LEN);
+}
+
+static int sc92031_ethtool_get_stats_count(struct net_device *dev)
+{
+ return SILAN_STATS_NUM;
+}
+
+static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ spin_lock_bh(&priv->lock);
+ data[0] = priv->tx_timeouts;
+ data[1] = priv->rx_loss;
+ spin_unlock_bh(&priv->lock);
+}
+
+static struct ethtool_ops sc92031_ethtool_ops = {
+ .get_settings = sc92031_ethtool_get_settings,
+ .set_settings = sc92031_ethtool_set_settings,
+ .get_drvinfo = sc92031_ethtool_get_drvinfo,
+ .get_wol = sc92031_ethtool_get_wol,
+ .set_wol = sc92031_ethtool_set_wol,
+ .nway_reset = sc92031_ethtool_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .get_tso = ethtool_op_get_tso,
+ .get_strings = sc92031_ethtool_get_strings,
+ .get_stats_count = sc92031_ethtool_get_stats_count,
+ .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_ufo = ethtool_op_get_ufo,
+};
+
+static int __devinit sc92031_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int err;
+ void __iomem* port_base;
+ struct net_device *dev;
+ struct sc92031_priv *priv;
+ u32 mac0, mac1;
+
+ err = pci_enable_device(pdev);
+ if (unlikely(err < 0))
+ goto out_enable_device;
+
+ pci_set_master(pdev);
+
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (unlikely(err < 0))
+ goto out_set_dma_mask;
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (unlikely(err < 0))
+ goto out_set_dma_mask;
+
+ err = pci_request_regions(pdev, SC92031_NAME);
+ if (unlikely(err < 0))
+ goto out_request_regions;
+
+ port_base = pci_iomap(pdev, SC92031_USE_BAR, 0);
+ if (unlikely(!port_base)) {
+ err = -EIO;
+ goto out_iomap;
+ }
+
+ dev = alloc_etherdev(sizeof(struct sc92031_priv));
+ if (unlikely(!dev)) {
+ err = -ENOMEM;
+ goto out_alloc_etherdev;
+ }
+
+ pci_set_drvdata(pdev, dev);
+
+#if SC92031_USE_BAR == 0
+ dev->mem_start = pci_resource_start(pdev, SC92031_USE_BAR);
+ dev->mem_end = pci_resource_end(pdev, SC92031_USE_BAR);
+#elif SC92031_USE_BAR == 1
+ dev->base_addr = pci_resource_start(pdev, SC92031_USE_BAR);
+#endif
+ dev->irq = pdev->irq;
+
+ /* faked with skb_copy_and_csum_dev */
+ dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
+
+ dev->get_stats = sc92031_get_stats;
+ dev->ethtool_ops = &sc92031_ethtool_ops;
+ dev->hard_start_xmit = sc92031_start_xmit;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->open = sc92031_open;
+ dev->stop = sc92031_stop;
+ dev->set_multicast_list = sc92031_set_multicast_list;
+ dev->tx_timeout = sc92031_tx_timeout;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = sc92031_poll_controller;
+#endif
+
+ priv = netdev_priv(dev);
+ spin_lock_init(&priv->lock);
+ priv->port_base = port_base;
+ priv->pdev = pdev;
+ tasklet_init(&priv->tasklet, sc92031_tasklet, (unsigned long)dev);
+ /* Fudge tasklet count so the call to sc92031_enable_interrupts at
+ * sc92031_open will work correctly */
+ tasklet_disable_nosync(&priv->tasklet);
+
+ /* PCI PM Wakeup */
+ iowrite32((~PM_LongWF & ~PM_LWPTN) | PM_Enable, port_base + PMConfig);
+
+ mac0 = ioread32(port_base + MAC0);
+ mac1 = ioread32(port_base + MAC0 + 4);
+ dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24;
+ dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16;
+ dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8;
+ dev->dev_addr[3] = dev->perm_addr[3] = mac0;
+ dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8;
+ dev->dev_addr[5] = dev->perm_addr[5] = mac1;
+
+ err = register_netdev(dev);
+ if (err < 0)
+ goto out_register_netdev;
+
+ return 0;
+
+out_register_netdev:
+ free_netdev(dev);
+out_alloc_etherdev:
+ pci_iounmap(pdev, port_base);
+out_iomap:
+ pci_release_regions(pdev);
+out_request_regions:
+out_set_dma_mask:
+ pci_disable_device(pdev);
+out_enable_device:
+ return err;
+}
+
+static void __devexit sc92031_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem* port_base = priv->port_base;
+
+ unregister_netdev(dev);
+ free_netdev(dev);
+ pci_iounmap(pdev, port_base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static int sc92031_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ pci_save_state(pdev);
+
+ if (!netif_running(dev))
+ goto out;
+
+ netif_device_detach(dev);
+
+ /* Disable interrupts, stop Tx and Rx. */
+ sc92031_disable_interrupts(dev);
+
+ spin_lock(&priv->lock);
+
+ _sc92031_disable_tx_rx(dev);
+ _sc92031_tx_clear(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+
+out:
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int sc92031_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ pci_restore_state(pdev);
+ pci_set_power_state(pdev, PCI_D0);
+
+ if (!netif_running(dev))
+ goto out;
+
+ /* Interrupts already disabled by sc92031_suspend */
+ spin_lock(&priv->lock);
+
+ _sc92031_reset(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+ sc92031_enable_interrupts(dev);
+
+ netif_device_attach(dev);
+
+ if (netif_carrier_ok(dev))
+ netif_wake_queue(dev);
+ else
+ netif_tx_disable(dev);
+
+out:
+ return 0;
+}
+
+static struct pci_device_id sc92031_pci_device_id_table[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_SC92031) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_8139D) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table);
+
+static struct pci_driver sc92031_pci_driver = {
+ .name = SC92031_NAME,
+ .id_table = sc92031_pci_device_id_table,
+ .probe = sc92031_probe,
+ .remove = __devexit_p(sc92031_remove),
+ .suspend = sc92031_suspend,
+ .resume = sc92031_resume,
+};
+
+static int __init sc92031_init(void)
+{
+ printk(KERN_INFO SC92031_DESCRIPTION " " SC92031_VERSION "\n");
+ return pci_register_driver(&sc92031_pci_driver);
+}
+
+static void __exit sc92031_exit(void)
+{
+ pci_unregister_driver(&sc92031_pci_driver);
+}
+
+module_init(sc92031_init);
+module_exit(sc92031_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cesar Eduardo Barros <cesarb@cesarb.net>");
+MODULE_DESCRIPTION(SC92031_DESCRIPTION);
+MODULE_VERSION(SC92031_VERSION);
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index b70ed79d412..45d91b15910 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -1562,7 +1562,7 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
for (i = 0; i < MAC_ADDR_LEN / 2; i++) {
__le16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i);
- ((u16 *)dev->dev_addr)[0] = le16_to_cpu(w);
+ ((u16 *)dev->dev_addr)[i] = le16_to_cpu(w);
}
sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo));
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
deleted file mode 100644
index 96e06c51b75..00000000000
--- a/drivers/net/sk_mca.c
+++ /dev/null
@@ -1,1216 +0,0 @@
-/*
-net-3-driver for the SKNET MCA-based cards
-
-This is an extension to the Linux operating system, and is covered by the
-same GNU General Public License that covers that work.
-
-Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
- alfred.arnold@lancom.de)
-
-This driver is based both on the 3C523 driver and the SK_G16 driver.
-
-paper sources:
- 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
- Hans-Peter Messmer for the basic Microchannel stuff
-
- 'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
- for help on Ethernet driver programming
-
- 'Ethernet/IEEE 802.3 Family 1992 World Network Data Book/Handbook' by AMD
- for documentation on the AM7990 LANCE
-
- 'SKNET Personal Technisches Manual', Version 1.2 by Schneider&Koch
- for documentation on the Junior board
-
- 'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for
- documentation on the MC2 bord
-
- A big thank you to the S&K support for providing me so quickly with
- documentation!
-
- Also see http://www.syskonnect.com/
-
- Missing things:
-
- -> set debug level via ioctl instead of compile-time switches
- -> I didn't follow the development of the 2.1.x kernels, so my
- assumptions about which things changed with which kernel version
- are probably nonsense
-
-History:
- May 16th, 1999
- startup
- May 22st, 1999
- added private structure, methods
- begun building data structures in RAM
- May 23nd, 1999
- can receive frames, send frames
- May 24th, 1999
- modularized initialization of LANCE
- loadable as module
- still Tx problem :-(
- May 26th, 1999
- MC2 works
- support for multiple devices
- display media type for MC2+
- May 28th, 1999
- fixed problem in GetLANCE leaving interrupts turned off
- increase TX queue to 4 packets to improve send performance
- May 29th, 1999
- a few corrections in statistics, caught rcvr overruns
- reinitialization of LANCE/board in critical situations
- MCA info implemented
- implemented LANCE multicast filter
- Jun 6th, 1999
- additions for Linux 2.2
- Dec 25th, 1999
- unfortunately there seem to be newer MC2+ boards that react
- on IRQ 3/5/9/10 instead of 3/5/10/11, so we have to autoprobe
- in questionable cases...
- Dec 28th, 1999
- integrated patches from David Weinehall & Bill Wendling for 2.3
- kernels (isa_...functions). Things are defined in a way that
- it still works with 2.0.x 8-)
- Dec 30th, 1999
- added handling of the remaining interrupt conditions. That
- should cure the spurious hangs.
- Jan 30th, 2000
- newer kernels automatically probe more than one board, so the
- 'startslot' as a variable is also needed here
- June 1st, 2000
- added changes for recent 2.3 kernels
-
- *************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/mca-legacy.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/processor.h>
-#include <asm/io.h>
-
-#define _SK_MCA_DRIVER_
-#include "sk_mca.h"
-
-/* ------------------------------------------------------------------------
- * global static data - not more since we can handle multiple boards and
- * have to pack all state info into the device struct!
- * ------------------------------------------------------------------------ */
-
-static char *MediaNames[Media_Count] =
- { "10Base2", "10BaseT", "10Base5", "Unknown" };
-
-static unsigned char poly[] =
- { 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0
-};
-
-/* ------------------------------------------------------------------------
- * private subfunctions
- * ------------------------------------------------------------------------ */
-
-/* dump parts of shared memory - only needed during debugging */
-
-#ifdef DEBUG
-static void dumpmem(struct net_device *dev, u32 start, u32 len)
-{
- skmca_priv *priv = netdev_priv(dev);
- int z;
-
- for (z = 0; z < len; z++) {
- if ((z & 15) == 0)
- printk("%04x:", z);
- printk(" %02x", readb(priv->base + start + z));
- if ((z & 15) == 15)
- printk("\n");
- }
-}
-
-/* print exact time - ditto */
-
-static void PrTime(void)
-{
- struct timeval tv;
-
- do_gettimeofday(&tv);
- printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
-}
-#endif
-
-/* deduce resources out of POS registers */
-
-static void __init getaddrs(int slot, int junior, int *base, int *irq,
- skmca_medium * medium)
-{
- u_char pos0, pos1, pos2;
-
- if (junior) {
- pos0 = mca_read_stored_pos(slot, 2);
- *base = ((pos0 & 0x0e) << 13) + 0xc0000;
- *irq = ((pos0 & 0x10) >> 4) + 10;
- *medium = Media_Unknown;
- } else {
- /* reset POS 104 Bits 0+1 so the shared memory region goes to the
- configured area between 640K and 1M. Afterwards, enable the MC2.
- I really don't know what rode SK to do this... */
-
- mca_write_pos(slot, 4,
- mca_read_stored_pos(slot, 4) & 0xfc);
- mca_write_pos(slot, 2,
- mca_read_stored_pos(slot, 2) | 0x01);
-
- pos1 = mca_read_stored_pos(slot, 3);
- pos2 = mca_read_stored_pos(slot, 4);
- *base = ((pos1 & 0x07) << 14) + 0xc0000;
- switch (pos2 & 0x0c) {
- case 0:
- *irq = 3;
- break;
- case 4:
- *irq = 5;
- break;
- case 8:
- *irq = -10;
- break;
- case 12:
- *irq = -11;
- break;
- }
- *medium = (pos2 >> 6) & 3;
- }
-}
-
-/* check for both cards:
- When the MC2 is turned off, it was configured for more than 15MB RAM,
- is disabled and won't get detected using the standard probe. We
- therefore have to scan the slots manually :-( */
-
-static int __init dofind(int *junior, int firstslot)
-{
- int slot;
- unsigned int id;
-
- for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++) {
- id = mca_read_stored_pos(slot, 0)
- + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8);
-
- *junior = 0;
- if (id == SKNET_MCA_ID)
- return slot;
- *junior = 1;
- if (id == SKNET_JUNIOR_MCA_ID)
- return slot;
- }
- return MCA_NOTFOUND;
-}
-
-/* reset the whole board */
-
-static void ResetBoard(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- writeb(CTRL_RESET_ON, priv->ctrladdr);
- udelay(10);
- writeb(CTRL_RESET_OFF, priv->ctrladdr);
-}
-
-/* wait for LANCE interface to become not busy */
-
-static int WaitLANCE(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- int t = 0;
-
- while ((readb(priv->ctrladdr) & STAT_IO_BUSY) ==
- STAT_IO_BUSY) {
- udelay(1);
- if (++t > 1000) {
- printk("%s: LANCE access timeout", dev->name);
- return 0;
- }
- }
-
- return 1;
-}
-
-/* set LANCE register - must be atomic */
-
-static void SetLANCE(struct net_device *dev, u16 addr, u16 value)
-{
- skmca_priv *priv = netdev_priv(dev);
- unsigned long flags;
-
- /* disable interrupts */
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* wait until no transfer is pending */
-
- WaitLANCE(dev);
-
- /* transfer register address to RAP */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
- writew(addr, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
-
- /* transfer data to register */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr);
- writew(value, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
-
- /* reenable interrupts */
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/* get LANCE register */
-
-static u16 GetLANCE(struct net_device *dev, u16 addr)
-{
- skmca_priv *priv = netdev_priv(dev);
- unsigned long flags;
- unsigned int res;
-
- /* disable interrupts */
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* wait until no transfer is pending */
-
- WaitLANCE(dev);
-
- /* transfer register address to RAP */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
- writew(addr, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
-
- /* transfer data from register */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
- res = readw(priv->ioregaddr);
-
- /* reenable interrupts */
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return res;
-}
-
-/* build up descriptors in shared RAM */
-
-static void InitDscrs(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- u32 bufaddr;
-
- /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
- are always 0. */
-
- bufaddr = RAM_DATABASE;
- {
- LANCE_TxDescr descr;
- int z;
-
- for (z = 0; z < TXCOUNT; z++) {
- descr.LowAddr = bufaddr;
- descr.Flags = 0;
- descr.Len = 0xf000;
- descr.Status = 0;
- memcpy_toio(priv->base + RAM_TXBASE +
- (z * sizeof(LANCE_TxDescr)), &descr,
- sizeof(LANCE_TxDescr));
- memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
- bufaddr += RAM_BUFSIZE;
- }
- }
-
- /* do the same for the Rx descriptors */
-
- {
- LANCE_RxDescr descr;
- int z;
-
- for (z = 0; z < RXCOUNT; z++) {
- descr.LowAddr = bufaddr;
- descr.Flags = RXDSCR_FLAGS_OWN;
- descr.MaxLen = -RAM_BUFSIZE;
- descr.Len = 0;
- memcpy_toio(priv->base + RAM_RXBASE +
- (z * sizeof(LANCE_RxDescr)), &descr,
- sizeof(LANCE_RxDescr));
- memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
- bufaddr += RAM_BUFSIZE;
- }
- }
-}
-
-/* calculate the hash bit position for a given multicast address
- taken more or less directly from the AMD datasheet... */
-
-static void UpdateCRC(unsigned char *CRC, int bit)
-{
- int j;
-
- /* shift CRC one bit */
-
- memmove(CRC + 1, CRC, 32 * sizeof(unsigned char));
- CRC[0] = 0;
-
- /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */
-
- if (bit ^ CRC[32])
- for (j = 0; j < 32; j++)
- CRC[j] ^= poly[j];
-}
-
-static unsigned int GetHash(char *address)
-{
- unsigned char CRC[33];
- int i, byte, hashcode;
-
- /* a multicast address has bit 0 in the first byte set */
-
- if ((address[0] & 1) == 0)
- return -1;
-
- /* initialize CRC */
-
- memset(CRC, 1, sizeof(CRC));
-
- /* loop through address bits */
-
- for (byte = 0; byte < 6; byte++)
- for (i = 0; i < 8; i++)
- UpdateCRC(CRC, (address[byte] >> i) & 1);
-
- /* hashcode is the 6 least significant bits of the CRC */
-
- hashcode = 0;
- for (i = 0; i < 6; i++)
- hashcode = (hashcode << 1) + CRC[i];
- return hashcode;
-}
-
-/* feed ready-built initialization block into LANCE */
-
-static void InitLANCE(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- /* build up descriptors. */
-
- InitDscrs(dev);
-
- /* next RX descriptor to be read is the first one. Since the LANCE
- will start from the beginning after initialization, we have to
- reset out pointers too. */
-
- priv->nextrx = 0;
-
- /* no TX descriptors active */
-
- priv->nexttxput = priv->nexttxdone = priv->txbusy = 0;
-
- /* set up the LANCE bus control register - constant for SKnet boards */
-
- SetLANCE(dev, LANCE_CSR3,
- CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD);
-
- /* write address of initialization block into LANCE */
-
- SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff);
- SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff);
-
- /* we don't get ready until the LANCE has read the init block */
-
- netif_stop_queue(dev);
-
- /* let LANCE read the initialization block. LANCE is ready
- when we receive the corresponding interrupt. */
-
- SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT);
-}
-
-/* stop the LANCE so we can reinitialize it */
-
-static void StopLANCE(struct net_device *dev)
-{
- /* can't take frames any more */
-
- netif_stop_queue(dev);
-
- /* disable interrupts, stop it */
-
- SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
-}
-
-/* initialize card and LANCE for proper operation */
-
-static void InitBoard(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_InitBlock block;
-
- /* Lay out the shared RAM - first we create the init block for the LANCE.
- We do not overwrite it later because we need it again when we switch
- promiscous mode on/off. */
-
- block.Mode = 0;
- if (dev->flags & IFF_PROMISC)
- block.Mode |= LANCE_INIT_PROM;
- memcpy(block.PAdr, dev->dev_addr, 6);
- memset(block.LAdrF, 0, sizeof(block.LAdrF));
- block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
- block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
-
- memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
-
- /* initialize LANCE. Implicitly sets up other structures in RAM. */
-
- InitLANCE(dev);
-}
-
-/* deinitialize card and LANCE */
-
-static void DeinitBoard(struct net_device *dev)
-{
- /* stop LANCE */
-
- StopLANCE(dev);
-
- /* reset board */
-
- ResetBoard(dev);
-}
-
-/* probe for device's irq */
-
-static int __init ProbeIRQ(struct net_device *dev)
-{
- unsigned long imaskval, njiffies, irq;
- u16 csr0val;
-
- /* enable all interrupts */
-
- imaskval = probe_irq_on();
-
- /* initialize the board. Wait for interrupt 'Initialization done'. */
-
- ResetBoard(dev);
- InitBoard(dev);
-
- njiffies = jiffies + HZ;
- do {
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- while (((csr0val & CSR0_IDON) == 0) && (jiffies != njiffies));
-
- /* turn of interrupts again */
-
- irq = probe_irq_off(imaskval);
-
- /* if we found something, ack the interrupt */
-
- if (irq)
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_IDON);
-
- /* back to idle state */
-
- DeinitBoard(dev);
-
- return irq;
-}
-
-/* ------------------------------------------------------------------------
- * interrupt handler(s)
- * ------------------------------------------------------------------------ */
-
-/* LANCE has read initialization block -> start it */
-
-static u16 irqstart_handler(struct net_device *dev, u16 oldcsr0)
-{
- /* now we're ready to transmit */
-
- netif_wake_queue(dev);
-
- /* reset IDON bit, start LANCE */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
- return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* did we lose blocks due to a FIFO overrun ? */
-
-static u16 irqmiss_handler(struct net_device *dev, u16 oldcsr0)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- /* update statistics */
-
- priv->stat.rx_fifo_errors++;
-
- /* reset MISS bit */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_MISS);
- return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* receive interrupt */
-
-static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_RxDescr descr;
- unsigned int descraddr;
-
- /* run through queue until we reach a descriptor we do not own */
-
- descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
- while (1) {
- /* read descriptor */
- memcpy_fromio(&descr, priv->base + descraddr,
- sizeof(LANCE_RxDescr));
-
- /* if we reach a descriptor we do not own, we're done */
- if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
- break;
-
-#ifdef DEBUG
- PrTime();
- printk("Receive packet on descr %d len %d\n", priv->nextrx,
- descr.Len);
-#endif
-
- /* erroneous packet ? */
- if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0) {
- priv->stat.rx_errors++;
- if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
- priv->stat.rx_crc_errors++;
- else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
- priv->stat.rx_frame_errors++;
- else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0)
- priv->stat.rx_fifo_errors++;
- }
-
- /* good packet ? */
- else {
- struct sk_buff *skb;
-
- skb = dev_alloc_skb(descr.Len + 2);
- if (skb == NULL)
- priv->stat.rx_dropped++;
- else {
- memcpy_fromio(skb_put(skb, descr.Len),
- priv->base +
- descr.LowAddr, descr.Len);
- skb->dev = dev;
- skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
- priv->stat.rx_packets++;
- priv->stat.rx_bytes += descr.Len;
- netif_rx(skb);
- dev->last_rx = jiffies;
- }
- }
-
- /* give descriptor back to LANCE */
- descr.Len = 0;
- descr.Flags |= RXDSCR_FLAGS_OWN;
-
- /* update descriptor in shared RAM */
- memcpy_toio(priv->base + descraddr, &descr,
- sizeof(LANCE_RxDescr));
-
- /* go to next descriptor */
- priv->nextrx++;
- descraddr += sizeof(LANCE_RxDescr);
- if (priv->nextrx >= RXCOUNT) {
- priv->nextrx = 0;
- descraddr = RAM_RXBASE;
- }
- }
-
- /* reset RINT bit */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT);
- return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* transmit interrupt */
-
-static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_TxDescr descr;
- unsigned int descraddr;
-
- /* check descriptors at most until no busy one is left */
-
- descraddr =
- RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
- while (priv->txbusy > 0) {
- /* read descriptor */
- memcpy_fromio(&descr, priv->base + descraddr,
- sizeof(LANCE_TxDescr));
-
- /* if the LANCE still owns this one, we've worked out all sent packets */
- if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
- break;
-
-#ifdef DEBUG
- PrTime();
- printk("Send packet done on descr %d\n", priv->nexttxdone);
-#endif
-
- /* update statistics */
- if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0) {
- priv->stat.tx_packets++;
- priv->stat.tx_bytes++;
- } else {
- priv->stat.tx_errors++;
- if ((descr.Status & TXDSCR_STATUS_UFLO) != 0) {
- priv->stat.tx_fifo_errors++;
- InitLANCE(dev);
- }
- else
- if ((descr.Status & TXDSCR_STATUS_LCOL) !=
- 0) priv->stat.tx_window_errors++;
- else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0)
- priv->stat.tx_carrier_errors++;
- else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0)
- priv->stat.tx_aborted_errors++;
- }
-
- /* go to next descriptor */
- priv->nexttxdone++;
- descraddr += sizeof(LANCE_TxDescr);
- if (priv->nexttxdone >= TXCOUNT) {
- priv->nexttxdone = 0;
- descraddr = RAM_TXBASE;
- }
- priv->txbusy--;
- }
-
- /* reset TX interrupt bit */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT);
- oldcsr0 = GetLANCE(dev, LANCE_CSR0);
-
- /* at least one descriptor is freed. Therefore we can accept
- a new one */
- /* inform upper layers we're in business again */
-
- netif_wake_queue(dev);
-
- return oldcsr0;
-}
-
-/* general interrupt entry */
-
-static irqreturn_t irq_handler(int irq, void *device)
-{
- struct net_device *dev = (struct net_device *) device;
- u16 csr0val;
-
- /* read CSR0 to get interrupt cause */
-
- csr0val = GetLANCE(dev, LANCE_CSR0);
-
- /* in case we're not meant... */
-
- if ((csr0val & CSR0_INTR) == 0)
- return IRQ_NONE;
-
-#if 0
- set_bit(LINK_STATE_RXSEM, &dev->state);
-#endif
-
- /* loop through the interrupt bits until everything is clear */
-
- do {
- if ((csr0val & CSR0_IDON) != 0)
- csr0val = irqstart_handler(dev, csr0val);
- if ((csr0val & CSR0_RINT) != 0)
- csr0val = irqrx_handler(dev, csr0val);
- if ((csr0val & CSR0_MISS) != 0)
- csr0val = irqmiss_handler(dev, csr0val);
- if ((csr0val & CSR0_TINT) != 0)
- csr0val = irqtx_handler(dev, csr0val);
- if ((csr0val & CSR0_MERR) != 0) {
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_MERR);
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- if ((csr0val & CSR0_BABL) != 0) {
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_BABL);
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- }
- while ((csr0val & CSR0_INTR) != 0);
-
-#if 0
- clear_bit(LINK_STATE_RXSEM, &dev->state);
-#endif
- return IRQ_HANDLED;
-}
-
-/* ------------------------------------------------------------------------
- * driver methods
- * ------------------------------------------------------------------------ */
-
-/* MCA info */
-
-static int skmca_getinfo(char *buf, int slot, void *d)
-{
- int len = 0, i;
- struct net_device *dev = (struct net_device *) d;
- skmca_priv *priv;
-
- /* can't say anything about an uninitialized device... */
-
- if (dev == NULL)
- return len;
- priv = netdev_priv(dev);
-
- /* print info */
-
- len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
- len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
- dev->mem_end - 1);
- len +=
- sprintf(buf + len, "Transceiver: %s\n",
- MediaNames[priv->medium]);
- len += sprintf(buf + len, "Device: %s\n", dev->name);
- len += sprintf(buf + len, "MAC address:");
- for (i = 0; i < 6; i++)
- len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
- buf[len++] = '\n';
- buf[len] = 0;
-
- return len;
-}
-
-/* open driver. Means also initialization and start of LANCE */
-
-static int skmca_open(struct net_device *dev)
-{
- int result;
- skmca_priv *priv = netdev_priv(dev);
-
- /* register resources - only necessary for IRQ */
- result =
- request_irq(priv->realirq, irq_handler,
- IRQF_SHARED | IRQF_SAMPLE_RANDOM, "sk_mca", dev);
- if (result != 0) {
- printk("%s: failed to register irq %d\n", dev->name,
- dev->irq);
- return result;
- }
- dev->irq = priv->realirq;
-
- /* set up the card and LANCE */
-
- InitBoard(dev);
-
- /* set up flags */
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-/* close driver. Shut down board and free allocated resources */
-
-static int skmca_close(struct net_device *dev)
-{
- /* turn off board */
- DeinitBoard(dev);
-
- /* release resources */
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- dev->irq = 0;
-
- return 0;
-}
-
-/* transmit a block. */
-
-static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_TxDescr descr;
- unsigned int address;
- int tmplen, retval = 0;
- unsigned long flags;
-
- /* if we get called with a NULL descriptor, the Ethernet layer thinks
- our card is stuck an we should reset it. We'll do this completely: */
-
- if (skb == NULL) {
- DeinitBoard(dev);
- InitBoard(dev);
- return 0; /* don't try to free the block here ;-) */
- }
-
- /* is there space in the Tx queue ? If no, the upper layer gave us a
- packet in spite of us not being ready and is really in trouble.
- We'll do the dropping for him: */
- if (priv->txbusy >= TXCOUNT) {
- priv->stat.tx_dropped++;
- retval = -EIO;
- goto tx_done;
- }
-
- /* get TX descriptor */
- address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
- memcpy_fromio(&descr, priv->base + address, sizeof(LANCE_TxDescr));
-
- /* enter packet length as 2s complement - assure minimum length */
- tmplen = skb->len;
- if (tmplen < 60)
- tmplen = 60;
- descr.Len = 65536 - tmplen;
-
- /* copy filler into RAM - in case we're filling up...
- we're filling a bit more than necessary, but that doesn't harm
- since the buffer is far larger... */
- if (tmplen > skb->len) {
- char *fill = "NetBSD is a nice OS too! ";
- unsigned int destoffs = 0, l = strlen(fill);
-
- while (destoffs < tmplen) {
- memcpy_toio(priv->base + descr.LowAddr +
- destoffs, fill, l);
- destoffs += l;
- }
- }
-
- /* do the real data copying */
- memcpy_toio(priv->base + descr.LowAddr, skb->data, skb->len);
-
- /* hand descriptor over to LANCE - this is the first and last chunk */
- descr.Flags =
- TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;
-
-#ifdef DEBUG
- PrTime();
- printk("Send packet on descr %d len %d\n", priv->nexttxput,
- skb->len);
-#endif
-
- /* one more descriptor busy */
-
- spin_lock_irqsave(&priv->lock, flags);
-
- priv->nexttxput++;
- if (priv->nexttxput >= TXCOUNT)
- priv->nexttxput = 0;
- priv->txbusy++;
-
- /* are we saturated ? */
-
- if (priv->txbusy >= TXCOUNT)
- netif_stop_queue(dev);
-
- /* write descriptor back to RAM */
- memcpy_toio(priv->base + address, &descr, sizeof(LANCE_TxDescr));
-
- /* if no descriptors were active, give the LANCE a hint to read it
- immediately */
-
- if (priv->txbusy == 0)
- SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- tx_done:
-
- dev_kfree_skb(skb);
-
- return retval;
-}
-
-/* return pointer to Ethernet statistics */
-
-static struct net_device_stats *skmca_stats(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- return &(priv->stat);
-}
-
-/* switch receiver mode. We use the LANCE's multicast filter to prefilter
- multicast addresses. */
-
-static void skmca_set_multicast_list(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_InitBlock block;
-
- /* first stop the LANCE... */
- StopLANCE(dev);
-
- /* ...then modify the initialization block... */
- memcpy_fromio(&block, priv->base + RAM_INITBASE, sizeof(block));
- if (dev->flags & IFF_PROMISC)
- block.Mode |= LANCE_INIT_PROM;
- else
- block.Mode &= ~LANCE_INIT_PROM;
-
- if (dev->flags & IFF_ALLMULTI) { /* get all multicasts */
- memset(block.LAdrF, 0xff, sizeof(block.LAdrF));
- } else { /* get selected/no multicasts */
-
- struct dev_mc_list *mptr;
- int code;
-
- memset(block.LAdrF, 0, sizeof(block.LAdrF));
- for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next) {
- code = GetHash(mptr->dmi_addr);
- block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7);
- }
- }
-
- memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
-
- /* ...then reinit LANCE with the correct flags */
- InitLANCE(dev);
-}
-
-/* ------------------------------------------------------------------------
- * hardware check
- * ------------------------------------------------------------------------ */
-
-static int startslot; /* counts through slots when probing multiple devices */
-
-static void cleanup_card(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- DeinitBoard(dev);
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- iounmap(priv->base);
- mca_mark_as_unused(priv->slot);
- mca_set_adapter_procfn(priv->slot, NULL, NULL);
-}
-
-struct net_device * __init skmca_probe(int unit)
-{
- struct net_device *dev;
- int force_detect = 0;
- int junior, slot, i;
- int base = 0, irq = 0;
- skmca_priv *priv;
- skmca_medium medium;
- int err;
-
- /* can't work without an MCA bus ;-) */
-
- if (MCA_bus == 0)
- return ERR_PTR(-ENODEV);
-
- dev = alloc_etherdev(sizeof(skmca_priv));
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- }
-
- SET_MODULE_OWNER(dev);
-
- /* start address of 1 --> forced detection */
-
- if (dev->mem_start == 1)
- force_detect = 1;
-
- /* search through slots */
-
- base = dev->mem_start;
- irq = dev->base_addr;
- for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) {
- /* deduce card addresses */
-
- getaddrs(slot, junior, &base, &irq, &medium);
-
- /* slot already in use ? */
-
- if (mca_is_adapter_used(slot))
- continue;
-
- /* were we looking for something different ? */
-
- if (dev->irq && dev->irq != irq)
- continue;
- if (dev->mem_start && dev->mem_start != base)
- continue;
-
- /* found something that matches */
-
- break;
- }
-
- /* nothing found ? */
-
- if (slot == -1) {
- free_netdev(dev);
- return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV);
- }
-
- /* make procfs entries */
-
- if (junior)
- mca_set_adapter_name(slot,
- "SKNET junior MC2 Ethernet Adapter");
- else
- mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter");
- mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);
-
- mca_mark_as_used(slot);
-
- /* announce success */
- printk("%s: SKNet %s adapter found in slot %d\n", dev->name,
- junior ? "Junior MC2" : "MC2+", slot + 1);
-
- priv = netdev_priv(dev);
- priv->base = ioremap(base, 0x4000);
- if (!priv->base) {
- mca_set_adapter_procfn(slot, NULL, NULL);
- mca_mark_as_unused(slot);
- free_netdev(dev);
- return ERR_PTR(-ENOMEM);
- }
-
- priv->slot = slot;
- priv->macbase = priv->base + 0x3fc0;
- priv->ioregaddr = priv->base + 0x3ff0;
- priv->ctrladdr = priv->base + 0x3ff2;
- priv->cmdaddr = priv->base + 0x3ff3;
- priv->medium = medium;
- memset(&priv->stat, 0, sizeof(struct net_device_stats));
- spin_lock_init(&priv->lock);
-
- /* set base + irq for this device (irq not allocated so far) */
- dev->irq = 0;
- dev->mem_start = base;
- dev->mem_end = base + 0x4000;
-
- /* autoprobe ? */
- if (irq < 0) {
- int nirq;
-
- printk
- ("%s: ambigous POS bit combination, must probe for IRQ...\n",
- dev->name);
- nirq = ProbeIRQ(dev);
- if (nirq <= 0)
- printk("%s: IRQ probe failed, assuming IRQ %d",
- dev->name, priv->realirq = -irq);
- else
- priv->realirq = nirq;
- } else
- priv->realirq = irq;
-
- /* set methods */
- dev->open = skmca_open;
- dev->stop = skmca_close;
- dev->hard_start_xmit = skmca_tx;
- dev->do_ioctl = NULL;
- dev->get_stats = skmca_stats;
- dev->set_multicast_list = skmca_set_multicast_list;
- dev->flags |= IFF_MULTICAST;
-
- /* copy out MAC address */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(priv->macbase + (i << 1));
-
- /* print config */
- printk("%s: IRQ %d, memory %#lx-%#lx, "
- "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
- dev->name, priv->realirq, dev->mem_start, dev->mem_end - 1,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
- printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]);
-
- /* reset board */
-
- ResetBoard(dev);
-
- startslot = slot + 1;
-
- err = register_netdev(dev);
- if (err) {
- cleanup_card(dev);
- free_netdev(dev);
- dev = ERR_PTR(err);
- }
- return dev;
-}
-
-/* ------------------------------------------------------------------------
- * modularization support
- * ------------------------------------------------------------------------ */
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-#define DEVMAX 5
-
-static struct net_device *moddevs[DEVMAX];
-
-int init_module(void)
-{
- int z;
-
- startslot = 0;
- for (z = 0; z < DEVMAX; z++) {
- struct net_device *dev = skmca_probe(-1);
- if (IS_ERR(dev))
- break;
- moddevs[z] = dev;
- }
- if (!z)
- return -EIO;
- return 0;
-}
-
-void cleanup_module(void)
-{
- int z;
-
- for (z = 0; z < DEVMAX; z++) {
- struct net_device *dev = moddevs[z];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-#endif /* MODULE */
diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h
deleted file mode 100644
index 0dae056fed9..00000000000
--- a/drivers/net/sk_mca.h
+++ /dev/null
@@ -1,170 +0,0 @@
-#ifndef _SK_MCA_INCLUDE_
-#define _SK_MCA_INCLUDE_
-
-#ifdef _SK_MCA_DRIVER_
-
-/* Adapter ID's */
-#define SKNET_MCA_ID 0x6afd
-#define SKNET_JUNIOR_MCA_ID 0x6be9
-
-/* media enumeration - defined in a way that it fits onto the MC2+'s
- POS registers... */
-
-typedef enum { Media_10Base2, Media_10BaseT,
- Media_10Base5, Media_Unknown, Media_Count
-} skmca_medium;
-
-/* private structure */
-typedef struct {
- unsigned int slot; /* MCA-Slot-# */
- void __iomem *base;
- void __iomem *macbase; /* base address of MAC address PROM */
- void __iomem *ioregaddr;/* address of I/O-register (Lo) */
- void __iomem *ctrladdr; /* address of control/stat register */
- void __iomem *cmdaddr; /* address of I/O-command register */
- int nextrx; /* index of next RX descriptor to
- be read */
- int nexttxput; /* index of next free TX descriptor */
- int nexttxdone; /* index of next TX descriptor to
- be finished */
- int txbusy; /* # of busy TX descriptors */
- struct net_device_stats stat; /* packet statistics */
- int realirq; /* memorizes actual IRQ, even when
- currently not allocated */
- skmca_medium medium; /* physical cannector */
- spinlock_t lock;
-} skmca_priv;
-
-/* card registers: control/status register bits */
-
-#define CTRL_ADR_DATA 0 /* Bit 0 = 0 ->access data register */
-#define CTRL_ADR_RAP 1 /* Bit 0 = 1 ->access RAP register */
-#define CTRL_RW_WRITE 0 /* Bit 1 = 0 ->write register */
-#define CTRL_RW_READ 2 /* Bit 1 = 1 ->read register */
-#define CTRL_RESET_ON 0 /* Bit 3 = 0 ->reset board */
-#define CTRL_RESET_OFF 8 /* Bit 3 = 1 ->no reset of board */
-
-#define STAT_ADR_DATA 0 /* Bit 0 of ctrl register read back */
-#define STAT_ADR_RAP 1
-#define STAT_RW_WRITE 0 /* Bit 1 of ctrl register read back */
-#define STAT_RW_READ 2
-#define STAT_RESET_ON 0 /* Bit 3 of ctrl register read back */
-#define STAT_RESET_OFF 8
-#define STAT_IRQ_ACT 0 /* interrupt pending */
-#define STAT_IRQ_NOACT 16 /* no interrupt pending */
-#define STAT_IO_NOBUSY 0 /* no transfer busy */
-#define STAT_IO_BUSY 32 /* transfer busy */
-
-/* I/O command register bits */
-
-#define IOCMD_GO 128 /* Bit 7 = 1 -> start register xfer */
-
-/* LANCE registers */
-
-#define LANCE_CSR0 0 /* Status/Control */
-
-#define CSR0_ERR 0x8000 /* general error flag */
-#define CSR0_BABL 0x4000 /* transmitter timeout */
-#define CSR0_CERR 0x2000 /* collision error */
-#define CSR0_MISS 0x1000 /* lost Rx block */
-#define CSR0_MERR 0x0800 /* memory access error */
-#define CSR0_RINT 0x0400 /* receiver interrupt */
-#define CSR0_TINT 0x0200 /* transmitter interrupt */
-#define CSR0_IDON 0x0100 /* initialization done */
-#define CSR0_INTR 0x0080 /* general interrupt flag */
-#define CSR0_INEA 0x0040 /* interrupt enable */
-#define CSR0_RXON 0x0020 /* receiver enabled */
-#define CSR0_TXON 0x0010 /* transmitter enabled */
-#define CSR0_TDMD 0x0008 /* force transmission now */
-#define CSR0_STOP 0x0004 /* stop LANCE */
-#define CSR0_STRT 0x0002 /* start LANCE */
-#define CSR0_INIT 0x0001 /* read initialization block */
-
-#define LANCE_CSR1 1 /* addr bit 0..15 of initialization */
-#define LANCE_CSR2 2 /* 16..23 block */
-
-#define LANCE_CSR3 3 /* Bus control */
-#define CSR3_BCON_HOLD 0 /* Bit 0 = 0 -> BM1,BM0,HOLD */
-#define CSR3_BCON_BUSRQ 1 /* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ */
-#define CSR3_ALE_HIGH 0 /* Bit 1 = 0 -> ALE asserted high */
-#define CSR3_ALE_LOW 2 /* Bit 1 = 1 -> ALE asserted low */
-#define CSR3_BSWAP_OFF 0 /* Bit 2 = 0 -> no byte swap */
-#define CSR3_BSWAP_ON 4 /* Bit 2 = 1 -> byte swap */
-
-/* LANCE structures */
-
-typedef struct { /* LANCE initialization block */
- u16 Mode; /* mode flags */
- u8 PAdr[6]; /* MAC address */
- u8 LAdrF[8]; /* Multicast filter */
- u32 RdrP; /* Receive descriptor */
- u32 TdrP; /* Transmit descriptor */
-} LANCE_InitBlock;
-
-/* Mode flags init block */
-
-#define LANCE_INIT_PROM 0x8000 /* enable promiscous mode */
-#define LANCE_INIT_INTL 0x0040 /* internal loopback */
-#define LANCE_INIT_DRTY 0x0020 /* disable retry */
-#define LANCE_INIT_COLL 0x0010 /* force collision */
-#define LANCE_INIT_DTCR 0x0008 /* disable transmit CRC */
-#define LANCE_INIT_LOOP 0x0004 /* loopback */
-#define LANCE_INIT_DTX 0x0002 /* disable transmitter */
-#define LANCE_INIT_DRX 0x0001 /* disable receiver */
-
-typedef struct { /* LANCE Tx descriptor */
- u16 LowAddr; /* bit 0..15 of address */
- u16 Flags; /* bit 16..23 of address + Flags */
- u16 Len; /* 2s complement of packet length */
- u16 Status; /* Result of transmission */
-} LANCE_TxDescr;
-
-#define TXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */
-#define TXDSCR_FLAGS_ERR 0x4000 /* summary error flag */
-#define TXDSCR_FLAGS_MORE 0x1000 /* more than one retry needed? */
-#define TXDSCR_FLAGS_ONE 0x0800 /* one retry? */
-#define TXDSCR_FLAGS_DEF 0x0400 /* transmission deferred? */
-#define TXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */
-#define TXDSCR_FLAGS_ENP 0x0100 /* last packet in chain? */
-
-#define TXDSCR_STATUS_BUFF 0x8000 /* buffer error? */
-#define TXDSCR_STATUS_UFLO 0x4000 /* silo underflow during transmit? */
-#define TXDSCR_STATUS_LCOL 0x1000 /* late collision? */
-#define TXDSCR_STATUS_LCAR 0x0800 /* loss of carrier? */
-#define TXDSCR_STATUS_RTRY 0x0400 /* retry error? */
-
-typedef struct { /* LANCE Rx descriptor */
- u16 LowAddr; /* bit 0..15 of address */
- u16 Flags; /* bit 16..23 of address + Flags */
- u16 MaxLen; /* 2s complement of buffer length */
- u16 Len; /* packet length */
-} LANCE_RxDescr;
-
-#define RXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */
-#define RXDSCR_FLAGS_ERR 0x4000 /* summary error flag */
-#define RXDSCR_FLAGS_FRAM 0x2000 /* framing error flag */
-#define RXDSCR_FLAGS_OFLO 0x1000 /* FIFO overflow? */
-#define RXDSCR_FLAGS_CRC 0x0800 /* CRC error? */
-#define RXDSCR_FLAGS_BUFF 0x0400 /* buffer error? */
-#define RXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */
-#define RXDCSR_FLAGS_ENP 0x0100 /* last packet in chain? */
-
-/* RAM layout */
-
-#define TXCOUNT 4 /* length of TX descriptor queue */
-#define LTXCOUNT 2 /* log2 of it */
-#define RXCOUNT 4 /* length of RX descriptor queue */
-#define LRXCOUNT 2 /* log2 of it */
-
-#define RAM_INITBASE 0 /* LANCE init block */
-#define RAM_TXBASE 24 /* Start of TX descriptor queue */
-#define RAM_RXBASE \
-(RAM_TXBASE + (TXCOUNT * 8)) /* Start of RX descriptor queue */
-#define RAM_DATABASE \
-(RAM_RXBASE + (RXCOUNT * 8)) /* Start of data area for frames */
-#define RAM_BUFSIZE 1580 /* max. frame size - should never be
- reached */
-
-#endif /* _SK_MCA_DRIVER_ */
-
-#endif /* _SK_MCA_INCLUDE_ */
diff --git a/drivers/net/skfp/can.c b/drivers/net/skfp/can.c
deleted file mode 100644
index 8a49abce796..00000000000
--- a/drivers/net/skfp/can.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/******************************************************************************
- *
- * (C)Copyright 1998,1999 SysKonnect,
- * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- * See the file "skfddi.c" for further information.
- *
- * This program is free software; you can redistribute it and/or modify
- * 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.
- *
- * The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-#ifndef lint
-static const char xID_sccs[] = "@(#)can.c 1.5 97/04/07 (C) SK " ;
-#endif
-
-/*
- * canonical bit order
- */
-const u_char canonical[256] = {
- 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
- 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
- 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
- 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
- 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
- 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
- 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
- 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
- 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
- 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
- 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
- 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
- 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
- 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
- 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
- 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
- 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
- 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
- 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
- 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
- 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
- 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
- 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
- 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
- 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
- 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
- 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
- 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
- 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
- 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
- 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
- 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
-} ;
-
-#ifdef MAKE_TABLE
-int byte_reverse(x)
-int x ;
-{
- int y = 0 ;
-
- if (x & 0x01)
- y |= 0x80 ;
- if (x & 0x02)
- y |= 0x40 ;
- if (x & 0x04)
- y |= 0x20 ;
- if (x & 0x08)
- y |= 0x10 ;
- if (x & 0x10)
- y |= 0x08 ;
- if (x & 0x20)
- y |= 0x04 ;
- if (x & 0x40)
- y |= 0x02 ;
- if (x & 0x80)
- y |= 0x01 ;
- return(y) ;
-}
-#endif
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
index 5b475833f64..4fe624b0dd2 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/skfp/drvfbi.c
@@ -23,6 +23,7 @@
#include "h/smc.h"
#include "h/supern_2.h"
#include "h/skfbiinc.h"
+#include <linux/bitrev.h>
#ifndef lint
static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ;
@@ -445,16 +446,14 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
char PmdType ;
int i ;
- extern const u_char canonical[256] ;
-
#if (defined(ISA) || defined(MCA))
for (i = 0; i < 4 ;i++) { /* read mac address from board */
smc->hw.fddi_phys_addr.a[i] =
- canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ;
+ bitrev8(inpw(PR_A(i+SA_MAC)));
}
for (i = 4; i < 6; i++) {
smc->hw.fddi_phys_addr.a[i] =
- canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ;
+ bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF)));
}
#endif
#ifdef EISA
@@ -464,17 +463,17 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
*/
for (i = 0; i < 4 ;i++) { /* read mac address from board */
smc->hw.fddi_phys_addr.a[i] =
- canonical[inp(PR_A(i+SA_MAC))] ;
+ bitrev8(inp(PR_A(i+SA_MAC)));
}
for (i = 4; i < 6; i++) {
smc->hw.fddi_phys_addr.a[i] =
- canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ;
+ bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF)));
}
#endif
#ifdef PCI
for (i = 0; i < 6; i++) { /* read mac address from board */
smc->hw.fddi_phys_addr.a[i] =
- canonical[inp(ADDR(B2_MAC_0+i))] ;
+ bitrev8(inp(ADDR(B2_MAC_0+i)));
}
#endif
#ifndef PCI
@@ -493,7 +492,7 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
if (mac_addr) {
for (i = 0; i < 6 ;i++) {
smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ;
- smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ;
+ smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]);
}
return ;
}
@@ -501,7 +500,7 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
for (i = 0; i < 6 ;i++) {
smc->hw.fddi_canon_addr.a[i] =
- canonical[smc->hw.fddi_phys_addr.a[i]] ;
+ bitrev8(smc->hw.fddi_phys_addr.a[i]);
}
}
@@ -1269,11 +1268,8 @@ void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr)
{
int i ;
- extern const u_char canonical[256] ;
-
- for (i = 0 ; i < 6 ; i++) {
- bia_addr->a[i] = canonical[smc->hw.fddi_phys_addr.a[i]] ;
- }
+ for (i = 0 ; i < 6 ; i++)
+ bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]);
}
void smt_start_watchdog(struct s_smc *smc)
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
index 0784f558ca9..a45205da803 100644
--- a/drivers/net/skfp/fplustm.c
+++ b/drivers/net/skfp/fplustm.c
@@ -22,7 +22,7 @@
#include "h/fddi.h"
#include "h/smc.h"
#include "h/supern_2.h"
-#include "can.c"
+#include <linux/bitrev.h>
#ifndef lint
static const char ID_sccs[] = "@(#)fplustm.c 1.32 99/02/23 (C) SK " ;
@@ -1073,7 +1073,7 @@ static struct s_fpmc* mac_get_mc_table(struct s_smc *smc,
if (can) {
p = own->a ;
for (i = 0 ; i < 6 ; i++, p++)
- *p = canonical[*p] ;
+ *p = bitrev8(*p);
}
slot = NULL;
for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index 99a776a51fb..fe847800acd 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -18,6 +18,7 @@
#include "h/fddi.h"
#include "h/smc.h"
#include "h/smt_p.h"
+#include <linux/bitrev.h>
#define KERNEL
#include "h/smtstate.h"
@@ -26,8 +27,6 @@
static const char ID_sccs[] = "@(#)smt.c 2.43 98/11/23 (C) SK " ;
#endif
-extern const u_char canonical[256] ;
-
/*
* FC in SMbuf
*/
@@ -180,7 +179,7 @@ void smt_agent_init(struct s_smc *smc)
driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ;
for (i = 0 ; i < 6 ; i ++) {
smc->mib.fddiSMTStationId.sid_node.a[i] =
- canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ;
+ bitrev8(smc->mib.fddiSMTStationId.sid_node.a[i]);
}
smc->mib.fddiSMTManufacturerData[0] =
smc->mib.fddiSMTStationId.sid_node.a[0] ;
@@ -2049,9 +2048,8 @@ static void hwm_conv_can(struct s_smc *smc, char *data, int len)
SK_UNUSED(smc) ;
- for (i = len; i ; i--, data++) {
- *data = canonical[*(u_char *)data] ;
- }
+ for (i = len; i ; i--, data++)
+ *data = bitrev8(*data);
}
#endif
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index b60f0451f6c..e482e7fcbb2 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -42,7 +42,7 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.9"
+#define DRV_VERSION "1.10"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@@ -60,7 +60,7 @@
#define LINK_HZ (HZ/2)
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
-MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
+MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
@@ -132,18 +132,93 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
}
/* Wake on Lan only supported on Yukon chips with rev 1 or above */
-static int wol_supported(const struct skge_hw *hw)
+static u32 wol_supported(const struct skge_hw *hw)
{
- return !((hw->chip_id == CHIP_ID_GENESIS ||
- (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)));
+ if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0)
+ return WAKE_MAGIC | WAKE_PHY;
+ else
+ return 0;
+}
+
+static u32 pci_wake_enabled(struct pci_dev *dev)
+{
+ int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ u16 value;
+
+ /* If device doesn't support PM Capabilities, but request is to disable
+ * wake events, it's a nop; otherwise fail */
+ if (!pm)
+ return 0;
+
+ pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
+
+ value &= PCI_PM_CAP_PME_MASK;
+ value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
+
+ return value != 0;
+}
+
+static void skge_wol_init(struct skge_port *skge)
+{
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+ enum pause_control save_mode;
+ u32 ctrl;
+
+ /* Bring hardware out of reset */
+ skge_write16(hw, B0_CTST, CS_RST_CLR);
+ skge_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+ skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+ skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+ /* Force to 10/100 skge_reset will re-enable on resume */
+ save_mode = skge->flow_control;
+ skge->flow_control = FLOW_MODE_SYMMETRIC;
+
+ ctrl = skge->advertising;
+ skge->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
+
+ skge_phy_reset(skge);
+
+ skge->flow_control = save_mode;
+ skge->advertising = ctrl;
+
+ /* Set GMAC to no flow control and auto update for speed/duplex */
+ gma_write16(hw, port, GM_GP_CTRL,
+ GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA|
+ GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS);
+
+ /* Set WOL address */
+ memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR),
+ skge->netdev->dev_addr, ETH_ALEN);
+
+ /* Turn on appropriate WOL control bits */
+ skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT);
+ ctrl = 0;
+ if (skge->wol & WAKE_PHY)
+ ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT;
+
+ if (skge->wol & WAKE_MAGIC)
+ ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
+
+ ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
+ skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
+
+ /* block receiver */
+ skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
}
static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct skge_port *skge = netdev_priv(dev);
- wol->supported = wol_supported(skge->hw) ? WAKE_MAGIC : 0;
- wol->wolopts = skge->wol ? WAKE_MAGIC : 0;
+ wol->supported = wol_supported(skge->hw);
+ wol->wolopts = skge->wol;
}
static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -151,23 +226,12 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
- if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
- return -EOPNOTSUPP;
-
- if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw))
+ if (wol->wolopts & wol_supported(hw))
return -EOPNOTSUPP;
- skge->wol = wol->wolopts == WAKE_MAGIC;
-
- if (skge->wol) {
- memcpy_toio(hw->regs + WOL_MAC_ADDR, dev->dev_addr, ETH_ALEN);
-
- skge_write16(hw, WOL_CTRL_STAT,
- WOL_CTL_ENA_PME_ON_MAGIC_PKT |
- WOL_CTL_ENA_MAGIC_PKT_UNIT);
- } else
- skge_write16(hw, WOL_CTRL_STAT, WOL_CTL_DEFAULT);
-
+ skge->wol = wol->wolopts;
+ if (!netif_running(dev))
+ skge_wol_init(skge);
return 0;
}
@@ -749,7 +813,7 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u32 base)
struct skge_element *e;
int i;
- ring->start = kcalloc(sizeof(*e), ring->count, GFP_KERNEL);
+ ring->start = kcalloc(ring->count, sizeof(*e), GFP_KERNEL);
if (!ring->start)
return -ENOMEM;
@@ -2373,6 +2437,9 @@ static int skge_up(struct net_device *dev)
size_t rx_size, tx_size;
int err;
+ if (!is_valid_ether_addr(dev->dev_addr))
+ return -EINVAL;
+
if (netif_msg_ifup(skge))
printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
@@ -2392,7 +2459,7 @@ static int skge_up(struct net_device *dev)
BUG_ON(skge->dma & 7);
if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) {
- printk(KERN_ERR PFX "pci_alloc_consistent region crosses 4G boundary\n");
+ dev_err(&hw->pdev->dev, "pci_alloc_consistent region crosses 4G boundary\n");
err = -EINVAL;
goto free_pci_mem;
}
@@ -2920,6 +2987,7 @@ static int skge_poll(struct net_device *dev, int *budget)
struct skge_hw *hw = skge->hw;
struct skge_ring *ring = &skge->rx_ring;
struct skge_element *e;
+ unsigned long flags;
int to_do = min(dev->quota, *budget);
int work_done = 0;
@@ -2957,12 +3025,12 @@ static int skge_poll(struct net_device *dev, int *budget)
if (work_done >= to_do)
return 1; /* not done */
- spin_lock_irq(&hw->hw_lock);
+ spin_lock_irqsave(&hw->hw_lock, flags);
__netif_rx_complete(dev);
hw->intr_mask |= irqmask[skge->port];
skge_write32(hw, B0_IMSK, hw->intr_mask);
skge_read32(hw, B0_IMSK);
- spin_unlock_irq(&hw->hw_lock);
+ spin_unlock_irqrestore(&hw->hw_lock, flags);
return 0;
}
@@ -3000,6 +3068,7 @@ static void skge_mac_intr(struct skge_hw *hw, int port)
/* Handle device specific framing and timeout interrupts */
static void skge_error_irq(struct skge_hw *hw)
{
+ struct pci_dev *pdev = hw->pdev;
u32 hwstatus = skge_read32(hw, B0_HWE_ISRC);
if (hw->chip_id == CHIP_ID_GENESIS) {
@@ -3015,12 +3084,12 @@ static void skge_error_irq(struct skge_hw *hw)
}
if (hwstatus & IS_RAM_RD_PAR) {
- printk(KERN_ERR PFX "Ram read data parity error\n");
+ dev_err(&pdev->dev, "Ram read data parity error\n");
skge_write16(hw, B3_RI_CTRL, RI_CLR_RD_PERR);
}
if (hwstatus & IS_RAM_WR_PAR) {
- printk(KERN_ERR PFX "Ram write data parity error\n");
+ dev_err(&pdev->dev, "Ram write data parity error\n");
skge_write16(hw, B3_RI_CTRL, RI_CLR_WR_PERR);
}
@@ -3031,38 +3100,38 @@ static void skge_error_irq(struct skge_hw *hw)
skge_mac_parity(hw, 1);
if (hwstatus & IS_R1_PAR_ERR) {
- printk(KERN_ERR PFX "%s: receive queue parity error\n",
- hw->dev[0]->name);
+ dev_err(&pdev->dev, "%s: receive queue parity error\n",
+ hw->dev[0]->name);
skge_write32(hw, B0_R1_CSR, CSR_IRQ_CL_P);
}
if (hwstatus & IS_R2_PAR_ERR) {
- printk(KERN_ERR PFX "%s: receive queue parity error\n",
- hw->dev[1]->name);
+ dev_err(&pdev->dev, "%s: receive queue parity error\n",
+ hw->dev[1]->name);
skge_write32(hw, B0_R2_CSR, CSR_IRQ_CL_P);
}
if (hwstatus & (IS_IRQ_MST_ERR|IS_IRQ_STAT)) {
u16 pci_status, pci_cmd;
- pci_read_config_word(hw->pdev, PCI_COMMAND, &pci_cmd);
- pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status);
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+ pci_read_config_word(pdev, PCI_STATUS, &pci_status);
- printk(KERN_ERR PFX "%s: PCI error cmd=%#x status=%#x\n",
- pci_name(hw->pdev), pci_cmd, pci_status);
+ dev_err(&pdev->dev, "PCI error cmd=%#x status=%#x\n",
+ pci_cmd, pci_status);
/* Write the error bits back to clear them. */
pci_status &= PCI_STATUS_ERROR_BITS;
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- pci_write_config_word(hw->pdev, PCI_COMMAND,
+ pci_write_config_word(pdev, PCI_COMMAND,
pci_cmd | PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
- pci_write_config_word(hw->pdev, PCI_STATUS, pci_status);
+ pci_write_config_word(pdev, PCI_STATUS, pci_status);
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
/* if error still set then just ignore it */
hwstatus = skge_read32(hw, B0_HWE_ISRC);
if (hwstatus & IS_IRQ_STAT) {
- printk(KERN_INFO PFX "unable to clear error (so ignoring them)\n");
+ dev_warn(&hw->pdev->dev, "unable to clear error (so ignoring them)\n");
hw->intr_mask &= ~IS_HW_ERR;
}
}
@@ -3276,8 +3345,8 @@ static int skge_reset(struct skge_hw *hw)
hw->phy_addr = PHY_ADDR_BCOM;
break;
default:
- printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
- pci_name(hw->pdev), hw->phy_type);
+ dev_err(&hw->pdev->dev, "unsupported phy type 0x%x\n",
+ hw->phy_type);
return -EOPNOTSUPP;
}
break;
@@ -3292,8 +3361,8 @@ static int skge_reset(struct skge_hw *hw)
break;
default:
- printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
- pci_name(hw->pdev), hw->chip_id);
+ dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
+ hw->chip_id);
return -EOPNOTSUPP;
}
@@ -3333,7 +3402,7 @@ static int skge_reset(struct skge_hw *hw)
/* avoid boards with stuck Hardware error bits */
if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) &&
(skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) {
- printk(KERN_WARNING PFX "stuck hardware sensor bit\n");
+ dev_warn(&hw->pdev->dev, "stuck hardware sensor bit\n");
hw->intr_mask &= ~IS_HW_ERR;
}
@@ -3407,7 +3476,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
struct net_device *dev = alloc_etherdev(sizeof(*skge));
if (!dev) {
- printk(KERN_ERR "skge etherdev alloc failed");
+ dev_err(&hw->pdev->dev, "etherdev alloc failed\n");
return NULL;
}
@@ -3451,6 +3520,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
skge->duplex = -1;
skge->speed = -1;
skge->advertising = skge_supported_modes(hw);
+ skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0;
hw->dev[port] = dev;
@@ -3495,15 +3565,13 @@ static int __devinit skge_probe(struct pci_dev *pdev,
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "%s cannot enable PCI device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot enable PCI device\n");
goto err_out;
}
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot obtain PCI resources\n");
goto err_out_disable_pdev;
}
@@ -3518,8 +3586,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
}
if (err) {
- printk(KERN_ERR PFX "%s no usable DMA configuration\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
goto err_out_free_regions;
}
@@ -3537,8 +3604,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
err = -ENOMEM;
hw = kzalloc(sizeof(*hw), GFP_KERNEL);
if (!hw) {
- printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot allocate hardware struct\n");
goto err_out_free_regions;
}
@@ -3549,8 +3615,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
if (!hw->regs) {
- printk(KERN_ERR PFX "%s: cannot map device registers\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot map device registers\n");
goto err_out_free_hw;
}
@@ -3566,23 +3631,19 @@ static int __devinit skge_probe(struct pci_dev *pdev,
if (!dev)
goto err_out_led_off;
- if (!is_valid_ether_addr(dev->dev_addr)) {
- printk(KERN_ERR PFX "%s: bad (zero?) ethernet address in rom\n",
- pci_name(pdev));
- err = -EIO;
- goto err_out_free_netdev;
- }
+ /* Some motherboards are broken and has zero in ROM. */
+ if (!is_valid_ether_addr(dev->dev_addr))
+ dev_warn(&pdev->dev, "bad (zero?) ethernet address in rom\n");
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "%s: cannot register net device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot register net device\n");
goto err_out_free_netdev;
}
err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw);
if (err) {
- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
+ dev_err(&pdev->dev, "%s: cannot assign irq %d\n",
dev->name, pdev->irq);
goto err_out_unregister;
}
@@ -3593,7 +3654,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
skge_show_addr(dev1);
else {
/* Failure to register second port need not be fatal */
- printk(KERN_WARNING PFX "register of second port failed\n");
+ dev_warn(&pdev->dev, "register of second port failed\n");
hw->dev[1] = NULL;
free_netdev(dev1);
}
@@ -3658,28 +3719,46 @@ static void __devexit skge_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM
+static int vaux_avail(struct pci_dev *pdev)
+{
+ int pm_cap;
+
+ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pm_cap) {
+ u16 ctl;
+ pci_read_config_word(pdev, pm_cap + PCI_PM_PMC, &ctl);
+ if (ctl & PCI_PM_CAP_AUX_POWER)
+ return 1;
+ }
+ return 0;
+}
+
+
static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct skge_hw *hw = pci_get_drvdata(pdev);
- int i, wol = 0;
+ int i, err, wol = 0;
+
+ err = pci_save_state(pdev);
+ if (err)
+ return err;
- pci_save_state(pdev);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
+ struct skge_port *skge = netdev_priv(dev);
- if (netif_running(dev)) {
- struct skge_port *skge = netdev_priv(dev);
+ if (netif_running(dev))
+ skge_down(dev);
+ if (skge->wol)
+ skge_wol_init(skge);
- netif_carrier_off(dev);
- if (skge->wol)
- netif_stop_queue(dev);
- else
- skge_down(dev);
- wol |= skge->wol;
- }
- netif_device_detach(dev);
+ wol |= skge->wol;
}
+ if (wol && vaux_avail(pdev))
+ skge_write8(hw, B0_POWER_CTRL,
+ PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF);
+
skge_write32(hw, B0_IMSK, 0);
pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -3692,8 +3771,14 @@ static int skge_resume(struct pci_dev *pdev)
struct skge_hw *hw = pci_get_drvdata(pdev);
int i, err;
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err)
+ goto out;
+
+ err = pci_restore_state(pdev);
+ if (err)
+ goto out;
+
pci_enable_wake(pdev, PCI_D0, 0);
err = skge_reset(hw);
@@ -3703,7 +3788,6 @@ static int skge_resume(struct pci_dev *pdev)
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
- netif_device_attach(dev);
if (netif_running(dev)) {
err = skge_up(dev);
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index f6223c533c0..17b1b479dff 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -876,11 +876,13 @@ enum {
WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */
WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */
};
+#define WOL_REGS(port, x) (x + (port)*0x80)
enum {
WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */
WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */
};
+#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400)
enum {
BASE_XMAC_1 = 0x2000,/* XMAC 1 registers */
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index fb1d2c30c1b..f2ab3d56e56 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -49,7 +49,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.10"
+#define DRV_VERSION "1.12"
#define PFX DRV_NAME " "
/*
@@ -105,6 +105,7 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, /* DGE-560T */
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4001) }, /* DGE-550SX */
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B02) }, /* DGE-560SX */
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B03) }, /* DGE-550T */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, /* 88E8021 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, /* 88E8022 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, /* 88E8061 */
@@ -126,6 +127,9 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
{ 0 }
};
@@ -140,7 +144,7 @@ static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 };
static const char *yukon2_name[] = {
"XL", /* 0xb3 */
"EC Ultra", /* 0xb4 */
- "UNKNOWN", /* 0xb5 */
+ "Extreme", /* 0xb5 */
"EC", /* 0xb6 */
"FE", /* 0xb7 */
};
@@ -192,76 +196,52 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
return v;
}
-static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
-{
- u16 power_control;
- int vaux;
-
- pr_debug("sky2_set_power_state %d\n", state);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-
- power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_PMC);
- vaux = (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) &&
- (power_control & PCI_PM_CAP_PME_D3cold);
-
- power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL);
-
- power_control |= PCI_PM_CTRL_PME_STATUS;
- power_control &= ~(PCI_PM_CTRL_STATE_MASK);
- switch (state) {
- case PCI_D0:
- /* switch power to VCC (WA for VAUX problem) */
- sky2_write8(hw, B0_POWER_CTRL,
- PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
-
- /* disable Core Clock Division, */
- sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
-
- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
- /* enable bits are inverted */
- sky2_write8(hw, B2_Y2_CLK_GATE,
- Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
- Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
- Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
- else
- sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+static void sky2_power_on(struct sky2_hw *hw)
+{
+ /* switch power to VCC (WA for VAUX problem) */
+ sky2_write8(hw, B0_POWER_CTRL,
+ PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
- u32 reg1;
+ /* disable Core Clock Division, */
+ sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
- sky2_pci_write32(hw, PCI_DEV_REG3, 0);
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
- reg1 &= P_ASPM_CONTROL_MSK;
- sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
- sky2_pci_write32(hw, PCI_DEV_REG5, 0);
- }
+ if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ /* enable bits are inverted */
+ sky2_write8(hw, B2_Y2_CLK_GATE,
+ Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+ Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+ Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+ else
+ sky2_write8(hw, B2_Y2_CLK_GATE, 0);
- break;
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
+ u32 reg1;
- case PCI_D3hot:
- case PCI_D3cold:
- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
- sky2_write8(hw, B2_Y2_CLK_GATE, 0);
- else
- /* enable bits are inverted */
- sky2_write8(hw, B2_Y2_CLK_GATE,
- Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
- Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
- Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
-
- /* switch power to VAUX */
- if (vaux && state != PCI_D3cold)
- sky2_write8(hw, B0_POWER_CTRL,
- (PC_VAUX_ENA | PC_VCC_ENA |
- PC_VAUX_ON | PC_VCC_OFF));
- break;
- default:
- printk(KERN_ERR PFX "Unknown power state %d\n", state);
+ sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+ reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
+ reg1 &= P_ASPM_CONTROL_MSK;
+ sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
+ sky2_pci_write32(hw, PCI_DEV_REG5, 0);
}
+}
- sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+static void sky2_power_aux(struct sky2_hw *hw)
+{
+ if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+ else
+ /* enable bits are inverted */
+ sky2_write8(hw, B2_Y2_CLK_GATE,
+ Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+ Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+ Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+
+ /* switch power to VAUX */
+ if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL)
+ sky2_write8(hw, B0_POWER_CTRL,
+ (PC_VAUX_ENA | PC_VCC_ENA |
+ PC_VAUX_ON | PC_VCC_OFF));
}
static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
@@ -313,8 +293,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
- if (sky2->autoneg == AUTONEG_ENABLE &&
- !(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
+ if (sky2->autoneg == AUTONEG_ENABLE
+ && !(hw->chip_id == CHIP_ID_YUKON_XL
+ || hw->chip_id == CHIP_ID_YUKON_EC_U
+ || hw->chip_id == CHIP_ID_YUKON_EX)) {
u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
@@ -341,8 +323,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* enable automatic crossover */
ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO);
- if (sky2->autoneg == AUTONEG_ENABLE &&
- (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
+ if (sky2->autoneg == AUTONEG_ENABLE
+ && (hw->chip_id == CHIP_ID_YUKON_XL
+ || hw->chip_id == CHIP_ID_YUKON_EC_U
+ || hw->chip_id == CHIP_ID_YUKON_EX)) {
ctrl &= ~PHY_M_PC_DSC_MSK;
ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
}
@@ -497,7 +481,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* restore page register */
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
break;
+
case CHIP_ID_YUKON_EC_U:
+ case CHIP_ID_YUKON_EX:
pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
/* select page 3 to access LED control register */
@@ -539,7 +525,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* set page register to 0 */
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
- } else {
+ } else if (hw->chip_id != CHIP_ID_YUKON_EX) {
gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
@@ -569,8 +555,8 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
onoff = !onoff;
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
-
if (onoff)
/* Turn off phy power saving */
reg1 &= ~phy_power[port];
@@ -579,6 +565,7 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
sky2_pci_read32(hw, PCI_DEV_REG1);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
udelay(100);
}
@@ -590,6 +577,73 @@ static void sky2_phy_reinit(struct sky2_port *sky2)
spin_unlock_bh(&sky2->phy_lock);
}
+/* Put device in state to listen for Wake On Lan */
+static void sky2_wol_init(struct sky2_port *sky2)
+{
+ struct sky2_hw *hw = sky2->hw;
+ unsigned port = sky2->port;
+ enum flow_control save_mode;
+ u16 ctrl;
+ u32 reg1;
+
+ /* Bring hardware out of reset */
+ sky2_write16(hw, B0_CTST, CS_RST_CLR);
+ sky2_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+ sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+ /* Force to 10/100
+ * sky2_reset will re-enable on resume
+ */
+ save_mode = sky2->flow_mode;
+ ctrl = sky2->advertising;
+
+ sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
+ sky2->flow_mode = FC_NONE;
+ sky2_phy_power(hw, port, 1);
+ sky2_phy_reinit(sky2);
+
+ sky2->flow_mode = save_mode;
+ sky2->advertising = ctrl;
+
+ /* Set GMAC to no flow control and auto update for speed/duplex */
+ gma_write16(hw, port, GM_GP_CTRL,
+ GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA|
+ GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS);
+
+ /* Set WOL address */
+ memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR),
+ sky2->netdev->dev_addr, ETH_ALEN);
+
+ /* Turn on appropriate WOL control bits */
+ sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT);
+ ctrl = 0;
+ if (sky2->wol & WAKE_PHY)
+ ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT;
+
+ if (sky2->wol & WAKE_MAGIC)
+ ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
+
+ ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
+ sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
+
+ /* Turn on legacy PCI-Express PME mode */
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+ reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+ reg1 |= PCI_Y2_PME_LEGACY;
+ sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+ /* block receiver */
+ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+
+}
+
static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
{
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
@@ -683,7 +737,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
if (hw->dev[port]->mtu > ETH_DATA_LEN) {
@@ -1466,6 +1520,9 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
if (unlikely(netif_msg_tx_done(sky2)))
printk(KERN_DEBUG "%s: tx done %u\n",
dev->name, idx);
+ sky2->net_stats.tx_packets++;
+ sky2->net_stats.tx_bytes += re->skb->len;
+
dev_kfree_skb_any(re->skb);
}
@@ -1511,6 +1568,13 @@ static int sky2_down(struct net_device *dev)
imask &= ~portirq_msk[port];
sky2_write32(hw, B0_IMSK, imask);
+ /*
+ * Both ports share the NAPI poll on port 0, so if necessary undo the
+ * the disable that is done in dev_close.
+ */
+ if (sky2->port == 0 && hw->ports > 1)
+ netif_poll_enable(dev);
+
sky2_gmac_reset(hw, port);
/* Stop transmitter */
@@ -1633,7 +1697,9 @@ static void sky2_link_up(struct sky2_port *sky2)
sky2_write8(hw, SK_REG(port, LNK_LED_REG),
LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
- if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) {
+ if (hw->chip_id == CHIP_ID_YUKON_XL
+ || hw->chip_id == CHIP_ID_YUKON_EC_U
+ || hw->chip_id == CHIP_ID_YUKON_EX) {
u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */
@@ -1726,14 +1792,16 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 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)
+ if (hw->chip_id == CHIP_ID_YUKON_XL
+ || hw->chip_id == CHIP_ID_YUKON_EC_U
+ || hw->chip_id == CHIP_ID_YUKON_EX)
aux >>= 6;
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
- && hw->chip_id != CHIP_ID_YUKON_EC_U)
+ && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX))
sky2->flow_status = FC_NONE;
if (aux & PHY_M_PS_RX_P_EN)
@@ -1786,48 +1854,37 @@ out:
}
-/* Transmit timeout is only called if we are running, carries is up
+/* Transmit timeout is only called if we are running, carrier is up
* and tx queue is full (stopped).
+ * Called with netif_tx_lock held.
*/
static void sky2_tx_timeout(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
- unsigned txq = txqaddr[sky2->port];
- u16 report, done;
+ u32 imask;
if (netif_msg_timer(sky2))
printk(KERN_ERR PFX "%s: tx timeout\n", dev->name);
- report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX);
- done = sky2_read16(hw, Q_ADDR(txq, Q_DONE));
-
printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n",
- dev->name,
- sky2->tx_cons, sky2->tx_prod, report, done);
+ dev->name, sky2->tx_cons, sky2->tx_prod,
+ sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX),
+ sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE)));
- if (report != done) {
- printk(KERN_INFO PFX "status burst pending (irq moderation?)\n");
-
- sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
- sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
- } else if (report != sky2->tx_cons) {
- printk(KERN_INFO PFX "status report lost?\n");
+ imask = sky2_read32(hw, B0_IMSK); /* block IRQ in hw */
+ sky2_write32(hw, B0_IMSK, 0);
+ sky2_read32(hw, B0_IMSK);
- netif_tx_lock_bh(dev);
- sky2_tx_complete(sky2, report);
- netif_tx_unlock_bh(dev);
- } else {
- printk(KERN_INFO PFX "hardware hung? flushing\n");
+ netif_poll_disable(hw->dev[0]); /* stop NAPI poll */
+ synchronize_irq(hw->pdev->irq);
- sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP);
- sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
+ netif_start_queue(dev); /* don't wakeup during flush */
+ sky2_tx_complete(sky2, sky2->tx_prod); /* Flush transmit queue */
- sky2_tx_clean(dev);
+ sky2_write32(hw, B0_IMSK, imask);
- sky2_qset(hw, txq);
- sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1);
- }
+ sky2_phy_reinit(sky2); /* this clears flow control etc */
}
static int sky2_change_mtu(struct net_device *dev, int new_mtu)
@@ -1841,8 +1898,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;
+ /* TSO on Yukon Ultra and MTU > 1500 not supported */
if (hw->chip_id == CHIP_ID_YUKON_EC_U && new_mtu > ETH_DATA_LEN)
- return -EINVAL;
+ dev->features &= ~NETIF_F_TSO;
if (!netif_running(dev)) {
dev->mtu = new_mtu;
@@ -2081,6 +2139,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
goto force_update;
skb->protocol = eth_type_trans(skb, dev);
+ sky2->net_stats.rx_packets++;
+ sky2->net_stats.rx_bytes += skb->len;
dev->last_rx = jiffies;
#ifdef SKY2_VLAN_TAG_USED
@@ -2210,8 +2270,8 @@ static void sky2_hw_intr(struct sky2_hw *hw)
pci_err = sky2_pci_read16(hw, PCI_STATUS);
if (net_ratelimit())
- printk(KERN_ERR PFX "%s: pci hw error (0x%x)\n",
- pci_name(hw->pdev), pci_err);
+ dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n",
+ pci_err);
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
sky2_pci_write16(hw, PCI_STATUS,
@@ -2226,8 +2286,8 @@ static void sky2_hw_intr(struct sky2_hw *hw)
pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT);
if (net_ratelimit())
- printk(KERN_ERR PFX "%s: pci express error (0x%x)\n",
- pci_name(hw->pdev), pex_err);
+ dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n",
+ pex_err);
/* clear the interrupt */
sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
@@ -2396,6 +2456,7 @@ static inline u32 sky2_mhz(const struct sky2_hw *hw)
switch (hw->chip_id) {
case CHIP_ID_YUKON_EC:
case CHIP_ID_YUKON_EC_U:
+ case CHIP_ID_YUKON_EX:
return 125; /* 125 Mhz */
case CHIP_ID_YUKON_FE:
return 100; /* 100 Mhz */
@@ -2415,34 +2476,62 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
}
-static int sky2_reset(struct sky2_hw *hw)
+static int __devinit sky2_init(struct sky2_hw *hw)
{
- u16 status;
u8 t8;
- int i;
sky2_write8(hw, B0_CTST, CS_RST_CLR);
hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) {
- printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
- pci_name(hw->pdev), hw->chip_id);
+ dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
+ hw->chip_id);
return -EOPNOTSUPP;
}
+ if (hw->chip_id == CHIP_ID_YUKON_EX)
+ dev_warn(&hw->pdev->dev, "this driver not yet tested on this chip type\n"
+ "Please report success or failure to <netdev@vger.kernel.org>\n");
+
+ /* Make sure and enable all clocks */
+ if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
+ sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+
hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
/* This rev is really old, and requires untested workarounds */
if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) {
- printk(KERN_ERR PFX "%s: unsupported revision Yukon-%s (0x%x) rev %d\n",
- pci_name(hw->pdev), yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
- hw->chip_id, hw->chip_rev);
+ dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n",
+ yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
+ hw->chip_id, hw->chip_rev);
return -EOPNOTSUPP;
}
+ hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
+ hw->ports = 1;
+ t8 = sky2_read8(hw, B2_Y2_HW_RES);
+ if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
+ if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
+ ++hw->ports;
+ }
+
+ return 0;
+}
+
+static void sky2_reset(struct sky2_hw *hw)
+{
+ u16 status;
+ int i;
+
/* disable ASF */
if (hw->chip_id <= CHIP_ID_YUKON_EC) {
- sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
+ if (hw->chip_id == CHIP_ID_YUKON_EX) {
+ status = sky2_read16(hw, HCU_CCSR);
+ status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE |
+ HCU_CCSR_UC_STATE_MSK);
+ sky2_write16(hw, HCU_CCSR, status);
+ } else
+ sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE);
}
@@ -2464,15 +2553,7 @@ static int sky2_reset(struct sky2_hw *hw)
sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL);
- hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
- hw->ports = 1;
- t8 = sky2_read8(hw, B2_Y2_HW_RES);
- if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
- if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
- ++hw->ports;
- }
-
- sky2_set_power_state(hw, PCI_D0);
+ sky2_power_on(hw);
for (i = 0; i < hw->ports; i++) {
sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
@@ -2555,7 +2636,37 @@ static int sky2_reset(struct sky2_hw *hw)
sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START);
sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START);
+}
+
+static inline u8 sky2_wol_supported(const struct sky2_hw *hw)
+{
+ return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0;
+}
+
+static void sky2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ const struct sky2_port *sky2 = netdev_priv(dev);
+
+ wol->supported = sky2_wol_supported(sky2->hw);
+ wol->wolopts = sky2->wol;
+}
+static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_hw *hw = sky2->hw;
+
+ if (wol->wolopts & ~sky2_wol_supported(sky2->hw))
+ return -EOPNOTSUPP;
+
+ sky2->wol = wol->wolopts;
+
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U)
+ sky2_write32(hw, B0_CTST, sky2->wol
+ ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
+
+ if (!netif_running(dev))
+ sky2_wol_init(sky2);
return 0;
}
@@ -2806,25 +2917,9 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
}
-/* Use hardware MIB variables for critical path statistics and
- * transmit feedback not reported at interrupt.
- * Other errors are accounted for in interrupt handler.
- */
static struct net_device_stats *sky2_get_stats(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
- u64 data[13];
-
- sky2_phy_stats(sky2, data, ARRAY_SIZE(data));
-
- sky2->net_stats.tx_bytes = data[0];
- sky2->net_stats.rx_bytes = data[1];
- sky2->net_stats.tx_packets = data[2] + data[4] + data[6];
- sky2->net_stats.rx_packets = data[3] + data[5] + data[7];
- sky2->net_stats.multicast = data[3] + data[5];
- sky2->net_stats.collisions = data[10];
- sky2->net_stats.tx_aborted_errors = data[12];
-
return &sky2->net_stats;
}
@@ -3183,7 +3278,9 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
static const struct ethtool_ops sky2_ethtool_ops = {
.get_settings = sky2_get_settings,
.set_settings = sky2_set_settings,
- .get_drvinfo = sky2_get_drvinfo,
+ .get_drvinfo = sky2_get_drvinfo,
+ .get_wol = sky2_get_wol,
+ .set_wol = sky2_set_wol,
.get_msglevel = sky2_get_msglevel,
.set_msglevel = sky2_set_msglevel,
.nway_reset = sky2_nway_reset,
@@ -3213,13 +3310,14 @@ static const struct ethtool_ops sky2_ethtool_ops = {
/* Initialize network device */
static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
- unsigned port, int highmem)
+ unsigned port,
+ int highmem, int wol)
{
struct sky2_port *sky2;
struct net_device *dev = alloc_etherdev(sizeof(*sky2));
if (!dev) {
- printk(KERN_ERR "sky2 etherdev alloc failed");
+ dev_err(&hw->pdev->dev, "etherdev alloc failed");
return NULL;
}
@@ -3261,6 +3359,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->speed = -1;
sky2->advertising = sky2_supported_modes(hw);
sky2->rx_csum = 1;
+ sky2->wol = wol;
spin_lock_init(&sky2->phy_lock);
sky2->tx_pending = TX_DEF_PENDING;
@@ -3270,11 +3369,9 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->port = port;
- if (hw->chip_id != CHIP_ID_YUKON_EC_U)
- dev->features |= NETIF_F_TSO;
+ dev->features |= NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_SG;
if (highmem)
dev->features |= NETIF_F_HIGHDMA;
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
#ifdef SKY2_VLAN_TAG_USED
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
@@ -3335,8 +3432,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
err = request_irq(pdev->irq, sky2_test_intr, 0, DRV_NAME, hw);
if (err) {
- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
- pci_name(pdev), pdev->irq);
+ dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
return err;
}
@@ -3347,9 +3443,8 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
if (!hw->msi) {
/* MSI test failed, go back to INTx mode */
- printk(KERN_INFO PFX "%s: No interrupt generated using MSI, "
- "switching to INTx mode.\n",
- pci_name(pdev));
+ dev_info(&pdev->dev, "No interrupt generated using MSI, "
+ "switching to INTx mode.\n");
err = -EOPNOTSUPP;
sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
@@ -3363,62 +3458,62 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
return err;
}
+static int __devinit pci_wake_enabled(struct pci_dev *dev)
+{
+ int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ u16 value;
+
+ if (!pm)
+ return 0;
+ if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value))
+ return 0;
+ return value & PCI_PM_CTRL_PME_ENABLE;
+}
+
static int __devinit sky2_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- struct net_device *dev, *dev1 = NULL;
+ struct net_device *dev;
struct sky2_hw *hw;
- int err, pm_cap, using_dac = 0;
+ int err, using_dac = 0, wol_default;
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "%s cannot enable PCI device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot enable PCI device\n");
goto err_out;
}
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot obtain PCI resources\n");
goto err_out;
}
pci_set_master(pdev);
- /* Find power-management capability. */
- pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
- if (pm_cap == 0) {
- printk(KERN_ERR PFX "Cannot find PowerManagement capability, "
- "aborting.\n");
- err = -EIO;
- goto err_out_free_regions;
- }
-
if (sizeof(dma_addr_t) > sizeof(u32) &&
!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
using_dac = 1;
err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
if (err < 0) {
- printk(KERN_ERR PFX "%s unable to obtain 64 bit DMA "
- "for consistent allocations\n", pci_name(pdev));
+ dev_err(&pdev->dev, "unable to obtain 64 bit DMA "
+ "for consistent allocations\n");
goto err_out_free_regions;
}
-
} else {
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
- printk(KERN_ERR PFX "%s no usable DMA configuration\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
goto err_out_free_regions;
}
}
+ wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0;
+
err = -ENOMEM;
hw = kzalloc(sizeof(*hw), GFP_KERNEL);
if (!hw) {
- printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot allocate hardware struct\n");
goto err_out_free_regions;
}
@@ -3426,11 +3521,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
if (!hw->regs) {
- printk(KERN_ERR PFX "%s: cannot map device registers\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot map device registers\n");
goto err_out_free_hw;
}
- hw->pm_cap = pm_cap;
#ifdef __BIG_ENDIAN
/* The sk98lin vendor driver uses hardware byte swapping but
@@ -3450,18 +3543,22 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
if (!hw->st_le)
goto err_out_iounmap;
- err = sky2_reset(hw);
+ err = sky2_init(hw);
if (err)
goto err_out_iounmap;
- printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
+ dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0),
pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
hw->chip_id, hw->chip_rev);
- dev = sky2_init_netdev(hw, 0, using_dac);
- if (!dev)
+ sky2_reset(hw);
+
+ dev = sky2_init_netdev(hw, 0, using_dac, wol_default);
+ if (!dev) {
+ err = -ENOMEM;
goto err_out_free_pci;
+ }
if (!disable_msi && pci_enable_msi(pdev) == 0) {
err = sky2_test_msi(hw);
@@ -3473,32 +3570,33 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "%s: cannot register net device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot register net device\n");
goto err_out_free_netdev;
}
err = request_irq(pdev->irq, sky2_intr, hw->msi ? 0 : IRQF_SHARED,
dev->name, hw);
if (err) {
- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
- pci_name(pdev), pdev->irq);
+ dev_err(&pdev->dev, "cannot assign irq %d\n", 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))) {
- if (register_netdev(dev1) == 0)
- sky2_show_addr(dev1);
- else {
- /* Failure to register second port need not be fatal */
- printk(KERN_WARNING PFX
- "register of second port failed\n");
+ if (hw->ports > 1) {
+ struct net_device *dev1;
+
+ dev1 = sky2_init_netdev(hw, 1, using_dac, wol_default);
+ if (!dev1)
+ dev_warn(&pdev->dev, "allocation for second device failed\n");
+ else if ((err = register_netdev(dev1))) {
+ dev_warn(&pdev->dev,
+ "register of second port failed (%d)\n", err);
hw->dev[1] = NULL;
free_netdev(dev1);
- }
+ } else
+ sky2_show_addr(dev1);
}
setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
@@ -3547,7 +3645,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
unregister_netdev(dev1);
unregister_netdev(dev0);
- sky2_set_power_state(hw, PCI_D3hot);
+ sky2_power_aux(hw);
+
sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
sky2_write8(hw, B0_CTST, CS_RST_SET);
sky2_read8(hw, B0_CTST);
@@ -3572,27 +3671,31 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct sky2_hw *hw = pci_get_drvdata(pdev);
- int i;
- pci_power_t pstate = pci_choose_state(pdev, state);
-
- if (!(pstate == PCI_D3hot || pstate == PCI_D3cold))
- return -EINVAL;
+ int i, wol = 0;
del_timer_sync(&hw->idle_timer);
netif_poll_disable(hw->dev[0]);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
+ struct sky2_port *sky2 = netdev_priv(dev);
- if (netif_running(dev)) {
+ if (netif_running(dev))
sky2_down(dev);
- netif_device_detach(dev);
- }
+
+ if (sky2->wol)
+ sky2_wol_init(sky2);
+
+ wol |= sky2->wol;
}
sky2_write32(hw, B0_IMSK, 0);
+ sky2_power_aux(hw);
+
pci_save_state(pdev);
- sky2_set_power_state(hw, pstate);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
return 0;
}
@@ -3601,21 +3704,22 @@ static int sky2_resume(struct pci_dev *pdev)
struct sky2_hw *hw = pci_get_drvdata(pdev);
int i, err;
- pci_restore_state(pdev);
- pci_enable_wake(pdev, PCI_D0, 0);
- sky2_set_power_state(hw, PCI_D0);
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err)
+ goto out;
- err = sky2_reset(hw);
+ err = pci_restore_state(pdev);
if (err)
goto out;
+ pci_enable_wake(pdev, PCI_D0, 0);
+ sky2_reset(hw);
+
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
if (netif_running(dev)) {
- netif_device_attach(dev);
-
err = sky2_up(dev);
if (err) {
printk(KERN_ERR PFX "%s: could not up: %d\n",
@@ -3628,11 +3732,43 @@ static int sky2_resume(struct pci_dev *pdev)
netif_poll_enable(hw->dev[0]);
sky2_idle_start(hw);
+ return 0;
out:
+ dev_err(&pdev->dev, "resume failed (%d)\n", err);
+ pci_disable_device(pdev);
return err;
}
#endif
+static void sky2_shutdown(struct pci_dev *pdev)
+{
+ struct sky2_hw *hw = pci_get_drvdata(pdev);
+ int i, wol = 0;
+
+ del_timer_sync(&hw->idle_timer);
+ netif_poll_disable(hw->dev[0]);
+
+ for (i = 0; i < hw->ports; i++) {
+ struct net_device *dev = hw->dev[i];
+ struct sky2_port *sky2 = netdev_priv(dev);
+
+ if (sky2->wol) {
+ wol = 1;
+ sky2_wol_init(sky2);
+ }
+ }
+
+ if (wol)
+ sky2_power_aux(hw);
+
+ pci_enable_wake(pdev, PCI_D3hot, wol);
+ pci_enable_wake(pdev, PCI_D3cold, wol);
+
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+
+}
+
static struct pci_driver sky2_driver = {
.name = DRV_NAME,
.id_table = sky2_id_table,
@@ -3642,6 +3778,7 @@ static struct pci_driver sky2_driver = {
.suspend = sky2_suspend,
.resume = sky2_resume,
#endif
+ .shutdown = sky2_shutdown,
};
static int __init sky2_init_module(void)
@@ -3658,6 +3795,6 @@ module_init(sky2_init_module);
module_exit(sky2_cleanup_module);
MODULE_DESCRIPTION("Marvell Yukon 2 Gigabit Ethernet driver");
-MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
+MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 6ed1d47dbbd..3b0189569d5 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -32,6 +32,7 @@ enum pci_dev_reg_1 {
PCI_Y2_PHY1_COMA = 1<<28, /* Set PHY 1 to Coma Mode (YUKON-2) */
PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */
PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */
+ PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */
};
enum pci_dev_reg_2 {
@@ -370,12 +371,9 @@ enum {
/* B2_CHIP_ID 8 bit Chip Identification Number */
enum {
- CHIP_ID_GENESIS = 0x0a, /* Chip ID for GENESIS */
- CHIP_ID_YUKON = 0xb0, /* Chip ID for YUKON */
- CHIP_ID_YUKON_LITE = 0xb1, /* Chip ID for YUKON-Lite (Rev. A1-A3) */
- CHIP_ID_YUKON_LP = 0xb2, /* Chip ID for YUKON-LP */
CHIP_ID_YUKON_XL = 0xb3, /* Chip ID for YUKON-2 XL */
CHIP_ID_YUKON_EC_U = 0xb4, /* Chip ID for YUKON-2 EC Ultra */
+ CHIP_ID_YUKON_EX = 0xb5, /* Chip ID for YUKON-2 Extreme */
CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */
CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */
@@ -767,6 +765,24 @@ enum {
POLL_LIST_ADDR_HI= 0x0e2c,/* 32 bit Poll. List Start Addr (high) */
};
+enum {
+ SMB_CFG = 0x0e40, /* 32 bit SMBus Config Register */
+ SMB_CSR = 0x0e44, /* 32 bit SMBus Control/Status Register */
+};
+
+enum {
+ CPU_WDOG = 0x0e48, /* 32 bit Watchdog Register */
+ CPU_CNTR = 0x0e4C, /* 32 bit Counter Register */
+ CPU_TIM = 0x0e50,/* 32 bit Timer Compare Register */
+ CPU_AHB_ADDR = 0x0e54, /* 32 bit CPU AHB Debug Register */
+ CPU_AHB_WDATA = 0x0e58, /* 32 bit CPU AHB Debug Register */
+ CPU_AHB_RDATA = 0x0e5C, /* 32 bit CPU AHB Debug Register */
+ HCU_MAP_BASE = 0x0e60, /* 32 bit Reset Mapping Base */
+ CPU_AHB_CTRL = 0x0e64, /* 32 bit CPU AHB Debug Register */
+ HCU_CCSR = 0x0e68, /* 32 bit CPU Control and Status Register */
+ HCU_HCSR = 0x0e6C, /* 32 bit Host Control and Status Register */
+};
+
/* ASF Subsystem Registers (Yukon-2 only) */
enum {
B28_Y2_SMB_CONFIG = 0x0e40,/* 32 bit ASF SMBus Config Register */
@@ -837,33 +853,27 @@ enum {
GMAC_LINK_CTRL = 0x0f10,/* 16 bit Link Control Reg */
/* Wake-up Frame Pattern Match Control Registers (YUKON only) */
-
- WOL_REG_OFFS = 0x20,/* HW-Bug: Address is + 0x20 against spec. */
-
WOL_CTRL_STAT = 0x0f20,/* 16 bit WOL Control/Status Reg */
WOL_MATCH_CTL = 0x0f22,/* 8 bit WOL Match Control Reg */
WOL_MATCH_RES = 0x0f23,/* 8 bit WOL Match Result Reg */
WOL_MAC_ADDR = 0x0f24,/* 32 bit WOL MAC Address */
- WOL_PATT_PME = 0x0f2a,/* 8 bit WOL PME Match Enable (Yukon-2) */
- WOL_PATT_ASFM = 0x0f2b,/* 8 bit WOL ASF Match Enable (Yukon-2) */
WOL_PATT_RPTR = 0x0f2c,/* 8 bit WOL Pattern Read Pointer */
/* WOL Pattern Length Registers (YUKON only) */
-
WOL_PATT_LEN_LO = 0x0f30,/* 32 bit WOL Pattern Length 3..0 */
WOL_PATT_LEN_HI = 0x0f34,/* 24 bit WOL Pattern Length 6..4 */
/* WOL Pattern Counter Registers (YUKON only) */
-
-
WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */
WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */
};
+#define WOL_REGS(port, x) (x + (port)*0x80)
enum {
WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */
WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */
};
+#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400)
enum {
BASE_GMAC_1 = 0x2800,/* GMAC 1 registers */
@@ -1654,6 +1664,39 @@ enum {
Y2_ASF_CLR_ASFI = 1<<1, /* Clear host IRQ */
Y2_ASF_HOST_IRQ = 1<<0, /* Issue an IRQ to HOST system */
};
+/* HCU_CCSR CPU Control and Status Register */
+enum {
+ HCU_CCSR_SMBALERT_MONITOR= 1<<27, /* SMBALERT pin monitor */
+ HCU_CCSR_CPU_SLEEP = 1<<26, /* CPU sleep status */
+ /* Clock Stretching Timeout */
+ HCU_CCSR_CS_TO = 1<<25,
+ HCU_CCSR_WDOG = 1<<24, /* Watchdog Reset */
+
+ HCU_CCSR_CLR_IRQ_HOST = 1<<17, /* Clear IRQ_HOST */
+ HCU_CCSR_SET_IRQ_HCU = 1<<16, /* Set IRQ_HCU */
+
+ HCU_CCSR_AHB_RST = 1<<9, /* Reset AHB bridge */
+ HCU_CCSR_CPU_RST_MODE = 1<<8, /* CPU Reset Mode */
+
+ HCU_CCSR_SET_SYNC_CPU = 1<<5,
+ HCU_CCSR_CPU_CLK_DIVIDE_MSK = 3<<3,/* CPU Clock Divide */
+ HCU_CCSR_CPU_CLK_DIVIDE_BASE= 1<<3,
+ HCU_CCSR_OS_PRSNT = 1<<2, /* ASF OS Present */
+/* Microcontroller State */
+ HCU_CCSR_UC_STATE_MSK = 3,
+ HCU_CCSR_UC_STATE_BASE = 1<<0,
+ HCU_CCSR_ASF_RESET = 0,
+ HCU_CCSR_ASF_HALTED = 1<<1,
+ HCU_CCSR_ASF_RUNNING = 1<<0,
+};
+
+/* HCU_HCSR Host Control and Status Register */
+enum {
+ HCU_HCSR_SET_IRQ_CPU = 1<<16, /* Set IRQ_CPU */
+
+ HCU_HCSR_CLR_IRQ_HCU = 1<<1, /* Clear IRQ_HCU */
+ HCU_HCSR_SET_IRQ_HOST = 1<<0, /* Set IRQ_HOST */
+};
/* STAT_CTRL 32 bit Status BMU control register (Yukon-2 only) */
enum {
@@ -1715,14 +1758,17 @@ enum {
GM_IS_RX_COMPL = 1<<0, /* Frame Reception Complete */
#define GMAC_DEF_MSK GM_IS_TX_FF_UR
+};
/* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */
- /* Bits 15.. 2: reserved */
+enum { /* Bits 15.. 2: reserved */
GMLC_RST_CLR = 1<<1, /* Clear GMAC Link Reset */
GMLC_RST_SET = 1<<0, /* Set GMAC Link Reset */
+};
/* WOL_CTRL_STAT 16 bit WOL Control/Status Reg */
+enum {
WOL_CTL_LINK_CHG_OCC = 1<<15,
WOL_CTL_MAGIC_PKT_OCC = 1<<14,
WOL_CTL_PATTERN_OCC = 1<<13,
@@ -1741,17 +1787,6 @@ enum {
WOL_CTL_DIS_PATTERN_UNIT = 1<<0,
};
-#define WOL_CTL_DEFAULT \
- (WOL_CTL_DIS_PME_ON_LINK_CHG | \
- WOL_CTL_DIS_PME_ON_PATTERN | \
- WOL_CTL_DIS_PME_ON_MAGIC_PKT | \
- WOL_CTL_DIS_LINK_CHG_UNIT | \
- WOL_CTL_DIS_PATTERN_UNIT | \
- WOL_CTL_DIS_MAGIC_PKT_UNIT)
-
-/* WOL_MATCH_CTL 8 bit WOL Match Control Reg */
-#define WOL_CTL_PATT_ENA(x) (1 << (x))
-
/* Control flags */
enum {
@@ -1875,6 +1910,7 @@ struct sky2_port {
u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */
u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */
u8 rx_csum;
+ u8 wol;
enum flow_control flow_mode;
enum flow_control flow_status;
@@ -1887,7 +1923,6 @@ struct sky2_hw {
struct pci_dev *pdev;
struct net_device *dev[2];
- int pm_cap;
u8 chip_id;
u8 chip_rev;
u8 pmd_type;
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 39c2152a07f..2f4b1de7a2b 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -229,10 +229,10 @@ static int sl_realloc_bufs(struct slip *sl, int mtu)
if (len < 576 * 2)
len = 576 * 2;
- xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
- rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+ xbuff = kmalloc(len + 4, GFP_ATOMIC);
+ rbuff = kmalloc(len + 4, GFP_ATOMIC);
#ifdef SL_INCLUDE_CSLIP
- cbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+ cbuff = kmalloc(len + 4, GFP_ATOMIC);
#endif
@@ -1343,15 +1343,12 @@ static int __init slip_init(void)
printk(KERN_INFO "SLIP linefill/keepalive option.\n");
#endif
- slip_devs = kmalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL);
+ slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL);
if (!slip_devs) {
printk(KERN_ERR "SLIP: Can't allocate slip devices array! Uaargh! (-> No SLIP available)\n");
return -ENOMEM;
}
- /* Clear the pointer array, we allocate devices when we need them */
- memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev);
-
/* Fill in our line protocol discipline, and register it */
if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) {
printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status);
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index 7122932eac9..ae1ae343bee 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -482,8 +482,7 @@ static void ultramca_block_input(struct net_device *dev, int count, struct sk_bu
count -= semi_count;
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
}
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index d70bc979534..a52b22d7db6 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -454,8 +454,7 @@ ultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ri
count -= semi_count;
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index 2c5319c62fa..88a30e56c64 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -395,8 +395,7 @@ static void ultra32_block_input(struct net_device *dev,
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
}
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
}
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 2c4343395a4..c9561413198 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -148,6 +148,8 @@ struct smc911x_local {
int tx_throttle;
spinlock_t lock;
+ struct net_device *netdev;
+
#ifdef SMC_USE_DMA
/* DMA needs the physical address of the chip */
u_long physaddr;
@@ -948,10 +950,11 @@ static void smc911x_phy_check_media(struct net_device *dev, int init)
* of autonegotiation.) If the RPC ANEG bit is cleared, the selection
* is controlled by the RPC SPEED and RPC DPLX bits.
*/
-static void smc911x_phy_configure(void *data)
+static void smc911x_phy_configure(struct work_struct *work)
{
- struct net_device *dev = data;
- struct smc911x_local *lp = netdev_priv(dev);
+ struct smc911x_local *lp = container_of(work, struct smc911x_local,
+ phy_configure);
+ struct net_device *dev = lp->netdev;
unsigned long ioaddr = dev->base_addr;
int phyaddr = lp->mii.phy_id;
int my_phy_caps; /* My PHY capabilities */
@@ -965,11 +968,11 @@ static void smc911x_phy_configure(void *data)
* We should not be called if phy_type is zero.
*/
if (lp->phy_type == 0)
- goto smc911x_phy_configure_exit;
+ goto smc911x_phy_configure_exit_nolock;
if (smc911x_phy_reset(dev, phyaddr)) {
printk("%s: PHY reset timed out\n", dev->name);
- goto smc911x_phy_configure_exit;
+ goto smc911x_phy_configure_exit_nolock;
}
spin_lock_irqsave(&lp->lock, flags);
@@ -1038,6 +1041,7 @@ static void smc911x_phy_configure(void *data)
smc911x_phy_configure_exit:
spin_unlock_irqrestore(&lp->lock, flags);
+smc911x_phy_configure_exit_nolock:
lp->work_pending = 0;
}
@@ -1331,7 +1335,7 @@ smc911x_rx_dma_irq(int dma, void *data)
static void smc911x_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- smc911x_interrupt(dev->irq, dev, NULL);
+ smc911x_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
@@ -1495,6 +1499,8 @@ static void smc911x_set_multicast_list(struct net_device *dev)
static int
smc911x_open(struct net_device *dev)
{
+ struct smc911x_local *lp = netdev_priv(dev);
+
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
/*
@@ -1511,7 +1517,7 @@ smc911x_open(struct net_device *dev)
smc911x_reset(dev);
/* Configure the PHY, initialize the link state */
- smc911x_phy_configure(dev);
+ smc911x_phy_configure(&lp->phy_configure);
/* Turn on Tx + Rx */
smc911x_enable(dev);
@@ -1653,7 +1659,7 @@ smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
strncpy(info->driver, CARDNAME, sizeof(info->driver));
strncpy(info->version, version, sizeof(info->version));
- strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+ strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
}
static int smc911x_ethtool_nwayreset(struct net_device *dev)
@@ -2060,7 +2066,7 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr)
dev->poll_controller = smc911x_poll_controller;
#endif
- INIT_WORK(&lp->phy_configure, smc911x_phy_configure, dev);
+ INIT_WORK(&lp->phy_configure, smc911x_phy_configure);
lp->mii.phy_id_mask = 0x1f;
lp->mii.reg_num_mask = 0x1f;
lp->mii.force_media = 0;
@@ -2154,6 +2160,7 @@ static int smc911x_drv_probe(struct platform_device *pdev)
{
struct net_device *ndev;
struct resource *res;
+ struct smc911x_local *lp;
unsigned int *addr;
int ret;
@@ -2183,6 +2190,8 @@ static int smc911x_drv_probe(struct platform_device *pdev)
ndev->dma = (unsigned char)-1;
ndev->irq = platform_get_irq(pdev, 0);
+ lp = netdev_priv(ndev);
+ lp->netdev = ndev;
addr = ioremap(res->start, SMC911X_IO_EXTENT);
if (!addr) {
@@ -2204,7 +2213,6 @@ out:
}
#ifdef SMC_USE_DMA
else {
- struct smc911x_local *lp = netdev_priv(ndev);
lp->physaddr = res->start;
lp->dev = &pdev->dev;
}
@@ -2275,7 +2283,7 @@ static int smc911x_drv_resume(struct platform_device *dev)
smc911x_reset(ndev);
smc911x_enable(ndev);
if (lp->phy_type != 0)
- smc911x_phy_configure(ndev);
+ smc911x_phy_configure(&lp->phy_configure);
netif_device_attach(ndev);
}
}
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index e62a9586fb9..49f4b7712eb 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1712,7 +1712,7 @@ smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
strncpy(info->driver, CARDNAME, sizeof(info->driver));
strncpy(info->version, version, sizeof(info->version));
- strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+ strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
}
static int smc_ethtool_nwayreset(struct net_device *dev)
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 9367c574477..d2767e6584a 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -362,96 +362,6 @@ 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)
-
-#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)
-
-#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
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index ebb6aa39f9c..64ed8ff5b03 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -280,72 +280,67 @@ spider_net_free_chain(struct spider_net_card *card,
{
struct spider_net_descr *descr;
- for (descr = chain->tail; !descr->bus_addr; descr = descr->next) {
- pci_unmap_single(card->pdev, descr->bus_addr,
- SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL);
+ descr = chain->ring;
+ do {
descr->bus_addr = 0;
- }
+ descr->next_descr_addr = 0;
+ descr = descr->next;
+ } while (descr != chain->ring);
+
+ dma_free_coherent(&card->pdev->dev, chain->num_desc,
+ chain->ring, chain->dma_addr);
}
/**
- * spider_net_init_chain - links descriptor chain
+ * spider_net_init_chain - alloc and link descriptor chain
* @card: card structure
* @chain: address of chain
- * @start_descr: address of descriptor array
- * @no: number of descriptors
*
- * we manage a circular list that mirrors the hardware structure,
+ * We manage a circular list that mirrors the hardware structure,
* except that the hardware uses bus addresses.
*
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure
*/
static int
spider_net_init_chain(struct spider_net_card *card,
- struct spider_net_descr_chain *chain,
- struct spider_net_descr *start_descr,
- int no)
+ struct spider_net_descr_chain *chain)
{
int i;
struct spider_net_descr *descr;
dma_addr_t buf;
+ size_t alloc_size;
- descr = start_descr;
- memset(descr, 0, sizeof(*descr) * no);
+ alloc_size = chain->num_desc * sizeof (struct spider_net_descr);
- /* set up the hardware pointers in each descriptor */
- for (i=0; i<no; i++, descr++) {
- descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ chain->ring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
+ &chain->dma_addr, GFP_KERNEL);
+
+ if (!chain->ring)
+ return -ENOMEM;
- buf = pci_map_single(card->pdev, descr,
- SPIDER_NET_DESCR_SIZE,
- PCI_DMA_BIDIRECTIONAL);
+ descr = chain->ring;
+ memset(descr, 0, alloc_size);
- if (pci_dma_mapping_error(buf))
- goto iommu_error;
+ /* Set up the hardware pointers in each descriptor */
+ buf = chain->dma_addr;
+ for (i=0; i < chain->num_desc; i++, descr++) {
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
descr->bus_addr = buf;
+ descr->next_descr_addr = 0;
descr->next = descr + 1;
descr->prev = descr - 1;
+ buf += sizeof(struct spider_net_descr);
}
/* do actual circular list */
- (descr-1)->next = start_descr;
- start_descr->prev = descr-1;
+ (descr-1)->next = chain->ring;
+ chain->ring->prev = descr-1;
spin_lock_init(&chain->lock);
- chain->head = start_descr;
- chain->tail = start_descr;
-
+ chain->head = chain->ring;
+ chain->tail = chain->ring;
return 0;
-
-iommu_error:
- descr = start_descr;
- for (i=0; i < no; i++, descr++)
- if (descr->bus_addr)
- pci_unmap_single(card->pdev, descr->bus_addr,
- SPIDER_NET_DESCR_SIZE,
- PCI_DMA_BIDIRECTIONAL);
- return -ENOMEM;
}
/**
@@ -372,21 +367,20 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card)
}
/**
- * spider_net_prepare_rx_descr - reinitializes a rx descriptor
+ * spider_net_prepare_rx_descr - Reinitialize RX descriptor
* @card: card structure
* @descr: descriptor to re-init
*
- * return 0 on succes, <0 on failure
+ * Return 0 on succes, <0 on failure.
*
- * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
- * Activate the descriptor state-wise
+ * Allocates a new rx skb, iommu-maps it and attaches it to the
+ * descriptor. Mark the descriptor as activated, ready-to-use.
*/
static int
spider_net_prepare_rx_descr(struct spider_net_card *card,
struct spider_net_descr *descr)
{
dma_addr_t buf;
- int error = 0;
int offset;
int bufsize;
@@ -414,7 +408,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
(SPIDER_NET_RXBUF_ALIGN - 1);
if (offset)
skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
- /* io-mmu-map the skb */
+ /* iommu-map the skb */
buf = pci_map_single(card->pdev, descr->skb->data,
SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
descr->buf_addr = buf;
@@ -425,11 +419,16 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
card->spider_stats.rx_iommu_map_error++;
descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
} else {
+ descr->next_descr_addr = 0;
+ wmb();
descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
SPIDER_NET_DMAC_NOINTR_COMPLETE;
+
+ wmb();
+ descr->prev->next_descr_addr = descr->bus_addr;
}
- return error;
+ return 0;
}
/**
@@ -493,10 +492,10 @@ spider_net_refill_rx_chain(struct spider_net_card *card)
}
/**
- * spider_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
+ * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains
* @card: card structure
*
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure.
*/
static int
spider_net_alloc_rx_skbs(struct spider_net_card *card)
@@ -507,16 +506,16 @@ spider_net_alloc_rx_skbs(struct spider_net_card *card)
result = -ENOMEM;
chain = &card->rx_chain;
- /* put at least one buffer into the chain. if this fails,
- * we've got a problem. if not, spider_net_refill_rx_chain
- * will do the rest at the end of this function */
+ /* Put at least one buffer into the chain. if this fails,
+ * we've got a problem. If not, spider_net_refill_rx_chain
+ * will do the rest at the end of this function. */
if (spider_net_prepare_rx_descr(card, chain->head))
goto error;
else
chain->head = chain->head->next;
- /* this will allocate the rest of the rx buffers; if not, it's
- * business as usual later on */
+ /* This will allocate the rest of the rx buffers;
+ * if not, it's business as usual later on. */
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
return 0;
@@ -707,7 +706,7 @@ spider_net_set_low_watermark(struct spider_net_card *card)
}
/* If TX queue is short, don't even bother with interrupts */
- if (cnt < card->num_tx_desc/4)
+ if (cnt < card->tx_chain.num_desc/4)
return cnt;
/* Set low-watermark 3/4th's of the way into the queue. */
@@ -915,16 +914,13 @@ spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
* spider_net_pass_skb_up - takes an skb from a descriptor and passes it on
* @descr: descriptor to process
* @card: card structure
- * @napi: whether caller is in NAPI context
- *
- * returns 1 on success, 0 if no packet was passed to the stack
*
- * iommu-unmaps the skb, fills out skb structure and passes the data to the
- * stack. The descriptor state is not changed.
+ * Fills out skb structure and passes the data to the stack.
+ * The descriptor state is not changed.
*/
-static int
+static void
spider_net_pass_skb_up(struct spider_net_descr *descr,
- struct spider_net_card *card, int napi)
+ struct spider_net_card *card)
{
struct sk_buff *skb;
struct net_device *netdev;
@@ -932,23 +928,8 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
data_status = descr->data_status;
data_error = descr->data_error;
-
netdev = card->netdev;
- /* unmap descriptor */
- pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME,
- PCI_DMA_FROMDEVICE);
-
- /* the cases we'll throw away the packet immediately */
- if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
- if (netif_msg_rx_err(card))
- pr_err("error in received descriptor found, "
- "data_status=x%08x, data_error=x%08x\n",
- data_status, data_error);
- card->spider_stats.rx_desc_error++;
- return 0;
- }
-
skb = descr->skb;
skb->dev = netdev;
skb_put(skb, descr->valid_size);
@@ -977,57 +958,72 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
}
/* pass skb up to stack */
- if (napi)
- netif_receive_skb(skb);
- else
- netif_rx_ni(skb);
+ netif_receive_skb(skb);
/* update netdevice statistics */
card->netdev_stats.rx_packets++;
card->netdev_stats.rx_bytes += skb->len;
+}
- return 1;
+#ifdef DEBUG
+static void show_rx_chain(struct spider_net_card *card)
+{
+ struct spider_net_descr_chain *chain = &card->rx_chain;
+ struct spider_net_descr *start= chain->tail;
+ struct spider_net_descr *descr= start;
+ int status;
+
+ int cnt = 0;
+ int cstat = spider_net_get_descr_status(descr);
+ printk(KERN_INFO "RX chain tail at descr=%ld\n",
+ (start - card->descr) - card->tx_chain.num_desc);
+ status = cstat;
+ do
+ {
+ status = spider_net_get_descr_status(descr);
+ if (cstat != status) {
+ printk(KERN_INFO "Have %d descrs with stat=x%08x\n", cnt, cstat);
+ cstat = status;
+ cnt = 0;
+ }
+ cnt ++;
+ descr = descr->next;
+ } while (descr != start);
+ printk(KERN_INFO "Last %d descrs with stat=x%08x\n", cnt, cstat);
}
+#endif
/**
* spider_net_decode_one_descr - processes an rx descriptor
* @card: card structure
- * @napi: whether caller is in NAPI context
*
- * returns 1 if a packet has been sent to the stack, otherwise 0
+ * Returns 1 if a packet has been sent to the stack, otherwise 0
*
- * processes an rx descriptor by iommu-unmapping the data buffer and passing
+ * Processes an rx descriptor by iommu-unmapping the data buffer and passing
* the packet up to the stack. This function is called in softirq
* context, e.g. either bottom half from interrupt or NAPI polling context
*/
static int
-spider_net_decode_one_descr(struct spider_net_card *card, int napi)
+spider_net_decode_one_descr(struct spider_net_card *card)
{
struct spider_net_descr_chain *chain = &card->rx_chain;
struct spider_net_descr *descr = chain->tail;
int status;
- int result;
status = spider_net_get_descr_status(descr);
- if (status == SPIDER_NET_DESCR_CARDOWNED) {
- /* nothing in the descriptor yet */
- result=0;
- goto out;
- }
-
- if (status == SPIDER_NET_DESCR_NOT_IN_USE) {
- /* not initialized yet, the ring must be empty */
- spider_net_refill_rx_chain(card);
- spider_net_enable_rxdmac(card);
- result=0;
- goto out;
- }
+ /* Nothing in the descriptor, or ring must be empty */
+ if ((status == SPIDER_NET_DESCR_CARDOWNED) ||
+ (status == SPIDER_NET_DESCR_NOT_IN_USE))
+ return 0;
/* descriptor definitively used -- move on tail */
chain->tail = descr->next;
- result = 0;
+ /* unmap descriptor */
+ pci_unmap_single(card->pdev, descr->buf_addr,
+ SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
+
if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
(status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
(status == SPIDER_NET_DESCR_FORCE_END) ) {
@@ -1035,31 +1031,55 @@ spider_net_decode_one_descr(struct spider_net_card *card, int napi)
pr_err("%s: dropping RX descriptor with state %d\n",
card->netdev->name, status);
card->netdev_stats.rx_dropped++;
- pci_unmap_single(card->pdev, descr->buf_addr,
- SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
- dev_kfree_skb_irq(descr->skb);
- goto refill;
+ goto bad_desc;
}
if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
(status != SPIDER_NET_DESCR_FRAME_END) ) {
- if (netif_msg_rx_err(card)) {
- pr_err("%s: RX descriptor with state %d\n",
+ if (netif_msg_rx_err(card))
+ pr_err("%s: RX descriptor with unkown state %d\n",
card->netdev->name, status);
- card->spider_stats.rx_desc_unk_state++;
- }
- goto refill;
+ card->spider_stats.rx_desc_unk_state++;
+ goto bad_desc;
+ }
+
+ /* The cases we'll throw away the packet immediately */
+ if (descr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
+ if (netif_msg_rx_err(card))
+ pr_err("%s: error in received descriptor found, "
+ "data_status=x%08x, data_error=x%08x\n",
+ card->netdev->name,
+ descr->data_status, descr->data_error);
+ goto bad_desc;
}
- /* ok, we've got a packet in descr */
- result = spider_net_pass_skb_up(descr, card, napi);
-refill:
+ if (descr->dmac_cmd_status & 0xfefe) {
+ pr_err("%s: bad status, cmd_status=x%08x\n",
+ card->netdev->name,
+ descr->dmac_cmd_status);
+ pr_err("buf_addr=x%08x\n", descr->buf_addr);
+ pr_err("buf_size=x%08x\n", descr->buf_size);
+ pr_err("next_descr_addr=x%08x\n", descr->next_descr_addr);
+ pr_err("result_size=x%08x\n", descr->result_size);
+ pr_err("valid_size=x%08x\n", descr->valid_size);
+ pr_err("data_status=x%08x\n", descr->data_status);
+ pr_err("data_error=x%08x\n", descr->data_error);
+ pr_err("bus_addr=x%08x\n", descr->bus_addr);
+ pr_err("which=%ld\n", descr - card->rx_chain.ring);
+
+ card->spider_stats.rx_desc_error++;
+ goto bad_desc;
+ }
+
+ /* Ok, we've got a packet in descr */
+ spider_net_pass_skb_up(descr, card);
descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
- /* change the descriptor state: */
- if (!napi)
- spider_net_refill_rx_chain(card);
-out:
- return result;
+ return 1;
+
+bad_desc:
+ dev_kfree_skb_irq(descr->skb);
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ return 0;
}
/**
@@ -1085,7 +1105,7 @@ spider_net_poll(struct net_device *netdev, int *budget)
packets_to_do = min(*budget, netdev->quota);
while (packets_to_do) {
- if (spider_net_decode_one_descr(card, 1)) {
+ if (spider_net_decode_one_descr(card)) {
packets_done++;
packets_to_do--;
} else {
@@ -1098,6 +1118,7 @@ spider_net_poll(struct net_device *netdev, int *budget)
netdev->quota -= packets_done;
*budget -= packets_done;
spider_net_refill_rx_chain(card);
+ spider_net_enable_rxdmac(card);
/* if all packets are in the stack, enable interrupts and return 0 */
/* if not, return 1 */
@@ -1227,24 +1248,6 @@ spider_net_set_mac(struct net_device *netdev, void *p)
}
/**
- * spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt
- * @card: card structure
- *
- * spider_net_handle_rxram_full empties the RX ring so that spider can put
- * more packets in it and empty its RX RAM. This is called in bottom half
- * context
- */
-static void
-spider_net_handle_rxram_full(struct spider_net_card *card)
-{
- while (spider_net_decode_one_descr(card, 0))
- ;
- spider_net_enable_rxchtails(card);
- spider_net_enable_rxdmac(card);
- netif_rx_schedule(card->netdev);
-}
-
-/**
* spider_net_handle_error_irq - handles errors raised by an interrupt
* @card: card structure
* @status_reg: interrupt status register 0 (GHIINT0STS)
@@ -1366,10 +1369,10 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
case SPIDER_NET_GRFAFLLINT: /* fallthrough */
case SPIDER_NET_GRMFLLINT:
if (netif_msg_intr(card) && net_ratelimit())
- pr_debug("Spider RX RAM full, incoming packets "
+ pr_err("Spider RX RAM full, incoming packets "
"might be discarded!\n");
spider_net_rx_irq_off(card);
- tasklet_schedule(&card->rxram_full_tl);
+ netif_rx_schedule(card->netdev);
show_error = 0;
break;
@@ -1384,7 +1387,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
case SPIDER_NET_GDCDCEINT: /* fallthrough */
case SPIDER_NET_GDBDCEINT: /* fallthrough */
case SPIDER_NET_GDADCEINT:
- if (netif_msg_intr(card))
+ if (netif_msg_intr(card) && net_ratelimit())
pr_err("got descriptor chain end interrupt, "
"restarting DMAC %c.\n",
'D'-(i-SPIDER_NET_GDDDCEINT)/3);
@@ -1455,7 +1458,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
break;
}
- if ((show_error) && (netif_msg_intr(card)))
+ if ((show_error) && (netif_msg_intr(card)) && net_ratelimit())
pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, "
"GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
card->netdev->name,
@@ -1651,27 +1654,18 @@ int
spider_net_open(struct net_device *netdev)
{
struct spider_net_card *card = netdev_priv(netdev);
- struct spider_net_descr *descr;
- int i, result;
+ int result;
- result = -ENOMEM;
- if (spider_net_init_chain(card, &card->tx_chain, card->descr,
- card->num_tx_desc))
+ result = spider_net_init_chain(card, &card->tx_chain);
+ if (result)
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->num_tx_desc,
- card->num_rx_desc))
+ result = spider_net_init_chain(card, &card->rx_chain);
+ if (result)
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 */
+ /* Allocate rx skbs */
if (spider_net_alloc_rx_skbs(card))
goto alloc_skbs_failed;
@@ -1902,7 +1896,6 @@ spider_net_stop(struct net_device *netdev)
{
struct spider_net_card *card = netdev_priv(netdev);
- tasklet_kill(&card->rxram_full_tl);
netif_poll_disable(netdev);
netif_carrier_off(netdev);
netif_stop_queue(netdev);
@@ -1914,7 +1907,7 @@ spider_net_stop(struct net_device *netdev)
spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
/* free_irq(netdev->irq, netdev);*/
- free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev);
+ free_irq(to_pci_dev(netdev->dev.parent)->irq, netdev);
spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
SPIDER_NET_DMA_TX_FEND_VALUE);
@@ -1924,6 +1917,9 @@ spider_net_stop(struct net_device *netdev)
/* release chains */
spider_net_release_tx_chain(card, 1);
+ spider_net_free_rx_chain_contents(card);
+
+ spider_net_free_rx_chain_contents(card);
spider_net_free_chain(card, &card->tx_chain);
spider_net_free_chain(card, &card->rx_chain);
@@ -2044,9 +2040,6 @@ spider_net_setup_netdev(struct spider_net_card *card)
pci_set_drvdata(card->pdev, netdev);
- card->rxram_full_tl.data = (unsigned long) card;
- card->rxram_full_tl.func =
- (void (*)(unsigned long)) spider_net_handle_rxram_full;
init_timer(&card->tx_timer);
card->tx_timer.function =
(void (*)(unsigned long)) spider_net_cleanup_tx_ring;
@@ -2055,8 +2048,8 @@ spider_net_setup_netdev(struct spider_net_card *card)
card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
- card->num_tx_desc = tx_descriptors;
- card->num_rx_desc = rx_descriptors;
+ card->tx_chain.num_desc = tx_descriptors;
+ card->rx_chain.num_desc = rx_descriptors;
spider_net_setup_netdev_ops(netdev);
@@ -2105,12 +2098,8 @@ spider_net_alloc_card(void)
{
struct net_device *netdev;
struct spider_net_card *card;
- size_t alloc_size;
- alloc_size = sizeof (*card) +
- sizeof (struct spider_net_descr) * rx_descriptors +
- sizeof (struct spider_net_descr) * tx_descriptors;
- netdev = alloc_etherdev(alloc_size);
+ netdev = alloc_etherdev(sizeof(struct spider_net_card));
if (!netdev)
return NULL;
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index 3e196df2979..2fec5cf7692 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -24,7 +24,7 @@
#ifndef _SPIDER_NET_H
#define _SPIDER_NET_H
-#define VERSION "1.6 A"
+#define VERSION "1.6 B"
#include "sungem_phy.h"
@@ -378,6 +378,9 @@ struct spider_net_descr_chain {
spinlock_t lock;
struct spider_net_descr *head;
struct spider_net_descr *tail;
+ struct spider_net_descr *ring;
+ int num_desc;
+ dma_addr_t dma_addr;
};
/* descriptor data_status bits */
@@ -397,8 +400,6 @@ struct spider_net_descr_chain {
* 701b8000 would be correct, but every packets gets that flag */
#define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000
-#define SPIDER_NET_DESCR_SIZE 32
-
/* this will be bigger some time */
struct spider_net_options {
int rx_csum; /* for rx: if 0 ip_summed=NONE,
@@ -441,25 +442,16 @@ struct spider_net_card {
struct spider_net_descr_chain rx_chain;
struct spider_net_descr *low_watermark;
- struct net_device_stats netdev_stats;
-
- struct spider_net_options options;
-
- spinlock_t intmask_lock;
- struct tasklet_struct rxram_full_tl;
struct timer_list tx_timer;
-
struct work_struct tx_timeout_task;
atomic_t tx_timeout_task_counter;
wait_queue_head_t waitq;
/* for ethtool */
int msg_enable;
- int num_rx_desc;
- int num_tx_desc;
+ struct net_device_stats netdev_stats;
struct spider_net_extra_stats spider_stats;
-
- struct spider_net_descr descr[0];
+ struct spider_net_options options;
};
#define pr_err(fmt,arg...) \
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index 91b99510291..6bcf03fc89b 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -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->num_tx_desc;
+ ering->tx_pending = card->tx_chain.num_desc;
ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX;
- ering->rx_pending = card->num_rx_desc;
+ ering->rx_pending = card->rx_chain.num_desc;
}
static int spider_net_get_stats_count(struct net_device *netdev)
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 785e4a535f9..616be8d0fa8 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -90,7 +90,8 @@
#define ADVERTISE_MASK (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
- SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
+ SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full | \
+ SUPPORTED_Pause | SUPPORTED_Autoneg)
#define DRV_NAME "sungem"
#define DRV_VERSION "0.98"
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index 49800b25907..d21991ee88c 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -3,10 +3,9 @@
*
* This file could be shared with other drivers.
*
- * (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
*
* TODO:
- * - Implement WOL
* - Add support for PHYs that provide an IRQ line
* - Eventually moved the entire polling state machine in
* there (out of the eth driver), so that it can easily be
@@ -152,6 +151,44 @@ static int bcm5221_suspend(struct mii_phy* phy)
return 0;
}
+static int bcm5241_init(struct mii_phy* phy)
+{
+ u16 data;
+
+ data = phy_read(phy, MII_BCM5221_TEST);
+ phy_write(phy, MII_BCM5221_TEST,
+ data | MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+ data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
+ phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
+ data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
+
+ data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+ phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+ data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
+
+ data = phy_read(phy, MII_BCM5221_TEST);
+ phy_write(phy, MII_BCM5221_TEST,
+ data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+ return 0;
+}
+
+static int bcm5241_suspend(struct mii_phy* phy)
+{
+ u16 data;
+
+ data = phy_read(phy, MII_BCM5221_TEST);
+ phy_write(phy, MII_BCM5221_TEST,
+ data | MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+ data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+ phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+ data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
+
+ return 0;
+}
+
static int bcm5400_init(struct mii_phy* phy)
{
u16 data;
@@ -373,6 +410,10 @@ static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
adv |= ADVERTISE_100HALF;
if (advertise & ADVERTISED_100baseT_Full)
adv |= ADVERTISE_100FULL;
+ if (advertise & ADVERTISED_Pause)
+ adv |= ADVERTISE_PAUSE_CAP;
+ if (advertise & ADVERTISED_Asym_Pause)
+ adv |= ADVERTISE_PAUSE_ASYM;
phy_write(phy, MII_ADVERTISE, adv);
/* Setup 1000BT advertise */
@@ -436,12 +477,15 @@ static int bcm54xx_read_link(struct mii_phy *phy)
val = phy_read(phy, MII_BCM5400_AUXSTATUS);
link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
- phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF;
+ phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
+ DUPLEX_FULL : DUPLEX_HALF;
phy->speed = phy_BCM5400_link_table[link_mode][2] ?
SPEED_1000 :
- (phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10);
+ (phy_BCM5400_link_table[link_mode][1] ?
+ SPEED_100 : SPEED_10);
val = phy_read(phy, MII_LPA);
- phy->pause = ((val & LPA_PAUSE) != 0);
+ phy->pause = (phy->duplex == DUPLEX_FULL) &&
+ ((val & LPA_PAUSE) != 0);
}
/* On non-aneg, we assume what we put in BMCR is the speed,
* though magic-aneg shouldn't prevent this case from occurring
@@ -450,6 +494,28 @@ static int bcm54xx_read_link(struct mii_phy *phy)
return 0;
}
+static int marvell88e1111_init(struct mii_phy* phy)
+{
+ u16 rev;
+
+ /* magic init sequence for rev 0 */
+ rev = phy_read(phy, MII_PHYSID2) & 0x000f;
+ if (rev == 0) {
+ phy_write(phy, 0x1d, 0x000a);
+ phy_write(phy, 0x1e, 0x0821);
+
+ phy_write(phy, 0x1d, 0x0006);
+ phy_write(phy, 0x1e, 0x8600);
+
+ phy_write(phy, 0x1d, 0x000b);
+ phy_write(phy, 0x1e, 0x0100);
+
+ phy_write(phy, 0x1d, 0x0004);
+ phy_write(phy, 0x1e, 0x4850);
+ }
+ return 0;
+}
+
static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
{
u16 ctl, adv;
@@ -471,6 +537,10 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
adv |= ADVERTISE_100HALF;
if (advertise & ADVERTISED_100baseT_Full)
adv |= ADVERTISE_100FULL;
+ if (advertise & ADVERTISED_Pause)
+ adv |= ADVERTISE_PAUSE_CAP;
+ if (advertise & ADVERTISED_Asym_Pause)
+ adv |= ADVERTISE_PAUSE_ASYM;
phy_write(phy, MII_ADVERTISE, adv);
/* Setup 1000BT advertise & enable crossover detect
@@ -549,7 +619,7 @@ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
static int marvell_read_link(struct mii_phy *phy)
{
- u16 status;
+ u16 status, pmask;
if (phy->autoneg) {
status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
@@ -565,7 +635,9 @@ static int marvell_read_link(struct mii_phy *phy)
phy->duplex = DUPLEX_FULL;
else
phy->duplex = DUPLEX_HALF;
- phy->pause = 0; /* XXX Check against spec ! */
+ pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
+ MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
+ phy->pause = (status & pmask) == pmask;
}
/* On non-aneg, we assume what we put in BMCR is the speed,
* though magic-aneg shouldn't prevent this case from occurring
@@ -595,6 +667,10 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
adv |= ADVERTISE_100HALF;
if (advertise & ADVERTISED_100baseT_Full)
adv |= ADVERTISE_100FULL;
+ if (advertise & ADVERTISED_Pause)
+ adv |= ADVERTISE_PAUSE_CAP;
+ if (advertise & ADVERTISED_Asym_Pause)
+ adv |= ADVERTISE_PAUSE_ASYM;
phy_write(phy, MII_ADVERTISE, adv);
/* Start/Restart aneg */
@@ -666,7 +742,8 @@ static int genmii_read_link(struct mii_phy *phy)
phy->speed = SPEED_100;
else
phy->speed = SPEED_10;
- phy->pause = 0;
+ phy->pause = (phy->duplex == DUPLEX_FULL) &&
+ ((lpa & LPA_PAUSE) != 0);
}
/* On non-aneg, we assume what we put in BMCR is the speed,
* though magic-aneg shouldn't prevent this case from occurring
@@ -676,11 +753,19 @@ static int genmii_read_link(struct mii_phy *phy)
}
-#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
- SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
- SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII)
-#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \
- SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
+#define MII_BASIC_FEATURES \
+ (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
+ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
+ SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \
+ SUPPORTED_Pause)
+
+/* On gigabit capable PHYs, we advertise Pause support but not asym pause
+ * support for now as I'm not sure it's supported and Darwin doesn't do
+ * it neither. --BenH.
+ */
+#define MII_GBIT_FEATURES \
+ (MII_BASIC_FEATURES | \
+ SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
/* Broadcom BCM 5201 */
static struct mii_phy_ops bcm5201_phy_ops = {
@@ -720,6 +805,24 @@ static struct mii_phy_def bcm5221_phy_def = {
.ops = &bcm5221_phy_ops
};
+/* Broadcom BCM 5241 */
+static struct mii_phy_ops bcm5241_phy_ops = {
+ .suspend = bcm5241_suspend,
+ .init = bcm5241_init,
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link,
+};
+static struct mii_phy_def bcm5241_phy_def = {
+ .phy_id = 0x0143bc30,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5241",
+ .features = MII_BASIC_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5241_phy_ops
+};
+
/* Broadcom BCM 5400 */
static struct mii_phy_ops bcm5400_phy_ops = {
.init = bcm5400_init,
@@ -854,11 +957,8 @@ static struct mii_phy_def bcm5462V_phy_def = {
.ops = &bcm5462V_phy_ops
};
-/* Marvell 88E1101 (Apple seem to deal with 2 different revs,
- * I masked out the 8 last bits to get both, but some specs
- * would be useful here) --BenH.
- */
-static struct mii_phy_ops marvell_phy_ops = {
+/* Marvell 88E1101 amd 88E1111 */
+static struct mii_phy_ops marvell88e1101_phy_ops = {
.suspend = generic_suspend,
.setup_aneg = marvell_setup_aneg,
.setup_forced = marvell_setup_forced,
@@ -866,13 +966,41 @@ static struct mii_phy_ops marvell_phy_ops = {
.read_link = marvell_read_link
};
-static struct mii_phy_def marvell_phy_def = {
- .phy_id = 0x01410c00,
- .phy_id_mask = 0xffffff00,
- .name = "Marvell 88E1101",
+static struct mii_phy_ops marvell88e1111_phy_ops = {
+ .init = marvell88e1111_init,
+ .suspend = generic_suspend,
+ .setup_aneg = marvell_setup_aneg,
+ .setup_forced = marvell_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = marvell_read_link
+};
+
+/* two revs in darwin for the 88e1101 ... I could use a datasheet
+ * to get the proper names...
+ */
+static struct mii_phy_def marvell88e1101v1_phy_def = {
+ .phy_id = 0x01410c20,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Marvell 88E1101v1",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &marvell88e1101_phy_ops
+};
+static struct mii_phy_def marvell88e1101v2_phy_def = {
+ .phy_id = 0x01410c60,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Marvell 88E1101v2",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &marvell88e1101_phy_ops
+};
+static struct mii_phy_def marvell88e1111_phy_def = {
+ .phy_id = 0x01410cc0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Marvell 88E1111",
.features = MII_GBIT_FEATURES,
.magic_aneg = 1,
- .ops = &marvell_phy_ops
+ .ops = &marvell88e1111_phy_ops
};
/* Generic implementation for most 10/100 PHYs */
@@ -895,6 +1023,7 @@ static struct mii_phy_def genmii_phy_def = {
static struct mii_phy_def* mii_phy_table[] = {
&bcm5201_phy_def,
&bcm5221_phy_def,
+ &bcm5241_phy_def,
&bcm5400_phy_def,
&bcm5401_phy_def,
&bcm5411_phy_def,
@@ -902,7 +1031,9 @@ static struct mii_phy_def* mii_phy_table[] = {
&bcm5421k2_phy_def,
&bcm5461_phy_def,
&bcm5462V_phy_def,
- &marvell_phy_def,
+ &marvell88e1101v1_phy_def,
+ &marvell88e1101v2_phy_def,
+ &marvell88e1111_phy_def,
&genmii_phy_def,
NULL
};
diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h
index 8ee1ca0471c..1d70ba6f9f1 100644
--- a/drivers/net/sungem_phy.h
+++ b/drivers/net/sungem_phy.h
@@ -30,7 +30,7 @@ struct mii_phy_def
struct mii_phy
{
struct mii_phy_def* def;
- int advertising;
+ u32 advertising;
int mii_id;
/* 1: autoneg enabled, 0: disabled */
@@ -85,6 +85,9 @@ extern int mii_phy_probe(struct mii_phy *phy, int mii_id);
#define MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE 0x0001
#define MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR 0x0004
+/* MII BCM5241 Additional registers */
+#define MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR 0x0008
+
/* MII BCM5400 1000-BASET Control register */
#define MII_BCM5400_GB_CONTROL 0x09
#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200
@@ -115,5 +118,7 @@ extern int mii_phy_probe(struct mii_phy *phy, int mii_id);
#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000
#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000
#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800
+#define MII_M1011_PHY_SPEC_STATUS_TX_PAUSE 0x0008
+#define MII_M1011_PHY_SPEC_STATUS_RX_PAUSE 0x0004
#endif /* __SUNGEM_PHY_H__ */
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 571320ae87a..e136bae6197 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -58,18 +58,14 @@
#define TG3_VLAN_TAG_USED 0
#endif
-#ifdef NETIF_F_TSO
#define TG3_TSO_SUPPORT 1
-#else
-#define TG3_TSO_SUPPORT 0
-#endif
#include "tg3.h"
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.70"
-#define DRV_MODULE_RELDATE "December 1, 2006"
+#define DRV_MODULE_VERSION "3.72"
+#define DRV_MODULE_RELDATE "January 8, 2007"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -959,6 +955,13 @@ static int tg3_phy_reset(struct tg3 *tp)
u32 phy_status;
int err;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 val;
+
+ val = tr32(GRC_MISC_CFG);
+ tw32_f(GRC_MISC_CFG, val & ~GRC_MISC_CFG_EPHY_IDDQ);
+ udelay(40);
+ }
err = tg3_readphy(tp, MII_BMSR, &phy_status);
err |= tg3_readphy(tp, MII_BMSR, &phy_status);
if (err != 0)
@@ -1008,7 +1011,12 @@ out:
else if (tp->tg3_flags2 & TG3_FLG2_PHY_JITTER_BUG) {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
- tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b);
+ if (tp->tg3_flags2 & TG3_FLG2_PHY_ADJUST_TRIM) {
+ tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b);
+ tg3_writephy(tp, MII_TG3_TEST1,
+ MII_TG3_TEST1_TRIM_EN | 0x4);
+ } else
+ tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b);
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
}
/* Set Extended packet length bit (bit 14) on all chips that */
@@ -1170,7 +1178,15 @@ 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) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 val;
+
+ tg3_bmcr_reset(tp);
+ val = tr32(GRC_MISC_CFG);
+ tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
+ udelay(40);
+ return;
+ } else {
tg3_writephy(tp, MII_TG3_EXT_CTRL,
MII_TG3_EXT_CTRL_FORCE_LED_OFF);
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
@@ -3364,7 +3380,7 @@ next_pkt:
}
next_pkt_nopost:
sw_idx++;
- sw_idx %= TG3_RX_RCB_RING_SIZE(tp);
+ sw_idx &= (TG3_RX_RCB_RING_SIZE(tp) - 1);
/* Refresh hw_idx to see if there is new work */
if (sw_idx == hw_idx) {
@@ -3853,7 +3869,6 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = tp->tx_prod;
base_flags = 0;
-#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
(mss = skb_shinfo(skb)->gso_size) != 0) {
@@ -3886,11 +3901,6 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
else if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#else
- mss = 0;
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#endif
#if TG3_VLAN_TAG_USED
if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
base_flags |= (TXD_FLAG_VLAN |
@@ -3950,7 +3960,6 @@ out_unlock:
return NETDEV_TX_OK;
}
-#if TG3_TSO_SUPPORT != 0
static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *);
/* Use GSO to workaround a rare TSO bug that may be triggered when the
@@ -3982,7 +3991,6 @@ tg3_tso_bug_end:
return NETDEV_TX_OK;
}
-#endif
/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
* support TG3_FLG2_HW_TSO_1 or firmware TSO only.
@@ -4016,7 +4024,6 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
base_flags = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
(mss = skb_shinfo(skb)->gso_size) != 0) {
@@ -4071,9 +4078,6 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
}
}
}
-#else
- mss = 0;
-#endif
#if TG3_VLAN_TAG_USED
if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
base_flags |= (TXD_FLAG_VLAN |
@@ -4426,7 +4430,7 @@ static void tg3_free_consistent(struct tg3 *tp)
*/
static int tg3_alloc_consistent(struct tg3 *tp)
{
- tp->rx_std_buffers = kmalloc((sizeof(struct ring_info) *
+ tp->rx_std_buffers = kzalloc((sizeof(struct ring_info) *
(TG3_RX_RING_SIZE +
TG3_RX_JUMBO_RING_SIZE)) +
(sizeof(struct tx_ring_info) *
@@ -4435,13 +4439,6 @@ static int tg3_alloc_consistent(struct tg3 *tp)
if (!tp->rx_std_buffers)
return -ENOMEM;
- memset(tp->rx_std_buffers, 0,
- (sizeof(struct ring_info) *
- (TG3_RX_RING_SIZE +
- TG3_RX_JUMBO_RING_SIZE)) +
- (sizeof(struct tx_ring_info) *
- TG3_TX_RING_SIZE));
-
tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
tp->tx_buffers = (struct tx_ring_info *)
&tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE];
@@ -5316,7 +5313,6 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
return 0;
}
-#if TG3_TSO_SUPPORT != 0
#define TG3_TSO_FW_RELEASE_MAJOR 0x1
#define TG3_TSO_FW_RELASE_MINOR 0x6
@@ -5893,7 +5889,6 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
return 0;
}
-#endif /* TG3_TSO_SUPPORT != 0 */
/* tp->lock is held. */
static void __tg3_set_mac_addr(struct tg3 *tp)
@@ -6107,7 +6102,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
}
-#if TG3_TSO_SUPPORT != 0
else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
int fw_len;
@@ -6122,7 +6116,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(BUFMGR_MB_POOL_SIZE,
NIC_SRAM_MBUF_POOL_SIZE5705 - fw_len - 0xa00);
}
-#endif
if (tp->dev->mtu <= ETH_DATA_LEN) {
tw32(BUFMGR_MB_RDMA_LOW_WATER,
@@ -6324,10 +6317,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
rdmac_mode |= (1 << 27);
-#endif
/* Receive/send statistics. */
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
@@ -6498,10 +6489,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8);
-#endif
tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE);
tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE);
@@ -6511,13 +6500,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
return err;
}
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
err = tg3_load_tso_firmware(tp);
if (err)
return err;
}
-#endif
tp->tx_mode = TX_MODE_ENABLE;
tw32_f(MAC_TX_MODE, tp->tx_mode);
@@ -6988,6 +6975,8 @@ static int tg3_open(struct net_device *dev)
struct tg3 *tp = netdev_priv(dev);
int err;
+ netif_carrier_off(tp->dev);
+
tg3_full_lock(tp, 0);
err = tg3_set_power_state(tp, PCI_D0);
@@ -7981,6 +7970,10 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
tp->link_config.duplex = cmd->duplex;
}
+ tp->link_config.orig_speed = tp->link_config.speed;
+ tp->link_config.orig_duplex = tp->link_config.duplex;
+ tp->link_config.orig_autoneg = tp->link_config.autoneg;
+
if (netif_running(dev))
tg3_setup_phy(tp, 1);
@@ -8043,7 +8036,6 @@ static void tg3_set_msglevel(struct net_device *dev, u32 value)
tp->msg_enable = value;
}
-#if TG3_TSO_SUPPORT != 0
static int tg3_set_tso(struct net_device *dev, u32 value)
{
struct tg3 *tp = netdev_priv(dev);
@@ -8062,7 +8054,6 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
}
return ethtool_op_set_tso(dev, value);
}
-#endif
static int tg3_nway_reset(struct net_device *dev)
{
@@ -9193,10 +9184,8 @@ static const struct ethtool_ops tg3_ethtool_ops = {
.set_tx_csum = tg3_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#if TG3_TSO_SUPPORT != 0
.get_tso = ethtool_op_get_tso,
.set_tso = tg3_set_tso,
-#endif
.self_test_count = tg3_get_test_count,
.self_test = tg3_self_test,
.get_strings = tg3_get_strings,
@@ -10789,9 +10778,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5705_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) {
tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
+ if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M)
+ tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM;
+ } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
}
@@ -11835,7 +11826,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tg3_init_bufmgr_config(tp);
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
}
@@ -11860,7 +11850,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev->features |= NETIF_F_TSO6;
}
-#endif
if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 &&
!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) &&
@@ -11923,6 +11912,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
*/
pci_save_state(tp->pdev);
+ pci_set_drvdata(pdev, dev);
+
err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "Cannot register net device, "
@@ -11930,8 +11921,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
goto err_out_iounmap;
}
- pci_set_drvdata(pdev, dev);
-
printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ",
dev->name,
tp->board_part_number,
@@ -11962,8 +11951,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
(pdev->dma_mask == DMA_32BIT_MASK) ? 32 :
(((u64) pdev->dma_mask == DMA_40BIT_MASK) ? 40 : 64));
- netif_carrier_off(tp->dev);
-
return 0;
err_out_iounmap:
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index dfaf4ed127b..80f59ac7ec5 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -1350,6 +1350,7 @@
#define GRC_MISC_CFG_BOARD_ID_5788 0x00010000
#define GRC_MISC_CFG_BOARD_ID_5788M 0x00018000
#define GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000
+#define GRC_MISC_CFG_EPHY_IDDQ 0x00200000
#define GRC_MISC_CFG_KEEP_GPHY_POWER 0x04000000
#define GRC_LOCAL_CTRL 0x00006808
#define GRC_LCLCTRL_INT_ACTIVE 0x00000001
@@ -1657,6 +1658,9 @@
#define MII_TG3_EPHY_TEST 0x1f /* 5906 PHY register */
#define MII_TG3_EPHY_SHADOW_EN 0x80
+#define MII_TG3_TEST1 0x1e
+#define MII_TG3_TEST1_TRIM_EN 0x0010
+
/* 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
@@ -2255,6 +2259,7 @@ struct tg3 {
#define TG3_FLG2_1SHOT_MSI 0x10000000
#define TG3_FLG2_PHY_JITTER_BUG 0x20000000
#define TG3_FLG2_NO_FWARE_REPORTED 0x40000000
+#define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000
u32 split_mode_max_reqs;
#define SPLIT_MODE_5704_MAX_REQ 3
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 1f05511fa39..31c97a6591a 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -29,6 +29,7 @@
#include <linux/fsl_devices.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/workqueue.h>
#include <asm/of_platform.h>
#include <asm/uaccess.h>
@@ -194,9 +195,9 @@ static void enqueue(struct list_head *node, struct list_head *lh)
{
unsigned long flags;
- spin_lock_irqsave(ugeth_lock, flags);
+ spin_lock_irqsave(&ugeth_lock, flags);
list_add_tail(node, lh);
- spin_unlock_irqrestore(ugeth_lock, flags);
+ spin_unlock_irqrestore(&ugeth_lock, flags);
}
#endif /* CONFIG_UGETH_FILTERING */
@@ -204,14 +205,14 @@ static struct list_head *dequeue(struct list_head *lh)
{
unsigned long flags;
- spin_lock_irqsave(ugeth_lock, flags);
+ spin_lock_irqsave(&ugeth_lock, flags);
if (!list_empty(lh)) {
struct list_head *node = lh->next;
list_del(node);
- spin_unlock_irqrestore(ugeth_lock, flags);
+ spin_unlock_irqrestore(&ugeth_lock, flags);
return node;
} else {
- spin_unlock_irqrestore(ugeth_lock, flags);
+ spin_unlock_irqrestore(&ugeth_lock, flags);
return NULL;
}
}
@@ -472,7 +473,7 @@ static void put_enet_addr_container(struct enet_addr_container *enet_addr_cont)
kfree(enet_addr_cont);
}
-static int set_mac_addr(__be16 __iomem *reg, u8 *mac)
+static void set_mac_addr(__be16 __iomem *reg, u8 *mac)
{
out_be16(&reg[0], ((u16)mac[5] << 8) | mac[4]);
out_be16(&reg[1], ((u16)mac[3] << 8) | mac[2]);
@@ -1708,75 +1709,13 @@ static void adjust_link(struct net_device *dev)
if (mii_info->speed != ugeth->oldspeed) {
switch (mii_info->speed) {
case 1000:
-#ifdef CONFIG_PPC_MPC836x
-/* FIXME: This code is for 100Mbs BUG fixing,
-remove this when it is fixed!!! */
- if (ugeth->ug_info->enet_interface ==
- ENET_1000_GMII)
- /* Run the commands which initialize the PHY */
- {
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id, 0x1b);
- tempval |= 0x000f;
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, 0x1b,
- (u16) tempval);
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id,
- MII_BMCR);
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, MII_BMCR,
- (u16) (tempval | BMCR_RESET));
- } else if (ugeth->ug_info->enet_interface ==
- ENET_1000_RGMII)
- /* Run the commands which initialize the PHY */
- {
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id, 0x1b);
- tempval = (tempval & ~0x000f) | 0x000b;
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, 0x1b,
- (u16) tempval);
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id,
- MII_BMCR);
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, MII_BMCR,
- (u16) (tempval | BMCR_RESET));
- }
- msleep(4000);
-#endif /* CONFIG_MPC8360 */
- adjust_enet_interface(ugeth);
+ ugeth->ug_info->enet_interface = ENET_1000_RGMII;
break;
case 100:
- case 10:
-#ifdef CONFIG_PPC_MPC836x
-/* FIXME: This code is for 100Mbs BUG fixing,
-remove this lines when it will be fixed!!! */
ugeth->ug_info->enet_interface = ENET_100_RGMII;
- tempval =
- (u32) mii_info->mdio_read(ugeth->dev,
- mii_info->mii_id,
- 0x1b);
- tempval = (tempval & ~0x000f) | 0x000b;
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, 0x1b,
- (u16) tempval);
- tempval =
- (u32) mii_info->mdio_read(ugeth->dev,
- mii_info->mii_id,
- MII_BMCR);
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, MII_BMCR,
- (u16) (tempval |
- BMCR_RESET));
- msleep(4000);
-#endif /* CONFIG_MPC8360 */
- adjust_enet_interface(ugeth);
+ break;
+ case 10:
+ ugeth->ug_info->enet_interface = ENET_10_RGMII;
break;
default:
ugeth_warn
@@ -1784,6 +1723,7 @@ remove this lines when it will be fixed!!! */
dev->name, mii_info->speed);
break;
}
+ adjust_enet_interface(ugeth);
ugeth_info("%s: Speed %dBT", dev->name,
mii_info->speed);
@@ -1852,6 +1792,8 @@ static int init_phy(struct net_device *dev)
mii_info->mdio_read = &read_phy_reg;
mii_info->mdio_write = &write_phy_reg;
+ spin_lock_init(&mii_info->mdio_lock);
+
ugeth->mii_info = mii_info;
spin_lock_irq(&ugeth->lock);
@@ -2862,8 +2804,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4)
align = UCC_GETH_TX_BD_RING_ALIGNMENT;
ugeth->tx_bd_ring_offset[j] =
- (u32) (kmalloc((u32) (length + align),
- GFP_KERNEL));
+ kmalloc((u32) (length + align), GFP_KERNEL);
+
if (ugeth->tx_bd_ring_offset[j] != 0)
ugeth->p_tx_bd_ring[j] =
(void*)((ugeth->tx_bd_ring_offset[j] +
@@ -2898,7 +2840,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4)
align = UCC_GETH_RX_BD_RING_ALIGNMENT;
ugeth->rx_bd_ring_offset[j] =
- (u32) (kmalloc((u32) (length + align), GFP_KERNEL));
+ kmalloc((u32) (length + align), GFP_KERNEL);
if (ugeth->rx_bd_ring_offset[j] != 0)
ugeth->p_rx_bd_ring[j] =
(void*)((ugeth->rx_bd_ring_offset[j] +
@@ -2924,10 +2866,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* Init Tx bds */
for (j = 0; j < ug_info->numQueuesTx; j++) {
/* Setup the skbuff rings */
- ugeth->tx_skbuff[j] =
- (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
- ugeth->ug_info->bdRingLenTx[j],
- GFP_KERNEL);
+ ugeth->tx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+ ugeth->ug_info->bdRingLenTx[j],
+ GFP_KERNEL);
if (ugeth->tx_skbuff[j] == NULL) {
ugeth_err("%s: Could not allocate tx_skbuff",
@@ -2956,10 +2897,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* Init Rx bds */
for (j = 0; j < ug_info->numQueuesRx; j++) {
/* Setup the skbuff rings */
- ugeth->rx_skbuff[j] =
- (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
- ugeth->ug_info->bdRingLenRx[j],
- GFP_KERNEL);
+ ugeth->rx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+ ugeth->ug_info->bdRingLenRx[j],
+ GFP_KERNEL);
if (ugeth->rx_skbuff[j] == NULL) {
ugeth_err("%s: Could not allocate rx_skbuff",
@@ -3450,8 +3390,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
* allocated resources can be released when the channel is freed.
*/
if (!(ugeth->p_init_enet_param_shadow =
- (struct ucc_geth_init_pram *) kmalloc(sizeof(struct ucc_geth_init_pram),
- GFP_KERNEL))) {
+ kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) {
ugeth_err
("%s: Can not allocate memory for"
" p_UccInitEnetParamShadows.", __FUNCTION__);
@@ -3918,10 +3857,11 @@ static irqreturn_t phy_interrupt(int irq, void *dev_id)
}
/* Scheduled by the phy_interrupt/timer to handle PHY changes */
-static void ugeth_phy_change(void *data)
+static void ugeth_phy_change(struct work_struct *work)
{
- struct net_device *dev = (struct net_device *)data;
- struct ucc_geth_private *ugeth = netdev_priv(dev);
+ struct ucc_geth_private *ugeth =
+ container_of(work, struct ucc_geth_private, tq);
+ struct net_device *dev = ugeth->dev;
struct ucc_geth *ug_regs;
int result = 0;
@@ -4078,7 +4018,7 @@ static int ucc_geth_open(struct net_device *dev)
#endif /* CONFIG_UGETH_NAPI */
/* Set up the PHY change work queue */
- INIT_WORK(&ugeth->tq, ugeth_phy_change, dev);
+ INIT_WORK(&ugeth->tq, ugeth_phy_change);
init_timer(&ugeth->phy_info_timer);
ugeth->phy_info_timer.function = &ugeth_phy_startup_timer;
@@ -4132,6 +4072,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
static int mii_mng_configured = 0;
const phandle *ph;
const unsigned int *prop;
+ const void *mac_addr;
ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -4257,7 +4198,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
ugeth->ug_info = ug_info;
ugeth->dev = dev;
- memcpy(dev->dev_addr, get_property(np, "mac-address", NULL), 6);
+
+ mac_addr = get_property(np, "mac-address", NULL);
+ if (mac_addr == NULL)
+ mac_addr = get_property(np, "local-mac-address", NULL);
+ if (mac_addr)
+ memcpy(dev->dev_addr, mac_addr, 6);
return 0;
}
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
index 5360ec05eaa..6fda6d88be4 100644
--- a/drivers/net/ucc_geth_phy.c
+++ b/drivers/net/ucc_geth_phy.c
@@ -68,8 +68,31 @@ static int gbit_config_aneg(struct ugeth_mii_info *mii_info);
static int genmii_config_aneg(struct ugeth_mii_info *mii_info);
static int genmii_update_link(struct ugeth_mii_info *mii_info);
static int genmii_read_status(struct ugeth_mii_info *mii_info);
-u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum);
-void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val);
+
+static u16 ucc_geth_phy_read(struct ugeth_mii_info *mii_info, u16 regnum)
+{
+ u16 retval;
+ unsigned long flags;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ spin_lock_irqsave(&mii_info->mdio_lock, flags);
+ retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
+ spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
+
+ return retval;
+}
+
+static void ucc_geth_phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val)
+{
+ unsigned long flags;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ spin_lock_irqsave(&mii_info->mdio_lock, flags);
+ mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val);
+ spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
+}
/* Write value to the PHY for this device to the register at regnum, */
/* waiting until the write is done before it returns. All PHY */
@@ -184,7 +207,7 @@ static void config_genmii_advert(struct ugeth_mii_info *mii_info)
advertise = mii_info->advertising;
/* Setup standard advertisement */
- adv = phy_read(mii_info, MII_ADVERTISE);
+ adv = ucc_geth_phy_read(mii_info, MII_ADVERTISE);
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
if (advertise & ADVERTISED_10baseT_Half)
adv |= ADVERTISE_10HALF;
@@ -194,7 +217,7 @@ static void config_genmii_advert(struct ugeth_mii_info *mii_info)
adv |= ADVERTISE_100HALF;
if (advertise & ADVERTISED_100baseT_Full)
adv |= ADVERTISE_100FULL;
- phy_write(mii_info, MII_ADVERTISE, adv);
+ ucc_geth_phy_write(mii_info, MII_ADVERTISE, adv);
}
static void genmii_setup_forced(struct ugeth_mii_info *mii_info)
@@ -204,7 +227,7 @@ static void genmii_setup_forced(struct ugeth_mii_info *mii_info)
ugphy_vdbg("%s: IN", __FUNCTION__);
- ctrl = phy_read(mii_info, MII_BMCR);
+ ctrl = ucc_geth_phy_read(mii_info, MII_BMCR);
ctrl &=
~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
@@ -234,7 +257,7 @@ static void genmii_setup_forced(struct ugeth_mii_info *mii_info)
break;
}
- phy_write(mii_info, MII_BMCR, ctrl);
+ ucc_geth_phy_write(mii_info, MII_BMCR, ctrl);
}
/* Enable and Restart Autonegotiation */
@@ -244,9 +267,9 @@ static void genmii_restart_aneg(struct ugeth_mii_info *mii_info)
ugphy_vdbg("%s: IN", __FUNCTION__);
- ctl = phy_read(mii_info, MII_BMCR);
+ ctl = ucc_geth_phy_read(mii_info, MII_BMCR);
ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- phy_write(mii_info, MII_BMCR, ctl);
+ ucc_geth_phy_write(mii_info, MII_BMCR, ctl);
}
static int gbit_config_aneg(struct ugeth_mii_info *mii_info)
@@ -261,14 +284,14 @@ static int gbit_config_aneg(struct ugeth_mii_info *mii_info)
config_genmii_advert(mii_info);
advertise = mii_info->advertising;
- adv = phy_read(mii_info, MII_1000BASETCONTROL);
+ adv = ucc_geth_phy_read(mii_info, MII_1000BASETCONTROL);
adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
MII_1000BASETCONTROL_HALFDUPLEXCAP);
if (advertise & SUPPORTED_1000baseT_Half)
adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
if (advertise & SUPPORTED_1000baseT_Full)
adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
- phy_write(mii_info, MII_1000BASETCONTROL, adv);
+ ucc_geth_phy_write(mii_info, MII_1000BASETCONTROL, adv);
/* Start/Restart aneg */
genmii_restart_aneg(mii_info);
@@ -298,10 +321,10 @@ static int genmii_update_link(struct ugeth_mii_info *mii_info)
ugphy_vdbg("%s: IN", __FUNCTION__);
/* Do a fake read */
- phy_read(mii_info, MII_BMSR);
+ ucc_geth_phy_read(mii_info, MII_BMSR);
/* Read link and autonegotiation status */
- status = phy_read(mii_info, MII_BMSR);
+ status = ucc_geth_phy_read(mii_info, MII_BMSR);
if ((status & BMSR_LSTATUS) == 0)
mii_info->link = 0;
else
@@ -329,7 +352,7 @@ static int genmii_read_status(struct ugeth_mii_info *mii_info)
return err;
if (mii_info->autoneg) {
- status = phy_read(mii_info, MII_LPA);
+ status = ucc_geth_phy_read(mii_info, MII_LPA);
if (status & (LPA_10FULL | LPA_100FULL))
mii_info->duplex = DUPLEX_FULL;
@@ -352,9 +375,11 @@ static int marvell_init(struct ugeth_mii_info *mii_info)
{
ugphy_vdbg("%s: IN", __FUNCTION__);
- phy_write(mii_info, 0x14, 0x0cd2);
- phy_write(mii_info, MII_BMCR,
- phy_read(mii_info, MII_BMCR) | BMCR_RESET);
+ ucc_geth_phy_write(mii_info, 0x14, 0x0cd2);
+ ucc_geth_phy_write(mii_info, 0x1b,
+ (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b);
+ ucc_geth_phy_write(mii_info, MII_BMCR,
+ ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
msleep(4000);
return 0;
@@ -367,13 +392,13 @@ static int marvell_config_aneg(struct ugeth_mii_info *mii_info)
/* The Marvell PHY has an errata which requires
* that certain registers get written in order
* to restart autonegotiation */
- phy_write(mii_info, MII_BMCR, BMCR_RESET);
+ ucc_geth_phy_write(mii_info, MII_BMCR, BMCR_RESET);
- phy_write(mii_info, 0x1d, 0x1f);
- phy_write(mii_info, 0x1e, 0x200c);
- phy_write(mii_info, 0x1d, 0x5);
- phy_write(mii_info, 0x1e, 0);
- phy_write(mii_info, 0x1e, 0x100);
+ ucc_geth_phy_write(mii_info, 0x1d, 0x1f);
+ ucc_geth_phy_write(mii_info, 0x1e, 0x200c);
+ ucc_geth_phy_write(mii_info, 0x1d, 0x5);
+ ucc_geth_phy_write(mii_info, 0x1e, 0);
+ ucc_geth_phy_write(mii_info, 0x1e, 0x100);
gbit_config_aneg(mii_info);
@@ -398,7 +423,7 @@ static int marvell_read_status(struct ugeth_mii_info *mii_info)
* are as set */
if (mii_info->autoneg && mii_info->link) {
int speed;
- status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
+ status = ucc_geth_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
/* Get the duplexity */
if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
@@ -430,7 +455,7 @@ static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info)
ugphy_vdbg("%s: IN", __FUNCTION__);
/* Clear the interrupts by reading the reg */
- phy_read(mii_info, MII_M1011_IEVENT);
+ ucc_geth_phy_read(mii_info, MII_M1011_IEVENT);
return 0;
}
@@ -440,9 +465,9 @@ static int marvell_config_intr(struct ugeth_mii_info *mii_info)
ugphy_vdbg("%s: IN", __FUNCTION__);
if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
- phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
+ ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
else
- phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
+ ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
return 0;
}
@@ -451,9 +476,9 @@ static int cis820x_init(struct ugeth_mii_info *mii_info)
{
ugphy_vdbg("%s: IN", __FUNCTION__);
- phy_write(mii_info, MII_CIS8201_AUX_CONSTAT,
+ ucc_geth_phy_write(mii_info, MII_CIS8201_AUX_CONSTAT,
MII_CIS8201_AUXCONSTAT_INIT);
- phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT);
+ ucc_geth_phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT);
return 0;
}
@@ -477,7 +502,7 @@ static int cis820x_read_status(struct ugeth_mii_info *mii_info)
if (mii_info->autoneg && mii_info->link) {
int speed;
- status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT);
+ status = ucc_geth_phy_read(mii_info, MII_CIS8201_AUX_CONSTAT);
if (status & MII_CIS8201_AUXCONSTAT_DUPLEX)
mii_info->duplex = DUPLEX_FULL;
else
@@ -505,7 +530,7 @@ static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info)
{
ugphy_vdbg("%s: IN", __FUNCTION__);
- phy_read(mii_info, MII_CIS8201_ISTAT);
+ ucc_geth_phy_read(mii_info, MII_CIS8201_ISTAT);
return 0;
}
@@ -515,9 +540,9 @@ static int cis820x_config_intr(struct ugeth_mii_info *mii_info)
ugphy_vdbg("%s: IN", __FUNCTION__);
if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
- phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK);
+ ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK);
else
- phy_write(mii_info, MII_CIS8201_IMASK, 0);
+ ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, 0);
return 0;
}
@@ -541,7 +566,7 @@ static int dm9161_read_status(struct ugeth_mii_info *mii_info)
/* If we aren't autonegotiating, assume speeds
* are as set */
if (mii_info->autoneg && mii_info->link) {
- status = phy_read(mii_info, MII_DM9161_SCSR);
+ status = ucc_geth_phy_read(mii_info, MII_DM9161_SCSR);
if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
mii_info->speed = SPEED_100;
else
@@ -572,7 +597,7 @@ static void dm9161_timer(unsigned long data)
{
struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
struct dm9161_private *priv = mii_info->priv;
- u16 status = phy_read(mii_info, MII_BMSR);
+ u16 status = ucc_geth_phy_read(mii_info, MII_BMSR);
ugphy_vdbg("%s: IN", __FUNCTION__);
@@ -599,11 +624,11 @@ static int dm9161_init(struct ugeth_mii_info *mii_info)
/* Reset is not done yet */
priv->resetdone = 0;
- phy_write(mii_info, MII_BMCR,
- phy_read(mii_info, MII_BMCR) | BMCR_RESET);
+ ucc_geth_phy_write(mii_info, MII_BMCR,
+ ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
- phy_write(mii_info, MII_BMCR,
- phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE);
+ ucc_geth_phy_write(mii_info, MII_BMCR,
+ ucc_geth_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE);
config_genmii_advert(mii_info);
/* Start/Restart aneg */
@@ -634,7 +659,7 @@ static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info)
ugphy_vdbg("%s: IN", __FUNCTION__);
/* Clear the interrupts by reading the reg */
- phy_read(mii_info, MII_DM9161_INTR);
+ ucc_geth_phy_read(mii_info, MII_DM9161_INTR);
return 0;
@@ -645,9 +670,9 @@ static int dm9161_config_intr(struct ugeth_mii_info *mii_info)
ugphy_vdbg("%s: IN", __FUNCTION__);
if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
- phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
+ ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
else
- phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
+ ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
return 0;
}
@@ -718,31 +743,6 @@ static struct phy_info *phy_info[] = {
NULL
};
-u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum)
-{
- u16 retval;
- unsigned long flags;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- spin_lock_irqsave(&mii_info->mdio_lock, flags);
- retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
- spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-
- return retval;
-}
-
-void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val)
-{
- unsigned long flags;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- spin_lock_irqsave(&mii_info->mdio_lock, flags);
- mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val);
- spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-}
-
/* Use the PHY ID registers to determine what type of PHY is attached
* to device dev. return a struct phy_info structure describing that PHY
*/
@@ -757,11 +757,11 @@ struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info)
ugphy_vdbg("%s: IN", __FUNCTION__);
/* Grab the bits from PHYIR1, and put them in the upper half */
- phy_reg = phy_read(mii_info, MII_PHYSID1);
+ phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID1);
phy_ID = (phy_reg & 0xffff) << 16;
/* Grab the bits from PHYIR2, and put them in the lower half */
- phy_reg = phy_read(mii_info, MII_PHYSID2);
+ phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID2);
phy_ID |= (phy_reg & 0xffff);
/* loop through all the known PHY types, and find one that */
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 74f894795a1..8e5d82051bd 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -265,15 +265,19 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
static int velocity_suspend(struct pci_dev *pdev, pm_message_t state);
static int velocity_resume(struct pci_dev *pdev);
+static DEFINE_SPINLOCK(velocity_dev_list_lock);
+static LIST_HEAD(velocity_dev_list);
+
+#endif
+
+#if defined(CONFIG_PM) && defined(CONFIG_INET)
+
static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr);
static struct notifier_block velocity_inetaddr_notifier = {
.notifier_call = velocity_netdev_event,
};
-static DEFINE_SPINLOCK(velocity_dev_list_lock);
-static LIST_HEAD(velocity_dev_list);
-
static void velocity_register_notifier(void)
{
register_inetaddr_notifier(&velocity_inetaddr_notifier);
@@ -284,12 +288,12 @@ static void velocity_unregister_notifier(void)
unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
}
-#else /* CONFIG_PM */
+#else
#define velocity_register_notifier() do {} while (0)
#define velocity_unregister_notifier() do {} while (0)
-#endif /* !CONFIG_PM */
+#endif
/*
* Internal board variants. At the moment we have only one
@@ -3132,7 +3136,7 @@ static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
}
/* Finally, invert the result once to get the correct data */
crc = ~crc;
- return bitreverse(crc) >> 16;
+ return bitrev32(crc) >> 16;
}
/**
@@ -3292,6 +3296,8 @@ static int velocity_resume(struct pci_dev *pdev)
return 0;
}
+#ifdef CONFIG_INET
+
static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
{
struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
@@ -3312,4 +3318,6 @@ static int velocity_netdev_event(struct notifier_block *nb, unsigned long notifi
}
return NOTIFY_DONE;
}
+
+#endif
#endif
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index d5ab9cf1325..61708cf4c85 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -235,6 +235,19 @@ comment "Cyclades-PC300 MLPPP support is disabled."
comment "Refer to the file README.mlppp, provided by PC300 package."
depends on WAN && HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
+config PC300TOO
+ tristate "Cyclades PC300 RSV/X21 alternative support"
+ depends on HDLC && PCI
+ help
+ Alternative driver for PC300 RSV/X21 PCI cards made by
+ Cyclades, Inc. If you have such a card, say Y here and see
+ <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
+
+ To compile this as a module, choose M here: the module
+ will be called pc300too.
+
+ If unsure, say N here.
+
config N2
tristate "SDL RISCom/N2 support"
depends on HDLC && ISA
@@ -344,17 +357,6 @@ config DLCI
To compile this driver as a module, choose M here: the
module will be called dlci.
-config DLCI_COUNT
- int "Max open DLCI"
- depends on DLCI
- default "24"
- help
- Maximal number of logical point-to-point frame relay connections
- (the identifiers of which are called DCLIs) that the driver can
- handle.
-
- The default is probably fine.
-
config DLCI_MAX
int "Max DLCI per device"
depends on DLCI
@@ -382,7 +384,7 @@ config SDLA
# Wan router core.
config WAN_ROUTER_DRIVERS
- bool "WAN router drivers"
+ tristate "WAN router drivers"
depends on WAN && WAN_ROUTER
---help---
Connect LAN to WAN via Linux box.
@@ -393,7 +395,8 @@ config WAN_ROUTER_DRIVERS
<file:Documentation/networking/wan-router.txt>.
Note that the answer to this question won't directly affect the
- kernel: saying N will just cause the configurator to skip all
+ kernel except for how subordinate drivers may be built:
+ saying N will just cause the configurator to skip all
the questions about WAN router drivers.
If unsure, say N.
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 83ec2c87ba3..d61fef36afc 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_N2) += n2.o
obj-$(CONFIG_C101) += c101.o
obj-$(CONFIG_WANXL) += wanxl.o
obj-$(CONFIG_PCI200SYN) += pci200syn.o
+obj-$(CONFIG_PC300TOO) += pc300too.o
clean-files := wanxlfw.inc
$(obj)/wanxl.o: $(obj)/wanxlfw.inc
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index e1bf8b93f95..6c7dfb50143 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -974,12 +974,12 @@ static int cosa_open(struct inode *inode, struct file *file)
unsigned long flags;
int n;
- if ((n=iminor(file->f_dentry->d_inode)>>CARD_MINOR_BITS)
+ if ((n=iminor(file->f_path.dentry->d_inode)>>CARD_MINOR_BITS)
>= nr_cards)
return -ENODEV;
cosa = cosa_cards+n;
- if ((n=iminor(file->f_dentry->d_inode)
+ if ((n=iminor(file->f_path.dentry->d_inode)
& ((1<<CARD_MINOR_BITS)-1)) >= cosa->nchannels)
return -ENODEV;
chan = cosa->chan + n;
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index db354e0edbe..9040d7cf651 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -222,7 +222,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EINVAL;
}
-void hdlc_setup(struct net_device *dev)
+static void hdlc_setup(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -325,7 +325,6 @@ MODULE_LICENSE("GPL v2");
EXPORT_SYMBOL(hdlc_open);
EXPORT_SYMBOL(hdlc_close);
EXPORT_SYMBOL(hdlc_ioctl);
-EXPORT_SYMBOL(hdlc_setup);
EXPORT_SYMBOL(alloc_hdlcdev);
EXPORT_SYMBOL(unregister_hdlc_device);
EXPORT_SYMBOL(register_hdlc_protocol);
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index a4f735723c4..a02c5fb4056 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -231,7 +231,7 @@ static struct sv11_device *sv11_init(int iobase, int irq)
return NULL;
}
- sv=(struct sv11_device *)kmalloc(sizeof(struct sv11_device), GFP_KERNEL);
+ sv = kmalloc(sizeof(struct sv11_device), GFP_KERNEL);
if(!sv)
goto fail3;
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index 36d1c3ff707..62184dee377 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -3455,7 +3455,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if ((err = pci_enable_device(pdev)) < 0)
return err;
- card = (pc300_t *) kmalloc(sizeof(pc300_t), GFP_KERNEL);
+ card = kmalloc(sizeof(pc300_t), GFP_KERNEL);
if (card == NULL) {
printk("PC300 found at RAM 0x%016llx, "
"but could not allocate card structure.\n",
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index b2a23aed442..5873c346e7e 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -784,7 +784,7 @@ void cpc_tty_receive(pc300dev_t *pc300dev)
continue;
}
- new = (st_cpc_rx_buf *)kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC);
+ new = kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC);
if (new == 0) {
cpc_tty_rx_disc_frame(pc300chan);
continue;
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
new file mode 100644
index 00000000000..bc156b51678
--- /dev/null
+++ b/drivers/net/wan/pc300too.c
@@ -0,0 +1,565 @@
+/*
+ * Cyclades PC300 synchronous serial card driver for Linux
+ *
+ * Copyright (C) 2000-2007 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
+ * as published by the Free Software Foundation.
+ *
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
+ *
+ * Sources of information:
+ * Hitachi HD64572 SCA-II User's Manual
+ * Cyclades PC300 Linux driver
+ *
+ * This driver currently supports only PC300/RSV (V.24/V.35) and
+ * PC300/X21 cards.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/hdlc.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "hd64572.h"
+
+static const char* version = "Cyclades PC300 driver version: 1.17";
+static const char* devname = "PC300";
+
+#undef DEBUG_PKT
+#define DEBUG_RINGS
+
+#define PC300_PLX_SIZE 0x80 /* PLX control window size (128 B) */
+#define PC300_SCA_SIZE 0x400 /* SCA window size (1 KB) */
+#define ALL_PAGES_ALWAYS_MAPPED
+#define NEED_DETECT_RAM
+#define NEED_SCA_MSCI_INTR
+#define MAX_TX_BUFFERS 10
+
+static int pci_clock_freq = 33000000;
+static int use_crystal_clock = 0;
+static unsigned int CLOCK_BASE;
+
+/* Masks to access the init_ctrl PLX register */
+#define PC300_CLKSEL_MASK (0x00000004UL)
+#define PC300_CHMEDIA_MASK(port) (0x00000020UL << ((port) * 3))
+#define PC300_CTYPE_MASK (0x00000800UL)
+
+
+enum { PC300_RSV = 1, PC300_X21, PC300_TE }; /* card types */
+
+/*
+ * PLX PCI9050-1 local configuration and shared runtime registers.
+ * This structure can be used to access 9050 registers (memory mapped).
+ */
+typedef struct {
+ u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */
+ u32 loc_rom_range; /* 10h : Local ROM Range */
+ u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */
+ u32 loc_rom_base; /* 24h : Local ROM Base */
+ u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */
+ u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */
+ u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */
+ u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */
+ u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */
+}plx9050;
+
+
+
+typedef struct port_s {
+ struct net_device *dev;
+ struct card_s *card;
+ spinlock_t lock; /* TX lock */
+ sync_serial_settings settings;
+ int rxpart; /* partial frame received, next frame invalid*/
+ unsigned short encoding;
+ unsigned short parity;
+ unsigned int iface;
+ u16 rxin; /* rx ring buffer 'in' pointer */
+ u16 txin; /* tx ring buffer 'in' and 'last' pointers */
+ u16 txlast;
+ u8 rxs, txs, tmc; /* SCA registers */
+ u8 phy_node; /* physical port # - 0 or 1 */
+}port_t;
+
+
+
+typedef struct card_s {
+ int type; /* RSV, X21, etc. */
+ int n_ports; /* 1 or 2 ports */
+ u8 __iomem *rambase; /* buffer memory base (virtual) */
+ u8 __iomem *scabase; /* SCA memory base (virtual) */
+ plx9050 __iomem *plxbase; /* PLX registers memory base (virtual) */
+ u32 init_ctrl_value; /* Saved value - 9050 bug workaround */
+ u16 rx_ring_buffers; /* number of buffers in a ring */
+ u16 tx_ring_buffers;
+ u16 buff_offset; /* offset of first buffer of first channel */
+ u8 irq; /* interrupt request level */
+
+ port_t ports[2];
+}card_t;
+
+
+#define sca_in(reg, card) readb(card->scabase + (reg))
+#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))
+#define sca_inw(reg, card) readw(card->scabase + (reg))
+#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))
+#define sca_inl(reg, card) readl(card->scabase + (reg))
+#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))
+
+#define port_to_card(port) (port->card)
+#define log_node(port) (port->phy_node)
+#define phy_node(port) (port->phy_node)
+#define winbase(card) (card->rambase)
+#define get_port(card, port) ((port) < (card)->n_ports ? \
+ (&(card)->ports[port]) : (NULL))
+
+#include "hd6457x.c"
+
+
+static void pc300_set_iface(port_t *port)
+{
+ card_t *card = port->card;
+ u32 __iomem * init_ctrl = &card->plxbase->init_ctrl;
+ u16 msci = get_msci(port);
+ u8 rxs = port->rxs & CLK_BRG_MASK;
+ u8 txs = port->txs & CLK_BRG_MASK;
+
+ sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
+ port_to_card(port));
+ switch(port->settings.clock_type) {
+ case CLOCK_INT:
+ rxs |= CLK_BRG; /* BRG output */
+ txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
+ break;
+
+ case CLOCK_TXINT:
+ rxs |= CLK_LINE; /* RXC input */
+ txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */
+ break;
+
+ case CLOCK_TXFROMRX:
+ rxs |= CLK_LINE; /* RXC input */
+ txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
+ break;
+
+ default: /* EXTernal clock */
+ rxs |= CLK_LINE; /* RXC input */
+ txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */
+ break;
+ }
+
+ port->rxs = rxs;
+ port->txs = txs;
+ sca_out(rxs, msci + RXS, card);
+ sca_out(txs, msci + TXS, card);
+ sca_set_port(port);
+
+ if (port->card->type == PC300_RSV) {
+ if (port->iface == IF_IFACE_V35)
+ writel(card->init_ctrl_value |
+ PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+ else
+ writel(card->init_ctrl_value &
+ ~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+ }
+}
+
+
+
+static int pc300_open(struct net_device *dev)
+{
+ port_t *port = dev_to_port(dev);
+
+ int result = hdlc_open(dev);
+ if (result)
+ return result;
+
+ sca_open(dev);
+ pc300_set_iface(port);
+ return 0;
+}
+
+
+
+static int pc300_close(struct net_device *dev)
+{
+ sca_close(dev);
+ hdlc_close(dev);
+ return 0;
+}
+
+
+
+static int pc300_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ const size_t size = sizeof(sync_serial_settings);
+ sync_serial_settings new_line;
+ sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
+ int new_type;
+ port_t *port = dev_to_port(dev);
+
+#ifdef DEBUG_RINGS
+ if (cmd == SIOCDEVPRIVATE) {
+ sca_dump_rings(dev);
+ return 0;
+ }
+#endif
+ if (cmd != SIOCWANDEV)
+ return hdlc_ioctl(dev, ifr, cmd);
+
+ if (ifr->ifr_settings.type == IF_GET_IFACE) {
+ ifr->ifr_settings.type = port->iface;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+ if (copy_to_user(line, &port->settings, size))
+ return -EFAULT;
+ return 0;
+
+ }
+
+ if (port->card->type == PC300_X21 &&
+ (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL ||
+ ifr->ifr_settings.type == IF_IFACE_X21))
+ new_type = IF_IFACE_X21;
+
+ else if (port->card->type == PC300_RSV &&
+ (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL ||
+ ifr->ifr_settings.type == IF_IFACE_V35))
+ new_type = IF_IFACE_V35;
+
+ else if (port->card->type == PC300_RSV &&
+ ifr->ifr_settings.type == IF_IFACE_V24)
+ new_type = IF_IFACE_V24;
+
+ else
+ return hdlc_ioctl(dev, ifr, cmd);
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&new_line, line, size))
+ return -EFAULT;
+
+ if (new_line.clock_type != CLOCK_EXT &&
+ new_line.clock_type != CLOCK_TXFROMRX &&
+ new_line.clock_type != CLOCK_INT &&
+ new_line.clock_type != CLOCK_TXINT)
+ return -EINVAL; /* No such clock setting */
+
+ if (new_line.loopback != 0 && new_line.loopback != 1)
+ return -EINVAL;
+
+ memcpy(&port->settings, &new_line, size); /* Update settings */
+ port->iface = new_type;
+ pc300_set_iface(port);
+ return 0;
+}
+
+
+
+static void pc300_pci_remove_one(struct pci_dev *pdev)
+{
+ int i;
+ card_t *card = pci_get_drvdata(pdev);
+
+ for (i = 0; i < 2; i++)
+ if (card->ports[i].card) {
+ struct net_device *dev = port_to_dev(&card->ports[i]);
+ unregister_hdlc_device(dev);
+ }
+
+ if (card->irq)
+ free_irq(card->irq, card);
+
+ if (card->rambase)
+ iounmap(card->rambase);
+ if (card->scabase)
+ iounmap(card->scabase);
+ if (card->plxbase)
+ iounmap(card->plxbase);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ if (card->ports[0].dev)
+ free_netdev(card->ports[0].dev);
+ if (card->ports[1].dev)
+ free_netdev(card->ports[1].dev);
+ kfree(card);
+}
+
+
+
+static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ card_t *card;
+ u8 rev_id;
+ u32 __iomem *p;
+ int i;
+ u32 ramsize;
+ u32 ramphys; /* buffer memory base */
+ u32 scaphys; /* SCA memory base */
+ u32 plxphys; /* PLX registers memory base */
+
+#ifndef MODULE
+ static int printed_version;
+ if (!printed_version++)
+ printk(KERN_INFO "%s\n", version);
+#endif
+
+ i = pci_enable_device(pdev);
+ if (i)
+ return i;
+
+ i = pci_request_regions(pdev, "PC300");
+ if (i) {
+ pci_disable_device(pdev);
+ return i;
+ }
+
+ card = kmalloc(sizeof(card_t), GFP_KERNEL);
+ if (card == NULL) {
+ printk(KERN_ERR "pc300: unable to allocate memory\n");
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ return -ENOBUFS;
+ }
+ memset(card, 0, sizeof(card_t));
+ pci_set_drvdata(pdev, card);
+
+ if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 ||
+ pdev->device == PCI_DEVICE_ID_PC300_TE_2)
+ card->type = PC300_TE; /* not fully supported */
+ else if (card->init_ctrl_value & PC300_CTYPE_MASK)
+ card->type = PC300_X21;
+ else
+ card->type = PC300_RSV;
+
+ if (pdev->device == PCI_DEVICE_ID_PC300_RX_1 ||
+ pdev->device == PCI_DEVICE_ID_PC300_TE_1)
+ card->n_ports = 1;
+ else
+ card->n_ports = 2;
+
+ for (i = 0; i < card->n_ports; i++)
+ if (!(card->ports[i].dev = alloc_hdlcdev(&card->ports[i]))) {
+ printk(KERN_ERR "pc300: unable to allocate memory\n");
+ pc300_pci_remove_one(pdev);
+ return -ENOMEM;
+ }
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+ if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE ||
+ pci_resource_len(pdev, 2) != PC300_SCA_SIZE ||
+ pci_resource_len(pdev, 3) < 16384) {
+ printk(KERN_ERR "pc300: invalid card EEPROM parameters\n");
+ pc300_pci_remove_one(pdev);
+ return -EFAULT;
+ }
+
+ plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK;
+ card->plxbase = ioremap(plxphys, PC300_PLX_SIZE);
+
+ scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK;
+ card->scabase = ioremap(scaphys, PC300_SCA_SIZE);
+
+ ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK;
+ card->rambase = ioremap(ramphys, pci_resource_len(pdev,3));
+
+ if (card->plxbase == NULL ||
+ card->scabase == NULL ||
+ card->rambase == NULL) {
+ printk(KERN_ERR "pc300: ioremap() failed\n");
+ pc300_pci_remove_one(pdev);
+ }
+
+ /* PLX PCI 9050 workaround for local configuration register read bug */
+ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys);
+ card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl);
+ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys);
+
+ /* Reset PLX */
+ p = &card->plxbase->init_ctrl;
+ writel(card->init_ctrl_value | 0x40000000, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ writel(card->init_ctrl_value, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ /* Reload Config. Registers from EEPROM */
+ writel(card->init_ctrl_value | 0x20000000, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ writel(card->init_ctrl_value, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ ramsize = sca_detect_ram(card, card->rambase,
+ pci_resource_len(pdev, 3));
+
+ if (use_crystal_clock)
+ card->init_ctrl_value &= ~PC300_CLKSEL_MASK;
+ else
+ card->init_ctrl_value |= PC300_CLKSEL_MASK;
+
+ writel(card->init_ctrl_value, &card->plxbase->init_ctrl);
+ /* number of TX + RX buffers for one port */
+ i = ramsize / (card->n_ports * (sizeof(pkt_desc) + HDLC_MAX_MRU));
+ card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS);
+ card->rx_ring_buffers = i - card->tx_ring_buffers;
+
+ card->buff_offset = card->n_ports * sizeof(pkt_desc) *
+ (card->tx_ring_buffers + card->rx_ring_buffers);
+
+ printk(KERN_INFO "pc300: PC300/%s, %u KB RAM at 0x%x, IRQ%u, "
+ "using %u TX + %u RX packets rings\n",
+ card->type == PC300_X21 ? "X21" :
+ card->type == PC300_TE ? "TE" : "RSV",
+ ramsize / 1024, ramphys, pdev->irq,
+ card->tx_ring_buffers, card->rx_ring_buffers);
+
+ if (card->tx_ring_buffers < 1) {
+ printk(KERN_ERR "pc300: RAM test failed\n");
+ pc300_pci_remove_one(pdev);
+ return -EFAULT;
+ }
+
+ /* Enable interrupts on the PCI bridge, LINTi1 active low */
+ writew(0x0041, &card->plxbase->intr_ctrl_stat);
+
+ /* Allocate IRQ */
+ if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) {
+ printk(KERN_WARNING "pc300: could not allocate IRQ%d.\n",
+ pdev->irq);
+ pc300_pci_remove_one(pdev);
+ return -EBUSY;
+ }
+ card->irq = pdev->irq;
+
+ sca_init(card, 0);
+
+ // COTE not set - allows better TX DMA settings
+ // sca_out(sca_in(PCR, card) | PCR_COTE, PCR, card);
+
+ sca_out(0x10, BTCR, card);
+
+ for (i = 0; i < card->n_ports; i++) {
+ port_t *port = &card->ports[i];
+ struct net_device *dev = port_to_dev(port);
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ port->phy_node = i;
+
+ spin_lock_init(&port->lock);
+ SET_MODULE_OWNER(dev);
+ dev->irq = card->irq;
+ dev->mem_start = ramphys;
+ dev->mem_end = ramphys + ramsize - 1;
+ dev->tx_queue_len = 50;
+ dev->do_ioctl = pc300_ioctl;
+ dev->open = pc300_open;
+ dev->stop = pc300_close;
+ hdlc->attach = sca_attach;
+ hdlc->xmit = sca_xmit;
+ port->settings.clock_type = CLOCK_EXT;
+ port->card = card;
+ if (card->type == PC300_X21)
+ port->iface = IF_IFACE_X21;
+ else
+ port->iface = IF_IFACE_V35;
+
+ if (register_hdlc_device(dev)) {
+ printk(KERN_ERR "pc300: unable to register hdlc "
+ "device\n");
+ port->card = NULL;
+ pc300_pci_remove_one(pdev);
+ return -ENOBUFS;
+ }
+ sca_init_sync_port(port); /* Set up SCA memory */
+
+ printk(KERN_INFO "%s: PC300 node %d\n",
+ dev->name, port->phy_node);
+ }
+ return 0;
+}
+
+
+
+static struct pci_device_id pc300_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_1, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_2, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_1, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_2, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { 0, }
+};
+
+
+static struct pci_driver pc300_pci_driver = {
+ .name = "PC300",
+ .id_table = pc300_pci_tbl,
+ .probe = pc300_pci_init_one,
+ .remove = pc300_pci_remove_one,
+};
+
+
+static int __init pc300_init_module(void)
+{
+#ifdef MODULE
+ printk(KERN_INFO "%s\n", version);
+#endif
+ if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
+ printk(KERN_ERR "pc300: Invalid PCI clock frequency\n");
+ return -EINVAL;
+ }
+ if (use_crystal_clock != 0 && use_crystal_clock != 1) {
+ printk(KERN_ERR "pc300: Invalid 'use_crystal_clock' value\n");
+ return -EINVAL;
+ }
+
+ CLOCK_BASE = use_crystal_clock ? 24576000 : pci_clock_freq;
+
+ return pci_module_init(&pc300_pci_driver);
+}
+
+
+
+static void __exit pc300_cleanup_module(void)
+{
+ pci_unregister_driver(&pc300_pci_driver);
+}
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Cyclades PC300 serial port driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, pc300_pci_tbl);
+module_param(pci_clock_freq, int, 0444);
+MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz");
+module_param(use_crystal_clock, int, 0444);
+MODULE_PARM_DESC(use_crystal_clock,
+ "Use 24.576 MHz clock instead of PCI clock");
+module_init(pc300_init_module);
+module_exit(pc300_cleanup_module);
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 9c3ccc66914..1c9edd97acc 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -123,8 +123,8 @@ static int x25_asy_change_mtu(struct net_device *dev, int newmtu)
unsigned char *xbuff, *rbuff;
int len = 2* newmtu;
- xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
- rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+ xbuff = kmalloc(len + 4, GFP_ATOMIC);
+ rbuff = kmalloc(len + 4, GFP_ATOMIC);
if (xbuff == NULL || rbuff == NULL)
{
@@ -465,11 +465,11 @@ static int x25_asy_open(struct net_device *dev)
len = dev->mtu * 2;
- sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+ sl->rbuff = kmalloc(len + 4, GFP_KERNEL);
if (sl->rbuff == NULL) {
goto norbuff;
}
- sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+ sl->xbuff = kmalloc(len + 4, GFP_KERNEL);
if (sl->xbuff == NULL) {
goto noxbuff;
}
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 59ddd21c395..8dbcf83bb5f 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -331,8 +331,7 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set)
static void z8530_rx(struct z8530_channel *c)
{
u8 ch,stat;
- spin_lock(c->lock);
-
+
while(1)
{
/* FIFO empty ? */
@@ -390,7 +389,6 @@ static void z8530_rx(struct z8530_channel *c)
*/
write_zsctrl(c, ERR_RES);
write_zsctrl(c, RES_H_IUS);
- spin_unlock(c->lock);
}
@@ -406,7 +404,6 @@ static void z8530_rx(struct z8530_channel *c)
static void z8530_tx(struct z8530_channel *c)
{
- spin_lock(c->lock);
while(c->txcount) {
/* FIFO full ? */
if(!(read_zsreg(c, R0)&4))
@@ -434,7 +431,6 @@ static void z8530_tx(struct z8530_channel *c)
z8530_tx_done(c);
write_zsctrl(c, RES_H_IUS);
- spin_unlock(c->lock);
}
/**
@@ -452,7 +448,6 @@ static void z8530_status(struct z8530_channel *chan)
{
u8 status, altered;
- spin_lock(chan->lock);
status=read_zsreg(chan, R0);
altered=chan->status^status;
@@ -487,7 +482,6 @@ static void z8530_status(struct z8530_channel *chan)
}
write_zsctrl(chan, RES_EXT_INT);
write_zsctrl(chan, RES_H_IUS);
- spin_unlock(chan->lock);
}
struct z8530_irqhandler z8530_sync=
@@ -511,7 +505,6 @@ EXPORT_SYMBOL(z8530_sync);
static void z8530_dma_rx(struct z8530_channel *chan)
{
- spin_lock(chan->lock);
if(chan->rxdma_on)
{
/* Special condition check only */
@@ -534,7 +527,6 @@ static void z8530_dma_rx(struct z8530_channel *chan)
/* DMA is off right now, drain the slow way */
z8530_rx(chan);
}
- spin_unlock(chan->lock);
}
/**
@@ -547,7 +539,6 @@ static void z8530_dma_rx(struct z8530_channel *chan)
static void z8530_dma_tx(struct z8530_channel *chan)
{
- spin_lock(chan->lock);
if(!chan->dma_tx)
{
printk(KERN_WARNING "Hey who turned the DMA off?\n");
@@ -557,7 +548,6 @@ static void z8530_dma_tx(struct z8530_channel *chan)
/* This shouldnt occur in DMA mode */
printk(KERN_ERR "DMA tx - bogus event!\n");
z8530_tx(chan);
- spin_unlock(chan->lock);
}
/**
@@ -596,7 +586,6 @@ static void z8530_dma_status(struct z8530_channel *chan)
}
}
- spin_lock(chan->lock);
if(altered&chan->dcdcheck)
{
if(status&chan->dcdcheck)
@@ -618,7 +607,6 @@ static void z8530_dma_status(struct z8530_channel *chan)
write_zsctrl(chan, RES_EXT_INT);
write_zsctrl(chan, RES_H_IUS);
- spin_unlock(chan->lock);
}
struct z8530_irqhandler z8530_dma_sync=
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index 7f38012b9c9..a0326818ff2 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -433,7 +433,7 @@ wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
/* Turn off 16 bit access so that reboot works. ISA brain-damage */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 8286678513b..3a064def162 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -352,6 +352,10 @@
#define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040
#define BCM43xx_UCODEFLAG_JAPAN 0x0080
+/* Hardware Radio Enable masks */
+#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
/* Generic-Interrupt reasons. */
#define BCM43xx_IRQ_READY (1 << 0)
#define BCM43xx_IRQ_BEACON (1 << 1)
@@ -758,7 +762,8 @@ struct bcm43xx_private {
bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */
reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */
short_preamble:1, /* TRUE, if short preamble is enabled. */
- firmware_norelease:1; /* Do not release the firmware. Used on suspend. */
+ firmware_norelease:1, /* Do not release the firmware. Used on suspend. */
+ radio_hw_enable:1; /* TRUE if radio is hardware enabled */
struct bcm43xx_stats stats;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index 7d383a27b92..8f198befba3 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -26,6 +26,7 @@
*/
#include "bcm43xx_leds.h"
+#include "bcm43xx_radio.h"
#include "bcm43xx.h"
#include <asm/bitops.h>
@@ -108,6 +109,7 @@ static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
switch (led_index) {
case 0:
led->behaviour = BCM43xx_LED_ACTIVITY;
+ led->activelow = 1;
if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
led->behaviour = BCM43xx_LED_RADIO_ALL;
break;
@@ -199,20 +201,21 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
turn_on = activity;
break;
case BCM43xx_LED_RADIO_ALL:
- turn_on = radio->enabled;
+ turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
break;
case BCM43xx_LED_RADIO_A:
case BCM43xx_LED_BCM4303_2:
- turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
+ turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
+ phy->type == BCM43xx_PHYTYPE_A);
break;
case BCM43xx_LED_RADIO_B:
case BCM43xx_LED_BCM4303_1:
- turn_on = (radio->enabled &&
+ turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
(phy->type == BCM43xx_PHYTYPE_B ||
phy->type == BCM43xx_PHYTYPE_G));
break;
case BCM43xx_LED_MODE_BG:
- if (phy->type == BCM43xx_PHYTYPE_G &&
+ if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
1/*FIXME: using G rates.*/)
turn_on = 1;
break;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 2ec2e5afce6..23aaf1ed854 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -2441,6 +2441,9 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
if (err)
goto err_gpio_cleanup;
bcm43xx_radio_turn_on(bcm);
+ bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+ dprintk(KERN_INFO PFX "Radio %s by hardware\n",
+ (bcm->radio_hw_enable == 0) ? "disabled" : "enabled");
bcm43xx_write16(bcm, 0x03E6, 0x0000);
err = bcm43xx_phy_init(bcm);
@@ -2701,8 +2704,8 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
/* extract core_id, core_rev, core_vendor */
- core_id = (sb_id_hi & 0xFFF0) >> 4;
- core_rev = (sb_id_hi & 0xF);
+ core_id = (sb_id_hi & 0x8FF0) >> 4;
+ core_rev = ((sb_id_hi & 0xF) | ((sb_id_hi & 0x7000) >> 8));
core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x\n",
@@ -2873,7 +2876,10 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
- sbimconfiglow |= 0x32;
+ if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
+ sbimconfiglow |= 0x32;
+ else
+ sbimconfiglow |= 0x53;
bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
}
@@ -3077,7 +3083,7 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
if (err)
goto out;
- if (bcm->current_core->rev < 6 ||
+ if (bcm->current_core->rev < 6 &&
bcm->current_core->id == BCM43xx_COREID_PCI) {
value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
value |= (1 << backplane_flag_nr);
@@ -3172,9 +3178,24 @@ static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
{
+ bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
+ //TODO for APHY (temperature?)
+}
+
+static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm)
+{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+ int radio_hw_enable;
+ /* check if radio hardware enabled status changed */
+ radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+ if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) {
+ bcm->radio_hw_enable = radio_hw_enable;
+ dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n",
+ (radio_hw_enable == 0) ? "disabled" : "enabled");
+ bcm43xx_leds_update(bcm, 0);
+ }
if (phy->type == BCM43xx_PHYTYPE_G) {
//TODO: update_aci_moving_average
if (radio->aci_enable && radio->aci_wlan_automatic) {
@@ -3198,21 +3219,21 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
//TODO: implement rev1 workaround
}
}
- bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
- //TODO for APHY (temperature?)
}
static void do_periodic_work(struct bcm43xx_private *bcm)
{
- if (bcm->periodic_state % 8 == 0)
+ if (bcm->periodic_state % 120 == 0)
bcm43xx_periodic_every120sec(bcm);
- if (bcm->periodic_state % 4 == 0)
+ if (bcm->periodic_state % 60 == 0)
bcm43xx_periodic_every60sec(bcm);
- if (bcm->periodic_state % 2 == 0)
+ if (bcm->periodic_state % 30 == 0)
bcm43xx_periodic_every30sec(bcm);
- bcm43xx_periodic_every15sec(bcm);
+ if (bcm->periodic_state % 15 == 0)
+ bcm43xx_periodic_every15sec(bcm);
+ bcm43xx_periodic_every1sec(bcm);
- schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+ schedule_delayed_work(&bcm->periodic_work, HZ);
}
static void bcm43xx_periodic_work_handler(struct work_struct *work)
@@ -3225,7 +3246,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
unsigned long orig_trans_start = 0;
mutex_lock(&bcm->mutex);
- if (unlikely(bcm->periodic_state % 4 == 0)) {
+ if (unlikely(bcm->periodic_state % 60 == 0)) {
/* Periodic work will take a long time, so we want it to
* be preemtible.
*/
@@ -3257,7 +3278,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
do_periodic_work(bcm);
- if (unlikely(bcm->periodic_state % 4 == 0)) {
+ if (unlikely(bcm->periodic_state % 60 == 0)) {
spin_lock_irqsave(&bcm->irq_lock, flags);
tasklet_enable(&bcm->isr_tasklet);
bcm43xx_interrupt_enable(bcm, savedirqs);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index bb9c484d7e1..af19a07032a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1981,6 +1981,7 @@ void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
}
radio->enabled = 1;
dprintk(KERN_INFO PFX "Radio turned on\n");
+ bcm43xx_leds_update(bcm, 0);
}
void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
@@ -2001,6 +2002,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
radio->enabled = 0;
dprintk(KERN_INFO PFX "Radio turned off\n");
+ bcm43xx_leds_update(bcm, 0);
}
void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
index 9ed18039fa3..77a98a53a2e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
@@ -65,6 +65,22 @@ void bcm43xx_radio_init2060(struct bcm43xx_private *bcm);
void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm);
void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm);
+static inline
+int bcm43xx_is_hw_radio_enabled(struct bcm43xx_private *bcm)
+{
+ /* function to return state of hardware enable of radio
+ * returns 0 if radio disabled, 1 if radio enabled
+ */
+ if (bcm->current_core->rev >= 3)
+ return ((bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI)
+ & BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK)
+ == 0) ? 1 : 0;
+ else
+ return ((bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO)
+ & BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK)
+ == 0) ? 0 : 1;
+}
+
int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel,
int synthetic_pu_workaround);
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 974a8e5bec8..efb8cf3bd8a 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -1253,7 +1253,7 @@ static char * ap_auth_make_challenge(struct ap_data *ap)
return NULL;
}
- tmpbuf = (char *) kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC);
+ tmpbuf = kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC);
if (tmpbuf == NULL) {
PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n");
return NULL;
diff --git a/drivers/net/wireless/hostap/hostap_download.c b/drivers/net/wireless/hostap/hostap_download.c
index 24fc387bba6..c7678e67697 100644
--- a/drivers/net/wireless/hostap/hostap_download.c
+++ b/drivers/net/wireless/hostap/hostap_download.c
@@ -201,7 +201,7 @@ static u8 * prism2_read_pda(struct net_device *dev)
0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */,
};
- buf = (u8 *) kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
+ buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
if (buf == NULL)
return NULL;
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index a394a23b9a2..3079378fb8c 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -2252,7 +2252,7 @@ static int hostap_tx_compl_read(local_info_t *local, int error,
if (txdesc->sw_support) {
len = le16_to_cpu(txdesc->data_len);
if (len < PRISM2_DATA_MAXLEN) {
- *payload = (char *) kmalloc(len, GFP_ATOMIC);
+ *payload = kmalloc(len, GFP_ATOMIC);
if (*payload == NULL ||
hfa384x_from_bap(dev, BAP0, *payload, len)) {
PDEBUG(DEBUG_EXTRA, "%s: could not read TX "
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index 3b7b8063ff1..cb08bc5db2b 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -3829,7 +3829,7 @@ static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p)
p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
return -EINVAL;
- param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
+ param = kmalloc(p->length, GFP_KERNEL);
if (param == NULL)
return -ENOMEM;
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 0796be9d9e7..9077e6edde3 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -84,7 +84,7 @@ struct net_device * hostap_add_interface(struct local_info *local,
if (strchr(dev->name, '%'))
ret = dev_alloc_name(dev, dev->name);
- SET_NETDEV_DEV(dev, mdev->class_dev.dev);
+ SET_NETDEV_DEV(dev, mdev->dev.parent);
if (ret >= 0)
ret = register_netdevice(dev);
@@ -250,7 +250,7 @@ u16 hostap_tx_callback_register(local_info_t *local,
unsigned long flags;
struct hostap_tx_callback_info *entry;
- entry = (struct hostap_tx_callback_info *) kmalloc(sizeof(*entry),
+ entry = kmalloc(sizeof(*entry),
GFP_ATOMIC);
if (entry == NULL)
return 0;
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index dd9ba4aad7b..b85857a8487 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -2246,7 +2246,7 @@ static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
if (priv->snapshot[0])
return 1;
for (i = 0; i < 0x30; i++) {
- priv->snapshot[i] = (u8 *) kmalloc(0x1000, GFP_ATOMIC);
+ priv->snapshot[i] = kmalloc(0x1000, GFP_ATOMIC);
if (!priv->snapshot[i]) {
IPW_DEBUG_INFO("%s: Error allocating snapshot "
"buffer %d\n", priv->net_dev->name, i);
@@ -2664,7 +2664,7 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
break;
}
#endif
- if (stats.len < sizeof(u->rx_data.header))
+ if (stats.len < sizeof(struct ieee80211_hdr_3addr))
break;
switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) {
case IEEE80211_FTYPE_MGMT:
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 22cb3fb7502..c878a2f3239 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -9166,7 +9166,7 @@ static int ipw_wx_set_rts(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
mutex_lock(&priv->mutex);
- if (wrqu->rts.disabled)
+ if (wrqu->rts.disabled || !wrqu->rts.fixed)
priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
else {
if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
@@ -9255,7 +9255,7 @@ static int ipw_wx_set_frag(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
mutex_lock(&priv->mutex);
- if (wrqu->frag.disabled)
+ if (wrqu->frag.disabled || !wrqu->frag.fixed)
priv->ieee->fts = DEFAULT_FTS;
else {
if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index 644b4741ef7..a009ab51771 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -406,7 +406,6 @@ static int netwave_probe(struct pcmcia_device *link)
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
- link->conf.Present = PRESENT_OPTION;
/* Netwave private struct init. link/dev/node already taken care of,
* other stuff zero'd - Jean II */
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 936c888e03e..4e7f6cf5143 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -2059,7 +2059,7 @@ static int determine_firmware(struct net_device *dev)
int err;
struct comp_id nic_id, sta_id;
unsigned int firmver;
- char tmp[SYMBOL_MAX_VER_LEN+1];
+ char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
/* Get the hardware version */
err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
@@ -4293,8 +4293,8 @@ static void orinoco_get_drvinfo(struct net_device *dev,
strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
- if (dev->class_dev.dev)
- strncpy(info->bus_info, dev->class_dev.dev->bus_id,
+ if (dev->dev.parent)
+ strncpy(info->bus_info, dev->dev.parent->bus_id,
sizeof(info->bus_info) - 1);
else
snprintf(info->bus_info, sizeof(info->bus_info) - 1,
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index d08ae8d2726..d1e502236b2 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -332,7 +332,7 @@ orinoco_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+ "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
link->irq.AssignedIRQ, link->io.BasePort1,
link->io.BasePort1 + link->io.NumPorts1 - 1);
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 96606ed1007..838d510213c 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -2775,7 +2775,7 @@ prism54_hostapd(struct net_device *ndev, struct iw_point *p)
p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
return -EINVAL;
- param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
+ param = kmalloc(p->length, GFP_KERNEL);
if (param == NULL)
return -ENOMEM;
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index f057fd9fcd7..a037b11dac9 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
+#include <linux/ethtool.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
@@ -787,6 +788,17 @@ islpci_set_multicast_list(struct net_device *dev)
}
#endif
+static void islpci_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+}
+
+static struct ethtool_ops islpci_ethtool_ops = {
+ .get_drvinfo = islpci_ethtool_get_drvinfo,
+};
+
struct net_device *
islpci_setup(struct pci_dev *pdev)
{
@@ -813,6 +825,7 @@ islpci_setup(struct pci_dev *pdev)
ndev->do_ioctl = &prism54_ioctl;
ndev->wireless_handlers =
(struct iw_handler_def *) &prism54_handler_def;
+ ndev->ethtool_ops = &islpci_ethtool_ops;
ndev->hard_start_xmit = &islpci_eth_transmit;
/* ndev->set_multicast_list = &islpci_set_multicast_list; */
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index a9aa1662eaa..736666da6c2 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -211,4 +211,8 @@ islpci_trigger(islpci_private *priv)
int islpci_free_memory(islpci_private *);
struct net_device *islpci_setup(struct pci_dev *);
+
+#define DRV_NAME "prism54"
+#define DRV_VERSION "1.2"
+
#endif /* _ISLPCI_DEV_H */
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 58257b40c04..3dcb13bb7d5 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -28,9 +28,6 @@
#include "islpci_mgt.h" /* for pc_debug */
#include "isl_oid.h"
-#define DRV_NAME "prism54"
-#define DRV_VERSION "1.2"
-
MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 88e10c9bc4a..47b2ccb6a63 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -331,7 +331,6 @@ static int ray_probe(struct pcmcia_device *p_dev)
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
p_dev->conf.IntType = INT_MEMORY_AND_IO;
p_dev->conf.ConfigIndex = 1;
- p_dev->conf.Present = PRESENT_OPTION;
p_dev->priv = dev;
p_dev->irq.Instance = dev;
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index cf2d1486b01..af70460f008 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -806,7 +806,7 @@ spectrum_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+ "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
link->irq.AssignedIRQ, link->io.BasePort1,
link->io.BasePort1 + link->io.NumPorts1 - 1);
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 337c692f6fd..ce3a8bac66f 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -798,7 +798,7 @@ static unsigned int get_baud(struct tty_struct *tty)
*/
static void set_baud(struct tty_struct *tty, unsigned int baudcode)
{
- struct termios old_termios = *(tty->termios);
+ struct ktermios old_termios = *(tty->termios);
tty->termios->c_cflag &= ~CBAUD; /* Clear the old baud setting */
tty->termios->c_cflag |= baudcode; /* Set the new baud setting */
tty->driver->set_termios(tty, &old_termios);
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 233d906c08f..5eb81638e84 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -603,7 +603,7 @@ static wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char se
if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS)
return NULL;
- new_wavepoint=(wavepoint_history *) kmalloc(sizeof(wavepoint_history),GFP_ATOMIC);
+ new_wavepoint = kmalloc(sizeof(wavepoint_history),GFP_ATOMIC);
if(new_wavepoint==NULL)
return NULL;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 583e0d655a9..c250f08c8dd 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1928,7 +1928,6 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
p_dev->conf.IntType = INT_MEMORY_AND_IO;
p_dev->conf.ConfigIndex = 1;
- p_dev->conf.Present = PRESENT_OPTION;
dev = alloc_etherdev(sizeof(struct wl3501_card));
if (!dev)
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 77e11ddad83..12dfc0b6efe 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -84,6 +84,18 @@ static void print_id(struct zd_chip *chip)
dev_info(zd_chip_dev(chip), "%s\n", buffer);
}
+static zd_addr_t inc_addr(zd_addr_t addr)
+{
+ u16 a = (u16)addr;
+ /* Control registers use byte addressing, but everything else uses word
+ * addressing. */
+ if ((a & 0xf000) == CR_START)
+ a += 2;
+ else
+ a += 1;
+ return (zd_addr_t)a;
+}
+
/* Read a variable number of 32-bit values. Parameter count is not allowed to
* exceed USB_MAX_IOREAD32_COUNT.
*/
@@ -101,7 +113,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
/* Allocate a single memory block for values and addresses. */
count16 = 2*count;
- a16 = (zd_addr_t *)kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
+ a16 = kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
GFP_NOFS);
if (!a16) {
dev_dbg_f(zd_chip_dev(chip),
@@ -114,7 +126,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
for (i = 0; i < count; i++) {
int j = 2*i;
/* We read the high word always first. */
- a16[j] = zd_inc_word(addr[i]);
+ a16[j] = inc_addr(addr[i]);
a16[j+1] = addr[i];
}
@@ -163,7 +175,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
j = 2*i;
/* We write the high word always first. */
ioreqs16[j].value = ioreqs[i].value >> 16;
- ioreqs16[j].addr = zd_inc_word(ioreqs[i].addr);
+ ioreqs16[j].addr = inc_addr(ioreqs[i].addr);
ioreqs16[j+1].value = ioreqs[i].value;
ioreqs16[j+1].addr = ioreqs[i].addr;
}
@@ -466,7 +478,8 @@ static int read_values(struct zd_chip *chip, u8 *values, size_t count,
ZD_ASSERT(mutex_is_locked(&chip->mutex));
for (i = 0;;) {
- r = zd_ioread32_locked(chip, &v, e2p_addr+i/2);
+ r = zd_ioread32_locked(chip, &v,
+ (zd_addr_t)((u16)e2p_addr+i/2));
if (r)
return r;
v -= guard;
@@ -798,47 +811,18 @@ static int hw_reset_phy(struct zd_chip *chip)
static int zd1211_hw_init_hmac(struct zd_chip *chip)
{
static const struct zd_ioreq32 ioreqs[] = {
- { CR_ACK_TIMEOUT_EXT, 0x20 },
- { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
{ CR_ZD1211_RETRY_MAX, 0x2 },
- { CR_SNIFFER_ON, 0 },
- { CR_RX_FILTER, STA_RX_FILTER },
- { CR_GROUP_HASH_P1, 0x00 },
- { CR_GROUP_HASH_P2, 0x80000000 },
- { CR_REG1, 0xa4 },
- { CR_ADDA_PWR_DWN, 0x7f },
- { CR_BCN_PLCP_CFG, 0x00f00401 },
- { CR_PHY_DELAY, 0x00 },
- { CR_ACK_TIMEOUT_EXT, 0x80 },
- { CR_ADDA_PWR_DWN, 0x00 },
- { CR_ACK_TIME_80211, 0x100 },
- { CR_RX_PE_DELAY, 0x70 },
- { CR_PS_CTRL, 0x10000000 },
- { CR_RTS_CTS_RATE, 0x02030203 },
{ CR_RX_THRESHOLD, 0x000c0640 },
- { CR_AFTER_PNP, 0x1 },
- { CR_WEP_PROTECT, 0x114 },
};
- int r;
-
dev_dbg_f(zd_chip_dev(chip), "\n");
ZD_ASSERT(mutex_is_locked(&chip->mutex));
- r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
-#ifdef DEBUG
- if (r) {
- dev_err(zd_chip_dev(chip),
- "error in zd_iowrite32a_locked. Error number %d\n", r);
- }
-#endif /* DEBUG */
- return r;
+ return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
static int zd1211b_hw_init_hmac(struct zd_chip *chip)
{
static const struct zd_ioreq32 ioreqs[] = {
- { CR_ACK_TIMEOUT_EXT, 0x20 },
- { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
{ CR_ZD1211B_RETRY_MAX, 0x02020202 },
{ CR_ZD1211B_TX_PWR_CTL4, 0x007f003f },
{ CR_ZD1211B_TX_PWR_CTL3, 0x007f003f },
@@ -847,6 +831,20 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
{ CR_ZD1211B_AIFS_CTL1, 0x00280028 },
{ CR_ZD1211B_AIFS_CTL2, 0x008C003C },
{ CR_ZD1211B_TXOP, 0x01800824 },
+ { CR_RX_THRESHOLD, 0x000c0eff, },
+ };
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int hw_init_hmac(struct zd_chip *chip)
+{
+ int r;
+ static const struct zd_ioreq32 ioreqs[] = {
+ { CR_ACK_TIMEOUT_EXT, 0x20 },
+ { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
{ CR_SNIFFER_ON, 0 },
{ CR_RX_FILTER, STA_RX_FILTER },
{ CR_GROUP_HASH_P1, 0x00 },
@@ -861,25 +859,16 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
{ CR_RX_PE_DELAY, 0x70 },
{ CR_PS_CTRL, 0x10000000 },
{ CR_RTS_CTS_RATE, 0x02030203 },
- { CR_RX_THRESHOLD, 0x000c0eff, },
{ CR_AFTER_PNP, 0x1 },
{ CR_WEP_PROTECT, 0x114 },
+ { CR_IFS_VALUE, IFS_VALUE_DEFAULT },
};
- int r;
-
- dev_dbg_f(zd_chip_dev(chip), "\n");
ZD_ASSERT(mutex_is_locked(&chip->mutex));
r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
- if (r) {
- dev_dbg_f(zd_chip_dev(chip),
- "error in zd_iowrite32a_locked. Error number %d\n", r);
- }
- return r;
-}
+ if (r)
+ return r;
-static int hw_init_hmac(struct zd_chip *chip)
-{
return chip->is_zd1211b ?
zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
}
@@ -974,16 +963,14 @@ static int hw_init(struct zd_chip *chip)
if (r)
return r;
- /* Although the vendor driver defaults to a different value during
- * init, it overwrites the IFS value with the following every time
- * the channel changes. We should aim to be more intelligent... */
- r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
- if (r)
- return r;
-
return set_beacon_interval(chip, 100);
}
+static zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset)
+{
+ return (zd_addr_t)((u16)chip->fw_regs_base + offset);
+}
+
#ifdef DEBUG
static int dump_cr(struct zd_chip *chip, const zd_addr_t addr,
const char *addr_string)
@@ -1018,9 +1005,11 @@ static int test_init(struct zd_chip *chip)
static void dump_fw_registers(struct zd_chip *chip)
{
- static const zd_addr_t addr[4] = {
- FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE,
- FW_LINK_STATUS
+ const zd_addr_t addr[4] = {
+ fw_reg_addr(chip, FW_REG_FIRMWARE_VER),
+ fw_reg_addr(chip, FW_REG_USB_SPEED),
+ fw_reg_addr(chip, FW_REG_FIX_TX_RATE),
+ fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
};
int r;
@@ -1046,7 +1035,8 @@ static int print_fw_version(struct zd_chip *chip)
int r;
u16 version;
- r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER);
+ r = zd_ioread16_locked(chip, &version,
+ fw_reg_addr(chip, FW_REG_FIRMWARE_VER));
if (r)
return r;
@@ -1126,6 +1116,22 @@ int zd_chip_disable_hwint(struct zd_chip *chip)
return r;
}
+static int read_fw_regs_offset(struct zd_chip *chip)
+{
+ int r;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base,
+ FWRAW_REGS_ADDR);
+ if (r)
+ return r;
+ dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n",
+ (u16)chip->fw_regs_base);
+
+ return 0;
+}
+
+
int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
{
int r;
@@ -1145,7 +1151,7 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
if (r)
goto out;
- r = zd_usb_init_hw(&chip->usb);
+ r = read_fw_regs_offset(chip);
if (r)
goto out;
@@ -1325,15 +1331,15 @@ u8 zd_chip_get_channel(struct zd_chip *chip)
int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
{
- static const zd_addr_t a[] = {
- FW_LINK_STATUS,
+ const zd_addr_t a[] = {
+ fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
CR_LED,
};
int r;
u16 v[ARRAY_SIZE(a)];
struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
- [0] = { FW_LINK_STATUS },
+ [0] = { fw_reg_addr(chip, FW_REG_LED_LINK_STATUS) },
[1] = { CR_LED },
};
u16 other_led;
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index a4e3cee9b59..b07569e391e 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -18,7 +18,6 @@
#ifndef _ZD_CHIP_H
#define _ZD_CHIP_H
-#include "zd_types.h"
#include "zd_rf.h"
#include "zd_usb.h"
@@ -27,6 +26,37 @@
* adds a processor for handling the USB protocol.
*/
+/* Address space */
+enum {
+ /* CONTROL REGISTERS */
+ CR_START = 0x9000,
+
+
+ /* FIRMWARE */
+ FW_START = 0xee00,
+
+
+ /* EEPROM */
+ E2P_START = 0xf800,
+ E2P_LEN = 0x800,
+
+ /* EEPROM layout */
+ E2P_LOAD_CODE_LEN = 0xe, /* base 0xf800 */
+ E2P_LOAD_VECT_LEN = 0x9, /* base 0xf80e */
+ /* E2P_DATA indexes into this */
+ E2P_DATA_LEN = 0x7e, /* base 0xf817 */
+ E2P_BOOT_CODE_LEN = 0x760, /* base 0xf895 */
+ E2P_INTR_VECT_LEN = 0xb, /* base 0xfff5 */
+
+ /* Some precomputed offsets into the EEPROM */
+ E2P_DATA_OFFSET = E2P_LOAD_CODE_LEN + E2P_LOAD_VECT_LEN,
+ E2P_BOOT_CODE_OFFSET = E2P_DATA_OFFSET + E2P_DATA_LEN,
+};
+
+#define CTL_REG(offset) ((zd_addr_t)(CR_START + (offset)))
+#define E2P_DATA(offset) ((zd_addr_t)(E2P_START + E2P_DATA_OFFSET + (offset)))
+#define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset)))
+
/* 8-bit hardware registers */
#define CR0 CTL_REG(0x0000)
#define CR1 CTL_REG(0x0004)
@@ -302,7 +332,7 @@
#define CR_MAX_PHY_REG 255
-/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
+/* Taken from the ZYDAS driver, not all of them are relevant for the ZD1211
* driver.
*/
@@ -594,81 +624,71 @@
/*
* Upper 16 bit contains the regulatory domain.
*/
-#define E2P_SUBID E2P_REG(0x00)
-#define E2P_POD E2P_REG(0x02)
-#define E2P_MAC_ADDR_P1 E2P_REG(0x04)
-#define E2P_MAC_ADDR_P2 E2P_REG(0x06)
-#define E2P_PWR_CAL_VALUE1 E2P_REG(0x08)
-#define E2P_PWR_CAL_VALUE2 E2P_REG(0x0a)
-#define E2P_PWR_CAL_VALUE3 E2P_REG(0x0c)
-#define E2P_PWR_CAL_VALUE4 E2P_REG(0x0e)
-#define E2P_PWR_INT_VALUE1 E2P_REG(0x10)
-#define E2P_PWR_INT_VALUE2 E2P_REG(0x12)
-#define E2P_PWR_INT_VALUE3 E2P_REG(0x14)
-#define E2P_PWR_INT_VALUE4 E2P_REG(0x16)
+#define E2P_SUBID E2P_DATA(0x00)
+#define E2P_POD E2P_DATA(0x02)
+#define E2P_MAC_ADDR_P1 E2P_DATA(0x04)
+#define E2P_MAC_ADDR_P2 E2P_DATA(0x06)
+#define E2P_PWR_CAL_VALUE1 E2P_DATA(0x08)
+#define E2P_PWR_CAL_VALUE2 E2P_DATA(0x0a)
+#define E2P_PWR_CAL_VALUE3 E2P_DATA(0x0c)
+#define E2P_PWR_CAL_VALUE4 E2P_DATA(0x0e)
+#define E2P_PWR_INT_VALUE1 E2P_DATA(0x10)
+#define E2P_PWR_INT_VALUE2 E2P_DATA(0x12)
+#define E2P_PWR_INT_VALUE3 E2P_DATA(0x14)
+#define E2P_PWR_INT_VALUE4 E2P_DATA(0x16)
/* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30)
* also only 11 channels. */
-#define E2P_ALLOWED_CHANNEL E2P_REG(0x18)
-
-#define E2P_PHY_REG E2P_REG(0x1a)
-#define E2P_DEVICE_VER E2P_REG(0x20)
-#define E2P_36M_CAL_VALUE1 E2P_REG(0x28)
-#define E2P_36M_CAL_VALUE2 E2P_REG(0x2a)
-#define E2P_36M_CAL_VALUE3 E2P_REG(0x2c)
-#define E2P_36M_CAL_VALUE4 E2P_REG(0x2e)
-#define E2P_11A_INT_VALUE1 E2P_REG(0x30)
-#define E2P_11A_INT_VALUE2 E2P_REG(0x32)
-#define E2P_11A_INT_VALUE3 E2P_REG(0x34)
-#define E2P_11A_INT_VALUE4 E2P_REG(0x36)
-#define E2P_48M_CAL_VALUE1 E2P_REG(0x38)
-#define E2P_48M_CAL_VALUE2 E2P_REG(0x3a)
-#define E2P_48M_CAL_VALUE3 E2P_REG(0x3c)
-#define E2P_48M_CAL_VALUE4 E2P_REG(0x3e)
-#define E2P_48M_INT_VALUE1 E2P_REG(0x40)
-#define E2P_48M_INT_VALUE2 E2P_REG(0x42)
-#define E2P_48M_INT_VALUE3 E2P_REG(0x44)
-#define E2P_48M_INT_VALUE4 E2P_REG(0x46)
-#define E2P_54M_CAL_VALUE1 E2P_REG(0x48) /* ??? */
-#define E2P_54M_CAL_VALUE2 E2P_REG(0x4a)
-#define E2P_54M_CAL_VALUE3 E2P_REG(0x4c)
-#define E2P_54M_CAL_VALUE4 E2P_REG(0x4e)
-#define E2P_54M_INT_VALUE1 E2P_REG(0x50)
-#define E2P_54M_INT_VALUE2 E2P_REG(0x52)
-#define E2P_54M_INT_VALUE3 E2P_REG(0x54)
-#define E2P_54M_INT_VALUE4 E2P_REG(0x56)
-
-/* All 16 bit values */
-#define FW_FIRMWARE_VER FW_REG(0)
-/* non-zero if USB high speed connection */
-#define FW_USB_SPEED FW_REG(1)
-#define FW_FIX_TX_RATE FW_REG(2)
-/* Seems to be able to control LEDs over the firmware */
-#define FW_LINK_STATUS FW_REG(3)
-#define FW_SOFT_RESET FW_REG(4)
-#define FW_FLASH_CHK FW_REG(5)
+#define E2P_ALLOWED_CHANNEL E2P_DATA(0x18)
+
+#define E2P_PHY_REG E2P_DATA(0x1a)
+#define E2P_DEVICE_VER E2P_DATA(0x20)
+#define E2P_36M_CAL_VALUE1 E2P_DATA(0x28)
+#define E2P_36M_CAL_VALUE2 E2P_DATA(0x2a)
+#define E2P_36M_CAL_VALUE3 E2P_DATA(0x2c)
+#define E2P_36M_CAL_VALUE4 E2P_DATA(0x2e)
+#define E2P_11A_INT_VALUE1 E2P_DATA(0x30)
+#define E2P_11A_INT_VALUE2 E2P_DATA(0x32)
+#define E2P_11A_INT_VALUE3 E2P_DATA(0x34)
+#define E2P_11A_INT_VALUE4 E2P_DATA(0x36)
+#define E2P_48M_CAL_VALUE1 E2P_DATA(0x38)
+#define E2P_48M_CAL_VALUE2 E2P_DATA(0x3a)
+#define E2P_48M_CAL_VALUE3 E2P_DATA(0x3c)
+#define E2P_48M_CAL_VALUE4 E2P_DATA(0x3e)
+#define E2P_48M_INT_VALUE1 E2P_DATA(0x40)
+#define E2P_48M_INT_VALUE2 E2P_DATA(0x42)
+#define E2P_48M_INT_VALUE3 E2P_DATA(0x44)
+#define E2P_48M_INT_VALUE4 E2P_DATA(0x46)
+#define E2P_54M_CAL_VALUE1 E2P_DATA(0x48) /* ??? */
+#define E2P_54M_CAL_VALUE2 E2P_DATA(0x4a)
+#define E2P_54M_CAL_VALUE3 E2P_DATA(0x4c)
+#define E2P_54M_CAL_VALUE4 E2P_DATA(0x4e)
+#define E2P_54M_INT_VALUE1 E2P_DATA(0x50)
+#define E2P_54M_INT_VALUE2 E2P_DATA(0x52)
+#define E2P_54M_INT_VALUE3 E2P_DATA(0x54)
+#define E2P_54M_INT_VALUE4 E2P_DATA(0x56)
+
+/* This word contains the base address of the FW_REG_ registers below */
+#define FWRAW_REGS_ADDR FWRAW_DATA(0x1d)
+
+/* All 16 bit values, offset from the address in FWRAW_REGS_ADDR */
+enum {
+ FW_REG_FIRMWARE_VER = 0,
+ /* non-zero if USB high speed connection */
+ FW_REG_USB_SPEED = 1,
+ FW_REG_FIX_TX_RATE = 2,
+ /* Seems to be able to control LEDs over the firmware */
+ FW_REG_LED_LINK_STATUS = 3,
+ FW_REG_SOFT_RESET = 4,
+ FW_REG_FLASH_CHK = 5,
+};
+/* Values for FW_LINK_STATUS */
#define FW_LINK_OFF 0x0
#define FW_LINK_TX 0x1
/* 0x2 - link led on? */
enum {
- CR_BASE_OFFSET = 0x9000,
- FW_START_OFFSET = 0xee00,
- FW_BASE_ADDR_OFFSET = FW_START_OFFSET + 0x1d,
- EEPROM_START_OFFSET = 0xf800,
- EEPROM_SIZE = 0x800, /* words */
- LOAD_CODE_SIZE = 0xe, /* words */
- LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */
- EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
- EEPROM_REGS_SIZE = 0x7e, /* words */
- E2P_BASE_OFFSET = EEPROM_START_OFFSET +
- EEPROM_REGS_OFFSET,
-};
-
-#define FW_REG_TABLE_ADDR USB_ADDR(FW_START_OFFSET + 0x1d)
-
-enum {
/* indices for ofdm_cal_values */
OFDM_36M_INDEX = 0,
OFDM_48M_INDEX = 1,
@@ -679,6 +699,8 @@ struct zd_chip {
struct zd_usb usb;
struct zd_rf rf;
struct mutex mutex;
+ /* Base address of FW_REG_ registers */
+ zd_addr_t fw_regs_base;
u8 e2p_mac[ETH_ALEN];
/* EepSetPoint in the vendor driver */
u8 pwr_cal_values[E2P_CHANNEL_COUNT];
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index fb22f62cf1f..deb99d1eaa7 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -23,6 +23,8 @@
#include <linux/device.h>
#include <linux/kernel.h>
+typedef u16 __nocast zd_addr_t;
+
#define dev_printk_f(level, dev, fmt, args...) \
dev_printk(level, dev, "%s() " fmt, __func__, ##args)
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index 26b8298dff8..c4f36d39642 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -2,7 +2,6 @@
#define _ZD_IEEE80211_H
#include <net/ieee80211.h>
-#include "zd_types.h"
/* Additional definitions from the standards.
*/
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 00ca704ece3..a08524191b5 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -41,6 +41,8 @@ static void housekeeping_disable(struct zd_mac *mac);
static void set_multicast_hash_handler(struct work_struct *work);
+static void do_rx(unsigned long mac_ptr);
+
int zd_mac_init(struct zd_mac *mac,
struct net_device *netdev,
struct usb_interface *intf)
@@ -53,6 +55,10 @@ int zd_mac_init(struct zd_mac *mac,
INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work);
+ skb_queue_head_init(&mac->rx_queue);
+ tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac);
+ tasklet_disable(&mac->rx_tasklet);
+
ieee_init(ieee);
softmac_init(ieee80211_priv(netdev));
zd_chip_init(&mac->chip, netdev, intf);
@@ -140,6 +146,8 @@ out:
void zd_mac_clear(struct zd_mac *mac)
{
flush_workqueue(zd_workqueue);
+ skb_queue_purge(&mac->rx_queue);
+ tasklet_kill(&mac->rx_tasklet);
zd_chip_clear(&mac->chip);
ZD_ASSERT(!spin_is_locked(&mac->lock));
ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
@@ -168,6 +176,8 @@ int zd_mac_open(struct net_device *netdev)
struct zd_chip *chip = &mac->chip;
int r;
+ tasklet_enable(&mac->rx_tasklet);
+
r = zd_chip_enable_int(chip);
if (r < 0)
goto out;
@@ -218,6 +228,8 @@ int zd_mac_stop(struct net_device *netdev)
*/
zd_chip_disable_rx(chip);
+ skb_queue_purge(&mac->rx_queue);
+ tasklet_disable(&mac->rx_tasklet);
housekeeping_disable(mac);
ieee80211softmac_stop(netdev);
@@ -470,13 +482,13 @@ static void bssinfo_change(struct net_device *netdev, u32 changes)
if (changes & IEEE80211SOFTMAC_BSSINFOCHG_RATES) {
/* Set RTS rate to highest available basic rate */
- u8 rate = ieee80211softmac_highest_supported_rate(softmac,
+ u8 hi_rate = ieee80211softmac_highest_supported_rate(softmac,
&bssinfo->supported_rates, 1);
- rate = rate_to_zd_rate(rate);
+ hi_rate = rate_to_zd_rate(hi_rate);
spin_lock_irqsave(&mac->lock, flags);
- if (rate != mac->rts_rate) {
- mac->rts_rate = rate;
+ if (hi_rate != mac->rts_rate) {
+ mac->rts_rate = hi_rate;
need_set_rts_cts = 1;
}
spin_unlock_irqrestore(&mac->lock, flags);
@@ -1072,43 +1084,75 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
return 0;
}
-int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
{
int r;
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
struct ieee80211_rx_stats stats;
const struct rx_status *status;
- struct sk_buff *skb;
- if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
- IEEE80211_FCS_LEN + sizeof(struct rx_status))
- return -EINVAL;
+ if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
+ IEEE80211_FCS_LEN + sizeof(struct rx_status))
+ {
+ dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n",
+ skb->len);
+ goto free_skb;
+ }
- r = fill_rx_stats(&stats, &status, mac, buffer, length);
- if (r)
- return r;
+ r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len);
+ if (r) {
+ /* Only packets with rx errors are included here. */
+ goto free_skb;
+ }
- length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+
- sizeof(struct rx_status);
- buffer += ZD_PLCP_HEADER_SIZE;
+ __skb_pull(skb, ZD_PLCP_HEADER_SIZE);
+ __skb_trim(skb, skb->len -
+ (IEEE80211_FCS_LEN + sizeof(struct rx_status)));
- update_qual_rssi(mac, buffer, length, stats.signal, stats.rssi);
+ update_qual_rssi(mac, skb->data, skb->len, stats.signal,
+ status->signal_strength);
- r = filter_rx(ieee, buffer, length, &stats);
- if (r <= 0)
- return r;
+ r = filter_rx(ieee, skb->data, skb->len, &stats);
+ if (r <= 0) {
+ if (r < 0)
+ dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n");
+ goto free_skb;
+ }
- skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
- if (!skb)
- return -ENOMEM;
if (ieee->iw_mode == IW_MODE_MONITOR)
- fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac,
+ fill_rt_header(skb_push(skb, sizeof(struct zd_rt_hdr)), mac,
&stats, status);
- memcpy(skb_put(skb, length), buffer, length);
r = ieee80211_rx(ieee, skb, &stats);
- if (!r)
- dev_kfree_skb_any(skb);
+ if (r)
+ return;
+free_skb:
+ /* We are always in a soft irq. */
+ dev_kfree_skb(skb);
+}
+
+static void do_rx(unsigned long mac_ptr)
+{
+ struct zd_mac *mac = (struct zd_mac *)mac_ptr;
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&mac->rx_queue)) != NULL)
+ zd_mac_rx(mac, skb);
+}
+
+int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+{
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
+ if (!skb) {
+ dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
+ return -ENOMEM;
+ }
+ skb_reserve(skb, sizeof(struct zd_rt_hdr));
+ memcpy(__skb_put(skb, length), buffer, length);
+ skb_queue_tail(&mac->rx_queue, skb);
+ tasklet_schedule(&mac->rx_tasklet);
return 0;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index f0cf05dc7d3..faf4c7828d4 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -138,6 +138,9 @@ struct zd_mac {
struct delayed_work set_rts_cts_work;
struct delayed_work set_basic_rates_work;
+ struct tasklet_struct rx_tasklet;
+ struct sk_buff_head rx_queue;
+
unsigned int stats_count;
u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE];
u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE];
@@ -193,7 +196,7 @@ int zd_mac_stop(struct net_device *netdev);
int zd_mac_set_mac_address(struct net_device *dev, void *p);
void zd_mac_set_multicast_list(struct net_device *netdev);
-int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length);
+int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length);
int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain);
u8 zd_mac_get_regdomain(struct zd_mac *zd_mac);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index 676b3734f1e..a57732eb69e 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -18,8 +18,6 @@
#ifndef _ZD_RF_H
#define _ZD_RF_H
-#include "zd_types.h"
-
#define UW2451_RF 0x2
#define UCHIP_RF 0x3
#define AL2230_RF 0x4
diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h
deleted file mode 100644
index 0155a1584ed..00000000000
--- a/drivers/net/wireless/zd1211rw/zd_types.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* zd_types.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.
- *
- * 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 _ZD_TYPES_H
-#define _ZD_TYPES_H
-
-#include <linux/types.h>
-
-/* We have three register spaces mapped into the overall USB address space of
- * 64K words (16-bit values). There is the control register space of
- * double-word registers, the eeprom register space and the firmware register
- * space. The control register space is byte mapped, the others are word
- * mapped.
- *
- * For that reason, we are using byte offsets for control registers and word
- * offsets for everything else.
- */
-
-typedef u32 __nocast zd_addr_t;
-
-enum {
- ADDR_BASE_MASK = 0xff000000,
- ADDR_OFFSET_MASK = 0x0000ffff,
- ADDR_ZERO_MASK = 0x00ff0000,
- NULL_BASE = 0x00000000,
- USB_BASE = 0x01000000,
- CR_BASE = 0x02000000,
- CR_MAX_OFFSET = 0x0b30,
- E2P_BASE = 0x03000000,
- E2P_MAX_OFFSET = 0x007e,
- FW_BASE = 0x04000000,
- FW_MAX_OFFSET = 0x0005,
-};
-
-#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK)
-#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK)
-
-#define ZD_ADDR(base, offset) \
- ((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK)))
-
-#define ZD_NULL_ADDR ((zd_addr_t)0)
-#define USB_REG(offset) ZD_ADDR(USB_BASE, offset) /* word addressing */
-#define CTL_REG(offset) ZD_ADDR(CR_BASE, offset) /* byte addressing */
-#define E2P_REG(offset) ZD_ADDR(E2P_BASE, offset) /* word addressing */
-#define FW_REG(offset) ZD_ADDR(FW_BASE, offset) /* word addressing */
-
-static inline zd_addr_t zd_inc_word(zd_addr_t addr)
-{
- u32 base = ZD_ADDR_BASE(addr);
- u32 offset = ZD_OFFSET(addr);
-
- offset += base == CR_BASE ? 2 : 1;
-
- return base | offset;
-}
-
-#endif /* _ZD_TYPES_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index aa782e88754..75ef55624d7 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -58,6 +58,10 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{}
@@ -73,96 +77,6 @@ MODULE_DEVICE_TABLE(usb, usb_ids);
#define FW_ZD1211_PREFIX "zd1211/zd1211_"
#define FW_ZD1211B_PREFIX "zd1211/zd1211b_"
-/* register address handling */
-
-#ifdef DEBUG
-static int check_addr(struct zd_usb *usb, zd_addr_t addr)
-{
- u32 base = ZD_ADDR_BASE(addr);
- u32 offset = ZD_OFFSET(addr);
-
- if ((u32)addr & ADDR_ZERO_MASK)
- goto invalid_address;
- switch (base) {
- case USB_BASE:
- break;
- case CR_BASE:
- if (offset > CR_MAX_OFFSET) {
- dev_dbg(zd_usb_dev(usb),
- "CR offset %#010x larger than"
- " CR_MAX_OFFSET %#10x\n",
- offset, CR_MAX_OFFSET);
- goto invalid_address;
- }
- if (offset & 1) {
- dev_dbg(zd_usb_dev(usb),
- "CR offset %#010x is not a multiple of 2\n",
- offset);
- goto invalid_address;
- }
- break;
- case E2P_BASE:
- if (offset > E2P_MAX_OFFSET) {
- dev_dbg(zd_usb_dev(usb),
- "E2P offset %#010x larger than"
- " E2P_MAX_OFFSET %#010x\n",
- offset, E2P_MAX_OFFSET);
- goto invalid_address;
- }
- break;
- case FW_BASE:
- if (!usb->fw_base_offset) {
- dev_dbg(zd_usb_dev(usb),
- "ERROR: fw base offset has not been set\n");
- return -EAGAIN;
- }
- if (offset > FW_MAX_OFFSET) {
- dev_dbg(zd_usb_dev(usb),
- "FW offset %#10x is larger than"
- " FW_MAX_OFFSET %#010x\n",
- offset, FW_MAX_OFFSET);
- goto invalid_address;
- }
- break;
- default:
- dev_dbg(zd_usb_dev(usb),
- "address has unsupported base %#010x\n", addr);
- goto invalid_address;
- }
-
- return 0;
-invalid_address:
- dev_dbg(zd_usb_dev(usb),
- "ERROR: invalid address: %#010x\n", addr);
- return -EINVAL;
-}
-#endif /* DEBUG */
-
-static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr)
-{
- u32 base;
- u16 offset;
-
- base = ZD_ADDR_BASE(addr);
- offset = ZD_OFFSET(addr);
-
- ZD_ASSERT(check_addr(usb, addr) == 0);
-
- switch (base) {
- case CR_BASE:
- offset += CR_BASE_OFFSET;
- break;
- case E2P_BASE:
- offset += E2P_BASE_OFFSET;
- break;
- case FW_BASE:
- offset += usb->fw_base_offset;
- break;
- }
-
- return offset;
-}
-
/* USB device initialization */
static int request_fw_file(
@@ -295,14 +209,13 @@ static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
if (r)
goto error;
- r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
- REBOOT);
+ r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT);
if (r)
goto error;
- offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+ offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16));
r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
- E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+ E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT);
/* At this point, the vendor driver downloads the whole firmware
* image, hacks around with version IDs, and uploads it again,
@@ -331,7 +244,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
if (r)
goto error;
- fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+ fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET);
if (fw_bcdDevice != bcdDevice) {
dev_info(&udev->dev,
@@ -357,8 +270,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
if (r)
goto error;
- r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET,
- REBOOT);
+ r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT);
if (r) {
dev_err(&udev->dev,
"Could not upload firmware code uph. Error number %d\n",
@@ -598,13 +510,13 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
n = l+k;
if (n > length)
return;
- zd_mac_rx(mac, buffer+l, k);
+ zd_mac_rx_irq(mac, buffer+l, k);
if (i >= 2)
return;
l = (n+3) & ~3;
}
} else {
- zd_mac_rx(mac, buffer, length);
+ zd_mac_rx_irq(mac, buffer, length);
}
}
@@ -858,7 +770,7 @@ static inline void init_usb_interrupt(struct zd_usb *usb)
spin_lock_init(&intr->lock);
intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
init_completion(&intr->read_regs.completion);
- intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT));
+ intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT);
}
static inline void init_usb_rx(struct zd_usb *usb)
@@ -890,22 +802,6 @@ void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
init_usb_rx(usb);
}
-int zd_usb_init_hw(struct zd_usb *usb)
-{
- int r;
- struct zd_chip *chip = zd_usb_to_chip(usb);
-
- ZD_ASSERT(mutex_is_locked(&chip->mutex));
- r = zd_ioread16_locked(chip, &usb->fw_base_offset,
- USB_REG((u16)FW_BASE_ADDR_OFFSET));
- if (r)
- return r;
- dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n",
- usb->fw_base_offset);
-
- return 0;
-}
-
void zd_usb_clear(struct zd_usb *usb)
{
usb_set_intfdata(usb->intf, NULL);
@@ -1253,7 +1149,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
return -ENOMEM;
req->id = cpu_to_le16(USB_REQ_READ_REGS);
for (i = 0; i < count; i++)
- req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i]));
+ req->addr[i] = cpu_to_le16((u16)addresses[i]);
udev = zd_usb_to_usbdev(usb);
prepare_read_regs_int(usb);
@@ -1318,7 +1214,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
for (i = 0; i < count; i++) {
struct reg_data *rw = &req->reg_writes[i];
- rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr));
+ rw->addr = cpu_to_le16((u16)ioreqs[i].addr);
rw->value = cpu_to_le16(ioreqs[i].value);
}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 317d37c3667..506ea6a7439 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -25,7 +25,6 @@
#include <linux/usb.h>
#include "zd_def.h"
-#include "zd_types.h"
enum devicetype {
DEVICE_ZD1211 = 0,
@@ -181,15 +180,14 @@ struct zd_usb_tx {
spinlock_t lock;
};
-/* Contains the usb parts. The structure doesn't require a lock, because intf
- * and fw_base_offset, will not be changed after initialization.
+/* Contains the usb parts. The structure doesn't require a lock because intf
+ * will not be changed after initialization.
*/
struct zd_usb {
struct zd_usb_interrupt intr;
struct zd_usb_rx rx;
struct zd_usb_tx tx;
struct usb_interface *intf;
- u16 fw_base_offset;
};
#define zd_usb_dev(usb) (&usb->intf->dev)
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index 43e521e9912..78c2e6e4b42 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -220,8 +220,8 @@ static unsigned long get_exec_dcookie(struct mm_struct * mm)
continue;
if (!(vma->vm_flags & VM_EXECUTABLE))
continue;
- cookie = fast_get_dcookie(vma->vm_file->f_dentry,
- vma->vm_file->f_vfsmnt);
+ cookie = fast_get_dcookie(vma->vm_file->f_path.dentry,
+ vma->vm_file->f_path.mnt);
break;
}
@@ -246,8 +246,8 @@ static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, o
continue;
if (vma->vm_file) {
- cookie = fast_get_dcookie(vma->vm_file->f_dentry,
- vma->vm_file->f_vfsmnt);
+ cookie = fast_get_dcookie(vma->vm_file->f_path.dentry,
+ vma->vm_file->f_path.mnt);
*offset = (vma->vm_pgoff << PAGE_SHIFT) + addr -
vma->vm_start;
} else {
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 12bab64a62a..6fb3f7979f2 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -874,7 +874,7 @@ void *iosapic_register(unsigned long hpa)
return NULL;
}
- isi = (struct iosapic_info *)kzalloc(sizeof(struct iosapic_info), GFP_KERNEL);
+ isi = kzalloc(sizeof(struct iosapic_info), GFP_KERNEL);
if (!isi) {
BUG();
return NULL;
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index c7fa28a28b9..36c6a1bfe55 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -82,9 +82,6 @@ config PARPORT_PC_PCMCIA
Say Y here if you need PCMCIA support for your PC-style parallel
ports. If unsure, say N.
-config PARPORT_NOT_PC
- bool
-
config PARPORT_IP32
tristate "SGI IP32 builtin port (EXPERIMENTAL)"
depends on SGI_IP32 && PARPORT && EXPERIMENTAL
@@ -158,5 +155,8 @@ config PARPORT_1284
transfer modes. Also say Y if you want device ID information to
appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N.
+config PARPORT_NOT_PC
+ bool
+
endmenu
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index f1dd81a1d59..3cfb0a3575e 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -19,7 +19,7 @@ config PCI_MSI
config PCI_MULTITHREAD_PROBE
bool "PCI Multi-threaded probe (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI && EXPERIMENTAL && BROKEN
help
Say Y here if you want the PCI core to spawn a new thread for
every PCI device that is probed. This can cause a huge
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index 6e780db9454..be92695a783 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -76,7 +76,8 @@ config HOTPLUG_PCI_IBM
config HOTPLUG_PCI_ACPI
tristate "ACPI PCI Hotplug driver"
- depends on (!ACPI_DOCK && ACPI && HOTPLUG_PCI) || (ACPI_DOCK && HOTPLUG_PCI)
+ depends on HOTPLUG_PCI
+ depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK)
help
Say Y here if you have a system that supports PCI Hotplug using
ACPI.
@@ -144,15 +145,6 @@ config HOTPLUG_PCI_SHPC
When in doubt, say N.
-config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
- bool "Use polling mechanism for hot-plug events (for testing purpose)"
- depends on HOTPLUG_PCI_SHPC
- help
- Say Y here if you want to use the polling mechanism for hot-plug
- events for early platform testing.
-
- When in doubt, say N.
-
config HOTPLUG_PCI_RPA
tristate "RPA PCI Hotplug driver"
depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 0b9d0db1590..fca978fb158 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -773,13 +773,13 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
goto out;
table = obj->buffer.pointer;
- switch (((acpi_table_entry_header *)table)->type) {
- case ACPI_MADT_IOSAPIC:
- *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base;
+ switch (((struct acpi_subtable_header *)table)->type) {
+ case ACPI_MADT_TYPE_IO_SAPIC:
+ *gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base;
result = 0;
break;
- case ACPI_MADT_IOAPIC:
- *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base;
+ case ACPI_MADT_TYPE_IO_APIC:
+ *gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base;
result = 0;
break;
default:
@@ -1682,7 +1682,7 @@ int __init acpiphp_glue_init(void)
*
* This function frees all data allocated in acpiphp_glue_init()
*/
-void __exit acpiphp_glue_exit(void)
+void acpiphp_glue_exit(void)
{
acpi_pci_unregister_driver(&acpi_pci_hp_driver);
}
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index bd40aee10e1..7f03881a8b6 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -319,13 +319,12 @@ static int ibm_get_table_from_acpi(char **bufp)
if (bufp == NULL)
goto read_table_done;
- lbuf = kmalloc(size, GFP_KERNEL);
+ lbuf = kzalloc(size, GFP_KERNEL);
dbg("%s: element count: %i, ASL table size: %i, &table = 0x%p\n",
__FUNCTION__, package->package.count, size, lbuf);
if (lbuf) {
*bufp = lbuf;
- memset(lbuf, 0, size);
} else {
size = -ENOMEM;
goto read_table_done;
diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c
index 298a6cfd840..ae5e974c45a 100644
--- a/drivers/pci/hotplug/cpqphp_nvram.c
+++ b/drivers/pci/hotplug/cpqphp_nvram.c
@@ -520,7 +520,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
return 2;
while (nummem--) {
- mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!mem_node)
break;
@@ -548,7 +548,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
}
while (numpmem--) {
- p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!p_mem_node)
break;
@@ -576,7 +576,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
}
while (numio--) {
- io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ io_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!io_node)
break;
@@ -604,7 +604,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
}
while (numbus--) {
- bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!bus_node)
break;
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 4fb12fcda56..d19fcae8a7c 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -44,15 +44,20 @@ extern int pciehp_poll_time;
extern int pciehp_debug;
extern int pciehp_force;
-/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
-#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
-
+#define dbg(format, arg...) \
+ do { \
+ if (pciehp_debug) \
+ printk("%s: " format, MY_NAME , ## arg); \
+ } while (0)
+#define err(format, arg...) \
+ printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) \
+ printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) \
+ printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+#define SLOT_NAME_SIZE 10
struct slot {
- struct slot *next;
u8 bus;
u8 device;
u32 number;
@@ -63,6 +68,8 @@ struct slot {
struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
struct list_head slot_list;
+ char name[SLOT_NAME_SIZE];
+ unsigned long last_emi_toggle;
};
struct event_info {
@@ -70,34 +77,15 @@ struct event_info {
u8 hp_slot;
};
-typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id);
-
-struct php_ctlr_state_s {
- struct php_ctlr_state_s *pnext;
- struct pci_dev *pci_dev;
- unsigned int irq;
- unsigned long flags; /* spinlock's */
- u32 slot_device_offset;
- u32 num_slots;
- struct timer_list int_poll_timer; /* Added for poll event */
- php_intr_callback_t attention_button_callback;
- php_intr_callback_t switch_change_callback;
- php_intr_callback_t presence_change_callback;
- php_intr_callback_t power_fault_callback;
- void *callback_instance_id;
- struct ctrl_reg *creg; /* Ptr to controller register space */
-};
-
#define MAX_EVENTS 10
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 */
struct pci_dev *pci_dev;
- struct pci_bus *pci_bus;
+ struct list_head slot_list;
struct event_info event_queue[MAX_EVENTS];
struct slot *slot;
struct hpc_ops *hpc_ops;
@@ -112,6 +100,8 @@ struct controller {
u8 ctrlcap;
u16 vendor_id;
u8 cap_base;
+ struct timer_list poll_timer;
+ volatile int cmd_busy;
};
#define INT_BUTTON_IGNORE 0
@@ -131,8 +121,6 @@ struct controller {
#define POWERON_STATE 3
#define POWEROFF_STATE 4
-#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400
-
/* Error messages */
#define INTERLOCK_OPEN 0x00000002
#define ADD_NOT_SUPPORTED 0x00000003
@@ -144,10 +132,6 @@ struct controller {
#define WRONG_BUS_FREQUENCY 0x0000000D
#define POWER_FAILURE 0x0000000E
-#define REMOVE_NOT_SUPPORTED 0x00000003
-
-#define DISABLE_CARD 1
-
/* Field definitions in Slot Capabilities Register */
#define ATTN_BUTTN_PRSN 0x00000001
#define PWR_CTRL_PRSN 0x00000002
@@ -155,6 +139,7 @@ struct controller {
#define ATTN_LED_PRSN 0x00000008
#define PWR_LED_PRSN 0x00000010
#define HP_SUPR_RM_SUP 0x00000020
+#define EMI_PRSN 0x00020000
#define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN)
#define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN)
@@ -162,130 +147,65 @@ struct controller {
#define ATTN_LED(cap) (cap & ATTN_LED_PRSN)
#define PWR_LED(cap) (cap & PWR_LED_PRSN)
#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP)
-
-/*
- * error Messages
- */
-#define msg_initialization_err "Initialization failure, error=%d\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);
-extern void pciehp_event_stop_thread (void);
-extern int pciehp_enable_slot (struct slot *slot);
-extern int pciehp_disable_slot (struct slot *slot);
-
-extern u8 pciehp_handle_attention_button (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_switch_change (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_presence_change (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_power_fault (u8 hp_slot, void *inst_id);
-/* extern void long_delay (int delay); */
-
-/* pci functions */
-extern int pciehp_configure_device (struct slot *p_slot);
-extern int pciehp_unconfigure_device (struct slot *p_slot);
-
-
+#define EMI(cap) (cap & EMI_PRSN)
+
+extern int pciehp_event_start_thread(void);
+extern void pciehp_event_stop_thread(void);
+extern int pciehp_enable_slot(struct slot *slot);
+extern int pciehp_disable_slot(struct slot *slot);
+extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
+extern int pciehp_configure_device(struct slot *p_slot);
+extern int pciehp_unconfigure_device(struct slot *p_slot);
+int pcie_init(struct controller *ctrl, struct pcie_device *dev);
/* Global variables */
extern struct controller *pciehp_ctrl_list;
-/* Inline functions */
-
static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
{
- struct slot *p_slot, *tmp_slot = NULL;
-
- p_slot = ctrl->slot;
+ struct slot *slot;
- while (p_slot && (p_slot->device != device)) {
- tmp_slot = p_slot;
- p_slot = p_slot->next;
+ list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
+ if (slot->device == device)
+ return slot;
}
- if (p_slot == NULL) {
- err("ERROR: pciehp_find_slot device=0x%x\n", device);
- p_slot = tmp_slot;
- }
-
- return p_slot;
-}
-
-static inline int wait_for_ctrl_irq(struct controller *ctrl)
-{
- int retval = 0;
-
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&ctrl->queue, &wait);
- if (!pciehp_poll_mode)
- /* Sleep for up to 1 second */
- msleep_interruptible(1000);
- else
- msleep_interruptible(2500);
-
- remove_wait_queue(&ctrl->queue, &wait);
- if (signal_pending(current))
- retval = -EINTR;
-
- return retval;
-}
-
-#define SLOT_NAME_SIZE 10
-static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
-{
- snprintf(buffer, buffer_size, "%04d_%04d", slot->bus, slot->number);
+ err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device);
+ return NULL;
}
-enum php_ctlr_type {
- PCI,
- ISA,
- ACPI
-};
-
-int pcie_init(struct controller *ctrl, struct pcie_device *dev);
-
-/* This has no meaning for PCI Express, as there is only 1 slot per port */
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
- int *num_ctlr_slots,
- int *first_device_num,
- int *physical_slot_num,
- u8 *ctrlcap);
-
struct hpc_ops {
- int (*power_on_slot) (struct slot *slot);
- int (*power_off_slot) (struct slot *slot);
- int (*get_power_status) (struct slot *slot, u8 *status);
- int (*get_attention_status) (struct slot *slot, u8 *status);
- int (*set_attention_status) (struct slot *slot, u8 status);
- int (*get_latch_status) (struct slot *slot, u8 *status);
- int (*get_adapter_status) (struct slot *slot, u8 *status);
-
- int (*get_max_bus_speed) (struct slot *slot, enum pci_bus_speed *speed);
- int (*get_cur_bus_speed) (struct slot *slot, enum pci_bus_speed *speed);
-
- int (*get_max_lnk_width) (struct slot *slot, enum pcie_link_width *value);
- int (*get_cur_lnk_width) (struct slot *slot, enum pcie_link_width *value);
-
- int (*query_power_fault) (struct slot *slot);
- void (*green_led_on) (struct slot *slot);
- void (*green_led_off) (struct slot *slot);
- void (*green_led_blink) (struct slot *slot);
- void (*release_ctlr) (struct controller *ctrl);
- int (*check_lnk_status) (struct controller *ctrl);
+ int (*power_on_slot)(struct slot *slot);
+ int (*power_off_slot)(struct slot *slot);
+ int (*get_power_status)(struct slot *slot, u8 *status);
+ int (*get_attention_status)(struct slot *slot, u8 *status);
+ int (*set_attention_status)(struct slot *slot, u8 status);
+ int (*get_latch_status)(struct slot *slot, u8 *status);
+ int (*get_adapter_status)(struct slot *slot, u8 *status);
+ int (*get_emi_status)(struct slot *slot, u8 *status);
+ int (*toggle_emi)(struct slot *slot);
+ int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+ int (*get_cur_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+ int (*query_power_fault)(struct slot *slot);
+ void (*green_led_on)(struct slot *slot);
+ void (*green_led_off)(struct slot *slot);
+ void (*green_led_blink)(struct slot *slot);
+ void (*release_ctlr)(struct controller *ctrl);
+ int (*check_lnk_status)(struct controller *ctrl);
};
-
#ifdef CONFIG_ACPI
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/actypes.h>
#include <linux/pci-acpi.h>
-#define pciehp_get_hp_hw_control_from_firmware(dev) \
+#define pciehp_get_hp_hw_control_from_firmware(dev) \
pciehp_acpi_get_hp_hw_control_from_firmware(dev)
static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
struct hotplug_params *hpp)
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index f13f31323e8..a92eda6e02f 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -34,6 +34,7 @@
#include <linux/pci.h>
#include "pciehp.h"
#include <linux/interrupt.h>
+#include <linux/time.h>
/* Global variables */
int pciehp_debug;
@@ -87,6 +88,95 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
.get_cur_bus_speed = get_cur_bus_speed,
};
+/*
+ * Check the status of the Electro Mechanical Interlock (EMI)
+ */
+static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+ struct slot *slot = hotplug_slot->private;
+ return (slot->hpc_ops->get_emi_status(slot, value));
+}
+
+/*
+ * sysfs interface for the Electro Mechanical Interlock (EMI)
+ * 1 == locked, 0 == unlocked
+ */
+static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf)
+{
+ int retval;
+ u8 value;
+
+ retval = get_lock_status(slot, &value);
+ if (retval)
+ goto lock_read_exit;
+ retval = sprintf (buf, "%d\n", value);
+
+lock_read_exit:
+ return retval;
+}
+
+/*
+ * Change the status of the Electro Mechanical Interlock (EMI)
+ * This is a toggle - in addition there must be at least 1 second
+ * in between toggles.
+ */
+static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status)
+{
+ struct slot *slot = hotplug_slot->private;
+ int retval;
+ u8 value;
+
+ mutex_lock(&slot->ctrl->crit_sect);
+
+ /* has it been >1 sec since our last toggle? */
+ if ((get_seconds() - slot->last_emi_toggle) < 1)
+ return -EINVAL;
+
+ /* see what our current state is */
+ retval = get_lock_status(hotplug_slot, &value);
+ if (retval || (value == status))
+ goto set_lock_exit;
+
+ slot->hpc_ops->toggle_emi(slot);
+set_lock_exit:
+ mutex_unlock(&slot->ctrl->crit_sect);
+ return 0;
+}
+
+/*
+ * sysfs interface which allows the user to toggle the Electro Mechanical
+ * Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock
+ */
+static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf,
+ size_t count)
+{
+ unsigned long llock;
+ u8 lock;
+ int retval = 0;
+
+ llock = simple_strtoul(buf, NULL, 10);
+ lock = (u8)(llock & 0xff);
+
+ switch (lock) {
+ case 0:
+ case 1:
+ retval = set_lock_status(slot, lock);
+ break;
+ default:
+ err ("%d is an invalid lock value\n", lock);
+ retval = -EINVAL;
+ }
+ if (retval)
+ return retval;
+ return count;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
+ .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+ .show = lock_read_file,
+ .store = lock_write_file
+};
+
/**
* release_slot - free up the memory used by a slot
* @hotplug_slot: slot to free
@@ -98,148 +188,108 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
kfree(slot);
}
+static void make_slot_name(struct slot *slot)
+{
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
+ slot->bus, slot->number);
+}
+
static int init_slots(struct controller *ctrl)
{
struct slot *slot;
- struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
- struct hotplug_slot_info *hotplug_slot_info;
- u8 number_of_slots;
- u8 slot_device;
- u32 slot_number;
- int result = -ENOMEM;
+ struct hotplug_slot_info *info;
+ int retval = -ENOMEM;
+ int i;
- number_of_slots = ctrl->num_slots;
- slot_device = ctrl->slot_device_offset;
- slot_number = ctrl->first_slot;
-
- while (number_of_slots) {
+ for (i = 0; i < ctrl->num_slots; i++) {
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
if (!slot)
goto error;
- slot->hotplug_slot =
- kzalloc(sizeof(*(slot->hotplug_slot)),
- GFP_KERNEL);
- if (!slot->hotplug_slot)
+ hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
+ if (!hotplug_slot)
goto error_slot;
- hotplug_slot = slot->hotplug_slot;
+ slot->hotplug_slot = hotplug_slot;
- hotplug_slot->info =
- kzalloc(sizeof(*(hotplug_slot->info)),
- GFP_KERNEL);
- if (!hotplug_slot->info)
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
goto error_hpslot;
- hotplug_slot_info = hotplug_slot->info;
- hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
- if (!hotplug_slot->name)
- goto error_info;
+ hotplug_slot->info = info;
- slot->ctrl = ctrl;
- slot->bus = ctrl->slot_bus;
- slot->device = slot_device;
- slot->hpc_ops = hpc_ops = ctrl->hpc_ops;
+ hotplug_slot->name = slot->name;
+ slot->hp_slot = i;
+ slot->ctrl = ctrl;
+ slot->bus = ctrl->pci_dev->subordinate->number;
+ slot->device = ctrl->slot_device_offset + i;
+ slot->hpc_ops = ctrl->hpc_ops;
slot->number = ctrl->first_slot;
- slot->hp_slot = slot_device - ctrl->slot_device_offset;
/* register this slot with the hotplug pci core */
hotplug_slot->private = slot;
hotplug_slot->release = &release_slot;
- make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
+ make_slot_name(slot);
hotplug_slot->ops = &pciehp_hotplug_slot_ops;
- hpc_ops->get_power_status(slot,
- &(hotplug_slot_info->power_status));
- hpc_ops->get_attention_status(slot,
- &(hotplug_slot_info->attention_status));
- hpc_ops->get_latch_status(slot,
- &(hotplug_slot_info->latch_status));
- hpc_ops->get_adapter_status(slot,
- &(hotplug_slot_info->adapter_status));
+ get_power_status(hotplug_slot, &info->power_status);
+ get_attention_status(hotplug_slot, &info->attention_status);
+ get_latch_status(hotplug_slot, &info->latch_status);
+ get_adapter_status(hotplug_slot, &info->adapter_status);
dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
- "slot_device_offset=%x\n",
- slot->bus, slot->device, slot->hp_slot, slot->number,
- ctrl->slot_device_offset);
- result = pci_hp_register(hotplug_slot);
- if (result) {
- err ("pci_hp_register failed with error %d\n", result);
- goto error_name;
+ "slot_device_offset=%x\n", slot->bus, slot->device,
+ slot->hp_slot, slot->number, ctrl->slot_device_offset);
+ retval = pci_hp_register(hotplug_slot);
+ if (retval) {
+ err ("pci_hp_register failed with error %d\n", retval);
+ goto error_info;
+ }
+ /* create additional sysfs entries */
+ if (EMI(ctrl->ctrlcap)) {
+ retval = sysfs_create_file(&hotplug_slot->kobj,
+ &hotplug_slot_attr_lock.attr);
+ if (retval) {
+ pci_hp_deregister(hotplug_slot);
+ err("cannot create additional sysfs entries\n");
+ goto error_info;
+ }
}
- slot->next = ctrl->slot;
- ctrl->slot = slot;
-
- number_of_slots--;
- slot_device++;
- slot_number += ctrl->slot_num_inc;
+ list_add(&slot->slot_list, &ctrl->slot_list);
}
return 0;
-
-error_name:
- kfree(hotplug_slot->name);
error_info:
- kfree(hotplug_slot_info);
+ kfree(info);
error_hpslot:
kfree(hotplug_slot);
error_slot:
kfree(slot);
error:
- return result;
-}
-
-
-static int cleanup_slots (struct controller * ctrl)
-{
- struct slot *old_slot, *next_slot;
-
- old_slot = ctrl->slot;
- ctrl->slot = NULL;
-
- while (old_slot) {
- next_slot = old_slot->next;
- pci_hp_deregister (old_slot->hotplug_slot);
- old_slot = next_slot;
- }
-
-
- return(0);
+ return retval;
}
-static int get_ctlr_slot_config(struct controller *ctrl)
+static void cleanup_slots(struct controller *ctrl)
{
- int num_ctlr_slots; /* Not needed; PCI Express has 1 slot per port*/
- int first_device_num; /* Not needed */
- int physical_slot_num;
- u8 ctrlcap;
- int rc;
+ struct list_head *tmp;
+ struct list_head *next;
+ struct slot *slot;
- rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap);
- if (rc) {
- err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
- return (-1);
+ list_for_each_safe(tmp, next, &ctrl->slot_list) {
+ slot = list_entry(tmp, struct slot, slot_list);
+ list_del(&slot->slot_list);
+ if (EMI(ctrl->ctrlcap))
+ sysfs_remove_file(&slot->hotplug_slot->kobj,
+ &hotplug_slot_attr_lock.attr);
+ pci_hp_deregister(slot->hotplug_slot);
}
-
- ctrl->num_slots = num_ctlr_slots; /* PCI Express has 1 slot per port */
- ctrl->slot_device_offset = first_device_num;
- ctrl->first_slot = physical_slot_num;
- ctrl->ctrlcap = ctrlcap;
-
- dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n",
- __FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap,
- ctrl->bus, ctrl->device);
-
- return (0);
}
-
/*
* set_attention_status - Turns the Amber LED for a slot on, off or blink
*/
@@ -378,8 +428,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
int rc;
struct controller *ctrl;
struct slot *t_slot;
- int first_device_num = 0 ; /* first PCI device number supported by this PCIE */
- int num_ctlr_slots; /* number of slots supported by this HPC */
u8 value;
struct pci_dev *pdev;
@@ -388,6 +436,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
err("%s : out of memory\n", __FUNCTION__);
goto err_out_none;
}
+ INIT_LIST_HEAD(&ctrl->slot_list);
pdev = dev->port;
ctrl->pci_dev = pdev;
@@ -400,13 +449,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
pci_set_drvdata(pdev, ctrl);
- ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
- if (!ctrl->pci_bus) {
- err("%s: out of memory\n", __FUNCTION__);
- rc = -ENOMEM;
- goto err_out_unmap_mmio_region;
- }
- memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
ctrl->bus = pdev->bus->number; /* ctrl bus */
ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */
@@ -415,26 +457,14 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
- /*
- * Save configuration headers for this and subordinate PCI buses
- */
-
- rc = get_ctlr_slot_config(ctrl);
- if (rc) {
- err(msg_initialization_err, rc);
- goto err_out_free_ctrl_bus;
- }
- first_device_num = ctrl->slot_device_offset;
- num_ctlr_slots = ctrl->num_slots;
-
/* Setup the slot information structures */
rc = init_slots(ctrl);
if (rc) {
- err(msg_initialization_err, 6);
- goto err_out_free_ctrl_slot;
+ err("%s: slot initialization failed\n", PCIE_MODULE_NAME);
+ goto err_out_release_ctlr;
}
- t_slot = pciehp_find_slot(ctrl, first_device_num);
+ t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
/* Finish setting up the hot plug ctrl device */
ctrl->next_event = 0;
@@ -447,32 +477,18 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
pciehp_ctrl_list = ctrl;
}
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
-
if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
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->ctrl_lock);
+ if (rc)
goto err_out_free_ctrl_slot;
- } else
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
}
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
-
return 0;
err_out_free_ctrl_slot:
cleanup_slots(ctrl);
-err_out_free_ctrl_bus:
- kfree(ctrl->pci_bus);
-err_out_unmap_mmio_region:
+err_out_release_ctlr:
ctrl->hpc_ops->release_ctlr(ctrl);
err_out_free_ctrl:
kfree(ctrl);
@@ -506,8 +522,6 @@ static void __exit unload_pciehpd(void)
while (ctrl) {
cleanup_slots(ctrl);
- kfree (ctrl->pci_bus);
-
ctrl->hpc_ops->release_ctlr(ctrl);
tctrl = ctrl;
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 372c63e35aa..4283ef56dbd 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -48,9 +48,8 @@ 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)
+u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
u8 getstatus;
@@ -101,9 +100,8 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
}
-u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
u8 getstatus;
@@ -143,9 +141,8 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
return rc;
}
-u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 presence_save, rc = 0;
struct event_info *taskInfo;
@@ -187,9 +184,8 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
return rc;
}
-u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
struct event_info *taskInfo;
@@ -233,35 +229,25 @@ 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->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->ctrl_lock);
+ err("%s: Issue of Slot Power Off command failed\n",
+ __FUNCTION__);
return;
}
- wait_for_ctrl_irq (ctrl);
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
pslot->hpc_ops->green_led_off(pslot);
- wait_for_ctrl_irq (ctrl);
- }
- 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->ctrl_lock);
+ 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__);
return;
}
- wait_for_ctrl_irq (ctrl);
}
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
}
/**
@@ -274,7 +260,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
static int board_added(struct slot *p_slot)
{
u8 hp_slot;
- int rc = 0;
+ int retval = 0;
struct controller *ctrl = p_slot->ctrl;
hp_slot = p_slot->device - ctrl->slot_device_offset;
@@ -283,53 +269,38 @@ static int board_added(struct slot *p_slot)
__FUNCTION__, p_slot->device,
ctrl->slot_device_offset, hp_slot);
- /* Wait for exclusive access to hardware */
- 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->ctrl_lock);
- return -1;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
+ retval = p_slot->hpc_ops->power_on_slot(p_slot);
+ if (retval)
+ return retval;
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_blink(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
/* Wait for ~1 second */
- wait_for_ctrl_irq (ctrl);
+ msleep(1000);
- /* Check link training status */
- rc = p_slot->hpc_ops->check_lnk_status(ctrl);
- if (rc) {
+ /* Check link training status */
+ retval = p_slot->hpc_ops->check_lnk_status(ctrl);
+ if (retval) {
err("%s: Failed to check link status\n", __FUNCTION__);
set_slot_off(ctrl, p_slot);
- return rc;
+ return retval;
}
/* Check for a power fault */
if (p_slot->hpc_ops->query_power_fault(p_slot)) {
dbg("%s: power fault detected\n", __FUNCTION__);
- rc = POWER_FAILURE;
+ retval = POWER_FAILURE;
goto err_exit;
}
- rc = pciehp_configure_device(p_slot);
- if (rc) {
+ retval = pciehp_configure_device(p_slot);
+ if (retval) {
err("Cannot add device 0x%x:%x\n", p_slot->bus,
- p_slot->device);
+ p_slot->device);
goto err_exit;
}
@@ -338,26 +309,16 @@ static int board_added(struct slot *p_slot)
*/
if (pcie_mch_quirk)
pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
- if (PWR_LED(ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_on(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
- }
+
return 0;
err_exit:
set_slot_off(ctrl, p_slot);
- return -1;
+ return retval;
}
-
/**
* remove_board - Turns off slot and LED's
*
@@ -366,44 +327,32 @@ static int remove_board(struct slot *p_slot)
{
u8 device;
u8 hp_slot;
- int rc;
+ int retval = 0;
struct controller *ctrl = p_slot->ctrl;
- if (pciehp_unconfigure_device(p_slot))
- return 1;
+ retval = pciehp_unconfigure_device(p_slot);
+ if (retval)
+ return retval;
device = p_slot->device;
-
hp_slot = p_slot->device - ctrl->slot_device_offset;
p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
- /* Wait for exclusive access to hardware */
- 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->ctrl_lock);
- return rc;
+ retval = p_slot->hpc_ops->power_off_slot(p_slot);
+ if (retval) {
+ err("%s: Issue of Slot Disable command failed\n",
+ __FUNCTION__);
+ return retval;
}
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
/* turn off Green LED */
p_slot->hpc_ops->green_led_off(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
return 0;
}
@@ -448,18 +397,10 @@ static void pciehp_pushbutton_thread(unsigned long slot)
dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__,
p_slot->bus, p_slot->device);
- if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+ if (pciehp_enable_slot(p_slot) &&
+ PWR_LED(p_slot->ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (p_slot->ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&p_slot->ctrl->ctrl_lock);
- }
p_slot->state = STATIC_STATE;
}
@@ -498,18 +439,10 @@ static void pciehp_surprise_rm_thread(unsigned long slot)
dbg("%s: adding bus:device(%x:%x)\n",
__FUNCTION__, p_slot->bus, p_slot->device);
- if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+ if (pciehp_enable_slot(p_slot) &&
+ PWR_LED(p_slot->ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (p_slot->ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&p_slot->ctrl->ctrl_lock);
- }
p_slot->state = STATIC_STATE;
}
@@ -620,46 +553,24 @@ static void interrupt_event_handler(struct controller *ctrl)
switch (p_slot->state) {
case BLINKINGOFF_STATE:
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_on(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)) {
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
+ if (ATTN_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->set_attention_status(p_slot, 0);
break;
case BLINKINGON_STATE:
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)){
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
+ if (ATTN_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->set_attention_status(p_slot, 0);
break;
default:
warn("Not a valid state\n");
return;
}
- info(msg_button_cancel, slot_name(p_slot));
+ info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot));
p_slot->state = STATIC_STATE;
}
/* ***********Button Pressed (No action on 1st press...) */
@@ -672,34 +583,21 @@ 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, slot_name(p_slot));
+ info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot));
} else {
/* slot is off */
dbg("slot is off\n");
p_slot->state = BLINKINGON_STATE;
- info(msg_button_on, slot_name(p_slot));
+ info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot));
}
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
/* blink green LED and turn off amber */
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_blink(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)) {
+ if (ATTN_LED(ctrl->ctrlcap))
p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
-
init_timer(&p_slot->task_event);
p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
@@ -712,21 +610,11 @@ static void interrupt_event_handler(struct controller *ctrl)
else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
if (POWER_CTRL(ctrl->ctrlcap)) {
dbg("power fault\n");
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (ATTN_LED(ctrl->ctrlcap)) {
+ if (ATTN_LED(ctrl->ctrlcap))
p_slot->hpc_ops->set_attention_status(p_slot, 1);
- wait_for_ctrl_irq (ctrl);
- }
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
}
}
/***********SURPRISE REMOVAL********************/
@@ -754,7 +642,6 @@ static void interrupt_event_handler(struct controller *ctrl)
}
}
-
int pciehp_enable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 6d3f580f266..fbc64aa2dd6 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -35,6 +35,7 @@
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/time.h>
#include "../pci.h"
#include "pciehp.h"
@@ -105,34 +106,30 @@ enum ctrl_offsets {
ROOTCTRL = offsetof(struct ctrl_reg, root_ctrl),
ROOTSTATUS = offsetof(struct ctrl_reg, root_status),
};
-static int pcie_cap_base = 0; /* Base of the PCI Express capability item structure */
-
-#define PCIE_CAP_ID(cb) ( cb + PCIECAPID )
-#define NXT_CAP_PTR(cb) ( cb + NXTCAPPTR )
-#define CAP_REG(cb) ( cb + CAPREG )
-#define DEV_CAP(cb) ( cb + DEVCAP )
-#define DEV_CTRL(cb) ( cb + DEVCTRL )
-#define DEV_STATUS(cb) ( cb + DEVSTATUS )
-#define LNK_CAP(cb) ( cb + LNKCAP )
-#define LNK_CTRL(cb) ( cb + LNKCTRL )
-#define LNK_STATUS(cb) ( cb + LNKSTATUS )
-#define SLOT_CAP(cb) ( cb + SLOTCAP )
-#define SLOT_CTRL(cb) ( cb + SLOTCTRL )
-#define SLOT_STATUS(cb) ( cb + SLOTSTATUS )
-#define ROOT_CTRL(cb) ( cb + ROOTCTRL )
-#define ROOT_STATUS(cb) ( cb + ROOTSTATUS )
-
-#define hp_register_read_word(pdev, reg , value) \
- pci_read_config_word(pdev, reg, &value)
-
-#define hp_register_read_dword(pdev, reg , value) \
- pci_read_config_dword(pdev, reg, &value)
-
-#define hp_register_write_word(pdev, reg , value) \
- pci_write_config_word(pdev, reg, value)
-
-#define hp_register_dwrite_word(pdev, reg , value) \
- pci_write_config_dword(pdev, reg, value)
+
+static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_read_config_word(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_read_config_dword(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_write_config_word(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_write_config_dword(dev, ctrl->cap_base + reg, value);
+}
/* Field definitions in PCI Express Capabilities Register */
#define CAP_VER 0x000F
@@ -196,6 +193,7 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define ATTN_LED_CTRL 0x00C0
#define PWR_LED_CTRL 0x0300
#define PWR_CTRL 0x0400
+#define EMI_CTRL 0x0800
/* Attention indicator and Power indicator states */
#define LED_ON 0x01
@@ -206,6 +204,10 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define POWER_ON 0
#define POWER_OFF 0x0400
+/* EMI Status defines */
+#define EMI_DISENGAGED 0
+#define EMI_ENGAGED 1
+
/* Field definitions in Slot Status Register */
#define ATTN_BUTTN_PRESSED 0x0001
#define PWR_FAULT_DETECTED 0x0002
@@ -214,114 +216,117 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define CMD_COMPLETED 0x0010
#define MRL_STATE 0x0020
#define PRSN_STATE 0x0040
+#define EMI_STATE 0x0080
+#define EMI_STATUS_BIT 7
static spinlock_t hpc_event_lock;
DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
-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);
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+static irqreturn_t pcie_isr(int irq, void *dev_id);
+static void start_int_poll_timer(struct controller *ctrl, int sec);
/* This is the interrupt polling timeout function. */
-static void int_poll_timeout(unsigned long lphp_ctlr)
+static void int_poll_timeout(unsigned long data)
{
- struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+ struct controller *ctrl = (struct controller *)data;
DBG_ENTER_ROUTINE
- if ( !php_ctlr ) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return;
- }
-
/* Poll for interrupt events. regs == NULL => polling */
- pcie_isr( 0, (void *)php_ctlr );
-
- init_timer(&php_ctlr->int_poll_timer);
+ pcie_isr(0, ctrl);
+ init_timer(&ctrl->poll_timer);
if (!pciehp_poll_time)
pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
- start_int_poll_timer(php_ctlr, pciehp_poll_time);
-
- return;
+ start_int_poll_timer(ctrl, pciehp_poll_time);
}
/* This function starts the interrupt polling timer. */
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+static void start_int_poll_timer(struct controller *ctrl, int sec)
{
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return;
- }
+ /* Clamp to sane value */
+ if ((sec <= 0) || (sec > 60))
+ sec = 2;
+
+ ctrl->poll_timer.function = &int_poll_timeout;
+ ctrl->poll_timer.data = (unsigned long)ctrl;
+ ctrl->poll_timer.expires = jiffies + sec * HZ;
+ add_timer(&ctrl->poll_timer);
+}
- if ( ( seconds <= 0 ) || ( seconds > 60 ) )
- seconds = 2; /* Clamp to sane value */
+static inline int pcie_wait_cmd(struct controller *ctrl)
+{
+ int retval = 0;
+ unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
+ unsigned long timeout = msecs_to_jiffies(msecs);
+ int rc;
- php_ctlr->int_poll_timer.function = &int_poll_timeout;
- php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */
- php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
- add_timer(&php_ctlr->int_poll_timer);
+ rc = wait_event_interruptible_timeout(ctrl->queue,
+ !ctrl->cmd_busy, timeout);
+ if (!rc)
+ dbg("Command not completed in 1000 msec\n");
+ else if (rc < 0) {
+ retval = -EINTR;
+ info("Command was interrupted by a signal\n");
+ }
- return;
+ return retval;
}
static int pcie_write_cmd(struct slot *slot, u16 cmd)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
int retval = 0;
u16 slot_status;
DBG_ENTER_ROUTINE
-
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+ mutex_lock(&ctrl->ctrl_lock);
+
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
- return retval;
- }
-
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+ goto out;
+ }
+
if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
- /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue
- the next command according to spec. Just print out the error message */
- dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__);
+ /* After 1 sec and CMD_COMPLETED still not set, just
+ proceed forward to issue the next command according
+ to spec. Just print out the error message */
+ dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
+ __FUNCTION__);
}
- retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE);
+ ctrl->cmd_busy = 1;
+ retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE));
if (retval) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
- return retval;
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+ goto out;
}
+ /*
+ * Wait for command completion.
+ */
+ retval = pcie_wait_cmd(ctrl);
+ out:
+ mutex_unlock(&ctrl->ctrl_lock);
DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_check_lnk_status(struct controller *ctrl)
{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
u16 lnk_status;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -340,26 +345,21 @@ static int hpc_check_lnk_status(struct controller *ctrl)
static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_ctrl;
u8 atten_led_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
- dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL %x, value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
@@ -385,27 +385,22 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
return 0;
}
-static int hpc_get_power_status(struct slot * slot, u8 *status)
+static int hpc_get_power_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_ctrl;
u8 pwr_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
- dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL %x value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
@@ -428,21 +423,15 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -454,22 +443,16 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status)
static int hpc_get_adapter_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
u8 card_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return retval;
}
card_state = (u8)((slot_status & PRSN_STATE) >> 6);
@@ -479,24 +462,18 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
return 0;
}
-static int hpc_query_power_fault(struct slot * slot)
+static int hpc_query_power_fault(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
u8 pwr_fault;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : Cannot check for power fault\n", __FUNCTION__);
+ err("%s: Cannot check for power fault\n", __FUNCTION__);
return retval;
}
pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
@@ -505,28 +482,63 @@ static int hpc_query_power_fault(struct slot * slot)
return pwr_fault;
}
-static int hpc_set_attention_status(struct slot *slot, u8 value)
+static int hpc_get_emi_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
+ u16 slot_status;
+ int retval = 0;
+
+ DBG_ENTER_ROUTINE
+
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ if (retval) {
+ err("%s : Cannot check EMI status\n", __FUNCTION__);
+ return retval;
+ }
+ *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
+
+ DBG_LEAVE_ROUTINE
+ return retval;
+}
+
+static int hpc_toggle_emi(struct slot *slot)
+{
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd = 0;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
+ if (rc) {
+ err("%s : hp_register_read_word SLOT_CTRL failed\n",
+ __FUNCTION__);
+ return rc;
}
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ slot_cmd = (slot_ctrl | EMI_CTRL);
+ if (!pciehp_poll_mode)
+ slot_cmd = slot_cmd | HP_INTR_ENABLE;
+ pcie_write_cmd(slot, slot_cmd);
+ slot->last_emi_toggle = get_seconds();
+ DBG_LEAVE_ROUTINE
+ return rc;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+ struct controller *ctrl = slot->ctrl;
+ u16 slot_cmd = 0;
+ u16 slot_ctrl;
+ int rc = 0;
+
+ DBG_ENTER_ROUTINE
+
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return rc;
}
@@ -547,7 +559,8 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return rc;
@@ -556,27 +569,16 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
static void hpc_set_green_led_on(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
@@ -585,34 +587,24 @@ static void hpc_set_green_led_on(struct slot *slot)
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
}
static void hpc_set_green_led_off(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
@@ -621,7 +613,8 @@ static void hpc_set_green_led_off(struct slot *slot)
if (!pciehp_poll_mode)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
@@ -629,27 +622,16 @@ static void hpc_set_green_led_off(struct slot *slot)
static void hpc_set_green_led_blink(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
@@ -659,126 +641,54 @@ static void hpc_set_green_led_blink(struct slot *slot)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
}
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
- int *num_ctlr_slots, /* number of slots in this HPC; only 1 in PCIE */
- int *first_device_num, /* PCI dev num of the first slot in this PCIE */
- int *physical_slot_num, /* phy slot num of the first slot in this PCIE */
- u8 *ctrlcap)
-{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
- u32 slot_cap;
- int rc = 0;
-
- DBG_ENTER_ROUTINE
-
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- *first_device_num = 0;
- *num_ctlr_slots = 1;
-
- rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
-
- if (rc) {
- err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__);
- return -1;
- }
-
- *physical_slot_num = slot_cap >> 19;
- dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num);
-
- *ctrlcap = slot_cap & 0x0000007f;
-
- DBG_LEAVE_ROUTINE
- return 0;
-}
-
static void hpc_release_ctlr(struct controller *ctrl)
{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
- struct php_ctlr_state_s *p, *p_prev;
-
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (pciehp_poll_mode) {
- del_timer(&php_ctlr->int_poll_timer);
- } else {
- if (php_ctlr->irq) {
- free_irq(php_ctlr->irq, ctrl);
- php_ctlr->irq = 0;
- }
- }
- if (php_ctlr->pci_dev)
- php_ctlr->pci_dev = NULL;
-
- spin_lock(&list_lock);
- p = php_ctlr_list_head;
- p_prev = NULL;
- while (p) {
- if (p == php_ctlr) {
- if (p_prev)
- p_prev->pnext = p->pnext;
- else
- php_ctlr_list_head = p->pnext;
- break;
- } else {
- p_prev = p;
- p = p->pnext;
- }
- }
- spin_unlock(&list_lock);
-
- kfree(php_ctlr);
+ if (pciehp_poll_mode)
+ del_timer(&ctrl->poll_timer);
+ else
+ free_irq(ctrl->pci_dev->irq, ctrl);
DBG_LEAVE_ROUTINE
-
}
static int hpc_power_on_slot(struct slot * slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl, slot_status;
-
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
/* Clear sticky power-fault bit from previous power failures */
- hp_register_read_word(php_ctlr->pci_dev,
- SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ if (retval) {
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+ return retval;
+ }
slot_status &= PWR_FAULT_DETECTED;
- if (slot_status)
- hp_register_write_word(php_ctlr->pci_dev,
- SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ if (slot_status) {
+ retval = pciehp_writew(ctrl, SLOTSTATUS, slot_status);
+ if (retval) {
+ err("%s: Cannot write to SLOTSTATUS register\n",
+ __FUNCTION__);
+ return retval;
+ }
+ }
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
@@ -798,7 +708,8 @@ static int hpc_power_on_slot(struct slot * slot)
err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
return -1;
}
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
@@ -807,29 +718,18 @@ static int hpc_power_on_slot(struct slot * slot)
static int hpc_power_off_slot(struct slot * slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
-
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
- slot->hp_slot = 0;
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
@@ -854,47 +754,25 @@ static int hpc_power_off_slot(struct slot * slot)
err("%s: Write command failed!\n", __FUNCTION__);
return -1;
}
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return retval;
}
-static irqreturn_t pcie_isr(int IRQ, void *dev_id)
+static irqreturn_t pcie_isr(int irq, void *dev_id)
{
- struct controller *ctrl = NULL;
- struct php_ctlr_state_s *php_ctlr;
- u8 schedule_flag = 0;
+ struct controller *ctrl = (struct controller *)dev_id;
u16 slot_status, intr_detect, intr_loc;
u16 temp_word;
int hp_slot = 0; /* only 1 slot per PCI Express port */
int rc = 0;
- if (!dev_id)
- return IRQ_NONE;
-
- if (!pciehp_poll_mode) {
- ctrl = dev_id;
- php_ctlr = ctrl->hpc_ctlr_handle;
- } else {
- php_ctlr = dev_id;
- ctrl = (struct controller *)php_ctlr->callback_instance_id;
- }
-
- if (!ctrl) {
- dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id);
- return IRQ_NONE;
- }
-
- if (!php_ctlr) {
- dbg("%s: php_ctlr == NULL\n", __FUNCTION__);
- return IRQ_NONE;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return IRQ_NONE;
}
@@ -910,33 +788,38 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
/* Mask Hot-plug Interrupt Enable */
if (!pciehp_poll_mode) {
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_CTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+ dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
+ __FUNCTION__, temp_word);
temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
-
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_STATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status);
+ dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
+ __FUNCTION__, slot_status);
/* Clear command complete interrupt caused by this write */
temp_word = 0x1f;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
}
@@ -945,60 +828,65 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
/*
* Command Complete Interrupt Pending
*/
+ ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue);
}
- if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED))
- schedule_flag += php_ctlr->switch_change_callback(
- hp_slot, php_ctlr->callback_instance_id);
- if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED))
- schedule_flag += php_ctlr->attention_button_callback(
- hp_slot, php_ctlr->callback_instance_id);
- if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED))
- schedule_flag += php_ctlr->presence_change_callback(
- hp_slot , php_ctlr->callback_instance_id);
- if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED))
- schedule_flag += php_ctlr->power_fault_callback(
- hp_slot, php_ctlr->callback_instance_id);
+ if (intr_loc & MRL_SENS_CHANGED)
+ pciehp_handle_switch_change(hp_slot, ctrl);
+
+ if (intr_loc & ATTN_BUTTN_PRESSED)
+ pciehp_handle_attention_button(hp_slot, ctrl);
+
+ if (intr_loc & PRSN_DETECT_CHANGED)
+ pciehp_handle_presence_change(hp_slot, ctrl);
+
+ if (intr_loc & PWR_FAULT_DETECTED)
+ pciehp_handle_power_fault(hp_slot, ctrl);
/* Clear all events after serving them */
temp_word = 0x1F;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
return IRQ_NONE;
}
/* Unmask Hot-plug Interrupt Enable */
if (!pciehp_poll_mode) {
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__);
temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_STATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
/* Clear command complete interrupt caused by this write */
temp_word = 0x1F;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS failed\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word);
+ dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
+ __FUNCTION__, temp_word);
}
return IRQ_HANDLED;
@@ -1006,27 +894,16 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed;
u32 lnk_cap;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+ retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
- err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
return retval;
}
@@ -1047,27 +924,16 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth;
u32 lnk_cap;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+ retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
- err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
return retval;
}
@@ -1109,27 +975,16 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value
static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
int retval = 0;
u16 lnk_status;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -1150,27 +1005,16 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
int retval = 0;
u16 lnk_status;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -1218,6 +1062,8 @@ static struct hpc_ops pciehp_hpc_ops = {
.get_attention_status = hpc_get_attention_status,
.get_latch_status = hpc_get_latch_status,
.get_adapter_status = hpc_get_adapter_status,
+ .get_emi_status = hpc_get_emi_status,
+ .toggle_emi = hpc_toggle_emi,
.get_max_bus_speed = hpc_get_max_lnk_speed,
.get_cur_bus_speed = hpc_get_cur_lnk_speed,
@@ -1305,38 +1151,24 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
int pcie_init(struct controller * ctrl, struct pcie_device *dev)
{
- struct php_ctlr_state_s *php_ctlr, *p;
- void *instance_id = ctrl;
int rc;
static int first = 1;
u16 temp_word;
u16 cap_reg;
u16 intr_enable = 0;
u32 slot_cap;
- int cap_base, saved_cap_base;
+ int cap_base;
u16 slot_status, slot_ctrl;
struct pci_dev *pdev;
DBG_ENTER_ROUTINE
- spin_lock_init(&list_lock);
- php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
-
- if (!php_ctlr) { /* allocate controller state data */
- err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
- goto abort;
- }
-
- memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
-
pdev = dev->port;
- php_ctlr->pci_dev = pdev; /* save pci_dev in context */
+ ctrl->pci_dev = pdev; /* save pci_dev in context */
dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
__FUNCTION__, pdev->vendor, pdev->device);
- saved_cap_base = pcie_cap_base;
-
if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
goto abort_free_ctlr;
@@ -1344,14 +1176,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
ctrl->cap_base = cap_base;
- dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base);
+ dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base);
- rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg);
+ rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
if (rc) {
- err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+ err("%s: Cannot read CAPREG register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg);
+ dbg("%s: CAPREG offset %x cap_reg %x\n",
+ __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
&& ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
@@ -1359,31 +1192,34 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
goto abort_free_ctlr;
}
- rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
+ rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
if (rc) {
- err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap);
+ dbg("%s: SLOTCAP offset %x slot_cap %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap);
if (!(slot_cap & HP_CAP)) {
dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
goto abort_free_ctlr;
}
/* For debugging purpose */
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status);
+ dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status);
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
if (first) {
spin_lock_init(&hpc_event_lock);
@@ -1405,69 +1241,64 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
/* setup wait queue */
init_waitqueue_head(&ctrl->queue);
- /* find the IRQ */
- php_ctlr->irq = dev->irq;
-
- /* Save interrupt callback info */
- php_ctlr->attention_button_callback = pciehp_handle_attention_button;
- php_ctlr->switch_change_callback = pciehp_handle_switch_change;
- php_ctlr->presence_change_callback = pciehp_handle_presence_change;
- php_ctlr->power_fault_callback = pciehp_handle_power_fault;
- php_ctlr->callback_instance_id = instance_id;
-
/* return PCI Controller Info */
- php_ctlr->slot_device_offset = 0;
- php_ctlr->num_slots = 1;
+ ctrl->slot_device_offset = 0;
+ ctrl->num_slots = 1;
+ ctrl->first_slot = slot_cap >> 19;
+ ctrl->ctrlcap = slot_cap & 0x0000007f;
/* Mask Hot-plug Interrupt Enable */
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word);
+ dbg("%s: SLOTCTRL %x value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
temp_word = 0x1F; /* Clear all events */
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- if (pciehp_poll_mode) {/* Install interrupt polling code */
- /* Install and start the interrupt polling timer */
- init_timer(&php_ctlr->int_poll_timer);
- start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */
+ if (pciehp_poll_mode) {
+ /* Install interrupt polling timer. Start with 10 sec delay */
+ init_timer(&ctrl->poll_timer);
+ start_int_poll_timer(ctrl, 10);
} else {
/* Installs the interrupt handler */
- rc = request_irq(php_ctlr->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *) ctrl);
- dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+ rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
+ MY_NAME, (void *)ctrl);
+ dbg("%s: request_irq %d for hpc%d (returns %d)\n",
+ __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc);
if (rc) {
- err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
+ err("Can't get irq %d for the hotplug controller\n",
+ ctrl->pci_dev->irq);
goto abort_free_ctlr;
}
}
-
dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_irq;
}
@@ -1491,21 +1322,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
}
/* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
goto abort_free_irq;
}
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
temp_word = 0x1F; /* Clear all events */
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
@@ -1518,24 +1349,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
goto abort_disable_intr;
}
- /* Add this HPC instance into the HPC list */
- spin_lock(&list_lock);
- if (php_ctlr_list_head == 0) {
- php_ctlr_list_head = php_ctlr;
- p = php_ctlr_list_head;
- p->pnext = NULL;
- } else {
- p = php_ctlr_list_head;
-
- while (p->pnext)
- p = p->pnext;
-
- p->pnext = php_ctlr;
- }
- spin_unlock(&list_lock);
-
ctlr_seq_num++;
- ctrl->hpc_ctlr_handle = php_ctlr;
ctrl->hpc_ops = &pciehp_hpc_ops;
DBG_LEAVE_ROUTINE
@@ -1543,24 +1357,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
/* We end up here for the many possible ways to fail this API. */
abort_disable_intr:
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (!rc) {
temp_word &= ~(intr_enable | HP_INTR_ENABLE);
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
}
if (rc)
err("%s : disabling interrupts failed\n", __FUNCTION__);
abort_free_irq:
if (pciehp_poll_mode)
- del_timer_sync(&php_ctlr->int_poll_timer);
+ del_timer_sync(&ctrl->poll_timer);
else
- free_irq(php_ctlr->irq, ctrl);
+ free_irq(ctrl->pci_dev->irq, ctrl);
abort_free_ctlr:
- pcie_cap_base = saved_cap_base;
- kfree(php_ctlr);
-abort:
DBG_LEAVE_ROUTINE
return -1;
}
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
index b771196a654..3009193f005 100644
--- a/drivers/pci/hotplug/rpaphp_slot.c
+++ b/drivers/pci/hotplug/rpaphp_slot.c
@@ -47,21 +47,11 @@ static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf)
return retval;
}
-static struct hotplug_slot_attribute hotplug_slot_attr_location = {
+static struct hotplug_slot_attribute php_attr_location = {
.attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO},
.show = location_read_file,
};
-static void rpaphp_sysfs_add_attr_location (struct hotplug_slot *slot)
-{
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_location.attr);
-}
-
-static void rpaphp_sysfs_remove_attr_location (struct hotplug_slot *slot)
-{
- sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_location.attr);
-}
-
/* free up the memory used by a slot */
static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
{
@@ -145,7 +135,7 @@ int rpaphp_deregister_slot(struct slot *slot)
list_del(&slot->rpaphp_slot_list);
/* remove "phy_location" file */
- rpaphp_sysfs_remove_attr_location(php_slot);
+ sysfs_remove_file(&php_slot->kobj, &php_attr_location.attr);
retval = pci_hp_deregister(php_slot);
if (retval)
@@ -160,36 +150,45 @@ EXPORT_SYMBOL_GPL(rpaphp_deregister_slot);
int rpaphp_register_slot(struct slot *slot)
{
+ struct hotplug_slot *php_slot = slot->hotplug_slot;
int retval;
dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n",
__FUNCTION__, slot->dn->full_name, slot->index, slot->name,
slot->power_domain, slot->type);
+
/* should not try to register the same slot twice */
- if (is_registered(slot)) { /* should't be here */
+ if (is_registered(slot)) {
err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name);
- rpaphp_release_slot(slot->hotplug_slot);
- return -EAGAIN;
+ retval = -EAGAIN;
+ goto register_fail;
}
- retval = pci_hp_register(slot->hotplug_slot);
+
+ retval = pci_hp_register(php_slot);
if (retval) {
err("pci_hp_register failed with error %d\n", retval);
- rpaphp_release_slot(slot->hotplug_slot);
- return retval;
+ goto register_fail;
}
-
- /* create "phy_locatoin" file */
- rpaphp_sysfs_add_attr_location(slot->hotplug_slot);
- /* add slot to our internal list */
- dbg("%s adding slot[%s] to rpaphp_slot_list\n",
- __FUNCTION__, slot->name);
+ /* create "phy_location" file */
+ retval = sysfs_create_file(&php_slot->kobj, &php_attr_location.attr);
+ if (retval) {
+ err("sysfs_create_file failed with error %d\n", retval);
+ goto sysfs_fail;
+ }
+ /* add slot to our internal list */
list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
info("Slot [%s](PCI location=%s) registered\n", slot->name,
slot->location);
num_slots++;
return 0;
+
+sysfs_fail:
+ pci_hp_deregister(php_slot);
+register_fail:
+ rpaphp_release_slot(php_slot);
+ return retval;
}
int rpaphp_get_power_status(struct slot *slot, u8 * value)
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index 5d188c55838..78cf0711d1f 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -28,6 +28,8 @@
#include <asm/sn/sn_feature_sets.h>
#include <asm/sn/sn_sal.h>
#include <asm/sn/types.h>
+#include <linux/acpi.h>
+#include <asm/sn/acpi.h>
#include "../pci.h"
@@ -35,14 +37,17 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");
-#define PCIIO_ASIC_TYPE_TIOCA 4
+
+/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */
#define PCI_SLOT_ALREADY_UP 2 /* slot already up */
#define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */
#define PCI_L1_ERR 7 /* L1 console command error */
#define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */
+
+
+#define PCIIO_ASIC_TYPE_TIOCA 4
#define PCI_L1_QSIZE 128 /* our L1 message buffer size */
#define SN_MAX_HP_SLOTS 32 /* max hotplug slots */
-#define SGI_HOTPLUG_PROM_REV 0x0430 /* Min. required PROM version */
#define SN_SLOT_NAME_SIZE 33 /* size of name string */
/* internal list head */
@@ -227,7 +232,7 @@ static void sn_bus_free_data(struct pci_dev *dev)
}
static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
- int device_num)
+ int device_num, char **ssdt)
{
struct slot *slot = bss_hotplug_slot->private;
struct pcibus_info *pcibus_info;
@@ -240,7 +245,8 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
* Power-on and initialize the slot in the SN
* PCI infrastructure.
*/
- rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp);
+ rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt);
+
if (rc == PCI_SLOT_ALREADY_UP) {
dev_dbg(slot->pci_bus->self, "is already active\n");
@@ -335,6 +341,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
int func, num_funcs;
int new_ppb = 0;
int rc;
+ char *ssdt = NULL;
void pcibios_fixup_device_resources(struct pci_dev *);
/* Serialize the Linux PCI infrastructure */
@@ -342,14 +349,29 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
/*
* Power-on and initialize the slot in the SN
- * PCI infrastructure.
+ * PCI infrastructure. Also, retrieve the ACPI SSDT
+ * table for the slot (if ACPI capable PROM).
*/
- rc = sn_slot_enable(bss_hotplug_slot, slot->device_num);
+ rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt);
if (rc) {
mutex_unlock(&sn_hotplug_mutex);
return rc;
}
+ if (ssdt)
+ ssdt = __va(ssdt);
+ /* Add the new SSDT for the slot to the ACPI namespace */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+ acpi_status ret;
+
+ ret = acpi_load_table((struct acpi_table_header *)ssdt);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n",
+ __FUNCTION__, ret);
+ /* try to continue on */
+ }
+ }
+
num_funcs = pci_scan_slot(slot->pci_bus,
PCI_DEVFN(slot->device_num + 1, 0));
if (!num_funcs) {
@@ -374,7 +396,10 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
* pdi_host_pcidev_info).
*/
pcibios_fixup_device_resources(dev);
- sn_pci_fixup_slot(dev);
+ if (SN_ACPI_BASE_SUPPORT())
+ sn_acpi_slot_fixup(dev);
+ else
+ sn_io_slot_fixup(dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
unsigned char sec_bus;
pci_read_config_byte(dev, PCI_SECONDARY_BUS,
@@ -388,6 +413,63 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
}
}
+ /*
+ * Add the slot's devices to the ACPI infrastructure */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+ unsigned long adr;
+ struct acpi_device *pdevice;
+ struct acpi_device *device;
+ acpi_handle phandle;
+ acpi_handle chandle = NULL;
+ acpi_handle rethandle;
+ acpi_status ret;
+
+ phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+ if (acpi_bus_get_device(phandle, &pdevice)) {
+ dev_dbg(slot->pci_bus->self,
+ "no parent device, assuming NULL\n");
+ pdevice = NULL;
+ }
+
+ /*
+ * Walk the rootbus node's immediate children looking for
+ * the slot's device node(s). There can be more than
+ * one for multifunction devices.
+ */
+ for (;;) {
+ rethandle = NULL;
+ ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+ phandle, chandle,
+ &rethandle);
+
+ if (ret == AE_NOT_FOUND || rethandle == NULL)
+ break;
+
+ chandle = rethandle;
+
+ ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR,
+ NULL, &adr);
+
+ if (ACPI_SUCCESS(ret) &&
+ (adr>>16) == (slot->device_num + 1)) {
+
+ ret = acpi_bus_add(&device, pdevice, chandle,
+ ACPI_BUS_TYPE_DEVICE);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_bus_add "
+ "failed (0x%x) for slot %d "
+ "func %d\n", __FUNCTION__,
+ ret, (int)(adr>>16),
+ (int)(adr&0xffff));
+ /* try to continue on */
+ } else {
+ acpi_bus_start(device);
+ }
+ }
+ }
+ }
+
/* Call the driver for the new device */
pci_bus_add_devices(slot->pci_bus);
/* Call the drivers for the new devices subordinate to PPB */
@@ -412,6 +494,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
struct pci_dev *dev;
int func;
int rc;
+ acpi_owner_id ssdt_id = 0;
/* Acquire update access to the bus */
mutex_lock(&sn_hotplug_mutex);
@@ -422,6 +505,52 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
if (rc)
goto leaving;
+ /* free the ACPI resources for the slot */
+ if (SN_ACPI_BASE_SUPPORT() &&
+ PCI_CONTROLLER(slot->pci_bus)->acpi_handle) {
+ unsigned long adr;
+ struct acpi_device *device;
+ acpi_handle phandle;
+ acpi_handle chandle = NULL;
+ acpi_handle rethandle;
+ acpi_status ret;
+
+ /* Get the rootbus node pointer */
+ phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+ /*
+ * Walk the rootbus node's immediate children looking for
+ * the slot's device node(s). There can be more than
+ * one for multifunction devices.
+ */
+ for (;;) {
+ rethandle = NULL;
+ ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+ phandle, chandle,
+ &rethandle);
+
+ if (ret == AE_NOT_FOUND || rethandle == NULL)
+ break;
+
+ chandle = rethandle;
+
+ ret = acpi_evaluate_integer(chandle,
+ METHOD_NAME__ADR,
+ NULL, &adr);
+ if (ACPI_SUCCESS(ret) &&
+ (adr>>16) == (slot->device_num + 1)) {
+ /* retain the owner id */
+ acpi_get_id(chandle, &ssdt_id);
+
+ ret = acpi_bus_get_device(chandle,
+ &device);
+ if (ACPI_SUCCESS(ret))
+ acpi_bus_trim(device, 1);
+ }
+ }
+
+ }
+
/* Free the SN resources assigned to the Linux device.*/
for (func = 0; func < 8; func++) {
dev = pci_get_slot(slot->pci_bus,
@@ -434,6 +563,18 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
}
}
+ /* Remove the SSDT for the slot from the ACPI namespace */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {
+ acpi_status ret;
+ ret = acpi_unload_table_id(ssdt_id);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_unload_table_id "
+ "failed (0x%x) for id %d\n",
+ __FUNCTION__, ret, ssdt_id);
+ /* try to continue on */
+ }
+ }
+
/* free the collected sysdata pointers */
sn_bus_free_sysdata();
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 50757695844..01d31a1f697 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -47,11 +47,17 @@ extern int shpchp_poll_time;
extern int shpchp_debug;
extern struct workqueue_struct *shpchp_wq;
-/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
-#define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+#define dbg(format, arg...) \
+ do { \
+ if (shpchp_debug) \
+ printk("%s: " format, MY_NAME , ## arg); \
+ } while (0)
+#define err(format, arg...) \
+ printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) \
+ printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) \
+ printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
#define SLOT_NAME_SIZE 10
struct slot {
@@ -83,34 +89,27 @@ struct event_info {
struct controller {
struct mutex crit_sect; /* critical section mutex */
struct mutex cmd_lock; /* command 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 */
struct pci_dev *pci_dev;
struct list_head slot_list;
struct hpc_ops *hpc_ops;
wait_queue_head_t queue; /* sleep & wake process */
- u8 bus;
- u8 device;
- u8 function;
u8 slot_device_offset;
- u8 add_support;
u32 pcix_misc2_reg; /* for amd pogo errata */
- enum pci_bus_speed speed;
u32 first_slot; /* First physical slot number */
- u8 slot_bus; /* Bus where the slots handled by this controller sit */
u32 cap_offset;
unsigned long mmio_base;
unsigned long mmio_size;
+ void __iomem *creg;
+ struct timer_list poll_timer;
};
-
/* Define AMD SHPC ID */
-#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
+#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
#define PCI_DEVICE_ID_AMD_POGO_7458 0x7458
/* AMD PCIX bridge registers */
-
#define PCIX_MEM_BASE_LIMIT_OFFSET 0x1C
#define PCIX_MISCII_OFFSET 0x48
#define PCIX_MISC_BRIDGE_ERRORS_OFFSET 0x80
@@ -145,8 +144,6 @@ struct controller {
#define POWERON_STATE 3
#define POWEROFF_STATE 4
-#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400
-
/* Error messages */
#define INTERLOCK_OPEN 0x00000002
#define ADD_NOT_SUPPORTED 0x00000003
@@ -158,50 +155,32 @@ struct controller {
#define WRONG_BUS_FREQUENCY 0x0000000D
#define POWER_FAILURE 0x0000000E
-#define REMOVE_NOT_SUPPORTED 0x00000003
-
-#define DISABLE_CARD 1
-
-/*
- * error Messages
- */
-#define msg_initialization_err "Initialization failure, error=%d\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"
-
-/* sysfs functions for the hotplug controller info */
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);
-
-extern u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id);
-extern u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id);
-extern u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id);
-extern u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id);
-
-/* pci functions */
-extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
-extern int shpchp_configure_device(struct slot *p_slot);
-extern int shpchp_unconfigure_device(struct slot *p_slot);
-extern void shpchp_remove_ctrl_files(struct controller *ctrl);
-extern void cleanup_slots(struct controller *ctrl);
-extern void queue_pushbutton_work(struct work_struct *work);
-
+extern void shpchp_remove_ctrl_files(struct controller *ctrl);
+extern int shpchp_sysfs_enable_slot(struct slot *slot);
+extern int shpchp_sysfs_disable_slot(struct slot *slot);
+extern u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
+extern u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
+extern u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
+extern u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
+extern int shpchp_configure_device(struct slot *p_slot);
+extern int shpchp_unconfigure_device(struct slot *p_slot);
+extern void cleanup_slots(struct controller *ctrl);
+extern void queue_pushbutton_work(struct work_struct *work);
+extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
#ifdef CONFIG_ACPI
static inline int get_hp_params_from_firmware(struct pci_dev *dev,
- struct hotplug_params *hpp)
+ struct hotplug_params *hpp)
{
if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp)))
return -ENODEV;
return 0;
}
-#define get_hp_hw_control_from_firmware(pdev) \
- do { \
- if (DEVICE_ACPI_HANDLE(&(pdev->dev))) \
- acpi_run_oshp(DEVICE_ACPI_HANDLE(&(pdev->dev))); \
+#define get_hp_hw_control_from_firmware(pdev) \
+ do { \
+ if (DEVICE_ACPI_HANDLE(&(pdev->dev))) \
+ acpi_run_oshp(DEVICE_ACPI_HANDLE(&(pdev->dev)));\
} while (0)
#else
#define get_hp_params_from_firmware(dev, hpp) (-ENODEV)
@@ -222,108 +201,40 @@ struct ctrl_reg {
volatile u32 serr_loc;
volatile u32 serr_intr_enable;
volatile u32 slot1;
- volatile u32 slot2;
- volatile u32 slot3;
- volatile u32 slot4;
- volatile u32 slot5;
- volatile u32 slot6;
- volatile u32 slot7;
- volatile u32 slot8;
- volatile u32 slot9;
- volatile u32 slot10;
- volatile u32 slot11;
- volatile u32 slot12;
} __attribute__ ((packed));
/* offsets to the controller registers based on the above structure layout */
enum ctrl_offsets {
- BASE_OFFSET = offsetof(struct ctrl_reg, base_offset),
- SLOT_AVAIL1 = offsetof(struct ctrl_reg, slot_avail1),
- SLOT_AVAIL2 = offsetof(struct ctrl_reg, slot_avail2),
- SLOT_CONFIG = offsetof(struct ctrl_reg, slot_config),
- SEC_BUS_CONFIG = offsetof(struct ctrl_reg, sec_bus_config),
- MSI_CTRL = offsetof(struct ctrl_reg, msi_ctrl),
- PROG_INTERFACE = offsetof(struct ctrl_reg, prog_interface),
- CMD = offsetof(struct ctrl_reg, cmd),
- CMD_STATUS = offsetof(struct ctrl_reg, cmd_status),
- INTR_LOC = offsetof(struct ctrl_reg, intr_loc),
- SERR_LOC = offsetof(struct ctrl_reg, serr_loc),
- SERR_INTR_ENABLE = offsetof(struct ctrl_reg, serr_intr_enable),
- SLOT1 = offsetof(struct ctrl_reg, slot1),
- SLOT2 = offsetof(struct ctrl_reg, slot2),
- SLOT3 = offsetof(struct ctrl_reg, slot3),
- SLOT4 = offsetof(struct ctrl_reg, slot4),
- SLOT5 = offsetof(struct ctrl_reg, slot5),
- SLOT6 = offsetof(struct ctrl_reg, slot6),
- SLOT7 = offsetof(struct ctrl_reg, slot7),
- SLOT8 = offsetof(struct ctrl_reg, slot8),
- SLOT9 = offsetof(struct ctrl_reg, slot9),
- SLOT10 = offsetof(struct ctrl_reg, slot10),
- SLOT11 = offsetof(struct ctrl_reg, slot11),
- SLOT12 = offsetof(struct ctrl_reg, slot12),
-};
-typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id);
-struct php_ctlr_state_s {
- struct php_ctlr_state_s *pnext;
- struct pci_dev *pci_dev;
- unsigned int irq;
- unsigned long flags; /* spinlock's */
- u32 slot_device_offset;
- u32 num_slots;
- struct timer_list int_poll_timer; /* Added for poll event */
- php_intr_callback_t attention_button_callback;
- php_intr_callback_t switch_change_callback;
- php_intr_callback_t presence_change_callback;
- php_intr_callback_t power_fault_callback;
- void *callback_instance_id;
- void __iomem *creg; /* Ptr to controller register space */
+ BASE_OFFSET = offsetof(struct ctrl_reg, base_offset),
+ SLOT_AVAIL1 = offsetof(struct ctrl_reg, slot_avail1),
+ SLOT_AVAIL2 = offsetof(struct ctrl_reg, slot_avail2),
+ SLOT_CONFIG = offsetof(struct ctrl_reg, slot_config),
+ SEC_BUS_CONFIG = offsetof(struct ctrl_reg, sec_bus_config),
+ MSI_CTRL = offsetof(struct ctrl_reg, msi_ctrl),
+ PROG_INTERFACE = offsetof(struct ctrl_reg, prog_interface),
+ CMD = offsetof(struct ctrl_reg, cmd),
+ CMD_STATUS = offsetof(struct ctrl_reg, cmd_status),
+ INTR_LOC = offsetof(struct ctrl_reg, intr_loc),
+ SERR_LOC = offsetof(struct ctrl_reg, serr_loc),
+ SERR_INTR_ENABLE = offsetof(struct ctrl_reg, serr_intr_enable),
+ SLOT1 = offsetof(struct ctrl_reg, slot1),
};
-/* Inline functions */
-
-/* Inline functions to check the sanity of a pointer that is passed to us */
-static inline int slot_paranoia_check (struct slot *slot, const char *function)
+static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot)
{
- if (!slot) {
- dbg("%s - slot == NULL", function);
- return -1;
- }
- if (!slot->hotplug_slot) {
- dbg("%s - slot->hotplug_slot == NULL!", function);
- return -1;
- }
- return 0;
-}
-
-static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
-{
- struct slot *slot;
-
- if (!hotplug_slot) {
- dbg("%s - hotplug_slot == NULL\n", function);
- return NULL;
- }
-
- slot = (struct slot *)hotplug_slot->private;
- if (slot_paranoia_check (slot, function))
- return NULL;
- return slot;
+ return hotplug_slot->private;
}
-static inline struct slot *shpchp_find_slot (struct controller *ctrl, u8 device)
+static inline struct slot *shpchp_find_slot(struct controller *ctrl, u8 device)
{
struct slot *slot;
- if (!ctrl)
- return NULL;
-
list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
if (slot->device == device)
return slot;
}
err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device);
-
return NULL;
}
@@ -400,44 +311,27 @@ static inline void amd_pogo_errata_restore_misc_reg(struct slot *p_slot)
pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp);
}
-enum php_ctlr_type {
- PCI,
- ISA,
- ACPI
-};
-
-int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
-
-int shpc_get_ctlr_slot_config( struct controller *ctrl,
- int *num_ctlr_slots,
- int *first_device_num,
- int *physical_slot_num,
- int *updown,
- int *flags);
-
struct hpc_ops {
- int (*power_on_slot ) (struct slot *slot);
- int (*slot_enable ) (struct slot *slot);
- int (*slot_disable ) (struct slot *slot);
- int (*set_bus_speed_mode) (struct slot *slot, enum pci_bus_speed speed);
- int (*get_power_status) (struct slot *slot, u8 *status);
- int (*get_attention_status) (struct slot *slot, u8 *status);
- int (*set_attention_status) (struct slot *slot, u8 status);
- int (*get_latch_status) (struct slot *slot, u8 *status);
- int (*get_adapter_status) (struct slot *slot, u8 *status);
-
- int (*get_max_bus_speed) (struct slot *slot, enum pci_bus_speed *speed);
- int (*get_cur_bus_speed) (struct slot *slot, enum pci_bus_speed *speed);
- int (*get_adapter_speed) (struct slot *slot, enum pci_bus_speed *speed);
- int (*get_mode1_ECC_cap) (struct slot *slot, u8 *mode);
- int (*get_prog_int) (struct slot *slot, u8 *prog_int);
-
- int (*query_power_fault) (struct slot *slot);
- void (*green_led_on) (struct slot *slot);
- void (*green_led_off) (struct slot *slot);
- void (*green_led_blink) (struct slot *slot);
- void (*release_ctlr) (struct controller *ctrl);
- int (*check_cmd_status) (struct controller *ctrl);
+ int (*power_on_slot)(struct slot *slot);
+ int (*slot_enable)(struct slot *slot);
+ int (*slot_disable)(struct slot *slot);
+ int (*set_bus_speed_mode)(struct slot *slot, enum pci_bus_speed speed);
+ int (*get_power_status)(struct slot *slot, u8 *status);
+ int (*get_attention_status)(struct slot *slot, u8 *status);
+ int (*set_attention_status)(struct slot *slot, u8 status);
+ int (*get_latch_status)(struct slot *slot, u8 *status);
+ int (*get_adapter_status)(struct slot *slot, u8 *status);
+ int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_adapter_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_mode1_ECC_cap)(struct slot *slot, u8 *mode);
+ int (*get_prog_int)(struct slot *slot, u8 *prog_int);
+ int (*query_power_fault)(struct slot *slot);
+ void (*green_led_on)(struct slot *slot);
+ void (*green_led_off)(struct slot *slot);
+ void (*green_led_blink)(struct slot *slot);
+ void (*release_ctlr)(struct controller *ctrl);
+ int (*check_cmd_status)(struct controller *ctrl);
};
#endif /* _SHPCHP_H */
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 4eac85b3d90..5f4bc08a633 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -104,23 +104,6 @@ static void make_slot_name(struct slot *slot)
slot->bus, slot->number);
}
-
-
-
-static int
-shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun,
- u8 busnum, u8 devnum)
-{
- int offset = devnum - ctrl->slot_device_offset;
-
- dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__,
- ctrl->slot_num_inc, offset);
- *sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc *offset);
- return 0;
-}
-
-
-
static int init_slots(struct controller *ctrl)
{
struct slot *slot;
@@ -128,7 +111,6 @@ static int init_slots(struct controller *ctrl)
struct hotplug_slot_info *info;
int retval = -ENOMEM;
int i;
- u32 sun;
for (i = 0; i < ctrl->num_slots; i++) {
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
@@ -149,16 +131,11 @@ static int init_slots(struct controller *ctrl)
slot->hp_slot = i;
slot->ctrl = ctrl;
- slot->bus = ctrl->slot_bus;
+ slot->bus = ctrl->pci_dev->subordinate->number;
slot->device = ctrl->slot_device_offset + i;
slot->hpc_ops = ctrl->hpc_ops;
+ slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i);
mutex_init(&slot->lock);
-
- if (shpchprm_get_physical_slot_number(ctrl, &sun,
- slot->bus, slot->device))
- goto error_info;
-
- slot->number = sun;
INIT_DELAYED_WORK(&slot->work, queue_pushbutton_work);
/* register this slot with the hotplug pci core */
@@ -211,42 +188,12 @@ void cleanup_slots(struct controller *ctrl)
}
}
-static int get_ctlr_slot_config(struct controller *ctrl)
-{
- int num_ctlr_slots;
- int first_device_num;
- int physical_slot_num;
- int updown;
- int rc;
- int flags;
-
- rc = shpc_get_ctlr_slot_config(ctrl, &num_ctlr_slots,
- &first_device_num, &physical_slot_num,
- &updown, &flags);
- if (rc) {
- err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n",
- __FUNCTION__, ctrl->bus, ctrl->device);
- return -1;
- }
-
- ctrl->num_slots = num_ctlr_slots;
- ctrl->slot_device_offset = first_device_num;
- ctrl->first_slot = physical_slot_num;
- ctrl->slot_num_inc = updown; /* either -1 or 1 */
-
- dbg("%s: num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d "
- "(%x:%x)\n", __FUNCTION__, num_ctlr_slots, first_device_num,
- physical_slot_num, updown, ctrl->bus, ctrl->device);
-
- return 0;
-}
-
/*
* set_attention_status - Turns the Amber LED for a slot on, off or blink
*/
static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -258,7 +205,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
static int enable_slot (struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -267,7 +214,7 @@ static int enable_slot (struct hotplug_slot *hotplug_slot)
static int disable_slot (struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -276,7 +223,7 @@ static int disable_slot (struct hotplug_slot *hotplug_slot)
static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -290,7 +237,7 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -304,7 +251,7 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -318,7 +265,7 @@ static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -332,7 +279,7 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -344,7 +291,7 @@ static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -358,7 +305,7 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -385,9 +332,6 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int rc;
struct controller *ctrl;
- struct slot *t_slot;
- int first_device_num; /* first PCI device number */
- int num_ctlr_slots; /* number of slots implemented */
if (!is_shpc_capable(pdev))
return -ENODEV;
@@ -408,47 +352,13 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, ctrl);
- ctrl->bus = pdev->bus->number;
- ctrl->slot_bus = pdev->subordinate->number;
- ctrl->device = PCI_SLOT(pdev->devfn);
- ctrl->function = PCI_FUNC(pdev->devfn);
-
- dbg("ctrl bus=0x%x, device=%x, function=%x, irq=%x\n",
- ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
-
- /*
- * Save configuration headers for this and subordinate PCI buses
- */
- rc = get_ctlr_slot_config(ctrl);
- if (rc) {
- err(msg_initialization_err, rc);
- goto err_out_release_ctlr;
- }
- first_device_num = ctrl->slot_device_offset;
- num_ctlr_slots = ctrl->num_slots;
-
- ctrl->add_support = 1;
-
/* Setup the slot information structures */
rc = init_slots(ctrl);
if (rc) {
- err(msg_initialization_err, 6);
+ err("%s: slot initialization failed\n", SHPC_MODULE_NAME);
goto err_out_release_ctlr;
}
- /* Now hpc_functions (slot->hpc_ops->functions) are ready */
- t_slot = shpchp_find_slot(ctrl, first_device_num);
-
- /* Check for operation bus speed */
- rc = t_slot->hpc_ops->get_cur_bus_speed(t_slot, &ctrl->speed);
- dbg("%s: t_slot->hp_slot %x\n", __FUNCTION__,t_slot->hp_slot);
-
- if (rc || ctrl->speed == PCI_SPEED_UNKNOWN) {
- err(SHPC_MODULE_NAME ": Can't get current bus speed. "
- "Set to 33MHz PCI.\n");
- ctrl->speed = PCI_SPEED_33MHz;
- }
-
rc = shpchp_create_ctrl_files(ctrl);
if (rc)
goto err_cleanup_slots;
@@ -491,10 +401,6 @@ static int __init shpcd_init(void)
{
int retval = 0;
-#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
- shpchp_poll_mode = 1;
-#endif
-
retval = pci_register_driver(&shpc_driver);
dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index 158ac783609..b746bd265bc 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -57,15 +57,14 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
return 0;
}
-u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
+u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u32 event_type;
/* Attention Button Change */
dbg("shpchp: Attention button interrupt received.\n");
-
+
p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
@@ -81,9 +80,8 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
}
-u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
+u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 getstatus;
u32 event_type;
@@ -120,9 +118,8 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
return 1;
}
-u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
+u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u32 event_type;
@@ -131,7 +128,7 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
- /*
+ /*
* Save the presence state
*/
p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
@@ -154,9 +151,8 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
return 1;
}
-u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
+u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u32 event_type;
@@ -188,12 +184,12 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
return 1;
}
-/* The following routines constitute the bulk of the
+/* The following routines constitute the bulk of the
hotplug controller logic
*/
static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
enum pci_bus_speed speed)
-{
+{
int rc = 0;
dbg("%s: change to speed %d\n", __FUNCTION__, speed);
@@ -208,7 +204,7 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
static int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
enum pci_bus_speed msp)
-{
+{
int rc = 0;
/*
@@ -261,23 +257,23 @@ static int board_added(struct slot *p_slot)
err("%s: Failed to power on slot\n", __FUNCTION__);
return -1;
}
-
+
if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
if (slots_not_empty)
return WRONG_BUS_FREQUENCY;
-
+
if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
return WRONG_BUS_FREQUENCY;
}
-
+
/* turn on board, blink green LED, turn off Amber LED */
if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
return rc;
}
}
-
+
rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp);
if (rc) {
err("%s: Can't get adapter speed or bus mode mismatch\n",
@@ -382,7 +378,7 @@ static int remove_board(struct slot *p_slot)
err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
return rc;
}
-
+
rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
if (rc) {
err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
@@ -497,10 +493,12 @@ static void handle_button_press_event(struct slot *p_slot)
p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (getstatus) {
p_slot->state = BLINKINGOFF_STATE;
- info(msg_button_off, p_slot->name);
+ info("PCI slot #%s - powering off due to button "
+ "press.\n", p_slot->name);
} else {
p_slot->state = BLINKINGON_STATE;
- info(msg_button_on, p_slot->name);
+ info("PCI slot #%s - powering on due to button "
+ "press.\n", p_slot->name);
}
/* blink green LED and turn off amber */
p_slot->hpc_ops->green_led_blink(p_slot);
@@ -523,7 +521,8 @@ static void handle_button_press_event(struct slot *p_slot)
else
p_slot->hpc_ops->green_led_off(p_slot);
p_slot->hpc_ops->set_attention_status(p_slot, 0);
- info(msg_button_cancel, p_slot->name);
+ info("PCI slot #%s - action canceled due to button press\n",
+ p_slot->name);
p_slot->state = STATIC_STATE;
break;
case POWEROFF_STATE:
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 83a5226ba9e..5183a45d45b 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -35,38 +35,6 @@
#include "shpchp.h"
-#ifdef DEBUG
-#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */
-#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */
-#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */
-#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */
-#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
-#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
-/* Redefine this flagword to set debug level */
-#define DEBUG_LEVEL DBG_K_STANDARD
-
-#define DEFINE_DBG_BUFFER char __dbg_str_buf[256];
-
-#define DBG_PRINT( dbg_flags, args... ) \
- do { \
- if ( DEBUG_LEVEL & ( dbg_flags ) ) \
- { \
- int len; \
- len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
- __FILE__, __LINE__, __FUNCTION__ ); \
- sprintf( __dbg_str_buf + len, args ); \
- printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
- } \
- } while (0)
-
-#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
-#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
-#else
-#define DEFINE_DBG_BUFFER
-#define DBG_ENTER_ROUTINE
-#define DBG_LEAVE_ROUTINE
-#endif /* DEBUG */
-
/* Slot Available Register I field definition */
#define SLOT_33MHZ 0x0000001f
#define SLOT_66MHZ_PCIX 0x00001f00
@@ -211,45 +179,40 @@
#define SLOT_EVENT_LATCH 0x2
#define SLOT_SERR_INT_MASK 0x3
-DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
-static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
-static int ctlr_seq_num = 0; /* Controller sequenc # */
-static spinlock_t list_lock;
-
static atomic_t shpchp_num_controllers = ATOMIC_INIT(0);
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 void start_int_poll_timer(struct controller *ctrl, int sec);
static int hpc_check_cmd_status(struct controller *ctrl);
static inline u8 shpc_readb(struct controller *ctrl, int reg)
{
- return readb(ctrl->hpc_ctlr_handle->creg + reg);
+ return readb(ctrl->creg + reg);
}
static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val)
{
- writeb(val, ctrl->hpc_ctlr_handle->creg + reg);
+ writeb(val, ctrl->creg + reg);
}
static inline u16 shpc_readw(struct controller *ctrl, int reg)
{
- return readw(ctrl->hpc_ctlr_handle->creg + reg);
+ return readw(ctrl->creg + reg);
}
static inline void shpc_writew(struct controller *ctrl, int reg, u16 val)
{
- writew(val, ctrl->hpc_ctlr_handle->creg + reg);
+ writew(val, ctrl->creg + reg);
}
static inline u32 shpc_readl(struct controller *ctrl, int reg)
{
- return readl(ctrl->hpc_ctlr_handle->creg + reg);
+ return readl(ctrl->creg + reg);
}
static inline void shpc_writel(struct controller *ctrl, int reg, u32 val)
{
- writel(val, ctrl->hpc_ctlr_handle->creg + reg);
+ writel(val, ctrl->creg + reg);
}
static inline int shpc_indirect_read(struct controller *ctrl, int index,
@@ -268,38 +231,33 @@ static inline int shpc_indirect_read(struct controller *ctrl, int index,
/*
* This is the interrupt polling timeout function.
*/
-static void int_poll_timeout(unsigned long lphp_ctlr)
+static void int_poll_timeout(unsigned long data)
{
- struct php_ctlr_state_s *php_ctlr =
- (struct php_ctlr_state_s *)lphp_ctlr;
-
- DBG_ENTER_ROUTINE
+ struct controller *ctrl = (struct controller *)data;
/* Poll for interrupt events. regs == NULL => polling */
- shpc_isr(0, php_ctlr->callback_instance_id);
+ shpc_isr(0, ctrl);
- init_timer(&php_ctlr->int_poll_timer);
+ init_timer(&ctrl->poll_timer);
if (!shpchp_poll_time)
shpchp_poll_time = 2; /* default polling interval is 2 sec */
- start_int_poll_timer(php_ctlr, shpchp_poll_time);
-
- DBG_LEAVE_ROUTINE
+ start_int_poll_timer(ctrl, shpchp_poll_time);
}
/*
* This function starts the interrupt polling timer.
*/
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec)
+static void start_int_poll_timer(struct controller *ctrl, int sec)
{
/* Clamp to sane value */
if ((sec <= 0) || (sec > 60))
sec = 2;
- php_ctlr->int_poll_timer.function = &int_poll_timeout;
- php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;
- php_ctlr->int_poll_timer.expires = jiffies + sec * HZ;
- add_timer(&php_ctlr->int_poll_timer);
+ ctrl->poll_timer.function = &int_poll_timeout;
+ ctrl->poll_timer.data = (unsigned long)ctrl;
+ ctrl->poll_timer.expires = jiffies + sec * HZ;
+ add_timer(&ctrl->poll_timer);
}
static inline int is_ctrl_busy(struct controller *ctrl)
@@ -358,8 +316,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
int retval = 0;
u16 temp_word;
- DBG_ENTER_ROUTINE
-
mutex_lock(&slot->ctrl->cmd_lock);
if (!shpc_poll_ctrl_busy(ctrl)) {
@@ -373,9 +329,9 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
++t_slot;
temp_word = (t_slot << 8) | (cmd & 0xFF);
dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
-
+
/* To make sure the Controller Busy bit is 0 before we send out the
- * command.
+ * command.
*/
shpc_writew(ctrl, CMD, temp_word);
@@ -394,20 +350,14 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
}
out:
mutex_unlock(&slot->ctrl->cmd_lock);
-
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_check_cmd_status(struct controller *ctrl)
{
- u16 cmd_status;
int retval = 0;
+ u16 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
- DBG_ENTER_ROUTINE
-
- cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
-
switch (cmd_status >> 1) {
case 0:
retval = 0;
@@ -428,7 +378,6 @@ static int hpc_check_cmd_status(struct controller *ctrl)
retval = cmd_status;
}
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -436,13 +385,8 @@ static int hpc_check_cmd_status(struct controller *ctrl)
static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
switch (state) {
case ATN_LED_STATE_ON:
@@ -459,20 +403,14 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
break;
}
- DBG_LEAVE_ROUTINE
return 0;
}
static int hpc_get_power_status(struct slot * slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
switch (state) {
case SLOT_STATE_PWRONLY:
@@ -489,7 +427,6 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
break;
}
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -497,30 +434,21 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
-
- DBG_ENTER_ROUTINE
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
*status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */
- DBG_LEAVE_ROUTINE
return 0;
}
static int hpc_get_adapter_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
*status = (state != 0x3) ? 1 : 0;
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -528,11 +456,8 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
{
struct controller *ctrl = slot->ctrl;
- DBG_ENTER_ROUTINE
-
*prog_int = shpc_readb(ctrl, PROG_INTERFACE);
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -544,8 +469,6 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
u8 m66_cap = !!(slot_reg & MHZ66_CAP);
u8 pi, pcix_cap;
- DBG_ENTER_ROUTINE
-
if ((retval = hpc_get_prog_int(slot, &pi)))
return retval;
@@ -587,21 +510,15 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
}
dbg("Adapter speed = %d\n", *value);
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
{
- struct controller *ctrl = slot->ctrl;
- u16 sec_bus_status;
- u8 pi;
int retval = 0;
-
- DBG_ENTER_ROUTINE
-
- pi = shpc_readb(ctrl, PROG_INTERFACE);
- sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+ struct controller *ctrl = slot->ctrl;
+ u16 sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+ u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
if (pi == 2) {
*mode = (sec_bus_status & 0x0100) >> 8;
@@ -610,21 +527,14 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
}
dbg("Mode 1 ECC cap = %d\n", *mode);
-
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_query_power_fault(struct slot * slot)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- DBG_LEAVE_ROUTINE
/* Note: Logic 0 => fault */
return !(slot_reg & POWER_FAULT);
}
@@ -634,7 +544,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
u8 slot_cmd = 0;
switch (value) {
- case 0 :
+ case 0 :
slot_cmd = SET_ATTN_OFF; /* OFF */
break;
case 1:
@@ -666,38 +576,11 @@ static void hpc_set_green_led_blink(struct slot *slot)
shpc_write_cmd(slot, slot->hp_slot, SET_PWR_BLINK);
}
-int shpc_get_ctlr_slot_config(struct controller *ctrl,
- int *num_ctlr_slots, /* number of slots in this HPC */
- int *first_device_num, /* PCI dev num of the first slot in this SHPC */
- int *physical_slot_num, /* phy slot num of the first slot in this SHPC */
- int *updown, /* physical_slot_num increament: 1 or -1 */
- int *flags)
-{
- u32 slot_config;
-
- DBG_ENTER_ROUTINE
-
- slot_config = shpc_readl(ctrl, SLOT_CONFIG);
- *first_device_num = (slot_config & FIRST_DEV_NUM) >> 8;
- *num_ctlr_slots = slot_config & SLOT_NUM;
- *physical_slot_num = (slot_config & PSN) >> 16;
- *updown = ((slot_config & UPDOWN) >> 29) ? 1 : -1;
-
- dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num);
-
- DBG_LEAVE_ROUTINE
- return 0;
-}
-
static void hpc_release_ctlr(struct controller *ctrl)
{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
- struct php_ctlr_state_s *p, *p_prev;
int i;
u32 slot_reg, serr_int;
- DBG_ENTER_ROUTINE
-
/*
* Mask event interrupts and SERRs of all slots
*/
@@ -722,40 +605,15 @@ static void hpc_release_ctlr(struct controller *ctrl)
serr_int &= ~SERR_INTR_RSVDZ_MASK;
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
- if (shpchp_poll_mode) {
- del_timer(&php_ctlr->int_poll_timer);
- } else {
- if (php_ctlr->irq) {
- free_irq(php_ctlr->irq, ctrl);
- php_ctlr->irq = 0;
- pci_disable_msi(php_ctlr->pci_dev);
- }
- }
-
- if (php_ctlr->pci_dev) {
- iounmap(php_ctlr->creg);
- release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
- php_ctlr->pci_dev = NULL;
- }
-
- spin_lock(&list_lock);
- p = php_ctlr_list_head;
- p_prev = NULL;
- while (p) {
- if (p == php_ctlr) {
- if (p_prev)
- p_prev->pnext = p->pnext;
- else
- php_ctlr_list_head = p->pnext;
- break;
- } else {
- p_prev = p;
- p = p->pnext;
- }
+ if (shpchp_poll_mode)
+ del_timer(&ctrl->poll_timer);
+ else {
+ free_irq(ctrl->pci_dev->irq, ctrl);
+ pci_disable_msi(ctrl->pci_dev);
}
- spin_unlock(&list_lock);
- kfree(php_ctlr);
+ iounmap(ctrl->creg);
+ release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
/*
* If this is the last controller to be released, destroy the
@@ -763,62 +621,43 @@ static void hpc_release_ctlr(struct controller *ctrl)
*/
if (atomic_dec_and_test(&shpchp_num_controllers))
destroy_workqueue(shpchp_wq);
-
-DBG_LEAVE_ROUTINE
-
}
static int hpc_power_on_slot(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
-
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_slot_enable(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
/* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
retval = shpc_write_cmd(slot, slot->hp_slot,
SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_slot_disable(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
/* Slot - Disable, Power Indicator - Off, Attention Indicator - On */
retval = shpc_write_cmd(slot, slot->hp_slot,
SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
@@ -827,8 +666,6 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
struct controller *ctrl = slot->ctrl;
u8 pi, cmd;
- DBG_ENTER_ROUTINE
-
pi = shpc_readb(ctrl, PROG_INTERFACE);
if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX))
return -EINVAL;
@@ -884,14 +721,12 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- DBG_LEAVE_ROUTINE
return retval;
}
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;
u32 serr_int, slot_reg, intr_loc, intr_loc2;
int hp_slot;
@@ -900,7 +735,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
if (!intr_loc)
return IRQ_NONE;
- dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
+ dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
if(!shpchp_poll_mode) {
/*
@@ -913,12 +748,12 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
intr_loc2 = shpc_readl(ctrl, INTR_LOC);
- dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
+ dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
}
if (intr_loc & CMD_INTR_PENDING) {
- /*
- * Command Complete Interrupt Pending
+ /*
+ * Command Complete Interrupt Pending
* RO only - clear by writing 1 to the Command Completion
* Detect bit in Controller SERR-INT register
*/
@@ -932,7 +767,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
if (!(intr_loc & ~CMD_INTR_PENDING))
goto out;
- for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
+ for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
/* To find out which slot has interrupt pending */
if (!(intr_loc & SLOT_INTR_PENDING(hp_slot)))
continue;
@@ -942,20 +777,16 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
__FUNCTION__, hp_slot, slot_reg);
if (slot_reg & MRL_CHANGE_DETECTED)
- php_ctlr->switch_change_callback(
- hp_slot, php_ctlr->callback_instance_id);
+ shpchp_handle_switch_change(hp_slot, ctrl);
if (slot_reg & BUTTON_PRESS_DETECTED)
- php_ctlr->attention_button_callback(
- hp_slot, php_ctlr->callback_instance_id);
+ shpchp_handle_attention_button(hp_slot, ctrl);
if (slot_reg & PRSNT_CHANGE_DETECTED)
- php_ctlr->presence_change_callback(
- hp_slot , php_ctlr->callback_instance_id);
+ shpchp_handle_presence_change(hp_slot, ctrl);
if (slot_reg & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED))
- php_ctlr->power_fault_callback(
- hp_slot, php_ctlr->callback_instance_id);
+ shpchp_handle_power_fault(hp_slot, ctrl);
/* Clear all slot events */
slot_reg &= ~SLOT_REG_RSVDZ_MASK;
@@ -968,7 +799,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK);
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
}
-
+
return IRQ_HANDLED;
}
@@ -981,8 +812,6 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1);
u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2);
- DBG_ENTER_ROUTINE
-
if (pi == 2) {
if (slot_avail2 & SLOT_133MHZ_PCIX_533)
bus_speed = PCI_SPEED_133MHz_PCIX_533;
@@ -1015,7 +844,7 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
*value = bus_speed;
dbg("Max bus speed = %d\n", bus_speed);
- DBG_LEAVE_ROUTINE
+
return retval;
}
@@ -1028,8 +857,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);
- DBG_ENTER_ROUTINE
-
if ((pi == 1) && (speed_mode > 4)) {
*value = PCI_SPEED_UNKNOWN;
return -ENODEV;
@@ -1085,7 +912,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
}
dbg("Current bus speed = %d\n", bus_speed);
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -1093,7 +919,7 @@ static struct hpc_ops shpchp_hpc_ops = {
.power_on_slot = hpc_power_on_slot,
.slot_enable = hpc_slot_enable,
.slot_disable = hpc_slot_disable,
- .set_bus_speed_mode = hpc_set_bus_speed_mode,
+ .set_bus_speed_mode = hpc_set_bus_speed_mode,
.set_attention_status = hpc_set_attention_status,
.get_power_status = hpc_get_power_status,
.get_attention_status = hpc_get_attention_status,
@@ -1110,34 +936,20 @@ static struct hpc_ops shpchp_hpc_ops = {
.green_led_on = hpc_set_green_led_on,
.green_led_off = hpc_set_green_led_off,
.green_led_blink = hpc_set_green_led_blink,
-
+
.release_ctlr = hpc_release_ctlr,
};
-int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
+int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
{
- struct php_ctlr_state_s *php_ctlr, *p;
- void *instance_id = ctrl;
int rc = -1, num_slots = 0;
u8 hp_slot;
u32 shpc_base_offset;
u32 tempdword, slot_reg, slot_config;
u8 i;
- DBG_ENTER_ROUTINE
-
ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
- spin_lock_init(&list_lock);
- php_ctlr = kzalloc(sizeof(*php_ctlr), GFP_KERNEL);
-
- if (!php_ctlr) { /* allocate controller state data */
- err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
- goto abort;
- }
-
- php_ctlr->pci_dev = pdev; /* save pci_dev in context */
-
if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
PCI_DEVICE_ID_AMD_GOLAM_7450)) {
/* amd shpc driver doesn't use Base Offset; assume 0 */
@@ -1147,20 +959,20 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC);
if (!ctrl->cap_offset) {
err("%s : cap_offset == 0\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset);
rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset);
if (rc) {
err("%s: cannot read base_offset\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
rc = shpc_indirect_read(ctrl, 3, &tempdword);
if (rc) {
err("%s: cannot read slot config\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
num_slots = tempdword & SLOT_NUM;
dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots);
@@ -1170,7 +982,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
if (rc) {
err("%s: cannot read creg (index = %d)\n",
__FUNCTION__, i);
- goto abort_free_ctlr;
+ goto abort;
}
dbg("%s: offset %d: value %x\n", __FUNCTION__,i,
tempdword);
@@ -1181,30 +993,30 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
ctrl->mmio_size = 0x24 + 0x4 * num_slots;
}
- info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
+ 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);
-
+
rc = pci_enable_device(pdev);
if (rc) {
err("%s: pci_enable_device failed\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
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;
+ goto abort;
}
- php_ctlr->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size);
- if (!php_ctlr->creg) {
+ ctrl->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size);
+ if (!ctrl->creg) {
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;
+ goto abort;
}
- dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
+ dbg("%s: ctrl->creg %p\n", __FUNCTION__, ctrl->creg);
mutex_init(&ctrl->crit_sect);
mutex_init(&ctrl->cmd_lock);
@@ -1212,23 +1024,14 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
/* Setup wait queue */
init_waitqueue_head(&ctrl->queue);
- /* Find the IRQ */
- php_ctlr->irq = pdev->irq;
- php_ctlr->attention_button_callback = shpchp_handle_attention_button,
- php_ctlr->switch_change_callback = shpchp_handle_switch_change;
- php_ctlr->presence_change_callback = shpchp_handle_presence_change;
- php_ctlr->power_fault_callback = shpchp_handle_power_fault;
- php_ctlr->callback_instance_id = instance_id;
-
- ctrl->hpc_ctlr_handle = php_ctlr;
ctrl->hpc_ops = &shpchp_hpc_ops;
/* Return PCI Controller Info */
slot_config = shpc_readl(ctrl, SLOT_CONFIG);
- php_ctlr->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8;
- php_ctlr->num_slots = slot_config & SLOT_NUM;
- dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset);
- dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots);
+ ctrl->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8;
+ ctrl->num_slots = slot_config & SLOT_NUM;
+ ctrl->first_slot = (slot_config & PSN) >> 16;
+ ctrl->slot_num_inc = ((slot_config & UPDOWN) >> 29) ? 1 : -1;
/* Mask Global Interrupt Mask & Command Complete Interrupt Mask */
tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
@@ -1243,7 +1046,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
/* Mask the MRL sensor SERR Mask of individual slot in
* Slot SERR-INT Mask & clear all the existing event if any
*/
- for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
+ for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
hp_slot, slot_reg);
@@ -1254,25 +1057,28 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
slot_reg &= ~SLOT_REG_RSVDZ_MASK;
shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
}
-
- if (shpchp_poll_mode) {/* Install interrupt polling code */
- /* Install and start the interrupt polling timer */
- init_timer(&php_ctlr->int_poll_timer);
- start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */
+
+ if (shpchp_poll_mode) {
+ /* Install interrupt polling timer. Start with 10 sec delay */
+ init_timer(&ctrl->poll_timer);
+ start_int_poll_timer(ctrl, 10);
} else {
/* Installs the interrupt handler */
rc = pci_enable_msi(pdev);
if (rc) {
info("Can't get msi for the hotplug controller\n");
info("Use INTx for the hotplug controller\n");
- } else
- php_ctlr->irq = pdev->irq;
-
- rc = request_irq(php_ctlr->irq, shpc_isr, IRQF_SHARED, MY_NAME, (void *) ctrl);
- dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+ }
+
+ rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED,
+ MY_NAME, (void *)ctrl);
+ dbg("%s: request_irq %d for hpc%d (returns %d)\n",
+ __FUNCTION__, ctrl->pci_dev->irq,
+ atomic_read(&shpchp_num_controllers), rc);
if (rc) {
- err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
- goto abort_free_ctlr;
+ err("Can't get irq %d for the hotplug controller\n",
+ ctrl->pci_dev->irq);
+ goto abort_iounmap;
}
}
dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__,
@@ -1280,24 +1086,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
PCI_FUNC(pdev->devfn), pdev->irq);
get_hp_hw_control_from_firmware(pdev);
- /* Add this HPC instance into the HPC list */
- spin_lock(&list_lock);
- if (php_ctlr_list_head == 0) {
- php_ctlr_list_head = php_ctlr;
- p = php_ctlr_list_head;
- p->pnext = NULL;
- } else {
- p = php_ctlr_list_head;
-
- while (p->pnext)
- p = p->pnext;
-
- p->pnext = php_ctlr;
- }
- spin_unlock(&list_lock);
-
- ctlr_seq_num++;
-
/*
* If this is the first controller to be initialized,
* initialize the shpchpd work queue
@@ -1306,14 +1094,14 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
shpchp_wq = create_singlethread_workqueue("shpchpd");
if (!shpchp_wq) {
rc = -ENOMEM;
- goto abort_free_ctlr;
+ goto abort_iounmap;
}
}
/*
* Unmask all event interrupts of all slots
*/
- for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
+ for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
hp_slot, slot_reg);
@@ -1332,15 +1120,11 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
}
- DBG_LEAVE_ROUTINE
return 0;
/* 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_iounmap:
+ iounmap(ctrl->creg);
abort:
- DBG_LEAVE_ROUTINE
return rc;
}
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
index 0a8d1cce9fa..279c940a003 100644
--- a/drivers/pci/htirq.c
+++ b/drivers/pci/htirq.c
@@ -99,14 +99,7 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
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);
- }
+ pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
if (!pos)
return -EINVAL;
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index ed3f7e1a563..68555c11f55 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -24,8 +24,6 @@
#include "pci.h"
#include "msi.h"
-static DEFINE_SPINLOCK(msi_lock);
-static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
static struct kmem_cache* msi_cachep;
static int pci_msi_enable = 1;
@@ -44,13 +42,13 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
{
struct msi_desc *entry;
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
BUG_ON(!entry || !entry->dev);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
if (entry->msi_attrib.maskbit) {
- int pos;
- u32 mask_bits;
+ int pos;
+ u32 mask_bits;
pos = (long)entry->mask_base;
pci_read_config_dword(entry->dev, pos, &mask_bits);
@@ -74,7 +72,7 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
void read_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct msi_desc *entry = get_irq_data(irq);
+ struct msi_desc *entry = get_irq_msi(irq);
switch(entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
@@ -113,7 +111,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
void write_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct msi_desc *entry = get_irq_data(irq);
+ struct msi_desc *entry = get_irq_msi(irq);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
@@ -162,6 +160,7 @@ void unmask_msi_irq(unsigned int irq)
}
static int msi_free_irq(struct pci_dev* dev, int irq);
+
static int msi_init(void)
{
static int status = -ENOMEM;
@@ -169,13 +168,6 @@ static int msi_init(void)
if (!status)
return status;
- if (pci_msi_quirk) {
- pci_msi_enable = 0;
- printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n");
- status = -EINVAL;
- return status;
- }
-
status = msi_cache_init();
if (status < 0) {
pci_msi_enable = 0;
@@ -200,46 +192,6 @@ static struct msi_desc* alloc_msi_entry(void)
return entry;
}
-static void attach_msi_entry(struct msi_desc *entry, int irq)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- msi_desc[irq] = entry;
- spin_unlock_irqrestore(&msi_lock, flags);
-}
-
-static int create_msi_irq(void)
-{
- struct msi_desc *entry;
- int irq;
-
- entry = alloc_msi_entry();
- if (!entry)
- return -ENOMEM;
-
- irq = create_irq();
- if (irq < 0) {
- kmem_cache_free(msi_cachep, entry);
- return -EBUSY;
- }
-
- 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)
{
u16 control;
@@ -278,36 +230,8 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type)
pci_intx(dev, 1); /* enable intx */
}
-static int msi_lookup_irq(struct pci_dev *dev, int type)
-{
- int irq;
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- 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 irq for this device
- already exits. Override dev->irq with this irq */
- dev->irq = irq;
- return 0;
- }
- spin_unlock_irqrestore(&msi_lock, flags);
-
- return -EACCES;
-}
-
-void pci_scan_msi_device(struct pci_dev *dev)
-{
- if (!dev)
- return;
-}
-
#ifdef CONFIG_PM
-int pci_save_msi_state(struct pci_dev *dev)
+static int __pci_save_msi_state(struct pci_dev *dev)
{
int pos, i = 0;
u16 control;
@@ -345,7 +269,7 @@ int pci_save_msi_state(struct pci_dev *dev)
return 0;
}
-void pci_restore_msi_state(struct pci_dev *dev)
+static void __pci_restore_msi_state(struct pci_dev *dev)
{
int i = 0, pos;
u16 control;
@@ -373,14 +297,16 @@ void pci_restore_msi_state(struct pci_dev *dev)
kfree(save_state);
}
-int pci_save_msix_state(struct pci_dev *dev)
+static int __pci_save_msix_state(struct pci_dev *dev)
{
int pos;
- int temp;
int irq, head, tail = 0;
u16 control;
struct pci_cap_saved_state *save_state;
+ if (!dev->msix_enabled)
+ return 0;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (pos <= 0 || dev->no_msi)
return 0;
@@ -398,38 +324,46 @@ int pci_save_msix_state(struct pci_dev *dev)
*((u16 *)&save_state->data[0]) = control;
/* save the table */
- temp = dev->irq;
- if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
- kfree(save_state);
- return -EINVAL;
- }
-
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
struct msi_desc *entry;
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
read_msi_msg(irq, &entry->msg_save);
- tail = msi_desc[irq]->link.tail;
+ tail = entry->link.tail;
irq = tail;
}
- dev->irq = temp;
save_state->cap_nr = PCI_CAP_ID_MSIX;
pci_add_saved_cap(dev, save_state);
return 0;
}
-void pci_restore_msix_state(struct pci_dev *dev)
+int pci_save_msi_state(struct pci_dev *dev)
+{
+ int rc;
+
+ rc = __pci_save_msi_state(dev);
+ if (rc)
+ return rc;
+
+ rc = __pci_save_msix_state(dev);
+
+ return rc;
+}
+
+static void __pci_restore_msix_state(struct pci_dev *dev)
{
u16 save;
int pos;
int irq, head, tail = 0;
struct msi_desc *entry;
- int temp;
struct pci_cap_saved_state *save_state;
+ if (!dev->msix_enabled)
+ return;
+
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX);
if (!save_state)
return;
@@ -442,23 +376,25 @@ void pci_restore_msix_state(struct pci_dev *dev)
return;
/* route the table */
- temp = dev->irq;
- if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX))
- return;
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
write_msi_msg(irq, &entry->msg_save);
- tail = msi_desc[irq]->link.tail;
+ tail = entry->link.tail;
irq = tail;
}
- dev->irq = temp;
pci_write_config_word(dev, msi_control_reg(pos), save);
enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
}
-#endif
+
+void pci_restore_msi_state(struct pci_dev *dev)
+{
+ __pci_restore_msi_state(dev);
+ __pci_restore_msix_state(dev);
+}
+#endif /* CONFIG_PM */
/**
* msi_capability_init - configure device's MSI capability structure
@@ -471,7 +407,6 @@ void pci_restore_msix_state(struct pci_dev *dev)
**/
static int msi_capability_init(struct pci_dev *dev)
{
- int status;
struct msi_desc *entry;
int pos, irq;
u16 control;
@@ -479,13 +414,10 @@ static int msi_capability_init(struct pci_dev *dev)
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
pci_read_config_word(dev, msi_control_reg(pos), &control);
/* MSI Entry Initialization */
- irq = create_msi_irq();
- if (irq < 0)
- return irq;
+ entry = alloc_msi_entry();
+ if (!entry)
+ return -ENOMEM;
- entry = get_irq_data(irq);
- entry->link.head = irq;
- entry->link.tail = irq;
entry->msi_attrib.type = PCI_CAP_ID_MSI;
entry->msi_attrib.is_64 = is_64bit_address(control);
entry->msi_attrib.entry_nr = 0;
@@ -511,13 +443,16 @@ static int msi_capability_init(struct pci_dev *dev)
maskbits);
}
/* Configure MSI capability structure */
- status = arch_setup_msi_irq(irq, dev);
- if (status < 0) {
- destroy_msi_irq(irq);
- return status;
+ irq = arch_setup_msi_irq(dev, entry);
+ if (irq < 0) {
+ kmem_cache_free(msi_cachep, entry);
+ return irq;
}
+ entry->link.head = irq;
+ entry->link.tail = irq;
+ dev->first_msi_irq = irq;
+ set_irq_msi(irq, entry);
- attach_msi_entry(entry, irq);
/* Set MSI enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
@@ -539,7 +474,6 @@ static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
- int status;
int irq, pos, i, j, nr_entries, temp = 0;
unsigned long phys_addr;
u32 table_offset;
@@ -562,13 +496,11 @@ static int msix_capability_init(struct pci_dev *dev,
/* MSI-X Table Initialization */
for (i = 0; i < nvec; i++) {
- irq = create_msi_irq();
- if (irq < 0)
+ entry = alloc_msi_entry();
+ if (!entry)
break;
- entry = get_irq_data(irq);
j = entries[i].entry;
- entries[i].vector = irq;
entry->msi_attrib.type = PCI_CAP_ID_MSIX;
entry->msi_attrib.is_64 = 1;
entry->msi_attrib.entry_nr = j;
@@ -577,6 +509,14 @@ static int msix_capability_init(struct pci_dev *dev,
entry->msi_attrib.pos = pos;
entry->dev = dev;
entry->mask_base = base;
+
+ /* Configure MSI-X capability structure */
+ irq = arch_setup_msi_irq(dev, entry);
+ if (irq < 0) {
+ kmem_cache_free(msi_cachep, entry);
+ break;
+ }
+ entries[i].vector = irq;
if (!head) {
entry->link.head = irq;
entry->link.tail = irq;
@@ -589,14 +529,8 @@ static int msix_capability_init(struct pci_dev *dev,
}
temp = irq;
tail = entry;
- /* Configure MSI-X capability structure */
- status = arch_setup_msi_irq(irq, dev);
- if (status < 0) {
- destroy_msi_irq(irq);
- break;
- }
- attach_msi_entry(entry, irq);
+ set_irq_msi(irq, entry);
}
if (i != nvec) {
int avail = i - 1;
@@ -613,6 +547,7 @@ static int msix_capability_init(struct pci_dev *dev,
avail = -EBUSY;
return avail;
}
+ dev->first_msi_irq = entries[0].vector;
/* Set MSI-X enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
@@ -660,13 +595,11 @@ int pci_msi_supported(struct pci_dev * dev)
**/
int pci_enable_msi(struct pci_dev* dev)
{
- int pos, temp, status;
+ int pos, status;
if (pci_msi_supported(dev) < 0)
return -EINVAL;
- temp = dev->irq;
-
status = msi_init();
if (status < 0)
return status;
@@ -675,15 +608,14 @@ int pci_enable_msi(struct pci_dev* dev)
if (!pos)
return -EINVAL;
- WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
+ WARN_ON(!!dev->msi_enabled);
/* Check whether driver already requested for MSI-X irqs */
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ if (pos > 0 && dev->msix_enabled) {
printk(KERN_INFO "PCI: %s: Can't enable MSI. "
- "Device already has MSI-X irq assigned\n",
+ "Device already has MSI-X enabled\n",
pci_name(dev));
- dev->irq = temp;
return -EINVAL;
}
status = msi_capability_init(dev);
@@ -695,13 +627,15 @@ void pci_disable_msi(struct pci_dev* dev)
struct msi_desc *entry;
int pos, default_irq;
u16 control;
- unsigned long flags;
if (!pci_msi_enable)
return;
if (!dev)
return;
+ if (!dev->msi_enabled)
+ return;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (!pos)
return;
@@ -710,28 +644,26 @@ 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];
+ entry = get_irq_msi(dev->first_msi_irq);
if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
- spin_unlock_irqrestore(&msi_lock, flags);
return;
}
- if (irq_has_action(dev->irq)) {
- spin_unlock_irqrestore(&msi_lock, flags);
+ if (irq_has_action(dev->first_msi_irq)) {
printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
"free_irq() on MSI irq %d\n",
- pci_name(dev), dev->irq);
- BUG_ON(irq_has_action(dev->irq));
+ pci_name(dev), dev->first_msi_irq);
+ BUG_ON(irq_has_action(dev->first_msi_irq));
} else {
default_irq = entry->msi_attrib.default_irq;
- spin_unlock_irqrestore(&msi_lock, flags);
- msi_free_irq(dev, dev->irq);
+ msi_free_irq(dev, dev->first_msi_irq);
/* Restore dev->irq to its default pin-assertion irq */
dev->irq = default_irq;
}
+ dev->first_msi_irq = 0;
}
static int msi_free_irq(struct pci_dev* dev, int irq)
@@ -739,27 +671,20 @@ 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;
- arch_teardown_msi_irq(irq);
-
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
if (!entry || entry->dev != dev) {
- spin_unlock_irqrestore(&msi_lock, flags);
return -EINVAL;
}
type = entry->msi_attrib.type;
entry_nr = entry->msi_attrib.entry_nr;
head = entry->link.head;
base = entry->mask_base;
- msi_desc[entry->link.head]->link.tail = entry->link.tail;
- msi_desc[entry->link.tail]->link.head = entry->link.head;
- entry->dev = NULL;
- msi_desc[irq] = NULL;
- spin_unlock_irqrestore(&msi_lock, flags);
+ get_irq_msi(entry->link.head)->link.tail = entry->link.tail;
+ get_irq_msi(entry->link.tail)->link.head = entry->link.head;
- destroy_msi_irq(irq);
+ arch_teardown_msi_irq(irq);
+ kmem_cache_free(msi_cachep, entry);
if (type == PCI_CAP_ID_MSIX) {
writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
@@ -790,7 +715,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
{
int status, pos, nr_entries;
- int i, j, temp;
+ int i, j;
u16 control;
if (!entries || pci_msi_supported(dev) < 0)
@@ -818,16 +743,14 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
return -EINVAL; /* duplicate entry */
}
}
- temp = dev->irq;
- WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX));
+ WARN_ON(!!dev->msix_enabled);
/* Check whether driver already requested for MSI irq */
if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
- !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
+ dev->msi_enabled) {
printk(KERN_INFO "PCI: %s: Can't enable MSI-X. "
"Device already has an MSI irq assigned\n",
pci_name(dev));
- dev->irq = temp;
return -EINVAL;
}
status = msix_capability_init(dev, entries, nvec);
@@ -836,7 +759,8 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
void pci_disable_msix(struct pci_dev* dev)
{
- int pos, temp;
+ int irq, head, tail = 0, warning = 0;
+ int pos;
u16 control;
if (!pci_msi_enable)
@@ -844,6 +768,9 @@ void pci_disable_msix(struct pci_dev* dev)
if (!dev)
return;
+ if (!dev->msix_enabled)
+ return;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (!pos)
return;
@@ -854,31 +781,23 @@ void pci_disable_msix(struct pci_dev* dev)
disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
- temp = dev->irq;
- if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
- int irq, head, tail = 0, warning = 0;
- unsigned long flags;
-
- irq = head = dev->irq;
- dev->irq = temp; /* Restore pin IRQ */
- while (head != tail) {
- 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 if (irq != head) /* Release MSI-X irq */
- msi_free_irq(dev, irq);
- irq = tail;
- }
- msi_free_irq(dev, irq);
- if (warning) {
- printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
- "free_irq() on all MSI-X irqs\n",
- pci_name(dev));
- BUG_ON(warning > 0);
- }
+ irq = head = dev->first_msi_irq;
+ while (head != tail) {
+ tail = get_irq_msi(irq)->link.tail;
+ if (irq_has_action(irq))
+ warning = 1;
+ else if (irq != head) /* Release MSI-X irq */
+ msi_free_irq(dev, irq);
+ irq = tail;
+ }
+ msi_free_irq(dev, irq);
+ if (warning) {
+ printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
+ "free_irq() on all MSI-X irqs\n",
+ pci_name(dev));
+ BUG_ON(warning > 0);
}
+ dev->first_msi_irq = 0;
}
/**
@@ -892,35 +811,26 @@ void pci_disable_msix(struct pci_dev* dev)
**/
void msi_remove_pci_irq_vectors(struct pci_dev* dev)
{
- int pos, temp;
- unsigned long flags;
-
if (!pci_msi_enable || !dev)
return;
- temp = dev->irq; /* Save IOAPIC IRQ */
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
- if (irq_has_action(dev->irq)) {
+ if (dev->msi_enabled) {
+ if (irq_has_action(dev->first_msi_irq)) {
printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
"called without free_irq() on MSI irq %d\n",
- pci_name(dev), dev->irq);
- BUG_ON(irq_has_action(dev->irq));
+ pci_name(dev), dev->first_msi_irq);
+ BUG_ON(irq_has_action(dev->first_msi_irq));
} else /* Release MSI irq assigned to this device */
- msi_free_irq(dev, dev->irq);
- dev->irq = temp; /* Restore IOAPIC IRQ */
+ msi_free_irq(dev, dev->first_msi_irq);
}
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ if (dev->msix_enabled) {
int irq, head, tail = 0, warning = 0;
void __iomem *base = NULL;
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
- spin_lock_irqsave(&msi_lock, flags);
- tail = msi_desc[irq]->link.tail;
- base = msi_desc[irq]->mask_base;
- spin_unlock_irqrestore(&msi_lock, flags);
+ tail = get_irq_msi(irq)->link.tail;
+ base = get_irq_msi(irq)->mask_base;
if (irq_has_action(irq))
warning = 1;
else if (irq != head) /* Release MSI-X irq */
@@ -935,7 +845,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
pci_name(dev));
BUG_ON(warning > 0);
}
- dev->irq = temp; /* Restore IOAPIC IRQ */
}
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index e5ae3a0c13b..4438ae1ede4 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -150,8 +150,7 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
}
/**
- * pci_match_device - Tell if a PCI device structure has a matching
- * PCI device id structure
+ * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
* @drv: the PCI driver to match against
* @dev: the PCI device structure to match against
*
@@ -162,14 +161,9 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
const struct pci_device_id *pci_match_device(struct pci_driver *drv,
struct pci_dev *dev)
{
- const struct pci_device_id *id;
struct pci_dynid *dynid;
- id = pci_match_id(drv->id_table, dev);
- if (id)
- return id;
-
- /* static ids didn't match, lets look at the dynamic ones */
+ /* Look at the dynamic ids first, before the static ones */
spin_lock(&drv->dynids.lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (pci_match_one_device(&dynid->id, dev)) {
@@ -178,7 +172,8 @@ const struct pci_device_id *pci_match_device(struct pci_driver *drv,
}
}
spin_unlock(&drv->dynids.lock);
- return NULL;
+
+ return pci_match_id(drv->id_table, dev);
}
static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
@@ -329,8 +324,7 @@ static int pci_default_resume(struct pci_dev *pci_dev)
/* restore the PCI config space */
pci_restore_state(pci_dev);
/* if the device was enabled before suspend, reenable */
- if (atomic_read(&pci_dev->enable_cnt))
- retval = __pci_enable_device(pci_dev);
+ retval = __pci_reenable_device(pci_dev);
/* if the device was busmaster before the suspend, make it busmaster again */
if (pci_dev->is_busmaster)
pci_set_master(pci_dev);
@@ -357,6 +351,8 @@ static int pci_device_resume_early(struct device * dev)
struct pci_dev * pci_dev = to_pci_dev(dev);
struct pci_driver * drv = pci_dev->driver;
+ pci_fixup_device(pci_fixup_resume, pci_dev);
+
if (drv && drv->resume_early)
error = drv->resume_early(pci_dev);
return error;
@@ -425,7 +421,8 @@ static struct kobj_type pci_driver_kobj_type = {
* If no error occurred, the driver remains registered even if
* no device was claimed during registration.
*/
-int __pci_register_driver(struct pci_driver *drv, struct module *owner)
+int __pci_register_driver(struct pci_driver *drv, struct module *owner,
+ const char *mod_name)
{
int error;
@@ -433,6 +430,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner)
drv->driver.name = drv->name;
drv->driver.bus = &pci_bus_type;
drv->driver.owner = owner;
+ drv->driver.mod_name = mod_name;
drv->driver.kobj.ktype = &pci_driver_kobj_type;
if (pci_multithread_probe)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 5a14b73cf3a..8b44cff2c17 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -68,12 +68,14 @@ pci_max_busnr(void)
#endif /* 0 */
-static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap)
+#define PCI_FIND_CAP_TTL 48
+
+static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
+ u8 pos, int cap, int *ttl)
{
u8 id;
- int ttl = 48;
- while (ttl--) {
+ while ((*ttl)--) {
pci_bus_read_config_byte(bus, devfn, pos, &pos);
if (pos < 0x40)
break;
@@ -89,6 +91,14 @@ static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos,
return 0;
}
+static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
+ u8 pos, int cap)
+{
+ int ttl = PCI_FIND_CAP_TTL;
+
+ return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl);
+}
+
int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
{
return __pci_find_next_cap(dev->bus, dev->devfn,
@@ -96,10 +106,10 @@ int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
}
EXPORT_SYMBOL_GPL(pci_find_next_capability);
-static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_type, int cap)
+static int __pci_bus_find_cap_start(struct pci_bus *bus,
+ unsigned int devfn, u8 hdr_type)
{
u16 status;
- u8 pos;
pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST))
@@ -108,15 +118,14 @@ static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_ty
switch (hdr_type) {
case PCI_HEADER_TYPE_NORMAL:
case PCI_HEADER_TYPE_BRIDGE:
- pos = PCI_CAPABILITY_LIST;
- break;
+ return PCI_CAPABILITY_LIST;
case PCI_HEADER_TYPE_CARDBUS:
- pos = PCI_CB_CAPABILITY_LIST;
- break;
+ return PCI_CB_CAPABILITY_LIST;
default:
return 0;
}
- return __pci_find_next_cap(bus, devfn, pos, cap);
+
+ return 0;
}
/**
@@ -140,7 +149,13 @@ static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_ty
*/
int pci_find_capability(struct pci_dev *dev, int cap)
{
- return __pci_bus_find_cap(dev->bus, dev->devfn, dev->hdr_type, cap);
+ int pos;
+
+ pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
+ if (pos)
+ pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap);
+
+ return pos;
}
/**
@@ -158,11 +173,16 @@ int pci_find_capability(struct pci_dev *dev, int cap)
*/
int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
{
+ int pos;
u8 hdr_type;
pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
- return __pci_bus_find_cap(bus, devfn, hdr_type & 0x7f, cap);
+ pos = __pci_bus_find_cap_start(bus, devfn, hdr_type & 0x7f);
+ if (pos)
+ pos = __pci_find_next_cap(bus, devfn, pos, cap);
+
+ return pos;
}
/**
@@ -214,6 +234,75 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap)
}
EXPORT_SYMBOL_GPL(pci_find_ext_capability);
+static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
+{
+ int rc, ttl = PCI_FIND_CAP_TTL;
+ u8 cap, mask;
+
+ if (ht_cap == HT_CAPTYPE_SLAVE || ht_cap == HT_CAPTYPE_HOST)
+ mask = HT_3BIT_CAP_MASK;
+ else
+ mask = HT_5BIT_CAP_MASK;
+
+ pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos,
+ PCI_CAP_ID_HT, &ttl);
+ while (pos) {
+ rc = pci_read_config_byte(dev, pos + 3, &cap);
+ if (rc != PCIBIOS_SUCCESSFUL)
+ return 0;
+
+ if ((cap & mask) == ht_cap)
+ return pos;
+
+ pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn,
+ pos + PCI_CAP_LIST_NEXT,
+ PCI_CAP_ID_HT, &ttl);
+ }
+
+ return 0;
+}
+/**
+ * pci_find_next_ht_capability - query a device's Hypertransport capabilities
+ * @dev: PCI device to query
+ * @pos: Position from which to continue searching
+ * @ht_cap: Hypertransport capability code
+ *
+ * To be used in conjunction with pci_find_ht_capability() to search for
+ * all capabilities matching @ht_cap. @pos should always be a value returned
+ * from pci_find_ht_capability().
+ *
+ * NB. To be 100% safe against broken PCI devices, the caller should take
+ * steps to avoid an infinite loop.
+ */
+int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap)
+{
+ return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap);
+}
+EXPORT_SYMBOL_GPL(pci_find_next_ht_capability);
+
+/**
+ * pci_find_ht_capability - query a device's Hypertransport capabilities
+ * @dev: PCI device to query
+ * @ht_cap: Hypertransport capability code
+ *
+ * Tell if a device supports a given Hypertransport capability.
+ * Returns an address within the device's PCI configuration space
+ * or 0 in case the device does not support the request capability.
+ * The address points to the PCI capability, of type PCI_CAP_ID_HT,
+ * which has a Hypertransport capability matching @ht_cap.
+ */
+int pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
+{
+ int pos;
+
+ pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
+ if (pos)
+ pos = __pci_find_next_ht_cap(dev, pos, ht_cap);
+
+ return pos;
+}
+EXPORT_SYMBOL_GPL(pci_find_ht_capability);
+
/**
* pci_find_parent_resource - return resource region of parent bus of given region
* @dev: PCI device structure contains resources to be searched
@@ -303,6 +392,14 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
if (state > PCI_D3hot)
state = PCI_D3hot;
+ /*
+ * If the device or the parent bridge can't support PCI PM, ignore
+ * the request if we're doing anything besides putting it into D0
+ * (which would only happen on boot).
+ */
+ if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
+ return 0;
+
/* Validate current state:
* Can enter D0 from any state, but if we can only go deeper
* to sleep if we're already in a low power state
@@ -314,13 +411,6 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
} else if (dev->current_state == state)
return 0; /* we're already there */
- /*
- * If the device or the parent bridge can't support PCI PM, ignore
- * the request if we're doing anything besides putting it into D0
- * (which would only happen on boot).
- */
- if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
- return 0;
/* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM);
@@ -544,8 +634,6 @@ pci_save_state(struct pci_dev *dev)
pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]);
if ((i = pci_save_msi_state(dev)) != 0)
return i;
- if ((i = pci_save_msix_state(dev)) != 0)
- return i;
if ((i = pci_save_pcie_state(dev)) != 0)
return i;
if ((i = pci_save_pcix_state(dev)) != 0)
@@ -583,22 +671,11 @@ pci_restore_state(struct pci_dev *dev)
}
pci_restore_pcix_state(dev);
pci_restore_msi_state(dev);
- pci_restore_msix_state(dev);
+
return 0;
}
-/**
- * pci_enable_device_bars - Initialize some of a device for use
- * @dev: PCI device to be initialized
- * @bars: bitmask of BAR's that must be configured
- *
- * Initialize device before it's used by a driver. Ask low-level code
- * to enable selected I/O and memory resources. Wake up the device if it
- * was suspended. Beware, this function can fail.
- */
-
-int
-pci_enable_device_bars(struct pci_dev *dev, int bars)
+static int do_pci_enable_device(struct pci_dev *dev, int bars)
{
int err;
@@ -608,30 +685,47 @@ pci_enable_device_bars(struct pci_dev *dev, int bars)
err = pcibios_enable_device(dev, bars);
if (err < 0)
return err;
+ pci_fixup_device(pci_fixup_enable, dev);
+
+ return 0;
+}
+
+/**
+ * __pci_reenable_device - Resume abandoned device
+ * @dev: PCI device to be resumed
+ *
+ * Note this function is a backend of pci_default_resume and is not supposed
+ * to be called by normal code, write proper resume handler and use it instead.
+ */
+int
+__pci_reenable_device(struct pci_dev *dev)
+{
+ if (atomic_read(&dev->enable_cnt))
+ return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
return 0;
}
/**
- * __pci_enable_device - Initialize device before it's used by a driver.
+ * pci_enable_device_bars - Initialize some of a device for use
* @dev: PCI device to be initialized
+ * @bars: bitmask of BAR's that must be configured
*
* Initialize device before it's used by a driver. Ask low-level code
- * to enable I/O and memory. Wake up the device if it was suspended.
- * Beware, this function can fail.
- *
- * Note this function is a backend and is not supposed to be called by
- * normal code, use pci_enable_device() instead.
+ * to enable selected I/O and memory resources. Wake up the device if it
+ * was suspended. Beware, this function can fail.
*/
int
-__pci_enable_device(struct pci_dev *dev)
+pci_enable_device_bars(struct pci_dev *dev, int bars)
{
int err;
- err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
- if (err)
- return err;
- pci_fixup_device(pci_fixup_enable, dev);
- return 0;
+ if (atomic_add_return(1, &dev->enable_cnt) > 1)
+ return 0; /* already enabled */
+
+ err = do_pci_enable_device(dev, bars);
+ if (err < 0)
+ atomic_dec(&dev->enable_cnt);
+ return err;
}
/**
@@ -647,13 +741,105 @@ __pci_enable_device(struct pci_dev *dev)
*/
int pci_enable_device(struct pci_dev *dev)
{
- int result;
- if (atomic_add_return(1, &dev->enable_cnt) > 1)
- return 0; /* already enabled */
- result = __pci_enable_device(dev);
- if (result < 0)
- atomic_dec(&dev->enable_cnt);
- return result;
+ return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
+}
+
+/*
+ * Managed PCI resources. This manages device on/off, intx/msi/msix
+ * on/off and BAR regions. pci_dev itself records msi/msix status, so
+ * there's no need to track it separately. pci_devres is initialized
+ * when a device is enabled using managed PCI device enable interface.
+ */
+struct pci_devres {
+ unsigned int disable:1;
+ unsigned int orig_intx:1;
+ unsigned int restore_intx:1;
+ u32 region_mask;
+};
+
+static void pcim_release(struct device *gendev, void *res)
+{
+ struct pci_dev *dev = container_of(gendev, struct pci_dev, dev);
+ struct pci_devres *this = res;
+ int i;
+
+ if (dev->msi_enabled)
+ pci_disable_msi(dev);
+ if (dev->msix_enabled)
+ pci_disable_msix(dev);
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
+ if (this->region_mask & (1 << i))
+ pci_release_region(dev, i);
+
+ if (this->restore_intx)
+ pci_intx(dev, this->orig_intx);
+
+ if (this->disable)
+ pci_disable_device(dev);
+}
+
+static struct pci_devres * get_pci_dr(struct pci_dev *pdev)
+{
+ struct pci_devres *dr, *new_dr;
+
+ dr = devres_find(&pdev->dev, pcim_release, NULL, NULL);
+ if (dr)
+ return dr;
+
+ new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL);
+ if (!new_dr)
+ return NULL;
+ return devres_get(&pdev->dev, new_dr, NULL, NULL);
+}
+
+static struct pci_devres * find_pci_dr(struct pci_dev *pdev)
+{
+ if (pci_is_managed(pdev))
+ return devres_find(&pdev->dev, pcim_release, NULL, NULL);
+ return NULL;
+}
+
+/**
+ * pcim_enable_device - Managed pci_enable_device()
+ * @pdev: PCI device to be initialized
+ *
+ * Managed pci_enable_device().
+ */
+int pcim_enable_device(struct pci_dev *pdev)
+{
+ struct pci_devres *dr;
+ int rc;
+
+ dr = get_pci_dr(pdev);
+ if (unlikely(!dr))
+ return -ENOMEM;
+ WARN_ON(!!dr->disable);
+
+ rc = pci_enable_device(pdev);
+ if (!rc) {
+ pdev->is_managed = 1;
+ dr->disable = 1;
+ }
+ return rc;
+}
+
+/**
+ * pcim_pin_device - Pin managed PCI device
+ * @pdev: PCI device to pin
+ *
+ * Pin managed PCI device @pdev. Pinned device won't be disabled on
+ * driver detach. @pdev must have been enabled with
+ * pcim_enable_device().
+ */
+void pcim_pin_device(struct pci_dev *pdev)
+{
+ struct pci_devres *dr;
+
+ dr = find_pci_dr(pdev);
+ WARN_ON(!dr || !dr->disable);
+ if (dr)
+ dr->disable = 0;
}
/**
@@ -679,8 +865,13 @@ void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
void
pci_disable_device(struct pci_dev *dev)
{
+ struct pci_devres *dr;
u16 pci_command;
+ dr = find_pci_dr(dev);
+ if (dr)
+ dr->disable = 0;
+
if (atomic_sub_return(1, &dev->enable_cnt) != 0)
return;
@@ -779,6 +970,8 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
*/
void pci_release_region(struct pci_dev *pdev, int bar)
{
+ struct pci_devres *dr;
+
if (pci_resource_len(pdev, bar) == 0)
return;
if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
@@ -787,6 +980,10 @@ void pci_release_region(struct pci_dev *pdev, int bar)
else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
release_mem_region(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar));
+
+ dr = find_pci_dr(pdev);
+ if (dr)
+ dr->region_mask &= ~(1 << bar);
}
/**
@@ -805,6 +1002,8 @@ void pci_release_region(struct pci_dev *pdev, int bar)
*/
int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
{
+ struct pci_devres *dr;
+
if (pci_resource_len(pdev, bar) == 0)
return 0;
@@ -818,7 +1017,11 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
pci_resource_len(pdev, bar), res_name))
goto err_out;
}
-
+
+ dr = find_pci_dr(pdev);
+ if (dr)
+ dr->region_mask |= 1 << bar;
+
return 0;
err_out:
@@ -832,6 +1035,47 @@ err_out:
return -EBUSY;
}
+/**
+ * pci_release_selected_regions - Release selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources were previously reserved
+ * @bars: Bitmask of BARs to be released
+ *
+ * Release selected PCI I/O and memory resources previously reserved.
+ * Call this function only after all use of the PCI regions has ceased.
+ */
+void pci_release_selected_regions(struct pci_dev *pdev, int bars)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ if (bars & (1 << i))
+ pci_release_region(pdev, i);
+}
+
+/**
+ * pci_request_selected_regions - Reserve selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources are to be reserved
+ * @bars: Bitmask of BARs to be requested
+ * @res_name: Name to be associated with resource
+ */
+int pci_request_selected_regions(struct pci_dev *pdev, int bars,
+ const char *res_name)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ if (bars & (1 << i))
+ if(pci_request_region(pdev, i, res_name))
+ goto err_out;
+ return 0;
+
+err_out:
+ while(--i >= 0)
+ if (bars & (1 << i))
+ pci_release_region(pdev, i);
+
+ return -EBUSY;
+}
/**
* pci_release_regions - Release reserved PCI I/O and memory resources
@@ -844,10 +1088,7 @@ err_out:
void pci_release_regions(struct pci_dev *pdev)
{
- int i;
-
- for (i = 0; i < 6; i++)
- pci_release_region(pdev, i);
+ pci_release_selected_regions(pdev, (1 << 6) - 1);
}
/**
@@ -865,18 +1106,7 @@ void pci_release_regions(struct pci_dev *pdev)
*/
int pci_request_regions(struct pci_dev *pdev, const char *res_name)
{
- int i;
-
- for (i = 0; i < 6; i++)
- if(pci_request_region(pdev, i, res_name))
- goto err_out;
- return 0;
-
-err_out:
- while(--i >= 0)
- pci_release_region(pdev, i);
-
- return -EBUSY;
+ return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name);
}
/**
@@ -1029,7 +1259,15 @@ pci_intx(struct pci_dev *pdev, int enable)
}
if (new != pci_command) {
+ struct pci_devres *dr;
+
pci_write_config_word(pdev, PCI_COMMAND, new);
+
+ dr = find_pci_dr(pdev);
+ if (dr && !dr->restore_intx) {
+ dr->restore_intx = 1;
+ dr->orig_intx = !enable;
+ }
}
}
@@ -1059,7 +1297,23 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
return 0;
}
#endif
-
+
+/**
+ * pci_select_bars - Make BAR mask from the type of resource
+ * @pdev: the PCI device for which BAR mask is made
+ * @flags: resource type mask to be selected
+ *
+ * This helper routine makes bar mask from the type of resource.
+ */
+int pci_select_bars(struct pci_dev *dev, unsigned long flags)
+{
+ int i, bars = 0;
+ for (i = 0; i < PCI_NUM_RESOURCES; i++)
+ if (pci_resource_flags(dev, i) & flags)
+ bars |= (1 << i);
+ return bars;
+}
+
static int __devinit pci_init(void)
{
struct pci_dev *dev = NULL;
@@ -1092,15 +1346,11 @@ early_param("pci", pci_setup);
device_initcall(pci_init);
-#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
-/* FIXME: Some boxes have multiple ISA bridges! */
-struct pci_dev *isa_bridge;
-EXPORT_SYMBOL(isa_bridge);
-#endif
-
EXPORT_SYMBOL_GPL(pci_restore_bars);
EXPORT_SYMBOL(pci_enable_device_bars);
EXPORT_SYMBOL(pci_enable_device);
+EXPORT_SYMBOL(pcim_enable_device);
+EXPORT_SYMBOL(pcim_pin_device);
EXPORT_SYMBOL(pci_disable_device);
EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_bus_find_capability);
@@ -1108,6 +1358,8 @@ EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_regions);
EXPORT_SYMBOL(pci_release_region);
EXPORT_SYMBOL(pci_request_region);
+EXPORT_SYMBOL(pci_release_selected_regions);
+EXPORT_SYMBOL(pci_request_selected_regions);
EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi);
@@ -1116,13 +1368,10 @@ EXPORT_SYMBOL(pci_set_dma_mask);
EXPORT_SYMBOL(pci_set_consistent_dma_mask);
EXPORT_SYMBOL(pci_assign_resource);
EXPORT_SYMBOL(pci_find_parent_resource);
+EXPORT_SYMBOL(pci_select_bars);
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_save_state);
EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_enable_wake);
-/* Quirk info */
-
-EXPORT_SYMBOL(isa_dma_bridge_buggy);
-EXPORT_SYMBOL(pci_pci_problems);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 398852f526a..a4f2d580625 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,6 +1,6 @@
/* Functions internal to the PCI core code */
-extern int __must_check __pci_enable_device(struct pci_dev *);
+extern int __must_check __pci_reenable_device(struct pci_dev *);
extern int pci_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
@@ -43,12 +43,8 @@ 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_PCI_MSI
-extern int pci_msi_quirk;
-#else
-#define pci_msi_quirk 0
-#endif
extern unsigned int pci_pm_d3_delay;
+
#ifdef CONFIG_PCI_MSI
void disable_msi_mode(struct pci_dev *dev, int pos, int type);
void pci_no_msi(void);
@@ -56,17 +52,15 @@ void pci_no_msi(void);
static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { }
static inline void pci_no_msi(void) { }
#endif
+
#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
int pci_save_msi_state(struct pci_dev *dev);
-int pci_save_msix_state(struct pci_dev *dev);
void pci_restore_msi_state(struct pci_dev *dev);
-void pci_restore_msix_state(struct pci_dev *dev);
#else
static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; }
-static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; }
static inline void pci_restore_msi_state(struct pci_dev *dev) {}
-static inline void pci_restore_msix_state(struct pci_dev *dev) {}
#endif
+
static inline int pci_no_d1d2(struct pci_dev *dev)
{
unsigned int parent_dstates = 0;
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 55866b6b26f..6f5fabbd14e 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -148,7 +148,7 @@ 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),
+ if (!(rpc = kmalloc(sizeof(struct aer_rpc),
GFP_KERNEL)))
return NULL;
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index b4da7954611..f17e7ed2b2a 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -90,7 +90,7 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
return -ENODEV;
pci_set_master(dev);
- if (!dev->irq) {
+ if (!dev->irq && dev->pin) {
printk(KERN_WARNING
"%s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS\n",
__FUNCTION__, dev->device, dev->vendor);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6a3c1e72890..2fe1d690eb1 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -144,6 +144,32 @@ static u32 pci_size(u32 base, u32 maxbase, u32 mask)
return size;
}
+static u64 pci_size64(u64 base, u64 maxbase, u64 mask)
+{
+ u64 size = mask & maxbase; /* Find the significant bits */
+ if (!size)
+ return 0;
+
+ /* Get the lowest of them to find the decode size, and
+ from that the extent. */
+ size = (size & ~(size-1)) - 1;
+
+ /* base == maxbase can be valid only if the BAR has
+ already been programmed with all 1s. */
+ if (base == maxbase && ((base | size) & mask) != mask)
+ return 0;
+
+ return size;
+}
+
+static inline int is_64bit_memory(u32 mask)
+{
+ if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
+ (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64))
+ return 1;
+ return 0;
+}
+
static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
unsigned int pos, reg, next;
@@ -151,6 +177,10 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
struct resource *res;
for(pos=0; pos<howmany; pos = next) {
+ u64 l64;
+ u64 sz64;
+ u32 raw_sz;
+
next = pos+1;
res = &dev->resource[pos];
res->name = pci_name(dev);
@@ -163,9 +193,16 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
continue;
if (l == 0xffffffff)
l = 0;
- if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+ raw_sz = sz;
+ if ((l & PCI_BASE_ADDRESS_SPACE) ==
+ PCI_BASE_ADDRESS_SPACE_MEMORY) {
sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
- if (!sz)
+ /*
+ * For 64bit prefetchable memory sz could be 0, if the
+ * real size is bigger than 4G, so we need to check
+ * szhi for that.
+ */
+ if (!is_64bit_memory(l) && !sz)
continue;
res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
@@ -178,30 +215,36 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
}
res->end = res->start + (unsigned long) sz;
res->flags |= pci_calc_resource_flags(l);
- if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
- == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+ if (is_64bit_memory(l)) {
u32 szhi, lhi;
+
pci_read_config_dword(dev, reg+4, &lhi);
pci_write_config_dword(dev, reg+4, ~0);
pci_read_config_dword(dev, reg+4, &szhi);
pci_write_config_dword(dev, reg+4, lhi);
- szhi = pci_size(lhi, szhi, 0xffffffff);
+ sz64 = ((u64)szhi << 32) | raw_sz;
+ l64 = ((u64)lhi << 32) | l;
+ sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK);
next++;
#if BITS_PER_LONG == 64
- res->start |= ((unsigned long) lhi) << 32;
- res->end = res->start + sz;
- if (szhi) {
- /* This BAR needs > 4GB? Wow. */
- res->end |= (unsigned long)szhi<<32;
+ if (!sz64) {
+ res->start = 0;
+ res->end = 0;
+ res->flags = 0;
+ continue;
}
+ res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK;
+ res->end = res->start + sz64;
#else
- if (szhi) {
- printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev));
+ if (sz64 > 0x100000000ULL) {
+ printk(KERN_ERR "PCI: Unable to handle 64-bit "
+ "BAR for device %s\n", pci_name(dev));
res->start = 0;
res->flags = 0;
} else if (lhi) {
/* 64-bit wide address, treat as disabled */
- pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
+ pci_write_config_dword(dev, reg,
+ l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
pci_write_config_dword(dev, reg+4, 0);
res->start = 0;
res->end = sz;
@@ -639,6 +682,8 @@ static void pci_read_irq(struct pci_dev *dev)
dev->irq = irq;
}
+#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
+
/**
* pci_setup_device - fill in class and map information of a device
* @dev: the device structure to fill
@@ -692,18 +737,18 @@ static int pci_setup_device(struct pci_dev * dev)
if ((progif & 1) == 0) {
dev->resource[0].start = 0x1F0;
dev->resource[0].end = 0x1F7;
- dev->resource[0].flags = IORESOURCE_IO;
+ dev->resource[0].flags = LEGACY_IO_RESOURCE;
dev->resource[1].start = 0x3F6;
dev->resource[1].end = 0x3F6;
- dev->resource[1].flags = IORESOURCE_IO;
+ dev->resource[1].flags = LEGACY_IO_RESOURCE;
}
if ((progif & 4) == 0) {
dev->resource[2].start = 0x170;
dev->resource[2].end = 0x177;
- dev->resource[2].flags = IORESOURCE_IO;
+ dev->resource[2].flags = LEGACY_IO_RESOURCE;
dev->resource[3].start = 0x376;
dev->resource[3].end = 0x376;
- dev->resource[3].flags = IORESOURCE_IO;
+ dev->resource[3].flags = LEGACY_IO_RESOURCE;
}
}
break;
@@ -900,7 +945,6 @@ pci_scan_single_device(struct pci_bus *bus, int devfn)
return NULL;
pci_device_add(dev, bus);
- pci_scan_msi_device(dev);
return dev;
}
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 99cf3337976..4a6760a3b31 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -23,7 +23,7 @@ static loff_t
proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
{
loff_t new = -1;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
mutex_lock(&inode->i_mutex);
switch (whence) {
@@ -48,7 +48,7 @@ proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
static ssize_t
proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
- const struct inode *ino = file->f_dentry->d_inode;
+ const struct inode *ino = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(ino);
struct pci_dev *dev = dp->data;
unsigned int pos = *ppos;
@@ -130,7 +130,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
static ssize_t
proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos)
{
- const struct inode *ino = file->f_dentry->d_inode;
+ const struct inode *ino = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(ino);
struct pci_dev *dev = dp->data;
int pos = *ppos;
@@ -245,7 +245,7 @@ static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned i
#ifdef HAVE_PCI_MMAP
static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(inode);
struct pci_dev *dev = dp->data;
struct pci_filp_private *fpriv = file->private_data;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 9ca9b9bf616..1e6eda25c0d 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -36,7 +36,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRID
/* Deal with broken BIOS'es that neglect to enable passive release,
which can cause problems in combination with the 82441FX/PPro MTRRs */
-static void __devinit quirk_passive_release(struct pci_dev *dev)
+static void quirk_passive_release(struct pci_dev *dev)
{
struct pci_dev *d = NULL;
unsigned char dlc;
@@ -53,6 +53,7 @@ static void __devinit quirk_passive_release(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release );
/* The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround
but VIA don't answer queries. If you happen to have good contacts at VIA
@@ -60,7 +61,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_pa
This appears to be BIOS not version dependent. So presumably there is a
chipset level fix */
-int isa_dma_bridge_buggy; /* Exported */
+int isa_dma_bridge_buggy;
+EXPORT_SYMBOL(isa_dma_bridge_buggy);
static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
{
@@ -82,6 +84,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_d
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs );
int pci_pci_problems;
+EXPORT_SYMBOL(pci_pci_problems);
/*
* Chipsets where PCI->PCI transfers vanish or hang
@@ -93,6 +96,8 @@ static void __devinit quirk_nopcipci(struct pci_dev *dev)
pci_pci_problems |= PCIPCI_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 );
static void __devinit quirk_nopciamd(struct pci_dev *dev)
{
@@ -104,9 +109,6 @@ static void __devinit quirk_nopciamd(struct pci_dev *dev)
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 );
/*
@@ -134,7 +136,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quir
* Updated based on further information from the site and also on
* information provided by VIA
*/
-static void __devinit quirk_vialatency(struct pci_dev *dev)
+static void quirk_vialatency(struct pci_dev *dev)
{
struct pci_dev *p;
u8 rev;
@@ -185,6 +187,10 @@ exit:
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency );
+/* Must restore this on a resume from RAM */
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency );
/*
* VIA Apollo VP3 needs ETBF on BT848/878
@@ -532,7 +538,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_vt8235
* TODO: When we have device-specific interrupt routers,
* this code will go away from quirks.
*/
-static void __devinit quirk_via_ioapic(struct pci_dev *dev)
+static void quirk_via_ioapic(struct pci_dev *dev)
{
u8 tmp;
@@ -548,6 +554,7 @@ static void __devinit quirk_via_ioapic(struct pci_dev *dev)
pci_write_config_byte (dev, 0x58, tmp);
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic );
/*
* VIA 8237: Some BIOSs don't set the 'Bypass APIC De-Assert Message' Bit.
@@ -555,7 +562,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_i
* Set this bit to get rid of cycle wastage.
* Otherwise uncritical.
*/
-static void __devinit quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev)
+static void quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev)
{
u8 misc_control2;
#define BYPASS_APIC_DEASSERT 8
@@ -567,6 +574,7 @@ static void __devinit quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_vt8237_bypass_apic_deassert);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_vt8237_bypass_apic_deassert);
/*
* The AMD io apic can hang the box when an apic irq is masked.
@@ -600,7 +608,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw );
#define AMD8131_revB0 0x11
#define AMD8131_MISC 0x40
#define AMD8131_NIOAMODE_BIT 0
-static void __init quirk_amd_8131_ioapic(struct pci_dev *dev)
+static void quirk_amd_8131_ioapic(struct pci_dev *dev)
{
unsigned char revid, tmp;
@@ -616,6 +624,7 @@ 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);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic);
#endif /* CONFIG_X86_IO_APIC */
@@ -641,48 +650,67 @@ static void __devinit quirk_via_acpi(struct pci_dev *d)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi );
+
/*
- * Via 686A/B: The PCI_INTERRUPT_LINE register for the on-chip
- * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature:
- * when written, it makes an internal connection to the PIC.
- * For these devices, this register is defined to be 4 bits wide.
- * Normally this is fine. However for IO-APIC motherboards, or
- * non-x86 architectures (yes Via exists on PPC among other places),
- * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
- * interrupts delivered properly.
- *
- * Some of the on-chip devices are actually '586 devices' so they are
- * listed here.
+ * VIA bridges which have VLink
*/
-static int via_irq_fixup_needed = -1;
+static int via_vlink_dev_lo = -1, via_vlink_dev_hi = 18;
-/*
- * 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 void quirk_via_bridge(struct pci_dev *dev)
+{
+ /* See what bridge we have and find the device ranges */
+ switch (dev->device) {
+ case PCI_DEVICE_ID_VIA_82C686:
+ /* The VT82C686 is special, it attaches to PCI and can have
+ any device number. All its subdevices are functions of
+ that single device. */
+ via_vlink_dev_lo = PCI_SLOT(dev->devfn);
+ via_vlink_dev_hi = PCI_SLOT(dev->devfn);
+ break;
+ case PCI_DEVICE_ID_VIA_8237:
+ case PCI_DEVICE_ID_VIA_8237A:
+ via_vlink_dev_lo = 15;
+ break;
+ case PCI_DEVICE_ID_VIA_8235:
+ via_vlink_dev_lo = 16;
+ break;
+ case PCI_DEVICE_ID_VIA_8231:
+ case PCI_DEVICE_ID_VIA_8233_0:
+ case PCI_DEVICE_ID_VIA_8233A:
+ case PCI_DEVICE_ID_VIA_8233C_0:
+ via_vlink_dev_lo = 17;
+ break;
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_0, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233A, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233C_0, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A, quirk_via_bridge);
+
+/**
+ * quirk_via_vlink - VIA VLink IRQ number update
+ * @dev: PCI device
+ *
+ * If the device we are dealing with is on a PIC IRQ we need to
+ * ensure that the IRQ line register which usually is not relevant
+ * for PCI cards, is actually written so that interrupts get sent
+ * to the right place.
+ * We only do this on systems where a VIA south bridge was detected,
+ * and only for VIA devices on the motherboard (see quirk_via_bridge
+ * above).
*/
-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)
+
+static void quirk_via_vlink(struct pci_dev *dev)
{
u8 irq, new_irq;
- if (via_irq_fixup_needed == -1)
- via_irq_fixup_needed = pci_dev_present(via_irq_fixup_tbl);
-
- if (!via_irq_fixup_needed)
+ /* Check if we have VLink at all */
+ if (via_vlink_dev_lo == -1)
return;
new_irq = dev->irq;
@@ -691,15 +719,23 @@ static void quirk_via_irq(struct pci_dev *dev)
if (!new_irq || new_irq > 15)
return;
+ /* Internal device ? */
+ if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) > via_vlink_dev_hi ||
+ PCI_SLOT(dev->devfn) < via_vlink_dev_lo)
+ return;
+
+ /* This is an internal VLink device on a PIC interrupt. The BIOS
+ ought to have set this but may not have, so we redo it */
+
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",
+ printk(KERN_INFO "PCI: VIA VLink IRQ fixup for %s, from %d to %d\n",
pci_name(dev), irq, new_irq);
udelay(15); /* unknown if delay really needed */
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
}
}
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_vlink);
/*
* VIA VT82C598 has its device ID settable and many BIOSes
@@ -720,13 +756,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt
* do this even if the Linux CardBus driver is not loaded, because
* the Linux i82365 driver does not (and should not) handle CardBus.
*/
-static void __devinit quirk_cardbus_legacy(struct pci_dev *dev)
+static void quirk_cardbus_legacy(struct pci_dev *dev)
{
if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class)
return;
pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0);
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
+DECLARE_PCI_FIXUP_RESUME(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
/*
* Following the PCI ordering rules is optional on the AMD762. I'm not
@@ -735,7 +772,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
* To be fair to AMD, it follows the spec by default, its BIOS people
* who turn it off!
*/
-static void __devinit quirk_amd_ordering(struct pci_dev *dev)
+static void quirk_amd_ordering(struct pci_dev *dev)
{
u32 pcic;
pci_read_config_dword(dev, 0x4C, &pcic);
@@ -749,6 +786,7 @@ static void __devinit quirk_amd_ordering(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering );
/*
* DreamWorks provided workaround for Dunord I-3000 problem
@@ -784,7 +822,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge
* datasheets found at http://www.national.com/ds/GX for info on what
* these bits do. <christer@weinigel.se>
*/
-static void __init quirk_mediagx_master(struct pci_dev *dev)
+static void quirk_mediagx_master(struct pci_dev *dev)
{
u8 reg;
pci_read_config_byte(dev, 0x41, &reg);
@@ -795,13 +833,14 @@ static void __init quirk_mediagx_master(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master );
/*
* Ensure C0 rev restreaming is off. This is normally done by
* the BIOS but in the odd case it is not the results are corruption
* hence the presence of a Linux check
*/
-static void __init quirk_disable_pxb(struct pci_dev *pdev)
+static void quirk_disable_pxb(struct pci_dev *pdev)
{
u16 config;
u8 rev;
@@ -817,7 +856,25 @@ static void __init quirk_disable_pxb(struct pci_dev *pdev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb );
+
+static void __devinit quirk_sb600_sata(struct pci_dev *pdev)
+{
+ /* set sb600 sata to ahci mode */
+ if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+ u8 tmp;
+
+ pci_read_config_byte(pdev, 0x40, &tmp);
+ pci_write_config_byte(pdev, 0x40, tmp|1);
+ pci_write_config_byte(pdev, 0x9, 1);
+ pci_write_config_byte(pdev, 0xa, 6);
+ pci_write_config_byte(pdev, 0x40, tmp);
+
+ pdev->class = PCI_CLASS_STORAGE_SATA_AHCI;
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_sb600_sata);
/*
* Serverworks CSB5 IDE does not fully support native mode
@@ -874,7 +931,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e
* runs everywhere at present we suppress the printk output in most
* irrelevant cases.
*/
-static void __init k8t_sound_hostbridge(struct pci_dev *dev)
+static void k8t_sound_hostbridge(struct pci_dev *dev)
{
unsigned char val;
@@ -893,8 +950,8 @@ static void __init k8t_sound_hostbridge(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
-#ifndef CONFIG_ACPI_SLEEP
/*
* On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge
* is not activated. The myth is that Asus said that they do not want the
@@ -906,12 +963,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_ho
* bridge. Unfortunately, this device has no subvendor/subdevice ID. So it
* becomes necessary to do this tweak in two steps -- I've chosen the Host
* bridge as trigger.
- *
- * Actually, leaving it unhidden and not redoing the quirk over suspend2ram
- * will cause thermal management to break down, and causing machine to
- * overheat.
*/
-static int __initdata asus_hides_smbus;
+static int asus_hides_smbus;
static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
{
@@ -924,47 +977,51 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x1626: /* L3C notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
switch(dev->subsystem_device) {
case 0x80b1: /* P4GE-V */
case 0x80b2: /* P4PE */
case 0x8093: /* P4B533-V */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
switch(dev->subsystem_device) {
case 0x8030: /* P4T533 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
switch (dev->subsystem_device) {
case 0x8070: /* P4G8X Deluxe */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
switch (dev->subsystem_device) {
case 0x80c9: /* PU-DLS */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
switch (dev->subsystem_device) {
case 0x1751: /* M2N notebook */
case 0x1821: /* M5N notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch (dev->subsystem_device) {
case 0x184b: /* W1N notebook */
case 0x186a: /* M6Ne notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+ switch (dev->subsystem_device) {
+ case 0x80f2: /* P4P800-X */
+ asus_hides_smbus = 1;
+ }
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
switch (dev->subsystem_device) {
case 0x1882: /* M6V notebook */
case 0x1977: /* A6VA notebook */
asus_hides_smbus = 1;
}
- }
} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) {
if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch(dev->subsystem_device) {
@@ -972,25 +1029,24 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x0890: /* HP Compaq nc6000 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
switch (dev->subsystem_device) {
case 0x12bc: /* HP D330L */
case 0x12bd: /* HP D530 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
switch (dev->subsystem_device) {
case 0x099c: /* HP Compaq nx6110 */
asus_hides_smbus = 1;
}
- }
} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) {
if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
switch(dev->subsystem_device) {
case 0x0001: /* Toshiba Satellite A40 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch(dev->subsystem_device) {
case 0x0001: /* Toshiba Tecra M2 */
asus_hides_smbus = 1;
@@ -1019,7 +1075,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, as
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge );
-static void __init asus_hides_smbus_lpc(struct pci_dev *dev)
+static void asus_hides_smbus_lpc(struct pci_dev *dev)
{
u16 val;
@@ -1042,8 +1098,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asu
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc );
-static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
+static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
{
u32 val, rcba;
void __iomem *base;
@@ -1059,20 +1121,28 @@ static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
printk(KERN_INFO "PCI: Enabled ICH6/i801 SMBus device\n");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 );
-
-#endif
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 );
/*
* SiS 96x south bridge: BIOS typically hides SMBus device...
*/
-static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
+static void quirk_sis_96x_smbus(struct pci_dev *dev)
{
u8 val = 0;
- printk(KERN_INFO "Enabling SiS 96x SMBus.\n");
- pci_read_config_byte(dev, 0x77, &val);
- pci_write_config_byte(dev, 0x77, val & ~0x10);
pci_read_config_byte(dev, 0x77, &val);
+ if (val & 0x10) {
+ printk(KERN_INFO "Enabling SiS 96x SMBus.\n");
+ pci_write_config_byte(dev, 0x77, val & ~0x10);
+ }
}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
/*
* ... This is further complicated by the fact that some SiS96x south
@@ -1082,11 +1152,9 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
*
* We can also enable the sis96x bit in the discovery register..
*/
-static int __devinitdata sis_96x_compatible = 0;
-
#define SIS_DETECT_REGISTER 0x40
-static void __init quirk_sis_503(struct pci_dev *dev)
+static void quirk_sis_503(struct pci_dev *dev)
{
u8 reg;
u16 devid;
@@ -1099,36 +1167,25 @@ static void __init quirk_sis_503(struct pci_dev *dev)
return;
}
- /* Make people aware that we changed the config.. */
- printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible);
-
/*
- * Ok, it now shows up as a 96x.. The 96x quirks are after
- * the 503 quirk in the quirk table, so they'll automatically
- * run and enable things like the SMBus device
+ * Ok, it now shows up as a 96x.. run the 96x quirk by
+ * hand in case it has already been processed.
+ * (depends on link order, which is apparently not guaranteed)
*/
dev->device = devid;
+ quirk_sis_96x_smbus(dev);
}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
-static void __init quirk_sis_96x_compatible(struct pci_dev *dev)
-{
- sis_96x_compatible = 1;
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
/*
* On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller
* and MC97 modem controller are disabled when a second PCI soundcard is
* present. This patch, tweaking the VT8237 ISA bridge, enables them.
* -- bjd
*/
-static void __init asus_hides_ac97_lpc(struct pci_dev *dev)
+static void asus_hides_ac97_lpc(struct pci_dev *dev)
{
u8 val;
int asus_hides_ac97 = 0;
@@ -1152,12 +1209,7 @@ static void __init asus_hides_ac97_lpc(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
-
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
@@ -1167,7 +1219,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_
* the PCI scanning.
*/
-static void __devinit quirk_jmicron_dualfn(struct pci_dev *pdev)
+static void quirk_jmicron_dualfn(struct pci_dev *pdev)
{
u32 conf;
u8 hdr;
@@ -1189,8 +1241,8 @@ static void __devinit quirk_jmicron_dualfn(struct pci_dev *pdev)
pci_read_config_dword(pdev, 0x40, &conf);
/* Enable dual function mode, AHCI on fn 0, IDE fn1 */
/* Set the class codes correctly and then direct IDE 0 */
- conf &= ~0x000F0200; /* Clear bit 9 and 16-19 */
- conf |= 0x00C20002; /* Set bit 1, 17, 22, 23 */
+ conf &= ~0x000FF200; /* Clear bit 9 and 12-19 */
+ conf |= 0x00C2A102; /* Set 1, 8, 13, 15, 17, 22, 23 */
pci_write_config_dword(pdev, 0x40, conf);
/* Reconfigure so that the PCI scanner discovers the
@@ -1203,8 +1255,8 @@ static void __devinit quirk_jmicron_dualfn(struct pci_dev *pdev)
break;
}
}
-
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
#endif
@@ -1346,6 +1398,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_co
int pcie_mch_quirk;
+EXPORT_SYMBOL(pcie_mch_quirk);
static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
{
@@ -1407,6 +1460,24 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2609, quirk_intel_pcie_pm);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
+/*
+ * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
+ * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
+ * Re-allocate the region if needed...
+ */
+static void __init quirk_tc86c001_ide(struct pci_dev *dev)
+{
+ struct resource *r = &dev->resource[0];
+
+ if (r->start & 0x8) {
+ r->start = 0;
+ r->end = 0xf;
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
+ PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+ quirk_tc86c001_ide);
+
static void __devinit quirk_netmos(struct pci_dev *dev)
{
unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
@@ -1532,6 +1603,8 @@ extern struct pci_fixup __start_pci_fixups_final[];
extern struct pci_fixup __end_pci_fixups_final[];
extern struct pci_fixup __start_pci_fixups_enable[];
extern struct pci_fixup __end_pci_fixups_enable[];
+extern struct pci_fixup __start_pci_fixups_resume[];
+extern struct pci_fixup __end_pci_fixups_resume[];
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
@@ -1559,12 +1632,18 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
end = __end_pci_fixups_enable;
break;
+ case pci_fixup_resume:
+ start = __start_pci_fixups_resume;
+ end = __end_pci_fixups_resume;
+ break;
+
default:
/* stupid compiler warning, you would think with an enum... */
return;
}
pci_do_fixups(dev, start, end);
}
+EXPORT_SYMBOL(pci_fixup_device);
/* Enable 1k I/O space granularity on the Intel P64H2 */
static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
@@ -1592,11 +1671,36 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io);
+/* Fix the IOBL_ADR for 1k I/O space granularity on the Intel P64H2
+ * The IOBL_ADR gets re-written to 4k boundaries in pci_setup_bridge()
+ * in drivers/pci/setup-bus.c
+ */
+static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev)
+{
+ u16 en1k, iobl_adr, iobl_adr_1k;
+ struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES;
+
+ pci_read_config_word(dev, 0x40, &en1k);
+
+ if (en1k & 0x200) {
+ pci_read_config_word(dev, PCI_IO_BASE, &iobl_adr);
+
+ iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00);
+
+ if (iobl_adr != iobl_adr_1k) {
+ printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n",
+ iobl_adr,iobl_adr_1k);
+ pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k);
+ }
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io_fix_iobl);
+
/* Under some circumstances, AER is not linked with extended capabilities.
* Force it to be linked by setting the corresponding control bit in the
* config space.
*/
-static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev)
+static void quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev)
{
uint8_t b;
if (pci_read_config_byte(dev, 0xf41, &b) == 0) {
@@ -1610,11 +1714,10 @@ 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);
+DECLARE_PCI_FIXUP_RESUME(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.
@@ -1623,8 +1726,8 @@ int pci_msi_quirk;
*/
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");
+ pci_no_msi();
+ printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n");
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi);
@@ -1644,19 +1747,23 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_
* 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 */
+ int pos, ttl = 48;
+
+ pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+ while (pos && ttl--) {
+ u8 flags;
+
+ if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+ &flags) == 0)
+ {
+ printk(KERN_INFO "PCI: Found %s HT MSI Mapping on %s\n",
+ flags & HT_MSI_FLAGS_ENABLE ?
+ "enabled" : "disabled", pci_name(dev));
+ return (flags & HT_MSI_FLAGS_ENABLE) != 0;
}
+
+ pos = pci_find_next_ht_capability(dev, pos,
+ HT_CAPTYPE_MSI_MAPPING);
}
return 0;
}
@@ -1688,8 +1795,9 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
* 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)) {
+ if (!pdev)
+ return;
+ if (!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));
@@ -1700,8 +1808,3 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
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);
-#endif
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 2f13eba5d5a..ff98eaddaa7 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -193,6 +193,15 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor,
struct pci_dev *dev;
WARN_ON(in_interrupt());
+
+ /*
+ * pci_find_subsys() can be called on the ide_setup() path, super-early
+ * in boot. But the down_read() will enable local interrupts, which
+ * can cause some machines to crash. So here we detect and flag that
+ * situation and bail out early.
+ */
+ if (unlikely(list_empty(&pci_devices)))
+ return NULL;
down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;
@@ -259,6 +268,15 @@ pci_get_subsys(unsigned int vendor, unsigned int device,
struct pci_dev *dev;
WARN_ON(in_interrupt());
+
+ /*
+ * pci_get_subsys() can potentially be called by drivers super-early
+ * in boot. But the down_read() will enable local interrupts, which
+ * can cause some machines to crash. So here we detect and flag that
+ * situation and bail out early.
+ */
+ if (unlikely(list_empty(&pci_devices)))
+ return NULL;
down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;
@@ -340,43 +358,6 @@ exit:
}
/**
- * pci_find_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_find_device().
- * If a PCI device is found with a matching @vendor and @device, 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 previous device
- * on the global list.
- */
-struct pci_dev *
-pci_find_device_reverse(unsigned int vendor, unsigned int device, const 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:
- up_read(&pci_bus_sem);
- return dev;
-}
-
-/**
* pci_get_class - begin or continue searching for a PCI device by class
* @class: search for a PCI device with this class designation
* @from: Previous PCI device found in search, or %NULL for new search.
@@ -413,6 +394,24 @@ exit:
return dev;
}
+const struct pci_device_id *pci_find_present(const struct pci_device_id *ids)
+{
+ struct pci_dev *dev;
+ const struct pci_device_id *found = NULL;
+
+ WARN_ON(in_interrupt());
+ down_read(&pci_bus_sem);
+ while (ids->vendor || ids->subvendor || ids->class_mask) {
+ list_for_each_entry(dev, &pci_devices, global_list) {
+ if ((found = pci_match_one_device(ids, dev)) != NULL)
+ break;
+ }
+ ids++;
+ }
+ up_read(&pci_bus_sem);
+ return found;
+}
+
/**
* pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
* @ids: A pointer to a null terminated list of struct pci_device_id structures
@@ -426,28 +425,13 @@ exit:
*/
int pci_dev_present(const struct pci_device_id *ids)
{
- struct pci_dev *dev;
- int found = 0;
-
- WARN_ON(in_interrupt());
- down_read(&pci_bus_sem);
- while (ids->vendor || ids->subvendor || ids->class_mask) {
- list_for_each_entry(dev, &pci_devices, global_list) {
- if (pci_match_one_device(ids, dev)) {
- found = 1;
- goto exit;
- }
- }
- ids++;
- }
-exit:
- up_read(&pci_bus_sem);
- return found;
+ return pci_find_present(ids) == NULL ? 0 : 1;
}
+
EXPORT_SYMBOL(pci_dev_present);
+EXPORT_SYMBOL(pci_find_present);
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);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 8f7bcf56f14..89f3036f0de 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -41,7 +41,7 @@
* have a P2P bridge below a cardbus bridge, we need 4K.
*/
#define CARDBUS_IO_SIZE (256)
-#define CARDBUS_MEM_SIZE (32*1024*1024)
+#define CARDBUS_MEM_SIZE (64*1024*1024)
static void __devinit
pbus_assign_resources_sorted(struct pci_bus *bus)
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index ab78e4bbdd8..cb4ced3560e 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -33,11 +33,22 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
u32 new, check, mask;
int reg;
- /* Ignore resources for unimplemented BARs and unused resource slots
- for 64 bit BARs. */
+ /*
+ * Ignore resources for unimplemented BARs and unused resource slots
+ * for 64 bit BARs.
+ */
if (!res->flags)
return;
+ /*
+ * Ignore non-moveable resources. This might be legacy resources for
+ * which no functional BAR register exists or another important
+ * system resource we should better not move around in system address
+ * space.
+ */
+ if (res->flags & IORESOURCE_PCI_FIXED)
+ return;
+
pcibios_resource_to_bus(dev, &region, res);
pr_debug(" got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
@@ -212,6 +223,10 @@ pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
resource_size_t r_align;
r = &dev->resource[i];
+
+ if (r->flags & IORESOURCE_PCI_FIXED)
+ continue;
+
r_align = r->end - r->start;
if (!(r->flags) || r->parent)
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index 52d4a38b366..3334f22a86c 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -230,7 +230,7 @@ static int __init at91_cf_probe(struct platform_device *pdev)
if (!io)
return -ENODEV;
- cf = kcalloc(1, sizeof *cf, GFP_KERNEL);
+ cf = kzalloc(sizeof *cf, GFP_KERNEL);
if (!cf)
return -ENOMEM;
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 606a4674033..ac004248324 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -110,7 +110,7 @@ int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state)
down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
- if (socket->dev.dev != dev)
+ if (socket->dev.parent != dev)
continue;
mutex_lock(&socket->skt_mutex);
socket_suspend(socket);
@@ -128,7 +128,7 @@ int pcmcia_socket_dev_resume(struct device *dev)
down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
- if (socket->dev.dev != dev)
+ if (socket->dev.parent != dev)
continue;
mutex_lock(&socket->skt_mutex);
socket_resume(socket);
@@ -143,12 +143,12 @@ EXPORT_SYMBOL(pcmcia_socket_dev_resume);
struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt)
{
- struct class_device *cl_dev = class_device_get(&skt->dev);
- if (!cl_dev)
+ struct device *dev = get_device(&skt->dev);
+ if (!dev)
return NULL;
- skt = class_get_devdata(cl_dev);
+ skt = dev_get_drvdata(dev);
if (!try_module_get(skt->owner)) {
- class_device_put(&skt->dev);
+ put_device(&skt->dev);
return NULL;
}
return (skt);
@@ -159,14 +159,14 @@ EXPORT_SYMBOL(pcmcia_get_socket);
void pcmcia_put_socket(struct pcmcia_socket *skt)
{
module_put(skt->owner);
- class_device_put(&skt->dev);
+ put_device(&skt->dev);
}
EXPORT_SYMBOL(pcmcia_put_socket);
-static void pcmcia_release_socket(struct class_device *class_dev)
+static void pcmcia_release_socket(struct device *dev)
{
- struct pcmcia_socket *socket = class_get_devdata(class_dev);
+ struct pcmcia_socket *socket = dev_get_drvdata(dev);
complete(&socket->socket_released);
}
@@ -181,7 +181,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
struct task_struct *tsk;
int ret;
- if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops)
+ if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops)
return -EINVAL;
cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops);
@@ -226,9 +226,9 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
#endif
/* set proper values in socket->dev */
- socket->dev.class_data = socket;
+ dev_set_drvdata(&socket->dev, socket);
socket->dev.class = &pcmcia_socket_class;
- snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
+ snprintf(socket->dev.bus_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
/* base address = 0, map = 0 */
socket->cis_mem.flags = 0;
@@ -640,7 +640,7 @@ static int pccardd(void *__skt)
skt->ops->set_socket(skt, &skt->socket);
/* register with the device core */
- ret = class_device_register(&skt->dev);
+ ret = device_register(&skt->dev);
if (ret) {
printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",
skt);
@@ -689,7 +689,7 @@ static int pccardd(void *__skt)
remove_wait_queue(&skt->thread_wait, &wait);
/* remove from the device core */
- class_device_unregister(&skt->dev);
+ device_unregister(&skt->dev);
return 0;
}
@@ -904,7 +904,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
EXPORT_SYMBOL(pcmcia_insert_card);
-static int pcmcia_socket_uevent(struct class_device *dev, char **envp,
+static int pcmcia_socket_uevent(struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size)
{
struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
@@ -930,8 +930,8 @@ static void pcmcia_release_socket_class(struct class *data)
struct class pcmcia_socket_class = {
.name = "pcmcia_socket",
- .uevent = pcmcia_socket_uevent,
- .release = pcmcia_release_socket,
+ .dev_uevent = pcmcia_socket_uevent,
+ .dev_release = pcmcia_release_socket,
.class_release = pcmcia_release_socket_class,
};
EXPORT_SYMBOL(pcmcia_socket_class);
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index f573ea04db6..9fa207e3c7b 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -142,7 +142,7 @@ struct pcmcia_callback{
int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
-#define cs_socket_name(skt) ((skt)->dev.class_id)
+#define cs_socket_name(skt) ((skt)->dev.bus_id)
#ifdef DEBUG
extern int cs_debug_level(int);
@@ -158,6 +158,6 @@ extern int cs_debug_level(int);
#endif
#define cs_err(skt, fmt, arg...) \
- printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.class_id , ## arg)
+ printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.bus_id , ## arg)
#endif /* _LINUX_CS_INTERNAL_H */
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 7355eb455a8..18e111e1233 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -572,7 +572,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
p_dev->func = function;
p_dev->dev.bus = &pcmcia_bus_type;
- p_dev->dev.parent = s->dev.dev;
+ p_dev->dev.parent = s->dev.parent;
p_dev->dev.release = pcmcia_release_dev;
bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
@@ -1328,10 +1328,10 @@ static struct pcmcia_callback pcmcia_bus_callback = {
.resume = pcmcia_bus_resume,
};
-static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev,
+static int __devinit pcmcia_bus_add_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *socket = class_get_devdata(class_dev);
+ struct pcmcia_socket *socket = dev_get_drvdata(dev);
int ret;
socket = pcmcia_get_socket(socket);
@@ -1364,10 +1364,10 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev,
return 0;
}
-static void pcmcia_bus_remove_socket(struct class_device *class_dev,
+static void pcmcia_bus_remove_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *socket = class_get_devdata(class_dev);
+ struct pcmcia_socket *socket = dev_get_drvdata(dev);
if (!socket)
return;
@@ -1389,8 +1389,8 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev,
/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
static struct class_interface pcmcia_bus_interface = {
.class = &pcmcia_socket_class,
- .add = &pcmcia_bus_add_socket,
- .remove = &pcmcia_bus_remove_socket,
+ .add_dev = &pcmcia_bus_add_socket,
+ .remove_dev = &pcmcia_bus_remove_socket,
};
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index c2ea07aa7a1..df21e2d16f8 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -161,7 +161,7 @@ static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_de
pci_set_drvdata(dev, &sockets[i].socket);
for (i = 0; i<socket_count; i++) {
- sockets[i].socket.dev.dev = &dev->dev;
+ sockets[i].socket.dev.parent = &dev->dev;
sockets[i].socket.ops = &i82092aa_operations;
sockets[i].socket.resource_ops = &pccard_nonstatic_ops;
ret = pcmcia_register_socket(&sockets[i].socket);
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index ea74f98a735..72ff2f615b3 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -1298,7 +1298,7 @@ static int __init init_i82365(void)
/* register sockets with the pcmcia core */
for (i = 0; i < sockets; i++) {
- socket[i].socket.dev.dev = &i82365_device->dev;
+ socket[i].socket.dev.parent = &i82365_device->dev;
socket[i].socket.ops = &pcic_operations;
socket[i].socket.resource_ops = &pccard_nonstatic_ops;
socket[i].socket.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index bbf025874d0..4dbef076237 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -722,7 +722,7 @@ static int __init init_m32r_pcc(void)
/* Set up interrupt handler(s) */
for (i = 0 ; i < pcc_sockets ; i++) {
- socket[i].socket.dev.dev = &pcc_device.dev;
+ socket[i].socket.dev.parent = &pcc_device.dev;
socket[i].socket.ops = &pcc_operations;
socket[i].socket.resource_ops = &pccard_static_ops;
socket[i].socket.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index 06bf7f48836..e65a6b8188f 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -220,7 +220,7 @@ static int __devinit omap_cf_probe(struct device *dev)
if (irq < 0)
return -EINVAL;
- cf = kcalloc(1, sizeof *cf, GFP_KERNEL);
+ cf = kzalloc(sizeof *cf, GFP_KERNEL);
if (!cf)
return -ENOMEM;
init_timer(&cf->timer);
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index d077870c673..88494149e91 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -59,7 +59,6 @@ typedef struct user_info_t {
#ifdef DEBUG
extern int ds_pc_debug;
-#define cs_socket_name(skt) ((skt)->dev.class_id)
#define ds_dbg(lvl, fmt, arg...) do { \
if (ds_pc_debug >= lvl) \
@@ -486,7 +485,7 @@ static ssize_t ds_read(struct file *file, char __user *buf,
user_info_t *user;
int ret;
- ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
+ ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
if (count < 4)
return -EINVAL;
@@ -511,7 +510,7 @@ static ssize_t ds_read(struct file *file, char __user *buf,
static ssize_t ds_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
+ ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
if (count != 4)
return -EINVAL;
@@ -529,7 +528,7 @@ static u_int ds_poll(struct file *file, poll_table *wait)
struct pcmcia_socket *s;
user_info_t *user;
- ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
+ ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
user = file->private_data;
if (CHECK_USER(user))
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index b9201c2ec38..0ce39de834c 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -48,7 +48,6 @@ static u8 pcmcia_used_irq[NR_IRQS];
#ifdef DEBUG
extern int ds_pc_debug;
-#define cs_socket_name(skt) ((skt)->dev.class_id)
#define ds_dbg(skt, lvl, fmt, arg...) do { \
if (ds_pc_debug >= lvl) \
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 360c2489654..dd0ddf19ee5 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -682,7 +682,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
socket[i].socket.ops = &pd6729_operations;
socket[i].socket.resource_ops = &pccard_nonstatic_ops;
- socket[i].socket.dev.dev = &dev->dev;
+ socket[i].socket.dev.parent = &dev->dev;
socket[i].socket.driver_data = &socket[i];
}
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index c3176b16b7b..bfcaad6021c 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -616,7 +616,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
static struct resource *nonstatic_find_io_region(unsigned long base, int num,
unsigned long align, struct pcmcia_socket *s)
{
- struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id);
+ struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.bus_id);
struct socket_data *s_data = s->resource_data;
struct pcmcia_align_data data;
unsigned long min = base;
@@ -650,7 +650,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
u_long align, int low, struct pcmcia_socket *s)
{
- struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id);
+ struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.bus_id);
struct socket_data *s_data = s->resource_data;
struct pcmcia_align_data data;
unsigned long min, max;
@@ -897,9 +897,10 @@ EXPORT_SYMBOL(pccard_nonstatic_ops);
/* sysfs interface to the resource database */
-static ssize_t show_io_db(struct class_device *class_dev, char *buf)
+static ssize_t show_io_db(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
struct socket_data *data;
struct resource_map *p;
ssize_t ret = 0;
@@ -920,9 +921,11 @@ static ssize_t show_io_db(struct class_device *class_dev, char *buf)
return (ret);
}
-static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size_t count)
+static ssize_t store_io_db(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
unsigned long start_addr, end_addr;
unsigned int add = ADD_MANAGED_RESOURCE;
ssize_t ret = 0;
@@ -947,11 +950,12 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
+static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
-static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
+static ssize_t show_mem_db(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
struct socket_data *data;
struct resource_map *p;
ssize_t ret = 0;
@@ -972,9 +976,11 @@ static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
return (ret);
}
-static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, size_t count)
+static ssize_t store_mem_db(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
unsigned long start_addr, end_addr;
unsigned int add = ADD_MANAGED_RESOURCE;
ssize_t ret = 0;
@@ -999,25 +1005,25 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
+static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
-static struct class_device_attribute *pccard_rsrc_attributes[] = {
- &class_device_attr_available_resources_io,
- &class_device_attr_available_resources_mem,
+static struct device_attribute *pccard_rsrc_attributes[] = {
+ &dev_attr_available_resources_io,
+ &dev_attr_available_resources_mem,
NULL,
};
-static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev,
+static int __devinit pccard_sysfs_add_rsrc(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
- struct class_device_attribute **attr;
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
+ struct device_attribute **attr;
int ret = 0;
if (s->resource_ops != &pccard_nonstatic_ops)
return 0;
for (attr = pccard_rsrc_attributes; *attr; attr++) {
- ret = class_device_create_file(class_dev, *attr);
+ ret = device_create_file(dev, *attr);
if (ret)
break;
}
@@ -1025,23 +1031,23 @@ static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev,
return ret;
}
-static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev,
+static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
- struct class_device_attribute **attr;
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
+ struct device_attribute **attr;
if (s->resource_ops != &pccard_nonstatic_ops)
return;
for (attr = pccard_rsrc_attributes; *attr; attr++)
- class_device_remove_file(class_dev, *attr);
+ device_remove_file(dev, *attr);
}
static struct class_interface pccard_rsrc_interface = {
.class = &pcmcia_socket_class,
- .add = &pccard_sysfs_add_rsrc,
- .remove = __devexit_p(&pccard_sysfs_remove_rsrc),
+ .add_dev = &pccard_sysfs_add_rsrc,
+ .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
};
static int __init nonstatic_sysfs_init(void)
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index e433704e026..d2a3bea55de 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -478,10 +478,10 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i
*
* Returns: the number of characters added to the buffer
*/
-static ssize_t show_status(struct class_device *class_dev, char *buf)
+static ssize_t show_status(struct device *dev, char *buf)
{
struct soc_pcmcia_socket *skt =
- container_of(class_dev, struct soc_pcmcia_socket, socket.dev);
+ container_of(dev, struct soc_pcmcia_socket, socket.dev);
char *p = buf;
p+=sprintf(p, "slot : %d\n", skt->nr);
@@ -747,7 +747,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
add_timer(&skt->poll_timer);
- class_device_create_file(&skt->socket.dev, &class_device_attr_status);
+ device_create_file(&skt->socket.dev, &device_attr_status);
}
dev_set_drvdata(dev, sinfo);
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index b005602d6b5..ea5765c3bdc 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -40,7 +40,8 @@
#define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
-static ssize_t pccard_show_type(struct class_device *dev, char *buf)
+static ssize_t pccard_show_type(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
@@ -50,9 +51,10 @@ static ssize_t pccard_show_type(struct class_device *dev, char *buf)
return sprintf(buf, "32-bit\n");
return sprintf(buf, "16-bit\n");
}
-static CLASS_DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
+static DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
-static ssize_t pccard_show_voltage(struct class_device *dev, char *buf)
+static ssize_t pccard_show_voltage(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
@@ -63,28 +65,31 @@ static ssize_t pccard_show_voltage(struct class_device *dev, char *buf)
s->socket.Vcc % 10);
return sprintf(buf, "X.XV\n");
}
-static CLASS_DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
+static DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
-static ssize_t pccard_show_vpp(struct class_device *dev, char *buf)
+static ssize_t pccard_show_vpp(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10);
}
-static CLASS_DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
+static DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
-static ssize_t pccard_show_vcc(struct class_device *dev, char *buf)
+static ssize_t pccard_show_vcc(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10);
}
-static CLASS_DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
+static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
-static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t ret;
struct pcmcia_socket *s = to_socket(dev);
@@ -96,16 +101,20 @@ static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, si
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
+static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
-static ssize_t pccard_show_card_pm_state(struct class_device *dev, char *buf)
+static ssize_t pccard_show_card_pm_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
return sprintf(buf, "%s\n", s->state & SOCKET_SUSPEND ? "off" : "on");
}
-static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_card_pm_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t ret = -EINVAL;
struct pcmcia_socket *s = to_socket(dev);
@@ -120,9 +129,11 @@ static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *
return ret ? -ENODEV : count;
}
-static CLASS_DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
+static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
-static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_eject(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t ret;
struct pcmcia_socket *s = to_socket(dev);
@@ -134,16 +145,20 @@ static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, siz
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
+static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
-static ssize_t pccard_show_irq_mask(struct class_device *dev, char *buf)
+static ssize_t pccard_show_irq_mask(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
return sprintf(buf, "0x%04x\n", s->irq_mask);
}
-static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_irq_mask(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t ret;
struct pcmcia_socket *s = to_socket(dev);
@@ -161,16 +176,19 @@ static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf,
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
+static DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
-static ssize_t pccard_show_resource(struct class_device *dev, char *buf)
+static ssize_t pccard_show_resource(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no");
}
-static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_resource(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
unsigned long flags;
struct pcmcia_socket *s = to_socket(dev);
@@ -196,7 +214,7 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf,
return count;
}
-static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count)
@@ -279,7 +297,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size
if (off + count > size)
count = size - off;
- s = to_socket(container_of(kobj, struct class_device, kobj));
+ s = to_socket(container_of(kobj, struct device, kobj));
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
@@ -296,7 +314,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size
static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
- struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj));
+ struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));
cisdump_t *cis;
int error;
@@ -335,16 +353,16 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz
}
-static struct class_device_attribute *pccard_socket_attributes[] = {
- &class_device_attr_card_type,
- &class_device_attr_card_voltage,
- &class_device_attr_card_vpp,
- &class_device_attr_card_vcc,
- &class_device_attr_card_insert,
- &class_device_attr_card_pm_state,
- &class_device_attr_card_eject,
- &class_device_attr_card_irq_mask,
- &class_device_attr_available_resources_setup_done,
+static struct device_attribute *pccard_socket_attributes[] = {
+ &dev_attr_card_type,
+ &dev_attr_card_voltage,
+ &dev_attr_card_vpp,
+ &dev_attr_card_vcc,
+ &dev_attr_card_insert,
+ &dev_attr_card_pm_state,
+ &dev_attr_card_eject,
+ &dev_attr_card_irq_mask,
+ &dev_attr_available_resources_setup_done,
NULL,
};
@@ -355,35 +373,35 @@ static struct bin_attribute pccard_cis_attr = {
.write = pccard_store_cis,
};
-static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev,
+static int __devinit pccard_sysfs_add_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct class_device_attribute **attr;
+ struct device_attribute **attr;
int ret = 0;
for (attr = pccard_socket_attributes; *attr; attr++) {
- ret = class_device_create_file(class_dev, *attr);
+ ret = device_create_file(dev, *attr);
if (ret)
break;
}
if (!ret)
- ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr);
+ ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
return ret;
}
-static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev,
+static void __devexit pccard_sysfs_remove_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct class_device_attribute **attr;
+ struct device_attribute **attr;
- sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr);
+ sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
for (attr = pccard_socket_attributes; *attr; attr++)
- class_device_remove_file(class_dev, *attr);
+ device_remove_file(dev, *attr);
}
struct class_interface pccard_sysfs_interface = {
.class = &pcmcia_socket_class,
- .add = &pccard_sysfs_add_socket,
- .remove = __devexit_p(&pccard_sysfs_remove_socket),
+ .add_dev = &pccard_sysfs_add_socket,
+ .remove_dev = __devexit_p(&pccard_sysfs_remove_socket),
};
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 2d2f415f80a..c158cf38b9d 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -512,7 +512,7 @@ static int __init init_tcic(void)
for (i = 0; i < sockets; i++) {
socket_table[i].socket.ops = &tcic_operations;
socket_table[i].socket.resource_ops = &pccard_nonstatic_ops;
- socket_table[i].socket.dev.dev = &tcic_device.dev;
+ socket_table[i].socket.dev.parent = &tcic_device.dev;
ret = pcmcia_register_socket(&socket_table[i].socket);
if (ret && i)
pcmcia_unregister_socket(&socket_table[0].socket);
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index da471bddc97..a61d768f6e0 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -1104,7 +1104,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
/* prepare pcmcia_socket */
socket->socket.ops = &yenta_socket_operations;
socket->socket.resource_ops = &pccard_nonstatic_ops;
- socket->socket.dev.dev = &dev->dev;
+ socket->socket.dev.parent = &dev->dev;
socket->socket.driver_data = socket;
socket->socket.owner = THIS_MODULE;
socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 3ac5b123215..a0b158704ca 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -395,7 +395,7 @@ static void isapnp_parse_id(struct pnp_dev * dev, unsigned short vendor, unsigne
struct pnp_id * id;
if (!dev)
return;
- id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
+ id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
if (!id)
return;
sprintf(id->id, "%c%c%c%x%x%x%x",
@@ -419,7 +419,7 @@ static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int si
struct pnp_dev *dev;
isapnp_peek(tmp, size);
- dev = kcalloc(1, sizeof(struct pnp_dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
if (!dev)
return NULL;
dev->number = number;
@@ -450,7 +450,7 @@ static void __init isapnp_parse_irq_resource(struct pnp_option *option,
unsigned long bits;
isapnp_peek(tmp, size);
- irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
+ irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
bits = (tmp[1] << 8) | tmp[0];
@@ -474,7 +474,7 @@ static void __init isapnp_parse_dma_resource(struct pnp_option *option,
struct pnp_dma *dma;
isapnp_peek(tmp, size);
- dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
+ dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
if (!dma)
return;
dma->map = tmp[0];
@@ -494,7 +494,7 @@ static void __init isapnp_parse_port_resource(struct pnp_option *option,
struct pnp_port *port;
isapnp_peek(tmp, size);
- port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
+ port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = (tmp[2] << 8) | tmp[1];
@@ -517,7 +517,7 @@ static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,
struct pnp_port *port;
isapnp_peek(tmp, size);
- port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
+ port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = port->max = (tmp[1] << 8) | tmp[0];
@@ -539,7 +539,7 @@ static void __init isapnp_parse_mem_resource(struct pnp_option *option,
struct pnp_mem *mem;
isapnp_peek(tmp, size);
- mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = ((tmp[2] << 8) | tmp[1]) << 8;
@@ -562,7 +562,7 @@ static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
struct pnp_mem *mem;
isapnp_peek(tmp, size);
- mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
@@ -584,7 +584,7 @@ static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
struct pnp_mem *mem;
isapnp_peek(tmp, size);
- mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = mem->max = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
@@ -829,7 +829,7 @@ static unsigned char __init isapnp_checksum(unsigned char *data)
static void isapnp_parse_card_id(struct pnp_card * card, unsigned short vendor, unsigned short device)
{
- struct pnp_id * id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
+ struct pnp_id * id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
if (!id)
return;
sprintf(id->id, "%c%c%c%x%x%x%x",
@@ -865,7 +865,7 @@ static int __init isapnp_build_device_list(void)
header[4], header[5], header[6], header[7], header[8]);
printk(KERN_DEBUG "checksum = 0x%x\n", checksum);
#endif
- if ((card = kcalloc(1, sizeof(struct pnp_card), GFP_KERNEL)) == NULL)
+ if ((card = kzalloc(sizeof(struct pnp_card), GFP_KERNEL)) == NULL)
continue;
card->number = csn;
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
index 958c11bedd0..d21f3c1e72f 100644
--- a/drivers/pnp/isapnp/proc.c
+++ b/drivers/pnp/isapnp/proc.c
@@ -56,7 +56,7 @@ static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
static ssize_t isapnp_proc_bus_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
- struct inode *ino = file->f_dentry->d_inode;
+ struct inode *ino = file->f_path.dentry->d_inode;
struct proc_dir_entry *dp = PDE(ino);
struct pnp_dev *dev = dp->data;
int pos = *ppos;
diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig
index b1854171b96..ad27e5e0101 100644
--- a/drivers/pnp/pnpacpi/Kconfig
+++ b/drivers/pnp/pnpacpi/Kconfig
@@ -2,8 +2,8 @@
# Plug and Play ACPI configuration
#
config PNPACPI
- bool "Plug and Play ACPI support (EXPERIMENTAL)"
- depends on PNP && ACPI && EXPERIMENTAL
+ bool "Plug and Play ACPI support"
+ depends on PNP && ACPI
default y
---help---
Linux uses the PNPACPI to autodetect built-in
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 6cf34a63c79..62eda5d5902 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -139,7 +139,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
return 0;
pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
- dev = kcalloc(1, sizeof(struct pnp_dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
if (!dev) {
pnp_err("Out of memory");
return -ENOMEM;
@@ -169,7 +169,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
dev->number = num;
/* set the initial values for the PnP device */
- dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
+ dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
goto err;
pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
@@ -201,7 +201,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
for (i = 0; i < cid_list->count; i++) {
if (!ispnpidacpi(cid_list->id[i].value))
continue;
- dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
+ dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
continue;
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 379048fdf05..7a535542fe9 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -298,7 +298,7 @@ static void pnpacpi_parse_dma_option(struct pnp_option *option, struct acpi_reso
if (p->channel_count == 0)
return;
- dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
+ dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
if (!dma)
return;
@@ -354,7 +354,7 @@ static void pnpacpi_parse_irq_option(struct pnp_option *option,
if (p->interrupt_count == 0)
return;
- irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
+ irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
@@ -375,7 +375,7 @@ static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
if (p->interrupt_count == 0)
return;
- irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
+ irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
@@ -396,7 +396,7 @@ pnpacpi_parse_port_option(struct pnp_option *option,
if (io->address_length == 0)
return;
- port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
+ port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = io->minimum;
@@ -417,7 +417,7 @@ pnpacpi_parse_fixed_port_option(struct pnp_option *option,
if (io->address_length == 0)
return;
- port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
+ port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = port->max = io->address;
@@ -436,7 +436,7 @@ pnpacpi_parse_mem24_option(struct pnp_option *option,
if (p->address_length == 0)
return;
- mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = p->minimum;
@@ -459,7 +459,7 @@ pnpacpi_parse_mem32_option(struct pnp_option *option,
if (p->address_length == 0)
return;
- mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = p->minimum;
@@ -482,7 +482,7 @@ pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
if (p->address_length == 0)
return;
- mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = mem->max = p->address;
@@ -514,7 +514,7 @@ pnpacpi_parse_address_option(struct pnp_option *option, struct acpi_resource *r)
return;
if (p->resource_type == ACPI_MEMORY_RANGE) {
- mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = mem->max = p->minimum;
@@ -524,7 +524,7 @@ pnpacpi_parse_address_option(struct pnp_option *option, struct acpi_resource *r)
ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE : 0;
pnp_register_mem_resource(option, mem);
} else if (p->resource_type == ACPI_IO_RANGE) {
- port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
+ port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = port->max = p->minimum;
@@ -721,7 +721,7 @@ int pnpacpi_build_resource_template(acpi_handle handle,
if (!res_cnt)
return -EINVAL;
buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
- buffer->pointer = kcalloc(1, buffer->length - 1, GFP_KERNEL);
+ buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
if (!buffer->pointer)
return -ENOMEM;
pnp_dbg("Res cnt %d", res_cnt);
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 33adeba1a31..95738dbd5d4 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -109,10 +109,10 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
if (!current->fs->root) {
return -EAGAIN;
}
- if (!(envp = (char **) kcalloc (20, sizeof (char *), GFP_KERNEL))) {
+ if (!(envp = kcalloc(20, sizeof (char *), GFP_KERNEL))) {
return -ENOMEM;
}
- if (!(buf = kcalloc (1, 256, GFP_KERNEL))) {
+ if (!(buf = kzalloc(256, GFP_KERNEL))) {
kfree (envp);
return -ENOMEM;
}
@@ -220,7 +220,7 @@ static int pnpbios_get_resources(struct pnp_dev * dev, struct pnp_resource_table
if(!pnpbios_is_dynamic(dev))
return -EPERM;
- node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
+ node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
@@ -243,7 +243,7 @@ static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table
if (!pnpbios_is_dynamic(dev))
return -EPERM;
- node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
+ node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
@@ -294,7 +294,7 @@ static int pnpbios_disable_resources(struct pnp_dev *dev)
if(dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
return -EPERM;
- node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
+ node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -ENOMEM;
@@ -336,7 +336,7 @@ static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
}
/* set the initial values for the PnP device */
- dev_id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);
+ dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
return -1;
pnpid32_to_pnpid(node->eisa_id,id);
@@ -374,7 +374,7 @@ static void __init build_devlist(void)
struct pnp_bios_node *node;
struct pnp_dev *dev;
- node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
+ node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return;
@@ -391,7 +391,7 @@ static void __init build_devlist(void)
break;
}
nodes_got++;
- dev = kcalloc(1, sizeof (struct pnp_dev), GFP_KERNEL);
+ dev = kzalloc(sizeof (struct pnp_dev), GFP_KERNEL);
if (!dev)
break;
if(insert_device(dev,node)<0)
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
index 5a3dfc97f5e..8027073f791 100644
--- a/drivers/pnp/pnpbios/proc.c
+++ b/drivers/pnp/pnpbios/proc.c
@@ -87,7 +87,7 @@ static int proc_read_escd(char *buf, char **start, off_t pos,
return -EFBIG;
}
- tmpbuf = kcalloc(1, escd.escd_size, GFP_KERNEL);
+ tmpbuf = kzalloc(escd.escd_size, GFP_KERNEL);
if (!tmpbuf) return -ENOMEM;
if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) {
@@ -133,7 +133,7 @@ static int proc_read_devices(char *buf, char **start, off_t pos,
if (pos >= 0xff)
return 0;
- node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
+ node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
for (nodenum=pos; nodenum<0xff; ) {
@@ -168,7 +168,7 @@ static int proc_read_node(char *buf, char **start, off_t pos,
u8 nodenum = (long)data;
int len;
- node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
+ node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
kfree(node);
@@ -188,7 +188,7 @@ static int proc_write_node(struct file *file, const char __user *buf,
u8 nodenum = (long)data;
int ret = count;
- node = kcalloc(1, node_info.max_node_size, GFP_KERNEL);
+ node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -ENOMEM;
if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index ef508a4de55..95b79685a9d 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -248,7 +248,7 @@ static void
pnpbios_parse_mem_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
- mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = ((p[5] << 8) | p[4]) << 8;
@@ -264,7 +264,7 @@ static void
pnpbios_parse_mem32_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
- mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
@@ -280,7 +280,7 @@ static void
pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
- mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
+ mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
@@ -297,7 +297,7 @@ pnpbios_parse_irq_option(unsigned char *p, int size, struct pnp_option *option)
struct pnp_irq * irq;
unsigned long bits;
- irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
+ irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
if (!irq)
return;
bits = (p[2] << 8) | p[1];
@@ -314,7 +314,7 @@ static void
pnpbios_parse_dma_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_dma * dma;
- dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
+ dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
if (!dma)
return;
dma->map = p[1];
@@ -327,7 +327,7 @@ static void
pnpbios_parse_port_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_port * port;
- port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
+ port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = (p[3] << 8) | p[2];
@@ -343,7 +343,7 @@ static void
pnpbios_parse_fixed_port_option(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_port * port;
- port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
+ port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
port->min = port->max = (p[2] << 8) | p[1];
@@ -527,7 +527,7 @@ pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_de
case SMALL_TAG_COMPATDEVID: /* compatible ID */
if (len != 4)
goto len_err;
- dev_id = kcalloc(1, sizeof (struct pnp_id), GFP_KERNEL);
+ dev_id = kzalloc(sizeof (struct pnp_id), GFP_KERNEL);
if (!dev_id)
return NULL;
memset(dev_id, 0, sizeof(struct pnp_id));
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index d42015c382a..2065e74bb63 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -3,7 +3,8 @@
*
* Some code is based on pnpbios_core.c
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*/
#include <linux/pnp.h>
@@ -21,18 +22,21 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "", 0 }
};
-static void reserve_ioport_range(char *pnpid, int start, int end)
+static void reserve_range(char *pnpid, int start, int end, int port)
{
struct resource *res;
char *regionid;
regionid = kmalloc(16, GFP_KERNEL);
- if ( regionid == NULL )
+ if (regionid == NULL)
return;
snprintf(regionid, 16, "pnp %s", pnpid);
- res = request_region(start,end-start+1,regionid);
- if ( res == NULL )
- kfree( regionid );
+ if (port)
+ res = request_region(start,end-start+1,regionid);
+ else
+ res = request_mem_region(start,end-start+1,regionid);
+ if (res == NULL)
+ kfree(regionid);
else
res->flags &= ~IORESOURCE_BUSY;
/*
@@ -41,26 +45,20 @@ static void reserve_ioport_range(char *pnpid, int start, int end)
* have double reservations.
*/
printk(KERN_INFO
- "pnp: %s: ioport range 0x%x-0x%x %s reserved\n",
- pnpid, start, end,
- NULL != res ? "has been" : "could not be"
- );
-
- return;
+ "pnp: %s: %s range 0x%x-0x%x %s reserved\n",
+ pnpid, port ? "ioport" : "iomem", start, end,
+ NULL != res ? "has been" : "could not be");
}
-static void reserve_resources_of_dev( struct pnp_dev *dev )
+static void reserve_resources_of_dev(struct pnp_dev *dev)
{
int i;
- for (i=0;i<PNP_MAX_PORT;i++) {
+ for (i = 0; i < PNP_MAX_PORT; i++) {
if (!pnp_port_valid(dev, i))
- /* end of resources */
continue;
if (pnp_port_start(dev, i) == 0)
- /* disabled */
- /* Do nothing */
- continue;
+ continue; /* disabled */
if (pnp_port_start(dev, i) < 0x100)
/*
* Below 0x100 is only standard PC hardware
@@ -72,14 +70,18 @@ static void reserve_resources_of_dev( struct pnp_dev *dev )
*/
continue;
if (pnp_port_end(dev, i) < pnp_port_start(dev, i))
- /* invalid endpoint */
- /* Do nothing */
+ continue; /* invalid */
+
+ reserve_range(dev->dev.bus_id, pnp_port_start(dev, i),
+ pnp_port_end(dev, i), 1);
+ }
+
+ for (i = 0; i < PNP_MAX_MEM; i++) {
+ if (!pnp_mem_valid(dev, i))
continue;
- reserve_ioport_range(
- dev->dev.bus_id,
- pnp_port_start(dev, i),
- pnp_port_end(dev, i)
- );
+
+ reserve_range(dev->dev.bus_id, pnp_mem_start(dev, i),
+ pnp_mem_end(dev, i), 0);
}
return;
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index b52d547b7a7..d547cf50ca9 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -1 +1 @@
-obj-y += system-bus.o
+obj-$(CONFIG_PS3_VUART) += vuart.o
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
new file mode 100644
index 00000000000..a72da8f651f
--- /dev/null
+++ b/drivers/ps3/vuart.c
@@ -0,0 +1,965 @@
+/*
+ * PS3 virtual uart
+ *
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <asm/ps3.h>
+
+#include <asm/lv1call.h>
+#include <asm/bitops.h>
+
+#include "vuart.h"
+
+MODULE_AUTHOR("Sony Corporation");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ps3 vuart");
+
+/**
+ * vuart - An inter-partition data link service.
+ * port 0: PS3 AV Settings.
+ * port 2: PS3 System Manager.
+ *
+ * The vuart provides a bi-directional byte stream data link between logical
+ * partitions. Its primary role is as a communications link between the guest
+ * OS and the system policy module. The current HV does not support any
+ * connections other than those listed.
+ */
+
+enum {PORT_COUNT = 3,};
+
+enum vuart_param {
+ PARAM_TX_TRIGGER = 0,
+ PARAM_RX_TRIGGER = 1,
+ PARAM_INTERRUPT_MASK = 2,
+ PARAM_RX_BUF_SIZE = 3, /* read only */
+ PARAM_RX_BYTES = 4, /* read only */
+ PARAM_TX_BUF_SIZE = 5, /* read only */
+ PARAM_TX_BYTES = 6, /* read only */
+ PARAM_INTERRUPT_STATUS = 7, /* read only */
+};
+
+enum vuart_interrupt_bit {
+ INTERRUPT_BIT_TX = 0,
+ INTERRUPT_BIT_RX = 1,
+ INTERRUPT_BIT_DISCONNECT = 2,
+};
+
+enum vuart_interrupt_mask {
+ INTERRUPT_MASK_TX = 1,
+ INTERRUPT_MASK_RX = 2,
+ INTERRUPT_MASK_DISCONNECT = 4,
+};
+
+/**
+ * struct ports_bmp - bitmap indicating ports needing service.
+ *
+ * A 256 bit read only bitmap indicating ports needing service. Do not write
+ * to these bits. Must not cross a page boundary.
+ */
+
+struct ports_bmp {
+ u64 status;
+ u64 unused[3];
+} __attribute__ ((aligned (32)));
+
+/* redefine dev_dbg to do a syntax check */
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+ const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+#define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
+static void __attribute__ ((unused)) _dump_ports_bmp(
+ const struct ports_bmp* bmp, const char* func, int line)
+{
+ pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status);
+}
+
+static int ps3_vuart_match_id_to_port(enum ps3_match_id match_id,
+ unsigned int *port_number)
+{
+ switch(match_id) {
+ case PS3_MATCH_ID_AV_SETTINGS:
+ *port_number = 0;
+ return 0;
+ case PS3_MATCH_ID_SYSTEM_MANAGER:
+ *port_number = 2;
+ return 0;
+ default:
+ WARN_ON(1);
+ *port_number = UINT_MAX;
+ return -EINVAL;
+ };
+}
+
+#define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__)
+static void __attribute__ ((unused)) _dump_port_params(unsigned int port_number,
+ const char* func, int line)
+{
+#if defined(DEBUG)
+ static const char *strings[] = {
+ "tx_trigger ",
+ "rx_trigger ",
+ "interrupt_mask ",
+ "rx_buf_size ",
+ "rx_bytes ",
+ "tx_buf_size ",
+ "tx_bytes ",
+ "interrupt_status",
+ };
+ int result;
+ unsigned int i;
+ u64 value;
+
+ for (i = 0; i < ARRAY_SIZE(strings); i++) {
+ result = lv1_get_virtual_uart_param(port_number, i, &value);
+
+ if (result) {
+ pr_debug("%s:%d: port_%u: %s failed: %s\n", func, line,
+ port_number, strings[i], ps3_result(result));
+ continue;
+ }
+ pr_debug("%s:%d: port_%u: %s = %lxh\n",
+ func, line, port_number, strings[i], value);
+ }
+#endif
+}
+
+struct vuart_triggers {
+ unsigned long rx;
+ unsigned long tx;
+};
+
+int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
+ struct vuart_triggers *trig)
+{
+ int result;
+ unsigned long size;
+ unsigned long val;
+
+ result = lv1_get_virtual_uart_param(dev->port_number,
+ PARAM_TX_TRIGGER, &trig->tx);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return result;
+ }
+
+ result = lv1_get_virtual_uart_param(dev->port_number,
+ PARAM_RX_BUF_SIZE, &size);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return result;
+ }
+
+ result = lv1_get_virtual_uart_param(dev->port_number,
+ PARAM_RX_TRIGGER, &val);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return result;
+ }
+
+ trig->rx = size - val;
+
+ dev_dbg(&dev->core, "%s:%d: tx %lxh, rx %lxh\n", __func__, __LINE__,
+ trig->tx, trig->rx);
+
+ return result;
+}
+
+int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
+ unsigned int rx)
+{
+ int result;
+ unsigned long size;
+
+ result = lv1_set_virtual_uart_param(dev->port_number,
+ PARAM_TX_TRIGGER, tx);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return result;
+ }
+
+ result = lv1_get_virtual_uart_param(dev->port_number,
+ PARAM_RX_BUF_SIZE, &size);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return result;
+ }
+
+ result = lv1_set_virtual_uart_param(dev->port_number,
+ PARAM_RX_TRIGGER, size - rx);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return result;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: tx %xh, rx %xh\n", __func__, __LINE__,
+ tx, rx);
+
+ return result;
+}
+
+static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev,
+ unsigned long *bytes_waiting)
+{
+ int result = lv1_get_virtual_uart_param(dev->port_number,
+ PARAM_RX_BYTES, bytes_waiting);
+
+ if (result)
+ dev_dbg(&dev->core, "%s:%d: rx_bytes failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+
+ dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__,
+ *bytes_waiting);
+ return result;
+}
+
+static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev,
+ unsigned long mask)
+{
+ int result;
+
+ dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask);
+
+ dev->interrupt_mask = mask;
+
+ result = lv1_set_virtual_uart_param(dev->port_number,
+ PARAM_INTERRUPT_MASK, dev->interrupt_mask);
+
+ if (result)
+ dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+
+ return result;
+}
+
+static int ps3_vuart_get_interrupt_mask(struct ps3_vuart_port_device *dev,
+ unsigned long *status)
+{
+ int result = lv1_get_virtual_uart_param(dev->port_number,
+ PARAM_INTERRUPT_STATUS, status);
+
+ if (result)
+ dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+
+ dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n",
+ __func__, __LINE__, dev->interrupt_mask, *status,
+ dev->interrupt_mask & *status);
+
+ return result;
+}
+
+int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev)
+{
+ return (dev->interrupt_mask & INTERRUPT_MASK_TX) ? 0
+ : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ | INTERRUPT_MASK_TX);
+}
+
+int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev)
+{
+ return (dev->interrupt_mask & INTERRUPT_MASK_RX) ? 0
+ : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ | INTERRUPT_MASK_RX);
+}
+
+int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
+{
+ return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0
+ : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ | INTERRUPT_MASK_DISCONNECT);
+}
+
+int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev)
+{
+ return (dev->interrupt_mask & INTERRUPT_MASK_TX)
+ ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ & ~INTERRUPT_MASK_TX) : 0;
+}
+
+int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev)
+{
+ return (dev->interrupt_mask & INTERRUPT_MASK_RX)
+ ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ & ~INTERRUPT_MASK_RX) : 0;
+}
+
+int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
+{
+ return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT)
+ ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ & ~INTERRUPT_MASK_DISCONNECT) : 0;
+}
+
+/**
+ * ps3_vuart_raw_write - Low level write helper.
+ *
+ * Do not call ps3_vuart_raw_write directly, use ps3_vuart_write.
+ */
+
+static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev,
+ const void* buf, unsigned int bytes, unsigned long *bytes_written)
+{
+ int result;
+
+ dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
+
+ result = lv1_write_virtual_uart(dev->port_number,
+ ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: lv1_write_virtual_uart failed: "
+ "%s\n", __func__, __LINE__, ps3_result(result));
+ return result;
+ }
+
+ dev->stats.bytes_written += *bytes_written;
+
+ dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__,
+ __LINE__, *bytes_written, bytes, dev->stats.bytes_written);
+
+ return result;
+}
+
+/**
+ * ps3_vuart_raw_read - Low level read helper.
+ *
+ * Do not call ps3_vuart_raw_read directly, use ps3_vuart_read.
+ */
+
+static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf,
+ unsigned int bytes, unsigned long *bytes_read)
+{
+ int result;
+
+ dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
+
+ result = lv1_read_virtual_uart(dev->port_number,
+ ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: lv1_read_virtual_uart failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return result;
+ }
+
+ dev->stats.bytes_read += *bytes_read;
+
+ dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__,
+ *bytes_read, bytes, dev->stats.bytes_read);
+
+ return result;
+}
+
+/**
+ * struct list_buffer - An element for a port device fifo buffer list.
+ */
+
+struct list_buffer {
+ struct list_head link;
+ const unsigned char *head;
+ const unsigned char *tail;
+ unsigned long dbg_number;
+ unsigned char data[];
+};
+
+/**
+ * ps3_vuart_write - the entry point for writing data to a port
+ *
+ * If the port is idle on entry as much of the incoming data is written to
+ * the port as the port will accept. Otherwise a list buffer is created
+ * and any remaning incoming data is copied to that buffer. The buffer is
+ * then enqueued for transmision via the transmit interrupt.
+ */
+
+int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
+ unsigned int bytes)
+{
+ static unsigned long dbg_number;
+ int result;
+ unsigned long flags;
+ struct list_buffer *lb;
+
+ dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
+ bytes, bytes);
+
+ spin_lock_irqsave(&dev->tx_list.lock, flags);
+
+ if (list_empty(&dev->tx_list.head)) {
+ unsigned long bytes_written;
+
+ result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written);
+
+ spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+
+ if (result) {
+ dev_dbg(&dev->core,
+ "%s:%d: ps3_vuart_raw_write failed\n",
+ __func__, __LINE__);
+ return result;
+ }
+
+ if (bytes_written == bytes) {
+ dev_dbg(&dev->core, "%s:%d: wrote %xh bytes\n",
+ __func__, __LINE__, bytes);
+ return 0;
+ }
+
+ bytes -= bytes_written;
+ buf += bytes_written;
+ } else
+ spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+
+ lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL);
+
+ if (!lb) {
+ return -ENOMEM;
+ }
+
+ memcpy(lb->data, buf, bytes);
+ lb->head = lb->data;
+ lb->tail = lb->data + bytes;
+ lb->dbg_number = ++dbg_number;
+
+ spin_lock_irqsave(&dev->tx_list.lock, flags);
+ list_add_tail(&lb->link, &dev->tx_list.head);
+ ps3_vuart_enable_interrupt_tx(dev);
+ spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+
+ dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n",
+ __func__, __LINE__, lb->dbg_number, bytes);
+
+ return 0;
+}
+
+/**
+ * ps3_vuart_read - the entry point for reading data from a port
+ *
+ * If enough bytes to satisfy the request are held in the buffer list those
+ * bytes are dequeued and copied to the caller's buffer. Emptied list buffers
+ * are retiered. If the request cannot be statified by bytes held in the list
+ * buffers -EAGAIN is returned.
+ */
+
+int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
+ unsigned int bytes)
+{
+ unsigned long flags;
+ struct list_buffer *lb, *n;
+ unsigned long bytes_read;
+
+ dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
+ bytes, bytes);
+
+ spin_lock_irqsave(&dev->rx_list.lock, flags);
+
+ if (dev->rx_list.bytes_held < bytes) {
+ spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+ dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n",
+ __func__, __LINE__, bytes - dev->rx_list.bytes_held);
+ return -EAGAIN;
+ }
+
+ list_for_each_entry_safe(lb, n, &dev->rx_list.head, link) {
+ bytes_read = min((unsigned int)(lb->tail - lb->head), bytes);
+
+ memcpy(buf, lb->head, bytes_read);
+ buf += bytes_read;
+ bytes -= bytes_read;
+ dev->rx_list.bytes_held -= bytes_read;
+
+ if (bytes_read < lb->tail - lb->head) {
+ lb->head += bytes_read;
+ spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+
+ dev_dbg(&dev->core,
+ "%s:%d: dequeued buf_%lu, %lxh bytes\n",
+ __func__, __LINE__, lb->dbg_number, bytes_read);
+ return 0;
+ }
+
+ dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
+ lb->dbg_number);
+
+ list_del(&lb->link);
+ kfree(lb);
+ }
+ spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+
+ dev_dbg(&dev->core, "%s:%d: dequeued buf_%lu, %xh bytes\n",
+ __func__, __LINE__, lb->dbg_number, bytes);
+
+ return 0;
+}
+
+/**
+ * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler
+ *
+ * Services the transmit interrupt for the port. Writes as much data from the
+ * buffer list as the port will accept. Retires any emptied list buffers and
+ * adjusts the final list buffer state for a partial write.
+ */
+
+static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev)
+{
+ int result = 0;
+ unsigned long flags;
+ struct list_buffer *lb, *n;
+ unsigned long bytes_total = 0;
+
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+ spin_lock_irqsave(&dev->tx_list.lock, flags);
+
+ list_for_each_entry_safe(lb, n, &dev->tx_list.head, link) {
+
+ unsigned long bytes_written;
+
+ result = ps3_vuart_raw_write(dev, lb->head, lb->tail - lb->head,
+ &bytes_written);
+
+ if (result) {
+ dev_dbg(&dev->core,
+ "%s:%d: ps3_vuart_raw_write failed\n",
+ __func__, __LINE__);
+ break;
+ }
+
+ bytes_total += bytes_written;
+
+ if (bytes_written < lb->tail - lb->head) {
+ lb->head += bytes_written;
+ dev_dbg(&dev->core,
+ "%s:%d cleared buf_%lu, %lxh bytes\n",
+ __func__, __LINE__, lb->dbg_number,
+ bytes_written);
+ goto port_full;
+ }
+
+ dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
+ lb->dbg_number);
+
+ list_del(&lb->link);
+ kfree(lb);
+ }
+
+ ps3_vuart_disable_interrupt_tx(dev);
+port_full:
+ spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+ dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n",
+ __func__, __LINE__, bytes_total);
+ return result;
+}
+
+/**
+ * ps3_vuart_handle_interrupt_rx - third stage receive interrupt handler
+ *
+ * Services the receive interrupt for the port. Creates a list buffer and
+ * copies all waiting port data to that buffer and enqueues the buffer in the
+ * buffer list. Buffer list data is dequeued via ps3_vuart_read.
+ */
+
+static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev)
+{
+ static unsigned long dbg_number;
+ int result = 0;
+ unsigned long flags;
+ struct list_buffer *lb;
+ unsigned long bytes;
+
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+ result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes);
+
+ if (result)
+ return -EIO;
+
+ BUG_ON(!bytes);
+
+ /* add some extra space for recently arrived data */
+
+ bytes += 128;
+
+ lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC);
+
+ if (!lb)
+ return -ENOMEM;
+
+ ps3_vuart_raw_read(dev, lb->data, bytes, &bytes);
+
+ lb->head = lb->data;
+ lb->tail = lb->data + bytes;
+ lb->dbg_number = ++dbg_number;
+
+ spin_lock_irqsave(&dev->rx_list.lock, flags);
+ list_add_tail(&lb->link, &dev->rx_list.head);
+ dev->rx_list.bytes_held += bytes;
+ spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+
+ dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %lxh bytes\n",
+ __func__, __LINE__, lb->dbg_number, bytes);
+
+ return 0;
+}
+
+static int ps3_vuart_handle_interrupt_disconnect(
+ struct ps3_vuart_port_device *dev)
+{
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+ BUG_ON("no support");
+ return -1;
+}
+
+/**
+ * ps3_vuart_handle_port_interrupt - second stage interrupt handler
+ *
+ * Services any pending interrupt types for the port. Passes control to the
+ * third stage type specific interrupt handler. Returns control to the first
+ * stage handler after one iteration.
+ */
+
+static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev)
+{
+ int result;
+ unsigned long status;
+
+ result = ps3_vuart_get_interrupt_mask(dev, &status);
+
+ if (result)
+ return result;
+
+ dev_dbg(&dev->core, "%s:%d: status: %lxh\n", __func__, __LINE__,
+ status);
+
+ if (status & INTERRUPT_MASK_DISCONNECT) {
+ dev->stats.disconnect_interrupts++;
+ result = ps3_vuart_handle_interrupt_disconnect(dev);
+ if (result)
+ ps3_vuart_disable_interrupt_disconnect(dev);
+ }
+
+ if (status & INTERRUPT_MASK_TX) {
+ dev->stats.tx_interrupts++;
+ result = ps3_vuart_handle_interrupt_tx(dev);
+ if (result)
+ ps3_vuart_disable_interrupt_tx(dev);
+ }
+
+ if (status & INTERRUPT_MASK_RX) {
+ dev->stats.rx_interrupts++;
+ result = ps3_vuart_handle_interrupt_rx(dev);
+ if (result)
+ ps3_vuart_disable_interrupt_rx(dev);
+ }
+
+ return 0;
+}
+
+struct vuart_private {
+ unsigned int in_use;
+ unsigned int virq;
+ struct ps3_vuart_port_device *devices[PORT_COUNT];
+ const struct ports_bmp bmp;
+};
+
+/**
+ * ps3_vuart_irq_handler - first stage interrupt handler
+ *
+ * Loops finding any interrupting port and its associated instance data.
+ * Passes control to the second stage port specific interrupt handler. Loops
+ * until all outstanding interrupts are serviced.
+ */
+
+static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private)
+{
+ struct vuart_private *private;
+
+ BUG_ON(!_private);
+ private = (struct vuart_private *)_private;
+
+ while (1) {
+ unsigned int port;
+
+ dump_ports_bmp(&private->bmp);
+
+ port = (BITS_PER_LONG - 1) - __ilog2(private->bmp.status);
+
+ if (port == BITS_PER_LONG)
+ break;
+
+ BUG_ON(port >= PORT_COUNT);
+ BUG_ON(!private->devices[port]);
+
+ ps3_vuart_handle_port_interrupt(private->devices[port]);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv)
+{
+ int result;
+ struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_drv);
+ struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+
+ result = dev->match_id == drv->match_id;
+
+ dev_info(&dev->core, "%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__,
+ __LINE__, dev->match_id, dev->core.bus_id, drv->match_id,
+ drv->core.name, (result ? "match" : "miss"));
+
+ return result;
+}
+
+static struct vuart_private vuart_private;
+
+static int ps3_vuart_probe(struct device *_dev)
+{
+ int result;
+ unsigned long tmp;
+ struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+ struct ps3_vuart_port_driver *drv =
+ to_ps3_vuart_port_driver(_dev->driver);
+
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+ BUG_ON(!drv);
+
+ result = ps3_vuart_match_id_to_port(dev->match_id, &dev->port_number);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n",
+ __func__, __LINE__, dev->match_id);
+ result = -EINVAL;
+ goto fail_match;
+ }
+
+ if (vuart_private.devices[dev->port_number]) {
+ dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__,
+ __LINE__, dev->port_number);
+ result = -EBUSY;
+ goto fail_match;
+ }
+
+ vuart_private.devices[dev->port_number] = dev;
+
+ INIT_LIST_HEAD(&dev->tx_list.head);
+ spin_lock_init(&dev->tx_list.lock);
+ INIT_LIST_HEAD(&dev->rx_list.head);
+ spin_lock_init(&dev->rx_list.lock);
+
+ vuart_private.in_use++;
+ if (vuart_private.in_use == 1) {
+ result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY,
+ (void*)&vuart_private.bmp.status, &vuart_private.virq);
+
+ if (result) {
+ dev_dbg(&dev->core,
+ "%s:%d: ps3_alloc_vuart_irq failed (%d)\n",
+ __func__, __LINE__, result);
+ result = -EPERM;
+ goto fail_alloc_irq;
+ }
+
+ result = request_irq(vuart_private.virq, ps3_vuart_irq_handler,
+ IRQF_DISABLED, "vuart", &vuart_private);
+
+ if (result) {
+ dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n",
+ __func__, __LINE__, result);
+ goto fail_request_irq;
+ }
+ }
+
+ ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX);
+
+ /* clear stale pending interrupts */
+ ps3_vuart_get_interrupt_mask(dev, &tmp);
+
+ ps3_vuart_set_triggers(dev, 1, 1);
+
+ if (drv->probe)
+ result = drv->probe(dev);
+ else {
+ result = 0;
+ dev_info(&dev->core, "%s:%d: no probe method\n", __func__,
+ __LINE__);
+ }
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: drv->probe failed\n",
+ __func__, __LINE__);
+ goto fail_probe;
+ }
+
+ return result;
+
+fail_probe:
+fail_request_irq:
+ vuart_private.in_use--;
+ if (!vuart_private.in_use) {
+ ps3_free_vuart_irq(vuart_private.virq);
+ vuart_private.virq = NO_IRQ;
+ }
+fail_alloc_irq:
+fail_match:
+ dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__);
+ return result;
+}
+
+static int ps3_vuart_remove(struct device *_dev)
+{
+ struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+ struct ps3_vuart_port_driver *drv =
+ to_ps3_vuart_port_driver(_dev->driver);
+
+ dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__,
+ dev->core.bus_id);
+
+ BUG_ON(vuart_private.in_use < 1);
+
+ if (drv->remove)
+ drv->remove(dev);
+ else
+ dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__,
+ __LINE__, dev->core.bus_id);
+
+ vuart_private.in_use--;
+
+ if (!vuart_private.in_use) {
+ free_irq(vuart_private.virq, &vuart_private);
+ ps3_free_vuart_irq(vuart_private.virq);
+ vuart_private.virq = NO_IRQ;
+ }
+ return 0;
+}
+
+/**
+ * ps3_vuart - The vuart instance.
+ *
+ * The vuart is managed as a bus that port devices connect to.
+ */
+
+struct bus_type ps3_vuart = {
+ .name = "ps3_vuart",
+ .match = ps3_vuart_match,
+ .probe = ps3_vuart_probe,
+ .remove = ps3_vuart_remove,
+};
+
+int __init ps3_vuart_init(void)
+{
+ int result;
+
+ pr_debug("%s:%d:\n", __func__, __LINE__);
+ result = bus_register(&ps3_vuart);
+ BUG_ON(result);
+ return result;
+}
+
+void __exit ps3_vuart_exit(void)
+{
+ pr_debug("%s:%d:\n", __func__, __LINE__);
+ bus_unregister(&ps3_vuart);
+}
+
+core_initcall(ps3_vuart_init);
+module_exit(ps3_vuart_exit);
+
+/**
+ * ps3_vuart_port_release_device - Remove a vuart port device.
+ */
+
+static void ps3_vuart_port_release_device(struct device *_dev)
+{
+ struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+#if defined(DEBUG)
+ memset(dev, 0xad, sizeof(struct ps3_vuart_port_device));
+#endif
+ kfree(dev);
+}
+
+/**
+ * ps3_vuart_port_device_register - Add a vuart port device.
+ */
+
+int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev)
+{
+ int result;
+ static unsigned int dev_count = 1;
+
+ dev->core.parent = NULL;
+ dev->core.bus = &ps3_vuart;
+ dev->core.release = ps3_vuart_port_release_device;
+
+ snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x",
+ dev_count++);
+
+ dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__);
+
+ result = device_register(&dev->core);
+
+ return result;
+}
+
+EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register);
+
+/**
+ * ps3_vuart_port_driver_register - Add a vuart port device driver.
+ */
+
+int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv)
+{
+ int result;
+
+ pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name);
+ drv->core.bus = &ps3_vuart;
+ result = driver_register(&drv->core);
+ return result;
+}
+
+EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register);
+
+/**
+ * ps3_vuart_port_driver_unregister - Remove a vuart port device driver.
+ */
+
+void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv)
+{
+ driver_unregister(&drv->core);
+}
+
+EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister);
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h
new file mode 100644
index 00000000000..11c421cf7a0
--- /dev/null
+++ b/drivers/ps3/vuart.h
@@ -0,0 +1,58 @@
+/*
+ * PS3 virtual uart
+ *
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined(_PS3_VUART_H)
+#define _PS3_VUART_H
+
+/**
+ * struct ps3_vuart_port_driver - a driver for a device on a vuart port
+ */
+
+struct ps3_vuart_port_driver {
+ enum ps3_match_id match_id;
+ struct device_driver core;
+ int (*probe)(struct ps3_vuart_port_device *);
+ int (*remove)(struct ps3_vuart_port_device *);
+ int (*tx_event)(struct ps3_vuart_port_device *dev);
+ int (*rx_event)(struct ps3_vuart_port_device *dev);
+ int (*disconnect_event)(struct ps3_vuart_port_device *dev);
+ /* int (*suspend)(struct ps3_vuart_port_device *, pm_message_t); */
+ /* int (*resume)(struct ps3_vuart_port_device *); */
+};
+
+int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
+void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);
+
+int ps3_vuart_write(struct ps3_vuart_port_device *dev,
+ const void* buf, unsigned int bytes);
+int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
+ unsigned int bytes);
+static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver(
+ struct device_driver *_drv)
+{
+ return container_of(_drv, struct ps3_vuart_port_driver, core);
+}
+static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device(
+ struct device *_dev)
+{
+ return container_of(_dev, struct ps3_vuart_port_device, core);
+}
+
+#endif
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2a63ab2b47f..09660e2ab05 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -288,7 +288,7 @@ config RTC_DRV_PL031
To compile this driver as a module, choose M here: the
module will be called rtc-pl031.
-config RTC_DRV_AT91
+config RTC_DRV_AT91RM9200
tristate "AT91RM9200"
depends on RTC_CLASS && ARCH_AT91RM9200
help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index bd4c45d333f..e6beedacc96 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -35,5 +35,5 @@ obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
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_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
diff --git a/drivers/rtc/rtc-at91.c b/drivers/rtc/rtc-at91rm9200.c
index 5c8addcaf1f..a724ab49a79 100644
--- a/drivers/rtc/rtc-at91.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -33,6 +33,8 @@
#include <asm/mach/time.h>
+#include <asm/arch/at91_rtc.h>
+
#define AT91_RTC_FREQ 1
#define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
@@ -137,6 +139,9 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
tm->tm_year = at91_alarm_year - 1900;
+ alrm->enabled = (at91_sys_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
+ ? 1 : 0;
+
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);
@@ -223,8 +228,6 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
{
unsigned long imr = at91_sys_read(AT91_RTC_IMR);
- seq_printf(seq, "alarm_IRQ\t: %s\n",
- (imr & AT91_RTC_ALARM) ? "yes" : "no");
seq_printf(seq, "update_IRQ\t: %s\n",
(imr & AT91_RTC_ACKUPD) ? "yes" : "no");
seq_printf(seq, "periodic_IRQ\t: %s\n",
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 828b329e08e..82f2ac87ccd 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -305,7 +305,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
case RTC_IRQP_READ:
if (ops->irq_set_freq)
- err = put_user(rtc->irq_freq, (unsigned long *) arg);
+ err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
break;
case RTC_IRQP_SET:
@@ -435,7 +435,7 @@ static int rtc_dev_add_device(struct class_device *class_dev,
goto err_cdev_del;
}
- dev_info(class_dev->dev, "rtc intf: dev (%d:%d)\n",
+ dev_dbg(class_dev->dev, "rtc intf: dev (%d:%d)\n",
MAJOR(rtc->rtc_dev->devt),
MINOR(rtc->rtc_dev->devt));
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index dfef1637bfb..205fa28593b 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -199,7 +199,7 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
struct i2c_client *client;
struct rtc_device *rtc;
- dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+ dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index ba795a4db1e..7bbc26a34bd 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -117,4 +117,85 @@ int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
}
EXPORT_SYMBOL(rtc_tm_to_time);
+
+/* Merge the valid (i.e. non-negative) fields of alarm into the current
+ * time. If the valid alarm fields are earlier than the equivalent
+ * fields in the time, carry one into the least significant invalid
+ * field, so that the alarm expiry is in the future. It assumes that the
+ * least significant invalid field is more significant than the most
+ * significant valid field, and that the seconds field is valid.
+ *
+ * This is used by alarms that take relative (rather than absolute)
+ * times, and/or have a simple binary second counter instead of
+ * day/hour/minute/sec registers.
+ */
+void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm)
+{
+ int *alarmp = &alarm->tm_sec;
+ int *timep = &now->tm_sec;
+ int carry_into, i;
+
+ /* Ignore everything past the 6th element (tm_year). */
+ for (i = 5; i > 0; i--) {
+ if (alarmp[i] < 0)
+ alarmp[i] = timep[i];
+ else
+ break;
+ }
+
+ /* No carry needed if all fields are valid. */
+ if (i == 5)
+ return;
+
+ for (carry_into = i + 1; i >= 0; i--) {
+ if (alarmp[i] < timep[i])
+ break;
+
+ if (alarmp[i] > timep[i])
+ return;
+ }
+
+ switch (carry_into) {
+ case 1:
+ alarm->tm_min++;
+
+ if (alarm->tm_min < 60)
+ return;
+
+ alarm->tm_min = 0;
+ /* fall-through */
+
+ case 2:
+ alarm->tm_hour++;
+
+ if (alarm->tm_hour < 60)
+ return;
+
+ alarm->tm_hour = 0;
+ /* fall-through */
+
+ case 3:
+ alarm->tm_mday++;
+
+ if (alarm->tm_mday <= rtc_days_in_month[alarm->tm_mon])
+ return;
+
+ alarm->tm_mday = 1;
+ /* fall-through */
+
+ case 4:
+ alarm->tm_mon++;
+
+ if (alarm->tm_mon <= 12)
+ return;
+
+ alarm->tm_mon = 1;
+ /* fall-through */
+
+ case 5:
+ alarm->tm_year++;
+ }
+}
+EXPORT_SYMBOL(rtc_merge_alarm);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index eac5fb1fc02..d59880d44fb 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -279,9 +279,8 @@ static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
local_irq_enable();
bcd2tm(&alm->time);
- alm->pending = !!(rtc_read(OMAP_RTC_INTERRUPTS_REG)
+ alm->enabled = !!(rtc_read(OMAP_RTC_INTERRUPTS_REG)
& OMAP_RTC_INTERRUPTS_IT_ALARM);
- alm->enabled = alm->pending && device_may_wakeup(dev);
return 0;
}
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index a760cf69af9..038118bbfae 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -53,6 +53,25 @@ I2C_CLIENT_INSMOD;
#define PCF8563_SC_LV 0x80 /* low voltage */
#define PCF8563_MO_C 0x80 /* century */
+struct pcf8563 {
+ struct i2c_client client;
+ /*
+ * The meaning of MO_C bit varies by the chip type.
+ * From PCF8563 datasheet: this bit is toggled when the years
+ * register overflows from 99 to 00
+ * 0 indicates the century is 20xx
+ * 1 indicates the century is 19xx
+ * From RTC8564 datasheet: this bit indicates change of
+ * century. When the year digit data overflows from 99 to 00,
+ * this bit is set. By presetting it to 0 while still in the
+ * 20th century, it will be set in year 2000, ...
+ * There seems no reliable way to know how the system use this
+ * bit. So let's do it heuristically, assuming we are live in
+ * 1970...2069.
+ */
+ int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
+};
+
static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind);
static int pcf8563_detach(struct i2c_client *client);
@@ -62,6 +81,7 @@ static int pcf8563_detach(struct i2c_client *client);
*/
static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
unsigned char buf[13] = { PCF8563_REG_ST1 };
struct i2c_msg msgs[] = {
@@ -94,8 +114,12 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
tm->tm_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F);
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 ? 0 : 100);
+ tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]);
+ if (tm->tm_year < 70)
+ tm->tm_year += 100; /* assume we are in 1970...2069 */
+ /* detect the polarity heuristically. see note above. */
+ pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
+ (tm->tm_year >= 100) : (tm->tm_year < 100);
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -114,6 +138,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
int i, err;
unsigned char buf[9];
@@ -135,7 +160,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 (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
buf[PCF8563_REG_MO] |= PCF8563_MO_C;
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
@@ -192,7 +217,7 @@ static int pcf8563_validate_client(struct i2c_client *client)
xfer = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (xfer != ARRAY_SIZE(msgs)) {
- dev_err(&client->adapter->dev,
+ dev_err(&client->dev,
"%s: could not read register 0x%02X\n",
__FUNCTION__, pattern[i].reg);
@@ -203,7 +228,7 @@ static int pcf8563_validate_client(struct i2c_client *client)
if (value > pattern[i].max ||
value < pattern[i].min) {
- dev_dbg(&client->adapter->dev,
+ dev_dbg(&client->dev,
"%s: pattern=%d, reg=%x, mask=0x%02x, min=%d, "
"max=%d, value=%d, raw=0x%02X\n",
__FUNCTION__, i, pattern[i].reg, pattern[i].mask,
@@ -248,23 +273,25 @@ static struct i2c_driver pcf8563_driver = {
static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
{
+ struct pcf8563 *pcf8563;
struct i2c_client *client;
struct rtc_device *rtc;
int err = 0;
- dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+ dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
goto exit;
}
- if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+ if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
+ client = &pcf8563->client;
client->addr = address;
client->driver = &pcf8563_driver;
client->adapter = adapter;
@@ -301,7 +328,7 @@ exit_detach:
i2c_detach_client(client);
exit_kfree:
- kfree(client);
+ kfree(pcf8563);
exit:
return err;
@@ -309,6 +336,7 @@ exit:
static int pcf8563_detach(struct i2c_client *client)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
@@ -318,7 +346,7 @@ static int pcf8563_detach(struct i2c_client *client)
if ((err = i2c_detach_client(client)))
return err;
- kfree(client);
+ kfree(pcf8563);
return 0;
}
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
index d51d8f20e63..c272afd6217 100644
--- a/drivers/rtc/rtc-proc.c
+++ b/drivers/rtc/rtc-proc.c
@@ -65,7 +65,7 @@ static int rtc_proc_show(struct seq_file *seq, void *offset)
seq_printf(seq, "%02d\n", alrm.time.tm_mday);
else
seq_printf(seq, "**\n");
- seq_printf(seq, "alrm_wakeup\t: %s\n",
+ seq_printf(seq, "alarm_IRQ\t: %s\n",
alrm.enabled ? "yes" : "no");
seq_printf(seq, "alrm_pending\t: %s\n",
alrm.pending ? "yes" : "no");
@@ -120,7 +120,7 @@ static int rtc_proc_add_device(struct class_device *class_dev,
ent->owner = rtc->owner;
ent->data = class_dev;
- dev_info(class_dev->dev, "rtc intf: proc\n");
+ dev_dbg(class_dev->dev, "rtc intf: proc\n");
}
else
rtc_dev = NULL;
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index e2c7698fdba..e7851e3739a 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -1,5 +1,5 @@
/*
- * An I2C driver for the Ricoh RS5C372 RTC
+ * An I2C driver for Ricoh RS5C372 and RV5C38[67] RTCs
*
* Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net>
* Copyright (C) 2006 Tower Technologies
@@ -13,7 +13,7 @@
#include <linux/rtc.h>
#include <linux/bcd.h>
-#define DRV_VERSION "0.3"
+#define DRV_VERSION "0.4"
/* Addresses to scan */
static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END };
@@ -21,6 +21,13 @@ static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD;
+
+/*
+ * Ricoh has a family of I2C based RTCs, which differ only slightly from
+ * each other. Differences center on pinout (e.g. how many interrupts,
+ * output clock, etc) and how the control registers are used. The '372
+ * is significant only because that's the one this driver first supported.
+ */
#define RS5C372_REG_SECS 0
#define RS5C372_REG_MINS 1
#define RS5C372_REG_HOURS 2
@@ -29,59 +36,142 @@ I2C_CLIENT_INSMOD;
#define RS5C372_REG_MONTH 5
#define RS5C372_REG_YEAR 6
#define RS5C372_REG_TRIM 7
+# define RS5C372_TRIM_XSL 0x80
+# define RS5C372_TRIM_MASK 0x7F
+
+#define RS5C_REG_ALARM_A_MIN 8 /* or ALARM_W */
+#define RS5C_REG_ALARM_A_HOURS 9
+#define RS5C_REG_ALARM_A_WDAY 10
+
+#define RS5C_REG_ALARM_B_MIN 11 /* or ALARM_D */
+#define RS5C_REG_ALARM_B_HOURS 12
+#define RS5C_REG_ALARM_B_WDAY 13 /* (ALARM_B only) */
+
+#define RS5C_REG_CTRL1 14
+# define RS5C_CTRL1_AALE (1 << 7) /* or WALE */
+# define RS5C_CTRL1_BALE (1 << 6) /* or DALE */
+# define RV5C387_CTRL1_24 (1 << 5)
+# define RS5C372A_CTRL1_SL1 (1 << 5)
+# define RS5C_CTRL1_CT_MASK (7 << 0)
+# define RS5C_CTRL1_CT0 (0 << 0) /* no periodic irq */
+# define RS5C_CTRL1_CT4 (4 << 0) /* 1 Hz level irq */
+#define RS5C_REG_CTRL2 15
+# define RS5C372_CTRL2_24 (1 << 5)
+# define RS5C_CTRL2_XSTP (1 << 4)
+# define RS5C_CTRL2_CTFG (1 << 2)
+# define RS5C_CTRL2_AAFG (1 << 1) /* or WAFG */
+# define RS5C_CTRL2_BAFG (1 << 0) /* or DAFG */
+
+
+/* to read (style 1) or write registers starting at R */
+#define RS5C_ADDR(R) (((R) << 4) | 0)
+
+
+enum rtc_type {
+ rtc_undef = 0,
+ rtc_rs5c372a,
+ rtc_rs5c372b,
+ rtc_rv5c386,
+ rtc_rv5c387a,
+};
-#define RS5C372_TRIM_XSL 0x80
-#define RS5C372_TRIM_MASK 0x7F
+/* REVISIT: this assumes that:
+ * - we're in the 21st century, so it's safe to ignore the century
+ * bit for rv5c38[67] (REG_MONTH bit 7);
+ * - we should use ALARM_A not ALARM_B (may be wrong on some boards)
+ */
+struct rs5c372 {
+ struct i2c_client *client;
+ struct rtc_device *rtc;
+ enum rtc_type type;
+ unsigned time24:1;
+ unsigned has_irq:1;
+ char buf[17];
+ char *regs;
+
+ /* on conversion to a "new style" i2c driver, this vanishes */
+ struct i2c_client dev;
+};
-#define RS5C372_REG_BASE 0
+static int rs5c_get_regs(struct rs5c372 *rs5c)
+{
+ struct i2c_client *client = rs5c->client;
+ struct i2c_msg msgs[] = {
+ { client->addr, I2C_M_RD, sizeof rs5c->buf, rs5c->buf },
+ };
+
+ /* This implements the third reading method from the datasheet, using
+ * an internal address that's reset after each transaction (by STOP)
+ * to 0x0f ... so we read extra registers, and skip the first one.
+ *
+ * The first method doesn't work with the iop3xx adapter driver, on at
+ * least 80219 chips; this works around that bug.
+ */
+ if ((i2c_transfer(client->adapter, msgs, 1)) != 1) {
+ pr_debug("%s: can't read registers\n", rs5c->rtc->name);
+ return -EIO;
+ }
-static int rs5c372_attach(struct i2c_adapter *adapter);
-static int rs5c372_detach(struct i2c_client *client);
-static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind);
+ dev_dbg(&client->dev,
+ "%02x %02x %02x (%02x) %02x %02x %02x (%02x), "
+ "%02x %02x %02x, %02x %02x %02x; %02x %02x\n",
+ rs5c->regs[0], rs5c->regs[1], rs5c->regs[2], rs5c->regs[3],
+ rs5c->regs[4], rs5c->regs[5], rs5c->regs[6], rs5c->regs[7],
+ rs5c->regs[8], rs5c->regs[9], rs5c->regs[10], rs5c->regs[11],
+ rs5c->regs[12], rs5c->regs[13], rs5c->regs[14], rs5c->regs[15]);
-struct rs5c372 {
- u8 reg_addr;
- u8 regs[17];
- struct i2c_msg msg[1];
- struct i2c_client client;
- struct rtc_device *rtc;
-};
+ return 0;
+}
-static struct i2c_driver rs5c372_driver = {
- .driver = {
- .name = "rs5c372",
- },
- .attach_adapter = &rs5c372_attach,
- .detach_client = &rs5c372_detach,
-};
+static unsigned rs5c_reg2hr(struct rs5c372 *rs5c, unsigned reg)
+{
+ unsigned hour;
-static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+ if (rs5c->time24)
+ return BCD2BIN(reg & 0x3f);
+
+ hour = BCD2BIN(reg & 0x1f);
+ if (hour == 12)
+ hour = 0;
+ if (reg & 0x20)
+ hour += 12;
+ return hour;
+}
+
+static unsigned rs5c_hr2reg(struct rs5c372 *rs5c, unsigned hour)
{
+ if (rs5c->time24)
+ return BIN2BCD(hour);
+
+ if (hour > 12)
+ return 0x20 | BIN2BCD(hour - 12);
+ if (hour == 12)
+ return 0x20 | BIN2BCD(12);
+ if (hour == 0)
+ return BIN2BCD(12);
+ return BIN2BCD(hour);
+}
- struct rs5c372 *rs5c372 = i2c_get_clientdata(client);
- u8 *buf = &(rs5c372->regs[1]);
+static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+ struct rs5c372 *rs5c = i2c_get_clientdata(client);
+ int status = rs5c_get_regs(rs5c);
- /* this implements the 3rd reading method, according
- * to the datasheet. rs5c372 defaults to internal
- * address 0xF, so 0x0 is in regs[1]
- */
+ if (status < 0)
+ return status;
- if ((i2c_transfer(client->adapter, rs5c372->msg, 1)) != 1) {
- dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
- return -EIO;
- }
+ tm->tm_sec = BCD2BIN(rs5c->regs[RS5C372_REG_SECS] & 0x7f);
+ tm->tm_min = BCD2BIN(rs5c->regs[RS5C372_REG_MINS] & 0x7f);
+ tm->tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C372_REG_HOURS]);
- tm->tm_sec = BCD2BIN(buf[RS5C372_REG_SECS] & 0x7f);
- tm->tm_min = BCD2BIN(buf[RS5C372_REG_MINS] & 0x7f);
- tm->tm_hour = BCD2BIN(buf[RS5C372_REG_HOURS] & 0x3f);
- tm->tm_wday = BCD2BIN(buf[RS5C372_REG_WDAY] & 0x07);
- tm->tm_mday = BCD2BIN(buf[RS5C372_REG_DAY] & 0x3f);
+ tm->tm_wday = BCD2BIN(rs5c->regs[RS5C372_REG_WDAY] & 0x07);
+ tm->tm_mday = BCD2BIN(rs5c->regs[RS5C372_REG_DAY] & 0x3f);
/* tm->tm_mon is zero-based */
- tm->tm_mon = BCD2BIN(buf[RS5C372_REG_MONTH] & 0x1f) - 1;
+ tm->tm_mon = BCD2BIN(rs5c->regs[RS5C372_REG_MONTH] & 0x1f) - 1;
/* year is 1900 + tm->tm_year */
- tm->tm_year = BCD2BIN(buf[RS5C372_REG_YEAR]) + 100;
+ tm->tm_year = BCD2BIN(rs5c->regs[RS5C372_REG_YEAR]) + 100;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -89,22 +179,25 @@ static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
- return 0;
+ /* rtc might need initialization */
+ return rtc_valid_tm(tm);
}
static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
- unsigned char buf[8] = { RS5C372_REG_BASE };
+ struct rs5c372 *rs5c = i2c_get_clientdata(client);
+ unsigned char buf[8];
- dev_dbg(&client->dev,
- "%s: secs=%d, mins=%d, hours=%d "
+ dev_dbg(&client->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,
+ __FUNCTION__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+ buf[0] = RS5C_ADDR(RS5C372_REG_SECS);
buf[1] = BIN2BCD(tm->tm_sec);
buf[2] = BIN2BCD(tm->tm_min);
- buf[3] = BIN2BCD(tm->tm_hour);
+ buf[3] = rs5c_hr2reg(rs5c, tm->tm_hour);
buf[4] = BIN2BCD(tm->tm_wday);
buf[5] = BIN2BCD(tm->tm_mday);
buf[6] = BIN2BCD(tm->tm_mon + 1);
@@ -118,21 +211,43 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
return 0;
}
+#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
+#define NEED_TRIM
+#endif
+
+#if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
+#define NEED_TRIM
+#endif
+
+#ifdef NEED_TRIM
static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim)
{
struct rs5c372 *rs5c372 = i2c_get_clientdata(client);
- u8 tmp = rs5c372->regs[RS5C372_REG_TRIM + 1];
+ u8 tmp = rs5c372->regs[RS5C372_REG_TRIM];
if (osc)
*osc = (tmp & RS5C372_TRIM_XSL) ? 32000 : 32768;
if (trim) {
- *trim = tmp & RS5C372_TRIM_MASK;
- dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, *trim);
+ dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, tmp);
+ tmp &= RS5C372_TRIM_MASK;
+ if (tmp & 0x3e) {
+ int t = tmp & 0x3f;
+
+ if (tmp & 0x40)
+ t = (~t | (s8)0xc0) + 1;
+ else
+ t = t - 1;
+
+ tmp = t * 2;
+ } else
+ tmp = 0;
+ *trim = tmp;
}
return 0;
}
+#endif
static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
@@ -144,25 +259,190 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm)
return rs5c372_set_datetime(to_i2c_client(dev), tm);
}
+#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
+
+static int
+rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rs5c372 *rs5c = i2c_get_clientdata(client);
+ unsigned char buf[2];
+ int status;
+
+ buf[1] = rs5c->regs[RS5C_REG_CTRL1];
+ switch (cmd) {
+ case RTC_UIE_OFF:
+ case RTC_UIE_ON:
+ /* some 327a modes use a different IRQ pin for 1Hz irqs */
+ if (rs5c->type == rtc_rs5c372a
+ && (buf[1] & RS5C372A_CTRL1_SL1))
+ return -ENOIOCTLCMD;
+ case RTC_AIE_OFF:
+ case RTC_AIE_ON:
+ /* these irq management calls only make sense for chips
+ * which are wired up to an IRQ.
+ */
+ if (!rs5c->has_irq)
+ return -ENOIOCTLCMD;
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ status = rs5c_get_regs(rs5c);
+ if (status < 0)
+ return status;
+
+ buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
+ switch (cmd) {
+ case RTC_AIE_OFF: /* alarm off */
+ buf[1] &= ~RS5C_CTRL1_AALE;
+ break;
+ case RTC_AIE_ON: /* alarm on */
+ buf[1] |= RS5C_CTRL1_AALE;
+ break;
+ case RTC_UIE_OFF: /* update off */
+ buf[1] &= ~RS5C_CTRL1_CT_MASK;
+ break;
+ case RTC_UIE_ON: /* update on */
+ buf[1] &= ~RS5C_CTRL1_CT_MASK;
+ buf[1] |= RS5C_CTRL1_CT4;
+ break;
+ }
+ if ((i2c_master_send(client, buf, 2)) != 2) {
+ printk(KERN_WARNING "%s: can't update alarm\n",
+ rs5c->rtc->name);
+ status = -EIO;
+ } else
+ rs5c->regs[RS5C_REG_CTRL1] = buf[1];
+ return status;
+}
+
+#else
+#define rs5c_rtc_ioctl NULL
+#endif
+
+
+/* NOTE: Since RTC_WKALM_{RD,SET} were originally defined for EFI,
+ * which only exposes a polled programming interface; and since
+ * these calls map directly to those EFI requests; we don't demand
+ * we have an IRQ for this chip when we go through this API.
+ *
+ * The older x86_pc derived RTC_ALM_{READ,SET} calls require irqs
+ * though, managed through RTC_AIE_{ON,OFF} requests.
+ */
+
+static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rs5c372 *rs5c = i2c_get_clientdata(client);
+ int status;
+
+ status = rs5c_get_regs(rs5c);
+ if (status < 0)
+ return status;
+
+ /* report alarm time */
+ t->time.tm_sec = 0;
+ t->time.tm_min = BCD2BIN(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
+ t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
+ t->time.tm_mday = -1;
+ t->time.tm_mon = -1;
+ t->time.tm_year = -1;
+ t->time.tm_wday = -1;
+ t->time.tm_yday = -1;
+ t->time.tm_isdst = -1;
+
+ /* ... and status */
+ t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);
+ t->pending = !!(rs5c->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_AAFG);
+
+ return 0;
+}
+
+static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rs5c372 *rs5c = i2c_get_clientdata(client);
+ int status;
+ unsigned char buf[4];
+
+ /* only handle up to 24 hours in the future, like RTC_ALM_SET */
+ if (t->time.tm_mday != -1
+ || t->time.tm_mon != -1
+ || t->time.tm_year != -1)
+ return -EINVAL;
+
+ /* REVISIT: round up tm_sec */
+
+ /* if needed, disable irq (clears pending status) */
+ status = rs5c_get_regs(rs5c);
+ if (status < 0)
+ return status;
+ if (rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE) {
+ buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
+ buf[1] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
+ if (i2c_master_send(client, buf, 2) != 2) {
+ pr_debug("%s: can't disable alarm\n", rs5c->rtc->name);
+ return -EIO;
+ }
+ rs5c->regs[RS5C_REG_CTRL1] = buf[1];
+ }
+
+ /* set alarm */
+ buf[0] = RS5C_ADDR(RS5C_REG_ALARM_A_MIN);
+ buf[1] = BIN2BCD(t->time.tm_min);
+ buf[2] = rs5c_hr2reg(rs5c, t->time.tm_hour);
+ buf[3] = 0x7f; /* any/all days */
+ if ((i2c_master_send(client, buf, 4)) != 4) {
+ pr_debug("%s: can't set alarm time\n", rs5c->rtc->name);
+ return -EIO;
+ }
+
+ /* ... and maybe enable its irq */
+ if (t->enabled) {
+ buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
+ buf[1] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
+ if ((i2c_master_send(client, buf, 2)) != 2)
+ printk(KERN_WARNING "%s: can't enable alarm\n",
+ rs5c->rtc->name);
+ rs5c->regs[RS5C_REG_CTRL1] = buf[1];
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
+
static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq)
{
int err, osc, trim;
err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim);
if (err == 0) {
- seq_printf(seq, "%d.%03d KHz\n", osc / 1000, osc % 1000);
- seq_printf(seq, "trim\t: %d\n", trim);
+ seq_printf(seq, "crystal\t\t: %d.%03d KHz\n",
+ osc / 1000, osc % 1000);
+ seq_printf(seq, "trim\t\t: %d\n", trim);
}
return 0;
}
+#else
+#define rs5c372_rtc_proc NULL
+#endif
+
static const struct rtc_class_ops rs5c372_rtc_ops = {
.proc = rs5c372_rtc_proc,
+ .ioctl = rs5c_rtc_ioctl,
.read_time = rs5c372_rtc_read_time,
.set_time = rs5c372_rtc_set_time,
+ .read_alarm = rs5c_read_alarm,
+ .set_alarm = rs5c_set_alarm,
};
+#if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
+
static ssize_t rs5c372_sysfs_show_trim(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -172,7 +452,7 @@ static ssize_t rs5c372_sysfs_show_trim(struct device *dev,
if (err)
return err;
- return sprintf(buf, "0x%2x\n", trim);
+ return sprintf(buf, "%d\n", trim);
}
static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL);
@@ -189,18 +469,37 @@ static ssize_t rs5c372_sysfs_show_osc(struct device *dev,
}
static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL);
-static int rs5c372_attach(struct i2c_adapter *adapter)
+static int rs5c_sysfs_register(struct device *dev)
{
- return i2c_probe(adapter, &addr_data, rs5c372_probe);
+ int err;
+
+ err = device_create_file(dev, &dev_attr_trim);
+ if (err)
+ return err;
+ err = device_create_file(dev, &dev_attr_osc);
+ if (err)
+ device_remove_file(dev, &dev_attr_trim);
+
+ return err;
+}
+
+#else
+static int rs5c_sysfs_register(struct device *dev)
+{
+ return 0;
}
+#endif /* SYSFS */
+
+static struct i2c_driver rs5c372_driver;
static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
{
int err = 0;
struct i2c_client *client;
struct rs5c372 *rs5c372;
+ struct rtc_time tm;
- dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+ dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
@@ -211,7 +510,15 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
err = -ENOMEM;
goto exit;
}
- client = &rs5c372->client;
+
+ /* we read registers 0x0f then 0x00-0x0f; skip the first one */
+ rs5c372->regs=&rs5c372->buf[1];
+
+ /* On conversion to a "new style" i2c driver, we'll be handed
+ * the i2c_client (we won't create it)
+ */
+ client = &rs5c372->dev;
+ rs5c372->client = client;
/* I2C client */
client->addr = address;
@@ -222,16 +529,99 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
i2c_set_clientdata(client, rs5c372);
- rs5c372->msg[0].addr = address;
- rs5c372->msg[0].flags = I2C_M_RD;
- rs5c372->msg[0].len = sizeof(rs5c372->regs);
- rs5c372->msg[0].buf = rs5c372->regs;
-
/* Inform the i2c layer */
if ((err = i2c_attach_client(client)))
goto exit_kfree;
- dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+ err = rs5c_get_regs(rs5c372);
+ if (err < 0)
+ goto exit_detach;
+
+ /* For "new style" drivers, irq is in i2c_client and chip type
+ * info comes from i2c_client.dev.platform_data. Meanwhile:
+ *
+ * STICK BOARD-SPECIFIC SETUP CODE RIGHT HERE
+ */
+ if (rs5c372->type == rtc_undef) {
+ rs5c372->type = rtc_rs5c372b;
+ dev_warn(&client->dev, "assuming rs5c372b\n");
+ }
+
+ /* clock may be set for am/pm or 24 hr time */
+ switch (rs5c372->type) {
+ case rtc_rs5c372a:
+ case rtc_rs5c372b:
+ /* alarm uses ALARM_A; and nINTRA on 372a, nINTR on 372b.
+ * so does periodic irq, except some 327a modes.
+ */
+ if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C372_CTRL2_24)
+ rs5c372->time24 = 1;
+ break;
+ case rtc_rv5c386:
+ case rtc_rv5c387a:
+ if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24)
+ rs5c372->time24 = 1;
+ /* alarm uses ALARM_W; and nINTRB for alarm and periodic
+ * irq, on both 386 and 387
+ */
+ break;
+ default:
+ dev_err(&client->dev, "unknown RTC type\n");
+ goto exit_detach;
+ }
+
+ /* if the oscillator lost power and no other software (like
+ * the bootloader) set it up, do it here.
+ */
+ if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP) {
+ unsigned char buf[3];
+
+ rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;
+
+ buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
+ buf[1] = rs5c372->regs[RS5C_REG_CTRL1];
+ buf[2] = rs5c372->regs[RS5C_REG_CTRL2];
+
+ /* use 24hr mode */
+ switch (rs5c372->type) {
+ case rtc_rs5c372a:
+ case rtc_rs5c372b:
+ buf[2] |= RS5C372_CTRL2_24;
+ rs5c372->time24 = 1;
+ break;
+ case rtc_rv5c386:
+ case rtc_rv5c387a:
+ buf[1] |= RV5C387_CTRL1_24;
+ rs5c372->time24 = 1;
+ break;
+ default:
+ /* impossible */
+ break;
+ }
+
+ if ((i2c_master_send(client, buf, 3)) != 3) {
+ dev_err(&client->dev, "setup error\n");
+ goto exit_detach;
+ }
+ rs5c372->regs[RS5C_REG_CTRL1] = buf[1];
+ rs5c372->regs[RS5C_REG_CTRL2] = buf[2];
+ }
+
+ if (rs5c372_get_datetime(client, &tm) < 0)
+ dev_warn(&client->dev, "clock needs to be set\n");
+
+ dev_info(&client->dev, "%s found, %s, driver version " DRV_VERSION "\n",
+ ({ char *s; switch (rs5c372->type) {
+ case rtc_rs5c372a: s = "rs5c372a"; break;
+ case rtc_rs5c372b: s = "rs5c372b"; break;
+ case rtc_rv5c386: s = "rv5c386"; break;
+ case rtc_rv5c387a: s = "rv5c387a"; break;
+ default: s = "chip"; break;
+ }; s;}),
+ rs5c372->time24 ? "24hr" : "am/pm"
+ );
+
+ /* FIXME when client->irq exists, use it to register alarm irq */
rs5c372->rtc = rtc_device_register(rs5c372_driver.driver.name,
&client->dev, &rs5c372_rtc_ops, THIS_MODULE);
@@ -241,18 +631,12 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
goto exit_detach;
}
- err = device_create_file(&client->dev, &dev_attr_trim);
+ err = rs5c_sysfs_register(&client->dev);
if (err)
goto exit_devreg;
- err = device_create_file(&client->dev, &dev_attr_osc);
- if (err)
- goto exit_trim;
return 0;
-exit_trim:
- device_remove_file(&client->dev, &dev_attr_trim);
-
exit_devreg:
rtc_device_unregister(rs5c372->rtc);
@@ -266,6 +650,11 @@ exit:
return err;
}
+static int rs5c372_attach(struct i2c_adapter *adapter)
+{
+ return i2c_probe(adapter, &addr_data, rs5c372_probe);
+}
+
static int rs5c372_detach(struct i2c_client *client)
{
int err;
@@ -274,6 +663,8 @@ static int rs5c372_detach(struct i2c_client *client)
if (rs5c372->rtc)
rtc_device_unregister(rs5c372->rtc);
+ /* REVISIT properly destroy the sysfs files ... */
+
if ((err = i2c_detach_client(client)))
return err;
@@ -281,6 +672,14 @@ static int rs5c372_detach(struct i2c_client *client)
return 0;
}
+static struct i2c_driver rs5c372_driver = {
+ .driver = {
+ .name = "rtc-rs5c372",
+ },
+ .attach_adapter = &rs5c372_attach,
+ .detach_client = &rs5c372_detach,
+};
+
static __init int rs5c372_init(void)
{
return i2c_add_driver(&rs5c372_driver);
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index e301dea57bb..f406a2b55ae 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -191,6 +191,8 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
alm_en = readb(base + S3C2410_RTCALM);
+ alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
+
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,
@@ -331,12 +333,8 @@ static int s3c_rtc_ioctl(struct device *dev,
static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
{
- unsigned int rtcalm = readb(s3c_rtc_base + S3C2410_RTCALM);
unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
- seq_printf(seq, "alarm_IRQ\t: %s\n",
- (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" );
-
seq_printf(seq, "periodic_IRQ\t: %s\n",
(ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index bd4d7d174ef..9c8ead43a59 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -289,9 +289,7 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
{
- seq_printf(seq, "trim/divider\t: 0x%08lx\n", RTTR);
- seq_printf(seq, "alarm_IRQ\t: %s\n",
- (RTSR & RTSR_ALE) ? "yes" : "no" );
+ seq_printf(seq, "trim/divider\t: 0x%08x\n", (u32) RTTR);
seq_printf(seq, "update_IRQ\t: %s\n",
(RTSR & RTSR_HZE) ? "yes" : "no");
seq_printf(seq, "periodic_IRQ\t: %s\n",
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 143302a8e79..198b9f22fbf 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -2,6 +2,7 @@
* SuperH On-Chip RTC Support
*
* Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2006 Jamie Lenehan
*
* Based on the old arch/sh/kernel/cpu/rtc.c by:
*
@@ -21,7 +22,10 @@
#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
-#include <asm/io.h>
+#include <linux/io.h>
+
+#define DRV_NAME "sh-rtc"
+#define DRV_VERSION "0.1.2"
#ifdef CONFIG_CPU_SH3
#define rtc_reg_size sizeof(u16)
@@ -33,22 +37,26 @@
#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)
+#define R64CNT RTC_REG(0)
+
+#define RSECCNT RTC_REG(1) /* RTC sec */
+#define RMINCNT RTC_REG(2) /* RTC min */
+#define RHRCNT RTC_REG(3) /* RTC hour */
+#define RWKCNT RTC_REG(4) /* RTC week */
+#define RDAYCNT RTC_REG(5) /* RTC day */
+#define RMONCNT RTC_REG(6) /* RTC month */
+#define RYRCNT RTC_REG(7) /* RTC year */
+#define RSECAR RTC_REG(8) /* ALARM sec */
+#define RMINAR RTC_REG(9) /* ALARM min */
+#define RHRAR RTC_REG(10) /* ALARM hour */
+#define RWKAR RTC_REG(11) /* ALARM week */
+#define RDAYAR RTC_REG(12) /* ALARM day */
+#define RMONAR RTC_REG(13) /* ALARM month */
+#define RCR1 RTC_REG(14) /* Control */
+#define RCR2 RTC_REG(15) /* Control */
+
+/* ALARM Bits - or with BCD encoded value */
+#define AR_ENB 0x80 /* Enable for alarm cmp */
/* RCR1 Bits */
#define RCR1_CF 0x80 /* Carry Flag */
@@ -71,22 +79,28 @@ struct sh_rtc {
unsigned int alarm_irq, periodic_irq, carry_irq;
struct rtc_device *rtc_dev;
spinlock_t lock;
+ int rearm_aie;
};
-static irqreturn_t sh_rtc_interrupt(int irq, void *id)
+static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
{
- struct platform_device *pdev = id;
+ struct platform_device *pdev = to_platform_device(dev_id);
struct sh_rtc *rtc = platform_get_drvdata(pdev);
unsigned int tmp, events = 0;
spin_lock(&rtc->lock);
tmp = readb(rtc->regbase + RCR1);
+ tmp &= ~RCR1_CF;
- if (tmp & RCR1_AF)
- events |= RTC_AF | RTC_IRQF;
-
- tmp &= ~(RCR1_CF | RCR1_AF);
+ if (rtc->rearm_aie) {
+ if (tmp & RCR1_AF)
+ tmp &= ~RCR1_AF; /* try to clear AF again */
+ else {
+ tmp |= RCR1_AIE; /* AF has cleared, rearm IRQ */
+ rtc->rearm_aie = 0;
+ }
+ }
writeb(tmp, rtc->regbase + RCR1);
@@ -97,9 +111,45 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *id)
return IRQ_HANDLED;
}
-static irqreturn_t sh_rtc_periodic(int irq, void *id)
+static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
+{
+ struct platform_device *pdev = to_platform_device(dev_id);
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
+ unsigned int tmp, events = 0;
+
+ spin_lock(&rtc->lock);
+
+ tmp = readb(rtc->regbase + RCR1);
+
+ /*
+ * If AF is set then the alarm has triggered. If we clear AF while
+ * the alarm time still matches the RTC time then AF will
+ * immediately be set again, and if AIE is enabled then the alarm
+ * interrupt will immediately be retrigger. So we clear AIE here
+ * and use rtc->rearm_aie so that the carry interrupt will keep
+ * trying to clear AF and once it stays cleared it'll re-enable
+ * AIE.
+ */
+ if (tmp & RCR1_AF) {
+ events |= RTC_AF | RTC_IRQF;
+
+ tmp &= ~(RCR1_AF|RCR1_AIE);
+
+ writeb(tmp, rtc->regbase + RCR1);
+
+ rtc->rearm_aie = 1;
+
+ 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 *dev_id)
{
- struct sh_rtc *rtc = dev_get_drvdata(id);
+ struct platform_device *pdev = to_platform_device(dev_id);
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
spin_lock(&rtc->lock);
@@ -139,10 +189,11 @@ static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
tmp = readb(rtc->regbase + RCR1);
- if (enable)
- tmp |= RCR1_AIE;
- else
+ if (!enable) {
tmp &= ~RCR1_AIE;
+ rtc->rearm_aie = 0;
+ } else if (rtc->rearm_aie == 0)
+ tmp |= RCR1_AIE;
writeb(tmp, rtc->regbase + RCR1);
@@ -177,7 +228,7 @@ static int sh_rtc_open(struct device *dev)
goto err_bad_carry;
}
- ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, IRQF_DISABLED,
+ ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, IRQF_DISABLED,
"sh-rtc alarm", dev);
if (unlikely(ret)) {
dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n",
@@ -200,6 +251,7 @@ static void sh_rtc_release(struct device *dev)
struct sh_rtc *rtc = dev_get_drvdata(dev);
sh_rtc_setpie(dev, 0);
+ sh_rtc_setaie(dev, 0);
free_irq(rtc->periodic_irq, dev);
free_irq(rtc->carry_irq, dev);
@@ -212,8 +264,6 @@ static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
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");
@@ -267,7 +317,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
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));
+ tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)) - 1;
#if defined(CONFIG_CPU_SH4)
yr = readw(rtc->regbase + RYRCNT);
@@ -295,7 +345,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
"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);
+ tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
if (rtc_valid_tm(tm) < 0)
dev_err(dev, "invalid date\n");
@@ -322,7 +372,7 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
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);
+ writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT);
#ifdef CONFIG_CPU_SH3
year = tm->tm_year % 100;
@@ -344,12 +394,140 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
return 0;
}
+static inline int sh_rtc_read_alarm_value(struct sh_rtc *rtc, int reg_off)
+{
+ unsigned int byte;
+ int value = 0xff; /* return 0xff for ignored values */
+
+ byte = readb(rtc->regbase + reg_off);
+ if (byte & AR_ENB) {
+ byte &= ~AR_ENB; /* strip the enable bit */
+ value = BCD2BIN(byte);
+ }
+
+ return value;
+}
+
+static int sh_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
+ struct rtc_time* tm = &wkalrm->time;
+
+ spin_lock_irq(&rtc->lock);
+
+ tm->tm_sec = sh_rtc_read_alarm_value(rtc, RSECAR);
+ tm->tm_min = sh_rtc_read_alarm_value(rtc, RMINAR);
+ tm->tm_hour = sh_rtc_read_alarm_value(rtc, RHRAR);
+ tm->tm_wday = sh_rtc_read_alarm_value(rtc, RWKAR);
+ tm->tm_mday = sh_rtc_read_alarm_value(rtc, RDAYAR);
+ tm->tm_mon = sh_rtc_read_alarm_value(rtc, RMONAR);
+ if (tm->tm_mon > 0)
+ tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
+ tm->tm_year = 0xffff;
+
+ wkalrm->enabled = (readb(rtc->regbase + RCR1) & RCR1_AIE) ? 1 : 0;
+
+ spin_unlock_irq(&rtc->lock);
+
+ return 0;
+}
+
+static inline void sh_rtc_write_alarm_value(struct sh_rtc *rtc,
+ int value, int reg_off)
+{
+ /* < 0 for a value that is ignored */
+ if (value < 0)
+ writeb(0, rtc->regbase + reg_off);
+ else
+ writeb(BIN2BCD(value) | AR_ENB, rtc->regbase + reg_off);
+}
+
+static int sh_rtc_check_alarm(struct rtc_time* tm)
+{
+ /*
+ * The original rtc says anything > 0xc0 is "don't care" or "match
+ * all" - most users use 0xff but rtc-dev uses -1 for the same thing.
+ * The original rtc doesn't support years - some things use -1 and
+ * some 0xffff. We use -1 to make out tests easier.
+ */
+ if (tm->tm_year == 0xffff)
+ tm->tm_year = -1;
+ if (tm->tm_mon >= 0xff)
+ tm->tm_mon = -1;
+ if (tm->tm_mday >= 0xff)
+ tm->tm_mday = -1;
+ if (tm->tm_wday >= 0xff)
+ tm->tm_wday = -1;
+ if (tm->tm_hour >= 0xff)
+ tm->tm_hour = -1;
+ if (tm->tm_min >= 0xff)
+ tm->tm_min = -1;
+ if (tm->tm_sec >= 0xff)
+ tm->tm_sec = -1;
+
+ if (tm->tm_year > 9999 ||
+ tm->tm_mon >= 12 ||
+ tm->tm_mday == 0 || tm->tm_mday >= 32 ||
+ tm->tm_wday >= 7 ||
+ tm->tm_hour >= 24 ||
+ tm->tm_min >= 60 ||
+ tm->tm_sec >= 60)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
+ unsigned int rcr1;
+ struct rtc_time *tm = &wkalrm->time;
+ int mon, err;
+
+ err = sh_rtc_check_alarm(tm);
+ if (unlikely(err < 0))
+ return err;
+
+ spin_lock_irq(&rtc->lock);
+
+ /* disable alarm interrupt and clear the alarm flag */
+ rcr1 = readb(rtc->regbase + RCR1);
+ rcr1 &= ~(RCR1_AF|RCR1_AIE);
+ writeb(rcr1, rtc->regbase + RCR1);
+
+ rtc->rearm_aie = 0;
+
+ /* set alarm time */
+ sh_rtc_write_alarm_value(rtc, tm->tm_sec, RSECAR);
+ sh_rtc_write_alarm_value(rtc, tm->tm_min, RMINAR);
+ sh_rtc_write_alarm_value(rtc, tm->tm_hour, RHRAR);
+ sh_rtc_write_alarm_value(rtc, tm->tm_wday, RWKAR);
+ sh_rtc_write_alarm_value(rtc, tm->tm_mday, RDAYAR);
+ mon = tm->tm_mon;
+ if (mon >= 0)
+ mon += 1;
+ sh_rtc_write_alarm_value(rtc, mon, RMONAR);
+
+ if (wkalrm->enabled) {
+ rcr1 |= RCR1_AIE;
+ writeb(rcr1, rtc->regbase + RCR1);
+ }
+
+ 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,
+ .read_alarm = sh_rtc_read_alarm,
+ .set_alarm = sh_rtc_set_alarm,
.proc = sh_rtc_proc,
};
@@ -442,7 +620,7 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev)
}
static struct platform_driver sh_rtc_platform_driver = {
.driver = {
- .name = "sh-rtc",
+ .name = DRV_NAME,
.owner = THIS_MODULE,
},
.probe = sh_rtc_probe,
@@ -463,5 +641,6 @@ 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_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, Jamie Lenehan <lenehan@twibble.org>");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 625637b84d3..2ddd0cf0714 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -78,12 +78,12 @@ static struct attribute_group rtc_attr_group = {
.attrs = rtc_attrs,
};
-static int __devinit rtc_sysfs_add_device(struct class_device *class_dev,
+static int rtc_sysfs_add_device(struct class_device *class_dev,
struct class_interface *class_intf)
{
int err;
- dev_info(class_dev->dev, "rtc intf: sysfs\n");
+ dev_dbg(class_dev->dev, "rtc intf: sysfs\n");
err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group);
if (err)
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index 9a67487d086..019ae255b0c 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -372,7 +372,7 @@ static int x1205_validate_client(struct i2c_client *client)
};
if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
- dev_err(&client->adapter->dev,
+ dev_err(&client->dev,
"%s: could not read register %x\n",
__FUNCTION__, probe_zero_pattern[i]);
@@ -380,7 +380,7 @@ static int x1205_validate_client(struct i2c_client *client)
}
if ((buf & probe_zero_pattern[i+1]) != 0) {
- dev_err(&client->adapter->dev,
+ dev_err(&client->dev,
"%s: register=%02x, zero pattern=%d, value=%x\n",
__FUNCTION__, probe_zero_pattern[i], i, buf);
@@ -400,7 +400,7 @@ static int x1205_validate_client(struct i2c_client *client)
};
if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
- dev_err(&client->adapter->dev,
+ dev_err(&client->dev,
"%s: could not read register %x\n",
__FUNCTION__, probe_limits_pattern[i].reg);
@@ -411,7 +411,7 @@ static int x1205_validate_client(struct i2c_client *client)
if (value > probe_limits_pattern[i].max ||
value < probe_limits_pattern[i].min) {
- dev_dbg(&client->adapter->dev,
+ dev_dbg(&client->dev,
"%s: register=%x, lim pattern=%d, value=%d\n",
__FUNCTION__, probe_limits_pattern[i].reg,
i, value);
@@ -506,7 +506,7 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
struct i2c_client *client;
struct rtc_device *rtc;
- dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+ dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig
index ae89b9b8874..165af398fde 100644
--- a/drivers/s390/Kconfig
+++ b/drivers/s390/Kconfig
@@ -103,14 +103,8 @@ config CCW_CONSOLE
depends on TN3215_CONSOLE || TN3270_CONSOLE
default y
-config SCLP
- bool "Support for SCLP"
- help
- Include support for the SCLP interface to the service element.
-
config SCLP_TTY
bool "Support for SCLP line mode terminal"
- depends on SCLP
help
Include support for IBM SCLP line-mode terminals.
@@ -123,7 +117,6 @@ config SCLP_CONSOLE
config SCLP_VT220_TTY
bool "Support for SCLP VT220-compatible terminal"
- depends on SCLP
help
Include support for an IBM SCLP VT220-compatible terminal.
@@ -136,7 +129,6 @@ config SCLP_VT220_CONSOLE
config SCLP_CPI
tristate "Control-Program Identification"
- depends on SCLP
help
This option enables the hardware console interface for system
identification. This is commonly used for workload management and
diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile
index 9803c9352d7..5a888704a8d 100644
--- a/drivers/s390/Makefile
+++ b/drivers/s390/Makefile
@@ -2,6 +2,8 @@
# Makefile for the S/390 specific device drivers
#
+CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
+
obj-y += s390mach.o sysinfo.o s390_rdev.o
obj-y += cio/ block/ char/ crypto/ net/ scsi/
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 2af2d9b53d1..eb5dc62f0d9 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -37,6 +37,7 @@
*/
debug_info_t *dasd_debug_area;
struct dasd_discipline *dasd_diag_discipline_pointer;
+void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
@@ -51,7 +52,6 @@ static int dasd_alloc_queue(struct dasd_device * device);
static void dasd_setup_queue(struct dasd_device * device);
static void dasd_free_queue(struct dasd_device * device);
static void dasd_flush_request_queue(struct dasd_device *);
-static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
static int dasd_flush_ccw_queue(struct dasd_device *, int);
static void dasd_tasklet(struct dasd_device *);
static void do_kick_device(struct work_struct *);
@@ -483,7 +483,7 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF;
/*
* Add profiling information for cqr before execution.
*/
-static inline void
+static void
dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
struct request *req)
{
@@ -505,7 +505,7 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
/*
* Add profiling information for cqr after execution.
*/
-static inline void
+static void
dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
struct request *req)
{
@@ -1022,8 +1022,6 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
irb->scsw.cstat == 0 &&
!irb->esw.esw0.erw.cons)
era = dasd_era_none;
- else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags))
- era = dasd_era_fatal; /* don't recover this request */
else if (irb->esw.esw0.erw.cons)
era = device->discipline->examine_error(cqr, irb);
else
@@ -1050,10 +1048,10 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
}
} else { /* error */
memcpy(&cqr->irb, irb, sizeof (struct irb));
-#ifdef ERP_DEBUG
- /* dump sense data */
- dasd_log_sense(cqr, irb);
-#endif
+ if (device->features & DASD_FEATURE_ERPLOG) {
+ /* dump sense data */
+ dasd_log_sense(cqr, irb);
+ }
switch (era) {
case dasd_era_fatal:
cqr->status = DASD_CQR_FAILED;
@@ -1104,7 +1102,7 @@ __dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
/*
* Process ccw request queue.
*/
-static inline void
+static void
__dasd_process_ccw_queue(struct dasd_device * device,
struct list_head *final_queue)
{
@@ -1127,7 +1125,9 @@ restart:
cqr->status = DASD_CQR_FAILED;
cqr->stopclk = get_clock();
} else {
- if (cqr->irb.esw.esw0.erw.cons) {
+ if (cqr->irb.esw.esw0.erw.cons &&
+ test_bit(DASD_CQR_FLAGS_USE_ERP,
+ &cqr->flags)) {
erp_fn = device->discipline->
erp_action(cqr);
erp_fn(cqr);
@@ -1181,7 +1181,7 @@ dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
/*
* Fetch requests from the block device queue.
*/
-static inline void
+static void
__dasd_process_blk_queue(struct dasd_device * device)
{
request_queue_t *queue;
@@ -1232,6 +1232,19 @@ __dasd_process_blk_queue(struct dasd_device * device)
if (IS_ERR(cqr)) {
if (PTR_ERR(cqr) == -ENOMEM)
break; /* terminate request queue loop */
+ if (PTR_ERR(cqr) == -EAGAIN) {
+ /*
+ * The current request cannot be build right
+ * now, we have to try later. If this request
+ * is the head-of-queue we stop the device
+ * for 1/2 second.
+ */
+ if (!list_empty(&device->ccw_queue))
+ break;
+ device->stopped |= DASD_STOPPED_PENDING;
+ dasd_set_timer(device, HZ/2);
+ break;
+ }
DBF_DEV_EVENT(DBF_ERR, device,
"CCW creation failed (rc=%ld) "
"on request %p",
@@ -1254,7 +1267,7 @@ __dasd_process_blk_queue(struct dasd_device * device)
* Take a look at the first request on the ccw queue and check
* if it reached its expire time. If so, terminate the IO.
*/
-static inline void
+static void
__dasd_check_expire(struct dasd_device * device)
{
struct dasd_ccw_req *cqr;
@@ -1285,7 +1298,7 @@ __dasd_check_expire(struct dasd_device * device)
* Take a look at the first request on the ccw queue and check
* if it needs to be started.
*/
-static inline void
+static void
__dasd_start_head(struct dasd_device * device)
{
struct dasd_ccw_req *cqr;
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 669805d4402..8b9d68f6e01 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -170,7 +170,6 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
/* log the erp chain if fatal error occurred */
if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
dasd_log_sense(cqr, irb);
- dasd_log_ccw(cqr, 0, irb->scsw.cpa);
}
return era;
@@ -2640,15 +2639,12 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
struct dasd_ccw_req *erp = NULL;
struct dasd_device *device = cqr->device;
- __u32 cpa = cqr->irb.scsw.cpa;
-
-#ifdef ERP_DEBUG
- /* print current erp_chain */
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "ERP chain at BEGINNING of ERP-ACTION");
- {
- struct dasd_ccw_req *temp_erp = NULL;
+ struct dasd_ccw_req *temp_erp = NULL;
+ if (device->features & DASD_FEATURE_ERPLOG) {
+ /* print current erp_chain */
+ DEV_MESSAGE(KERN_ERR, device, "%s",
+ "ERP chain at BEGINNING of ERP-ACTION");
for (temp_erp = cqr;
temp_erp != NULL; temp_erp = temp_erp->refers) {
@@ -2658,7 +2654,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
temp_erp->refers);
}
}
-#endif /* ERP_DEBUG */
/* double-check if current erp/cqr was successfull */
if ((cqr->irb.scsw.cstat == 0x00) &&
@@ -2695,11 +2690,10 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
erp = dasd_3990_erp_handle_match_erp(cqr, erp);
}
-#ifdef ERP_DEBUG
- /* print current erp_chain */
- DEV_MESSAGE(KERN_ERR, device, "%s", "ERP chain at END of ERP-ACTION");
- {
- struct dasd_ccw_req *temp_erp = NULL;
+ if (device->features & DASD_FEATURE_ERPLOG) {
+ /* print current erp_chain */
+ DEV_MESSAGE(KERN_ERR, device, "%s",
+ "ERP chain at END of ERP-ACTION");
for (temp_erp = erp;
temp_erp != NULL; temp_erp = temp_erp->refers) {
@@ -2709,10 +2703,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
temp_erp->refers);
}
}
-#endif /* ERP_DEBUG */
-
- if (erp->status == DASD_CQR_FAILED)
- dasd_log_ccw(erp, 1, cpa);
/* enqueue added ERP request */
if (erp->status == DASD_CQR_FILLED) {
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index cf28ccc5794..ed70852cc91 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -136,7 +136,7 @@ __setup ("dasd=", dasd_call_setup);
/*
* Read a device busid/devno from a string.
*/
-static inline int
+static int
dasd_busid(char **str, int *id0, int *id1, int *devno)
{
int val, old_style;
@@ -182,7 +182,7 @@ dasd_busid(char **str, int *id0, int *id1, int *devno)
* only one: "ro" for read-only devices. The default feature set
* is empty (value 0).
*/
-static inline int
+static int
dasd_feature_list(char *str, char **endp)
{
int features, len, rc;
@@ -202,6 +202,8 @@ dasd_feature_list(char *str, char **endp)
features |= DASD_FEATURE_READONLY;
else if (len == 4 && !strncmp(str, "diag", 4))
features |= DASD_FEATURE_USEDIAG;
+ else if (len == 6 && !strncmp(str, "erplog", 6))
+ features |= DASD_FEATURE_ERPLOG;
else {
MESSAGE(KERN_WARNING,
"unsupported feature: %*s, "
@@ -339,7 +341,7 @@ dasd_parse_range( char *parsestring ) {
return ERR_PTR(-EINVAL);
}
-static inline char *
+static char *
dasd_parse_next_element( char *parsestring ) {
char * residual_str;
residual_str = dasd_parse_keyword(parsestring);
@@ -709,6 +711,52 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
+/*
+ * erplog controls the logging of ERP related data
+ * (e.g. failing channel programs).
+ */
+static ssize_t
+dasd_erplog_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dasd_devmap *devmap;
+ int erplog;
+
+ devmap = dasd_find_busid(dev->bus_id);
+ if (!IS_ERR(devmap))
+ erplog = (devmap->features & DASD_FEATURE_ERPLOG) != 0;
+ else
+ erplog = (DASD_FEATURE_DEFAULT & DASD_FEATURE_ERPLOG) != 0;
+ return snprintf(buf, PAGE_SIZE, erplog ? "1\n" : "0\n");
+}
+
+static ssize_t
+dasd_erplog_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dasd_devmap *devmap;
+ int val;
+ char *endp;
+
+ devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
+ if (IS_ERR(devmap))
+ return PTR_ERR(devmap);
+
+ val = simple_strtoul(buf, &endp, 0);
+ if (((endp + 1) < (buf + count)) || (val > 1))
+ return -EINVAL;
+
+ spin_lock(&dasd_devmap_lock);
+ if (val)
+ devmap->features |= DASD_FEATURE_ERPLOG;
+ else
+ devmap->features &= ~DASD_FEATURE_ERPLOG;
+ if (devmap->device)
+ devmap->device->features = devmap->features;
+ spin_unlock(&dasd_devmap_lock);
+ return count;
+}
+
+static DEVICE_ATTR(erplog, 0644, dasd_erplog_show, dasd_erplog_store);
/*
* use_diag controls whether the driver should use diag rather than ssch
@@ -896,6 +944,7 @@ static struct attribute * dasd_attrs[] = {
&dev_attr_uid.attr,
&dev_attr_use_diag.attr,
&dev_attr_eer_enabled.attr,
+ &dev_attr_erplog.attr,
NULL,
};
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 53db58a6861..ab782bb46ac 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");
#define DIAG_MAX_RETRIES 32
#define DIAG_TIMEOUT 50 * HZ
-struct dasd_discipline dasd_diag_discipline;
+static struct dasd_discipline dasd_diag_discipline;
struct dasd_diag_private {
struct dasd_diag_characteristics rdc_data;
@@ -90,7 +90,7 @@ static inline int dia250(void *iob, int cmd)
* block offset. On success, return zero and set end_block to contain the
* number of blocks on the device minus the specified offset. Return non-zero
* otherwise. */
-static __inline__ int
+static inline int
mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
blocknum_t offset, blocknum_t *end_block)
{
@@ -117,7 +117,7 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
/* Remove block I/O environment for device. Return zero on success, non-zero
* otherwise. */
-static __inline__ int
+static inline int
mdsk_term_io(struct dasd_device * device)
{
struct dasd_diag_private *private;
@@ -576,7 +576,7 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
"dump sense not available for DIAG data");
}
-struct dasd_discipline dasd_diag_discipline = {
+static struct dasd_discipline dasd_diag_discipline = {
.owner = THIS_MODULE,
.name = "DIAG",
.ebcname = "DIAG",
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index fdaa471e845..cecab2274a6 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -134,44 +134,7 @@ ceil_quot(unsigned int d1, unsigned int d2)
return (d1 + (d2 - 1)) / d2;
}
-static inline int
-bytes_per_record(struct dasd_eckd_characteristics *rdc, int kl, int dl)
-{
- unsigned int fl1, fl2, int1, int2;
- int bpr;
-
- switch (rdc->formula) {
- case 0x01:
- fl1 = round_up_multiple(ECKD_F2(rdc) + dl, ECKD_F1(rdc));
- fl2 = round_up_multiple(kl ? ECKD_F2(rdc) + kl : 0,
- ECKD_F1(rdc));
- bpr = fl1 + fl2;
- break;
- case 0x02:
- int1 = ceil_quot(dl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
- int2 = ceil_quot(kl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
- fl1 = round_up_multiple(ECKD_F1(rdc) * ECKD_F2(rdc) + dl +
- ECKD_F6(rdc) + ECKD_F4(rdc) * int1,
- ECKD_F1(rdc));
- fl2 = round_up_multiple(ECKD_F1(rdc) * ECKD_F3(rdc) + kl +
- ECKD_F6(rdc) + ECKD_F4(rdc) * int2,
- ECKD_F1(rdc));
- bpr = fl1 + fl2;
- break;
- default:
- bpr = 0;
- break;
- }
- return bpr;
-}
-
-static inline unsigned int
-bytes_per_track(struct dasd_eckd_characteristics *rdc)
-{
- return *(unsigned int *) (rdc->byte_per_track) >> 8;
-}
-
-static inline unsigned int
+static unsigned int
recs_per_track(struct dasd_eckd_characteristics * rdc,
unsigned int kl, unsigned int dl)
{
@@ -204,37 +167,39 @@ recs_per_track(struct dasd_eckd_characteristics * rdc,
return 0;
}
-static inline void
+static int
check_XRC (struct ccw1 *de_ccw,
struct DE_eckd_data *data,
struct dasd_device *device)
{
struct dasd_eckd_private *private;
+ int rc;
private = (struct dasd_eckd_private *) device->private;
+ if (!private->rdc_data.facilities.XRC_supported)
+ return 0;
/* switch on System Time Stamp - needed for XRC Support */
- if (private->rdc_data.facilities.XRC_supported) {
-
- data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
- data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
-
- data->ep_sys_time = get_clock ();
-
- de_ccw->count = sizeof (struct DE_eckd_data);
- de_ccw->flags |= CCW_FLAG_SLI;
- }
+ data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
+ data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
- return;
+ rc = get_sync_clock(&data->ep_sys_time);
+ /* Ignore return code if sync clock is switched off. */
+ if (rc == -ENOSYS || rc == -EACCES)
+ rc = 0;
-} /* end check_XRC */
+ de_ccw->count = sizeof (struct DE_eckd_data);
+ de_ccw->flags |= CCW_FLAG_SLI;
+ return rc;
+}
-static inline void
+static int
define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
int totrk, int cmd, struct dasd_device * device)
{
struct dasd_eckd_private *private;
struct ch_t geo, beg, end;
+ int rc = 0;
private = (struct dasd_eckd_private *) device->private;
@@ -263,12 +228,12 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
case DASD_ECKD_CCW_WRITE_KD_MT:
data->mask.perm = 0x02;
data->attributes.operation = private->attrib.operation;
- check_XRC (ccw, data, device);
+ rc = check_XRC (ccw, data, device);
break;
case DASD_ECKD_CCW_WRITE_CKD:
case DASD_ECKD_CCW_WRITE_CKD_MT:
data->attributes.operation = DASD_BYPASS_CACHE;
- check_XRC (ccw, data, device);
+ rc = check_XRC (ccw, data, device);
break;
case DASD_ECKD_CCW_ERASE:
case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
@@ -276,7 +241,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
data->mask.perm = 0x3;
data->mask.auth = 0x1;
data->attributes.operation = DASD_BYPASS_CACHE;
- check_XRC (ccw, data, device);
+ rc = check_XRC (ccw, data, device);
break;
default:
DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd);
@@ -312,9 +277,10 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
data->beg_ext.head = beg.head;
data->end_ext.cyl = end.cyl;
data->end_ext.head = end.head;
+ return rc;
}
-static inline void
+static void
locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
int rec_on_trk, int no_rec, int cmd,
struct dasd_device * device, int reclen)
@@ -548,7 +514,7 @@ dasd_eckd_read_conf(struct dasd_device *device)
/*
* Build CP for Perform Subsystem Function - SSC.
*/
-struct dasd_ccw_req *
+static struct dasd_ccw_req *
dasd_eckd_build_psf_ssc(struct dasd_device *device)
{
struct dasd_ccw_req *cqr;
@@ -1200,7 +1166,12 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
return cqr;
ccw = cqr->cpaddr;
/* First ccw is define extent. */
- define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device);
+ if (define_extent(ccw++, cqr->data, first_trk,
+ last_trk, cmd, device) == -EAGAIN) {
+ /* Clock not in sync and XRC is enabled. Try again later. */
+ dasd_sfree_request(cqr, device);
+ return ERR_PTR(-EAGAIN);
+ }
/* Build locate_record+read/write/ccws. */
idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
LO_data = (struct LO_eckd_data *) (idaws + cidaw);
@@ -1380,7 +1351,7 @@ dasd_eckd_release(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- cqr->retries = 0;
+ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1420,7 +1391,7 @@ dasd_eckd_reserve(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- cqr->retries = 0;
+ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1459,7 +1430,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- cqr->retries = 0;
+ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1609,7 +1580,7 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
* Dump the range of CCWs into 'page' buffer
* and return number of printed chars.
*/
-static inline int
+static int
dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
{
int len, count;
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index e0bf30ebb21..6cedc914077 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -658,18 +658,24 @@ static struct file_operations dasd_eer_fops = {
.owner = THIS_MODULE,
};
-static struct miscdevice dasd_eer_dev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "dasd_eer",
- .fops = &dasd_eer_fops,
-};
+static struct miscdevice *dasd_eer_dev = NULL;
int __init dasd_eer_init(void)
{
int rc;
- rc = misc_register(&dasd_eer_dev);
+ dasd_eer_dev = kzalloc(sizeof(*dasd_eer_dev), GFP_KERNEL);
+ if (!dasd_eer_dev)
+ return -ENOMEM;
+
+ dasd_eer_dev->minor = MISC_DYNAMIC_MINOR;
+ dasd_eer_dev->name = "dasd_eer";
+ dasd_eer_dev->fops = &dasd_eer_fops;
+
+ rc = misc_register(dasd_eer_dev);
if (rc) {
+ kfree(dasd_eer_dev);
+ dasd_eer_dev = NULL;
MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
"register misc device");
return rc;
@@ -680,5 +686,9 @@ int __init dasd_eer_init(void)
void dasd_eer_exit(void)
{
- WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
+ if (dasd_eer_dev) {
+ WARN_ON(misc_deregister(dasd_eer_dev) != 0);
+ kfree(dasd_eer_dev);
+ dasd_eer_dev = NULL;
+ }
}
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index 58a65097922..caa5d91420f 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -152,25 +152,6 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
} /* end default_erp_postaction */
-/*
- * Print the hex dump of the memory used by a request. This includes
- * all error recovery ccws that have been chained in from of the
- * real request.
- */
-static inline void
-hex_dump_memory(struct dasd_device *device, void *data, int len)
-{
- int *pint;
-
- pint = (int *) data;
- while (len > 0) {
- DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x",
- pint, pint[0], pint[1], pint[2], pint[3]);
- pint += 4;
- len -= 16;
- }
-}
-
void
dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
{
@@ -182,69 +163,8 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
device->discipline->dump_sense(device, cqr, irb);
}
-void
-dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa)
-{
- struct dasd_device *device;
- struct dasd_ccw_req *lcqr;
- struct ccw1 *ccw;
- int cplength;
-
- device = cqr->device;
- /* log the channel program */
- for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) {
- DEV_MESSAGE(KERN_ERR, device,
- "(%s) ERP chain report for req: %p",
- caller == 0 ? "EXAMINE" : "ACTION", lcqr);
- hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req));
-
- cplength = 1;
- ccw = lcqr->cpaddr;
- while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC))
- cplength++;
-
- if (cplength > 40) { /* log only parts of the CP */
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "Start of channel program:");
- hex_dump_memory(device, lcqr->cpaddr,
- 40*sizeof(struct ccw1));
-
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "End of channel program:");
- hex_dump_memory(device, lcqr->cpaddr + cplength - 10,
- 10*sizeof(struct ccw1));
- } else { /* log the whole CP */
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "Channel program (complete):");
- hex_dump_memory(device, lcqr->cpaddr,
- cplength*sizeof(struct ccw1));
- }
-
- if (lcqr != cqr)
- continue;
-
- /*
- * Log bytes arround failed CCW but only if we did
- * not log the whole CP of the CCW is outside the
- * logged CP.
- */
- if (cplength > 40 ||
- ((addr_t) cpa < (addr_t) lcqr->cpaddr &&
- (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
-
- DEV_MESSAGE(KERN_ERR, device,
- "Failed CCW (%p) (area):",
- (void *) (long) cpa);
- hex_dump_memory(device, cqr->cpaddr - 10,
- 20*sizeof(struct ccw1));
- }
- }
-
-} /* end log_erp_chain */
-
EXPORT_SYMBOL(dasd_default_erp_action);
EXPORT_SYMBOL(dasd_default_erp_postaction);
EXPORT_SYMBOL(dasd_alloc_erp_request);
EXPORT_SYMBOL(dasd_free_erp_request);
EXPORT_SYMBOL(dasd_log_sense);
-EXPORT_SYMBOL(dasd_log_ccw);
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index b857fd5893f..be0909e3922 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -75,7 +75,7 @@ static struct ccw_driver dasd_fba_driver = {
.notify = dasd_generic_notify,
};
-static inline void
+static void
define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
int blksize, int beg, int nr)
{
@@ -95,7 +95,7 @@ define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
data->ext_end = nr - 1;
}
-static inline void
+static void
locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
int block_nr, int block_ct)
{
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index d163632101d..47ba4462708 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -147,7 +147,7 @@ dasd_destroy_partitions(struct dasd_device * device)
*/
memset(&bpart, 0, sizeof(struct blkpg_partition));
memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
- barg.data = (void __user *) &bpart;
+ barg.data = (void __force __user *) &bpart;
barg.op = BLKPG_DEL_PARTITION;
for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index dc5dd509434..a2cc69e1141 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -13,10 +13,6 @@
#ifdef __KERNEL__
-/* erp debugging in dasd.c and dasd_3990_erp.c */
-#define ERP_DEBUG
-
-
/* we keep old device allocation scheme; IOW, minors are still in 0..255 */
#define DASD_PER_MAJOR (1U << (MINORBITS - DASD_PARTN_BITS))
#define DASD_PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
@@ -563,7 +559,6 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
struct dasd_device *);
void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
-void dasd_log_ccw(struct dasd_ccw_req *, int, __u32);
/* externals in dasd_3370_erp.c */
dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 8fed3603e9e..758cfb54286 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -430,7 +430,7 @@ dasd_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
int rval;
lock_kernel();
- rval = dasd_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ rval = dasd_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return (rval == -EINVAL) ? -ENOIOCTLCMD : rval;
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index bfa010f6dab..8b7e11815d7 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -28,7 +28,7 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL;
static struct proc_dir_entry *dasd_devices_entry = NULL;
static struct proc_dir_entry *dasd_statistics_entry = NULL;
-static inline char *
+static char *
dasd_get_user_string(const char __user *user_buf, size_t user_len)
{
char *buffer;
@@ -154,7 +154,7 @@ static struct file_operations dasd_devices_file_ops = {
.release = seq_release,
};
-static inline int
+static int
dasd_calc_metrics(char *page, char **start, off_t off,
int count, int *eof, int len)
{
@@ -167,8 +167,8 @@ dasd_calc_metrics(char *page, char **start, off_t off,
return len;
}
-static inline char *
-dasd_statistics_array(char *str, int *array, int shift)
+static char *
+dasd_statistics_array(char *str, unsigned int *array, int shift)
{
int i;
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index be9b05347b4..1340451ea40 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -102,7 +102,7 @@ dcssblk_release_segment(struct device *dev)
* device needs to be enqueued before the semaphore is
* freed.
*/
-static inline int
+static int
dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
{
int minor, found;
@@ -230,7 +230,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
SEGMENT_SHARED);
if (rc < 0) {
BUG_ON(rc == -EINVAL);
- if (rc == -EIO || rc == -ENOENT)
+ if (rc != -EAGAIN)
goto removeseg;
} else {
dev_info->is_shared = 1;
@@ -253,7 +253,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
SEGMENT_EXCLUSIVE);
if (rc < 0) {
BUG_ON(rc == -EINVAL);
- if (rc == -EIO || rc == -ENOENT)
+ if (rc != -EAGAIN)
goto removeseg;
} else {
dev_info->is_shared = 0;
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index c3e97b4fc18..293e667b50f 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -2,7 +2,8 @@
# S/390 character devices
#
-obj-y += ctrlchar.o keyboard.o defkeymap.o
+obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
+ sclp_info.o
obj-$(CONFIG_TN3270) += raw3270.o
obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
@@ -11,7 +12,6 @@ obj-$(CONFIG_TN3270_FS) += fs3270.o
obj-$(CONFIG_TN3215) += con3215.o
-obj-$(CONFIG_SCLP) += sclp.o sclp_rw.o sclp_quiesce.o
obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index c9321b920e9..9a328f14a64 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -688,7 +688,7 @@ raw3215_probe (struct ccw_device *cdev)
raw->cdev = cdev;
raw->inbuf = (char *) raw + sizeof(struct raw3215_info);
memset(raw, 0, sizeof(struct raw3215_info));
- raw->buffer = (char *) kmalloc(RAW3215_BUFFER_SIZE,
+ raw->buffer = kmalloc(RAW3215_BUFFER_SIZE,
GFP_KERNEL|GFP_DMA);
if (raw->buffer == NULL) {
spin_lock(&raw3215_device_lock);
@@ -1121,7 +1121,7 @@ static const struct tty_operations tty3215_ops = {
* 3215 tty registration code called from tty_init().
* Most kernel services (incl. kmalloc) are available at this poimt.
*/
-int __init
+static int __init
tty3215_init(void)
{
struct tty_driver *driver;
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 7566be89068..8e7f2d7633d 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -69,8 +69,7 @@ static void con3270_update(struct con3270 *);
/*
* Setup timeout for a device. On timeout trigger an update.
*/
-void
-con3270_set_timer(struct con3270 *cp, int expires)
+static void con3270_set_timer(struct con3270 *cp, int expires)
{
if (expires == 0) {
if (timer_pending(&cp->timer))
diff --git a/drivers/s390/char/ctrlchar.c b/drivers/s390/char/ctrlchar.c
index 49e9628d929..c6cbcb3f925 100644
--- a/drivers/s390/char/ctrlchar.c
+++ b/drivers/s390/char/ctrlchar.c
@@ -16,14 +16,15 @@
#ifdef CONFIG_MAGIC_SYSRQ
static int ctrlchar_sysrq_key;
+static struct tty_struct *sysrq_tty;
static void
-ctrlchar_handle_sysrq(void *tty)
+ctrlchar_handle_sysrq(struct work_struct *work)
{
- handle_sysrq(ctrlchar_sysrq_key, (struct tty_struct *) tty);
+ handle_sysrq(ctrlchar_sysrq_key, sysrq_tty);
}
-static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, NULL);
+static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq);
#endif
@@ -53,7 +54,7 @@ ctrlchar_handle(const unsigned char *buf, int len, struct tty_struct *tty)
/* racy */
if (len == 3 && buf[1] == '-') {
ctrlchar_sysrq_key = buf[2];
- ctrlchar_work.data = tty;
+ sysrq_tty = tty;
schedule_work(&ctrlchar_work);
return CTRLCHAR_SYSRQ;
}
diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c
index 17027d918cf..564baca01b7 100644
--- a/drivers/s390/char/defkeymap.c
+++ b/drivers/s390/char/defkeymap.c
@@ -5,6 +5,8 @@
#include <linux/types.h>
#include <linux/keyboard.h>
#include <linux/kd.h>
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
u_short plain_map[NR_KEYS] = {
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 78f8bda81da..e1a746269c4 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -23,7 +23,7 @@
#include "raw3270.h"
#include "ctrlchar.h"
-struct raw3270_fn fs3270_fn;
+static struct raw3270_fn fs3270_fn;
struct fs3270 {
struct raw3270_view view;
@@ -401,7 +401,7 @@ fs3270_release(struct raw3270_view *view)
}
/* View to a 3270 device. Can be console, tty or fullscreen. */
-struct raw3270_fn fs3270_fn = {
+static struct raw3270_fn fs3270_fn = {
.activate = fs3270_activate,
.deactivate = fs3270_deactivate,
.intv = (void *) fs3270_irq,
@@ -419,16 +419,20 @@ fs3270_open(struct inode *inode, struct file *filp)
struct idal_buffer *ib;
int minor, rc;
- if (imajor(filp->f_dentry->d_inode) != IBM_FS3270_MAJOR)
+ if (imajor(filp->f_path.dentry->d_inode) != IBM_FS3270_MAJOR)
return -ENODEV;
- minor = iminor(filp->f_dentry->d_inode);
+ minor = iminor(filp->f_path.dentry->d_inode);
/* Check for minor 0 multiplexer. */
if (minor == 0) {
- if (!current->signal->tty)
+ struct tty_struct *tty;
+ mutex_lock(&tty_mutex);
+ tty = get_current_tty();
+ if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
+ mutex_unlock(&tty_mutex);
return -ENODEV;
- if (current->signal->tty->driver->major != IBM_TTY3270_MAJOR)
- return -ENODEV;
- minor = current->signal->tty->index + RAW3270_FIRSTMINOR;
+ }
+ minor = tty->index + RAW3270_FIRSTMINOR;
+ mutex_unlock(&tty_mutex);
}
/* Check if some other program is already using fullscreen mode. */
fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index e3491a5f521..f62f9a4e895 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -148,6 +148,7 @@ kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc)
}
}
+#if 0
/*
* Generate ebcdic -> ascii translation table from kbd_data.
*/
@@ -173,6 +174,7 @@ kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc)
}
}
}
+#endif
/*
* We have a combining character DIACR here, followed by the character CH.
@@ -377,7 +379,7 @@ do_kdsk_ioctl(struct kbd_data *kbd, struct kbentry __user *user_kbe,
if (!(key_map = kbd->key_maps[tmp.kb_table])) {
int j;
- key_map = (ushort *) kmalloc(sizeof(plain_map),
+ key_map = kmalloc(sizeof(plain_map),
GFP_KERNEL);
if (!key_map)
return -ENOMEM;
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index a138b151009..3a1a958fb5f 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -3,7 +3,7 @@
*
* Character device driver for reading z/VM *MONITOR service records.
*
- * Copyright (C) 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH.
*
* Author: Gerald Schaefer <geraldsc@de.ibm.com>
*/
@@ -22,7 +22,7 @@
#include <asm/ebcdic.h>
#include <asm/extmem.h>
#include <linux/poll.h>
-#include "../net/iucv.h"
+#include <net/iucv/iucv.h>
//#define MON_DEBUG /* Debug messages on/off */
@@ -50,14 +50,13 @@ static char mon_dcss_name[9] = "MONDCSS\0";
struct mon_msg {
u32 pos;
u32 mca_offset;
- iucv_MessagePending local_eib;
+ struct iucv_message msg;
char msglim_reached;
char replied_msglim;
};
struct mon_private {
- u16 pathid;
- iucv_handle_t iucv_handle;
+ struct iucv_path *path;
struct mon_msg *msg_array[MON_MSGLIM];
unsigned int write_index;
unsigned int read_index;
@@ -75,8 +74,6 @@ static unsigned long mon_dcss_end;
static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue);
static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue);
-static u8 iucv_host[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
static u8 user_data_connect[16] = {
/* Version code, must be 0x01 for shared mode */
0x01,
@@ -100,8 +97,7 @@ static u8 user_data_sever[16] = {
* Create the 8 bytes EBCDIC DCSS segment name from
* an ASCII name, incl. padding
*/
-static inline void
-dcss_mkname(char *ascii_name, char *ebcdic_name)
+static inline void dcss_mkname(char *ascii_name, char *ebcdic_name)
{
int i;
@@ -119,8 +115,7 @@ dcss_mkname(char *ascii_name, char *ebcdic_name)
* print appropriate error message for segment_load()/segment_type()
* return code
*/
-static void
-mon_segment_warn(int rc, char* seg_name)
+static void mon_segment_warn(int rc, char* seg_name)
{
switch (rc) {
case -ENOENT:
@@ -166,44 +161,37 @@ mon_segment_warn(int rc, char* seg_name)
}
}
-static inline unsigned long
-mon_mca_start(struct mon_msg *monmsg)
+static inline unsigned long mon_mca_start(struct mon_msg *monmsg)
{
- return monmsg->local_eib.ln1msg1.iprmmsg1_u32;
+ return *(u32 *) &monmsg->msg.rmmsg;
}
-static inline unsigned long
-mon_mca_end(struct mon_msg *monmsg)
+static inline unsigned long mon_mca_end(struct mon_msg *monmsg)
{
- return monmsg->local_eib.ln1msg2.ipbfln1f;
+ return *(u32 *) &monmsg->msg.rmmsg[4];
}
-static inline u8
-mon_mca_type(struct mon_msg *monmsg, u8 index)
+static inline u8 mon_mca_type(struct mon_msg *monmsg, u8 index)
{
return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index);
}
-static inline u32
-mon_mca_size(struct mon_msg *monmsg)
+static inline u32 mon_mca_size(struct mon_msg *monmsg)
{
return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1;
}
-static inline u32
-mon_rec_start(struct mon_msg *monmsg)
+static inline u32 mon_rec_start(struct mon_msg *monmsg)
{
return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4));
}
-static inline u32
-mon_rec_end(struct mon_msg *monmsg)
+static inline u32 mon_rec_end(struct mon_msg *monmsg)
{
return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8));
}
-static inline int
-mon_check_mca(struct mon_msg *monmsg)
+static inline int mon_check_mca(struct mon_msg *monmsg)
{
if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) ||
(mon_rec_start(monmsg) < mon_dcss_start) ||
@@ -221,20 +209,17 @@ mon_check_mca(struct mon_msg *monmsg)
return 0;
}
-static inline int
-mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv)
+static inline int mon_send_reply(struct mon_msg *monmsg,
+ struct mon_private *monpriv)
{
- u8 prmmsg[8];
int rc;
P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = "
"0x%08X\n\n",
- monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid,
- monmsg->local_eib.iptrgcls);
- rc = iucv_reply_prmmsg(monmsg->local_eib.ippathid,
- monmsg->local_eib.ipmsgid,
- monmsg->local_eib.iptrgcls,
- 0, prmmsg);
+ monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class);
+
+ rc = iucv_message_reply(monpriv->path, &monmsg->msg,
+ IUCV_IPRMDATA, NULL, 0);
atomic_dec(&monpriv->msglim_count);
if (likely(!monmsg->msglim_reached)) {
monmsg->pos = 0;
@@ -251,10 +236,19 @@ mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv)
return 0;
}
-static inline struct mon_private *
-mon_alloc_mem(void)
+static inline void mon_free_mem(struct mon_private *monpriv)
+{
+ int i;
+
+ for (i = 0; i < MON_MSGLIM; i++)
+ if (monpriv->msg_array[i])
+ kfree(monpriv->msg_array[i]);
+ kfree(monpriv);
+}
+
+static inline struct mon_private *mon_alloc_mem(void)
{
- int i,j;
+ int i;
struct mon_private *monpriv;
monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
@@ -267,16 +261,15 @@ mon_alloc_mem(void)
GFP_KERNEL);
if (!monpriv->msg_array[i]) {
P_ERROR("open, no memory for msg_array\n");
- for (j = 0; j < i; j++)
- kfree(monpriv->msg_array[j]);
+ mon_free_mem(monpriv);
return NULL;
}
}
return monpriv;
}
-static inline void
-mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
+static inline void mon_read_debug(struct mon_msg *monmsg,
+ struct mon_private *monpriv)
{
#ifdef MON_DEBUG
u8 msg_type[2], mca_type;
@@ -284,7 +277,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1;
- memcpy(msg_type, &monmsg->local_eib.iptrgcls, 2);
+ memcpy(msg_type, &monmsg->msg.class, 2);
EBCASC(msg_type, 2);
mca_type = mon_mca_type(monmsg, 0);
EBCASC(&mca_type, 1);
@@ -292,8 +285,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n",
monpriv->read_index, monpriv->write_index);
P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n",
- monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid,
- monmsg->local_eib.iptrgcls);
+ monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class);
P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n",
msg_type[0], msg_type[1], mca_type ? mca_type : 'X',
mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2));
@@ -306,8 +298,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
#endif
}
-static inline void
-mon_next_mca(struct mon_msg *monmsg)
+static inline void mon_next_mca(struct mon_msg *monmsg)
{
if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12))
return;
@@ -316,8 +307,7 @@ mon_next_mca(struct mon_msg *monmsg)
monmsg->pos = 0;
}
-static inline struct mon_msg *
-mon_next_message(struct mon_private *monpriv)
+static inline struct mon_msg *mon_next_message(struct mon_private *monpriv)
{
struct mon_msg *monmsg;
@@ -342,39 +332,37 @@ mon_next_message(struct mon_private *monpriv)
/******************************************************************************
* IUCV handler *
*****************************************************************************/
-static void
-mon_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data)
+static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16])
{
- struct mon_private *monpriv = (struct mon_private *) pgm_data;
+ struct mon_private *monpriv = path->private;
P_DEBUG("IUCV connection completed\n");
P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = "
"0x%02X, Sample = 0x%02X\n",
- eib->ipuser[0], eib->ipuser[1], eib->ipuser[2]);
+ ipuser[0], ipuser[1], ipuser[2]);
atomic_set(&monpriv->iucv_connected, 1);
wake_up(&mon_conn_wait_queue);
}
-static void
-mon_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data)
+static void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
{
- struct mon_private *monpriv = (struct mon_private *) pgm_data;
+ struct mon_private *monpriv = path->private;
- P_ERROR("IUCV connection severed with rc = 0x%X\n",
- (u8) eib->ipuser[0]);
+ P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]);
+ iucv_path_sever(path, NULL);
atomic_set(&monpriv->iucv_severed, 1);
wake_up(&mon_conn_wait_queue);
wake_up_interruptible(&mon_read_wait_queue);
}
-static void
-mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data)
+static void mon_iucv_message_pending(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct mon_private *monpriv = (struct mon_private *) pgm_data;
+ struct mon_private *monpriv = path->private;
P_DEBUG("IUCV message pending\n");
- memcpy(&monpriv->msg_array[monpriv->write_index]->local_eib, eib,
- sizeof(iucv_MessagePending));
+ memcpy(&monpriv->msg_array[monpriv->write_index]->msg,
+ msg, sizeof(*msg));
if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) {
P_WARNING("IUCV message pending, message limit (%i) reached\n",
MON_MSGLIM);
@@ -385,54 +373,45 @@ mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data)
wake_up_interruptible(&mon_read_wait_queue);
}
-static iucv_interrupt_ops_t mon_iucvops = {
- .ConnectionComplete = mon_iucv_ConnectionComplete,
- .ConnectionSevered = mon_iucv_ConnectionSevered,
- .MessagePending = mon_iucv_MessagePending,
+static struct iucv_handler monreader_iucv_handler = {
+ .path_complete = mon_iucv_path_complete,
+ .path_severed = mon_iucv_path_severed,
+ .message_pending = mon_iucv_message_pending,
};
/******************************************************************************
* file operations *
*****************************************************************************/
-static int
-mon_open(struct inode *inode, struct file *filp)
+static int mon_open(struct inode *inode, struct file *filp)
{
- int rc, i;
struct mon_private *monpriv;
+ int rc;
/*
* only one user allowed
*/
+ rc = -EBUSY;
if (test_and_set_bit(MON_IN_USE, &mon_in_use))
- return -EBUSY;
+ goto out;
+ rc = -ENOMEM;
monpriv = mon_alloc_mem();
if (!monpriv)
- return -ENOMEM;
+ goto out_use;
/*
- * Register with IUCV and connect to *MONITOR service
+ * Connect to *MONITOR service
*/
- monpriv->iucv_handle = iucv_register_program("my_monreader ",
- MON_SERVICE,
- NULL,
- &mon_iucvops,
- monpriv);
- if (!monpriv->iucv_handle) {
- P_ERROR("failed to register with iucv driver\n");
- rc = -EIO;
- goto out_error;
- }
- P_INFO("open, registered with IUCV\n");
-
- rc = iucv_connect(&monpriv->pathid, MON_MSGLIM, user_data_connect,
- MON_SERVICE, iucv_host, IPRMDATA, NULL, NULL,
- monpriv->iucv_handle, NULL);
+ monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL);
+ if (!monpriv->path)
+ goto out_priv;
+ rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
+ MON_SERVICE, NULL, user_data_connect, monpriv);
if (rc) {
P_ERROR("iucv connection to *MONITOR failed with "
"IPUSER SEVER code = %i\n", rc);
rc = -EIO;
- goto out_unregister;
+ goto out_path;
}
/*
* Wait for connection confirmation
@@ -444,24 +423,23 @@ mon_open(struct inode *inode, struct file *filp)
atomic_set(&monpriv->iucv_severed, 0);
atomic_set(&monpriv->iucv_connected, 0);
rc = -EIO;
- goto out_unregister;
+ goto out_path;
}
P_INFO("open, established connection to *MONITOR service\n\n");
filp->private_data = monpriv;
return nonseekable_open(inode, filp);
-out_unregister:
- iucv_unregister_program(monpriv->iucv_handle);
-out_error:
- for (i = 0; i < MON_MSGLIM; i++)
- kfree(monpriv->msg_array[i]);
- kfree(monpriv);
+out_path:
+ kfree(monpriv->path);
+out_priv:
+ mon_free_mem(monpriv);
+out_use:
clear_bit(MON_IN_USE, &mon_in_use);
+out:
return rc;
}
-static int
-mon_close(struct inode *inode, struct file *filp)
+static int mon_close(struct inode *inode, struct file *filp)
{
int rc, i;
struct mon_private *monpriv = filp->private_data;
@@ -469,18 +447,12 @@ mon_close(struct inode *inode, struct file *filp)
/*
* Close IUCV connection and unregister
*/
- rc = iucv_sever(monpriv->pathid, user_data_sever);
+ rc = iucv_path_sever(monpriv->path, user_data_sever);
if (rc)
P_ERROR("close, iucv_sever failed with rc = %i\n", rc);
else
P_INFO("close, terminated connection to *MONITOR service\n");
- rc = iucv_unregister_program(monpriv->iucv_handle);
- if (rc)
- P_ERROR("close, iucv_unregister failed with rc = %i\n", rc);
- else
- P_INFO("close, unregistered with IUCV\n");
-
atomic_set(&monpriv->iucv_severed, 0);
atomic_set(&monpriv->iucv_connected, 0);
atomic_set(&monpriv->read_ready, 0);
@@ -495,8 +467,8 @@ mon_close(struct inode *inode, struct file *filp)
return 0;
}
-static ssize_t
-mon_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
+static ssize_t mon_read(struct file *filp, char __user *data,
+ size_t count, loff_t *ppos)
{
struct mon_private *monpriv = filp->private_data;
struct mon_msg *monmsg;
@@ -563,8 +535,7 @@ out_copy:
return count;
}
-static unsigned int
-mon_poll(struct file *filp, struct poll_table_struct *p)
+static unsigned int mon_poll(struct file *filp, struct poll_table_struct *p)
{
struct mon_private *monpriv = filp->private_data;
@@ -593,8 +564,7 @@ static struct miscdevice mon_dev = {
/******************************************************************************
* module init/exit *
*****************************************************************************/
-static int __init
-mon_init(void)
+static int __init mon_init(void)
{
int rc;
@@ -603,22 +573,34 @@ mon_init(void)
return -ENODEV;
}
+ /*
+ * Register with IUCV and connect to *MONITOR service
+ */
+ rc = iucv_register(&monreader_iucv_handler, 1);
+ if (rc) {
+ P_ERROR("failed to register with iucv driver\n");
+ return rc;
+ }
+ P_INFO("open, registered with IUCV\n");
+
rc = segment_type(mon_dcss_name);
if (rc < 0) {
mon_segment_warn(rc, mon_dcss_name);
- return rc;
+ goto out_iucv;
}
if (rc != SEG_TYPE_SC) {
P_ERROR("segment %s has unsupported type, should be SC\n",
mon_dcss_name);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out_iucv;
}
rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
&mon_dcss_start, &mon_dcss_end);
if (rc < 0) {
mon_segment_warn(rc, mon_dcss_name);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out_iucv;
}
dcss_mkname(mon_dcss_name, &user_data_connect[8]);
@@ -634,14 +616,16 @@ mon_init(void)
out:
segment_unload(mon_dcss_name);
+out_iucv:
+ iucv_unregister(&monreader_iucv_handler, 1);
return rc;
}
-static void __exit
-mon_exit(void)
+static void __exit mon_exit(void)
{
segment_unload(mon_dcss_name);
WARN_ON(misc_deregister(&mon_dev) != 0);
+ iucv_unregister(&monreader_iucv_handler, 1);
return;
}
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index b9b0fc3f812..9e451acc649 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -23,7 +23,7 @@
#include <asm/appldata.h>
#include <asm/monwriter.h>
-#define MONWRITE_MAX_DATALEN 4024
+#define MONWRITE_MAX_DATALEN 4010
static int mon_max_bufs = 255;
static int mon_buf_count;
@@ -67,8 +67,8 @@ static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
return -EINVAL;
}
-static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
- struct monwrite_hdr *monhdr)
+static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
+ struct monwrite_hdr *monhdr)
{
struct mon_buf *entry, *next;
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 7a84014f203..8facd14adb7 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -29,7 +29,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
-struct class *class3270;
+static struct class *class3270;
/* The main 3270 data structure. */
struct raw3270 {
@@ -86,7 +86,7 @@ DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
/*
* Encode array for 12 bit 3270 addresses.
*/
-unsigned char raw3270_ebcgraf[64] = {
+static unsigned char raw3270_ebcgraf[64] = {
0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 8a056df09d6..f171de3b0b1 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -59,7 +59,8 @@ static volatile enum sclp_init_state_t {
/* Internal state: is a request active at the sclp? */
static volatile enum sclp_running_state_t {
sclp_running_state_idle,
- sclp_running_state_running
+ sclp_running_state_running,
+ sclp_running_state_reset_pending
} sclp_running_state = sclp_running_state_idle;
/* Internal state: is a read request pending? */
@@ -88,15 +89,15 @@ static volatile enum sclp_mask_state_t {
/* Timeout intervals in seconds.*/
#define SCLP_BUSY_INTERVAL 10
-#define SCLP_RETRY_INTERVAL 15
+#define SCLP_RETRY_INTERVAL 30
static void sclp_process_queue(void);
static int sclp_init_mask(int calculate);
static int sclp_init(void);
/* Perform service call. Return 0 on success, non-zero otherwise. */
-static int
-service_call(sclp_cmdw_t command, void *sccb)
+int
+sclp_service_call(sclp_cmdw_t command, void *sccb)
{
int cc;
@@ -113,19 +114,17 @@ service_call(sclp_cmdw_t command, void *sccb)
return 0;
}
-/* Request timeout handler. Restart the request queue. If DATA is non-zero,
- * force restart of running request. */
+static inline void __sclp_make_read_req(void);
+
static void
-sclp_request_timeout(unsigned long data)
+__sclp_queue_read_req(void)
{
- unsigned long flags;
-
- if (data) {
- spin_lock_irqsave(&sclp_lock, flags);
- sclp_running_state = sclp_running_state_idle;
- spin_unlock_irqrestore(&sclp_lock, flags);
+ if (sclp_reading_state == sclp_reading_state_idle) {
+ sclp_reading_state = sclp_reading_state_reading;
+ __sclp_make_read_req();
+ /* Add request to head of queue */
+ list_add(&sclp_read_req.list, &sclp_req_queue);
}
- sclp_process_queue();
}
/* Set up request retry timer. Called while sclp_lock is locked. */
@@ -140,6 +139,29 @@ __sclp_set_request_timer(unsigned long time, void (*function)(unsigned long),
add_timer(&sclp_request_timer);
}
+/* Request timeout handler. Restart the request queue. If DATA is non-zero,
+ * force restart of running request. */
+static void
+sclp_request_timeout(unsigned long data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sclp_lock, flags);
+ if (data) {
+ if (sclp_running_state == sclp_running_state_running) {
+ /* Break running state and queue NOP read event request
+ * to get a defined interface state. */
+ __sclp_queue_read_req();
+ sclp_running_state = sclp_running_state_idle;
+ }
+ } else {
+ __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+ sclp_request_timeout, 0);
+ }
+ spin_unlock_irqrestore(&sclp_lock, flags);
+ sclp_process_queue();
+}
+
/* Try to start a request. Return zero if the request was successfully
* started or if it will be started at a later time. Return non-zero otherwise.
* Called while sclp_lock is locked. */
@@ -151,7 +173,7 @@ __sclp_start_request(struct sclp_req *req)
if (sclp_running_state != sclp_running_state_idle)
return 0;
del_timer(&sclp_request_timer);
- rc = service_call(req->command, req->sccb);
+ rc = sclp_service_call(req->command, req->sccb);
req->start_count++;
if (rc == 0) {
@@ -191,7 +213,15 @@ sclp_process_queue(void)
rc = __sclp_start_request(req);
if (rc == 0)
break;
- /* Request failed. */
+ /* Request failed */
+ if (req->start_count > 1) {
+ /* Cannot abort already submitted request - could still
+ * be active at the SCLP */
+ __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+ sclp_request_timeout, 0);
+ break;
+ }
+ /* Post-processing for aborted request */
list_del(&req->list);
if (req->callback) {
spin_unlock_irqrestore(&sclp_lock, flags);
@@ -221,7 +251,8 @@ sclp_add_request(struct sclp_req *req)
list_add_tail(&req->list, &sclp_req_queue);
rc = 0;
/* Start if request is first in list */
- if (req->list.prev == &sclp_req_queue) {
+ if (sclp_running_state == sclp_running_state_idle &&
+ req->list.prev == &sclp_req_queue) {
rc = __sclp_start_request(req);
if (rc)
list_del(&req->list);
@@ -294,7 +325,7 @@ __sclp_make_read_req(void)
sccb = (struct sccb_header *) sclp_read_sccb;
clear_page(sccb);
memset(&sclp_read_req, 0, sizeof(struct sclp_req));
- sclp_read_req.command = SCLP_CMDW_READDATA;
+ sclp_read_req.command = SCLP_CMDW_READ_EVENT_DATA;
sclp_read_req.status = SCLP_REQ_QUEUED;
sclp_read_req.start_count = 0;
sclp_read_req.callback = sclp_read_cb;
@@ -334,6 +365,8 @@ sclp_interrupt_handler(__u16 code)
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
evbuf_pending = S390_lowcore.ext_params & 0x3;
if (finished_sccb) {
+ del_timer(&sclp_request_timer);
+ sclp_running_state = sclp_running_state_reset_pending;
req = __sclp_find_req(finished_sccb);
if (req) {
/* Request post-processing */
@@ -348,13 +381,8 @@ sclp_interrupt_handler(__u16 code)
sclp_running_state = sclp_running_state_idle;
}
if (evbuf_pending && sclp_receive_mask != 0 &&
- sclp_reading_state == sclp_reading_state_idle &&
- sclp_activation_state == sclp_activation_state_active ) {
- sclp_reading_state = sclp_reading_state_reading;
- __sclp_make_read_req();
- /* Add request to head of queue */
- list_add(&sclp_read_req.list, &sclp_req_queue);
- }
+ sclp_activation_state == sclp_activation_state_active)
+ __sclp_queue_read_req();
spin_unlock(&sclp_lock);
sclp_process_queue();
}
@@ -374,6 +402,7 @@ sclp_sync_wait(void)
unsigned long flags;
unsigned long cr0, cr0_sync;
u64 timeout;
+ int irq_context;
/* We'll be disabling timer interrupts, so we need a custom timeout
* mechanism */
@@ -386,7 +415,9 @@ sclp_sync_wait(void)
}
local_irq_save(flags);
/* Prevent bottom half from executing once we force interrupts open */
- local_bh_disable();
+ irq_context = in_interrupt();
+ if (!irq_context)
+ local_bh_disable();
/* Enable service-signal interruption, disable timer interrupts */
trace_hardirqs_on();
__ctl_store(cr0, 0, 0);
@@ -402,19 +433,19 @@ sclp_sync_wait(void)
get_clock() > timeout &&
del_timer(&sclp_request_timer))
sclp_request_timer.function(sclp_request_timer.data);
- barrier();
cpu_relax();
}
local_irq_disable();
__ctl_load(cr0, 0, 0);
- _local_bh_enable();
+ if (!irq_context)
+ _local_bh_enable();
local_irq_restore(flags);
}
EXPORT_SYMBOL(sclp_sync_wait);
/* Dispatch changes in send and receive mask to registered listeners. */
-static inline void
+static void
sclp_dispatch_state_change(void)
{
struct list_head *l;
@@ -597,7 +628,7 @@ __sclp_make_init_req(u32 receive_mask, u32 send_mask)
sccb = (struct init_sccb *) sclp_init_sccb;
clear_page(sccb);
memset(&sclp_init_req, 0, sizeof(struct sclp_req));
- sclp_init_req.command = SCLP_CMDW_WRITEMASK;
+ sclp_init_req.command = SCLP_CMDW_WRITE_EVENT_MASK;
sclp_init_req.status = SCLP_REQ_FILLED;
sclp_init_req.start_count = 0;
sclp_init_req.callback = NULL;
@@ -800,7 +831,7 @@ sclp_check_interface(void)
for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) {
__sclp_make_init_req(0, 0);
sccb = (struct init_sccb *) sclp_init_req.sccb;
- rc = service_call(sclp_init_req.command, sccb);
+ rc = sclp_service_call(sclp_init_req.command, sccb);
if (rc == -EIO)
break;
sclp_init_req.status = SCLP_REQ_RUNNING;
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 2c71d6ee7b5..7d29ab45a6e 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -12,7 +12,7 @@
#include <linux/types.h>
#include <linux/list.h>
-
+#include <asm/sclp.h>
#include <asm/ebcdic.h>
/* maximum number of pages concerning our own memory management */
@@ -49,9 +49,11 @@
typedef unsigned int sclp_cmdw_t;
-#define SCLP_CMDW_READDATA 0x00770005
-#define SCLP_CMDW_WRITEDATA 0x00760005
-#define SCLP_CMDW_WRITEMASK 0x00780005
+#define SCLP_CMDW_READ_EVENT_DATA 0x00770005
+#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005
+#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005
+#define SCLP_CMDW_READ_SCP_INFO 0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
#define GDS_ID_MDSMU 0x1310
#define GDS_ID_MDSRouteInfo 0x1311
@@ -66,13 +68,6 @@ typedef unsigned int sclp_cmdw_t;
typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */
-struct sccb_header {
- u16 length;
- u8 function_code;
- u8 control_mask[3];
- u16 response_code;
-} __attribute__((packed));
-
struct gds_subvector {
u8 length;
u8 key;
@@ -131,6 +126,7 @@ void sclp_unregister(struct sclp_register *reg);
int sclp_remove_processed(struct sccb_header *sccb);
int sclp_deactivate(void);
int sclp_reactivate(void);
+int sclp_service_call(sclp_cmdw_t command, void *sccb);
/* useful inlines */
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c
index 86864f64171..ead1043d788 100644
--- a/drivers/s390/char/sclp_con.c
+++ b/drivers/s390/char/sclp_con.c
@@ -66,7 +66,7 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
} while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
}
-static inline void
+static void
sclp_conbuf_emit(void)
{
struct sclp_buffer* buffer;
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
index 732dfbdb85c..65aa2c85737 100644
--- a/drivers/s390/char/sclp_cpi.c
+++ b/drivers/s390/char/sclp_cpi.c
@@ -49,6 +49,8 @@ static struct sclp_register sclp_cpi_event =
.send_mask = EvTyp_CtlProgIdent_Mask
};
+MODULE_LICENSE("GPL");
+
MODULE_AUTHOR(
"Martin Peschke, IBM Deutschland Entwicklung GmbH "
"<mpeschke@de.ibm.com>");
@@ -127,7 +129,7 @@ cpi_prepare_req(void)
struct cpi_sccb *sccb;
struct cpi_evbuf *evb;
- req = (struct sclp_req *) kmalloc(sizeof(struct sclp_req), GFP_KERNEL);
+ req = kmalloc(sizeof(struct sclp_req), GFP_KERNEL);
if (req == NULL)
return ERR_PTR(-ENOMEM);
sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA);
@@ -167,7 +169,7 @@ cpi_prepare_req(void)
}
/* prepare request data structure presented to SCLP driver */
- req->command = SCLP_CMDW_WRITEDATA;
+ req->command = SCLP_CMDW_WRITE_EVENT_DATA;
req->sccb = sccb;
req->status = SCLP_REQ_FILLED;
req->callback = cpi_callback;
diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c
new file mode 100644
index 00000000000..7bcbe643b08
--- /dev/null
+++ b/drivers/s390/char/sclp_info.c
@@ -0,0 +1,57 @@
+/*
+ * drivers/s390/char/sclp_info.c
+ *
+ * Copyright IBM Corp. 2007
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+
+struct sclp_readinfo_sccb s390_readinfo_sccb;
+
+void __init sclp_readinfo_early(void)
+{
+ sclp_cmdw_t command;
+ struct sccb_header *sccb;
+ int ret;
+
+ __ctl_set_bit(0, 9); /* enable service signal subclass mask */
+
+ sccb = &s390_readinfo_sccb.header;
+ command = SCLP_CMDW_READ_SCP_INFO_FORCED;
+ while (1) {
+ u16 response;
+
+ memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb));
+ sccb->length = sizeof(s390_readinfo_sccb);
+ sccb->control_mask[2] = 0x80;
+
+ ret = sclp_service_call(command, &s390_readinfo_sccb);
+
+ if (ret == -EIO)
+ goto out;
+ if (ret == -EBUSY)
+ continue;
+
+ __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
+ PSW_MASK_WAIT | PSW_DEFAULT_KEY);
+ local_irq_disable();
+ barrier();
+
+ response = sccb->response_code;
+
+ if (response == 0x10)
+ break;
+
+ if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO)
+ break;
+
+ command = SCLP_CMDW_READ_SCP_INFO;
+ }
+out:
+ __ctl_clear_bit(0, 9); /* disable service signal subclass mask */
+}
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index 0c92d3909cc..2486783ea58 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -460,7 +460,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
sccb->msg_buf.header.type = EvTyp_PMsgCmd;
else
return -ENOSYS;
- buffer->request.command = SCLP_CMDW_WRITEDATA;
+ buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
buffer->request.status = SCLP_REQ_FILLED;
buffer->request.callback = sclp_writedata_callback;
buffer->request.callback_data = buffer;
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 6f43e04dbef..90536f60bf5 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -60,8 +60,6 @@ static unsigned short int sclp_tty_chars_count;
struct tty_driver *sclp_tty_driver;
-extern struct termios tty_std_termios;
-
static struct sclp_ioctls sclp_ioctls;
static struct sclp_ioctls sclp_ioctls_init =
{
@@ -723,7 +721,7 @@ static const struct tty_operations sclp_ops = {
.ioctl = sclp_tty_ioctl,
};
-int __init
+static int __init
sclp_tty_init(void)
{
struct tty_driver *driver;
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 723bf4191bf..544f137d70d 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -207,7 +207,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request)
request->sclp_req.status = SCLP_REQ_FAILED;
return -EIO;
}
- request->sclp_req.command = SCLP_CMDW_WRITEDATA;
+ request->sclp_req.command = SCLP_CMDW_WRITE_EVENT_DATA;
request->sclp_req.status = SCLP_REQ_FILLED;
request->sclp_req.callback = sclp_vt220_callback;
request->sclp_req.callback_data = (void *) request;
@@ -669,7 +669,7 @@ static const struct tty_operations sclp_vt220_ops = {
/*
* Register driver with SCLP and Linux and initialize internal tty structures.
*/
-int __init
+static int __init
sclp_vt220_tty_init(void)
{
struct tty_driver *driver;
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index 1f4c89967be..bb4ff537729 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -3,7 +3,7 @@
* tape device driver for 3480/3490E/3590 tapes.
*
* S390 and zSeries version
- * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2001,2006
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -99,7 +99,11 @@ enum tape_op {
TO_DIS, /* Tape display */
TO_ASSIGN, /* Assign tape to channel path */
TO_UNASSIGN, /* Unassign tape from channel path */
- TO_SIZE /* #entries in tape_op_t */
+ TO_CRYPT_ON, /* Enable encrpytion */
+ TO_CRYPT_OFF, /* Disable encrpytion */
+ TO_KEKL_SET, /* Set KEK label */
+ TO_KEKL_QUERY, /* Query KEK label */
+ TO_SIZE, /* #entries in tape_op_t */
};
/* Forward declaration */
@@ -112,6 +116,7 @@ enum tape_request_status {
TAPE_REQUEST_IN_IO, /* request is currently in IO */
TAPE_REQUEST_DONE, /* request is completed. */
TAPE_REQUEST_CANCEL, /* request should be canceled. */
+ TAPE_REQUEST_LONG_BUSY, /* request has to be restarted after long busy */
};
/* Tape CCW request */
@@ -164,10 +169,11 @@ struct tape_discipline {
* The discipline irq function either returns an error code (<0) which
* means that the request has failed with an error or one of the following:
*/
-#define TAPE_IO_SUCCESS 0 /* request successful */
-#define TAPE_IO_PENDING 1 /* request still running */
-#define TAPE_IO_RETRY 2 /* retry to current request */
-#define TAPE_IO_STOP 3 /* stop the running request */
+#define TAPE_IO_SUCCESS 0 /* request successful */
+#define TAPE_IO_PENDING 1 /* request still running */
+#define TAPE_IO_RETRY 2 /* retry to current request */
+#define TAPE_IO_STOP 3 /* stop the running request */
+#define TAPE_IO_LONG_BUSY 4 /* delay the running request */
/* Char Frontend Data */
struct tape_char_data {
@@ -179,6 +185,7 @@ struct tape_char_data {
/* Block Frontend Data */
struct tape_blk_data
{
+ struct tape_device * device;
/* Block device request queue. */
request_queue_t * request_queue;
spinlock_t request_queue_lock;
@@ -240,7 +247,11 @@ struct tape_device {
#endif
/* Function to start or stop the next request later. */
- struct work_struct tape_dnr;
+ struct delayed_work tape_dnr;
+
+ /* Timer for long busy */
+ struct timer_list lb_timeout;
+
};
/* Externals from tape_core.c */
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index 7b95dab913d..e765875e8db 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -95,6 +95,12 @@ tape_34xx_medium_sense(struct tape_device *device)
return rc;
}
+struct tape_34xx_work {
+ struct tape_device *device;
+ enum tape_op op;
+ struct work_struct work;
+};
+
/*
* These functions are currently used only to schedule a medium_sense for
* later execution. This is because we get an interrupt whenever a medium
@@ -103,13 +109,10 @@ tape_34xx_medium_sense(struct tape_device *device)
* interrupt handler.
*/
static void
-tape_34xx_work_handler(void *data)
+tape_34xx_work_handler(struct work_struct *work)
{
- struct {
- struct tape_device *device;
- enum tape_op op;
- struct work_struct work;
- } *p = data;
+ struct tape_34xx_work *p =
+ container_of(work, struct tape_34xx_work, work);
switch(p->op) {
case TO_MSEN:
@@ -126,17 +129,13 @@ tape_34xx_work_handler(void *data)
static int
tape_34xx_schedule_work(struct tape_device *device, enum tape_op op)
{
- struct {
- struct tape_device *device;
- enum tape_op op;
- struct work_struct work;
- } *p;
+ struct tape_34xx_work *p;
if ((p = kmalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
return -ENOMEM;
memset(p, 0, sizeof(*p));
- INIT_WORK(&p->work, tape_34xx_work_handler, p);
+ INIT_WORK(&p->work, tape_34xx_work_handler);
p->device = tape_get_device_reference(device);
p->op = op;
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 928cbefc49d..50f5edab83d 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -2,7 +2,7 @@
* drivers/s390/char/tape_3590.c
* tape device discipline for 3590 tapes.
*
- * Copyright (C) IBM Corp. 2001,2006
+ * Copyright IBM Corp. 2001,2006
* Author(s): Stefan Bader <shbader@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/bio.h>
+#include <asm/ebcdic.h>
#define TAPE_DBF_AREA tape_3590_dbf
@@ -30,7 +31,7 @@ EXPORT_SYMBOL(TAPE_DBF_AREA);
* - Read Device (buffered) log: BRA
* - Read Library log: BRA
* - Swap Devices: BRA
- * - Long Busy: BRA
+ * - Long Busy: implemented
* - Special Intercept: BRA
* - Read Alternate: implemented
*******************************************************************/
@@ -94,6 +95,332 @@ static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = {
[0xae] = "Subsystem environmental alert",
};
+static int crypt_supported(struct tape_device *device)
+{
+ return TAPE390_CRYPT_SUPPORTED(TAPE_3590_CRYPT_INFO(device));
+}
+
+static int crypt_enabled(struct tape_device *device)
+{
+ return TAPE390_CRYPT_ON(TAPE_3590_CRYPT_INFO(device));
+}
+
+static void ext_to_int_kekl(struct tape390_kekl *in,
+ struct tape3592_kekl *out)
+{
+ int i;
+
+ memset(out, 0, sizeof(*out));
+ if (in->type == TAPE390_KEKL_TYPE_HASH)
+ out->flags |= 0x40;
+ if (in->type_on_tape == TAPE390_KEKL_TYPE_HASH)
+ out->flags |= 0x80;
+ strncpy(out->label, in->label, 64);
+ for (i = strlen(in->label); i < sizeof(out->label); i++)
+ out->label[i] = ' ';
+ ASCEBC(out->label, sizeof(out->label));
+}
+
+static void int_to_ext_kekl(struct tape3592_kekl *in,
+ struct tape390_kekl *out)
+{
+ memset(out, 0, sizeof(*out));
+ if(in->flags & 0x40)
+ out->type = TAPE390_KEKL_TYPE_HASH;
+ else
+ out->type = TAPE390_KEKL_TYPE_LABEL;
+ if(in->flags & 0x80)
+ out->type_on_tape = TAPE390_KEKL_TYPE_HASH;
+ else
+ out->type_on_tape = TAPE390_KEKL_TYPE_LABEL;
+ memcpy(out->label, in->label, sizeof(in->label));
+ EBCASC(out->label, sizeof(in->label));
+ strstrip(out->label);
+}
+
+static void int_to_ext_kekl_pair(struct tape3592_kekl_pair *in,
+ struct tape390_kekl_pair *out)
+{
+ if (in->count == 0) {
+ out->kekl[0].type = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[0].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+ } else if (in->count == 1) {
+ int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
+ out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+ } else if (in->count == 2) {
+ int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
+ int_to_ext_kekl(&in->kekl[1], &out->kekl[1]);
+ } else {
+ printk("Invalid KEKL number: %d\n", in->count);
+ BUG();
+ }
+}
+
+static int check_ext_kekl(struct tape390_kekl *kekl)
+{
+ if (kekl->type == TAPE390_KEKL_TYPE_NONE)
+ goto invalid;
+ if (kekl->type > TAPE390_KEKL_TYPE_HASH)
+ goto invalid;
+ if (kekl->type_on_tape == TAPE390_KEKL_TYPE_NONE)
+ goto invalid;
+ if (kekl->type_on_tape > TAPE390_KEKL_TYPE_HASH)
+ goto invalid;
+ if ((kekl->type == TAPE390_KEKL_TYPE_HASH) &&
+ (kekl->type_on_tape == TAPE390_KEKL_TYPE_LABEL))
+ goto invalid;
+
+ return 0;
+invalid:
+ return -EINVAL;
+}
+
+static int check_ext_kekl_pair(struct tape390_kekl_pair *kekls)
+{
+ if (check_ext_kekl(&kekls->kekl[0]))
+ goto invalid;
+ if (check_ext_kekl(&kekls->kekl[1]))
+ goto invalid;
+
+ return 0;
+invalid:
+ return -EINVAL;
+}
+
+/*
+ * Query KEKLs
+ */
+static int tape_3592_kekl_query(struct tape_device *device,
+ struct tape390_kekl_pair *ext_kekls)
+{
+ struct tape_request *request;
+ struct tape3592_kekl_query_order *order;
+ struct tape3592_kekl_query_data *int_kekls;
+ int rc;
+
+ DBF_EVENT(6, "tape3592_kekl_query\n");
+ int_kekls = kmalloc(sizeof(*int_kekls), GFP_KERNEL|GFP_DMA);
+ if (!int_kekls)
+ return -ENOMEM;
+ request = tape_alloc_request(2, sizeof(*order));
+ if (IS_ERR(request)) {
+ rc = PTR_ERR(request);
+ goto fail_malloc;
+ }
+ order = request->cpdata;
+ memset(order,0,sizeof(*order));
+ order->code = 0xe2;
+ order->max_count = 2;
+ request->op = TO_KEKL_QUERY;
+ tape_ccw_cc(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
+ tape_ccw_end(request->cpaddr + 1, READ_SS_DATA, sizeof(*int_kekls),
+ int_kekls);
+ rc = tape_do_io(device, request);
+ if (rc)
+ goto fail_request;
+ int_to_ext_kekl_pair(&int_kekls->kekls, ext_kekls);
+
+ rc = 0;
+fail_request:
+ tape_free_request(request);
+fail_malloc:
+ kfree(int_kekls);
+ return rc;
+}
+
+/*
+ * IOCTL: Query KEKLs
+ */
+static int tape_3592_ioctl_kekl_query(struct tape_device *device,
+ unsigned long arg)
+{
+ int rc;
+ struct tape390_kekl_pair *ext_kekls;
+
+ DBF_EVENT(6, "tape_3592_ioctl_kekl_query\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ if (!crypt_enabled(device))
+ return -EUNATCH;
+ ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);
+ if (!ext_kekls)
+ return -ENOMEM;
+ rc = tape_3592_kekl_query(device, ext_kekls);
+ if (rc != 0)
+ goto fail;
+ if (copy_to_user((char __user *) arg, ext_kekls, sizeof(*ext_kekls))) {
+ rc = -EFAULT;
+ goto fail;
+ }
+ rc = 0;
+fail:
+ kfree(ext_kekls);
+ return rc;
+}
+
+static int tape_3590_mttell(struct tape_device *device, int mt_count);
+
+/*
+ * Set KEKLs
+ */
+static int tape_3592_kekl_set(struct tape_device *device,
+ struct tape390_kekl_pair *ext_kekls)
+{
+ struct tape_request *request;
+ struct tape3592_kekl_set_order *order;
+
+ DBF_EVENT(6, "tape3592_kekl_set\n");
+ if (check_ext_kekl_pair(ext_kekls)) {
+ DBF_EVENT(6, "invalid kekls\n");
+ return -EINVAL;
+ }
+ if (tape_3590_mttell(device, 0) != 0)
+ return -EBADSLT;
+ request = tape_alloc_request(1, sizeof(*order));
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ order = request->cpdata;
+ memset(order, 0, sizeof(*order));
+ order->code = 0xe3;
+ order->kekls.count = 2;
+ ext_to_int_kekl(&ext_kekls->kekl[0], &order->kekls.kekl[0]);
+ ext_to_int_kekl(&ext_kekls->kekl[1], &order->kekls.kekl[1]);
+ request->op = TO_KEKL_SET;
+ tape_ccw_end(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
+
+ return tape_do_io_free(device, request);
+}
+
+/*
+ * IOCTL: Set KEKLs
+ */
+static int tape_3592_ioctl_kekl_set(struct tape_device *device,
+ unsigned long arg)
+{
+ int rc;
+ struct tape390_kekl_pair *ext_kekls;
+
+ DBF_EVENT(6, "tape_3592_ioctl_kekl_set\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ if (!crypt_enabled(device))
+ return -EUNATCH;
+ ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);
+ if (!ext_kekls)
+ return -ENOMEM;
+ if (copy_from_user(ext_kekls, (char __user *)arg, sizeof(*ext_kekls))) {
+ rc = -EFAULT;
+ goto out;
+ }
+ rc = tape_3592_kekl_set(device, ext_kekls);
+out:
+ kfree(ext_kekls);
+ return rc;
+}
+
+/*
+ * Enable encryption
+ */
+static int tape_3592_enable_crypt(struct tape_device *device)
+{
+ struct tape_request *request;
+ char *data;
+
+ DBF_EVENT(6, "tape_3592_enable_crypt\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ request = tape_alloc_request(2, 72);
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ data = request->cpdata;
+ memset(data,0,72);
+
+ data[0] = 0x05;
+ data[36 + 0] = 0x03;
+ data[36 + 1] = 0x03;
+ data[36 + 4] = 0x40;
+ data[36 + 6] = 0x01;
+ data[36 + 14] = 0x2f;
+ data[36 + 18] = 0xc3;
+ data[36 + 35] = 0x72;
+ request->op = TO_CRYPT_ON;
+ tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
+ tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
+ return tape_do_io_free(device, request);
+}
+
+/*
+ * Disable encryption
+ */
+static int tape_3592_disable_crypt(struct tape_device *device)
+{
+ struct tape_request *request;
+ char *data;
+
+ DBF_EVENT(6, "tape_3592_disable_crypt\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ request = tape_alloc_request(2, 72);
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ data = request->cpdata;
+ memset(data,0,72);
+
+ data[0] = 0x05;
+ data[36 + 0] = 0x03;
+ data[36 + 1] = 0x03;
+ data[36 + 35] = 0x32;
+
+ request->op = TO_CRYPT_OFF;
+ tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
+ tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
+
+ return tape_do_io_free(device, request);
+}
+
+/*
+ * IOCTL: Set encryption status
+ */
+static int tape_3592_ioctl_crypt_set(struct tape_device *device,
+ unsigned long arg)
+{
+ struct tape390_crypt_info info;
+
+ DBF_EVENT(6, "tape_3592_ioctl_crypt_set\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ if (copy_from_user(&info, (char __user *)arg, sizeof(info)))
+ return -EFAULT;
+ if (info.status & ~TAPE390_CRYPT_ON_MASK)
+ return -EINVAL;
+ if (info.status & TAPE390_CRYPT_ON_MASK)
+ return tape_3592_enable_crypt(device);
+ else
+ return tape_3592_disable_crypt(device);
+}
+
+static int tape_3590_sense_medium(struct tape_device *device);
+
+/*
+ * IOCTL: Query enryption status
+ */
+static int tape_3592_ioctl_crypt_query(struct tape_device *device,
+ unsigned long arg)
+{
+ DBF_EVENT(6, "tape_3592_ioctl_crypt_query\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ tape_3590_sense_medium(device);
+ if (copy_to_user((char __user *) arg, &TAPE_3590_CRYPT_INFO(device),
+ sizeof(TAPE_3590_CRYPT_INFO(device))))
+ return -EFAULT;
+ else
+ return 0;
+}
+
/*
* 3590 IOCTL Overload
*/
@@ -109,6 +436,14 @@ tape_3590_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg)
return tape_std_display(device, &disp);
}
+ case TAPE390_KEKL_SET:
+ return tape_3592_ioctl_kekl_set(device, arg);
+ case TAPE390_KEKL_QUERY:
+ return tape_3592_ioctl_kekl_query(device, arg);
+ case TAPE390_CRYPT_SET:
+ return tape_3592_ioctl_crypt_set(device, arg);
+ case TAPE390_CRYPT_QUERY:
+ return tape_3592_ioctl_crypt_query(device, arg);
default:
return -EINVAL; /* no additional ioctls */
}
@@ -236,9 +571,10 @@ struct work_handler_data {
};
static void
-tape_3590_work_handler(void *data)
+tape_3590_work_handler(struct work_struct *work)
{
- struct work_handler_data *p = data;
+ struct work_handler_data *p =
+ container_of(work, struct work_handler_data, work);
switch (p->op) {
case TO_MSEN:
@@ -247,6 +583,12 @@ tape_3590_work_handler(void *data)
case TO_READ_ATTMSG:
tape_3590_read_attmsg(p->device);
break;
+ case TO_CRYPT_ON:
+ tape_3592_enable_crypt(p->device);
+ break;
+ case TO_CRYPT_OFF:
+ tape_3592_disable_crypt(p->device);
+ break;
default:
DBF_EVENT(3, "T3590: work handler undefined for "
"operation 0x%02x\n", p->op);
@@ -263,7 +605,7 @@ tape_3590_schedule_work(struct tape_device *device, enum tape_op op)
if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
return -ENOMEM;
- INIT_WORK(&p->work, tape_3590_work_handler, p);
+ INIT_WORK(&p->work, tape_3590_work_handler);
p->device = tape_get_device_reference(device);
p->op = op;
@@ -364,6 +706,33 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request)
}
#endif
+static void tape_3590_med_state_set(struct tape_device *device,
+ struct tape_3590_med_sense *sense)
+{
+ struct tape390_crypt_info *c_info;
+
+ c_info = &TAPE_3590_CRYPT_INFO(device);
+
+ if (sense->masst == MSENSE_UNASSOCIATED) {
+ tape_med_state_set(device, MS_UNLOADED);
+ TAPE_3590_CRYPT_INFO(device).medium_status = 0;
+ return;
+ }
+ if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
+ PRINT_ERR("Unknown medium state: %x\n", sense->masst);
+ return;
+ }
+ tape_med_state_set(device, MS_LOADED);
+ c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
+ if (sense->flags & MSENSE_CRYPT_MASK) {
+ PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
+ c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK;
+ } else {
+ DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags);
+ c_info->medium_status &= ~TAPE390_MEDIUM_ENCRYPTED_MASK;
+ }
+}
+
/*
* The done handler is called at device/channel end and wakes up the sleeping
* process
@@ -371,9 +740,10 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request)
static int
tape_3590_done(struct tape_device *device, struct tape_request *request)
{
- struct tape_3590_med_sense *sense;
+ struct tape_3590_disc_data *disc_data;
DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
+ disc_data = device->discdata;
switch (request->op) {
case TO_BSB:
@@ -393,13 +763,20 @@ tape_3590_done(struct tape_device *device, struct tape_request *request)
break;
case TO_RUN:
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
break;
case TO_MSEN:
- sense = (struct tape_3590_med_sense *) request->cpdata;
- if (sense->masst == MSENSE_UNASSOCIATED)
- tape_med_state_set(device, MS_UNLOADED);
- if (sense->masst == MSENSE_ASSOCIATED_MOUNT)
- tape_med_state_set(device, MS_LOADED);
+ tape_3590_med_state_set(device, request->cpdata);
+ break;
+ case TO_CRYPT_ON:
+ TAPE_3590_CRYPT_INFO(device).status
+ |= TAPE390_CRYPT_ON_MASK;
+ *(device->modeset_byte) |= 0x03;
+ break;
+ case TO_CRYPT_OFF:
+ TAPE_3590_CRYPT_INFO(device).status
+ &= ~TAPE390_CRYPT_ON_MASK;
+ *(device->modeset_byte) &= ~0x03;
break;
case TO_RBI: /* RBI seems to succeed even without medium loaded. */
case TO_NOP: /* Same to NOP. */
@@ -408,8 +785,9 @@ tape_3590_done(struct tape_device *device, struct tape_request *request)
case TO_DIS:
case TO_ASSIGN:
case TO_UNASSIGN:
- break;
case TO_SIZE:
+ case TO_KEKL_SET:
+ case TO_KEKL_QUERY:
break;
}
return TAPE_IO_SUCCESS;
@@ -539,10 +917,8 @@ static int
tape_3590_erp_long_busy(struct tape_device *device,
struct tape_request *request, struct irb *irb)
{
- /* FIXME: how about WAITING for a minute ? */
- PRINT_WARN("(%s): Device is busy! Please wait a minute!\n",
- device->cdev->dev.bus_id);
- return tape_3590_erp_basic(device, request, irb, -EBUSY);
+ DBF_EVENT(6, "Device is busy\n");
+ return TAPE_IO_LONG_BUSY;
}
/*
@@ -950,6 +1326,34 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
device->cdev->dev.bus_id, sense->mc);
}
+static int tape_3590_crypt_error(struct tape_device *device,
+ struct tape_request *request, struct irb *irb)
+{
+ u8 cu_rc, ekm_rc1;
+ u16 ekm_rc2;
+ u32 drv_rc;
+ char *bus_id, *sense;
+
+ sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data;
+ bus_id = device->cdev->dev.bus_id;
+ cu_rc = sense[0];
+ drv_rc = *((u32*) &sense[5]) & 0xffffff;
+ ekm_rc1 = sense[9];
+ ekm_rc2 = *((u16*) &sense[10]);
+ if ((cu_rc == 0) && (ekm_rc2 == 0xee31))
+ /* key not defined on EKM */
+ return tape_3590_erp_basic(device, request, irb, -EKEYREJECTED);
+ if ((cu_rc == 1) || (cu_rc == 2))
+ /* No connection to EKM */
+ return tape_3590_erp_basic(device, request, irb, -ENOTCONN);
+
+ PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id);
+ PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc,
+ drv_rc, ekm_rc1, ekm_rc2);
+
+ return tape_3590_erp_basic(device, request, irb, -ENOKEY);
+}
+
/*
* 3590 error Recovery routine:
* If possible, it tries to recover from the error. If this is not possible,
@@ -978,6 +1382,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
sense = (struct tape_3590_sense *) irb->ecw;
+ DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc);
+
/*
* First check all RC-QRCs where we want to do something special
* - "break": basic error recovery is done
@@ -998,6 +1404,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
case 0x2231:
tape_3590_print_era_msg(device, irb);
return tape_3590_erp_special_interrupt(device, request, irb);
+ case 0x2240:
+ return tape_3590_crypt_error(device, request, irb);
case 0x3010:
DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n",
@@ -1019,6 +1427,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
DBF_EVENT(2, "(%08x): Rewind Unload complete\n",
device->cdev_id);
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
return tape_3590_erp_basic(device, request, irb, 0);
case 0x4010:
@@ -1029,9 +1438,15 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
PRINT_WARN("(%s): Tape operation when medium not loaded\n",
device->cdev->dev.bus_id);
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
case 0x4012: /* Device Long Busy */
+ /* XXX: Also use long busy handling here? */
+ DBF_EVENT(6, "(%08x): LONG BUSY\n", device->cdev_id);
tape_3590_print_era_msg(device, irb);
+ return tape_3590_erp_basic(device, request, irb, -EBUSY);
+ case 0x4014:
+ DBF_EVENT(6, "(%08x): Crypto LONG BUSY\n", device->cdev_id);
return tape_3590_erp_long_busy(device, request, irb);
case 0x5010:
@@ -1063,6 +1478,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
case 0x5120:
case 0x1120:
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
case 0x6020:
@@ -1141,21 +1557,47 @@ tape_3590_setup_device(struct tape_device *device)
{
int rc;
struct tape_3590_disc_data *data;
+ char *rdc_data;
DBF_EVENT(6, "3590 device setup\n");
- data = kmalloc(sizeof(struct tape_3590_disc_data),
- GFP_KERNEL | GFP_DMA);
+ data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA);
if (data == NULL)
return -ENOMEM;
data->read_back_op = READ_PREVIOUS;
device->discdata = data;
- if ((rc = tape_std_assign(device)) == 0) {
- /* Try to find out if medium is loaded */
- if ((rc = tape_3590_sense_medium(device)) != 0)
- DBF_LH(3, "3590 medium sense returned %d\n", rc);
+ rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA);
+ if (!rdc_data) {
+ rc = -ENOMEM;
+ goto fail_kmalloc;
+ }
+ rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64);
+ if (rc) {
+ DBF_LH(3, "Read device characteristics failed!\n");
+ goto fail_kmalloc;
+ }
+ rc = tape_std_assign(device);
+ if (rc)
+ goto fail_rdc_data;
+ if (rdc_data[31] == 0x13) {
+ PRINT_INFO("Device has crypto support\n");
+ data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK;
+ tape_3592_disable_crypt(device);
+ } else {
+ DBF_EVENT(6, "Device has NO crypto support\n");
}
+ /* Try to find out if medium is loaded */
+ rc = tape_3590_sense_medium(device);
+ if (rc) {
+ DBF_LH(3, "3590 medium sense returned %d\n", rc);
+ goto fail_rdc_data;
+ }
+ return 0;
+fail_rdc_data:
+ kfree(rdc_data);
+fail_kmalloc:
+ kfree(data);
return rc;
}
diff --git a/drivers/s390/char/tape_3590.h b/drivers/s390/char/tape_3590.h
index cf274b9445a..aa5138807af 100644
--- a/drivers/s390/char/tape_3590.h
+++ b/drivers/s390/char/tape_3590.h
@@ -2,7 +2,7 @@
* drivers/s390/char/tape_3590.h
* tape device discipline for 3590 tapes.
*
- * Copyright (C) IBM Corp. 2001,2006
+ * Copyright IBM Corp. 2001,2006
* Author(s): Stefan Bader <shbader@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -38,16 +38,22 @@
#define MSENSE_UNASSOCIATED 0x00
#define MSENSE_ASSOCIATED_MOUNT 0x01
#define MSENSE_ASSOCIATED_UMOUNT 0x02
+#define MSENSE_CRYPT_MASK 0x00000010
#define TAPE_3590_MAX_MSG 0xb0
/* Datatypes */
struct tape_3590_disc_data {
- unsigned char modeset_byte;
+ struct tape390_crypt_info crypt_info;
int read_back_op;
};
+#define TAPE_3590_CRYPT_INFO(device) \
+ ((struct tape_3590_disc_data*)(device->discdata))->crypt_info
+#define TAPE_3590_READ_BACK_OP(device) \
+ ((struct tape_3590_disc_data*)(device->discdata))->read_back_op
+
struct tape_3590_sense {
unsigned int command_rej:1;
@@ -118,7 +124,48 @@ struct tape_3590_sense {
struct tape_3590_med_sense {
unsigned int macst:4;
unsigned int masst:4;
- char pad[127];
+ char pad1[7];
+ unsigned int flags;
+ char pad2[116];
+} __attribute__ ((packed));
+
+/* Datastructures for 3592 encryption support */
+
+struct tape3592_kekl {
+ __u8 flags;
+ char label[64];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_pair {
+ __u8 count;
+ struct tape3592_kekl kekl[2];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_query_data {
+ __u16 len;
+ __u8 fmt;
+ __u8 mc;
+ __u32 id;
+ __u8 flags;
+ struct tape3592_kekl_pair kekls;
+ char reserved[116];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_query_order {
+ __u8 code;
+ __u8 flags;
+ char reserved1[2];
+ __u8 max_count;
+ char reserved2[35];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_set_order {
+ __u8 code;
+ __u8 flags;
+ char reserved1[2];
+ __u8 op;
+ struct tape3592_kekl_pair kekls;
+ char reserved2[120];
} __attribute__ ((packed));
#endif /* _TAPE_3590_H */
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index 3225fcd1dcb..dd0ecaed592 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -15,6 +15,7 @@
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/buffer_head.h>
+#include <linux/kernel.h>
#include <asm/debug.h>
@@ -72,7 +73,7 @@ tapeblock_trigger_requeue(struct tape_device *device)
/*
* Post finished request.
*/
-static inline void
+static void
tapeblock_end_request(struct request *req, int uptodate)
{
if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
@@ -107,7 +108,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data)
/*
* Feed the tape device CCW queue with requests supplied in a list.
*/
-static inline int
+static int
tapeblock_start_request(struct tape_device *device, struct request *req)
{
struct tape_request * ccw_req;
@@ -143,7 +144,8 @@ tapeblock_start_request(struct tape_device *device, struct request *req)
* queue.
*/
static void
-tapeblock_requeue(void *data) {
+tapeblock_requeue(struct work_struct *work) {
+ struct tape_blk_data * blkdat;
struct tape_device * device;
request_queue_t * queue;
int nr_queued;
@@ -151,7 +153,8 @@ tapeblock_requeue(void *data) {
struct list_head * l;
int rc;
- device = (struct tape_device *) data;
+ blkdat = container_of(work, struct tape_blk_data, requeue_task);
+ device = blkdat->device;
if (!device)
return;
@@ -212,6 +215,7 @@ tapeblock_setup_device(struct tape_device * device)
int rc;
blkdat = &device->blk_data;
+ blkdat->device = device;
spin_lock_init(&blkdat->request_queue_lock);
atomic_set(&blkdat->requeue_scheduled, 0);
@@ -255,8 +259,8 @@ tapeblock_setup_device(struct tape_device * device)
add_disk(disk);
- INIT_WORK(&blkdat->requeue_task, tapeblock_requeue,
- tape_get_device_reference(device));
+ tape_get_device_reference(device);
+ INIT_WORK(&blkdat->requeue_task, tapeblock_requeue);
return 0;
@@ -271,7 +275,7 @@ void
tapeblock_cleanup_device(struct tape_device *device)
{
flush_scheduled_work();
- device->blk_data.requeue_task.data = tape_put_device(device);
+ tape_put_device(device);
if (!device->blk_data.disk) {
PRINT_ERR("(%s): No gendisk to clean up!\n",
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 97f75237bed..9faea04e11e 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -3,7 +3,7 @@
* character device frontend for tape device driver
*
* S390 and zSeries version
- * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2001,2006
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
@@ -89,22 +89,7 @@ tapechar_cleanup_device(struct tape_device *device)
device->nt = NULL;
}
-/*
- * Terminate write command (we write two TMs and skip backward over last)
- * This ensures that the tape is always correctly terminated.
- * When the user writes afterwards a new file, he will overwrite the
- * second TM and therefore one TM will remain to separate the
- * two files on the tape...
- */
-static inline void
-tapechar_terminate_write(struct tape_device *device)
-{
- if (tape_mtop(device, MTWEOF, 1) == 0 &&
- tape_mtop(device, MTWEOF, 1) == 0)
- tape_mtop(device, MTBSR, 1);
-}
-
-static inline int
+static int
tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
{
struct idal_buffer *new;
@@ -137,7 +122,7 @@ tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
/*
* Tape device read function
*/
-ssize_t
+static ssize_t
tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
{
struct tape_device *device;
@@ -201,7 +186,7 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
/*
* Tape device write function
*/
-ssize_t
+static ssize_t
tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos)
{
struct tape_device *device;
@@ -291,20 +276,20 @@ tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t
/*
* Character frontend tape device open function.
*/
-int
+static int
tapechar_open (struct inode *inode, struct file *filp)
{
struct tape_device *device;
int minor, rc;
DBF_EVENT(6, "TCHAR:open: %i:%i\n",
- imajor(filp->f_dentry->d_inode),
- iminor(filp->f_dentry->d_inode));
+ imajor(filp->f_path.dentry->d_inode),
+ iminor(filp->f_path.dentry->d_inode));
- if (imajor(filp->f_dentry->d_inode) != tapechar_major)
+ if (imajor(filp->f_path.dentry->d_inode) != tapechar_major)
return -ENODEV;
- minor = iminor(filp->f_dentry->d_inode);
+ minor = iminor(filp->f_path.dentry->d_inode);
device = tape_get_device(minor / TAPE_MINORS_PER_DEV);
if (IS_ERR(device)) {
DBF_EVENT(3, "TCHAR:open: tape_get_device() failed\n");
@@ -326,7 +311,7 @@ tapechar_open (struct inode *inode, struct file *filp)
* Character frontend tape device release function.
*/
-int
+static int
tapechar_release(struct inode *inode, struct file *filp)
{
struct tape_device *device;
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 2826aed9104..e2a8a1a04ba 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -3,7 +3,7 @@
* basic function of the tape device driver
*
* S390 and zSeries version
- * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2001,2006
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
@@ -26,9 +26,11 @@
#include "tape_std.h"
#define PRINTK_HEADER "TAPE_CORE: "
+#define LONG_BUSY_TIMEOUT 180 /* seconds */
static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *);
-static void tape_delayed_next_request(void * data);
+static void tape_delayed_next_request(struct work_struct *);
+static void tape_long_busy_timeout(unsigned long data);
/*
* One list to contain all tape devices of all disciplines, so
@@ -69,10 +71,12 @@ const char *tape_op_verbose[TO_SIZE] =
[TO_LOAD] = "LOA", [TO_READ_CONFIG] = "RCF",
[TO_READ_ATTMSG] = "RAT",
[TO_DIS] = "DIS", [TO_ASSIGN] = "ASS",
- [TO_UNASSIGN] = "UAS"
+ [TO_UNASSIGN] = "UAS", [TO_CRYPT_ON] = "CON",
+ [TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS",
+ [TO_KEKL_QUERY] = "KLQ",
};
-static inline int
+static int
busid_to_int(char *bus_id)
{
int dec;
@@ -252,7 +256,7 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate)
/*
* Stop running ccw. Has to be called with the device lock held.
*/
-static inline int
+static int
__tape_cancel_io(struct tape_device *device, struct tape_request *request)
{
int retries;
@@ -272,7 +276,7 @@ __tape_cancel_io(struct tape_device *device, struct tape_request *request)
return 0;
case -EBUSY:
request->status = TAPE_REQUEST_CANCEL;
- schedule_work(&device->tape_dnr);
+ schedule_delayed_work(&device->tape_dnr, 0);
return 0;
case -ENODEV:
DBF_EXCEPTION(2, "device gone, retry\n");
@@ -346,6 +350,9 @@ tape_generic_online(struct tape_device *device,
return -EINVAL;
}
+ init_timer(&device->lb_timeout);
+ device->lb_timeout.function = tape_long_busy_timeout;
+
/* Let the discipline have a go at the device. */
device->discipline = discipline;
if (!try_module_get(discipline->owner)) {
@@ -385,7 +392,7 @@ out:
return rc;
}
-static inline void
+static void
tape_cleanup_device(struct tape_device *device)
{
tapeblock_cleanup_device(device);
@@ -470,7 +477,7 @@ tape_alloc_device(void)
*device->modeset_byte = 0;
device->first_minor = -1;
atomic_set(&device->ref_count, 1);
- INIT_WORK(&device->tape_dnr, tape_delayed_next_request, device);
+ INIT_DELAYED_WORK(&device->tape_dnr, tape_delayed_next_request);
return device;
}
@@ -563,7 +570,7 @@ tape_generic_probe(struct ccw_device *cdev)
return ret;
}
-static inline void
+static void
__tape_discard_requests(struct tape_device *device)
{
struct tape_request * request;
@@ -703,7 +710,7 @@ tape_free_request (struct tape_request * request)
kfree(request);
}
-static inline int
+static int
__tape_start_io(struct tape_device *device, struct tape_request *request)
{
int rc;
@@ -724,7 +731,7 @@ __tape_start_io(struct tape_device *device, struct tape_request *request)
} else if (rc == -EBUSY) {
/* The common I/O subsystem is currently busy. Retry later. */
request->status = TAPE_REQUEST_QUEUED;
- schedule_work(&device->tape_dnr);
+ schedule_delayed_work(&device->tape_dnr, 0);
rc = 0;
} else {
/* Start failed. Remove request and indicate failure. */
@@ -733,7 +740,7 @@ __tape_start_io(struct tape_device *device, struct tape_request *request)
return rc;
}
-static inline void
+static void
__tape_start_next_request(struct tape_device *device)
{
struct list_head *l, *n;
@@ -790,18 +797,34 @@ __tape_start_next_request(struct tape_device *device)
}
static void
-tape_delayed_next_request(void *data)
+tape_delayed_next_request(struct work_struct *work)
{
- struct tape_device * device;
+ struct tape_device *device =
+ container_of(work, struct tape_device, tape_dnr.work);
- device = (struct tape_device *) data;
DBF_LH(6, "tape_delayed_next_request(%p)\n", device);
spin_lock_irq(get_ccwdev_lock(device->cdev));
__tape_start_next_request(device);
spin_unlock_irq(get_ccwdev_lock(device->cdev));
}
-static inline void
+static void tape_long_busy_timeout(unsigned long data)
+{
+ struct tape_request *request;
+ struct tape_device *device;
+
+ device = (struct tape_device *) data;
+ spin_lock_irq(get_ccwdev_lock(device->cdev));
+ request = list_entry(device->req_queue.next, struct tape_request, list);
+ if (request->status != TAPE_REQUEST_LONG_BUSY)
+ BUG();
+ DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id);
+ __tape_start_next_request(device);
+ device->lb_timeout.data = (unsigned long) tape_put_device(device);
+ spin_unlock_irq(get_ccwdev_lock(device->cdev));
+}
+
+static void
__tape_end_request(
struct tape_device * device,
struct tape_request * request,
@@ -878,7 +901,7 @@ tape_dump_sense_dbf(struct tape_device *device, struct tape_request *request,
* and starts it if the tape is idle. Has to be called with
* the device lock held.
*/
-static inline int
+static int
__tape_start_request(struct tape_device *device, struct tape_request *request)
{
int rc;
@@ -1094,7 +1117,22 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
/* May be an unsolicited irq */
if(request != NULL)
request->rescnt = irb->scsw.count;
-
+ else if ((irb->scsw.dstat == 0x85 || irb->scsw.dstat == 0x80) &&
+ !list_empty(&device->req_queue)) {
+ /* Not Ready to Ready after long busy ? */
+ struct tape_request *req;
+ req = list_entry(device->req_queue.next,
+ struct tape_request, list);
+ if (req->status == TAPE_REQUEST_LONG_BUSY) {
+ DBF_EVENT(3, "(%08x): del timer\n", device->cdev_id);
+ if (del_timer(&device->lb_timeout)) {
+ device->lb_timeout.data = (unsigned long)
+ tape_put_device(device);
+ __tape_start_next_request(device);
+ }
+ return;
+ }
+ }
if (irb->scsw.dstat != 0x0c) {
/* Set the 'ONLINE' flag depending on sense byte 1 */
if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE)
@@ -1142,6 +1180,15 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
break;
case TAPE_IO_PENDING:
break;
+ case TAPE_IO_LONG_BUSY:
+ device->lb_timeout.data =
+ (unsigned long)tape_get_device_reference(device);
+ device->lb_timeout.expires = jiffies +
+ LONG_BUSY_TIMEOUT * HZ;
+ DBF_EVENT(3, "(%08x): add timer\n", device->cdev_id);
+ add_timer(&device->lb_timeout);
+ request->status = TAPE_REQUEST_LONG_BUSY;
+ break;
case TAPE_IO_RETRY:
rc = __tape_start_io(device, request);
if (rc)
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 4717c361160..bc33068b9ce 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -36,7 +36,7 @@
struct tty_driver *tty3270_driver;
static int tty3270_max_index;
-struct raw3270_fn tty3270_fn;
+static struct raw3270_fn tty3270_fn;
struct tty3270_cell {
unsigned char character;
@@ -119,8 +119,7 @@ static void tty3270_update(struct tty3270 *);
/*
* Setup timeout for a device. On timeout trigger an update.
*/
-void
-tty3270_set_timer(struct tty3270 *tp, int expires)
+static void tty3270_set_timer(struct tty3270 *tp, int expires)
{
if (expires == 0) {
if (timer_pending(&tp->timer) && del_timer(&tp->timer))
@@ -841,7 +840,7 @@ tty3270_del_views(void)
}
}
-struct raw3270_fn tty3270_fn = {
+static struct raw3270_fn tty3270_fn = {
.activate = tty3270_activate,
.deactivate = tty3270_deactivate,
.intv = (void *) tty3270_irq,
@@ -1659,7 +1658,7 @@ tty3270_flush_buffer(struct tty_struct *tty)
* Check for visible/invisible input switches
*/
static void
-tty3270_set_termios(struct tty_struct *tty, struct termios *old)
+tty3270_set_termios(struct tty_struct *tty, struct ktermios *old)
{
struct tty3270 *tp;
int new;
@@ -1754,8 +1753,7 @@ static const struct tty_operations tty3270_ops = {
.set_termios = tty3270_set_termios
};
-void
-tty3270_notifier(int index, int active)
+static void tty3270_notifier(int index, int active)
{
if (active)
tty_register_device(tty3270_driver, index, NULL);
@@ -1767,8 +1765,7 @@ tty3270_notifier(int index, int active)
* 3270 tty registration code called from tty_init().
* Most kernel services (incl. kmalloc) are available at this poimt.
*/
-int __init
-tty3270_init(void)
+static int __init tty3270_init(void)
{
struct tty_driver *driver;
int ret;
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 1678b6c757e..a420cd09904 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -117,7 +117,7 @@ vmcp_write(struct file *file, const char __user * buff, size_t count,
return -ENOMEM;
}
debug_text_event(vmcp_debug, 1, cmd);
- session->resp_size = __cpcmd(cmd, session->response,
+ session->resp_size = cpcmd(cmd, session->response,
session->bufsize,
&session->resp_code);
up(&session->mutex);
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 6cb23040954..8432a76b961 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -3,7 +3,7 @@
* character device driver for reading z/VM system service records
*
*
- * Copyright (C) 2004 IBM Corporation
+ * Copyright 2004 IBM Corporation
* character device driver for reading z/VM system service records,
* Version 1.0
* Author(s): Xenia Tkatschow <xenia@us.ibm.com>
@@ -21,7 +21,7 @@
#include <asm/cpcmd.h>
#include <asm/debug.h>
#include <asm/ebcdic.h>
-#include "../net/iucv.h"
+#include <net/iucv/iucv.h>
#include <linux/kmod.h>
#include <linux/cdev.h>
#include <linux/device.h>
@@ -60,12 +60,11 @@ struct vmlogrdr_priv_t {
char system_service[8];
char internal_name[8];
char recording_name[8];
- u16 pathid;
+ struct iucv_path *path;
int connection_established;
int iucv_path_severed;
- iucv_MessagePending local_interrupt_buffer;
+ struct iucv_message local_interrupt_buffer;
atomic_t receive_ready;
- iucv_handle_t iucv_handle;
int minor_num;
char * buffer;
char * current_position;
@@ -97,40 +96,21 @@ static struct file_operations vmlogrdr_fops = {
};
-static u8 iucvMagic[16] = {
- 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
- 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
-};
+static void vmlogrdr_iucv_path_complete(struct iucv_path *, u8 ipuser[16]);
+static void vmlogrdr_iucv_path_severed(struct iucv_path *, u8 ipuser[16]);
+static void vmlogrdr_iucv_message_pending(struct iucv_path *,
+ struct iucv_message *);
-static u8 mask[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+static struct iucv_handler vmlogrdr_iucv_handler = {
+ .path_complete = vmlogrdr_iucv_path_complete,
+ .path_severed = vmlogrdr_iucv_path_severed,
+ .message_pending = vmlogrdr_iucv_message_pending,
};
-static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-
-static void
-vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data);
-static void
-vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data);
-static void
-vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data);
-
-
-static iucv_interrupt_ops_t vmlogrdr_iucvops = {
- .ConnectionComplete = vmlogrdr_iucv_ConnectionComplete,
- .ConnectionSevered = vmlogrdr_iucv_ConnectionSevered,
- .MessagePending = vmlogrdr_iucv_MessagePending,
-};
-
-
-DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
-DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
/*
* pointer to system service private structure
@@ -177,28 +157,29 @@ static struct cdev *vmlogrdr_cdev = NULL;
static int recording_class_AB;
-static void
-vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib,
- void * pgm_data)
+static void vmlogrdr_iucv_path_complete(struct iucv_path *path, u8 ipuser[16])
{
- struct vmlogrdr_priv_t * logptr = pgm_data;
+ struct vmlogrdr_priv_t * logptr = path->private;
+
spin_lock(&logptr->priv_lock);
logptr->connection_established = 1;
spin_unlock(&logptr->priv_lock);
wake_up(&conn_wait_queue);
- return;
}
-static void
-vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data)
+static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
{
- u8 reason = (u8) eib->ipuser[8];
- struct vmlogrdr_priv_t * logptr = pgm_data;
+ struct vmlogrdr_priv_t * logptr = path->private;
+ u8 reason = (u8) ipuser[8];
printk (KERN_ERR "vmlogrdr: connection severed with"
" reason %i\n", reason);
+ iucv_path_sever(path, NULL);
+ kfree(path);
+ logptr->path = NULL;
+
spin_lock(&logptr->priv_lock);
logptr->connection_established = 0;
logptr->iucv_path_severed = 1;
@@ -210,10 +191,10 @@ vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data)
}
-static void
-vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data)
+static void vmlogrdr_iucv_message_pending(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct vmlogrdr_priv_t * logptr = pgm_data;
+ struct vmlogrdr_priv_t * logptr = path->private;
/*
* This function is the bottom half so it should be quick.
@@ -221,15 +202,15 @@ vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data)
* the usage count
*/
spin_lock(&logptr->priv_lock);
- memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib));
+ memcpy(&logptr->local_interrupt_buffer, msg, sizeof(*msg));
atomic_inc(&logptr->receive_ready);
spin_unlock(&logptr->priv_lock);
wake_up_interruptible(&read_wait_queue);
}
-static int
-vmlogrdr_get_recording_class_AB(void) {
+static int vmlogrdr_get_recording_class_AB(void)
+{
char cp_command[]="QUERY COMMAND RECORDING ";
char cp_response[80];
char *tail;
@@ -259,8 +240,9 @@ vmlogrdr_get_recording_class_AB(void) {
}
-static int
-vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
+static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr,
+ int action, int purge)
+{
char cp_command[80];
char cp_response[160];
@@ -318,8 +300,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
}
-static int
-vmlogrdr_open (struct inode *inode, struct file *filp)
+static int vmlogrdr_open (struct inode *inode, struct file *filp)
{
int dev_num = 0;
struct vmlogrdr_priv_t * logptr = NULL;
@@ -329,10 +310,7 @@ vmlogrdr_open (struct inode *inode, struct file *filp)
dev_num = iminor(inode);
if (dev_num > MAXMINOR)
return -ENODEV;
-
logptr = &sys_ser[dev_num];
- if (logptr == NULL)
- return -ENODEV;
/*
* only allow for blocking reads to be open
@@ -345,52 +323,38 @@ vmlogrdr_open (struct inode *inode, struct file *filp)
if (logptr->dev_in_use) {
spin_unlock_bh(&logptr->priv_lock);
return -EBUSY;
- } else {
- logptr->dev_in_use = 1;
- spin_unlock_bh(&logptr->priv_lock);
}
-
+ logptr->dev_in_use = 1;
+ logptr->connection_established = 0;
+ logptr->iucv_path_severed = 0;
atomic_set(&logptr->receive_ready, 0);
logptr->buffer_free = 1;
+ spin_unlock_bh(&logptr->priv_lock);
/* set the file options */
filp->private_data = logptr;
filp->f_op = &vmlogrdr_fops;
/* start recording for this service*/
- ret=0;
- if (logptr->autorecording)
+ if (logptr->autorecording) {
ret = vmlogrdr_recording(logptr,1,logptr->autopurge);
- if (ret)
- printk (KERN_WARNING "vmlogrdr: failed to start "
- "recording automatically\n");
-
- /* Register with iucv driver */
- logptr->iucv_handle = iucv_register_program(iucvMagic,
- logptr->system_service, mask, &vmlogrdr_iucvops,
- logptr);
-
- if (logptr->iucv_handle == NULL) {
- printk (KERN_ERR "vmlogrdr: failed to register with"
- "iucv driver\n");
- goto not_registered;
+ if (ret)
+ printk (KERN_WARNING "vmlogrdr: failed to start "
+ "recording automatically\n");
}
/* create connection to the system service */
- spin_lock_bh(&logptr->priv_lock);
- logptr->connection_established = 0;
- logptr->iucv_path_severed = 0;
- spin_unlock_bh(&logptr->priv_lock);
-
- connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic,
- logptr->system_service, iucv_host, 0,
- NULL, NULL,
- logptr->iucv_handle, NULL);
+ logptr->path = iucv_path_alloc(10, 0, GFP_KERNEL);
+ if (!logptr->path)
+ goto out_dev;
+ connect_rc = iucv_path_connect(logptr->path, &vmlogrdr_iucv_handler,
+ logptr->system_service, NULL, NULL,
+ logptr);
if (connect_rc) {
printk (KERN_ERR "vmlogrdr: iucv connection to %s "
"failed with rc %i \n", logptr->system_service,
connect_rc);
- goto not_connected;
+ goto out_path;
}
/* We've issued the connect and now we must wait for a
@@ -399,35 +363,28 @@ vmlogrdr_open (struct inode *inode, struct file *filp)
*/
wait_event(conn_wait_queue, (logptr->connection_established)
|| (logptr->iucv_path_severed));
- if (logptr->iucv_path_severed) {
- goto not_connected;
- }
-
+ if (logptr->iucv_path_severed)
+ goto out_record;
return nonseekable_open(inode, filp);
-not_connected:
- iucv_unregister_program(logptr->iucv_handle);
- logptr->iucv_handle = NULL;
-not_registered:
+out_record:
if (logptr->autorecording)
vmlogrdr_recording(logptr,0,logptr->autopurge);
+out_path:
+ kfree(logptr->path); /* kfree(NULL) is ok. */
+ logptr->path = NULL;
+out_dev:
logptr->dev_in_use = 0;
return -EIO;
-
-
}
-static int
-vmlogrdr_release (struct inode *inode, struct file *filp)
+static int vmlogrdr_release (struct inode *inode, struct file *filp)
{
int ret;
struct vmlogrdr_priv_t * logptr = filp->private_data;
- iucv_unregister_program(logptr->iucv_handle);
- logptr->iucv_handle = NULL;
-
if (logptr->autorecording) {
ret = vmlogrdr_recording(logptr,0,logptr->autopurge);
if (ret)
@@ -440,8 +397,8 @@ vmlogrdr_release (struct inode *inode, struct file *filp)
}
-static int
-vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
+static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv)
+{
int rc, *temp;
/* we need to keep track of two data sizes here:
* The number of bytes we need to receive from iucv and
@@ -462,8 +419,7 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
* We need to return the total length of the record
* + size of FENCE in the first 4 bytes of the buffer.
*/
- iucv_data_count =
- priv->local_interrupt_buffer.ln1msg2.ipbfln1f;
+ iucv_data_count = priv->local_interrupt_buffer.length;
user_data_count = sizeof(int);
temp = (int*)priv->buffer;
*temp= iucv_data_count + sizeof(FENCE);
@@ -475,14 +431,10 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
*/
if (iucv_data_count > NET_BUFFER_SIZE)
iucv_data_count = NET_BUFFER_SIZE;
- rc = iucv_receive(priv->pathid,
- priv->local_interrupt_buffer.ipmsgid,
- priv->local_interrupt_buffer.iptrgcls,
- buffer,
- iucv_data_count,
- NULL,
- NULL,
- &priv->residual_length);
+ rc = iucv_message_receive(priv->path,
+ &priv->local_interrupt_buffer,
+ 0, buffer, iucv_data_count,
+ &priv->residual_length);
spin_unlock_bh(&priv->priv_lock);
/* An rc of 5 indicates that the record was bigger then
* the buffer, which is OK for us. A 9 indicates that the
@@ -514,8 +466,8 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
}
-static ssize_t
-vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos)
+static ssize_t vmlogrdr_read(struct file *filp, char __user *data,
+ size_t count, loff_t * ppos)
{
int rc;
struct vmlogrdr_priv_t * priv = filp->private_data;
@@ -547,8 +499,10 @@ vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos)
return count;
}
-static ssize_t
-vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
+static ssize_t vmlogrdr_autopurge_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
ssize_t ret = count;
@@ -566,8 +520,10 @@ vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, con
}
-static ssize_t
-vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t vmlogrdr_autopurge_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
return sprintf(buf, "%u\n", priv->autopurge);
}
@@ -577,8 +533,10 @@ static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show,
vmlogrdr_autopurge_store);
-static ssize_t
-vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
+static ssize_t vmlogrdr_purge_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
char cp_command[80];
char cp_response[80];
@@ -618,9 +576,10 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c
static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store);
-static ssize_t
-vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count) {
+static ssize_t vmlogrdr_autorecording_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
ssize_t ret = count;
@@ -638,8 +597,10 @@ vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr,
}
-static ssize_t
-vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t vmlogrdr_autorecording_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
return sprintf(buf, "%u\n", priv->autorecording);
}
@@ -649,9 +610,10 @@ static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show,
vmlogrdr_autorecording_store);
-static ssize_t
-vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
-
+static ssize_t vmlogrdr_recording_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
ssize_t ret;
@@ -676,8 +638,9 @@ vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, con
static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store);
-static ssize_t
-vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) {
+static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver,
+ char *buf)
+{
char cp_command[] = "QUERY RECORDING ";
int len;
@@ -710,52 +673,63 @@ static struct device_driver vmlogrdr_driver = {
};
-static int
-vmlogrdr_register_driver(void) {
+static int vmlogrdr_register_driver(void)
+{
int ret;
+ /* Register with iucv driver */
+ ret = iucv_register(&vmlogrdr_iucv_handler, 1);
+ if (ret) {
+ printk (KERN_ERR "vmlogrdr: failed to register with"
+ "iucv driver\n");
+ goto out;
+ }
+
ret = driver_register(&vmlogrdr_driver);
if (ret) {
printk(KERN_ERR "vmlogrdr: failed to register driver.\n");
- return ret;
+ goto out_iucv;
}
ret = driver_create_file(&vmlogrdr_driver,
&driver_attr_recording_status);
if (ret) {
printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n");
- goto unregdriver;
+ goto out_driver;
}
vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr");
if (IS_ERR(vmlogrdr_class)) {
printk(KERN_ERR "vmlogrdr: failed to create class.\n");
- ret=PTR_ERR(vmlogrdr_class);
- vmlogrdr_class=NULL;
- goto unregattr;
+ ret = PTR_ERR(vmlogrdr_class);
+ vmlogrdr_class = NULL;
+ goto out_attr;
}
return 0;
-unregattr:
+out_attr:
driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
-unregdriver:
+out_driver:
driver_unregister(&vmlogrdr_driver);
+out_iucv:
+ iucv_unregister(&vmlogrdr_iucv_handler, 1);
+out:
return ret;
}
-static void
-vmlogrdr_unregister_driver(void) {
+static void vmlogrdr_unregister_driver(void)
+{
class_destroy(vmlogrdr_class);
vmlogrdr_class = NULL;
driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
driver_unregister(&vmlogrdr_driver);
- return;
+ iucv_unregister(&vmlogrdr_iucv_handler, 1);
}
-static int
-vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) {
+static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
+{
struct device *dev;
int ret;
@@ -804,9 +778,10 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) {
}
-static int
-vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) {
- class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));
+static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv)
+{
+ class_device_destroy(vmlogrdr_class,
+ MKDEV(vmlogrdr_major, priv->minor_num));
if (priv->device != NULL) {
sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group);
device_unregister(priv->device);
@@ -816,8 +791,8 @@ vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) {
}
-static int
-vmlogrdr_register_cdev(dev_t dev) {
+static int vmlogrdr_register_cdev(dev_t dev)
+{
int rc = 0;
vmlogrdr_cdev = cdev_alloc();
if (!vmlogrdr_cdev) {
@@ -837,9 +812,10 @@ vmlogrdr_register_cdev(dev_t dev) {
}
-static void
-vmlogrdr_cleanup(void) {
+static void vmlogrdr_cleanup(void)
+{
int i;
+
if (vmlogrdr_cdev) {
cdev_del(vmlogrdr_cdev);
vmlogrdr_cdev=NULL;
@@ -856,8 +832,7 @@ vmlogrdr_cleanup(void) {
}
-static int
-vmlogrdr_init(void)
+static int vmlogrdr_init(void)
{
int rc;
int i;
@@ -907,8 +882,7 @@ cleanup:
}
-static void
-vmlogrdr_exit(void)
+static void vmlogrdr_exit(void)
{
vmlogrdr_cleanup();
printk (KERN_INFO "vmlogrdr: driver unloaded\n");
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 12c2d6b746e..aa65df4dfce 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -43,7 +43,7 @@ typedef enum {add, free} range_action;
* Function: blacklist_range
* (Un-)blacklist the devices from-to
*/
-static inline void
+static void
blacklist_range (range_action action, unsigned int from, unsigned int to,
unsigned int ssid)
{
@@ -69,7 +69,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to,
* Get devno/busid from given string.
* Shamelessly grabbed from dasd_devmap.c.
*/
-static inline int
+static int
blacklist_busid(char **str, int *id0, int *ssid, int *devno)
{
int val, old_style;
@@ -123,10 +123,10 @@ confused:
return 1;
}
-static inline int
+static int
blacklist_parse_parameters (char *str, range_action action)
{
- unsigned int from, to, from_id0, to_id0, from_ssid, to_ssid;
+ int from, to, from_id0, to_id0, from_ssid, to_ssid;
while (*str != 0 && *str != '\n') {
range_action ra = action;
@@ -227,7 +227,7 @@ is_blacklisted (int ssid, int devno)
* Function: blacklist_parse_proc_parameters
* parse the stuff which is piped to /proc/cio_ignore
*/
-static inline void
+static void
blacklist_parse_proc_parameters (char *buf)
{
if (strncmp (buf, "free ", 5) == 0) {
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 38954f5cd14..d48e3ca4752 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -53,7 +53,7 @@ ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
static struct bus_type ccwgroup_bus_type;
-static inline void
+static void
__ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
{
int i;
@@ -104,7 +104,7 @@ ccwgroup_release (struct device *dev)
kfree(gdev);
}
-static inline int
+static int
__ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
{
char str[8];
@@ -424,7 +424,7 @@ ccwgroup_probe_ccwdev(struct ccw_device *cdev)
return 0;
}
-static inline struct ccwgroup_device *
+static struct ccwgroup_device *
__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
{
struct ccwgroup_device *gdev;
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index dbfb77b0392..6f05a44e381 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -93,7 +93,7 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
u16 sch; /* subchannel */
u8 chpid[8]; /* chpids 0-7 */
u16 fla[8]; /* full link addresses 0-7 */
- } *ssd_area;
+ } __attribute__ ((packed)) *ssd_area;
ssd_area = page;
@@ -183,7 +183,7 @@ css_get_ssd_info(struct subchannel *sch)
page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!page)
return -ENOMEM;
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
ret = chsc_get_sch_desc_irq(sch, page);
if (ret) {
static int cio_chsc_err_msg;
@@ -197,7 +197,7 @@ css_get_ssd_info(struct subchannel *sch)
cio_chsc_err_msg = 1;
}
}
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
free_page((unsigned long)page);
if (!ret) {
int j, chpid, mask;
@@ -233,7 +233,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
if (j >= 8)
return 0;
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
stsch(sch->schid, &schib);
if (!schib.pmcw.dnv)
@@ -265,10 +265,10 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
else if (sch->lpm == mask)
goto out_unreg;
out_unlock:
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
return 0;
out_unreg:
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
sch->lpm = 0;
if (css_enqueue_subchannel_slow(sch->schid)) {
css_clear_subchannel_slow_list();
@@ -277,7 +277,7 @@ out_unreg:
return 0;
}
-static inline void
+static void
s390_set_chpid_offline( __u8 chpid)
{
char dbf_txt[15];
@@ -338,7 +338,7 @@ s390_process_res_acc_sch(struct res_acc_data *res_data, struct subchannel *sch)
return 0x80 >> chp;
}
-static inline int
+static int
s390_process_res_acc_new_sch(struct subchannel_id schid)
{
struct schib schib;
@@ -378,12 +378,12 @@ __s390_process_res_acc(struct subchannel_id schid, void *data)
/* Check if a subchannel is newly available. */
return s390_process_res_acc_new_sch(schid);
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
chp_mask = s390_process_res_acc_sch(res_data, sch);
if (chp_mask == 0) {
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
put_device(&sch->dev);
return 0;
}
@@ -397,7 +397,7 @@ __s390_process_res_acc(struct subchannel_id schid, void *data)
else if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
put_device(&sch->dev);
return 0;
}
@@ -444,7 +444,7 @@ __get_chpid_from_lir(void *data)
u32 andesc[28];
/* incident-specific information */
u32 isinfo[28];
- } *lir;
+ } __attribute__ ((packed)) *lir;
lir = data;
if (!(lir->iq&0x80))
@@ -461,154 +461,146 @@ __get_chpid_from_lir(void *data)
return (u16) (lir->indesc[0]&0x000000ff);
}
-int
-chsc_process_crw(void)
+struct chsc_sei_area {
+ struct chsc_header request;
+ u32 reserved1;
+ u32 reserved2;
+ u32 reserved3;
+ struct chsc_header response;
+ u32 reserved4;
+ u8 flags;
+ u8 vf; /* validity flags */
+ u8 rs; /* reporting source */
+ u8 cc; /* content code */
+ u16 fla; /* full link address */
+ u16 rsid; /* reporting source id */
+ u32 reserved5;
+ u32 reserved6;
+ u8 ccdf[4096 - 16 - 24]; /* content-code dependent field */
+ /* ccdf has to be big enough for a link-incident record */
+} __attribute__ ((packed));
+
+static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
+{
+ int chpid;
+
+ CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n",
+ sei_area->rs, sei_area->rsid);
+ if (sei_area->rs != 4)
+ return 0;
+ chpid = __get_chpid_from_lir(sei_area->ccdf);
+ if (chpid < 0)
+ CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n");
+ else
+ s390_set_chpid_offline(chpid);
+
+ return 0;
+}
+
+static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
{
- int chpid, ret;
struct res_acc_data res_data;
- struct {
- struct chsc_header request;
- u32 reserved1;
- u32 reserved2;
- u32 reserved3;
- struct chsc_header response;
- u32 reserved4;
- u8 flags;
- u8 vf; /* validity flags */
- u8 rs; /* reporting source */
- u8 cc; /* content code */
- u16 fla; /* full link address */
- u16 rsid; /* reporting source id */
- u32 reserved5;
- u32 reserved6;
- u32 ccdf[96]; /* content-code dependent field */
- /* ccdf has to be big enough for a link-incident record */
- } *sei_area;
+ struct device *dev;
+ int status;
+ int rc;
+
+ CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, "
+ "rs_id=%04x)\n", sei_area->rs, sei_area->rsid);
+ if (sei_area->rs != 4)
+ return 0;
+ /* allocate a new channel path structure, if needed */
+ status = get_chp_status(sei_area->rsid);
+ if (status < 0)
+ new_channel_path(sei_area->rsid);
+ else if (!status)
+ return 0;
+ dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
+ memset(&res_data, 0, sizeof(struct res_acc_data));
+ res_data.chp = to_channelpath(dev);
+ if ((sei_area->vf & 0xc0) != 0) {
+ res_data.fla = sei_area->fla;
+ if ((sei_area->vf & 0xc0) == 0xc0)
+ /* full link address */
+ res_data.fla_mask = 0xffff;
+ else
+ /* link address */
+ res_data.fla_mask = 0xff00;
+ }
+ rc = s390_process_res_acc(&res_data);
+ put_device(dev);
+
+ return rc;
+}
+
+static int chsc_process_sei(struct chsc_sei_area *sei_area)
+{
+ int rc;
+
+ /* Check if we might have lost some information. */
+ if (sei_area->flags & 0x40)
+ CIO_CRW_EVENT(2, "chsc: event overflow\n");
+ /* which kind of information was stored? */
+ rc = 0;
+ switch (sei_area->cc) {
+ case 1: /* link incident*/
+ rc = chsc_process_sei_link_incident(sei_area);
+ break;
+ case 2: /* i/o resource accessibiliy */
+ rc = chsc_process_sei_res_acc(sei_area);
+ break;
+ default: /* other stuff */
+ CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n",
+ sei_area->cc);
+ break;
+ }
+
+ return rc;
+}
+
+int chsc_process_crw(void)
+{
+ struct chsc_sei_area *sei_area;
+ int ret;
+ int rc;
if (!sei_page)
return 0;
- /*
- * build the chsc request block for store event information
- * and do the call
- * This function is only called by the machine check handler thread,
- * so we don't need locking for the sei_page.
- */
+ /* Access to sei_page is serialized through machine check handler
+ * thread, so no need for locking. */
sei_area = sei_page;
CIO_TRACE_EVENT( 2, "prcss");
ret = 0;
do {
- int ccode, status;
- struct device *dev;
memset(sei_area, 0, sizeof(*sei_area));
- memset(&res_data, 0, sizeof(struct res_acc_data));
sei_area->request.length = 0x0010;
sei_area->request.code = 0x000e;
+ if (chsc(sei_area))
+ break;
- ccode = chsc(sei_area);
- if (ccode > 0)
- return 0;
-
- switch (sei_area->response.code) {
- /* for debug purposes, check for problems */
- case 0x0001:
- CIO_CRW_EVENT(4, "chsc_process_crw: event information "
- "successfully stored\n");
- break; /* everything ok */
- case 0x0002:
- CIO_CRW_EVENT(2,
- "chsc_process_crw: invalid command!\n");
- return 0;
- case 0x0003:
- CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc "
- "request block!\n");
- return 0;
- case 0x0005:
- CIO_CRW_EVENT(2, "chsc_process_crw: no event "
- "information stored\n");
- return 0;
- default:
- CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n",
+ if (sei_area->response.code == 0x0001) {
+ CIO_CRW_EVENT(4, "chsc: sei successful\n");
+ rc = chsc_process_sei(sei_area);
+ if (rc)
+ ret = rc;
+ } else {
+ CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
sei_area->response.code);
- return 0;
- }
-
- /* Check if we might have lost some information. */
- if (sei_area->flags & 0x40)
- CIO_CRW_EVENT(2, "chsc_process_crw: Event information "
- "has been lost due to overflow!\n");
-
- if (sei_area->rs != 4) {
- CIO_CRW_EVENT(2, "chsc_process_crw: reporting source "
- "(%04X) isn't a chpid!\n",
- sei_area->rsid);
- continue;
- }
-
- /* which kind of information was stored? */
- switch (sei_area->cc) {
- case 1: /* link incident*/
- CIO_CRW_EVENT(4, "chsc_process_crw: "
- "channel subsystem reports link incident,"
- " reporting source is chpid %x\n",
- sei_area->rsid);
- chpid = __get_chpid_from_lir(sei_area->ccdf);
- if (chpid < 0)
- CIO_CRW_EVENT(4, "%s: Invalid LIR, skipping\n",
- __FUNCTION__);
- else
- s390_set_chpid_offline(chpid);
- break;
-
- case 2: /* i/o resource accessibiliy */
- CIO_CRW_EVENT(4, "chsc_process_crw: "
- "channel subsystem reports some I/O "
- "devices may have become accessible\n");
- pr_debug("Data received after sei: \n");
- pr_debug("Validity flags: %x\n", sei_area->vf);
-
- /* allocate a new channel path structure, if needed */
- status = get_chp_status(sei_area->rsid);
- if (status < 0)
- new_channel_path(sei_area->rsid);
- else if (!status)
- break;
- dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
- res_data.chp = to_channelpath(dev);
- pr_debug("chpid: %x", sei_area->rsid);
- if ((sei_area->vf & 0xc0) != 0) {
- res_data.fla = sei_area->fla;
- if ((sei_area->vf & 0xc0) == 0xc0) {
- pr_debug(" full link addr: %x",
- sei_area->fla);
- res_data.fla_mask = 0xffff;
- } else {
- pr_debug(" link addr: %x",
- sei_area->fla);
- res_data.fla_mask = 0xff00;
- }
- }
- ret = s390_process_res_acc(&res_data);
- pr_debug("\n\n");
- put_device(dev);
- break;
-
- default: /* other stuff */
- CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n",
- sei_area->cc);
+ ret = 0;
break;
}
} while (sei_area->flags & 0x80);
+
return ret;
}
-static inline int
+static int
__chp_add_new_sch(struct subchannel_id schid)
{
struct schib schib;
int ret;
- if (stsch(schid, &schib))
+ if (stsch_err(schid, &schib))
/* We're through */
return need_rescan ? -EAGAIN : -ENXIO;
@@ -635,21 +627,21 @@ __chp_add(struct subchannel_id schid, void *data)
if (!sch)
/* Check if the subchannel is now available. */
return __chp_add_new_sch(schid);
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
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);
+ spin_unlock_irq(sch->lock);
return -ENXIO;
}
break;
}
}
if (i==8) {
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
return 0;
}
sch->lpm = ((sch->schib.pmcw.pim &
@@ -660,7 +652,7 @@ __chp_add(struct subchannel_id schid, void *data)
if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
put_device(&sch->dev);
return 0;
}
@@ -709,7 +701,7 @@ chp_process_crw(int chpid, int on)
return chp_add(chpid);
}
-static inline int check_for_io_on_path(struct subchannel *sch, int index)
+static int check_for_io_on_path(struct subchannel *sch, int index)
{
int cc;
@@ -741,7 +733,7 @@ static void terminate_internal_io(struct subchannel *sch)
sch->driver->termination(&sch->dev);
}
-static inline void
+static void
__s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
{
int chp, old_lpm;
@@ -750,7 +742,7 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
if (!sch->ssd_info.valid)
return;
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
old_lpm = sch->lpm;
for (chp = 0; chp < 8; chp++) {
if (sch->ssd_info.chpid[chp] != chpid)
@@ -785,7 +777,7 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
sch->driver->verify(&sch->dev);
break;
}
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
}
static int
@@ -967,8 +959,8 @@ static struct bin_attribute chp_measurement_attr = {
static void
chsc_remove_chp_cmg_attr(struct channel_path *chp)
{
- sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_chars_attr);
- sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_attr);
+ device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
+ device_remove_bin_file(&chp->dev, &chp_measurement_attr);
}
static int
@@ -976,14 +968,12 @@ chsc_add_chp_cmg_attr(struct channel_path *chp)
{
int ret;
- ret = sysfs_create_bin_file(&chp->dev.kobj,
- &chp_measurement_chars_attr);
+ ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr);
if (ret)
return ret;
- ret = sysfs_create_bin_file(&chp->dev.kobj, &chp_measurement_attr);
+ ret = device_create_bin_file(&chp->dev, &chp_measurement_attr);
if (ret)
- sysfs_remove_bin_file(&chp->dev.kobj,
- &chp_measurement_chars_attr);
+ device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
return ret;
}
@@ -1042,7 +1032,7 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
u32 : 4;
u32 fmt : 4;
u32 : 16;
- } *secm_area;
+ } __attribute__ ((packed)) *secm_area;
int ret, ccode;
secm_area = page;
@@ -1253,7 +1243,7 @@ chsc_determine_channel_path_description(int chpid,
struct chsc_header response;
u32 zeroes2;
struct channel_path_desc desc;
- } *scpd_area;
+ } __attribute__ ((packed)) *scpd_area;
scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scpd_area)
@@ -1350,7 +1340,7 @@ chsc_get_channel_measurement_chars(struct channel_path *chp)
u32 cmg : 8;
u32 zeroes3;
u32 data[NR_MEASUREMENT_CHARS];
- } *scmc_area;
+ } __attribute__ ((packed)) *scmc_area;
scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scmc_area)
@@ -1517,7 +1507,7 @@ chsc_enable_facility(int operation_code)
u32 reserved5:4;
u32 format2:4;
u32 reserved6:24;
- } *sda_area;
+ } __attribute__ ((packed)) *sda_area;
sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
if (!sda_area)
@@ -1569,7 +1559,7 @@ chsc_determine_css_characteristics(void)
u32 reserved4;
u32 general_char[510];
u32 chsc_char[518];
- } *scsc_area;
+ } __attribute__ ((packed)) *scsc_area;
scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scsc_area) {
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index a259245780a..0fb2b024208 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -10,17 +10,17 @@
struct chsc_header {
u16 length;
u16 code;
-};
+} __attribute__ ((packed));
#define NR_MEASUREMENT_CHARS 5
struct cmg_chars {
u32 values[NR_MEASUREMENT_CHARS];
-};
+} __attribute__ ((packed));
#define NR_MEASUREMENT_ENTRIES 8
struct cmg_entry {
u32 values[NR_MEASUREMENT_ENTRIES];
-};
+} __attribute__ ((packed));
struct channel_path_desc {
u8 flags;
@@ -31,7 +31,7 @@ struct channel_path_desc {
u8 zeroes;
u8 chla;
u8 chpp;
-};
+} __attribute__ ((packed));
struct channel_path {
int id;
@@ -47,6 +47,9 @@ struct channel_path {
extern void s390_process_css( void );
extern void chsc_validate_chpids(struct subchannel *);
extern void chpid_is_actually_online(int);
+extern int css_get_ssd_info(struct subchannel *);
+extern int chsc_process_crw(void);
+extern int chp_process_crw(int, int);
struct css_general_char {
u64 : 41;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 20aee278384..b3a56dc5f68 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -2,8 +2,7 @@
* drivers/s390/cio/cio.c
* S/390 common I/O routines -- low level i/o calls
*
- * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
- * IBM Corporation
+ * Copyright (C) IBM Corp. 1999,2006
* Author(s): Ingo Adlung (adlung@de.ibm.com)
* Cornelia Huck (cornelia.huck@de.ibm.com)
* Arnd Bergmann (arndb@de.ibm.com)
@@ -123,7 +122,7 @@ cio_get_options (struct subchannel *sch)
* Use tpi to get a pending interrupt, call the interrupt handler and
* return a pointer to the subchannel structure.
*/
-static inline int
+static int
cio_tpi(void)
{
struct tpi_info *tpi_info;
@@ -143,17 +142,17 @@ cio_tpi(void)
return 1;
local_bh_disable();
irq_enter ();
- spin_lock(&sch->lock);
+ spin_lock(sch->lock);
memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
if (sch->driver && sch->driver->irq)
sch->driver->irq(&sch->dev);
- spin_unlock(&sch->lock);
+ spin_unlock(sch->lock);
irq_exit ();
_local_bh_enable();
return 1;
}
-static inline int
+static int
cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
{
char dbf_text[15];
@@ -415,6 +414,8 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
CIO_TRACE_EVENT (2, "ensch");
CIO_TRACE_EVENT (2, sch->dev.bus_id);
+ if (sch_is_pseudo_sch(sch))
+ return -EINVAL;
ccode = stsch (sch->schid, &sch->schib);
if (ccode)
return -ENODEV;
@@ -462,6 +463,8 @@ cio_disable_subchannel (struct subchannel *sch)
CIO_TRACE_EVENT (2, "dissch");
CIO_TRACE_EVENT (2, sch->dev.bus_id);
+ if (sch_is_pseudo_sch(sch))
+ return 0;
ccode = stsch (sch->schid, &sch->schib);
if (ccode == 3) /* Not operational. */
return -ENODEV;
@@ -496,6 +499,15 @@ cio_disable_subchannel (struct subchannel *sch)
return ret;
}
+int cio_create_sch_lock(struct subchannel *sch)
+{
+ sch->lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+ if (!sch->lock)
+ return -ENOMEM;
+ spin_lock_init(sch->lock);
+ return 0;
+}
+
/*
* cio_validate_subchannel()
*
@@ -513,6 +525,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
{
char dbf_txt[15];
int ccode;
+ int err;
sprintf (dbf_txt, "valsch%x", schid.sch_no);
CIO_TRACE_EVENT (4, dbf_txt);
@@ -520,9 +533,15 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
/* Nuke all fields. */
memset(sch, 0, sizeof(struct subchannel));
- spin_lock_init(&sch->lock);
+ sch->schid = schid;
+ if (cio_is_console(schid)) {
+ sch->lock = cio_get_console_lock();
+ } else {
+ err = cio_create_sch_lock(sch);
+ if (err)
+ goto out;
+ }
mutex_init(&sch->reg_mutex);
-
/* Set a name for the subchannel */
snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid,
schid.sch_no);
@@ -534,10 +553,10 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
* is not valid.
*/
ccode = stsch_err (schid, &sch->schib);
- if (ccode)
- return (ccode == 3) ? -ENXIO : ccode;
-
- sch->schid = schid;
+ if (ccode) {
+ err = (ccode == 3) ? -ENXIO : ccode;
+ goto out;
+ }
/* Copy subchannel type from path management control word. */
sch->st = sch->schib.pmcw.st;
@@ -550,24 +569,27 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
"non-I/O subchannel type %04X\n",
sch->schid.ssid, sch->schid.sch_no, sch->st);
/* We stop here for non-io subchannels. */
- return sch->st;
+ err = sch->st;
+ goto out;
}
/* Initialization for io subchannels. */
- if (!sch->schib.pmcw.dnv)
+ if (!sch->schib.pmcw.dnv) {
/* io subchannel but device number is invalid. */
- return -ENODEV;
-
+ err = -ENODEV;
+ goto out;
+ }
/* Devno is valid. */
if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
/*
* This device must not be known to Linux. So we simply
* say that there is no device and return ENODEV.
*/
- CIO_MSG_EVENT(0, "Blacklisted device detected "
+ CIO_MSG_EVENT(4, "Blacklisted device detected "
"at devno %04X, subchannel set %x\n",
sch->schib.pmcw.dev, sch->schid.ssid);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
sch->opm = 0xff;
if (!cio_is_console(sch->schid))
@@ -595,6 +617,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
if ((sch->lpm & (sch->lpm - 1)) != 0)
sch->schib.pmcw.mp = 1; /* multipath mode */
return 0;
+out:
+ if (!cio_is_console(schid))
+ kfree(sch->lock);
+ sch->lock = NULL;
+ return err;
}
/*
@@ -619,7 +646,7 @@ do_IRQ (struct pt_regs *regs)
* Make sure that the i/o interrupt did not "overtake"
* the last HZ timer interrupt.
*/
- account_ticks();
+ account_ticks(S390_lowcore.int_clock);
/*
* Get interrupt information from lowcore
*/
@@ -637,7 +664,7 @@ do_IRQ (struct pt_regs *regs)
}
sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
if (sch)
- spin_lock(&sch->lock);
+ spin_lock(sch->lock);
/* Store interrupt response block to lowcore. */
if (tsch (tpi_info->schid, irb) == 0 && sch) {
/* Keep subchannel information word up to date. */
@@ -648,7 +675,7 @@ do_IRQ (struct pt_regs *regs)
sch->driver->irq(&sch->dev);
}
if (sch)
- spin_unlock(&sch->lock);
+ spin_unlock(sch->lock);
/*
* Are more interrupts pending?
* If so, the tpi instruction will update the lowcore
@@ -687,10 +714,10 @@ wait_cons_dev (void)
__ctl_load (cr6, 6, 6);
do {
- spin_unlock(&console_subchannel.lock);
+ spin_unlock(console_subchannel.lock);
if (!cio_tpi())
cpu_relax();
- spin_lock(&console_subchannel.lock);
+ spin_lock(console_subchannel.lock);
} while (console_subchannel.schib.scsw.actl != 0);
/*
* restore previous isc value
@@ -805,7 +832,7 @@ cio_get_console_subchannel(void)
}
#endif
-static inline int
+static int
__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
{
int retry, cc;
@@ -823,7 +850,20 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
return -EBUSY; /* uhm... */
}
-static inline int
+/* we can't use the normal udelay here, since it enables external interrupts */
+
+static void udelay_reset(unsigned long usecs)
+{
+ uint64_t start_cc, end_cc;
+
+ asm volatile ("STCK %0" : "=m" (start_cc));
+ do {
+ cpu_relax();
+ asm volatile ("STCK %0" : "=m" (end_cc));
+ } while (((end_cc - start_cc)/4096) < usecs);
+}
+
+static int
__clear_subchannel_easy(struct subchannel_id schid)
{
int retry;
@@ -838,16 +878,41 @@ __clear_subchannel_easy(struct subchannel_id schid)
if (schid_equal(&ti.schid, &schid))
return 0;
}
- udelay(100);
+ udelay_reset(100);
}
return -EBUSY;
}
+static int pgm_check_occured;
+
+static void cio_reset_pgm_check_handler(void)
+{
+ pgm_check_occured = 1;
+}
+
+static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr)
+{
+ int rc;
+
+ pgm_check_occured = 0;
+ s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
+ rc = stsch(schid, addr);
+ s390_base_pgm_handler_fn = NULL;
+
+ /* The program check handler could have changed pgm_check_occured. */
+ barrier();
+
+ if (pgm_check_occured)
+ return -EIO;
+ else
+ return rc;
+}
+
static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
{
struct schib schib;
- if (stsch_err(schid, &schib))
+ if (stsch_reset(schid, &schib))
return -ENXIO;
if (!schib.pmcw.ena)
return 0;
@@ -892,7 +957,7 @@ static void css_reset(void)
/* Reset subchannels. */
for_each_subchannel(__shutdown_subchannel_easy, NULL);
/* Reset channel paths. */
- s390_reset_mcck_handler = s390_reset_chpids_mcck_handler;
+ s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler;
/* Enable channel report machine checks. */
__ctl_set_bit(14, 28);
/* Temporarily reenable machine checks. */
@@ -917,7 +982,7 @@ static void css_reset(void)
local_mcck_disable();
/* Disable channel report machine checks. */
__ctl_clear_bit(14, 28);
- s390_reset_mcck_handler = NULL;
+ s390_base_mcck_handler_fn = NULL;
}
static struct reset_call css_reset_call = {
@@ -944,7 +1009,7 @@ static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
struct schib schib;
struct sch_match_id *match_id = data;
- if (stsch_err(schid, &schib))
+ if (stsch_reset(schid, &schib))
return -ENXIO;
if (schib.pmcw.dnv &&
(schib.pmcw.dev == match_id->devid.devno) &&
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 4541c1af4b6..35154a21035 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -87,7 +87,7 @@ struct orb {
/* subchannel data structure used by I/O subroutines */
struct subchannel {
struct subchannel_id schid;
- spinlock_t lock; /* subchannel lock */
+ spinlock_t *lock; /* subchannel lock */
struct mutex reg_mutex;
enum {
SUBCHANNEL_TYPE_IO = 0,
@@ -131,15 +131,19 @@ extern int cio_set_options (struct subchannel *, int);
extern int cio_get_options (struct subchannel *);
extern int cio_modify (struct subchannel *);
+int cio_create_sch_lock(struct subchannel *);
+
/* Use with care. */
#ifdef CONFIG_CCW_CONSOLE
extern struct subchannel *cio_probe_console(void);
extern void cio_release_console(void);
extern int cio_is_console(struct subchannel_id);
extern struct subchannel *cio_get_console_subchannel(void);
+extern spinlock_t * cio_get_console_lock(void);
#else
#define cio_is_console(schid) 0
#define cio_get_console_subchannel() NULL
+#define cio_get_console_lock() NULL;
#endif
extern int cio_show_msg;
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 828b2d334f0..90b22faabbf 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -519,8 +519,8 @@ struct cmb {
/* insert a single device into the cmb_area list
* called with cmb_area.lock held from alloc_cmb
*/
-static inline int alloc_cmb_single (struct ccw_device *cdev,
- struct cmb_data *cmb_data)
+static int alloc_cmb_single(struct ccw_device *cdev,
+ struct cmb_data *cmb_data)
{
struct cmb *cmb;
struct ccw_device_private *node;
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 26cf2f5ae2e..fe0ace7aece 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -30,7 +30,7 @@ struct channel_subsystem *css[__MAX_CSSID + 1];
int css_characteristics_avail = 0;
-inline int
+int
for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
{
struct subchannel_id schid;
@@ -91,9 +91,9 @@ css_free_subchannel(struct subchannel *sch)
/* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0;
cio_modify(sch);
+ kfree(sch->lock);
kfree(sch);
}
-
}
static void
@@ -102,13 +102,12 @@ css_subchannel_release(struct device *dev)
struct subchannel *sch;
sch = to_subchannel(dev);
- if (!cio_is_console(sch->schid))
+ if (!cio_is_console(sch->schid)) {
+ kfree(sch->lock);
kfree(sch);
+ }
}
-extern int css_get_ssd_info(struct subchannel *sch);
-
-
int css_sch_device_register(struct subchannel *sch)
{
int ret;
@@ -135,14 +134,17 @@ css_register_subchannel(struct subchannel *sch)
sch->dev.parent = &css[0]->device;
sch->dev.bus = &css_bus_type;
sch->dev.release = &css_subchannel_release;
-
+ sch->dev.groups = subch_attr_groups;
+
+ css_get_ssd_info(sch);
+
/* make it known to the system */
ret = css_sch_device_register(sch);
- if (ret)
+ if (ret) {
printk (KERN_WARNING "%s: could not register %s\n",
__func__, sch->dev.bus_id);
- else
- css_get_ssd_info(sch);
+ return ret;
+ }
return ret;
}
@@ -182,7 +184,7 @@ get_subchannel_by_schid(struct subchannel_id schid)
return dev ? to_subchannel(dev) : NULL;
}
-static inline int css_get_subchannel_status(struct subchannel *sch)
+static int css_get_subchannel_status(struct subchannel *sch)
{
struct schib schib;
@@ -201,18 +203,18 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
unsigned long flags;
enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action;
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
disc = device_is_disconnected(sch);
if (disc && slow) {
/* Disconnected devices are evaluated directly only.*/
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
return 0;
}
/* No interrupt after machine check - kill pending timers. */
device_kill_pending_timer(sch);
if (!disc && !slow) {
/* Non-disconnected devices are evaluated on the slow path. */
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
return -EAGAIN;
}
event = css_get_subchannel_status(sch);
@@ -237,9 +239,9 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
/* Ask driver what to do with device. */
action = UNREGISTER;
if (sch->driver && sch->driver->notify) {
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
ret = sch->driver->notify(&sch->dev, event);
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
if (ret)
action = NONE;
}
@@ -264,9 +266,9 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
case UNREGISTER:
case UNREGISTER_PROBE:
/* Unregister device (will use subchannel lock). */
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
css_sch_device_unregister(sch);
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
/* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0;
@@ -278,7 +280,7 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
default:
break;
}
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
/* Probe if necessary. */
if (action == UNREGISTER_PROBE)
ret = css_probe_device(sch->schid);
@@ -294,7 +296,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
/* Will be done on the slow path. */
return -EAGAIN;
}
- if (stsch(schid, &schib) || !schib.pmcw.dnv) {
+ if (stsch_err(schid, &schib) || !schib.pmcw.dnv) {
/* Unusable - ignore. */
return 0;
}
@@ -412,7 +414,7 @@ static void reprobe_all(struct work_struct *unused)
need_reprobe);
}
-DECLARE_WORK(css_reprobe_work, reprobe_all);
+static DECLARE_WORK(css_reprobe_work, reprobe_all);
/* Schedule reprobing of all unregistered subchannels. */
void css_schedule_reprobe(void)
@@ -573,12 +575,24 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store);
-static inline void __init
-setup_css(int nr)
+static int __init setup_css(int nr)
{
u32 tod_high;
+ int ret;
memset(css[nr], 0, sizeof(struct channel_subsystem));
+ css[nr]->pseudo_subchannel =
+ kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL);
+ if (!css[nr]->pseudo_subchannel)
+ return -ENOMEM;
+ css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device;
+ css[nr]->pseudo_subchannel->dev.release = css_subchannel_release;
+ sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct");
+ ret = cio_create_sch_lock(css[nr]->pseudo_subchannel);
+ if (ret) {
+ kfree(css[nr]->pseudo_subchannel);
+ return ret;
+ }
mutex_init(&css[nr]->mutex);
css[nr]->valid = 1;
css[nr]->cssid = nr;
@@ -586,6 +600,7 @@ setup_css(int nr)
css[nr]->device.release = channel_subsystem_release;
tod_high = (u32) (get_clock() >> 32);
css_generate_pgid(css[nr], tod_high);
+ return 0;
}
/*
@@ -622,10 +637,12 @@ init_channel_subsystem (void)
ret = -ENOMEM;
goto out_unregister;
}
- setup_css(i);
- ret = device_register(&css[i]->device);
+ ret = setup_css(i);
if (ret)
goto out_free;
+ ret = device_register(&css[i]->device);
+ if (ret)
+ goto out_free_all;
if (css_characteristics_avail &&
css_chsc_characteristics.secm) {
ret = device_create_file(&css[i]->device,
@@ -633,6 +650,9 @@ init_channel_subsystem (void)
if (ret)
goto out_device;
}
+ ret = device_register(&css[i]->pseudo_subchannel->dev);
+ if (ret)
+ goto out_file;
}
css_init_done = 1;
@@ -640,13 +660,19 @@ init_channel_subsystem (void)
for_each_subchannel(__init_channel_subsystem, NULL);
return 0;
+out_file:
+ device_remove_file(&css[i]->device, &dev_attr_cm_enable);
out_device:
device_unregister(&css[i]->device);
+out_free_all:
+ kfree(css[i]->pseudo_subchannel->lock);
+ kfree(css[i]->pseudo_subchannel);
out_free:
kfree(css[i]);
out_unregister:
while (i > 0) {
i--;
+ device_unregister(&css[i]->pseudo_subchannel->dev);
if (css_characteristics_avail && css_chsc_characteristics.secm)
device_remove_file(&css[i]->device,
&dev_attr_cm_enable);
@@ -658,6 +684,11 @@ out:
return ret;
}
+int sch_is_pseudo_sch(struct subchannel *sch)
+{
+ return sch == to_css(sch->dev.parent)->pseudo_subchannel;
+}
+
/*
* find a driver for a subchannel. They identify by the subchannel
* type with the exception that the console subchannel driver has its own
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 9ff064e7176..ca2bab932a8 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -73,6 +73,8 @@ struct senseid {
} __attribute__ ((packed,aligned(4)));
struct ccw_device_private {
+ struct ccw_device *cdev;
+ struct subchannel *sch;
int state; /* device state */
atomic_t onoff;
unsigned long registered;
@@ -141,6 +143,8 @@ extern void css_sch_device_unregister(struct subchannel *);
extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
extern int css_init_done;
extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
+extern int css_process_crw(int, int);
+extern void css_reiterate_subchannels(void);
#define __MAX_SUBCHANNEL 65535
#define __MAX_SSID 3
@@ -158,6 +162,8 @@ struct channel_subsystem {
int cm_enabled;
void *cub_addr1;
void *cub_addr2;
+ /* for orphaned ccw devices */
+ struct subchannel *pseudo_subchannel;
};
#define to_css(dev) container_of(dev, struct channel_subsystem, device)
@@ -185,6 +191,11 @@ void css_clear_subchannel_slow_list(void);
int css_slow_subchannels_exist(void);
extern int need_rescan;
+int sch_is_pseudo_sch(struct subchannel *);
+
extern struct workqueue_struct *slow_path_wq;
extern struct work_struct slow_path_work;
+
+int subchannel_add_files (struct device *);
+extern struct attribute_group *subch_attr_groups[];
#endif
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index d3d3716ff84..e322111fb36 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -23,6 +23,7 @@
#include <asm/param.h> /* HZ */
#include "cio.h"
+#include "cio_debug.h"
#include "css.h"
#include "device.h"
#include "ioasm.h"
@@ -137,7 +138,6 @@ struct bus_type ccw_bus_type;
static int io_subchannel_probe (struct subchannel *);
static int io_subchannel_remove (struct subchannel *);
-void io_subchannel_irq (struct device *);
static int io_subchannel_notify(struct device *, int);
static void io_subchannel_verify(struct device *);
static void io_subchannel_ioterm(struct device *);
@@ -236,7 +236,6 @@ chpids_show (struct device * dev, struct device_attribute *attr, char * buf)
for (chp = 0; chp < 8; chp++)
ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
-
ret += sprintf (buf+ret, "\n");
return min((ssize_t)PAGE_SIZE, ret);
}
@@ -294,14 +293,44 @@ online_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, cdev->online ? "1\n" : "0\n");
}
+int ccw_device_is_orphan(struct ccw_device *cdev)
+{
+ return sch_is_pseudo_sch(to_subchannel(cdev->dev.parent));
+}
+
+static void ccw_device_unregister(struct work_struct *work)
+{
+ struct ccw_device_private *priv;
+ struct ccw_device *cdev;
+
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
+ if (test_and_clear_bit(1, &cdev->private->registered))
+ device_unregister(&cdev->dev);
+ put_device(&cdev->dev);
+}
+
static void
ccw_device_remove_disconnected(struct ccw_device *cdev)
{
struct subchannel *sch;
+ unsigned long flags;
/*
* Forced offline in disconnected state means
* 'throw away device'.
*/
+ if (ccw_device_is_orphan(cdev)) {
+ /* Deregister ccw device. */
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ cdev->private->state = DEV_STATE_NOT_OPER;
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_unregister);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ }
+ return ;
+ }
sch = to_subchannel(cdev->dev.parent);
css_sch_device_unregister(sch);
/* Reset intparm to zeroes. */
@@ -462,6 +491,8 @@ available_show (struct device *dev, struct device_attribute *attr, char *buf)
struct ccw_device *cdev = to_ccwdev(dev);
struct subchannel *sch;
+ if (ccw_device_is_orphan(cdev))
+ return sprintf(buf, "no device\n");
switch (cdev->private->state) {
case DEV_STATE_BOXED:
return sprintf(buf, "boxed\n");
@@ -498,11 +529,10 @@ static struct attribute_group subch_attr_group = {
.attrs = subch_attrs,
};
-static inline int
-subchannel_add_files (struct device *dev)
-{
- return sysfs_create_group(&dev->kobj, &subch_attr_group);
-}
+struct attribute_group *subch_attr_groups[] = {
+ &subch_attr_group,
+ NULL,
+};
static struct attribute * ccwdev_attrs[] = {
&dev_attr_devtype.attr,
@@ -518,13 +548,13 @@ static struct attribute_group ccwdev_attr_group = {
.attrs = ccwdev_attrs,
};
-static inline int
+static int
device_add_files (struct device *dev)
{
return sysfs_create_group(&dev->kobj, &ccwdev_attr_group);
}
-static inline void
+static void
device_remove_files(struct device *dev)
{
sysfs_remove_group(&dev->kobj, &ccwdev_attr_group);
@@ -563,11 +593,10 @@ match_devno(struct device * dev, void * data)
cdev = to_ccwdev(dev);
if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
+ !ccw_device_is_orphan(cdev) &&
ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) &&
- (cdev != d->sibling)) {
- cdev->private->state = DEV_STATE_NOT_OPER;
+ (cdev != d->sibling))
return 1;
- }
return 0;
}
@@ -584,13 +613,36 @@ static struct ccw_device * get_disc_ccwdev_by_dev_id(struct ccw_dev_id *dev_id,
return dev ? to_ccwdev(dev) : NULL;
}
-static void
-ccw_device_add_changed(void *data)
+static int match_orphan(struct device *dev, void *data)
+{
+ struct ccw_dev_id *dev_id;
+ struct ccw_device *cdev;
+
+ dev_id = data;
+ cdev = to_ccwdev(dev);
+ return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
+}
+
+static struct ccw_device *
+get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css,
+ struct ccw_dev_id *dev_id)
{
+ struct device *dev;
+ dev = device_find_child(&css->pseudo_subchannel->dev, dev_id,
+ match_orphan);
+
+ return dev ? to_ccwdev(dev) : NULL;
+}
+
+static void
+ccw_device_add_changed(struct work_struct *work)
+{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
- cdev = data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
if (device_add(&cdev->dev)) {
put_device(&cdev->dev);
return;
@@ -602,64 +654,21 @@ ccw_device_add_changed(void *data)
}
}
-extern int css_get_ssd_info(struct subchannel *sch);
-
-void
-ccw_device_do_unreg_rereg(void *data)
+void ccw_device_do_unreg_rereg(struct work_struct *work)
{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
struct subchannel *sch;
- int need_rename;
- cdev = data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
sch = to_subchannel(cdev->dev.parent);
- 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
- * on another subchannel because of a different attachment
- * order than before. Ideally, we should should just switch
- * subchannels, but unfortunately, this is not possible with
- * the current implementation.
- * Instead, we search for the old subchannel for this device
- * number and deregister so there are no collisions with the
- * newly registered ccw_device.
- * FIXME: Find another solution so the block layer doesn't
- * get possibly sick...
- */
- struct ccw_device *other_cdev;
- struct ccw_dev_id dev_id;
-
- need_rename = 1;
- 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;
-
- other_sch = to_subchannel(other_cdev->dev.parent);
- if (get_device(&other_sch->dev)) {
- stsch(other_sch->schid, &other_sch->schib);
- if (other_sch->schib.pmcw.dnv) {
- other_sch->schib.pmcw.intparm = 0;
- cio_modify(other_sch);
- }
- css_sch_device_unregister(other_sch);
- }
- }
- /* Update ssd info here. */
- css_get_ssd_info(sch);
- cdev->private->dev_id.devno = sch->schib.pmcw.dev;
- } else
- need_rename = 0;
+
device_remove_files(&cdev->dev);
if (test_and_clear_bit(1, &cdev->private->registered))
device_del(&cdev->dev);
- if (need_rename)
- 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, cdev);
+ ccw_device_add_changed);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
@@ -673,18 +682,194 @@ ccw_device_release(struct device *dev)
kfree(cdev);
}
+static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch)
+{
+ struct ccw_device *cdev;
+
+ cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+ if (cdev) {
+ cdev->private = kzalloc(sizeof(struct ccw_device_private),
+ GFP_KERNEL | GFP_DMA);
+ if (cdev->private)
+ return cdev;
+ }
+ kfree(cdev);
+ return ERR_PTR(-ENOMEM);
+}
+
+static int io_subchannel_initialize_dev(struct subchannel *sch,
+ struct ccw_device *cdev)
+{
+ cdev->private->cdev = cdev;
+ atomic_set(&cdev->private->onoff, 0);
+ cdev->dev.parent = &sch->dev;
+ cdev->dev.release = ccw_device_release;
+ INIT_LIST_HEAD(&cdev->private->kick_work.entry);
+ /* Do first half of device_register. */
+ device_initialize(&cdev->dev);
+ if (!get_device(&sch->dev)) {
+ if (cdev->dev.release)
+ cdev->dev.release(&cdev->dev);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static struct ccw_device * io_subchannel_create_ccwdev(struct subchannel *sch)
+{
+ struct ccw_device *cdev;
+ int ret;
+
+ cdev = io_subchannel_allocate_dev(sch);
+ if (!IS_ERR(cdev)) {
+ ret = io_subchannel_initialize_dev(sch, cdev);
+ if (ret) {
+ kfree(cdev);
+ cdev = ERR_PTR(ret);
+ }
+ }
+ return cdev;
+}
+
+static int io_subchannel_recog(struct ccw_device *, struct subchannel *);
+
+static void sch_attach_device(struct subchannel *sch,
+ struct ccw_device *cdev)
+{
+ spin_lock_irq(sch->lock);
+ sch->dev.driver_data = cdev;
+ cdev->private->schid = sch->schid;
+ cdev->ccwlock = sch->lock;
+ device_trigger_reprobe(sch);
+ spin_unlock_irq(sch->lock);
+}
+
+static void sch_attach_disconnected_device(struct subchannel *sch,
+ struct ccw_device *cdev)
+{
+ struct subchannel *other_sch;
+ int ret;
+
+ other_sch = to_subchannel(get_device(cdev->dev.parent));
+ ret = device_move(&cdev->dev, &sch->dev);
+ if (ret) {
+ CIO_MSG_EVENT(2, "Moving disconnected device 0.%x.%04x failed "
+ "(ret=%d)!\n", cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
+ put_device(&other_sch->dev);
+ return;
+ }
+ other_sch->dev.driver_data = NULL;
+ /* No need to keep a subchannel without ccw device around. */
+ css_sch_device_unregister(other_sch);
+ put_device(&other_sch->dev);
+ sch_attach_device(sch, cdev);
+}
+
+static void sch_attach_orphaned_device(struct subchannel *sch,
+ struct ccw_device *cdev)
+{
+ int ret;
+
+ /* Try to move the ccw device to its new subchannel. */
+ ret = device_move(&cdev->dev, &sch->dev);
+ if (ret) {
+ CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage "
+ "failed (ret=%d)!\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
+ return;
+ }
+ sch_attach_device(sch, cdev);
+}
+
+static void sch_create_and_recog_new_device(struct subchannel *sch)
+{
+ struct ccw_device *cdev;
+
+ /* Need to allocate a new ccw device. */
+ cdev = io_subchannel_create_ccwdev(sch);
+ if (IS_ERR(cdev)) {
+ /* OK, we did everything we could... */
+ css_sch_device_unregister(sch);
+ return;
+ }
+ spin_lock_irq(sch->lock);
+ sch->dev.driver_data = cdev;
+ spin_unlock_irq(sch->lock);
+ /* Start recognition for the new ccw device. */
+ if (io_subchannel_recog(cdev, sch)) {
+ spin_lock_irq(sch->lock);
+ sch->dev.driver_data = NULL;
+ spin_unlock_irq(sch->lock);
+ if (cdev->dev.release)
+ cdev->dev.release(&cdev->dev);
+ css_sch_device_unregister(sch);
+ }
+}
+
+
+void ccw_device_move_to_orphanage(struct work_struct *work)
+{
+ struct ccw_device_private *priv;
+ struct ccw_device *cdev;
+ struct ccw_device *replacing_cdev;
+ struct subchannel *sch;
+ int ret;
+ struct channel_subsystem *css;
+ struct ccw_dev_id dev_id;
+
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
+ sch = to_subchannel(cdev->dev.parent);
+ css = to_css(sch->dev.parent);
+ dev_id.devno = sch->schib.pmcw.dev;
+ dev_id.ssid = sch->schid.ssid;
+
+ /*
+ * Move the orphaned ccw device to the orphanage so the replacing
+ * ccw device can take its place on the subchannel.
+ */
+ ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev);
+ if (ret) {
+ CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed "
+ "(ret=%d)!\n", cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
+ return;
+ }
+ cdev->ccwlock = css->pseudo_subchannel->lock;
+ /*
+ * Search for the replacing ccw device
+ * - among the disconnected devices
+ * - in the orphanage
+ */
+ replacing_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev);
+ if (replacing_cdev) {
+ sch_attach_disconnected_device(sch, replacing_cdev);
+ return;
+ }
+ replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id);
+ if (replacing_cdev) {
+ sch_attach_orphaned_device(sch, replacing_cdev);
+ return;
+ }
+ sch_create_and_recog_new_device(sch);
+}
+
/*
* Register recognized device.
*/
static void
-io_subchannel_register(void *data)
+io_subchannel_register(struct work_struct *work)
{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
struct subchannel *sch;
int ret;
unsigned long flags;
- cdev = data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
sch = to_subchannel(cdev->dev.parent);
/*
@@ -709,9 +894,9 @@ io_subchannel_register(void *data)
printk (KERN_WARNING "%s: could not register %s\n",
__func__, cdev->dev.bus_id);
put_device(&cdev->dev);
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
sch->dev.driver_data = NULL;
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
kfree (cdev->private);
kfree (cdev);
put_device(&sch->dev);
@@ -719,11 +904,6 @@ io_subchannel_register(void *data)
wake_up(&ccw_device_init_wq);
return;
}
-
- ret = subchannel_add_files(cdev->dev.parent);
- if (ret)
- printk(KERN_WARNING "%s: could not add attributes to %s\n",
- __func__, sch->dev.bus_id);
put_device(&cdev->dev);
out:
cdev->private->flags.recog_done = 1;
@@ -734,11 +914,14 @@ out:
}
void
-ccw_device_call_sch_unregister(void *data)
+ccw_device_call_sch_unregister(struct work_struct *work)
{
- struct ccw_device *cdev = data;
+ struct ccw_device_private *priv;
+ struct ccw_device *cdev;
struct subchannel *sch;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
sch = to_subchannel(cdev->dev.parent);
css_sch_device_unregister(sch);
/* Reset intparm to zeroes. */
@@ -768,7 +951,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, cdev);
+ ccw_device_call_sch_unregister);
queue_work(slow_path_wq, &cdev->private->kick_work);
if (atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
@@ -783,7 +966,7 @@ io_subchannel_recog_done(struct ccw_device *cdev)
if (!get_device(&cdev->dev))
break;
PREPARE_WORK(&cdev->private->kick_work,
- io_subchannel_register, cdev);
+ io_subchannel_register);
queue_work(slow_path_wq, &cdev->private->kick_work);
break;
}
@@ -797,7 +980,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
sch->dev.driver_data = cdev;
sch->driver = &io_subchannel_driver;
- cdev->ccwlock = &sch->lock;
+ cdev->ccwlock = sch->lock;
/* Init private data. */
priv = cdev->private;
@@ -817,9 +1000,9 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
atomic_inc(&ccw_device_init_count);
/* Start async. device sensing. */
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
rc = ccw_device_recognition(cdev);
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
if (rc) {
if (atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
@@ -827,12 +1010,55 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
return rc;
}
+static void ccw_device_move_to_sch(struct work_struct *work)
+{
+ struct ccw_device_private *priv;
+ int rc;
+ struct subchannel *sch;
+ struct ccw_device *cdev;
+ struct subchannel *former_parent;
+
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ sch = priv->sch;
+ cdev = priv->cdev;
+ former_parent = ccw_device_is_orphan(cdev) ?
+ NULL : to_subchannel(get_device(cdev->dev.parent));
+ mutex_lock(&sch->reg_mutex);
+ /* Try to move the ccw device to its new subchannel. */
+ rc = device_move(&cdev->dev, &sch->dev);
+ mutex_unlock(&sch->reg_mutex);
+ if (rc) {
+ CIO_MSG_EVENT(2, "Moving device 0.%x.%04x to subchannel "
+ "0.%x.%04x failed (ret=%d)!\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, sch->schid.ssid,
+ sch->schid.sch_no, rc);
+ css_sch_device_unregister(sch);
+ goto out;
+ }
+ if (former_parent) {
+ spin_lock_irq(former_parent->lock);
+ former_parent->dev.driver_data = NULL;
+ spin_unlock_irq(former_parent->lock);
+ css_sch_device_unregister(former_parent);
+ /* Reset intparm to zeroes. */
+ former_parent->schib.pmcw.intparm = 0;
+ cio_modify(former_parent);
+ }
+ sch_attach_device(sch, cdev);
+out:
+ if (former_parent)
+ put_device(&former_parent->dev);
+ put_device(&cdev->dev);
+}
+
static int
io_subchannel_probe (struct subchannel *sch)
{
struct ccw_device *cdev;
int rc;
unsigned long flags;
+ struct ccw_dev_id dev_id;
if (sch->dev.driver_data) {
/*
@@ -843,7 +1069,6 @@ io_subchannel_probe (struct subchannel *sch)
cdev = sch->dev.driver_data;
device_initialize(&cdev->dev);
ccw_device_register(cdev);
- subchannel_add_files(&sch->dev);
/*
* Check if the device is already online. If it is
* the reference count needs to be corrected
@@ -856,33 +1081,37 @@ io_subchannel_probe (struct subchannel *sch)
get_device(&cdev->dev);
return 0;
}
- cdev = kzalloc (sizeof(*cdev), GFP_KERNEL);
+ /*
+ * First check if a fitting device may be found amongst the
+ * disconnected devices or in the orphanage.
+ */
+ dev_id.devno = sch->schib.pmcw.dev;
+ dev_id.ssid = sch->schid.ssid;
+ cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
if (!cdev)
- return -ENOMEM;
- cdev->private = kzalloc(sizeof(struct ccw_device_private),
- GFP_KERNEL | GFP_DMA);
- if (!cdev->private) {
- kfree(cdev);
- return -ENOMEM;
- }
- atomic_set(&cdev->private->onoff, 0);
- cdev->dev.parent = &sch->dev;
- cdev->dev.release = ccw_device_release;
- INIT_LIST_HEAD(&cdev->private->kick_work.entry);
- /* Do first half of device_register. */
- device_initialize(&cdev->dev);
-
- if (!get_device(&sch->dev)) {
- if (cdev->dev.release)
- cdev->dev.release(&cdev->dev);
- return -ENODEV;
+ cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
+ &dev_id);
+ if (cdev) {
+ /*
+ * Schedule moving the device until when we have a registered
+ * subchannel to move to and succeed the probe. We can
+ * unregister later again, when the probe is through.
+ */
+ cdev->private->sch = sch;
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_move_to_sch);
+ queue_work(slow_path_wq, &cdev->private->kick_work);
+ return 0;
}
+ cdev = io_subchannel_create_ccwdev(sch);
+ if (IS_ERR(cdev))
+ return PTR_ERR(cdev);
rc = io_subchannel_recog(cdev, sch);
if (rc) {
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
sch->dev.driver_data = NULL;
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
if (cdev->dev.release)
cdev->dev.release(&cdev->dev);
}
@@ -890,17 +1119,6 @@ io_subchannel_probe (struct subchannel *sch)
return rc;
}
-static void
-ccw_device_unregister(void *data)
-{
- struct ccw_device *cdev;
-
- cdev = (struct ccw_device *)data;
- if (test_and_clear_bit(1, &cdev->private->registered))
- device_unregister(&cdev->dev);
- put_device(&cdev->dev);
-}
-
static int
io_subchannel_remove (struct subchannel *sch)
{
@@ -921,7 +1139,7 @@ io_subchannel_remove (struct subchannel *sch)
*/
if (get_device(&cdev->dev)) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_unregister, cdev);
+ ccw_device_unregister);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
return 0;
@@ -1003,6 +1221,13 @@ static struct ccw_device console_cdev;
static struct ccw_device_private console_private;
static int console_cdev_in_use;
+static DEFINE_SPINLOCK(ccw_console_lock);
+
+spinlock_t * cio_get_console_lock(void)
+{
+ return &ccw_console_lock;
+}
+
static int
ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
{
@@ -1048,6 +1273,7 @@ ccw_device_probe_console(void)
memset(&console_cdev, 0, sizeof(struct ccw_device));
memset(&console_private, 0, sizeof(struct ccw_device_private));
console_cdev.private = &console_private;
+ console_private.cdev = &console_cdev;
ret = ccw_device_console_enable(&console_cdev, sch);
if (ret) {
cio_release_console();
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 9233b5c0bcc..b66338b7657 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -74,12 +74,15 @@ extern struct workqueue_struct *ccw_device_notify_work;
extern wait_queue_head_t ccw_device_init_wq;
extern atomic_t ccw_device_init_count;
+void io_subchannel_irq (struct device *pdev);
void io_subchannel_recog_done(struct ccw_device *cdev);
int ccw_device_cancel_halt_clear(struct ccw_device *);
-void ccw_device_do_unreg_rereg(void *);
-void ccw_device_call_sch_unregister(void *);
+void ccw_device_do_unreg_rereg(struct work_struct *);
+void ccw_device_call_sch_unregister(struct work_struct *);
+void ccw_device_move_to_orphanage(struct work_struct *);
+int ccw_device_is_orphan(struct ccw_device *);
int ccw_device_recognition(struct ccw_device *);
int ccw_device_online(struct ccw_device *);
@@ -116,6 +119,7 @@ int ccw_device_stlck(struct ccw_device *);
/* qdio needs this. */
void ccw_device_set_timeout(struct ccw_device *, int);
extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
+extern struct bus_type ccw_bus_type;
/* Channel measurement facility related */
void retry_set_schib(struct ccw_device *cdev);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 09c7672eb3f..51238e7555b 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -186,15 +186,14 @@ ccw_device_handle_oper(struct ccw_device *cdev)
/*
* Check if cu type and device type still match. If
* not, it is certainly another device and we have to
- * de- and re-register. Also check here for non-matching devno.
+ * de- and re-register.
*/
if (cdev->id.cu_type != cdev->private->senseid.cu_type ||
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->dev_id.devno != sch->schib.pmcw.dev) {
+ cdev->id.dev_model != cdev->private->senseid.dev_model) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_do_unreg_rereg, cdev);
+ ccw_device_do_unreg_rereg);
queue_work(ccw_device_work, &cdev->private->kick_work);
return 0;
}
@@ -207,7 +206,7 @@ ccw_device_handle_oper(struct ccw_device *cdev)
* been varied online on the SE so we have to find out by magic (i. e. driving
* the channel subsystem to device selection and updating our path masks).
*/
-static inline void
+static void
__recover_lost_chpids(struct subchannel *sch, int old_lpm)
{
int mask, i;
@@ -329,19 +328,21 @@ ccw_device_sense_id_done(struct ccw_device *cdev, int err)
}
static void
-ccw_device_oper_notify(void *data)
+ccw_device_oper_notify(struct work_struct *work)
{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
struct subchannel *sch;
int ret;
- cdev = data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
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(cdev);
+ ccw_device_do_unreg_rereg(work);
else {
/* Reenable channel measurements, if needed. */
cmf_reenable(cdev);
@@ -377,8 +378,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
if (cdev->private->flags.donotify) {
cdev->private->flags.donotify = 0;
- PREPARE_WORK(&cdev->private->kick_work, ccw_device_oper_notify,
- cdev);
+ PREPARE_WORK(&cdev->private->kick_work, ccw_device_oper_notify);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
}
wake_up(&cdev->private->wait_q);
@@ -387,7 +387,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
put_device (&cdev->dev);
}
-static inline int cmp_pgid(struct pgid *p1, struct pgid *p2)
+static int cmp_pgid(struct pgid *p1, struct pgid *p2)
{
char *c1;
char *c2;
@@ -528,13 +528,15 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event)
static void
-ccw_device_nopath_notify(void *data)
+ccw_device_nopath_notify(struct work_struct *work)
{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
struct subchannel *sch;
int ret;
- cdev = data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
sch = to_subchannel(cdev->dev.parent);
/* Extra sanity. */
if (sch->lpm)
@@ -547,8 +549,7 @@ ccw_device_nopath_notify(void *data)
cio_disable_subchannel(sch);
if (get_device(&cdev->dev)) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister,
- cdev);
+ ccw_device_call_sch_unregister);
queue_work(ccw_device_work,
&cdev->private->kick_work);
} else
@@ -607,7 +608,7 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
/* Reset oper notify indication after verify error. */
cdev->private->flags.donotify = 0;
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
@@ -674,6 +675,10 @@ ccw_device_offline(struct ccw_device *cdev)
{
struct subchannel *sch;
+ if (ccw_device_is_orphan(cdev)) {
+ ccw_device_done(cdev, DEV_STATE_OFFLINE);
+ return 0;
+ }
sch = to_subchannel(cdev->dev.parent);
if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv)
return -ENODEV;
@@ -738,7 +743,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, cdev);
+ ccw_device_call_sch_unregister);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
wake_up(&cdev->private->wait_q);
@@ -769,7 +774,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, cdev);
+ ccw_device_call_sch_unregister);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
wake_up(&cdev->private->wait_q);
@@ -837,6 +842,8 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
call_handler_unsol:
if (cdev->handler)
cdev->handler (cdev, 0, irb);
+ if (cdev->private->flags.doverify)
+ ccw_device_online_verify(cdev, 0);
return;
}
/* Accumulate status and find out if a basic sense is needed. */
@@ -874,7 +881,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, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work,
&cdev->private->kick_work);
} else
@@ -887,7 +894,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
/*
* Got an interrupt for a basic sense.
*/
-void
+static void
ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
{
struct irb *irb;
@@ -969,7 +976,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event)
ERR_PTR(-EIO));
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
} else if (cdev->private->flags.doverify)
/* Start delayed path verification. */
@@ -992,7 +999,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, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work,
&cdev->private->kick_work);
} else
@@ -1021,7 +1028,7 @@ void device_kill_io(struct subchannel *sch)
if (ret == -ENODEV) {
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work,
&cdev->private->kick_work);
} else
@@ -1033,7 +1040,7 @@ void device_kill_io(struct subchannel *sch)
ERR_PTR(-EIO));
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
} else
/* Start delayed path verification. */
@@ -1104,7 +1111,8 @@ device_trigger_reprobe(struct subchannel *sch)
/* Update some values. */
if (stsch(sch->schid, &sch->schib))
return;
-
+ if (!sch->schib.pmcw.dnv)
+ return;
/*
* The pim, pam, pom values may not be accurate, but they are the best
* we have before performing device selection :/
@@ -1118,7 +1126,13 @@ device_trigger_reprobe(struct subchannel *sch)
sch->schib.pmcw.mp = 1;
sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
/* We should also udate ssd info, but this has to wait. */
- ccw_device_start_id(cdev, 0);
+ /* Check if this is another device which appeared on the same sch. */
+ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_move_to_orphanage);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ } else
+ ccw_device_start_id(cdev, 0);
}
static void
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index b39c1fa48ac..d7b25b8f71d 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -302,7 +302,7 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
wake_up(&cdev->private->wait_q);
}
-static inline int
+static int
__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm)
{
int ret;
@@ -316,9 +316,9 @@ __ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, _
ccw_device_set_timeout(cdev, 0);
if (ret == -EBUSY) {
/* Try again later. */
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
msleep(10);
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
continue;
}
if (ret != 0)
@@ -326,12 +326,12 @@ __ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, _
break;
/* Wait for end of request. */
cdev->private->intparm = magic;
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
wait_event(cdev->private->wait_q,
(cdev->private->intparm == -EIO) ||
(cdev->private->intparm == -EAGAIN) ||
(cdev->private->intparm == 0));
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
/* Check at least for channel end / device end */
if (cdev->private->intparm == -EIO) {
/* Non-retryable error. */
@@ -342,9 +342,9 @@ __ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, _
/* Success. */
break;
/* Try again later. */
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
msleep(10);
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
} while (1);
return ret;
@@ -389,7 +389,7 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
return ret;
}
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
/* Save interrupt handler. */
handler = cdev->handler;
/* Temporarily install own handler. */
@@ -406,7 +406,7 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
/* Restore interrupt handler. */
cdev->handler = handler;
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
clear_normalized_cda (rdc_ccw);
kfree(rdc_ccw);
@@ -463,7 +463,7 @@ read_conf_data_lpm (struct ccw_device *cdev, void **buffer, int *length, __u8 lp
rcd_ccw->count = ciw->count;
rcd_ccw->flags = CCW_FLAG_SLI;
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
/* Save interrupt handler. */
handler = cdev->handler;
/* Temporarily install own handler. */
@@ -480,7 +480,7 @@ read_conf_data_lpm (struct ccw_device *cdev, void **buffer, int *length, __u8 lp
/* Restore interrupt handler. */
cdev->handler = handler;
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
/*
* on success we update the user input parms
@@ -537,7 +537,7 @@ ccw_device_stlck(struct ccw_device *cdev)
kfree(buf);
return -ENOMEM;
}
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
ret = cio_enable_subchannel(sch, 3);
if (ret)
goto out_unlock;
@@ -559,9 +559,9 @@ ccw_device_stlck(struct ccw_device *cdev)
goto out_unlock;
}
cdev->private->irb.scsw.actl |= SCSW_ACTL_START_PEND;
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
wait_event(cdev->private->wait_q, cdev->private->irb.scsw.actl == 0);
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
cio_disable_subchannel(sch); //FIXME: return code?
if ((cdev->private->irb.scsw.dstat !=
(DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
@@ -572,7 +572,7 @@ ccw_device_stlck(struct ccw_device *cdev)
out_unlock:
kfree(buf);
kfree(buf2);
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
return ret;
}
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index bdcf930f7be..6b1caea622e 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -25,7 +25,7 @@
* Check for any kind of channel or interface control check but don't
* issue the message for the console device
*/
-static inline void
+static void
ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
{
if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK |
@@ -72,7 +72,7 @@ ccw_device_path_notoper(struct ccw_device *cdev)
/*
* Copy valid bits from the extended control word to device irb.
*/
-static inline void
+static void
ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
{
/*
@@ -94,7 +94,7 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
/*
* Check if extended status word is valid.
*/
-static inline int
+static int
ccw_device_accumulate_esw_valid(struct irb *irb)
{
if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
@@ -109,7 +109,7 @@ ccw_device_accumulate_esw_valid(struct irb *irb)
/*
* Copy valid bits from the extended status word to device irb.
*/
-static inline void
+static void
ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
{
struct irb *cdev_irb;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 8d5fa1b4d11..d726cd5777d 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -46,6 +46,7 @@
#include <asm/timex.h>
#include <asm/debug.h>
+#include <asm/s390_rdev.h>
#include <asm/qdio.h>
#include "cio.h"
@@ -66,11 +67,10 @@ MODULE_LICENSE("GPL");
static const char version[] = "QDIO base support version 2";
-#ifdef QDIO_PERFORMANCE_STATS
+static int qdio_performance_stats = 0;
static int proc_perf_file_registration;
static unsigned long i_p_c, i_p_nc, o_p_c, o_p_nc, ii_p_c, ii_p_nc;
static struct qdio_perf_stats perf_stats;
-#endif /* QDIO_PERFORMANCE_STATS */
static int hydra_thinints;
static int is_passthrough = 0;
@@ -137,7 +137,7 @@ qdio_release_q(struct qdio_q *q)
}
/*check ccq */
-static inline int
+static int
qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
{
char dbf_text[15];
@@ -152,7 +152,7 @@ qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
return -EIO;
}
/* EQBS: extract buffer states */
-static inline int
+static int
qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
unsigned int *start, unsigned int *cnt)
{
@@ -187,7 +187,7 @@ again:
}
/* SQBS: set buffer states */
-static inline int
+static int
qdio_do_sqbs(struct qdio_q *q, unsigned char state,
unsigned int *start, unsigned int *cnt)
{
@@ -275,9 +275,8 @@ qdio_siga_sync(struct qdio_q *q, unsigned int gpr2,
QDIO_DBF_TEXT4(0,trace,"sigasync");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.siga_syncs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.siga_syncs++;
cc = do_siga_sync(q->schid, gpr2, gpr3);
if (cc)
@@ -315,16 +314,15 @@ __do_siga_output(struct qdio_q *q, unsigned int *busy_bit)
* returns QDIO_SIGA_ERROR_ACCESS_EXCEPTION as cc, when SIGA returns
* an access exception
*/
-static inline int
+static int
qdio_siga_output(struct qdio_q *q)
{
int cc;
__u32 busy_bit;
__u64 start_time=0;
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.siga_outs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.siga_outs++;
QDIO_DBF_TEXT4(0,trace,"sigaout");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
@@ -350,7 +348,7 @@ qdio_siga_output(struct qdio_q *q)
return cc;
}
-static inline int
+static int
qdio_siga_input(struct qdio_q *q)
{
int cc;
@@ -358,9 +356,8 @@ qdio_siga_input(struct qdio_q *q)
QDIO_DBF_TEXT4(0,trace,"sigain");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.siga_ins++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.siga_ins++;
cc = do_siga_input(q->schid, q->mask);
@@ -423,7 +420,7 @@ tiqdio_sched_tl(void)
tasklet_hi_schedule(&tiqdio_tasklet);
}
-static inline void
+static void
qdio_mark_tiq(struct qdio_q *q)
{
unsigned long flags;
@@ -473,7 +470,7 @@ qdio_mark_q(struct qdio_q *q)
tasklet_schedule(&q->tasklet);
}
-static inline int
+static int
qdio_stop_polling(struct qdio_q *q)
{
#ifdef QDIO_USE_PROCESSING_STATE
@@ -527,7 +524,7 @@ qdio_stop_polling(struct qdio_q *q)
* sophisticated locking outside of unmark_q, so that we don't need to
* disable the interrupts :-)
*/
-static inline void
+static void
qdio_unmark_q(struct qdio_q *q)
{
unsigned long flags;
@@ -693,7 +690,7 @@ qdio_qebsm_get_inbound_buffer_frontier(struct qdio_q *q)
return q->first_to_check;
}
-static inline int
+static int
qdio_get_outbound_buffer_frontier(struct qdio_q *q)
{
struct qdio_irq *irq;
@@ -776,7 +773,7 @@ out:
}
/* all buffers are processed */
-static inline int
+static int
qdio_is_outbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -798,7 +795,7 @@ qdio_is_outbound_q_done(struct qdio_q *q)
return (no_used==0);
}
-static inline int
+static int
qdio_has_outbound_q_moved(struct qdio_q *q)
{
int i;
@@ -818,7 +815,7 @@ qdio_has_outbound_q_moved(struct qdio_q *q)
}
}
-static inline void
+static void
qdio_kick_outbound_q(struct qdio_q *q)
{
int result;
@@ -907,7 +904,7 @@ qdio_kick_outbound_q(struct qdio_q *q)
}
}
-static inline void
+static void
qdio_kick_outbound_handler(struct qdio_q *q)
{
int start, end, real_end, count;
@@ -944,7 +941,7 @@ qdio_kick_outbound_handler(struct qdio_q *q)
q->error_status_flags=0;
}
-static inline void
+static void
__qdio_outbound_processing(struct qdio_q *q)
{
int siga_attempts;
@@ -954,9 +951,8 @@ __qdio_outbound_processing(struct qdio_q *q)
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- o_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ o_p_c++;
/* as we're sissies, we'll check next time */
if (likely(!atomic_read(&q->is_in_shutdown))) {
qdio_mark_q(q);
@@ -964,10 +960,10 @@ __qdio_outbound_processing(struct qdio_q *q)
}
return;
}
-#ifdef QDIO_PERFORMANCE_STATS
- o_p_nc++;
- perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ o_p_nc++;
+ perf_stats.tl_runs++;
+ }
/* see comment in qdio_kick_outbound_q */
siga_attempts=atomic_read(&q->busy_siga_counter);
@@ -982,12 +978,11 @@ __qdio_outbound_processing(struct qdio_q *q)
if (q->is_iqdio_q) {
/*
- * for asynchronous queues, we better check, if the fill
- * level is too high. for synchronous queues, the fill
- * level will never be that high.
+ * for asynchronous queues, we better check, if the sent
+ * buffer is already switched from PRIMED to EMPTY.
*/
- if (atomic_read(&q->number_of_buffers_used)>
- IQDIO_FILL_LEVEL_TO_POLL)
+ if ((q->queue_type == QDIO_IQDIO_QFMT_ASYNCH) &&
+ !qdio_is_outbound_q_done(q))
qdio_mark_q(q);
} else if (!q->hydra_gives_outbound_pcis)
@@ -1006,7 +1001,7 @@ qdio_outbound_processing(struct qdio_q *q)
/************************* INBOUND ROUTINES *******************************/
-static inline int
+static int
qdio_get_inbound_buffer_frontier(struct qdio_q *q)
{
struct qdio_irq *irq;
@@ -1137,20 +1132,21 @@ out:
return q->first_to_check;
}
-static inline int
+static int
qdio_has_inbound_q_moved(struct qdio_q *q)
{
int i;
-#ifdef QDIO_PERFORMANCE_STATS
static int old_pcis=0;
static int old_thinints=0;
- if ((old_pcis==perf_stats.pcis)&&(old_thinints==perf_stats.thinints))
- perf_stats.start_time_inbound=NOW;
- else
- old_pcis=perf_stats.pcis;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ if ((old_pcis==perf_stats.pcis)&&
+ (old_thinints==perf_stats.thinints))
+ perf_stats.start_time_inbound=NOW;
+ else
+ old_pcis=perf_stats.pcis;
+ }
i=qdio_get_inbound_buffer_frontier(q);
if ( (i!=GET_SAVED_FRONTIER(q)) ||
@@ -1170,7 +1166,7 @@ qdio_has_inbound_q_moved(struct qdio_q *q)
}
/* means, no more buffers to be filled */
-static inline int
+static int
tiqdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -1231,7 +1227,7 @@ tiqdio_is_inbound_q_done(struct qdio_q *q)
return 0;
}
-static inline int
+static int
qdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -1299,7 +1295,7 @@ qdio_is_inbound_q_done(struct qdio_q *q)
}
}
-static inline void
+static void
qdio_kick_inbound_handler(struct qdio_q *q)
{
int count, start, end, real_end, i;
@@ -1340,13 +1336,13 @@ qdio_kick_inbound_handler(struct qdio_q *q)
q->siga_error=0;
q->error_status_flags=0;
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
- perf_stats.inbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
+ perf_stats.inbound_cnt++;
+ }
}
-static inline void
+static void
__tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
{
struct qdio_irq *irq_ptr;
@@ -1363,9 +1359,8 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
*/
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- ii_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ ii_p_c++;
/*
* as we might just be about to stop polling, we make
* sure that we check again at least once more
@@ -1373,9 +1368,8 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
tiqdio_sched_tl();
return;
}
-#ifdef QDIO_PERFORMANCE_STATS
- ii_p_nc++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ ii_p_nc++;
if (unlikely(atomic_read(&q->is_in_shutdown))) {
qdio_unmark_q(q);
goto out;
@@ -1416,11 +1410,11 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
irq_ptr = (struct qdio_irq*)q->irq_ptr;
for (i=0;i<irq_ptr->no_output_qs;i++) {
oq = irq_ptr->output_qs[i];
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
- if (!qdio_is_outbound_q_done(oq))
+ if (!qdio_is_outbound_q_done(oq)) {
+ if (qdio_performance_stats)
+ perf_stats.tl_runs--;
__qdio_outbound_processing(oq);
+ }
}
}
@@ -1447,7 +1441,7 @@ tiqdio_inbound_processing(struct qdio_q *q)
__tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
}
-static inline void
+static void
__qdio_inbound_processing(struct qdio_q *q)
{
int q_laps=0;
@@ -1457,9 +1451,8 @@ __qdio_inbound_processing(struct qdio_q *q)
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- i_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ i_p_c++;
/* as we're sissies, we'll check next time */
if (likely(!atomic_read(&q->is_in_shutdown))) {
qdio_mark_q(q);
@@ -1467,10 +1460,10 @@ __qdio_inbound_processing(struct qdio_q *q)
}
return;
}
-#ifdef QDIO_PERFORMANCE_STATS
- i_p_nc++;
- perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ i_p_nc++;
+ perf_stats.tl_runs++;
+ }
again:
if (qdio_has_inbound_q_moved(q)) {
@@ -1499,7 +1492,7 @@ qdio_inbound_processing(struct qdio_q *q)
/************************* MAIN ROUTINES *******************************/
#ifdef QDIO_USE_PROCESSING_STATE
-static inline int
+static int
tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
{
if (!q) {
@@ -1516,9 +1509,8 @@ tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- ii_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ ii_p_c++;
/*
* as we might just be about to stop polling, we make
* sure that we check again at least once more
@@ -1552,7 +1544,7 @@ tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
}
#endif /* QDIO_USE_PROCESSING_STATE */
-static inline void
+static void
tiqdio_inbound_checks(void)
{
struct qdio_q *q;
@@ -1609,9 +1601,8 @@ tiqdio_tl(unsigned long data)
{
QDIO_DBF_TEXT4(0,trace,"iqdio_tl");
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.tl_runs++;
tiqdio_inbound_checks();
}
@@ -1832,6 +1823,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
q->sbal[j]=*(outbound_sbals_array++);
q->queue_type=q_format;
+ if ((q->queue_type == QDIO_IQDIO_QFMT) &&
+ (no_output_qs > 1) &&
+ (i == no_output_qs-1))
+ q->queue_type = QDIO_IQDIO_QFMT_ASYNCH;
q->int_parm=int_parm;
q->is_input_q=0;
q->schid = irq_ptr->schid;
@@ -1918,10 +1913,10 @@ tiqdio_thinint_handler(void)
{
QDIO_DBF_TEXT4(0,trace,"thin_int");
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.thinints++;
- perf_stats.start_time_inbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.thinints++;
+ perf_stats.start_time_inbound=NOW;
+ }
/* SVS only when needed:
* issue SVS to benefit from iqdio interrupt avoidance
@@ -1953,7 +1948,7 @@ qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state)
mb();
}
-static inline void
+static void
qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
{
char dbf_text[15];
@@ -1970,24 +1965,23 @@ qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
}
-static inline void
+static void
qdio_handle_pci(struct qdio_irq *irq_ptr)
{
int i;
struct qdio_q *q;
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.pcis++;
- perf_stats.start_time_inbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.pcis++;
+ perf_stats.start_time_inbound=NOW;
+ }
for (i=0;i<irq_ptr->no_input_qs;i++) {
q=irq_ptr->input_qs[i];
if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT)
qdio_mark_q(q);
else {
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.tl_runs--;
__qdio_inbound_processing(q);
}
}
@@ -1995,11 +1989,10 @@ qdio_handle_pci(struct qdio_irq *irq_ptr)
return;
for (i=0;i<irq_ptr->no_output_qs;i++) {
q=irq_ptr->output_qs[i];
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
if (qdio_is_outbound_q_done(q))
continue;
+ if (qdio_performance_stats)
+ perf_stats.tl_runs--;
if (!irq_ptr->sync_done_on_outb_pcis)
SYNC_MEMORY;
__qdio_outbound_processing(q);
@@ -2008,7 +2001,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr)
static void qdio_establish_handle_irq(struct ccw_device*, int, int);
-static inline void
+static void
qdio_handle_activate_check(struct ccw_device *cdev, unsigned long intparm,
int cstat, int dstat)
{
@@ -2045,11 +2038,13 @@ omit_handler_call:
}
static void
-qdio_call_shutdown(void *data)
+qdio_call_shutdown(struct work_struct *work)
{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
- cdev = (struct ccw_device *)data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
put_device(&cdev->dev);
}
@@ -2091,7 +2086,7 @@ qdio_timeout_handler(struct ccw_device *cdev)
if (get_device(&cdev->dev)) {
/* Can't call shutdown from interrupt context. */
PREPARE_WORK(&cdev->private->kick_work,
- qdio_call_shutdown, (void *)cdev);
+ qdio_call_shutdown);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
break;
@@ -2233,7 +2228,7 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags,
return cc;
}
-static inline void
+static void
qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
unsigned long token)
{
@@ -2744,7 +2739,7 @@ qdio_free(struct ccw_device *cdev)
return 0;
}
-static inline void
+static void
qdio_allocate_do_dbf(struct qdio_initialize *init_data)
{
char dbf_text[20]; /* if a printf printed out more than 8 chars */
@@ -2777,7 +2772,7 @@ qdio_allocate_do_dbf(struct qdio_initialize *init_data)
QDIO_DBF_HEX0(0,setup,&init_data->output_sbal_addr_array,sizeof(void*));
}
-static inline void
+static void
qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
{
irq_ptr->input_qs[i]->is_iqdio_q = iqfmt;
@@ -2796,7 +2791,7 @@ qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
irq_ptr->qdr->qdf0[i].dkey=QDIO_STORAGE_KEY;
}
-static inline void
+static void
qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i,
int j, int iqfmt)
{
@@ -2817,7 +2812,7 @@ qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i,
}
-static inline void
+static void
qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr)
{
int i;
@@ -2843,7 +2838,7 @@ qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr)
}
}
-static inline void
+static void
qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr)
{
int i;
@@ -2869,7 +2864,7 @@ qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr)
}
}
-static inline int
+static int
qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat,
int dstat)
{
@@ -3018,7 +3013,7 @@ qdio_allocate(struct qdio_initialize *init_data)
return 0;
}
-int qdio_fill_irq(struct qdio_initialize *init_data)
+static int qdio_fill_irq(struct qdio_initialize *init_data)
{
int i;
char dbf_text[15];
@@ -3371,7 +3366,7 @@ qdio_activate(struct ccw_device *cdev, int flags)
}
/* buffers filled forwards again to make Rick happy */
-static inline void
+static void
qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx,
unsigned int count, struct qdio_buffer *buffers)
{
@@ -3390,7 +3385,7 @@ qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx,
}
}
-static inline void
+static void
qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx,
unsigned int count, struct qdio_buffer *buffers)
{
@@ -3411,7 +3406,7 @@ qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx,
}
}
-static inline void
+static void
do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags,
unsigned int qidx, unsigned int count,
struct qdio_buffer *buffers)
@@ -3447,7 +3442,7 @@ do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags,
qdio_mark_q(q);
}
-static inline void
+static void
do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
unsigned int qidx, unsigned int count,
struct qdio_buffer *buffers)
@@ -3458,19 +3453,18 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr;
/* This is the outbound handling of queues */
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.start_time_outbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.start_time_outbound=NOW;
qdio_do_qdio_fill_output(q,qidx,count,buffers);
used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count;
if (callflags&QDIO_FLAG_DONT_SIGA) {
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
- perf_stats.outbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
+ perf_stats.outbound_cnt++;
+ }
return;
}
if (q->is_iqdio_q) {
@@ -3500,9 +3494,8 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
qdio_kick_outbound_q(q);
} else {
QDIO_DBF_TEXT3(0,trace, "fast-req");
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.fast_reqs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.fast_reqs++;
}
}
/*
@@ -3513,10 +3506,10 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
__qdio_outbound_processing(q);
}
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
- perf_stats.outbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
+ perf_stats.outbound_cnt++;
+ }
}
/* count must be 1 in iqdio */
@@ -3574,7 +3567,6 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags,
return 0;
}
-#ifdef QDIO_PERFORMANCE_STATS
static int
qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset,
int buffer_length, int *eof, void *data)
@@ -3590,29 +3582,29 @@ qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset,
_OUTP_IT("i_p_nc/c=%lu/%lu\n",i_p_nc,i_p_c);
_OUTP_IT("ii_p_nc/c=%lu/%lu\n",ii_p_nc,ii_p_c);
_OUTP_IT("o_p_nc/c=%lu/%lu\n",o_p_nc,o_p_c);
- _OUTP_IT("Number of tasklet runs (total) : %u\n",
+ _OUTP_IT("Number of tasklet runs (total) : %lu\n",
perf_stats.tl_runs);
_OUTP_IT("\n");
- _OUTP_IT("Number of SIGA sync's issued : %u\n",
+ _OUTP_IT("Number of SIGA sync's issued : %lu\n",
perf_stats.siga_syncs);
- _OUTP_IT("Number of SIGA in's issued : %u\n",
+ _OUTP_IT("Number of SIGA in's issued : %lu\n",
perf_stats.siga_ins);
- _OUTP_IT("Number of SIGA out's issued : %u\n",
+ _OUTP_IT("Number of SIGA out's issued : %lu\n",
perf_stats.siga_outs);
- _OUTP_IT("Number of PCIs caught : %u\n",
+ _OUTP_IT("Number of PCIs caught : %lu\n",
perf_stats.pcis);
- _OUTP_IT("Number of adapter interrupts caught : %u\n",
+ _OUTP_IT("Number of adapter interrupts caught : %lu\n",
perf_stats.thinints);
- _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %u\n",
+ _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %lu\n",
perf_stats.fast_reqs);
_OUTP_IT("\n");
- _OUTP_IT("Total time of all inbound actions (us) incl. UL : %u\n",
+ _OUTP_IT("Total time of all inbound actions (us) incl. UL : %lu\n",
perf_stats.inbound_time);
- _OUTP_IT("Number of inbound transfers : %u\n",
+ _OUTP_IT("Number of inbound transfers : %lu\n",
perf_stats.inbound_cnt);
- _OUTP_IT("Total time of all outbound do_QDIOs (us) : %u\n",
+ _OUTP_IT("Total time of all outbound do_QDIOs (us) : %lu\n",
perf_stats.outbound_time);
- _OUTP_IT("Number of do_QDIOs outbound : %u\n",
+ _OUTP_IT("Number of do_QDIOs outbound : %lu\n",
perf_stats.outbound_cnt);
_OUTP_IT("\n");
@@ -3620,12 +3612,10 @@ qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset,
}
static struct proc_dir_entry *qdio_perf_proc_file;
-#endif /* QDIO_PERFORMANCE_STATS */
static void
qdio_add_procfs_entry(void)
{
-#ifdef QDIO_PERFORMANCE_STATS
proc_perf_file_registration=0;
qdio_perf_proc_file=create_proc_entry(QDIO_PERF,
S_IFREG|0444,&proc_root);
@@ -3637,20 +3627,58 @@ qdio_add_procfs_entry(void)
QDIO_PRINT_WARN("was not able to register perf. " \
"proc-file (%i).\n",
proc_perf_file_registration);
-#endif /* QDIO_PERFORMANCE_STATS */
}
static void
qdio_remove_procfs_entry(void)
{
-#ifdef QDIO_PERFORMANCE_STATS
perf_stats.tl_runs=0;
if (!proc_perf_file_registration) /* means if it went ok earlier */
remove_proc_entry(QDIO_PERF,&proc_root);
-#endif /* QDIO_PERFORMANCE_STATS */
}
+/**
+ * attributes in sysfs
+ *****************************************************************************/
+
+static ssize_t
+qdio_performance_stats_show(struct bus_type *bus, char *buf)
+{
+ return sprintf(buf, "%i\n", qdio_performance_stats ? 1 : 0);
+}
+
+static ssize_t
+qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count)
+{
+ char *tmp;
+ int i;
+
+ i = simple_strtoul(buf, &tmp, 16);
+ if ((i == 0) || (i == 1)) {
+ if (i == qdio_performance_stats)
+ return count;
+ qdio_performance_stats = i;
+ if (i==0) {
+ /* reset perf. stat. info */
+ i_p_nc = 0;
+ i_p_c = 0;
+ ii_p_nc = 0;
+ ii_p_c = 0;
+ o_p_nc = 0;
+ o_p_c = 0;
+ memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
+ }
+ } else {
+ QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
+ return -EINVAL;
+ }
+ return count;
+}
+
+static BUS_ATTR(qdio_performance_stats, 0644, qdio_performance_stats_show,
+ qdio_performance_stats_store);
+
static void
tiqdio_register_thinints(void)
{
@@ -3695,6 +3723,7 @@ qdio_release_qdio_memory(void)
kfree(indicators);
}
+
static void
qdio_unregister_dbf_views(void)
{
@@ -3796,9 +3825,7 @@ static int __init
init_QDIO(void)
{
int res;
-#ifdef QDIO_PERFORMANCE_STATS
void *ptr;
-#endif /* QDIO_PERFORMANCE_STATS */
printk("qdio: loading %s\n",version);
@@ -3811,13 +3838,12 @@ init_QDIO(void)
return res;
QDIO_DBF_TEXT0(0,setup,"initQDIO");
+ res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
-#ifdef QDIO_PERFORMANCE_STATS
- memset((void*)&perf_stats,0,sizeof(perf_stats));
+ memset((void*)&perf_stats,0,sizeof(perf_stats));
QDIO_DBF_TEXT0(0,setup,"perfstat");
ptr=&perf_stats;
QDIO_DBF_HEX0(0,setup,&ptr,sizeof(void*));
-#endif /* QDIO_PERFORMANCE_STATS */
qdio_add_procfs_entry();
@@ -3841,7 +3867,7 @@ cleanup_QDIO(void)
qdio_release_qdio_memory();
qdio_unregister_dbf_views();
mempool_destroy(qdio_mempool_scssc);
-
+ bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
printk("qdio: %s: module removed\n",version);
}
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 42927c1b745..ec9af72b2af 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -12,10 +12,6 @@
#endif /* CONFIG_QDIO_DEBUG */
#define QDIO_USE_PROCESSING_STATE
-#ifdef CONFIG_QDIO_PERF_STATS
-#define QDIO_PERFORMANCE_STATS
-#endif /* CONFIG_QDIO_PERF_STATS */
-
#define QDIO_MINIMAL_BH_RELIEF_TIME 16
#define QDIO_TIMER_POLL_VALUE 1
#define IQDIO_TIMER_POLL_VALUE 1
@@ -409,25 +405,23 @@ do_clear_global_summary(void)
#define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08
#define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04
-#ifdef QDIO_PERFORMANCE_STATS
struct qdio_perf_stats {
- unsigned int tl_runs;
+ unsigned long tl_runs;
- unsigned int siga_outs;
- unsigned int siga_ins;
- unsigned int siga_syncs;
- unsigned int pcis;
- unsigned int thinints;
- unsigned int fast_reqs;
+ unsigned long siga_outs;
+ unsigned long siga_ins;
+ unsigned long siga_syncs;
+ unsigned long pcis;
+ unsigned long thinints;
+ unsigned long fast_reqs;
__u64 start_time_outbound;
- unsigned int outbound_cnt;
- unsigned int outbound_time;
+ unsigned long outbound_cnt;
+ unsigned long outbound_time;
__u64 start_time_inbound;
- unsigned int inbound_cnt;
- unsigned int inbound_time;
+ unsigned long inbound_cnt;
+ unsigned long inbound_time;
};
-#endif /* QDIO_PERFORMANCE_STATS */
/* unlikely as the later the better */
#define SYNC_MEMORY if (unlikely(q->siga_sync)) qdio_siga_sync_q(q)
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index e4dc947e74e..c7d1355237b 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -33,6 +33,7 @@
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <asm/s390_rdev.h>
+#include <asm/reset.h>
#include "ap_bus.h"
@@ -464,7 +465,7 @@ static int ap_device_probe(struct device *dev)
* Flush all requests from the request/pending queue of an AP device.
* @ap_dev: pointer to the AP device.
*/
-static inline void __ap_flush_queue(struct ap_device *ap_dev)
+static void __ap_flush_queue(struct ap_device *ap_dev)
{
struct ap_message *ap_msg, *next;
@@ -586,7 +587,7 @@ static struct bus_attribute *const ap_bus_attrs[] = {
/**
* Pick one of the 16 ap domains.
*/
-static inline int ap_select_domain(void)
+static int ap_select_domain(void)
{
int queue_depth, device_type, count, max_count, best_domain;
int rc, i, j;
@@ -824,7 +825,7 @@ static inline void ap_schedule_poll_timer(void)
* required, bit 2^1 is set if the poll timer needs to get armed
* Returns 0 if the device is still present, -ENODEV if not.
*/
-static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
{
struct ap_queue_status status;
struct ap_message *ap_msg;
@@ -871,7 +872,7 @@ static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
* required, bit 2^1 is set if the poll timer needs to get armed
* Returns 0 if the device is still present, -ENODEV if not.
*/
-static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
{
struct ap_queue_status status;
struct ap_message *ap_msg;
@@ -1128,6 +1129,27 @@ static void ap_poll_thread_stop(void)
mutex_unlock(&ap_poll_thread_mutex);
}
+static void ap_reset_domain(void)
+{
+ int i;
+
+ for (i = 0; i < AP_DEVICES; i++)
+ ap_reset_queue(AP_MKQID(i, ap_domain_index));
+}
+
+static void ap_reset_all(void)
+{
+ int i, j;
+
+ for (i = 0; i < AP_DOMAINS; i++)
+ for (j = 0; j < AP_DEVICES; j++)
+ ap_reset_queue(AP_MKQID(j, i));
+}
+
+static struct reset_call ap_reset_call = {
+ .fn = ap_reset_all,
+};
+
/**
* The module initialization code.
*/
@@ -1144,6 +1166,7 @@ int __init ap_module_init(void)
printk(KERN_WARNING "AP instructions not installed.\n");
return -ENODEV;
}
+ register_reset_call(&ap_reset_call);
/* Create /sys/bus/ap. */
rc = bus_register(&ap_bus_type);
@@ -1197,6 +1220,7 @@ out_bus:
bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
bus_unregister(&ap_bus_type);
out:
+ unregister_reset_call(&ap_reset_call);
return rc;
}
@@ -1213,10 +1237,12 @@ void ap_module_exit(void)
int i;
struct device *dev;
+ ap_reset_domain();
ap_poll_thread_stop();
del_timer_sync(&ap_config_timer);
del_timer_sync(&ap_poll_timer);
destroy_workqueue(ap_work_queue);
+ tasklet_kill(&ap_tasklet);
s390_root_dev_unregister(ap_root_device);
while ((dev = bus_find_device(&ap_bus_type, NULL, NULL,
__ap_match_all)))
@@ -1227,6 +1253,7 @@ void ap_module_exit(void)
for (i = 0; ap_bus_attrs[i]; i++)
bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
bus_unregister(&ap_bus_type);
+ unregister_reset_call(&ap_reset_call);
}
#ifndef CONFIG_ZCRYPT_MONOLITHIC
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 1edc10a7a6f..b9e59bc9435 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -791,7 +791,7 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
return rc;
}
-long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
+static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
if (cmd == ICARSAMODEXPO)
@@ -833,8 +833,8 @@ static struct miscdevice zcrypt_misc_device = {
*/
static struct proc_dir_entry *zcrypt_entry;
-static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
- unsigned int len)
+static int sprintcl(unsigned char *outaddr, unsigned char *addr,
+ unsigned int len)
{
int hl, i;
@@ -845,8 +845,8 @@ static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
return hl;
}
-static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
- unsigned int len)
+static int sprintrw(unsigned char *outaddr, unsigned char *addr,
+ unsigned int len)
{
int hl, inl, c, cx;
@@ -865,8 +865,8 @@ static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
return hl;
}
-static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
- unsigned char *addr, unsigned int len)
+static int sprinthx(unsigned char *title, unsigned char *outaddr,
+ unsigned char *addr, unsigned int len)
{
int hl, inl, r, rx;
@@ -885,8 +885,8 @@ static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
return hl;
}
-static inline int sprinthx4(unsigned char *title, unsigned char *outaddr,
- unsigned int *array, unsigned int len)
+static int sprinthx4(unsigned char *title, unsigned char *outaddr,
+ unsigned int *array, unsigned int len)
{
int hl, r;
@@ -943,7 +943,7 @@ static int zcrypt_status_read(char *resp_buff, char **start, off_t offset,
zcrypt_qdepth_mask(workarea);
len += sprinthx("Waiting work element counts",
resp_buff+len, workarea, AP_DEVICES);
- zcrypt_perdev_reqcnt((unsigned int *) workarea);
+ zcrypt_perdev_reqcnt((int *) workarea);
len += sprinthx4("Per-device successfully completed request counts",
resp_buff+len,(unsigned int *) workarea, AP_DEVICES);
*eof = 1;
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index a62b00083d0..5bb13a9d089 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -295,7 +295,7 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
struct completion work;
int rc;
- ap_msg.message = (void *) kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
@@ -337,7 +337,7 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
struct completion work;
int rc;
- ap_msg.message = (void *) kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c
index b6a4ecdc802..818ffe05ac0 100644
--- a/drivers/s390/crypto/zcrypt_pcica.c
+++ b/drivers/s390/crypto/zcrypt_pcica.c
@@ -191,10 +191,10 @@ static int ICACRT_msg_to_type4CRT_msg(struct zcrypt_device *zdev,
*
* Returns 0 on success or -EFAULT.
*/
-static inline int convert_type84(struct zcrypt_device *zdev,
- struct ap_message *reply,
- char __user *outputdata,
- unsigned int outputdatalength)
+static int convert_type84(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
{
struct type84_hdr *t84h = reply->message;
char *data;
@@ -279,7 +279,7 @@ static long zcrypt_pcica_modexpo(struct zcrypt_device *zdev,
struct completion work;
int rc;
- ap_msg.message = (void *) kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
@@ -321,7 +321,7 @@ static long zcrypt_pcica_modexpo_crt(struct zcrypt_device *zdev,
struct completion work;
int rc;
- ap_msg.message = (void *) kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 2da8b938140..252443b6bd1 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -709,7 +709,8 @@ out_free:
* PCIXCC/CEX2C device to the request distributor
* @xcRB: pointer to the send_cprb request buffer
*/
-long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB)
+static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,
+ struct ica_xcRB *xcRB)
{
struct ap_message ap_msg;
struct response_type resp_type = {
@@ -717,7 +718,7 @@ long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB)
};
int rc;
- ap_msg.message = (void *) kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
+ ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
if (!ap_msg.message)
return -ENOMEM;
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 1a93fa684e9..f98fa465df0 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -22,16 +22,6 @@ config CTC
available. This option is also available as a module which will be
called ctc.ko. If you do not know what it is, it's safe to say "Y".
-config IUCV
- tristate "IUCV support (VM only)"
- help
- Select this option if you want to use inter-user communication
- under VM or VIF. If unsure, say "Y" to enable a fast communication
- link between VM guests. At boot time the user ID of the guest needs
- to be passed to the kernel. Note that both kernels need to be
- compiled with this option and both need to be booted with the user ID
- of the other VM guest.
-
config NETIUCV
tristate "IUCV network device support (VM only)"
depends on IUCV && NETDEVICES
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index 4777e36a922..bbe3ab2e93d 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -4,7 +4,6 @@
ctc-objs := ctcmain.o ctcdbug.o
-obj-$(CONFIG_IUCV) += iucv.o
obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 95f4e105cb9..7809a79feec 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -121,7 +121,7 @@ MODULE_LICENSE("GPL");
#define DEBUG
#endif
- char debug_buffer[255];
+static char debug_buffer[255];
/**
* Debug Facility Stuff
*/
@@ -223,16 +223,14 @@ static void claw_timer ( struct chbk * p_ch );
/* Functions */
static int add_claw_reads(struct net_device *dev,
struct ccwbk* p_first, struct ccwbk* p_last);
-static void inline ccw_check_return_code (struct ccw_device *cdev,
- int return_code);
-static void inline ccw_check_unit_check (struct chbk * p_ch,
- unsigned char sense );
+static void ccw_check_return_code (struct ccw_device *cdev, int return_code);
+static void ccw_check_unit_check (struct chbk * p_ch, unsigned char sense );
static int find_link(struct net_device *dev, char *host_name, char *ws_name );
static int claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid);
static int init_ccw_bk(struct net_device *dev);
static void probe_error( struct ccwgroup_device *cgdev);
static struct net_device_stats *claw_stats(struct net_device *dev);
-static int inline pages_to_order_of_mag(int num_of_pages);
+static int pages_to_order_of_mag(int num_of_pages);
static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr);
#ifdef DEBUG
static void dumpit (char *buf, int len);
@@ -1310,7 +1308,7 @@ claw_timer ( struct chbk * p_ch )
* of magnitude get_free_pages() has an upper order of 9 *
*--------------------------------------------------------------------*/
-static int inline
+static int
pages_to_order_of_mag(int num_of_pages)
{
int order_of_mag=1; /* assume 2 pages */
@@ -1482,7 +1480,7 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first,
* *
*-------------------------------------------------------------------*/
-static void inline
+static void
ccw_check_return_code(struct ccw_device *cdev, int return_code)
{
#ifdef FUNCTRACE
@@ -1529,7 +1527,7 @@ ccw_check_return_code(struct ccw_device *cdev, int return_code)
* ccw_check_unit_check *
*--------------------------------------------------------------------*/
-static void inline
+static void
ccw_check_unit_check(struct chbk * p_ch, unsigned char sense )
{
struct net_device *dev = p_ch->ndev;
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index 3257c22dd79..5a84fbbc661 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -369,7 +369,7 @@ ctc_dump_skb(struct sk_buff *skb, int offset)
* @param ch The channel where this skb has been received.
* @param pskb The received skb.
*/
-static __inline__ void
+static void
ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
{
struct net_device *dev = ch->netdev;
@@ -512,7 +512,7 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
* @param ch The channel, the error belongs to.
* @param return_code The error code to inspect.
*/
-static void inline
+static void
ccw_check_return_code(struct channel *ch, int return_code, char *msg)
{
DBF_TEXT(trace, 5, __FUNCTION__);
@@ -547,7 +547,7 @@ ccw_check_return_code(struct channel *ch, int return_code, char *msg)
* @param ch The channel, the sense code belongs to.
* @param sense The sense code to inspect.
*/
-static void inline
+static void
ccw_unit_check(struct channel *ch, unsigned char sense)
{
DBF_TEXT(trace, 5, __FUNCTION__);
@@ -603,7 +603,7 @@ ctc_purge_skb_queue(struct sk_buff_head *q)
}
}
-static __inline__ int
+static int
ctc_checkalloc_buffer(struct channel *ch, int warn)
{
DBF_TEXT(trace, 5, __FUNCTION__);
@@ -1646,7 +1646,7 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
return -1;
}
memset(ch, 0, sizeof (struct channel));
- if ((ch->ccw = (struct ccw1 *) kmalloc(8*sizeof(struct ccw1),
+ if ((ch->ccw = kmalloc(8*sizeof(struct ccw1),
GFP_KERNEL | GFP_DMA)) == NULL) {
kfree(ch);
ctc_pr_warn("ctc: Out of memory in add_channel\n");
@@ -1693,7 +1693,7 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
return -1;
}
fsm_newstate(ch->fsm, CH_STATE_IDLE);
- if ((ch->irb = (struct irb *) kmalloc(sizeof (struct irb),
+ if ((ch->irb = kmalloc(sizeof (struct irb),
GFP_KERNEL)) == NULL) {
ctc_pr_warn("ctc: Out of memory in add_channel\n");
kfree_fsm(ch->fsm);
@@ -2535,7 +2535,7 @@ ctc_print_statistics(struct ctc_priv *priv)
DBF_TEXT(trace, 4, __FUNCTION__);
if (!priv)
return;
- sbuf = (char *)kmalloc(2048, GFP_KERNEL);
+ sbuf = kmalloc(2048, GFP_KERNEL);
if (sbuf == NULL)
return;
p = sbuf;
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
index e965f03a729..76728ae4b84 100644
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -57,7 +57,7 @@ static struct ccw_device_id cu3088_ids[] = {
static struct ccw_driver cu3088_driver;
-struct device *cu3088_root_dev;
+static struct device *cu3088_root_dev;
static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count)
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
deleted file mode 100644
index 1476ce2b437..00000000000
--- a/drivers/s390/net/iucv.c
+++ /dev/null
@@ -1,2540 +0,0 @@
-/*
- * IUCV network driver
- *
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s):
- * Original source:
- * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000
- * Xenia Tkatschow (xenia@us.ibm.com)
- * 2Gb awareness and general cleanup:
- * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
- *
- * Documentation used:
- * The original source
- * CP Programming Service, IBM document # SC24-5760
- *
- * This program is free software; you can redistribute 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.
- *
- */
-
-/* #define DEBUG */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <asm/atomic.h>
-#include "iucv.h"
-#include <asm/io.h>
-#include <asm/s390_ext.h>
-#include <asm/ebcdic.h>
-#include <asm/smp.h>
-#include <asm/s390_rdev.h>
-
-/* FLAGS:
- * All flags are defined in the field IPFLAGS1 of each function
- * and can be found in CP Programming Services.
- * IPSRCCLS - Indicates you have specified a source class
- * IPFGMCL - Indicates you have specified a target class
- * IPFGPID - Indicates you have specified a pathid
- * IPFGMID - Indicates you have specified a message ID
- * IPANSLST - Indicates that you are using an address list for
- * reply data
- * IPBUFLST - Indicates that you are using an address list for
- * message data
- */
-
-#define IPSRCCLS 0x01
-#define IPFGMCL 0x01
-#define IPFGPID 0x02
-#define IPFGMID 0x04
-#define IPANSLST 0x08
-#define IPBUFLST 0x40
-
-static int
-iucv_bus_match (struct device *dev, struct device_driver *drv)
-{
- return 0;
-}
-
-struct bus_type iucv_bus = {
- .name = "iucv",
- .match = iucv_bus_match,
-};
-
-struct device *iucv_root;
-
-/* General IUCV interrupt structure */
-typedef struct {
- __u16 ippathid;
- __u8 res1;
- __u8 iptype;
- __u32 res2;
- __u8 ipvmid[8];
- __u8 res3[24];
-} iucv_GeneralInterrupt;
-
-static iucv_GeneralInterrupt *iucv_external_int_buffer = NULL;
-
-/* Spin Lock declaration */
-
-static DEFINE_SPINLOCK(iucv_lock);
-
-static int messagesDisabled = 0;
-
-/***************INTERRUPT HANDLING ***************/
-
-typedef struct {
- struct list_head queue;
- iucv_GeneralInterrupt data;
-} iucv_irqdata;
-
-static struct list_head iucv_irq_queue;
-static DEFINE_SPINLOCK(iucv_irq_queue_lock);
-
-/*
- *Internal function prototypes
- */
-static void iucv_tasklet_handler(unsigned long);
-static void iucv_irq_handler(__u16);
-
-static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0);
-
-/************ FUNCTION ID'S ****************************/
-
-#define ACCEPT 10
-#define CONNECT 11
-#define DECLARE_BUFFER 12
-#define PURGE 9
-#define QUERY 0
-#define QUIESCE 13
-#define RECEIVE 5
-#define REJECT 8
-#define REPLY 6
-#define RESUME 14
-#define RETRIEVE_BUFFER 2
-#define SEND 4
-#define SETMASK 16
-#define SEVER 15
-
-/**
- * Structure: handler
- * members: list - list management.
- * structure: id
- * userid - 8 char array of machine identification
- * user_data - 16 char array for user identification
- * mask - 24 char array used to compare the 2 previous
- * interrupt_table - vector of interrupt functions.
- * pgm_data - ulong, application data that is passed
- * to the interrupt handlers
-*/
-typedef struct handler_t {
- struct list_head list;
- struct {
- __u8 userid[8];
- __u8 user_data[16];
- __u8 mask[24];
- } id;
- iucv_interrupt_ops_t *interrupt_table;
- void *pgm_data;
-} handler;
-
-/**
- * iucv_handler_table: List of registered handlers.
- */
-static struct list_head iucv_handler_table;
-
-/**
- * iucv_pathid_table: an array of *handler pointing into
- * iucv_handler_table for fast indexing by pathid;
- */
-static handler **iucv_pathid_table;
-
-static unsigned long max_connections;
-
-/**
- * iucv_cpuid: contains the logical cpu number of the cpu which
- * has declared the iucv buffer by issuing DECLARE_BUFFER.
- * If no cpu has done the initialization iucv_cpuid contains -1.
- */
-static int iucv_cpuid = -1;
-/**
- * register_flag: is 0 when external interrupt has not been registered
- */
-static int register_flag;
-
-/****************FIVE 40-BYTE PARAMETER STRUCTURES******************/
-/* Data struct 1: iparml_control
- * Used for iucv_accept
- * iucv_connect
- * iucv_quiesce
- * iucv_resume
- * iucv_sever
- * iucv_retrieve_buffer
- * Data struct 2: iparml_dpl (data in parameter list)
- * Used for iucv_send_prmmsg
- * iucv_send2way_prmmsg
- * iucv_send2way_prmmsg_array
- * iucv_reply_prmmsg
- * Data struct 3: iparml_db (data in a buffer)
- * Used for iucv_receive
- * iucv_receive_array
- * iucv_reject
- * iucv_reply
- * iucv_reply_array
- * iucv_send
- * iucv_send_array
- * iucv_send2way
- * iucv_send2way_array
- * iucv_declare_buffer
- * Data struct 4: iparml_purge
- * Used for iucv_purge
- * iucv_query
- * Data struct 5: iparml_set_mask
- * Used for iucv_set_mask
- */
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u16 ipmsglim;
- __u16 res1;
- __u8 ipvmid[8];
- __u8 ipuser[16];
- __u8 iptarget[8];
-} iparml_control;
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u32 ipmsgid;
- __u32 iptrgcls;
- __u8 iprmmsg[8];
- __u32 ipsrccls;
- __u32 ipmsgtag;
- __u32 ipbfadr2;
- __u32 ipbfln2f;
- __u32 res;
-} iparml_dpl;
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u32 ipmsgid;
- __u32 iptrgcls;
- __u32 ipbfadr1;
- __u32 ipbfln1f;
- __u32 ipsrccls;
- __u32 ipmsgtag;
- __u32 ipbfadr2;
- __u32 ipbfln2f;
- __u32 res;
-} iparml_db;
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u32 ipmsgid;
- __u8 ipaudit[3];
- __u8 res1[5];
- __u32 res2;
- __u32 ipsrccls;
- __u32 ipmsgtag;
- __u32 res3[3];
-} iparml_purge;
-
-typedef struct {
- __u8 ipmask;
- __u8 res1[2];
- __u8 iprcode;
- __u32 res2[9];
-} iparml_set_mask;
-
-typedef struct {
- union {
- iparml_control p_ctrl;
- iparml_dpl p_dpl;
- iparml_db p_db;
- iparml_purge p_purge;
- iparml_set_mask p_set_mask;
- } param;
- atomic_t in_use;
- __u32 res;
-} __attribute__ ((aligned(8))) iucv_param;
-#define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param))
-
-static iucv_param * iucv_param_pool;
-
-MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
-MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");
-MODULE_LICENSE("GPL");
-
-/*
- * Debugging stuff
- *******************************************************************************/
-
-
-#ifdef DEBUG
-static int debuglevel = 0;
-
-module_param(debuglevel, int, 0);
-MODULE_PARM_DESC(debuglevel,
- "Specifies the debug level (0=off ... 3=all)");
-
-static void
-iucv_dumpit(char *title, void *buf, int len)
-{
- int i;
- __u8 *p = (__u8 *)buf;
-
- if (debuglevel < 3)
- return;
-
- printk(KERN_DEBUG "%s\n", title);
- printk(" ");
- for (i = 0; i < len; i++) {
- if (!(i % 16) && i != 0)
- printk ("\n ");
- else if (!(i % 4) && i != 0)
- printk(" ");
- printk("%02X", *p++);
- }
- if (len % 16)
- printk ("\n");
- return;
-}
-#define iucv_debug(lvl, fmt, args...) \
-do { \
- if (debuglevel >= lvl) \
- printk(KERN_DEBUG "%s: " fmt "\n", __FUNCTION__ , ## args); \
-} while (0)
-
-#else
-
-#define iucv_debug(lvl, fmt, args...) do { } while (0)
-#define iucv_dumpit(title, buf, len) do { } while (0)
-
-#endif
-
-/*
- * Internal functions
- *******************************************************************************/
-
-/**
- * print start banner
- */
-static void
-iucv_banner(void)
-{
- printk(KERN_INFO "IUCV lowlevel driver initialized\n");
-}
-
-/**
- * iucv_init - Initialization
- *
- * Allocates and initializes various data structures.
- */
-static int
-iucv_init(void)
-{
- int ret;
-
- if (iucv_external_int_buffer)
- return 0;
-
- if (!MACHINE_IS_VM) {
- printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n");
- return -EPROTONOSUPPORT;
- }
-
- ret = bus_register(&iucv_bus);
- if (ret) {
- printk(KERN_ERR "IUCV: failed to register bus.\n");
- return ret;
- }
-
- iucv_root = s390_root_dev_register("iucv");
- if (IS_ERR(iucv_root)) {
- printk(KERN_ERR "IUCV: failed to register iucv root.\n");
- bus_unregister(&iucv_bus);
- return PTR_ERR(iucv_root);
- }
-
- /* Note: GFP_DMA used used to get memory below 2G */
- iucv_external_int_buffer = kzalloc(sizeof(iucv_GeneralInterrupt),
- GFP_KERNEL|GFP_DMA);
- if (!iucv_external_int_buffer) {
- printk(KERN_WARNING
- "%s: Could not allocate external interrupt buffer\n",
- __FUNCTION__);
- s390_root_dev_unregister(iucv_root);
- bus_unregister(&iucv_bus);
- return -ENOMEM;
- }
-
- /* Initialize parameter pool */
- iucv_param_pool = kzalloc(sizeof(iucv_param) * PARAM_POOL_SIZE,
- GFP_KERNEL|GFP_DMA);
- if (!iucv_param_pool) {
- printk(KERN_WARNING "%s: Could not allocate param pool\n",
- __FUNCTION__);
- kfree(iucv_external_int_buffer);
- iucv_external_int_buffer = NULL;
- s390_root_dev_unregister(iucv_root);
- bus_unregister(&iucv_bus);
- return -ENOMEM;
- }
-
- /* Initialize irq queue */
- INIT_LIST_HEAD(&iucv_irq_queue);
-
- /* Initialize handler table */
- INIT_LIST_HEAD(&iucv_handler_table);
-
- iucv_banner();
- return 0;
-}
-
-/**
- * iucv_exit - De-Initialization
- *
- * Frees everything allocated from iucv_init.
- */
-static int iucv_retrieve_buffer (void);
-
-static void
-iucv_exit(void)
-{
- iucv_retrieve_buffer();
- kfree(iucv_external_int_buffer);
- iucv_external_int_buffer = NULL;
- kfree(iucv_param_pool);
- iucv_param_pool = NULL;
- s390_root_dev_unregister(iucv_root);
- bus_unregister(&iucv_bus);
- printk(KERN_INFO "IUCV lowlevel driver unloaded\n");
-}
-
-/**
- * grab_param: - Get a parameter buffer from the pre-allocated pool.
- *
- * This function searches for an unused element in the pre-allocated pool
- * of parameter buffers. If one is found, it marks it "in use" and returns
- * a pointer to it. The calling function is responsible for releasing it
- * when it has finished its usage.
- *
- * Returns: A pointer to iucv_param.
- */
-static __inline__ iucv_param *
-grab_param(void)
-{
- iucv_param *ptr;
- static int hint = 0;
-
- ptr = iucv_param_pool + hint;
- do {
- ptr++;
- if (ptr >= iucv_param_pool + PARAM_POOL_SIZE)
- ptr = iucv_param_pool;
- } while (atomic_cmpxchg(&ptr->in_use, 0, 1) != 0);
- hint = ptr - iucv_param_pool;
-
- memset(&ptr->param, 0, sizeof(ptr->param));
- return ptr;
-}
-
-/**
- * release_param - Release a parameter buffer.
- * @p: A pointer to a struct iucv_param, previously obtained by calling
- * grab_param().
- *
- * This function marks the specified parameter buffer "unused".
- */
-static __inline__ void
-release_param(void *p)
-{
- atomic_set(&((iucv_param *)p)->in_use, 0);
-}
-
-/**
- * iucv_add_handler: - Add a new handler
- * @new_handler: handle that is being entered into chain.
- *
- * Places new handle on iucv_handler_table, if identical handler is not
- * found.
- *
- * Returns: 0 on success, !0 on failure (handler already in chain).
- */
-static int
-iucv_add_handler (handler *new)
-{
- ulong flags;
-
- iucv_debug(1, "entering");
- iucv_dumpit("handler:", new, sizeof(handler));
-
- spin_lock_irqsave (&iucv_lock, flags);
- if (!list_empty(&iucv_handler_table)) {
- struct list_head *lh;
-
- /**
- * Search list for handler with identical id. If one
- * is found, the new handler is _not_ added.
- */
- list_for_each(lh, &iucv_handler_table) {
- handler *h = list_entry(lh, handler, list);
- if (!memcmp(&new->id, &h->id, sizeof(h->id))) {
- iucv_debug(1, "ret 1");
- spin_unlock_irqrestore (&iucv_lock, flags);
- return 1;
- }
- }
- }
- /**
- * If we get here, no handler was found.
- */
- INIT_LIST_HEAD(&new->list);
- list_add(&new->list, &iucv_handler_table);
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- iucv_debug(1, "exiting");
- return 0;
-}
-
-/**
- * b2f0:
- * @code: identifier of IUCV call to CP.
- * @parm: pointer to 40 byte iparml area passed to CP
- *
- * Calls CP to execute IUCV commands.
- *
- * Returns: return code from CP's IUCV call
- */
-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));
-
- 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));
-
- return (unsigned long)*((__u8 *)(parm + 3));
-}
-
-/*
- * Name: iucv_add_pathid
- * Purpose: Adds a path id to the system.
- * Input: pathid - pathid that is going to be entered into system
- * handle - address of handler that the pathid will be associated
- * with.
- * pgm_data - token passed in by application.
- * Output: 0: successful addition of pathid
- * - EINVAL - pathid entry is being used by another application
- * - ENOMEM - storage allocation for a new pathid table failed
-*/
-static int
-__iucv_add_pathid(__u16 pathid, handler *handler)
-{
-
- iucv_debug(1, "entering");
-
- iucv_debug(1, "handler is pointing to %p", handler);
-
- if (pathid > (max_connections - 1))
- return -EINVAL;
-
- if (iucv_pathid_table[pathid]) {
- iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]);
- printk(KERN_WARNING
- "%s: Pathid being used, error.\n", __FUNCTION__);
- return -EINVAL;
- }
- iucv_pathid_table[pathid] = handler;
-
- iucv_debug(1, "exiting");
- return 0;
-} /* end of add_pathid function */
-
-static int
-iucv_add_pathid(__u16 pathid, handler *handler)
-{
- ulong flags;
- int rc;
-
- spin_lock_irqsave (&iucv_lock, flags);
- rc = __iucv_add_pathid(pathid, handler);
- spin_unlock_irqrestore (&iucv_lock, flags);
- return rc;
-}
-
-static void
-iucv_remove_pathid(__u16 pathid)
-{
- ulong flags;
-
- if (pathid > (max_connections - 1))
- return;
-
- spin_lock_irqsave (&iucv_lock, flags);
- iucv_pathid_table[pathid] = NULL;
- spin_unlock_irqrestore (&iucv_lock, flags);
-}
-
-/**
- * iucv_declare_buffer_cpuid
- * Register at VM for subsequent IUCV operations. This is executed
- * on the reserved CPU iucv_cpuid. Called from iucv_declare_buffer().
- */
-static void
-iucv_declare_buffer_cpuid (void *result)
-{
- iparml_db *parm;
-
- parm = (iparml_db *)grab_param();
- parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer);
- if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1)
- *((ulong *)result) = parm->iprcode;
- release_param(parm);
-}
-
-/**
- * iucv_retrieve_buffer_cpuid:
- * Unregister IUCV usage at VM. This is always executed on the same
- * cpu that registered the buffer to VM.
- * Called from iucv_retrieve_buffer().
- */
-static void
-iucv_retrieve_buffer_cpuid (void *cpu)
-{
- iparml_control *parm;
-
- parm = (iparml_control *)grab_param();
- b2f0(RETRIEVE_BUFFER, parm);
- release_param(parm);
-}
-
-/**
- * Name: iucv_declare_buffer
- * Purpose: Specifies the guests real address of an external
- * interrupt.
- * Input: void
- * Output: iprcode - return code from b2f0 call
- */
-static int
-iucv_declare_buffer (void)
-{
- unsigned long flags;
- ulong b2f0_result;
-
- iucv_debug(1, "entering");
- b2f0_result = -ENODEV;
- spin_lock_irqsave (&iucv_lock, flags);
- if (iucv_cpuid == -1) {
- /* Reserve any cpu for use by iucv. */
- iucv_cpuid = smp_get_cpu(CPU_MASK_ALL);
- spin_unlock_irqrestore (&iucv_lock, flags);
- smp_call_function_on(iucv_declare_buffer_cpuid,
- &b2f0_result, 0, 1, iucv_cpuid);
- if (b2f0_result) {
- smp_put_cpu(iucv_cpuid);
- iucv_cpuid = -1;
- }
- iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer);
- } else {
- spin_unlock_irqrestore (&iucv_lock, flags);
- b2f0_result = 0;
- }
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_retrieve_buffer:
- *
- * Terminates all use of IUCV.
- * Returns: return code from CP
- */
-static int
-iucv_retrieve_buffer (void)
-{
- iucv_debug(1, "entering");
- if (iucv_cpuid != -1) {
- smp_call_function_on(iucv_retrieve_buffer_cpuid,
- NULL, 0, 1, iucv_cpuid);
- /* Release the cpu reserved by iucv_declare_buffer. */
- smp_put_cpu(iucv_cpuid);
- iucv_cpuid = -1;
- }
- iucv_debug(1, "exiting");
- return 0;
-}
-
-/**
- * iucv_remove_handler:
- * @users_handler: handler to be removed
- *
- * Remove handler when application unregisters.
- */
-static void
-iucv_remove_handler(handler *handler)
-{
- unsigned long flags;
-
- if ((!iucv_pathid_table) || (!handler))
- return;
-
- iucv_debug(1, "entering");
-
- spin_lock_irqsave (&iucv_lock, flags);
- list_del(&handler->list);
- if (list_empty(&iucv_handler_table)) {
- if (register_flag) {
- unregister_external_interrupt(0x4000, iucv_irq_handler);
- register_flag = 0;
- }
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- iucv_debug(1, "exiting");
- return;
-}
-
-/**
- * iucv_register_program:
- * @pgmname: user identification
- * @userid: machine identification
- * @pgmmask: Indicates which bits in the pgmname and userid combined will be
- * used to determine who is given control.
- * @ops: Address of interrupt handler table.
- * @pgm_data: Application data to be passed to interrupt handlers.
- *
- * Registers an application with IUCV.
- * Returns:
- * The address of handler, or NULL on failure.
- * NOTE on pgmmask:
- * If pgmname, userid and pgmmask are provided, pgmmask is entered into the
- * handler as is.
- * If pgmmask is NULL, the internal mask is set to all 0xff's
- * When userid is NULL, the first 8 bytes of the internal mask are forced
- * to 0x00.
- * If pgmmask and userid are NULL, the first 8 bytes of the internal mask
- * are forced to 0x00 and the last 16 bytes to 0xff.
- */
-
-iucv_handle_t
-iucv_register_program (__u8 pgmname[16],
- __u8 userid[8],
- __u8 pgmmask[24],
- iucv_interrupt_ops_t * ops, void *pgm_data)
-{
- ulong rc = 0; /* return code from function calls */
- handler *new_handler;
-
- iucv_debug(1, "entering");
-
- if (ops == NULL) {
- /* interrupt table is not defined */
- printk(KERN_WARNING "%s: Interrupt table is not defined, "
- "exiting\n", __FUNCTION__);
- return NULL;
- }
- if (!pgmname) {
- printk(KERN_WARNING "%s: pgmname not provided\n", __FUNCTION__);
- return NULL;
- }
-
- /* Allocate handler entry */
- new_handler = (handler *)kmalloc(sizeof(handler), GFP_ATOMIC);
- if (new_handler == NULL) {
- printk(KERN_WARNING "%s: storage allocation for new handler "
- "failed.\n", __FUNCTION__);
- return NULL;
- }
-
- if (!iucv_pathid_table) {
- if (iucv_init()) {
- kfree(new_handler);
- return NULL;
- }
-
- max_connections = iucv_query_maxconn();
- iucv_pathid_table = kcalloc(max_connections, sizeof(handler *),
- GFP_ATOMIC);
- if (iucv_pathid_table == NULL) {
- printk(KERN_WARNING "%s: iucv_pathid_table storage "
- "allocation failed\n", __FUNCTION__);
- kfree(new_handler);
- return NULL;
- }
- }
- memset(new_handler, 0, sizeof (handler));
- memcpy(new_handler->id.user_data, pgmname,
- sizeof (new_handler->id.user_data));
- if (userid) {
- memcpy (new_handler->id.userid, userid,
- sizeof (new_handler->id.userid));
- ASCEBC (new_handler->id.userid,
- sizeof (new_handler->id.userid));
- EBC_TOUPPER (new_handler->id.userid,
- sizeof (new_handler->id.userid));
-
- if (pgmmask) {
- memcpy (new_handler->id.mask, pgmmask,
- sizeof (new_handler->id.mask));
- } else {
- memset (new_handler->id.mask, 0xFF,
- sizeof (new_handler->id.mask));
- }
- } else {
- if (pgmmask) {
- memcpy (new_handler->id.mask, pgmmask,
- sizeof (new_handler->id.mask));
- } else {
- memset (new_handler->id.mask, 0xFF,
- sizeof (new_handler->id.mask));
- }
- memset (new_handler->id.userid, 0x00,
- sizeof (new_handler->id.userid));
- }
- /* fill in the rest of handler */
- new_handler->pgm_data = pgm_data;
- new_handler->interrupt_table = ops;
-
- /*
- * Check if someone else is registered with same pgmname, userid
- * and mask. If someone is already registered with same pgmname,
- * userid and mask, registration will fail and NULL will be returned
- * to the application.
- * If identical handler not found, then handler is added to list.
- */
- rc = iucv_add_handler(new_handler);
- if (rc) {
- printk(KERN_WARNING "%s: Someone already registered with same "
- "pgmname, userid, pgmmask\n", __FUNCTION__);
- kfree (new_handler);
- return NULL;
- }
-
- rc = iucv_declare_buffer();
- if (rc) {
- char *err = "Unknown";
- iucv_remove_handler(new_handler);
- kfree(new_handler);
- switch(rc) {
- case 0x03:
- err = "Directory error";
- break;
- case 0x0a:
- err = "Invalid length";
- break;
- case 0x13:
- err = "Buffer already exists";
- break;
- case 0x3e:
- err = "Buffer overlap";
- break;
- case 0x5c:
- err = "Paging or storage error";
- break;
- }
- printk(KERN_WARNING "%s: iucv_declare_buffer "
- "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err);
- return NULL;
- }
- if (!register_flag) {
- /* request the 0x4000 external interrupt */
- rc = register_external_interrupt (0x4000, iucv_irq_handler);
- if (rc) {
- iucv_remove_handler(new_handler);
- kfree (new_handler);
- printk(KERN_WARNING "%s: "
- "register_external_interrupt returned %ld\n",
- __FUNCTION__, rc);
- return NULL;
-
- }
- register_flag = 1;
- }
- iucv_debug(1, "exiting");
- return new_handler;
-} /* end of register function */
-
-/**
- * iucv_unregister_program:
- * @handle: address of handler
- *
- * Unregister application with IUCV.
- * Returns:
- * 0 on success, -EINVAL, if specified handle is invalid.
- */
-
-int
-iucv_unregister_program (iucv_handle_t handle)
-{
- handler *h = NULL;
- struct list_head *lh;
- int i;
- ulong flags;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "address of handler is %p", h);
-
- /* Checking if handle is valid */
- spin_lock_irqsave (&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- if ((handler *)handle == list_entry(lh, handler, list)) {
- h = (handler *)handle;
- break;
- }
- }
- if (!h) {
- spin_unlock_irqrestore (&iucv_lock, flags);
- if (handle)
- printk(KERN_WARNING
- "%s: Handler not found in iucv_handler_table.\n",
- __FUNCTION__);
- else
- printk(KERN_WARNING
- "%s: NULL handle passed by application.\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- /**
- * First, walk thru iucv_pathid_table and sever any pathid which is
- * still pointing to the handler to be removed.
- */
- for (i = 0; i < max_connections; i++)
- if (iucv_pathid_table[i] == h) {
- spin_unlock_irqrestore (&iucv_lock, flags);
- iucv_sever(i, h->id.user_data);
- spin_lock_irqsave(&iucv_lock, flags);
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- iucv_remove_handler(h);
- kfree(h);
-
- iucv_debug(1, "exiting");
- return 0;
-}
-
-/**
- * iucv_accept:
- * @pathid: Path identification number
- * @msglim_reqstd: The number of outstanding messages requested.
- * @user_data: Data specified by the iucv_connect function.
- * @flags1: Contains options for this path.
- * - IPPRTY (0x20) Specifies if you want to send priority message.
- * - IPRMDATA (0x80) Specifies whether your program can handle a message
- * in the parameter list.
- * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being
- * established.
- * @handle: Address of handler.
- * @pgm_data: Application data passed to interrupt handlers.
- * @flags1_out: Pointer to an int. If not NULL, on return the options for
- * the path are stored at the given location:
- * - IPPRTY (0x20) Indicates you may send a priority message.
- * @msglim: Pointer to an __u16. If not NULL, on return the maximum
- * number of outstanding messages is stored at the given
- * location.
- *
- * This function is issued after the user receives a Connection Pending external
- * interrupt and now wishes to complete the IUCV communication path.
- * Returns:
- * return code from CP
- */
-int
-iucv_accept(__u16 pathid, __u16 msglim_reqstd,
- __u8 user_data[16], int flags1,
- iucv_handle_t handle, void *pgm_data,
- int *flags1_out, __u16 * msglim)
-{
- ulong b2f0_result = 0;
- ulong flags;
- struct list_head *lh;
- handler *h = NULL;
- iparml_control *parm;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- /* Checking if handle is valid */
- spin_lock_irqsave (&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- if ((handler *)handle == list_entry(lh, handler, list)) {
- h = (handler *)handle;
- break;
- }
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- if (!h) {
- if (handle)
- printk(KERN_WARNING
- "%s: Handler not found in iucv_handler_table.\n",
- __FUNCTION__);
- else
- printk(KERN_WARNING
- "%s: NULL handle passed by application.\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- parm = (iparml_control *)grab_param();
-
- parm->ippathid = pathid;
- parm->ipmsglim = msglim_reqstd;
- if (user_data)
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
-
- parm->ipflags1 = (__u8)flags1;
- b2f0_result = b2f0(ACCEPT, parm);
-
- if (!b2f0_result) {
- if (msglim)
- *msglim = parm->ipmsglim;
- if (pgm_data)
- h->pgm_data = pgm_data;
- if (flags1_out)
- *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0;
- }
- release_param(parm);
-
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_connect:
- * @pathid: Path identification number
- * @msglim_reqstd: Number of outstanding messages requested
- * @user_data: 16-byte user data
- * @userid: 8-byte of user identification
- * @system_name: 8-byte identifying the system name
- * @flags1: Specifies options for this path:
- * - IPPRTY (0x20) Specifies if you want to send priority message.
- * - IPRMDATA (0x80) Specifies whether your program can handle a message
- * in the parameter list.
- * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being
- * established.
- * - IPLOCAL (0x01) Allows an application to force the partner to be on the
- * local system. If local is specified then target class
- * cannot be specified.
- * @flags1_out: Pointer to an int. If not NULL, on return the options for
- * the path are stored at the given location:
- * - IPPRTY (0x20) Indicates you may send a priority message.
- * @msglim: Pointer to an __u16. If not NULL, on return the maximum
- * number of outstanding messages is stored at the given
- * location.
- * @handle: Address of handler.
- * @pgm_data: Application data to be passed to interrupt handlers.
- *
- * This function establishes an IUCV path. Although the connect may complete
- * successfully, you are not able to use the path until you receive an IUCV
- * Connection Complete external interrupt.
- * Returns: return code from CP, or one of the following
- * - ENOMEM
- * - return code from iucv_declare_buffer
- * - EINVAL - invalid handle passed by application
- * - EINVAL - pathid address is NULL
- * - ENOMEM - pathid table storage allocation failed
- * - return code from internal function add_pathid
- */
-int
-iucv_connect (__u16 *pathid, __u16 msglim_reqstd,
- __u8 user_data[16], __u8 userid[8],
- __u8 system_name[8], int flags1,
- int *flags1_out, __u16 * msglim,
- iucv_handle_t handle, void *pgm_data)
-{
- iparml_control *parm;
- iparml_control local_parm;
- struct list_head *lh;
- ulong b2f0_result = 0;
- ulong flags;
- int add_pathid_result = 0;
- handler *h = NULL;
- __u8 no_memory[16] = "NO MEMORY";
-
- iucv_debug(1, "entering");
-
- /* Checking if handle is valid */
- spin_lock_irqsave (&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- if ((handler *)handle == list_entry(lh, handler, list)) {
- h = (handler *)handle;
- break;
- }
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- if (!h) {
- if (handle)
- printk(KERN_WARNING
- "%s: Handler not found in iucv_handler_table.\n",
- __FUNCTION__);
- else
- printk(KERN_WARNING
- "%s: NULL handle passed by application.\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- if (pathid == NULL) {
- printk(KERN_WARNING "%s: NULL pathid pointer\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- parm = (iparml_control *)grab_param();
-
- parm->ipmsglim = msglim_reqstd;
-
- if (user_data)
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
-
- if (userid) {
- memcpy(parm->ipvmid, userid, sizeof(parm->ipvmid));
- ASCEBC(parm->ipvmid, sizeof(parm->ipvmid));
- EBC_TOUPPER(parm->ipvmid, sizeof(parm->ipvmid));
- }
-
- if (system_name) {
- memcpy(parm->iptarget, system_name, sizeof(parm->iptarget));
- ASCEBC(parm->iptarget, sizeof(parm->iptarget));
- EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget));
- }
-
- /* In order to establish an IUCV connection, the procedure is:
- *
- * b2f0(CONNECT)
- * take the ippathid from the b2f0 call
- * register the handler to the ippathid
- *
- * Unfortunately, the ConnectionEstablished message gets sent after the
- * b2f0(CONNECT) call but before the register is handled.
- *
- * In order for this race condition to be eliminated, the IUCV Control
- * Interrupts must be disabled for the above procedure.
- *
- * David Kennedy <dkennedy@linuxcare.com>
- */
-
- /* Enable everything but IUCV Control messages */
- iucv_setmask(~(AllInterrupts));
- messagesDisabled = 1;
-
- spin_lock_irqsave (&iucv_lock, flags);
- parm->ipflags1 = (__u8)flags1;
- b2f0_result = b2f0(CONNECT, parm);
- memcpy(&local_parm, parm, sizeof(local_parm));
- release_param(parm);
- parm = &local_parm;
- if (!b2f0_result)
- add_pathid_result = __iucv_add_pathid(parm->ippathid, h);
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- if (b2f0_result) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- return b2f0_result;
- }
-
- *pathid = parm->ippathid;
-
- /* Enable everything again */
- iucv_setmask(IUCVControlInterruptsFlag);
-
- if (msglim)
- *msglim = parm->ipmsglim;
- if (flags1_out)
- *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0;
-
- if (add_pathid_result) {
- iucv_sever(*pathid, no_memory);
- printk(KERN_WARNING "%s: add_pathid failed with rc ="
- " %d\n", __FUNCTION__, add_pathid_result);
- return(add_pathid_result);
- }
-
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_purge:
- * @pathid: Path identification number
- * @msgid: Message ID of message to purge.
- * @srccls: Message class of the message to purge.
- * @audit: Pointer to an __u32. If not NULL, on return, information about
- * asynchronous errors that may have affected the normal completion
- * of this message ist stored at the given location.
- *
- * Cancels a message you have sent.
- * Returns: return code from CP
- */
-int
-iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit)
-{
- iparml_purge *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_purge *)grab_param();
-
- parm->ipmsgid = msgid;
- parm->ippathid = pathid;
- parm->ipsrccls = srccls;
- parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID);
- b2f0_result = b2f0(PURGE, parm);
-
- if (!b2f0_result && audit) {
- memcpy(audit, parm->ipaudit, sizeof(parm->ipaudit));
- /* parm->ipaudit has only 3 bytes */
- *audit >>= 8;
- }
-
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", b2f0_result);
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_query_generic:
- * @want_maxconn: Flag, describing which value is to be returned.
- *
- * Helper function for iucv_query_maxconn() and iucv_query_bufsize().
- *
- * Returns: The buffersize, if want_maxconn is 0; the maximum number of
- * connections, if want_maxconn is 1 or an error-code < 0 on failure.
- */
-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;
-
- /**
- * Call b2f0 and store R0 (max buffer size),
- * R1 (max connections) and 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)
- return -EPERM;
- if (want_maxconn)
- return maxconn;
- return bufsize;
-}
-
-/**
- * iucv_query_maxconn:
- *
- * Determines the maximum number of connections thay may be established.
- *
- * Returns: Maximum number of connections that can be.
- */
-ulong
-iucv_query_maxconn(void)
-{
- return iucv_query_generic(1);
-}
-
-/**
- * iucv_query_bufsize:
- *
- * Determines the size of the external interrupt buffer.
- *
- * Returns: Size of external interrupt buffer.
- */
-ulong
-iucv_query_bufsize (void)
-{
- return iucv_query_generic(0);
-}
-
-/**
- * iucv_quiesce:
- * @pathid: Path identification number
- * @user_data: 16-byte user data
- *
- * Temporarily suspends incoming messages on an IUCV path.
- * You can later reactivate the path by invoking the iucv_resume function.
- * Returns: return code from CP
- */
-int
-iucv_quiesce (__u16 pathid, __u8 user_data[16])
-{
- iparml_control *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_control *)grab_param();
-
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
- parm->ippathid = pathid;
-
- b2f0_result = b2f0(QUIESCE, parm);
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", b2f0_result);
- iucv_debug(1, "exiting");
-
- return b2f0_result;
-}
-
-/**
- * iucv_receive:
- * @pathid: Path identification number.
- * @buffer: Address of buffer to receive. Must be below 2G.
- * @buflen: Length of buffer to receive.
- * @msgid: Specifies the message ID.
- * @trgcls: Specifies target class.
- * @flags1_out: Receives options for path on return.
- * - IPNORPY (0x10) Specifies whether a reply is required
- * - IPPRTY (0x20) Specifies if you want to send priority message
- * - IPRMDATA (0x80) Specifies the data is contained in the parameter list
- * @residual_buffer: Receives the address of buffer updated by the number
- * of bytes you have received on return.
- * @residual_length: On return, receives one of the following values:
- * - 0 If the receive buffer is the same length as
- * the message.
- * - Remaining bytes in buffer If the receive buffer is longer than the
- * message.
- * - Remaining bytes in message If the receive buffer is shorter than the
- * message.
- *
- * This function receives messages that are being sent to you over established
- * paths.
- * Returns: return code from CP IUCV call; If the receive buffer is shorter
- * than the message, always 5
- * -EINVAL - buffer address is pointing to NULL
- */
-int
-iucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls,
- void *buffer, ulong buflen,
- int *flags1_out, ulong * residual_buffer, ulong * residual_length)
-{
- iparml_db *parm;
- ulong b2f0_result;
- int moved = 0; /* number of bytes moved from parmlist to buffer */
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr1 = (__u32) (addr_t) buffer;
- parm->ipbfln1f = (__u32) ((ulong) buflen);
- parm->ipmsgid = msgid;
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPFGPID | IPFGMID | IPFGMCL);
-
- b2f0_result = b2f0(RECEIVE, parm);
-
- if (!b2f0_result || b2f0_result == 5) {
- if (flags1_out) {
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- *flags1_out = (parm->ipflags1 & (~0x07));
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- }
-
- if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */
- if (residual_length)
- *residual_length = parm->ipbfln1f;
-
- if (residual_buffer)
- *residual_buffer = parm->ipbfadr1;
- } else {
- moved = min_t (unsigned long, buflen, 8);
-
- memcpy ((char *) buffer,
- (char *) &parm->ipbfadr1, moved);
-
- if (buflen < 8)
- b2f0_result = 5;
-
- if (residual_length)
- *residual_length = abs (buflen - 8);
-
- if (residual_buffer)
- *residual_buffer = (ulong) (buffer + moved);
- }
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/*
- * Name: iucv_receive_array
- * Purpose: This function receives messages that are being sent to you
- * over established paths.
- * Input: pathid - path identification number
- * buffer - address of array of buffers
- * buflen - total length of buffers
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * Output:
- * flags1_out: Options for path.
- * IPNORPY - 0x10 specifies whether a reply is required
- * IPPRTY - 0x20 specifies if you want to send priority message
- * IPRMDATA - 0x80 specifies the data is contained in the parameter list
- * residual_buffer - address points to the current list entry IUCV
- * is working on.
- * residual_length -
- * Contains one of the following values, if the receive buffer is:
- * The same length as the message, this field is zero.
- * Longer than the message, this field contains the number of
- * bytes remaining in the buffer.
- * Shorter than the message, this field contains the residual
- * count (that is, the number of bytes remaining in the
- * message that does not fit into the buffer. In this case
- * b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_receive_array (__u16 pathid,
- __u32 msgid, __u32 trgcls,
- iucv_array_t * buffer, ulong buflen,
- int *flags1_out,
- ulong * residual_buffer, ulong * residual_length)
-{
- iparml_db *parm;
- ulong b2f0_result;
- int i = 0, moved = 0, need_to_move = 8, dyn_len;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen;
- parm->ipmsgid = msgid;
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL);
-
- b2f0_result = b2f0(RECEIVE, parm);
-
- if (!b2f0_result || b2f0_result == 5) {
-
- if (flags1_out) {
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- *flags1_out = (parm->ipflags1 & (~0x07));
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- }
-
- if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */
-
- if (residual_length)
- *residual_length = parm->ipbfln1f;
-
- if (residual_buffer)
- *residual_buffer = parm->ipbfadr1;
-
- } else {
- /* copy msg from parmlist to users array. */
-
- while ((moved < 8) && (moved < buflen)) {
- dyn_len =
- min_t (unsigned int,
- (buffer + i)->length, need_to_move);
-
- memcpy ((char *)((ulong)((buffer + i)->address)),
- ((char *) &parm->ipbfadr1) + moved,
- dyn_len);
-
- moved += dyn_len;
- need_to_move -= dyn_len;
-
- (buffer + i)->address =
- (__u32)
- ((ulong)(__u8 *) ((ulong)(buffer + i)->address)
- + dyn_len);
-
- (buffer + i)->length -= dyn_len;
- i++;
- }
-
- if (need_to_move) /* buflen < 8 bytes */
- b2f0_result = 5;
-
- if (residual_length)
- *residual_length = abs (buflen - 8);
-
- if (residual_buffer) {
- if (!moved)
- *residual_buffer = (ulong) buffer;
- else
- *residual_buffer =
- (ulong) (buffer + (i - 1));
- }
-
- }
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_reject:
- * @pathid: Path identification number.
- * @msgid: Message ID of the message to reject.
- * @trgcls: Target class of the message to reject.
- * Returns: return code from CP
- *
- * Refuses a specified message. Between the time you are notified of a
- * message and the time that you complete the message, the message may
- * be rejected.
- */
-int
-iucv_reject (__u16 pathid, __u32 msgid, __u32 trgcls)
-{
- iparml_db *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPFGMCL | IPFGMID | IPFGPID);
-
- b2f0_result = b2f0(REJECT, parm);
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", b2f0_result);
- iucv_debug(1, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_reply
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Input: pathid - path identification number
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * flags1 - option for path
- * IPPRTY- 0x20 - specifies if you want to send priority message
- * buffer - address of reply buffer
- * buflen - length of reply buffer
- * Output: ipbfadr2 - Address of buffer updated by the number
- * of bytes you have moved.
- * ipbfln2f - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_reply (__u16 pathid,
- __u32 msgid, __u32 trgcls,
- int flags1,
- void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr2 = (__u32) ((ulong) buffer);
- parm->ipbfln2f = (__u32) buflen; /* length of message */
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (__u8) flags1; /* priority message */
-
- b2f0_result = b2f0(REPLY, parm);
-
- if ((!b2f0_result) || (b2f0_result == 5)) {
- if (ipbfadr2)
- *ipbfadr2 = parm->ipbfadr2;
- if (ipbfln2f)
- *ipbfln2f = parm->ipbfln2f;
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_reply_array
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * The array identifies a list of addresses and lengths of
- * discontiguous buffers that contains the reply data.
- * Input: pathid - path identification number
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of array of reply buffers
- * buflen - total length of reply buffers
- * Output: ipbfadr2 - Address of buffer which IUCV is currently working on.
- * ipbfln2f - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
-*/
-int
-iucv_reply_array (__u16 pathid,
- __u32 msgid, __u32 trgcls,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr2 = (__u32) ((ulong) buffer);
- parm->ipbfln2f = buflen; /* length of message */
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPANSLST | flags1);
-
- b2f0_result = b2f0(REPLY, parm);
-
- if ((!b2f0_result) || (b2f0_result == 5)) {
-
- if (ipbfadr2)
- *ipbfadr2 = parm->ipbfadr2;
- if (ipbfln2f)
- *ipbfln2f = parm->ipbfln2f;
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_reply_prmmsg
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Prmmsg signifies the data is moved into the
- * parameter list.
- * Input: pathid - path identification number
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed into the parameter
- * list.
- * Output: NA
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_reply_prmmsg (__u16 pathid,
- __u32 msgid, __u32 trgcls, int flags1, __u8 prmmsg[8])
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- memcpy(parm->iprmmsg, prmmsg, sizeof (parm->iprmmsg));
- parm->ipflags1 = (IPRMDATA | flags1);
-
- b2f0_result = b2f0(REPLY, parm);
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/**
- * iucv_resume:
- * @pathid: Path identification number
- * @user_data: 16-byte of user data
- *
- * This function restores communication over a quiesced path.
- * Returns: return code from CP
- */
-int
-iucv_resume (__u16 pathid, __u8 user_data[16])
-{
- iparml_control *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_control *)grab_param();
-
- memcpy (parm->ipuser, user_data, sizeof (*user_data));
- parm->ippathid = pathid;
-
- b2f0_result = b2f0(RESUME, parm);
- release_param(parm);
-
- iucv_debug(1, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send
- * Purpose: sends messages
- * Input: pathid - ushort, pathid
- * msgid - ulong *, id of message returned to caller
- * trgcls - ulong, target message class
- * srccls - ulong, source message class
- * msgtag - ulong, message tag
- * flags1 - Contains options for this path.
- * IPPRTY - Ox20 - specifies if you want to send a priority message.
- * buffer - pointer to buffer
- * buflen - ulong, length of buffer
- * Output: b2f0_result - return code from b2f0 call
- * msgid - returns message id
- */
-int
-iucv_send (__u16 pathid, __u32 * msgid,
- __u32 trgcls, __u32 srccls,
- __u32 msgtag, int flags1, void *buffer, ulong buflen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPNORPY | flags1); /* one way priority message */
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated witht the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of array of send buffers
- * buflen - total length of send buffers
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_send_array (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPNORPY | IPBUFLST | flags1);
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed into parameter list
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_send_prmmsg (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls, __u32 msgtag, int flags1, __u8 prmmsg[8])
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPRMDATA | IPNORPY | flags1);
- memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way
- * Purpose: This function transmits data to another application.
- * Data to be transmitted is in a buffer. The receiver
- * of the send is expected to reply to the message and
- * a buffer is provided into which IUCV moves the reply
- * to this message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of send buffer
- * buflen - length of send buffer
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer or ansbuf address is NULL
- */
-int
-iucv_send2way (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- int flags1,
- void *buffer, ulong buflen, void *ansbuf, ulong anslen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer || !ansbuf)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = flags1; /* priority message */
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. The receiver of the send is expected to
- * reply to the message and a buffer is provided into which
- * IUCV moves the reply to this message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - spcifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of array of send buffers
- * buflen - total length of send buffers
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_send2way_array (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, iucv_array_t * ansbuf, ulong anslen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer || !ansbuf)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPBUFLST | IPANSLST | flags1);
- b2f0_result = b2f0(SEND, parm);
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed in parameter list
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
-*/
-int
-iucv_send2way_prmmsg (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- ulong flags1, __u8 prmmsg[8], void *ansbuf, ulong anslen)
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!ansbuf)
- return -EINVAL;
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipflags1 = (IPRMDATA | flags1); /* message in prmlist */
- memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_prmmsg_array
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message. The contents of ansbuf is the address of the
- * array of addresses and lengths of discontiguous buffers
- * that contain the reply.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed into the parameter list
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - ansbuf address is NULL
- */
-int
-iucv_send2way_prmmsg_array (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- int flags1,
- __u8 prmmsg[8],
- iucv_array_t * ansbuf, ulong anslen)
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!ansbuf)
- return -EINVAL;
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipflags1 = (IPRMDATA | IPANSLST | flags1);
- memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
- b2f0_result = b2f0(SEND, parm);
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-void
-iucv_setmask_cpuid (void *result)
-{
- iparml_set_mask *parm;
-
- iucv_debug(1, "entering");
- parm = (iparml_set_mask *)grab_param();
- parm->ipmask = *((__u8*)result);
- *((ulong *)result) = b2f0(SETMASK, parm);
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", *((ulong *)result));
- iucv_debug(1, "exiting");
-}
-
-/*
- * Name: iucv_setmask
- * Purpose: This function enables or disables the following IUCV
- * external interruptions: Nonpriority and priority message
- * interrupts, nonpriority and priority reply interrupts.
- * Input: SetMaskFlag - options for interrupts
- * 0x80 - Nonpriority_MessagePendingInterruptsFlag
- * 0x40 - Priority_MessagePendingInterruptsFlag
- * 0x20 - Nonpriority_MessageCompletionInterruptsFlag
- * 0x10 - Priority_MessageCompletionInterruptsFlag
- * 0x08 - IUCVControlInterruptsFlag
- * Output: NA
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_setmask (int SetMaskFlag)
-{
- union {
- ulong result;
- __u8 param;
- } u;
- int cpu;
-
- u.param = SetMaskFlag;
- cpu = get_cpu();
- smp_call_function_on(iucv_setmask_cpuid, &u, 0, 1, iucv_cpuid);
- put_cpu();
-
- return u.result;
-}
-
-/**
- * iucv_sever:
- * @pathid: Path identification number
- * @user_data: 16-byte of user data
- *
- * This function terminates an iucv path.
- * Returns: return code from CP
- */
-int
-iucv_sever(__u16 pathid, __u8 user_data[16])
-{
- iparml_control *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- parm = (iparml_control *)grab_param();
-
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
- parm->ippathid = pathid;
-
- b2f0_result = b2f0(SEVER, parm);
-
- if (!b2f0_result)
- iucv_remove_pathid(pathid);
- release_param(parm);
-
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/*
- * Interrupt Handlers
- *******************************************************************************/
-
-/**
- * iucv_irq_handler:
- * @regs: Current registers
- * @code: irq code
- *
- * Handles external interrupts coming in from CP.
- * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
- */
-static void
-iucv_irq_handler(__u16 code)
-{
- iucv_irqdata *irqdata;
-
- irqdata = kmalloc(sizeof(iucv_irqdata), GFP_ATOMIC);
- if (!irqdata) {
- printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__);
- return;
- }
-
- memcpy(&irqdata->data, iucv_external_int_buffer,
- sizeof(iucv_GeneralInterrupt));
-
- spin_lock(&iucv_irq_queue_lock);
- list_add_tail(&irqdata->queue, &iucv_irq_queue);
- spin_unlock(&iucv_irq_queue_lock);
-
- tasklet_schedule(&iucv_tasklet);
-}
-
-/**
- * iucv_do_int:
- * @int_buf: Pointer to copy of external interrupt buffer
- *
- * The workhorse for handling interrupts queued by iucv_irq_handler().
- * This function is called from the bottom half iucv_tasklet_handler().
- */
-static void
-iucv_do_int(iucv_GeneralInterrupt * int_buf)
-{
- handler *h = NULL;
- struct list_head *lh;
- ulong flags;
- iucv_interrupt_ops_t *interrupt = NULL; /* interrupt addresses */
- __u8 temp_buff1[24], temp_buff2[24]; /* masked handler id. */
- int rc = 0, j = 0;
- __u8 no_listener[16] = "NO LISTENER";
-
- iucv_debug(2, "entering, pathid %d, type %02X",
- int_buf->ippathid, int_buf->iptype);
- iucv_dumpit("External Interrupt Buffer:",
- int_buf, sizeof(iucv_GeneralInterrupt));
-
- ASCEBC (no_listener, 16);
-
- if (int_buf->iptype != 01) {
- if ((int_buf->ippathid) > (max_connections - 1)) {
- printk(KERN_WARNING "%s: Got interrupt with pathid %d"
- " > max_connections (%ld)\n", __FUNCTION__,
- int_buf->ippathid, max_connections - 1);
- } else {
- h = iucv_pathid_table[int_buf->ippathid];
- interrupt = h->interrupt_table;
- iucv_dumpit("Handler:", h, sizeof(handler));
- }
- }
-
- /* end of if statement */
- switch (int_buf->iptype) {
- case 0x01: /* connection pending */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- spin_lock_irqsave(&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- h = list_entry(lh, handler, list);
- memcpy(temp_buff1, &(int_buf->ipvmid), 24);
- memcpy(temp_buff2, &(h->id.userid), 24);
- for (j = 0; j < 24; j++) {
- temp_buff1[j] &= (h->id.mask)[j];
- temp_buff2[j] &= (h->id.mask)[j];
- }
-
- iucv_dumpit("temp_buff1:",
- temp_buff1, sizeof(temp_buff1));
- iucv_dumpit("temp_buff2",
- temp_buff2, sizeof(temp_buff2));
-
- if (!memcmp (temp_buff1, temp_buff2, 24)) {
-
- iucv_debug(2,
- "found a matching handler");
- break;
- } else
- h = NULL;
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
- if (h) {
- /* ADD PATH TO PATHID TABLE */
- rc = iucv_add_pathid(int_buf->ippathid, h);
- if (rc) {
- iucv_sever (int_buf->ippathid,
- no_listener);
- iucv_debug(1,
- "add_pathid failed, rc = %d",
- rc);
- } else {
- interrupt = h->interrupt_table;
- if (interrupt->ConnectionPending) {
- EBCASC (int_buf->ipvmid, 8);
- interrupt->ConnectionPending(
- (iucv_ConnectionPending *)int_buf,
- h->pgm_data);
- } else
- iucv_sever(int_buf->ippathid,
- no_listener);
- }
- } else
- iucv_sever(int_buf->ippathid, no_listener);
- break;
-
- case 0x02: /*connection complete */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionComplete)
- {
- interrupt->ConnectionComplete(
- (iucv_ConnectionComplete *)int_buf,
- h->pgm_data);
- }
- else
- iucv_debug(1,
- "ConnectionComplete not called");
- } else
- iucv_sever(int_buf->ippathid, no_listener);
- break;
-
- case 0x03: /* connection severed */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionSevered)
- interrupt->ConnectionSevered(
- (iucv_ConnectionSevered *)int_buf,
- h->pgm_data);
-
- else
- iucv_sever (int_buf->ippathid, no_listener);
- } else
- iucv_sever(int_buf->ippathid, no_listener);
- break;
-
- case 0x04: /* connection quiesced */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionQuiesced)
- interrupt->ConnectionQuiesced(
- (iucv_ConnectionQuiesced *)int_buf,
- h->pgm_data);
- else
- iucv_debug(1,
- "ConnectionQuiesced not called");
- }
- break;
-
- case 0x05: /* connection resumed */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionResumed)
- interrupt->ConnectionResumed(
- (iucv_ConnectionResumed *)int_buf,
- h->pgm_data);
- else
- iucv_debug(1,
- "ConnectionResumed not called");
- }
- break;
-
- case 0x06: /* priority message complete */
- case 0x07: /* nonpriority message complete */
- if (h) {
- if (interrupt->MessageComplete)
- interrupt->MessageComplete(
- (iucv_MessageComplete *)int_buf,
- h->pgm_data);
- else
- iucv_debug(2,
- "MessageComplete not called");
- }
- break;
-
- case 0x08: /* priority message pending */
- case 0x09: /* nonpriority message pending */
- if (h) {
- if (interrupt->MessagePending)
- interrupt->MessagePending(
- (iucv_MessagePending *) int_buf,
- h->pgm_data);
- else
- iucv_debug(2,
- "MessagePending not called");
- }
- break;
- default: /* unknown iucv type */
- printk(KERN_WARNING "%s: unknown iucv interrupt\n",
- __FUNCTION__);
- break;
- } /* end switch */
-
- iucv_debug(2, "exiting pathid %d, type %02X",
- int_buf->ippathid, int_buf->iptype);
-
- return;
-}
-
-/**
- * iucv_tasklet_handler:
- *
- * This function loops over the queue of irq buffers and runs iucv_do_int()
- * on every queue element.
- */
-static void
-iucv_tasklet_handler(unsigned long ignored)
-{
- struct list_head head;
- struct list_head *next;
- ulong flags;
-
- spin_lock_irqsave(&iucv_irq_queue_lock, flags);
- list_add(&head, &iucv_irq_queue);
- list_del_init(&iucv_irq_queue);
- spin_unlock_irqrestore (&iucv_irq_queue_lock, flags);
-
- next = head.next;
- while (next != &head) {
- iucv_irqdata *p = list_entry(next, iucv_irqdata, queue);
-
- next = next->next;
- iucv_do_int(&p->data);
- kfree(p);
- }
-
- return;
-}
-
-subsys_initcall(iucv_init);
-module_exit(iucv_exit);
-
-/**
- * Export all public stuff
- */
-EXPORT_SYMBOL (iucv_bus);
-EXPORT_SYMBOL (iucv_root);
-EXPORT_SYMBOL (iucv_accept);
-EXPORT_SYMBOL (iucv_connect);
-#if 0
-EXPORT_SYMBOL (iucv_purge);
-EXPORT_SYMBOL (iucv_query_maxconn);
-EXPORT_SYMBOL (iucv_query_bufsize);
-EXPORT_SYMBOL (iucv_quiesce);
-#endif
-EXPORT_SYMBOL (iucv_receive);
-#if 0
-EXPORT_SYMBOL (iucv_receive_array);
-#endif
-EXPORT_SYMBOL (iucv_reject);
-#if 0
-EXPORT_SYMBOL (iucv_reply);
-EXPORT_SYMBOL (iucv_reply_array);
-EXPORT_SYMBOL (iucv_resume);
-#endif
-EXPORT_SYMBOL (iucv_reply_prmmsg);
-EXPORT_SYMBOL (iucv_send);
-EXPORT_SYMBOL (iucv_send2way);
-EXPORT_SYMBOL (iucv_send2way_array);
-EXPORT_SYMBOL (iucv_send2way_prmmsg);
-EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
-#if 0
-EXPORT_SYMBOL (iucv_send_array);
-EXPORT_SYMBOL (iucv_send_prmmsg);
-EXPORT_SYMBOL (iucv_setmask);
-#endif
-EXPORT_SYMBOL (iucv_sever);
-EXPORT_SYMBOL (iucv_register_program);
-EXPORT_SYMBOL (iucv_unregister_program);
diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h
deleted file mode 100644
index 5b6b1b7241c..00000000000
--- a/drivers/s390/net/iucv.h
+++ /dev/null
@@ -1,849 +0,0 @@
-/*
- * drivers/s390/net/iucv.h
- * IUCV base support.
- *
- * S390 version
- * Copyright (C) 2000 IBM Corporation
- * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com)
- * Xenia Tkatschow (xenia@us.ibm.com)
- *
- *
- * Functionality:
- * To explore any of the IUCV functions, one must first register
- * their program using iucv_register_program(). Once your program has
- * successfully completed a register, it can exploit the other functions.
- * For furthur reference on all IUCV functionality, refer to the
- * CP Programming Services book, also available on the web
- * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
- *
- * Definition of Return Codes
- * -All positive return codes including zero are reflected back
- * from CP except for iucv_register_program. The definition of each
- * return code can be found in CP Programming Services book.
- * Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
- * - Return Code of:
- * (-EINVAL) Invalid value
- * (-ENOMEM) storage allocation failed
- * pgmask defined in iucv_register_program will be set depending on input
- * paramters.
- *
- */
-
-#include <linux/types.h>
-#include <asm/debug.h>
-
-/**
- * Debug Facility stuff
- */
-#define IUCV_DBF_SETUP_NAME "iucv_setup"
-#define IUCV_DBF_SETUP_LEN 32
-#define IUCV_DBF_SETUP_PAGES 2
-#define IUCV_DBF_SETUP_NR_AREAS 1
-#define IUCV_DBF_SETUP_LEVEL 3
-
-#define IUCV_DBF_DATA_NAME "iucv_data"
-#define IUCV_DBF_DATA_LEN 128
-#define IUCV_DBF_DATA_PAGES 2
-#define IUCV_DBF_DATA_NR_AREAS 1
-#define IUCV_DBF_DATA_LEVEL 2
-
-#define IUCV_DBF_TRACE_NAME "iucv_trace"
-#define IUCV_DBF_TRACE_LEN 16
-#define IUCV_DBF_TRACE_PAGES 4
-#define IUCV_DBF_TRACE_NR_AREAS 1
-#define IUCV_DBF_TRACE_LEVEL 3
-
-#define IUCV_DBF_TEXT(name,level,text) \
- do { \
- debug_text_event(iucv_dbf_##name,level,text); \
- } while (0)
-
-#define IUCV_DBF_HEX(name,level,addr,len) \
- do { \
- debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
- } while (0)
-
-DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
-
-#define IUCV_DBF_TEXT_(name,level,text...) \
- do { \
- char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \
- sprintf(iucv_dbf_txt_buf, text); \
- debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \
- put_cpu_var(iucv_dbf_txt_buf); \
- } while (0)
-
-#define IUCV_DBF_SPRINTF(name,level,text...) \
- do { \
- debug_sprintf_event(iucv_dbf_trace, level, ##text ); \
- debug_sprintf_event(iucv_dbf_trace, level, text ); \
- } while (0)
-
-/**
- * some more debug stuff
- */
-#define IUCV_HEXDUMP16(importance,header,ptr) \
-PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
- "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
- *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
- *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
- *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
- *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
- *(((char*)ptr)+12),*(((char*)ptr)+13), \
- *(((char*)ptr)+14),*(((char*)ptr)+15)); \
-PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
- "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
- *(((char*)ptr)+16),*(((char*)ptr)+17), \
- *(((char*)ptr)+18),*(((char*)ptr)+19), \
- *(((char*)ptr)+20),*(((char*)ptr)+21), \
- *(((char*)ptr)+22),*(((char*)ptr)+23), \
- *(((char*)ptr)+24),*(((char*)ptr)+25), \
- *(((char*)ptr)+26),*(((char*)ptr)+27), \
- *(((char*)ptr)+28),*(((char*)ptr)+29), \
- *(((char*)ptr)+30),*(((char*)ptr)+31));
-
-static inline void
-iucv_hex_dump(unsigned char *buf, size_t len)
-{
- size_t i;
-
- for (i = 0; i < len; i++) {
- if (i && !(i % 16))
- printk("\n");
- printk("%02x ", *(buf + i));
- }
- printk("\n");
-}
-/**
- * end of debug stuff
- */
-
-#define uchar unsigned char
-#define ushort unsigned short
-#define ulong unsigned long
-#define iucv_handle_t void *
-
-/* flags1:
- * All flags are defined in the field IPFLAGS1 of each function
- * and can be found in CP Programming Services.
- * IPLOCAL - Indicates the connect can only be satisfied on the
- * local system
- * IPPRTY - Indicates a priority message
- * IPQUSCE - Indicates you do not want to receive messages on a
- * path until an iucv_resume is issued
- * IPRMDATA - Indicates that the message is in the parameter list
- */
-#define IPLOCAL 0x01
-#define IPPRTY 0x20
-#define IPQUSCE 0x40
-#define IPRMDATA 0x80
-
-/* flags1_out:
- * All flags are defined in the output field of IPFLAGS1 for each function
- * and can be found in CP Programming Services.
- * IPNORPY - Specifies this is a one-way message and no reply is expected.
- * IPPRTY - Indicates a priority message is permitted. Defined in flags1.
- */
-#define IPNORPY 0x10
-
-#define Nonpriority_MessagePendingInterruptsFlag 0x80
-#define Priority_MessagePendingInterruptsFlag 0x40
-#define Nonpriority_MessageCompletionInterruptsFlag 0x20
-#define Priority_MessageCompletionInterruptsFlag 0x10
-#define IUCVControlInterruptsFlag 0x08
-#define AllInterrupts 0xf8
-/*
- * Mapping of external interrupt buffers should be used with the corresponding
- * interrupt types.
- * Names: iucv_ConnectionPending -> connection pending
- * iucv_ConnectionComplete -> connection complete
- * iucv_ConnectionSevered -> connection severed
- * iucv_ConnectionQuiesced -> connection quiesced
- * iucv_ConnectionResumed -> connection resumed
- * iucv_MessagePending -> message pending
- * iucv_MessageComplete -> message complete
- */
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u16 ipmsglim;
- u16 res1;
- uchar ipvmid[8];
- uchar ipuser[16];
- u32 res3;
- uchar ippollfg;
- uchar res4[3];
-} iucv_ConnectionPending;
-
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u16 ipmsglim;
- u16 res1;
- uchar res2[8];
- uchar ipuser[16];
- u32 res3;
- uchar ippollfg;
- uchar res4[3];
-} iucv_ConnectionComplete;
-
-typedef struct {
- u16 ippathid;
- uchar res1;
- uchar iptype;
- u32 res2;
- uchar res3[8];
- uchar ipuser[16];
- u32 res4;
- uchar ippollfg;
- uchar res5[3];
-} iucv_ConnectionSevered;
-
-typedef struct {
- u16 ippathid;
- uchar res1;
- uchar iptype;
- u32 res2;
- uchar res3[8];
- uchar ipuser[16];
- u32 res4;
- uchar ippollfg;
- uchar res5[3];
-} iucv_ConnectionQuiesced;
-
-typedef struct {
- u16 ippathid;
- uchar res1;
- uchar iptype;
- u32 res2;
- uchar res3[8];
- uchar ipuser[16];
- u32 res4;
- uchar ippollfg;
- uchar res5[3];
-} iucv_ConnectionResumed;
-
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u32 ipmsgid;
- u32 iptrgcls;
- union u2 {
- u32 iprmmsg1_u32;
- uchar iprmmsg1[4];
- } ln1msg1;
- union u1 {
- u32 ipbfln1f;
- uchar iprmmsg2[4];
- } ln1msg2;
- u32 res1[3];
- u32 ipbfln2f;
- uchar ippollfg;
- uchar res2[3];
-} iucv_MessagePending;
-
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u32 ipmsgid;
- u32 ipaudit;
- uchar iprmmsg[8];
- u32 ipsrccls;
- u32 ipmsgtag;
- u32 res;
- u32 ipbfln2f;
- uchar ippollfg;
- uchar res2[3];
-} iucv_MessageComplete;
-
-/*
- * iucv_interrupt_ops_t: Is a vector of functions that handle
- * IUCV interrupts.
- * Parameter list:
- * eib - is a pointer to a 40-byte area described
- * with one of the structures above.
- * pgm_data - this data is strictly for the
- * interrupt handler that is passed by
- * the application. This may be an address
- * or token.
-*/
-typedef struct {
- void (*ConnectionPending) (iucv_ConnectionPending * eib,
- void *pgm_data);
- void (*ConnectionComplete) (iucv_ConnectionComplete * eib,
- void *pgm_data);
- void (*ConnectionSevered) (iucv_ConnectionSevered * eib,
- void *pgm_data);
- void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib,
- void *pgm_data);
- void (*ConnectionResumed) (iucv_ConnectionResumed * eib,
- void *pgm_data);
- void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data);
- void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data);
-} iucv_interrupt_ops_t;
-
-/*
- *iucv_array_t : Defines buffer array.
- * Inside the array may be 31- bit addresses and 31-bit lengths.
-*/
-typedef struct {
- u32 address;
- u32 length;
-} iucv_array_t __attribute__ ((aligned (8)));
-
-extern struct bus_type iucv_bus;
-extern struct device *iucv_root;
-
-/* -prototypes- */
-/*
- * Name: iucv_register_program
- * Purpose: Registers an application with IUCV
- * Input: prmname - user identification
- * userid - machine identification
- * pgmmask - indicates which bits in the prmname and userid combined will be
- * used to determine who is given control
- * ops - address of vector of interrupt handlers
- * pgm_data- application data passed to interrupt handlers
- * Output: NA
- * Return: address of handler
- * (0) - Error occurred, registration not completed.
- * NOTE: Exact cause of failure will be recorded in syslog.
-*/
-iucv_handle_t iucv_register_program (uchar pgmname[16],
- uchar userid[8],
- uchar pgmmask[24],
- iucv_interrupt_ops_t * ops,
- void *pgm_data);
-
-/*
- * Name: iucv_unregister_program
- * Purpose: Unregister application with IUCV
- * Input: address of handler
- * Output: NA
- * Return: (0) - Normal return
- * (-EINVAL) - Internal error, wild pointer
-*/
-int iucv_unregister_program (iucv_handle_t handle);
-
-/*
- * Name: iucv_accept
- * Purpose: This function is issued after the user receives a Connection Pending external
- * interrupt and now wishes to complete the IUCV communication path.
- * Input: pathid - u16 , Path identification number
- * msglim_reqstd - u16, The number of outstanding messages requested.
- * user_data - uchar[16], Data specified by the iucv_connect function.
- * flags1 - int, Contains options for this path.
- * -IPPRTY - 0x20- Specifies if you want to send priority message.
- * -IPRMDATA - 0x80, Specifies whether your program can handle a message
- * in the parameter list.
- * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
- * established.
- * handle - iucv_handle_t, Address of handler.
- * pgm_data - void *, Application data passed to interrupt handlers.
- * flags1_out - int * Contains information about the path
- * - IPPRTY - 0x20, Indicates you may send priority messages.
- * msglim - *u16, Number of outstanding messages.
- * Output: return code from CP IUCV call.
-*/
-
-int iucv_accept (u16 pathid,
- u16 msglim_reqstd,
- uchar user_data[16],
- int flags1,
- iucv_handle_t handle,
- void *pgm_data, int *flags1_out, u16 * msglim);
-
-/*
- * Name: iucv_connect
- * Purpose: This function establishes an IUCV path. Although the connect may complete
- * successfully, you are not able to use the path until you receive an IUCV
- * Connection Complete external interrupt.
- * Input: pathid - u16 *, Path identification number
- * msglim_reqstd - u16, Number of outstanding messages requested
- * user_data - uchar[16], 16-byte user data
- * userid - uchar[8], User identification
- * system_name - uchar[8], 8-byte identifying the system name
- * flags1 - int, Contains options for this path.
- * -IPPRTY - 0x20, Specifies if you want to send priority message.
- * -IPRMDATA - 0x80, Specifies whether your program can handle a message
- * in the parameter list.
- * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
- * established.
- * -IPLOCAL - 0X01, Allows an application to force the partner to be on
- * the local system. If local is specified then target class cannot be
- * specified.
- * flags1_out - int * Contains information about the path
- * - IPPRTY - 0x20, Indicates you may send priority messages.
- * msglim - * u16, Number of outstanding messages
- * handle - iucv_handle_t, Address of handler
- * pgm_data - void *, Application data passed to interrupt handlers
- * Output: return code from CP IUCV call
- * rc - return code from iucv_declare_buffer
- * -EINVAL - Invalid handle passed by application
- * -EINVAL - Pathid address is NULL
- * add_pathid_result - Return code from internal function add_pathid
-*/
-int
- iucv_connect (u16 * pathid,
- u16 msglim_reqstd,
- uchar user_data[16],
- uchar userid[8],
- uchar system_name[8],
- int flags1,
- int *flags1_out,
- u16 * msglim, iucv_handle_t handle, void *pgm_data);
-
-/*
- * Name: iucv_purge
- * Purpose: This function cancels a message that you have sent.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID of the message to be purged.
- * srccls - Specifies the source message class.
- * Output: audit - Contains information about asynchronous error
- * that may have affected the normal completion
- * of this message.
- * Return: Return code from CP IUCV call.
-*/
-int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit);
-/*
- * Name: iucv_query_maxconn
- * Purpose: This function determines the maximum number of communication paths you
- * may establish.
- * Return: maxconn - ulong, Maximum number of connection the virtual machine may
- * establish.
-*/
-ulong iucv_query_maxconn (void);
-
-/*
- * Name: iucv_query_bufsize
- * Purpose: This function determines how large an external interrupt
- * buffer IUCV requires to store information.
- * Return: bufsize - ulong, Size of external interrupt buffer.
- */
-ulong iucv_query_bufsize (void);
-
-/*
- * Name: iucv_quiesce
- * Purpose: This function temporarily suspends incoming messages on an
- * IUCV path. You can later reactivate the path by invoking
- * the iucv_resume function.
- * Input: pathid - Path identification number
- * user_data - 16-bytes of user data
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_quiesce (u16 pathid, uchar user_data[16]);
-
-/*
- * Name: iucv_receive
- * Purpose: This function receives messages that are being sent to you
- * over established paths. Data will be returned in buffer for length of
- * buflen.
- * Input:
- * pathid - Path identification number.
- * buffer - Address of buffer to receive.
- * buflen - Length of buffer to receive.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * Output:
- * flags1_out: int *, Contains information about this path.
- * IPNORPY - 0x10 Specifies this is a one-way message and no reply is
- * expected.
- * IPPRTY - 0x20 Specifies if you want to send priority message.
- * IPRMDATA - 0x80 specifies the data is contained in the parameter list
- * residual_buffer - address of buffer updated by the number
- * of bytes you have received.
- * residual_length -
- * Contains one of the following values, if the receive buffer is:
- * The same length as the message, this field is zero.
- * Longer than the message, this field contains the number of
- * bytes remaining in the buffer.
- * Shorter than the message, this field contains the residual
- * count (that is, the number of bytes remaining in the
- * message that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - buffer address is pointing to NULL
-*/
-int iucv_receive (u16 pathid,
- u32 msgid,
- u32 trgcls,
- void *buffer,
- ulong buflen,
- int *flags1_out,
- ulong * residual_buffer, ulong * residual_length);
-
- /*
- * Name: iucv_receive_array
- * Purpose: This function receives messages that are being sent to you
- * over established paths. Data will be returned in first buffer for
- * length of first buffer.
- * Input: pathid - Path identification number.
- * msgid - specifies the message ID.
- * trgcls - Specifies target class.
- * buffer - Address of array of buffers.
- * buflen - Total length of buffers.
- * Output:
- * flags1_out: int *, Contains information about this path.
- * IPNORPY - 0x10 Specifies this is a one-way message and no reply is
- * expected.
- * IPPRTY - 0x20 Specifies if you want to send priority message.
- * IPRMDATA - 0x80 specifies the data is contained in the parameter list
- * residual_buffer - address points to the current list entry IUCV
- * is working on.
- * residual_length -
- * Contains one of the following values, if the receive buffer is:
- * The same length as the message, this field is zero.
- * Longer than the message, this field contains the number of
- * bytes remaining in the buffer.
- * Shorter than the message, this field contains the residual
- * count (that is, the number of bytes remaining in the
- * message that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
- */
-int iucv_receive_array (u16 pathid,
- u32 msgid,
- u32 trgcls,
- iucv_array_t * buffer,
- ulong buflen,
- int *flags1_out,
- ulong * residual_buffer, ulong * residual_length);
-
-/*
- * Name: iucv_reject
- * Purpose: The reject function refuses a specified message. Between the
- * time you are notified of a message and the time that you
- * complete the message, the message may be rejected.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_reject (u16 pathid, u32 msgid, u32 trgcls);
-
-/*
- * Name: iucv_reply
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * flags1 - Option for path.
- * IPPRTY- 0x20, Specifies if you want to send priority message.
- * buffer - Address of reply buffer.
- * buflen - Length of reply buffer.
- * Output: residual_buffer - Address of buffer updated by the number
- * of bytes you have moved.
- * residual_length - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_reply (u16 pathid,
- u32 msgid,
- u32 trgcls,
- int flags1,
- void *buffer, ulong buflen, ulong * residual_buffer,
- ulong * residual_length);
-
-/*
- * Name: iucv_reply_array
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * The array identifies a list of addresses and lengths of
- * discontiguous buffers that contains the reply data.
- * Input: pathid - Path identification number
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * flags1 - Option for path.
- * IPPRTY- 0x20, Specifies if you want to send priority message.
- * buffer - Address of array of reply buffers.
- * buflen - Total length of reply buffers.
- * Output: residual_buffer - Address of buffer which IUCV is currently working on.
- * residual_length - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_reply_array (u16 pathid,
- u32 msgid,
- u32 trgcls,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, ulong * residual_address,
- ulong * residual_length);
-
-/*
- * Name: iucv_reply_prmmsg
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Prmmsg signifies the data is moved into the
- * parameter list.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into the parameter.
- * list.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_reply_prmmsg (u16 pathid,
- u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]);
-
-/*
- * Name: iucv_resume
- * Purpose: This function restores communications over a quiesced path
- * Input: pathid - Path identification number.
- * user_data - 16-bytes of user data.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_resume (u16 pathid, uchar user_data[16]);
-
-/*
- * Name: iucv_send
- * Purpose: This function transmits data to another application.
- * Data to be transmitted is in a buffer and this is a
- * one-way message and the receiver will not reply to the
- * message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Address of send buffer.
- * buflen - Length of send buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen);
-
-/*
- * Name: iucv_send_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated witht the message.
- * flags1 - Option for path.
- * IPPRTY- specifies if you want to send priority message.
- * buffer - Address of array of send buffers.
- * buflen - Total length of send buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send_array (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1, iucv_array_t * buffer, ulong buflen);
-
-/*
- * Name: iucv_send_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into parameter list.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
-*/
-int iucv_send_prmmsg (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]);
-
-/*
- * Name: iucv_send2way
- * Purpose: This function transmits data to another application.
- * Data to be transmitted is in a buffer. The receiver
- * of the send is expected to reply to the message and
- * a buffer is provided into which IUCV moves the reply
- * to this message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Address of send buffer.
- * buflen - Length of send buffer.
- * ansbuf - Address of buffer into which IUCV moves the reply of
- * this message.
- * anslen - Address of length of buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer or ansbuf address is NULL.
-*/
-int iucv_send2way (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1,
- void *buffer, ulong buflen, void *ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. The receiver of the send is expected to
- * reply to the message and a buffer is provided into which
- * IUCV moves the reply to this message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Sddress of array of send buffers.
- * buflen - Total length of send buffers.
- * ansbuf - Address of array of buffer into which IUCV moves the reply
- * of this message.
- * anslen - Address of length reply buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send2way_array (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, iucv_array_t * ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message.
- * Input: pathid - Rath identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed in parameter list.
- * ansbuf - Address of buffer into which IUCV moves the reply of
- * this message.
- * anslen - Address of length of buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send2way_prmmsg (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- ulong flags1,
- uchar prmmsg[8], void *ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_prmmsg_array
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message. The contents of ansbuf is the address of the
- * array of addresses and lengths of discontiguous buffers
- * that contain the reply.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into the parameter list.
- * ansbuf - Address of array of buffer into which IUCV moves the reply
- * of this message.
- * anslen - Address of length of reply buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Ansbuf address is NULL.
-*/
-int iucv_send2way_prmmsg_array (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1,
- uchar prmmsg[8],
- iucv_array_t * ansbuf, ulong anslen);
-
-/*
- * Name: iucv_setmask
- * Purpose: This function enables or disables the following IUCV
- * external interruptions: Nonpriority and priority message
- * interrupts, nonpriority and priority reply interrupts.
- * Input: SetMaskFlag - options for interrupts
- * 0x80 - Nonpriority_MessagePendingInterruptsFlag
- * 0x40 - Priority_MessagePendingInterruptsFlag
- * 0x20 - Nonpriority_MessageCompletionInterruptsFlag
- * 0x10 - Priority_MessageCompletionInterruptsFlag
- * 0x08 - IUCVControlInterruptsFlag
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_setmask (int SetMaskFlag);
-
-/*
- * Name: iucv_sever
- * Purpose: This function terminates an IUCV path.
- * Input: pathid - Path identification number.
- * user_data - 16-bytes of user data.
- * Output: NA
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Interal error, wild pointer.
-*/
-int iucv_sever (u16 pathid, uchar user_data[16]);
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index e5665b6743a..b97dd15bdb9 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -828,7 +828,7 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd)
/**
* Emit buffer of a lan comand.
*/
-void
+static void
lcs_lancmd_timeout(unsigned long data)
{
struct lcs_reply *reply, *list_reply, *r;
@@ -1360,7 +1360,7 @@ lcs_get_problem(struct ccw_device *cdev, struct irb *irb)
return 0;
}
-void
+static void
lcs_schedule_recovery(struct lcs_card *card)
{
LCS_DBF_TEXT(2, trace, "startrec");
@@ -1990,7 +1990,7 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char
}
-DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
+static DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
static ssize_t
lcs_dev_recover_store(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index d7d1cc0a5c8..6387b483f2b 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1,7 +1,7 @@
/*
* IUCV network driver
*
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
*
* Sysfs integration and all bugs therein by Cornelia Huck
@@ -58,13 +58,94 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-#include "iucv.h"
+#include <net/iucv/iucv.h>
#include "fsm.h"
MODULE_AUTHOR
("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
+/**
+ * Debug Facility stuff
+ */
+#define IUCV_DBF_SETUP_NAME "iucv_setup"
+#define IUCV_DBF_SETUP_LEN 32
+#define IUCV_DBF_SETUP_PAGES 2
+#define IUCV_DBF_SETUP_NR_AREAS 1
+#define IUCV_DBF_SETUP_LEVEL 3
+
+#define IUCV_DBF_DATA_NAME "iucv_data"
+#define IUCV_DBF_DATA_LEN 128
+#define IUCV_DBF_DATA_PAGES 2
+#define IUCV_DBF_DATA_NR_AREAS 1
+#define IUCV_DBF_DATA_LEVEL 2
+
+#define IUCV_DBF_TRACE_NAME "iucv_trace"
+#define IUCV_DBF_TRACE_LEN 16
+#define IUCV_DBF_TRACE_PAGES 4
+#define IUCV_DBF_TRACE_NR_AREAS 1
+#define IUCV_DBF_TRACE_LEVEL 3
+
+#define IUCV_DBF_TEXT(name,level,text) \
+ do { \
+ debug_text_event(iucv_dbf_##name,level,text); \
+ } while (0)
+
+#define IUCV_DBF_HEX(name,level,addr,len) \
+ do { \
+ debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
+ } while (0)
+
+DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
+
+#define IUCV_DBF_TEXT_(name,level,text...) \
+ do { \
+ char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \
+ sprintf(iucv_dbf_txt_buf, text); \
+ debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \
+ put_cpu_var(iucv_dbf_txt_buf); \
+ } while (0)
+
+#define IUCV_DBF_SPRINTF(name,level,text...) \
+ do { \
+ debug_sprintf_event(iucv_dbf_trace, level, ##text ); \
+ debug_sprintf_event(iucv_dbf_trace, level, text ); \
+ } while (0)
+
+/**
+ * some more debug stuff
+ */
+#define IUCV_HEXDUMP16(importance,header,ptr) \
+PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
+ *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
+ *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
+ *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
+ *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
+ *(((char*)ptr)+12),*(((char*)ptr)+13), \
+ *(((char*)ptr)+14),*(((char*)ptr)+15)); \
+PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
+ *(((char*)ptr)+16),*(((char*)ptr)+17), \
+ *(((char*)ptr)+18),*(((char*)ptr)+19), \
+ *(((char*)ptr)+20),*(((char*)ptr)+21), \
+ *(((char*)ptr)+22),*(((char*)ptr)+23), \
+ *(((char*)ptr)+24),*(((char*)ptr)+25), \
+ *(((char*)ptr)+26),*(((char*)ptr)+27), \
+ *(((char*)ptr)+28),*(((char*)ptr)+29), \
+ *(((char*)ptr)+30),*(((char*)ptr)+31));
+
+static inline void iucv_hex_dump(unsigned char *buf, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (i && !(i % 16))
+ printk("\n");
+ printk("%02x ", *(buf + i));
+ }
+ printk("\n");
+}
#define PRINTK_HEADER " iucv: " /* for debugging */
@@ -73,6 +154,25 @@ static struct device_driver netiucv_driver = {
.bus = &iucv_bus,
};
+static int netiucv_callback_connreq(struct iucv_path *,
+ u8 ipvmid[8], u8 ipuser[16]);
+static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *);
+static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *);
+
+static struct iucv_handler netiucv_handler = {
+ .path_pending = netiucv_callback_connreq,
+ .path_complete = netiucv_callback_connack,
+ .path_severed = netiucv_callback_connrej,
+ .path_quiesced = netiucv_callback_connsusp,
+ .path_resumed = netiucv_callback_connres,
+ .message_pending = netiucv_callback_rx,
+ .message_complete = netiucv_callback_txdone
+};
+
/**
* Per connection profiling data
*/
@@ -92,9 +192,8 @@ struct connection_profile {
* Representation of one iucv connection
*/
struct iucv_connection {
- struct iucv_connection *next;
- iucv_handle_t handle;
- __u16 pathid;
+ struct list_head list;
+ struct iucv_path *path;
struct sk_buff *rx_buff;
struct sk_buff *tx_buff;
struct sk_buff_head collect_queue;
@@ -112,12 +211,9 @@ struct iucv_connection {
/**
* Linked list of all connection structs.
*/
-struct iucv_connection_struct {
- struct iucv_connection *iucv_connections;
- rwlock_t iucv_rwlock;
-};
-
-static struct iucv_connection_struct iucv_conns;
+static struct list_head iucv_connection_list =
+ LIST_HEAD_INIT(iucv_connection_list);
+static rwlock_t iucv_connection_rwlock = RW_LOCK_UNLOCKED;
/**
* Representation of event-data for the
@@ -142,11 +238,11 @@ struct netiucv_priv {
/**
* Link level header for a packet.
*/
-typedef struct ll_header_t {
- __u16 next;
-} ll_header;
+struct ll_header {
+ u16 next;
+};
-#define NETIUCV_HDRLEN (sizeof(ll_header))
+#define NETIUCV_HDRLEN (sizeof(struct ll_header))
#define NETIUCV_BUFSIZE_MAX 32768
#define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX
#define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN)
@@ -158,36 +254,26 @@ typedef struct ll_header_t {
* Compatibility macros for busy handling
* of network devices.
*/
-static __inline__ void netiucv_clear_busy(struct net_device *dev)
+static inline void netiucv_clear_busy(struct net_device *dev)
{
- clear_bit(0, &(((struct netiucv_priv *)dev->priv)->tbusy));
+ struct netiucv_priv *priv = netdev_priv(dev);
+ clear_bit(0, &priv->tbusy);
netif_wake_queue(dev);
}
-static __inline__ int netiucv_test_and_set_busy(struct net_device *dev)
+static inline int netiucv_test_and_set_busy(struct net_device *dev)
{
+ struct netiucv_priv *priv = netdev_priv(dev);
netif_stop_queue(dev);
- return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy);
+ return test_and_set_bit(0, &priv->tbusy);
}
-static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-static __u8 iucvMagic[16] = {
+static u8 iucvMagic[16] = {
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
};
/**
- * This mask means the 16-byte IUCV "magic" and the origin userid must
- * match exactly as specified in order to give connection_pending()
- * control.
- */
-static __u8 netiucv_mask[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-};
-
-/**
* Convert an iucv userId to its printable
* form (strip whitespace at end).
*
@@ -195,8 +281,7 @@ static __u8 netiucv_mask[] = {
*
* @returns The printable string (static data!!)
*/
-static __inline__ char *
-netiucv_printname(char *name)
+static inline char *netiucv_printname(char *name)
{
static char tmp[9];
char *p = tmp;
@@ -379,8 +464,7 @@ static debug_info_t *iucv_dbf_trace = NULL;
DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf);
-static void
-iucv_unregister_dbf_views(void)
+static void iucv_unregister_dbf_views(void)
{
if (iucv_dbf_setup)
debug_unregister(iucv_dbf_setup);
@@ -389,8 +473,7 @@ iucv_unregister_dbf_views(void)
if (iucv_dbf_trace)
debug_unregister(iucv_dbf_trace);
}
-static int
-iucv_register_dbf_views(void)
+static int iucv_register_dbf_views(void)
{
iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME,
IUCV_DBF_SETUP_PAGES,
@@ -422,125 +505,111 @@ iucv_register_dbf_views(void)
return 0;
}
-/**
+/*
* Callback-wrappers, called from lowlevel iucv layer.
- *****************************************************************************/
+ */
-static void
-netiucv_callback_rx(iucv_MessagePending *eib, void *pgm_data)
+static void netiucv_callback_rx(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+ struct iucv_connection *conn = path->private;
struct iucv_event ev;
ev.conn = conn;
- ev.data = (void *)eib;
-
+ ev.data = msg;
fsm_event(conn->fsm, CONN_EVENT_RX, &ev);
}
-static void
-netiucv_callback_txdone(iucv_MessageComplete *eib, void *pgm_data)
+static void netiucv_callback_txdone(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+ struct iucv_connection *conn = path->private;
struct iucv_event ev;
ev.conn = conn;
- ev.data = (void *)eib;
+ ev.data = msg;
fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev);
}
-static void
-netiucv_callback_connack(iucv_ConnectionComplete *eib, void *pgm_data)
+static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev);
+ fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn);
}
-static void
-netiucv_callback_connreq(iucv_ConnectionPending *eib, void *pgm_data)
+static int netiucv_callback_connreq(struct iucv_path *path,
+ u8 ipvmid[8], u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+ struct iucv_connection *conn = path->private;
struct iucv_event ev;
+ int rc;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);
+ if (memcmp(iucvMagic, ipuser, sizeof(ipuser)))
+ /* ipuser must match iucvMagic. */
+ return -EINVAL;
+ rc = -EINVAL;
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(conn, &iucv_connection_list, list) {
+ if (strncmp(ipvmid, conn->userid, 8))
+ continue;
+ /* Found a matching connection for this path. */
+ conn->path = path;
+ ev.conn = conn;
+ ev.data = path;
+ fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);
+ rc = 0;
+ }
+ read_unlock_bh(&iucv_connection_rwlock);
+ return rc;
}
-static void
-netiucv_callback_connrej(iucv_ConnectionSevered *eib, void *pgm_data)
+static void netiucv_callback_connrej(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, &ev);
+ fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, conn);
}
-static void
-netiucv_callback_connsusp(iucv_ConnectionQuiesced *eib, void *pgm_data)
+static void netiucv_callback_connsusp(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, &ev);
+ fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, conn);
}
-static void
-netiucv_callback_connres(iucv_ConnectionResumed *eib, void *pgm_data)
+static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_RES, &ev);
-}
-
-static iucv_interrupt_ops_t netiucv_ops = {
- .ConnectionPending = netiucv_callback_connreq,
- .ConnectionComplete = netiucv_callback_connack,
- .ConnectionSevered = netiucv_callback_connrej,
- .ConnectionQuiesced = netiucv_callback_connsusp,
- .ConnectionResumed = netiucv_callback_connres,
- .MessagePending = netiucv_callback_rx,
- .MessageComplete = netiucv_callback_txdone
-};
+ fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn);
+}
/**
* Dummy NOP action for all statemachines
*/
-static void
-fsm_action_nop(fsm_instance *fi, int event, void *arg)
+static void fsm_action_nop(fsm_instance *fi, int event, void *arg)
{
}
-/**
+/*
* Actions of the connection statemachine
- *****************************************************************************/
+ */
/**
- * Helper function for conn_action_rx()
- * Unpack a just received skb and hand it over to
- * upper layers.
+ * netiucv_unpack_skb
+ * @conn: The connection where this skb has been received.
+ * @pskb: The received skb.
*
- * @param conn The connection where this skb has been received.
- * @param pskb The received skb.
+ * Unpack a just received skb and hand it over to upper layers.
+ * Helper function for conn_action_rx.
*/
-//static __inline__ void
-static void
-netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb)
+static void netiucv_unpack_skb(struct iucv_connection *conn,
+ struct sk_buff *pskb)
{
struct net_device *dev = conn->netdev;
- struct netiucv_priv *privptr = dev->priv;
- __u16 offset = 0;
+ struct netiucv_priv *privptr = netdev_priv(dev);
+ u16 offset = 0;
skb_put(pskb, NETIUCV_HDRLEN);
pskb->dev = dev;
@@ -549,7 +618,7 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb)
while (1) {
struct sk_buff *skb;
- ll_header *header = (ll_header *)pskb->data;
+ struct ll_header *header = (struct ll_header *) pskb->data;
if (!header->next)
break;
@@ -595,40 +664,37 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb)
}
}
-static void
-conn_action_rx(fsm_instance *fi, int event, void *arg)
+static void conn_action_rx(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
- iucv_MessagePending *eib = (iucv_MessagePending *)ev->data;
- struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv;
-
- __u32 msglen = eib->ln1msg2.ipbfln1f;
+ struct iucv_message *msg = ev->data;
+ struct netiucv_priv *privptr = netdev_priv(conn->netdev);
int rc;
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
if (!conn->netdev) {
- /* FRITZ: How to tell iucv LL to drop the msg? */
+ iucv_message_reject(conn->path, msg);
PRINT_WARN("Received data for unlinked connection\n");
IUCV_DBF_TEXT(data, 2,
- "Received data for unlinked connection\n");
+ "Received data for unlinked connection\n");
return;
}
- if (msglen > conn->max_buffsize) {
- /* FRITZ: How to tell iucv LL to drop the msg? */
+ if (msg->length > conn->max_buffsize) {
+ iucv_message_reject(conn->path, msg);
privptr->stats.rx_dropped++;
PRINT_WARN("msglen %d > max_buffsize %d\n",
- msglen, conn->max_buffsize);
+ msg->length, conn->max_buffsize);
IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n",
- msglen, conn->max_buffsize);
+ msg->length, conn->max_buffsize);
return;
}
conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head;
conn->rx_buff->len = 0;
- rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls,
- conn->rx_buff->data, msglen, NULL, NULL, NULL);
- if (rc || msglen < 5) {
+ rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data,
+ msg->length, NULL);
+ if (rc || msg->length < 5) {
privptr->stats.rx_errors++;
PRINT_WARN("iucv_receive returned %08x\n", rc);
IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc);
@@ -637,26 +703,26 @@ conn_action_rx(fsm_instance *fi, int event, void *arg)
netiucv_unpack_skb(conn, conn->rx_buff);
}
-static void
-conn_action_txdone(fsm_instance *fi, int event, void *arg)
+static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
- iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data;
+ struct iucv_message *msg = ev->data;
+ struct iucv_message txmsg;
struct netiucv_priv *privptr = NULL;
- /* Shut up, gcc! skb is always below 2G. */
- __u32 single_flag = eib->ipmsgtag;
- __u32 txbytes = 0;
- __u32 txpackets = 0;
- __u32 stat_maxcq = 0;
+ u32 single_flag = msg->tag;
+ u32 txbytes = 0;
+ u32 txpackets = 0;
+ u32 stat_maxcq = 0;
struct sk_buff *skb;
unsigned long saveflags;
- ll_header header;
+ struct ll_header header;
+ int rc;
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
- if (conn && conn->netdev && conn->netdev->priv)
- privptr = (struct netiucv_priv *)conn->netdev->priv;
+ if (conn && conn->netdev)
+ privptr = netdev_priv(conn->netdev);
conn->prof.tx_pending--;
if (single_flag) {
if ((skb = skb_dequeue(&conn->commit_queue))) {
@@ -688,56 +754,55 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg)
conn->prof.maxmulti = conn->collect_len;
conn->collect_len = 0;
spin_unlock_irqrestore(&conn->collect_lock, saveflags);
- if (conn->tx_buff->len) {
- int rc;
-
- header.next = 0;
- memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header,
- NETIUCV_HDRLEN);
+ if (conn->tx_buff->len == 0) {
+ fsm_newstate(fi, CONN_STATE_IDLE);
+ return;
+ }
- conn->prof.send_stamp = xtime;
- rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0,
+ header.next = 0;
+ memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
+ conn->prof.send_stamp = xtime;
+ txmsg.class = 0;
+ txmsg.tag = 0;
+ rc = iucv_message_send(conn->path, &txmsg, 0, 0,
conn->tx_buff->data, conn->tx_buff->len);
- conn->prof.doios_multi++;
- conn->prof.txlen += conn->tx_buff->len;
- conn->prof.tx_pending++;
- if (conn->prof.tx_pending > conn->prof.tx_max_pending)
- conn->prof.tx_max_pending = conn->prof.tx_pending;
- if (rc) {
- conn->prof.tx_pending--;
- fsm_newstate(fi, CONN_STATE_IDLE);
- if (privptr)
- privptr->stats.tx_errors += txpackets;
- PRINT_WARN("iucv_send returned %08x\n", rc);
- IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
- } else {
- if (privptr) {
- privptr->stats.tx_packets += txpackets;
- privptr->stats.tx_bytes += txbytes;
- }
- if (stat_maxcq > conn->prof.maxcqueue)
- conn->prof.maxcqueue = stat_maxcq;
- }
- } else
+ conn->prof.doios_multi++;
+ conn->prof.txlen += conn->tx_buff->len;
+ conn->prof.tx_pending++;
+ if (conn->prof.tx_pending > conn->prof.tx_max_pending)
+ conn->prof.tx_max_pending = conn->prof.tx_pending;
+ if (rc) {
+ conn->prof.tx_pending--;
fsm_newstate(fi, CONN_STATE_IDLE);
+ if (privptr)
+ privptr->stats.tx_errors += txpackets;
+ PRINT_WARN("iucv_send returned %08x\n", rc);
+ IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
+ } else {
+ if (privptr) {
+ privptr->stats.tx_packets += txpackets;
+ privptr->stats.tx_bytes += txbytes;
+ }
+ if (stat_maxcq > conn->prof.maxcqueue)
+ conn->prof.maxcqueue = stat_maxcq;
+ }
}
-static void
-conn_action_connaccept(fsm_instance *fi, int event, void *arg)
+static void conn_action_connaccept(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
- iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data;
+ struct iucv_path *path = ev->data;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+ struct netiucv_priv *privptr = netdev_priv(netdev);
int rc;
- __u16 msglimit;
- __u8 udata[16];
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0,
- conn->handle, conn, NULL, &msglimit);
+ conn->path = path;
+ path->msglim = NETIUCV_QUEUELEN_DEFAULT;
+ path->flags = 0;
+ rc = iucv_path_accept(path, &netiucv_handler, NULL, conn);
if (rc) {
PRINT_WARN("%s: IUCV accept failed with error %d\n",
netdev->name, rc);
@@ -745,183 +810,126 @@ conn_action_connaccept(fsm_instance *fi, int event, void *arg)
return;
}
fsm_newstate(fi, CONN_STATE_IDLE);
- conn->pathid = eib->ippathid;
- netdev->tx_queue_len = msglimit;
+ netdev->tx_queue_len = conn->path->msglim;
fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);
}
-static void
-conn_action_connreject(fsm_instance *fi, int event, void *arg)
+static void conn_action_connreject(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
- struct net_device *netdev = conn->netdev;
- iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data;
- __u8 udata[16];
+ struct iucv_event *ev = arg;
+ struct iucv_path *path = ev->data;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
- iucv_sever(eib->ippathid, udata);
- if (eib->ippathid != conn->pathid) {
- PRINT_INFO("%s: IR Connection Pending; "
- "pathid %d does not match original pathid %d\n",
- netdev->name, eib->ippathid, conn->pathid);
- IUCV_DBF_TEXT_(data, 2,
- "connreject: IR pathid %d, conn. pathid %d\n",
- eib->ippathid, conn->pathid);
- iucv_sever(conn->pathid, udata);
- }
+ iucv_path_sever(path, NULL);
}
-static void
-conn_action_connack(fsm_instance *fi, int event, void *arg)
+static void conn_action_connack(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
- iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data;
+ struct iucv_connection *conn = arg;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+ struct netiucv_priv *privptr = netdev_priv(netdev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
fsm_deltimer(&conn->timer);
fsm_newstate(fi, CONN_STATE_IDLE);
- if (eib->ippathid != conn->pathid) {
- PRINT_INFO("%s: IR Connection Complete; "
- "pathid %d does not match original pathid %d\n",
- netdev->name, eib->ippathid, conn->pathid);
- IUCV_DBF_TEXT_(data, 2,
- "connack: IR pathid %d, conn. pathid %d\n",
- eib->ippathid, conn->pathid);
- conn->pathid = eib->ippathid;
- }
- netdev->tx_queue_len = eib->ipmsglim;
+ netdev->tx_queue_len = conn->path->msglim;
fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);
}
-static void
-conn_action_conntimsev(fsm_instance *fi, int event, void *arg)
+static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg)
{
- struct iucv_connection *conn = (struct iucv_connection *)arg;
- __u8 udata[16];
+ struct iucv_connection *conn = arg;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
fsm_deltimer(&conn->timer);
- iucv_sever(conn->pathid, udata);
+ iucv_path_sever(conn->path, NULL);
fsm_newstate(fi, CONN_STATE_STARTWAIT);
}
-static void
-conn_action_connsever(fsm_instance *fi, int event, void *arg)
+static void conn_action_connsever(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
+ struct iucv_connection *conn = arg;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
- __u8 udata[16];
+ struct netiucv_priv *privptr = netdev_priv(netdev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
fsm_deltimer(&conn->timer);
- iucv_sever(conn->pathid, udata);
+ iucv_path_sever(conn->path, NULL);
PRINT_INFO("%s: Remote dropped connection\n", netdev->name);
IUCV_DBF_TEXT(data, 2,
- "conn_action_connsever: Remote dropped connection\n");
+ "conn_action_connsever: Remote dropped connection\n");
fsm_newstate(fi, CONN_STATE_STARTWAIT);
fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
}
-static void
-conn_action_start(fsm_instance *fi, int event, void *arg)
+static void conn_action_start(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
- __u16 msglimit;
+ struct iucv_connection *conn = arg;
int rc;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if (!conn->handle) {
- IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n");
- conn->handle =
- iucv_register_program(iucvMagic, conn->userid,
- netiucv_mask,
- &netiucv_ops, conn);
- fsm_newstate(fi, CONN_STATE_STARTWAIT);
- if (!conn->handle) {
- fsm_newstate(fi, CONN_STATE_REGERR);
- conn->handle = NULL;
- IUCV_DBF_TEXT(setup, 2,
- "NULL from iucv_register_program\n");
- return;
- }
-
- PRINT_DEBUG("%s('%s'): registered successfully\n",
- conn->netdev->name, conn->userid);
- }
-
+ fsm_newstate(fi, CONN_STATE_STARTWAIT);
PRINT_DEBUG("%s('%s'): connecting ...\n",
- conn->netdev->name, conn->userid);
+ conn->netdev->name, conn->userid);
- /* We must set the state before calling iucv_connect because the callback
- * handler could be called at any point after the connection request is
- * sent */
+ /*
+ * We must set the state before calling iucv_connect because the
+ * callback handler could be called at any point after the connection
+ * request is sent
+ */
fsm_newstate(fi, CONN_STATE_SETUPWAIT);
- rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic,
- conn->userid, iucv_host, 0, NULL, &msglimit,
- conn->handle, conn);
+ conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL);
+ rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid,
+ NULL, iucvMagic, conn);
switch (rc) {
- case 0:
- conn->netdev->tx_queue_len = msglimit;
- fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
- CONN_EVENT_TIMER, conn);
- return;
- case 11:
- PRINT_INFO("%s: User %s is currently not available.\n",
- conn->netdev->name,
- netiucv_printname(conn->userid));
- fsm_newstate(fi, CONN_STATE_STARTWAIT);
- return;
- case 12:
- PRINT_INFO("%s: User %s is currently not ready.\n",
- conn->netdev->name,
- netiucv_printname(conn->userid));
- fsm_newstate(fi, CONN_STATE_STARTWAIT);
- return;
- case 13:
- PRINT_WARN("%s: Too many IUCV connections.\n",
- conn->netdev->name);
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
- case 14:
- PRINT_WARN(
- "%s: User %s has too many IUCV connections.\n",
- conn->netdev->name,
- netiucv_printname(conn->userid));
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
- case 15:
- PRINT_WARN(
- "%s: No IUCV authorization in CP directory.\n",
- conn->netdev->name);
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
- default:
- PRINT_WARN("%s: iucv_connect returned error %d\n",
- conn->netdev->name, rc);
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
+ case 0:
+ conn->netdev->tx_queue_len = conn->path->msglim;
+ fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
+ CONN_EVENT_TIMER, conn);
+ return;
+ case 11:
+ PRINT_INFO("%s: User %s is currently not available.\n",
+ conn->netdev->name,
+ netiucv_printname(conn->userid));
+ fsm_newstate(fi, CONN_STATE_STARTWAIT);
+ break;
+ case 12:
+ PRINT_INFO("%s: User %s is currently not ready.\n",
+ conn->netdev->name,
+ netiucv_printname(conn->userid));
+ fsm_newstate(fi, CONN_STATE_STARTWAIT);
+ break;
+ case 13:
+ PRINT_WARN("%s: Too many IUCV connections.\n",
+ conn->netdev->name);
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
+ case 14:
+ PRINT_WARN("%s: User %s has too many IUCV connections.\n",
+ conn->netdev->name,
+ netiucv_printname(conn->userid));
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
+ case 15:
+ PRINT_WARN("%s: No IUCV authorization in CP directory.\n",
+ conn->netdev->name);
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
+ default:
+ PRINT_WARN("%s: iucv_connect returned error %d\n",
+ conn->netdev->name, rc);
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
}
IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc);
- IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n");
- iucv_unregister_program(conn->handle);
- conn->handle = NULL;
+ kfree(conn->path);
+ conn->path = NULL;
}
-static void
-netiucv_purge_skb_queue(struct sk_buff_head *q)
+static void netiucv_purge_skb_queue(struct sk_buff_head *q)
{
struct sk_buff *skb;
@@ -931,36 +939,34 @@ netiucv_purge_skb_queue(struct sk_buff_head *q)
}
}
-static void
-conn_action_stop(fsm_instance *fi, int event, void *arg)
+static void conn_action_stop(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+ struct netiucv_priv *privptr = netdev_priv(netdev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
fsm_deltimer(&conn->timer);
fsm_newstate(fi, CONN_STATE_STOPPED);
netiucv_purge_skb_queue(&conn->collect_queue);
- if (conn->handle)
- IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n");
- iucv_unregister_program(conn->handle);
- conn->handle = NULL;
+ if (conn->path) {
+ IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n");
+ iucv_path_sever(conn->path, iucvMagic);
+ kfree(conn->path);
+ conn->path = NULL;
+ }
netiucv_purge_skb_queue(&conn->commit_queue);
fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
}
-static void
-conn_action_inval(fsm_instance *fi, int event, void *arg)
+static void conn_action_inval(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
+ struct iucv_connection *conn = arg;
struct net_device *netdev = conn->netdev;
- PRINT_WARN("%s: Cannot connect without username\n",
- netdev->name);
+ PRINT_WARN("%s: Cannot connect without username\n", netdev->name);
IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n");
}
@@ -999,29 +1005,27 @@ static const fsm_node conn_fsm[] = {
static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);
-/**
+/*
* Actions for interface - statemachine.
- *****************************************************************************/
+ */
/**
- * Startup connection by sending CONN_EVENT_START to it.
+ * dev_action_start
+ * @fi: An instance of an interface statemachine.
+ * @event: The event, just happened.
+ * @arg: Generic pointer, casted from struct net_device * upon call.
*
- * @param fi An instance of an interface statemachine.
- * @param event The event, just happened.
- * @param arg Generic pointer, casted from struct net_device * upon call.
+ * Startup connection by sending CONN_EVENT_START to it.
*/
-static void
-dev_action_start(fsm_instance *fi, int event, void *arg)
+static void dev_action_start(fsm_instance *fi, int event, void *arg)
{
- struct net_device *dev = (struct net_device *)arg;
- struct netiucv_priv *privptr = dev->priv;
- struct iucv_event ev;
+ struct net_device *dev = arg;
+ struct netiucv_priv *privptr = netdev_priv(dev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- ev.conn = privptr->conn;
fsm_newstate(fi, DEV_STATE_STARTWAIT);
- fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev);
+ fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn);
}
/**
@@ -1034,8 +1038,8 @@ dev_action_start(fsm_instance *fi, int event, void *arg)
static void
dev_action_stop(fsm_instance *fi, int event, void *arg)
{
- struct net_device *dev = (struct net_device *)arg;
- struct netiucv_priv *privptr = dev->priv;
+ struct net_device *dev = arg;
+ struct netiucv_priv *privptr = netdev_priv(dev);
struct iucv_event ev;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
@@ -1057,8 +1061,8 @@ dev_action_stop(fsm_instance *fi, int event, void *arg)
static void
dev_action_connup(fsm_instance *fi, int event, void *arg)
{
- struct net_device *dev = (struct net_device *)arg;
- struct netiucv_priv *privptr = dev->priv;
+ struct net_device *dev = arg;
+ struct netiucv_priv *privptr = netdev_priv(dev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
@@ -1131,11 +1135,13 @@ static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node);
*
* @return 0 on success, -ERRNO on failure. (Never fails.)
*/
-static int
-netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
+static int netiucv_transmit_skb(struct iucv_connection *conn,
+ struct sk_buff *skb)
+{
+ struct iucv_message msg;
unsigned long saveflags;
- ll_header header;
- int rc = 0;
+ struct ll_header header;
+ int rc;
if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) {
int l = skb->len + NETIUCV_HDRLEN;
@@ -1145,11 +1151,12 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
(conn->max_buffsize - NETIUCV_HDRLEN)) {
rc = -EBUSY;
IUCV_DBF_TEXT(data, 2,
- "EBUSY from netiucv_transmit_skb\n");
+ "EBUSY from netiucv_transmit_skb\n");
} else {
atomic_inc(&skb->users);
skb_queue_tail(&conn->collect_queue, skb);
conn->collect_len += l;
+ rc = 0;
}
spin_unlock_irqrestore(&conn->collect_lock, saveflags);
} else {
@@ -1188,9 +1195,10 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
fsm_newstate(conn->fsm, CONN_STATE_TX);
conn->prof.send_stamp = xtime;
- rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */,
- 0, nskb->data, nskb->len);
- /* Shut up, gcc! nskb is always below 2G. */
+ msg.tag = 1;
+ msg.class = 0;
+ rc = iucv_message_send(conn->path, &msg, 0, 0,
+ nskb->data, nskb->len);
conn->prof.doios_single++;
conn->prof.txlen += skb->len;
conn->prof.tx_pending++;
@@ -1200,7 +1208,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
struct netiucv_priv *privptr;
fsm_newstate(conn->fsm, CONN_STATE_IDLE);
conn->prof.tx_pending--;
- privptr = (struct netiucv_priv *)conn->netdev->priv;
+ privptr = netdev_priv(conn->netdev);
if (privptr)
privptr->stats.tx_errors++;
if (copied)
@@ -1226,9 +1234,9 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
return rc;
}
-/**
+/*
* Interface API for upper network layers
- *****************************************************************************/
+ */
/**
* Open an interface.
@@ -1238,9 +1246,11 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
*
* @return 0 on success, -ERRNO on failure. (Never fails.)
*/
-static int
-netiucv_open(struct net_device *dev) {
- fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START,dev);
+static int netiucv_open(struct net_device *dev)
+{
+ struct netiucv_priv *priv = netdev_priv(dev);
+
+ fsm_event(priv->fsm, DEV_EVENT_START, dev);
return 0;
}
@@ -1252,9 +1262,11 @@ netiucv_open(struct net_device *dev) {
*
* @return 0 on success, -ERRNO on failure. (Never fails.)
*/
-static int
-netiucv_close(struct net_device *dev) {
- fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev);
+static int netiucv_close(struct net_device *dev)
+{
+ struct netiucv_priv *priv = netdev_priv(dev);
+
+ fsm_event(priv->fsm, DEV_EVENT_STOP, dev);
return 0;
}
@@ -1271,8 +1283,8 @@ netiucv_close(struct net_device *dev) {
*/
static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
{
- int rc = 0;
- struct netiucv_priv *privptr = dev->priv;
+ struct netiucv_priv *privptr = netdev_priv(dev);
+ int rc;
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
/**
@@ -1312,40 +1324,41 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
return -EBUSY;
}
dev->trans_start = jiffies;
- if (netiucv_transmit_skb(privptr->conn, skb))
- rc = 1;
+ rc = netiucv_transmit_skb(privptr->conn, skb) != 0;
netiucv_clear_busy(dev);
return rc;
}
/**
- * Returns interface statistics of a device.
+ * netiucv_stats
+ * @dev: Pointer to interface struct.
*
- * @param dev Pointer to interface struct.
+ * Returns interface statistics of a device.
*
- * @return Pointer to stats struct of this interface.
+ * Returns pointer to stats struct of this interface.
*/
-static struct net_device_stats *
-netiucv_stats (struct net_device * dev)
+static struct net_device_stats *netiucv_stats (struct net_device * dev)
{
+ struct netiucv_priv *priv = netdev_priv(dev);
+
IUCV_DBF_TEXT(trace, 5, __FUNCTION__);
- return &((struct netiucv_priv *)dev->priv)->stats;
+ return &priv->stats;
}
/**
- * Sets MTU of an interface.
+ * netiucv_change_mtu
+ * @dev: Pointer to interface struct.
+ * @new_mtu: The new MTU to use for this interface.
*
- * @param dev Pointer to interface struct.
- * @param new_mtu The new MTU to use for this interface.
+ * Sets MTU of an interface.
*
- * @return 0 on success, -EINVAL if MTU is out of valid range.
+ * Returns 0 on success, -EINVAL if MTU is out of valid range.
* (valid range is 576 .. NETIUCV_MTU_MAX).
*/
-static int
-netiucv_change_mtu (struct net_device * dev, int new_mtu)
+static int netiucv_change_mtu(struct net_device * dev, int new_mtu)
{
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if ((new_mtu < 576) || (new_mtu > NETIUCV_MTU_MAX)) {
+ if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) {
IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n");
return -EINVAL;
}
@@ -1353,12 +1366,12 @@ netiucv_change_mtu (struct net_device * dev, int new_mtu)
return 0;
}
-/**
+/*
* attributes in sysfs
- *****************************************************************************/
+ */
-static ssize_t
-user_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t user_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1366,8 +1379,8 @@ user_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid));
}
-static ssize_t
-user_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t user_write(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
struct net_device *ndev = priv->conn->netdev;
@@ -1375,80 +1388,70 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf,
char *tmp;
char username[9];
int i;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
+ struct iucv_connection *cp;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if (count>9) {
- PRINT_WARN("netiucv: username too long (%d)!\n", (int)count);
+ if (count > 9) {
+ PRINT_WARN("netiucv: username too long (%d)!\n", (int) count);
IUCV_DBF_TEXT_(setup, 2,
- "%d is length of username\n", (int)count);
+ "%d is length of username\n", (int) count);
return -EINVAL;
}
tmp = strsep((char **) &buf, "\n");
- for (i=0, p=tmp; i<8 && *p; i++, p++) {
- if (isalnum(*p) || (*p == '$'))
+ for (i = 0, p = tmp; i < 8 && *p; i++, p++) {
+ if (isalnum(*p) || (*p == '$')) {
username[i]= toupper(*p);
- else if (*p == '\n') {
+ continue;
+ }
+ if (*p == '\n') {
/* trailing lf, grr */
break;
- } else {
- PRINT_WARN("netiucv: Invalid char %c in username!\n",
- *p);
- IUCV_DBF_TEXT_(setup, 2,
- "username: invalid character %c\n",
- *p);
- return -EINVAL;
}
+ PRINT_WARN("netiucv: Invalid char %c in username!\n", *p);
+ IUCV_DBF_TEXT_(setup, 2,
+ "username: invalid character %c\n", *p);
+ return -EINVAL;
}
- while (i<8)
+ while (i < 8)
username[i++] = ' ';
username[8] = '\0';
- if (memcmp(username, priv->conn->userid, 9)) {
- /* username changed */
- if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
- PRINT_WARN(
- "netiucv: device %s active, connected to %s\n",
- dev->bus_id, priv->conn->userid);
- PRINT_WARN("netiucv: user cannot be updated\n");
- IUCV_DBF_TEXT(setup, 2, "user_write: device active\n");
- return -EBUSY;
+ if (memcmp(username, priv->conn->userid, 9) &&
+ (ndev->flags & (IFF_UP | IFF_RUNNING))) {
+ /* username changed while the interface is active. */
+ PRINT_WARN("netiucv: device %s active, connected to %s\n",
+ dev->bus_id, priv->conn->userid);
+ PRINT_WARN("netiucv: user cannot be updated\n");
+ IUCV_DBF_TEXT(setup, 2, "user_write: device active\n");
+ return -EBUSY;
+ }
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(cp, &iucv_connection_list, list) {
+ if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) {
+ read_unlock_bh(&iucv_connection_rwlock);
+ PRINT_WARN("netiucv: Connection to %s already "
+ "exists\n", username);
+ return -EEXIST;
}
}
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- if (!strncmp(username, (*clist)->userid, 9) ||
- ((*clist)->netdev != ndev))
- break;
- clist = &((*clist)->next);
- }
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
- if (*clist) {
- PRINT_WARN("netiucv: Connection to %s already exists\n",
- username);
- return -EEXIST;
- }
+ read_unlock_bh(&iucv_connection_rwlock);
memcpy(priv->conn->userid, username, 9);
-
return count;
-
}
static DEVICE_ATTR(user, 0644, user_show, user_write);
-static ssize_t
-buffer_show (struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct netiucv_priv *priv = dev->driver_data;
+static ssize_t buffer_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
+{ struct netiucv_priv *priv = dev->driver_data;
IUCV_DBF_TEXT(trace, 5, __FUNCTION__);
return sprintf(buf, "%d\n", priv->conn->max_buffsize);
}
-static ssize_t
-buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t buffer_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
struct net_device *ndev = priv->conn->netdev;
@@ -1502,8 +1505,8 @@ buffer_write (struct device *dev, struct device_attribute *attr, const char *buf
static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
-static ssize_t
-dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1513,8 +1516,8 @@ dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL);
-static ssize_t
-conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t conn_fsm_show (struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1524,8 +1527,8 @@ conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL);
-static ssize_t
-maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t maxmulti_show (struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1533,8 +1536,9 @@ maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti);
}
-static ssize_t
-maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t maxmulti_write (struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1545,8 +1549,8 @@ maxmulti_write (struct device *dev, struct device_attribute *attr, const char *b
static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write);
-static ssize_t
-maxcq_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1554,8 +1558,8 @@ maxcq_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue);
}
-static ssize_t
-maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1566,8 +1570,8 @@ maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write);
-static ssize_t
-sdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1575,8 +1579,8 @@ sdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.doios_single);
}
-static ssize_t
-sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1587,8 +1591,8 @@ sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write);
-static ssize_t
-mdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1596,8 +1600,8 @@ mdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi);
}
-static ssize_t
-mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1608,8 +1612,8 @@ mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write);
-static ssize_t
-txlen_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txlen_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1617,8 +1621,8 @@ txlen_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.txlen);
}
-static ssize_t
-txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txlen_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1629,8 +1633,8 @@ txlen_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write);
-static ssize_t
-txtime_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txtime_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1638,8 +1642,8 @@ txtime_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.tx_time);
}
-static ssize_t
-txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txtime_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1650,8 +1654,8 @@ txtime_write (struct device *dev, struct device_attribute *attr, const char *buf
static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write);
-static ssize_t
-txpend_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txpend_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1659,8 +1663,8 @@ txpend_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending);
}
-static ssize_t
-txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txpend_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1671,8 +1675,8 @@ txpend_write (struct device *dev, struct device_attribute *attr, const char *buf
static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write);
-static ssize_t
-txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1680,8 +1684,8 @@ txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending);
}
-static ssize_t
-txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1721,8 +1725,7 @@ static struct attribute_group netiucv_stat_attr_group = {
.attrs = netiucv_stat_attrs,
};
-static inline int
-netiucv_add_files(struct device *dev)
+static inline int netiucv_add_files(struct device *dev)
{
int ret;
@@ -1736,18 +1739,16 @@ netiucv_add_files(struct device *dev)
return ret;
}
-static inline void
-netiucv_remove_files(struct device *dev)
+static inline void netiucv_remove_files(struct device *dev)
{
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group);
sysfs_remove_group(&dev->kobj, &netiucv_attr_group);
}
-static int
-netiucv_register_device(struct net_device *ndev)
+static int netiucv_register_device(struct net_device *ndev)
{
- struct netiucv_priv *priv = ndev->priv;
+ struct netiucv_priv *priv = netdev_priv(ndev);
struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
int ret;
@@ -1786,8 +1787,7 @@ out_unreg:
return ret;
}
-static void
-netiucv_unregister_device(struct device *dev)
+static void netiucv_unregister_device(struct device *dev)
{
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
netiucv_remove_files(dev);
@@ -1798,107 +1798,89 @@ netiucv_unregister_device(struct device *dev)
* Allocate and initialize a new connection structure.
* Add it to the list of netiucv connections;
*/
-static struct iucv_connection *
-netiucv_new_connection(struct net_device *dev, char *username)
-{
- unsigned long flags;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- struct iucv_connection *conn =
- kzalloc(sizeof(struct iucv_connection), GFP_KERNEL);
-
- if (conn) {
- skb_queue_head_init(&conn->collect_queue);
- skb_queue_head_init(&conn->commit_queue);
- spin_lock_init(&conn->collect_lock);
- conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
- conn->netdev = dev;
-
- conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,
- GFP_KERNEL | GFP_DMA);
- if (!conn->rx_buff) {
- kfree(conn);
- return NULL;
- }
- conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,
- GFP_KERNEL | GFP_DMA);
- if (!conn->tx_buff) {
- kfree_skb(conn->rx_buff);
- kfree(conn);
- return NULL;
- }
- conn->fsm = init_fsm("netiucvconn", conn_state_names,
- conn_event_names, NR_CONN_STATES,
- NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN,
- GFP_KERNEL);
- if (!conn->fsm) {
- kfree_skb(conn->tx_buff);
- kfree_skb(conn->rx_buff);
- kfree(conn);
- return NULL;
- }
- fsm_settimer(conn->fsm, &conn->timer);
- fsm_newstate(conn->fsm, CONN_STATE_INVALID);
-
- if (username) {
- memcpy(conn->userid, username, 9);
- fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
- }
+static struct iucv_connection *netiucv_new_connection(struct net_device *dev,
+ char *username)
+{
+ struct iucv_connection *conn;
- write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- conn->next = *clist;
- *clist = conn;
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+ if (!conn)
+ goto out;
+ skb_queue_head_init(&conn->collect_queue);
+ skb_queue_head_init(&conn->commit_queue);
+ spin_lock_init(&conn->collect_lock);
+ conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
+ conn->netdev = dev;
+
+ conn->rx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA);
+ if (!conn->rx_buff)
+ goto out_conn;
+ conn->tx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA);
+ if (!conn->tx_buff)
+ goto out_rx;
+ conn->fsm = init_fsm("netiucvconn", conn_state_names,
+ conn_event_names, NR_CONN_STATES,
+ NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN,
+ GFP_KERNEL);
+ if (!conn->fsm)
+ goto out_tx;
+
+ fsm_settimer(conn->fsm, &conn->timer);
+ fsm_newstate(conn->fsm, CONN_STATE_INVALID);
+
+ if (username) {
+ memcpy(conn->userid, username, 9);
+ fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
}
+
+ write_lock_bh(&iucv_connection_rwlock);
+ list_add_tail(&conn->list, &iucv_connection_list);
+ write_unlock_bh(&iucv_connection_rwlock);
return conn;
+
+out_tx:
+ kfree_skb(conn->tx_buff);
+out_rx:
+ kfree_skb(conn->rx_buff);
+out_conn:
+ kfree(conn);
+out:
+ return NULL;
}
/**
* Release a connection structure and remove it from the
* list of netiucv connections.
*/
-static void
-netiucv_remove_connection(struct iucv_connection *conn)
+static void netiucv_remove_connection(struct iucv_connection *conn)
{
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
-
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if (conn == NULL)
- return;
- write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- if (*clist == conn) {
- *clist = conn->next;
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
- if (conn->handle) {
- iucv_unregister_program(conn->handle);
- conn->handle = NULL;
- }
- fsm_deltimer(&conn->timer);
- kfree_fsm(conn->fsm);
- kfree_skb(conn->rx_buff);
- kfree_skb(conn->tx_buff);
- return;
- }
- clist = &((*clist)->next);
+ write_lock_bh(&iucv_connection_rwlock);
+ list_del_init(&conn->list);
+ write_unlock_bh(&iucv_connection_rwlock);
+ if (conn->path) {
+ iucv_path_sever(conn->path, iucvMagic);
+ kfree(conn->path);
+ conn->path = NULL;
}
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ fsm_deltimer(&conn->timer);
+ kfree_fsm(conn->fsm);
+ kfree_skb(conn->rx_buff);
+ kfree_skb(conn->tx_buff);
}
/**
* Release everything of a net device.
*/
-static void
-netiucv_free_netdevice(struct net_device *dev)
+static void netiucv_free_netdevice(struct net_device *dev)
{
- struct netiucv_priv *privptr;
+ struct netiucv_priv *privptr = netdev_priv(dev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (!dev)
return;
- privptr = (struct netiucv_priv *)dev->priv;
if (privptr) {
if (privptr->conn)
netiucv_remove_connection(privptr->conn);
@@ -1913,11 +1895,8 @@ netiucv_free_netdevice(struct net_device *dev)
/**
* Initialize a net device. (Called from kernel in alloc_netdev())
*/
-static void
-netiucv_setup_netdevice(struct net_device *dev)
+static void netiucv_setup_netdevice(struct net_device *dev)
{
- memset(dev->priv, 0, sizeof(struct netiucv_priv));
-
dev->mtu = NETIUCV_MTU_DEFAULT;
dev->hard_start_xmit = netiucv_tx;
dev->open = netiucv_open;
@@ -1936,8 +1915,7 @@ netiucv_setup_netdevice(struct net_device *dev)
/**
* Allocate and initialize everything of a net device.
*/
-static struct net_device *
-netiucv_init_netdevice(char *username)
+static struct net_device *netiucv_init_netdevice(char *username)
{
struct netiucv_priv *privptr;
struct net_device *dev;
@@ -1946,40 +1924,40 @@ netiucv_init_netdevice(char *username)
netiucv_setup_netdevice);
if (!dev)
return NULL;
- if (dev_alloc_name(dev, dev->name) < 0) {
- free_netdev(dev);
- return NULL;
- }
+ if (dev_alloc_name(dev, dev->name) < 0)
+ goto out_netdev;
- privptr = (struct netiucv_priv *)dev->priv;
+ privptr = netdev_priv(dev);
privptr->fsm = init_fsm("netiucvdev", dev_state_names,
dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
- if (!privptr->fsm) {
- free_netdev(dev);
- return NULL;
- }
+ if (!privptr->fsm)
+ goto out_netdev;
+
privptr->conn = netiucv_new_connection(dev, username);
if (!privptr->conn) {
- kfree_fsm(privptr->fsm);
- free_netdev(dev);
IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n");
- return NULL;
+ goto out_fsm;
}
fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
-
return dev;
+
+out_fsm:
+ kfree_fsm(privptr->fsm);
+out_netdev:
+ free_netdev(dev);
+ return NULL;
}
-static ssize_t
-conn_write(struct device_driver *drv, const char *buf, size_t count)
+static ssize_t conn_write(struct device_driver *drv,
+ const char *buf, size_t count)
{
- char *p;
+ const char *p;
char username[9];
- int i, ret;
+ int i, rc;
struct net_device *dev;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
+ struct netiucv_priv *priv;
+ struct iucv_connection *cp;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (count>9) {
@@ -1988,83 +1966,82 @@ conn_write(struct device_driver *drv, const char *buf, size_t count)
return -EINVAL;
}
- for (i=0, p=(char *)buf; i<8 && *p; i++, p++) {
- if (isalnum(*p) || (*p == '$'))
- username[i]= toupper(*p);
- else if (*p == '\n') {
+ for (i = 0, p = buf; i < 8 && *p; i++, p++) {
+ if (isalnum(*p) || *p == '$') {
+ username[i] = toupper(*p);
+ continue;
+ }
+ if (*p == '\n')
/* trailing lf, grr */
break;
- } else {
- PRINT_WARN("netiucv: Invalid character in username!\n");
- IUCV_DBF_TEXT_(setup, 2,
- "conn_write: invalid character %c\n", *p);
- return -EINVAL;
- }
+ PRINT_WARN("netiucv: Invalid character in username!\n");
+ IUCV_DBF_TEXT_(setup, 2,
+ "conn_write: invalid character %c\n", *p);
+ return -EINVAL;
}
- while (i<8)
+ while (i < 8)
username[i++] = ' ';
username[8] = '\0';
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- if (!strncmp(username, (*clist)->userid, 9))
- break;
- clist = &((*clist)->next);
- }
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
- if (*clist) {
- PRINT_WARN("netiucv: Connection to %s already exists\n",
- username);
- return -EEXIST;
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(cp, &iucv_connection_list, list) {
+ if (!strncmp(username, cp->userid, 9)) {
+ read_unlock_bh(&iucv_connection_rwlock);
+ PRINT_WARN("netiucv: Connection to %s already "
+ "exists\n", username);
+ return -EEXIST;
+ }
}
+ read_unlock_bh(&iucv_connection_rwlock);
+
dev = netiucv_init_netdevice(username);
if (!dev) {
- PRINT_WARN(
- "netiucv: Could not allocate network device structure "
- "for user '%s'\n", netiucv_printname(username));
+ PRINT_WARN("netiucv: Could not allocate network device "
+ "structure for user '%s'\n",
+ netiucv_printname(username));
IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n");
return -ENODEV;
}
- if ((ret = netiucv_register_device(dev))) {
+ rc = netiucv_register_device(dev);
+ if (rc) {
IUCV_DBF_TEXT_(setup, 2,
- "ret %d from netiucv_register_device\n", ret);
+ "ret %d from netiucv_register_device\n", rc);
goto out_free_ndev;
}
/* sysfs magic */
- SET_NETDEV_DEV(dev,
- (struct device*)((struct netiucv_priv*)dev->priv)->dev);
+ priv = netdev_priv(dev);
+ SET_NETDEV_DEV(dev, priv->dev);
- if ((ret = register_netdev(dev))) {
- netiucv_unregister_device((struct device*)
- ((struct netiucv_priv*)dev->priv)->dev);
- goto out_free_ndev;
- }
+ rc = register_netdev(dev);
+ if (rc)
+ goto out_unreg;
PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username));
return count;
+out_unreg:
+ netiucv_unregister_device(priv->dev);
out_free_ndev:
PRINT_WARN("netiucv: Could not register '%s'\n", dev->name);
IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n");
netiucv_free_netdevice(dev);
- return ret;
+ return rc;
}
-DRIVER_ATTR(connection, 0200, NULL, conn_write);
+static DRIVER_ATTR(connection, 0200, NULL, conn_write);
-static ssize_t
-remove_write (struct device_driver *drv, const char *buf, size_t count)
+static ssize_t remove_write (struct device_driver *drv,
+ const char *buf, size_t count)
{
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
+ struct iucv_connection *cp;
struct net_device *ndev;
struct netiucv_priv *priv;
struct device *dev;
char name[IFNAMSIZ];
- char *p;
+ const char *p;
int i;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
@@ -2072,33 +2049,27 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
if (count >= IFNAMSIZ)
count = IFNAMSIZ - 1;;
- for (i=0, p=(char *)buf; i<count && *p; i++, p++) {
- if ((*p == '\n') || (*p == ' ')) {
+ for (i = 0, p = buf; i < count && *p; i++, p++) {
+ if (*p == '\n' || *p == ' ')
/* trailing lf, grr */
break;
- } else {
- name[i]=*p;
- }
+ name[i] = *p;
}
name[i] = '\0';
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- ndev = (*clist)->netdev;
- priv = (struct netiucv_priv*)ndev->priv;
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(cp, &iucv_connection_list, list) {
+ ndev = cp->netdev;
+ priv = netdev_priv(ndev);
dev = priv->dev;
-
- if (strncmp(name, ndev->name, count)) {
- clist = &((*clist)->next);
- continue;
- }
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ if (strncmp(name, ndev->name, count))
+ continue;
+ read_unlock_bh(&iucv_connection_rwlock);
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
- PRINT_WARN(
- "netiucv: net device %s active with peer %s\n",
- ndev->name, priv->conn->userid);
+ PRINT_WARN("netiucv: net device %s active with peer "
+ "%s\n", ndev->name, priv->conn->userid);
PRINT_WARN("netiucv: %s cannot be removed\n",
- ndev->name);
+ ndev->name);
IUCV_DBF_TEXT(data, 2, "remove_write: still active\n");
return -EBUSY;
}
@@ -2106,75 +2077,94 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
netiucv_unregister_device(dev);
return count;
}
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ read_unlock_bh(&iucv_connection_rwlock);
PRINT_WARN("netiucv: net device %s unknown\n", name);
IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
return -EINVAL;
}
-DRIVER_ATTR(remove, 0200, NULL, remove_write);
+static DRIVER_ATTR(remove, 0200, NULL, remove_write);
-static void
-netiucv_banner(void)
+static struct attribute * netiucv_drv_attrs[] = {
+ &driver_attr_connection.attr,
+ &driver_attr_remove.attr,
+ NULL,
+};
+
+static struct attribute_group netiucv_drv_attr_group = {
+ .attrs = netiucv_drv_attrs,
+};
+
+static void netiucv_banner(void)
{
PRINT_INFO("NETIUCV driver initialized\n");
}
-static void __exit
-netiucv_exit(void)
+static void __exit netiucv_exit(void)
{
+ struct iucv_connection *cp;
+ struct net_device *ndev;
+ struct netiucv_priv *priv;
+ struct device *dev;
+
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- while (iucv_conns.iucv_connections) {
- struct net_device *ndev = iucv_conns.iucv_connections->netdev;
- struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv;
- struct device *dev = priv->dev;
+ while (!list_empty(&iucv_connection_list)) {
+ cp = list_entry(iucv_connection_list.next,
+ struct iucv_connection, list);
+ list_del(&cp->list);
+ ndev = cp->netdev;
+ priv = netdev_priv(ndev);
+ dev = priv->dev;
unregister_netdev(ndev);
netiucv_unregister_device(dev);
}
- driver_remove_file(&netiucv_driver, &driver_attr_connection);
- driver_remove_file(&netiucv_driver, &driver_attr_remove);
+ sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
driver_unregister(&netiucv_driver);
+ iucv_unregister(&netiucv_handler, 1);
iucv_unregister_dbf_views();
PRINT_INFO("NETIUCV driver unloaded\n");
return;
}
-static int __init
-netiucv_init(void)
+static int __init netiucv_init(void)
{
- int ret;
+ int rc;
- ret = iucv_register_dbf_views();
- if (ret) {
- PRINT_WARN("netiucv_init failed, "
- "iucv_register_dbf_views rc = %d\n", ret);
- return ret;
- }
+ rc = iucv_register_dbf_views();
+ if (rc)
+ goto out;
+ rc = iucv_register(&netiucv_handler, 1);
+ if (rc)
+ goto out_dbf;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- ret = driver_register(&netiucv_driver);
- if (ret) {
+ rc = driver_register(&netiucv_driver);
+ if (rc) {
PRINT_ERR("NETIUCV: failed to register driver.\n");
- IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", ret);
- iucv_unregister_dbf_views();
- return ret;
+ IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc);
+ goto out_iucv;
}
- /* Add entry for specifying connections. */
- ret = driver_create_file(&netiucv_driver, &driver_attr_connection);
- if (!ret) {
- ret = driver_create_file(&netiucv_driver, &driver_attr_remove);
- netiucv_banner();
- rwlock_init(&iucv_conns.iucv_rwlock);
- } else {
- PRINT_ERR("NETIUCV: failed to add driver attribute.\n");
- IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret);
- driver_unregister(&netiucv_driver);
- iucv_unregister_dbf_views();
+ rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
+ if (rc) {
+ PRINT_ERR("NETIUCV: failed to add driver attributes.\n");
+ IUCV_DBF_TEXT_(setup, 2,
+ "ret %d - netiucv_drv_attr_group\n", rc);
+ goto out_driver;
}
- return ret;
+ netiucv_banner();
+ return rc;
+
+out_driver:
+ driver_unregister(&netiucv_driver);
+out_iucv:
+ iucv_unregister(&netiucv_handler, 1);
+out_dbf:
+ iucv_unregister_dbf_views();
+out:
+ return rc;
}
module_init(netiucv_init);
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index 53c358c7d36..e95c281f1e3 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -710,7 +710,7 @@ struct qeth_reply {
int (*callback)(struct qeth_card *,struct qeth_reply *,unsigned long);
u32 seqno;
unsigned long offset;
- int received;
+ atomic_t received;
int rc;
void *param;
struct qeth_card *card;
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 6bb558a9a03..7c735e1fe06 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -49,7 +49,7 @@ qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *queue,
return buffers_needed;
}
-static inline void
+static void
qeth_eddp_free_context(struct qeth_eddp_context *ctx)
{
int i;
@@ -91,7 +91,7 @@ qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
}
}
-static inline int
+static int
qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf,
struct qeth_eddp_context *ctx)
{
@@ -196,7 +196,7 @@ out:
return flush_cnt;
}
-static inline void
+static void
qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
struct qeth_eddp_data *eddp, int data_len)
{
@@ -256,7 +256,7 @@ qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
ctx->offset += eddp->thl;
}
-static inline void
+static void
qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
__wsum *hcsum)
{
@@ -302,7 +302,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
}
}
-static inline void
+static void
qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
struct qeth_eddp_data *eddp, int data_len,
__wsum hcsum)
@@ -349,7 +349,7 @@ qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum);
}
-static inline __wsum
+static __wsum
qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
{
__wsum phcsum; /* pseudo header checksum */
@@ -363,7 +363,7 @@ qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum);
}
-static inline __wsum
+static __wsum
qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
{
__be32 proto;
@@ -381,7 +381,7 @@ qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
return phcsum;
}
-static inline struct qeth_eddp_data *
+static struct qeth_eddp_data *
qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
{
struct qeth_eddp_data *eddp;
@@ -399,7 +399,7 @@ qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
return eddp;
}
-static inline void
+static void
__qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct qeth_eddp_data *eddp)
{
@@ -464,7 +464,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
}
}
-static inline int
+static int
qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct sk_buff *skb, struct qeth_hdr *qhdr)
{
@@ -505,7 +505,7 @@ qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
return 0;
}
-static inline void
+static void
qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
int hdr_len)
{
@@ -529,7 +529,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
(skb_shinfo(skb)->gso_segs + 1);
}
-static inline struct qeth_eddp_context *
+static struct qeth_eddp_context *
qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
int hdr_len)
{
@@ -581,7 +581,7 @@ qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
return ctx;
}
-static inline struct qeth_eddp_context *
+static struct qeth_eddp_context *
qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *qhdr)
{
@@ -625,5 +625,3 @@ qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb,
}
return NULL;
}
-
-
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 2bde4f1fb9c..2257e45594b 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -471,7 +471,7 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
channel->state == CH_STATE_UP)
qeth_issue_next_read(card);
- tasklet_schedule(&channel->irq_tasklet);
+ qeth_irq_tasklet((unsigned long)channel);
return;
out:
wake_up(&card->wait_q);
@@ -651,7 +651,7 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
return 0;
}
-static inline int
+static int
__qeth_address_exists_in_list(struct list_head *list, struct qeth_ipaddr *addr,
int same_type)
{
@@ -795,7 +795,7 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
return rc;
}
-static inline void
+static void
__qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags)
{
struct qeth_ipaddr *addr, *tmp;
@@ -882,7 +882,7 @@ static void qeth_layer2_add_multicast(struct qeth_card *);
static void qeth_add_multicast_ipv6(struct qeth_card *);
#endif
-static inline int
+static int
qeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread)
{
unsigned long flags;
@@ -920,7 +920,7 @@ qeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread)
wake_up(&card->wait_q);
}
-static inline int
+static int
__qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
{
unsigned long flags;
@@ -951,40 +951,6 @@ qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
}
static int
-qeth_register_ip_addresses(void *ptr)
-{
- struct qeth_card *card;
-
- card = (struct qeth_card *) ptr;
- daemonize("qeth_reg_ip");
- QETH_DBF_TEXT(trace,4,"regipth1");
- if (!qeth_do_run_thread(card, QETH_SET_IP_THREAD))
- return 0;
- QETH_DBF_TEXT(trace,4,"regipth2");
- qeth_set_ip_addr_list(card);
- qeth_clear_thread_running_bit(card, QETH_SET_IP_THREAD);
- return 0;
-}
-
-/*
- * Drive the SET_PROMISC_MODE thread
- */
-static int
-qeth_set_promisc_mode(void *ptr)
-{
- struct qeth_card *card = (struct qeth_card *) ptr;
-
- daemonize("qeth_setprm");
- QETH_DBF_TEXT(trace,4,"setprm1");
- if (!qeth_do_run_thread(card, QETH_SET_PROMISC_MODE_THREAD))
- return 0;
- QETH_DBF_TEXT(trace,4,"setprm2");
- qeth_setadp_promisc_mode(card);
- qeth_clear_thread_running_bit(card, QETH_SET_PROMISC_MODE_THREAD);
- return 0;
-}
-
-static int
qeth_recover(void *ptr)
{
struct qeth_card *card;
@@ -1047,11 +1013,6 @@ qeth_start_kernel_thread(struct work_struct *work)
if (card->read.state != CH_STATE_UP &&
card->write.state != CH_STATE_UP)
return;
-
- if (qeth_do_start_thread(card, QETH_SET_IP_THREAD))
- kernel_thread(qeth_register_ip_addresses, (void *)card,SIGCHLD);
- if (qeth_do_start_thread(card, QETH_SET_PROMISC_MODE_THREAD))
- kernel_thread(qeth_set_promisc_mode, (void *)card, SIGCHLD);
if (qeth_do_start_thread(card, QETH_RECOVER_THREAD))
kernel_thread(qeth_recover, (void *) card, SIGCHLD);
}
@@ -1074,7 +1035,7 @@ qeth_set_intial_options(struct qeth_card *card)
card->options.layer2 = 1;
else
card->options.layer2 = 0;
- card->options.performance_stats = 1;
+ card->options.performance_stats = 0;
}
/**
@@ -1613,8 +1574,6 @@ qeth_issue_next_read(struct qeth_card *card)
return -ENOMEM;
}
qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE);
- wait_event(card->wait_q,
- atomic_cmpxchg(&card->read.irq_pending, 0, 1) == 0);
QETH_DBF_TEXT(trace, 6, "noirqpnd");
rc = ccw_device_start(card->read.ccwdev, &card->read.ccw,
(addr_t) iob, 0, 0);
@@ -1635,6 +1594,7 @@ qeth_alloc_reply(struct qeth_card *card)
reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC);
if (reply){
atomic_set(&reply->refcnt, 1);
+ atomic_set(&reply->received, 0);
reply->card = card;
};
return reply;
@@ -1655,31 +1615,6 @@ qeth_put_reply(struct qeth_reply *reply)
kfree(reply);
}
-static void
-qeth_cmd_timeout(unsigned long data)
-{
- struct qeth_reply *reply, *list_reply, *r;
- unsigned long flags;
-
- reply = (struct qeth_reply *) data;
- spin_lock_irqsave(&reply->card->lock, flags);
- list_for_each_entry_safe(list_reply, r,
- &reply->card->cmd_waiter_list, list) {
- if (reply == list_reply){
- qeth_get_reply(reply);
- list_del_init(&reply->list);
- spin_unlock_irqrestore(&reply->card->lock, flags);
- reply->rc = -ETIME;
- reply->received = 1;
- wake_up(&reply->wait_q);
- qeth_put_reply(reply);
- return;
- }
- }
- spin_unlock_irqrestore(&reply->card->lock, flags);
-}
-
-
static struct qeth_ipa_cmd *
qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
{
@@ -1745,7 +1680,7 @@ qeth_clear_ipacmd_list(struct qeth_card *card)
list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) {
qeth_get_reply(reply);
reply->rc = -EIO;
- reply->received = 1;
+ atomic_inc(&reply->received);
list_del_init(&reply->list);
wake_up(&reply->wait_q);
qeth_put_reply(reply);
@@ -1814,7 +1749,7 @@ qeth_send_control_data_cb(struct qeth_channel *channel,
&card->cmd_waiter_list);
spin_unlock_irqrestore(&card->lock, flags);
} else {
- reply->received = 1;
+ atomic_inc(&reply->received);
wake_up(&reply->wait_q);
}
qeth_put_reply(reply);
@@ -1829,9 +1764,9 @@ out:
qeth_release_buffer(channel,iob);
}
-static inline void
+static void
qeth_prepare_control_data(struct qeth_card *card, int len,
-struct qeth_cmd_buffer *iob)
+ struct qeth_cmd_buffer *iob)
{
qeth_setup_ccw(&card->write,iob->data,len);
iob->callback = qeth_release_buffer;
@@ -1858,7 +1793,7 @@ qeth_send_control_data(struct qeth_card *card, int len,
int rc;
unsigned long flags;
struct qeth_reply *reply = NULL;
- struct timer_list timer;
+ unsigned long timeout;
QETH_DBF_TEXT(trace, 2, "sendctl");
@@ -1873,21 +1808,20 @@ qeth_send_control_data(struct qeth_card *card, int len,
reply->seqno = QETH_IDX_COMMAND_SEQNO;
else
reply->seqno = card->seqno.ipa++;
- init_timer(&timer);
- timer.function = qeth_cmd_timeout;
- timer.data = (unsigned long) reply;
init_waitqueue_head(&reply->wait_q);
spin_lock_irqsave(&card->lock, flags);
list_add_tail(&reply->list, &card->cmd_waiter_list);
spin_unlock_irqrestore(&card->lock, flags);
QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN);
- wait_event(card->wait_q,
- atomic_cmpxchg(&card->write.irq_pending, 0, 1) == 0);
+
+ while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ;
qeth_prepare_control_data(card, len, iob);
+
if (IS_IPA(iob->data))
- timer.expires = jiffies + QETH_IPA_TIMEOUT;
+ timeout = jiffies + QETH_IPA_TIMEOUT;
else
- timer.expires = jiffies + QETH_TIMEOUT;
+ timeout = jiffies + QETH_TIMEOUT;
+
QETH_DBF_TEXT(trace, 6, "noirqpnd");
spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
@@ -1906,9 +1840,16 @@ qeth_send_control_data(struct qeth_card *card, int len,
wake_up(&card->wait_q);
return rc;
}
- add_timer(&timer);
- wait_event(reply->wait_q, reply->received);
- del_timer_sync(&timer);
+ while (!atomic_read(&reply->received)) {
+ if (time_after(jiffies, timeout)) {
+ spin_lock_irqsave(&reply->card->lock, flags);
+ list_del_init(&reply->list);
+ spin_unlock_irqrestore(&reply->card->lock, flags);
+ reply->rc = -ETIME;
+ atomic_inc(&reply->received);
+ wake_up(&reply->wait_q);
+ }
+ };
rc = reply->rc;
qeth_put_reply(reply);
return rc;
@@ -2219,7 +2160,7 @@ qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
return 0;
}
-static inline struct sk_buff *
+static struct sk_buff *
qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
{
struct sk_buff* skb;
@@ -2238,7 +2179,7 @@ qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
return skb;
}
-static inline struct sk_buff *
+static struct sk_buff *
qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
struct qdio_buffer_element **__element, int *__offset,
struct qeth_hdr **hdr)
@@ -2323,7 +2264,7 @@ no_mem:
return NULL;
}
-static inline __be16
+static __be16
qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct qeth_card *card;
@@ -2356,7 +2297,7 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
return htons(ETH_P_802_2);
}
-static inline void
+static void
qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
@@ -2410,7 +2351,7 @@ qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
fake_llc->ethertype = ETH_P_IP;
}
-static inline void
+static void
qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
@@ -2466,35 +2407,20 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
qeth_rebuild_skb_fake_ll_eth(card, skb, hdr);
}
-static inline __u16
+static inline void
qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
- unsigned short vlan_id = 0;
-#ifdef CONFIG_QETH_VLAN
- struct vlan_hdr *vhdr;
-#endif
-
skb->pkt_type = PACKET_HOST;
skb->protocol = qeth_type_trans(skb, skb->dev);
if (card->options.checksum_type == NO_CHECKSUMMING)
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb->ip_summed = CHECKSUM_NONE;
-#ifdef CONFIG_QETH_VLAN
- if (hdr->hdr.l2.flags[2] & (QETH_LAYER2_FLAG_VLAN)) {
- vhdr = (struct vlan_hdr *) skb->data;
- skb->protocol =
- __constant_htons(vhdr->h_vlan_encapsulated_proto);
- vlan_id = hdr->hdr.l2.vlan_id;
- skb_pull(skb, VLAN_HLEN);
- }
-#endif
*((__u32 *)skb->cb) = ++card->seqno.pkt_seqno;
- return vlan_id;
}
-static inline __u16
+static __u16
qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
@@ -2550,7 +2476,7 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
return vlan_id;
}
-static inline void
+static void
qeth_process_inbound_buffer(struct qeth_card *card,
struct qeth_qdio_buffer *buf, int index)
{
@@ -2560,7 +2486,6 @@ qeth_process_inbound_buffer(struct qeth_card *card,
int offset;
int rxrc;
__u16 vlan_tag = 0;
- __u16 *vlan_addr;
/* get first element of current buffer */
element = (struct qdio_buffer_element *)&buf->buffer->element[0];
@@ -2571,7 +2496,7 @@ qeth_process_inbound_buffer(struct qeth_card *card,
&offset, &hdr))) {
skb->dev = card->dev;
if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
- vlan_tag = qeth_layer2_rebuild_skb(card, skb, hdr);
+ qeth_layer2_rebuild_skb(card, skb, hdr);
else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3)
vlan_tag = qeth_rebuild_skb(card, skb, hdr);
else { /*in case of OSN*/
@@ -2603,7 +2528,7 @@ qeth_process_inbound_buffer(struct qeth_card *card,
}
}
-static inline struct qeth_buffer_pool_entry *
+static struct qeth_buffer_pool_entry *
qeth_get_buffer_pool_entry(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *entry;
@@ -2618,7 +2543,7 @@ qeth_get_buffer_pool_entry(struct qeth_card *card)
return NULL;
}
-static inline void
+static void
qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
{
struct qeth_buffer_pool_entry *pool_entry;
@@ -2645,7 +2570,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
buf->state = QETH_QDIO_BUF_EMPTY;
}
-static inline void
+static void
qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
struct qeth_qdio_out_buffer *buf)
{
@@ -2670,7 +2595,7 @@ qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
}
-static inline void
+static void
qeth_queue_input_buffer(struct qeth_card *card, int index)
{
struct qeth_qdio_q *queue = card->qdio.in_q;
@@ -2774,7 +2699,7 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
card->perf_stats.inbound_start_time;
}
-static inline int
+static int
qeth_handle_send_error(struct qeth_card *card,
struct qeth_qdio_out_buffer *buffer,
unsigned int qdio_err, unsigned int siga_err)
@@ -2896,7 +2821,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
* Switched to packing state if the number of used buffers on a queue
* reaches a certain limit.
*/
-static inline void
+static void
qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
{
if (!queue->do_pack) {
@@ -2917,7 +2842,7 @@ qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
* In that case 1 is returned to inform the caller. If no buffer
* has to be flushed, zero is returned.
*/
-static inline int
+static int
qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
{
struct qeth_qdio_out_buffer *buffer;
@@ -2952,7 +2877,7 @@ qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
* Checks if there is a packing buffer and prepares it to be flushed.
* In that case returns 1, otherwise zero.
*/
-static inline int
+static int
qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
{
struct qeth_qdio_out_buffer *buffer;
@@ -2969,7 +2894,7 @@ qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
return 0;
}
-static inline void
+static void
qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
{
int index;
@@ -3669,7 +3594,7 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
}
}
-static inline int
+static int
qeth_send_packet(struct qeth_card *, struct sk_buff *);
static int
@@ -3834,7 +3759,7 @@ qeth_stop(struct net_device *dev)
return 0;
}
-static inline int
+static int
qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
{
int cast_type = RTN_UNSPEC;
@@ -3881,7 +3806,7 @@ qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
return cast_type;
}
-static inline int
+static int
qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
int ipv, int cast_type)
{
@@ -3928,7 +3853,7 @@ qeth_get_ip_version(struct sk_buff *skb)
}
}
-static inline struct qeth_hdr *
+static struct qeth_hdr *
__qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv)
{
#ifdef CONFIG_QETH_VLAN
@@ -3957,24 +3882,33 @@ __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv)
qeth_push_skb(card, skb, sizeof(struct qeth_hdr)));
}
-static inline void
+static void
__qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb)
{
if (orig_skb != new_skb)
dev_kfree_skb_any(new_skb);
}
-static inline struct sk_buff *
+static struct sk_buff *
qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr **hdr, int ipv)
{
- struct sk_buff *new_skb;
+ struct sk_buff *new_skb, *new_skb2;
QETH_DBF_TEXT(trace, 6, "prepskb");
-
- new_skb = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr));
- if (new_skb == NULL)
+ new_skb = skb;
+ new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC);
+ if (!new_skb)
return NULL;
+ new_skb2 = qeth_realloc_headroom(card, new_skb,
+ sizeof(struct qeth_hdr));
+ if (!new_skb2) {
+ __qeth_free_new_skb(skb, new_skb);
+ return NULL;
+ }
+ if (new_skb != skb)
+ __qeth_free_new_skb(new_skb2, new_skb);
+ new_skb = new_skb2;
*hdr = __qeth_prepare_skb(card, new_skb, ipv);
if (*hdr == NULL) {
__qeth_free_new_skb(skb, new_skb);
@@ -4006,7 +3940,7 @@ qeth_get_qeth_hdr_flags6(int cast_type)
return ct | QETH_CAST_UNICAST;
}
-static inline void
+static void
qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb)
{
@@ -4043,7 +3977,7 @@ qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr,
}
}
-static inline void
+static void
qeth_layer2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int cast_type)
{
@@ -4134,7 +4068,7 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
}
}
-static inline void
+static void
__qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
int is_tso, int *next_element_to_fill)
{
@@ -4178,7 +4112,7 @@ __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
*next_element_to_fill = element;
}
-static inline int
+static int
qeth_fill_buffer(struct qeth_qdio_out_q *queue,
struct qeth_qdio_out_buffer *buf,
struct sk_buff *skb)
@@ -4237,7 +4171,7 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue,
return flush_cnt;
}
-static inline int
+static int
qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct sk_buff *skb, struct qeth_hdr *hdr,
int elements_needed,
@@ -4288,7 +4222,7 @@ out:
return -EBUSY;
}
-static inline int
+static int
qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct sk_buff *skb, struct qeth_hdr *hdr,
int elements_needed, struct qeth_eddp_context *ctx)
@@ -4394,7 +4328,7 @@ out:
return rc;
}
-static inline int
+static int
qeth_get_elements_no(struct qeth_card *card, void *hdr,
struct sk_buff *skb, int elems)
{
@@ -4415,7 +4349,7 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr,
}
-static inline int
+static int
qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
{
int ipv = 0;
@@ -4602,7 +4536,7 @@ qeth_mdio_read(struct net_device *dev, int phy_id, int regnum)
}
-static inline const char *
+static const char *
qeth_arp_get_error_cause(int *rc)
{
switch (*rc) {
@@ -4663,7 +4597,7 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries)
return rc;
}
-static inline void
+static void
qeth_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo,
struct qeth_arp_query_data *qdata,
int entry_size, int uentry_size)
@@ -4844,9 +4778,11 @@ qeth_arp_query(struct qeth_card *card, char __user *udata)
"(0x%x/%d)\n",
QETH_CARD_IFNAME(card), qeth_arp_get_error_cause(&rc),
tmp, tmp);
- copy_to_user(udata, qinfo.udata, 4);
+ if (copy_to_user(udata, qinfo.udata, 4))
+ rc = -EFAULT;
} else {
- copy_to_user(udata, qinfo.udata, qinfo.udata_len);
+ if (copy_to_user(udata, qinfo.udata, qinfo.udata_len))
+ rc = -EFAULT;
}
kfree(qinfo.udata);
return rc;
@@ -4992,8 +4928,10 @@ qeth_snmp_command(struct qeth_card *card, char __user *udata)
if (rc)
PRINT_WARN("SNMP command failed on %s: (0x%x)\n",
QETH_CARD_IFNAME(card), rc);
- else
- copy_to_user(udata, qinfo.udata, qinfo.udata_len);
+ else {
+ if (copy_to_user(udata, qinfo.udata, qinfo.udata_len))
+ rc = -EFAULT;
+ }
kfree(ureq);
kfree(qinfo.udata);
@@ -5276,7 +5214,7 @@ qeth_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
spin_unlock_irqrestore(&card->vlanlock, flags);
}
-static inline void
+static void
qeth_free_vlan_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf,
unsigned short vid)
{
@@ -5544,12 +5482,10 @@ qeth_set_multicast_list(struct net_device *dev)
qeth_add_multicast_ipv6(card);
#endif
out:
- if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
- schedule_work(&card->kernel_thread_starter);
+ qeth_set_ip_addr_list(card);
if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
return;
- if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0)
- schedule_work(&card->kernel_thread_starter);
+ qeth_setadp_promisc_mode(card);
}
static int
@@ -5689,7 +5625,7 @@ qeth_delete_mc_addresses(struct qeth_card *card)
spin_unlock_irqrestore(&card->ip_lock, flags);
}
-static inline void
+static void
qeth_add_mc(struct qeth_card *card, struct in_device *in4_dev)
{
struct qeth_ipaddr *ipm;
@@ -5775,7 +5711,7 @@ qeth_layer2_add_multicast(struct qeth_card *card)
}
#ifdef CONFIG_QETH_IPV6
-static inline void
+static void
qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
{
struct qeth_ipaddr *ipm;
@@ -6086,7 +6022,7 @@ qeth_send_setdelmc(struct qeth_card *card, struct qeth_ipaddr *addr, int ipacmd)
return rc;
}
-static inline void
+static void
qeth_fill_netmask(u8 *netmask, unsigned int len)
{
int i,j;
@@ -6351,6 +6287,42 @@ static struct ethtool_ops qeth_ethtool_ops = {
};
static int
+qeth_hard_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+ struct qeth_card *card;
+ struct ethhdr *eth;
+
+ card = qeth_get_card_from_dev(skb->dev);
+ if (card->options.layer2)
+ goto haveheader;
+#ifdef CONFIG_QETH_IPV6
+ /* cause of the manipulated arp constructor and the ARP
+ flag for OSAE devices we have some nasty exceptions */
+ if (card->info.type == QETH_CARD_TYPE_OSAE) {
+ if (!card->options.fake_ll) {
+ if ((skb->pkt_type==PACKET_OUTGOING) &&
+ (skb->protocol==ETH_P_IPV6))
+ goto haveheader;
+ else
+ return 0;
+ } else {
+ if ((skb->pkt_type==PACKET_OUTGOING) &&
+ (skb->protocol==ETH_P_IP))
+ return 0;
+ else
+ goto haveheader;
+ }
+ }
+#endif
+ if (!card->options.fake_ll)
+ return 0;
+haveheader:
+ eth = eth_hdr(skb);
+ memcpy(haddr, eth->h_source, ETH_ALEN);
+ return ETH_ALEN;
+}
+
+static int
qeth_netdev_init(struct net_device *dev)
{
struct qeth_card *card;
@@ -6388,7 +6360,10 @@ qeth_netdev_init(struct net_device *dev)
if (card->options.fake_ll &&
(qeth_get_netdev_flags(card) & IFF_NOARP))
dev->hard_header = qeth_fake_header;
- dev->hard_header_parse = NULL;
+ if (dev->type == ARPHRD_IEEE802_TR)
+ dev->hard_header_parse = NULL;
+ else
+ dev->hard_header_parse = qeth_hard_header_parse;
dev->set_mac_address = qeth_layer2_set_mac_address;
dev->flags |= qeth_get_netdev_flags(card);
if ((card->options.fake_broadcast) ||
@@ -6651,7 +6626,7 @@ qeth_send_setadp_mode(struct qeth_card *card, __u32 command, __u32 mode)
return rc;
}
-static inline int
+static int
qeth_setadapter_hstr(struct qeth_card *card)
{
int rc;
@@ -6914,7 +6889,7 @@ qeth_send_simple_setassparms(struct qeth_card *card,
return rc;
}
-static inline int
+static int
qeth_start_ipa_arp_processing(struct qeth_card *card)
{
int rc;
@@ -7554,7 +7529,7 @@ qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads,
wake_up(&card->wait_q);
}
-static inline int
+static int
qeth_threads_running(struct qeth_card *card, unsigned long threads)
{
unsigned long flags;
@@ -8143,7 +8118,7 @@ qeth_del_ipato_entry(struct qeth_card *card, enum qeth_prot_versions proto,
spin_unlock_irqrestore(&card->ip_lock, flags);
}
-static inline void
+static void
qeth_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
{
int i, j;
@@ -8235,8 +8210,7 @@ qeth_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
}
if (!qeth_add_ip(card, ipaddr))
kfree(ipaddr);
- if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
- schedule_work(&card->kernel_thread_starter);
+ qeth_set_ip_addr_list(card);
return rc;
}
@@ -8264,8 +8238,7 @@ qeth_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
return;
if (!qeth_delete_ip(card, ipaddr))
kfree(ipaddr);
- if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
- schedule_work(&card->kernel_thread_starter);
+ qeth_set_ip_addr_list(card);
}
/*
@@ -8308,8 +8281,7 @@ qeth_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
}
if (!qeth_add_ip(card, ipaddr))
kfree(ipaddr);
- if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
- schedule_work(&card->kernel_thread_starter);
+ qeth_set_ip_addr_list(card);
return 0;
}
@@ -8337,8 +8309,7 @@ qeth_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
return;
if (!qeth_delete_ip(card, ipaddr))
kfree(ipaddr);
- if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
- schedule_work(&card->kernel_thread_starter);
+ qeth_set_ip_addr_list(card);
}
/**
@@ -8380,8 +8351,7 @@ qeth_ip_event(struct notifier_block *this,
default:
break;
}
- if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
- schedule_work(&card->kernel_thread_starter);
+ qeth_set_ip_addr_list(card);
out:
return NOTIFY_DONE;
}
@@ -8433,8 +8403,7 @@ qeth_ip6_event(struct notifier_block *this,
default:
break;
}
- if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
- schedule_work(&card->kernel_thread_starter);
+ qeth_set_ip_addr_list(card);
out:
return NOTIFY_DONE;
}
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index 5836737ac58..d518419cd0c 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -328,7 +328,7 @@ qeth_dev_bufcnt_store(struct device *dev, struct device_attribute *attr, const c
static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show,
qeth_dev_bufcnt_store);
-static inline ssize_t
+static ssize_t
qeth_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route,
char *buf)
{
@@ -368,7 +368,7 @@ qeth_dev_route4_show(struct device *dev, struct device_attribute *attr, char *bu
return qeth_dev_route_show(card, &card->options.route4, buf);
}
-static inline ssize_t
+static ssize_t
qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route,
enum qeth_prot_versions prot, const char *buf, size_t count)
{
@@ -998,7 +998,7 @@ struct device_attribute dev_attr_##_id = { \
.store = _store, \
};
-int
+static int
qeth_check_layer2(struct qeth_card *card)
{
if (card->options.layer2)
@@ -1100,7 +1100,7 @@ static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
qeth_dev_ipato_invert4_show,
qeth_dev_ipato_invert4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_ipato_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
@@ -1146,7 +1146,7 @@ qeth_dev_ipato_add4_show(struct device *dev, struct device_attribute *attr, char
return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
}
-static inline int
+static int
qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
u8 *addr, int *mask_bits)
{
@@ -1178,7 +1178,7 @@ qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
return 0;
}
-static inline ssize_t
+static ssize_t
qeth_dev_ipato_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1223,7 +1223,7 @@ static QETH_DEVICE_ATTR(ipato_add4, add4, 0644,
qeth_dev_ipato_add4_show,
qeth_dev_ipato_add4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_ipato_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1361,7 +1361,7 @@ static struct attribute_group qeth_device_ipato_group = {
.attrs = (struct attribute **)qeth_ipato_device_attrs,
};
-static inline ssize_t
+static ssize_t
qeth_dev_vipa_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
@@ -1407,7 +1407,7 @@ qeth_dev_vipa_add4_show(struct device *dev, struct device_attribute *attr, char
return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
}
-static inline int
+static int
qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto,
u8 *addr)
{
@@ -1418,7 +1418,7 @@ qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto,
return 0;
}
-static inline ssize_t
+static ssize_t
qeth_dev_vipa_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1451,7 +1451,7 @@ static QETH_DEVICE_ATTR(vipa_add4, add4, 0644,
qeth_dev_vipa_add4_show,
qeth_dev_vipa_add4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_vipa_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1542,7 +1542,7 @@ static struct attribute_group qeth_device_vipa_group = {
.attrs = (struct attribute **)qeth_vipa_device_attrs,
};
-static inline ssize_t
+static ssize_t
qeth_dev_rxip_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
@@ -1588,7 +1588,7 @@ qeth_dev_rxip_add4_show(struct device *dev, struct device_attribute *attr, char
return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
}
-static inline int
+static int
qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto,
u8 *addr)
{
@@ -1599,7 +1599,7 @@ qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto,
return 0;
}
-static inline ssize_t
+static ssize_t
qeth_dev_rxip_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1632,7 +1632,7 @@ static QETH_DEVICE_ATTR(rxip_add4, add4, 0644,
qeth_dev_rxip_add4_show,
qeth_dev_rxip_add4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_rxip_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index b8179c27ceb..3ccca5871fd 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -1,7 +1,7 @@
/*
* IUCV special message driver
*
- * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -23,10 +23,10 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/device.h>
+#include <net/iucv/iucv.h>
#include <asm/cpcmd.h>
#include <asm/ebcdic.h>
-
-#include "iucv.h"
+#include "smsgiucv.h"
struct smsg_callback {
struct list_head list;
@@ -39,38 +39,46 @@ MODULE_AUTHOR
("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)");
MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
-static iucv_handle_t smsg_handle;
-static unsigned short smsg_pathid;
+static struct iucv_path *smsg_path;
+
static DEFINE_SPINLOCK(smsg_list_lock);
static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list);
-static void
-smsg_connection_complete(iucv_ConnectionComplete *eib, void *pgm_data)
+static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
+static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
+
+static struct iucv_handler smsg_handler = {
+ .path_pending = smsg_path_pending,
+ .message_pending = smsg_message_pending,
+};
+
+static int smsg_path_pending(struct iucv_path *path, u8 ipvmid[8],
+ u8 ipuser[16])
{
+ if (strncmp(ipvmid, "*MSG ", sizeof(ipvmid)) != 0)
+ return -EINVAL;
+ /* Path pending from *MSG. */
+ return iucv_path_accept(path, &smsg_handler, "SMSGIUCV ", NULL);
}
-
-static void
-smsg_message_pending(iucv_MessagePending *eib, void *pgm_data)
+static void smsg_message_pending(struct iucv_path *path,
+ struct iucv_message *msg)
{
struct smsg_callback *cb;
- unsigned char *msg;
+ unsigned char *buffer;
unsigned char sender[9];
- unsigned short len;
int rc, i;
- len = eib->ln1msg2.ipbfln1f;
- msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA);
- if (!msg) {
- iucv_reject(eib->ippathid, eib->ipmsgid, eib->iptrgcls);
+ buffer = kmalloc(msg->length + 1, GFP_ATOMIC | GFP_DMA);
+ if (!buffer) {
+ iucv_message_reject(path, msg);
return;
}
- rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls,
- msg, len, NULL, NULL, NULL);
+ rc = iucv_message_receive(path, msg, 0, buffer, msg->length, NULL);
if (rc == 0) {
- msg[len] = 0;
- EBCASC(msg, len);
- memcpy(sender, msg, 8);
+ buffer[msg->length] = 0;
+ EBCASC(buffer, msg->length);
+ memcpy(sender, buffer, 8);
sender[8] = 0;
/* Remove trailing whitespace from the sender name. */
for (i = 7; i >= 0; i--) {
@@ -80,27 +88,17 @@ smsg_message_pending(iucv_MessagePending *eib, void *pgm_data)
}
spin_lock(&smsg_list_lock);
list_for_each_entry(cb, &smsg_list, list)
- if (strncmp(msg + 8, cb->prefix, cb->len) == 0) {
- cb->callback(sender, msg + 8);
+ if (strncmp(buffer + 8, cb->prefix, cb->len) == 0) {
+ cb->callback(sender, buffer + 8);
break;
}
spin_unlock(&smsg_list_lock);
}
- kfree(msg);
+ kfree(buffer);
}
-static iucv_interrupt_ops_t smsg_ops = {
- .ConnectionComplete = smsg_connection_complete,
- .MessagePending = smsg_message_pending,
-};
-
-static struct device_driver smsg_driver = {
- .name = "SMSGIUCV",
- .bus = &iucv_bus,
-};
-
-int
-smsg_register_callback(char *prefix, void (*callback)(char *from, char *str))
+int smsg_register_callback(char *prefix,
+ void (*callback)(char *from, char *str))
{
struct smsg_callback *cb;
@@ -110,18 +108,18 @@ smsg_register_callback(char *prefix, void (*callback)(char *from, char *str))
cb->prefix = prefix;
cb->len = strlen(prefix);
cb->callback = callback;
- spin_lock(&smsg_list_lock);
+ spin_lock_bh(&smsg_list_lock);
list_add_tail(&cb->list, &smsg_list);
- spin_unlock(&smsg_list_lock);
+ spin_unlock_bh(&smsg_list_lock);
return 0;
}
-void
-smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str))
+void smsg_unregister_callback(char *prefix,
+ void (*callback)(char *from, char *str))
{
struct smsg_callback *cb, *tmp;
- spin_lock(&smsg_list_lock);
+ spin_lock_bh(&smsg_list_lock);
cb = NULL;
list_for_each_entry(tmp, &smsg_list, list)
if (tmp->callback == callback &&
@@ -130,55 +128,58 @@ smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str))
list_del(&cb->list);
break;
}
- spin_unlock(&smsg_list_lock);
+ spin_unlock_bh(&smsg_list_lock);
kfree(cb);
}
-static void __exit
-smsg_exit(void)
+static struct device_driver smsg_driver = {
+ .name = "SMSGIUCV",
+ .bus = &iucv_bus,
+};
+
+static void __exit smsg_exit(void)
{
- if (smsg_handle > 0) {
- cpcmd("SET SMSG OFF", NULL, 0, NULL);
- iucv_sever(smsg_pathid, NULL);
- iucv_unregister_program(smsg_handle);
- driver_unregister(&smsg_driver);
- }
- return;
+ cpcmd("SET SMSG IUCV", NULL, 0, NULL);
+ iucv_unregister(&smsg_handler, 1);
+ driver_unregister(&smsg_driver);
}
-static int __init
-smsg_init(void)
+static int __init smsg_init(void)
{
- static unsigned char pgmmask[24] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
int rc;
rc = driver_register(&smsg_driver);
- if (rc != 0) {
- printk(KERN_ERR "SMSGIUCV: failed to register driver.\n");
- return rc;
- }
- smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ",
- pgmmask, &smsg_ops, NULL);
- if (!smsg_handle) {
+ if (rc != 0)
+ goto out;
+ rc = iucv_register(&smsg_handler, 1);
+ if (rc) {
printk(KERN_ERR "SMSGIUCV: failed to register to iucv");
- driver_unregister(&smsg_driver);
- return -EIO; /* better errno ? */
+ rc = -EIO; /* better errno ? */
+ goto out_driver;
+ }
+ smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL);
+ if (!smsg_path) {
+ rc = -ENOMEM;
+ goto out_register;
}
- rc = iucv_connect (&smsg_pathid, 255, NULL, "*MSG ", NULL, 0,
- NULL, NULL, smsg_handle, NULL);
+ rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ",
+ NULL, NULL, NULL);
if (rc) {
printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG");
- iucv_unregister_program(smsg_handle);
- driver_unregister(&smsg_driver);
- smsg_handle = NULL;
- return -EIO;
+ rc = -EIO; /* better errno ? */
+ goto out_free;
}
cpcmd("SET SMSG IUCV", NULL, 0, NULL);
return 0;
+
+out_free:
+ iucv_path_free(smsg_path);
+out_register:
+ iucv_unregister(&smsg_handler, 1);
+out_driver:
+ driver_unregister(&smsg_driver);
+out:
+ return rc;
}
module_init(smsg_init);
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index e088b5e2871..806bb1a921e 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -13,22 +13,18 @@
#include <linux/errno.h>
#include <linux/workqueue.h>
#include <linux/time.h>
+#include <linux/device.h>
#include <linux/kthread.h>
-
+#include <asm/etr.h>
#include <asm/lowcore.h>
-
+#include <asm/cio.h>
+#include "cio/cio.h"
+#include "cio/chsc.h"
+#include "cio/css.h"
#include "s390mach.h"
static struct semaphore m_sem;
-extern int css_process_crw(int, int);
-extern int chsc_process_crw(void);
-extern int chp_process_crw(int, int);
-extern void css_reiterate_subchannels(void);
-
-extern struct workqueue_struct *slow_path_wq;
-extern struct work_struct slow_path_work;
-
static NORET_TYPE void
s390_handle_damage(char *msg)
{
@@ -470,6 +466,19 @@ s390_do_machine_check(struct pt_regs *regs)
s390_handle_damage("unable to revalidate registers.");
}
+ if (mci->cd) {
+ /* Timing facility damage */
+ s390_handle_damage("TOD clock damaged");
+ }
+
+ if (mci->ed && mci->ec) {
+ /* External damage */
+ if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC))
+ etr_sync_check();
+ if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH))
+ etr_switch_to_local();
+ }
+
if (mci->se)
/* Storage error uncorrected */
s390_handle_damage("received storage error uncorrected "
@@ -508,7 +517,7 @@ static int
machine_check_init(void)
{
init_MUTEX_LOCKED(&m_sem);
- ctl_clear_bit(14, 25); /* disable external damage MCH */
+ ctl_set_bit(14, 25); /* enable external damage MCH */
ctl_set_bit(14, 27); /* enable system recovery MCH */
#ifdef CONFIG_MACHCHK_WARNING
ctl_set_bit(14, 24); /* enable warning MCH */
@@ -529,7 +538,11 @@ arch_initcall(machine_check_init);
static int __init
machine_check_crw_init (void)
{
- kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
+ struct task_struct *task;
+
+ task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
ctl_set_bit(14, 28); /* enable channel report MCH */
return 0;
}
diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h
index 7abb42a09ae..d3ca4281a49 100644
--- a/drivers/s390/s390mach.h
+++ b/drivers/s390/s390mach.h
@@ -102,4 +102,7 @@ static inline int stcrw(struct crw *pcrw )
return ccode;
}
+#define ED_ETR_SYNC 12 /* External damage ETR sync check */
+#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */
+
#endif /* __s390mach */
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 5d39b2df0cc..39a88526679 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -47,13 +47,12 @@ static int __init zfcp_module_init(void);
static void zfcp_ns_gid_pn_handler(unsigned long);
/* miscellaneous */
-static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
-static inline void zfcp_sg_list_free(struct zfcp_sg_list *);
-static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
- void __user *, size_t);
-static inline int zfcp_sg_list_copy_to_user(void __user *,
- struct zfcp_sg_list *, size_t);
-
+static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
+static void zfcp_sg_list_free(struct zfcp_sg_list *);
+static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
+ void __user *, size_t);
+static int zfcp_sg_list_copy_to_user(void __user *,
+ struct zfcp_sg_list *, size_t);
static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long);
#define ZFCP_CFDC_IOC_MAGIC 0xDD
@@ -237,7 +236,7 @@ zfcp_device_setup(char *devstr)
return 0;
len = strlen(devstr) + 1;
- str = (char *) kmalloc(len, GFP_KERNEL);
+ str = kmalloc(len, GFP_KERNEL);
if (!str)
goto err_out;
memcpy(str, devstr, len);
@@ -605,7 +604,7 @@ zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
* elements of the scatter-gather list. The maximum size of a single element
* in the scatter-gather list is PAGE_SIZE.
*/
-static inline int
+static int
zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
{
struct scatterlist *sg;
@@ -652,7 +651,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
* Memory for each element in the scatter-gather list is freed.
* Finally sg_list->sg is freed itself and sg_list->count is reset.
*/
-static inline void
+static void
zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
{
struct scatterlist *sg;
@@ -697,7 +696,7 @@ zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count)
* @size: number of bytes to be copied
* Return: 0 on success, -EFAULT if copy_from_user fails.
*/
-static inline int
+static int
zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list,
void __user *user_buffer,
size_t size)
@@ -735,7 +734,7 @@ zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list,
* @size: number of bytes to be copied
* Return: 0 on success, -EFAULT if copy_to_user fails
*/
-static inline int
+static int
zfcp_sg_list_copy_to_user(void __user *user_buffer,
struct zfcp_sg_list *sg_list,
size_t size)
@@ -1799,7 +1798,7 @@ static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = {
* @code: reason code
* @rc_table: table of reason codes and descriptions
*/
-static inline const char *
+static const char *
zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table)
{
const char *descr = "unknown reason code";
@@ -1847,7 +1846,7 @@ zfcp_check_ct_response(struct ct_hdr *rjt)
* @rjt_par: reject parameter acc. to FC-PH/FC-FS
* @rc_table: table of reason codes and descriptions
*/
-static inline void
+static void
zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par,
const struct zfcp_rc_entry *rc_table)
{
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 0aa3b1ac76a..d8191d115c1 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -31,7 +31,7 @@ MODULE_PARM_DESC(dbfsize,
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER
-static inline int
+static int
zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
{
unsigned long long sec;
@@ -106,7 +106,7 @@ zfcp_dbf_view_dump(char *out_buf, const char *label,
return len;
}
-static inline int
+static int
zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
debug_entry_t * entry, char *out_buf)
{
@@ -130,7 +130,7 @@ zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
return len;
}
-inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_adapter *adapter = fsf_req->adapter;
struct fsf_qtcb *qtcb = fsf_req->qtcb;
@@ -241,7 +241,7 @@ inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
}
-inline void
+void
zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
struct fsf_status_read_buffer *status_buffer)
{
@@ -295,7 +295,7 @@ zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
}
-inline void
+void
zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status,
unsigned int qdio_error, unsigned int siga_error,
int sbal_index, int sbal_count)
@@ -316,7 +316,7 @@ zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status,
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
}
-static inline int
+static int
zfcp_hba_dbf_view_response(char *out_buf,
struct zfcp_hba_dbf_record_response *rec)
{
@@ -403,7 +403,7 @@ zfcp_hba_dbf_view_response(char *out_buf,
return len;
}
-static inline int
+static int
zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec)
{
int len = 0;
@@ -424,7 +424,7 @@ zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec)
return len;
}
-static inline int
+static int
zfcp_hba_dbf_view_qdio(char *out_buf, struct zfcp_hba_dbf_record_qdio *rec)
{
int len = 0;
@@ -469,7 +469,7 @@ zfcp_hba_dbf_view_format(debug_info_t * id, struct debug_view *view,
return len;
}
-struct debug_view zfcp_hba_dbf_view = {
+static struct debug_view zfcp_hba_dbf_view = {
"structured",
NULL,
&zfcp_dbf_view_header,
@@ -478,7 +478,7 @@ struct debug_view zfcp_hba_dbf_view = {
NULL
};
-inline void
+void
_zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
u32 s_id, u32 d_id, void *buffer, int buflen)
{
@@ -519,7 +519,7 @@ _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
}
-inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
struct zfcp_port *port = ct->port;
@@ -531,7 +531,7 @@ inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
ct->req->length);
}
-inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
struct zfcp_port *port = ct->port;
@@ -543,7 +543,7 @@ inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
ct->resp->length);
}
-static inline void
+static void
_zfcp_san_dbf_event_common_els(const char *tag, int level,
struct zfcp_fsf_req *fsf_req, u32 s_id,
u32 d_id, u8 ls_code, void *buffer, int buflen)
@@ -585,7 +585,7 @@ _zfcp_san_dbf_event_common_els(const char *tag, int level,
spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
}
-inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
@@ -597,7 +597,7 @@ inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
els->req->length);
}
-inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
@@ -608,7 +608,7 @@ inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
els->resp->length);
}
-inline void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_adapter *adapter = fsf_req->adapter;
struct fsf_status_read_buffer *status_buffer =
@@ -693,7 +693,7 @@ zfcp_san_dbf_view_format(debug_info_t * id, struct debug_view *view,
return len;
}
-struct debug_view zfcp_san_dbf_view = {
+static struct debug_view zfcp_san_dbf_view = {
"structured",
NULL,
&zfcp_dbf_view_header,
@@ -702,7 +702,7 @@ struct debug_view zfcp_san_dbf_view = {
NULL
};
-static inline void
+static void
_zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
struct zfcp_adapter *adapter,
struct scsi_cmnd *scsi_cmnd,
@@ -786,7 +786,7 @@ _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags);
}
-inline void
+void
zfcp_scsi_dbf_event_result(const char *tag, int level,
struct zfcp_adapter *adapter,
struct scsi_cmnd *scsi_cmnd,
@@ -796,7 +796,7 @@ zfcp_scsi_dbf_event_result(const char *tag, int level,
adapter, scsi_cmnd, fsf_req, 0);
}
-inline void
+void
zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
struct scsi_cmnd *scsi_cmnd,
struct zfcp_fsf_req *new_fsf_req,
@@ -806,7 +806,7 @@ zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
adapter, scsi_cmnd, new_fsf_req, old_req_id);
}
-inline void
+void
zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
struct scsi_cmnd *scsi_cmnd)
{
@@ -884,7 +884,7 @@ zfcp_scsi_dbf_view_format(debug_info_t * id, struct debug_view *view,
return len;
}
-struct debug_view zfcp_scsi_dbf_view = {
+static struct debug_view zfcp_scsi_dbf_view = {
"structured",
NULL,
&zfcp_dbf_view_header,
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index c88babce9bc..88642dec080 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -200,7 +200,7 @@ void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
* returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
-int
+static int
zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask)
{
int retval;
@@ -295,7 +295,7 @@ zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask)
* zfcp_erp_adisc - send ADISC ELS command
* @port: port structure
*/
-int
+static int
zfcp_erp_adisc(struct zfcp_port *port)
{
struct zfcp_adapter *adapter = port->adapter;
@@ -380,7 +380,7 @@ zfcp_erp_adisc(struct zfcp_port *port)
*
* If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered.
*/
-void
+static void
zfcp_erp_adisc_handler(unsigned long data)
{
struct zfcp_send_els *send_els;
@@ -3141,7 +3141,6 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
if (result != ZFCP_ERP_SUCCEEDED) {
- struct zfcp_port *port;
list_for_each_entry(port, &adapter->port_list_head, list)
if (port->rport &&
!atomic_test_mask(ZFCP_STATUS_PORT_WKA,
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index b8794d77285..cda0cc095ad 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -119,8 +119,8 @@ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t);
extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *);
-extern void set_host_byte(u32 *, char);
-extern void set_driver_byte(u32 *, char);
+extern void set_host_byte(int *, char);
+extern void set_driver_byte(int *, char);
extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 067f1519eb0..4b3ae3f22e7 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -4563,7 +4563,7 @@ zfcp_fsf_req_sbal_check(unsigned long *flags,
/*
* set qtcb pointer in fsf_req and initialize QTCB
*/
-static inline void
+static void
zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req)
{
if (likely(fsf_req->qtcb != NULL)) {
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index dbd9f48e863..1e12a78e8ed 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -21,22 +21,22 @@
#include "zfcp_ext.h"
-static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
+static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get
(struct zfcp_qdio_queue *, int, int);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp
(struct zfcp_fsf_req *, int, int);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
+static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
(struct zfcp_fsf_req *, unsigned long);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
+static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
(struct zfcp_fsf_req *, unsigned long);
-static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
+static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *);
-static inline void zfcp_qdio_sbale_fill
+static void zfcp_qdio_sbale_fill
(struct zfcp_fsf_req *, unsigned long, void *, int);
-static inline int zfcp_qdio_sbals_from_segment
+static int zfcp_qdio_sbals_from_segment
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
-static inline int zfcp_qdio_sbals_from_buffer
+static int zfcp_qdio_sbals_from_buffer
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
static qdio_handler_t zfcp_qdio_request_handler;
@@ -201,7 +201,7 @@ zfcp_qdio_allocate(struct zfcp_adapter *adapter)
* returns: error flag
*
*/
-static inline int
+static int
zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
unsigned int qdio_error, unsigned int siga_error,
int first_element, int elements_processed)
@@ -462,7 +462,7 @@ zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale)
* zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for
* a struct zfcp_fsf_req
*/
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
{
return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue,
@@ -484,7 +484,7 @@ zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
* zfcp_qdio_sbale_curr - return current SBALE on request_queue for
* a struct zfcp_fsf_req
*/
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
{
return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr,
@@ -499,7 +499,7 @@ zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
*
* Note: We can assume at least one free SBAL in the request_queue when called.
*/
-static inline void
+static void
zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
{
int count = atomic_read(&fsf_req->adapter->request_queue.free_count);
@@ -517,7 +517,7 @@ zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
*
* This function changes sbal_curr, sbale_curr, sbal_number of fsf_req.
*/
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
volatile struct qdio_buffer_element *sbale;
@@ -554,7 +554,7 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
/**
* zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed
*/
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
@@ -569,7 +569,7 @@ zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
* zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue
* with zero from
*/
-static inline int
+static int
zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last)
{
struct qdio_buffer **buf = queue->buffer;
@@ -603,7 +603,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req)
* zfcp_qdio_sbale_fill - set address and lenght in current SBALE
* on request_queue
*/
-static inline void
+static void
zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *addr, int length)
{
@@ -624,7 +624,7 @@ zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
* Alignment and length of the segment determine how many SBALEs are needed
* for the memory segment.
*/
-static inline int
+static int
zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *start_addr, unsigned long total_length)
{
@@ -659,7 +659,7 @@ zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
* @sg_count: number of elements in scatter-gather list
* @max_sbals: upper bound for number of SBALs to be used
*/
-inline int
+int
zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
struct scatterlist *sg, int sg_count, int max_sbals)
{
@@ -707,7 +707,7 @@ out:
* @length: length of buffer
* @max_sbals: upper bound for number of SBALs to be used
*/
-static inline int
+static int
zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *buffer, unsigned long length, int max_sbals)
{
@@ -728,7 +728,7 @@ zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
* @scsi_cmnd: either scatter-gather list or buffer contained herein is used
* to fill SBALs
*/
-inline int
+int
zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
{
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 452d96f92a1..99db02062c3 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -90,7 +90,7 @@ zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
return fcp_sns_info_ptr;
}
-fcp_dl_t *
+static fcp_dl_t *
zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd)
{
int additional_length = fcp_cmd->add_fcp_cdb_length << 2;
@@ -124,19 +124,19 @@ zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl)
* regarding the specified byte
*/
static inline void
-set_byte(u32 * result, char status, char pos)
+set_byte(int *result, char status, char pos)
{
*result |= status << (pos * 8);
}
void
-set_host_byte(u32 * result, char status)
+set_host_byte(int *result, char status)
{
set_byte(result, status, 2);
}
void
-set_driver_byte(u32 * result, char status)
+set_driver_byte(int *result, char status)
{
set_byte(result, status, 3);
}
@@ -280,7 +280,7 @@ out:
return retval;
}
-void
+static void
zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt)
{
struct completion *wait = (struct completion *) scpnt->SCp.ptr;
@@ -324,7 +324,7 @@ zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt,
* returns: 0 - success, SCSI command enqueued
* !0 - failure
*/
-int
+static int
zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
void (*done) (struct scsi_cmnd *))
{
@@ -380,7 +380,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
* will handle late commands. (Usually, the normal completion of late
* commands is ignored with respect to the running abort operation.)
*/
-int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
+static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
{
struct Scsi_Host *scsi_host;
struct zfcp_adapter *adapter;
@@ -445,7 +445,7 @@ int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
return retval;
}
-int
+static int
zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
{
int retval;
@@ -541,7 +541,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
/**
* zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
*/
-int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
+static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{
struct zfcp_unit *unit;
struct zfcp_adapter *adapter;
diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
index 1e788e815ce..090743d2f91 100644
--- a/drivers/s390/sysinfo.c
+++ b/drivers/s390/sysinfo.c
@@ -9,8 +9,14 @@
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/ebcdic.h>
+/* Sigh, math-emu. Don't ask. */
+#include <asm/sfp-util.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+
struct sysinfo_1_1_1 {
char reserved_0[32];
char manufacturer[16];
@@ -198,7 +204,7 @@ static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
* if the higher order 8 bits are not zero. Printing
* a floating point number in the kernel is a no-no,
* always print the number as 32 bit unsigned integer.
- * The user-space needs to know about the stange
+ * The user-space needs to know about the strange
* encoding of the alternate cpu capability.
*/
len += sprintf(page + len, "Capability: %u %u\n",
@@ -351,3 +357,58 @@ static __init int create_proc_sysinfo(void)
__initcall(create_proc_sysinfo);
+/*
+ * CPU capability might have changed. Therefore recalculate loops_per_jiffy.
+ */
+void s390_adjust_jiffies(void)
+{
+ struct sysinfo_1_2_2 *info;
+ const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_EX;
+ unsigned int capability;
+
+ info = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!info)
+ return;
+
+ if (stsi(info, 1, 2, 2) != -ENOSYS) {
+ /*
+ * Major sigh. The cpu capability encoding is "special".
+ * If the first 9 bits of info->capability are 0 then it
+ * is a 32 bit unsigned integer in the range 0 .. 2^23.
+ * If the first 9 bits are != 0 then it is a 32 bit float.
+ * In addition a lower value indicates a proportionally
+ * higher cpu capacity. Bogomips are the other way round.
+ * To get to a halfway suitable number we divide 1e7
+ * by the cpu capability number. Yes, that means a floating
+ * point division .. math-emu here we come :-)
+ */
+ FP_UNPACK_SP(SA, &fmil);
+ if ((info->capability >> 23) == 0)
+ FP_FROM_INT_S(SB, info->capability, 32, int);
+ else
+ FP_UNPACK_SP(SB, &info->capability);
+ FP_DIV_S(SR, SA, SB);
+ FP_TO_INT_S(capability, SR, 32, 0);
+ } else
+ /*
+ * Really old machine without stsi block for basic
+ * cpu information. Report 42.0 bogomips.
+ */
+ capability = 42;
+ loops_per_jiffy = capability * (500000/HZ);
+ free_page((unsigned long) info);
+}
+
+/*
+ * calibrate the delay loop
+ */
+void __init calibrate_delay(void)
+{
+ s390_adjust_jiffies();
+ /* Print the good old Bogomips line .. */
+ printk(KERN_DEBUG "Calibrating delay loop (skipped)... "
+ "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ)) % 100);
+}
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index 385f4f76831..ac7d1258efe 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -621,7 +621,7 @@ static long read_ecp(unsigned minor, char __user *c, unsigned long cnt)
static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos)
{
long rc;
- unsigned minor = iminor(f->f_dentry->d_inode);
+ unsigned minor = iminor(f->f_path.dentry->d_inode);
if (minor >= BPP_NO) return -ENODEV;
if (!instances[minor].present) return -ENODEV;
@@ -774,7 +774,7 @@ static long write_ecp(unsigned minor, const char __user *c, unsigned long cnt)
static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos)
{
long errno = 0;
- unsigned minor = iminor(f->f_dentry->d_inode);
+ unsigned minor = iminor(f->f_path.dentry->d_inode);
if (minor >= BPP_NO) return -ENODEV;
if (!instances[minor].present) return -ENODEV;
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
index f5803ecb199..ad1c7db96cb 100644
--- a/drivers/sbus/char/cpwatchdog.c
+++ b/drivers/sbus/char/cpwatchdog.c
@@ -404,7 +404,7 @@ static long wd_compat_ioctl(struct file *file, unsigned int cmd,
case WIOCSTOP:
case WIOCGSTAT:
lock_kernel();
- rval = wd_ioctl(file->f_dentry->d_inode, file, cmd, arg);
+ rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
unlock_kernel();
break;
/* everything else is handled by the generic compat layer */
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index d92bc8827a9..a4909e0c7f8 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -121,7 +121,7 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
__u8 ireg = 0;
int error = 0;
- if (D7S_MINOR != iminor(file->f_dentry->d_inode))
+ if (D7S_MINOR != iminor(file->f_path.dentry->d_inode))
return -ENODEV;
lock_kernel();
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 81ba2d71cee..4e2a0e2dcc2 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -676,7 +676,7 @@ static long openprom_compat_ioctl(struct file *file, unsigned int cmd,
case OPROMSETCUR:
case OPROMPCI2NODE:
case OPROMPATH2NODE:
- rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg);
+ rval = openprom_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
break;
}
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 55b2b31bd7a..386e7de0b7e 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -610,7 +610,7 @@ static int vfc_mmap(struct file *file, struct vm_area_struct *vma)
unsigned int map_size, ret, map_offset;
struct vfc_dev *dev;
- dev = vfc_get_dev_ptr(iminor(file->f_dentry->d_inode));
+ dev = vfc_get_dev_ptr(iminor(file->f_path.dentry->d_inode));
if(dev == NULL)
return -ENODEV;
@@ -659,7 +659,7 @@ static int vfc_probe(void)
if (!cards)
return -ENODEV;
- vfc_dev_lst = (struct vfc_dev **)kmalloc(sizeof(struct vfc_dev *) *
+ vfc_dev_lst = kmalloc(sizeof(struct vfc_dev *) *
(cards+1),
GFP_KERNEL);
if (vfc_dev_lst == NULL)
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 99a259c5a0c..e1b44d6c0c3 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -6,7 +6,7 @@
Arnaldo Carvalho de Melo <acme@conectiva.com.br>
Brad Strand <linux@3ware.com>
- Copyright (C) 1999-2005 3ware Inc.
+ Copyright (C) 1999-2007 3ware Inc.
Kernel compatiblity By: Andre Hedrick <andre@suse.com>
Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com>
@@ -191,6 +191,9 @@
before shutting down card.
Change to new 'change_queue_depth' api.
Fix 'handled=1' ISR usage, remove bogus IRQ check.
+ 1.26.02.002 - Free irq handler in __tw_shutdown().
+ Turn on RCD bit for caching mode page.
+ Serialize reset code.
*/
#include <linux/module.h>
@@ -214,7 +217,7 @@
#include "3w-xxxx.h"
/* Globals */
-#define TW_DRIVER_VERSION "1.26.02.001"
+#define TW_DRIVER_VERSION "1.26.02.002"
static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
static int tw_device_extension_count = 0;
static int twe_major = -1;
@@ -226,7 +229,7 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(TW_DRIVER_VERSION);
/* Function prototypes */
-static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
+static int tw_reset_device_extension(TW_Device_Extension *tw_dev);
/* Functions */
@@ -984,24 +987,12 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
/* Now wait for the command to complete */
timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
- /* See if we reset while waiting for the ioctl to complete */
- if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
- clear_bit(TW_IN_RESET, &tw_dev->flags);
- retval = -ERESTARTSYS;
- goto out2;
- }
-
/* We timed out, and didn't get an interrupt */
if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
/* Now we need to reset the board */
printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
retval = -EIO;
- spin_lock_irqsave(tw_dev->host->host_lock, flags);
- tw_dev->state[request_id] = TW_S_COMPLETED;
- tw_state_request_finish(tw_dev, request_id);
- tw_dev->posted_request_count--;
- spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
- if (tw_reset_device_extension(tw_dev, 1)) {
+ if (tw_reset_device_extension(tw_dev)) {
printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
}
goto out2;
@@ -1336,7 +1327,7 @@ static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
} /* End tw_unmap_scsi_data() */
/* This function will reset a device extension */
-static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset)
+static int tw_reset_device_extension(TW_Device_Extension *tw_dev)
{
int i = 0;
struct scsi_cmnd *srb;
@@ -1382,15 +1373,10 @@ static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_rese
printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no);
return 1;
}
- TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
- /* Wake up any ioctl that was pending before the reset */
- if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) {
- clear_bit(TW_IN_RESET, &tw_dev->flags);
- } else {
- tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
- wake_up(&tw_dev->ioctl_wqueue);
- }
+ TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+ clear_bit(TW_IN_RESET, &tw_dev->flags);
+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
return 0;
} /* End tw_reset_device_extension() */
@@ -1437,14 +1423,18 @@ static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt)
"WARNING: Command (0x%x) timed out, resetting card.\n",
SCpnt->cmnd[0]);
+ /* Make sure we are not issuing an ioctl or resetting from ioctl */
+ mutex_lock(&tw_dev->ioctl_lock);
+
/* Now reset the card and some of the device extension data */
- if (tw_reset_device_extension(tw_dev, 0)) {
+ if (tw_reset_device_extension(tw_dev)) {
printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no);
goto out;
}
retval = SUCCESS;
out:
+ mutex_unlock(&tw_dev->ioctl_lock);
return retval;
} /* End tw_scsi_eh_reset() */
@@ -1660,9 +1650,9 @@ static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int reques
request_buffer[4] = 0x8; /* caching page */
request_buffer[5] = 0xa; /* page length */
if (*flags & 0x1)
- request_buffer[6] = 0x4; /* WCE on */
+ request_buffer[6] = 0x5; /* WCE on, RCD on */
else
- request_buffer[6] = 0x0; /* WCE off */
+ request_buffer[6] = 0x1; /* WCE off, RCD on */
tw_transfer_internal(tw_dev, request_id, request_buffer,
sizeof(request_buffer));
@@ -2012,6 +2002,10 @@ static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd
int retval = 1;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+ /* If we are resetting due to timed out ioctl, report as busy */
+ if (test_bit(TW_IN_RESET, &tw_dev->flags))
+ return SCSI_MLQUEUE_HOST_BUSY;
+
/* Save done function into Scsi_Cmnd struct */
SCpnt->scsi_done = done;
@@ -2100,6 +2094,10 @@ static irqreturn_t tw_interrupt(int irq, void *dev_instance)
handled = 1;
+ /* If we are resetting, bail */
+ if (test_bit(TW_IN_RESET, &tw_dev->flags))
+ goto tw_interrupt_bail;
+
/* Check controller for errors */
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
@@ -2276,6 +2274,9 @@ static void __tw_shutdown(TW_Device_Extension *tw_dev)
/* Disable interrupts */
TW_DISABLE_INTERRUPTS(tw_dev);
+ /* Free up the IRQ */
+ free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+
printk(KERN_WARNING "3w-xxxx: Shutting down host %d.\n", tw_dev->host->host_no);
/* Tell the card we are shutting down */
@@ -2444,9 +2445,6 @@ static void tw_remove(struct pci_dev *pdev)
twe_major = -1;
}
- /* Free up the IRQ */
- free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
-
/* Shutdown the card */
__tw_shutdown(tw_dev);
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
index bbd654a2b9b..0742e684665 100644
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -6,7 +6,7 @@
Arnaldo Carvalho de Melo <acme@conectiva.com.br>
Brad Strand <linux@3ware.com>
- Copyright (C) 1999-2005 3ware Inc.
+ Copyright (C) 1999-2007 3ware Inc.
Kernel compatiblity By: Andre Hedrick <andre@suse.com>
Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com>
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 69569096dae..7869c34a4a3 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1303,7 +1303,7 @@ config SCSI_LPFC
config SCSI_SEAGATE
tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support"
- depends on X86 && ISA && SCSI && BROKEN
+ depends on X86 && ISA && SCSI
---help---
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,
@@ -1737,7 +1737,7 @@ config SCSI_NCR53C7xx_FAST
config SUN3_SCSI
tristate "Sun3 NCR5380 SCSI"
- depends on SUN3 && SCSI && BROKEN
+ depends on SUN3 && SCSI
select SCSI_SPI_ATTRS
help
This option will enable support for the OBIO (onboard io) NCR5380
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 3c912ee29da..8b5334c56f0 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -528,12 +528,16 @@ void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
/* Allocate structure and insert basic data such as SCSI chip frequency
* data and a pointer to the device
*/
-struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev)
+struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev,
+ int hotplug)
{
struct NCR_ESP *esp, *elink;
struct Scsi_Host *esp_host;
- esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
+ if (hotplug)
+ esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP));
+ else
+ esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
if(!esp_host)
panic("Cannot register ESP SCSI host");
esp = (struct NCR_ESP *) esp_host->hostdata;
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
index 521e3f842cf..d85cb73a9f6 100644
--- a/drivers/scsi/NCR53C9x.h
+++ b/drivers/scsi/NCR53C9x.h
@@ -652,7 +652,7 @@ extern int nesps, esps_in_use, esps_running;
/* External functions */
extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs);
-extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *);
+extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int);
extern void esp_deallocate(struct NCR_ESP *);
extern void esp_release(void);
extern void esp_initialize(struct NCR_ESP *);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index ac108f9e267..426cd6f49f5 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -288,7 +288,7 @@ int aac_get_containers(struct aac_dev *dev)
if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
- fsa_dev_ptr = (struct fsa_dev_info *) kmalloc(
+ fsa_dev_ptr = kmalloc(
sizeof(*fsa_dev_ptr) * maximum_num_containers, GFP_KERNEL);
if (!fsa_dev_ptr) {
aac_fib_free(fibptr);
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index d5cf8b91a0e..6d305b2f854 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -386,7 +386,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
* Ok now init the communication subsystem
*/
- dev->queues = (struct aac_queue_block *) kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
+ dev->queues = kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
if (dev->queues == NULL) {
printk(KERN_ERR "Error could not allocate comm region.\n");
return NULL;
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 359e7ddfdb4..d2cf875af59 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -117,8 +117,8 @@ static struct pci_device_id aac_pci_tbl[] = {
{ 0x9005, 0x0286, 0x9005, 0x029b, 0, 0, 22 }, /* AAR-2820SA (Intruder) */
{ 0x9005, 0x0286, 0x9005, 0x029c, 0, 0, 23 }, /* AAR-2620SA (Intruder) */
{ 0x9005, 0x0286, 0x9005, 0x029d, 0, 0, 24 }, /* AAR-2420SA (Intruder) */
- { 0x9005, 0x0286, 0x9005, 0x029e, 0, 0, 25 }, /* ICP9024R0 (Lancer) */
- { 0x9005, 0x0286, 0x9005, 0x029f, 0, 0, 26 }, /* ICP9014R0 (Lancer) */
+ { 0x9005, 0x0286, 0x9005, 0x029e, 0, 0, 25 }, /* ICP9024RO (Lancer) */
+ { 0x9005, 0x0286, 0x9005, 0x029f, 0, 0, 26 }, /* ICP9014RO (Lancer) */
{ 0x9005, 0x0286, 0x9005, 0x02a0, 0, 0, 27 }, /* ICP9047MA (Lancer) */
{ 0x9005, 0x0286, 0x9005, 0x02a1, 0, 0, 28 }, /* ICP9087MA (Lancer) */
{ 0x9005, 0x0286, 0x9005, 0x02a3, 0, 0, 29 }, /* ICP5445AU (Hurricane44) */
@@ -137,15 +137,15 @@ static struct pci_device_id aac_pci_tbl[] = {
{ 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 41 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
{ 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 42 }, /* AAR-2610SA PCI SATA 6ch */
{ 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 43 }, /* ASR-2240S (SabreExpress) */
- { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005SAS */
+ { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005 */
{ 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 45 }, /* IBM 8i (AvonPark) */
{ 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 45 }, /* IBM 8i (AvonPark Lite) */
{ 0x9005, 0x0286, 0x1014, 0x9580, 0, 0, 46 }, /* IBM 8k/8k-l8 (Aurora) */
{ 0x9005, 0x0286, 0x1014, 0x9540, 0, 0, 47 }, /* IBM 8k/8k-l4 (Aurora Lite) */
- { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000SAS (BlackBird) */
+ { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000 (BlackBird) */
{ 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 49 }, /* ASR-4800SAS (Marauder-X) */
{ 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 50 }, /* ASR-4805SAS (Marauder-E) */
- { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-3800SAS (Hurricane44) */
+ { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-3800 (Hurricane44) */
{ 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 52 }, /* Perc 320/DC*/
{ 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 53 }, /* Adaptec 5400S (Mustang)*/
@@ -193,8 +193,8 @@ static struct aac_driver_ident aac_drivers[] = {
{ aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2820SA ", 1 }, /* AAR-2820SA (Intruder) */
{ aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2620SA ", 1 }, /* AAR-2620SA (Intruder) */
{ aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2420SA ", 1 }, /* AAR-2420SA (Intruder) */
- { aac_rkt_init, "aacraid", "ICP ", "ICP9024R0 ", 2 }, /* ICP9024R0 (Lancer) */
- { aac_rkt_init, "aacraid", "ICP ", "ICP9014R0 ", 1 }, /* ICP9014R0 (Lancer) */
+ { aac_rkt_init, "aacraid", "ICP ", "ICP9024RO ", 2 }, /* ICP9024RO (Lancer) */
+ { aac_rkt_init, "aacraid", "ICP ", "ICP9014RO ", 1 }, /* ICP9014RO (Lancer) */
{ aac_rkt_init, "aacraid", "ICP ", "ICP9047MA ", 1 }, /* ICP9047MA (Lancer) */
{ aac_rkt_init, "aacraid", "ICP ", "ICP9087MA ", 1 }, /* ICP9087MA (Lancer) */
{ aac_rkt_init, "aacraid", "ICP ", "ICP5445AU ", 1 }, /* ICP5445AU (Hurricane44) */
@@ -212,14 +212,14 @@ static struct aac_driver_ident aac_drivers[] = {
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2026ZCR ", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2610SA ", 1 }, /* SATA 6Ch (Bearcat) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S (SabreExpress) */
- { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005SAS ", 1 }, /* ASR-4005SAS */
+ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005 ", 1 }, /* ASR-4005 */
{ aac_rx_init, "ServeRAID","IBM ", "ServeRAID 8i ", 1 }, /* IBM 8i (AvonPark) */
{ aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l8 ", 1 }, /* IBM 8k/8k-l8 (Aurora) */
{ aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l4 ", 1 }, /* IBM 8k/8k-l4 (Aurora Lite) */
- { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000SAS ", 1 }, /* ASR-4000SAS (BlackBird & AvonPark) */
+ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000 ", 1 }, /* ASR-4000 (BlackBird & AvonPark) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS (Marauder-X) */
{ aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS (Marauder-E) */
- { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-3800SAS ", 1 }, /* ASR-3800SAS (Hurricane44) */
+ { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-3800 ", 1 }, /* ASR-3800 (Hurricane44) */
{ aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/
{ aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 2b344356a29..306bec355e4 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -18215,6 +18215,7 @@ AdvInquiryHandling(
}
MODULE_LICENSE("Dual BSD/GPL");
+#ifdef CONFIG_PCI
/* PCI Devices supported by this driver */
static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
@@ -18232,4 +18233,4 @@ static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
{ }
};
MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
-
+#endif /* CONFIG_PCI */
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index d7a61a6bdaa..1d239f6c010 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -699,7 +699,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
#endif
int i;
ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */
- SCpnt->host_scribble = (unsigned char *) kmalloc(512, GFP_KERNEL | GFP_DMA);
+ SCpnt->host_scribble = kmalloc(512, GFP_KERNEL | GFP_DMA);
sgpnt = (struct scatterlist *) SCpnt->request_buffer;
cptr = (struct chain *) SCpnt->host_scribble;
if (cptr == NULL) {
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 46eed10b25d..7d1fec62094 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -2565,7 +2565,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
}
}
scb_count = min( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs);
- scb_ap = (struct aic7xxx_scb *)kmalloc(sizeof (struct aic7xxx_scb) * scb_count
+ scb_ap = kmalloc(sizeof (struct aic7xxx_scb) * scb_count
+ sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC);
if (scb_ap == NULL)
return(0);
diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
index 329a8f297b3..23f7c24ab80 100644
--- a/drivers/scsi/blz1230.c
+++ b/drivers/scsi/blz1230.c
@@ -121,7 +121,8 @@ int __init blz1230_esp_detect(struct scsi_host_template *tpnt)
*/
address = ZTWO_VADDR(board);
eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR);
- esp = esp_allocate(tpnt, (void *)board+REAL_BLZ1230_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR,
+ 0);
esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
udelay(5);
diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
index b6c137b9735..b6203ec0096 100644
--- a/drivers/scsi/blz2060.c
+++ b/drivers/scsi/blz2060.c
@@ -100,7 +100,7 @@ int __init blz2060_esp_detect(struct scsi_host_template *tpnt)
unsigned long board = z->resource.start;
if (request_mem_region(board+BLZ2060_ESP_ADDR,
sizeof(struct ESP_regs), "NCR53C9x")) {
- esp = esp_allocate(tpnt, (void *)board+BLZ2060_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
index 7c7cfb54e89..c6b98a42e89 100644
--- a/drivers/scsi/cyberstorm.c
+++ b/drivers/scsi/cyberstorm.c
@@ -126,7 +126,7 @@ int __init cyber_esp_detect(struct scsi_host_template *tpnt)
sizeof(struct ESP_regs));
return 0;
}
- esp = esp_allocate(tpnt, (void *)board+CYBER_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
index d88cb9cf091..e336e853e66 100644
--- a/drivers/scsi/cyberstormII.c
+++ b/drivers/scsi/cyberstormII.c
@@ -98,7 +98,7 @@ int __init cyberII_esp_detect(struct scsi_host_template *tpnt)
address = (unsigned long)ZTWO_VADDR(board);
eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR);
- esp = esp_allocate(tpnt, (void *)board+CYBERII_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0);
esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
udelay(5);
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index e95b367d09e..a965ed3548d 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -4319,7 +4319,7 @@ static int __devinit adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages);
while (pages--) {
- ptr = (struct SGentry *)kmalloc(PAGE_SIZE, GFP_KERNEL);
+ ptr = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!ptr) {
adapter_sg_tables_free(acb);
return 1;
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
index c29ccbc4469..d42ad663ffe 100644
--- a/drivers/scsi/dec_esp.c
+++ b/drivers/scsi/dec_esp.c
@@ -18,7 +18,7 @@
* 20001005 - Initialization fixes for 2.4.0-test9
* Florian Lohoff <flo@rfc822.org>
*
- * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki
+ * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki
*/
#include <linux/kernel.h>
@@ -30,6 +30,7 @@
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
+#include <linux/tc.h>
#include <asm/dma.h>
#include <asm/irq.h>
@@ -42,7 +43,6 @@
#include <asm/dec/ioasic_ints.h>
#include <asm/dec/machtype.h>
#include <asm/dec/system.h>
-#include <asm/dec/tc.h>
#define DEC_SCSI_SREG 0
#define DEC_SCSI_DMAREG 0x40000
@@ -98,51 +98,33 @@ 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);
-
-static int dec_esp_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, NULL);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- scsi_unregister(shost);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .proc_name = "dec_esp",
- .proc_info = esp_proc_info,
+static struct scsi_host_template dec_esp_template = {
+ .module = THIS_MODULE,
.name = "NCR53C94",
- .detect = dec_esp_detect,
- .slave_alloc = esp_slave_alloc,
- .slave_destroy = esp_slave_destroy,
- .release = dec_esp_release,
.info = esp_info,
.queuecommand = esp_queue,
.eh_abort_handler = esp_abort,
.eh_bus_reset_handler = esp_reset,
+ .slave_alloc = esp_slave_alloc,
+ .slave_destroy = esp_slave_destroy,
+ .proc_info = esp_proc_info,
+ .proc_name = "dec_esp",
.can_queue = 7,
- .this_id = 7,
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
};
-
-#include "scsi_module.c"
+static struct NCR_ESP *dec_esp_platform;
/***************************************************************** Detection */
-static int dec_esp_detect(struct scsi_host_template * tpnt)
+static int dec_esp_platform_probe(void)
{
struct NCR_ESP *esp;
- struct ConfigDev *esp_dev;
- int slot;
- unsigned long mem_start;
+ int err = 0;
if (IOASIC) {
- esp_dev = 0;
- esp = esp_allocate(tpnt, (void *) esp_dev);
+ esp = esp_allocate(&dec_esp_template, NULL, 1);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
@@ -200,112 +182,175 @@ static int dec_esp_detect(struct scsi_host_template * tpnt)
/* Check for differential SCSI-bus */
esp->diff = 0;
+ err = request_irq(esp->irq, esp_intr, IRQF_DISABLED,
+ "ncr53c94", esp->ehost);
+ if (err)
+ goto err_alloc;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
+ scsi_dma_merr_int, IRQF_DISABLED,
+ "ncr53c94 error", esp->ehost);
+ if (err)
+ goto err_irq;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
+ scsi_dma_err_int, IRQF_DISABLED,
+ "ncr53c94 overrun", esp->ehost);
+ if (err)
+ goto err_irq_merr;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int,
+ IRQF_DISABLED, "ncr53c94 dma", esp->ehost);
+ if (err)
+ goto err_irq_err;
+
esp_initialize(esp);
- if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
- "ncr53c94", esp->ehost))
- goto err_dealloc;
- if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
- scsi_dma_merr_int, IRQF_DISABLED,
- "ncr53c94 error", esp->ehost))
- goto err_free_irq;
- if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
- scsi_dma_err_int, IRQF_DISABLED,
- "ncr53c94 overrun", esp->ehost))
- goto err_free_irq_merr;
- if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA],
- scsi_dma_int, IRQF_DISABLED,
- "ncr53c94 dma", esp->ehost))
- goto err_free_irq_err;
+ err = scsi_add_host(esp->ehost, NULL);
+ if (err) {
+ printk(KERN_ERR "ESP: Unable to register adapter\n");
+ goto err_irq_dma;
+ }
+
+ scsi_scan_host(esp->ehost);
+ dec_esp_platform = esp;
}
- if (TURBOCHANNEL) {
- while ((slot = search_tc_card("PMAZ-AA")) >= 0) {
- claim_tc_card(slot);
-
- esp_dev = 0;
- esp = esp_allocate(tpnt, (void *) esp_dev);
-
- mem_start = get_tc_base_addr(slot);
-
- /* Store base addr into esp struct */
- esp->slot = CPHYSADDR(mem_start);
-
- esp->dregs = 0;
- esp->eregs = (void *)CKSEG1ADDR(mem_start +
- DEC_SCSI_SREG);
- esp->do_pio_cmds = 1;
-
- /* Set the command buffer */
- esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer;
-
- /* get virtual dma address for command buffer */
- esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
-
- esp->cfreq = get_tc_speed();
-
- esp->irq = get_tc_irq_nr(slot);
-
- /* Required functions */
- esp->dma_bytes_sent = &dma_bytes_sent;
- esp->dma_can_transfer = &dma_can_transfer;
- esp->dma_dump_state = &dma_dump_state;
- esp->dma_init_read = &pmaz_dma_init_read;
- esp->dma_init_write = &pmaz_dma_init_write;
- esp->dma_ints_off = &pmaz_dma_ints_off;
- esp->dma_ints_on = &pmaz_dma_ints_on;
- esp->dma_irq_p = &dma_irq_p;
- esp->dma_ports_p = &dma_ports_p;
- esp->dma_setup = &pmaz_dma_setup;
-
- /* Optional functions */
- esp->dma_barrier = 0;
- esp->dma_drain = &pmaz_dma_drain;
- esp->dma_invalidate = 0;
- esp->dma_irq_entry = 0;
- esp->dma_irq_exit = 0;
- esp->dma_poll = 0;
- esp->dma_reset = 0;
- esp->dma_led_off = 0;
- esp->dma_led_on = 0;
-
- esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
- esp->dma_mmu_get_scsi_sgl = 0;
- esp->dma_mmu_release_scsi_one = 0;
- esp->dma_mmu_release_scsi_sgl = 0;
- esp->dma_advance_sg = 0;
-
- if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
- "PMAZ_AA", esp->ehost)) {
- esp_deallocate(esp);
- release_tc_card(slot);
- continue;
- }
- esp->scsi_id = 7;
- esp->diff = 0;
- esp_initialize(esp);
- }
+ return 0;
+
+err_irq_dma:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost);
+err_irq_err:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost);
+err_irq_merr:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost);
+err_irq:
+ free_irq(esp->irq, esp->ehost);
+err_alloc:
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+ return err;
+}
+
+static int __init dec_esp_probe(struct device *dev)
+{
+ struct NCR_ESP *esp;
+ resource_size_t start, len;
+ int err;
+
+ esp = esp_allocate(&dec_esp_template, NULL, 1);
+
+ dev_set_drvdata(dev, esp);
+
+ start = to_tc_dev(dev)->resource.start;
+ len = to_tc_dev(dev)->resource.end - start + 1;
+
+ if (!request_mem_region(start, len, dev->bus_id)) {
+ printk(KERN_ERR "%s: Unable to reserve MMIO resource\n",
+ dev->bus_id);
+ err = -EBUSY;
+ goto err_alloc;
}
- if(nesps) {
- printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
- esps_running = esps_in_use;
- return esps_in_use;
+ /* Store base addr into esp struct. */
+ esp->slot = start;
+
+ esp->dregs = 0;
+ esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG);
+ esp->do_pio_cmds = 1;
+
+ /* Set the command buffer. */
+ esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer;
+
+ /* Get virtual dma address for command buffer. */
+ esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
+
+ esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus);
+
+ esp->irq = to_tc_dev(dev)->interrupt;
+
+ /* Required functions. */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &pmaz_dma_init_read;
+ esp->dma_init_write = &pmaz_dma_init_write;
+ esp->dma_ints_off = &pmaz_dma_ints_off;
+ esp->dma_ints_on = &pmaz_dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &pmaz_dma_setup;
+
+ /* Optional functions. */
+ esp->dma_barrier = 0;
+ esp->dma_drain = &pmaz_dma_drain;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = 0;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+ esp->dma_led_off = 0;
+ esp->dma_led_on = 0;
+
+ esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
+ esp->dma_mmu_get_scsi_sgl = 0;
+ esp->dma_mmu_release_scsi_one = 0;
+ esp->dma_mmu_release_scsi_sgl = 0;
+ esp->dma_advance_sg = 0;
+
+ err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA",
+ esp->ehost);
+ if (err) {
+ printk(KERN_ERR "%s: Unable to get IRQ %d\n",
+ dev->bus_id, esp->irq);
+ goto err_resource;
+ }
+
+ esp->scsi_id = 7;
+ esp->diff = 0;
+ esp_initialize(esp);
+
+ err = scsi_add_host(esp->ehost, dev);
+ if (err) {
+ printk(KERN_ERR "%s: Unable to register adapter\n",
+ dev->bus_id);
+ goto err_irq;
}
+
+ scsi_scan_host(esp->ehost);
+
return 0;
-err_free_irq_err:
- free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int);
-err_free_irq_merr:
- free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int);
-err_free_irq:
- free_irq(esp->irq, esp_intr);
-err_dealloc:
+err_irq:
+ free_irq(esp->irq, esp->ehost);
+
+err_resource:
+ release_mem_region(start, len);
+
+err_alloc:
esp_deallocate(esp);
- return 0;
+ scsi_host_put(esp->ehost);
+ return err;
+}
+
+static void __exit dec_esp_platform_remove(void)
+{
+ struct NCR_ESP *esp = dec_esp_platform;
+
+ free_irq(esp->irq, esp->ehost);
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+ dec_esp_platform = NULL;
}
+static void __exit dec_esp_remove(struct device *dev)
+{
+ struct NCR_ESP *esp = dev_get_drvdata(dev);
+
+ free_irq(esp->irq, esp->ehost);
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+}
+
+
/************************************************************* DMA Functions */
static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id)
{
@@ -576,3 +621,67 @@ static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp
{
sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer);
}
+
+
+#ifdef CONFIG_TC
+static int __init dec_esp_tc_probe(struct device *dev);
+static int __exit dec_esp_tc_remove(struct device *dev);
+
+static const struct tc_device_id dec_esp_tc_table[] = {
+ { "DEC ", "PMAZ-AA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, dec_esp_tc_table);
+
+static struct tc_driver dec_esp_tc_driver = {
+ .id_table = dec_esp_tc_table,
+ .driver = {
+ .name = "dec_esp",
+ .bus = &tc_bus_type,
+ .probe = dec_esp_tc_probe,
+ .remove = __exit_p(dec_esp_tc_remove),
+ },
+};
+
+static int __init dec_esp_tc_probe(struct device *dev)
+{
+ int status = dec_esp_probe(dev);
+ if (!status)
+ get_device(dev);
+ return status;
+}
+
+static int __exit dec_esp_tc_remove(struct device *dev)
+{
+ put_device(dev);
+ dec_esp_remove(dev);
+ return 0;
+}
+#endif
+
+static int __init dec_esp_init(void)
+{
+ int status;
+
+ status = tc_register_driver(&dec_esp_tc_driver);
+ if (!status)
+ dec_esp_platform_probe();
+
+ if (nesps) {
+ pr_info("ESP: Total of %d ESP hosts found, "
+ "%d actually in use.\n", nesps, esps_in_use);
+ esps_running = esps_in_use;
+ }
+
+ return status;
+}
+
+static void __exit dec_esp_exit(void)
+{
+ dec_esp_platform_remove();
+ tc_unregister_driver(&dec_esp_tc_driver);
+}
+
+
+module_init(dec_esp_init);
+module_exit(dec_esp_exit);
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 60b1b434eba..365db537a28 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -297,7 +297,7 @@ static void adpt_inquiry(adpt_hba* pHba)
s32 rcode;
memset(msg, 0, sizeof(msg));
- buf = (u8*)kmalloc(80,GFP_KERNEL|ADDR32);
+ buf = kmalloc(80,GFP_KERNEL|ADDR32);
if(!buf){
printk(KERN_ERR"%s: Could not allocate buffer\n",pHba->name);
return;
@@ -1311,7 +1311,7 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
schedule_timeout_uninterruptible(1);
} while (m == EMPTY_QUEUE);
- status = (u8*)kmalloc(4, GFP_KERNEL|ADDR32);
+ status = kmalloc(4, GFP_KERNEL|ADDR32);
if(status == NULL) {
adpt_send_nop(pHba, m);
printk(KERN_ERR"IOP reset failed - no free memory.\n");
@@ -1444,7 +1444,7 @@ static int adpt_i2o_parse_lct(adpt_hba* pHba)
}
continue;
}
- d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+ d = kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
if(d==NULL)
{
printk(KERN_CRIT"%s: Out of memory for I2O device data.\n",pHba->name);
@@ -2425,7 +2425,7 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
pDev = pDev->next_lun;
}
if(!pDev ) { // Something new add it
- d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+ d = kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
if(d==NULL)
{
printk(KERN_CRIT "Out of memory for I2O device data.\n");
@@ -2728,7 +2728,7 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
kfree(pHba->reply_pool);
- pHba->reply_pool = (u32*)kmalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
+ pHba->reply_pool = kmalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
if(!pHba->reply_pool){
printk(KERN_ERR"%s: Could not allocate reply pool\n",pHba->name);
return -1;
diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
index 2a1c5c22b9e..4266a2139b5 100644
--- a/drivers/scsi/fastlane.c
+++ b/drivers/scsi/fastlane.c
@@ -142,7 +142,7 @@ int __init fastlane_esp_detect(struct scsi_host_template *tpnt)
if (board < 0x1000000) {
goto err_release;
}
- esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
index 6ac0633d545..f67d9efc7a9 100644
--- a/drivers/scsi/ibmvscsi/Makefile
+++ b/drivers/scsi/ibmvscsi/Makefile
@@ -1,7 +1,9 @@
obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o
ibmvscsic-y += ibmvscsi.o
+ifndef CONFIG_PPC_PSERIES
ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o
+endif
ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o
obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index f160357e37a..d561663fb4e 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -2828,7 +2828,7 @@ static int i91u_detect(struct scsi_host_template * tpnt)
for (; tul_num_scb >= MAX_TARGETS + 3; tul_num_scb--) {
i = tul_num_ch * tul_num_scb * sizeof(SCB);
- if ((tul_scb = (SCB *) kmalloc(i, GFP_ATOMIC | GFP_DMA)) != NULL)
+ if ((tul_scb = kmalloc(i, GFP_ATOMIC | GFP_DMA)) != NULL)
break;
}
if (tul_scb == NULL) {
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index b318500785e..821386c7b57 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -7558,9 +7558,6 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
- { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7,
0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index d0b139cccbb..8f55e143143 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -749,7 +749,7 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
if (!offset)
crypto_hash_update(
&tcp_conn->rx_hash,
- &sg[i], 1);
+ &sg[i], sg[i].length);
else
partial_sg_digest_update(
&tcp_conn->rx_hash,
@@ -1375,7 +1375,7 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
}
BUG_ON(tcp_mtask->xmstate != XMSTATE_IDLE);
- if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
+ if (mtask->hdr->itt == RESERVED_ITT) {
struct iscsi_session *session = conn->session;
spin_lock_bh(&session->lock);
@@ -1777,13 +1777,13 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
CRYPTO_ALG_ASYNC);
tcp_conn->tx_hash.flags = 0;
- if (!tcp_conn->tx_hash.tfm)
+ if (IS_ERR(tcp_conn->tx_hash.tfm))
goto free_tcp_conn;
tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
CRYPTO_ALG_ASYNC);
tcp_conn->rx_hash.flags = 0;
- if (!tcp_conn->rx_hash.tfm)
+ if (IS_ERR(tcp_conn->rx_hash.tfm))
goto free_tx_tfm;
return cls_conn;
@@ -2044,13 +2044,11 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
sk = tcp_conn->sock->sk;
if (sk->sk_family == PF_INET) {
inet = inet_sk(sk);
- len = sprintf(buf, "%u.%u.%u.%u\n",
+ len = sprintf(buf, NIPQUAD_FMT "\n",
NIPQUAD(inet->daddr));
} else {
np = inet6_sk(sk);
- len = sprintf(buf,
- "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
- NIP6(np->daddr));
+ len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr));
}
mutex_unlock(&conn->xmitmutex);
break;
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index bfac4441d89..19dd4b962e1 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -75,7 +75,7 @@ static int jazz_esp_detect(struct scsi_host_template *tpnt)
*/
if (1) {
esp_dev = NULL;
- esp = esp_allocate(tpnt, (void *) esp_dev);
+ esp = esp_allocate(tpnt, esp_dev, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index e11b23c641e..7c75771c77f 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -113,8 +113,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
hdr->opcode = ISCSI_OP_SCSI_CMD;
hdr->flags = ISCSI_ATTR_SIMPLE;
int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
- hdr->itt = ctask->itt | (conn->id << ISCSI_CID_SHIFT) |
- (session->age << ISCSI_AGE_SHIFT);
+ hdr->itt = build_itt(ctask->itt, conn->id, session->age);
hdr->data_length = cpu_to_be32(sc->request_bufflen);
hdr->cmdsn = cpu_to_be32(session->cmdsn);
session->cmdsn++;
@@ -260,7 +259,7 @@ static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
}
if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) {
- int senselen;
+ uint16_t senselen;
if (datalen < 2) {
invalid_datalen:
@@ -270,12 +269,12 @@ invalid_datalen:
goto out;
}
- senselen = (data[0] << 8) | data[1];
+ senselen = be16_to_cpu(*(__be16 *)data);
if (datalen < senselen)
goto invalid_datalen;
memcpy(sc->sense_buffer, data + 2,
- min(senselen, SCSI_SENSE_BUFFERSIZE));
+ min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
debug_scsi("copied %d bytes of sense\n",
min(senselen, SCSI_SENSE_BUFFERSIZE));
}
@@ -338,7 +337,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
- itt = rejected_pdu.itt & ISCSI_ITT_MASK;
+ itt = get_itt(rejected_pdu.itt);
printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
"due to DataDigest error.\n", itt,
rejected_pdu.opcode);
@@ -367,10 +366,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
struct iscsi_mgmt_task *mtask;
uint32_t itt;
- if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG))
- itt = hdr->itt & ISCSI_ITT_MASK;
+ if (hdr->itt != RESERVED_ITT)
+ itt = get_itt(hdr->itt);
else
- itt = hdr->itt;
+ itt = ~0U;
if (itt < session->cmds_max) {
ctask = session->cmds[itt];
@@ -440,7 +439,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
iscsi_tmf_rsp(conn, hdr);
break;
case ISCSI_OP_NOOP_IN:
- if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) {
+ if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
rc = ISCSI_ERR_PROTO;
break;
}
@@ -457,7 +456,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
rc = ISCSI_ERR_BAD_OPCODE;
break;
}
- } else if (itt == ISCSI_RESERVED_TAG) {
+ } else if (itt == ~0U) {
rc = iscsi_check_assign_cmdsn(session,
(struct iscsi_nopin*)hdr);
if (rc)
@@ -470,7 +469,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
break;
}
- if (hdr->ttt == ISCSI_RESERVED_TAG)
+ if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
break;
if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
@@ -516,24 +515,24 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
struct iscsi_cmd_task *ctask;
uint32_t itt;
- if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
- if ((hdr->itt & ISCSI_AGE_MASK) !=
+ if (hdr->itt != RESERVED_ITT) {
+ if (((__force u32)hdr->itt & ISCSI_AGE_MASK) !=
(session->age << ISCSI_AGE_SHIFT)) {
printk(KERN_ERR "iscsi: received itt %x expected "
- "session age (%x)\n", hdr->itt,
+ "session age (%x)\n", (__force u32)hdr->itt,
session->age & ISCSI_AGE_MASK);
return ISCSI_ERR_BAD_ITT;
}
- if ((hdr->itt & ISCSI_CID_MASK) !=
+ if (((__force u32)hdr->itt & ISCSI_CID_MASK) !=
(conn->id << ISCSI_CID_SHIFT)) {
printk(KERN_ERR "iscsi: received itt %x, expected "
- "CID (%x)\n", hdr->itt, conn->id);
+ "CID (%x)\n", (__force u32)hdr->itt, conn->id);
return ISCSI_ERR_BAD_ITT;
}
- itt = hdr->itt & ISCSI_ITT_MASK;
+ itt = get_itt(hdr->itt);
} else
- itt = hdr->itt;
+ itt = ~0U;
if (itt < session->cmds_max) {
ctask = session->cmds[itt];
@@ -896,9 +895,8 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
/*
* pre-format CmdSN for outgoing PDU.
*/
- if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
- hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) |
- (session->age << ISCSI_AGE_SHIFT);
+ if (hdr->itt != RESERVED_ITT) {
+ hdr->itt = build_itt(mtask->itt, conn->id, session->age);
nop->cmdsn = cpu_to_be32(session->cmdsn);
if (conn->c_stage == ISCSI_CONN_STARTED &&
!(hdr->opcode & ISCSI_OP_IMMEDIATE))
@@ -1064,7 +1062,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
spin_lock_bh(&session->lock);
ctask->mtask = (struct iscsi_mgmt_task *)
- session->mgmt_cmds[(hdr->itt & ISCSI_ITT_MASK) -
+ session->mgmt_cmds[get_itt(hdr->itt) -
ISCSI_MGMT_ITT_OFFSET];
if (conn->tmabort_state == TMABORT_INITIAL) {
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 066292d3995..ec3bbbde6f7 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -56,6 +56,9 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
pool->elements = kmalloc(sizeof(struct lpfc_dmabuf) *
LPFC_MBUF_POOL_SIZE, GFP_KERNEL);
+ if (!pool->elements)
+ goto fail_free_lpfc_mbuf_pool;
+
pool->max_count = 0;
pool->current_count = 0;
for ( i = 0; i < LPFC_MBUF_POOL_SIZE; i++) {
@@ -82,10 +85,11 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
fail_free_mbox_pool:
mempool_destroy(phba->mbox_mem_pool);
fail_free_mbuf_pool:
- while (--i)
+ while (i--)
pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
pool->elements[i].phys);
kfree(pool->elements);
+ fail_free_lpfc_mbuf_pool:
pci_pool_destroy(phba->lpfc_mbuf_pool);
fail_free_dma_buf_pool:
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index 3586fac9be9..bcb49021b7e 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -351,7 +351,7 @@ int mac_esp_detect(struct scsi_host_template * tpnt)
for (chipnum = 0; chipnum < chipspresent; chipnum ++) {
struct NCR_ESP * esp;
- esp = esp_allocate(tpnt, (void *) NULL);
+ esp = esp_allocate(tpnt, NULL, 0);
esp->eregs = (struct ESP_regs *) get_base(chipnum);
esp->dma_irq_p = &esp_dafb_dma_irq_p;
diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c
index 998a8bbc1a4..d693d0f2139 100644
--- a/drivers/scsi/mca_53c9x.c
+++ b/drivers/scsi/mca_53c9x.c
@@ -122,7 +122,7 @@ static int mca_esp_detect(struct scsi_host_template *tpnt)
if ((slot = mca_find_adapter(*id_to_check, 0)) !=
MCA_NOTFOUND)
{
- esp = esp_allocate(tpnt, (void *) NULL);
+ esp = esp_allocate(tpnt, NULL, 0);
pos[0] = mca_read_stored_pos(slot, 2);
pos[1] = mca_read_stored_pos(slot, 3);
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 046223b4ae5..b5bdd0d7a8b 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -13,8 +13,8 @@
* Version : v00.00.03.05
*
* Authors:
- * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
- * Sumant Patro <Sumant.Patro@lsil.com>
+ * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsi.com>
+ * Sumant Patro <Sumant.Patro@lsi.com>
*
* List of supported controllers
*
@@ -45,7 +45,7 @@
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGASAS_VERSION);
-MODULE_AUTHOR("sreenivas.bagalkote@lsil.com");
+MODULE_AUTHOR("megaraidlinux@lsi.com");
MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");
/*
diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
index c116a6ae3c5..26a6d55faf3 100644
--- a/drivers/scsi/oktagon_esp.c
+++ b/drivers/scsi/oktagon_esp.c
@@ -133,7 +133,7 @@ int oktagon_esp_detect(struct scsi_host_template *tpnt)
eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR);
/* This line was 5 lines lower */
- esp = esp_allocate(tpnt, (void *)board+OKTAGON_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0);
/* we have to shift the registers only one bit for oktagon */
esp->shift = 1;
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 824fe080d1d..bd6bbf61adb 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -521,10 +521,10 @@ static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_
break;
default: ; /* probably FILL */
}
- aux->filemark_cnt = ntohl(STp->filemark_cnt);
- aux->phys_fm = ntohl(0xffffffff);
- aux->last_mark_ppos = ntohl(STp->last_mark_ppos);
- aux->last_mark_lbn = ntohl(STp->last_mark_lbn);
+ aux->filemark_cnt = htonl(STp->filemark_cnt);
+ aux->phys_fm = htonl(0xffffffff);
+ aux->last_mark_ppos = htonl(STp->last_mark_ppos);
+ aux->last_mark_lbn = htonl(STp->last_mark_lbn);
}
/*
@@ -5777,7 +5777,7 @@ static int osst_probe(struct device *dev)
dev_num = i;
/* allocate a struct osst_tape for this device */
- tpnt = (struct osst_tape *)kmalloc(sizeof(struct osst_tape), GFP_ATOMIC);
+ tpnt = kmalloc(sizeof(struct osst_tape), GFP_ATOMIC);
if (tpnt == NULL) {
write_unlock(&os_scsi_tapes_lock);
printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
index 1e426f5d0ed..2cc7b5a1606 100644
--- a/drivers/scsi/osst.h
+++ b/drivers/scsi/osst.h
@@ -288,11 +288,11 @@ typedef struct {
#else
#error "Please fix <asm/byteorder.h>"
#endif
- u16 max_speed; /* Maximum speed supported in KBps */
+ __be16 max_speed; /* Maximum speed supported in KBps */
u8 reserved10, reserved11;
- u16 ctl; /* Continuous Transfer Limit in blocks */
- u16 speed; /* Current Speed, in KBps */
- u16 buffer_size; /* Buffer Size, in 512 bytes */
+ __be16 ctl; /* Continuous Transfer Limit in blocks */
+ __be16 speed; /* Current Speed, in KBps */
+ __be16 buffer_size; /* Buffer Size, in 512 bytes */
u8 reserved18, reserved19;
} osst_capabilities_page_t;
@@ -352,8 +352,8 @@ typedef struct {
u8 reserved2;
u8 density;
u8 reserved3,reserved4;
- u16 segtrk;
- u16 trks;
+ __be16 segtrk;
+ __be16 trks;
u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
} osst_tape_paramtr_page_t;
@@ -369,18 +369,18 @@ typedef struct {
typedef struct os_partition_s {
__u8 partition_num;
__u8 par_desc_ver;
- __u16 wrt_pass_cntr;
- __u32 first_frame_ppos;
- __u32 last_frame_ppos;
- __u32 eod_frame_ppos;
+ __be16 wrt_pass_cntr;
+ __be32 first_frame_ppos;
+ __be32 last_frame_ppos;
+ __be32 eod_frame_ppos;
} os_partition_t;
/*
* DAT entry
*/
typedef struct os_dat_entry_s {
- __u32 blk_sz;
- __u16 blk_cnt;
+ __be32 blk_sz;
+ __be16 blk_cnt;
__u8 flags;
__u8 reserved;
} os_dat_entry_t;
@@ -412,23 +412,23 @@ typedef struct os_dat_s {
* AUX
*/
typedef struct os_aux_s {
- __u32 format_id; /* hardware compability AUX is based on */
+ __be32 format_id; /* hardware compability AUX is based on */
char application_sig[4]; /* driver used to write this media */
- __u32 hdwr; /* reserved */
- __u32 update_frame_cntr; /* for configuration frame */
+ __be32 hdwr; /* reserved */
+ __be32 update_frame_cntr; /* for configuration frame */
__u8 frame_type;
__u8 frame_type_reserved;
__u8 reserved_18_19[2];
os_partition_t partition;
__u8 reserved_36_43[8];
- __u32 frame_seq_num;
- __u32 logical_blk_num_high;
- __u32 logical_blk_num;
+ __be32 frame_seq_num;
+ __be32 logical_blk_num_high;
+ __be32 logical_blk_num;
os_dat_t dat;
__u8 reserved188_191[4];
- __u32 filemark_cnt;
- __u32 phys_fm;
- __u32 last_mark_ppos;
+ __be32 filemark_cnt;
+ __be32 phys_fm;
+ __be32 last_mark_ppos;
__u8 reserved204_223[20];
/*
@@ -436,8 +436,8 @@ typedef struct os_aux_s {
*
* Linux specific fields:
*/
- __u32 next_mark_ppos; /* when known, points to next marker */
- __u32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */
+ __be32 next_mark_ppos; /* when known, points to next marker */
+ __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */
__u8 linux_specific[24];
__u8 reserved_256_511[256];
@@ -450,19 +450,19 @@ typedef struct os_fm_tab_s {
__u8 reserved_1;
__u8 fm_tab_ent_sz;
__u8 reserved_3;
- __u16 fm_tab_ent_cnt;
+ __be16 fm_tab_ent_cnt;
__u8 reserved6_15[10];
- __u32 fm_tab_ent[OS_FM_TAB_MAX];
+ __be32 fm_tab_ent[OS_FM_TAB_MAX];
} os_fm_tab_t;
typedef struct os_ext_trk_ey_s {
__u8 et_part_num;
__u8 fmt;
- __u16 fm_tab_off;
+ __be16 fm_tab_off;
__u8 reserved4_7[4];
- __u32 last_hlb_hi;
- __u32 last_hlb;
- __u32 last_pp;
+ __be32 last_hlb_hi;
+ __be32 last_hlb;
+ __be32 last_pp;
__u8 reserved20_31[12];
} os_ext_trk_ey_t;
@@ -479,17 +479,17 @@ typedef struct os_header_s {
char ident_str[8];
__u8 major_rev;
__u8 minor_rev;
- __u16 ext_trk_tb_off;
+ __be16 ext_trk_tb_off;
__u8 reserved12_15[4];
__u8 pt_par_num;
__u8 pt_reserved1_3[3];
os_partition_t partition[16];
- __u32 cfg_col_width;
- __u32 dat_col_width;
- __u32 qfa_col_width;
+ __be32 cfg_col_width;
+ __be32 dat_col_width;
+ __be32 qfa_col_width;
__u8 cartridge[16];
__u8 reserved304_511[208];
- __u32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */
+ __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */
os_ext_trk_tb_t ext_track_tb;
__u8 reserved17272_17735[464];
os_fm_tab_t dat_fm_tab;
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index d72df5dae4e..e16fe361436 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1629,7 +1629,6 @@ static int nsp_cs_probe(struct pcmcia_device *link)
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
- link->conf.Present = PRESENT_OPTION;
ret = nsp_cs_config(link);
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index fb7acea6028..5b458d2478f 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -545,8 +545,6 @@ SYM53C500_release(struct pcmcia_device *link)
*/
if (shost->irq)
free_irq(shost->irq, shost);
- if (shost->dma_channel != 0xff)
- free_dma(shost->dma_channel);
if (shost->io_port && shost->n_io_port)
release_region(shost->io_port, shost->n_io_port);
@@ -895,7 +893,6 @@ SYM53C500_probe(struct pcmcia_device *link)
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
- link->conf.Present = PRESENT_OPTION;
return SYM53C500_config(link);
} /* SYM53C500_attach */
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
index aa60a5f1fbc..3b2e1a53e6e 100644
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -117,7 +117,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
#endif
return 0;
}
- fcs = (struct ctrl_inquiry *) kmalloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA);
+ fcs = kmalloc(sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA);
if (!fcs) {
printk ("PLUTO: Not enough memory to probe\n");
return 0;
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 16af5b79e58..1548d42a3b4 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -1341,7 +1341,7 @@ qla1280_return_status(struct response * sts, struct scsi_cmnd *cp)
int host_status = DID_ERROR;
uint16_t comp_status = le16_to_cpu(sts->comp_status);
uint16_t state_flags = le16_to_cpu(sts->state_flags);
- uint16_t residual_length = le32_to_cpu(sts->residual_length);
+ uint32_t residual_length = le32_to_cpu(sts->residual_length);
uint16_t scsi_status = le16_to_cpu(sts->scsi_status);
#if DEBUG_QLA1280_INTR
static char *reason[] = {
@@ -1413,8 +1413,10 @@ qla1280_return_status(struct response * sts, struct scsi_cmnd *cp)
"scsi: Underflow detected - retrying "
"command.\n");
host_status = DID_ERROR;
- } else
+ } else {
+ cp->resid = residual_length;
host_status = DID_OK;
+ }
break;
default:
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index c4fc40f8e8c..2c10130d9e0 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1602,6 +1602,7 @@ typedef struct fc_port {
#define CT_REJECT_RESPONSE 0x8001
#define CT_ACCEPT_RESPONSE 0x8002
+#define CT_REASON_INVALID_COMMAND_CODE 0x01
#define CT_REASON_CANNOT_PERFORM 0x09
#define CT_EXPL_ALREADY_REGISTERED 0x10
@@ -2079,6 +2080,7 @@ typedef struct scsi_qla_host {
uint32_t msi_enabled :1;
uint32_t msix_enabled :1;
uint32_t disable_serdes :1;
+ uint32_t gpsc_supported :1;
} flags;
atomic_t loop_state;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 32ebeec45ff..e4dd12f4b80 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -45,7 +45,6 @@ extern void qla2x00_update_fcports(scsi_qla_host_t *);
extern int qla2x00_abort_isp(scsi_qla_host_t *);
extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
-extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *);
extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *);
extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 97fbc62ec66..ec5b2dd90d6 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -127,8 +127,8 @@ qla2x00_chk_ms_status(scsi_qla_host_t *ha, ms_iocb_entry_t *ms_pkt,
ha->host_no, routine, ms_pkt->entry_status));
} else {
if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
- comp_status =
- ((struct ct_entry_24xx *)ms_pkt)->comp_status;
+ comp_status = le16_to_cpu(
+ ((struct ct_entry_24xx *)ms_pkt)->comp_status);
else
comp_status = le16_to_cpu(ms_pkt->status);
switch (comp_status) {
@@ -143,6 +143,7 @@ qla2x00_chk_ms_status(scsi_qla_host_t *ha, ms_iocb_entry_t *ms_pkt,
DEBUG2_3(qla2x00_dump_buffer(
(uint8_t *)&ct_rsp->header,
sizeof(struct ct_rsp_hdr)));
+ rval = QLA_INVALID_COMMAND;
} else
rval = QLA_SUCCESS;
break;
@@ -1683,7 +1684,7 @@ qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list)
memset(list[i].fabric_port_name, 0, WWN_SIZE);
/* Prepare common MS IOCB */
- ms_pkt = qla2x00_prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
+ ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
GFPN_ID_RSP_SIZE);
/* Prepare CT request */
@@ -1784,6 +1785,8 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
return QLA_FUNCTION_FAILED;
+ if (!ha->flags.gpsc_supported)
+ return QLA_FUNCTION_FAILED;
rval = qla2x00_mgmt_svr_login(ha);
if (rval)
@@ -1813,8 +1816,19 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
/*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) {
+ } else if ((rval = qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp,
+ "GPSC")) != QLA_SUCCESS) {
+ /* FM command unsupported? */
+ if (rval == QLA_INVALID_COMMAND &&
+ ct_rsp->header.reason_code ==
+ CT_REASON_INVALID_COMMAND_CODE) {
+ DEBUG2(printk("scsi(%ld): GPSC command "
+ "unsupported, disabling query...\n",
+ ha->host_no));
+ ha->flags.gpsc_supported = 0;
+ rval = QLA_FUNCTION_FAILED;
+ break;
+ }
rval = QLA_FUNCTION_FAILED;
} else {
/* Save portname */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index a823f0bc519..b3dac26ddba 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -2103,40 +2103,7 @@ qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
}
}
-/*
- * qla2x00_update_fcport
- * Updates device on list.
- *
- * Input:
- * ha = adapter block pointer.
- * fcport = port structure pointer.
- *
- * Return:
- * 0 - Success
- * BIT_0 - error
- *
- * Context:
- * Kernel context.
- */
-void
-qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
-{
- fcport->ha = ha;
- fcport->login_retry = 0;
- fcport->port_login_retry_count = ha->port_down_retry_count *
- PORT_RETRY_TIME;
- atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
- PORT_RETRY_TIME);
- fcport->flags &= ~FCF_LOGIN_NEEDED;
-
- qla2x00_iidma_fcport(ha, fcport);
-
- atomic_set(&fcport->state, FCS_ONLINE);
-
- qla2x00_reg_remote_port(ha, fcport);
-}
-
-void
+static void
qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
{
struct fc_rport_identifiers rport_ids;
@@ -2179,6 +2146,39 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
}
/*
+ * qla2x00_update_fcport
+ * Updates device on list.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * fcport = port structure pointer.
+ *
+ * Return:
+ * 0 - Success
+ * BIT_0 - error
+ *
+ * Context:
+ * Kernel context.
+ */
+void
+qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
+{
+ fcport->ha = ha;
+ fcport->login_retry = 0;
+ fcport->port_login_retry_count = ha->port_down_retry_count *
+ PORT_RETRY_TIME;
+ atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
+ PORT_RETRY_TIME);
+ fcport->flags &= ~FCF_LOGIN_NEEDED;
+
+ qla2x00_iidma_fcport(ha, fcport);
+
+ atomic_set(&fcport->state, FCS_ONLINE);
+
+ qla2x00_reg_remote_port(ha, fcport);
+}
+
+/*
* qla2x00_configure_fabric
* Setup SNS devices with loop ID's.
*
@@ -3476,9 +3476,11 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
/* Set host adapter parameters. */
ha->flags.disable_risc_code_load = 0;
- ha->flags.enable_lip_reset = 1;
- ha->flags.enable_lip_full_login = 1;
- ha->flags.enable_target_reset = 1;
+ ha->flags.enable_lip_reset = 0;
+ ha->flags.enable_lip_full_login =
+ le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
+ ha->flags.enable_target_reset =
+ le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
ha->flags.enable_led_scheme = 0;
ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index d3b6df4d55c..39fd17b05be 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -134,11 +134,11 @@ qla2300_intr_handler(int irq, void *dev_id)
if (stat & HSR_RISC_PAUSED) {
hccr = RD_REG_WORD(&reg->hccr);
if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
- qla_printk(KERN_INFO, ha,
- "Parity error -- HCCR=%x.\n", hccr);
+ qla_printk(KERN_INFO, ha, "Parity error -- "
+ "HCCR=%x, Dumping firmware!\n", hccr);
else
- qla_printk(KERN_INFO, ha,
- "RISC paused -- HCCR=%x.\n", hccr);
+ qla_printk(KERN_INFO, ha, "RISC paused -- "
+ "HCCR=%x, Dumping firmware!\n", hccr);
/*
* Issue a "HARD" reset in order for the RISC
@@ -147,6 +147,8 @@ qla2300_intr_handler(int irq, void *dev_id)
*/
WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
RD_REG_WORD(&reg->hccr);
+
+ ha->isp_ops.fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
} else if ((stat & HSR_RISC_INT) == 0)
@@ -475,6 +477,8 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
}
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
+
+ ha->flags.gpsc_supported = 1;
break;
case MBA_CHG_IN_CONNECTION: /* Change in connection mode */
@@ -1440,8 +1444,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
"Dumping firmware!\n", hccr);
- qla24xx_fw_dump(ha, 1);
-
+ ha->isp_ops.fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
} else if ((stat & HSRX_RISC_INT) == 0)
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 4cde76c85cb..077e5789bee 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -1339,9 +1339,9 @@ qla2x00_lip_reset(scsi_qla_host_t *ha)
if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
mcp->mb[0] = MBC_LIP_FULL_LOGIN;
- mcp->mb[1] = BIT_0;
- mcp->mb[2] = 0xff;
- mcp->mb[3] = 0;
+ mcp->mb[1] = BIT_6;
+ mcp->mb[2] = 0;
+ mcp->mb[3] = ha->loop_reset_delay;
mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
} else {
mcp->mb[0] = MBC_LIP_RESET;
@@ -1823,8 +1823,8 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha)
ha->host_no));
mcp->mb[0] = MBC_LIP_FULL_LOGIN;
- mcp->mb[1] = 0;
- mcp->mb[2] = 0xff;
+ mcp->mb[1] = IS_QLA24XX(ha) || IS_QLA54XX(ha) ? BIT_3: 0;
+ mcp->mb[2] = 0;
mcp->mb[3] = 0;
mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
mcp->in_mb = MBX_0;
@@ -2486,7 +2486,7 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
mcp->mb[4] = LSW(MSD(eft_dma));
mcp->mb[5] = MSW(MSD(eft_dma));
mcp->mb[6] = buffers;
- mcp->mb[7] = buffers;
+ mcp->mb[7] = 0;
mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2;
}
mcp->tov = 30;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index d03523d3bf3..d6445ae841b 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1037,48 +1037,49 @@ eh_host_reset_lock:
static int
qla2x00_loop_reset(scsi_qla_host_t *ha)
{
- int status = QLA_SUCCESS;
+ int ret;
struct fc_port *fcport;
+ if (ha->flags.enable_lip_full_login) {
+ ret = qla2x00_full_login_lip(ha);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2_3(printk("%s(%ld): bus_reset failed: "
+ "full_login_lip=%d.\n", __func__, ha->host_no,
+ ret));
+ }
+ atomic_set(&ha->loop_state, LOOP_DOWN);
+ atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
+ qla2x00_mark_all_devices_lost(ha, 0);
+ qla2x00_wait_for_loop_ready(ha);
+ }
+
if (ha->flags.enable_lip_reset) {
- status = qla2x00_lip_reset(ha);
+ ret = qla2x00_lip_reset(ha);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2_3(printk("%s(%ld): bus_reset failed: "
+ "lip_reset=%d.\n", __func__, ha->host_no, ret));
+ }
+ qla2x00_wait_for_loop_ready(ha);
}
- if (status == QLA_SUCCESS && ha->flags.enable_target_reset) {
+ if (ha->flags.enable_target_reset) {
list_for_each_entry(fcport, &ha->fcports, list) {
if (fcport->port_type != FCT_TARGET)
continue;
- status = qla2x00_device_reset(ha, fcport);
- if (status != QLA_SUCCESS)
- break;
+ ret = qla2x00_device_reset(ha, fcport);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2_3(printk("%s(%ld): bus_reset failed: "
+ "target_reset=%d d_id=%x.\n", __func__,
+ ha->host_no, ret, fcport->d_id.b24));
+ }
}
}
- if (status == QLA_SUCCESS &&
- ((!ha->flags.enable_target_reset &&
- !ha->flags.enable_lip_reset) ||
- ha->flags.enable_lip_full_login)) {
-
- status = qla2x00_full_login_lip(ha);
- }
-
/* Issue marker command only when we are going to start the I/O */
ha->marker_needed = 1;
- if (status) {
- /* Empty */
- DEBUG2_3(printk("%s(%ld): **** FAILED ****\n",
- __func__,
- ha->host_no));
- } else {
- /* Empty */
- DEBUG3(printk("%s(%ld): exiting normally.\n",
- __func__,
- ha->host_no));
- }
-
- return(status);
+ return QLA_SUCCESS;
}
/*
@@ -1413,7 +1414,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
sht = &qla2x00_driver_template;
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
- pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432)
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432)
sht = &qla24xx_driver_template;
host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
if (host == NULL) {
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 1fa0bce6b24..459e0d6bd2b 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-k3"
+#define QLA2XXX_VERSION "8.01.07-k4"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 1
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 4249e52a559..6f4cf2dd2f4 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -418,7 +418,6 @@ struct scsi_qla_host {
* concurrently.
*/
struct mutex mbox_sem;
- wait_queue_head_t mailbox_wait_queue;
/* temporary mailbox status registers */
volatile uint8_t mbox_status_count;
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 2122967bbf0..e021eb5db2b 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -76,4 +76,5 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha,
extern int ql4xextended_error_logging;
extern int ql4xdiscoverywait;
extern int ql4xdontresethba;
+extern int ql4_mod_unload;
#endif /* _QLA4x_GBL_H */
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index cc210f297a7..b907b06d72a 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -958,25 +958,25 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
return status;
}
-int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
+int ql4xxx_lock_drvr_wait(struct scsi_qla_host *ha)
{
-#define QL4_LOCK_DRVR_WAIT 300
-#define QL4_LOCK_DRVR_SLEEP 100
+#define QL4_LOCK_DRVR_WAIT 30
+#define QL4_LOCK_DRVR_SLEEP 1
int drvr_wait = QL4_LOCK_DRVR_WAIT;
while (drvr_wait) {
- if (ql4xxx_lock_drvr(a) == 0) {
- msleep(QL4_LOCK_DRVR_SLEEP);
+ if (ql4xxx_lock_drvr(ha) == 0) {
+ ssleep(QL4_LOCK_DRVR_SLEEP);
if (drvr_wait) {
DEBUG2(printk("scsi%ld: %s: Waiting for "
- "Global Init Semaphore...n",
- a->host_no,
- __func__));
+ "Global Init Semaphore(%d)...n",
+ ha->host_no,
+ __func__, drvr_wait));
}
drvr_wait -= QL4_LOCK_DRVR_SLEEP;
} else {
DEBUG2(printk("scsi%ld: %s: Global Init Semaphore "
- "acquired.n", a->host_no, __func__));
+ "acquired.n", ha->host_no, __func__));
return QLA_SUCCESS;
}
}
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index ef975e0dc87..35b9e36a0e8 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -433,7 +433,6 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
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.
@@ -686,7 +685,8 @@ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id)
&ha->reg->ctrl_status);
readl(&ha->reg->ctrl_status);
- set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
+ if (!ql4_mod_unload)
+ set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
break;
} else if (intr_status & INTR_PENDING) {
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index b721dc5dd71..7f28657eef3 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -29,18 +29,30 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
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;
+ return status;
+ }
+ /* Mailbox code active */
+ wait_count = MBOX_TOV * 100;
+
+ while (wait_count--) {
+ mutex_lock(&ha->mbox_sem);
+ if (!test_bit(AF_MBOX_COMMAND, &ha->flags)) {
+ set_bit(AF_MBOX_COMMAND, &ha->flags);
+ mutex_unlock(&ha->mbox_sem);
+ break;
+ }
+ mutex_unlock(&ha->mbox_sem);
+ if (!wait_count) {
+ DEBUG2(printk("scsi%ld: %s: mbox_sem failed\n",
+ ha->host_no, __func__));
+ return status;
+ }
+ msleep(10);
}
/* To prevent overwriting mailbox registers for a command that has
@@ -73,8 +85,6 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
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
@@ -83,8 +93,6 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
*/
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 */
@@ -108,8 +116,6 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
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)) {
@@ -155,9 +161,10 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
spin_unlock_irqrestore(&ha->hardware_lock, flags);
mbox_exit:
+ mutex_lock(&ha->mbox_sem);
clear_bit(AF_MBOX_COMMAND, &ha->flags);
- clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
mutex_unlock(&ha->mbox_sem);
+ clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
return status;
}
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 9ef693c8809..81fb7bd44f0 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -40,6 +40,8 @@ MODULE_PARM_DESC(ql4xextended_error_logging,
"Option to enable extended error logging, "
"Default is 0 - no logging, 1 - debug logging");
+int ql4_mod_unload = 0;
+
/*
* SCSI host template entry points
*/
@@ -422,6 +424,9 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
goto qc_host_busy;
}
+ if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags))
+ goto qc_host_busy;
+
spin_unlock_irq(ha->host->host_lock);
srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done);
@@ -707,16 +712,12 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
return stat;
}
-/**
- * qla4xxx_soft_reset - performs soft reset.
- * @ha: Pointer to host adapter structure.
- **/
-int qla4xxx_soft_reset(struct scsi_qla_host *ha)
+static void qla4xxx_hw_reset(struct scsi_qla_host *ha)
{
- uint32_t max_wait_time;
- unsigned long flags = 0;
- int status = QLA_ERROR;
uint32_t ctrl_status;
+ unsigned long flags = 0;
+
+ DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__));
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -733,6 +734,20 @@ int qla4xxx_soft_reset(struct scsi_qla_host *ha)
readl(&ha->reg->ctrl_status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+/**
+ * qla4xxx_soft_reset - performs soft reset.
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4xxx_soft_reset(struct scsi_qla_host *ha)
+{
+ uint32_t max_wait_time;
+ unsigned long flags = 0;
+ int status = QLA_ERROR;
+ uint32_t ctrl_status;
+
+ qla4xxx_hw_reset(ha);
/* Wait until the Network Reset Intr bit is cleared */
max_wait_time = RESET_INTR_TOV;
@@ -966,10 +981,12 @@ static void qla4xxx_do_dpc(struct work_struct *work)
struct scsi_qla_host *ha =
container_of(work, struct scsi_qla_host, dpc_work);
struct ddb_entry *ddb_entry, *dtemp;
+ int status = QLA_ERROR;
DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
- "flags = 0x%08lx, dpc_flags = 0x%08lx\n",
- ha->host_no, __func__, ha->flags, ha->dpc_flags));
+ "flags = 0x%08lx, dpc_flags = 0x%08lx ctrl_stat = 0x%08x\n",
+ ha->host_no, __func__, ha->flags, ha->dpc_flags,
+ readw(&ha->reg->ctrl_status)));
/* Initialization not yet finished. Don't do anything yet. */
if (!test_bit(AF_INIT_DONE, &ha->flags))
@@ -983,31 +1000,28 @@ static void qla4xxx_do_dpc(struct work_struct *work)
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)) {
+ if (test_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__));
+ qla4xxx_flush_active_srbs(ha);
+ if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) {
+ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+ status = qla4xxx_initialize_adapter(ha,
+ PRESERVE_DDB_LIST);
+ }
+ clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
+ if (status == QLA_SUCCESS)
+ qla4xxx_enable_intrs(ha);
}
}
@@ -1062,7 +1076,7 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
/* Issue Soft Reset to put firmware in unknown state */
if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
- qla4xxx_soft_reset(ha);
+ qla4xxx_hw_reset(ha);
/* Remove timer thread, if present */
if (ha->timer_active)
@@ -1198,7 +1212,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
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);
@@ -1665,6 +1678,7 @@ no_srp_cache:
static void __exit qla4xxx_module_exit(void)
{
+ ql4_mod_unload = 1;
pci_unregister_driver(&qla4xxx_pci_driver);
iscsi_unregister_transport(&qla4xxx_iscsi_transport);
kmem_cache_destroy(srb_cachep);
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index 454e19c8ad6..e5183a697d1 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,4 +5,4 @@
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.00.07-k"
+#define QLA4XXX_DRIVER_VERSION "5.00.07-k1"
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 1748e27501c..f02f48a882a 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -265,13 +265,11 @@ static int scsi_merge_bio(struct request *rq, struct bio *bio)
if (!rq->bio)
blk_rq_bio_prep(q, rq, bio);
- else if (!q->back_merge_fn(q, rq, bio))
+ else if (!ll_back_merge_fn(q, rq, bio))
return -EINVAL;
else {
rq->biotail->bi_next = bio;
rq->biotail = bio;
- rq->hard_nr_sectors += bio_sectors(bio);
- rq->nr_sectors = rq->hard_nr_sectors;
}
return 0;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 14e635aa44c..96b7cbd746a 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -133,12 +133,10 @@ struct async_scan_data {
/**
* scsi_complete_async_scans - Wait for asynchronous scans to complete
*
- * Asynchronous scans add themselves to the scanning_hosts list. Once
- * that list is empty, we know that the scans are complete. Rather than
- * waking up periodically to check the state of the list, we pretend to be
- * a scanning task by adding ourselves at the end of the list and going to
- * sleep. When the task before us wakes us up, we take ourselves off the
- * list and return.
+ * When this function returns, any host which started scanning before
+ * this function was called will have finished its scan. Hosts which
+ * started scanning after this function was called may or may not have
+ * finished.
*/
int scsi_complete_async_scans(void)
{
@@ -171,6 +169,11 @@ int scsi_complete_async_scans(void)
spin_lock(&async_scan_lock);
list_del(&data->list);
+ if (!list_empty(&scanning_hosts)) {
+ struct async_scan_data *next = list_entry(scanning_hosts.next,
+ struct async_scan_data, list);
+ complete(&next->prev_finished);
+ }
done:
spin_unlock(&async_scan_lock);
@@ -739,6 +742,14 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
sdev->no_uld_attach = 1;
switch (sdev->type = (inq_result[0] & 0x1f)) {
+ case TYPE_RBC:
+ /* RBC devices can return SCSI-3 compliance and yet
+ * still not support REPORT LUNS, so make them act as
+ * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is
+ * specifically set */
+ if ((*bflags & BLIST_REPORTLUN2) == 0)
+ *bflags |= BLIST_NOREPORTLUN;
+ /* fall through */
case TYPE_TAPE:
case TYPE_DISK:
case TYPE_PRINTER:
@@ -749,11 +760,17 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
case TYPE_ENCLOSURE:
case TYPE_COMM:
case TYPE_RAID:
- case TYPE_RBC:
sdev->writeable = 1;
break;
- case TYPE_WORM:
case TYPE_ROM:
+ /* MMC devices can return SCSI-3 compliance and yet
+ * still not support REPORT LUNS, so make them act as
+ * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is
+ * specifically set */
+ if ((*bflags & BLIST_REPORTLUN2) == 0)
+ *bflags |= BLIST_NOREPORTLUN;
+ /* fall through */
+ case TYPE_WORM:
sdev->writeable = 0;
break;
default:
@@ -1436,6 +1453,12 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
struct device *parent = &shost->shost_gendev;
struct scsi_target *starget;
+ if (strncmp(scsi_scan_type, "none", 4) == 0)
+ return ERR_PTR(-ENODEV);
+
+ if (!shost->async_scan)
+ scsi_complete_async_scans();
+
starget = scsi_alloc_target(parent, channel, id);
if (!starget)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 9c22f134271..ce0d14af33c 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1416,7 +1416,7 @@ static __init int iscsi_transport_init(void)
{
int err;
- printk(KERN_INFO "Loading iSCSI transport class v%s.",
+ printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
ISCSI_TRANSPORT_VERSION);
err = class_register(&iscsi_transport_class);
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index 3fded483146..014d7fea1ff 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -122,7 +122,7 @@ static int spi_execute(struct scsi_device *sdev, const void *cmd,
if (!sshdr)
sshdr = &sshdr_tmp;
- if (scsi_normalize_sense(sense, sizeof(*sense),
+ if (scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE,
sshdr)
&& sshdr->sense_key == UNIT_ATTENTION)
continue;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index f6a452846fa..b781a90d669 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -863,7 +863,7 @@ static void sd_rescan(struct device *dev)
*/
static long sd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = file->f_dentry->d_inode->i_bdev;
+ struct block_device *bdev = file->f_path.dentry->d_inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
struct scsi_device *sdev = scsi_disk(disk)->device;
@@ -1647,16 +1647,6 @@ static int sd_probe(struct device *dev)
if (error)
goto out_put;
- class_device_initialize(&sdkp->cdev);
- sdkp->cdev.dev = &sdp->sdev_gendev;
- sdkp->cdev.class = &sd_disk_class;
- strncpy(sdkp->cdev.class_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);
-
- if (class_device_add(&sdkp->cdev))
- goto out_put;
-
- get_device(&sdp->sdev_gendev);
-
sdkp->device = sdp;
sdkp->driver = &sd_template;
sdkp->disk = gd;
@@ -1670,6 +1660,16 @@ static int sd_probe(struct device *dev)
sdp->timeout = SD_MOD_TIMEOUT;
}
+ class_device_initialize(&sdkp->cdev);
+ sdkp->cdev.dev = &sdp->sdev_gendev;
+ sdkp->cdev.class = &sd_disk_class;
+ strncpy(sdkp->cdev.class_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);
+
+ if (class_device_add(&sdkp->cdev))
+ goto out_put;
+
+ get_device(&sdp->sdev_gendev);
+
gd->major = sd_major((index & 0xf0) >> 4);
gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
gd->minors = 16;
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index 5ffec2721b2..ff62e9708e1 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -114,6 +114,7 @@
#define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0)
#else
#define DPRINTK( when, msg... ) do { } while (0)
+#define DEBUG 0
#endif
#define DANY( msg... ) DPRINTK( 0xffff, msg );
@@ -523,7 +524,7 @@ int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
#ifdef ARBITRATE
" ARBITRATE"
#endif
-#ifdef DEBUG
+#if DEBUG
" DEBUG"
#endif
#ifdef FAST
@@ -733,7 +734,7 @@ static int internal_command (unsigned char target, unsigned char lun,
unsigned char *data = NULL;
struct scatterlist *buffer = NULL;
int clock, temp, nobuffs = 0, done = 0, len = 0;
-#ifdef DEBUG
+#if DEBUG
int transfered = 0, phase = 0, newphase;
#endif
register unsigned char status_read;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index fae6e95a629..89e9b36b178 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -468,7 +468,7 @@ static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd,
}
ret = cdrom_ioctl(file, &cd->cdi, inode, cmd, arg);
- if (ret != ENOSYS)
+ if (ret != -ENOSYS)
return ret;
/*
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index d1268cb4683..0578ba42718 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -546,7 +546,7 @@ int sr_is_xa(Scsi_CD *cd)
if (!xa_test)
return 0;
- raw_sector = (unsigned char *) kmalloc(2048, GFP_KERNEL | SR_GFP_DMA(cd));
+ raw_sector = kmalloc(2048, GFP_KERNEL | SR_GFP_DMA(cd));
if (!raw_sector)
return -ENOMEM;
if (0 == sr_read_sector(cd, cd->ms_offset + 16,
diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c
index a3e9d0f2eb5..4eb3da996b3 100644
--- a/drivers/scsi/sr_vendor.c
+++ b/drivers/scsi/sr_vendor.c
@@ -117,7 +117,7 @@ int sr_set_blocklength(Scsi_CD *cd, int blocklength)
density = (blocklength > 2048) ? 0x81 : 0x83;
#endif
- buffer = (unsigned char *) kmalloc(512, GFP_KERNEL | GFP_DMA);
+ buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
if (!buffer)
return -ENOMEM;
@@ -164,7 +164,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
if (cd->cdi.mask & CDC_MULTI_SESSION)
return 0;
- buffer = (unsigned char *) kmalloc(512, GFP_KERNEL | GFP_DMA);
+ buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
if (!buffer)
return -ENOMEM;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 587274dd705..488ec7948a5 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -922,7 +922,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
struct st_modedef *STm;
struct st_partstat *STps;
char *name = tape_name(STp);
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int mode = TAPE_MODE(inode);
STp->ready = ST_READY;
@@ -2816,15 +2816,18 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
if (cmd_in == MTWEOF &&
cmdstatp->have_sense &&
- (cmdstatp->flags & SENSE_EOM) &&
- (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
- cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
- undone == 0) {
- ioctl_result = 0; /* EOF written successfully at EOM */
- if (fileno >= 0)
- fileno++;
+ (cmdstatp->flags & SENSE_EOM)) {
+ if (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+ cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) {
+ ioctl_result = 0; /* EOF(s) written successfully at EOM */
+ STps->eof = ST_NOEOF;
+ } else { /* Writing EOF(s) failed */
+ if (fileno >= 0)
+ fileno -= undone;
+ if (undone < arg)
+ STps->eof = ST_NOEOF;
+ }
STps->drv_file = fileno;
- STps->eof = ST_NOEOF;
} else if ((cmd_in == MTFSF) || (cmd_in == MTFSFM)) {
if (fileno >= 0)
STps->drv_file = fileno - undone;
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 3b3f3050a87..98e3fe10c1d 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -266,7 +266,7 @@ static struct scsi_host_template *the_template = NULL;
(struct NCR5380_hostdata *)(in)->hostdata
#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
-#define NEXT(cmd) ((struct scsi_cmnd *)((cmd)->host_scribble))
+#define NEXT(cmd) (*(struct scsi_cmnd **)&((cmd)->host_scribble))
#define NEXTADDR(cmd) ((struct scsi_cmnd **)&((cmd)->host_scribble))
#define HOSTNO instance->host_no
@@ -650,7 +650,7 @@ __inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
#include <linux/interrupt.h>
static volatile int main_running = 0;
-static DECLARE_WORK(NCR5380_tqueue, (void (*)(void*))NCR5380_main, NULL);
+static DECLARE_WORK(NCR5380_tqueue, NCR5380_main);
static __inline__ void queue_main(void)
{
@@ -1031,7 +1031,7 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd,
* reenable them. This prevents reentrancy and kernel stack overflow.
*/
-static void NCR5380_main (void *bl)
+static void NCR5380_main (struct work_struct *bl)
{
struct scsi_cmnd *tmp, *prev;
struct Scsi_Host *instance = first_instance;
@@ -1271,7 +1271,7 @@ static irqreturn_t NCR5380_intr (int irq, void *dev_id)
NCR_PRINT(NDEBUG_INTR);
if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
done = 0;
- ENABLE_IRQ();
+// ENABLE_IRQ();
INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
NCR5380_reselect(instance);
(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
@@ -1304,7 +1304,7 @@ static irqreturn_t NCR5380_intr (int irq, void *dev_id)
INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
NCR5380_dma_complete( instance );
done = 0;
- ENABLE_IRQ();
+// ENABLE_IRQ();
} else
#endif /* REAL_DMA */
{
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index d56d85dd9ba..69ee3e4a820 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -75,9 +75,9 @@
#define REAL_DMA
#include "scsi.h"
+#include "initio.h"
#include <scsi/scsi_host.h>
#include "sun3_scsi.h"
-#include "NCR5380.h"
static void NCR5380_print(struct Scsi_Host *instance);
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
index a1103b3e203..b29a9d661ca 100644
--- a/drivers/scsi/sun3_scsi.h
+++ b/drivers/scsi/sun3_scsi.h
@@ -221,7 +221,7 @@ struct sun3_udc_regs {
*
*/
-
+#include "NCR5380.h"
#if NDEBUG & NDEBUG_ARBITRATION
#define ARB_PRINTK(format, args...) \
diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c
index 92def310a84..bb0c9fd99e6 100644
--- a/drivers/scsi/sun3_scsi_vme.c
+++ b/drivers/scsi/sun3_scsi_vme.c
@@ -41,9 +41,9 @@
#define REAL_DMA
#include "scsi.h"
+#include "initio.h"
#include <scsi/scsi_host.h>
#include "sun3_scsi.h"
-#include "NCR5380.h"
extern int sun3_map_test(unsigned long, char *);
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 6b60536ac92..80fb3f88af2 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -53,7 +53,7 @@ int sun3x_esp_detect(struct scsi_host_template *tpnt)
struct ConfigDev *esp_dev;
esp_dev = 0;
- esp = esp_allocate(tpnt, (void *) esp_dev);
+ esp = esp_allocate(tpnt, esp_dev, 0);
/* Do command transfer with DMA */
esp->do_pio_cmds = 0;
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
index 940fa1e6f99..21cd4c7f528 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -5545,7 +5545,7 @@ int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram
/*
* Allocate the array of lists of CCBs hashed by DSA.
*/
- np->ccbh = kcalloc(sizeof(struct sym_ccb **), CCB_HASH_SIZE, GFP_KERNEL);
+ np->ccbh = kcalloc(CCB_HASH_SIZE, sizeof(struct sym_ccb **), GFP_KERNEL);
if (!np->ccbh)
goto attach_failed;
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
index 6a1a568ca64..facb6785561 100644
--- a/drivers/serial/21285.c
+++ b/drivers/serial/21285.c
@@ -214,8 +214,8 @@ static void serial21285_shutdown(struct uart_port *port)
}
static void
-serial21285_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned long flags;
unsigned int baud, quot, h_lcr;
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 9b8b585513e..cad426c9711 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -1061,7 +1061,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
return 0;
}
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index 634ecca36a7..68817a7d8c0 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -1523,7 +1523,7 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
/* FIX UP modem control here someday......
*/
-static void rs_360_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index e34bd03cfce..5261f0af8b1 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1763,8 +1763,8 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
}
static void
-serial8250_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char cval, fcr = 0;
@@ -2296,7 +2296,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
local_irq_restore(flags);
}
-static int serial8250_console_setup(struct console *co, char *options)
+static int __init serial8250_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 9600;
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 4d0ff8f4a01..52e2e64c664 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -2239,6 +2239,30 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_b0_bt_1_460800 },
/*
+ * Korenix Jetcard F0/F1 cards (JC1204, JC1208, JC1404, JC1408).
+ * Cards are identified by their subsystem vendor IDs, which
+ * (in hex) match the model number.
+ *
+ * Note that JC140x are RS422/485 cards which require ox950
+ * ACR = 0x10, and as such are not currently fully supported.
+ */
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1204, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+/* { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1402, 0x0002, 0, 0,
+ pbn_b0_2_921600 }, */
+/* { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1404, 0x0004, 0, 0,
+ pbn_b0_4_921600 }, */
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+
+ /*
* Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com
*/
{ PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4,
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index fc12d5df10e..2978c09860e 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -151,32 +151,6 @@ config SERIAL_8250_MANY_PORTS
say N here to save some memory. You can also say Y if you have an
"intelligent" multiport card such as Cyclades, Digiboards, etc.
-config SERIAL_8250_SHARE_IRQ
- bool "Support for sharing serial interrupts"
- depends on SERIAL_8250_EXTENDED
- help
- Some serial boards have hardware support which allows multiple dumb
- serial ports on the same board to share a single IRQ. To enable
- support for this in the serial driver, say Y here.
-
-config SERIAL_8250_DETECT_IRQ
- bool "Autodetect IRQ on standard ports (unsafe)"
- depends on SERIAL_8250_EXTENDED
- help
- Say Y here if you want the kernel to try to guess which IRQ
- to use for your serial port.
-
- This is considered unsafe; it is far better to configure the IRQ in
- a boot script using the setserial command.
-
- If unsure, say N.
-
-config SERIAL_8250_RSA
- bool "Support RSA serial ports"
- depends on SERIAL_8250_EXTENDED
- help
- ::: To be written :::
-
#
# Multi-port serial cards
#
@@ -199,7 +173,6 @@ config SERIAL_8250_ACCENT
To compile this driver as a module, choose M here: the module
will be called 8250_accent.
-
config SERIAL_8250_BOCA
tristate "Support Boca cards"
depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
@@ -230,6 +203,32 @@ config SERIAL_8250_HUB6
To compile this driver as a module, choose M here: the module
will be called 8250_hub6.
+config SERIAL_8250_SHARE_IRQ
+ bool "Support for sharing serial interrupts"
+ depends on SERIAL_8250_EXTENDED
+ help
+ Some serial boards have hardware support which allows multiple dumb
+ serial ports on the same board to share a single IRQ. To enable
+ support for this in the serial driver, say Y here.
+
+config SERIAL_8250_DETECT_IRQ
+ bool "Autodetect IRQ on standard ports (unsafe)"
+ depends on SERIAL_8250_EXTENDED
+ help
+ Say Y here if you want the kernel to try to guess which IRQ
+ to use for your serial port.
+
+ This is considered unsafe; it is far better to configure the IRQ in
+ a boot script using the setserial command.
+
+ If unsure, say N.
+
+config SERIAL_8250_RSA
+ bool "Support RSA serial ports"
+ depends on SERIAL_8250_EXTENDED
+ help
+ ::: To be written :::
+
config SERIAL_8250_MCA
tristate "Support 8250-type ports on MCA buses"
depends on SERIAL_8250 != n && MCA
@@ -664,7 +663,7 @@ config V850E_UART
config V850E_UARTB
bool
- depends V850E_UART && V850E_ME2
+ depends on V850E_UART && V850E_ME2
default y
config V850E_UART_CONSOLE
@@ -910,7 +909,7 @@ config SERIAL_M32R_PLDSIO
config SERIAL_TXX9
bool "TMPTX39XX/49XX SIO support"
- depends HAS_TXX9_SERIAL
+ depends on HAS_TXX9_SERIAL
select SERIAL_CORE
default y
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 4d3626ef464..f69bd097166 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -345,8 +345,8 @@ static void pl010_shutdown(struct uart_port *port)
}
static void
-pl010_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+pl010_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int lcr_h, old_cr;
unsigned long flags;
@@ -589,6 +589,8 @@ static int __init pl010_console_setup(struct console *co, char *options)
*/
if (co->index >= UART_NR)
co->index = 0;
+ if (!amba_ports[co->index])
+ return -ENODEV;
port = &amba_ports[co->index]->port;
if (options)
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index d503625730d..44639e71372 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -412,8 +412,8 @@ static void pl011_shutdown(struct uart_port *port)
}
static void
-pl011_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+pl011_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int lcr_h, old_cr;
unsigned long flags;
@@ -661,6 +661,8 @@ static int __init pl011_console_setup(struct console *co, char *options)
if (co->index >= UART_NR)
co->index = 0;
uap = amba_ports[co->index];
+ if (!uap)
+ return -ENODEV;
uap->port.uartclk = clk_get_rate(uap->clk);
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 9217ee6c786..881f886b91c 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -478,7 +478,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, unsigned
/*
* Change the port parameters
*/
-static void atmel_set_termios(struct uart_port *port, struct termios * termios, struct termios * old)
+static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, struct ktermios * old)
{
unsigned long flags;
unsigned int mode, imr, quot, baud;
@@ -689,9 +689,9 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct
struct atmel_uart_data *data = pdev->dev.platform_data;
port->iotype = UPIO_MEM;
- port->flags = UPF_BOOT_AUTOCONF;
+ port->flags = UPF_BOOT_AUTOCONF;
port->ops = &atmel_pops;
- port->fifosize = 1;
+ port->fifosize = 1;
port->line = pdev->id;
port->dev = &pdev->dev;
@@ -890,7 +890,6 @@ static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state
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;
}
@@ -907,6 +906,8 @@ static int atmel_serial_resume(struct platform_device *pdev)
uart_resume_port(&atmel_uart, port);
atmel_port->suspended = 0;
}
+ else
+ disable_irq_wake(port->irq);
return 0;
}
diff --git a/drivers/serial/atmel_serial.h b/drivers/serial/atmel_serial.h
index fe1763b2a6d..11b44360e10 100644
--- a/drivers/serial/atmel_serial.h
+++ b/drivers/serial/atmel_serial.h
@@ -106,7 +106,7 @@
#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_SYNH (1 << 15) /* Transmit/Receive Sync [SAM9 only] */
+#define ATMEL_US_SYNH (1 << 15) /* Transmit/Receive Sync [AT91SAM9261 only] */
#define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */
#define ATMEL_US_CD (0xffff << 0) /* Clock Divider */
diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c
index 59801271488..23827189ec0 100644
--- a/drivers/serial/clps711x.c
+++ b/drivers/serial/clps711x.c
@@ -286,8 +286,8 @@ static void clps711xuart_shutdown(struct uart_port *port)
}
static void
-clps711xuart_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int ubrlcr, baud, quot;
unsigned long flags;
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 08e55fdc882..925fb607d8c 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.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>
@@ -145,7 +146,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
/* was hostalloc but changed cause it blows away the */
/* large tlb mapping when pinning the kernel area */
mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
- dma_addr = (u32)mem_addr;
+ dma_addr = (u32)cpm_dpram_phys(mem_addr);
} else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL);
@@ -205,7 +206,7 @@ int __init cpm_uart_init_portdesc(void)
(unsigned long)&cpmp->cp_smc[0];
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
@@ -217,7 +218,7 @@ int __init cpm_uart_init_portdesc(void)
(unsigned long)&cpmp->cp_smc[1];
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
@@ -231,7 +232,7 @@ int __init cpm_uart_init_portdesc(void)
~(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
@@ -245,7 +246,7 @@ int __init cpm_uart_init_portdesc(void)
~(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
@@ -259,7 +260,7 @@ int __init cpm_uart_init_portdesc(void)
~(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
@@ -273,7 +274,7 @@ int __init cpm_uart_init_portdesc(void)
~(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
return 0;
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
index 5eb49ea63bf..a99e45e2b6d 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
@@ -20,9 +20,6 @@
#define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3)
#define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4)
-/* the CPM address */
-#define CPM_ADDR IMAP_ADDR
-
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
index 4b779111eaf..1b3219f56c8 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
@@ -20,9 +20,6 @@
#define SCC3_IRQ SIU_INT_SCC3
#define SCC4_IRQ SIU_INT_SCC4
-/* the CPM address */
-#define CPM_ADDR CPM_MAP_ADDR
-
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 7a24e53546c..42b050c46ab 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -804,8 +804,8 @@ static struct e100_serial rs_table[] = {
#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
-static struct termios *serial_termios[NR_PORTS];
-static struct termios *serial_termios_locked[NR_PORTS];
+static struct ktermios *serial_termios[NR_PORTS];
+static struct ktermios *serial_termios_locked[NR_PORTS];
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
static struct fast_timer fast_timers[NR_PORTS];
#endif
@@ -4223,7 +4223,7 @@ rs_ioctl(struct tty_struct *tty, struct file * file,
}
static void
-rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
@@ -4877,6 +4877,8 @@ rs_init(void)
driver->init_termios = tty_std_termios;
driver->init_termios.c_cflag =
B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
+ driver->init_termios.c_ispeed = 115200;
+ driver->init_termios.c_ospeed = 115200;
driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
driver->termios = serial_termios;
driver->termios_locked = serial_termios_locked;
diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h
index f30b93d6ef7..4a23340663a 100644
--- a/drivers/serial/crisv10.h
+++ b/drivers/serial/crisv10.h
@@ -93,8 +93,8 @@ struct e100_serial {
struct work_struct work;
struct async_icount icount; /* error-statistics etc.*/
- struct termios normal_termios;
- struct termios callout_termios;
+ struct ktermios normal_termios;
+ struct ktermios callout_termios;
#ifdef DECLARE_WAITQUEUE
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index af1544f3356..587d87b9eb3 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -461,8 +461,8 @@ static void dz_break_ctl(struct uart_port *uport, int break_state)
spin_unlock_irqrestore(&uport->lock, flags);
}
-static void dz_set_termios(struct uart_port *uport, struct termios *termios,
- struct termios *old_termios)
+static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
+ struct ktermios *old_termios)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned long flags;
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index 8aa0f641866..71e6a24d8c2 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -1087,8 +1087,8 @@ static void icom_close(struct uart_port *port)
}
static void icom_set_termios(struct uart_port *port,
- struct termios *termios,
- struct termios *old_termios)
+ struct ktermios *termios,
+ struct ktermios *old_termios)
{
int baud;
unsigned cflag, iflag;
@@ -1510,7 +1510,7 @@ static int __devinit icom_probe(struct pci_dev *dev,
}
if ( (retval = pci_request_regions(dev, "icom"))) {
- dev_err(&dev->dev, "pci_request_region FAILED\n");
+ dev_err(&dev->dev, "pci_request_regions FAILED\n");
pci_disable_device(dev);
return retval;
}
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index ee5c782597d..e216dcf2937 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -459,8 +459,8 @@ static void imx_shutdown(struct uart_port *port)
}
static void
-imx_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+imx_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long flags;
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
index 2308d26c862..9cc0be93231 100644
--- a/drivers/serial/ioc3_serial.c
+++ b/drivers/serial/ioc3_serial.c
@@ -950,7 +950,7 @@ static void transmit_chars(struct uart_port *the_port)
*/
static void
ioc3_change_speed(struct uart_port *the_port,
- struct termios *new_termios, struct termios *old_termios)
+ struct ktermios *new_termios, struct ktermios *old_termios)
{
struct ioc3_port *port = get_ioc3_port(the_port);
unsigned int cflag;
@@ -1853,7 +1853,7 @@ static int ic3_startup(struct uart_port *the_port)
*/
static void
ic3_set_termios(struct uart_port *the_port,
- struct termios *termios, struct termios *old_termios)
+ struct ktermios *termios, struct ktermios *old_termios)
{
unsigned long port_flags;
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
index 711bd151143..c862f67c985 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/serial/ioc4_serial.c
@@ -1681,7 +1681,7 @@ static void transmit_chars(struct uart_port *the_port)
*/
static void
ioc4_change_speed(struct uart_port *the_port,
- struct termios *new_termios, struct termios *old_termios)
+ struct ktermios *new_termios, struct ktermios *old_termios)
{
struct ioc4_port *port = get_ioc4_port(the_port, 0);
int baud, bits;
@@ -1802,7 +1802,7 @@ static inline int ic4_startup_local(struct uart_port *the_port)
ioc4_set_proto(port, the_port->mapbase);
/* set the speed of the serial port */
- ioc4_change_speed(the_port, info->tty->termios, (struct termios *)0);
+ ioc4_change_speed(the_port, info->tty->termios, (struct ktermios *)0);
return 0;
}
@@ -2570,7 +2570,7 @@ static int ic4_startup(struct uart_port *the_port)
*/
static void
ic4_set_termios(struct uart_port *the_port,
- struct termios *termios, struct termios *old_termios)
+ struct ktermios *termios, struct ktermios *old_termios)
{
unsigned long port_flags;
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
index dca6c1bde8f..0746c9446ae 100644
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/serial/ip22zilog.c
@@ -840,8 +840,8 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,
/* The port lock is not held. */
static void
-ip22zilog_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
unsigned long flags;
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index f8262e6ad8d..7cf1c60027f 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -142,7 +142,7 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch)
{
unsigned long lock_flags;
struct jsm_channel *channel = (struct jsm_channel *)port;
- struct termios *termios;
+ struct ktermios *termios;
spin_lock_irqsave(&port->lock, lock_flags);
termios = port->info->tty->termios;
@@ -180,7 +180,7 @@ static int jsm_tty_open(struct uart_port *port)
struct jsm_board *brd;
int rc = 0;
struct jsm_channel *channel = (struct jsm_channel *)port;
- struct termios *termios;
+ struct ktermios *termios;
/* Get board pointer from our array of majors we have allocated */
brd = channel->ch_bd;
@@ -269,7 +269,7 @@ static int jsm_tty_open(struct uart_port *port)
static void jsm_tty_close(struct uart_port *port)
{
struct jsm_board *bd;
- struct termios *ts;
+ struct ktermios *ts;
struct jsm_channel *channel = (struct jsm_channel *)port;
jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
@@ -302,8 +302,8 @@ static void jsm_tty_close(struct uart_port *port)
}
static void jsm_tty_set_termios(struct uart_port *port,
- struct termios *termios,
- struct termios *old_termios)
+ struct ktermios *termios,
+ struct ktermios *old_termios)
{
unsigned long lock_flags;
struct jsm_channel *channel = (struct jsm_channel *)port;
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
index 7656a35f5e2..6e09c8b395e 100644
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/serial/m32r_sio.c
@@ -699,7 +699,7 @@ static unsigned int m32r_sio_get_divisor(struct uart_port *port,
}
static void m32r_sio_set_termios(struct uart_port *port,
- struct termios *termios, struct termios *old)
+ struct ktermios *termios, struct ktermios *old)
{
struct uart_sio_port *up = (struct uart_sio_port *)port;
unsigned char cval = 0;
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index 3db206d29b3..08430961a89 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -1132,7 +1132,7 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
return 0;
}
-static void mcfrs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 6dd579ed977..3c4b6c24371 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -270,8 +270,8 @@ mpc52xx_uart_shutdown(struct uart_port *port)
}
static void
-mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
- struct termios *old)
+mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
+ struct ktermios *old)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned long flags;
@@ -789,7 +789,9 @@ static struct console mpc52xx_console = {
static int __init
mpc52xx_console_init(void)
{
+#if defined(CONFIG_PPC_MERGE)
mpc52xx_uart_of_enumerate();
+#endif
register_console(&mpc52xx_console);
return 0;
}
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index 29823bd60fb..3d2fcc57b1c 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -1440,8 +1440,8 @@ mpsc_shutdown(struct uart_port *port)
}
static void
-mpsc_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
u32 baud;
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
index 8ad1b8c5ec5..ccb8fa1800a 100644
--- a/drivers/serial/mux.c
+++ b/drivers/serial/mux.c
@@ -273,8 +273,8 @@ static void mux_shutdown(struct uart_port *port)
* The Serial Mux does not support this function.
*/
static void
-mux_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+mux_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
}
diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c
index 062bad457b1..b56f7db4503 100644
--- a/drivers/serial/netx-serial.c
+++ b/drivers/serial/netx-serial.c
@@ -337,8 +337,8 @@ static void netx_shutdown(struct uart_port *port)
}
static void
-netx_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+netx_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int baud, quot;
unsigned char old_cr;
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index bf9809ed9c0..752ef07516b 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1262,8 +1262,8 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
}
-static void __pmz_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_pmac_port *uap = to_pmz(port);
unsigned long baud;
@@ -1273,7 +1273,7 @@ static void __pmz_set_termios(struct uart_port *port, struct termios *termios,
if (ZS_IS_ASLEEP(uap))
return;
- memcpy(&uap->termios_cache, termios, sizeof(struct termios));
+ memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));
/* XXX Check which revs of machines actually allow 1 and 4Mb speeds
* on the IR dongle. Note that the IRTTY driver currently doesn't know
@@ -1313,8 +1313,8 @@ static void __pmz_set_termios(struct uart_port *port, struct termios *termios,
}
/* The port lock is not held. */
-static void pmz_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_pmac_port *uap = to_pmz(port);
unsigned long flags;
diff --git a/drivers/serial/pmac_zilog.h b/drivers/serial/pmac_zilog.h
index c03f9bfacdd..570b0d925e8 100644
--- a/drivers/serial/pmac_zilog.h
+++ b/drivers/serial/pmac_zilog.h
@@ -60,7 +60,7 @@ struct uart_pmac_port {
volatile struct dbdma_regs __iomem *tx_dma_regs;
volatile struct dbdma_regs __iomem *rx_dma_regs;
- struct termios termios_cache;
+ struct ktermios termios_cache;
};
#define to_pmz(p) ((struct uart_pmac_port *)(p))
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index 415fe9633a9..d403aaa5509 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -433,8 +433,8 @@ static void serial_pxa_shutdown(struct uart_port *port)
}
static void
-serial_pxa_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
unsigned char cval, fcr = 0;
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 8dfc2dd058c..3ba9208ebd0 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -738,8 +738,8 @@ static unsigned int s3c24xx_serial_getclk(struct uart_port *port,
}
static void s3c24xx_serial_set_termios(struct uart_port *port,
- struct termios *termios,
- struct termios *old)
+ struct ktermios *termios,
+ struct ktermios *old)
{
struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
struct s3c24xx_uart_port *ourport = to_ourport(port);
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
index d4065266b6f..58a83c27e14 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -408,8 +408,8 @@ static void sa1100_shutdown(struct uart_port *port)
}
static void
-sa1100_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
unsigned long flags;
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index c67b05e9a45..f84982e508c 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -65,7 +65,7 @@ static struct lock_class_key port_lock_key;
#define uart_console(port) (0)
#endif
-static void uart_change_speed(struct uart_state *state, struct termios *old_termios);
+static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios);
static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
static void uart_change_pm(struct uart_state *state, int pm_state);
@@ -338,8 +338,8 @@ EXPORT_SYMBOL(uart_update_timeout);
* we're actually going to be using.
*/
unsigned int
-uart_get_baud_rate(struct uart_port *port, struct termios *termios,
- struct termios *old, unsigned int min, unsigned int max)
+uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old, unsigned int min, unsigned int max)
{
unsigned int try, baud, altbaud = 38400;
upf_t flags = port->flags & UPF_SPD_MASK;
@@ -421,11 +421,11 @@ uart_get_divisor(struct uart_port *port, unsigned int baud)
EXPORT_SYMBOL(uart_get_divisor);
static void
-uart_change_speed(struct uart_state *state, struct termios *old_termios)
+uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
{
struct tty_struct *tty = state->info->tty;
struct uart_port *port = state->port;
- struct termios *termios;
+ struct ktermios *termios;
/*
* If we have no tty, termios, or the port does not exist,
@@ -1139,7 +1139,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
return ret;
}
-static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct uart_state *state = tty->driver_data;
unsigned long flags;
@@ -1866,7 +1866,7 @@ int __init
uart_set_options(struct uart_port *port, struct console *co,
int baud, int parity, int bits, int flow)
{
- struct termios termios;
+ struct ktermios termios;
int i;
/*
@@ -1876,7 +1876,7 @@ uart_set_options(struct uart_port *port, struct console *co,
spin_lock_init(&port->lock);
lockdep_set_class(&port->lock, &port_lock_key);
- memset(&termios, 0, sizeof(struct termios));
+ memset(&termios, 0, sizeof(struct ktermios));
termios.c_cflag = CREAD | HUPCL | CLOCAL;
@@ -1991,12 +1991,12 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
* Re-enable the console device after suspending.
*/
if (uart_console(port)) {
- struct termios termios;
+ struct ktermios termios;
/*
* First try to use the console cflag setting.
*/
- memset(&termios, 0, sizeof(struct termios));
+ memset(&termios, 0, sizeof(struct ktermios));
termios.c_cflag = port->cons->cflag;
/*
@@ -2189,6 +2189,7 @@ int uart_register_driver(struct uart_driver *drv)
normal->subtype = SERIAL_TYPE_NORMAL;
normal->init_termios = tty_std_termios;
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv;
tty_set_operations(normal, &uart_ops);
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
index 5e1ac356bbb..eb18d429752 100644
--- a/drivers/serial/serial_lh7a40x.c
+++ b/drivers/serial/serial_lh7a40x.c
@@ -348,8 +348,8 @@ static void lh7a40xuart_shutdown (struct uart_port* port)
}
static void lh7a40xuart_set_termios (struct uart_port* port,
- struct termios* termios,
- struct termios* old)
+ struct ktermios* termios,
+ struct ktermios* old)
{
unsigned int con;
unsigned int inten;
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 2a48289ac72..7186a82c475 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -556,8 +556,8 @@ static void serial_txx9_shutdown(struct uart_port *port)
}
static void
-serial_txx9_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
unsigned int cval, fcr = 0;
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 3b5f19ec212..c53b69610a5 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -319,6 +319,28 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
sci_out(port, SCFCR, fcr_val);
}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+{
+ unsigned int fcr_val = 0;
+
+ if (cflag & CRTSCTS) {
+ fcr_val |= SCFCR_MCE;
+
+ ctrl_outw(0x0000, PORT_PSCR);
+ } else {
+ unsigned short data;
+
+ data = ctrl_inw(PORT_PSCR);
+ data &= 0x033f;
+ data |= 0x0400;
+ ctrl_outw(data, PORT_PSCR);
+
+ ctrl_outw(ctrl_inw(SCSPTR0) & 0x17, SCSPTR0);
+ }
+
+ sci_out(port, SCFCR, fcr_val);
+}
#else
/* For SH7750 */
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
@@ -943,8 +965,8 @@ static void sci_shutdown(struct uart_port *port)
s->disable(port);
}
-static void sci_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct sci_port *s = &sci_ports[port->line];
unsigned int status, baud, smr_val;
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index e4557cc4f74..77f7d6351ab 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -90,6 +90,13 @@
# 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_SH7722)
+# define SCPDR0 0xA405013E /* 16 bit SCIF0 PSDR */
+# define SCSPTR0 SCPDR0
+# define SCIF_ORER 0x0001 /* overrun error bit */
+# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+# define SCIF_ONLY
+# define PORT_PSCR 0xA405011E
#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
@@ -495,6 +502,7 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfe620000)
return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7300)
static inline int sci_rxd_in(struct uart_port *port)
@@ -521,6 +529,13 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+ if (port->mapbase == 0xffe00000)
+ return ctrl_inb(SCPDR0) & 0x0001 ? 1 : 0; /* SCIF0 */
+ return 1;
+}
#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
static inline int sci_rxd_in(struct uart_port *port)
{
@@ -550,6 +565,7 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xff925000)
return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
static inline int sci_rxd_in(struct uart_port *port)
@@ -558,6 +574,7 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffe10000)
return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
static inline int sci_rxd_in(struct uart_port *port)
@@ -570,6 +587,7 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfffe9800)
return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+ return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
static inline int sci_rxd_in(struct uart_port *port)
@@ -580,6 +598,7 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xf8420000)
return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ return 1;
}
#endif
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index 956b2cf08e1..253ceb895ca 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -361,8 +361,8 @@ static int snp_startup(struct uart_port *port)
*
*/
static void
-snp_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+snp_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
}
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index 03941d27d15..40d48566215 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -281,8 +281,8 @@ static void sunhv_shutdown(struct uart_port *port)
}
/* port->lock is not held. */
-static void sunhv_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
unsigned int quot = uart_get_divisor(port, baud);
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 08a7cd6a3a0..145d6236954 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -786,8 +786,8 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla
}
/* port->lock is not held. */
-static void sunsab_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
unsigned long flags;
@@ -1037,7 +1037,8 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
err = request_irq(up->port.irq, sunsab_interrupt,
IRQF_SHARED, "sab", up);
if (err) {
- of_iounmap(up->port.membase,
+ of_iounmap(&op->resource[0],
+ up->port.membase,
sizeof(union sab82532_async_regs));
return err;
}
@@ -1064,7 +1065,8 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
sizeof(union sab82532_async_regs),
(inst * 2) + 1);
if (err) {
- of_iounmap(up[0].port.membase,
+ of_iounmap(&op->resource[0],
+ up[0].port.membase,
sizeof(union sab82532_async_regs));
free_irq(up[0].port.irq, &up[0]);
return err;
@@ -1082,10 +1084,13 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
static void __devexit sab_remove_one(struct uart_sunsab_port *up)
{
+ struct of_device *op = to_of_device(up->port.dev);
+
uart_remove_one_port(&sunsab_reg, &up->port);
if (!(up->port.line & 1))
free_irq(up->port.irq, up);
- of_iounmap(up->port.membase,
+ of_iounmap(&op->resource[0],
+ up->port.membase,
sizeof(union sab82532_async_regs));
}
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index c577faea60e..3ec3df21816 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -893,8 +893,8 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
}
static void
-sunsu_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+sunsu_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int baud, quot;
@@ -1480,13 +1480,13 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
return 0;
out_unmap:
- of_iounmap(up->port.membase, up->reg_size);
+ of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
return err;
}
-static int __devexit su_remove(struct of_device *dev)
+static int __devexit su_remove(struct of_device *op)
{
- struct uart_sunsu_port *up = dev_get_drvdata(&dev->dev);;
+ struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
if (up->su_type == SU_PORT_MS ||
up->su_type == SU_PORT_KBD) {
@@ -1499,9 +1499,9 @@ static int __devexit su_remove(struct of_device *dev)
}
if (up->port.membase)
- of_iounmap(up->port.membase, up->reg_size);
+ of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index b2cc703b2b9..244f796dc62 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -922,8 +922,8 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
/* The port lock is not held. */
static void
-sunzilog_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
unsigned long flags;
@@ -1379,13 +1379,15 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
if (!keyboard_mouse) {
err = uart_add_one_port(&sunzilog_reg, &up[0].port);
if (err) {
- of_iounmap(rp, sizeof(struct zilog_layout));
+ of_iounmap(&op->resource[0],
+ rp, sizeof(struct zilog_layout));
return err;
}
err = uart_add_one_port(&sunzilog_reg, &up[1].port);
if (err) {
uart_remove_one_port(&sunzilog_reg, &up[0].port);
- of_iounmap(rp, sizeof(struct zilog_layout));
+ of_iounmap(&op->resource[0],
+ rp, sizeof(struct zilog_layout));
return err;
}
} else {
@@ -1414,18 +1416,18 @@ static void __devexit zs_remove_one(struct uart_sunzilog_port *up)
uart_remove_one_port(&sunzilog_reg, &up->port);
}
-static int __devexit zs_remove(struct of_device *dev)
+static int __devexit zs_remove(struct of_device *op)
{
- struct uart_sunzilog_port *up = dev_get_drvdata(&dev->dev);
+ struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev);
struct zilog_layout __iomem *regs;
zs_remove_one(&up[0]);
zs_remove_one(&up[1]);
regs = sunzilog_chip_regs[up[0].port.line / 2];
- of_iounmap(regs, sizeof(struct zilog_layout));
+ of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout));
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index 83690653b78..f5051cf1a0c 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -214,8 +214,8 @@ static void ulite_shutdown(struct uart_port *port)
free_irq(port->irq, port);
}
-static void ulite_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned long flags;
unsigned int baud;
@@ -256,7 +256,7 @@ static void ulite_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, ULITE_REGION);
iounmap(port->membase);
- port->membase = 0;
+ port->membase = NULL;
}
static int ulite_request_port(struct uart_port *port)
@@ -278,8 +278,8 @@ static int ulite_request_port(struct uart_port *port)
static void ulite_config_port(struct uart_port *port, int flags)
{
- ulite_request_port(port);
- port->type = PORT_UARTLITE;
+ if (!ulite_request_port(port))
+ port->type = PORT_UARTLITE;
}
static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
@@ -438,7 +438,7 @@ static int __devinit ulite_probe(struct platform_device *pdev)
port->iotype = UPIO_MEM;
port->iobase = 1; /* mark port in use */
port->mapbase = res->start;
- port->membase = 0;
+ port->membase = NULL;
port->ops = &ulite_ops;
port->irq = res2->start;
port->flags = UPF_BOOT_AUTOCONF;
@@ -462,7 +462,7 @@ static int ulite_remove(struct platform_device *pdev)
uart_remove_one_port(&ulite_uart_driver, port);
/* mark port as free */
- port->membase = 0;
+ port->membase = NULL;
return 0;
}
diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c
index 28f3bbff87b..dd98aca6ed0 100644
--- a/drivers/serial/v850e_uart.c
+++ b/drivers/serial/v850e_uart.c
@@ -404,8 +404,8 @@ static void v850e_uart_shutdown (struct uart_port *port)
}
static void
-v850e_uart_set_termios (struct uart_port *port, struct termios *termios,
- struct termios *old)
+v850e_uart_set_termios (struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned cflags = termios->c_cflag;
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index fd51f8182de..cf0e663b42e 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -562,8 +562,8 @@ static void siu_shutdown(struct uart_port *port)
free_irq(port->irq, port);
}
-static void siu_set_termios(struct uart_port *port, struct termios *new,
- struct termios *old)
+static void siu_set_termios(struct uart_port *port, struct ktermios *new,
+ struct ktermios *old)
{
tcflag_t c_cflag, c_iflag;
uint8_t lcr, fcr, ier;
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 494d9b85648..8b41f9cc256 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -49,6 +49,14 @@ MODULE_LICENSE("GPL");
#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
+/* for testing SSCR1 changes that require SSP restart, basically
+ * everything except the service and interrupt enables */
+#define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_EBCEI | SSCR1_SCFR \
+ | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
+ | SSCR1_RWOT | SSCR1_TRAIL | SSCR1_PINTE \
+ | SSCR1_STRF | SSCR1_EFWR |SSCR1_RFT \
+ | SSCR1_TFT | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
+
#define DEFINE_SSP_REG(reg, off) \
static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \
static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (off)); }
@@ -123,8 +131,8 @@ struct driver_data {
u8 n_bytes;
u32 dma_width;
int cs_change;
- void (*write)(struct driver_data *drv_data);
- void (*read)(struct driver_data *drv_data);
+ int (*write)(struct driver_data *drv_data);
+ int (*read)(struct driver_data *drv_data);
irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
void (*cs_control)(u32 command);
};
@@ -132,7 +140,6 @@ struct driver_data {
struct chip_data {
u32 cr0;
u32 cr1;
- u32 to;
u32 psp;
u32 timeout;
u8 n_bytes;
@@ -143,8 +150,8 @@ struct chip_data {
u8 enable_dma;
u8 bits_per_word;
u32 speed_hz;
- void (*write)(struct driver_data *drv_data);
- void (*read)(struct driver_data *drv_data);
+ int (*write)(struct driver_data *drv_data);
+ int (*read)(struct driver_data *drv_data);
void (*cs_control)(u32 command);
};
@@ -166,114 +173,118 @@ static int flush(struct driver_data *drv_data)
return limit;
}
-static void restore_state(struct driver_data *drv_data)
-{
- void *reg = drv_data->ioaddr;
-
- /* Clear status and disable clock */
- write_SSSR(drv_data->clear_sr, reg);
- write_SSCR0(drv_data->cur_chip->cr0 & ~SSCR0_SSE, reg);
-
- /* Load the registers */
- write_SSCR1(drv_data->cur_chip->cr1, reg);
- write_SSCR0(drv_data->cur_chip->cr0, reg);
- if (drv_data->ssp_type != PXA25x_SSP) {
- write_SSTO(0, reg);
- write_SSPSP(drv_data->cur_chip->psp, reg);
- }
-}
-
static void null_cs_control(u32 command)
{
}
-static void null_writer(struct driver_data *drv_data)
+static int null_writer(struct driver_data *drv_data)
{
void *reg = drv_data->ioaddr;
u8 n_bytes = drv_data->n_bytes;
- while ((read_SSSR(reg) & SSSR_TNF)
- && (drv_data->tx < drv_data->tx_end)) {
- write_SSDR(0, reg);
- drv_data->tx += n_bytes;
- }
+ if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+ || (drv_data->tx == drv_data->tx_end))
+ return 0;
+
+ write_SSDR(0, reg);
+ drv_data->tx += n_bytes;
+
+ return 1;
}
-static void null_reader(struct driver_data *drv_data)
+static int null_reader(struct driver_data *drv_data)
{
void *reg = drv_data->ioaddr;
u8 n_bytes = drv_data->n_bytes;
while ((read_SSSR(reg) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
+ && (drv_data->rx < drv_data->rx_end)) {
read_SSDR(reg);
drv_data->rx += n_bytes;
}
+
+ return drv_data->rx == drv_data->rx_end;
}
-static void u8_writer(struct driver_data *drv_data)
+static int u8_writer(struct driver_data *drv_data)
{
void *reg = drv_data->ioaddr;
- while ((read_SSSR(reg) & SSSR_TNF)
- && (drv_data->tx < drv_data->tx_end)) {
- write_SSDR(*(u8 *)(drv_data->tx), reg);
- ++drv_data->tx;
- }
+ if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+ || (drv_data->tx == drv_data->tx_end))
+ return 0;
+
+ write_SSDR(*(u8 *)(drv_data->tx), reg);
+ ++drv_data->tx;
+
+ return 1;
}
-static void u8_reader(struct driver_data *drv_data)
+static int u8_reader(struct driver_data *drv_data)
{
void *reg = drv_data->ioaddr;
while ((read_SSSR(reg) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
+ && (drv_data->rx < drv_data->rx_end)) {
*(u8 *)(drv_data->rx) = read_SSDR(reg);
++drv_data->rx;
}
+
+ return drv_data->rx == drv_data->rx_end;
}
-static void u16_writer(struct driver_data *drv_data)
+static int u16_writer(struct driver_data *drv_data)
{
void *reg = drv_data->ioaddr;
- while ((read_SSSR(reg) & SSSR_TNF)
- && (drv_data->tx < drv_data->tx_end)) {
- write_SSDR(*(u16 *)(drv_data->tx), reg);
- drv_data->tx += 2;
- }
+ if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+ || (drv_data->tx == drv_data->tx_end))
+ return 0;
+
+ write_SSDR(*(u16 *)(drv_data->tx), reg);
+ drv_data->tx += 2;
+
+ return 1;
}
-static void u16_reader(struct driver_data *drv_data)
+static int u16_reader(struct driver_data *drv_data)
{
void *reg = drv_data->ioaddr;
while ((read_SSSR(reg) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
+ && (drv_data->rx < drv_data->rx_end)) {
*(u16 *)(drv_data->rx) = read_SSDR(reg);
drv_data->rx += 2;
}
+
+ return drv_data->rx == drv_data->rx_end;
}
-static void u32_writer(struct driver_data *drv_data)
+
+static int u32_writer(struct driver_data *drv_data)
{
void *reg = drv_data->ioaddr;
- while ((read_SSSR(reg) & SSSR_TNF)
- && (drv_data->tx < drv_data->tx_end)) {
- write_SSDR(*(u32 *)(drv_data->tx), reg);
- drv_data->tx += 4;
- }
+ if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+ || (drv_data->tx == drv_data->tx_end))
+ return 0;
+
+ write_SSDR(*(u32 *)(drv_data->tx), reg);
+ drv_data->tx += 4;
+
+ return 1;
}
-static void u32_reader(struct driver_data *drv_data)
+static int u32_reader(struct driver_data *drv_data)
{
void *reg = drv_data->ioaddr;
while ((read_SSSR(reg) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
+ && (drv_data->rx < drv_data->rx_end)) {
*(u32 *)(drv_data->rx) = read_SSDR(reg);
drv_data->rx += 4;
}
+
+ return drv_data->rx == drv_data->rx_end;
}
static void *next_transfer(struct driver_data *drv_data)
@@ -409,166 +420,134 @@ static int wait_dma_channel_stop(int channel)
return limit;
}
-static void dma_handler(int channel, void *data)
+void dma_error_stop(struct driver_data *drv_data, const char *msg)
{
- struct driver_data *drv_data = data;
- struct spi_message *msg = drv_data->cur_msg;
void *reg = drv_data->ioaddr;
- u32 irq_status = DCSR(channel) & DMA_INT_MASK;
- u32 trailing_sssr = 0;
- if (irq_status & DCSR_BUSERR) {
+ /* Stop and reset */
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+ write_SSSR(drv_data->clear_sr, reg);
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(0, reg);
+ flush(drv_data);
+ write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
- /* Disable interrupts, clear status and reset DMA */
- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
- if (drv_data->ssp_type != PXA25x_SSP)
- write_SSTO(0, reg);
- write_SSSR(drv_data->clear_sr, reg);
- DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
- DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+ unmap_dma_buffers(drv_data);
- if (flush(drv_data) == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_handler: flush fail\n");
+ dev_err(&drv_data->pdev->dev, "%s\n", msg);
- unmap_dma_buffers(drv_data);
+ drv_data->cur_msg->state = ERROR_STATE;
+ tasklet_schedule(&drv_data->pump_transfers);
+}
+
+static void dma_transfer_complete(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
+ struct spi_message *msg = drv_data->cur_msg;
+
+ /* Clear and disable interrupts on SSP and DMA channels*/
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ write_SSSR(drv_data->clear_sr, reg);
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+
+ if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_handler: dma rx channel stop failed\n");
+
+ if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_transfer: ssp rx stall failed\n");
+
+ unmap_dma_buffers(drv_data);
+
+ /* update the buffer pointer for the amount completed in dma */
+ drv_data->rx += drv_data->len -
+ (DCMD(drv_data->rx_channel) & DCMD_LENGTH);
+
+ /* read trailing data from fifo, it does not matter how many
+ * bytes are in the fifo just read until buffer is full
+ * or fifo is empty, which ever occurs first */
+ drv_data->read(drv_data);
+
+ /* return count of what was actually read */
+ msg->actual_length += drv_data->len -
+ (drv_data->rx_end - drv_data->rx);
+
+ /* Release chip select if requested, transfer delays are
+ * handled in pump_transfers */
+ if (drv_data->cs_change)
+ drv_data->cs_control(PXA2XX_CS_DEASSERT);
+
+ /* Move to next transfer */
+ msg->state = next_transfer(drv_data);
+
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+}
+
+static void dma_handler(int channel, void *data)
+{
+ struct driver_data *drv_data = data;
+ u32 irq_status = DCSR(channel) & DMA_INT_MASK;
+
+ if (irq_status & DCSR_BUSERR) {
if (channel == drv_data->tx_channel)
- dev_err(&drv_data->pdev->dev,
- "dma_handler: bad bus address on "
- "tx channel %d, source %x target = %x\n",
- channel, DSADR(channel), DTADR(channel));
+ dma_error_stop(drv_data,
+ "dma_handler: "
+ "bad bus address on tx channel");
else
- dev_err(&drv_data->pdev->dev,
- "dma_handler: bad bus address on "
- "rx channel %d, source %x target = %x\n",
- channel, DSADR(channel), DTADR(channel));
-
- msg->state = ERROR_STATE;
- tasklet_schedule(&drv_data->pump_transfers);
+ dma_error_stop(drv_data,
+ "dma_handler: "
+ "bad bus address on rx channel");
+ return;
}
/* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */
- if ((drv_data->ssp_type == PXA25x_SSP)
- && (channel == drv_data->tx_channel)
- && (irq_status & DCSR_ENDINTR)) {
+ if ((channel == drv_data->tx_channel)
+ && (irq_status & DCSR_ENDINTR)
+ && (drv_data->ssp_type == PXA25x_SSP)) {
/* Wait for rx to stall */
if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
dev_err(&drv_data->pdev->dev,
"dma_handler: ssp rx stall failed\n");
- /* Clear and disable interrupts on SSP and DMA channels*/
- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
- write_SSSR(drv_data->clear_sr, reg);
- DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
- DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
- if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_handler: dma rx channel stop failed\n");
-
- unmap_dma_buffers(drv_data);
-
- /* Read trailing bytes */
- /* Calculate number of trailing bytes, read them */
- trailing_sssr = read_SSSR(reg);
- if ((trailing_sssr & 0xf008) != 0xf000) {
- drv_data->rx = drv_data->rx_end -
- (((trailing_sssr >> 12) & 0x0f) + 1);
- drv_data->read(drv_data);
- }
- msg->actual_length += drv_data->len;
-
- /* Release chip select if requested, transfer delays are
- * handled in pump_transfers */
- if (drv_data->cs_change)
- drv_data->cs_control(PXA2XX_CS_DEASSERT);
-
- /* Move to next transfer */
- msg->state = next_transfer(drv_data);
-
- /* Schedule transfer tasklet */
- tasklet_schedule(&drv_data->pump_transfers);
+ /* finish this transfer, start the next */
+ dma_transfer_complete(drv_data);
}
}
static irqreturn_t dma_transfer(struct driver_data *drv_data)
{
u32 irq_status;
- u32 trailing_sssr = 0;
- struct spi_message *msg = drv_data->cur_msg;
void *reg = drv_data->ioaddr;
irq_status = read_SSSR(reg) & drv_data->mask_sr;
if (irq_status & SSSR_ROR) {
- /* Clear and disable interrupts on SSP and DMA channels*/
- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
- if (drv_data->ssp_type != PXA25x_SSP)
- write_SSTO(0, reg);
- write_SSSR(drv_data->clear_sr, reg);
- DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
- DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
- unmap_dma_buffers(drv_data);
-
- if (flush(drv_data) == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_transfer: flush fail\n");
-
- dev_warn(&drv_data->pdev->dev, "dma_transfer: fifo overun\n");
-
- drv_data->cur_msg->state = ERROR_STATE;
- tasklet_schedule(&drv_data->pump_transfers);
-
+ dma_error_stop(drv_data, "dma_transfer: fifo overrun");
return IRQ_HANDLED;
}
/* Check for false positive timeout */
- if ((irq_status & SSSR_TINT) && DCSR(drv_data->tx_channel) & DCSR_RUN) {
+ if ((irq_status & SSSR_TINT)
+ && (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
write_SSSR(SSSR_TINT, reg);
return IRQ_HANDLED;
}
if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) {
- /* Clear and disable interrupts on SSP and DMA channels*/
- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ /* Clear and disable timeout interrupt, do the rest in
+ * dma_transfer_complete */
if (drv_data->ssp_type != PXA25x_SSP)
write_SSTO(0, reg);
- write_SSSR(drv_data->clear_sr, reg);
- DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
- DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
- if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_transfer: dma rx channel stop failed\n");
-
- if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_transfer: ssp rx stall failed\n");
-
- unmap_dma_buffers(drv_data);
-
- /* Calculate number of trailing bytes, read them */
- trailing_sssr = read_SSSR(reg);
- if ((trailing_sssr & 0xf008) != 0xf000) {
- drv_data->rx = drv_data->rx_end -
- (((trailing_sssr >> 12) & 0x0f) + 1);
- drv_data->read(drv_data);
- }
- msg->actual_length += drv_data->len;
-
- /* Release chip select if requested, transfer delays are
- * handled in pump_transfers */
- if (drv_data->cs_change)
- drv_data->cs_control(PXA2XX_CS_DEASSERT);
-
- /* Move to next transfer */
- msg->state = next_transfer(drv_data);
-
- /* Schedule transfer tasklet */
- tasklet_schedule(&drv_data->pump_transfers);
+ /* finish this transfer, start the next */
+ dma_transfer_complete(drv_data);
return IRQ_HANDLED;
}
@@ -577,89 +556,103 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
return IRQ_NONE;
}
-static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+static void int_error_stop(struct driver_data *drv_data, const char* msg)
{
- struct spi_message *msg = drv_data->cur_msg;
void *reg = drv_data->ioaddr;
- unsigned long limit = loops_per_jiffy << 1;
- u32 irq_status;
- u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
- drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
-
- while ((irq_status = read_SSSR(reg) & irq_mask)) {
-
- if (irq_status & SSSR_ROR) {
- /* Clear and disable interrupts */
- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
- write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
- if (drv_data->ssp_type != PXA25x_SSP)
- write_SSTO(0, reg);
- write_SSSR(drv_data->clear_sr, reg);
+ /* Stop and reset SSP */
+ write_SSSR(drv_data->clear_sr, reg);
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(0, reg);
+ flush(drv_data);
+ write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
- if (flush(drv_data) == 0)
- dev_err(&drv_data->pdev->dev,
- "interrupt_transfer: flush fail\n");
+ dev_err(&drv_data->pdev->dev, "%s\n", msg);
- /* Stop the SSP */
+ drv_data->cur_msg->state = ERROR_STATE;
+ tasklet_schedule(&drv_data->pump_transfers);
+}
- dev_warn(&drv_data->pdev->dev,
- "interrupt_transfer: fifo overun\n");
+static void int_transfer_complete(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
- msg->state = ERROR_STATE;
- tasklet_schedule(&drv_data->pump_transfers);
+ /* Stop SSP */
+ write_SSSR(drv_data->clear_sr, reg);
+ write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(0, reg);
- return IRQ_HANDLED;
- }
+ /* Update total byte transfered return count actual bytes read */
+ drv_data->cur_msg->actual_length += drv_data->len -
+ (drv_data->rx_end - drv_data->rx);
- /* Look for false positive timeout */
- if ((irq_status & SSSR_TINT)
- && (drv_data->rx < drv_data->rx_end))
- write_SSSR(SSSR_TINT, reg);
+ /* Release chip select if requested, transfer delays are
+ * handled in pump_transfers */
+ if (drv_data->cs_change)
+ drv_data->cs_control(PXA2XX_CS_DEASSERT);
- /* Pump data */
- drv_data->read(drv_data);
- drv_data->write(drv_data);
+ /* Move to next transfer */
+ drv_data->cur_msg->state = next_transfer(drv_data);
- if (drv_data->tx == drv_data->tx_end) {
- /* Disable tx interrupt */
- write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
- irq_mask = drv_data->mask_sr & ~SSSR_TFS;
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+}
- /* PXA25x_SSP has no timeout, read trailing bytes */
- if (drv_data->ssp_type == PXA25x_SSP) {
- while ((read_SSSR(reg) & SSSR_BSY) && limit--)
- drv_data->read(drv_data);
+static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+{
+ void *reg = drv_data->ioaddr;
- if (limit == 0)
- dev_err(&drv_data->pdev->dev,
- "interrupt_transfer: "
- "trailing byte read failed\n");
- }
- }
+ u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
+ drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
- if ((irq_status & SSSR_TINT)
- || (drv_data->rx == drv_data->rx_end)) {
+ u32 irq_status = read_SSSR(reg) & irq_mask;
- /* Clear timeout */
- write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
- if (drv_data->ssp_type != PXA25x_SSP)
- write_SSTO(0, reg);
- write_SSSR(drv_data->clear_sr, reg);
+ if (irq_status & SSSR_ROR) {
+ int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
+ return IRQ_HANDLED;
+ }
- /* Update total byte transfered */
- msg->actual_length += drv_data->len;
+ if (irq_status & SSSR_TINT) {
+ write_SSSR(SSSR_TINT, reg);
+ if (drv_data->read(drv_data)) {
+ int_transfer_complete(drv_data);
+ return IRQ_HANDLED;
+ }
+ }
- /* Release chip select if requested, transfer delays are
- * handled in pump_transfers */
- if (drv_data->cs_change)
- drv_data->cs_control(PXA2XX_CS_DEASSERT);
+ /* Drain rx fifo, Fill tx fifo and prevent overruns */
+ do {
+ if (drv_data->read(drv_data)) {
+ int_transfer_complete(drv_data);
+ return IRQ_HANDLED;
+ }
+ } while (drv_data->write(drv_data));
- /* Move to next transfer */
- msg->state = next_transfer(drv_data);
+ if (drv_data->read(drv_data)) {
+ int_transfer_complete(drv_data);
+ return IRQ_HANDLED;
+ }
- /* Schedule transfer tasklet */
- tasklet_schedule(&drv_data->pump_transfers);
+ if (drv_data->tx == drv_data->tx_end) {
+ write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
+ /* PXA25x_SSP has no timeout, read trailing bytes */
+ if (drv_data->ssp_type == PXA25x_SSP) {
+ if (!wait_ssp_rx_stall(reg))
+ {
+ int_error_stop(drv_data, "interrupt_transfer: "
+ "rx stall failed");
+ return IRQ_HANDLED;
+ }
+ if (!drv_data->read(drv_data))
+ {
+ int_error_stop(drv_data,
+ "interrupt_transfer: "
+ "trailing byte read failed");
+ return IRQ_HANDLED;
+ }
+ int_transfer_complete(drv_data);
}
}
@@ -681,7 +674,7 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
write_SSSR(drv_data->clear_sr, reg);
dev_err(&drv_data->pdev->dev, "bad message state "
- "in interrupt handler");
+ "in interrupt handler\n");
/* Never fail */
return IRQ_HANDLED;
@@ -690,6 +683,102 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
return drv_data->transfer_handler(drv_data);
}
+int set_dma_burst_and_threshold(struct chip_data *chip, struct spi_device *spi,
+ u8 bits_per_word, u32 *burst_code,
+ u32 *threshold)
+{
+ struct pxa2xx_spi_chip *chip_info =
+ (struct pxa2xx_spi_chip *)spi->controller_data;
+ int bytes_per_word;
+ int burst_bytes;
+ int thresh_words;
+ int req_burst_size;
+ int retval = 0;
+
+ /* Set the threshold (in registers) to equal the same amount of data
+ * as represented by burst size (in bytes). The computation below
+ * is (burst_size rounded up to nearest 8 byte, word or long word)
+ * divided by (bytes/register); the tx threshold is the inverse of
+ * the rx, so that there will always be enough data in the rx fifo
+ * to satisfy a burst, and there will always be enough space in the
+ * tx fifo to accept a burst (a tx burst will overwrite the fifo if
+ * there is not enough space), there must always remain enough empty
+ * space in the rx fifo for any data loaded to the tx fifo.
+ * Whenever burst_size (in bytes) equals bits/word, the fifo threshold
+ * will be 8, or half the fifo;
+ * The threshold can only be set to 2, 4 or 8, but not 16, because
+ * to burst 16 to the tx fifo, the fifo would have to be empty;
+ * however, the minimum fifo trigger level is 1, and the tx will
+ * request service when the fifo is at this level, with only 15 spaces.
+ */
+
+ /* find bytes/word */
+ if (bits_per_word <= 8)
+ bytes_per_word = 1;
+ else if (bits_per_word <= 16)
+ bytes_per_word = 2;
+ else
+ bytes_per_word = 4;
+
+ /* use struct pxa2xx_spi_chip->dma_burst_size if available */
+ if (chip_info)
+ req_burst_size = chip_info->dma_burst_size;
+ else {
+ switch (chip->dma_burst_size) {
+ default:
+ /* if the default burst size is not set,
+ * do it now */
+ chip->dma_burst_size = DCMD_BURST8;
+ case DCMD_BURST8:
+ req_burst_size = 8;
+ break;
+ case DCMD_BURST16:
+ req_burst_size = 16;
+ break;
+ case DCMD_BURST32:
+ req_burst_size = 32;
+ break;
+ }
+ }
+ if (req_burst_size <= 8) {
+ *burst_code = DCMD_BURST8;
+ burst_bytes = 8;
+ } else if (req_burst_size <= 16) {
+ if (bytes_per_word == 1) {
+ /* don't burst more than 1/2 the fifo */
+ *burst_code = DCMD_BURST8;
+ burst_bytes = 8;
+ retval = 1;
+ } else {
+ *burst_code = DCMD_BURST16;
+ burst_bytes = 16;
+ }
+ } else {
+ if (bytes_per_word == 1) {
+ /* don't burst more than 1/2 the fifo */
+ *burst_code = DCMD_BURST8;
+ burst_bytes = 8;
+ retval = 1;
+ } else if (bytes_per_word == 2) {
+ /* don't burst more than 1/2 the fifo */
+ *burst_code = DCMD_BURST16;
+ burst_bytes = 16;
+ retval = 1;
+ } else {
+ *burst_code = DCMD_BURST32;
+ burst_bytes = 32;
+ }
+ }
+
+ thresh_words = burst_bytes / bytes_per_word;
+
+ /* thresh_words will be between 2 and 8 */
+ *threshold = (SSCR1_RxTresh(thresh_words) & SSCR1_RFT)
+ | (SSCR1_TxTresh(16-thresh_words) & SSCR1_TFT);
+
+ return retval;
+}
+
static void pump_transfers(unsigned long data)
{
struct driver_data *drv_data = (struct driver_data *)data;
@@ -702,6 +791,9 @@ static void pump_transfers(unsigned long data)
u8 bits = 0;
u32 speed = 0;
u32 cr0;
+ u32 cr1;
+ u32 dma_thresh = drv_data->cur_chip->dma_threshold;
+ u32 dma_burst = drv_data->cur_chip->dma_burst_size;
/* Get current state information */
message = drv_data->cur_msg;
@@ -731,6 +823,16 @@ static void pump_transfers(unsigned long data)
udelay(previous->delay_usecs);
}
+ /* Check transfer length */
+ if (transfer->len > 8191)
+ {
+ dev_warn(&drv_data->pdev->dev, "pump_transfers: transfer "
+ "length greater than 8191\n");
+ message->status = -EINVAL;
+ giveback(drv_data);
+ return;
+ }
+
/* Setup the transfer state based on the type of transfer */
if (flush(drv_data) == 0) {
dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
@@ -747,17 +849,15 @@ static void pump_transfers(unsigned long data)
drv_data->rx_end = drv_data->rx + transfer->len;
drv_data->rx_dma = transfer->rx_dma;
drv_data->tx_dma = transfer->tx_dma;
- drv_data->len = transfer->len;
+ drv_data->len = transfer->len & DCMD_LENGTH;
drv_data->write = drv_data->tx ? chip->write : null_writer;
drv_data->read = drv_data->rx ? chip->read : null_reader;
drv_data->cs_change = transfer->cs_change;
/* Change speed and bit per word on a per transfer */
+ cr0 = chip->cr0;
if (transfer->speed_hz || transfer->bits_per_word) {
- /* Disable clock */
- write_SSCR0(chip->cr0 & ~SSCR0_SSE, reg);
- cr0 = chip->cr0;
bits = chip->bits_per_word;
speed = chip->speed_hz;
@@ -796,15 +896,24 @@ static void pump_transfers(unsigned long data)
drv_data->write = drv_data->write != null_writer ?
u32_writer : null_writer;
}
+ /* if bits/word is changed in dma mode, then must check the
+ * thresholds and burst also */
+ if (chip->enable_dma) {
+ if (set_dma_burst_and_threshold(chip, message->spi,
+ bits, &dma_burst,
+ &dma_thresh))
+ if (printk_ratelimit())
+ dev_warn(&message->spi->dev,
+ "pump_transfer: "
+ "DMA burst size reduced to "
+ "match bits_per_word\n");
+ }
cr0 = clk_div
| SSCR0_Motorola
| SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
| SSCR0_SSE
| (bits > 16 ? SSCR0_EDSS : 0);
-
- /* Start it back up */
- write_SSCR0(cr0, reg);
}
message->state = RUNNING_STATE;
@@ -823,13 +932,13 @@ static void pump_transfers(unsigned long data)
/* No target address increment */
DCMD(drv_data->rx_channel) = DCMD_FLOWSRC
| drv_data->dma_width
- | chip->dma_burst_size
+ | dma_burst
| drv_data->len;
else
DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR
| DCMD_FLOWSRC
| drv_data->dma_width
- | chip->dma_burst_size
+ | dma_burst
| drv_data->len;
/* Setup tx DMA Channel */
@@ -840,13 +949,13 @@ static void pump_transfers(unsigned long data)
/* No source address increment */
DCMD(drv_data->tx_channel) = DCMD_FLOWTRG
| drv_data->dma_width
- | chip->dma_burst_size
+ | dma_burst
| drv_data->len;
else
DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR
| DCMD_FLOWTRG
| drv_data->dma_width
- | chip->dma_burst_size
+ | dma_burst
| drv_data->len;
/* Enable dma end irqs on SSP to detect end of transfer */
@@ -856,16 +965,11 @@ static void pump_transfers(unsigned long data)
/* Fix me, need to handle cs polarity */
drv_data->cs_control(PXA2XX_CS_ASSERT);
- /* Go baby, go */
+ /* Clear status and start DMA engine */
+ cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1;
write_SSSR(drv_data->clear_sr, reg);
DCSR(drv_data->rx_channel) |= DCSR_RUN;
DCSR(drv_data->tx_channel) |= DCSR_RUN;
- if (drv_data->ssp_type != PXA25x_SSP)
- write_SSTO(chip->timeout, reg);
- write_SSCR1(chip->cr1
- | chip->dma_threshold
- | drv_data->dma_cr1,
- reg);
} else {
/* Ensure we have the correct interrupt handler */
drv_data->transfer_handler = interrupt_transfer;
@@ -873,14 +977,25 @@ static void pump_transfers(unsigned long data)
/* Fix me, need to handle cs polarity */
drv_data->cs_control(PXA2XX_CS_ASSERT);
- /* Go baby, go */
+ /* Clear status */
+ cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
write_SSSR(drv_data->clear_sr, reg);
+ }
+
+ /* see if we need to reload the config registers */
+ if ((read_SSCR0(reg) != cr0)
+ || (read_SSCR1(reg) & SSCR1_CHANGE_MASK) !=
+ (cr1 & SSCR1_CHANGE_MASK)) {
+
+ write_SSCR0(cr0 & ~SSCR0_SSE, reg);
if (drv_data->ssp_type != PXA25x_SSP)
write_SSTO(chip->timeout, reg);
- write_SSCR1(chip->cr1
- | chip->threshold
- | drv_data->int_cr1,
- reg);
+ write_SSCR1(cr1, reg);
+ write_SSCR0(cr0, reg);
+ } else {
+ if (drv_data->ssp_type != PXA25x_SSP)
+ write_SSTO(chip->timeout, reg);
+ write_SSCR1(cr1, reg);
}
}
@@ -915,9 +1030,9 @@ static void pump_messages(struct work_struct *work)
struct spi_transfer,
transfer_list);
- /* Setup the SSP using the per chip configuration */
+ /* prepare to setup the SSP, in pump_transfers, using the per
+ * chip configuration */
drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
- restore_state(drv_data);
/* Mark as busy and launch transfers */
tasklet_schedule(&drv_data->pump_transfers);
@@ -963,63 +1078,77 @@ static int setup(struct spi_device *spi)
spi->bits_per_word = 8;
if (drv_data->ssp_type != PXA25x_SSP
- && (spi->bits_per_word < 4 || spi->bits_per_word > 32))
+ && (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
+ dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
+ "b/w not 4-32 for type non-PXA25x_SSP\n",
+ drv_data->ssp_type, spi->bits_per_word);
return -EINVAL;
- else if (spi->bits_per_word < 4 || spi->bits_per_word > 16)
+ }
+ else if (drv_data->ssp_type == PXA25x_SSP
+ && (spi->bits_per_word < 4
+ || spi->bits_per_word > 16)) {
+ dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
+ "b/w not 4-16 for type PXA25x_SSP\n",
+ drv_data->ssp_type, spi->bits_per_word);
return -EINVAL;
+ }
- /* Only alloc (or use chip_info) on first setup */
+ /* Only alloc on first setup */
chip = spi_get_ctldata(spi);
- if (chip == NULL) {
+ if (!chip) {
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
- if (!chip)
+ if (!chip) {
+ dev_err(&spi->dev,
+ "failed setup: can't allocate chip data\n");
return -ENOMEM;
+ }
chip->cs_control = null_cs_control;
chip->enable_dma = 0;
- chip->timeout = SSP_TIMEOUT(1000);
+ chip->timeout = 1000;
chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1);
chip->dma_burst_size = drv_data->master_info->enable_dma ?
DCMD_BURST8 : 0;
-
- chip_info = spi->controller_data;
}
+ /* protocol drivers may change the chip settings, so...
+ * if chip_info exists, use it */
+ chip_info = spi->controller_data;
+
/* chip_info isn't always needed */
+ chip->cr1 = 0;
if (chip_info) {
if (chip_info->cs_control)
chip->cs_control = chip_info->cs_control;
- chip->timeout = SSP_TIMEOUT(chip_info->timeout_microsecs);
+ chip->timeout = chip_info->timeout;
- chip->threshold = SSCR1_RxTresh(chip_info->rx_threshold)
- | SSCR1_TxTresh(chip_info->tx_threshold);
+ chip->threshold = (SSCR1_RxTresh(chip_info->rx_threshold) &
+ SSCR1_RFT) |
+ (SSCR1_TxTresh(chip_info->tx_threshold) &
+ SSCR1_TFT);
chip->enable_dma = chip_info->dma_burst_size != 0
&& drv_data->master_info->enable_dma;
chip->dma_threshold = 0;
- if (chip->enable_dma) {
- if (chip_info->dma_burst_size <= 8) {
- chip->dma_threshold = SSCR1_RxTresh(8)
- | SSCR1_TxTresh(8);
- chip->dma_burst_size = DCMD_BURST8;
- } else if (chip_info->dma_burst_size <= 16) {
- chip->dma_threshold = SSCR1_RxTresh(16)
- | SSCR1_TxTresh(16);
- chip->dma_burst_size = DCMD_BURST16;
- } else {
- chip->dma_threshold = SSCR1_RxTresh(32)
- | SSCR1_TxTresh(32);
- chip->dma_burst_size = DCMD_BURST32;
- }
- }
-
-
if (chip_info->enable_loopback)
chip->cr1 = SSCR1_LBM;
}
+ /* set dma burst and threshold outside of chip_info path so that if
+ * chip_info goes away after setting chip->enable_dma, the
+ * burst and threshold can still respond to changes in bits_per_word */
+ if (chip->enable_dma) {
+ /* set up legal burst and threshold for dma */
+ if (set_dma_burst_and_threshold(chip, spi, spi->bits_per_word,
+ &chip->dma_burst_size,
+ &chip->dma_threshold)) {
+ dev_warn(&spi->dev, "in setup: DMA burst size reduced "
+ "to match bits_per_word\n");
+ }
+ }
+
if (drv_data->ioaddr == SSP1_VIRT)
clk_div = SSP1_SerClkDiv(spi->max_speed_hz);
else if (drv_data->ioaddr == SSP2_VIRT)
@@ -1027,7 +1156,11 @@ static int setup(struct spi_device *spi)
else if (drv_data->ioaddr == SSP3_VIRT)
clk_div = SSP3_SerClkDiv(spi->max_speed_hz);
else
+ {
+ dev_err(&spi->dev, "failed setup: unknown IO address=0x%p\n",
+ drv_data->ioaddr);
return -ENODEV;
+ }
chip->speed_hz = spi->max_speed_hz;
chip->cr0 = clk_div
@@ -1036,8 +1169,9 @@ static int setup(struct spi_device *spi)
spi->bits_per_word - 16 : spi->bits_per_word)
| SSCR0_SSE
| (spi->bits_per_word > 16 ? SSCR0_EDSS : 0);
- chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) << 4)
- | (((spi->mode & SPI_CPOL) != 0) << 3);
+ chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH);
+ chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
+ | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
/* NOTE: PXA25x_SSP _could_ use external clocking ... */
if (drv_data->ssp_type != PXA25x_SSP)
@@ -1071,7 +1205,6 @@ static int setup(struct spi_device *spi)
chip->write = u32_writer;
} else {
dev_err(&spi->dev, "invalid wordsize\n");
- kfree(chip);
return -ENODEV;
}
chip->bits_per_word = spi->bits_per_word;
@@ -1162,6 +1295,12 @@ static int destroy_queue(struct driver_data *drv_data)
int status;
status = stop_queue(drv_data);
+ /* we are unloading the module or failing to load (only two calls
+ * to this routine), and neither call can handle a return value.
+ * However, destroy_workqueue calls flush_workqueue, and that will
+ * block until all work is done. If the reason that stop_queue
+ * timed out is that the work will never finish, then it does no
+ * good to call destroy_workqueue, so return anyway. */
if (status != 0)
return status;
@@ -1360,7 +1499,16 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
/* Remove the queue */
status = destroy_queue(drv_data);
if (status != 0)
- return status;
+ /* the kernel does not check the return status of this
+ * this routine (mod->exit, within the kernel). Therefore
+ * nothing is gained by returning from here, the module is
+ * going away regardless, and we should not leave any more
+ * resources allocated than necessary. We cannot free the
+ * message memory in drv_data->queue, but we can release the
+ * resources below. I think the kernel should honor -EBUSY
+ * returns but... */
+ dev_err(&pdev->dev, "pxa2xx_spi_remove: workqueue will not "
+ "complete, message memory not freed\n");
/* Disable the SSP at the peripheral and SOC level */
write_SSCR0(0, drv_data->ioaddr);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 270e6211c2e..6307428d2c9 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -366,7 +366,6 @@ spi_alloc_master(struct device *dev, unsigned size)
class_device_initialize(&master->cdev);
master->cdev.class = &spi_master_class;
- kobj_set_kset_s(&master->cdev, spi_master_class.subsys);
master->cdev.dev = get_device(dev);
spi_master_set_devdata(master, &master[1]);
@@ -466,14 +465,20 @@ EXPORT_SYMBOL_GPL(spi_unregister_master);
*/
struct spi_master *spi_busnum_to_master(u16 bus_num)
{
- char name[9];
- struct kobject *bus;
-
- snprintf(name, sizeof name, "spi%u", bus_num);
- bus = kset_find_obj(&spi_master_class.subsys.kset, name);
- if (bus)
- return container_of(bus, struct spi_master, cdev.kobj);
- return NULL;
+ struct class_device *cdev;
+ struct spi_master *master = NULL;
+ struct spi_master *m;
+
+ down(&spi_master_class.sem);
+ list_for_each_entry(cdev, &spi_master_class.children, node) {
+ m = container_of(cdev, struct spi_master, cdev);
+ if (m->bus_num == bus_num) {
+ master = spi_master_get(m);
+ break;
+ }
+ }
+ up(&spi_master_class.sem);
+ return master;
}
EXPORT_SYMBOL_GPL(spi_busnum_to_master);
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index ff0b04895db..e9798bf7b8c 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -112,6 +112,8 @@ u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \
{ \
u32 data; \
const type * tx = mpc83xx_spi->tx; \
+ if (!tx) \
+ return 0; \
data = *tx++; \
mpc83xx_spi->tx = tx; \
return data; \
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 2ebe1fc4c39..651379c51ae 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -10,9 +10,6 @@
*
*/
-
-//#define DEBUG
-
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -44,6 +41,9 @@ struct s3c24xx_spi {
int len;
int count;
+ int (*set_cs)(struct s3c2410_spi_info *spi,
+ int cs, int pol);
+
/* data buffers */
const unsigned char *tx;
unsigned char *rx;
@@ -64,6 +64,11 @@ static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev)
return spi_master_get_devdata(sdev->master);
}
+static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol)
+{
+ s3c2410_gpio_setpin(spi->pin_cs, pol);
+}
+
static void s3c24xx_spi_chipsel(struct spi_device *spi, int value)
{
struct s3c24xx_spi *hw = to_hw(spi);
@@ -72,10 +77,7 @@ static void s3c24xx_spi_chipsel(struct spi_device *spi, int value)
switch (value) {
case BITBANG_CS_INACTIVE:
- if (hw->pdata->set_cs)
- hw->pdata->set_cs(hw->pdata, value, cspol);
- else
- s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol ^ 1);
+ hw->pdata->set_cs(hw->pdata, spi->chip_select, cspol^1);
break;
case BITBANG_CS_ACTIVE:
@@ -96,14 +98,9 @@ static void s3c24xx_spi_chipsel(struct spi_device *spi, int value)
/* write new configration */
writeb(spcon, hw->regs + S3C2410_SPCON);
-
- if (hw->pdata->set_cs)
- hw->pdata->set_cs(hw->pdata, value, cspol);
- else
- s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol);
+ hw->pdata->set_cs(hw->pdata, spi->chip_select, cspol);
break;
-
}
}
@@ -174,7 +171,7 @@ static int s3c24xx_spi_setup(struct spi_device *spi)
static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
{
- return hw->tx ? hw->tx[count] : 0xff;
+ return hw->tx ? hw->tx[count] : 0;
}
static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
@@ -330,9 +327,12 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
/* setup any gpio we can */
if (!hw->pdata->set_cs) {
+ hw->set_cs = s3c24xx_spi_gpiocs;
+
s3c2410_gpio_setpin(hw->pdata->pin_cs, 1);
s3c2410_gpio_cfgpin(hw->pdata->pin_cs, S3C2410_GPIO_OUTPUT);
- }
+ } else
+ hw->set_cs = hw->pdata->set_cs;
/* register our spi controller */
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index a5d2cdfff46..eda53ed04cb 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
@@ -22,7 +23,7 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/spi-gpio.h>
-#include <asm/arch/hardware.h>
+#include <asm/hardware.h>
struct s3c2410_spigpio {
struct spi_bitbang bitbang;
diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile
index 83b5bd75ce2..96734269221 100644
--- a/drivers/tc/Makefile
+++ b/drivers/tc/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-$(CONFIG_TC) += tc.o
+obj-$(CONFIG_TC) += tc.o tc-driver.o
obj-$(CONFIG_ZS) += zs.o
obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
diff --git a/drivers/tc/tc-driver.c b/drivers/tc/tc-driver.c
new file mode 100644
index 00000000000..16b5bae63c7
--- /dev/null
+++ b/drivers/tc/tc-driver.c
@@ -0,0 +1,110 @@
+/*
+ * TURBOchannel driver services.
+ *
+ * Copyright (c) 2005 James Simmons
+ * Copyright (c) 2006 Maciej W. Rozycki
+ *
+ * Loosely based on drivers/dio/dio-driver.c and
+ * drivers/pci/pci-driver.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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/tc.h>
+
+/**
+ * tc_register_driver - register a new TC driver
+ * @drv: the driver structure to register
+ *
+ * Adds the driver structure to the list of registered drivers
+ * Returns a negative value on error, otherwise 0.
+ * If no error occurred, the driver remains registered even if
+ * no device was claimed during registration.
+ */
+int tc_register_driver(struct tc_driver *tdrv)
+{
+ return driver_register(&tdrv->driver);
+}
+EXPORT_SYMBOL(tc_register_driver);
+
+/**
+ * tc_unregister_driver - unregister a TC driver
+ * @drv: the driver structure to unregister
+ *
+ * Deletes the driver structure from the list of registered TC drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
+void tc_unregister_driver(struct tc_driver *tdrv)
+{
+ driver_unregister(&tdrv->driver);
+}
+EXPORT_SYMBOL(tc_unregister_driver);
+
+/**
+ * tc_match_device - tell if a TC device structure has a matching
+ * TC device ID structure
+ * @tdrv: the TC driver to earch for matching TC device ID strings
+ * @tdev: the TC device structure to match against
+ *
+ * Used by a driver to check whether a TC device present in the
+ * system is in its list of supported devices. Returns the matching
+ * tc_device_id structure or %NULL if there is no match.
+ */
+const struct tc_device_id *tc_match_device(struct tc_driver *tdrv,
+ struct tc_dev *tdev)
+{
+ const struct tc_device_id *id = tdrv->id_table;
+
+ if (id) {
+ while (id->name[0] || id->vendor[0]) {
+ if (strcmp(tdev->name, id->name) == 0 &&
+ strcmp(tdev->vendor, id->vendor) == 0)
+ return id;
+ id++;
+ }
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(tc_match_device);
+
+/**
+ * tc_bus_match - Tell if a device structure has a matching
+ * TC device ID structure
+ * @dev: the device structure to match against
+ * @drv: the device driver to search for matching TC device ID strings
+ *
+ * Used by a driver to check whether a TC device present in the
+ * system is in its list of supported devices. Returns 1 if there
+ * is a match or 0 otherwise.
+ */
+static int tc_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct tc_dev *tdev = to_tc_dev(dev);
+ struct tc_driver *tdrv = to_tc_driver(drv);
+ const struct tc_device_id *id;
+
+ id = tc_match_device(tdrv, tdev);
+ if (id)
+ return 1;
+
+ return 0;
+}
+
+struct bus_type tc_bus_type = {
+ .name = "tc",
+ .match = tc_bus_match,
+};
+EXPORT_SYMBOL(tc_bus_type);
+
+static int __init tc_driver_init(void)
+{
+ return bus_register(&tc_bus_type);
+}
+
+postcore_initcall(tc_driver_init);
diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c
index 4a51e56f85b..f77f62a4b32 100644
--- a/drivers/tc/tc.c
+++ b/drivers/tc/tc.c
@@ -1,254 +1,193 @@
/*
- * tc-init: We assume the TURBOchannel to be up and running so
- * just probe for Modules and fill in the global data structure
- * tc_bus.
+ * TURBOchannel bus services.
*
- * 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) Harald Koerfgen, 1998
+ * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki
+ * Copyright (c) 2005 James Simmons
*
- * Copyright (c) Harald Koerfgen, 1998
- * Copyright (c) 2001, 2003, 2005 Maciej W. Rozycki
+ * 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/compiler.h>
+#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/module.h>
#include <linux/string.h>
+#include <linux/tc.h>
#include <linux/types.h>
-#include <asm/addrspace.h>
-#include <asm/errno.h>
#include <asm/io.h>
-#include <asm/paccess.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/prom.h>
-#include <asm/dec/tcinfo.h>
-#include <asm/dec/tcmodule.h>
-#include <asm/dec/interrupts.h>
-
-MODULE_LICENSE("GPL");
-slot_info tc_bus[MAX_SLOT];
-static int num_tcslots;
-static tcinfo *info;
+static struct tc_bus tc_bus = {
+ .name = "TURBOchannel",
+};
/*
- * Interface to the world. Read comment in include/asm-mips/tc.h.
+ * Probing for TURBOchannel modules.
*/
-
-int search_tc_card(const char *name)
-{
- int slot;
- slot_info *sip;
-
- for (slot = 0; slot < num_tcslots; slot++) {
- sip = &tc_bus[slot];
- if ((sip->flags & FREE) &&
- (strncmp(sip->name, name, strlen(name)) == 0)) {
- return slot;
- }
- }
-
- return -ENODEV;
-}
-
-void claim_tc_card(int slot)
-{
- if (tc_bus[slot].flags & IN_USE) {
- printk("claim_tc_card: attempting to claim a card already in use\n");
- return;
- }
- tc_bus[slot].flags &= ~FREE;
- tc_bus[slot].flags |= IN_USE;
-}
-
-void release_tc_card(int slot)
+static void __init tc_bus_add_devices(struct tc_bus *tbus)
{
- if (tc_bus[slot].flags & FREE) {
- printk("release_tc_card: "
- "attempting to release a card already free\n");
- return;
- }
- tc_bus[slot].flags &= ~IN_USE;
- tc_bus[slot].flags |= FREE;
-}
-
-unsigned long get_tc_base_addr(int slot)
-{
- return tc_bus[slot].base_addr;
-}
-
-unsigned long get_tc_irq_nr(int slot)
-{
- return tc_bus[slot].interrupt;
-}
-
-unsigned long get_tc_speed(void)
-{
- return 100000 * (10000 / (unsigned long)info->clk_period);
-}
-
-/*
- * Probing for TURBOchannel modules
- */
-static void __init tc_probe(unsigned long startaddr, unsigned long size,
- int slots)
-{
- unsigned long slotaddr;
+ resource_size_t slotsize = tbus->info.slot_size << 20;
+ resource_size_t extslotsize = tbus->ext_slot_size;
+ resource_size_t slotaddr;
+ resource_size_t extslotaddr;
+ resource_size_t devsize;
+ void __iomem *module;
+ struct tc_dev *tdev;
int i, slot, err;
- long offset;
u8 pattern[4];
- volatile u8 *module;
+ long offset;
- for (slot = 0; slot < slots; slot++) {
- slotaddr = startaddr + slot * size;
- module = ioremap_nocache(slotaddr, size);
+ for (slot = 0; slot < tbus->num_tcslots; slot++) {
+ slotaddr = tbus->slot_base + slot * slotsize;
+ extslotaddr = tbus->ext_slot_base + slot * extslotsize;
+ module = ioremap_nocache(slotaddr, slotsize);
BUG_ON(!module);
- offset = OLDCARD;
+ offset = TC_OLDCARD;
err = 0;
- err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0);
- err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1);
- err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2);
- err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3);
- if (err) {
- iounmap(module);
- continue;
- }
+ err |= tc_preadb(pattern + 0, module + offset + TC_PATTERN0);
+ err |= tc_preadb(pattern + 1, module + offset + TC_PATTERN1);
+ err |= tc_preadb(pattern + 2, module + offset + TC_PATTERN2);
+ err |= tc_preadb(pattern + 3, module + offset + TC_PATTERN3);
+ if (err)
+ goto out_err;
if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
pattern[2] != 0xaa || pattern[3] != 0xff) {
- offset = NEWCARD;
+ offset = TC_NEWCARD;
err = 0;
- err |= get_dbe(pattern[0], module + TC_PATTERN0);
- err |= get_dbe(pattern[1], module + TC_PATTERN1);
- err |= get_dbe(pattern[2], module + TC_PATTERN2);
- err |= get_dbe(pattern[3], module + TC_PATTERN3);
- if (err) {
- iounmap(module);
- continue;
- }
+ err |= tc_preadb(pattern + 0,
+ module + offset + TC_PATTERN0);
+ err |= tc_preadb(pattern + 1,
+ module + offset + TC_PATTERN1);
+ err |= tc_preadb(pattern + 2,
+ module + offset + TC_PATTERN2);
+ err |= tc_preadb(pattern + 3,
+ module + offset + TC_PATTERN3);
+ if (err)
+ goto out_err;
}
if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
- pattern[2] != 0xaa || pattern[3] != 0xff) {
- iounmap(module);
- continue;
+ pattern[2] != 0xaa || pattern[3] != 0xff)
+ goto out_err;
+
+ /* Found a board, allocate it an entry in the list */
+ tdev = kzalloc(sizeof(*tdev), GFP_KERNEL);
+ if (!tdev) {
+ printk(KERN_ERR "tc%x: unable to allocate tc_dev\n",
+ slot);
+ goto out_err;
}
+ sprintf(tdev->dev.bus_id, "tc%x", slot);
+ tdev->bus = tbus;
+ tdev->dev.parent = &tbus->dev;
+ tdev->dev.bus = &tc_bus_type;
+ tdev->slot = slot;
- tc_bus[slot].base_addr = slotaddr;
for (i = 0; i < 8; i++) {
- tc_bus[slot].firmware[i] =
- module[TC_FIRM_VER + offset + 4 * i];
- tc_bus[slot].vendor[i] =
- module[TC_VENDOR + offset + 4 * i];
- tc_bus[slot].name[i] =
- module[TC_MODULE + offset + 4 * i];
+ tdev->firmware[i] =
+ readb(module + offset + TC_FIRM_VER + 4 * i);
+ tdev->vendor[i] =
+ readb(module + offset + TC_VENDOR + 4 * i);
+ tdev->name[i] =
+ readb(module + offset + TC_MODULE + 4 * i);
}
- tc_bus[slot].firmware[8] = 0;
- tc_bus[slot].vendor[8] = 0;
- tc_bus[slot].name[8] = 0;
- /*
- * Looks unneccesary, but we may change
- * TC? in the future
- */
- switch (slot) {
- case 0:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0];
- break;
- case 1:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1];
- break;
- case 2:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2];
- break;
- /*
- * Yuck! DS5000/200 onboard devices
- */
- case 5:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5];
- break;
- case 6:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6];
- break;
- default:
- tc_bus[slot].interrupt = -1;
- break;
+ tdev->firmware[8] = 0;
+ tdev->vendor[8] = 0;
+ tdev->name[8] = 0;
+
+ pr_info("%s: %s %s %s\n", tdev->dev.bus_id, tdev->vendor,
+ tdev->name, tdev->firmware);
+
+ devsize = readb(module + offset + TC_SLOT_SIZE);
+ devsize <<= 22;
+ if (devsize <= slotsize) {
+ tdev->resource.start = slotaddr;
+ tdev->resource.end = slotaddr + devsize - 1;
+ } else if (devsize <= extslotsize) {
+ tdev->resource.start = extslotaddr;
+ tdev->resource.end = extslotaddr + devsize - 1;
+ } else {
+ printk(KERN_ERR "%s: Cannot provide slot space "
+ "(%dMiB required, up to %dMiB supported)\n",
+ tdev->dev.bus_id, devsize >> 20,
+ max(slotsize, extslotsize) >> 20);
+ kfree(tdev);
+ goto out_err;
}
+ tdev->resource.name = tdev->name;
+ tdev->resource.flags = IORESOURCE_MEM;
+
+ tc_device_get_irq(tdev);
+ device_register(&tdev->dev);
+ list_add_tail(&tdev->node, &tbus->devices);
+
+out_err:
iounmap(module);
}
}
/*
- * the main entry
+ * The main entry.
*/
static int __init tc_init(void)
{
- int tc_clock;
- int i;
- unsigned long slot0addr;
- unsigned long slot_size;
-
- if (!TURBOCHANNEL)
+ /* Initialize the TURBOchannel bus */
+ if (tc_bus_get_info(&tc_bus))
return 0;
- for (i = 0; i < MAX_SLOT; i++) {
- tc_bus[i].base_addr = 0;
- tc_bus[i].name[0] = 0;
- tc_bus[i].vendor[0] = 0;
- tc_bus[i].firmware[0] = 0;
- tc_bus[i].interrupt = -1;
- tc_bus[i].flags = FREE;
- }
-
- info = rex_gettcinfo();
- slot0addr = CPHYSADDR((long)rex_slot_address(0));
-
- switch (mips_machtype) {
- case MACH_DS5000_200:
- num_tcslots = 7;
- break;
- case MACH_DS5000_1XX:
- case MACH_DS5000_2X0:
- case MACH_DS5900:
- num_tcslots = 3;
- break;
- case MACH_DS5000_XX:
- default:
- num_tcslots = 2;
- break;
- }
-
- tc_clock = 10000 / info->clk_period;
-
- if (info->slot_size && slot0addr) {
- pr_info("TURBOchannel rev. %d at %d.%d MHz (with%s parity)\n",
- info->revision, tc_clock / 10, tc_clock % 10,
- info->parity ? "" : "out");
-
- slot_size = info->slot_size << 20;
-
- tc_probe(slot0addr, slot_size, num_tcslots);
-
- for (i = 0; i < num_tcslots; i++) {
- if (!tc_bus[i].base_addr)
- continue;
- pr_info(" slot %d: %s %s %s\n", i, tc_bus[i].vendor,
- tc_bus[i].name, tc_bus[i].firmware);
+ INIT_LIST_HEAD(&tc_bus.devices);
+ strcpy(tc_bus.dev.bus_id, "tc");
+ device_register(&tc_bus.dev);
+
+ if (tc_bus.info.slot_size) {
+ unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000;
+
+ pr_info("tc: TURBOchannel rev. %d at %d.%d MHz "
+ "(with%s parity)\n", tc_bus.info.revision,
+ tc_clock / 10, tc_clock % 10,
+ tc_bus.info.parity ? "" : "out");
+
+ tc_bus.resource[0].start = tc_bus.slot_base;
+ tc_bus.resource[0].end = tc_bus.slot_base +
+ (tc_bus.info.slot_size << 20) *
+ tc_bus.num_tcslots - 1;
+ tc_bus.resource[0].name = tc_bus.name;
+ tc_bus.resource[0].flags = IORESOURCE_MEM;
+ if (request_resource(&iomem_resource,
+ &tc_bus.resource[0]) < 0) {
+ printk(KERN_ERR "tc: Cannot reserve resource\n");
+ return 0;
+ }
+ if (tc_bus.ext_slot_size) {
+ tc_bus.resource[1].start = tc_bus.ext_slot_base;
+ tc_bus.resource[1].end = tc_bus.ext_slot_base +
+ tc_bus.ext_slot_size *
+ tc_bus.num_tcslots - 1;
+ tc_bus.resource[1].name = tc_bus.name;
+ tc_bus.resource[1].flags = IORESOURCE_MEM;
+ if (request_resource(&iomem_resource,
+ &tc_bus.resource[1]) < 0) {
+ printk(KERN_ERR
+ "tc: Cannot reserve resource\n");
+ release_resource(&tc_bus.resource[0]);
+ return 0;
+ }
}
+
+ tc_bus_add_devices(&tc_bus);
}
return 0;
}
subsys_initcall(tc_init);
-
-EXPORT_SYMBOL(search_tc_card);
-EXPORT_SYMBOL(claim_tc_card);
-EXPORT_SYMBOL(release_tc_card);
-EXPORT_SYMBOL(get_tc_base_addr);
-EXPORT_SYMBOL(get_tc_irq_nr);
-EXPORT_SYMBOL(get_tc_speed);
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
index 792becdfe6f..fc319727366 100644
--- a/drivers/tc/zs.c
+++ b/drivers/tc/zs.c
@@ -1238,7 +1238,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
return 0;
}
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct dec_serial *info = (struct dec_serial *)tty->driver_data;
int was_stopped;
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index 1b601b6cf2a..df4cc1fb5f6 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -2747,7 +2747,7 @@ static void alaw2ulaw(unsigned char *buff, unsigned long len)
static ssize_t ixj_read(struct file * file_p, char __user *buf, size_t length, loff_t * ppos)
{
unsigned long i = *ppos;
- IXJ * j = get_ixj(NUM(file_p->f_dentry->d_inode));
+ IXJ * j = get_ixj(NUM(file_p->f_path.dentry->d_inode));
DECLARE_WAITQUEUE(wait, current);
@@ -2804,7 +2804,7 @@ static ssize_t ixj_enhanced_read(struct file * file_p, char __user *buf, size_t
{
int pre_retval;
ssize_t read_retval = 0;
- IXJ *j = get_ixj(NUM(file_p->f_dentry->d_inode));
+ IXJ *j = get_ixj(NUM(file_p->f_path.dentry->d_inode));
pre_retval = ixj_PreRead(j, 0L);
switch (pre_retval) {
@@ -2883,7 +2883,7 @@ static ssize_t ixj_enhanced_write(struct file * file_p, const char __user *buf,
int pre_retval;
ssize_t write_retval = 0;
- IXJ *j = get_ixj(NUM(file_p->f_dentry->d_inode));
+ IXJ *j = get_ixj(NUM(file_p->f_path.dentry->d_inode));
pre_retval = ixj_PreWrite(j, 0L);
switch (pre_retval) {
@@ -4582,7 +4582,7 @@ static unsigned int ixj_poll(struct file *file_p, poll_table * wait)
{
unsigned int mask = 0;
- IXJ *j = get_ixj(NUM(file_p->f_dentry->d_inode));
+ IXJ *j = get_ixj(NUM(file_p->f_path.dentry->d_inode));
poll_wait(file_p, &(j->poll_q), wait);
if (j->read_buffer_ready > 0)
@@ -6657,7 +6657,7 @@ static int ixj_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd,
static int ixj_fasync(int fd, struct file *file_p, int mode)
{
- IXJ *j = get_ixj(NUM(file_p->f_dentry->d_inode));
+ IXJ *j = get_ixj(NUM(file_p->f_path.dentry->d_inode));
return fasync_helper(fd, file_p, mode, &j->async_queue);
}
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 8ed6c75adf0..638b8009b3b 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -36,7 +36,7 @@
#include <linux/stat.h>
#include <linux/timer.h>
#include <linux/types.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/workqueue.h>
#include "usbatm.h"
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 7f1fa956dcd..98199628e39 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -677,10 +677,10 @@ static const __u8 acm_tty_size[] = {
5, 6, 7, 8
};
-static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
+static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old)
{
struct acm *acm = tty->driver_data;
- struct termios *termios = tty->termios;
+ struct ktermios *termios = tty->termios;
struct usb_cdc_line_coding newline;
int newctrl = acm->ctrlout;
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 6303970e93c..63e50a1f139 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -130,7 +130,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
struct usblp {
struct usb_device *dev; /* USB device */
- struct semaphore sem; /* locks this struct, especially "dev" */
+ struct mutex mut; /* locks this struct, especially "dev" */
char *writebuf; /* write transfer_buffer */
char *readbuf; /* read transfer_buffer */
char *statusbuf; /* status transfer_buffer */
@@ -217,6 +217,7 @@ static const struct quirk_printer_struct quirk_printers[] = {
{ 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */
{ 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */
{ 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */
+ { 0x0482, 0x0010, USBLP_QUIRK_BIDIR }, /* Kyocera Mita FS 820, by zut <kernel@zut.de> */
{ 0, 0 }
};
@@ -397,6 +398,9 @@ static int usblp_open(struct inode *inode, struct file *file)
retval = 0;
#endif
+ retval = usb_autopm_get_interface(intf);
+ if (retval < 0)
+ goto out;
usblp->used = 1;
file->private_data = usblp;
@@ -441,6 +445,7 @@ static int usblp_release(struct inode *inode, struct file *file)
usblp->used = 0;
if (usblp->present) {
usblp_unlink_urbs(usblp);
+ usb_autopm_put_interface(usblp->intf);
} else /* finish cleanup from disconnect */
usblp_cleanup (usblp);
mutex_unlock (&usblp_mutex);
@@ -465,7 +470,7 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int twoints[2];
int retval = 0;
- down (&usblp->sem);
+ mutex_lock (&usblp->mut);
if (!usblp->present) {
retval = -ENODEV;
goto done;
@@ -644,14 +649,14 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
done:
- up (&usblp->sem);
+ mutex_unlock (&usblp->mut);
return retval;
}
static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
- int timeout, rv, err = 0, transfer_length = 0;
+ int timeout, intr, rv, err = 0, transfer_length = 0;
size_t writecount = 0;
while (writecount < count) {
@@ -668,14 +673,16 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
if (rv < 0)
return writecount ? writecount : -EINTR;
}
- down (&usblp->sem);
+ intr = mutex_lock_interruptible (&usblp->mut);
+ if (intr)
+ return writecount ? writecount : -EINTR;
if (!usblp->present) {
- up (&usblp->sem);
+ mutex_unlock (&usblp->mut);
return -ENODEV;
}
if (usblp->sleeping) {
- up (&usblp->sem);
+ mutex_unlock (&usblp->mut);
return writecount ? writecount : -ENODEV;
}
@@ -687,10 +694,10 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
err = usblp->writeurb->status;
} else
err = usblp_check_status(usblp, err);
- up (&usblp->sem);
+ mutex_unlock (&usblp->mut);
/* if the fault was due to disconnect, let khubd's
- * call to usblp_disconnect() grab usblp->sem ...
+ * call to usblp_disconnect() grab usblp->mut ...
*/
schedule ();
continue;
@@ -702,7 +709,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
*/
writecount += transfer_length;
if (writecount == count) {
- up(&usblp->sem);
+ mutex_unlock(&usblp->mut);
break;
}
@@ -714,7 +721,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
if (copy_from_user(usblp->writeurb->transfer_buffer,
buffer + writecount, transfer_length)) {
- up(&usblp->sem);
+ mutex_unlock(&usblp->mut);
return writecount ? writecount : -EFAULT;
}
@@ -727,10 +734,10 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
count = -EIO;
else
count = writecount ? writecount : -ENOMEM;
- up (&usblp->sem);
+ mutex_unlock (&usblp->mut);
break;
}
- up (&usblp->sem);
+ mutex_unlock (&usblp->mut);
}
return count;
@@ -739,12 +746,14 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
- int rv;
+ int rv, intr;
if (!usblp->bidir)
return -EINVAL;
- down (&usblp->sem);
+ intr = mutex_lock_interruptible (&usblp->mut);
+ if (intr)
+ return -EINTR;
if (!usblp->present) {
count = -ENODEV;
goto done;
@@ -757,9 +766,9 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
count = -EAGAIN;
goto done;
}
- up(&usblp->sem);
+ mutex_unlock(&usblp->mut);
rv = wait_event_interruptible(usblp->wait, usblp->rcomplete || !usblp->present);
- down(&usblp->sem);
+ mutex_lock(&usblp->mut);
if (rv < 0) {
count = -EINTR;
goto done;
@@ -807,7 +816,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
}
done:
- up (&usblp->sem);
+ mutex_unlock (&usblp->mut);
return count;
}
@@ -886,7 +895,7 @@ static int usblp_probe(struct usb_interface *intf,
goto abort;
}
usblp->dev = dev;
- init_MUTEX (&usblp->sem);
+ mutex_init (&usblp->mut);
init_waitqueue_head(&usblp->wait);
usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
usblp->intf = intf;
@@ -1178,7 +1187,7 @@ static void usblp_disconnect(struct usb_interface *intf)
device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
mutex_lock (&usblp_mutex);
- down (&usblp->sem);
+ mutex_lock (&usblp->mut);
usblp->present = 0;
usb_set_intfdata (intf, NULL);
@@ -1187,7 +1196,7 @@ static void usblp_disconnect(struct usb_interface *intf)
usblp->writebuf, usblp->writeurb->transfer_dma);
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->readbuf, usblp->readurb->transfer_dma);
- up (&usblp->sem);
+ mutex_unlock (&usblp->mut);
if (!usblp->used)
usblp_cleanup (usblp);
@@ -1198,14 +1207,9 @@ 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;
usblp_unlink_urbs(usblp);
- up (&usblp->sem);
- mutex_unlock (&usblp_mutex);
return 0;
}
@@ -1215,15 +1219,9 @@ 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;
}
@@ -1246,6 +1244,7 @@ static struct usb_driver usblp_driver = {
.suspend = usblp_suspend,
.resume = usblp_resume,
.id_table = usblp_ids,
+ .supports_autosuspend = 1,
};
static int __init usblp_init(void)
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index f8324d8d06a..2fc0f88a3d8 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -33,19 +33,6 @@ config USB_DEVICEFS
Most users want to say Y here.
-config USB_BANDWIDTH
- bool "Enforce USB bandwidth allocation (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
- help
- If you say Y here, the USB subsystem enforces USB bandwidth
- allocation and will prevent some device opens from succeeding
- if they would cause USB bandwidth usage to go above 90% of
- the bus bandwidth.
-
- If you say N here, these conditions will cause warning messages
- about USB bandwidth usage to be logged and some devices or
- drivers may not work correctly.
-
config USB_DYNAMIC_MINORS
bool "Dynamic USB minor allocation (EXPERIMENTAL)"
depends on USB && EXPERIMENTAL
@@ -72,22 +59,6 @@ config USB_SUSPEND
If you are unsure about this, say N here.
-config USB_MULTITHREAD_PROBE
- bool "USB Multi-threaded probe (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
- default n
- help
- Say Y here if you want the USB core to spawn a new thread for
- every USB device that is probed. This can cause a small speedup
- in boot times on systems with a lot of different USB devices.
-
- This option should be safe to enable, but if any odd probing
- problems are found, please disable it, or dynamically turn it
- off in the /sys/module/usbcore/parameters/multithread_probe
- file
-
- When in doubt, say N.
-
config USB_OTG
bool
depends on USB && EXPERIMENTAL
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index c3915dc2860..ead2475406b 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -49,9 +49,9 @@ static const size_t pool_max [HCD_BUFFER_POOLS] = {
*
* Call hcd_buffer_destroy() to clean up after using those pools.
*/
-int hcd_buffer_create (struct usb_hcd *hcd)
+int hcd_buffer_create(struct usb_hcd *hcd)
{
- char name [16];
+ char name[16];
int i, size;
if (!hcd->self.controller->dma_mask)
@@ -60,11 +60,11 @@ int hcd_buffer_create (struct usb_hcd *hcd)
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (!(size = pool_max [i]))
continue;
- snprintf (name, sizeof name, "buffer-%d", size);
- hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
+ snprintf(name, sizeof name, "buffer-%d", size);
+ hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
size, size, 0);
if (!hcd->pool [i]) {
- hcd_buffer_destroy (hcd);
+ hcd_buffer_destroy(hcd);
return -ENOMEM;
}
}
@@ -79,14 +79,14 @@ int hcd_buffer_create (struct usb_hcd *hcd)
*
* This frees the buffer pools created by hcd_buffer_create().
*/
-void hcd_buffer_destroy (struct usb_hcd *hcd)
+void hcd_buffer_destroy(struct usb_hcd *hcd)
{
int i;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
- struct dma_pool *pool = hcd->pool [i];
+ struct dma_pool *pool = hcd->pool[i];
if (pool) {
- dma_pool_destroy (pool);
+ dma_pool_destroy(pool);
hcd->pool[i] = NULL;
}
}
@@ -97,8 +97,8 @@ void hcd_buffer_destroy (struct usb_hcd *hcd)
* better sharing and to leverage mm/slab.c intelligence.
*/
-void *hcd_buffer_alloc (
- struct usb_bus *bus,
+void *hcd_buffer_alloc(
+ struct usb_bus *bus,
size_t size,
gfp_t mem_flags,
dma_addr_t *dma
@@ -110,18 +110,18 @@ void *hcd_buffer_alloc (
/* some USB hosts just use PIO */
if (!bus->controller->dma_mask) {
*dma = ~(dma_addr_t) 0;
- return kmalloc (size, mem_flags);
+ return kmalloc(size, mem_flags);
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i])
- return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
+ return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
}
- return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
+ return dma_alloc_coherent(hcd->self.controller, size, dma, 0);
}
-void hcd_buffer_free (
- struct usb_bus *bus,
+void hcd_buffer_free(
+ struct usb_bus *bus,
size_t size,
void *addr,
dma_addr_t dma
@@ -134,15 +134,15 @@ void hcd_buffer_free (
return;
if (!bus->controller->dma_mask) {
- kfree (addr);
+ kfree(addr);
return;
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i]) {
- dma_pool_free (hcd->pool [i], addr, dma);
+ dma_pool_free(hcd->pool [i], addr, dma);
return;
}
}
- dma_free_coherent (hcd->self.controller, size, addr, dma);
+ dma_free_coherent(hcd->self.controller, size, addr, dma);
}
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index ea398e5d50a..a47c30b2d76 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -104,7 +104,7 @@ static const char *format_config =
static const char *format_iface =
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
- "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+ "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
static const char *format_endpt =
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
@@ -164,10 +164,10 @@ static const char *class_decode(const int class)
for (ix = 0; clas_info[ix].class != -1; ix++)
if (clas_info[ix].class == class)
break;
- return (clas_info[ix].class_name);
+ return clas_info[ix].class_name;
}
-static char *usb_dump_endpoint_descriptor (
+static char *usb_dump_endpoint_descriptor(
int speed,
char *start,
char *end,
@@ -212,9 +212,9 @@ static char *usb_dump_endpoint_descriptor (
break;
case USB_ENDPOINT_XFER_INT:
type = "Int.";
- if (speed == USB_SPEED_HIGH) {
+ if (speed == USB_SPEED_HIGH)
interval = 1 << (desc->bInterval - 1);
- } else
+ else
interval = desc->bInterval;
break;
default: /* "can't happen" */
@@ -242,15 +242,19 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
{
const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
const char *driver_name = "";
+ int active = 0;
if (start > end)
return start;
down_read(&usb_bus_type.subsys.rwsem);
- if (iface)
+ if (iface) {
driver_name = (iface->dev.driver
? iface->dev.driver->name
: "(none)");
+ active = (desc == &iface->cur_altsetting->desc);
+ }
start += sprintf(start, format_iface,
+ active ? '*' : ' ', /* mark active altsetting */
desc->bInterfaceNumber,
desc->bAlternateSetting,
desc->bNumEndpoints,
@@ -343,7 +347,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
if (start > end)
return start;
- start += sprintf (start, format_device1,
+ start += sprintf(start, format_device1,
bcdUSB >> 8, bcdUSB & 0xff,
desc->bDeviceClass,
class_decode (desc->bDeviceClass),
@@ -363,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
/*
* Dump the different strings that this device holds.
*/
-static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
+static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
{
if (start > end)
return start;
@@ -395,7 +399,7 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
if (start > end)
return start;
- start = usb_dump_device_strings (start, end, dev);
+ start = usb_dump_device_strings(start, end, dev);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (start > end)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 3ed4cb2d56d..2087766f9e8 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -522,19 +522,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
static struct usb_device *usbdev_lookup_minor(int minor)
{
- struct class_device *class_dev;
- struct usb_device *dev = NULL;
+ struct device *device;
+ struct usb_device *udev = NULL;
down(&usb_device_class->sem);
- list_for_each_entry(class_dev, &usb_device_class->children, node) {
- if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
- dev = class_dev->class_data;
+ list_for_each_entry(device, &usb_device_class->devices, node) {
+ if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+ udev = device->platform_data;
break;
}
}
up(&usb_device_class->sem);
- return dev;
+ return udev;
};
/*
@@ -570,6 +570,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
ps->dev = dev;
ps->file = file;
spin_lock_init(&ps->lock);
+ INIT_LIST_HEAD(&ps->list);
INIT_LIST_HEAD(&ps->async_pending);
INIT_LIST_HEAD(&ps->async_completed);
init_waitqueue_head(&ps->wait);
@@ -962,7 +963,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr);
return -EFAULT;
}
- snoop(&ps->dev->dev, "control urb\n");
+ snoop(&ps->dev->dev, "control urb: bRequest=%02x "
+ "bRrequestType=%02x wValue=%04x "
+ "wIndex=%04x wLength=%04x\n",
+ dr->bRequest, dr->bRequestType, dr->wValue,
+ dr->wIndex, dr->wLength);
break;
case USBDEVFS_URB_TYPE_BULK:
@@ -1592,19 +1597,19 @@ 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,
+ dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
+ MKDEV(USB_DEVICE_MAJOR, minor),
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
- if (IS_ERR(dev->class_dev))
- return PTR_ERR(dev->class_dev);
+ if (IS_ERR(dev->usbfs_dev))
+ return PTR_ERR(dev->usbfs_dev);
- dev->class_dev->class_data = dev;
+ dev->usbfs_dev->platform_data = dev;
return 0;
}
static void usbdev_remove(struct usb_device *dev)
{
- class_device_unregister(dev->class_dev);
+ device_unregister(dev->usbfs_dev);
}
static int usbdev_notify(struct notifier_block *self, unsigned long action,
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index d6eb5ce1dd1..600d1bc8272 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -28,24 +28,16 @@
#include "hcd.h"
#include "usb.h"
-static int usb_match_one_id(struct usb_interface *interface,
- const struct usb_device_id *id);
-
-struct usb_dynid {
- struct list_head node;
- struct usb_device_id id;
-};
-
#ifdef CONFIG_HOTPLUG
/*
* Adds a new dynamic USBdevice ID to this driver,
* and cause the driver to probe for all devices again.
*/
-static ssize_t store_new_id(struct device_driver *driver,
- const char *buf, size_t count)
+ssize_t usb_store_new_id(struct usb_dynids *dynids,
+ struct device_driver *driver,
+ const char *buf, size_t count)
{
- struct usb_driver *usb_drv = to_usb_driver(driver);
struct usb_dynid *dynid;
u32 idVendor = 0;
u32 idProduct = 0;
@@ -65,9 +57,9 @@ static ssize_t store_new_id(struct device_driver *driver,
dynid->id.idProduct = idProduct;
dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- spin_lock(&usb_drv->dynids.lock);
- list_add_tail(&usb_drv->dynids.list, &dynid->node);
- spin_unlock(&usb_drv->dynids.lock);
+ spin_lock(&dynids->lock);
+ list_add_tail(&dynids->list, &dynid->node);
+ spin_unlock(&dynids->lock);
if (get_driver(driver)) {
retval = driver_attach(driver);
@@ -78,6 +70,15 @@ static ssize_t store_new_id(struct device_driver *driver,
return retval;
return count;
}
+EXPORT_SYMBOL_GPL(usb_store_new_id);
+
+static ssize_t store_new_id(struct device_driver *driver,
+ const char *buf, size_t count)
+{
+ struct usb_driver *usb_drv = to_usb_driver(driver);
+
+ return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+}
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
static int usb_create_newid_file(struct usb_driver *usb_drv)
@@ -365,8 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver,
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)
+int usb_match_one_id(struct usb_interface *interface,
+ const struct usb_device_id *id)
{
struct usb_host_interface *intf;
struct usb_device *dev;
@@ -432,6 +433,8 @@ static int usb_match_one_id(struct usb_interface *interface,
return 1;
}
+EXPORT_SYMBOL_GPL(usb_match_one_id);
+
/**
* usb_match_id - find first usb_device_id matching device or interface
* @interface: the interface of interest
@@ -750,7 +753,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
* usb_register_dev() to enable that functionality. This function no longer
* takes care of that.
*/
-int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
+int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
+ const char *mod_name)
{
int retval = 0;
@@ -763,6 +767,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
new_driver->drvwrap.driver.probe = usb_probe_interface;
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
+ new_driver->drvwrap.driver.mod_name = mod_name;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index c505b767cee..5e628ae3aec 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -268,6 +268,7 @@ static void ep_device_release(struct device *dev)
struct ep_device *ep_dev = to_ep_device(dev);
dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
+ endpoint_free_minor(ep_dev);
kfree(ep_dev);
}
@@ -349,7 +350,6 @@ void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
sysfs_remove_link(&ep_dev->dev.parent->kobj, name);
sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
- endpoint_free_minor(ep_dev);
device_unregister(&ep_dev->dev);
endpoint->ep_dev = NULL;
destroy_endpoint_class();
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index f794f07cfb3..01c857ac27a 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -194,14 +194,13 @@ int usb_register_dev(struct usb_interface *intf,
++temp;
else
temp = name;
- intf->class_dev = class_device_create(usb_class->class, NULL,
- MKDEV(USB_MAJOR, minor),
- &intf->dev, "%s", temp);
- if (IS_ERR(intf->class_dev)) {
+ intf->usb_dev = device_create(usb_class->class, &intf->dev,
+ MKDEV(USB_MAJOR, minor), "%s", temp);
+ if (IS_ERR(intf->usb_dev)) {
spin_lock (&minor_lock);
usb_minors[intf->minor] = NULL;
spin_unlock (&minor_lock);
- retval = PTR_ERR(intf->class_dev);
+ retval = PTR_ERR(intf->usb_dev);
}
exit:
return retval;
@@ -242,8 +241,8 @@ void usb_deregister_dev(struct usb_interface *intf,
spin_unlock (&minor_lock);
snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
- class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
- intf->class_dev = NULL;
+ device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+ intf->usb_dev = NULL;
intf->minor = -1;
destroy_usb_class();
}
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index ebb20ff7ac5..b531a4fd30c 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -25,6 +25,20 @@ static inline const char *plural(int n)
return (n == 1 ? "" : "s");
}
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_COMM
+ && desc->bInterfaceSubClass == 2
+ && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_MISC
+ && desc->bInterfaceSubClass == 1
+ && desc->bInterfaceProtocol == 1;
+}
+
static int choose_configuration(struct usb_device *udev)
{
int i;
@@ -87,14 +101,12 @@ static int choose_configuration(struct usb_device *udev)
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
+ /* When the first config's first interface is one of Microsoft's
+ * pet nonstandard Ethernet-over-USB protocols, ignore it unless
+ * this kernel has enabled the necessary host side driver.
+ */
+ if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
+#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
continue;
#else
best = c;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 10064af65d1..b26c19e8d19 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -45,8 +45,6 @@
#include "hub.h"
-// #define USB_BANDWIDTH_MESSAGES
-
/*-------------------------------------------------------------------------*/
/*
@@ -891,136 +889,6 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
}
EXPORT_SYMBOL (usb_calc_bus_time);
-/*
- * usb_check_bandwidth():
- *
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;
- * bustime is from calc_bus_time(), but converted to microseconds.
- *
- * returns <bustime in us> if successful,
- * or -ENOSPC if bandwidth request fails.
- *
- * FIXME:
- * This initial implementation does not use Endpoint.bInterval
- * in managing bandwidth allocation.
- * It probably needs to be expanded to use Endpoint.bInterval.
- * This can be done as a later enhancement (correction).
- *
- * This will also probably require some kind of
- * frame allocation tracking...meaning, for example,
- * that if multiple drivers request interrupts every 10 USB frames,
- * they don't all have to be allocated at
- * frame numbers N, N+10, N+20, etc. Some of them could be at
- * N+11, N+21, N+31, etc., and others at
- * N+12, N+22, N+32, etc.
- *
- * Similarly for isochronous transfers...
- *
- * Individual HCDs can schedule more directly ... this logic
- * is not correct for high speed transfers.
- */
-int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
-{
- unsigned int pipe = urb->pipe;
- long bustime;
- int is_in = usb_pipein (pipe);
- int is_iso = usb_pipeisoc (pipe);
- int old_alloc = dev->bus->bandwidth_allocated;
- int new_alloc;
-
-
- bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
- usb_maxpacket (dev, pipe, !is_in)));
- if (is_iso)
- bustime /= urb->number_of_packets;
-
- new_alloc = old_alloc + (int) bustime;
- if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
-#ifdef DEBUG
- char *mode =
-#ifdef CONFIG_USB_BANDWIDTH
- "";
-#else
- "would have ";
-#endif
- dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",
- mode, old_alloc, bustime, new_alloc);
-#endif
-#ifdef CONFIG_USB_BANDWIDTH
- bustime = -ENOSPC; /* report error */
-#endif
- }
-
- return bustime;
-}
-EXPORT_SYMBOL (usb_check_bandwidth);
-
-
-/**
- * usb_claim_bandwidth - records bandwidth for a periodic transfer
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @bustime: bandwidth consumed, in (average) microseconds per frame
- * @isoc: true iff the request is isochronous
- *
- * Bus bandwidth reservations are recorded purely for diagnostic purposes.
- * HCDs are expected not to overcommit periodic bandwidth, and to record such
- * reservations whenever endpoints are added to the periodic schedule.
- *
- * FIXME averaging per-frame is suboptimal. Better to sum over the HCD's
- * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
- * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
- * large its periodic schedule is.
- */
-void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
-{
- dev->bus->bandwidth_allocated += bustime;
- if (isoc)
- dev->bus->bandwidth_isoc_reqs++;
- else
- dev->bus->bandwidth_int_reqs++;
- urb->bandwidth = bustime;
-
-#ifdef USB_BANDWIDTH_MESSAGES
- dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",
- bustime,
- isoc ? "ISOC" : "INTR",
- dev->bus->bandwidth_allocated,
- dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-}
-EXPORT_SYMBOL (usb_claim_bandwidth);
-
-
-/**
- * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @isoc: true iff the request is isochronous
- *
- * This records that previously allocated bandwidth has been released.
- * Bandwidth is released when endpoints are removed from the host controller's
- * periodic schedule.
- */
-void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
-{
- dev->bus->bandwidth_allocated -= urb->bandwidth;
- if (isoc)
- dev->bus->bandwidth_isoc_reqs--;
- else
- dev->bus->bandwidth_int_reqs--;
-
-#ifdef USB_BANDWIDTH_MESSAGES
- dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",
- urb->bandwidth,
- isoc ? "ISOC" : "INTR",
- dev->bus->bandwidth_allocated,
- dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
- urb->bandwidth = 0;
-}
-EXPORT_SYMBOL (usb_release_bandwidth);
-
/*-------------------------------------------------------------------------*/
@@ -1034,11 +902,6 @@ static void urb_unlink (struct urb *urb)
{
unsigned long flags;
- /* Release any periodic transfer bandwidth */
- if (urb->bandwidth)
- usb_release_bandwidth (urb->dev, urb,
- usb_pipeisoc (urb->pipe));
-
/* clear all state linking urb to this dev (and hcd) */
spin_lock_irqsave (&hcd_data_lock, flags);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 8f8df0d4382..2a269ca2051 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -308,10 +308,6 @@ extern void usb_destroy_configuration(struct usb_device *dev);
#define NS_TO_US(ns) ((ns + 500L) / 1000L)
/* convert & round nanoseconds to microseconds */
-extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
- int bustime, int isoc);
-extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
- int isoc);
/*
* Full/low speed bandwidth allocation constants/support.
@@ -324,8 +320,6 @@ extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L)
#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L)
-extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
-
/*
* Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
* ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 2651c2e2a89..590ec82d051 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -87,16 +87,6 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
static struct task_struct *khubd_task;
-/* multithreaded probe logic */
-static int multithread_probe =
-#ifdef CONFIG_USB_MULTITHREAD_PROBE
- 1;
-#else
- 0;
-#endif
-module_param(multithread_probe, bool, S_IRUGO);
-MODULE_PARM_DESC(multithread_probe, "Run each USB device probe in a new thread");
-
/* cycle leds on hubs that aren't blinking for attention */
static int blinkenlights = 0;
module_param (blinkenlights, bool, S_IRUGO);
@@ -1263,9 +1253,28 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
static int __usb_port_suspend(struct usb_device *, int port1);
#endif
-static int __usb_new_device(void *void_data)
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured. The device descriptor is available, but not descriptors
+ * for any device configuration. The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not. Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
{
- struct usb_device *udev = void_data;
int err;
/* Lock ourself into memory in order to keep a probe sequence
@@ -1382,44 +1391,6 @@ fail:
goto exit;
}
-/**
- * usb_new_device - perform initial device setup (usbcore-internal)
- * @udev: newly addressed device (in ADDRESS state)
- *
- * This is called with devices which have been enumerated, but not yet
- * configured. The device descriptor is available, but not descriptors
- * for any device configuration. The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * The return value for this function depends on if the
- * multithread_probe variable is set or not. If it's set, it will
- * return a if the probe thread was successfully created or not. If the
- * variable is not set, it will return if the device is configured
- * properly or not. interfaces, in sysfs); else a negative errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
- */
-int usb_new_device(struct usb_device *udev)
-{
- struct task_struct *probe_task;
- int ret = 0;
-
- if (multithread_probe) {
- probe_task = kthread_run(__usb_new_device, udev,
- "usb-probe-%s", udev->devnum);
- if (IS_ERR(probe_task))
- ret = PTR_ERR(probe_task);
- } else
- ret = __usb_new_device(udev);
-
- return ret;
-}
-
static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change)
{
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index b5d6a79af0b..11dad22da41 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -379,7 +379,7 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
{
loff_t retval = -EINVAL;
- mutex_lock(&file->f_dentry->d_inode->i_mutex);
+ mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
switch(orig) {
case 0:
if (offset > 0) {
@@ -396,7 +396,7 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
default:
break;
}
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return retval;
}
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 149aa8bfb1f..8aca3574c2b 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1545,11 +1545,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
INIT_WORK(&req->work, driver_set_config_work);
usb_get_dev(udev);
- if (!schedule_work(&req->work)) {
- usb_put_dev(udev);
- kfree(req);
- return -EINVAL;
- }
+ schedule_work(&req->work);
return 0;
}
EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 55d8f575206..4eaa0ee8e72 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -16,16 +16,16 @@
/* Active configuration fields */
#define usb_actconfig_show(field, multiplier, format_string) \
-static ssize_t show_##field (struct device *dev, \
+static ssize_t show_##field(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_device *udev; \
struct usb_host_config *actconfig; \
\
- udev = to_usb_device (dev); \
+ udev = to_usb_device(dev); \
actconfig = udev->actconfig; \
if (actconfig) \
- return sprintf (buf, format_string, \
+ return sprintf(buf, format_string, \
actconfig->desc.field * multiplier); \
else \
return 0; \
@@ -35,9 +35,9 @@ static ssize_t show_##field (struct device *dev, \
usb_actconfig_show(field, multiplier, format_string) \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
-usb_actconfig_attr (bmAttributes, 1, "%2x\n")
-usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
+usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
+usb_actconfig_attr(bmAttributes, 1, "%2x\n")
+usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
static ssize_t show_configuration_string(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -45,7 +45,7 @@ static ssize_t show_configuration_string(struct device *dev,
struct usb_device *udev;
struct usb_host_config *actconfig;
- udev = to_usb_device (dev);
+ udev = to_usb_device(dev);
actconfig = udev->actconfig;
if ((!actconfig) || (!actconfig->string))
return 0;
@@ -57,16 +57,16 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
usb_actconfig_show(bConfigurationValue, 1, "%u\n");
static ssize_t
-set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
+set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct usb_device *udev = to_usb_device (dev);
+ struct usb_device *udev = to_usb_device(dev);
int config, value;
- if (sscanf (buf, "%u", &config) != 1 || config > 255)
+ if (sscanf(buf, "%u", &config) != 1 || config > 255)
return -EINVAL;
usb_lock_device(udev);
- value = usb_set_configuration (udev, config);
+ value = usb_set_configuration(udev, config);
usb_unlock_device(udev);
return (value < 0) ? value : count;
}
@@ -81,7 +81,7 @@ static ssize_t show_##name(struct device *dev, \
{ \
struct usb_device *udev; \
\
- udev = to_usb_device (dev); \
+ udev = to_usb_device(dev); \
return sprintf(buf, "%s\n", udev->name); \
} \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
@@ -91,12 +91,12 @@ usb_string_attr(manufacturer);
usb_string_attr(serial);
static ssize_t
-show_speed (struct device *dev, struct device_attribute *attr, char *buf)
+show_speed(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
char *speed;
- udev = to_usb_device (dev);
+ udev = to_usb_device(dev);
switch (udev->speed) {
case USB_SPEED_LOW:
@@ -112,22 +112,22 @@ show_speed (struct device *dev, struct device_attribute *attr, char *buf)
default:
speed = "unknown";
}
- return sprintf (buf, "%s\n", speed);
+ return sprintf(buf, "%s\n", speed);
}
static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
static ssize_t
-show_devnum (struct device *dev, struct device_attribute *attr, char *buf)
+show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
- udev = to_usb_device (dev);
- return sprintf (buf, "%d\n", udev->devnum);
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->devnum);
}
static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
static ssize_t
-show_version (struct device *dev, struct device_attribute *attr, char *buf)
+show_version(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
u16 bcdUSB;
@@ -139,25 +139,25 @@ show_version (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
static ssize_t
-show_maxchild (struct device *dev, struct device_attribute *attr, char *buf)
+show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
- udev = to_usb_device (dev);
- return sprintf (buf, "%d\n", udev->maxchild);
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->maxchild);
}
static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
/* Descriptor fields */
#define usb_descriptor_attr_le16(field, format_string) \
static ssize_t \
-show_##field (struct device *dev, struct device_attribute *attr, \
+show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_device *udev; \
\
- udev = to_usb_device (dev); \
- return sprintf (buf, format_string, \
+ udev = to_usb_device(dev); \
+ return sprintf(buf, format_string, \
le16_to_cpu(udev->descriptor.field)); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
@@ -168,21 +168,21 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n")
#define usb_descriptor_attr(field, format_string) \
static ssize_t \
-show_##field (struct device *dev, struct device_attribute *attr, \
+show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_device *udev; \
\
- udev = to_usb_device (dev); \
- return sprintf (buf, format_string, udev->descriptor.field); \
+ udev = to_usb_device(dev); \
+ return sprintf(buf, format_string, udev->descriptor.field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-usb_descriptor_attr (bDeviceClass, "%02x\n")
-usb_descriptor_attr (bDeviceSubClass, "%02x\n")
-usb_descriptor_attr (bDeviceProtocol, "%02x\n")
-usb_descriptor_attr (bNumConfigurations, "%d\n")
-usb_descriptor_attr (bMaxPacketSize0, "%d\n")
+usb_descriptor_attr(bDeviceClass, "%02x\n")
+usb_descriptor_attr(bDeviceSubClass, "%02x\n")
+usb_descriptor_attr(bDeviceProtocol, "%02x\n")
+usb_descriptor_attr(bNumConfigurations, "%d\n")
+usb_descriptor_attr(bMaxPacketSize0, "%d\n")
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
@@ -220,17 +220,17 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
return retval;
if (udev->manufacturer) {
- retval = device_create_file (dev, &dev_attr_manufacturer);
+ retval = device_create_file(dev, &dev_attr_manufacturer);
if (retval)
goto error;
}
if (udev->product) {
- retval = device_create_file (dev, &dev_attr_product);
+ retval = device_create_file(dev, &dev_attr_product);
if (retval)
goto error;
}
if (udev->serial) {
- retval = device_create_file (dev, &dev_attr_serial);
+ retval = device_create_file(dev, &dev_attr_serial);
if (retval)
goto error;
}
@@ -246,7 +246,7 @@ error:
return retval;
}
-void usb_remove_sysfs_dev_files (struct usb_device *udev)
+void usb_remove_sysfs_dev_files(struct usb_device *udev)
{
struct device *dev = &udev->dev;
@@ -264,22 +264,22 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
/* Interface fields */
#define usb_intf_attr(field, format_string) \
static ssize_t \
-show_##field (struct device *dev, struct device_attribute *attr, \
+show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface (dev); \
+ struct usb_interface *intf = to_usb_interface(dev); \
\
- return sprintf (buf, format_string, \
+ return sprintf(buf, format_string, \
intf->cur_altsetting->desc.field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-usb_intf_attr (bInterfaceNumber, "%02x\n")
-usb_intf_attr (bAlternateSetting, "%2d\n")
-usb_intf_attr (bNumEndpoints, "%02x\n")
-usb_intf_attr (bInterfaceClass, "%02x\n")
-usb_intf_attr (bInterfaceSubClass, "%02x\n")
-usb_intf_attr (bInterfaceProtocol, "%02x\n")
+usb_intf_attr(bInterfaceNumber, "%02x\n")
+usb_intf_attr(bAlternateSetting, "%2d\n")
+usb_intf_attr(bNumEndpoints, "%02x\n")
+usb_intf_attr(bInterfaceClass, "%02x\n")
+usb_intf_attr(bInterfaceSubClass, "%02x\n")
+usb_intf_attr(bInterfaceProtocol, "%02x\n")
static ssize_t show_interface_string(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -288,8 +288,8 @@ static ssize_t show_interface_string(struct device *dev,
struct usb_device *udev;
int len;
- intf = to_usb_interface (dev);
- udev = interface_to_usbdev (intf);
+ intf = to_usb_interface(dev);
+ udev = interface_to_usbdev(intf);
len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
if (len < 0)
return 0;
@@ -384,7 +384,7 @@ error:
return retval;
}
-void usb_remove_sysfs_intf_files (struct usb_interface *intf)
+void usb_remove_sysfs_intf_files(struct usb_interface *intf)
{
usb_remove_intf_ep_files(intf);
sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 9801d08edac..94ea9727ff5 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -235,16 +235,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->status = -EINPROGRESS;
urb->actual_length = 0;
- urb->bandwidth = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
pipe = urb->pipe;
- temp = usb_pipetype (pipe);
- is_out = usb_pipeout (pipe);
+ temp = usb_pipetype(pipe);
+ is_out = usb_pipeout(pipe);
- if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)
+ if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
/* FIXME there should be a sharable lock protecting us against
@@ -253,11 +252,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* checks get made.)
*/
- max = usb_maxpacket (dev, pipe, is_out);
+ max = usb_maxpacket(dev, pipe, is_out);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
- usb_pipeendpoint (pipe), is_out ? "out" : "in",
+ usb_pipeendpoint(pipe), is_out ? "out" : "in",
__FUNCTION__, max);
return -EMSGSIZE;
}
@@ -279,11 +278,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (urb->number_of_packets <= 0)
return -EINVAL;
for (n = 0; n < urb->number_of_packets; n++) {
- len = urb->iso_frame_desc [n].length;
+ len = urb->iso_frame_desc[n].length;
if (len < 0 || len > max)
return -EMSGSIZE;
- urb->iso_frame_desc [n].status = -EXDEV;
- urb->iso_frame_desc [n].actual_length = 0;
+ urb->iso_frame_desc[n].status = -EXDEV;
+ urb->iso_frame_desc[n].actual_length = 0;
}
}
@@ -322,7 +321,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* fail if submitter gave bogus flags */
if (urb->transfer_flags != orig_flags) {
- err ("BOGUS urb flags, %x --> %x",
+ err("BOGUS urb flags, %x --> %x",
orig_flags, urb->transfer_flags);
return -EINVAL;
}
@@ -373,7 +372,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->interval = temp;
}
- return usb_hcd_submit_urb (urb, mem_flags);
+ return usb_hcd_submit_urb(urb, mem_flags);
}
/*-------------------------------------------------------------------*/
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 02426d0b9a3..3db721cd557 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -233,7 +233,7 @@ static void usb_autosuspend_work(struct work_struct *work)
* @parent: hub to which device is connected; null to allocate a root hub
* @bus: bus used to access the device
* @port1: one-based index of port; ignored for root hubs
- * Context: !in_interrupt ()
+ * Context: !in_interrupt()
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
@@ -277,22 +277,22 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
* as stable: bus->busnum changes easily from modprobe order,
* cardbus or pci hotplugging, and so on.
*/
- if (unlikely (!parent)) {
- dev->devpath [0] = '0';
+ if (unlikely(!parent)) {
+ dev->devpath[0] = '0';
dev->dev.parent = bus->controller;
- sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum);
+ sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
} else {
/* match any labeling on the hubs; it's one-based */
- if (parent->devpath [0] == '0')
- snprintf (dev->devpath, sizeof dev->devpath,
+ if (parent->devpath[0] == '0')
+ snprintf(dev->devpath, sizeof dev->devpath,
"%d", port1);
else
- snprintf (dev->devpath, sizeof dev->devpath,
+ snprintf(dev->devpath, sizeof dev->devpath,
"%s.%d", parent->devpath, port1);
dev->dev.parent = &parent->dev;
- sprintf (&dev->dev.bus_id[0], "%d-%s",
+ sprintf(&dev->dev.bus_id[0], "%d-%s",
bus->busnum, dev->devpath);
/* hub driver sets up TT records */
@@ -463,7 +463,7 @@ static struct usb_device *match_device(struct usb_device *dev,
/* see if this device matches */
if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
(product_id == le16_to_cpu(dev->descriptor.idProduct))) {
- dev_dbg (&dev->dev, "matched this device!\n");
+ dev_dbg(&dev->dev, "matched this device!\n");
ret_dev = usb_get_dev(dev);
goto exit;
}
@@ -535,7 +535,7 @@ exit:
*/
int usb_get_current_frame_number(struct usb_device *dev)
{
- return usb_hcd_get_frame_number (dev);
+ return usb_hcd_get_frame_number(dev);
}
/*-------------------------------------------------------------------*/
@@ -593,7 +593,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
*
* When the buffer is no longer used, free it with usb_buffer_free().
*/
-void *usb_buffer_alloc (
+void *usb_buffer_alloc(
struct usb_device *dev,
size_t size,
gfp_t mem_flags,
@@ -602,7 +602,7 @@ void *usb_buffer_alloc (
{
if (!dev || !dev->bus)
return NULL;
- return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
+ return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
}
/**
@@ -616,7 +616,7 @@ void *usb_buffer_alloc (
* been allocated using usb_buffer_alloc(), and the parameters must match
* those provided in that allocation request.
*/
-void usb_buffer_free (
+void usb_buffer_free(
struct usb_device *dev,
size_t size,
void *addr,
@@ -627,7 +627,7 @@ void usb_buffer_free (
return;
if (!addr)
return;
- hcd_buffer_free (dev->bus, size, addr, dma);
+ hcd_buffer_free(dev->bus, size, addr, dma);
}
/**
@@ -647,7 +647,7 @@ void usb_buffer_free (
* Reverse the effect of this call with usb_buffer_unmap().
*/
#if 0
-struct urb *usb_buffer_map (struct urb *urb)
+struct urb *usb_buffer_map(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@@ -659,14 +659,14 @@ struct urb *usb_buffer_map (struct urb *urb)
return NULL;
if (controller->dma_mask) {
- urb->transfer_dma = dma_map_single (controller,
+ urb->transfer_dma = dma_map_single(controller,
urb->transfer_buffer, urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (usb_pipecontrol (urb->pipe))
- urb->setup_dma = dma_map_single (controller,
+ if (usb_pipecontrol(urb->pipe))
+ urb->setup_dma = dma_map_single(controller,
urb->setup_packet,
- sizeof (struct usb_ctrlrequest),
+ sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
@@ -689,7 +689,7 @@ struct urb *usb_buffer_map (struct urb *urb)
* usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
* @urb: urb whose transfer_buffer/setup_packet will be synchronized
*/
-void usb_buffer_dmasync (struct urb *urb)
+void usb_buffer_dmasync(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@@ -702,14 +702,14 @@ void usb_buffer_dmasync (struct urb *urb)
return;
if (controller->dma_mask) {
- dma_sync_single (controller,
+ dma_sync_single(controller,
urb->transfer_dma, urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (usb_pipecontrol (urb->pipe))
- dma_sync_single (controller,
+ if (usb_pipecontrol(urb->pipe))
+ dma_sync_single(controller,
urb->setup_dma,
- sizeof (struct usb_ctrlrequest),
+ sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
}
@@ -722,7 +722,7 @@ void usb_buffer_dmasync (struct urb *urb)
* Reverses the effect of usb_buffer_map().
*/
#if 0
-void usb_buffer_unmap (struct urb *urb)
+void usb_buffer_unmap(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@@ -735,14 +735,14 @@ void usb_buffer_unmap (struct urb *urb)
return;
if (controller->dma_mask) {
- dma_unmap_single (controller,
+ dma_unmap_single(controller,
urb->transfer_dma, urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (usb_pipecontrol (urb->pipe))
- dma_unmap_single (controller,
+ if (usb_pipecontrol(urb->pipe))
+ dma_unmap_single(controller,
urb->setup_dma,
- sizeof (struct usb_ctrlrequest),
+ sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
@@ -783,15 +783,15 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
struct device *controller;
if (!dev
- || usb_pipecontrol (pipe)
+ || usb_pipecontrol(pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return -1;
// FIXME generic api broken like pci, can't report errors
- return dma_map_sg (controller, sg, nents,
- usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ return dma_map_sg(controller, sg, nents,
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* XXX DISABLED, no users currently. If you wish to re-enable this
@@ -823,8 +823,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
|| !controller->dma_mask)
return;
- dma_sync_sg (controller, sg, n_hw_ents,
- usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ dma_sync_sg(controller, sg, n_hw_ents,
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
#endif
@@ -849,8 +849,8 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
|| !controller->dma_mask)
return;
- dma_unmap_sg (controller, sg, n_hw_ents,
- usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ dma_unmap_sg(controller, sg, n_hw_ents,
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* format to disable USB on kernel command line is: nousb */
@@ -871,7 +871,7 @@ static int __init usb_init(void)
{
int retval;
if (nousb) {
- pr_info ("%s: USB support disabled\n", usbcore_name);
+ pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
}
@@ -971,19 +971,19 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor);
EXPORT_SYMBOL(usb_find_device);
EXPORT_SYMBOL(usb_get_current_frame_number);
-EXPORT_SYMBOL (usb_buffer_alloc);
-EXPORT_SYMBOL (usb_buffer_free);
+EXPORT_SYMBOL(usb_buffer_alloc);
+EXPORT_SYMBOL(usb_buffer_free);
#if 0
-EXPORT_SYMBOL (usb_buffer_map);
-EXPORT_SYMBOL (usb_buffer_dmasync);
-EXPORT_SYMBOL (usb_buffer_unmap);
+EXPORT_SYMBOL(usb_buffer_map);
+EXPORT_SYMBOL(usb_buffer_dmasync);
+EXPORT_SYMBOL(usb_buffer_unmap);
#endif
-EXPORT_SYMBOL (usb_buffer_map_sg);
+EXPORT_SYMBOL(usb_buffer_map_sg);
#if 0
-EXPORT_SYMBOL (usb_buffer_dmasync_sg);
+EXPORT_SYMBOL(usb_buffer_dmasync_sg);
#endif
-EXPORT_SYMBOL (usb_buffer_unmap_sg);
+EXPORT_SYMBOL(usb_buffer_unmap_sg);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 72f3db99ff9..f39050145f1 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -39,18 +39,20 @@
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/clk.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>
+#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/mach-types.h>
-#include <asm/arch/hardware.h>
#include <asm/arch/gpio.h>
#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/at91sam9261_matrix.h>
#include "at91_udc.h"
@@ -78,27 +80,11 @@
static const char driver_name [] = "at91_udc";
static const char ep0name[] = "ep0";
-/*-------------------------------------------------------------------------*/
-
-/*
- * Read from a UDP register.
- */
-static inline unsigned long at91_udp_read(unsigned int reg)
-{
- void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
- return __raw_readl(udp_base + reg);
-}
-
-/*
- * Write to a UDP register.
- */
-static inline void at91_udp_write(unsigned int reg, unsigned long value)
-{
- void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
-
- __raw_writel(value, udp_base + reg);
-}
+#define at91_udp_read(dev, reg) \
+ __raw_readl((dev)->udp_baseaddr + (reg))
+#define at91_udp_write(dev, reg, val) \
+ __raw_writel((val), (dev)->udp_baseaddr + (reg))
/*-------------------------------------------------------------------------*/
@@ -210,13 +196,13 @@ static int proc_udc_show(struct seq_file *s, void *unused)
return 0;
}
- tmp = at91_udp_read(AT91_UDP_FRM_NUM);
+ tmp = at91_udp_read(udc, AT91_UDP_FRM_NUM);
seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp,
(tmp & AT91_UDP_FRM_OK) ? " ok" : "",
(tmp & AT91_UDP_FRM_ERR) ? " err" : "",
(tmp & AT91_UDP_NUM));
- tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp,
(tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "",
(tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "",
@@ -224,13 +210,13 @@ static int proc_udc_show(struct seq_file *s, void *unused)
(tmp & AT91_UDP_CONFG) ? " confg" : "",
(tmp & AT91_UDP_FADDEN) ? " fadden" : "");
- tmp = at91_udp_read(AT91_UDP_FADDR);
+ tmp = at91_udp_read(udc, AT91_UDP_FADDR);
seq_printf(s, "faddr %03x:%s fadd=%d\n", tmp,
(tmp & AT91_UDP_FEN) ? " fen" : "",
(tmp & AT91_UDP_FADD));
- proc_irq_show(s, "imr ", at91_udp_read(AT91_UDP_IMR));
- proc_irq_show(s, "isr ", at91_udp_read(AT91_UDP_ISR));
+ proc_irq_show(s, "imr ", at91_udp_read(udc, AT91_UDP_IMR));
+ proc_irq_show(s, "isr ", at91_udp_read(udc, AT91_UDP_ISR));
if (udc->enabled && udc->vbus) {
proc_ep_show(s, &udc->ep[0]);
@@ -286,6 +272,7 @@ static inline void remove_debug_file(struct at91_udc *udc) {}
static void done(struct at91_ep *ep, struct at91_request *req, int status)
{
unsigned stopped = ep->stopped;
+ struct at91_udc *udc = ep->udc;
list_del_init(&req->queue);
if (req->req.status == -EINPROGRESS)
@@ -301,7 +288,7 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status)
/* ep0 is always ready; other endpoints need a non-empty queue */
if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
- at91_udp_write(AT91_UDP_IDR, ep->int_mask);
+ at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask);
}
/*-------------------------------------------------------------------------*/
@@ -554,8 +541,8 @@ ok:
* reset/init endpoint fifo. NOTE: leaves fifo_bank alone,
* since endpoint resets don't reset hw pingpong state.
*/
- at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
- at91_udp_write(AT91_UDP_RST_EP, 0);
+ at91_udp_write(dev, AT91_UDP_RST_EP, ep->int_mask);
+ at91_udp_write(dev, AT91_UDP_RST_EP, 0);
local_irq_restore(flags);
return 0;
@@ -564,6 +551,7 @@ ok:
static int at91_ep_disable (struct usb_ep * _ep)
{
struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
+ struct at91_udc *udc = ep->udc;
unsigned long flags;
if (ep == &ep->udc->ep[0])
@@ -579,8 +567,8 @@ static int at91_ep_disable (struct usb_ep * _ep)
/* reset fifos and endpoint */
if (ep->udc->clocked) {
- at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
- at91_udp_write(AT91_UDP_RST_EP, 0);
+ at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+ at91_udp_write(udc, AT91_UDP_RST_EP, 0);
__raw_writel(0, ep->creg);
}
@@ -598,7 +586,7 @@ at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags)
{
struct at91_request *req;
- req = kcalloc(1, sizeof (struct at91_request), gfp_flags);
+ req = kzalloc(sizeof (struct at91_request), gfp_flags);
if (!req)
return NULL;
@@ -695,10 +683,10 @@ static int at91_ep_queue(struct usb_ep *_ep,
* reconfigures the endpoints.
*/
if (dev->wait_for_config_ack) {
- tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+ tmp = at91_udp_read(dev, AT91_UDP_GLB_STAT);
tmp ^= AT91_UDP_CONFG;
VDBG("toggle config\n");
- at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+ at91_udp_write(dev, AT91_UDP_GLB_STAT, tmp);
}
if (req->req.length == 0) {
ep0_in_status:
@@ -727,7 +715,7 @@ ep0_in_status:
if (req && !status) {
list_add_tail (&req->queue, &ep->queue);
- at91_udp_write(AT91_UDP_IER, ep->int_mask);
+ at91_udp_write(dev, AT91_UDP_IER, ep->int_mask);
}
done:
local_irq_restore(flags);
@@ -758,6 +746,7 @@ static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
static int at91_ep_set_halt(struct usb_ep *_ep, int value)
{
struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
+ struct at91_udc *udc = ep->udc;
u32 __iomem *creg;
u32 csr;
unsigned long flags;
@@ -785,8 +774,8 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value)
csr |= AT91_UDP_FORCESTALL;
VDBG("halt %s\n", ep->ep.name);
} else {
- at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
- at91_udp_write(AT91_UDP_RST_EP, 0);
+ at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+ at91_udp_write(udc, AT91_UDP_RST_EP, 0);
csr &= ~AT91_UDP_FORCESTALL;
}
__raw_writel(csr, creg);
@@ -813,9 +802,11 @@ static struct usb_ep_ops at91_ep_ops = {
static int at91_get_frame(struct usb_gadget *gadget)
{
+ struct at91_udc *udc = to_udc(gadget);
+
if (!to_udc(gadget)->clocked)
return -EINVAL;
- return at91_udp_read(AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
+ return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
}
static int at91_wakeup(struct usb_gadget *gadget)
@@ -833,11 +824,11 @@ static int at91_wakeup(struct usb_gadget *gadget)
/* NOTE: some "early versions" handle ESR differently ... */
- glbstate = at91_udp_read(AT91_UDP_GLB_STAT);
+ glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT);
if (!(glbstate & AT91_UDP_ESR))
goto done;
glbstate |= AT91_UDP_ESR;
- at91_udp_write(AT91_UDP_GLB_STAT, glbstate);
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate);
done:
local_irq_restore(flags);
@@ -861,6 +852,7 @@ static void udc_reinit(struct at91_udc *udc)
ep->stopped = 0;
ep->fifo_bank = 0;
ep->ep.maxpacket = ep->maxpacket;
+ ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
// initialiser une queue par endpoint
INIT_LIST_HEAD(&ep->queue);
}
@@ -915,14 +907,41 @@ static void pullup(struct at91_udc *udc, int is_on)
if (!udc->enabled || !udc->vbus)
is_on = 0;
DBG("%sactive\n", is_on ? "" : "in");
+
if (is_on) {
clk_on(udc);
- at91_udp_write(AT91_UDP_TXVC, 0);
- at91_set_gpio_value(udc->board.pullup_pin, 1);
- } else {
+ at91_udp_write(udc, AT91_UDP_TXVC, 0);
+ if (cpu_is_at91rm9200())
+ at91_set_gpio_value(udc->board.pullup_pin, 1);
+ else if (cpu_is_at91sam9260()) {
+ u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+
+ txvc |= AT91_UDP_TXVC_PUON;
+ at91_udp_write(udc, AT91_UDP_TXVC, txvc);
+ } else if (cpu_is_at91sam9261()) {
+ u32 usbpucr;
+
+ usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
+ usbpucr |= AT91_MATRIX_USBPUCR_PUON;
+ at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
+ }
+ } else {
stop_activity(udc);
- at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
- at91_set_gpio_value(udc->board.pullup_pin, 0);
+ at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+ if (cpu_is_at91rm9200())
+ at91_set_gpio_value(udc->board.pullup_pin, 0);
+ else if (cpu_is_at91sam9260()) {
+ u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+
+ txvc &= ~AT91_UDP_TXVC_PUON;
+ at91_udp_write(udc, AT91_UDP_TXVC, txvc);
+ } else if (cpu_is_at91sam9261()) {
+ u32 usbpucr;
+
+ usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
+ usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
+ at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
+ }
clk_off(udc);
}
}
@@ -936,7 +955,10 @@ static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
// VDBG("vbus %s\n", is_active ? "on" : "off");
local_irq_save(flags);
udc->vbus = (is_active != 0);
- pullup(udc, is_active);
+ if (udc->driver)
+ pullup(udc, is_active);
+ else
+ pullup(udc, 0);
local_irq_restore(flags);
return 0;
}
@@ -1086,7 +1108,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
| USB_REQ_SET_CONFIGURATION:
- tmp = at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
if (pkt.r.wValue)
udc->wait_for_config_ack = (tmp == 0);
else
@@ -1103,7 +1125,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
| USB_REQ_GET_STATUS:
tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
- if (at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
+ if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
PACKET("get device status\n");
__raw_writeb(tmp, dreg);
@@ -1114,17 +1136,17 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
| USB_REQ_SET_FEATURE:
if (w_value != USB_DEVICE_REMOTE_WAKEUP)
goto stall;
- tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
tmp |= AT91_UDP_ESR;
- at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
goto succeed;
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
| USB_REQ_CLEAR_FEATURE:
if (w_value != USB_DEVICE_REMOTE_WAKEUP)
goto stall;
- tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
tmp &= ~AT91_UDP_ESR;
- at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
goto succeed;
/*
@@ -1206,8 +1228,8 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
} else if (ep->is_in)
goto stall;
- at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
- at91_udp_write(AT91_UDP_RST_EP, 0);
+ at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+ at91_udp_write(udc, AT91_UDP_RST_EP, 0);
tmp = __raw_readl(ep->creg);
tmp |= CLR_FX;
tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
@@ -1222,7 +1244,10 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
#undef w_length
/* pass request up to the gadget driver */
- status = udc->driver->setup(&udc->gadget, &pkt.r);
+ if (udc->driver)
+ status = udc->driver->setup(&udc->gadget, &pkt.r);
+ else
+ status = -ENODEV;
if (status < 0) {
stall:
VDBG("req %02x.%02x protocol STALL; stat %d\n",
@@ -1300,13 +1325,13 @@ static void handle_ep0(struct at91_udc *udc)
if (udc->wait_for_addr_ack) {
u32 tmp;
- at91_udp_write(AT91_UDP_FADDR,
+ at91_udp_write(udc, AT91_UDP_FADDR,
AT91_UDP_FEN | udc->addr);
- tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
tmp &= ~AT91_UDP_FADDEN;
if (udc->addr)
tmp |= AT91_UDP_FADDEN;
- at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
udc->wait_for_addr_ack = 0;
VDBG("address %d\n", udc->addr);
@@ -1374,28 +1399,28 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
while (rescans--) {
u32 status;
- status = at91_udp_read(AT91_UDP_ISR)
- & at91_udp_read(AT91_UDP_IMR);
+ status = at91_udp_read(udc, AT91_UDP_ISR)
+ & at91_udp_read(udc, AT91_UDP_IMR);
if (!status)
break;
/* USB reset irq: not maskable */
if (status & AT91_UDP_ENDBUSRES) {
- at91_udp_write(AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
- at91_udp_write(AT91_UDP_IER, MINIMUS_INTERRUPTUS);
+ at91_udp_write(udc, AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
+ at91_udp_write(udc, AT91_UDP_IER, MINIMUS_INTERRUPTUS);
/* Atmel code clears this irq twice */
- at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
- at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
VDBG("end bus reset\n");
udc->addr = 0;
stop_activity(udc);
/* enable ep0 */
- at91_udp_write(AT91_UDP_CSR(0),
+ at91_udp_write(udc, AT91_UDP_CSR(0),
AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
udc->gadget.speed = USB_SPEED_FULL;
udc->suspended = 0;
- at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0));
+ at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_EP(0));
/*
* NOTE: this driver keeps clocks off unless the
@@ -1406,9 +1431,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
/* host initiated suspend (3+ms bus idle) */
} else if (status & AT91_UDP_RXSUSP) {
- at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXSUSP);
- at91_udp_write(AT91_UDP_IER, AT91_UDP_RXRSM);
- at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXSUSP);
+ at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP);
+ at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM);
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP);
// VDBG("bus suspend\n");
if (udc->suspended)
continue;
@@ -1425,9 +1450,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
/* host initiated resume */
} else if (status & AT91_UDP_RXRSM) {
- at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXRSM);
- at91_udp_write(AT91_UDP_IER, AT91_UDP_RXSUSP);
- at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXRSM);
+ at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
+ at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP);
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
// VDBG("bus resume\n");
if (!udc->suspended)
continue;
@@ -1485,8 +1510,6 @@ static struct at91_udc controller = {
},
.udc = &controller,
.maxpacket = 8,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
- + AT91_UDP_CSR(0)),
.int_mask = 1 << 0,
},
.ep[1] = {
@@ -1497,8 +1520,6 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 64,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
- + AT91_UDP_CSR(1)),
.int_mask = 1 << 1,
},
.ep[2] = {
@@ -1509,8 +1530,6 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 64,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
- + AT91_UDP_CSR(2)),
.int_mask = 1 << 2,
},
.ep[3] = {
@@ -1521,8 +1540,6 @@ static struct at91_udc controller = {
},
.udc = &controller,
.maxpacket = 8,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
- + AT91_UDP_CSR(3)),
.int_mask = 1 << 3,
},
.ep[4] = {
@@ -1533,8 +1550,6 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 256,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
- + AT91_UDP_CSR(4)),
.int_mask = 1 << 4,
},
.ep[5] = {
@@ -1545,8 +1560,6 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 256,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP
- + AT91_UDP_CSR(5)),
.int_mask = 1 << 5,
},
/* ep6 and ep7 are also reserved (custom silicon might use them) */
@@ -1572,9 +1585,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
int retval;
if (!driver
- || driver->speed != USB_SPEED_FULL
+ || driver->speed < USB_SPEED_FULL
|| !driver->bind
- || !driver->unbind
|| !driver->setup) {
DBG("bad parameter.\n");
return -EINVAL;
@@ -1595,6 +1607,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
if (retval) {
DBG("driver->bind() returned %d\n", retval);
udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ udc->gadget.dev.driver_data = NULL;
+ udc->enabled = 0;
+ udc->selfpowered = 0;
return retval;
}
@@ -1611,12 +1627,12 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
{
struct at91_udc *udc = &controller;
- if (!driver || driver != udc->driver)
+ if (!driver || driver != udc->driver || !driver->unbind)
return -EINVAL;
local_irq_disable();
udc->enabled = 0;
- at91_udp_write(AT91_UDP_IDR, ~0);
+ at91_udp_write(udc, AT91_UDP_IDR, ~0);
pullup(udc, 0);
local_irq_enable();
@@ -1641,6 +1657,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct at91_udc *udc;
int retval;
+ struct resource *res;
if (!dev->platform_data) {
/* small (so we copy it) but critical! */
@@ -1658,7 +1675,13 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
return -ENODEV;
}
- if (!request_mem_region(AT91RM9200_BASE_UDP, SZ_16K, driver_name)) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ if (!request_mem_region(res->start,
+ res->end - res->start + 1,
+ driver_name)) {
DBG("someone's using UDC memory\n");
return -EBUSY;
}
@@ -1668,15 +1691,23 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
udc->gadget.dev.parent = dev;
udc->board = *(struct at91_udc_data *) dev->platform_data;
udc->pdev = pdev;
- udc_reinit(udc);
udc->enabled = 0;
+ udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
+ if (!udc->udp_baseaddr) {
+ release_mem_region(res->start, res->end - res->start + 1);
+ return -ENOMEM;
+ }
+
+ udc_reinit(udc);
+
/* get interface and function clocks */
udc->iclk = clk_get(dev, "udc_clk");
udc->fclk = clk_get(dev, "udpck");
if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
DBG("clocks missing\n");
- return -ENODEV;
+ retval = -ENODEV;
+ goto fail0;
}
retval = device_register(&udc->gadget.dev);
@@ -1685,8 +1716,10 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
/* don't do anything until we have both gadget driver and VBUS */
clk_enable(udc->iclk);
- at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
- at91_udp_write(AT91_UDP_IDR, 0xffffffff);
+ at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+ at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
+ /* Clear all pending interrupts - UDP may be used by bootloader. */
+ at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff);
clk_disable(udc->iclk);
/* request UDC and maybe VBUS irqs */
@@ -1698,6 +1731,11 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
goto fail1;
}
if (udc->board.vbus_pin > 0) {
+ /*
+ * Get the initial state of VBUS - we cannot expect
+ * a pending interrupt.
+ */
+ udc->vbus = at91_get_gpio_value(udc->board.vbus_pin);
if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
IRQF_DISABLED, driver_name, udc)) {
DBG("request vbus irq %d failed\n",
@@ -1720,7 +1758,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
fail1:
device_unregister(&udc->gadget.dev);
fail0:
- release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
+ release_mem_region(res->start, res->end - res->start + 1);
DBG("%s probe failed, %d\n", driver_name, retval);
return retval;
}
@@ -1728,13 +1766,14 @@ fail0:
static int __devexit at91udc_remove(struct platform_device *pdev)
{
struct at91_udc *udc = platform_get_drvdata(pdev);
+ struct resource *res;
DBG("remove\n");
- pullup(udc, 0);
+ if (udc->driver)
+ return -EBUSY;
- if (udc->driver != 0)
- usb_gadget_unregister_driver(udc->driver);
+ pullup(udc, 0);
device_init_wakeup(&pdev->dev, 0);
remove_debug_file(udc);
@@ -1742,7 +1781,10 @@ 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(AT91RM9200_BASE_UDP, SZ_16K);
+
+ iounmap(udc->udp_baseaddr);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
clk_put(udc->iclk);
clk_put(udc->fclk);
@@ -1765,16 +1807,13 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
|| !wake
|| at91_suspend_entering_slow_clock()) {
pullup(udc, 0);
- disable_irq_wake(udc->udp_irq);
+ wake = 0;
} else
enable_irq_wake(udc->udp_irq);
- if (udc->board.vbus_pin > 0) {
- if (wake)
- enable_irq_wake(udc->board.vbus_pin);
- else
- disable_irq_wake(udc->board.vbus_pin);
- }
+ udc->active_suspend = wake;
+ if (udc->board.vbus_pin > 0 && wake)
+ enable_irq_wake(udc->board.vbus_pin);
return 0;
}
@@ -1782,8 +1821,14 @@ static int at91udc_resume(struct platform_device *pdev)
{
struct at91_udc *udc = platform_get_drvdata(pdev);
+ if (udc->board.vbus_pin > 0 && udc->active_suspend)
+ disable_irq_wake(udc->board.vbus_pin);
+
/* maybe reconnect to host; if so, clocks on */
- pullup(udc, 1);
+ if (udc->active_suspend)
+ disable_irq_wake(udc->udp_irq);
+ else
+ pullup(udc, 1);
return 0;
}
#else
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 882af42e86c..7e34e2f864f 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -51,10 +51,10 @@
#define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */
#define AT91_UDP_RXSUSP (1 << 8) /* USB Suspend Interrupt Status */
#define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */
-#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status */
+#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status [AT91RM9200 only] */
#define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */
#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt Status */
-#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status */
+#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status [AT91RM9200 only] */
#define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */
#define AT91_UDP_RST_EP 0x28 /* Reset Endpoint Register */
@@ -84,7 +84,7 @@
#define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */
#define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */
-
+#define AT91_UDP_TXVC_PUON (1 << 9) /* PullUp On [AT91SAM9260 only] */
/*-------------------------------------------------------------------------*/
@@ -136,11 +136,13 @@ struct at91_udc {
unsigned wait_for_addr_ack:1;
unsigned wait_for_config_ack:1;
unsigned selfpowered:1;
+ unsigned active_suspend:1;
u8 addr;
struct at91_udc_data board;
struct clk *iclk, *fclk;
struct platform_device *pdev;
struct proc_dir_entry *pde;
+ void __iomem *udp_baseaddr;
int udp_irq;
};
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 83b4866df9a..d18901b92cd 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -24,7 +24,7 @@
#include <linux/string.h>
#include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index f1f32d7be5f..3c2bc075ef4 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -779,7 +779,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
return -EINVAL;
if (dum->driver)
return -EBUSY;
- if (!driver->bind || !driver->unbind || !driver->setup
+ if (!driver->bind || !driver->setup
|| driver->speed == USB_SPEED_UNKNOWN)
return -EINVAL;
@@ -837,7 +837,8 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
err_bind_driver:
driver_unregister (&driver->driver);
err_register:
- driver->unbind (&dum->gadget);
+ if (driver->unbind)
+ driver->unbind (&dum->gadget);
spin_lock_irq (&dum->lock);
dum->pullup = 0;
set_link_state (dum);
@@ -857,7 +858,7 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
if (!dum)
return -ENODEV;
- if (!driver || driver != dum->driver)
+ if (!driver || driver != dum->driver || !driver->unbind)
return -EINVAL;
dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 53d584589c2..f28af06905a 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -27,7 +27,7 @@
#include <linux/ctype.h>
#include <linux/string.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index d15bf22b9a0..22e3c944364 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -47,7 +47,7 @@
#include <asm/uaccess.h>
#include <asm/unaligned.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
#include <linux/usb_gadget.h>
@@ -72,9 +72,18 @@
*
* There's some hardware that can't talk CDC. We make that hardware
* implement a "minimalist" vendor-agnostic CDC core: same framing, but
- * link-level setup only requires activating the configuration.
- * Linux supports it, but other host operating systems may not.
- * (This is a subset of CDC Ethernet.)
+ * link-level setup only requires activating the configuration. Only the
+ * endpoint descriptors, and product/vendor IDs, are relevant; no control
+ * operations are available. Linux supports it, but other host operating
+ * systems may not. (This is a subset of CDC Ethernet.)
+ *
+ * It turns out that if you add a few descriptors to that "CDC Subset",
+ * (Windows) host side drivers from MCCI can treat it as one submode of
+ * a proprietary scheme called "SAFE" ... without needing to know about
+ * specific product/vendor IDs. So we do that, making it easier to use
+ * those MS-Windows drivers. Those added descriptors make it resemble a
+ * CDC MDLM device, but they don't change device behavior at all. (See
+ * MCCI Engineering report 950198 "SAFE Networking Functions".)
*
* A third option is also in use. Rather than CDC Ethernet, or something
* simpler, Microsoft pushes their own approach: RNDIS. The published
@@ -254,6 +263,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define DEV_CONFIG_CDC
+#endif
+
#ifdef CONFIG_USB_GADGET_AT91
#define DEV_CONFIG_CDC
#endif
@@ -266,6 +279,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define DEV_CONFIG_CDC
+#endif
+
/* For CDC-incapable hardware, choose the simple cdc subset.
* Anything that talks bulk (without notable bugs) can do this.
@@ -283,9 +300,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
-#ifdef CONFIG_USB_GADGET_S3C2410
-#define DEV_CONFIG_CDC
-#endif
/*-------------------------------------------------------------------------*/
@@ -487,8 +501,17 @@ rndis_config = {
* endpoint. Both have a "data" interface and two bulk endpoints.
* There are also differences in how control requests are handled.
*
- * RNDIS shares a lot with CDC-Ethernet, since it's a variant of
- * the CDC-ACM (modem) spec.
+ * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the
+ * CDC-ACM (modem) spec. Unfortunately MSFT's RNDIS driver is buggy; it
+ * may hang or oops. Since bugfixes (or accurate specs, letting Linux
+ * work around those bugs) are unlikely to ever come from MSFT, you may
+ * wish to avoid using RNDIS.
+ *
+ * MCCI offers an alternative to RNDIS if you need to connect to Windows
+ * but have hardware that can't support CDC Ethernet. We add descriptors
+ * to present the CDC Subset as a (nonconformant) CDC MDLM variant called
+ * "SAFE". That borrows from both CDC Ethernet and CDC MDLM. You can
+ * get those drivers from MCCI, or bundled with various products.
*/
#ifdef DEV_CONFIG_CDC
@@ -522,8 +545,6 @@ rndis_control_intf = {
};
#endif
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-
static const struct usb_cdc_header_desc header_desc = {
.bLength = sizeof header_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
@@ -532,6 +553,8 @@ static const struct usb_cdc_header_desc header_desc = {
.bcdCDC = __constant_cpu_to_le16 (0x0110),
};
+#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+
static const struct usb_cdc_union_desc union_desc = {
.bLength = sizeof union_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
@@ -564,7 +587,40 @@ static const struct usb_cdc_acm_descriptor acm_descriptor = {
#endif
-#ifdef DEV_CONFIG_CDC
+#ifndef DEV_CONFIG_CDC
+
+/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
+ * ways: data endpoints live in the control interface, there's no data
+ * interface, and it's not used to talk to a cell phone radio.
+ */
+
+static const struct usb_cdc_mdlm_desc mdlm_desc = {
+ .bLength = sizeof mdlm_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_MDLM_TYPE,
+
+ .bcdVersion = __constant_cpu_to_le16(0x0100),
+ .bGUID = {
+ 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+ 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+ },
+};
+
+/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
+ * can't really use its struct. All we do here is say that we're using
+ * the submode of "SAFE" which directly matches the CDC Subset.
+ */
+static const u8 mdlm_detail_desc[] = {
+ 6,
+ USB_DT_CS_INTERFACE,
+ USB_CDC_MDLM_DETAIL_TYPE,
+
+ 0, /* "SAFE" */
+ 0, /* network control capabilities (none) */
+ 0, /* network data capabilities ("raw" encapsulation) */
+};
+
+#endif
static const struct usb_cdc_ether_desc ether_desc = {
.bLength = sizeof ether_desc,
@@ -579,7 +635,6 @@ static const struct usb_cdc_ether_desc ether_desc = {
.bNumberPowerFilters = 0,
};
-#endif
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
@@ -672,6 +727,9 @@ rndis_data_intf = {
/*
* "Simple" CDC-subset option is a simple vendor-neutral model that most
* full speed controllers can handle: one interface, two bulk endpoints.
+ *
+ * To assist host side drivers, we fancy it up a bit, and add descriptors
+ * so some host side drivers will understand it as a "SAFE" variant.
*/
static const struct usb_interface_descriptor
@@ -682,8 +740,8 @@ subset_data_intf = {
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 0,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM,
.bInterfaceProtocol = 0,
.iInterface = STRING_DATA,
};
@@ -731,10 +789,15 @@ static const struct usb_descriptor_header *fs_eth_function [11] = {
static inline void __init fs_subset_descriptors(void)
{
#ifdef DEV_CONFIG_SUBSET
+ /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
- fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
- fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
- fs_eth_function[4] = NULL;
+ fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+ fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+ fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+ fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+ fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
+ fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
+ fs_eth_function[8] = NULL;
#else
fs_eth_function[1] = NULL;
#endif
@@ -828,10 +891,15 @@ static const struct usb_descriptor_header *hs_eth_function [11] = {
static inline void __init hs_subset_descriptors(void)
{
#ifdef DEV_CONFIG_SUBSET
+ /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
- hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
- hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
- hs_eth_function[4] = NULL;
+ hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+ hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+ hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+ hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+ hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
+ hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
+ hs_eth_function[8] = NULL;
#else
hs_eth_function[1] = NULL;
#endif
@@ -878,10 +946,8 @@ static char manufacturer [50];
static char product_desc [40] = DRIVER_DESC;
static char serial_number [20];
-#ifdef DEV_CONFIG_CDC
/* address that the host will use ... usually assigned at random */
static char ethaddr [2 * ETH_ALEN + 1];
-#endif
/* static strings, in UTF-8 */
static struct usb_string strings [] = {
@@ -889,9 +955,9 @@ static struct usb_string strings [] = {
{ STRING_PRODUCT, product_desc, },
{ STRING_SERIALNUMBER, serial_number, },
{ STRING_DATA, "Ethernet Data", },
+ { STRING_ETHADDR, ethaddr, },
#ifdef DEV_CONFIG_CDC
{ STRING_CDC, "CDC Ethernet", },
- { STRING_ETHADDR, ethaddr, },
{ STRING_CONTROL, "CDC Communications Control", },
#endif
#ifdef DEV_CONFIG_SUBSET
@@ -986,10 +1052,10 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags)
}
#endif
- dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
+ dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
dev->in_ep->driver_data = dev;
- dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
+ dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
dev->out_ep->driver_data = dev;
/* With CDC, the host isn't allowed to use these two data
@@ -2278,10 +2344,10 @@ eth_bind (struct usb_gadget *gadget)
"RNDIS/%s", driver_desc);
/* CDC subset ... recognized by Linux since 2.4.10, but Windows
- * drivers aren't widely available.
+ * drivers aren't widely available. (That may be improved by
+ * supporting one submode of the "SAFE" variant of MDLM.)
*/
} else if (!cdc) {
- device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
device_desc.idVendor =
__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
device_desc.idProduct =
@@ -2352,6 +2418,10 @@ autoconf_fail:
if (!cdc) {
eth_config.bNumInterfaces = 1;
eth_config.iConfiguration = STRING_SUBSET;
+
+ /* use functions to set these up, in case we're built to work
+ * with multiple controllers and must override CDC Ethernet.
+ */
fs_subset_descriptors();
hs_subset_descriptors();
}
@@ -2415,22 +2485,20 @@ autoconf_fail:
/* Module params for these addresses should come from ID proms.
* The host side address is used with CDC and RNDIS, and commonly
- * ends up in a persistent config database.
+ * ends up in a persistent config database. It's not clear if
+ * host side code for the SAFE thing cares -- its original BLAN
+ * thing didn't, Sharp never assigned those addresses on Zaurii.
*/
if (get_ether_addr(dev_addr, net->dev_addr))
dev_warn(&gadget->dev,
"using random %s ethernet address\n", "self");
- if (cdc || rndis) {
- if (get_ether_addr(host_addr, dev->host_mac))
- dev_warn(&gadget->dev,
- "using random %s ethernet address\n", "host");
-#ifdef DEV_CONFIG_CDC
- snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
- dev->host_mac [0], dev->host_mac [1],
- dev->host_mac [2], dev->host_mac [3],
- dev->host_mac [4], dev->host_mac [5]);
-#endif
- }
+ if (get_ether_addr(host_addr, dev->host_mac))
+ dev_warn(&gadget->dev,
+ "using random %s ethernet address\n", "host");
+ snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
+ dev->host_mac [0], dev->host_mac [1],
+ dev->host_mac [2], dev->host_mac [3],
+ dev->host_mac [4], dev->host_mac [5]);
if (rndis) {
status = rndis_init();
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index c98316ce838..f04a29a4664 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -253,7 +253,7 @@
#include <linux/freezer.h>
#include <linux/utsname.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
@@ -1148,7 +1148,7 @@ static int ep0_queue(struct fsg_dev *fsg)
static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
+ struct fsg_dev *fsg = ep->driver_data;
if (req->actual > 0)
dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
@@ -1170,8 +1170,8 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
- struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
+ struct fsg_dev *fsg = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
if (req->status || req->actual != req->length)
DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -1190,8 +1190,8 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
- struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
+ struct fsg_dev *fsg = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
dump_msg(fsg, "bulk-out", req->buf, req->actual);
if (req->status || req->actual != bh->bulk_out_intended_length)
@@ -1214,8 +1214,8 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
#ifdef CONFIG_USB_FILE_STORAGE_TEST
static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
- struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
+ struct fsg_dev *fsg = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
if (req->status || req->actual != req->length)
DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -1909,10 +1909,10 @@ static int fsync_sub(struct lun *curlun)
if (!filp->f_op->fsync)
return -EINVAL;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
mutex_lock(&inode->i_mutex);
rc = filemap_fdatawrite(inode->i_mapping);
- err = filp->f_op->fsync(filp, filp->f_dentry, 1);
+ err = filp->f_op->fsync(filp, filp->f_path.dentry, 1);
if (!rc)
rc = err;
err = filemap_fdatawait(inode->i_mapping);
@@ -1950,7 +1950,7 @@ static int do_synchronize_cache(struct fsg_dev *fsg)
static void invalidate_sub(struct lun *curlun)
{
struct file *filp = curlun->filp;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
unsigned long rc;
rc = invalidate_inode_pages(inode->i_mapping);
@@ -2577,7 +2577,7 @@ static int send_status(struct fsg_dev *fsg)
}
if (transport_is_bbb()) {
- struct bulk_cs_wrap *csw = (struct bulk_cs_wrap *) bh->buf;
+ struct bulk_cs_wrap *csw = bh->buf;
/* Store and send the Bulk-only CSW */
csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
@@ -2596,8 +2596,7 @@ static int send_status(struct fsg_dev *fsg)
return 0;
} else { // USB_PR_CBI
- struct interrupt_data *buf = (struct interrupt_data *)
- bh->buf;
+ struct interrupt_data *buf = bh->buf;
/* Store and send the Interrupt data. UFI sends the ASC
* and ASCQ bytes. Everything else sends a Type (which
@@ -2982,7 +2981,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct usb_request *req = bh->outreq;
- struct bulk_cb_wrap *cbw = (struct bulk_cb_wrap *) req->buf;
+ struct bulk_cb_wrap *cbw = req->buf;
/* Was this a real packet? */
if (req->status)
@@ -3428,7 +3427,7 @@ static void handle_exception(struct fsg_dev *fsg)
static int fsg_main_thread(void *fsg_)
{
- struct fsg_dev *fsg = (struct fsg_dev *) fsg_;
+ struct fsg_dev *fsg = fsg_;
/* Allow the thread to be killed by a signal, but set the signal mask
* to block everything but INT, TERM, KILL, and USR1. */
@@ -3526,8 +3525,8 @@ static int open_backing_file(struct lun *curlun, const char *filename)
if (!(filp->f_mode & FMODE_WRITE))
ro = 1;
- if (filp->f_dentry)
- inode = filp->f_dentry->d_inode;
+ if (filp->f_path.dentry)
+ inode = filp->f_path.dentry->d_inode;
if (inode && S_ISBLK(inode->i_mode)) {
if (bdev_read_only(inode->i_bdev))
ro = 1;
@@ -3600,13 +3599,13 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
{
struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
char *p;
ssize_t rc;
down_read(&fsg->filesem);
if (backing_file_is_open(curlun)) { // Get the complete pathname
- p = d_path(curlun->filp->f_dentry, curlun->filp->f_vfsmnt,
+ p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
buf, PAGE_SIZE - 1);
if (IS_ERR(p))
rc = PTR_ERR(p);
@@ -3629,7 +3628,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
{
ssize_t rc = count;
struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
int i;
if (sscanf(buf, "%d", &i) != 1)
@@ -3652,7 +3651,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
int rc = 0;
if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
@@ -3700,7 +3699,7 @@ static void fsg_release(struct kref *ref)
static void lun_release(struct device *dev)
{
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
kref_put(&fsg->ref, fsg_release);
}
@@ -4030,8 +4029,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
if (backing_file_is_open(curlun)) {
p = NULL;
if (pathbuf) {
- p = d_path(curlun->filp->f_dentry,
- curlun->filp->f_vfsmnt,
+ p = d_path(curlun->filp->f_path.dentry,
+ curlun->filp->f_path.mnt,
pathbuf, PATH_MAX);
if (IS_ERR(p))
p = NULL;
@@ -4100,7 +4099,7 @@ static struct usb_gadget_driver fsg_driver = {
#endif
.function = (char *) longname,
.bind = fsg_bind,
- .unbind = __exit_p(fsg_unbind),
+ .unbind = fsg_unbind,
.disconnect = fsg_disconnect,
.setup = fsg_setup,
.suspend = fsg_suspend,
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index aa80f091072..2e3d6620d21 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -75,6 +75,12 @@
#define gadget_is_pxa27x(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name)
+#else
+#define gadget_is_husb2dev(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_S3C2410
#define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name)
#else
@@ -169,5 +175,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x16;
else if (gadget_is_mpc8272(gadget))
return 0x17;
+ else if (gadget_is_husb2dev(gadget))
+ return 0x18;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 31351826f2b..d08a8d0e642 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -35,7 +35,7 @@
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>
@@ -123,7 +123,7 @@ struct gmidi_device {
struct usb_request *req; /* for control responses */
u8 config;
struct usb_ep *in_ep, *out_ep;
- struct snd_card *card;
+ struct snd_card *card;
struct snd_rawmidi *rmidi;
struct snd_rawmidi_substream *in_substream;
struct snd_rawmidi_substream *out_substream;
@@ -490,7 +490,7 @@ static void gmidi_complete(struct usb_ep *ep, struct usb_request *req)
int status = req->status;
switch (status) {
- case 0: /* normal completion */
+ case 0: /* normal completion */
if (ep == dev->out_ep) {
/* we received stuff.
req is queued again, below */
@@ -505,7 +505,7 @@ static void gmidi_complete(struct usb_ep *ep, struct usb_request *req)
break;
/* this endpoint is normally active while we're configured */
- case -ECONNABORTED: /* hardware forced ep reset */
+ 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,
@@ -656,7 +656,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break;
- default: speed = "?"; break;
+ default: speed = "?"; break;
}
dev->config = number;
@@ -1308,7 +1308,7 @@ static struct usb_gadget_driver gmidi_driver = {
.speed = USB_SPEED_FULL,
.function = (char *)longname,
.bind = gmidi_bind,
- .unbind = __exit_p(gmidi_unbind),
+ .unbind = gmidi_unbind,
.setup = gmidi_setup,
.disconnect = gmidi_disconnect,
@@ -1316,7 +1316,7 @@ static struct usb_gadget_driver gmidi_driver = {
.suspend = gmidi_suspend,
.resume = gmidi_resume,
- .driver = {
+ .driver = {
.name = (char *)shortname,
.owner = THIS_MODULE,
},
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 805a9826842..e873cf48824 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -39,7 +39,7 @@
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>
@@ -1432,7 +1432,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
if (!driver
|| driver->speed != USB_SPEED_FULL
|| !driver->bind
- || !driver->unbind
|| !driver->disconnect
|| !driver->setup)
return -EINVAL;
@@ -1495,7 +1494,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!dev)
return -ENODEV;
- if (!driver || driver != dev->driver)
+ if (!driver || driver != dev->driver || !driver->unbind)
return -EINVAL;
spin_lock_irqsave(&dev->lock, flags);
@@ -1808,13 +1807,8 @@ static void goku_remove(struct pci_dev *pdev)
struct goku_udc *dev = pci_get_drvdata(pdev);
DBG(dev, "%s\n", __FUNCTION__);
- /* start with the driver above us */
- if (dev->driver) {
- /* should have been done already by driver model core */
- WARN(dev, "pci remove, driver '%s' is still registered\n",
- dev->driver->driver.name);
- usb_gadget_unregister_driver(dev->driver);
- }
+
+ BUG_ON(dev->driver);
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
remove_proc_entry(proc_node_name, NULL);
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 3fb1044a4db..34296e79edc 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -20,7 +20,7 @@
*/
-// #define DEBUG /* data to help fault diagnosis */
+// #define DEBUG /* data to help fault diagnosis */
// #define VERBOSE /* extra debug messages (success too) */
#include <linux/init.h>
@@ -59,11 +59,11 @@
* may serve as a source of device events, used to handle all control
* requests other than basic enumeration.
*
- * - Then either immediately, or after a SET_CONFIGURATION control request,
- * ep_config() is called when each /dev/gadget/ep* file is configured
- * (by writing endpoint descriptors). Afterwards these files are used
- * to write() IN data or to read() OUT data. To halt the endpoint, a
- * "wrong direction" request is issued (like reading an IN endpoint).
+ * - Then, after a SET_CONFIGURATION control request, ep_config() is
+ * called when each /dev/gadget/ep* file is configured (by writing
+ * endpoint descriptors). Afterwards these files are used to write()
+ * IN data or to read() OUT data. To halt the endpoint, a "wrong
+ * direction" request is issued (like reading an IN endpoint).
*
* Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
* not possible on all hardware. For example, precise fault handling with
@@ -98,16 +98,16 @@ enum ep0_state {
* must always write descriptors to initialize the device, then
* the device becomes UNCONNECTED until enumeration.
*/
- STATE_OPENED,
+ STATE_DEV_OPENED,
/* From then on, ep0 fd is in either of two basic modes:
* - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
* - SETUP: read/write will transfer control data and succeed;
* or if "wrong direction", performs protocol stall
*/
- STATE_UNCONNECTED,
- STATE_CONNECTED,
- STATE_SETUP,
+ STATE_DEV_UNCONNECTED,
+ STATE_DEV_CONNECTED,
+ STATE_DEV_SETUP,
/* UNBOUND means the driver closed ep0, so the device won't be
* accessible again (DEV_DISABLED) until all fds are closed.
@@ -121,7 +121,7 @@ enum ep0_state {
struct dev_data {
spinlock_t lock;
atomic_t count;
- enum ep0_state state;
+ enum ep0_state state; /* P: lock */
struct usb_gadgetfs_event event [N_EVENT];
unsigned ev_next;
struct fasync_struct *fasync;
@@ -188,7 +188,6 @@ static struct dev_data *dev_new (void)
enum ep_state {
STATE_EP_DISABLED = 0,
STATE_EP_READY,
- STATE_EP_DEFER_ENABLE,
STATE_EP_ENABLED,
STATE_EP_UNBOUND,
};
@@ -313,18 +312,10 @@ nonblock:
if ((val = down_interruptible (&epdata->lock)) < 0)
return val;
-newstate:
+
switch (epdata->state) {
case STATE_EP_ENABLED:
break;
- case STATE_EP_DEFER_ENABLE:
- DBG (epdata->dev, "%s wait for host\n", epdata->name);
- if ((val = wait_event_interruptible (epdata->wait,
- epdata->state != STATE_EP_DEFER_ENABLE
- || epdata->dev->state == STATE_DEV_UNBOUND
- )) < 0)
- goto fail;
- goto newstate;
// case STATE_EP_DISABLED: /* "can't happen" */
// case STATE_EP_READY: /* "can't happen" */
default: /* error! */
@@ -333,7 +324,6 @@ newstate:
// FALLTHROUGH
case STATE_EP_UNBOUND: /* clean disconnect */
val = -ENODEV;
-fail:
up (&epdata->lock);
}
return val;
@@ -565,29 +555,28 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
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;
+ /* 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);
+ return len;
}
static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -600,18 +589,17 @@ 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->iv == NULL
- || unlikely(req->actual == 0)
- || unlikely(kiocbIsCancelled(iocb))) {
+
+ /* if this was a write or a read returning no data then we
+ * don't need to copy anything to userspace, so we can
+ * complete the aio request immediately.
+ */
+ if (priv->iv == NULL || unlikely(req->actual == 0)) {
kfree(req->buf);
kfree(priv);
iocb->private = NULL;
/* aio_complete() reports bytes-transferred _and_ faults */
- if (unlikely(kiocbIsCancelled(iocb)))
- aio_put_req(iocb);
- else
- aio_complete(iocb,
- req->actual ? req->actual : req->status,
+ aio_complete(iocb, req->actual ? req->actual : req->status,
req->status);
} else {
/* retry() won't report both; so we hide some faults */
@@ -636,7 +624,7 @@ ep_aio_rwtail(
size_t len,
struct ep_data *epdata,
const struct iovec *iv,
- unsigned long nr_segs
+ unsigned long nr_segs
)
{
struct kiocb_priv *priv;
@@ -852,9 +840,9 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
break;
#endif
default:
- DBG (data->dev, "unconnected, %s init deferred\n",
+ DBG(data->dev, "unconnected, %s init abandoned\n",
data->name);
- data->state = STATE_EP_DEFER_ENABLE;
+ value = -EINVAL;
}
if (value == 0) {
fd->f_op = &ep_io_operations;
@@ -943,22 +931,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
{
struct dev_data *dev = ep->driver_data;
+ unsigned long flags;
int free = 1;
/* for control OUT, data must still get to userspace */
+ spin_lock_irqsave(&dev->lock, flags);
if (!dev->setup_in) {
dev->setup_out_error = (req->status != 0);
if (!dev->setup_out_error)
free = 0;
dev->setup_out_ready = 1;
ep0_readable (dev);
- } else if (dev->state == STATE_SETUP)
- dev->state = STATE_CONNECTED;
+ }
/* clean up as appropriate */
if (free && req->buf != &dev->rbuf)
clean_req (ep, req);
req->complete = epio_complete;
+ spin_unlock_irqrestore(&dev->lock, flags);
}
static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
@@ -998,13 +988,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
}
/* control DATA stage */
- if ((state = dev->state) == STATE_SETUP) {
+ if ((state = dev->state) == STATE_DEV_SETUP) {
if (dev->setup_in) { /* stall IN */
VDEBUG(dev, "ep0in stall\n");
(void) usb_ep_set_halt (dev->gadget->ep0);
retval = -EL2HLT;
- dev->state = STATE_CONNECTED;
+ dev->state = STATE_DEV_CONNECTED;
} else if (len == 0) { /* ack SET_CONFIGURATION etc */
struct usb_ep *ep = dev->gadget->ep0;
@@ -1012,7 +1002,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
if ((retval = setup_req (ep, req, 0)) == 0)
retval = usb_ep_queue (ep, req, GFP_ATOMIC);
- dev->state = STATE_CONNECTED;
+ dev->state = STATE_DEV_CONNECTED;
/* assume that was SET_CONFIGURATION */
if (dev->current_config) {
@@ -1040,6 +1030,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
spin_lock_irq (&dev->lock);
if (retval)
goto done;
+
+ if (dev->state != STATE_DEV_SETUP) {
+ retval = -ECANCELED;
+ goto done;
+ }
+ dev->state = STATE_DEV_CONNECTED;
+
if (dev->setup_out_error)
retval = -EIO;
else {
@@ -1066,39 +1063,36 @@ scan:
/* return queued events right away */
if (dev->ev_next != 0) {
unsigned i, n;
- int tmp = dev->ev_next;
- len = min (len, tmp * sizeof (struct usb_gadgetfs_event));
n = len / sizeof (struct usb_gadgetfs_event);
+ if (dev->ev_next < n)
+ n = dev->ev_next;
- /* ep0 can't deliver events when STATE_SETUP */
+ /* ep0 i/o has special semantics during STATE_DEV_SETUP */
for (i = 0; i < n; i++) {
if (dev->event [i].type == GADGETFS_SETUP) {
- len = i + 1;
- len *= sizeof (struct usb_gadgetfs_event);
- n = 0;
+ dev->state = STATE_DEV_SETUP;
+ n = i + 1;
break;
}
}
spin_unlock_irq (&dev->lock);
+ len = n * sizeof (struct usb_gadgetfs_event);
if (copy_to_user (buf, &dev->event, len))
retval = -EFAULT;
else
retval = len;
if (len > 0) {
- len /= sizeof (struct usb_gadgetfs_event);
-
/* NOTE this doesn't guard against broken drivers;
* concurrent ep0 readers may lose events.
*/
spin_lock_irq (&dev->lock);
- dev->ev_next -= len;
- if (dev->ev_next != 0)
- memmove (&dev->event, &dev->event [len],
+ if (dev->ev_next > n) {
+ memmove(&dev->event[0], &dev->event[n],
sizeof (struct usb_gadgetfs_event)
- * (tmp - len));
- if (n == 0)
- dev->state = STATE_SETUP;
+ * (dev->ev_next - n));
+ }
+ dev->ev_next -= n;
spin_unlock_irq (&dev->lock);
}
return retval;
@@ -1113,8 +1107,8 @@ scan:
DBG (dev, "fail %s, state %d\n", __FUNCTION__, state);
retval = -ESRCH;
break;
- case STATE_UNCONNECTED:
- case STATE_CONNECTED:
+ case STATE_DEV_UNCONNECTED:
+ case STATE_DEV_CONNECTED:
spin_unlock_irq (&dev->lock);
DBG (dev, "%s wait\n", __FUNCTION__);
@@ -1141,7 +1135,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
switch (type) {
/* these events purge the queue */
case GADGETFS_DISCONNECT:
- if (dev->state == STATE_SETUP)
+ if (dev->state == STATE_DEV_SETUP)
dev->setup_abort = 1;
// FALL THROUGH
case GADGETFS_CONNECT:
@@ -1153,7 +1147,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
for (i = 0; i != dev->ev_next; i++) {
if (dev->event [i].type != type)
continue;
- DBG (dev, "discard old event %d\n", type);
+ DBG(dev, "discard old event[%d] %d\n", i, type);
dev->ev_next--;
if (i == dev->ev_next)
break;
@@ -1166,9 +1160,9 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
default:
BUG ();
}
+ VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
event = &dev->event [dev->ev_next++];
BUG_ON (dev->ev_next > N_EVENT);
- VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next);
memset (event, 0, sizeof *event);
event->type = type;
return event;
@@ -1188,12 +1182,13 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
retval = -EIDRM;
/* data and/or status stage for control request */
- } else if (dev->state == STATE_SETUP) {
+ } else if (dev->state == STATE_DEV_SETUP) {
/* IN DATA+STATUS caller makes len <= wLength */
if (dev->setup_in) {
retval = setup_req (dev->gadget->ep0, dev->req, len);
if (retval == 0) {
+ dev->state = STATE_DEV_CONNECTED;
spin_unlock_irq (&dev->lock);
if (copy_from_user (dev->req->buf, buf, len))
retval = -EFAULT;
@@ -1219,7 +1214,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
VDEBUG(dev, "ep0out stall\n");
(void) usb_ep_set_halt (dev->gadget->ep0);
retval = -EL2HLT;
- dev->state = STATE_CONNECTED;
+ dev->state = STATE_DEV_CONNECTED;
} else {
DBG(dev, "bogus ep0out stall!\n");
}
@@ -1261,7 +1256,9 @@ dev_release (struct inode *inode, struct file *fd)
put_dev (dev);
/* other endpoints were all decoupled from this device */
+ spin_lock_irq(&dev->lock);
dev->state = STATE_DEV_DISABLED;
+ spin_unlock_irq(&dev->lock);
return 0;
}
@@ -1282,7 +1279,7 @@ ep0_poll (struct file *fd, poll_table *wait)
goto out;
}
- if (dev->state == STATE_SETUP) {
+ if (dev->state == STATE_DEV_SETUP) {
if (dev->setup_in || dev->setup_can_stall)
mask = POLLOUT;
} else {
@@ -1392,52 +1389,29 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
spin_lock (&dev->lock);
dev->setup_abort = 0;
- if (dev->state == STATE_UNCONNECTED) {
- struct usb_ep *ep;
- struct ep_data *data;
-
- dev->state = STATE_CONNECTED;
- dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
-
+ if (dev->state == STATE_DEV_UNCONNECTED) {
#ifdef CONFIG_USB_GADGET_DUALSPEED
if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
+ spin_unlock(&dev->lock);
ERROR (dev, "no high speed config??\n");
return -EINVAL;
}
#endif /* CONFIG_USB_GADGET_DUALSPEED */
+ dev->state = STATE_DEV_CONNECTED;
+ dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
+
INFO (dev, "connected\n");
event = next_event (dev, GADGETFS_CONNECT);
event->u.speed = gadget->speed;
ep0_readable (dev);
- list_for_each_entry (ep, &gadget->ep_list, ep_list) {
- data = ep->driver_data;
- /* ... down_trylock (&data->lock) ... */
- if (data->state != STATE_EP_DEFER_ENABLE)
- continue;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (gadget->speed == USB_SPEED_HIGH)
- value = usb_ep_enable (ep, &data->hs_desc);
- else
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
- value = usb_ep_enable (ep, &data->desc);
- if (value) {
- ERROR (dev, "deferred %s enable --> %d\n",
- data->name, value);
- continue;
- }
- data->state = STATE_EP_ENABLED;
- wake_up (&data->wait);
- DBG (dev, "woke up %s waiters\n", data->name);
- }
-
/* host may have given up waiting for response. we can miss control
* requests handled lower down (device/endpoint status and features);
* then ep0_{read,write} will report the wrong status. controller
* driver will have aborted pending i/o.
*/
- } else if (dev->state == STATE_SETUP)
+ } else if (dev->state == STATE_DEV_SETUP)
dev->setup_abort = 1;
req->buf = dev->rbuf;
@@ -1583,7 +1557,7 @@ delegate:
}
/* proceed with data transfer and status phases? */
- if (value >= 0 && dev->state != STATE_SETUP) {
+ if (value >= 0 && dev->state != STATE_DEV_SETUP) {
req->length = value;
req->zero = value < w_length;
value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
@@ -1747,7 +1721,9 @@ gadgetfs_bind (struct usb_gadget *gadget)
goto enomem;
INFO (dev, "bound to %s driver\n", gadget->name);
- dev->state = STATE_UNCONNECTED;
+ spin_lock_irq(&dev->lock);
+ dev->state = STATE_DEV_UNCONNECTED;
+ spin_unlock_irq(&dev->lock);
get_dev (dev);
return 0;
@@ -1762,11 +1738,9 @@ 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");
+ if (dev->state == STATE_DEV_UNCONNECTED)
goto exit;
- }
- dev->state = STATE_UNCONNECTED;
+ dev->state = STATE_DEV_UNCONNECTED;
INFO (dev, "disconnected\n");
next_event (dev, GADGETFS_DISCONNECT);
@@ -1783,9 +1757,9 @@ gadgetfs_suspend (struct usb_gadget *gadget)
INFO (dev, "suspended from state %d\n", dev->state);
spin_lock (&dev->lock);
switch (dev->state) {
- case STATE_SETUP: // VERY odd... host died??
- case STATE_CONNECTED:
- case STATE_UNCONNECTED:
+ case STATE_DEV_SETUP: // VERY odd... host died??
+ case STATE_DEV_CONNECTED:
+ case STATE_DEV_UNCONNECTED:
next_event (dev, GADGETFS_SUSPEND);
ep0_readable (dev);
/* FALLTHROUGH */
@@ -1808,7 +1782,7 @@ static struct usb_gadget_driver gadgetfs_driver = {
.disconnect = gadgetfs_disconnect,
.suspend = gadgetfs_suspend,
- .driver = {
+ .driver = {
.name = (char *) shortname,
},
};
@@ -1829,7 +1803,7 @@ static struct usb_gadget_driver probe_driver = {
.unbind = gadgetfs_nop,
.setup = (void *)gadgetfs_nop,
.disconnect = gadgetfs_nop,
- .driver = {
+ .driver = {
.name = "nop",
},
};
@@ -1849,19 +1823,16 @@ static struct usb_gadget_driver probe_driver = {
* . full/low speed config ... all wTotalLength bytes (with interface,
* class, altsetting, endpoint, and other descriptors)
* . high speed config ... all descriptors, for high speed operation;
- * this one's optional except for high-speed hardware
+ * this one's optional except for high-speed hardware
* . device descriptor
*
- * Endpoints are not yet enabled. Drivers may want to immediately
- * initialize them, using the /dev/gadget/ep* files that are available
- * as soon as the kernel sees the configuration, or they can wait
- * until device configuration and interface altsetting changes create
+ * Endpoints are not yet enabled. Drivers must wait until device
+ * configuration and interface altsetting changes create
* the need to configure (or unconfigure) them.
*
* After initialization, the device stays active for as long as that
- * $CHIP file is open. Events may then be read from that descriptor,
- * such as configuration notifications. More complex drivers will handle
- * some control requests in user space.
+ * $CHIP file is open. Events must then be read from that descriptor,
+ * such as configuration notifications.
*/
static int is_valid_config (struct usb_config_descriptor *config)
@@ -1884,9 +1855,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
u32 tag;
char *kbuf;
- if (dev->state != STATE_OPENED)
- return -EEXIST;
-
if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
return -EINVAL;
@@ -1978,13 +1946,15 @@ dev_open (struct inode *inode, struct file *fd)
struct dev_data *dev = inode->i_private;
int value = -EBUSY;
+ spin_lock_irq(&dev->lock);
if (dev->state == STATE_DEV_DISABLED) {
dev->ev_next = 0;
- dev->state = STATE_OPENED;
+ dev->state = STATE_DEV_OPENED;
fd->private_data = dev;
get_dev (dev);
value = 0;
}
+ spin_unlock_irq(&dev->lock);
return value;
}
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index 4a991564a03..a0a73c08a34 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -422,9 +422,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
DEBUG("%s: %s\n", __FUNCTION__, driver->driver.name);
if (!driver
- || driver->speed != USB_SPEED_FULL
- || !driver->bind
- || !driver->unbind || !driver->disconnect || !driver->setup)
+ || driver->speed != USB_SPEED_FULL
+ || !driver->bind
+ || !driver->disconnect
+ || !driver->setup)
return -EINVAL;
if (!dev)
return -ENODEV;
@@ -471,7 +472,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!dev)
return -ENODEV;
- if (!driver || driver != dev->driver)
+ if (!driver || driver != dev->driver || !driver->unbind)
return -EINVAL;
spin_lock_irqsave(&dev->lock, flags);
@@ -2125,9 +2126,11 @@ static int lh7a40x_udc_remove(struct platform_device *pdev)
DEBUG("%s: %p\n", __FUNCTION__, pdev);
+ if (dev->driver)
+ return -EBUSY;
+
udc_disable(dev);
remove_proc_files();
- usb_gadget_unregister_driver(dev->driver);
free_irq(IRQ_USBINTR, dev);
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index e3bb78524c8..b3fe197e1ee 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -49,7 +49,7 @@
#include <asm/unaligned.h>
#include <asm/hardware.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
/*
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 3024c679e38..7617ff7bd5a 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -63,7 +63,7 @@
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>
@@ -2020,7 +2020,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
if (!driver
|| driver->speed != USB_SPEED_HIGH
|| !driver->bind
- || !driver->unbind
|| !driver->setup)
return -EINVAL;
if (!dev)
@@ -2107,7 +2106,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
if (!dev)
return -ENODEV;
- if (!driver || driver != dev->driver)
+ if (!driver || driver != dev->driver || !driver->unbind)
return -EINVAL;
spin_lock_irqsave (&dev->lock, flags);
@@ -2803,13 +2802,7 @@ static void net2280_remove (struct pci_dev *pdev)
{
struct net2280 *dev = pci_get_drvdata (pdev);
- /* start with the driver above us */
- if (dev->driver) {
- /* should have been done already by driver model core */
- WARN (dev, "pci remove, driver '%s' is still registered\n",
- dev->driver->driver.name);
- usb_gadget_unregister_driver (dev->driver);
- }
+ BUG_ON(dev->driver);
/* then clean up the resources we allocated during probe() */
net2280_led_shutdown (dev);
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 030d87c28c2..140104341db 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -38,10 +38,11 @@
#include <linux/mm.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
+#include <linux/clk.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -60,6 +61,11 @@
/* bulk DMA seems to be behaving for both IN and OUT */
#define USE_DMA
+/* FIXME: OMAP2 currently has some problem in DMA mode */
+#ifdef CONFIG_ARCH_OMAP2
+#undef USE_DMA
+#endif
+
/* ISO too */
#define USE_ISO
@@ -99,7 +105,7 @@ static unsigned fifo_mode = 0;
* boot parameter "omap_udc:fifo_mode=42"
*/
module_param (fifo_mode, uint, 0);
-MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)");
+MODULE_PARM_DESC (fifo_mode, "endpoint configuration");
#ifdef USE_DMA
static unsigned use_dma = 1;
@@ -122,7 +128,7 @@ static const char driver_desc [] = DRIVER_DESC;
/*-------------------------------------------------------------------------*/
/* there's a notion of "current endpoint" for modifying endpoint
- * state, and PIO access to its FIFO.
+ * state, and PIO access to its FIFO.
*/
static void use_ep(struct omap_ep *ep, u16 select)
@@ -391,7 +397,7 @@ done(struct omap_ep *ep, struct omap_req *req, int status)
#define FIFO_EMPTY (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY)
#define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY)
-static inline int
+static inline int
write_packet(u8 *buf, struct omap_req *req, unsigned max)
{
unsigned len;
@@ -456,7 +462,7 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req)
return is_last;
}
-static inline int
+static inline int
read_packet(u8 *buf, struct omap_req *req, unsigned avail)
{
unsigned len;
@@ -542,9 +548,9 @@ static inline dma_addr_t dma_csac(unsigned lch)
/* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
* read before the DMA controller finished disabling the channel.
*/
- csac = omap_readw(OMAP_DMA_CSAC(lch));
+ csac = OMAP_DMA_CSAC_REG(lch);
if (csac == 0)
- csac = omap_readw(OMAP_DMA_CSAC(lch));
+ csac = OMAP_DMA_CSAC_REG(lch);
return csac;
}
@@ -555,9 +561,9 @@ static inline dma_addr_t dma_cdac(unsigned lch)
/* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
* read before the DMA controller finished disabling the channel.
*/
- cdac = omap_readw(OMAP_DMA_CDAC(lch));
+ cdac = OMAP_DMA_CDAC_REG(lch);
if (cdac == 0)
- cdac = omap_readw(OMAP_DMA_CDAC(lch));
+ cdac = OMAP_DMA_CDAC_REG(lch);
return cdac;
}
@@ -582,7 +588,7 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
}
#define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
- ? omap_readw(OMAP_DMA_CSAC(x)) /* really: CPC */ \
+ ? OMAP_DMA_CSAC_REG(x) /* really: CPC */ \
: dma_cdac(x))
static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
@@ -620,17 +626,19 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
|| (cpu_is_omap15xx() && length < ep->maxpacket)) {
txdma_ctrl = UDC_TXN_EOT | length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
- length, 1, sync_mode);
+ length, 1, sync_mode, 0, 0);
} else {
length = min(length / ep->maxpacket,
(unsigned) UDC_TXN_TSC + 1);
- txdma_ctrl = length;
+ txdma_ctrl = length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
- ep->ep.maxpacket >> 1, length, sync_mode);
+ ep->ep.maxpacket >> 1, length, sync_mode,
+ 0, 0);
length *= ep->maxpacket;
}
omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
+ OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
+ 0, 0);
omap_start_dma(ep->lch);
ep->dma_counter = dma_csac(ep->lch);
@@ -675,9 +683,11 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
req->dma_bytes = packets * ep->ep.maxpacket;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
ep->ep.maxpacket >> 1, packets,
- OMAP_DMA_SYNC_ELEMENT);
+ OMAP_DMA_SYNC_ELEMENT,
+ 0, 0);
omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
+ OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
+ 0, 0);
ep->dma_counter = DMA_DEST_LAST(ep->lch);
UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
@@ -820,7 +830,8 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
omap_set_dma_dest_params(ep->lch,
OMAP_DMA_PORT_TIPB,
OMAP_DMA_AMODE_CONSTANT,
- (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
+ (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
+ 0, 0);
}
} else {
status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel,
@@ -831,7 +842,8 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
omap_set_dma_src_params(ep->lch,
OMAP_DMA_PORT_TIPB,
OMAP_DMA_AMODE_CONSTANT,
- (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
+ (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
+ 0, 0);
/* EMIFF */
omap_set_dma_dest_burst_mode(ep->lch,
OMAP_DMA_DATA_BURST_4);
@@ -846,7 +858,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
/* channel type P: hw synch (fifo) */
if (!cpu_is_omap15xx())
- omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch));
+ OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2;
}
just_restart:
@@ -893,7 +905,7 @@ static void dma_channel_release(struct omap_ep *ep)
else
req = NULL;
- active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0;
+ active = ((1 << 7) & OMAP_DMA_CCR_REG(ep->lch)) != 0;
DBG("%s release %s %cxdma%d %p\n", ep->ep.name,
active ? "active" : "idle",
@@ -1117,7 +1129,7 @@ static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
*/
dma_channel_release(ep);
dma_channel_claim(ep, channel);
- } else
+ } else
done(ep, req, -ECONNRESET);
spin_unlock_irqrestore(&ep->udc->lock, flags);
return 0;
@@ -1153,7 +1165,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
/* IN endpoints must already be idle */
if ((ep->bEndpointAddress & USB_DIR_IN)
- && !list_empty(&ep->queue)) {
+ && !list_empty(&ep->queue)) {
status = -EAGAIN;
goto done;
}
@@ -1298,6 +1310,23 @@ static void pullup_disable(struct omap_udc *udc)
UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
}
+static struct omap_udc *udc;
+
+static void omap_udc_enable_clock(int enable)
+{
+ if (udc == NULL || udc->dc_clk == NULL || udc->hhc_clk == NULL)
+ return;
+
+ if (enable) {
+ clk_enable(udc->dc_clk);
+ clk_enable(udc->hhc_clk);
+ udelay(100);
+ } else {
+ clk_disable(udc->hhc_clk);
+ clk_disable(udc->dc_clk);
+ }
+}
+
/*
* Called by whatever detects VBUS sessions: external transceiver
* driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock.
@@ -1318,10 +1347,22 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
else
FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
}
+ if (udc->dc_clk != NULL && is_active) {
+ if (!udc->clk_requested) {
+ omap_udc_enable_clock(1);
+ udc->clk_requested = 1;
+ }
+ }
if (can_pullup(udc))
pullup_enable(udc);
else
pullup_disable(udc);
+ if (udc->dc_clk != NULL && !is_active) {
+ if (udc->clk_requested) {
+ omap_udc_enable_clock(0);
+ udc->clk_requested = 0;
+ }
+ }
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
@@ -1441,7 +1482,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
}
}
- /* IN/OUT packets mean we're in the DATA or STATUS stage.
+ /* IN/OUT packets mean we're in the DATA or STATUS stage.
* This driver uses only uses protocol stalls (ep0 never halts),
* and if we got this far the gadget driver already had a
* chance to stall. Tries to be forgiving of host oddities.
@@ -1509,7 +1550,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
} else if (stat == 0)
UDC_CTRL_REG = UDC_SET_FIFO_EN;
UDC_EP_NUM_REG = 0;
-
+
/* activate status stage */
if (stat == 1) {
done(ep0, req, 0);
@@ -1866,7 +1907,7 @@ static void pio_out_timer(unsigned long _ep)
spin_lock_irqsave(&ep->udc->lock, flags);
if (!list_empty(&ep->queue) && ep->ackwait) {
- use_ep(ep, 0);
+ use_ep(ep, UDC_EP_SEL);
stat_flg = UDC_STAT_FLG_REG;
if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN)
@@ -1876,12 +1917,12 @@ static void pio_out_timer(unsigned long _ep)
VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg);
req = container_of(ep->queue.next,
struct omap_req, queue);
- UDC_EP_NUM_REG = ep->bEndpointAddress | UDC_EP_SEL;
(void) read_fifo(ep, req);
UDC_EP_NUM_REG = ep->bEndpointAddress;
UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
- }
+ } else
+ deselect_ep();
}
mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
spin_unlock_irqrestore(&ep->udc->lock, flags);
@@ -2028,7 +2069,17 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
/*-------------------------------------------------------------------------*/
-static struct omap_udc *udc;
+static inline int machine_needs_vbus_session(void)
+{
+ return (machine_is_omap_innovator()
+ || machine_is_omap_osk()
+ || machine_is_omap_apollon()
+#ifndef CONFIG_MACH_OMAP_H4_OTG
+ || machine_is_omap_h4()
+#endif
+ || machine_is_sx1()
+ );
+}
int usb_gadget_register_driver (struct usb_gadget_driver *driver)
{
@@ -2043,7 +2094,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
// FIXME if otg, check: driver->is_otg
|| driver->speed < USB_SPEED_FULL
|| !driver->bind
- || !driver->unbind
|| !driver->setup)
return -EINVAL;
@@ -2071,6 +2121,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags);
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(1);
+
status = driver->bind (&udc->gadget);
if (status) {
DBG("bind to %s --> %d\n", driver->driver.name, status);
@@ -2087,9 +2140,11 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
status = otg_set_peripheral(udc->transceiver, &udc->gadget);
if (status < 0) {
ERR("can't bind to transceiver\n");
- driver->unbind (&udc->gadget);
- udc->gadget.dev.driver = NULL;
- udc->driver = NULL;
+ if (driver->unbind) {
+ driver->unbind (&udc->gadget);
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
+ }
goto done;
}
} else {
@@ -2102,10 +2157,12 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
/* boards that don't have VBUS sensing can't autogate 48MHz;
* can't enter deep sleep while a gadget driver is active.
*/
- if (machine_is_omap_innovator() || machine_is_omap_osk())
+ if (machine_needs_vbus_session())
omap_vbus_session(&udc->gadget, 1);
done:
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(0);
return status;
}
EXPORT_SYMBOL(usb_gadget_register_driver);
@@ -2117,10 +2174,13 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
if (!udc)
return -ENODEV;
- if (!driver || driver != udc->driver)
+ if (!driver || driver != udc->driver || !driver->unbind)
return -EINVAL;
- if (machine_is_omap_innovator() || machine_is_omap_osk())
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(1);
+
+ if (machine_needs_vbus_session())
omap_vbus_session(&udc->gadget, 0);
if (udc->transceiver)
@@ -2136,6 +2196,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
+ if (udc->dc_clk != NULL)
+ omap_udc_enable_clock(0);
DBG("unregistered driver '%s'\n", driver->driver.name);
return status;
}
@@ -2218,7 +2280,7 @@ static char *trx_mode(unsigned m, int enabled)
case 0: return enabled ? "*6wire" : "unused";
case 1: return "4wire";
case 2: return "3wire";
- case 3: return "6wire";
+ case 3: return "6wire";
default: return "unknown";
}
}
@@ -2227,11 +2289,18 @@ static int proc_otg_show(struct seq_file *s)
{
u32 tmp;
u32 trans;
+ char *ctrl_name;
tmp = OTG_REV_REG;
- trans = USB_TRANSCEIVER_CTRL_REG;
- seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %05x\n",
- tmp >> 4, tmp & 0xf, trans);
+ if (cpu_is_omap24xx()) {
+ ctrl_name = "control_devconf";
+ trans = CONTROL_DEVCONF_REG;
+ } else {
+ ctrl_name = "tranceiver_ctrl";
+ trans = USB_TRANSCEIVER_CTRL_REG;
+ }
+ seq_printf(s, "\nOTG rev %d.%d, %s %05x\n",
+ tmp >> 4, tmp & 0xf, ctrl_name, trans);
tmp = OTG_SYSCON_1_REG;
seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
FOURBITS "\n", tmp,
@@ -2306,7 +2375,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
driver_desc,
use_dma ? " (dma)" : "");
- tmp = UDC_REV_REG & 0xff;
+ tmp = UDC_REV_REG & 0xff;
seq_printf(s,
"UDC rev %d.%d, fifo mode %d, gadget %s\n"
"hmc %d, transceiver %s\n",
@@ -2314,11 +2383,16 @@ static int proc_udc_show(struct seq_file *s, void *_)
fifo_mode,
udc->driver ? udc->driver->driver.name : "(none)",
HMC,
- udc->transceiver ? udc->transceiver->label : "(none)");
- seq_printf(s, "ULPD control %04x req %04x status %04x\n",
- __REG16(ULPD_CLOCK_CTRL),
- __REG16(ULPD_SOFT_REQ),
- __REG16(ULPD_STATUS_REQ));
+ udc->transceiver
+ ? udc->transceiver->label
+ : ((cpu_is_omap1710() || cpu_is_omap24xx())
+ ? "external" : "(none)"));
+ if (cpu_class_is_omap1()) {
+ seq_printf(s, "ULPD control %04x req %04x status %04x\n",
+ __REG16(ULPD_CLOCK_CTRL),
+ __REG16(ULPD_SOFT_REQ),
+ __REG16(ULPD_STATUS_REQ));
+ }
/* OTG controller registers */
if (!cpu_is_omap15xx())
@@ -2503,9 +2577,10 @@ omap_ep_setup(char *name, u8 addr, u8 type,
dbuf = 1;
} else {
/* double-buffering "not supported" on 15xx,
- * and ignored for PIO-IN on 16xx
+ * and ignored for PIO-IN on newer chips
+ * (for more reliable behavior)
*/
- if (!use_dma || cpu_is_omap15xx())
+ if (!use_dma || cpu_is_omap15xx() || cpu_is_omap24xx())
dbuf = 0;
switch (maxp) {
@@ -2548,7 +2623,7 @@ omap_ep_setup(char *name, u8 addr, u8 type,
ep->bEndpointAddress = addr;
ep->bmAttributes = type;
ep->double_buf = dbuf;
- ep->udc = udc;
+ ep->udc = udc;
ep->ep.name = ep->name;
ep->ep.ops = &omap_ep_ops;
@@ -2708,15 +2783,37 @@ static int __init omap_udc_probe(struct platform_device *pdev)
struct otg_transceiver *xceiv = NULL;
const char *type = NULL;
struct omap_usb_config *config = pdev->dev.platform_data;
+ struct clk *dc_clk;
+ struct clk *hhc_clk;
/* NOTE: "knows" the order of the resources! */
- if (!request_mem_region(pdev->resource[0].start,
+ if (!request_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1,
driver_name)) {
DBG("request_mem_region failed\n");
return -EBUSY;
}
+ if (cpu_is_omap16xx()) {
+ dc_clk = clk_get(&pdev->dev, "usb_dc_ck");
+ hhc_clk = clk_get(&pdev->dev, "usb_hhc_ck");
+ BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
+ /* can't use omap_udc_enable_clock yet */
+ clk_enable(dc_clk);
+ clk_enable(hhc_clk);
+ udelay(100);
+ }
+
+ if (cpu_is_omap24xx()) {
+ dc_clk = clk_get(&pdev->dev, "usb_fck");
+ hhc_clk = clk_get(&pdev->dev, "usb_l4_ick");
+ BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
+ /* can't use omap_udc_enable_clock yet */
+ clk_enable(dc_clk);
+ clk_enable(hhc_clk);
+ udelay(100);
+ }
+
INFO("OMAP UDC rev %d.%d%s\n",
UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
config->otg ? ", Mini-AB" : "");
@@ -2726,7 +2823,7 @@ static int __init omap_udc_probe(struct platform_device *pdev)
hmc = HMC_1510;
type = "(unknown)";
- if (machine_is_omap_innovator()) {
+ if (machine_is_omap_innovator() || machine_is_sx1()) {
/* just set up software VBUS detect, and then
* later rig it so we always report VBUS.
* FIXME without really sensing VBUS, we can't
@@ -2755,6 +2852,15 @@ static int __init omap_udc_probe(struct platform_device *pdev)
}
hmc = HMC_1610;
+
+ if (cpu_is_omap24xx()) {
+ /* this could be transceiverless in one of the
+ * "we don't need to know" modes.
+ */
+ type = "external";
+ goto known;
+ }
+
switch (hmc) {
case 0: /* POWERUP DEFAULT == 0 */
case 4:
@@ -2793,6 +2899,7 @@ bad_on_1710:
goto cleanup0;
}
}
+known:
INFO("hmc mode %d, %s transceiver\n", hmc, type);
/* a "gadget" abstracts/virtualizes the controller */
@@ -2817,8 +2924,8 @@ bad_on_1710:
status = request_irq(pdev->resource[1].start, omap_udc_irq,
IRQF_SAMPLE_RANDOM, driver_name, udc);
if (status != 0) {
- ERR( "can't get irq %ld, err %d\n",
- pdev->resource[1].start, status);
+ ERR("can't get irq %d, err %d\n",
+ (int) pdev->resource[1].start, status);
goto cleanup1;
}
@@ -2826,24 +2933,41 @@ bad_on_1710:
status = request_irq(pdev->resource[2].start, omap_udc_pio_irq,
IRQF_SAMPLE_RANDOM, "omap_udc pio", udc);
if (status != 0) {
- ERR( "can't get irq %ld, err %d\n",
- pdev->resource[2].start, status);
+ ERR("can't get irq %d, err %d\n",
+ (int) pdev->resource[2].start, status);
goto cleanup2;
}
#ifdef USE_ISO
status = request_irq(pdev->resource[3].start, omap_udc_iso_irq,
IRQF_DISABLED, "omap_udc iso", udc);
if (status != 0) {
- ERR("can't get irq %ld, err %d\n",
- pdev->resource[3].start, status);
+ ERR("can't get irq %d, err %d\n",
+ (int) pdev->resource[3].start, status);
goto cleanup3;
}
#endif
+ if (cpu_is_omap16xx()) {
+ udc->dc_clk = dc_clk;
+ udc->hhc_clk = hhc_clk;
+ clk_disable(hhc_clk);
+ clk_disable(dc_clk);
+ }
+
+ if (cpu_is_omap24xx()) {
+ udc->dc_clk = dc_clk;
+ udc->hhc_clk = hhc_clk;
+ /* FIXME OMAP2 don't release hhc & dc clock */
+#if 0
+ clk_disable(hhc_clk);
+ clk_disable(dc_clk);
+#endif
+ }
create_proc_file();
- device_add(&udc->gadget.dev);
- return 0;
-
+ status = device_add(&udc->gadget.dev);
+ if (!status)
+ return status;
+ /* If fail, fall through */
#ifdef USE_ISO
cleanup3:
free_irq(pdev->resource[2].start, udc);
@@ -2859,8 +2983,17 @@ cleanup1:
cleanup0:
if (xceiv)
put_device(xceiv->dev);
+
+ if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+ clk_disable(hhc_clk);
+ clk_disable(dc_clk);
+ clk_put(hhc_clk);
+ clk_put(dc_clk);
+ }
+
release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
+
return status;
}
@@ -2870,6 +3003,8 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
if (!udc)
return -ENODEV;
+ if (udc->driver)
+ return -EBUSY;
udc->done = &done;
@@ -2888,6 +3023,13 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
free_irq(pdev->resource[2].start, udc);
free_irq(pdev->resource[1].start, udc);
+ if (udc->dc_clk) {
+ if (udc->clk_requested)
+ omap_udc_enable_clock(0);
+ clk_put(udc->hhc_clk);
+ clk_put(udc->dc_clk);
+ }
+
release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
index 652ee462734..1dc398bb9ab 100644
--- a/drivers/usb/gadget/omap_udc.h
+++ b/drivers/usb/gadget/omap_udc.h
@@ -175,6 +175,9 @@ struct omap_udc {
unsigned ep0_reset_config:1;
unsigned ep0_setup:1;
struct completion *done;
+ struct clk *dc_clk;
+ struct clk *hhc_clk;
+ unsigned clk_requested:1;
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 1ed506e9598..0d225369847 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -56,7 +56,7 @@
#include <asm/arch/pxa-regs.h>
#endif
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/arch/udc.h>
@@ -1623,7 +1623,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
if (!driver
|| driver->speed < USB_SPEED_FULL
|| !driver->bind
- || !driver->unbind
|| !driver->disconnect
|| !driver->setup)
return -EINVAL;
@@ -1694,7 +1693,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!dev)
return -ENODEV;
- if (!driver || driver != dev->driver)
+ if (!driver || driver != dev->driver || !driver->unbind)
return -EINVAL;
local_irq_disable();
@@ -2638,9 +2637,11 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
{
struct pxa2xx_udc *dev = platform_get_drvdata(pdev);
+ if (dev->driver)
+ return -EBUSY;
+
udc_disable(dev);
remove_proc_files();
- usb_gadget_unregister_driver(dev->driver);
if (dev->got_irq) {
free_irq(IRQ_USB, dev);
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 208e55a667a..6c742a90922 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -43,7 +43,7 @@
#include <asm/unaligned.h>
#include <asm/uaccess.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
#include <linux/usb_gadget.h>
@@ -200,7 +200,7 @@ static void gs_unthrottle(struct tty_struct * tty);
static void gs_break(struct tty_struct *tty, int break_state);
static int gs_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
-static void gs_set_termios(struct tty_struct *tty, struct termios *old);
+static void gs_set_termios(struct tty_struct *tty, struct ktermios *old);
static int gs_send(struct gs_dev *dev);
static int gs_send_packet(struct gs_dev *dev, char *packet,
@@ -296,7 +296,7 @@ static struct usb_gadget_driver gs_gadget_driver = {
#endif /* CONFIG_USB_GADGET_DUALSPEED */
.function = GS_LONG_NAME,
.bind = gs_bind,
- .unbind = __exit_p(gs_unbind),
+ .unbind = gs_unbind,
.setup = gs_setup,
.disconnect = gs_disconnect,
.driver = {
@@ -1077,7 +1077,7 @@ static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd,
/*
* gs_set_termios
*/
-static void gs_set_termios(struct tty_struct *tty, struct termios *old)
+static void gs_set_termios(struct tty_struct *tty, struct ktermios *old)
{
}
@@ -2195,7 +2195,7 @@ static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags)
if (size == 0)
return NULL;
- gb = (struct gs_buf *)kmalloc(sizeof(struct gs_buf), kmalloc_flags);
+ gb = kmalloc(sizeof(struct gs_buf), kmalloc_flags);
if (gb == NULL)
return NULL;
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index b1735767660..3459ea6c6c0 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -14,7 +14,7 @@
#include <linux/device.h>
#include <linux/init.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 40710ea1b49..ebe04e0d287 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -84,7 +84,7 @@
#include <asm/system.h>
#include <asm/unaligned.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index cc60759083b..62711870f8e 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED
If unsure, say N.
+config USB_EHCI_BIG_ENDIAN_MMIO
+ bool
+ depends on USB_EHCI_HCD
+ default n
+
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
depends on USB
@@ -101,21 +106,48 @@ config USB_OHCI_HCD_PPC_SOC
bool "OHCI support for on-chip PPC USB controller"
depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
default y
- select USB_OHCI_BIG_ENDIAN
+ select USB_OHCI_BIG_ENDIAN_DESC
+ select USB_OHCI_BIG_ENDIAN_MMIO
---help---
Enables support for the USB controller on the MPC52xx or
STB03xxx processor chip. If unsure, say Y.
+config USB_OHCI_HCD_PPC_OF
+ bool "OHCI support for PPC USB controller on OF platform bus"
+ depends on USB_OHCI_HCD && PPC_OF
+ default y
+ ---help---
+ Enables support for the USB controller PowerPC present on the
+ OpenFirmware platform bus.
+
+config USB_OHCI_HCD_PPC_OF_BE
+ bool "Support big endian HC"
+ depends on USB_OHCI_HCD_PPC_OF
+ default y
+ select USB_OHCI_BIG_ENDIAN_DESC
+ select USB_OHCI_BIG_ENDIAN_MMIO
+
+config USB_OHCI_HCD_PPC_OF_LE
+ bool "Support little endian HC"
+ depends on USB_OHCI_HCD_PPC_OF
+ default n
+ select USB_OHCI_LITTLE_ENDIAN
+
config USB_OHCI_HCD_PCI
bool "OHCI support for PCI-bus USB controllers"
- depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+ depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
default y
select USB_OHCI_LITTLE_ENDIAN
---help---
Enables support for PCI-bus plug-in USB controller cards.
If unsure, say Y.
-config USB_OHCI_BIG_ENDIAN
+config USB_OHCI_BIG_ENDIAN_DESC
+ bool
+ depends on USB_OHCI_HCD
+ default n
+
+config USB_OHCI_BIG_ENDIAN_MMIO
bool
depends on USB_OHCI_HCD
default n
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 56349d21e6e..246afea9e83 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -43,7 +43,7 @@
*/
static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
{
- u32 params = readl (&ehci->caps->hcs_params);
+ u32 params = ehci_readl(ehci, &ehci->caps->hcs_params);
ehci_dbg (ehci,
"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
@@ -87,7 +87,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
* */
static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
{
- u32 params = readl (&ehci->caps->hcc_params);
+ u32 params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_ISOC_CACHE (params)) {
ehci_dbg (ehci,
@@ -653,7 +653,7 @@ show_registers (struct class_device *class_dev, char *buf)
}
/* Capability Registers */
- i = HC_VERSION(readl (&ehci->caps->hc_capbase));
+ i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
temp = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
"%s\n"
@@ -673,7 +673,7 @@ show_registers (struct class_device *class_dev, char *buf)
unsigned count = 256/4;
pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
- offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+ offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
while (offset && count--) {
pci_read_config_dword (pdev, offset, &cap);
switch (cap & 0xff) {
@@ -704,50 +704,50 @@ show_registers (struct class_device *class_dev, char *buf)
#endif
// FIXME interpret both types of params
- i = readl (&ehci->caps->hcs_params);
+ i = ehci_readl(ehci, &ehci->caps->hcs_params);
temp = scnprintf (next, size, "structural params 0x%08x\n", i);
size -= temp;
next += temp;
- i = readl (&ehci->caps->hcc_params);
+ i = ehci_readl(ehci, &ehci->caps->hcc_params);
temp = scnprintf (next, size, "capability params 0x%08x\n", i);
size -= temp;
next += temp;
/* Operational Registers */
temp = dbg_status_buf (scratch, sizeof scratch, label,
- readl (&ehci->regs->status));
+ ehci_readl(ehci, &ehci->regs->status));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = dbg_command_buf (scratch, sizeof scratch, label,
- readl (&ehci->regs->command));
+ ehci_readl(ehci, &ehci->regs->command));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = dbg_intr_buf (scratch, sizeof scratch, label,
- readl (&ehci->regs->intr_enable));
+ ehci_readl(ehci, &ehci->regs->intr_enable));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = scnprintf (next, size, "uframe %04x\n",
- readl (&ehci->regs->frame_index));
+ ehci_readl(ehci, &ehci->regs->frame_index));
size -= temp;
next += temp;
for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
temp = dbg_port_buf (scratch, sizeof scratch, label, i,
- readl (&ehci->regs->port_status [i - 1]));
+ ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
temp = scnprintf (next, size,
" debug control %08x\n",
- readl (&ehci->debug->control));
+ ehci_readl(ehci, &ehci->debug->control));
size -= temp;
next += temp;
}
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 1a915e982c1..a52480505f7 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
case FSL_USB2_PHY_NONE:
break;
}
- writel(portsc, &ehci->regs->port_status[port_offset]);
+ ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
}
static void mpc83xx_usb_setup(struct usb_hcd *hcd)
@@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
}
/* put controller in host mode. */
- writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+ ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
@@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
/* cache this readonly data; minimize chip reads */
- ehci->hcs_params = readl(&ehci->caps->hcs_params);
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci);
if (retval)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 025d3331368..185721dba42 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -157,12 +157,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
* before driver shutdown. But it also seems to be caused by bugs in cardbus
* bridge shutdown: shutting down the bridge before the devices using it.
*/
-static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
+static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
+ u32 mask, u32 done, int usec)
{
u32 result;
do {
- result = readl (ptr);
+ result = ehci_readl(ehci, ptr);
if (result == ~(u32)0) /* card removed */
return -ENODEV;
result &= mask;
@@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
/* force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt (struct ehci_hcd *ehci)
{
- u32 temp = readl (&ehci->regs->status);
+ u32 temp = ehci_readl(ehci, &ehci->regs->status);
/* disable any irqs left enabled by previous code */
- writel (0, &ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
if ((temp & STS_HALT) != 0)
return 0;
- temp = readl (&ehci->regs->command);
+ temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~CMD_RUN;
- writel (temp, &ehci->regs->command);
- return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+ ehci_writel(ehci, temp, &ehci->regs->command);
+ return handshake (ehci, &ehci->regs->status,
+ STS_HALT, STS_HALT, 16 * 125);
}
/* put TDI/ARC silicon into EHCI mode */
@@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd *ehci)
u32 tmp;
reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
- tmp = readl (reg_ptr);
+ tmp = ehci_readl(ehci, reg_ptr);
tmp |= 0x3;
- writel (tmp, reg_ptr);
+ ehci_writel(ehci, tmp, reg_ptr);
}
/* reset a non-running (STS_HALT == 1) controller */
static int ehci_reset (struct ehci_hcd *ehci)
{
int retval;
- u32 command = readl (&ehci->regs->command);
+ u32 command = ehci_readl(ehci, &ehci->regs->command);
command |= CMD_RESET;
dbg_cmd (ehci, "reset", command);
- writel (command, &ehci->regs->command);
+ ehci_writel(ehci, command, &ehci->regs->command);
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
ehci->next_statechange = jiffies;
- retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+ retval = handshake (ehci, &ehci->regs->command,
+ CMD_RESET, 0, 250 * 1000);
if (retval)
return retval;
@@ -236,21 +239,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
#endif
/* wait for any schedule enables/disables to take effect */
- temp = readl (&ehci->regs->command) << 10;
+ temp = ehci_readl(ehci, &ehci->regs->command) << 10;
temp &= STS_ASS | STS_PSS;
- if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+ if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
temp, 16 * 125) != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return;
}
/* then disable anything that's still active */
- temp = readl (&ehci->regs->command);
+ temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
- writel (temp, &ehci->regs->command);
+ ehci_writel(ehci, temp, &ehci->regs->command);
/* hardware can take 16 microframes to turn off ... */
- if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+ if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
0, 16 * 125) != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return;
@@ -277,11 +280,11 @@ 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);
+ u32 status = ehci_readl(ehci, &ehci->regs->status);
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
- writel (STS_IAA, &ehci->regs->status);
+ ehci_writel(ehci, STS_IAA, &ehci->regs->status);
ehci->reclaim_ready = 1;
}
}
@@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd)
(void) ehci_halt (ehci);
/* make BIOS/etc use companion controller during reboot */
- writel (0, &ehci->regs->configured_flag);
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
}
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -379,12 +382,13 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_quiesce (ehci);
ehci_reset (ehci);
- writel (0, &ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock);
/* let companion controllers work when we aren't */
- writel (0, &ehci->regs->configured_flag);
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+ remove_companion_file(ehci);
remove_debug_files (ehci);
/* root hub is shut down separately (first, when possible) */
@@ -402,7 +406,8 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci->stats.complete, ehci->stats.unlink);
#endif
- dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+ dbg_status (ehci, "ehci_stop completed",
+ ehci_readl(ehci, &ehci->regs->status));
}
/* one-time init, only for memory state */
@@ -428,7 +433,7 @@ static int ehci_init(struct usb_hcd *hcd)
return retval;
/* controllers may cache some of the periodic schedule ... */
- hcc_params = readl(&ehci->caps->hcc_params);
+ hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
ehci->i_thresh = 8;
else // N microframes cached
@@ -496,13 +501,16 @@ static int ehci_run (struct usb_hcd *hcd)
u32 temp;
u32 hcc_params;
+ hcd->uses_new_polling = 1;
+ hcd->poll_rh = 0;
+
/* EHCI spec section 4.1 */
if ((retval = ehci_reset(ehci)) != 0) {
ehci_mem_cleanup(ehci);
return retval;
}
- writel(ehci->periodic_dma, &ehci->regs->frame_list);
- writel((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+ ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
/*
* hcc_params controls whether ehci->regs->segment must (!!!)
@@ -516,9 +524,9 @@ static int ehci_run (struct usb_hcd *hcd)
* Scsi_Host.highmem_io, and so forth. It's readonly to all
* host side drivers though.
*/
- hcc_params = readl(&ehci->caps->hcc_params);
+ hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_64BIT_ADDR(hcc_params)) {
- writel(0, &ehci->regs->segment);
+ ehci_writel(ehci, 0, &ehci->regs->segment);
#if 0
// this is deeply broken on almost all architectures
if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
@@ -531,7 +539,7 @@ static int ehci_run (struct usb_hcd *hcd)
// root hub will detect new devices (why?); NEC doesn't
ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
ehci->command |= CMD_RUN;
- writel (ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
dbg_cmd (ehci, "init", ehci->command);
/*
@@ -541,23 +549,25 @@ static int ehci_run (struct usb_hcd *hcd)
* and there's no companion controller unless maybe for USB OTG.)
*/
hcd->state = HC_STATE_RUNNING;
- writel (FLAG_CF, &ehci->regs->configured_flag);
- readl (&ehci->regs->command); /* unblock posted writes */
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
- temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
+ temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
"USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
temp >> 8, temp & 0xff, DRIVER_VERSION,
ignore_oc ? ", overcurrent ignored" : "");
- writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+ ehci_writel(ehci, INTR_MASK,
+ &ehci->regs->intr_enable); /* Turn On Interrupts */
/* GRR this is run-once init(), being done every time the HC starts.
* So long as they're part of class devices, we can't do it init()
* since the class device isn't created that early.
*/
create_debug_files(ehci);
+ create_companion_file(ehci);
return 0;
}
@@ -567,12 +577,12 @@ static int ehci_run (struct usb_hcd *hcd)
static irqreturn_t ehci_irq (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- u32 status;
+ u32 status, pcd_status = 0;
int bh;
spin_lock (&ehci->lock);
- status = readl (&ehci->regs->status);
+ status = ehci_readl(ehci, &ehci->regs->status);
/* e.g. cardbus physical eject */
if (status == ~(u32) 0) {
@@ -587,8 +597,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
}
/* clear (just) interrupts */
- writel (status, &ehci->regs->status);
- readl (&ehci->regs->command); /* unblock posted write */
+ ehci_writel(ehci, status, &ehci->regs->status);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
bh = 0;
#ifdef EHCI_VERBOSE_DEBUG
@@ -617,13 +627,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* remote wakeup [4.3.1] */
if (status & STS_PCD) {
unsigned i = HCS_N_PORTS (ehci->hcs_params);
+ pcd_status = status;
/* resume root hub? */
- if (!(readl(&ehci->regs->command) & CMD_RUN))
+ if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
usb_hcd_resume_root_hub(hcd);
while (i--) {
- int pstatus = readl (&ehci->regs->port_status [i]);
+ int pstatus = ehci_readl(ehci,
+ &ehci->regs->port_status [i]);
if (pstatus & PORT_OWNER)
continue;
@@ -643,14 +655,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) {
/* bogus "fatal" IRQs appear on some chips... why? */
- status = readl (&ehci->regs->status);
- dbg_cmd (ehci, "fatal", readl (&ehci->regs->command));
+ status = ehci_readl(ehci, &ehci->regs->status);
+ dbg_cmd (ehci, "fatal", ehci_readl(ehci,
+ &ehci->regs->command));
dbg_status (ehci, "fatal", status);
if (status & STS_HALT) {
ehci_err (ehci, "fatal error\n");
dead:
ehci_reset (ehci);
- writel (0, &ehci->regs->configured_flag);
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
/* generic layer kills/unlinks all urbs, then
* uses ehci_stop to clean up the rest
*/
@@ -661,6 +674,8 @@ dead:
if (bh)
ehci_work (ehci);
spin_unlock (&ehci->lock);
+ if (pcd_status & STS_PCD)
+ usb_hcd_poll_rh_status(hcd);
return IRQ_HANDLED;
}
@@ -873,7 +888,8 @@ done:
static int ehci_get_frame (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+ return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
+ ehci->periodic_size;
}
/*-------------------------------------------------------------------------*/
@@ -899,7 +915,13 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
#endif
-#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
+#ifdef CONFIG_PPC_PS3
+#include "ehci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_sb_driver
+#endif
+
+#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+ !defined(PS3_SYSTEM_BUS_DRIVER)
#error "missing bus glue for ehci-hcd"
#endif
@@ -924,6 +946,20 @@ static int __init ehci_hcd_init(void)
#ifdef PLATFORM_DRIVER
platform_driver_unregister(&PLATFORM_DRIVER);
#endif
+ return retval;
+ }
+#endif
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+ if (retval < 0) {
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
+#endif
+ return retval;
}
#endif
@@ -939,6 +975,9 @@ static void __exit ehci_hcd_cleanup(void)
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
}
module_exit(ehci_hcd_cleanup);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index bfe5f307cba..0d83c6df1a3 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -47,7 +47,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci_quiesce (ehci);
hcd->state = HC_STATE_QUIESCING;
}
- ehci->command = readl (&ehci->regs->command);
+ ehci->command = ehci_readl(ehci, &ehci->regs->command);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
ehci_work(ehci);
@@ -60,7 +60,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci->bus_suspended = 0;
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status [port];
- u32 t1 = readl (reg) & ~PORT_RWC_BITS;
+ u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
u32 t2 = t1;
/* keep track of which ports we suspend */
@@ -79,7 +79,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
if (t1 != t2) {
ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
port + 1, t1, t2);
- writel (t2, reg);
+ ehci_writel(ehci, t2, reg);
}
}
@@ -92,8 +92,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
mask = INTR_MASK;
if (!device_may_wakeup(&hcd->self.root_hub->dev))
mask &= ~STS_PCD;
- writel(mask, &ehci->regs->intr_enable);
- readl(&ehci->regs->intr_enable);
+ ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+ ehci_readl(ehci, &ehci->regs->intr_enable);
ehci->next_statechange = jiffies + msecs_to_jiffies(10);
spin_unlock_irq (&ehci->lock);
@@ -118,26 +118,26 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
* the last user of the controller, not reset/pm hardware keeping
* state we gave to it.
*/
- temp = readl(&ehci->regs->intr_enable);
+ temp = ehci_readl(ehci, &ehci->regs->intr_enable);
ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
/* at least some APM implementations will try to deliver
* IRQs right away, so delay them until we're ready.
*/
- writel(0, &ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
/* re-init operational registers */
- writel(0, &ehci->regs->segment);
- writel(ehci->periodic_dma, &ehci->regs->frame_list);
- writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);
+ ehci_writel(ehci, 0, &ehci->regs->segment);
+ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+ ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
/* restore CMD_RUN, framelist size, and irq threshold */
- writel (ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* manually resume the ports we suspended during bus_suspend() */
i = HCS_N_PORTS (ehci->hcs_params);
while (i--) {
- temp = readl (&ehci->regs->port_status [i]);
+ temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
temp &= ~(PORT_RWC_BITS
| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
if (test_bit(i, &ehci->bus_suspended) &&
@@ -145,20 +145,20 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
temp |= PORT_RESUME;
}
- writel (temp, &ehci->regs->port_status [i]);
+ ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
}
i = HCS_N_PORTS (ehci->hcs_params);
mdelay (20);
while (i--) {
- temp = readl (&ehci->regs->port_status [i]);
+ temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
if (test_bit(i, &ehci->bus_suspended) &&
(temp & PORT_SUSPEND)) {
temp &= ~(PORT_RWC_BITS | PORT_RESUME);
- writel (temp, &ehci->regs->port_status [i]);
+ ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
}
}
- (void) readl (&ehci->regs->command);
+ (void) ehci_readl(ehci, &ehci->regs->command);
/* maybe re-activate the schedule(s) */
temp = 0;
@@ -168,14 +168,14 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
temp |= CMD_PSE;
if (temp) {
ehci->command |= temp;
- writel (ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
}
ehci->next_statechange = jiffies + msecs_to_jiffies(5);
hcd->state = HC_STATE_RUNNING;
/* Now we can safely re-enable irqs */
- writel(INTR_MASK, &ehci->regs->intr_enable);
+ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
spin_unlock_irq (&ehci->lock);
return 0;
@@ -190,9 +190,107 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
+/* Display the ports dedicated to the companion controller */
+static ssize_t show_companion(struct class_device *class_dev, char *buf)
+{
+ struct ehci_hcd *ehci;
+ int nports, index, n;
+ int count = PAGE_SIZE;
+ char *ptr = buf;
+
+ ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+ nports = HCS_N_PORTS(ehci->hcs_params);
+
+ for (index = 0; index < nports; ++index) {
+ if (test_bit(index, &ehci->companion_ports)) {
+ n = scnprintf(ptr, count, "%d\n", index + 1);
+ ptr += n;
+ count -= n;
+ }
+ }
+ return ptr - buf;
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct class_device *class_dev,
+ const char *buf, size_t count)
+{
+ struct ehci_hcd *ehci;
+ int portnum, new_owner, try;
+ u32 __iomem *status_reg;
+ u32 port_status;
+
+ ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+ new_owner = PORT_OWNER; /* Owned by companion */
+ if (sscanf(buf, "%d", &portnum) != 1)
+ return -EINVAL;
+ if (portnum < 0) {
+ portnum = - portnum;
+ new_owner = 0; /* Owned by EHCI */
+ }
+ if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+ return -ENOENT;
+ status_reg = &ehci->regs->port_status[--portnum];
+ if (new_owner)
+ set_bit(portnum, &ehci->companion_ports);
+ else
+ clear_bit(portnum, &ehci->companion_ports);
+
+ /*
+ * The controller won't set the OWNER bit if the port is
+ * enabled, so this loop will sometimes require at least two
+ * iterations: one to disable the port and one to set OWNER.
+ */
+
+ for (try = 4; try > 0; --try) {
+ spin_lock_irq(&ehci->lock);
+ port_status = ehci_readl(ehci, status_reg);
+ if ((port_status & PORT_OWNER) == new_owner
+ || (port_status & (PORT_OWNER | PORT_CONNECT))
+ == 0)
+ try = 0;
+ else {
+ port_status ^= PORT_OWNER;
+ port_status &= ~(PORT_PE | PORT_RWC_BITS);
+ ehci_writel(ehci, port_status, status_reg);
+ }
+ spin_unlock_irq(&ehci->lock);
+ if (try > 1)
+ msleep(5);
+ }
+ return count;
+}
+static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+
+static inline void create_companion_file(struct ehci_hcd *ehci)
+{
+ int i;
+
+ /* with integrated TT there is no companion! */
+ if (!ehci_is_TDI(ehci))
+ i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
+ &class_device_attr_companion);
+}
+
+static inline void remove_companion_file(struct ehci_hcd *ehci)
+{
+ /* with integrated TT there is no companion! */
+ if (!ehci_is_TDI(ehci))
+ class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
+ &class_device_attr_companion);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
static int check_reset_complete (
struct ehci_hcd *ehci,
int index,
+ u32 __iomem *status_reg,
int port_status
) {
if (!(port_status & PORT_CONNECT)) {
@@ -217,7 +315,7 @@ static int check_reset_complete (
// what happens if HCS_N_CC(params) == 0 ?
port_status |= PORT_OWNER;
port_status &= ~PORT_RWC_BITS;
- writel (port_status, &ehci->regs->port_status [index]);
+ ehci_writel(ehci, port_status, status_reg);
} else
ehci_dbg (ehci, "port %d high speed\n", index + 1);
@@ -268,22 +366,21 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
/* port N changes (bit N)? */
spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < ports; i++) {
- temp = readl (&ehci->regs->port_status [i]);
- if (temp & PORT_OWNER) {
- /* don't report this in GetPortStatus */
- if (temp & PORT_CSC) {
- temp &= ~PORT_RWC_BITS;
- temp |= PORT_CSC;
- writel (temp, &ehci->regs->port_status [i]);
- }
- continue;
- }
+ temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+
+ /*
+ * Return status information even for ports with OWNER set.
+ * Otherwise khubd wouldn't see the disconnect event when a
+ * high-speed device is switched over to the companion
+ * controller by the user.
+ */
+
if (!(temp & PORT_CONNECT))
ehci->reset_done [i] = 0;
if ((temp & mask) != 0
|| ((temp & PORT_RESUME) != 0
- && time_after (jiffies,
- ehci->reset_done [i]))) {
+ && time_after_eq(jiffies,
+ ehci->reset_done[i]))) {
if (i < 7)
buf [0] |= 1 << (i + 1);
else
@@ -345,6 +442,7 @@ static int ehci_hub_control (
) {
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int ports = HCS_N_PORTS (ehci->hcs_params);
+ u32 __iomem *status_reg = &ehci->regs->port_status[wIndex - 1];
u32 temp, status;
unsigned long flags;
int retval = 0;
@@ -373,18 +471,22 @@ static int ehci_hub_control (
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
- temp = readl (&ehci->regs->port_status [wIndex]);
- if (temp & PORT_OWNER)
- break;
+ temp = ehci_readl(ehci, status_reg);
+
+ /*
+ * Even if OWNER is set, so the port is owned by the
+ * companion controller, khubd needs to be able to clear
+ * the port-change status bits (especially
+ * USB_PORT_FEAT_C_CONNECTION).
+ */
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
- writel (temp & ~PORT_PE,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp & ~PORT_PE, status_reg);
break;
case USB_PORT_FEAT_C_ENABLE:
- writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
+ status_reg);
break;
case USB_PORT_FEAT_SUSPEND:
if (temp & PORT_RESET)
@@ -396,8 +498,8 @@ static int ehci_hub_control (
goto error;
/* resume signaling for 20 msec */
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
- writel (temp | PORT_RESUME,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp | PORT_RESUME,
+ status_reg);
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (20);
}
@@ -407,16 +509,17 @@ static int ehci_hub_control (
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
- writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci,
+ temp & ~(PORT_RWC_BITS | PORT_POWER),
+ status_reg);
break;
case USB_PORT_FEAT_C_CONNECTION:
- writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
+ status_reg);
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
- writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
+ status_reg);
break;
case USB_PORT_FEAT_C_RESET:
/* GetPortStatus clears reset */
@@ -424,7 +527,7 @@ static int ehci_hub_control (
default:
goto error;
}
- readl (&ehci->regs->command); /* unblock posted write */
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
break;
case GetHubDescriptor:
ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
@@ -440,7 +543,7 @@ static int ehci_hub_control (
goto error;
wIndex--;
status = 0;
- temp = readl (&ehci->regs->port_status [wIndex]);
+ temp = ehci_readl(ehci, status_reg);
// wPortChange bits
if (temp & PORT_CSC)
@@ -451,42 +554,55 @@ static int ehci_hub_control (
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
/* whoever resumes must GetPortStatus to complete it!! */
- if ((temp & PORT_RESUME)
- && time_after (jiffies,
- ehci->reset_done [wIndex])) {
- status |= 1 << USB_PORT_FEAT_C_SUSPEND;
- ehci->reset_done [wIndex] = 0;
+ if (temp & PORT_RESUME) {
- /* stop resume signaling */
- temp = readl (&ehci->regs->port_status [wIndex]);
- writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
- &ehci->regs->port_status [wIndex]);
- retval = handshake (
- &ehci->regs->port_status [wIndex],
- PORT_RESUME, 0, 2000 /* 2msec */);
- if (retval != 0) {
- ehci_err (ehci, "port %d resume error %d\n",
- wIndex + 1, retval);
- goto error;
+ /* Remote Wakeup received? */
+ if (!ehci->reset_done[wIndex]) {
+ /* resume signaling for 20 msec */
+ ehci->reset_done[wIndex] = jiffies
+ + msecs_to_jiffies(20);
+ /* check the port again */
+ mod_timer(&ehci_to_hcd(ehci)->rh_timer,
+ ehci->reset_done[wIndex]);
+ }
+
+ /* resume completed? */
+ else if (time_after_eq(jiffies,
+ ehci->reset_done[wIndex])) {
+ status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+ ehci->reset_done[wIndex] = 0;
+
+ /* stop resume signaling */
+ temp = ehci_readl(ehci, status_reg);
+ ehci_writel(ehci,
+ temp & ~(PORT_RWC_BITS | PORT_RESUME),
+ status_reg);
+ retval = handshake(ehci, status_reg,
+ PORT_RESUME, 0, 2000 /* 2msec */);
+ if (retval != 0) {
+ ehci_err(ehci,
+ "port %d resume error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+ temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
}
- temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
}
/* whoever resets must GetPortStatus to complete it!! */
if ((temp & PORT_RESET)
- && time_after (jiffies,
- ehci->reset_done [wIndex])) {
+ && time_after_eq(jiffies,
+ ehci->reset_done[wIndex])) {
status |= 1 << USB_PORT_FEAT_C_RESET;
ehci->reset_done [wIndex] = 0;
/* force reset to complete */
- writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
+ status_reg);
/* REVISIT: some hardware needs 550+ usec to clear
* this bit; seems too long to spin routinely...
*/
- retval = handshake (
- &ehci->regs->port_status [wIndex],
+ retval = handshake(ehci, status_reg,
PORT_RESET, 0, 750);
if (retval != 0) {
ehci_err (ehci, "port %d reset error %d\n",
@@ -495,28 +611,41 @@ static int ehci_hub_control (
}
/* see what we found out */
- temp = check_reset_complete (ehci, wIndex,
- readl (&ehci->regs->port_status [wIndex]));
+ temp = check_reset_complete (ehci, wIndex, status_reg,
+ ehci_readl(ehci, status_reg));
}
- // don't show wPortStatus if it's owned by a companion hc
- if (!(temp & PORT_OWNER)) {
- if (temp & PORT_CONNECT) {
- status |= 1 << USB_PORT_FEAT_CONNECTION;
- // status may be from integrated TT
- status |= ehci_port_speed(ehci, temp);
- }
- if (temp & PORT_PE)
- status |= 1 << USB_PORT_FEAT_ENABLE;
- if (temp & (PORT_SUSPEND|PORT_RESUME))
- status |= 1 << USB_PORT_FEAT_SUSPEND;
- if (temp & PORT_OC)
- status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
- if (temp & PORT_RESET)
- status |= 1 << USB_PORT_FEAT_RESET;
- if (temp & PORT_POWER)
- status |= 1 << USB_PORT_FEAT_POWER;
+ /* transfer dedicated ports to the companion hc */
+ if ((temp & PORT_CONNECT) &&
+ test_bit(wIndex, &ehci->companion_ports)) {
+ temp &= ~PORT_RWC_BITS;
+ temp |= PORT_OWNER;
+ ehci_writel(ehci, temp, status_reg);
+ ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1);
+ temp = ehci_readl(ehci, status_reg);
+ }
+
+ /*
+ * Even if OWNER is set, there's no harm letting khubd
+ * see the wPortStatus values (they should all be 0 except
+ * for PORT_POWER anyway).
+ */
+
+ if (temp & PORT_CONNECT) {
+ status |= 1 << USB_PORT_FEAT_CONNECTION;
+ // status may be from integrated TT
+ status |= ehci_port_speed(ehci, temp);
}
+ if (temp & PORT_PE)
+ status |= 1 << USB_PORT_FEAT_ENABLE;
+ if (temp & (PORT_SUSPEND|PORT_RESUME))
+ status |= 1 << USB_PORT_FEAT_SUSPEND;
+ if (temp & PORT_OC)
+ status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+ if (temp & PORT_RESET)
+ status |= 1 << USB_PORT_FEAT_RESET;
+ if (temp & PORT_POWER)
+ status |= 1 << USB_PORT_FEAT_POWER;
#ifndef EHCI_VERBOSE_DEBUG
if (status & ~0xffff) /* only if wPortChange is interesting */
@@ -541,7 +670,7 @@ static int ehci_hub_control (
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
- temp = readl (&ehci->regs->port_status [wIndex]);
+ temp = ehci_readl(ehci, status_reg);
if (temp & PORT_OWNER)
break;
@@ -555,13 +684,12 @@ static int ehci_hub_control (
goto error;
if (device_may_wakeup(&hcd->self.root_hub->dev))
temp |= PORT_WAKE_BITS;
- writel (temp | PORT_SUSPEND,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
- writel (temp | PORT_POWER,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp | PORT_POWER,
+ status_reg);
break;
case USB_PORT_FEAT_RESET:
if (temp & PORT_RESUME)
@@ -589,7 +717,7 @@ static int ehci_hub_control (
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (50);
}
- writel (temp, &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp, status_reg);
break;
/* For downstream facing ports (these): one hub port is put
@@ -604,13 +732,13 @@ static int ehci_hub_control (
ehci_quiesce(ehci);
ehci_halt(ehci);
temp |= selector << 16;
- writel (temp, &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp, status_reg);
break;
default:
goto error;
}
- readl (&ehci->regs->command); /* unblock posted writes */
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
break;
default:
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 4bc7970ba3e..12edc723ec7 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
if ((temp & (3 << 13)) == (1 << 13)) {
temp &= 0x1fff;
ehci->debug = ehci_to_hcd(ehci)->regs + temp;
- temp = readl(&ehci->debug->control);
+ temp = ehci_readl(ehci, &ehci->debug->control);
ehci_info(ehci, "debug port %d%s\n",
HCS_DEBUG_PORT(ehci->hcs_params),
(temp & DBGP_ENABLED)
@@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
u32 temp;
int retval;
+ switch (pdev->vendor) {
+ case PCI_VENDOR_ID_TOSHIBA_2:
+ /* celleb's companion chip */
+ if (pdev->device == 0x01b5) {
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ ehci->big_endian_mmio = 1;
+#else
+ ehci_warn(ehci,
+ "unsupported big endian Toshiba quirk\n");
+#endif
+ }
+ break;
+ }
+
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ ehci->regs = hcd->regs +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
@@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
}
/* cache this readonly data; minimize chip reads */
- ehci->hcs_params = readl(&ehci->caps->hcs_params);
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci);
if (retval)
@@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
rc = -EINVAL;
goto bail;
}
- writel (0, &ehci->regs->intr_enable);
- (void)readl(&ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ (void)ehci_readl(ehci, &ehci->regs->intr_enable);
/* make sure snapshot being resumed re-enumerates everything */
if (message.event == PM_EVENT_PRETHAW) {
@@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* If CF is still set, we maintained PCI Vaux power.
* Just undo the effect of ehci_pci_suspend().
*/
- if (readl(&ehci->regs->configured_flag) == FLAG_CF) {
+ if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
int mask = INTR_MASK;
if (!device_may_wakeup(&hcd->self.root_hub->dev))
mask &= ~STS_PCD;
- writel(mask, &ehci->regs->intr_enable);
- readl(&ehci->regs->intr_enable);
+ ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+ ehci_readl(ehci, &ehci->regs->intr_enable);
return 0;
}
@@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1);
- writel(ehci->command, &ehci->regs->command);
- writel(FLAG_CF, &ehci->regs->configured_flag);
- readl(&ehci->regs->command); /* unblock posted writes */
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
hcd->state = HC_STATE_SUSPENDED;
return 0;
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
new file mode 100644
index 00000000000..4d781a2a980
--- /dev/null
+++ b/drivers/usb/host/ehci-ps3.c
@@ -0,0 +1,193 @@
+/*
+ * PS3 EHCI Host Controller driver
+ *
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/ps3.h>
+
+static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
+{
+ int result;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ ehci->big_endian_mmio = 1;
+
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+ &ehci->caps->hc_capbase));
+
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ result = ehci_halt(ehci);
+
+ if (result)
+ return result;
+
+ result = ehci_init(hcd);
+
+ if (result)
+ return result;
+
+ ehci_port_power(ehci, 0);
+
+ return result;
+}
+
+static const struct hc_driver ps3_ehci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "PS3 EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+ .reset = ps3_ehci_hc_reset,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .get_frame_number = ehci_get_frame,
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+#if defined(CONFIG_PM)
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+#endif
+};
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+ const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+
+static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+{
+ int result;
+ struct usb_hcd *hcd;
+ unsigned int virq;
+ static u64 dummy_mask = DMA_32BIT_MASK;
+
+ if (usb_disabled()) {
+ result = -ENODEV;
+ goto fail_start;
+ }
+
+ result = ps3_mmio_region_create(dev->m_region);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+ __func__, __LINE__);
+ result = -EPERM;
+ goto fail_mmio;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+ __LINE__, dev->m_region->lpar_addr);
+
+ result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+ __func__, __LINE__, virq);
+ result = -EPERM;
+ goto fail_irq;
+ }
+
+ dev->core.power.power_state = PMSG_ON;
+ dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+ hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
+
+ if (!hcd) {
+ dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+ __LINE__);
+ result = -ENOMEM;
+ goto fail_create_hcd;
+ }
+
+ hcd->rsrc_start = dev->m_region->lpar_addr;
+ hcd->rsrc_len = dev->m_region->len;
+ hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+ if (!hcd->regs) {
+ dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+ __LINE__);
+ result = -EPERM;
+ goto fail_ioremap;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_start);
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_len);
+ dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->regs);
+ dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
+ (unsigned long)virq);
+
+ ps3_system_bus_set_driver_data(dev, hcd);
+
+ result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+ __func__, __LINE__, result);
+ goto fail_add_hcd;
+ }
+
+ return result;
+
+fail_add_hcd:
+ iounmap(hcd->regs);
+fail_ioremap:
+ usb_put_hcd(hcd);
+fail_create_hcd:
+ ps3_free_io_irq(virq);
+fail_irq:
+ ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+ return result;
+}
+
+static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+{
+ struct usb_hcd *hcd =
+ (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+ usb_put_hcd(hcd);
+ ps3_system_bus_set_driver_data(dev, NULL);
+
+ return 0;
+}
+
+MODULE_ALIAS("ps3-ehci");
+
+static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+ .match_id = PS3_MATCH_ID_EHCI,
+ .core = {
+ .name = "ps3-ehci-driver",
+ },
+ .probe = ps3_ehci_sb_probe,
+ .remove = ps3_ehci_sb_remove,
+};
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 62e46dc60e8..e7fbbd00e7c 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head = ehci->async;
timer_action_done (ehci, TIMER_ASYNC_OFF);
if (!head->qh_next.qh) {
- u32 cmd = readl (&ehci->regs->command);
+ u32 cmd = ehci_readl(ehci, &ehci->regs->command);
if (!(cmd & CMD_ASE)) {
/* in case a clear of CMD_ASE didn't take yet */
- (void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+ (void)handshake(ehci, &ehci->regs->status,
+ STS_ASS, 0, 150);
cmd |= CMD_ASE | CMD_RUN;
- writel (cmd, &ehci->regs->command);
+ ehci_writel(ehci, cmd, &ehci->regs->command);
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* posted write need not be known to HC yet ... */
}
@@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- int cmd = readl (&ehci->regs->command);
+ int cmd = ehci_readl(ehci, &ehci->regs->command);
struct ehci_qh *prev;
#ifdef DEBUG
@@ -1025,7 +1026,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
&& !ehci->reclaim) {
/* ... and CMD_IAAD clear */
- writel (cmd & ~CMD_ASE, &ehci->regs->command);
+ ehci_writel(ehci, cmd & ~CMD_ASE,
+ &ehci->regs->command);
wmb ();
// handshake later, if we need to
timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1054,8 +1056,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci->reclaim_ready = 0;
cmd |= CMD_IAAD;
- writel (cmd, &ehci->regs->command);
- (void) readl (&ehci->regs->command);
+ ehci_writel(ehci, cmd, &ehci->regs->command);
+ (void)ehci_readl(ehci, &ehci->regs->command);
timer_action (ehci, TIMER_IAA_WATCHDOG);
}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 65c402a0fa7..7b5ae7111f2 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_hcd *ehci)
/* did clearing PSE did take effect yet?
* takes effect only at frame boundaries...
*/
- status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+ status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125);
if (status != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return status;
}
- cmd = readl (&ehci->regs->command) | CMD_PSE;
- writel (cmd, &ehci->regs->command);
+ cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
+ ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... PSS happens later */
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* make sure ehci_work scans these */
- ehci->next_uframe = readl (&ehci->regs->frame_index)
- % (ehci->periodic_size << 3);
+ ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+ % (ehci->periodic_size << 3);
return 0;
}
@@ -458,14 +458,14 @@ static int disable_periodic (struct ehci_hcd *ehci)
/* did setting PSE not take effect yet?
* takes effect only at frame boundaries...
*/
- status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+ status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
if (status != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return status;
}
- cmd = readl (&ehci->regs->command) & ~CMD_PSE;
- writel (cmd, &ehci->regs->command);
+ cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
+ ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... */
ehci->next_uframe = -1;
@@ -1336,7 +1336,7 @@ iso_stream_schedule (
goto fail;
}
- now = readl (&ehci->regs->frame_index) % mod;
+ now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
/* when's the last uframe this urb could start? */
max = now + mod;
@@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci)
*/
now_uframe = ehci->next_uframe;
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
- clock = readl (&ehci->regs->frame_index);
+ clock = ehci_readl(ehci, &ehci->regs->frame_index);
else
clock = now_uframe + mod - 1;
clock %= mod;
@@ -2213,7 +2213,7 @@ restart:
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
break;
ehci->next_uframe = now_uframe;
- now = readl (&ehci->regs->frame_index) % mod;
+ now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
if (now_uframe == now)
break;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 74dbc6c8228..46fa57a520d 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -74,7 +74,11 @@ struct ehci_hcd { /* one per controller */
/* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
- unsigned long bus_suspended;
+ /* bit vectors (one bit per port) */
+ unsigned long bus_suspended; /* which ports were
+ already suspended at the start of a bus suspend */
+ unsigned long companion_ports; /* which ports are
+ dedicated to the companion controller */
/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
@@ -92,6 +96,7 @@ struct ehci_hcd { /* one per controller */
unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */
unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */
+ unsigned big_endian_mmio:1;
u8 sbrn; /* packed release number */
@@ -651,6 +656,45 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#define ehci_has_fsl_portno_bug(e) (0)
#endif
+/*
+ * While most USB host controllers implement their registers in
+ * little-endian format, a minority (celleb companion chip) implement
+ * them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ */
+
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
+#else
+#define ehci_big_endian_mmio(e) 0
+#endif
+
+static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
+ __u32 __iomem * regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ return ehci_big_endian_mmio(ehci) ?
+ readl_be(regs) :
+ readl(regs);
+#else
+ return readl(regs);
+#endif
+}
+
+static inline void ehci_writel (const struct ehci_hcd *ehci,
+ const unsigned int val, __u32 __iomem *regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ ehci_big_endian_mmio(ehci) ?
+ writel_be(val, regs) :
+ writel(val, regs);
+#else
+ writel(val, regs);
+#endif
+}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
index 9325e46a68c..282d82efc0b 100644
--- a/drivers/usb/host/hc_crisv10.c
+++ b/drivers/usb/host/hc_crisv10.c
@@ -365,7 +365,7 @@ static inline struct urb *urb_list_first(int epid)
/* Adds an urb_entry last in the list for this epid. */
static inline void urb_list_add(struct urb *urb, int epid)
{
- urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG);
+ urb_entry_t *urb_entry = kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG);
assert(urb_entry);
urb_entry->urb = urb;
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index b466581beb4..93034648727 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -170,7 +170,6 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd,
at91_stop_hc(pdev);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- disable_irq_wake(hcd->irq);
clk_put(fclk);
clk_put(iclk);
@@ -187,7 +186,6 @@ ohci_at91_start (struct usb_hcd *hcd)
{
struct at91_usbh_data *board = hcd->self.controller->platform_data;
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- struct usb_device *root = hcd->self.root_hub;
int ret;
if ((ret = ohci_init(ohci)) < 0)
@@ -221,7 +219,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
*/
.start = ohci_at91_start,
.stop = ohci_stop,
- .shutdown = ohci_shutdown,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -272,8 +270,6 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(hcd->irq);
- else
- disable_irq_wake(hcd->irq);
/*
* The integrated transceivers seem unable to notice disconnect,
@@ -294,6 +290,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(hcd->irq);
+
if (!clocked) {
clk_enable(iclk);
clk_enable(fclk);
@@ -321,18 +322,3 @@ static struct platform_driver ohci_hcd_at91_driver = {
},
};
-static int __init ohci_hcd_at91_init (void)
-{
- if (usb_disabled())
- return -ENODEV;
-
- return platform_driver_register(&ohci_hcd_at91_driver);
-}
-
-static void __exit ohci_hcd_at91_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_at91_driver);
-}
-
-module_init (ohci_hcd_at91_init);
-module_exit (ohci_hcd_at91_cleanup);
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 24e23c5783d..663a0600b6e 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -269,7 +269,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
*/
.start = ohci_au1xxx_start,
.stop = ohci_stop,
- .shutdown = ohci_shutdown,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -336,7 +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,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_au1xxx_drv_suspend, */
/*.resume = ohci_hcd_au1xxx_drv_resume, */
.driver = {
@@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_au1xxx_driver = {
},
};
-static int __init ohci_hcd_au1xxx_init (void)
-{
- pr_debug (DRIVER_INFO " (Au1xxx)");
- pr_debug ("block sizes: ed %d td %d\n",
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_au1xxx_driver);
-}
-
-static void __exit ohci_hcd_au1xxx_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_au1xxx_driver);
-}
-
-module_init (ohci_hcd_au1xxx_init);
-module_exit (ohci_hcd_au1xxx_cleanup);
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 0f47a57dac2..273d5ddb72b 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -16,7 +16,7 @@
case PIPE_CONTROL: temp = "ctrl"; break; \
case PIPE_BULK: temp = "bulk"; break; \
case PIPE_INTERRUPT: temp = "intr"; break; \
- default: temp = "isoc"; break; \
+ default: temp = "isoc"; break; \
}; temp;})
#define pipestring(pipe) edstring(usb_pipetype(pipe))
@@ -205,13 +205,13 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
(temp & RH_PS_PSSC) ? " PSSC" : "", \
(temp & RH_PS_PESC) ? " PESC" : "", \
(temp & RH_PS_CSC) ? " CSC" : "", \
- \
+ \
(temp & RH_PS_LSDA) ? " LSDA" : "", \
(temp & RH_PS_PPS) ? " PPS" : "", \
(temp & RH_PS_PRS) ? " PRS" : "", \
(temp & RH_PS_POCI) ? " POCI" : "", \
(temp & RH_PS_PSS) ? " PSS" : "", \
- \
+ \
(temp & RH_PS_PES) ? " PES" : "", \
(temp & RH_PS_CCS) ? " CCS" : "" \
);
@@ -563,7 +563,7 @@ show_periodic (struct class_device *class_dev, char *buf)
(info & ED_SKIP) ? " K" : "",
(ed->hwHeadP &
cpu_to_hc32(ohci, ED_H)) ?
- " H" : "");
+ " H" : "");
size -= temp;
next += temp;
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 1bf5e7a4e73..44c60fba76e 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -169,7 +169,7 @@ static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev)
static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct ochi_hcd *ohci = hcd_to_ohci(hcd);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
if (time_before(jiffies, ohci->next_statechange))
msleep(5);
@@ -204,7 +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,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_hcd_ep93xx_drv_suspend,
.resume = ohci_hcd_ep93xx_drv_resume,
@@ -214,15 +214,3 @@ static struct platform_driver ohci_hcd_ep93xx_driver = {
},
};
-static int __init ohci_hcd_ep93xx_init(void)
-{
- return platform_driver_register(&ohci_hcd_ep93xx_driver);
-}
-
-static void __exit ohci_hcd_ep93xx_cleanup(void)
-{
- platform_driver_unregister(&ohci_hcd_ep93xx_driver);
-}
-
-module_init(ohci_hcd_ep93xx_init);
-module_exit(ohci_hcd_ep93xx_cleanup);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index b28a9b60206..fa6a7ceaa0d 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -3,77 +3,21 @@
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
- *
+ *
* [ Initialisation is based on Linus' ]
* [ uhci code and gregs ohci fragments ]
* [ (C) Copyright 1999 Linus Torvalds ]
* [ (C) Copyright 1999 Gregory P. Smith]
- *
- *
+ *
+ *
* OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller
* interfaces (though some non-x86 Intel chips use it). It supports
* smarter hardware than UHCI. A download link for the spec available
* through the http://www.usb.org website.
*
- * History:
- *
- * 2004/03/24 LH7A404 support (Durgesh Pattamatta & Marc Singer)
- * 2004/02/04 use generic dma_* functions instead of pci_* (dsaxena@plexity.net)
- * 2003/02/24 show registers in sysfs (Kevin Brosius)
- *
- * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
- * bandwidth accounting; if debugging, show schedules in driverfs
- * 2002/07/19 fixes to management of ED and schedule state.
- * 2002/06/09 SA-1111 support (Christopher Hoover)
- * 2002/06/01 remember frame when HC won't see EDs any more; use that info
- * to fix urb unlink races caused by interrupt latency assumptions;
- * minor ED field and function naming updates
- * 2002/01/18 package as a patch for 2.5.3; this should match the
- * 2.4.17 kernel modulo some bugs being fixed.
- *
- * 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes
- * from post-2.4.5 patches.
- * 2001/09/20 URB_ZERO_PACKET support; hcca_dma portability, OPTi warning
- * 2001/09/07 match PCI PM changes, errnos from Linus' tree
- * 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify;
- * pbook pci quirks gone (please fix pbook pci sw!) (db)
- *
- * 2001/04/08 Identify version on module load (gb)
- * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
- pci_map_single (db)
- * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
- * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
- *
- * 2000/09/26 fixed races in removing the private portion of the urb
- * 2000/09/07 disable bulk and control lists when unlinking the last
- * endpoint descriptor in order to avoid unrecoverable errors on
- * the Lucent chips. (rwc@sgi)
- * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
- * urb unlink probs, indentation fixes
- * 2000/08/11 various oops fixes mostly affecting iso and cleanup from
- * device unplugs.
- * 2000/06/28 use PCI hotplug framework, for better power management
- * and for Cardbus support (David Brownell)
- * 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling
- * when the controller loses power; handle UE; cleanup; ...
- *
- * v5.2 1999/12/07 URB 3rd preview,
- * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
- * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume
- * i386: HUB, Keyboard, Mouse, Printer
- *
- * v4.3 1999/10/27 multiple HCs, bulk_request
- * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
- * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
- * v4.0 1999/08/18
- * v3.0 1999/06/25
- * v2.1 1999/05/09 code clean up
- * v2.0 1999/05/04
- * v1.0 1999/04/27 initial release
- *
* This file is licenced under the GPL.
*/
-
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
@@ -89,7 +33,7 @@
#include <linux/list.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
-#include <linux/dma-mapping.h>
+#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/reboot.h>
@@ -183,11 +127,11 @@ static int ohci_urb_enqueue (
int i, size = 0;
unsigned long flags;
int retval = 0;
-
+
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "SUB", usb_pipein (pipe));
#endif
-
+
/* every endpoint has a ed, locate and maybe (re)initialize it */
if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
return -ENOMEM;
@@ -232,7 +176,7 @@ static int ohci_urb_enqueue (
memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
INIT_LIST_HEAD (&urb_priv->pending);
urb_priv->length = size;
- urb_priv->ed = ed;
+ urb_priv->ed = ed;
/* allocate the TDs (deferring hash chain updates) */
for (i = 0; i < size; i++) {
@@ -242,7 +186,7 @@ static int ohci_urb_enqueue (
urb_free_priv (ohci, urb_priv);
return -ENOMEM;
}
- }
+ }
spin_lock_irqsave (&ohci->lock, flags);
@@ -313,13 +257,13 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
-
+
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "UNLINK", 1);
-#endif
+#endif
spin_lock_irqsave (&ohci->lock, flags);
- if (HC_IS_RUNNING(hcd->state)) {
+ if (HC_IS_RUNNING(hcd->state)) {
urb_priv_t *urb_priv;
/* Unless an IRQ completed the unlink while it was being
@@ -512,11 +456,11 @@ static int ohci_init (struct ohci_hcd *ohci)
/* Start an OHCI controller, set the BUS operational
* resets USB and controller
- * enable interrupts
+ * enable interrupts
*/
static int ohci_run (struct ohci_hcd *ohci)
{
- u32 mask, temp;
+ u32 mask, temp;
int first = ohci->fminterval == 0;
struct usb_hcd *hcd = ohci_to_hcd(ohci);
@@ -534,7 +478,7 @@ static int ohci_run (struct ohci_hcd *ohci)
/* also: power/overcurrent flags in roothub.a */
}
- /* Reset USB nearly "by the book". RemoteWakeupConnected was
+ /* Reset USB nearly "by the book". RemoteWakeupConnected was
* saved if boot firmware (BIOS/SMM/...) told us it's connected,
* or if bus glue did the same (e.g. for PCI add-in cards with
* PCI PM support).
@@ -765,9 +709,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
dl_done_list (ohci);
spin_unlock (&ohci->lock);
if (HC_IS_RUNNING(hcd->state))
- ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
+ ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
}
-
+
/* could track INTR_SO to reduce available PCI/... bandwidth */
/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
@@ -778,12 +722,12 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
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);
+ ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
spin_unlock (&ohci->lock);
if (HC_IS_RUNNING(hcd->state)) {
ohci_writel (ohci, ints, &regs->intrstatus);
- ohci_writel (ohci, OHCI_INTR_MIE, &regs->intrenable);
+ ohci_writel (ohci, OHCI_INTR_MIE, &regs->intrenable);
// flush those writes
(void) ohci_readl (ohci, &ohci->regs->control);
}
@@ -794,7 +738,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
static void ohci_stop (struct usb_hcd *hcd)
-{
+{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n",
@@ -812,8 +756,8 @@ static void ohci_stop (struct usb_hcd *hcd)
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
- dma_free_coherent (hcd->self.controller,
- sizeof *ohci->hcca,
+ dma_free_coherent (hcd->self.controller,
+ sizeof *ohci->hcca,
ohci->hcca, ohci->hcca_dma);
ohci->hcca = NULL;
ohci->hcca_dma = 0;
@@ -836,7 +780,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
* recycle any "live" eds/tds (and urbs) right away.
* later, khubd disconnect processing will recycle the other state,
* (either as disconnect/reconnect, or maybe someday as a reset).
- */
+ */
spin_lock_irq(&ohci->lock);
disable (ohci);
usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub);
@@ -875,11 +819,11 @@ static int ohci_restart (struct ohci_hcd *ohci)
/* empty the interrupt branches */
for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0;
for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;
-
+
/* no EDs to remove */
ohci->ed_rm_list = NULL;
- /* empty control and bulk lists */
+ /* empty control and bulk lists */
ohci->ed_controltail = NULL;
ohci->ed_bulktail = NULL;
@@ -911,59 +855,167 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_PCI
#include "ohci-pci.c"
+#define PCI_DRIVER ohci_pci_driver
#endif
#ifdef CONFIG_SA1111
#include "ohci-sa1111.c"
+#define SA1111_DRIVER ohci_hcd_sa1111_driver
#endif
#ifdef CONFIG_ARCH_S3C2410
#include "ohci-s3c2410.c"
+#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
#endif
#ifdef CONFIG_ARCH_OMAP
#include "ohci-omap.c"
+#define PLATFORM_DRIVER ohci_hcd_omap_driver
#endif
#ifdef CONFIG_ARCH_LH7A404
#include "ohci-lh7a404.c"
+#define PLATFORM_DRIVER ohci_hcd_lh7a404_driver
#endif
#ifdef CONFIG_PXA27x
#include "ohci-pxa27x.c"
+#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver
#endif
#ifdef CONFIG_ARCH_EP93XX
#include "ohci-ep93xx.c"
+#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver
#endif
#ifdef CONFIG_SOC_AU1X00
#include "ohci-au1xxx.c"
+#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver
+#endif
+
+#ifdef CONFIG_PNX8550
+#include "ohci-pnx8550.c"
+#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver
#endif
#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
#include "ohci-ppc-soc.c"
+#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver
#endif
#ifdef CONFIG_ARCH_AT91
#include "ohci-at91.c"
+#define PLATFORM_DRIVER ohci_hcd_at91_driver
#endif
#ifdef CONFIG_ARCH_PNX4008
#include "ohci-pnx4008.c"
+#define PLATFORM_DRIVER usb_hcd_pnx4008_driver
#endif
-#if !(defined(CONFIG_PCI) \
- || defined(CONFIG_SA1111) \
- || defined(CONFIG_ARCH_S3C2410) \
- || defined(CONFIG_ARCH_OMAP) \
- || defined (CONFIG_ARCH_LH7A404) \
- || defined (CONFIG_PXA27x) \
- || defined (CONFIG_ARCH_EP93XX) \
- || defined (CONFIG_SOC_AU1X00) \
- || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
- || defined (CONFIG_ARCH_AT91) \
- || defined (CONFIG_ARCH_PNX4008) \
- )
+
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
+#include "ohci-ppc-of.c"
+#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver
+#endif
+
+#ifdef CONFIG_PPC_PS3
+#include "ohci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver
+#endif
+
+#if !defined(PCI_DRIVER) && \
+ !defined(PLATFORM_DRIVER) && \
+ !defined(OF_PLATFORM_DRIVER) && \
+ !defined(SA1111_DRIVER) && \
+ !defined(PS3_SYSTEM_BUS_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
+
+static int __init ohci_hcd_mod_init(void)
+{
+ int retval = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
+ pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+ sizeof (struct ed), sizeof (struct td));
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+ if (retval < 0)
+ goto error_ps3;
+#endif
+
+#ifdef PLATFORM_DRIVER
+ retval = platform_driver_register(&PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_platform;
+#endif
+
+#ifdef OF_PLATFORM_DRIVER
+ retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_of_platform;
+#endif
+
+#ifdef SA1111_DRIVER
+ retval = sa1111_driver_register(&SA1111_DRIVER);
+ if (retval < 0)
+ goto error_sa1111;
+#endif
+
+#ifdef PCI_DRIVER
+ retval = pci_register_driver(&PCI_DRIVER);
+ if (retval < 0)
+ goto error_pci;
+#endif
+
+ return retval;
+
+ /* Error path */
+#ifdef PCI_DRIVER
+ error_pci:
+#endif
+#ifdef SA1111_DRIVER
+ sa1111_driver_unregister(&SA1111_DRIVER);
+ error_sa1111:
+#endif
+#ifdef OF_PLATFORM_DRIVER
+ of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+ error_of_platform:
+#endif
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+ error_platform:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ error_ps3:
+#endif
+ return retval;
+}
+module_init(ohci_hcd_mod_init);
+
+static void __exit ohci_hcd_mod_exit(void)
+{
+#ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
+#endif
+#ifdef SA1111_DRIVER
+ sa1111_driver_unregister(&SA1111_DRIVER);
+#endif
+#ifdef OF_PLATFORM_DRIVER
+ of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
+}
+module_exit(ohci_hcd_mod_exit);
+
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 2441642cb7b..216c9c9d4d6 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -1,9 +1,9 @@
/*
* OHCI HCD (Host Controller Driver) for USB.
- *
+ *
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
- *
+ *
* This file is licenced under GPL
*/
@@ -23,13 +23,13 @@
(temp & RH_PS_PSSC) ? " PSSC" : "", \
(temp & RH_PS_PESC) ? " PESC" : "", \
(temp & RH_PS_CSC) ? " CSC" : "", \
- \
+ \
(temp & RH_PS_LSDA) ? " LSDA" : "", \
(temp & RH_PS_PPS) ? " PPS" : "", \
(temp & RH_PS_PRS) ? " PRS" : "", \
(temp & RH_PS_POCI) ? " POCI" : "", \
(temp & RH_PS_PSS) ? " PSS" : "", \
- \
+ \
(temp & RH_PS_PES) ? " PES" : "", \
(temp & RH_PS_CCS) ? " CCS" : "" \
);
@@ -484,7 +484,7 @@ ohci_hub_descriptor (
temp = 0;
if (rh & RH_A_NPS) /* no power switching? */
temp |= 0x0002;
- if (rh & RH_A_PSM) /* per-port power switching? */
+ if (rh & RH_A_PSM) /* per-port power switching? */
temp |= 0x0001;
if (rh & RH_A_NOCP) /* no overcurrent reporting? */
temp |= 0x0010;
@@ -555,7 +555,7 @@ static void start_hnp(struct ohci_hcd *ohci);
#define tick_before(t1,t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
/* called from some task, normally khubd */
-static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
+static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
{
__hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];
u32 temp;
@@ -570,10 +570,13 @@ static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
/* spin until any current reset finishes */
for (;;) {
temp = ohci_readl (ohci, portstat);
+ /* handle e.g. CardBus eject */
+ if (temp == ~(u32)0)
+ return -ESHUTDOWN;
if (!(temp & RH_PS_PRS))
break;
udelay (500);
- }
+ }
if (!(temp & RH_PS_CCS))
break;
@@ -586,6 +589,8 @@ static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
now = ohci_readl(ohci, &ohci->regs->fmnumber);
} while (tick_before(now, reset_done));
/* caller synchronizes using PRSC */
+
+ return 0;
}
static int ohci_hub_control (
@@ -702,7 +707,7 @@ static int ohci_hub_control (
&ohci->regs->roothub.portstatus [wIndex]);
break;
case USB_PORT_FEAT_RESET:
- root_port_reset (ohci, wIndex);
+ retval = root_port_reset (ohci, wIndex);
break;
default:
goto error;
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index e121d97ed91..4a043abd85e 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -38,7 +38,7 @@ static void lh7a404_start_hc(struct platform_device *dev)
CSC_PWRCNT |= CSC_PWRCNT_USBH_EN; /* Enable clock */
udelay(1000);
USBH_CMDSTATUS = OHCI_HCR;
-
+
printk(KERN_DEBUG __FILE__
": Clock to USB host has been enabled \n");
}
@@ -89,7 +89,7 @@ int usb_hcd_lh7a404_probe (const struct hc_driver *driver,
retval = -EBUSY;
goto err1;
}
-
+
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
pr_debug("ioremap failed");
@@ -174,7 +174,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
*/
.start = ohci_lh7a404_start,
.stop = ohci_stop,
- .shutdown = ohci_shutdown,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -242,7 +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,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_lh7a404_drv_suspend, */
/*.resume = ohci_hcd_lh7a404_drv_resume, */
.driver = {
@@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_lh7a404_driver = {
},
};
-static int __init ohci_hcd_lh7a404_init (void)
-{
- pr_debug (DRIVER_INFO " (LH7A404)");
- pr_debug ("block sizes: ed %d td %d\n",
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_lh7a404_driver);
-}
-
-static void __exit ohci_hcd_lh7a404_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_lh7a404_driver);
-}
-
-module_init (ohci_hcd_lh7a404_init);
-module_exit (ohci_hcd_lh7a404_cleanup);
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index d976614eebd..2f20d3dc895 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -1,24 +1,24 @@
/*
* OHCI HCD (Host Controller Driver) for USB.
- *
+ *
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
- *
+ *
* This file is licenced under the GPL.
*/
/*-------------------------------------------------------------------------*/
/*
- * There's basically three types of memory:
+ * OHCI deals with three types of memory:
* - 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 ... the hcd glue or the
* device driver provides us with dma addresses
*
- * There's also PCI "register" data, which is memory mapped.
- * No memory seen by this driver is pagable.
+ * There's also "register" data, which is memory mapped.
+ * No memory seen by this driver (or any HCD) may be paged out.
*/
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 9c02177de50..5cfa3d1c441 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -447,7 +447,7 @@ static const struct hc_driver ohci_omap_hc_driver = {
.reset = ohci_omap_init,
.start = ohci_omap_start,
.stop = ohci_omap_stop,
- .shutdown = ohci_shutdown,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -533,7 +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,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_omap_suspend,
.resume = ohci_omap_resume,
@@ -544,22 +544,3 @@ static struct platform_driver ohci_hcd_omap_driver = {
},
};
-static int __init ohci_hcd_omap_init (void)
-{
- printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name);
- if (usb_disabled())
- return -ENODEV;
-
- pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_omap_driver);
-}
-
-static void __exit ohci_hcd_omap_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_omap_driver);
-}
-
-module_init (ohci_hcd_omap_init);
-module_exit (ohci_hcd_omap_cleanup);
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 87441855278..b331ac4d0d6 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -3,96 +3,171 @@
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
- *
+ *
* [ Initialisation is based on Linus' ]
* [ uhci code and gregs ohci fragments ]
* [ (C) Copyright 1999 Linus Torvalds ]
* [ (C) Copyright 1999 Gregory P. Smith]
- *
+ *
* PCI Bus Glue
*
* This file is licenced under the GPL.
*/
-
+
#ifndef CONFIG_PCI
#error "This file is PCI bus glue. CONFIG_PCI must be defined."
#endif
/*-------------------------------------------------------------------------*/
-static int
-ohci_pci_reset (struct usb_hcd *hcd)
+/* AMD 756, for most chips (early revs), corrupts register
+ * values on read ... so enable the vendor workaround.
+ */
+static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- ohci_hcd_init (ohci);
- return ohci_init (ohci);
+ ohci->flags = OHCI_QUIRK_AMD756;
+ ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
+
+ /* also erratum 10 (suspend/resume issues) */
+ device_init_wakeup(&hcd->self.root_hub->dev, 0);
+
+ return 0;
}
-static int __devinit
-ohci_pci_start (struct usb_hcd *hcd)
+/* Apple's OHCI driver has a lot of bizarre workarounds
+ * for this chip. Evidently control and bulk lists
+ * can get confused. (B&W G3 models, and ...)
+ */
+static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- int ret;
- /* REVISIT this whole block should move to reset(), which handles
- * all the other one-time init.
+ ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n");
+
+ return 0;
+}
+
+/* Check for NSC87560. We have to look at the bridge (fn1) to
+ * identify the USB (fn2). This quirk might apply to more or
+ * even all NSC stuff.
+ */
+static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
+{
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+ struct pci_dev *b;
+
+ 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) {
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ ohci->flags |= OHCI_QUIRK_SUPERIO;
+ ohci_dbg (ohci, "Using NSC SuperIO setup\n");
+ }
+ pci_dev_put(b);
+
+ return 0;
+}
+
+/* Check for Compaq's ZFMicro chipset, which needs short
+ * delays before control or bulk queues get re-activated
+ * in finish_unlinks()
+ */
+static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ ohci->flags |= OHCI_QUIRK_ZFMICRO;
+ ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+
+ return 0;
+}
+
+/* Check for Toshiba SCC OHCI which has big endian registers
+ * and little endian in memory data structures
+ */
+static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ /* That chip is only present in the southbridge of some
+ * cell based platforms which are supposed to select
+ * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if
+ * that was the case though.
*/
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ ohci->flags |= OHCI_QUIRK_BE_MMIO;
+ ohci_dbg (ohci, "enabled big endian Toshiba quirk\n");
+ return 0;
+#else
+ ohci_err (ohci, "unsupported big endian Toshiba quirk\n");
+ return -ENXIO;
+#endif
+}
+
+/* List of quirks for OHCI */
+static const struct pci_device_id ohci_pci_quirks[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c),
+ .driver_data = (unsigned long)ohci_quirk_amd756,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861),
+ .driver_data = (unsigned long)ohci_quirk_opti,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID),
+ .driver_data = (unsigned long)ohci_quirk_ns,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
+ .driver_data = (unsigned long)ohci_quirk_zfmicro,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
+ .driver_data = (unsigned long)ohci_quirk_toshiba_scc,
+ },
+ /* FIXME for some of the early AMD 760 southbridges, OHCI
+ * won't work at all. blacklist them.
+ */
+
+ {},
+};
+
+static int ohci_pci_reset (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret = 0;
+
if (hcd->self.controller) {
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+ const struct pci_device_id *quirk_id;
- /* AMD 756, for most chips (early revs), corrupts register
- * values on read ... so enable the vendor workaround.
- */
- if (pdev->vendor == PCI_VENDOR_ID_AMD
- && pdev->device == 0x740c) {
- ohci->flags = OHCI_QUIRK_AMD756;
- ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
- /* also erratum 10 (suspend/resume issues) */
- device_init_wakeup(&hcd->self.root_hub->dev, 0);
+ quirk_id = pci_match_id(ohci_pci_quirks, pdev);
+ if (quirk_id != NULL) {
+ int (*quirk)(struct usb_hcd *ohci);
+ quirk = (void *)quirk_id->driver_data;
+ ret = quirk(hcd);
}
+ }
+ if (ret == 0) {
+ ohci_hcd_init (ohci);
+ return ohci_init (ohci);
+ }
+ return ret;
+}
- /* FIXME for some of the early AMD 760 southbridges, OHCI
- * won't work at all. blacklist them.
- */
-
- /* Apple's OHCI driver has a lot of bizarre workarounds
- * for this chip. Evidently control and bulk lists
- * can get confused. (B&W G3 models, and ...)
- */
- else if (pdev->vendor == PCI_VENDOR_ID_OPTI
- && pdev->device == 0xc861) {
- ohci_dbg (ohci,
- "WARNING: OPTi workarounds unavailable\n");
- }
- /* Check for NSC87560. We have to look at the bridge (fn1) to
- * identify the USB (fn2). This quirk might apply to more or
- * even all NSC stuff.
- */
- else if (pdev->vendor == PCI_VENDOR_ID_NS) {
- struct pci_dev *b;
-
- 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);
- }
+static int __devinit ohci_pci_start (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret;
- /* Check for Compaq's ZFMicro chipset, which needs short
- * delays before control or bulk queues get re-activated
- * in finish_unlinks()
- */
- else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
- && pdev->device == 0xa0f8) {
- ohci->flags |= OHCI_QUIRK_ZFMICRO;
- ohci_dbg (ohci,
- "enabled Compaq ZFMicro chipset quirk\n");
- }
+#ifdef CONFIG_PM /* avoid warnings about unused pdev */
+ if (hcd->self.controller) {
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
/* RWC may not be set for add-in PCI cards, since boot
* firmware probably ignored them. This transfers PCI
@@ -101,16 +176,14 @@ ohci_pci_start (struct usb_hcd *hcd)
if (device_may_wakeup(&pdev->dev))
ohci->hc_control |= OHCI_CTRL_RWC;
}
+#endif /* CONFIG_PM */
- /* NOTE: there may have already been a first reset, to
- * keep bios/smm irqs from making trouble
- */
- if ((ret = ohci_run (ohci)) < 0) {
+ ret = ohci_run (ohci);
+ if (ret < 0) {
ohci_err (ohci, "can't start\n");
ohci_stop (hcd);
- return ret;
}
- return 0;
+ return ret;
}
#ifdef CONFIG_PM
@@ -238,23 +311,3 @@ static struct pci_driver ohci_pci_driver = {
.shutdown = usb_hcd_pci_shutdown,
};
-
-static int __init ohci_hcd_pci_init (void)
-{
- printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
- if (usb_disabled())
- return -ENODEV;
-
- pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
- sizeof (struct ed), sizeof (struct td));
- return pci_register_driver (&ohci_pci_driver);
-}
-module_init (ohci_hcd_pci_init);
-
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_pci_cleanup (void)
-{
- pci_unregister_driver (&ohci_pci_driver);
-}
-module_exit (ohci_hcd_pci_cleanup);
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index 7f26f9bdbaf..893b172384d 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -4,7 +4,7 @@
* driver for Philips PNX4008 USB Host
*
* Authors: Dmitry Chigirev <source@mvista.com>
- * Vitaly Wool <vitalywool@gmail.com>
+ * Vitaly Wool <vitalywool@gmail.com>
*
* register initialization is based on code examples provided by Philips
* Copyright (c) 2005 Koninklijke Philips Electronics N.V.
@@ -29,7 +29,7 @@
#include <asm/arch/irqs.h>
#include <asm/arch/gpio.h>
-#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64)
+#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64)
/* USB_CTRL bit defines */
#define USB_SLAVE_HCLK_EN (1 << 24)
@@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pnx4008_driver = {
.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-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
new file mode 100644
index 00000000000..de45eb0051a
--- /dev/null
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -0,0 +1,242 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2005 Embedded Alley Solutions, Inc.
+ *
+ * Bus Glue for PNX8550
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Russell King et al.
+ *
+ * Modified for LH7A404 from ohci-sa1111.c
+ * by Durgesh Pattamatta <pattamattad@sharpsec.com>
+ *
+ * Modified for PNX8550 from ohci-sa1111.c and sa-omap.c
+ * by Vitaly Wool <vitalywool@gmail.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/mach-pnx8550/usb.h>
+#include <asm/mach-pnx8550/int.h>
+#include <asm/mach-pnx8550/pci.h>
+
+#ifndef CONFIG_PNX8550
+#error "This file is PNX8550 bus glue. CONFIG_PNX8550 must be defined."
+#endif
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void pnx8550_start_hc(struct platform_device *dev)
+{
+ /*
+ * Set register CLK48CTL to enable and 48MHz
+ */
+ outl(0x00000003, PCI_BASE | 0x0004770c);
+
+ /*
+ * Set register CLK12CTL to enable and 48MHz
+ */
+ outl(0x00000003, PCI_BASE | 0x00047710);
+
+ udelay(100);
+}
+
+static void pnx8550_stop_hc(struct platform_device *dev)
+{
+ udelay(10);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_pnx8550_probe - initialize pnx8550-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_hcd_pnx8550_probe (const struct hc_driver *driver,
+ struct platform_device *dev)
+{
+ int retval;
+ struct usb_hcd *hcd;
+
+ if (dev->resource[0].flags != IORESOURCE_MEM ||
+ dev->resource[1].flags != IORESOURCE_IRQ) {
+ dev_err (&dev->dev,"invalid resource type\n");
+ return -ENOMEM;
+ }
+
+ hcd = usb_create_hcd (driver, &dev->dev, "pnx8550");
+ if (!hcd)
+ return -ENOMEM;
+ hcd->rsrc_start = dev->resource[0].start;
+ hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_err(&dev->dev, "request_mem_region [0x%08llx, 0x%08llx] "
+ "failed\n", hcd->rsrc_start, hcd->rsrc_len);
+ retval = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_err(&dev->dev, "ioremap [[0x%08llx, 0x%08llx] failed\n",
+ hcd->rsrc_start, hcd->rsrc_len);
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ pnx8550_start_hc(dev);
+
+ ohci_hcd_init(hcd_to_ohci(hcd));
+
+ retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+ if (retval == 0)
+ return retval;
+
+ pnx8550_stop_hc(dev);
+ iounmap(hcd->regs);
+ err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+ usb_put_hcd(hcd);
+ return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_pnx8550_remove - shutdown processing for pnx8550-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_pnx8550_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_pnx8550_remove (struct usb_hcd *hcd, struct platform_device *dev)
+{
+ usb_remove_hcd(hcd);
+ pnx8550_stop_hc(dev);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_pnx8550_start (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret;
+
+ ohci_dbg (ohci, "ohci_pnx8550_start, ohci:%p", ohci);
+
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+ if ((ret = ohci_run (ohci)) < 0) {
+ err ("can't start %s", hcd->self.bus_name);
+ ohci_stop (hcd);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_pnx8550_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "PNX8550 OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_pnx8550_start,
+ .stop = ohci_stop,
+
+ /*
+ * 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,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_pnx8550_drv_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ ret = usb_hcd_pnx8550_probe(&ohci_pnx8550_hc_driver, pdev);
+ return ret;
+}
+
+static int ohci_hcd_pnx8550_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_hcd_pnx8550_remove(hcd, pdev);
+ return 0;
+}
+
+MODULE_ALIAS("pnx8550-ohci");
+
+static struct platform_driver ohci_hcd_pnx8550_driver = {
+ .driver = {
+ .name = "pnx8550-ohci",
+ },
+ .probe = ohci_hcd_pnx8550_drv_probe,
+ .remove = ohci_hcd_pnx8550_drv_remove,
+};
+
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
new file mode 100644
index 00000000000..08e237c7bc4
--- /dev/null
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -0,0 +1,232 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Bus glue for OHCI HC on the of_platform bus
+ *
+ * Modified for of_platform bus from ohci-sa1111.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>
+
+#include <asm/of_platform.h>
+#include <asm/prom.h>
+
+
+static int __devinit
+ohci_ppc_of_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) {
+ err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct hc_driver ohci_ppc_of_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "OF OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_ppc_of_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,
+};
+
+
+static int __devinit
+ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct device_node *dn = op->node;
+ struct usb_hcd *hcd;
+ struct ohci_hcd *ohci;
+ struct resource res;
+ int irq;
+
+ int rv;
+ int is_bigendian;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ is_bigendian =
+ device_is_compatible(dn, "ohci-bigendian") ||
+ device_is_compatible(dn, "ohci-be");
+
+ dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+
+ rv = of_address_to_resource(dn, 0, &res);
+ if (rv)
+ return rv;
+
+ hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res.start;
+ hcd->rsrc_len = res.end - res.start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+ rv = -EBUSY;
+ goto err_rmr;
+ }
+
+ irq = irq_of_parse_and_map(dn, 0);
+ if (irq == NO_IRQ) {
+ printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+ rv = -EBUSY;
+ goto err_irq;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ printk(KERN_ERR __FILE__ ": ioremap failed\n");
+ rv = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ ohci = hcd_to_ohci(hcd);
+ if (is_bigendian)
+ ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+ ohci_hcd_init(ohci);
+
+ rv = usb_add_hcd(hcd, irq, 0);
+ if (rv == 0)
+ return 0;
+
+ iounmap(hcd->regs);
+err_ioremap:
+ irq_dispose_mapping(irq);
+err_irq:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+ usb_put_hcd(hcd);
+
+ return rv;
+}
+
+static int ohci_hcd_ppc_of_remove(struct of_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+ dev_set_drvdata(&op->dev, NULL);
+
+ dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
+
+ usb_remove_hcd(hcd);
+
+ iounmap(hcd->regs);
+ irq_dispose_mapping(hcd->irq);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+
+ return 0;
+}
+
+
+static struct of_device_id ohci_hcd_ppc_of_match[] = {
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
+ {
+ .name = "usb",
+ .compatible = "ohci-bigendian",
+ },
+ {
+ .name = "usb",
+ .compatible = "ohci-be",
+ },
+#endif
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
+ {
+ .name = "usb",
+ .compatible = "ohci-littledian",
+ },
+ {
+ .name = "usb",
+ .compatible = "ohci-le",
+ },
+#endif
+ {},
+};
+MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
+
+#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
+ !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
+#error "No endianess selected for ppc-of-ohci"
+#endif
+
+
+static struct of_platform_driver ohci_hcd_ppc_of_driver = {
+ .name = "ppc-of-ohci",
+ .match_table = ohci_hcd_ppc_of_match,
+ .probe = ohci_hcd_ppc_of_probe,
+ .remove = ohci_hcd_ppc_of_remove,
+ .shutdown = ohci_hcd_ppc_of_shutdown,
+#ifdef CONFIG_PM
+ /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
+ /*.resume = ohci_hcd_ppc_soc_drv_resume,*/
+#endif
+ .driver = {
+ .name = "ppc-of-ohci",
+ .owner = THIS_MODULE,
+ },
+};
+
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index d9d1ae236bd..1a2e1777ca6 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -5,7 +5,7 @@
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
* (C) Copyright 2002 Hewlett-Packard Company
* (C) Copyright 2003-2005 MontaVista Software Inc.
- *
+ *
* Bus Glue for PPC On-Chip OHCI driver
* Tested on Freescale MPC5200 and IBM STB04xxx
*
@@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
}
ohci = hcd_to_ohci(hcd);
- ohci->flags |= OHCI_BIG_ENDIAN;
+ ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
ohci_hcd_init(ohci);
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
@@ -85,7 +85,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
- usb_put_hcd(hcd);
+ usb_put_hcd(hcd);
return retval;
}
@@ -148,7 +148,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/
.start = ohci_ppc_soc_start,
.stop = ohci_stop,
- .shutdown = ohci_shutdown,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -197,7 +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,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
/*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
/*.resume = ohci_hcd_ppc_soc_drv_resume,*/
@@ -208,19 +208,3 @@ static struct platform_driver ohci_hcd_ppc_soc_driver = {
},
};
-static int __init ohci_hcd_ppc_soc_init(void)
-{
- pr_debug(DRIVER_INFO " (PPC SOC)\n");
- pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
- sizeof(struct td));
-
- return platform_driver_register(&ohci_hcd_ppc_soc_driver);
-}
-
-static void __exit ohci_hcd_ppc_soc_cleanup(void)
-{
- platform_driver_unregister(&ohci_hcd_ppc_soc_driver);
-}
-
-module_init(ohci_hcd_ppc_soc_init);
-module_exit(ohci_hcd_ppc_soc_cleanup);
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
new file mode 100644
index 00000000000..62283a3926d
--- /dev/null
+++ b/drivers/usb/host/ohci-ps3.c
@@ -0,0 +1,196 @@
+/*
+ * PS3 OHCI Host Controller driver
+ *
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/ps3.h>
+
+static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ ohci->flags |= OHCI_QUIRK_BE_MMIO;
+ ohci_hcd_init(ohci);
+ return ohci_init(ohci);
+}
+
+static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
+{
+ int result;
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ /* Handle root hub init quirk in spider south bridge. */
+ /* Also set PwrOn2PwrGood to 0x7f (254ms). */
+
+ ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM,
+ &ohci->regs->roothub.a);
+ ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b);
+
+ result = ohci_run(ohci);
+
+ if (result < 0) {
+ err("can't start %s", hcd->self.bus_name);
+ ohci_stop(hcd);
+ }
+
+ return result;
+}
+
+static const struct hc_driver ps3_ohci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "PS3 OHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+ .irq = ohci_irq,
+ .flags = HCD_MEMORY | HCD_USB11,
+ .reset = ps3_ohci_hc_reset,
+ .start = ps3_ohci_hc_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,
+ .start_port_reset = ohci_start_port_reset,
+#if defined(CONFIG_PM)
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+};
+
+/* redefine dev_dbg to do a syntax check */
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+ const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+{
+ int result;
+ struct usb_hcd *hcd;
+ unsigned int virq;
+ static u64 dummy_mask = DMA_32BIT_MASK;
+
+ if (usb_disabled()) {
+ result = -ENODEV;
+ goto fail_start;
+ }
+
+ result = ps3_mmio_region_create(dev->m_region);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+ __func__, __LINE__);
+ result = -EPERM;
+ goto fail_mmio;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+ __LINE__, dev->m_region->lpar_addr);
+
+ result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+ __func__, __LINE__, virq);
+ result = -EPERM;
+ goto fail_irq;
+ }
+
+ dev->core.power.power_state = PMSG_ON;
+ dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+ hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id);
+
+ if (!hcd) {
+ dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+ __LINE__);
+ result = -ENOMEM;
+ goto fail_create_hcd;
+ }
+
+ hcd->rsrc_start = dev->m_region->lpar_addr;
+ hcd->rsrc_len = dev->m_region->len;
+ hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+ if (!hcd->regs) {
+ dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+ __LINE__);
+ result = -EPERM;
+ goto fail_ioremap;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_start);
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_len);
+ dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->regs);
+ dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
+ (unsigned long)virq);
+
+ ps3_system_bus_set_driver_data(dev, hcd);
+
+ result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+ __func__, __LINE__, result);
+ goto fail_add_hcd;
+ }
+
+ return result;
+
+fail_add_hcd:
+ iounmap(hcd->regs);
+fail_ioremap:
+ usb_put_hcd(hcd);
+fail_create_hcd:
+ ps3_free_io_irq(virq);
+fail_irq:
+ ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+ return result;
+}
+
+static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+{
+ struct usb_hcd *hcd =
+ (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+ usb_put_hcd(hcd);
+ ps3_system_bus_set_driver_data(dev, NULL);
+
+ return 0;
+}
+
+MODULE_ALIAS("ps3-ohci");
+
+static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+ .match_id = PS3_MATCH_ID_OHCI,
+ .core = {
+ .name = "ps3-ohci-driver",
+ },
+ .probe = ps3_ohci_sb_probe,
+ .remove = ps3_ohci_sb_remove,
+};
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index e176b04d7ae..f1563dc319d 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -47,7 +47,7 @@ static int pxa27x_ohci_select_pmm( int mode )
switch ( mode ) {
case PMM_NPS_MODE:
UHCRHDA |= RH_A_NPS;
- break;
+ break;
case PMM_GLOBAL_MODE:
UHCRHDA &= ~(RH_A_NPS & RH_A_PSM);
break;
@@ -60,7 +60,7 @@ static int pxa27x_ohci_select_pmm( int mode )
break;
default:
printk( KERN_ERR
- "Invalid mode %d, set to non-power switch mode.\n",
+ "Invalid mode %d, set to non-power switch mode.\n",
mode );
UHCRHDA |= RH_A_NPS;
@@ -270,7 +270,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/
.start = ohci_pxa27x_start,
.stop = ohci_stop,
- .shutdown = ohci_shutdown,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -359,9 +359,9 @@ 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,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
- .suspend = ohci_hcd_pxa27x_drv_suspend,
+ .suspend = ohci_hcd_pxa27x_drv_suspend,
.resume = ohci_hcd_pxa27x_drv_resume,
#endif
.driver = {
@@ -369,19 +369,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
},
};
-static int __init ohci_hcd_pxa27x_init (void)
-{
- pr_debug (DRIVER_INFO " (pxa27x)");
- pr_debug ("block sizes: ed %d td %d\n",
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_pxa27x_driver);
-}
-
-static void __exit ohci_hcd_pxa27x_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_pxa27x_driver);
-}
-
-module_init (ohci_hcd_pxa27x_init);
-module_exit (ohci_hcd_pxa27x_cleanup);
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index fe1fe2f97cb..830a3fe8615 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -1,9 +1,9 @@
/*
* OHCI HCD (Host Controller Driver) for USB.
- *
+ *
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
- *
+ *
* This file is licenced under the GPL.
*/
@@ -89,7 +89,7 @@ __acquires(ohci->lock)
/*-------------------------------------------------------------------------*
* ED handling functions
- *-------------------------------------------------------------------------*/
+ *-------------------------------------------------------------------------*/
/* search for the right schedule branch to use for a periodic ed.
* does some load balancing; returns the branch, or negative errno.
@@ -107,7 +107,6 @@ static int balance (struct ohci_hcd *ohci, int interval, int load)
*/
for (i = 0; i < interval ; i++) {
if (branch < 0 || ohci->load [branch] > ohci->load [i]) {
-#if 1 /* CONFIG_USB_BANDWIDTH */
int j;
/* usb 1.1 says 90% of one frame */
@@ -117,8 +116,7 @@ static int balance (struct ohci_hcd *ohci, int interval, int load)
}
if (j < NUM_INTS)
continue;
-#endif
- branch = i;
+ branch = i;
}
}
return branch;
@@ -171,7 +169,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
/* link an ed into one of the HC chains */
static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
-{
+{
int branch;
if (ohci_to_hcd(ohci)->state == HC_STATE_QUIESCING)
@@ -248,7 +246,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
}
ed->branch = branch;
periodic_link (ohci, ed);
- }
+ }
/* the HC may not see the schedule updates yet, but if it does
* then they'll be properly ordered.
@@ -277,7 +275,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
*prev = ed->ed_next;
}
ohci->load [i] -= ed->load;
- }
+ }
ohci_to_hcd(ohci)->self.bandwidth_allocated -= ed->load / ed->interval;
ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n",
@@ -285,7 +283,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
ed, ed->branch, ed->load, ed->interval);
}
-/* unlink an ed from one of the HC chains.
+/* unlink an ed from one of the HC chains.
* just the link to the ed is unlinked.
* the link from the ed still points to another operational ed or 0
* so the HC can eventually finish the processing of the unlinked ed
@@ -307,7 +305,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
* When finish_unlinks() runs later, after SOF interrupt, it will often
* complete one or more URB unlinks before making that state change.
*/
-static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
+static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
{
ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP);
wmb ();
@@ -397,7 +395,7 @@ static struct ed *ed_get (
unsigned int pipe,
int interval
) {
- struct ed *ed;
+ struct ed *ed;
unsigned long flags;
spin_lock_irqsave (&ohci->lock, flags);
@@ -413,9 +411,9 @@ static struct ed *ed_get (
goto done;
}
- /* dummy td; end of td list for ed */
+ /* dummy td; end of td list for ed */
td = td_alloc (ohci, GFP_ATOMIC);
- if (!td) {
+ if (!td) {
/* out of memory */
ed_free (ohci, ed);
ed = NULL;
@@ -462,7 +460,7 @@ static struct ed *ed_get (
done:
spin_unlock_irqrestore (&ohci->lock, flags);
- return ed;
+ return ed;
}
/*-------------------------------------------------------------------------*/
@@ -474,7 +472,7 @@ done:
* and that ed->state is ED_OPER
*/
static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed)
-{
+{
ed->hwINFO |= cpu_to_hc32 (ohci, ED_DEQUEUE);
ed_deschedule (ohci, ed);
@@ -541,7 +539,7 @@ td_fill (struct ohci_hcd *ohci, u32 info,
td->ed = urb_priv->ed;
td->next_dl_td = NULL;
td->index = index;
- td->urb = urb;
+ td->urb = urb;
td->data_dma = data;
if (!len)
data = 0;
@@ -553,8 +551,8 @@ td_fill (struct ohci_hcd *ohci, u32 info,
(data & 0x0FFF) | 0xE000);
td->ed->last_iso = info & 0xffff;
} else {
- td->hwCBP = cpu_to_hc32 (ohci, data);
- }
+ td->hwCBP = cpu_to_hc32 (ohci, data);
+ }
if (data)
td->hwBE = cpu_to_hc32 (ohci, data + len - 1);
else
@@ -597,7 +595,7 @@ static void td_submit_urb (
* use the device toggle bits for resetting, and rely on the fact
* that resetting toggle is meaningless if the endpoint is active.
*/
- if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) {
+ if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) {
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
is_out, 1);
urb_priv->ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_C);
@@ -721,16 +719,16 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
list_del (&td->td_list);
/* ISO ... drivers see per-TD length/status */
- if (tdINFO & TD_ISO) {
- u16 tdPSW = ohci_hwPSW (ohci, td, 0);
+ if (tdINFO & TD_ISO) {
+ u16 tdPSW = ohci_hwPSW (ohci, td, 0);
int dlen = 0;
/* NOTE: assumes FC in tdINFO == 0, and that
* only the first of 0..MAXPSW psws is used.
*/
- cc = (tdPSW >> 12) & 0xF;
- if (tdINFO & TD_CC) /* hc didn't touch? */
+ cc = (tdPSW >> 12) & 0xF;
+ if (tdINFO & TD_CC) /* hc didn't touch? */
return;
if (usb_pipeout (urb->pipe))
@@ -758,7 +756,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
int type = usb_pipetype (urb->pipe);
u32 tdBE = hc32_to_cpup (ohci, &td->hwBE);
- cc = TD_CC_GET (tdINFO);
+ cc = TD_CC_GET (tdINFO);
/* update packet status if needed (short is normally ok) */
if (cc == TD_DATAUNDERRUN
@@ -787,7 +785,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
urb, td, 1 + td->index, cc,
urb->actual_length,
urb->transfer_buffer_length);
- }
+ }
}
/*-------------------------------------------------------------------------*/
@@ -795,7 +793,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
static inline struct td *
ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
{
- struct urb *urb = td->urb;
+ struct urb *urb = td->urb;
struct ed *ed = td->ed;
struct list_head *tmp = td->td_list.next;
__hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
@@ -805,7 +803,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
*/
ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP);
wmb ();
- ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
+ ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
/* put any later tds from this urb onto the donelist, after 'td',
* order won't matter here: no errors, and nothing was transferred.
@@ -833,7 +831,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
info &= ~cpu_to_hc32 (ohci, TD_CC);
next->hwINFO = info;
- next->next_dl_td = rev;
+ next->next_dl_td = rev;
rev = next;
ed->hwHeadP = next->hwNextTD | toggle;
@@ -881,8 +879,8 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
/* get TD from hc's singly linked list, and
* prepend to ours. ed->td_list changes later.
*/
- while (td_dma) {
- int cc;
+ while (td_dma) {
+ int cc;
td = dma_to_td (ohci, td_dma);
if (!td) {
@@ -901,10 +899,10 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
td_rev = ed_halted (ohci, td, cc, td_rev);
- td->next_dl_td = td_rev;
+ td->next_dl_td = td_rev;
td_rev = td;
td_dma = hc32_to_cpup (ohci, &td->hwNextTD);
- }
+ }
return td_rev;
}
@@ -1013,9 +1011,9 @@ rescan_this:
if (modified)
goto rescan_all;
- }
+ }
- /* maybe reenable control and bulk lists */
+ /* maybe reenable control and bulk lists */
if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state)
&& ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING
&& !ohci->ed_rm_list) {
@@ -1041,20 +1039,20 @@ rescan_this:
&ohci->regs->ed_bulkcurrent);
}
}
-
+
/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
if (control) {
ohci->hc_control |= control;
if (ohci->flags & OHCI_QUIRK_ZFMICRO)
mdelay(1);
- ohci_writel (ohci, ohci->hc_control,
- &ohci->regs->control);
- }
+ ohci_writel (ohci, ohci->hc_control,
+ &ohci->regs->control);
+ }
if (command) {
if (ohci->flags & OHCI_QUIRK_ZFMICRO)
mdelay(1);
- ohci_writel (ohci, command, &ohci->regs->cmdstatus);
- }
+ ohci_writel (ohci, command, &ohci->regs->cmdstatus);
+ }
}
}
@@ -1074,19 +1072,19 @@ dl_done_list (struct ohci_hcd *ohci)
{
struct td *td = dl_reverse_done_list (ohci);
- while (td) {
+ while (td) {
struct td *td_next = td->next_dl_td;
struct urb *urb = td->urb;
urb_priv_t *urb_priv = urb->hcpriv;
struct ed *ed = td->ed;
/* update URB's length and status from TD */
- td_done (ohci, urb, td);
- urb_priv->td_cnt++;
+ td_done (ohci, urb, td);
+ urb_priv->td_cnt++;
/* If all this urb's TDs are done, call complete() */
- if (urb_priv->td_cnt == urb_priv->length)
- finish_urb (ohci, urb);
+ if (urb_priv->td_cnt == urb_priv->length)
+ finish_urb (ohci, urb);
/* clean schedule: unlink EDs that are no longer busy */
if (list_empty (&ed->td_list)) {
@@ -1094,25 +1092,26 @@ dl_done_list (struct ohci_hcd *ohci)
start_ed_unlink (ohci, ed);
/* ... reenabling halted EDs only after fault cleanup */
- } else if ((ed->hwINFO & cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE))
+ } else if ((ed->hwINFO & cpu_to_hc32 (ohci,
+ ED_SKIP | ED_DEQUEUE))
== cpu_to_hc32 (ohci, ED_SKIP)) {
td = list_entry (ed->td_list.next, struct td, td_list);
- if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
+ if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
/* ... hc may need waking-up */
switch (ed->type) {
case PIPE_CONTROL:
ohci_writel (ohci, OHCI_CLF,
- &ohci->regs->cmdstatus);
+ &ohci->regs->cmdstatus);
break;
case PIPE_BULK:
ohci_writel (ohci, OHCI_BLF,
- &ohci->regs->cmdstatus);
+ &ohci->regs->cmdstatus);
break;
}
}
}
- td = td_next;
- }
+ td = td_next;
+ }
}
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 59e436424d4..6829814b7aa 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -447,7 +447,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/
.start = ohci_s3c2410_start,
.stop = ohci_stop,
- .shutdown = ohci_shutdown,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -492,7 +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,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_s3c2410_drv_suspend, */
/*.resume = ohci_hcd_s3c2410_drv_resume, */
.driver = {
@@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s3c2410_driver = {
},
};
-static int __init ohci_hcd_s3c2410_init (void)
-{
- return platform_driver_register(&ohci_hcd_s3c2410_driver);
-}
-
-static void __exit ohci_hcd_s3c2410_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_s3c2410_driver);
-}
-
-module_init (ohci_hcd_s3c2410_init);
-module_exit (ohci_hcd_s3c2410_cleanup);
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 71371de32ad..0f48f2d9922 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -4,7 +4,7 @@
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
* (C) Copyright 2002 Hewlett-Packard Company
- *
+ *
* SA1111 Bus Glue
*
* Written by Christopher Hoover <ch@hpl.hp.com>
@@ -12,7 +12,7 @@
*
* This file is licenced under the GPL.
*/
-
+
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/arch/assabet.h>
@@ -31,7 +31,7 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
{
unsigned int usb_rst = 0;
- printk(KERN_DEBUG __FILE__
+ printk(KERN_DEBUG __FILE__
": starting SA-1111 OHCI USB Controller\n");
#ifdef CONFIG_SA1100_BADGE4
@@ -65,7 +65,7 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
static void sa1111_stop_hc(struct sa1111_dev *dev)
{
unsigned int usb_rst;
- printk(KERN_DEBUG __FILE__
+ printk(KERN_DEBUG __FILE__
": stopping SA-1111 OHCI USB Controller\n");
/*
@@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = {
.remove = ohci_hcd_sa1111_drv_remove,
};
-static int __init ohci_hcd_sa1111_init (void)
-{
- dbg (DRIVER_INFO " (SA-1111)");
- dbg ("block sizes: ed %d td %d",
- sizeof (struct ed), sizeof (struct td));
-
- return sa1111_driver_register(&ohci_hcd_sa1111_driver);
-}
-
-static void __exit ohci_hcd_sa1111_cleanup (void)
-{
- sa1111_driver_unregister(&ohci_hcd_sa1111_driver);
-}
-
-module_init (ohci_hcd_sa1111_init);
-module_exit (ohci_hcd_sa1111_cleanup);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index a2f42a2f47c..c2b5ecfe5e9 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -1,9 +1,9 @@
/*
* OHCI HCD (Host Controller Driver) for USB.
- *
+ *
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
- *
+ *
* This file is licenced under the GPL.
*/
@@ -14,7 +14,7 @@
*/
typedef __u32 __bitwise __hc32;
typedef __u16 __bitwise __hc16;
-
+
/*
* OHCI Endpoint Descriptor (ED) ... holds TD queue
* See OHCI spec, section 4.2
@@ -24,7 +24,7 @@ typedef __u16 __bitwise __hc16;
*/
struct ed {
/* first fields are hardware-specified */
- __hc32 hwINFO; /* endpoint config bitmap */
+ __hc32 hwINFO; /* endpoint config bitmap */
/* info bits defined by hcd */
#define ED_DEQUEUE (1 << 27)
/* info bits defined by the hardware */
@@ -52,11 +52,11 @@ struct ed {
* usually: OPER --> UNLINK --> (IDLE | OPER) --> ...
*/
u8 state; /* ED_{IDLE,UNLINK,OPER} */
-#define ED_IDLE 0x00 /* NOT linked to HC */
-#define ED_UNLINK 0x01 /* being unlinked from hc */
+#define ED_IDLE 0x00 /* NOT linked to HC */
+#define ED_UNLINK 0x01 /* being unlinked from hc */
#define ED_OPER 0x02 /* IS linked to hc */
- u8 type; /* PIPE_{BULK,...} */
+ u8 type; /* PIPE_{BULK,...} */
/* periodic scheduling params (for intr and iso) */
u8 branch;
@@ -70,7 +70,7 @@ struct ed {
#define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */
-
+
/*
* OHCI Transfer Descriptor (TD) ... one per transfer segment
* See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt)
@@ -107,22 +107,22 @@ struct td {
/* (no hwINFO #defines yet for iso tds) */
- __hc32 hwCBP; /* Current Buffer Pointer (or 0) */
- __hc32 hwNextTD; /* Next TD Pointer */
- __hc32 hwBE; /* Memory Buffer End Pointer */
+ __hc32 hwCBP; /* Current Buffer Pointer (or 0) */
+ __hc32 hwNextTD; /* Next TD Pointer */
+ __hc32 hwBE; /* Memory Buffer End Pointer */
/* PSW is only for ISO. Only 1 PSW entry is used, but on
* big-endian PPC hardware that's the second entry.
*/
#define MAXPSW 2
- __hc16 hwPSW [MAXPSW];
+ __hc16 hwPSW [MAXPSW];
/* rest are purely for the driver's use */
- __u8 index;
- struct ed *ed;
- struct td *td_hash; /* dma-->td hashtable */
- struct td *next_dl_td;
- struct urb *urb;
+ __u8 index;
+ struct ed *ed;
+ struct td *td_hash; /* dma-->td hashtable */
+ struct td *next_dl_td;
+ struct urb *urb;
dma_addr_t td_dma; /* addr of this TD */
dma_addr_t data_dma; /* addr of data it points to */
@@ -152,8 +152,8 @@ struct td {
#define TD_NOTACCESSED 0x0F
-/* map OHCI TD status codes (CC) to errno values */
-static const int cc_to_error [16] = {
+/* map OHCI TD status codes (CC) to errno values */
+static const int cc_to_error [16] = {
/* No Error */ 0,
/* CRC Error */ -EILSEQ,
/* Bit Stuff */ -EPROTO,
@@ -169,7 +169,7 @@ static const int cc_to_error [16] = {
/* BufferOver */ -ECOMM,
/* BuffUnder */ -ENOSR,
/* (for HCD) */ -EALREADY,
- /* (for HCD) */ -EALREADY
+ /* (for HCD) */ -EALREADY
};
@@ -182,7 +182,7 @@ struct ohci_hcca {
#define NUM_INTS 32
__hc32 int_table [NUM_INTS]; /* periodic schedule */
- /*
+ /*
* OHCI defines u16 frame_no, followed by u16 zero pad.
* Since some processors can't do 16 bit bus accesses,
* portable access must be a 32 bits wide.
@@ -262,10 +262,10 @@ struct ohci_regs {
* HcCommandStatus (cmdstatus) register masks
*/
#define OHCI_HCR (1 << 0) /* host controller reset */
-#define OHCI_CLF (1 << 1) /* control list filled */
-#define OHCI_BLF (1 << 2) /* bulk list filled */
-#define OHCI_OCR (1 << 3) /* ownership change request */
-#define OHCI_SOC (3 << 16) /* scheduling overrun count */
+#define OHCI_CLF (1 << 1) /* control list filled */
+#define OHCI_BLF (1 << 2) /* bulk list filled */
+#define OHCI_OCR (1 << 3) /* ownership change request */
+#define OHCI_SOC (3 << 16) /* scheduling overrun count */
/*
* masks used with interrupt registers:
@@ -285,20 +285,20 @@ struct ohci_regs {
/* OHCI ROOT HUB REGISTER MASKS */
-
+
/* roothub.portstatus [i] bits */
-#define RH_PS_CCS 0x00000001 /* current connect status */
-#define RH_PS_PES 0x00000002 /* port enable status*/
-#define RH_PS_PSS 0x00000004 /* port suspend status */
-#define RH_PS_POCI 0x00000008 /* port over current indicator */
-#define RH_PS_PRS 0x00000010 /* port reset status */
-#define RH_PS_PPS 0x00000100 /* port power status */
-#define RH_PS_LSDA 0x00000200 /* low speed device attached */
-#define RH_PS_CSC 0x00010000 /* connect status change */
-#define RH_PS_PESC 0x00020000 /* port enable status change */
-#define RH_PS_PSSC 0x00040000 /* port suspend status change */
-#define RH_PS_OCIC 0x00080000 /* over current indicator change */
-#define RH_PS_PRSC 0x00100000 /* port reset status change */
+#define RH_PS_CCS 0x00000001 /* current connect status */
+#define RH_PS_PES 0x00000002 /* port enable status*/
+#define RH_PS_PSS 0x00000004 /* port suspend status */
+#define RH_PS_POCI 0x00000008 /* port over current indicator */
+#define RH_PS_PRS 0x00000010 /* port reset status */
+#define RH_PS_PPS 0x00000100 /* port power status */
+#define RH_PS_LSDA 0x00000200 /* low speed device attached */
+#define RH_PS_CSC 0x00010000 /* connect status change */
+#define RH_PS_PESC 0x00020000 /* port enable status change */
+#define RH_PS_PSSC 0x00040000 /* port suspend status change */
+#define RH_PS_OCIC 0x00080000 /* over current indicator change */
+#define RH_PS_PRSC 0x00100000 /* port reset status change */
/* roothub.status bits */
#define RH_HS_LPS 0x00000001 /* local power status */
@@ -333,7 +333,7 @@ typedef struct urb_priv {
} urb_priv_t;
#define TD_HASH_SIZE 64 /* power'o'two */
-// sizeof (struct td) ~= 64 == 2^6 ...
+// sizeof (struct td) ~= 64 == 2^6 ...
#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE)
@@ -364,11 +364,11 @@ struct ohci_hcd {
struct ed *ed_bulktail; /* last in bulk list */
struct ed *ed_controltail; /* last in ctrl list */
- struct ed *periodic [NUM_INTS]; /* shadow int_table */
+ struct ed *periodic [NUM_INTS]; /* shadow int_table */
/*
* OTG controllers and transceivers need software interaction;
- * other external transceivers should be software-transparent
+ * other external transceivers should be software-transparent
*/
struct otg_transceiver *transceiver;
@@ -385,7 +385,7 @@ struct ohci_hcd {
*/
int num_ports;
int load [NUM_INTS];
- u32 hc_control; /* copy of hc control reg */
+ u32 hc_control; /* copy of hc control reg */
unsigned long next_statechange; /* suspend/resume */
u32 fminterval; /* saved register */
unsigned autostop:1; /* rh auto stopping/stopped */
@@ -394,8 +394,9 @@ struct ohci_hcd {
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */
#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */
-#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */
-#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/
+#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */
+#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */
+#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
// there are also chip quirks/bugs in init logic
};
@@ -439,117 +440,164 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)
* a minority (notably the IBM STB04XXX and the Motorola MPC5200
* processors) implement them in big endian format.
*
+ * In addition some more exotic implementations like the Toshiba
+ * Spider (aka SCC) cell southbridge are "mixed" endian, that is,
+ * they have a different endianness for registers vs. in-memory
+ * descriptors.
+ *
* This attempts to support either format at compile time without a
* runtime penalty, or both formats with the additional overhead
* of checking a flag bit.
+ *
+ * That leads to some tricky Kconfig rules howevber. There are
+ * different defaults based on some arch/ppc platforms, though
+ * the basic rules are:
+ *
+ * Controller type Kconfig options needed
+ * --------------- ----------------------
+ * little endian CONFIG_USB_OHCI_LITTLE_ENDIAN
+ *
+ * fully big endian CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_
+ * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ *
+ * mixed endian CONFIG_USB_OHCI_LITTLE_ENDIAN _and_
+ * CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC}
+ *
+ * (If you have a mixed endian controller, you -must- also define
+ * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building
+ * both your mixed endian and a fully big endian controller support in
+ * the same kernel image).
*/
-#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
+#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
+#define big_endian_desc(ohci) (ohci->flags & OHCI_QUIRK_BE_DESC)
+#else
+#define big_endian_desc(ohci) 1 /* only big endian */
+#endif
+#else
+#define big_endian_desc(ohci) 0 /* only little endian */
+#endif
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
-#define big_endian(ohci) (ohci->flags & OHCI_BIG_ENDIAN) /* either */
+#define big_endian_mmio(ohci) (ohci->flags & OHCI_QUIRK_BE_MMIO)
+#else
+#define big_endian_mmio(ohci) 1 /* only big endian */
+#endif
#else
-#define big_endian(ohci) 1 /* only big endian */
+#define big_endian_mmio(ohci) 0 /* only little endian */
#endif
/*
* Big-endian read/write functions are arch-specific.
* Other arches can be added if/when they're needed.
+ *
+ * REVISIT: arch/powerpc now has readl/writel_be, so the
+ * definition below can die once the STB04xxx support is
+ * finally ported over.
*/
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
#define readl_be(addr) in_be32((__force unsigned *)addr)
#define writel_be(val, addr) out_be32((__force unsigned *)addr, val)
#endif
-static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
- __hc32 __iomem * regs)
+static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
+ __hc32 __iomem * regs)
{
- return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ return big_endian_mmio(ohci) ?
+ readl_be (regs) :
+ readl (regs);
+#else
+ return readl (regs);
+#endif
}
-static inline void ohci_writel (const struct ohci_hcd *ohci,
- const unsigned int val, __hc32 __iomem *regs)
+static inline void _ohci_writel (const struct ohci_hcd *ohci,
+ const unsigned int val, __hc32 __iomem *regs)
{
- big_endian(ohci) ? writel_be (val, regs) :
- writel (val, (__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ big_endian_mmio(ohci) ?
+ writel_be (val, regs) :
+ writel (val, regs);
+#else
+ writel (val, regs);
+#endif
}
-#else /* !CONFIG_USB_OHCI_BIG_ENDIAN */
-
-#define big_endian(ohci) 0 /* only little endian */
-
#ifdef CONFIG_ARCH_LH7A404
- /* Marc Singer: at the time this code was written, the LH7A404
- * had a problem reading the USB host registers. This
- * implementation of the ohci_readl function performs the read
- * twice as a work-around.
- */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
-{
- *(volatile __force unsigned int*) regs;
- return *(volatile __force unsigned int*) regs;
-}
+/* Marc Singer: at the time this code was written, the LH7A404
+ * had a problem reading the USB host registers. This
+ * implementation of the ohci_readl function performs the read
+ * twice as a work-around.
+ */
+#define ohci_readl(o,r) (_ohci_readl(o,r),_ohci_readl(o,r))
+#define ohci_writel(o,v,r) _ohci_writel(o,v,r)
#else
- /* Standard version of ohci_readl uses standard, platform
- * specific implementation. */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
-{
- return readl(regs);
-}
+#define ohci_readl(o,r) _ohci_readl(o,r)
+#define ohci_writel(o,v,r) _ohci_writel(o,v,r)
#endif
-static inline void ohci_writel (const struct ohci_hcd *ohci,
- const unsigned int val, __hc32 __iomem *regs)
-{
- writel (val, regs);
-}
-
-#endif /* !CONFIG_USB_OHCI_BIG_ENDIAN */
/*-------------------------------------------------------------------------*/
/* cpu to ohci */
static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
{
- return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
+ return big_endian_desc(ohci) ?
+ (__force __hc16)cpu_to_be16(x) :
+ (__force __hc16)cpu_to_le16(x);
}
static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
{
- return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
+ return big_endian_desc(ohci) ?
+ cpu_to_be16p(x) :
+ cpu_to_le16p(x);
}
static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
{
- return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
+ return big_endian_desc(ohci) ?
+ (__force __hc32)cpu_to_be32(x) :
+ (__force __hc32)cpu_to_le32(x);
}
static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
{
- return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
+ return big_endian_desc(ohci) ?
+ cpu_to_be32p(x) :
+ cpu_to_le32p(x);
}
/* ohci to cpu */
static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
{
- return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
+ return big_endian_desc(ohci) ?
+ be16_to_cpu((__force __be16)x) :
+ le16_to_cpu((__force __le16)x);
}
static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
{
- return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
+ return big_endian_desc(ohci) ?
+ be16_to_cpup((__force __be16 *)x) :
+ le16_to_cpup((__force __le16 *)x);
}
static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
{
- return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
+ return big_endian_desc(ohci) ?
+ be32_to_cpu((__force __be32)x) :
+ le32_to_cpu((__force __le32)x);
}
static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
{
- return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
+ return big_endian_desc(ohci) ?
+ be32_to_cpup((__force __be32 *)x) :
+ le32_to_cpup((__force __le32 *)x);
}
/*-------------------------------------------------------------------------*/
@@ -557,6 +605,9 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
* hardware handles 16 bit reads. That creates a different confusion on
* some big-endian SOC implementations. Same thing happens with PSW access.
+ *
+ * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
+ * to arch/powerpc
*/
#ifdef CONFIG_STB03xxx
@@ -568,7 +619,7 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
{
u32 tmp;
- if (big_endian(ohci)) {
+ if (big_endian_desc(ohci)) {
tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
tmp >>= OHCI_BE_FRAME_NO_SHIFT;
} else
@@ -580,7 +631,7 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
const struct td *td, int index)
{
- return (__hc16 *)(big_endian(ohci) ?
+ return (__hc16 *)(big_endian_desc(ohci) ?
&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
}
@@ -598,11 +649,11 @@ static inline void disable (struct ohci_hcd *ohci)
}
#define FI 0x2edf /* 12000 bits per frame (-1) */
-#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7))
+#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7))
#define FIT (1 << 31)
#define LSTHRESH 0x628 /* lowspeed bit threshold */
-static void periodic_reinit (struct ohci_hcd *ohci)
+static inline void periodic_reinit (struct ohci_hcd *ohci)
{
u32 fi = ohci->fminterval & 0x03fff;
u32 fit = ohci_readl(ohci, &ohci->regs->fminterval) & FIT;
@@ -626,11 +677,11 @@ static void periodic_reinit (struct ohci_hcd *ohci)
temp = ohci_readl (hc, &hc->regs->roothub.register); \
temp; })
-static u32 roothub_a (struct ohci_hcd *hc)
+static inline u32 roothub_a (struct ohci_hcd *hc)
{ return read_roothub (hc, a, 0xfc0fe000); }
static inline u32 roothub_b (struct ohci_hcd *hc)
{ return ohci_readl (hc, &hc->regs->roothub.b); }
static inline u32 roothub_status (struct ohci_hcd *hc)
{ return ohci_readl (hc, &hc->regs->roothub.status); }
-static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
+static inline u32 roothub_portstatus (struct ohci_hcd *hc, int i)
{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index a9d7119e317..a7fa0d75567 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -40,6 +40,7 @@
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/ioport.h>
+#include <linux/pci_ids.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
@@ -210,15 +211,16 @@ struct u132 {
* these cannot be inlines because we need the structure offset!!
* Does anyone have a better way?????
*/
+#define ftdi_read_pcimem(pdev, member, data) usb_ftdi_elan_read_pcimem(pdev, \
+ offsetof(struct ohci_regs, member), 0, data);
+#define ftdi_write_pcimem(pdev, member, data) usb_ftdi_elan_write_pcimem(pdev, \
+ offsetof(struct ohci_regs, member), 0, data);
#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;
@@ -1574,59 +1576,12 @@ static char *hcfs2string(int state)
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);
- }
- }
+ u132->next_statechange = jiffies;
retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE);
if (retval)
return retval;
@@ -1725,7 +1680,7 @@ static int u132_run(struct u132 *u132)
retry:retval = u132_read_pcimem(u132, cmdstatus, &status);
if (retval)
return retval;
- retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_HCR);
+ retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR);
if (retval)
return retval;
extra:{
@@ -1782,7 +1737,7 @@ static int u132_run(struct u132 *u132)
retval = u132_write_pcimem(u132, control, u132->hc_control);
if (retval)
return retval;
- retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_BLF);
+ retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF);
if (retval)
return retval;
retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus);
@@ -1839,8 +1794,8 @@ 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);
+ dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b"
+ "een removed %d\n", u132, hcd, u132->going);
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
"ed\n", hcd);
@@ -2545,8 +2500,9 @@ static void u132_endpoint_disable(struct usb_hcd *hcd,
{
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);
+ dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p"
+ ") has been removed %d\n", u132, hcd, hep,
+ u132->going);
} else {
struct u132_endp *endp = hep->hcpriv;
if (endp)
@@ -2790,7 +2746,6 @@ static int u132_hub_status_data(struct usb_hcd *hcd, char *buf)
} 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;
@@ -3034,12 +2989,15 @@ 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) {
+ dev_err(&u132->platform_dev->dev, "already being remove"
+ "d\n");
return -ENODEV;
} else {
int rings = MAX_U132_RINGS;
int endps = MAX_U132_ENDPS;
+ dev_err(&u132->platform_dev->dev, "removing device u132"
+ ".%d\n", u132->sequence_num);
msleep(100);
down(&u132->sw_lock);
u132_monitor_cancel_work(u132);
@@ -3121,10 +3079,24 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
static int __devinit u132_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
+ int retval;
+ u32 control;
+ u32 rh_a = -1;
+ u32 num_ports;
msleep(100);
if (u132_exiting > 0) {
return -ENODEV;
- } /* refuse to confuse usbcore */
+ }
+ retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(pdev, control, &control);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
+ if (retval)
+ return retval;
+ num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */
if (pdev->dev.dma_mask) {
return -EINVAL;
}
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index e345f15b7d8..5d6c06bc452 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -168,9 +168,13 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
space, "", qh, qtype,
le32_to_cpu(qh->link), le32_to_cpu(element));
if (qh->type == USB_ENDPOINT_XFER_ISOC)
- out += sprintf(out, "%*s period %d frame %x desc [%p]\n",
- space, "", qh->period, qh->iso_frame,
- qh->iso_packet_desc);
+ out += sprintf(out, "%*s period %d phase %d load %d us, "
+ "frame %x desc [%p]\n",
+ space, "", qh->period, qh->phase, qh->load,
+ qh->iso_frame, qh->iso_packet_desc);
+ else if (qh->type == USB_ENDPOINT_XFER_INT)
+ out += sprintf(out, "%*s period %d phase %d load %d us\n",
+ space, "", qh->period, qh->phase, qh->load);
if (element & UHCI_PTR_QH)
out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
@@ -208,7 +212,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
space, "", nurbs);
}
- if (qh->udev) {
+ if (qh->dummy_td) {
out += sprintf(out, "%*s Dummy TD\n", space, "");
out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
}
@@ -347,31 +351,80 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
struct uhci_qh *qh;
struct uhci_td *td;
struct list_head *tmp, *head;
+ int nframes, nerrs;
out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
out += sprintf(out, "HC status\n");
out += uhci_show_status(uhci, out, len - (out - buf));
+
+ out += sprintf(out, "Periodic load table\n");
+ for (i = 0; i < MAX_PHASE; ++i) {
+ out += sprintf(out, "\t%d", uhci->load[i]);
+ if (i % 8 == 7)
+ *out++ = '\n';
+ }
+ out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
+ uhci->total_load,
+ uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
+ uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
if (debug <= 1)
return out - buf;
out += sprintf(out, "Frame List\n");
+ nframes = 10;
+ nerrs = 0;
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+ __le32 link, qh_dma;
+
+ j = 0;
td = uhci->frame_cpu[i];
+ link = uhci->frame[i];
if (!td)
- continue;
+ goto check_link;
- out += sprintf(out, "- Frame %d\n", i); \
- if (td->dma_handle != (dma_addr_t)uhci->frame[i])
- out += sprintf(out, " frame list does not match td->dma_handle!\n");
+ if (nframes > 0) {
+ out += sprintf(out, "- Frame %d -> (%08x)\n",
+ i, le32_to_cpu(link));
+ j = 1;
+ }
head = &td->fl_list;
tmp = head;
do {
td = list_entry(tmp, struct uhci_td, fl_list);
tmp = tmp->next;
- out += uhci_show_td(td, out, len - (out - buf), 4);
+ if (cpu_to_le32(td->dma_handle) != link) {
+ if (nframes > 0)
+ out += sprintf(out, " link does "
+ "not match list entry!\n");
+ else
+ ++nerrs;
+ }
+ if (nframes > 0)
+ out += uhci_show_td(td, out,
+ len - (out - buf), 4);
+ link = td->link;
} while (tmp != head);
+
+check_link:
+ qh_dma = uhci_frame_skel_link(uhci, i);
+ if (link != qh_dma) {
+ if (nframes > 0) {
+ if (!j) {
+ out += sprintf(out,
+ "- Frame %d -> (%08x)\n",
+ i, le32_to_cpu(link));
+ j = 1;
+ }
+ out += sprintf(out, " link does not match "
+ "QH (%08x)!\n", le32_to_cpu(qh_dma));
+ } else
+ ++nerrs;
+ }
+ nframes -= j;
}
+ if (nerrs > 0)
+ out += sprintf(out, "Skipped %d bad links\n", nerrs);
out += sprintf(out, "Skeleton QHs\n");
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index e87692c31be..49b9d390b95 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -60,6 +60,11 @@ Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
Alan Stern"
#define DRIVER_DESC "USB Universal Host Controller Interface driver"
+/* for flakey hardware, ignore overcurrent indicators */
+static int ignore_oc;
+module_param(ignore_oc, bool, S_IRUGO);
+MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications");
+
/*
* debug = 0, no debugging messages
* debug = 1, dump failed URBs except for stalls
@@ -87,6 +92,34 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
static void wakeup_rh(struct uhci_hcd *uhci);
static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
+/*
+ * Calculate the link pointer DMA value for the first Skeleton QH in a frame.
+ */
+static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
+{
+ int skelnum;
+
+ /*
+ * The interrupt queues will be interleaved as evenly as possible.
+ * There's not much to be done about period-1 interrupts; they have
+ * to occur in every frame. But we can schedule period-2 interrupts
+ * in odd-numbered frames, period-4 interrupts in frames congruent
+ * to 2 (mod 4), and so on. This way each frame only has two
+ * interrupt QHs, which will help spread out bandwidth utilization.
+ *
+ * ffs (Find First bit Set) does exactly what we need:
+ * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
+ * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+ * ffs >= 7 => not on any high-period queue, so use
+ * skel_int1_qh = skelqh[9].
+ * Add in UHCI_NUMFRAMES to insure at least one bit is set.
+ */
+ skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
+ if (skelnum <= 1)
+ skelnum = 9;
+ return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle);
+}
+
#include "uhci-debug.c"
#include "uhci-q.c"
#include "uhci-hub.c"
@@ -169,6 +202,11 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
{
int port;
+ /* If we have to ignore overcurrent events then almost by definition
+ * we can't depend on resume-detect interrupts. */
+ if (ignore_oc)
+ return 1;
+
switch (to_pci_dev(uhci_dev(uhci))->vendor) {
default:
break;
@@ -199,24 +237,16 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
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;
+ char *sys_info;
+ static char bad_Asus_board[] = "A7V8X";
/* 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)) {
+ sys_info = dmi_get_system_info(DMI_BOARD_NAME);
+ if (sys_info && !strcmp(sys_info, bad_Asus_board)) {
for (port = 0; port < uhci->rh_numports; ++port) {
if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
USBPORTSC_CCS)
@@ -255,7 +285,9 @@ __acquires(uhci->lock)
int_enable = USBINTR_RESUME;
if (remote_wakeup_is_broken(uhci))
egsm_enable = 0;
- if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable)
+ if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable ||
+ !device_may_wakeup(
+ &uhci_to_hcd(uhci)->self.root_hub->dev))
uhci->working_RD = int_enable = 0;
outw(int_enable, uhci->io_addr + USBINTR);
@@ -627,32 +659,11 @@ static int uhci_start(struct usb_hcd *hcd)
/*
* Fill the frame list: make all entries point to the proper
* interrupt queue.
- *
- * The interrupt queues will be interleaved as evenly as possible.
- * There's not much to be done about period-1 interrupts; they have
- * to occur in every frame. But we can schedule period-2 interrupts
- * in odd-numbered frames, period-4 interrupts in frames congruent
- * to 2 (mod 4), and so on. This way each frame only has two
- * interrupt QHs, which will help spread out bandwidth utilization.
*/
for (i = 0; i < UHCI_NUMFRAMES; i++) {
- int irq;
-
- /*
- * ffs (Find First bit Set) does exactly what we need:
- * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
- * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
- * ffs >= 7 => not on any high-period queue, so use
- * skel_int1_qh = skelqh[9].
- * Add UHCI_NUMFRAMES to insure at least one bit is set.
- */
- irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
- if (irq <= 1)
- irq = 9;
/* Only place we don't use the frame list routines */
- uhci->frame[i] = UHCI_PTR_QH |
- cpu_to_le32(uhci->skelqh[irq]->dma_handle);
+ uhci->frame[i] = uhci_frame_skel_link(uhci, i);
}
/*
@@ -921,7 +932,8 @@ static int __init uhci_hcd_init(void)
{
int retval = -ENOMEM;
- printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n");
+ printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "%s\n",
+ ignore_oc ? ", overcurrent ignored" : "");
if (usb_disabled())
return -ENODEV;
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 108e3de2dc2..74469b5bcb6 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -83,6 +83,7 @@
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
#define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames
* can be scheduled */
+#define MAX_PHASE 32 /* Periodic scheduling length */
/* When no queues need Full-Speed Bandwidth Reclamation,
* delay this long before turning FSBR off */
@@ -141,6 +142,8 @@ struct uhci_qh {
unsigned long advance_jiffies; /* Time of last queue advance */
unsigned int unlink_frame; /* When the QH was unlinked */
unsigned int period; /* For Interrupt and Isochronous QHs */
+ short phase; /* Between 0 and period-1 */
+ short load; /* Periodic time requirement, in us */
unsigned int iso_frame; /* Frame # for iso_packet_desc */
int iso_status; /* Status for Isochronous URBs */
@@ -153,6 +156,8 @@ struct uhci_qh {
unsigned int needs_fixup:1; /* Must fix the TD toggle values */
unsigned int is_stopped:1; /* Queue was stopped by error/unlink */
unsigned int wait_expired:1; /* QH_WAIT_TIMEOUT has expired */
+ unsigned int bandwidth_reserved:1; /* Periodic bandwidth has
+ * been allocated */
} __attribute__((aligned(16)));
/*
@@ -414,6 +419,9 @@ struct uhci_hcd {
wait_queue_head_t waitqh; /* endpoint_disable waiters */
int num_waiting; /* Number of waiters */
+
+ int total_load; /* Sum of array values */
+ short load[MAX_PHASE]; /* Periodic allocations */
};
/* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index f8347f1a10b..bacc25c53ba 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -52,10 +52,20 @@ static int any_ports_active(struct uhci_hcd *uhci)
static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
{
int port;
+ int mask = RWC_BITS;
+
+ /* Some boards (both VIA and Intel apparently) report bogus
+ * overcurrent indications, causing massive log spam unless
+ * we completely ignore them. This doesn't seem to be a problem
+ * with the chipset so much as with the way it is connected on
+ * the motherboard; if the overcurrent input is left to float
+ * then it may constantly register false positives. */
+ if (ignore_oc)
+ mask &= ~USBPORTSC_OCC;
*buf = 0;
for (port = 0; port < uhci->rh_numports; ++port) {
- if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) ||
+ if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & mask) ||
test_bit(port, &uhci->port_c_suspend))
*buf |= (1 << (port + 1));
}
@@ -263,7 +273,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
wPortChange |= USB_PORT_STAT_C_CONNECTION;
if (status & USBPORTSC_PEC)
wPortChange |= USB_PORT_STAT_C_ENABLE;
- if (status & USBPORTSC_OCC)
+ if ((status & USBPORTSC_OCC) && !ignore_oc)
wPortChange |= USB_PORT_STAT_C_OVERCURRENT;
if (test_bit(port, &uhci->port_c_suspend)) {
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 30b88459ac7..2cbb239e63f 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -248,16 +248,26 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
INIT_LIST_HEAD(&qh->node);
if (udev) { /* Normal QH */
- qh->dummy_td = uhci_alloc_td(uhci);
- if (!qh->dummy_td) {
- dma_pool_free(uhci->qh_pool, qh, dma_handle);
- return NULL;
+ qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ if (qh->type != USB_ENDPOINT_XFER_ISOC) {
+ qh->dummy_td = uhci_alloc_td(uhci);
+ if (!qh->dummy_td) {
+ dma_pool_free(uhci->qh_pool, qh, dma_handle);
+ return NULL;
+ }
}
qh->state = QH_STATE_IDLE;
qh->hep = hep;
qh->udev = udev;
hep->hcpriv = qh;
- qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ if (qh->type == USB_ENDPOINT_XFER_INT ||
+ qh->type == USB_ENDPOINT_XFER_ISOC)
+ qh->load = usb_calc_bus_time(udev->speed,
+ usb_endpoint_dir_in(&hep->desc),
+ qh->type == USB_ENDPOINT_XFER_ISOC,
+ le16_to_cpu(hep->desc.wMaxPacketSize))
+ / 1000 + 1;
} else { /* Skeleton QH */
qh->state = QH_STATE_ACTIVE;
@@ -275,7 +285,8 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
list_del(&qh->node);
if (qh->udev) {
qh->hep->hcpriv = NULL;
- uhci_free_td(uhci, qh->dummy_td);
+ if (qh->dummy_td)
+ uhci_free_td(uhci, qh->dummy_td);
}
dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
}
@@ -327,7 +338,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
goto done;
qh->element = UHCI_PTR_TERM;
- /* Control pipes have to worry about toggles */
+ /* Control pipes don't have to worry about toggles */
if (qh->type == USB_ENDPOINT_XFER_CONTROL)
goto done;
@@ -493,6 +504,121 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
wake_up_all(&uhci->waitqh);
}
+/*
+ * Find the highest existing bandwidth load for a given phase and period.
+ */
+static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period)
+{
+ int highest_load = uhci->load[phase];
+
+ for (phase += period; phase < MAX_PHASE; phase += period)
+ highest_load = max_t(int, highest_load, uhci->load[phase]);
+ return highest_load;
+}
+
+/*
+ * Set qh->phase to the optimal phase for a periodic transfer and
+ * check whether the bandwidth requirement is acceptable.
+ */
+static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ int minimax_load;
+
+ /* Find the optimal phase (unless it is already set) and get
+ * its load value. */
+ if (qh->phase >= 0)
+ minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+ else {
+ int phase, load;
+ int max_phase = min_t(int, MAX_PHASE, qh->period);
+
+ qh->phase = 0;
+ minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+ for (phase = 1; phase < max_phase; ++phase) {
+ load = uhci_highest_load(uhci, phase, qh->period);
+ if (load < minimax_load) {
+ minimax_load = load;
+ qh->phase = phase;
+ }
+ }
+ }
+
+ /* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */
+ if (minimax_load + qh->load > 900) {
+ dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: "
+ "period %d, phase %d, %d + %d us\n",
+ qh->period, qh->phase, minimax_load, qh->load);
+ return -ENOSPC;
+ }
+ return 0;
+}
+
+/*
+ * Reserve a periodic QH's bandwidth in the schedule
+ */
+static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ int i;
+ int load = qh->load;
+ char *p = "??";
+
+ for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+ uhci->load[i] += load;
+ uhci->total_load += load;
+ }
+ uhci_to_hcd(uhci)->self.bandwidth_allocated =
+ uhci->total_load / MAX_PHASE;
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_INT:
+ ++uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+ p = "INT";
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ ++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+ p = "ISO";
+ break;
+ }
+ qh->bandwidth_reserved = 1;
+ dev_dbg(uhci_dev(uhci),
+ "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+ "reserve", qh->udev->devnum,
+ qh->hep->desc.bEndpointAddress, p,
+ qh->period, qh->phase, load);
+}
+
+/*
+ * Release a periodic QH's bandwidth reservation
+ */
+static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ int i;
+ int load = qh->load;
+ char *p = "??";
+
+ for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+ uhci->load[i] -= load;
+ uhci->total_load -= load;
+ }
+ uhci_to_hcd(uhci)->self.bandwidth_allocated =
+ uhci->total_load / MAX_PHASE;
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_INT:
+ --uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+ p = "INT";
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ --uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+ p = "ISO";
+ break;
+ }
+ qh->bandwidth_reserved = 0;
+ dev_dbg(uhci_dev(uhci),
+ "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+ "release", qh->udev->devnum,
+ qh->hep->desc.bEndpointAddress, p,
+ qh->period, qh->phase, load);
+}
+
static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
struct urb *urb)
{
@@ -796,7 +922,6 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
wmb();
qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
qh->dummy_td = td;
- qh->period = urb->interval;
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), toggle);
@@ -827,28 +952,42 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
struct uhci_qh *qh)
{
- int exponent;
+ int ret;
/* USB 1.1 interrupt transfers only involve one packet per interval.
* Drivers can submit URBs of any length, but longer ones will need
* multiple intervals to complete.
*/
- /* Figure out which power-of-two queue to use */
- for (exponent = 7; exponent >= 0; --exponent) {
- if ((1 << exponent) <= urb->interval)
- break;
- }
- if (exponent < 0)
- return -EINVAL;
- urb->interval = 1 << exponent;
+ if (!qh->bandwidth_reserved) {
+ int exponent;
- if (qh->period == 0)
+ /* Figure out which power-of-two queue to use */
+ for (exponent = 7; exponent >= 0; --exponent) {
+ if ((1 << exponent) <= urb->interval)
+ break;
+ }
+ if (exponent < 0)
+ return -EINVAL;
+ qh->period = 1 << exponent;
qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
- else if (qh->period != urb->interval)
- return -EINVAL; /* Can't change the period */
- return uhci_submit_common(uhci, urb, qh);
+ /* For now, interrupt phase is fixed by the layout
+ * of the QH lists. */
+ qh->phase = (qh->period / 2) & (MAX_PHASE - 1);
+ ret = uhci_check_bandwidth(uhci, qh);
+ if (ret)
+ return ret;
+ } else if (qh->period > urb->interval)
+ return -EINVAL; /* Can't decrease the period */
+
+ ret = uhci_submit_common(uhci, urb, qh);
+ if (ret == 0) {
+ urb->interval = qh->period;
+ if (!qh->bandwidth_reserved)
+ uhci_reserve_bandwidth(uhci, qh);
+ }
+ return ret;
}
/*
@@ -995,15 +1134,32 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
return -EFBIG;
/* Check the period and figure out the starting frame number */
- if (qh->period == 0) {
+ if (!qh->bandwidth_reserved) {
+ qh->period = urb->interval;
if (urb->transfer_flags & URB_ISO_ASAP) {
+ qh->phase = -1; /* Find the best phase */
+ i = uhci_check_bandwidth(uhci, qh);
+ if (i)
+ return i;
+
+ /* Allow a little time to allocate the TDs */
uhci_get_current_frame_number(uhci);
- urb->start_frame = uhci->frame_number + 10;
+ frame = uhci->frame_number + 10;
+
+ /* Move forward to the first frame having the
+ * correct phase */
+ urb->start_frame = frame + ((qh->phase - frame) &
+ (qh->period - 1));
} else {
i = urb->start_frame - uhci->last_iso_frame;
if (i <= 0 || i >= UHCI_NUMFRAMES)
return -EINVAL;
+ qh->phase = urb->start_frame & (qh->period - 1);
+ i = uhci_check_bandwidth(uhci, qh);
+ if (i)
+ return i;
}
+
} else if (qh->period != urb->interval) {
return -EINVAL; /* Can't change the period */
@@ -1049,9 +1205,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
/* Set the interrupt-on-completion flag on the last packet. */
td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
- qh->skel = uhci->skel_iso_qh;
- qh->period = urb->interval;
-
/* Add the TDs to the frame list */
frame = urb->start_frame;
list_for_each_entry(td, &urbp->td_list, list) {
@@ -1065,6 +1218,9 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
qh->iso_status = 0;
}
+ qh->skel = uhci->skel_iso_qh;
+ if (!qh->bandwidth_reserved)
+ uhci_reserve_bandwidth(uhci, qh);
return 0;
}
@@ -1119,7 +1275,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
unsigned long flags;
struct urb_priv *urbp;
struct uhci_qh *qh;
- int bustime;
spin_lock_irqsave(&uhci->lock, flags);
@@ -1149,35 +1304,11 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
ret = uhci_submit_bulk(uhci, urb, qh);
break;
case USB_ENDPOINT_XFER_INT:
- if (list_empty(&qh->queue)) {
- bustime = usb_check_bandwidth(urb->dev, urb);
- if (bustime < 0)
- ret = bustime;
- else {
- ret = uhci_submit_interrupt(uhci, urb, qh);
- if (ret == 0)
- usb_claim_bandwidth(urb->dev, urb, bustime, 0);
- }
- } else { /* inherit from parent */
- struct urb_priv *eurbp;
-
- eurbp = list_entry(qh->queue.prev, struct urb_priv,
- node);
- urb->bandwidth = eurbp->urb->bandwidth;
- ret = uhci_submit_interrupt(uhci, urb, qh);
- }
+ ret = uhci_submit_interrupt(uhci, urb, qh);
break;
case USB_ENDPOINT_XFER_ISOC:
urb->error_count = 0;
- bustime = usb_check_bandwidth(urb->dev, urb);
- if (bustime < 0) {
- ret = bustime;
- break;
- }
-
ret = uhci_submit_isochronous(uhci, urb, qh);
- if (ret == 0)
- usb_claim_bandwidth(urb->dev, urb, bustime, 1);
break;
}
if (ret != 0)
@@ -1274,24 +1405,6 @@ __acquires(uhci->lock)
uhci_free_urb_priv(uhci, urbp);
- switch (qh->type) {
- case USB_ENDPOINT_XFER_ISOC:
- /* Release bandwidth for Interrupt or Isoc. transfers */
- if (urb->bandwidth)
- usb_release_bandwidth(urb->dev, urb, 1);
- break;
- case USB_ENDPOINT_XFER_INT:
- /* Release bandwidth for Interrupt or Isoc. transfers */
- /* Make sure we don't release if we have a queued URB */
- if (list_empty(&qh->queue) && urb->bandwidth)
- usb_release_bandwidth(urb->dev, urb, 0);
- else
- /* bandwidth was passed on to queued URB, */
- /* so don't let usb_unlink_urb() release it */
- urb->bandwidth = 0;
- break;
- }
-
spin_unlock(&uhci->lock);
usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
spin_lock(&uhci->lock);
@@ -1300,9 +1413,8 @@ __acquires(uhci->lock)
* reserved bandwidth. */
if (list_empty(&qh->queue)) {
uhci_unlink_qh(uhci, qh);
-
- /* Bandwidth stuff not yet implemented */
- qh->period = 0;
+ if (qh->bandwidth_reserved)
+ uhci_release_bandwidth(uhci, qh);
}
}
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 63a84bbc310..d308afd0693 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -565,11 +565,15 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)
usb_deregister_dev(intf, &mdc800_class);
+ /* must be under lock to make sure no URB
+ is submitted after usb_kill_urb() */
+ mutex_lock(&mdc800->io_lock);
mdc800->state=NOT_CONNECTED;
usb_kill_urb(mdc800->irq_urb);
usb_kill_urb(mdc800->write_urb);
usb_kill_urb(mdc800->download_urb);
+ mutex_unlock(&mdc800->io_lock);
mdc800->dev = NULL;
usb_set_intfdata(intf, NULL);
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index 661af7aa623..2e71d3cca19 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -6,14 +6,14 @@ comment "USB Input Devices"
config USB_HID
tristate "USB Human Interface Device (full HID) support"
- depends on USB
+ default y
+ depends on USB && INPUT
+ select HID
---help---
- Say Y here if you want full HID support to connect keyboards,
+ Say Y here if you want full HID support to connect USB keyboards,
mice, joysticks, graphic tablets, or any other HID based devices
- to your computer via USB. You also need to select HID Input layer
- support (below) if you want to use keyboards, mice, joysticks and
- the like ... as well as Uninterruptible Power Supply (UPS) and
- monitor control devices.
+ to your computer via USB, as well as Uninterruptible Power Supply
+ (UPS) and monitor control devices.
You can't use this driver and the HIDBP (Boot Protocol) keyboard
and mouse drivers at the same time. More information is available:
@@ -27,20 +27,10 @@ config USB_HID
comment "Input core support is needed for USB HID input layer or HIDBP support"
depends on USB_HID && INPUT=n
-config USB_HIDINPUT
- bool "HID input layer support"
- default y
- depends on INPUT && USB_HID
- help
- Say Y here if you want to use a USB keyboard, mouse or joystick,
- or any other HID input device.
-
- If unsure, say Y.
-
config USB_HIDINPUT_POWERBOOK
bool "Enable support for iBook/PowerBook special keys"
default n
- depends on USB_HIDINPUT
+ depends on USB_HID
help
Say Y here if you want support for the special keys (Fn, Numlock) on
Apple iBooks and PowerBooks.
@@ -49,7 +39,7 @@ config USB_HIDINPUT_POWERBOOK
config HID_FF
bool "Force feedback support (EXPERIMENTAL)"
- depends on USB_HIDINPUT && EXPERIMENTAL
+ depends on USB_HID && EXPERIMENTAL
help
Say Y here is you want force feedback support for a few HID devices.
See below for a list of supported devices.
@@ -79,6 +69,14 @@ config LOGITECH_FF
Note: if you say N here, this device will still be supported, but without
force feedback.
+config PANTHERLORD_FF
+ bool "PantherLord USB/PS2 2in1 Adapter support"
+ depends on HID_FF
+ select INPUT_FF_MEMLESS if USB_HID
+ help
+ Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
+ to enable force feedback support for it.
+
config THRUSTMASTER_FF
bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
depends on HID_FF && EXPERIMENTAL
@@ -354,3 +352,15 @@ config USB_APPLETOUCH
To compile this driver as a module, choose M here: the
module will be called appletouch.
+
+config USB_GTCO
+ tristate "GTCO CalComp/InterWrite USB Support"
+ depends on USB && INPUT
+ ---help---
+ Say Y here if you want to use the USB version of the GTCO
+ CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support"
+ (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+ (CONFIG_INPUT_EVDEV) as well.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gtco.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
index d946d5213b3..a9d206c945e 100644
--- a/drivers/usb/input/Makefile
+++ b/drivers/usb/input/Makefile
@@ -11,15 +11,15 @@ usbhid-objs := hid-core.o
ifeq ($(CONFIG_USB_HIDDEV),y)
usbhid-objs += hiddev.o
endif
-ifeq ($(CONFIG_USB_HIDINPUT),y)
- usbhid-objs += hid-input.o
-endif
ifeq ($(CONFIG_HID_PID),y)
usbhid-objs += hid-pidff.o
endif
ifeq ($(CONFIG_LOGITECH_FF),y)
usbhid-objs += hid-lgff.o
endif
+ifeq ($(CONFIG_PANTHERLORD_FF),y)
+ usbhid-objs += hid-plff.o
+endif
ifeq ($(CONFIG_THRUSTMASTER_FF),y)
usbhid-objs += hid-tmff.o
endif
@@ -48,6 +48,7 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o
obj-$(CONFIG_USB_YEALINK) += yealink.o
obj-$(CONFIG_USB_XPAD) += xpad.o
obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o
+obj-$(CONFIG_USB_GTCO) += gtco.o
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c
new file mode 100644
index 00000000000..203cdc1bbba
--- /dev/null
+++ b/drivers/usb/input/gtco.c
@@ -0,0 +1,1104 @@
+/* -*- linux-c -*-
+
+GTCO digitizer USB driver
+
+Use the err(), dbg() and info() macros from usb.h for system logging
+
+TO CHECK: Is pressure done right on report 5?
+
+Copyright (C) 2006 GTCO CalComp
+
+This program is free software; 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.
+
+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.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of GTCO-CalComp not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. GTCO-CalComp makes no representations about the
+suitability of this software for any purpose. It is provided "as is"
+without express or implied warranty.
+
+GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+GTCO CalComp, Inc.
+7125 Riverwood Drive
+Columbia, MD 21046
+
+Jeremy Roberson jroberson@gtcocalcomp.com
+Scott Hill shill@gtcocalcomp.com
+*/
+
+
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/version.h>
+#include <linux/usb/input.h>
+
+/* Version with a Major number of 2 is for kernel inclusion only. */
+#define GTCO_VERSION "2.00.0006"
+
+
+/* MACROS */
+
+#define VENDOR_ID_GTCO 0x078C
+#define PID_400 0x400
+#define PID_401 0x401
+#define PID_1000 0x1000
+#define PID_1001 0x1001
+#define PID_1002 0x1002
+
+/* Max size of a single report */
+#define REPORT_MAX_SIZE 10
+
+
+/* Bitmask whether pen is in range */
+#define MASK_INRANGE 0x20
+#define MASK_BUTTON 0x01F
+
+#define PATHLENGTH 64
+
+/* DATA STRUCTURES */
+
+/* Device table */
+static struct usb_device_id gtco_usbid_table [] = {
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
+ { }
+};
+MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
+
+
+/* Structure to hold all of our device specific stuff */
+struct gtco {
+
+ struct input_dev *inputdevice; /* input device struct pointer */
+ struct usb_device *usbdev; /* the usb device for this device */
+ struct urb *urbinfo; /* urb for incoming reports */
+ dma_addr_t buf_dma; /* dma addr of the data buffer*/
+ unsigned char * buffer; /* databuffer for reports */
+
+ char usbpath[PATHLENGTH];
+ int openCount;
+
+ /* Information pulled from Report Descriptor */
+ u32 usage;
+ u32 min_X;
+ u32 max_X;
+ u32 min_Y;
+ u32 max_Y;
+ s8 mintilt_X;
+ s8 maxtilt_X;
+ s8 mintilt_Y;
+ s8 maxtilt_Y;
+ u32 maxpressure;
+ u32 minpressure;
+};
+
+
+
+/* Code for parsing the HID REPORT DESCRIPTOR */
+
+/* From HID1.11 spec */
+struct hid_descriptor
+{
+ struct usb_descriptor_header header;
+ __le16 bcdHID;
+ u8 bCountryCode;
+ u8 bNumDescriptors;
+ u8 bDescriptorType;
+ __le16 wDescriptorLength;
+} __attribute__ ((packed));
+
+
+#define HID_DESCRIPTOR_SIZE 9
+#define HID_DEVICE_TYPE 33
+#define REPORT_DEVICE_TYPE 34
+
+
+#define PREF_TAG(x) ((x)>>4)
+#define PREF_TYPE(x) ((x>>2)&0x03)
+#define PREF_SIZE(x) ((x)&0x03)
+
+#define TYPE_MAIN 0
+#define TYPE_GLOBAL 1
+#define TYPE_LOCAL 2
+#define TYPE_RESERVED 3
+
+#define TAG_MAIN_INPUT 0x8
+#define TAG_MAIN_OUTPUT 0x9
+#define TAG_MAIN_FEATURE 0xB
+#define TAG_MAIN_COL_START 0xA
+#define TAG_MAIN_COL_END 0xC
+
+#define TAG_GLOB_USAGE 0
+#define TAG_GLOB_LOG_MIN 1
+#define TAG_GLOB_LOG_MAX 2
+#define TAG_GLOB_PHYS_MIN 3
+#define TAG_GLOB_PHYS_MAX 4
+#define TAG_GLOB_UNIT_EXP 5
+#define TAG_GLOB_UNIT 6
+#define TAG_GLOB_REPORT_SZ 7
+#define TAG_GLOB_REPORT_ID 8
+#define TAG_GLOB_REPORT_CNT 9
+#define TAG_GLOB_PUSH 10
+#define TAG_GLOB_POP 11
+
+#define TAG_GLOB_MAX 12
+
+#define DIGITIZER_USAGE_TIP_PRESSURE 0x30
+#define DIGITIZER_USAGE_TILT_X 0x3D
+#define DIGITIZER_USAGE_TILT_Y 0x3E
+
+
+/*
+ *
+ * This is an abbreviated parser for the HID Report Descriptor. We
+ * know what devices we are talking to, so this is by no means meant
+ * to be generic. We can make some safe assumptions:
+ *
+ * - We know there are no LONG tags, all short
+ * - We know that we have no MAIN Feature and MAIN Output items
+ * - We know what the IRQ reports are supposed to look like.
+ *
+ * The main purpose of this is to use the HID report desc to figure
+ * out the mins and maxs of the fields in the IRQ reports. The IRQ
+ * reports for 400/401 change slightly if the max X is bigger than 64K.
+ *
+ */
+static void parse_hid_report_descriptor(struct gtco *device, char * report,
+ int length)
+{
+ int x,i=0;
+
+ /* Tag primitive vars */
+ __u8 prefix;
+ __u8 size;
+ __u8 tag;
+ __u8 type;
+ __u8 data = 0;
+ __u16 data16 = 0;
+ __u32 data32 = 0;
+
+
+ /* For parsing logic */
+ int inputnum = 0;
+ __u32 usage = 0;
+
+ /* Global Values, indexed by TAG */
+ __u32 globalval[TAG_GLOB_MAX];
+ __u32 oldval[TAG_GLOB_MAX];
+
+ /* Debug stuff */
+ char maintype='x';
+ char globtype[12];
+ int indent=0;
+ char indentstr[10]="";
+
+
+
+ dbg("======>>>>>>PARSE<<<<<<======");
+
+ /* Walk this report and pull out the info we need */
+ while (i<length){
+ prefix=report[i];
+
+ /* Skip over prefix */
+ i++;
+
+ /* Determine data size and save the data in the proper variable */
+ size = PREF_SIZE(prefix);
+ switch(size){
+ case 1:
+ data = report[i];
+ break;
+ case 2:
+ data16 = le16_to_cpu(get_unaligned((__le16*)(&(report[i]))));
+ break;
+ case 3:
+ size = 4;
+ data32 = le32_to_cpu(get_unaligned((__le32*)(&(report[i]))));
+ }
+
+ /* Skip size of data */
+ i+=size;
+
+ /* What we do depends on the tag type */
+ tag = PREF_TAG(prefix);
+ type = PREF_TYPE(prefix);
+ switch(type){
+ case TYPE_MAIN:
+ strcpy(globtype,"");
+ switch(tag){
+
+ case TAG_MAIN_INPUT:
+ /*
+ * The INPUT MAIN tag signifies this is
+ * information from a report. We need to
+ * figure out what it is and store the
+ * min/max values
+ */
+
+ maintype='I';
+ if (data==2){
+ strcpy(globtype,"Variable");
+ }
+ if (data==3){
+ strcpy(globtype,"Var|Const");
+ }
+
+ dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
+ globalval[TAG_GLOB_REPORT_ID],inputnum,
+ globalval[TAG_GLOB_LOG_MAX],globalval[TAG_GLOB_LOG_MAX],
+ globalval[TAG_GLOB_LOG_MIN],globalval[TAG_GLOB_LOG_MIN],
+ (globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]));
+
+
+ /*
+ We can assume that the first two input items
+ are always the X and Y coordinates. After
+ that, we look for everything else by
+ local usage value
+ */
+ switch (inputnum){
+ case 0: /* X coord */
+ dbg("GER: X Usage: 0x%x",usage);
+ if (device->max_X == 0){
+ device->max_X = globalval[TAG_GLOB_LOG_MAX];
+ device->min_X = globalval[TAG_GLOB_LOG_MIN];
+ }
+
+ break;
+ case 1: /* Y coord */
+ dbg("GER: Y Usage: 0x%x",usage);
+ if (device->max_Y == 0){
+ device->max_Y = globalval[TAG_GLOB_LOG_MAX];
+ device->min_Y = globalval[TAG_GLOB_LOG_MIN];
+ }
+ break;
+ default:
+ /* Tilt X */
+ if (usage == DIGITIZER_USAGE_TILT_X){
+ if (device->maxtilt_X == 0){
+ device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
+ device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
+ }
+ }
+
+ /* Tilt Y */
+ if (usage == DIGITIZER_USAGE_TILT_Y){
+ if (device->maxtilt_Y == 0){
+ device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
+ device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
+ }
+ }
+
+
+ /* Pressure */
+ if (usage == DIGITIZER_USAGE_TIP_PRESSURE){
+ if (device->maxpressure == 0){
+ device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
+ device->minpressure = globalval[TAG_GLOB_LOG_MIN];
+ }
+ }
+
+ break;
+ }
+
+ inputnum++;
+
+
+ break;
+ case TAG_MAIN_OUTPUT:
+ maintype='O';
+ break;
+ case TAG_MAIN_FEATURE:
+ maintype='F';
+ break;
+ case TAG_MAIN_COL_START:
+ maintype='S';
+
+ if (data==0){
+ dbg("======>>>>>> Physical");
+ strcpy(globtype,"Physical");
+ }else{
+ dbg("======>>>>>>");
+ }
+
+ /* Indent the debug output */
+ indent++;
+ for (x=0;x<indent;x++){
+ indentstr[x]='-';
+ }
+ indentstr[x]=0;
+
+ /* Save global tags */
+ for (x=0;x<TAG_GLOB_MAX;x++){
+ oldval[x] = globalval[x];
+ }
+
+ break;
+ case TAG_MAIN_COL_END:
+ dbg("<<<<<<======");
+ maintype='E';
+ indent--;
+ for (x=0;x<indent;x++){
+ indentstr[x]='-';
+ }
+ indentstr[x]=0;
+
+ /* Copy global tags back */
+ for (x=0;x<TAG_GLOB_MAX;x++){
+ globalval[x] = oldval[x];
+ }
+
+ break;
+ }
+
+ switch (size){
+ case 1:
+ dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+ indentstr,tag,maintype,size,globtype,data);
+ break;
+ case 2:
+ dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+ indentstr,tag,maintype,size,globtype, data16);
+ break;
+ case 4:
+ dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+ indentstr,tag,maintype,size,globtype,data32);
+ break;
+ }
+ break;
+ case TYPE_GLOBAL:
+ switch(tag){
+ case TAG_GLOB_USAGE:
+ /*
+ * First time we hit the global usage tag,
+ * it should tell us the type of device
+ */
+ if (device->usage == 0){
+ device->usage = data;
+ }
+ strcpy(globtype,"USAGE");
+ break;
+ case TAG_GLOB_LOG_MIN :
+ strcpy(globtype,"LOG_MIN");
+ break;
+ case TAG_GLOB_LOG_MAX :
+ strcpy(globtype,"LOG_MAX");
+ break;
+ case TAG_GLOB_PHYS_MIN :
+ strcpy(globtype,"PHYS_MIN");
+ break;
+ case TAG_GLOB_PHYS_MAX :
+ strcpy(globtype,"PHYS_MAX");
+ break;
+ case TAG_GLOB_UNIT_EXP :
+ strcpy(globtype,"EXP");
+ break;
+ case TAG_GLOB_UNIT :
+ strcpy(globtype,"UNIT");
+ break;
+ case TAG_GLOB_REPORT_SZ :
+ strcpy(globtype,"REPORT_SZ");
+ break;
+ case TAG_GLOB_REPORT_ID :
+ strcpy(globtype,"REPORT_ID");
+ /* New report, restart numbering */
+ inputnum=0;
+ break;
+ case TAG_GLOB_REPORT_CNT:
+ strcpy(globtype,"REPORT_CNT");
+ break;
+ case TAG_GLOB_PUSH :
+ strcpy(globtype,"PUSH");
+ break;
+ case TAG_GLOB_POP:
+ strcpy(globtype,"POP");
+ break;
+ }
+
+
+ /* Check to make sure we have a good tag number
+ so we don't overflow array */
+ if (tag < TAG_GLOB_MAX){
+ switch (size){
+ case 1:
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data);
+ globalval[tag]=data;
+ break;
+ case 2:
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16);
+ globalval[tag]=data16;
+ break;
+ case 4:
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32);
+ globalval[tag]=data32;
+ break;
+ }
+ }else{
+ dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
+ indentstr,tag,size);
+ }
+
+
+ break;
+
+ case TYPE_LOCAL:
+ switch(tag){
+ case TAG_GLOB_USAGE:
+ strcpy(globtype,"USAGE");
+ /* Always 1 byte */
+ usage = data;
+ break;
+ case TAG_GLOB_LOG_MIN :
+ strcpy(globtype,"MIN");
+ break;
+ case TAG_GLOB_LOG_MAX :
+ strcpy(globtype,"MAX");
+ break;
+ default:
+ strcpy(globtype,"UNKNOWN");
+ }
+
+ switch (size){
+ case 1:
+ dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+ indentstr,tag,globtype,size,data);
+ break;
+ case 2:
+ dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+ indentstr,tag,globtype,size,data16);
+ break;
+ case 4:
+ dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+ indentstr,tag,globtype,size,data32);
+ break;
+ }
+
+ break;
+ }
+
+ }
+
+}
+
+
+
+/* INPUT DRIVER Routines */
+
+
+/*
+ * Called when opening the input device. This will submit the URB to
+ * the usb system so we start getting reports
+ */
+static int gtco_input_open(struct input_dev *inputdev)
+{
+ struct gtco *device;
+ device = inputdev->private;
+
+ device->urbinfo->dev = device->usbdev;
+ if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) {
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ Called when closing the input device. This will unlink the URB
+*/
+static void gtco_input_close(struct input_dev *inputdev)
+{
+ struct gtco *device = inputdev->private;
+
+ usb_kill_urb(device->urbinfo);
+
+}
+
+
+/*
+ * Setup input device capabilities. Tell the input system what this
+ * device is capable of generating.
+ *
+ * This information is based on what is read from the HID report and
+ * placed in the struct gtco structure
+ *
+ */
+static void gtco_setup_caps(struct input_dev *inputdev)
+{
+ struct gtco *device = inputdev->private;
+
+
+ /* Which events */
+ inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+
+
+ /* Misc event menu block */
+ inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
+
+
+ /* Absolute values based on HID report info */
+ input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
+ 0, 0);
+ input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
+ 0, 0);
+
+ /* Proximity */
+ input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
+
+ /* Tilt & pressure */
+ input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
+ device->maxtilt_X, 0, 0);
+ input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
+ device->maxtilt_Y, 0, 0);
+ input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
+ device->maxpressure, 0, 0);
+
+
+ /* Transducer */
+ input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0);
+
+}
+
+
+
+/* USB Routines */
+
+
+/*
+ * URB callback routine. Called when we get IRQ reports from the
+ * digitizer.
+ *
+ * This bridges the USB and input device worlds. It generates events
+ * on the input device based on the USB reports.
+ */
+static void gtco_urb_callback(struct urb *urbinfo)
+{
+
+
+ struct gtco *device = urbinfo->context;
+ struct input_dev *inputdev;
+ int rc;
+ u32 val = 0;
+ s8 valsigned = 0;
+ char le_buffer[2];
+
+ inputdev = device->inputdevice;
+
+
+ /* Was callback OK? */
+ if ((urbinfo->status == -ECONNRESET ) ||
+ (urbinfo->status == -ENOENT ) ||
+ (urbinfo->status == -ESHUTDOWN )){
+
+ /* Shutdown is occurring. Return and don't queue up any more */
+ return;
+ }
+
+ if (urbinfo->status != 0 ) {
+ /* Some unknown error. Hopefully temporary. Just go and */
+ /* requeue an URB */
+ goto resubmit;
+ }
+
+ /*
+ * Good URB, now process
+ */
+
+ /* PID dependent when we interpret the report */
+ if ((inputdev->id.product == PID_1000 )||
+ (inputdev->id.product == PID_1001 )||
+ (inputdev->id.product == PID_1002 ))
+ {
+
+ /*
+ * Switch on the report ID
+ * Conveniently, the reports have more information, the higher
+ * the report number. We can just fall through the case
+ * statements if we start with the highest number report
+ */
+ switch(device->buffer[0]){
+ case 5:
+ /* Pressure is 9 bits */
+ val = ((u16)(device->buffer[8]) << 1);
+ val |= (u16)(device->buffer[7] >> 7);
+ input_report_abs(inputdev, ABS_PRESSURE,
+ device->buffer[8]);
+
+ /* Mask out the Y tilt value used for pressure */
+ device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
+
+
+ /* Fall thru */
+ case 4:
+ /* Tilt */
+
+ /* Sign extend these 7 bit numbers. */
+ if (device->buffer[6] & 0x40)
+ device->buffer[6] |= 0x80;
+
+ if (device->buffer[7] & 0x40)
+ device->buffer[7] |= 0x80;
+
+
+ valsigned = (device->buffer[6]);
+ input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
+
+ valsigned = (device->buffer[7]);
+ input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
+
+ /* Fall thru */
+
+ case 2:
+ case 3:
+ /* Convert buttons, only 5 bits possible */
+ val = (device->buffer[5])&MASK_BUTTON;
+
+ /* We don't apply any meaning to the bitmask,
+ just report */
+ input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+ /* Fall thru */
+ case 1:
+
+ /* All reports have X and Y coords in the same place */
+ val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1])));
+ input_report_abs(inputdev, ABS_X, val);
+
+ val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3])));
+ input_report_abs(inputdev, ABS_Y, val);
+
+
+ /* Ditto for proximity bit */
+ if (device->buffer[5]& MASK_INRANGE){
+ val = 1;
+ }else{
+ val=0;
+ }
+ input_report_abs(inputdev, ABS_DISTANCE, val);
+
+
+ /* Report 1 is an exception to how we handle buttons */
+ /* Buttons are an index, not a bitmask */
+ if (device->buffer[0] == 1){
+
+ /* Convert buttons, 5 bit index */
+ /* Report value of index set as one,
+ the rest as 0 */
+ val = device->buffer[5]& MASK_BUTTON;
+ dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
+ val,val);
+
+ /*
+ * We don't apply any meaning to the button
+ * index, just report it
+ */
+ input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+
+ }
+
+ break;
+ case 7:
+ /* Menu blocks */
+ input_event(inputdev, EV_MSC, MSC_SCAN,
+ device->buffer[1]);
+
+
+ break;
+
+ }
+
+
+ }
+ /* Other pid class */
+ if ((inputdev->id.product == PID_400 )||
+ (inputdev->id.product == PID_401 ))
+ {
+
+ /* Report 2 */
+ if (device->buffer[0] == 2){
+ /* Menu blocks */
+ input_event(inputdev, EV_MSC, MSC_SCAN,
+ device->buffer[1]);
+ }
+
+ /* Report 1 */
+ if (device->buffer[0] == 1){
+ char buttonbyte;
+
+
+ /* IF X max > 64K, we still a bit from the y report */
+ if (device->max_X > 0x10000){
+
+ val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1])));
+ val |= (u32)(((u8)device->buffer[3]&0x1)<< 16);
+
+ input_report_abs(inputdev, ABS_X, val);
+
+ le_buffer[0] = (u8)((u8)(device->buffer[3])>>1);
+ le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7);
+
+ le_buffer[1] = (u8)(device->buffer[4]>>1);
+ le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7);
+
+ val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer)));
+
+ input_report_abs(inputdev, ABS_Y, val);
+
+
+ /*
+ * Shift the button byte right by one to
+ * make it look like the standard report
+ */
+ buttonbyte = (device->buffer[5])>>1;
+ }else{
+
+ val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1]))));
+ input_report_abs(inputdev, ABS_X, val);
+
+ val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3]))));
+ input_report_abs(inputdev, ABS_Y, val);
+
+ buttonbyte = device->buffer[5];
+
+ }
+
+
+ /* BUTTONS and PROXIMITY */
+ if (buttonbyte& MASK_INRANGE){
+ val = 1;
+ }else{
+ val=0;
+ }
+ input_report_abs(inputdev, ABS_DISTANCE, val);
+
+ /* Convert buttons, only 4 bits possible */
+ val = buttonbyte&0x0F;
+#ifdef USE_BUTTONS
+ for ( i=0;i<5;i++){
+ input_report_key(inputdev, BTN_DIGI+i,val&(1<<i));
+ }
+#else
+ /* We don't apply any meaning to the bitmask, just report */
+ input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+#endif
+ /* TRANSDUCER */
+ input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
+
+ }
+ }
+
+ /* Everybody gets report ID's */
+ input_event(inputdev, EV_MSC, MSC_RAW, device->buffer[0]);
+
+ /* Sync it up */
+ input_sync(inputdev);
+
+ resubmit:
+ rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
+ if (rc != 0) {
+ err("usb_submit_urb failed rc=0x%x",rc);
+ }
+
+}
+
+/*
+ * The probe routine. This is called when the kernel find the matching USB
+ * vendor/product. We do the following:
+ *
+ * - Allocate mem for a local structure to manage the device
+ * - Request a HID Report Descriptor from the device and parse it to
+ * find out the device parameters
+ * - Create an input device and assign it attributes
+ * - Allocate an URB so the device can talk to us when the input
+ * queue is open
+ */
+static int gtco_probe(struct usb_interface *usbinterface,
+ const struct usb_device_id *id)
+{
+
+ struct gtco *device = NULL;
+ char path[PATHLENGTH];
+ struct input_dev *inputdev;
+ struct hid_descriptor *hid_desc;
+ char *report;
+ int result=0, retry;
+ struct usb_endpoint_descriptor *endpoint;
+
+ /* Allocate memory for device structure */
+ device = kzalloc(sizeof(struct gtco), GFP_KERNEL);
+ if (device == NULL) {
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+
+ device->inputdevice = input_allocate_device();
+ if (!device->inputdevice){
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+ /* Get pointer to the input device */
+ inputdev = device->inputdevice;
+
+ /* Save interface information */
+ device->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
+
+
+ /* Allocate some data for incoming reports */
+ device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE,
+ GFP_KERNEL, &(device->buf_dma));
+ if (!device->buffer){
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+ /* Allocate URB for reports */
+ device->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
+ if (!device->urbinfo) {
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+
+ /*
+ * The endpoint is always altsetting 0, we know this since we know
+ * this device only has one interrupt endpoint
+ */
+ endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+ /* Some debug */
+ dbg("gtco # interfaces: %d",usbinterface->num_altsetting);
+ dbg("num endpoints: %d",usbinterface->cur_altsetting->desc.bNumEndpoints);
+ dbg("interface class: %d",usbinterface->cur_altsetting->desc.bInterfaceClass);
+ dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType);
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+ dbg("endpoint: we have interrupt endpoint\n");
+
+ dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen);
+
+
+
+ /*
+ * Find the HID descriptor so we can find out the size of the
+ * HID report descriptor
+ */
+ if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
+ HID_DEVICE_TYPE,&hid_desc) != 0){
+ err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ input_free_device(device->inputdevice);
+ kfree(device);
+ return -EIO;
+ }
+
+ dbg("Extra descriptor success: type:%d len:%d",
+ hid_desc->bDescriptorType, hid_desc->wDescriptorLength);
+
+ if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) {
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+ /* Couple of tries to get reply */
+ for (retry=0;retry<3;retry++) {
+ result = usb_control_msg(device->usbdev,
+ usb_rcvctrlpipe(device->usbdev, 0),
+ USB_REQ_GET_DESCRIPTOR,
+ USB_RECIP_INTERFACE | USB_DIR_IN,
+ (REPORT_DEVICE_TYPE << 8),
+ 0, /* interface */
+ report,
+ hid_desc->wDescriptorLength,
+ 5000); /* 5 secs */
+
+ if (result == hid_desc->wDescriptorLength)
+ break;
+ }
+
+ /* If we didn't get the report, fail */
+ dbg("usb_control_msg result: :%d", result);
+ if (result != hid_desc->wDescriptorLength){
+ kfree(report);
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("Failed to get HID Report Descriptor of size: %d",
+ hid_desc->wDescriptorLength);
+ return -EIO;
+ }
+
+
+ /* Now we parse the report */
+ parse_hid_report_descriptor(device,report,result);
+
+ /* Now we delete it */
+ kfree(report);
+
+ /* Create a device file node */
+ usb_make_path(device->usbdev, path, PATHLENGTH);
+ sprintf(device->usbpath, "%s/input0", path);
+
+
+ /* Set Input device functions */
+ inputdev->open = gtco_input_open;
+ inputdev->close = gtco_input_close;
+
+ /* Set input device information */
+ inputdev->name = "GTCO_CalComp";
+ inputdev->phys = device->usbpath;
+ inputdev->private = device;
+
+
+ /* Now set up all the input device capabilities */
+ gtco_setup_caps(inputdev);
+
+ /* Set input device required ID information */
+ usb_to_input_id(device->usbdev, &device->inputdevice->id);
+ inputdev->cdev.dev = &usbinterface->dev;
+
+ /* Setup the URB, it will be posted later on open of input device */
+ endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+ usb_fill_int_urb(device->urbinfo,
+ device->usbdev,
+ usb_rcvintpipe(device->usbdev,
+ endpoint->bEndpointAddress),
+ device->buffer,
+ REPORT_MAX_SIZE,
+ gtco_urb_callback,
+ device,
+ endpoint->bInterval);
+
+ device->urbinfo->transfer_dma = device->buf_dma;
+ device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+
+ /* Save device pointer in USB interface device */
+ usb_set_intfdata(usbinterface, device);
+
+ /* All done, now register the input device */
+ input_register_device(inputdev);
+
+ info( "gtco driver created usb: %s\n", path);
+ return 0;
+
+}
+
+/*
+ * This function is a standard USB function called when the USB device
+ * is disconnected. We will get rid of the URV, de-register the input
+ * device, and free up allocated memory
+ */
+static void gtco_disconnect(struct usb_interface *interface)
+{
+
+ /* Grab private device ptr */
+ struct gtco *device = usb_get_intfdata (interface);
+ struct input_dev *inputdev;
+
+ inputdev = device->inputdevice;
+
+ /* Now reverse all the registration stuff */
+ if (device) {
+ input_unregister_device(inputdev);
+ usb_kill_urb(device->urbinfo);
+ usb_free_urb(device->urbinfo);
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ kfree(device);
+ }
+
+ info("gtco driver disconnected");
+}
+
+
+/* STANDARD MODULE LOAD ROUTINES */
+
+static struct usb_driver gtco_driverinfo_table = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+ .owner = THIS_MODULE,
+#endif
+ .name = "gtco",
+ .id_table = gtco_usbid_table,
+ .probe = gtco_probe,
+ .disconnect = gtco_disconnect,
+};
+/*
+ * Register this module with the USB subsystem
+ */
+static int __init gtco_init(void)
+{
+ int rc;
+ rc = usb_register(&gtco_driverinfo_table);
+ if (rc) {
+ err("usb_register() failed rc=0x%x", rc);
+ }
+ printk("GTCO usb driver version: %s",GTCO_VERSION);
+ return rc;
+}
+
+/*
+ * Deregister this module with the USB subsystem
+ */
+static void __exit gtco_exit(void)
+{
+ usb_deregister(&gtco_driverinfo_table);
+}
+
+module_init (gtco_init);
+module_exit (gtco_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 0811c39bd14..84983d1b716 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -4,6 +4,7 @@
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006 Jiri Kosina
*/
/*
@@ -32,8 +33,10 @@
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
#include <linux/hiddev.h>
+#include <linux/hid-debug.h>
+#include "usbhid.h"
/*
* Version Information
@@ -55,887 +58,6 @@ module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
/*
- * Register a new report for a device.
- */
-
-static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
-{
- struct hid_report_enum *report_enum = device->report_enum + type;
- struct hid_report *report;
-
- if (report_enum->report_id_hash[id])
- return report_enum->report_id_hash[id];
-
- if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
- return NULL;
-
- if (id != 0)
- report_enum->numbered = 1;
-
- report->id = id;
- report->type = type;
- report->size = 0;
- report->device = device;
- report_enum->report_id_hash[id] = report;
-
- list_add_tail(&report->list, &report_enum->report_list);
-
- return report;
-}
-
-/*
- * Register a new field for this report.
- */
-
-static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
-{
- struct hid_field *field;
-
- if (report->maxfield == HID_MAX_FIELDS) {
- dbg("too many fields in report");
- return NULL;
- }
-
- if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
- + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
-
- field->index = report->maxfield++;
- report->field[field->index] = field;
- field->usage = (struct hid_usage *)(field + 1);
- field->value = (unsigned *)(field->usage + usages);
- field->report = report;
-
- return field;
-}
-
-/*
- * Open a collection. The type/usage is pushed on the stack.
- */
-
-static int open_collection(struct hid_parser *parser, unsigned type)
-{
- struct hid_collection *collection;
- unsigned usage;
-
- usage = parser->local.usage[0];
-
- if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
- dbg("collection stack overflow");
- return -1;
- }
-
- if (parser->device->maxcollection == parser->device->collection_size) {
- collection = kmalloc(sizeof(struct hid_collection) *
- parser->device->collection_size * 2, GFP_KERNEL);
- if (collection == NULL) {
- dbg("failed to reallocate collection array");
- return -1;
- }
- memcpy(collection, parser->device->collection,
- sizeof(struct hid_collection) *
- parser->device->collection_size);
- memset(collection + parser->device->collection_size, 0,
- sizeof(struct hid_collection) *
- parser->device->collection_size);
- kfree(parser->device->collection);
- parser->device->collection = collection;
- parser->device->collection_size *= 2;
- }
-
- parser->collection_stack[parser->collection_stack_ptr++] =
- parser->device->maxcollection;
-
- collection = parser->device->collection +
- parser->device->maxcollection++;
- collection->type = type;
- collection->usage = usage;
- collection->level = parser->collection_stack_ptr - 1;
-
- if (type == HID_COLLECTION_APPLICATION)
- parser->device->maxapplication++;
-
- return 0;
-}
-
-/*
- * Close a collection.
- */
-
-static int close_collection(struct hid_parser *parser)
-{
- if (!parser->collection_stack_ptr) {
- dbg("collection stack underflow");
- return -1;
- }
- parser->collection_stack_ptr--;
- return 0;
-}
-
-/*
- * Climb up the stack, search for the specified collection type
- * and return the usage.
- */
-
-static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
-{
- int n;
- for (n = parser->collection_stack_ptr - 1; n >= 0; n--)
- if (parser->device->collection[parser->collection_stack[n]].type == type)
- return parser->device->collection[parser->collection_stack[n]].usage;
- return 0; /* we know nothing about this usage type */
-}
-
-/*
- * Add a usage to the temporary parser table.
- */
-
-static int hid_add_usage(struct hid_parser *parser, unsigned usage)
-{
- if (parser->local.usage_index >= HID_MAX_USAGES) {
- dbg("usage index exceeded");
- return -1;
- }
- parser->local.usage[parser->local.usage_index] = usage;
- parser->local.collection_index[parser->local.usage_index] =
- parser->collection_stack_ptr ?
- parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
- parser->local.usage_index++;
- return 0;
-}
-
-/*
- * Register a new field for this report.
- */
-
-static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags)
-{
- struct hid_report *report;
- struct hid_field *field;
- int usages;
- unsigned offset;
- int i;
-
- if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
- dbg("hid_register_report failed");
- return -1;
- }
-
- if (parser->global.logical_maximum < parser->global.logical_minimum) {
- dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
- return -1;
- }
-
- offset = report->size;
- report->size += parser->global.report_size * parser->global.report_count;
-
- if (!parser->local.usage_index) /* Ignore padding fields */
- return 0;
-
- usages = max_t(int, parser->local.usage_index, parser->global.report_count);
-
- if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
- return 0;
-
- field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
- field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
- field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
-
- for (i = 0; i < usages; i++) {
- int j = i;
- /* Duplicate the last usage we parsed if we have excess values */
- if (i >= parser->local.usage_index)
- j = parser->local.usage_index - 1;
- field->usage[i].hid = parser->local.usage[j];
- field->usage[i].collection_index =
- parser->local.collection_index[j];
- }
-
- field->maxusage = usages;
- field->flags = flags;
- field->report_offset = offset;
- field->report_type = report_type;
- field->report_size = parser->global.report_size;
- field->report_count = parser->global.report_count;
- field->logical_minimum = parser->global.logical_minimum;
- field->logical_maximum = parser->global.logical_maximum;
- field->physical_minimum = parser->global.physical_minimum;
- field->physical_maximum = parser->global.physical_maximum;
- field->unit_exponent = parser->global.unit_exponent;
- field->unit = parser->global.unit;
-
- return 0;
-}
-
-/*
- * Read data value from item.
- */
-
-static u32 item_udata(struct hid_item *item)
-{
- switch (item->size) {
- case 1: return item->data.u8;
- case 2: return item->data.u16;
- case 4: return item->data.u32;
- }
- return 0;
-}
-
-static s32 item_sdata(struct hid_item *item)
-{
- switch (item->size) {
- case 1: return item->data.s8;
- case 2: return item->data.s16;
- case 4: return item->data.s32;
- }
- return 0;
-}
-
-/*
- * Process a global item.
- */
-
-static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
-{
- switch (item->tag) {
-
- case HID_GLOBAL_ITEM_TAG_PUSH:
-
- if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
- dbg("global enviroment stack overflow");
- return -1;
- }
-
- memcpy(parser->global_stack + parser->global_stack_ptr++,
- &parser->global, sizeof(struct hid_global));
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_POP:
-
- if (!parser->global_stack_ptr) {
- dbg("global enviroment stack underflow");
- return -1;
- }
-
- memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
- sizeof(struct hid_global));
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
- parser->global.usage_page = item_udata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
- parser->global.logical_minimum = item_sdata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
- if (parser->global.logical_minimum < 0)
- parser->global.logical_maximum = item_sdata(item);
- else
- parser->global.logical_maximum = item_udata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
- parser->global.physical_minimum = item_sdata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
- if (parser->global.physical_minimum < 0)
- parser->global.physical_maximum = item_sdata(item);
- else
- parser->global.physical_maximum = item_udata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
- parser->global.unit_exponent = item_sdata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_UNIT:
- parser->global.unit = item_udata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
- if ((parser->global.report_size = item_udata(item)) > 32) {
- dbg("invalid report_size %d", parser->global.report_size);
- return -1;
- }
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
- if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
- dbg("invalid report_count %d", parser->global.report_count);
- return -1;
- }
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_REPORT_ID:
- if ((parser->global.report_id = item_udata(item)) == 0) {
- dbg("report_id 0 is invalid");
- return -1;
- }
- return 0;
-
- default:
- dbg("unknown global tag 0x%x", item->tag);
- return -1;
- }
-}
-
-/*
- * Process a local item.
- */
-
-static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
-{
- __u32 data;
- unsigned n;
-
- if (item->size == 0) {
- dbg("item data expected for local item");
- return -1;
- }
-
- data = item_udata(item);
-
- switch (item->tag) {
-
- case HID_LOCAL_ITEM_TAG_DELIMITER:
-
- if (data) {
- /*
- * We treat items before the first delimiter
- * as global to all usage sets (branch 0).
- * In the moment we process only these global
- * items and the first delimiter set.
- */
- if (parser->local.delimiter_depth != 0) {
- dbg("nested delimiters");
- return -1;
- }
- parser->local.delimiter_depth++;
- parser->local.delimiter_branch++;
- } else {
- if (parser->local.delimiter_depth < 1) {
- dbg("bogus close delimiter");
- return -1;
- }
- parser->local.delimiter_depth--;
- }
- return 1;
-
- case HID_LOCAL_ITEM_TAG_USAGE:
-
- if (parser->local.delimiter_branch > 1) {
- dbg("alternative usage ignored");
- return 0;
- }
-
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
-
- return hid_add_usage(parser, data);
-
- case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
-
- if (parser->local.delimiter_branch > 1) {
- dbg("alternative usage ignored");
- return 0;
- }
-
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
-
- parser->local.usage_minimum = data;
- return 0;
-
- case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
-
- if (parser->local.delimiter_branch > 1) {
- dbg("alternative usage ignored");
- return 0;
- }
-
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
-
- for (n = parser->local.usage_minimum; n <= data; n++)
- if (hid_add_usage(parser, n)) {
- dbg("hid_add_usage failed\n");
- return -1;
- }
- return 0;
-
- default:
-
- dbg("unknown local item tag 0x%x", item->tag);
- return 0;
- }
- return 0;
-}
-
-/*
- * Process a main item.
- */
-
-static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
-{
- __u32 data;
- int ret;
-
- data = item_udata(item);
-
- switch (item->tag) {
- case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
- ret = open_collection(parser, data & 0xff);
- break;
- case HID_MAIN_ITEM_TAG_END_COLLECTION:
- ret = close_collection(parser);
- break;
- case HID_MAIN_ITEM_TAG_INPUT:
- ret = hid_add_field(parser, HID_INPUT_REPORT, data);
- break;
- case HID_MAIN_ITEM_TAG_OUTPUT:
- ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
- break;
- case HID_MAIN_ITEM_TAG_FEATURE:
- ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
- break;
- default:
- dbg("unknown main item tag 0x%x", item->tag);
- ret = 0;
- }
-
- memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */
-
- return ret;
-}
-
-/*
- * Process a reserved item.
- */
-
-static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item)
-{
- dbg("reserved item type, tag 0x%x", item->tag);
- return 0;
-}
-
-/*
- * Free a report and all registered fields. The field->usage and
- * field->value table's are allocated behind the field, so we need
- * only to free(field) itself.
- */
-
-static void hid_free_report(struct hid_report *report)
-{
- unsigned n;
-
- for (n = 0; n < report->maxfield; n++)
- kfree(report->field[n]);
- kfree(report);
-}
-
-/*
- * Free a device structure, all reports, and all fields.
- */
-
-static void hid_free_device(struct hid_device *device)
-{
- unsigned i,j;
-
- for (i = 0; i < HID_REPORT_TYPES; i++) {
- struct hid_report_enum *report_enum = device->report_enum + i;
-
- for (j = 0; j < 256; j++) {
- struct hid_report *report = report_enum->report_id_hash[j];
- if (report)
- hid_free_report(report);
- }
- }
-
- kfree(device->rdesc);
- kfree(device);
-}
-
-/*
- * Fetch a report description item from the data stream. We support long
- * items, though they are not used yet.
- */
-
-static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
-{
- u8 b;
-
- if ((end - start) <= 0)
- return NULL;
-
- b = *start++;
-
- item->type = (b >> 2) & 3;
- item->tag = (b >> 4) & 15;
-
- if (item->tag == HID_ITEM_TAG_LONG) {
-
- item->format = HID_ITEM_FORMAT_LONG;
-
- if ((end - start) < 2)
- return NULL;
-
- item->size = *start++;
- item->tag = *start++;
-
- if ((end - start) < item->size)
- return NULL;
-
- item->data.longdata = start;
- start += item->size;
- return start;
- }
-
- item->format = HID_ITEM_FORMAT_SHORT;
- item->size = b & 3;
-
- switch (item->size) {
-
- case 0:
- return start;
-
- case 1:
- if ((end - start) < 1)
- return NULL;
- item->data.u8 = *start++;
- return start;
-
- case 2:
- if ((end - start) < 2)
- return NULL;
- item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));
- start = (__u8 *)((__le16 *)start + 1);
- return start;
-
- case 3:
- item->size++;
- if ((end - start) < 4)
- return NULL;
- item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start));
- start = (__u8 *)((__le32 *)start + 1);
- return start;
- }
-
- return NULL;
-}
-
-/*
- * Parse a report description into a hid_device structure. Reports are
- * enumerated, fields are attached to these reports.
- */
-
-static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
-{
- struct hid_device *device;
- struct hid_parser *parser;
- struct hid_item item;
- __u8 *end;
- unsigned i;
- static int (*dispatch_type[])(struct hid_parser *parser,
- struct hid_item *item) = {
- hid_parser_main,
- hid_parser_global,
- hid_parser_local,
- hid_parser_reserved
- };
-
- if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
- return NULL;
-
- if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
- HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
- kfree(device);
- return NULL;
- }
- device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
-
- for (i = 0; i < HID_REPORT_TYPES; i++)
- INIT_LIST_HEAD(&device->report_enum[i].report_list);
-
- if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) {
- kfree(device->collection);
- kfree(device);
- return NULL;
- }
- memcpy(device->rdesc, start, size);
- device->rsize = size;
-
- if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
- kfree(device->rdesc);
- kfree(device->collection);
- kfree(device);
- return NULL;
- }
- parser->device = device;
-
- end = start + size;
- while ((start = fetch_item(start, end, &item)) != NULL) {
-
- if (item.format != HID_ITEM_FORMAT_SHORT) {
- dbg("unexpected long global item");
- kfree(device->collection);
- hid_free_device(device);
- kfree(parser);
- return NULL;
- }
-
- if (dispatch_type[item.type](parser, &item)) {
- dbg("item %u %u %u %u parsing failed\n",
- item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
- kfree(device->collection);
- hid_free_device(device);
- kfree(parser);
- return NULL;
- }
-
- if (start == end) {
- if (parser->collection_stack_ptr) {
- dbg("unbalanced collection at end of report description");
- kfree(device->collection);
- hid_free_device(device);
- kfree(parser);
- return NULL;
- }
- if (parser->local.delimiter_depth) {
- dbg("unbalanced delimiter at end of report description");
- kfree(device->collection);
- hid_free_device(device);
- kfree(parser);
- return NULL;
- }
- kfree(parser);
- return device;
- }
- }
-
- dbg("item fetching failed at offset %d\n", (int)(end - start));
- kfree(device->collection);
- hid_free_device(device);
- kfree(parser);
- return NULL;
-}
-
-/*
- * Convert a signed n-bit integer to signed 32-bit integer. Common
- * cases are done through the compiler, the screwed things has to be
- * done by hand.
- */
-
-static s32 snto32(__u32 value, unsigned n)
-{
- switch (n) {
- case 8: return ((__s8)value);
- case 16: return ((__s16)value);
- case 32: return ((__s32)value);
- }
- return value & (1 << (n - 1)) ? value | (-1 << n) : value;
-}
-
-/*
- * Convert a signed 32-bit integer to a signed n-bit integer.
- */
-
-static u32 s32ton(__s32 value, unsigned n)
-{
- s32 a = value >> (n - 1);
- if (a && a != -1)
- return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
- return value & ((1 << n) - 1);
-}
-
-/*
- * Extract/implement a data field from/to a little endian report (bit array).
- *
- * Code sort-of follows HID spec:
- * http://www.usb.org/developers/devclass_docs/HID1_11.pdf
- *
- * While the USB HID spec allows unlimited length bit fields in "report
- * descriptors", most devices never use more than 16 bits.
- * One model of UPS is claimed to report "LINEV" as a 32-bit field.
- * Search linux-kernel and linux-usb-devel archives for "hid-core extract".
- */
-
-static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
-{
- u64 x;
-
- WARN_ON(n > 32);
-
- report += offset >> 3; /* adjust byte index */
- offset &= 7; /* now only need bit offset into one byte */
- x = get_unaligned((u64 *) report);
- x = le64_to_cpu(x);
- x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */
- return (u32) x;
-}
-
-/*
- * "implement" : set bits in a little endian bit stream.
- * Same concepts as "extract" (see comments above).
- * The data mangled in the bit stream remains in little endian
- * order the whole time. It make more sense to talk about
- * endianness of register values by considering a register
- * a "cached" copy of the little endiad bit stream.
- */
-static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
-{
- u64 x;
- u64 m = (1ULL << n) - 1;
-
- WARN_ON(n > 32);
-
- WARN_ON(value > m);
- value &= m;
-
- report += offset >> 3;
- offset &= 7;
-
- x = get_unaligned((u64 *)report);
- x &= cpu_to_le64(~(m << offset));
- x |= cpu_to_le64(((u64) value) << offset);
- put_unaligned(x, (u64 *) report);
-}
-
-/*
- * Search an array for a value.
- */
-
-static __inline__ int search(__s32 *array, __s32 value, unsigned n)
-{
- while (n--) {
- if (*array++ == value)
- return 0;
- }
- return -1;
-}
-
-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);
- if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt)
- hiddev_hid_event(hid, field, usage, value);
-}
-
-/*
- * Analyse a received field, and fetch the data from it. The field
- * content is stored for next report processing (we do differential
- * reporting to the layer).
- */
-
-static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt)
-{
- unsigned n;
- unsigned count = field->report_count;
- unsigned offset = field->report_offset;
- unsigned size = field->report_size;
- __s32 min = field->logical_minimum;
- __s32 max = field->logical_maximum;
- __s32 *value;
-
- if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
- return;
-
- for (n = 0; n < count; n++) {
-
- value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :
- extract(data, offset + n * size, size);
-
- if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */
- && value[n] >= min && value[n] <= max
- && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
- goto exit;
- }
-
- for (n = 0; n < count; n++) {
-
- if (HID_MAIN_ITEM_VARIABLE & field->flags) {
- 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);
-
- 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);
- }
-
- memcpy(field->value, value, count * sizeof(__s32));
-exit:
- kfree(value);
-}
-
-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;
- u8 *data = urb->transfer_buffer;
- int len = urb->actual_length;
- struct hid_report *report;
- int n, size;
-
- if (!len) {
- dbg("empty report");
- return -1;
- }
-
-#ifdef DEBUG_DATA
- printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un");
-#endif
-
- n = 0; /* Normally report number is 0 */
- if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */
- n = *data++;
- len--;
- }
-
-#ifdef DEBUG_DATA
- {
- int i;
- printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len);
- for (i = 0; i < len; i++)
- printk(" %02x", data[i]);
- printk("\n");
- }
-#endif
-
- if (!(report = report_enum->report_id_hash[n])) {
- dbg("undefined report_id %d received", n);
- return -1;
- }
-
- size = ((report->size - 1) >> 3) + 1;
-
- if (len < size) {
- dbg("report %d is too short, (%d < %d)", report->id, len, size);
- memset(data + len, 0, size - len);
- }
-
- if (hid->claimed & HID_CLAIMED_HIDDEV)
- hiddev_report_event(hid, report);
-
- for (n = 0; n < report->maxfield; n++)
- hid_input_field(hid, report->field[n], data, interrupt);
-
- if (hid->claimed & HID_CLAIMED_INPUT)
- hidinput_report_event(hid, report);
-
- return 0;
-}
-
-/*
* Input submission and I/O error handler.
*/
@@ -946,15 +68,16 @@ static int hid_start_in(struct hid_device *hid)
{
unsigned long flags;
int rc = 0;
+ struct usbhid_device *usbhid = hid->driver_data;
- spin_lock_irqsave(&hid->inlock, flags);
- if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) &&
- !test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) {
- rc = usb_submit_urb(hid->urbin, GFP_ATOMIC);
+ spin_lock_irqsave(&usbhid->inlock, flags);
+ if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
+ !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
+ rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
if (rc != 0)
- clear_bit(HID_IN_RUNNING, &hid->iofl);
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
}
- spin_unlock_irqrestore(&hid->inlock, flags);
+ spin_unlock_irqrestore(&usbhid->inlock, flags);
return rc;
}
@@ -962,8 +85,9 @@ static int hid_start_in(struct hid_device *hid)
static void hid_retry_timeout(unsigned long _hid)
{
struct hid_device *hid = (struct hid_device *) _hid;
+ struct usbhid_device *usbhid = hid->driver_data;
- dev_dbg(&hid->intf->dev, "retrying intr urb\n");
+ dev_dbg(&usbhid->intf->dev, "retrying intr urb\n");
if (hid_start_in(hid))
hid_io_error(hid);
}
@@ -971,38 +95,39 @@ static void hid_retry_timeout(unsigned long _hid)
/* Workqueue routine to reset the device or clear a halt */
static void hid_reset(struct work_struct *work)
{
- struct hid_device *hid =
- container_of(work, struct hid_device, reset_work);
+ struct usbhid_device *usbhid =
+ container_of(work, struct usbhid_device, reset_work);
+ struct hid_device *hid = usbhid->hid;
int rc_lock, rc = 0;
- if (test_bit(HID_CLEAR_HALT, &hid->iofl)) {
- dev_dbg(&hid->intf->dev, "clear halt\n");
- rc = usb_clear_halt(hid->dev, hid->urbin->pipe);
- clear_bit(HID_CLEAR_HALT, &hid->iofl);
+ if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) {
+ dev_dbg(&usbhid->intf->dev, "clear halt\n");
+ rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe);
+ clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
hid_start_in(hid);
}
- else if (test_bit(HID_RESET_PENDING, &hid->iofl)) {
- dev_dbg(&hid->intf->dev, "resetting device\n");
- rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf);
+ else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+ dev_dbg(&usbhid->intf->dev, "resetting device\n");
+ rc = rc_lock = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf);
if (rc_lock >= 0) {
- rc = usb_reset_composite_device(hid->dev, hid->intf);
+ rc = usb_reset_composite_device(hid_to_usb_dev(hid), usbhid->intf);
if (rc_lock)
- usb_unlock_device(hid->dev);
+ usb_unlock_device(hid_to_usb_dev(hid));
}
- clear_bit(HID_RESET_PENDING, &hid->iofl);
+ clear_bit(HID_RESET_PENDING, &usbhid->iofl);
}
switch (rc) {
case 0:
- if (!test_bit(HID_IN_RUNNING, &hid->iofl))
+ if (!test_bit(HID_IN_RUNNING, &usbhid->iofl))
hid_io_error(hid);
break;
default:
err("can't reset device, %s-%s/input%d, status %d",
- hid->dev->bus->bus_name,
- hid->dev->devpath,
- hid->ifnum, rc);
+ hid_to_usb_dev(hid)->bus->bus_name,
+ hid_to_usb_dev(hid)->devpath,
+ usbhid->ifnum, rc);
/* FALLTHROUGH */
case -EHOSTUNREACH:
case -ENODEV:
@@ -1015,33 +140,34 @@ static void hid_reset(struct work_struct *work)
static void hid_io_error(struct hid_device *hid)
{
unsigned long flags;
+ struct usbhid_device *usbhid = hid->driver_data;
- spin_lock_irqsave(&hid->inlock, flags);
+ spin_lock_irqsave(&usbhid->inlock, flags);
/* Stop when disconnected */
- if (usb_get_intfdata(hid->intf) == NULL)
+ if (usb_get_intfdata(usbhid->intf) == NULL)
goto done;
/* When an error occurs, retry at increasing intervals */
- if (hid->retry_delay == 0) {
- hid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */
- hid->stop_retry = jiffies + msecs_to_jiffies(1000);
- } else if (hid->retry_delay < 100)
- hid->retry_delay *= 2;
+ if (usbhid->retry_delay == 0) {
+ usbhid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */
+ usbhid->stop_retry = jiffies + msecs_to_jiffies(1000);
+ } else if (usbhid->retry_delay < 100)
+ usbhid->retry_delay *= 2;
- if (time_after(jiffies, hid->stop_retry)) {
+ if (time_after(jiffies, usbhid->stop_retry)) {
/* Retries failed, so do a port reset */
- if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) {
- schedule_work(&hid->reset_work);
+ if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+ schedule_work(&usbhid->reset_work);
goto done;
}
}
- mod_timer(&hid->io_retry,
- jiffies + msecs_to_jiffies(hid->retry_delay));
+ mod_timer(&usbhid->io_retry,
+ jiffies + msecs_to_jiffies(usbhid->retry_delay));
done:
- spin_unlock_irqrestore(&hid->inlock, flags);
+ spin_unlock_irqrestore(&usbhid->inlock, flags);
}
/*
@@ -1051,28 +177,31 @@ done:
static void hid_irq_in(struct urb *urb)
{
struct hid_device *hid = urb->context;
+ struct usbhid_device *usbhid = hid->driver_data;
int status;
switch (urb->status) {
case 0: /* success */
- hid->retry_delay = 0;
- hid_input_report(HID_INPUT_REPORT, urb, 1);
+ usbhid->retry_delay = 0;
+ hid_input_report(urb->context, HID_INPUT_REPORT,
+ urb->transfer_buffer,
+ urb->actual_length, 1);
break;
case -EPIPE: /* stall */
- clear_bit(HID_IN_RUNNING, &hid->iofl);
- set_bit(HID_CLEAR_HALT, &hid->iofl);
- schedule_work(&hid->reset_work);
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+ set_bit(HID_CLEAR_HALT, &usbhid->iofl);
+ schedule_work(&usbhid->reset_work);
return;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN: /* unplug */
- clear_bit(HID_IN_RUNNING, &hid->iofl);
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
return;
case -EILSEQ: /* protocol error or unplug */
case -EPROTO: /* protocol error or unplug */
case -ETIME: /* protocol error or unplug */
case -ETIMEDOUT: /* Should never happen, but... */
- clear_bit(HID_IN_RUNNING, &hid->iofl);
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
hid_io_error(hid);
return;
default: /* error */
@@ -1081,108 +210,31 @@ static void hid_irq_in(struct urb *urb)
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
- clear_bit(HID_IN_RUNNING, &hid->iofl);
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
if (status != -EPERM) {
err("can't resubmit intr, %s-%s/input%d, status %d",
- hid->dev->bus->bus_name,
- hid->dev->devpath,
- hid->ifnum, status);
+ hid_to_usb_dev(hid)->bus->bus_name,
+ hid_to_usb_dev(hid)->devpath,
+ usbhid->ifnum, status);
hid_io_error(hid);
}
}
}
-/*
- * Output the field into the report.
- */
-
-static void hid_output_field(struct hid_field *field, __u8 *data)
-{
- unsigned count = field->report_count;
- unsigned offset = field->report_offset;
- unsigned size = field->report_size;
- unsigned n;
-
- for (n = 0; n < count; n++) {
- if (field->logical_minimum < 0) /* signed values */
- implement(data, offset + n * size, size, s32ton(field->value[n], size));
- else /* unsigned values */
- implement(data, offset + n * size, size, field->value[n]);
- }
-}
-
-/*
- * Create a report.
- */
-
-static void hid_output_report(struct hid_report *report, __u8 *data)
-{
- unsigned n;
-
- if (report->id > 0)
- *data++ = report->id;
-
- for (n = 0; n < report->maxfield; n++)
- hid_output_field(report->field[n], data);
-}
-
-/*
- * Set a field value. The report this field belongs to has to be
- * created and transferred to the device, to set this value in the
- * device.
- */
-
-int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
-{
- unsigned size = field->report_size;
-
- hid_dump_input(field->usage + offset, value);
-
- if (offset >= field->report_count) {
- dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count);
- hid_dump_field(field, 8);
- return -1;
- }
- if (field->logical_minimum < 0) {
- if (value != snto32(s32ton(value, size), size)) {
- dbg("value %d is out of range", value);
- return -1;
- }
- }
- field->value[offset] = value;
- return 0;
-}
-
-/*
- * 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;
- int i;
-
- list_for_each_entry(report, &hid->report_enum[type].report_list, list)
- for (i = 0; i < report->maxfield; i++)
- if (report->field[i]->logical == wanted_usage)
- return report->field[i];
- return NULL;
-}
-#endif /* 0 */
-
static int hid_submit_out(struct hid_device *hid)
{
struct hid_report *report;
+ struct usbhid_device *usbhid = hid->driver_data;
- report = hid->out[hid->outtail];
+ report = usbhid->out[usbhid->outtail];
- hid_output_report(report, hid->outbuf);
- hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
- hid->urbout->dev = hid->dev;
+ hid_output_report(report, usbhid->outbuf);
+ usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+ usbhid->urbout->dev = hid_to_usb_dev(hid);
dbg("submitting out urb");
- if (usb_submit_urb(hid->urbout, GFP_ATOMIC)) {
+ if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
err("usb_submit_urb(out) failed");
return -1;
}
@@ -1195,42 +247,43 @@ static int hid_submit_ctrl(struct hid_device *hid)
struct hid_report *report;
unsigned char dir;
int len;
+ struct usbhid_device *usbhid = hid->driver_data;
- report = hid->ctrl[hid->ctrltail].report;
- dir = hid->ctrl[hid->ctrltail].dir;
+ report = usbhid->ctrl[usbhid->ctrltail].report;
+ dir = usbhid->ctrl[usbhid->ctrltail].dir;
len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if (dir == USB_DIR_OUT) {
- hid_output_report(report, hid->ctrlbuf);
- hid->urbctrl->pipe = usb_sndctrlpipe(hid->dev, 0);
- hid->urbctrl->transfer_buffer_length = len;
+ hid_output_report(report, usbhid->ctrlbuf);
+ usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
+ usbhid->urbctrl->transfer_buffer_length = len;
} else {
int maxpacket, padlen;
- hid->urbctrl->pipe = usb_rcvctrlpipe(hid->dev, 0);
- maxpacket = usb_maxpacket(hid->dev, hid->urbctrl->pipe, 0);
+ usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
+ maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0);
if (maxpacket > 0) {
padlen = (len + maxpacket - 1) / maxpacket;
padlen *= maxpacket;
- if (padlen > hid->bufsize)
- padlen = hid->bufsize;
+ if (padlen > usbhid->bufsize)
+ padlen = usbhid->bufsize;
} else
padlen = 0;
- hid->urbctrl->transfer_buffer_length = padlen;
+ usbhid->urbctrl->transfer_buffer_length = padlen;
}
- hid->urbctrl->dev = hid->dev;
+ usbhid->urbctrl->dev = hid_to_usb_dev(hid);
- hid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
- hid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
- hid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
- hid->cr->wIndex = cpu_to_le16(hid->ifnum);
- hid->cr->wLength = cpu_to_le16(len);
+ usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
+ usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
+ usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
+ usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
+ usbhid->cr->wLength = cpu_to_le16(len);
dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u",
- hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
- hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength);
+ usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
+ usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
- if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) {
+ if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
err("usb_submit_urb(ctrl) failed");
return -1;
}
@@ -1245,6 +298,7 @@ static int hid_submit_ctrl(struct hid_device *hid)
static void hid_irq_out(struct urb *urb)
{
struct hid_device *hid = urb->context;
+ struct usbhid_device *usbhid = hid->driver_data;
unsigned long flags;
int unplug = 0;
@@ -1262,24 +316,24 @@ static void hid_irq_out(struct urb *urb)
warn("output irq status %d received", urb->status);
}
- spin_lock_irqsave(&hid->outlock, flags);
+ spin_lock_irqsave(&usbhid->outlock, flags);
if (unplug)
- hid->outtail = hid->outhead;
+ usbhid->outtail = usbhid->outhead;
else
- hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
+ usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
- if (hid->outhead != hid->outtail) {
+ if (usbhid->outhead != usbhid->outtail) {
if (hid_submit_out(hid)) {
- clear_bit(HID_OUT_RUNNING, &hid->iofl);
+ clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
wake_up(&hid->wait);
}
- spin_unlock_irqrestore(&hid->outlock, flags);
+ spin_unlock_irqrestore(&usbhid->outlock, flags);
return;
}
- clear_bit(HID_OUT_RUNNING, &hid->iofl);
- spin_unlock_irqrestore(&hid->outlock, flags);
+ clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+ spin_unlock_irqrestore(&usbhid->outlock, flags);
wake_up(&hid->wait);
}
@@ -1290,15 +344,17 @@ static void hid_irq_out(struct urb *urb)
static void hid_ctrl(struct urb *urb)
{
struct hid_device *hid = urb->context;
+ struct usbhid_device *usbhid = hid->driver_data;
unsigned long flags;
int unplug = 0;
- spin_lock_irqsave(&hid->ctrllock, flags);
+ spin_lock_irqsave(&usbhid->ctrllock, flags);
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);
+ if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
+ hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type,
+ urb->transfer_buffer, urb->actual_length, 0);
break;
case -ESHUTDOWN: /* unplug */
unplug = 1;
@@ -1313,76 +369,102 @@ static void hid_ctrl(struct urb *urb)
}
if (unplug)
- hid->ctrltail = hid->ctrlhead;
+ usbhid->ctrltail = usbhid->ctrlhead;
else
- hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+ usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
- if (hid->ctrlhead != hid->ctrltail) {
+ if (usbhid->ctrlhead != usbhid->ctrltail) {
if (hid_submit_ctrl(hid)) {
- clear_bit(HID_CTRL_RUNNING, &hid->iofl);
+ clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
wake_up(&hid->wait);
}
- spin_unlock_irqrestore(&hid->ctrllock, flags);
+ spin_unlock_irqrestore(&usbhid->ctrllock, flags);
return;
}
- clear_bit(HID_CTRL_RUNNING, &hid->iofl);
- spin_unlock_irqrestore(&hid->ctrllock, flags);
+ clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+ spin_unlock_irqrestore(&usbhid->ctrllock, flags);
wake_up(&hid->wait);
}
-void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
{
int head;
unsigned long flags;
+ struct usbhid_device *usbhid = hid->driver_data;
if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
return;
- if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
+ if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
- spin_lock_irqsave(&hid->outlock, flags);
+ spin_lock_irqsave(&usbhid->outlock, flags);
- if ((head = (hid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == hid->outtail) {
- spin_unlock_irqrestore(&hid->outlock, flags);
+ if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
+ spin_unlock_irqrestore(&usbhid->outlock, flags);
warn("output queue full");
return;
}
- hid->out[hid->outhead] = report;
- hid->outhead = head;
+ usbhid->out[usbhid->outhead] = report;
+ usbhid->outhead = head;
- if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl))
+ if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
if (hid_submit_out(hid))
- clear_bit(HID_OUT_RUNNING, &hid->iofl);
+ clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
- spin_unlock_irqrestore(&hid->outlock, flags);
+ spin_unlock_irqrestore(&usbhid->outlock, flags);
return;
}
- spin_lock_irqsave(&hid->ctrllock, flags);
+ spin_lock_irqsave(&usbhid->ctrllock, flags);
- if ((head = (hid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == hid->ctrltail) {
- spin_unlock_irqrestore(&hid->ctrllock, flags);
+ if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
+ spin_unlock_irqrestore(&usbhid->ctrllock, flags);
warn("control queue full");
return;
}
- hid->ctrl[hid->ctrlhead].report = report;
- hid->ctrl[hid->ctrlhead].dir = dir;
- hid->ctrlhead = head;
+ usbhid->ctrl[usbhid->ctrlhead].report = report;
+ usbhid->ctrl[usbhid->ctrlhead].dir = dir;
+ usbhid->ctrlhead = head;
- if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl))
+ if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
if (hid_submit_ctrl(hid))
- clear_bit(HID_CTRL_RUNNING, &hid->iofl);
+ clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+
+ spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+}
+
+static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+ struct hid_device *hid = dev->private;
+ struct hid_field *field;
+ int offset;
- spin_unlock_irqrestore(&hid->ctrllock, flags);
+ if (type == EV_FF)
+ return input_ff_event(dev, type, code, value);
+
+ if (type != EV_LED)
+ return -1;
+
+ if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
+ warn("event field not found");
+ return -1;
+ }
+
+ hid_set_field(field, offset, value);
+ usbhid_submit_report(hid, field->report, USB_DIR_OUT);
+
+ return 0;
}
-int hid_wait_io(struct hid_device *hid)
+int usbhid_wait_io(struct hid_device *hid)
{
- if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &hid->iofl) &&
- !test_bit(HID_OUT_RUNNING, &hid->iofl)),
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
+ !test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
10*HZ)) {
dbg("timeout waiting for ctrl or out queue to clear");
return -1;
@@ -1403,7 +485,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
{
int result, retries = 4;
- memset(buf,0,size); // Make sure we parse really received data
+ memset(buf, 0, size);
do {
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
@@ -1414,7 +496,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
return result;
}
-int hid_open(struct hid_device *hid)
+int usbhid_open(struct hid_device *hid)
{
++hid->open;
if (hid_start_in(hid))
@@ -1422,10 +504,12 @@ int hid_open(struct hid_device *hid)
return 0;
}
-void hid_close(struct hid_device *hid)
+void usbhid_close(struct hid_device *hid)
{
+ struct usbhid_device *usbhid = hid->driver_data;
+
if (!--hid->open)
- usb_kill_urb(hid->urbin);
+ usb_kill_urb(usbhid->urbin);
}
#define USB_VENDOR_ID_PANJIT 0x134c
@@ -1437,26 +521,27 @@ void hid_close(struct hid_device *hid)
* Initialize all reports
*/
-void hid_init_reports(struct hid_device *hid)
+void usbhid_init_reports(struct hid_device *hid)
{
struct hid_report *report;
+ struct usbhid_device *usbhid = hid->driver_data;
int err, ret;
list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
- hid_submit_report(hid, report, USB_DIR_IN);
+ usbhid_submit_report(hid, report, USB_DIR_IN);
list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
- hid_submit_report(hid, report, USB_DIR_IN);
+ usbhid_submit_report(hid, report, USB_DIR_IN);
err = 0;
- ret = hid_wait_io(hid);
+ ret = usbhid_wait_io(hid);
while (ret) {
err |= ret;
- if (test_bit(HID_CTRL_RUNNING, &hid->iofl))
- usb_kill_urb(hid->urbctrl);
- if (test_bit(HID_OUT_RUNNING, &hid->iofl))
- usb_kill_urb(hid->urbout);
- ret = hid_wait_io(hid);
+ if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+ usb_kill_urb(usbhid->urbctrl);
+ if (test_bit(HID_OUT_RUNNING, &usbhid->iofl))
+ usb_kill_urb(usbhid->urbout);
+ ret = usbhid_wait_io(hid);
}
if (err)
@@ -1464,6 +549,7 @@ void hid_init_reports(struct hid_device *hid)
}
#define USB_VENDOR_ID_GTCO 0x078c
+#define USB_VENDOR_ID_GTCO_IPANEL_2 0x5543
#define USB_DEVICE_ID_GTCO_90 0x0090
#define USB_DEVICE_ID_GTCO_100 0x0100
#define USB_DEVICE_ID_GTCO_101 0x0101
@@ -1509,6 +595,8 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_GTCO_1004 0x1004
#define USB_DEVICE_ID_GTCO_1005 0x1005
#define USB_DEVICE_ID_GTCO_1006 0x1006
+#define USB_DEVICE_ID_GTCO_8 0x0008
+#define USB_DEVICE_ID_GTCO_d 0x000d
#define USB_VENDOR_ID_WACOM 0x056a
@@ -1654,6 +742,7 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
+#define USB_DEVICE_ID_APPLE_IR 0x8240
#define USB_VENDOR_ID_CHERRY 0x046a
#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
@@ -1673,6 +762,15 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101
+#define USB_VENDOR_ID_IMATION 0x0718
+#define USB_DEVICE_ID_DISC_STAKKA 0xd000
+
+#define USB_VENDOR_ID_PANTHERLORD 0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001
+
+#define USB_VENDOR_ID_SONY 0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
+
/*
* Alphabetically sorted blacklist by quirk type.
*/
@@ -1757,6 +855,9 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_8, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_d, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE },
@@ -1824,19 +925,21 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
@@ -1847,6 +950,10 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
+ { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
+
+ { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
{ 0, 0 }
};
@@ -1869,13 +976,15 @@ static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *
static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
{
- if (!(hid->inbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->inbuf_dma)))
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma)))
return -1;
- if (!(hid->outbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->outbuf_dma)))
+ if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma)))
return -1;
- if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), GFP_ATOMIC, &hid->cr_dma)))
+ if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma)))
return -1;
- if (!(hid->ctrlbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->ctrlbuf_dma)))
+ if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma)))
return -1;
return 0;
@@ -1883,14 +992,16 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{
- if (hid->inbuf)
- usb_buffer_free(dev, hid->bufsize, hid->inbuf, hid->inbuf_dma);
- if (hid->outbuf)
- usb_buffer_free(dev, hid->bufsize, hid->outbuf, hid->outbuf_dma);
- if (hid->cr)
- usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma);
- if (hid->ctrlbuf)
- usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->ctrlbuf_dma);
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ if (usbhid->inbuf)
+ usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
+ if (usbhid->outbuf)
+ usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
+ if (usbhid->cr)
+ usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
+ if (usbhid->ctrlbuf)
+ usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
}
/*
@@ -1907,6 +1018,32 @@ static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
}
}
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational". Without this, the ps3 controller will not report any
+ * events.
+ */
+static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+{
+ int result;
+ char *buf = kmalloc(18, GFP_KERNEL);
+
+ if (!buf)
+ return;
+
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ HID_REQ_GET_REPORT,
+ USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE,
+ (3 << 8) | 0xf2, ifnum, buf, 17,
+ USB_CTRL_GET_TIMEOUT);
+
+ if (result < 0)
+ err("%s failed: %d\n", __func__, result);
+
+ kfree(buf);
+}
+
static struct hid_device *usb_hid_configure(struct usb_interface *intf)
{
struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1916,6 +1053,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
unsigned quirks = 0, rsize = 0;
char *rdesc;
int n, len, insize = 0;
+ struct usbhid_device *usbhid;
/* Ignore all Wacom devices */
if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM)
@@ -1937,6 +1075,11 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if (quirks & HID_QUIRK_IGNORE)
return NULL;
+ if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
+ (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
+ return NULL;
+
+
if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
(!interface->desc.bNumEndpoints ||
usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
@@ -1985,13 +1128,19 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
kfree(rdesc);
hid->quirks = quirks;
- hid->bufsize = HID_MIN_BUFFER_SIZE;
- hid_find_max_report(hid, HID_INPUT_REPORT, &hid->bufsize);
- hid_find_max_report(hid, HID_OUTPUT_REPORT, &hid->bufsize);
- hid_find_max_report(hid, HID_FEATURE_REPORT, &hid->bufsize);
+ if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
+ goto fail;
+
+ hid->driver_data = usbhid;
+ usbhid->hid = hid;
+
+ usbhid->bufsize = HID_MIN_BUFFER_SIZE;
+ hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
+ hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
+ hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize);
- if (hid->bufsize > HID_MAX_BUFFER_SIZE)
- hid->bufsize = HID_MAX_BUFFER_SIZE;
+ if (usbhid->bufsize > HID_MAX_BUFFER_SIZE)
+ usbhid->bufsize = HID_MAX_BUFFER_SIZE;
hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
@@ -2020,47 +1169,47 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
interval = hid_mousepoll_interval;
if (usb_endpoint_dir_in(endpoint)) {
- if (hid->urbin)
+ if (usbhid->urbin)
continue;
- if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
+ if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
goto fail;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
- usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, insize,
+ usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,
hid_irq_in, hid, interval);
- hid->urbin->transfer_dma = hid->inbuf_dma;
- hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
+ usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
} else {
- if (hid->urbout)
+ if (usbhid->urbout)
continue;
- if (!(hid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
+ if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
goto fail;
pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);
- usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0,
+ usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0,
hid_irq_out, hid, interval);
- hid->urbout->transfer_dma = hid->outbuf_dma;
- hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usbhid->urbout->transfer_dma = usbhid->outbuf_dma;
+ usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
}
}
- if (!hid->urbin) {
+ if (!usbhid->urbin) {
err("couldn't find an input interrupt endpoint");
goto fail;
}
init_waitqueue_head(&hid->wait);
- INIT_WORK(&hid->reset_work, hid_reset);
- setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid);
+ INIT_WORK(&usbhid->reset_work, hid_reset);
+ setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
- spin_lock_init(&hid->inlock);
- spin_lock_init(&hid->outlock);
- spin_lock_init(&hid->ctrllock);
+ spin_lock_init(&usbhid->inlock);
+ spin_lock_init(&usbhid->outlock);
+ spin_lock_init(&usbhid->ctrllock);
hid->version = le16_to_cpu(hdesc->bcdHID);
hid->country = hdesc->bCountryCode;
- hid->dev = dev;
- hid->intf = intf;
- hid->ifnum = interface->desc.bInterfaceNumber;
+ hid->dev = &intf->dev;
+ usbhid->intf = intf;
+ usbhid->ifnum = interface->desc.bInterfaceNumber;
hid->name[0] = 0;
@@ -2078,6 +1227,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
+ hid->bus = BUS_USB;
+ hid->vendor = dev->descriptor.idVendor;
+ hid->product = dev->descriptor.idProduct;
+
usb_make_path(dev, hid->phys, sizeof(hid->phys));
strlcat(hid->phys, "/input", sizeof(hid->phys));
len = strlen(hid->phys);
@@ -2088,22 +1241,28 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
hid->uniq[0] = 0;
- hid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
- if (!hid->urbctrl)
+ usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
+ if (!usbhid->urbctrl)
goto fail;
- usb_fill_control_urb(hid->urbctrl, dev, 0, (void *) hid->cr,
- hid->ctrlbuf, 1, hid_ctrl, hid);
- hid->urbctrl->setup_dma = hid->cr_dma;
- hid->urbctrl->transfer_dma = hid->ctrlbuf_dma;
- hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
-
+ usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
+ usbhid->ctrlbuf, 1, hid_ctrl, hid);
+ usbhid->urbctrl->setup_dma = usbhid->cr_dma;
+ usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
+ usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
+ hid->hidinput_input_event = usb_hidinput_input_event;
+ hid->hid_open = usbhid_open;
+ hid->hid_close = usbhid_close;
+#ifdef CONFIG_USB_HIDDEV
+ hid->hiddev_hid_event = hiddev_hid_event;
+ hid->hiddev_report_event = hiddev_report_event;
+#endif
return hid;
fail:
- usb_free_urb(hid->urbin);
- usb_free_urb(hid->urbout);
- usb_free_urb(hid->urbctrl);
+ usb_free_urb(usbhid->urbin);
+ usb_free_urb(usbhid->urbout);
+ usb_free_urb(usbhid->urbctrl);
hid_free_buffers(dev, hid);
hid_free_device(hid);
@@ -2113,18 +1272,21 @@ fail:
static void hid_disconnect(struct usb_interface *intf)
{
struct hid_device *hid = usb_get_intfdata (intf);
+ struct usbhid_device *usbhid;
if (!hid)
return;
- spin_lock_irq(&hid->inlock); /* Sync with error handler */
+ usbhid = hid->driver_data;
+
+ spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
usb_set_intfdata(intf, NULL);
- spin_unlock_irq(&hid->inlock);
- usb_kill_urb(hid->urbin);
- usb_kill_urb(hid->urbout);
- usb_kill_urb(hid->urbctrl);
+ spin_unlock_irq(&usbhid->inlock);
+ usb_kill_urb(usbhid->urbin);
+ usb_kill_urb(usbhid->urbout);
+ usb_kill_urb(usbhid->urbctrl);
- del_timer_sync(&hid->io_retry);
+ del_timer_sync(&usbhid->io_retry);
flush_scheduled_work();
if (hid->claimed & HID_CLAIMED_INPUT)
@@ -2132,11 +1294,11 @@ static void hid_disconnect(struct usb_interface *intf)
if (hid->claimed & HID_CLAIMED_HIDDEV)
hiddev_disconnect(hid);
- usb_free_urb(hid->urbin);
- usb_free_urb(hid->urbctrl);
- usb_free_urb(hid->urbout);
+ usb_free_urb(usbhid->urbin);
+ usb_free_urb(usbhid->urbctrl);
+ usb_free_urb(usbhid->urbout);
- hid_free_buffers(hid->dev, hid);
+ hid_free_buffers(hid_to_usb_dev(hid), hid);
hid_free_device(hid);
}
@@ -2153,7 +1315,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (!(hid = usb_hid_configure(intf)))
return -ENODEV;
- hid_init_reports(hid);
+ usbhid_init_reports(hid);
hid_dump_device(hid);
if (!hidinput_connect(hid))
@@ -2169,6 +1331,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
return -ENODEV;
}
+ if ((hid->claimed & HID_CLAIMED_INPUT))
+ hid_ff_init(hid);
+
+ if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
+ hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
printk(KERN_INFO);
if (hid->claimed & HID_CLAIMED_INPUT)
@@ -2199,12 +1368,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
static int hid_suspend(struct usb_interface *intf, pm_message_t message)
{
struct hid_device *hid = usb_get_intfdata (intf);
+ struct usbhid_device *usbhid = hid->driver_data;
- spin_lock_irq(&hid->inlock); /* Sync with error handler */
- set_bit(HID_SUSPENDED, &hid->iofl);
- spin_unlock_irq(&hid->inlock);
- del_timer(&hid->io_retry);
- usb_kill_urb(hid->urbin);
+ spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
+ set_bit(HID_SUSPENDED, &usbhid->iofl);
+ spin_unlock_irq(&usbhid->inlock);
+ del_timer(&usbhid->io_retry);
+ usb_kill_urb(usbhid->urbin);
dev_dbg(&intf->dev, "suspend\n");
return 0;
}
@@ -2212,10 +1382,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
static int hid_resume(struct usb_interface *intf)
{
struct hid_device *hid = usb_get_intfdata (intf);
+ struct usbhid_device *usbhid = hid->driver_data;
int status;
- clear_bit(HID_SUSPENDED, &hid->iofl);
- hid->retry_delay = 0;
+ clear_bit(HID_SUSPENDED, &usbhid->iofl);
+ usbhid->retry_delay = 0;
status = hid_start_in(hid);
dev_dbg(&intf->dev, "resume status %d\n", status);
return status;
diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
index 0d644fa37c6..bc7f8e6f8c9 100644
--- a/drivers/usb/input/hid-ff.c
+++ b/drivers/usb/input/hid-ff.c
@@ -32,7 +32,8 @@
#undef DEBUG
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
+#include "usbhid.h"
/*
* This table contains pointers to initializers. To add support for new
@@ -58,6 +59,9 @@ static struct hid_ff_initializer inits[] = {
{ 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
#endif
+#ifdef CONFIG_PANTHERLORD_FF
+ { 0x810, 0x0001, hid_plff_init },
+#endif
#ifdef CONFIG_THRUSTMASTER_FF
{ 0x44f, 0xb304, hid_tmff_init },
#endif
@@ -71,8 +75,8 @@ static struct hid_ff_initializer inits[] = {
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);
+ int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor);
+ int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct);
for (init = inits; init->idVendor; init++)
if (init->idVendor == vendor && init->idProduct == product)
@@ -80,3 +84,5 @@ int hid_ff_init(struct hid_device* hid)
return init->init(hid);
}
+EXPORT_SYMBOL_GPL(hid_ff_init);
+
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
index 52be7a8f55a..4df0968f852 100644
--- a/drivers/usb/input/hid-lgff.c
+++ b/drivers/usb/input/hid-lgff.c
@@ -29,9 +29,10 @@
#include <linux/input.h>
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
+#include "usbhid.h"
-struct device_type {
+struct dev_type {
u16 idVendor;
u16 idProduct;
const signed short *ff;
@@ -47,7 +48,7 @@ static const signed short ff_joystick[] = {
-1
};
-static const struct device_type devices[] = {
+static const struct dev_type devices[] = {
{ 0x046d, 0xc211, ff_rumble },
{ 0x046d, 0xc219, ff_rumble },
{ 0x046d, 0xc283, ff_joystick },
@@ -76,7 +77,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
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);
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
break;
case FF_RUMBLE:
@@ -91,7 +92,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
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);
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
break;
}
return 0;
diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c
index 5420c13eb8e..cbd2d53feff 100644
--- a/drivers/usb/input/hid-pidff.c
+++ b/drivers/usb/input/hid-pidff.c
@@ -28,7 +28,9 @@
#include <linux/input.h>
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
+
+#include "usbhid.h"
#define PID_EFFECTS_MAX 64
@@ -260,7 +262,7 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
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],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
USB_DIR_OUT);
}
@@ -287,7 +289,7 @@ static void pidff_set_constant_force_report(struct pidff_device *pidff,
pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],
effect->u.constant.level);
- hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
USB_DIR_OUT);
}
@@ -322,7 +324,7 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
pidff->effect_direction);
pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
- hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
USB_DIR_OUT);
}
@@ -354,7 +356,7 @@ static void pidff_set_periodic_report(struct pidff_device *pidff,
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],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],
USB_DIR_OUT);
}
@@ -396,8 +398,8 @@ static void pidff_set_condition_report(struct pidff_device *pidff,
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],
+ usbhid_wait_io(pidff->hid);
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
USB_DIR_OUT);
}
}
@@ -438,7 +440,7 @@ static void pidff_set_ramp_force_report(struct pidff_device *pidff,
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],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],
USB_DIR_OUT);
}
@@ -463,19 +465,19 @@ 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],
+ usbhid_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);
+ usbhid_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],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
USB_DIR_IN);
- hid_wait_io(pidff->hid);
+ usbhid_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",
@@ -511,8 +513,8 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
}
- hid_wait_io(pidff->hid);
- hid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
+ usbhid_wait_io(pidff->hid);
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
USB_DIR_OUT);
}
@@ -534,7 +536,7 @@ static int pidff_playback(struct input_dev *dev, int effect_id, int value)
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],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],
USB_DIR_OUT);
}
@@ -714,7 +716,7 @@ 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],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
USB_DIR_OUT);
}
@@ -739,7 +741,7 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
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],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
USB_DIR_OUT);
}
@@ -1163,19 +1165,19 @@ static void pidff_reset(struct pidff_device *pidff)
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);
+ usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+ usbhid_wait_io(hid);
+ usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+ usbhid_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);
+ usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+ usbhid_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);
+ usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
+ usbhid_wait_io(hid);
if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0];
@@ -1187,9 +1189,9 @@ static void pidff_reset(struct pidff_device *pidff)
break;
}
debug("pid_pool requested again");
- hid_submit_report(hid, pidff->reports[PID_POOL],
+ usbhid_submit_report(hid, pidff->reports[PID_POOL],
USB_DIR_IN);
- hid_wait_io(hid);
+ usbhid_wait_io(hid);
}
}
}
@@ -1275,7 +1277,7 @@ int hid_pidff_init(struct hid_device *hid)
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],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
USB_DIR_OUT);
}
diff --git a/drivers/usb/input/hid-plff.c b/drivers/usb/input/hid-plff.c
new file mode 100644
index 00000000000..76d2e6e14db
--- /dev/null
+++ b/drivers/usb/input/hid-plff.c
@@ -0,0 +1,129 @@
+/*
+ * Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
+ *
+ * Copyright (c) 2007 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-plff: " format "\n" , ## arg)
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "usbhid.h"
+
+struct plff_device {
+ struct hid_report *report;
+};
+
+static int hid_plff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = dev->private;
+ struct plff_device *plff = data;
+ int left, right;
+
+ 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;
+
+ plff->report->field[0]->value[2] = left;
+ plff->report->field[0]->value[3] = right;
+ debug("running with 0x%02x 0x%02x", left, right);
+ usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+
+ return 0;
+}
+
+int hid_plff_init(struct hid_device *hid)
+{
+ struct plff_device *plff;
+ struct hid_report *report;
+ struct hid_input *hidinput;
+ struct list_head *report_list =
+ &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct list_head *report_ptr = report_list;
+ struct input_dev *dev;
+ int error;
+
+ /* The device contains 2 output reports (one for each
+ HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
+ contains 4 ff00.0002 usages and 4 16bit absolute values.
+
+ The 2 input reports also contain a field which contains
+ 8 ff00.0001 usages and 8 boolean values. Their meaning is
+ currently unknown. */
+
+ if (list_empty(report_list)) {
+ printk(KERN_ERR "hid-plff: no output reports found\n");
+ return -ENODEV;
+ }
+
+ list_for_each_entry(hidinput, &hid->inputs, list) {
+
+ report_ptr = report_ptr->next;
+
+ if (report_ptr == report_list) {
+ printk(KERN_ERR "hid-plff: required output report is missing\n");
+ return -ENODEV;
+ }
+
+ report = list_entry(report_ptr, struct hid_report, list);
+ if (report->maxfield < 1) {
+ printk(KERN_ERR "hid-plff: no fields in the report\n");
+ return -ENODEV;
+ }
+
+ if (report->field[0]->report_count < 4) {
+ printk(KERN_ERR "hid-plff: not enough values in the field\n");
+ return -ENODEV;
+ }
+
+ plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL);
+ if (!plff)
+ return -ENOMEM;
+
+ dev = hidinput->input;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ error = input_ff_create_memless(dev, plff, hid_plff_play);
+ if (error) {
+ kfree(plff);
+ return error;
+ }
+
+ plff->report = report;
+ plff->report->field[0]->value[0] = 0x00;
+ plff->report->field[0]->value[1] = 0x00;
+ plff->report->field[0]->value[2] = 0x00;
+ plff->report->field[0]->value[3] = 0x00;
+ usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+ }
+
+ printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
+ "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+ return 0;
+}
diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c
index 2d5be4c318a..ab67331620d 100644
--- a/drivers/usb/input/hid-tmff.c
+++ b/drivers/usb/input/hid-tmff.c
@@ -32,7 +32,8 @@
#undef DEBUG
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
+#include "usbhid.h"
/* Usages for thrustmaster devices I know about */
#define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb)
@@ -70,7 +71,7 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef
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);
+ usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
return 0;
}
diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c
index d2ce3214572..7bd8238ca21 100644
--- a/drivers/usb/input/hid-zpff.c
+++ b/drivers/usb/input/hid-zpff.c
@@ -27,7 +27,8 @@
#include <linux/input.h>
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
+#include "usbhid.h"
struct zpff_device {
struct hid_report *report;
@@ -56,7 +57,7 @@ static int hid_zpff_play(struct input_dev *dev, void *data,
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);
+ usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
return 0;
}
@@ -101,7 +102,7 @@ int hid_zpff_init(struct hid_device *hid)
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);
+ usbhid_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");
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
index 7dc14d0cacc..a8b3d66cd49 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -32,8 +32,9 @@
#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
#include <linux/hiddev.h>
+#include "usbhid.h"
#ifdef CONFIG_USB_DYNAMIC_MINORS
#define HIDDEV_MINOR_BASE 0
@@ -196,7 +197,7 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
hiddev_send_event(hid, &uref);
}
-
+EXPORT_SYMBOL_GPL(hiddev_hid_event);
void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
{
@@ -213,6 +214,7 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
hiddev_send_event(hid, &uref);
}
+
/*
* fasync file op
*/
@@ -239,7 +241,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
if (!--list->hiddev->open) {
if (list->hiddev->exist)
- hid_close(list->hiddev->hid);
+ usbhid_close(list->hiddev->hid);
else
kfree(list->hiddev);
}
@@ -270,7 +272,7 @@ static int hiddev_open(struct inode *inode, struct file *file)
if (!list->hiddev->open++)
if (list->hiddev->exist)
- hid_open(hiddev_table[i]->hid);
+ usbhid_open(hiddev_table[i]->hid);
return 0;
}
@@ -382,7 +384,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct hiddev_list *list = file->private_data;
struct hiddev *hiddev = list->hiddev;
struct hid_device *hid = hiddev->hid;
- struct usb_device *dev = hid->dev;
+ struct usb_device *dev = hid_to_usb_dev(hid);
struct hiddev_collection_info cinfo;
struct hiddev_report_info rinfo;
struct hiddev_field_info finfo;
@@ -391,6 +393,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct hiddev_devinfo dinfo;
struct hid_report *report;
struct hid_field *field;
+ struct usbhid_device *usbhid = hid->driver_data;
void __user *user_arg = (void __user *)arg;
int i;
@@ -420,7 +423,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
dinfo.bustype = BUS_USB;
dinfo.busnum = dev->bus->busnum;
dinfo.devnum = dev->devnum;
- dinfo.ifnum = hid->ifnum;
+ dinfo.ifnum = usbhid->ifnum;
dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
@@ -479,7 +482,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
case HIDIOCINITREPORT:
- hid_init_reports(hid);
+ usbhid_init_reports(hid);
return 0;
@@ -493,8 +496,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL;
- hid_submit_report(hid, report, USB_DIR_IN);
- hid_wait_io(hid);
+ usbhid_submit_report(hid, report, USB_DIR_IN);
+ usbhid_wait_io(hid);
return 0;
@@ -508,8 +511,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL;
- hid_submit_report(hid, report, USB_DIR_OUT);
- hid_wait_io(hid);
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+ usbhid_wait_io(hid);
return 0;
@@ -745,6 +748,7 @@ static struct usb_class_driver hiddev_class = {
int hiddev_connect(struct hid_device *hid)
{
struct hiddev *hiddev;
+ struct usbhid_device *usbhid = hid->driver_data;
int i;
int retval;
@@ -760,7 +764,7 @@ int hiddev_connect(struct hid_device *hid)
if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
return -1;
- retval = usb_register_dev(hid->intf, &hiddev_class);
+ retval = usb_register_dev(usbhid->intf, &hiddev_class);
if (retval) {
err("Not able to get a minor for this device.");
kfree(hiddev);
@@ -772,10 +776,10 @@ int hiddev_connect(struct hid_device *hid)
hiddev->hid = hid;
hiddev->exist = 1;
- hid->minor = hid->intf->minor;
+ hid->minor = usbhid->intf->minor;
hid->hiddev = hiddev;
- hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
+ hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
return 0;
}
@@ -788,14 +792,15 @@ static struct usb_class_driver hiddev_class;
void hiddev_disconnect(struct hid_device *hid)
{
struct hiddev *hiddev = hid->hiddev;
+ struct usbhid_device *usbhid = hid->driver_data;
hiddev->exist = 0;
hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
- usb_deregister_dev(hiddev->hid->intf, &hiddev_class);
+ usb_deregister_dev(usbhid->intf, &hiddev_class);
if (hiddev->open) {
- hid_close(hiddev->hid);
+ usbhid_close(hiddev->hid);
wake_up_interruptible(&hiddev->wait);
} else {
kfree(hiddev);
diff --git a/drivers/usb/input/usbhid.h b/drivers/usb/input/usbhid.h
new file mode 100644
index 00000000000..0023f96d429
--- /dev/null
+++ b/drivers/usb/input/usbhid.h
@@ -0,0 +1,87 @@
+#ifndef __USBHID_H
+#define __USBHID_H
+
+/*
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ * Copyright (c) 2006 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * 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/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+
+/* API provided by hid-core.c for USB HID drivers */
+int usbhid_wait_io(struct hid_device* hid);
+void usbhid_close(struct hid_device *hid);
+int usbhid_open(struct hid_device *hid);
+void usbhid_init_reports(struct hid_device *hid);
+void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir);
+
+/*
+ * USB-specific HID struct, to be pointed to
+ * from struct hid_device->driver_data
+ */
+
+struct usbhid_device {
+ struct hid_device *hid; /* pointer to corresponding HID dev */
+
+ struct usb_interface *intf; /* USB interface */
+ int ifnum; /* USB interface number */
+
+ unsigned int bufsize; /* URB buffer size */
+
+ struct urb *urbin; /* Input URB */
+ char *inbuf; /* Input buffer */
+ dma_addr_t inbuf_dma; /* Input buffer dma */
+ spinlock_t inlock; /* Input fifo spinlock */
+
+ struct urb *urbctrl; /* Control URB */
+ struct usb_ctrlrequest *cr; /* Control request struct */
+ dma_addr_t cr_dma; /* Control request struct dma */
+ struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */
+ unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */
+ char *ctrlbuf; /* Control buffer */
+ dma_addr_t ctrlbuf_dma; /* Control buffer dma */
+ spinlock_t ctrllock; /* Control fifo spinlock */
+
+ struct urb *urbout; /* Output URB */
+ struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
+ unsigned char outhead, outtail; /* Output pipe fifo head & tail */
+ char *outbuf; /* Output buffer */
+ dma_addr_t outbuf_dma; /* Output buffer dma */
+ spinlock_t outlock; /* Output fifo spinlock */
+
+ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
+ struct timer_list io_retry; /* Retry timer */
+ unsigned long stop_retry; /* Time to give up, in jiffies */
+ unsigned int retry_delay; /* Delay length in ms */
+ struct work_struct reset_work; /* Task context for resets */
+
+};
+
+#define hid_to_usb_dev(hid_dev) \
+ container_of(hid_dev->dev->parent, struct usb_device, dev)
+
+#endif
+
diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c
index 7f3c57da9bc..86e37a20f8e 100644
--- a/drivers/usb/input/usbtouchscreen.c
+++ b/drivers/usb/input/usbtouchscreen.c
@@ -66,7 +66,7 @@ struct usbtouch_device_info {
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 (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt);
int (*init) (struct usbtouch_usb *usbtouch);
};
@@ -85,6 +85,9 @@ struct usbtouch_usb {
struct usbtouch_device_info *type;
char name[128];
char phys[64];
+
+ int x, y;
+ int touch, press;
};
@@ -161,14 +164,14 @@ static struct usb_device_id usbtouch_devices[] = {
#define EGALAX_PKT_TYPE_REPT 0x80
#define EGALAX_PKT_TYPE_DIAG 0x0A
-static int egalax_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
+static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT)
return 0;
- *x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F);
- *y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F);
- *touch = pkt[0] & 0x01;
+ dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F);
+ dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F);
+ dev->touch = pkt[0] & 0x01;
return 1;
}
@@ -195,11 +198,11 @@ static int egalax_get_pkt_len(unsigned char *buf, int len)
* PanJit Part
*/
#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT
-static int panjit_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
+static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
- *x = ((pkt[2] & 0x0F) << 8) | pkt[1];
- *y = ((pkt[4] & 0x0F) << 8) | pkt[3];
- *touch = pkt[0] & 0x01;
+ dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
+ dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
+ dev->touch = pkt[0] & 0x01;
return 1;
}
@@ -215,11 +218,11 @@ static int panjit_read_data(unsigned char *pkt, int *x, int *y, int *touch, int
#define MTOUCHUSB_RESET 7
#define MTOUCHUSB_REQ_CTRLLR_ID 10
-static int mtouch_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
+static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
- *x = (pkt[8] << 8) | pkt[7];
- *y = (pkt[10] << 8) | pkt[9];
- *touch = (pkt[2] & 0x40) ? 1 : 0;
+ dev->x = (pkt[8] << 8) | pkt[7];
+ dev->y = (pkt[10] << 8) | pkt[9];
+ dev->touch = (pkt[2] & 0x40) ? 1 : 0;
return 1;
}
@@ -260,14 +263,32 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
* ITM Part
*/
#ifdef CONFIG_USB_TOUCHSCREEN_ITM
-static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
+static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
- *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
- *y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
- *press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
- *touch = ~pkt[7] & 0x20;
+ int touch;
+ /*
+ * ITM devices report invalid x/y data if not touched.
+ * if the screen was touched before but is not touched any more
+ * report touch as 0 with the last valid x/y data once. then stop
+ * reporting data until touched again.
+ */
+ dev->press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
+
+ touch = ~pkt[7] & 0x20;
+ if (!touch) {
+ if (dev->touch) {
+ dev->touch = 0;
+ return 1;
+ }
- return *touch;
+ return 0;
+ }
+
+ dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
+ dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
+ dev->touch = touch;
+
+ return 1;
}
#endif
@@ -276,7 +297,7 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr
* eTurboTouch part
*/
#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
-static int eturbo_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
+static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
unsigned int shift;
@@ -285,9 +306,9 @@ static int eturbo_read_data(unsigned char *pkt, int *x, int *y, int *touch, int
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;
+ dev->x = ((pkt[3] << 7) | pkt[4]) >> shift;
+ dev->y = ((pkt[1] << 7) | pkt[2]) >> shift;
+ dev->touch = (pkt[0] & 0x10) ? 1 : 0;
return 1;
}
@@ -307,14 +328,14 @@ static int eturbo_get_pkt_len(unsigned char *buf, int len)
* Gunze part
*/
#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
-static int gunze_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
+static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
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;
+ dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F);
+ dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F);
+ dev->touch = pkt[0] & 0x20;
return 1;
}
@@ -383,11 +404,11 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
}
-static int dmc_tsc10_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
+static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
- *x = ((pkt[2] & 0x03) << 8) | pkt[1];
- *y = ((pkt[4] & 0x03) << 8) | pkt[3];
- *touch = pkt[0] & 0x01;
+ dev->x = ((pkt[2] & 0x03) << 8) | pkt[1];
+ dev->y = ((pkt[4] & 0x03) << 8) | pkt[3];
+ dev->touch = pkt[0] & 0x01;
return 1;
}
@@ -492,23 +513,22 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
unsigned char *pkt, int len)
{
- int x, y, touch, press;
struct usbtouch_device_info *type = usbtouch->type;
- if (!type->read_data(pkt, &x, &y, &touch, &press))
+ if (!type->read_data(usbtouch, pkt))
return;
- input_report_key(usbtouch->input, BTN_TOUCH, touch);
+ input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
if (swap_xy) {
- input_report_abs(usbtouch->input, ABS_X, y);
- input_report_abs(usbtouch->input, ABS_Y, x);
+ input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
+ input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
} else {
- input_report_abs(usbtouch->input, ABS_X, x);
- input_report_abs(usbtouch->input, ABS_Y, y);
+ input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
+ input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
}
if (type->max_press)
- input_report_abs(usbtouch->input, ABS_PRESSURE, press);
+ input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
input_sync(usbtouch->input);
}
diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c
index e7cc20ab815..12b42746ded 100644
--- a/drivers/usb/input/wacom_sys.c
+++ b/drivers/usb/input/wacom_sys.c
@@ -159,13 +159,13 @@ 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);
+ input_set_abs_params(input_dev, ABS_RX, 0, 4096, 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);
+ input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
}
void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c
index 92726fe8937..4142e36730f 100644
--- a/drivers/usb/input/wacom_wac.c
+++ b/drivers/usb/input/wacom_wac.c
@@ -209,13 +209,15 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
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);
+
+ if (data[1] & 0x10) /* only report prox-in when in area */
+ wacom_report_key(wcombo, wacom->tool[0], 1);
+ if (!(data[1] & 0x90)) /* report prox-out when physically out */
+ wacom_report_key(wcombo, wacom->tool[0], 0);
wacom_input_sync(wcombo);
/* send pad data */
@@ -405,7 +407,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
return 0;
- if (wacom->features->type >= INTUOS3) {
+ if (wacom->features->type >= INTUOS3S) {
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));
@@ -423,7 +425,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
if (data[1] & 0x02) {
/* Rotation packet */
- if (wacom->features->type >= INTUOS3) {
+ if (wacom->features->type >= INTUOS3S) {
/* I3 marker pen rotation reported as wheel
* due to valuator limitation
*/
@@ -547,11 +549,11 @@ static struct wacom_features wacom_features[] = {
{ "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 Volito", 8, 5104, 3712, 511, 63, GRAPHIRE },
+ { "Wacom PenStation2", 8, 3250, 2320, 255, 63, GRAPHIRE },
+ { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE },
+ { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE },
+ { "Wacom PenPartner2", 8, 3250, 2320, 255, 63, 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 },
@@ -580,7 +582,7 @@ static struct wacom_features wacom_features[] = {
{ "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 Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S },
{ "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ },
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
{ }
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index 02cbb7fff24..a7932a72d29 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -281,7 +281,7 @@ static int appledisplay_probe(struct usb_interface *iface,
/* Register backlight device */
snprintf(bl_name, sizeof(bl_name), "appledisplay%d",
atomic_inc_return(&count_displays) - 1);
- pdata->bd = backlight_device_register(bl_name, pdata,
+ pdata->bd = backlight_device_register(bl_name, NULL, NULL,
&appledisplay_bl_data);
if (IS_ERR(pdata->bd)) {
err("appledisplay: Backlight registration failed");
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index c703f73e165..b5332e679c4 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -766,7 +766,7 @@ static int auerbuf_setup (pauerbufctl_t bcp, unsigned int numElements, unsigned
bep->bufp = kmalloc (bufsize, GFP_KERNEL);
if (!bep->bufp)
goto bl_fail;
- bep->dr = (struct usb_ctrlrequest *) kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL);
+ bep->dr = kmalloc(sizeof (struct usb_ctrlrequest), GFP_KERNEL);
if (!bep->dr)
goto bl_fail;
bep->urbp = usb_alloc_urb (0, GFP_KERNEL);
@@ -1376,7 +1376,7 @@ static int auerchar_open (struct inode *inode, struct file *file)
}
/* we have access to the device. Now lets allocate memory */
- ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL);
+ ccp = kzalloc(sizeof(auerchar_t), GFP_KERNEL);
if (ccp == NULL) {
err ("out of memory");
ret = -ENOMEM;
@@ -1384,7 +1384,6 @@ static int auerchar_open (struct inode *inode, struct file *file)
}
/* Initialize device descriptor */
- memset( ccp, 0, sizeof(auerchar_t));
init_MUTEX( &ccp->mutex);
init_MUTEX( &ccp->readmutex);
auerbuf_init (&ccp->bufctl);
@@ -1912,14 +1911,13 @@ static int auerswald_probe (struct usb_interface *intf,
return -ENODEV;
/* allocate memory for our device and initialize it */
- cp = kmalloc (sizeof(auerswald_t), GFP_KERNEL);
+ cp = kzalloc (sizeof(auerswald_t), GFP_KERNEL);
if (cp == NULL) {
err ("out of memory");
goto pfail;
}
/* Initialize device descriptor */
- memset (cp, 0, sizeof(auerswald_t));
init_MUTEX (&cp->mutex);
cp->usbdev = usbdev;
auerchain_init (&cp->controlchain);
@@ -1969,7 +1967,7 @@ static int auerswald_probe (struct usb_interface *intf,
info("device is a %s", cp->dev_desc);
/* get the maximum allowed control transfer length */
- pbuf = (__le16 *) kmalloc (2, GFP_KERNEL); /* use an allocated buffer because of urb target */
+ pbuf = kmalloc(2, GFP_KERNEL); /* use an allocated buffer because of urb target */
if (!pbuf) {
err( "out of memory");
goto pfail;
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 18b1925032a..41c0161abdb 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -40,6 +40,7 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/ioctl.h>
+#include <linux/pci_ids.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
@@ -51,6 +52,10 @@ 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)
+static int distrust_firmware = 1;
+module_param(distrust_firmware, bool, 0);
+MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
+ "t setup");
extern struct platform_driver u132_platform_driver;
static struct workqueue_struct *status_queue;
static struct workqueue_struct *command_queue;
@@ -66,7 +71,9 @@ 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
+#include <asm/io.h>
+#include "../core/hcd.h"
+#include "../host/ohci.h"
/* Define these values to match your devices*/
#define USB_FTDI_ELAN_VENDOR_ID 0x0403
#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea
@@ -551,7 +558,7 @@ static void ftdi_elan_status_work(struct work_struct *work)
} else {
dev_err(&ftdi->udev->dev, "initialized failed - trying "
"again in 10 seconds\n");
- work_delay_in_msec = 10 *1000;
+ work_delay_in_msec = 1 *1000;
}
} else if (ftdi->registered == 0) {
work_delay_in_msec = 10;
@@ -2288,82 +2295,288 @@ static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi)
}
}
-static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
+
+#define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \
+ offsetof(struct ohci_regs, member), 0, data);
+#define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \
+ offsetof(struct ohci_regs, member), 0, data);
+#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
+#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
+#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
+ OHCI_INTR_WDH)
+static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk)
+{
+ int devices = 0;
+ int retval;
+ u32 hc_control;
+ int num_ports;
+ u32 control;
+ u32 rh_a = -1;
+ u32 status;
+ u32 fminterval;
+ u32 hc_fminterval;
+ u32 periodicstart;
+ u32 cmdstatus;
+ u32 roothub_a;
+ int mask = OHCI_INTR_INIT;
+ int sleep_time = 0;
+ int reset_timeout = 30; /* ... allow extra time */
+ int temp;
+ retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(ftdi, control, &control);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a);
+ if (retval)
+ return retval;
+ num_ports = rh_a & RH_A_NDP;
+ retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval);
+ if (retval)
+ return retval;
+ hc_fminterval &= 0x3fff;
+ if (hc_fminterval != FI) {
+ }
+ hc_fminterval |= FSMP(hc_fminterval) << 16;
+ retval = ftdi_read_pcimem(ftdi, control, &hc_control);
+ if (retval)
+ return retval;
+ switch (hc_control & OHCI_CTRL_HCFS) {
+ case OHCI_USB_OPER:
+ sleep_time = 0;
+ break;
+ case OHCI_USB_SUSPEND:
+ case OHCI_USB_RESUME:
+ hc_control &= OHCI_CTRL_RWC;
+ hc_control |= OHCI_USB_RESUME;
+ sleep_time = 10;
+ break;
+ default:
+ hc_control &= OHCI_CTRL_RWC;
+ hc_control |= OHCI_USB_RESET;
+ sleep_time = 50;
+ break;
+ }
+ retval = ftdi_write_pcimem(ftdi, control, hc_control);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(ftdi, control, &control);
+ if (retval)
+ return retval;
+ msleep(sleep_time);
+ retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a);
+ if (retval)
+ return retval;
+ if (!(roothub_a & RH_A_NPS)) { /* power down each port */
+ for (temp = 0; temp < num_ports; temp++) {
+ retval = ftdi_write_pcimem(ftdi,
+ roothub.portstatus[temp], RH_PS_LSDA);
+ if (retval)
+ return retval;
+ }
+ }
+ retval = ftdi_read_pcimem(ftdi, control, &control);
+ if (retval)
+ return retval;
+ retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status);
+ if (retval)
+ return retval;
+ retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR);
+ if (retval)
+ return retval;
+ extra:{
+ retval = ftdi_read_pcimem(ftdi, cmdstatus, &status);
+ if (retval)
+ return retval;
+ if (0 != (status & OHCI_HCR)) {
+ if (--reset_timeout == 0) {
+ dev_err(&ftdi->udev->dev, "USB HC reset timed o"
+ "ut!\n");
+ return -ENODEV;
+ } else {
+ msleep(5);
+ goto extra;
+ }
+ }
+ }
+ if (quirk & OHCI_QUIRK_INITRESET) {
+ retval = ftdi_write_pcimem(ftdi, control, hc_control);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(ftdi, control, &control);
+ if (retval)
+ return retval;
+ }
+ retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000);
+ if (retval)
+ return retval;
+ retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000);
+ if (retval)
+ return retval;
+ retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval);
+ if (retval)
+ return retval;
+ retval = ftdi_write_pcimem(ftdi, fminterval,
+ ((fminterval & FIT) ^ FIT) | hc_fminterval);
+ if (retval)
+ return retval;
+ retval = ftdi_write_pcimem(ftdi, periodicstart,
+ ((9 *hc_fminterval) / 10) & 0x3fff);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart);
+ if (retval)
+ return retval;
+ if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
+ if (!(quirk & OHCI_QUIRK_INITRESET)) {
+ quirk |= OHCI_QUIRK_INITRESET;
+ goto retry;
+ } else
+ dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n",
+ fminterval, periodicstart);
+ } /* start controller operations */
+ hc_control &= OHCI_CTRL_RWC;
+ hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
+ retval = ftdi_write_pcimem(ftdi, control, hc_control);
+ if (retval)
+ return retval;
+ retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(ftdi, control, &control);
+ if (retval)
+ return retval;
+ retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE);
+ if (retval)
+ return retval;
+ retval = ftdi_write_pcimem(ftdi, intrstatus, mask);
+ if (retval)
+ return retval;
+ retval = ftdi_write_pcimem(ftdi, 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 = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a);
+ if (retval)
+ return retval;
+ roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
+ if (quirk & OHCI_QUIRK_SUPERIO) {
+ roothub_a |= RH_A_NOCP;
+ roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
+ retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a);
+ if (retval)
+ return retval;
+ } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) {
+ roothub_a |= RH_A_NPS;
+ retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a);
+ if (retval)
+ return retval;
+ }
+ retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC);
+ if (retval)
+ return retval;
+ retval = ftdi_write_pcimem(ftdi, roothub.b,
+ (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(ftdi, control, &control);
+ if (retval)
+ return retval;
+ mdelay((roothub_a >> 23) & 0x1fe);
+ for (temp = 0; temp < num_ports; temp++) {
+ u32 portstatus;
+ retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp],
+ &portstatus);
+ if (retval)
+ return retval;
+ if (1 & portstatus)
+ devices += 1;
+ }
+ return devices;
+}
+
+static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn)
{
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);
+ int activePCIfn = fn << 8;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800);
if (UxxxStatus)
return UxxxStatus;
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500);
+ reg = 16;
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
+ 0xFFFFFFFF);
if (UxxxStatus)
return UxxxStatus;
- UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
if (UxxxStatus)
return UxxxStatus;
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000);
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
+ 0xF0000000);
if (UxxxStatus)
return UxxxStatus;
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000);
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
if (UxxxStatus)
return UxxxStatus;
- msleep(250);
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000);
+ reg = 12;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &latence_timer);
if (UxxxStatus)
return UxxxStatus;
- UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ latence_timer &= 0xFFFF00FF;
+ latence_timer |= 0x00001600;
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
+ latence_timer);
if (UxxxStatus)
return UxxxStatus;
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800);
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
if (UxxxStatus)
return UxxxStatus;
- UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ reg = 4;
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
+ 0x06);
if (UxxxStatus)
return UxxxStatus;
- UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
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);
+ for (reg = 0; reg <= 0x54; reg += 4) {
+ UxxxStatus = ftdi_elan_read_pcimem(ftdi, 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;
+ return 0;
+}
+
+static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn)
+{
+ u32 latence_timer;
+ int UxxxStatus;
+ u32 pcidata;
+ int reg = 0;
+ int activePCIfn = fn << 8;
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800);
if (UxxxStatus)
return UxxxStatus;
@@ -2377,7 +2590,7 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
if (UxxxStatus)
return UxxxStatus;
UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
- 0xF0000000);
+ 0x00000000);
if (UxxxStatus)
return UxxxStatus;
UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
@@ -2401,7 +2614,7 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
return UxxxStatus;
reg = 4;
UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
- 0x06);
+ 0x00);
if (UxxxStatus)
return UxxxStatus;
UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
@@ -2411,159 +2624,139 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
return 0;
}
+static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk)
+{
+ int result;
+ int UxxxStatus;
+ UxxxStatus = ftdi_elan_setup_controller(ftdi, fn);
+ if (UxxxStatus)
+ return UxxxStatus;
+ result = ftdi_elan_check_controller(ftdi, quirk);
+ UxxxStatus = ftdi_elan_close_controller(ftdi, fn);
+ if (UxxxStatus)
+ return UxxxStatus;
+ return result;
+}
+
+static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
+{
+ u32 controlreg;
+ u8 sensebits;
+ int UxxxStatus;
+ 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);
+ sensebits = (controlreg >> 16) & 0x000F;
+ if (0x0D == sensebits)
+ return 0;
+ else
+ return - ENXIO;
+}
+
static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi)
{
+ int UxxxStatus;
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;
+ int reg = 0;
+ u8 fn;
+ int activePCIfn = 0;
+ int max_devices = 0;
+ int controllers = 0;
+ int unrecognized = 0;
+ ftdi->function = 0;
+ for (fn = 0; (fn < 4); fn++) {
+ u32 pciVID = 0;
+ u32 pciPID = 0;
+ int devices = 0;
+ activePCIfn = fn << 8;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ pciVID = pcidata & 0xFFFF;
+ pciPID = (pcidata >> 16) & 0xFFFF;
+ if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) {
+ devices = ftdi_elan_found_controller(ftdi, fn, 0);
+ controllers += 1;
+ } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035))
+ {
+ devices = ftdi_elan_found_controller(ftdi, fn, 0);
+ controllers += 1;
+ } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) {
+ devices = ftdi_elan_found_controller(ftdi, fn, 0);
+ controllers += 1;
+ } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802))
+ {
+ devices = ftdi_elan_found_controller(ftdi, fn, 0);
+ controllers += 1;
+ } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) {
+ devices = ftdi_elan_found_controller(ftdi, fn,
+ OHCI_QUIRK_AMD756);
+ controllers += 1;
+ } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) {
+ devices = ftdi_elan_found_controller(ftdi, fn,
+ OHCI_QUIRK_ZFMICRO);
+ controllers += 1;
+ } else if (0 == pcidata) {
+ } else
+ unrecognized += 1;
+ if (devices > max_devices) {
+ max_devices = devices;
+ ftdi->function = fn + 1;
+ ftdi->platform_data.vendor = pciVID;
+ ftdi->platform_data.device = pciPID;
}
}
- 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;
+ if (ftdi->function > 0) {
+ UxxxStatus = ftdi_elan_setup_controller(ftdi,
+ ftdi->function - 1);
+ if (UxxxStatus)
+ return UxxxStatus;
+ return 0;
+ } else if (controllers > 0) {
+ return -ENXIO;
+ } else if (unrecognized > 0) {
+ return -ENXIO;
+ } else {
+ ftdi->enumerated = 0;
+ return -ENXIO;
}
- return 0;
}
@@ -2688,6 +2881,7 @@ static void ftdi_elan_disconnect(struct usb_interface *interface)
platform_device_unregister(&ftdi->platform_dev);
ftdi->synchronized = 0;
ftdi->enumerated = 0;
+ ftdi->initialized = 0;
ftdi->registered = 0;
}
flush_workqueue(status_queue);
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index c9418535bef..15c70bd048c 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -269,7 +269,7 @@ static int idmouse_release(struct inode *inode, struct file *file)
/* prevent a race condition with open() */
mutex_lock(&disconnect_mutex);
- dev = (struct usb_idmouse *) file->private_data;
+ dev = file->private_data;
if (dev == NULL) {
mutex_unlock(&disconnect_mutex);
@@ -304,17 +304,15 @@ static int idmouse_release(struct inode *inode, struct file *file)
static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
loff_t * ppos)
{
- struct usb_idmouse *dev;
+ struct usb_idmouse *dev = file->private_data;
int result;
- dev = (struct usb_idmouse *) file->private_data;
-
/* lock this object */
- down (&dev->sem);
+ down(&dev->sem);
/* verify that the device wasn't unplugged */
if (!dev->present) {
- up (&dev->sem);
+ up(&dev->sem);
return -ENODEV;
}
diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c
index 7163f05c5b2..0d9de2f7393 100644
--- a/drivers/usb/misc/phidgetservo.c
+++ b/drivers/usb/misc/phidgetservo.c
@@ -282,6 +282,7 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
dev->dev = NULL;
goto out;
}
+ dev_set_drvdata(dev->dev, dev);
servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 384fa376980..fdf68479a16 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -69,7 +69,7 @@ struct rio_usb_data {
char *obuf, *ibuf; /* transfer buffers */
char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */
wait_queue_head_t wait_q; /* for timeouts */
- struct semaphore lock; /* general race avoidance */
+ struct mutex lock; /* general race avoidance */
};
static struct rio_usb_data rio_instance;
@@ -78,17 +78,17 @@ static int open_rio(struct inode *inode, struct file *file)
{
struct rio_usb_data *rio = &rio_instance;
- down(&(rio->lock));
+ mutex_lock(&(rio->lock));
if (rio->isopen || !rio->present) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -EBUSY;
}
rio->isopen = 1;
init_waitqueue_head(&rio->wait_q);
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
info("Rio opened.");
@@ -117,7 +117,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
int retries;
int retval=0;
- down(&(rio->lock));
+ mutex_lock(&(rio->lock));
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
@@ -257,7 +257,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
err_out:
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return retval;
}
@@ -275,14 +275,17 @@ write_rio(struct file *file, const char __user *buffer,
int result = 0;
int maxretry;
int errn = 0;
+ int intr;
- down(&(rio->lock));
+ intr = mutex_lock_interruptible(&(rio->lock));
+ if (intr)
+ return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
rio->rio_dev == NULL )
{
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -ENODEV;
}
@@ -305,7 +308,7 @@ write_rio(struct file *file, const char __user *buffer,
goto error;
}
if (signal_pending(current)) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return bytes_written ? bytes_written : -EINTR;
}
@@ -341,12 +344,12 @@ write_rio(struct file *file, const char __user *buffer,
buffer += copy_size;
} while (count > 0);
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return bytes_written ? bytes_written : -EIO;
error:
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return errn;
}
@@ -361,14 +364,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
int result;
int maxretry = 10;
char *ibuf;
+ int intr;
- down(&(rio->lock));
+ intr = mutex_lock_interruptible(&(rio->lock));
+ if (intr)
+ return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
rio->rio_dev == NULL )
{
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -ENODEV;
}
@@ -379,11 +385,11 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
while (count > 0) {
if (signal_pending(current)) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return read_count ? read_count : -EINTR;
}
if (!rio->rio_dev) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -ENODEV;
}
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
@@ -400,7 +406,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
count = this_read = partial;
} else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */
if (!maxretry--) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
err("read_rio: maxretry timeout");
return -ETIME;
}
@@ -409,18 +415,18 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
finish_wait(&rio->wait_q, &wait);
continue;
} else if (result != -EREMOTEIO) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
err("Read Whoops - result:%u partial:%u this_read:%u",
result, partial, this_read);
return -EIO;
} else {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return (0);
}
if (this_read) {
if (copy_to_user(buffer, ibuf, this_read)) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -EFAULT;
}
count -= this_read;
@@ -428,7 +434,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
buffer += this_read;
}
}
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return read_count;
}
@@ -480,7 +486,7 @@ static int probe_rio(struct usb_interface *intf,
}
dbg("probe_rio: ibuf address:%p", rio->ibuf);
- init_MUTEX(&(rio->lock));
+ mutex_init(&(rio->lock));
usb_set_intfdata (intf, rio);
rio->present = 1;
@@ -496,12 +502,12 @@ static void disconnect_rio(struct usb_interface *intf)
if (rio) {
usb_deregister_dev(intf, &usb_rio_class);
- down(&(rio->lock));
+ mutex_lock(&(rio->lock));
if (rio->isopen) {
rio->isopen = 0;
/* better let it finish - the release will do whats needed */
rio->rio_dev = NULL;
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return;
}
kfree(rio->ibuf);
@@ -510,7 +516,7 @@ static void disconnect_rio(struct usb_interface *intf)
info("USB Rio disconnected.");
rio->present = 0;
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
}
}
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index b99ca9c7982..0398908b15d 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -3168,7 +3168,7 @@ sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
case SISUSB_GET_CONFIG:
case SISUSB_COMMAND:
lock_kernel();
- retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
+ retval = sisusb_ioctl(f->f_path.dentry->d_inode, f, cmd, arg);
unlock_kernel();
return retval;
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index bf26c3c5699..9148694627d 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -403,7 +403,7 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
- (u32)SISUSB_HADDR(x, y), 2, &written);
+ (long)SISUSB_HADDR(x, y), 2, &written);
mutex_unlock(&sisusb->lock);
}
@@ -438,7 +438,7 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s,
}
sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
- (u32)SISUSB_HADDR(x, y), count * 2, &written);
+ (long)SISUSB_HADDR(x, y), count * 2, &written);
mutex_unlock(&sisusb->lock);
}
@@ -492,7 +492,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width)
sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y),
- (u32)SISUSB_HADDR(x, y), length, &written);
+ (long)SISUSB_HADDR(x, y), length, &written);
mutex_unlock(&sisusb->lock);
}
@@ -564,7 +564,7 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy),
- (u32)SISUSB_HADDR(dx, dy), length, &written);
+ (long)SISUSB_HADDR(dx, dy), length, &written);
mutex_unlock(&sisusb->lock);
}
@@ -612,7 +612,7 @@ sisusbcon_switch(struct vc_data *c)
length);
sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin,
- (u32)SISUSB_HADDR(0, 0),
+ (long)SISUSB_HADDR(0, 0),
length, &written);
mutex_unlock(&sisusb->lock);
@@ -939,7 +939,7 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb,
}
sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t),
- (u32)SISUSB_HADDR(0, t), length, &written);
+ (long)SISUSB_HADDR(0, t), length, &written);
mutex_unlock(&sisusb->lock);
diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c
index 33cd91d11ec..67e2fc20eee 100644
--- a/drivers/usb/misc/trancevibrator.c
+++ b/drivers/usb/misc/trancevibrator.c
@@ -120,8 +120,8 @@ 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_set_intfdata(interface, NULL);
usb_put_dev(dev->udev);
kfree(dev);
}
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 7e8a0acd52e..70250252ae2 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -705,7 +705,7 @@ static int uss720_probe(struct usb_interface *intf,
/*
* Allocate parport interface
*/
- if (!(priv = kcalloc(sizeof(struct parport_uss720_private), 1, GFP_KERNEL))) {
+ if (!(priv = kzalloc(sizeof(struct parport_uss720_private), GFP_KERNEL))) {
usb_put_dev(usbdev);
return -ENOMEM;
}
diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile
index 3cf3ea3a88e..90c59535778 100644
--- a/drivers/usb/mon/Makefile
+++ b/drivers/usb/mon/Makefile
@@ -2,7 +2,7 @@
# Makefile for USB Core files and filesystem
#
-usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_dma.o
+usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o
# This does not use CONFIG_USB_MON because we want this to use a tristate.
obj-$(CONFIG_USB) += usbmon.o
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
new file mode 100644
index 00000000000..c01dfe60367
--- /dev/null
+++ b/drivers/usb/mon/mon_bin.c
@@ -0,0 +1,1172 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is a binary format reader.
+ *
+ * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
+ * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <linux/compat.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+/*
+ * Defined by USB 2.0 clause 9.3, table 9.2.
+ */
+#define SETUP_LEN 8
+
+/* ioctl macros */
+#define MON_IOC_MAGIC 0x92
+
+#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1)
+/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */
+#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
+#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
+#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
+#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
+#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
+#ifdef CONFIG_COMPAT
+#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32)
+#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32)
+#endif
+
+/*
+ * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc).
+ * But it's all right. Just use a simple way to make sure the chunk is never
+ * smaller than a page.
+ *
+ * N.B. An application does not know our chunk size.
+ *
+ * Woops, get_zeroed_page() returns a single page. I guess we're stuck with
+ * page-sized chunks for the time being.
+ */
+#define CHUNK_SIZE PAGE_SIZE
+#define CHUNK_ALIGN(x) (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1))
+
+/*
+ * The magic limit was calculated so that it allows the monitoring
+ * application to pick data once in two ticks. This way, another application,
+ * which presumably drives the bus, gets to hog CPU, yet we collect our data.
+ * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an
+ * enormous overhead built into the bus protocol, so we need about 1000 KB.
+ *
+ * This is still too much for most cases, where we just snoop a few
+ * descriptor fetches for enumeration. So, the default is a "reasonable"
+ * amount for systems with HZ=250 and incomplete bus saturation.
+ *
+ * XXX What about multi-megabyte URBs which take minutes to transfer?
+ */
+#define BUFF_MAX CHUNK_ALIGN(1200*1024)
+#define BUFF_DFL CHUNK_ALIGN(300*1024)
+#define BUFF_MIN CHUNK_ALIGN(8*1024)
+
+/*
+ * The per-event API header (2 per URB).
+ *
+ * This structure is seen in userland as defined by the documentation.
+ */
+struct mon_bin_hdr {
+ u64 id; /* URB ID - from submission to callback */
+ unsigned char type; /* Same as in text API; extensible. */
+ unsigned char xfer_type; /* ISO, Intr, Control, Bulk */
+ unsigned char epnum; /* Endpoint number and transfer direction */
+ unsigned char devnum; /* Device address */
+ unsigned short busnum; /* Bus number */
+ char flag_setup;
+ char flag_data;
+ s64 ts_sec; /* gettimeofday */
+ s32 ts_usec; /* gettimeofday */
+ int status;
+ unsigned int len_urb; /* Length of data (submitted or actual) */
+ unsigned int len_cap; /* Delivered length */
+ unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
+};
+
+/* per file statistic */
+struct mon_bin_stats {
+ u32 queued;
+ u32 dropped;
+};
+
+struct mon_bin_get {
+ struct mon_bin_hdr __user *hdr; /* Only 48 bytes, not 64. */
+ void __user *data;
+ size_t alloc; /* Length of data (can be zero) */
+};
+
+struct mon_bin_mfetch {
+ u32 __user *offvec; /* Vector of events fetched */
+ u32 nfetch; /* Number of events to fetch (out: fetched) */
+ u32 nflush; /* Number of events to flush */
+};
+
+#ifdef CONFIG_COMPAT
+struct mon_bin_get32 {
+ u32 hdr32;
+ u32 data32;
+ u32 alloc32;
+};
+
+struct mon_bin_mfetch32 {
+ u32 offvec32;
+ u32 nfetch32;
+ u32 nflush32;
+};
+#endif
+
+/* Having these two values same prevents wrapping of the mon_bin_hdr */
+#define PKT_ALIGN 64
+#define PKT_SIZE 64
+
+/* max number of USB bus supported */
+#define MON_BIN_MAX_MINOR 128
+
+/*
+ * The buffer: map of used pages.
+ */
+struct mon_pgmap {
+ struct page *pg;
+ unsigned char *ptr; /* XXX just use page_to_virt everywhere? */
+};
+
+/*
+ * This gets associated with an open file struct.
+ */
+struct mon_reader_bin {
+ /* The buffer: one per open. */
+ spinlock_t b_lock; /* Protect b_cnt, b_in */
+ unsigned int b_size; /* Current size of the buffer - bytes */
+ unsigned int b_cnt; /* Bytes used */
+ unsigned int b_in, b_out; /* Offsets into buffer - bytes */
+ unsigned int b_read; /* Amount of read data in curr. pkt. */
+ struct mon_pgmap *b_vec; /* The map array */
+ wait_queue_head_t b_wait; /* Wait for data here */
+
+ struct mutex fetch_lock; /* Protect b_read, b_out */
+ int mmap_active;
+
+ /* A list of these is needed for "bus 0". Some time later. */
+ struct mon_reader r;
+
+ /* Stats */
+ unsigned int cnt_lost;
+};
+
+static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
+ unsigned int offset)
+{
+ return (struct mon_bin_hdr *)
+ (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE);
+}
+
+#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0)
+
+static dev_t mon_bin_dev0;
+static struct cdev mon_bin_cdev;
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+ unsigned int offset, unsigned int size);
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp);
+static int mon_alloc_buff(struct mon_pgmap *map, int npages);
+static void mon_free_buff(struct mon_pgmap *map, int npages);
+
+/*
+ * This is a "chunked memcpy". It does not manipulate any counters.
+ * But it returns the new offset for repeated application.
+ */
+unsigned int mon_copy_to_buff(const struct mon_reader_bin *this,
+ unsigned int off, const unsigned char *from, unsigned int length)
+{
+ unsigned int step_len;
+ unsigned char *buf;
+ unsigned int in_page;
+
+ while (length) {
+ /*
+ * Determine step_len.
+ */
+ step_len = length;
+ in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+ if (in_page < step_len)
+ step_len = in_page;
+
+ /*
+ * Copy data and advance pointers.
+ */
+ buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+ memcpy(buf, from, step_len);
+ if ((off += step_len) >= this->b_size) off = 0;
+ from += step_len;
+ length -= step_len;
+ }
+ return off;
+}
+
+/*
+ * This is a little worse than the above because it's "chunked copy_to_user".
+ * The return value is an error code, not an offset.
+ */
+static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off,
+ char __user *to, int length)
+{
+ unsigned int step_len;
+ unsigned char *buf;
+ unsigned int in_page;
+
+ while (length) {
+ /*
+ * Determine step_len.
+ */
+ step_len = length;
+ in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+ if (in_page < step_len)
+ step_len = in_page;
+
+ /*
+ * Copy data and advance pointers.
+ */
+ buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+ if (copy_to_user(to, buf, step_len))
+ return -EINVAL;
+ if ((off += step_len) >= this->b_size) off = 0;
+ to += step_len;
+ length -= step_len;
+ }
+ return 0;
+}
+
+/*
+ * Allocate an (aligned) area in the buffer.
+ * This is called under b_lock.
+ * Returns ~0 on failure.
+ */
+static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp,
+ unsigned int size)
+{
+ unsigned int offset;
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if (rp->b_cnt + size > rp->b_size)
+ return ~0;
+ offset = rp->b_in;
+ rp->b_cnt += size;
+ if ((rp->b_in += size) >= rp->b_size)
+ rp->b_in -= rp->b_size;
+ return offset;
+}
+
+/*
+ * This is the same thing as mon_buff_area_alloc, only it does not allow
+ * buffers to wrap. This is needed by applications which pass references
+ * into mmap-ed buffers up their stacks (libpcap can do that).
+ *
+ * Currently, we always have the header stuck with the data, although
+ * it is not strictly speaking necessary.
+ *
+ * When a buffer would wrap, we place a filler packet to mark the space.
+ */
+static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp,
+ unsigned int size)
+{
+ unsigned int offset;
+ unsigned int fill_size;
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if (rp->b_cnt + size > rp->b_size)
+ return ~0;
+ if (rp->b_in + size > rp->b_size) {
+ /*
+ * This would wrap. Find if we still have space after
+ * skipping to the end of the buffer. If we do, place
+ * a filler packet and allocate a new packet.
+ */
+ fill_size = rp->b_size - rp->b_in;
+ if (rp->b_cnt + size + fill_size > rp->b_size)
+ return ~0;
+ mon_buff_area_fill(rp, rp->b_in, fill_size);
+
+ offset = 0;
+ rp->b_in = size;
+ rp->b_cnt += size + fill_size;
+ } else if (rp->b_in + size == rp->b_size) {
+ offset = rp->b_in;
+ rp->b_in = 0;
+ rp->b_cnt += size;
+ } else {
+ offset = rp->b_in;
+ rp->b_in += size;
+ rp->b_cnt += size;
+ }
+ return offset;
+}
+
+/*
+ * Return a few (kilo-)bytes to the head of the buffer.
+ * This is used if a DMA fetch fails.
+ */
+static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size)
+{
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ rp->b_cnt -= size;
+ if (rp->b_in < size)
+ rp->b_in += rp->b_size;
+ rp->b_in -= size;
+}
+
+/*
+ * This has to be called under both b_lock and fetch_lock, because
+ * it accesses both b_cnt and b_out.
+ */
+static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size)
+{
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ rp->b_cnt -= size;
+ if ((rp->b_out += size) >= rp->b_size)
+ rp->b_out -= rp->b_size;
+}
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+ unsigned int offset, unsigned int size)
+{
+ struct mon_bin_hdr *ep;
+
+ ep = MON_OFF2HDR(rp, offset);
+ memset(ep, 0, PKT_SIZE);
+ ep->type = '@';
+ ep->len_cap = size - PKT_SIZE;
+}
+
+static inline char mon_bin_get_setup(unsigned char *setupb,
+ const struct urb *urb, char ev_type)
+{
+
+ if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ return '-';
+
+ if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+ return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
+ if (urb->setup_packet == NULL)
+ return 'Z';
+
+ memcpy(setupb, urb->setup_packet, SETUP_LEN);
+ return 0;
+}
+
+static char mon_bin_get_data(const struct mon_reader_bin *rp,
+ unsigned int offset, struct urb *urb, unsigned int length)
+{
+
+ if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
+ mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
+ return 0;
+ }
+
+ if (urb->transfer_buffer == NULL)
+ return 'Z';
+
+ mon_copy_to_buff(rp, offset, urb->transfer_buffer, length);
+ return 0;
+}
+
+static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
+ char ev_type)
+{
+ unsigned long flags;
+ struct timeval ts;
+ unsigned int urb_length;
+ unsigned int offset;
+ unsigned int length;
+ struct mon_bin_hdr *ep;
+ char data_tag = 0;
+
+ do_gettimeofday(&ts);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+
+ /*
+ * Find the maximum allowable length, then allocate space.
+ */
+ urb_length = (ev_type == 'S') ?
+ urb->transfer_buffer_length : urb->actual_length;
+ length = urb_length;
+
+ if (length >= rp->b_size/5)
+ length = rp->b_size/5;
+
+ if (usb_pipein(urb->pipe)) {
+ if (ev_type == 'S') {
+ length = 0;
+ data_tag = '<';
+ }
+ } else {
+ if (ev_type == 'C') {
+ length = 0;
+ data_tag = '>';
+ }
+ }
+
+ if (rp->mmap_active)
+ offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE);
+ else
+ offset = mon_buff_area_alloc(rp, length + PKT_SIZE);
+ if (offset == ~0) {
+ rp->cnt_lost++;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ return;
+ }
+
+ ep = MON_OFF2HDR(rp, offset);
+ if ((offset += PKT_SIZE) >= rp->b_size) offset = 0;
+
+ /*
+ * Fill the allocated area.
+ */
+ memset(ep, 0, PKT_SIZE);
+ ep->type = ev_type;
+ ep->xfer_type = usb_pipetype(urb->pipe);
+ /* We use the fact that usb_pipein() returns 0x80 */
+ ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+ ep->devnum = usb_pipedevice(urb->pipe);
+ ep->busnum = rp->r.m_bus->u_bus->busnum;
+ ep->id = (unsigned long) urb;
+ ep->ts_sec = ts.tv_sec;
+ ep->ts_usec = ts.tv_usec;
+ ep->status = urb->status;
+ ep->len_urb = urb_length;
+ ep->len_cap = length;
+
+ ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type);
+ if (length != 0) {
+ ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
+ if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */
+ ep->len_cap = 0;
+ mon_buff_area_shrink(rp, length);
+ }
+ } else {
+ ep->flag_data = data_tag;
+ }
+
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ wake_up(&rp->b_wait);
+}
+
+static void mon_bin_submit(void *data, struct urb *urb)
+{
+ struct mon_reader_bin *rp = data;
+ mon_bin_event(rp, urb, 'S');
+}
+
+static void mon_bin_complete(void *data, struct urb *urb)
+{
+ struct mon_reader_bin *rp = data;
+ mon_bin_event(rp, urb, 'C');
+}
+
+static void mon_bin_error(void *data, struct urb *urb, int error)
+{
+ struct mon_reader_bin *rp = data;
+ unsigned long flags;
+ unsigned int offset;
+ struct mon_bin_hdr *ep;
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+
+ offset = mon_buff_area_alloc(rp, PKT_SIZE);
+ if (offset == ~0) {
+ /* Not incrementing cnt_lost. Just because. */
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ return;
+ }
+
+ ep = MON_OFF2HDR(rp, offset);
+
+ memset(ep, 0, PKT_SIZE);
+ ep->type = 'E';
+ ep->xfer_type = usb_pipetype(urb->pipe);
+ /* We use the fact that usb_pipein() returns 0x80 */
+ ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+ ep->devnum = usb_pipedevice(urb->pipe);
+ ep->busnum = rp->r.m_bus->u_bus->busnum;
+ ep->id = (unsigned long) urb;
+ ep->status = error;
+
+ ep->flag_setup = '-';
+ ep->flag_data = 'E';
+
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ wake_up(&rp->b_wait);
+}
+
+static int mon_bin_open(struct inode *inode, struct file *file)
+{
+ struct mon_bus *mbus;
+ struct usb_bus *ubus;
+ struct mon_reader_bin *rp;
+ size_t size;
+ int rc;
+
+ mutex_lock(&mon_lock);
+ if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) {
+ mutex_unlock(&mon_lock);
+ return -ENODEV;
+ }
+ if ((ubus = mbus->u_bus) == NULL) {
+ printk(KERN_ERR TAG ": consistency error on open\n");
+ mutex_unlock(&mon_lock);
+ return -ENODEV;
+ }
+
+ rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL);
+ if (rp == NULL) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ spin_lock_init(&rp->b_lock);
+ init_waitqueue_head(&rp->b_wait);
+ mutex_init(&rp->fetch_lock);
+
+ rp->b_size = BUFF_DFL;
+
+ size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE);
+ if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) {
+ rc = -ENOMEM;
+ goto err_allocvec;
+ }
+
+ if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0)
+ goto err_allocbuff;
+
+ rp->r.m_bus = mbus;
+ rp->r.r_data = rp;
+ rp->r.rnf_submit = mon_bin_submit;
+ rp->r.rnf_error = mon_bin_error;
+ rp->r.rnf_complete = mon_bin_complete;
+
+ mon_reader_add(mbus, &rp->r);
+
+ file->private_data = rp;
+ mutex_unlock(&mon_lock);
+ return 0;
+
+err_allocbuff:
+ kfree(rp->b_vec);
+err_allocvec:
+ kfree(rp);
+err_alloc:
+ mutex_unlock(&mon_lock);
+ return rc;
+}
+
+/*
+ * Extract an event from buffer and copy it to user space.
+ * Wait if there is no event ready.
+ * Returns zero or error.
+ */
+static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp,
+ struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes)
+{
+ unsigned long flags;
+ struct mon_bin_hdr *ep;
+ size_t step_len;
+ unsigned int offset;
+ int rc;
+
+ mutex_lock(&rp->fetch_lock);
+
+ if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+ mutex_unlock(&rp->fetch_lock);
+ return rc;
+ }
+
+ ep = MON_OFF2HDR(rp, rp->b_out);
+
+ if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+
+ step_len = min(ep->len_cap, nbytes);
+ if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0;
+
+ if (copy_from_buf(rp, offset, data, step_len)) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ rp->b_read = 0;
+
+ mutex_unlock(&rp->fetch_lock);
+ return 0;
+}
+
+static int mon_bin_release(struct inode *inode, struct file *file)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ struct mon_bus* mbus = rp->r.m_bus;
+
+ mutex_lock(&mon_lock);
+
+ if (mbus->nreaders <= 0) {
+ printk(KERN_ERR TAG ": consistency error on close\n");
+ mutex_unlock(&mon_lock);
+ return 0;
+ }
+ mon_reader_del(mbus, &rp->r);
+
+ mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
+ kfree(rp->b_vec);
+ kfree(rp);
+
+ mutex_unlock(&mon_lock);
+ return 0;
+}
+
+static ssize_t mon_bin_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ unsigned long flags;
+ struct mon_bin_hdr *ep;
+ unsigned int offset;
+ size_t step_len;
+ char *ptr;
+ ssize_t done = 0;
+ int rc;
+
+ mutex_lock(&rp->fetch_lock);
+
+ if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+ mutex_unlock(&rp->fetch_lock);
+ return rc;
+ }
+
+ ep = MON_OFF2HDR(rp, rp->b_out);
+
+ if (rp->b_read < sizeof(struct mon_bin_hdr)) {
+ step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read);
+ ptr = ((char *)ep) + rp->b_read;
+ if (step_len && copy_to_user(buf, ptr, step_len)) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+ nbytes -= step_len;
+ buf += step_len;
+ rp->b_read += step_len;
+ done += step_len;
+ }
+
+ if (rp->b_read >= sizeof(struct mon_bin_hdr)) {
+ step_len = min(nbytes, (size_t)ep->len_cap);
+ offset = rp->b_out + PKT_SIZE;
+ offset += rp->b_read - sizeof(struct mon_bin_hdr);
+ if (offset >= rp->b_size)
+ offset -= rp->b_size;
+ if (copy_from_buf(rp, offset, buf, step_len)) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+ nbytes -= step_len;
+ buf += step_len;
+ rp->b_read += step_len;
+ done += step_len;
+ }
+
+ /*
+ * Check if whole packet was read, and if so, jump to the next one.
+ */
+ if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) {
+ spin_lock_irqsave(&rp->b_lock, flags);
+ mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ rp->b_read = 0;
+ }
+
+ mutex_unlock(&rp->fetch_lock);
+ return done;
+}
+
+/*
+ * Remove at most nevents from chunked buffer.
+ * Returns the number of removed events.
+ */
+static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents)
+{
+ unsigned long flags;
+ struct mon_bin_hdr *ep;
+ int i;
+
+ mutex_lock(&rp->fetch_lock);
+ spin_lock_irqsave(&rp->b_lock, flags);
+ for (i = 0; i < nevents; ++i) {
+ if (MON_RING_EMPTY(rp))
+ break;
+
+ ep = MON_OFF2HDR(rp, rp->b_out);
+ mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+ }
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ rp->b_read = 0;
+ mutex_unlock(&rp->fetch_lock);
+ return i;
+}
+
+/*
+ * Fetch at most max event offsets into the buffer and put them into vec.
+ * The events are usually freed later with mon_bin_flush.
+ * Return the effective number of events fetched.
+ */
+static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp,
+ u32 __user *vec, unsigned int max)
+{
+ unsigned int cur_out;
+ unsigned int bytes, avail;
+ unsigned int size;
+ unsigned int nevents;
+ struct mon_bin_hdr *ep;
+ unsigned long flags;
+ int rc;
+
+ mutex_lock(&rp->fetch_lock);
+
+ if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+ mutex_unlock(&rp->fetch_lock);
+ return rc;
+ }
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ avail = rp->b_cnt;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ cur_out = rp->b_out;
+ nevents = 0;
+ bytes = 0;
+ while (bytes < avail) {
+ if (nevents >= max)
+ break;
+
+ ep = MON_OFF2HDR(rp, cur_out);
+ if (put_user(cur_out, &vec[nevents])) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+
+ nevents++;
+ size = ep->len_cap + PKT_SIZE;
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if ((cur_out += size) >= rp->b_size)
+ cur_out -= rp->b_size;
+ bytes += size;
+ }
+
+ mutex_unlock(&rp->fetch_lock);
+ return nevents;
+}
+
+/*
+ * Count events. This is almost the same as the above mon_bin_fetch,
+ * only we do not store offsets into user vector, and we have no limit.
+ */
+static int mon_bin_queued(struct mon_reader_bin *rp)
+{
+ unsigned int cur_out;
+ unsigned int bytes, avail;
+ unsigned int size;
+ unsigned int nevents;
+ struct mon_bin_hdr *ep;
+ unsigned long flags;
+
+ mutex_lock(&rp->fetch_lock);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ avail = rp->b_cnt;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ cur_out = rp->b_out;
+ nevents = 0;
+ bytes = 0;
+ while (bytes < avail) {
+ ep = MON_OFF2HDR(rp, cur_out);
+
+ nevents++;
+ size = ep->len_cap + PKT_SIZE;
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if ((cur_out += size) >= rp->b_size)
+ cur_out -= rp->b_size;
+ bytes += size;
+ }
+
+ mutex_unlock(&rp->fetch_lock);
+ return nevents;
+}
+
+/*
+ */
+static int mon_bin_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ // struct mon_bus* mbus = rp->r.m_bus;
+ int ret = 0;
+ struct mon_bin_hdr *ep;
+ unsigned long flags;
+
+ switch (cmd) {
+
+ case MON_IOCQ_URB_LEN:
+ /*
+ * N.B. This only returns the size of data, without the header.
+ */
+ spin_lock_irqsave(&rp->b_lock, flags);
+ if (!MON_RING_EMPTY(rp)) {
+ ep = MON_OFF2HDR(rp, rp->b_out);
+ ret = ep->len_cap;
+ }
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ break;
+
+ case MON_IOCQ_RING_SIZE:
+ ret = rp->b_size;
+ break;
+
+ case MON_IOCT_RING_SIZE:
+ /*
+ * Changing the buffer size will flush it's contents; the new
+ * buffer is allocated before releasing the old one to be sure
+ * the device will stay functional also in case of memory
+ * pressure.
+ */
+ {
+ int size;
+ struct mon_pgmap *vec;
+
+ if (arg < BUFF_MIN || arg > BUFF_MAX)
+ return -EINVAL;
+
+ size = CHUNK_ALIGN(arg);
+ if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE),
+ GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ ret = mon_alloc_buff(vec, size/CHUNK_SIZE);
+ if (ret < 0) {
+ kfree(vec);
+ break;
+ }
+
+ mutex_lock(&rp->fetch_lock);
+ spin_lock_irqsave(&rp->b_lock, flags);
+ mon_free_buff(rp->b_vec, size/CHUNK_SIZE);
+ kfree(rp->b_vec);
+ rp->b_vec = vec;
+ rp->b_size = size;
+ rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
+ rp->cnt_lost = 0;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ mutex_unlock(&rp->fetch_lock);
+ }
+ break;
+
+ case MON_IOCH_MFLUSH:
+ ret = mon_bin_flush(rp, arg);
+ break;
+
+ case MON_IOCX_GET:
+ {
+ struct mon_bin_get getb;
+
+ if (copy_from_user(&getb, (void __user *)arg,
+ sizeof(struct mon_bin_get)))
+ return -EFAULT;
+
+ if (getb.alloc > 0x10000000) /* Want to cast to u32 */
+ return -EINVAL;
+ ret = mon_bin_get_event(file, rp,
+ getb.hdr, getb.data, (unsigned int)getb.alloc);
+ }
+ break;
+
+#ifdef CONFIG_COMPAT
+ case MON_IOCX_GET32: {
+ struct mon_bin_get32 getb;
+
+ if (copy_from_user(&getb, (void __user *)arg,
+ sizeof(struct mon_bin_get32)))
+ return -EFAULT;
+
+ ret = mon_bin_get_event(file, rp,
+ compat_ptr(getb.hdr32), compat_ptr(getb.data32),
+ getb.alloc32);
+ }
+ break;
+#endif
+
+ case MON_IOCX_MFETCH:
+ {
+ struct mon_bin_mfetch mfetch;
+ struct mon_bin_mfetch __user *uptr;
+
+ uptr = (struct mon_bin_mfetch __user *)arg;
+
+ if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+ return -EFAULT;
+
+ if (mfetch.nflush) {
+ ret = mon_bin_flush(rp, mfetch.nflush);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nflush))
+ return -EFAULT;
+ }
+ ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nfetch))
+ return -EFAULT;
+ ret = 0;
+ }
+ break;
+
+#ifdef CONFIG_COMPAT
+ case MON_IOCX_MFETCH32:
+ {
+ struct mon_bin_mfetch32 mfetch;
+ struct mon_bin_mfetch32 __user *uptr;
+
+ uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg);
+
+ if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+ return -EFAULT;
+
+ if (mfetch.nflush32) {
+ ret = mon_bin_flush(rp, mfetch.nflush32);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nflush32))
+ return -EFAULT;
+ }
+ ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32),
+ mfetch.nfetch32);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nfetch32))
+ return -EFAULT;
+ ret = 0;
+ }
+ break;
+#endif
+
+ case MON_IOCG_STATS: {
+ struct mon_bin_stats __user *sp;
+ unsigned int nevents;
+ unsigned int ndropped;
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ ndropped = rp->cnt_lost;
+ rp->cnt_lost = 0;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ nevents = mon_bin_queued(rp);
+
+ sp = (struct mon_bin_stats __user *)arg;
+ if (put_user(rp->cnt_lost, &sp->dropped))
+ return -EFAULT;
+ if (put_user(nevents, &sp->queued))
+ return -EFAULT;
+
+ }
+ break;
+
+ default:
+ return -ENOTTY;
+ }
+
+ return ret;
+}
+
+static unsigned int
+mon_bin_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ if (file->f_mode & FMODE_READ)
+ poll_wait(file, &rp->b_wait, wait);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ if (!MON_RING_EMPTY(rp))
+ mask |= POLLIN | POLLRDNORM; /* readable */
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ return mask;
+}
+
+/*
+ * open and close: just keep track of how many times the device is
+ * mapped, to use the proper memory allocation function.
+ */
+static void mon_bin_vma_open(struct vm_area_struct *vma)
+{
+ struct mon_reader_bin *rp = vma->vm_private_data;
+ rp->mmap_active++;
+}
+
+static void mon_bin_vma_close(struct vm_area_struct *vma)
+{
+ struct mon_reader_bin *rp = vma->vm_private_data;
+ rp->mmap_active--;
+}
+
+/*
+ * Map ring pages to user space.
+ */
+struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ struct mon_reader_bin *rp = vma->vm_private_data;
+ unsigned long offset, chunk_idx;
+ struct page *pageptr;
+
+ offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+ if (offset >= rp->b_size)
+ return NOPAGE_SIGBUS;
+ chunk_idx = offset / CHUNK_SIZE;
+ pageptr = rp->b_vec[chunk_idx].pg;
+ get_page(pageptr);
+ if (type)
+ *type = VM_FAULT_MINOR;
+ return pageptr;
+}
+
+struct vm_operations_struct mon_bin_vm_ops = {
+ .open = mon_bin_vma_open,
+ .close = mon_bin_vma_close,
+ .nopage = mon_bin_vma_nopage,
+};
+
+int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ /* don't do anything here: "nopage" will set up page table entries */
+ vma->vm_ops = &mon_bin_vm_ops;
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_private_data = filp->private_data;
+ mon_bin_vma_open(vma);
+ return 0;
+}
+
+struct file_operations mon_fops_binary = {
+ .owner = THIS_MODULE,
+ .open = mon_bin_open,
+ .llseek = no_llseek,
+ .read = mon_bin_read,
+ /* .write = mon_text_write, */
+ .poll = mon_bin_poll,
+ .ioctl = mon_bin_ioctl,
+ .release = mon_bin_release,
+};
+
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp)
+{
+ DECLARE_WAITQUEUE(waita, current);
+ unsigned long flags;
+
+ add_wait_queue(&rp->b_wait, &waita);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ while (MON_RING_EMPTY(rp)) {
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ if (file->f_flags & O_NONBLOCK) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&rp->b_wait, &waita);
+ return -EWOULDBLOCK; /* Same as EAGAIN in Linux */
+ }
+ schedule();
+ if (signal_pending(current)) {
+ remove_wait_queue(&rp->b_wait, &waita);
+ return -EINTR;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ }
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&rp->b_wait, &waita);
+ return 0;
+}
+
+static int mon_alloc_buff(struct mon_pgmap *map, int npages)
+{
+ int n;
+ unsigned long vaddr;
+
+ for (n = 0; n < npages; n++) {
+ vaddr = get_zeroed_page(GFP_KERNEL);
+ if (vaddr == 0) {
+ while (n-- != 0)
+ free_page((unsigned long) map[n].ptr);
+ return -ENOMEM;
+ }
+ map[n].ptr = (unsigned char *) vaddr;
+ map[n].pg = virt_to_page(vaddr);
+ }
+ return 0;
+}
+
+static void mon_free_buff(struct mon_pgmap *map, int npages)
+{
+ int n;
+
+ for (n = 0; n < npages; n++)
+ free_page((unsigned long) map[n].ptr);
+}
+
+int __init mon_bin_init(void)
+{
+ int rc;
+
+ rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
+ if (rc < 0)
+ goto err_dev;
+
+ cdev_init(&mon_bin_cdev, &mon_fops_binary);
+ mon_bin_cdev.owner = THIS_MODULE;
+
+ rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR);
+ if (rc < 0)
+ goto err_add;
+
+ return 0;
+
+err_add:
+ unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+err_dev:
+ return rc;
+}
+
+void __exit mon_bin_exit(void)
+{
+ cdev_del(&mon_bin_cdev);
+ unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+}
diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c
index ddcfc01e77a..140cc80bd2b 100644
--- a/drivers/usb/mon/mon_dma.c
+++ b/drivers/usb/mon/mon_dma.c
@@ -48,6 +48,36 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
local_irq_restore(flags);
return 0;
}
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+ unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+ unsigned long flags;
+ unsigned int step_len;
+ struct page *pg;
+ unsigned char *map;
+ unsigned long page_off, page_len;
+
+ local_irq_save(flags);
+ while (length) {
+ /* compute number of bytes we are going to copy in this page */
+ step_len = length;
+ page_off = dma_addr & (PAGE_SIZE-1);
+ page_len = PAGE_SIZE - page_off;
+ if (page_len < step_len)
+ step_len = page_len;
+
+ /* copy data and advance pointers */
+ pg = phys_to_page(dma_addr);
+ map = kmap_atomic(pg, KM_IRQ0);
+ offset = mon_copy_to_buff(rp, offset, map + page_off, step_len);
+ kunmap_atomic(map, KM_IRQ0);
+ dma_addr += step_len;
+ length -= step_len;
+ }
+ local_irq_restore(flags);
+}
+
#endif /* __i386__ */
#ifndef MON_HAS_UNMAP
@@ -55,4 +85,11 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
{
return 'D';
}
-#endif
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+ unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+ ;
+}
+
+#endif /* MON_HAS_UNMAP */
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 394bbf2f68d..c9739e7b35e 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include <linux/debugfs.h>
#include <linux/smp_lock.h>
#include <linux/notifier.h>
#include <linux/mutex.h>
@@ -22,11 +21,10 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb);
static void mon_stop(struct mon_bus *mbus);
static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
static void mon_bus_drop(struct kref *r);
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
+static void mon_bus_init(struct usb_bus *ubus);
DEFINE_MUTEX(mon_lock);
-static struct dentry *mon_dir; /* /dbg/usbmon */
static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */
/*
@@ -200,7 +198,7 @@ static void mon_stop(struct mon_bus *mbus)
*/
static void mon_bus_add(struct usb_bus *ubus)
{
- mon_bus_init(mon_dir, ubus);
+ mon_bus_init(ubus);
}
/*
@@ -212,8 +210,8 @@ static void mon_bus_remove(struct usb_bus *ubus)
mutex_lock(&mon_lock);
list_del(&mbus->bus_link);
- debugfs_remove(mbus->dent_t);
- debugfs_remove(mbus->dent_s);
+ if (mbus->text_inited)
+ mon_text_del(mbus);
mon_dissolve(mbus, ubus);
kref_put(&mbus->ref, mon_bus_drop);
@@ -281,13 +279,9 @@ static void mon_bus_drop(struct kref *r)
* - refcount USB bus struct
* - link
*/
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
+static void mon_bus_init(struct usb_bus *ubus)
{
- struct dentry *d;
struct mon_bus *mbus;
- enum { NAMESZ = 10 };
- char name[NAMESZ];
- int rc;
if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
goto err_alloc;
@@ -303,57 +297,54 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
ubus->mon_bus = mbus;
mbus->uses_dma = ubus->uses_dma;
- rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
- if (rc <= 0 || rc >= NAMESZ)
- goto err_print_t;
- d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
- if (d == NULL)
- goto err_create_t;
- mbus->dent_t = d;
-
- rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
- if (rc <= 0 || rc >= NAMESZ)
- goto err_print_s;
- d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
- if (d == NULL)
- goto err_create_s;
- mbus->dent_s = d;
+ mbus->text_inited = mon_text_add(mbus, ubus);
+ // mon_bin_add(...)
mutex_lock(&mon_lock);
list_add_tail(&mbus->bus_link, &mon_buses);
mutex_unlock(&mon_lock);
return;
-err_create_s:
-err_print_s:
- debugfs_remove(mbus->dent_t);
-err_create_t:
-err_print_t:
- kfree(mbus);
err_alloc:
return;
}
+/*
+ * Search a USB bus by number. Notice that USB bus numbers start from one,
+ * which we may later use to identify "all" with zero.
+ *
+ * This function must be called with mon_lock held.
+ *
+ * This is obviously inefficient and may be revised in the future.
+ */
+struct mon_bus *mon_bus_lookup(unsigned int num)
+{
+ struct list_head *p;
+ struct mon_bus *mbus;
+
+ list_for_each (p, &mon_buses) {
+ mbus = list_entry(p, struct mon_bus, bus_link);
+ if (mbus->u_bus->busnum == num) {
+ return mbus;
+ }
+ }
+ return NULL;
+}
+
static int __init mon_init(void)
{
struct usb_bus *ubus;
- struct dentry *mondir;
+ int rc;
- mondir = debugfs_create_dir("usbmon", NULL);
- if (IS_ERR(mondir)) {
- printk(KERN_NOTICE TAG ": debugfs is not available\n");
- return -ENODEV;
- }
- if (mondir == NULL) {
- printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
- return -ENODEV;
- }
- mon_dir = mondir;
+ if ((rc = mon_text_init()) != 0)
+ goto err_text;
+ if ((rc = mon_bin_init()) != 0)
+ goto err_bin;
if (usb_mon_register(&mon_ops_0) != 0) {
printk(KERN_NOTICE TAG ": unable to register with the core\n");
- debugfs_remove(mondir);
- return -ENODEV;
+ rc = -ENODEV;
+ goto err_reg;
}
// MOD_INC_USE_COUNT(which_module?);
@@ -361,10 +352,17 @@ static int __init mon_init(void)
mutex_lock(&usb_bus_list_lock);
list_for_each_entry (ubus, &usb_bus_list, bus_list) {
- mon_bus_init(mondir, ubus);
+ mon_bus_init(ubus);
}
mutex_unlock(&usb_bus_list_lock);
return 0;
+
+err_reg:
+ mon_bin_exit();
+err_bin:
+ mon_text_exit();
+err_text:
+ return rc;
}
static void __exit mon_exit(void)
@@ -381,8 +379,8 @@ static void __exit mon_exit(void)
mbus = list_entry(p, struct mon_bus, bus_link);
list_del(p);
- debugfs_remove(mbus->dent_t);
- debugfs_remove(mbus->dent_s);
+ if (mbus->text_inited)
+ mon_text_del(mbus);
/*
* This never happens, because the open/close paths in
@@ -401,7 +399,8 @@ static void __exit mon_exit(void)
}
mutex_unlock(&mon_lock);
- debugfs_remove(mon_dir);
+ mon_text_exit();
+ mon_bin_exit();
}
module_init(mon_init);
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 05cf2c9a8f8..d38a1279d9d 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -9,6 +9,7 @@
#include <linux/usb.h>
#include <linux/time.h>
#include <linux/mutex.h>
+#include <linux/debugfs.h>
#include <asm/uaccess.h>
#include "usb_mon.h"
@@ -63,6 +64,8 @@ struct mon_reader_text {
char slab_name[SLAB_NAME_SZ];
};
+static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */
+
static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
/*
@@ -436,7 +439,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
return 0;
}
-const struct file_operations mon_fops_text = {
+static const struct file_operations mon_fops_text = {
.owner = THIS_MODULE,
.open = mon_text_open,
.llseek = no_llseek,
@@ -447,6 +450,47 @@ const struct file_operations mon_fops_text = {
.release = mon_text_release,
};
+int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+{
+ struct dentry *d;
+ enum { NAMESZ = 10 };
+ char name[NAMESZ];
+ int rc;
+
+ rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+ if (rc <= 0 || rc >= NAMESZ)
+ goto err_print_t;
+ d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text);
+ if (d == NULL)
+ goto err_create_t;
+ mbus->dent_t = d;
+
+ /* XXX The stats do not belong to here (text API), but oh well... */
+ rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+ if (rc <= 0 || rc >= NAMESZ)
+ goto err_print_s;
+ d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
+ if (d == NULL)
+ goto err_create_s;
+ mbus->dent_s = d;
+
+ return 1;
+
+err_create_s:
+err_print_s:
+ debugfs_remove(mbus->dent_t);
+ mbus->dent_t = NULL;
+err_create_t:
+err_print_t:
+ return 0;
+}
+
+void mon_text_del(struct mon_bus *mbus)
+{
+ debugfs_remove(mbus->dent_t);
+ debugfs_remove(mbus->dent_s);
+}
+
/*
* Slab interface: constructor.
*/
@@ -459,3 +503,24 @@ static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sfla
memset(mem, 0xe5, sizeof(struct mon_event_text));
}
+int __init mon_text_init(void)
+{
+ struct dentry *mondir;
+
+ mondir = debugfs_create_dir("usbmon", NULL);
+ if (IS_ERR(mondir)) {
+ printk(KERN_NOTICE TAG ": debugfs is not available\n");
+ return -ENODEV;
+ }
+ if (mondir == NULL) {
+ printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
+ return -ENODEV;
+ }
+ mon_dir = mondir;
+ return 0;
+}
+
+void __exit mon_text_exit(void)
+{
+ debugfs_remove(mon_dir);
+}
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index ab9d02d5df7..4f949ce8a7f 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -17,9 +17,11 @@
struct mon_bus {
struct list_head bus_link;
spinlock_t lock;
+ struct usb_bus *u_bus;
+
+ int text_inited;
struct dentry *dent_s; /* Debugging file */
struct dentry *dent_t; /* Text interface file */
- struct usb_bus *u_bus;
int uses_dma;
/* Ref */
@@ -48,13 +50,35 @@ struct mon_reader {
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
+struct mon_bus *mon_bus_lookup(unsigned int num);
+
+int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+void mon_text_del(struct mon_bus *mbus);
+// void mon_bin_add(struct mon_bus *);
+
+int __init mon_text_init(void);
+void __exit mon_text_exit(void);
+int __init mon_bin_init(void);
+void __exit mon_bin_exit(void);
+
/*
- */
+ * DMA interface.
+ *
+ * XXX The vectored side needs a serious re-thinking. Abstracting vectors,
+ * like in Paolo's original patch, produces a double pkmap. We need an idea.
+*/
extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
+struct mon_reader_bin;
+extern void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+ unsigned int offset, dma_addr_t dma_addr, unsigned int len);
+extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp,
+ unsigned int offset, const unsigned char *from, unsigned int len);
+
+/*
+ */
extern struct mutex mon_lock;
-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 e081836014a..a2b94ef512b 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -222,13 +222,15 @@ config USB_NET_MCS7830
adapters marketed under the DeLOCK brand.
config USB_NET_RNDIS_HOST
- tristate "Host for RNDIS devices (EXPERIMENTAL)"
+ tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
depends on USB_USBNET && EXPERIMENTAL
select USB_NET_CDCETHER
help
This option enables hosting "Remote NDIS" USB networking links,
as encouraged by Microsoft (instead of CDC Ethernet!) for use in
- various devices that may only support this protocol.
+ various devices that may only support this protocol. A variant
+ of this protocol (with even less public documentation) seems to
+ be at the root of Microsoft's "ActiveSync" too.
Avoid using this protocol unless you have no better options.
The protocol specification is incomplete, and is controlled by
diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c
index 95e682e2c9d..4206df2d61b 100644
--- a/drivers/usb/net/asix.c
+++ b/drivers/usb/net/asix.c
@@ -898,7 +898,7 @@ static int ax88772_link_reset(struct usbnet *dev)
static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
{
- int ret;
+ int ret, embd_phy;
void *buf;
u16 rx_ctl;
struct asix_data *data = (struct asix_data *)&dev->data;
@@ -919,13 +919,15 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0)
goto out2;
+ /* 0x10 is the phy id of the embedded 10/100 ethernet phy */
+ embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);
if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
- 0x0000, 0, 0, buf)) < 0) {
+ embd_phy, 0, 0, buf)) < 0) {
dbg("Select PHY #1 failed: %d", ret);
goto out2;
}
- if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD)) < 0)
+ if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL)) < 0)
goto out2;
msleep(150);
@@ -933,8 +935,14 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
goto out2;
msleep(150);
- if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0)
- goto out2;
+ if (embd_phy) {
+ if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL)) < 0)
+ goto out2;
+ }
+ else {
+ if ((ret = asix_sw_reset(dev, AX_SWRESET_PRTE)) < 0)
+ goto out2;
+ }
msleep(150);
rx_ctl = asix_read_rx_ctl(dev);
@@ -1441,6 +1449,10 @@ static const struct usb_device_id products [] = {
// Linksys USB1000
USB_DEVICE (0x1737, 0x0039),
.driver_info = (unsigned long) &ax88178_info,
+}, {
+ // IO-DATA ETG-US2
+ USB_DEVICE (0x04bb, 0x0930),
+ .driver_info = (unsigned long) &ax88178_info,
},
{ }, // END
};
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c
index 44a91547146..e5cdafa258d 100644
--- a/drivers/usb/net/cdc_ether.c
+++ b/drivers/usb/net/cdc_ether.c
@@ -1,6 +1,7 @@
/*
* CDC Ethernet based networking peripherals
* Copyright (C) 2003-2005 by David Brownell
+ * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,6 +36,29 @@
#include "usbnet.h"
+#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_COMM
+ && desc->bInterfaceSubClass == 2
+ && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_MISC
+ && desc->bInterfaceSubClass == 1
+ && desc->bInterfaceProtocol == 1;
+}
+
+#else
+
+#define is_rndis(desc) 0
+#define is_activesync(desc) 0
+
+#endif
+
/*
* probes control interface, claims data interface, collects the bulk
* endpoints, activates data interface (if needed), maybe sets MTU.
@@ -71,7 +95,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
/* this assumes that if there's a non-RNDIS vendor variant
* of cdc-acm, it'll fail RNDIS requests cleanly.
*/
- rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
+ rndis = is_rndis(&intf->cur_altsetting->desc)
+ || is_activesync(&intf->cur_altsetting->desc);
memset(info, 0, sizeof *info);
info->control = intf;
@@ -99,6 +124,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
goto bad_desc;
}
break;
+ case USB_CDC_ACM_TYPE:
+ /* paranoia: disambiguate a "real" vendor-specific
+ * modem interface from an RNDIS non-modem.
+ */
+ if (rndis) {
+ struct usb_cdc_acm_descriptor *d;
+
+ d = (void *) buf;
+ if (d->bmCapabilities) {
+ dev_dbg(&intf->dev,
+ "ACM capabilities %02x, "
+ "not really RNDIS?\n",
+ d->bmCapabilities);
+ goto bad_desc;
+ }
+ }
+ break;
case USB_CDC_UNION_TYPE:
if (info->u) {
dev_dbg(&intf->dev, "extra CDC union\n");
@@ -171,7 +213,21 @@ next_desc:
buf += buf [0];
}
- if (!info->header || !info->u || (!rndis && !info->ether)) {
+ /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
+ * so we'll hard-wire the interfaces and not check for descriptors.
+ */
+ if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
+ info->control = usb_ifnum_to_if(dev->udev, 0);
+ info->data = usb_ifnum_to_if(dev->udev, 1);
+ if (!info->control || !info->data) {
+ dev_dbg(&intf->dev,
+ "activesync: master #0/%p slave #1/%p\n",
+ info->control,
+ info->data);
+ goto bad_desc;
+ }
+
+ } else if (!info->header || !info->u || (!rndis && !info->ether)) {
dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
info->header ? "" : "header ",
info->u ? "" : "union ",
diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c
index a3242be2195..31e5fe363fd 100644
--- a/drivers/usb/net/gl620a.c
+++ b/drivers/usb/net/gl620a.c
@@ -70,184 +70,29 @@
(((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
struct gl_packet {
- u32 packet_length;
+ __le32 packet_length;
char packet_data [1];
};
struct gl_header {
- u32 packet_count;
+ __le32 packet_count;
struct gl_packet packets;
};
-#ifdef GENELINK_ACK
-
-// FIXME: this code is incomplete, not debugged; it doesn't
-// handle interrupts correctly; it should use the generic
-// status IRQ code (which didn't exist back in 2001).
-
-struct gl_priv {
- struct urb *irq_urb;
- char irq_buf [INTERRUPT_BUFSIZE];
-};
-
-static inline int gl_control_write(struct usbnet *dev, u8 request, u16 value)
-{
- int retval;
-
- retval = usb_control_msg(dev->udev,
- usb_sndctrlpipe(dev->udev, 0),
- request,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- value,
- 0, // index
- 0, // data buffer
- 0, // size
- USB_CTRL_SET_TIMEOUT);
- return retval;
-}
-
-static void gl_interrupt_complete(struct urb *urb)
-{
- int status = urb->status;
-
- switch (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__, status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
- }
-
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
- err("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, status);
-}
-
-static int gl_interrupt_read(struct usbnet *dev)
-{
- struct gl_priv *priv = dev->priv_data;
- int retval;
-
- // issue usb interrupt read
- if (priv && priv->irq_urb) {
- // submit urb
- if ((retval = usb_submit_urb(priv->irq_urb, GFP_KERNEL)) != 0)
- dbg("gl_interrupt_read: submit fail - %X...", retval);
- else
- dbg("gl_interrupt_read: submit success...");
- }
-
- return 0;
-}
-
-// check whether another side is connected
-static int genelink_check_connect(struct usbnet *dev)
-{
- int retval;
-
- dbg("genelink_check_connect...");
-
- // detect whether another side is connected
- if ((retval = gl_control_write(dev, GENELINK_CONNECT_WRITE, 0)) != 0) {
- dbg("%s: genelink_check_connect write fail - %X",
- dev->net->name, retval);
- return retval;
- }
-
- // usb interrupt read to ack another side
- if ((retval = gl_interrupt_read(dev)) != 0) {
- dbg("%s: genelink_check_connect read fail - %X",
- dev->net->name, retval);
- return retval;
- }
-
- dbg("%s: genelink_check_connect read success", dev->net->name);
- return 0;
-}
-
-// allocate and initialize the private data for genelink
-static int genelink_init(struct usbnet *dev)
-{
- struct gl_priv *priv;
-
- // allocate the private data structure
- if ((priv = kmalloc(sizeof *priv, GFP_KERNEL)) == 0) {
- dbg("%s: cannot allocate private data per device",
- dev->net->name);
- return -ENOMEM;
- }
-
- // allocate irq urb
- if ((priv->irq_urb = usb_alloc_urb(0, GFP_KERNEL)) == 0) {
- dbg("%s: cannot allocate private irq urb per device",
- dev->net->name);
- kfree(priv);
- return -ENOMEM;
- }
-
- // fill irq urb
- usb_fill_int_urb(priv->irq_urb, dev->udev,
- usb_rcvintpipe(dev->udev, GENELINK_INTERRUPT_PIPE),
- priv->irq_buf, INTERRUPT_BUFSIZE,
- gl_interrupt_complete, 0,
- GENELINK_INTERRUPT_INTERVAL);
-
- // set private data pointer
- dev->priv_data = priv;
-
- return 0;
-}
-
-// release the private data
-static int genelink_free(struct usbnet *dev)
-{
- struct gl_priv *priv = dev->priv_data;
-
- if (!priv)
- return 0;
-
-// FIXME: can't cancel here; it's synchronous, and
-// should have happened earlier in any case (interrupt
-// handling needs to be generic)
-
- // cancel irq urb first
- usb_kill_urb(priv->irq_urb);
-
- // free irq urb
- usb_free_urb(priv->irq_urb);
-
- // free the private data structure
- kfree(priv);
-
- return 0;
-}
-
-#endif
-
static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
struct gl_header *header;
struct gl_packet *packet;
struct sk_buff *gl_skb;
u32 size;
+ u32 count;
header = (struct gl_header *) skb->data;
// get the packet count of the received skb
- le32_to_cpus(&header->packet_count);
- if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS)
- || (header->packet_count < 0)) {
- dbg("genelink: invalid received packet count %d",
- header->packet_count);
+ count = le32_to_cpu(header->packet_count);
+ if (count > GL_MAX_TRANSMIT_PACKETS) {
+ dbg("genelink: invalid received packet count %u", count);
return 0;
}
@@ -257,7 +102,7 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
// decrement the length for the packet count size 4 bytes
skb_pull(skb, 4);
- while (header->packet_count > 1) {
+ while (count > 1) {
// get the packet length
size = le32_to_cpu(packet->packet_length);
@@ -278,9 +123,8 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
}
// advance to the next packet
- packet = (struct gl_packet *)
- &packet->packet_data [size];
- header->packet_count--;
+ packet = (struct gl_packet *)&packet->packet_data[size];
+ count--;
// shift the data pointer to the next gl_packet
skb_pull(skb, size + 4);
@@ -303,8 +147,8 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
int length = skb->len;
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
- u32 *packet_count;
- u32 *packet_len;
+ __le32 *packet_count;
+ __le32 *packet_len;
// FIXME: magic numbers, bleech
padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
@@ -326,7 +170,7 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
}
// attach the packet count to the header
- packet_count = (u32 *) skb_push(skb, (4 + 4*1));
+ packet_count = (__le32 *) skb_push(skb, (4 + 4*1));
packet_len = packet_count + 1;
*packet_count = cpu_to_le32(1);
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index fa78326d0bf..36a989160a6 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = {
.suspend = kaweth_suspend,
.resume = kaweth_resume,
.id_table = usb_klsi_table,
+ .supports_autosuspend = 1,
};
typedef __u8 eth_addr_t[6];
@@ -225,6 +226,7 @@ struct kaweth_device
struct delayed_work lowmem_work;
struct usb_device *dev;
+ struct usb_interface *intf;
struct net_device *net;
wait_queue_head_t term_wait;
@@ -662,9 +664,14 @@ static int kaweth_open(struct net_device *net)
dbg("Opening network device.");
+ res = usb_autopm_get_interface(kaweth->intf);
+ if (res) {
+ err("Interface cannot be resumed.");
+ return -EIO;
+ }
res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
if (res)
- return -EIO;
+ goto err_out;
usb_fill_int_urb(
kaweth->irq_urb,
@@ -681,7 +688,7 @@ static int kaweth_open(struct net_device *net)
res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
if (res) {
usb_kill_urb(kaweth->rx_urb);
- return -EIO;
+ goto err_out;
}
kaweth->opened = 1;
@@ -689,10 +696,14 @@ static int kaweth_open(struct net_device *net)
kaweth_async_set_rx_mode(kaweth);
return 0;
+
+err_out:
+ usb_autopm_enable(kaweth->intf);
+ return -EIO;
}
/****************************************************************
- * kaweth_close
+ * kaweth_kill_urbs
****************************************************************/
static void kaweth_kill_urbs(struct kaweth_device *kaweth)
{
@@ -724,17 +735,29 @@ static int kaweth_close(struct net_device *net)
kaweth->status &= ~KAWETH_STATUS_CLOSING;
+ usb_autopm_enable(kaweth->intf);
+
return 0;
}
static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
+ struct kaweth_device *kaweth = netdev_priv(dev);
strlcpy(info->driver, driver_name, sizeof(info->driver));
+ usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
+}
+
+static u32 kaweth_get_link(struct net_device *dev)
+{
+ struct kaweth_device *kaweth = netdev_priv(dev);
+
+ return kaweth->linkstate;
}
static struct ethtool_ops ops = {
- .get_drvinfo = kaweth_get_drvinfo
+ .get_drvinfo = kaweth_get_drvinfo,
+ .get_link = kaweth_get_link
};
/****************************************************************
@@ -908,6 +931,7 @@ static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
+ dbg("Suspending device");
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status |= KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -924,6 +948,7 @@ static int kaweth_resume(struct usb_interface *intf)
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
+ dbg("Resuming device");
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -1086,6 +1111,8 @@ err_fw:
dbg("Initializing net device.");
+ kaweth->intf = intf;
+
kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kaweth->tx_urb)
goto err_free_netdev;
@@ -1265,7 +1292,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
{
struct urb *urb;
int retv;
- int length;
+ int length = 0; /* shut up GCC */
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index 98f6898cae1..c7467823cd1 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -214,9 +214,9 @@ PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
+PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004,
DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d,
+PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
DEFAULT_GPIO_RESET )
diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c
index 99f26b3e502..be888d2d813 100644
--- a/drivers/usb/net/rndis_host.c
+++ b/drivers/usb/net/rndis_host.c
@@ -49,6 +49,8 @@
* - In some cases, MS-Windows will emit undocumented requests; this
* matters more to peripheral implementations than host ones.
*
+ * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync".
+ *
* For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
* favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
* currently rare) "Ethernet Emulation Model" (EEM).
@@ -61,6 +63,9 @@
* - control-in: GET_ENCAPSULATED
*
* We'll try to ignore the RESPONSE_AVAILABLE notifications.
+ *
+ * REVISIT some RNDIS implementations seem to have curious issues still
+ * to be resolved.
*/
struct rndis_msg_hdr {
__le32 msg_type; /* RNDIS_MSG_* */
@@ -71,8 +76,14 @@ struct rndis_msg_hdr {
// ... and more
} __attribute__ ((packed));
-/* RNDIS defines this (absurdly huge) control timeout */
-#define RNDIS_CONTROL_TIMEOUT_MS (10 * 1000)
+/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
+#define CONTROL_BUFFER_SIZE 1025
+
+/* RNDIS defines an (absurdly huge) 10 second control timeout,
+ * but ActiveSync seems to use a more usual 5 second timeout
+ * (which matches the USB 2.0 spec).
+ */
+#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000)
#define ccpu2 __constant_cpu_to_le32
@@ -270,6 +281,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb)
static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
{
struct cdc_state *info = (void *) &dev->data;
+ int master_ifnum;
int retval;
unsigned count;
__le32 rsp;
@@ -279,7 +291,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
* disconnect(): either serialize, or dispatch responses on xid
*/
- /* Issue the request; don't bother byteswapping our xid */
+ /* Issue the request; xid is unique, don't bother byteswapping it */
if (likely(buf->msg_type != RNDIS_MSG_HALT
&& buf->msg_type != RNDIS_MSG_RESET)) {
xid = dev->xid++;
@@ -287,11 +299,12 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
xid = dev->xid++;
buf->request_id = (__force __le32) xid;
}
+ master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber;
retval = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, info->u->bMasterInterface0,
+ 0, master_ifnum,
buf, le32_to_cpu(buf->msg_len),
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0 || xid == 0))
@@ -306,13 +319,13 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
*/
rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
for (count = 0; count < 10; count++) {
- memset(buf, 0, 1024);
+ memset(buf, 0, CONTROL_BUFFER_SIZE);
retval = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
USB_CDC_GET_ENCAPSULATED_RESPONSE,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, info->u->bMasterInterface0,
- buf, 1024,
+ 0, master_ifnum,
+ buf, CONTROL_BUFFER_SIZE,
RNDIS_CONTROL_TIMEOUT_MS);
if (likely(retval >= 8)) {
msg_len = le32_to_cpu(buf->msg_len);
@@ -350,7 +363,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, info->u->bMasterInterface0,
+ 0, master_ifnum,
msg, sizeof *msg,
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0))
@@ -379,6 +392,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
{
int retval;
struct net_device *net = dev->net;
+ struct cdc_state *info = (void *) &dev->data;
union {
void *buf;
struct rndis_msg_hdr *header;
@@ -392,54 +406,77 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
u32 tmp;
/* we can't rely on i/o from stack working, or stack allocation */
- u.buf = kmalloc(1024, GFP_KERNEL);
+ u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
if (!u.buf)
return -ENOMEM;
retval = usbnet_generic_cdc_bind(dev, intf);
if (retval < 0)
- goto done;
-
- net->hard_header_len += sizeof (struct rndis_data_hdr);
+ goto fail;
- /* initialize; max transfer is 16KB at full speed */
u.init->msg_type = RNDIS_MSG_INIT;
u.init->msg_len = ccpu2(sizeof *u.init);
u.init->major_version = ccpu2(1);
u.init->minor_version = ccpu2(0);
- u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
+ /* max transfer (in spec) is 0x4000 at full speed, but for
+ * TX we'll stick to one Ethernet packet plus RNDIS framing.
+ * For RX we handle drivers that zero-pad to end-of-packet.
+ * Don't let userspace change these settings.
+ */
+ net->hard_header_len += sizeof (struct rndis_data_hdr);
+ dev->hard_mtu = net->mtu + net->hard_header_len;
+
+ dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
+ dev->rx_urb_size &= ~(dev->maxpacket - 1);
+ u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
+
+ net->change_mtu = NULL;
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
/* it might not even be an RNDIS device!! */
dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
-fail:
- usb_driver_release_interface(driver_of(intf),
- ((struct cdc_state *)&(dev->data))->data);
- goto done;
+ goto fail_and_release;
}
- dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
+ tmp = le32_to_cpu(u.init_c->max_transfer_size);
+ if (tmp < dev->hard_mtu) {
+ dev_err(&intf->dev,
+ "dev can't take %u byte packets (max %u)\n",
+ dev->hard_mtu, tmp);
+ goto fail_and_release;
+ }
+
/* REVISIT: peripheral "alignment" request is ignored ... */
- dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
+ dev_dbg(&intf->dev,
+ "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
+ dev->hard_mtu, tmp, dev->rx_urb_size,
1 << le32_to_cpu(u.init_c->packet_alignment));
- /* get designated host ethernet address */
- memset(u.get, 0, sizeof *u.get);
+ /* Get designated host ethernet address.
+ *
+ * Adding a payload exactly the same size as the expected response
+ * payload is an evident requirement MSFT added for ActiveSync.
+ * This undocumented (and nonsensical) issue was found by sniffing
+ * protocol requests from the ActiveSync 4.1 Windows driver.
+ */
+ memset(u.get, 0, sizeof *u.get + 48);
u.get->msg_type = RNDIS_MSG_QUERY;
- u.get->msg_len = ccpu2(sizeof *u.get);
+ u.get->msg_len = ccpu2(sizeof *u.get + 48);
u.get->oid = OID_802_3_PERMANENT_ADDRESS;
+ u.get->len = ccpu2(48);
+ u.get->offset = ccpu2(20);
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
- goto fail;
+ goto fail_and_release;
}
tmp = le32_to_cpu(u.get_c->offset);
- if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
+ if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
|| u.get_c->len != ccpu2(ETH_ALEN))) {
dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
tmp, le32_to_cpu(u.get_c->len));
retval = -EDOM;
- goto fail;
+ goto fail_and_release;
}
memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN);
@@ -455,11 +492,18 @@ fail:
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
- goto fail;
+ goto fail_and_release;
}
retval = 0;
-done:
+
+ kfree(u.buf);
+ return retval;
+
+fail_and_release:
+ usb_set_intfdata(info->data, NULL);
+ usb_driver_release_interface(driver_of(intf), info->data);
+fail:
kfree(u.buf);
return retval;
}
@@ -469,7 +513,7 @@ static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
struct rndis_halt *halt;
/* try to clear any rndis state/activity (no i/o from stack!) */
- halt = kcalloc(1, sizeof *halt, GFP_KERNEL);
+ halt = kzalloc(sizeof *halt, GFP_KERNEL);
if (halt) {
halt->msg_type = RNDIS_MSG_HALT;
halt->msg_len = ccpu2(sizeof *halt);
@@ -593,6 +637,10 @@ static const struct usb_device_id products [] = {
/* RNDIS is MSFT's un-official variant of CDC ACM */
USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
.driver_info = (unsigned long) &rndis_info,
+}, {
+ /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
+ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
+ .driver_info = (unsigned long) &rndis_info,
},
{ }, // END
};
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index c54235f73cb..670262a38a0 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -124,10 +124,11 @@
#define RX_URB_FAIL 3
/* Define these values to match your device */
-#define VENDOR_ID_REALTEK 0x0bda
+#define VENDOR_ID_REALTEK 0x0bda
#define VENDOR_ID_MELCO 0x0411
-#define VENDOR_ID_MICRONET 0x3980
+#define VENDOR_ID_MICRONET 0x3980
#define VENDOR_ID_LONGSHINE 0x07b8
+#define VENDOR_ID_OQO 0x1557
#define VENDOR_ID_ZYXEL 0x0586
#define PRODUCT_ID_RTL8150 0x8150
@@ -144,6 +145,7 @@ static struct usb_device_id rtl8150_table[] = {
{USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)},
{USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)},
{USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)},
+ {USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150)},
{USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)},
{}
};
@@ -282,7 +284,8 @@ static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
u8 data[3], tmp;
data[0] = phy;
- *(data + 1) = cpu_to_le16p(&reg);
+ data[1] = reg & 0xff;
+ data[2] = (reg >> 8) & 0xff;
tmp = indx | PHY_WRITE | PHY_GO;
i = 0;
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 86bcf63b6ba..11dad42c3c6 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -572,8 +572,20 @@ static void aircable_unthrottle(struct usb_serial_port *port)
schedule_work(&priv->rx_work);
}
+static struct usb_driver aircable_driver = {
+ .name = "aircable",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver aircable_device = {
- .description = "aircable",
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "aircable",
+ },
+ .usb_driver = &aircable_driver,
.id_table = id_table,
.num_ports = 1,
.attach = aircable_attach,
@@ -587,13 +599,6 @@ static struct usb_serial_driver aircable_device = {
.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;
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 96c73726d74..0af42e32fa0 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -19,8 +19,11 @@
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
{ USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
+ { USB_DEVICE(0x1410, 0x1130) }, /* Novatel Wireless S720 CDMA/EV-DO */
+ { USB_DEVICE(0x1410, 0x2110) }, /* Novatel Wireless U720 CDMA/EV-DO */
{ USB_DEVICE(0x1410, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */
{ USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */
+ { USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
@@ -274,6 +277,7 @@ static struct usb_serial_driver airprime_device = {
.owner = THIS_MODULE,
.name = "airprime",
},
+ .usb_driver = &airprime_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 863966c1c5a..edd685791a6 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -156,7 +156,7 @@ cleanup:
}
static void ark3116_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
struct ark3116_private *priv = usb_get_serial_port_data(port);
@@ -326,7 +326,7 @@ static void ark3116_set_termios(struct usb_serial_port *port,
static int ark3116_open(struct usb_serial_port *port, struct file *filp)
{
- struct termios tmp_termios;
+ struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
char *buf;
int result = 0;
@@ -444,6 +444,7 @@ static struct usb_driver ark3116_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
+ .no_dynamic_id = 1,
};
static struct usb_serial_driver ark3116_device = {
@@ -452,6 +453,7 @@ static struct usb_serial_driver ark3116_device = {
.name = "ark3116",
},
.id_table = id_table,
+ .usb_driver = &ark3116_driver,
.num_interrupt_in = 1,
.num_bulk_in = 1,
.num_bulk_out = 1,
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 8835bb58ca9..3b800d277c4 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -92,7 +92,7 @@ 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);
-static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old);
+static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios * 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 );
static int belkin_sa_tiocmget (struct usb_serial_port *port, struct file *file);
@@ -126,6 +126,7 @@ static struct usb_serial_driver belkin_device = {
.name = "belkin",
},
.description = "Belkin / Peracom / GoHubs USB Serial Adapter",
+ .usb_driver = &belkin_driver,
.id_table = id_table_combined,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -333,7 +334,7 @@ exit:
__FUNCTION__, retval);
}
-static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
struct belkin_sa_private *priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 6542f220468..c08a38402b9 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -103,11 +103,52 @@ exit:
return retval;
}
+#ifdef CONFIG_HOTPLUG
+static ssize_t store_new_id(struct device_driver *driver,
+ const char *buf, size_t count)
+{
+ struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+ ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+
+ if (retval >= 0 && usb_drv->usb_driver != NULL)
+ retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
+ &usb_drv->usb_driver->drvwrap.driver,
+ buf, count);
+ return retval;
+}
+
+static struct driver_attribute drv_attrs[] = {
+ __ATTR(new_id, S_IWUSR, NULL, store_new_id),
+ __ATTR_NULL,
+};
+
+static void free_dynids(struct usb_serial_driver *drv)
+{
+ struct usb_dynid *dynid, *n;
+
+ spin_lock(&drv->dynids.lock);
+ list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+ list_del(&dynid->node);
+ kfree(dynid);
+ }
+ spin_unlock(&drv->dynids.lock);
+}
+
+#else
+static struct driver_attribute drv_attrs[] = {
+ __ATTR_NULL,
+};
+static inline void free_dynids(struct usb_driver *drv)
+{
+}
+#endif
+
struct bus_type usb_serial_bus_type = {
.name = "usb-serial",
.match = usb_serial_device_match,
.probe = usb_serial_device_probe,
.remove = usb_serial_device_remove,
+ .drv_attrs = drv_attrs,
};
int usb_serial_bus_register(struct usb_serial_driver *driver)
@@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
int retval;
driver->driver.bus = &usb_serial_bus_type;
+ spin_lock_init(&driver->dynids.lock);
+ INIT_LIST_HEAD(&driver->dynids.list);
+
retval = driver_register(&driver->driver);
return retval;
@@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
void usb_serial_bus_deregister(struct usb_serial_driver *driver)
{
+ free_dynids(driver);
driver_unregister(&driver->driver);
}
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 7167728d764..9386e216d68 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -65,7 +65,7 @@ static int usb_console_setup(struct console *co, char *options)
struct usb_serial_port *port;
int retval = 0;
struct tty_struct *tty;
- struct termios *termios;
+ struct ktermios *termios;
dbg ("%s", __FUNCTION__);
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index f95d42c0d16..3ec24870bca 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -41,7 +41,7 @@ static int cp2101_open(struct usb_serial_port*, struct file*);
static void cp2101_cleanup(struct usb_serial_port*);
static void cp2101_close(struct usb_serial_port*, struct file*);
static void cp2101_get_termios(struct usb_serial_port*);
-static void cp2101_set_termios(struct usb_serial_port*, struct termios*);
+static void cp2101_set_termios(struct usb_serial_port*, struct ktermios*);
static int cp2101_tiocmget (struct usb_serial_port *, struct file *);
static int cp2101_tiocmset (struct usb_serial_port *, struct file *,
unsigned int, unsigned int);
@@ -69,6 +69,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
+ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ } /* Terminating Entry */
};
@@ -88,6 +89,7 @@ static struct usb_serial_driver cp2101_device = {
.owner = THIS_MODULE,
.name = "cp2101",
},
+ .usb_driver = &cp2101_driver,
.id_table = id_table,
.num_interrupt_in = 0,
.num_bulk_in = 0,
@@ -168,13 +170,13 @@ static int cp2101_get_config(struct usb_serial_port* port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
- u32 *buf;
+ __le32 *buf;
int result, i, length;
/* Number of integers required to contain the array */
length = (((size - 1) | 3) + 1)/4;
- buf = kcalloc(length, sizeof(u32), GFP_KERNEL);
+ buf = kcalloc(length, sizeof(__le32), GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
return -ENOMEM;
@@ -214,13 +216,13 @@ static int cp2101_set_config(struct usb_serial_port* port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
- u32 *buf;
+ __le32 *buf;
int result, i, length;
/* Number of integers required to contain the array */
length = (((size - 1) | 3) + 1)/4;
- buf = kmalloc(length * sizeof(u32), GFP_KERNEL);
+ buf = kmalloc(length * sizeof(__le32), GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n",
__FUNCTION__);
@@ -506,7 +508,7 @@ static void cp2101_get_termios (struct usb_serial_port *port)
}
static void cp2101_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
unsigned int cflag, old_cflag=0;
int baud=0, bits;
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index a63c3286caa..4167753ed31 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -88,6 +88,7 @@ static struct usb_serial_driver cyberjack_device = {
.name = "cyberjack",
},
.description = "Reiner SCT Cyberjack USB card reader",
+ .usb_driver = &cyberjack_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -98,7 +99,7 @@ static struct usb_serial_driver cyberjack_device = {
.open = cyberjack_open,
.close = cyberjack_close,
.write = cyberjack_write,
- .write_room = cyberjack_write_room,
+ .write_room = cyberjack_write_room,
.read_int_callback = cyberjack_read_int_callback,
.read_bulk_callback = cyberjack_read_bulk_callback,
.write_bulk_callback = cyberjack_write_bulk_callback,
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 093f303b318..57b8e27285f 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -143,7 +143,7 @@ struct cypress_private {
wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */
char prev_status, diff_status; /* used for TIOCMIWAIT */
/* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */
- struct termios tmp_termios; /* stores the old termios settings */
+ struct ktermios tmp_termios; /* stores the old termios settings */
};
/* write buffer structure */
@@ -165,7 +165,7 @@ static int cypress_write (struct usb_serial_port *port, const unsigned char *b
static void cypress_send (struct usb_serial_port *port);
static int cypress_write_room (struct usb_serial_port *port);
static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void cypress_set_termios (struct usb_serial_port *port, struct termios * old);
+static void cypress_set_termios (struct usb_serial_port *port, struct ktermios * old);
static int cypress_tiocmget (struct usb_serial_port *port, struct file *file);
static int cypress_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
static int cypress_chars_in_buffer (struct usb_serial_port *port);
@@ -193,6 +193,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
.name = "earthmate",
},
.description = "DeLorme Earthmate USB",
+ .usb_driver = &cypress_driver,
.id_table = id_table_earthmate,
.num_interrupt_in = 1,
.num_interrupt_out = 1,
@@ -222,6 +223,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
.name = "cyphidcom",
},
.description = "HID->COM RS232 Adapter",
+ .usb_driver = &cypress_driver,
.id_table = id_table_cyphidcomrs232,
.num_interrupt_in = 1,
.num_interrupt_out = 1,
@@ -251,6 +253,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.name = "nokiaca42v2",
},
.description = "Nokia CA-42 V2 Adapter",
+ .usb_driver = &cypress_driver,
.id_table = id_table_nokiaca42v2,
.num_interrupt_in = 1,
.num_interrupt_out = 1,
@@ -949,28 +952,13 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi
switch (cmd) {
case TIOCGSERIAL:
- if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) {
+ if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct ktermios))) {
return -EFAULT;
}
return (0);
break;
case TIOCSSERIAL:
- if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) {
- return -EFAULT;
- }
- /* here we need to call cypress_set_termios to invoke the new settings */
- cypress_set_termios(port, &priv->tmp_termios);
- return (0);
- break;
- /* these are called when setting baud rate from gpsd */
- case TCGETS:
- if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) {
- return -EFAULT;
- }
- return (0);
- break;
- case TCSETS:
- if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) {
+ if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct ktermios))) {
return -EFAULT;
}
/* here we need to call cypress_set_termios to invoke the new settings */
@@ -1019,7 +1007,7 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi
static void cypress_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
@@ -1493,7 +1481,7 @@ static struct cypress_buf *cypress_buf_alloc(unsigned int size)
if (size == 0)
return NULL;
- cb = (struct cypress_buf *)kmalloc(sizeof(struct cypress_buf), GFP_KERNEL);
+ cb = kmalloc(sizeof(struct cypress_buf), GFP_KERNEL);
if (cb == NULL)
return NULL;
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 83d0e21145b..0b0fb51bad3 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -449,7 +449,7 @@ static int digi_transmit_idle( struct usb_serial_port *port,
static void digi_rx_throttle (struct usb_serial_port *port);
static void digi_rx_unthrottle (struct usb_serial_port *port);
static void digi_set_termios( struct usb_serial_port *port,
- struct termios *old_termios );
+ struct ktermios *old_termios );
static void digi_break_ctl( struct usb_serial_port *port, int break_state );
static int digi_ioctl( struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg );
@@ -509,6 +509,7 @@ static struct usb_serial_driver digi_acceleport_2_device = {
.name = "digi_2",
},
.description = "Digi 2 port USB adapter",
+ .usb_driver = &digi_driver,
.id_table = id_table_2,
.num_interrupt_in = 0,
.num_bulk_in = 4,
@@ -538,6 +539,7 @@ static struct usb_serial_driver digi_acceleport_4_device = {
.name = "digi_4",
},
.description = "Digi 4 port USB adapter",
+ .usb_driver = &digi_driver,
.id_table = id_table_4,
.num_interrupt_in = 0,
.num_bulk_in = 5,
@@ -976,7 +978,7 @@ dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num );
static void digi_set_termios( struct usb_serial_port *port,
- struct termios *old_termios )
+ struct ktermios *old_termios )
{
struct digi_port *priv = usb_get_serial_port_data(port);
@@ -1463,7 +1465,7 @@ static int digi_open( struct usb_serial_port *port, struct file *filp )
int ret;
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
- struct termios not_termios;
+ struct ktermios not_termios;
unsigned long flags = 0;
@@ -1681,7 +1683,7 @@ dbg( "digi_startup: TOP" );
for( i=0; i<serial->type->num_ports+1; i++ ) {
/* allocate port private structure */
- priv = (struct digi_port *)kmalloc( sizeof(struct digi_port),
+ priv = kmalloc( sizeof(struct digi_port),
GFP_KERNEL );
if( priv == (struct digi_port *)0 ) {
while( --i >= 0 )
@@ -1714,7 +1716,7 @@ dbg( "digi_startup: TOP" );
}
/* allocate serial private structure */
- serial_priv = (struct digi_serial *)kmalloc( sizeof(struct digi_serial),
+ serial_priv = kmalloc( sizeof(struct digi_serial),
GFP_KERNEL );
if( serial_priv == (struct digi_serial *)0 ) {
for( i=0; i<serial->type->num_ports+1; i++ )
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 4ce10a83195..4703c8f8538 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -92,7 +92,7 @@ static int empeg_ioctl (struct usb_serial_port *port,
struct file * file,
unsigned int cmd,
unsigned long arg);
-static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static void empeg_write_bulk_callback (struct urb *urb);
static void empeg_read_bulk_callback (struct urb *urb);
@@ -117,6 +117,7 @@ static struct usb_serial_driver empeg_device = {
.name = "empeg",
},
.id_table = id_table,
+ .usb_driver = &empeg_driver,
.num_interrupt_in = 0,
.num_bulk_in = 1,
.num_bulk_out = 1,
@@ -442,7 +443,7 @@ static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsign
}
-static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
dbg("%s - port %d", __FUNCTION__, port->number);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 72e4d48f51e..4695952b647 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -452,6 +452,7 @@ static struct usb_device_id id_table_combined [] = {
{ 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, FTDI_CCSMACHX_2_PID) },
{ USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
{ USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
@@ -463,7 +464,6 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
{ USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
- { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
@@ -595,7 +595,7 @@ static int ftdi_chars_in_buffer (struct usb_serial_port *port);
static void ftdi_write_bulk_callback (struct urb *urb);
static void ftdi_read_bulk_callback (struct urb *urb);
static void ftdi_process_read (struct work_struct *work);
-static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old);
+static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios * old);
static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file);
static int ftdi_tiocmset (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear);
static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
@@ -614,6 +614,7 @@ static struct usb_serial_driver ftdi_sio_device = {
.name = "ftdi_sio",
},
.description = "FTDI USB Serial Device",
+ .usb_driver = &ftdi_driver ,
.id_table = id_table_combined,
.num_interrupt_in = 0,
.num_bulk_in = 1,
@@ -1880,7 +1881,7 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
* WARNING: set_termios calls this with old_termios in kernel space
*/
-static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{ /* ftdi_termios */
struct usb_device *dev = port->serial->dev;
unsigned int cflag = port->tty->termios->c_cflag;
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index bae117d359a..7eff1c03ba8 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -312,8 +312,9 @@
/* CCS Inc. ICDU/ICDU40 product ID - the FT232BM is used in an in-circuit-debugger */
/* unit for PIC16's/PIC18's */
-#define FTDI_CCSICDU20_0_PID 0xF9D0
-#define FTDI_CCSICDU40_1_PID 0xF9D1
+#define FTDI_CCSICDU20_0_PID 0xF9D0
+#define FTDI_CCSICDU40_1_PID 0xF9D1
+#define FTDI_CCSMACHX_2_PID 0xF9D2
/* Inside Accesso contactless reader (http://www.insidefr.com) */
#define INSIDE_ACCESSO 0xFAD0
@@ -363,7 +364,6 @@
* USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices
* and I'm not entirely sure which are used by which.
*/
-#define FTDI_4N_GALAXY_DE_0_PID 0x8372
#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0
#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 77b977206a8..4092f6dc9ef 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -14,6 +14,9 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#include <asm/uaccess.h>
+
+static int debug;
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1404, 0xcddc) },
@@ -21,6 +24,26 @@ static struct usb_device_id id_table [] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
+static int funsoft_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ktermios t;
+
+ dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd);
+
+ if (cmd == TCSETSF) {
+ if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg))
+ return -EFAULT;
+
+ dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__,
+ t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
+
+ if (!(t.c_lflag & ICANON))
+ return -EINVAL;
+ }
+ return -ENOIOCTLCMD;
+}
+
static struct usb_driver funsoft_driver = {
.name = "funsoft",
.probe = usb_serial_probe,
@@ -35,10 +58,12 @@ static struct usb_serial_driver funsoft_device = {
.name = "funsoft",
},
.id_table = id_table,
+ .usb_driver = &funsoft_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
+ .ioctl = funsoft_ioctl,
};
static int __init funsoft_init(void)
@@ -63,3 +88,6 @@ static void __exit funsoft_exit(void)
module_init(funsoft_init);
module_exit(funsoft_exit);
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/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 6530d391ebe..74660a3aa67 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1566,6 +1566,7 @@ static struct usb_serial_driver garmin_device = {
.name = "garmin_gps",
},
.description = "Garmin GPS usb/tty",
+ .usb_driver = &garmin_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 36042937e77..601e0648dec 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -20,6 +20,10 @@
#include <linux/usb/serial.h>
#include <asm/uaccess.h>
+static int generic_probe(struct usb_interface *interface,
+ const struct usb_device_id *id);
+
+
static int debug;
#ifdef CONFIG_USB_SERIAL_GENERIC
@@ -34,6 +38,21 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
+/* we want to look at all devices, as the vendor/product id can change
+ * depending on the command line argument */
+static struct usb_device_id generic_serial_ids[] = {
+ {.driver_info = 42},
+ {}
+};
+
+static struct usb_driver generic_driver = {
+ .name = "usbserial_generic",
+ .probe = generic_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = generic_serial_ids,
+ .no_dynamic_id = 1,
+};
+
/* All of the device info needed for the Generic Serial Converter */
struct usb_serial_driver usb_serial_generic_device = {
.driver = {
@@ -41,6 +60,7 @@ struct usb_serial_driver usb_serial_generic_device = {
.name = "generic",
},
.id_table = generic_device_ids,
+ .usb_driver = &generic_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
@@ -48,13 +68,6 @@ struct usb_serial_driver usb_serial_generic_device = {
.shutdown = usb_serial_generic_shutdown,
};
-/* we want to look at all devices, as the vendor/product id can change
- * depending on the command line argument */
-static struct usb_device_id generic_serial_ids[] = {
- {.driver_info = 42},
- {}
-};
-
static int generic_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@@ -65,14 +78,6 @@ static int generic_probe(struct usb_interface *interface,
return usb_serial_probe(interface, id);
return -ENODEV;
}
-
-static struct usb_driver generic_driver = {
- .name = "usbserial_generic",
- .probe = generic_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = generic_serial_ids,
- .no_dynamic_id = 1,
-};
#endif
int usb_serial_generic_register (int _debug)
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index ebcac701b06..6c6ebae741c 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -49,6 +49,7 @@ static struct usb_serial_driver hp49gp_device = {
.name = "hp4X",
},
.id_table = id_table,
+ .usb_driver = &hp49gp_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index d06547a13f2..6a26a2e683a 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -146,6 +146,8 @@ struct edgeport_serial {
struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */
struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */
struct edgeport_product_info product_info; /* Product Info */
+ struct edge_compatibility_descriptor epic_descriptor; /* Edgeport compatible descriptor */
+ int is_epic; /* flag if EPiC device or not */
__u8 interrupt_in_endpoint; /* the interrupt endpoint handle */
unsigned char * interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */
@@ -229,7 +231,7 @@ static int edge_write_room (struct usb_serial_port *port);
static int edge_chars_in_buffer (struct usb_serial_port *port);
static void edge_throttle (struct usb_serial_port *port);
static void edge_unthrottle (struct usb_serial_port *port);
-static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg);
static void edge_break (struct usb_serial_port *port, int break_state);
static int edge_tiocmget (struct usb_serial_port *port, struct file *file);
@@ -240,14 +242,6 @@ static void edge_shutdown (struct usb_serial *serial);
#include "io_tables.h" /* all of the devices that this driver supports */
-static struct usb_driver io_driver = {
- .name = "io_edgeport",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
- .no_dynamic_id = 1,
-};
-
/* function prototypes for all of our local functions */
static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3);
@@ -257,7 +251,7 @@ static void handle_new_lsr (struct edgeport_port *edge_port, __u8 lsrData, __u8
static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u8 param);
static int calc_baud_rate_divisor (int baud_rate, int *divisor);
static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate);
-static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios);
+static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios);
static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue);
static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer, int writeLength);
static void send_more_port_data (struct edgeport_serial *edge_serial, struct edgeport_port *edge_port);
@@ -397,6 +391,7 @@ static int get_string (struct usb_device *dev, int Id, char *string, int buflen)
unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2);
kfree(pStringDesc);
+ dbg("%s - USB String %s", __FUNCTION__, string);
return strlen(string);
}
@@ -434,6 +429,34 @@ static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_de
}
#endif
+static void dump_product_info(struct edgeport_product_info *product_info)
+{
+ // Dump Product Info structure
+ dbg("**Product Information:");
+ dbg(" ProductId %x", product_info->ProductId );
+ dbg(" NumPorts %d", product_info->NumPorts );
+ dbg(" ProdInfoVer %d", product_info->ProdInfoVer );
+ dbg(" IsServer %d", product_info->IsServer);
+ dbg(" IsRS232 %d", product_info->IsRS232 );
+ dbg(" IsRS422 %d", product_info->IsRS422 );
+ dbg(" IsRS485 %d", product_info->IsRS485 );
+ dbg(" RomSize %d", product_info->RomSize );
+ dbg(" RamSize %d", product_info->RamSize );
+ dbg(" CpuRev %x", product_info->CpuRev );
+ dbg(" BoardRev %x", product_info->BoardRev);
+ dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion,
+ product_info->BootMinorVersion,
+ le16_to_cpu(product_info->BootBuildNumber));
+ dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion,
+ product_info->FirmwareMinorVersion,
+ le16_to_cpu(product_info->FirmwareBuildNumber));
+ dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0],
+ product_info->ManufactureDescDate[1],
+ product_info->ManufactureDescDate[2]+1900);
+ dbg(" iDownloadFile 0x%x", product_info->iDownloadFile);
+ dbg(" EpicVer %d", product_info->EpicVer);
+}
+
static void get_product_info(struct edgeport_serial *edge_serial)
{
struct edgeport_product_info *product_info = &edge_serial->product_info;
@@ -495,30 +518,60 @@ static void get_product_info(struct edgeport_serial *edge_serial)
break;
}
- // Dump Product Info structure
- dbg("**Product Information:");
- dbg(" ProductId %x", product_info->ProductId );
- dbg(" NumPorts %d", product_info->NumPorts );
- dbg(" ProdInfoVer %d", product_info->ProdInfoVer );
- dbg(" IsServer %d", product_info->IsServer);
- dbg(" IsRS232 %d", product_info->IsRS232 );
- dbg(" IsRS422 %d", product_info->IsRS422 );
- dbg(" IsRS485 %d", product_info->IsRS485 );
- dbg(" RomSize %d", product_info->RomSize );
- dbg(" RamSize %d", product_info->RamSize );
- dbg(" CpuRev %x", product_info->CpuRev );
- dbg(" BoardRev %x", product_info->BoardRev);
- dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion,
- product_info->BootMinorVersion,
- le16_to_cpu(product_info->BootBuildNumber));
- dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion,
- product_info->FirmwareMinorVersion,
- le16_to_cpu(product_info->FirmwareBuildNumber));
- dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0],
- product_info->ManufactureDescDate[1],
- product_info->ManufactureDescDate[2]+1900);
- dbg(" iDownloadFile 0x%x", product_info->iDownloadFile);
+ dump_product_info(product_info);
+}
+static int get_epic_descriptor(struct edgeport_serial *ep)
+{
+ int result;
+ struct usb_serial *serial = ep->serial;
+ struct edgeport_product_info *product_info = &ep->product_info;
+ struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
+ struct edge_compatibility_bits *bits;
+
+ ep->is_epic = 0;
+ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ USB_REQUEST_ION_GET_EPIC_DESC,
+ 0xC0, 0x00, 0x00,
+ &ep->epic_descriptor,
+ sizeof(struct edge_compatibility_descriptor),
+ 300);
+
+ dbg("%s result = %d", __FUNCTION__, result);
+
+ if (result > 0) {
+ ep->is_epic = 1;
+ memset(product_info, 0, sizeof(struct edgeport_product_info));
+
+ product_info->NumPorts = epic->NumPorts;
+ product_info->ProdInfoVer = 0;
+ product_info->FirmwareMajorVersion = epic->MajorVersion;
+ product_info->FirmwareMinorVersion = epic->MinorVersion;
+ product_info->FirmwareBuildNumber = epic->BuildNumber;
+ product_info->iDownloadFile = epic->iDownloadFile;
+ product_info->EpicVer = epic->EpicVer;
+ product_info->Epic = epic->Supports;
+ product_info->ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE;
+ dump_product_info(product_info);
+
+ bits = &ep->epic_descriptor.Supports;
+ dbg("**EPIC descriptor:");
+ dbg(" VendEnableSuspend: %s", bits->VendEnableSuspend ? "TRUE": "FALSE");
+ dbg(" IOSPOpen : %s", bits->IOSPOpen ? "TRUE": "FALSE" );
+ dbg(" IOSPClose : %s", bits->IOSPClose ? "TRUE": "FALSE" );
+ dbg(" IOSPChase : %s", bits->IOSPChase ? "TRUE": "FALSE" );
+ dbg(" IOSPSetRxFlow : %s", bits->IOSPSetRxFlow ? "TRUE": "FALSE" );
+ dbg(" IOSPSetTxFlow : %s", bits->IOSPSetTxFlow ? "TRUE": "FALSE" );
+ dbg(" IOSPSetXChar : %s", bits->IOSPSetXChar ? "TRUE": "FALSE" );
+ dbg(" IOSPRxCheck : %s", bits->IOSPRxCheck ? "TRUE": "FALSE" );
+ dbg(" IOSPSetClrBreak : %s", bits->IOSPSetClrBreak ? "TRUE": "FALSE" );
+ dbg(" IOSPWriteMCR : %s", bits->IOSPWriteMCR ? "TRUE": "FALSE" );
+ dbg(" IOSPWriteLCR : %s", bits->IOSPWriteLCR ? "TRUE": "FALSE" );
+ dbg(" IOSPSetBaudRate : %s", bits->IOSPSetBaudRate ? "TRUE": "FALSE" );
+ dbg(" TrueEdgeport : %s", bits->TrueEdgeport ? "TRUE": "FALSE" );
+ }
+
+ return result;
}
@@ -1017,21 +1070,29 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
edge_port->closePending = TRUE;
- /* flush and chase */
- edge_port->chaseResponsePending = TRUE;
-
- dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
- if (status == 0) {
- // block until chase finished
- block_until_chase_response(edge_port);
- } else {
- edge_port->chaseResponsePending = FALSE;
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+ /* flush and chase */
+ edge_port->chaseResponsePending = TRUE;
+
+ dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+ if (status == 0) {
+ // block until chase finished
+ block_until_chase_response(edge_port);
+ } else {
+ edge_port->chaseResponsePending = FALSE;
+ }
}
- /* close the port */
- dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPClose))) {
+ /* close the port */
+ dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
+ send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+ }
//port->close = TRUE;
edge_port->closePending = FALSE;
@@ -1431,7 +1492,7 @@ static void edge_unthrottle (struct usb_serial_port *port)
* SerialSetTermios
* this function is called by the tty driver when it wants to change the termios structure
*****************************************************************************/
-static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct tty_struct *tty = port->tty;
@@ -1694,29 +1755,38 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
static void edge_break (struct usb_serial_port *port, int break_state)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial);
int status;
- /* flush and chase */
- edge_port->chaseResponsePending = TRUE;
-
- dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
- if (status == 0) {
- // block until chase finished
- block_until_chase_response(edge_port);
- } else {
- edge_port->chaseResponsePending = FALSE;
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+ /* flush and chase */
+ edge_port->chaseResponsePending = TRUE;
+
+ dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+ if (status == 0) {
+ // block until chase finished
+ block_until_chase_response(edge_port);
+ } else {
+ edge_port->chaseResponsePending = FALSE;
+ }
}
- if (break_state == -1) {
- dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
- } else {
- dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
- }
- if (status) {
- dbg("%s - error sending break set/clear command.", __FUNCTION__);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) {
+ if (break_state == -1) {
+ dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
+ } else {
+ dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
+ }
+ if (status) {
+ dbg("%s - error sending break set/clear command.", __FUNCTION__);
+ }
}
return;
@@ -2288,6 +2358,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
*****************************************************************************/
static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
unsigned char *cmdBuffer;
unsigned char *currCmd;
int cmdLen = 0;
@@ -2295,6 +2366,14 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa
int status;
unsigned char number = edge_port->port->number - edge_port->port->serial->minor;
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) {
+ dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d",
+ edge_port->port->number, baudRate);
+ return 0;
+ }
+
dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate);
status = calc_baud_rate_divisor (baudRate, &divisor);
@@ -2374,6 +2453,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
*****************************************************************************/
static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
unsigned char *cmdBuffer;
unsigned char *currCmd;
unsigned long cmdLen = 0;
@@ -2381,6 +2461,22 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
+ (regNum == MCR))) {
+ dbg("SendCmdWriteUartReg - Not writting to MCR Register");
+ return 0;
+ }
+
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
+ (regNum == LCR))) {
+ dbg ("SendCmdWriteUartReg - Not writting to LCR Register");
+ return 0;
+ }
+
// Alloc memory for the string of commands.
cmdBuffer = kmalloc (0x10, GFP_ATOMIC);
if (cmdBuffer == NULL ) {
@@ -2412,8 +2508,9 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
#ifndef CMSPAR
#define CMSPAR 0
#endif
-static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios)
+static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
struct tty_struct *tty;
int baud;
unsigned cflag;
@@ -2494,8 +2591,12 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
unsigned char stop_char = STOP_CHAR(tty);
unsigned char start_char = START_CHAR(tty);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) {
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+ }
/* if we are implementing INBOUND XON/XOFF */
if (I_IXOFF(tty)) {
@@ -2515,8 +2616,14 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
}
/* Set flow control to the configured value */
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow)))
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow)))
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
@@ -2728,6 +2835,13 @@ static int edge_startup (struct usb_serial *serial)
struct edgeport_port *edge_port;
struct usb_device *dev;
int i, j;
+ int response;
+ int interrupt_in_found;
+ int bulk_in_found;
+ int bulk_out_found;
+ static __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0,
+ EDGE_COMPATIBILITY_MASK1,
+ EDGE_COMPATIBILITY_MASK2 };
dev = serial->dev;
@@ -2750,38 +2864,50 @@ static int edge_startup (struct usb_serial *serial)
dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
- /* get the manufacturing descriptor for this device */
- get_manufacturing_desc (edge_serial);
+ /* Read the epic descriptor */
+ if (get_epic_descriptor(edge_serial) <= 0) {
+ /* memcpy descriptor to Supports structures */
+ memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
+ sizeof(struct edge_compatibility_bits));
+
+ /* get the manufacturing descriptor for this device */
+ get_manufacturing_desc (edge_serial);
- /* get the boot descriptor */
- get_boot_desc (edge_serial);
+ /* get the boot descriptor */
+ get_boot_desc (edge_serial);
- get_product_info(edge_serial);
+ get_product_info(edge_serial);
+ }
/* set the number of ports from the manufacturing description */
/* serial->num_ports = serial->product_info.NumPorts; */
- if (edge_serial->product_info.NumPorts != serial->num_ports) {
- warn("%s - Device Reported %d serial ports vs core "
- "thinking we have %d ports, email greg@kroah.com this info.",
- __FUNCTION__, edge_serial->product_info.NumPorts,
- serial->num_ports);
+ if ((!edge_serial->is_epic) &&
+ (edge_serial->product_info.NumPorts != serial->num_ports)) {
+ dev_warn(&serial->dev->dev, "Device Reported %d serial ports "
+ "vs. core thinking we have %d ports, email "
+ "greg@kroah.com this information.",
+ edge_serial->product_info.NumPorts,
+ serial->num_ports);
}
dbg("%s - time 1 %ld", __FUNCTION__, jiffies);
- /* now load the application firmware into this device */
- load_application_firmware (edge_serial);
+ /* If not an EPiC device */
+ if (!edge_serial->is_epic) {
+ /* now load the application firmware into this device */
+ load_application_firmware (edge_serial);
- dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
+ dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
- /* Check current Edgeport EEPROM and update if necessary */
- update_edgeport_E2PROM (edge_serial);
-
- dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+ /* Check current Edgeport EEPROM and update if necessary */
+ update_edgeport_E2PROM (edge_serial);
- /* set the configuration to use #1 */
-// dbg("set_configuration 1");
-// usb_set_configuration (dev, 1);
+ dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+
+ /* set the configuration to use #1 */
+// dbg("set_configuration 1");
+// usb_set_configuration (dev, 1);
+ }
/* we set up the pointers to the endpoints in the edge_open function,
* as the structures aren't created yet. */
@@ -2804,8 +2930,101 @@ static int edge_startup (struct usb_serial *serial)
edge_port->port = serial->port[i];
usb_set_serial_port_data(serial->port[i], edge_port);
}
-
- return 0;
+
+ response = 0;
+
+ if (edge_serial->is_epic) {
+ /* EPIC thing, set up our interrupt polling now and our read urb, so
+ * that the device knows it really is connected. */
+ interrupt_in_found = bulk_in_found = bulk_out_found = FALSE;
+ for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) {
+ struct usb_endpoint_descriptor *endpoint;
+ int buffer_size;
+
+ endpoint = &serial->interface->altsetting[0].endpoint[i].desc;
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if ((!interrupt_in_found) &&
+ (usb_endpoint_is_int_in(endpoint))) {
+ /* we found a interrupt in endpoint */
+ dbg("found interrupt in");
+
+ /* not set up yet, so do it now */
+ edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!edge_serial->interrupt_read_urb) {
+ err("out of memory");
+ return -ENOMEM;
+ }
+ edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!edge_serial->interrupt_in_buffer) {
+ err("out of memory");
+ usb_free_urb(edge_serial->interrupt_read_urb);
+ return -ENOMEM;
+ }
+ edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress;
+
+ /* set up our interrupt urb */
+ usb_fill_int_urb(edge_serial->interrupt_read_urb,
+ dev,
+ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ edge_serial->interrupt_in_buffer,
+ buffer_size,
+ edge_interrupt_callback,
+ edge_serial,
+ endpoint->bInterval);
+
+ interrupt_in_found = TRUE;
+ }
+
+ if ((!bulk_in_found) &&
+ (usb_endpoint_is_bulk_in(endpoint))) {
+ /* we found a bulk in endpoint */
+ dbg("found bulk in");
+
+ /* not set up yet, so do it now */
+ edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!edge_serial->read_urb) {
+ err("out of memory");
+ return -ENOMEM;
+ }
+ edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!edge_serial->bulk_in_buffer) {
+ err ("out of memory");
+ usb_free_urb(edge_serial->read_urb);
+ return -ENOMEM;
+ }
+ edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress;
+
+ /* set up our bulk in urb */
+ usb_fill_bulk_urb(edge_serial->read_urb, dev,
+ usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+ edge_serial->bulk_in_buffer,
+ endpoint->wMaxPacketSize,
+ edge_bulk_in_callback,
+ edge_serial);
+ bulk_in_found = TRUE;
+ }
+
+ if ((!bulk_out_found) &&
+ (usb_endpoint_is_bulk_out(endpoint))) {
+ /* we found a bulk out endpoint */
+ dbg("found bulk out");
+ edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress;
+ bulk_out_found = TRUE;
+ }
+ }
+
+ if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) {
+ err ("Error - the proper endpoints were not found!");
+ return -ENODEV;
+ }
+
+ /* start interrupt read for this edgeport this interrupt will
+ * continue as long as the edgeport is connected */
+ response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL);
+ if (response)
+ err("%s - Error %d submitting control urb", __FUNCTION__, response);
+ }
+ return response;
}
@@ -2815,6 +3034,7 @@ static int edge_startup (struct usb_serial *serial)
****************************************************************************/
static void edge_shutdown (struct usb_serial *serial)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
int i;
dbg("%s", __FUNCTION__);
@@ -2824,7 +3044,18 @@ static void edge_shutdown (struct usb_serial *serial)
kfree (usb_get_serial_port_data(serial->port[i]));
usb_set_serial_port_data(serial->port[i], NULL);
}
- kfree (usb_get_serial_data(serial));
+ /* free up our endpoint stuff */
+ if (edge_serial->is_epic) {
+ usb_unlink_urb(edge_serial->interrupt_read_urb);
+ usb_free_urb(edge_serial->interrupt_read_urb);
+ kfree(edge_serial->interrupt_in_buffer);
+
+ usb_unlink_urb(edge_serial->read_urb);
+ usb_free_urb(edge_serial->read_urb);
+ kfree(edge_serial->bulk_in_buffer);
+ }
+
+ kfree(edge_serial);
usb_set_serial_data(serial, NULL);
}
@@ -2846,6 +3077,9 @@ static int __init edgeport_init(void)
retval = usb_serial_register(&edgeport_8port_device);
if (retval)
goto failed_8port_device_register;
+ retval = usb_serial_register(&epic_device);
+ if (retval)
+ goto failed_epic_device_register;
retval = usb_register(&io_driver);
if (retval)
goto failed_usb_register;
@@ -2853,6 +3087,8 @@ static int __init edgeport_init(void)
return 0;
failed_usb_register:
+ usb_serial_deregister(&epic_device);
+failed_epic_device_register:
usb_serial_deregister(&edgeport_8port_device);
failed_8port_device_register:
usb_serial_deregister(&edgeport_4port_device);
@@ -2873,6 +3109,7 @@ static void __exit edgeport_exit (void)
usb_serial_deregister (&edgeport_2port_device);
usb_serial_deregister (&edgeport_4port_device);
usb_serial_deregister (&edgeport_8port_device);
+ usb_serial_deregister (&epic_device);
}
module_init(edgeport_init);
diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h
index 123fa8a904e..29a913a6dac 100644
--- a/drivers/usb/serial/io_edgeport.h
+++ b/drivers/usb/serial/io_edgeport.h
@@ -111,10 +111,12 @@ struct edgeport_product_info {
__le16 FirmwareBuildNumber; /* zzzz (LE format) */
__u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */
- __u8 Unused1[1]; /* Available */
+ __u8 HardwareType;
__u8 iDownloadFile; /* What to download to EPiC device */
- __u8 Unused2[2]; /* Available */
+ __u8 EpicVer; /* What version of EPiC spec this device supports */
+
+ struct edge_compatibility_bits Epic;
};
/*
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index fad561c04c7..6d300877254 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -47,6 +47,18 @@ static struct usb_device_id edgeport_8port_id_table [] = {
{ }
};
+static struct usb_device_id Epic_port_id_table [] = {
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
+ { }
+};
+
/* Devices that this driver supports */
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) },
@@ -70,17 +82,34 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, id_table_combined);
+static struct usb_driver io_driver = {
+ .name = "io_edgeport",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table_combined,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver edgeport_2port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "edgeport_2",
},
.description = "Edgeport 2 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_2port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -111,6 +140,7 @@ static struct usb_serial_driver edgeport_4port_device = {
.name = "edgeport_4",
},
.description = "Edgeport 4 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_4port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -141,6 +171,7 @@ static struct usb_serial_driver edgeport_8port_device = {
.name = "edgeport_8",
},
.description = "Edgeport 8 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_8port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -165,5 +196,35 @@ static struct usb_serial_driver edgeport_8port_device = {
.write_bulk_callback = edge_bulk_out_data_callback,
};
+static struct usb_serial_driver epic_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "epic",
+ },
+ .description = "EPiC device",
+ .id_table = Epic_port_id_table,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = edge_open,
+ .close = edge_close,
+ .throttle = edge_throttle,
+ .unthrottle = edge_unthrottle,
+ .attach = edge_startup,
+ .shutdown = edge_shutdown,
+ .ioctl = edge_ioctl,
+ .set_termios = edge_set_termios,
+ .tiocmget = edge_tiocmget,
+ .tiocmset = edge_tiocmset,
+ .write = edge_write,
+ .write_room = edge_write_room,
+ .chars_in_buffer = edge_chars_in_buffer,
+ .break_ctl = edge_break,
+ .read_int_callback = edge_interrupt_callback,
+ .read_bulk_callback = edge_bulk_in_callback,
+ .write_bulk_callback = edge_bulk_out_data_callback,
+};
+
#endif
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index ee0c921e152..544098d2b77 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -238,7 +238,7 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned c
static void stop_read(struct edgeport_port *edge_port);
static int restart_read(struct edgeport_port *edge_port);
-static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static void edge_send(struct usb_serial_port *port);
/* circular buffer */
@@ -2361,7 +2361,7 @@ static int restart_read(struct edgeport_port *edge_port)
return status;
}
-static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios)
+static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios)
{
struct ump_uart_config *config;
struct tty_struct *tty;
@@ -2512,7 +2512,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
return;
}
-static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct tty_struct *tty = port->tty;
@@ -2811,7 +2811,7 @@ static struct edge_buf *edge_buf_alloc(unsigned int size)
if (size == 0)
return NULL;
- eb = (struct edge_buf *)kmalloc(sizeof(struct edge_buf), GFP_KERNEL);
+ eb = kmalloc(sizeof(struct edge_buf), GFP_KERNEL);
if (eb == NULL)
return NULL;
@@ -2979,6 +2979,7 @@ static struct usb_serial_driver edgeport_1port_device = {
.name = "edgeport_ti_1",
},
.description = "Edgeport TI 1 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_1port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -3009,6 +3010,7 @@ static struct usb_serial_driver edgeport_2port_device = {
.name = "edgeport_ti_2",
},
.description = "Edgeport TI 2 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_2port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 2,
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
index f1804fd5a3d..e57fa117e48 100644
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -30,6 +30,7 @@
#define USB_VENDOR_ID_ION 0x1608 // Our VID
#define USB_VENDOR_ID_TI 0x0451 // TI VID
+#define USB_VENDOR_ID_AXIOHM 0x05D9 /* Axiohm VID */
//
// Definitions of USB product IDs (PID)
@@ -334,6 +335,10 @@ struct edge_compatibility_bits
};
+#define EDGE_COMPATIBILITY_MASK0 0x0001
+#define EDGE_COMPATIBILITY_MASK1 0x3FFF
+#define EDGE_COMPATIBILITY_MASK2 0x0001
+
struct edge_compatibility_descriptor
{
__u8 Length; // Descriptor Length (per USB spec)
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index d72cf8bc7f7..a408184334e 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -563,6 +563,7 @@ static struct usb_serial_driver ipaq_device = {
.name = "ipaq",
},
.description = "PocketPC PDA",
+ .usb_driver = &ipaq_driver,
.id_table = ipaq_id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
@@ -595,7 +596,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
bytes_in = 0;
bytes_out = 0;
- priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
+ priv = kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
if (priv == NULL) {
err("%s - Out of memory", __FUNCTION__);
return -ENOMEM;
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index d3b9a351cef..1bc586064c7 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -442,6 +442,7 @@ static struct usb_serial_driver ipw_device = {
.name = "ipw",
},
.description = "IPWireless converter",
+ .usb_driver = &usb_ipw_driver,
.id_table = usb_ipw_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 331bf81556f..9d847f69291 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -107,7 +107,7 @@ 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);
static void ir_read_bulk_callback (struct urb *urb);
-static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static u8 ir_baud = 0;
static u8 ir_xbof = 0;
@@ -138,6 +138,7 @@ static struct usb_serial_driver ir_device = {
.name = "ir-usb",
},
.description = "IR Dongle",
+ .usb_driver = &ir_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -497,7 +498,7 @@ static void ir_read_bulk_callback (struct urb *urb)
return;
}
-static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
unsigned char *transfer_buffer;
unsigned int cflag;
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 7639652cec4..e6966f12ed5 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -264,7 +264,7 @@ static void keyspan_break_ctl (struct usb_serial_port *port, int break_state)
static void keyspan_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
int baud_rate, device_port;
struct keyspan_port_private *p_priv;
@@ -1275,11 +1275,31 @@ static int keyspan_fake_startup (struct usb_serial *serial)
}
/* Helper functions used by keyspan_setup_urbs */
+static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
+ int endpoint)
+{
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *ep;
+ int i;
+
+ iface_desc = serial->interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ ep = &iface_desc->endpoint[i].desc;
+ if (ep->bEndpointAddress == endpoint)
+ return ep;
+ }
+ dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
+ "endpoint %x\n", endpoint);
+ return NULL;
+}
+
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 urb *urb;
+ struct usb_endpoint_descriptor const *ep_desc;
+ char const *ep_type_name;
if (endpoint == -1)
return NULL; /* endpoint not needed */
@@ -1291,11 +1311,32 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int 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);
+ ep_desc = find_ep(serial, endpoint);
+ if (!ep_desc) {
+ /* leak the urb, something's wrong and the callers don't care */
+ return urb;
+ }
+ if (usb_endpoint_xfer_int(ep_desc)) {
+ ep_type_name = "INT";
+ usb_fill_int_urb(urb, serial->dev,
+ usb_sndintpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx,
+ ep_desc->bInterval);
+ } else if (usb_endpoint_xfer_bulk(ep_desc)) {
+ ep_type_name = "BULK";
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx);
+ } else {
+ dev_warn(&serial->interface->dev,
+ "unsupported endpoint type %x\n",
+ ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+ usb_free_urb(urb);
+ return NULL;
+ }
+ dbg("%s - using urb %p for %s endpoint %x",
+ __func__, urb, ep_type_name, endpoint);
return urb;
}
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 7472ed6bf62..c6830cbdc6d 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -59,7 +59,7 @@ static int keyspan_ioctl (struct usb_serial_port *port,
unsigned int cmd,
unsigned long arg);
static void keyspan_set_termios (struct usb_serial_port *port,
- struct termios *old);
+ struct ktermios *old);
static void keyspan_break_ctl (struct usb_serial_port *port,
int break_state);
static int keyspan_tiocmget (struct usb_serial_port *port,
@@ -229,7 +229,6 @@ struct ezusb_hex_record {
#define keyspan_usa28_product_id 0x010f
#define keyspan_usa28x_product_id 0x0110
#define keyspan_usa28xa_product_id 0x0115
-#define keyspan_usa28xb_product_id 0x0110
#define keyspan_usa49w_product_id 0x010a
#define keyspan_usa49wlc_product_id 0x012a
@@ -511,7 +510,6 @@ static struct usb_device_id keyspan_ids_combined[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
- { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
{ } /* Terminating entry */
@@ -559,7 +557,6 @@ static struct usb_device_id keyspan_2port_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
- { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
{ } /* Terminating entry */
};
@@ -576,6 +573,7 @@ static struct usb_serial_driver keyspan_pre_device = {
.name = "keyspan_no_firm",
},
.description = "Keyspan - (without firmware)",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_pre_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -590,6 +588,7 @@ static struct usb_serial_driver keyspan_1port_device = {
.name = "keyspan_1",
},
.description = "Keyspan 1 port adapter",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_1port_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -617,6 +616,7 @@ static struct usb_serial_driver keyspan_2port_device = {
.name = "keyspan_2",
},
.description = "Keyspan 2 port adapter",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_2port_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -644,6 +644,7 @@ static struct usb_serial_driver keyspan_4port_device = {
.name = "keyspan_4",
},
.description = "Keyspan 4 port adapter",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_4port_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 5,
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index e09a0bfe623..da514cb785b 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -365,7 +365,7 @@ static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state
static void keyspan_pda_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
unsigned int cflag = port->tty->termios->c_cflag;
@@ -793,6 +793,7 @@ static struct usb_serial_driver keyspan_pda_fake_device = {
.name = "keyspan_pda_pre",
},
.description = "Keyspan PDA - (prerenumeration)",
+ .usb_driver = &keyspan_pda_driver,
.id_table = id_table_fake,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -809,6 +810,7 @@ static struct usb_serial_driver xircom_pgs_fake_device = {
.name = "xircom_no_firm",
},
.description = "Xircom / Entregra PGS - (prerenumeration)",
+ .usb_driver = &keyspan_pda_driver,
.id_table = id_table_fake_xircom,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -824,6 +826,7 @@ static struct usb_serial_driver keyspan_pda_device = {
.name = "keyspan_pda",
},
.description = "Keyspan PDA",
+ .usb_driver = &keyspan_pda_driver,
.id_table = id_table_std,
.num_interrupt_in = 1,
.num_bulk_in = 0,
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 17e205699c2..b2097c45a23 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -86,11 +86,7 @@ static int klsi_105_write_room (struct usb_serial_port *port);
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,
- struct file * file,
- unsigned int cmd,
- unsigned long arg);
+ struct ktermios *old);
static void klsi_105_throttle (struct usb_serial_port *port);
static void klsi_105_unthrottle (struct usb_serial_port *port);
/*
@@ -128,6 +124,7 @@ static struct usb_serial_driver kl5kusb105d_device = {
.name = "kl5kusb105d",
},
.description = "KL5KUSB105D / PalmConnect",
+ .usb_driver = &kl5kusb105d_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -140,7 +137,6 @@ static struct usb_serial_driver kl5kusb105d_device = {
.chars_in_buffer = klsi_105_chars_in_buffer,
.write_room = klsi_105_write_room,
.read_bulk_callback =klsi_105_read_bulk_callback,
- .ioctl = klsi_105_ioctl,
.set_termios = klsi_105_set_termios,
/*.break_ctl = klsi_105_break_ctl,*/
.tiocmget = klsi_105_tiocmget,
@@ -164,7 +160,7 @@ struct klsi_105_port_settings {
#define URB_TRANSFER_BUFFER_SIZE 64
struct klsi_105_private {
struct klsi_105_port_settings cfg;
- struct termios termios;
+ struct ktermios termios;
unsigned long line_state; /* modem line settings */
/* write pool */
struct urb * write_urb_pool[NUM_URBS];
@@ -688,7 +684,7 @@ static void klsi_105_read_bulk_callback (struct urb *urb)
static void klsi_105_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct klsi_105_private *priv = usb_get_serial_port_data(port);
unsigned int iflag = port->tty->termios->c_iflag;
@@ -899,69 +895,6 @@ static int klsi_105_tiocmset (struct usb_serial_port *port, struct file *file,
*/
return retval;
}
-
-static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- struct klsi_105_private *priv = usb_get_serial_port_data(port);
- void __user *user_arg = (void __user *)arg;
-
- dbg("%scmd=0x%x", __FUNCTION__, cmd);
-
- /* Based on code from acm.c and others */
- switch (cmd) {
- case TIOCMIWAIT:
- /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
- /* TODO */
- dbg("%s - TIOCMIWAIT not handled", __FUNCTION__);
- return -ENOIOCTLCMD;
- case TIOCGICOUNT:
- /* return count of modemline transitions */
- /* TODO */
- dbg("%s - TIOCGICOUNT not handled", __FUNCTION__);
- return -ENOIOCTLCMD;
- case TCGETS:
- /* return current info to caller */
- dbg("%s - TCGETS data faked/incomplete", __FUNCTION__);
-
- if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios)))
- return -EFAULT;
-
- if (kernel_termios_to_user_termios((struct termios __user *)arg,
- &priv->termios))
- return -EFAULT;
- return 0;
- case TCSETS:
- /* set port termios to the one given by the user */
- dbg("%s - TCSETS not handled", __FUNCTION__);
-
- if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios)))
- return -EFAULT;
-
- if (user_termios_to_kernel_termios(&priv->termios,
- (struct termios __user *)arg))
- return -EFAULT;
- klsi_105_set_termios(port, &priv->termios);
- return 0;
- case TCSETSW: {
- /* set port termios and try to wait for completion of last
- * write operation */
- /* We guess here. If there are not too many write urbs
- * outstanding, we lie. */
- /* what is the right way to wait here? schedule() ? */
- /*
- while (klsi_105_chars_in_buffer(port) > (NUM_URBS / 4 ) * URB_TRANSFER_BUFFER_SIZE)
- schedule();
- */
- return -ENOIOCTLCMD;
- }
- default:
- dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd);
- return(-ENOIOCTLCMD);
- break;
- }
- return 0;
-} /* klsi_105_ioctl */
static void klsi_105_throttle (struct usb_serial_port *port)
{
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 237289920f0..0683b51f093 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -110,6 +110,7 @@ static struct usb_serial_driver kobil_device = {
.name = "kobil",
},
.description = "KOBIL USB smart card terminal",
+ .usb_driver = &kobil_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 0,
@@ -136,7 +137,7 @@ struct kobil_private {
int cur_pos; // index of the next char to send in buf
__u16 device_type;
int line_state;
- struct termios internal_termios;
+ struct ktermios internal_termios;
};
@@ -269,7 +270,7 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
}
// allocate memory for write_urb transfer buffer
- port->write_urb->transfer_buffer = (unsigned char *) kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL);
+ port->write_urb->transfer_buffer = kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL);
if (! port->write_urb->transfer_buffer) {
kfree(transfer_buffer);
usb_free_urb(port->write_urb);
@@ -624,11 +625,11 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
switch (cmd) {
case TCGETS: // 0x5401
- if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios))) {
+ if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
return -EFAULT;
}
- if (kernel_termios_to_user_termios((struct termios __user *)arg,
+ if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
&priv->internal_termios))
return -EFAULT;
return 0;
@@ -638,12 +639,12 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
return -ENOTTY;
}
- if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios))) {
+ if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
return -EFAULT;
}
if (user_termios_to_kernel_termios(&priv->internal_termios,
- (struct termios __user *)arg))
+ (struct ktermios __user *)arg))
return -EFAULT;
settings = kzalloc(50, GFP_KERNEL);
@@ -696,7 +697,7 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
return 0;
case TCFLSH: // 0x540B
- transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);
+ transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
if (! transfer_buffer) {
return -ENOBUFS;
}
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index a906e500a02..4cd839b1407 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -98,7 +98,7 @@ static void mct_u232_close (struct usb_serial_port *port,
struct file *filp);
static void mct_u232_read_int_callback (struct urb *urb);
static void mct_u232_set_termios (struct usb_serial_port *port,
- struct termios * old);
+ struct ktermios * old);
static int mct_u232_ioctl (struct usb_serial_port *port,
struct file * file,
unsigned int cmd,
@@ -137,6 +137,7 @@ static struct usb_serial_driver mct_u232_device = {
.name = "mct_u232",
},
.description = "MCT U232",
+ .usb_driver = &mct_u232_driver,
.id_table = id_table_combined,
.num_interrupt_in = 2,
.num_bulk_in = 0,
@@ -556,7 +557,7 @@ exit:
} /* mct_u232_read_int_callback */
static void mct_u232_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
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
index 70f93b18292..6109c6704a7 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1014,7 +1014,7 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
* the specified new settings.
*/
static void change_port_settings(struct moschip_port *mos7720_port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct usb_serial_port *port;
struct usb_serial *serial;
@@ -1203,7 +1203,7 @@ static void change_port_settings(struct moschip_port *mos7720_port,
* termios structure.
*/
static void mos7720_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
int status;
unsigned int cflag;
@@ -1605,12 +1605,21 @@ static void mos7720_shutdown(struct usb_serial *serial)
usb_set_serial_data(serial, NULL);
}
+static struct usb_driver usb_driver = {
+ .name = "moschip7720",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = moschip_port_id_table,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver moschip7720_2port_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "moschip7720",
},
.description = "Moschip 2 port adapter",
+ .usb_driver = &usb_driver,
.id_table = moschip_port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 2,
@@ -1631,13 +1640,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.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;
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 5432c634008..b2264a87617 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1931,7 +1931,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
*****************************************************************************/
static void mos7840_change_port_settings(struct moschip_port *mos7840_port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct tty_struct *tty;
int baud;
@@ -2118,7 +2118,7 @@ static void mos7840_change_port_settings(struct moschip_port *mos7840_port,
*****************************************************************************/
static void mos7840_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
int status;
unsigned int cflag;
@@ -2460,12 +2460,6 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
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);
@@ -2840,12 +2834,21 @@ static void mos7840_shutdown(struct usb_serial *serial)
}
+static struct usb_driver io_driver = {
+ .name = "mos7840",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = moschip_id_table_combined,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver moschip7840_4port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "mos7840",
},
.description = DRIVER_DESC,
+ .usb_driver = &io_driver,
.id_table = moschip_port_id_table,
.num_interrupt_in = 1, //NUM_DONT_CARE,//1,
#ifdef check
@@ -2875,13 +2878,6 @@ static struct usb_serial_driver moschip7840_4port_device = {
.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
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 054abee8165..90701111d74 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -119,6 +119,7 @@ static struct usb_serial_driver navman_device = {
.name = "navman",
},
.id_table = id_table,
+ .usb_driver = &navman_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index bc91d3b726f..0216ac12a27 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -93,6 +93,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
.name = "omninet",
},
.description = "ZyXEL - omni.net lcd plus usb",
+ .usb_driver = &omninet_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 130afbbd3fc..ced9f32b29d 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -59,7 +59,7 @@ static int option_chars_in_buffer(struct usb_serial_port *port);
static int option_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg);
static void option_set_termios(struct usb_serial_port *port,
- struct termios *old);
+ struct ktermios *old);
static void option_break_ctl(struct usb_serial_port *port, int break_state);
static int option_tiocmget(struct usb_serial_port *port, struct file *file);
static int option_tiocmset(struct usb_serial_port *port, struct file *file,
@@ -78,7 +78,9 @@ static int option_send_setup(struct usb_serial_port *port);
#define OPTION_PRODUCT_FUSION2 0x6300
#define OPTION_PRODUCT_COBRA 0x6500
#define OPTION_PRODUCT_COBRA2 0x6600
+#define OPTION_PRODUCT_GTMAX36 0x6701
#define HUAWEI_PRODUCT_E600 0x1001
+#define HUAWEI_PRODUCT_E220 0x1003
#define AUDIOVOX_PRODUCT_AIRCARD 0x0112
#define NOVATELWIRELESS_PRODUCT_U740 0x1400
#define ANYDATA_PRODUCT_ID 0x6501
@@ -89,7 +91,9 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
+ { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
@@ -102,7 +106,9 @@ static struct usb_device_id option_ids1[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
+ { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
@@ -129,6 +135,7 @@ static struct usb_serial_driver option_1port_device = {
.name = "option1",
},
.description = "GSM modem (1-port)",
+ .usb_driver = &option_driver,
.id_table = option_ids1,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -230,7 +237,7 @@ static void option_break_ctl(struct usb_serial_port *port, int break_state)
}
static void option_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
dbg("%s", __FUNCTION__);
@@ -622,6 +629,9 @@ static int option_send_setup(struct usb_serial_port *port)
dbg("%s", __FUNCTION__);
+ if (port->number != 0)
+ return 0;
+
portdata = usb_get_serial_port_data(port);
if (port->tty) {
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index bc800c8787a..6c083d4e2c9 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -159,7 +159,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
if (size == 0)
return NULL;
- pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+ pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
if (pb == NULL)
return NULL;
@@ -455,7 +455,7 @@ static int pl2303_chars_in_buffer(struct usb_serial_port *port)
}
static void pl2303_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
@@ -687,7 +687,7 @@ static void pl2303_close(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 ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned char *buf;
@@ -1118,6 +1118,7 @@ static struct usb_serial_driver pl2303_device = {
.name = "pl2303",
},
.id_table = id_table,
+ .usb_driver = &pl2303_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
.num_bulk_out = 1,
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 30b7ebc8d45..5a03a3fc938 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -402,6 +402,7 @@ static struct usb_serial_driver safe_device = {
.name = "safe_serial",
},
.id_table = id_table,
+ .usb_driver = &safe_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 4b5097fa48d..ecedd833818 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -13,10 +13,9 @@
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_VERSION "v.1.0.6"
#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
@@ -31,14 +30,15 @@
static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0218) }, /* 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, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+ { USB_DEVICE(0x1199, 0x6804) }, /* 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 */
@@ -55,14 +55,15 @@ static struct usb_device_id id_table_1port [] = {
};
static struct usb_device_id id_table_3port [] = {
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0218) }, /* 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, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+ { USB_DEVICE(0x1199, 0x6804) }, /* 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 */
{ }
@@ -81,7 +82,7 @@ static int debug;
/* per port private data */
#define N_IN_URB 4
-#define N_OUT_URB 1
+#define N_OUT_URB 4
#define IN_BUFLEN 4096
#define OUT_BUFLEN 128
@@ -145,7 +146,7 @@ static void sierra_break_ctl(struct usb_serial_port *port, int break_state)
}
static void sierra_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
dbg("%s", __FUNCTION__);
@@ -396,6 +397,8 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
int i, err;
struct urb *urb;
+ int result;
+ __u16 set_mode_dzero = 0x0000;
portdata = usb_get_serial_port_data(port);
@@ -442,6 +445,12 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
port->tty->low_latency = 1;
+ /* set mode to D0 */
+ result = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ 0x00, 0x40, set_mode_dzero, 0, NULL,
+ 0, USB_CTRL_SET_TIMEOUT);
+
sierra_send_setup(port);
return (0);
@@ -614,6 +623,7 @@ static struct usb_serial_driver sierra_1port_device = {
},
.description = "Sierra USB modem (1 port)",
.id_table = id_table_1port,
+ .usb_driver = &sierra_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
.num_bulk_out = 1,
@@ -642,6 +652,7 @@ static struct usb_serial_driver sierra_3port_device = {
},
.description = "Sierra USB modem (3 port)",
.id_table = id_table_3port,
+ .usb_driver = &sierra_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 3,
.num_bulk_out = 3,
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index ae98d8cbdbb..4203e2b1a76 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -161,7 +161,7 @@ static void ti_throttle(struct usb_serial_port *port);
static void ti_unthrottle(struct usb_serial_port *port);
static int ti_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg);
static void ti_set_termios(struct usb_serial_port *port,
- struct termios *old_termios);
+ struct ktermios *old_termios);
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);
@@ -262,6 +262,7 @@ static struct usb_serial_driver ti_1port_device = {
.name = "ti_usb_3410_5052_1",
},
.description = "TI USB 3410 1 port adapter",
+ .usb_driver = &ti_usb_driver,
.id_table = ti_id_table_3410,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -292,6 +293,7 @@ static struct usb_serial_driver ti_2port_device = {
.name = "ti_usb_3410_5052_2",
},
.description = "TI USB 5052 2 port adapter",
+ .usb_driver = &ti_usb_driver,
.id_table = ti_id_table_5052,
.num_interrupt_in = 1,
.num_bulk_in = 2,
@@ -881,7 +883,7 @@ static int ti_ioctl(struct usb_serial_port *port, struct file *file,
static void ti_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct ti_port *tport = usb_get_serial_port_data(port);
struct tty_struct *tty = port->tty;
@@ -1710,7 +1712,7 @@ static struct circ_buf *ti_buf_alloc(void)
{
struct circ_buf *cb;
- cb = (struct circ_buf *)kmalloc(sizeof(struct circ_buf), GFP_KERNEL);
+ cb = kmalloc(sizeof(struct circ_buf), GFP_KERNEL);
if (cb == NULL)
return NULL;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 3d5072f14b8..6bf22a28adb 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -59,14 +59,19 @@ static struct usb_driver usb_serial_driver = {
static int debug;
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
+static spinlock_t table_lock;
static LIST_HEAD(usb_serial_driver_list);
struct usb_serial *usb_serial_get_by_index(unsigned index)
{
- struct usb_serial *serial = serial_table[index];
+ struct usb_serial *serial;
+
+ spin_lock(&table_lock);
+ serial = serial_table[index];
if (serial)
kref_get(&serial->kref);
+ spin_unlock(&table_lock);
return serial;
}
@@ -78,6 +83,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
dbg("%s %d", __FUNCTION__, num_ports);
*minor = 0;
+ spin_lock(&table_lock);
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
if (serial_table[i])
continue;
@@ -96,8 +102,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
dbg("%s - minor base = %d", __FUNCTION__, *minor);
for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
serial_table[i] = serial;
+ spin_unlock(&table_lock);
return serial;
}
+ spin_unlock(&table_lock);
return NULL;
}
@@ -110,9 +118,11 @@ static void return_serial(struct usb_serial *serial)
if (serial == NULL)
return;
+ spin_lock(&table_lock);
for (i = 0; i < serial->num_ports; ++i) {
serial_table[serial->minor + i] = NULL;
}
+ spin_unlock(&table_lock);
}
static void destroy_serial(struct kref *kref)
@@ -271,7 +281,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -EINVAL;
+ int retval = -ENODEV;
if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit;
@@ -279,6 +289,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
if (!port->open_count) {
+ retval = -EINVAL;
dbg("%s - port not opened", __FUNCTION__);
goto exit;
}
@@ -397,7 +408,7 @@ exit:
return retval;
}
-static void serial_set_termios (struct tty_struct *tty, struct termios * old)
+static void serial_set_termios (struct tty_struct *tty, struct ktermios * old)
{
struct usb_serial_port *port = tty->driver_data;
@@ -559,15 +570,20 @@ static void port_release(struct device *dev)
port_free(port);
}
-static void port_free(struct usb_serial_port *port)
+static void kill_traffic(struct usb_serial_port *port)
{
usb_kill_urb(port->read_urb);
- usb_free_urb(port->read_urb);
usb_kill_urb(port->write_urb);
- usb_free_urb(port->write_urb);
usb_kill_urb(port->interrupt_in_urb);
- usb_free_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_out_urb);
+}
+
+static void port_free(struct usb_serial_port *port)
+{
+ kill_traffic(port);
+ usb_free_urb(port->read_urb);
+ usb_free_urb(port->write_urb);
+ usb_free_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_out_urb);
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
@@ -596,6 +612,39 @@ static struct usb_serial * create_serial (struct usb_device *dev,
return serial;
}
+static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
+ struct usb_serial_driver *drv)
+{
+ struct usb_dynid *dynid;
+
+ spin_lock(&drv->dynids.lock);
+ list_for_each_entry(dynid, &drv->dynids.list, node) {
+ if (usb_match_one_id(intf, &dynid->id)) {
+ spin_unlock(&drv->dynids.lock);
+ return &dynid->id;
+ }
+ }
+ spin_unlock(&drv->dynids.lock);
+ return NULL;
+}
+
+static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
+ struct usb_interface *intf)
+{
+ const struct usb_device_id *id;
+
+ id = usb_match_id(intf, drv->id_table);
+ if (id) {
+ dbg("static descriptor matches");
+ goto exit;
+ }
+ id = match_dynamic_id(intf, drv);
+ if (id)
+ dbg("dynamic descriptor matches");
+exit:
+ return id;
+}
+
static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
{
struct list_head *p;
@@ -605,11 +654,9 @@ static struct usb_serial_driver *search_serial_device(struct usb_interface *ifac
/* Check if the usb id matches a known device */
list_for_each(p, &usb_serial_driver_list) {
t = list_entry(p, struct usb_serial_driver, driver_list);
- id = usb_match_id(iface, t->id_table);
- if (id != NULL) {
- dbg("descriptor matches");
+ id = get_iface_id(t, iface);
+ if (id)
return t;
- }
}
return NULL;
@@ -639,14 +686,17 @@ int usb_serial_probe(struct usb_interface *interface,
int num_ports = 0;
int max_endpoints;
+ lock_kernel(); /* guard against unloading a serial driver module */
type = search_serial_device(interface);
if (!type) {
+ unlock_kernel();
dbg("none matched");
return -ENODEV;
}
serial = create_serial (dev, interface, type);
if (!serial) {
+ unlock_kernel();
dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
return -ENOMEM;
}
@@ -656,16 +706,18 @@ int usb_serial_probe(struct usb_interface *interface,
const struct usb_device_id *id;
if (!try_module_get(type->driver.owner)) {
+ unlock_kernel();
dev_err(&interface->dev, "module get failed, exiting\n");
kfree (serial);
return -EIO;
}
- id = usb_match_id(interface, type->id_table);
+ id = get_iface_id(type, interface);
retval = type->probe(serial, id);
module_put(type->driver.owner);
if (retval) {
+ unlock_kernel();
dbg ("sub driver rejected device");
kfree (serial);
return retval;
@@ -735,6 +787,7 @@ int usb_serial_probe(struct usb_interface *interface,
* properly during a later invocation of usb_serial_probe
*/
if (num_bulk_in == 0 || num_bulk_out == 0) {
+ unlock_kernel();
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
kfree (serial);
return -ENODEV;
@@ -750,6 +803,7 @@ int usb_serial_probe(struct usb_interface *interface,
if (type == &usb_serial_generic_device) {
num_ports = num_bulk_out;
if (num_ports == 0) {
+ unlock_kernel();
dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
kfree (serial);
return -EIO;
@@ -760,6 +814,7 @@ int usb_serial_probe(struct usb_interface *interface,
/* if this device type has a calc_num_ports function, call it */
if (type->calc_num_ports) {
if (!try_module_get(type->driver.owner)) {
+ unlock_kernel();
dev_err(&interface->dev, "module get failed, exiting\n");
kfree (serial);
return -EIO;
@@ -771,12 +826,6 @@ int usb_serial_probe(struct usb_interface *interface,
num_ports = type->num_ports;
}
- if (get_free_serial (serial, num_ports, &minor) == NULL) {
- dev_err(&interface->dev, "No more free serial devices\n");
- kfree (serial);
- return -ENOMEM;
- }
-
serial->minor = minor;
serial->num_ports = num_ports;
serial->num_bulk_in = num_bulk_in;
@@ -791,6 +840,8 @@ int usb_serial_probe(struct usb_interface *interface,
max_endpoints = max(max_endpoints, num_interrupt_out);
max_endpoints = max(max_endpoints, (int)serial->num_ports);
serial->num_port_pointers = max_endpoints;
+ unlock_kernel();
+
dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
for (i = 0; i < max_endpoints; ++i) {
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
@@ -925,6 +976,11 @@ int usb_serial_probe(struct usb_interface *interface,
}
}
+ if (get_free_serial (serial, num_ports, &minor) == NULL) {
+ dev_err(&interface->dev, "No more free serial devices\n");
+ goto probe_error;
+ }
+
/* register all of the individual ports with the driver core */
for (i = 0; i < num_ports; ++i) {
port = serial->port[i];
@@ -1002,8 +1058,11 @@ void usb_serial_disconnect(struct usb_interface *interface)
if (serial) {
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
- if (port && port->tty)
- tty_hangup(port->tty);
+ if (port) {
+ if (port->tty)
+ tty_hangup(port->tty);
+ kill_traffic(port);
+ }
}
/* let the last holder of this object
* cause it to be cleaned up */
@@ -1040,6 +1099,7 @@ static int __init usb_serial_init(void)
return -ENOMEM;
/* Initialize our global data */
+ spin_lock_init(&table_lock);
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL;
}
@@ -1138,7 +1198,7 @@ static void fixup_generic(struct usb_serial_driver *device)
set_to_generic_if_null(device, shutdown);
}
-int usb_serial_register(struct usb_serial_driver *driver)
+int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
{
int retval;
@@ -1162,7 +1222,7 @@ int usb_serial_register(struct usb_serial_driver *driver)
}
-void usb_serial_deregister(struct usb_serial_driver *device)
+void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */
{
info("USB Serial deregistering driver %s", device->description);
list_del(&device->driver_list);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index eef5eaa5fa0..2f59ff226e2 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -46,7 +46,7 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id
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_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
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);
@@ -90,8 +90,6 @@ static struct usb_device_id id_table [] = {
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
- { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID),
- .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
@@ -151,7 +149,6 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
- { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -189,6 +186,7 @@ static struct usb_serial_driver handspring_device = {
.name = "visor",
},
.description = "Handspring Visor / Palm OS",
+ .usb_driver = &visor_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 2,
@@ -219,6 +217,7 @@ static struct usb_serial_driver clie_5_device = {
.name = "clie_5",
},
.description = "Sony Clie 5.0",
+ .usb_driver = &visor_driver,
.id_table = clie_id_5_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 2,
@@ -249,6 +248,7 @@ static struct usb_serial_driver clie_3_5_device = {
.name = "clie_3.5",
},
.description = "Sony Clie 3.5",
+ .usb_driver = &visor_driver,
.id_table = clie_id_3_5_table,
.num_interrupt_in = 0,
.num_bulk_in = 1,
@@ -916,7 +916,7 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign
/* This function is all nice and good, but we don't change anything based on it :) */
-static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
unsigned int cflag;
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index 765118d83fb..4ce6f62a6f3 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -32,7 +32,6 @@
#define PALM_TUNGSTEN_T_ID 0x0060
#define PALM_TREO_650 0x0061
#define PALM_TUNGSTEN_Z_ID 0x0031
-#define PALM_ZIRE31_ID 0x0061
#define PALM_ZIRE_ID 0x0070
#define PALM_M100_ID 0x0080
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 154c7d29059..bf16e9e1d84 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -145,7 +145,7 @@ static void whiteheat_close (struct usb_serial_port *port, struct file *filp);
static int whiteheat_write (struct usb_serial_port *port, const unsigned char *buf, int count);
static int whiteheat_write_room (struct usb_serial_port *port);
static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old);
+static void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios * old);
static int whiteheat_tiocmget (struct usb_serial_port *port, struct file *file);
static int whiteheat_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
static void whiteheat_break_ctl (struct usb_serial_port *port, int break_state);
@@ -161,6 +161,7 @@ static struct usb_serial_driver whiteheat_fake_device = {
.name = "whiteheatnofirm",
},
.description = "Connect Tech - WhiteHEAT - (prerenumeration)",
+ .usb_driver = &whiteheat_driver,
.id_table = id_table_prerenumeration,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -176,6 +177,7 @@ static struct usb_serial_driver whiteheat_device = {
.name = "whiteheat",
},
.description = "Connect Tech - WhiteHEAT",
+ .usb_driver = &whiteheat_driver,
.id_table = id_table_std,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -416,7 +418,7 @@ static int whiteheat_attach (struct usb_serial *serial)
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
- info = (struct whiteheat_private *)kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL);
+ info = kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL);
if (info == NULL) {
err("%s: Out of memory for port structures\n", serial->type->description);
goto no_private;
@@ -487,7 +489,7 @@ static int whiteheat_attach (struct usb_serial *serial)
usb_set_serial_port_data(port, info);
}
- command_info = (struct whiteheat_command_private *)kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL);
+ command_info = kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL);
if (command_info == NULL) {
err("%s: Out of memory for port structures\n", serial->type->description);
goto no_command_private;
@@ -597,7 +599,7 @@ static void whiteheat_shutdown (struct usb_serial *serial)
static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
{
int retval = 0;
- struct termios old_term;
+ struct ktermios old_term;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -870,7 +872,7 @@ static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, un
}
-static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
dbg("%s -port %d", __FUNCTION__, port->number);
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index e565d3d2ab2..6d3dad3d1da 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -33,7 +33,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/usb_ch9.h>
#include <linux/usb/input.h>
#include "usb.h"
#include "onetouch.h"
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e1072d52d64..70234f5dbee 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -110,23 +110,6 @@ static int slave_configure(struct scsi_device *sdev)
* the end, scatter-gather buffers follow page boundaries. */
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
- /* Set the SCSI level to at least 2. We'll leave it at 3 if that's
- * what is originally reported. We need this to avoid confusing
- * the SCSI layer with devices that report 0 or 1, but need 10-byte
- * commands (ala ATAPI devices behind certain bridges, or devices
- * which simply have broken INQUIRY data).
- *
- * NOTE: This means /dev/sg programs (ala cdrecord) will get the
- * actual information. This seems to be the preference for
- * programs like that.
- *
- * NOTE: This also means that /proc/scsi/scsi and sysfs may report
- * the actual value or the modified one, depending on where the
- * data comes from.
- */
- if (sdev->scsi_level < SCSI_2)
- sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
-
/* Many devices have trouble transfering more than 32KB at a time,
* while others have trouble with more than 64K. At this time we
* are limiting both to 32K (64 sectores).
@@ -176,7 +159,9 @@ static int slave_configure(struct scsi_device *sdev)
* a Get-Max-LUN request, we won't lose much by setting the
* revision level down to 2. The only devices that would be
* affected are those with sparse LUNs. */
- sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
+ if (sdev->scsi_level > SCSI_2)
+ sdev->sdev_target->scsi_level =
+ sdev->scsi_level = SCSI_2;
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
* Hardware Error) when any low-level error occurs,
@@ -194,6 +179,16 @@ static int slave_configure(struct scsi_device *sdev)
sdev->use_10_for_ms = 1;
}
+ /* The CB and CBI transports have no way to pass LUN values
+ * other than the bits in the second byte of a CDB. But those
+ * bits don't get set to the LUN value if the device reports
+ * scsi_level == 0 (UNKNOWN). Hence such devices must necessarily
+ * be single-LUN.
+ */
+ if ((us->protocol == US_PR_CB || us->protocol == US_PR_CBI) &&
+ sdev->scsi_level == SCSI_UNKNOWN)
+ us->max_lun = 0;
+
/* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
* REMOVAL command, so suppress those commands. */
if (us->flags & US_FL_NOT_LOCKABLE)
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index fb8bacaae27..e3528eca29a 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -646,7 +646,7 @@ sddr09_read_sg_test_only(struct us_data *us) {
return result;
}
- buf = (unsigned char *) kmalloc(bulklen, GFP_NOIO);
+ buf = kmalloc(bulklen, GFP_NOIO);
if (!buf)
return -ENOMEM;
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index db8b26012c7..f49a62fc32d 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -153,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 <honkkis@gmail.com> */
+UNUSUAL_DEV( 0x0421, 0x0433, 0x0100, 0x0100,
+ "Nokia",
+ "E70",
+ 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",
@@ -190,6 +197,13 @@ UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_MAX_SECTORS_64 ),
+/* Reported by Manuel Osdoba <manuel.osdoba@tu-ilmenau.de> */
+UNUSUAL_DEV( 0x0421, 0x0492, 0x0452, 0x0452,
+ "Nokia",
+ "Nokia 6233",
+ 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",
@@ -247,6 +261,18 @@ UNUSUAL_DEV( 0x045a, 0x5210, 0x0101, 0x0101,
US_SC_SCSI, US_PR_KARMA, rio_karma_init, 0),
#endif
+/*
+ * This virtual floppy is found in Sun equipment (x4600, x4200m2, etc.)
+ * Reported by Pete Zaitcev <zaitcev@redhat.com>
+ * This device chokes on both version of MODE SENSE which we have, so
+ * use_10_for_ms is not effective, and we use US_FL_NO_WP_DETECT.
+ */
+UNUSUAL_DEV( 0x046b, 0xff40, 0x0100, 0x0100,
+ "AMI",
+ "Virtual Floppy",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_NO_WP_DETECT),
+
/* Patch submitted by Philipp Friedrich <philipp@void.at> */
UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100,
"Kyocera",
@@ -547,7 +573,7 @@ UNUSUAL_DEV( 0x054c, 0x002b, 0x0100, 0x0110,
#endif
/* Submitted by Olaf Hering, <olh@suse.de> SuSE Bugzilla #49049 */
-UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x0501,
+UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x2000,
"Sony",
"USB Floppy Drive",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -721,7 +747,7 @@ UNUSUAL_DEV( 0x05ac, 0x1204, 0x0000, 0x9999,
"Apple",
"iPod",
US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
+ US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
UNUSUAL_DEV( 0x05ac, 0x1205, 0x0000, 0x9999,
"Apple",
@@ -1299,13 +1325,6 @@ 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 Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
* Tested on hardware version 1.10.
* Entry is needed only for the initializer function override.
@@ -1328,6 +1347,15 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* This prevents the kernel from detecting the virtual cd-drive with the
+ * Windows drivers. <johann.wilhelm@student.tugraz.at>
+*/
+UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0xffff,
+ "HUAWEI",
+ "E220 USB-UMTS Install",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE),
+
/* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
UNUSUAL_DEV( 0x132b, 0x000b, 0x0001, 0x0001,
"Minolta",
@@ -1342,6 +1370,21 @@ UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Francesco Foresti <frafore@tiscali.it> */
+UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201,
+ "Super Top",
+ "IDE DEVICE",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Robert Schedel <r.schedel@yahoo.de>
+ * Note: this is a 'super top' device like the above 14cd/6600 device */
+UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201,
+ "Teac",
+ "HD-35PUK-B",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
/* patch submitted by Davide Perini <perini.davide@dpsoftware.org>
* and Renato Perini <rperini@email.it>
*/
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 70644506651..7e7ec29782f 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -731,26 +731,27 @@ static int get_pipes(struct us_data *us)
struct usb_endpoint_descriptor *ep_int = NULL;
/*
- * Find the endpoints we need.
+ * Find the first endpoint of each type we need.
* We are expecting a minimum of 2 endpoints - in and out (bulk).
- * An optional interrupt is OK (necessary for CBI protocol).
+ * An optional interrupt-in is OK (necessary for CBI protocol).
* We will ignore any others.
*/
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
ep = &altsetting->endpoint[i].desc;
- /* Is it a BULK endpoint? */
if (usb_endpoint_xfer_bulk(ep)) {
- /* BULK in or out? */
- if (usb_endpoint_dir_in(ep))
- ep_in = ep;
- else
- ep_out = ep;
+ if (usb_endpoint_dir_in(ep)) {
+ if (!ep_in)
+ ep_in = ep;
+ } else {
+ if (!ep_out)
+ ep_out = ep;
+ }
}
- /* Is it an interrupt endpoint? */
- else if (usb_endpoint_xfer_int(ep)) {
- ep_int = ep;
+ else if (usb_endpoint_is_int_in(ep)) {
+ if (!ep_int)
+ ep_int = ep;
}
}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 7a43020fa58..45fe65d8d7a 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -541,6 +541,7 @@ config FB_TGA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select BITREVERSE
help
This is the frame buffer device driver for generic TGA graphic
cards. Say Y if you have one of those.
@@ -551,6 +552,7 @@ config FB_VESA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_SELECT
help
This is the frame buffer device driver for generic VESA 2.0
compliant graphic cards. The older VESA 1.2 cards are not supported.
@@ -705,6 +707,7 @@ config FB_NVIDIA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select BITREVERSE
help
This driver supports graphics boards with the nVidia chips, TNT
and newer. For very old chipsets, such as the RIVA128, then use
@@ -744,6 +747,7 @@ config FB_RIVA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select BITREVERSE
help
This driver supports graphics boards with the nVidia Riva/Geforce
chips.
@@ -1440,8 +1444,8 @@ config FB_PMAG_AA
used mainly in the MIPS-based DECstation series.
config FB_PMAG_BA
- bool "PMAG-BA TURBOchannel framebuffer support"
- depends on (FB = y) && TC
+ tristate "PMAG-BA TURBOchannel framebuffer support"
+ depends on FB && TC
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1450,8 +1454,8 @@ config FB_PMAG_BA
used mainly in the MIPS-based DECstation series.
config FB_PMAGB_B
- bool "PMAGB-B TURBOchannel framebuffer support"
- depends on (FB = y) && TC
+ tristate "PMAGB-B TURBOchannel framebuffer support"
+ depends on TC
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1611,6 +1615,16 @@ config FB_PNX4008_DUM_RGB
---help---
Say Y here to enable support for PNX4008 RGB Framebuffer
+config FB_IBM_GXT4500
+ tristate "Framebuffer support for IBM GXT4500P adaptor"
+ depends on PPC
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Say Y here to enable support for the IBM GXT4500P display
+ adaptor, found on some IBM System P (pSeries) machines.
+
config FB_VIRTUAL
tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a6980e9a248..309a26dd164 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -99,6 +99,7 @@ obj-$(CONFIG_FB_IMX) += imxfb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
+obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_VESA) += vesafb.o
diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c
index 397005eb392..b3717c8f1bc 100644
--- a/drivers/video/S3triofb.c
+++ b/drivers/video/S3triofb.c
@@ -535,8 +535,11 @@ static void __init s3triofb_of_init(struct device_node *dp)
#endif
fb_info.flags = FBINFO_FLAG_DEFAULT;
- if (register_framebuffer(&fb_info) < 0)
- return;
+ if (register_framebuffer(&fb_info) < 0) {
+ iounmap(fb_info.screen_base);
+ fb_info.screen_base = NULL;
+ return;
+ }
printk("fb%d: S3 Trio frame buffer device on %s\n",
fb_info.node, dp->full_name);
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 6761b68c35e..6c9dc2e69c8 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -447,7 +447,7 @@ static int clcdfb_probe(struct amba_device *dev, void *id)
goto out;
}
- fb = (struct clcd_fb *) kmalloc(sizeof(struct clcd_fb), GFP_KERNEL);
+ fb = kmalloc(sizeof(struct clcd_fb), GFP_KERNEL);
if (!fb) {
printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n");
ret = -ENOMEM;
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index a4e3fca0589..1a849b870bc 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -2407,10 +2407,10 @@ default_chipset:
fb_info.fix.smem_len);
if (!videomemory) {
printk("amifb: WARNING! unable to map videomem cached writethrough\n");
- videomemory = ZTWO_VADDR(fb_info.fix.smem_start);
- }
+ fb_info.screen_base = (char *)ZTWO_VADDR(fb_info.fix.smem_start);
+ } else
+ fb_info.screen_base = (char *)videomemory;
- fb_info.screen_base = (char *)videomemory;
memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
/*
@@ -2453,6 +2453,8 @@ static void amifb_deinit(void)
{
fb_dealloc_cmap(&fb_info.cmap);
chipfree();
+ if (videomemory)
+ iounmap((void*)videomemory);
release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
custom.dmacon = DMAF_ALL | DMAF_MASTER;
}
@@ -2904,14 +2906,6 @@ static int ami_decode_var(struct fb_var_screeninfo *var,
par->crsr.spot_x = par->crsr.spot_y = 0;
par->crsr.height = par->crsr.width = 0;
-#if 0 /* fbmon not done. uncomment for 2.5.x -brad */
- if (!fbmon_valid_timings(pixclock[clk_shift], htotal, vtotal,
- &fb_info)) {
- DPRINTK("mode doesn't fit for monitor\n");
- return -EINVAL;
- }
-#endif
-
return 0;
}
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index ab34b96acc3..30a8369757e 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -454,7 +454,7 @@ static ssize_t arcfb_write(struct file *file, const char __user *buf, size_t cou
unsigned int xres;
p = *ppos;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
fbidx = iminor(inode);
info = registered_fb[fbidx];
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 02c41a626fa..602db660bc7 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -2804,8 +2804,19 @@ int __init atafb_init(void)
atafb_set_disp(-1, &fb_info);
do_install_cmap(0, &fb_info);
- if (register_framebuffer(&fb_info) < 0)
+ if (register_framebuffer(&fb_info) < 0) {
+#ifdef ATAFB_EXT
+ if (external_addr) {
+ iounmap(external_addr);
+ external_addr = NULL;
+ }
+ if (external_vgaiobase) {
+ iounmap((void*)external_vgaiobase);
+ external_vgaiobase = 0;
+ }
+#endif
return -EINVAL;
+ }
printk("Determined %dx%d, depth %d\n",
disp.var.xres, disp.var.yres, disp.var.bits_per_pixel);
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 276a21530b9..2e976ffcde0 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1333,6 +1333,8 @@ static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
if (vclk * 12 < c.ppll_min)
vclk = c.ppll_min/12;
+ pll->post_divider = -1;
+
/* now, find an acceptable divider */
for (i = 0; i < sizeof(post_dividers); i++) {
output_freq = post_dividers[i] * vclk;
@@ -1342,6 +1344,9 @@ static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
}
}
+ if (pll->post_divider < 0)
+ return -EINVAL;
+
/* calculate feedback divider */
n = c.ref_divider * output_freq;
d = c.ref_clk;
@@ -1829,7 +1834,7 @@ static void aty128_bl_init(struct aty128fb_par *par)
snprintf(name, sizeof(name), "aty128bl%d", info->node);
- bd = backlight_device_register(name, par, &aty128_bl_data);
+ bd = backlight_device_register(name, info->dev, par, &aty128_bl_data);
if (IS_ERR(bd)) {
info->bl_dev = NULL;
printk(KERN_WARNING "aty128: Backlight registration failed\n");
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index b04f49fb976..f72faff33c0 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -126,7 +126,6 @@ union aty_pll {
*/
struct atyfb_par {
- struct aty_cmap_regs __iomem *aty_cmap_regs;
struct { u8 red, green, blue; } palette[256];
const struct aty_dac_ops *dac_ops;
const struct aty_pll_ops *pll_ops;
@@ -186,6 +185,7 @@ struct atyfb_par {
int mtrr_aper;
int mtrr_reg;
#endif
+ u32 mem_cntl;
};
/*
@@ -227,7 +227,7 @@ static inline u32 aty_ld_le32(int regindex, const struct atyfb_par *par)
regindex -= 0x800;
#ifdef CONFIG_ATARI
- return in_le32((volatile u32 *)(par->ati_regbase + regindex));
+ return in_le32(par->ati_regbase + regindex);
#else
return readl(par->ati_regbase + regindex);
#endif
@@ -240,7 +240,7 @@ static inline void aty_st_le32(int regindex, u32 val, const struct atyfb_par *pa
regindex -= 0x800;
#ifdef CONFIG_ATARI
- out_le32((volatile u32 *)(par->ati_regbase + regindex), val);
+ out_le32(par->ati_regbase + regindex, val);
#else
writel(val, par->ati_regbase + regindex);
#endif
@@ -253,7 +253,7 @@ static inline void aty_st_le16(int regindex, u16 val,
if (regindex >= 0x400)
regindex -= 0x800;
#ifdef CONFIG_ATARI
- out_le16((volatile u16 *)(par->ati_regbase + regindex), val);
+ out_le16(par->ati_regbase + regindex, val);
#else
writel(val, par->ati_regbase + regindex);
#endif
@@ -315,6 +315,7 @@ struct aty_pll_ops {
void (*set_pll) (const struct fb_info * info, const union aty_pll * pll);
void (*get_pll) (const struct fb_info *info, union aty_pll * pll);
int (*init_pll) (const struct fb_info * info, union aty_pll * pll);
+ void (*resume_pll)(const struct fb_info *info, union aty_pll *pll);
};
extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index e815b354c09..f2ebdd88008 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -203,14 +203,6 @@ static void ATIReduceRatio(int *Numerator, int *Denominator)
* The Hardware parameters for each card
*/
-struct aty_cmap_regs {
- u8 windex;
- u8 lut;
- u8 mask;
- u8 rindex;
- u8 cntl;
-};
-
struct pci_mmap_map {
unsigned long voff;
unsigned long poff;
@@ -249,7 +241,8 @@ static int atyfb_sync(struct fb_info *info);
* Internal routines
*/
-static int aty_init(struct fb_info *info, const char *name);
+static int aty_init(struct fb_info *info);
+static void aty_resume_chip(struct fb_info *info);
#ifdef CONFIG_ATARI
static int store_video_par(char *videopar, unsigned char m64_num);
#endif
@@ -1495,10 +1488,6 @@ static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
else
info->var.accel_flags = 0;
-#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */
- if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
- return -EINVAL;
-#endif
aty_crtc_to_var(&crtc, var);
var->pixclock = par->pll_ops->pll_to_var(info, &pll);
return 0;
@@ -1937,17 +1926,14 @@ static void atyfb_save_palette(struct atyfb_par *par, int enter)
aty_st_8(DAC_CNTL, tmp, par);
aty_st_8(DAC_MASK, 0xff, par);
- writeb(i, &par->aty_cmap_regs->rindex);
- atyfb_save.r[enter][i] = readb(&par->aty_cmap_regs->lut);
- atyfb_save.g[enter][i] = readb(&par->aty_cmap_regs->lut);
- atyfb_save.b[enter][i] = readb(&par->aty_cmap_regs->lut);
- writeb(i, &par->aty_cmap_regs->windex);
- writeb(atyfb_save.r[1 - enter][i],
- &par->aty_cmap_regs->lut);
- writeb(atyfb_save.g[1 - enter][i],
- &par->aty_cmap_regs->lut);
- writeb(atyfb_save.b[1 - enter][i],
- &par->aty_cmap_regs->lut);
+ aty_st_8(DAC_R_INDEX, i, par);
+ atyfb_save.r[enter][i] = aty_ld_8(DAC_DATA, par);
+ atyfb_save.g[enter][i] = aty_ld_8(DAC_DATA, par);
+ atyfb_save.b[enter][i] = aty_ld_8(DAC_DATA, par);
+ aty_st_8(DAC_W_INDEX, i, par);
+ aty_st_8(DAC_DATA, atyfb_save.r[1 - enter][i], par);
+ aty_st_8(DAC_DATA, atyfb_save.g[1 - enter][i], par);
+ aty_st_8(DAC_DATA, atyfb_save.b[1 - enter][i], par);
}
}
@@ -1982,6 +1968,7 @@ static void atyfb_palette(int enter)
#if defined(CONFIG_PM) && defined(CONFIG_PCI)
+#ifdef CONFIG_PPC_PMAC
/* Power management routines. Those are used for PowerBook sleep.
*/
static int aty_power_mgmt(int sleep, struct atyfb_par *par)
@@ -2038,21 +2025,13 @@ static int aty_power_mgmt(int sleep, struct atyfb_par *par)
return timeout ? 0 : -EIO;
}
+#endif
static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct fb_info *info = pci_get_drvdata(pdev);
struct atyfb_par *par = (struct atyfb_par *) info->par;
-#ifndef CONFIG_PPC_PMAC
- /* HACK ALERT ! Once I find a proper way to say to each driver
- * individually what will happen with it's PCI slot, I'll change
- * that. On laptops, the AGP slot is just unclocked, so D2 is
- * expected, while on desktops, the card is powered off
- */
- return 0;
-#endif /* CONFIG_PPC_PMAC */
-
if (state.event == pdev->dev.power.power_state.event)
return 0;
@@ -2070,6 +2049,7 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
par->asleep = 1;
par->lock_blank = 1;
+#ifdef CONFIG_PPC_PMAC
/* Set chip to "suspend" mode */
if (aty_power_mgmt(1, par)) {
par->asleep = 0;
@@ -2079,6 +2059,9 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
release_console_sem();
return -EIO;
}
+#else
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+#endif
release_console_sem();
@@ -2097,8 +2080,15 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
acquire_console_sem();
+#ifdef CONFIG_PPC_PMAC
if (pdev->dev.power.power_state.event == 2)
aty_power_mgmt(0, par);
+#else
+ pci_set_power_state(pdev, PCI_D0);
+#endif
+
+ aty_resume_chip(info);
+
par->asleep = 0;
/* Restore display */
@@ -2221,7 +2211,7 @@ static void aty_bl_init(struct atyfb_par *par)
snprintf(name, sizeof(name), "atybl%d", info->node);
- bd = backlight_device_register(name, par, &aty_bl_data);
+ bd = backlight_device_register(name, info->dev, par, &aty_bl_data);
if (IS_ERR(bd)) {
info->bl_dev = NULL;
printk(KERN_WARNING "aty: Backlight registration failed\n");
@@ -2344,24 +2334,16 @@ static int __devinit atyfb_get_timings_from_lcd(struct atyfb_par *par,
}
#endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */
-static int __devinit aty_init(struct fb_info *info, const char *name)
+static int __devinit aty_init(struct fb_info *info)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
const char *ramname = NULL, *xtal;
int gtb_memsize, has_var = 0;
struct fb_var_screeninfo var;
- u8 pll_ref_div;
- u32 i;
-#if defined(CONFIG_PPC)
- int sense;
-#endif
init_waitqueue_head(&par->vblank.wait);
spin_lock_init(&par->int_lock);
- par->aty_cmap_regs =
- (struct aty_cmap_regs __iomem *) (par->ati_regbase + 0xc0);
-
#ifdef CONFIG_PPC_PMAC
/* The Apple iBook1 uses non-standard memory frequencies. We detect it
* and set the frequency manually. */
@@ -2464,18 +2446,21 @@ static int __devinit aty_init(struct fb_info *info, const char *name)
par->pll_limits.mclk = 63;
}
- if (M64_HAS(GTB_DSP)
- && (pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par))) {
- int diff1, diff2;
- diff1 = 510 * 14 / pll_ref_div - par->pll_limits.pll_max;
- diff2 = 510 * 29 / pll_ref_div - par->pll_limits.pll_max;
- if (diff1 < 0)
- diff1 = -diff1;
- if (diff2 < 0)
- diff2 = -diff2;
- if (diff2 < diff1) {
- par->ref_clk_per = 1000000000000ULL / 29498928;
- xtal = "29.498928";
+ if (M64_HAS(GTB_DSP)) {
+ u8 pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
+
+ if (pll_ref_div) {
+ int diff1, diff2;
+ diff1 = 510 * 14 / pll_ref_div - par->pll_limits.pll_max;
+ diff2 = 510 * 29 / pll_ref_div - par->pll_limits.pll_max;
+ if (diff1 < 0)
+ diff1 = -diff1;
+ if (diff2 < 0)
+ diff2 = -diff2;
+ if (diff2 < diff1) {
+ par->ref_clk_per = 1000000000000ULL / 29498928;
+ xtal = "29.498928";
+ }
}
}
#endif /* CONFIG_FB_ATY_CT */
@@ -2485,10 +2470,10 @@ static int __devinit aty_init(struct fb_info *info, const char *name)
if(par->pll_ops->get_pll)
par->pll_ops->get_pll(info, &saved_pll);
- i = aty_ld_le32(MEM_CNTL, par);
+ par->mem_cntl = aty_ld_le32(MEM_CNTL, par);
gtb_memsize = M64_HAS(GTB_DSP);
if (gtb_memsize)
- switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
+ switch (par->mem_cntl & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
case MEM_SIZE_512K:
info->fix.smem_len = 0x80000;
break;
@@ -2510,7 +2495,7 @@ static int __devinit aty_init(struct fb_info *info, const char *name)
default:
info->fix.smem_len = 0x80000;
} else
- switch (i & MEM_SIZE_ALIAS) {
+ switch (par->mem_cntl & MEM_SIZE_ALIAS) {
case MEM_SIZE_512K:
info->fix.smem_len = 0x80000;
break;
@@ -2540,20 +2525,20 @@ static int __devinit aty_init(struct fb_info *info, const char *name)
if (vram) {
info->fix.smem_len = vram * 1024;
- i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
+ par->mem_cntl &= ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
if (info->fix.smem_len <= 0x80000)
- i |= MEM_SIZE_512K;
+ par->mem_cntl |= MEM_SIZE_512K;
else if (info->fix.smem_len <= 0x100000)
- i |= MEM_SIZE_1M;
+ par->mem_cntl |= MEM_SIZE_1M;
else if (info->fix.smem_len <= 0x200000)
- i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
+ par->mem_cntl |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
else if (info->fix.smem_len <= 0x400000)
- i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
+ par->mem_cntl |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
else if (info->fix.smem_len <= 0x600000)
- i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
+ par->mem_cntl |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
else
- i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
- aty_st_le32(MEM_CNTL, i, par);
+ par->mem_cntl |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
+ aty_st_le32(MEM_CNTL, par->mem_cntl, par);
}
/*
@@ -2599,11 +2584,12 @@ static int __devinit aty_init(struct fb_info *info, const char *name)
#endif
if(par->pll_ops->init_pll)
par->pll_ops->init_pll(info, &par->pll);
+ if (par->pll_ops->resume_pll)
+ par->pll_ops->resume_pll(info, &par->pll);
/*
- * Last page of 8 MB (4 MB on ISA) aperture is MMIO
- * FIXME: we should use the auxiliary aperture instead so we can access
- * the full 8 MB of video RAM on 8 MB boards
+ * Last page of 8 MB (4 MB on ISA) aperture is MMIO,
+ * unless the auxiliary register aperture is used.
*/
if (!par->aux_start &&
@@ -2669,6 +2655,7 @@ static int __devinit aty_init(struct fb_info *info, const char *name)
has_var = 1;
} else {
if (default_vmode == VMODE_CHOOSE) {
+ int sense;
if (M64_HAS(G3_PB_1024x768))
/* G3 PowerBook with 1024x768 LCD */
default_vmode = VMODE_1024_768_60;
@@ -2749,7 +2736,7 @@ static int __devinit aty_init(struct fb_info *info, const char *name)
fb_list = info;
PRINTKI("fb%d: %s frame buffer device on %s\n",
- info->node, info->fix.id, name);
+ info->node, info->fix.id, par->bus_type == ISA ? "ISA" : "PCI");
return 0;
aty_init_exit:
@@ -2770,6 +2757,19 @@ aty_init_exit:
return -1;
}
+static void aty_resume_chip(struct fb_info *info)
+{
+ struct atyfb_par *par = info->par;
+
+ aty_st_le32(MEM_CNTL, par->mem_cntl, par);
+
+ if (par->pll_ops->resume_pll)
+ par->pll_ops->resume_pll(info, &par->pll);
+
+ if (par->aux_start)
+ aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);
+}
+
#ifdef CONFIG_ATARI
static int __devinit store_video_par(char *video_str, unsigned char m64_num)
{
@@ -2826,9 +2826,9 @@ static int atyfb_blank(int blank, struct fb_info *info)
#endif
gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
+ gen_cntl &= ~0x400004c;
switch (blank) {
- case FB_BLANK_UNBLANK:
- gen_cntl &= ~0x400004c;
+ case FB_BLANK_UNBLANK:
break;
case FB_BLANK_NORMAL:
gen_cntl |= 0x4000040;
@@ -2863,17 +2863,10 @@ static int atyfb_blank(int blank, struct fb_info *info)
static void aty_st_pal(u_int regno, u_int red, u_int green, u_int blue,
const struct atyfb_par *par)
{
-#ifdef CONFIG_ATARI
- out_8(&par->aty_cmap_regs->windex, regno);
- out_8(&par->aty_cmap_regs->lut, red);
- out_8(&par->aty_cmap_regs->lut, green);
- out_8(&par->aty_cmap_regs->lut, blue);
-#else
- writeb(regno, &par->aty_cmap_regs->windex);
- writeb(red, &par->aty_cmap_regs->lut);
- writeb(green, &par->aty_cmap_regs->lut);
- writeb(blue, &par->aty_cmap_regs->lut);
-#endif
+ aty_st_8(DAC_W_INDEX, regno, par);
+ aty_st_8(DAC_DATA, red, par);
+ aty_st_8(DAC_DATA, green, par);
+ aty_st_8(DAC_DATA, blue, par);
}
/*
@@ -3182,7 +3175,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
#ifdef __i386__
#ifdef CONFIG_FB_ATY_GENERIC_LCD
-static void aty_init_lcd(struct atyfb_par *par, u32 bios_base)
+static void __devinit aty_init_lcd(struct atyfb_par *par, u32 bios_base)
{
u32 driv_inf_tab, sig;
u16 lcd_ofs;
@@ -3527,6 +3520,10 @@ static int __devinit atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *i
atyfb_setup_generic_fail:
iounmap(par->ati_regbase);
par->ati_regbase = NULL;
+ if (info->screen_base) {
+ iounmap(info->screen_base);
+ info->screen_base = NULL;
+ }
return ret;
}
@@ -3594,7 +3591,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
pci_set_drvdata(pdev, info);
/* Init chip & register framebuffer */
- if (aty_init(info, "PCI"))
+ if (aty_init(info))
goto err_release_io;
#ifdef __sparc__
@@ -3641,12 +3638,13 @@ err_release_mem:
#ifdef CONFIG_ATARI
-static int __devinit atyfb_atari_probe(void)
+static int __init atyfb_atari_probe(void)
{
struct atyfb_par *par;
struct fb_info *info;
int m64_num;
u32 clock_r;
+ int num_found = 0;
for (m64_num = 0; m64_num < mach64_count; m64_num++) {
if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
@@ -3694,16 +3692,34 @@ static int __devinit atyfb_atari_probe(void)
break;
}
- if (aty_init(info, "ISA bus")) {
+ /* Fake pci_id for correct_chipset() */
+ switch (aty_ld_le32(CONFIG_CHIP_ID, par) & CFG_CHIP_TYPE) {
+ case 0x00d7:
+ par->pci_id = PCI_CHIP_MACH64GX;
+ break;
+ case 0x0057:
+ par->pci_id = PCI_CHIP_MACH64CX;
+ break;
+ default:
+ break;
+ }
+
+ if (correct_chipset(par) || aty_init(info)) {
+ iounmap(info->screen_base);
+ iounmap(par->ati_regbase);
framebuffer_release(info);
- /* This is insufficient! kernel_map has added two large chunks!! */
- return -ENXIO;
+ } else {
+ num_found++;
}
}
+
+ return num_found ? 0 : -ENXIO;
}
#endif /* CONFIG_ATARI */
+#ifdef CONFIG_PCI
+
static void __devexit atyfb_remove(struct fb_info *info)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
@@ -3751,7 +3767,6 @@ static void __devexit atyfb_remove(struct fb_info *info)
framebuffer_release(info);
}
-#ifdef CONFIG_PCI
static void __devexit atyfb_pci_remove(struct pci_dev *pdev)
{
@@ -3786,7 +3801,7 @@ static struct pci_driver atyfb_driver = {
#endif /* CONFIG_PCI */
#ifndef MODULE
-static int __devinit atyfb_setup(char *options)
+static int __init atyfb_setup(char *options)
{
char *this_opt;
@@ -3858,7 +3873,7 @@ static int __devinit atyfb_setup(char *options)
}
#endif /* MODULE */
-static int __devinit atyfb_init(void)
+static int __init atyfb_init(void)
{
int err1 = 1, err2 = 1;
#ifndef MODULE
diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
index 5080816be65..f3b487b8710 100644
--- a/drivers/video/aty/mach64_ct.c
+++ b/drivers/video/aty/mach64_ct.c
@@ -370,8 +370,8 @@ void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll)
#endif
}
-static void __init aty_get_pll_ct(const struct fb_info *info,
- union aty_pll *pll)
+static void __devinit aty_get_pll_ct(const struct fb_info *info,
+ union aty_pll *pll)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
u8 tmp, clock;
@@ -394,12 +394,12 @@ static void __init aty_get_pll_ct(const struct fb_info *info,
}
}
-static int __init aty_init_pll_ct(const struct fb_info *info,
- union aty_pll *pll)
+static int __devinit aty_init_pll_ct(const struct fb_info *info,
+ union aty_pll *pll)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
- u8 mpost_div, xpost_div, sclk_post_div_real, sclk_fb_div, spll_cntl2;
- u32 q, i, memcntl, trp;
+ u8 mpost_div, xpost_div, sclk_post_div_real;
+ u32 q, memcntl, trp;
u32 dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off;
#ifdef DEBUG
int pllmclk, pllsclk;
@@ -575,14 +575,30 @@ static int __init aty_init_pll_ct(const struct fb_info *info,
mpost_div += (q < 32*8);
}
sclk_post_div_real = postdividers[mpost_div];
- sclk_fb_div = q * sclk_post_div_real / 8;
- spll_cntl2 = mpost_div << 4;
+ pll->ct.sclk_fb_div = q * sclk_post_div_real / 8;
+ pll->ct.spll_cntl2 = mpost_div << 4;
#ifdef DEBUG
- pllsclk = (1000000 * 2 * sclk_fb_div) /
+ pllsclk = (1000000 * 2 * pll->ct.sclk_fb_div) /
(par->ref_clk_per * pll->ct.pll_ref_div);
printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
__FUNCTION__, pllsclk, pllsclk / sclk_post_div_real);
#endif
+ }
+
+ /* Disable the extra precision pixel clock controls since we do not use them. */
+ pll->ct.ext_vpll_cntl = aty_ld_pll_ct(EXT_VPLL_CNTL, par);
+ pll->ct.ext_vpll_cntl &= ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC);
+
+ return 0;
+}
+
+static void aty_resume_pll_ct(const struct fb_info *info,
+ union aty_pll *pll)
+{
+ struct atyfb_par *par = info->par;
+
+ if (par->mclk_per != par->xclk_per) {
+ int i;
/*
* This disables the sclk, crashes the computer as reported:
* aty_st_pll_ct(SPLL_CNTL2, 3, info);
@@ -590,8 +606,8 @@ static int __init aty_init_pll_ct(const struct fb_info *info,
* So it seems the sclk must be enabled before it is used;
* so PLL_GEN_CNTL must be programmed *after* the sclk.
*/
- aty_st_pll_ct(SCLK_FB_DIV, sclk_fb_div, par);
- aty_st_pll_ct(SPLL_CNTL2, spll_cntl2, par);
+ aty_st_pll_ct(SCLK_FB_DIV, pll->ct.sclk_fb_div, par);
+ aty_st_pll_ct(SPLL_CNTL2, pll->ct.spll_cntl2, par);
/*
* The sclk has been started. However, I believe the first clock
* ticks it generates are not very stable. Hope this primitive loop
@@ -605,11 +621,7 @@ static int __init aty_init_pll_ct(const struct fb_info *info,
aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
aty_st_pll_ct(MCLK_FB_DIV, pll->ct.mclk_fb_div, par);
aty_st_pll_ct(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par);
- /* Disable the extra precision pixel clock controls since we do not use them. */
- aty_st_pll_ct(EXT_VPLL_CNTL, aty_ld_pll_ct(EXT_VPLL_CNTL, par) &
- ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC), par);
-
- return 0;
+ aty_st_pll_ct(EXT_VPLL_CNTL, pll->ct.ext_vpll_cntl, par);
}
static int dummy(void)
@@ -626,5 +638,6 @@ const struct aty_pll_ops aty_pll_ct = {
.pll_to_var = aty_pll_to_var_ct,
.set_pll = aty_set_pll_ct,
.get_pll = aty_get_pll_ct,
- .init_pll = aty_init_pll_ct
+ .init_pll = aty_init_pll_ct,
+ .resume_pll = aty_resume_pll_ct,
};
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 585eb7b9e63..3abfd4a380c 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -163,7 +163,7 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
- bd = backlight_device_register(name, pdata, &radeon_bl_data);
+ bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data);
if (IS_ERR(bd)) {
rinfo->info->bl_dev = NULL;
printk("radeonfb: Backlight registration failed\n");
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
index 869725a13c2..e7c5b219ad1 100644
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -120,19 +120,19 @@ void radeon_create_i2c_busses(struct radeonfb_info *rinfo)
void radeon_delete_i2c_busses(struct radeonfb_info *rinfo)
{
if (rinfo->i2c[0].rinfo)
- i2c_bit_del_bus(&rinfo->i2c[0].adapter);
+ i2c_del_adapter(&rinfo->i2c[0].adapter);
rinfo->i2c[0].rinfo = NULL;
if (rinfo->i2c[1].rinfo)
- i2c_bit_del_bus(&rinfo->i2c[1].adapter);
+ i2c_del_adapter(&rinfo->i2c[1].adapter);
rinfo->i2c[1].rinfo = NULL;
if (rinfo->i2c[2].rinfo)
- i2c_bit_del_bus(&rinfo->i2c[2].adapter);
+ i2c_del_adapter(&rinfo->i2c[2].adapter);
rinfo->i2c[2].rinfo = NULL;
if (rinfo->i2c[3].rinfo)
- i2c_bit_del_bus(&rinfo->i2c[3].adapter);
+ i2c_del_adapter(&rinfo->i2c[3].adapter);
rinfo->i2c[3].rinfo = NULL;
}
diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
index ea531a6f45d..38c7dbf8c15 100644
--- a/drivers/video/aty/radeon_monitor.c
+++ b/drivers/video/aty/radeon_monitor.c
@@ -104,10 +104,9 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_
if (pedid == NULL)
return mt;
- tmp = (u8 *)kmalloc(EDID_LENGTH, GFP_KERNEL);
+ tmp = kmemdup(pedid, EDID_LENGTH, GFP_KERNEL);
if (!tmp)
return mt;
- memcpy(tmp, pedid, EDID_LENGTH);
*out_EDID = tmp;
return mt;
}
diff --git a/drivers/video/au1100fb.h b/drivers/video/au1100fb.h
index 2855534dc23..164fe2f231e 100644
--- a/drivers/video/au1100fb.h
+++ b/drivers/video/au1100fb.h
@@ -274,7 +274,7 @@ static struct au1100fb_panel known_lcd_panels[] =
.bpp = 16,
.control_base = 0x0004886A |
LCD_CONTROL_DEFAULT_PO | LCD_CONTROL_DEFAULT_SBPPF |
- LCD_CONTROL_BPP_16,
+ LCD_CONTROL_BPP_16 | LCD_CONTROL_SBB_4,
.clkcontrol_base = 0x00020000,
.horztiming = 0x005aff1f,
.verttiming = 0x16000e57,
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 27597c576ef..9601bfe309a 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -14,6 +14,59 @@
#include <linux/err.h>
#include <linux/fb.h>
+
+#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
+ defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
+/* This callback gets called when something important happens inside a
+ * framebuffer driver. We're looking if that important event is blanking,
+ * and if it is, we're switching backlight power as well ...
+ */
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct backlight_device *bd;
+ struct fb_event *evdata = data;
+
+ /* If we aren't interested in this event, skip it immediately ... */
+ if (event != FB_EVENT_BLANK)
+ return 0;
+
+ bd = container_of(self, struct backlight_device, fb_notif);
+ down(&bd->sem);
+ if (bd->props)
+ if (!bd->props->check_fb ||
+ bd->props->check_fb(evdata->info)) {
+ bd->props->fb_blank = *(int *)evdata->data;
+ if (likely(bd->props && bd->props->update_status))
+ bd->props->update_status(bd);
+ }
+ up(&bd->sem);
+ return 0;
+}
+
+static int backlight_register_fb(struct backlight_device *bd)
+{
+ memset(&bd->fb_notif, 0, sizeof(bd->fb_notif));
+ bd->fb_notif.notifier_call = fb_notifier_callback;
+
+ return fb_register_client(&bd->fb_notif);
+}
+
+static void backlight_unregister_fb(struct backlight_device *bd)
+{
+ fb_unregister_client(&bd->fb_notif);
+}
+#else
+static inline int backlight_register_fb(struct backlight_device *bd)
+{
+ return 0;
+}
+
+static inline void backlight_unregister_fb(struct backlight_device *bd)
+{
+}
+#endif /* CONFIG_FB */
+
static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
{
int rc = -ENXIO;
@@ -142,7 +195,7 @@ static struct class backlight_class = {
.store = _store, \
}
-static struct class_device_attribute bl_class_device_attributes[] = {
+static const struct class_device_attribute bl_class_device_attributes[] = {
DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power),
DECLARE_ATTR(brightness, 0644, backlight_show_brightness,
backlight_store_brightness),
@@ -151,33 +204,6 @@ static struct class_device_attribute bl_class_device_attributes[] = {
DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
};
-/* This callback gets called when something important happens inside a
- * framebuffer driver. We're looking if that important event is blanking,
- * and if it is, we're switching backlight power as well ...
- */
-static int fb_notifier_callback(struct notifier_block *self,
- unsigned long event, void *data)
-{
- struct backlight_device *bd;
- struct fb_event *evdata =(struct fb_event *)data;
-
- /* If we aren't interested in this event, skip it immediately ... */
- if (event != FB_EVENT_BLANK)
- return 0;
-
- bd = container_of(self, struct backlight_device, fb_notif);
- down(&bd->sem);
- if (bd->props)
- if (!bd->props->check_fb ||
- bd->props->check_fb(evdata->info)) {
- bd->props->fb_blank = *(int *)evdata->data;
- if (likely(bd->props && bd->props->update_status))
- bd->props->update_status(bd);
- }
- up(&bd->sem);
- return 0;
-}
-
/**
* backlight_device_register - create and register a new object of
* backlight_device class.
@@ -190,8 +216,10 @@ static int fb_notifier_callback(struct notifier_block *self,
* Creates and registers new backlight class_device. Returns either an
* ERR_PTR() or a pointer to the newly allocated device.
*/
-struct backlight_device *backlight_device_register(const char *name, void *devdata,
- struct backlight_properties *bp)
+struct backlight_device *backlight_device_register(const char *name,
+ struct device *dev,
+ void *devdata,
+ struct backlight_properties *bp)
{
int i, rc;
struct backlight_device *new_bd;
@@ -206,6 +234,7 @@ struct backlight_device *backlight_device_register(const char *name, void *devda
new_bd->props = bp;
memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev));
new_bd->class_dev.class = &backlight_class;
+ new_bd->class_dev.dev = dev;
strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
class_set_devdata(&new_bd->class_dev, devdata);
@@ -215,10 +244,7 @@ error: kfree(new_bd);
return ERR_PTR(rc);
}
- memset(&new_bd->fb_notif, 0, sizeof(new_bd->fb_notif));
- new_bd->fb_notif.notifier_call = fb_notifier_callback;
-
- rc = fb_register_client(&new_bd->fb_notif);
+ rc = backlight_register_fb(new_bd);
if (unlikely(rc))
goto error;
@@ -259,16 +285,10 @@ void backlight_device_unregister(struct backlight_device *bd)
&bl_class_device_attributes[i]);
down(&bd->sem);
- if (likely(bd->props && bd->props->update_status)) {
- bd->props->brightness = 0;
- bd->props->power = 0;
- bd->props->update_status(bd);
- }
-
bd->props = NULL;
up(&bd->sem);
- fb_unregister_client(&bd->fb_notif);
+ backlight_unregister_fb(bd);
class_device_unregister(&bd->class_dev);
}
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
index d07ecb53c68..fde1d951812 100644
--- a/drivers/video/backlight/corgi_bl.c
+++ b/drivers/video/backlight/corgi_bl.c
@@ -121,7 +121,7 @@ static int corgibl_probe(struct platform_device *pdev)
machinfo->limit_mask = -1;
corgi_backlight_device = backlight_device_register ("corgi-bl",
- NULL, &corgibl_data);
+ &pdev->dev, NULL, &corgibl_data);
if (IS_ERR (corgi_backlight_device))
return PTR_ERR (corgi_backlight_device);
@@ -135,6 +135,10 @@ static int corgibl_probe(struct platform_device *pdev)
static int corgibl_remove(struct platform_device *dev)
{
+ corgibl_data.power = 0;
+ corgibl_data.brightness = 0;
+ corgibl_send_intensity(corgi_backlight_device);
+
backlight_device_unregister(corgi_backlight_device);
printk("Corgi Backlight Driver Unloaded\n");
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index e3993213d10..c07d8207fb5 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -105,7 +105,7 @@ static struct backlight_properties hp680bl_data = {
static int __init hp680bl_probe(struct platform_device *dev)
{
hp680_backlight_device = backlight_device_register ("hp680-bl",
- NULL, &hp680bl_data);
+ &dev->dev, NULL, &hp680bl_data);
if (IS_ERR (hp680_backlight_device))
return PTR_ERR (hp680_backlight_device);
@@ -117,6 +117,10 @@ static int __init hp680bl_probe(struct platform_device *dev)
static int hp680bl_remove(struct platform_device *dev)
{
+ hp680bl_data.brightness = 0;
+ hp680bl_data.power = 0;
+ hp680bl_send_intensity(hp680_backlight_device);
+
backlight_device_unregister(hp680_backlight_device);
return 0;
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index bc8ab005a3f..f6e041627ed 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -14,6 +14,53 @@
#include <linux/err.h>
#include <linux/fb.h>
+#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
+ defined(CONFIG_LCD_CLASS_DEVICE_MODULE))
+/* This callback gets called when something important happens inside a
+ * framebuffer driver. We're looking if that important event is blanking,
+ * and if it is, we're switching lcd power as well ...
+ */
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct lcd_device *ld;
+ struct fb_event *evdata = data;
+
+ /* If we aren't interested in this event, skip it immediately ... */
+ if (event != FB_EVENT_BLANK)
+ return 0;
+
+ ld = container_of(self, struct lcd_device, fb_notif);
+ down(&ld->sem);
+ if (ld->props)
+ if (!ld->props->check_fb || ld->props->check_fb(evdata->info))
+ ld->props->set_power(ld, *(int *)evdata->data);
+ up(&ld->sem);
+ return 0;
+}
+
+static int lcd_register_fb(struct lcd_device *ld)
+{
+ memset(&ld->fb_notif, 0, sizeof(&ld->fb_notif));
+ ld->fb_notif.notifier_call = fb_notifier_callback;
+ return fb_register_client(&ld->fb_notif);
+}
+
+static void lcd_unregister_fb(struct lcd_device *ld)
+{
+ fb_unregister_client(&ld->fb_notif);
+}
+#else
+static int lcd_register_fb(struct lcd_device *ld)
+{
+ return 0;
+}
+
+static inline void lcd_unregister_fb(struct lcd_device *ld)
+{
+}
+#endif /* CONFIG_FB */
+
static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
{
int rc;
@@ -121,35 +168,12 @@ static struct class lcd_class = {
.store = _store, \
}
-static struct class_device_attribute lcd_class_device_attributes[] = {
+static const struct class_device_attribute lcd_class_device_attributes[] = {
DECLARE_ATTR(power, 0644, lcd_show_power, lcd_store_power),
DECLARE_ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
DECLARE_ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
};
-/* This callback gets called when something important happens inside a
- * framebuffer driver. We're looking if that important event is blanking,
- * and if it is, we're switching lcd power as well ...
- */
-static int fb_notifier_callback(struct notifier_block *self,
- unsigned long event, void *data)
-{
- struct lcd_device *ld;
- struct fb_event *evdata =(struct fb_event *)data;
-
- /* If we aren't interested in this event, skip it immediately ... */
- if (event != FB_EVENT_BLANK)
- return 0;
-
- ld = container_of(self, struct lcd_device, fb_notif);
- down(&ld->sem);
- if (ld->props)
- if (!ld->props->check_fb || ld->props->check_fb(evdata->info))
- ld->props->set_power(ld, *(int *)evdata->data);
- up(&ld->sem);
- return 0;
-}
-
/**
* lcd_device_register - register a new object of lcd_device class.
* @name: the name of the new object(must be the same as the name of the
@@ -186,10 +210,8 @@ error: kfree(new_ld);
return ERR_PTR(rc);
}
- memset(&new_ld->fb_notif, 0, sizeof(new_ld->fb_notif));
- new_ld->fb_notif.notifier_call = fb_notifier_callback;
+ rc = lcd_register_fb(new_ld);
- rc = fb_register_client(&new_ld->fb_notif);
if (unlikely(rc))
goto error;
@@ -232,9 +254,7 @@ void lcd_device_unregister(struct lcd_device *ld)
down(&ld->sem);
ld->props = NULL;
up(&ld->sem);
-
- fb_unregister_client(&ld->fb_notif);
-
+ lcd_unregister_fb(ld);
class_device_unregister(&ld->class_dev);
}
EXPORT_SYMBOL(lcd_device_unregister);
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index 628571c63ba..fc812d96c31 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -184,7 +184,7 @@ static int locomolcd_probe(struct locomo_dev *ldev)
local_irq_restore(flags);
- locomolcd_bl_device = backlight_device_register("locomo-bl", NULL, &locomobl_data);
+ locomolcd_bl_device = backlight_device_register("locomo-bl", &ldev->dev, NULL, &locomobl_data);
if (IS_ERR (locomolcd_bl_device))
return PTR_ERR (locomolcd_bl_device);
@@ -200,6 +200,10 @@ static int locomolcd_remove(struct locomo_dev *dev)
{
unsigned long flags;
+ locomobl_data.brightness = 0;
+ locomobl_data.power = 0;
+ locomolcd_set_intensity(locomolcd_bl_device);
+
backlight_device_unregister(locomolcd_bl_device);
local_irq_save(flags);
locomolcd_dev = NULL;
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index c66e3d52cbf..9bb6257d691 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -320,7 +320,7 @@ static int __devinit bw2_init_one(struct of_device *op)
all->info.fbops = &bw2_ops;
all->info.screen_base =
- sbus_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram");
+ of_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram");
all->info.par = &all->par;
bw2_blank(0, &all->info);
@@ -329,8 +329,10 @@ static int __devinit bw2_init_one(struct of_device *op)
err= register_framebuffer(&all->info);
if (err < 0) {
- of_iounmap(all->par.regs, sizeof(struct bw2_regs));
- of_iounmap(all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0],
+ all->par.regs, sizeof(struct bw2_regs));
+ of_iounmap(&op->resource[0],
+ all->info.screen_base, all->par.fbsize);
kfree(all);
return err;
}
@@ -351,18 +353,18 @@ static int __devinit bw2_probe(struct of_device *dev, const struct of_device_id
return bw2_init_one(op);
}
-static int __devexit bw2_remove(struct of_device *dev)
+static int __devexit bw2_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&dev->dev);
+ struct all_info *all = dev_get_drvdata(&op->dev);
unregister_framebuffer(&all->info);
- of_iounmap(all->par.regs, sizeof(struct bw2_regs));
- of_iounmap(all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0], all->par.regs, sizeof(struct bw2_regs));
+ of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize);
kfree(all);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index 51d35386a94..261004473c8 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/cfbimgblt.c
@@ -42,7 +42,7 @@
#define DPRINTK(fmt, args...)
#endif
-static u32 cfb_tab8[] = {
+static const u32 cfb_tab8[] = {
#if defined(__BIG_ENDIAN)
0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
@@ -58,7 +58,7 @@ static u32 cfb_tab8[] = {
#endif
};
-static u32 cfb_tab16[] = {
+static const u32 cfb_tab16[] = {
#if defined(__BIG_ENDIAN)
0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
#elif defined(__LITTLE_ENDIAN)
@@ -68,7 +68,7 @@ static u32 cfb_tab16[] = {
#endif
};
-static u32 cfb_tab32[] = {
+static const u32 cfb_tab32[] = {
0x00000000, 0xffffffff
};
@@ -218,7 +218,7 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
u32 bit_mask, end_mask, eorx, shift;
const char *s = image->data, *src;
u32 __iomem *dst;
- u32 *tab = NULL;
+ const u32 *tab = NULL;
int i, j, k;
switch (bpp) {
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index 7f926c619b6..ec6a51a5822 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -452,16 +452,20 @@ struct all_info {
struct cg14_par par;
};
-static void cg14_unmap_regs(struct all_info *all)
+static void cg14_unmap_regs(struct of_device *op, struct all_info *all)
{
if (all->par.regs)
- of_iounmap(all->par.regs, sizeof(struct cg14_regs));
+ of_iounmap(&op->resource[0],
+ all->par.regs, sizeof(struct cg14_regs));
if (all->par.clut)
- of_iounmap(all->par.clut, sizeof(struct cg14_clut));
+ of_iounmap(&op->resource[0],
+ all->par.clut, sizeof(struct cg14_clut));
if (all->par.cursor)
- of_iounmap(all->par.cursor, sizeof(struct cg14_cursor));
+ of_iounmap(&op->resource[0],
+ all->par.cursor, sizeof(struct cg14_cursor));
if (all->info.screen_base)
- of_iounmap(all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[1],
+ all->info.screen_base, all->par.fbsize);
}
static int __devinit cg14_init_one(struct of_device *op)
@@ -506,7 +510,7 @@ static int __devinit cg14_init_one(struct of_device *op)
if (!all->par.regs || !all->par.clut || !all->par.cursor ||
!all->info.screen_base)
- cg14_unmap_regs(all);
+ cg14_unmap_regs(op, all);
is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) ==
(8 * 1024 * 1024));
@@ -541,7 +545,7 @@ static int __devinit cg14_init_one(struct of_device *op)
__cg14_reset(&all->par);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- cg14_unmap_regs(all);
+ cg14_unmap_regs(op, all);
kfree(all);
return -ENOMEM;
}
@@ -552,7 +556,7 @@ static int __devinit cg14_init_one(struct of_device *op)
err = register_framebuffer(&all->info);
if (err < 0) {
fb_dealloc_cmap(&all->info.cmap);
- cg14_unmap_regs(all);
+ cg14_unmap_regs(op, all);
kfree(all);
return err;
}
@@ -574,18 +578,18 @@ static int __devinit cg14_probe(struct of_device *dev, const struct of_device_id
return cg14_init_one(op);
}
-static int __devexit cg14_remove(struct of_device *dev)
+static int __devexit cg14_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&dev->dev);
+ struct all_info *all = dev_get_drvdata(&op->dev);
unregister_framebuffer(&all->info);
fb_dealloc_cmap(&all->info.cmap);
- cg14_unmap_regs(all);
+ cg14_unmap_regs(op, all);
kfree(all);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 9c8c753ef45..ada6f7e3a89 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -403,8 +403,10 @@ static int __devinit cg3_init_one(struct of_device *op)
cg3_do_default_mode(&all->par);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- of_iounmap(all->par.regs, sizeof(struct cg3_regs));
- of_iounmap(all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0],
+ all->par.regs, sizeof(struct cg3_regs));
+ of_iounmap(&op->resource[0],
+ all->info.screen_base, all->par.fbsize);
kfree(all);
return -ENOMEM;
}
@@ -415,8 +417,10 @@ static int __devinit cg3_init_one(struct of_device *op)
err = register_framebuffer(&all->info);
if (err < 0) {
fb_dealloc_cmap(&all->info.cmap);
- of_iounmap(all->par.regs, sizeof(struct cg3_regs));
- of_iounmap(all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0],
+ all->par.regs, sizeof(struct cg3_regs));
+ of_iounmap(&op->resource[0],
+ all->info.screen_base, all->par.fbsize);
kfree(all);
return err;
}
@@ -436,19 +440,19 @@ static int __devinit cg3_probe(struct of_device *dev, const struct of_device_id
return cg3_init_one(op);
}
-static int __devexit cg3_remove(struct of_device *dev)
+static int __devexit cg3_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&dev->dev);
+ struct all_info *all = dev_get_drvdata(&op->dev);
unregister_framebuffer(&all->info);
fb_dealloc_cmap(&all->info.cmap);
- of_iounmap(all->par.regs, sizeof(struct cg3_regs));
- of_iounmap(all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0], all->par.regs, sizeof(struct cg3_regs));
+ of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize);
kfree(all);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 64146be2eeb..4dad23a28f5 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -658,21 +658,26 @@ struct all_info {
struct cg6_par par;
};
-static void cg6_unmap_regs(struct all_info *all)
+static void cg6_unmap_regs(struct of_device *op, struct all_info *all)
{
if (all->par.fbc)
- of_iounmap(all->par.fbc, 4096);
+ of_iounmap(&op->resource[0], all->par.fbc, 4096);
if (all->par.tec)
- of_iounmap(all->par.tec, sizeof(struct cg6_tec));
+ of_iounmap(&op->resource[0],
+ all->par.tec, sizeof(struct cg6_tec));
if (all->par.thc)
- of_iounmap(all->par.thc, sizeof(struct cg6_thc));
+ of_iounmap(&op->resource[0],
+ all->par.thc, sizeof(struct cg6_thc));
if (all->par.bt)
- of_iounmap(all->par.bt, sizeof(struct bt_regs));
+ of_iounmap(&op->resource[0],
+ all->par.bt, sizeof(struct bt_regs));
if (all->par.fhc)
- of_iounmap(all->par.fhc, sizeof(u32));
+ of_iounmap(&op->resource[0],
+ all->par.fhc, sizeof(u32));
if (all->info.screen_base)
- of_iounmap(all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0],
+ all->info.screen_base, all->par.fbsize);
}
static int __devinit cg6_init_one(struct of_device *op)
@@ -720,7 +725,7 @@ static int __devinit cg6_init_one(struct of_device *op)
all->par.fbsize, "cgsix ram");
if (!all->par.fbc || !all->par.tec || !all->par.thc ||
!all->par.bt || !all->par.fhc || !all->info.screen_base) {
- cg6_unmap_regs(all);
+ cg6_unmap_regs(op, all);
kfree(all);
return -ENOMEM;
}
@@ -734,7 +739,7 @@ static int __devinit cg6_init_one(struct of_device *op)
cg6_blank(0, &all->info);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- cg6_unmap_regs(all);
+ cg6_unmap_regs(op, all);
kfree(all);
return -ENOMEM;
}
@@ -744,7 +749,7 @@ static int __devinit cg6_init_one(struct of_device *op)
err = register_framebuffer(&all->info);
if (err < 0) {
- cg6_unmap_regs(all);
+ cg6_unmap_regs(op, all);
fb_dealloc_cmap(&all->info.cmap);
kfree(all);
return err;
@@ -767,18 +772,18 @@ static int __devinit cg6_probe(struct of_device *dev, const struct of_device_id
return cg6_init_one(op);
}
-static int __devexit cg6_remove(struct of_device *dev)
+static int __devexit cg6_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&dev->dev);
+ struct all_info *all = dev_get_drvdata(&op->dev);
unregister_framebuffer(&all->info);
fb_dealloc_cmap(&all->info.cmap);
- cg6_unmap_regs(all);
+ cg6_unmap_regs(op, all);
kfree(all);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index daf43f535a0..2c4bc620573 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -2442,7 +2442,10 @@ static int cirrusfb_pci_register (struct pci_dev *pdev,
printk ("Cirrus Logic chipset on PCI bus\n");
pci_set_drvdata(pdev, info);
- return cirrusfb_register(cinfo);
+ ret = cirrusfb_register(cinfo);
+ if (ret)
+ iounmap(cinfo->fbmem);
+ return ret;
err_release_legacy:
if (release_io_ports)
@@ -2574,7 +2577,15 @@ static int cirrusfb_zorro_register(struct zorro_dev *z,
printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
zorro_set_drvdata(z, info);
- return cirrusfb_register(cinfo);
+ ret = cirrusfb_register(cinfo);
+ if (ret) {
+ if (btype == BT_PICASSO4) {
+ iounmap(cinfo->fbmem);
+ iounmap(cinfo->regbase - 0x600000);
+ } else if (board_addr > 0x01000000)
+ iounmap(cinfo->fbmem);
+ }
+ return ret;
err_unmap_regbase:
/* Parental advisory: explicit hack */
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c
index 7d07d838356..f577bd80e02 100644
--- a/drivers/video/console/softcursor.c
+++ b/drivers/video/console/softcursor.c
@@ -1,11 +1,13 @@
/*
- * linux/drivers/video/softcursor.c -- Generic software cursor for frame buffer devices
+ * linux/drivers/video/softcursor.c
+ *
+ * Generic software cursor for frame buffer devices
*
* Created 14 Nov 2002 by James Simmons
*
- * 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 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>
@@ -25,7 +27,7 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
unsigned int buf_align = info->pixmap.buf_align - 1;
unsigned int i, size, dsize, s_pitch, d_pitch;
struct fb_image *image;
- u8 *dst;
+ u8 *src, *dst;
if (info->state != FBINFO_STATE_RUNNING)
return 0;
@@ -45,7 +47,8 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
}
}
- image = (struct fb_image *) (ops->cursor_src + dsize);
+ src = ops->cursor_src + sizeof(struct fb_image);
+ image = (struct fb_image *)ops->cursor_src;
*image = cursor->image;
d_pitch = (s_pitch + scan_align) & ~scan_align;
@@ -57,21 +60,18 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
switch (cursor->rop) {
case ROP_XOR:
for (i = 0; i < dsize; i++)
- ops->cursor_src[i] = image->data[i] ^
- cursor->mask[i];
+ src[i] = image->data[i] ^ cursor->mask[i];
break;
case ROP_COPY:
default:
for (i = 0; i < dsize; i++)
- ops->cursor_src[i] = image->data[i] &
- cursor->mask[i];
+ src[i] = image->data[i] & cursor->mask[i];
break;
}
} else
- memcpy(ops->cursor_src, image->data, dsize);
+ memcpy(src, image->data, dsize);
- fb_pad_aligned_buffer(dst, d_pitch, ops->cursor_src, s_pitch,
- image->height);
+ fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height);
image->data = dst;
info->fbops->fb_imageblit(info, image);
return 0;
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index 45586aaabd1..57b21e53303 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -345,7 +345,7 @@ static void sticon_save_screen(struct vc_data *conp)
{
}
-static struct consw sti_con = {
+static const struct consw sti_con = {
.owner = THIS_MODULE,
.con_startup = sticon_startup,
.con_init = sticon_init,
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index 0a2c10a1abf..4a9bde2c839 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -93,27 +93,27 @@ static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
static unsigned long vgacon_uni_pagedir[2];
/* Description of the hardware situation */
-static unsigned long vga_vram_base; /* Base of video memory */
-static unsigned long vga_vram_end; /* End of video memory */
-static int vga_vram_size; /* Size of video memory */
-static u16 vga_video_port_reg; /* Video register select port */
-static u16 vga_video_port_val; /* Video register value port */
-static unsigned int vga_video_num_columns; /* Number of text columns */
-static unsigned int vga_video_num_lines; /* Number of text lines */
-static int vga_can_do_color = 0; /* Do we support colors? */
-static unsigned int vga_default_font_height;/* Height of default screen font */
-static unsigned char vga_video_type; /* Card type */
-static unsigned char vga_hardscroll_enabled;
-static unsigned char vga_hardscroll_user_enable = 1;
+static int vga_init_done __read_mostly;
+static unsigned long vga_vram_base __read_mostly; /* Base of video memory */
+static unsigned long vga_vram_end __read_mostly; /* End of video memory */
+static unsigned int vga_vram_size __read_mostly; /* Size of video memory */
+static u16 vga_video_port_reg __read_mostly; /* Video register select port */
+static u16 vga_video_port_val __read_mostly; /* Video register value port */
+static unsigned int vga_video_num_columns; /* Number of text columns */
+static unsigned int vga_video_num_lines; /* Number of text lines */
+static int vga_can_do_color __read_mostly; /* Do we support colors? */
+static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */
+static unsigned char vga_video_type __read_mostly; /* Card type */
+static unsigned char vga_hardscroll_enabled __read_mostly;
+static unsigned char vga_hardscroll_user_enable __read_mostly = 1;
static unsigned char vga_font_is_default = 1;
static int vga_vesa_blanked;
static int vga_palette_blanked;
static int vga_is_gfx;
static int vga_512_chars;
static int vga_video_font_height;
-static int vga_scan_lines;
-static unsigned int vga_rolled_over = 0;
-static int vga_init_done;
+static int vga_scan_lines __read_mostly;
+static unsigned int vga_rolled_over;
static int __init no_scroll(char *str)
{
diff --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c
index c40e72dafb0..0b8d5b12115 100644
--- a/drivers/video/cyberfb.c
+++ b/drivers/video/cyberfb.c
@@ -109,8 +109,6 @@ static void cv64_dump(void);
#define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat)
#define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg))
-#define ww_64(regs,reg,dat) (*((volatile unsigned short *)(regs + reg) = dat)
-
struct cyberfb_par {
struct fb_var_screeninfo var;
__u32 type;
@@ -1055,6 +1053,8 @@ int __init cyberfb_init(void)
if (register_framebuffer(&fb_info) < 0) {
DPRINTK("EXIT - register_framebuffer failed\n");
+ if (CyberBase)
+ iounmap(CyberBase);
release_mem_region(CyberMem_phys, 0x400000);
release_mem_region(CyberRegs_phys, 0x10000);
return -EINVAL;
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index 737257d278f..29e07c10988 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -405,7 +405,7 @@ static inline unsigned long copy_to_user16(void *to, const void *from,
static ssize_t
epson1355fb_read(struct file *file, char *buf, size_t count, loff_t * ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
unsigned long p = *ppos;
@@ -437,7 +437,7 @@ static ssize_t
epson1355fb_write(struct file *file, const char *buf,
size_t count, loff_t * ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
unsigned long p = *ppos;
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index e8b135f3d80..148108afdd5 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -18,63 +18,64 @@
#include <asm/uaccess.h>
-static u16 red2[] = {
+static u16 red2[] __read_mostly = {
0x0000, 0xaaaa
};
-static u16 green2[] = {
+static u16 green2[] __read_mostly = {
0x0000, 0xaaaa
};
-static u16 blue2[] = {
+static u16 blue2[] __read_mostly = {
0x0000, 0xaaaa
};
-static u16 red4[] = {
+static u16 red4[] __read_mostly = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
-static u16 green4[] = {
+static u16 green4[] __read_mostly = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
-static u16 blue4[] = {
+static u16 blue4[] __read_mostly = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
-static u16 red8[] = {
+static u16 red8[] __read_mostly = {
0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa
};
-static u16 green8[] = {
+static u16 green8[] __read_mostly = {
0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa
};
-static u16 blue8[] = {
+static u16 blue8[] __read_mostly = {
0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa
};
-static u16 red16[] = {
+static u16 red16[] __read_mostly = {
0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff
};
-static u16 green16[] = {
+static u16 green16[] __read_mostly = {
0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa,
0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff
};
-static u16 blue16[] = {
+static u16 blue16[] __read_mostly = {
0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff
};
-static struct fb_cmap default_2_colors = {
- 0, 2, red2, green2, blue2, NULL
+static const struct fb_cmap default_2_colors = {
+ .len=2, .red=red2, .green=green2, .blue=blue2
};
-static struct fb_cmap default_8_colors = {
- 0, 8, red8, green8, blue8, NULL
+static const struct fb_cmap default_8_colors = {
+ .len=8, .red=red8, .green=green8, .blue=blue8
};
-static struct fb_cmap default_4_colors = {
- 0, 4, red4, green4, blue4, NULL
+static const struct fb_cmap default_4_colors = {
+ .len=4, .red=red4, .green=green4, .blue=blue4
};
-static struct fb_cmap default_16_colors = {
- 0, 16, red16, green16, blue16, NULL
+static const struct fb_cmap default_16_colors = {
+ .len=16, .red=red16, .green=green16, .blue=blue16
};
+
/**
* fb_alloc_cmap - allocate a colormap
* @cmap: frame buffer colormap structure
@@ -146,7 +147,7 @@ void fb_dealloc_cmap(struct fb_cmap *cmap)
* Copy contents of colormap from @from to @to.
*/
-int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to)
+int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
{
int tooff = 0, fromoff = 0;
int size;
@@ -170,7 +171,7 @@ int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to)
return 0;
}
-int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to)
+int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to)
{
int tooff = 0, fromoff = 0;
int size;
@@ -282,7 +283,7 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
*
*/
-struct fb_cmap *fb_default_cmap(int len)
+const struct fb_cmap *fb_default_cmap(int len)
{
if (len <= 2)
return &default_2_colors;
@@ -305,22 +306,22 @@ void fb_invert_cmaps(void)
{
u_int i;
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < ARRAY_SIZE(red2); i++) {
red2[i] = ~red2[i];
green2[i] = ~green2[i];
blue2[i] = ~blue2[i];
}
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < ARRAY_SIZE(red4); i++) {
red4[i] = ~red4[i];
green4[i] = ~green4[i];
blue4[i] = ~blue4[i];
}
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < ARRAY_SIZE(red8); i++) {
red8[i] = ~red8[i];
green8[i] = ~green8[i];
blue8[i] = ~blue8[i];
}
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < ARRAY_SIZE(red16); i++) {
red16[i] = ~red16[i];
green16[i] = ~green16[i];
blue16[i] = ~blue16[i];
diff --git a/drivers/video/fbcvt.c b/drivers/video/fbcvt.c
index b5498999c4e..0847c5e72cb 100644
--- a/drivers/video/fbcvt.c
+++ b/drivers/video/fbcvt.c
@@ -57,7 +57,7 @@ struct fb_cvt_data {
u32 status;
};
-static int fb_cvt_vbi_tab[] = {
+static const unsigned char fb_cvt_vbi_tab[] = {
4, /* 4:3 */
5, /* 16:9 */
6, /* 16:10 */
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index e973a87fbb0..3cfea315a48 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -52,8 +52,8 @@
#define FBPIXMAPSIZE (1024 * 8)
-struct fb_info *registered_fb[FB_MAX];
-int num_registered_fb;
+struct fb_info *registered_fb[FB_MAX] __read_mostly;
+int num_registered_fb __read_mostly;
/*
* Helpers
@@ -202,7 +202,7 @@ static void fb_set_logo_truepalette(struct fb_info *info,
const struct linux_logo *logo,
u32 *palette)
{
- unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
+ static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
unsigned char redmask, greenmask, bluemask;
int redshift, greenshift, blueshift;
int i;
@@ -317,7 +317,7 @@ static struct logo_data {
int needs_truepalette;
int needs_cmapreset;
const struct linux_logo *logo;
-} fb_logo;
+} fb_logo __read_mostly;
static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
{
@@ -572,7 +572,7 @@ static ssize_t
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
u32 *buffer, *dst;
@@ -647,7 +647,7 @@ static ssize_t
fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
u32 *buffer, *src;
@@ -1081,7 +1081,7 @@ static int fb_get_fscreeninfo(struct inode *inode, struct file *file,
static long
fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
@@ -1121,7 +1121,7 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static int
fb_mmap(struct file *file, struct vm_area_struct * vma)
{
- int fbidx = iminor(file->f_dentry->d_inode);
+ int fbidx = iminor(file->f_path.dentry->d_inode);
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
unsigned long off;
@@ -1253,7 +1253,7 @@ fb_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations fb_fops = {
+static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
@@ -1459,8 +1459,8 @@ int fb_new_modelist(struct fb_info *info)
return err;
}
-static char *video_options[FB_MAX];
-static int ofonly;
+static char *video_options[FB_MAX] __read_mostly;
+static int ofonly __read_mostly;
extern const char *global_mode_option;
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index de93139ccbb..6b385c39b8b 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -58,7 +58,7 @@ struct broken_edid {
u32 fix;
};
-static struct broken_edid brokendb[] = {
+static const struct broken_edid brokendb[] = {
/* DEC FR-PCXAV-YZ */
{
.manufacturer = "DEC",
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 2a0e8210d39..15854aec318 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -910,7 +910,8 @@ static int ffb_init_one(struct of_device *op)
all->par.dac = of_ioremap(&op->resource[1], 0,
sizeof(struct ffb_dac), "ffb dac");
if (!all->par.dac) {
- of_iounmap(all->par.fbc, sizeof(struct ffb_fbc));
+ of_iounmap(&op->resource[2],
+ all->par.fbc, sizeof(struct ffb_fbc));
kfree(all);
return -ENOMEM;
}
@@ -968,6 +969,10 @@ static int ffb_init_one(struct of_device *op)
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
printk(KERN_ERR "ffb: Could not allocate color map.\n");
+ of_iounmap(&op->resource[2],
+ all->par.fbc, sizeof(struct ffb_fbc));
+ of_iounmap(&op->resource[1],
+ all->par.dac, sizeof(struct ffb_dac));
kfree(all);
return -ENOMEM;
}
@@ -978,6 +983,10 @@ static int ffb_init_one(struct of_device *op)
if (err < 0) {
printk(KERN_ERR "ffb: Could not register framebuffer.\n");
fb_dealloc_cmap(&all->info.cmap);
+ of_iounmap(&op->resource[2],
+ all->par.fbc, sizeof(struct ffb_fbc));
+ of_iounmap(&op->resource[1],
+ all->par.dac, sizeof(struct ffb_dac));
kfree(all);
return err;
}
@@ -999,19 +1008,19 @@ static int __devinit ffb_probe(struct of_device *dev, const struct of_device_id
return ffb_init_one(op);
}
-static int __devexit ffb_remove(struct of_device *dev)
+static int __devexit ffb_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&dev->dev);
+ struct all_info *all = dev_get_drvdata(&op->dev);
unregister_framebuffer(&all->info);
fb_dealloc_cmap(&all->info.cmap);
- of_iounmap(all->par.fbc, sizeof(struct ffb_fbc));
- of_iounmap(all->par.dac, sizeof(struct ffb_dac));
+ of_iounmap(&op->resource[2], all->par.fbc, sizeof(struct ffb_fbc));
+ of_iounmap(&op->resource[1], all->par.dac, sizeof(struct ffb_dac));
kfree(all);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c
index 998374cfae6..70ff55b1459 100644
--- a/drivers/video/fm2fb.c
+++ b/drivers/video/fm2fb.c
@@ -283,6 +283,7 @@ static int __devinit fm2fb_probe(struct zorro_dev *z,
if (register_framebuffer(info) < 0) {
fb_dealloc_cmap(&info->cmap);
+ iounmap(info->screen_base);
framebuffer_release(info);
zorro_release_device(z);
return -EINVAL;
diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig
index 4e173ef20a7..a814b6c2605 100644
--- a/drivers/video/geode/Kconfig
+++ b/drivers/video/geode/Kconfig
@@ -23,6 +23,26 @@ config FB_GEODE_GX
If unsure, say N.
+config FB_GEODE_GX_SET_FBSIZE
+ bool "Manually specify the Geode GX framebuffer size"
+ depends on FB_GEODE_GX
+ default n
+ ---help---
+ If you want to manually specify the size of your GX framebuffer,
+ say Y here, otherwise say N to dynamically probe it.
+
+ Say N unless you know what you are doing.
+
+config FB_GEODE_GX_FBSIZE
+ hex "Size of the GX framebuffer, in bytes"
+ depends on FB_GEODE_GX_SET_FBSIZE
+ default "0x1600000"
+ ---help---
+ Specify the size of the GX framebuffer. Normally, you will
+ want this to be MB aligned. Common values are 0x80000 (8MB)
+ and 0x1600000 (16MB). Don't change this unless you know what
+ you are doing
+
config FB_GEODE_GX1
tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
depends on FB && FB_GEODE && EXPERIMENTAL
diff --git a/drivers/video/geode/display_gx.c b/drivers/video/geode/display_gx.c
index 825c3405f5c..0f16e4bffc6 100644
--- a/drivers/video/geode/display_gx.c
+++ b/drivers/video/geode/display_gx.c
@@ -21,11 +21,27 @@
#include "geodefb.h"
#include "display_gx.h"
-int gx_frame_buffer_size(void)
+#ifdef CONFIG_FB_GEODE_GX_SET_FBSIZE
+unsigned int gx_frame_buffer_size(void)
{
- /* Assuming 16 MiB. */
- return 16*1024*1024;
+ return CONFIG_FB_GEODE_GX_FBSIZE;
}
+#else
+unsigned int gx_frame_buffer_size(void)
+{
+ unsigned int val;
+
+ /* FB size is reported by a virtual register */
+ /* Virtual register class = 0x02 */
+ /* VG_MEM_SIZE(512Kb units) = 0x00 */
+
+ outw(0xFC53, 0xAC1C);
+ outw(0x0200, 0xAC1C);
+
+ val = (unsigned int)(inw(0xAC1E)) & 0xFFl;
+ return (val << 19);
+}
+#endif
int gx_line_delta(int xres, int bpp)
{
@@ -81,6 +97,7 @@ static void gx_set_mode(struct fb_info *info)
writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
par->dc_regs + DC_LINE_SIZE);
+
/* Enable graphics and video data and unmask address lines. */
dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M;
diff --git a/drivers/video/geode/display_gx.h b/drivers/video/geode/display_gx.h
index 86c62336130..0af33f329e8 100644
--- a/drivers/video/geode/display_gx.h
+++ b/drivers/video/geode/display_gx.h
@@ -11,11 +11,15 @@
#ifndef __DISPLAY_GX_H__
#define __DISPLAY_GX_H__
-int gx_frame_buffer_size(void);
+unsigned int gx_frame_buffer_size(void);
int gx_line_delta(int xres, int bpp);
extern struct geode_dc_ops gx_dc_ops;
+/* MSR that tells us if a TFT or CRT is attached */
+#define GLD_MSR_CONFIG 0xC0002001
+#define GLD_MSR_CONFIG_DM_FP 0x40
+
/* Display controller registers */
#define DC_UNLOCK 0x00
@@ -93,4 +97,5 @@ extern struct geode_dc_ops gx_dc_ops;
#define DC_PAL_ADDRESS 0x70
#define DC_PAL_DATA 0x74
+#define DC_GLIU0_MEM_OFFSET 0x84
#endif /* !__DISPLAY_GX1_H__ */
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
index a454dcb8e21..cf841efa229 100644
--- a/drivers/video/geode/gxfb_core.c
+++ b/drivers/video/geode/gxfb_core.c
@@ -35,10 +35,10 @@
#include "display_gx.h"
#include "video_gx.h"
-static char mode_option[32] = "640x480-16@60";
+static char *mode_option;
/* Modes relevant to the GX (taken from modedb.c) */
-static const struct fb_videomode __initdata gx_modedb[] = {
+static const struct fb_videomode gx_modedb[] __initdata = {
/* 640x480-60 VESA */
{ NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
@@ -240,6 +240,12 @@ static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *de
if (!info->screen_base)
return -ENOMEM;
+ /* Set the 16MB aligned base address of the graphics memory region
+ * in the display controller */
+
+ writel(info->fix.smem_start & 0xFF000000,
+ par->dc_regs + DC_GLIU0_MEM_OFFSET);
+
dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n",
info->fix.smem_len / 1024, info->fix.smem_start);
@@ -302,6 +308,7 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
struct geodefb_par *par;
struct fb_info *info;
int ret;
+ unsigned long val;
info = gxfb_init_fbinfo(&pdev->dev);
if (!info)
@@ -317,6 +324,15 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
goto err;
}
+ /* Figure out if this is a TFT or CRT part */
+
+ rdmsrl(GLD_MSR_CONFIG, val);
+
+ if ((val & GLD_MSR_CONFIG_DM_FP) == GLD_MSR_CONFIG_DM_FP)
+ par->enable_crt = 0;
+ else
+ par->enable_crt = 1;
+
ret = fb_find_mode(&info->var, info, mode_option,
gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16);
if (ret == 0 || ret == 4) {
@@ -325,7 +341,8 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
goto err;
}
- /* Clear the frame buffer of garbage. */
+
+ /* Clear the frame buffer of garbage. */
memset_io(info->screen_base, 0, info->fix.smem_len);
gxfb_check_var(&info->var, info);
@@ -395,11 +412,35 @@ static struct pci_driver gxfb_driver = {
.remove = gxfb_remove,
};
+#ifndef MODULE
+static int __init gxfb_setup(char *options)
+{
+
+ char *opt;
+
+ if (!options || !*options)
+ return 0;
+
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+
+ mode_option = opt;
+ }
+
+ return 0;
+}
+#endif
+
static int __init gxfb_init(void)
{
#ifndef MODULE
- if (fb_get_options("gxfb", NULL))
+ char *option = NULL;
+
+ if (fb_get_options("gxfb", &option))
return -ENODEV;
+
+ gxfb_setup(option);
#endif
return pci_register_driver(&gxfb_driver);
}
@@ -412,8 +453,8 @@ static void __exit gxfb_cleanup(void)
module_init(gxfb_init);
module_exit(gxfb_cleanup);
-module_param_string(mode, mode_option, sizeof(mode_option), 0444);
-MODULE_PARM_DESC(mode, "video mode (<x>x<y>[-<bpp>][@<refr>])");
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c
index 2b2a7880ea7..7f3f18d0671 100644
--- a/drivers/video/geode/video_gx.c
+++ b/drivers/video/geode/video_gx.c
@@ -175,13 +175,88 @@ static void gx_set_dclk_frequency(struct fb_info *info)
} while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
}
+static void
+gx_configure_tft(struct fb_info *info)
+{
+ struct geodefb_par *par = info->par;
+ unsigned long val;
+ unsigned long fp;
+
+ /* Set up the DF pad select MSR */
+
+ rdmsrl(GX_VP_MSR_PAD_SELECT, val);
+ val &= ~GX_VP_PAD_SELECT_MASK;
+ val |= GX_VP_PAD_SELECT_TFT;
+ wrmsrl(GX_VP_MSR_PAD_SELECT, val);
+
+ /* Turn off the panel */
+
+ fp = readl(par->vid_regs + GX_FP_PM);
+ fp &= ~GX_FP_PM_P;
+ writel(fp, par->vid_regs + GX_FP_PM);
+
+ /* Set timing 1 */
+
+ fp = readl(par->vid_regs + GX_FP_PT1);
+ fp &= GX_FP_PT1_VSIZE_MASK;
+ fp |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT;
+ writel(fp, par->vid_regs + GX_FP_PT1);
+
+ /* Timing 2 */
+ /* Set bits that are always on for TFT */
+
+ fp = 0x0F100000;
+
+ /* Add sync polarity */
+
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+ fp |= GX_FP_PT2_VSP;
+
+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+ fp |= GX_FP_PT2_HSP;
+
+ writel(fp, par->vid_regs + GX_FP_PT2);
+
+ /* Set the dither control */
+ writel(0x70, par->vid_regs + GX_FP_DFC);
+
+ /* Enable the FP data and power (in case the BIOS didn't) */
+
+ fp = readl(par->vid_regs + GX_DCFG);
+ fp |= GX_DCFG_FP_PWR_EN | GX_DCFG_FP_DATA_EN;
+ writel(fp, par->vid_regs + GX_DCFG);
+
+ /* Unblank the panel */
+
+ fp = readl(par->vid_regs + GX_FP_PM);
+ fp |= GX_FP_PM_P;
+ writel(fp, par->vid_regs + GX_FP_PM);
+}
+
static void gx_configure_display(struct fb_info *info)
{
struct geodefb_par *par = info->par;
- u32 dcfg, fp_pm;
+ u32 dcfg, misc;
+
+ /* Set up the MISC register */
+
+ misc = readl(par->vid_regs + GX_MISC);
+
+ /* Power up the DAC */
+ misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
+
+ /* Disable gamma correction */
+ misc |= GX_MISC_GAM_EN;
+
+ writel(misc, par->vid_regs + GX_MISC);
+ /* Write the display configuration */
dcfg = readl(par->vid_regs + GX_DCFG);
+ /* Disable hsync and vsync */
+ dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
+ writel(dcfg, par->vid_regs + GX_DCFG);
+
/* Clear bits from existing mode. */
dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK
| GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL
@@ -199,12 +274,19 @@ static void gx_configure_display(struct fb_info *info)
if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
dcfg |= GX_DCFG_CRT_VSYNC_POL;
+ /* Enable the display logic */
+ /* Set up the DACS to blank normally */
+
+ dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN;
+
+ /* Enable the external DAC VREF? */
+
writel(dcfg, par->vid_regs + GX_DCFG);
- /* Power on flat panel. */
- fp_pm = readl(par->vid_regs + GX_FP_PM);
- fp_pm |= GX_FP_PM_P;
- writel(fp_pm, par->vid_regs + GX_FP_PM);
+ /* Set up the flat panel (if it is enabled) */
+
+ if (par->enable_crt == 0)
+ gx_configure_tft(info);
}
static int gx_blank_display(struct fb_info *info, int blank_mode)
@@ -245,12 +327,15 @@ static int gx_blank_display(struct fb_info *info, int blank_mode)
writel(dcfg, par->vid_regs + GX_DCFG);
/* Power on/off flat panel. */
- fp_pm = readl(par->vid_regs + GX_FP_PM);
- if (blank_mode == FB_BLANK_POWERDOWN)
- fp_pm &= ~GX_FP_PM_P;
- else
- fp_pm |= GX_FP_PM_P;
- writel(fp_pm, par->vid_regs + GX_FP_PM);
+
+ if (par->enable_crt == 0) {
+ fp_pm = readl(par->vid_regs + GX_FP_PM);
+ if (blank_mode == FB_BLANK_POWERDOWN)
+ fp_pm &= ~GX_FP_PM_P;
+ else
+ fp_pm |= GX_FP_PM_P;
+ writel(fp_pm, par->vid_regs + GX_FP_PM);
+ }
return 0;
}
diff --git a/drivers/video/geode/video_gx.h b/drivers/video/geode/video_gx.h
index 2d9211f3ed8..ce28d8f382d 100644
--- a/drivers/video/geode/video_gx.h
+++ b/drivers/video/geode/video_gx.h
@@ -13,6 +13,11 @@
extern struct geode_vid_ops gx_vid_ops;
+/* GX Flatpanel control MSR */
+#define GX_VP_MSR_PAD_SELECT 0xC0002011
+#define GX_VP_PAD_SELECT_MASK 0x3FFFFFFF
+#define GX_VP_PAD_SELECT_TFT 0x1FFFFFFF
+
/* Geode GX video processor registers */
#define GX_DCFG 0x0008
@@ -20,6 +25,8 @@ extern struct geode_vid_ops gx_vid_ops;
# define GX_DCFG_HSYNC_EN 0x00000002
# define GX_DCFG_VSYNC_EN 0x00000004
# define GX_DCFG_DAC_BL_EN 0x00000008
+# define GX_DCFG_FP_PWR_EN 0x00000040
+# define GX_DCFG_FP_DATA_EN 0x00000080
# define GX_DCFG_CRT_HSYNC_POL 0x00000100
# define GX_DCFG_CRT_VSYNC_POL 0x00000200
# define GX_DCFG_CRT_SYNC_SKW_MASK 0x0001C000
@@ -28,10 +35,28 @@ extern struct geode_vid_ops gx_vid_ops;
# define GX_DCFG_GV_GAM 0x00200000
# define GX_DCFG_DAC_VREF 0x04000000
+/* Geode GX MISC video configuration */
+
+#define GX_MISC 0x50
+#define GX_MISC_GAM_EN 0x00000001
+#define GX_MISC_DAC_PWRDN 0x00000400
+#define GX_MISC_A_PWRDN 0x00000800
+
/* Geode GX flat panel display control registers */
+
+#define GX_FP_PT1 0x0400
+#define GX_FP_PT1_VSIZE_MASK 0x7FF0000
+#define GX_FP_PT1_VSIZE_SHIFT 16
+
+#define GX_FP_PT2 0x408
+#define GX_FP_PT2_VSP (1 << 23)
+#define GX_FP_PT2_HSP (1 << 22)
+
#define GX_FP_PM 0x410
# define GX_FP_PM_P 0x01000000
+#define GX_FP_DFC 0x418
+
/* Geode GX clock control MSRs */
#define MSR_GLCP_SYS_RSTPLL 0x4c000014
diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c
new file mode 100644
index 00000000000..23a6bcc3e3c
--- /dev/null
+++ b/drivers/video/gxt4500.c
@@ -0,0 +1,774 @@
+/*
+ * Frame buffer device for IBM GXT4500P and GXT6000P display adaptors
+ *
+ * Copyright (C) 2006 Paul Mackerras, IBM Corp. <paulus@samba.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+
+#define PCI_DEVICE_ID_IBM_GXT4500P 0x21c
+#define PCI_DEVICE_ID_IBM_GXT6000P 0x170
+
+/* GXT4500P registers */
+
+/* Registers in PCI config space */
+#define CFG_ENDIAN0 0x40
+
+/* Misc control/status registers */
+#define STATUS 0x1000
+#define CTRL_REG0 0x1004
+#define CR0_HALT_DMA 0x4
+#define CR0_RASTER_RESET 0x8
+#define CR0_GEOM_RESET 0x10
+#define CR0_MEM_CTRLER_RESET 0x20
+
+/* Framebuffer control registers */
+#define FB_AB_CTRL 0x1100
+#define FB_CD_CTRL 0x1104
+#define FB_WID_CTRL 0x1108
+#define FB_Z_CTRL 0x110c
+#define FB_VGA_CTRL 0x1110
+#define REFRESH_AB_CTRL 0x1114
+#define REFRESH_CD_CTRL 0x1118
+#define FB_OVL_CTRL 0x111c
+#define FB_CTRL_TYPE 0x80000000
+#define FB_CTRL_WIDTH_MASK 0x007f0000
+#define FB_CTRL_WIDTH_SHIFT 16
+#define FB_CTRL_START_SEG_MASK 0x00003fff
+
+#define REFRESH_START 0x1098
+#define REFRESH_SIZE 0x109c
+
+/* "Direct" framebuffer access registers */
+#define DFA_FB_A 0x11e0
+#define DFA_FB_B 0x11e4
+#define DFA_FB_C 0x11e8
+#define DFA_FB_D 0x11ec
+#define DFA_FB_ENABLE 0x80000000
+#define DFA_FB_BASE_MASK 0x03f00000
+#define DFA_FB_STRIDE_1k 0x00000000
+#define DFA_FB_STRIDE_2k 0x00000010
+#define DFA_FB_STRIDE_4k 0x00000020
+#define DFA_PIX_8BIT 0x00000000
+#define DFA_PIX_16BIT_565 0x00000001
+#define DFA_PIX_16BIT_1555 0x00000002
+#define DFA_PIX_24BIT 0x00000004
+#define DFA_PIX_32BIT 0x00000005
+
+/* maps DFA_PIX_* to pixel size in bytes */
+static const unsigned char pixsize[] = {
+ 1, 2, 2, 2, 4, 4
+};
+
+/* Display timing generator registers */
+#define DTG_CONTROL 0x1900
+#define DTG_CTL_SCREEN_REFRESH 2
+#define DTG_CTL_ENABLE 1
+#define DTG_HORIZ_EXTENT 0x1904
+#define DTG_HORIZ_DISPLAY 0x1908
+#define DTG_HSYNC_START 0x190c
+#define DTG_HSYNC_END 0x1910
+#define DTG_HSYNC_END_COMP 0x1914
+#define DTG_VERT_EXTENT 0x1918
+#define DTG_VERT_DISPLAY 0x191c
+#define DTG_VSYNC_START 0x1920
+#define DTG_VSYNC_END 0x1924
+#define DTG_VERT_SHORT 0x1928
+
+/* PLL/RAMDAC registers */
+#define DISP_CTL 0x402c
+#define DISP_CTL_OFF 2
+#define SYNC_CTL 0x4034
+#define SYNC_CTL_SYNC_ON_RGB 1
+#define SYNC_CTL_SYNC_OFF 2
+#define SYNC_CTL_HSYNC_INV 8
+#define SYNC_CTL_VSYNC_INV 0x10
+#define SYNC_CTL_HSYNC_OFF 0x20
+#define SYNC_CTL_VSYNC_OFF 0x40
+
+#define PLL_M 0x4040
+#define PLL_N 0x4044
+#define PLL_POSTDIV 0x4048
+#define PLL_C 0x404c
+
+/* Hardware cursor */
+#define CURSOR_X 0x4078
+#define CURSOR_Y 0x407c
+#define CURSOR_HOTSPOT 0x4080
+#define CURSOR_MODE 0x4084
+#define CURSOR_MODE_OFF 0
+#define CURSOR_MODE_4BPP 1
+#define CURSOR_PIXMAP 0x5000
+#define CURSOR_CMAP 0x7400
+
+/* Window attribute table */
+#define WAT_FMT 0x4100
+#define WAT_FMT_24BIT 0
+#define WAT_FMT_16BIT_565 1
+#define WAT_FMT_16BIT_1555 2
+#define WAT_FMT_32BIT 3 /* 0 vs. 3 is a guess */
+#define WAT_FMT_8BIT_332 9
+#define WAT_FMT_8BIT 0xa
+#define WAT_FMT_NO_CMAP 4 /* ORd in to other values */
+#define WAT_CMAP_OFFSET 0x4104 /* 4-bit value gets << 6 */
+#define WAT_CTRL 0x4108
+#define WAT_CTRL_SEL_B 1 /* select B buffer if 1 */
+#define WAT_CTRL_NO_INC 2
+#define WAT_GAMMA_CTRL 0x410c
+#define WAT_GAMMA_DISABLE 1 /* disables gamma cmap */
+#define WAT_OVL_CTRL 0x430c /* controls overlay */
+
+/* Indexed by DFA_PIX_* values */
+static const unsigned char watfmt[] = {
+ WAT_FMT_8BIT, WAT_FMT_16BIT_565, WAT_FMT_16BIT_1555, 0,
+ WAT_FMT_24BIT, WAT_FMT_32BIT
+};
+
+/* Colormap array; 1k entries of 4 bytes each */
+#define CMAP 0x6000
+
+#define readreg(par, reg) readl((par)->regs + (reg))
+#define writereg(par, reg, val) writel((val), (par)->regs + (reg))
+
+struct gxt4500_par {
+ void __iomem *regs;
+
+ int pixfmt; /* pixel format, see DFA_PIX_* values */
+
+ /* PLL parameters */
+ int refclk_ps; /* ref clock period in picoseconds */
+ int pll_m; /* ref clock divisor */
+ int pll_n; /* VCO divisor */
+ int pll_pd1; /* first post-divisor */
+ int pll_pd2; /* second post-divisor */
+
+ u32 pseudo_palette[16]; /* used in color blits */
+};
+
+/* mode requested by user */
+static char *mode_option;
+
+/* default mode: 1280x1024 @ 60 Hz, 8 bpp */
+static const struct fb_videomode defaultmode __devinitdata = {
+ .refresh = 60,
+ .xres = 1280,
+ .yres = 1024,
+ .pixclock = 9295,
+ .left_margin = 248,
+ .right_margin = 48,
+ .upper_margin = 38,
+ .lower_margin = 1,
+ .hsync_len = 112,
+ .vsync_len = 3,
+ .vmode = FB_VMODE_NONINTERLACED
+};
+
+/* List of supported cards */
+enum gxt_cards {
+ GXT4500P,
+ GXT6000P
+};
+
+/* Card-specific information */
+static const struct cardinfo {
+ int refclk_ps; /* period of PLL reference clock in ps */
+ const char *cardname;
+} cardinfo[] = {
+ [GXT4500P] = { .refclk_ps = 9259, .cardname = "IBM GXT4500P" },
+ [GXT6000P] = { .refclk_ps = 40000, .cardname = "IBM GXT6000P" },
+};
+
+/*
+ * The refclk and VCO dividers appear to use a linear feedback shift
+ * register, which gets reloaded when it reaches a terminal value, at
+ * which point the divider output is toggled. Thus one can obtain
+ * whatever divisor is required by putting the appropriate value into
+ * the reload register. For a divisor of N, one puts the value from
+ * the LFSR sequence that comes N-1 places before the terminal value
+ * into the reload register.
+ */
+
+static const unsigned char mdivtab[] = {
+/* 1 */ 0x3f, 0x00, 0x20, 0x10, 0x28, 0x14, 0x2a, 0x15, 0x0a,
+/* 10 */ 0x25, 0x32, 0x19, 0x0c, 0x26, 0x13, 0x09, 0x04, 0x22, 0x11,
+/* 20 */ 0x08, 0x24, 0x12, 0x29, 0x34, 0x1a, 0x2d, 0x36, 0x1b, 0x0d,
+/* 30 */ 0x06, 0x23, 0x31, 0x38, 0x1c, 0x2e, 0x17, 0x0b, 0x05, 0x02,
+/* 40 */ 0x21, 0x30, 0x18, 0x2c, 0x16, 0x2b, 0x35, 0x3a, 0x1d, 0x0e,
+/* 50 */ 0x27, 0x33, 0x39, 0x3c, 0x1e, 0x2f, 0x37, 0x3b, 0x3d, 0x3e,
+/* 60 */ 0x1f, 0x0f, 0x07, 0x03, 0x01,
+};
+
+static const unsigned char ndivtab[] = {
+/* 2 */ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0x78, 0xbc, 0x5e,
+/* 10 */ 0x2f, 0x17, 0x0b, 0x85, 0xc2, 0xe1, 0x70, 0x38, 0x9c, 0x4e,
+/* 20 */ 0xa7, 0xd3, 0xe9, 0xf4, 0xfa, 0xfd, 0xfe, 0x7f, 0xbf, 0xdf,
+/* 30 */ 0xef, 0x77, 0x3b, 0x1d, 0x8e, 0xc7, 0xe3, 0x71, 0xb8, 0xdc,
+/* 40 */ 0x6e, 0xb7, 0x5b, 0x2d, 0x16, 0x8b, 0xc5, 0xe2, 0xf1, 0xf8,
+/* 50 */ 0xfc, 0x7e, 0x3f, 0x9f, 0xcf, 0x67, 0xb3, 0xd9, 0x6c, 0xb6,
+/* 60 */ 0xdb, 0x6d, 0x36, 0x9b, 0x4d, 0x26, 0x13, 0x89, 0xc4, 0x62,
+/* 70 */ 0xb1, 0xd8, 0xec, 0xf6, 0xfb, 0x7d, 0xbe, 0x5f, 0xaf, 0x57,
+/* 80 */ 0x2b, 0x95, 0x4a, 0x25, 0x92, 0x49, 0xa4, 0x52, 0x29, 0x94,
+/* 90 */ 0xca, 0x65, 0xb2, 0x59, 0x2c, 0x96, 0xcb, 0xe5, 0xf2, 0x79,
+/* 100 */ 0x3c, 0x1e, 0x0f, 0x07, 0x83, 0x41, 0x20, 0x90, 0x48, 0x24,
+/* 110 */ 0x12, 0x09, 0x84, 0x42, 0xa1, 0x50, 0x28, 0x14, 0x8a, 0x45,
+/* 120 */ 0xa2, 0xd1, 0xe8, 0x74, 0xba, 0xdd, 0xee, 0xf7, 0x7b, 0x3d,
+/* 130 */ 0x9e, 0x4f, 0x27, 0x93, 0xc9, 0xe4, 0x72, 0x39, 0x1c, 0x0e,
+/* 140 */ 0x87, 0xc3, 0x61, 0x30, 0x18, 0x8c, 0xc6, 0x63, 0x31, 0x98,
+/* 150 */ 0xcc, 0xe6, 0x73, 0xb9, 0x5c, 0x2e, 0x97, 0x4b, 0xa5, 0xd2,
+/* 160 */ 0x69,
+};
+
+static int calc_pll(int period_ps, struct gxt4500_par *par)
+{
+ int m, n, pdiv1, pdiv2, postdiv;
+ int pll_period, best_error, t, intf;
+
+ /* only deal with range 5MHz - 300MHz */
+ if (period_ps < 3333 || period_ps > 200000)
+ return -1;
+
+ best_error = 1000000;
+ for (pdiv1 = 1; pdiv1 <= 8; ++pdiv1) {
+ for (pdiv2 = 1; pdiv2 <= pdiv1; ++pdiv2) {
+ postdiv = pdiv1 * pdiv2;
+ pll_period = (period_ps + postdiv - 1) / postdiv;
+ /* keep pll in range 350..600 MHz */
+ if (pll_period < 1666 || pll_period > 2857)
+ continue;
+ for (m = 1; m <= 64; ++m) {
+ intf = m * par->refclk_ps;
+ if (intf > 500000)
+ break;
+ n = intf * postdiv / period_ps;
+ if (n < 3 || n > 160)
+ continue;
+ t = par->refclk_ps * m * postdiv / n;
+ t -= period_ps;
+ if (t >= 0 && t < best_error) {
+ par->pll_m = m;
+ par->pll_n = n;
+ par->pll_pd1 = pdiv1;
+ par->pll_pd2 = pdiv2;
+ best_error = t;
+ }
+ }
+ }
+ }
+ if (best_error == 1000000)
+ return -1;
+ return 0;
+}
+
+static int calc_pixclock(struct gxt4500_par *par)
+{
+ return par->refclk_ps * par->pll_m * par->pll_pd1 * par->pll_pd2
+ / par->pll_n;
+}
+
+static int gxt4500_var_to_par(struct fb_var_screeninfo *var,
+ struct gxt4500_par *par)
+{
+ if (var->xres + var->xoffset > var->xres_virtual ||
+ var->yres + var->yoffset > var->yres_virtual ||
+ var->xres_virtual > 4096)
+ return -EINVAL;
+ if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+ return -EINVAL;
+
+ if (calc_pll(var->pixclock, par) < 0)
+ return -EINVAL;
+
+ switch (var->bits_per_pixel) {
+ case 32:
+ if (var->transp.length)
+ par->pixfmt = DFA_PIX_32BIT;
+ else
+ par->pixfmt = DFA_PIX_24BIT;
+ break;
+ case 24:
+ par->pixfmt = DFA_PIX_24BIT;
+ break;
+ case 16:
+ if (var->green.length == 5)
+ par->pixfmt = DFA_PIX_16BIT_1555;
+ else
+ par->pixfmt = DFA_PIX_16BIT_565;
+ break;
+ case 8:
+ par->pixfmt = DFA_PIX_8BIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct fb_bitfield eightbits = {0, 8};
+static const struct fb_bitfield nobits = {0, 0};
+
+static void gxt4500_unpack_pixfmt(struct fb_var_screeninfo *var,
+ int pixfmt)
+{
+ var->bits_per_pixel = pixsize[pixfmt] * 8;
+ var->red = eightbits;
+ var->green = eightbits;
+ var->blue = eightbits;
+ var->transp = nobits;
+
+ switch (pixfmt) {
+ case DFA_PIX_16BIT_565:
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ break;
+ case DFA_PIX_16BIT_1555:
+ var->red.length = 5;
+ var->green.length = 5;
+ var->blue.length = 5;
+ var->transp.length = 1;
+ break;
+ case DFA_PIX_32BIT:
+ var->transp.length = 8;
+ break;
+ }
+ if (pixfmt != DFA_PIX_8BIT) {
+ var->green.offset = var->red.length;
+ var->blue.offset = var->green.offset + var->green.length;
+ if (var->transp.length)
+ var->transp.offset =
+ var->blue.offset + var->blue.length;
+ }
+}
+
+static int gxt4500_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct gxt4500_par par;
+ int err;
+
+ par = *(struct gxt4500_par *)info->par;
+ err = gxt4500_var_to_par(var, &par);
+ if (!err) {
+ var->pixclock = calc_pixclock(&par);
+ gxt4500_unpack_pixfmt(var, par.pixfmt);
+ }
+ return err;
+}
+
+static int gxt4500_set_par(struct fb_info *info)
+{
+ struct gxt4500_par *par = info->par;
+ struct fb_var_screeninfo *var = &info->var;
+ int err;
+ u32 ctrlreg, tmp;
+ unsigned int dfa_ctl, pixfmt, stride;
+ unsigned int wid_tiles, i;
+ unsigned int prefetch_pix, htot;
+ struct gxt4500_par save_par;
+
+ save_par = *par;
+ err = gxt4500_var_to_par(var, par);
+ if (err) {
+ *par = save_par;
+ return err;
+ }
+
+ /* turn off DTG for now */
+ ctrlreg = readreg(par, DTG_CONTROL);
+ ctrlreg &= ~(DTG_CTL_ENABLE | DTG_CTL_SCREEN_REFRESH);
+ writereg(par, DTG_CONTROL, ctrlreg);
+
+ /* set PLL registers */
+ tmp = readreg(par, PLL_C) & ~0x7f;
+ if (par->pll_n < 38)
+ tmp |= 0x29;
+ if (par->pll_n < 69)
+ tmp |= 0x35;
+ else if (par->pll_n < 100)
+ tmp |= 0x76;
+ else
+ tmp |= 0x7e;
+ writereg(par, PLL_C, tmp);
+ writereg(par, PLL_M, mdivtab[par->pll_m - 1]);
+ writereg(par, PLL_N, ndivtab[par->pll_n - 2]);
+ tmp = ((8 - par->pll_pd2) << 3) | (8 - par->pll_pd1);
+ if (par->pll_pd1 == 8 || par->pll_pd2 == 8) {
+ /* work around erratum */
+ writereg(par, PLL_POSTDIV, tmp | 0x9);
+ udelay(1);
+ }
+ writereg(par, PLL_POSTDIV, tmp);
+ msleep(20);
+
+ /* turn off hardware cursor */
+ writereg(par, CURSOR_MODE, CURSOR_MODE_OFF);
+
+ /* reset raster engine */
+ writereg(par, CTRL_REG0, CR0_RASTER_RESET | (CR0_RASTER_RESET << 16));
+ udelay(10);
+ writereg(par, CTRL_REG0, CR0_RASTER_RESET << 16);
+
+ /* set display timing generator registers */
+ htot = var->xres + var->left_margin + var->right_margin +
+ var->hsync_len;
+ writereg(par, DTG_HORIZ_EXTENT, htot - 1);
+ writereg(par, DTG_HORIZ_DISPLAY, var->xres - 1);
+ writereg(par, DTG_HSYNC_START, var->xres + var->right_margin - 1);
+ writereg(par, DTG_HSYNC_END,
+ var->xres + var->right_margin + var->hsync_len - 1);
+ writereg(par, DTG_HSYNC_END_COMP,
+ var->xres + var->right_margin + var->hsync_len - 1);
+ writereg(par, DTG_VERT_EXTENT,
+ var->yres + var->upper_margin + var->lower_margin +
+ var->vsync_len - 1);
+ writereg(par, DTG_VERT_DISPLAY, var->yres - 1);
+ writereg(par, DTG_VSYNC_START, var->yres + var->lower_margin - 1);
+ writereg(par, DTG_VSYNC_END,
+ var->yres + var->lower_margin + var->vsync_len - 1);
+ prefetch_pix = 3300000 / var->pixclock;
+ if (prefetch_pix >= htot)
+ prefetch_pix = htot - 1;
+ writereg(par, DTG_VERT_SHORT, htot - prefetch_pix - 1);
+ ctrlreg |= DTG_CTL_ENABLE | DTG_CTL_SCREEN_REFRESH;
+ writereg(par, DTG_CONTROL, ctrlreg);
+
+ /* calculate stride in DFA aperture */
+ if (var->xres_virtual > 2048) {
+ stride = 4096;
+ dfa_ctl = DFA_FB_STRIDE_4k;
+ } else if (var->xres_virtual > 1024) {
+ stride = 2048;
+ dfa_ctl = DFA_FB_STRIDE_2k;
+ } else {
+ stride = 1024;
+ dfa_ctl = DFA_FB_STRIDE_1k;
+ }
+
+ /* Set up framebuffer definition */
+ wid_tiles = (var->xres_virtual + 63) >> 6;
+
+ /* XXX add proper FB allocation here someday */
+ writereg(par, FB_AB_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
+ writereg(par, REFRESH_AB_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
+ writereg(par, FB_CD_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
+ writereg(par, REFRESH_CD_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
+ writereg(par, REFRESH_START, (var->xoffset << 16) | var->yoffset);
+ writereg(par, REFRESH_SIZE, (var->xres << 16) | var->yres);
+
+ /* Set up framebuffer access by CPU */
+
+ pixfmt = par->pixfmt;
+ dfa_ctl |= DFA_FB_ENABLE | pixfmt;
+ writereg(par, DFA_FB_A, dfa_ctl);
+
+ /*
+ * Set up window attribute table.
+ * We set all WAT entries the same so it doesn't matter what the
+ * window ID (WID) plane contains.
+ */
+ for (i = 0; i < 32; ++i) {
+ writereg(par, WAT_FMT + (i << 4), watfmt[pixfmt]);
+ writereg(par, WAT_CMAP_OFFSET + (i << 4), 0);
+ writereg(par, WAT_CTRL + (i << 4), 0);
+ writereg(par, WAT_GAMMA_CTRL + (i << 4), WAT_GAMMA_DISABLE);
+ }
+
+ /* Set sync polarity etc. */
+ ctrlreg = readreg(par, SYNC_CTL) &
+ ~(SYNC_CTL_SYNC_ON_RGB | SYNC_CTL_HSYNC_INV |
+ SYNC_CTL_VSYNC_INV);
+ if (var->sync & FB_SYNC_ON_GREEN)
+ ctrlreg |= SYNC_CTL_SYNC_ON_RGB;
+ if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
+ ctrlreg |= SYNC_CTL_HSYNC_INV;
+ if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
+ ctrlreg |= SYNC_CTL_VSYNC_INV;
+ writereg(par, SYNC_CTL, ctrlreg);
+
+ info->fix.line_length = stride * pixsize[pixfmt];
+ info->fix.visual = (pixfmt == DFA_PIX_8BIT)? FB_VISUAL_PSEUDOCOLOR:
+ FB_VISUAL_DIRECTCOLOR;
+
+ return 0;
+}
+
+static int gxt4500_setcolreg(unsigned int reg, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
+{
+ u32 cmap_entry;
+ struct gxt4500_par *par = info->par;
+
+ if (reg > 1023)
+ return 1;
+ cmap_entry = ((transp & 0xff00) << 16) | ((red & 0xff00) << 8) |
+ (green & 0xff00) | (blue >> 8);
+ writereg(par, CMAP + reg * 4, cmap_entry);
+
+ if (reg < 16 && par->pixfmt != DFA_PIX_8BIT) {
+ u32 *pal = info->pseudo_palette;
+ u32 val = reg;
+ switch (par->pixfmt) {
+ case DFA_PIX_16BIT_565:
+ val |= (reg << 11) | (reg << 6);
+ break;
+ case DFA_PIX_16BIT_1555:
+ val |= (reg << 10) | (reg << 5);
+ break;
+ case DFA_PIX_32BIT:
+ val |= (reg << 24);
+ /* fall through */
+ case DFA_PIX_24BIT:
+ val |= (reg << 16) | (reg << 8);
+ break;
+ }
+ pal[reg] = val;
+ }
+
+ return 0;
+}
+
+static int gxt4500_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct gxt4500_par *par = info->par;
+
+ if (var->xoffset & 7)
+ return -EINVAL;
+ if (var->xoffset + var->xres > var->xres_virtual ||
+ var->yoffset + var->yres > var->yres_virtual)
+ return -EINVAL;
+
+ writereg(par, REFRESH_START, (var->xoffset << 16) | var->yoffset);
+ return 0;
+}
+
+static int gxt4500_blank(int blank, struct fb_info *info)
+{
+ struct gxt4500_par *par = info->par;
+ int ctrl, dctl;
+
+ ctrl = readreg(par, SYNC_CTL);
+ ctrl &= ~(SYNC_CTL_SYNC_OFF | SYNC_CTL_HSYNC_OFF | SYNC_CTL_VSYNC_OFF);
+ dctl = readreg(par, DISP_CTL);
+ dctl |= DISP_CTL_OFF;
+ switch (blank) {
+ case FB_BLANK_UNBLANK:
+ dctl &= ~DISP_CTL_OFF;
+ break;
+ case FB_BLANK_POWERDOWN:
+ ctrl |= SYNC_CTL_SYNC_OFF;
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ ctrl |= SYNC_CTL_HSYNC_OFF;
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ ctrl |= SYNC_CTL_VSYNC_OFF;
+ break;
+ default: ;
+ }
+ writereg(par, SYNC_CTL, ctrl);
+ writereg(par, DISP_CTL, dctl);
+
+ return 0;
+}
+
+static const struct fb_fix_screeninfo gxt4500_fix __devinitdata = {
+ .id = "IBM GXT4500P",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_PSEUDOCOLOR,
+ .xpanstep = 8,
+ .ypanstep = 1,
+ .mmio_len = 0x20000,
+};
+
+static struct fb_ops gxt4500_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = gxt4500_check_var,
+ .fb_set_par = gxt4500_set_par,
+ .fb_setcolreg = gxt4500_setcolreg,
+ .fb_pan_display = gxt4500_pan_display,
+ .fb_blank = gxt4500_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+/* PCI functions */
+static int __devinit gxt4500_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int err;
+ unsigned long reg_phys, fb_phys;
+ struct gxt4500_par *par;
+ struct fb_info *info;
+ struct fb_var_screeninfo var;
+ enum gxt_cards cardtype;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "gxt4500: cannot enable PCI device: %d\n",
+ err);
+ return err;
+ }
+
+ reg_phys = pci_resource_start(pdev, 0);
+ if (!request_mem_region(reg_phys, pci_resource_len(pdev, 0),
+ "gxt4500 regs")) {
+ dev_err(&pdev->dev, "gxt4500: cannot get registers\n");
+ goto err_nodev;
+ }
+
+ fb_phys = pci_resource_start(pdev, 1);
+ if (!request_mem_region(fb_phys, pci_resource_len(pdev, 1),
+ "gxt4500 FB")) {
+ dev_err(&pdev->dev, "gxt4500: cannot get framebuffer\n");
+ goto err_free_regs;
+ }
+
+ info = framebuffer_alloc(sizeof(struct gxt4500_par), &pdev->dev);
+ if (!info) {
+ dev_err(&pdev->dev, "gxt4500: cannot alloc FB info record");
+ goto err_free_fb;
+ }
+ par = info->par;
+ cardtype = ent->driver_data;
+ par->refclk_ps = cardinfo[cardtype].refclk_ps;
+ info->fix = gxt4500_fix;
+ strlcpy(info->fix.id, cardinfo[cardtype].cardname,
+ sizeof(info->fix.id));
+ info->pseudo_palette = par->pseudo_palette;
+
+ info->fix.mmio_start = reg_phys;
+ par->regs = ioremap(reg_phys, pci_resource_len(pdev, 0));
+ if (!par->regs) {
+ dev_err(&pdev->dev, "gxt4500: cannot map registers\n");
+ goto err_free_all;
+ }
+
+ info->fix.smem_start = fb_phys;
+ info->fix.smem_len = pci_resource_len(pdev, 1);
+ info->screen_base = ioremap(fb_phys, pci_resource_len(pdev, 1));
+ if (!info->screen_base) {
+ dev_err(&pdev->dev, "gxt4500: cannot map framebuffer\n");
+ goto err_unmap_regs;
+ }
+
+ pci_set_drvdata(pdev, info);
+
+ /* Set byte-swapping for DFA aperture for all pixel sizes */
+ pci_write_config_dword(pdev, CFG_ENDIAN0, 0x333300);
+
+ info->fbops = &gxt4500_ops;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ err = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (err) {
+ dev_err(&pdev->dev, "gxt4500: cannot allocate cmap\n");
+ goto err_unmap_all;
+ }
+
+ gxt4500_blank(FB_BLANK_UNBLANK, info);
+
+ if (!fb_find_mode(&var, info, mode_option, NULL, 0, &defaultmode, 8)) {
+ dev_err(&pdev->dev, "gxt4500: cannot find valid video mode\n");
+ goto err_free_cmap;
+ }
+ info->var = var;
+ if (gxt4500_set_par(info)) {
+ printk(KERN_ERR "gxt4500: cannot set video mode\n");
+ goto err_free_cmap;
+ }
+
+ if (register_framebuffer(info) < 0) {
+ dev_err(&pdev->dev, "gxt4500: cannot register framebuffer\n");
+ goto err_free_cmap;
+ }
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ info->node, info->fix.id);
+
+ return 0;
+
+ err_free_cmap:
+ fb_dealloc_cmap(&info->cmap);
+ err_unmap_all:
+ iounmap(info->screen_base);
+ err_unmap_regs:
+ iounmap(par->regs);
+ err_free_all:
+ framebuffer_release(info);
+ err_free_fb:
+ release_mem_region(fb_phys, pci_resource_len(pdev, 1));
+ err_free_regs:
+ release_mem_region(reg_phys, pci_resource_len(pdev, 0));
+ err_nodev:
+ return -ENODEV;
+}
+
+static void __devexit gxt4500_remove(struct pci_dev *pdev)
+{
+ struct fb_info *info = pci_get_drvdata(pdev);
+ struct gxt4500_par *par;
+
+ if (!info)
+ return;
+ par = info->par;
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+ iounmap(par->regs);
+ iounmap(info->screen_base);
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ release_mem_region(pci_resource_start(pdev, 1),
+ pci_resource_len(pdev, 1));
+ framebuffer_release(info);
+}
+
+/* supported chipsets */
+static const struct pci_device_id gxt4500_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4500P),
+ .driver_data = GXT4500P },
+ { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6000P),
+ .driver_data = GXT6000P },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, gxt4500_pci_tbl);
+
+static struct pci_driver gxt4500_driver = {
+ .name = "gxt4500",
+ .id_table = gxt4500_pci_tbl,
+ .probe = gxt4500_probe,
+ .remove = __devexit_p(gxt4500_remove),
+};
+
+static int __devinit gxt4500_init(void)
+{
+#ifndef MODULE
+ if (fb_get_options("gxt4500", &mode_option))
+ return -ENODEV;
+#endif
+
+ return pci_register_driver(&gxt4500_driver);
+}
+module_init(gxt4500_init);
+
+static void __exit gxt4500_exit(void)
+{
+ pci_unregister_driver(&gxt4500_driver);
+}
+module_exit(gxt4500_exit);
+
+MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
+MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P/6000P");
+MODULE_LICENSE("GPL");
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\"");
diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c
index 91cf3b577d1..9ab9b839a0f 100644
--- a/drivers/video/hpfb.c
+++ b/drivers/video/hpfb.c
@@ -295,6 +295,8 @@ static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base
if (register_framebuffer(&fb_info) < 0) {
fb_dealloc_cmap(&fb_info.cmap);
+ iounmap(fb_info.screen_base);
+ fb_info.screen_base = NULL;
return 1;
}
diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c
index b38d805db31..961f4d40446 100644
--- a/drivers/video/i810/i810-i2c.c
+++ b/drivers/video/i810/i810-i2c.c
@@ -137,15 +137,15 @@ void i810_create_i2c_busses(struct i810fb_par *par)
void i810_delete_i2c_busses(struct i810fb_par *par)
{
if (par->chan[0].par)
- i2c_bit_del_bus(&par->chan[0].adapter);
+ i2c_del_adapter(&par->chan[0].adapter);
par->chan[0].par = NULL;
if (par->chan[1].par)
- i2c_bit_del_bus(&par->chan[1].adapter);
+ i2c_del_adapter(&par->chan[1].adapter);
par->chan[1].par = NULL;
if (par->chan[2].par)
- i2c_bit_del_bus(&par->chan[2].adapter);
+ i2c_del_adapter(&par->chan[2].adapter);
par->chan[2].par = NULL;
}
@@ -162,9 +162,7 @@ int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
if (e != NULL) {
DPRINTK("i810-i2c: Getting EDID from BIOS\n");
- edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
- if (edid)
- memcpy(edid, e, EDID_LENGTH);
+ edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
}
}
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index e6df492c22a..655ae0fa99c 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -384,19 +384,21 @@ int __init igafb_init(void)
if (!con_is_present())
return -ENXIO;
- pdev = pci_find_device(PCI_VENDOR_ID_INTERG,
+ pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
PCI_DEVICE_ID_INTERG_1682, 0);
if (pdev == NULL) {
/*
* XXX We tried to use cyber2000fb.c for IGS 2000.
* But it does not initialize the chip in JavaStation-E, alas.
*/
- pdev = pci_find_device(PCI_VENDOR_ID_INTERG, 0x2000, 0);
+ pdev = pci_get_device(PCI_VENDOR_ID_INTERG, 0x2000, 0);
if(pdev == NULL) {
return -ENXIO;
}
iga2000 = 1;
}
+ /* We leak a reference here but as it cannot be unloaded this is
+ fine. If you write unload code remember to free it in unload */
size = sizeof(struct fb_info) + sizeof(struct iga_par) + sizeof(u32)*16;
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
index 5686e2164e3..33bc41f5054 100644
--- a/drivers/video/intelfb/intelfb_i2c.c
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -188,11 +188,11 @@ void intelfb_delete_i2c_busses(struct intelfb_info *dinfo)
for (i = 0; i < MAX_OUTPUTS; i++) {
if (dinfo->output[i].i2c_bus.dinfo) {
- i2c_bit_del_bus(&dinfo->output[i].i2c_bus.adapter);
+ i2c_del_adapter(&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);
+ i2c_del_adapter(&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 6f9de04193d..664fc5cf962 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1058,10 +1058,9 @@ intelfb_init_var(struct intelfb_info *dinfo)
u8 *edid_d = NULL;
if (edid_s) {
- edid_d = kmalloc(EDID_LENGTH, GFP_KERNEL);
+ edid_d = kmemdup(edid_s, EDID_LENGTH, GFP_KERNEL);
if (edid_d) {
- memcpy(edid_d, edid_s, EDID_LENGTH);
fb_edid_to_monspecs(edid_d,
&dinfo->info->monspecs);
kfree(edid_d);
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index f3a24338d9a..a038aa5a9e1 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -530,20 +530,21 @@ struct all_info {
struct leo_par par;
};
-static void leo_unmap_regs(struct all_info *all)
+static void leo_unmap_regs(struct of_device *op, struct all_info *all)
{
if (all->par.lc_ss0_usr)
- of_iounmap(all->par.lc_ss0_usr, 0x1000);
+ of_iounmap(&op->resource[0], all->par.lc_ss0_usr, 0x1000);
if (all->par.ld_ss0)
- of_iounmap(all->par.ld_ss0, 0x1000);
+ of_iounmap(&op->resource[0], all->par.ld_ss0, 0x1000);
if (all->par.ld_ss1)
- of_iounmap(all->par.ld_ss1, 0x1000);
+ of_iounmap(&op->resource[0], all->par.ld_ss1, 0x1000);
if (all->par.lx_krn)
- of_iounmap(all->par.lx_krn, 0x1000);
+ of_iounmap(&op->resource[0], all->par.lx_krn, 0x1000);
if (all->par.cursor)
- of_iounmap(all->par.cursor, sizeof(struct leo_cursor));
+ of_iounmap(&op->resource[0],
+ all->par.cursor, sizeof(struct leo_cursor));
if (all->info.screen_base)
- of_iounmap(all->info.screen_base, 0x800000);
+ of_iounmap(&op->resource[0], all->info.screen_base, 0x800000);
}
static int __devinit leo_init_one(struct of_device *op)
@@ -592,7 +593,7 @@ static int __devinit leo_init_one(struct of_device *op)
!all->par.lx_krn ||
!all->par.cursor ||
!all->info.screen_base) {
- leo_unmap_regs(all);
+ leo_unmap_regs(op, all);
kfree(all);
return -ENOMEM;
}
@@ -607,7 +608,7 @@ static int __devinit leo_init_one(struct of_device *op)
leo_blank(0, &all->info);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- leo_unmap_regs(all);
+ leo_unmap_regs(op, all);
kfree(all);
return -ENOMEM;;
}
@@ -617,7 +618,7 @@ static int __devinit leo_init_one(struct of_device *op)
err = register_framebuffer(&all->info);
if (err < 0) {
fb_dealloc_cmap(&all->info.cmap);
- leo_unmap_regs(all);
+ leo_unmap_regs(op, all);
kfree(all);
return err;
}
@@ -638,18 +639,18 @@ static int __devinit leo_probe(struct of_device *dev, const struct of_device_id
return leo_init_one(op);
}
-static int __devexit leo_remove(struct of_device *dev)
+static int __devexit leo_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&dev->dev);
+ struct all_info *all = dev_get_drvdata(&op->dev);
unregister_framebuffer(&all->info);
fb_dealloc_cmap(&all->info.cmap);
- leo_unmap_regs(all);
+ leo_unmap_regs(op, all);
kfree(all);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index 80a04380716..180d94c2b4d 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -608,6 +608,22 @@ void __init macfb_setup(char *options)
}
}
+static void __init iounmap_macfb(void)
+{
+ if (valkyrie_cmap_regs)
+ iounmap(valkyrie_cmap_regs);
+ if (dafb_cmap_regs)
+ iounmap(dafb_cmap_regs);
+ if (v8_brazil_cmap_regs)
+ iounmap(v8_brazil_cmap_regs);
+ if (rbv_cmap_regs)
+ iounmap(rbv_cmap_regs);
+ if (civic_cmap_regs)
+ iounmap(civic_cmap_regs);
+ if (csc_cmap_regs)
+ iounmap(csc_cmap_regs);
+}
+
static int __init macfb_init(void)
{
int video_cmap_len, video_is_nubus = 0;
@@ -962,6 +978,10 @@ static int __init macfb_init(void)
if (!err)
printk("fb%d: %s frame buffer device\n",
fb_info.node, fb_info.fix.id);
+ else {
+ iounmap(fb_info.screen_base);
+ iounmap_macfb();
+ }
return err;
}
diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
index 795c1a99a68..fe28848e7b5 100644
--- a/drivers/video/matrox/i2c-matroxfb.c
+++ b/drivers/video/matrox/i2c-matroxfb.c
@@ -124,7 +124,7 @@ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
static void i2c_bit_bus_del(struct i2c_bit_adapter* b) {
if (b->initialized) {
- i2c_bit_del_bus(&b->adapter);
+ i2c_del_adapter(&b->adapter);
b->initialized = 0;
}
}
@@ -146,7 +146,7 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
unsigned long flags;
struct matroxfb_dh_maven_info* m2info;
- m2info = (struct matroxfb_dh_maven_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
+ m2info = kmalloc(sizeof(*m2info), GFP_KERNEL);
if (!m2info)
return NULL;
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index e9b4115fcad..cb2aa402ddf 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -2028,7 +2028,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
}
#ifdef CONFIG_FB_MATROX_MULTIHEAD
- minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL);
+ minfo = kmalloc(sizeof(*minfo), GFP_KERNEL);
if (!minfo)
return -1;
#else
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
index 27eb4bb4f89..2c9801090fa 100644
--- a/drivers/video/matrox/matroxfb_crtc2.c
+++ b/drivers/video/matrox/matroxfb_crtc2.c
@@ -694,7 +694,7 @@ static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) {
/* hardware is CRTC2 incapable... */
if (!ACCESS_FBINFO(devflags.crtc2))
return NULL;
- m2info = (struct matroxfb_dh_fb_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
+ m2info = kmalloc(sizeof(*m2info), GFP_KERNEL);
if (!m2info) {
printk(KERN_ERR "matroxfb_crtc2: Not enough memory for CRTC2 control structs\n");
return NULL;
diff --git a/drivers/video/mbx/mbxdebugfs.c b/drivers/video/mbx/mbxdebugfs.c
index 84aab3ad024..472a3ca3d92 100644
--- a/drivers/video/mbx/mbxdebugfs.c
+++ b/drivers/video/mbx/mbxdebugfs.c
@@ -10,6 +10,8 @@ struct mbxfb_debugfs_data {
struct dentry *clock;
struct dentry *display;
struct dentry *gsctl;
+ struct dentry *sdram;
+ struct dentry *misc;
};
static int open_file_generic(struct inode *inode, struct file *file)
@@ -29,11 +31,11 @@ static ssize_t sysconf_read_file(struct file *file, char __user *userbuf,
{
char * s = big_buffer;
- s += sprintf(s, "SYSCFG = %08lx\n", SYSCFG);
- s += sprintf(s, "PFBASE = %08lx\n", PFBASE);
- s += sprintf(s, "PFCEIL = %08lx\n", PFCEIL);
- s += sprintf(s, "POLLFLAG = %08lx\n", POLLFLAG);
- s += sprintf(s, "SYSRST = %08lx\n", SYSRST);
+ s += sprintf(s, "SYSCFG = %08x\n", readl(SYSCFG));
+ s += sprintf(s, "PFBASE = %08x\n", readl(PFBASE));
+ s += sprintf(s, "PFCEIL = %08x\n", readl(PFCEIL));
+ s += sprintf(s, "POLLFLAG = %08x\n", readl(POLLFLAG));
+ s += sprintf(s, "SYSRST = %08x\n", readl(SYSRST));
return simple_read_from_buffer(userbuf, count, ppos,
big_buffer, s-big_buffer);
@@ -45,24 +47,24 @@ static ssize_t gsctl_read_file(struct file *file, char __user *userbuf,
{
char * s = big_buffer;
- s += sprintf(s, "GSCTRL = %08lx\n", GSCTRL);
- s += sprintf(s, "VSCTRL = %08lx\n", VSCTRL);
- s += sprintf(s, "GBBASE = %08lx\n", GBBASE);
- s += sprintf(s, "VBBASE = %08lx\n", VBBASE);
- s += sprintf(s, "GDRCTRL = %08lx\n", GDRCTRL);
- s += sprintf(s, "VCMSK = %08lx\n", VCMSK);
- s += sprintf(s, "GSCADR = %08lx\n", GSCADR);
- s += sprintf(s, "VSCADR = %08lx\n", VSCADR);
- s += sprintf(s, "VUBASE = %08lx\n", VUBASE);
- s += sprintf(s, "VVBASE = %08lx\n", VVBASE);
- s += sprintf(s, "GSADR = %08lx\n", GSADR);
- s += sprintf(s, "VSADR = %08lx\n", VSADR);
- s += sprintf(s, "HCCTRL = %08lx\n", HCCTRL);
- s += sprintf(s, "HCSIZE = %08lx\n", HCSIZE);
- s += sprintf(s, "HCPOS = %08lx\n", HCPOS);
- s += sprintf(s, "HCBADR = %08lx\n", HCBADR);
- s += sprintf(s, "HCCKMSK = %08lx\n", HCCKMSK);
- s += sprintf(s, "GPLUT = %08lx\n", GPLUT);
+ s += sprintf(s, "GSCTRL = %08x\n", readl(GSCTRL));
+ s += sprintf(s, "VSCTRL = %08x\n", readl(VSCTRL));
+ s += sprintf(s, "GBBASE = %08x\n", readl(GBBASE));
+ s += sprintf(s, "VBBASE = %08x\n", readl(VBBASE));
+ s += sprintf(s, "GDRCTRL = %08x\n", readl(GDRCTRL));
+ s += sprintf(s, "VCMSK = %08x\n", readl(VCMSK));
+ s += sprintf(s, "GSCADR = %08x\n", readl(GSCADR));
+ s += sprintf(s, "VSCADR = %08x\n", readl(VSCADR));
+ s += sprintf(s, "VUBASE = %08x\n", readl(VUBASE));
+ s += sprintf(s, "VVBASE = %08x\n", readl(VVBASE));
+ s += sprintf(s, "GSADR = %08x\n", readl(GSADR));
+ s += sprintf(s, "VSADR = %08x\n", readl(VSADR));
+ s += sprintf(s, "HCCTRL = %08x\n", readl(HCCTRL));
+ s += sprintf(s, "HCSIZE = %08x\n", readl(HCSIZE));
+ s += sprintf(s, "HCPOS = %08x\n", readl(HCPOS));
+ s += sprintf(s, "HCBADR = %08x\n", readl(HCBADR));
+ s += sprintf(s, "HCCKMSK = %08x\n", readl(HCCKMSK));
+ s += sprintf(s, "GPLUT = %08x\n", readl(GPLUT));
return simple_read_from_buffer(userbuf, count, ppos,
big_buffer, s-big_buffer);
@@ -73,36 +75,36 @@ static ssize_t display_read_file(struct file *file, char __user *userbuf,
{
char * s = big_buffer;
- s += sprintf(s, "DSCTRL = %08lx\n", DSCTRL);
- s += sprintf(s, "DHT01 = %08lx\n", DHT01);
- s += sprintf(s, "DHT02 = %08lx\n", DHT02);
- s += sprintf(s, "DHT03 = %08lx\n", DHT03);
- s += sprintf(s, "DVT01 = %08lx\n", DVT01);
- s += sprintf(s, "DVT02 = %08lx\n", DVT02);
- s += sprintf(s, "DVT03 = %08lx\n", DVT03);
- s += sprintf(s, "DBCOL = %08lx\n", DBCOL);
- s += sprintf(s, "BGCOLOR = %08lx\n", BGCOLOR);
- s += sprintf(s, "DINTRS = %08lx\n", DINTRS);
- s += sprintf(s, "DINTRE = %08lx\n", DINTRE);
- s += sprintf(s, "DINTRCNT = %08lx\n", DINTRCNT);
- s += sprintf(s, "DSIG = %08lx\n", DSIG);
- s += sprintf(s, "DMCTRL = %08lx\n", DMCTRL);
- s += sprintf(s, "CLIPCTRL = %08lx\n", CLIPCTRL);
- s += sprintf(s, "SPOCTRL = %08lx\n", SPOCTRL);
- s += sprintf(s, "SVCTRL = %08lx\n", SVCTRL);
- s += sprintf(s, "DLSTS = %08lx\n", DLSTS);
- s += sprintf(s, "DLLCTRL = %08lx\n", DLLCTRL);
- s += sprintf(s, "DVLNUM = %08lx\n", DVLNUM);
- s += sprintf(s, "DUCTRL = %08lx\n", DUCTRL);
- s += sprintf(s, "DVECTRL = %08lx\n", DVECTRL);
- s += sprintf(s, "DHDET = %08lx\n", DHDET);
- s += sprintf(s, "DVDET = %08lx\n", DVDET);
- s += sprintf(s, "DODMSK = %08lx\n", DODMSK);
- s += sprintf(s, "CSC01 = %08lx\n", CSC01);
- s += sprintf(s, "CSC02 = %08lx\n", CSC02);
- s += sprintf(s, "CSC03 = %08lx\n", CSC03);
- s += sprintf(s, "CSC04 = %08lx\n", CSC04);
- s += sprintf(s, "CSC05 = %08lx\n", CSC05);
+ s += sprintf(s, "DSCTRL = %08x\n", readl(DSCTRL));
+ s += sprintf(s, "DHT01 = %08x\n", readl(DHT01));
+ s += sprintf(s, "DHT02 = %08x\n", readl(DHT02));
+ s += sprintf(s, "DHT03 = %08x\n", readl(DHT03));
+ s += sprintf(s, "DVT01 = %08x\n", readl(DVT01));
+ s += sprintf(s, "DVT02 = %08x\n", readl(DVT02));
+ s += sprintf(s, "DVT03 = %08x\n", readl(DVT03));
+ s += sprintf(s, "DBCOL = %08x\n", readl(DBCOL));
+ s += sprintf(s, "BGCOLOR = %08x\n", readl(BGCOLOR));
+ s += sprintf(s, "DINTRS = %08x\n", readl(DINTRS));
+ s += sprintf(s, "DINTRE = %08x\n", readl(DINTRE));
+ s += sprintf(s, "DINTRCNT = %08x\n", readl(DINTRCNT));
+ s += sprintf(s, "DSIG = %08x\n", readl(DSIG));
+ s += sprintf(s, "DMCTRL = %08x\n", readl(DMCTRL));
+ s += sprintf(s, "CLIPCTRL = %08x\n", readl(CLIPCTRL));
+ s += sprintf(s, "SPOCTRL = %08x\n", readl(SPOCTRL));
+ s += sprintf(s, "SVCTRL = %08x\n", readl(SVCTRL));
+ s += sprintf(s, "DLSTS = %08x\n", readl(DLSTS));
+ s += sprintf(s, "DLLCTRL = %08x\n", readl(DLLCTRL));
+ s += sprintf(s, "DVLNUM = %08x\n", readl(DVLNUM));
+ s += sprintf(s, "DUCTRL = %08x\n", readl(DUCTRL));
+ s += sprintf(s, "DVECTRL = %08x\n", readl(DVECTRL));
+ s += sprintf(s, "DHDET = %08x\n", readl(DHDET));
+ s += sprintf(s, "DVDET = %08x\n", readl(DVDET));
+ s += sprintf(s, "DODMSK = %08x\n", readl(DODMSK));
+ s += sprintf(s, "CSC01 = %08x\n", readl(CSC01));
+ s += sprintf(s, "CSC02 = %08x\n", readl(CSC02));
+ s += sprintf(s, "CSC03 = %08x\n", readl(CSC03));
+ s += sprintf(s, "CSC04 = %08x\n", readl(CSC04));
+ s += sprintf(s, "CSC05 = %08x\n", readl(CSC05));
return simple_read_from_buffer(userbuf, count, ppos,
big_buffer, s-big_buffer);
@@ -113,24 +115,61 @@ static ssize_t clock_read_file(struct file *file, char __user *userbuf,
{
char * s = big_buffer;
- s += sprintf(s, "SYSCLKSRC = %08lx\n", SYSCLKSRC);
- s += sprintf(s, "PIXCLKSRC = %08lx\n", PIXCLKSRC);
- s += sprintf(s, "CLKSLEEP = %08lx\n", CLKSLEEP);
- s += sprintf(s, "COREPLL = %08lx\n", COREPLL);
- s += sprintf(s, "DISPPLL = %08lx\n", DISPPLL);
- s += sprintf(s, "PLLSTAT = %08lx\n", PLLSTAT);
- s += sprintf(s, "VOVRCLK = %08lx\n", VOVRCLK);
- s += sprintf(s, "PIXCLK = %08lx\n", PIXCLK);
- s += sprintf(s, "MEMCLK = %08lx\n", MEMCLK);
- s += sprintf(s, "M24CLK = %08lx\n", M24CLK);
- s += sprintf(s, "MBXCLK = %08lx\n", MBXCLK);
- s += sprintf(s, "SDCLK = %08lx\n", SDCLK);
- s += sprintf(s, "PIXCLKDIV = %08lx\n", PIXCLKDIV);
+ s += sprintf(s, "SYSCLKSRC = %08x\n", readl(SYSCLKSRC));
+ s += sprintf(s, "PIXCLKSRC = %08x\n", readl(PIXCLKSRC));
+ s += sprintf(s, "CLKSLEEP = %08x\n", readl(CLKSLEEP));
+ s += sprintf(s, "COREPLL = %08x\n", readl(COREPLL));
+ s += sprintf(s, "DISPPLL = %08x\n", readl(DISPPLL));
+ s += sprintf(s, "PLLSTAT = %08x\n", readl(PLLSTAT));
+ s += sprintf(s, "VOVRCLK = %08x\n", readl(VOVRCLK));
+ s += sprintf(s, "PIXCLK = %08x\n", readl(PIXCLK));
+ s += sprintf(s, "MEMCLK = %08x\n", readl(MEMCLK));
+ s += sprintf(s, "M24CLK = %08x\n", readl(M24CLK));
+ s += sprintf(s, "MBXCLK = %08x\n", readl(MBXCLK));
+ s += sprintf(s, "SDCLK = %08x\n", readl(SDCLK));
+ s += sprintf(s, "PIXCLKDIV = %08x\n", readl(PIXCLKDIV));
return simple_read_from_buffer(userbuf, count, ppos,
big_buffer, s-big_buffer);
}
+static ssize_t sdram_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "LMRST = %08x\n", readl(LMRST));
+ s += sprintf(s, "LMCFG = %08x\n", readl(LMCFG));
+ s += sprintf(s, "LMPWR = %08x\n", readl(LMPWR));
+ s += sprintf(s, "LMPWRSTAT = %08x\n", readl(LMPWRSTAT));
+ s += sprintf(s, "LMCEMR = %08x\n", readl(LMCEMR));
+ s += sprintf(s, "LMTYPE = %08x\n", readl(LMTYPE));
+ s += sprintf(s, "LMTIM = %08x\n", readl(LMTIM));
+ s += sprintf(s, "LMREFRESH = %08x\n", readl(LMREFRESH));
+ s += sprintf(s, "LMPROTMIN = %08x\n", readl(LMPROTMIN));
+ s += sprintf(s, "LMPROTMAX = %08x\n", readl(LMPROTMAX));
+ s += sprintf(s, "LMPROTCFG = %08x\n", readl(LMPROTCFG));
+ s += sprintf(s, "LMPROTERR = %08x\n", readl(LMPROTERR));
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+static ssize_t misc_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "LCD_CONFIG = %08x\n", readl(LCD_CONFIG));
+ s += sprintf(s, "ODFBPWR = %08x\n", readl(ODFBPWR));
+ s += sprintf(s, "ODFBSTAT = %08x\n", readl(ODFBSTAT));
+ s += sprintf(s, "ID = %08x\n", readl(ID));
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+
static struct file_operations sysconf_fops = {
.read = sysconf_read_file,
.write = write_file_dummy,
@@ -155,6 +194,17 @@ static struct file_operations gsctl_fops = {
.open = open_file_generic,
};
+static struct file_operations sdram_fops = {
+ .read = sdram_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+static struct file_operations misc_fops = {
+ .read = misc_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
static void __devinit mbxfb_debugfs_init(struct fb_info *fbi)
{
@@ -173,6 +223,10 @@ static void __devinit mbxfb_debugfs_init(struct fb_info *fbi)
fbi, &display_fops);
dbg->gsctl = debugfs_create_file("gsctl", 0444, dbg->dir,
fbi, &gsctl_fops);
+ dbg->sdram = debugfs_create_file("sdram", 0444, dbg->dir,
+ fbi, &sdram_fops);
+ dbg->misc = debugfs_create_file("misc", 0444, dbg->dir,
+ fbi, &misc_fops);
}
static void __devexit mbxfb_debugfs_remove(struct fb_info *fbi)
@@ -180,6 +234,8 @@ static void __devexit mbxfb_debugfs_remove(struct fb_info *fbi)
struct mbxfb_info *mfbi = fbi->par;
struct mbxfb_debugfs_data *dbg = mfbi->debugfs_data;
+ debugfs_remove(dbg->misc);
+ debugfs_remove(dbg->sdram);
debugfs_remove(dbg->gsctl);
debugfs_remove(dbg->display);
debugfs_remove(dbg->clock);
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c
index a32d1af79e0..980d5f62390 100644
--- a/drivers/video/mbx/mbxfb.c
+++ b/drivers/video/mbx/mbxfb.c
@@ -1,8 +1,14 @@
/*
* linux/drivers/video/mbx/mbxfb.c
*
+ * Copyright (C) 2006 8D Technologies inc
+ * Raphael Assenat <raph@8d.com>
+ * - Added video overlay support
+ * - Various improvements
+ *
* Copyright (C) 2006 Compulab, Ltd.
* Mike Rapoport <mike@compulab.co.il>
+ * - Creation of driver
*
* Based on pxafb.c
*
@@ -19,6 +25,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/uaccess.h>
#include <asm/io.h>
@@ -29,6 +36,14 @@
static unsigned long virt_base_2700;
+#define write_reg(val, reg) do { writel((val), (reg)); } while(0)
+
+/* Without this delay, the graphics appears somehow scaled and
+ * there is a lot of jitter in scanlines. This delay is probably
+ * needed only after setting some specific register(s) somewhere,
+ * not all over the place... */
+#define write_reg_dly(val, reg) do { writel((val), reg); udelay(1000); } while(0)
+
#define MIN_XRES 16
#define MIN_YRES 16
#define MAX_XRES 2048
@@ -257,19 +272,17 @@ static int mbxfb_set_par(struct fb_info *info)
gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
gsctrl |= Gsctrl_Width(info->var.xres) |
Gsctrl_Height(info->var.yres);
- writel(gsctrl, GSCTRL);
- udelay(1000);
+ write_reg_dly(gsctrl, GSCTRL);
gsadr &= ~(FMsk(GSADR_SRCSTRIDE));
gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel /
(8 * 16) - 1);
- writel(gsadr, GSADR);
- udelay(1000);
+ write_reg_dly(gsadr, GSADR);
/* setup timings */
var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div);
- writel((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
+ write_reg_dly((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL);
hbps = var->hsync_len;
@@ -282,18 +295,20 @@ static int mbxfb_set_par(struct fb_info *info)
vfps = vas + var->yres;
vt = vfps + var->lower_margin;
- writel((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
- writel((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
- writel((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
- writel((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
+ write_reg_dly((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
+ write_reg_dly((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
+ write_reg_dly((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
+ write_reg_dly((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
- writel((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
- writel((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
- writel((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
- writel((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
- writel((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
+ write_reg_dly((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
+ write_reg_dly((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
+ write_reg_dly((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
+ write_reg_dly((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
+ write_reg_dly((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
- writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+
+ write_reg_dly(DINTRE_VEVENT0_EN, DINTRE);
return 0;
}
@@ -305,23 +320,203 @@ static int mbxfb_blank(int blank, struct fb_info *info)
case FB_BLANK_VSYNC_SUSPEND:
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_NORMAL:
- writel((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
- udelay(1000);
- writel((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
- udelay(1000);
- writel((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
- udelay(1000);
+ write_reg_dly((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
+ write_reg_dly((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
+ write_reg_dly((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
break;
case FB_BLANK_UNBLANK:
- writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
- udelay(1000);
- writel((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
- udelay(1000);
+ write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ write_reg_dly((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
break;
}
return 0;
}
+static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
+{
+ u32 vsctrl, vbbase, vscadr, vsadr;
+ u32 sssize, spoctrl, svctrl, shctrl;
+ u32 vubase, vvbase;
+ u32 vovrclk;
+
+ if (set->scaled_width==0 || set->scaled_height==0)
+ return -EINVAL;
+
+ /* read registers which have reserved bits
+ * so we can write them back as-is. */
+ vovrclk = readl(VOVRCLK);
+ vsctrl = readl(VSCTRL);
+ vscadr = readl(VSCADR);
+ vubase = readl(VUBASE);
+ vvbase = readl(VVBASE);
+
+ spoctrl = readl(SPOCTRL);
+ sssize = readl(SSSIZE);
+
+
+ vbbase = Vbbase_Glalpha(set->alpha);
+
+ vsctrl &= ~( FMsk(VSCTRL_VSWIDTH) |
+ FMsk(VSCTRL_VSHEIGHT) |
+ FMsk(VSCTRL_VPIXFMT) |
+ VSCTRL_GAMMA_EN | VSCTRL_CSC_EN |
+ VSCTRL_COSITED );
+ vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) |
+ VSCTRL_CSC_EN;
+
+ vscadr &= ~(VSCADR_STR_EN | VSCADR_COLKEY_EN | VSCADR_COLKEYSRC |
+ FMsk(VSCADR_BLEND_M) | FMsk(VSCADR_BLEND_POS) |
+ FMsk(VSCADR_VBASE_ADR) );
+ vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR));
+ vvbase &= ~(FMsk(VVBASE_VBASE_ADR));
+
+ switch (set->fmt)
+ {
+ case MBXFB_FMT_YUV12:
+ vsctrl |= VSCTRL_VPIXFMT_YUV12;
+
+ set->Y_stride = ((set->width) + 0xf ) & ~0xf;
+
+ break;
+ case MBXFB_FMT_UY0VY1:
+ vsctrl |= VSCTRL_VPIXFMT_UY0VY1;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
+ break;
+ case MBXFB_FMT_VY0UY1:
+ vsctrl |= VSCTRL_VPIXFMT_VY0UY1;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
+ break;
+ case MBXFB_FMT_Y0UY1V:
+ vsctrl |= VSCTRL_VPIXFMT_Y0UY1V;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
+ break;
+ case MBXFB_FMT_Y0VY1U:
+ vsctrl |= VSCTRL_VPIXFMT_Y0VY1U;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* VSCTRL has the bits which sets the Video Pixel Format.
+ * When passing from a packed to planar format,
+ * if we write VSCTRL first, VVBASE and VUBASE would
+ * be zero if we would not set them here. (And then,
+ * the chips hangs and only a reset seems to fix it).
+ *
+ * If course, the values calculated here have no meaning
+ * for packed formats.
+ */
+ set->UV_stride = ((set->width/2) + 0x7 ) & ~0x7;
+ set->U_offset = set->height * set->Y_stride;
+ set->V_offset = set->U_offset +
+ set->height * set->UV_stride;
+ vubase |= Vubase_Ubase_Adr(
+ (0x60000 + set->mem_offset + set->U_offset)>>3);
+ vvbase |= Vvbase_Vbase_Adr(
+ (0x60000 + set->mem_offset + set->V_offset)>>3);
+
+
+ vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_GLOB |
+ Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4);
+
+ if (set->enable)
+ vscadr |= VSCADR_STR_EN;
+
+
+ vsadr = Vsadr_Srcstride((set->Y_stride)/16-1) |
+ Vsadr_Xstart(set->x) | Vsadr_Ystart(set->y);
+
+ sssize &= ~(FMsk(SSSIZE_SC_WIDTH) | FMsk(SSSIZE_SC_HEIGHT));
+ sssize = Sssize_Sc_Width(set->scaled_width-1) |
+ Sssize_Sc_Height(set->scaled_height-1);
+
+ spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP |
+ SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C |
+ FMsk(SPOCTRL_VORDER) | FMsk(SPOCTRL_VPITCH));
+ spoctrl = Spoctrl_Vpitch((set->height<<11)/set->scaled_height)
+ | SPOCTRL_VORDER_2TAP;
+
+ /* Bypass horiz/vert scaler when same size */
+ if (set->scaled_width == set->width)
+ spoctrl |= SPOCTRL_H_SC_BP;
+ if (set->scaled_height == set->height)
+ spoctrl |= SPOCTRL_V_SC_BP;
+
+ svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10);
+
+ shctrl = Shctrl_Hinitial(4<<11)
+ | Shctrl_Hpitch((set->width<<11)/set->scaled_width);
+
+ /* Video plane registers */
+ write_reg(vsctrl, VSCTRL);
+ write_reg(vbbase, VBBASE);
+ write_reg(vscadr, VSCADR);
+ write_reg(vubase, VUBASE);
+ write_reg(vvbase, VVBASE);
+ write_reg(vsadr, VSADR);
+
+ /* Video scaler registers */
+ write_reg(sssize, SSSIZE);
+ write_reg(spoctrl, SPOCTRL);
+ write_reg(svctrl, SVCTRL);
+ write_reg(shctrl, SHCTRL);
+
+ /* RAPH: Using those coefficients, the scaled
+ * image is quite blurry. I dont know how
+ * to improve them ; The chip documentation
+ * was not helpful.. */
+ write_reg(0x21212121, VSCOEFF0);
+ write_reg(0x21212121, VSCOEFF1);
+ write_reg(0x21212121, VSCOEFF2);
+ write_reg(0x21212121, VSCOEFF3);
+ write_reg(0x21212121, VSCOEFF4);
+ write_reg(0x00000000, HSCOEFF0);
+ write_reg(0x00000000, HSCOEFF1);
+ write_reg(0x00000000, HSCOEFF2);
+ write_reg(0x03020201, HSCOEFF3);
+ write_reg(0x09070604, HSCOEFF4);
+ write_reg(0x0f0e0c0a, HSCOEFF5);
+ write_reg(0x15141211, HSCOEFF6);
+ write_reg(0x19181716, HSCOEFF7);
+ write_reg(0x00000019, HSCOEFF8);
+
+ /* Clock */
+ if (set->enable)
+ vovrclk |= 1;
+ else
+ vovrclk &= ~1;
+
+ write_reg(vovrclk, VOVRCLK);
+
+ return 0;
+}
+
+static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mbxfb_overlaySetup setup;
+ int res;
+
+ if (cmd == MBXFB_IOCX_OVERLAY)
+ {
+ if (copy_from_user(&setup, (void __user*)arg,
+ sizeof(struct mbxfb_overlaySetup)))
+ return -EFAULT;
+
+ res = mbxfb_setupOverlay(&setup);
+ if (res)
+ return res;
+
+ if (copy_to_user((void __user*)arg, &setup,
+ sizeof(struct mbxfb_overlaySetup)))
+ return -EFAULT;
+
+ return 0;
+ }
+ return -EINVAL;
+}
+
static struct fb_ops mbxfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = mbxfb_check_var,
@@ -331,6 +526,7 @@ static struct fb_ops mbxfb_ops = {
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_blank = mbxfb_blank,
+ .fb_ioctl = mbxfb_ioctl,
};
/*
@@ -339,36 +535,29 @@ static struct fb_ops mbxfb_ops = {
*/
static void __devinit setup_memc(struct fb_info *fbi)
{
- struct mbxfb_info *mfbi = fbi->par;
unsigned long tmp;
int i;
/* FIXME: use platfrom specific parameters */
/* setup SDRAM controller */
- writel((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
+ write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
LMCFG_LMA_TS),
LMCFG);
- udelay(1000);
- writel(LMPWR_MC_PWR_ACT, LMPWR);
- udelay(1000);
+ write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
/* setup SDRAM timings */
- writel((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
+ write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
Lmtim_Trc(9) | Lmtim_Tdpl(2)),
LMTIM);
- udelay(1000);
/* setup SDRAM refresh rate */
- writel(0xc2b, LMREFRESH);
- udelay(1000);
+ write_reg_dly(0xc2b, LMREFRESH);
/* setup SDRAM type parameters */
- writel((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
+ write_reg_dly((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
LMTYPE_COLSZ_8),
LMTYPE);
- udelay(1000);
/* enable memory controller */
- writel(LMPWR_MC_PWR_ACT, LMPWR);
- udelay(1000);
+ write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
/* perform dummy reads */
for ( i = 0; i < 16; i++ ) {
@@ -379,34 +568,30 @@ static void __devinit setup_memc(struct fb_info *fbi)
static void enable_clocks(struct fb_info *fbi)
{
/* enable clocks */
- writel(SYSCLKSRC_PLL_2, SYSCLKSRC);
- udelay(1000);
- writel(PIXCLKSRC_PLL_1, PIXCLKSRC);
- udelay(1000);
- writel(0x00000000, CLKSLEEP);
- udelay(1000);
- writel((Core_Pll_M(0x17) | Core_Pll_N(0x3) | Core_Pll_P(0x0) |
+ write_reg_dly(SYSCLKSRC_PLL_2, SYSCLKSRC);
+ write_reg_dly(PIXCLKSRC_PLL_1, PIXCLKSRC);
+ write_reg_dly(0x00000000, CLKSLEEP);
+
+ /* PLL output = (Frefclk * M) / (N * 2^P )
+ *
+ * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz!
+ * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz
+ * */
+ write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) |
CORE_PLL_EN),
COREPLL);
- udelay(1000);
- writel((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
+
+ write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
DISP_PLL_EN),
DISPPLL);
- writel(0x00000000, VOVRCLK);
- udelay(1000);
- writel(PIXCLK_EN, PIXCLK);
- udelay(1000);
- writel(MEMCLK_EN, MEMCLK);
- udelay(1000);
- writel(0x00000006, M24CLK);
- udelay(1000);
- writel(0x00000006, MBXCLK);
- udelay(1000);
- writel(SDCLK_EN, SDCLK);
- udelay(1000);
- writel(0x00000001, PIXCLKDIV);
- udelay(1000);
+ write_reg_dly(0x00000000, VOVRCLK);
+ write_reg_dly(PIXCLK_EN, PIXCLK);
+ write_reg_dly(MEMCLK_EN, MEMCLK);
+ write_reg_dly(0x00000006, M24CLK);
+ write_reg_dly(0x00000006, MBXCLK);
+ write_reg_dly(SDCLK_EN, SDCLK);
+ write_reg_dly(0x00000001, PIXCLKDIV);
}
static void __devinit setup_graphics(struct fb_info *fbi)
@@ -430,16 +615,11 @@ static void __devinit setup_graphics(struct fb_info *fbi)
break;
}
- writel(gsctrl, GSCTRL);
- udelay(1000);
- writel(0x00000000, GBBASE);
- udelay(1000);
- writel(0x00ffffff, GDRCTRL);
- udelay(1000);
- writel((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
- udelay(1000);
- writel(0x00000000, GPLUT);
- udelay(1000);
+ write_reg_dly(gsctrl, GSCTRL);
+ write_reg_dly(0x00000000, GBBASE);
+ write_reg_dly(0x00ffffff, GDRCTRL);
+ write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
+ write_reg_dly(0x00000000, GPLUT);
}
static void __devinit setup_display(struct fb_info *fbi)
@@ -451,17 +631,14 @@ static void __devinit setup_display(struct fb_info *fbi)
dsctrl |= DSCTRL_HS_POL;
if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
dsctrl |= DSCTRL_VS_POL;
- writel(dsctrl, DSCTRL);
- udelay(1000);
- writel(0xd0303010, DMCTRL);
- udelay(1000);
- writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ write_reg_dly(dsctrl, DSCTRL);
+ write_reg_dly(0xd0303010, DMCTRL);
+ write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
}
static void __devinit enable_controller(struct fb_info *fbi)
{
- writel(SYSRST_RST, SYSRST);
- udelay(1000);
+ write_reg_dly(SYSRST_RST, SYSRST);
enable_clocks(fbi);
@@ -478,12 +655,12 @@ static void __devinit enable_controller(struct fb_info *fbi)
static int mbxfb_suspend(struct platform_device *dev, pm_message_t state)
{
/* make frame buffer memory enter self-refresh mode */
- writel(LMPWR_MC_PWR_SRM, LMPWR);
+ write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR);
while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM)
; /* empty statement */
/* reset the device, since it's initial state is 'mostly sleeping' */
- writel(SYSRST_RST, SYSRST);
+ write_reg_dly(SYSRST_RST, SYSRST);
return 0;
}
@@ -495,7 +672,7 @@ static int mbxfb_resume(struct platform_device *dev)
/* setup_graphics(fbi); */
/* setup_display(fbi); */
- writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
return 0;
}
#else
@@ -520,6 +697,12 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
dev_dbg(dev, "mbxfb_probe\n");
+ pdata = dev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&dev->dev, "platform data is required\n");
+ return -EINVAL;
+ }
+
fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev);
if (fbi == NULL) {
dev_err(&dev->dev, "framebuffer_alloc failed\n");
@@ -528,7 +711,8 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
mfbi = fbi->par;
fbi->pseudo_palette = mfbi->pseudo_palette;
- pdata = dev->dev.platform_data;
+
+
if (pdata->probe)
mfbi->platform_probe = pdata->probe;
if (pdata->remove)
@@ -578,16 +762,16 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
goto err4;
}
- /* FIXME: get from platform */
fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
- fbi->screen_size = 8 * 1024 * 1024; /* 8 Megs */
+ fbi->screen_size = pdata->memsize;
fbi->fbops = &mbxfb_ops;
fbi->var = mbxfb_default;
fbi->fix = mbxfb_fix;
fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000;
- fbi->fix.smem_len = 8 * 1024 * 1024;
- fbi->fix.line_length = 640 * 2;
+ fbi->fix.smem_len = pdata->memsize;
+ fbi->fix.line_length = mbxfb_default.xres_virtual *
+ mbxfb_default.bits_per_pixel / 8;
ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
if (ret < 0) {
@@ -636,8 +820,7 @@ static int __devexit mbxfb_remove(struct platform_device *dev)
{
struct fb_info *fbi = platform_get_drvdata(dev);
- writel(SYSRST_RST, SYSRST);
- udelay(1000);
+ write_reg_dly(SYSRST_RST, SYSRST);
mbxfb_debugfs_remove(fbi);
diff --git a/drivers/video/mbx/reg_bits.h b/drivers/video/mbx/reg_bits.h
index c226a8e4531..9a24fb0c7d4 100644
--- a/drivers/video/mbx/reg_bits.h
+++ b/drivers/video/mbx/reg_bits.h
@@ -242,6 +242,67 @@
#define GPLUT_LUTDATA Fld(24,0)
#define Gplut_Lutdata(x) ((x) << FShft(GPLUT_LUTDATA))
+/* VSCTRL - Video Surface Control Register */
+#define VSCTRL_VPIXFMT Fld(4,27)
+#define VSCTRL_VPIXFMT_YUV12 ((0x9) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_UY0VY1 ((0xc) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_VY0UY1 ((0xd) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_Y0UY1V ((0xe) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_Y0VY1U ((0xf) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_GAMMA_EN (1 << 26)
+#define VSCTRL_CSC_EN (1 << 25)
+#define VSCTRL_COSITED (1 << 22)
+#define VSCTRL_VSWIDTH Fld(11,11)
+#define Vsctrl_Width(Pixels) /* Video Width [1-2048] */ \
+ (((Pixels) - 1) << FShft(VSCTRL_VSWIDTH))
+#define VSCTRL_VSHEIGHT Fld(11,0)
+#define Vsctrl_Height(Pixels) /* Video Height [1-2048] */ \
+ (((Pixels) - 1) << FShft(VSCTRL_VSHEIGHT))
+
+/* VBBASE - Video Blending Base Register */
+#define VBBASE_GLALPHA Fld(8,24)
+#define Vbbase_Glalpha(x) ((x) << FShft(VBBASE_GLALPHA))
+
+#define VBBASE_COLKEY Fld(24,0)
+#define Vbbase_Colkey(x) ((x) << FShft(VBBASE_COLKEY))
+
+/* VCMSK - Video Color Key Mask Register */
+#define VCMSK_COLKEY_M Fld(24,0)
+#define Vcmsk_colkey_m(x) ((x) << FShft(VCMSK_COLKEY_M))
+
+/* VSCADR - Video Stream Control Rddress Register */
+#define VSCADR_STR_EN (1 << 31)
+#define VSCADR_COLKEY_EN (1 << 30)
+#define VSCADR_COLKEYSRC (1 << 29)
+#define VSCADR_BLEND_M Fld(2,27)
+#define VSCADR_BLEND_NONE ((0x0) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_INV ((0x1) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_GLOB ((0x2) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_PIX ((0x3) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_POS Fld(2,24)
+#define VSCADR_BLEND_GFX ((0x0) << FShft(VSCADR_BLEND_POS))
+#define VSCADR_BLEND_VID ((0x1) << FShft(VSCADR_BLEND_POS))
+#define VSCADR_BLEND_CUR ((0x2) << FShft(VSCADR_BLEND_POS))
+#define VSCADR_VBASE_ADR Fld(23,0)
+#define Vscadr_Vbase_Adr(x) ((x) << FShft(VSCADR_VBASE_ADR))
+
+/* VUBASE - Video U Base Register */
+#define VUBASE_UVHALFSTR (1 << 31)
+#define VUBASE_UBASE_ADR Fld(24,0)
+#define Vubase_Ubase_Adr(x) ((x) << FShft(VUBASE_UBASE_ADR))
+
+/* VVBASE - Video V Base Register */
+#define VVBASE_VBASE_ADR Fld(24,0)
+#define Vvbase_Vbase_Adr(x) ((x) << FShft(VVBASE_VBASE_ADR))
+
+/* VSADR - Video Stride Address Register */
+#define VSADR_SRCSTRIDE Fld(10,22)
+#define Vsadr_Srcstride(x) ((x) << FShft(VSADR_SRCSTRIDE))
+#define VSADR_XSTART Fld(11,11)
+#define Vsadr_Xstart(x) ((x) << FShft(VSADR_XSTART))
+#define VSADR_YSTART Fld(11,0)
+#define Vsadr_Ystart(x) ((x) << FShft(VSADR_YSTART))
+
/* HCCTRL - Hardware Cursor Register fields */
#define HCCTRL_CUR_EN (1 << 31)
#define HCCTRL_COLKEY_EN (1 << 29)
@@ -394,6 +455,30 @@
#define DMCTRL_BURSTLEN Fld(6,0)
#define Dmctrl_Burstlen(x) ((x) << FShft(DMCTRL_BURSTLEN))
+/* DINTRS - Display Interrupt Status Register */
+#define DINTRS_CUR_OR_S (1 << 18)
+#define DINTRS_STR2_OR_S (1 << 17)
+#define DINTRS_STR1_OR_S (1 << 16)
+#define DINTRS_CUR_UR_S (1 << 6)
+#define DINTRS_STR2_UR_S (1 << 5)
+#define DINTRS_STR1_UR_S (1 << 4)
+#define DINTRS_VEVENT1_S (1 << 3)
+#define DINTRS_VEVENT0_S (1 << 2)
+#define DINTRS_HBLNK1_S (1 << 1)
+#define DINTRS_HBLNK0_S (1 << 0)
+
+/* DINTRE - Display Interrupt Enable Register */
+#define DINTRE_CUR_OR_EN (1 << 18)
+#define DINTRE_STR2_OR_EN (1 << 17)
+#define DINTRE_STR1_OR_EN (1 << 16)
+#define DINTRE_CUR_UR_EN (1 << 6)
+#define DINTRE_STR2_UR_EN (1 << 5)
+#define DINTRE_STR1_UR_EN (1 << 4)
+#define DINTRE_VEVENT1_EN (1 << 3)
+#define DINTRE_VEVENT0_EN (1 << 2)
+#define DINTRE_HBLNK1_EN (1 << 1)
+#define DINTRE_HBLNK0_EN (1 << 0)
+
/* DLSTS - display load status register */
#define DLSTS_RLD_ADONE (1 << 23)
@@ -403,16 +488,41 @@
#define DLLCTRL_RLD_ADRLN Fld(8,24)
#define Dllctrl_Rld_Adrln(x) ((x) << FShft(DLLCTRL_RLD_ADRLN))
+/* CLIPCTRL - Clipping Control Register */
+#define CLIPCTRL_HSKIP Fld(11,16)
+#define Clipctrl_Hskip ((x) << FShft(CLIPCTRL_HSKIP))
+#define CLIPCTRL_VSKIP Fld(11,0)
+#define Clipctrl_Vskip ((x) << FShft(CLIPCTRL_VSKIP))
+
/* SPOCTRL - Scale Pitch/Order Control Register */
#define SPOCTRL_H_SC_BP (1 << 31)
#define SPOCTRL_V_SC_BP (1 << 30)
#define SPOCTRL_HV_SC_OR (1 << 29)
#define SPOCTRL_VS_UR_C (1 << 27)
-#define SPOCTRL_VORDER Fld(2,16)
+#define SPOCTRL_VORDER Fld(2,16)
#define SPOCTRL_VORDER_1TAP ((0x0) << FShft(SPOCTRL_VORDER))
#define SPOCTRL_VORDER_2TAP ((0x1) << FShft(SPOCTRL_VORDER))
#define SPOCTRL_VORDER_4TAP ((0x3) << FShft(SPOCTRL_VORDER))
-#define SPOCTRL_VPITCH Fld(16,0)
+#define SPOCTRL_VPITCH Fld(16,0)
#define Spoctrl_Vpitch(x) ((x) << FShft(SPOCTRL_VPITCH))
+/* SVCTRL - Scale Vertical Control Register */
+#define SVCTRL_INITIAL1 Fld(16,16)
+#define Svctrl_Initial1(x) ((x) << FShft(SVCTRL_INITIAL1))
+#define SVCTRL_INITIAL2 Fld(16,0)
+#define Svctrl_Initial2(x) ((x) << FShft(SVCTRL_INITIAL2))
+
+/* SHCTRL - Scale Horizontal Control Register */
+#define SHCTRL_HINITIAL Fld(16,16)
+#define Shctrl_Hinitial(x) ((x) << FShft(SHCTRL_HINITIAL))
+#define SHCTRL_HDECIM (1 << 15)
+#define SHCTRL_HPITCH Fld(15,0)
+#define Shctrl_Hpitch(x) ((x) << FShft(SHCTRL_HPITCH))
+
+/* SSSIZE - Scale Surface Size Register */
+#define SSSIZE_SC_WIDTH Fld(11,16)
+#define Sssize_Sc_Width(x) ((x) << FShft(SSSIZE_SC_WIDTH))
+#define SSSIZE_SC_HEIGHT Fld(11,0)
+#define Sssize_Sc_Height(x) ((x) << FShft(SSSIZE_SC_HEIGHT))
+
#endif /* __REG_BITS_2700G_ */
diff --git a/drivers/video/mbx/regs.h b/drivers/video/mbx/regs.h
index ad20be07666..a7c63d865aa 100644
--- a/drivers/video/mbx/regs.h
+++ b/drivers/video/mbx/regs.h
@@ -127,7 +127,7 @@
#define HSCOEFF0 __REG_2700G(0x000021b4)
#define HSCOEFF1 __REG_2700G(0x000021b8)
#define HSCOEFF2 __REG_2700G(0x000021bc)
-#define HSCOEFF3 __REG_2700G(0x000021b0)
+#define HSCOEFF3 __REG_2700G(0x000021c0)
#define HSCOEFF4 __REG_2700G(0x000021c4)
#define HSCOEFF5 __REG_2700G(0x000021c8)
#define HSCOEFF6 __REG_2700G(0x000021cc)
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index d1267904c28..5df41f6f2b8 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -34,8 +34,6 @@ const char *global_mode_option;
* Standard video mode definitions (taken from XFree86)
*/
-#define DEFAULT_MODEDB_INDEX 0
-
static const struct fb_videomode modedb[] = {
{
/* 640x400 @ 70 Hz, 31.5 kHz hsync */
@@ -505,8 +503,10 @@ int fb_find_mode(struct fb_var_screeninfo *var,
db = modedb;
dbsize = ARRAY_SIZE(modedb);
}
+
if (!default_mode)
- default_mode = &modedb[DEFAULT_MODEDB_INDEX];
+ default_mode = &db[0];
+
if (!default_bpp)
default_bpp = 8;
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 59a6f5fa5ae..deaf820cb38 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -1932,7 +1932,7 @@ static int __devinit neo_init_hw(struct fb_info *info)
printk(KERN_DEBUG "--- Neo extended register dump ---\n");
for (int w = 0; w < 0x85; w++)
printk(KERN_DEBUG "CR %p: %p\n", (void *) w,
- (void *) vga_rcrt(NULL, w);
+ (void *) vga_rcrt(NULL, w));
for (int w = 0; w < 0xC7; w++)
printk(KERN_DEBUG "GR %p: %p\n", (void *) w,
(void *) vga_rgfx(NULL, w));
diff --git a/drivers/video/nvidia/nv_accel.c b/drivers/video/nvidia/nv_accel.c
index 4aefb8f4163..9efb8a3854e 100644
--- a/drivers/video/nvidia/nv_accel.c
+++ b/drivers/video/nvidia/nv_accel.c
@@ -261,41 +261,6 @@ void NVResetGraphics(struct fb_info *info)
NVDmaKickoff(par);
}
-u8 byte_rev[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
-};
-
int nvidiafb_sync(struct fb_info *info)
{
struct nvidia_par *par = info->par;
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index 5b75ae4e945..df934bd2189 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -141,7 +141,7 @@ void nvidia_bl_init(struct nvidia_par *par)
snprintf(name, sizeof(name), "nvidiabl%d", info->node);
- bd = backlight_device_register(name, par, &nvidia_bl_data);
+ bd = backlight_device_register(name, info->dev, par, &nvidia_bl_data);
if (IS_ERR(bd)) {
info->bl_dev = NULL;
printk(KERN_WARNING "nvidia: Backlight registration failed\n");
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c
index 19eef3a0902..8454adf2d17 100644
--- a/drivers/video/nvidia/nv_i2c.c
+++ b/drivers/video/nvidia/nv_i2c.c
@@ -147,15 +147,15 @@ void nvidia_create_i2c_busses(struct nvidia_par *par)
void nvidia_delete_i2c_busses(struct nvidia_par *par)
{
if (par->chan[0].par)
- i2c_bit_del_bus(&par->chan[0].adapter);
+ i2c_del_adapter(&par->chan[0].adapter);
par->chan[0].par = NULL;
if (par->chan[1].par)
- i2c_bit_del_bus(&par->chan[1].adapter);
+ i2c_del_adapter(&par->chan[1].adapter);
par->chan[1].par = NULL;
if (par->chan[2].par)
- i2c_bit_del_bus(&par->chan[2].adapter);
+ i2c_del_adapter(&par->chan[2].adapter);
par->chan[2].par = NULL;
}
@@ -210,11 +210,8 @@ int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid)
/* try to get from firmware */
const u8 *e = fb_firmware_edid(info->device);
- if (e != NULL) {
- edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
- if (edid)
- memcpy(edid, e, EDID_LENGTH);
- }
+ if (e != NULL)
+ edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
}
*out_edid = edid;
diff --git a/drivers/video/nvidia/nv_local.h b/drivers/video/nvidia/nv_local.h
index 4243d7fae97..e009d242ea1 100644
--- a/drivers/video/nvidia/nv_local.h
+++ b/drivers/video/nvidia/nv_local.h
@@ -96,13 +96,16 @@
#define READ_GET(par) (NV_RD32(&(par)->FIFO[0x0011], 0) >> 2)
#ifdef __LITTLE_ENDIAN
+
+#include <linux/bitrev.h>
+
#define reverse_order(l) \
do { \
u8 *a = (u8 *)(l); \
- *a = byte_rev[*a], a++; \
- *a = byte_rev[*a], a++; \
- *a = byte_rev[*a], a++; \
- *a = byte_rev[*a]; \
+ a[0] = bitrev8(a[0]); \
+ a[1] = bitrev8(a[1]); \
+ a[2] = bitrev8(a[2]); \
+ a[3] = bitrev8(a[3]); \
} while(0)
#else
#define reverse_order(l) do { } while(0)
diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c
index d9af88c2b58..181875fe35c 100644
--- a/drivers/video/nvidia/nv_of.c
+++ b/drivers/video/nvidia/nv_of.c
@@ -72,10 +72,9 @@ int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid)
}
}
if (pedid) {
- *out_edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
+ *out_edid = kmemdup(pedid, EDID_LENGTH, GFP_KERNEL);
if (*out_edid == NULL)
return -1;
- memcpy(*out_edid, pedid, EDID_LENGTH);
printk(KERN_DEBUG "nvidiafb: Found OF EDID for head %d\n", conn);
return 0;
}
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index 86127101765..43058d0cf5b 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -62,7 +62,6 @@ extern void nvidiafb_fillrect(struct fb_info *info,
extern void nvidiafb_imageblit(struct fb_info *info,
const struct fb_image *image);
extern int nvidiafb_sync(struct fb_info *info);
-extern u8 byte_rev[256];
/* in nv_backlight.h */
#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 9a40bbecf76..9576a55eaf1 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -402,6 +402,9 @@ static void __init offb_init_fb(const char *name, const char *full_name,
fb_alloc_cmap(&info->cmap, 256, 0);
if (register_framebuffer(info) < 0) {
+ iounmap(par->cmap_adr);
+ par->cmap_adr = NULL;
+ iounmap(info->screen_base);
kfree(info);
release_mem_region(res_start, res_size);
return;
diff --git a/drivers/video/output.c b/drivers/video/output.c
new file mode 100644
index 00000000000..1473f2c892d
--- /dev/null
+++ b/drivers/video/output.c
@@ -0,0 +1,129 @@
+/*
+ * output.c - Display Output Switch driver
+ *
+ * Copyright (C) 2006 Luming Yu <luming.yu@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; 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/video_output.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+
+
+MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
+
+static ssize_t video_output_show_state(struct class_device *dev,char *buf)
+{
+ ssize_t ret_size = 0;
+ struct output_device *od = to_output_device(dev);
+ if (od->props)
+ ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od));
+ return ret_size;
+}
+
+static ssize_t video_output_store_state(struct class_device *dev,
+ const char *buf,size_t count)
+{
+ char *endp;
+ struct output_device *od = to_output_device(dev);
+ int request_state = simple_strtoul(buf,&endp,0);
+ size_t size = endp - buf;
+
+ if (*endp && isspace(*endp))
+ size++;
+ if (size != count)
+ return -EINVAL;
+
+ if (od->props) {
+ od->request_state = request_state;
+ od->props->set_state(od);
+ }
+ return count;
+}
+
+static void video_output_class_release(struct class_device *dev)
+{
+ struct output_device *od = to_output_device(dev);
+ kfree(od);
+}
+
+static struct class_device_attribute video_output_attributes[] = {
+ __ATTR(state, 0644, video_output_show_state, video_output_store_state),
+ __ATTR_NULL,
+};
+
+static struct class video_output_class = {
+ .name = "video_output",
+ .release = video_output_class_release,
+ .class_dev_attrs = video_output_attributes,
+};
+
+struct output_device *video_output_register(const char *name,
+ struct device *dev,
+ void *devdata,
+ struct output_properties *op)
+{
+ struct output_device *new_dev;
+ int ret_code = 0;
+
+ new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL);
+ if (!new_dev) {
+ ret_code = -ENOMEM;
+ goto error_return;
+ }
+ new_dev->props = op;
+ new_dev->class_dev.class = &video_output_class;
+ new_dev->class_dev.dev = dev;
+ strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN);
+ class_set_devdata(&new_dev->class_dev,devdata);
+ ret_code = class_device_register(&new_dev->class_dev);
+ if (ret_code) {
+ kfree(new_dev);
+ goto error_return;
+ }
+ return new_dev;
+
+error_return:
+ return ERR_PTR(ret_code);
+}
+EXPORT_SYMBOL(video_output_register);
+
+void video_output_unregister(struct output_device *dev)
+{
+ if (!dev)
+ return;
+ class_device_unregister(&dev->class_dev);
+}
+EXPORT_SYMBOL(video_output_unregister);
+
+static void __exit video_output_class_exit(void)
+{
+ class_unregister(&video_output_class);
+}
+
+static int __init video_output_class_init(void)
+{
+ return class_register(&video_output_class);
+}
+
+postcore_initcall(video_output_class_init);
+module_exit(video_output_class_exit);
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index 56ac51d6a7f..637b78bb4bf 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -297,7 +297,8 @@ static int __devinit p9100_init_one(struct of_device *op)
all->info.screen_base = of_ioremap(&op->resource[2], 0,
all->par.fbsize, "p9100 ram");
if (!all->info.screen_base) {
- of_iounmap(all->par.regs, sizeof(struct p9100_regs));
+ of_iounmap(&op->resource[0],
+ all->par.regs, sizeof(struct p9100_regs));
kfree(all);
return -ENOMEM;
}
@@ -306,8 +307,10 @@ static int __devinit p9100_init_one(struct of_device *op)
p9100_blank(0, &all->info);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- of_iounmap(all->par.regs, sizeof(struct p9100_regs));
- of_iounmap(all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0],
+ all->par.regs, sizeof(struct p9100_regs));
+ of_iounmap(&op->resource[2],
+ all->info.screen_base, all->par.fbsize);
kfree(all);
return -ENOMEM;
}
@@ -317,8 +320,10 @@ static int __devinit p9100_init_one(struct of_device *op)
err = register_framebuffer(&all->info);
if (err < 0) {
fb_dealloc_cmap(&all->info.cmap);
- of_iounmap(all->par.regs, sizeof(struct p9100_regs));
- of_iounmap(all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0],
+ all->par.regs, sizeof(struct p9100_regs));
+ of_iounmap(&op->resource[2],
+ all->info.screen_base, all->par.fbsize);
kfree(all);
return err;
}
@@ -340,19 +345,19 @@ static int __devinit p9100_probe(struct of_device *dev, const struct of_device_i
return p9100_init_one(op);
}
-static int __devexit p9100_remove(struct of_device *dev)
+static int __devexit p9100_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&dev->dev);
+ struct all_info *all = dev_get_drvdata(&op->dev);
unregister_framebuffer(&all->info);
fb_dealloc_cmap(&all->info.cmap);
- of_iounmap(all->par.regs, sizeof(struct p9100_regs));
- of_iounmap(all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0], all->par.regs, sizeof(struct p9100_regs));
+ of_iounmap(&op->resource[2], all->info.screen_base, all->par.fbsize);
kfree(all);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index cb26c6df058..23387165582 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -627,6 +627,9 @@ static int __devinit platinumfb_probe(struct of_device* odev,
rc = platinum_init_fb(info);
if (rc != 0) {
+ iounmap(pinfo->frame_buffer);
+ iounmap(pinfo->platinum_regs);
+ iounmap(pinfo->cmap_regs);
dev_set_drvdata(&odev->dev, NULL);
framebuffer_release(info);
}
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
index f5361cd8ccc..264d37243fa 100644
--- a/drivers/video/pmag-ba-fb.c
+++ b/drivers/video/pmag-ba-fb.c
@@ -15,7 +15,8 @@
* Michael Engel <engel@unix-ag.org>,
* Karsten Merker <merker@linuxtag.org> and
* Harald Koerfgen.
- * Copyright (c) 2005 Maciej W. Rozycki
+ * Copyright (c) 2005, 2006 Maciej W. Rozycki
+ * Copyright (c) 2005 James Simmons
*
* 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
@@ -28,26 +29,21 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/tc.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/system.h>
-#include <asm/dec/tc.h>
-
#include <video/pmag-ba-fb.h>
struct pmagbafb_par {
- struct fb_info *next;
volatile void __iomem *mmio;
volatile u32 __iomem *dac;
- int slot;
};
-static struct fb_info *root_pmagbafb_dev;
-
static struct fb_var_screeninfo pmagbafb_defined __initdata = {
.xres = 1024,
.yres = 864,
@@ -145,24 +141,19 @@ static void __init pmagbafb_erase_cursor(struct fb_info *info)
}
-static int __init pmagbafb_init_one(int slot)
+static int __init pmagbafb_probe(struct device *dev)
{
+ struct tc_dev *tdev = to_tc_dev(dev);
+ resource_size_t start, len;
struct fb_info *info;
struct pmagbafb_par *par;
- unsigned long base_addr;
- info = framebuffer_alloc(sizeof(struct pmagbafb_par), NULL);
+ info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
if (!info)
return -ENOMEM;
par = info->par;
- par->slot = slot;
- claim_tc_card(par->slot);
-
- base_addr = get_tc_base_addr(par->slot);
-
- par->next = root_pmagbafb_dev;
- root_pmagbafb_dev = info;
+ dev_set_drvdata(dev, info);
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
goto err_alloc;
@@ -172,15 +163,21 @@ static int __init pmagbafb_init_one(int slot)
info->var = pmagbafb_defined;
info->flags = FBINFO_DEFAULT;
+ /* Request the I/O MEM resource. */
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ if (!request_mem_region(start, len, dev->bus_id))
+ goto err_cmap;
+
/* MMIO mapping setup. */
- info->fix.mmio_start = base_addr;
+ info->fix.mmio_start = start;
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
if (!par->mmio)
- goto err_cmap;
+ goto err_resource;
par->dac = par->mmio + PMAG_BA_BT459;
/* Frame buffer mapping setup. */
- info->fix.smem_start = base_addr + PMAG_BA_FBMEM;
+ info->fix.smem_start = start + PMAG_BA_FBMEM;
info->screen_base = ioremap_nocache(info->fix.smem_start,
info->fix.smem_len);
if (!info->screen_base)
@@ -192,8 +189,10 @@ static int __init pmagbafb_init_one(int slot)
if (register_framebuffer(info) < 0)
goto err_smem_map;
- pr_info("fb%d: %s frame buffer device in slot %d\n",
- info->node, info->fix.id, par->slot);
+ get_device(dev);
+
+ pr_info("fb%d: %s frame buffer device at %s\n",
+ info->node, info->fix.id, dev->bus_id);
return 0;
@@ -204,54 +203,68 @@ err_smem_map:
err_mmio_map:
iounmap(par->mmio);
+err_resource:
+ release_mem_region(start, len);
+
err_cmap:
fb_dealloc_cmap(&info->cmap);
err_alloc:
- root_pmagbafb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
return -ENXIO;
}
-static void __exit pmagbafb_exit_one(void)
+static int __exit pmagbafb_remove(struct device *dev)
{
- struct fb_info *info = root_pmagbafb_dev;
+ struct tc_dev *tdev = to_tc_dev(dev);
+ struct fb_info *info = dev_get_drvdata(dev);
struct pmagbafb_par *par = info->par;
+ resource_size_t start, len;
+ put_device(dev);
unregister_framebuffer(info);
iounmap(info->screen_base);
iounmap(par->mmio);
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ release_mem_region(start, len);
fb_dealloc_cmap(&info->cmap);
- root_pmagbafb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
+ return 0;
}
/*
- * Initialise the framebuffer.
+ * Initialize the framebuffer.
*/
+static const struct tc_device_id pmagbafb_tc_table[] = {
+ { "DEC ", "PMAG-BA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, pmagbafb_tc_table);
+
+static struct tc_driver pmagbafb_driver = {
+ .id_table = pmagbafb_tc_table,
+ .driver = {
+ .name = "pmagbafb",
+ .bus = &tc_bus_type,
+ .probe = pmagbafb_probe,
+ .remove = __exit_p(pmagbafb_remove),
+ },
+};
+
static int __init pmagbafb_init(void)
{
- int count = 0;
- int slot;
-
+#ifndef MODULE
if (fb_get_options("pmagbafb", NULL))
return -ENXIO;
-
- while ((slot = search_tc_card("PMAG-BA")) >= 0) {
- if (pmagbafb_init_one(slot) < 0)
- break;
- count++;
- }
- return (count > 0) ? 0 : -ENXIO;
+#endif
+ return tc_register_driver(&pmagbafb_driver);
}
static void __exit pmagbafb_exit(void)
{
- while (root_pmagbafb_dev)
- pmagbafb_exit_one();
+ tc_unregister_driver(&pmagbafb_driver);
}
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
index 73e2d7d1660..7a0ce7d5af6 100644
--- a/drivers/video/pmagb-b-fb.c
+++ b/drivers/video/pmagb-b-fb.c
@@ -11,7 +11,7 @@
* Michael Engel <engel@unix-ag.org>,
* Karsten Merker <merker@linuxtag.org> and
* Harald Koerfgen.
- * Copyright (c) 2005 Maciej W. Rozycki
+ * Copyright (c) 2005, 2006 Maciej W. Rozycki
*
* 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
@@ -25,18 +25,16 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/tc.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/system.h>
-#include <asm/dec/tc.h>
-
#include <video/pmagb-b-fb.h>
struct pmagbbfb_par {
- struct fb_info *next;
volatile void __iomem *mmio;
volatile void __iomem *smem;
volatile u32 __iomem *sfb;
@@ -47,8 +45,6 @@ struct pmagbbfb_par {
};
-static struct fb_info *root_pmagbbfb_dev;
-
static struct fb_var_screeninfo pmagbbfb_defined __initdata = {
.bits_per_pixel = 8,
.red.length = 8,
@@ -186,12 +182,13 @@ static void __init pmagbbfb_screen_setup(struct fb_info *info)
static void __init pmagbbfb_osc_setup(struct fb_info *info)
{
static unsigned int pmagbbfb_freqs[] __initdata = {
- 130808, 119843, 104000, 92980, 74367, 72800,
+ 130808, 119843, 104000, 92980, 74370, 72800,
69197, 66000, 65000, 50350, 36000, 32000, 25175
};
struct pmagbbfb_par *par = info->par;
+ struct tc_bus *tbus = to_tc_dev(info->device)->bus;
u32 count0 = 8, count1 = 8, counttc = 16 * 256 + 8;
- u32 freq0, freq1, freqtc = get_tc_speed() / 250;
+ u32 freq0, freq1, freqtc = tc_get_speed(tbus) / 250;
int i, j;
gp0_write(par, 0); /* select Osc0 */
@@ -249,26 +246,21 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info)
};
-static int __init pmagbbfb_init_one(int slot)
+static int __init pmagbbfb_probe(struct device *dev)
{
- char freq0[12], freq1[12];
+ struct tc_dev *tdev = to_tc_dev(dev);
+ resource_size_t start, len;
struct fb_info *info;
struct pmagbbfb_par *par;
- unsigned long base_addr;
+ char freq0[12], freq1[12];
u32 vid_base;
- info = framebuffer_alloc(sizeof(struct pmagbbfb_par), NULL);
+ info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev);
if (!info)
return -ENOMEM;
par = info->par;
- par->slot = slot;
- claim_tc_card(par->slot);
-
- base_addr = get_tc_base_addr(par->slot);
-
- par->next = root_pmagbbfb_dev;
- root_pmagbbfb_dev = info;
+ dev_set_drvdata(dev, info);
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
goto err_alloc;
@@ -278,16 +270,22 @@ static int __init pmagbbfb_init_one(int slot)
info->var = pmagbbfb_defined;
info->flags = FBINFO_DEFAULT;
+ /* Request the I/O MEM resource. */
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ if (!request_mem_region(start, len, dev->bus_id))
+ goto err_cmap;
+
/* MMIO mapping setup. */
- info->fix.mmio_start = base_addr;
+ info->fix.mmio_start = start;
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
if (!par->mmio)
- goto err_cmap;
+ goto err_resource;
par->sfb = par->mmio + PMAGB_B_SFB;
par->dac = par->mmio + PMAGB_B_BT459;
/* Frame buffer mapping setup. */
- info->fix.smem_start = base_addr + PMAGB_B_FBMEM;
+ info->fix.smem_start = start + PMAGB_B_FBMEM;
par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
if (!par->smem)
goto err_mmio_map;
@@ -302,13 +300,15 @@ static int __init pmagbbfb_init_one(int slot)
if (register_framebuffer(info) < 0)
goto err_smem_map;
+ get_device(dev);
+
snprintf(freq0, sizeof(freq0), "%u.%03uMHz",
par->osc0 / 1000, par->osc0 % 1000);
snprintf(freq1, sizeof(freq1), "%u.%03uMHz",
par->osc1 / 1000, par->osc1 % 1000);
- pr_info("fb%d: %s frame buffer device in slot %d\n",
- info->node, info->fix.id, par->slot);
+ pr_info("fb%d: %s frame buffer device at %s\n",
+ info->node, info->fix.id, dev->bus_id);
pr_info("fb%d: Osc0: %s, Osc1: %s, Osc%u selected\n",
info->node, freq0, par->osc1 ? freq1 : "disabled",
par->osc1 != 0);
@@ -322,54 +322,68 @@ err_smem_map:
err_mmio_map:
iounmap(par->mmio);
+err_resource:
+ release_mem_region(start, len);
+
err_cmap:
fb_dealloc_cmap(&info->cmap);
err_alloc:
- root_pmagbbfb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
return -ENXIO;
}
-static void __exit pmagbbfb_exit_one(void)
+static int __exit pmagbbfb_remove(struct device *dev)
{
- struct fb_info *info = root_pmagbbfb_dev;
+ struct tc_dev *tdev = to_tc_dev(dev);
+ struct fb_info *info = dev_get_drvdata(dev);
struct pmagbbfb_par *par = info->par;
+ resource_size_t start, len;
+ put_device(dev);
unregister_framebuffer(info);
iounmap(par->smem);
iounmap(par->mmio);
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ release_mem_region(start, len);
fb_dealloc_cmap(&info->cmap);
- root_pmagbbfb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
+ return 0;
}
/*
- * Initialise the framebuffer.
+ * Initialize the framebuffer.
*/
+static const struct tc_device_id pmagbbfb_tc_table[] = {
+ { "DEC ", "PMAGB-BA" },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, pmagbbfb_tc_table);
+
+static struct tc_driver pmagbbfb_driver = {
+ .id_table = pmagbbfb_tc_table,
+ .driver = {
+ .name = "pmagbbfb",
+ .bus = &tc_bus_type,
+ .probe = pmagbbfb_probe,
+ .remove = __exit_p(pmagbbfb_remove),
+ },
+};
+
static int __init pmagbbfb_init(void)
{
- int count = 0;
- int slot;
-
+#ifndef MODULE
if (fb_get_options("pmagbbfb", NULL))
return -ENXIO;
-
- while ((slot = search_tc_card("PMAGB-BA")) >= 0) {
- if (pmagbbfb_init_one(slot) < 0)
- break;
- count++;
- }
- return (count > 0) ? 0 : -ENXIO;
+#endif
+ return tc_register_driver(&pmagbbfb_driver);
}
static void __exit pmagbbfb_exit(void)
{
- while (root_pmagbbfb_dev)
- pmagbbfb_exit_one();
+ tc_unregister_driver(&pmagbbfb_driver);
}
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index c7bc80921f1..a93618bc9d2 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -905,6 +905,15 @@ static int __init pvr2fb_dc_init(void)
static void pvr2fb_dc_exit(void)
{
+ if (fb_info->screen_base) {
+ iounmap(fb_info->screen_base);
+ fb_info->screen_base = NULL;
+ }
+ if (currentpar->mmio_base) {
+ iounmap((void *)currentpar->mmio_base);
+ currentpar->mmio_base = 0;
+ }
+
free_irq(HW_EVENT_VSYNC, 0);
#ifdef CONFIG_SH_DMA
free_dma(pvr2dma);
@@ -946,6 +955,15 @@ static int __devinit pvr2fb_pci_probe(struct pci_dev *pdev,
static void __devexit pvr2fb_pci_remove(struct pci_dev *pdev)
{
+ if (fb_info->screen_base) {
+ iounmap(fb_info->screen_base);
+ fb_info->screen_base = NULL;
+ }
+ if (currentpar->mmio_base) {
+ iounmap((void *)currentpar->mmio_base);
+ currentpar->mmio_base = 0;
+ }
+
pci_release_regions(pdev);
}
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 38eb0b69c2d..b4947c81070 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -1216,7 +1216,7 @@ static int __init pxafb_parse_options(struct device *dev, char *options)
done:
if (res_specified) {
dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
- inf->xres = xres; inf->yres = yres;
+ inf->modes[0].xres = xres; inf->modes[0].yres = yres;
}
if (bpp_specified)
switch (bpp) {
@@ -1225,48 +1225,48 @@ static int __init pxafb_parse_options(struct device *dev, char *options)
case 4:
case 8:
case 16:
- inf->bpp = bpp;
+ inf->modes[0].bpp = bpp;
dev_info(dev, "overriding bit depth: %d\n", bpp);
break;
default:
dev_err(dev, "Depth %d is not valid\n", bpp);
}
} else if (!strncmp(this_opt, "pixclock:", 9)) {
- inf->pixclock = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override pixclock: %ld\n", inf->pixclock);
+ inf->modes[0].pixclock = simple_strtoul(this_opt+9, NULL, 0);
+ dev_info(dev, "override pixclock: %ld\n", inf->modes[0].pixclock);
} else if (!strncmp(this_opt, "left:", 5)) {
- inf->left_margin = simple_strtoul(this_opt+5, NULL, 0);
- dev_info(dev, "override left: %u\n", inf->left_margin);
+ inf->modes[0].left_margin = simple_strtoul(this_opt+5, NULL, 0);
+ dev_info(dev, "override left: %u\n", inf->modes[0].left_margin);
} else if (!strncmp(this_opt, "right:", 6)) {
- inf->right_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override right: %u\n", inf->right_margin);
+ inf->modes[0].right_margin = simple_strtoul(this_opt+6, NULL, 0);
+ dev_info(dev, "override right: %u\n", inf->modes[0].right_margin);
} else if (!strncmp(this_opt, "upper:", 6)) {
- inf->upper_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override upper: %u\n", inf->upper_margin);
+ inf->modes[0].upper_margin = simple_strtoul(this_opt+6, NULL, 0);
+ dev_info(dev, "override upper: %u\n", inf->modes[0].upper_margin);
} else if (!strncmp(this_opt, "lower:", 6)) {
- inf->lower_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override lower: %u\n", inf->lower_margin);
+ inf->modes[0].lower_margin = simple_strtoul(this_opt+6, NULL, 0);
+ dev_info(dev, "override lower: %u\n", inf->modes[0].lower_margin);
} else if (!strncmp(this_opt, "hsynclen:", 9)) {
- inf->hsync_len = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override hsynclen: %u\n", inf->hsync_len);
+ inf->modes[0].hsync_len = simple_strtoul(this_opt+9, NULL, 0);
+ dev_info(dev, "override hsynclen: %u\n", inf->modes[0].hsync_len);
} else if (!strncmp(this_opt, "vsynclen:", 9)) {
- inf->vsync_len = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override vsynclen: %u\n", inf->vsync_len);
+ inf->modes[0].vsync_len = simple_strtoul(this_opt+9, NULL, 0);
+ dev_info(dev, "override vsynclen: %u\n", inf->modes[0].vsync_len);
} else if (!strncmp(this_opt, "hsync:", 6)) {
if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
dev_info(dev, "override hsync: Active Low\n");
- inf->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+ inf->modes[0].sync &= ~FB_SYNC_HOR_HIGH_ACT;
} else {
dev_info(dev, "override hsync: Active High\n");
- inf->sync |= FB_SYNC_HOR_HIGH_ACT;
+ inf->modes[0].sync |= FB_SYNC_HOR_HIGH_ACT;
}
} else if (!strncmp(this_opt, "vsync:", 6)) {
if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
dev_info(dev, "override vsync: Active Low\n");
- inf->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+ inf->modes[0].sync &= ~FB_SYNC_VERT_HIGH_ACT;
} else {
dev_info(dev, "override vsync: Active High\n");
- inf->sync |= FB_SYNC_VERT_HIGH_ACT;
+ inf->modes[0].sync |= FB_SYNC_VERT_HIGH_ACT;
}
} else if (!strncmp(this_opt, "dpc:", 4)) {
if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
diff --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c
index cf41ff17764..bc7ffc84e18 100644
--- a/drivers/video/retz3fb.c
+++ b/drivers/video/retz3fb.c
@@ -1423,8 +1423,10 @@ int __init retz3fb_init(void)
do_install_cmap(0, fb_info);
- if (register_framebuffer(fb_info) < 0)
+ if (register_framebuffer(fb_info) < 0) {
+ iounmap(zinfo->base);
return -EINVAL;
+ }
printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of "
"video memory\n", fb_info->node,
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index a433cc78ef9..1a13966b7d5 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -40,6 +40,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/backlight.h>
+#include <linux/bitrev.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
@@ -383,7 +384,7 @@ static void riva_bl_init(struct riva_par *par)
snprintf(name, sizeof(name), "rivabl%d", info->node);
- bd = backlight_device_register(name, par, &riva_bl_data);
+ bd = backlight_device_register(name, info->dev, par, &riva_bl_data);
if (IS_ERR(bd)) {
info->bl_dev = NULL;
printk(KERN_WARNING "riva: Backlight registration failed\n");
@@ -521,48 +522,13 @@ static inline unsigned char MISCin(struct riva_par *par)
return (VGA_RD08(par->riva.PVIO, 0x3cc));
}
-static u8 byte_rev[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
-};
-
static inline void reverse_order(u32 *l)
{
u8 *a = (u8 *)l;
- *a = byte_rev[*a], a++;
- *a = byte_rev[*a], a++;
- *a = byte_rev[*a], a++;
- *a = byte_rev[*a];
+ a[0] = bitrev8(a[0]);
+ a[1] = bitrev8(a[1]);
+ a[2] = bitrev8(a[2]);
+ a[3] = bitrev8(a[3]);
}
/* ------------------------------------------------------------------------- *
@@ -774,11 +740,12 @@ static void riva_load_state(struct riva_par *par, struct riva_regs *regs)
* CALLED FROM:
* rivafb_set_par()
*/
-static void riva_load_video_mode(struct fb_info *info)
+static int riva_load_video_mode(struct fb_info *info)
{
int bpp, width, hDisplaySize, hDisplay, hStart,
hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
int hBlankStart, hBlankEnd, vBlankStart, vBlankEnd;
+ int rc;
struct riva_par *par = info->par;
struct riva_regs newmode;
@@ -884,8 +851,10 @@ static void riva_load_video_mode(struct fb_info *info)
else
newmode.misc_output |= 0x80;
- par->riva.CalcStateExt(&par->riva, &newmode.ext, bpp, width,
- hDisplaySize, height, dotClock);
+ rc = CalcStateExt(&par->riva, &newmode.ext, bpp, width,
+ hDisplaySize, height, dotClock);
+ if (rc)
+ goto out;
newmode.ext.scale = NV_RD32(par->riva.PRAMDAC, 0x00000848) &
0xfff000ff;
@@ -917,8 +886,12 @@ 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 */
+
+out:
rivafb_blank(FB_BLANK_UNBLANK, info);
NVTRACE_LEAVE();
+
+ return rc;
}
static void riva_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
@@ -1286,12 +1259,15 @@ static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
static int rivafb_set_par(struct fb_info *info)
{
struct riva_par *par = info->par;
+ int rc = 0;
NVTRACE_ENTER();
/* vgaHWunlock() + riva unlock (0x7F) */
CRTCout(par, 0x11, 0xFF);
par->riva.LockUnlock(&par->riva, 0);
- riva_load_video_mode(info);
+ rc = riva_load_video_mode(info);
+ if (rc)
+ goto out;
if(!(info->flags & FBINFO_HWACCEL_DISABLED))
riva_setup_accel(info);
@@ -1304,8 +1280,10 @@ static int rivafb_set_par(struct fb_info *info)
info->pixmap.scan_align = 1;
else
info->pixmap.scan_align = 4;
+
+out:
NVTRACE_LEAVE();
- return 0;
+ return rc;
}
/**
diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c
index b6f8690b96c..e0b8c521cc9 100644
--- a/drivers/video/riva/riva_hw.c
+++ b/drivers/video/riva/riva_hw.c
@@ -1227,7 +1227,7 @@ static int CalcVClock
* Calculate extended mode parameters (SVGA) and save in a
* mode state structure.
*/
-static void CalcStateExt
+int CalcStateExt
(
RIVA_HW_INST *chip,
RIVA_HW_STATE *state,
@@ -1249,7 +1249,8 @@ static void CalcStateExt
* Extended RIVA registers.
*/
pixelDepth = (bpp + 1)/8;
- CalcVClock(dotClock, &VClk, &m, &n, &p, chip);
+ if (!CalcVClock(dotClock, &VClk, &m, &n, &p, chip))
+ return -EINVAL;
switch (chip->Architecture)
{
@@ -1327,6 +1328,8 @@ static void CalcStateExt
state->pitch1 =
state->pitch2 =
state->pitch3 = pixelDepth * width;
+
+ return 0;
}
/*
* Load fixed function state and pre-calculated/stored state.
@@ -2026,7 +2029,6 @@ static void nv3GetConfig
*/
chip->Busy = nv3Busy;
chip->ShowHideCursor = ShowHideCursor;
- chip->CalcStateExt = CalcStateExt;
chip->LoadStateExt = LoadStateExt;
chip->UnloadStateExt = UnloadStateExt;
chip->SetStartAddress = SetStartAddress3;
@@ -2084,7 +2086,6 @@ static void nv4GetConfig
*/
chip->Busy = nv4Busy;
chip->ShowHideCursor = ShowHideCursor;
- chip->CalcStateExt = CalcStateExt;
chip->LoadStateExt = LoadStateExt;
chip->UnloadStateExt = UnloadStateExt;
chip->SetStartAddress = SetStartAddress;
@@ -2186,7 +2187,6 @@ static void nv10GetConfig
*/
chip->Busy = nv10Busy;
chip->ShowHideCursor = ShowHideCursor;
- chip->CalcStateExt = CalcStateExt;
chip->LoadStateExt = LoadStateExt;
chip->UnloadStateExt = UnloadStateExt;
chip->SetStartAddress = SetStartAddress;
diff --git a/drivers/video/riva/riva_hw.h b/drivers/video/riva/riva_hw.h
index a1e71a626df..c2769f73e0b 100644
--- a/drivers/video/riva/riva_hw.h
+++ b/drivers/video/riva/riva_hw.h
@@ -463,7 +463,6 @@ typedef struct _riva_hw_inst
* Common chip functions.
*/
int (*Busy)(struct _riva_hw_inst *);
- void (*CalcStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *,int,int,int,int,int);
void (*LoadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *);
void (*UnloadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *);
void (*SetStartAddress)(struct _riva_hw_inst *,U032);
@@ -528,6 +527,22 @@ typedef struct _riva_hw_state
U032 pitch2;
U032 pitch3;
} RIVA_HW_STATE;
+
+/*
+ * function prototypes
+ */
+
+extern int CalcStateExt
+(
+ RIVA_HW_INST *chip,
+ RIVA_HW_STATE *state,
+ int bpp,
+ int width,
+ int hDisplaySize,
+ int height,
+ int dotClock
+);
+
/*
* External routines.
*/
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
index c15b259af64..01b85e3b0ae 100644
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -144,15 +144,15 @@ void riva_create_i2c_busses(struct riva_par *par)
void riva_delete_i2c_busses(struct riva_par *par)
{
if (par->chan[0].par)
- i2c_bit_del_bus(&par->chan[0].adapter);
+ i2c_del_adapter(&par->chan[0].adapter);
par->chan[0].par = NULL;
if (par->chan[1].par)
- i2c_bit_del_bus(&par->chan[1].adapter);
+ i2c_del_adapter(&par->chan[1].adapter);
par->chan[1].par = NULL;
if (par->chan[2].par)
- i2c_bit_del_bus(&par->chan[2].adapter);
+ i2c_del_adapter(&par->chan[2].adapter);
par->chan[2].par = NULL;
}
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 59407343cc7..ccef56d0c15 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -131,7 +131,7 @@ static void s3c2410fb_set_lcdaddr(struct s3c2410fb_info *fbi)
saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8;
saddr2>>= 1;
- saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH(var->xres);
+ saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((var->xres * var->bits_per_pixel / 16) & 0x3ff);
dprintk("LCDSADDR1 = 0x%08lx\n", saddr1);
dprintk("LCDSADDR2 = 0x%08lx\n", saddr2);
@@ -199,28 +199,86 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
var->bits_per_pixel = fbi->mach_info->bpp.min;
/* set r/g/b positions */
+ switch (var->bits_per_pixel) {
+ case 1:
+ case 2:
+ case 4:
+ var->red.offset = 0;
+ var->red.length = var->bits_per_pixel;
+ var->green = var->red;
+ var->blue = var->red;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 8:
+ if ( fbi->mach_info->type != S3C2410_LCDCON1_TFT ) {
+ /* 8 bpp 332 */
+ var->red.length = 3;
+ var->red.offset = 5;
+ var->green.length = 3;
+ var->green.offset = 2;
+ var->blue.length = 2;
+ var->blue.offset = 0;
+ var->transp.length = 0;
+ } else {
+ var->red.offset = 0;
+ var->red.length = var->bits_per_pixel;
+ var->green = var->red;
+ var->blue = var->red;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ }
+ break;
+ case 12:
+ /* 12 bpp 444 */
+ var->red.length = 4;
+ var->red.offset = 8;
+ var->green.length = 4;
+ var->green.offset = 4;
+ var->blue.length = 4;
+ var->blue.offset = 0;
+ var->transp.length = 0;
+ break;
+
+ default:
+ case 16:
+ if (fbi->regs.lcdcon5 & S3C2410_LCDCON5_FRM565 ) {
+ /* 16 bpp, 565 format */
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ var->transp.length = 0;
+ } else {
+ /* 16 bpp, 5551 format */
+ var->red.offset = 11;
+ var->green.offset = 6;
+ var->blue.offset = 1;
+ var->red.length = 5;
+ var->green.length = 5;
+ var->blue.length = 5;
+ var->transp.length = 0;
+ }
+ break;
+ case 24:
+ /* 24 bpp 888 */
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->transp.length = 0;
+ break;
- if (var->bits_per_pixel == 16) {
- var->red.offset = 11;
- var->green.offset = 5;
- var->blue.offset = 0;
- var->red.length = 5;
- var->green.length = 6;
- var->blue.length = 5;
- var->transp.length = 0;
- } else {
- var->red.length = var->bits_per_pixel;
- var->red.offset = 0;
- var->green.length = var->bits_per_pixel;
- var->green.offset = 0;
- var->blue.length = var->bits_per_pixel;
- var->blue.offset = 0;
- var->transp.length = 0;
- }
+ }
return 0;
}
+
/* s3c2410fb_activate_var
*
* activate (set) the controller from the given framebuffer
@@ -230,29 +288,61 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi,
struct fb_var_screeninfo *var)
{
+ int hs;
+
fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK;
+ fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT;
dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres);
dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres);
dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel);
- switch (var->bits_per_pixel) {
- case 1:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
- break;
- case 2:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
- break;
- case 4:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
- break;
- case 8:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
- break;
- case 16:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
- break;
- }
+ fbi->regs.lcdcon1 |= fbi->mach_info->type;
+
+ if (fbi->mach_info->type == S3C2410_LCDCON1_TFT)
+ switch (var->bits_per_pixel) {
+ case 1:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
+ break;
+ case 2:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
+ break;
+ case 4:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
+ break;
+ case 8:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
+ break;
+ case 16:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
+ break;
+
+ default:
+ /* invalid pixel depth */
+ dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel);
+ }
+ else
+ switch (var->bits_per_pixel) {
+ case 1:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
+ break;
+ case 2:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN2GREY;
+ break;
+ case 4:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN4GREY;
+ break;
+ case 8:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN8BPP;
+ break;
+ case 12:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN12BPP;
+ break;
+
+ default:
+ /* invalid pixel depth */
+ dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel);
+ }
/* check to see if we need to update sync/borders */
@@ -283,15 +373,44 @@ static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi,
fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff);
fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1);
+ switch(fbi->mach_info->type) {
+ case S3C2410_LCDCON1_DSCAN4:
+ case S3C2410_LCDCON1_STN8:
+ hs = var->xres / 8;
+ break;
+ case S3C2410_LCDCON1_STN4:
+ hs = var->xres / 4;
+ break;
+ default:
+ case S3C2410_LCDCON1_TFT:
+ hs = var->xres;
+ break;
+
+ }
+
+ /* Special cases : STN color displays */
+ if ( ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN8BPP) \
+ || ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN12BPP) ) {
+ hs = hs * 3;
+ }
+
+
fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff);
- fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(var->xres - 1);
+ fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(hs - 1);
if (var->pixclock > 0) {
int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock);
- clkdiv = (clkdiv / 2) -1;
- if (clkdiv < 0)
- clkdiv = 0;
+ if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) {
+ clkdiv = (clkdiv / 2) -1;
+ if (clkdiv < 0)
+ clkdiv = 0;
+ }
+ else {
+ clkdiv = (clkdiv / 2);
+ if (clkdiv < 2)
+ clkdiv = 2;
+ }
fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_CLKVAL(0x3ff);
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv);
@@ -329,10 +448,18 @@ static int s3c2410fb_set_par(struct fb_info *info)
struct s3c2410fb_info *fbi = info->par;
struct fb_var_screeninfo *var = &info->var;
- if (var->bits_per_pixel == 16)
- fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR;
- else
- fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ switch (var->bits_per_pixel)
+ {
+ case 16:
+ fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
+ case 1:
+ fbi->fb->fix.visual = FB_VISUAL_MONO01;
+ break;
+ default:
+ fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+ }
fbi->fb->fix.line_length = (var->width*var->bits_per_pixel)/8;
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index cd10b18150b..5d2a4a4b731 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -1200,9 +1200,9 @@ static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
* Our LCD controller task (which is called when we blank or unblank)
* via keventd.
*/
-static void sa1100fb_task(void *dummy)
+static void sa1100fb_task(struct work_struct *w)
{
- struct sa1100fb_info *fbi = dummy;
+ struct sa1100fb_info *fbi = container_of(w, struct sa1100fb_info, task);
u_int state = xchg(&fbi->task_state, -1);
set_ctrlr_state(fbi, state);
@@ -1444,7 +1444,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
fbi->max_bpp / 8;
init_waitqueue_head(&fbi->ctrlr_wait);
- INIT_WORK(&fbi->task, sa1100fb_task, fbi);
+ INIT_WORK(&fbi->task, sa1100fb_task);
init_MUTEX(&fbi->ctrlr_sem);
return fbi;
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
index 3f94223b7f0..1411f3b6a00 100644
--- a/drivers/video/savage/savagefb-i2c.c
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -208,7 +208,7 @@ void savagefb_delete_i2c_busses(struct fb_info *info)
struct savagefb_par *par = info->par;
if (par->chan.par)
- i2c_bit_del_bus(&par->chan.adapter);
+ i2c_del_adapter(&par->chan.adapter);
par->chan.par = NULL;
}
@@ -227,11 +227,8 @@ int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid)
/* try to get from firmware */
const u8 *e = fb_firmware_edid(info->device);
- if (e) {
- edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
- if (edid)
- memcpy(edid, e, EDID_LENGTH);
- }
+ if (e)
+ edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
}
*out_edid = edid;
diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c
index f13faddc618..47e1896cffe 100644
--- a/drivers/video/sis/init301.c
+++ b/drivers/video/sis/init301.c
@@ -445,11 +445,8 @@ SiS_CR36BIOSWord23d(struct SiS_Private *SiS_Pr)
void
SiS_DDC2Delay(struct SiS_Private *SiS_Pr, unsigned int delaytime)
{
- unsigned int i, j;
-
- for(i = 0; i < delaytime; i++) {
- j += SiS_GetReg(SiS_Pr->SiS_P3c4,0x05);
- }
+ while (delaytime-- > 0)
+ SiS_GetReg(SiS_Pr->SiS_P3c4, 0x05);
}
#if defined(SIS300) || defined(SIS315H)
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index 711cb11d6eb..59cd1e750f3 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -21,6 +21,11 @@
* Remove never finished and bogus 24/32bit support
* Clean up macro abuse
* Minor tidying for format.
+ * 12/2006 Helge Deller <deller@gmx.de>
+ * add /sys/class/graphics/fbX/vgapass sysfs-interface
+ * add module option "mode_option" to set initial screen mode
+ * use fbdev default videomode database
+ * remove debug functions from ioctl
*/
/*
@@ -65,19 +70,10 @@
*
* sstfb specific ioctls:
* toggle vga (0x46db) : toggle vga_pass_through
- * fill fb (0x46dc) : fills fb
- * test disp (0x46de) : draws a test image
*/
#undef SST_DEBUG
-/*
- Default video mode .
- 0 800x600@60 took from glide
- 1 640x480@75 took from glide
- 2 1024x768@76 std fb.mode
- 3 640x480@60 glide default */
-#define DEFAULT_MODE 3
/*
* Includes
@@ -92,20 +88,24 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/io.h>
-#include <asm/ioctl.h>
#include <asm/uaccess.h>
#include <video/sstfb.h>
/* initialized by setup */
-static int vgapass; /* enable Vga passthrough cable */
+static int vgapass; /* enable VGA passthrough cable */
static int mem; /* mem size in MB, 0 = autodetect */
static int clipping = 1; /* use clipping (slower, safer) */
static int gfxclk; /* force FBI freq in Mhz . Dangerous */
static int slowpci; /* slow PCI settings */
-static char *mode_option __devinitdata;
+/*
+ Possible default video modes: 800x600@60, 640x480@75, 1024x768@76, 640x480@60
+*/
+#define DEFAULT_VIDEO_MODE "640x480@60"
+
+static char *mode_option __devinitdata = DEFAULT_VIDEO_MODE;
enum {
ID_VOODOO1 = 0,
@@ -119,48 +119,11 @@ static struct sst_spec voodoo_spec[] __devinitdata = {
{ .name = "Voodoo2", .default_gfx_clock = 75000, .max_gfxclk = 85 },
};
-static struct fb_var_screeninfo sstfb_default =
-#if ( DEFAULT_MODE == 0 )
- { /* 800x600@60, 16 bpp .borowed from glide/sst1/include/sst1init.h */
- 800, 600, 800, 600, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0,
- 25000, 86, 41, 23, 1, 127, 4,
- 0, FB_VMODE_NONINTERLACED };
-#elif ( DEFAULT_MODE == 1 )
- {/* 640x480@75, 16 bpp .borowed from glide/sst1/include/sst1init.h */
- 640, 480, 640, 480, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0,
- 31746, 118, 17, 16, 1, 63, 3,
- 0, FB_VMODE_NONINTERLACED };
-#elif ( DEFAULT_MODE == 2 )
- { /* 1024x768@76 took from my /etc/fb.modes */
- 1024, 768, 1024, 768,0, 0, 16,0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0,
- 11764, 208, 8, 36, 16, 120, 3 ,
- 0, FB_VMODE_NONINTERLACED };
-#elif ( DEFAULT_MODE == 3 )
- { /* 640x480@60 , 16bpp glide default ?*/
- 640, 480, 640, 480, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0,
- 39721 , 38, 26 , 25 ,18 , 96 ,2,
- 0, FB_VMODE_NONINTERLACED };
-#elif
- #error "Invalid DEFAULT_MODE value !"
-#endif
-
/*
* debug functions
*/
-static void sstfb_drawdebugimage(struct fb_info *info);
-static int sstfb_dump_regs(struct fb_info *info);
-
-
#if (SST_DEBUG_REG > 0)
static void sst_dbg_print_read_reg(u32 reg, u32 val) {
const char *regname;
@@ -726,51 +689,77 @@ static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
return 0;
}
-static int sstfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
+static void sstfb_setvgapass( struct fb_info *info, int enable )
{
struct sstfb_par *par = info->par;
struct pci_dev *sst_dev = par->dev;
- u32 fbiinit0, tmp, val;
- u_long p;
+ u32 fbiinit0, tmp;
+
+ enable = enable ? 1:0;
+ if (par->vgapass == enable)
+ return;
+ par->vgapass = enable;
+
+ pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp);
+ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
+ tmp | PCI_EN_INIT_WR );
+ fbiinit0 = sst_read (FBIINIT0);
+ if (par->vgapass) {
+ sst_write(FBIINIT0, fbiinit0 & ~DIS_VGA_PASSTHROUGH);
+ printk(KERN_INFO "fb%d: Enabling VGA pass-through\n", info->node );
+ } else {
+ sst_write(FBIINIT0, fbiinit0 | DIS_VGA_PASSTHROUGH);
+ printk(KERN_INFO "fb%d: Disabling VGA pass-through\n", info->node );
+ }
+ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp);
+}
+
+static ssize_t store_vgapass(struct device *device, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info = dev_get_drvdata(device);
+ char ** last = NULL;
+ int val;
+
+ val = simple_strtoul(buf, last, 0);
+ sstfb_setvgapass(info, val);
+
+ return count;
+}
+
+static ssize_t show_vgapass(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(device);
+ struct sstfb_par *par = info->par;
+ return snprintf(buf, PAGE_SIZE, "%d\n", par->vgapass);
+}
+
+static struct device_attribute device_attrs[] = {
+ __ATTR(vgapass, S_IRUGO|S_IWUSR, show_vgapass, store_vgapass)
+ };
+
+static int sstfb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct sstfb_par *par;
+ u32 val;
switch (cmd) {
-
- /* dump current FBIINIT values to system log */
- case _IO('F', 0xdb): /* 0x46db */
- return sstfb_dump_regs(info);
-
- /* fills lfb with #arg pixels */
- case _IOW('F', 0xdc, u32): /* 0x46dc */
+ /* set/get VGA pass_through mode */
+ case SSTFB_SET_VGAPASS:
if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
return -EFAULT;
- if (val > info->fix.smem_len)
- val = info->fix.smem_len;
- for (p = 0 ; p < val; p += 2)
- writew(p >> 6, info->screen_base + p);
+ sstfb_setvgapass(info, val);
return 0;
-
- /* change VGA pass_through mode */
- case _IOW('F', 0xdd, u32): /* 0x46dd */
- if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
+ case SSTFB_GET_VGAPASS:
+ par = info->par;
+ val = par->vgapass;
+ if (copy_to_user((void __user *)arg, &val, sizeof(val)))
return -EFAULT;
- pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp);
- pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
- tmp | PCI_EN_INIT_WR );
- fbiinit0 = sst_read (FBIINIT0);
- if (val)
- sst_write(FBIINIT0, fbiinit0 & ~EN_VGA_PASSTHROUGH);
- else
- sst_write(FBIINIT0, fbiinit0 | EN_VGA_PASSTHROUGH);
- pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp);
- return 0;
-
- /* draw test image */
- case _IO('F', 0xde): /* 0x46de */
- f_dprintk("test color display at %d bpp\n",
- info->var.bits_per_pixel);
- sstfb_drawdebugimage(info);
return 0;
}
+
return -EINVAL;
}
@@ -804,6 +793,7 @@ static void sstfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
/*
* FillRect 2D command (solidfill or invert (via ROP_XOR)) - Voodoo2 only
*/
+#if 0
static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct sstfb_par *par = info->par;
@@ -825,6 +815,7 @@ static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
| (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) | BIT(16) );
sst_wait_idle();
}
+#endif
@@ -1156,6 +1147,7 @@ static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par)
struct pll_timing gfx_timings;
struct sst_spec *spec;
int Fout;
+ int gfx_clock;
spec = &voodoo_spec[par->type];
f_ddprintk(" fbiinit0 fbiinit1 fbiinit2 fbiinit3 fbiinit4 "
@@ -1196,15 +1188,15 @@ static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par)
}
/* set graphic clock */
- par->gfx_clock = spec->default_gfx_clock;
+ gfx_clock = spec->default_gfx_clock;
if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) {
printk(KERN_INFO "sstfb: Using supplied graphic freq : %dMHz\n", gfxclk);
- par->gfx_clock = gfxclk *1000;
+ gfx_clock = gfxclk *1000;
} else if (gfxclk) {
printk(KERN_WARNING "sstfb: %dMhz is way out of spec! Using default\n", gfxclk);
}
- sst_calc_pll(par->gfx_clock, &Fout, &gfx_timings);
+ sst_calc_pll(gfx_clock, &Fout, &gfx_timings);
par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK);
/* disable fbiinit remap */
@@ -1215,10 +1207,11 @@ static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par)
fbiinit0 = FBIINIT0_DEFAULT;
fbiinit1 = FBIINIT1_DEFAULT;
fbiinit4 = FBIINIT4_DEFAULT;
- if (vgapass)
- fbiinit0 &= ~EN_VGA_PASSTHROUGH;
+ par->vgapass = vgapass;
+ if (par->vgapass)
+ fbiinit0 &= ~DIS_VGA_PASSTHROUGH;
else
- fbiinit0 |= EN_VGA_PASSTHROUGH;
+ fbiinit0 |= DIS_VGA_PASSTHROUGH;
if (slowpci) {
fbiinit1 |= SLOW_PCI_WRITES;
fbiinit4 |= SLOW_PCI_READS;
@@ -1267,7 +1260,7 @@ static void __devexit sst_shutdown(struct fb_info *info)
/* TODO maybe shutdown the dac, vrefresh and so on... */
pci_write_config_dword(dev, PCI_INIT_ENABLE,
PCI_EN_INIT_WR);
- sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET | EN_VGA_PASSTHROUGH);
+ sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET | DIS_VGA_PASSTHROUGH);
pci_write_config_dword(dev, PCI_VCLK_DISABLE,0);
/* maybe keep fbiinit* and PCI_INIT_enable in the fb_info struct
* from start ? */
@@ -1278,8 +1271,7 @@ static void __devexit sst_shutdown(struct fb_info *info)
/*
* Interface to the world
*/
-#ifndef MODULE
-static int __init sstfb_setup(char *options)
+static int __devinit sstfb_setup(char *options)
{
char *this_opt;
@@ -1312,7 +1304,7 @@ static int __init sstfb_setup(char *options)
}
return 0;
}
-#endif
+
static struct fb_ops sstfb_ops = {
.owner = THIS_MODULE,
@@ -1416,15 +1408,10 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
*/
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)) {
- printk(KERN_ERR "sstfb: can't set supplied video mode. Using default\n");
- info->var = sstfb_default;
- } else
- info->var = sstfb_default;
+ fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16);
if (sstfb_check_var(&info->var, info)) {
- printk(KERN_ERR "sstfb: invalid default video mode.\n");
+ printk(KERN_ERR "sstfb: invalid video mode.\n");
goto fail;
}
@@ -1442,10 +1429,11 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
goto fail;
}
- if (1) /* set to 0 to see an initial bitmap instead */
- sstfb_clear_screen(info);
- else
- sstfb_drawdebugimage(info);
+ sstfb_clear_screen(info);
+
+ if (device_create_file(info->dev, &device_attrs[0]))
+ printk(KERN_WARNING "sstfb: can't create sysfs entry.\n");
+
printk(KERN_INFO "fb%d: %s frame buffer device at 0x%p\n",
info->node, fix->id, info->screen_base);
@@ -1453,6 +1441,7 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
return 0;
fail:
+ fb_dealloc_cmap(&info->cmap);
iounmap(info->screen_base);
fail_fb_remap:
iounmap(par->mmio_vbase);
@@ -1473,21 +1462,23 @@ static void __devexit sstfb_remove(struct pci_dev *pdev)
info = pci_get_drvdata(pdev);
par = info->par;
+ device_remove_file(info->dev, &device_attrs[0]);
sst_shutdown(info);
- unregister_framebuffer(info);
iounmap(info->screen_base);
iounmap(par->mmio_vbase);
release_mem_region(info->fix.smem_start, 0x400000);
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+ fb_dealloc_cmap(&info->cmap);
+ unregister_framebuffer(info);
framebuffer_release(info);
}
-static struct pci_device_id sstfb_id_tbl[] = {
- { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO1 },
- { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO2 },
+static const struct pci_device_id sstfb_id_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO ),
+ .driver_data = ID_VOODOO1, },
+ { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2),
+ .driver_data = ID_VOODOO2, },
{ 0 },
};
@@ -1501,142 +1492,23 @@ static struct pci_driver sstfb_driver = {
static int __devinit sstfb_init(void)
{
-#ifndef MODULE
char *option = NULL;
if (fb_get_options("sstfb", &option))
return -ENODEV;
sstfb_setup(option);
-#endif
+
return pci_register_driver(&sstfb_driver);
}
-#ifdef MODULE
static void __devexit sstfb_exit(void)
{
pci_unregister_driver(&sstfb_driver);
}
-#endif
-/*
- * testing and debugging functions
- */
-
-static int sstfb_dump_regs(struct fb_info *info)
-{
-#ifdef SST_DEBUG
- static struct { u32 reg ; const char *reg_name;} pci_regs[] = {
- { PCI_INIT_ENABLE, "initenable"},
- { PCI_VCLK_ENABLE, "enable vclk"},
- { PCI_VCLK_DISABLE, "disable vclk"},
- };
-
- static struct { u32 reg ; const char *reg_name;} sst_regs[] = {
- {FBIINIT0,"fbiinit0"},
- {FBIINIT1,"fbiinit1"},
- {FBIINIT2,"fbiinit2"},
- {FBIINIT3,"fbiinit3"},
- {FBIINIT4,"fbiinit4"},
- {FBIINIT5,"fbiinit5"},
- {FBIINIT6,"fbiinit6"},
- {FBIINIT7,"fbiinit7"},
- {LFBMODE,"lfbmode"},
- {FBZMODE,"fbzmode"},
- };
-
- const int pci_s = ARRAY_SIZE(pci_regs);
- const int sst_s = ARRAY_SIZE(sst_regs);
- struct sstfb_par *par = info->par;
- struct pci_dev *dev = par->dev;
- u32 pci_res[pci_s];
- u32 sst_res[sst_s];
- int i;
-
- for (i=0; i<pci_s; i++) {
- pci_read_config_dword(dev, pci_regs[i].reg, &pci_res[i]);
- }
- for (i=0; i<sst_s; i++) {
- sst_res[i] = sst_read(sst_regs[i].reg);
- }
-
- dprintk("hardware register dump:\n");
- for (i=0; i<pci_s; i++) {
- dprintk("%s %0#10x\n", pci_regs[i].reg_name, pci_res[i]);
- }
- for (i=0; i<sst_s; i++) {
- dprintk("%s %0#10x\n", sst_regs[i].reg_name, sst_res[i]);
- }
- return 0;
-#else
- return -EINVAL;
-#endif
-}
-
-static void sstfb_fillrect_softw( struct fb_info *info, const struct fb_fillrect *rect)
-{
- u8 __iomem *fbbase_virt = info->screen_base;
- int x, y, w = info->var.bits_per_pixel == 16 ? 2 : 4;
- u32 color = rect->color, height = rect->height;
- u8 __iomem *p;
-
- if (w==2) color |= color<<16;
- for (y=rect->dy; height; y++, height--) {
- p = fbbase_virt + y*info->fix.line_length + rect->dx*w;
- x = rect->width;
- if (w==2) x>>=1;
- while (x) {
- writel(color, p);
- p += 4;
- x--;
- }
- }
-}
-
-static void sstfb_drawrect_XY( struct fb_info *info, int x, int y,
- int w, int h, int color, int hwfunc)
-{
- struct fb_fillrect rect;
- rect.dx = x;
- rect.dy = y;
- rect.height = h;
- rect.width = w;
- rect.color = color;
- rect.rop = ROP_COPY;
- if (hwfunc)
- sstfb_fillrect(info, &rect);
- else
- sstfb_fillrect_softw(info, &rect);
-}
-
-/* print some squares on the fb */
-static void sstfb_drawdebugimage(struct fb_info *info)
-{
- static int idx;
-
- /* clear screen */
- sstfb_clear_screen(info);
-
- idx = (idx+1) & 1;
-
- /* white rect */
- sstfb_drawrect_XY(info, 0, 0, 50, 50, 0xffff, idx);
-
- /* blue rect */
- sstfb_drawrect_XY(info, 50, 50, 50, 50, 0x001f, idx);
-
- /* green rect */
- sstfb_drawrect_XY(info, 100, 100, 80, 80, 0x07e0, idx);
-
- /* red rect */
- sstfb_drawrect_XY(info, 250, 250, 120, 100, 0xf800, idx);
-}
-
module_init(sstfb_init);
-
-#ifdef MODULE
module_exit(sstfb_exit);
-#endif
MODULE_AUTHOR("(c) 2000,2002 Ghozlane Toumi <gtoumi@laposte.net>");
MODULE_DESCRIPTION("FBDev driver for 3dfx Voodoo Graphics and Voodoo2 based video boards");
@@ -1652,3 +1524,6 @@ 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)");
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Initial video mode (default=" DEFAULT_VIDEO_MODE ")");
+
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index 3e16e2d9d55..69f3b264a22 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -1291,6 +1291,7 @@ out_err3:
out_err2:
release_mem_region(fix->smem_start, fix->smem_len);
out_err1:
+ iounmap(info->screen_base);
fb_dealloc_cmap(&info->cmap);
out_err0:
kfree(fb);
@@ -1364,6 +1365,8 @@ stifb_cleanup(void)
unregister_framebuffer(sti->info);
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
release_mem_region(info->fix.smem_start, info->fix.smem_len);
+ if (info->screen_base)
+ iounmap(info->screen_base);
fb_dealloc_cmap(&info->cmap);
kfree(info);
}
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index 6990ab11cd0..5a99669232c 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -350,18 +350,23 @@ struct all_info {
struct tcx_par par;
};
-static void tcx_unmap_regs(struct all_info *all)
+static void tcx_unmap_regs(struct of_device *op, struct all_info *all)
{
if (all->par.tec)
- of_iounmap(all->par.tec, sizeof(struct tcx_tec));
+ of_iounmap(&op->resource[7],
+ all->par.tec, sizeof(struct tcx_tec));
if (all->par.thc)
- of_iounmap(all->par.thc, sizeof(struct tcx_thc));
+ of_iounmap(&op->resource[9],
+ all->par.thc, sizeof(struct tcx_thc));
if (all->par.bt)
- of_iounmap(all->par.bt, sizeof(struct bt_regs));
+ of_iounmap(&op->resource[8],
+ all->par.bt, sizeof(struct bt_regs));
if (all->par.cplane)
- of_iounmap(all->par.cplane, all->par.fbsize * sizeof(u32));
+ of_iounmap(&op->resource[4],
+ all->par.cplane, all->par.fbsize * sizeof(u32));
if (all->info.screen_base)
- of_iounmap(all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0],
+ all->info.screen_base, all->par.fbsize);
}
static int __devinit tcx_init_one(struct of_device *op)
@@ -398,7 +403,7 @@ static int __devinit tcx_init_one(struct of_device *op)
all->par.fbsize, "tcx ram");
if (!all->par.tec || !all->par.thc ||
!all->par.bt || !all->info.screen_base) {
- tcx_unmap_regs(all);
+ tcx_unmap_regs(op, all);
kfree(all);
return -ENOMEM;
}
@@ -409,7 +414,7 @@ static int __devinit tcx_init_one(struct of_device *op)
all->par.fbsize * sizeof(u32),
"tcx cplane");
if (!all->par.cplane) {
- tcx_unmap_regs(all);
+ tcx_unmap_regs(op, all);
kfree(all);
return -ENOMEM;
}
@@ -461,7 +466,7 @@ static int __devinit tcx_init_one(struct of_device *op)
tcx_blank(FB_BLANK_UNBLANK, &all->info);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- tcx_unmap_regs(all);
+ tcx_unmap_regs(op, all);
kfree(all);
return -ENOMEM;
}
@@ -472,7 +477,7 @@ static int __devinit tcx_init_one(struct of_device *op)
err = register_framebuffer(&all->info);
if (err < 0) {
fb_dealloc_cmap(&all->info.cmap);
- tcx_unmap_regs(all);
+ tcx_unmap_regs(op, all);
kfree(all);
return err;
}
@@ -495,18 +500,18 @@ static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id
return tcx_init_one(op);
}
-static int __devexit tcx_remove(struct of_device *dev)
+static int __devexit tcx_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&dev->dev);
+ struct all_info *all = dev_get_drvdata(&op->dev);
unregister_framebuffer(&all->info);
fb_dealloc_cmap(&all->info.cmap);
- tcx_unmap_regs(all);
+ tcx_unmap_regs(op, all);
kfree(all);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 94fde625a6c..4b88fab83b7 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -23,6 +23,7 @@
#include <linux/fb.h>
#include <linux/pci.h>
#include <linux/selection.h>
+#include <linux/bitrev.h>
#include <asm/io.h>
#include <video/tgafb.h>
@@ -517,41 +518,6 @@ tgafb_blank(int blank, struct fb_info *info)
static void
tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
{
- static unsigned char const bitrev[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
- };
-
struct tga_par *par = (struct tga_par *) info->par;
u32 fgcolor, bgcolor, dx, dy, width, height, vxres, vyres, pixelmask;
unsigned long rincr, line_length, shift, pos, is8bpp;
@@ -649,7 +615,7 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
/* The image data is bit big endian; we need
little endian. */
for (j = 0; j < bwidth; ++j)
- mask |= bitrev[data[j]] << (j * 8);
+ mask |= bitrev8(data[j]) << (j * 8);
__raw_writel(mask << shift, fb_base + pos);
@@ -676,10 +642,10 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
for (i = 0; i < height; ++i) {
for (j = 0; j < bwidth; j += 4) {
u32 mask = 0;
- mask |= bitrev[data[j+0]] << (0 * 8);
- mask |= bitrev[data[j+1]] << (1 * 8);
- mask |= bitrev[data[j+2]] << (2 * 8);
- mask |= bitrev[data[j+3]] << (3 * 8);
+ mask |= bitrev8(data[j+0]) << (0 * 8);
+ mask |= bitrev8(data[j+1]) << (1 * 8);
+ mask |= bitrev8(data[j+2]) << (2 * 8);
+ mask |= bitrev8(data[j+3]) << (3 * 8);
__raw_writel(mask, fb_base + pos + j*bincr);
}
pos += line_length;
@@ -699,7 +665,7 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
for (i = 0; i < height; ++i) {
u32 mask = 0;
for (j = 0; j < bwidth; ++j)
- mask |= bitrev[data[j]] << (j * 8);
+ mask |= bitrev8(data[j]) << (j * 8);
__raw_writel(mask, fb_base + pos);
pos += line_length;
data += rincr;
@@ -726,8 +692,8 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
for (i = 0; i < height; ++i) {
for (j = 0; j < bwidth; j += 2) {
u32 mask = 0;
- mask |= bitrev[data[j+0]] << (0 * 8);
- mask |= bitrev[data[j+1]] << (1 * 8);
+ mask |= bitrev8(data[j+0]) << (0 * 8);
+ mask |= bitrev8(data[j+1]) << (1 * 8);
mask <<= shift;
__raw_writel(mask, fb_base + pos + j*bincr);
}
@@ -746,9 +712,9 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
bwidth = (width & 15) > 8;
for (i = 0; i < height; ++i) {
- u32 mask = bitrev[data[0]];
+ u32 mask = bitrev8(data[0]);
if (bwidth)
- mask |= bitrev[data[1]] << 8;
+ mask |= bitrev8(data[1]) << 8;
mask <<= shift;
__raw_writel(mask, fb_base + pos);
pos += line_length;
@@ -1473,6 +1439,8 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
err1:
+ if (mem_base)
+ iounmap(mem_base);
release_mem_region(bar0_start, bar0_len);
err0:
kfree(all);
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index 14175cdb9c9..55e8aa450bf 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -1130,7 +1130,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
debug("request_mem_region failed!\n");
- return -1;
+ err = -1;
+ goto out_unmap;
}
fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
@@ -1139,7 +1140,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
if (!fb_info.screen_base) {
release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
debug("ioremap failed\n");
- return -1;
+ err = -1;
+ goto out_unmap;
}
output("%s board found\n", pci_name(dev));
@@ -1162,8 +1164,10 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
#endif
fb_info.pseudo_palette = pseudo_pal;
- if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp))
- return -EINVAL;
+ if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp)) {
+ err = -EINVAL;
+ goto out_unmap;
+ }
fb_alloc_cmap(&fb_info.cmap,256,0);
if (defaultaccel && acc)
default_var.accel_flags |= FB_ACCELF_TEXT;
@@ -1174,12 +1178,20 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
fb_info.device = &dev->dev;
if (register_framebuffer(&fb_info) < 0) {
printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto out_unmap;
}
output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
fb_info.node, fb_info.fix.id,default_var.xres,
default_var.yres,default_var.bits_per_pixel);
return 0;
+
+out_unmap:
+ if (default_par.io_virt)
+ iounmap(default_par.io_virt);
+ if (fb_info.screen_base)
+ iounmap(fb_info.screen_base);
+ return err;
}
static void __devexit trident_pci_remove(struct pci_dev * dev)
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 2196448396e..e16322d157d 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -47,17 +47,16 @@ static struct fb_fix_screeninfo vesafb_fix __initdata = {
.accel = FB_ACCEL_NONE,
};
-static int inverse = 0;
-static int mtrr = 0; /* disable mtrr */
-static int vram_remap __initdata = 0; /* Set amount of memory to be used */
-static int vram_total __initdata = 0; /* Set total amount of memory */
-static int pmi_setpal = 1; /* pmi for palette changes ??? */
-static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */
-static unsigned short *pmi_base = NULL;
-static void (*pmi_start)(void);
-static void (*pmi_pal)(void);
-static int depth;
-static int vga_compat;
+static int inverse __read_mostly;
+static int mtrr __read_mostly; /* disable mtrr */
+static int vram_remap __initdata; /* Set amount of memory to be used */
+static int vram_total __initdata; /* Set total amount of memory */
+static int pmi_setpal __read_mostly = 1; /* pmi for palette changes ??? */
+static int ypan __read_mostly; /* 0..nothing, 1..ypan, 2..ywrap */
+static void (*pmi_start)(void) __read_mostly;
+static void (*pmi_pal) (void) __read_mostly;
+static int depth __read_mostly;
+static int vga_compat __read_mostly;
/* --------------------------------------------------------------------- */
static int vesafb_pan_display(struct fb_var_screeninfo *var,
@@ -312,6 +311,7 @@ static int __init vesafb_probe(struct platform_device *dev)
ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
if (ypan || pmi_setpal) {
+ unsigned short *pmi_base;
pmi_base = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
pmi_pal = (void*)((char*)pmi_base + pmi_base[2]);
@@ -456,6 +456,8 @@ static int __init vesafb_probe(struct platform_device *dev)
info->node, info->fix.id);
return 0;
err:
+ if (info->screen_base)
+ iounmap(info->screen_base);
framebuffer_release(info);
release_mem_region(vesafb_fix.smem_start, size_total);
return err;
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 43d5a6d9c4a..6aff63d5b29 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -264,7 +264,7 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
const struct fb_info *info,
int mul, int div)
{
- static struct {
+ static const struct {
u32 pixclock;
u8 misc;
u8 seq_clock_mode;
@@ -652,7 +652,7 @@ static int vga16fb_set_par(struct fb_info *info)
static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
{
- static unsigned char map[] = { 000, 001, 010, 011 };
+ static const unsigned char map[] = { 000, 001, 010, 011 };
int val;
if (regno >= 16)
@@ -1139,23 +1139,19 @@ static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *are
}
}
-#ifdef __LITTLE_ENDIAN
-static unsigned int transl_l[] =
-{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
-static unsigned int transl_h[] =
-{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
- 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
-#else
-#ifdef __BIG_ENDIAN
-static unsigned int transl_h[] =
-{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
-static unsigned int transl_l[] =
-{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
- 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
+#define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
+#define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
+ 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
+
+#if defined(__LITTLE_ENDIAN)
+static const u16 transl_l[] = TRANS_MASK_LOW;
+static const u16 transl_h[] = TRANS_MASK_HIGH;
+#elif defined(__BIG_ENDIAN)
+static const u16 transl_l[] = TRANS_MASK_HIGH;
+static const u16 transl_h[] = TRANS_MASK_LOW;
#else
#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
#endif
-#endif
static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
{
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c
index 64378959dd7..b9fb6fb3600 100644
--- a/drivers/video/virgefb.c
+++ b/drivers/video/virgefb.c
@@ -1799,7 +1799,7 @@ int __init virgefb_init(void)
#warning release resources
printk(KERN_ERR "virgefb.c: register_framebuffer failed\n");
DPRINTK("EXIT\n");
- return -EINVAL;
+ goto out_unmap;
}
printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of video memory\n",
@@ -1809,6 +1809,21 @@ int __init virgefb_init(void)
DPRINTK("EXIT\n");
return 0;
+
+out_unmap:
+ if (board_addr >= 0x01000000) {
+ if (v_ram)
+ iounmap((void*)v_ram);
+ if (vgaio_regs)
+ iounmap(vgaio_regs);
+ if (mmio_regs)
+ iounmap(mmio_regs);
+ if (vcode_switch_base)
+ iounmap((void*)vcode_switch_base);
+ v_ram = vcode_switch_base = 0;
+ vgaio_regs = mmio_regs = NULL;
+ }
+ return -EINVAL;
}
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index d18d6424cd2..904e5aeb696 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -9,7 +9,7 @@ config W1_SLAVE_THERM
tristate "Thermal family implementation"
depends on W1
help
- Say Y here if you want to connect 1-wire thermal sensors to you
+ Say Y here if you want to connect 1-wire thermal sensors to your
wire.
config W1_SLAVE_SMEM
@@ -17,7 +17,7 @@ config W1_SLAVE_SMEM
depends on W1
help
Say Y here if you want to connect 1-wire
- simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire.
+ simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire.
config W1_SLAVE_DS2433
tristate "4kb EEPROM family support (DS2433)"
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index 7aa2d3de6d3..60b05bc1564 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -47,7 +47,7 @@ proc_bus_zorro_lseek(struct file *file, loff_t off, int whence)
static ssize_t
proc_bus_zorro_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
- struct inode *ino = file->f_dentry->d_inode;
+ struct inode *ino = file->f_path.dentry->d_inode;
struct proc_dir_entry *dp = PDE(ino);
struct zorro_dev *z = dp->data;
struct ConfigDev cd;
diff --git a/fs/9p/error.c b/fs/9p/error.c
index ae91555c155..0d7fa4e0881 100644
--- a/fs/9p/error.c
+++ b/fs/9p/error.c
@@ -83,6 +83,7 @@ int v9fs_errstr2errno(char *errstr, int len)
if (errno == 0) {
/* TODO: if error isn't found, add it dynamically */
+ errstr[len] = 0;
printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__,
errstr);
errno = 1;
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 27507201f9e..a9b6301a04f 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -25,6 +25,7 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/idr.h>
+#include <asm/semaphore.h>
#include "debug.h"
#include "v9fs.h"
@@ -84,6 +85,7 @@ struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *v9ses, int fid)
new->iounit = 0;
new->rdir_pos = 0;
new->rdir_fcall = NULL;
+ init_MUTEX(&new->lock);
INIT_LIST_HEAD(&new->list);
return new;
@@ -102,11 +104,11 @@ void v9fs_fid_destroy(struct v9fs_fid *fid)
}
/**
- * v9fs_fid_lookup - retrieve the right fid from a particular dentry
+ * v9fs_fid_lookup - return a locked fid from a dentry
* @dentry: dentry to look for fid in
- * @type: intent of lookup (operation or traversal)
*
- * find a fid in the dentry
+ * find a fid in the dentry, obtain its semaphore and return a reference to it.
+ * code calling lookup is responsible for releasing lock
*
* TODO: only match fids that have the same uid as current user
*
@@ -124,7 +126,68 @@ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry)
if (!return_fid) {
dprintk(DEBUG_ERROR, "Couldn't find a fid in dentry\n");
+ return_fid = ERR_PTR(-EBADF);
}
+ if(down_interruptible(&return_fid->lock))
+ return ERR_PTR(-EINTR);
+
return return_fid;
}
+
+/**
+ * v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and release it
+ * @dentry: dentry to look for fid in
+ *
+ * find a fid in the dentry and then clone to a new private fid
+ *
+ * TODO: only match fids that have the same uid as current user
+ *
+ */
+
+struct v9fs_fid *v9fs_fid_clone(struct dentry *dentry)
+{
+ struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
+ struct v9fs_fid *base_fid, *new_fid = ERR_PTR(-EBADF);
+ struct v9fs_fcall *fcall = NULL;
+ int fid, err;
+
+ base_fid = v9fs_fid_lookup(dentry);
+
+ if(IS_ERR(base_fid))
+ return base_fid;
+
+ if(base_fid) { /* clone fid */
+ fid = v9fs_get_idpool(&v9ses->fidpool);
+ if (fid < 0) {
+ eprintk(KERN_WARNING, "newfid fails!\n");
+ new_fid = ERR_PTR(-ENOSPC);
+ goto Release_Fid;
+ }
+
+ err = v9fs_t_walk(v9ses, base_fid->fid, fid, NULL, &fcall);
+ if (err < 0) {
+ dprintk(DEBUG_ERROR, "clone walk didn't work\n");
+ v9fs_put_idpool(fid, &v9ses->fidpool);
+ new_fid = ERR_PTR(err);
+ goto Free_Fcall;
+ }
+ new_fid = v9fs_fid_create(v9ses, fid);
+ if (new_fid == NULL) {
+ dprintk(DEBUG_ERROR, "out of memory\n");
+ new_fid = ERR_PTR(-ENOMEM);
+ }
+Free_Fcall:
+ kfree(fcall);
+ }
+
+Release_Fid:
+ up(&base_fid->lock);
+ return new_fid;
+}
+
+void v9fs_fid_clunk(struct v9fs_session_info *v9ses, struct v9fs_fid *fid)
+{
+ v9fs_t_clunk(v9ses, fid->fid);
+ v9fs_fid_destroy(fid);
+}
diff --git a/fs/9p/fid.h b/fs/9p/fid.h
index aa974d6875c..48fc170c26c 100644
--- a/fs/9p/fid.h
+++ b/fs/9p/fid.h
@@ -30,6 +30,8 @@ struct v9fs_fid {
struct list_head list; /* list of fids associated with a dentry */
struct list_head active; /* XXX - debug */
+ struct semaphore lock;
+
u32 fid;
unsigned char fidopen; /* set when fid is opened */
unsigned char fidclunked; /* set when fid has already been clunked */
@@ -55,3 +57,6 @@ struct v9fs_fid *v9fs_fid_get_created(struct dentry *);
void v9fs_fid_destroy(struct v9fs_fid *fid);
struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *, int fid);
int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry);
+struct v9fs_fid *v9fs_fid_clone(struct dentry *dentry);
+void v9fs_fid_clunk(struct v9fs_session_info *v9ses, struct v9fs_fid *fid);
+
diff --git a/fs/9p/mux.c b/fs/9p/mux.c
index 944273c3dbf..147ceef8e53 100644
--- a/fs/9p/mux.c
+++ b/fs/9p/mux.c
@@ -132,8 +132,10 @@ int v9fs_mux_global_init(void)
v9fs_mux_poll_tasks[i].task = NULL;
v9fs_mux_wq = create_workqueue("v9fs");
- if (!v9fs_mux_wq)
+ if (!v9fs_mux_wq) {
+ printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
return -ENOMEM;
+ }
return 0;
}
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 0b96fae8b47..d9b561ba5e5 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -457,14 +457,19 @@ static int __init init_v9fs(void)
v9fs_error_init();
- printk(KERN_INFO "Installing v9fs 9P2000 file system support\n");
+ printk(KERN_INFO "Installing v9fs 9p2000 file system support\n");
ret = v9fs_mux_global_init();
- if (!ret)
+ if (ret) {
+ printk(KERN_WARNING "v9fs: starting mux failed\n");
return ret;
+ }
ret = register_filesystem(&v9fs_fs_type);
- if (!ret)
+ if (ret) {
+ printk(KERN_WARNING "v9fs: registering file system failed\n");
v9fs_mux_global_exit();
+ }
+
return ret;
}
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 9dfd259a70b..cc24abf232d 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -54,7 +54,7 @@ static int v9fs_vfs_readpage(struct file *filp, struct page *page)
int retval = -EIO;
loff_t offset = page_offset(page);
int count = PAGE_CACHE_SIZE;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
int rsize = v9ses->maxdata - V9FS_IOHDRSZ;
struct v9fs_fid *v9f = filp->private_data;
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 905c882f4e2..3129688143e 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -71,7 +71,7 @@ static inline int dt_type(struct v9fs_stat *mistat)
static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct v9fs_fcall *fcall = NULL;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
struct v9fs_fid *file = filp->private_data;
unsigned int i, n, s;
@@ -80,7 +80,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct v9fs_stat stat;
int over = 0;
- dprintk(DEBUG_VFS, "name %s\n", filp->f_dentry->d_name.name);
+ dprintk(DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
fid = file->fid;
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 79e6f9cd734..9f17b0cacdd 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -55,53 +55,22 @@ int v9fs_file_open(struct inode *inode, struct file *file)
struct v9fs_fid *vfid;
struct v9fs_fcall *fcall = NULL;
int omode;
- int fid = V9FS_NOFID;
int err;
dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file);
- vfid = v9fs_fid_lookup(file->f_dentry);
- if (!vfid) {
- dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n");
- return -EBADF;
- }
-
- fid = v9fs_get_idpool(&v9ses->fidpool);
- if (fid < 0) {
- eprintk(KERN_WARNING, "newfid fails!\n");
- return -ENOSPC;
- }
+ vfid = v9fs_fid_clone(file->f_path.dentry);
+ if (IS_ERR(vfid))
+ return PTR_ERR(vfid);
- err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, &fcall);
- if (err < 0) {
- dprintk(DEBUG_ERROR, "rewalk didn't work\n");
- if (fcall && fcall->id == RWALK)
- goto clunk_fid;
- else {
- v9fs_put_idpool(fid, &v9ses->fidpool);
- goto free_fcall;
- }
- }
- kfree(fcall);
-
- /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */
- /* translate open mode appropriately */
omode = v9fs_uflags2omode(file->f_flags);
- err = v9fs_t_open(v9ses, fid, omode, &fcall);
+ err = v9fs_t_open(v9ses, vfid->fid, omode, &fcall);
if (err < 0) {
PRINT_FCALL_ERROR("open failed", fcall);
- goto clunk_fid;
- }
-
- vfid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
- if (vfid == NULL) {
- dprintk(DEBUG_ERROR, "out of memory\n");
- err = -ENOMEM;
- goto clunk_fid;
+ goto Clunk_Fid;
}
file->private_data = vfid;
- vfid->fid = fid;
vfid->fidopen = 1;
vfid->fidclunked = 0;
vfid->iounit = fcall->params.ropen.iounit;
@@ -112,10 +81,8 @@ int v9fs_file_open(struct inode *inode, struct file *file)
return 0;
-clunk_fid:
- v9fs_t_clunk(v9ses, fid);
-
-free_fcall:
+Clunk_Fid:
+ v9fs_fid_clunk(v9ses, vfid);
kfree(fcall);
return err;
@@ -133,7 +100,7 @@ free_fcall:
static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
{
int res = 0;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
dprintk(DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
@@ -161,7 +128,7 @@ static ssize_t
v9fs_file_read(struct file *filp, char __user * data, size_t count,
loff_t * offset)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
struct v9fs_fid *v9f = filp->private_data;
struct v9fs_fcall *fcall = NULL;
@@ -225,7 +192,7 @@ static ssize_t
v9fs_file_write(struct file *filp, const char __user * data,
size_t count, loff_t * offset)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
struct v9fs_fid *v9fid = filp->private_data;
struct v9fs_fcall *fcall;
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 18f26cdfd88..378767c07bf 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -416,12 +416,8 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
sb = file_inode->i_sb;
v9ses = v9fs_inode2v9ses(file_inode);
v9fid = v9fs_fid_lookup(file);
-
- if (!v9fid) {
- dprintk(DEBUG_ERROR,
- "no v9fs_fid\n");
- return -EBADF;
- }
+ if(IS_ERR(v9fid))
+ return PTR_ERR(v9fid);
fid = v9fid->fid;
if (fid < 0) {
@@ -433,11 +429,13 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
result = v9fs_t_remove(v9ses, fid, &fcall);
if (result < 0) {
PRINT_FCALL_ERROR("remove fails", fcall);
+ goto Error;
}
v9fs_put_idpool(fid, &v9ses->fidpool);
v9fs_fid_destroy(v9fid);
+Error:
kfree(fcall);
return result;
}
@@ -473,9 +471,13 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
inode = NULL;
vfid = NULL;
v9ses = v9fs_inode2v9ses(dir);
- dfid = v9fs_fid_lookup(dentry->d_parent);
- perm = unixmode2p9mode(v9ses, mode);
+ dfid = v9fs_fid_clone(dentry->d_parent);
+ if(IS_ERR(dfid)) {
+ err = PTR_ERR(dfid);
+ goto error;
+ }
+ perm = unixmode2p9mode(v9ses, mode);
if (nd && nd->flags & LOOKUP_OPEN)
flags = nd->intent.open.flags - 1;
else
@@ -485,9 +487,10 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit);
if (err)
- goto error;
+ goto clunk_dfid;
vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
+ v9fs_fid_clunk(v9ses, dfid);
if (IS_ERR(vfid)) {
err = PTR_ERR(vfid);
vfid = NULL;
@@ -525,6 +528,9 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
return 0;
+clunk_dfid:
+ v9fs_fid_clunk(v9ses, dfid);
+
error:
if (vfid)
v9fs_fid_destroy(vfid);
@@ -551,7 +557,12 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
inode = NULL;
vfid = NULL;
v9ses = v9fs_inode2v9ses(dir);
- dfid = v9fs_fid_lookup(dentry->d_parent);
+ dfid = v9fs_fid_clone(dentry->d_parent);
+ if(IS_ERR(dfid)) {
+ err = PTR_ERR(dfid);
+ goto error;
+ }
+
perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
@@ -559,26 +570,22 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (err) {
dprintk(DEBUG_ERROR, "create error %d\n", err);
- goto error;
- }
-
- err = v9fs_t_clunk(v9ses, fid);
- if (err) {
- dprintk(DEBUG_ERROR, "clunk error %d\n", err);
- goto error;
+ goto clean_up_dfid;
}
vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
if (IS_ERR(vfid)) {
err = PTR_ERR(vfid);
vfid = NULL;
- goto error;
+ goto clean_up_dfid;
}
+ v9fs_fid_clunk(v9ses, dfid);
inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
inode = NULL;
+ v9fs_fid_destroy(vfid);
goto error;
}
@@ -586,10 +593,10 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
d_instantiate(dentry, inode);
return 0;
-error:
- if (vfid)
- v9fs_fid_destroy(vfid);
+clean_up_dfid:
+ v9fs_fid_clunk(v9ses, dfid);
+error:
return err;
}
@@ -622,28 +629,23 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
dentry->d_op = &v9fs_dentry_operations;
dirfid = v9fs_fid_lookup(dentry->d_parent);
- if (!dirfid) {
- dprintk(DEBUG_ERROR, "no dirfid\n");
- return ERR_PTR(-EINVAL);
- }
+ if(IS_ERR(dirfid))
+ return ERR_PTR(PTR_ERR(dirfid));
dirfidnum = dirfid->fid;
- if (dirfidnum < 0) {
- dprintk(DEBUG_ERROR, "no dirfid for inode %p, #%lu\n",
- dir, dir->i_ino);
- return ERR_PTR(-EBADF);
- }
-
newfid = v9fs_get_idpool(&v9ses->fidpool);
if (newfid < 0) {
eprintk(KERN_WARNING, "newfid fails!\n");
- return ERR_PTR(-ENOSPC);
+ result = -ENOSPC;
+ goto Release_Dirfid;
}
result = v9fs_t_walk(v9ses, dirfidnum, newfid,
(char *)dentry->d_name.name, &fcall);
+ up(&dirfid->lock);
+
if (result < 0) {
if (fcall && fcall->id == RWALK)
v9fs_t_clunk(v9ses, newfid);
@@ -701,8 +703,12 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
return NULL;
- FreeFcall:
+Release_Dirfid:
+ up(&dirfid->lock);
+
+FreeFcall:
kfree(fcall);
+
return ERR_PTR(result);
}
@@ -746,10 +752,8 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *old_inode = old_dentry->d_inode;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode);
struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry);
- struct v9fs_fid *olddirfid =
- v9fs_fid_lookup(old_dentry->d_parent);
- struct v9fs_fid *newdirfid =
- v9fs_fid_lookup(new_dentry->d_parent);
+ struct v9fs_fid *olddirfid;
+ struct v9fs_fid *newdirfid;
struct v9fs_wstat wstat;
struct v9fs_fcall *fcall = NULL;
int fid = -1;
@@ -759,16 +763,26 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
dprintk(DEBUG_VFS, "\n");
- if ((!oldfid) || (!olddirfid) || (!newdirfid)) {
- dprintk(DEBUG_ERROR, "problem with arguments\n");
- return -EBADF;
+ if(IS_ERR(oldfid))
+ return PTR_ERR(oldfid);
+
+ olddirfid = v9fs_fid_clone(old_dentry->d_parent);
+ if(IS_ERR(olddirfid)) {
+ retval = PTR_ERR(olddirfid);
+ goto Release_lock;
+ }
+
+ newdirfid = v9fs_fid_clone(new_dentry->d_parent);
+ if(IS_ERR(newdirfid)) {
+ retval = PTR_ERR(newdirfid);
+ goto Clunk_olddir;
}
/* 9P can only handle file rename in the same directory */
if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) {
dprintk(DEBUG_ERROR, "old dir and new dir are different\n");
- retval = -EPERM;
- goto FreeFcallnBail;
+ retval = -EXDEV;
+ goto Clunk_newdir;
}
fid = oldfid->fid;
@@ -779,7 +793,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
dprintk(DEBUG_ERROR, "no fid for old file #%lu\n",
old_inode->i_ino);
retval = -EBADF;
- goto FreeFcallnBail;
+ goto Clunk_newdir;
}
v9fs_blank_wstat(&wstat);
@@ -788,11 +802,20 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall);
- FreeFcallnBail:
if (retval < 0)
PRINT_FCALL_ERROR("wstat error", fcall);
kfree(fcall);
+
+Clunk_newdir:
+ v9fs_fid_clunk(v9ses, newdirfid);
+
+Clunk_olddir:
+ v9fs_fid_clunk(v9ses, olddirfid);
+
+Release_lock:
+ up(&oldfid->lock);
+
return retval;
}
@@ -810,15 +833,12 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
{
struct v9fs_fcall *fcall = NULL;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_lookup(dentry);
+ struct v9fs_fid *fid = v9fs_fid_clone(dentry);
int err = -EPERM;
dprintk(DEBUG_VFS, "dentry: %p\n", dentry);
- if (!fid) {
- dprintk(DEBUG_ERROR,
- "couldn't find fid associated with dentry\n");
- return -EBADF;
- }
+ if(IS_ERR(fid))
+ return PTR_ERR(fid);
err = v9fs_t_stat(v9ses, fid->fid, &fcall);
@@ -831,6 +851,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
}
kfree(fcall);
+ v9fs_fid_clunk(v9ses, fid);
return err;
}
@@ -844,18 +865,14 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_lookup(dentry);
+ struct v9fs_fid *fid = v9fs_fid_clone(dentry);
struct v9fs_fcall *fcall = NULL;
struct v9fs_wstat wstat;
int res = -EPERM;
dprintk(DEBUG_VFS, "\n");
-
- if (!fid) {
- dprintk(DEBUG_ERROR,
- "Couldn't find fid associated with dentry\n");
- return -EBADF;
- }
+ if(IS_ERR(fid))
+ return PTR_ERR(fid);
v9fs_blank_wstat(&wstat);
if (iattr->ia_valid & ATTR_MODE)
@@ -887,6 +904,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
if (res >= 0)
res = inode_setattr(dentry->d_inode, iattr);
+ v9fs_fid_clunk(v9ses, fid);
return res;
}
@@ -987,18 +1005,15 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
struct v9fs_fcall *fcall = NULL;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_lookup(dentry);
+ struct v9fs_fid *fid = v9fs_fid_clone(dentry);
- if (!fid) {
- dprintk(DEBUG_ERROR, "could not resolve fid from dentry\n");
- retval = -EBADF;
- goto FreeFcall;
- }
+ if(IS_ERR(fid))
+ return PTR_ERR(fid);
if (!v9ses->extended) {
retval = -EBADF;
dprintk(DEBUG_ERROR, "not extended\n");
- goto FreeFcall;
+ goto ClunkFid;
}
dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name);
@@ -1009,8 +1024,10 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
goto FreeFcall;
}
- if (!fcall)
- return -EIO;
+ if (!fcall) {
+ retval = -EIO;
+ goto ClunkFid;
+ }
if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) {
retval = -EINVAL;
@@ -1028,9 +1045,12 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
fcall->params.rstat.stat.extension.str, buffer);
retval = buflen;
- FreeFcall:
+FreeFcall:
kfree(fcall);
+ClunkFid:
+ v9fs_fid_clunk(v9ses, fid);
+
return retval;
}
@@ -1123,52 +1143,58 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
int err;
u32 fid, perm;
struct v9fs_session_info *v9ses;
- struct v9fs_fid *dfid, *vfid;
- struct inode *inode;
+ struct v9fs_fid *dfid, *vfid = NULL;
+ struct inode *inode = NULL;
- inode = NULL;
- vfid = NULL;
v9ses = v9fs_inode2v9ses(dir);
- dfid = v9fs_fid_lookup(dentry->d_parent);
- perm = unixmode2p9mode(v9ses, mode);
-
if (!v9ses->extended) {
dprintk(DEBUG_ERROR, "not extended\n");
return -EPERM;
}
+ dfid = v9fs_fid_clone(dentry->d_parent);
+ if(IS_ERR(dfid)) {
+ err = PTR_ERR(dfid);
+ goto error;
+ }
+
+ perm = unixmode2p9mode(v9ses, mode);
+
err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL);
if (err)
- goto error;
+ goto clunk_dfid;
err = v9fs_t_clunk(v9ses, fid);
if (err)
- goto error;
+ goto clunk_dfid;
vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
if (IS_ERR(vfid)) {
err = PTR_ERR(vfid);
vfid = NULL;
- goto error;
+ goto clunk_dfid;
}
inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
inode = NULL;
- goto error;
+ goto free_vfid;
}
dentry->d_op = &v9fs_dentry_operations;
d_instantiate(dentry, inode);
return 0;
-error:
- if (vfid)
- v9fs_fid_destroy(vfid);
+free_vfid:
+ v9fs_fid_destroy(vfid);
+
+clunk_dfid:
+ v9fs_fid_clunk(v9ses, dfid);
+error:
return err;
}
@@ -1209,26 +1235,29 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *dentry)
{
int retval;
+ struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
struct v9fs_fid *oldfid;
char *name;
dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
old_dentry->d_name.name);
- oldfid = v9fs_fid_lookup(old_dentry);
- if (!oldfid) {
- dprintk(DEBUG_ERROR, "can't find oldfid\n");
- return -EPERM;
- }
+ oldfid = v9fs_fid_clone(old_dentry);
+ if(IS_ERR(oldfid))
+ return PTR_ERR(oldfid);
name = __getname();
- if (unlikely(!name))
- return -ENOMEM;
+ if (unlikely(!name)) {
+ retval = -ENOMEM;
+ goto clunk_fid;
+ }
sprintf(name, "%d\n", oldfid->fid);
retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name);
__putname(name);
+clunk_fid:
+ v9fs_fid_clunk(v9ses, oldfid);
return retval;
}
diff --git a/fs/Kconfig b/fs/Kconfig
index b3b5aa0edff..5e8e9d9ccb3 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -12,9 +12,7 @@ config EXT2_FS
Ext2 is a standard Linux file system for hard disks.
To compile this file system support as a module, choose M here: the
- module will be called ext2. Be aware however that the file system
- of your root partition (the one containing the directory /) cannot
- be compiled as a module, and so this could be dangerous.
+ module will be called ext2.
If unsure, say Y.
@@ -98,9 +96,7 @@ config EXT3_FS
(available at <http://sourceforge.net/projects/e2fsprogs/>).
To compile this file system support as a module, choose M here: the
- module will be called ext3. Be aware however that the file system
- of your root partition (the one containing the directory /) cannot
- be compiled as a module, and so this may be dangerous.
+ module will be called ext3.
config EXT3_FS_XATTR
bool "Ext3 extended attributes"
@@ -163,9 +159,7 @@ config EXT4DEV_FS
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.
+ module will be called ext4dev.
If unsure, say N.
@@ -432,7 +426,6 @@ config OCFS2_FS
select CONFIGFS_FS
select JBD
select CRC32
- select INET
help
OCFS2 is a general purpose extent based shared disk cluster file
system with many similarities to ext3. It supports 64 bit inode
@@ -1008,7 +1001,7 @@ config TMPFS_POSIX_ACL
config HUGETLBFS
bool "HugeTLB file system support"
- depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN
+ depends on X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN
help
hugetlbfs is a filesystem backing for HugeTLB pages, based on
ramfs. For architectures that support it, say Y here and read
@@ -1204,13 +1197,16 @@ config EFS_FS
config JFFS_FS
tristate "Journalling Flash File System (JFFS) support"
- depends on MTD && BLOCK
+ depends on MTD && BLOCK && BROKEN
help
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/>).
+ NOTE: This filesystem is deprecated and is scheduled for removal in
+ 2.6.21. See Documentation/feature-removal-schedule.txt
+
config JFFS_FS_VERBOSE
int "JFFS debugging verbosity (0 = quiet, 3 = noisy)"
depends on JFFS_FS
diff --git a/fs/Makefile b/fs/Makefile
index 9a5ce9323bf..b9ffa63f77f 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -10,7 +10,8 @@ obj-y := open.o read_write.o file_table.o super.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 \
- pnode.o drop_caches.o splice.o sync.o utimes.o
+ pnode.o drop_caches.o splice.o sync.o utimes.o \
+ stack.o
ifeq ($(CONFIG_BLOCK),y)
obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index d3c7905b2dd..2b8903893d3 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -28,7 +28,7 @@ static DEFINE_RWLOCK(adfs_dir_lock);
static int
adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
struct object_info obj;
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index bbfc8625927..b9b2b27b68c 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -53,7 +53,7 @@ static inline int adfs_readname(char *buf, char *ptr, int maxlen)
{
char *old_buf = buf;
- while (*ptr >= ' ' && maxlen--) {
+ while ((unsigned char)*ptr >= ' ' && maxlen--) {
if (*ptr == '/')
*buf++ = '.';
else
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index 5d9649fa181..cad3ee34006 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -41,7 +41,7 @@ struct inode_operations affs_dir_inode_operations = {
static int
affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
struct buffer_head *dir_bh;
struct buffer_head *fh_bh;
@@ -71,7 +71,7 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
stored++;
}
if (f_pos == 1) {
- if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_dentry), DT_DIR) < 0)
+ if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_path.dentry), DT_DIR) < 0)
return stored;
filp->f_pos = f_pos = 2;
stored++;
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index a6ec75c56fc..4acd0413405 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -392,10 +392,10 @@ static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir)
unsigned fpos;
int ret;
- _enter("{%Ld,{%lu}}", file->f_pos, file->f_dentry->d_inode->i_ino);
+ _enter("{%Ld,{%lu}}", file->f_pos, file->f_path.dentry->d_inode->i_ino);
fpos = file->f_pos;
- ret = afs_dir_iterate(file->f_dentry->d_inode, &fpos, cookie, filldir);
+ ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, cookie, filldir);
file->f_pos = fpos;
_leave(" = %d", ret);
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 99785a79d04..8f74e845082 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -18,7 +18,7 @@
#include <linux/pagemap.h>
#include <linux/mount.h>
#include <linux/namei.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include "super.h"
#include "cell.h"
#include "volume.h"
@@ -136,11 +136,11 @@ static int afs_mntpt_open(struct inode *inode, struct file *file)
{
kenter("%p,%p{%p{%s},%s}",
inode, file,
- file->f_dentry->d_parent,
- file->f_dentry->d_parent ?
- file->f_dentry->d_parent->d_name.name :
+ file->f_path.dentry->d_parent,
+ file->f_path.dentry->d_parent ?
+ file->f_path.dentry->d_parent->d_name.name :
(const unsigned char *) "",
- file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.name);
return -EREMOTE;
} /* end afs_mntpt_open() */
diff --git a/fs/aio.c b/fs/aio.c
index d3a6ec2c962..55991e4132a 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -298,17 +298,23 @@ static void wait_for_all_aios(struct kioctx *ctx)
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
+ spin_lock_irq(&ctx->ctx_lock);
if (!ctx->reqs_active)
- return;
+ goto out;
add_wait_queue(&ctx->wait, &wait);
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
while (ctx->reqs_active) {
+ spin_unlock_irq(&ctx->ctx_lock);
schedule();
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ spin_lock_irq(&ctx->ctx_lock);
}
__set_task_state(tsk, TASK_RUNNING);
remove_wait_queue(&ctx->wait, &wait);
+
+out:
+ spin_unlock_irq(&ctx->ctx_lock);
}
/* wait_on_sync_kiocb:
@@ -424,7 +430,6 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx)
ring = kmap_atomic(ctx->ring_info.ring_pages[0], KM_USER0);
if (ctx->reqs_active < aio_ring_avail(&ctx->ring_info, ring)) {
list_add(&req->ki_list, &ctx->active_reqs);
- get_ioctx(ctx);
ctx->reqs_active++;
okay = 1;
}
@@ -536,8 +541,6 @@ int fastcall aio_put_req(struct kiocb *req)
spin_lock_irq(&ctx->ctx_lock);
ret = __aio_put_req(ctx, req);
spin_unlock_irq(&ctx->ctx_lock);
- if (ret)
- put_ioctx(ctx);
return ret;
}
@@ -586,7 +589,7 @@ static void use_mm(struct mm_struct *mm)
* Note that on UML this *requires* PF_BORROWED_MM to be set, otherwise
* it won't work. Update it accordingly if you change it here
*/
- activate_mm(active_mm, mm);
+ switch_mm(active_mm, mm, tsk);
task_unlock(tsk);
mmdrop(active_mm);
@@ -599,9 +602,6 @@ static void use_mm(struct mm_struct *mm)
* by the calling kernel thread
* (Note: this routine is intended to be called only
* from a kernel thread context)
- *
- * Comments: Called with ctx->ctx_lock held. This nests
- * task_lock instead ctx_lock.
*/
static void unuse_mm(struct mm_struct *mm)
{
@@ -782,8 +782,7 @@ static int __aio_run_iocbs(struct kioctx *ctx)
*/
iocb->ki_users++; /* grab extra reference */
aio_run_iocb(iocb);
- if (__aio_put_req(ctx, iocb)) /* drop extra ref */
- put_ioctx(ctx);
+ __aio_put_req(ctx, iocb);
}
if (!list_empty(&ctx->run_list))
return 1;
@@ -850,14 +849,16 @@ static void aio_kick_handler(struct work_struct *work)
{
struct kioctx *ctx = container_of(work, struct kioctx, wq.work);
mm_segment_t oldfs = get_fs();
+ struct mm_struct *mm;
int requeue;
set_fs(USER_DS);
use_mm(ctx->mm);
spin_lock_irq(&ctx->ctx_lock);
requeue =__aio_run_iocbs(ctx);
- unuse_mm(ctx->mm);
+ mm = ctx->mm;
spin_unlock_irq(&ctx->ctx_lock);
+ unuse_mm(mm);
set_fs(oldfs);
/*
* we're in a worker thread already, don't use queue_delayed_work,
@@ -998,14 +999,10 @@ put_rq:
/* everything turned out well, dispose of the aiocb. */
ret = __aio_put_req(ctx, iocb);
- spin_unlock_irqrestore(&ctx->ctx_lock, flags);
-
if (waitqueue_active(&ctx->wait))
wake_up(&ctx->wait);
- if (ret)
- put_ioctx(ctx);
-
+ spin_unlock_irqrestore(&ctx->ctx_lock, flags);
return ret;
}
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 368a1c33a3c..e698c51d2b0 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -45,7 +45,7 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldi
struct autofs_dir_ent *ent = NULL;
struct autofs_dirhash *dirhash;
struct autofs_sb_info *sbi;
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode * inode = filp->f_path.dentry->d_inode;
off_t onr, nr;
lock_kernel();
@@ -557,7 +557,7 @@ static int autofs_root_ioctl(struct inode *inode, struct file *filp,
case AUTOFS_IOC_SETTIMEOUT:
return autofs_get_set_timeout(sbi, argp);
case AUTOFS_IOC_EXPIRE:
- return autofs_expire_run(inode->i_sb, sbi, filp->f_vfsmnt,
+ return autofs_expire_run(inode->i_sb, sbi, filp->f_path.mnt,
argp);
default:
return -ENOSYS;
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index b13f32c8aee..216b1a364cc 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -150,7 +150,8 @@ static inline int autofs4_ispending(struct dentry *dentry)
static inline void autofs4_copy_atime(struct file *src, struct file *dst)
{
- dst->f_dentry->d_inode->i_atime = src->f_dentry->d_inode->i_atime;
+ dst->f_path.dentry->d_inode->i_atime =
+ src->f_path.dentry->d_inode->i_atime;
return;
}
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 9c48250fd72..e8f6c5ad3e9 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -313,7 +313,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
struct autofs_sb_info *sbi;
struct autofs_info *ino;
- sbi = (struct autofs_sb_info *) kmalloc(sizeof(*sbi), GFP_KERNEL);
+ sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
if ( !sbi )
goto fail_unlock;
DPRINTK("starting up, sbi = %p",sbi);
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index c1493524da4..8d05b9f7578 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -74,7 +74,7 @@ struct inode_operations autofs4_dir_inode_operations = {
static int autofs4_root_readdir(struct file *file, void *dirent,
filldir_t filldir)
{
- struct autofs_sb_info *sbi = autofs4_sbi(file->f_dentry->d_sb);
+ struct autofs_sb_info *sbi = autofs4_sbi(file->f_path.dentry->d_sb);
int oz_mode = autofs4_oz_mode(sbi);
DPRINTK("called, filp->f_pos = %lld", file->f_pos);
@@ -95,8 +95,8 @@ static int autofs4_root_readdir(struct file *file, void *dirent,
static int autofs4_dir_open(struct inode *inode, struct file *file)
{
- struct dentry *dentry = file->f_dentry;
- struct vfsmount *mnt = file->f_vfsmnt;
+ struct dentry *dentry = file->f_path.dentry;
+ struct vfsmount *mnt = file->f_path.mnt;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct dentry *cursor;
int status;
@@ -172,7 +172,7 @@ out:
static int autofs4_dir_close(struct inode *inode, struct file *file)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct dentry *cursor = file->private_data;
int status = 0;
@@ -204,7 +204,7 @@ out:
static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldir)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct dentry *cursor = file->private_data;
int status;
@@ -858,14 +858,14 @@ static int autofs4_root_ioctl(struct inode *inode, struct file *filp,
return autofs4_ask_reghost(sbi, p);
case AUTOFS_IOC_ASKUMOUNT:
- return autofs4_ask_umount(filp->f_vfsmnt, p);
+ return autofs4_ask_umount(filp->f_path.mnt, p);
/* return a single thing to expire */
case AUTOFS_IOC_EXPIRE:
- return autofs4_expire_run(inode->i_sb,filp->f_vfsmnt,sbi, p);
+ return autofs4_expire_run(inode->i_sb,filp->f_path.mnt,sbi, p);
/* same as above, but can send multiple expires through pipe */
case AUTOFS_IOC_EXPIRE_MULTI:
- return autofs4_expire_multi(inode->i_sb,filp->f_vfsmnt,sbi, p);
+ return autofs4_expire_multi(inode->i_sb,filp->f_path.mnt,sbi, p);
default:
return -ENOSYS;
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 34e6d7b220c..869f5193ecc 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -14,59 +14,307 @@
#include <linux/time.h>
#include <linux/smp_lock.h>
#include <linux/namei.h>
+#include <linux/poll.h>
-static int return_EIO(void)
+
+static loff_t bad_file_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -EIO;
+}
+
+static ssize_t bad_file_read(struct file *filp, char __user *buf,
+ size_t size, loff_t *ppos)
+{
+ return -EIO;
+}
+
+static ssize_t bad_file_write(struct file *filp, const char __user *buf,
+ size_t siz, loff_t *ppos)
+{
+ return -EIO;
+}
+
+static ssize_t bad_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ return -EIO;
+}
+
+static ssize_t bad_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ return -EIO;
+}
+
+static int bad_file_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ return -EIO;
+}
+
+static unsigned int bad_file_poll(struct file *filp, poll_table *wait)
+{
+ return POLLERR;
+}
+
+static int bad_file_ioctl (struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ return -EIO;
+}
+
+static long bad_file_unlocked_ioctl(struct file *file, unsigned cmd,
+ unsigned long arg)
+{
+ return -EIO;
+}
+
+static long bad_file_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return -EIO;
+}
+
+static int bad_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return -EIO;
+}
+
+static int bad_file_open(struct inode *inode, struct file *filp)
+{
+ return -EIO;
+}
+
+static int bad_file_flush(struct file *file, fl_owner_t id)
+{
+ return -EIO;
+}
+
+static int bad_file_release(struct inode *inode, struct file *filp)
+{
+ return -EIO;
+}
+
+static int bad_file_fsync(struct file *file, struct dentry *dentry,
+ int datasync)
+{
+ return -EIO;
+}
+
+static int bad_file_aio_fsync(struct kiocb *iocb, int datasync)
+{
+ return -EIO;
+}
+
+static int bad_file_fasync(int fd, struct file *filp, int on)
+{
+ return -EIO;
+}
+
+static int bad_file_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+ return -EIO;
+}
+
+static ssize_t bad_file_sendfile(struct file *in_file, loff_t *ppos,
+ size_t count, read_actor_t actor, void *target)
+{
+ return -EIO;
+}
+
+static ssize_t bad_file_sendpage(struct file *file, struct page *page,
+ int off, size_t len, loff_t *pos, int more)
+{
+ return -EIO;
+}
+
+static unsigned long bad_file_get_unmapped_area(struct file *file,
+ unsigned long addr, unsigned long len,
+ unsigned long pgoff, unsigned long flags)
+{
+ return -EIO;
+}
+
+static int bad_file_check_flags(int flags)
{
return -EIO;
}
-#define EIO_ERROR ((void *) (return_EIO))
+static int bad_file_dir_notify(struct file *file, unsigned long arg)
+{
+ return -EIO;
+}
+
+static int bad_file_flock(struct file *filp, int cmd, struct file_lock *fl)
+{
+ return -EIO;
+}
+
+static ssize_t bad_file_splice_write(struct pipe_inode_info *pipe,
+ struct file *out, loff_t *ppos, size_t len,
+ unsigned int flags)
+{
+ return -EIO;
+}
+
+static ssize_t bad_file_splice_read(struct file *in, loff_t *ppos,
+ struct pipe_inode_info *pipe, size_t len,
+ unsigned int flags)
+{
+ return -EIO;
+}
static const struct file_operations bad_file_ops =
{
- .llseek = EIO_ERROR,
- .aio_read = EIO_ERROR,
- .read = EIO_ERROR,
- .write = EIO_ERROR,
- .aio_write = EIO_ERROR,
- .readdir = EIO_ERROR,
- .poll = EIO_ERROR,
- .ioctl = EIO_ERROR,
- .mmap = EIO_ERROR,
- .open = EIO_ERROR,
- .flush = EIO_ERROR,
- .release = EIO_ERROR,
- .fsync = EIO_ERROR,
- .aio_fsync = EIO_ERROR,
- .fasync = EIO_ERROR,
- .lock = EIO_ERROR,
- .sendfile = EIO_ERROR,
- .sendpage = EIO_ERROR,
- .get_unmapped_area = EIO_ERROR,
+ .llseek = bad_file_llseek,
+ .read = bad_file_read,
+ .write = bad_file_write,
+ .aio_read = bad_file_aio_read,
+ .aio_write = bad_file_aio_write,
+ .readdir = bad_file_readdir,
+ .poll = bad_file_poll,
+ .ioctl = bad_file_ioctl,
+ .unlocked_ioctl = bad_file_unlocked_ioctl,
+ .compat_ioctl = bad_file_compat_ioctl,
+ .mmap = bad_file_mmap,
+ .open = bad_file_open,
+ .flush = bad_file_flush,
+ .release = bad_file_release,
+ .fsync = bad_file_fsync,
+ .aio_fsync = bad_file_aio_fsync,
+ .fasync = bad_file_fasync,
+ .lock = bad_file_lock,
+ .sendfile = bad_file_sendfile,
+ .sendpage = bad_file_sendpage,
+ .get_unmapped_area = bad_file_get_unmapped_area,
+ .check_flags = bad_file_check_flags,
+ .dir_notify = bad_file_dir_notify,
+ .flock = bad_file_flock,
+ .splice_write = bad_file_splice_write,
+ .splice_read = bad_file_splice_read,
};
+static int bad_inode_create (struct inode *dir, struct dentry *dentry,
+ int mode, struct nameidata *nd)
+{
+ return -EIO;
+}
+
+static struct dentry *bad_inode_lookup(struct inode *dir,
+ struct dentry *dentry, struct nameidata *nd)
+{
+ return ERR_PTR(-EIO);
+}
+
+static int bad_inode_link (struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
+{
+ return -EIO;
+}
+
+static int bad_inode_unlink(struct inode *dir, struct dentry *dentry)
+{
+ return -EIO;
+}
+
+static int bad_inode_symlink (struct inode *dir, struct dentry *dentry,
+ const char *symname)
+{
+ return -EIO;
+}
+
+static int bad_inode_mkdir(struct inode *dir, struct dentry *dentry,
+ int mode)
+{
+ return -EIO;
+}
+
+static int bad_inode_rmdir (struct inode *dir, struct dentry *dentry)
+{
+ return -EIO;
+}
+
+static int bad_inode_mknod (struct inode *dir, struct dentry *dentry,
+ int mode, dev_t rdev)
+{
+ return -EIO;
+}
+
+static int bad_inode_rename (struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+ return -EIO;
+}
+
+static int bad_inode_readlink(struct dentry *dentry, char __user *buffer,
+ int buflen)
+{
+ return -EIO;
+}
+
+static int bad_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ return -EIO;
+}
+
+static int bad_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat)
+{
+ return -EIO;
+}
+
+static int bad_inode_setattr(struct dentry *direntry, struct iattr *attrs)
+{
+ return -EIO;
+}
+
+static int bad_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ return -EIO;
+}
+
+static ssize_t bad_inode_getxattr(struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
+{
+ return -EIO;
+}
+
+static ssize_t bad_inode_listxattr(struct dentry *dentry, char *buffer,
+ size_t buffer_size)
+{
+ return -EIO;
+}
+
+static int bad_inode_removexattr(struct dentry *dentry, const char *name)
+{
+ return -EIO;
+}
+
static struct inode_operations bad_inode_ops =
{
- .create = EIO_ERROR,
- .lookup = EIO_ERROR,
- .link = EIO_ERROR,
- .unlink = EIO_ERROR,
- .symlink = EIO_ERROR,
- .mkdir = EIO_ERROR,
- .rmdir = EIO_ERROR,
- .mknod = EIO_ERROR,
- .rename = EIO_ERROR,
- .readlink = EIO_ERROR,
+ .create = bad_inode_create,
+ .lookup = bad_inode_lookup,
+ .link = bad_inode_link,
+ .unlink = bad_inode_unlink,
+ .symlink = bad_inode_symlink,
+ .mkdir = bad_inode_mkdir,
+ .rmdir = bad_inode_rmdir,
+ .mknod = bad_inode_mknod,
+ .rename = bad_inode_rename,
+ .readlink = bad_inode_readlink,
/* follow_link must be no-op, otherwise unmounting this inode
won't work */
- .truncate = EIO_ERROR,
- .permission = EIO_ERROR,
- .getattr = EIO_ERROR,
- .setattr = EIO_ERROR,
- .setxattr = EIO_ERROR,
- .getxattr = EIO_ERROR,
- .listxattr = EIO_ERROR,
- .removexattr = EIO_ERROR,
+ /* put_link returns void */
+ /* truncate returns void */
+ .permission = bad_inode_permission,
+ .getattr = bad_inode_getattr,
+ .setattr = bad_inode_setattr,
+ .setxattr = bad_inode_setxattr,
+ .getxattr = bad_inode_getxattr,
+ .listxattr = bad_inode_listxattr,
+ .removexattr = bad_inode_removexattr,
+ /* truncate_range returns void */
};
@@ -88,7 +336,7 @@ static struct inode_operations bad_inode_ops =
* on it to fail from this point on.
*/
-void make_bad_inode(struct inode * inode)
+void make_bad_inode(struct inode *inode)
{
remove_inode_hash(inode);
@@ -113,7 +361,7 @@ EXPORT_SYMBOL(make_bad_inode);
* Returns true if the inode in question has been marked as bad.
*/
-int is_bad_inode(struct inode * inode)
+int is_bad_inode(struct inode *inode)
{
return (inode->i_op == &bad_inode_ops);
}
diff --git a/fs/befs/btree.c b/fs/befs/btree.c
index 81b042ee24e..af5bb93276f 100644
--- a/fs/befs/btree.c
+++ b/fs/befs/btree.c
@@ -260,7 +260,7 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds,
goto error;
}
- this_node = (befs_btree_node *) kmalloc(sizeof (befs_btree_node),
+ this_node = kmalloc(sizeof (befs_btree_node),
GFP_NOFS);
if (!this_node) {
befs_error(sb, "befs_btree_find() failed to allocate %u "
diff --git a/fs/befs/debug.c b/fs/befs/debug.c
index e831a8f3084..b8e304a0661 100644
--- a/fs/befs/debug.c
+++ b/fs/befs/debug.c
@@ -28,7 +28,7 @@ void
befs_error(const struct super_block *sb, const char *fmt, ...)
{
va_list args;
- char *err_buf = (char *) kmalloc(ERRBUFSIZE, GFP_KERNEL);
+ char *err_buf = kmalloc(ERRBUFSIZE, GFP_KERNEL);
if (err_buf == NULL) {
printk(KERN_ERR "could not allocate %d bytes\n", ERRBUFSIZE);
return;
@@ -46,7 +46,7 @@ void
befs_warning(const struct super_block *sb, const char *fmt, ...)
{
va_list args;
- char *err_buf = (char *) kmalloc(ERRBUFSIZE, GFP_KERNEL);
+ char *err_buf = kmalloc(ERRBUFSIZE, GFP_KERNEL);
if (err_buf == NULL) {
printk(KERN_ERR "could not allocate %d bytes\n", ERRBUFSIZE);
return;
@@ -70,7 +70,7 @@ befs_debug(const struct super_block *sb, const char *fmt, ...)
char *err_buf = NULL;
if (BEFS_SB(sb)->mount_opts.debug) {
- err_buf = (char *) kmalloc(ERRBUFSIZE, GFP_KERNEL);
+ err_buf = kmalloc(ERRBUFSIZE, GFP_KERNEL);
if (err_buf == NULL) {
printk(KERN_ERR "could not allocate %d bytes\n",
ERRBUFSIZE);
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index bce402eee55..481e59b9d91 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -212,7 +212,7 @@ befs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
static int
befs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
befs_off_t value;
@@ -222,7 +222,7 @@ befs_readdir(struct file *filp, void *dirent, filldir_t filldir)
char keybuf[BEFS_NAME_LEN + 1];
char *nlsname;
int nlsnamelen;
- const char *dirname = filp->f_dentry->d_name.name;
+ const char *dirname = filp->f_path.dentry->d_name.name;
befs_debug(sb, "---> befs_readdir() "
"name %s, inode %ld, filp->f_pos %Ld",
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index a650f1d0b85..2a746e688df 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -27,7 +27,7 @@ static struct buffer_head * bfs_find_entry(struct inode * dir,
static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
{
- struct inode * dir = f->f_dentry->d_inode;
+ struct inode * dir = f->f_path.dentry->d_inode;
struct buffer_head * bh;
struct bfs_dirent * de;
unsigned int offset;
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index eac175ed9f4..134c99941a6 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -1,7 +1,7 @@
/*
* fs/bfs/inode.c
* BFS superblock and inode operations.
- * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com>
+ * Copyright (C) 1999-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
* From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds.
*
* Made endianness-clean by Andrew Stribblehill <ads@wompom.org>, 2005.
@@ -18,7 +18,7 @@
#include <asm/uaccess.h>
#include "bfs.h"
-MODULE_AUTHOR("Tigran A. Aivazian <tigran@veritas.com>");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
MODULE_DESCRIPTION("SCO UnixWare BFS filesystem for Linux");
MODULE_LICENSE("GPL");
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 517e111bb7e..813a887cd2b 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -274,7 +274,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
N_TRSIZE(ex) || N_DRSIZE(ex) ||
- i_size_read(bprm->file->f_dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+ i_size_read(bprm->file->f_path.dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
return -ENOEXEC;
}
@@ -389,7 +389,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
printk(KERN_WARNING
"fd_offset is not page aligned. Please convert program: %s\n",
- bprm->file->f_dentry->d_name.name);
+ bprm->file->f_path.dentry->d_name.name);
error_time = jiffies;
}
@@ -469,7 +469,7 @@ static int load_aout_library(struct file *file)
int retval;
struct exec ex;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
retval = -ENOEXEC;
error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
@@ -506,7 +506,7 @@ static int load_aout_library(struct file *file)
{
printk(KERN_WARNING
"N_TXTOFF is not page aligned. Please convert library: %s\n",
- file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.name);
error_time = jiffies;
}
down_write(&current->mm->mmap_sem);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index be5869d3499..669dbe5b031 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -682,6 +682,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
retval = PTR_ERR(interpreter);
if (IS_ERR(interpreter))
goto out_free_interp;
+
+ /*
+ * If the binary is not readable then enforce
+ * mm->dumpable = 0 regardless of the interpreter's
+ * permissions.
+ */
+ if (file_permission(interpreter, MAY_READ) < 0)
+ bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
+
retval = kernel_read(interpreter, 0, bprm->buf,
BINPRM_BUF_SIZE);
if (retval != BINPRM_BUF_SIZE) {
@@ -854,13 +863,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
* default mmap base, as well as whatever program they
* might try to exec. This is because the brk will
* follow the loader, and is not movable. */
- if (current->flags & PF_RANDOMIZE)
- load_bias = randomize_range(0x10000,
- ELF_ET_DYN_BASE,
- 0);
- else
- load_bias = ELF_ET_DYN_BASE;
- load_bias = ELF_PAGESTART(load_bias - vaddr);
+ load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
}
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
@@ -1184,13 +1187,17 @@ static int dump_seek(struct file *file, loff_t off)
*/
static int maydump(struct vm_area_struct *vma)
{
+ /* The vma can be set up to tell us the answer directly. */
+ if (vma->vm_flags & VM_ALWAYSDUMP)
+ return 1;
+
/* Do not dump I/O mapped devices or special mappings */
if (vma->vm_flags & (VM_IO | VM_RESERVED))
return 0;
/* Dump shared memory only if mapped from an anonymous file. */
if (vma->vm_flags & VM_SHARED)
- return vma->vm_file->f_dentry->d_inode->i_nlink == 0;
+ return vma->vm_file->f_path.dentry->d_inode->i_nlink == 0;
/* If it hasn't been written to, don't write it out */
if (!vma->anon_vma)
@@ -1317,7 +1324,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
prstatus->pr_pid = p->pid;
prstatus->pr_ppid = p->parent->pid;
prstatus->pr_pgrp = process_group(p);
- prstatus->pr_sid = p->signal->session;
+ prstatus->pr_sid = process_session(p);
if (thread_group_leader(p)) {
/*
* This is the record for the group leader. Add in the
@@ -1363,7 +1370,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
psinfo->pr_pid = p->pid;
psinfo->pr_ppid = p->parent->pid;
psinfo->pr_pgrp = process_group(p);
- psinfo->pr_sid = p->signal->session;
+ psinfo->pr_sid = process_session(p);
i = p->state ? ffz(~p->state) + 1 : 0;
psinfo->pr_state = i;
@@ -1430,6 +1437,32 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
return sz;
}
+static struct vm_area_struct *first_vma(struct task_struct *tsk,
+ struct vm_area_struct *gate_vma)
+{
+ struct vm_area_struct *ret = tsk->mm->mmap;
+
+ if (ret)
+ return ret;
+ return gate_vma;
+}
+/*
+ * Helper function for iterating across a vma list. It ensures that the caller
+ * will visit `gate_vma' prior to terminating the search.
+ */
+static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
+ struct vm_area_struct *gate_vma)
+{
+ struct vm_area_struct *ret;
+
+ ret = this_vma->vm_next;
+ if (ret)
+ return ret;
+ if (this_vma == gate_vma)
+ return NULL;
+ return gate_vma;
+}
+
/*
* Actual dumper
*
@@ -1445,7 +1478,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
int segs;
size_t size = 0;
int i;
- struct vm_area_struct *vma;
+ struct vm_area_struct *vma, *gate_vma;
struct elfhdr *elf = NULL;
loff_t offset = 0, dataoff, foffset;
unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
@@ -1531,6 +1564,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
segs += ELF_CORE_EXTRA_PHDRS;
#endif
+ gate_vma = get_gate_vma(current);
+ if (gate_vma != NULL)
+ segs++;
+
/* Set up header */
fill_elf_header(elf, segs + 1); /* including notes section */
@@ -1598,7 +1635,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
/* Write program headers for segments dump */
- for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+ for (vma = first_vma(current, gate_vma); vma != NULL;
+ vma = next_vma(vma, gate_vma)) {
struct elf_phdr phdr;
size_t sz;
@@ -1647,7 +1685,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
/* Align to page */
DUMP_SEEK(dataoff - foffset);
- for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+ for (vma = first_vma(current, gate_vma); vma != NULL;
+ vma = next_vma(vma, gate_vma)) {
unsigned long addr;
if (!maydump(vma))
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index ed9a61c6beb..a4d933a5120 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -234,6 +234,14 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm,
goto error;
}
+ /*
+ * If the binary is not readable then enforce
+ * mm->dumpable = 0 regardless of the interpreter's
+ * permissions.
+ */
+ if (file_permission(interpreter, MAY_READ) < 0)
+ bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
+
retval = kernel_read(interpreter, 0, bprm->buf,
BINPRM_BUF_SIZE);
if (retval < 0)
@@ -706,12 +714,11 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
return -ELIBBAD;
size = sizeof(*loadmap) + nloads * sizeof(*seg);
- loadmap = kmalloc(size, GFP_KERNEL);
+ loadmap = kzalloc(size, GFP_KERNEL);
if (!loadmap)
return -ENOMEM;
params->loadmap = loadmap;
- memset(loadmap, 0, size);
loadmap->version = ELF32_FDPIC_LOADMAP_VERSION;
loadmap->nsegs = nloads;
@@ -855,7 +862,7 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
dynamic_error:
printk("ELF FDPIC %s with invalid DYNAMIC section (inode=%lu)\n",
- what, file->f_dentry->d_inode->i_ino);
+ what, file->f_path.dentry->d_inode->i_ino);
return -ELIBBAD;
}
@@ -1186,7 +1193,7 @@ static int maydump(struct vm_area_struct *vma)
/* Dump shared memory only if mapped from an anonymous file. */
if (vma->vm_flags & VM_SHARED) {
- if (vma->vm_file->f_dentry->d_inode->i_nlink == 0) {
+ if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0) {
kdcore("%08lx: %08lx: no (share)", vma->vm_start, vma->vm_flags);
return 1;
}
@@ -1322,7 +1329,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
prstatus->pr_pid = p->pid;
prstatus->pr_ppid = p->parent->pid;
prstatus->pr_pgrp = process_group(p);
- prstatus->pr_sid = p->signal->session;
+ prstatus->pr_sid = process_session(p);
if (thread_group_leader(p)) {
/*
* This is the record for the group leader. Add in the
@@ -1371,7 +1378,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
psinfo->pr_pid = p->pid;
psinfo->pr_ppid = p->parent->pid;
psinfo->pr_pgrp = process_group(p);
- psinfo->pr_sid = p->signal->session;
+ psinfo->pr_sid = process_session(p);
i = p->state ? ffz(~p->state) + 1 : 0;
psinfo->pr_state = i;
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index a62fd4018a2..7b0265d7f3a 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -419,7 +419,7 @@ static int load_flat_file(struct linux_binprm * bprm,
unsigned long textpos = 0, datapos = 0, result;
unsigned long realdatastart = 0;
unsigned long text_len, data_len, bss_len, stack_len, flags;
- unsigned long memp = 0; /* for finding the brk area */
+ unsigned long len, reallen, memp = 0;
unsigned long extra, rlim;
unsigned long *reloc = 0, *rp;
struct inode *inode;
@@ -429,7 +429,7 @@ static int load_flat_file(struct linux_binprm * bprm,
int ret;
hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */
- inode = bprm->file->f_dentry->d_inode;
+ inode = bprm->file->f_path.dentry->d_inode;
text_len = ntohl(hdr->data_start);
data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start);
@@ -540,10 +540,18 @@ static int load_flat_file(struct linux_binprm * bprm,
goto err;
}
+ len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
down_write(&current->mm->mmap_sem);
- realdatastart = do_mmap(0, 0, data_len + extra +
- MAX_SHARED_LIBS * sizeof(unsigned long),
- PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
+ realdatastart = do_mmap(0, 0, len,
+ PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
+ /* Remap to use all availabe slack region space */
+ if (realdatastart && (realdatastart < (unsigned long)-4096)) {
+ reallen = ksize(realdatastart);
+ if (reallen > len) {
+ realdatastart = do_mremap(realdatastart, len,
+ reallen, MREMAP_FIXED, realdatastart);
+ }
+ }
up_write(&current->mm->mmap_sem);
if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) {
@@ -584,11 +592,20 @@ static int load_flat_file(struct linux_binprm * bprm,
} else {
+ len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
down_write(&current->mm->mmap_sem);
- textpos = do_mmap(0, 0, text_len + data_len + extra +
- MAX_SHARED_LIBS * sizeof(unsigned long),
- PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
+ textpos = do_mmap(0, 0, len,
+ PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
+ /* Remap to use all availabe slack region space */
+ if (textpos && (textpos < (unsigned long) -4096)) {
+ reallen = ksize(textpos);
+ if (reallen > len) {
+ textpos = do_mremap(textpos, len, reallen,
+ MREMAP_FIXED, textpos);
+ }
+ }
up_write(&current->mm->mmap_sem);
+
if (!textpos || textpos >= (unsigned long) -4096) {
if (!textpos)
textpos = (unsigned long) -ENOMEM;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 1713c48fef5..c2e08252af3 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -311,7 +311,7 @@ static Node *create_entry(const char __user *buffer, size_t count)
err = -ENOMEM;
memsize = sizeof(Node) + count + 8;
- e = (Node *) kmalloc(memsize, GFP_USER);
+ e = kmalloc(memsize, GFP_USER);
if (!e)
goto out;
@@ -542,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->i_private;
+ Node *e = file->f_path.dentry->d_inode->i_private;
loff_t pos = *ppos;
ssize_t res;
char *page;
@@ -576,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->i_private;
+ Node *e = file->f_path.dentry->d_inode->i_private;
int res = parse_command(buffer, count);
switch (res) {
@@ -584,7 +584,7 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
break;
case 2: set_bit(Enabled, &e->flags);
break;
- case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root);
+ case 3: root = dget(file->f_path.mnt->mnt_sb->s_root);
mutex_lock(&root->d_inode->i_mutex);
kill_node(e);
@@ -610,7 +610,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
Node *e;
struct inode *inode;
struct dentry *root, *dentry;
- struct super_block *sb = file->f_vfsmnt->mnt_sb;
+ struct super_block *sb = file->f_path.mnt->mnt_sb;
int err = 0;
e = create_entry(buffer, count);
@@ -699,7 +699,7 @@ static ssize_t bm_status_write(struct file * file, const char __user * buffer,
switch (res) {
case 1: enabled = 0; break;
case 2: enabled = 1; break;
- case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root);
+ case 3: root = dget(file->f_path.mnt->mnt_sb->s_root);
mutex_lock(&root->d_inode->i_mutex);
while (!list_empty(&entries))
diff --git a/fs/bio.c b/fs/bio.c
index 7ec737eda72..7618bcb1836 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -916,7 +916,7 @@ void bio_set_pages_dirty(struct bio *bio)
}
}
-static void bio_release_pages(struct bio *bio)
+void bio_release_pages(struct bio *bio)
{
struct bio_vec *bvec = bio->bi_io_vec;
int i;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 13816b4d76f..fc7028b685f 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -168,6 +168,203 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
iov, offset, nr_segs, blkdev_get_blocks, NULL);
}
+#if 0
+static int blk_end_aio(struct bio *bio, unsigned int bytes_done, int error)
+{
+ struct kiocb *iocb = bio->bi_private;
+ atomic_t *bio_count = &iocb->ki_bio_count;
+
+ if (bio_data_dir(bio) == READ)
+ bio_check_pages_dirty(bio);
+ else {
+ bio_release_pages(bio);
+ bio_put(bio);
+ }
+
+ /* iocb->ki_nbytes stores error code from LLDD */
+ if (error)
+ iocb->ki_nbytes = -EIO;
+
+ if (atomic_dec_and_test(bio_count)) {
+ if ((long)iocb->ki_nbytes < 0)
+ aio_complete(iocb, iocb->ki_nbytes, 0);
+ else
+ aio_complete(iocb, iocb->ki_left, 0);
+ }
+
+ return 0;
+}
+
+#define VEC_SIZE 16
+struct pvec {
+ unsigned short nr;
+ unsigned short idx;
+ struct page *page[VEC_SIZE];
+};
+
+#define PAGES_SPANNED(addr, len) \
+ (DIV_ROUND_UP((addr) + (len), PAGE_SIZE) - (addr) / PAGE_SIZE);
+
+/*
+ * get page pointer for user addr, we internally cache struct page array for
+ * (addr, count) range in pvec to avoid frequent call to get_user_pages. If
+ * internal page list is exhausted, a batch count of up to VEC_SIZE is used
+ * to get next set of page struct.
+ */
+static struct page *blk_get_page(unsigned long addr, size_t count, int rw,
+ struct pvec *pvec)
+{
+ int ret, nr_pages;
+ if (pvec->idx == pvec->nr) {
+ nr_pages = PAGES_SPANNED(addr, count);
+ nr_pages = min(nr_pages, VEC_SIZE);
+ down_read(&current->mm->mmap_sem);
+ ret = get_user_pages(current, current->mm, addr, nr_pages,
+ rw == READ, 0, pvec->page, NULL);
+ up_read(&current->mm->mmap_sem);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ pvec->nr = ret;
+ pvec->idx = 0;
+ }
+ return pvec->page[pvec->idx++];
+}
+
+/* return a page back to pvec array */
+static void blk_unget_page(struct page *page, struct pvec *pvec)
+{
+ pvec->page[--pvec->idx] = page;
+}
+
+static ssize_t
+blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
+ loff_t pos, unsigned long nr_segs)
+{
+ struct inode *inode = iocb->ki_filp->f_mapping->host;
+ unsigned blkbits = blksize_bits(bdev_hardsect_size(I_BDEV(inode)));
+ unsigned blocksize_mask = (1 << blkbits) - 1;
+ unsigned long seg = 0; /* iov segment iterator */
+ unsigned long nvec; /* number of bio vec needed */
+ unsigned long cur_off; /* offset into current page */
+ unsigned long cur_len; /* I/O len of current page, up to PAGE_SIZE */
+
+ unsigned long addr; /* user iovec address */
+ size_t count; /* user iovec len */
+ size_t nbytes = iocb->ki_nbytes = iocb->ki_left; /* total xfer size */
+ loff_t size; /* size of block device */
+ struct bio *bio;
+ atomic_t *bio_count = &iocb->ki_bio_count;
+ struct page *page;
+ struct pvec pvec;
+
+ pvec.nr = 0;
+ pvec.idx = 0;
+
+ if (pos & blocksize_mask)
+ return -EINVAL;
+
+ size = i_size_read(inode);
+ if (pos + nbytes > size) {
+ nbytes = size - pos;
+ iocb->ki_left = nbytes;
+ }
+
+ /*
+ * check first non-zero iov alignment, the remaining
+ * iov alignment is checked inside bio loop below.
+ */
+ do {
+ addr = (unsigned long) iov[seg].iov_base;
+ count = min(iov[seg].iov_len, nbytes);
+ if (addr & blocksize_mask || count & blocksize_mask)
+ return -EINVAL;
+ } while (!count && ++seg < nr_segs);
+ atomic_set(bio_count, 1);
+
+ while (nbytes) {
+ /* roughly estimate number of bio vec needed */
+ nvec = (nbytes + PAGE_SIZE - 1) / PAGE_SIZE;
+ nvec = max(nvec, nr_segs - seg);
+ nvec = min(nvec, (unsigned long) BIO_MAX_PAGES);
+
+ /* bio_alloc should not fail with GFP_KERNEL flag */
+ bio = bio_alloc(GFP_KERNEL, nvec);
+ bio->bi_bdev = I_BDEV(inode);
+ bio->bi_end_io = blk_end_aio;
+ bio->bi_private = iocb;
+ bio->bi_sector = pos >> blkbits;
+same_bio:
+ cur_off = addr & ~PAGE_MASK;
+ cur_len = PAGE_SIZE - cur_off;
+ if (count < cur_len)
+ cur_len = count;
+
+ page = blk_get_page(addr, count, rw, &pvec);
+ if (unlikely(IS_ERR(page)))
+ goto backout;
+
+ if (bio_add_page(bio, page, cur_len, cur_off)) {
+ pos += cur_len;
+ addr += cur_len;
+ count -= cur_len;
+ nbytes -= cur_len;
+
+ if (count)
+ goto same_bio;
+ while (++seg < nr_segs) {
+ addr = (unsigned long) iov[seg].iov_base;
+ count = iov[seg].iov_len;
+ if (!count)
+ continue;
+ if (unlikely(addr & blocksize_mask ||
+ count & blocksize_mask)) {
+ page = ERR_PTR(-EINVAL);
+ goto backout;
+ }
+ count = min(count, nbytes);
+ goto same_bio;
+ }
+ } else {
+ blk_unget_page(page, &pvec);
+ }
+
+ /* bio is ready, submit it */
+ if (rw == READ)
+ bio_set_pages_dirty(bio);
+ atomic_inc(bio_count);
+ submit_bio(rw, bio);
+ }
+
+completion:
+ iocb->ki_left -= nbytes;
+ nbytes = iocb->ki_left;
+ iocb->ki_pos += nbytes;
+
+ blk_run_address_space(inode->i_mapping);
+ if (atomic_dec_and_test(bio_count))
+ aio_complete(iocb, nbytes, 0);
+
+ return -EIOCBQUEUED;
+
+backout:
+ /*
+ * back out nbytes count constructed so far for this bio,
+ * we will throw away current bio.
+ */
+ nbytes += bio->bi_size;
+ bio_release_pages(bio);
+ bio_put(bio);
+
+ /*
+ * if no bio was submmitted, return the error code.
+ * otherwise, proceed with pending I/O completion.
+ */
+ if (atomic_read(bio_count) == 1)
+ return PTR_ERR(page);
+ goto completion;
+}
+#endif
+
static int blkdev_writepage(struct page *page, struct writeback_control *wbc)
{
return block_write_full_page(page, blkdev_get_block, wbc);
@@ -190,7 +387,7 @@ static int blkdev_commit_write(struct file *file, struct page *page, unsigned fr
/*
* private llseek:
- * for a block special file file->f_dentry->d_inode->i_size is zero
+ * for a block special file file->f_path.dentry->d_inode->i_size is zero
* so we compute the size by hand (just as in block_read/write above)
*/
static loff_t block_llseek(struct file *file, loff_t offset, int origin)
@@ -263,7 +460,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
memset(bdev, 0, sizeof(*bdev));
mutex_init(&bdev->bd_mutex);
- mutex_init(&bdev->bd_mount_mutex);
+ sema_init(&bdev->bd_mount_sem, 1);
INIT_LIST_HEAD(&bdev->bd_inodes);
INIT_LIST_HEAD(&bdev->bd_list);
#ifdef CONFIG_SYSFS
@@ -762,7 +959,7 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
if (!bo)
return -ENOMEM;
- mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION);
+ mutex_lock(&bdev->bd_mutex);
res = bd_claim(bdev, holder);
if (res == 0) {
found = find_bd_holder(bdev, bo);
@@ -796,7 +993,7 @@ static void bd_release_from_kobject(struct block_device *bdev,
if (!kobj)
return;
- mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION);
+ mutex_lock(&bdev->bd_mutex);
bd_release(bdev);
if ((bo = del_bd_holder(bdev, kobj)))
free_bd_holder(bo);
@@ -854,22 +1051,6 @@ struct block_device *open_by_devnum(dev_t dev, unsigned mode)
EXPORT_SYMBOL(open_by_devnum);
-static int
-blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags);
-
-struct block_device *open_partition_by_devnum(dev_t dev, unsigned mode)
-{
- struct block_device *bdev = bdget(dev);
- int err = -ENOMEM;
- int flags = mode & FMODE_WRITE ? O_RDWR : O_RDONLY;
- if (bdev)
- err = blkdev_get_partition(bdev, mode, flags);
- return err ? ERR_PTR(err) : bdev;
-}
-
-EXPORT_SYMBOL(open_partition_by_devnum);
-
-
/*
* This routine checks whether a removable media has been changed,
* and invalidates all buffer-cache-entries in that case. This
@@ -916,66 +1097,11 @@ void bd_set_size(struct block_device *bdev, loff_t size)
}
EXPORT_SYMBOL(bd_set_size);
-static int __blkdev_put(struct block_device *bdev, unsigned int subclass)
-{
- int ret = 0;
- struct inode *bd_inode = bdev->bd_inode;
- struct gendisk *disk = bdev->bd_disk;
-
- mutex_lock_nested(&bdev->bd_mutex, subclass);
- lock_kernel();
- if (!--bdev->bd_openers) {
- sync_blockdev(bdev);
- kill_bdev(bdev);
- }
- if (bdev->bd_contains == bdev) {
- if (disk->fops->release)
- ret = disk->fops->release(bd_inode, NULL);
- } else {
- mutex_lock_nested(&bdev->bd_contains->bd_mutex,
- subclass + 1);
- bdev->bd_contains->bd_part_count--;
- mutex_unlock(&bdev->bd_contains->bd_mutex);
- }
- if (!bdev->bd_openers) {
- struct module *owner = disk->fops->owner;
-
- put_disk(disk);
- module_put(owner);
-
- if (bdev->bd_contains != bdev) {
- kobject_put(&bdev->bd_part->kobj);
- bdev->bd_part = NULL;
- }
- bdev->bd_disk = NULL;
- bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
- if (bdev != bdev->bd_contains)
- __blkdev_put(bdev->bd_contains, subclass + 1);
- bdev->bd_contains = NULL;
- }
- unlock_kernel();
- mutex_unlock(&bdev->bd_mutex);
- bdput(bdev);
- return ret;
-}
-
-int blkdev_put(struct block_device *bdev)
-{
- return __blkdev_put(bdev, BD_MUTEX_NORMAL);
-}
-EXPORT_SYMBOL(blkdev_put);
+static int __blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags,
+ int for_part);
+static int __blkdev_put(struct block_device *bdev, int for_part);
-int blkdev_put_partition(struct block_device *bdev)
-{
- return __blkdev_put(bdev, BD_MUTEX_PARTITION);
-}
-EXPORT_SYMBOL(blkdev_put_partition);
-
-static int
-blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags);
-
-static int
-do_open(struct block_device *bdev, struct file *file, unsigned int subclass)
+static int do_open(struct block_device *bdev, struct file *file, int for_part)
{
struct module *owner = NULL;
struct gendisk *disk;
@@ -992,8 +1118,7 @@ do_open(struct block_device *bdev, struct file *file, unsigned int subclass)
}
owner = disk->fops->owner;
- mutex_lock_nested(&bdev->bd_mutex, subclass);
-
+ mutex_lock_nested(&bdev->bd_mutex, for_part);
if (!bdev->bd_openers) {
bdev->bd_disk = disk;
bdev->bd_contains = bdev;
@@ -1020,25 +1145,21 @@ do_open(struct block_device *bdev, struct file *file, unsigned int subclass)
ret = -ENOMEM;
if (!whole)
goto out_first;
- ret = blkdev_get_whole(whole, file->f_mode, file->f_flags);
+ BUG_ON(for_part);
+ ret = __blkdev_get(whole, file->f_mode, file->f_flags, 1);
if (ret)
goto out_first;
bdev->bd_contains = whole;
- mutex_lock_nested(&whole->bd_mutex, BD_MUTEX_WHOLE);
- whole->bd_part_count++;
p = disk->part[part - 1];
bdev->bd_inode->i_data.backing_dev_info =
whole->bd_inode->i_data.backing_dev_info;
if (!(disk->flags & GENHD_FL_UP) || !p || !p->nr_sects) {
- whole->bd_part_count--;
- mutex_unlock(&whole->bd_mutex);
ret = -ENXIO;
goto out_first;
}
kobject_get(&p->kobj);
bdev->bd_part = p;
bd_set_size(bdev, (loff_t) p->nr_sects << 9);
- mutex_unlock(&whole->bd_mutex);
}
} else {
put_disk(disk);
@@ -1051,14 +1172,11 @@ do_open(struct block_device *bdev, struct file *file, unsigned int subclass)
}
if (bdev->bd_invalidated)
rescan_partitions(bdev->bd_disk, bdev);
- } else {
- mutex_lock_nested(&bdev->bd_contains->bd_mutex,
- BD_MUTEX_WHOLE);
- bdev->bd_contains->bd_part_count++;
- mutex_unlock(&bdev->bd_contains->bd_mutex);
}
}
bdev->bd_openers++;
+ if (for_part)
+ bdev->bd_part_count++;
mutex_unlock(&bdev->bd_mutex);
unlock_kernel();
return 0;
@@ -1067,7 +1185,7 @@ out_first:
bdev->bd_disk = NULL;
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
if (bdev != bdev->bd_contains)
- __blkdev_put(bdev->bd_contains, BD_MUTEX_WHOLE);
+ __blkdev_put(bdev->bd_contains, 1);
bdev->bd_contains = NULL;
put_disk(disk);
module_put(owner);
@@ -1079,7 +1197,8 @@ out:
return ret;
}
-int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags)
+static int __blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags,
+ int for_part)
{
/*
* This crockload is due to bad choice of ->open() type.
@@ -1091,51 +1210,17 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags)
struct dentry fake_dentry = {};
fake_file.f_mode = mode;
fake_file.f_flags = flags;
- fake_file.f_dentry = &fake_dentry;
+ fake_file.f_path.dentry = &fake_dentry;
fake_dentry.d_inode = bdev->bd_inode;
- return do_open(bdev, &fake_file, BD_MUTEX_NORMAL);
+ return do_open(bdev, &fake_file, for_part);
}
-EXPORT_SYMBOL(blkdev_get);
-
-static int
-blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags)
+int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags)
{
- /*
- * This crockload is due to bad choice of ->open() type.
- * It will go away.
- * For now, block device ->open() routine must _not_
- * examine anything in 'inode' argument except ->i_rdev.
- */
- struct file fake_file = {};
- struct dentry fake_dentry = {};
- fake_file.f_mode = mode;
- fake_file.f_flags = flags;
- fake_file.f_dentry = &fake_dentry;
- fake_dentry.d_inode = bdev->bd_inode;
-
- return do_open(bdev, &fake_file, BD_MUTEX_WHOLE);
-}
-
-static int
-blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags)
-{
- /*
- * This crockload is due to bad choice of ->open() type.
- * It will go away.
- * For now, block device ->open() routine must _not_
- * examine anything in 'inode' argument except ->i_rdev.
- */
- struct file fake_file = {};
- struct dentry fake_dentry = {};
- fake_file.f_mode = mode;
- fake_file.f_flags = flags;
- fake_file.f_dentry = &fake_dentry;
- fake_dentry.d_inode = bdev->bd_inode;
-
- return do_open(bdev, &fake_file, BD_MUTEX_PARTITION);
+ return __blkdev_get(bdev, mode, flags, 0);
}
+EXPORT_SYMBOL(blkdev_get);
static int blkdev_open(struct inode * inode, struct file * filp)
{
@@ -1154,7 +1239,7 @@ static int blkdev_open(struct inode * inode, struct file * filp)
if (bdev == NULL)
return -ENOMEM;
- res = do_open(bdev, filp, BD_MUTEX_NORMAL);
+ res = do_open(bdev, filp, 0);
if (res)
return res;
@@ -1168,6 +1253,56 @@ static int blkdev_open(struct inode * inode, struct file * filp)
return res;
}
+static int __blkdev_put(struct block_device *bdev, int for_part)
+{
+ int ret = 0;
+ struct inode *bd_inode = bdev->bd_inode;
+ struct gendisk *disk = bdev->bd_disk;
+ struct block_device *victim = NULL;
+
+ mutex_lock_nested(&bdev->bd_mutex, for_part);
+ lock_kernel();
+ if (for_part)
+ bdev->bd_part_count--;
+
+ if (!--bdev->bd_openers) {
+ sync_blockdev(bdev);
+ kill_bdev(bdev);
+ }
+ if (bdev->bd_contains == bdev) {
+ if (disk->fops->release)
+ ret = disk->fops->release(bd_inode, NULL);
+ }
+ if (!bdev->bd_openers) {
+ struct module *owner = disk->fops->owner;
+
+ put_disk(disk);
+ module_put(owner);
+
+ if (bdev->bd_contains != bdev) {
+ kobject_put(&bdev->bd_part->kobj);
+ bdev->bd_part = NULL;
+ }
+ bdev->bd_disk = NULL;
+ bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
+ if (bdev != bdev->bd_contains)
+ victim = bdev->bd_contains;
+ bdev->bd_contains = NULL;
+ }
+ unlock_kernel();
+ mutex_unlock(&bdev->bd_mutex);
+ bdput(bdev);
+ if (victim)
+ __blkdev_put(victim, 1);
+ return ret;
+}
+
+int blkdev_put(struct block_device *bdev)
+{
+ return __blkdev_put(bdev, 0);
+}
+EXPORT_SYMBOL(blkdev_put);
+
static int blkdev_close(struct inode * inode, struct file * filp)
{
struct block_device *bdev = I_BDEV(filp->f_mapping->host);
diff --git a/fs/buffer.c b/fs/buffer.c
index 517860f2d75..1ad674fd348 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -35,6 +35,7 @@
#include <linux/hash.h>
#include <linux/suspend.h>
#include <linux/buffer_head.h>
+#include <linux/task_io_accounting_ops.h>
#include <linux/bio.h>
#include <linux/notifier.h>
#include <linux/cpu.h>
@@ -179,7 +180,7 @@ int fsync_bdev(struct block_device *bdev)
* freeze_bdev -- lock a filesystem and force it into a consistent state
* @bdev: blockdevice to lock
*
- * This takes the block device bd_mount_mutex to make sure no new mounts
+ * This takes the block device bd_mount_sem to make sure no new mounts
* happen on bdev until thaw_bdev() is called.
* If a superblock is found on this device, we take the s_umount semaphore
* on it to make sure nobody unmounts until the snapshot creation is done.
@@ -188,7 +189,7 @@ struct super_block *freeze_bdev(struct block_device *bdev)
{
struct super_block *sb;
- mutex_lock(&bdev->bd_mount_mutex);
+ down(&bdev->bd_mount_sem);
sb = get_super(bdev);
if (sb && !(sb->s_flags & MS_RDONLY)) {
sb->s_frozen = SB_FREEZE_WRITE;
@@ -230,7 +231,7 @@ void thaw_bdev(struct block_device *bdev, struct super_block *sb)
drop_super(sb);
}
- mutex_unlock(&bdev->bd_mount_mutex);
+ up(&bdev->bd_mount_sem);
}
EXPORT_SYMBOL(thaw_bdev);
@@ -724,20 +725,21 @@ int __set_page_dirty_buffers(struct page *page)
}
spin_unlock(&mapping->private_lock);
- if (!TestSetPageDirty(page)) {
- write_lock_irq(&mapping->tree_lock);
- if (page->mapping) { /* Race with truncate? */
- if (mapping_cap_account_dirty(mapping))
- __inc_zone_page_state(page, NR_FILE_DIRTY);
- radix_tree_tag_set(&mapping->page_tree,
- page_index(page),
- PAGECACHE_TAG_DIRTY);
+ if (TestSetPageDirty(page))
+ return 0;
+
+ write_lock_irq(&mapping->tree_lock);
+ if (page->mapping) { /* Race with truncate? */
+ if (mapping_cap_account_dirty(mapping)) {
+ __inc_zone_page_state(page, NR_FILE_DIRTY);
+ task_io_account_write(PAGE_CACHE_SIZE);
}
- write_unlock_irq(&mapping->tree_lock);
- __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
- return 1;
+ radix_tree_tag_set(&mapping->page_tree,
+ page_index(page), PAGECACHE_TAG_DIRTY);
}
- return 0;
+ write_unlock_irq(&mapping->tree_lock);
+ __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+ return 1;
}
EXPORT_SYMBOL(__set_page_dirty_buffers);
@@ -2842,18 +2844,24 @@ int try_to_free_buffers(struct page *page)
spin_lock(&mapping->private_lock);
ret = drop_buffers(page, &buffers_to_free);
+
+ /*
+ * If the filesystem writes its buffers by hand (eg ext3)
+ * then we can have clean buffers against a dirty page. We
+ * clean the page here; otherwise the VM will never notice
+ * that the filesystem did any IO at all.
+ *
+ * Also, during truncate, discard_buffer will have marked all
+ * the page's buffers clean. We discover that here and clean
+ * the page also.
+ *
+ * private_lock must be held over this entire operation in order
+ * to synchronise against __set_page_dirty_buffers and prevent the
+ * dirty bit from being lost.
+ */
+ if (ret)
+ cancel_dirty_page(page, PAGE_CACHE_SIZE);
spin_unlock(&mapping->private_lock);
- if (ret) {
- /*
- * If the filesystem writes its buffers by hand (eg ext3)
- * then we can have clean buffers against a dirty page. We
- * clean the page here; otherwise later reattachment of buffers
- * could encounter a non-uptodate page, which is unresolvable.
- * This only applies in the rare case where try_to_free_buffers
- * succeeds but the page is not freed.
- */
- clear_page_dirty(page);
- }
out:
if (buffers_to_free) {
struct buffer_head *bh = buffers_to_free;
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 0b3c37ef52e..85e3850bf2c 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,9 @@
+Version 1.47
+------------
+Fix oops in list_del during mount caused by unaligned string.
+Seek to SEEK_END forces check for update of file size for non-cached
+files.
+
Version 1.46
------------
Support deep tree mounts. Better support OS/2, Win9x (DOS) time stamps.
@@ -5,7 +11,8 @@ Allow null user to be specified on mount ("username="). Do not return
EINVAL on readdir when filldir fails due to overwritten blocksize
(fixes FC problem). Return error in rename 2nd attempt retry (ie report
if rename by handle also fails, after rename by path fails, we were
-not reporting whether the retry worked or not).
+not reporting whether the retry worked or not). Fix NTLMv2 to
+work to Windows servers (mount with option "sec=ntlmv2").
Version 1.45
------------
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 96abeb73897..6017c465440 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -143,8 +143,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
if((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
(ses->serverNOS == NULL)) {
- buf += sprintf("\nentry for %s not fully displayed\n\t",
- ses->serverName);
+ buf += sprintf(buf, "\nentry for %s not fully "
+ "displayed\n\t", ses->serverName);
} else {
length =
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 4bc250b2d9f..fdeda519eac 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -372,8 +372,10 @@ void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf,
buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
buf->reserved2 = 0;
- buf->names[0].type = 0;
+ buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
buf->names[0].length = 0;
+ buf->names[1].type = 0;
+ buf->names[1].length = 0;
/* calculate buf->ntlmv2_hash */
rc = calc_ntlmv2_hash(ses, nls_cp);
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 71bc87a37fc..93ef09971d2 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -498,7 +498,7 @@ cifs_get_sb(struct file_system_type *fs_type,
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;
+ struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
ssize_t written;
written = generic_file_aio_write(iocb, iov, nr_segs, pos);
@@ -511,7 +511,15 @@ 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 == SEEK_END) {
- int retval = cifs_revalidate(file->f_dentry);
+ int retval;
+
+ /* some applications poll for the file length in this strange
+ way so we must seek to end on non-oplocked files by
+ setting the revalidate time to zero */
+ if(file->f_path.dentry->d_inode)
+ CIFS_I(file->f_path.dentry->d_inode)->time = 0;
+
+ retval = cifs_revalidate(file->f_path.dentry);
if (retval < 0)
return (loff_t)retval;
}
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index a243f779b36..8aa66dcf13b 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -100,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern int cifs_ioctl (struct inode * inode, struct file * filep,
unsigned int command, unsigned long arg);
-#define CIFS_VERSION "1.46"
+#define CIFS_VERSION "1.47"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 6df9dadba64..068ef51edbf 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -580,6 +580,12 @@ typedef union smb_com_session_setup_andx {
/* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */
+#define NTLMSSP_SERVER_TYPE 1
+#define NTLMSSP_DOMAIN_TYPE 2
+#define NTLMSSP_FQ_DOMAIN_TYPE 3
+#define NTLMSSP_DNS_DOMAIN_TYPE 4
+#define NTLMSSP_DNS_PARENT_TYPE 5
+
struct ntlmssp2_name {
__le16 type;
__le16 length;
@@ -593,7 +599,7 @@ struct ntlmv2_resp {
__le64 time;
__u64 client_chal; /* random */
__u32 reserved2;
- struct ntlmssp2_name names[1];
+ struct ntlmssp2_name names[2];
/* array of name entries could follow ending in minimum 4 byte struct */
} __attribute__((packed));
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 098790eb2aa..472e33e0f3c 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -4876,7 +4876,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
} else {
/* Add file to outstanding requests */
/* BB change to kmem cache alloc */
- dnotify_req = (struct dir_notify_req *) kmalloc(
+ dnotify_req = kmalloc(
sizeof(struct dir_notify_req),
GFP_KERNEL);
if(dnotify_req) {
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c
index d91a3d44e9e..da12b482ebe 100644
--- a/fs/cifs/fcntl.c
+++ b/fs/cifs/fcntl.c
@@ -83,10 +83,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
return 0;
xid = GetXid();
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
- full_path = build_path_from_dentry(file->f_dentry);
+ full_path = build_path_from_dentry(file->f_path.dentry);
if(full_path == NULL) {
rc = -ENOMEM;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 2436ed8fc84..e9dcf5ee29a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -29,6 +29,7 @@
#include <linux/pagevec.h>
#include <linux/smp_lock.h>
#include <linux/writeback.h>
+#include <linux/task_io_accounting_ops.h>
#include <linux/delay.h>
#include <asm/div64.h>
#include "cifsfs.h"
@@ -122,34 +123,34 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
/* if not oplocked, invalidate inode pages if mtime or file
size changed */
temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
- if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) &&
- (file->f_dentry->d_inode->i_size ==
+ if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
+ (file->f_path.dentry->d_inode->i_size ==
(loff_t)le64_to_cpu(buf->EndOfFile))) {
cFYI(1, ("inode unchanged on server"));
} else {
- if (file->f_dentry->d_inode->i_mapping) {
+ if (file->f_path.dentry->d_inode->i_mapping) {
/* BB no need to lock inode until after invalidate
since namei code should already have it locked? */
- filemap_write_and_wait(file->f_dentry->d_inode->i_mapping);
+ filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
}
cFYI(1, ("invalidating remote inode since open detected it "
"changed"));
- invalidate_remote_inode(file->f_dentry->d_inode);
+ invalidate_remote_inode(file->f_path.dentry->d_inode);
}
client_can_cache:
if (pTcon->ses->capabilities & CAP_UNIX)
- rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
+ rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
full_path, inode->i_sb, xid);
else
- rc = cifs_get_inode_info(&file->f_dentry->d_inode,
+ rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
full_path, buf, inode->i_sb, xid);
if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = TRUE;
pCifsInode->clientCanCacheRead = TRUE;
cFYI(1, ("Exclusive Oplock granted on inode %p",
- file->f_dentry->d_inode));
+ file->f_path.dentry->d_inode));
} else if ((*oplock & 0xF) == OPLOCK_READ)
pCifsInode->clientCanCacheRead = TRUE;
@@ -178,7 +179,7 @@ int cifs_open(struct inode *inode, struct file *file)
if (file->f_flags & O_CREAT) {
/* search inode for this file and fill in file->private_data */
- pCifsInode = CIFS_I(file->f_dentry->d_inode);
+ pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &pCifsInode->openFileList) {
pCifsFile = list_entry(tmp, struct cifsFileInfo,
@@ -206,7 +207,7 @@ int cifs_open(struct inode *inode, struct file *file)
}
}
- full_path = build_path_from_dentry(file->f_dentry);
+ full_path = build_path_from_dentry(file->f_path.dentry);
if (full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
@@ -291,7 +292,7 @@ int cifs_open(struct inode *inode, struct file *file)
write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist, &pTcon->openFileList);
- pCifsInode = CIFS_I(file->f_dentry->d_inode);
+ pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
if (pCifsInode) {
rc = cifs_open_inode_helper(inode, file, pCifsInode,
pCifsFile, pTcon,
@@ -366,7 +367,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
return 0;
}
- if (file->f_dentry == NULL) {
+ if (file->f_path.dentry == NULL) {
up(&pCifsFile->fh_sem);
cFYI(1, ("failed file reopen, no valid name if dentry freed"));
FreeXid(xid);
@@ -378,7 +379,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
those that already have the rename sem can end up causing writepage
to get called and if the server was down that means we end up here,
and we can never tell if the caller already has the rename_sem */
- full_path = build_path_from_dentry(file->f_dentry);
+ full_path = build_path_from_dentry(file->f_path.dentry);
if (full_path == NULL) {
up(&pCifsFile->fh_sem);
FreeXid(xid);
@@ -444,7 +445,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
pCifsInode->clientCanCacheAll = TRUE;
pCifsInode->clientCanCacheRead = TRUE;
cFYI(1, ("Exclusive Oplock granted on inode %p",
- file->f_dentry->d_inode));
+ file->f_path.dentry->d_inode));
} else if ((oplock & 0xF) == OPLOCK_READ) {
pCifsInode->clientCanCacheRead = TRUE;
pCifsInode->clientCanCacheAll = FALSE;
@@ -551,7 +552,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
if (pCFileStruct) {
struct cifsTconInfo *pTcon;
- struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
@@ -664,7 +665,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
} else
cFYI(1, ("Unknown type of lock"));
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if (file->private_data == NULL) {
@@ -791,10 +792,10 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
int xid, long_op;
struct cifsFileInfo *open_file;
- if (file->f_dentry == NULL)
+ if (file->f_path.dentry == NULL)
return -EBADF;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
if (cifs_sb == NULL)
return -EBADF;
@@ -802,7 +803,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
/* cFYI(1,
(" write %d bytes to offset %lld of %s", write_size,
- *poffset, file->f_dentry->d_name.name)); */
+ *poffset, file->f_path.dentry->d_name.name)); */
if (file->private_data == NULL)
return -EBADF;
@@ -810,12 +811,12 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
open_file = (struct cifsFileInfo *) file->private_data;
xid = GetXid();
- if (file->f_dentry->d_inode == NULL) {
+ if (file->f_path.dentry->d_inode == NULL) {
FreeXid(xid);
return -EBADF;
}
- if (*poffset > file->f_dentry->d_inode->i_size)
+ if (*poffset > file->f_path.dentry->d_inode->i_size)
long_op = 2; /* writes past end of file can take a long time */
else
long_op = 1;
@@ -840,8 +841,8 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
return -EBADF;
}
if (open_file->invalidHandle) {
- if ((file->f_dentry == NULL) ||
- (file->f_dentry->d_inode == NULL)) {
+ if ((file->f_path.dentry == NULL) ||
+ (file->f_path.dentry->d_inode == NULL)) {
FreeXid(xid);
return total_written;
}
@@ -849,7 +850,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
filemap_fdatawait from here so tell
reopen_file not to flush data to server
now */
- rc = cifs_reopen_file(file->f_dentry->d_inode,
+ rc = cifs_reopen_file(file->f_path.dentry->d_inode,
file, FALSE);
if (rc != 0)
break;
@@ -878,17 +879,17 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
cifs_stats_bytes_written(pTcon, total_written);
/* since the write may have blocked check these pointers again */
- if (file->f_dentry) {
- if (file->f_dentry->d_inode) {
- struct inode *inode = file->f_dentry->d_inode;
+ if (file->f_path.dentry) {
+ if (file->f_path.dentry->d_inode) {
+ struct inode *inode = file->f_path.dentry->d_inode;
inode->i_ctime = inode->i_mtime =
current_fs_time(inode->i_sb);
if (total_written > 0) {
- if (*poffset > file->f_dentry->d_inode->i_size)
- i_size_write(file->f_dentry->d_inode,
+ if (*poffset > file->f_path.dentry->d_inode->i_size)
+ i_size_write(file->f_path.dentry->d_inode,
*poffset);
}
- mark_inode_dirty_sync(file->f_dentry->d_inode);
+ mark_inode_dirty_sync(file->f_path.dentry->d_inode);
}
}
FreeXid(xid);
@@ -906,17 +907,17 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
int xid, long_op;
struct cifsFileInfo *open_file;
- if (file->f_dentry == NULL)
+ if (file->f_path.dentry == NULL)
return -EBADF;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
if (cifs_sb == NULL)
return -EBADF;
pTcon = cifs_sb->tcon;
cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
- *poffset, file->f_dentry->d_name.name));
+ *poffset, file->f_path.dentry->d_name.name));
if (file->private_data == NULL)
return -EBADF;
@@ -924,12 +925,12 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
open_file = (struct cifsFileInfo *)file->private_data;
xid = GetXid();
- if (file->f_dentry->d_inode == NULL) {
+ if (file->f_path.dentry->d_inode == NULL) {
FreeXid(xid);
return -EBADF;
}
- if (*poffset > file->f_dentry->d_inode->i_size)
+ if (*poffset > file->f_path.dentry->d_inode->i_size)
long_op = 2; /* writes past end of file can take a long time */
else
long_op = 1;
@@ -955,8 +956,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
return -EBADF;
}
if (open_file->invalidHandle) {
- if ((file->f_dentry == NULL) ||
- (file->f_dentry->d_inode == NULL)) {
+ if ((file->f_path.dentry == NULL) ||
+ (file->f_path.dentry->d_inode == NULL)) {
FreeXid(xid);
return total_written;
}
@@ -964,7 +965,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
filemap_fdatawait from here so tell
reopen_file not to flush data to
server now */
- rc = cifs_reopen_file(file->f_dentry->d_inode,
+ rc = cifs_reopen_file(file->f_path.dentry->d_inode,
file, FALSE);
if (rc != 0)
break;
@@ -1011,16 +1012,16 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
cifs_stats_bytes_written(pTcon, total_written);
/* since the write may have blocked check these pointers again */
- if (file->f_dentry) {
- if (file->f_dentry->d_inode) {
- file->f_dentry->d_inode->i_ctime =
- file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+ if (file->f_path.dentry) {
+ if (file->f_path.dentry->d_inode) {
+ file->f_path.dentry->d_inode->i_ctime =
+ file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;
if (total_written > 0) {
- if (*poffset > file->f_dentry->d_inode->i_size)
- i_size_write(file->f_dentry->d_inode,
+ if (*poffset > file->f_path.dentry->d_inode->i_size)
+ i_size_write(file->f_path.dentry->d_inode,
*poffset);
}
- mark_inode_dirty_sync(file->f_dentry->d_inode);
+ mark_inode_dirty_sync(file->f_path.dentry->d_inode);
}
}
FreeXid(xid);
@@ -1145,7 +1146,7 @@ static int cifs_writepages(struct address_space *mapping,
pgoff_t end;
pgoff_t index;
int range_whole = 0;
- struct kvec iov[32];
+ struct kvec * iov;
int len;
int n_iov = 0;
pgoff_t next;
@@ -1170,15 +1171,21 @@ static int cifs_writepages(struct address_space *mapping,
if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
if(cifs_sb->tcon->ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
- if(!experimEnabled)
+ if(!experimEnabled)
return generic_writepages(mapping, wbc);
+ iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
+ if(iov == NULL)
+ return generic_writepages(mapping, wbc);
+
+
/*
* BB: Is this meaningful for a non-block-device file system?
* If it is, we should test it again after we do I/O
*/
if (wbc->nonblocking && bdi_write_congested(bdi)) {
wbc->encountered_congestion = 1;
+ kfree(iov);
return 0;
}
@@ -1244,14 +1251,21 @@ retry:
wait_on_page_writeback(page);
if (PageWriteback(page) ||
- !test_clear_page_dirty(page)) {
+ !clear_page_dirty_for_io(page)) {
unlock_page(page);
break;
}
+ /*
+ * This actually clears the dirty bit in the radix tree.
+ * See cifs_writepage() for more commentary.
+ */
+ set_page_writeback(page);
+
if (page_offset(page) >= mapping->host->i_size) {
done = 1;
unlock_page(page);
+ end_page_writeback(page);
break;
}
@@ -1315,6 +1329,7 @@ retry:
SetPageError(page);
kunmap(page);
unlock_page(page);
+ end_page_writeback(page);
page_cache_release(page);
}
if ((wbc->nr_to_write -= n_iov) <= 0)
@@ -1336,7 +1351,7 @@ retry:
mapping->writeback_index = index;
FreeXid(xid);
-
+ kfree(iov);
return rc;
}
@@ -1351,11 +1366,23 @@ static int cifs_writepage(struct page* page, struct writeback_control *wbc)
if (!PageUptodate(page)) {
cFYI(1, ("ppw - page not up to date"));
}
-
+
+ /*
+ * Set the "writeback" flag, and clear "dirty" in the radix tree.
+ *
+ * A writepage() implementation always needs to do either this,
+ * or re-dirty the page with "redirty_page_for_writepage()" in
+ * the case of a failure.
+ *
+ * Just unlocking the page will cause the radix tree tag-bits
+ * to fail to update with the state of the page correctly.
+ */
+ set_page_writeback(page);
rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
unlock_page(page);
- page_cache_release(page);
+ end_page_writeback(page);
+ page_cache_release(page);
FreeXid(xid);
return rc;
}
@@ -1384,7 +1411,7 @@ static int cifs_commit_write(struct file *file, struct page *page,
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
rc = cifs_reopen_file(
- file->f_dentry->d_inode, file);
+ file->f_path.dentry->d_inode, file);
if (rc != 0)
break;
}
@@ -1434,7 +1461,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
{
int xid;
int rc = 0;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
xid = GetXid();
@@ -1482,7 +1509,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
*/
int cifs_flush(struct file *file, fl_owner_t id)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
int rc = 0;
/* Rather than do the steps manually:
@@ -1519,7 +1546,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
struct smb_com_read_rsp *pSMBr;
xid = GetXid();
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if (file->private_data == NULL) {
@@ -1542,7 +1569,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
int buf_type = CIFS_NO_BUFFER;
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
- rc = cifs_reopen_file(file->f_dentry->d_inode,
+ rc = cifs_reopen_file(file->f_path.dentry->d_inode,
file, TRUE);
if (rc != 0)
break;
@@ -1601,7 +1628,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
int buf_type = CIFS_NO_BUFFER;
xid = GetXid();
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if (file->private_data == NULL) {
@@ -1629,7 +1656,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
while (rc == -EAGAIN) {
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
- rc = cifs_reopen_file(file->f_dentry->d_inode,
+ rc = cifs_reopen_file(file->f_path.dentry->d_inode,
file, TRUE);
if (rc != 0)
break;
@@ -1658,7 +1685,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
int rc, xid;
xid = GetXid();
@@ -1744,7 +1771,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
return -EBADF;
}
open_file = (struct cifsFileInfo *)file->private_data;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
pagevec_init(&lru_pvec, 0);
@@ -1786,7 +1813,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
while (rc == -EAGAIN) {
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
- rc = cifs_reopen_file(file->f_dentry->d_inode,
+ rc = cifs_reopen_file(file->f_path.dentry->d_inode,
file, TRUE);
if (rc != 0)
break;
@@ -1812,6 +1839,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
cFYI(1, ("Read error in readpages: %d", rc));
break;
} else if (bytes_read > 0) {
+ task_io_account_read(bytes_read);
pSMBr = (struct smb_com_read_rsp *)smb_read_data;
cifs_copy_cache_pages(mapping, page_list, bytes_read,
smb_read_data + 4 /* RFC1001 hdr */ +
@@ -1880,8 +1908,8 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
else
cFYI(1, ("Bytes read %d",rc));
- file->f_dentry->d_inode->i_atime =
- current_fs_time(file->f_dentry->d_inode->i_sb);
+ file->f_path.dentry->d_inode->i_atime =
+ current_fs_time(file->f_path.dentry->d_inode->i_sb);
if (PAGE_CACHE_SIZE > rc)
memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index aedf683f011..19cc294c7c7 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -71,9 +71,7 @@ sesInfoAlloc(void)
{
struct cifsSesInfo *ret_buf;
- ret_buf =
- (struct cifsSesInfo *) kzalloc(sizeof (struct cifsSesInfo),
- GFP_KERNEL);
+ ret_buf = kzalloc(sizeof (struct cifsSesInfo), GFP_KERNEL);
if (ret_buf) {
write_lock(&GlobalSMBSeslock);
atomic_inc(&sesInfoAllocCount);
@@ -109,9 +107,7 @@ struct cifsTconInfo *
tconInfoAlloc(void)
{
struct cifsTconInfo *ret_buf;
- ret_buf =
- (struct cifsTconInfo *) kzalloc(sizeof (struct cifsTconInfo),
- GFP_KERNEL);
+ ret_buf = kzalloc(sizeof (struct cifsTconInfo), GFP_KERNEL);
if (ret_buf) {
write_lock(&GlobalSMBSeslock);
atomic_inc(&tconInfoAllocCount);
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index ed18c3965f7..782940be550 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -68,30 +68,30 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
int rc = 0;
cFYI(1, ("For %s", qstring->name));
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
qstring->hash = full_name_hash(qstring->name, qstring->len);
- tmp_dentry = d_lookup(file->f_dentry, qstring);
+ tmp_dentry = d_lookup(file->f_path.dentry, qstring);
if (tmp_dentry) {
cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode));
*ptmp_inode = tmp_dentry->d_inode;
/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
if(*ptmp_inode == NULL) {
- *ptmp_inode = new_inode(file->f_dentry->d_sb);
+ *ptmp_inode = new_inode(file->f_path.dentry->d_sb);
if(*ptmp_inode == NULL)
return rc;
rc = 1;
}
} else {
- tmp_dentry = d_alloc(file->f_dentry, qstring);
+ tmp_dentry = d_alloc(file->f_path.dentry, qstring);
if(tmp_dentry == NULL) {
cERROR(1,("Failed allocating dentry"));
*ptmp_inode = NULL;
return rc;
}
- *ptmp_inode = new_inode(file->f_dentry->d_sb);
+ *ptmp_inode = new_inode(file->f_path.dentry->d_sb);
if (pTcon->nocase)
tmp_dentry->d_op = &cifs_ci_dentry_ops;
else
@@ -156,9 +156,9 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
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));
+ 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);
@@ -432,10 +432,10 @@ static int initiate_cifs_search(const int xid, struct file *file)
cifsFile->invalidHandle = TRUE;
cifsFile->srch_inf.endOfSearch = FALSE;
- if(file->f_dentry == NULL)
+ if(file->f_path.dentry == NULL)
return -ENOENT;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
if(cifs_sb == NULL)
return -EINVAL;
@@ -443,7 +443,7 @@ static int initiate_cifs_search(const int xid, struct file *file)
if(pTcon == NULL)
return -EINVAL;
- full_path = build_path_from_dentry(file->f_dentry);
+ full_path = build_path_from_dentry(file->f_path.dentry);
if(full_path == NULL) {
return -ENOMEM;
@@ -609,10 +609,10 @@ static int is_dir_changed(struct file * file)
struct inode * inode;
struct cifsInodeInfo *cifsInfo;
- if(file->f_dentry == NULL)
+ if(file->f_path.dentry == NULL)
return 0;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if(inode == NULL)
return 0;
@@ -839,7 +839,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
return -ENOENT;
- if(file->f_dentry == NULL)
+ if(file->f_path.dentry == NULL)
return -ENOENT;
rc = cifs_entry_is_dot(pfindEntry,pCifsF);
@@ -847,7 +847,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
if(rc != 0)
return 0;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
qstring.name = scratch_buf;
rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
@@ -985,12 +985,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
xid = GetXid();
- if(file->f_dentry == NULL) {
+ if(file->f_path.dentry == NULL) {
FreeXid(xid);
return -EIO;
}
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if(pTcon == NULL)
return -EINVAL;
@@ -998,7 +998,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
switch ((int) file->f_pos) {
case 0:
if (filldir(direntry, ".", 1, file->f_pos,
- file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
+ file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) {
cERROR(1, ("Filldir for current dir failed"));
rc = -ENOMEM;
break;
@@ -1006,7 +1006,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
file->f_pos++;
case 1:
if (filldir(direntry, "..", 2, file->f_pos,
- file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
+ file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
cERROR(1, ("Filldir for parent dir failed"));
rc = -ENOMEM;
break;
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index bbdda99dce6..75846463089 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -182,11 +182,14 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
cFYI(1,("bleft %d",bleft));
- /* word align, if bytes remaining is not even */
- if(bleft % 2) {
- bleft--;
- data++;
- }
+ /* SMB header is unaligned, so cifs servers word align start of
+ Unicode strings */
+ data++;
+ bleft--; /* Windows servers do not always double null terminate
+ their final Unicode string - in which case we
+ now will not attempt to decode the byte of junk
+ which follows it */
+
words_left = bleft / 2;
/* save off server operating system */
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
index 7a1b2b961ec..1b1daf63f06 100644
--- a/fs/cifs/smbdes.c
+++ b/fs/cifs/smbdes.c
@@ -196,7 +196,7 @@ dohash(char *out, char *in, char *key, int forw)
char c[28];
char d[28];
char *cd;
- char ki[16][48];
+ char (*ki)[48];
char *pd1;
char l[32], r[32];
char *rl;
@@ -206,6 +206,12 @@ dohash(char *out, char *in, char *key, int forw)
if(pk1 == NULL)
return;
+ ki = kmalloc(16*48, GFP_KERNEL);
+ if(ki == NULL) {
+ kfree(pk1);
+ return;
+ }
+
cd = pk1 + 56;
pd1= cd + 56;
rl = pd1 + 64;
@@ -243,6 +249,7 @@ dohash(char *out, char *in, char *key, int forw)
er = kmalloc(48+48+32+32+32, GFP_KERNEL);
if(er == NULL) {
kfree(pk1);
+ kfree(ki);
return;
}
erk = er+48;
@@ -290,6 +297,7 @@ dohash(char *out, char *in, char *key, int forw)
permute(out, rl, perm6, 64);
kfree(pk1);
+ kfree(ki);
}
static void
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 0102b28a15f..0c6f7f3b3dd 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -441,7 +441,7 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
/* file operations for directories */
int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
{
- struct dentry *coda_dentry = coda_file->f_dentry;
+ struct dentry *coda_dentry = coda_file->f_path.dentry;
struct coda_file_info *cfi;
struct file *host_file;
struct inode *host_inode;
@@ -453,7 +453,7 @@ int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
coda_vfs_stat.readdir++;
- host_inode = host_file->f_dentry->d_inode;
+ host_inode = host_file->f_path.dentry->d_inode;
mutex_lock(&host_inode->i_mutex);
host_file->f_pos = coda_file->f_pos;
@@ -544,14 +544,14 @@ static int coda_venus_readdir(struct file *filp, filldir_t filldir,
/* catch truncated reads */
if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
printk("coda_venus_readdir: short read: %ld\n",
- filp->f_dentry->d_inode->i_ino);
+ filp->f_path.dentry->d_inode->i_ino);
ret = -EBADF;
break;
}
/* validate whether the directory file actually makes sense */
if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
printk("coda_venus_readdir: Invalid dir: %ld\n",
- filp->f_dentry->d_inode->i_ino);
+ filp->f_path.dentry->d_inode->i_ino);
ret = -EBADF;
break;
}
diff --git a/fs/coda/file.c b/fs/coda/file.c
index dbfbcfa5b3c..5ef2b609ec7 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -66,7 +66,7 @@ coda_file_sendfile(struct file *coda_file, loff_t *ppos, size_t count,
static ssize_t
coda_file_write(struct file *coda_file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct inode *host_inode, *coda_inode = coda_file->f_dentry->d_inode;
+ struct inode *host_inode, *coda_inode = coda_file->f_path.dentry->d_inode;
struct coda_file_info *cfi;
struct file *host_file;
ssize_t ret;
@@ -78,7 +78,7 @@ coda_file_write(struct file *coda_file, const char __user *buf, size_t count, lo
if (!host_file->f_op || !host_file->f_op->write)
return -EINVAL;
- host_inode = host_file->f_dentry->d_inode;
+ host_inode = host_file->f_path.dentry->d_inode;
mutex_lock(&coda_inode->i_mutex);
ret = host_file->f_op->write(host_file, buf, count, ppos);
@@ -106,8 +106,8 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
if (!host_file->f_op || !host_file->f_op->mmap)
return -ENODEV;
- coda_inode = coda_file->f_dentry->d_inode;
- host_inode = host_file->f_dentry->d_inode;
+ coda_inode = coda_file->f_path.dentry->d_inode;
+ host_inode = host_file->f_path.dentry->d_inode;
coda_file->f_mapping = host_file->f_mapping;
if (coda_inode->i_mapping == &coda_inode->i_data)
coda_inode->i_mapping = host_inode->i_mapping;
@@ -190,7 +190,7 @@ int coda_flush(struct file *coda_file, fl_owner_t id)
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
- coda_inode = coda_file->f_dentry->d_inode;
+ coda_inode = coda_file->f_path.dentry->d_inode;
err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
coda_file->f_uid);
@@ -233,7 +233,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
coda_flags, coda_file->f_uid);
- host_inode = cfi->cfi_container->f_dentry->d_inode;
+ host_inode = cfi->cfi_container->f_path.dentry->d_inode;
cii = ITOC(coda_inode);
/* did we mmap this file? */
@@ -270,7 +270,7 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
coda_vfs_stat.fsync++;
if (host_file->f_op && host_file->f_op->fsync) {
- host_dentry = host_file->f_dentry;
+ host_dentry = host_file->f_path.dentry;
host_inode = host_dentry->d_inode;
mutex_lock(&host_inode->i_mutex);
err = host_file->f_op->fsync(host_file, host_dentry, datasync);
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index b64659fa82d..01395defed8 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -119,7 +119,7 @@ static int get_device_index(struct coda_mount_data *data)
file = fget(data->fd);
inode = NULL;
if(file)
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if(!inode || !S_ISCHR(inode->i_mode) ||
imajor(inode) != CODA_PSDEV_MAJOR) {
diff --git a/fs/compat.c b/fs/compat.c
index a7e3f162fb1..0ec70e3cee0 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -232,7 +232,7 @@ asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs(file->f_dentry, &tmp);
+ error = vfs_statfs(file->f_path.dentry, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
fput(file);
@@ -303,7 +303,7 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs(file->f_dentry, &tmp);
+ error = vfs_statfs(file->f_path.dentry, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
fput(file);
@@ -365,7 +365,7 @@ static void compat_ioctl_error(struct file *filp, unsigned int fd,
/* find the name of the device. */
path = (char *)__get_free_page(GFP_KERNEL);
if (path) {
- fn = d_path(filp->f_dentry, filp->f_vfsmnt, path, PAGE_SIZE);
+ fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE);
if (IS_ERR(fn))
fn = "?";
}
@@ -416,7 +416,7 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
case FIBMAP:
case FIGETBSZ:
case FIONREAD:
- if (S_ISREG(filp->f_dentry->d_inode->i_mode))
+ if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
break;
/*FALL THROUGH*/
@@ -438,7 +438,7 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
goto found_handler;
}
- if (S_ISSOCK(filp->f_dentry->d_inode->i_mode) &&
+ if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) &&
cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
error = siocdevprivate_ioctl(fd, cmd, arg);
} else {
@@ -1259,7 +1259,7 @@ out:
if (iov != iovstack)
kfree(iov);
if ((ret + (type == READ)) > 0) {
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
if (type == READ)
fsnotify_access(dentry);
else
@@ -1679,19 +1679,19 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
{
fd_set_bits fds;
char *bits;
- int size, max_fdset, ret = -EINVAL;
+ int size, max_fds, ret = -EINVAL;
struct fdtable *fdt;
if (n < 0)
goto out_nofds;
- /* max_fdset can increase, so grab it once to avoid race */
+ /* max_fds can increase, so grab it once to avoid race */
rcu_read_lock();
fdt = files_fdtable(current->files);
- max_fdset = fdt->max_fdset;
+ max_fds = fdt->max_fds;
rcu_read_unlock();
- if (n > max_fdset)
- n = max_fdset;
+ if (n > max_fds)
+ n = max_fds;
/*
* We need 6 bitmaps (in/out/ex for both incoming and outgoing),
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index bcc3caf5d82..c81c958b3e1 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1177,7 +1177,7 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long ar
static int vt_check(struct file *file)
{
struct tty_struct *tty;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
if (file->f_op->ioctl != tty_ioctl)
return -EINVAL;
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index c398861f78a..1814ba44680 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -980,7 +980,7 @@ int configfs_rename_dir(struct config_item * item, const char *new_name)
static int configfs_dir_open(struct inode *inode, struct file *file)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
struct configfs_dirent * parent_sd = dentry->d_fsdata;
mutex_lock(&dentry->d_inode->i_mutex);
@@ -993,7 +993,7 @@ static int configfs_dir_open(struct inode *inode, struct file *file)
static int configfs_dir_close(struct inode *inode, struct file *file)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
struct configfs_dirent * cursor = file->private_data;
mutex_lock(&dentry->d_inode->i_mutex);
@@ -1013,7 +1013,7 @@ static inline unsigned char dt_type(struct configfs_dirent *sd)
static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct configfs_dirent * parent_sd = dentry->d_fsdata;
struct configfs_dirent *cursor = filp->private_data;
struct list_head *p, *q = &cursor->s_sibling;
@@ -1070,7 +1070,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
static loff_t configfs_dir_lseek(struct file * file, loff_t offset, int origin)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
mutex_lock(&dentry->d_inode->i_mutex);
switch (origin) {
@@ -1080,7 +1080,7 @@ static loff_t configfs_dir_lseek(struct file * file, loff_t offset, int origin)
if (offset >= 0)
break;
default:
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return -EINVAL;
}
if (offset != file->f_pos) {
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index cf33fac68c8..d98be5e0132 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -134,7 +134,7 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp
down(&buffer->sem);
if (buffer->needs_read_fill) {
- if ((retval = fill_read_buffer(file->f_dentry,buffer)))
+ if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
goto out;
}
pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
@@ -162,14 +162,17 @@ fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size
int error;
if (!buffer->page)
- buffer->page = (char *)get_zeroed_page(GFP_KERNEL);
+ buffer->page = (char *)__get_free_pages(GFP_KERNEL, 0);
if (!buffer->page)
return -ENOMEM;
- if (count > PAGE_SIZE)
- count = PAGE_SIZE;
+ if (count >= PAGE_SIZE)
+ count = PAGE_SIZE - 1;
error = copy_from_user(buffer->page,buf,count);
buffer->needs_read_fill = 1;
+ /* if buf is assumed to contain a string, terminate it by \0,
+ * so e.g. sscanf() can scan the string easily */
+ buffer->page[count] = 0;
return error ? -EFAULT : count;
}
@@ -222,7 +225,7 @@ configfs_write_file(struct file *file, const char __user *buf, size_t count, lof
down(&buffer->sem);
len = fill_write_buffer(buffer, buf, count);
if (len > 0)
- len = flush_write_buffer(file->f_dentry, buffer, count);
+ len = flush_write_buffer(file->f_path.dentry, buffer, count);
if (len > 0)
*ppos += len;
up(&buffer->sem);
@@ -231,8 +234,8 @@ configfs_write_file(struct file *file, const char __user *buf, size_t count, lof
static int check_perm(struct inode * inode, struct file * file)
{
- struct config_item *item = configfs_get_config_item(file->f_dentry->d_parent);
- struct configfs_attribute * attr = to_attr(file->f_dentry);
+ struct config_item *item = configfs_get_config_item(file->f_path.dentry->d_parent);
+ struct configfs_attribute * attr = to_attr(file->f_path.dentry);
struct configfs_buffer * buffer;
struct configfs_item_operations * ops = NULL;
int error = 0;
@@ -305,8 +308,8 @@ static int configfs_open_file(struct inode * inode, struct file * filp)
static int configfs_release(struct inode * inode, struct file * filp)
{
- struct config_item * item = to_item(filp->f_dentry->d_parent);
- struct configfs_attribute * attr = to_attr(filp->f_dentry);
+ struct config_item * item = to_item(filp->f_path.dentry->d_parent);
+ struct configfs_attribute * attr = to_attr(filp->f_path.dentry);
struct module * owner = attr->ca_owner;
struct configfs_buffer * buffer = filp->private_data;
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 0509cedd415..6db03fb089d 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -338,7 +338,7 @@ static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)
*/
static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
char *buf;
unsigned int offset;
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 137d76c3f90..c692487346e 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -24,6 +24,7 @@
#include <linux/kobject.h>
#include <linux/namei.h>
#include <linux/debugfs.h>
+#include <linux/fsnotify.h>
#define DEBUGFS_MAGIC 0x64626720
@@ -54,7 +55,8 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
- /* directory inodes start off with i_nlink == 2 (for "." entry) */
+ /* directory inodes start off with i_nlink == 2
+ * (for "." entry) */
inc_nlink(inode);
break;
}
@@ -87,15 +89,22 @@ 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)
+ if (!res) {
inc_nlink(dir);
+ fsnotify_mkdir(dir, dentry);
+ }
return res;
}
static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode)
{
+ int res;
+
mode = (mode & S_IALLUGO) | S_IFREG;
- return debugfs_mknod(dir, dentry, mode, 0);
+ res = debugfs_mknod(dir, dentry, mode, 0);
+ if (!res)
+ fsnotify_create(dir, dentry);
+ return res;
}
static inline int debugfs_positive(struct dentry *dentry)
@@ -135,7 +144,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode,
* block. A pointer to that is in the struct vfsmount that we
* have around.
*/
- if (!parent ) {
+ if (!parent) {
if (debugfs_mount && debugfs_mount->mnt_sb) {
parent = debugfs_mount->mnt_sb->s_root;
}
@@ -153,6 +162,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode,
error = debugfs_mkdir(parent->d_inode, *dentry, mode);
else
error = debugfs_create(parent->d_inode, *dentry, mode);
+ dput(*dentry);
} else
error = PTR_ERR(*dentry);
mutex_unlock(&parent->d_inode->i_mutex);
@@ -197,13 +207,15 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode,
pr_debug("debugfs: creating file '%s'\n",name);
- error = simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count);
+ error = simple_pin_fs(&debug_fs_type, &debugfs_mount,
+ &debugfs_mount_count);
if (error)
goto exit;
error = debugfs_create_by_name(name, mode, parent, &dentry);
if (error) {
dentry = NULL;
+ simple_release_fs(&debugfs_mount, &debugfs_mount_count);
goto exit;
}
@@ -262,6 +274,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_dir);
void debugfs_remove(struct dentry *dentry)
{
struct dentry *parent;
+ int ret = 0;
if (!dentry)
return;
@@ -273,11 +286,19 @@ void debugfs_remove(struct dentry *dentry)
mutex_lock(&parent->d_inode->i_mutex);
if (debugfs_positive(dentry)) {
if (dentry->d_inode) {
- if (S_ISDIR(dentry->d_inode->i_mode))
- simple_rmdir(parent->d_inode, dentry);
- else
+ dget(dentry);
+ if (S_ISDIR(dentry->d_inode->i_mode)) {
+ ret = simple_rmdir(parent->d_inode, dentry);
+ if (ret)
+ printk(KERN_ERR
+ "DebugFS rmdir on %s failed : "
+ "directory not empty.\n",
+ dentry->d_name.name);
+ } else
simple_unlink(parent->d_inode, dentry);
- dput(dentry);
+ if (!ret)
+ d_delete(dentry);
+ dput(dentry);
}
}
mutex_unlock(&parent->d_inode->i_mutex);
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 5981e17f46f..d9d0833444f 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
+#include <linux/task_io_accounting_ops.h>
#include <linux/bio.h>
#include <linux/wait.h>
#include <linux/err.h>
@@ -121,8 +122,7 @@ struct dio {
/* BIO completion state */
spinlock_t bio_lock; /* protects BIO fields below */
- int bio_count; /* nr bios to be completed */
- int bios_in_flight; /* nr bios in flight */
+ unsigned long refcount; /* direct_io_worker() and bios */
struct bio *bio_list; /* singly linked via bi_private */
struct task_struct *waiter; /* waiting task (NULL if none) */
@@ -209,76 +209,55 @@ static struct page *dio_get_page(struct dio *dio)
return dio->pages[dio->head++];
}
-/*
- * Called when all DIO BIO I/O has been completed - let the filesystem
- * know, if it registered an interest earlier via get_block. Pass the
- * private field of the map buffer_head so that filesystems can use it
- * to hold additional state between get_block calls and dio_complete.
- */
-static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes)
-{
- if (dio->end_io && dio->result)
- dio->end_io(dio->iocb, offset, bytes, dio->map_bh.b_private);
- if (dio->lock_type == DIO_LOCKING)
- /* lockdep: non-owner release */
- up_read_non_owner(&dio->inode->i_alloc_sem);
-}
-
-/*
- * Called when a BIO has been processed. If the count goes to zero then IO is
- * complete and we can signal this to the AIO layer.
+/**
+ * dio_complete() - called when all DIO BIO I/O has been completed
+ * @offset: the byte offset in the file of the completed operation
+ *
+ * This releases locks as dictated by the locking type, lets interested parties
+ * know that a DIO operation has completed, and calculates the resulting return
+ * code for the operation.
+ *
+ * It lets the filesystem know if it registered an interest earlier via
+ * get_block. Pass the private field of the map buffer_head so that
+ * filesystems can use it to hold additional state between get_block calls and
+ * dio_complete.
*/
-static void finished_one_bio(struct dio *dio)
+static int dio_complete(struct dio *dio, loff_t offset, int ret)
{
- unsigned long flags;
+ ssize_t transferred = 0;
- spin_lock_irqsave(&dio->bio_lock, flags);
- if (dio->bio_count == 1) {
- if (dio->is_async) {
- ssize_t transferred;
- loff_t offset;
-
- /*
- * Last reference to the dio is going away.
- * Drop spinlock and complete the DIO.
- */
- spin_unlock_irqrestore(&dio->bio_lock, flags);
+ /*
+ * AIO submission can race with bio completion to get here while
+ * expecting to have the last io completed by bio completion.
+ * In that case -EIOCBQUEUED is in fact not an error we want
+ * to preserve through this call.
+ */
+ if (ret == -EIOCBQUEUED)
+ ret = 0;
- /* Check for short read case */
- transferred = dio->result;
- offset = dio->iocb->ki_pos;
+ if (dio->result) {
+ transferred = dio->result;
- if ((dio->rw == READ) &&
- ((offset + transferred) > dio->i_size))
- transferred = dio->i_size - offset;
+ /* Check for short read case */
+ if ((dio->rw == READ) && ((offset + transferred) > dio->i_size))
+ transferred = dio->i_size - offset;
+ }
- /* check for error in completion path */
- if (dio->io_error)
- transferred = dio->io_error;
+ if (dio->end_io && dio->result)
+ dio->end_io(dio->iocb, offset, transferred,
+ dio->map_bh.b_private);
+ if (dio->lock_type == DIO_LOCKING)
+ /* lockdep: non-owner release */
+ up_read_non_owner(&dio->inode->i_alloc_sem);
- dio_complete(dio, offset, transferred);
+ if (ret == 0)
+ ret = dio->page_errors;
+ if (ret == 0)
+ ret = dio->io_error;
+ if (ret == 0)
+ ret = transferred;
- /* Complete AIO later if falling back to buffered i/o */
- if (dio->result == dio->size ||
- ((dio->rw == READ) && dio->result)) {
- aio_complete(dio->iocb, transferred, 0);
- kfree(dio);
- return;
- } else {
- /*
- * Falling back to buffered
- */
- spin_lock_irqsave(&dio->bio_lock, flags);
- dio->bio_count--;
- if (dio->waiter)
- wake_up_process(dio->waiter);
- spin_unlock_irqrestore(&dio->bio_lock, flags);
- return;
- }
- }
- }
- dio->bio_count--;
- spin_unlock_irqrestore(&dio->bio_lock, flags);
+ return ret;
}
static int dio_bio_complete(struct dio *dio, struct bio *bio);
@@ -288,12 +267,27 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio);
static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error)
{
struct dio *dio = bio->bi_private;
+ unsigned long remaining;
+ unsigned long flags;
if (bio->bi_size)
return 1;
/* cleanup the bio */
dio_bio_complete(dio, bio);
+
+ spin_lock_irqsave(&dio->bio_lock, flags);
+ remaining = --dio->refcount;
+ if (remaining == 1 && dio->waiter)
+ wake_up_process(dio->waiter);
+ spin_unlock_irqrestore(&dio->bio_lock, flags);
+
+ if (remaining == 0) {
+ int ret = dio_complete(dio, dio->iocb->ki_pos, 0);
+ aio_complete(dio->iocb, ret, 0);
+ kfree(dio);
+ }
+
return 0;
}
@@ -315,8 +309,7 @@ static int dio_bio_end_io(struct bio *bio, unsigned int bytes_done, int error)
spin_lock_irqsave(&dio->bio_lock, flags);
bio->bi_private = dio->bio_list;
dio->bio_list = bio;
- dio->bios_in_flight--;
- if (dio->waiter && dio->bios_in_flight == 0)
+ if (--dio->refcount == 1 && dio->waiter)
wake_up_process(dio->waiter);
spin_unlock_irqrestore(&dio->bio_lock, flags);
return 0;
@@ -347,6 +340,8 @@ dio_bio_alloc(struct dio *dio, struct block_device *bdev,
* In the AIO read case we speculatively dirty the pages before starting IO.
* During IO completion, any of these pages which happen to have been written
* back will be redirtied by bio_check_pages_dirty().
+ *
+ * bios hold a dio reference between submit_bio and ->end_io.
*/
static void dio_bio_submit(struct dio *dio)
{
@@ -354,12 +349,14 @@ static void dio_bio_submit(struct dio *dio)
unsigned long flags;
bio->bi_private = dio;
+
spin_lock_irqsave(&dio->bio_lock, flags);
- dio->bio_count++;
- dio->bios_in_flight++;
+ dio->refcount++;
spin_unlock_irqrestore(&dio->bio_lock, flags);
+
if (dio->is_async && dio->rw == READ)
bio_set_pages_dirty(bio);
+
submit_bio(dio->rw, bio);
dio->bio = NULL;
@@ -376,28 +373,37 @@ static void dio_cleanup(struct dio *dio)
}
/*
- * Wait for the next BIO to complete. Remove it and return it.
+ * Wait for the next BIO to complete. Remove it and return it. NULL is
+ * returned once all BIOs have been completed. This must only be called once
+ * all bios have been issued so that dio->refcount can only decrease. This
+ * requires that that the caller hold a reference on the dio.
*/
static struct bio *dio_await_one(struct dio *dio)
{
unsigned long flags;
- struct bio *bio;
+ struct bio *bio = NULL;
spin_lock_irqsave(&dio->bio_lock, flags);
- while (dio->bio_list == NULL) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- if (dio->bio_list == NULL) {
- dio->waiter = current;
- spin_unlock_irqrestore(&dio->bio_lock, flags);
- blk_run_address_space(dio->inode->i_mapping);
- io_schedule();
- spin_lock_irqsave(&dio->bio_lock, flags);
- dio->waiter = NULL;
- }
- set_current_state(TASK_RUNNING);
+
+ /*
+ * Wait as long as the list is empty and there are bios in flight. bio
+ * completion drops the count, maybe adds to the list, and wakes while
+ * holding the bio_lock so we don't need set_current_state()'s barrier
+ * and can call it after testing our condition.
+ */
+ while (dio->refcount > 1 && dio->bio_list == NULL) {
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ dio->waiter = current;
+ spin_unlock_irqrestore(&dio->bio_lock, flags);
+ io_schedule();
+ /* wake up sets us TASK_RUNNING */
+ spin_lock_irqsave(&dio->bio_lock, flags);
+ dio->waiter = NULL;
+ }
+ if (dio->bio_list) {
+ bio = dio->bio_list;
+ dio->bio_list = bio->bi_private;
}
- bio = dio->bio_list;
- dio->bio_list = bio->bi_private;
spin_unlock_irqrestore(&dio->bio_lock, flags);
return bio;
}
@@ -426,34 +432,24 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio)
}
bio_put(bio);
}
- finished_one_bio(dio);
return uptodate ? 0 : -EIO;
}
/*
- * Wait on and process all in-flight BIOs.
+ * Wait on and process all in-flight BIOs. This must only be called once
+ * all bios have been issued so that the refcount can only decrease.
+ * This just waits for all bios to make it through dio_bio_complete. IO
+ * errors are propogated through dio->io_error and should be propogated via
+ * dio_complete().
*/
-static int dio_await_completion(struct dio *dio)
+static void dio_await_completion(struct dio *dio)
{
- int ret = 0;
-
- if (dio->bio)
- dio_bio_submit(dio);
-
- /*
- * The bio_lock is not held for the read of bio_count.
- * This is ok since it is the dio_bio_complete() that changes
- * bio_count.
- */
- while (dio->bio_count) {
- struct bio *bio = dio_await_one(dio);
- int ret2;
-
- ret2 = dio_bio_complete(dio, bio);
- if (ret == 0)
- ret = ret2;
- }
- return ret;
+ struct bio *bio;
+ do {
+ bio = dio_await_one(dio);
+ if (bio)
+ dio_bio_complete(dio, bio);
+ } while (bio);
}
/*
@@ -675,6 +671,13 @@ submit_page_section(struct dio *dio, struct page *page,
{
int ret = 0;
+ if (dio->rw & WRITE) {
+ /*
+ * Read accounting is performed in submit_bio()
+ */
+ task_io_account_write(len);
+ }
+
/*
* Can we just grow the current page's presence in the dio?
*/
@@ -953,6 +956,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
struct dio *dio)
{
unsigned long user_addr;
+ unsigned long flags;
int seg;
ssize_t ret = 0;
ssize_t ret2;
@@ -983,17 +987,8 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
dio->iocb = iocb;
dio->i_size = i_size_read(inode);
- /*
- * BIO completion state.
- *
- * ->bio_count starts out at one, and we decrement it to zero after all
- * BIOs are submitted. This to avoid the situation where a really fast
- * (or synchronous) device could take the count to zero while we're
- * still submitting BIOs.
- */
- dio->bio_count = 1;
- dio->bios_in_flight = 0;
spin_lock_init(&dio->bio_lock);
+ dio->refcount = 1;
dio->bio_list = NULL;
dio->waiter = NULL;
@@ -1069,6 +1064,9 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
if (dio->bio)
dio_bio_submit(dio);
+ /* All IO is now issued, send it on its way */
+ blk_run_address_space(inode->i_mapping);
+
/*
* It is possible that, we return short IO due to end of file.
* In that case, we need to release all the pages we got hold on.
@@ -1084,74 +1082,41 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
mutex_unlock(&dio->inode->i_mutex);
/*
- * OK, all BIOs are submitted, so we can decrement bio_count to truly
- * reflect the number of to-be-processed BIOs.
+ * The only time we want to leave bios in flight is when a successful
+ * partial aio read or full aio write have been setup. In that case
+ * bio completion will call aio_complete. The only time it's safe to
+ * call aio_complete is when we return -EIOCBQUEUED, so we key on that.
+ * This had *better* be the only place that raises -EIOCBQUEUED.
*/
- if (dio->is_async) {
- int should_wait = 0;
+ BUG_ON(ret == -EIOCBQUEUED);
+ if (dio->is_async && ret == 0 && dio->result &&
+ ((rw & READ) || (dio->result == dio->size)))
+ ret = -EIOCBQUEUED;
- if (dio->result < dio->size && (rw & WRITE)) {
- dio->waiter = current;
- should_wait = 1;
- }
- if (ret == 0)
- ret = dio->result;
- finished_one_bio(dio); /* This can free the dio */
- blk_run_address_space(inode->i_mapping);
- if (should_wait) {
- unsigned long flags;
- /*
- * Wait for already issued I/O to drain out and
- * release its references to user-space pages
- * before returning to fallback on buffered I/O
- */
-
- spin_lock_irqsave(&dio->bio_lock, flags);
- set_current_state(TASK_UNINTERRUPTIBLE);
- while (dio->bio_count) {
- spin_unlock_irqrestore(&dio->bio_lock, flags);
- io_schedule();
- spin_lock_irqsave(&dio->bio_lock, flags);
- set_current_state(TASK_UNINTERRUPTIBLE);
- }
- spin_unlock_irqrestore(&dio->bio_lock, flags);
- set_current_state(TASK_RUNNING);
- kfree(dio);
- }
- } else {
- ssize_t transferred = 0;
-
- finished_one_bio(dio);
- ret2 = dio_await_completion(dio);
- if (ret == 0)
- ret = ret2;
- if (ret == 0)
- ret = dio->page_errors;
- if (dio->result) {
- loff_t i_size = i_size_read(inode);
-
- transferred = dio->result;
- /*
- * Adjust the return value if the read crossed a
- * non-block-aligned EOF.
- */
- if (rw == READ && (offset + transferred > i_size))
- transferred = i_size - offset;
- }
- dio_complete(dio, offset, transferred);
- if (ret == 0)
- ret = transferred;
+ if (ret != -EIOCBQUEUED)
+ dio_await_completion(dio);
- /* We could have also come here on an AIO file extend */
- if (!is_sync_kiocb(iocb) && (rw & WRITE) &&
- ret >= 0 && dio->result == dio->size)
- /*
- * For AIO writes where we have completed the
- * i/o, we have to mark the the aio complete.
- */
- aio_complete(iocb, ret, 0);
+ /*
+ * Sync will always be dropping the final ref and completing the
+ * operation. AIO can if it was a broken operation described above or
+ * in fact if all the bios race to complete before we get here. In
+ * that case dio_complete() translates the EIOCBQUEUED into the proper
+ * return code that the caller will hand to aio_complete().
+ *
+ * This is managed by the bio_lock instead of being an atomic_t so that
+ * completion paths can drop their ref and use the remaining count to
+ * decide to wake the submission path atomically.
+ */
+ spin_lock_irqsave(&dio->bio_lock, flags);
+ ret2 = --dio->refcount;
+ spin_unlock_irqrestore(&dio->bio_lock, flags);
+ BUG_ON(!dio->is_async && ret2 != 0);
+ if (ret2 == 0) {
+ ret = dio_complete(dio, offset, ret);
kfree(dio);
- }
+ } else
+ BUG_ON(ret != -EIOCBQUEUED);
+
return ret;
}
diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig
index b5654a284fe..6fa7b0d5c04 100644
--- a/fs/dlm/Kconfig
+++ b/fs/dlm/Kconfig
@@ -3,21 +3,21 @@ menu "Distributed Lock Manager"
config DLM
tristate "Distributed Lock Manager (DLM)"
- depends on IPV6 || IPV6=n
+ depends on SYSFS && (IPV6 || IPV6=n)
select CONFIGFS_FS
select IP_SCTP if DLM_SCTP
help
- A general purpose distributed lock manager for kernel or userspace
- applications.
+ A general purpose distributed lock manager for kernel or userspace
+ applications.
choice
prompt "Select DLM communications protocol"
depends on DLM
default DLM_TCP
help
- The DLM Can use TCP or SCTP for it's network communications.
- SCTP supports multi-homed operations whereas TCP doesn't.
- However, SCTP seems to have stability problems at the moment.
+ The DLM Can use TCP or SCTP for it's network communications.
+ SCTP supports multi-homed operations whereas TCP doesn't.
+ However, SCTP seems to have stability problems at the moment.
config DLM_TCP
bool "TCP/IP"
@@ -31,8 +31,8 @@ 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.
+ 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/config.c b/fs/dlm/config.c
index 88553054bbf..8665c88e5af 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -54,6 +54,11 @@ 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_cluster(struct config_item *i, struct configfs_attribute *a,
+ char *buf);
+static ssize_t store_cluster(struct config_item *i,
+ struct configfs_attribute *a,
+ const char *buf, size_t len);
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,
@@ -73,6 +78,101 @@ 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);
+struct cluster {
+ struct config_group group;
+ unsigned int cl_tcp_port;
+ unsigned int cl_buffer_size;
+ unsigned int cl_rsbtbl_size;
+ unsigned int cl_lkbtbl_size;
+ unsigned int cl_dirtbl_size;
+ unsigned int cl_recover_timer;
+ unsigned int cl_toss_secs;
+ unsigned int cl_scan_secs;
+ unsigned int cl_log_debug;
+};
+
+enum {
+ CLUSTER_ATTR_TCP_PORT = 0,
+ CLUSTER_ATTR_BUFFER_SIZE,
+ CLUSTER_ATTR_RSBTBL_SIZE,
+ CLUSTER_ATTR_LKBTBL_SIZE,
+ CLUSTER_ATTR_DIRTBL_SIZE,
+ CLUSTER_ATTR_RECOVER_TIMER,
+ CLUSTER_ATTR_TOSS_SECS,
+ CLUSTER_ATTR_SCAN_SECS,
+ CLUSTER_ATTR_LOG_DEBUG,
+};
+
+struct cluster_attribute {
+ struct configfs_attribute attr;
+ ssize_t (*show)(struct cluster *, char *);
+ ssize_t (*store)(struct cluster *, const char *, size_t);
+};
+
+static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field,
+ unsigned int *info_field, int check_zero,
+ const char *buf, size_t len)
+{
+ unsigned int x;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ x = simple_strtoul(buf, NULL, 0);
+
+ if (check_zero && !x)
+ return -EINVAL;
+
+ *cl_field = x;
+ *info_field = x;
+
+ return len;
+}
+
+#define __CONFIGFS_ATTR(_name,_mode,_read,_write) { \
+ .attr = { .ca_name = __stringify(_name), \
+ .ca_mode = _mode, \
+ .ca_owner = THIS_MODULE }, \
+ .show = _read, \
+ .store = _write, \
+}
+
+#define CLUSTER_ATTR(name, check_zero) \
+static ssize_t name##_write(struct cluster *cl, const char *buf, size_t len) \
+{ \
+ return cluster_set(cl, &cl->cl_##name, &dlm_config.ci_##name, \
+ check_zero, buf, len); \
+} \
+static ssize_t name##_read(struct cluster *cl, char *buf) \
+{ \
+ return snprintf(buf, PAGE_SIZE, "%u\n", cl->cl_##name); \
+} \
+static struct cluster_attribute cluster_attr_##name = \
+__CONFIGFS_ATTR(name, 0644, name##_read, name##_write)
+
+CLUSTER_ATTR(tcp_port, 1);
+CLUSTER_ATTR(buffer_size, 1);
+CLUSTER_ATTR(rsbtbl_size, 1);
+CLUSTER_ATTR(lkbtbl_size, 1);
+CLUSTER_ATTR(dirtbl_size, 1);
+CLUSTER_ATTR(recover_timer, 1);
+CLUSTER_ATTR(toss_secs, 1);
+CLUSTER_ATTR(scan_secs, 1);
+CLUSTER_ATTR(log_debug, 0);
+
+static struct configfs_attribute *cluster_attrs[] = {
+ [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
+ [CLUSTER_ATTR_BUFFER_SIZE] = &cluster_attr_buffer_size.attr,
+ [CLUSTER_ATTR_RSBTBL_SIZE] = &cluster_attr_rsbtbl_size.attr,
+ [CLUSTER_ATTR_LKBTBL_SIZE] = &cluster_attr_lkbtbl_size.attr,
+ [CLUSTER_ATTR_DIRTBL_SIZE] = &cluster_attr_dirtbl_size.attr,
+ [CLUSTER_ATTR_RECOVER_TIMER] = &cluster_attr_recover_timer.attr,
+ [CLUSTER_ATTR_TOSS_SECS] = &cluster_attr_toss_secs.attr,
+ [CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr,
+ [CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr,
+ NULL,
+};
+
enum {
COMM_ATTR_NODEID = 0,
COMM_ATTR_LOCAL,
@@ -152,10 +252,6 @@ struct clusters {
struct configfs_subsystem subsys;
};
-struct cluster {
- struct config_group group;
-};
-
struct spaces {
struct config_group ss_group;
};
@@ -197,6 +293,8 @@ static struct configfs_group_operations clusters_ops = {
static struct configfs_item_operations cluster_ops = {
.release = release_cluster,
+ .show_attribute = show_cluster,
+ .store_attribute = store_cluster,
};
static struct configfs_group_operations spaces_ops = {
@@ -237,6 +335,7 @@ static struct config_item_type clusters_type = {
static struct config_item_type cluster_type = {
.ct_item_ops = &cluster_ops,
+ .ct_attrs = cluster_attrs,
.ct_owner = THIS_MODULE,
};
@@ -317,6 +416,16 @@ static struct config_group *make_cluster(struct config_group *g,
cl->group.default_groups[1] = &cms->cs_group;
cl->group.default_groups[2] = NULL;
+ cl->cl_tcp_port = dlm_config.ci_tcp_port;
+ cl->cl_buffer_size = dlm_config.ci_buffer_size;
+ cl->cl_rsbtbl_size = dlm_config.ci_rsbtbl_size;
+ cl->cl_lkbtbl_size = dlm_config.ci_lkbtbl_size;
+ cl->cl_dirtbl_size = dlm_config.ci_dirtbl_size;
+ cl->cl_recover_timer = dlm_config.ci_recover_timer;
+ cl->cl_toss_secs = dlm_config.ci_toss_secs;
+ cl->cl_scan_secs = dlm_config.ci_scan_secs;
+ cl->cl_log_debug = dlm_config.ci_log_debug;
+
space_list = &sps->ss_group;
comm_list = &cms->cs_group;
return &cl->group;
@@ -509,6 +618,25 @@ void dlm_config_exit(void)
* Functions for user space to read/write attributes
*/
+static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a,
+ char *buf)
+{
+ struct cluster *cl = to_cluster(i);
+ struct cluster_attribute *cla =
+ container_of(a, struct cluster_attribute, attr);
+ return cla->show ? cla->show(cl, buf) : 0;
+}
+
+static ssize_t store_cluster(struct config_item *i,
+ struct configfs_attribute *a,
+ const char *buf, size_t len)
+{
+ struct cluster *cl = to_cluster(i);
+ struct cluster_attribute *cla =
+ container_of(a, struct cluster_attribute, attr);
+ return cla->store ? cla->store(cl, buf, len) : -EINVAL;
+}
+
static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
char *buf)
{
@@ -775,15 +903,17 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
#define DEFAULT_RECOVER_TIMER 5
#define DEFAULT_TOSS_SECS 10
#define DEFAULT_SCAN_SECS 5
+#define DEFAULT_LOG_DEBUG 0
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
+ .ci_tcp_port = DEFAULT_TCP_PORT,
+ .ci_buffer_size = DEFAULT_BUFFER_SIZE,
+ .ci_rsbtbl_size = DEFAULT_RSBTBL_SIZE,
+ .ci_lkbtbl_size = DEFAULT_LKBTBL_SIZE,
+ .ci_dirtbl_size = DEFAULT_DIRTBL_SIZE,
+ .ci_recover_timer = DEFAULT_RECOVER_TIMER,
+ .ci_toss_secs = DEFAULT_TOSS_SECS,
+ .ci_scan_secs = DEFAULT_SCAN_SECS,
+ .ci_log_debug = DEFAULT_LOG_DEBUG
};
diff --git a/fs/dlm/config.h b/fs/dlm/config.h
index 9da7839958a..1e978611a96 100644
--- a/fs/dlm/config.h
+++ b/fs/dlm/config.h
@@ -17,14 +17,15 @@
#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;
+ int ci_tcp_port;
+ int ci_buffer_size;
+ int ci_rsbtbl_size;
+ int ci_lkbtbl_size;
+ int ci_dirtbl_size;
+ int ci_recover_timer;
+ int ci_toss_secs;
+ int ci_scan_secs;
+ int ci_log_debug;
};
extern struct dlm_config_info dlm_config;
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 1ee8195e6fc..61d93201e1b 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -41,6 +41,7 @@
#include <asm/uaccess.h>
#include <linux/dlm.h>
+#include "config.h"
#define DLM_LOCKSPACE_LEN 64
@@ -69,12 +70,12 @@ struct dlm_mhandle;
#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 log_debug(ls, fmt, args...) \
+do { \
+ if (dlm_config.ci_log_debug) \
+ printk(KERN_DEBUG "dlm: %s: " fmt "\n", \
+ (ls)->ls_name , ##args); \
+} while (0)
#define DLM_ASSERT(x, do) \
{ \
@@ -309,8 +310,8 @@ static inline int rsb_flag(struct dlm_rsb *r, enum rsb_flags flag)
/* dlm_header is first element of all structs sent between nodes */
-#define DLM_HEADER_MAJOR 0x00020000
-#define DLM_HEADER_MINOR 0x00000001
+#define DLM_HEADER_MAJOR 0x00030000
+#define DLM_HEADER_MINOR 0x00000000
#define DLM_MSG 1
#define DLM_RCOM 2
@@ -386,6 +387,8 @@ struct dlm_rcom {
uint32_t rc_type; /* DLM_RCOM_ */
int rc_result; /* multi-purpose */
uint64_t rc_id; /* match reply with request */
+ uint64_t rc_seq; /* sender's ls_recover_seq */
+ uint64_t rc_seq_reply; /* remote ls_recover_seq */
char rc_buf[0];
};
@@ -523,6 +526,7 @@ struct dlm_user_proc {
spinlock_t asts_spin;
struct list_head locks;
spinlock_t locks_spin;
+ struct list_head unlocking;
wait_queue_head_t wait;
};
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 30878defaeb..e725005fafd 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -754,6 +754,11 @@ static void add_to_waiters(struct dlm_lkb *lkb, int mstype)
mutex_unlock(&ls->ls_waiters_mutex);
}
+/* We clear the RESEND flag because we might be taking an lkb off the waiters
+ list as part of process_requestqueue (e.g. a lookup that has an optimized
+ request reply on the requestqueue) between dlm_recover_waiters_pre() which
+ set RESEND and dlm_recover_waiters_post() */
+
static int _remove_from_waiters(struct dlm_lkb *lkb)
{
int error = 0;
@@ -764,6 +769,7 @@ static int _remove_from_waiters(struct dlm_lkb *lkb)
goto out;
}
lkb->lkb_wait_type = 0;
+ lkb->lkb_flags &= ~DLM_IFL_RESEND;
list_del(&lkb->lkb_wait_reply);
unhold_lkb(lkb);
out:
@@ -810,7 +816,7 @@ static int shrink_bucket(struct dlm_ls *ls, int b)
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))
+ dlm_config.ci_toss_secs * HZ))
continue;
found = 1;
break;
@@ -2144,12 +2150,24 @@ static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb,
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);
+ /* compare with switch in create_message; send_remove() doesn't
+ use send_args() */
- else if (lkb->lkb_lvbptr)
+ switch (ms->m_type) {
+ case DLM_MSG_REQUEST:
+ case DLM_MSG_LOOKUP:
+ memcpy(ms->m_extra, r->res_name, 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_lvbptr)
+ break;
memcpy(ms->m_extra, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
-
+ break;
+ }
}
static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
@@ -2418,8 +2436,12 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb););
- if (receive_lvb(ls, lkb, ms))
- return -ENOMEM;
+ if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
+ /* lkb was just created so there won't be an lvb yet */
+ lkb->lkb_lvbptr = allocate_lvb(ls);
+ if (!lkb->lkb_lvbptr)
+ return -ENOMEM;
+ }
return 0;
}
@@ -3002,7 +3024,7 @@ 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;
+ int error = 0;
if (!recovery)
dlm_message_in(ms);
@@ -3119,7 +3141,7 @@ int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
out:
dlm_put_lockspace(ls);
dlm_astd_wake();
- return 0;
+ return error;
}
@@ -3132,6 +3154,7 @@ 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;
+ ls->ls_stub_ms.m_flags = lkb->lkb_flags;
_remove_from_waiters(lkb);
_receive_convert_reply(lkb, &ls->ls_stub_ms);
@@ -3205,6 +3228,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
case DLM_MSG_UNLOCK:
hold_lkb(lkb);
ls->ls_stub_ms.m_result = -DLM_EUNLOCK;
+ ls->ls_stub_ms.m_flags = lkb->lkb_flags;
_remove_from_waiters(lkb);
_receive_unlock_reply(lkb, &ls->ls_stub_ms);
dlm_put_lkb(lkb);
@@ -3213,6 +3237,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
case DLM_MSG_CANCEL:
hold_lkb(lkb);
ls->ls_stub_ms.m_result = -DLM_ECANCEL;
+ ls->ls_stub_ms.m_flags = lkb->lkb_flags;
_remove_from_waiters(lkb);
_receive_cancel_reply(lkb, &ls->ls_stub_ms);
dlm_put_lkb(lkb);
@@ -3571,6 +3596,14 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
lock_rsb(r);
switch (error) {
+ case -EBADR:
+ /* There's a chance the new master received our lock before
+ dlm_recover_master_reply(), this wouldn't happen if we did
+ a barrier between recover_masters and recover_locks. */
+ log_debug(ls, "master copy not ready %x r %lx %s", lkb->lkb_id,
+ (unsigned long)r, r->res_name);
+ dlm_send_rcom_lock(r, lkb);
+ goto out;
case -EEXIST:
log_debug(ls, "master copy exists %x", lkb->lkb_id);
/* fall through */
@@ -3585,7 +3618,7 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
/* an ack for dlm_recover_locks() which waits for replies from
all the locks it sends to new masters */
dlm_recovered_lock(r);
-
+ out:
unlock_rsb(r);
put_rsb(r);
dlm_put_lkb(lkb);
@@ -3610,7 +3643,7 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
}
if (flags & DLM_LKF_VALBLK) {
- ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
+ ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
if (!ua->lksb.sb_lvbptr) {
kfree(ua);
__put_lkb(ls, lkb);
@@ -3679,7 +3712,7 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
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);
+ ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
if (!ua->lksb.sb_lvbptr) {
error = -ENOMEM;
goto out_put;
@@ -3745,12 +3778,10 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
goto out_put;
spin_lock(&ua->proc->locks_spin);
- list_del_init(&lkb->lkb_ownqueue);
+ /* dlm_user_add_ast() may have already taken lkb off the proc list */
+ if (!list_empty(&lkb->lkb_ownqueue))
+ list_move(&lkb->lkb_ownqueue, &ua->proc->unlocking);
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:
@@ -3790,9 +3821,8 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
/* 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);
+ list_move(&lkb->lkb_ownqueue, &ua->proc->unlocking);
spin_unlock(&ua->proc->locks_spin);
- unhold_lkb(lkb);
}
out_put:
dlm_put_lkb(lkb);
@@ -3853,11 +3883,6 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
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) {
@@ -3874,6 +3899,20 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
dlm_put_lkb(lkb);
}
+
+ /* in-progress unlocks */
+ list_for_each_entry_safe(lkb, safe, &proc->unlocking, lkb_ownqueue) {
+ list_del_init(&lkb->lkb_ownqueue);
+ lkb->lkb_flags |= DLM_IFL_DEAD;
+ dlm_put_lkb(lkb);
+ }
+
+ list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) {
+ list_del(&lkb->lkb_astqueue);
+ dlm_put_lkb(lkb);
+ }
+
mutex_unlock(&ls->ls_clear_proc_locks);
unlock_recovery(ls);
}
+
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index 59012b089e8..f40817b53c6 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -236,7 +236,7 @@ static int dlm_scand(void *data)
while (!kthread_should_stop()) {
list_for_each_entry(ls, &lslist, ls_list)
dlm_scan_rsbs(ls);
- schedule_timeout_interruptible(dlm_config.scan_secs * HZ);
+ schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ);
}
return 0;
}
@@ -422,7 +422,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
ls->ls_count = 0;
ls->ls_flags = 0;
- size = dlm_config.rsbtbl_size;
+ size = dlm_config.ci_rsbtbl_size;
ls->ls_rsbtbl_size = size;
ls->ls_rsbtbl = kmalloc(sizeof(struct dlm_rsbtable) * size, GFP_KERNEL);
@@ -434,7 +434,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
rwlock_init(&ls->ls_rsbtbl[i].lock);
}
- size = dlm_config.lkbtbl_size;
+ size = dlm_config.ci_lkbtbl_size;
ls->ls_lkbtbl_size = size;
ls->ls_lkbtbl = kmalloc(sizeof(struct dlm_lkbtable) * size, GFP_KERNEL);
@@ -446,7 +446,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
ls->ls_lkbtbl[i].counter = 1;
}
- size = dlm_config.dirtbl_size;
+ size = dlm_config.ci_dirtbl_size;
ls->ls_dirtbl_size = size;
ls->ls_dirtbl = kmalloc(sizeof(struct dlm_dirtable) * size, GFP_KERNEL);
@@ -489,7 +489,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
mutex_init(&ls->ls_requestqueue_mutex);
mutex_init(&ls->ls_clear_proc_locks);
- ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+ ls->ls_recover_buf = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL);
if (!ls->ls_recover_buf)
goto out_dirfree;
diff --git a/fs/dlm/lowcomms-sctp.c b/fs/dlm/lowcomms-sctp.c
index fe158d7a928..dc83a9d979b 100644
--- a/fs/dlm/lowcomms-sctp.c
+++ b/fs/dlm/lowcomms-sctp.c
@@ -72,6 +72,8 @@ struct nodeinfo {
struct list_head writequeue; /* outgoing writequeue_entries */
spinlock_t writequeue_lock;
int nodeid;
+ struct work_struct swork; /* Send workqueue */
+ struct work_struct lwork; /* Locking workqueue */
};
static DEFINE_IDR(nodeinfo_idr);
@@ -96,6 +98,7 @@ struct connection {
atomic_t waiting_requests;
struct cbuf cb;
int eagain_flag;
+ struct work_struct work; /* Send workqueue */
};
/* An entry waiting to be sent */
@@ -137,19 +140,23 @@ static void cbuf_eat(struct cbuf *cb, int n)
static LIST_HEAD(write_nodes);
static DEFINE_SPINLOCK(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 DECLARE_WAIT_QUEUE_HEAD(lowcomms_recv_wait);
+/* Work queues */
+static struct workqueue_struct *recv_workqueue;
+static struct workqueue_struct *send_workqueue;
+static struct workqueue_struct *lock_workqueue;
/* The SCTP connection */
static struct connection sctp_con;
+static void process_send_sockets(struct work_struct *work);
+static void process_recv_sockets(struct work_struct *work);
+static void process_lock_request(struct work_struct *work);
static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
{
@@ -222,6 +229,8 @@ static struct nodeinfo *nodeid2nodeinfo(int nodeid, gfp_t alloc)
spin_lock_init(&ni->lock);
INIT_LIST_HEAD(&ni->writequeue);
spin_lock_init(&ni->writequeue_lock);
+ INIT_WORK(&ni->lwork, process_lock_request);
+ INIT_WORK(&ni->swork, process_send_sockets);
ni->nodeid = nodeid;
if (nodeid > max_nodeid)
@@ -249,11 +258,8 @@ static struct nodeinfo *assoc2nodeinfo(sctp_assoc_t assoc)
/* 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);
+ queue_work(recv_workqueue, &sctp_con.work);
}
@@ -361,10 +367,10 @@ static void init_failed(void)
spin_lock_bh(&write_nodes_lock);
list_add_tail(&ni->write_list, &write_nodes);
spin_unlock_bh(&write_nodes_lock);
+ queue_work(send_workqueue, &ni->swork);
}
}
}
- wake_up_process(send_task);
}
/* Something happened to an association */
@@ -446,8 +452,8 @@ static void process_sctp_notification(struct msghdr *msg, char *buf)
spin_lock_bh(&write_nodes_lock);
list_add_tail(&ni->write_list, &write_nodes);
spin_unlock_bh(&write_nodes_lock);
+ queue_work(send_workqueue, &ni->swork);
}
- wake_up_process(send_task);
}
break;
@@ -580,8 +586,8 @@ static int receive_from_sock(void)
spin_lock_bh(&write_nodes_lock);
list_add_tail(&ni->write_list, &write_nodes);
spin_unlock_bh(&write_nodes_lock);
+ queue_work(send_workqueue, &ni->swork);
}
- wake_up_process(send_task);
}
}
@@ -590,6 +596,7 @@ static int receive_from_sock(void)
return 0;
cbuf_add(&sctp_con.cb, ret);
+ // PJC: TODO: Add to node's workqueue....can we ??
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,
@@ -635,7 +642,7 @@ static int add_bind_addr(struct sockaddr_storage *addr, int addr_len, int num)
if (result < 0)
log_print("Can't bind to port %d addr number %d",
- dlm_config.tcp_port, num);
+ dlm_config.ci_tcp_port, num);
return result;
}
@@ -711,7 +718,7 @@ static int init_sock(void)
/* 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);
+ make_sockaddr(&localaddr, dlm_config.ci_tcp_port, &addr_len);
result = add_bind_addr(&localaddr, addr_len, num);
if (result)
@@ -820,7 +827,8 @@ void dlm_lowcomms_commit_buffer(void *arg)
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);
+
+ queue_work(send_workqueue, &ni->swork);
}
return;
@@ -863,7 +871,7 @@ static void initiate_association(int nodeid)
return;
}
- make_sockaddr(&rem_addr, dlm_config.tcp_port, &addrlen);
+ make_sockaddr(&rem_addr, dlm_config.ci_tcp_port, &addrlen);
outmessage.msg_name = &rem_addr;
outmessage.msg_namelen = addrlen;
@@ -1088,101 +1096,75 @@ int dlm_lowcomms_close(int nodeid)
return 0;
}
-static int write_list_empty(void)
+// PJC: The work queue function for receiving.
+static void process_recv_sockets(struct work_struct *work)
{
- 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()) {
+ if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) {
+ int ret;
int count = 0;
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&lowcomms_recv_wait, &wait);
- if (!test_bit(CF_READ_PENDING, &sctp_con.flags))
- cond_resched();
- 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();
+ do {
+ ret = receive_from_sock();
- /* Don't starve out everyone else */
- if (++count >= MAX_RX_MSG_COUNT) {
- cond_resched();
- count = 0;
- }
- } while (!kthread_should_stop() && ret >=0);
- }
- cond_resched();
+ /* Don't starve out everyone else */
+ if (++count >= MAX_RX_MSG_COUNT) {
+ cond_resched();
+ count = 0;
+ }
+ } while (!kthread_should_stop() && ret >=0);
}
-
- return 0;
+ cond_resched();
}
-static int dlm_sendd(void *data)
+// PJC: the work queue function for sending
+static void process_send_sockets(struct work_struct *work)
{
- 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())
- cond_resched();
- set_current_state(TASK_RUNNING);
-
- if (sctp_con.eagain_flag) {
- sctp_con.eagain_flag = 0;
- refill_write_queue();
- }
- process_output_queue();
+ 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;
+// PJC: Process lock requests from a particular node.
+// TODO: can we optimise this out on UP ??
+static void process_lock_request(struct work_struct *work)
+{
}
static void daemons_stop(void)
{
- kthread_stop(recv_task);
- kthread_stop(send_task);
+ destroy_workqueue(recv_workqueue);
+ destroy_workqueue(send_workqueue);
+ destroy_workqueue(lock_workqueue);
}
static int daemons_start(void)
{
- struct task_struct *p;
int error;
+ recv_workqueue = create_workqueue("dlm_recv");
+ error = IS_ERR(recv_workqueue);
+ if (error) {
+ log_print("can't start dlm_recv %d", error);
+ return error;
+ }
- p = kthread_run(dlm_recvd, NULL, "dlm_recvd");
- error = IS_ERR(p);
+ send_workqueue = create_singlethread_workqueue("dlm_send");
+ error = IS_ERR(send_workqueue);
if (error) {
- log_print("can't start dlm_recvd %d", error);
+ log_print("can't start dlm_send %d", error);
+ destroy_workqueue(recv_workqueue);
return error;
}
- recv_task = p;
- p = kthread_run(dlm_sendd, NULL, "dlm_sendd");
- error = IS_ERR(p);
+ lock_workqueue = create_workqueue("dlm_rlock");
+ error = IS_ERR(lock_workqueue);
if (error) {
- log_print("can't start dlm_sendd %d", error);
- kthread_stop(recv_task);
+ log_print("can't start dlm_rlock %d", error);
+ destroy_workqueue(send_workqueue);
+ destroy_workqueue(recv_workqueue);
return error;
}
- send_task = p;
return 0;
}
@@ -1194,6 +1176,8 @@ int dlm_lowcomms_start(void)
{
int error;
+ INIT_WORK(&sctp_con.work, process_recv_sockets);
+
error = init_sock();
if (error)
goto fail_sock;
@@ -1224,4 +1208,3 @@ void dlm_lowcomms_stop(void)
for (i = 0; i < dlm_local_count; i++)
kfree(dlm_local_addr[i]);
}
-
diff --git a/fs/dlm/lowcomms-tcp.c b/fs/dlm/lowcomms-tcp.c
index 8f2791fc844..07e0a122c32 100644
--- a/fs/dlm/lowcomms-tcp.c
+++ b/fs/dlm/lowcomms-tcp.c
@@ -2,7 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2004-2007 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
@@ -96,10 +96,7 @@ static bool cbuf_empty(struct cbuf *cb)
struct connection {
struct socket *sock; /* NULL if not connected */
uint32_t nodeid; /* So we know who we are in the list */
- struct rw_semaphore sock_sem; /* Stop connect races */
- struct list_head read_list; /* On this list when ready for reading */
- struct list_head write_list; /* On this list when ready for writing */
- struct list_head state_list; /* On this list when ready to connect */
+ struct mutex sock_mutex;
unsigned long flags; /* bit 1,2 = We are on the read/write lists */
#define CF_READ_PENDING 1
#define CF_WRITE_PENDING 2
@@ -112,9 +109,10 @@ struct connection {
struct page *rx_page;
struct cbuf cb;
int retries;
- atomic_t waiting_requests;
#define MAX_CONNECT_RETRIES 3
struct connection *othercon;
+ struct work_struct rwork; /* Receive workqueue */
+ struct work_struct swork; /* Send workqueue */
};
#define sock2con(x) ((struct connection *)(x)->sk_user_data)
@@ -131,32 +129,18 @@ struct writequeue_entry {
static struct sockaddr_storage dlm_local_addr;
-/* Manage daemons */
-static struct task_struct *recv_task;
-static struct task_struct *send_task;
-
-static wait_queue_t lowcomms_send_waitq_head;
-static DECLARE_WAIT_QUEUE_HEAD(lowcomms_send_waitq);
-static wait_queue_t lowcomms_recv_waitq_head;
-static DECLARE_WAIT_QUEUE_HEAD(lowcomms_recv_waitq);
+/* Work queues */
+static struct workqueue_struct *recv_workqueue;
+static struct workqueue_struct *send_workqueue;
/* An array of pointers to connections, indexed by NODEID */
static struct connection **connections;
static DECLARE_MUTEX(connections_lock);
-static kmem_cache_t *con_cache;
+static struct kmem_cache *con_cache;
static int conn_array_size;
-/* List of sockets that have reads pending */
-static LIST_HEAD(read_sockets);
-static DEFINE_SPINLOCK(read_sockets_lock);
-
-/* List of sockets which have writes pending */
-static LIST_HEAD(write_sockets);
-static DEFINE_SPINLOCK(write_sockets_lock);
-
-/* List of sockets which have connects pending */
-static LIST_HEAD(state_sockets);
-static DEFINE_SPINLOCK(state_sockets_lock);
+static void process_recv_sockets(struct work_struct *work);
+static void process_send_sockets(struct work_struct *work);
static struct connection *nodeid2con(int nodeid, gfp_t allocation)
{
@@ -186,9 +170,11 @@ static struct connection *nodeid2con(int nodeid, gfp_t allocation)
goto finish;
con->nodeid = nodeid;
- init_rwsem(&con->sock_sem);
+ mutex_init(&con->sock_mutex);
INIT_LIST_HEAD(&con->writequeue);
spin_lock_init(&con->writequeue_lock);
+ INIT_WORK(&con->swork, process_send_sockets);
+ INIT_WORK(&con->rwork, process_recv_sockets);
connections[nodeid] = con;
}
@@ -203,41 +189,22 @@ static void lowcomms_data_ready(struct sock *sk, int count_unused)
{
struct connection *con = sock2con(sk);
- atomic_inc(&con->waiting_requests);
- if (test_and_set_bit(CF_READ_PENDING, &con->flags))
- return;
-
- spin_lock_bh(&read_sockets_lock);
- list_add_tail(&con->read_list, &read_sockets);
- spin_unlock_bh(&read_sockets_lock);
-
- wake_up_interruptible(&lowcomms_recv_waitq);
+ if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
+ queue_work(recv_workqueue, &con->rwork);
}
static void lowcomms_write_space(struct sock *sk)
{
struct connection *con = sock2con(sk);
- if (test_and_set_bit(CF_WRITE_PENDING, &con->flags))
- return;
-
- spin_lock_bh(&write_sockets_lock);
- list_add_tail(&con->write_list, &write_sockets);
- spin_unlock_bh(&write_sockets_lock);
-
- wake_up_interruptible(&lowcomms_send_waitq);
+ if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags))
+ queue_work(send_workqueue, &con->swork);
}
static inline void lowcomms_connect_sock(struct connection *con)
{
- if (test_and_set_bit(CF_CONNECT_PENDING, &con->flags))
- return;
-
- spin_lock_bh(&state_sockets_lock);
- list_add_tail(&con->state_list, &state_sockets);
- spin_unlock_bh(&state_sockets_lock);
-
- wake_up_interruptible(&lowcomms_send_waitq);
+ if (!test_and_set_bit(CF_CONNECT_PENDING, &con->flags))
+ queue_work(send_workqueue, &con->swork);
}
static void lowcomms_state_change(struct sock *sk)
@@ -279,7 +246,7 @@ static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
/* Close a remote connection and tidy up */
static void close_connection(struct connection *con, bool and_other)
{
- down_write(&con->sock_sem);
+ mutex_lock(&con->sock_mutex);
if (con->sock) {
sock_release(con->sock);
@@ -294,24 +261,27 @@ static void close_connection(struct connection *con, bool and_other)
con->rx_page = NULL;
}
con->retries = 0;
- up_write(&con->sock_sem);
+ mutex_unlock(&con->sock_mutex);
}
/* Data received from remote end */
static int receive_from_sock(struct connection *con)
{
int ret = 0;
- struct msghdr msg;
- struct iovec iov[2];
- mm_segment_t fs;
+ struct msghdr msg = {};
+ struct kvec iov[2];
unsigned len;
int r;
int call_again_soon = 0;
+ int nvec;
- down_read(&con->sock_sem);
+ mutex_lock(&con->sock_mutex);
+
+ if (con->sock == NULL) {
+ ret = -EAGAIN;
+ goto out_close;
+ }
- if (con->sock == NULL)
- goto out;
if (con->rx_page == NULL) {
/*
* This doesn't need to be atomic, but I think it should
@@ -323,21 +293,13 @@ static int receive_from_sock(struct connection *con)
cbuf_init(&con->cb, PAGE_CACHE_SIZE);
}
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_iovlen = 1;
- msg.msg_iov = iov;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_flags = 0;
-
/*
* 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 = con->cb.base - cbuf_data(&con->cb);
iov[0].iov_base = page_address(con->rx_page) + cbuf_data(&con->cb);
- iov[1].iov_len = 0;
+ nvec = 1;
/*
* iov[1] is the bit of the circular buffer between the start of the
@@ -347,18 +309,18 @@ static int receive_from_sock(struct connection *con)
iov[0].iov_len = PAGE_CACHE_SIZE - cbuf_data(&con->cb);
iov[1].iov_len = con->cb.base;
iov[1].iov_base = page_address(con->rx_page);
- msg.msg_iovlen = 2;
+ nvec = 2;
}
len = iov[0].iov_len + iov[1].iov_len;
- fs = get_fs();
- set_fs(get_ds());
- r = ret = sock_recvmsg(con->sock, &msg, len,
+ r = ret = kernel_recvmsg(con->sock, &msg, iov, nvec, len,
MSG_DONTWAIT | MSG_NOSIGNAL);
- set_fs(fs);
if (ret <= 0)
goto out_close;
+ if (ret == -EAGAIN)
+ goto out_resched;
+
if (ret == len)
call_again_soon = 1;
cbuf_add(&con->cb, ret);
@@ -381,24 +343,26 @@ static int receive_from_sock(struct connection *con)
con->rx_page = NULL;
}
-out:
if (call_again_soon)
goto out_resched;
- up_read(&con->sock_sem);
+ mutex_unlock(&con->sock_mutex);
return 0;
out_resched:
- lowcomms_data_ready(con->sock->sk, 0);
- up_read(&con->sock_sem);
- cond_resched();
- return 0;
+ if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
+ queue_work(recv_workqueue, &con->rwork);
+ mutex_unlock(&con->sock_mutex);
+ return -EAGAIN;
out_close:
- up_read(&con->sock_sem);
+ mutex_unlock(&con->sock_mutex);
if (ret != -EAGAIN && !test_bit(CF_IS_OTHERCON, &con->flags)) {
close_connection(con, false);
/* Reconnect when there is something to send */
}
+ /* Don't return success if we really got EOF */
+ if (ret == 0)
+ ret = -EAGAIN;
return ret;
}
@@ -412,6 +376,7 @@ static int accept_from_sock(struct connection *con)
int len;
int nodeid;
struct connection *newcon;
+ struct connection *addcon;
memset(&peeraddr, 0, sizeof(peeraddr));
result = sock_create_kern(dlm_local_addr.ss_family, SOCK_STREAM,
@@ -419,7 +384,7 @@ static int accept_from_sock(struct connection *con)
if (result < 0)
return -ENOMEM;
- down_read(&con->sock_sem);
+ mutex_lock_nested(&con->sock_mutex, 0);
result = -ENOTCONN;
if (con->sock == NULL)
@@ -445,7 +410,7 @@ static int accept_from_sock(struct connection *con)
if (dlm_addr_to_nodeid(&peeraddr, &nodeid)) {
printk("dlm: connect from non cluster node\n");
sock_release(newsock);
- up_read(&con->sock_sem);
+ mutex_unlock(&con->sock_mutex);
return -1;
}
@@ -462,7 +427,7 @@ static int accept_from_sock(struct connection *con)
result = -ENOMEM;
goto accept_err;
}
- down_write(&newcon->sock_sem);
+ mutex_lock_nested(&newcon->sock_mutex, 1);
if (newcon->sock) {
struct connection *othercon = newcon->othercon;
@@ -470,41 +435,45 @@ static int accept_from_sock(struct connection *con)
othercon = kmem_cache_zalloc(con_cache, GFP_KERNEL);
if (!othercon) {
printk("dlm: failed to allocate incoming socket\n");
- up_write(&newcon->sock_sem);
+ mutex_unlock(&newcon->sock_mutex);
result = -ENOMEM;
goto accept_err;
}
othercon->nodeid = nodeid;
othercon->rx_action = receive_from_sock;
- init_rwsem(&othercon->sock_sem);
+ mutex_init(&othercon->sock_mutex);
+ INIT_WORK(&othercon->swork, process_send_sockets);
+ INIT_WORK(&othercon->rwork, process_recv_sockets);
set_bit(CF_IS_OTHERCON, &othercon->flags);
newcon->othercon = othercon;
}
othercon->sock = newsock;
newsock->sk->sk_user_data = othercon;
add_sock(newsock, othercon);
+ addcon = othercon;
}
else {
newsock->sk->sk_user_data = newcon;
newcon->rx_action = receive_from_sock;
add_sock(newsock, newcon);
-
+ addcon = newcon;
}
- up_write(&newcon->sock_sem);
+ mutex_unlock(&newcon->sock_mutex);
/*
* Add it to the active queue in case we got data
* beween processing the accept adding the socket
* to the read_sockets list
*/
- lowcomms_data_ready(newsock->sk, 0);
- up_read(&con->sock_sem);
+ if (!test_and_set_bit(CF_READ_PENDING, &addcon->flags))
+ queue_work(recv_workqueue, &addcon->rwork);
+ mutex_unlock(&con->sock_mutex);
return 0;
accept_err:
- up_read(&con->sock_sem);
+ mutex_unlock(&con->sock_mutex);
sock_release(newsock);
if (result != -EAGAIN)
@@ -525,7 +494,7 @@ static void connect_to_sock(struct connection *con)
return;
}
- down_write(&con->sock_sem);
+ mutex_lock(&con->sock_mutex);
if (con->retries++ > MAX_CONNECT_RETRIES)
goto out;
@@ -548,7 +517,7 @@ static void connect_to_sock(struct connection *con)
sock->sk->sk_user_data = con;
con->rx_action = receive_from_sock;
- make_sockaddr(&saddr, dlm_config.tcp_port, &addr_len);
+ make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len);
add_sock(sock, con);
@@ -577,7 +546,7 @@ out_err:
result = 0;
}
out:
- up_write(&con->sock_sem);
+ mutex_unlock(&con->sock_mutex);
return;
}
@@ -616,10 +585,10 @@ static struct socket *create_listen_sock(struct connection *con,
con->sock = sock;
/* Bind to our port */
- make_sockaddr(saddr, dlm_config.tcp_port, &addr_len);
+ make_sockaddr(saddr, dlm_config.ci_tcp_port, &addr_len);
result = sock->ops->bind(sock, (struct sockaddr *) saddr, addr_len);
if (result < 0) {
- printk("dlm: Can't bind to port %d\n", dlm_config.tcp_port);
+ printk("dlm: Can't bind to port %d\n", dlm_config.ci_tcp_port);
sock_release(sock);
sock = NULL;
con->sock = NULL;
@@ -638,7 +607,7 @@ static struct socket *create_listen_sock(struct connection *con,
result = sock->ops->listen(sock, 5);
if (result < 0) {
- printk("dlm: Can't listen on port %d\n", dlm_config.tcp_port);
+ printk("dlm: Can't listen on port %d\n", dlm_config.ci_tcp_port);
sock_release(sock);
sock = NULL;
goto create_out;
@@ -709,6 +678,7 @@ void *dlm_lowcomms_get_buffer(int nodeid, int len,
if (!con)
return NULL;
+ spin_lock(&con->writequeue_lock);
e = list_entry(con->writequeue.prev, struct writequeue_entry, list);
if ((&e->list == &con->writequeue) ||
(PAGE_CACHE_SIZE - e->end < len)) {
@@ -747,6 +717,7 @@ void dlm_lowcomms_commit_buffer(void *mh)
struct connection *con = e->con;
int users;
+ spin_lock(&con->writequeue_lock);
users = --e->users;
if (users)
goto out;
@@ -754,12 +725,8 @@ void dlm_lowcomms_commit_buffer(void *mh)
kunmap(e->page);
spin_unlock(&con->writequeue_lock);
- if (test_and_set_bit(CF_WRITE_PENDING, &con->flags) == 0) {
- spin_lock_bh(&write_sockets_lock);
- list_add_tail(&con->write_list, &write_sockets);
- spin_unlock_bh(&write_sockets_lock);
-
- wake_up_interruptible(&lowcomms_send_waitq);
+ if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) {
+ queue_work(send_workqueue, &con->swork);
}
return;
@@ -783,7 +750,7 @@ static void send_to_sock(struct connection *con)
struct writequeue_entry *e;
int len, offset;
- down_read(&con->sock_sem);
+ mutex_lock(&con->sock_mutex);
if (con->sock == NULL)
goto out_connect;
@@ -800,6 +767,7 @@ static void send_to_sock(struct connection *con)
offset = e->offset;
BUG_ON(len == 0 && e->users == 0);
spin_unlock(&con->writequeue_lock);
+ kmap(e->page);
ret = 0;
if (len) {
@@ -828,18 +796,18 @@ static void send_to_sock(struct connection *con)
}
spin_unlock(&con->writequeue_lock);
out:
- up_read(&con->sock_sem);
+ mutex_unlock(&con->sock_mutex);
return;
send_error:
- up_read(&con->sock_sem);
+ mutex_unlock(&con->sock_mutex);
close_connection(con, false);
lowcomms_connect_sock(con);
return;
out_connect:
- up_read(&con->sock_sem);
- lowcomms_connect_sock(con);
+ mutex_unlock(&con->sock_mutex);
+ connect_to_sock(con);
return;
}
@@ -872,7 +840,6 @@ int dlm_lowcomms_close(int nodeid)
if (con) {
clean_one_writequeue(con);
close_connection(con, true);
- atomic_set(&con->waiting_requests, 0);
}
return 0;
@@ -880,102 +847,29 @@ out:
return -1;
}
-/* API send message call, may queue the request */
-/* N.B. This is the old interface - use the new one for new calls */
-int lowcomms_send_message(int nodeid, char *buf, int len, gfp_t allocation)
-{
- struct writequeue_entry *e;
- char *b;
-
- e = dlm_lowcomms_get_buffer(nodeid, len, allocation, &b);
- if (e) {
- memcpy(b, buf, len);
- dlm_lowcomms_commit_buffer(e);
- return 0;
- }
- return -ENOBUFS;
-}
-
/* Look for activity on active sockets */
-static void process_sockets(void)
+static void process_recv_sockets(struct work_struct *work)
{
- struct list_head *list;
- struct list_head *temp;
- int count = 0;
-
- spin_lock_bh(&read_sockets_lock);
- list_for_each_safe(list, temp, &read_sockets) {
-
- struct connection *con =
- list_entry(list, struct connection, read_list);
- list_del(&con->read_list);
- clear_bit(CF_READ_PENDING, &con->flags);
-
- spin_unlock_bh(&read_sockets_lock);
-
- /* This can reach zero if we are processing requests
- * as they come in.
- */
- if (atomic_read(&con->waiting_requests) == 0) {
- spin_lock_bh(&read_sockets_lock);
- continue;
- }
-
- do {
- con->rx_action(con);
-
- /* Don't starve out everyone else */
- if (++count >= MAX_RX_MSG_COUNT) {
- cond_resched();
- count = 0;
- }
+ struct connection *con = container_of(work, struct connection, rwork);
+ int err;
- } while (!atomic_dec_and_test(&con->waiting_requests) &&
- !kthread_should_stop());
-
- spin_lock_bh(&read_sockets_lock);
- }
- spin_unlock_bh(&read_sockets_lock);
+ clear_bit(CF_READ_PENDING, &con->flags);
+ do {
+ err = con->rx_action(con);
+ } while (!err);
}
-/* 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_sockets_lock);
- list_for_each_safe(list, temp, &write_sockets) {
- struct connection *con =
- list_entry(list, struct connection, write_list);
- clear_bit(CF_WRITE_PENDING, &con->flags);
- list_del(&con->write_list);
- spin_unlock_bh(&write_sockets_lock);
- send_to_sock(con);
- spin_lock_bh(&write_sockets_lock);
- }
- spin_unlock_bh(&write_sockets_lock);
-}
-
-static void process_state_queue(void)
+static void process_send_sockets(struct work_struct *work)
{
- struct list_head *list;
- struct list_head *temp;
-
- spin_lock_bh(&state_sockets_lock);
- list_for_each_safe(list, temp, &state_sockets) {
- struct connection *con =
- list_entry(list, struct connection, state_list);
- list_del(&con->state_list);
- clear_bit(CF_CONNECT_PENDING, &con->flags);
- spin_unlock_bh(&state_sockets_lock);
+ struct connection *con = container_of(work, struct connection, swork);
+ if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) {
connect_to_sock(con);
- spin_lock_bh(&state_sockets_lock);
}
- spin_unlock_bh(&state_sockets_lock);
+
+ clear_bit(CF_WRITE_PENDING, &con->flags);
+ send_to_sock(con);
}
@@ -992,109 +886,33 @@ static void clean_writequeues(void)
}
}
-static int read_list_empty(void)
-{
- int status;
-
- spin_lock_bh(&read_sockets_lock);
- status = list_empty(&read_sockets);
- spin_unlock_bh(&read_sockets_lock);
-
- return status;
-}
-
-/* DLM Transport comms receive daemon */
-static int dlm_recvd(void *data)
+static void work_stop(void)
{
- init_waitqueue_entry(&lowcomms_recv_waitq_head, current);
- add_wait_queue(&lowcomms_recv_waitq, &lowcomms_recv_waitq_head);
-
- while (!kthread_should_stop()) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (read_list_empty())
- cond_resched();
- set_current_state(TASK_RUNNING);
-
- process_sockets();
- }
-
- return 0;
+ destroy_workqueue(recv_workqueue);
+ destroy_workqueue(send_workqueue);
}
-static int write_and_state_lists_empty(void)
+static int work_start(void)
{
- int status;
-
- spin_lock_bh(&write_sockets_lock);
- status = list_empty(&write_sockets);
- spin_unlock_bh(&write_sockets_lock);
-
- spin_lock_bh(&state_sockets_lock);
- if (list_empty(&state_sockets) == 0)
- status = 0;
- spin_unlock_bh(&state_sockets_lock);
-
- return status;
-}
-
-/* DLM Transport send daemon */
-static int dlm_sendd(void *data)
-{
- init_waitqueue_entry(&lowcomms_send_waitq_head, current);
- add_wait_queue(&lowcomms_send_waitq, &lowcomms_send_waitq_head);
-
- while (!kthread_should_stop()) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (write_and_state_lists_empty())
- cond_resched();
- set_current_state(TASK_RUNNING);
-
- process_state_queue();
- process_output_queue();
- }
-
- 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);
+ recv_workqueue = create_workqueue("dlm_recv");
+ error = IS_ERR(recv_workqueue);
if (error) {
- log_print("can't start dlm_recvd %d", error);
+ log_print("can't start dlm_recv %d", error);
return error;
}
- recv_task = p;
- p = kthread_run(dlm_sendd, NULL, "dlm_sendd");
- error = IS_ERR(p);
+ send_workqueue = create_singlethread_workqueue("dlm_send");
+ error = IS_ERR(send_workqueue);
if (error) {
- log_print("can't start dlm_sendd %d", error);
- kthread_stop(recv_task);
+ log_print("can't start dlm_send %d", error);
+ destroy_workqueue(recv_workqueue);
return error;
}
- send_task = p;
return 0;
}
-/*
- * Return the largest buffer size we can cope with.
- */
-int lowcomms_max_buffer_size(void)
-{
- return PAGE_CACHE_SIZE;
-}
-
void dlm_lowcomms_stop(void)
{
int i;
@@ -1107,7 +925,7 @@ void dlm_lowcomms_stop(void)
connections[i]->flags |= 0xFF;
}
- daemons_stop();
+ work_stop();
clean_writequeues();
for (i = 0; i < conn_array_size; i++) {
@@ -1159,7 +977,7 @@ int dlm_lowcomms_start(void)
if (error)
goto fail_unlisten;
- error = daemons_start();
+ error = work_start();
if (error)
goto fail_unlisten;
diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c
index c9b1c3d535f..a5126e0c68a 100644
--- a/fs/dlm/midcomms.c
+++ b/fs/dlm/midcomms.c
@@ -82,7 +82,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base,
if (msglen < sizeof(struct dlm_header))
break;
err = -E2BIG;
- if (msglen > dlm_config.buffer_size) {
+ if (msglen > dlm_config.ci_buffer_size) {
log_print("message size %d from %d too big, buf len %d",
msglen, nodeid, len);
break;
@@ -103,7 +103,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base,
if (msglen > sizeof(__tmp) &&
msg == (struct dlm_header *) __tmp) {
- msg = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+ msg = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL);
if (msg == NULL)
return ret;
}
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
index 4cc31be9cd9..6bfbd615380 100644
--- a/fs/dlm/rcom.c
+++ b/fs/dlm/rcom.c
@@ -56,6 +56,10 @@ static int create_rcom(struct dlm_ls *ls, int to_nodeid, int type, int len,
rc->rc_type = type;
+ spin_lock(&ls->ls_recover_lock);
+ rc->rc_seq = ls->ls_recover_seq;
+ spin_unlock(&ls->ls_recover_lock);
+
*mh_ret = mh;
*rc_ret = rc;
return 0;
@@ -78,8 +82,17 @@ static void make_config(struct dlm_ls *ls, struct rcom_config *rf)
rf->rf_lsflags = ls->ls_exflags;
}
-static int check_config(struct dlm_ls *ls, struct rcom_config *rf, int nodeid)
+static int check_config(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
{
+ struct rcom_config *rf = (struct rcom_config *) rc->rc_buf;
+
+ if ((rc->rc_header.h_version & 0xFFFF0000) != DLM_HEADER_MAJOR) {
+ log_error(ls, "version mismatch: %x nodeid %d: %x",
+ DLM_HEADER_MAJOR | DLM_HEADER_MINOR, nodeid,
+ rc->rc_header.h_version);
+ return -EINVAL;
+ }
+
if (rf->rf_lvblen != ls->ls_lvblen ||
rf->rf_lsflags != ls->ls_exflags) {
log_error(ls, "config mismatch: %d,%x nodeid %d: %d,%x",
@@ -125,7 +138,7 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid)
goto out;
allow_sync_reply(ls, &rc->rc_id);
- memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+ memset(ls->ls_recover_buf, 0, dlm_config.ci_buffer_size);
send_rcom(ls, mh, rc);
@@ -141,8 +154,7 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid)
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);
+ error = check_config(ls, rc, nodeid);
/* the caller looks at rc_result for the remote recovery status */
out:
return error;
@@ -159,6 +171,7 @@ static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in)
if (error)
return;
rc->rc_id = rc_in->rc_id;
+ rc->rc_seq_reply = rc_in->rc_seq;
rc->rc_result = dlm_recover_status(ls);
make_config(ls, (struct rcom_config *) rc->rc_buf);
@@ -200,7 +213,7 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len)
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);
+ dlm_config.ci_buffer_size - len, nodeid);
goto out;
}
@@ -210,7 +223,7 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len)
memcpy(rc->rc_buf, last_name, last_len);
allow_sync_reply(ls, &rc->rc_id);
- memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+ memset(ls->ls_recover_buf, 0, dlm_config.ci_buffer_size);
send_rcom(ls, mh, rc);
@@ -224,30 +237,17 @@ 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;
- }
+ int error, inlen, outlen, nodeid;
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);
+ outlen = dlm_config.ci_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;
+ rc->rc_seq_reply = rc_in->rc_seq;
dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen,
nodeid);
@@ -294,6 +294,7 @@ static void receive_rcom_lookup(struct dlm_ls *ls, struct dlm_rcom *rc_in)
ret_nodeid = error;
rc->rc_result = ret_nodeid;
rc->rc_id = rc_in->rc_id;
+ rc->rc_seq_reply = rc_in->rc_seq;
send_rcom(ls, mh, rc);
}
@@ -375,20 +376,13 @@ static void receive_rcom_lock(struct dlm_ls *ls, struct dlm_rcom *rc_in)
memcpy(rc->rc_buf, rc_in->rc_buf, sizeof(struct rcom_lock));
rc->rc_id = rc_in->rc_id;
+ rc->rc_seq_reply = rc_in->rc_seq;
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);
}
@@ -415,6 +409,7 @@ static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
rc->rc_type = DLM_RCOM_STATUS_REPLY;
rc->rc_id = rc_in->rc_id;
+ rc->rc_seq_reply = rc_in->rc_seq;
rc->rc_result = -ESRCH;
rf = (struct rcom_config *) rc->rc_buf;
@@ -426,6 +421,31 @@ static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
return 0;
}
+static int is_old_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+ uint64_t seq;
+ int rv = 0;
+
+ switch (rc->rc_type) {
+ case DLM_RCOM_STATUS_REPLY:
+ case DLM_RCOM_NAMES_REPLY:
+ case DLM_RCOM_LOOKUP_REPLY:
+ case DLM_RCOM_LOCK_REPLY:
+ spin_lock(&ls->ls_recover_lock);
+ seq = ls->ls_recover_seq;
+ spin_unlock(&ls->ls_recover_lock);
+ if (rc->rc_seq_reply != seq) {
+ log_debug(ls, "ignoring old reply %x from %d "
+ "seq_reply %llx expect %llx",
+ rc->rc_type, rc->rc_header.h_nodeid,
+ (unsigned long long)rc->rc_seq_reply,
+ (unsigned long long)seq);
+ rv = 1;
+ }
+ }
+ return rv;
+}
+
/* Called by dlm_recvd; corresponds to dlm_receive_message() but special
recovery-only comms are sent through here. */
@@ -449,11 +469,14 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
}
if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
- log_error(ls, "ignoring recovery message %x from %d",
+ log_debug(ls, "ignoring recovery message %x from %d",
rc->rc_type, nodeid);
goto out;
}
+ if (is_old_reply(ls, rc))
+ goto out;
+
if (nodeid != rc->rc_header.h_nodeid) {
log_error(ls, "bad rcom nodeid %d from %d",
rc->rc_header.h_nodeid, nodeid);
diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c
index cf9f6831bab..c2cc7694cd1 100644
--- a/fs/dlm/recover.c
+++ b/fs/dlm/recover.c
@@ -44,7 +44,7 @@
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));
+ mod_timer(&ls->ls_timer, jiffies + (dlm_config.ci_recover_timer * HZ));
wake_up(&ls->ls_wait_general);
}
@@ -55,7 +55,7 @@ int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls))
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);
+ ls->ls_timer.expires = jiffies + (dlm_config.ci_recover_timer * HZ);
add_timer(&ls->ls_timer);
wait_event(ls->ls_wait_general, testfn(ls) || dlm_recovery_stopped(ls));
@@ -397,7 +397,9 @@ int dlm_recover_masters(struct dlm_ls *ls)
if (dlm_no_directory(ls))
count += recover_master_static(r);
- else if (!is_master(r) && dlm_is_removed(ls, r->res_nodeid)) {
+ else if (!is_master(r) &&
+ (dlm_is_removed(ls, r->res_nodeid) ||
+ rsb_flag(r, RSB_NEW_MASTER))) {
recover_master(r);
count++;
}
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
index 650536aa513..3cb636d6024 100644
--- a/fs/dlm/recoverd.c
+++ b/fs/dlm/recoverd.c
@@ -77,7 +77,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
error = dlm_recover_members(ls, rv, &neg);
if (error) {
- log_error(ls, "recover_members failed %d", error);
+ log_debug(ls, "recover_members failed %d", error);
goto fail;
}
start = jiffies;
@@ -89,7 +89,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
error = dlm_recover_directory(ls);
if (error) {
- log_error(ls, "recover_directory failed %d", error);
+ log_debug(ls, "recover_directory failed %d", error);
goto fail;
}
@@ -99,7 +99,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
error = dlm_recover_directory_wait(ls);
if (error) {
- log_error(ls, "recover_directory_wait failed %d", error);
+ log_debug(ls, "recover_directory_wait failed %d", error);
goto fail;
}
@@ -129,7 +129,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
error = dlm_recover_masters(ls);
if (error) {
- log_error(ls, "recover_masters failed %d", error);
+ log_debug(ls, "recover_masters failed %d", error);
goto fail;
}
@@ -139,13 +139,13 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
error = dlm_recover_locks(ls);
if (error) {
- log_error(ls, "recover_locks failed %d", error);
+ log_debug(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);
+ log_debug(ls, "recover_locks_wait failed %d", error);
goto fail;
}
@@ -166,7 +166,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
error = dlm_recover_locks_wait(ls);
if (error) {
- log_error(ls, "recover_locks_wait failed %d", error);
+ log_debug(ls, "recover_locks_wait failed %d", error);
goto fail;
}
}
@@ -184,7 +184,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
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);
+ log_debug(ls, "recover_done_wait failed %d", error);
goto fail;
}
@@ -192,19 +192,19 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
error = enable_locking(ls, rv->seq);
if (error) {
- log_error(ls, "enable_locking failed %d", error);
+ log_debug(ls, "enable_locking failed %d", error);
goto fail;
}
error = dlm_process_requestqueue(ls);
if (error) {
- log_error(ls, "process_requestqueue failed %d", error);
+ log_debug(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);
+ log_debug(ls, "recover_waiters_post failed %d", error);
goto fail;
}
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index c37e93e4f2d..d378b7fe2a1 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -180,6 +180,14 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue))
remove_ownqueue = 1;
+ /* unlocks or cancels of waiting requests need to be removed from the
+ proc's unlocking list, again there must be a better way... */
+
+ if (ua->lksb.sb_status == -DLM_EUNLOCK ||
+ (ua->lksb.sb_status == -DLM_ECANCEL &&
+ lkb->lkb_grmode == DLM_LOCK_IV))
+ 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()
@@ -523,6 +531,7 @@ static int device_open(struct inode *inode, struct file *file)
proc->lockspace = ls->ls_local_handle;
INIT_LIST_HEAD(&proc->asts);
INIT_LIST_HEAD(&proc->locks);
+ INIT_LIST_HEAD(&proc->unlocking);
spin_lock_init(&proc->asts_spin);
spin_lock_init(&proc->locks_spin);
init_waitqueue_head(&proc->wait);
diff --git a/fs/dlm/util.c b/fs/dlm/util.c
index 767197db994..963889cf674 100644
--- a/fs/dlm/util.c
+++ b/fs/dlm/util.c
@@ -134,6 +134,8 @@ void dlm_rcom_out(struct dlm_rcom *rc)
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);
+ rc->rc_seq = cpu_to_le64(rc->rc_seq);
+ rc->rc_seq_reply = cpu_to_le64(rc->rc_seq_reply);
if (type == DLM_RCOM_LOCK)
rcom_lock_out((struct rcom_lock *) rc->rc_buf);
@@ -151,6 +153,8 @@ void dlm_rcom_in(struct dlm_rcom *rc)
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);
+ rc->rc_seq = le64_to_cpu(rc->rc_seq);
+ rc->rc_seq_reply = le64_to_cpu(rc->rc_seq_reply);
if (rc->rc_type == DLM_RCOM_LOCK)
rcom_lock_in((struct rcom_lock *) rc->rc_buf);
diff --git a/fs/dnotify.c b/fs/dnotify.c
index 1f26a2b9eee..936409fcd93 100644
--- a/fs/dnotify.c
+++ b/fs/dnotify.c
@@ -42,7 +42,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id)
struct dnotify_struct **prev;
struct inode *inode;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (!S_ISDIR(inode->i_mode))
return;
spin_lock(&inode->i_lock);
@@ -74,7 +74,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
}
if (!dir_notify_enable)
return -EINVAL;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (!S_ISDIR(inode->i_mode))
return -ENOTDIR;
dn = kmem_cache_alloc(dn_cache, GFP_KERNEL);
diff --git a/fs/dquot.c b/fs/dquot.c
index f9cd5e23ebd..0952cc474d9 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -694,9 +694,9 @@ restart:
file_list_lock();
list_for_each(p, &sb->s_files) {
struct file *filp = list_entry(p, struct file, f_u.fu_list);
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) {
- struct dentry *dentry = dget(filp->f_dentry);
+ struct dentry *dentry = dget(filp->f_path.dentry);
file_list_unlock();
sb->dq_op->initialize(inode, type);
dput(dentry);
@@ -828,6 +828,7 @@ static inline int need_print_warning(struct dquot *dquot)
static void print_warning(struct dquot *dquot, const char warntype)
{
char *msg = NULL;
+ struct tty_struct *tty;
int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS_B :
((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES_B : 0);
@@ -835,14 +836,15 @@ static void print_warning(struct dquot *dquot, const char warntype)
return;
mutex_lock(&tty_mutex);
- if (!current->signal->tty)
+ tty = get_current_tty();
+ if (!tty)
goto out_lock;
- tty_write_message(current->signal->tty, dquot->dq_sb->s_id);
+ tty_write_message(tty, dquot->dq_sb->s_id);
if (warntype == ISOFTWARN || warntype == BSOFTWARN)
- tty_write_message(current->signal->tty, ": warning, ");
+ tty_write_message(tty, ": warning, ");
else
- tty_write_message(current->signal->tty, ": write failed, ");
- tty_write_message(current->signal->tty, quotatypes[dquot->dq_type]);
+ tty_write_message(tty, ": write failed, ");
+ tty_write_message(tty, quotatypes[dquot->dq_type]);
switch (warntype) {
case IHARDWARN:
msg = " file limit reached.\r\n";
@@ -863,7 +865,7 @@ static void print_warning(struct dquot *dquot, const char warntype)
msg = " block quota exceeded.\r\n";
break;
}
- tty_write_message(current->signal->tty, msg);
+ tty_write_message(tty, msg);
out_lock:
mutex_unlock(&tty_mutex);
}
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 7196f50fe15..a86a55ccf87 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -828,9 +828,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
mutex_unlock(&crypt_stat->cs_tfm_mutex);
goto out;
}
- crypto_blkcipher_set_flags(crypt_stat->tfm,
- (ECRYPTFS_DEFAULT_CHAINING_MODE
- | CRYPTO_TFM_REQ_WEAK_KEY));
+ crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY);
mutex_unlock(&crypt_stat->cs_tfm_mutex);
rc = 0;
out:
diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c
index 52d1e36dc74..329efcd3d8c 100644
--- a/fs/ecryptfs/dentry.c
+++ b/fs/ecryptfs/dentry.c
@@ -25,6 +25,7 @@
#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/mount.h>
+#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
/**
@@ -61,7 +62,7 @@ static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
struct inode *lower_inode =
ecryptfs_inode_to_lower(dentry->d_inode);
- ecryptfs_copy_attr_all(dentry->d_inode, lower_inode);
+ fsstack_copy_attr_all(dentry->d_inode, lower_inode, NULL);
}
out:
return rc;
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index f992533d169..0f897109759 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -28,6 +28,8 @@
#include <keys/user-type.h>
#include <linux/fs.h>
+#include <linux/fs_stack.h>
+#include <linux/namei.h>
#include <linux/scatterlist.h>
/* Version verification for shared data structures w/ userspace */
@@ -174,7 +176,6 @@ ecryptfs_get_key_payload_data(struct key *key)
#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_DEFAULT_HASH "md5"
#define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C
#define ECRYPTFS_TAG_11_PACKET_TYPE 0xED
@@ -227,8 +228,7 @@ struct ecryptfs_inode_info {
/* 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 path lower_path;
struct ecryptfs_crypt_stat *crypt_stat;
};
@@ -355,26 +355,26 @@ ecryptfs_set_dentry_private(struct dentry *dentry,
static inline struct dentry *
ecryptfs_dentry_to_lower(struct dentry *dentry)
{
- return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry;
+ return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.dentry;
}
static inline void
ecryptfs_set_dentry_lower(struct dentry *dentry, struct dentry *lower_dentry)
{
- ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry =
+ ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.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;
+ return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.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 =
+ ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.mnt =
lower_mnt;
}
@@ -413,9 +413,6 @@ 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);
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 42099e779a5..c5a2e5298f1 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -30,6 +30,7 @@
#include <linux/security.h>
#include <linux/smp_lock.h>
#include <linux/compat.h>
+#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
/**
@@ -75,7 +76,7 @@ static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin)
}
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);
+ rc = ecryptfs_truncate(file->f_path.dentry, new_end_pos);
if (rc) {
rv = rc;
ecryptfs_printk(KERN_ERR, "Error on attempt to "
@@ -116,8 +117,8 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
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);
+ lower_dentry = ecryptfs_dentry_to_lower(file->f_path.dentry);
+ lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry);
touch_atime(lower_vfsmount, lower_dentry);
}
return rc;
@@ -176,10 +177,10 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
lower_file = ecryptfs_file_to_lower(file);
lower_file->f_pos = file->f_pos;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
memset(&buf, 0, sizeof(buf));
buf.dirent = dirent;
- buf.dentry = file->f_dentry;
+ buf.dentry = file->f_path.dentry;
buf.filldir = filldir;
retry:
buf.filldir_called = 0;
@@ -192,7 +193,7 @@ retry:
goto retry;
file->f_pos = lower_file->f_pos;
if (rc >= 0)
- ecryptfs_copy_attr_atime(inode, lower_file->f_dentry->d_inode);
+ fsstack_copy_attr_atime(inode, lower_file->f_path.dentry->d_inode);
return rc;
}
@@ -239,7 +240,7 @@ 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;
+ struct dentry *ecryptfs_dentry = file->f_path.dentry;
/* Private value of ecryptfs_dentry allocated in
* ecryptfs_lookup() */
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 8a1945a84c3..11f5e5076ae 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -30,6 +30,7 @@
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/crypto.h>
+#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
static struct dentry *lock_parent(struct dentry *dentry)
@@ -53,48 +54,6 @@ static void unlock_dir(struct dentry *dir)
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
@@ -171,8 +130,8 @@ ecryptfs_do_create(struct inode *directory_inode,
ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n");
goto out_lock;
}
- ecryptfs_copy_attr_timesizes(directory_inode,
- lower_dir_dentry->d_inode);
+ fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode);
+ fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode);
out_lock:
unlock_dir(lower_dir_dentry);
out:
@@ -196,7 +155,7 @@ static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file,
struct ecryptfs_file_info tmp_file_info;
memset(&fake_file, 0, sizeof(fake_file));
- fake_file.f_dentry = ecryptfs_dentry;
+ fake_file.f_path.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);
@@ -365,7 +324,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *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);
+ fsstack_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,
@@ -462,7 +421,8 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
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);
+ fsstack_copy_attr_times(dir, lower_new_dentry->d_inode);
+ fsstack_copy_inode_size(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);
@@ -488,7 +448,7 @@ static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
goto out_unlock;
}
- ecryptfs_copy_attr_times(dir, lower_dir_inode);
+ fsstack_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;
@@ -527,7 +487,8 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
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);
+ fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
out_lock:
unlock_dir(lower_dir_dentry);
dput(lower_dentry);
@@ -550,7 +511,8 @@ static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
if (rc)
goto out;
- ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
out:
unlock_dir(lower_dir_dentry);
@@ -573,7 +535,7 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
dput(lower_dentry);
if (!rc)
d_delete(lower_dentry);
- ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode);
+ fsstack_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)
@@ -597,7 +559,8 @@ ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
if (rc)
goto out;
- ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
out:
unlock_dir(lower_dir_dentry);
if (!dentry->d_inode)
@@ -626,9 +589,9 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *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);
+ fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL);
if (new_dir != old_dir)
- ecryptfs_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
+ fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode, NULL);
out_lock:
unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
dput(lower_new_dentry->d_parent);
@@ -684,8 +647,8 @@ ecryptfs_readlink(struct dentry *dentry, char __user * buf, int bufsiz)
rc = -EFAULT;
}
kfree(decoded_name);
- ecryptfs_copy_attr_atime(dentry->d_inode,
- lower_dentry->d_inode);
+ fsstack_copy_attr_atime(dentry->d_inode,
+ lower_dentry->d_inode);
}
out_free_lower_buf:
kfree(lower_buf);
@@ -791,7 +754,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
* 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;
+ fake_ecryptfs_file.f_path.dentry = dentry;
/* Released at out_free: label */
ecryptfs_set_file_private(&fake_ecryptfs_file,
kmem_cache_alloc(ecryptfs_file_info_cache,
@@ -915,7 +878,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
}
rc = notify_change(lower_dentry, ia);
out:
- ecryptfs_copy_attr_all(inode, lower_inode);
+ fsstack_copy_attr_all(inode, lower_inode, NULL);
return rc;
}
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 3ede12b2593..d0541ae8fab 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -35,6 +35,7 @@
#include <linux/pagemap.h>
#include <linux/key.h>
#include <linux/parser.h>
+#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
/**
@@ -112,10 +113,10 @@ int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
d_add(dentry, inode);
else
d_instantiate(dentry, inode);
- ecryptfs_copy_attr_all(inode, lower_inode);
+ fsstack_copy_attr_all(inode, lower_inode, NULL);
/* This size will be overwritten for real files w/ headers and
* other metadata */
- ecryptfs_copy_inode_size(inode, lower_inode);
+ fsstack_copy_inode_size(inode, lower_inode);
out:
return rc;
}
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 924dd90a4cf..06843d24f23 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -51,7 +51,7 @@ static struct page *ecryptfs_get1page(struct file *file, int index)
struct inode *inode;
struct address_space *mapping;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
inode = dentry->d_inode;
mapping = inode->i_mapping;
page = read_cache_page(mapping, index,
@@ -84,7 +84,7 @@ int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros);
int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
{
int rc = 0;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
pgoff_t old_end_page_index = 0;
pgoff_t index = old_end_page_index;
@@ -218,7 +218,7 @@ int ecryptfs_do_readpage(struct file *file, struct page *page,
char *lower_page_data;
const struct address_space_operations *lower_a_ops;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
lower_file = ecryptfs_file_to_lower(file);
lower_dentry = ecryptfs_dentry_to_lower(dentry);
inode = dentry->d_inode;
@@ -275,9 +275,9 @@ 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;
+ BUG_ON(!(file && file->f_path.dentry && file->f_path.dentry->d_inode));
+ crypt_stat = &ecryptfs_inode_to_private(file->f_path.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)) {
@@ -638,8 +638,8 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
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;
+ crypt_stat = &ecryptfs_inode_to_private(file->f_path.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);
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index 17f5b2d3c16..b46c488eefc 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -20,7 +20,7 @@ struct inode_operations efs_dir_inode_operations = {
};
static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct buffer_head *bh;
struct efs_dir *dirblock;
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 88a6f8d0b88..3ae644e7e86 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -795,8 +795,8 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
goto eexit_4;
dentry->d_op = &eventpollfs_dentry_operations;
d_add(dentry, inode);
- file->f_vfsmnt = mntget(eventpoll_mnt);
- file->f_dentry = dentry;
+ file->f_path.mnt = mntget(eventpoll_mnt);
+ file->f_path.dentry = dentry;
file->f_mapping = inode->i_mapping;
file->f_pos = 0;
diff --git a/fs/exec.c b/fs/exec.c
index add0e03c3ea..11fe93f7363 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -38,6 +38,7 @@
#include <linux/binfmts.h>
#include <linux/swap.h>
#include <linux/utsname.h>
+#include <linux/pid_namespace.h>
#include <linux/module.h>
#include <linux/namei.h>
#include <linux/proc_fs.h>
@@ -620,8 +621,8 @@ 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(tsk->group_leader == child_reaper))
- child_reaper = tsk;
+ if (unlikely(tsk->group_leader == child_reaper(tsk)))
+ tsk->nsproxy->pid_ns->child_reaper = tsk;
zap_other_threads(tsk);
read_unlock(&tasklist_lock);
@@ -782,7 +783,7 @@ static void flush_old_files(struct files_struct * files)
j++;
i = j * __NFDBITS;
fdt = files_fdtable(files);
- if (i >= fdt->max_fds || i >= fdt->max_fdset)
+ if (i >= fdt->max_fds)
break;
set = fdt->close_on_exec->fds_bits[j];
if (!set)
@@ -912,7 +913,7 @@ EXPORT_SYMBOL(flush_old_exec);
int prepare_binprm(struct linux_binprm *bprm)
{
int mode;
- struct inode * inode = bprm->file->f_dentry->d_inode;
+ struct inode * inode = bprm->file->f_path.dentry->d_inode;
int retval;
mode = inode->i_mode;
@@ -922,7 +923,7 @@ int prepare_binprm(struct linux_binprm *bprm)
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
- if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) {
+ if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
/* Set-uid? */
if (mode & S_ISUID) {
current->personality &= ~PER_CLEAR_ON_SETID;
@@ -1519,10 +1520,10 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
0600);
if (IS_ERR(file))
goto fail_unlock;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (inode->i_nlink > 1)
goto close_fail; /* multiple links - don't dump */
- if (!ispipe && d_unhashed(file->f_dentry))
+ if (!ispipe && d_unhashed(file->f_path.dentry))
goto close_fail;
/* AK: actually i see no reason to not allow this for named pipes etc.,
@@ -1533,7 +1534,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
goto close_fail;
if (!file->f_op->write)
goto close_fail;
- if (!ispipe && do_truncate(file->f_dentry, 0, 0, file) != 0)
+ if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
goto close_fail;
retval = binfmt->core_dump(signr, regs, file);
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 3e7a84a1e50..0b02ba9642d 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -248,7 +248,7 @@ static int
ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
{
loff_t pos = filp->f_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
unsigned int offset = pos & ~PAGE_CACHE_MASK;
unsigned long n = pos >> PAGE_CACHE_SHIFT;
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index e3cf8c81507..4b099d31071 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -90,7 +90,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
#ifdef CONFIG_COMPAT
long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int ret;
/* These are just misnamed, they actually get/put from/to user an int */
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 255cef5f742..6347c2dbdd8 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -597,8 +597,6 @@ static int ext2_check_descriptors (struct super_block * sb)
return 1;
}
-#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.
@@ -834,9 +832,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_sbh = bh;
sbi->s_mount_state = le16_to_cpu(es->s_state);
sbi->s_addr_per_block_bits =
- log2 (EXT2_ADDR_PER_BLOCK(sb));
+ ilog2 (EXT2_ADDR_PER_BLOCK(sb));
sbi->s_desc_per_block_bits =
- log2 (EXT2_DESC_PER_BLOCK(sb));
+ ilog2 (EXT2_DESC_PER_BLOCK(sb));
if (sb->s_magic != EXT2_SUPER_MAGIC)
goto cantfind_ext2;
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 5a9313ecd4e..665adee99b3 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -103,7 +103,7 @@ static int ext3_readdir(struct file * filp,
struct ext3_dir_entry_2 *de;
struct super_block *sb;
int err;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
sb = inode->i_sb;
@@ -122,7 +122,7 @@ static int ext3_readdir(struct file * filp,
* We don't set the inode dirty flag since it's not
* critical that it get flushed back to the disk.
*/
- EXT3_I(filp->f_dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL;
+ EXT3_I(filp->f_path.dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL;
}
#endif
stored = 0;
@@ -402,7 +402,7 @@ static int call_filldir(struct file * filp, void * dirent,
{
struct dir_private_info *info = filp->private_data;
loff_t curr_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block * sb;
int error;
@@ -432,7 +432,7 @@ static int ext3_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 inode *inode = filp->f_path.dentry->d_inode;
struct fname *fname;
int ret;
diff --git a/fs/ext3/file.c b/fs/ext3/file.c
index e96c388047e..881f6365c41 100644
--- a/fs/ext3/file.c
+++ b/fs/ext3/file.c
@@ -52,7 +52,7 @@ 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;
+ struct inode *inode = file->f_path.dentry->d_inode;
ssize_t ret;
int err;
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 12daa686957..9b8090d94e6 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -257,7 +257,7 @@ flags_err:
#ifdef CONFIG_COMPAT
long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int ret;
/* These are just misnamed, they actually get/put from/to user an int */
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 60d2f9dbdb0..4df39c4315e 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -602,7 +602,7 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
start_minor_hash));
- dir = dir_file->f_dentry->d_inode;
+ dir = dir_file->f_path.dentry->d_inode;
if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) {
hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed;
@@ -613,7 +613,7 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
}
hinfo.hash = start_hash;
hinfo.minor_hash = 0;
- frame = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
+ frame = dx_probe(NULL, dir_file->f_path.dentry->d_inode, &hinfo, frames, &err);
if (!frame)
return err;
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 580b8a6ca97..b34886734a4 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -1347,8 +1347,6 @@ static void ext3_orphan_cleanup (struct super_block * sb,
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.
@@ -1597,8 +1595,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc);
sbi->s_sbh = bh;
sbi->s_mount_state = le16_to_cpu(es->s_state);
- sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb));
- sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb));
+ sbi->s_addr_per_block_bits = ilog2(EXT3_ADDR_PER_BLOCK(sb));
+ sbi->s_desc_per_block_bits = ilog2(EXT3_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;
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index f2ed3e7fb9f..da80368b66f 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -103,7 +103,7 @@ static int ext4_readdir(struct file * filp,
struct ext4_dir_entry_2 *de;
struct super_block *sb;
int err;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
sb = inode->i_sb;
@@ -122,7 +122,7 @@ static int ext4_readdir(struct file * filp,
* 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;
+ EXT4_I(filp->f_path.dentry->d_inode)->i_flags &= ~EXT4_INDEX_FL;
}
#endif
stored = 0;
@@ -402,7 +402,7 @@ static int call_filldir(struct file * filp, void * dirent,
{
struct dir_private_info *info = filp->private_data;
loff_t curr_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block * sb;
int error;
@@ -432,7 +432,7 @@ 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 inode *inode = filp->f_path.dentry->d_inode;
struct fname *fname;
int ret;
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 0b622c0624b..3bbc24b5878 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -52,7 +52,7 @@ 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;
+ struct inode *inode = file->f_path.dentry->d_inode;
ssize_t ret;
int err;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 1d85d4ec959..a127cc03c9f 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1232,7 +1232,7 @@ retry:
from, to, NULL, do_journal_get_write_access);
if (ret)
/* fatal error, just put the handle and return */
- journal_stop(handle);
+ ext4_journal_stop(handle);
}
return ret;
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 22a737c306c..500567dd53b 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -256,7 +256,7 @@ flags_err:
#ifdef CONFIG_COMPAT
long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int ret;
/* These are just misnamed, they actually get/put from/to user an int */
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 859990eac50..e5a74a5ac26 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -602,7 +602,7 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
start_minor_hash));
- dir = dir_file->f_dentry->d_inode;
+ dir = dir_file->f_path.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;
@@ -613,7 +613,7 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
}
hinfo.hash = start_hash;
hinfo.minor_hash = 0;
- frame = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
+ frame = dx_probe(NULL, dir_file->f_path.dentry->d_inode, &hinfo, frames, &err);
if (!frame)
return err;
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 69c439f4438..c16af246d24 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -579,7 +579,7 @@ parse_record:
if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME))
inum = inode->i_ino;
else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
- inum = parent_ino(filp->f_dentry);
+ inum = parent_ino(filp->f_path.dentry);
} else {
loff_t i_pos = fat_make_i_pos(sb, bh, de);
struct inode *tmp = fat_iget(sb, i_pos);
@@ -643,7 +643,7 @@ out:
static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
return __fat_readdir(inode, filp, dirent, filldir, 0, 0);
}
@@ -782,7 +782,7 @@ static long fat_compat_dir_ioctl(struct file *file, unsigned cmd,
set_fs(KERNEL_DS);
lock_kernel();
- ret = fat_dir_ioctl(file->f_dentry->d_inode, file,
+ ret = fat_dir_ioctl(file->f_path.dentry->d_inode, file,
cmd, (unsigned long) &d);
unlock_kernel();
set_fs(oldfs);
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 0aa813d944a..c1237b70c1f 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -92,7 +92,7 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
}
/* This MUST be done before doing anything irreversible... */
- err = notify_change(filp->f_dentry, &ia);
+ err = notify_change(filp->f_path.dentry, &ia);
if (err)
goto up;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 4740d35e52c..8e382a5d51b 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -77,10 +77,9 @@ repeat:
start = files->next_fd;
newfd = start;
- if (start < fdt->max_fdset) {
+ if (start < fdt->max_fds)
newfd = find_next_zero_bit(fdt->open_fds->fds_bits,
- fdt->max_fdset, start);
- }
+ fdt->max_fds, start);
error = -EMFILE;
if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
@@ -204,7 +203,7 @@ asmlinkage long sys_dup(unsigned int fildes)
static int setfl(int fd, struct file * filp, unsigned long arg)
{
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode * inode = filp->f_path.dentry->d_inode;
int error = 0;
/*
diff --git a/fs/file.c b/fs/file.c
index 51aef675470..c5575de0111 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -32,46 +32,28 @@ struct fdtable_defer {
*/
static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list);
-
-/*
- * Allocate an fd array, using kmalloc or vmalloc.
- * Note: the array isn't cleared at allocation time.
- */
-struct file ** alloc_fd_array(int num)
+static inline void * alloc_fdmem(unsigned int size)
{
- struct file **new_fds;
- int size = num * sizeof(struct file *);
-
if (size <= PAGE_SIZE)
- new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
- else
- new_fds = (struct file **) vmalloc(size);
- return new_fds;
+ return kmalloc(size, GFP_KERNEL);
+ else
+ return vmalloc(size);
}
-void free_fd_array(struct file **array, int num)
+static inline void free_fdarr(struct fdtable *fdt)
{
- int size = num * sizeof(struct file *);
-
- if (!array) {
- printk (KERN_ERR "free_fd_array: array = 0 (num = %d)\n", num);
- return;
- }
-
- if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */
- return;
- else if (size <= PAGE_SIZE)
- kfree(array);
+ if (fdt->max_fds <= (PAGE_SIZE / sizeof(struct file *)))
+ kfree(fdt->fd);
else
- vfree(array);
+ vfree(fdt->fd);
}
-static void __free_fdtable(struct fdtable *fdt)
+static inline void free_fdset(struct fdtable *fdt)
{
- free_fdset(fdt->open_fds, fdt->max_fdset);
- free_fdset(fdt->close_on_exec, fdt->max_fdset);
- free_fd_array(fdt->fd, fdt->max_fds);
- kfree(fdt);
+ if (fdt->max_fds <= (PAGE_SIZE * BITS_PER_BYTE / 2))
+ kfree(fdt->open_fds);
+ else
+ vfree(fdt->open_fds);
}
static void free_fdtable_work(struct work_struct *work)
@@ -86,41 +68,32 @@ static void free_fdtable_work(struct work_struct *work)
spin_unlock_bh(&f->lock);
while(fdt) {
struct fdtable *next = fdt->next;
- __free_fdtable(fdt);
+ vfree(fdt->fd);
+ free_fdset(fdt);
+ kfree(fdt);
fdt = next;
}
}
-static void free_fdtable_rcu(struct rcu_head *rcu)
+void free_fdtable_rcu(struct rcu_head *rcu)
{
struct fdtable *fdt = container_of(rcu, struct fdtable, rcu);
- int fdset_size, fdarray_size;
struct fdtable_defer *fddef;
BUG_ON(!fdt);
- fdset_size = fdt->max_fdset / 8;
- fdarray_size = fdt->max_fds * sizeof(struct file *);
- if (fdt->free_files) {
+ if (fdt->max_fds <= NR_OPEN_DEFAULT) {
/*
- * The this fdtable was embedded in the files structure
- * and the files structure itself was getting destroyed.
- * It is now safe to free the files structure.
+ * This fdtable is embedded in the files structure and that
+ * structure itself is getting destroyed.
*/
- kmem_cache_free(files_cachep, fdt->free_files);
+ kmem_cache_free(files_cachep,
+ container_of(fdt, struct files_struct, fdtab));
return;
}
- if (fdt->max_fdset <= EMBEDDED_FD_SET_SIZE &&
- fdt->max_fds <= NR_OPEN_DEFAULT) {
- /*
- * The fdtable was embedded
- */
- return;
- }
- if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) {
- kfree(fdt->open_fds);
- kfree(fdt->close_on_exec);
+ if (fdt->max_fds <= (PAGE_SIZE / sizeof(struct file *))) {
kfree(fdt->fd);
+ kfree(fdt->open_fds);
kfree(fdt);
} else {
fddef = &get_cpu_var(fdtable_defer_list);
@@ -134,136 +107,74 @@ static void free_fdtable_rcu(struct rcu_head *rcu)
}
}
-void free_fdtable(struct fdtable *fdt)
-{
- if (fdt->free_files ||
- fdt->max_fdset > EMBEDDED_FD_SET_SIZE ||
- fdt->max_fds > NR_OPEN_DEFAULT)
- call_rcu(&fdt->rcu, free_fdtable_rcu);
-}
-
/*
* Expand the fdset in the files_struct. Called with the files spinlock
* held for write.
*/
-static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt)
+static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt)
{
- int i;
- int count;
-
- BUG_ON(nfdt->max_fdset < fdt->max_fdset);
- BUG_ON(nfdt->max_fds < fdt->max_fds);
- /* Copy the existing tables and install the new pointers */
-
- i = fdt->max_fdset / (sizeof(unsigned long) * 8);
- count = (nfdt->max_fdset - fdt->max_fdset) / 8;
+ unsigned int cpy, set;
- /*
- * Don't copy the entire array if the current fdset is
- * not yet initialised.
- */
- if (i) {
- memcpy (nfdt->open_fds, fdt->open_fds,
- fdt->max_fdset/8);
- memcpy (nfdt->close_on_exec, fdt->close_on_exec,
- fdt->max_fdset/8);
- memset (&nfdt->open_fds->fds_bits[i], 0, count);
- memset (&nfdt->close_on_exec->fds_bits[i], 0, count);
- }
-
- /* Don't copy/clear the array if we are creating a new
- fd array for fork() */
- if (fdt->max_fds) {
- memcpy(nfdt->fd, fdt->fd,
- fdt->max_fds * sizeof(struct file *));
- /* clear the remainder of the array */
- memset(&nfdt->fd[fdt->max_fds], 0,
- (nfdt->max_fds - fdt->max_fds) *
- sizeof(struct file *));
- }
-}
-
-/*
- * Allocate an fdset array, using kmalloc or vmalloc.
- * Note: the array isn't cleared at allocation time.
- */
-fd_set * alloc_fdset(int num)
-{
- fd_set *new_fdset;
- int size = num / 8;
+ BUG_ON(nfdt->max_fds < ofdt->max_fds);
+ if (ofdt->max_fds == 0)
+ return;
- if (size <= PAGE_SIZE)
- new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL);
- else
- new_fdset = (fd_set *) vmalloc(size);
- return new_fdset;
+ cpy = ofdt->max_fds * sizeof(struct file *);
+ set = (nfdt->max_fds - ofdt->max_fds) * sizeof(struct file *);
+ memcpy(nfdt->fd, ofdt->fd, cpy);
+ memset((char *)(nfdt->fd) + cpy, 0, set);
+
+ cpy = ofdt->max_fds / BITS_PER_BYTE;
+ set = (nfdt->max_fds - ofdt->max_fds) / BITS_PER_BYTE;
+ memcpy(nfdt->open_fds, ofdt->open_fds, cpy);
+ memset((char *)(nfdt->open_fds) + cpy, 0, set);
+ memcpy(nfdt->close_on_exec, ofdt->close_on_exec, cpy);
+ memset((char *)(nfdt->close_on_exec) + cpy, 0, set);
}
-void free_fdset(fd_set *array, int num)
+static struct fdtable * alloc_fdtable(unsigned int nr)
{
- if (num <= EMBEDDED_FD_SET_SIZE) /* Don't free an embedded fdset */
- return;
- else if (num <= 8 * PAGE_SIZE)
- kfree(array);
- else
- vfree(array);
-}
+ struct fdtable *fdt;
+ char *data;
-static struct fdtable *alloc_fdtable(int nr)
-{
- struct fdtable *fdt = NULL;
- int nfds = 0;
- fd_set *new_openset = NULL, *new_execset = NULL;
- struct file **new_fds;
+ /*
+ * Figure out how many fds we actually want to support in this fdtable.
+ * Allocation steps are keyed to the size of the fdarray, since it
+ * grows far faster than any of the other dynamic data. We try to fit
+ * the fdarray into comfortable page-tuned chunks: starting at 1024B
+ * and growing in powers of two from there on.
+ */
+ nr /= (1024 / sizeof(struct file *));
+ nr = roundup_pow_of_two(nr + 1);
+ nr *= (1024 / sizeof(struct file *));
+ if (nr > NR_OPEN)
+ nr = NR_OPEN;
- fdt = kzalloc(sizeof(*fdt), GFP_KERNEL);
+ fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL);
if (!fdt)
- goto out;
-
- nfds = max_t(int, 8 * L1_CACHE_BYTES, roundup_pow_of_two(nr + 1));
- if (nfds > NR_OPEN)
- nfds = NR_OPEN;
+ goto out;
+ fdt->max_fds = nr;
+ data = alloc_fdmem(nr * sizeof(struct file *));
+ if (!data)
+ goto out_fdt;
+ fdt->fd = (struct file **)data;
+ data = alloc_fdmem(max_t(unsigned int,
+ 2 * nr / BITS_PER_BYTE, L1_CACHE_BYTES));
+ if (!data)
+ goto out_arr;
+ fdt->open_fds = (fd_set *)data;
+ data += nr / BITS_PER_BYTE;
+ fdt->close_on_exec = (fd_set *)data;
+ INIT_RCU_HEAD(&fdt->rcu);
+ fdt->next = NULL;
- new_openset = alloc_fdset(nfds);
- new_execset = alloc_fdset(nfds);
- if (!new_openset || !new_execset)
- goto out;
- fdt->open_fds = new_openset;
- fdt->close_on_exec = new_execset;
- fdt->max_fdset = nfds;
-
- nfds = NR_OPEN_DEFAULT;
- /*
- * Expand to the max in easy steps, and keep expanding it until
- * we have enough for the requested fd array size.
- */
- do {
-#if NR_OPEN_DEFAULT < 256
- if (nfds < 256)
- nfds = 256;
- else
-#endif
- if (nfds < (PAGE_SIZE / sizeof(struct file *)))
- nfds = PAGE_SIZE / sizeof(struct file *);
- else {
- nfds = nfds * 2;
- if (nfds > NR_OPEN)
- nfds = NR_OPEN;
- }
- } while (nfds <= nr);
- new_fds = alloc_fd_array(nfds);
- if (!new_fds)
- goto out2;
- fdt->fd = new_fds;
- fdt->max_fds = nfds;
- fdt->free_files = NULL;
return fdt;
-out2:
- nfds = fdt->max_fdset;
-out:
- free_fdset(new_openset, nfds);
- free_fdset(new_execset, nfds);
+
+out_arr:
+ free_fdarr(fdt);
+out_fdt:
kfree(fdt);
+out:
return NULL;
}
@@ -290,14 +201,17 @@ static int expand_fdtable(struct files_struct *files, int nr)
* we dropped the lock
*/
cur_fdt = files_fdtable(files);
- if (nr >= cur_fdt->max_fds || nr >= cur_fdt->max_fdset) {
+ if (nr >= cur_fdt->max_fds) {
/* Continue as planned */
copy_fdtable(new_fdt, cur_fdt);
rcu_assign_pointer(files->fdt, new_fdt);
- free_fdtable(cur_fdt);
+ if (cur_fdt->max_fds > NR_OPEN_DEFAULT)
+ free_fdtable(cur_fdt);
} else {
/* Somebody else expanded, so undo our attempt */
- __free_fdtable(new_fdt);
+ free_fdarr(new_fdt);
+ free_fdset(new_fdt);
+ kfree(new_fdt);
}
return 1;
}
@@ -316,11 +230,10 @@ int expand_files(struct files_struct *files, int nr)
fdt = files_fdtable(files);
/* Do we need to expand? */
- if (nr < fdt->max_fdset && nr < fdt->max_fds)
+ if (nr < fdt->max_fds)
return 0;
/* Can we expand? */
- if (fdt->max_fdset >= NR_OPEN || fdt->max_fds >= NR_OPEN ||
- nr >= NR_OPEN)
+ if (nr >= NR_OPEN)
return -EMFILE;
/* All good, so we try */
diff --git a/fs/file_table.c b/fs/file_table.c
index 24f25a057d9..4c17a18d8c1 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -152,8 +152,8 @@ EXPORT_SYMBOL(fput);
*/
void fastcall __fput(struct file *file)
{
- struct dentry *dentry = file->f_dentry;
- struct vfsmount *mnt = file->f_vfsmnt;
+ struct dentry *dentry = file->f_path.dentry;
+ struct vfsmount *mnt = file->f_path.mnt;
struct inode *inode = dentry->d_inode;
might_sleep();
@@ -176,8 +176,8 @@ void fastcall __fput(struct file *file)
put_write_access(inode);
put_pid(file->f_owner.pid);
file_kill(file);
- file->f_dentry = NULL;
- file->f_vfsmnt = NULL;
+ file->f_path.dentry = NULL;
+ file->f_path.mnt = NULL;
file_free(file);
dput(dentry);
mntput(mnt);
@@ -271,7 +271,7 @@ int fs_may_remount_ro(struct super_block *sb)
file_list_lock();
list_for_each(p, &sb->s_files) {
struct file *file = list_entry(p, struct file, f_u.fu_list);
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
/* File with pending delete? */
if (inode->i_nlink == 0)
diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c
index 43886fa00a2..3995d7fbeda 100644
--- a/fs/freevxfs/vxfs_lookup.c
+++ b/fs/freevxfs/vxfs_lookup.c
@@ -240,7 +240,7 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd)
static int
vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
{
- struct inode *ip = fp->f_dentry->d_inode;
+ struct inode *ip = fp->f_path.dentry->d_inode;
struct super_block *sbp = ip->i_sb;
u_long bsize = sbp->s_blocksize;
u_long page, npages, block, pblocks, nblocks, offset;
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index c403b66ec83..a4b142a6a2c 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -251,8 +251,19 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
WARN_ON(inode->i_state & I_WILL_FREE);
if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_LOCK)) {
+ struct address_space *mapping = inode->i_mapping;
+ int ret;
+
list_move(&inode->i_list, &inode->i_sb->s_dirty);
- return 0;
+
+ /*
+ * Even if we don't actually write the inode itself here,
+ * we can at least start some of the data writeout..
+ */
+ spin_unlock(&inode_lock);
+ ret = do_writepages(mapping, wbc);
+ spin_lock(&inode_lock);
+ return ret;
}
/*
diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index 16b39c053d4..1794305f9ed 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->i_private;
+ fc = file->f_path.dentry->d_inode->i_private;
if (fc)
fc = fuse_conn_get(fc);
mutex_unlock(&fuse_mutex);
@@ -193,8 +193,12 @@ static int fuse_ctl_get_sb(struct file_system_type *fs_type, int flags,
static void fuse_ctl_kill_sb(struct super_block *sb)
{
+ struct fuse_conn *fc;
+
mutex_lock(&fuse_mutex);
fuse_control_sb = NULL;
+ list_for_each_entry(fc, &fuse_conn_list, entry)
+ fc->ctl_ndents = 0;
mutex_unlock(&fuse_mutex);
kill_litter_super(sb);
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 1cabdb229ad..40080477ceb 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -856,7 +856,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
int err;
size_t nbytes;
struct page *page;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 128f79c4080..f63efe1337e 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -141,8 +141,8 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir)
isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
/* Hold vfsmount and dentry until release is finished */
- req->vfsmount = mntget(file->f_vfsmnt);
- req->dentry = dget(file->f_dentry);
+ req->vfsmount = mntget(file->f_path.mnt);
+ req->dentry = dget(file->f_path.dentry);
request_send_background(fc, req);
}
@@ -184,7 +184,7 @@ static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id)
static int fuse_flush(struct file *file, fl_owner_t id)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data;
struct fuse_req *req;
@@ -483,10 +483,8 @@ static int fuse_commit_write(struct file *file, struct page *page,
i_size_write(inode, pos);
spin_unlock(&fc->lock);
- if (offset == 0 && to == PAGE_CACHE_SIZE) {
- clear_page_dirty(page);
+ if (offset == 0 && to == PAGE_CACHE_SIZE)
SetPageUptodate(page);
- }
}
fuse_invalidate_attr(inode);
return err;
@@ -533,7 +531,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
size_t count, loff_t *ppos, int write)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
size_t nmax = write ? fc->max_write : fc->max_read;
loff_t pos = *ppos;
@@ -607,7 +605,7 @@ static ssize_t fuse_direct_read(struct file *file, char __user *buf,
static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
ssize_t res;
/* Don't allow parallel writes to the same file */
mutex_lock(&inode->i_mutex);
@@ -662,7 +660,7 @@ static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
static void fuse_lk_fill(struct fuse_req *req, struct file *file,
const struct file_lock *fl, int opcode, pid_t pid)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data;
struct fuse_lk_in *arg = &req->misc.lk_in;
@@ -682,7 +680,7 @@ static void fuse_lk_fill(struct fuse_req *req, struct file *file,
static int fuse_getlk(struct file *file, struct file_lock *fl)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_lk_out outarg;
@@ -707,7 +705,7 @@ static int fuse_getlk(struct file *file, struct file_lock *fl)
static int fuse_setlk(struct file *file, struct file_lock *fl)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
@@ -734,7 +732,7 @@ static int fuse_setlk(struct file *file, struct file_lock *fl)
static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
int err;
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig
index c0791cbacad..de8e64c03f7 100644
--- a/fs/gfs2/Kconfig
+++ b/fs/gfs2/Kconfig
@@ -4,42 +4,43 @@ config GFS2_FS
select FS_POSIX_ACL
select CRC32
help
- A cluster filesystem.
+ 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.
+ 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
+ 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.
+ 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.
+ 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.
+ 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
+ depends on GFS2_FS && SYSFS && NET && INET && (IPV6 || IPV6=n)
+ select IP_SCTP if DLM_SCTP
+ select CONFIGFS_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.
+ 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/bmap.c b/fs/gfs2/bmap.c
index 8240c1ff94f..113f6c9110c 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -773,7 +773,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
gfs2_free_data(ip, bstart, blen);
}
- ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_dinode_out(ip, dibh->b_data);
@@ -848,7 +848,7 @@ static int do_grow(struct gfs2_inode *ip, u64 size)
}
ip->i_di.di_size = size;
- ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
@@ -963,7 +963,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size)
if (gfs2_is_stuffed(ip)) {
ip->i_di.di_size = size;
- ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size);
@@ -975,7 +975,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size)
if (!error) {
ip->i_di.di_size = size;
- ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
ip->i_di.di_flags |= GFS2_DIF_TRUNC_IN_PROG;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
@@ -1048,7 +1048,7 @@ static int trunc_end(struct gfs2_inode *ip)
ip->i_num.no_addr;
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
}
- ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
ip->i_di.di_flags &= ~GFS2_DIF_TRUNC_IN_PROG;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 0fdcb7713cd..c93ca8f361b 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -131,7 +131,7 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf,
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_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
@@ -229,7 +229,7 @@ out:
if (ip->i_di.di_size < offset + copied)
ip->i_di.di_size = offset + copied;
- ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
@@ -1198,12 +1198,11 @@ static int compare_dents(const void *a, const void *b)
*/
static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
- void *opaque, gfs2_filldir_t filldir,
+ void *opaque, filldir_t filldir,
const struct gfs2_dirent **darr, u32 entries,
int *copied)
{
const struct gfs2_dirent *dent, *dent_next;
- struct gfs2_inum_host inum;
u64 off, off_next;
unsigned int x, y;
int run = 0;
@@ -1240,11 +1239,9 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
*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,
+ off, be64_to_cpu(dent->de_inum.no_addr),
be16_to_cpu(dent->de_type));
if (error)
return 1;
@@ -1262,8 +1259,8 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
}
static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
- gfs2_filldir_t filldir, int *copied,
- unsigned *depth, u64 leaf_no)
+ filldir_t filldir, int *copied, unsigned *depth,
+ u64 leaf_no)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct buffer_head *bh;
@@ -1343,7 +1340,7 @@ out:
*/
static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
- gfs2_filldir_t filldir)
+ filldir_t filldir)
{
struct gfs2_inode *dip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
@@ -1402,7 +1399,7 @@ out:
}
int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
- gfs2_filldir_t filldir)
+ filldir_t filldir)
{
struct gfs2_inode *dip = GFS2_I(inode);
struct dirent_gather g;
@@ -1568,7 +1565,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name,
break;
gfs2_trans_add_bh(ip->i_gl, bh, 1);
ip->i_di.di_entries++;
- ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_dinode_out(ip, bh->b_data);
brelse(bh);
error = 0;
@@ -1654,7 +1651,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name)
gfs2_consist_inode(dip);
gfs2_trans_add_bh(dip->i_gl, bh, 1);
dip->i_di.di_entries--;
- dip->i_inode.i_mtime.tv_sec = dip->i_inode.i_ctime.tv_sec = get_seconds();
+ dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_dinode_out(dip, bh->b_data);
brelse(bh);
mark_inode_dirty(&dip->i_inode);
@@ -1702,7 +1699,7 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
gfs2_trans_add_bh(dip->i_gl, bh, 1);
}
- dip->i_inode.i_mtime.tv_sec = dip->i_inode.i_ctime.tv_sec = get_seconds();
+ dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_dinode_out(dip, bh->b_data);
brelse(bh);
return 0;
diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h
index b21b33668a5..48fe89046bb 100644
--- a/fs/gfs2/dir.h
+++ b/fs/gfs2/dir.h
@@ -16,30 +16,13 @@ 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_host *inum, unsigned int type);
-
int gfs2_dir_search(struct inode *dir, const struct qstr *filename,
struct gfs2_inum_host *inum, unsigned int *type);
int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
const struct gfs2_inum_host *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_read(struct inode *inode, u64 *offset, void *opaque,
+ filldir_t filldir);
int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
struct gfs2_inum_host *new_inum, unsigned int new_type);
diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c
index ebebbdcd705..0c83c7f4dda 100644
--- a/fs/gfs2/eattr.c
+++ b/fs/gfs2/eattr.c
@@ -301,7 +301,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
- ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
@@ -718,7 +718,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
(er->er_mode & S_IFMT));
ip->i_inode.i_mode = er->er_mode;
}
- ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
@@ -853,7 +853,7 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh,
(ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT));
ip->i_inode.i_mode = er->er_mode;
}
- ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
@@ -1134,7 +1134,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
- ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 438146904b5..6618c119025 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -19,6 +19,8 @@
#include <linux/gfs2_ondisk.h>
#include <linux/list.h>
#include <linux/lm_interface.h>
+#include <linux/wait.h>
+#include <linux/rwsem.h>
#include <asm/uaccess.h>
#include "gfs2.h"
@@ -33,11 +35,6 @@
#include "super.h"
#include "util.h"
-struct greedy {
- struct gfs2_holder gr_gh;
- struct delayed_work gr_work;
-};
-
struct gfs2_gl_hash_bucket {
struct hlist_head hb_list;
};
@@ -47,6 +44,9 @@ 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);
+static void gfs2_glock_xmote_th(struct gfs2_holder *gh);
+static void gfs2_glock_drop_th(struct gfs2_glock *gl);
+static DECLARE_RWSEM(gfs2_umount_flush_sem);
#define GFS2_GL_HASH_SHIFT 15
#define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT)
@@ -213,30 +213,6 @@ out:
}
/**
- * 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
@@ -395,11 +371,6 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
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);
}
@@ -417,9 +388,6 @@ void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *
{
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);
}
@@ -479,6 +447,29 @@ static void gfs2_holder_put(struct gfs2_holder *gh)
kfree(gh);
}
+static void gfs2_holder_dispose_or_wake(struct gfs2_holder *gh)
+{
+ if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) {
+ gfs2_holder_put(gh);
+ return;
+ }
+ clear_bit(HIF_WAIT, &gh->gh_iflags);
+ smp_mb();
+ wake_up_bit(&gh->gh_iflags, HIF_WAIT);
+}
+
+static int holder_wait(void *word)
+{
+ schedule();
+ return 0;
+}
+
+static void wait_on_holder(struct gfs2_holder *gh)
+{
+ might_sleep();
+ wait_on_bit(&gh->gh_iflags, HIF_WAIT, holder_wait, TASK_UNINTERRUPTIBLE);
+}
+
/**
* rq_mutex - process a mutex request in the queue
* @gh: the glock holder
@@ -493,7 +484,9 @@ static int rq_mutex(struct gfs2_holder *gh)
list_del_init(&gh->gh_list);
/* gh->gh_error never examined. */
set_bit(GLF_LOCK, &gl->gl_flags);
- complete(&gh->gh_wait);
+ clear_bit(HIF_WAIT, &gh->gh_iflags);
+ smp_mb();
+ wake_up_bit(&gh->gh_iflags, HIF_WAIT);
return 1;
}
@@ -511,7 +504,6 @@ 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)) {
@@ -526,7 +518,7 @@ static int rq_promote(struct gfs2_holder *gh)
gfs2_reclaim_glock(sdp);
}
- glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
+ gfs2_glock_xmote_th(gh);
spin_lock(&gl->gl_spin);
}
return 1;
@@ -537,11 +529,11 @@ static int rq_promote(struct gfs2_holder *gh)
set_bit(GLF_LOCK, &gl->gl_flags);
} else {
struct gfs2_holder *next_gh;
- if (gh->gh_flags & GL_LOCAL_EXCL)
+ if (gh->gh_state == LM_ST_EXCLUSIVE)
return 1;
next_gh = list_entry(gl->gl_holders.next, struct gfs2_holder,
gh_list);
- if (next_gh->gh_flags & GL_LOCAL_EXCL)
+ if (next_gh->gh_state == LM_ST_EXCLUSIVE)
return 1;
}
@@ -549,7 +541,7 @@ static int rq_promote(struct gfs2_holder *gh)
gh->gh_error = 0;
set_bit(HIF_HOLDER, &gh->gh_iflags);
- complete(&gh->gh_wait);
+ gfs2_holder_dispose_or_wake(gh);
return 0;
}
@@ -564,7 +556,6 @@ static int rq_promote(struct gfs2_holder *gh)
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;
@@ -573,10 +564,7 @@ static int rq_demote(struct gfs2_holder *gh)
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);
+ gfs2_holder_dispose_or_wake(gh);
spin_lock(&gl->gl_spin);
} else {
gl->gl_req_gh = gh;
@@ -585,9 +573,9 @@ static int rq_demote(struct gfs2_holder *gh)
if (gh->gh_state == LM_ST_UNLOCKED ||
gl->gl_state != LM_ST_EXCLUSIVE)
- glops->go_drop_th(gl);
+ gfs2_glock_drop_th(gl);
else
- glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
+ gfs2_glock_xmote_th(gh);
spin_lock(&gl->gl_spin);
}
@@ -596,30 +584,6 @@ static int rq_demote(struct gfs2_holder *gh)
}
/**
- * 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
*
@@ -649,8 +613,6 @@ static void run_queue(struct gfs2_glock *gl)
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);
@@ -684,6 +646,8 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
gfs2_holder_init(gl, 0, 0, &gh);
set_bit(HIF_MUTEX, &gh.gh_iflags);
+ if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags))
+ BUG();
spin_lock(&gl->gl_spin);
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
@@ -691,11 +655,13 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
} else {
gl->gl_owner = current;
gl->gl_ip = (unsigned long)__builtin_return_address(0);
- complete(&gh.gh_wait);
+ clear_bit(HIF_WAIT, &gh.gh_iflags);
+ smp_mb();
+ wake_up_bit(&gh.gh_iflags, HIF_WAIT);
}
spin_unlock(&gl->gl_spin);
- wait_for_completion(&gh.gh_wait);
+ wait_on_holder(&gh);
gfs2_holder_uninit(&gh);
}
@@ -774,6 +740,7 @@ restart:
return;
set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
+ set_bit(HIF_WAIT, &new_gh->gh_iflags);
goto restart;
}
@@ -825,7 +792,7 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
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, list_empty(&gl->gl_holders));
gfs2_assert_warn(sdp, !(ret & LM_OUT_ASYNC));
state_change(gl, ret & LM_OUT_ST_MASK);
@@ -908,12 +875,8 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
gfs2_glock_put(gl);
- if (gh) {
- if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
- gfs2_holder_put(gh);
- else
- complete(&gh->gh_wait);
- }
+ if (gh)
+ gfs2_holder_dispose_or_wake(gh);
}
/**
@@ -924,23 +887,26 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
*
*/
-void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags)
+void gfs2_glock_xmote_th(struct gfs2_holder *gh)
{
+ struct gfs2_glock *gl = gh->gh_gl;
struct gfs2_sbd *sdp = gl->gl_sbd;
+ int flags = gh->gh_flags;
+ unsigned state = gh->gh_state;
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;
+ if (glops->go_xmote_th)
+ glops->go_xmote_th(gl);
+
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, list_empty(&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);
-
gfs2_glock_hold(gl);
gl->gl_req_bh = xmote_bh;
@@ -971,10 +937,8 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
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, list_empty(&gl->gl_holders));
gfs2_assert_warn(sdp, !ret);
state_change(gl, LM_ST_UNLOCKED);
@@ -1001,12 +965,8 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
gfs2_glock_put(gl);
- if (gh) {
- if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
- gfs2_holder_put(gh);
- else
- complete(&gh->gh_wait);
- }
+ if (gh)
+ gfs2_holder_dispose_or_wake(gh);
}
/**
@@ -1015,19 +975,19 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
*
*/
-void gfs2_glock_drop_th(struct gfs2_glock *gl)
+static 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;
+ if (glops->go_drop_th)
+ glops->go_drop_th(gl);
+
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, list_empty(&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);
-
gfs2_glock_hold(gl);
gl->gl_req_bh = drop_bh;
@@ -1107,8 +1067,7 @@ static int glock_wait_internal(struct gfs2_holder *gh)
if (gh->gh_flags & LM_FLAG_PRIORITY)
do_cancels(gh);
- wait_for_completion(&gh->gh_wait);
-
+ wait_on_holder(gh);
if (gh->gh_error)
return gh->gh_error;
@@ -1164,6 +1123,8 @@ static void add_to_queue(struct gfs2_holder *gh)
struct gfs2_holder *existing;
BUG_ON(!gh->gh_owner);
+ if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
+ BUG();
existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
if (existing) {
@@ -1227,8 +1188,6 @@ restart:
}
}
- clear_bit(GLF_PREFETCH, &gl->gl_flags);
-
return error;
}
@@ -1321,98 +1280,6 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
}
/**
- * 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(struct work_struct *work)
-{
- struct greedy *gr = container_of(work, struct greedy, gr_work.work);
- 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_DELAYED_WORK(&gr->gr_work, greedy_work);
-
- 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
*
@@ -1470,10 +1337,7 @@ static int glock_compare(const void *arg_a, const void *arg_b)
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;
+ BUG_ON(gh_a->gh_gl->gl_ops->go_type == gh_b->gh_gl->gl_ops->go_type);
return 0;
}
@@ -1618,34 +1482,6 @@ void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs)
}
/**
- * 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
*
@@ -1703,8 +1539,6 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *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);
@@ -1746,12 +1580,14 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)
struct lm_async_cb *async = data;
struct gfs2_glock *gl;
+ down_read(&gfs2_umount_flush_sem);
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);
+ up_read(&gfs2_umount_flush_sem);
return;
}
@@ -1781,15 +1617,11 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)
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);
@@ -1845,7 +1677,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp)
atomic_inc(&sdp->sd_reclaimed);
if (gfs2_glmutex_trylock(gl)) {
- if (queue_empty(gl, &gl->gl_holders) &&
+ if (list_empty(&gl->gl_holders) &&
gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
handle_callback(gl, LM_ST_UNLOCKED);
gfs2_glmutex_unlock(gl);
@@ -1909,7 +1741,7 @@ static void scan_glock(struct gfs2_glock *gl)
return;
if (gfs2_glmutex_trylock(gl)) {
- if (queue_empty(gl, &gl->gl_holders) &&
+ if (list_empty(&gl->gl_holders) &&
gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
goto out_schedule;
gfs2_glmutex_unlock(gl);
@@ -1958,7 +1790,7 @@ static void clear_glock(struct gfs2_glock *gl)
}
if (gfs2_glmutex_trylock(gl)) {
- if (queue_empty(gl, &gl->gl_holders) &&
+ if (list_empty(&gl->gl_holders) &&
gl->gl_state != LM_ST_UNLOCKED)
handle_callback(gl, LM_ST_UNLOCKED);
gfs2_glmutex_unlock(gl);
@@ -2000,7 +1832,9 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
t = jiffies;
}
+ down_write(&gfs2_umount_flush_sem);
invalidate_inodes(sdp->sd_vfs);
+ up_write(&gfs2_umount_flush_sem);
msleep(10);
}
}
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index fb39108fc05..f50e40ceca4 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -20,7 +20,6 @@
#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
@@ -83,17 +82,11 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
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,
@@ -103,10 +96,6 @@ 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);
-
/**
* gfs2_glock_nq_init - intialize a holder and enqueue it on a glock
* @gl: the glock
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index b068d10bcb6..c4b0391b7aa 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -117,12 +117,14 @@ static void gfs2_pte_inval(struct gfs2_glock *gl)
static void meta_go_sync(struct gfs2_glock *gl)
{
+ if (gl->gl_state != LM_ST_EXCLUSIVE)
+ return;
+
if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) {
gfs2_log_flush(gl->gl_sbd, gl);
gfs2_meta_sync(gl);
gfs2_ail_empty_gl(gl);
}
-
}
/**
@@ -142,6 +144,37 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags)
}
/**
+ * inode_go_sync - Sync the dirty data and/or metadata for an inode glock
+ * @gl: the glock protecting the inode
+ *
+ */
+
+static void inode_go_sync(struct gfs2_glock *gl)
+{
+ struct gfs2_inode *ip = gl->gl_object;
+
+ if (ip && !S_ISREG(ip->i_inode.i_mode))
+ ip = NULL;
+
+ if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
+ gfs2_log_flush(gl->gl_sbd, gl);
+ if (ip)
+ filemap_fdatawrite(ip->i_inode.i_mapping);
+ gfs2_meta_sync(gl);
+ if (ip) {
+ struct address_space *mapping = ip->i_inode.i_mapping;
+ int error = filemap_fdatawait(mapping);
+ if (error == -ENOSPC)
+ set_bit(AS_ENOSPC, &mapping->flags);
+ else if (error)
+ set_bit(AS_EIO, &mapping->flags);
+ }
+ clear_bit(GLF_DIRTY, &gl->gl_flags);
+ gfs2_ail_empty_gl(gl);
+ }
+}
+
+/**
* inode_go_xmote_th - promote/demote a glock
* @gl: the glock
* @state: the requested state
@@ -149,12 +182,12 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags)
*
*/
-static void inode_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
- int flags)
+static void inode_go_xmote_th(struct gfs2_glock *gl)
{
if (gl->gl_state != LM_ST_UNLOCKED)
gfs2_pte_inval(gl);
- gfs2_glock_xmote_th(gl, state, flags);
+ if (gl->gl_state == LM_ST_EXCLUSIVE)
+ inode_go_sync(gl);
}
/**
@@ -189,38 +222,8 @@ static void inode_go_xmote_bh(struct gfs2_glock *gl)
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
- *
- */
-
-static void inode_go_sync(struct gfs2_glock *gl)
-{
- struct gfs2_inode *ip = gl->gl_object;
-
- if (ip && !S_ISREG(ip->i_inode.i_mode))
- ip = NULL;
-
- if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
- gfs2_log_flush(gl->gl_sbd, gl);
- if (ip)
- filemap_fdatawrite(ip->i_inode.i_mapping);
- gfs2_meta_sync(gl);
- if (ip) {
- struct address_space *mapping = ip->i_inode.i_mapping;
- int error = filemap_fdatawait(mapping);
- if (error == -ENOSPC)
- set_bit(AS_ENOSPC, &mapping->flags);
- else if (error)
- set_bit(AS_EIO, &mapping->flags);
- }
- clear_bit(GLF_DIRTY, &gl->gl_flags);
- gfs2_ail_empty_gl(gl);
- }
+ if (gl->gl_state == LM_ST_EXCLUSIVE)
+ inode_go_sync(gl);
}
/**
@@ -295,7 +298,7 @@ static int inode_go_lock(struct gfs2_holder *gh)
if ((ip->i_di.di_flags & GFS2_DIF_TRUNC_IN_PROG) &&
(gl->gl_state == LM_ST_EXCLUSIVE) &&
- (gh->gh_flags & GL_LOCAL_EXCL))
+ (gh->gh_state == LM_ST_EXCLUSIVE))
error = gfs2_truncatei_resume(ip);
return error;
@@ -319,39 +322,6 @@ static void inode_go_unlock(struct gfs2_holder *gh)
}
/**
- * 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
*
@@ -398,8 +368,7 @@ static void rgrp_go_unlock(struct gfs2_holder *gh)
*
*/
-static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
- int flags)
+static void trans_go_xmote_th(struct gfs2_glock *gl)
{
struct gfs2_sbd *sdp = gl->gl_sbd;
@@ -408,8 +377,6 @@ static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
gfs2_meta_syncfs(sdp);
gfs2_log_shutdown(sdp);
}
-
- gfs2_glock_xmote_th(gl, state, flags);
}
/**
@@ -461,8 +428,6 @@ static void trans_go_drop_th(struct gfs2_glock *gl)
gfs2_meta_syncfs(sdp);
gfs2_log_shutdown(sdp);
}
-
- gfs2_glock_drop_th(gl);
}
/**
@@ -478,8 +443,8 @@ static int quota_go_demote_ok(struct gfs2_glock *gl)
}
const struct gfs2_glock_operations gfs2_meta_glops = {
- .go_xmote_th = gfs2_glock_xmote_th,
- .go_drop_th = gfs2_glock_drop_th,
+ .go_xmote_th = meta_go_sync,
+ .go_drop_th = meta_go_sync,
.go_type = LM_TYPE_META,
};
@@ -487,19 +452,14 @@ 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,
@@ -515,33 +475,23 @@ const struct gfs2_glock_operations gfs2_trans_glops = {
};
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/incore.h b/fs/gfs2/incore.h
index 734421edae8..12c80fd28db 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -101,17 +101,14 @@ struct gfs2_bufdata {
};
struct gfs2_glock_operations {
- void (*go_xmote_th) (struct gfs2_glock *gl, unsigned int state, int flags);
+ void (*go_xmote_th) (struct gfs2_glock *gl);
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);
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;
};
@@ -120,7 +117,6 @@ enum {
HIF_MUTEX = 0,
HIF_PROMOTE = 1,
HIF_DEMOTE = 2,
- HIF_GREEDY = 3,
/* States */
HIF_ALLOCED = 4,
@@ -128,6 +124,7 @@ enum {
HIF_HOLDER = 6,
HIF_FIRST = 7,
HIF_ABORTED = 9,
+ HIF_WAIT = 10,
};
struct gfs2_holder {
@@ -140,17 +137,14 @@ struct gfs2_holder {
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 {
@@ -167,7 +161,7 @@ struct gfs2_glock {
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_waiters2; /* HIF_DEMOTE */
struct list_head gl_waiters3; /* HIF_PROMOTE */
const struct gfs2_glock_operations *gl_ops;
@@ -236,7 +230,6 @@ struct gfs2_inode {
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];
@@ -418,17 +411,12 @@ struct gfs2_tune {
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;
};
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index d122074c45e..0d6831a4056 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -287,10 +287,8 @@ out:
*
* 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;
@@ -315,42 +313,34 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
else
drop_nlink(&ip->i_inode);
- ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
mark_inode_dirty(&ip->i_inode);
- if (ip->i_inode.i_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;
-
+ if (ip->i_inode.i_nlink == 0)
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;
+ struct inode *inode;
gfs2_str2qstr(&qstr, name);
- return gfs2_lookupi(dip, &qstr, 1, NULL);
+ inode = gfs2_lookupi(dip, &qstr, 1, NULL);
+ /* gfs2_lookupi has inconsistent callers: vfs
+ * related routines expect NULL for no entry found,
+ * gfs2_lookup_simple callers expect ENOENT
+ * and do not check for NULL.
+ */
+ if (inode == NULL)
+ return ERR_PTR(-ENOENT);
+ else
+ return inode;
}
@@ -361,8 +351,10 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
* @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.
+ * This can be called via the VFS filldir function when NFS is doing
+ * a readdirplus and the inode which its intending to stat isn't
+ * already in cache. In this case we must not take the directory glock
+ * again, since the readdir call will have already taken that lock.
*
* Returns: errno
*/
@@ -375,8 +367,9 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
struct gfs2_holder d_gh;
struct gfs2_inum_host inum;
unsigned int type;
- int error = 0;
+ int error;
struct inode *inode = NULL;
+ int unlock = 0;
if (!name->len || name->len > GFS2_FNAMESIZE)
return ERR_PTR(-ENAMETOOLONG);
@@ -388,9 +381,12 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
return dir;
}
- error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
- if (error)
- return ERR_PTR(error);
+ if (gfs2_glock_is_locked_by_me(dip->i_gl) == 0) {
+ error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+ if (error)
+ return ERR_PTR(error);
+ unlock = 1;
+ }
if (!is_root) {
error = permission(dir, MAY_EXEC, NULL);
@@ -405,10 +401,11 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
inode = gfs2_inode_lookup(sb, &inum, type);
out:
- gfs2_glock_dq_uninit(&d_gh);
+ if (unlock)
+ gfs2_glock_dq_uninit(&d_gh);
if (error == -ENOENT)
return NULL;
- return inode;
+ return inode ? inode : ERR_PTR(error);
}
static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino)
diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c
index effe4a337c1..e30673dd37e 100644
--- a/fs/gfs2/lm.c
+++ b/fs/gfs2/lm.c
@@ -104,15 +104,9 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
vprintk(fmt, args);
va_end(args);
- fs_err(sdp, "about to withdraw from the cluster\n");
+ fs_err(sdp, "about to withdraw this file system\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");
diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h
index 33af707a4d3..a87c7bf3c56 100644
--- a/fs/gfs2/locking/dlm/lock_dlm.h
+++ b/fs/gfs2/locking/dlm/lock_dlm.h
@@ -36,7 +36,7 @@
#define GDLM_STRNAME_BYTES 24
#define GDLM_LVB_SIZE 32
-#define GDLM_DROP_COUNT 50000
+#define GDLM_DROP_COUNT 200000
#define GDLM_DROP_PERIOD 60
#define GDLM_NAME_LEN 128
diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c
index 2194b1d5b5e..a0e7eda643e 100644
--- a/fs/gfs2/locking/dlm/main.c
+++ b/fs/gfs2/locking/dlm/main.c
@@ -11,9 +11,6 @@
#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)
@@ -40,9 +37,6 @@ static int __init init_lock_dlm(void)
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;
diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c
index cdd1694e889..1d8faa3da8a 100644
--- a/fs/gfs2/locking/dlm/mount.c
+++ b/fs/gfs2/locking/dlm/mount.c
@@ -9,8 +9,6 @@
#include "lock_dlm.h"
-int gdlm_drop_count;
-int gdlm_drop_period;
const struct lm_lockops gdlm_ops;
@@ -24,8 +22,8 @@ static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp,
if (!ls)
return NULL;
- ls->drop_locks_count = gdlm_drop_count;
- ls->drop_locks_period = gdlm_drop_period;
+ ls->drop_locks_count = GDLM_DROP_COUNT;
+ ls->drop_locks_period = GDLM_DROP_PERIOD;
ls->fscb = cb;
ls->sdp = sdp;
ls->fsflags = flags;
diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
index 29ae06f9494..4746b884662 100644
--- a/fs/gfs2/locking/dlm/sysfs.c
+++ b/fs/gfs2/locking/dlm/sysfs.c
@@ -116,6 +116,17 @@ static ssize_t recover_status_show(struct gdlm_ls *ls, char *buf)
return sprintf(buf, "%d\n", ls->recover_jid_status);
}
+static ssize_t drop_count_show(struct gdlm_ls *ls, char *buf)
+{
+ return sprintf(buf, "%d\n", ls->drop_locks_count);
+}
+
+static ssize_t drop_count_store(struct gdlm_ls *ls, const char *buf, size_t len)
+{
+ ls->drop_locks_count = simple_strtol(buf, NULL, 0);
+ return len;
+}
+
struct gdlm_attr {
struct attribute attr;
ssize_t (*show)(struct gdlm_ls *, char *);
@@ -135,6 +146,7 @@ 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);
+GDLM_ATTR(drop_count, 0644, drop_count_show, drop_count_store);
static struct attribute *gdlm_attrs[] = {
&gdlm_attr_proto_name.attr,
@@ -147,6 +159,7 @@ static struct attribute *gdlm_attrs[] = {
&gdlm_attr_recover.attr,
&gdlm_attr_recover_done.attr,
&gdlm_attr_recover_status.attr,
+ &gdlm_attr_drop_count.attr,
NULL,
};
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 4d7f94d8c7b..16bb4b4561a 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -69,13 +69,16 @@ 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))
+ gfs2_log_lock(sdp);
+ if (!list_empty(&bd->bd_list_tr)) {
+ gfs2_log_unlock(sdp);
return;
-
+ }
tr = current->journal_info;
tr->tr_touched = 1;
tr->tr_num_buf++;
list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+ gfs2_log_unlock(sdp);
if (!list_empty(&le->le_list))
return;
@@ -84,7 +87,6 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
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);
@@ -98,11 +100,13 @@ 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;
+ gfs2_log_lock(sdp);
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_log_unlock(sdp);
gfs2_assert_warn(sdp, !tr->tr_num_buf);
}
@@ -462,13 +466,17 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
struct address_space *mapping = bd->bd_bh->b_page->mapping;
struct gfs2_inode *ip = GFS2_I(mapping->host);
+ gfs2_log_lock(sdp);
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_log_unlock(sdp);
gfs2_pin(sdp, bd->bd_bh);
tr->tr_num_buf_new++;
+ } else {
+ gfs2_log_unlock(sdp);
}
gfs2_trans_add_gl(bd->bd_gl);
gfs2_log_lock(sdp);
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index d8d69a72a10..56e33590b65 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -16,6 +16,7 @@
#include <linux/pagevec.h>
#include <linux/mpage.h>
#include <linux/fs.h>
+#include <linux/writeback.h>
#include <linux/gfs2_ondisk.h>
#include <linux/lm_interface.h>
@@ -157,6 +158,32 @@ out_ignore:
}
/**
+ * gfs2_writepages - Write a bunch of dirty pages back to disk
+ * @mapping: The mapping to write
+ * @wbc: Write-back control
+ *
+ * For journaled files and/or ordered writes this just falls back to the
+ * kernel's default writepages path for now. We will probably want to change
+ * that eventually (i.e. when we look at allocate on flush).
+ *
+ * For the data=writeback case though we can already ignore buffer heads
+ * and write whole extents at once. This is a big reduction in the
+ * number of I/O requests we send and the bmap calls we make in this case.
+ */
+static int gfs2_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
+{
+ struct inode *inode = mapping->host;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+
+ if (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK && !gfs2_is_jdata(ip))
+ return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
+
+ return generic_writepages(mapping, wbc);
+}
+
+/**
* stuffed_readpage - Fill in a Linux page with stuffed file data
* @ip: the inode
* @page: the page
@@ -256,7 +283,7 @@ out_unlock:
* 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.
+ * 2. We don't handle stuffed files here we let readpage do the honours.
* 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
@@ -269,8 +296,7 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping,
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_holder gh;
- unsigned page_idx;
- int ret;
+ int ret = 0;
int do_unlock = 0;
if (likely(file != &gfs2_internal_file_sentinel)) {
@@ -289,29 +315,8 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping,
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 .... */
+ if (!gfs2_is_stuffed(ip))
ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
- }
if (do_unlock) {
gfs2_glock_dq_m(1, &gh);
@@ -356,8 +361,10 @@ static int gfs2_prepare_write(struct file *file, struct page *page,
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|LM_FLAG_TRY_1CB, &ip->i_gh);
error = gfs2_glock_nq_atime(&ip->i_gh);
if (unlikely(error)) {
- if (error == GLR_TRYFAILED)
+ if (error == GLR_TRYFAILED) {
+ unlock_page(page);
error = AOP_TRUNCATED_PAGE;
+ }
goto out_uninit;
}
@@ -594,6 +601,36 @@ static void gfs2_invalidatepage(struct page *page, unsigned long offset)
return;
}
+/**
+ * gfs2_ok_for_dio - check that dio is valid on this file
+ * @ip: The inode
+ * @rw: READ or WRITE
+ * @offset: The offset at which we are reading or writing
+ *
+ * Returns: 0 (to ignore the i/o request and thus fall back to buffered i/o)
+ * 1 (to accept the i/o request)
+ */
+static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset)
+{
+ /*
+ * 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))
+ return 0;
+
+ if (gfs2_is_stuffed(ip))
+ return 0;
+
+ if (offset > i_size_read(&ip->i_inode))
+ return 0;
+ return 1;
+}
+
+
+
static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
const struct iovec *iov, loff_t offset,
unsigned long nr_segs)
@@ -604,42 +641,28 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
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.
+ * Deferred lock, even if its a write, since we do no allocation
+ * on this path. All we need change is atime, and this lock mode
+ * ensures that other nodes have flushed their buffered read caches
+ * (i.e. their page cache entries for this inode). We do not,
+ * unfortunately have the option of only flushing a range like
+ * the VFS does.
*/
- gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
+ gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, GL_ATIME, &gh);
rv = gfs2_glock_nq_atime(&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);
+ return rv;
+ rv = gfs2_ok_for_dio(ip, rw, offset);
+ if (rv != 1)
+ goto out; /* dio not valid, fall back to buffered i/o */
+
+ rv = blockdev_direct_IO_no_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;
}
@@ -763,6 +786,7 @@ out:
const struct address_space_operations gfs2_file_aops = {
.writepage = gfs2_writepage,
+ .writepages = gfs2_writepages,
.readpage = gfs2_readpage,
.readpages = gfs2_readpages,
.sync_page = block_sync_page,
diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c
index d355899585d..9187eb174b4 100644
--- a/fs/gfs2/ops_dentry.c
+++ b/fs/gfs2/ops_dentry.c
@@ -46,6 +46,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
struct gfs2_inum_host inum;
unsigned int type;
int error;
+ int had_lock=0;
if (inode && is_bad_inode(inode))
goto invalid;
@@ -53,9 +54,12 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
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;
+ had_lock = gfs2_glock_is_locked_by_me(dip->i_gl);
+ if (!had_lock) {
+ 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) {
@@ -82,13 +86,15 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
}
valid_gunlock:
- gfs2_glock_dq_uninit(&d_gh);
+ if (!had_lock)
+ gfs2_glock_dq_uninit(&d_gh);
valid:
dput(parent);
return 1;
invalid_gunlock:
- gfs2_glock_dq_uninit(&d_gh);
+ if (!had_lock)
+ gfs2_glock_dq_uninit(&d_gh);
invalid:
if (inode && S_ISDIR(inode->i_mode)) {
if (have_submounts(dentry))
diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
index b4e7b877531..4855e8cca62 100644
--- a/fs/gfs2/ops_export.c
+++ b/fs/gfs2/ops_export.c
@@ -22,6 +22,7 @@
#include "glock.h"
#include "glops.h"
#include "inode.h"
+#include "ops_dentry.h"
#include "ops_export.h"
#include "rgrp.h"
#include "util.h"
@@ -112,13 +113,12 @@ struct get_name_filldir {
char *name;
};
-static int get_name_filldir(void *opaque, const char *name, unsigned int length,
- u64 offset, struct gfs2_inum_host *inum,
- unsigned int type)
+static int get_name_filldir(void *opaque, const char *name, int length,
+ loff_t offset, u64 inum, unsigned int type)
{
- struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque;
+ struct get_name_filldir *gnfd = opaque;
- if (!gfs2_inum_equal(inum, &gnfd->inum))
+ if (inum != gnfd->inum.no_addr)
return 0;
memcpy(gnfd->name, name, length);
@@ -189,6 +189,7 @@ static struct dentry *gfs2_get_parent(struct dentry *child)
return ERR_PTR(-ENOMEM);
}
+ dentry->d_op = &gfs2_dops;
return dentry;
}
@@ -215,8 +216,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj)
}
error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops,
- LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL,
- &i_gh);
+ LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
if (error)
return ERR_PTR(error);
@@ -269,6 +269,7 @@ out_inode:
return ERR_PTR(-ENOMEM);
}
+ dentry->d_op = &gfs2_dops;
return dentry;
fail_rgd:
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index b3f1e0349ae..c996aa739a0 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -43,15 +43,6 @@
#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
@@ -128,41 +119,6 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
}
/**
- * 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_host *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
@@ -175,16 +131,10 @@ 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) {
@@ -192,7 +142,7 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
return error;
}
- error = gfs2_dir_read(dir, &offset, &fdr, filldir_func);
+ error = gfs2_dir_read(dir, &offset, dirent, filldir);
gfs2_glock_dq_uninit(&d_gh);
@@ -247,7 +197,7 @@ static const u32 gfs2_to_fsflags[32] = {
static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
int error;
@@ -305,7 +255,7 @@ void gfs2_set_inode_flags(struct inode *inode)
*/
static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct buffer_head *bh;
@@ -588,7 +538,7 @@ 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_inode *ip = GFS2_I(file->f_path.dentry->d_inode);
struct gfs2_glock *gl;
unsigned int state;
int flags;
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index d14e139d267..ee80b8a5e7b 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -867,9 +867,9 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
error = -EBUSY;
goto error;
}
- mutex_lock(&sb->s_bdev->bd_mount_mutex);
+ down(&sb->s_bdev->bd_mount_sem);
new = sget(fs_type, test_bdev_super, set_bdev_super, sb->s_bdev);
- mutex_unlock(&sb->s_bdev->bd_mount_mutex);
+ up(&sb->s_bdev->bd_mount_sem);
if (IS_ERR(new)) {
error = PTR_ERR(new);
goto error;
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 636dda4c7d3..f40a84807d7 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -264,13 +264,23 @@ 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];
+ struct gfs2_holder ghs[3];
+ struct gfs2_rgrpd *rgd;
+ struct gfs2_holder ri_gh;
int error;
+ error = gfs2_rindex_hold(sdp, &ri_gh);
+ if (error)
+ return error;
+
gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
- gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
+ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
- error = gfs2_glock_nq_m(2, ghs);
+ rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
+ gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
+
+
+ error = gfs2_glock_nq_m(3, ghs);
if (error)
goto out;
@@ -291,10 +301,12 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
out_end_trans:
gfs2_trans_end(sdp);
out_gunlock:
- gfs2_glock_dq_m(2, ghs);
+ gfs2_glock_dq_m(3, ghs);
out:
gfs2_holder_uninit(ghs);
gfs2_holder_uninit(ghs + 1);
+ gfs2_holder_uninit(ghs + 2);
+ gfs2_glock_dq_uninit(&ri_gh);
return error;
}
@@ -449,13 +461,22 @@ 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];
+ struct gfs2_holder ghs[3];
+ struct gfs2_rgrpd *rgd;
+ struct gfs2_holder ri_gh;
int error;
+
+ error = gfs2_rindex_hold(sdp, &ri_gh);
+ if (error)
+ return 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);
+ rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
+ gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
+
+ error = gfs2_glock_nq_m(3, ghs);
if (error)
goto out;
@@ -483,10 +504,12 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry)
gfs2_trans_end(sdp);
out_gunlock:
- gfs2_glock_dq_m(2, ghs);
+ gfs2_glock_dq_m(3, ghs);
out:
gfs2_holder_uninit(ghs);
gfs2_holder_uninit(ghs + 1);
+ gfs2_holder_uninit(ghs + 2);
+ gfs2_glock_dq_uninit(&ri_gh);
return error;
}
@@ -547,7 +570,8 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
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;
+ struct gfs2_holder ghs[5], r_gh;
+ struct gfs2_rgrpd *nrgd;
unsigned int num_gh;
int dir_rename = 0;
int alloc_required;
@@ -587,6 +611,13 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (nip) {
gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
num_gh++;
+ /* grab the resource lock for unlink flag twiddling
+ * this is the case of the target file already existing
+ * so we unlink before doing the rename
+ */
+ nrgd = gfs2_blk2rgrpd(sdp, nip->i_num.no_addr);
+ if (nrgd)
+ gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);
}
error = gfs2_glock_nq_m(num_gh, ghs);
@@ -684,12 +715,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
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);
+ RES_STATFS + RES_QUOTA + 4, 0);
if (error)
goto out_ipreserv;
} else {
error = gfs2_trans_begin(sdp, 4 * RES_DINODE +
- 5 * RES_LEAF, 0);
+ 5 * RES_LEAF + 4, 0);
if (error)
goto out_gunlock;
}
@@ -728,7 +759,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
goto out_end_trans;
- ip->i_inode.i_ctime.tv_sec = get_seconds();
+ ip->i_inode.i_ctime = CURRENT_TIME_SEC;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
@@ -1018,7 +1049,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
}
generic_fillattr(inode, stat);
- if (unlock);
+ if (unlock)
gfs2_glock_dq_uninit(&gh);
return 0;
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
index 7685b46f934..47369d01121 100644
--- a/fs/gfs2/ops_super.c
+++ b/fs/gfs2/ops_super.c
@@ -173,6 +173,9 @@ static void gfs2_write_super_lockfs(struct super_block *sb)
struct gfs2_sbd *sdp = sb->s_fs_info;
int error;
+ if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+ return;
+
for (;;) {
error = gfs2_freeze_fs(sdp);
if (!error)
@@ -426,6 +429,12 @@ static void gfs2_delete_inode(struct inode *inode)
}
error = gfs2_dinode_dealloc(ip);
+ /*
+ * Must do this before unlock to avoid trying to write back
+ * potentially dirty data now that inode no longer exists
+ * on disk.
+ */
+ truncate_inode_pages(&inode->i_data, 0);
out_unlock:
gfs2_glock_dq(&ip->i_iopen_gh);
@@ -443,14 +452,12 @@ out:
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;
diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c
index 45a5f11fc39..14b380fb060 100644
--- a/fs/gfs2/ops_vm.c
+++ b/fs/gfs2/ops_vm.c
@@ -28,34 +28,13 @@
#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;
+ return filemap_nopage(area, address, type);
}
static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
@@ -167,7 +146,6 @@ static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area,
set_page_dirty(result);
}
- pfault_be_greedy(ip);
out:
gfs2_glock_dq_uninit(&i_gh);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 43a24f2e590..70f424fcf1c 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -71,17 +71,12 @@ void gfs2_tune_init(struct gfs2_tune *gt)
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;
}
@@ -359,8 +354,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
mutex_lock(&sdp->sd_jindex_mutex);
for (;;) {
- error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED,
- GL_LOCAL_EXCL, ji_gh);
+ error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, ji_gh);
if (error)
break;
@@ -529,8 +523,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
struct gfs2_log_header_host head;
int error;
- error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
- GL_LOCAL_EXCL, &t_gh);
+ error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &t_gh);
if (error)
return error;
@@ -583,9 +576,8 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
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);
+ error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE,
+ &t_gh);
if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
return error;
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index 983eaf1e06b..d01f9f0fda2 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -436,17 +436,12 @@ 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(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);
@@ -465,15 +460,10 @@ static struct attribute *tune_attrs[] = {
&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_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,
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 37d681b4f21..e2e0358da33 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -53,7 +53,7 @@ done:
*/
static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
int len, err;
char strbuf[HFS_MAX_NAMELEN];
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 02f5573e034..5cb7f8fee8d 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -102,7 +102,7 @@ static ssize_t hfs_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_dentry->d_inode->i_mapping->host;
+ struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, hfs_get_block, NULL);
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 7e309751645..e886ac8460d 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -111,7 +111,7 @@ fail:
static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
int len, err;
char strbuf[HFSPLUS_MAX_STRLEN + 1];
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 9e367524963..75e8c4d8aac 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -97,7 +97,7 @@ static ssize_t hfsplus_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_dentry->d_inode->i_mapping->host;
+ struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, hfsplus_get_block, NULL);
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index cca3fb693f9..70543b17e4c 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -76,7 +76,7 @@ extern int make_symlink(const char *from, const char *to);
extern int unlink_file(const char *file);
extern int do_mkdir(const char *file, int mode);
extern int do_rmdir(const char *file);
-extern int do_mknod(const char *file, int mode, int dev);
+extern int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor);
extern int link_file(const char *from, const char *to);
extern int do_readlink(char *file, char *buf, int size);
extern int rename_file(char *from, char *to);
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index b6bd33ca373..69a376f35a6 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -35,7 +35,7 @@ static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
return(list_entry(inode, struct hostfs_inode_info, vfs_inode));
}
-#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_dentry->d_inode)
+#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
int hostfs_d_delete(struct dentry *dentry)
{
@@ -325,7 +325,7 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
unsigned long long next, ino;
int error, len;
- name = dentry_name(file->f_dentry, 0);
+ name = dentry_name(file->f_path.dentry, 0);
if(name == NULL) return(-ENOMEM);
dir = open_dir(name, &error);
kfree(name);
@@ -366,7 +366,7 @@ int hostfs_file_open(struct inode *ino, struct file *file)
if(w)
r = 1;
- name = dentry_name(file->f_dentry, 0);
+ name = dentry_name(file->f_path.dentry, 0);
if(name == NULL)
return(-ENOMEM);
@@ -755,7 +755,7 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
goto out_put;
init_special_inode(inode, mode, dev);
- err = do_mknod(name, mode, dev);
+ err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
if(err)
goto out_free;
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index 23b7cee7212..1ed5ea389f1 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -295,11 +295,11 @@ int do_rmdir(const char *file)
return(0);
}
-int do_mknod(const char *file, int mode, int dev)
+int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor)
{
int err;
- err = mknod(file, mode, dev);
+ err = mknod(file, mode, makedev(major, minor));
if(err) return(-errno);
return(0);
}
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index 594f9c428fc..6916c41d701 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -24,7 +24,7 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
loff_t new_off = off + (whence == 1 ? filp->f_pos : 0);
loff_t pos;
struct quad_buffer_head qbh;
- struct inode *i = filp->f_dentry->d_inode;
+ struct inode *i = filp->f_path.dentry->d_inode;
struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
struct super_block *s = i->i_sb;
@@ -52,7 +52,7 @@ fail:
static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
struct quad_buffer_head qbh;
struct hpfs_dirent *de;
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index 8b94d24855f..fb4c8915010 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -115,7 +115,7 @@ static ssize_t hpfs_file_write(struct file *file, const char __user *buf,
retval = do_sync_write(file, buf, count, ppos);
if (retval > 0)
- hpfs_i(file->f_dentry->d_inode)->i_dirty = 1;
+ hpfs_i(file->f_path.dentry->d_inode)->i_dirty = 1;
return retval;
}
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
index 642675fc394..afd340a45da 100644
--- a/fs/hppfs/hppfs_kern.c
+++ b/fs/hppfs/hppfs_kern.c
@@ -221,7 +221,7 @@ static ssize_t read_proc(struct file *file, char __user *buf, ssize_t count,
ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
ssize_t n;
- read = file->f_dentry->d_inode->i_fop->read;
+ read = file->f_path.dentry->d_inode->i_fop->read;
if(!is_user)
set_fs(KERNEL_DS);
@@ -320,7 +320,7 @@ static ssize_t hppfs_write(struct file *file, const char __user *buf, size_t len
ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
int err;
- write = proc_file->f_dentry->d_inode->i_fop->write;
+ write = proc_file->f_path.dentry->d_inode->i_fop->write;
proc_file->f_pos = file->f_pos;
err = (*write)(proc_file, buf, len, &proc_file->f_pos);
@@ -464,7 +464,7 @@ static int hppfs_open(struct inode *inode, struct file *file)
if(data == NULL)
goto out;
- host_file = dentry_name(file->f_dentry, strlen("/rw"));
+ host_file = dentry_name(file->f_path.dentry, strlen("/rw"));
if(host_file == NULL)
goto out_free2;
@@ -547,7 +547,7 @@ static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
loff_t (*llseek)(struct file *, loff_t, int);
loff_t ret;
- llseek = proc_file->f_dentry->d_inode->i_fop->llseek;
+ llseek = proc_file->f_path.dentry->d_inode->i_fop->llseek;
if(llseek != NULL){
ret = (*llseek)(proc_file, off, where);
if(ret < 0)
@@ -591,10 +591,10 @@ static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
struct hppfs_dirent dirent = ((struct hppfs_dirent)
{ .vfs_dirent = ent,
.filldir = filldir,
- .dentry = file->f_dentry } );
+ .dentry = file->f_path.dentry } );
int err;
- readdir = proc_file->f_dentry->d_inode->i_fop->readdir;
+ readdir = proc_file->f_path.dentry->d_inode->i_fop->readdir;
proc_file->f_pos = file->f_pos;
err = (*readdir)(proc_file, &dirent, hppfs_filldir);
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 0706f5aac6a..e6bd553fdc4 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -58,7 +58,7 @@ static void huge_pagevec_release(struct pagevec *pvec)
static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
loff_t len, vma_len;
int ret;
@@ -176,7 +176,7 @@ static int hugetlbfs_commit_write(struct file *file,
static void truncate_huge_page(struct page *page)
{
- clear_page_dirty(page);
+ cancel_dirty_page(page, /* No IO accounting for huge pages? */0);
ClearPageUptodate(page);
remove_from_page_cache(page);
put_page(page);
@@ -449,10 +449,13 @@ static int hugetlbfs_symlink(struct inode *dir,
}
/*
- * For direct-IO reads into hugetlb pages
+ * mark the head page dirty
*/
static int hugetlbfs_set_page_dirty(struct page *page)
{
+ struct page *head = (struct page *)page_private(page);
+
+ SetPageDirty(head);
return 0;
}
@@ -774,8 +777,8 @@ struct file *hugetlb_zero_setup(size_t size)
d_instantiate(dentry, inode);
inode->i_size = size;
inode->i_nlink = 0;
- file->f_vfsmnt = mntget(hugetlbfs_vfsmount);
- file->f_dentry = dentry;
+ file->f_path.mnt = mntget(hugetlbfs_vfsmount);
+ file->f_path.dentry = dentry;
file->f_mapping = inode->i_mapping;
file->f_op = &hugetlbfs_file_operations;
file->f_mode = FMODE_WRITE | FMODE_READ;
diff --git a/fs/inode.c b/fs/inode.c
index 9ecccab7326..bf21dc6d0db 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1144,7 +1144,6 @@ sector_t bmap(struct inode * inode, sector_t block)
res = inode->i_mapping->a_ops->bmap(inode->i_mapping, block);
return res;
}
-
EXPORT_SYMBOL(bmap);
/**
@@ -1163,27 +1162,43 @@ void touch_atime(struct vfsmount *mnt, struct dentry *dentry)
if (IS_RDONLY(inode))
return;
-
- if ((inode->i_flags & S_NOATIME) ||
- (inode->i_sb->s_flags & MS_NOATIME) ||
- ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)))
+ if (inode->i_flags & S_NOATIME)
+ return;
+ if (inode->i_sb->s_flags & MS_NOATIME)
+ return;
+ if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
return;
/*
* We may have a NULL vfsmount when coming from NFSD
*/
- if (mnt &&
- ((mnt->mnt_flags & MNT_NOATIME) ||
- ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))))
- return;
+ if (mnt) {
+ if (mnt->mnt_flags & MNT_NOATIME)
+ return;
+ if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
+ return;
- now = current_fs_time(inode->i_sb);
- if (!timespec_equal(&inode->i_atime, &now)) {
- inode->i_atime = now;
- mark_inode_dirty_sync(inode);
+ if (mnt->mnt_flags & MNT_RELATIME) {
+ /*
+ * With relative atime, only update atime if the
+ * previous atime is earlier than either the ctime or
+ * mtime.
+ */
+ if (timespec_compare(&inode->i_mtime,
+ &inode->i_atime) < 0 &&
+ timespec_compare(&inode->i_ctime,
+ &inode->i_atime) < 0)
+ return;
+ }
}
-}
+ now = current_fs_time(inode->i_sb);
+ if (timespec_equal(&inode->i_atime, &now))
+ return;
+
+ inode->i_atime = now;
+ mark_inode_dirty_sync(inode);
+}
EXPORT_SYMBOL(touch_atime);
/**
@@ -1200,7 +1215,7 @@ EXPORT_SYMBOL(touch_atime);
void file_update_time(struct file *file)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct timespec now;
int sync_it = 0;
diff --git a/fs/inotify_user.c b/fs/inotify_user.c
index e1956e6f116..55f6da55b7c 100644
--- a/fs/inotify_user.c
+++ b/fs/inotify_user.c
@@ -570,9 +570,9 @@ asmlinkage long sys_inotify_init(void)
dev->ih = ih;
filp->f_op = &inotify_fops;
- filp->f_vfsmnt = mntget(inotify_mnt);
- filp->f_dentry = dget(inotify_mnt->mnt_root);
- filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+ filp->f_path.mnt = mntget(inotify_mnt);
+ filp->f_path.dentry = dget(inotify_mnt->mnt_root);
+ filp->f_mapping = filp->f_path.dentry->d_inode->i_mapping;
filp->f_mode = FMODE_READ;
filp->f_flags = O_RDONLY;
filp->private_data = dev;
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 4b7660b09ac..ff61772ceed 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -31,7 +31,7 @@ static long do_ioctl(struct file *filp, unsigned int cmd,
goto out;
} else if (filp->f_op->ioctl) {
lock_kernel();
- error = filp->f_op->ioctl(filp->f_dentry->d_inode,
+ error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,
filp, cmd, arg);
unlock_kernel();
}
@@ -45,7 +45,7 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
{
int error;
int block;
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode * inode = filp->f_path.dentry->d_inode;
int __user *p = (int __user *)arg;
switch (cmd) {
@@ -137,17 +137,17 @@ int vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, unsigned lon
break;
case FIOQSIZE:
- if (S_ISDIR(filp->f_dentry->d_inode->i_mode) ||
- S_ISREG(filp->f_dentry->d_inode->i_mode) ||
- S_ISLNK(filp->f_dentry->d_inode->i_mode)) {
- loff_t res = inode_get_bytes(filp->f_dentry->d_inode);
+ if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode) ||
+ S_ISREG(filp->f_path.dentry->d_inode->i_mode) ||
+ S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) {
+ loff_t res = inode_get_bytes(filp->f_path.dentry->d_inode);
error = copy_to_user((loff_t __user *)arg, &res, sizeof(res)) ? -EFAULT : 0;
}
else
error = -ENOTTY;
break;
default:
- if (S_ISREG(filp->f_dentry->d_inode->i_mode))
+ if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
error = file_ioctl(filp, cmd, arg);
else
error = do_ioctl(filp, cmd, arg);
diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c
index 731816332b1..6bbbdb53581 100644
--- a/fs/isofs/compress.c
+++ b/fs/isofs/compress.c
@@ -42,7 +42,7 @@ static struct semaphore zisofs_zlib_semaphore;
*/
static int zisofs_readpage(struct file *file, struct page *page)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct address_space *mapping = inode->i_mapping;
unsigned int maxpage, xpage, fpage, blockindex;
unsigned long offset;
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 27e276987fd..4af2548f97a 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -183,7 +183,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
/* Handle the case of the '..' directory */
if (de->name_len[0] == 1 && de->name[0] == 1) {
- inode_number = parent_ino(filp->f_dentry);
+ inode_number = parent_ino(filp->f_path.dentry);
if (filldir(dirent, "..", 2, filp->f_pos, inode_number, DT_DIR) < 0)
break;
filp->f_pos += de_len;
@@ -255,8 +255,7 @@ static int isofs_readdir(struct file *filp,
int result;
char * tmpname;
struct iso_directory_record * tmpde;
- struct inode *inode = filp->f_dentry->d_inode;
-
+ struct inode *inode = filp->f_path.dentry->d_inode;
tmpname = (char *)__get_free_page(GFP_KERNEL);
if (tmpname == NULL)
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index 10be51290a2..be4648bc7a2 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -248,8 +248,12 @@ write_out_data:
bufs = 0;
goto write_out_data;
}
- }
- else {
+ } else if (!locked && buffer_locked(bh)) {
+ __journal_file_buffer(jh, commit_transaction,
+ BJ_Locked);
+ jbd_unlock_bh_state(bh);
+ put_bh(bh);
+ } else {
BUFFER_TRACE(bh, "writeout complete: unfile");
__journal_unfile_buffer(jh);
jbd_unlock_bh_state(bh);
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index d38e0d575e4..cceaf57e377 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -55,7 +55,7 @@ get_transaction(journal_t *journal, transaction_t *transaction)
spin_lock_init(&transaction->t_handle_lock);
/* Set up the commit timer for the new transaction. */
- journal->j_commit_timer.expires = transaction->t_expires;
+ journal->j_commit_timer.expires = round_jiffies(transaction->t_expires);
add_timer(&journal->j_commit_timer);
J_ASSERT(journal->j_running_transaction == NULL);
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index 9f15bce9202..43baa1afa02 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -566,7 +566,7 @@ static int
jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct jffs_file *f;
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct jffs_control *c = (struct jffs_control *)inode->i_sb->s_fs_info;
int j;
@@ -818,7 +818,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
D1({
int len = dentry->d_name.len;
- char *_name = (char *) kmalloc(len + 1, GFP_KERNEL);
+ char *_name = kmalloc(len + 1, GFP_KERNEL);
memcpy(_name, dentry->d_name.name, len);
_name[len] = '\0';
printk("***jffs_mkdir(): dir = 0x%p, name = \"%s\", "
@@ -964,7 +964,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type)
D1({
int len = dentry->d_name.len;
const char *name = dentry->d_name.name;
- char *_name = (char *) kmalloc(len + 1, GFP_KERNEL);
+ char *_name = kmalloc(len + 1, GFP_KERNEL);
memcpy(_name, name, len);
_name[len] = '\0';
printk("***jffs_remove(): file = \"%s\", ino = %ld\n", _name, dentry->d_inode->i_ino);
@@ -1372,7 +1372,7 @@ jffs_file_write(struct file *filp, const char *buf, size_t count,
struct jffs_control *c;
struct jffs_file *f;
struct jffs_node *node;
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int recoverable = 0;
size_t written = 0;
@@ -1380,7 +1380,7 @@ jffs_file_write(struct file *filp, const char *buf, size_t count,
loff_t pos = *ppos;
int err;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
D2(printk("***jffs_file_write(): inode: 0x%p (ino: %lu), "
"filp: 0x%p, buf: 0x%p, count: %d\n",
diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c
index d0e783f199e..6dd18911b44 100644
--- a/fs/jffs/intrep.c
+++ b/fs/jffs/intrep.c
@@ -436,7 +436,7 @@ jffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size, __u32 *result)
int i, length;
/* Allocate read buffer */
- read_buf = (__u8 *) kmalloc (sizeof(__u8) * 4096, GFP_KERNEL);
+ read_buf = kmalloc(sizeof(__u8) * 4096, GFP_KERNEL);
if (!read_buf) {
printk(KERN_NOTICE "kmalloc failed in jffs_checksum_flash()\n");
return -ENOMEM;
@@ -744,11 +744,11 @@ static int check_partly_erased_sectors(struct jffs_fmcontrol *fmc){
/* Allocate read buffers */
- read_buf1 = (__u8 *) kmalloc (sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL);
+ read_buf1 = kmalloc(sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL);
if (!read_buf1)
return -ENOMEM;
- read_buf2 = (__u8 *) kmalloc (sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL);
+ read_buf2 = kmalloc(sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL);
if (!read_buf2) {
kfree(read_buf1);
return -ENOMEM;
@@ -876,7 +876,7 @@ jffs_scan_flash(struct jffs_control *c)
}
/* Allocate read buffer */
- read_buf = (__u8 *) kmalloc (sizeof(__u8) * 4096, GFP_KERNEL);
+ read_buf = kmalloc(sizeof(__u8) * 4096, GFP_KERNEL);
if (!read_buf) {
flash_safe_release(fmc->mtd);
return -ENOMEM;
@@ -1463,7 +1463,7 @@ jffs_insert_node(struct jffs_control *c, struct jffs_file *f,
kfree(f->name);
DJM(no_name--);
}
- if (!(f->name = (char *) kmalloc(raw_inode->nsize + 1,
+ if (!(f->name = kmalloc(raw_inode->nsize + 1,
GFP_KERNEL))) {
return -ENOMEM;
}
@@ -1737,7 +1737,7 @@ jffs_find_child(struct jffs_file *dir, const char *name, int len)
printk("jffs_find_child(): Found \"%s\".\n", f->name);
}
else {
- char *copy = (char *) kmalloc(len + 1, GFP_KERNEL);
+ char *copy = kmalloc(len + 1, GFP_KERNEL);
if (copy) {
memcpy(copy, name, len);
copy[len] = '\0';
@@ -2627,7 +2627,7 @@ jffs_print_tree(struct jffs_file *first_file, int indent)
return;
}
- if (!(space = (char *) kmalloc(indent + 1, GFP_KERNEL))) {
+ if (!(space = kmalloc(indent + 1, GFP_KERNEL))) {
printk("jffs_print_tree(): Out of memory!\n");
return;
}
diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c
index 077258b2103..5a95fbdd6fd 100644
--- a/fs/jffs/jffs_fm.c
+++ b/fs/jffs/jffs_fm.c
@@ -17,6 +17,7 @@
*
*/
#include <linux/slab.h>
+#include <linux/err.h>
#include <linux/blkdev.h>
#include <linux/jffs.h>
#include "jffs_fm.h"
@@ -104,7 +105,7 @@ jffs_build_begin(struct jffs_control *c, int unit)
mtd = get_mtd_device(NULL, unit);
- if (!mtd) {
+ if (IS_ERR(mtd)) {
kfree(fmc);
DJM(no_jffs_fmcontrol--);
return NULL;
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c
index 72b4fc13a10..4189e4a3605 100644
--- a/fs/jffs2/debug.c
+++ b/fs/jffs2/debug.c
@@ -178,8 +178,8 @@ __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
while (ref2) {
uint32_t totlen = ref_totlen(c, jeb, ref2);
- if (ref2->flash_offset < jeb->offset ||
- ref2->flash_offset > jeb->offset + c->sector_size) {
+ if (ref_offset(ref2) < jeb->offset ||
+ ref_offset(ref2) > jeb->offset + c->sector_size) {
JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
ref_offset(ref2), jeb->offset);
goto error;
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h
index 3daf3bca037..f89c85d5a3f 100644
--- a/fs/jffs2/debug.h
+++ b/fs/jffs2/debug.h
@@ -13,6 +13,7 @@
#ifndef _JFFS2_DEBUG_H_
#define _JFFS2_DEBUG_H_
+#include <linux/sched.h>
#ifndef CONFIG_JFFS2_FS_DEBUG
#define CONFIG_JFFS2_FS_DEBUG 0
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 9def6adf4a5..da6034d5071 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -123,11 +123,11 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct jffs2_inode_info *f;
struct jffs2_sb_info *c;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct jffs2_full_dirent *fd;
unsigned long offset, curofs;
- D1(printk(KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", filp->f_dentry->d_inode->i_ino));
+ D1(printk(KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", filp->f_path.dentry->d_inode->i_ino));
f = JFFS2_INODE_INFO(inode);
c = JFFS2_SB_INFO(inode->i_sb);
@@ -141,7 +141,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
offset++;
}
if (offset == 1) {
- unsigned long pino = parent_ino(filp->f_dentry);
+ unsigned long pino = parent_ino(filp->f_path.dentry);
D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", pino));
if (filldir(dirent, "..", 2, 1, pino, DT_DIR) < 0)
goto out;
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 7bc1a4201c0..abb90c0c09c 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -502,12 +502,11 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
if (ret)
return ret;
- c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
+ c->inocache_list = kcalloc(INOCACHE_HASHSIZE, sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
if (!c->inocache_list) {
ret = -ENOMEM;
goto out_wbuf;
}
- memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
jffs2_init_xattr_subsystem(c);
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index daff3341ff9..3a3cf225981 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -838,6 +838,8 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {
+ cond_resched();
+
/* We only care about obsolete ones */
if (!(ref_obsolete(raw)))
continue;
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index 0ddfd70307f..4178b4b5594 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -294,23 +294,21 @@ static inline int jffs2_encode_dev(union jffs2_device_node *jdev, dev_t rdev)
static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
{
- struct rb_node *node = root->rb_node;
+ struct rb_node *node = rb_first(root);
if (!node)
return NULL;
- while(node->rb_left)
- node = node->rb_left;
+
return rb_entry(node, struct jffs2_node_frag, rb);
}
static inline struct jffs2_node_frag *frag_last(struct rb_root *root)
{
- struct rb_node *node = root->rb_node;
+ struct rb_node *node = rb_last(root);
if (!node)
return NULL;
- while(node->rb_right)
- node = node->rb_right;
+
return rb_entry(node, struct jffs2_node_frag, rb);
}
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 266423b2709..58a0b912e9d 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -944,13 +944,12 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
{
struct jffs2_raw_inode n;
- struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL);
+ struct jffs2_inode_info *f = kzalloc(sizeof(*f), GFP_KERNEL);
int ret;
if (!f)
return -ENOMEM;
- memset(f, 0, sizeof(*f));
init_MUTEX_LOCKED(&f->sem);
f->inocache = ic;
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index e2413466ddd..3af746eaff0 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -128,17 +128,19 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
}
if (jffs2_sum_active()) {
- s = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
+ s = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
if (!s) {
+ kfree(flashbuf);
JFFS2_WARNING("Can't allocate memory for summary\n");
return -ENOMEM;
}
- memset(s, 0, sizeof(struct jffs2_summary));
}
for (i=0; i<c->nr_blocks; i++) {
struct jffs2_eraseblock *jeb = &c->blocks[i];
+ cond_resched();
+
/* reset summary info for next eraseblock scan */
jffs2_sum_reset_collected(s);
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
index e52cef526d9..25265965bdc 100644
--- a/fs/jffs2/summary.c
+++ b/fs/jffs2/summary.c
@@ -26,15 +26,13 @@
int jffs2_sum_init(struct jffs2_sb_info *c)
{
- c->summary = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
+ c->summary = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
if (!c->summary) {
JFFS2_WARNING("Can't allocate memory for summary information!\n");
return -ENOMEM;
}
- memset(c->summary, 0, sizeof(struct jffs2_summary));
-
c->summary->sum_buf = vmalloc(c->sector_size);
if (!c->summary->sum_buf) {
@@ -398,6 +396,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
dbg_summary("processing summary index %d\n", i);
+ cond_resched();
+
/* Make sure there's a spare ref for dirty space */
err = jffs2_prealloc_raw_node_refs(c, jeb, 2);
if (err)
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 7deb7825402..08a0e6c49e6 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/fs.h>
+#include <linux/err.h>
#include <linux/mount.h>
#include <linux/jffs2.h>
#include <linux/pagemap.h>
@@ -184,9 +185,9 @@ static int jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
struct mtd_info *mtd;
mtd = get_mtd_device(NULL, mtdnr);
- if (!mtd) {
+ if (IS_ERR(mtd)) {
D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr));
- return -EINVAL;
+ return PTR_ERR(mtd);
}
return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt);
@@ -221,7 +222,7 @@ static int jffs2_get_sb(struct file_system_type *fs_type,
D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4));
for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) {
mtd = get_mtd_device(NULL, mtdnr);
- if (mtd) {
+ if (!IS_ERR(mtd)) {
if (!strcmp(mtd->name, dev_name+4))
return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt);
put_mtd_device(mtd);
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index fc211b6e9b0..b90d5aa3d96 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -51,7 +51,7 @@ static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
*/
if (!p) {
- printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n");
+ printk(KERN_ERR "jffs2_follow_link(): can't find symlink target\n");
p = ERR_PTR(-EIO);
}
D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->target));
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 70707309dfa..9c99859f5ed 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -969,8 +969,7 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,
int oobsize = c->mtd->oobsize;
struct mtd_oob_ops ops;
- ops.len = NR_OOB_SCAN_PAGES * oobsize;
- ops.ooblen = oobsize;
+ ops.ooblen = NR_OOB_SCAN_PAGES * oobsize;
ops.oobbuf = c->oobbuf;
ops.ooboffs = 0;
ops.datbuf = NULL;
@@ -983,10 +982,10 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,
return ret;
}
- if (ops.retlen < ops.len) {
+ if (ops.oobretlen < ops.ooblen) {
D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB "
"returned short read (%zd bytes not %d) for block "
- "at %08x\n", ops.retlen, ops.len, jeb->offset));
+ "at %08x\n", ops.oobretlen, ops.ooblen, jeb->offset));
return -EIO;
}
@@ -1005,7 +1004,7 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,
}
/* we know, we are aligned :) */
- for (page = oobsize; page < ops.len; page += sizeof(long)) {
+ for (page = oobsize; page < ops.ooblen; page += sizeof(long)) {
long dat = *(long *)(&ops.oobbuf[page]);
if(dat != -1)
return 1;
@@ -1033,7 +1032,6 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c,
return 2;
}
- ops.len = oobsize;
ops.ooblen = oobsize;
ops.oobbuf = c->oobbuf;
ops.ooboffs = 0;
@@ -1048,10 +1046,10 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c,
return ret;
}
- if (ops.retlen < ops.len) {
+ if (ops.oobretlen < ops.ooblen) {
D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): "
"Read OOB return short read (%zd bytes not %d) "
- "for block at %08x\n", ops.retlen, ops.len,
+ "for block at %08x\n", ops.oobretlen, ops.ooblen,
jeb->offset));
return -EIO;
}
@@ -1090,8 +1088,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c,
n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
n.totlen = cpu_to_je32(8);
- ops.len = c->fsdata_len;
- ops.ooblen = c->fsdata_len;;
+ ops.ooblen = c->fsdata_len;
ops.oobbuf = (uint8_t *)&n;
ops.ooboffs = c->fsdata_pos;
ops.datbuf = NULL;
@@ -1105,10 +1102,10 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c,
jeb->offset, ret));
return ret;
}
- if (ops.retlen != ops.len) {
+ if (ops.oobretlen != ops.ooblen) {
D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): "
"Short write for block at %08x: %zd not %d\n",
- jeb->offset, ops.retlen, ops.len));
+ jeb->offset, ops.oobretlen, ops.ooblen));
return -EIO;
}
return 0;
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 4da09ce1d1f..4bb3f189733 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -399,8 +399,6 @@ static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datu
{
/* must be called under down_write(xattr_sem) */
if (atomic_dec_and_lock(&xd->refcnt, &c->erase_completion_lock)) {
- uint32_t xid = xd->xid, version = xd->version;
-
unload_xattr_datum(c, xd);
xd->flags |= JFFS2_XFLAGS_DEAD;
if (xd->node == (void *)xd) {
@@ -411,7 +409,8 @@ static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datu
}
spin_unlock(&c->erase_completion_lock);
- dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xid, version);
+ dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n",
+ xd->xid, xd->version);
}
}
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index f5719117edf..e285022f006 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -182,9 +182,9 @@ int jfs_get_block(struct inode *ip, sector_t lblock,
* Take appropriate lock on inode
*/
if (create)
- IWRITE_LOCK(ip);
+ IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
else
- IREAD_LOCK(ip);
+ IREAD_LOCK(ip, RDWRLOCK_NORMAL);
if (((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size) &&
(!xtLookup(ip, lblock64, xlen, &xflag, &xaddr, &xlen, 0)) &&
@@ -359,7 +359,7 @@ void jfs_truncate(struct inode *ip)
nobh_truncate_page(ip->i_mapping, ip->i_size);
- IWRITE_LOCK(ip);
+ IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
jfs_truncate_nolock(ip, ip->i_size);
IWRITE_UNLOCK(ip);
}
diff --git a/fs/jfs/jfs_debug.h b/fs/jfs/jfs_debug.h
index ddffbbd4d95..7378798f0b2 100644
--- a/fs/jfs/jfs_debug.h
+++ b/fs/jfs/jfs_debug.h
@@ -39,10 +39,6 @@ extern void jfs_proc_clean(void);
/*
* assert with traditional printf/panic
*/
-#ifdef CONFIG_KERNEL_ASSERTS
-/* kgdb stuff */
-#define assert(p) KERNEL_ASSERT(#p, p)
-#else
#define assert(p) do { \
if (!(p)) { \
printk(KERN_CRIT "BUG at %s:%d assert(%s)\n", \
@@ -50,7 +46,6 @@ extern void jfs_proc_clean(void);
BUG(); \
} \
} while (0)
-#endif
/*
* debug ON
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index 23546c8fd48..82b0544bd76 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -337,7 +337,7 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
- IREAD_LOCK(ipbmap);
+ IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
/* block to be freed better be within the mapsize. */
if (unlikely((blkno == 0) || (blkno + nblocks > bmp->db_mapsize))) {
@@ -733,7 +733,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
* allocation group size, try to allocate anywhere.
*/
if (l2nb > bmp->db_agl2size) {
- IWRITE_LOCK(ipbmap);
+ IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
rc = dbAllocAny(bmp, nblocks, l2nb, results);
@@ -774,7 +774,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
* the hint using a tiered strategy.
*/
if (nblocks <= BPERDMAP) {
- IREAD_LOCK(ipbmap);
+ IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
/* get the buffer for the dmap containing the hint.
*/
@@ -844,7 +844,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
/* try to satisfy the allocation request with blocks within
* the same allocation group as the hint.
*/
- IWRITE_LOCK(ipbmap);
+ IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) != -ENOSPC)
goto write_unlock;
@@ -856,7 +856,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
* Let dbNextAG recommend a preferred allocation group
*/
agno = dbNextAG(ipbmap);
- IWRITE_LOCK(ipbmap);
+ IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
/* Try to allocate within this allocation group. if that fails, try to
* allocate anywhere in the map.
@@ -900,7 +900,7 @@ int dbAllocExact(struct inode *ip, s64 blkno, int nblocks)
s64 lblkno;
struct metapage *mp;
- IREAD_LOCK(ipbmap);
+ IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
/*
* validate extent request:
@@ -1050,7 +1050,7 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
*/
extblkno = lastblkno + 1;
- IREAD_LOCK(ipbmap);
+ IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
/* better be within the file system */
bmp = sbi->bmap;
@@ -3116,7 +3116,7 @@ int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks)
struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
- IREAD_LOCK(ipbmap);
+ IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
/* block to be allocated better be within the mapsize. */
ASSERT(nblocks <= bmp->db_mapsize - blkno);
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index ecb2216d881..6d62f322289 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -3009,7 +3009,7 @@ static inline struct jfs_dirent *next_jfs_dirent(struct jfs_dirent *dirent)
*/
int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *ip = filp->f_dentry->d_inode;
+ struct inode *ip = filp->f_path.dentry->d_inode;
struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab;
int rc = 0;
loff_t dtpos; /* legacy OS/2 style position */
@@ -3777,12 +3777,12 @@ static int ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
struct component_name lkey;
struct component_name rkey;
- lkey.name = (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
+ lkey.name = kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
GFP_KERNEL);
if (lkey.name == NULL)
return -ENOMEM;
- rkey.name = (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
+ rkey.name = kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
GFP_KERNEL);
if (rkey.name == NULL) {
kfree(lkey.name);
diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h
index eb550b339bb..38f70ac03be 100644
--- a/fs/jfs/jfs_filsys.h
+++ b/fs/jfs/jfs_filsys.h
@@ -29,31 +29,21 @@
/*
* file system option (superblock flag)
*/
-/* mount time flag to disable journaling to disk */
-#define JFS_NOINTEGRITY 0x00000010
+
+/* directory option */
+#define JFS_UNICODE 0x00000001 /* unicode name */
/* mount time flags for error handling */
#define JFS_ERR_REMOUNT_RO 0x00000002 /* remount read-only */
#define JFS_ERR_CONTINUE 0x00000004 /* continue */
#define JFS_ERR_PANIC 0x00000008 /* panic */
+/* Quota support */
#define JFS_USRQUOTA 0x00000010
#define JFS_GRPQUOTA 0x00000020
-/* platform option (conditional compilation) */
-#define JFS_AIX 0x80000000 /* AIX support */
-/* POSIX name/directory support */
-
-#define JFS_OS2 0x40000000 /* OS/2 support */
-/* case-insensitive name/directory support */
-
-#define JFS_DFS 0x20000000 /* DCE DFS LFS support */
-
-#define JFS_LINUX 0x10000000 /* Linux support */
-/* case-sensitive name/directory support */
-
-/* directory option */
-#define JFS_UNICODE 0x00000001 /* unicode name */
+/* mount time flag to disable journaling to disk */
+#define JFS_NOINTEGRITY 0x00000040
/* commit option */
#define JFS_COMMIT 0x00000f00 /* commit option mask */
@@ -61,6 +51,7 @@
#define JFS_LAZYCOMMIT 0x00000200 /* lazy commit */
#define JFS_TMPFS 0x00000400 /* temporary file system -
* do not log/commit:
+ * Never implemented
*/
/* log logical volume option */
@@ -74,16 +65,25 @@
#define JFS_SPARSE 0x00020000 /* sparse regular file */
/* DASD Limits F226941 */
-#define JFS_DASD_ENABLED 0x00040000 /* DASD limits enabled */
-#define JFS_DASD_PRIME 0x00080000 /* Prime DASD usage on boot */
+#define JFS_DASD_ENABLED 0x00040000 /* DASD limits enabled */
+#define JFS_DASD_PRIME 0x00080000 /* Prime DASD usage on boot */
/* big endian flag */
-#define JFS_SWAP_BYTES 0x00100000 /* running on big endian computer */
+#define JFS_SWAP_BYTES 0x00100000 /* running on big endian computer */
/* Directory index */
-#define JFS_DIR_INDEX 0x00200000 /* Persistent index for */
- /* directory entries */
+#define JFS_DIR_INDEX 0x00200000 /* Persistent index for */
+/* platform options */
+#define JFS_LINUX 0x10000000 /* Linux support */
+#define JFS_DFS 0x20000000 /* DCE DFS LFS support */
+/* Never implemented */
+
+#define JFS_OS2 0x40000000 /* OS/2 support */
+/* case-insensitive name/directory support */
+
+#define JFS_AIX 0x80000000 /* AIX support */
+/* POSIX name/directory support - Never implemented*/
/*
* buffer cache configuration
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index ee9b473b7b8..aa5124b643b 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -120,7 +120,7 @@ int diMount(struct inode *ipimap)
* allocate/initialize the in-memory inode map control structure
*/
/* allocate the in-memory inode map control structure. */
- imap = (struct inomap *) kmalloc(sizeof(struct inomap), GFP_KERNEL);
+ imap = kmalloc(sizeof(struct inomap), GFP_KERNEL);
if (imap == NULL) {
jfs_err("diMount: kmalloc returned NULL!");
return -ENOMEM;
@@ -331,7 +331,7 @@ int diRead(struct inode *ip)
/* read the iag */
imap = JFS_IP(ipimap)->i_imap;
- IREAD_LOCK(ipimap);
+ IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
rc = diIAGRead(imap, iagno, &mp);
IREAD_UNLOCK(ipimap);
if (rc) {
@@ -920,7 +920,7 @@ int diFree(struct inode *ip)
/* Obtain read lock in imap inode. Don't release it until we have
* read all of the IAG's that we are going to.
*/
- IREAD_LOCK(ipimap);
+ IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
/* read the iag.
*/
@@ -1415,7 +1415,7 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
AG_LOCK(imap, agno);
/* Get read lock on imap inode */
- IREAD_LOCK(ipimap);
+ IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
/* get the iag number and read the iag */
iagno = INOTOIAG(inum);
@@ -1808,7 +1808,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
return -ENOSPC;
/* obtain read lock on imap inode */
- IREAD_LOCK(imap->im_ipimap);
+ IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP);
/* read the iag at the head of the list.
*/
@@ -1946,7 +1946,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
} else {
/* read the iag.
*/
- IREAD_LOCK(imap->im_ipimap);
+ IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP);
if ((rc = diIAGRead(imap, iagno, &mp))) {
IREAD_UNLOCK(imap->im_ipimap);
jfs_error(ip->i_sb, "diAllocExt: error reading iag");
@@ -2509,7 +2509,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
*/
/* acquire inode map lock */
- IWRITE_LOCK(ipimap);
+ IWRITE_LOCK(ipimap, RDWRLOCK_IMAP);
if (ipimap->i_size >> L2PSIZE != imap->im_nextiag + 1) {
IWRITE_UNLOCK(ipimap);
@@ -2648,7 +2648,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
}
/* obtain read lock on map */
- IREAD_LOCK(ipimap);
+ IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
/* read the iag */
if ((rc = diIAGRead(imap, iagno, &mp))) {
@@ -2779,7 +2779,7 @@ diUpdatePMap(struct inode *ipimap,
return -EIO;
}
/* read the iag */
- IREAD_LOCK(ipimap);
+ IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
rc = diIAGRead(imap, iagno, &mp);
IREAD_UNLOCK(ipimap);
if (rc)
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
index 94005584445..8f453eff3c8 100644
--- a/fs/jfs/jfs_incore.h
+++ b/fs/jfs/jfs_incore.h
@@ -109,9 +109,11 @@ struct jfs_inode_info {
#define JFS_ACL_NOT_CACHED ((void *)-1)
-#define IREAD_LOCK(ip) down_read(&JFS_IP(ip)->rdwrlock)
+#define IREAD_LOCK(ip, subclass) \
+ down_read_nested(&JFS_IP(ip)->rdwrlock, subclass)
#define IREAD_UNLOCK(ip) up_read(&JFS_IP(ip)->rdwrlock)
-#define IWRITE_LOCK(ip) down_write(&JFS_IP(ip)->rdwrlock)
+#define IWRITE_LOCK(ip, subclass) \
+ down_write_nested(&JFS_IP(ip)->rdwrlock, subclass)
#define IWRITE_UNLOCK(ip) up_write(&JFS_IP(ip)->rdwrlock)
/*
@@ -127,6 +129,29 @@ enum cflags {
COMMIT_Synclist, /* metadata pages on group commit synclist */
};
+/*
+ * commit_mutex nesting subclasses:
+ */
+enum commit_mutex_class
+{
+ COMMIT_MUTEX_PARENT,
+ COMMIT_MUTEX_CHILD,
+ COMMIT_MUTEX_SECOND_PARENT, /* Renaming */
+ COMMIT_MUTEX_VICTIM /* Inode being unlinked due to rename */
+};
+
+/*
+ * rdwrlock subclasses:
+ * The dmap inode may be locked while a normal inode or the imap inode are
+ * locked.
+ */
+enum rdwrlock_class
+{
+ RDWRLOCK_NORMAL,
+ RDWRLOCK_IMAP,
+ RDWRLOCK_DMAP
+};
+
#define set_cflag(flag, ip) set_bit(flag, &(JFS_IP(ip)->cflag))
#define clear_cflag(flag, ip) clear_bit(flag, &(JFS_IP(ip)->cflag))
#define test_cflag(flag, ip) test_bit(flag, &(JFS_IP(ip)->cflag))
diff --git a/fs/jfs/jfs_lock.h b/fs/jfs/jfs_lock.h
index 7d78e83d7c4..df48ece4b7a 100644
--- a/fs/jfs/jfs_lock.h
+++ b/fs/jfs/jfs_lock.h
@@ -42,7 +42,7 @@ do { \
if (cond) \
break; \
unlock_cmd; \
- schedule(); \
+ io_schedule(); \
lock_cmd; \
} \
current->state = TASK_RUNNING; \
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index b1a1c729601..58deae00750 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -56,7 +56,7 @@ static inline void __lock_metapage(struct metapage *mp)
set_current_state(TASK_UNINTERRUPTIBLE);
if (metapage_locked(mp)) {
unlock_page(mp->page);
- schedule();
+ io_schedule();
lock_page(mp->page);
}
} while (trylock_metapage(mp));
@@ -764,22 +764,9 @@ void release_metapage(struct metapage * mp)
} else if (mp->lsn) /* discard_metapage doesn't remove it */
remove_from_logsync(mp);
-#if MPS_PER_PAGE == 1
- /*
- * If we know this is the only thing in the page, we can throw
- * the page out of the page cache. If pages are larger, we
- * don't want to do this.
- */
-
- /* Retest mp->count since we may have released page lock */
- if (test_bit(META_discard, &mp->flag) && !mp->count) {
- clear_page_dirty(page);
- ClearPageUptodate(page);
- }
-#else
/* Try to keep metapages from using up too much memory */
drop_metapage(page, mp);
-#endif
+
unlock_page(page);
page_cache_release(page);
}
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index d558e51b0df..6988a1082f5 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -135,7 +135,7 @@ static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
add_wait_queue(event, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
TXN_UNLOCK();
- schedule();
+ io_schedule();
current->state = TASK_RUNNING;
remove_wait_queue(event, &wait);
}
diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
index e98eb03e531..acc97c46d8a 100644
--- a/fs/jfs/jfs_xtree.c
+++ b/fs/jfs/jfs_xtree.c
@@ -757,6 +757,11 @@ static int xtSearch(struct inode *ip, s64 xoff, s64 *nextp,
nsplit = 0;
/* push (bn, index) of the parent page/entry */
+ if (BT_STACK_FULL(btstack)) {
+ jfs_error(ip->i_sb, "stack overrun in xtSearch!");
+ XT_PUTPAGE(mp);
+ return -EIO;
+ }
BT_PUSH(btstack, bn, index);
/* get the child page block number */
@@ -3915,6 +3920,11 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
*/
getChild:
/* save current parent entry for the child page */
+ if (BT_STACK_FULL(&btstack)) {
+ jfs_error(ip->i_sb, "stack overrun in xtTruncate!");
+ XT_PUTPAGE(mp);
+ return -EIO;
+ }
BT_PUSH(&btstack, bn, index);
/* get child page */
@@ -4112,6 +4122,11 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
*/
getChild:
/* save current parent entry for the child page */
+ if (BT_STACK_FULL(&btstack)) {
+ jfs_error(ip->i_sb, "stack overrun in xtTruncate_pmap!");
+ XT_PUTPAGE(mp);
+ return -EIO;
+ }
BT_PUSH(&btstack, bn, index);
/* get child page */
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index a6a8c16c872..7ab47561b68 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -104,8 +104,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
tid = txBegin(dip->i_sb, 0);
- mutex_lock(&JFS_IP(dip)->commit_mutex);
- mutex_lock(&JFS_IP(ip)->commit_mutex);
+ mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+ mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
rc = jfs_init_acl(tid, ip, dip);
if (rc)
@@ -238,8 +238,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
tid = txBegin(dip->i_sb, 0);
- mutex_lock(&JFS_IP(dip)->commit_mutex);
- mutex_lock(&JFS_IP(ip)->commit_mutex);
+ mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+ mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
rc = jfs_init_acl(tid, ip, dip);
if (rc)
@@ -365,8 +365,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
tid = txBegin(dip->i_sb, 0);
- mutex_lock(&JFS_IP(dip)->commit_mutex);
- mutex_lock(&JFS_IP(ip)->commit_mutex);
+ mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+ mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
iplist[0] = dip;
iplist[1] = ip;
@@ -483,12 +483,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
if ((rc = get_UCSname(&dname, dentry)))
goto out;
- IWRITE_LOCK(ip);
+ IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
tid = txBegin(dip->i_sb, 0);
- mutex_lock(&JFS_IP(dip)->commit_mutex);
- mutex_lock(&JFS_IP(ip)->commit_mutex);
+ mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+ mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
iplist[0] = dip;
iplist[1] = ip;
@@ -802,8 +802,8 @@ static int jfs_link(struct dentry *old_dentry,
tid = txBegin(ip->i_sb, 0);
- mutex_lock(&JFS_IP(dir)->commit_mutex);
- mutex_lock(&JFS_IP(ip)->commit_mutex);
+ mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+ mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
/*
* scan parent directory for entry/freespace
@@ -913,8 +913,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
tid = txBegin(dip->i_sb, 0);
- mutex_lock(&JFS_IP(dip)->commit_mutex);
- mutex_lock(&JFS_IP(ip)->commit_mutex);
+ mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+ mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
rc = jfs_init_security(tid, ip, dip);
if (rc)
@@ -1127,7 +1127,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out3;
}
} else if (new_ip) {
- IWRITE_LOCK(new_ip);
+ IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
/* Init inode for quota operations. */
DQUOT_INIT(new_ip);
}
@@ -1137,13 +1137,21 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
*/
tid = txBegin(new_dir->i_sb, 0);
- mutex_lock(&JFS_IP(new_dir)->commit_mutex);
- mutex_lock(&JFS_IP(old_ip)->commit_mutex);
+ /*
+ * How do we know the locking is safe from deadlocks?
+ * The vfs does the hard part for us. Any time we are taking nested
+ * commit_mutexes, the vfs already has i_mutex held on the parent.
+ * Here, the vfs has already taken i_mutex on both old_dir and new_dir.
+ */
+ mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+ mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD);
if (old_dir != new_dir)
- mutex_lock(&JFS_IP(old_dir)->commit_mutex);
+ mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex,
+ COMMIT_MUTEX_SECOND_PARENT);
if (new_ip) {
- mutex_lock(&JFS_IP(new_ip)->commit_mutex);
+ mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex,
+ COMMIT_MUTEX_VICTIM);
/*
* Change existing directory entry to new inode number
*/
@@ -1357,8 +1365,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
tid = txBegin(dir->i_sb, 0);
- mutex_lock(&JFS_IP(dir)->commit_mutex);
- mutex_lock(&JFS_IP(ip)->commit_mutex);
+ mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+ mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
rc = jfs_init_acl(tid, ip, dir);
if (rc)
diff --git a/fs/libfs.c b/fs/libfs.c
index bd08e0e64a8..503898d5c4a 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -63,7 +63,7 @@ int dcache_dir_open(struct inode *inode, struct file *file)
{
static struct qstr cursor_name = {.len = 1, .name = "."};
- file->private_data = d_alloc(file->f_dentry, &cursor_name);
+ file->private_data = d_alloc(file->f_path.dentry, &cursor_name);
return file->private_data ? 0 : -ENOMEM;
}
@@ -76,7 +76,7 @@ int dcache_dir_close(struct inode *inode, struct file *file)
loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
{
- mutex_lock(&file->f_dentry->d_inode->i_mutex);
+ mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
switch (origin) {
case 1:
offset += file->f_pos;
@@ -84,7 +84,7 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
if (offset >= 0)
break;
default:
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return -EINVAL;
}
if (offset != file->f_pos) {
@@ -96,8 +96,8 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
spin_lock(&dcache_lock);
list_del(&cursor->d_u.d_child);
- p = file->f_dentry->d_subdirs.next;
- while (n && p != &file->f_dentry->d_subdirs) {
+ p = file->f_path.dentry->d_subdirs.next;
+ while (n && p != &file->f_path.dentry->d_subdirs) {
struct dentry *next;
next = list_entry(p, struct dentry, d_u.d_child);
if (!d_unhashed(next) && next->d_inode)
@@ -108,7 +108,7 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
spin_unlock(&dcache_lock);
}
}
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return offset;
}
@@ -126,7 +126,7 @@ static inline unsigned char dt_type(struct inode *inode)
int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct dentry *cursor = filp->private_data;
struct list_head *p, *q = &cursor->d_u.d_child;
ino_t ino;
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index b85a0ad2cfb..f4d45d4d835 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -36,7 +36,7 @@ struct nlm_wait {
struct nlm_host * b_host;
struct file_lock * b_lock; /* local file lock */
unsigned short b_reclaim; /* got to reclaim lock */
- u32 b_status; /* grant callback status */
+ __be32 b_status; /* grant callback status */
};
static LIST_HEAD(nlm_blocked);
@@ -53,7 +53,7 @@ struct nlm_wait *nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *
block->b_host = host;
block->b_lock = fl;
init_waitqueue_head(&block->b_wait);
- block->b_status = NLM_LCK_BLOCKED;
+ block->b_status = nlm_lck_blocked;
list_add(&block->b_list, &nlm_blocked);
}
return block;
@@ -89,7 +89,7 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
* nlmclnt_lock for an explanation.
*/
ret = wait_event_interruptible_timeout(block->b_wait,
- block->b_status != NLM_LCK_BLOCKED,
+ block->b_status != nlm_lck_blocked,
timeout);
if (ret < 0)
return -ERESTARTSYS;
@@ -126,12 +126,12 @@ __be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock
continue;
if (!nlm_cmp_addr(&block->b_host->h_addr, addr))
continue;
- if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_dentry->d_inode) ,fh) != 0)
+ if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
continue;
/* Alright, we found a lock. Set the return status
* and wake up the caller
*/
- block->b_status = NLM_LCK_GRANTED;
+ block->b_status = nlm_granted;
wake_up(&block->b_wait);
res = nlm_granted;
}
@@ -176,7 +176,7 @@ reclaimer(void *ptr)
lock_kernel();
lockd_up(0); /* note: this cannot fail as lockd is already running */
- dprintk("lockd: reclaiming locks for host %s", host->h_name);
+ dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
restart:
nsmstate = host->h_nsmstate;
@@ -206,12 +206,12 @@ restart:
host->h_reclaiming = 0;
up_write(&host->h_rwsem);
- dprintk("NLM: done reclaiming locks for host %s", host->h_name);
+ dprintk("NLM: done reclaiming locks for host %s\n", host->h_name);
/* Now, wake up all processes that sleep on a blocked lock */
list_for_each_entry(block, &nlm_blocked, b_list) {
if (block->b_host == host) {
- block->b_status = NLM_LCK_DENIED_GRACE_PERIOD;
+ block->b_status = nlm_lck_denied_grace_period;
wake_up(&block->b_wait);
}
}
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 497c3cd59d5..0b4acc1c5e7 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -27,7 +27,7 @@
static int nlmclnt_test(struct nlm_rqst *, struct file_lock *);
static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *);
static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *);
-static int nlm_stat_to_errno(u32 stat);
+static int nlm_stat_to_errno(__be32 stat);
static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host);
static int nlmclnt_cancel(struct nlm_host *, int , struct file_lock *);
@@ -129,7 +129,7 @@ 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));
+ memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh));
lock->caller = utsname()->nodename;
lock->oh.data = req->a_owner;
lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
@@ -325,7 +325,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
}
break;
} else
- if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) {
+ if (resp->status == nlm_lck_denied_grace_period) {
dprintk("lockd: server in grace period\n");
if (argp->reclaim) {
printk(KERN_WARNING
@@ -411,10 +411,10 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
goto out;
switch (req->a_res.status) {
- case NLM_LCK_GRANTED:
+ case nlm_granted:
fl->fl_type = F_UNLCK;
break;
- case NLM_LCK_DENIED:
+ case nlm_lck_denied:
/*
* Report the conflicting lock back to the application.
*/
@@ -524,9 +524,9 @@ again:
if (!req->a_args.block)
break;
/* Did a reclaimer thread notify us of a server reboot? */
- if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD)
+ if (resp->status == nlm_lck_denied_grace_period)
continue;
- if (resp->status != NLM_LCK_BLOCKED)
+ if (resp->status != nlm_lck_blocked)
break;
/* Wait on an NLM blocking lock */
status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);
@@ -535,11 +535,11 @@ again:
*/
if (status < 0)
goto out_unblock;
- if (resp->status != NLM_LCK_BLOCKED)
+ if (resp->status != nlm_lck_blocked)
break;
}
- if (resp->status == NLM_LCK_GRANTED) {
+ if (resp->status == nlm_granted) {
down_read(&host->h_rwsem);
/* Check whether or not the server has rebooted */
if (fl->fl_u.nfs_fl.state != host->h_state) {
@@ -556,7 +556,7 @@ again:
out_unblock:
nlmclnt_finish_block(block);
/* Cancel the blocked request if it is still pending */
- if (resp->status == NLM_LCK_BLOCKED)
+ if (resp->status == nlm_lck_blocked)
nlmclnt_cancel(host, req->a_args.block, fl);
out:
nlm_release_call(req);
@@ -585,12 +585,12 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
req->a_args.reclaim = 1;
if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0
- && req->a_res.status == NLM_LCK_GRANTED)
+ && req->a_res.status == nlm_granted)
return 0;
printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d "
"(errno %d, status %d)\n", fl->fl_pid,
- status, req->a_res.status);
+ status, ntohl(req->a_res.status));
/*
* FIXME: This is a serious failure. We can
@@ -637,10 +637,10 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
if (status < 0)
goto out;
- if (resp->status == NLM_LCK_GRANTED)
+ if (resp->status == nlm_granted)
goto out;
- if (resp->status != NLM_LCK_DENIED_NOLOCKS)
+ if (resp->status != nlm_lck_denied_nolocks)
printk("lockd: unexpected unlock status: %d\n", resp->status);
/* What to do now? I'm out of my depth... */
status = -ENOLCK;
@@ -652,7 +652,7 @@ out:
static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
{
struct nlm_rqst *req = data;
- int status = req->a_res.status;
+ u32 status = ntohl(req->a_res.status);
if (RPC_ASSASSINATED(task))
goto die;
@@ -720,6 +720,7 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl
static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
{
struct nlm_rqst *req = data;
+ u32 status = ntohl(req->a_res.status);
if (RPC_ASSASSINATED(task))
goto die;
@@ -731,9 +732,9 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
}
dprintk("lockd: cancel status %u (task %u)\n",
- req->a_res.status, task->tk_pid);
+ status, task->tk_pid);
- switch (req->a_res.status) {
+ switch (status) {
case NLM_LCK_GRANTED:
case NLM_LCK_DENIED_GRACE_PERIOD:
case NLM_LCK_DENIED:
@@ -744,7 +745,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
goto retry_cancel;
default:
printk(KERN_NOTICE "lockd: weird return %d for CANCEL call\n",
- req->a_res.status);
+ status);
}
die:
@@ -768,9 +769,9 @@ static const struct rpc_call_ops nlmclnt_cancel_ops = {
* Convert an NLM status code to a generic kernel errno
*/
static int
-nlm_stat_to_errno(u32 status)
+nlm_stat_to_errno(__be32 status)
{
- switch(status) {
+ switch(ntohl(status)) {
case NLM_LCK_GRANTED:
return 0;
case NLM_LCK_DENIED:
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 7e219b93855..c7db0a5bccd 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -343,8 +343,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
__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,
- file->f_file->f_dentry->d_inode->i_ino,
+ file->f_file->f_path.dentry->d_inode->i_sb->s_id,
+ file->f_file->f_path.dentry->d_inode->i_ino,
lock->fl.fl_type, lock->fl.fl_pid,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end,
@@ -420,8 +420,8 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
struct nlm_lock *conflock)
{
dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
- file->f_file->f_dentry->d_inode->i_sb->s_id,
- file->f_file->f_dentry->d_inode->i_ino,
+ file->f_file->f_path.dentry->d_inode->i_sb->s_id,
+ file->f_file->f_path.dentry->d_inode->i_ino,
lock->fl.fl_type,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
@@ -454,8 +454,8 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
int error;
dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n",
- file->f_file->f_dentry->d_inode->i_sb->s_id,
- file->f_file->f_dentry->d_inode->i_ino,
+ file->f_file->f_path.dentry->d_inode->i_sb->s_id,
+ file->f_file->f_path.dentry->d_inode->i_ino,
lock->fl.fl_pid,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
@@ -483,8 +483,8 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
int status = 0;
dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
- file->f_file->f_dentry->d_inode->i_sb->s_id,
- file->f_file->f_dentry->d_inode->i_ino,
+ file->f_file->f_path.dentry->d_inode->i_sb->s_id,
+ file->f_file->f_path.dentry->d_inode->i_ino,
lock->fl.fl_pid,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
@@ -645,7 +645,7 @@ static const struct rpc_call_ops nlmsvc_grant_ops = {
* block.
*/
void
-nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status)
+nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
{
struct nlm_block *block;
@@ -655,7 +655,7 @@ nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status)
return;
if (block) {
- if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
+ if (status == nlm_lck_denied_grace_period) {
/* Try again in a couple of seconds */
nlmsvc_insert_block(block, 10 * HZ);
} else {
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 6220dc2a3f2..068886de4dd 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -39,7 +39,7 @@ nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
return nlm_lck_denied;
}
- share = (struct nlm_share *) kmalloc(sizeof(*share) + oh->len,
+ share = kmalloc(sizeof(*share) + oh->len,
GFP_KERNEL);
if (share == NULL)
return nlm_lck_denied_nolocks;
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index e83024e1604..c0df00c74ce 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -43,7 +43,7 @@ static inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f)
static inline void nlm_debug_print_file(char *msg, struct nlm_file *file)
{
- struct inode *inode = file->f_file->f_dentry->d_inode;
+ struct inode *inode = file->f_file->f_path.dentry->d_inode;
dprintk("lockd: %s %s/%ld\n",
msg, inode->i_sb->s_id, inode->i_ino);
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index b7c949256e5..34dae5d7073 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -361,7 +361,7 @@ nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm_decode_cookie(p, &resp->cookie)))
return 0;
- resp->status = ntohl(*p++);
+ resp->status = *p++;
return xdr_argsize_check(rqstp, p);
}
@@ -407,8 +407,8 @@ nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm_decode_cookie(p, &resp->cookie)))
return -EIO;
- resp->status = ntohl(*p++);
- if (resp->status == NLM_LCK_DENIED) {
+ resp->status = *p++;
+ if (resp->status == nlm_lck_denied) {
struct file_lock *fl = &resp->lock.fl;
u32 excl;
s32 start, len, end;
@@ -506,7 +506,7 @@ nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm_decode_cookie(p, &resp->cookie)))
return -EIO;
- resp->status = ntohl(*p++);
+ resp->status = *p++;
return 0;
}
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index f4c0b2b9f75..a7824055121 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -367,7 +367,7 @@ nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
return 0;
- resp->status = ntohl(*p++);
+ resp->status = *p++;
return xdr_argsize_check(rqstp, p);
}
@@ -413,8 +413,8 @@ nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
return -EIO;
- resp->status = ntohl(*p++);
- if (resp->status == NLM_LCK_DENIED) {
+ resp->status = *p++;
+ if (resp->status == nlm_lck_denied) {
struct file_lock *fl = &resp->lock.fl;
u32 excl;
s64 start, end, len;
@@ -512,7 +512,7 @@ nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
return -EIO;
- resp->status = ntohl(*p++);
+ resp->status = *p++;
return 0;
}
diff --git a/fs/locks.c b/fs/locks.c
index 1cb0c57fedb..52a81005dab 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -321,7 +321,7 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
start = filp->f_pos;
break;
case SEEK_END:
- start = i_size_read(filp->f_dentry->d_inode);
+ start = i_size_read(filp->f_path.dentry->d_inode);
break;
default:
return -EINVAL;
@@ -371,7 +371,7 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl,
start = filp->f_pos;
break;
case SEEK_END:
- start = i_size_read(filp->f_dentry->d_inode);
+ start = i_size_read(filp->f_path.dentry->d_inode);
break;
default:
return -EINVAL;
@@ -672,7 +672,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl,
struct file_lock *cfl;
lock_kernel();
- for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
+ for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
if (!IS_POSIX(cfl))
continue;
if (posix_locks_conflict(cfl, fl))
@@ -734,7 +734,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
{
struct file_lock *new_fl = NULL;
struct file_lock **before;
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode * inode = filp->f_path.dentry->d_inode;
int error = 0;
int found = 0;
@@ -1018,7 +1018,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
*/
int posix_lock_file(struct file *filp, struct file_lock *fl)
{
- return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, NULL);
+ return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, NULL);
}
EXPORT_SYMBOL(posix_lock_file);
@@ -1033,7 +1033,7 @@ EXPORT_SYMBOL(posix_lock_file);
int posix_lock_file_conf(struct file *filp, struct file_lock *fl,
struct file_lock *conflock)
{
- return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, conflock);
+ return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, conflock);
}
EXPORT_SYMBOL(posix_lock_file_conf);
@@ -1333,8 +1333,8 @@ int fcntl_getlease(struct file *filp)
int type = F_UNLCK;
lock_kernel();
- time_out_leases(filp->f_dentry->d_inode);
- for (fl = filp->f_dentry->d_inode->i_flock; fl && IS_LEASE(fl);
+ time_out_leases(filp->f_path.dentry->d_inode);
+ for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl);
fl = fl->fl_next) {
if (fl->fl_file == filp) {
type = fl->fl_type & ~F_INPROGRESS;
@@ -1359,7 +1359,7 @@ int fcntl_getlease(struct file *filp)
static int __setlease(struct file *filp, long arg, struct file_lock **flp)
{
struct file_lock *fl, **before, **my_before = NULL, *lease;
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int error, rdlease_count = 0, wrlease_count = 0;
@@ -1448,7 +1448,7 @@ out:
int setlease(struct file *filp, long arg, struct file_lock **lease)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int error;
@@ -1482,7 +1482,7 @@ EXPORT_SYMBOL(setlease);
int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
{
struct file_lock fl, *flp = &fl;
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int error;
@@ -1692,7 +1692,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
if (copy_from_user(&flock, l, sizeof(flock)))
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
@@ -1835,7 +1835,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
if (copy_from_user(&flock, l, sizeof(flock)))
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
@@ -1922,7 +1922,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
* posix_lock_file(). Another process could be setting a lock on this
* file at the same time, but we wouldn't remove that lock anyway.
*/
- if (!filp->f_dentry->d_inode->i_flock)
+ if (!filp->f_path.dentry->d_inode->i_flock)
return;
lock.fl_type = F_UNLCK;
@@ -1951,7 +1951,7 @@ EXPORT_SYMBOL(locks_remove_posix);
*/
void locks_remove_flock(struct file *filp)
{
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode * inode = filp->f_path.dentry->d_inode;
struct file_lock *fl;
struct file_lock **before;
@@ -2020,7 +2020,7 @@ static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
struct inode *inode = NULL;
if (fl->fl_file != NULL)
- inode = fl->fl_file->f_dentry->d_inode;
+ inode = fl->fl_file->f_path.dentry->d_inode;
out += sprintf(out, "%d:%s ", id, pfx);
if (IS_POSIX(fl)) {
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 2b0a389d198..ab782c4086f 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -82,7 +82,7 @@ static inline void *minix_next_entry(void *de, struct minix_sb_info *sbi)
static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
unsigned long pos = filp->f_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
unsigned offset = pos & ~PAGE_CACHE_MASK;
unsigned long n = pos >> PAGE_CACHE_SHIFT;
diff --git a/fs/namei.c b/fs/namei.c
index db1bca26d88..e4f108f0823 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -297,7 +297,7 @@ int vfs_permission(struct nameidata *nd, int mask)
*/
int file_permission(struct file *file, int mask)
{
- return permission(file->f_dentry->d_inode, mask, NULL);
+ return permission(file->f_path.dentry->d_inode, mask, NULL);
}
/*
@@ -333,7 +333,7 @@ int get_write_access(struct inode * inode)
int deny_write_access(struct file * file)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
spin_lock(&inode->i_lock);
if (atomic_read(&inode->i_writecount) > 0) {
@@ -368,7 +368,7 @@ void path_release_on_umount(struct nameidata *nd)
*/
void release_open_intent(struct nameidata *nd)
{
- if (nd->intent.open.file->f_dentry == NULL)
+ if (nd->intent.open.file->f_path.dentry == NULL)
put_filp(nd->intent.open.file);
else
fput(nd->intent.open.file);
@@ -572,11 +572,6 @@ fail:
return PTR_ERR(link);
}
-struct path {
- struct vfsmount *mnt;
- struct dentry *dentry;
-};
-
static inline void dput_path(struct path *path, struct nameidata *nd)
{
dput(path->dentry);
@@ -1143,7 +1138,7 @@ static int fastcall do_path_lookup(int dfd, const char *name,
if (!file)
goto out_fail;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
retval = -ENOTDIR;
if (!S_ISDIR(dentry->d_inode->i_mode))
@@ -1153,7 +1148,7 @@ static int fastcall do_path_lookup(int dfd, const char *name,
if (retval)
goto fput_fail;
- nd->mnt = mntget(file->f_vfsmnt);
+ nd->mnt = mntget(file->f_path.mnt);
nd->dentry = dget(dentry);
fput_light(file, fput_needed);
diff --git a/fs/namespace.c b/fs/namespace.c
index b00ac84ebbd..5ef336c1103 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -20,7 +20,7 @@
#include <linux/module.h>
#include <linux/sysfs.h>
#include <linux/seq_file.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/mount.h>
@@ -133,10 +133,10 @@ struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
static inline int check_mnt(struct vfsmount *mnt)
{
- return mnt->mnt_namespace == current->nsproxy->namespace;
+ return mnt->mnt_ns == current->nsproxy->mnt_ns;
}
-static void touch_namespace(struct namespace *ns)
+static void touch_mnt_namespace(struct mnt_namespace *ns)
{
if (ns) {
ns->event = ++event;
@@ -144,7 +144,7 @@ static void touch_namespace(struct namespace *ns)
}
}
-static void __touch_namespace(struct namespace *ns)
+static void __touch_mnt_namespace(struct mnt_namespace *ns)
{
if (ns && ns->event != event) {
ns->event = event;
@@ -187,19 +187,19 @@ static void commit_tree(struct vfsmount *mnt)
struct vfsmount *parent = mnt->mnt_parent;
struct vfsmount *m;
LIST_HEAD(head);
- struct namespace *n = parent->mnt_namespace;
+ struct mnt_namespace *n = parent->mnt_ns;
BUG_ON(parent == mnt);
list_add_tail(&head, &mnt->mnt_list);
list_for_each_entry(m, &head, mnt_list)
- m->mnt_namespace = n;
+ m->mnt_ns = n;
list_splice(&head, n->list.prev);
list_add_tail(&mnt->mnt_hash, mount_hashtable +
hash(parent, mnt->mnt_mountpoint));
list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
- touch_namespace(n);
+ touch_mnt_namespace(n);
}
static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root)
@@ -320,7 +320,7 @@ EXPORT_SYMBOL(mnt_unpin);
/* iterator */
static void *m_start(struct seq_file *m, loff_t *pos)
{
- struct namespace *n = m->private;
+ struct mnt_namespace *n = m->private;
struct list_head *p;
loff_t l = *pos;
@@ -333,7 +333,7 @@ static void *m_start(struct seq_file *m, loff_t *pos)
static void *m_next(struct seq_file *m, void *v, loff_t *pos)
{
- struct namespace *n = m->private;
+ struct mnt_namespace *n = m->private;
struct list_head *p = ((struct vfsmount *)v)->mnt_list.next;
(*pos)++;
return p == &n->list ? NULL : list_entry(p, struct vfsmount, mnt_list);
@@ -368,6 +368,7 @@ static int show_vfsmnt(struct seq_file *m, void *v)
{ MNT_NOEXEC, ",noexec" },
{ MNT_NOATIME, ",noatime" },
{ MNT_NODIRATIME, ",nodiratime" },
+ { MNT_RELATIME, ",relatime" },
{ 0, NULL }
};
struct proc_fs_info *fs_infop;
@@ -526,8 +527,8 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
list_for_each_entry(p, kill, mnt_hash) {
list_del_init(&p->mnt_expire);
list_del_init(&p->mnt_list);
- __touch_namespace(p->mnt_namespace);
- p->mnt_namespace = NULL;
+ __touch_mnt_namespace(p->mnt_ns);
+ p->mnt_ns = NULL;
list_del_init(&p->mnt_child);
if (p->mnt_parent != p)
p->mnt_mountpoint->d_mounted--;
@@ -830,7 +831,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->nsproxy->namespace);
+ touch_mnt_namespace(current->nsproxy->mnt_ns);
} else {
mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
commit_tree(source_mnt);
@@ -1145,9 +1146,9 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
*/
if (!propagate_mount_busy(mnt, 2)) {
/* delete from the namespace */
- touch_namespace(mnt->mnt_namespace);
+ touch_mnt_namespace(mnt->mnt_ns);
list_del_init(&mnt->mnt_list);
- mnt->mnt_namespace = NULL;
+ mnt->mnt_ns = NULL;
umount_tree(mnt, 1, umounts);
spin_unlock(&vfsmount_lock);
} else {
@@ -1168,7 +1169,7 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
*/
static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts)
{
- struct namespace *namespace;
+ struct mnt_namespace *ns;
struct vfsmount *mnt;
while (!list_empty(graveyard)) {
@@ -1178,10 +1179,10 @@ static void expire_mount_list(struct list_head *graveyard, struct list_head *mou
/* don't do anything if the namespace is dead - all the
* vfsmounts from it are going away anyway */
- namespace = mnt->mnt_namespace;
- if (!namespace || !namespace->root)
+ ns = mnt->mnt_ns;
+ if (!ns || !ns->root)
continue;
- get_namespace(namespace);
+ get_mnt_ns(ns);
spin_unlock(&vfsmount_lock);
down_write(&namespace_sem);
@@ -1189,7 +1190,7 @@ static void expire_mount_list(struct list_head *graveyard, struct list_head *mou
up_write(&namespace_sem);
release_mounts(&umounts);
mntput(mnt);
- put_namespace(namespace);
+ put_mnt_ns(ns);
spin_lock(&vfsmount_lock);
}
}
@@ -1405,9 +1406,11 @@ long do_mount(char *dev_name, char *dir_name, char *type_page,
mnt_flags |= MNT_NOATIME;
if (flags & MS_NODIRATIME)
mnt_flags |= MNT_NODIRATIME;
+ if (flags & MS_RELATIME)
+ mnt_flags |= MNT_RELATIME;
flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE |
- MS_NOATIME | MS_NODIRATIME);
+ MS_NOATIME | MS_NODIRATIME | MS_RELATIME);
/* ... and get the mountpoint */
retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd);
@@ -1439,14 +1442,15 @@ dput_out:
* Allocate a new namespace structure and populate it with contents
* copied from the namespace of the passed in task structure.
*/
-struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
+struct mnt_namespace *dup_mnt_ns(struct task_struct *tsk,
+ struct fs_struct *fs)
{
- struct namespace *namespace = tsk->nsproxy->namespace;
- struct namespace *new_ns;
+ struct mnt_namespace *mnt_ns = tsk->nsproxy->mnt_ns;
+ struct mnt_namespace *new_ns;
struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
struct vfsmount *p, *q;
- new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL);
+ new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
if (!new_ns)
return NULL;
@@ -1457,7 +1461,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
down_write(&namespace_sem);
/* First pass: copy the tree topology */
- new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root,
+ new_ns->root = copy_tree(mnt_ns->root, mnt_ns->root->mnt_root,
CL_COPY_ALL | CL_EXPIRE);
if (!new_ns->root) {
up_write(&namespace_sem);
@@ -1473,10 +1477,10 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
* as belonging to new namespace. We have already acquired a private
* fs_struct, so tsk->fs->lock is not needed.
*/
- p = namespace->root;
+ p = mnt_ns->root;
q = new_ns->root;
while (p) {
- q->mnt_namespace = new_ns;
+ q->mnt_ns = new_ns;
if (fs) {
if (p == fs->rootmnt) {
rootmnt = p;
@@ -1491,7 +1495,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
fs->altrootmnt = mntget(q);
}
}
- p = next_mnt(p, namespace->root);
+ p = next_mnt(p, mnt_ns->root);
q = next_mnt(q, new_ns->root);
}
up_write(&namespace_sem);
@@ -1506,16 +1510,16 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
return new_ns;
}
-int copy_namespace(int flags, struct task_struct *tsk)
+int copy_mnt_ns(int flags, struct task_struct *tsk)
{
- struct namespace *namespace = tsk->nsproxy->namespace;
- struct namespace *new_ns;
+ struct mnt_namespace *ns = tsk->nsproxy->mnt_ns;
+ struct mnt_namespace *new_ns;
int err = 0;
- if (!namespace)
+ if (!ns)
return 0;
- get_namespace(namespace);
+ get_mnt_ns(ns);
if (!(flags & CLONE_NEWNS))
return 0;
@@ -1525,16 +1529,16 @@ int copy_namespace(int flags, struct task_struct *tsk)
goto out;
}
- new_ns = dup_namespace(tsk, tsk->fs);
+ new_ns = dup_mnt_ns(tsk, tsk->fs);
if (!new_ns) {
err = -ENOMEM;
goto out;
}
- tsk->nsproxy->namespace = new_ns;
+ tsk->nsproxy->mnt_ns = new_ns;
out:
- put_namespace(namespace);
+ put_mnt_ns(ns);
return err;
}
@@ -1754,7 +1758,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->nsproxy->namespace);
+ touch_mnt_namespace(current->nsproxy->mnt_ns);
spin_unlock(&vfsmount_lock);
chroot_fs_refs(&user_nd, &new_nd);
security_sb_post_pivotroot(&user_nd, &new_nd);
@@ -1779,27 +1783,27 @@ out3:
static void __init init_mount_tree(void)
{
struct vfsmount *mnt;
- struct namespace *namespace;
+ struct mnt_namespace *ns;
mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
if (IS_ERR(mnt))
panic("Can't create rootfs");
- namespace = kmalloc(sizeof(*namespace), GFP_KERNEL);
- if (!namespace)
+ ns = kmalloc(sizeof(*ns), GFP_KERNEL);
+ if (!ns)
panic("Can't allocate initial namespace");
- atomic_set(&namespace->count, 1);
- INIT_LIST_HEAD(&namespace->list);
- init_waitqueue_head(&namespace->poll);
- namespace->event = 0;
- list_add(&mnt->mnt_list, &namespace->list);
- namespace->root = mnt;
- mnt->mnt_namespace = namespace;
-
- 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);
+ atomic_set(&ns->count, 1);
+ INIT_LIST_HEAD(&ns->list);
+ init_waitqueue_head(&ns->poll);
+ ns->event = 0;
+ list_add(&mnt->mnt_list, &ns->list);
+ ns->root = mnt;
+ mnt->mnt_ns = ns;
+
+ init_task.nsproxy->mnt_ns = ns;
+ get_mnt_ns(ns);
+
+ set_fs_pwd(current->fs, ns->root, ns->root->mnt_root);
+ set_fs_root(current->fs, ns->root, ns->root->mnt_root);
}
void __init mnt_init(unsigned long mempages)
@@ -1860,11 +1864,11 @@ void __init mnt_init(unsigned long mempages)
init_mount_tree();
}
-void __put_namespace(struct namespace *namespace)
+void __put_mnt_ns(struct mnt_namespace *ns)
{
- struct vfsmount *root = namespace->root;
+ struct vfsmount *root = ns->root;
LIST_HEAD(umount_list);
- namespace->root = NULL;
+ ns->root = NULL;
spin_unlock(&vfsmount_lock);
down_write(&namespace_sem);
spin_lock(&vfsmount_lock);
@@ -1872,5 +1876,5 @@ void __put_namespace(struct namespace *namespace)
spin_unlock(&vfsmount_lock);
up_write(&namespace_sem);
release_mounts(&umount_list);
- kfree(namespace);
+ kfree(ns);
}
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 458b3b78519..73747772c3b 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -402,7 +402,7 @@ static time_t ncp_obtain_mtime(struct dentry *dentry)
static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct page *page = NULL;
struct ncp_server *server = NCP_SERVER(inode);
@@ -554,7 +554,7 @@ static int
ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
struct ncp_cache_control *ctrl, struct ncp_entry_info *entry)
{
- struct dentry *newdent, *dentry = filp->f_dentry;
+ struct dentry *newdent, *dentry = filp->f_path.dentry;
struct inode *newino, *inode = dentry->d_inode;
struct ncp_cache_control ctl = *ctrl;
struct qstr qname;
@@ -649,7 +649,7 @@ static void
ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
struct ncp_cache_control *ctl)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct ncp_server *server = NCP_SERVER(inode);
struct ncp_volume_info info;
@@ -685,7 +685,7 @@ static void
ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
struct ncp_cache_control *ctl)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *dir = dentry->d_inode;
struct ncp_server *server = NCP_SERVER(dir);
struct nw_search_sequence seq;
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index df37524b85d..b91fea03b1c 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -101,7 +101,7 @@ out:
static ssize_t
ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
size_t already_read = 0;
off_t pos;
@@ -182,7 +182,7 @@ outrel:
static ssize_t
ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
size_t already_written = 0;
off_t pos;
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index fae53243bb9..67a90bf795d 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -327,11 +327,12 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options)
char *optarg;
unsigned long optint;
int version = 0;
+ int ret;
data->flags = 0;
data->int_flags = 0;
data->mounted_uid = 0;
- data->wdog_pid = -1;
+ data->wdog_pid = NULL;
data->ncp_fd = ~0;
data->time_out = 10;
data->retry_count = 20;
@@ -343,8 +344,9 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options)
data->mounted_vol[0] = 0;
while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
- if (optval < 0)
- return optval;
+ ret = optval;
+ if (ret < 0)
+ goto err;
switch (optval) {
case 'u':
data->uid = optint;
@@ -371,7 +373,7 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options)
data->flags = optint;
break;
case 'w':
- data->wdog_pid = optint;
+ data->wdog_pid = find_get_pid(optint);
break;
case 'n':
data->ncp_fd = optint;
@@ -380,18 +382,21 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options)
data->info_fd = optint;
break;
case 'v':
- if (optint < NCP_MOUNT_VERSION_V4) {
- return -ECHRNG;
- }
- if (optint > NCP_MOUNT_VERSION_V5) {
- return -ECHRNG;
- }
+ ret = -ECHRNG;
+ if (optint < NCP_MOUNT_VERSION_V4)
+ goto err;
+ if (optint > NCP_MOUNT_VERSION_V5)
+ goto err;
version = optint;
break;
}
}
return 0;
+err:
+ put_pid(data->wdog_pid);
+ data->wdog_pid = NULL;
+ return ret;
}
static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
@@ -409,6 +414,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
#endif
struct ncp_entry_info finfo;
+ data.wdog_pid = NULL;
server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
if (!server)
return -ENOMEM;
@@ -425,7 +431,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
data.flags = md->flags;
data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
data.mounted_uid = md->mounted_uid;
- data.wdog_pid = md->wdog_pid;
+ data.wdog_pid = find_get_pid(md->wdog_pid);
data.ncp_fd = md->ncp_fd;
data.time_out = md->time_out;
data.retry_count = md->retry_count;
@@ -445,7 +451,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
data.flags = md->flags;
data.int_flags = 0;
data.mounted_uid = md->mounted_uid;
- data.wdog_pid = md->wdog_pid;
+ data.wdog_pid = find_get_pid(md->wdog_pid);
data.ncp_fd = md->ncp_fd;
data.time_out = md->time_out;
data.retry_count = md->retry_count;
@@ -471,7 +477,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
if (!ncp_filp)
goto out;
error = -ENOTSOCK;
- sock_inode = ncp_filp->f_dentry->d_inode;
+ sock_inode = ncp_filp->f_path.dentry->d_inode;
if (!S_ISSOCK(sock_inode->i_mode))
goto out_fput;
sock = SOCKET_I(sock_inode);
@@ -504,7 +510,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
if (!server->info_filp)
goto out_fput;
error = -ENOTSOCK;
- sock_inode = server->info_filp->f_dentry->d_inode;
+ sock_inode = server->info_filp->f_path.dentry->d_inode;
if (!S_ISSOCK(sock_inode->i_mode))
goto out_fput2;
info_sock = SOCKET_I(sock_inode);
@@ -679,6 +685,7 @@ out_fput:
*/
fput(ncp_filp);
out:
+ put_pid(data.wdog_pid);
sb->s_fs_info = NULL;
kfree(server);
return error;
@@ -711,7 +718,8 @@ static void ncp_put_super(struct super_block *sb)
if (server->info_filp)
fput(server->info_filp);
fput(server->ncp_filp);
- kill_proc(server->m.wdog_pid, SIGTERM, 1);
+ kill_pid(server->m.wdog_pid, SIGTERM, 1);
+ put_pid(server->m.wdog_pid);
kfree(server->priv.data);
kfree(server->auth.object_name);
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 589d1eac55c..8843a83d4ef 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -35,7 +35,7 @@ static int
ncp_get_fs_info(struct ncp_server * server, struct file *file,
struct ncp_fs_info __user *arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct ncp_fs_info info;
if ((file_permission(file, MAY_WRITE) != 0)
@@ -65,7 +65,7 @@ static int
ncp_get_fs_info_v2(struct ncp_server * server, struct file *file,
struct ncp_fs_info_v2 __user * arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct ncp_fs_info_v2 info2;
if ((file_permission(file, MAY_WRITE) != 0)
@@ -136,7 +136,7 @@ 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 inode *inode = file->f_path.dentry->d_inode;
struct compat_ncp_fs_info_v2 info2;
if ((file_permission(file, MAY_WRITE) != 0)
@@ -824,7 +824,7 @@ outrel:
#ifdef CONFIG_COMPAT
long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int ret;
lock_kernel();
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index e7d5a3097fe..70a69115500 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -29,7 +29,7 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
unsigned long address, int *type)
{
struct file *file = area->vm_file;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct page* page;
char *pg_addr;
@@ -106,7 +106,7 @@ static struct vm_operations_struct ncp_file_mmap =
/* This is used for a general mmap of a ncp file */
int ncp_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
DPRINTK("ncp_mmap: called\n");
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index b34cd16f472..d9ba8cb0ee7 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -172,7 +172,7 @@ static
int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
{
struct file *file = desc->file;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct rpc_cred *cred = nfs_file_cred(file);
unsigned long timestamp;
int error;
@@ -183,7 +183,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
again:
timestamp = jiffies;
- error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->entry->cookie, page,
+ error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, desc->entry->cookie, page,
NFS_SERVER(inode)->dtsize, desc->plus);
if (error < 0) {
/* We requested READDIRPLUS, but the server doesn't grok it */
@@ -308,7 +308,7 @@ int find_dirent_index(nfs_readdir_descriptor_t *desc)
static inline
int find_dirent_page(nfs_readdir_descriptor_t *desc)
{
- struct inode *inode = desc->file->f_dentry->d_inode;
+ struct inode *inode = desc->file->f_path.dentry->d_inode;
struct page *page;
int status;
@@ -464,7 +464,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
filldir_t filldir)
{
struct file *file = desc->file;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct rpc_cred *cred = nfs_file_cred(file);
struct page *page = NULL;
int status;
@@ -477,7 +477,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
status = -ENOMEM;
goto out;
}
- desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, *desc->dir_cookie,
+ desc->error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, *desc->dir_cookie,
page,
NFS_SERVER(inode)->dtsize,
desc->plus);
@@ -516,7 +516,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
*/
static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
nfs_readdir_descriptor_t my_desc,
*desc = &my_desc;
@@ -532,7 +532,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
lock_kernel();
- res = nfs_revalidate_mapping(inode, filp->f_mapping);
+ res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping);
if (res < 0) {
unlock_kernel();
return res;
@@ -599,7 +599,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
{
- mutex_lock(&filp->f_dentry->d_inode->i_mutex);
+ mutex_lock(&filp->f_path.dentry->d_inode->i_mutex);
switch (origin) {
case 1:
offset += filp->f_pos;
@@ -615,7 +615,7 @@ loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
((struct nfs_open_context *)filp->private_data)->dir_cookie = 0;
}
out:
- mutex_unlock(&filp->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex);
return offset;
}
@@ -1102,7 +1102,7 @@ no_open:
static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
{
- struct dentry *parent = desc->file->f_dentry;
+ struct dentry *parent = desc->file->f_path.dentry;
struct inode *dir = parent->d_inode;
struct nfs_entry *entry = desc->entry;
struct dentry *dentry, *alias;
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index f9d678f4ae0..bd21d7fde65 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -116,7 +116,7 @@ static inline int put_dreq(struct nfs_direct_req *dreq)
ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t pos, unsigned long nr_segs)
{
dprintk("NFS: nfs_direct_IO (%s) off/no(%Ld/%lu) EINVAL\n",
- iocb->ki_filp->f_dentry->d_name.name,
+ iocb->ki_filp->f_path.dentry->d_name.name,
(long long) pos, nr_segs);
return -EINVAL;
@@ -734,8 +734,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
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,
+ file->f_path.dentry->d_parent->d_name.name,
+ file->f_path.dentry->d_name.name,
(unsigned long) count, (long long) pos);
if (nr_segs != 1)
@@ -798,8 +798,8 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
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,
+ file->f_path.dentry->d_parent->d_name.name,
+ file->f_path.dentry->d_name.name,
(unsigned long) count, (long long) pos);
if (nr_segs != 1)
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 8e28bffc35a..9e4a2b70995 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -176,7 +176,7 @@ static int
nfs_file_flush(struct file *file, fl_owner_t id)
{
struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int status;
dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
@@ -201,7 +201,7 @@ static ssize_t
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 dentry * dentry = iocb->ki_filp->f_path.dentry;
struct inode * inode = dentry->d_inode;
ssize_t result;
size_t count = iov_length(iov, nr_segs);
@@ -226,7 +226,7 @@ static ssize_t
nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count,
read_actor_t actor, void *target)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
ssize_t res;
@@ -243,7 +243,7 @@ nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count,
static int
nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
int status;
@@ -315,14 +315,13 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
static int nfs_release_page(struct page *page, gfp_t gfp)
{
- /*
- * Avoid deadlock on nfs_wait_on_request().
- */
- if (!(gfp & __GFP_FS))
- return 0;
- /* Hack... Force nfs_wb_page() to write out the page */
- SetPageDirty(page);
- return !nfs_wb_page(page->mapping->host, page);
+ /* If PagePrivate() is set, then the page is not freeable */
+ return 0;
+}
+
+static int nfs_launder_page(struct page *page)
+{
+ return nfs_wb_page(page->mapping->host, page);
}
const struct address_space_operations nfs_file_aops = {
@@ -338,12 +337,13 @@ const struct address_space_operations nfs_file_aops = {
#ifdef CONFIG_NFS_DIRECTIO
.direct_IO = nfs_direct_IO,
#endif
+ .launder_page = nfs_launder_page,
};
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 dentry * dentry = iocb->ki_filp->f_path.dentry;
struct inode * inode = dentry->d_inode;
ssize_t result;
size_t count = iov_length(iov, nr_segs);
@@ -434,8 +434,9 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
BUG();
}
if (res < 0)
- printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
- __FUNCTION__);
+ dprintk(KERN_WARNING "%s: VFS is out of sync with lock manager"
+ " - error %d!\n",
+ __FUNCTION__, res);
return res;
}
@@ -535,8 +536,8 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
{
dprintk("NFS: nfs_flock(f=%s/%ld, t=%x, fl=%x)\n",
- filp->f_dentry->d_inode->i_sb->s_id,
- filp->f_dentry->d_inode->i_ino,
+ filp->f_path.dentry->d_inode->i_sb->s_id,
+ filp->f_path.dentry->d_inode->i_ino,
fl->fl_type, fl->fl_flags);
/*
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 20c6f39ea38..8391bd7a83c 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -31,7 +31,7 @@
#include <linux/nfs_idmap.h>
#include <linux/vfs.h>
#include <linux/namei.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/security.h>
#include <asm/system.h>
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 82ad7110a1c..9d4a6b2d199 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -377,7 +377,7 @@ idmap_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
static ssize_t
idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
{
- struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
+ struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
struct idmap *idmap = (struct idmap *)rpci->private;
struct idmap_msg im_in, *im = &idmap->idmap_im;
struct idmap_hashtable *h;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 36680d1061b..d8349828283 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -496,7 +496,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx)
*/
static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode);
filp->private_data = get_nfs_open_context(ctx);
@@ -528,7 +528,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c
static void nfs_file_clear_open_context(struct file *filp)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data;
if (ctx) {
@@ -551,7 +551,7 @@ int nfs_open(struct inode *inode, struct file *filp)
cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
if (IS_ERR(cred))
return PTR_ERR(cred);
- ctx = alloc_nfs_open_context(filp->f_vfsmnt, filp->f_dentry, cred);
+ ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred);
put_rpccred(cred);
if (ctx == NULL)
return -ENOMEM;
@@ -665,49 +665,86 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
return __nfs_revalidate_inode(server, inode);
}
+static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_space *mapping)
+{
+ struct nfs_inode *nfsi = NFS_I(inode);
+
+ if (mapping->nrpages != 0) {
+ int ret = invalidate_inode_pages2(mapping);
+ if (ret < 0)
+ return ret;
+ }
+ spin_lock(&inode->i_lock);
+ nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
+ if (S_ISDIR(inode->i_mode)) {
+ memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
+ /* This ensures we revalidate child dentries */
+ nfsi->cache_change_attribute = jiffies;
+ }
+ 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));
+ return 0;
+}
+
+static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
+{
+ int ret = 0;
+
+ mutex_lock(&inode->i_mutex);
+ if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_DATA) {
+ ret = nfs_sync_mapping(mapping);
+ if (ret == 0)
+ ret = nfs_invalidate_mapping_nolock(inode, mapping);
+ }
+ mutex_unlock(&inode->i_mutex);
+ return ret;
+}
+
/**
- * nfs_revalidate_mapping - Revalidate the pagecache
+ * nfs_revalidate_mapping_nolock - Revalidate the pagecache
* @inode - pointer to host inode
* @mapping - pointer to mapping
*/
-int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping)
{
struct nfs_inode *nfsi = NFS_I(inode);
int ret = 0;
- if (NFS_STALE(inode))
- ret = -ESTALE;
if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
- || nfs_attribute_timeout(inode))
+ || nfs_attribute_timeout(inode) || NFS_STALE(inode)) {
ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
- if (ret < 0)
- goto out;
+ if (ret < 0)
+ goto out;
+ }
+ if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
+ ret = nfs_invalidate_mapping_nolock(inode, mapping);
+out:
+ return ret;
+}
- if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
- 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)) {
- memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
- /* This ensures we revalidate child dentries */
- nfsi->cache_change_attribute = jiffies;
- }
- spin_unlock(&inode->i_lock);
+/**
+ * nfs_revalidate_mapping - Revalidate the pagecache
+ * @inode - pointer to host inode
+ * @mapping - pointer to mapping
+ *
+ * This version of the function will take the inode->i_mutex and attempt to
+ * flush out all dirty data if it needs to invalidate the page cache.
+ */
+int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+{
+ struct nfs_inode *nfsi = NFS_I(inode);
+ int ret = 0;
- 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));
+ if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
+ || nfs_attribute_timeout(inode) || NFS_STALE(inode)) {
+ ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ if (ret < 0)
+ goto out;
}
+ if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
+ ret = nfs_invalidate_mapping(inode, mapping);
out:
return ret;
}
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 510ae524f3f..acd8fe9762d 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -841,7 +841,7 @@ static void nfs3_proc_commit_setup(struct nfs_write_data *data, int how)
static int
nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
- return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
+ return nlmclnt_proc(filp->f_path.dentry->d_inode, cmd, fl);
}
const struct nfs_rpc_ops nfs_v3_clientops = {
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ee458aeab24..b3fd29baadc 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1877,7 +1877,7 @@ static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir,
struct nfs_server *server = NFS_SERVER(dir->d_inode);
struct unlink_desc *up;
- up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL);
+ up = kmalloc(sizeof(*up), GFP_KERNEL);
if (!up)
return -ENOMEM;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 10f5e80ca15..560536ad74a 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -651,7 +651,7 @@ nfs_proc_commit_setup(struct nfs_write_data *data, int how)
static int
nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
- return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
+ return nlmclnt_proc(filp->f_path.dentry->d_inode, cmd, fl);
}
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 6c686112cc0..525c136c7d8 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -50,7 +50,9 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
struct page *page;
- void *err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
+ void *err;
+
+ err = ERR_PTR(nfs_revalidate_mapping_nolock(inode, inode->i_mapping));
if (err)
goto read_failed;
page = read_cache_page(&inode->i_data, 0,
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 594eb16879e..345492e7864 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -754,8 +754,8 @@ int nfs_updatepage(struct file *file, struct page *page,
nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE);
dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n",
- file->f_dentry->d_parent->d_name.name,
- file->f_dentry->d_name.name, count,
+ file->f_path.dentry->d_parent->d_name.name,
+ file->f_path.dentry->d_name.name, count,
(long long)(page_offset(page) +offset));
/* If we're not using byte range locks, and we know the page
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index f37df46d2ea..49c310b8492 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -35,7 +35,6 @@
#include <linux/lockd/bind.h>
#define NFSDDBG_FACILITY NFSDDBG_EXPORT
-#define NFSD_PARANOIA 1
typedef struct auth_domain svc_client;
typedef struct svc_export svc_export;
@@ -787,15 +786,20 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
key.ex_dentry = dentry;
exp = svc_export_lookup(&key);
- if (exp != NULL)
- switch (cache_check(&svc_export_cache, &exp->h, reqp)) {
+ if (exp != NULL) {
+ int err;
+
+ err = cache_check(&svc_export_cache, &exp->h, reqp);
+ switch (err) {
case 0: break;
case -EAGAIN:
- exp = ERR_PTR(-EAGAIN);
+ case -ETIMEDOUT:
+ exp = ERR_PTR(err);
break;
default:
exp = NULL;
}
+ }
return exp;
}
@@ -950,6 +954,8 @@ exp_export(struct nfsctl_export *nxp)
exp = exp_get_by_name(clp, nd.mnt, nd.dentry, NULL);
+ memset(&new, 0, sizeof(new));
+
/* must make sure there won't be an ex_fsid clash */
if ((nxp->ex_flags & NFSEXP_FSID) &&
(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) &&
@@ -980,6 +986,9 @@ exp_export(struct nfsctl_export *nxp)
new.h.expiry_time = NEVER;
new.h.flags = 0;
+ new.ex_path = kstrdup(nxp->ex_path, GFP_KERNEL);
+ if (!new.ex_path)
+ goto finish;
new.ex_client = clp;
new.ex_mnt = nd.mnt;
new.ex_dentry = nd.dentry;
@@ -1000,10 +1009,11 @@ exp_export(struct nfsctl_export *nxp)
/* failed to create at least one index */
exp_do_unexport(exp);
cache_flush();
- err = -ENOMEM;
- }
-
+ } else
+ err = 0;
finish:
+ if (new.ex_path)
+ kfree(new.ex_path);
if (exp)
exp_put(exp);
if (fsid_key && !IS_ERR(fsid_key))
@@ -1104,6 +1114,10 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
path, nd.dentry, clp->name,
inode->i_sb->s_id, inode->i_ino);
exp = exp_parent(clp, nd.mnt, nd.dentry, NULL);
+ if (IS_ERR(exp)) {
+ err = PTR_ERR(exp);
+ goto out;
+ }
if (!exp) {
dprintk("nfsd: exp_rootfh export not found.\n");
goto out;
@@ -1159,12 +1173,10 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
mk_fsid_v1(fsidv, 0);
exp = exp_find(clp, 1, fsidv, creq);
- if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN)
- return nfserr_dropit;
+ if (IS_ERR(exp))
+ return nfserrno(PTR_ERR(exp));
if (exp == NULL)
return nfserr_perm;
- else if (IS_ERR(exp))
- return nfserrno(PTR_ERR(exp));
rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
exp_put(exp);
return rv;
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 11fdaf7721b..221acd1f11f 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -22,7 +22,7 @@
/*
* Note: we hold the dentry use count while the file is open.
*/
-static u32
+static __be32
nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp)
{
__be32 nfserr;
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index e3eca081698..edde5dc5f79 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -222,12 +222,10 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
{
struct dentry *dentry = resp->fh.fh_dentry;
struct inode *inode = dentry->d_inode;
- int w = nfsacl_size(
- (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
- (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
struct kvec *head = rqstp->rq_res.head;
unsigned int base;
int n;
+ int w;
if (dentry == NULL || dentry->d_inode == NULL)
return 0;
@@ -239,7 +237,9 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
return 0;
base = (char *)p - (char *)head->iov_base;
- rqstp->rq_res.page_len = w;
+ rqstp->rq_res.page_len = w = nfsacl_size(
+ (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
+ (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
while (w > 0) {
if (!rqstp->rq_respages[rqstp->rq_resused++])
return 0;
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index fcad2895ddb..3e3f2de82c3 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -171,19 +171,19 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
if (resp->status == 0 && dentry && dentry->d_inode) {
struct inode *inode = dentry->d_inode;
- int w = nfsacl_size(
- (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
- (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
struct kvec *head = rqstp->rq_res.head;
unsigned int base;
int n;
+ int w;
*p++ = htonl(resp->mask);
if (!xdr_ressize_check(rqstp, p))
return 0;
base = (char *)p - (char *)head->iov_base;
- rqstp->rq_res.page_len = w;
+ rqstp->rq_res.page_len = w = nfsacl_size(
+ (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
+ (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
while (w > 0) {
if (!rqstp->rq_respages[rqstp->rq_resused++])
return 0;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 277df40f098..e695660921e 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -990,15 +990,16 @@ encode_entry(struct readdir_cd *ccd, const char *name,
}
int
-nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
- int namlen, loff_t offset, ino_t ino, unsigned int d_type)
+nfs3svc_encode_entry(void *cd, const char *name,
+ int namlen, loff_t offset, u64 ino, unsigned int d_type)
{
return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
}
int
-nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
- int namlen, loff_t offset, ino_t ino, unsigned int d_type)
+nfs3svc_encode_entry_plus(void *cd, const char *name,
+ int namlen, loff_t offset, u64 ino,
+ unsigned int d_type)
{
return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 50bc94243ca..8522729830d 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -33,13 +33,6 @@
* 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.
- *
- * Note: some routines in this file are just trivial wrappers
- * (e.g. nfsd4_lookup()) defined solely for the sake of consistent
- * naming. Since all such routines have been declared "inline",
- * there shouldn't be any associated overhead. At some point in
- * the future, I might inline these "by hand" to clean up a
- * little.
*/
#include <linux/param.h>
@@ -161,8 +154,9 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
}
-static inline __be32
-nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner)
+static __be32
+nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_open *open)
{
__be32 status;
dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
@@ -179,11 +173,11 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
status = nfsd4_process_open1(open);
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;
- memcpy(&current_fh->fh_handle.fh_base, rp->rp_openfh,
+ fh_put(&cstate->current_fh);
+ cstate->current_fh.fh_handle.fh_size = rp->rp_openfh_len;
+ memcpy(&cstate->current_fh.fh_handle.fh_base, rp->rp_openfh,
rp->rp_openfh_len);
- status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
+ status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP);
if (status)
dprintk("nfsd4_open: replay failed"
" restoring previous filehandle\n");
@@ -215,7 +209,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
* (3) set open->op_truncate if the file is to be
* truncated after opening, (4) do permission checking.
*/
- status = do_open_lookup(rqstp, current_fh, open);
+ status = do_open_lookup(rqstp, &cstate->current_fh,
+ open);
if (status)
goto out;
break;
@@ -227,7 +222,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
* open->op_truncate if the file is to be truncated
* after opening, (3) do permission checking.
*/
- status = do_open_fhandle(rqstp, current_fh, open);
+ status = do_open_fhandle(rqstp, &cstate->current_fh,
+ open);
if (status)
goto out;
break;
@@ -248,11 +244,11 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
* successful, it (1) truncates the file if open->op_truncate was
* set, (2) sets open->op_stateid, (3) sets open->op_delegation.
*/
- status = nfsd4_process_open2(rqstp, current_fh, open);
+ status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
out:
if (open->op_stateowner) {
nfs4_get_stateowner(open->op_stateowner);
- *replay_owner = open->op_stateowner;
+ cstate->replay_owner = open->op_stateowner;
}
nfs4_unlock_state();
return status;
@@ -261,71 +257,80 @@ out:
/*
* filehandle-manipulating ops.
*/
-static inline __be32
-nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh)
+static __be32
+nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct svc_fh **getfh)
{
- if (!current_fh->fh_dentry)
+ if (!cstate->current_fh.fh_dentry)
return nfserr_nofilehandle;
- *getfh = current_fh;
+ *getfh = &cstate->current_fh;
return nfs_ok;
}
-static inline __be32
-nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putfh *putfh)
+static __be32
+nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_putfh *putfh)
{
- fh_put(current_fh);
- current_fh->fh_handle.fh_size = putfh->pf_fhlen;
- memcpy(&current_fh->fh_handle.fh_base, putfh->pf_fhval, putfh->pf_fhlen);
- return fh_verify(rqstp, current_fh, 0, MAY_NOP);
+ fh_put(&cstate->current_fh);
+ cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
+ memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
+ putfh->pf_fhlen);
+ return fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP);
}
-static inline __be32
-nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh)
+static __be32
+nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ void *arg)
{
__be32 status;
- fh_put(current_fh);
- status = exp_pseudoroot(rqstp->rq_client, current_fh,
+ fh_put(&cstate->current_fh);
+ status = exp_pseudoroot(rqstp->rq_client, &cstate->current_fh,
&rqstp->rq_chandle);
return status;
}
-static inline __be32
-nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
+static __be32
+nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ void *arg)
{
- if (!save_fh->fh_dentry)
+ if (!cstate->save_fh.fh_dentry)
return nfserr_restorefh;
- fh_dup2(current_fh, save_fh);
+ fh_dup2(&cstate->current_fh, &cstate->save_fh);
return nfs_ok;
}
-static inline __be32
-nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
+static __be32
+nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ void *arg)
{
- if (!current_fh->fh_dentry)
+ if (!cstate->current_fh.fh_dentry)
return nfserr_nofilehandle;
- fh_dup2(save_fh, current_fh);
+ fh_dup2(&cstate->save_fh, &cstate->current_fh);
return nfs_ok;
}
/*
* misc nfsv4 ops
*/
-static inline __be32
-nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_access *access)
+static __be32
+nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_access *access)
{
if (access->ac_req_access & ~NFS3_ACCESS_FULL)
return nfserr_inval;
access->ac_resp_access = access->ac_req_access;
- return nfsd_access(rqstp, current_fh, &access->ac_resp_access, &access->ac_supported);
+ return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access,
+ &access->ac_supported);
}
-static inline __be32
-nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit)
+static __be32
+nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_commit *commit)
{
__be32 status;
@@ -333,14 +338,16 @@ nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_com
*p++ = nfssvc_boot.tv_sec;
*p++ = nfssvc_boot.tv_usec;
- status = nfsd_commit(rqstp, current_fh, commit->co_offset, commit->co_count);
+ status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
+ commit->co_count);
if (status == nfserr_symlink)
status = nfserr_inval;
return status;
}
static __be32
-nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create)
+nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_create *create)
{
struct svc_fh resfh;
__be32 status;
@@ -348,7 +355,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre
fh_init(&resfh, NFS4_FHSIZE);
- status = fh_verify(rqstp, current_fh, S_IFDIR, MAY_CREATE);
+ status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, MAY_CREATE);
if (status == nfserr_symlink)
status = nfserr_notdir;
if (status)
@@ -365,9 +372,10 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre
*/
create->cr_linkname[create->cr_linklen] = 0;
- status = nfsd_symlink(rqstp, current_fh, create->cr_name,
- create->cr_namelen, create->cr_linkname,
- create->cr_linklen, &resfh, &create->cr_iattr);
+ status = nfsd_symlink(rqstp, &cstate->current_fh,
+ create->cr_name, create->cr_namelen,
+ create->cr_linkname, create->cr_linklen,
+ &resfh, &create->cr_iattr);
break;
case NF4BLK:
@@ -375,9 +383,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre
if (MAJOR(rdev) != create->cr_specdata1 ||
MINOR(rdev) != create->cr_specdata2)
return nfserr_inval;
- status = nfsd_create(rqstp, current_fh, create->cr_name,
- create->cr_namelen, &create->cr_iattr,
- S_IFBLK, rdev, &resfh);
+ status = nfsd_create(rqstp, &cstate->current_fh,
+ create->cr_name, create->cr_namelen,
+ &create->cr_iattr, S_IFBLK, rdev, &resfh);
break;
case NF4CHR:
@@ -385,28 +393,28 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre
if (MAJOR(rdev) != create->cr_specdata1 ||
MINOR(rdev) != create->cr_specdata2)
return nfserr_inval;
- status = nfsd_create(rqstp, current_fh, create->cr_name,
- create->cr_namelen, &create->cr_iattr,
- S_IFCHR, rdev, &resfh);
+ status = nfsd_create(rqstp, &cstate->current_fh,
+ create->cr_name, create->cr_namelen,
+ &create->cr_iattr,S_IFCHR, rdev, &resfh);
break;
case NF4SOCK:
- status = nfsd_create(rqstp, current_fh, create->cr_name,
- create->cr_namelen, &create->cr_iattr,
- S_IFSOCK, 0, &resfh);
+ status = nfsd_create(rqstp, &cstate->current_fh,
+ create->cr_name, create->cr_namelen,
+ &create->cr_iattr, S_IFSOCK, 0, &resfh);
break;
case NF4FIFO:
- status = nfsd_create(rqstp, current_fh, create->cr_name,
- create->cr_namelen, &create->cr_iattr,
- S_IFIFO, 0, &resfh);
+ status = nfsd_create(rqstp, &cstate->current_fh,
+ create->cr_name, create->cr_namelen,
+ &create->cr_iattr, S_IFIFO, 0, &resfh);
break;
case NF4DIR:
create->cr_iattr.ia_valid &= ~ATTR_SIZE;
- status = nfsd_create(rqstp, current_fh, create->cr_name,
- create->cr_namelen, &create->cr_iattr,
- S_IFDIR, 0, &resfh);
+ status = nfsd_create(rqstp, &cstate->current_fh,
+ create->cr_name, create->cr_namelen,
+ &create->cr_iattr, S_IFDIR, 0, &resfh);
break;
default:
@@ -414,21 +422,22 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre
}
if (!status) {
- fh_unlock(current_fh);
- set_change_info(&create->cr_cinfo, current_fh);
- fh_dup2(current_fh, &resfh);
+ fh_unlock(&cstate->current_fh);
+ set_change_info(&create->cr_cinfo, &cstate->current_fh);
+ fh_dup2(&cstate->current_fh, &resfh);
}
fh_put(&resfh);
return status;
}
-static inline __be32
-nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr)
+static __be32
+nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_getattr *getattr)
{
__be32 status;
- status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
+ status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP);
if (status)
return status;
@@ -438,26 +447,28 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ge
getattr->ga_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
getattr->ga_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;
- getattr->ga_fhp = current_fh;
+ getattr->ga_fhp = &cstate->current_fh;
return nfs_ok;
}
-static inline __be32
-nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh,
- struct svc_fh *save_fh, struct nfsd4_link *link)
+static __be32
+nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_link *link)
{
__be32 status = nfserr_nofilehandle;
- if (!save_fh->fh_dentry)
+ if (!cstate->save_fh.fh_dentry)
return status;
- status = nfsd_link(rqstp, current_fh, link->li_name, link->li_namelen, save_fh);
+ status = nfsd_link(rqstp, &cstate->current_fh,
+ link->li_name, link->li_namelen, &cstate->save_fh);
if (!status)
- set_change_info(&link->li_cinfo, current_fh);
+ set_change_info(&link->li_cinfo, &cstate->current_fh);
return status;
}
static __be32
-nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
+nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ void *arg)
{
struct svc_fh tmp_fh;
__be32 ret;
@@ -466,22 +477,27 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh,
&rqstp->rq_chandle)) != 0)
return ret;
- if (tmp_fh.fh_dentry == current_fh->fh_dentry) {
+ if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
fh_put(&tmp_fh);
return nfserr_noent;
}
fh_put(&tmp_fh);
- return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh);
+ return nfsd_lookup(rqstp, &cstate->current_fh,
+ "..", 2, &cstate->current_fh);
}
-static inline __be32
-nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lookup *lookup)
+static __be32
+nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_lookup *lookup)
{
- return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh);
+ return nfsd_lookup(rqstp, &cstate->current_fh,
+ lookup->lo_name, lookup->lo_len,
+ &cstate->current_fh);
}
-static inline __be32
-nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
+static __be32
+nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_read *read)
{
__be32 status;
@@ -493,7 +509,8 @@ nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read
nfs4_lock_state();
/* check stateid */
- if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid,
+ if ((status = nfs4_preprocess_stateid_op(&cstate->current_fh,
+ &read->rd_stateid,
CHECK_FH | RD_STATE, &read->rd_filp))) {
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
goto out;
@@ -504,12 +521,13 @@ nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read
out:
nfs4_unlock_state();
read->rd_rqstp = rqstp;
- read->rd_fhp = current_fh;
+ read->rd_fhp = &cstate->current_fh;
return status;
}
-static inline __be32
-nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir)
+static __be32
+nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_readdir *readdir)
{
u64 cookie = readdir->rd_cookie;
static const nfs4_verifier zeroverf;
@@ -527,48 +545,51 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_re
return nfserr_bad_cookie;
readdir->rd_rqstp = rqstp;
- readdir->rd_fhp = current_fh;
+ readdir->rd_fhp = &cstate->current_fh;
return nfs_ok;
}
-static inline __be32
-nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readlink *readlink)
+static __be32
+nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_readlink *readlink)
{
readlink->rl_rqstp = rqstp;
- readlink->rl_fhp = current_fh;
+ readlink->rl_fhp = &cstate->current_fh;
return nfs_ok;
}
-static inline __be32
-nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_remove *remove)
+static __be32
+nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_remove *remove)
{
__be32 status;
if (nfs4_in_grace())
return nfserr_grace;
- status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen);
+ status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
+ remove->rm_name, remove->rm_namelen);
if (status == nfserr_symlink)
return nfserr_notdir;
if (!status) {
- fh_unlock(current_fh);
- set_change_info(&remove->rm_cinfo, current_fh);
+ fh_unlock(&cstate->current_fh);
+ set_change_info(&remove->rm_cinfo, &cstate->current_fh);
}
return status;
}
-static inline __be32
-nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh,
- struct svc_fh *save_fh, struct nfsd4_rename *rename)
+static __be32
+nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_rename *rename)
{
__be32 status = nfserr_nofilehandle;
- if (!save_fh->fh_dentry)
+ if (!cstate->save_fh.fh_dentry)
return status;
- if (nfs4_in_grace() && !(save_fh->fh_export->ex_flags
+ if (nfs4_in_grace() && !(cstate->save_fh.fh_export->ex_flags
& NFSEXP_NOSUBTREECHECK))
return nfserr_grace;
- status = nfsd_rename(rqstp, save_fh, rename->rn_sname,
- rename->rn_snamelen, current_fh,
+ status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
+ rename->rn_snamelen, &cstate->current_fh,
rename->rn_tname, rename->rn_tnamelen);
/* the underlying filesystem returns different error's than required
@@ -576,27 +597,28 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh,
if (status == nfserr_isdir)
status = nfserr_exist;
else if ((status == nfserr_notdir) &&
- (S_ISDIR(save_fh->fh_dentry->d_inode->i_mode) &&
- S_ISDIR(current_fh->fh_dentry->d_inode->i_mode)))
+ (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) &&
+ S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode)))
status = nfserr_exist;
else if (status == nfserr_symlink)
status = nfserr_notdir;
if (!status) {
- set_change_info(&rename->rn_sinfo, current_fh);
- set_change_info(&rename->rn_tinfo, save_fh);
+ set_change_info(&rename->rn_sinfo, &cstate->current_fh);
+ set_change_info(&rename->rn_tinfo, &cstate->save_fh);
}
return status;
}
-static inline __be32
-nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr)
+static __be32
+nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_setattr *setattr)
{
__be32 status = nfs_ok;
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
nfs4_lock_state();
- status = nfs4_preprocess_stateid_op(current_fh,
+ status = nfs4_preprocess_stateid_op(&cstate->current_fh,
&setattr->sa_stateid, CHECK_FH | WR_STATE, NULL);
nfs4_unlock_state();
if (status) {
@@ -606,16 +628,18 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se
}
status = nfs_ok;
if (setattr->sa_acl != NULL)
- status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl);
+ status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
+ setattr->sa_acl);
if (status)
return status;
- status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr,
+ status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
0, (time_t)0);
return status;
}
-static inline __be32
-nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write)
+static __be32
+nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_write *write)
{
stateid_t *stateid = &write->wr_stateid;
struct file *filp = NULL;
@@ -628,7 +652,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
return nfserr_inval;
nfs4_lock_state();
- status = nfs4_preprocess_stateid_op(current_fh, stateid,
+ status = nfs4_preprocess_stateid_op(&cstate->current_fh, stateid,
CHECK_FH | WR_STATE, &filp);
if (filp)
get_file(filp);
@@ -645,9 +669,9 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
*p++ = nfssvc_boot.tv_sec;
*p++ = nfssvc_boot.tv_usec;
- status = nfsd_write(rqstp, current_fh, filp, write->wr_offset,
- rqstp->rq_vec, write->wr_vlen, write->wr_buflen,
- &write->wr_how_written);
+ status = nfsd_write(rqstp, &cstate->current_fh, filp,
+ write->wr_offset, rqstp->rq_vec, write->wr_vlen,
+ write->wr_buflen, &write->wr_how_written);
if (filp)
fput(filp);
@@ -662,13 +686,14 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
* to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK.
*/
static __be32
-nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify)
+_nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_verify *verify)
{
__be32 *buf, *p;
int count;
__be32 status;
- status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
+ status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP);
if (status)
return status;
@@ -689,8 +714,9 @@ nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ver
if (!buf)
return nfserr_resource;
- status = nfsd4_encode_fattr(current_fh, current_fh->fh_export,
- current_fh->fh_dentry, buf,
+ status = nfsd4_encode_fattr(&cstate->current_fh,
+ cstate->current_fh.fh_export,
+ cstate->current_fh.fh_dentry, buf,
&count, verify->ve_bmval,
rqstp);
@@ -712,6 +738,26 @@ out_kfree:
return status;
}
+static __be32
+nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_verify *verify)
+{
+ __be32 status;
+
+ status = _nfsd4_verify(rqstp, cstate, verify);
+ return status == nfserr_not_same ? nfs_ok : status;
+}
+
+static __be32
+nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_verify *verify)
+{
+ __be32 status;
+
+ status = _nfsd4_verify(rqstp, cstate, verify);
+ return status == nfserr_same ? nfs_ok : status;
+}
+
/*
* NULL call.
*/
@@ -727,6 +773,42 @@ static inline void nfsd4_increment_op_stats(u32 opnum)
nfsdstats.nfs4_opcount[opnum]++;
}
+static void cstate_free(struct nfsd4_compound_state *cstate)
+{
+ if (cstate == NULL)
+ return;
+ fh_put(&cstate->current_fh);
+ fh_put(&cstate->save_fh);
+ BUG_ON(cstate->replay_owner);
+ kfree(cstate);
+}
+
+static struct nfsd4_compound_state *cstate_alloc(void)
+{
+ struct nfsd4_compound_state *cstate;
+
+ cstate = kmalloc(sizeof(struct nfsd4_compound_state), GFP_KERNEL);
+ if (cstate == NULL)
+ return NULL;
+ fh_init(&cstate->current_fh, NFS4_FHSIZE);
+ fh_init(&cstate->save_fh, NFS4_FHSIZE);
+ cstate->replay_owner = NULL;
+ return cstate;
+}
+
+typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
+ void *);
+
+struct nfsd4_operation {
+ nfsd4op_func op_func;
+ u32 op_flags;
+/* Most ops require a valid current filehandle; a few don't: */
+#define ALLOWED_WITHOUT_FH 1
+/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */
+#define ALLOWED_ON_ABSENT_FS 2
+};
+
+static struct nfsd4_operation nfsd4_ops[];
/*
* COMPOUND call.
@@ -737,21 +819,15 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
struct nfsd4_compoundres *resp)
{
struct nfsd4_op *op;
- struct svc_fh *current_fh = NULL;
- struct svc_fh *save_fh = NULL;
- struct nfs4_stateowner *replay_owner = NULL;
- int slack_space; /* in words, not bytes! */
+ struct nfsd4_operation *opdesc;
+ struct nfsd4_compound_state *cstate = NULL;
+ int slack_bytes;
__be32 status;
status = nfserr_resource;
- current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL);
- if (current_fh == NULL)
- goto out;
- fh_init(current_fh, NFS4_FHSIZE);
- save_fh = kmalloc(sizeof(*save_fh), GFP_KERNEL);
- if (save_fh == NULL)
+ cstate = cstate_alloc();
+ if (cstate == NULL)
goto out;
- fh_init(save_fh, NFS4_FHSIZE);
resp->xbuf = &rqstp->rq_res;
resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len;
@@ -790,164 +866,44 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
* failed response to the next operation. If we don't
* have enough room, fail with ERR_RESOURCE.
*/
-/* FIXME - is slack_space *really* words, or bytes??? - neilb */
- slack_space = (char *)resp->end - (char *)resp->p;
- if (slack_space < COMPOUND_SLACK_SPACE + COMPOUND_ERR_SLACK_SPACE) {
- BUG_ON(slack_space < COMPOUND_ERR_SLACK_SPACE);
+ slack_bytes = (char *)resp->end - (char *)resp->p;
+ if (slack_bytes < COMPOUND_SLACK_SPACE
+ + COMPOUND_ERR_SLACK_SPACE) {
+ BUG_ON(slack_bytes < COMPOUND_ERR_SLACK_SPACE);
op->status = nfserr_resource;
goto encode_op;
}
- /* All operations except RENEW, SETCLIENTID, RESTOREFH
- * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH
- * require a valid current filehandle
- */
- 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))) {
+ opdesc = &nfsd4_ops[op->opnum];
+
+ if (!cstate->current_fh.fh_dentry) {
+ if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
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))) {
+ } else if (cstate->current_fh.fh_export->ex_fslocs.migrated &&
+ !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
op->status = nfserr_moved;
goto encode_op;
}
- switch (op->opnum) {
- case OP_ACCESS:
- op->status = nfsd4_access(rqstp, current_fh, &op->u.access);
- break;
- case OP_CLOSE:
- op->status = nfsd4_close(rqstp, current_fh, &op->u.close, &replay_owner);
- break;
- case OP_COMMIT:
- op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit);
- break;
- case OP_CREATE:
- op->status = nfsd4_create(rqstp, current_fh, &op->u.create);
- break;
- case OP_DELEGRETURN:
- op->status = nfsd4_delegreturn(rqstp, current_fh, &op->u.delegreturn);
- break;
- case OP_GETATTR:
- op->status = nfsd4_getattr(rqstp, current_fh, &op->u.getattr);
- break;
- case OP_GETFH:
- op->status = nfsd4_getfh(current_fh, &op->u.getfh);
- break;
- case OP_LINK:
- op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link);
- break;
- case OP_LOCK:
- op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock, &replay_owner);
- break;
- case OP_LOCKT:
- op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt);
- break;
- case OP_LOCKU:
- op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku, &replay_owner);
- break;
- case OP_LOOKUP:
- op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup);
- break;
- case OP_LOOKUPP:
- op->status = nfsd4_lookupp(rqstp, current_fh);
- break;
- case OP_NVERIFY:
- op->status = nfsd4_verify(rqstp, current_fh, &op->u.nverify);
- if (op->status == nfserr_not_same)
- op->status = nfs_ok;
- break;
- case OP_OPEN:
- op->status = nfsd4_open(rqstp, current_fh, &op->u.open, &replay_owner);
- break;
- case OP_OPEN_CONFIRM:
- op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm, &replay_owner);
- break;
- case OP_OPEN_DOWNGRADE:
- op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade, &replay_owner);
- break;
- case OP_PUTFH:
- op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh);
- break;
- case OP_PUTROOTFH:
- op->status = nfsd4_putrootfh(rqstp, current_fh);
- break;
- case OP_READ:
- op->status = nfsd4_read(rqstp, current_fh, &op->u.read);
- break;
- case OP_READDIR:
- op->status = nfsd4_readdir(rqstp, current_fh, &op->u.readdir);
- break;
- case OP_READLINK:
- op->status = nfsd4_readlink(rqstp, current_fh, &op->u.readlink);
- break;
- case OP_REMOVE:
- op->status = nfsd4_remove(rqstp, current_fh, &op->u.remove);
- break;
- case OP_RENAME:
- op->status = nfsd4_rename(rqstp, current_fh, save_fh, &op->u.rename);
- break;
- case OP_RENEW:
- op->status = nfsd4_renew(&op->u.renew);
- break;
- case OP_RESTOREFH:
- op->status = nfsd4_restorefh(current_fh, save_fh);
- break;
- case OP_SAVEFH:
- op->status = nfsd4_savefh(current_fh, save_fh);
- break;
- case OP_SETATTR:
- op->status = nfsd4_setattr(rqstp, current_fh, &op->u.setattr);
- break;
- case OP_SETCLIENTID:
- op->status = nfsd4_setclientid(rqstp, &op->u.setclientid);
- break;
- case OP_SETCLIENTID_CONFIRM:
- op->status = nfsd4_setclientid_confirm(rqstp, &op->u.setclientid_confirm);
- break;
- case OP_VERIFY:
- op->status = nfsd4_verify(rqstp, current_fh, &op->u.verify);
- if (op->status == nfserr_same)
- op->status = nfs_ok;
- break;
- case OP_WRITE:
- op->status = nfsd4_write(rqstp, current_fh, &op->u.write);
- break;
- case OP_RELEASE_LOCKOWNER:
- op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner);
- break;
- default:
+
+ if (opdesc->op_func)
+ op->status = opdesc->op_func(rqstp, cstate, &op->u);
+ else
BUG_ON(op->status == nfs_ok);
- break;
- }
encode_op:
if (op->status == nfserr_replay_me) {
- op->replay = &replay_owner->so_replay;
+ op->replay = &cstate->replay_owner->so_replay;
nfsd4_encode_replay(resp, op);
status = op->status = op->replay->rp_status;
} else {
nfsd4_encode_operation(resp, op);
status = op->status;
}
- if (replay_owner && (replay_owner != (void *)(-1))) {
- nfs4_put_stateowner(replay_owner);
- replay_owner = NULL;
+ if (cstate->replay_owner) {
+ nfs4_put_stateowner(cstate->replay_owner);
+ cstate->replay_owner = NULL;
}
/* XXX Ugh, we need to get rid of this kind of special case: */
if (op->opnum == OP_READ && op->u.read.rd_filp)
@@ -958,15 +914,124 @@ encode_op:
out:
nfsd4_release_compoundargs(args);
- if (current_fh)
- fh_put(current_fh);
- kfree(current_fh);
- if (save_fh)
- fh_put(save_fh);
- kfree(save_fh);
+ cstate_free(cstate);
return status;
}
+static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
+ [OP_ACCESS] = {
+ .op_func = (nfsd4op_func)nfsd4_access,
+ },
+ [OP_CLOSE] = {
+ .op_func = (nfsd4op_func)nfsd4_close,
+ },
+ [OP_COMMIT] = {
+ .op_func = (nfsd4op_func)nfsd4_commit,
+ },
+ [OP_CREATE] = {
+ .op_func = (nfsd4op_func)nfsd4_create,
+ },
+ [OP_DELEGRETURN] = {
+ .op_func = (nfsd4op_func)nfsd4_delegreturn,
+ },
+ [OP_GETATTR] = {
+ .op_func = (nfsd4op_func)nfsd4_getattr,
+ .op_flags = ALLOWED_ON_ABSENT_FS,
+ },
+ [OP_GETFH] = {
+ .op_func = (nfsd4op_func)nfsd4_getfh,
+ },
+ [OP_LINK] = {
+ .op_func = (nfsd4op_func)nfsd4_link,
+ },
+ [OP_LOCK] = {
+ .op_func = (nfsd4op_func)nfsd4_lock,
+ },
+ [OP_LOCKT] = {
+ .op_func = (nfsd4op_func)nfsd4_lockt,
+ },
+ [OP_LOCKU] = {
+ .op_func = (nfsd4op_func)nfsd4_locku,
+ },
+ [OP_LOOKUP] = {
+ .op_func = (nfsd4op_func)nfsd4_lookup,
+ },
+ [OP_LOOKUPP] = {
+ .op_func = (nfsd4op_func)nfsd4_lookupp,
+ },
+ [OP_NVERIFY] = {
+ .op_func = (nfsd4op_func)nfsd4_nverify,
+ },
+ [OP_OPEN] = {
+ .op_func = (nfsd4op_func)nfsd4_open,
+ },
+ [OP_OPEN_CONFIRM] = {
+ .op_func = (nfsd4op_func)nfsd4_open_confirm,
+ },
+ [OP_OPEN_DOWNGRADE] = {
+ .op_func = (nfsd4op_func)nfsd4_open_downgrade,
+ },
+ [OP_PUTFH] = {
+ .op_func = (nfsd4op_func)nfsd4_putfh,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ },
+ [OP_PUTPUBFH] = {
+ /* unsupported; just for future reference: */
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ },
+ [OP_PUTROOTFH] = {
+ .op_func = (nfsd4op_func)nfsd4_putrootfh,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ },
+ [OP_READ] = {
+ .op_func = (nfsd4op_func)nfsd4_read,
+ },
+ [OP_READDIR] = {
+ .op_func = (nfsd4op_func)nfsd4_readdir,
+ },
+ [OP_READLINK] = {
+ .op_func = (nfsd4op_func)nfsd4_readlink,
+ },
+ [OP_REMOVE] = {
+ .op_func = (nfsd4op_func)nfsd4_remove,
+ },
+ [OP_RENAME] = {
+ .op_func = (nfsd4op_func)nfsd4_rename,
+ },
+ [OP_RENEW] = {
+ .op_func = (nfsd4op_func)nfsd4_renew,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ },
+ [OP_RESTOREFH] = {
+ .op_func = (nfsd4op_func)nfsd4_restorefh,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ },
+ [OP_SAVEFH] = {
+ .op_func = (nfsd4op_func)nfsd4_savefh,
+ },
+ [OP_SETATTR] = {
+ .op_func = (nfsd4op_func)nfsd4_setattr,
+ },
+ [OP_SETCLIENTID] = {
+ .op_func = (nfsd4op_func)nfsd4_setclientid,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ },
+ [OP_SETCLIENTID_CONFIRM] = {
+ .op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ },
+ [OP_VERIFY] = {
+ .op_func = (nfsd4op_func)nfsd4_verify,
+ },
+ [OP_WRITE] = {
+ .op_func = (nfsd4op_func)nfsd4_write,
+ },
+ [OP_RELEASE_LOCKOWNER] = {
+ .op_func = (nfsd4op_func)nfsd4_release_lockowner,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ },
+};
+
#define nfs4svc_decode_voidargs NULL
#define nfs4svc_release_void NULL
#define nfsd4_voidres nfsd4_voidargs
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 81b8565d383..c7774e3a946 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -259,7 +259,7 @@ nfsd4_remove_clid_file(struct dentry *dir, struct dentry *dentry)
printk("nfsd4: non-file found in client recovery directory\n");
return -EINVAL;
}
- mutex_lock(&dir->d_inode->i_mutex);
+ mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
status = vfs_unlink(dir->d_inode, dentry);
mutex_unlock(&dir->d_inode->i_mutex);
return status;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 640c92b2a9f..9de89df961f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -711,7 +711,8 @@ out_err:
*
*/
__be32
-nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
+nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_setclientid *setclid)
{
__be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
struct xdr_netobj clname = {
@@ -876,7 +877,9 @@ out:
* NOTE: callback information will be processed here in a future patch
*/
__be32
-nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
+nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *cstate,
+ struct nfsd4_setclientid_confirm *setclientid_confirm)
{
__be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
struct nfs4_client *conf, *unconf;
@@ -1310,7 +1313,7 @@ static inline void
nfs4_file_downgrade(struct file *filp, unsigned int share_access)
{
if (share_access & NFS4_SHARE_ACCESS_WRITE) {
- put_write_access(filp->f_dentry->d_inode);
+ put_write_access(filp->f_path.dentry->d_inode);
filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE;
}
}
@@ -1623,7 +1626,7 @@ 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;
+ struct inode *inode = filp->f_path.dentry->d_inode;
unsigned int share_access, new_writer;
__be32 status;
@@ -1833,7 +1836,8 @@ static void laundromat_main(struct work_struct *);
static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
__be32
-nfsd4_renew(clientid_t *clid)
+nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ clientid_t *clid)
{
struct nfs4_client *clp;
__be32 status;
@@ -1965,7 +1969,7 @@ search_close_lru(u32 st_id, int flags)
static inline int
nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
{
- return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_dentry->d_inode;
+ return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode;
}
static int
@@ -2241,24 +2245,25 @@ check_replay:
}
__be32
-nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner)
+nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_open_confirm *oc)
{
__be32 status;
struct nfs4_stateowner *sop;
struct nfs4_stateid *stp;
dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
- (int)current_fh->fh_dentry->d_name.len,
- current_fh->fh_dentry->d_name.name);
+ (int)cstate->current_fh.fh_dentry->d_name.len,
+ cstate->current_fh.fh_dentry->d_name.name);
- status = fh_verify(rqstp, current_fh, S_IFREG, 0);
+ status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
if (status)
return status;
nfs4_lock_state();
- if ((status = nfs4_preprocess_seqid_op(current_fh, oc->oc_seqid,
- &oc->oc_req_stateid,
+ if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
+ oc->oc_seqid, &oc->oc_req_stateid,
CHECK_FH | CONFIRM | OPEN_STATE,
&oc->oc_stateowner, &stp, NULL)))
goto out;
@@ -2278,7 +2283,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
out:
if (oc->oc_stateowner) {
nfs4_get_stateowner(oc->oc_stateowner);
- *replay_owner = oc->oc_stateowner;
+ cstate->replay_owner = oc->oc_stateowner;
}
nfs4_unlock_state();
return status;
@@ -2310,22 +2315,25 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap)
}
__be32
-nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner)
+nfsd4_open_downgrade(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *cstate,
+ struct nfsd4_open_downgrade *od)
{
__be32 status;
struct nfs4_stateid *stp;
unsigned int share_access;
dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n",
- (int)current_fh->fh_dentry->d_name.len,
- current_fh->fh_dentry->d_name.name);
+ (int)cstate->current_fh.fh_dentry->d_name.len,
+ cstate->current_fh.fh_dentry->d_name.name);
if (!access_valid(od->od_share_access)
|| !deny_valid(od->od_share_deny))
return nfserr_inval;
nfs4_lock_state();
- if ((status = nfs4_preprocess_seqid_op(current_fh, od->od_seqid,
+ if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
+ od->od_seqid,
&od->od_stateid,
CHECK_FH | OPEN_STATE,
&od->od_stateowner, &stp, NULL)))
@@ -2355,7 +2363,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n
out:
if (od->od_stateowner) {
nfs4_get_stateowner(od->od_stateowner);
- *replay_owner = od->od_stateowner;
+ cstate->replay_owner = od->od_stateowner;
}
nfs4_unlock_state();
return status;
@@ -2365,18 +2373,20 @@ out:
* nfs4_unlock_state() called after encode
*/
__be32
-nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner)
+nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_close *close)
{
__be32 status;
struct nfs4_stateid *stp;
dprintk("NFSD: nfsd4_close on file %.*s\n",
- (int)current_fh->fh_dentry->d_name.len,
- current_fh->fh_dentry->d_name.name);
+ (int)cstate->current_fh.fh_dentry->d_name.len,
+ cstate->current_fh.fh_dentry->d_name.name);
nfs4_lock_state();
/* check close_lru for replay */
- if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid,
+ if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
+ close->cl_seqid,
&close->cl_stateid,
CHECK_FH | OPEN_STATE | CLOSE_STATE,
&close->cl_stateowner, &stp, NULL)))
@@ -2397,22 +2407,24 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos
out:
if (close->cl_stateowner) {
nfs4_get_stateowner(close->cl_stateowner);
- *replay_owner = close->cl_stateowner;
+ cstate->replay_owner = close->cl_stateowner;
}
nfs4_unlock_state();
return status;
}
__be32
-nfsd4_delegreturn(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_delegreturn *dr)
+nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_delegreturn *dr)
{
__be32 status;
- if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0)))
+ if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
goto out;
nfs4_lock_state();
- status = nfs4_preprocess_stateid_op(current_fh, &dr->dr_stateid, DELEG_RET, NULL);
+ status = nfs4_preprocess_stateid_op(&cstate->current_fh,
+ &dr->dr_stateid, DELEG_RET, NULL);
nfs4_unlock_state();
out:
return status;
@@ -2635,7 +2647,8 @@ check_lock_length(u64 offset, u64 length)
* LOCK operation
*/
__be32
-nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner)
+nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_lock *lock)
{
struct nfs4_stateowner *open_sop = NULL;
struct nfs4_stateowner *lock_sop = NULL;
@@ -2654,7 +2667,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
if (check_lock_length(lock->lk_offset, lock->lk_length))
return nfserr_inval;
- if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) {
+ if ((status = fh_verify(rqstp, &cstate->current_fh,
+ S_IFREG, MAY_LOCK))) {
dprintk("NFSD: nfsd4_lock: permission denied!\n");
return status;
}
@@ -2675,7 +2689,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
goto out;
/* validate and update open stateid and open seqid */
- status = nfs4_preprocess_seqid_op(current_fh,
+ status = nfs4_preprocess_seqid_op(&cstate->current_fh,
lock->lk_new_open_seqid,
&lock->lk_new_open_stateid,
CHECK_FH | OPEN_STATE,
@@ -2702,7 +2716,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
goto out;
} else {
/* lock (lock owner + lock stateid) already exists */
- status = nfs4_preprocess_seqid_op(current_fh,
+ status = nfs4_preprocess_seqid_op(&cstate->current_fh,
lock->lk_old_lock_seqid,
&lock->lk_old_lock_stateid,
CHECK_FH | LOCK_STATE,
@@ -2759,7 +2773,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
conflock.fl_ops = NULL;
conflock.fl_lmops = NULL;
err = posix_lock_file_conf(filp, &file_lock, &conflock);
- dprintk("NFSD: nfsd4_lock: posix_lock_file_conf status %d\n",status);
switch (-err) {
case 0: /* success! */
update_stateid(&lock_stp->st_stateid);
@@ -2785,7 +2798,7 @@ out:
release_stateowner(lock_sop);
if (lock->lk_replay_owner) {
nfs4_get_stateowner(lock->lk_replay_owner);
- *replay_owner = lock->lk_replay_owner;
+ cstate->replay_owner = lock->lk_replay_owner;
}
nfs4_unlock_state();
return status;
@@ -2795,7 +2808,8 @@ out:
* LOCKT operation
*/
__be32
-nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt)
+nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_lockt *lockt)
{
struct inode *inode;
struct file file;
@@ -2816,14 +2830,14 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
if (STALE_CLIENTID(&lockt->lt_clientid))
goto out;
- if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) {
+ if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) {
dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n");
if (status == nfserr_symlink)
status = nfserr_inval;
goto out;
}
- inode = current_fh->fh_dentry->d_inode;
+ inode = cstate->current_fh.fh_dentry->d_inode;
locks_init_lock(&file_lock);
switch (lockt->lt_type) {
case NFS4_READ_LT:
@@ -2862,7 +2876,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
* only the dentry:inode set.
*/
memset(&file, 0, sizeof (struct file));
- file.f_dentry = current_fh->fh_dentry;
+ file.f_path.dentry = cstate->current_fh.fh_dentry;
status = nfs_ok;
if (posix_test_lock(&file, &file_lock, &conflock)) {
@@ -2875,7 +2889,8 @@ out:
}
__be32
-nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner)
+nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_locku *locku)
{
struct nfs4_stateid *stp;
struct file *filp = NULL;
@@ -2892,7 +2907,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
nfs4_lock_state();
- if ((status = nfs4_preprocess_seqid_op(current_fh,
+ if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
locku->lu_seqid,
&locku->lu_stateid,
CHECK_FH | LOCK_STATE,
@@ -2933,7 +2948,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
out:
if (locku->lu_stateowner) {
nfs4_get_stateowner(locku->lu_stateowner);
- *replay_owner = locku->lu_stateowner;
+ cstate->replay_owner = locku->lu_stateowner;
}
nfs4_unlock_state();
return status;
@@ -2952,7 +2967,7 @@ static int
check_for_locks(struct file *filp, struct nfs4_stateowner *lowner)
{
struct file_lock **flpp;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int status = 0;
lock_kernel();
@@ -2968,7 +2983,9 @@ out:
}
__be32
-nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
+nfsd4_release_lockowner(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *cstate,
+ struct nfsd4_release_lockowner *rlockowner)
{
clientid_t *clid = &rlockowner->rl_clientid;
struct nfs4_stateowner *sop;
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index f3f239db04b..18aa9440df1 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1845,15 +1845,11 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
exp_get(exp);
if (d_mountpoint(dentry)) {
- if (nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp)) {
- /*
- * -EAGAIN is the only error returned from
- * nfsd_cross_mnt() and it indicates that an
- * up-call has been initiated to fill in the export
- * options on exp. When the answer comes back,
- * this call will be retried.
- */
- nfserr = nfserr_dropit;
+ int err;
+
+ err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
+ if (err) {
+ nfserr = nfserrno(err);
goto out_put;
}
@@ -1884,9 +1880,10 @@ nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr)
}
static int
-nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
- loff_t offset, ino_t ino, unsigned int d_type)
+nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
+ loff_t offset, u64 ino, unsigned int d_type)
{
+ struct readdir_cd *ccd = ccdv;
struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
int buflen;
__be32 *p = cd->buffer;
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 6100bbe2743..f90d7047585 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -66,14 +66,13 @@ nfsd_cache_init(void)
printk (KERN_ERR "nfsd: cannot allocate all %d cache entries, only got %d\n",
CACHESIZE, CACHESIZE-i);
- hash_list = kmalloc (HASHSIZE * sizeof(struct hlist_head), GFP_KERNEL);
+ hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL);
if (!hash_list) {
nfsd_cache_shutdown();
printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n",
HASHSIZE * sizeof(struct hlist_head));
return;
}
- memset(hash_list, 0, HASHSIZE * sizeof(struct hlist_head));
cache_disabled = 0;
}
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 39aed901514..eedf2e3990a 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -111,7 +111,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
{
- ino_t ino = file->f_dentry->d_inode->i_ino;
+ ino_t ino = file->f_path.dentry->d_inode->i_ino;
char *data;
ssize_t rv;
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 727ab3bd450..c59d6fbb7a6 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -24,8 +24,6 @@
#include <linux/nfsd/nfsd.h>
#define NFSDDBG_FACILITY NFSDDBG_FH
-#define NFSD_PARANOIA 1
-/* #define NFSD_DEBUG_VERBOSE 1 */
static int nfsd_nr_verified;
@@ -169,9 +167,11 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle);
}
- error = nfserr_dropit;
- if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN)
+ if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN
+ || PTR_ERR(exp) == -ETIMEDOUT)) {
+ error = nfserrno(PTR_ERR(exp));
goto out;
+ }
error = nfserr_stale;
if (!exp || IS_ERR(exp))
@@ -228,13 +228,12 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
error = nfserrno(PTR_ERR(dentry));
goto out;
}
-#ifdef NFSD_PARANOIA
+
if (S_ISDIR(dentry->d_inode->i_mode) &&
(dentry->d_flags & DCACHE_DISCONNECTED)) {
printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
}
-#endif
fhp->fh_dentry = dentry;
fhp->fh_export = exp;
@@ -265,12 +264,13 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
/* Finally, check access permissions. */
error = nfsd_permission(exp, dentry, access);
-#ifdef NFSD_PARANOIA_EXTREME
if (error) {
- printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
- dentry->d_parent->d_name.name, dentry->d_name.name, access, (error >> 24));
+ dprintk("fh_verify: %s/%s permission failure, "
+ "acc=%x, error=%d\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name,
+ access, ntohl(error));
}
-#endif
out:
if (exp && !IS_ERR(exp))
exp_put(exp);
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 0aaccb03bf7..fbf5d51947e 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -72,7 +72,7 @@ static struct svc_program nfsd_acl_program = {
.pg_prog = NFS_ACL_PROGRAM,
.pg_nvers = NFSD_ACL_NRVERS,
.pg_vers = nfsd_acl_versions,
- .pg_name = "nfsd",
+ .pg_name = "nfsacl",
.pg_class = "nfsd",
.pg_stats = &nfsd_acl_svcstats,
.pg_authenticate = &svc_set_client,
@@ -118,16 +118,16 @@ int nfsd_vers(int vers, enum vers_op change)
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];
+ nfsd_acl_versions[vers] = nfsd_acl_version[vers];
#endif
+ break;
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;
+ nfsd_acl_versions[vers] = NULL;
#endif
break;
case NFSD_TEST:
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index f5243f94399..6555c50d900 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -462,9 +462,10 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p,
}
int
-nfssvc_encode_entry(struct readdir_cd *ccd, const char *name,
- int namlen, loff_t offset, ino_t ino, unsigned int d_type)
+nfssvc_encode_entry(void *ccdv, const char *name,
+ int namlen, loff_t offset, u64 ino, unsigned int d_type)
{
+ struct readdir_cd *ccd = ccdv;
struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common);
__be32 *p = cd->buffer;
int buflen, slen;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index bb4d926e448..8283236c6a0 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -59,7 +59,6 @@
#include <asm/uaccess.h>
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
-#define NFSD_PARANOIA
/* We must ignore files (but only files) which might have mandatory
@@ -99,7 +98,7 @@ static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE];
/*
* Called from nfsd_lookup and encode_dirent. Check if we have crossed
* a mount point.
- * Returns -EAGAIN leaving *dpp and *expp unchanged,
+ * Returns -EAGAIN or -ETIMEDOUT leaving *dpp and *expp unchanged,
* or nfs_ok having possibly changed *dpp and *expp
*/
int
@@ -736,10 +735,10 @@ static int
nfsd_sync(struct file *filp)
{
int err;
- struct inode *inode = filp->f_dentry->d_inode;
- dprintk("nfsd: sync file %s\n", filp->f_dentry->d_name.name);
+ struct inode *inode = filp->f_path.dentry->d_inode;
+ dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name);
mutex_lock(&inode->i_mutex);
- err=nfsd_dosync(filp, filp->f_dentry, filp->f_op);
+ err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op);
mutex_unlock(&inode->i_mutex);
return err;
@@ -822,7 +821,8 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset
rqstp->rq_res.page_len = size;
} else if (page != pp[-1]) {
get_page(page);
- put_page(*pp);
+ if (*pp)
+ put_page(*pp);
*pp = page;
rqstp->rq_resused++;
rqstp->rq_res.page_len += size;
@@ -845,7 +845,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
int host_err;
err = nfserr_perm;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
#ifdef MSNFS
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
(!lock_may_read(inode, offset, *count)))
@@ -883,7 +883,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
nfsdstats.io_read += host_err;
*count = host_err;
err = 0;
- fsnotify_access(file->f_dentry);
+ fsnotify_access(file->f_path.dentry);
} else
err = nfserrno(host_err);
out:
@@ -917,11 +917,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
err = nfserr_perm;
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
- (!lock_may_write(file->f_dentry->d_inode, offset, cnt)))
+ (!lock_may_write(file->f_path.dentry->d_inode, offset, cnt)))
goto out;
#endif
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
inode = dentry->d_inode;
exp = fhp->fh_export;
@@ -950,7 +950,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
set_fs(oldfs);
if (host_err >= 0) {
nfsdstats.io_write += cnt;
- fsnotify_modify(file->f_dentry);
+ fsnotify_modify(file->f_path.dentry);
}
/* clear setuid/setgid flag after write */
@@ -1244,7 +1244,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
__be32 err;
int host_err;
__u32 v_mtime=0, v_atime=0;
- int v_mode=0;
err = nfserr_perm;
if (!flen)
@@ -1281,16 +1280,11 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
goto out;
if (createmode == NFS3_CREATE_EXCLUSIVE) {
- /* while the verifier would fit in mtime+atime,
- * solaris7 gets confused (bugid 4218508) if these have
- * the high bit set, so we use the mode as well
+ /* solaris7 gets confused (bugid 4218508) if these have
+ * the high bit set, so just clear the high bits.
*/
v_mtime = verifier[0]&0x7fffffff;
v_atime = verifier[1]&0x7fffffff;
- v_mode = S_IFREG
- | ((verifier[0]&0x80000000) >> (32-7)) /* u+x */
- | ((verifier[1]&0x80000000) >> (32-9)) /* u+r */
- ;
}
if (dchild->d_inode) {
@@ -1318,7 +1312,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
case NFS3_CREATE_EXCLUSIVE:
if ( dchild->d_inode->i_mtime.tv_sec == v_mtime
&& dchild->d_inode->i_atime.tv_sec == v_atime
- && dchild->d_inode->i_mode == v_mode
&& dchild->d_inode->i_size == 0 )
break;
/* fallthru */
@@ -1340,26 +1333,22 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
}
if (createmode == NFS3_CREATE_EXCLUSIVE) {
- /* Cram the verifier into atime/mtime/mode */
+ /* Cram the verifier into atime/mtime */
iap->ia_valid = ATTR_MTIME|ATTR_ATIME
- | ATTR_MTIME_SET|ATTR_ATIME_SET
- | ATTR_MODE;
+ | ATTR_MTIME_SET|ATTR_ATIME_SET;
/* XXX someone who knows this better please fix it for nsec */
iap->ia_mtime.tv_sec = v_mtime;
iap->ia_atime.tv_sec = v_atime;
iap->ia_mtime.tv_nsec = 0;
iap->ia_atime.tv_nsec = 0;
- iap->ia_mode = v_mode;
}
/* Set file attributes.
- * Mode has already been set but we might need to reset it
- * for CREATE_EXCLUSIVE
* Irix appears to send along the gid when it tries to
* implement setgid directories via NFS. Clear out all that cruft.
*/
set_attr:
- if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) {
+ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
__be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
if (err2)
err = err2;
@@ -1726,7 +1715,7 @@ out:
*/
__be32
nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
- struct readdir_cd *cdp, encode_dent_fn func)
+ struct readdir_cd *cdp, filldir_t func)
{
__be32 err;
int host_err;
@@ -1751,7 +1740,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
do {
cdp->err = nfserr_eof; /* will be cleared on successful read */
- host_err = vfs_readdir(file, (filldir_t) func, cdp);
+ host_err = vfs_readdir(file, func, cdp);
} while (host_err >=0 && cdp->err == nfs_ok);
if (host_err)
err = nfserrno(host_err);
@@ -1885,28 +1874,27 @@ nfsd_racache_init(int cache_size)
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++) {
- if (i % nperbucket == 0)
- raparm_hash[j++].pb_head = raparml + i;
- if (i % nperbucket < nperbucket-1)
- raparml[i].p_next = raparml + i + 1;
- }
- } else {
+ raparml = kcalloc(cache_size, sizeof(struct raparms), GFP_KERNEL);
+
+ if (!raparml) {
printk(KERN_WARNING
- "nfsd: Could not allocate memory read-ahead cache.\n");
+ "nfsd: Could not allocate memory read-ahead cache.\n");
return -ENOMEM;
}
+
+ 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;
+ for (i = 0; i < cache_size - 1; i++) {
+ if (i % nperbucket == 0)
+ raparm_hash[j++].pb_head = raparml + i;
+ if (i % nperbucket < nperbucket-1)
+ raparml[i].p_next = raparml + i + 1;
+ }
+
nfsdstats.ra_size = cache_size;
return 0;
}
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
index 35cc4b1d60f..af4ef808fa9 100644
--- a/fs/ntfs/ChangeLog
+++ b/fs/ntfs/ChangeLog
@@ -17,6 +17,13 @@ ToDo/Notes:
happen is unclear however so it is worth waiting until someone hits
the problem.
+2.1.28 - Fix a deadlock.
+
+ - Fix deadlock in fs/ntfs/inode.c::ntfs_put_inode(). Thanks to Sergey
+ Vlasov for the report and detailed analysis of the deadlock. The fix
+ involved getting rid of ntfs_put_inode() altogether and hence NTFS no
+ longer has a ->put_inode super operation.
+
2.1.27 - Various bug fixes and cleanups.
- Fix two compiler warnings on Alpha. Thanks to Andrew Morton for
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
index e27b4eacffb..82550838556 100644
--- a/fs/ntfs/Makefile
+++ b/fs/ntfs/Makefile
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
unistr.o upcase.o
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.27\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.28\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index 7b2c8f4f6a6..629e7abdd84 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -92,10 +92,12 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
ofs = 0;
if (file_ofs < init_size)
ofs = init_size - file_ofs;
+ local_irq_save(flags);
kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ);
memset(kaddr + bh_offset(bh) + ofs, 0,
bh->b_size - ofs);
kunmap_atomic(kaddr, KM_BIO_SRC_IRQ);
+ local_irq_restore(flags);
flush_dcache_page(page);
}
} else {
@@ -143,11 +145,13 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
recs = PAGE_CACHE_SIZE / rec_size;
/* Should have been verified before we got here... */
BUG_ON(!recs);
+ local_irq_save(flags);
kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ);
for (i = 0; i < recs; i++)
post_read_mst_fixup((NTFS_RECORD*)(kaddr +
i * rec_size), rec_size);
kunmap_atomic(kaddr, KM_BIO_SRC_IRQ);
+ local_irq_restore(flags);
flush_dcache_page(page);
if (likely(page_uptodate && !PageError(page)))
SetPageUptodate(page);
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
index 85c36b8ca45..74f99a6a369 100644
--- a/fs/ntfs/dir.c
+++ b/fs/ntfs/dir.c
@@ -1,7 +1,7 @@
/**
* dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
*
- * Copyright (c) 2001-2005 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
@@ -1101,7 +1101,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
s64 ia_pos, ia_start, prev_ia_pos, bmp_pos;
loff_t fpos, i_size;
- struct inode *bmp_vi, *vdir = filp->f_dentry->d_inode;
+ struct inode *bmp_vi, *vdir = filp->f_path.dentry->d_inode;
struct super_block *sb = vdir->i_sb;
ntfs_inode *ndir = NTFS_I(vdir);
ntfs_volume *vol = NTFS_SB(sb);
@@ -1136,9 +1136,9 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (fpos == 1) {
ntfs_debug("Calling filldir for .. with len 2, fpos 0x1, "
"inode 0x%lx, DT_DIR.",
- (unsigned long)parent_ino(filp->f_dentry));
+ (unsigned long)parent_ino(filp->f_path.dentry));
rc = filldir(dirent, "..", 2, fpos,
- parent_ino(filp->f_dentry), DT_DIR);
+ parent_ino(filp->f_path.dentry), DT_DIR);
if (rc)
goto done;
fpos++;
@@ -1249,16 +1249,12 @@ skip_index_root:
/* Get the offset into the index allocation attribute. */
ia_pos = (s64)fpos - vol->mft_record_size;
ia_mapping = vdir->i_mapping;
- bmp_vi = ndir->itype.index.bmp_ino;
- if (unlikely(!bmp_vi)) {
- ntfs_debug("Inode 0x%lx, regetting index bitmap.", vdir->i_ino);
- bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4);
- if (IS_ERR(bmp_vi)) {
- ntfs_error(sb, "Failed to get bitmap attribute.");
- err = PTR_ERR(bmp_vi);
- goto err_out;
- }
- ndir->itype.index.bmp_ino = bmp_vi;
+ ntfs_debug("Inode 0x%lx, getting index bitmap.", vdir->i_ino);
+ bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4);
+ if (IS_ERR(bmp_vi)) {
+ ntfs_error(sb, "Failed to get bitmap attribute.");
+ err = PTR_ERR(bmp_vi);
+ goto err_out;
}
bmp_mapping = bmp_vi->i_mapping;
/* Get the starting bitmap bit position and sanity check it. */
@@ -1266,7 +1262,7 @@ skip_index_root:
if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) {
ntfs_error(sb, "Current index allocation position exceeds "
"index bitmap size.");
- goto err_out;
+ goto iput_err_out;
}
/* Get the starting bit position in the current bitmap page. */
cur_bmp_pos = bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1);
@@ -1282,7 +1278,7 @@ get_next_bmp_page:
ntfs_error(sb, "Reading index bitmap failed.");
err = PTR_ERR(bmp_page);
bmp_page = NULL;
- goto err_out;
+ goto iput_err_out;
}
bmp = (u8*)page_address(bmp_page);
/* Find next index block in use. */
@@ -1429,6 +1425,7 @@ find_next_index_buffer:
/* @ia_page is already unlocked in this case. */
ntfs_unmap_page(ia_page);
ntfs_unmap_page(bmp_page);
+ iput(bmp_vi);
goto abort;
}
}
@@ -1439,6 +1436,7 @@ unm_EOD:
ntfs_unmap_page(ia_page);
}
ntfs_unmap_page(bmp_page);
+ iput(bmp_vi);
EOD:
/* We are finished, set fpos to EOD. */
fpos = i_size + vol->mft_record_size;
@@ -1455,8 +1453,11 @@ done:
filp->f_pos = fpos;
return 0;
err_out:
- if (bmp_page)
+ if (bmp_page) {
ntfs_unmap_page(bmp_page);
+iput_err_out:
+ iput(bmp_vi);
+ }
if (ia_page) {
unlock_page(ia_page);
ntfs_unmap_page(ia_page);
@@ -1529,14 +1530,22 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp)
static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry,
int datasync)
{
- struct inode *vi = dentry->d_inode;
- ntfs_inode *ni = NTFS_I(vi);
+ struct inode *bmp_vi, *vi = dentry->d_inode;
int err, ret;
+ ntfs_attr na;
ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
BUG_ON(!S_ISDIR(vi->i_mode));
- if (NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino)
- write_inode_now(ni->itype.index.bmp_ino, !datasync);
+ /* If the bitmap attribute inode is in memory sync it, too. */
+ na.mft_no = vi->i_ino;
+ na.type = AT_BITMAP;
+ na.name = I30;
+ na.name_len = 4;
+ bmp_vi = ilookup5(vi->i_sb, vi->i_ino, (test_t)ntfs_test_inode, &na);
+ if (bmp_vi) {
+ write_inode_now(bmp_vi, !datasync);
+ iput(bmp_vi);
+ }
ret = ntfs_write_inode(vi, 1);
write_inode_now(vi, !datasync);
err = sync_blockdev(vi->i_sb->s_bdev);
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index ae2fe0016d2..076c9420c25 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -2162,7 +2162,7 @@ static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb,
goto out;
if (!count)
goto out;
- err = remove_suid(file->f_dentry);
+ err = remove_suid(file->f_path.dentry);
if (err)
goto out;
file_update_time(file);
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 247989891b4..f8bf8da67ee 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1,7 +1,7 @@
/**
* inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project.
*
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@@ -95,7 +95,7 @@ int ntfs_test_inode(struct inode *vi, ntfs_attr *na)
* If initializing the normal file/directory inode, set @na->type to AT_UNUSED.
* In that case, @na->name and @na->name_len should be set to NULL and 0,
* respectively. Although that is not strictly necessary as
- * ntfs_read_inode_locked() will fill them in later.
+ * ntfs_read_locked_inode() will fill them in later.
*
* Return 0 on success and -errno on error.
*
@@ -171,8 +171,8 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi,
struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no)
{
struct inode *vi;
- ntfs_attr na;
int err;
+ ntfs_attr na;
na.mft_no = mft_no;
na.type = AT_UNUSED;
@@ -229,8 +229,8 @@ struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPE type,
ntfschar *name, u32 name_len)
{
struct inode *vi;
- ntfs_attr na;
int err;
+ ntfs_attr na;
/* Make sure no one calls ntfs_attr_iget() for indices. */
BUG_ON(type == AT_INDEX_ALLOCATION);
@@ -287,8 +287,8 @@ struct inode *ntfs_index_iget(struct inode *base_vi, ntfschar *name,
u32 name_len)
{
struct inode *vi;
- ntfs_attr na;
int err;
+ ntfs_attr na;
na.mft_no = base_vi->i_ino;
na.type = AT_INDEX_ALLOCATION;
@@ -402,7 +402,6 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
ntfs_init_runlist(&ni->attr_list_rl);
lockdep_set_class(&ni->attr_list_rl.lock,
&attr_list_rl_lock_class);
- ni->itype.index.bmp_ino = NULL;
ni->itype.index.block_size = 0;
ni->itype.index.vcn_size = 0;
ni->itype.index.collation_rule = 0;
@@ -546,6 +545,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
{
ntfs_volume *vol = NTFS_SB(vi->i_sb);
ntfs_inode *ni;
+ struct inode *bvi;
MFT_RECORD *m;
ATTR_RECORD *a;
STANDARD_INFORMATION *si;
@@ -780,7 +780,6 @@ skip_attr_list_load:
*/
if (S_ISDIR(vi->i_mode)) {
loff_t bvi_size;
- struct inode *bvi;
ntfs_inode *bni;
INDEX_ROOT *ir;
u8 *ir_end, *index_end;
@@ -985,13 +984,12 @@ skip_attr_list_load:
err = PTR_ERR(bvi);
goto unm_err_out;
}
- ni->itype.index.bmp_ino = bvi;
bni = NTFS_I(bvi);
if (NInoCompressed(bni) || NInoEncrypted(bni) ||
NInoSparse(bni)) {
ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
"and/or encrypted and/or sparse.");
- goto unm_err_out;
+ goto iput_unm_err_out;
}
/* Consistency check bitmap size vs. index allocation size. */
bvi_size = i_size_read(bvi);
@@ -1000,8 +998,10 @@ skip_attr_list_load:
ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) "
"for index allocation (0x%llx).",
bvi_size << 3, vi->i_size);
- goto unm_err_out;
+ goto iput_unm_err_out;
}
+ /* No longer need the bitmap attribute inode. */
+ iput(bvi);
skip_large_dir_stuff:
/* Setup the operations for this inode. */
vi->i_op = &ntfs_dir_inode_ops;
@@ -1176,7 +1176,8 @@ no_data_attr_special_case:
vi->i_blocks = ni->allocated_size >> 9;
ntfs_debug("Done.");
return 0;
-
+iput_unm_err_out:
+ iput(bvi);
unm_err_out:
if (!err)
err = -EIO;
@@ -1697,7 +1698,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
vi->i_size);
goto iput_unm_err_out;
}
- ni->itype.index.bmp_ino = bvi;
+ iput(bvi);
skip_large_index_stuff:
/* Setup the operations for this index inode. */
vi->i_op = NULL;
@@ -1714,7 +1715,6 @@ skip_large_index_stuff:
ntfs_debug("Done.");
return 0;
-
iput_unm_err_out:
iput(bvi);
unm_err_out:
@@ -2191,37 +2191,6 @@ err_out:
return -1;
}
-/**
- * ntfs_put_inode - handler for when the inode reference count is decremented
- * @vi: vfs inode
- *
- * The VFS calls ntfs_put_inode() every time the inode reference count (i_count)
- * is about to be decremented (but before the decrement itself.
- *
- * If the inode @vi is a directory with two references, one of which is being
- * dropped, we need to put the attribute inode for the directory index bitmap,
- * if it is present, otherwise the directory inode would remain pinned for
- * ever.
- */
-void ntfs_put_inode(struct inode *vi)
-{
- if (S_ISDIR(vi->i_mode) && atomic_read(&vi->i_count) == 2) {
- ntfs_inode *ni = NTFS_I(vi);
- if (NInoIndexAllocPresent(ni)) {
- struct inode *bvi = NULL;
- mutex_lock(&vi->i_mutex);
- if (atomic_read(&vi->i_count) == 2) {
- bvi = ni->itype.index.bmp_ino;
- if (bvi)
- ni->itype.index.bmp_ino = NULL;
- }
- mutex_unlock(&vi->i_mutex);
- if (bvi)
- iput(bvi);
- }
- }
-}
-
static void __ntfs_clear_inode(ntfs_inode *ni)
{
/* Free all alocated memory. */
@@ -2287,18 +2256,6 @@ void ntfs_clear_big_inode(struct inode *vi)
{
ntfs_inode *ni = NTFS_I(vi);
- /*
- * If the inode @vi is an index inode we need to put the attribute
- * inode for the index bitmap, if it is present, otherwise the index
- * inode would disappear and the attribute inode for the index bitmap
- * would no longer be referenced from anywhere and thus it would remain
- * pinned for ever.
- */
- if (NInoAttr(ni) && (ni->type == AT_INDEX_ALLOCATION) &&
- NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino) {
- iput(ni->itype.index.bmp_ino);
- ni->itype.index.bmp_ino = NULL;
- }
#ifdef NTFS_RW
if (NInoDirty(ni)) {
bool was_bad = (is_bad_inode(vi));
diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h
index f088291e017..117eaf8032a 100644
--- a/fs/ntfs/inode.h
+++ b/fs/ntfs/inode.h
@@ -2,7 +2,7 @@
* inode.h - Defines for inode structures NTFS Linux kernel driver. Part of
* the Linux-NTFS project.
*
- * Copyright (c) 2001-2005 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
@@ -101,8 +101,6 @@ struct _ntfs_inode {
runlist attr_list_rl; /* Run list for the attribute list value. */
union {
struct { /* It is a directory, $MFT, or an index inode. */
- struct inode *bmp_ino; /* Attribute inode for the
- index $BITMAP. */
u32 block_size; /* Size of an index block. */
u32 vcn_size; /* Size of a vcn in this
index. */
@@ -300,8 +298,6 @@ extern void ntfs_clear_extent_inode(ntfs_inode *ni);
extern int ntfs_read_inode_mount(struct inode *vi);
-extern void ntfs_put_inode(struct inode *vi);
-
extern int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt);
#ifdef NTFS_RW
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 03a391ac714..babf94d90de 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -1,7 +1,7 @@
/*
* super.c - NTFS kernel super block handling. Part of the Linux-NTFS project.
*
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
* Copyright (c) 2001,2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
@@ -2702,9 +2702,6 @@ static int ntfs_statfs(struct dentry *dentry, struct kstatfs *sfs)
static struct super_operations ntfs_sops = {
.alloc_inode = ntfs_alloc_big_inode, /* VFS: Allocate new inode. */
.destroy_inode = ntfs_destroy_big_inode, /* VFS: Deallocate inode. */
- .put_inode = ntfs_put_inode, /* VFS: Called just before
- the inode reference count
- is decreased. */
#ifdef NTFS_RW
//.dirty_inode = NULL, /* VFS: Called from
// __mark_inode_dirty(). */
@@ -3261,7 +3258,7 @@ static void __exit exit_ntfs_fs(void)
}
MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>");
-MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2006 Anton Altaparmakov");
+MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2007 Anton Altaparmakov");
MODULE_VERSION(NTFS_VERSION);
MODULE_LICENSE("GPL");
#ifdef DEBUG
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index edc91ca3792..f27e5378caf 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -1959,7 +1959,7 @@ int ocfs2_prepare_truncate(struct ocfs2_super *osb,
goto bail;
}
- *tc = kcalloc(1, sizeof(struct ocfs2_truncate_context), GFP_KERNEL);
+ *tc = kzalloc(sizeof(struct ocfs2_truncate_context), GFP_KERNEL);
if (!(*tc)) {
status = -ENOMEM;
mlog_errno(status);
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 2f7268e8152..93628b02ef5 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -540,8 +540,7 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
int ret;
- u64 vbo_max; /* file offset, max_blocks from iblock */
- u64 p_blkno;
+ u64 p_blkno, inode_blocks;
int contig_blocks;
unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
@@ -550,12 +549,23 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
* nicely aligned and of the right size, so there's no need
* for us to check any of that. */
- vbo_max = ((u64)iblock + max_blocks) << blocksize_bits;
-
spin_lock(&OCFS2_I(inode)->ip_lock);
- if ((iblock + max_blocks) >
- ocfs2_clusters_to_blocks(inode->i_sb,
- OCFS2_I(inode)->ip_clusters)) {
+ inode_blocks = ocfs2_clusters_to_blocks(inode->i_sb,
+ OCFS2_I(inode)->ip_clusters);
+
+ /*
+ * For a read which begins past the end of file, we return a hole.
+ */
+ if (!create && (iblock >= inode_blocks)) {
+ spin_unlock(&OCFS2_I(inode)->ip_lock);
+ ret = 0;
+ goto bail;
+ }
+
+ /*
+ * Any write past EOF is not allowed because we'd be extending.
+ */
+ if (create && (iblock + max_blocks) > inode_blocks) {
spin_unlock(&OCFS2_I(inode)->ip_lock);
ret = -EIO;
goto bail;
@@ -595,7 +605,7 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
ssize_t bytes,
void *private)
{
- struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
+ struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
/* this io's submitter should not have unlocked this before we could */
BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));
@@ -611,7 +621,7 @@ static ssize_t ocfs2_direct_IO(int rw,
unsigned long nr_segs)
{
struct file *file = iocb->ki_filp;
- struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
+ struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
int ret;
mlog_entry_void();
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index 4cd9a958045..5a9779bb923 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -184,10 +184,9 @@ static void o2hb_disarm_write_timeout(struct o2hb_region *reg)
flush_scheduled_work();
}
-static inline void o2hb_bio_wait_init(struct o2hb_bio_wait_ctxt *wc,
- unsigned int num_ios)
+static inline void o2hb_bio_wait_init(struct o2hb_bio_wait_ctxt *wc)
{
- atomic_set(&wc->wc_num_reqs, num_ios);
+ atomic_set(&wc->wc_num_reqs, 1);
init_completion(&wc->wc_io_complete);
wc->wc_error = 0;
}
@@ -212,6 +211,7 @@ static void o2hb_wait_on_io(struct o2hb_region *reg,
struct address_space *mapping = reg->hr_bdev->bd_inode->i_mapping;
blk_run_address_space(mapping);
+ o2hb_bio_wait_dec(wc, 1);
wait_for_completion(&wc->wc_io_complete);
}
@@ -231,6 +231,7 @@ static int o2hb_bio_end_io(struct bio *bio,
return 1;
o2hb_bio_wait_dec(wc, 1);
+ bio_put(bio);
return 0;
}
@@ -238,23 +239,22 @@ static int o2hb_bio_end_io(struct bio *bio,
* start_slot. */
static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg,
struct o2hb_bio_wait_ctxt *wc,
- unsigned int start_slot,
- unsigned int num_slots)
+ unsigned int *current_slot,
+ unsigned int max_slots)
{
- int i, nr_vecs, len, first_page, last_page;
+ int len, current_page;
unsigned int vec_len, vec_start;
unsigned int bits = reg->hr_block_bits;
unsigned int spp = reg->hr_slots_per_page;
+ unsigned int cs = *current_slot;
struct bio *bio;
struct page *page;
- nr_vecs = (num_slots + spp - 1) / spp;
-
/* Testing has shown this allocation to take long enough under
* GFP_KERNEL that the local node can get fenced. It would be
* nicest if we could pre-allocate these bios and avoid this
* all together. */
- bio = bio_alloc(GFP_ATOMIC, nr_vecs);
+ bio = bio_alloc(GFP_ATOMIC, 16);
if (!bio) {
mlog(ML_ERROR, "Could not alloc slots BIO!\n");
bio = ERR_PTR(-ENOMEM);
@@ -262,137 +262,53 @@ static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg,
}
/* Must put everything in 512 byte sectors for the bio... */
- bio->bi_sector = (reg->hr_start_block + start_slot) << (bits - 9);
+ bio->bi_sector = (reg->hr_start_block + cs) << (bits - 9);
bio->bi_bdev = reg->hr_bdev;
bio->bi_private = wc;
bio->bi_end_io = o2hb_bio_end_io;
- first_page = start_slot / spp;
- last_page = first_page + nr_vecs;
- vec_start = (start_slot << bits) % PAGE_CACHE_SIZE;
- for(i = first_page; i < last_page; i++) {
- page = reg->hr_slot_data[i];
+ vec_start = (cs << bits) % PAGE_CACHE_SIZE;
+ while(cs < max_slots) {
+ current_page = cs / spp;
+ page = reg->hr_slot_data[current_page];
- vec_len = PAGE_CACHE_SIZE;
- /* last page might be short */
- if (((i + 1) * spp) > (start_slot + num_slots))
- vec_len = ((num_slots + start_slot) % spp) << bits;
- vec_len -= vec_start;
+ vec_len = min(PAGE_CACHE_SIZE,
+ (max_slots-cs) * (PAGE_CACHE_SIZE/spp) );
mlog(ML_HB_BIO, "page %d, vec_len = %u, vec_start = %u\n",
- i, vec_len, vec_start);
+ current_page, vec_len, vec_start);
len = bio_add_page(bio, page, vec_len, vec_start);
- if (len != vec_len) {
- bio_put(bio);
- bio = ERR_PTR(-EIO);
-
- mlog(ML_ERROR, "Error adding page to bio i = %d, "
- "vec_len = %u, len = %d\n, start = %u\n",
- i, vec_len, len, vec_start);
- goto bail;
- }
+ if (len != vec_len) break;
+ cs += vec_len / (PAGE_CACHE_SIZE/spp);
vec_start = 0;
}
bail:
+ *current_slot = cs;
return bio;
}
-/*
- * Compute the maximum number of sectors the bdev can handle in one bio,
- * as a power of two.
- *
- * Stolen from oracleasm, thanks Joel!
- */
-static int compute_max_sectors(struct block_device *bdev)
-{
- int max_pages, max_sectors, pow_two_sectors;
-
- struct request_queue *q;
-
- q = bdev_get_queue(bdev);
- max_pages = q->max_sectors >> (PAGE_SHIFT - 9);
- if (max_pages > BIO_MAX_PAGES)
- max_pages = BIO_MAX_PAGES;
- if (max_pages > q->max_phys_segments)
- max_pages = q->max_phys_segments;
- if (max_pages > q->max_hw_segments)
- max_pages = q->max_hw_segments;
- max_pages--; /* Handle I/Os that straddle a page */
-
- if (max_pages) {
- max_sectors = max_pages << (PAGE_SHIFT - 9);
- } else {
- /* If BIO contains 1 or less than 1 page. */
- max_sectors = q->max_sectors;
- }
- /* Why is fls() 1-based???? */
- pow_two_sectors = 1 << (fls(max_sectors) - 1);
-
- return pow_two_sectors;
-}
-
-static inline void o2hb_compute_request_limits(struct o2hb_region *reg,
- unsigned int num_slots,
- unsigned int *num_bios,
- unsigned int *slots_per_bio)
-{
- unsigned int max_sectors, io_sectors;
-
- max_sectors = compute_max_sectors(reg->hr_bdev);
-
- io_sectors = num_slots << (reg->hr_block_bits - 9);
-
- *num_bios = (io_sectors + max_sectors - 1) / max_sectors;
- *slots_per_bio = max_sectors >> (reg->hr_block_bits - 9);
-
- mlog(ML_HB_BIO, "My io size is %u sectors for %u slots. This "
- "device can handle %u sectors of I/O\n", io_sectors, num_slots,
- max_sectors);
- mlog(ML_HB_BIO, "Will need %u bios holding %u slots each\n",
- *num_bios, *slots_per_bio);
-}
-
static int o2hb_read_slots(struct o2hb_region *reg,
unsigned int max_slots)
{
- unsigned int num_bios, slots_per_bio, start_slot, num_slots;
- int i, status;
+ unsigned int current_slot=0;
+ int status;
struct o2hb_bio_wait_ctxt wc;
- struct bio **bios;
struct bio *bio;
- o2hb_compute_request_limits(reg, max_slots, &num_bios, &slots_per_bio);
-
- bios = kcalloc(num_bios, sizeof(struct bio *), GFP_KERNEL);
- if (!bios) {
- status = -ENOMEM;
- mlog_errno(status);
- return status;
- }
+ o2hb_bio_wait_init(&wc);
- o2hb_bio_wait_init(&wc, num_bios);
-
- num_slots = slots_per_bio;
- for(i = 0; i < num_bios; i++) {
- start_slot = i * slots_per_bio;
-
- /* adjust num_slots at last bio */
- if (max_slots < (start_slot + num_slots))
- num_slots = max_slots - start_slot;
-
- bio = o2hb_setup_one_bio(reg, &wc, start_slot, num_slots);
+ while(current_slot < max_slots) {
+ bio = o2hb_setup_one_bio(reg, &wc, &current_slot, max_slots);
if (IS_ERR(bio)) {
- o2hb_bio_wait_dec(&wc, num_bios - i);
-
status = PTR_ERR(bio);
mlog_errno(status);
goto bail_and_wait;
}
- bios[i] = bio;
+ atomic_inc(&wc.wc_num_reqs);
submit_bio(READ, bio);
}
@@ -403,38 +319,30 @@ bail_and_wait:
if (wc.wc_error && !status)
status = wc.wc_error;
- if (bios) {
- for(i = 0; i < num_bios; i++)
- if (bios[i])
- bio_put(bios[i]);
- kfree(bios);
- }
-
return status;
}
static int o2hb_issue_node_write(struct o2hb_region *reg,
- struct bio **write_bio,
struct o2hb_bio_wait_ctxt *write_wc)
{
int status;
unsigned int slot;
struct bio *bio;
- o2hb_bio_wait_init(write_wc, 1);
+ o2hb_bio_wait_init(write_wc);
slot = o2nm_this_node();
- bio = o2hb_setup_one_bio(reg, write_wc, slot, 1);
+ bio = o2hb_setup_one_bio(reg, write_wc, &slot, slot+1);
if (IS_ERR(bio)) {
status = PTR_ERR(bio);
mlog_errno(status);
goto bail;
}
+ atomic_inc(&write_wc->wc_num_reqs);
submit_bio(WRITE, bio);
- *write_bio = bio;
status = 0;
bail:
return status;
@@ -826,7 +734,6 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
{
int i, ret, highest_node, change = 0;
unsigned long configured_nodes[BITS_TO_LONGS(O2NM_MAX_NODES)];
- struct bio *write_bio;
struct o2hb_bio_wait_ctxt write_wc;
ret = o2nm_configured_node_map(configured_nodes,
@@ -864,7 +771,7 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
/* And fire off the write. Note that we don't wait on this I/O
* until later. */
- ret = o2hb_issue_node_write(reg, &write_bio, &write_wc);
+ ret = o2hb_issue_node_write(reg, &write_wc);
if (ret < 0) {
mlog_errno(ret);
return ret;
@@ -882,7 +789,6 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
* people we find in our steady state have seen us.
*/
o2hb_wait_on_io(reg, &write_wc);
- bio_put(write_bio);
if (write_wc.wc_error) {
/* Do not re-arm the write timeout on I/O error - we
* can't be sure that the new block ever made it to
@@ -943,7 +849,6 @@ static int o2hb_thread(void *data)
{
int i, ret;
struct o2hb_region *reg = data;
- struct bio *write_bio;
struct o2hb_bio_wait_ctxt write_wc;
struct timeval before_hb, after_hb;
unsigned int elapsed_msec;
@@ -993,10 +898,9 @@ static int o2hb_thread(void *data)
*
* XXX: Should we skip this on unclean_stop? */
o2hb_prepare_block(reg, 0);
- ret = o2hb_issue_node_write(reg, &write_bio, &write_wc);
+ ret = o2hb_issue_node_write(reg, &write_wc);
if (ret == 0) {
o2hb_wait_on_io(reg, &write_wc);
- bio_put(write_bio);
} else {
mlog_errno(ret);
}
@@ -1447,6 +1351,15 @@ out:
return ret;
}
+static ssize_t o2hb_region_pid_read(struct o2hb_region *reg,
+ char *page)
+{
+ if (!reg->hr_task)
+ return 0;
+
+ return sprintf(page, "%u\n", reg->hr_task->pid);
+}
+
struct o2hb_region_attribute {
struct configfs_attribute attr;
ssize_t (*show)(struct o2hb_region *, char *);
@@ -1485,11 +1398,19 @@ static struct o2hb_region_attribute o2hb_region_attr_dev = {
.store = o2hb_region_dev_write,
};
+static struct o2hb_region_attribute o2hb_region_attr_pid = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "pid",
+ .ca_mode = S_IRUGO | S_IRUSR },
+ .show = o2hb_region_pid_read,
+};
+
static struct configfs_attribute *o2hb_region_attrs[] = {
&o2hb_region_attr_block_bytes.attr,
&o2hb_region_attr_start_block.attr,
&o2hb_region_attr_blocks.attr,
&o2hb_region_attr_dev.attr,
+ &o2hb_region_attr_pid.attr,
NULL,
};
@@ -1553,7 +1474,7 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g
struct o2hb_region *reg = NULL;
struct config_item *ret = NULL;
- reg = kcalloc(1, sizeof(struct o2hb_region), GFP_KERNEL);
+ reg = kzalloc(sizeof(struct o2hb_region), GFP_KERNEL);
if (reg == NULL)
goto out; /* ENOMEM */
@@ -1679,7 +1600,7 @@ struct config_group *o2hb_alloc_hb_set(void)
struct o2hb_heartbeat_group *hs = NULL;
struct config_group *ret = NULL;
- hs = kcalloc(1, sizeof(struct o2hb_heartbeat_group), GFP_KERNEL);
+ hs = kzalloc(sizeof(struct o2hb_heartbeat_group), GFP_KERNEL);
if (hs == NULL)
goto out;
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index d11753c50bc..b17333a0606 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -35,7 +35,7 @@
/* for now we operate under the assertion that there can be only one
* cluster active at a time. Changing this will require trickling
* cluster references throughout where nodes are looked up */
-static struct o2nm_cluster *o2nm_single_cluster = NULL;
+struct o2nm_cluster *o2nm_single_cluster = NULL;
#define OCFS2_MAX_HB_CTL_PATH 256
static char ocfs2_hb_ctl_path[OCFS2_MAX_HB_CTL_PATH] = "/sbin/ocfs2_hb_ctl";
@@ -97,17 +97,6 @@ const char *o2nm_get_hb_ctl_path(void)
}
EXPORT_SYMBOL_GPL(o2nm_get_hb_ctl_path);
-struct o2nm_cluster {
- struct config_group cl_group;
- unsigned cl_has_local:1;
- u8 cl_local_node;
- rwlock_t cl_nodes_lock;
- struct o2nm_node *cl_nodes[O2NM_MAX_NODES];
- struct rb_root cl_node_ip_tree;
- /* this bitmap is part of a hack for disk bitmap.. will go eventually. - zab */
- unsigned long cl_nodes_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
-};
-
struct o2nm_node *o2nm_get_node_by_num(u8 node_num)
{
struct o2nm_node *node = NULL;
@@ -543,6 +532,179 @@ static struct o2nm_node_group *to_o2nm_node_group(struct config_group *group)
}
#endif
+struct o2nm_cluster_attribute {
+ struct configfs_attribute attr;
+ ssize_t (*show)(struct o2nm_cluster *, char *);
+ ssize_t (*store)(struct o2nm_cluster *, const char *, size_t);
+};
+
+static ssize_t o2nm_cluster_attr_write(const char *page, ssize_t count,
+ unsigned int *val)
+{
+ unsigned long tmp;
+ char *p = (char *)page;
+
+ tmp = simple_strtoul(p, &p, 0);
+ if (!p || (*p && (*p != '\n')))
+ return -EINVAL;
+
+ if (tmp == 0)
+ return -EINVAL;
+ if (tmp >= (u32)-1)
+ return -ERANGE;
+
+ *val = tmp;
+
+ return count;
+}
+
+static ssize_t o2nm_cluster_attr_idle_timeout_ms_read(
+ struct o2nm_cluster *cluster, char *page)
+{
+ return sprintf(page, "%u\n", cluster->cl_idle_timeout_ms);
+}
+
+static ssize_t o2nm_cluster_attr_idle_timeout_ms_write(
+ struct o2nm_cluster *cluster, const char *page, size_t count)
+{
+ ssize_t ret;
+ unsigned int val;
+
+ ret = o2nm_cluster_attr_write(page, count, &val);
+
+ if (ret > 0) {
+ if (cluster->cl_idle_timeout_ms != val
+ && o2net_num_connected_peers()) {
+ mlog(ML_NOTICE,
+ "o2net: cannot change idle timeout after "
+ "the first peer has agreed to it."
+ " %d connected peers\n",
+ o2net_num_connected_peers());
+ ret = -EINVAL;
+ } else if (val <= cluster->cl_keepalive_delay_ms) {
+ mlog(ML_NOTICE, "o2net: idle timeout must be larger "
+ "than keepalive delay\n");
+ ret = -EINVAL;
+ } else {
+ cluster->cl_idle_timeout_ms = val;
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t o2nm_cluster_attr_keepalive_delay_ms_read(
+ struct o2nm_cluster *cluster, char *page)
+{
+ return sprintf(page, "%u\n", cluster->cl_keepalive_delay_ms);
+}
+
+static ssize_t o2nm_cluster_attr_keepalive_delay_ms_write(
+ struct o2nm_cluster *cluster, const char *page, size_t count)
+{
+ ssize_t ret;
+ unsigned int val;
+
+ ret = o2nm_cluster_attr_write(page, count, &val);
+
+ if (ret > 0) {
+ if (cluster->cl_keepalive_delay_ms != val
+ && o2net_num_connected_peers()) {
+ mlog(ML_NOTICE,
+ "o2net: cannot change keepalive delay after"
+ " the first peer has agreed to it."
+ " %d connected peers\n",
+ o2net_num_connected_peers());
+ ret = -EINVAL;
+ } else if (val >= cluster->cl_idle_timeout_ms) {
+ mlog(ML_NOTICE, "o2net: keepalive delay must be "
+ "smaller than idle timeout\n");
+ ret = -EINVAL;
+ } else {
+ cluster->cl_keepalive_delay_ms = val;
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t o2nm_cluster_attr_reconnect_delay_ms_read(
+ struct o2nm_cluster *cluster, char *page)
+{
+ return sprintf(page, "%u\n", cluster->cl_reconnect_delay_ms);
+}
+
+static ssize_t o2nm_cluster_attr_reconnect_delay_ms_write(
+ struct o2nm_cluster *cluster, const char *page, size_t count)
+{
+ return o2nm_cluster_attr_write(page, count,
+ &cluster->cl_reconnect_delay_ms);
+}
+static struct o2nm_cluster_attribute o2nm_cluster_attr_idle_timeout_ms = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "idle_timeout_ms",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = o2nm_cluster_attr_idle_timeout_ms_read,
+ .store = o2nm_cluster_attr_idle_timeout_ms_write,
+};
+
+static struct o2nm_cluster_attribute o2nm_cluster_attr_keepalive_delay_ms = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "keepalive_delay_ms",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = o2nm_cluster_attr_keepalive_delay_ms_read,
+ .store = o2nm_cluster_attr_keepalive_delay_ms_write,
+};
+
+static struct o2nm_cluster_attribute o2nm_cluster_attr_reconnect_delay_ms = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "reconnect_delay_ms",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = o2nm_cluster_attr_reconnect_delay_ms_read,
+ .store = o2nm_cluster_attr_reconnect_delay_ms_write,
+};
+
+static struct configfs_attribute *o2nm_cluster_attrs[] = {
+ &o2nm_cluster_attr_idle_timeout_ms.attr,
+ &o2nm_cluster_attr_keepalive_delay_ms.attr,
+ &o2nm_cluster_attr_reconnect_delay_ms.attr,
+ NULL,
+};
+static ssize_t o2nm_cluster_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
+{
+ struct o2nm_cluster *cluster = to_o2nm_cluster(item);
+ struct o2nm_cluster_attribute *o2nm_cluster_attr =
+ container_of(attr, struct o2nm_cluster_attribute, attr);
+ ssize_t ret = 0;
+
+ if (o2nm_cluster_attr->show)
+ ret = o2nm_cluster_attr->show(cluster, page);
+ return ret;
+}
+
+static ssize_t o2nm_cluster_store(struct config_item *item,
+ struct configfs_attribute *attr,
+ const char *page, size_t count)
+{
+ struct o2nm_cluster *cluster = to_o2nm_cluster(item);
+ struct o2nm_cluster_attribute *o2nm_cluster_attr =
+ container_of(attr, struct o2nm_cluster_attribute, attr);
+ ssize_t ret;
+
+ if (o2nm_cluster_attr->store == NULL) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = o2nm_cluster_attr->store(cluster, page, count);
+ if (ret < count)
+ goto out;
+out:
+ return ret;
+}
+
static struct config_item *o2nm_node_group_make_item(struct config_group *group,
const char *name)
{
@@ -552,7 +714,7 @@ static struct config_item *o2nm_node_group_make_item(struct config_group *group,
if (strlen(name) > O2NM_MAX_NAME_LEN)
goto out; /* ENAMETOOLONG */
- node = kcalloc(1, sizeof(struct o2nm_node), GFP_KERNEL);
+ node = kzalloc(sizeof(struct o2nm_node), GFP_KERNEL);
if (node == NULL)
goto out; /* ENOMEM */
@@ -624,10 +786,13 @@ static void o2nm_cluster_release(struct config_item *item)
static struct configfs_item_operations o2nm_cluster_item_ops = {
.release = o2nm_cluster_release,
+ .show_attribute = o2nm_cluster_show,
+ .store_attribute = o2nm_cluster_store,
};
static struct config_item_type o2nm_cluster_type = {
.ct_item_ops = &o2nm_cluster_item_ops,
+ .ct_attrs = o2nm_cluster_attrs,
.ct_owner = THIS_MODULE,
};
@@ -660,8 +825,8 @@ static struct config_group *o2nm_cluster_group_make_group(struct config_group *g
if (o2nm_single_cluster)
goto out; /* ENOSPC */
- cluster = kcalloc(1, sizeof(struct o2nm_cluster), GFP_KERNEL);
- ns = kcalloc(1, sizeof(struct o2nm_node_group), GFP_KERNEL);
+ cluster = kzalloc(sizeof(struct o2nm_cluster), GFP_KERNEL);
+ ns = kzalloc(sizeof(struct o2nm_node_group), GFP_KERNEL);
defs = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
o2hb_group = o2hb_alloc_hb_set();
if (cluster == NULL || ns == NULL || o2hb_group == NULL || defs == NULL)
@@ -678,6 +843,9 @@ static struct config_group *o2nm_cluster_group_make_group(struct config_group *g
cluster->cl_group.default_groups[2] = NULL;
rwlock_init(&cluster->cl_nodes_lock);
cluster->cl_node_ip_tree = RB_ROOT;
+ cluster->cl_reconnect_delay_ms = O2NET_RECONNECT_DELAY_MS_DEFAULT;
+ cluster->cl_idle_timeout_ms = O2NET_IDLE_TIMEOUT_MS_DEFAULT;
+ cluster->cl_keepalive_delay_ms = O2NET_KEEPALIVE_DELAY_MS_DEFAULT;
ret = &cluster->cl_group;
o2nm_single_cluster = cluster;
diff --git a/fs/ocfs2/cluster/nodemanager.h b/fs/ocfs2/cluster/nodemanager.h
index fce8033c310..8fb23cacc2f 100644
--- a/fs/ocfs2/cluster/nodemanager.h
+++ b/fs/ocfs2/cluster/nodemanager.h
@@ -53,6 +53,23 @@ struct o2nm_node {
unsigned long nd_set_attributes;
};
+struct o2nm_cluster {
+ struct config_group cl_group;
+ unsigned cl_has_local:1;
+ u8 cl_local_node;
+ rwlock_t cl_nodes_lock;
+ struct o2nm_node *cl_nodes[O2NM_MAX_NODES];
+ struct rb_root cl_node_ip_tree;
+ unsigned int cl_idle_timeout_ms;
+ unsigned int cl_keepalive_delay_ms;
+ unsigned int cl_reconnect_delay_ms;
+
+ /* this bitmap is part of a hack for disk bitmap.. will go eventually. - zab */
+ unsigned long cl_nodes_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
+};
+
+extern struct o2nm_cluster *o2nm_single_cluster;
+
u8 o2nm_this_node(void);
int o2nm_configured_node_map(unsigned long *map, unsigned bytes);
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 9b3209dc0b1..1718215fc01 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -147,6 +147,28 @@ static void o2net_listen_data_ready(struct sock *sk, int bytes);
static void o2net_sc_send_keep_req(struct work_struct *work);
static void o2net_idle_timer(unsigned long data);
static void o2net_sc_postpone_idle(struct o2net_sock_container *sc);
+static void o2net_sc_reset_idle_timer(struct o2net_sock_container *sc);
+
+/*
+ * FIXME: These should use to_o2nm_cluster_from_node(), but we end up
+ * losing our parent link to the cluster during shutdown. This can be
+ * solved by adding a pre-removal callback to configfs, or passing
+ * around the cluster with the node. -jeffm
+ */
+static inline int o2net_reconnect_delay(struct o2nm_node *node)
+{
+ return o2nm_single_cluster->cl_reconnect_delay_ms;
+}
+
+static inline int o2net_keepalive_delay(struct o2nm_node *node)
+{
+ return o2nm_single_cluster->cl_keepalive_delay_ms;
+}
+
+static inline int o2net_idle_timeout(struct o2nm_node *node)
+{
+ return o2nm_single_cluster->cl_idle_timeout_ms;
+}
static inline int o2net_sys_err_to_errno(enum o2net_system_error err)
{
@@ -271,6 +293,8 @@ static void sc_kref_release(struct kref *kref)
{
struct o2net_sock_container *sc = container_of(kref,
struct o2net_sock_container, sc_kref);
+ BUG_ON(timer_pending(&sc->sc_idle_timeout));
+
sclog(sc, "releasing\n");
if (sc->sc_sock) {
@@ -300,7 +324,7 @@ static struct o2net_sock_container *sc_alloc(struct o2nm_node *node)
struct page *page = NULL;
page = alloc_page(GFP_NOFS);
- sc = kcalloc(1, sizeof(*sc), GFP_NOFS);
+ sc = kzalloc(sizeof(*sc), GFP_NOFS);
if (sc == NULL || page == NULL)
goto out;
@@ -356,6 +380,13 @@ static void o2net_sc_cancel_delayed_work(struct o2net_sock_container *sc,
sc_put(sc);
}
+static atomic_t o2net_connected_peers = ATOMIC_INIT(0);
+
+int o2net_num_connected_peers(void)
+{
+ return atomic_read(&o2net_connected_peers);
+}
+
static void o2net_set_nn_state(struct o2net_node *nn,
struct o2net_sock_container *sc,
unsigned valid, int err)
@@ -366,6 +397,11 @@ static void o2net_set_nn_state(struct o2net_node *nn,
assert_spin_locked(&nn->nn_lock);
+ if (old_sc && !sc)
+ atomic_dec(&o2net_connected_peers);
+ else if (!old_sc && sc)
+ atomic_inc(&o2net_connected_peers);
+
/* the node num comparison and single connect/accept path should stop
* an non-null sc from being overwritten with another */
BUG_ON(sc && nn->nn_sc && nn->nn_sc != sc);
@@ -424,9 +460,9 @@ static void o2net_set_nn_state(struct o2net_node *nn,
/* delay if we're withing a RECONNECT_DELAY of the
* last attempt */
delay = (nn->nn_last_connect_attempt +
- msecs_to_jiffies(O2NET_RECONNECT_DELAY_MS))
+ msecs_to_jiffies(o2net_reconnect_delay(sc->sc_node)))
- jiffies;
- if (delay > msecs_to_jiffies(O2NET_RECONNECT_DELAY_MS))
+ if (delay > msecs_to_jiffies(o2net_reconnect_delay(sc->sc_node)))
delay = 0;
mlog(ML_CONN, "queueing conn attempt in %lu jiffies\n", delay);
queue_delayed_work(o2net_wq, &nn->nn_connect_work, delay);
@@ -520,6 +556,8 @@ static void o2net_register_callbacks(struct sock *sk,
sk->sk_data_ready = o2net_data_ready;
sk->sk_state_change = o2net_state_change;
+ mutex_init(&sc->sc_send_lock);
+
write_unlock_bh(&sk->sk_callback_lock);
}
@@ -652,6 +690,7 @@ static void o2net_handler_put(struct o2net_msg_handler *nmh)
* be given to the handler if their payload is longer than the max. */
int o2net_register_handler(u32 msg_type, u32 key, u32 max_len,
o2net_msg_handler_func *func, void *data,
+ o2net_post_msg_handler_func *post_func,
struct list_head *unreg_list)
{
struct o2net_msg_handler *nmh = NULL;
@@ -678,7 +717,7 @@ int o2net_register_handler(u32 msg_type, u32 key, u32 max_len,
goto out;
}
- nmh = kcalloc(1, sizeof(struct o2net_msg_handler), GFP_NOFS);
+ nmh = kzalloc(sizeof(struct o2net_msg_handler), GFP_NOFS);
if (nmh == NULL) {
ret = -ENOMEM;
goto out;
@@ -686,6 +725,7 @@ int o2net_register_handler(u32 msg_type, u32 key, u32 max_len,
nmh->nh_func = func;
nmh->nh_func_data = data;
+ nmh->nh_post_func = post_func;
nmh->nh_msg_type = msg_type;
nmh->nh_max_len = max_len;
nmh->nh_key = key;
@@ -820,10 +860,12 @@ static void o2net_sendpage(struct o2net_sock_container *sc,
ssize_t ret;
+ mutex_lock(&sc->sc_send_lock);
ret = sc->sc_sock->ops->sendpage(sc->sc_sock,
virt_to_page(kmalloced_virt),
(long)kmalloced_virt & ~PAGE_MASK,
size, MSG_DONTWAIT);
+ mutex_unlock(&sc->sc_send_lock);
if (ret != size) {
mlog(ML_ERROR, "sendpage of size %zu to " SC_NODEF_FMT
" failed with %zd\n", size, SC_NODEF_ARGS(sc), ret);
@@ -938,8 +980,10 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
/* finally, convert the message header to network byte-order
* and send */
+ mutex_lock(&sc->sc_send_lock);
ret = o2net_send_tcp_msg(sc->sc_sock, vec, veclen,
sizeof(struct o2net_msg) + caller_bytes);
+ mutex_unlock(&sc->sc_send_lock);
msglog(msg, "sending returned %d\n", ret);
if (ret < 0) {
mlog(0, "error returned from o2net_send_tcp_msg=%d\n", ret);
@@ -1013,6 +1057,7 @@ static int o2net_process_message(struct o2net_sock_container *sc,
int ret = 0, handler_status;
enum o2net_system_error syserr;
struct o2net_msg_handler *nmh = NULL;
+ void *ret_data = NULL;
msglog(hdr, "processing message\n");
@@ -1065,17 +1110,26 @@ static int o2net_process_message(struct o2net_sock_container *sc,
sc->sc_msg_type = be16_to_cpu(hdr->msg_type);
handler_status = (nmh->nh_func)(hdr, sizeof(struct o2net_msg) +
be16_to_cpu(hdr->data_len),
- nmh->nh_func_data);
+ nmh->nh_func_data, &ret_data);
do_gettimeofday(&sc->sc_tv_func_stop);
out_respond:
/* this destroys the hdr, so don't use it after this */
+ mutex_lock(&sc->sc_send_lock);
ret = o2net_send_status_magic(sc->sc_sock, hdr, syserr,
handler_status);
+ mutex_unlock(&sc->sc_send_lock);
hdr = NULL;
mlog(0, "sending handler status %d, syserr %d returned %d\n",
handler_status, syserr, ret);
+ if (nmh) {
+ BUG_ON(ret_data != NULL && nmh->nh_post_func == NULL);
+ if (nmh->nh_post_func)
+ (nmh->nh_post_func)(handler_status, nmh->nh_func_data,
+ ret_data);
+ }
+
out:
if (nmh)
o2net_handler_put(nmh);
@@ -1099,13 +1153,51 @@ static int o2net_check_handshake(struct o2net_sock_container *sc)
return -1;
}
+ /*
+ * Ensure timeouts are consistent with other nodes, otherwise
+ * we can end up with one node thinking that the other must be down,
+ * but isn't. This can ultimately cause corruption.
+ */
+ if (be32_to_cpu(hand->o2net_idle_timeout_ms) !=
+ o2net_idle_timeout(sc->sc_node)) {
+ mlog(ML_NOTICE, SC_NODEF_FMT " uses a network idle timeout of "
+ "%u ms, but we use %u ms locally. disconnecting\n",
+ SC_NODEF_ARGS(sc),
+ be32_to_cpu(hand->o2net_idle_timeout_ms),
+ o2net_idle_timeout(sc->sc_node));
+ o2net_ensure_shutdown(nn, sc, -ENOTCONN);
+ return -1;
+ }
+
+ if (be32_to_cpu(hand->o2net_keepalive_delay_ms) !=
+ o2net_keepalive_delay(sc->sc_node)) {
+ mlog(ML_NOTICE, SC_NODEF_FMT " uses a keepalive delay of "
+ "%u ms, but we use %u ms locally. disconnecting\n",
+ SC_NODEF_ARGS(sc),
+ be32_to_cpu(hand->o2net_keepalive_delay_ms),
+ o2net_keepalive_delay(sc->sc_node));
+ o2net_ensure_shutdown(nn, sc, -ENOTCONN);
+ return -1;
+ }
+
+ if (be32_to_cpu(hand->o2hb_heartbeat_timeout_ms) !=
+ O2HB_MAX_WRITE_TIMEOUT_MS) {
+ mlog(ML_NOTICE, SC_NODEF_FMT " uses a heartbeat timeout of "
+ "%u ms, but we use %u ms locally. disconnecting\n",
+ SC_NODEF_ARGS(sc),
+ be32_to_cpu(hand->o2hb_heartbeat_timeout_ms),
+ O2HB_MAX_WRITE_TIMEOUT_MS);
+ o2net_ensure_shutdown(nn, sc, -ENOTCONN);
+ return -1;
+ }
+
sc->sc_handshake_ok = 1;
spin_lock(&nn->nn_lock);
/* set valid and queue the idle timers only if it hasn't been
* shut down already */
if (nn->nn_sc == sc) {
- o2net_sc_postpone_idle(sc);
+ o2net_sc_reset_idle_timer(sc);
o2net_set_nn_state(nn, sc, 1, 0);
}
spin_unlock(&nn->nn_lock);
@@ -1131,6 +1223,23 @@ static int o2net_advance_rx(struct o2net_sock_container *sc)
sclog(sc, "receiving\n");
do_gettimeofday(&sc->sc_tv_advance_start);
+ if (unlikely(sc->sc_handshake_ok == 0)) {
+ if(sc->sc_page_off < sizeof(struct o2net_handshake)) {
+ data = page_address(sc->sc_page) + sc->sc_page_off;
+ datalen = sizeof(struct o2net_handshake) - sc->sc_page_off;
+ ret = o2net_recv_tcp_msg(sc->sc_sock, data, datalen);
+ if (ret > 0)
+ sc->sc_page_off += ret;
+ }
+
+ if (sc->sc_page_off == sizeof(struct o2net_handshake)) {
+ o2net_check_handshake(sc);
+ if (unlikely(sc->sc_handshake_ok == 0))
+ ret = -EPROTO;
+ }
+ goto out;
+ }
+
/* do we need more header? */
if (sc->sc_page_off < sizeof(struct o2net_msg)) {
data = page_address(sc->sc_page) + sc->sc_page_off;
@@ -1138,15 +1247,6 @@ static int o2net_advance_rx(struct o2net_sock_container *sc)
ret = o2net_recv_tcp_msg(sc->sc_sock, data, datalen);
if (ret > 0) {
sc->sc_page_off += ret;
-
- /* this working relies on the handshake being
- * smaller than the normal message header */
- if (sc->sc_page_off >= sizeof(struct o2net_handshake)&&
- !sc->sc_handshake_ok && o2net_check_handshake(sc)) {
- ret = -EPROTO;
- goto out;
- }
-
/* only swab incoming here.. we can
* only get here once as we cross from
* being under to over */
@@ -1248,6 +1348,18 @@ static int o2net_set_nodelay(struct socket *sock)
return ret;
}
+static void o2net_initialize_handshake(void)
+{
+ o2net_hand->o2hb_heartbeat_timeout_ms = cpu_to_be32(
+ O2HB_MAX_WRITE_TIMEOUT_MS);
+ o2net_hand->o2net_idle_timeout_ms = cpu_to_be32(
+ o2net_idle_timeout(NULL));
+ o2net_hand->o2net_keepalive_delay_ms = cpu_to_be32(
+ o2net_keepalive_delay(NULL));
+ o2net_hand->o2net_reconnect_delay_ms = cpu_to_be32(
+ o2net_reconnect_delay(NULL));
+}
+
/* ------------------------------------------------------------ */
/* called when a connect completes and after a sock is accepted. the
@@ -1262,6 +1374,7 @@ static void o2net_sc_connect_completed(struct work_struct *work)
(unsigned long long)O2NET_PROTOCOL_VERSION,
(unsigned long long)be64_to_cpu(o2net_hand->connector_id));
+ o2net_initialize_handshake();
o2net_sendpage(sc, o2net_hand, sizeof(*o2net_hand));
sc_put(sc);
}
@@ -1287,8 +1400,10 @@ static void o2net_idle_timer(unsigned long data)
do_gettimeofday(&now);
- printk(KERN_INFO "o2net: connection to " SC_NODEF_FMT " has been idle for 10 "
- "seconds, shutting it down.\n", SC_NODEF_ARGS(sc));
+ printk(KERN_INFO "o2net: connection to " SC_NODEF_FMT " has been idle for %u.%u "
+ "seconds, shutting it down.\n", SC_NODEF_ARGS(sc),
+ o2net_idle_timeout(sc->sc_node) / 1000,
+ o2net_idle_timeout(sc->sc_node) % 1000);
mlog(ML_NOTICE, "here are some times that might help debug the "
"situation: (tmr %ld.%ld now %ld.%ld dr %ld.%ld adv "
"%ld.%ld:%ld.%ld func (%08x:%u) %ld.%ld:%ld.%ld)\n",
@@ -1306,14 +1421,21 @@ static void o2net_idle_timer(unsigned long data)
o2net_sc_queue_work(sc, &sc->sc_shutdown_work);
}
-static void o2net_sc_postpone_idle(struct o2net_sock_container *sc)
+static void o2net_sc_reset_idle_timer(struct o2net_sock_container *sc)
{
o2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work);
o2net_sc_queue_delayed_work(sc, &sc->sc_keepalive_work,
- O2NET_KEEPALIVE_DELAY_SECS * HZ);
+ msecs_to_jiffies(o2net_keepalive_delay(sc->sc_node)));
do_gettimeofday(&sc->sc_tv_timer);
mod_timer(&sc->sc_idle_timeout,
- jiffies + (O2NET_IDLE_TIMEOUT_SECS * HZ));
+ jiffies + msecs_to_jiffies(o2net_idle_timeout(sc->sc_node)));
+}
+
+static void o2net_sc_postpone_idle(struct o2net_sock_container *sc)
+{
+ /* Only push out an existing timer */
+ if (timer_pending(&sc->sc_idle_timeout))
+ o2net_sc_reset_idle_timer(sc);
}
/* this work func is kicked whenever a path sets the nn state which doesn't
@@ -1435,9 +1557,12 @@ static void o2net_connect_expired(struct work_struct *work)
spin_lock(&nn->nn_lock);
if (!nn->nn_sc_valid) {
+ struct o2nm_node *node = nn->nn_sc->sc_node;
mlog(ML_ERROR, "no connection established with node %u after "
- "%u seconds, giving up and returning errors.\n",
- o2net_num_from_nn(nn), O2NET_IDLE_TIMEOUT_SECS);
+ "%u.%u seconds, giving up and returning errors.\n",
+ o2net_num_from_nn(nn),
+ o2net_idle_timeout(node) / 1000,
+ o2net_idle_timeout(node) % 1000);
o2net_set_nn_state(nn, NULL, 0, -ENOTCONN);
}
@@ -1478,6 +1603,8 @@ static void o2net_hb_node_down_cb(struct o2nm_node *node, int node_num,
if (node_num != o2nm_this_node())
o2net_disconnect_node(node);
+
+ BUG_ON(atomic_read(&o2net_connected_peers) < 0);
}
static void o2net_hb_node_up_cb(struct o2nm_node *node, int node_num,
@@ -1489,14 +1616,14 @@ static void o2net_hb_node_up_cb(struct o2nm_node *node, int node_num,
/* ensure an immediate connect attempt */
nn->nn_last_connect_attempt = jiffies -
- (msecs_to_jiffies(O2NET_RECONNECT_DELAY_MS) + 1);
+ (msecs_to_jiffies(o2net_reconnect_delay(node)) + 1);
if (node_num != o2nm_this_node()) {
/* heartbeat doesn't work unless a local node number is
* configured and doing so brings up the o2net_wq, so we can
* use it.. */
queue_delayed_work(o2net_wq, &nn->nn_connect_expired,
- O2NET_IDLE_TIMEOUT_SECS * HZ);
+ msecs_to_jiffies(o2net_idle_timeout(node)));
/* believe it or not, accept and node hearbeating testing
* can succeed for this node before we got here.. so
@@ -1641,6 +1768,7 @@ static int o2net_accept_one(struct socket *sock)
o2net_register_callbacks(sc->sc_sock->sk, sc);
o2net_sc_queue_work(sc, &sc->sc_rx_work);
+ o2net_initialize_handshake();
o2net_sendpage(sc, o2net_hand, sizeof(*o2net_hand));
out:
@@ -1685,13 +1813,13 @@ out:
ready(sk, bytes);
}
-static int o2net_open_listening_sock(__be16 port)
+static int o2net_open_listening_sock(__be32 addr, __be16 port)
{
struct socket *sock = NULL;
int ret;
struct sockaddr_in sin = {
.sin_family = PF_INET,
- .sin_addr = { .s_addr = (__force u32)htonl(INADDR_ANY) },
+ .sin_addr = { .s_addr = (__force u32)addr },
.sin_port = (__force u16)port,
};
@@ -1714,15 +1842,15 @@ static int o2net_open_listening_sock(__be16 port)
sock->sk->sk_reuse = 1;
ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
if (ret < 0) {
- mlog(ML_ERROR, "unable to bind socket to port %d, ret=%d\n",
- ntohs(port), ret);
+ mlog(ML_ERROR, "unable to bind socket at %u.%u.%u.%u:%u, "
+ "ret=%d\n", NIPQUAD(addr), ntohs(port), ret);
goto out;
}
ret = sock->ops->listen(sock, 64);
if (ret < 0) {
- mlog(ML_ERROR, "unable to listen on port %d, ret=%d\n",
- ntohs(port), ret);
+ mlog(ML_ERROR, "unable to listen on %u.%u.%u.%u:%u, ret=%d\n",
+ NIPQUAD(addr), ntohs(port), ret);
}
out:
@@ -1755,7 +1883,8 @@ int o2net_start_listening(struct o2nm_node *node)
return -ENOMEM; /* ? */
}
- ret = o2net_open_listening_sock(node->nd_ipv4_port);
+ ret = o2net_open_listening_sock(node->nd_ipv4_address,
+ node->nd_ipv4_port);
if (ret) {
destroy_workqueue(o2net_wq);
o2net_wq = NULL;
@@ -1808,9 +1937,9 @@ int o2net_init(void)
o2quo_init();
- o2net_hand = kcalloc(1, sizeof(struct o2net_handshake), GFP_KERNEL);
- o2net_keep_req = kcalloc(1, sizeof(struct o2net_msg), GFP_KERNEL);
- o2net_keep_resp = kcalloc(1, sizeof(struct o2net_msg), GFP_KERNEL);
+ o2net_hand = kzalloc(sizeof(struct o2net_handshake), GFP_KERNEL);
+ o2net_keep_req = kzalloc(sizeof(struct o2net_msg), GFP_KERNEL);
+ o2net_keep_resp = kzalloc(sizeof(struct o2net_msg), GFP_KERNEL);
if (!o2net_hand || !o2net_keep_req || !o2net_keep_resp) {
kfree(o2net_hand);
kfree(o2net_keep_req);
diff --git a/fs/ocfs2/cluster/tcp.h b/fs/ocfs2/cluster/tcp.h
index 616ff2b8434..da880fc215f 100644
--- a/fs/ocfs2/cluster/tcp.h
+++ b/fs/ocfs2/cluster/tcp.h
@@ -50,10 +50,20 @@ struct o2net_msg
__u8 buf[0];
};
-typedef int (o2net_msg_handler_func)(struct o2net_msg *msg, u32 len, void *data);
+typedef int (o2net_msg_handler_func)(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+typedef void (o2net_post_msg_handler_func)(int status, void *data,
+ void *ret_data);
#define O2NET_MAX_PAYLOAD_BYTES (4096 - sizeof(struct o2net_msg))
+/* same as hb delay, we're waiting for another node to recognize our hb */
+#define O2NET_RECONNECT_DELAY_MS_DEFAULT 2000
+
+#define O2NET_KEEPALIVE_DELAY_MS_DEFAULT 5000
+#define O2NET_IDLE_TIMEOUT_MS_DEFAULT 10000
+
+
/* TODO: figure this out.... */
static inline int o2net_link_down(int err, struct socket *sock)
{
@@ -92,6 +102,7 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *vec,
int o2net_register_handler(u32 msg_type, u32 key, u32 max_len,
o2net_msg_handler_func *func, void *data,
+ o2net_post_msg_handler_func *post_func,
struct list_head *unreg_list);
void o2net_unregister_handler_list(struct list_head *list);
@@ -101,6 +112,7 @@ void o2net_unregister_hb_callbacks(void);
int o2net_start_listening(struct o2nm_node *node);
void o2net_stop_listening(struct o2nm_node *node);
void o2net_disconnect_node(struct o2nm_node *node);
+int o2net_num_connected_peers(void);
int o2net_init(void);
void o2net_exit(void);
diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h
index daebbd3a2c8..4dae5df5e46 100644
--- a/fs/ocfs2/cluster/tcp_internal.h
+++ b/fs/ocfs2/cluster/tcp_internal.h
@@ -27,23 +27,26 @@
#define O2NET_MSG_KEEP_REQ_MAGIC ((u16)0xfa57)
#define O2NET_MSG_KEEP_RESP_MAGIC ((u16)0xfa58)
-/* same as hb delay, we're waiting for another node to recognize our hb */
-#define O2NET_RECONNECT_DELAY_MS O2HB_REGION_TIMEOUT_MS
-
/* we're delaying our quorum decision so that heartbeat will have timed
* out truly dead nodes by the time we come around to making decisions
* on their number */
#define O2NET_QUORUM_DELAY_MS ((o2hb_dead_threshold + 2) * O2HB_REGION_TIMEOUT_MS)
-#define O2NET_KEEPALIVE_DELAY_SECS 5
-#define O2NET_IDLE_TIMEOUT_SECS 10
-
/*
* This version number represents quite a lot, unfortunately. It not
* only represents the raw network message protocol on the wire but also
* locking semantics of the file system using the protocol. It should
* be somewhere else, I'm sure, but right now it isn't.
*
+ * New in version 7:
+ * - DLM join domain includes the live nodemap
+ *
+ * New in version 6:
+ * - DLM lockres remote refcount fixes.
+ *
+ * New in version 5:
+ * - Network timeout checking protocol
+ *
* New in version 4:
* - Remove i_generation from lock names for better stat performance.
*
@@ -54,10 +57,14 @@
* - full 64 bit i_size in the metadata lock lvbs
* - introduction of "rw" lock and pushing meta/data locking down
*/
-#define O2NET_PROTOCOL_VERSION 4ULL
+#define O2NET_PROTOCOL_VERSION 7ULL
struct o2net_handshake {
__be64 protocol_version;
__be64 connector_id;
+ __be32 o2hb_heartbeat_timeout_ms;
+ __be32 o2net_idle_timeout_ms;
+ __be32 o2net_keepalive_delay_ms;
+ __be32 o2net_reconnect_delay_ms;
};
struct o2net_node {
@@ -148,6 +155,8 @@ struct o2net_sock_container {
struct timeval sc_tv_func_stop;
u32 sc_msg_key;
u16 sc_msg_type;
+
+ struct mutex sc_send_lock;
};
struct o2net_msg_handler {
@@ -157,6 +166,8 @@ struct o2net_msg_handler {
u32 nh_key;
o2net_msg_handler_func *nh_func;
o2net_msg_handler_func *nh_func_data;
+ o2net_post_msg_handler_func
+ *nh_post_func;
struct kref nh_kref;
struct list_head nh_unregister_item;
};
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index baad2aa27c1..66821e17816 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -79,7 +79,7 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
struct buffer_head * bh, * tmp;
struct ocfs2_dir_entry * de;
int err;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block * sb = inode->i_sb;
unsigned int ra_sectors = 16;
int lock_level = 0;
diff --git a/fs/ocfs2/dlm/dlmast.c b/fs/ocfs2/dlm/dlmast.c
index 681046d5139..241cad342a4 100644
--- a/fs/ocfs2/dlm/dlmast.c
+++ b/fs/ocfs2/dlm/dlmast.c
@@ -263,7 +263,8 @@ void dlm_do_local_bast(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
-int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
int ret;
unsigned int locklen;
@@ -311,8 +312,8 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data)
past->type != DLM_BAST) {
mlog(ML_ERROR, "Unknown ast type! %d, cookie=%u:%llu"
"name=%.*s\n", past->type,
- dlm_get_lock_cookie_node(cookie),
- dlm_get_lock_cookie_seq(cookie),
+ dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
locklen, name);
ret = DLM_IVLOCKID;
goto leave;
@@ -323,8 +324,8 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data)
mlog(0, "got %sast for unknown lockres! "
"cookie=%u:%llu, name=%.*s, namelen=%u\n",
past->type == DLM_AST ? "" : "b",
- dlm_get_lock_cookie_node(cookie),
- dlm_get_lock_cookie_seq(cookie),
+ dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
locklen, name, locklen);
ret = DLM_IVLOCKID;
goto leave;
@@ -369,7 +370,8 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data)
mlog(0, "got %sast for unknown lock! cookie=%u:%llu, "
"name=%.*s, namelen=%u\n", past->type == DLM_AST ? "" : "b",
- dlm_get_lock_cookie_node(cookie), dlm_get_lock_cookie_seq(cookie),
+ dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
locklen, name, locklen);
ret = DLM_NORMAL;
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h
index 6b6ff76538c..e90b92f9ece 100644
--- a/fs/ocfs2/dlm/dlmcommon.h
+++ b/fs/ocfs2/dlm/dlmcommon.h
@@ -180,6 +180,11 @@ struct dlm_assert_master_priv
unsigned ignore_higher:1;
};
+struct dlm_deref_lockres_priv
+{
+ struct dlm_lock_resource *deref_res;
+ u8 deref_node;
+};
struct dlm_work_item
{
@@ -191,6 +196,7 @@ struct dlm_work_item
struct dlm_request_all_locks_priv ral;
struct dlm_mig_lockres_priv ml;
struct dlm_assert_master_priv am;
+ struct dlm_deref_lockres_priv dl;
} u;
};
@@ -222,6 +228,9 @@ static inline void __dlm_set_joining_node(struct dlm_ctxt *dlm,
#define DLM_LOCK_RES_DIRTY 0x00000008
#define DLM_LOCK_RES_IN_PROGRESS 0x00000010
#define DLM_LOCK_RES_MIGRATING 0x00000020
+#define DLM_LOCK_RES_DROPPING_REF 0x00000040
+#define DLM_LOCK_RES_BLOCK_DIRTY 0x00001000
+#define DLM_LOCK_RES_SETREF_INPROG 0x00002000
/* max milliseconds to wait to sync up a network failure with a node death */
#define DLM_NODE_DEATH_WAIT_MAX (5 * 1000)
@@ -265,6 +274,8 @@ struct dlm_lock_resource
u8 owner; //node which owns the lock resource, or unknown
u16 state;
char lvb[DLM_LVB_LEN];
+ unsigned int inflight_locks;
+ unsigned long refmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
};
struct dlm_migratable_lock
@@ -367,7 +378,7 @@ enum {
DLM_CONVERT_LOCK_MSG, /* 504 */
DLM_PROXY_AST_MSG, /* 505 */
DLM_UNLOCK_LOCK_MSG, /* 506 */
- DLM_UNUSED_MSG2, /* 507 */
+ DLM_DEREF_LOCKRES_MSG, /* 507 */
DLM_MIGRATE_REQUEST_MSG, /* 508 */
DLM_MIG_LOCKRES_MSG, /* 509 */
DLM_QUERY_JOIN_MSG, /* 510 */
@@ -417,6 +428,9 @@ struct dlm_master_request
u8 name[O2NM_MAX_NAME_LEN];
};
+#define DLM_ASSERT_RESPONSE_REASSERT 0x00000001
+#define DLM_ASSERT_RESPONSE_MASTERY_REF 0x00000002
+
#define DLM_ASSERT_MASTER_MLE_CLEANUP 0x00000001
#define DLM_ASSERT_MASTER_REQUERY 0x00000002
#define DLM_ASSERT_MASTER_FINISH_MIGRATION 0x00000004
@@ -430,6 +444,8 @@ struct dlm_assert_master
u8 name[O2NM_MAX_NAME_LEN];
};
+#define DLM_MIGRATE_RESPONSE_MASTERY_REF 0x00000001
+
struct dlm_migrate_request
{
u8 master;
@@ -609,12 +625,16 @@ struct dlm_begin_reco
};
+#define BITS_PER_BYTE 8
+#define BITS_TO_BYTES(bits) (((bits)+BITS_PER_BYTE-1)/BITS_PER_BYTE)
+
struct dlm_query_join_request
{
u8 node_idx;
u8 pad1[2];
u8 name_len;
u8 domain[O2NM_MAX_NAME_LEN];
+ u8 node_map[BITS_TO_BYTES(O2NM_MAX_NODES)];
};
struct dlm_assert_joined
@@ -648,6 +668,16 @@ struct dlm_finalize_reco
__be32 pad2;
};
+struct dlm_deref_lockres
+{
+ u32 pad1;
+ u16 pad2;
+ u8 node_idx;
+ u8 namelen;
+
+ u8 name[O2NM_MAX_NAME_LEN];
+};
+
static inline enum dlm_status
__dlm_lockres_state_to_status(struct dlm_lock_resource *res)
{
@@ -688,16 +718,20 @@ void dlm_lock_put(struct dlm_lock *lock);
void dlm_lock_attach_lockres(struct dlm_lock *lock,
struct dlm_lock_resource *res);
-int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data);
+int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
void dlm_revert_pending_convert(struct dlm_lock_resource *res,
struct dlm_lock *lock);
void dlm_revert_pending_lock(struct dlm_lock_resource *res,
struct dlm_lock *lock);
-int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data);
+int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
void dlm_commit_pending_cancel(struct dlm_lock_resource *res,
struct dlm_lock *lock);
void dlm_commit_pending_unlock(struct dlm_lock_resource *res,
@@ -721,8 +755,6 @@ void __dlm_lockres_calc_usage(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res);
void dlm_lockres_calc_usage(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res);
-void dlm_purge_lockres(struct dlm_ctxt *dlm,
- struct dlm_lock_resource *lockres);
static inline void dlm_lockres_get(struct dlm_lock_resource *res)
{
/* This is called on every lookup, so it might be worth
@@ -733,6 +765,10 @@ void dlm_lockres_put(struct dlm_lock_resource *res);
void __dlm_unhash_lockres(struct dlm_lock_resource *res);
void __dlm_insert_lockres(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res);
+struct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm,
+ const char *name,
+ unsigned int len,
+ unsigned int hash);
struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm,
const char *name,
unsigned int len,
@@ -753,6 +789,47 @@ struct dlm_lock_resource *dlm_new_lockres(struct dlm_ctxt *dlm,
const char *name,
unsigned int namelen);
+#define dlm_lockres_set_refmap_bit(bit,res) \
+ __dlm_lockres_set_refmap_bit(bit,res,__FILE__,__LINE__)
+#define dlm_lockres_clear_refmap_bit(bit,res) \
+ __dlm_lockres_clear_refmap_bit(bit,res,__FILE__,__LINE__)
+
+static inline void __dlm_lockres_set_refmap_bit(int bit,
+ struct dlm_lock_resource *res,
+ const char *file,
+ int line)
+{
+ //printk("%s:%d:%.*s: setting bit %d\n", file, line,
+ // res->lockname.len, res->lockname.name, bit);
+ set_bit(bit, res->refmap);
+}
+
+static inline void __dlm_lockres_clear_refmap_bit(int bit,
+ struct dlm_lock_resource *res,
+ const char *file,
+ int line)
+{
+ //printk("%s:%d:%.*s: clearing bit %d\n", file, line,
+ // res->lockname.len, res->lockname.name, bit);
+ clear_bit(bit, res->refmap);
+}
+
+void __dlm_lockres_drop_inflight_ref(struct dlm_ctxt *dlm,
+ struct dlm_lock_resource *res,
+ const char *file,
+ int line);
+void __dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm,
+ struct dlm_lock_resource *res,
+ int new_lockres,
+ const char *file,
+ int line);
+#define dlm_lockres_drop_inflight_ref(d,r) \
+ __dlm_lockres_drop_inflight_ref(d,r,__FILE__,__LINE__)
+#define dlm_lockres_grab_inflight_ref(d,r) \
+ __dlm_lockres_grab_inflight_ref(d,r,0,__FILE__,__LINE__)
+#define dlm_lockres_grab_inflight_ref_new(d,r) \
+ __dlm_lockres_grab_inflight_ref(d,r,1,__FILE__,__LINE__)
+
void dlm_queue_ast(struct dlm_ctxt *dlm, struct dlm_lock *lock);
void dlm_queue_bast(struct dlm_ctxt *dlm, struct dlm_lock *lock);
void dlm_do_local_ast(struct dlm_ctxt *dlm,
@@ -801,10 +878,7 @@ int dlm_heartbeat_init(struct dlm_ctxt *dlm);
void dlm_hb_node_down_cb(struct o2nm_node *node, int idx, void *data);
void dlm_hb_node_up_cb(struct o2nm_node *node, int idx, void *data);
-int dlm_lockres_is_dirty(struct dlm_ctxt *dlm, struct dlm_lock_resource *res);
-int dlm_migrate_lockres(struct dlm_ctxt *dlm,
- struct dlm_lock_resource *res,
- u8 target);
+int dlm_empty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res);
int dlm_finish_migration(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res,
u8 old_master);
@@ -812,15 +886,27 @@ void dlm_lockres_release_ast(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res);
void __dlm_lockres_reserve_ast(struct dlm_lock_resource *res);
-int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data);
-int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data);
+int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+void dlm_assert_master_post_handler(int status, void *data, void *ret_data);
+int dlm_deref_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
int dlm_do_master_requery(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
u8 nodenum, u8 *real_master);
@@ -856,10 +942,12 @@ static inline void __dlm_wait_on_lockres(struct dlm_lock_resource *res)
int dlm_init_mle_cache(void);
void dlm_destroy_mle_cache(void);
void dlm_hb_event_notify_attached(struct dlm_ctxt *dlm, int idx, int node_up);
+int dlm_drop_lockres_ref(struct dlm_ctxt *dlm,
+ struct dlm_lock_resource *res);
void dlm_clean_master_list(struct dlm_ctxt *dlm,
u8 dead_node);
int dlm_lock_basts_flushed(struct dlm_ctxt *dlm, struct dlm_lock *lock);
-
+int __dlm_lockres_has_locks(struct dlm_lock_resource *res);
int __dlm_lockres_unused(struct dlm_lock_resource *res);
static inline const char * dlm_lock_mode_name(int mode)
diff --git a/fs/ocfs2/dlm/dlmconvert.c b/fs/ocfs2/dlm/dlmconvert.c
index c764dc8e40a..ecb4d997221 100644
--- a/fs/ocfs2/dlm/dlmconvert.c
+++ b/fs/ocfs2/dlm/dlmconvert.c
@@ -286,8 +286,8 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm,
__dlm_print_one_lock_resource(res);
mlog(ML_ERROR, "converting a remote lock that is already "
"converting! (cookie=%u:%llu, conv=%d)\n",
- dlm_get_lock_cookie_node(lock->ml.cookie),
- dlm_get_lock_cookie_seq(lock->ml.cookie),
+ dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
lock->ml.convert_type);
status = DLM_DENIED;
goto bail;
@@ -418,7 +418,8 @@ static enum dlm_status dlm_send_remote_convert_request(struct dlm_ctxt *dlm,
* returns: DLM_NORMAL, DLM_IVLOCKID, DLM_BADARGS,
* status from __dlmconvert_master
*/
-int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
struct dlm_convert_lock *cnv = (struct dlm_convert_lock *)msg->buf;
@@ -428,7 +429,7 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data)
struct dlm_lockstatus *lksb;
enum dlm_status status = DLM_NORMAL;
u32 flags;
- int call_ast = 0, kick_thread = 0, ast_reserved = 0;
+ int call_ast = 0, kick_thread = 0, ast_reserved = 0, wake = 0;
if (!dlm_grab(dlm)) {
dlm_error(DLM_REJECTED);
@@ -479,25 +480,14 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data)
}
lock = NULL;
}
- if (!lock) {
- __dlm_print_one_lock_resource(res);
- list_for_each(iter, &res->granted) {
- lock = list_entry(iter, struct dlm_lock, list);
- if (lock->ml.node == cnv->node_idx) {
- mlog(ML_ERROR, "There is something here "
- "for node %u, lock->ml.cookie=%llu, "
- "cnv->cookie=%llu\n", cnv->node_idx,
- (unsigned long long)lock->ml.cookie,
- (unsigned long long)cnv->cookie);
- break;
- }
- }
- lock = NULL;
- }
spin_unlock(&res->spinlock);
if (!lock) {
status = DLM_IVLOCKID;
- dlm_error(status);
+ mlog(ML_ERROR, "did not find lock to convert on grant queue! "
+ "cookie=%u:%llu\n",
+ dlm_get_lock_cookie_node(be64_to_cpu(cnv->cookie)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(cnv->cookie)));
+ __dlm_print_one_lock_resource(res);
goto leave;
}
@@ -524,8 +514,11 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data)
cnv->requested_type,
&call_ast, &kick_thread);
res->state &= ~DLM_LOCK_RES_IN_PROGRESS;
+ wake = 1;
}
spin_unlock(&res->spinlock);
+ if (wake)
+ wake_up(&res->wq);
if (status != DLM_NORMAL) {
if (status != DLM_NOTQUEUED)
@@ -534,12 +527,7 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data)
}
leave:
- if (!lock)
- mlog(ML_ERROR, "did not find lock to convert on grant queue! "
- "cookie=%u:%llu\n",
- dlm_get_lock_cookie_node(cnv->cookie),
- dlm_get_lock_cookie_seq(cnv->cookie));
- else
+ if (lock)
dlm_lock_put(lock);
/* either queue the ast or release it, if reserved */
diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c
index 3f6c8d88f7a..64239b37e5d 100644
--- a/fs/ocfs2/dlm/dlmdebug.c
+++ b/fs/ocfs2/dlm/dlmdebug.c
@@ -53,6 +53,23 @@ void dlm_print_one_lock_resource(struct dlm_lock_resource *res)
spin_unlock(&res->spinlock);
}
+static void dlm_print_lockres_refmap(struct dlm_lock_resource *res)
+{
+ int bit;
+ assert_spin_locked(&res->spinlock);
+
+ mlog(ML_NOTICE, " refmap nodes: [ ");
+ bit = 0;
+ while (1) {
+ bit = find_next_bit(res->refmap, O2NM_MAX_NODES, bit);
+ if (bit >= O2NM_MAX_NODES)
+ break;
+ printk("%u ", bit);
+ bit++;
+ }
+ printk("], inflight=%u\n", res->inflight_locks);
+}
+
void __dlm_print_one_lock_resource(struct dlm_lock_resource *res)
{
struct list_head *iter2;
@@ -65,6 +82,7 @@ void __dlm_print_one_lock_resource(struct dlm_lock_resource *res)
res->owner, res->state);
mlog(ML_NOTICE, " last used: %lu, on purge list: %s\n",
res->last_used, list_empty(&res->purge) ? "no" : "yes");
+ dlm_print_lockres_refmap(res);
mlog(ML_NOTICE, " granted queue: \n");
list_for_each(iter2, &res->granted) {
lock = list_entry(iter2, struct dlm_lock, list);
@@ -72,8 +90,8 @@ void __dlm_print_one_lock_resource(struct dlm_lock_resource *res)
mlog(ML_NOTICE, " type=%d, conv=%d, node=%u, "
"cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n",
lock->ml.type, lock->ml.convert_type, lock->ml.node,
- dlm_get_lock_cookie_node(lock->ml.cookie),
- dlm_get_lock_cookie_seq(lock->ml.cookie),
+ dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
list_empty(&lock->ast_list) ? 'y' : 'n',
lock->ast_pending ? 'y' : 'n',
list_empty(&lock->bast_list) ? 'y' : 'n',
@@ -87,8 +105,8 @@ void __dlm_print_one_lock_resource(struct dlm_lock_resource *res)
mlog(ML_NOTICE, " type=%d, conv=%d, node=%u, "
"cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n",
lock->ml.type, lock->ml.convert_type, lock->ml.node,
- dlm_get_lock_cookie_node(lock->ml.cookie),
- dlm_get_lock_cookie_seq(lock->ml.cookie),
+ dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
list_empty(&lock->ast_list) ? 'y' : 'n',
lock->ast_pending ? 'y' : 'n',
list_empty(&lock->bast_list) ? 'y' : 'n',
@@ -102,8 +120,8 @@ void __dlm_print_one_lock_resource(struct dlm_lock_resource *res)
mlog(ML_NOTICE, " type=%d, conv=%d, node=%u, "
"cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n",
lock->ml.type, lock->ml.convert_type, lock->ml.node,
- dlm_get_lock_cookie_node(lock->ml.cookie),
- dlm_get_lock_cookie_seq(lock->ml.cookie),
+ dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
list_empty(&lock->ast_list) ? 'y' : 'n',
lock->ast_pending ? 'y' : 'n',
list_empty(&lock->bast_list) ? 'y' : 'n',
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c
index 420a375a394..6087c4749fe 100644
--- a/fs/ocfs2/dlm/dlmdomain.c
+++ b/fs/ocfs2/dlm/dlmdomain.c
@@ -48,6 +48,36 @@
#define MLOG_MASK_PREFIX (ML_DLM|ML_DLM_DOMAIN)
#include "cluster/masklog.h"
+/*
+ * ocfs2 node maps are array of long int, which limits to send them freely
+ * across the wire due to endianness issues. To workaround this, we convert
+ * long ints to byte arrays. Following 3 routines are helper functions to
+ * set/test/copy bits within those array of bytes
+ */
+static inline void byte_set_bit(u8 nr, u8 map[])
+{
+ map[nr >> 3] |= (1UL << (nr & 7));
+}
+
+static inline int byte_test_bit(u8 nr, u8 map[])
+{
+ return ((1UL << (nr & 7)) & (map[nr >> 3])) != 0;
+}
+
+static inline void byte_copymap(u8 dmap[], unsigned long smap[],
+ unsigned int sz)
+{
+ unsigned int nn;
+
+ if (!sz)
+ return;
+
+ memset(dmap, 0, ((sz + 7) >> 3));
+ for (nn = 0 ; nn < sz; nn++)
+ if (test_bit(nn, smap))
+ byte_set_bit(nn, dmap);
+}
+
static void dlm_free_pagevec(void **vec, int pages)
{
while (pages--)
@@ -95,10 +125,14 @@ static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events);
#define DLM_DOMAIN_BACKOFF_MS 200
-static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data);
-static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data);
-static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data);
-static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data);
+static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
+static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data);
static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm);
@@ -125,10 +159,10 @@ void __dlm_insert_lockres(struct dlm_ctxt *dlm,
hlist_add_head(&res->hash_node, bucket);
}
-struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm,
- const char *name,
- unsigned int len,
- unsigned int hash)
+struct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm,
+ const char *name,
+ unsigned int len,
+ unsigned int hash)
{
struct hlist_head *bucket;
struct hlist_node *list;
@@ -154,6 +188,37 @@ struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm,
return NULL;
}
+/* intended to be called by functions which do not care about lock
+ * resources which are being purged (most net _handler functions).
+ * this will return NULL for any lock resource which is found but
+ * currently in the process of dropping its mastery reference.
+ * use __dlm_lookup_lockres_full when you need the lock resource
+ * regardless (e.g. dlm_get_lock_resource) */
+struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm,
+ const char *name,
+ unsigned int len,
+ unsigned int hash)
+{
+ struct dlm_lock_resource *res = NULL;
+
+ mlog_entry("%.*s\n", len, name);
+
+ assert_spin_locked(&dlm->spinlock);
+
+ res = __dlm_lookup_lockres_full(dlm, name, len, hash);
+ if (res) {
+ spin_lock(&res->spinlock);
+ if (res->state & DLM_LOCK_RES_DROPPING_REF) {
+ spin_unlock(&res->spinlock);
+ dlm_lockres_put(res);
+ return NULL;
+ }
+ spin_unlock(&res->spinlock);
+ }
+
+ return res;
+}
+
struct dlm_lock_resource * dlm_lookup_lockres(struct dlm_ctxt *dlm,
const char *name,
unsigned int len)
@@ -330,43 +395,60 @@ static void dlm_complete_dlm_shutdown(struct dlm_ctxt *dlm)
wake_up(&dlm_domain_events);
}
-static void dlm_migrate_all_locks(struct dlm_ctxt *dlm)
+static int dlm_migrate_all_locks(struct dlm_ctxt *dlm)
{
- int i;
+ int i, num, n, ret = 0;
struct dlm_lock_resource *res;
+ struct hlist_node *iter;
+ struct hlist_head *bucket;
+ int dropped;
mlog(0, "Migrating locks from domain %s\n", dlm->name);
-restart:
+
+ num = 0;
spin_lock(&dlm->spinlock);
for (i = 0; i < DLM_HASH_BUCKETS; i++) {
- while (!hlist_empty(dlm_lockres_hash(dlm, i))) {
- res = hlist_entry(dlm_lockres_hash(dlm, i)->first,
- struct dlm_lock_resource, hash_node);
- /* need reference when manually grabbing lockres */
+redo_bucket:
+ n = 0;
+ bucket = dlm_lockres_hash(dlm, i);
+ iter = bucket->first;
+ while (iter) {
+ n++;
+ res = hlist_entry(iter, struct dlm_lock_resource,
+ hash_node);
dlm_lockres_get(res);
- /* this should unhash the lockres
- * and exit with dlm->spinlock */
- mlog(0, "purging res=%p\n", res);
- if (dlm_lockres_is_dirty(dlm, res)) {
- /* HACK! this should absolutely go.
- * need to figure out why some empty
- * lockreses are still marked dirty */
- mlog(ML_ERROR, "lockres %.*s dirty!\n",
- res->lockname.len, res->lockname.name);
-
- spin_unlock(&dlm->spinlock);
- dlm_kick_thread(dlm, res);
- wait_event(dlm->ast_wq, !dlm_lockres_is_dirty(dlm, res));
- dlm_lockres_put(res);
- goto restart;
- }
- dlm_purge_lockres(dlm, res);
+ /* migrate, if necessary. this will drop the dlm
+ * spinlock and retake it if it does migration. */
+ dropped = dlm_empty_lockres(dlm, res);
+
+ spin_lock(&res->spinlock);
+ __dlm_lockres_calc_usage(dlm, res);
+ iter = res->hash_node.next;
+ spin_unlock(&res->spinlock);
+
dlm_lockres_put(res);
+
+ cond_resched_lock(&dlm->spinlock);
+
+ if (dropped)
+ goto redo_bucket;
}
+ num += n;
+ mlog(0, "%s: touched %d lockreses in bucket %d "
+ "(tot=%d)\n", dlm->name, n, i, num);
}
spin_unlock(&dlm->spinlock);
-
+ wake_up(&dlm->dlm_thread_wq);
+
+ /* let the dlm thread take care of purging, keep scanning until
+ * nothing remains in the hash */
+ if (num) {
+ mlog(0, "%s: %d lock resources in hash last pass\n",
+ dlm->name, num);
+ ret = -EAGAIN;
+ }
mlog(0, "DONE Migrating locks from domain %s\n", dlm->name);
+ return ret;
}
static int dlm_no_joining_node(struct dlm_ctxt *dlm)
@@ -418,7 +500,8 @@ static void __dlm_print_nodes(struct dlm_ctxt *dlm)
printk("\n");
}
-static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data)
+static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
unsigned int node;
@@ -571,7 +654,9 @@ void dlm_unregister_domain(struct dlm_ctxt *dlm)
/* We changed dlm state, notify the thread */
dlm_kick_thread(dlm, NULL);
- dlm_migrate_all_locks(dlm);
+ while (dlm_migrate_all_locks(dlm)) {
+ mlog(0, "%s: more migration to do\n", dlm->name);
+ }
dlm_mark_domain_leaving(dlm);
dlm_leave_domain(dlm);
dlm_complete_dlm_shutdown(dlm);
@@ -580,11 +665,13 @@ void dlm_unregister_domain(struct dlm_ctxt *dlm)
}
EXPORT_SYMBOL_GPL(dlm_unregister_domain);
-static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data)
+static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_query_join_request *query;
enum dlm_query_join_response response;
struct dlm_ctxt *dlm = NULL;
+ u8 nodenum;
query = (struct dlm_query_join_request *) msg->buf;
@@ -608,6 +695,28 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data)
spin_lock(&dlm_domain_lock);
dlm = __dlm_lookup_domain_full(query->domain, query->name_len);
+ if (!dlm)
+ goto unlock_respond;
+
+ /*
+ * There is a small window where the joining node may not see the
+ * node(s) that just left but still part of the cluster. DISALLOW
+ * join request if joining node has different node map.
+ */
+ nodenum=0;
+ while (nodenum < O2NM_MAX_NODES) {
+ if (test_bit(nodenum, dlm->domain_map)) {
+ if (!byte_test_bit(nodenum, query->node_map)) {
+ mlog(0, "disallow join as node %u does not "
+ "have node %u in its nodemap\n",
+ query->node_idx, nodenum);
+ response = JOIN_DISALLOW;
+ goto unlock_respond;
+ }
+ }
+ nodenum++;
+ }
+
/* Once the dlm ctxt is marked as leaving then we don't want
* to be put in someone's domain map.
* Also, explicitly disallow joining at certain troublesome
@@ -626,15 +735,15 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data)
/* Disallow parallel joins. */
response = JOIN_DISALLOW;
} else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) {
- mlog(ML_NOTICE, "node %u trying to join, but recovery "
+ mlog(0, "node %u trying to join, but recovery "
"is ongoing.\n", bit);
response = JOIN_DISALLOW;
} else if (test_bit(bit, dlm->recovery_map)) {
- mlog(ML_NOTICE, "node %u trying to join, but it "
+ mlog(0, "node %u trying to join, but it "
"still needs recovery.\n", bit);
response = JOIN_DISALLOW;
} else if (test_bit(bit, dlm->domain_map)) {
- mlog(ML_NOTICE, "node %u trying to join, but it "
+ mlog(0, "node %u trying to join, but it "
"is still in the domain! needs recovery?\n",
bit);
response = JOIN_DISALLOW;
@@ -649,6 +758,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data)
spin_unlock(&dlm->spinlock);
}
+unlock_respond:
spin_unlock(&dlm_domain_lock);
respond:
@@ -657,7 +767,8 @@ respond:
return response;
}
-static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data)
+static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_assert_joined *assert;
struct dlm_ctxt *dlm = NULL;
@@ -694,7 +805,8 @@ static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data)
return 0;
}
-static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data)
+static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_cancel_join *cancel;
struct dlm_ctxt *dlm = NULL;
@@ -796,6 +908,9 @@ static int dlm_request_join(struct dlm_ctxt *dlm,
join_msg.name_len = strlen(dlm->name);
memcpy(join_msg.domain, dlm->name, join_msg.name_len);
+ /* copy live node map to join message */
+ byte_copymap(join_msg.node_map, dlm->live_nodes_map, O2NM_MAX_NODES);
+
status = o2net_send_message(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, &join_msg,
sizeof(join_msg), node, &retval);
if (status < 0 && status != -ENOPROTOOPT) {
@@ -920,7 +1035,7 @@ static int dlm_try_to_join_domain(struct dlm_ctxt *dlm)
mlog_entry("%p", dlm);
- ctxt = kcalloc(1, sizeof(*ctxt), GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
if (!ctxt) {
status = -ENOMEM;
mlog_errno(status);
@@ -1036,98 +1151,106 @@ static int dlm_register_domain_handlers(struct dlm_ctxt *dlm)
status = o2net_register_handler(DLM_MASTER_REQUEST_MSG, dlm->key,
sizeof(struct dlm_master_request),
dlm_master_request_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_ASSERT_MASTER_MSG, dlm->key,
sizeof(struct dlm_assert_master),
dlm_assert_master_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, dlm_assert_master_post_handler,
+ &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_CREATE_LOCK_MSG, dlm->key,
sizeof(struct dlm_create_lock),
dlm_create_lock_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_CONVERT_LOCK_MSG, dlm->key,
DLM_CONVERT_LOCK_MAX_LEN,
dlm_convert_lock_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_UNLOCK_LOCK_MSG, dlm->key,
DLM_UNLOCK_LOCK_MAX_LEN,
dlm_unlock_lock_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_PROXY_AST_MSG, dlm->key,
DLM_PROXY_AST_MAX_LEN,
dlm_proxy_ast_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_EXIT_DOMAIN_MSG, dlm->key,
sizeof(struct dlm_exit_domain),
dlm_exit_domain_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
+ if (status)
+ goto bail;
+
+ status = o2net_register_handler(DLM_DEREF_LOCKRES_MSG, dlm->key,
+ sizeof(struct dlm_deref_lockres),
+ dlm_deref_lockres_handler,
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_MIGRATE_REQUEST_MSG, dlm->key,
sizeof(struct dlm_migrate_request),
dlm_migrate_request_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_MIG_LOCKRES_MSG, dlm->key,
DLM_MIG_LOCKRES_MAX_LEN,
dlm_mig_lockres_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_MASTER_REQUERY_MSG, dlm->key,
sizeof(struct dlm_master_requery),
dlm_master_requery_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_LOCK_REQUEST_MSG, dlm->key,
sizeof(struct dlm_lock_request),
dlm_request_all_locks_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_RECO_DATA_DONE_MSG, dlm->key,
sizeof(struct dlm_reco_data_done),
dlm_reco_data_done_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_BEGIN_RECO_MSG, dlm->key,
sizeof(struct dlm_begin_reco),
dlm_begin_reco_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_FINALIZE_RECO_MSG, dlm->key,
sizeof(struct dlm_finalize_reco),
dlm_finalize_reco_handler,
- dlm, &dlm->dlm_domain_handlers);
+ dlm, NULL, &dlm->dlm_domain_handlers);
if (status)
goto bail;
@@ -1141,6 +1264,8 @@ bail:
static int dlm_join_domain(struct dlm_ctxt *dlm)
{
int status;
+ unsigned int backoff;
+ unsigned int total_backoff = 0;
BUG_ON(!dlm);
@@ -1172,18 +1297,27 @@ static int dlm_join_domain(struct dlm_ctxt *dlm)
}
do {
- unsigned int backoff;
status = dlm_try_to_join_domain(dlm);
/* If we're racing another node to the join, then we
* need to back off temporarily and let them
* complete. */
+#define DLM_JOIN_TIMEOUT_MSECS 90000
if (status == -EAGAIN) {
if (signal_pending(current)) {
status = -ERESTARTSYS;
goto bail;
}
+ if (total_backoff >
+ msecs_to_jiffies(DLM_JOIN_TIMEOUT_MSECS)) {
+ status = -ERESTARTSYS;
+ mlog(ML_NOTICE, "Timed out joining dlm domain "
+ "%s after %u msecs\n", dlm->name,
+ jiffies_to_msecs(total_backoff));
+ goto bail;
+ }
+
/*
* <chip> After you!
* <dale> No, after you!
@@ -1193,6 +1327,7 @@ static int dlm_join_domain(struct dlm_ctxt *dlm)
*/
backoff = (unsigned int)(jiffies & 0x3);
backoff *= DLM_DOMAIN_BACKOFF_MS;
+ total_backoff += backoff;
mlog(0, "backoff %d\n", backoff);
msleep(backoff);
}
@@ -1223,7 +1358,7 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain,
int i;
struct dlm_ctxt *dlm = NULL;
- dlm = kcalloc(1, sizeof(*dlm), GFP_KERNEL);
+ dlm = kzalloc(sizeof(*dlm), GFP_KERNEL);
if (!dlm) {
mlog_errno(-ENOMEM);
goto leave;
@@ -1421,21 +1556,21 @@ static int dlm_register_net_handlers(void)
status = o2net_register_handler(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY,
sizeof(struct dlm_query_join_request),
dlm_query_join_handler,
- NULL, &dlm_join_handlers);
+ NULL, NULL, &dlm_join_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_ASSERT_JOINED_MSG, DLM_MOD_KEY,
sizeof(struct dlm_assert_joined),
dlm_assert_joined_handler,
- NULL, &dlm_join_handlers);
+ NULL, NULL, &dlm_join_handlers);
if (status)
goto bail;
status = o2net_register_handler(DLM_CANCEL_JOIN_MSG, DLM_MOD_KEY,
sizeof(struct dlm_cancel_join),
dlm_cancel_join_handler,
- NULL, &dlm_join_handlers);
+ NULL, NULL, &dlm_join_handlers);
bail:
if (status < 0)
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index 941acf14e61..b7f0ba97a1a 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -176,7 +176,7 @@ static ssize_t dlmfs_file_read(struct file *filp,
int bytes_left;
ssize_t readlen;
char *lvb_buf;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
mlog(0, "inode %lu, count = %zu, *ppos = %llu\n",
inode->i_ino, count, *ppos);
@@ -220,7 +220,7 @@ static ssize_t dlmfs_file_write(struct file *filp,
int bytes_left;
ssize_t writelen;
char *lvb_buf;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
mlog(0, "inode %lu, count = %zu, *ppos = %llu\n",
inode->i_ino, count, *ppos);
diff --git a/fs/ocfs2/dlm/dlmlock.c b/fs/ocfs2/dlm/dlmlock.c
index 42a1b91979b..52578d907d9 100644
--- a/fs/ocfs2/dlm/dlmlock.c
+++ b/fs/ocfs2/dlm/dlmlock.c
@@ -163,6 +163,10 @@ static enum dlm_status dlmlock_master(struct dlm_ctxt *dlm,
kick_thread = 1;
}
}
+ /* reduce the inflight count, this may result in the lockres
+ * being purged below during calc_usage */
+ if (lock->ml.node == dlm->node_num)
+ dlm_lockres_drop_inflight_ref(dlm, res);
spin_unlock(&res->spinlock);
wake_up(&res->wq);
@@ -408,13 +412,13 @@ struct dlm_lock * dlm_new_lock(int type, u8 node, u64 cookie,
struct dlm_lock *lock;
int kernel_allocated = 0;
- lock = kcalloc(1, sizeof(*lock), GFP_NOFS);
+ lock = kzalloc(sizeof(*lock), GFP_NOFS);
if (!lock)
return NULL;
if (!lksb) {
/* zero memory only if kernel-allocated */
- lksb = kcalloc(1, sizeof(*lksb), GFP_NOFS);
+ lksb = kzalloc(sizeof(*lksb), GFP_NOFS);
if (!lksb) {
kfree(lock);
return NULL;
@@ -437,7 +441,8 @@ struct dlm_lock * dlm_new_lock(int type, u8 node, u64 cookie,
* held on exit: none
* returns: DLM_NORMAL, DLM_SYSERR, DLM_IVLOCKID, DLM_NOTQUEUED
*/
-int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
struct dlm_create_lock *create = (struct dlm_create_lock *)msg->buf;
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 856012b4fa4..77e4e6169a0 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -99,9 +99,10 @@ static void dlm_mle_node_up(struct dlm_ctxt *dlm,
int idx);
static void dlm_assert_master_worker(struct dlm_work_item *item, void *data);
-static int dlm_do_assert_master(struct dlm_ctxt *dlm, const char *lockname,
- unsigned int namelen, void *nodemap,
- u32 flags);
+static int dlm_do_assert_master(struct dlm_ctxt *dlm,
+ struct dlm_lock_resource *res,
+ void *nodemap, u32 flags);
+static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data);
static inline int dlm_mle_equal(struct dlm_ctxt *dlm,
struct dlm_master_list_entry *mle,
@@ -237,7 +238,8 @@ static int dlm_find_mle(struct dlm_ctxt *dlm,
struct dlm_master_list_entry **mle,
char *name, unsigned int namelen);
-static int dlm_do_master_request(struct dlm_master_list_entry *mle, int to);
+static int dlm_do_master_request(struct dlm_lock_resource *res,
+ struct dlm_master_list_entry *mle, int to);
static int dlm_wait_for_lock_mastery(struct dlm_ctxt *dlm,
@@ -687,6 +689,7 @@ static void dlm_init_lockres(struct dlm_ctxt *dlm,
INIT_LIST_HEAD(&res->purge);
atomic_set(&res->asts_reserved, 0);
res->migration_pending = 0;
+ res->inflight_locks = 0;
kref_init(&res->refs);
@@ -700,6 +703,7 @@ static void dlm_init_lockres(struct dlm_ctxt *dlm,
res->last_used = 0;
memset(res->lvb, 0, DLM_LVB_LEN);
+ memset(res->refmap, 0, sizeof(res->refmap));
}
struct dlm_lock_resource *dlm_new_lockres(struct dlm_ctxt *dlm,
@@ -722,6 +726,42 @@ struct dlm_lock_resource *dlm_new_lockres(struct dlm_ctxt *dlm,
return res;
}
+void __dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm,
+ struct dlm_lock_resource *res,
+ int new_lockres,
+ const char *file,
+ int line)
+{
+ if (!new_lockres)
+ assert_spin_locked(&res->spinlock);
+
+ if (!test_bit(dlm->node_num, res->refmap)) {
+ BUG_ON(res->inflight_locks != 0);
+ dlm_lockres_set_refmap_bit(dlm->node_num, res);
+ }
+ res->inflight_locks++;
+ mlog(0, "%s:%.*s: inflight++: now %u\n",
+ dlm->name, res->lockname.len, res->lockname.name,
+ res->inflight_locks);
+}
+
+void __dlm_lockres_drop_inflight_ref(struct dlm_ctxt *dlm,
+ struct dlm_lock_resource *res,
+ const char *file,
+ int line)
+{
+ assert_spin_locked(&res->spinlock);
+
+ BUG_ON(res->inflight_locks == 0);
+ res->inflight_locks--;
+ mlog(0, "%s:%.*s: inflight--: now %u\n",
+ dlm->name, res->lockname.len, res->lockname.name,
+ res->inflight_locks);
+ if (res->inflight_locks == 0)
+ dlm_lockres_clear_refmap_bit(dlm->node_num, res);
+ wake_up(&res->wq);
+}
+
/*
* lookup a lock resource by name.
* may already exist in the hashtable.
@@ -752,6 +792,7 @@ struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm,
unsigned int hash;
int tries = 0;
int bit, wait_on_recovery = 0;
+ int drop_inflight_if_nonlocal = 0;
BUG_ON(!lockid);
@@ -761,9 +802,30 @@ struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm,
lookup:
spin_lock(&dlm->spinlock);
- tmpres = __dlm_lookup_lockres(dlm, lockid, namelen, hash);
+ tmpres = __dlm_lookup_lockres_full(dlm, lockid, namelen, hash);
if (tmpres) {
+ int dropping_ref = 0;
+
+ spin_lock(&tmpres->spinlock);
+ if (tmpres->owner == dlm->node_num) {
+ BUG_ON(tmpres->state & DLM_LOCK_RES_DROPPING_REF);
+ dlm_lockres_grab_inflight_ref(dlm, tmpres);
+ } else if (tmpres->state & DLM_LOCK_RES_DROPPING_REF)
+ dropping_ref = 1;
+ spin_unlock(&tmpres->spinlock);
spin_unlock(&dlm->spinlock);
+
+ /* wait until done messaging the master, drop our ref to allow
+ * the lockres to be purged, start over. */
+ if (dropping_ref) {
+ spin_lock(&tmpres->spinlock);
+ __dlm_wait_on_lockres_flags(tmpres, DLM_LOCK_RES_DROPPING_REF);
+ spin_unlock(&tmpres->spinlock);
+ dlm_lockres_put(tmpres);
+ tmpres = NULL;
+ goto lookup;
+ }
+
mlog(0, "found in hash!\n");
if (res)
dlm_lockres_put(res);
@@ -793,6 +855,7 @@ lookup:
spin_lock(&res->spinlock);
dlm_change_lockres_owner(dlm, res, dlm->node_num);
__dlm_insert_lockres(dlm, res);
+ dlm_lockres_grab_inflight_ref(dlm, res);
spin_unlock(&res->spinlock);
spin_unlock(&dlm->spinlock);
/* lockres still marked IN_PROGRESS */
@@ -805,29 +868,40 @@ lookup:
/* if we found a block, wait for lock to be mastered by another node */
blocked = dlm_find_mle(dlm, &mle, (char *)lockid, namelen);
if (blocked) {
+ int mig;
if (mle->type == DLM_MLE_MASTER) {
mlog(ML_ERROR, "master entry for nonexistent lock!\n");
BUG();
- } else if (mle->type == DLM_MLE_MIGRATION) {
- /* migration is in progress! */
- /* the good news is that we now know the
- * "current" master (mle->master). */
-
+ }
+ mig = (mle->type == DLM_MLE_MIGRATION);
+ /* if there is a migration in progress, let the migration
+ * finish before continuing. we can wait for the absence
+ * of the MIGRATION mle: either the migrate finished or
+ * one of the nodes died and the mle was cleaned up.
+ * if there is a BLOCK here, but it already has a master
+ * set, we are too late. the master does not have a ref
+ * for us in the refmap. detach the mle and drop it.
+ * either way, go back to the top and start over. */
+ if (mig || mle->master != O2NM_MAX_NODES) {
+ BUG_ON(mig && mle->master == dlm->node_num);
+ /* we arrived too late. the master does not
+ * have a ref for us. retry. */
+ mlog(0, "%s:%.*s: late on %s\n",
+ dlm->name, namelen, lockid,
+ mig ? "MIGRATION" : "BLOCK");
spin_unlock(&dlm->master_lock);
- assert_spin_locked(&dlm->spinlock);
-
- /* set the lockres owner and hash it */
- spin_lock(&res->spinlock);
- dlm_set_lockres_owner(dlm, res, mle->master);
- __dlm_insert_lockres(dlm, res);
- spin_unlock(&res->spinlock);
spin_unlock(&dlm->spinlock);
/* master is known, detach */
- dlm_mle_detach_hb_events(dlm, mle);
+ if (!mig)
+ dlm_mle_detach_hb_events(dlm, mle);
dlm_put_mle(mle);
mle = NULL;
- goto wake_waiters;
+ /* this is lame, but we cant wait on either
+ * the mle or lockres waitqueue here */
+ if (mig)
+ msleep(100);
+ goto lookup;
}
} else {
/* go ahead and try to master lock on this node */
@@ -858,6 +932,13 @@ lookup:
/* finally add the lockres to its hash bucket */
__dlm_insert_lockres(dlm, res);
+ /* since this lockres is new it doesnt not require the spinlock */
+ dlm_lockres_grab_inflight_ref_new(dlm, res);
+
+ /* if this node does not become the master make sure to drop
+ * this inflight reference below */
+ drop_inflight_if_nonlocal = 1;
+
/* get an extra ref on the mle in case this is a BLOCK
* if so, the creator of the BLOCK may try to put the last
* ref at this time in the assert master handler, so we
@@ -910,7 +991,7 @@ redo_request:
ret = -EINVAL;
dlm_node_iter_init(mle->vote_map, &iter);
while ((nodenum = dlm_node_iter_next(&iter)) >= 0) {
- ret = dlm_do_master_request(mle, nodenum);
+ ret = dlm_do_master_request(res, mle, nodenum);
if (ret < 0)
mlog_errno(ret);
if (mle->master != O2NM_MAX_NODES) {
@@ -960,6 +1041,8 @@ wait:
wake_waiters:
spin_lock(&res->spinlock);
+ if (res->owner != dlm->node_num && drop_inflight_if_nonlocal)
+ dlm_lockres_drop_inflight_ref(dlm, res);
res->state &= ~DLM_LOCK_RES_IN_PROGRESS;
spin_unlock(&res->spinlock);
wake_up(&res->wq);
@@ -998,7 +1081,7 @@ recheck:
/* this will cause the master to re-assert across
* the whole cluster, freeing up mles */
if (res->owner != dlm->node_num) {
- ret = dlm_do_master_request(mle, res->owner);
+ ret = dlm_do_master_request(res, mle, res->owner);
if (ret < 0) {
/* give recovery a chance to run */
mlog(ML_ERROR, "link to %u went down?: %d\n", res->owner, ret);
@@ -1062,6 +1145,8 @@ recheck:
* now tell other nodes that I am
* mastering this. */
mle->master = dlm->node_num;
+ /* ref was grabbed in get_lock_resource
+ * will be dropped in dlmlock_master */
assert = 1;
sleep = 0;
}
@@ -1087,7 +1172,8 @@ recheck:
(atomic_read(&mle->woken) == 1),
timeo);
if (res->owner == O2NM_MAX_NODES) {
- mlog(0, "waiting again\n");
+ mlog(0, "%s:%.*s: waiting again\n", dlm->name,
+ res->lockname.len, res->lockname.name);
goto recheck;
}
mlog(0, "done waiting, master is %u\n", res->owner);
@@ -1100,8 +1186,7 @@ recheck:
m = dlm->node_num;
mlog(0, "about to master %.*s here, this=%u\n",
res->lockname.len, res->lockname.name, m);
- ret = dlm_do_assert_master(dlm, res->lockname.name,
- res->lockname.len, mle->vote_map, 0);
+ ret = dlm_do_assert_master(dlm, res, mle->vote_map, 0);
if (ret) {
/* This is a failure in the network path,
* not in the response to the assert_master
@@ -1117,6 +1202,8 @@ recheck:
/* set the lockres owner */
spin_lock(&res->spinlock);
+ /* mastery reference obtained either during
+ * assert_master_handler or in get_lock_resource */
dlm_change_lockres_owner(dlm, res, m);
spin_unlock(&res->spinlock);
@@ -1283,7 +1370,8 @@ static int dlm_restart_lock_mastery(struct dlm_ctxt *dlm,
*
*/
-static int dlm_do_master_request(struct dlm_master_list_entry *mle, int to)
+static int dlm_do_master_request(struct dlm_lock_resource *res,
+ struct dlm_master_list_entry *mle, int to)
{
struct dlm_ctxt *dlm = mle->dlm;
struct dlm_master_request request;
@@ -1339,6 +1427,9 @@ again:
case DLM_MASTER_RESP_YES:
set_bit(to, mle->response_map);
mlog(0, "node %u is the master, response=YES\n", to);
+ mlog(0, "%s:%.*s: master node %u now knows I have a "
+ "reference\n", dlm->name, res->lockname.len,
+ res->lockname.name, to);
mle->master = to;
break;
case DLM_MASTER_RESP_NO:
@@ -1379,7 +1470,8 @@ out:
*
* if possible, TRIM THIS DOWN!!!
*/
-int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
u8 response = DLM_MASTER_RESP_MAYBE;
struct dlm_ctxt *dlm = data;
@@ -1417,10 +1509,11 @@ way_up_top:
/* take care of the easy cases up front */
spin_lock(&res->spinlock);
- if (res->state & DLM_LOCK_RES_RECOVERING) {
+ if (res->state & (DLM_LOCK_RES_RECOVERING|
+ DLM_LOCK_RES_MIGRATING)) {
spin_unlock(&res->spinlock);
mlog(0, "returning DLM_MASTER_RESP_ERROR since res is "
- "being recovered\n");
+ "being recovered/migrated\n");
response = DLM_MASTER_RESP_ERROR;
if (mle)
kmem_cache_free(dlm_mle_cache, mle);
@@ -1428,8 +1521,10 @@ way_up_top:
}
if (res->owner == dlm->node_num) {
+ mlog(0, "%s:%.*s: setting bit %u in refmap\n",
+ dlm->name, namelen, name, request->node_idx);
+ dlm_lockres_set_refmap_bit(request->node_idx, res);
spin_unlock(&res->spinlock);
- // mlog(0, "this node is the master\n");
response = DLM_MASTER_RESP_YES;
if (mle)
kmem_cache_free(dlm_mle_cache, mle);
@@ -1477,7 +1572,6 @@ way_up_top:
mlog(0, "node %u is master, but trying to migrate to "
"node %u.\n", tmpmle->master, tmpmle->new_master);
if (tmpmle->master == dlm->node_num) {
- response = DLM_MASTER_RESP_YES;
mlog(ML_ERROR, "no owner on lockres, but this "
"node is trying to migrate it to %u?!\n",
tmpmle->new_master);
@@ -1494,6 +1588,10 @@ way_up_top:
* go back and clean the mles on any
* other nodes */
dispatch_assert = 1;
+ dlm_lockres_set_refmap_bit(request->node_idx, res);
+ mlog(0, "%s:%.*s: setting bit %u in refmap\n",
+ dlm->name, namelen, name,
+ request->node_idx);
} else
response = DLM_MASTER_RESP_NO;
} else {
@@ -1607,17 +1705,24 @@ send_response:
* can periodically run all locks owned by this node
* and re-assert across the cluster...
*/
-static int dlm_do_assert_master(struct dlm_ctxt *dlm, const char *lockname,
- unsigned int namelen, void *nodemap,
- u32 flags)
+int dlm_do_assert_master(struct dlm_ctxt *dlm,
+ struct dlm_lock_resource *res,
+ void *nodemap, u32 flags)
{
struct dlm_assert_master assert;
int to, tmpret;
struct dlm_node_iter iter;
int ret = 0;
int reassert;
+ const char *lockname = res->lockname.name;
+ unsigned int namelen = res->lockname.len;
BUG_ON(namelen > O2NM_MAX_NAME_LEN);
+
+ spin_lock(&res->spinlock);
+ res->state |= DLM_LOCK_RES_SETREF_INPROG;
+ spin_unlock(&res->spinlock);
+
again:
reassert = 0;
@@ -1647,6 +1752,7 @@ again:
mlog(0, "link to %d went down!\n", to);
/* any nonzero status return will do */
ret = tmpret;
+ r = 0;
} else if (r < 0) {
/* ok, something horribly messed. kill thyself. */
mlog(ML_ERROR,"during assert master of %.*s to %u, "
@@ -1661,17 +1767,39 @@ again:
spin_unlock(&dlm->master_lock);
spin_unlock(&dlm->spinlock);
BUG();
- } else if (r == EAGAIN) {
+ }
+
+ if (r & DLM_ASSERT_RESPONSE_REASSERT &&
+ !(r & DLM_ASSERT_RESPONSE_MASTERY_REF)) {
+ mlog(ML_ERROR, "%.*s: very strange, "
+ "master MLE but no lockres on %u\n",
+ namelen, lockname, to);
+ }
+
+ if (r & DLM_ASSERT_RESPONSE_REASSERT) {
mlog(0, "%.*s: node %u create mles on other "
"nodes and requests a re-assert\n",
namelen, lockname, to);
reassert = 1;
}
+ if (r & DLM_ASSERT_RESPONSE_MASTERY_REF) {
+ mlog(0, "%.*s: node %u has a reference to this "
+ "lockres, set the bit in the refmap\n",
+ namelen, lockname, to);
+ spin_lock(&res->spinlock);
+ dlm_lockres_set_refmap_bit(to, res);
+ spin_unlock(&res->spinlock);
+ }
}
if (reassert)
goto again;
+ spin_lock(&res->spinlock);
+ res->state &= ~DLM_LOCK_RES_SETREF_INPROG;
+ spin_unlock(&res->spinlock);
+ wake_up(&res->wq);
+
return ret;
}
@@ -1684,7 +1812,8 @@ again:
*
* if possible, TRIM THIS DOWN!!!
*/
-int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
struct dlm_master_list_entry *mle = NULL;
@@ -1693,7 +1822,7 @@ int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data)
char *name;
unsigned int namelen, hash;
u32 flags;
- int master_request = 0;
+ int master_request = 0, have_lockres_ref = 0;
int ret = 0;
if (!dlm_grab(dlm))
@@ -1851,6 +1980,7 @@ ok:
spin_unlock(&mle->spinlock);
if (res) {
+ int wake = 0;
spin_lock(&res->spinlock);
if (mle->type == DLM_MLE_MIGRATION) {
mlog(0, "finishing off migration of lockres %.*s, "
@@ -1858,12 +1988,16 @@ ok:
res->lockname.len, res->lockname.name,
dlm->node_num, mle->new_master);
res->state &= ~DLM_LOCK_RES_MIGRATING;
+ wake = 1;
dlm_change_lockres_owner(dlm, res, mle->new_master);
BUG_ON(res->state & DLM_LOCK_RES_DIRTY);
} else {
dlm_change_lockres_owner(dlm, res, mle->master);
}
spin_unlock(&res->spinlock);
+ have_lockres_ref = 1;
+ if (wake)
+ wake_up(&res->wq);
}
/* master is known, detach if not already detached.
@@ -1913,12 +2047,28 @@ ok:
done:
ret = 0;
- if (res)
- dlm_lockres_put(res);
+ if (res) {
+ spin_lock(&res->spinlock);
+ res->state |= DLM_LOCK_RES_SETREF_INPROG;
+ spin_unlock(&res->spinlock);
+ *ret_data = (void *)res;
+ }
dlm_put(dlm);
if (master_request) {
mlog(0, "need to tell master to reassert\n");
- ret = EAGAIN; // positive. negative would shoot down the node.
+ /* positive. negative would shoot down the node. */
+ ret |= DLM_ASSERT_RESPONSE_REASSERT;
+ if (!have_lockres_ref) {
+ mlog(ML_ERROR, "strange, got assert from %u, MASTER "
+ "mle present here for %s:%.*s, but no lockres!\n",
+ assert->node_idx, dlm->name, namelen, name);
+ }
+ }
+ if (have_lockres_ref) {
+ /* let the master know we have a reference to the lockres */
+ ret |= DLM_ASSERT_RESPONSE_MASTERY_REF;
+ mlog(0, "%s:%.*s: got assert from %u, need a ref\n",
+ dlm->name, namelen, name, assert->node_idx);
}
return ret;
@@ -1929,17 +2079,31 @@ kill:
__dlm_print_one_lock_resource(res);
spin_unlock(&res->spinlock);
spin_unlock(&dlm->spinlock);
- dlm_lockres_put(res);
+ *ret_data = (void *)res;
dlm_put(dlm);
return -EINVAL;
}
+void dlm_assert_master_post_handler(int status, void *data, void *ret_data)
+{
+ struct dlm_lock_resource *res = (struct dlm_lock_resource *)ret_data;
+
+ if (ret_data) {
+ spin_lock(&res->spinlock);
+ res->state &= ~DLM_LOCK_RES_SETREF_INPROG;
+ spin_unlock(&res->spinlock);
+ wake_up(&res->wq);
+ dlm_lockres_put(res);
+ }
+ return;
+}
+
int dlm_dispatch_assert_master(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res,
int ignore_higher, u8 request_from, u32 flags)
{
struct dlm_work_item *item;
- item = kcalloc(1, sizeof(*item), GFP_NOFS);
+ item = kzalloc(sizeof(*item), GFP_NOFS);
if (!item)
return -ENOMEM;
@@ -2023,9 +2187,7 @@ static void dlm_assert_master_worker(struct dlm_work_item *item, void *data)
* even if one or more nodes die */
mlog(0, "worker about to master %.*s here, this=%u\n",
res->lockname.len, res->lockname.name, dlm->node_num);
- ret = dlm_do_assert_master(dlm, res->lockname.name,
- res->lockname.len,
- nodemap, flags);
+ ret = dlm_do_assert_master(dlm, res, nodemap, flags);
if (ret < 0) {
/* no need to restart, we are done */
if (!dlm_is_host_down(ret))
@@ -2097,14 +2259,180 @@ static int dlm_pre_master_reco_lockres(struct dlm_ctxt *dlm,
return ret;
}
+/*
+ * DLM_DEREF_LOCKRES_MSG
+ */
+
+int dlm_drop_lockres_ref(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
+{
+ struct dlm_deref_lockres deref;
+ int ret = 0, r;
+ const char *lockname;
+ unsigned int namelen;
+
+ lockname = res->lockname.name;
+ namelen = res->lockname.len;
+ BUG_ON(namelen > O2NM_MAX_NAME_LEN);
+
+ mlog(0, "%s:%.*s: sending deref to %d\n",
+ dlm->name, namelen, lockname, res->owner);
+ memset(&deref, 0, sizeof(deref));
+ deref.node_idx = dlm->node_num;
+ deref.namelen = namelen;
+ memcpy(deref.name, lockname, namelen);
+
+ ret = o2net_send_message(DLM_DEREF_LOCKRES_MSG, dlm->key,
+ &deref, sizeof(deref), res->owner, &r);
+ if (ret < 0)
+ mlog_errno(ret);
+ else if (r < 0) {
+ /* BAD. other node says I did not have a ref. */
+ mlog(ML_ERROR,"while dropping ref on %s:%.*s "
+ "(master=%u) got %d.\n", dlm->name, namelen,
+ lockname, res->owner, r);
+ dlm_print_one_lock_resource(res);
+ BUG();
+ }
+ return ret;
+}
+
+int dlm_deref_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
+{
+ struct dlm_ctxt *dlm = data;
+ struct dlm_deref_lockres *deref = (struct dlm_deref_lockres *)msg->buf;
+ struct dlm_lock_resource *res = NULL;
+ char *name;
+ unsigned int namelen;
+ int ret = -EINVAL;
+ u8 node;
+ unsigned int hash;
+ struct dlm_work_item *item;
+ int cleared = 0;
+ int dispatch = 0;
+
+ if (!dlm_grab(dlm))
+ return 0;
+
+ name = deref->name;
+ namelen = deref->namelen;
+ node = deref->node_idx;
+
+ if (namelen > DLM_LOCKID_NAME_MAX) {
+ mlog(ML_ERROR, "Invalid name length!");
+ goto done;
+ }
+ if (deref->node_idx >= O2NM_MAX_NODES) {
+ mlog(ML_ERROR, "Invalid node number: %u\n", node);
+ goto done;
+ }
+
+ hash = dlm_lockid_hash(name, namelen);
+
+ spin_lock(&dlm->spinlock);
+ res = __dlm_lookup_lockres_full(dlm, name, namelen, hash);
+ if (!res) {
+ spin_unlock(&dlm->spinlock);
+ mlog(ML_ERROR, "%s:%.*s: bad lockres name\n",
+ dlm->name, namelen, name);
+ goto done;
+ }
+ spin_unlock(&dlm->spinlock);
+
+ spin_lock(&res->spinlock);
+ if (res->state & DLM_LOCK_RES_SETREF_INPROG)
+ dispatch = 1;
+ else {
+ BUG_ON(res->state & DLM_LOCK_RES_DROPPING_REF);
+ if (test_bit(node, res->refmap)) {
+ dlm_lockres_clear_refmap_bit(node, res);
+ cleared = 1;
+ }
+ }
+ spin_unlock(&res->spinlock);
+
+ if (!dispatch) {
+ if (cleared)
+ dlm_lockres_calc_usage(dlm, res);
+ else {
+ mlog(ML_ERROR, "%s:%.*s: node %u trying to drop ref "
+ "but it is already dropped!\n", dlm->name,
+ res->lockname.len, res->lockname.name, node);
+ __dlm_print_one_lock_resource(res);
+ }
+ ret = 0;
+ goto done;
+ }
+
+ item = kzalloc(sizeof(*item), GFP_NOFS);
+ if (!item) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto done;
+ }
+
+ dlm_init_work_item(dlm, item, dlm_deref_lockres_worker, NULL);
+ item->u.dl.deref_res = res;
+ item->u.dl.deref_node = node;
+
+ spin_lock(&dlm->work_lock);
+ list_add_tail(&item->list, &dlm->work_list);
+ spin_unlock(&dlm->work_lock);
+
+ queue_work(dlm->dlm_worker, &dlm->dispatched_work);
+ return 0;
+
+done:
+ if (res)
+ dlm_lockres_put(res);
+ dlm_put(dlm);
+
+ return ret;
+}
+
+static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data)
+{
+ struct dlm_ctxt *dlm;
+ struct dlm_lock_resource *res;
+ u8 node;
+ u8 cleared = 0;
+
+ dlm = item->dlm;
+ res = item->u.dl.deref_res;
+ node = item->u.dl.deref_node;
+
+ spin_lock(&res->spinlock);
+ BUG_ON(res->state & DLM_LOCK_RES_DROPPING_REF);
+ if (test_bit(node, res->refmap)) {
+ __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG);
+ dlm_lockres_clear_refmap_bit(node, res);
+ cleared = 1;
+ }
+ spin_unlock(&res->spinlock);
+
+ if (cleared) {
+ mlog(0, "%s:%.*s node %u ref dropped in dispatch\n",
+ dlm->name, res->lockname.len, res->lockname.name, node);
+ dlm_lockres_calc_usage(dlm, res);
+ } else {
+ mlog(ML_ERROR, "%s:%.*s: node %u trying to drop ref "
+ "but it is already dropped!\n", dlm->name,
+ res->lockname.len, res->lockname.name, node);
+ __dlm_print_one_lock_resource(res);
+ }
+
+ dlm_lockres_put(res);
+}
+
/*
* DLM_MIGRATE_LOCKRES
*/
-int dlm_migrate_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
- u8 target)
+static int dlm_migrate_lockres(struct dlm_ctxt *dlm,
+ struct dlm_lock_resource *res,
+ u8 target)
{
struct dlm_master_list_entry *mle = NULL;
struct dlm_master_list_entry *oldmle = NULL;
@@ -2116,7 +2444,7 @@ int dlm_migrate_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
struct list_head *queue, *iter;
int i;
struct dlm_lock *lock;
- int empty = 1;
+ int empty = 1, wake = 0;
if (!dlm_grab(dlm))
return -EINVAL;
@@ -2241,6 +2569,7 @@ int dlm_migrate_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
res->lockname.name, target);
spin_lock(&res->spinlock);
res->state &= ~DLM_LOCK_RES_MIGRATING;
+ wake = 1;
spin_unlock(&res->spinlock);
ret = -EINVAL;
}
@@ -2268,6 +2597,9 @@ fail:
* the lockres
*/
+ /* now that remote nodes are spinning on the MIGRATING flag,
+ * ensure that all assert_master work is flushed. */
+ flush_workqueue(dlm->dlm_worker);
/* get an extra reference on the mle.
* otherwise the assert_master from the new
@@ -2296,6 +2628,7 @@ fail:
dlm_put_mle_inuse(mle);
spin_lock(&res->spinlock);
res->state &= ~DLM_LOCK_RES_MIGRATING;
+ wake = 1;
spin_unlock(&res->spinlock);
goto leave;
}
@@ -2322,7 +2655,8 @@ fail:
res->owner == target)
break;
- mlog(0, "timed out during migration\n");
+ mlog(0, "%s:%.*s: timed out during migration\n",
+ dlm->name, res->lockname.len, res->lockname.name);
/* avoid hang during shutdown when migrating lockres
* to a node which also goes down */
if (dlm_is_node_dead(dlm, target)) {
@@ -2330,20 +2664,20 @@ fail:
"target %u is no longer up, restarting\n",
dlm->name, res->lockname.len,
res->lockname.name, target);
- ret = -ERESTARTSYS;
+ ret = -EINVAL;
+ /* migration failed, detach and clean up mle */
+ dlm_mle_detach_hb_events(dlm, mle);
+ dlm_put_mle(mle);
+ dlm_put_mle_inuse(mle);
+ spin_lock(&res->spinlock);
+ res->state &= ~DLM_LOCK_RES_MIGRATING;
+ wake = 1;
+ spin_unlock(&res->spinlock);
+ goto leave;
}
- }
- if (ret == -ERESTARTSYS) {
- /* migration failed, detach and clean up mle */
- dlm_mle_detach_hb_events(dlm, mle);
- dlm_put_mle(mle);
- dlm_put_mle_inuse(mle);
- spin_lock(&res->spinlock);
- res->state &= ~DLM_LOCK_RES_MIGRATING;
- spin_unlock(&res->spinlock);
- goto leave;
- }
- /* TODO: if node died: stop, clean up, return error */
+ } else
+ mlog(0, "%s:%.*s: caught signal during migration\n",
+ dlm->name, res->lockname.len, res->lockname.name);
}
/* all done, set the owner, clear the flag */
@@ -2366,6 +2700,11 @@ leave:
if (ret < 0)
dlm_kick_thread(dlm, res);
+ /* wake up waiters if the MIGRATING flag got set
+ * but migration failed */
+ if (wake)
+ wake_up(&res->wq);
+
/* TODO: cleanup */
if (mres)
free_page((unsigned long)mres);
@@ -2376,6 +2715,53 @@ leave:
return ret;
}
+#define DLM_MIGRATION_RETRY_MS 100
+
+/* Should be called only after beginning the domain leave process.
+ * There should not be any remaining locks on nonlocal lock resources,
+ * and there should be no local locks left on locally mastered resources.
+ *
+ * Called with the dlm spinlock held, may drop it to do migration, but
+ * will re-acquire before exit.
+ *
+ * Returns: 1 if dlm->spinlock was dropped/retaken, 0 if never dropped */
+int dlm_empty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
+{
+ int ret;
+ int lock_dropped = 0;
+
+ if (res->owner != dlm->node_num) {
+ if (!__dlm_lockres_unused(res)) {
+ mlog(ML_ERROR, "%s:%.*s: this node is not master, "
+ "trying to free this but locks remain\n",
+ dlm->name, res->lockname.len, res->lockname.name);
+ }
+ goto leave;
+ }
+
+ /* Wheee! Migrate lockres here! Will sleep so drop spinlock. */
+ spin_unlock(&dlm->spinlock);
+ lock_dropped = 1;
+ while (1) {
+ ret = dlm_migrate_lockres(dlm, res, O2NM_MAX_NODES);
+ if (ret >= 0)
+ break;
+ if (ret == -ENOTEMPTY) {
+ mlog(ML_ERROR, "lockres %.*s still has local locks!\n",
+ res->lockname.len, res->lockname.name);
+ BUG();
+ }
+
+ mlog(0, "lockres %.*s: migrate failed, "
+ "retrying\n", res->lockname.len,
+ res->lockname.name);
+ msleep(DLM_MIGRATION_RETRY_MS);
+ }
+ spin_lock(&dlm->spinlock);
+leave:
+ return lock_dropped;
+}
+
int dlm_lock_basts_flushed(struct dlm_ctxt *dlm, struct dlm_lock *lock)
{
int ret;
@@ -2405,7 +2791,8 @@ static int dlm_migration_can_proceed(struct dlm_ctxt *dlm,
return can_proceed;
}
-int dlm_lockres_is_dirty(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
+static int dlm_lockres_is_dirty(struct dlm_ctxt *dlm,
+ struct dlm_lock_resource *res)
{
int ret;
spin_lock(&res->spinlock);
@@ -2434,8 +2821,15 @@ static int dlm_mark_lockres_migrating(struct dlm_ctxt *dlm,
__dlm_lockres_reserve_ast(res);
spin_unlock(&res->spinlock);
- /* now flush all the pending asts.. hang out for a bit */
+ /* now flush all the pending asts */
dlm_kick_thread(dlm, res);
+ /* before waiting on DIRTY, block processes which may
+ * try to dirty the lockres before MIGRATING is set */
+ spin_lock(&res->spinlock);
+ BUG_ON(res->state & DLM_LOCK_RES_BLOCK_DIRTY);
+ res->state |= DLM_LOCK_RES_BLOCK_DIRTY;
+ spin_unlock(&res->spinlock);
+ /* now wait on any pending asts and the DIRTY state */
wait_event(dlm->ast_wq, !dlm_lockres_is_dirty(dlm, res));
dlm_lockres_release_ast(dlm, res);
@@ -2461,6 +2855,13 @@ again:
mlog(0, "trying again...\n");
goto again;
}
+ /* now that we are sure the MIGRATING state is there, drop
+ * the unneded state which blocked threads trying to DIRTY */
+ spin_lock(&res->spinlock);
+ BUG_ON(!(res->state & DLM_LOCK_RES_BLOCK_DIRTY));
+ BUG_ON(!(res->state & DLM_LOCK_RES_MIGRATING));
+ res->state &= ~DLM_LOCK_RES_BLOCK_DIRTY;
+ spin_unlock(&res->spinlock);
/* did the target go down or die? */
spin_lock(&dlm->spinlock);
@@ -2490,7 +2891,7 @@ static void dlm_remove_nonlocal_locks(struct dlm_ctxt *dlm,
{
struct list_head *iter, *iter2;
struct list_head *queue = &res->granted;
- int i;
+ int i, bit;
struct dlm_lock *lock;
assert_spin_locked(&res->spinlock);
@@ -2508,12 +2909,28 @@ static void dlm_remove_nonlocal_locks(struct dlm_ctxt *dlm,
BUG_ON(!list_empty(&lock->bast_list));
BUG_ON(lock->ast_pending);
BUG_ON(lock->bast_pending);
+ dlm_lockres_clear_refmap_bit(lock->ml.node, res);
list_del_init(&lock->list);
dlm_lock_put(lock);
}
}
queue++;
}
+ bit = 0;
+ while (1) {
+ bit = find_next_bit(res->refmap, O2NM_MAX_NODES, bit);
+ if (bit >= O2NM_MAX_NODES)
+ break;
+ /* do not clear the local node reference, if there is a
+ * process holding this, let it drop the ref itself */
+ if (bit != dlm->node_num) {
+ mlog(0, "%s:%.*s: node %u had a ref to this "
+ "migrating lockres, clearing\n", dlm->name,
+ res->lockname.len, res->lockname.name, bit);
+ dlm_lockres_clear_refmap_bit(bit, res);
+ }
+ bit++;
+ }
}
/* for now this is not too intelligent. we will
@@ -2601,6 +3018,16 @@ static int dlm_do_migrate_request(struct dlm_ctxt *dlm,
mlog(0, "migrate request (node %u) returned %d!\n",
nodenum, status);
ret = status;
+ } else if (status == DLM_MIGRATE_RESPONSE_MASTERY_REF) {
+ /* during the migration request we short-circuited
+ * the mastery of the lockres. make sure we have
+ * a mastery ref for nodenum */
+ mlog(0, "%s:%.*s: need ref for node %u\n",
+ dlm->name, res->lockname.len, res->lockname.name,
+ nodenum);
+ spin_lock(&res->spinlock);
+ dlm_lockres_set_refmap_bit(nodenum, res);
+ spin_unlock(&res->spinlock);
}
}
@@ -2619,7 +3046,8 @@ static int dlm_do_migrate_request(struct dlm_ctxt *dlm,
* we will have no mle in the list to start with. now we can add an mle for
* the migration and this should be the only one found for those scanning the
* list. */
-int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
struct dlm_lock_resource *res = NULL;
@@ -2745,7 +3173,13 @@ static int dlm_add_migration_mle(struct dlm_ctxt *dlm,
/* remove it from the list so that only one
* mle will be found */
list_del_init(&tmp->list);
- __dlm_mle_detach_hb_events(dlm, mle);
+ /* this was obviously WRONG. mle is uninited here. should be tmp. */
+ __dlm_mle_detach_hb_events(dlm, tmp);
+ ret = DLM_MIGRATE_RESPONSE_MASTERY_REF;
+ mlog(0, "%s:%.*s: master=%u, newmaster=%u, "
+ "telling master to get ref for cleared out mle "
+ "during migration\n", dlm->name, namelen, name,
+ master, new_master);
}
spin_unlock(&tmp->spinlock);
}
@@ -2753,6 +3187,8 @@ static int dlm_add_migration_mle(struct dlm_ctxt *dlm,
/* now add a migration mle to the tail of the list */
dlm_init_mle(mle, DLM_MLE_MIGRATION, dlm, res, name, namelen);
mle->new_master = new_master;
+ /* the new master will be sending an assert master for this.
+ * at that point we will get the refmap reference */
mle->master = master;
/* do this for consistency with other mle types */
set_bit(new_master, mle->maybe_map);
@@ -2902,6 +3338,13 @@ int dlm_finish_migration(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
clear_bit(dlm->node_num, iter.node_map);
spin_unlock(&dlm->spinlock);
+ /* ownership of the lockres is changing. account for the
+ * mastery reference here since old_master will briefly have
+ * a reference after the migration completes */
+ spin_lock(&res->spinlock);
+ dlm_lockres_set_refmap_bit(old_master, res);
+ spin_unlock(&res->spinlock);
+
mlog(0, "now time to do a migrate request to other nodes\n");
ret = dlm_do_migrate_request(dlm, res, old_master,
dlm->node_num, &iter);
@@ -2914,8 +3357,7 @@ int dlm_finish_migration(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
res->lockname.len, res->lockname.name);
/* this call now finishes out the nodemap
* even if one or more nodes die */
- ret = dlm_do_assert_master(dlm, res->lockname.name,
- res->lockname.len, iter.node_map,
+ ret = dlm_do_assert_master(dlm, res, iter.node_map,
DLM_ASSERT_MASTER_FINISH_MIGRATION);
if (ret < 0) {
/* no longer need to retry. all living nodes contacted. */
@@ -2927,8 +3369,7 @@ int dlm_finish_migration(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
set_bit(old_master, iter.node_map);
mlog(0, "doing assert master of %.*s back to %u\n",
res->lockname.len, res->lockname.name, old_master);
- ret = dlm_do_assert_master(dlm, res->lockname.name,
- res->lockname.len, iter.node_map,
+ ret = dlm_do_assert_master(dlm, res, iter.node_map,
DLM_ASSERT_MASTER_FINISH_MIGRATION);
if (ret < 0) {
mlog(0, "assert master to original master failed "
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index fb3e2b0817f..6d4a83d5015 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -163,9 +163,6 @@ void dlm_dispatch_work(struct work_struct *work)
dlm_workfunc_t *workfunc;
int tot=0;
- if (!dlm_joined(dlm))
- return;
-
spin_lock(&dlm->work_lock);
list_splice_init(&dlm->work_list, &tmp_list);
spin_unlock(&dlm->work_lock);
@@ -757,7 +754,7 @@ static int dlm_init_recovery_area(struct dlm_ctxt *dlm, u8 dead_node)
}
BUG_ON(num == dead_node);
- ndata = kcalloc(1, sizeof(*ndata), GFP_NOFS);
+ ndata = kzalloc(sizeof(*ndata), GFP_NOFS);
if (!ndata) {
dlm_destroy_recovery_area(dlm, dead_node);
return -ENOMEM;
@@ -821,7 +818,8 @@ static int dlm_request_all_locks(struct dlm_ctxt *dlm, u8 request_from,
}
-int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
struct dlm_lock_request *lr = (struct dlm_lock_request *)msg->buf;
@@ -842,7 +840,7 @@ int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data)
}
BUG_ON(lr->dead_node != dlm->reco.dead_node);
- item = kcalloc(1, sizeof(*item), GFP_NOFS);
+ item = kzalloc(sizeof(*item), GFP_NOFS);
if (!item) {
dlm_put(dlm);
return -ENOMEM;
@@ -978,7 +976,8 @@ static int dlm_send_all_done_msg(struct dlm_ctxt *dlm, u8 dead_node, u8 send_to)
}
-int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
struct dlm_reco_data_done *done = (struct dlm_reco_data_done *)msg->buf;
@@ -1129,6 +1128,11 @@ static int dlm_send_mig_lockres_msg(struct dlm_ctxt *dlm,
if (total_locks == mres_total_locks)
mres->flags |= DLM_MRES_ALL_DONE;
+ mlog(0, "%s:%.*s: sending mig lockres (%s) to %u\n",
+ dlm->name, res->lockname.len, res->lockname.name,
+ orig_flags & DLM_MRES_MIGRATION ? "migrate" : "recovery",
+ send_to);
+
/* send it */
ret = o2net_send_message(DLM_MIG_LOCKRES_MSG, dlm->key, mres,
sz, send_to, &status);
@@ -1213,6 +1217,34 @@ static int dlm_add_lock_to_array(struct dlm_lock *lock,
return 0;
}
+static void dlm_add_dummy_lock(struct dlm_ctxt *dlm,
+ struct dlm_migratable_lockres *mres)
+{
+ struct dlm_lock dummy;
+ memset(&dummy, 0, sizeof(dummy));
+ dummy.ml.cookie = 0;
+ dummy.ml.type = LKM_IVMODE;
+ dummy.ml.convert_type = LKM_IVMODE;
+ dummy.ml.highest_blocked = LKM_IVMODE;
+ dummy.lksb = NULL;
+ dummy.ml.node = dlm->node_num;
+ dlm_add_lock_to_array(&dummy, mres, DLM_BLOCKED_LIST);
+}
+
+static inline int dlm_is_dummy_lock(struct dlm_ctxt *dlm,
+ struct dlm_migratable_lock *ml,
+ u8 *nodenum)
+{
+ if (unlikely(ml->cookie == 0 &&
+ ml->type == LKM_IVMODE &&
+ ml->convert_type == LKM_IVMODE &&
+ ml->highest_blocked == LKM_IVMODE &&
+ ml->list == DLM_BLOCKED_LIST)) {
+ *nodenum = ml->node;
+ return 1;
+ }
+ return 0;
+}
int dlm_send_one_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
struct dlm_migratable_lockres *mres,
@@ -1260,6 +1292,14 @@ int dlm_send_one_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
goto error;
}
}
+ if (total_locks == 0) {
+ /* send a dummy lock to indicate a mastery reference only */
+ mlog(0, "%s:%.*s: sending dummy lock to %u, %s\n",
+ dlm->name, res->lockname.len, res->lockname.name,
+ send_to, flags & DLM_MRES_RECOVERY ? "recovery" :
+ "migration");
+ dlm_add_dummy_lock(dlm, mres);
+ }
/* flush any remaining locks */
ret = dlm_send_mig_lockres_msg(dlm, mres, send_to, res, total_locks);
if (ret < 0)
@@ -1293,7 +1333,8 @@ error:
* do we spin? returning an error only delays the problem really
*/
-int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
struct dlm_migratable_lockres *mres =
@@ -1323,7 +1364,7 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data)
ret = -ENOMEM;
buf = kmalloc(be16_to_cpu(msg->data_len), GFP_NOFS);
- item = kcalloc(1, sizeof(*item), GFP_NOFS);
+ item = kzalloc(sizeof(*item), GFP_NOFS);
if (!buf || !item)
goto leave;
@@ -1382,17 +1423,21 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data)
spin_lock(&res->spinlock);
res->state &= ~DLM_LOCK_RES_IN_PROGRESS;
spin_unlock(&res->spinlock);
+ wake_up(&res->wq);
/* add an extra ref for just-allocated lockres
* otherwise the lockres will be purged immediately */
dlm_lockres_get(res);
-
}
/* at this point we have allocated everything we need,
* and we have a hashed lockres with an extra ref and
* the proper res->state flags. */
ret = 0;
+ spin_lock(&res->spinlock);
+ /* drop this either when master requery finds a different master
+ * or when a lock is added by the recovery worker */
+ dlm_lockres_grab_inflight_ref(dlm, res);
if (mres->master == DLM_LOCK_RES_OWNER_UNKNOWN) {
/* migration cannot have an unknown master */
BUG_ON(!(mres->flags & DLM_MRES_RECOVERY));
@@ -1400,10 +1445,11 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data)
"unknown owner.. will need to requery: "
"%.*s\n", mres->lockname_len, mres->lockname);
} else {
- spin_lock(&res->spinlock);
+ /* take a reference now to pin the lockres, drop it
+ * when locks are added in the worker */
dlm_change_lockres_owner(dlm, res, dlm->node_num);
- spin_unlock(&res->spinlock);
}
+ spin_unlock(&res->spinlock);
/* queue up work for dlm_mig_lockres_worker */
dlm_grab(dlm); /* get an extra ref for the work item */
@@ -1459,6 +1505,9 @@ again:
"this node will take it.\n",
res->lockname.len, res->lockname.name);
} else {
+ spin_lock(&res->spinlock);
+ dlm_lockres_drop_inflight_ref(dlm, res);
+ spin_unlock(&res->spinlock);
mlog(0, "master needs to respond to sender "
"that node %u still owns %.*s\n",
real_master, res->lockname.len,
@@ -1578,7 +1627,8 @@ int dlm_do_master_requery(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
/* this function cannot error, so unless the sending
* or receiving of the message failed, the owner can
* be trusted */
-int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
struct dlm_master_requery *req = (struct dlm_master_requery *)msg->buf;
@@ -1660,21 +1710,38 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
{
struct dlm_migratable_lock *ml;
struct list_head *queue;
+ struct list_head *tmpq = NULL;
struct dlm_lock *newlock = NULL;
struct dlm_lockstatus *lksb = NULL;
int ret = 0;
- int i, bad;
+ int i, j, bad;
struct list_head *iter;
struct dlm_lock *lock = NULL;
+ u8 from = O2NM_MAX_NODES;
+ unsigned int added = 0;
mlog(0, "running %d locks for this lockres\n", mres->num_locks);
for (i=0; i<mres->num_locks; i++) {
ml = &(mres->ml[i]);
+
+ if (dlm_is_dummy_lock(dlm, ml, &from)) {
+ /* placeholder, just need to set the refmap bit */
+ BUG_ON(mres->num_locks != 1);
+ mlog(0, "%s:%.*s: dummy lock for %u\n",
+ dlm->name, mres->lockname_len, mres->lockname,
+ from);
+ spin_lock(&res->spinlock);
+ dlm_lockres_set_refmap_bit(from, res);
+ spin_unlock(&res->spinlock);
+ added++;
+ break;
+ }
BUG_ON(ml->highest_blocked != LKM_IVMODE);
newlock = NULL;
lksb = NULL;
queue = dlm_list_num_to_pointer(res, ml->list);
+ tmpq = NULL;
/* if the lock is for the local node it needs to
* be moved to the proper location within the queue.
@@ -1684,11 +1751,16 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
BUG_ON(!(mres->flags & DLM_MRES_MIGRATION));
spin_lock(&res->spinlock);
- list_for_each(iter, queue) {
- lock = list_entry (iter, struct dlm_lock, list);
- if (lock->ml.cookie != ml->cookie)
- lock = NULL;
- else
+ for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) {
+ tmpq = dlm_list_idx_to_ptr(res, j);
+ list_for_each(iter, tmpq) {
+ lock = list_entry (iter, struct dlm_lock, list);
+ if (lock->ml.cookie != ml->cookie)
+ lock = NULL;
+ else
+ break;
+ }
+ if (lock)
break;
}
@@ -1698,12 +1770,20 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
u64 c = ml->cookie;
mlog(ML_ERROR, "could not find local lock "
"with cookie %u:%llu!\n",
- dlm_get_lock_cookie_node(c),
- dlm_get_lock_cookie_seq(c));
+ dlm_get_lock_cookie_node(be64_to_cpu(c)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(c)));
+ __dlm_print_one_lock_resource(res);
BUG();
}
BUG_ON(lock->ml.node != ml->node);
+ if (tmpq != queue) {
+ mlog(0, "lock was on %u instead of %u for %.*s\n",
+ j, ml->list, res->lockname.len, res->lockname.name);
+ spin_unlock(&res->spinlock);
+ continue;
+ }
+
/* see NOTE above about why we do not update
* to match the master here */
@@ -1711,6 +1791,7 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
/* do not alter lock refcount. switching lists. */
list_move_tail(&lock->list, queue);
spin_unlock(&res->spinlock);
+ added++;
mlog(0, "just reordered a local lock!\n");
continue;
@@ -1799,14 +1880,14 @@ skip_lvb:
mlog(ML_ERROR, "%s:%.*s: %u:%llu: lock already "
"exists on this lockres!\n", dlm->name,
res->lockname.len, res->lockname.name,
- dlm_get_lock_cookie_node(c),
- dlm_get_lock_cookie_seq(c));
+ dlm_get_lock_cookie_node(be64_to_cpu(c)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(c)));
mlog(ML_NOTICE, "sent lock: type=%d, conv=%d, "
"node=%u, cookie=%u:%llu, queue=%d\n",
ml->type, ml->convert_type, ml->node,
- dlm_get_lock_cookie_node(ml->cookie),
- dlm_get_lock_cookie_seq(ml->cookie),
+ dlm_get_lock_cookie_node(be64_to_cpu(ml->cookie)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(ml->cookie)),
ml->list);
__dlm_print_one_lock_resource(res);
@@ -1817,12 +1898,22 @@ skip_lvb:
if (!bad) {
dlm_lock_get(newlock);
list_add_tail(&newlock->list, queue);
+ mlog(0, "%s:%.*s: added lock for node %u, "
+ "setting refmap bit\n", dlm->name,
+ res->lockname.len, res->lockname.name, ml->node);
+ dlm_lockres_set_refmap_bit(ml->node, res);
+ added++;
}
spin_unlock(&res->spinlock);
}
mlog(0, "done running all the locks\n");
leave:
+ /* balance the ref taken when the work was queued */
+ spin_lock(&res->spinlock);
+ dlm_lockres_drop_inflight_ref(dlm, res);
+ spin_unlock(&res->spinlock);
+
if (ret < 0) {
mlog_errno(ret);
if (newlock)
@@ -1935,9 +2026,11 @@ static void dlm_finish_local_lockres_recovery(struct dlm_ctxt *dlm,
if (res->owner == dead_node) {
list_del_init(&res->recovering);
spin_lock(&res->spinlock);
+ /* new_master has our reference from
+ * the lock state sent during recovery */
dlm_change_lockres_owner(dlm, res, new_master);
res->state &= ~DLM_LOCK_RES_RECOVERING;
- if (!__dlm_lockres_unused(res))
+ if (__dlm_lockres_has_locks(res))
__dlm_dirty_lockres(dlm, res);
spin_unlock(&res->spinlock);
wake_up(&res->wq);
@@ -1977,9 +2070,11 @@ static void dlm_finish_local_lockres_recovery(struct dlm_ctxt *dlm,
dlm_lockres_put(res);
}
spin_lock(&res->spinlock);
+ /* new_master has our reference from
+ * the lock state sent during recovery */
dlm_change_lockres_owner(dlm, res, new_master);
res->state &= ~DLM_LOCK_RES_RECOVERING;
- if (!__dlm_lockres_unused(res))
+ if (__dlm_lockres_has_locks(res))
__dlm_dirty_lockres(dlm, res);
spin_unlock(&res->spinlock);
wake_up(&res->wq);
@@ -2048,6 +2143,7 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm,
{
struct list_head *iter, *tmpiter;
struct dlm_lock *lock;
+ unsigned int freed = 0;
/* this node is the lockres master:
* 1) remove any stale locks for the dead node
@@ -2062,6 +2158,7 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm,
if (lock->ml.node == dead_node) {
list_del_init(&lock->list);
dlm_lock_put(lock);
+ freed++;
}
}
list_for_each_safe(iter, tmpiter, &res->converting) {
@@ -2069,6 +2166,7 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm,
if (lock->ml.node == dead_node) {
list_del_init(&lock->list);
dlm_lock_put(lock);
+ freed++;
}
}
list_for_each_safe(iter, tmpiter, &res->blocked) {
@@ -2076,9 +2174,23 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm,
if (lock->ml.node == dead_node) {
list_del_init(&lock->list);
dlm_lock_put(lock);
+ freed++;
}
}
+ if (freed) {
+ mlog(0, "%s:%.*s: freed %u locks for dead node %u, "
+ "dropping ref from lockres\n", dlm->name,
+ res->lockname.len, res->lockname.name, freed, dead_node);
+ BUG_ON(!test_bit(dead_node, res->refmap));
+ dlm_lockres_clear_refmap_bit(dead_node, res);
+ } else if (test_bit(dead_node, res->refmap)) {
+ mlog(0, "%s:%.*s: dead node %u had a ref, but had "
+ "no locks and had not purged before dying\n", dlm->name,
+ res->lockname.len, res->lockname.name, dead_node);
+ dlm_lockres_clear_refmap_bit(dead_node, res);
+ }
+
/* do not kick thread yet */
__dlm_dirty_lockres(dlm, res);
}
@@ -2141,9 +2253,21 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
spin_lock(&res->spinlock);
/* zero the lvb if necessary */
dlm_revalidate_lvb(dlm, res, dead_node);
- if (res->owner == dead_node)
+ if (res->owner == dead_node) {
+ if (res->state & DLM_LOCK_RES_DROPPING_REF)
+ mlog(0, "%s:%.*s: owned by "
+ "dead node %u, this node was "
+ "dropping its ref when it died. "
+ "continue, dropping the flag.\n",
+ dlm->name, res->lockname.len,
+ res->lockname.name, dead_node);
+
+ /* the wake_up for this will happen when the
+ * RECOVERING flag is dropped later */
+ res->state &= ~DLM_LOCK_RES_DROPPING_REF;
+
dlm_move_lockres_to_recovery_list(dlm, res);
- else if (res->owner == dlm->node_num) {
+ } else if (res->owner == dlm->node_num) {
dlm_free_dead_locks(dlm, res, dead_node);
__dlm_lockres_calc_usage(dlm, res);
}
@@ -2480,7 +2604,8 @@ retry:
return ret;
}
-int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
struct dlm_begin_reco *br = (struct dlm_begin_reco *)msg->buf;
@@ -2608,7 +2733,8 @@ stage2:
return ret;
}
-int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
struct dlm_finalize_reco *fr = (struct dlm_finalize_reco *)msg->buf;
diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c
index 0c822f3ffb0..8ffa0916eb8 100644
--- a/fs/ocfs2/dlm/dlmthread.c
+++ b/fs/ocfs2/dlm/dlmthread.c
@@ -54,9 +54,6 @@
#include "cluster/masklog.h"
static int dlm_thread(void *data);
-static void dlm_purge_lockres_now(struct dlm_ctxt *dlm,
- struct dlm_lock_resource *lockres);
-
static void dlm_flush_asts(struct dlm_ctxt *dlm);
#define dlm_lock_is_remote(dlm, lock) ((lock)->ml.node != (dlm)->node_num)
@@ -82,14 +79,33 @@ repeat:
current->state = TASK_RUNNING;
}
-
-int __dlm_lockres_unused(struct dlm_lock_resource *res)
+int __dlm_lockres_has_locks(struct dlm_lock_resource *res)
{
if (list_empty(&res->granted) &&
list_empty(&res->converting) &&
- list_empty(&res->blocked) &&
- list_empty(&res->dirty))
- return 1;
+ list_empty(&res->blocked))
+ return 0;
+ return 1;
+}
+
+/* "unused": the lockres has no locks, is not on the dirty list,
+ * has no inflight locks (in the gap between mastery and acquiring
+ * the first lock), and has no bits in its refmap.
+ * truly ready to be freed. */
+int __dlm_lockres_unused(struct dlm_lock_resource *res)
+{
+ if (!__dlm_lockres_has_locks(res) &&
+ (list_empty(&res->dirty) && !(res->state & DLM_LOCK_RES_DIRTY))) {
+ /* try not to scan the bitmap unless the first two
+ * conditions are already true */
+ int bit = find_next_bit(res->refmap, O2NM_MAX_NODES, 0);
+ if (bit >= O2NM_MAX_NODES) {
+ /* since the bit for dlm->node_num is not
+ * set, inflight_locks better be zero */
+ BUG_ON(res->inflight_locks != 0);
+ return 1;
+ }
+ }
return 0;
}
@@ -106,46 +122,21 @@ void __dlm_lockres_calc_usage(struct dlm_ctxt *dlm,
assert_spin_locked(&res->spinlock);
if (__dlm_lockres_unused(res)){
- /* For now, just keep any resource we master */
- if (res->owner == dlm->node_num)
- {
- if (!list_empty(&res->purge)) {
- mlog(0, "we master %s:%.*s, but it is on "
- "the purge list. Removing\n",
- dlm->name, res->lockname.len,
- res->lockname.name);
- list_del_init(&res->purge);
- dlm->purge_count--;
- }
- return;
- }
-
if (list_empty(&res->purge)) {
- mlog(0, "putting lockres %.*s from purge list\n",
- res->lockname.len, res->lockname.name);
+ mlog(0, "putting lockres %.*s:%p onto purge list\n",
+ res->lockname.len, res->lockname.name, res);
res->last_used = jiffies;
+ dlm_lockres_get(res);
list_add_tail(&res->purge, &dlm->purge_list);
dlm->purge_count++;
-
- /* if this node is not the owner, there is
- * no way to keep track of who the owner could be.
- * unhash it to avoid serious problems. */
- if (res->owner != dlm->node_num) {
- mlog(0, "%s:%.*s: doing immediate "
- "purge of lockres owned by %u\n",
- dlm->name, res->lockname.len,
- res->lockname.name, res->owner);
-
- dlm_purge_lockres_now(dlm, res);
- }
}
} else if (!list_empty(&res->purge)) {
- mlog(0, "removing lockres %.*s from purge list, "
- "owner=%u\n", res->lockname.len, res->lockname.name,
- res->owner);
+ mlog(0, "removing lockres %.*s:%p from purge list, owner=%u\n",
+ res->lockname.len, res->lockname.name, res, res->owner);
list_del_init(&res->purge);
+ dlm_lockres_put(res);
dlm->purge_count--;
}
}
@@ -163,68 +154,65 @@ void dlm_lockres_calc_usage(struct dlm_ctxt *dlm,
spin_unlock(&dlm->spinlock);
}
-/* TODO: Eventual API: Called with the dlm spinlock held, may drop it
- * to do migration, but will re-acquire before exit. */
-void dlm_purge_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *lockres)
+static int dlm_purge_lockres(struct dlm_ctxt *dlm,
+ struct dlm_lock_resource *res)
{
int master;
- int ret;
-
- spin_lock(&lockres->spinlock);
- master = lockres->owner == dlm->node_num;
- spin_unlock(&lockres->spinlock);
+ int ret = 0;
- mlog(0, "purging lockres %.*s, master = %d\n", lockres->lockname.len,
- lockres->lockname.name, master);
-
- /* Non master is the easy case -- no migration required, just
- * quit. */
+ spin_lock(&res->spinlock);
+ if (!__dlm_lockres_unused(res)) {
+ spin_unlock(&res->spinlock);
+ mlog(0, "%s:%.*s: tried to purge but not unused\n",
+ dlm->name, res->lockname.len, res->lockname.name);
+ return -ENOTEMPTY;
+ }
+ master = (res->owner == dlm->node_num);
if (!master)
- goto finish;
-
- /* Wheee! Migrate lockres here! */
- spin_unlock(&dlm->spinlock);
-again:
+ res->state |= DLM_LOCK_RES_DROPPING_REF;
+ spin_unlock(&res->spinlock);
- ret = dlm_migrate_lockres(dlm, lockres, O2NM_MAX_NODES);
- if (ret == -ENOTEMPTY) {
- mlog(ML_ERROR, "lockres %.*s still has local locks!\n",
- lockres->lockname.len, lockres->lockname.name);
+ mlog(0, "purging lockres %.*s, master = %d\n", res->lockname.len,
+ res->lockname.name, master);
- BUG();
- } else if (ret < 0) {
- mlog(ML_NOTICE, "lockres %.*s: migrate failed, retrying\n",
- lockres->lockname.len, lockres->lockname.name);
- msleep(100);
- goto again;
+ if (!master) {
+ spin_lock(&res->spinlock);
+ /* This ensures that clear refmap is sent after the set */
+ __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG);
+ spin_unlock(&res->spinlock);
+ /* drop spinlock to do messaging, retake below */
+ spin_unlock(&dlm->spinlock);
+ /* clear our bit from the master's refmap, ignore errors */
+ ret = dlm_drop_lockres_ref(dlm, res);
+ if (ret < 0) {
+ mlog_errno(ret);
+ if (!dlm_is_host_down(ret))
+ BUG();
+ }
+ mlog(0, "%s:%.*s: dlm_deref_lockres returned %d\n",
+ dlm->name, res->lockname.len, res->lockname.name, ret);
+ spin_lock(&dlm->spinlock);
}
- spin_lock(&dlm->spinlock);
-
-finish:
- if (!list_empty(&lockres->purge)) {
- list_del_init(&lockres->purge);
+ if (!list_empty(&res->purge)) {
+ mlog(0, "removing lockres %.*s:%p from purgelist, "
+ "master = %d\n", res->lockname.len, res->lockname.name,
+ res, master);
+ list_del_init(&res->purge);
+ dlm_lockres_put(res);
dlm->purge_count--;
}
- __dlm_unhash_lockres(lockres);
-}
-
-/* make an unused lockres go away immediately.
- * as soon as the dlm spinlock is dropped, this lockres
- * will not be found. kfree still happens on last put. */
-static void dlm_purge_lockres_now(struct dlm_ctxt *dlm,
- struct dlm_lock_resource *lockres)
-{
- assert_spin_locked(&dlm->spinlock);
- assert_spin_locked(&lockres->spinlock);
+ __dlm_unhash_lockres(res);
- BUG_ON(!__dlm_lockres_unused(lockres));
-
- if (!list_empty(&lockres->purge)) {
- list_del_init(&lockres->purge);
- dlm->purge_count--;
+ /* lockres is not in the hash now. drop the flag and wake up
+ * any processes waiting in dlm_get_lock_resource. */
+ if (!master) {
+ spin_lock(&res->spinlock);
+ res->state &= ~DLM_LOCK_RES_DROPPING_REF;
+ spin_unlock(&res->spinlock);
+ wake_up(&res->wq);
}
- __dlm_unhash_lockres(lockres);
+ return 0;
}
static void dlm_run_purge_list(struct dlm_ctxt *dlm,
@@ -268,13 +256,17 @@ static void dlm_run_purge_list(struct dlm_ctxt *dlm,
break;
}
+ mlog(0, "removing lockres %.*s:%p from purgelist\n",
+ lockres->lockname.len, lockres->lockname.name, lockres);
list_del_init(&lockres->purge);
+ dlm_lockres_put(lockres);
dlm->purge_count--;
/* This may drop and reacquire the dlm spinlock if it
* has to do migration. */
mlog(0, "calling dlm_purge_lockres!\n");
- dlm_purge_lockres(dlm, lockres);
+ if (dlm_purge_lockres(dlm, lockres))
+ BUG();
mlog(0, "DONE calling dlm_purge_lockres!\n");
/* Avoid adding any scheduling latencies */
@@ -467,12 +459,17 @@ void __dlm_dirty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
assert_spin_locked(&res->spinlock);
/* don't shuffle secondary queues */
- if ((res->owner == dlm->node_num) &&
- !(res->state & DLM_LOCK_RES_DIRTY)) {
- /* ref for dirty_list */
- dlm_lockres_get(res);
- list_add_tail(&res->dirty, &dlm->dirty_list);
- res->state |= DLM_LOCK_RES_DIRTY;
+ if ((res->owner == dlm->node_num)) {
+ if (res->state & (DLM_LOCK_RES_MIGRATING |
+ DLM_LOCK_RES_BLOCK_DIRTY))
+ return;
+
+ if (list_empty(&res->dirty)) {
+ /* ref for dirty_list */
+ dlm_lockres_get(res);
+ list_add_tail(&res->dirty, &dlm->dirty_list);
+ res->state |= DLM_LOCK_RES_DIRTY;
+ }
}
}
@@ -651,7 +648,7 @@ static int dlm_thread(void *data)
dlm_lockres_get(res);
spin_lock(&res->spinlock);
- res->state &= ~DLM_LOCK_RES_DIRTY;
+ /* We clear the DLM_LOCK_RES_DIRTY state once we shuffle lists below */
list_del_init(&res->dirty);
spin_unlock(&res->spinlock);
spin_unlock(&dlm->spinlock);
@@ -675,10 +672,11 @@ static int dlm_thread(void *data)
/* it is now ok to move lockreses in these states
* to the dirty list, assuming that they will only be
* dirty for a short while. */
+ BUG_ON(res->state & DLM_LOCK_RES_MIGRATING);
if (res->state & (DLM_LOCK_RES_IN_PROGRESS |
- DLM_LOCK_RES_MIGRATING |
DLM_LOCK_RES_RECOVERING)) {
/* move it to the tail and keep going */
+ res->state &= ~DLM_LOCK_RES_DIRTY;
spin_unlock(&res->spinlock);
mlog(0, "delaying list shuffling for in-"
"progress lockres %.*s, state=%d\n",
@@ -699,6 +697,7 @@ static int dlm_thread(void *data)
/* called while holding lockres lock */
dlm_shuffle_lists(dlm, res);
+ res->state &= ~DLM_LOCK_RES_DIRTY;
spin_unlock(&res->spinlock);
dlm_lockres_calc_usage(dlm, res);
@@ -709,11 +708,8 @@ in_progress:
/* if the lock was in-progress, stick
* it on the back of the list */
if (delay) {
- /* ref for dirty_list */
- dlm_lockres_get(res);
spin_lock(&res->spinlock);
- list_add_tail(&res->dirty, &dlm->dirty_list);
- res->state |= DLM_LOCK_RES_DIRTY;
+ __dlm_dirty_lockres(dlm, res);
spin_unlock(&res->spinlock);
}
dlm_lockres_put(res);
diff --git a/fs/ocfs2/dlm/dlmunlock.c b/fs/ocfs2/dlm/dlmunlock.c
index 37be4b2e0d4..86ca085ef32 100644
--- a/fs/ocfs2/dlm/dlmunlock.c
+++ b/fs/ocfs2/dlm/dlmunlock.c
@@ -147,6 +147,10 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm,
goto leave;
}
+ if (res->state & DLM_LOCK_RES_MIGRATING) {
+ status = DLM_MIGRATING;
+ goto leave;
+ }
/* see above for what the spec says about
* LKM_CANCEL and the lock queue state */
@@ -244,8 +248,8 @@ leave:
/* this should always be coupled with list removal */
BUG_ON(!(actions & DLM_UNLOCK_REMOVE_LOCK));
mlog(0, "lock %u:%llu should be gone now! refs=%d\n",
- dlm_get_lock_cookie_node(lock->ml.cookie),
- dlm_get_lock_cookie_seq(lock->ml.cookie),
+ dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
atomic_read(&lock->lock_refs.refcount)-1);
dlm_lock_put(lock);
}
@@ -379,7 +383,8 @@ static enum dlm_status dlm_send_remote_unlock_request(struct dlm_ctxt *dlm,
* returns: DLM_NORMAL, DLM_BADARGS, DLM_IVLOCKID,
* return value from dlmunlock_master
*/
-int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data)
+int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data,
+ void **ret_data)
{
struct dlm_ctxt *dlm = data;
struct dlm_unlock_lock *unlock = (struct dlm_unlock_lock *)msg->buf;
@@ -502,8 +507,8 @@ not_found:
if (!found)
mlog(ML_ERROR, "failed to find lock to unlock! "
"cookie=%u:%llu\n",
- dlm_get_lock_cookie_node(unlock->cookie),
- dlm_get_lock_cookie_seq(unlock->cookie));
+ dlm_get_lock_cookie_node(be64_to_cpu(unlock->cookie)),
+ dlm_get_lock_cookie_seq(be64_to_cpu(unlock->cookie)));
else
dlm_lock_put(lock);
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 69fba16efbd..e335541727f 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -770,7 +770,7 @@ static int ocfs2_lock_create(struct ocfs2_super *osb,
int dlm_flags)
{
int ret = 0;
- enum dlm_status status;
+ enum dlm_status status = DLM_NORMAL;
unsigned long flags;
mlog_entry_void();
@@ -1138,6 +1138,7 @@ int ocfs2_rw_lock(struct inode *inode, int write)
{
int status, level;
struct ocfs2_lock_res *lockres;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
BUG_ON(!inode);
@@ -1147,6 +1148,9 @@ int ocfs2_rw_lock(struct inode *inode, int write)
(unsigned long long)OCFS2_I(inode)->ip_blkno,
write ? "EXMODE" : "PRMODE");
+ if (ocfs2_mount_local(osb))
+ return 0;
+
lockres = &OCFS2_I(inode)->ip_rw_lockres;
level = write ? LKM_EXMODE : LKM_PRMODE;
@@ -1164,6 +1168,7 @@ void ocfs2_rw_unlock(struct inode *inode, int write)
{
int level = write ? LKM_EXMODE : LKM_PRMODE;
struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_rw_lockres;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
mlog_entry_void();
@@ -1171,7 +1176,8 @@ void ocfs2_rw_unlock(struct inode *inode, int write)
(unsigned long long)OCFS2_I(inode)->ip_blkno,
write ? "EXMODE" : "PRMODE");
- ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
+ if (!ocfs2_mount_local(osb))
+ ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
mlog_exit_void();
}
@@ -1182,6 +1188,7 @@ int ocfs2_data_lock_full(struct inode *inode,
{
int status = 0, level;
struct ocfs2_lock_res *lockres;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
BUG_ON(!inode);
@@ -1201,6 +1208,9 @@ int ocfs2_data_lock_full(struct inode *inode,
goto out;
}
+ if (ocfs2_mount_local(osb))
+ goto out;
+
lockres = &OCFS2_I(inode)->ip_data_lockres;
level = write ? LKM_EXMODE : LKM_PRMODE;
@@ -1269,6 +1279,7 @@ void ocfs2_data_unlock(struct inode *inode,
{
int level = write ? LKM_EXMODE : LKM_PRMODE;
struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_data_lockres;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
mlog_entry_void();
@@ -1276,7 +1287,8 @@ void ocfs2_data_unlock(struct inode *inode,
(unsigned long long)OCFS2_I(inode)->ip_blkno,
write ? "EXMODE" : "PRMODE");
- if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)))
+ if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)) &&
+ !ocfs2_mount_local(osb))
ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
mlog_exit_void();
@@ -1467,8 +1479,9 @@ static int ocfs2_meta_lock_update(struct inode *inode,
{
int status = 0;
struct ocfs2_inode_info *oi = OCFS2_I(inode);
- struct ocfs2_lock_res *lockres;
+ struct ocfs2_lock_res *lockres = NULL;
struct ocfs2_dinode *fe;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
mlog_entry_void();
@@ -1483,10 +1496,12 @@ static int ocfs2_meta_lock_update(struct inode *inode,
}
spin_unlock(&oi->ip_lock);
- lockres = &oi->ip_meta_lockres;
+ if (!ocfs2_mount_local(osb)) {
+ lockres = &oi->ip_meta_lockres;
- if (!ocfs2_should_refresh_lock_res(lockres))
- goto bail;
+ if (!ocfs2_should_refresh_lock_res(lockres))
+ goto bail;
+ }
/* This will discard any caching information we might have had
* for the inode metadata. */
@@ -1496,7 +1511,7 @@ static int ocfs2_meta_lock_update(struct inode *inode,
* map (directories, bitmap files, etc) */
ocfs2_extent_map_trunc(inode, 0);
- if (ocfs2_meta_lvb_is_trustable(inode, lockres)) {
+ if (lockres && ocfs2_meta_lvb_is_trustable(inode, lockres)) {
mlog(0, "Trusting LVB on inode %llu\n",
(unsigned long long)oi->ip_blkno);
ocfs2_refresh_inode_from_lvb(inode);
@@ -1543,7 +1558,8 @@ static int ocfs2_meta_lock_update(struct inode *inode,
status = 0;
bail_refresh:
- ocfs2_complete_lock_res_refresh(lockres, status);
+ if (lockres)
+ ocfs2_complete_lock_res_refresh(lockres, status);
bail:
mlog_exit(status);
return status;
@@ -1585,7 +1601,7 @@ int ocfs2_meta_lock_full(struct inode *inode,
int arg_flags)
{
int status, level, dlm_flags, acquired;
- struct ocfs2_lock_res *lockres;
+ struct ocfs2_lock_res *lockres = NULL;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct buffer_head *local_bh = NULL;
@@ -1607,6 +1623,9 @@ int ocfs2_meta_lock_full(struct inode *inode,
goto bail;
}
+ if (ocfs2_mount_local(osb))
+ goto local;
+
if (!(arg_flags & OCFS2_META_LOCK_RECOVERY))
wait_event(osb->recovery_event,
ocfs2_node_map_is_empty(osb, &osb->recovery_map));
@@ -1636,6 +1655,7 @@ int ocfs2_meta_lock_full(struct inode *inode,
wait_event(osb->recovery_event,
ocfs2_node_map_is_empty(osb, &osb->recovery_map));
+local:
/*
* We only see this flag if we're being called from
* ocfs2_read_locked_inode(). It means we're locking an inode
@@ -1644,7 +1664,8 @@ int ocfs2_meta_lock_full(struct inode *inode,
*/
if (inode->i_state & I_NEW) {
status = 0;
- ocfs2_complete_lock_res_refresh(lockres, 0);
+ if (lockres)
+ ocfs2_complete_lock_res_refresh(lockres, 0);
goto bail;
}
@@ -1767,6 +1788,7 @@ void ocfs2_meta_unlock(struct inode *inode,
{
int level = ex ? LKM_EXMODE : LKM_PRMODE;
struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_meta_lockres;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
mlog_entry_void();
@@ -1774,7 +1796,8 @@ void ocfs2_meta_unlock(struct inode *inode,
(unsigned long long)OCFS2_I(inode)->ip_blkno,
ex ? "EXMODE" : "PRMODE");
- if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)))
+ if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)) &&
+ !ocfs2_mount_local(osb))
ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
mlog_exit_void();
@@ -1783,7 +1806,7 @@ void ocfs2_meta_unlock(struct inode *inode,
int ocfs2_super_lock(struct ocfs2_super *osb,
int ex)
{
- int status;
+ int status = 0;
int level = ex ? LKM_EXMODE : LKM_PRMODE;
struct ocfs2_lock_res *lockres = &osb->osb_super_lockres;
struct buffer_head *bh;
@@ -1794,6 +1817,9 @@ int ocfs2_super_lock(struct ocfs2_super *osb,
if (ocfs2_is_hard_readonly(osb))
return -EROFS;
+ if (ocfs2_mount_local(osb))
+ goto bail;
+
status = ocfs2_cluster_lock(osb, lockres, level, 0, 0);
if (status < 0) {
mlog_errno(status);
@@ -1832,7 +1858,8 @@ void ocfs2_super_unlock(struct ocfs2_super *osb,
int level = ex ? LKM_EXMODE : LKM_PRMODE;
struct ocfs2_lock_res *lockres = &osb->osb_super_lockres;
- ocfs2_cluster_unlock(osb, lockres, level);
+ if (!ocfs2_mount_local(osb))
+ ocfs2_cluster_unlock(osb, lockres, level);
}
int ocfs2_rename_lock(struct ocfs2_super *osb)
@@ -1843,6 +1870,9 @@ int ocfs2_rename_lock(struct ocfs2_super *osb)
if (ocfs2_is_hard_readonly(osb))
return -EROFS;
+ if (ocfs2_mount_local(osb))
+ return 0;
+
status = ocfs2_cluster_lock(osb, lockres, LKM_EXMODE, 0, 0);
if (status < 0)
mlog_errno(status);
@@ -1854,7 +1884,8 @@ void ocfs2_rename_unlock(struct ocfs2_super *osb)
{
struct ocfs2_lock_res *lockres = &osb->osb_rename_lockres;
- ocfs2_cluster_unlock(osb, lockres, LKM_EXMODE);
+ if (!ocfs2_mount_local(osb))
+ ocfs2_cluster_unlock(osb, lockres, LKM_EXMODE);
}
int ocfs2_dentry_lock(struct dentry *dentry, int ex)
@@ -1869,6 +1900,9 @@ int ocfs2_dentry_lock(struct dentry *dentry, int ex)
if (ocfs2_is_hard_readonly(osb))
return -EROFS;
+ if (ocfs2_mount_local(osb))
+ return 0;
+
ret = ocfs2_cluster_lock(osb, &dl->dl_lockres, level, 0, 0);
if (ret < 0)
mlog_errno(ret);
@@ -1882,7 +1916,8 @@ void ocfs2_dentry_unlock(struct dentry *dentry, int ex)
struct ocfs2_dentry_lock *dl = dentry->d_fsdata;
struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
- ocfs2_cluster_unlock(osb, &dl->dl_lockres, level);
+ if (!ocfs2_mount_local(osb))
+ ocfs2_cluster_unlock(osb, &dl->dl_lockres, level);
}
/* Reference counting of the dlm debug structure. We want this because
@@ -2145,12 +2180,15 @@ static void ocfs2_dlm_shutdown_debug(struct ocfs2_super *osb)
int ocfs2_dlm_init(struct ocfs2_super *osb)
{
- int status;
+ int status = 0;
u32 dlm_key;
- struct dlm_ctxt *dlm;
+ struct dlm_ctxt *dlm = NULL;
mlog_entry_void();
+ if (ocfs2_mount_local(osb))
+ goto local;
+
status = ocfs2_dlm_init_debug(osb);
if (status < 0) {
mlog_errno(status);
@@ -2178,11 +2216,12 @@ int ocfs2_dlm_init(struct ocfs2_super *osb)
goto bail;
}
+ dlm_register_eviction_cb(dlm, &osb->osb_eviction_cb);
+
+local:
ocfs2_super_lock_res_init(&osb->osb_super_lockres, osb);
ocfs2_rename_lock_res_init(&osb->osb_rename_lockres, osb);
- dlm_register_eviction_cb(dlm, &osb->osb_eviction_cb);
-
osb->dlm = dlm;
status = 0;
@@ -2679,6 +2718,15 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
inode = ocfs2_lock_res_inode(lockres);
mapping = inode->i_mapping;
+ /*
+ * We need this before the filemap_fdatawrite() so that it can
+ * transfer the dirty bit from the PTE to the
+ * page. Unfortunately this means that even for EX->PR
+ * downconverts, we'll lose our mappings and have to build
+ * them up again.
+ */
+ unmap_mapping_range(mapping, 0, 0, 0);
+
if (filemap_fdatawrite(mapping)) {
mlog(ML_ERROR, "Could not sync inode %llu for downconvert!",
(unsigned long long)OCFS2_I(inode)->ip_blkno);
@@ -2686,7 +2734,6 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
sync_mapping_buffers(mapping);
if (blocking == LKM_EXMODE) {
truncate_inode_pages(mapping, 0);
- unmap_mapping_range(mapping, 0, 0, 0);
} else {
/* We only need to wait on the I/O if we're not also
* truncating pages because truncate_inode_pages waits
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
index 06be6e774cf..56e1fefc120 100644
--- a/fs/ocfs2/export.c
+++ b/fs/ocfs2/export.c
@@ -60,14 +60,11 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb, void *vobjp)
inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0);
- if (IS_ERR(inode)) {
- mlog_errno(PTR_ERR(inode));
+ if (IS_ERR(inode))
return (void *)inode;
- }
if (handle->ih_generation != inode->i_generation) {
iput(inode);
- mlog_errno(-ESTALE);
return ERR_PTR(-ESTALE);
}
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 8786b3c490a..10953a508f2 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -68,7 +68,7 @@ static int ocfs2_file_open(struct inode *inode, struct file *file)
struct ocfs2_inode_info *oi = OCFS2_I(inode);
mlog_entry("(0x%p, 0x%p, '%.*s')\n", inode, file,
- file->f_dentry->d_name.len, file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.len, file->f_path.dentry->d_name.name);
spin_lock(&oi->ip_lock);
@@ -98,8 +98,8 @@ static int ocfs2_file_release(struct inode *inode, struct file *file)
struct ocfs2_inode_info *oi = OCFS2_I(inode);
mlog_entry("(0x%p, 0x%p, '%.*s')\n", inode, file,
- file->f_dentry->d_name.len,
- file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.len,
+ file->f_path.dentry->d_name.name);
spin_lock(&oi->ip_lock);
if (!--oi->ip_open_count)
@@ -149,10 +149,29 @@ int ocfs2_should_update_atime(struct inode *inode,
((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)))
return 0;
+ /*
+ * We can be called with no vfsmnt structure - NFSD will
+ * sometimes do this.
+ *
+ * Note that our action here is different than touch_atime() -
+ * if we can't tell whether this is a noatime mount, then we
+ * don't know whether to trust the value of s_atime_quantum.
+ */
+ if (vfsmnt == NULL)
+ return 0;
+
if ((vfsmnt->mnt_flags & MNT_NOATIME) ||
((vfsmnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
return 0;
+ if (vfsmnt->mnt_flags & MNT_RELATIME) {
+ if ((timespec_compare(&inode->i_atime, &inode->i_mtime) <= 0) ||
+ (timespec_compare(&inode->i_atime, &inode->i_ctime) <= 0))
+ return 1;
+
+ return 0;
+ }
+
now = CURRENT_TIME;
if ((now.tv_sec - inode->i_atime.tv_sec <= osb->s_atime_quantum))
return 0;
@@ -958,8 +977,6 @@ int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
}
ret = generic_permission(inode, mask, NULL);
- if (ret)
- mlog_errno(ret);
ocfs2_meta_unlock(inode, 0);
out:
@@ -1131,13 +1148,13 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
{
int ret, rw_level, have_alloc_sem = 0;
struct file *filp = iocb->ki_filp;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int appending = filp->f_flags & O_APPEND ? 1 : 0;
mlog_entry("(0x%p, %u, '%.*s')\n", filp,
(unsigned int)nr_segs,
- filp->f_dentry->d_name.len,
- filp->f_dentry->d_name.name);
+ filp->f_path.dentry->d_name.len,
+ filp->f_path.dentry->d_name.name);
/* happy write of zero bytes */
if (iocb->ki_left == 0)
@@ -1159,7 +1176,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
goto out;
}
- ret = ocfs2_prepare_inode_for_write(filp->f_dentry, &iocb->ki_pos,
+ ret = ocfs2_prepare_inode_for_write(filp->f_path.dentry, &iocb->ki_pos,
iocb->ki_left, appending);
if (ret < 0) {
mlog_errno(ret);
@@ -1207,12 +1224,12 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
unsigned int flags)
{
int ret;
- struct inode *inode = out->f_dentry->d_inode;
+ struct inode *inode = out->f_path.dentry->d_inode;
mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", out, pipe,
(unsigned int)len,
- out->f_dentry->d_name.len,
- out->f_dentry->d_name.name);
+ out->f_path.dentry->d_name.len,
+ out->f_path.dentry->d_name.name);
inode_double_lock(inode, pipe->inode);
@@ -1222,7 +1239,7 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
goto out;
}
- ret = ocfs2_prepare_inode_for_write(out->f_dentry, ppos, len, 0);
+ ret = ocfs2_prepare_inode_for_write(out->f_path.dentry, ppos, len, 0);
if (ret < 0) {
mlog_errno(ret);
goto out_unlock;
@@ -1247,12 +1264,12 @@ static ssize_t ocfs2_file_splice_read(struct file *in,
unsigned int flags)
{
int ret = 0;
- struct inode *inode = in->f_dentry->d_inode;
+ struct inode *inode = in->f_path.dentry->d_inode;
mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe,
(unsigned int)len,
- in->f_dentry->d_name.len,
- in->f_dentry->d_name.name);
+ in->f_path.dentry->d_name.len,
+ in->f_path.dentry->d_name.name);
/*
* See the comment in ocfs2_file_aio_read()
@@ -1278,12 +1295,12 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
{
int ret = 0, rw_level = -1, have_alloc_sem = 0, lock_level = 0;
struct file *filp = iocb->ki_filp;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
mlog_entry("(0x%p, %u, '%.*s')\n", filp,
(unsigned int)nr_segs,
- filp->f_dentry->d_name.len,
- filp->f_dentry->d_name.name);
+ filp->f_path.dentry->d_name.len,
+ filp->f_path.dentry->d_name.name);
if (!inode) {
ret = -EINVAL;
diff --git a/fs/ocfs2/heartbeat.c b/fs/ocfs2/heartbeat.c
index cbfd45a97a6..8fc52d6d0ce 100644
--- a/fs/ocfs2/heartbeat.c
+++ b/fs/ocfs2/heartbeat.c
@@ -154,6 +154,9 @@ int ocfs2_register_hb_callbacks(struct ocfs2_super *osb)
{
int status;
+ if (ocfs2_mount_local(osb))
+ return 0;
+
status = o2hb_register_callback(&osb->osb_hb_down);
if (status < 0) {
mlog_errno(status);
@@ -172,6 +175,9 @@ void ocfs2_clear_hb_callbacks(struct ocfs2_super *osb)
{
int status;
+ if (ocfs2_mount_local(osb))
+ return;
+
status = o2hb_unregister_callback(&osb->osb_hb_down);
if (status < 0)
mlog_errno(status);
@@ -186,6 +192,9 @@ void ocfs2_stop_heartbeat(struct ocfs2_super *osb)
int ret;
char *argv[5], *envp[3];
+ if (ocfs2_mount_local(osb))
+ return;
+
if (!osb->uuid_str) {
/* This can happen if we don't get far enough in mount... */
mlog(0, "No UUID with which to stop heartbeat!\n\n");
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 42e361f3054..28ab56f2b98 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -146,7 +146,6 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags)
if (is_bad_inode(inode)) {
iput(inode);
inode = ERR_PTR(-ESTALE);
- mlog_errno(PTR_ERR(inode));
goto bail;
}
@@ -155,8 +154,7 @@ bail:
mlog(0, "returning inode with number %llu\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno);
mlog_exit_ptr(inode);
- } else
- mlog_errno(PTR_ERR(inode));
+ }
return inode;
}
@@ -247,7 +245,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
* today. change if needed. */
if (!OCFS2_IS_VALID_DINODE(fe) ||
!(fe->i_flags & cpu_to_le32(OCFS2_VALID_FL))) {
- mlog(ML_ERROR, "Invalid dinode: i_ino=%lu, i_blkno=%llu, "
+ mlog(0, "Invalid dinode: i_ino=%lu, i_blkno=%llu, "
"signature = %.*s, flags = 0x%x\n",
inode->i_ino,
(unsigned long long)le64_to_cpu(fe->i_blkno), 7,
@@ -423,7 +421,8 @@ static int ocfs2_read_locked_inode(struct inode *inode,
* cluster lock before trusting anything anyway.
*/
can_lock = !(args->fi_flags & OCFS2_FI_FLAG_SYSFILE)
- && !(args->fi_flags & OCFS2_FI_FLAG_NOLOCK);
+ && !(args->fi_flags & OCFS2_FI_FLAG_NOLOCK)
+ && !ocfs2_mount_local(osb);
/*
* To maintain backwards compatibility with older versions of
@@ -477,11 +476,8 @@ static int ocfs2_read_locked_inode(struct inode *inode,
S_ISBLK(le16_to_cpu(fe->i_mode)))
inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev));
- if (ocfs2_populate_inode(inode, fe, 0) < 0) {
- mlog(ML_ERROR, "populate failed! i_blkno=%llu, i_ino=%lu\n",
- (unsigned long long)fe->i_blkno, inode->i_ino);
+ if (ocfs2_populate_inode(inode, fe, 0) < 0)
goto bail;
- }
BUG_ON(args->fi_blkno != le64_to_cpu(fe->i_blkno));
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 1d7f4ab1e5e..825cb0ae1b4 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -144,8 +144,10 @@ handle_t *ocfs2_start_trans(struct ocfs2_super *osb, int max_buffs)
ocfs2_abort(osb->sb, "Detected aborted journal");
handle = ERR_PTR(-EROFS);
}
- } else
- atomic_inc(&(osb->journal->j_num_trans));
+ } else {
+ if (!ocfs2_mount_local(osb))
+ atomic_inc(&(osb->journal->j_num_trans));
+ }
return handle;
}
@@ -507,9 +509,23 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
BUG_ON(atomic_read(&(osb->journal->j_num_trans)) != 0);
- status = ocfs2_journal_toggle_dirty(osb, 0);
- if (status < 0)
- mlog_errno(status);
+ if (ocfs2_mount_local(osb)) {
+ journal_lock_updates(journal->j_journal);
+ status = journal_flush(journal->j_journal);
+ journal_unlock_updates(journal->j_journal);
+ if (status < 0)
+ mlog_errno(status);
+ }
+
+ if (status == 0) {
+ /*
+ * Do not toggle if flush was unsuccessful otherwise
+ * will leave dirty metadata in a "clean" journal
+ */
+ status = ocfs2_journal_toggle_dirty(osb, 0);
+ if (status < 0)
+ mlog_errno(status);
+ }
/* Shutdown the kernel journal system */
journal_destroy(journal->j_journal);
@@ -549,7 +565,7 @@ static void ocfs2_clear_journal_error(struct super_block *sb,
}
}
-int ocfs2_journal_load(struct ocfs2_journal *journal)
+int ocfs2_journal_load(struct ocfs2_journal *journal, int local)
{
int status = 0;
struct ocfs2_super *osb;
@@ -576,14 +592,18 @@ int ocfs2_journal_load(struct ocfs2_journal *journal)
}
/* Launch the commit thread */
- osb->commit_task = kthread_run(ocfs2_commit_thread, osb, "ocfs2cmt");
- if (IS_ERR(osb->commit_task)) {
- status = PTR_ERR(osb->commit_task);
+ if (!local) {
+ osb->commit_task = kthread_run(ocfs2_commit_thread, osb,
+ "ocfs2cmt");
+ if (IS_ERR(osb->commit_task)) {
+ status = PTR_ERR(osb->commit_task);
+ osb->commit_task = NULL;
+ mlog(ML_ERROR, "unable to launch ocfs2commit thread, "
+ "error=%d", status);
+ goto done;
+ }
+ } else
osb->commit_task = NULL;
- mlog(ML_ERROR, "unable to launch ocfs2commit thread, error=%d",
- status);
- goto done;
- }
done:
mlog_exit(status);
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index 899112ad813..d026b4f2775 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -157,7 +157,7 @@ int ocfs2_journal_init(struct ocfs2_journal *journal,
void ocfs2_journal_shutdown(struct ocfs2_super *osb);
int ocfs2_journal_wipe(struct ocfs2_journal *journal,
int full);
-int ocfs2_journal_load(struct ocfs2_journal *journal);
+int ocfs2_journal_load(struct ocfs2_journal *journal, int local);
int ocfs2_check_journals_nolocks(struct ocfs2_super *osb);
void ocfs2_recovery_thread(struct ocfs2_super *osb,
int node_num);
@@ -174,6 +174,9 @@ static inline void ocfs2_checkpoint_inode(struct inode *inode)
{
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ if (ocfs2_mount_local(osb))
+ return;
+
if (!ocfs2_inode_fully_checkpointed(inode)) {
/* WARNING: This only kicks off a single
* checkpoint. If someone races you and adds more
@@ -303,8 +306,8 @@ int ocfs2_journal_dirty_data(handle_t *handle,
* for the dinode, one for the new block. */
#define OCFS2_SIMPLE_DIR_EXTEND_CREDITS (2)
-/* file update (nlink, etc) + dir entry block */
-#define OCFS2_LINK_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1)
+/* file update (nlink, etc) + directory mtime/ctime + dir entry block */
+#define OCFS2_LINK_CREDITS (2*OCFS2_INODE_UPDATE_CREDITS + 1)
/* inode + dir inode (if we unlink a dir), + dir entry block + orphan
* dir inode link */
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
index 698d79a74ef..4dedd978910 100644
--- a/fs/ocfs2/localalloc.c
+++ b/fs/ocfs2/localalloc.c
@@ -776,7 +776,7 @@ static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
{
int status;
- *ac = kcalloc(1, sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
+ *ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
if (!(*ac)) {
status = -ENOMEM;
mlog_errno(status);
diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c
index 69f85ae392d..51b02044768 100644
--- a/fs/ocfs2/mmap.c
+++ b/fs/ocfs2/mmap.c
@@ -83,10 +83,12 @@ static struct vm_operations_struct ocfs2_file_vm_ops = {
int ocfs2_mmap(struct file *file, struct vm_area_struct *vma)
{
int ret = 0, lock_level = 0;
+ struct ocfs2_super *osb = OCFS2_SB(file->f_dentry->d_inode->i_sb);
/* We don't want to support shared writable mappings yet. */
- if (((vma->vm_flags & VM_SHARED) || (vma->vm_flags & VM_MAYSHARE))
- && ((vma->vm_flags & VM_WRITE) || (vma->vm_flags & VM_MAYWRITE))) {
+ if (!ocfs2_mount_local(osb) &&
+ ((vma->vm_flags & VM_SHARED) || (vma->vm_flags & VM_MAYSHARE)) &&
+ ((vma->vm_flags & VM_WRITE) || (vma->vm_flags & VM_MAYWRITE))) {
mlog(0, "disallow shared writable mmaps %lx\n", vma->vm_flags);
/* This is -EINVAL because generic_file_readonly_mmap
* returns it in a similar situation. */
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 21db45ddf14..f3d7803b4b4 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -587,9 +587,11 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
}
ocfs2_inode_set_new(osb, inode);
- status = ocfs2_create_new_inode_locks(inode);
- if (status < 0)
- mlog_errno(status);
+ if (!ocfs2_mount_local(osb)) {
+ status = ocfs2_create_new_inode_locks(inode);
+ if (status < 0)
+ mlog_errno(status);
+ }
status = 0; /* error in ocfs2_create_new_inode_locks is not
* critical */
@@ -930,14 +932,15 @@ static int ocfs2_unlink(struct inode *dir,
goto leave;
}
- if (S_ISDIR(inode->i_mode)) {
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ if (S_ISDIR(inode->i_mode))
drop_nlink(dir);
- status = ocfs2_mark_inode_dirty(handle, dir,
- parent_node_bh);
- if (status < 0) {
- mlog_errno(status);
+
+ status = ocfs2_mark_inode_dirty(handle, dir, parent_node_bh);
+ if (status < 0) {
+ mlog_errno(status);
+ if (S_ISDIR(inode->i_mode))
inc_nlink(dir);
- }
}
leave:
@@ -1066,6 +1069,7 @@ static int ocfs2_rename(struct inode *old_dir,
char orphan_name[OCFS2_ORPHAN_NAMELEN + 1];
struct buffer_head *orphan_entry_bh = NULL;
struct buffer_head *newfe_bh = NULL;
+ struct buffer_head *old_inode_bh = NULL;
struct buffer_head *insert_entry_bh = NULL;
struct ocfs2_super *osb = NULL;
u64 newfe_blkno;
@@ -1077,7 +1081,7 @@ static int ocfs2_rename(struct inode *old_dir,
struct buffer_head *new_de_bh = NULL, *old_de_bh = NULL; // bhs for above
struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir,
// this is the 1st dirent bh
- nlink_t old_dir_nlink = old_dir->i_nlink, new_dir_nlink = new_dir->i_nlink;
+ nlink_t old_dir_nlink = old_dir->i_nlink;
/* At some point it might be nice to break this function up a
* bit. */
@@ -1137,12 +1141,11 @@ static int ocfs2_rename(struct inode *old_dir,
}
/*
- * Though we don't require an inode meta data update if
- * old_inode is not a directory, we lock anyway here to ensure
- * the vote thread on other nodes won't have to concurrently
- * downconvert the inode and the dentry locks.
+ * Aside from allowing a meta data update, the locking here
+ * also ensures that the vote thread on other nodes won't have
+ * to concurrently downconvert the inode and the dentry locks.
*/
- status = ocfs2_meta_lock(old_inode, NULL, 1);
+ status = ocfs2_meta_lock(old_inode, &old_inode_bh, 1);
if (status < 0) {
if (status != -ENOENT)
mlog_errno(status);
@@ -1353,6 +1356,7 @@ static int ocfs2_rename(struct inode *old_dir,
old_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(old_inode);
+ ocfs2_mark_inode_dirty(handle, old_inode, old_inode_bh);
/* now that the name has been added to new_dir, remove the old name */
status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh);
@@ -1382,27 +1386,22 @@ static int ocfs2_rename(struct inode *old_dir,
}
}
mark_inode_dirty(old_dir);
- if (new_inode)
+ ocfs2_mark_inode_dirty(handle, old_dir, old_dir_bh);
+ if (new_inode) {
mark_inode_dirty(new_inode);
+ ocfs2_mark_inode_dirty(handle, new_inode, newfe_bh);
+ }
- if (old_dir != new_dir)
- if (new_dir_nlink != new_dir->i_nlink) {
- if (!new_dir_bh) {
- mlog(ML_ERROR, "need to change nlink for new "
- "dir %llu from %d to %d but bh is NULL\n",
- (unsigned long long)OCFS2_I(new_dir)->ip_blkno,
- (int)new_dir_nlink, new_dir->i_nlink);
- } else {
- struct ocfs2_dinode *fe;
- status = ocfs2_journal_access(handle,
- new_dir,
- new_dir_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- fe = (struct ocfs2_dinode *) new_dir_bh->b_data;
- fe->i_links_count = cpu_to_le16(new_dir->i_nlink);
- status = ocfs2_journal_dirty(handle, new_dir_bh);
- }
- }
+ if (old_dir != new_dir) {
+ /* Keep the same times on both directories.*/
+ new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime;
+
+ /*
+ * This will also pick up the i_nlink change from the
+ * block above.
+ */
+ ocfs2_mark_inode_dirty(handle, new_dir, new_dir_bh);
+ }
if (old_dir_nlink != old_dir->i_nlink) {
if (!old_dir_bh) {
@@ -1453,6 +1452,8 @@ bail:
iput(new_inode);
if (newfe_bh)
brelse(newfe_bh);
+ if (old_inode_bh)
+ brelse(old_inode_bh);
if (old_dir_bh)
brelse(old_dir_bh);
if (new_dir_bh)
@@ -1824,6 +1825,13 @@ static int __ocfs2_add_entry(handle_t *handle,
(le16_to_cpu(de->rec_len) >= rec_len)) ||
(le16_to_cpu(de->rec_len) >=
(OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
+ if (retval < 0) {
+ mlog_errno(retval);
+ goto bail;
+ }
+
status = ocfs2_journal_access(handle, dir, insert_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
/* By now the buffer is marked for journaling */
@@ -1846,7 +1854,6 @@ static int __ocfs2_add_entry(handle_t *handle,
de->name_len = namelen;
memcpy(de->name, name, namelen);
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
dir->i_version++;
status = ocfs2_journal_dirty(handle, insert_bh);
retval = 0;
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index b767fd7da6e..db8e77cd35d 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -349,6 +349,11 @@ static inline int ocfs2_is_soft_readonly(struct ocfs2_super *osb)
return ret;
}
+static inline int ocfs2_mount_local(struct ocfs2_super *osb)
+{
+ return (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT);
+}
+
#define OCFS2_IS_VALID_DINODE(ptr) \
(!strcmp((ptr)->i_signature, OCFS2_INODE_SIGNATURE))
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index 3330a5dc6be..e61e218f5e0 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -85,8 +85,8 @@
#define OCFS2_CLEAR_INCOMPAT_FEATURE(sb,mask) \
OCFS2_SB(sb)->s_feature_incompat &= ~(mask)
-#define OCFS2_FEATURE_COMPAT_SUPP 0
-#define OCFS2_FEATURE_INCOMPAT_SUPP 0
+#define OCFS2_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_BACKUP_SB
+#define OCFS2_FEATURE_INCOMPAT_SUPP OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT
#define OCFS2_FEATURE_RO_COMPAT_SUPP 0
/*
@@ -96,6 +96,32 @@
*/
#define OCFS2_FEATURE_INCOMPAT_HEARTBEAT_DEV 0x0002
+/*
+ * tunefs sets this incompat flag before starting the resize and clears it
+ * at the end. This flag protects users from inadvertently mounting the fs
+ * after an aborted run without fsck-ing.
+ */
+#define OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG 0x0004
+
+/* Used to denote a non-clustered volume */
+#define OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT 0x0008
+
+/* Support for sparse allocation in b-trees */
+#define OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC 0x0010
+
+/*
+ * backup superblock flag is used to indicate that this volume
+ * has backup superblocks.
+ */
+#define OCFS2_FEATURE_COMPAT_BACKUP_SB 0x0001
+
+/* The byte offset of the first backup block will be 1G.
+ * The following will be 4G, 16G, 64G, 256G and 1T.
+ */
+#define OCFS2_BACKUP_SB_START 1 << 30
+
+/* the max backup superblock nums */
+#define OCFS2_MAX_BACKUP_SUPERBLOCKS 6
/*
* Flags on ocfs2_dinode.i_flags
@@ -554,6 +580,20 @@ static inline int ocfs2_truncate_recs_per_inode(struct super_block *sb)
return size / sizeof(struct ocfs2_truncate_rec);
}
+
+static inline u64 ocfs2_backup_super_blkno(struct super_block *sb, int index)
+{
+ u64 offset = OCFS2_BACKUP_SB_START;
+
+ if (index >= 0 && index < OCFS2_MAX_BACKUP_SUPERBLOCKS) {
+ offset <<= (2 * index);
+ offset >>= sb->s_blocksize_bits;
+ return offset;
+ }
+
+ return 0;
+
+}
#else
static inline int ocfs2_fast_symlink_chars(int blocksize)
{
@@ -619,6 +659,19 @@ static inline int ocfs2_truncate_recs_per_inode(int blocksize)
return size / sizeof(struct ocfs2_truncate_rec);
}
+
+static inline uint64_t ocfs2_backup_super_blkno(int blocksize, int index)
+{
+ uint64_t offset = OCFS2_BACKUP_SB_START;
+
+ if (index >= 0 && index < OCFS2_MAX_BACKUP_SUPERBLOCKS) {
+ offset <<= (2 * index);
+ offset /= blocksize;
+ return offset;
+ }
+
+ return 0;
+}
#endif /* __KERNEL__ */
diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c
index aa6f5aadedc..2d3ac32cb74 100644
--- a/fs/ocfs2/slot_map.c
+++ b/fs/ocfs2/slot_map.c
@@ -175,7 +175,7 @@ int ocfs2_init_slot_info(struct ocfs2_super *osb)
struct buffer_head *bh = NULL;
struct ocfs2_slot_info *si;
- si = kcalloc(1, sizeof(struct ocfs2_slot_info), GFP_KERNEL);
+ si = kzalloc(sizeof(struct ocfs2_slot_info), GFP_KERNEL);
if (!si) {
status = -ENOMEM;
mlog_errno(status);
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
index 000d71cca6c..6dbb1176275 100644
--- a/fs/ocfs2/suballoc.c
+++ b/fs/ocfs2/suballoc.c
@@ -488,7 +488,7 @@ int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
int status;
u32 slot;
- *ac = kcalloc(1, sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
+ *ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
if (!(*ac)) {
status = -ENOMEM;
mlog_errno(status);
@@ -530,7 +530,7 @@ int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
{
int status;
- *ac = kcalloc(1, sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
+ *ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
if (!(*ac)) {
status = -ENOMEM;
mlog_errno(status);
@@ -595,7 +595,7 @@ int ocfs2_reserve_clusters(struct ocfs2_super *osb,
mlog_entry_void();
- *ac = kcalloc(1, sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
+ *ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
if (!(*ac)) {
status = -ENOMEM;
mlog_errno(status);
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 4bf39540e65..6e300a88a47 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -508,6 +508,27 @@ bail:
return status;
}
+static int ocfs2_verify_heartbeat(struct ocfs2_super *osb)
+{
+ if (ocfs2_mount_local(osb)) {
+ if (osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) {
+ mlog(ML_ERROR, "Cannot heartbeat on a locally "
+ "mounted device.\n");
+ return -EINVAL;
+ }
+ }
+
+ if (!(osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL)) {
+ if (!ocfs2_mount_local(osb) && !ocfs2_is_hard_readonly(osb)) {
+ mlog(ML_ERROR, "Heartbeat has to be started to mount "
+ "a read-write clustered device.\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
{
struct dentry *root;
@@ -516,16 +537,24 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
struct inode *inode = NULL;
struct ocfs2_super *osb = NULL;
struct buffer_head *bh = NULL;
+ char nodestr[8];
mlog_entry("%p, %p, %i", sb, data, silent);
- /* for now we only have one cluster/node, make sure we see it
- * in the heartbeat universe */
- if (!o2hb_check_local_node_heartbeating()) {
+ if (!ocfs2_parse_options(sb, data, &parsed_opt, 0)) {
status = -EINVAL;
goto read_super_error;
}
+ /* for now we only have one cluster/node, make sure we see it
+ * in the heartbeat universe */
+ if (parsed_opt & OCFS2_MOUNT_HB_LOCAL) {
+ if (!o2hb_check_local_node_heartbeating()) {
+ status = -EINVAL;
+ goto read_super_error;
+ }
+ }
+
/* probe for superblock */
status = ocfs2_sb_probe(sb, &bh, &sector_size);
if (status < 0) {
@@ -541,11 +570,6 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
}
brelse(bh);
bh = NULL;
-
- if (!ocfs2_parse_options(sb, data, &parsed_opt, 0)) {
- status = -EINVAL;
- goto read_super_error;
- }
osb->s_mount_opt = parsed_opt;
sb->s_magic = OCFS2_SUPER_MAGIC;
@@ -588,21 +612,16 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
}
if (!ocfs2_is_hard_readonly(osb)) {
- /* If this isn't a hard readonly mount, then we need
- * to make sure that heartbeat is in a valid state,
- * and that we mark ourselves soft readonly is -oro
- * was specified. */
- if (!(osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL)) {
- mlog(ML_ERROR, "No heartbeat for device (%s)\n",
- sb->s_id);
- status = -EINVAL;
- goto read_super_error;
- }
-
if (sb->s_flags & MS_RDONLY)
ocfs2_set_ro_flag(osb, 0);
}
+ status = ocfs2_verify_heartbeat(osb);
+ if (status < 0) {
+ mlog_errno(status);
+ goto read_super_error;
+ }
+
osb->osb_debug_root = debugfs_create_dir(osb->uuid_str,
ocfs2_debugfs_root);
if (!osb->osb_debug_root) {
@@ -635,9 +654,14 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
ocfs2_complete_mount_recovery(osb);
- printk(KERN_INFO "ocfs2: Mounting device (%s) on (node %d, slot %d) "
+ if (ocfs2_mount_local(osb))
+ snprintf(nodestr, sizeof(nodestr), "local");
+ else
+ snprintf(nodestr, sizeof(nodestr), "%d", osb->node_num);
+
+ printk(KERN_INFO "ocfs2: Mounting device (%s) on (node %s, slot %d) "
"with %s data mode.\n",
- osb->dev_str, osb->node_num, osb->slot_num,
+ osb->dev_str, nodestr, osb->slot_num,
osb->s_mount_opt & OCFS2_MOUNT_DATA_WRITEBACK ? "writeback" :
"ordered");
@@ -999,7 +1023,11 @@ static int ocfs2_fill_local_node_info(struct ocfs2_super *osb)
/* XXX hold a ref on the node while mounte? easy enough, if
* desirable. */
- osb->node_num = o2nm_this_node();
+ if (ocfs2_mount_local(osb))
+ osb->node_num = 0;
+ else
+ osb->node_num = o2nm_this_node();
+
if (osb->node_num == O2NM_MAX_NODES) {
mlog(ML_ERROR, "could not find this host's node number\n");
status = -ENOENT;
@@ -1084,6 +1112,9 @@ static int ocfs2_mount_volume(struct super_block *sb)
goto leave;
}
+ if (ocfs2_mount_local(osb))
+ goto leave;
+
/* This should be sent *after* we recovered our journal as it
* will cause other nodes to unmark us as needing
* recovery. However, we need to send it *before* dropping the
@@ -1114,6 +1145,7 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
{
int tmp;
struct ocfs2_super *osb = NULL;
+ char nodestr[8];
mlog_entry("(0x%p)\n", sb);
@@ -1177,8 +1209,13 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
atomic_set(&osb->vol_state, VOLUME_DISMOUNTED);
- printk(KERN_INFO "ocfs2: Unmounting device (%s) on (node %d)\n",
- osb->dev_str, osb->node_num);
+ if (ocfs2_mount_local(osb))
+ snprintf(nodestr, sizeof(nodestr), "local");
+ else
+ snprintf(nodestr, sizeof(nodestr), "%d", osb->node_num);
+
+ printk(KERN_INFO "ocfs2: Unmounting device (%s) on (node %s)\n",
+ osb->dev_str, nodestr);
ocfs2_delete_osb(osb);
kfree(osb);
@@ -1194,7 +1231,7 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super *osb, const unsigned char *uu
BUG_ON(uuid_bytes != OCFS2_VOL_UUID_LEN);
- osb->uuid_str = kcalloc(1, OCFS2_VOL_UUID_LEN * 2 + 1, GFP_KERNEL);
+ osb->uuid_str = kzalloc(OCFS2_VOL_UUID_LEN * 2 + 1, GFP_KERNEL);
if (osb->uuid_str == NULL)
return -ENOMEM;
@@ -1225,7 +1262,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
mlog_entry_void();
- osb = kcalloc(1, sizeof(struct ocfs2_super), GFP_KERNEL);
+ osb = kzalloc(sizeof(struct ocfs2_super), GFP_KERNEL);
if (!osb) {
status = -ENOMEM;
mlog_errno(status);
@@ -1350,7 +1387,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
*/
/* initialize our journal structure */
- journal = kcalloc(1, sizeof(struct ocfs2_journal), GFP_KERNEL);
+ journal = kzalloc(sizeof(struct ocfs2_journal), GFP_KERNEL);
if (!journal) {
mlog(ML_ERROR, "unable to alloc journal\n");
status = -ENOMEM;
@@ -1536,6 +1573,7 @@ static int ocfs2_check_volume(struct ocfs2_super *osb)
{
int status = 0;
int dirty;
+ int local;
struct ocfs2_dinode *local_alloc = NULL; /* only used if we
* recover
* ourselves. */
@@ -1563,8 +1601,10 @@ static int ocfs2_check_volume(struct ocfs2_super *osb)
"recovering volume.\n");
}
+ local = ocfs2_mount_local(osb);
+
/* will play back anything left in the journal. */
- ocfs2_journal_load(osb->journal);
+ ocfs2_journal_load(osb->journal, local);
if (dirty) {
/* recover my local alloc if we didn't unmount cleanly. */
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index 957d6878b03..03b0191534d 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -158,8 +158,7 @@ static void *ocfs2_follow_link(struct dentry *dentry,
}
status = vfs_follow_link(nd, link);
- if (status && status != -ENOENT)
- mlog_errno(status);
+
bail:
if (page) {
kunmap(page);
diff --git a/fs/ocfs2/vote.c b/fs/ocfs2/vote.c
index 5b4dca79990..f30e63b9910 100644
--- a/fs/ocfs2/vote.c
+++ b/fs/ocfs2/vote.c
@@ -479,7 +479,7 @@ static struct ocfs2_net_wait_ctxt *ocfs2_new_net_wait_ctxt(unsigned int response
{
struct ocfs2_net_wait_ctxt *w;
- w = kcalloc(1, sizeof(*w), GFP_NOFS);
+ w = kzalloc(sizeof(*w), GFP_NOFS);
if (!w) {
mlog_errno(-ENOMEM);
goto bail;
@@ -642,7 +642,7 @@ static struct ocfs2_vote_msg * ocfs2_new_vote_request(struct ocfs2_super *osb,
BUG_ON(!ocfs2_is_valid_vote_request(type));
- request = kcalloc(1, sizeof(*request), GFP_NOFS);
+ request = kzalloc(sizeof(*request), GFP_NOFS);
if (!request) {
mlog_errno(-ENOMEM);
} else {
@@ -887,7 +887,7 @@ static inline int ocfs2_translate_response(int response)
static int ocfs2_handle_response_message(struct o2net_msg *msg,
u32 len,
- void *data)
+ void *data, void **ret_data)
{
unsigned int response_id, node_num;
int response_status;
@@ -943,7 +943,7 @@ bail:
static int ocfs2_handle_vote_message(struct o2net_msg *msg,
u32 len,
- void *data)
+ void *data, void **ret_data)
{
int status;
struct ocfs2_super *osb = data;
@@ -1000,11 +1000,14 @@ int ocfs2_register_net_handlers(struct ocfs2_super *osb)
{
int status = 0;
+ if (ocfs2_mount_local(osb))
+ return 0;
+
status = o2net_register_handler(OCFS2_MESSAGE_TYPE_RESPONSE,
osb->net_key,
sizeof(struct ocfs2_response_msg),
ocfs2_handle_response_message,
- osb, &osb->osb_net_handlers);
+ osb, NULL, &osb->osb_net_handlers);
if (status) {
mlog_errno(status);
goto bail;
@@ -1014,7 +1017,7 @@ int ocfs2_register_net_handlers(struct ocfs2_super *osb)
osb->net_key,
sizeof(struct ocfs2_vote_msg),
ocfs2_handle_vote_message,
- osb, &osb->osb_net_handlers);
+ osb, NULL, &osb->osb_net_handlers);
if (status) {
mlog_errno(status);
goto bail;
diff --git a/fs/open.c b/fs/open.c
index 89e0c237a63..c989fb4cf7b 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -165,7 +165,7 @@ asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf)
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs_native(file->f_dentry, &tmp);
+ error = vfs_statfs_native(file->f_path.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
@@ -186,7 +186,7 @@ asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs64(file->f_dentry, &tmp);
+ error = vfs_statfs64(file->f_path.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
@@ -302,7 +302,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
if (file->f_flags & O_LARGEFILE)
small = 0;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
inode = dentry->d_inode;
error = -EINVAL;
if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
@@ -448,8 +448,8 @@ asmlinkage long sys_fchdir(unsigned int fd)
if (!file)
goto out;
- dentry = file->f_dentry;
- mnt = file->f_vfsmnt;
+ dentry = file->f_path.dentry;
+ mnt = file->f_path.mnt;
inode = dentry->d_inode;
error = -ENOTDIR;
@@ -503,7 +503,7 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
if (!file)
goto out;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
inode = dentry->d_inode;
audit_inode(NULL, inode);
@@ -662,7 +662,7 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
if (!file)
goto out;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
audit_inode(NULL, dentry->d_inode);
error = chown_common(dentry, user, group);
fput(file);
@@ -688,8 +688,8 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
}
f->f_mapping = inode->i_mapping;
- f->f_dentry = dentry;
- f->f_vfsmnt = mnt;
+ f->f_path.dentry = dentry;
+ f->f_path.mnt = mnt;
f->f_pos = 0;
f->f_op = fops_get(inode->i_fop);
file_move(f, &inode->i_sb->s_files);
@@ -723,8 +723,8 @@ cleanup_all:
if (f->f_mode & FMODE_WRITE)
put_write_access(inode);
file_kill(f);
- f->f_dentry = NULL;
- f->f_vfsmnt = NULL;
+ f->f_path.dentry = NULL;
+ f->f_path.mnt = NULL;
cleanup_file:
put_filp(f);
dput(dentry);
@@ -822,7 +822,7 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags)
/* Pick up the filp from the open intent */
filp = nd->intent.open.file;
/* Has the filesystem initialised the file for us? */
- if (filp->f_dentry == NULL)
+ if (filp->f_path.dentry == NULL)
filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL);
else
path_release(nd);
@@ -864,8 +864,7 @@ int get_unused_fd(void)
repeat:
fdt = files_fdtable(files);
- fd = find_next_zero_bit(fdt->open_fds->fds_bits,
- fdt->max_fdset,
+ fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
files->next_fd);
/*
@@ -965,7 +964,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
- fsnotify_open(f->f_dentry);
+ fsnotify_open(f->f_path.dentry);
fd_install(fd, f);
}
}
@@ -1087,6 +1086,7 @@ EXPORT_SYMBOL(sys_close);
asmlinkage long sys_vhangup(void)
{
if (capable(CAP_SYS_TTY_CONFIG)) {
+ /* XXX: this needs locking */
tty_vhangup(current->signal->tty);
return 0;
}
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index 26f44e0074e..99c0bc37ba0 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -262,7 +262,7 @@ found:
static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct op_inode_info *oi = OP_I(inode);
struct device_node *dp = oi->u.node;
struct device_node *child;
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
index e478f194183..74552c60b67 100644
--- a/fs/partitions/Kconfig
+++ b/fs/partitions/Kconfig
@@ -194,7 +194,7 @@ config LDM_DEBUG
config SGI_PARTITION
bool "SGI partition support" if PARTITION_ADVANCED
- default y if (SGI_IP22 || SGI_IP27 || ((MACH_JAZZ || SNI_RM200_PCI) && !CPU_LITTLE_ENDIAN))
+ default y if (SGI_IP22 || SGI_IP27 || ((MACH_JAZZ || SNI_RM) && !CPU_LITTLE_ENDIAN))
help
Say Y here if you would like to be able to read the hard disk
partition table format used by SGI machines.
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 1901137f4ec..3d73d94d93a 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -276,12 +276,39 @@ static struct part_attribute part_attr_stat = {
.show = part_stat_read
};
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+
+static ssize_t part_fail_store(struct hd_struct * p,
+ const char *buf, size_t count)
+{
+ int i;
+
+ if (count > 0 && sscanf(buf, "%d", &i) > 0)
+ p->make_it_fail = (i == 0) ? 0 : 1;
+
+ return count;
+}
+static ssize_t part_fail_read(struct hd_struct * p, char *page)
+{
+ return sprintf(page, "%d\n", p->make_it_fail);
+}
+static struct part_attribute part_attr_fail = {
+ .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR },
+ .store = part_fail_store,
+ .show = part_fail_read
+};
+
+#endif
+
static struct attribute * default_attrs[] = {
&part_attr_uevent.attr,
&part_attr_dev.attr,
&part_attr_start.attr,
&part_attr_size.attr,
&part_attr_stat.attr,
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+ &part_attr_fail.attr,
+#endif
NULL,
};
diff --git a/fs/pipe.c b/fs/pipe.c
index ae36b89b1a3..68090e84f58 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -207,7 +207,7 @@ int generic_pipe_buf_pin(struct pipe_inode_info *info, struct pipe_buffer *buf)
return 0;
}
-static struct pipe_buf_operations anon_pipe_buf_ops = {
+static const struct pipe_buf_operations anon_pipe_buf_ops = {
.can_merge = 1,
.map = generic_pipe_buf_map,
.unmap = generic_pipe_buf_unmap,
@@ -222,7 +222,7 @@ 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 inode *inode = filp->f_path.dentry->d_inode;
struct pipe_inode_info *pipe;
int do_wakeup;
ssize_t ret;
@@ -243,7 +243,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
if (bufs) {
int curbuf = pipe->curbuf;
struct pipe_buffer *buf = pipe->bufs + curbuf;
- struct pipe_buf_operations *ops = buf->ops;
+ const struct pipe_buf_operations *ops = buf->ops;
void *addr;
size_t chars = buf->len;
int error, atomic;
@@ -335,7 +335,7 @@ 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 inode *inode = filp->f_path.dentry->d_inode;
struct pipe_inode_info *pipe;
ssize_t ret;
int do_wakeup;
@@ -365,7 +365,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov,
int lastbuf = (pipe->curbuf + pipe->nrbufs - 1) &
(PIPE_BUFFERS-1);
struct pipe_buffer *buf = pipe->bufs + lastbuf;
- struct pipe_buf_operations *ops = buf->ops;
+ const struct pipe_buf_operations *ops = buf->ops;
int offset = buf->offset + buf->len;
if (ops->can_merge && offset + chars <= PAGE_SIZE) {
@@ -520,7 +520,7 @@ static int
pipe_ioctl(struct inode *pino, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct pipe_inode_info *pipe;
int count, buf, nrbufs;
@@ -548,7 +548,7 @@ static unsigned int
pipe_poll(struct file *filp, poll_table *wait)
{
unsigned int mask;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct pipe_inode_info *pipe = inode->i_pipe;
int nrbufs;
@@ -601,7 +601,7 @@ pipe_release(struct inode *inode, int decr, int decw)
static int
pipe_read_fasync(int fd, struct file *filp, int on)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int retval;
mutex_lock(&inode->i_mutex);
@@ -618,7 +618,7 @@ pipe_read_fasync(int fd, struct file *filp, int on)
static int
pipe_write_fasync(int fd, struct file *filp, int on)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int retval;
mutex_lock(&inode->i_mutex);
@@ -635,7 +635,7 @@ pipe_write_fasync(int fd, struct file *filp, int on)
static int
pipe_rdwr_fasync(int fd, struct file *filp, int on)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct pipe_inode_info *pipe = inode->i_pipe;
int retval;
@@ -756,7 +756,7 @@ const struct file_operations rdwr_fifo_fops = {
.fasync = pipe_rdwr_fasync,
};
-static struct file_operations read_pipe_fops = {
+static const struct file_operations read_pipe_fops = {
.llseek = no_llseek,
.read = do_sync_read,
.aio_read = pipe_read,
@@ -768,7 +768,7 @@ static struct file_operations read_pipe_fops = {
.fasync = pipe_read_fasync,
};
-static struct file_operations write_pipe_fops = {
+static const struct file_operations write_pipe_fops = {
.llseek = no_llseek,
.read = bad_pipe_r,
.write = do_sync_write,
@@ -780,7 +780,7 @@ static struct file_operations write_pipe_fops = {
.fasync = pipe_write_fasync,
};
-static struct file_operations rdwr_pipe_fops = {
+static const struct file_operations rdwr_pipe_fops = {
.llseek = no_llseek,
.read = do_sync_read,
.aio_read = pipe_read,
@@ -914,8 +914,8 @@ struct file *create_write_pipe(void)
*/
dentry->d_flags &= ~DCACHE_UNHASHED;
d_instantiate(dentry, inode);
- f->f_vfsmnt = mntget(pipe_mnt);
- f->f_dentry = dentry;
+ f->f_path.mnt = mntget(pipe_mnt);
+ f->f_path.dentry = dentry;
f->f_mapping = inode->i_mapping;
f->f_flags = O_WRONLY;
@@ -935,8 +935,9 @@ struct file *create_write_pipe(void)
void free_write_pipe(struct file *f)
{
- mntput(f->f_vfsmnt);
- dput(f->f_dentry);
+ free_pipe_info(f->f_dentry->d_inode);
+ dput(f->f_path.dentry);
+ mntput(f->f_path.mnt);
put_filp(f);
}
@@ -947,9 +948,9 @@ struct file *create_read_pipe(struct file *wrf)
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_path.mnt = mntget(wrf->f_path.mnt);
+ f->f_path.dentry = dget(wrf->f_path.dentry);
+ f->f_mapping = wrf->f_path.dentry->d_inode->i_mapping;
f->f_pos = 0;
f->f_flags = O_RDONLY;
@@ -994,6 +995,8 @@ int do_pipe(int *fd)
err_fdr:
put_unused_fd(fdr);
err_read_pipe:
+ dput(fr->f_dentry);
+ mntput(fr->f_vfsmnt);
put_filp(fr);
err_write_pipe:
free_write_pipe(fw);
diff --git a/fs/pnode.c b/fs/pnode.c
index da42ee61c1d..56aacead836 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -6,7 +6,7 @@
* Author : Ram Pai (linuxram@us.ibm.com)
*
*/
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/mount.h>
#include <linux/fs.h>
#include "pnode.h"
diff --git a/fs/pnode.h b/fs/pnode.h
index 020e1bb60fd..d45bd8ec36b 100644
--- a/fs/pnode.h
+++ b/fs/pnode.h
@@ -13,7 +13,7 @@
#define IS_MNT_SHARED(mnt) (mnt->mnt_flags & MNT_SHARED)
#define IS_MNT_SLAVE(mnt) (mnt->mnt_master)
-#define IS_MNT_NEW(mnt) (!mnt->mnt_namespace)
+#define IS_MNT_NEW(mnt) (!mnt->mnt_ns)
#define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED)
#define IS_MNT_UNBINDABLE(mnt) (mnt->mnt_flags & MNT_UNBINDABLE)
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 25e917fb473..70e4fab117b 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -346,20 +346,13 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
sigemptyset(&sigcatch);
cutime = cstime = utime = stime = cputime_zero;
- 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));
+
+ if (sig->tty) {
+ tty_pgrp = sig->tty->pgrp;
+ tty_nr = new_encode_dev(tty_devnum(sig->tty));
}
num_threads = atomic_read(&sig->count);
@@ -388,14 +381,13 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
stime = cputime_add(stime, sig->stime);
}
- sid = sig->session;
+ sid = signal_session(sig);
pgid = process_group(task);
ppid = rcu_dereference(task->real_parent)->tgid;
unlock_task_sighand(task, &flags);
}
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 b859fc749c0..1a979ea3b37 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -59,7 +59,7 @@
#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/namei.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/rcupdate.h>
@@ -365,33 +365,35 @@ struct proc_mounts {
static int mounts_open(struct inode *inode, struct file *file)
{
struct task_struct *task = get_proc_task(inode);
- struct namespace *namespace = NULL;
+ struct mnt_namespace *ns = NULL;
struct proc_mounts *p;
int ret = -EINVAL;
if (task) {
task_lock(task);
- namespace = task->nsproxy->namespace;
- if (namespace)
- get_namespace(namespace);
+ if (task->nsproxy) {
+ ns = task->nsproxy->mnt_ns;
+ if (ns)
+ get_mnt_ns(ns);
+ }
task_unlock(task);
put_task_struct(task);
}
- if (namespace) {
+ if (ns) {
ret = -ENOMEM;
p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
if (p) {
file->private_data = &p->m;
ret = seq_open(file, &mounts_op);
if (!ret) {
- p->m.private = namespace;
- p->event = namespace->event;
+ p->m.private = ns;
+ p->event = ns->event;
return 0;
}
kfree(p);
}
- put_namespace(namespace);
+ put_mnt_ns(ns);
}
return ret;
}
@@ -399,15 +401,15 @@ static int mounts_open(struct inode *inode, struct file *file)
static int mounts_release(struct inode *inode, struct file *file)
{
struct seq_file *m = file->private_data;
- struct namespace *namespace = m->private;
- put_namespace(namespace);
+ struct mnt_namespace *ns = m->private;
+ put_mnt_ns(ns);
return seq_release(inode, file);
}
static unsigned mounts_poll(struct file *file, poll_table *wait)
{
struct proc_mounts *p = file->private_data;
- struct namespace *ns = p->m.private;
+ struct mnt_namespace *ns = p->m.private;
unsigned res = 0;
poll_wait(file, &ns->poll, wait);
@@ -437,21 +439,21 @@ static int mountstats_open(struct inode *inode, struct file *file)
if (!ret) {
struct seq_file *m = file->private_data;
- struct namespace *namespace = NULL;
+ struct mnt_namespace *mnt_ns = NULL;
struct task_struct *task = get_proc_task(inode);
if (task) {
task_lock(task);
if (task->nsproxy)
- namespace = task->nsproxy->namespace;
- if (namespace)
- get_namespace(namespace);
+ mnt_ns = task->nsproxy->mnt_ns;
+ if (mnt_ns)
+ get_mnt_ns(mnt_ns);
task_unlock(task);
put_task_struct(task);
}
- if (namespace)
- m->private = namespace;
+ if (mnt_ns)
+ m->private = mnt_ns;
else {
seq_release(inode, file);
ret = -EINVAL;
@@ -472,7 +474,7 @@ static struct file_operations proc_mountstats_operations = {
static ssize_t proc_info_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
unsigned long page;
ssize_t length;
struct task_struct *task = get_proc_task(inode);
@@ -512,7 +514,7 @@ static int mem_open(struct inode* inode, struct file* file)
static ssize_t mem_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
char *page;
unsigned long src = *ppos;
int ret = -ESRCH;
@@ -584,7 +586,7 @@ static ssize_t mem_write(struct file * file, const char * buf,
{
int copied;
char *page;
- struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
unsigned long dst = *ppos;
copied = -ESRCH;
@@ -654,7 +656,7 @@ static struct file_operations proc_mem_operations = {
static ssize_t oom_adjust_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
char buffer[PROC_NUMBUF];
size_t len;
int oom_adjust;
@@ -694,7 +696,7 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
return -EINVAL;
if (*end == '\n')
end++;
- task = get_proc_task(file->f_dentry->d_inode);
+ task = get_proc_task(file->f_path.dentry->d_inode);
if (!task)
return -ESRCH;
if (oom_adjust < task->oomkilladj && !capable(CAP_SYS_RESOURCE)) {
@@ -718,7 +720,7 @@ static struct file_operations proc_oom_adjust_operations = {
static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
struct task_struct *task = get_proc_task(inode);
ssize_t length;
char tmpbuf[TMPBUFLEN];
@@ -734,7 +736,7 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
char *page, *tmp;
ssize_t length;
uid_t loginuid;
@@ -853,6 +855,65 @@ static struct file_operations proc_seccomp_operations = {
};
#endif /* CONFIG_SECCOMP */
+#ifdef CONFIG_FAULT_INJECTION
+static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ char buffer[PROC_NUMBUF];
+ size_t len;
+ int make_it_fail;
+ loff_t __ppos = *ppos;
+
+ if (!task)
+ return -ESRCH;
+ make_it_fail = task->make_it_fail;
+ put_task_struct(task);
+
+ len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail);
+ if (__ppos >= len)
+ return 0;
+ if (count > len-__ppos)
+ count = len-__ppos;
+ if (copy_to_user(buf, buffer + __ppos, count))
+ return -EFAULT;
+ *ppos = __ppos + count;
+ return count;
+}
+
+static ssize_t proc_fault_inject_write(struct file * file,
+ const char __user * buf, size_t count, loff_t *ppos)
+{
+ struct task_struct *task;
+ char buffer[PROC_NUMBUF], *end;
+ int make_it_fail;
+
+ if (!capable(CAP_SYS_RESOURCE))
+ return -EPERM;
+ memset(buffer, 0, sizeof(buffer));
+ if (count > sizeof(buffer) - 1)
+ count = sizeof(buffer) - 1;
+ if (copy_from_user(buffer, buf, count))
+ return -EFAULT;
+ make_it_fail = simple_strtol(buffer, &end, 0);
+ if (*end == '\n')
+ end++;
+ task = get_proc_task(file->f_dentry->d_inode);
+ if (!task)
+ return -ESRCH;
+ task->make_it_fail = make_it_fail;
+ put_task_struct(task);
+ if (end - buffer == 0)
+ return -EIO;
+ return end - buffer;
+}
+
+static struct file_operations proc_fault_inject_operations = {
+ .read = proc_fault_inject_read,
+ .write = proc_fault_inject_write,
+};
+#endif
+
static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
@@ -1078,7 +1139,7 @@ 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 dentry *child, *dir = filp->f_path.dentry;
struct inode *inode;
struct qstr qname;
ino_t ino = 0;
@@ -1157,8 +1218,8 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (file) {
- *mnt = mntget(file->f_vfsmnt);
- *dentry = dget(file->f_dentry);
+ *mnt = mntget(file->f_path.mnt);
+ *dentry = dget(file->f_path.dentry);
spin_unlock(&files->file_lock);
put_files_struct(files);
return 0;
@@ -1293,7 +1354,7 @@ static int proc_fd_fill_cache(struct file *filp, void *dirent, filldir_t filldir
static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct task_struct *p = get_proc_task(inode);
unsigned int fd, tid, ino;
@@ -1440,7 +1501,7 @@ static int proc_pident_readdir(struct file *filp,
{
int i;
int pid;
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct task_struct *task = get_proc_task(inode);
struct pid_entry *p, *last;
@@ -1496,7 +1557,7 @@ out_no_task:
static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
unsigned long page;
ssize_t length;
struct task_struct *task = get_proc_task(inode);
@@ -1512,7 +1573,7 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
goto out;
length = security_getprocattr(task,
- (char*)file->f_dentry->d_name.name,
+ (char*)file->f_path.dentry->d_name.name,
(void*)page, count);
if (length >= 0)
length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
@@ -1526,7 +1587,7 @@ 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;
+ struct inode * inode = file->f_path.dentry->d_inode;
char *page;
ssize_t length;
struct task_struct *task = get_proc_task(inode);
@@ -1552,7 +1613,7 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
goto out_free;
length = security_setprocattr(task,
- (char*)file->f_dentry->d_name.name,
+ (char*)file->f_path.dentry->d_name.name,
(void*)page, count);
out_free:
free_page((unsigned long) page);
@@ -1745,6 +1806,27 @@ static int proc_base_fill_cache(struct file *filp, void *dirent, filldir_t filld
proc_base_instantiate, task, p);
}
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+static int proc_pid_io_accounting(struct task_struct *task, char *buffer)
+{
+ return sprintf(buffer,
+ "rchar: %llu\n"
+ "wchar: %llu\n"
+ "syscr: %llu\n"
+ "syscw: %llu\n"
+ "read_bytes: %llu\n"
+ "write_bytes: %llu\n"
+ "cancelled_write_bytes: %llu\n",
+ (unsigned long long)task->rchar,
+ (unsigned long long)task->wchar,
+ (unsigned long long)task->syscr,
+ (unsigned long long)task->syscw,
+ (unsigned long long)task->ioac.read_bytes,
+ (unsigned long long)task->ioac.write_bytes,
+ (unsigned long long)task->ioac.cancelled_write_bytes);
+}
+#endif
+
/*
* Thread groups
*/
@@ -1793,6 +1875,12 @@ static struct pid_entry tgid_base_stuff[] = {
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
#endif
+#ifdef CONFIG_FAULT_INJECTION
+ REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
+#endif
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+ INF("io", S_IRUGO, pid_io_accounting),
+#endif
};
static int proc_tgid_base_readdir(struct file * filp,
@@ -1994,7 +2082,7 @@ static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldi
int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
- struct task_struct *reaper = get_proc_task(filp->f_dentry->d_inode);
+ struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode);
struct task_struct *task;
int tgid;
@@ -2068,6 +2156,9 @@ static struct pid_entry tid_base_stuff[] = {
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
#endif
+#ifdef CONFIG_FAULT_INJECTION
+ REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
+#endif
};
static int proc_tid_base_readdir(struct file * filp,
@@ -2235,15 +2326,25 @@ static int proc_task_fill_cache(struct file *filp, void *dirent, filldir_t filld
/* for the /proc/TGID/task/ directories */
static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
- struct task_struct *leader = get_proc_task(inode);
+ struct task_struct *leader = NULL;
struct task_struct *task;
int retval = -ENOENT;
ino_t ino;
int tid;
unsigned long pos = filp->f_pos; /* avoiding "long long" filp->f_pos */
+ task = get_proc_task(inode);
+ if (!task)
+ goto out_no_task;
+ rcu_read_lock();
+ if (pid_alive(task)) {
+ leader = task->group_leader;
+ get_task_struct(leader);
+ }
+ rcu_read_unlock();
+ put_task_struct(task);
if (!leader)
goto out_no_task;
retval = 0;
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 4ba03009cf7..853cb877d5f 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -52,7 +52,7 @@ static ssize_t
proc_file_read(struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
char *page;
ssize_t retval=0;
int eof=0;
@@ -203,7 +203,7 @@ static ssize_t
proc_file_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct proc_dir_entry * dp;
dp = PDE(inode);
@@ -432,7 +432,7 @@ int proc_readdir(struct file * filp,
struct proc_dir_entry * de;
unsigned int ino;
int i;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
lock_kernel();
@@ -453,7 +453,7 @@ int proc_readdir(struct file * filp,
/* fall through */
case 1:
if (filldir(dirent, "..", 2, i,
- parent_ino(filp->f_dentry),
+ parent_ino(filp->f_path.dentry),
DT_DIR) < 0)
goto out;
i++;
@@ -558,7 +558,7 @@ static void proc_kill_inodes(struct proc_dir_entry *de)
file_list_lock();
list_for_each(p, &sb->s_files) {
struct file * filp = list_entry(p, struct file, f_u.fu_list);
- struct dentry * dentry = filp->f_dentry;
+ struct dentry * dentry = filp->f_path.dentry;
struct inode * inode;
const struct file_operations *fops;
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
index d7dbdf9e0f4..5ec67257e5f 100644
--- a/fs/proc/nommu.c
+++ b/fs/proc/nommu.c
@@ -46,7 +46,7 @@ int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
file = vma->vm_file;
if (file) {
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
dev = inode->i_sb->s_dev;
ino = inode->i_ino;
}
@@ -67,7 +67,7 @@ int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
if (len < 1)
len = 1;
seq_printf(m, "%*c", len, ' ');
- seq_path(m, file->f_vfsmnt, file->f_dentry, "");
+ seq_path(m, file->f_path.mnt, file->f_path.dentry, "");
}
seq_putc(m, '\n');
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 51815cece6f..b37ce33f67e 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -39,13 +39,14 @@
#include <linux/seq_file.h>
#include <linux/times.h>
#include <linux/profile.h>
+#include <linux/utsname.h>
#include <linux/blkdev.h>
#include <linux/hugetlb.h>
#include <linux/jiffies.h>
#include <linux/sysrq.h>
#include <linux/vmalloc.h>
#include <linux/crash_dump.h>
-#include <linux/pspace.h>
+#include <linux/pid_namespace.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
@@ -92,7 +93,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, init_pspace.last_pid);
+ nr_running(), nr_threads, current->nsproxy->pid_ns->last_pid);
return proc_calc_metrics(page, start, off, count, eof, len);
}
@@ -252,8 +253,10 @@ static int version_read_proc(char *page, char **start, off_t off,
{
int len;
- strcpy(page, linux_banner);
- len = strlen(page);
+ len = snprintf(page, PAGE_SIZE, linux_proc_banner,
+ utsname()->sysname,
+ utsname()->release,
+ utsname()->version);
return proc_calc_metrics(page, start, off, count, eof, len);
}
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 6b769afac55..55ade0d1562 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -94,8 +94,8 @@ int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount *
}
if (vma) {
- *mnt = mntget(vma->vm_file->f_vfsmnt);
- *dentry = dget(vma->vm_file->f_dentry);
+ *mnt = mntget(vma->vm_file->f_path.mnt);
+ *dentry = dget(vma->vm_file->f_path.dentry);
result = 0;
}
@@ -135,7 +135,7 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
int len;
if (file) {
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
dev = inode->i_sb->s_dev;
ino = inode->i_ino;
}
@@ -156,7 +156,7 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
*/
if (file) {
pad_len_spaces(m, len);
- seq_path(m, file->f_vfsmnt, file->f_dentry, "\n");
+ seq_path(m, file->f_path.mnt, file->f_path.dentry, "\n");
} else {
const char *name = arch_vma_name(vma);
if (!name) {
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 091aa8e48e0..fcc5caf93f5 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -126,8 +126,8 @@ int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount *
}
if (vma) {
- *mnt = mntget(vma->vm_file->f_vfsmnt);
- *dentry = dget(vma->vm_file->f_dentry);
+ *mnt = mntget(vma->vm_file->f_path.mnt);
+ *dentry = dget(vma->vm_file->f_path.dentry);
result = 0;
}
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index 0d7103fa0df..c94db1db7a7 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -22,7 +22,7 @@
static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
unsigned int offset;
struct buffer_head *bh;
struct qnx4_inode_entry *de;
diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
index 0947fb57dcf..54ebbc84207 100644
--- a/fs/ramfs/file-mmu.c
+++ b/fs/ramfs/file-mmu.c
@@ -25,11 +25,13 @@
*/
#include <linux/fs.h>
+#include <linux/mm.h>
const struct address_space_operations ramfs_aops = {
.readpage = simple_readpage,
.prepare_write = simple_prepare_write,
- .commit_write = simple_commit_write
+ .commit_write = simple_commit_write,
+ .set_page_dirty = __set_page_dirty_nobuffers,
};
const struct file_operations ramfs_file_operations = {
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index bfe5dbf1002..e9d6c473328 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <linux/init.h>
@@ -30,7 +31,8 @@ static int ramfs_nommu_setattr(struct dentry *, struct iattr *);
const struct address_space_operations ramfs_aops = {
.readpage = simple_readpage,
.prepare_write = simple_prepare_write,
- .commit_write = simple_commit_write
+ .commit_write = simple_commit_write,
+ .set_page_dirty = __set_page_dirty_nobuffers,
};
const struct file_operations ramfs_file_operations = {
@@ -232,7 +234,7 @@ unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
unsigned long pgoff, unsigned long flags)
{
unsigned long maxpages, lpages, nr, loop, ret;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct page **pages = NULL, **ptr, *page;
loff_t isize;
diff --git a/fs/read_write.c b/fs/read_write.c
index f792000a28e..707ac21700d 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -64,13 +64,13 @@ loff_t remote_llseek(struct file *file, loff_t offset, int origin)
lock_kernel();
switch (origin) {
case 2:
- offset += i_size_read(file->f_dentry->d_inode);
+ offset += i_size_read(file->f_path.dentry->d_inode);
break;
case 1:
offset += file->f_pos;
}
retval = -EINVAL;
- if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
+ if (offset>=0 && offset<=file->f_path.dentry->d_inode->i_sb->s_maxbytes) {
if (offset != file->f_pos) {
file->f_pos = offset;
file->f_version = 0;
@@ -95,7 +95,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin)
lock_kernel();
switch (origin) {
case 2:
- offset += i_size_read(file->f_dentry->d_inode);
+ offset += i_size_read(file->f_path.dentry->d_inode);
break;
case 1:
offset += file->f_pos;
@@ -203,7 +203,7 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count
if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
goto Einval;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) {
int retval = locks_mandatory_area(
read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
@@ -273,7 +273,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
else
ret = do_sync_read(file, buf, count, pos);
if (ret > 0) {
- fsnotify_access(file->f_dentry);
+ fsnotify_access(file->f_path.dentry);
current->rchar += ret;
}
current->syscr++;
@@ -331,7 +331,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
else
ret = do_sync_write(file, buf, count, pos);
if (ret > 0) {
- fsnotify_modify(file->f_dentry);
+ fsnotify_modify(file->f_path.dentry);
current->wchar += ret;
}
current->syscw++;
@@ -450,8 +450,6 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
return seg;
}
-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)
{
@@ -628,9 +626,9 @@ out:
kfree(iov);
if ((ret + (type == READ)) > 0) {
if (type == READ)
- fsnotify_access(file->f_dentry);
+ fsnotify_access(file->f_path.dentry);
else
- fsnotify_modify(file->f_dentry);
+ fsnotify_modify(file->f_path.dentry);
}
return ret;
}
@@ -722,7 +720,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
if (!(in_file->f_mode & FMODE_READ))
goto fput_in;
retval = -EINVAL;
- in_inode = in_file->f_dentry->d_inode;
+ in_inode = in_file->f_path.dentry->d_inode;
if (!in_inode)
goto fput_in;
if (!in_file->f_op || !in_file->f_op->sendfile)
@@ -754,7 +752,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
retval = -EINVAL;
if (!out_file->f_op || !out_file->f_op->sendpage)
goto fput_out;
- out_inode = out_file->f_dentry->d_inode;
+ out_inode = out_file->f_path.dentry->d_inode;
retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
if (retval < 0)
goto fput_out;
diff --git a/fs/readdir.c b/fs/readdir.c
index bff3ee58e2f..f39f5b31325 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -21,7 +21,7 @@
int vfs_readdir(struct file *file, filldir_t filler, void *buf)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int res = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
goto out;
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index e3d466a228d..b286ccb0858 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -708,7 +708,7 @@ static void oid_groups(reiserfs_blocknr_hint_t * hint)
*/
static int get_left_neighbor(reiserfs_blocknr_hint_t * hint)
{
- struct path *path;
+ struct treepath *path;
struct buffer_head *bh;
struct item_head *ih;
int pos_in_item;
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index 657050ad743..96a2f8889da 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -45,7 +45,7 @@ static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
//
static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
INITIALIZE_PATH(path_to_entry);
struct buffer_head *bh;
@@ -135,7 +135,7 @@ static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* Ignore the .reiserfs_priv entry */
if (reiserfs_xattrs(inode->i_sb) &&
!old_format_only(inode->i_sb) &&
- filp->f_dentry == inode->i_sb->s_root &&
+ filp->f_path.dentry == inode->i_sb->s_root &&
REISERFS_SB(inode->i_sb)->priv_root &&
REISERFS_SB(inode->i_sb)->priv_root->d_inode
&& deh_objectid(deh) ==
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 373d862c3f8..5109f1d5e7f 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -48,6 +48,11 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp)
}
mutex_lock(&inode->i_mutex);
+
+ mutex_lock(&(REISERFS_I(inode)->i_mmap));
+ if (REISERFS_I(inode)->i_flags & i_ever_mapped)
+ REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
+
reiserfs_write_lock(inode->i_sb);
/* freeing preallocation only involves relogging blocks that
* are already in the current transaction. preallocation gets
@@ -100,11 +105,24 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp)
err = reiserfs_truncate_file(inode, 0);
}
out:
+ mutex_unlock(&(REISERFS_I(inode)->i_mmap));
mutex_unlock(&inode->i_mutex);
reiserfs_write_unlock(inode->i_sb);
return err;
}
+static int reiserfs_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct inode *inode;
+
+ inode = file->f_path.dentry->d_inode;
+ mutex_lock(&(REISERFS_I(inode)->i_mmap));
+ REISERFS_I(inode)->i_flags |= i_ever_mapped;
+ mutex_unlock(&(REISERFS_I(inode)->i_mmap));
+
+ return generic_file_mmap(file, vma);
+}
+
static void reiserfs_vfs_truncate_file(struct inode *inode)
{
reiserfs_truncate_file(inode, 1);
@@ -1288,7 +1306,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t
loff_t pos; // Current position in the file.
ssize_t res; // return value of various functions that we call.
int err = 0;
- struct inode *inode = file->f_dentry->d_inode; // Inode of the file that we are writing to.
+ struct inode *inode = file->f_path.dentry->d_inode; // Inode of the file that we are writing to.
/* To simplify coding at this time, we store
locked pages in array for now */
struct page *prepared_pages[REISERFS_WRITE_PAGES_AT_A_TIME];
@@ -1335,7 +1353,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t
if (count == 0)
goto out;
- res = remove_suid(file->f_dentry);
+ res = remove_suid(file->f_path.dentry);
if (res)
goto out;
@@ -1527,7 +1545,7 @@ const struct file_operations reiserfs_file_operations = {
#ifdef CONFIG_COMPAT
.compat_ioctl = reiserfs_compat_ioctl,
#endif
- .mmap = generic_file_mmap,
+ .mmap = reiserfs_file_mmap,
.open = generic_file_open,
.release = reiserfs_file_release,
.fsync = reiserfs_sync_file,
diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c
index 6d0e554daa9..0ee35c6c9b7 100644
--- a/fs/reiserfs/fix_node.c
+++ b/fs/reiserfs/fix_node.c
@@ -957,7 +957,7 @@ static int get_far_parent(struct tree_balance *p_s_tb,
{
struct buffer_head *p_s_parent;
INITIALIZE_PATH(s_path_to_neighbor_father);
- struct path *p_s_path = p_s_tb->tb_path;
+ struct treepath *p_s_path = p_s_tb->tb_path;
struct cpu_key s_lr_father_key;
int n_counter,
n_position = INT_MAX,
@@ -1074,7 +1074,7 @@ static int get_far_parent(struct tree_balance *p_s_tb,
*/
static int get_parents(struct tree_balance *p_s_tb, int n_h)
{
- struct path *p_s_path = p_s_tb->tb_path;
+ struct treepath *p_s_path = p_s_tb->tb_path;
int n_position,
n_ret_value,
n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
@@ -1885,7 +1885,7 @@ static int check_balance(int mode,
static int get_direct_parent(struct tree_balance *p_s_tb, int n_h)
{
struct buffer_head *p_s_bh;
- struct path *p_s_path = p_s_tb->tb_path;
+ struct treepath *p_s_path = p_s_tb->tb_path;
int n_position,
n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 254239e6f9e..9fcbfe31697 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -207,7 +207,7 @@ static int file_capable(struct inode *inode, long block)
}
/*static*/ int restart_transaction(struct reiserfs_transaction_handle *th,
- struct inode *inode, struct path *path)
+ struct inode *inode, struct treepath *path)
{
struct super_block *s = th->t_super;
int len = th->t_blocks_allocated;
@@ -570,7 +570,7 @@ static inline int _allocate_block(struct reiserfs_transaction_handle *th,
long block,
struct inode *inode,
b_blocknr_t * allocated_block_nr,
- struct path *path, int flags)
+ struct treepath *path, int flags)
{
BUG_ON(!th->t_trans_id);
@@ -1107,7 +1107,7 @@ static inline ulong to_fake_used_blocks(struct inode *inode, int sd_size)
//
// called by read_locked_inode
-static void init_inode(struct inode *inode, struct path *path)
+static void init_inode(struct inode *inode, struct treepath *path)
{
struct buffer_head *bh;
struct item_head *ih;
@@ -1125,6 +1125,7 @@ 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;
+ mutex_init(&(REISERFS_I(inode)->i_mmap));
reiserfs_init_acl_access(inode);
reiserfs_init_acl_default(inode);
reiserfs_init_xattr_rwsem(inode);
@@ -1284,7 +1285,7 @@ static void inode2sd_v1(void *sd, struct inode *inode, loff_t size)
/* NOTE, you must prepare the buffer head before sending it here,
** and then log it after the call
*/
-static void update_stat_data(struct path *path, struct inode *inode,
+static void update_stat_data(struct treepath *path, struct inode *inode,
loff_t size)
{
struct buffer_head *bh;
@@ -1653,7 +1654,7 @@ int reiserfs_write_inode(struct inode *inode, int do_sync)
containing "." and ".." entries */
static int reiserfs_new_directory(struct reiserfs_transaction_handle *th,
struct inode *inode,
- struct item_head *ih, struct path *path,
+ struct item_head *ih, struct treepath *path,
struct inode *dir)
{
struct super_block *sb = th->t_super;
@@ -1712,7 +1713,7 @@ static int reiserfs_new_directory(struct reiserfs_transaction_handle *th,
containing the body of symlink */
static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct inode *inode, /* Inode of symlink */
struct item_head *ih,
- struct path *path, const char *symname,
+ struct treepath *path, const char *symname,
int item_len)
{
struct super_block *sb = th->t_super;
@@ -1832,6 +1833,7 @@ 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);
+ mutex_init(&(REISERFS_I(inode)->i_mmap));
reiserfs_init_acl_access(inode);
reiserfs_init_acl_default(inode);
reiserfs_init_xattr_rwsem(inode);
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index 9c57578cb83..b484d2913c0 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -99,7 +99,7 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int ret;
/* These are just misnamed, they actually get/put from/to user an int */
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index abde1edc223..23f5cd5bbf5 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -54,7 +54,7 @@ static int bin_search_in_dir_item(struct reiserfs_dir_entry *de, loff_t off)
// comment? maybe something like set de to point to what the path points to?
static inline void set_de_item_location(struct reiserfs_dir_entry *de,
- struct path *path)
+ struct treepath *path)
{
de->de_bh = get_last_bh(path);
de->de_ih = get_ih(path);
@@ -113,7 +113,7 @@ entry position in the item
/* The function is NOT SCHEDULE-SAFE! */
int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
- struct path *path, struct reiserfs_dir_entry *de)
+ struct treepath *path, struct reiserfs_dir_entry *de)
{
int retval;
@@ -282,7 +282,7 @@ static int linear_search_in_dir_item(struct cpu_key *key,
// may return NAME_FOUND, NAME_FOUND_INVISIBLE, NAME_NOT_FOUND
// FIXME: should add something like IOERROR
static int reiserfs_find_entry(struct inode *dir, const char *name, int namelen,
- struct path *path_to_entry,
+ struct treepath *path_to_entry,
struct reiserfs_dir_entry *de)
{
struct cpu_key key_to_search;
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index c533ec1bcae..ecc9943202f 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -295,7 +295,7 @@ static int show_oidmap(struct seq_file *m, struct super_block *sb)
}
#if defined( REISERFS_USE_OIDMAPF )
if (sb_info->oidmap.use_file && (sb_info->oidmap.mapf != NULL)) {
- loff_t size = sb_info->oidmap.mapf->f_dentry->d_inode->i_size;
+ loff_t size = sb_info->oidmap.mapf->f_path.dentry->d_inode->i_size;
total_used += size / sizeof(reiserfs_oidinterval_d_t);
}
#endif
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index 5240abe1a70..afb21ea4530 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -244,7 +244,7 @@ static const struct reiserfs_key MAX_KEY = {
of the path, and going upwards. We must check the path's validity at each step. If the key is not in
the path, there is no delimiting key in the tree (buffer is first or last buffer in tree), and in this
case we return a special key, either MIN_KEY or MAX_KEY. */
-static inline const struct reiserfs_key *get_lkey(const struct path
+static inline const struct reiserfs_key *get_lkey(const struct treepath
*p_s_chk_path,
const struct super_block
*p_s_sb)
@@ -290,7 +290,7 @@ static inline const struct reiserfs_key *get_lkey(const struct path
}
/* Get delimiting key of the buffer at the path and its right neighbor. */
-inline const struct reiserfs_key *get_rkey(const struct path *p_s_chk_path,
+inline const struct reiserfs_key *get_rkey(const struct treepath *p_s_chk_path,
const struct super_block *p_s_sb)
{
int n_position, n_path_offset = p_s_chk_path->path_length;
@@ -337,7 +337,7 @@ inline const struct reiserfs_key *get_rkey(const struct path *p_s_chk_path,
the path. These delimiting keys are stored at least one level above that buffer in the tree. If the
buffer is the first or last node in the tree order then one of the delimiting keys may be absent, and in
this case get_lkey and get_rkey return a special key which is MIN_KEY or MAX_KEY. */
-static inline int key_in_buffer(struct path *p_s_chk_path, /* Path which should be checked. */
+static inline int key_in_buffer(struct treepath *p_s_chk_path, /* Path which should be checked. */
const struct cpu_key *p_s_key, /* Key which should be checked. */
struct super_block *p_s_sb /* Super block pointer. */
)
@@ -374,7 +374,7 @@ inline void decrement_bcount(struct buffer_head *p_s_bh)
}
/* Decrement b_count field of the all buffers in the path. */
-void decrement_counters_in_path(struct path *p_s_search_path)
+void decrement_counters_in_path(struct treepath *p_s_search_path)
{
int n_path_offset = p_s_search_path->path_length;
@@ -391,7 +391,7 @@ void decrement_counters_in_path(struct path *p_s_search_path)
p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
}
-int reiserfs_check_path(struct path *p)
+int reiserfs_check_path(struct treepath *p)
{
RFALSE(p->path_length != ILLEGAL_PATH_ELEMENT_OFFSET,
"path not properly relsed");
@@ -403,7 +403,7 @@ int reiserfs_check_path(struct path *p)
**
** only called from fix_nodes()
*/
-void pathrelse_and_restore(struct super_block *s, struct path *p_s_search_path)
+void pathrelse_and_restore(struct super_block *s, struct treepath *p_s_search_path)
{
int n_path_offset = p_s_search_path->path_length;
@@ -421,7 +421,7 @@ void pathrelse_and_restore(struct super_block *s, struct path *p_s_search_path)
}
/* Release all buffers in the path. */
-void pathrelse(struct path *p_s_search_path)
+void pathrelse(struct treepath *p_s_search_path)
{
int n_path_offset = p_s_search_path->path_length;
@@ -602,7 +602,7 @@ static void search_by_key_reada(struct super_block *s,
correctness of the bottom of the path */
/* The function is NOT SCHEDULE-SAFE! */
int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* Key to search. */
- struct path *p_s_search_path, /* This structure was
+ struct treepath *p_s_search_path,/* This structure was
allocated and initialized
by the calling
function. It is filled up
@@ -813,7 +813,7 @@ int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /*
/* The function is NOT SCHEDULE-SAFE! */
int search_for_position_by_key(struct super_block *p_s_sb, /* Pointer to the super block. */
const struct cpu_key *p_cpu_key, /* Key to search (cpu variable) */
- struct path *p_s_search_path /* Filled up by this function. */
+ struct treepath *p_s_search_path /* Filled up by this function. */
)
{
struct item_head *p_le_ih; /* pointer to on-disk structure */
@@ -884,7 +884,7 @@ int search_for_position_by_key(struct super_block *p_s_sb, /* Pointer to the sup
}
/* Compare given item and item pointed to by the path. */
-int comp_items(const struct item_head *stored_ih, const struct path *p_s_path)
+int comp_items(const struct item_head *stored_ih, const struct treepath *p_s_path)
{
struct buffer_head *p_s_bh;
struct item_head *ih;
@@ -911,7 +911,7 @@ int comp_items(const struct item_head *stored_ih, const struct path *p_s_path)
#define block_in_use(bh) (buffer_locked(bh) || (held_by_others(bh)))
// prepare for delete or cut of direct item
-static inline int prepare_for_direct_item(struct path *path,
+static inline int prepare_for_direct_item(struct treepath *path,
struct item_head *le_ih,
struct inode *inode,
loff_t new_file_length, int *cut_size)
@@ -952,7 +952,7 @@ static inline int prepare_for_direct_item(struct path *path,
return M_CUT; /* Cut from this item. */
}
-static inline int prepare_for_direntry_item(struct path *path,
+static inline int prepare_for_direntry_item(struct treepath *path,
struct item_head *le_ih,
struct inode *inode,
loff_t new_file_length,
@@ -987,7 +987,7 @@ static inline int prepare_for_direntry_item(struct path *path,
In case of file truncate calculate whether this item must be deleted/truncated or last
unformatted node of this item will be converted to a direct item.
This function returns a determination of what balance mode the calling function should employ. */
-static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, struct inode *inode, struct path *p_s_path, const struct cpu_key *p_s_item_key, int *p_n_removed, /* Number of unformatted nodes which were removed
+static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, struct inode *inode, struct treepath *p_s_path, const struct cpu_key *p_s_item_key, int *p_n_removed, /* Number of unformatted nodes which were removed
from end of the file. */
int *p_n_cut_size, unsigned long long n_new_file_length /* MAX_KEY_OFFSET in case of delete. */
)
@@ -1125,7 +1125,7 @@ static int calc_deleted_bytes_number(struct tree_balance *p_s_tb, char c_mode)
static void init_tb_struct(struct reiserfs_transaction_handle *th,
struct tree_balance *p_s_tb,
struct super_block *p_s_sb,
- struct path *p_s_path, int n_size)
+ struct treepath *p_s_path, int n_size)
{
BUG_ON(!th->t_trans_id);
@@ -1176,7 +1176,7 @@ char head2type(struct item_head *ih)
#endif
/* Delete object item. */
-int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct path *p_s_path, /* Path to the deleted item. */
+int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_path, /* Path to the deleted item. */
const struct cpu_key *p_s_item_key, /* Key to search for the deleted item. */
struct inode *p_s_inode, /* inode is here just to update i_blocks and quotas */
struct buffer_head *p_s_un_bh)
@@ -1459,7 +1459,7 @@ static void unmap_buffers(struct page *page, loff_t pos)
bh = next;
} while (bh != head);
if (PAGE_SIZE == bh->b_size) {
- clear_page_dirty(page);
+ cancel_dirty_page(page, PAGE_CACHE_SIZE);
}
}
}
@@ -1468,7 +1468,7 @@ static void unmap_buffers(struct page *page, loff_t pos)
static int maybe_indirect_to_direct(struct reiserfs_transaction_handle *th,
struct inode *p_s_inode,
struct page *page,
- struct path *p_s_path,
+ struct treepath *p_s_path,
const struct cpu_key *p_s_item_key,
loff_t n_new_file_size, char *p_c_mode)
{
@@ -1503,7 +1503,7 @@ static int maybe_indirect_to_direct(struct reiserfs_transaction_handle *th,
pointer being converted. Therefore we have to delete inserted
direct item(s) */
static void indirect_to_direct_roll_back(struct reiserfs_transaction_handle *th,
- struct inode *inode, struct path *path)
+ struct inode *inode, struct treepath *path)
{
struct cpu_key tail_key;
int tail_len;
@@ -1545,7 +1545,7 @@ static void indirect_to_direct_roll_back(struct reiserfs_transaction_handle *th,
/* (Truncate or cut entry) or delete object item. Returns < 0 on failure */
int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
- struct path *p_s_path,
+ struct treepath *p_s_path,
struct cpu_key *p_s_item_key,
struct inode *p_s_inode,
struct page *page, loff_t n_new_file_size)
@@ -1920,7 +1920,7 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p
#ifdef CONFIG_REISERFS_CHECK
// this makes sure, that we __append__, not overwrite or add holes
-static void check_research_for_paste(struct path *path,
+static void check_research_for_paste(struct treepath *path,
const struct cpu_key *p_s_key)
{
struct item_head *found_ih = get_ih(path);
@@ -1954,7 +1954,7 @@ static void check_research_for_paste(struct path *path,
#endif /* config reiserfs check */
/* Paste bytes to the existing item. Returns bytes number pasted into the item. */
-int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct path *p_s_search_path, /* Path to the pasted item. */
+int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_search_path, /* Path to the pasted item. */
const struct cpu_key *p_s_key, /* Key to search for the needed item. */
struct inode *inode, /* Inode item belongs to */
const char *p_c_body, /* Pointer to the bytes to paste. */
@@ -2036,7 +2036,7 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct path
}
/* Insert new item into the buffer at the path. */
-int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct path *p_s_path, /* Path to the inserteded item. */
+int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_path, /* Path to the inserteded item. */
const struct cpu_key *key, struct item_head *p_s_ih, /* Pointer to the item header to insert. */
struct inode *inode, const char *p_c_body)
{ /* Pointer to the bytes to insert. */
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 7fb5fb036f9..58ad4551a7c 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -23,7 +23,7 @@
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/quotaops.h>
diff --git a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c
index 36f108fc1cf..f8121a1147e 100644
--- a/fs/reiserfs/tail_conversion.c
+++ b/fs/reiserfs/tail_conversion.c
@@ -15,7 +15,7 @@
/* path points to first direct item of the file regarless of how many of
them are there */
int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
- struct path *path, struct buffer_head *unbh,
+ struct treepath *path, struct buffer_head *unbh,
loff_t tail_offset)
{
struct super_block *sb = inode->i_sb;
@@ -171,7 +171,7 @@ void reiserfs_unmap_buffer(struct buffer_head *bh)
what we expect from it (number of cut bytes). But when tail remains
in the unformatted node, we set mode to SKIP_BALANCING and unlock
inode */
-int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, struct page *page, struct path *p_s_path, /* path to the indirect item. */
+int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, struct page *page, struct treepath *p_s_path, /* path to the indirect item. */
const struct cpu_key *p_s_item_key, /* Key to look for unformatted node pointer to be cut. */
loff_t n_new_file_size, /* New file size. */
char *p_c_mode)
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 1e4d6859017..f01389fd162 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -274,7 +274,7 @@ static struct file *open_xa_file(const struct inode *inode, const char *name,
*/
static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
INITIALIZE_PATH(path_to_entry);
struct buffer_head *bh;
@@ -420,7 +420,7 @@ static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir)
static
int xattr_readdir(struct file *file, filldir_t filler, void *buf)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int res = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
goto out;
@@ -508,7 +508,7 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
goto out;
}
- xinode = fp->f_dentry->d_inode;
+ xinode = fp->f_path.dentry->d_inode;
REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
/* we need to copy it off.. */
@@ -527,7 +527,7 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
newattrs.ia_size = buffer_size;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
mutex_lock(&xinode->i_mutex);
- err = notify_change(fp->f_dentry, &newattrs);
+ err = notify_change(fp->f_path.dentry, &newattrs);
if (err)
goto out_filp;
@@ -626,7 +626,7 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
goto out;
}
- xinode = fp->f_dentry->d_inode;
+ xinode = fp->f_path.dentry->d_inode;
isize = xinode->i_size;
REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index 97ae1b92bc4..5296a29cc5e 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -135,7 +135,7 @@ static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
int n;
*size = reiserfs_acl_size(acl->a_count);
- ext_acl = (reiserfs_acl_header *) kmalloc(sizeof(reiserfs_acl_header) +
+ ext_acl = kmalloc(sizeof(reiserfs_acl_header) +
acl->a_count *
sizeof(reiserfs_acl_entry),
GFP_NOFS);
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index c5af088d4a4..d3e243a6f60 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -276,7 +276,7 @@ static unsigned char romfs_dtype_table[] = {
static int
romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *i = filp->f_dentry->d_inode;
+ struct inode *i = filp->f_path.dentry->d_inode;
struct romfs_inode ri;
unsigned long offset, maxoff;
int j, ino, nextfh;
diff --git a/fs/select.c b/fs/select.c
index dcbc1112b7e..fe0893afd93 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -311,7 +311,7 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
{
fd_set_bits fds;
void *bits;
- int ret, max_fdset;
+ int ret, max_fds;
unsigned int size;
struct fdtable *fdt;
/* Allocate small arguments on the stack to save memory and be faster */
@@ -321,13 +321,13 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
if (n < 0)
goto out_nofds;
- /* max_fdset can increase, so grab it once to avoid race */
+ /* max_fds can increase, so grab it once to avoid race */
rcu_read_lock();
fdt = files_fdtable(current->files);
- max_fdset = fdt->max_fdset;
+ max_fds = fdt->max_fds;
rcu_read_unlock();
- if (n > max_fdset)
- n = max_fdset;
+ if (n > max_fds)
+ n = max_fds;
/*
* We need 6 bitmaps (in/out/ex for both incoming and outgoing),
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 10690aa401c..0ac22af7afe 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -269,7 +269,7 @@ EXPORT_SYMBOL(seq_lseek);
/**
* seq_release - free the structures associated with sequential file.
* @file: file in question
- * @inode: file->f_dentry->d_inode
+ * @inode: file->f_path.dentry->d_inode
*
* Frees the structures associated with sequential file; can be used
* as ->f_op->release() if you don't have private data to destroy.
diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c
index 74b86d9725a..8182f0542a2 100644
--- a/fs/smbfs/cache.c
+++ b/fs/smbfs/cache.c
@@ -125,7 +125,7 @@ smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
struct smb_cache_control *ctrl, struct qstr *qname,
struct smb_fattr *entry)
{
- struct dentry *newdent, *dentry = filp->f_dentry;
+ struct dentry *newdent, *dentry = filp->f_path.dentry;
struct inode *newino, *inode = dentry->d_inode;
struct smb_cache_control ctl = *ctrl;
int valid = 0;
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 70d9c5a37f5..b1e58d1ac9c 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -78,7 +78,7 @@ struct inode_operations smb_dir_inode_operations_unix =
static int
smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *dir = dentry->d_inode;
struct smb_sb_info *server = server_from_dentry(dentry);
union smb_dir_cache *cache = NULL;
@@ -238,12 +238,12 @@ out:
static int
smb_dir_open(struct inode *dir, struct file *file)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct smb_sb_info *server;
int error = 0;
VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name,
- file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.name);
/*
* Directory timestamps in the core protocol aren't updated
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 50784d13c87..e50533a7951 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -102,7 +102,7 @@ static int
smb_readpage(struct file *file, struct page *page)
{
int error;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
page_cache_get(page);
error = smb_readpage_sync(dentry, page);
@@ -205,7 +205,7 @@ static int
smb_updatepage(struct file *file, struct page *page, unsigned long offset,
unsigned int count)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
DEBUG1("(%s/%s %d@%lld)\n", DENTRY_PATH(dentry), count,
((unsigned long long)page->index << PAGE_CACHE_SHIFT) + offset);
@@ -218,7 +218,7 @@ 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;
+ struct dentry * dentry = file->f_path.dentry;
ssize_t status;
VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry),
@@ -243,7 +243,7 @@ out:
static int
smb_file_mmap(struct file * file, struct vm_area_struct * vma)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
int status;
VERBOSE("file %s/%s, address %lu - %lu\n",
@@ -264,7 +264,7 @@ static ssize_t
smb_file_sendfile(struct file *file, loff_t *ppos,
size_t count, read_actor_t actor, void *target)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
ssize_t status;
VERBOSE("file %s/%s, pos=%Ld, count=%d\n",
@@ -323,7 +323,7 @@ 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;
+ struct dentry * dentry = file->f_path.dentry;
ssize_t result;
VERBOSE("file %s/%s, count=%lu@%lu\n",
@@ -355,7 +355,7 @@ static int
smb_file_open(struct inode *inode, struct file * file)
{
int result;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
int smb_mode = (file->f_mode & O_ACCMODE) - 1;
lock_kernel();
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 4af4cd729a5..84dfe3f3482 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -482,12 +482,13 @@ smb_put_super(struct super_block *sb)
smb_close_socket(server);
if (server->conn_pid)
- kill_proc(server->conn_pid, SIGTERM, 1);
+ kill_pid(server->conn_pid, SIGTERM, 1);
kfree(server->ops);
smb_unload_nls(server);
sb->s_fs_info = NULL;
smb_unlock_server(server);
+ put_pid(server->conn_pid);
kfree(server);
}
@@ -530,7 +531,7 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
INIT_LIST_HEAD(&server->xmitq);
INIT_LIST_HEAD(&server->recvq);
server->conn_error = 0;
- server->conn_pid = 0;
+ server->conn_pid = NULL;
server->state = CONN_INVALID; /* no connection yet */
server->generation = 0;
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index 40e174db987..feac4605061 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -873,11 +873,11 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
filp = fget(opt->fd);
if (!filp)
goto out;
- if (!smb_valid_socket(filp->f_dentry->d_inode))
+ if (!smb_valid_socket(filp->f_path.dentry->d_inode))
goto out_putf;
server->sock_file = filp;
- server->conn_pid = current->pid;
+ server->conn_pid = get_pid(task_pid(current));
server->opt = *opt;
server->generation += 1;
server->state = CONN_VALID;
@@ -898,7 +898,7 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
/*
* Store the server in sock user_data (Only used by sunrpc)
*/
- sk = SOCKET_I(filp->f_dentry->d_inode)->sk;
+ sk = SOCKET_I(filp->f_path.dentry->d_inode)->sk;
sk->sk_user_data = server;
/* chain into the data_ready callback */
@@ -971,8 +971,8 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
}
VERBOSE("protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n",
- server->opt.protocol, server->opt.max_xmit, server->conn_pid,
- server->opt.capabilities);
+ server->opt.protocol, server->opt.max_xmit,
+ pid_nr(server->conn_pid), server->opt.capabilities);
/* FIXME: this really should be done by smbmount. */
if (server->opt.max_xmit > SMB_MAX_PACKET_SIZE) {
@@ -1939,7 +1939,7 @@ static int
smb_proc_readdir_short(struct file *filp, void *dirent, filldir_t filldir,
struct smb_cache_control *ctl)
{
- struct dentry *dir = filp->f_dentry;
+ struct dentry *dir = filp->f_path.dentry;
struct smb_sb_info *server = server_from_dentry(dir);
struct qstr qname;
struct smb_fattr fattr;
@@ -2291,7 +2291,7 @@ static int
smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir,
struct smb_cache_control *ctl)
{
- struct dentry *dir = filp->f_dentry;
+ struct dentry *dir = filp->f_path.dentry;
struct smb_sb_info *server = server_from_dentry(dir);
struct qstr qname;
struct smb_fattr fattr;
@@ -2859,7 +2859,7 @@ static int
smb_proc_readdir_null(struct file *filp, void *dirent, filldir_t filldir,
struct smb_cache_control *ctl)
{
- struct smb_sb_info *server = server_from_dentry(filp->f_dentry);
+ struct smb_sb_info *server = server_from_dentry(filp->f_path.dentry);
if (smb_proc_ops_wait(server) < 0)
return -EIO;
diff --git a/fs/smbfs/smbiod.c b/fs/smbfs/smbiod.c
index e6754044128..89eaf31f1d4 100644
--- a/fs/smbfs/smbiod.c
+++ b/fs/smbfs/smbiod.c
@@ -152,7 +152,7 @@ int smbiod_retry(struct smb_sb_info *server)
{
struct list_head *head;
struct smb_request *req;
- pid_t pid = server->conn_pid;
+ struct pid *pid = get_pid(server->conn_pid);
int result = 0;
VERBOSE("state: %d\n", server->state);
@@ -222,7 +222,7 @@ int smbiod_retry(struct smb_sb_info *server)
/*
* Note: use the "priv" flag, as a user process may need to reconnect.
*/
- result = kill_proc(pid, SIGUSR1, 1);
+ result = kill_pid(pid, SIGUSR1, 1);
if (result) {
/* FIXME: this is most likely fatal, umount? */
printk(KERN_ERR "smb_retry: signal failed [%d]\n", result);
@@ -233,6 +233,7 @@ int smbiod_retry(struct smb_sb_info *server)
/* FIXME: The retried requests should perhaps get a "time boost". */
out:
+ put_pid(pid);
return result;
}
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c
index 6815b1b12b6..92ea6b2367d 100644
--- a/fs/smbfs/sock.c
+++ b/fs/smbfs/sock.c
@@ -82,10 +82,10 @@ server_sock(struct smb_sb_info *server)
if (server && (file = server->sock_file))
{
#ifdef SMBFS_PARANOIA
- if (!smb_valid_socket(file->f_dentry->d_inode))
+ if (!smb_valid_socket(file->f_path.dentry->d_inode))
PARANOIA("bad socket!\n");
#endif
- return SOCKET_I(file->f_dentry->d_inode);
+ return SOCKET_I(file->f_path.dentry->d_inode);
}
return NULL;
}
diff --git a/fs/splice.c b/fs/splice.c
index da74583a00e..2fca6ebf4cc 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -42,7 +42,7 @@ struct splice_pipe_desc {
struct partial_page *partial; /* pages[] may not be contig */
int nr_pages; /* number of pages in map */
unsigned int flags; /* splice flags */
- struct pipe_buf_operations *ops;/* ops associated with output pipe */
+ const struct pipe_buf_operations *ops;/* ops associated with output pipe */
};
/*
@@ -139,7 +139,7 @@ error:
return err;
}
-static struct pipe_buf_operations page_cache_pipe_buf_ops = {
+static const struct pipe_buf_operations page_cache_pipe_buf_ops = {
.can_merge = 0,
.map = generic_pipe_buf_map,
.unmap = generic_pipe_buf_unmap,
@@ -159,7 +159,7 @@ static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe,
return generic_pipe_buf_steal(pipe, buf);
}
-static struct pipe_buf_operations user_page_pipe_buf_ops = {
+static const struct pipe_buf_operations user_page_pipe_buf_ops = {
.can_merge = 0,
.map = generic_pipe_buf_map,
.unmap = generic_pipe_buf_unmap,
@@ -724,7 +724,7 @@ static ssize_t __splice_from_pipe(struct pipe_inode_info *pipe,
for (;;) {
if (pipe->nrbufs) {
struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
- struct pipe_buf_operations *ops = buf->ops;
+ const struct pipe_buf_operations *ops = buf->ops;
sd.len = buf->len;
if (sd.len > sd.total_len)
@@ -844,7 +844,7 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out,
ssize_t ret;
int err;
- err = remove_suid(out->f_dentry);
+ err = remove_suid(out->f_path.dentry);
if (unlikely(err))
return err;
@@ -890,10 +890,10 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
ssize_t ret;
int err;
- err = should_remove_suid(out->f_dentry);
+ err = should_remove_suid(out->f_path.dentry);
if (unlikely(err)) {
mutex_lock(&inode->i_mutex);
- err = __remove_suid(out->f_dentry, err);
+ err = __remove_suid(out->f_path.dentry, err);
mutex_unlock(&inode->i_mutex);
if (err)
return err;
@@ -1008,7 +1008,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
* randomly drop data for eg socket -> socket splicing. Use the
* piped splicing for that!
*/
- i_mode = in->f_dentry->d_inode->i_mode;
+ i_mode = in->f_path.dentry->d_inode->i_mode;
if (unlikely(!S_ISREG(i_mode) && !S_ISBLK(i_mode)))
return -EINVAL;
@@ -1132,7 +1132,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
loff_t offset, *off;
long ret;
- pipe = pipe_info(in->f_dentry->d_inode);
+ pipe = pipe_info(in->f_path.dentry->d_inode);
if (pipe) {
if (off_in)
return -ESPIPE;
@@ -1153,7 +1153,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
return ret;
}
- pipe = pipe_info(out->f_dentry->d_inode);
+ pipe = pipe_info(out->f_path.dentry->d_inode);
if (pipe) {
if (off_out)
return -ESPIPE;
@@ -1321,7 +1321,7 @@ static long do_vmsplice(struct file *file, const struct iovec __user *iov,
.ops = &user_page_pipe_buf_ops,
};
- pipe = pipe_info(file->f_dentry->d_inode);
+ pipe = pipe_info(file->f_path.dentry->d_inode);
if (!pipe)
return -EBADF;
if (unlikely(nr_segs > UIO_MAXIOV))
@@ -1549,8 +1549,8 @@ static int link_pipe(struct pipe_inode_info *ipipe,
static long do_tee(struct file *in, struct file *out, size_t len,
unsigned int flags)
{
- struct pipe_inode_info *ipipe = pipe_info(in->f_dentry->d_inode);
- struct pipe_inode_info *opipe = pipe_info(out->f_dentry->d_inode);
+ struct pipe_inode_info *ipipe = pipe_info(in->f_path.dentry->d_inode);
+ struct pipe_inode_info *opipe = pipe_info(out->f_path.dentry->d_inode);
int ret = -EINVAL;
/*
diff --git a/fs/stack.c b/fs/stack.c
new file mode 100644
index 00000000000..8ffb880d2f4
--- /dev/null
+++ b/fs/stack.c
@@ -0,0 +1,38 @@
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/fs_stack.h>
+
+/* does _NOT_ require i_mutex to be held.
+ *
+ * This function cannot be inlined since i_size_{read,write} is rather
+ * heavy-weight on 32-bit systems
+ */
+void fsstack_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;
+}
+EXPORT_SYMBOL_GPL(fsstack_copy_inode_size);
+
+/* copy all attributes; get_nlinks is optional way to override the i_nlink
+ * copying
+ */
+void fsstack_copy_attr_all(struct inode *dest, const struct inode *src,
+ int (*get_nlinks)(struct inode *))
+{
+ if (!get_nlinks)
+ dest->i_nlink = src->i_nlink;
+ else
+ dest->i_nlink = (*get_nlinks)(dest);
+
+ dest->i_mode = src->i_mode;
+ 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;
+}
+EXPORT_SYMBOL_GPL(fsstack_copy_attr_all);
diff --git a/fs/stat.c b/fs/stat.c
index a0ebfc7f8a6..38a8cb2a28d 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -102,7 +102,7 @@ int vfs_fstat(unsigned int fd, struct kstat *stat)
int error = -EBADF;
if (f) {
- error = vfs_getattr(f->f_vfsmnt, f->f_dentry, stat);
+ error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
fput(f);
}
return error;
diff --git a/fs/super.c b/fs/super.c
index 84c320f6ad7..3e7458c2bb7 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -570,7 +570,7 @@ static void mark_files_ro(struct super_block *sb)
file_list_lock();
list_for_each_entry(f, &sb->s_files, f_u.fu_list) {
- if (S_ISREG(f->f_dentry->d_inode->i_mode) && file_count(f))
+ if (S_ISREG(f->f_path.dentry->d_inode->i_mode) && file_count(f))
f->f_mode &= ~FMODE_WRITE;
}
file_list_unlock();
@@ -753,9 +753,9 @@ int get_sb_bdev(struct file_system_type *fs_type,
* will protect the lockfs code from trying to start a snapshot
* while we are mounting
*/
- mutex_lock(&bdev->bd_mount_mutex);
+ down(&bdev->bd_mount_sem);
s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
- mutex_unlock(&bdev->bd_mount_mutex);
+ up(&bdev->bd_mount_sem);
if (IS_ERR(s))
goto error_s;
diff --git a/fs/sync.c b/fs/sync.c
index 865f32be386..d0feff61e6a 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -94,7 +94,7 @@ long do_fsync(struct file *file, int datasync)
* livelocks in fsync_buffers_list().
*/
mutex_lock(&mapping->host->i_mutex);
- err = file->f_op->fsync(file, file->f_dentry, datasync);
+ err = file->f_op->fsync(file, file->f_path.dentry, datasync);
if (!ret)
ret = err;
mutex_unlock(&mapping->host->i_mutex);
@@ -223,7 +223,7 @@ asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
if (!file)
goto out;
- i_mode = file->f_dentry->d_inode->i_mode;
+ i_mode = file->f_path.dentry->d_inode->i_mode;
ret = -ESPIPE;
if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) &&
!S_ISLNK(i_mode))
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 98022e41cda..d3b9f5f07db 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <asm/uaccess.h>
+#include <asm/semaphore.h>
#include "sysfs.h"
@@ -35,7 +36,7 @@ static ssize_t
read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
{
char *buffer = file->private_data;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
int size = dentry->d_inode->i_size;
loff_t offs = *off;
int ret;
@@ -81,7 +82,7 @@ static ssize_t write(struct file * file, const char __user * userbuf,
size_t count, loff_t * off)
{
char *buffer = file->private_data;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
int size = dentry->d_inode->i_size;
loff_t offs = *off;
@@ -105,7 +106,7 @@ static ssize_t write(struct file * file, const char __user * userbuf,
static int mmap(struct file *file, struct vm_area_struct *vma)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct bin_attribute *attr = to_bin_attr(dentry);
struct kobject *kobj = to_kobj(dentry->d_parent);
@@ -117,8 +118,8 @@ static int mmap(struct file *file, struct vm_area_struct *vma)
static int open(struct inode * inode, struct file * file)
{
- struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
- struct bin_attribute * attr = to_bin_attr(file->f_dentry);
+ struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
+ struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
int error = -EINVAL;
if (!kobj || !attr)
@@ -146,19 +147,18 @@ static int open(struct inode * inode, struct file * file)
Error:
module_put(attr->attr.owner);
Done:
- if (error && kobj)
+ if (error)
kobject_put(kobj);
return error;
}
static int release(struct inode * inode, struct file * file)
{
- struct kobject * kobj = to_kobj(file->f_dentry->d_parent);
- struct bin_attribute * attr = to_bin_attr(file->f_dentry);
+ struct kobject * kobj = to_kobj(file->f_path.dentry->d_parent);
+ struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
u8 * buffer = file->private_data;
- if (kobj)
- kobject_put(kobj);
+ kobject_put(kobj);
module_put(attr->attr.owner);
kfree(buffer);
return 0;
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index a5782e8c7f0..9dcdf556c99 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/namei.h>
+#include <asm/semaphore.h>
#include "sysfs.h"
DECLARE_RWSEM(sysfs_rename_sem);
@@ -32,8 +33,7 @@ static struct dentry_operations sysfs_dentry_ops = {
/*
* Allocates a new sysfs_dirent and links it to the parent sysfs_dirent
*/
-static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
- void * element)
+static struct sysfs_dirent * __sysfs_new_dirent(void * element)
{
struct sysfs_dirent * sd;
@@ -45,12 +45,28 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
atomic_set(&sd->s_count, 1);
atomic_set(&sd->s_event, 1);
INIT_LIST_HEAD(&sd->s_children);
- list_add(&sd->s_sibling, &parent_sd->s_children);
+ INIT_LIST_HEAD(&sd->s_sibling);
sd->s_element = element;
return sd;
}
+static void __sysfs_list_dirent(struct sysfs_dirent *parent_sd,
+ struct sysfs_dirent *sd)
+{
+ if (sd)
+ list_add(&sd->s_sibling, &parent_sd->s_children);
+}
+
+static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent *parent_sd,
+ void * element)
+{
+ struct sysfs_dirent *sd;
+ sd = __sysfs_new_dirent(element);
+ __sysfs_list_dirent(parent_sd, sd);
+ return sd;
+}
+
/*
*
* Return -EEXIST if there is already a sysfs element with the same name for
@@ -77,14 +93,14 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
}
-int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
- void * element, umode_t mode, int type)
+static struct sysfs_dirent *
+__sysfs_make_dirent(struct dentry *dentry, void *element, mode_t mode, int type)
{
struct sysfs_dirent * sd;
- sd = sysfs_new_dirent(parent_sd, element);
+ sd = __sysfs_new_dirent(element);
if (!sd)
- return -ENOMEM;
+ goto out;
sd->s_mode = mode;
sd->s_type = type;
@@ -94,7 +110,19 @@ int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
dentry->d_op = &sysfs_dentry_ops;
}
- return 0;
+out:
+ return sd;
+}
+
+int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
+ void * element, umode_t mode, int type)
+{
+ struct sysfs_dirent *sd;
+
+ sd = __sysfs_make_dirent(dentry, element, mode, type);
+ __sysfs_list_dirent(parent_sd, sd);
+
+ return sd ? 0 : -ENOMEM;
}
static int init_dir(struct inode * inode)
@@ -165,11 +193,11 @@ int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d)
/**
* sysfs_create_dir - create a directory for an object.
- * @parent: parent parent object.
* @kobj: object we're creating directory for.
+ * @shadow_parent: parent parent object.
*/
-int sysfs_create_dir(struct kobject * kobj)
+int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)
{
struct dentry * dentry = NULL;
struct dentry * parent;
@@ -177,7 +205,9 @@ int sysfs_create_dir(struct kobject * kobj)
BUG_ON(!kobj);
- if (kobj->parent)
+ if (shadow_parent)
+ parent = shadow_parent;
+ else if (kobj->parent)
parent = kobj->parent->dentry;
else if (sysfs_mount && sysfs_mount->mnt_sb)
parent = sysfs_mount->mnt_sb->s_root;
@@ -298,21 +328,12 @@ void sysfs_remove_subdir(struct dentry * d)
}
-/**
- * sysfs_remove_dir - remove an object's directory.
- * @kobj: object.
- *
- * The only thing special about this is that we remove any files in
- * the directory before we remove the directory, and we've inlined
- * what used to be sysfs_rmdir() below, instead of calling separately.
- */
-
-void sysfs_remove_dir(struct kobject * kobj)
+static void __sysfs_remove_dir(struct dentry *dentry)
{
- struct dentry * dentry = dget(kobj->dentry);
struct sysfs_dirent * parent_sd;
struct sysfs_dirent * sd, * tmp;
+ dget(dentry);
if (!dentry)
return;
@@ -333,32 +354,60 @@ void sysfs_remove_dir(struct kobject * kobj)
* Drop reference from dget() on entrance.
*/
dput(dentry);
+}
+
+/**
+ * sysfs_remove_dir - remove an object's directory.
+ * @kobj: object.
+ *
+ * The only thing special about this is that we remove any files in
+ * the directory before we remove the directory, and we've inlined
+ * what used to be sysfs_rmdir() below, instead of calling separately.
+ */
+
+void sysfs_remove_dir(struct kobject * kobj)
+{
+ __sysfs_remove_dir(kobj->dentry);
kobj->dentry = NULL;
}
-int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
+int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
+ const char *new_name)
{
int error = 0;
- struct dentry * new_dentry, * parent;
-
- if (!strcmp(kobject_name(kobj), new_name))
- return -EINVAL;
+ struct dentry * new_dentry;
- if (!kobj->parent)
- return -EINVAL;
+ if (!new_parent)
+ return -EFAULT;
down_write(&sysfs_rename_sem);
- parent = kobj->parent->dentry;
-
- mutex_lock(&parent->d_inode->i_mutex);
+ mutex_lock(&new_parent->d_inode->i_mutex);
- new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
+ new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
if (!IS_ERR(new_dentry)) {
- if (!new_dentry->d_inode) {
+ /* By allowing two different directories with the
+ * same d_parent we allow this routine to move
+ * between different shadows of the same directory
+ */
+ if (kobj->dentry->d_parent->d_inode != new_parent->d_inode)
+ return -EINVAL;
+ else if (new_dentry->d_parent->d_inode != new_parent->d_inode)
+ error = -EINVAL;
+ else if (new_dentry == kobj->dentry)
+ error = -EINVAL;
+ else if (!new_dentry->d_inode) {
error = kobject_set_name(kobj, "%s", new_name);
if (!error) {
+ struct sysfs_dirent *sd, *parent_sd;
+
d_add(new_dentry, NULL);
d_move(kobj->dentry, new_dentry);
+
+ sd = kobj->dentry->d_fsdata;
+ parent_sd = new_parent->d_fsdata;
+
+ list_del_init(&sd->s_sibling);
+ list_add(&sd->s_sibling, &parent_sd->s_children);
}
else
d_drop(new_dentry);
@@ -366,7 +415,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
error = -EEXIST;
dput(new_dentry);
}
- mutex_unlock(&parent->d_inode->i_mutex);
+ mutex_unlock(&new_parent->d_inode->i_mutex);
up_write(&sysfs_rename_sem);
return error;
@@ -378,12 +427,10 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent)
struct sysfs_dirent *new_parent_sd, *sd;
int error;
- if (!new_parent)
- return -EINVAL;
-
old_parent_dentry = kobj->parent ?
kobj->parent->dentry : sysfs_mount->mnt_sb->s_root;
- new_parent_dentry = new_parent->dentry;
+ new_parent_dentry = new_parent ?
+ new_parent->dentry : sysfs_mount->mnt_sb->s_root;
again:
mutex_lock(&old_parent_dentry->d_inode->i_mutex);
@@ -419,7 +466,7 @@ out:
static int sysfs_dir_open(struct inode *inode, struct file *file)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
mutex_lock(&dentry->d_inode->i_mutex);
@@ -432,7 +479,7 @@ static int sysfs_dir_open(struct inode *inode, struct file *file)
static int sysfs_dir_close(struct inode *inode, struct file *file)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
struct sysfs_dirent * cursor = file->private_data;
mutex_lock(&dentry->d_inode->i_mutex);
@@ -452,7 +499,7 @@ static inline unsigned char dt_type(struct sysfs_dirent *sd)
static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
struct sysfs_dirent *cursor = filp->private_data;
struct list_head *p, *q = &cursor->s_sibling;
@@ -509,7 +556,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
mutex_lock(&dentry->d_inode->i_mutex);
switch (origin) {
@@ -519,7 +566,7 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
if (offset >= 0)
break;
default:
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return -EINVAL;
}
if (offset != file->f_pos) {
@@ -547,6 +594,95 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
return offset;
}
+
+/**
+ * sysfs_make_shadowed_dir - Setup so a directory can be shadowed
+ * @kobj: object we're creating shadow of.
+ */
+
+int sysfs_make_shadowed_dir(struct kobject *kobj,
+ void * (*follow_link)(struct dentry *, struct nameidata *))
+{
+ struct inode *inode;
+ struct inode_operations *i_op;
+
+ inode = kobj->dentry->d_inode;
+ if (inode->i_op != &sysfs_dir_inode_operations)
+ return -EINVAL;
+
+ i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
+ if (!i_op)
+ return -ENOMEM;
+
+ memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
+ i_op->follow_link = follow_link;
+
+ /* Locking of inode->i_op?
+ * Since setting i_op is a single word write and they
+ * are atomic we should be ok here.
+ */
+ inode->i_op = i_op;
+ return 0;
+}
+
+/**
+ * sysfs_create_shadow_dir - create a shadow directory for an object.
+ * @kobj: object we're creating directory for.
+ *
+ * sysfs_make_shadowed_dir must already have been called on this
+ * directory.
+ */
+
+struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)
+{
+ struct sysfs_dirent *sd;
+ struct dentry *parent, *dir, *shadow;
+ struct inode *inode;
+
+ dir = kobj->dentry;
+ inode = dir->d_inode;
+ parent = dir->d_parent;
+ shadow = ERR_PTR(-EINVAL);
+ if (!sysfs_is_shadowed_inode(inode))
+ goto out;
+
+ shadow = d_alloc(parent, &dir->d_name);
+ if (!shadow)
+ goto nomem;
+
+ sd = __sysfs_make_dirent(shadow, kobj, inode->i_mode, SYSFS_DIR);
+ if (!sd)
+ goto nomem;
+
+ d_instantiate(shadow, igrab(inode));
+ inc_nlink(inode);
+ inc_nlink(parent->d_inode);
+ shadow->d_op = &sysfs_dentry_ops;
+
+ dget(shadow); /* Extra count - pin the dentry in core */
+
+out:
+ return shadow;
+nomem:
+ dput(shadow);
+ shadow = ERR_PTR(-ENOMEM);
+ goto out;
+}
+
+/**
+ * sysfs_remove_shadow_dir - remove an object's directory.
+ * @shadow: dentry of shadow directory
+ *
+ * The only thing special about this is that we remove any files in
+ * the directory before we remove the directory, and we've inlined
+ * what used to be sysfs_rmdir() below, instead of calling separately.
+ */
+
+void sysfs_remove_shadow_dir(struct dentry *shadow)
+{
+ __sysfs_remove_dir(shadow);
+}
+
const struct file_operations sysfs_dir_operations = {
.open = sysfs_dir_open,
.release = sysfs_dir_close,
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 95c165101c9..c0e117649a4 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -7,6 +7,7 @@
#include <linux/kobject.h>
#include <linux/namei.h>
#include <linux/poll.h>
+#include <linux/list.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
@@ -50,17 +51,29 @@ static struct sysfs_ops subsys_sysfs_ops = {
.store = subsys_attr_store,
};
+/**
+ * add_to_collection - add buffer to a collection
+ * @buffer: buffer to be added
+ * @node inode of set to add to
+ */
-struct sysfs_buffer {
- size_t count;
- loff_t pos;
- char * page;
- struct sysfs_ops * ops;
- struct semaphore sem;
- int needs_read_fill;
- int event;
-};
+static inline void
+add_to_collection(struct sysfs_buffer *buffer, struct inode *node)
+{
+ struct sysfs_buffer_collection *set = node->i_private;
+ mutex_lock(&node->i_mutex);
+ list_add(&buffer->associates, &set->associates);
+ mutex_unlock(&node->i_mutex);
+}
+
+static inline void
+remove_from_collection(struct sysfs_buffer *buffer, struct inode *node)
+{
+ mutex_lock(&node->i_mutex);
+ list_del(&buffer->associates);
+ mutex_unlock(&node->i_mutex);
+}
/**
* fill_read_buffer - allocate and fill buffer from object.
@@ -70,7 +83,8 @@ struct sysfs_buffer {
* Allocate @buffer->page, if it hasn't been already, then call the
* kobject's show() method to fill the buffer with this attribute's
* data.
- * This is called only once, on the file's first read.
+ * This is called only once, on the file's first read unless an error
+ * is returned.
*/
static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
{
@@ -88,12 +102,13 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
buffer->event = atomic_read(&sd->s_event);
count = ops->show(kobj,attr,buffer->page);
- buffer->needs_read_fill = 0;
BUG_ON(count > (ssize_t)PAGE_SIZE);
- if (count >= 0)
+ if (count >= 0) {
+ buffer->needs_read_fill = 0;
buffer->count = count;
- else
+ } else {
ret = count;
+ }
return ret;
}
@@ -153,8 +168,12 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
ssize_t retval = 0;
down(&buffer->sem);
+ if (buffer->orphaned) {
+ retval = -ENODEV;
+ goto out;
+ }
if (buffer->needs_read_fill) {
- if ((retval = fill_read_buffer(file->f_dentry,buffer)))
+ if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
goto out;
}
pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
@@ -165,7 +184,6 @@ out:
return retval;
}
-
/**
* fill_write_buffer - copy buffer from userspace.
* @buffer: data buffer for file.
@@ -243,19 +261,25 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t
ssize_t len;
down(&buffer->sem);
+ if (buffer->orphaned) {
+ len = -ENODEV;
+ goto out;
+ }
len = fill_write_buffer(buffer, buf, count);
if (len > 0)
- len = flush_write_buffer(file->f_dentry, buffer, len);
+ len = flush_write_buffer(file->f_path.dentry, buffer, len);
if (len > 0)
*ppos += len;
+out:
up(&buffer->sem);
return len;
}
-static int check_perm(struct inode * inode, struct file * file)
+static int sysfs_open_file(struct inode *inode, struct file *file)
{
- struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
- struct attribute * attr = to_attr(file->f_dentry);
+ struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
+ struct attribute * attr = to_attr(file->f_path.dentry);
+ struct sysfs_buffer_collection *set;
struct sysfs_buffer * buffer;
struct sysfs_ops * ops = NULL;
int error = 0;
@@ -285,6 +309,18 @@ static int check_perm(struct inode * inode, struct file * file)
if (!ops)
goto Eaccess;
+ /* make sure we have a collection to add our buffers to */
+ mutex_lock(&inode->i_mutex);
+ if (!(set = inode->i_private)) {
+ if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) {
+ error = -ENOMEM;
+ goto Done;
+ } else {
+ INIT_LIST_HEAD(&set->associates);
+ }
+ }
+ mutex_unlock(&inode->i_mutex);
+
/* File needs write support.
* The inode's perms must say it's ok,
* and we must have a store method.
@@ -310,9 +346,11 @@ static int check_perm(struct inode * inode, struct file * file)
*/
buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
if (buffer) {
+ INIT_LIST_HEAD(&buffer->associates);
init_MUTEX(&buffer->sem);
buffer->needs_read_fill = 1;
buffer->ops = ops;
+ add_to_collection(buffer, inode);
file->private_data = buffer;
} else
error = -ENOMEM;
@@ -325,25 +363,21 @@ static int check_perm(struct inode * inode, struct file * file)
error = -EACCES;
module_put(attr->owner);
Done:
- if (error && kobj)
+ if (error)
kobject_put(kobj);
return error;
}
-static int sysfs_open_file(struct inode * inode, struct file * filp)
-{
- return check_perm(inode,filp);
-}
-
static int sysfs_release(struct inode * inode, struct file * filp)
{
- struct kobject * kobj = to_kobj(filp->f_dentry->d_parent);
- struct attribute * attr = to_attr(filp->f_dentry);
+ struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
+ struct attribute * attr = to_attr(filp->f_path.dentry);
struct module * owner = attr->owner;
struct sysfs_buffer * buffer = filp->private_data;
- if (kobj)
- kobject_put(kobj);
+ if (buffer)
+ remove_from_collection(buffer, inode);
+ kobject_put(kobj);
/* After this point, attr should not be accessed. */
module_put(owner);
@@ -372,8 +406,8 @@ static int sysfs_release(struct inode * inode, struct file * filp)
static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
{
struct sysfs_buffer * buffer = filp->private_data;
- struct kobject * kobj = to_kobj(filp->f_dentry->d_parent);
- struct sysfs_dirent * sd = filp->f_dentry->d_fsdata;
+ struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
+ struct sysfs_dirent * sd = filp->f_path.dentry->d_fsdata;
int res = 0;
poll_wait(filp, &kobj->poll, wait);
@@ -548,7 +582,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file);
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
{
- sysfs_hash_and_remove(kobj->dentry,attr->name);
+ sysfs_hash_and_remove(kobj->dentry, attr->name);
}
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 122145b0895..b20951c9376 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -13,6 +13,8 @@
#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/err.h>
+#include <linux/fs.h>
+#include <asm/semaphore.h>
#include "sysfs.h"
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index e79e38d52c0..542d2bcc73d 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -13,6 +13,7 @@
#include <linux/backing-dev.h>
#include <linux/capability.h>
#include <linux/errno.h>
+#include <asm/semaphore.h>
#include "sysfs.h"
extern struct super_block * sysfs_sb;
@@ -32,6 +33,16 @@ static struct inode_operations sysfs_inode_operations ={
.setattr = sysfs_setattr,
};
+void sysfs_delete_inode(struct inode *inode)
+{
+ /* Free the shadowed directory inode operations */
+ if (sysfs_is_shadowed_inode(inode)) {
+ kfree(inode->i_op);
+ inode->i_op = NULL;
+ }
+ return generic_delete_inode(inode);
+}
+
int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
{
struct inode * inode = dentry->d_inode;
@@ -209,6 +220,22 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
return NULL;
}
+static inline void orphan_all_buffers(struct inode *node)
+{
+ struct sysfs_buffer_collection *set = node->i_private;
+ struct sysfs_buffer *buf;
+
+ mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD);
+ if (node->i_private) {
+ list_for_each_entry(buf, &set->associates, associates) {
+ down(&buf->sem);
+ buf->orphaned = 1;
+ up(&buf->sem);
+ }
+ }
+ mutex_unlock(&node->i_mutex);
+}
+
/*
* Unhashes the dentry corresponding to given sysfs_dirent
@@ -217,16 +244,23 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
{
struct dentry * dentry = sd->s_dentry;
+ struct inode *inode;
if (dentry) {
spin_lock(&dcache_lock);
spin_lock(&dentry->d_lock);
if (!(d_unhashed(dentry) && dentry->d_inode)) {
+ inode = dentry->d_inode;
+ spin_lock(&inode->i_lock);
+ __iget(inode);
+ spin_unlock(&inode->i_lock);
dget_locked(dentry);
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
simple_unlink(parent->d_inode, dentry);
+ orphan_all_buffers(inode);
+ iput(inode);
} else {
spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
@@ -248,7 +282,7 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name)
return -ENOENT;
parent_sd = dir->d_fsdata;
- mutex_lock(&dir->d_inode->i_mutex);
+ mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
if (!sd->s_element)
continue;
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index e503f858fba..f6a87a82488 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -8,6 +8,7 @@
#include <linux/mount.h>
#include <linux/pagemap.h>
#include <linux/init.h>
+#include <asm/semaphore.h>
#include "sysfs.h"
@@ -18,9 +19,12 @@ struct vfsmount *sysfs_mount;
struct super_block * sysfs_sb = NULL;
struct kmem_cache *sysfs_dir_cachep;
+static void sysfs_clear_inode(struct inode *inode);
+
static struct super_operations sysfs_ops = {
.statfs = simple_statfs,
- .drop_inode = generic_delete_inode,
+ .drop_inode = sysfs_delete_inode,
+ .clear_inode = sysfs_clear_inode,
};
static struct sysfs_dirent sysfs_root = {
@@ -31,6 +35,11 @@ static struct sysfs_dirent sysfs_root = {
.s_iattr = NULL,
};
+static void sysfs_clear_inode(struct inode *inode)
+{
+ kfree(inode->i_private);
+}
+
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index f50e3cc2ded..4869f611192 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/namei.h>
+#include <asm/semaphore.h>
#include "sysfs.h"
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index bd7cec295da..fe1cbfd208e 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -2,6 +2,7 @@
extern struct vfsmount * sysfs_mount;
extern struct kmem_cache *sysfs_dir_cachep;
+extern void sysfs_delete_inode(struct inode *inode);
extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
@@ -33,6 +34,22 @@ struct sysfs_symlink {
struct kobject * target_kobj;
};
+struct sysfs_buffer {
+ struct list_head associates;
+ size_t count;
+ loff_t pos;
+ char * page;
+ struct sysfs_ops * ops;
+ struct semaphore sem;
+ int orphaned;
+ int needs_read_fill;
+ int event;
+};
+
+struct sysfs_buffer_collection {
+ struct list_head associates;
+};
+
static inline struct kobject * to_kobj(struct dentry * dentry)
{
struct sysfs_dirent * sd = dentry->d_fsdata;
@@ -96,3 +113,7 @@ static inline void sysfs_put(struct sysfs_dirent * sd)
release_sysfs_dirent(sd);
}
+static inline int sysfs_is_shadowed_inode(struct inode *inode)
+{
+ return S_ISDIR(inode->i_mode) && inode->i_op->follow_link;
+}
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index f2bef962d30..ebf7007fa16 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -70,7 +70,7 @@ fail:
static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
unsigned long pos = filp->f_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
unsigned offset = pos & ~PAGE_CACHE_MASK;
unsigned long n = pos >> PAGE_CACHE_SHIFT;
diff --git a/fs/sysv/super.c b/fs/sysv/super.c
index dc9e7dc07fb..6f9707a1b95 100644
--- a/fs/sysv/super.c
+++ b/fs/sysv/super.c
@@ -528,9 +528,6 @@ static struct file_system_type v7_fs_type = {
.fs_flags = FS_REQUIRES_DEV,
};
-extern int sysv_init_icache(void) __init;
-extern void sysv_destroy_icache(void);
-
static int __init init_sysv_fs(void)
{
int error;
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h
index 9dcc8212093..dcb18b2171f 100644
--- a/fs/sysv/sysv.h
+++ b/fs/sysv/sysv.h
@@ -143,6 +143,9 @@ extern int sysv_sync_inode(struct inode *);
extern int sysv_sync_file(struct file *, struct dentry *, int);
extern void sysv_set_inode(struct inode *, dev_t);
extern int sysv_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int sysv_init_icache(void);
+extern void sysv_destroy_icache(void);
+
/* dir.c */
extern struct sysv_dir_entry *sysv_find_entry(struct dentry *, struct page **);
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 8c28efa3b8f..2391c9150c4 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -77,7 +77,7 @@ const struct file_operations udf_dir_operations = {
int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *dir = filp->f_dentry->d_inode;
+ struct inode *dir = filp->f_path.dentry->d_inode;
int result;
lock_kernel();
@@ -225,7 +225,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
if ( cfi.fileCharacteristics & FID_FILE_CHAR_PARENT )
{
- iblock = parent_ino(filp->f_dentry);
+ iblock = parent_ino(filp->f_path.dentry);
flen = 2;
memcpy(fname, "..", flen);
dt_type = DT_DIR;
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 7aedd552cba..d81f2db7b0e 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -108,7 +108,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
{
ssize_t retval;
struct file *file = iocb->ki_filp;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int err, pos;
size_t count = iocb->ki_left;
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index b8238147577..638f4c585e8 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -227,24 +227,27 @@ failed:
* We can come here from ufs_writepage or ufs_prepare_write,
* locked_page is argument of these functions, so we already lock it.
*/
-static void ufs_change_blocknr(struct inode *inode, unsigned int baseblk,
+static void ufs_change_blocknr(struct inode *inode, unsigned int beg,
unsigned int count, unsigned int oldb,
unsigned int newb, struct page *locked_page)
{
- unsigned int blk_per_page = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits);
- struct address_space *mapping = inode->i_mapping;
- pgoff_t index, cur_index = locked_page->index;
- unsigned int i, j;
+ const unsigned mask = (1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1;
+ struct address_space * const mapping = inode->i_mapping;
+ pgoff_t index, cur_index;
+ unsigned end, pos, j;
struct page *page;
struct buffer_head *head, *bh;
UFSD("ENTER, ino %lu, count %u, oldb %u, newb %u\n",
inode->i_ino, count, oldb, newb);
+ BUG_ON(!locked_page);
BUG_ON(!PageLocked(locked_page));
- for (i = 0; i < count; i += blk_per_page) {
- index = (baseblk+i) >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
+ cur_index = locked_page->index;
+
+ for (end = count + beg; beg < end; beg = (beg | mask) + 1) {
+ index = beg >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
if (likely(cur_index != index)) {
page = ufs_get_locked_page(mapping, index);
@@ -253,21 +256,32 @@ static void ufs_change_blocknr(struct inode *inode, unsigned int baseblk,
} else
page = locked_page;
- j = i;
head = page_buffers(page);
bh = head;
+ pos = beg & mask;
+ for (j = 0; j < pos; ++j)
+ bh = bh->b_this_page;
+ j = 0;
do {
- if (likely(bh->b_blocknr == j + oldb && j < count)) {
- unmap_underlying_metadata(bh->b_bdev,
- bh->b_blocknr);
- bh->b_blocknr = newb + j++;
- mark_buffer_dirty(bh);
+ if (buffer_mapped(bh)) {
+ pos = bh->b_blocknr - oldb;
+ if (pos < count) {
+ UFSD(" change from %llu to %llu\n",
+ (unsigned long long)pos + oldb,
+ (unsigned long long)pos + newb);
+ bh->b_blocknr = newb + pos;
+ unmap_underlying_metadata(bh->b_bdev,
+ bh->b_blocknr);
+ mark_buffer_dirty(bh);
+ ++j;
+ }
}
bh = bh->b_this_page;
} while (bh != head);
- set_page_dirty(page);
+ if (j)
+ set_page_dirty(page);
if (likely(cur_index != index))
ufs_put_locked_page(page);
@@ -275,6 +289,25 @@ static void ufs_change_blocknr(struct inode *inode, unsigned int baseblk,
UFSD("EXIT\n");
}
+static void ufs_clear_frags(struct inode *inode, sector_t beg, unsigned int n,
+ int sync)
+{
+ struct buffer_head *bh;
+ sector_t end = beg + n;
+
+ for (; beg < end; ++beg) {
+ bh = sb_getblk(inode->i_sb, beg);
+ lock_buffer(bh);
+ memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+ set_buffer_uptodate(bh);
+ mark_buffer_dirty(bh);
+ unlock_buffer(bh);
+ if (IS_SYNC(inode) || sync)
+ sync_dirty_buffer(bh);
+ brelse(bh);
+ }
+}
+
unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment,
unsigned goal, unsigned count, int * err, struct page *locked_page)
{
@@ -350,6 +383,8 @@ unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment,
*p = cpu_to_fs32(sb, result);
*err = 0;
UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
+ ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
+ locked_page != NULL);
}
unlock_super(sb);
UFSD("EXIT, result %u\n", result);
@@ -363,6 +398,8 @@ unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment,
if (result) {
*err = 0;
UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
+ ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
+ locked_page != NULL);
unlock_super(sb);
UFSD("EXIT, result %u\n", result);
return result;
@@ -392,6 +429,8 @@ unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment,
}
result = ufs_alloc_fragments (inode, cgno, goal, request, err);
if (result) {
+ ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
+ locked_page != NULL);
ufs_change_blocknr(inode, fragment - oldcount, oldcount, tmp,
result, locked_page);
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 7f0a0aa6358..a6c0ca9f48b 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -106,12 +106,13 @@ static void ufs_check_page(struct page *page)
char *kaddr = page_address(page);
unsigned offs, rec_len;
unsigned limit = PAGE_CACHE_SIZE;
+ const unsigned chunk_mask = UFS_SB(sb)->s_uspi->s_dirblksize - 1;
struct ufs_dir_entry *p;
char *error;
if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) {
limit = dir->i_size & ~PAGE_CACHE_MASK;
- if (limit & (UFS_SECTOR_SIZE - 1))
+ if (limit & chunk_mask)
goto Ebadsize;
if (!limit)
goto out;
@@ -126,7 +127,7 @@ static void ufs_check_page(struct page *page)
goto Ealign;
if (rec_len < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, p)))
goto Enamelen;
- if (((offs + rec_len - 1) ^ offs) & ~(UFS_SECTOR_SIZE-1))
+ if (((offs + rec_len - 1) ^ offs) & ~chunk_mask)
goto Espan;
if (fs32_to_cpu(sb, p->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg *
UFS_SB(sb)->s_uspi->s_ncg))
@@ -310,6 +311,7 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode)
int namelen = dentry->d_name.len;
struct super_block *sb = dir->i_sb;
unsigned reclen = UFS_DIR_REC_LEN(namelen);
+ const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize;
unsigned short rec_len, name_len;
struct page *page = NULL;
struct ufs_dir_entry *de;
@@ -342,8 +344,8 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode)
if ((char *)de == dir_end) {
/* We hit i_size */
name_len = 0;
- rec_len = UFS_SECTOR_SIZE;
- de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE);
+ rec_len = chunk_size;
+ de->d_reclen = cpu_to_fs16(sb, chunk_size);
de->d_ino = 0;
goto got_it;
}
@@ -426,12 +428,12 @@ static int
ufs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
loff_t pos = filp->f_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
unsigned int offset = pos & ~PAGE_CACHE_MASK;
unsigned long n = pos >> PAGE_CACHE_SHIFT;
unsigned long npages = ufs_dir_pages(inode);
- unsigned chunk_mask = ~(UFS_SECTOR_SIZE - 1);
+ unsigned chunk_mask = ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);
int need_revalidate = filp->f_version != inode->i_version;
unsigned flags = UFS_SB(sb)->s_flags;
@@ -511,7 +513,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
struct super_block *sb = inode->i_sb;
struct address_space *mapping = page->mapping;
char *kaddr = page_address(page);
- unsigned from = ((char*)dir - kaddr) & ~(UFS_SECTOR_SIZE - 1);
+ unsigned from = ((char*)dir - kaddr) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);
unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen);
struct ufs_dir_entry *pde = NULL;
struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from);
@@ -556,6 +558,7 @@ int ufs_make_empty(struct inode * inode, struct inode *dir)
struct super_block * sb = dir->i_sb;
struct address_space *mapping = inode->i_mapping;
struct page *page = grab_cache_page(mapping, 0);
+ const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize;
struct ufs_dir_entry * de;
char *base;
int err;
@@ -563,7 +566,7 @@ int ufs_make_empty(struct inode * inode, struct inode *dir)
if (!page)
return -ENOMEM;
kmap(page);
- err = mapping->a_ops->prepare_write(NULL, page, 0, UFS_SECTOR_SIZE);
+ err = mapping->a_ops->prepare_write(NULL, page, 0, chunk_size);
if (err) {
unlock_page(page);
goto fail;
@@ -584,11 +587,11 @@ int ufs_make_empty(struct inode * inode, struct inode *dir)
((char *)de + fs16_to_cpu(sb, de->d_reclen));
de->d_ino = cpu_to_fs32(sb, dir->i_ino);
ufs_set_de_type(sb, de, dir->i_mode);
- de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1));
+ de->d_reclen = cpu_to_fs16(sb, chunk_size - UFS_DIR_REC_LEN(1));
ufs_set_de_namlen(sb, de, 2);
strcpy (de->d_name, "..");
- err = ufs_commit_chunk(page, 0, UFS_SECTOR_SIZE);
+ err = ufs_commit_chunk(page, 0, chunk_size);
fail:
kunmap(page);
page_cache_release(page);
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index ee1eaa6f4ec..4295ca91cf8 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -156,36 +156,6 @@ out:
return ret;
}
-static void ufs_clear_frag(struct inode *inode, struct buffer_head *bh)
-{
- lock_buffer(bh);
- memset(bh->b_data, 0, inode->i_sb->s_blocksize);
- set_buffer_uptodate(bh);
- mark_buffer_dirty(bh);
- unlock_buffer(bh);
- if (IS_SYNC(inode))
- sync_dirty_buffer(bh);
-}
-
-static struct buffer_head *
-ufs_clear_frags(struct inode *inode, sector_t beg,
- unsigned int n, sector_t want)
-{
- struct buffer_head *res = NULL, *bh;
- sector_t end = beg + n;
-
- for (; beg < end; ++beg) {
- bh = sb_getblk(inode->i_sb, beg);
- ufs_clear_frag(inode, bh);
- if (want != beg)
- brelse(bh);
- else
- res = bh;
- }
- BUG_ON(!res);
- return res;
-}
-
/**
* ufs_inode_getfrag() - allocate new fragment(s)
* @inode - pointer to inode
@@ -272,7 +242,8 @@ repeat:
goal = tmp + uspi->s_fpb;
tmp = ufs_new_fragments (inode, p, fragment - blockoff,
goal, required + blockoff,
- err, locked_page);
+ err,
+ phys != NULL ? locked_page : NULL);
}
/*
* We will extend last allocated block
@@ -280,7 +251,7 @@ repeat:
else if (lastblock == block) {
tmp = ufs_new_fragments(inode, p, fragment - (blockoff - lastblockoff),
fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff),
- err, locked_page);
+ err, phys != NULL ? locked_page : NULL);
} else /* (lastblock > block) */ {
/*
* We will allocate new block before last allocated block
@@ -291,7 +262,8 @@ repeat:
goal = tmp + uspi->s_fpb;
}
tmp = ufs_new_fragments(inode, p, fragment - blockoff,
- goal, uspi->s_fpb, err, locked_page);
+ goal, uspi->s_fpb, err,
+ phys != NULL ? locked_page : NULL);
}
if (!tmp) {
if ((!blockoff && *p) ||
@@ -302,7 +274,7 @@ repeat:
}
if (!phys) {
- result = ufs_clear_frags(inode, tmp, required, tmp + blockoff);
+ result = sb_getblk(sb, tmp + blockoff);
} else {
*phys = tmp + blockoff;
result = NULL;
@@ -403,8 +375,7 @@ repeat:
if (!phys) {
- result = ufs_clear_frags(inode, tmp, uspi->s_fpb,
- tmp + blockoff);
+ result = sb_getblk(sb, tmp + blockoff);
} else {
*phys = tmp + blockoff;
*new = 1;
@@ -469,15 +440,17 @@ int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head
* it much more readable:
*/
#define GET_INODE_DATABLOCK(x) \
- ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new, bh_result->b_page)
+ ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new,\
+ bh_result->b_page)
#define GET_INODE_PTR(x) \
- ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page)
+ ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL,\
+ bh_result->b_page)
#define GET_INDIRECT_DATABLOCK(x) \
ufs_inode_getblock(inode, bh, x, fragment, \
- &err, &phys, &new, bh_result->b_page);
+ &err, &phys, &new, bh_result->b_page)
#define GET_INDIRECT_PTR(x) \
ufs_inode_getblock(inode, bh, x, fragment, \
- &err, NULL, NULL, bh_result->b_page);
+ &err, NULL, NULL, NULL)
if (ptr < UFS_NDIR_FRAGMENT) {
bh = GET_INODE_DATABLOCK(ptr);
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 8a8e9382ec0..209be95e9d1 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -649,7 +649,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL);
if (!uspi)
goto failed;
-
+ uspi->s_dirblksize = UFS_SECTOR_SIZE;
super_block_offset=UFS_SBLOCK;
/* Keep 2Gig file limit. Some UFS variants need to override
@@ -718,6 +718,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
break;
case UFS_MOUNT_UFSTYPE_NEXTSTEP:
+ /*TODO: check may be we need set special dir block size?*/
UFSD("ufstype=nextstep\n");
uspi->s_fsize = block_size = 1024;
uspi->s_fmask = ~(1024 - 1);
@@ -733,6 +734,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
break;
case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD:
+ /*TODO: check may be we need set special dir block size?*/
UFSD("ufstype=nextstep-cd\n");
uspi->s_fsize = block_size = 2048;
uspi->s_fmask = ~(2048 - 1);
@@ -754,6 +756,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
uspi->s_fshift = 10;
uspi->s_sbsize = super_block_size = 2048;
uspi->s_sbbase = 0;
+ uspi->s_dirblksize = 1024;
flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
if (!(sb->s_flags & MS_RDONLY)) {
if (!silent)
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index ea11d04c41a..0437b0a6fe9 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -109,10 +109,10 @@ static int ufs_trunc_direct (struct inode * inode)
tmp = fs32_to_cpu(sb, *p);
if (!tmp )
ufs_panic (sb, "ufs_trunc_direct", "internal error");
+ frag2 -= frag1;
frag1 = ufs_fragnum (frag1);
- frag2 = ufs_fragnum (frag2);
- ufs_free_fragments (inode, tmp + frag1, frag2 - frag1);
+ ufs_free_fragments(inode, tmp + frag1, frag2);
mark_inode_dirty(inode);
frag_to_free = tmp + frag1;
diff --git a/fs/xattr.c b/fs/xattr.c
index 0901bdc2ce2..38646132ab0 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -268,7 +268,7 @@ sys_fsetxattr(int fd, char __user *name, void __user *value,
f = fget(fd);
if (!f)
return error;
- dentry = f->f_dentry;
+ dentry = f->f_path.dentry;
audit_inode(NULL, dentry->d_inode);
error = setxattr(dentry, name, value, size, flags);
fput(f);
@@ -351,7 +351,7 @@ sys_fgetxattr(int fd, char __user *name, void __user *value, size_t size)
f = fget(fd);
if (!f)
return error;
- error = getxattr(f->f_dentry, name, value, size);
+ error = getxattr(f->f_path.dentry, name, value, size);
fput(f);
return error;
}
@@ -423,7 +423,7 @@ sys_flistxattr(int fd, char __user *list, size_t size)
f = fget(fd);
if (!f)
return error;
- error = listxattr(f->f_dentry, list, size);
+ error = listxattr(f->f_path.dentry, list, size);
fput(f);
return error;
}
@@ -484,7 +484,7 @@ sys_fremovexattr(int fd, char __user *name)
f = fget(fd);
if (!f)
return error;
- dentry = f->f_dentry;
+ dentry = f->f_path.dentry;
audit_inode(NULL, dentry->d_inode);
error = removexattr(dentry, name);
fput(f);
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 8e6b56fc1ca..7b54461695e 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -341,9 +341,9 @@ xfs_start_page_writeback(
{
ASSERT(PageLocked(page));
ASSERT(!PageWriteback(page));
- set_page_writeback(page);
if (clear_dirty)
- clear_page_dirty(page);
+ clear_page_dirty_for_io(page);
+ set_page_writeback(page);
unlock_page(page);
if (!buffers) {
end_page_writeback(page);
@@ -1406,7 +1406,7 @@ xfs_vm_direct_IO(
xfs_end_io_direct);
}
- if (unlikely(ret <= 0 && iocb->private))
+ if (unlikely(ret != -EIOCBQUEUED && iocb->private))
xfs_destroy_ioend(iocb->private);
return ret;
}
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index d93d8dd1958..d26f5cd2ba7 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -55,7 +55,7 @@ __xfs_file_read(
loff_t pos)
{
struct file *file = iocb->ki_filp;
- bhv_vnode_t *vp = vn_from_inode(file->f_dentry->d_inode);
+ bhv_vnode_t *vp = vn_from_inode(file->f_path.dentry->d_inode);
BUG_ON(iocb->ki_pos != pos);
if (unlikely(file->f_flags & O_DIRECT))
@@ -131,7 +131,7 @@ xfs_file_sendfile(
read_actor_t actor,
void *target)
{
- return bhv_vop_sendfile(vn_from_inode(filp->f_dentry->d_inode),
+ return bhv_vop_sendfile(vn_from_inode(filp->f_path.dentry->d_inode),
filp, pos, 0, count, actor, target, NULL);
}
@@ -143,7 +143,7 @@ xfs_file_sendfile_invis(
read_actor_t actor,
void *target)
{
- return bhv_vop_sendfile(vn_from_inode(filp->f_dentry->d_inode),
+ return bhv_vop_sendfile(vn_from_inode(filp->f_path.dentry->d_inode),
filp, pos, IO_INVIS, count, actor, target, NULL);
}
@@ -155,7 +155,7 @@ xfs_file_splice_read(
size_t len,
unsigned int flags)
{
- return bhv_vop_splice_read(vn_from_inode(infilp->f_dentry->d_inode),
+ return bhv_vop_splice_read(vn_from_inode(infilp->f_path.dentry->d_inode),
infilp, ppos, pipe, len, flags, 0, NULL);
}
@@ -167,7 +167,7 @@ xfs_file_splice_read_invis(
size_t len,
unsigned int flags)
{
- return bhv_vop_splice_read(vn_from_inode(infilp->f_dentry->d_inode),
+ return bhv_vop_splice_read(vn_from_inode(infilp->f_path.dentry->d_inode),
infilp, ppos, pipe, len, flags, IO_INVIS,
NULL);
}
@@ -180,7 +180,7 @@ xfs_file_splice_write(
size_t len,
unsigned int flags)
{
- return bhv_vop_splice_write(vn_from_inode(outfilp->f_dentry->d_inode),
+ return bhv_vop_splice_write(vn_from_inode(outfilp->f_path.dentry->d_inode),
pipe, outfilp, ppos, len, flags, 0, NULL);
}
@@ -192,7 +192,7 @@ xfs_file_splice_write_invis(
size_t len,
unsigned int flags)
{
- return bhv_vop_splice_write(vn_from_inode(outfilp->f_dentry->d_inode),
+ return bhv_vop_splice_write(vn_from_inode(outfilp->f_path.dentry->d_inode),
pipe, outfilp, ppos, len, flags, IO_INVIS,
NULL);
}
@@ -212,7 +212,7 @@ xfs_file_close(
struct file *filp,
fl_owner_t id)
{
- return -bhv_vop_close(vn_from_inode(filp->f_dentry->d_inode), 0,
+ return -bhv_vop_close(vn_from_inode(filp->f_path.dentry->d_inode), 0,
file_count(filp) > 1 ? L_FALSE : L_TRUE, NULL);
}
@@ -251,7 +251,7 @@ xfs_vm_nopage(
unsigned long address,
int *type)
{
- struct inode *inode = area->vm_file->f_dentry->d_inode;
+ struct inode *inode = area->vm_file->f_path.dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);
ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI);
@@ -268,7 +268,7 @@ xfs_file_readdir(
filldir_t filldir)
{
int error = 0;
- bhv_vnode_t *vp = vn_from_inode(filp->f_dentry->d_inode);
+ bhv_vnode_t *vp = vn_from_inode(filp->f_path.dentry->d_inode);
uio_t uio;
iovec_t iov;
int eof = 0;
@@ -345,7 +345,7 @@ xfs_file_mmap(
vma->vm_ops = &xfs_file_vm_ops;
#ifdef CONFIG_XFS_DMAPI
- if (vn_from_inode(filp->f_dentry->d_inode)->v_vfsp->vfs_flag & VFS_DMI)
+ if (vn_from_inode(filp->f_path.dentry->d_inode)->v_vfsp->vfs_flag & VFS_DMI)
vma->vm_ops = &xfs_dmapi_file_vm_ops;
#endif /* CONFIG_XFS_DMAPI */
@@ -360,7 +360,7 @@ xfs_file_ioctl(
unsigned long p)
{
int error;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);
error = bhv_vop_ioctl(vp, inode, filp, 0, cmd, (void __user *)p);
@@ -382,7 +382,7 @@ xfs_file_ioctl_invis(
unsigned long p)
{
int error;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);
error = bhv_vop_ioctl(vp, inode, filp, IO_INVIS, cmd, (void __user *)p);
@@ -404,7 +404,7 @@ xfs_vm_mprotect(
struct vm_area_struct *vma,
unsigned int newflags)
{
- bhv_vnode_t *vp = vn_from_inode(vma->vm_file->f_dentry->d_inode);
+ bhv_vnode_t *vp = vn_from_inode(vma->vm_file->f_path.dentry->d_inode);
int error = 0;
if (vp->v_vfsp->vfs_flag & VFS_DMI) {
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index 74d094829a4..f011c9cd0d6 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -107,9 +107,9 @@ xfs_find_handle(
if (!file)
return -EBADF;
- ASSERT(file->f_dentry);
- ASSERT(file->f_dentry->d_inode);
- inode = igrab(file->f_dentry->d_inode);
+ ASSERT(file->f_path.dentry);
+ ASSERT(file->f_path.dentry->d_inode);
+ inode = igrab(file->f_path.dentry->d_inode);
fput(file);
break;
}
@@ -333,10 +333,10 @@ xfs_open_by_handle(
}
/* Ensure umount returns EBUSY on umounts while this file is open. */
- mntget(parfilp->f_vfsmnt);
+ mntget(parfilp->f_path.mnt);
/* Create file pointer. */
- filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags);
+ filp = dentry_open(dentry, parfilp->f_path.mnt, hreq.oflags);
if (IS_ERR(filp)) {
put_unused_fd(new_fd);
return -XFS_ERROR(-PTR_ERR(filp));
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index 270db0f3861..b83cebc165f 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -112,7 +112,7 @@ xfs_compat_ioctl(
unsigned cmd,
unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);
int error;
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index fa842f1c9fa..65e79b471d4 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -805,7 +805,7 @@ start:
!capable(CAP_FSETID)) {
error = xfs_write_clear_setuid(xip);
if (likely(!error))
- error = -remove_suid(file->f_dentry);
+ error = -remove_suid(file->f_path.dentry);
if (unlikely(error)) {
xfs_iunlock(xip, iolock);
goto out_unlock_mutex;
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
index 80562b60fb9..50d0faea371 100644
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -71,7 +71,7 @@ xfs_swapext(
/* Pull information for the target fd */
if (((fp = fget((int)sxp->sx_fdtarget)) == NULL) ||
- ((vp = vn_from_inode(fp->f_dentry->d_inode)) == NULL)) {
+ ((vp = vn_from_inode(fp->f_path.dentry->d_inode)) == NULL)) {
error = XFS_ERROR(EINVAL);
goto error0;
}
@@ -83,7 +83,7 @@ xfs_swapext(
}
if (((tfp = fget((int)sxp->sx_fdtmp)) == NULL) ||
- ((tvp = vn_from_inode(tfp->f_dentry->d_inode)) == NULL)) {
+ ((tvp = vn_from_inode(tfp->f_path.dentry->d_inode)) == NULL)) {
error = XFS_ERROR(EINVAL);
goto error0;
}
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
index 9e6c23c360b..422f29c06c7 100644
--- a/include/acpi/acconfig.h
+++ b/include/acpi/acconfig.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,7 +63,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20060707
+#define ACPI_CA_VERSION 0x20070126
/*
* OS name, used for the _OS object. The _OS object is essentially obsolete,
@@ -105,7 +105,7 @@
/* Maximum object reference count (detects object deletion issues) */
-#define ACPI_MAX_REFERENCE_COUNT 0x800
+#define ACPI_MAX_REFERENCE_COUNT 0x1000
/* Size of cached memory mapping for system memory operation region */
@@ -115,6 +115,10 @@
#define ACPI_NUM_OWNERID_MASKS 8
+/* Size of the root table array is increased by this increment */
+
+#define ACPI_ROOT_TABLE_SIZE_INCREMENT 4
+
/******************************************************************************
*
* ACPI Specification constants (Do not change unless the specification changes)
@@ -152,6 +156,11 @@
#define ACPI_PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 char for separator */
#define ACPI_PATH_SEPARATOR '.'
+/* Sizes for ACPI table headers */
+
+#define ACPI_OEM_ID_SIZE 6
+#define ACPI_OEM_TABLE_ID_SIZE 8
+
/* Constants used in searching for the RSDP in low memory */
#define ACPI_EBDA_PTR_LOCATION 0x0000040E /* Physical Address */
diff --git a/include/acpi/acdebug.h b/include/acpi/acdebug.h
index d8167095caf..d626bb1d297 100644
--- a/include/acpi/acdebug.h
+++ b/include/acpi/acdebug.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -159,6 +159,10 @@ void
acpi_db_create_execution_threads(char *num_threads_arg,
char *num_loops_arg, char *method_name_arg);
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+u32 acpi_db_get_cache_info(struct acpi_memory_list *cache);
+#endif
+
/*
* dbfileio - Debugger file I/O commands
*/
@@ -214,4 +218,6 @@ void acpi_db_prep_namestring(char *name);
struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name);
+void acpi_db_uint32_to_hex_string(u32 value, char *buffer);
+
#endif /* __ACDEBUG_H__ */
diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h
index 9a7d6921f53..389d772c7d5 100644
--- a/include/acpi/acdisasm.h
+++ b/include/acpi/acdisasm.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,9 +97,11 @@ typedef const struct acpi_dmtable_info {
#define ACPI_DMT_CHKSUM 20
#define ACPI_DMT_SPACEID 21
#define ACPI_DMT_GAS 22
-#define ACPI_DMT_MADT 23
-#define ACPI_DMT_SRAT 24
-#define ACPI_DMT_EXIT 25
+#define ACPI_DMT_DMAR 23
+#define ACPI_DMT_MADT 24
+#define ACPI_DMT_SRAT 25
+#define ACPI_DMT_EXIT 26
+#define ACPI_DMT_SIG 27
typedef
void (*ACPI_TABLE_HANDLER) (struct acpi_table_header * table);
@@ -108,6 +110,7 @@ struct acpi_dmtable_data {
char *signature;
struct acpi_dmtable_info *table_info;
ACPI_TABLE_HANDLER table_handler;
+ char *name;
};
struct acpi_op_walk_info {
@@ -139,7 +142,9 @@ extern const char *acpi_gbl_match_ops[];
extern struct acpi_dmtable_info acpi_dm_table_info_asf0[];
extern struct acpi_dmtable_info acpi_dm_table_info_asf1[];
+extern struct acpi_dmtable_info acpi_dm_table_info_asf1a[];
extern struct acpi_dmtable_info acpi_dm_table_info_asf2[];
+extern struct acpi_dmtable_info acpi_dm_table_info_asf2a[];
extern struct acpi_dmtable_info acpi_dm_table_info_asf3[];
extern struct acpi_dmtable_info acpi_dm_table_info_asf4[];
extern struct acpi_dmtable_info acpi_dm_table_info_asf_hdr[];
@@ -147,6 +152,11 @@ extern struct acpi_dmtable_info acpi_dm_table_info_boot[];
extern struct acpi_dmtable_info acpi_dm_table_info_cpep[];
extern struct acpi_dmtable_info acpi_dm_table_info_cpep0[];
extern struct acpi_dmtable_info acpi_dm_table_info_dbgp[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar_hdr[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar_scope[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar0[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar1[];
extern struct acpi_dmtable_info acpi_dm_table_info_ecdt[];
extern struct acpi_dmtable_info acpi_dm_table_info_facs[];
extern struct acpi_dmtable_info acpi_dm_table_info_fadt1[];
@@ -201,6 +211,8 @@ void acpi_dm_dump_asf(struct acpi_table_header *table);
void acpi_dm_dump_cpep(struct acpi_table_header *table);
+void acpi_dm_dump_dmar(struct acpi_table_header *table);
+
void acpi_dm_dump_fadt(struct acpi_table_header *table);
void acpi_dm_dump_srat(struct acpi_table_header *table);
@@ -314,7 +326,7 @@ acpi_dm_resource_template(struct acpi_op_walk_info *info,
union acpi_parse_object *op,
u8 * byte_data, u32 byte_count);
-u8 acpi_dm_is_resource_template(union acpi_parse_object *op);
+acpi_status acpi_dm_is_resource_template(union acpi_parse_object *op);
void acpi_dm_indent(u32 level);
diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h
index a22fe9cf849..cb8d2868c8a 100644
--- a/include/acpi/acdispat.h
+++ b/include/acpi/acdispat.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -210,7 +210,7 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state);
* dsinit
*/
acpi_status
-acpi_ds_initialize_objects(struct acpi_table_desc *table_desc,
+acpi_ds_initialize_objects(acpi_native_uint table_index,
struct acpi_namespace_node *start_node);
/*
diff --git a/include/acpi/acevents.h b/include/acpi/acevents.h
index 234142828e1..d23cdf32680 100644
--- a/include/acpi/acevents.h
+++ b/include/acpi/acevents.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 797ca1ea521..b73f18a4878 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -178,8 +178,10 @@
#define AE_CTRL_BREAK (acpi_status) (0x0009 | AE_CODE_CONTROL)
#define AE_CTRL_CONTINUE (acpi_status) (0x000A | AE_CODE_CONTROL)
#define AE_CTRL_SKIP (acpi_status) (0x000B | AE_CODE_CONTROL)
+#define AE_CTRL_PARSE_CONTINUE (acpi_status) (0x000C | AE_CODE_CONTROL)
+#define AE_CTRL_PARSE_PENDING (acpi_status) (0x000D | AE_CODE_CONTROL)
-#define AE_CODE_CTRL_MAX 0x000B
+#define AE_CODE_CTRL_MAX 0x000D
#ifdef DEFINE_ACPI_GLOBALS
@@ -291,7 +293,9 @@ char const *acpi_gbl_exception_names_ctrl[] = {
"AE_CTRL_TRANSFER",
"AE_CTRL_BREAK",
"AE_CTRL_CONTINUE",
- "AE_CTRL_SKIP"
+ "AE_CTRL_SKIP",
+ "AE_CTRL_PARSE_CONTINUE",
+ "AE_CTRL_PARSE_PENDING"
};
#endif /* ACPI GLOBALS */
diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h
index 06972e6637d..24c3f05ab36 100644
--- a/include/acpi/acglobal.h
+++ b/include/acpi/acglobal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -58,37 +58,6 @@
#define ACPI_INIT_GLOBAL(a,b) a
#endif
-/*
- * Keep local copies of these FADT-based registers. NOTE: These globals
- * are first in this file for alignment reasons on 64-bit systems.
- */
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
-
-/*****************************************************************************
- *
- * Debug support
- *
- ****************************************************************************/
-
-/* Runtime configuration of debug print levels */
-
-extern u32 acpi_dbg_level;
-extern u32 acpi_dbg_layer;
-
-/* Procedure nesting level for debug output */
-
-extern u32 acpi_gbl_nesting_level;
-
-/* Support for dynamic control method tracing mechanism */
-
-ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
-ACPI_EXTERN acpi_name acpi_gbl_trace_method_name;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
-ACPI_EXTERN u32 acpi_gbl_trace_flags;
-
/*****************************************************************************
*
* Runtime configuration (static defaults that can be overriden at runtime)
@@ -135,52 +104,62 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE);
/*****************************************************************************
*
+ * Debug support
+ *
+ ****************************************************************************/
+
+/* Runtime configuration of debug print levels */
+
+extern u32 acpi_dbg_level;
+extern u32 acpi_dbg_layer;
+
+/* Procedure nesting level for debug output */
+
+extern u32 acpi_gbl_nesting_level;
+
+/* Event counters */
+
+ACPI_EXTERN u32 acpi_gpe_count;
+
+/* Support for dynamic control method tracing mechanism */
+
+ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
+ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
+ACPI_EXTERN acpi_name acpi_gbl_trace_method_name;
+ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
+ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
+ACPI_EXTERN u32 acpi_gbl_trace_flags;
+
+/*****************************************************************************
+ *
* ACPI Table globals
*
****************************************************************************/
/*
- * Table pointers.
- * Although these pointers are somewhat redundant with the global acpi_table,
- * they are convenient because they are typed pointers.
+ * acpi_gbl_root_table_list is the master list of ACPI tables found in the
+ * RSDT/XSDT.
*
- * These tables are single-table only; meaning that there can be at most one
- * of each in the system. Each global points to the actual table.
- */
-ACPI_EXTERN u32 acpi_gbl_table_flags;
-ACPI_EXTERN u32 acpi_gbl_rsdt_table_count;
-ACPI_EXTERN struct rsdp_descriptor *acpi_gbl_RSDP;
-ACPI_EXTERN struct xsdt_descriptor *acpi_gbl_XSDT;
-ACPI_EXTERN struct fadt_descriptor *acpi_gbl_FADT;
-ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT;
-ACPI_EXTERN struct facs_descriptor *acpi_gbl_FACS;
-ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS;
-/*
- * Since there may be multiple SSDTs and PSDTs, a single pointer is not
- * sufficient; Therefore, there isn't one!
+ * acpi_gbl_FADT is a local copy of the FADT, converted to a common format.
*/
+ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list;
+ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT;
+extern acpi_native_uint acpi_gbl_permanent_mmap;
-/* The root table can be either an RSDT or an XSDT */
+/* These addresses are calculated from FADT address values */
-ACPI_EXTERN u8 acpi_gbl_root_table_type;
-#define ACPI_TABLE_TYPE_RSDT 'R'
-#define ACPI_TABLE_TYPE_XSDT 'X'
+ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
+ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
/*
- * Handle both ACPI 1.0 and ACPI 2.0 Integer widths:
- * If we are executing a method that exists in a 32-bit ACPI table,
- * use only the lower 32 bits of the (internal) 64-bit Integer.
+ * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is
+ * determined by the revision of the DSDT: If the DSDT revision is less than
+ * 2, use only the lower 32 bits of the internal 64-bit Integer.
*/
ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
-/*
- * ACPI Table info arrays
- */
-extern struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1];
-extern struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1];
-
/*****************************************************************************
*
* Mutual exlusion within ACPICA subsystem
@@ -188,7 +167,7 @@ extern struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1];
****************************************************************************/
/*
- * Predefined mutex objects. This array contains the
+ * Predefined mutex objects. This array contains the
* actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs.
* (The table maps local handles to the real OS handles)
*/
@@ -197,6 +176,7 @@ ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX];
/*
* Global lock semaphore works in conjunction with the actual HW global lock
*/
+ACPI_EXTERN acpi_mutex acpi_gbl_global_lock_mutex;
ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore;
/*
@@ -220,6 +200,7 @@ ACPI_EXTERN spinlock_t _acpi_gbl_hardware_lock; /* For ACPI H/W except GPE regis
ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list;
ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list;
+ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats;
#endif
/* Object caches */
@@ -240,7 +221,6 @@ ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
/* Misc */
-ACPI_EXTERN u32 acpi_gbl_global_lock_thread_count;
ACPI_EXTERN u32 acpi_gbl_original_mode;
ACPI_EXTERN u32 acpi_gbl_rsdp_original_location;
ACPI_EXTERN u32 acpi_gbl_ns_lookup_count;
@@ -260,12 +240,19 @@ ACPI_EXTERN u8 acpi_gbl_system_awake_and_running;
extern u8 acpi_gbl_shutdown;
extern u32 acpi_gbl_startup_flags;
-extern const u8 acpi_gbl_decode_to8bit[8];
extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
extern const char *acpi_gbl_highest_dstate_names[4];
extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
+/* Exception codes */
+
+extern char const *acpi_gbl_exception_names_env[];
+extern char const *acpi_gbl_exception_names_pgm[];
+extern char const *acpi_gbl_exception_names_tbl[];
+extern char const *acpi_gbl_exception_names_aml[];
+extern char const *acpi_gbl_exception_names_ctrl[];
+
/*****************************************************************************
*
* Namespace globals
diff --git a/include/acpi/achware.h b/include/acpi/achware.h
index 29b60a8c059..9df275cf7bc 100644
--- a/include/acpi/achware.h
+++ b/include/acpi/achware.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,8 +61,6 @@
/*
* hwacpi - high level functions
*/
-acpi_status acpi_hw_initialize(void);
-
acpi_status acpi_hw_set_mode(u32 mode);
u32 acpi_hw_get_mode(void);
@@ -84,7 +82,7 @@ acpi_hw_low_level_read(u32 width,
acpi_status
acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address *reg);
-acpi_status acpi_hw_clear_acpi_status(u32 flags);
+acpi_status acpi_hw_clear_acpi_status(void);
/*
* hwgpe - GPE support
diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h
index 91586d0d5bb..ce7c9d65391 100644
--- a/include/acpi/acinterp.h
+++ b/include/acpi/acinterp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -277,12 +277,6 @@ acpi_status acpi_ex_system_do_suspend(acpi_integer time);
acpi_status acpi_ex_system_do_stall(u32 time);
-acpi_status
-acpi_ex_system_acquire_mutex(union acpi_operand_object *time,
- union acpi_operand_object *obj_desc);
-
-acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc);
-
acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc);
acpi_status
@@ -451,10 +445,14 @@ acpi_ex_copy_integer_to_buffer_field(union acpi_operand_object *source_desc,
/*
* exutils - interpreter/scanner utilities
*/
-acpi_status acpi_ex_enter_interpreter(void);
+void acpi_ex_enter_interpreter(void);
void acpi_ex_exit_interpreter(void);
+void acpi_ex_reacquire_interpreter(void);
+
+void acpi_ex_relinquish_interpreter(void);
+
void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
u8 acpi_ex_acquire_global_lock(u32 rule);
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index 063c4b54290..6f83ddbed3a 100644
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -80,8 +80,8 @@ union acpi_parse_object;
* table below also!
*/
#define ACPI_MTX_INTERPRETER 0 /* AML Interpreter, main lock */
-#define ACPI_MTX_TABLES 1 /* Data for ACPI tables */
-#define ACPI_MTX_NAMESPACE 2 /* ACPI Namespace */
+#define ACPI_MTX_NAMESPACE 1 /* ACPI Namespace */
+#define ACPI_MTX_TABLES 2 /* Data for ACPI tables */
#define ACPI_MTX_EVENTS 3 /* Data for ACPI events */
#define ACPI_MTX_CACHES 4 /* Internal caches, general purposes */
#define ACPI_MTX_MEMORY 5 /* Debug memory tracking lists */
@@ -162,7 +162,7 @@ struct acpi_mutex_info {
typedef enum {
ACPI_IMODE_LOAD_PASS1 = 0x01,
ACPI_IMODE_LOAD_PASS2 = 0x02,
- ACPI_IMODE_EXECUTE = 0x0E
+ ACPI_IMODE_EXECUTE = 0x03
} acpi_interpreter_mode;
union acpi_name_union {
@@ -204,7 +204,7 @@ struct acpi_namespace_node {
/* Namespace Node flags */
#define ANOBJ_END_OF_PEER_LIST 0x01 /* End-of-list, Peer field points to parent */
-#define ANOBJ_RESERVED 0x02 /* Available for future use */
+#define ANOBJ_TEMPORARY 0x02 /* Node is create by a method and is temporary */
#define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */
#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */
#define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */
@@ -219,25 +219,42 @@ struct acpi_namespace_node {
* ACPI Table Descriptor. One per ACPI table
*/
struct acpi_table_desc {
- struct acpi_table_desc *prev;
- struct acpi_table_desc *next;
- struct acpi_table_desc *installed_desc;
+ acpi_physical_address address;
struct acpi_table_header *pointer;
- u8 *aml_start;
- u64 physical_address;
- acpi_size length;
- u32 aml_length;
+ u32 length; /* Length fixed at 32 bits */
+ union acpi_name_union signature;
acpi_owner_id owner_id;
- u8 type;
- u8 allocation;
- u8 loaded_into_namespace;
+ u8 flags;
};
-struct acpi_table_list {
- struct acpi_table_desc *next;
+/* Flags for above */
+
+#define ACPI_TABLE_ORIGIN_UNKNOWN (0)
+#define ACPI_TABLE_ORIGIN_MAPPED (1)
+#define ACPI_TABLE_ORIGIN_ALLOCATED (2)
+#define ACPI_TABLE_ORIGIN_MASK (3)
+#define ACPI_TABLE_IS_LOADED (4)
+
+/* One internal RSDT for table management */
+
+struct acpi_internal_rsdt {
+ struct acpi_table_desc *tables;
u32 count;
+ u32 size;
+ u8 flags;
};
+/* Flags for above */
+
+#define ACPI_ROOT_ORIGIN_UNKNOWN (0) /* ~ORIGIN_ALLOCATED */
+#define ACPI_ROOT_ORIGIN_ALLOCATED (1)
+#define ACPI_ROOT_ALLOW_RESIZE (2)
+
+/* Predefined (fixed) table indexes */
+
+#define ACPI_TABLE_INDEX_DSDT (0)
+#define ACPI_TABLE_INDEX_FACS (1)
+
struct acpi_find_context {
char *search_for;
acpi_handle *list;
@@ -350,7 +367,7 @@ struct acpi_gpe_event_info {
union acpi_gpe_dispatch_info dispatch; /* Either Method or Handler */
struct acpi_gpe_register_info *register_info; /* Backpointer to register info */
u8 flags; /* Misc info about this GPE */
- u8 register_bit; /* This GPE bit within the register */
+ u8 gpe_number; /* This GPE */
};
/* Information about a GPE register pair, one per each status/enable pair in an array */
@@ -855,12 +872,30 @@ struct acpi_bit_register_info {
****************************************************************************/
struct acpi_db_method_info {
- acpi_handle thread_gate;
+ acpi_handle main_thread_gate;
+ acpi_handle thread_complete_gate;
+ u32 *threads;
+ u32 num_threads;
+ u32 num_created;
+ u32 num_completed;
+
char *name;
- char **args;
u32 flags;
u32 num_loops;
char pathname[128];
+ char **args;
+
+ /*
+ * Arguments to be passed to method for the command
+ * Threads -
+ * the Number of threads, ID of current thread and
+ * Index of current thread inside all them created.
+ */
+ char init_args;
+ char *arguments[4];
+ char num_threads_str[11];
+ char id_of_thread_str[11];
+ char index_of_thread_str[11];
};
struct acpi_integrity_info {
@@ -919,6 +954,8 @@ struct acpi_memory_list {
u32 total_allocated;
u32 total_freed;
+ u32 max_occupied;
+ u32 total_size;
u32 current_total_size;
u32 requests;
u32 hits;
diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h
index 192fa095a51..8948a646183 100644
--- a/include/acpi/acmacros.h
+++ b/include/acpi/acmacros.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,25 +55,12 @@
#define ACPI_SET_BIT(target,bit) ((target) |= (bit))
#define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit))
#define ACPI_MIN(a,b) (((a)<(b))?(a):(b))
+#define ACPI_MAX(a,b) (((a)>(b))?(a):(b))
/* Size calculation */
#define ACPI_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))
-#if ACPI_MACHINE_WIDTH == 16
-
-/*
- * For 16-bit addresses, we have to assume that the upper 32 bits
- * (out of 64) are zero.
- */
-#define ACPI_LODWORD(l) ((u32)(l))
-#define ACPI_HIDWORD(l) ((u32)(0))
-
-#define ACPI_GET_ADDRESS(a) ((a).lo)
-#define ACPI_STORE_ADDRESS(a,b) {(a).hi=0;(a).lo=(u32)(b);}
-#define ACPI_VALID_ADDRESS(a) ((a).hi | (a).lo)
-
-#else
#ifdef ACPI_NO_INTEGER64_SUPPORT
/*
* acpi_integer is 32-bits, no 64-bit support on this platform
@@ -81,10 +68,6 @@
#define ACPI_LODWORD(l) ((u32)(l))
#define ACPI_HIDWORD(l) ((u32)(0))
-#define ACPI_GET_ADDRESS(a) (a)
-#define ACPI_STORE_ADDRESS(a,b) ((a)=(b))
-#define ACPI_VALID_ADDRESS(a) (a)
-
#else
/*
@@ -92,11 +75,6 @@
*/
#define ACPI_LODWORD(l) ((u32)(u64)(l))
#define ACPI_HIDWORD(l) ((u32)(((*(struct uint64_struct *)(void *)(&l))).hi))
-
-#define ACPI_GET_ADDRESS(a) (a)
-#define ACPI_STORE_ADDRESS(a,b) ((a)=(acpi_physical_address)(b))
-#define ACPI_VALID_ADDRESS(a) (a)
-#endif
#endif
/*
@@ -134,15 +112,8 @@
#define ACPI_TO_POINTER(i) ACPI_ADD_PTR (void,(void *) NULL,(acpi_native_uint) i)
#define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p,(void *) NULL)
#define ACPI_OFFSET(d,f) (acpi_size) ACPI_PTR_DIFF (&(((d *)0)->f),(void *) NULL)
-
-#if ACPI_MACHINE_WIDTH == 16
-#define ACPI_STORE_POINTER(d,s) ACPI_MOVE_32_TO_32(d,s)
-#define ACPI_PHYSADDR_TO_PTR(i) (void *)(i)
-#define ACPI_PTR_TO_PHYSADDR(i) (u32) ACPI_CAST_PTR (u8,(i))
-#else
#define ACPI_PHYSADDR_TO_PTR(i) ACPI_TO_POINTER(i)
#define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i)
-#endif
#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED
#define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (u32,(a)) == *ACPI_CAST_PTR (u32,(b)))
@@ -223,28 +194,6 @@
/* The hardware supports unaligned transfers, just do the little-endian move */
-#if ACPI_MACHINE_WIDTH == 16
-
-/* No 64-bit integers */
-/* 16-bit source, 16/32/64 destination */
-
-#define ACPI_MOVE_16_TO_16(d,s) *(u16 *)(void *)(d) = *(u16 *)(void *)(s)
-#define ACPI_MOVE_16_TO_32(d,s) *(u32 *)(void *)(d) = *(u16 *)(void *)(s)
-#define ACPI_MOVE_16_TO_64(d,s) ACPI_MOVE_16_TO_32(d,s)
-
-/* 32-bit source, 16/32/64 destination */
-
-#define ACPI_MOVE_32_TO_16(d,s) ACPI_MOVE_16_TO_16(d,s) /* Truncate to 16 */
-#define ACPI_MOVE_32_TO_32(d,s) *(u32 *)(void *)(d) = *(u32 *)(void *)(s)
-#define ACPI_MOVE_32_TO_64(d,s) ACPI_MOVE_32_TO_32(d,s)
-
-/* 64-bit source, 16/32/64 destination */
-
-#define ACPI_MOVE_64_TO_16(d,s) ACPI_MOVE_16_TO_16(d,s) /* Truncate to 16 */
-#define ACPI_MOVE_64_TO_32(d,s) ACPI_MOVE_32_TO_32(d,s) /* Truncate to 32 */
-#define ACPI_MOVE_64_TO_64(d,s) ACPI_MOVE_32_TO_32(d,s)
-
-#else
/* 16-bit source, 16/32/64 destination */
#define ACPI_MOVE_16_TO_16(d,s) *(u16 *)(void *)(d) = *(u16 *)(void *)(s)
@@ -262,7 +211,6 @@
#define ACPI_MOVE_64_TO_16(d,s) ACPI_MOVE_16_TO_16(d,s) /* Truncate to 16 */
#define ACPI_MOVE_64_TO_32(d,s) ACPI_MOVE_32_TO_32(d,s) /* Truncate to 32 */
#define ACPI_MOVE_64_TO_64(d,s) *(u64 *)(void *)(d) = *(u64 *)(void *)(s)
-#endif
#else
/*
@@ -307,10 +255,7 @@
/* Macros based on machine integer width */
-#if ACPI_MACHINE_WIDTH == 16
-#define ACPI_MOVE_SIZE_TO_16(d,s) ACPI_MOVE_16_TO_16(d,s)
-
-#elif ACPI_MACHINE_WIDTH == 32
+#if ACPI_MACHINE_WIDTH == 32
#define ACPI_MOVE_SIZE_TO_16(d,s) ACPI_MOVE_32_TO_16(d,s)
#elif ACPI_MACHINE_WIDTH == 64
@@ -695,16 +640,6 @@
#define ACPI_DEBUGGER_EXEC(a)
#endif
-/*
- * For 16-bit code, we want to shrink some things even though
- * we are using ACPI_DEBUG_OUTPUT to get the debug output
- */
-#if ACPI_MACHINE_WIDTH == 16
-#undef ACPI_DEBUG_ONLY_MEMBERS
-#undef _VERBOSE_STRUCTURES
-#define ACPI_DEBUG_ONLY_MEMBERS(a)
-#endif
-
#ifdef ACPI_DEBUG_OUTPUT
/*
* 1) Set name to blanks
diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h
index b67da363689..34bfae8a05f 100644
--- a/include/acpi/acnames.h
+++ b/include/acpi/acnames.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h
index 83b52f9f899..535b7e1c41b 100644
--- a/include/acpi/acnamesp.h
+++ b/include/acpi/acnamesp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -65,9 +65,13 @@
#define ACPI_NS_ERROR_IF_FOUND 0x08
#define ACPI_NS_PREFIX_IS_SCOPE 0x10
#define ACPI_NS_EXTERNAL 0x20
+#define ACPI_NS_TEMPORARY 0x40
-#define ACPI_NS_WALK_UNLOCK TRUE
-#define ACPI_NS_WALK_NO_UNLOCK FALSE
+/* Flags for acpi_ns_walk_namespace */
+
+#define ACPI_NS_WALK_NO_UNLOCK 0
+#define ACPI_NS_WALK_UNLOCK 0x01
+#define ACPI_NS_WALK_TEMP_NODES 0x02
/*
* nsinit - Namespace initialization
@@ -82,7 +86,7 @@ acpi_status acpi_ns_initialize_devices(void);
acpi_status acpi_ns_load_namespace(void);
acpi_status
-acpi_ns_load_table(struct acpi_table_desc *table_desc,
+acpi_ns_load_table(acpi_native_uint table_index,
struct acpi_namespace_node *node);
/*
@@ -92,7 +96,7 @@ acpi_status
acpi_ns_walk_namespace(acpi_object_type type,
acpi_handle start_object,
u32 max_depth,
- u8 unlock_before_callback,
+ u32 flags,
acpi_walk_callback user_function,
void *context, void **return_value);
@@ -106,11 +110,12 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
* nsparse - table parsing
*/
acpi_status
-acpi_ns_parse_table(struct acpi_table_desc *table_desc,
- struct acpi_namespace_node *scope);
+acpi_ns_parse_table(acpi_native_uint table_index,
+ struct acpi_namespace_node *start_node);
acpi_status
-acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc);
+acpi_ns_one_complete_parse(acpi_native_uint pass_number,
+ acpi_native_uint table_index);
/*
* nsaccess - Top-level namespace access
diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h
index 8fdee31119f..04e9735a674 100644
--- a/include/acpi/acobject.h
+++ b/include/acpi/acobject.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -52,7 +52,15 @@
* to the interpreter, and to keep track of the various handlers such as
* address space handlers and notify handlers. The object is a constant
* size in order to allow it to be cached and reused.
+ *
+ * Note: The object is optimized to be aligned and will not work if it is
+ * byte-packed.
*/
+#if ACPI_MACHINE_WIDTH == 64
+#pragma pack(8)
+#else
+#pragma pack(4)
+#endif
/*******************************************************************************
*
@@ -101,7 +109,8 @@ struct acpi_object_common {
ACPI_OBJECT_COMMON_HEADER};
struct acpi_object_integer {
- ACPI_OBJECT_COMMON_HEADER acpi_integer value;
+ ACPI_OBJECT_COMMON_HEADER u8 fill[3]; /* Prevent warning on some compilers */
+ acpi_integer value;
};
/*
@@ -203,7 +212,9 @@ struct acpi_object_power_resource {
};
struct acpi_object_processor {
- ACPI_OBJECT_COMMON_HEADER u8 proc_id;
+ ACPI_OBJECT_COMMON_HEADER
+ /* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */
+ u8 proc_id;
u8 length;
ACPI_COMMON_NOTIFY_INFO acpi_io_address address;
};
@@ -406,4 +417,6 @@ union acpi_descriptor {
union acpi_parse_object op;
};
+#pragma pack()
+
#endif /* _ACOBJECT_H */
diff --git a/include/acpi/acopcode.h b/include/acpi/acopcode.h
index 7659a46bc43..e6f76a280a9 100644
--- a/include/acpi/acopcode.h
+++ b/include/acpi/acopcode.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -257,7 +257,7 @@
#define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE
#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER)
#define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE
-#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_FIELD,ARGI_TARGETREF)
+#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_BUFFER,ARGI_TARGETREF)
#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE)
#define ARGI_LOCAL0 ARG_NONE
#define ARGI_LOCAL1 ARG_NONE
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index 8d5039d0b43..7812267b577 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acparser.h b/include/acpi/acparser.h
index 9d49d3c41cd..85c358e2101 100644
--- a/include/acpi/acparser.h
+++ b/include/acpi/acparser.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h
index b9a39d1009b..2e5f00d3ea0 100644
--- a/include/acpi/acpi.h
+++ b/include/acpi/acpi.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index fdd10953b2b..0d9f984a60a 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -59,7 +59,6 @@ acpi_evaluate_reference(acpi_handle handle,
#define ACPI_BUS_FILE_ROOT "acpi"
extern struct proc_dir_entry *acpi_root_dir;
-extern struct fadt_descriptor acpi_fadt;
enum acpi_bus_removal_type {
ACPI_BUS_REMOVAL_NORMAL = 0,
@@ -92,13 +91,12 @@ typedef int (*acpi_op_remove) (struct acpi_device * device, int type);
typedef int (*acpi_op_lock) (struct acpi_device * device, int type);
typedef int (*acpi_op_start) (struct acpi_device * device);
typedef int (*acpi_op_stop) (struct acpi_device * device, int type);
-typedef int (*acpi_op_suspend) (struct acpi_device * device, int state);
-typedef int (*acpi_op_resume) (struct acpi_device * device, int state);
+typedef int (*acpi_op_suspend) (struct acpi_device * device, pm_message_t state);
+typedef int (*acpi_op_resume) (struct acpi_device * device);
typedef int (*acpi_op_scan) (struct acpi_device * device);
typedef int (*acpi_op_bind) (struct acpi_device * device);
typedef int (*acpi_op_unbind) (struct acpi_device * device);
-typedef int (*acpi_op_match) (struct acpi_device * device,
- struct acpi_driver * driver);
+typedef int (*acpi_op_shutdown) (struct acpi_device * device);
struct acpi_bus_ops {
u32 acpi_op_add:1;
@@ -111,7 +109,7 @@ struct acpi_bus_ops {
u32 acpi_op_scan:1;
u32 acpi_op_bind:1;
u32 acpi_op_unbind:1;
- u32 acpi_op_match:1;
+ u32 acpi_op_shutdown:1;
u32 reserved:21;
};
@@ -126,16 +124,16 @@ struct acpi_device_ops {
acpi_op_scan scan;
acpi_op_bind bind;
acpi_op_unbind unbind;
- acpi_op_match match;
+ acpi_op_shutdown shutdown;
};
struct acpi_driver {
- struct list_head node;
char name[80];
char class[80];
- atomic_t references;
char *ids; /* Supported Hardware IDs */
struct acpi_device_ops ops;
+ struct device_driver drv;
+ struct module *owner;
};
/*
@@ -185,7 +183,7 @@ struct acpi_device_dir {
typedef char acpi_bus_id[5];
typedef unsigned long acpi_bus_address;
-typedef char acpi_hardware_id[9];
+typedef char acpi_hardware_id[15];
typedef char acpi_unique_id[9];
typedef char acpi_device_name[40];
typedef char acpi_device_class[20];
@@ -296,11 +294,14 @@ struct acpi_device {
struct acpi_device_ops ops;
struct acpi_driver *driver;
void *driver_data;
- struct kobject kobj;
struct device dev;
+ struct acpi_bus_ops bus_ops; /* workaround for different code path for hotplug */
+ enum acpi_bus_removal_type removal_type; /* indicate for different removal type */
};
#define acpi_driver_data(d) ((d)->driver_data)
+#define to_acpi_device(d) container_of(d, struct acpi_device, dev)
+#define to_acpi_driver(d) container_of(d, struct acpi_driver, drv)
/*
* Events
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index 6a5bdcefec6..4dc8a5043ef 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -36,13 +36,14 @@
/* _HID definitions */
-#define ACPI_POWER_HID "ACPI_PWR"
-#define ACPI_PROCESSOR_HID "ACPI_CPU"
-#define ACPI_SYSTEM_HID "ACPI_SYS"
-#define ACPI_THERMAL_HID "ACPI_THM"
-#define ACPI_BUTTON_HID_POWERF "ACPI_FPB"
-#define ACPI_BUTTON_HID_SLEEPF "ACPI_FSB"
-
+#define ACPI_POWER_HID "power_resource"
+#define ACPI_PROCESSOR_HID "ACPI0007"
+#define ACPI_SYSTEM_HID "acpi_system"
+#define ACPI_THERMAL_HID "thermal"
+#define ACPI_BUTTON_HID_POWERF "button_power"
+#define ACPI_BUTTON_HID_SLEEPF "button_sleep"
+#define ACPI_VIDEO_HID "video"
+#define ACPI_BAY_HID "bay"
/* --------------------------------------------------------------------------
PCI
-------------------------------------------------------------------------- */
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 0cd63bce0ae..781394b9efe 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -8,7 +8,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -85,7 +85,7 @@ acpi_status acpi_os_terminate(void);
/*
* ACPI Table interfaces
*/
-acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *address);
+acpi_physical_address acpi_os_get_root_pointer(void);
acpi_status
acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
@@ -143,9 +143,7 @@ void acpi_os_release_mutex(acpi_mutex handle);
*/
void *acpi_os_allocate(acpi_size size);
-acpi_status
-acpi_os_map_memory(acpi_physical_address physical_address,
- acpi_size size, void __iomem ** logical_address);
+void __iomem *acpi_os_map_memory(acpi_physical_address where, acpi_native_uint length);
void acpi_os_unmap_memory(void __iomem * logical_address, acpi_size size);
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 049e9aa1b86..e08f7df85a4 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,10 @@
/*
* Global interfaces
*/
+acpi_status
+acpi_initialize_tables(struct acpi_table_desc *initial_storage,
+ u32 initial_table_count, u8 allow_resize);
+
acpi_status acpi_initialize_subsystem(void);
acpi_status acpi_enable_subsystem(u32 flags);
@@ -92,29 +96,28 @@ void acpi_free(void *address);
/*
* ACPI table manipulation interfaces
*/
-acpi_status
-acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address);
+acpi_status acpi_reallocate_root_table(void);
+
+acpi_status acpi_find_root_pointer(acpi_native_uint * rsdp_address);
acpi_status acpi_load_tables(void);
-#ifdef ACPI_FUTURE_USAGE
acpi_status acpi_load_table(struct acpi_table_header *table_ptr);
-acpi_status acpi_unload_table(acpi_table_type table_type);
+acpi_status acpi_unload_table_id(acpi_owner_id id);
acpi_status
-acpi_get_table_header(acpi_table_type table_type,
- u32 instance, struct acpi_table_header *out_table_header);
-#endif /* ACPI_FUTURE_USAGE */
+acpi_get_table_header(acpi_string signature,
+ acpi_native_uint instance,
+ struct acpi_table_header *out_table_header);
acpi_status
-acpi_get_table(acpi_table_type table_type,
- u32 instance, struct acpi_buffer *ret_buffer);
+acpi_get_table(acpi_string signature,
+ acpi_native_uint instance, struct acpi_table_header **out_table);
acpi_status
-acpi_get_firmware_table(acpi_string signature,
- u32 instance,
- u32 flags, struct acpi_table_header **table_pointer);
+acpi_get_table_by_index(acpi_native_uint table_index,
+ struct acpi_table_header **out_table);
/*
* Namespace and name interfaces
@@ -180,6 +183,8 @@ acpi_get_next_object(acpi_object_type type,
acpi_status acpi_get_type(acpi_handle object, acpi_object_type * out_type);
+acpi_status acpi_get_id(acpi_handle object, acpi_owner_id * out_type);
+
acpi_status acpi_get_parent(acpi_handle object, acpi_handle * out_handle);
/*
@@ -307,9 +312,9 @@ acpi_resource_to_address64(struct acpi_resource *resource,
/*
* Hardware (ACPI device) interfaces
*/
-acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags);
+acpi_status acpi_get_register(u32 register_id, u32 * return_value);
-acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags);
+acpi_status acpi_set_register(u32 register_id, u32 value);
acpi_status
acpi_set_firmware_waking_vector(acpi_physical_address physical_address);
diff --git a/include/acpi/acresrc.h b/include/acpi/acresrc.h
index 80a3b33571b..9486ab266a5 100644
--- a/include/acpi/acresrc.h
+++ b/include/acpi/acresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h
index 5e8095f0f78..aeb4498e5e0 100644
--- a/include/acpi/acstruct.h
+++ b/include/acpi/acstruct.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -139,7 +139,8 @@ struct acpi_init_walk_info {
u16 buffer_init;
u16 package_init;
u16 object_count;
- struct acpi_table_desc *table_desc;
+ acpi_owner_id owner_id;
+ acpi_native_uint table_index;
};
struct acpi_get_devices_info {
diff --git a/include/acpi/actables.h b/include/acpi/actables.h
index 4dbaf02fe52..2b9f46f9da4 100644
--- a/include/acpi/actables.h
+++ b/include/acpi/actables.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,105 +44,75 @@
#ifndef __ACTABLES_H__
#define __ACTABLES_H__
-/* Used in acpi_tb_map_acpi_table for size parameter if table header is to be used */
-
-#define SIZE_IN_HEADER 0
+acpi_status acpi_allocate_root_table(u32 initial_table_count);
/*
- * tbconvrt - Table conversion routines
+ * tbfadt - FADT parse/convert/validate
*/
-acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info);
-
-acpi_status acpi_tb_convert_table_fadt(void);
+void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags);
-acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info);
-
-u32
-acpi_tb_get_table_count(struct rsdp_descriptor *RSDP,
- struct acpi_table_header *RSDT);
+void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length);
/*
- * tbget - Table "get" routines
+ * tbfind - find ACPI table
*/
acpi_status
-acpi_tb_get_table(struct acpi_pointer *address,
- struct acpi_table_desc *table_info);
-
-acpi_status
-acpi_tb_get_table_header(struct acpi_pointer *address,
- struct acpi_table_header *return_header);
-
-acpi_status
-acpi_tb_get_table_body(struct acpi_pointer *address,
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info);
-
-acpi_status
-acpi_tb_get_table_ptr(acpi_table_type table_type,
- u32 instance, struct acpi_table_header **table_ptr_loc);
-
-acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address);
-
-void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address);
-
-acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr);
+acpi_tb_find_table(char *signature,
+ char *oem_id,
+ char *oem_table_id, acpi_native_uint * table_index);
/*
- * tbgetall - get multiple required tables
+ * tbinstal - Table removal and deletion
*/
-acpi_status acpi_tb_get_required_tables(void);
+acpi_status acpi_tb_resize_root_table_list(void);
-/*
- * tbinstall - Table installation
- */
-acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info);
+acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc);
acpi_status
-acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type);
+acpi_tb_add_table(struct acpi_table_desc *table_desc,
+ acpi_native_uint * table_index);
acpi_status
-acpi_tb_init_table_descriptor(acpi_table_type table_type,
- struct acpi_table_desc *table_info);
+acpi_tb_store_table(acpi_physical_address address,
+ struct acpi_table_header *table,
+ u32 length, u8 flags, acpi_native_uint * table_index);
-/*
- * tbremove - Table removal and deletion
- */
-void acpi_tb_delete_all_tables(void);
+void acpi_tb_delete_table(struct acpi_table_desc *table_desc);
-void acpi_tb_delete_tables_by_type(acpi_table_type type);
+void acpi_tb_terminate(void);
-void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc);
+void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index);
-struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
- *table_desc);
+acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index);
+
+acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index);
-/*
- * tbxfroot - RSDP, RSDT utilities
- */
acpi_status
-acpi_tb_find_table(char *signature,
- char *oem_id,
- char *oem_table_id, struct acpi_table_header **table_ptr);
+acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id);
-acpi_status acpi_tb_get_table_rsdt(void);
+u8 acpi_tb_is_table_loaded(acpi_native_uint table_index);
-acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp);
+void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded);
/*
- * tbutils - common table utilities
+ * tbutils - table manager utilities
*/
-acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc);
+u8 acpi_tb_tables_loaded(void);
-acpi_status
-acpi_tb_verify_table_checksum(struct acpi_table_header *table_header);
+void
+acpi_tb_print_table_header(acpi_physical_address address,
+ struct acpi_table_header *header);
-u8 acpi_tb_sum_table(void *buffer, u32 length);
+u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length);
-u8 acpi_tb_generate_checksum(struct acpi_table_header *table);
+acpi_status
+acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length);
-void acpi_tb_set_checksum(struct acpi_table_header *table);
+void
+acpi_tb_install_table(acpi_physical_address address,
+ u8 flags, char *signature, acpi_native_uint table_index);
acpi_status
-acpi_tb_validate_table_header(struct acpi_table_header *table_header);
+acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags);
#endif /* __ACTABLES_H__ */
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index b125ceed9cb..09469e7db6a 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,15 +48,15 @@
* Values for description table header signatures. Useful because they make
* it more difficult to inadvertently type in the wrong signature.
*/
-#define DSDT_SIG "DSDT" /* Differentiated System Description Table */
-#define FADT_SIG "FACP" /* Fixed ACPI Description Table */
-#define FACS_SIG "FACS" /* Firmware ACPI Control Structure */
-#define PSDT_SIG "PSDT" /* Persistent System Description Table */
-#define RSDP_SIG "RSD PTR " /* Root System Description Pointer */
-#define RSDT_SIG "RSDT" /* Root System Description Table */
-#define XSDT_SIG "XSDT" /* Extended System Description Table */
-#define SSDT_SIG "SSDT" /* Secondary System Description Table */
-#define RSDP_NAME "RSDP"
+#define ACPI_SIG_DSDT "DSDT" /* Differentiated System Description Table */
+#define ACPI_SIG_FADT "FACP" /* Fixed ACPI Description Table */
+#define ACPI_SIG_FACS "FACS" /* Firmware ACPI Control Structure */
+#define ACPI_SIG_PSDT "PSDT" /* Persistent System Description Table */
+#define ACPI_SIG_RSDP "RSD PTR " /* Root System Description Pointer */
+#define ACPI_SIG_RSDT "RSDT" /* Root System Description Table */
+#define ACPI_SIG_XSDT "XSDT" /* Extended System Description Table */
+#define ACPI_SIG_SSDT "SSDT" /* Secondary System Description Table */
+#define ACPI_RSDP_NAME "RSDP" /* Short name for RSDP, not signature */
/*
* All tables and structures must be byte-packed to match the ACPI
@@ -83,27 +83,29 @@
*
******************************************************************************/
-#define ACPI_TABLE_HEADER_DEF \
- char signature[4]; /* ASCII table signature */\
- u32 length; /* Length of table in bytes, including this header */\
- u8 revision; /* ACPI Specification minor version # */\
- u8 checksum; /* To make sum of entire table == 0 */\
- char oem_id[6]; /* ASCII OEM identification */\
- char oem_table_id[8]; /* ASCII OEM table identification */\
- u32 oem_revision; /* OEM revision number */\
- char asl_compiler_id[4]; /* ASCII ASL compiler vendor ID */\
- u32 asl_compiler_revision; /* ASL compiler version */
-
struct acpi_table_header {
-ACPI_TABLE_HEADER_DEF};
+ char signature[ACPI_NAME_SIZE]; /* ASCII table signature */
+ u32 length; /* Length of table in bytes, including this header */
+ u8 revision; /* ACPI Specification minor version # */
+ u8 checksum; /* To make sum of entire table == 0 */
+ char oem_id[ACPI_OEM_ID_SIZE]; /* ASCII OEM identification */
+ char oem_table_id[ACPI_OEM_TABLE_ID_SIZE]; /* ASCII OEM table identification */
+ u32 oem_revision; /* OEM revision number */
+ char asl_compiler_id[ACPI_NAME_SIZE]; /* ASCII ASL compiler vendor ID */
+ u32 asl_compiler_revision; /* ASL compiler version */
+};
/*
* GAS - Generic Address Structure (ACPI 2.0+)
+ *
+ * Note: Since this structure is used in the ACPI tables, it is byte aligned.
+ * If misalignment is not supported, access to the Address field must be
+ * performed with care.
*/
struct acpi_generic_address {
- u8 address_space_id; /* Address space where struct or register exists */
- u8 register_bit_width; /* Size in bits of given register */
- u8 register_bit_offset; /* Bit offset within the register */
+ u8 space_id; /* Address space where struct or register exists */
+ u8 bit_width; /* Size in bits of given register */
+ u8 bit_offset; /* Bit offset within the register */
u8 access_width; /* Minimum Access size (ACPI 3.0) */
u64 address; /* 64-bit address of struct or register */
};
@@ -114,10 +116,10 @@ struct acpi_generic_address {
*
******************************************************************************/
-struct rsdp_descriptor {
+struct acpi_table_rsdp {
char signature[8]; /* ACPI signature, contains "RSD PTR " */
u8 checksum; /* ACPI 1.0 checksum */
- char oem_id[6]; /* OEM identification */
+ char oem_id[ACPI_OEM_ID_SIZE]; /* OEM identification */
u8 revision; /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */
u32 rsdt_physical_address; /* 32-bit physical address of the RSDT */
u32 length; /* Table length in bytes, including header (ACPI 2.0+) */
@@ -134,12 +136,14 @@ struct rsdp_descriptor {
*
******************************************************************************/
-struct rsdt_descriptor {
- ACPI_TABLE_HEADER_DEF u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */
+struct acpi_table_rsdt {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */
};
-struct xsdt_descriptor {
- ACPI_TABLE_HEADER_DEF u64 table_offset_entry[1]; /* Array of pointers to ACPI tables */
+struct acpi_table_xsdt {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u64 table_offset_entry[1]; /* Array of pointers to ACPI tables */
};
/*******************************************************************************
@@ -148,36 +152,27 @@ struct xsdt_descriptor {
*
******************************************************************************/
-struct facs_descriptor {
+struct acpi_table_facs {
char signature[4]; /* ASCII table signature */
u32 length; /* Length of structure, in bytes */
u32 hardware_signature; /* Hardware configuration signature */
u32 firmware_waking_vector; /* 32-bit physical address of the Firmware Waking Vector */
u32 global_lock; /* Global Lock for shared hardware resources */
-
- /* Flags (32 bits) */
-
- u8 S4bios_f:1; /* 00: S4BIOS support is present */
- u8:7; /* 01-07: Reserved, must be zero */
- u8 reserved1[3]; /* 08-31: Reserved, must be zero */
-
+ u32 flags;
u64 xfirmware_waking_vector; /* 64-bit version of the Firmware Waking Vector (ACPI 2.0+) */
u8 version; /* Version of this table (ACPI 2.0+) */
u8 reserved[31]; /* Reserved, must be zero */
};
+/* Flag macros */
+
+#define ACPI_FACS_S4_BIOS_PRESENT (1) /* 00: S4BIOS support is present */
+
+/* Global lock flags */
+
#define ACPI_GLOCK_PENDING 0x01 /* 00: Pending global lock ownership */
#define ACPI_GLOCK_OWNED 0x02 /* 01: Global lock is owned */
-/*
- * Common FACS - This is a version-independent FACS structure used for internal use only
- */
-struct acpi_common_facs {
- u32 *global_lock;
- u64 *firmware_waking_vector;
- u8 vector_width;
-};
-
/*******************************************************************************
*
* FADT - Fixed ACPI Description Table (Signature "FACP")
@@ -186,121 +181,98 @@ struct acpi_common_facs {
/* Fields common to all versions of the FADT */
-#define ACPI_FADT_COMMON \
- ACPI_TABLE_HEADER_DEF \
- u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ \
- u32 V1_dsdt; /* 32-bit physical address of DSDT */ \
- u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ \
- u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ \
- u16 sci_int; /* System vector of SCI interrupt */ \
- u32 smi_cmd; /* Port address of SMI command port */ \
- u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ \
- u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ \
- u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ \
- u8 pstate_cnt; /* Processor performance state control*/ \
- u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a Event Reg Blk */ \
- u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b Event Reg Blk */ \
- u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ \
- u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ \
- u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ \
- u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ \
- u32 V1_gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ \
- u32 V1_gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ \
- u8 pm1_evt_len; /* Byte Length of ports at pm1_x_evt_blk */ \
- u8 pm1_cnt_len; /* Byte Length of ports at pm1_x_cnt_blk */ \
- u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ \
- u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ \
- u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ \
- u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ \
- u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ \
- u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ \
- u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ \
- u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ \
- u16 flush_size; /* Processor's memory cache line width, in bytes */ \
- u16 flush_stride; /* Number of flush strides that need to be read */ \
- u8 duty_offset; /* Processor's duty cycle index in processor's P_CNT reg*/ \
- u8 duty_width; /* Processor's duty cycle value bit width in P_CNT register.*/ \
- u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ \
- u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ \
- u8 century; /* Index to century in RTC CMOS RAM */ \
- u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ \
- u8 reserved2; /* Reserved, must be zero */
-
-/*
- * ACPI 2.0+ FADT
- */
-struct fadt_descriptor {
- ACPI_FADT_COMMON
- /* Flags (32 bits) */
- u8 wb_invd:1; /* 00: The wbinvd instruction works properly */
- u8 wb_invd_flush:1; /* 01: The wbinvd flushes but does not invalidate */
- u8 proc_c1:1; /* 02: All processors support C1 state */
- u8 plvl2_up:1; /* 03: C2 state works on MP system */
- u8 pwr_button:1; /* 04: Power button is handled as a generic feature */
- u8 sleep_button:1; /* 05: Sleep button is handled as a generic feature, or not present */
- u8 fixed_rTC:1; /* 06: RTC wakeup stat not in fixed register space */
- u8 rtcs4:1; /* 07: RTC wakeup stat not possible from S4 */
- u8 tmr_val_ext:1; /* 08: tmr_val is 32 bits 0=24-bits */
- u8 dock_cap:1; /* 09: Docking supported */
- u8 reset_reg_sup:1; /* 10: System reset via the FADT RESET_REG supported */
- u8 sealed_case:1; /* 11: No internal expansion capabilities and case is sealed */
- u8 headless:1; /* 12: No local video capabilities or local input devices */
- u8 cpu_sw_sleep:1; /* 13: Must execute native instruction after writing SLP_TYPx register */
-
- u8 pci_exp_wak:1; /* 14: System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */
- u8 use_platform_clock:1; /* 15: OSPM should use platform-provided timer (ACPI 3.0) */
- u8 S4rtc_sts_valid:1; /* 16: Contents of RTC_STS valid after S4 wake (ACPI 3.0) */
- u8 remote_power_on_capable:1; /* 17: System is compatible with remote power on (ACPI 3.0) */
- u8 force_apic_cluster_model:1; /* 18: All local APICs must use cluster model (ACPI 3.0) */
- u8 force_apic_physical_destination_mode:1; /* 19: All local x_aPICs must use physical dest mode (ACPI 3.0) */
- u8:4; /* 20-23: Reserved, must be zero */
- u8 reserved3; /* 24-31: Reserved, must be zero */
-
- struct acpi_generic_address reset_register; /* Reset register address in GAS format */
+struct acpi_table_fadt {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 facs; /* 32-bit physical address of FACS */
+ u32 dsdt; /* 32-bit physical address of DSDT */
+ u8 model; /* System Interrupt Model (ACPI 1.0) - not used in ACPI 2.0+ */
+ u8 preferred_profile; /* Conveys preferred power management profile to OSPM. */
+ u16 sci_interrupt; /* System vector of SCI interrupt */
+ u32 smi_command; /* 32-bit Port address of SMI command port */
+ u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */
+ u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */
+ u8 S4bios_request; /* Value to write to SMI CMD to enter S4BIOS state */
+ u8 pstate_control; /* Processor performance state control */
+ u32 pm1a_event_block; /* 32-bit Port address of Power Mgt 1a Event Reg Blk */
+ u32 pm1b_event_block; /* 32-bit Port address of Power Mgt 1b Event Reg Blk */
+ u32 pm1a_control_block; /* 32-bit Port address of Power Mgt 1a Control Reg Blk */
+ u32 pm1b_control_block; /* 32-bit Port address of Power Mgt 1b Control Reg Blk */
+ u32 pm2_control_block; /* 32-bit Port address of Power Mgt 2 Control Reg Blk */
+ u32 pm_timer_block; /* 32-bit Port address of Power Mgt Timer Ctrl Reg Blk */
+ u32 gpe0_block; /* 32-bit Port address of General Purpose Event 0 Reg Blk */
+ u32 gpe1_block; /* 32-bit Port address of General Purpose Event 1 Reg Blk */
+ u8 pm1_event_length; /* Byte Length of ports at pm1x_event_block */
+ u8 pm1_control_length; /* Byte Length of ports at pm1x_control_block */
+ u8 pm2_control_length; /* Byte Length of ports at pm2_control_block */
+ u8 pm_timer_length; /* Byte Length of ports at pm_timer_block */
+ u8 gpe0_block_length; /* Byte Length of ports at gpe0_block */
+ u8 gpe1_block_length; /* Byte Length of ports at gpe1_block */
+ u8 gpe1_base; /* Offset in GPE number space where GPE1 events start */
+ u8 cst_control; /* Support for the _CST object and C States change notification */
+ u16 C2latency; /* Worst case HW latency to enter/exit C2 state */
+ u16 C3latency; /* Worst case HW latency to enter/exit C3 state */
+ u16 flush_size; /* Processor's memory cache line width, in bytes */
+ u16 flush_stride; /* Number of flush strides that need to be read */
+ u8 duty_offset; /* Processor duty cycle index in processor's P_CNT reg */
+ u8 duty_width; /* Processor duty cycle value bit width in P_CNT register. */
+ u8 day_alarm; /* Index to day-of-month alarm in RTC CMOS RAM */
+ u8 month_alarm; /* Index to month-of-year alarm in RTC CMOS RAM */
+ u8 century; /* Index to century in RTC CMOS RAM */
+ u16 boot_flags; /* IA-PC Boot Architecture Flags. See Table 5-10 for description */
+ u8 reserved; /* Reserved, must be zero */
+ u32 flags; /* Miscellaneous flag bits (see below for individual flags) */
+ struct acpi_generic_address reset_register; /* 64-bit address of the Reset register */
u8 reset_value; /* Value to write to the reset_register port to reset the system */
- u8 reserved4[3]; /* These three bytes must be zero */
- u64 xfirmware_ctrl; /* 64-bit physical address of FACS */
+ u8 reserved4[3]; /* Reserved, must be zero */
+ u64 Xfacs; /* 64-bit physical address of FACS */
u64 Xdsdt; /* 64-bit physical address of DSDT */
- struct acpi_generic_address xpm1a_evt_blk; /* Extended Power Mgt 1a acpi_event Reg Blk address */
- struct acpi_generic_address xpm1b_evt_blk; /* Extended Power Mgt 1b acpi_event Reg Blk address */
- struct acpi_generic_address xpm1a_cnt_blk; /* Extended Power Mgt 1a Control Reg Blk address */
- struct acpi_generic_address xpm1b_cnt_blk; /* Extended Power Mgt 1b Control Reg Blk address */
- struct acpi_generic_address xpm2_cnt_blk; /* Extended Power Mgt 2 Control Reg Blk address */
- struct acpi_generic_address xpm_tmr_blk; /* Extended Power Mgt Timer Ctrl Reg Blk address */
- struct acpi_generic_address xgpe0_blk; /* Extended General Purpose acpi_event 0 Reg Blk address */
- struct acpi_generic_address xgpe1_blk; /* Extended General Purpose acpi_event 1 Reg Blk address */
+ struct acpi_generic_address xpm1a_event_block; /* 64-bit Extended Power Mgt 1a Event Reg Blk address */
+ struct acpi_generic_address xpm1b_event_block; /* 64-bit Extended Power Mgt 1b Event Reg Blk address */
+ struct acpi_generic_address xpm1a_control_block; /* 64-bit Extended Power Mgt 1a Control Reg Blk address */
+ struct acpi_generic_address xpm1b_control_block; /* 64-bit Extended Power Mgt 1b Control Reg Blk address */
+ struct acpi_generic_address xpm2_control_block; /* 64-bit Extended Power Mgt 2 Control Reg Blk address */
+ struct acpi_generic_address xpm_timer_block; /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */
+ struct acpi_generic_address xgpe0_block; /* 64-bit Extended General Purpose Event 0 Reg Blk address */
+ struct acpi_generic_address xgpe1_block; /* 64-bit Extended General Purpose Event 1 Reg Blk address */
};
-/*
- * "Down-revved" ACPI 2.0 FADT descriptor
- * Defined here to allow compiler to generate the length of the struct
- */
-struct fadt_descriptor_rev2_minus {
- ACPI_FADT_COMMON u32 flags;
- struct acpi_generic_address reset_register; /* Reset register address in GAS format */
- u8 reset_value; /* Value to write to the reset_register port to reset the system. */
- u8 reserved7[3]; /* Reserved, must be zero */
-};
+/* FADT flags */
+
+#define ACPI_FADT_WBINVD (1) /* 00: The wbinvd instruction works properly */
+#define ACPI_FADT_WBINVD_FLUSH (1<<1) /* 01: The wbinvd flushes but does not invalidate */
+#define ACPI_FADT_C1_SUPPORTED (1<<2) /* 02: All processors support C1 state */
+#define ACPI_FADT_C2_MP_SUPPORTED (1<<3) /* 03: C2 state works on MP system */
+#define ACPI_FADT_POWER_BUTTON (1<<4) /* 04: Power button is handled as a generic feature */
+#define ACPI_FADT_SLEEP_BUTTON (1<<5) /* 05: Sleep button is handled as a generic feature, or not present */
+#define ACPI_FADT_FIXED_RTC (1<<6) /* 06: RTC wakeup stat not in fixed register space */
+#define ACPI_FADT_S4_RTC_WAKE (1<<7) /* 07: RTC wakeup stat not possible from S4 */
+#define ACPI_FADT_32BIT_TIMER (1<<8) /* 08: tmr_val is 32 bits 0=24-bits */
+#define ACPI_FADT_DOCKING_SUPPORTED (1<<9) /* 09: Docking supported */
+#define ACPI_FADT_RESET_REGISTER (1<<10) /* 10: System reset via the FADT RESET_REG supported */
+#define ACPI_FADT_SEALED_CASE (1<<11) /* 11: No internal expansion capabilities and case is sealed */
+#define ACPI_FADT_HEADLESS (1<<12) /* 12: No local video capabilities or local input devices */
+#define ACPI_FADT_SLEEP_TYPE (1<<13) /* 13: Must execute native instruction after writing SLP_TYPx register */
+#define ACPI_FADT_PCI_EXPRESS_WAKE (1<<14) /* 14: System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */
+#define ACPI_FADT_PLATFORM_CLOCK (1<<15) /* 15: OSPM should use platform-provided timer (ACPI 3.0) */
+#define ACPI_FADT_S4_RTC_VALID (1<<16) /* 16: Contents of RTC_STS valid after S4 wake (ACPI 3.0) */
+#define ACPI_FADT_REMOTE_POWER_ON (1<<17) /* 17: System is compatible with remote power on (ACPI 3.0) */
+#define ACPI_FADT_APIC_CLUSTER (1<<18) /* 18: All local APICs must use cluster model (ACPI 3.0) */
+#define ACPI_FADT_APIC_PHYSICAL (1<<19) /* 19: All local x_aPICs must use physical dest mode (ACPI 3.0) */
/*
- * ACPI 1.0 FADT
- * Defined here to allow compiler to generate the length of the struct
+ * FADT Prefered Power Management Profiles
*/
-struct fadt_descriptor_rev1 {
- ACPI_FADT_COMMON u32 flags;
+enum acpi_prefered_pm_profiles {
+ PM_UNSPECIFIED = 0,
+ PM_DESKTOP = 1,
+ PM_MOBILE = 2,
+ PM_WORKSTATION = 3,
+ PM_ENTERPRISE_SERVER = 4,
+ PM_SOHO_SERVER = 5,
+ PM_APPLIANCE_PC = 6
};
-/* FADT: Prefered Power Management Profiles */
-
-#define PM_UNSPECIFIED 0
-#define PM_DESKTOP 1
-#define PM_MOBILE 2
-#define PM_WORKSTATION 3
-#define PM_ENTERPRISE_SERVER 4
-#define PM_SOHO_SERVER 5
-#define PM_APPLIANCE_PC 6
-
-/* FADT: Boot Arch Flags */
+/* FADT Boot Arch Flags */
#define BAF_LEGACY_DEVICES 0x0001
#define BAF_8042_KEYBOARD_CONTROLLER 0x0002
@@ -312,59 +284,12 @@ struct fadt_descriptor_rev1 {
#pragma pack()
-/*
- * This macro is temporary until the table bitfield flag definitions
- * are removed and replaced by a Flags field.
- */
-#define ACPI_FLAG_OFFSET(d,f,o) (u8) (ACPI_OFFSET (d,f) + \
- sizeof(((d *)0)->f) + o)
-/*
- * Get the remaining ACPI tables
- */
-#include "actbl1.h"
+#define ACPI_FADT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_fadt, f)
/*
- * ACPI Table information. We save the table address, length,
- * and type of memory allocation (mapped or allocated) for each
- * table for 1) when we exit, and 2) if a new table is installed
+ * Get the remaining ACPI tables
*/
-#define ACPI_MEM_NOT_ALLOCATED 0
-#define ACPI_MEM_ALLOCATED 1
-#define ACPI_MEM_MAPPED 2
-
-/* Definitions for the Flags bitfield member of struct acpi_table_support */
-
-#define ACPI_TABLE_SINGLE 0x00
-#define ACPI_TABLE_MULTIPLE 0x01
-#define ACPI_TABLE_EXECUTABLE 0x02
-
-#define ACPI_TABLE_ROOT 0x00
-#define ACPI_TABLE_PRIMARY 0x10
-#define ACPI_TABLE_SECONDARY 0x20
-#define ACPI_TABLE_ALL 0x30
-#define ACPI_TABLE_TYPE_MASK 0x30
-
-/* Data about each known table type */
-
-struct acpi_table_support {
- char *name;
- char *signature;
- void **global_ptr;
- u8 sig_length;
- u8 flags;
-};
-
-extern u8 acpi_fadt_is_v1; /* is set to 1 if FADT is revision 1,
- * needed for certain workarounds */
-/* Macros used to generate offsets to specific table fields */
-
-#define ACPI_FACS_OFFSET(f) (u8) ACPI_OFFSET (struct facs_descriptor,f)
-#define ACPI_FADT_OFFSET(f) (u8) ACPI_OFFSET (struct fadt_descriptor, f)
-#define ACPI_GAS_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_generic_address,f)
-#define ACPI_HDR_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_header,f)
-#define ACPI_RSDP_OFFSET(f) (u8) ACPI_OFFSET (struct rsdp_descriptor,f)
-#define ACPI_FADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct fadt_descriptor,f,o)
-#define ACPI_FACS_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct facs_descriptor,f,o)
+#include <acpi/actbl1.h>
#endif /* __ACTBL_H__ */
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index 745a6445a4f..4e5d3ca53a8 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,6 +61,7 @@
#define ACPI_SIG_BOOT "BOOT" /* Simple Boot Flag Table */
#define ACPI_SIG_CPEP "CPEP" /* Corrected Platform Error Polling table */
#define ACPI_SIG_DBGP "DBGP" /* Debug Port table */
+#define ACPI_SIG_DMAR "DMAR" /* DMA Remapping table */
#define ACPI_SIG_ECDT "ECDT" /* Embedded Controller Boot Resources Table */
#define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */
#define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */
@@ -73,12 +74,6 @@
#define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */
#define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */
-/* Legacy names */
-
-#define APIC_SIG "APIC" /* Multiple APIC Description Table */
-#define BOOT_SIG "BOOT" /* Simple Boot Flag Table */
-#define SBST_SIG "SBST" /* Smart Battery Specification Table */
-
/*
* All tables must be byte-packed to match the ACPI specification, since
* the tables are provided by the system BIOS.
@@ -91,31 +86,43 @@
* portable, so do not use any other bitfield types.
*/
+/* Common Sub-table header (used in MADT, SRAT, etc.) */
+
+struct acpi_subtable_header {
+ u8 type;
+ u8 length;
+};
+
/*******************************************************************************
*
* ASF - Alert Standard Format table (Signature "ASF!")
*
+ * Conforms to the Alert Standard Format Specification V2.0, 23 April 2003
+ *
******************************************************************************/
struct acpi_table_asf {
-ACPI_TABLE_HEADER_DEF};
+ struct acpi_table_header header; /* Common ACPI table header */
+};
-#define ACPI_ASF_HEADER_DEF \
- u8 type; \
- u8 reserved; \
- u16 length;
+/* ASF subtable header */
struct acpi_asf_header {
-ACPI_ASF_HEADER_DEF};
+ u8 type;
+ u8 reserved;
+ u16 length;
+};
-/* Values for Type field */
+/* Values for Type field above */
-#define ASF_INFO 0
-#define ASF_ALERT 1
-#define ASF_CONTROL 2
-#define ASF_BOOT 3
-#define ASF_ADDRESS 4
-#define ASF_RESERVED 5
+enum acpi_asf_type {
+ ACPI_ASF_TYPE_INFO = 0,
+ ACPI_ASF_TYPE_ALERT = 1,
+ ACPI_ASF_TYPE_CONTROL = 2,
+ ACPI_ASF_TYPE_BOOT = 3,
+ ACPI_ASF_TYPE_ADDRESS = 4,
+ ACPI_ASF_TYPE_RESERVED = 5
+};
/*
* ASF subtables
@@ -124,7 +131,8 @@ ACPI_ASF_HEADER_DEF};
/* 0: ASF Information */
struct acpi_asf_info {
- ACPI_ASF_HEADER_DEF u8 min_reset_value;
+ struct acpi_asf_header header;
+ u8 min_reset_value;
u8 min_poll_interval;
u16 system_id;
u32 mfg_id;
@@ -135,26 +143,49 @@ struct acpi_asf_info {
/* 1: ASF Alerts */
struct acpi_asf_alert {
- ACPI_ASF_HEADER_DEF u8 assert_mask;
+ struct acpi_asf_header header;
+ u8 assert_mask;
u8 deassert_mask;
u8 alerts;
u8 data_length;
- u8 array[1];
+};
+
+struct acpi_asf_alert_data {
+ u8 address;
+ u8 command;
+ u8 mask;
+ u8 value;
+ u8 sensor_type;
+ u8 type;
+ u8 offset;
+ u8 source_type;
+ u8 severity;
+ u8 sensor_number;
+ u8 entity;
+ u8 instance;
};
/* 2: ASF Remote Control */
struct acpi_asf_remote {
- ACPI_ASF_HEADER_DEF u8 controls;
+ struct acpi_asf_header header;
+ u8 controls;
u8 data_length;
u16 reserved2;
- u8 array[1];
+};
+
+struct acpi_asf_control_data {
+ u8 function;
+ u8 address;
+ u8 command;
+ u8 value;
};
/* 3: ASF RMCP Boot Options */
struct acpi_asf_rmcp {
- ACPI_ASF_HEADER_DEF u8 capabilities[7];
+ struct acpi_asf_header header;
+ u8 capabilities[7];
u8 completion_code;
u32 enterprise_id;
u8 command;
@@ -166,9 +197,9 @@ struct acpi_asf_rmcp {
/* 4: ASF Address */
struct acpi_asf_address {
- ACPI_ASF_HEADER_DEF u8 eprom_address;
+ struct acpi_asf_header header;
+ u8 eprom_address;
u8 devices;
- u8 smbus_addresses[1];
};
/*******************************************************************************
@@ -178,7 +209,8 @@ struct acpi_asf_address {
******************************************************************************/
struct acpi_table_boot {
- ACPI_TABLE_HEADER_DEF u8 cmos_index; /* Index in CMOS RAM for the boot register */
+ struct acpi_table_header header; /* Common ACPI table header */
+ u8 cmos_index; /* Index in CMOS RAM for the boot register */
u8 reserved[3];
};
@@ -189,7 +221,8 @@ struct acpi_table_boot {
******************************************************************************/
struct acpi_table_cpep {
- ACPI_TABLE_HEADER_DEF u64 reserved;
+ struct acpi_table_header header; /* Common ACPI table header */
+ u64 reserved;
};
/* Subtable */
@@ -197,9 +230,9 @@ struct acpi_table_cpep {
struct acpi_cpep_polling {
u8 type;
u8 length;
- u8 processor_id; /* Processor ID */
- u8 processor_eid; /* Processor EID */
- u32 polling_interval; /* Polling interval (msec) */
+ u8 id; /* Processor ID */
+ u8 eid; /* Processor EID */
+ u32 interval; /* Polling interval (msec) */
};
/*******************************************************************************
@@ -209,196 +242,281 @@ struct acpi_cpep_polling {
******************************************************************************/
struct acpi_table_dbgp {
- ACPI_TABLE_HEADER_DEF u8 interface_type; /* 0=full 16550, 1=subset of 16550 */
+ struct acpi_table_header header; /* Common ACPI table header */
+ u8 type; /* 0=full 16550, 1=subset of 16550 */
u8 reserved[3];
struct acpi_generic_address debug_port;
};
/*******************************************************************************
*
- * ECDT - Embedded Controller Boot Resources Table
+ * DMAR - DMA Remapping table
*
******************************************************************************/
-struct ec_boot_resources {
- ACPI_TABLE_HEADER_DEF struct acpi_generic_address ec_control; /* Address of EC command/status register */
- struct acpi_generic_address ec_data; /* Address of EC data register */
- u32 uid; /* Unique ID - must be same as the EC _UID method */
- u8 gpe_bit; /* The GPE for the EC */
- u8 ec_id[1]; /* Full namepath of the EC in the ACPI namespace */
+struct acpi_table_dmar {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u8 width; /* Host Address Width */
+ u8 reserved[11];
+};
+
+/* DMAR subtable header */
+
+struct acpi_dmar_header {
+ u16 type;
+ u16 length;
+ u8 flags;
+ u8 reserved[3];
+};
+
+/* Values for subtable type in struct acpi_dmar_header */
+
+enum acpi_dmar_type {
+ ACPI_DMAR_TYPE_HARDWARE_UNIT = 0,
+ ACPI_DMAR_TYPE_RESERVED_MEMORY = 1,
+ ACPI_DMAR_TYPE_RESERVED = 2 /* 2 and greater are reserved */
+};
+
+struct acpi_dmar_device_scope {
+ u8 entry_type;
+ u8 length;
+ u8 segment;
+ u8 bus;
+};
+
+/* Values for entry_type in struct acpi_dmar_device_scope */
+
+enum acpi_dmar_scope_type {
+ ACPI_DMAR_SCOPE_TYPE_NOT_USED = 0,
+ ACPI_DMAR_SCOPE_TYPE_ENDPOINT = 1,
+ ACPI_DMAR_SCOPE_TYPE_BRIDGE = 2,
+ ACPI_DMAR_SCOPE_TYPE_RESERVED = 3 /* 3 and greater are reserved */
+};
+
+/*
+ * DMAR Sub-tables, correspond to Type in struct acpi_dmar_header
+ */
+
+/* 0: Hardware Unit Definition */
+
+struct acpi_dmar_hardware_unit {
+ struct acpi_dmar_header header;
+ u64 address; /* Register Base Address */
+};
+
+/* Flags */
+
+#define ACPI_DMAR_INCLUDE_ALL (1)
+
+/* 1: Reserved Memory Defininition */
+
+struct acpi_dmar_reserved_memory {
+ struct acpi_dmar_header header;
+ u64 address; /* 4_k aligned base address */
+ u64 end_address; /* 4_k aligned limit address */
};
+/* Flags */
+
+#define ACPI_DMAR_ALLOW_ALL (1)
+
/*******************************************************************************
*
- * HPET - High Precision Event Timer table
+ * ECDT - Embedded Controller Boot Resources Table
*
******************************************************************************/
-struct acpi_hpet_table {
- ACPI_TABLE_HEADER_DEF u32 hardware_id; /* Hardware ID of event timer block */
- struct acpi_generic_address base_address; /* Address of event timer block */
- u8 hpet_number; /* HPET sequence number */
- u16 clock_tick; /* Main counter min tick, periodic mode */
- u8 attributes;
+struct acpi_table_ecdt {
+ struct acpi_table_header header; /* Common ACPI table header */
+ struct acpi_generic_address control; /* Address of EC command/status register */
+ struct acpi_generic_address data; /* Address of EC data register */
+ u32 uid; /* Unique ID - must be same as the EC _UID method */
+ u8 gpe; /* The GPE for the EC */
+ u8 id[1]; /* Full namepath of the EC in the ACPI namespace */
};
-#if 0 /* HPET flags to be converted to macros */
-struct { /* Flags (8 bits) */
- u8 page_protect:1; /* 00: No page protection */
- u8 page_protect4:1; /* 01: 4_kB page protected */
- u8 page_protect64:1; /* 02: 64_kB page protected */
- u8:5; /* 03-07: Reserved, must be zero */
-} flags;
-#endif
-
/*******************************************************************************
*
- * MADT - Multiple APIC Description Table
+ * HPET - High Precision Event Timer table
*
******************************************************************************/
-struct multiple_apic_table {
- ACPI_TABLE_HEADER_DEF u32 local_apic_address; /* Physical address of local APIC */
-
- /* Flags (32 bits) */
-
- u8 PCATcompat:1; /* 00: System also has dual 8259s */
- u8:7; /* 01-07: Reserved, must be zero */
- u8 reserved1[3]; /* 08-31: Reserved, must be zero */
+struct acpi_table_hpet {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 id; /* Hardware ID of event timer block */
+ struct acpi_generic_address address; /* Address of event timer block */
+ u8 sequence; /* HPET sequence number */
+ u16 minimum_tick; /* Main counter min tick, periodic mode */
+ u8 flags;
};
-/* Values for MADT PCATCompat */
+/*! Flags */
-#define DUAL_PIC 0
-#define MULTIPLE_APIC 1
+#define ACPI_HPET_PAGE_PROTECT (1) /* 00: No page protection */
+#define ACPI_HPET_PAGE_PROTECT_4 (1<<1) /* 01: 4KB page protected */
+#define ACPI_HPET_PAGE_PROTECT_64 (1<<2) /* 02: 64KB page protected */
-/* Common MADT Sub-table header */
+/*! [End] no source code translation !*/
-#define APIC_HEADER_DEF \
- u8 type; \
- u8 length;
-
-struct apic_header {
-APIC_HEADER_DEF};
-
-/* Values for Type in struct apic_header */
+/*******************************************************************************
+ *
+ * MADT - Multiple APIC Description Table
+ *
+ ******************************************************************************/
-#define APIC_PROCESSOR 0
-#define APIC_IO 1
-#define APIC_XRUPT_OVERRIDE 2
-#define APIC_NMI 3
-#define APIC_LOCAL_NMI 4
-#define APIC_ADDRESS_OVERRIDE 5
-#define APIC_IO_SAPIC 6
-#define APIC_LOCAL_SAPIC 7
-#define APIC_XRUPT_SOURCE 8
-#define APIC_RESERVED 9 /* 9 and greater are reserved */
+struct acpi_table_madt {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 address; /* Physical address of local APIC */
+ u32 flags;
+};
-/* Flag definitions for MADT sub-tables */
+/* Flags */
-#define ACPI_MADT_IFLAGS /* INTI flags (16 bits) */ \
- u8 polarity : 2; /* 00-01: Polarity of APIC I/O input signals */\
- u8 trigger_mode : 2; /* 02-03: Trigger mode of APIC input signals */\
- u8 : 4; /* 04-07: Reserved, must be zero */\
- u8 reserved1; /* 08-15: Reserved, must be zero */
+#define ACPI_MADT_PCAT_COMPAT (1) /* 00: System also has dual 8259s */
-#define ACPI_MADT_LFLAGS /* Local Sapic flags (32 bits) */ \
- u8 processor_enabled: 1; /* 00: Processor is usable if set */\
- u8 : 7; /* 01-07: Reserved, must be zero */\
- u8 reserved2[3]; /* 08-31: Reserved, must be zero */
+/* Values for PCATCompat flag */
-/* Values for MPS INTI flags */
+#define ACPI_MADT_DUAL_PIC 0
+#define ACPI_MADT_MULTIPLE_APIC 1
-#define POLARITY_CONFORMS 0
-#define POLARITY_ACTIVE_HIGH 1
-#define POLARITY_RESERVED 2
-#define POLARITY_ACTIVE_LOW 3
+/* Values for subtable type in struct acpi_subtable_header */
-#define TRIGGER_CONFORMS 0
-#define TRIGGER_EDGE 1
-#define TRIGGER_RESERVED 2
-#define TRIGGER_LEVEL 3
+enum acpi_madt_type {
+ ACPI_MADT_TYPE_LOCAL_APIC = 0,
+ ACPI_MADT_TYPE_IO_APIC = 1,
+ ACPI_MADT_TYPE_INTERRUPT_OVERRIDE = 2,
+ ACPI_MADT_TYPE_NMI_SOURCE = 3,
+ ACPI_MADT_TYPE_LOCAL_APIC_NMI = 4,
+ ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE = 5,
+ ACPI_MADT_TYPE_IO_SAPIC = 6,
+ ACPI_MADT_TYPE_LOCAL_SAPIC = 7,
+ ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8,
+ ACPI_MADT_TYPE_RESERVED = 9 /* 9 and greater are reserved */
+};
/*
- * MADT Sub-tables, correspond to Type in struct apic_header
+ * MADT Sub-tables, correspond to Type in struct acpi_subtable_header
*/
-/* 0: processor APIC */
+/* 0: Processor Local APIC */
-struct madt_processor_apic {
- APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */
- u8 local_apic_id; /* Processor's local APIC id */
- ACPI_MADT_LFLAGS};
+struct acpi_madt_local_apic {
+ struct acpi_subtable_header header;
+ u8 processor_id; /* ACPI processor id */
+ u8 id; /* Processor's local APIC id */
+ u32 lapic_flags;
+};
/* 1: IO APIC */
-struct madt_io_apic {
- APIC_HEADER_DEF u8 io_apic_id; /* I/O APIC ID */
+struct acpi_madt_io_apic {
+ struct acpi_subtable_header header;
+ u8 id; /* I/O APIC ID */
u8 reserved; /* Reserved - must be zero */
u32 address; /* APIC physical address */
- u32 interrupt; /* Global system interrupt where INTI lines start */
+ u32 global_irq_base; /* Global system interrupt where INTI lines start */
};
/* 2: Interrupt Override */
-struct madt_interrupt_override {
- APIC_HEADER_DEF u8 bus; /* 0 - ISA */
- u8 source; /* Interrupt source (IRQ) */
- u32 interrupt; /* Global system interrupt */
- ACPI_MADT_IFLAGS};
+struct acpi_madt_interrupt_override {
+ struct acpi_subtable_header header;
+ u8 bus; /* 0 - ISA */
+ u8 source_irq; /* Interrupt source (IRQ) */
+ u32 global_irq; /* Global system interrupt */
+ u16 inti_flags;
+};
-/* 3: NMI Sources */
+/* 3: NMI Source */
-struct madt_nmi_source {
- APIC_HEADER_DEF ACPI_MADT_IFLAGS u32 interrupt; /* Global system interrupt */
+struct acpi_madt_nmi_source {
+ struct acpi_subtable_header header;
+ u16 inti_flags;
+ u32 global_irq; /* Global system interrupt */
};
/* 4: Local APIC NMI */
-struct madt_local_apic_nmi {
- APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */
- ACPI_MADT_IFLAGS u8 lint; /* LINTn to which NMI is connected */
+struct acpi_madt_local_apic_nmi {
+ struct acpi_subtable_header header;
+ u8 processor_id; /* ACPI processor id */
+ u16 inti_flags;
+ u8 lint; /* LINTn to which NMI is connected */
};
/* 5: Address Override */
-struct madt_address_override {
- APIC_HEADER_DEF u16 reserved; /* Reserved, must be zero */
+struct acpi_madt_local_apic_override {
+ struct acpi_subtable_header header;
+ u16 reserved; /* Reserved, must be zero */
u64 address; /* APIC physical address */
};
/* 6: I/O Sapic */
-struct madt_io_sapic {
- APIC_HEADER_DEF u8 io_sapic_id; /* I/O SAPIC ID */
+struct acpi_madt_io_sapic {
+ struct acpi_subtable_header header;
+ u8 id; /* I/O SAPIC ID */
u8 reserved; /* Reserved, must be zero */
- u32 interrupt_base; /* Glocal interrupt for SAPIC start */
+ u32 global_irq_base; /* Global interrupt for SAPIC start */
u64 address; /* SAPIC physical address */
};
/* 7: Local Sapic */
-struct madt_local_sapic {
- APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */
- u8 local_sapic_id; /* SAPIC ID */
- u8 local_sapic_eid; /* SAPIC EID */
+struct acpi_madt_local_sapic {
+ struct acpi_subtable_header header;
+ u8 processor_id; /* ACPI processor id */
+ u8 id; /* SAPIC ID */
+ u8 eid; /* SAPIC EID */
u8 reserved[3]; /* Reserved, must be zero */
- ACPI_MADT_LFLAGS u32 processor_uID; /* Numeric UID - ACPI 3.0 */
- char processor_uIDstring[1]; /* String UID - ACPI 3.0 */
+ u32 lapic_flags;
+ u32 uid; /* Numeric UID - ACPI 3.0 */
+ char uid_string[1]; /* String UID - ACPI 3.0 */
};
/* 8: Platform Interrupt Source */
-struct madt_interrupt_source {
- APIC_HEADER_DEF ACPI_MADT_IFLAGS u8 interrupt_type; /* 1=PMI, 2=INIT, 3=corrected */
- u8 processor_id; /* Processor ID */
- u8 processor_eid; /* Processor EID */
+struct acpi_madt_interrupt_source {
+ struct acpi_subtable_header header;
+ u16 inti_flags;
+ u8 type; /* 1=PMI, 2=INIT, 3=corrected */
+ u8 id; /* Processor ID */
+ u8 eid; /* Processor EID */
u8 io_sapic_vector; /* Vector value for PMI interrupts */
- u32 interrupt; /* Global system interrupt */
+ u32 global_irq; /* Global system interrupt */
u32 flags; /* Interrupt Source Flags */
};
-#ifdef DUPLICATE_DEFINITION_WITH_LINUX_ACPI_H
+/* Flags field above */
+
+#define ACPI_MADT_CPEI_OVERRIDE (1)
+
+/*
+ * Common flags fields for MADT subtables
+ */
+
+/* MADT Local APIC flags (lapic_flags) */
+
+#define ACPI_MADT_ENABLED (1) /* 00: Processor is usable if set */
+
+/* MADT MPS INTI flags (inti_flags) */
+
+#define ACPI_MADT_POLARITY_MASK (3) /* 00-01: Polarity of APIC I/O input signals */
+#define ACPI_MADT_TRIGGER_MASK (3<<2) /* 02-03: Trigger mode of APIC input signals */
+
+/* Values for MPS INTI flags */
+
+#define ACPI_MADT_POLARITY_CONFORMS 0
+#define ACPI_MADT_POLARITY_ACTIVE_HIGH 1
+#define ACPI_MADT_POLARITY_RESERVED 2
+#define ACPI_MADT_POLARITY_ACTIVE_LOW 3
+
+#define ACPI_MADT_TRIGGER_CONFORMS (0)
+#define ACPI_MADT_TRIGGER_EDGE (1<<2)
+#define ACPI_MADT_TRIGGER_RESERVED (2<<2)
+#define ACPI_MADT_TRIGGER_LEVEL (3<<2)
+
/*******************************************************************************
*
* MCFG - PCI Memory Mapped Configuration table and sub-table
@@ -406,17 +524,19 @@ struct madt_interrupt_source {
******************************************************************************/
struct acpi_table_mcfg {
- ACPI_TABLE_HEADER_DEF u8 reserved[8];
+ struct acpi_table_header header; /* Common ACPI table header */
+ u8 reserved[8];
};
+/* Subtable */
+
struct acpi_mcfg_allocation {
- u64 base_address; /* Base address, processor-relative */
+ u64 address; /* Base address, processor-relative */
u16 pci_segment; /* PCI segment group number */
u8 start_bus_number; /* Starting PCI Bus number */
u8 end_bus_number; /* Final PCI Bus number */
u32 reserved;
};
-#endif
/*******************************************************************************
*
@@ -424,8 +544,9 @@ struct acpi_mcfg_allocation {
*
******************************************************************************/
-struct smart_battery_table {
- ACPI_TABLE_HEADER_DEF u32 warning_level;
+struct acpi_table_sbst {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 warning_level;
u32 low_level;
u32 critical_level;
};
@@ -436,9 +557,10 @@ struct smart_battery_table {
*
******************************************************************************/
-struct system_locality_info {
- ACPI_TABLE_HEADER_DEF u64 locality_count;
- u8 entry[1][1];
+struct acpi_table_slit {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u64 locality_count;
+ u8 entry[1]; /* Real size = localities^2 */
};
/*******************************************************************************
@@ -448,7 +570,8 @@ struct system_locality_info {
******************************************************************************/
struct acpi_table_spcr {
- ACPI_TABLE_HEADER_DEF u8 interface_type; /* 0=full 16550, 1=subset of 16550 */
+ struct acpi_table_header header; /* Common ACPI table header */
+ u8 interface_type; /* 0=full 16550, 1=subset of 16550 */
u8 reserved[3];
struct acpi_generic_address serial_port;
u8 interrupt_type;
@@ -459,7 +582,7 @@ struct acpi_table_spcr {
u8 stop_bits;
u8 flow_control;
u8 terminal_type;
- u8 reserved2;
+ u8 reserved1;
u16 pci_device_id;
u16 pci_vendor_id;
u8 pci_bus;
@@ -467,7 +590,7 @@ struct acpi_table_spcr {
u8 pci_function;
u32 pci_flags;
u8 pci_segment;
- u32 reserved3;
+ u32 reserved2;
};
/*******************************************************************************
@@ -477,12 +600,13 @@ struct acpi_table_spcr {
******************************************************************************/
struct acpi_table_spmi {
- ACPI_TABLE_HEADER_DEF u8 reserved;
+ struct acpi_table_header header; /* Common ACPI table header */
+ u8 reserved;
u8 interface_type;
u16 spec_revision; /* Version of IPMI */
u8 interrupt_type;
u8 gpe_number; /* GPE assigned */
- u8 reserved2;
+ u8 reserved1;
u8 pci_device_flag;
u32 interrupt;
struct acpi_generic_address ipmi_register;
@@ -498,58 +622,53 @@ struct acpi_table_spmi {
*
******************************************************************************/
-struct system_resource_affinity {
- ACPI_TABLE_HEADER_DEF u32 reserved1; /* Must be value '1' */
- u64 reserved2; /* Reserved, must be zero */
+struct acpi_table_srat {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 table_revision; /* Must be value '1' */
+ u64 reserved; /* Reserved, must be zero */
};
-/* SRAT common sub-table header */
+/* Values for subtable type in struct acpi_subtable_header */
-#define SRAT_SUBTABLE_HEADER \
- u8 type; \
- u8 length;
-
-/* Values for Type above */
-
-#define SRAT_CPU_AFFINITY 0
-#define SRAT_MEMORY_AFFINITY 1
-#define SRAT_RESERVED 2
+enum acpi_srat_type {
+ ACPI_SRAT_TYPE_CPU_AFFINITY = 0,
+ ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1,
+ ACPI_SRAT_TYPE_RESERVED = 2
+};
/* SRAT sub-tables */
-struct static_resource_alloc {
- SRAT_SUBTABLE_HEADER u8 proximity_domain_lo;
+struct acpi_srat_cpu_affinity {
+ struct acpi_subtable_header header;
+ u8 proximity_domain_lo;
u8 apic_id;
-
- /* Flags (32 bits) */
-
- u8 enabled:1; /* 00: Use affinity structure */
- u8:7; /* 01-07: Reserved, must be zero */
- u8 reserved3[3]; /* 08-31: Reserved, must be zero */
-
+ u32 flags;
u8 local_sapic_eid;
u8 proximity_domain_hi[3];
- u32 reserved4; /* Reserved, must be zero */
+ u32 reserved; /* Reserved, must be zero */
};
-struct memory_affinity {
- SRAT_SUBTABLE_HEADER u32 proximity_domain;
- u16 reserved3;
- u64 base_address;
- u64 address_length;
- u32 reserved4;
-
- /* Flags (32 bits) */
+/* Flags */
- u8 enabled:1; /* 00: Use affinity structure */
- u8 hot_pluggable:1; /* 01: Memory region is hot pluggable */
- u8 non_volatile:1; /* 02: Memory is non-volatile */
- u8:5; /* 03-07: Reserved, must be zero */
- u8 reserved5[3]; /* 08-31: Reserved, must be zero */
+#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */
- u64 reserved6; /* Reserved, must be zero */
+struct acpi_srat_mem_affinity {
+ struct acpi_subtable_header header;
+ u32 proximity_domain;
+ u16 reserved; /* Reserved, must be zero */
+ u64 base_address;
+ u64 length;
+ u32 memory_type; /* See acpi_address_range_id */
+ u32 flags;
+ u64 reserved1; /* Reserved, must be zero */
};
+/* Flags */
+
+#define ACPI_SRAT_MEM_ENABLED (1) /* 00: Use affinity structure */
+#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1) /* 01: Memory region is hot pluggable */
+#define ACPI_SRAT_MEM_NON_VOLATILE (1<<2) /* 02: Memory region is non-volatile */
+
/*******************************************************************************
*
* TCPA - Trusted Computing Platform Alliance table
@@ -557,7 +676,8 @@ struct memory_affinity {
******************************************************************************/
struct acpi_table_tcpa {
- ACPI_TABLE_HEADER_DEF u16 reserved;
+ struct acpi_table_header header; /* Common ACPI table header */
+ u16 reserved;
u32 max_log_length; /* Maximum length for the event log area */
u64 log_address; /* Address of the event log area */
};
@@ -569,7 +689,8 @@ struct acpi_table_tcpa {
******************************************************************************/
struct acpi_table_wdrt {
- ACPI_TABLE_HEADER_DEF u32 header_length; /* Watchdog Header Length */
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 header_length; /* Watchdog Header Length */
u8 pci_segment; /* PCI Segment number */
u8 pci_bus; /* PCI Bus number */
u8 pci_device; /* PCI Device number */
@@ -582,58 +703,9 @@ struct acpi_table_wdrt {
u32 entries; /* Number of watchdog entries that follow */
};
-#if 0 /* Flags, will be converted to macros */
-u8 enabled:1; /* 00: Timer enabled */
-u8:6; /* 01-06: Reserved */
-u8 sleep_stop:1; /* 07: Timer stopped in sleep state */
-#endif
-
-/* Macros used to generate offsets to specific table fields */
-
-#define ACPI_ASF0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_info,f)
-#define ACPI_ASF1_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_alert,f)
-#define ACPI_ASF2_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_remote,f)
-#define ACPI_ASF3_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_rmcp,f)
-#define ACPI_ASF4_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_address,f)
-#define ACPI_BOOT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_boot,f)
-#define ACPI_CPEP_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_cpep,f)
-#define ACPI_CPEP0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_cpep_polling,f)
-#define ACPI_DBGP_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_dbgp,f)
-#define ACPI_ECDT_OFFSET(f) (u8) ACPI_OFFSET (struct ec_boot_resources,f)
-#define ACPI_HPET_OFFSET(f) (u8) ACPI_OFFSET (struct hpet_table,f)
-#define ACPI_MADT_OFFSET(f) (u8) ACPI_OFFSET (struct multiple_apic_table,f)
-#define ACPI_MADT0_OFFSET(f) (u8) ACPI_OFFSET (struct madt_processor_apic,f)
-#define ACPI_MADT1_OFFSET(f) (u8) ACPI_OFFSET (struct madt_io_apic,f)
-#define ACPI_MADT2_OFFSET(f) (u8) ACPI_OFFSET (struct madt_interrupt_override,f)
-#define ACPI_MADT3_OFFSET(f) (u8) ACPI_OFFSET (struct madt_nmi_source,f)
-#define ACPI_MADT4_OFFSET(f) (u8) ACPI_OFFSET (struct madt_local_apic_nmi,f)
-#define ACPI_MADT5_OFFSET(f) (u8) ACPI_OFFSET (struct madt_address_override,f)
-#define ACPI_MADT6_OFFSET(f) (u8) ACPI_OFFSET (struct madt_io_sapic,f)
-#define ACPI_MADT7_OFFSET(f) (u8) ACPI_OFFSET (struct madt_local_sapic,f)
-#define ACPI_MADT8_OFFSET(f) (u8) ACPI_OFFSET (struct madt_interrupt_source,f)
-#define ACPI_MADTH_OFFSET(f) (u8) ACPI_OFFSET (struct apic_header,f)
-#define ACPI_MCFG_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_mcfg,f)
-#define ACPI_MCFG0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_mcfg_allocation,f)
-#define ACPI_SBST_OFFSET(f) (u8) ACPI_OFFSET (struct smart_battery_table,f)
-#define ACPI_SLIT_OFFSET(f) (u8) ACPI_OFFSET (struct system_locality_info,f)
-#define ACPI_SPCR_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_spcr,f)
-#define ACPI_SPMI_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_spmi,f)
-#define ACPI_SRAT_OFFSET(f) (u8) ACPI_OFFSET (struct system_resource_affinity,f)
-#define ACPI_SRAT0_OFFSET(f) (u8) ACPI_OFFSET (struct static_resource_alloc,f)
-#define ACPI_SRAT1_OFFSET(f) (u8) ACPI_OFFSET (struct memory_affinity,f)
-#define ACPI_TCPA_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_tcpa,f)
-#define ACPI_WDRT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_wdrt,f)
-
-#define ACPI_HPET_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct hpet_table,f,o)
-#define ACPI_SRAT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct static_resource_alloc,f,o)
-#define ACPI_SRAT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct memory_affinity,f,o)
-#define ACPI_MADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct multiple_apic_table,f,o)
-#define ACPI_MADT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_processor_apic,f,o)
-#define ACPI_MADT2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_interrupt_override,f,o)
-#define ACPI_MADT3_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_nmi_source,f,o)
-#define ACPI_MADT4_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_local_apic_nmi,f,o)
-#define ACPI_MADT7_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_local_sapic,f,o)
-#define ACPI_MADT8_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_interrupt_source,f,o)
+/* Flags */
+
+#define ACPI_WDRT_TIMER_ENABLED (1) /* 00: Timer enabled */
/* Reset to default packing */
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
deleted file mode 100644
index 67efe6cad27..00000000000
--- a/include/acpi/actbl2.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/******************************************************************************
- *
- * Name: actbl2.h - ACPI Specification Revision 2.0 Tables
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#ifndef __ACTBL2_H__
-#define __ACTBL2_H__
-
-/* Code moved to both actbl.h and actbl1.h */
-
-#endif /* __ACTBL2_H__ */
diff --git a/include/acpi/actbl71.h b/include/acpi/actbl71.h
deleted file mode 100644
index 10ac05bb36b..00000000000
--- a/include/acpi/actbl71.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/******************************************************************************
- *
- * Name: actbl71.h - IA-64 Extensions to the ACPI Spec Rev. 0.71
- * This file includes tables specific to this
- * specification revision.
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2003, R. Byron Moore
- *
- * This program is free software; you can redistribute it and/or modify
- * 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 __ACTBL71_H__
-#define __ACTBL71_H__
-
-/* 0.71 FADT address_space data item bitmasks defines */
-/* If the associated bit is zero then it is in memory space else in io space */
-
-#define SMI_CMD_ADDRESS_SPACE 0x01
-#define PM1_BLK_ADDRESS_SPACE 0x02
-#define PM2_CNT_BLK_ADDRESS_SPACE 0x04
-#define PM_TMR_BLK_ADDRESS_SPACE 0x08
-#define GPE0_BLK_ADDRESS_SPACE 0x10
-#define GPE1_BLK_ADDRESS_SPACE 0x20
-
-/* Only for clarity in declarations */
-
-typedef u64 IO_ADDRESS;
-
-#pragma pack(1)
-struct { /* Root System Descriptor Pointer */
- NATIVE_CHAR signature[8]; /* contains "RSD PTR " */
- u8 checksum; /* to make sum of struct == 0 */
- NATIVE_CHAR oem_id[6]; /* OEM identification */
- u8 reserved; /* Must be 0 for 1.0, 2 for 2.0 */
- u64 rsdt_physical_address; /* 64-bit physical address of RSDT */
-};
-
-/*****************************************/
-/* IA64 Extensions to ACPI Spec Rev 0.71 */
-/* for the Root System Description Table */
-/*****************************************/
-struct {
- struct acpi_table_header header; /* Table header */
- u32 reserved_pad; /* IA64 alignment, must be 0 */
- u64 table_offset_entry[1]; /* Array of pointers to other */
- /* tables' headers */
-};
-
-/*******************************************/
-/* IA64 Extensions to ACPI Spec Rev 0.71 */
-/* for the Firmware ACPI Control Structure */
-/*******************************************/
-struct {
- NATIVE_CHAR signature[4]; /* signature "FACS" */
- u32 length; /* length of structure, in bytes */
- u32 hardware_signature; /* hardware configuration signature */
- u32 reserved4; /* must be 0 */
- u64 firmware_waking_vector; /* ACPI OS waking vector */
- u64 global_lock; /* Global Lock */
- u32 S4bios_f:1; /* Indicates if S4BIOS support is present */
- u32 reserved1:31; /* must be 0 */
- u8 reserved3[28]; /* reserved - must be zero */
-};
-
-/******************************************/
-/* IA64 Extensions to ACPI Spec Rev 0.71 */
-/* for the Fixed ACPI Description Table */
-/******************************************/
-struct {
- struct acpi_table_header header; /* table header */
- u32 reserved_pad; /* IA64 alignment, must be 0 */
- u64 firmware_ctrl; /* 64-bit Physical address of FACS */
- u64 dsdt; /* 64-bit Physical address of DSDT */
- u8 model; /* System Interrupt Model */
- u8 address_space; /* Address Space Bitmask */
- u16 sci_int; /* System vector of SCI interrupt */
- u8 acpi_enable; /* value to write to smi_cmd to enable ACPI */
- u8 acpi_disable; /* value to write to smi_cmd to disable ACPI */
- u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
- u8 reserved2; /* reserved - must be zero */
- u64 smi_cmd; /* Port address of SMI command port */
- u64 pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
- u64 pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
- u64 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
- u64 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
- u64 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
- u64 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
- u64 gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
- u64 gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
- u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
- u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
- u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
- u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */
- u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
- u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
- u8 gpe1_base; /* offset in gpe model where gpe1 events start */
- u8 reserved3; /* reserved */
- u16 plvl2_lat; /* worst case HW latency to enter/exit C2 state */
- u16 plvl3_lat; /* worst case HW latency to enter/exit C3 state */
- u8 day_alrm; /* index to day-of-month alarm in RTC CMOS RAM */
- u8 mon_alrm; /* index to month-of-year alarm in RTC CMOS RAM */
- u8 century; /* index to century in RTC CMOS RAM */
- u8 reserved4; /* reserved */
- u32 flush_cash:1; /* PAL_FLUSH_CACHE is correctly supported */
- u32 reserved5:1; /* reserved - must be zero */
- u32 proc_c1:1; /* all processors support C1 state */
- u32 plvl2_up:1; /* C2 state works on MP system */
- u32 pwr_button:1; /* Power button is handled as a generic feature */
- u32 sleep_button:1; /* Sleep button is handled as a generic feature, or not present */
- u32 fixed_rTC:1; /* RTC wakeup stat not in fixed register space */
- u32 rtcs4:1; /* RTC wakeup stat not possible from S4 */
- u32 tmr_val_ext:1; /* tmr_val is 32 bits */
- u32 dock_cap:1; /* Supports Docking */
- u32 reserved6:22; /* reserved - must be zero */
-};
-
-#pragma pack()
-
-#endif /* __ACTBL71_H__ */
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 64b603cfe92..72a6e2c3a53 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,8 @@
/*
* ACPI_MACHINE_WIDTH must be specified in an OS- or compiler-dependent header
- * and must be either 16, 32, or 64
+ * and must be either 32 or 64. 16-bit ACPICA is no longer supported, as of
+ * 12/2006.
*/
#ifndef ACPI_MACHINE_WIDTH
#error ACPI_MACHINE_WIDTH not defined
@@ -149,7 +150,6 @@ typedef int INT32;
typedef u64 acpi_native_uint;
typedef s64 acpi_native_int;
-typedef u64 acpi_table_ptr;
typedef u64 acpi_io_address;
typedef u64 acpi_physical_address;
@@ -189,48 +189,15 @@ typedef int INT32;
typedef u32 acpi_native_uint;
typedef s32 acpi_native_int;
-typedef u64 acpi_table_ptr;
typedef u32 acpi_io_address;
-typedef u64 acpi_physical_address;
+typedef u32 acpi_physical_address;
#define ACPI_MAX_PTR ACPI_UINT32_MAX
#define ACPI_SIZE_MAX ACPI_UINT32_MAX
-/*******************************************************************************
- *
- * Types specific to 16-bit targets
- *
- ******************************************************************************/
-
-#elif ACPI_MACHINE_WIDTH == 16
-
-/*! [Begin] no source code translation (keep the typedefs as-is) */
-
-typedef unsigned long UINT32;
-typedef short INT16;
-typedef long INT32;
-
-/*! [End] no source code translation !*/
-
-typedef u16 acpi_native_uint;
-typedef s16 acpi_native_int;
-
-typedef u32 acpi_table_ptr;
-typedef u32 acpi_io_address;
-typedef char *acpi_physical_address;
-
-#define ACPI_MAX_PTR ACPI_UINT16_MAX
-#define ACPI_SIZE_MAX ACPI_UINT16_MAX
-
-#define ACPI_USE_NATIVE_DIVIDE /* No 64-bit integers, ok to use native divide */
-
-/* 64-bit integers cannot be supported */
-
-#define ACPI_NO_INTEGER64_SUPPORT
-
#else
-/* ACPI_MACHINE_WIDTH must be either 64, 32, or 16 */
+/* ACPI_MACHINE_WIDTH must be either 64 or 32 */
#error unknown ACPI_MACHINE_WIDTH
#endif
@@ -311,36 +278,6 @@ typedef acpi_native_uint acpi_size;
*
******************************************************************************/
-/*
- * Pointer overlays to avoid lots of typecasting for
- * code that accepts both physical and logical pointers.
- */
-union acpi_pointers {
- acpi_physical_address physical;
- void *logical;
- acpi_table_ptr value;
-};
-
-struct acpi_pointer {
- u32 pointer_type;
- union acpi_pointers pointer;
-};
-
-/* pointer_types for above */
-
-#define ACPI_PHYSICAL_POINTER 0x01
-#define ACPI_LOGICAL_POINTER 0x02
-
-/* Processor mode */
-
-#define ACPI_PHYSICAL_ADDRESSING 0x04
-#define ACPI_LOGICAL_ADDRESSING 0x08
-#define ACPI_MEMORY_MODE 0x0C
-
-#define ACPI_PHYSMODE_PHYSPTR ACPI_PHYSICAL_ADDRESSING | ACPI_PHYSICAL_POINTER
-#define ACPI_LOGMODE_PHYSPTR ACPI_LOGICAL_ADDRESSING | ACPI_PHYSICAL_POINTER
-#define ACPI_LOGMODE_LOGPTR ACPI_LOGICAL_ADDRESSING | ACPI_LOGICAL_POINTER
-
/* Logical defines and NULL */
#ifdef FALSE
@@ -442,7 +379,8 @@ typedef u64 acpi_integer;
/*
* Initialization state
*/
-#define ACPI_INITIALIZED_OK 0x01
+#define ACPI_SUBSYSTEM_INITIALIZE 0x01
+#define ACPI_INITIALIZED_OK 0x02
/*
* Power state values
@@ -491,21 +429,6 @@ typedef u64 acpi_integer;
#define ACPI_NOTIFY_POWER_FAULT (u8) 7
/*
- * Table types. These values are passed to the table related APIs
- */
-typedef u32 acpi_table_type;
-
-#define ACPI_TABLE_ID_RSDP (acpi_table_type) 0
-#define ACPI_TABLE_ID_DSDT (acpi_table_type) 1
-#define ACPI_TABLE_ID_FADT (acpi_table_type) 2
-#define ACPI_TABLE_ID_FACS (acpi_table_type) 3
-#define ACPI_TABLE_ID_PSDT (acpi_table_type) 4
-#define ACPI_TABLE_ID_SSDT (acpi_table_type) 5
-#define ACPI_TABLE_ID_XSDT (acpi_table_type) 6
-#define ACPI_TABLE_ID_MAX 6
-#define ACPI_NUM_TABLE_TYPES (ACPI_TABLE_ID_MAX+1)
-
-/*
* Types associated with ACPI names and objects. The first group of
* values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition
* of the ACPI object_type() operator (See the ACPI Spec). Therefore,
@@ -637,7 +560,7 @@ typedef u32 acpi_event_status;
* | | | +--- Type of dispatch -- to method, handler, or none
* | | +--- Enabled for runtime?
* | +--- Enabled for wake?
- * +--- System state when GPE ocurred (running/waking)
+ * +--- Unused
*/
#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x01
#define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x01
@@ -663,10 +586,6 @@ typedef u32 acpi_event_status;
#define ACPI_GPE_ENABLE_MASK (u8) 0x60 /* Both run/wake */
-#define ACPI_GPE_SYSTEM_MASK (u8) 0x80
-#define ACPI_GPE_SYSTEM_RUNNING (u8) 0x80
-#define ACPI_GPE_SYSTEM_WAKING (u8) 0x00
-
/*
* Flags for GPE and Lock interfaces
*/
@@ -816,13 +735,6 @@ struct acpi_buffer {
#define ACPI_SYS_MODES_MASK 0x0003
/*
- * ACPI Table Info. One per ACPI table _type_
- */
-struct acpi_table_info {
- u32 count;
-};
-
-/*
* System info returned by acpi_get_system_info()
*/
struct acpi_system_info {
@@ -833,8 +745,6 @@ struct acpi_system_info {
u32 reserved2;
u32 debug_level;
u32 debug_layer;
- u32 num_table_types;
- struct acpi_table_info table_info[ACPI_TABLE_ID_MAX + 1];
};
/*
diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h
index ba039ea1a05..883ffe92148 100644
--- a/include/acpi/acutils.h
+++ b/include/acpi/acutils.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -141,8 +141,6 @@ acpi_status acpi_ut_hardware_initialize(void);
void acpi_ut_subsystem_shutdown(void);
-acpi_status acpi_ut_validate_fadt(void);
-
/*
* utclib - Local implementations of C library functions
*/
@@ -453,6 +451,8 @@ acpi_ut_short_divide(acpi_integer in_dividend,
/*
* utmisc
*/
+const char *acpi_ut_validate_exception(acpi_status status);
+
u8 acpi_ut_is_aml_table(struct acpi_table_header *table);
acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id);
@@ -470,7 +470,7 @@ void acpi_ut_print_string(char *string, u8 max_length);
u8 acpi_ut_valid_acpi_name(u32 name);
-acpi_name acpi_ut_repair_name(acpi_name name);
+acpi_name acpi_ut_repair_name(char *name);
u8 acpi_ut_valid_acpi_char(char character, acpi_native_uint position);
diff --git a/include/acpi/amlcode.h b/include/acpi/amlcode.h
index cf18426a87b..da53a4ef287 100644
--- a/include/acpi/amlcode.h
+++ b/include/acpi/amlcode.h
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -273,7 +273,7 @@
#define ARGI_DATAOBJECT 0x12 /* Buffer, String, package or reference to a Node - Used only by size_of operator */
#define ARGI_COMPLEXOBJ 0x13 /* Buffer, String, or package (Used by INDEX op only) */
#define ARGI_REF_OR_STRING 0x14 /* Reference or String (Used by DEREFOF op only) */
-#define ARGI_REGION_OR_FIELD 0x15 /* Used by LOAD op only */
+#define ARGI_REGION_OR_BUFFER 0x15 /* Used by LOAD op only */
#define ARGI_DATAREFOBJ 0x16
/* Note: types above can expand to 0x1F maximum */
diff --git a/include/acpi/amlresrc.h b/include/acpi/amlresrc.h
index be03818af9d..f7d541239da 100644
--- a/include/acpi/amlresrc.h
+++ b/include/acpi/amlresrc.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index 453a469fd39..dab2ec59a3b 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h
index da80933963d..3bb50494a38 100644
--- a/include/acpi/platform/acgcc.h
+++ b/include/acpi/platform/acgcc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 7f1e92930b6..5f532d2ac18 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/asm-alpha/cacheflush.h b/include/asm-alpha/cacheflush.h
index 805640b4107..b686cc7fc44 100644
--- a/include/asm-alpha/cacheflush.h
+++ b/include/asm-alpha/cacheflush.h
@@ -6,6 +6,7 @@
/* Caches aren't brain-dead on the Alpha. */
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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)
diff --git a/include/asm-alpha/dma-mapping.h b/include/asm-alpha/dma-mapping.h
index 57e09f5e342..75a1aff5b57 100644
--- a/include/asm-alpha/dma-mapping.h
+++ b/include/asm-alpha/dma-mapping.h
@@ -41,9 +41,9 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
#define dma_map_single(dev, va, size, dir) virt_to_phys(va)
#define dma_map_page(dev, page, off, size, dir) (page_to_pa(page) + off)
-#define dma_unmap_single(dev, addr, size, dir) do { } while (0)
-#define dma_unmap_page(dev, addr, size, dir) do { } while (0)
-#define dma_unmap_sg(dev, sg, nents, dir) do { } while (0)
+#define dma_unmap_single(dev, addr, size, dir) ((void)0)
+#define dma_unmap_page(dev, addr, size, dir) ((void)0)
+#define dma_unmap_sg(dev, sg, nents, dir) ((void)0)
#define dma_mapping_error(addr) (0)
@@ -55,12 +55,14 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
int dma_set_mask(struct device *dev, u64 mask);
-#define dma_sync_single_for_cpu(dev, addr, size, dir) do { } while (0)
-#define dma_sync_single_for_device(dev, addr, size, dir) do { } while (0)
-#define dma_sync_single_range(dev, addr, off, size, dir) do { } while (0)
-#define dma_sync_sg_for_cpu(dev, sg, nents, dir) do { } while (0)
-#define dma_sync_sg_for_device(dev, sg, nents, dir) do { } while (0)
-#define dma_cache_sync(dev, va, size, dir) do { } while (0)
+#define dma_sync_single_for_cpu(dev, addr, size, dir) ((void)0)
+#define dma_sync_single_for_device(dev, addr, size, dir) ((void)0)
+#define dma_sync_single_range(dev, addr, off, size, dir) ((void)0)
+#define dma_sync_sg_for_cpu(dev, sg, nents, dir) ((void)0)
+#define dma_sync_sg_for_device(dev, sg, nents, dir) ((void)0)
+#define dma_cache_sync(dev, va, size, dir) ((void)0)
+#define dma_sync_single_range_for_cpu(dev, addr, offset, size, dir) ((void)0)
+#define dma_sync_single_range_for_device(dev, addr, offset, size, dir) ((void)0)
#define dma_get_cache_alignment() L1_CACHE_BYTES
diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h
index 5d15af24573..24bdcc8b63a 100644
--- a/include/asm-alpha/io.h
+++ b/include/asm-alpha/io.h
@@ -525,15 +525,6 @@ extern void outsw (unsigned long port, const void *src, unsigned long count);
extern void outsl (unsigned long port, const void *src, unsigned long count);
/*
- * XXX - We don't have csum_partial_copy_fromio() yet, so we cheat here and
- * just copy it. The net code will then do the checksum later. Presently
- * only used by some shared memory 8390 Ethernet cards anyway.
- */
-
-#define eth_io_copy_and_sum(skb,src,len,unused) \
- memcpy_fromio((skb)->data,src,len)
-
-/*
* The Alpha Jensen hardware for some rather strange reason puts
* the RTC clock at 0x170 instead of 0x70. Probably due to some
* misguided idea about using 0x70 for NMI stuff.
diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
index 4e115f368d5..85aa1127c90 100644
--- a/include/asm-alpha/pci.h
+++ b/include/asm-alpha/pci.h
@@ -293,4 +293,6 @@ struct pci_dev *alpha_gendev_to_pci(struct device *dev);
#define IOBASE_ROOT_BUS 5
#define IOBASE_FROM_HOSE 0x10000
+extern struct pci_dev *isa_bridge;
+
#endif /* __ALPHA_PCI_H */
diff --git a/include/asm-alpha/posix_types.h b/include/asm-alpha/posix_types.h
index c78c04a94f4..db167413300 100644
--- a/include/asm-alpha/posix_types.h
+++ b/include/asm-alpha/posix_types.h
@@ -49,7 +49,7 @@ typedef unsigned int __kernel_old_dev_t;
#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
#define __FD_ISSET(d, set) (((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) != 0)
#define __FD_ZERO(set) \
- ((void) memset ((__ptr_t) (set), 0, sizeof (__kernel_fd_set)))
+ ((void) memset ((void *) (set), 0, sizeof (__kernel_fd_set)))
#else /* __GNUC__ */
diff --git a/include/asm-alpha/termbits.h b/include/asm-alpha/termbits.h
index 5541101b58a..ad854a4a3af 100644
--- a/include/asm-alpha/termbits.h
+++ b/include/asm-alpha/termbits.h
@@ -25,6 +25,19 @@ struct termios {
speed_t c_ospeed; /* output speed */
};
+/* Alpha has matching termios and ktermios */
+
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_cc[NCCS]; /* control characters */
+ cc_t c_line; /* line discipline (== c_cc[19]) */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VEOF 0
#define VEOL 1
diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h
index 84313d14e78..e58a427012d 100644
--- a/include/asm-alpha/unistd.h
+++ b/include/asm-alpha/unistd.h
@@ -342,9 +342,14 @@
#define __NR_io_cancel 402
#define __NR_exit_group 405
#define __NR_lookup_dcookie 406
-#define __NR_sys_epoll_create 407
-#define __NR_sys_epoll_ctl 408
-#define __NR_sys_epoll_wait 409
+#define __NR_epoll_create 407
+#define __NR_epoll_ctl 408
+#define __NR_epoll_wait 409
+/* Feb 2007: These three sys_epoll defines shouldn't be here but culling
+ * them would break userspace apps ... we'll kill them off in 2010 :) */
+#define __NR_sys_epoll_create __NR_epoll_create
+#define __NR_sys_epoll_ctl __NR_epoll_ctl
+#define __NR_sys_epoll_wait __NR_epoll_wait
#define __NR_remap_file_pages 410
#define __NR_set_tid_address 411
#define __NR_restart_syscall 412
diff --git a/include/asm-arm/apm.h b/include/asm-arm/apm.h
deleted file mode 100644
index d09113b37e4..00000000000
--- a/include/asm-arm/apm.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- linux-c -*-
- *
- * (C) 2003 zecke@handhelds.org
- *
- * GPL version 2
- *
- * based on arch/arm/kernel/apm.c
- * factor out the information needed by architectures to provide
- * apm status
- *
- *
- */
-#ifndef ARM_ASM_SA1100_APM_H
-#define ARM_ASM_SA1100_APM_H
-
-#include <linux/apm_bios.h>
-
-/*
- * This structure gets filled in by the machine specific 'get_power_status'
- * implementation. Any fields which are not set default to a safe value.
- */
-struct apm_power_info {
- unsigned char ac_line_status;
-#define APM_AC_OFFLINE 0
-#define APM_AC_ONLINE 1
-#define APM_AC_BACKUP 2
-#define APM_AC_UNKNOWN 0xff
-
- unsigned char battery_status;
-#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
-
- unsigned char battery_flag;
-#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
-
- int battery_life;
- int time;
- int units;
-#define APM_UNITS_MINS 0
-#define APM_UNITS_SECS 1
-#define APM_UNITS_UNKNOWN -1
-
-};
-
-/*
- * This allows machines to provide their own "apm get power status" function.
- */
-extern void (*apm_get_power_status)(struct apm_power_info *);
-
-/*
- * Queue an event (APM_SYS_SUSPEND or APM_CRITICAL_SUSPEND)
- */
-void apm_queue_event(apm_event_t event);
-
-#endif
diff --git a/include/asm-arm/arch-at91rm9200/at91_ecc.h b/include/asm-arm/arch-at91rm9200/at91_ecc.h
index fddf256a98d..5c564ede5c5 100644
--- a/include/asm-arm/arch-at91rm9200/at91_ecc.h
+++ b/include/asm-arm/arch-at91rm9200/at91_ecc.h
@@ -14,7 +14,7 @@
#define AT91_ECC_H
#define AT91_ECC_CR (AT91_ECC + 0x00) /* Control register */
-#define AT91_ECC_RST (1 << 0) /* Reset parity */
+#define AT91_ECC_RST (1 << 0) /* Reset parity */
#define AT91_ECC_MR (AT91_ECC + 0x04) /* Mode register */
#define AT91_ECC_PAGESIZE (3 << 0) /* Page Size */
@@ -23,16 +23,16 @@
#define AT91_ECC_PAGESIZE_2112 (2)
#define AT91_ECC_PAGESIZE_4224 (3)
-#define AT91_ECC_SR (AT91_ECC + 0x08) /* Status register */
+#define AT91_ECC_SR (AT91_ECC + 0x08) /* Status register */
#define AT91_ECC_RECERR (1 << 0) /* Recoverable Error */
#define AT91_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */
#define AT91_ECC_MULERR (1 << 2) /* Multiple Errors */
-#define AT91_ECC_PR (AT91_ECC + 0x0c) /* Parity register */
+#define AT91_ECC_PR (AT91_ECC + 0x0c) /* Parity register */
#define AT91_ECC_BITADDR (0xf << 0) /* Bit Error Address */
#define AT91_ECC_WORDADDR (0xfff << 4) /* Word Error Address */
-#define AT91_ECC_NPR (AT91_ECC + 0x10) /* NParity register */
+#define AT91_ECC_NPR (AT91_ECC + 0x10) /* NParity register */
#define AT91_ECC_NPARITY (0xffff << 0) /* NParity */
#endif
diff --git a/include/asm-arm/arch-at91rm9200/at91_pmc.h b/include/asm-arm/arch-at91rm9200/at91_pmc.h
index de8c3da74a0..c3b489d09b6 100644
--- a/include/asm-arm/arch-at91rm9200/at91_pmc.h
+++ b/include/asm-arm/arch-at91rm9200/at91_pmc.h
@@ -61,7 +61,7 @@
#define AT91_PMC_CSS_PLLA (2 << 0)
#define AT91_PMC_CSS_PLLB (3 << 0)
#define AT91_PMC_PRES (7 << 2) /* Master Clock Prescaler */
-#define AT91_PMC_PRES_1 (0 << 2)
+#define AT91_PMC_PRES_1 (0 << 2)
#define AT91_PMC_PRES_2 (1 << 2)
#define AT91_PMC_PRES_4 (2 << 2)
#define AT91_PMC_PRES_8 (3 << 2)
diff --git a/include/asm-arm/arch-at91rm9200/at91_rstc.h b/include/asm-arm/arch-at91rm9200/at91_rstc.h
index ccdc52da973..237d3c40b31 100644
--- a/include/asm-arm/arch-at91rm9200/at91_rstc.h
+++ b/include/asm-arm/arch-at91rm9200/at91_rstc.h
@@ -17,7 +17,7 @@
#define AT91_RSTC_PROCRST (1 << 0) /* Processor Reset */
#define AT91_RSTC_PERRST (1 << 2) /* Peripheral Reset */
#define AT91_RSTC_EXTRST (1 << 3) /* External Reset */
-#define AT01_RSTC_KEY (0xff << 24) /* KEY Password */
+#define AT91_RSTC_KEY (0xff << 24) /* KEY Password */
#define AT91_RSTC_SR (AT91_RSTC + 0x04) /* Reset Controller Status Register */
#define AT91_RSTC_URSTS (1 << 0) /* User Reset Status */
diff --git a/include/asm-arm/arch-at91rm9200/at91_rtc.h b/include/asm-arm/arch-at91rm9200/at91_rtc.h
index 6e5065d5626..095fe088310 100644
--- a/include/asm-arm/arch-at91rm9200/at91_rtc.h
+++ b/include/asm-arm/arch-at91rm9200/at91_rtc.h
@@ -21,21 +21,21 @@
#define AT91_RTC_UPDCAL (1 << 1) /* Update Request Calendar Register */
#define AT91_RTC_TIMEVSEL (3 << 8) /* Time Event Selection */
#define AT91_RTC_TIMEVSEL_MINUTE (0 << 8)
-#define AT91_RTC_TIMEVSEL_HOUR (1 << 8)
-#define AT91_RTC_TIMEVSEL_DAY24 (2 << 8)
-#define AT91_RTC_TIMEVSEL_DAY12 (3 << 8)
+#define AT91_RTC_TIMEVSEL_HOUR (1 << 8)
+#define AT91_RTC_TIMEVSEL_DAY24 (2 << 8)
+#define AT91_RTC_TIMEVSEL_DAY12 (3 << 8)
#define AT91_RTC_CALEVSEL (3 << 16) /* Calendar Event Selection */
-#define AT91_RTC_CALEVSEL_WEEK (0 << 16)
-#define AT91_RTC_CALEVSEL_MONTH (1 << 16)
-#define AT91_RTC_CALEVSEL_YEAR (2 << 16)
+#define AT91_RTC_CALEVSEL_WEEK (0 << 16)
+#define AT91_RTC_CALEVSEL_MONTH (1 << 16)
+#define AT91_RTC_CALEVSEL_YEAR (2 << 16)
#define AT91_RTC_MR (AT91_RTC + 0x04) /* Mode Register */
-#define AT91_RTC_HRMOD (1 << 0) /* 12/24 Hour Mode */
+#define AT91_RTC_HRMOD (1 << 0) /* 12/24 Hour Mode */
#define AT91_RTC_TIMR (AT91_RTC + 0x08) /* Time Register */
#define AT91_RTC_SEC (0x7f << 0) /* Current Second */
#define AT91_RTC_MIN (0x7f << 8) /* Current Minute */
-#define AT91_RTC_HOUR (0x3f << 16) /* Current Hour */
+#define AT91_RTC_HOUR (0x3f << 16) /* Current Hour */
#define AT91_RTC_AMPM (1 << 22) /* Ante Meridiem Post Meridiem Indicator */
#define AT91_RTC_CALR (AT91_RTC + 0x0c) /* Calendar Register */
diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200.h b/include/asm-arm/arch-at91rm9200/at91rm9200.h
index 4d51177efdd..c569b6a21a4 100644
--- a/include/asm-arm/arch-at91rm9200/at91rm9200.h
+++ b/include/asm-arm/arch-at91rm9200/at91rm9200.h
@@ -274,7 +274,7 @@
#define AT91_PD19_TPK7 (1 << 19) /* B: ETM Trace Packet Port 7 */
#define AT91_PD20_NPCS3 (1 << 20) /* A: SPI Peripheral Chip Select 3 */
#define AT91_PD20_TPK8 (1 << 20) /* B: ETM Trace Packet Port 8 */
-#define AT91_PD21_RTS0 (1 << 21) /* A: USART Ready To Send 0 */
+#define AT91_PD21_RTS0 (1 << 21) /* A: USART Ready To Send 0 */
#define AT91_PD21_TPK9 (1 << 21) /* B: ETM Trace Packet Port 9 */
#define AT91_PD22_RTS1 (1 << 22) /* A: USART Ready To Send 1 */
#define AT91_PD22_TPK10 (1 << 22) /* B: ETM Trace Packet Port 10 */
diff --git a/include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h b/include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h
index 746d973705b..78f6b4917b8 100644
--- a/include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h
+++ b/include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h
@@ -58,7 +58,7 @@
#define AT91_MATRIX_RCB1 (1 << 1) /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
#define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x11C) /* EBI Chip Select Assignment Register */
-#define AT91_MATRIX_CS1A (1 << 1) /* Chip Select 1 Assignment */
+#define AT91_MATRIX_CS1A (1 << 1) /* Chip Select 1 Assignment */
#define AT91_MATRIX_CS1A_SMC (0 << 1)
#define AT91_MATRIX_CS1A_SDRAMC (1 << 1)
#define AT91_MATRIX_CS3A (1 << 3) /* Chip Select 3 Assignment */
diff --git a/include/asm-arm/arch-at91rm9200/at91sam9261_matrix.h b/include/asm-arm/arch-at91rm9200/at91sam9261_matrix.h
index 270a5dcdf1c..ec88efabbe6 100644
--- a/include/asm-arm/arch-at91rm9200/at91sam9261_matrix.h
+++ b/include/asm-arm/arch-at91rm9200/at91sam9261_matrix.h
@@ -15,7 +15,7 @@
#define AT91_MATRIX_MCFG (AT91_MATRIX + 0x00) /* Master Configuration Register */
#define AT91_MATRIX_RCB0 (1 << 0) /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
-#define AT01_MATRIX_RCB1 (1 << 1) /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
+#define AT91_MATRIX_RCB1 (1 << 1) /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
#define AT91_MATRIX_SCFG0 (AT91_MATRIX + 0x04) /* Slave Configuration Register 0 */
#define AT91_MATRIX_SCFG1 (AT91_MATRIX + 0x08) /* Slave Configuration Register 1 */
@@ -43,8 +43,8 @@
#define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x30) /* EBI Chip Select Assignment Register */
#define AT91_MATRIX_CS1A (1 << 1) /* Chip Select 1 Assignment */
-#define AT91_MATRIX_CS1A_SMC (0 << 1)
-#define AT91_MATRIX_CS1A_SDRAMC (1 << 1)
+#define AT91_MATRIX_CS1A_SMC (0 << 1)
+#define AT91_MATRIX_CS1A_SDRAMC (1 << 1)
#define AT91_MATRIX_CS3A (1 << 3) /* Chip Select 3 Assignment */
#define AT91_MATRIX_CS3A_SMC (0 << 3)
#define AT91_MATRIX_CS3A_SMC_SMARTMEDIA (1 << 3)
diff --git a/include/asm-arm/arch-at91rm9200/at91sam926x_mc.h b/include/asm-arm/arch-at91rm9200/at91sam926x_mc.h
index 7d94968b5d5..972e7531c7f 100644
--- a/include/asm-arm/arch-at91rm9200/at91sam926x_mc.h
+++ b/include/asm-arm/arch-at91rm9200/at91sam926x_mc.h
@@ -33,14 +33,14 @@
#define AT91_SDRAMC_NC_9 (1 << 0)
#define AT91_SDRAMC_NC_10 (2 << 0)
#define AT91_SDRAMC_NC_11 (3 << 0)
-#define AT91_SDRAMC_NR (3 << 2) /* Number of Row Bits */
+#define AT91_SDRAMC_NR (3 << 2) /* Number of Row Bits */
#define AT91_SDRAMC_NR_11 (0 << 2)
#define AT91_SDRAMC_NR_12 (1 << 2)
#define AT91_SDRAMC_NR_13 (2 << 2)
-#define AT91_SDRAMC_NB (1 << 4) /* Number of Banks */
+#define AT91_SDRAMC_NB (1 << 4) /* Number of Banks */
#define AT91_SDRAMC_NB_2 (0 << 4)
-#define AT91_SDRAMC_NB_4 (1 << 4)
-#define AT91_SDRAMC_CAS (3 << 5) /* CAS Latency */
+#define AT91_SDRAMC_NB_4 (1 << 4)
+#define AT91_SDRAMC_CAS (3 << 5) /* CAS Latency */
#define AT91_SDRAMC_CAS_1 (1 << 5)
#define AT91_SDRAMC_CAS_2 (2 << 5)
#define AT91_SDRAMC_CAS_3 (3 << 5)
@@ -110,10 +110,10 @@
#define AT91_SMC_MODE(n) (AT91_SMC + 0x0c + ((n)*0x10)) /* Mode Register for CS n */
#define AT91_SMC_READMODE (1 << 0) /* Read Mode */
#define AT91_SMC_WRITEMODE (1 << 1) /* Write Mode */
-#define AT91_SMC_EXNWMODE (3 << 5) /* NWAIT Mode */
-#define AT91_SMC_EXNWMODE_DISABLE (0 << 5)
-#define AT91_SMC_EXNWMODE_FROZEN (2 << 5)
-#define AT91_SMC_EXNWMODE_READY (3 << 5)
+#define AT91_SMC_EXNWMODE (3 << 4) /* NWAIT Mode */
+#define AT91_SMC_EXNWMODE_DISABLE (0 << 4)
+#define AT91_SMC_EXNWMODE_FROZEN (2 << 4)
+#define AT91_SMC_EXNWMODE_READY (3 << 4)
#define AT91_SMC_BAT (1 << 8) /* Byte Access Type */
#define AT91_SMC_BAT_SELECT (0 << 8)
#define AT91_SMC_BAT_WRITE (1 << 8)
diff --git a/include/asm-arm/arch-ep93xx/irqs.h b/include/asm-arm/arch-ep93xx/irqs.h
index 9a42f5de9e5..ae532e304bf 100644
--- a/include/asm-arm/arch-ep93xx/irqs.h
+++ b/include/asm-arm/arch-ep93xx/irqs.h
@@ -22,9 +22,9 @@
#define IRQ_EP93XX_DMAM2P9 16
#define IRQ_EP93XX_DMAM2M0 17
#define IRQ_EP93XX_DMAM2M1 18
-#define IRQ_EP93XX_GPIO0MUX 20
-#define IRQ_EP93XX_GPIO1MUX 21
-#define IRQ_EP93XX_GPIO2MUX 22
+#define IRQ_EP93XX_GPIO0MUX 19
+#define IRQ_EP93XX_GPIO1MUX 20
+#define IRQ_EP93XX_GPIO2MUX 21
#define IRQ_EP93XX_GPIO3MUX 22
#define IRQ_EP93XX_UART1RX 23
#define IRQ_EP93XX_UART1TX 24
diff --git a/include/asm-arm/arch-imx/imx-regs.h b/include/asm-arm/arch-imx/imx-regs.h
index a6912b3d867..e56a4e247d6 100644
--- a/include/asm-arm/arch-imx/imx-regs.h
+++ b/include/asm-arm/arch-imx/imx-regs.h
@@ -41,7 +41,13 @@
/* PLL registers */
#define CSCR __REG(IMX_PLL_BASE) /* Clock Source Control Register */
-#define CSCR_SYSTEM_SEL (1<<16)
+#define CSCR_SPLL_RESTART (1<<22)
+#define CSCR_MPLL_RESTART (1<<21)
+#define CSCR_SYSTEM_SEL (1<<16)
+#define CSCR_BCLK_DIV (0xf<<10)
+#define CSCR_MPU_PRESC (1<<15)
+#define CSCR_SPEN (1<<1)
+#define CSCR_MPEN (1<<0)
#define MPCTL0 __REG(IMX_PLL_BASE + 0x4) /* MCU PLL Control Register 0 */
#define MPCTL1 __REG(IMX_PLL_BASE + 0x8) /* MCU PLL and System Clock Register 1 */
@@ -49,8 +55,6 @@
#define SPCTL1 __REG(IMX_PLL_BASE + 0x10) /* System PLL Control Register 1 */
#define PCDR __REG(IMX_PLL_BASE + 0x20) /* Peripheral Clock Divider Register */
-#define CSCR_MPLL_RESTART (1<<21)
-
/*
* GPIO Module and I/O Multiplexer
* x = 0..3 for reg_A, reg_B, reg_C, reg_D
diff --git a/include/asm-arm/arch-iop13xx/io.h b/include/asm-arm/arch-iop13xx/io.h
index db6de2480a2..5a7bdb52660 100644
--- a/include/asm-arm/arch-iop13xx/io.h
+++ b/include/asm-arm/arch-iop13xx/io.h
@@ -21,10 +21,11 @@
#define IO_SPACE_LIMIT 0xffffffff
-#define __io(a) (a)
+#define __io(a) __iop13xx_io(a)
#define __mem_pci(a) (a)
#define __mem_isa(a) (a)
+extern void __iomem * __iop13xx_io(unsigned long io_addr);
extern void __iomem * __ioremap(unsigned long, size_t, unsigned long);
extern void __iomem *__iop13xx_ioremap(unsigned long cookie, size_t size,
unsigned long flags);
diff --git a/include/asm-arm/arch-iop13xx/iq81340.h b/include/asm-arm/arch-iop13xx/iq81340.h
index b98f8f109c2..ba2cf931e9c 100644
--- a/include/asm-arm/arch-iop13xx/iq81340.h
+++ b/include/asm-arm/arch-iop13xx/iq81340.h
@@ -24,8 +24,5 @@
#define PBI_CF_IDE_BASE (IQ81340_CMP_FLSH)
#define PBI_CF_BAR_ADDR (IOP13XX_PBI_BAR1)
-/* These are the values used in the Machine description */
-#define PHYS_IO 0xfeffff00
-#define IO_PG_OFFSET 0xffffff00
-#define BOOT_PARAM_OFFSET 0x00000100
+
#endif /* _IQ81340_H_ */
diff --git a/include/asm-arm/arch-iop32x/iop32x.h b/include/asm-arm/arch-iop32x/iop32x.h
index 4bbd85f3ed2..2e9469047eb 100644
--- a/include/asm-arm/arch-iop32x/iop32x.h
+++ b/include/asm-arm/arch-iop32x/iop32x.h
@@ -19,7 +19,7 @@
* 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_GPIO_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07c4 + (reg))
#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07e0 + (reg))
#include <asm/hardware/iop3xx.h>
diff --git a/include/asm-arm/arch-ixp23xx/memory.h b/include/asm-arm/arch-ixp23xx/memory.h
index c85fc06a043..6d859d742d7 100644
--- a/include/asm-arm/arch-ixp23xx/memory.h
+++ b/include/asm-arm/arch-ixp23xx/memory.h
@@ -41,21 +41,7 @@
data = *((volatile int *)IXP23XX_PCI_SDRAM_BAR); \
__phys_to_virt((((b - (data & 0xfffffff0)) + 0x00000000))); })
-/*
- * Coherency support. Only supported on A2 CPUs or on A1
- * systems that have the cache coherency workaround.
- */
-static inline int __ixp23xx_arch_is_coherent(void)
-{
- extern unsigned int processor_id;
-
- if (((processor_id & 15) >= 4) || machine_is_roadrunner())
- return 1;
-
- return 0;
-}
-
-#define arch_is_coherent() __ixp23xx_arch_is_coherent()
+#define arch_is_coherent() 1
#endif
diff --git a/include/asm-arm/arch-ixp4xx/io.h b/include/asm-arm/arch-ixp4xx/io.h
index 0d517267fb6..b7b5414d932 100644
--- a/include/asm-arm/arch-ixp4xx/io.h
+++ b/include/asm-arm/arch-ixp4xx/io.h
@@ -238,9 +238,6 @@ __ixp4xx_readsl(const volatile void __iomem *bus_addr, u32 *vaddr, u32 count)
#define memcpy_fromio(a,c,l) _memcpy_fromio((a),(c),(l))
#define memcpy_toio(c,a,l) _memcpy_toio((c),(a),(l))
-#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(const unsigned char __iomem *bus_addr, const unsigned char *signature,
int length)
diff --git a/include/asm-arm/arch-pnx4008/i2c.h b/include/asm-arm/arch-pnx4008/i2c.h
new file mode 100644
index 00000000000..92e8d65006f
--- /dev/null
+++ b/include/asm-arm/arch-pnx4008/i2c.h
@@ -0,0 +1,67 @@
+/*
+ * PNX4008-specific tweaks for I2C IP3204 block
+ *
+ * Author: Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __ASM_ARCH_I2C_H__
+#define __ASM_ARCH_I2C_H__
+
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+
+enum {
+ mstatus_tdi = 0x00000001,
+ mstatus_afi = 0x00000002,
+ mstatus_nai = 0x00000004,
+ mstatus_drmi = 0x00000008,
+ mstatus_active = 0x00000020,
+ mstatus_scl = 0x00000040,
+ mstatus_sda = 0x00000080,
+ mstatus_rff = 0x00000100,
+ mstatus_rfe = 0x00000200,
+ mstatus_tff = 0x00000400,
+ mstatus_tfe = 0x00000800,
+};
+
+enum {
+ mcntrl_tdie = 0x00000001,
+ mcntrl_afie = 0x00000002,
+ mcntrl_naie = 0x00000004,
+ mcntrl_drmie = 0x00000008,
+ mcntrl_daie = 0x00000020,
+ mcntrl_rffie = 0x00000040,
+ mcntrl_tffie = 0x00000080,
+ mcntrl_reset = 0x00000100,
+ mcntrl_cdbmode = 0x00000400,
+};
+
+enum {
+ rw_bit = 1 << 0,
+ start_bit = 1 << 8,
+ stop_bit = 1 << 9,
+};
+
+#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */
+#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */
+#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */
+#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */
+#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */
+#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */
+#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */
+#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */
+#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */
+#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */
+#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */
+#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */
+#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */
+
+#define HCLK_MHZ 13
+#define I2C_CHIP_NAME "PNX4008-I2C"
+
+#endif /* __ASM_ARCH_I2C_H___ */
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index 083e03c5639..e24f6b6c79a 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -1626,7 +1626,7 @@
#define SSCR0_RIM (1 << 22) /* Receive FIFO overrrun interrupt mask */
#define SSCR0_TUM (1 << 23) /* Transmit FIFO underrun interrupt mask */
#define SSCR0_FRDC (0x07000000) /* Frame rate divider control (mask) */
-#define SSCR0_SlotsPerFrm(x) ((x) - 1) /* Time slots per frame [1..8] */
+#define SSCR0_SlotsPerFrm(x) (((x) - 1) << 24) /* Time slots per frame [1..8] */
#define SSCR0_ADC (1 << 30) /* Audio clock select */
#define SSCR0_MOD (1 << 31) /* Mode (normal or network) */
#endif
@@ -1655,6 +1655,7 @@
#define SSCR0_EDSS (1 << 20) /* Extended Data Size Select */
/* extra bits in PXA255, PXA26x and PXA27x SSP ports */
+#define SSCR0_TISSP (1 << 4) /* TI Sync Serial Protocol */
#define SSCR0_PSP (3 << 4) /* PSP - Programmable Serial Protocol */
#define SSCR1_TTELP (1 << 31) /* TXD Tristate Enable Last Phase */
#define SSCR1_TTE (1 << 30) /* TXD Tristate Enable */
diff --git a/include/asm-arm/arch-pxa/pxa2xx_spi.h b/include/asm-arm/arch-pxa/pxa2xx_spi.h
index 915590c391c..acc7ec7a84a 100644
--- a/include/asm-arm/arch-pxa/pxa2xx_spi.h
+++ b/include/asm-arm/arch-pxa/pxa2xx_spi.h
@@ -27,16 +27,13 @@
#define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/2/(x+1))<<8)&0x0000ff00)
#define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
#define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
-#define SSP_TIMEOUT_SCALE (2712)
#elif defined(CONFIG_PXA27x)
#define CLOCK_SPEED_HZ 13000000
#define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
#define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
#define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
-#define SSP_TIMEOUT_SCALE (769)
#endif
-#define SSP_TIMEOUT(x) ((x*10000)/SSP_TIMEOUT_SCALE)
#define SSP1_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(1)))))
#define SSP2_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(2)))))
#define SSP3_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(3)))))
@@ -63,7 +60,7 @@ struct pxa2xx_spi_chip {
u8 tx_threshold;
u8 rx_threshold;
u8 dma_burst_size;
- u32 timeout_microsecs;
+ u32 timeout;
u8 enable_loopback;
void (*cs_control)(u32 command);
};
diff --git a/include/asm-arm/arch-s3c2410/anubis-cpld.h b/include/asm-arm/arch-s3c2410/anubis-cpld.h
index 40e8e270d33..dcebf6d6190 100644
--- a/include/asm-arm/arch-s3c2410/anubis-cpld.h
+++ b/include/asm-arm/arch-s3c2410/anubis-cpld.h
@@ -1,6 +1,6 @@
/* linux/include/asm-arm/arch-s3c2410/anubis-cpld.h
*
- * (c) 2005 Simtec Electronics
+ * Copyright (c) 2005 Simtec Electronics
* http://www.simtec.co.uk/products/
* Ben Dooks <ben@simtec.co.uk>
*
diff --git a/include/asm-arm/arch-s3c2410/anubis-irq.h b/include/asm-arm/arch-s3c2410/anubis-irq.h
index 4b5f423779d..cd77a70d45c 100644
--- a/include/asm-arm/arch-s3c2410/anubis-irq.h
+++ b/include/asm-arm/arch-s3c2410/anubis-irq.h
@@ -1,6 +1,6 @@
/* linux/include/asm-arm/arch-s3c2410/anubis-irq.h
*
- * (c) 2005 Simtec Electronics
+ * Copyright (c) 2005 Simtec Electronics
* http://www.simtec.co.uk/products/
* Ben Dooks <ben@simtec.co.uk>
*
diff --git a/include/asm-arm/arch-s3c2410/anubis-map.h b/include/asm-arm/arch-s3c2410/anubis-map.h
index 058a2104b03..ab076de4a0d 100644
--- a/include/asm-arm/arch-s3c2410/anubis-map.h
+++ b/include/asm-arm/arch-s3c2410/anubis-map.h
@@ -1,6 +1,6 @@
/* linux/include/asm-arm/arch-s3c2410/anubis-map.h
*
- * (c) 2005 Simtec Electronics
+ * Copyright (c) 2005 Simtec Electronics
* http://www.simtec.co.uk/products/
* Ben Dooks <ben@simtec.co.uk>
*
diff --git a/include/asm-arm/arch-s3c2410/audio.h b/include/asm-arm/arch-s3c2410/audio.h
index 7e0222276c9..65e0acffa1a 100644
--- a/include/asm-arm/arch-s3c2410/audio.h
+++ b/include/asm-arm/arch-s3c2410/audio.h
@@ -1,6 +1,6 @@
/* linux/include/asm-arm/arch-s3c2410/audio.h
*
- * (c) 2004-2005 Simtec Electronics
+ * Copyright (c) 2004-2005 Simtec Electronics
* http://www.simtec.co.uk/products/SWLINUX/
* Ben Dooks <ben@simtec.co.uk>
*
diff --git a/include/asm-arm/arch-s3c2410/bast-cpld.h b/include/asm-arm/arch-s3c2410/bast-cpld.h
index 8969cffe83f..034d2c5a47c 100644
--- a/include/asm-arm/arch-s3c2410/bast-cpld.h
+++ b/include/asm-arm/arch-s3c2410/bast-cpld.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/bast-cpld.h
*
- * (c) 2003,2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2003,2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* BAST - CPLD control constants
*
diff --git a/include/asm-arm/arch-s3c2410/bast-irq.h b/include/asm-arm/arch-s3c2410/bast-irq.h
index 15ffa66f501..726c0466f85 100644
--- a/include/asm-arm/arch-s3c2410/bast-irq.h
+++ b/include/asm-arm/arch-s3c2410/bast-irq.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/bast-irq.h
*
- * (c) 2003,2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2003,2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* Machine BAST - IRQ Number definitions
*
diff --git a/include/asm-arm/arch-s3c2410/bast-map.h b/include/asm-arm/arch-s3c2410/bast-map.h
index 727cef84c70..86ac1c108db 100644
--- a/include/asm-arm/arch-s3c2410/bast-map.h
+++ b/include/asm-arm/arch-s3c2410/bast-map.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/bast-map.h
*
- * (c) 2003,2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2003,2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* Machine BAST - Memory map definitions
*
diff --git a/include/asm-arm/arch-s3c2410/bast-pmu.h b/include/asm-arm/arch-s3c2410/bast-pmu.h
index 82836027f00..37a11fe54a7 100644
--- a/include/asm-arm/arch-s3c2410/bast-pmu.h
+++ b/include/asm-arm/arch-s3c2410/bast-pmu.h
@@ -1,6 +1,6 @@
/* linux/include/asm-arm/arch-s3c2410/bast-pmu.h
*
- * (c) 2003,2004 Simtec Electronics
+ * Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* Vincent Sanders <vince@simtec.co.uk>
*
diff --git a/include/asm-arm/arch-s3c2410/dma.h b/include/asm-arm/arch-s3c2410/dma.h
index 7ac22483697..58ffa7ba3c8 100644
--- a/include/asm-arm/arch-s3c2410/dma.h
+++ b/include/asm-arm/arch-s3c2410/dma.h
@@ -14,7 +14,7 @@
#define __ASM_ARCH_DMA_H __FILE__
#include <linux/sysdev.h>
-#include "hardware.h"
+#include <asm/hardware.h>
/*
* This is the maximum DMA address(physical address) that can be DMAd to.
diff --git a/include/asm-arm/arch-s3c2410/entry-macro.S b/include/asm-arm/arch-s3c2410/entry-macro.S
index e09a6b8ec15..1eb4e6b8d24 100644
--- a/include/asm-arm/arch-s3c2410/entry-macro.S
+++ b/include/asm-arm/arch-s3c2410/entry-macro.S
@@ -20,7 +20,7 @@
#define INTOFFSET (0x14)
#include <asm/hardware.h>
-#include <asm/arch/irqs.h>
+#include <asm/irq.h>
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
diff --git a/include/asm-arm/arch-s3c2410/fb.h b/include/asm-arm/arch-s3c2410/fb.h
index 90894214cac..93a58e7862b 100644
--- a/include/asm-arm/arch-s3c2410/fb.h
+++ b/include/asm-arm/arch-s3c2410/fb.h
@@ -31,6 +31,9 @@ struct s3c2410fb_hw {
struct s3c2410fb_mach_info {
unsigned char fixed_syncs; /* do not update sync/border */
+ /* LCD types */
+ int type;
+
/* Screen size */
int width;
int height;
diff --git a/include/asm-arm/arch-s3c2410/h1940-latch.h b/include/asm-arm/arch-s3c2410/h1940-latch.h
index c5802411f43..c3de5ab102e 100644
--- a/include/asm-arm/arch-s3c2410/h1940-latch.h
+++ b/include/asm-arm/arch-s3c2410/h1940-latch.h
@@ -1,6 +1,6 @@
/* linux/include/asm-arm/arch-s3c2410/h1940-latch.h
*
- * (c) 2005 Simtec Electronics
+ * Copyright (c) 2005 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
@@ -16,7 +16,7 @@
#ifndef __ASSEMBLY__
-#define H1940_LATCH ((void __iomem *)0xF8000000)
+#define H1940_LATCH ((void __force __iomem *)0xF8000000)
#else
#define H1940_LATCH 0xF8000000
#endif
diff --git a/include/asm-arm/arch-s3c2410/hardware.h b/include/asm-arm/arch-s3c2410/hardware.h
index 871f8af09b8..6dadf58ff98 100644
--- a/include/asm-arm/arch-s3c2410/hardware.h
+++ b/include/asm-arm/arch-s3c2410/hardware.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/hardware.h
*
- * (c) 2003 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2003 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 - hardware
*
@@ -13,6 +13,10 @@
#ifndef __ASM_ARCH_HARDWARE_H
#define __ASM_ARCH_HARDWARE_H
+#ifndef __ASM_HARDWARE_H
+#error "Do not include this directly, instead #include <asm/hardware.h>"
+#endif
+
#ifndef __ASSEMBLY__
/* external functions for GPIO support
diff --git a/include/asm-arm/arch-s3c2410/iic.h b/include/asm-arm/arch-s3c2410/iic.h
index ed3d6c7bf6d..71211c8b538 100644
--- a/include/asm-arm/arch-s3c2410/iic.h
+++ b/include/asm-arm/arch-s3c2410/iic.h
@@ -1,6 +1,6 @@
/* linux/include/asm-arm/arch-s3c2410/iic.h
*
- * (c) 2004 Simtec Electronics
+ * Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 - I2C Controller platfrom_device info
diff --git a/include/asm-arm/arch-s3c2410/irqs.h b/include/asm-arm/arch-s3c2410/irqs.h
index 39a69829d16..4b7cff456c4 100644
--- a/include/asm-arm/arch-s3c2410/irqs.h
+++ b/include/asm-arm/arch-s3c2410/irqs.h
@@ -12,6 +12,9 @@
#ifndef __ASM_ARCH_IRQS_H
#define __ASM_ARCH_IRQS_H __FILE__
+#ifndef __ASM_ARM_IRQ_H
+#error "Do not include this directly, instead #include <asm/irq.h>"
+#endif
/* we keep the first set of CPU IRQs out of the range of
* the ISA space, so that the PC104 has them to itself
diff --git a/include/asm-arm/arch-s3c2410/leds-gpio.h b/include/asm-arm/arch-s3c2410/leds-gpio.h
index f07ed040622..800846ebddb 100644
--- a/include/asm-arm/arch-s3c2410/leds-gpio.h
+++ b/include/asm-arm/arch-s3c2410/leds-gpio.h
@@ -1,6 +1,6 @@
/* linux/include/asm-arm/arch-s3c2410/leds-gpio.h
*
- * (c) 2006 Simtec Electronics
+ * Copyright (c) 2006 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
diff --git a/include/asm-arm/arch-s3c2410/map.h b/include/asm-arm/arch-s3c2410/map.h
index 7895042d176..4505aefbad1 100644
--- a/include/asm-arm/arch-s3c2410/map.h
+++ b/include/asm-arm/arch-s3c2410/map.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/map.h
*
- * (c) 2003 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2003 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 - Memory map definitions
*
@@ -25,7 +25,7 @@
*/
#ifndef __ASSEMBLY__
-#define S3C2410_ADDR(x) ((void __iomem *)0xF0000000 + (x))
+#define S3C2410_ADDR(x) ((void __iomem __force *)0xF0000000 + (x))
#else
#define S3C2410_ADDR(x) (0xF0000000 + (x))
#endif
@@ -47,73 +47,65 @@
#define S3C24XX_SZ_MEMCTRL SZ_1M
/* USB host controller */
-#define S3C24XX_VA_USBHOST S3C2410_ADDR(0x00200000)
#define S3C2400_PA_USBHOST (0x14200000)
#define S3C2410_PA_USBHOST (0x49000000)
#define S3C24XX_SZ_USBHOST SZ_1M
/* DMA controller */
-#define S3C24XX_VA_DMA S3C2410_ADDR(0x00300000)
#define S3C2400_PA_DMA (0x14600000)
#define S3C2410_PA_DMA (0x4B000000)
#define S3C24XX_SZ_DMA SZ_1M
/* Clock and Power management */
-#define S3C24XX_VA_CLKPWR S3C2410_ADDR(0x00400000)
+#define S3C24XX_VA_CLKPWR S3C2410_ADDR(0x00200000)
#define S3C2400_PA_CLKPWR (0x14800000)
#define S3C2410_PA_CLKPWR (0x4C000000)
#define S3C24XX_SZ_CLKPWR SZ_1M
/* LCD controller */
-#define S3C24XX_VA_LCD S3C2410_ADDR(0x00600000)
+#define S3C24XX_VA_LCD S3C2410_ADDR(0x00300000)
#define S3C2400_PA_LCD (0x14A00000)
#define S3C2410_PA_LCD (0x4D000000)
#define S3C24XX_SZ_LCD SZ_1M
/* NAND flash controller */
-#define S3C24XX_VA_NAND S3C2410_ADDR(0x00700000)
#define S3C2410_PA_NAND (0x4E000000)
#define S3C24XX_SZ_NAND SZ_1M
/* MMC controller - available on the S3C2400 */
-#define S3C2400_VA_MMC S3C2400_ADDR(0x00700000)
#define S3C2400_PA_MMC (0x15A00000)
#define S3C2400_SZ_MMC SZ_1M
/* UARTs */
-#define S3C24XX_VA_UART S3C2410_ADDR(0x00800000)
+#define S3C24XX_VA_UART S3C2410_ADDR(0x00400000)
#define S3C2400_PA_UART (0x15000000)
#define S3C2410_PA_UART (0x50000000)
#define S3C24XX_SZ_UART SZ_1M
/* Timers */
-#define S3C24XX_VA_TIMER S3C2410_ADDR(0x00900000)
+#define S3C24XX_VA_TIMER S3C2410_ADDR(0x00500000)
#define S3C2400_PA_TIMER (0x15100000)
#define S3C2410_PA_TIMER (0x51000000)
#define S3C24XX_SZ_TIMER SZ_1M
/* USB Device port */
-#define S3C24XX_VA_USBDEV S3C2410_ADDR(0x00A00000)
+#define S3C24XX_VA_USBDEV S3C2410_ADDR(0x00600000)
#define S3C2400_PA_USBDEV (0x15200140)
#define S3C2410_PA_USBDEV (0x52000000)
#define S3C24XX_SZ_USBDEV SZ_1M
/* Watchdog */
-#define S3C24XX_VA_WATCHDOG S3C2410_ADDR(0x00B00000)
+#define S3C24XX_VA_WATCHDOG S3C2410_ADDR(0x00700000)
#define S3C2400_PA_WATCHDOG (0x15300000)
#define S3C2410_PA_WATCHDOG (0x53000000)
#define S3C24XX_SZ_WATCHDOG SZ_1M
/* IIC hardware controller */
-#define S3C24XX_VA_IIC S3C2410_ADDR(0x00C00000)
#define S3C2400_PA_IIC (0x15400000)
#define S3C2410_PA_IIC (0x54000000)
#define S3C24XX_SZ_IIC SZ_1M
-#define VA_IIC_BASE (S3C24XX_VA_IIC)
-
/* IIS controller */
-#define S3C24XX_VA_IIS S3C2410_ADDR(0x00D00000)
#define S3C2400_PA_IIS (0x15508000)
#define S3C2410_PA_IIS (0x55000000)
#define S3C24XX_SZ_IIS SZ_1M
@@ -134,25 +126,21 @@
#define S3C24XX_SZ_GPIO SZ_1M
/* RTC */
-#define S3C24XX_VA_RTC S3C2410_ADDR(0x00F00000)
#define S3C2400_PA_RTC (0x15700040)
#define S3C2410_PA_RTC (0x57000000)
#define S3C24XX_SZ_RTC SZ_1M
/* ADC */
-#define S3C24XX_VA_ADC S3C2410_ADDR(0x01000000)
#define S3C2400_PA_ADC (0x15800000)
#define S3C2410_PA_ADC (0x58000000)
#define S3C24XX_SZ_ADC SZ_1M
/* SPI */
-#define S3C24XX_VA_SPI S3C2410_ADDR(0x01100000)
#define S3C2400_PA_SPI (0x15900000)
#define S3C2410_PA_SPI (0x59000000)
#define S3C24XX_SZ_SPI SZ_1M
/* SDI */
-#define S3C24XX_VA_SDI S3C2410_ADDR(0x01200000)
#define S3C2410_PA_SDI (0x5A000000)
#define S3C24XX_SZ_SDI SZ_1M
diff --git a/include/asm-arm/arch-s3c2410/nand.h b/include/asm-arm/arch-s3c2410/nand.h
index e350ae2acfc..8816f7f9cee 100644
--- a/include/asm-arm/arch-s3c2410/nand.h
+++ b/include/asm-arm/arch-s3c2410/nand.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/nand.h
*
- * (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 - NAND device controller platfrom_device info
*
diff --git a/include/asm-arm/arch-s3c2410/osiris-cpld.h b/include/asm-arm/arch-s3c2410/osiris-cpld.h
index e9d1ae1f354..3b6498468d6 100644
--- a/include/asm-arm/arch-s3c2410/osiris-cpld.h
+++ b/include/asm-arm/arch-s3c2410/osiris-cpld.h
@@ -1,6 +1,6 @@
/* linux/include/asm-arm/arch-s3c2410/osiris-cpld.h
*
- * (c) 2005 Simtec Electronics
+ * Copyright (c) 2005 Simtec Electronics
* http://www.simtec.co.uk/products/
* Ben Dooks <ben@simtec.co.uk>
*
diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h
index b2893e32a23..eae91694edc 100644
--- a/include/asm-arm/arch-s3c2410/regs-gpio.h
+++ b/include/asm-arm/arch-s3c2410/regs-gpio.h
@@ -52,10 +52,10 @@
/* general configuration options */
#define S3C2410_GPIO_LEAVE (0xFFFFFFFF)
-#define S3C2410_GPIO_INPUT (0xFFFFFFF0)
+#define S3C2410_GPIO_INPUT (0xFFFFFFF0) /* not available on A */
#define S3C2410_GPIO_OUTPUT (0xFFFFFFF1)
#define S3C2410_GPIO_IRQ (0xFFFFFFF2) /* not available for all */
-#define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* not available on A */
+#define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* bank A => addr/cs/nand */
#define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */
/* register address for the GPIO registers.
diff --git a/include/asm-arm/arch-s3c2410/regs-mem.h b/include/asm-arm/arch-s3c2410/regs-mem.h
index 375dca50364..e4d82341f7b 100644
--- a/include/asm-arm/arch-s3c2410/regs-mem.h
+++ b/include/asm-arm/arch-s3c2410/regs-mem.h
@@ -133,10 +133,10 @@
#define S3C2410_BANKCON_SDRAM (0x3 << 15)
/* next bits only for EDO DRAM in 6,7 */
-#define S3C2400_BANKCON_EDO_Trdc1 (0x00 << 4)
-#define S3C2400_BANKCON_EDO_Trdc2 (0x01 << 4)
-#define S3C2400_BANKCON_EDO_Trdc3 (0x02 << 4)
-#define S3C2400_BANKCON_EDO_Trdc4 (0x03 << 4)
+#define S3C2400_BANKCON_EDO_Trcd1 (0x00 << 4)
+#define S3C2400_BANKCON_EDO_Trcd2 (0x01 << 4)
+#define S3C2400_BANKCON_EDO_Trcd3 (0x02 << 4)
+#define S3C2400_BANKCON_EDO_Trcd4 (0x03 << 4)
/* CAS pulse width */
#define S3C2400_BANKCON_EDO_PULSE1 (0x00 << 3)
@@ -153,9 +153,9 @@
#define S3C2400_BANKCON_EDO_SCANb11 (0x03 << 0)
/* next bits only for SDRAM in 6,7 */
-#define S3C2410_BANKCON_Trdc2 (0x00 << 2)
-#define S3C2410_BANKCON_Trdc3 (0x01 << 2)
-#define S3C2410_BANKCON_Trdc4 (0x02 << 2)
+#define S3C2410_BANKCON_Trcd2 (0x00 << 2)
+#define S3C2410_BANKCON_Trcd3 (0x01 << 2)
+#define S3C2410_BANKCON_Trcd4 (0x02 << 2)
/* control column address select */
#define S3C2410_BANKCON_SCANb8 (0x00 << 0)
diff --git a/include/asm-arm/arch-s3c2410/regs-serial.h b/include/asm-arm/arch-s3c2410/regs-serial.h
index 19c77da9c3f..46f52401d13 100644
--- a/include/asm-arm/arch-s3c2410/regs-serial.h
+++ b/include/asm-arm/arch-s3c2410/regs-serial.h
@@ -197,7 +197,7 @@ struct s3c2410_uartcfg {
unsigned char hwport; /* hardware port number */
unsigned char unused;
unsigned short flags;
- unsigned long uart_flags; /* default uart flags */
+ upf_t uart_flags; /* default uart flags */
unsigned long ucon; /* value of ucon for port */
unsigned long ulcon; /* value of ulcon for port */
diff --git a/include/asm-arm/arch-s3c2410/regs-udc.h b/include/asm-arm/arch-s3c2410/regs-udc.h
index 487861d5b49..3c8354619b6 100644
--- a/include/asm-arm/arch-s3c2410/regs-udc.h
+++ b/include/asm-arm/arch-s3c2410/regs-udc.h
@@ -11,8 +11,7 @@
#ifndef __ASM_ARCH_REGS_UDC_H
#define __ASM_ARCH_REGS_UDC_H
-
-#define S3C2410_USBDREG(x) ((x) + S3C24XX_VA_USBDEV)
+#define S3C2410_USBDREG(x) (x)
#define S3C2410_UDC_FUNC_ADDR_REG S3C2410_USBDREG(0x0140)
#define S3C2410_UDC_PWR_REG S3C2410_USBDREG(0x0144)
@@ -136,8 +135,8 @@
#define S3C2410_UDC_OCSR2_ISO (1<<6) // R/W
#define S3C2410_UDC_OCSR2_DMAIEN (1<<5) // R/W
-#define S3C2410_UDC_SETIX(x) \
- __raw_writel(S3C2410_UDC_INDEX_ ## x, S3C2410_UDC_INDEX_REG);
+#define S3C2410_UDC_SETIX(base,x) \
+ writel(S3C2410_UDC_INDEX_ ## x, base+S3C2410_UDC_INDEX_REG);
#define S3C2410_UDC_EP0_CSR_OPKRDY (1<<0)
diff --git a/include/asm-arm/arch-s3c2410/system.h b/include/asm-arm/arch-s3c2410/system.h
index 4f72a853a5c..ecf250db45f 100644
--- a/include/asm-arm/arch-s3c2410/system.h
+++ b/include/asm-arm/arch-s3c2410/system.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/system.h
*
- * (c) 2003 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2003 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 - System function defines and includes
*
diff --git a/include/asm-arm/arch-s3c2410/timex.h b/include/asm-arm/arch-s3c2410/timex.h
index 703c337c561..c16a99c5a59 100644
--- a/include/asm-arm/arch-s3c2410/timex.h
+++ b/include/asm-arm/arch-s3c2410/timex.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/timex.h
*
- * (c) 2003-2005 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2003-2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 - time parameters
*
diff --git a/include/asm-arm/arch-s3c2410/uncompress.h b/include/asm-arm/arch-s3c2410/uncompress.h
index 81b3e91c56a..dcb2cef38f5 100644
--- a/include/asm-arm/arch-s3c2410/uncompress.h
+++ b/include/asm-arm/arch-s3c2410/uncompress.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/uncompress.h
*
- * (c) 2003 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2003 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 - uncompress code
*
@@ -13,6 +13,7 @@
#ifndef __ASM_ARCH_UNCOMPRESS_H
#define __ASM_ARCH_UNCOMPRESS_H
+typedef unsigned int upf_t; /* cannot include linux/serial_core.h */
/* defines for UART registers */
#include "asm/arch/regs-serial.h"
diff --git a/include/asm-arm/arch-s3c2410/usb-control.h b/include/asm-arm/arch-s3c2410/usb-control.h
index 35723569a17..5bfa376e33d 100644
--- a/include/asm-arm/arch-s3c2410/usb-control.h
+++ b/include/asm-arm/arch-s3c2410/usb-control.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/usb-control.h
*
- * (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 - usb port information
*
diff --git a/include/asm-arm/arch-s3c2410/vr1000-cpld.h b/include/asm-arm/arch-s3c2410/vr1000-cpld.h
index a341b1e1bd9..0557b0a5ab1 100644
--- a/include/asm-arm/arch-s3c2410/vr1000-cpld.h
+++ b/include/asm-arm/arch-s3c2410/vr1000-cpld.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/vr1000-cpld.h
*
- * (c) 2003 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2003 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* VR1000 - CPLD control constants
*
diff --git a/include/asm-arm/arch-s3c2410/vr1000-irq.h b/include/asm-arm/arch-s3c2410/vr1000-irq.h
index c39a0ffa670..890937083c6 100644
--- a/include/asm-arm/arch-s3c2410/vr1000-irq.h
+++ b/include/asm-arm/arch-s3c2410/vr1000-irq.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/vr1000-irq.h
*
- * (c) 2003,2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2003,2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* Machine VR1000 - IRQ Number definitions
*
diff --git a/include/asm-arm/arch-s3c2410/vr1000-map.h b/include/asm-arm/arch-s3c2410/vr1000-map.h
index 1fe4db36c83..92a56a724a8 100644
--- a/include/asm-arm/arch-s3c2410/vr1000-map.h
+++ b/include/asm-arm/arch-s3c2410/vr1000-map.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/vr1000-map.h
*
- * (c) 2003-2005 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2003-2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* Machine VR1000 - Memory map definitions
*
diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h
index f0845646aac..5f531ea0305 100644
--- a/include/asm-arm/cacheflush.h
+++ b/include/asm-arm/cacheflush.h
@@ -319,6 +319,8 @@ extern void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
unsigned long len, int write);
#endif
+#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
+
/*
* flush_cache_user_range is used when we want to ensure that the
* Harvard caches are synchronised for the user space address range.
@@ -353,6 +355,18 @@ extern void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
*/
extern void flush_dcache_page(struct page *);
+extern void __flush_dcache_page(struct address_space *mapping, struct page *page);
+
+#define ARCH_HAS_FLUSH_ANON_PAGE
+static inline void flush_anon_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vmaddr)
+{
+ extern void __flush_anon_page(struct vm_area_struct *vma,
+ struct page *, unsigned long);
+ if (PageAnon(page))
+ __flush_anon_page(vma, page, vmaddr);
+}
+
#define flush_dcache_mmap_lock(mapping) \
write_lock_irq(&(mapping)->tree_lock)
#define flush_dcache_mmap_unlock(mapping) \
diff --git a/include/asm-arm/cpu-multi32.h b/include/asm-arm/cpu-multi32.h
index 4679f63688e..715e18a4add 100644
--- a/include/asm-arm/cpu-multi32.h
+++ b/include/asm-arm/cpu-multi32.h
@@ -50,9 +50,10 @@ extern struct processor {
*/
void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm);
/*
- * Set a PTE
+ * Set a possibly extended PTE. Non-extended PTEs should
+ * ignore 'ext'.
*/
- void (*set_pte)(pte_t *ptep, pte_t pte);
+ void (*set_pte_ext)(pte_t *ptep, pte_t pte, unsigned int ext);
} processor;
#define cpu_proc_init() processor._proc_init()
@@ -60,5 +61,5 @@ extern struct processor {
#define cpu_reset(addr) processor.reset(addr)
#define cpu_do_idle() processor._do_idle()
#define cpu_dcache_clean_area(addr,sz) processor.dcache_clean_area(addr,sz)
-#define cpu_set_pte(ptep, pte) processor.set_pte(ptep, pte)
+#define cpu_set_pte_ext(ptep,pte,ext) processor.set_pte_ext(ptep,pte,ext)
#define cpu_do_switch_mm(pgd,mm) processor.switch_mm(pgd,mm)
diff --git a/include/asm-arm/cpu-single.h b/include/asm-arm/cpu-single.h
index 6723e67244f..0b120ee3609 100644
--- a/include/asm-arm/cpu-single.h
+++ b/include/asm-arm/cpu-single.h
@@ -28,7 +28,7 @@
#define cpu_do_idle __cpu_fn(CPU_NAME,_do_idle)
#define cpu_dcache_clean_area __cpu_fn(CPU_NAME,_dcache_clean_area)
#define cpu_do_switch_mm __cpu_fn(CPU_NAME,_switch_mm)
-#define cpu_set_pte __cpu_fn(CPU_NAME,_set_pte)
+#define cpu_set_pte_ext __cpu_fn(CPU_NAME,_set_pte_ext)
#include <asm/page.h>
@@ -40,5 +40,5 @@ extern void cpu_proc_fin(void);
extern int cpu_do_idle(void);
extern void cpu_dcache_clean_area(void *, int);
extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
-extern void cpu_set_pte(pte_t *ptep, pte_t pte);
+extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
diff --git a/include/asm-arm/elf.h b/include/asm-arm/elf.h
index 642382d2c9f..3679a8a8922 100644
--- a/include/asm-arm/elf.h
+++ b/include/asm-arm/elf.h
@@ -52,6 +52,7 @@ typedef struct user_fp elf_fpregset_t;
#define HWCAP_EDSP 128
#define HWCAP_JAVA 256
#define HWCAP_IWMMXT 512
+#define HWCAP_CRUNCH 1024
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
diff --git a/include/asm-arm/flat.h b/include/asm-arm/flat.h
index 96694647858..16f5375e57b 100644
--- a/include/asm-arm/flat.h
+++ b/include/asm-arm/flat.h
@@ -5,7 +5,9 @@
#ifndef __ARM_FLAT_H__
#define __ARM_FLAT_H__
-#define flat_stack_align(sp) /* nothing needed */
+/* An odd number of words will be pushed after this alignment, so
+ deliberately misalign the value. */
+#define flat_stack_align(sp) sp = (void *)(((unsigned long)(sp) - 4) | 4)
#define flat_argvp_envp_on_stack() 1
#define flat_old_ram_flag(flags) (flags)
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
diff --git a/include/asm-arm/fpstate.h b/include/asm-arm/fpstate.h
index 6af4e6bd129..f31cda5a55e 100644
--- a/include/asm-arm/fpstate.h
+++ b/include/asm-arm/fpstate.h
@@ -35,6 +35,9 @@ struct vfp_hard_struct {
*/
__u32 fpinst;
__u32 fpinst2;
+#ifdef CONFIG_SMP
+ __u32 cpu;
+#endif
};
union vfp_state {
diff --git a/include/asm-arm/hardware/iop3xx.h b/include/asm-arm/hardware/iop3xx.h
index 1018a7486ab..13ac8a4cd01 100644
--- a/include/asm-arm/hardware/iop3xx.h
+++ b/include/asm-arm/hardware/iop3xx.h
@@ -168,9 +168,9 @@ extern void gpio_line_set(int line, int value);
#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)
+#define IOP3XX_GPOE (volatile u32 *)IOP3XX_GPIO_REG(0x0000)
+#define IOP3XX_GPID (volatile u32 *)IOP3XX_GPIO_REG(0x0004)
+#define IOP3XX_GPOD (volatile u32 *)IOP3XX_GPIO_REG(0x0008)
/* Timers */
#define IOP3XX_TU_TMR0 (volatile u32 *)IOP3XX_TIMER_REG(0x0000)
diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
index 288f76b166d..5f60b422090 100644
--- a/include/asm-arm/io.h
+++ b/include/asm-arm/io.h
@@ -182,9 +182,6 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
#define memcpy_fromio(a,c,l) _memcpy_fromio((a),__mem_pci(c),(l))
#define memcpy_toio(c,a,l) _memcpy_toio(__mem_pci(c),(a),(l))
-#define eth_io_copy_and_sum(s,c,l,b) \
- eth_copy_and_sum((s),__mem_pci(c),(l),(b))
-
#elif !defined(readb)
#define readb(c) (__readwrite_bug("readb"),0)
@@ -194,8 +191,6 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
#define writew(v,c) __readwrite_bug("writew")
#define writel(v,c) __readwrite_bug("writel")
-#define eth_io_copy_and_sum(s,c,l,b) __readwrite_bug("eth_io_copy_and_sum")
-
#define check_signature(io,sig,len) (0)
#endif /* __mem_pci */
diff --git a/include/asm-arm/irq.h b/include/asm-arm/irq.h
index 283af50a16c..1b882a255e3 100644
--- a/include/asm-arm/irq.h
+++ b/include/asm-arm/irq.h
@@ -19,7 +19,6 @@
#define NO_IRQ ((unsigned int)(-1))
#endif
-struct irqaction;
/*
* Migration helpers
@@ -37,6 +36,10 @@ struct irqaction;
#define IRQT_HIGH (__IRQT_HIGHLVL)
#define IRQT_PROBE IRQ_TYPE_PROBE
+#ifndef __ASSEMBLY__
+struct irqaction;
extern void migrate_irqs(void);
#endif
+#endif
+
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index 88cd5c784ef..b8cf2d5ec30 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -21,6 +21,7 @@
#include <asm/memory.h>
#include <asm/arch/vmalloc.h>
+#include <asm/pgtable-hwdef.h>
/*
* Just any arbitrary offset to the start of the vmalloc VM area: the
@@ -170,7 +171,6 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
#define L_PTE_EXEC (1 << 6)
#define L_PTE_DIRTY (1 << 7)
#define L_PTE_SHARED (1 << 10) /* shared(v6), coherent(xsc3) */
-#define L_PTE_ASID (1 << 11) /* non-global (use ASID, v6) */
#ifndef __ASSEMBLY__
@@ -228,7 +228,7 @@ extern struct page *empty_zero_page;
#define pfn_pte(pfn,prot) (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)))
#define pte_none(pte) (!pte_val(pte))
-#define pte_clear(mm,addr,ptep) set_pte_at((mm),(addr),(ptep), __pte(0))
+#define pte_clear(mm,addr,ptep) set_pte_ext(ptep, __pte(0), 0)
#define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
#define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
#define pte_offset_map(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
@@ -236,8 +236,11 @@ extern struct page *empty_zero_page;
#define pte_unmap(pte) do { } while (0)
#define pte_unmap_nested(pte) do { } while (0)
-#define set_pte(ptep, pte) cpu_set_pte(ptep,pte)
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
+
+#define set_pte_at(mm,addr,ptep,pteval) do { \
+ set_pte_ext(ptep, pteval, (addr) >= PAGE_OFFSET ? 0 : PTE_EXT_NG); \
+ } while (0)
/*
* The following only work if pte_present() is true.
diff --git a/include/asm-arm/processor.h b/include/asm-arm/processor.h
index b442e8e2a80..1bbf16182d6 100644
--- a/include/asm-arm/processor.h
+++ b/include/asm-arm/processor.h
@@ -103,14 +103,14 @@ extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
#if __LINUX_ARM_ARCH__ >= 5
#define ARCH_HAS_PREFETCH
-#define prefetch(ptr) \
- ({ \
- __asm__ __volatile__( \
- "pld\t%0" \
- : \
- : "o" (*(char *)(ptr)) \
- : "cc"); \
- })
+static inline void prefetch(const void *ptr)
+{
+ __asm__ __volatile__(
+ "pld\t%0"
+ :
+ : "o" (*(char *)ptr)
+ : "cc");
+}
#define ARCH_HAS_PREFETCHW
#define prefetchw(ptr) prefetch(ptr)
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index f05fbe31576..aa223fc546a 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -73,6 +73,7 @@
#ifndef __ASSEMBLY__
#include <linux/linkage.h>
+#include <linux/irqflags.h>
struct thread_info;
struct task_struct;
@@ -139,23 +140,44 @@ static inline int cpu_is_xsc3(void)
#define cpu_is_xscale() 1
#endif
-#define set_cr(x) \
- __asm__ __volatile__( \
- "mcr p15, 0, %0, c1, c0, 0 @ set CR" \
- : : "r" (x) : "cc")
-
-#define get_cr() \
- ({ \
- unsigned int __val; \
- __asm__ __volatile__( \
- "mrc p15, 0, %0, c1, c0, 0 @ get CR" \
- : "=r" (__val) : : "cc"); \
- __val; \
- })
-
extern unsigned long cr_no_alignment; /* defined in entry-armv.S */
extern unsigned long cr_alignment; /* defined in entry-armv.S */
+static inline unsigned int get_cr(void)
+{
+ unsigned int val;
+ asm("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val) : : "cc");
+ return val;
+}
+
+static inline void set_cr(unsigned int val)
+{
+ asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR"
+ : : "r" (val) : "cc");
+}
+
+#ifndef CONFIG_SMP
+extern void adjust_cr(unsigned long mask, unsigned long set);
+#endif
+
+#define CPACC_FULL(n) (3 << (n * 2))
+#define CPACC_SVC(n) (1 << (n * 2))
+#define CPACC_DISABLE(n) (0 << (n * 2))
+
+static inline unsigned int get_copro_access(void)
+{
+ unsigned int val;
+ asm("mrc p15, 0, %0, c1, c0, 2 @ get copro access"
+ : "=r" (val) : : "cc");
+ return val;
+}
+
+static inline void set_copro_access(unsigned int val)
+{
+ asm volatile("mcr p15, 0, %0, c1, c0, 2 @ set copro access"
+ : : "r" (val) : "cc");
+}
+
#define UDBG_UNDEFINED (1 << 0)
#define UDBG_SYSCALL (1 << 1)
#define UDBG_BADABORT (1 << 2)
@@ -211,8 +233,6 @@ static inline void sched_cacheflush(void)
{
}
-#include <linux/irqflags.h>
-
#ifdef CONFIG_SMP
#define smp_mb() mb()
diff --git a/include/asm-arm/termbits.h b/include/asm-arm/termbits.h
index bbc6e1d24d3..a3f4fe1742d 100644
--- a/include/asm-arm/termbits.h
+++ b/include/asm-arm/termbits.h
@@ -15,6 +15,18 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-arm/thread_info.h b/include/asm-arm/thread_info.h
index d9b8bddc873..5014794f9eb 100644
--- a/include/asm-arm/thread_info.h
+++ b/include/asm-arm/thread_info.h
@@ -147,6 +147,7 @@ extern void iwmmxt_task_switch(struct thread_info *);
#define TIF_POLLING_NRFLAG 16
#define TIF_USING_IWMMXT 17
#define TIF_MEMDIE 18
+#define TIF_FREEZE 19
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
@@ -154,6 +155,7 @@ extern void iwmmxt_task_switch(struct thread_info *);
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
+#define _TIF_FREEZE (1 << TIF_FREEZE)
/*
* Change these and you break ASM code in entry-common.S
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
index d44c629d842..97e7060000c 100644
--- a/include/asm-arm/unistd.h
+++ b/include/asm-arm/unistd.h
@@ -347,6 +347,31 @@
#define __NR_mbind (__NR_SYSCALL_BASE+319)
#define __NR_get_mempolicy (__NR_SYSCALL_BASE+320)
#define __NR_set_mempolicy (__NR_SYSCALL_BASE+321)
+#define __NR_openat (__NR_SYSCALL_BASE+322)
+#define __NR_mkdirat (__NR_SYSCALL_BASE+323)
+#define __NR_mknodat (__NR_SYSCALL_BASE+324)
+#define __NR_fchownat (__NR_SYSCALL_BASE+325)
+#define __NR_futimesat (__NR_SYSCALL_BASE+326)
+#define __NR_fstatat64 (__NR_SYSCALL_BASE+327)
+#define __NR_unlinkat (__NR_SYSCALL_BASE+328)
+#define __NR_renameat (__NR_SYSCALL_BASE+329)
+#define __NR_linkat (__NR_SYSCALL_BASE+330)
+#define __NR_symlinkat (__NR_SYSCALL_BASE+331)
+#define __NR_readlinkat (__NR_SYSCALL_BASE+332)
+#define __NR_fchmodat (__NR_SYSCALL_BASE+333)
+#define __NR_faccessat (__NR_SYSCALL_BASE+334)
+ /* 335 for pselect6 */
+ /* 336 for ppoll */
+#define __NR_unshare (__NR_SYSCALL_BASE+337)
+#define __NR_set_robust_list (__NR_SYSCALL_BASE+338)
+#define __NR_get_robust_list (__NR_SYSCALL_BASE+339)
+#define __NR_splice (__NR_SYSCALL_BASE+340)
+#define __NR_arm_sync_file_range (__NR_SYSCALL_BASE+341)
+#define __NR_tee (__NR_SYSCALL_BASE+342)
+#define __NR_vmsplice (__NR_SYSCALL_BASE+343)
+#define __NR_move_pages (__NR_SYSCALL_BASE+344)
+#define __NR_getcpu (__NR_SYSCALL_BASE+345)
+ /* 346 for epoll_pwait */
/*
* The following SWIs are ARM private.
diff --git a/include/asm-arm26/cacheflush.h b/include/asm-arm26/cacheflush.h
index 9c1b9c7f2eb..14ae15b6faa 100644
--- a/include/asm-arm26/cacheflush.h
+++ b/include/asm-arm26/cacheflush.h
@@ -22,6 +22,7 @@
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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_cache_vmap(start, end) do { } while (0)
diff --git a/include/asm-arm26/termbits.h b/include/asm-arm26/termbits.h
index bbc6e1d24d3..a3f4fe1742d 100644
--- a/include/asm-arm26/termbits.h
+++ b/include/asm-arm26/termbits.h
@@ -15,6 +15,18 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-avr32/arch-at32ap/at32ap7000.h b/include/asm-avr32/arch-at32ap/at32ap7000.h
new file mode 100644
index 00000000000..3914d7b94ff
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/at32ap7000.h
@@ -0,0 +1,35 @@
+/*
+ * Pin definitions for AT32AP7000.
+ *
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARCH_AT32AP7000_H__
+#define __ASM_ARCH_AT32AP7000_H__
+
+#define GPIO_PERIPH_A 0
+#define GPIO_PERIPH_B 1
+
+#define NR_GPIO_CONTROLLERS 4
+
+/*
+ * Pin numbers identifying specific GPIO pins on the chip. They can
+ * also be converted to IRQ numbers by passing them through
+ * gpio_to_irq().
+ */
+#define GPIO_PIOA_BASE (0)
+#define GPIO_PIOB_BASE (GPIO_PIOA_BASE + 32)
+#define GPIO_PIOC_BASE (GPIO_PIOB_BASE + 32)
+#define GPIO_PIOD_BASE (GPIO_PIOC_BASE + 32)
+#define GPIO_PIOE_BASE (GPIO_PIOD_BASE + 32)
+
+#define GPIO_PIN_PA(N) (GPIO_PIOA_BASE + (N))
+#define GPIO_PIN_PB(N) (GPIO_PIOB_BASE + (N))
+#define GPIO_PIN_PC(N) (GPIO_PIOC_BASE + (N))
+#define GPIO_PIN_PD(N) (GPIO_PIOD_BASE + (N))
+#define GPIO_PIN_PE(N) (GPIO_PIOE_BASE + (N))
+
+#endif /* __ASM_ARCH_AT32AP7000_H__ */
diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h
index a39b3e999f1..b120ee030c8 100644
--- a/include/asm-avr32/arch-at32ap/board.h
+++ b/include/asm-avr32/arch-at32ap/board.h
@@ -21,10 +21,7 @@ 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 {
- u8 valid;
- u8 mii_phy_addr;
u8 is_rmii;
- u8 hw_addr[6];
};
struct platform_device *
at32_add_device_eth(unsigned int id, struct eth_platform_data *data);
diff --git a/include/asm-avr32/arch-at32ap/gpio.h b/include/asm-avr32/arch-at32ap/gpio.h
new file mode 100644
index 00000000000..fcb756bdaa8
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/gpio.h
@@ -0,0 +1,27 @@
+#ifndef __ASM_AVR32_ARCH_GPIO_H
+#define __ASM_AVR32_ARCH_GPIO_H
+
+#include <linux/compiler.h>
+#include <asm/irq.h>
+
+
+/* Arch-neutral GPIO API */
+int __must_check gpio_request(unsigned int gpio, const char *label);
+void gpio_free(unsigned int gpio);
+
+int gpio_direction_input(unsigned int gpio);
+int gpio_direction_output(unsigned int gpio);
+int gpio_get_value(unsigned int gpio);
+void gpio_set_value(unsigned int gpio, int value);
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+ return gpio + GPIO_IRQ_BASE;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+ return irq - GPIO_IRQ_BASE;
+}
+
+#endif /* __ASM_AVR32_ARCH_GPIO_H */
diff --git a/include/asm-avr32/arch-at32ap/irq.h b/include/asm-avr32/arch-at32ap/irq.h
new file mode 100644
index 00000000000..5adffab9a57
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/irq.h
@@ -0,0 +1,14 @@
+#ifndef __ASM_AVR32_ARCH_IRQ_H
+#define __ASM_AVR32_ARCH_IRQ_H
+
+#define EIM_IRQ_BASE NR_INTERNAL_IRQS
+#define NR_EIM_IRQS 32
+
+#define AT32_EXTINT(n) (EIM_IRQ_BASE + (n))
+
+#define GPIO_IRQ_BASE (EIM_IRQ_BASE + NR_EIM_IRQS)
+#define NR_GPIO_IRQS (5 * 32)
+
+#define NR_IRQS (GPIO_IRQ_BASE + NR_GPIO_IRQS)
+
+#endif /* __ASM_AVR32_ARCH_IRQ_H */
diff --git a/include/asm-avr32/arch-at32ap/portmux.h b/include/asm-avr32/arch-at32ap/portmux.h
index 4d50421262a..9930871decd 100644
--- a/include/asm-avr32/arch-at32ap/portmux.h
+++ b/include/asm-avr32/arch-at32ap/portmux.h
@@ -7,10 +7,22 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#ifndef __ASM_AVR32_AT32_PORTMUX_H__
-#define __ASM_AVR32_AT32_PORTMUX_H__
+#ifndef __ASM_ARCH_PORTMUX_H__
+#define __ASM_ARCH_PORTMUX_H__
-void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
- unsigned int function_id);
+/*
+ * Set up pin multiplexing, called from board init only.
+ *
+ * The following flags determine the initial state of the pin.
+ */
+#define AT32_GPIOF_PULLUP 0x00000001 /* (not-OUT) Enable pull-up */
+#define AT32_GPIOF_OUTPUT 0x00000002 /* (OUT) Enable output driver */
+#define AT32_GPIOF_HIGH 0x00000004 /* (OUT) Set output high */
+#define AT32_GPIOF_DEGLITCH 0x00000008 /* (IN) Filter glitches */
+
+void at32_select_periph(unsigned int pin, unsigned int periph,
+ unsigned long flags);
+void at32_select_gpio(unsigned int pin, unsigned long flags);
+void at32_reserve_pin(unsigned int pin);
-#endif /* __ASM_AVR32_AT32_PORTMUX_H__ */
+#endif /* __ASM_ARCH_PORTMUX_H__ */
diff --git a/include/asm-avr32/cacheflush.h b/include/asm-avr32/cacheflush.h
index f1bf1708980..dfaaa88cd41 100644
--- a/include/asm-avr32/cacheflush.h
+++ b/include/asm-avr32/cacheflush.h
@@ -87,6 +87,7 @@ void invalidate_icache_region(void *start, size_t len);
*/
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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_cache_vmap(start, end) do { } while (0)
diff --git a/include/asm-avr32/checksum.h b/include/asm-avr32/checksum.h
index af9d53f0f5d..4ddbfd2486a 100644
--- a/include/asm-avr32/checksum.h
+++ b/include/asm-avr32/checksum.h
@@ -38,7 +38,7 @@ __wsum csum_partial_copy_generic(const void *src, void *dst, int len,
* passed in an incorrect kernel address to one of these functions.
*
* If you use these functions directly please don't forget the
- * verify_area().
+ * access_ok().
*/
static inline
__wsum csum_partial_copy_nocheck(const void *src, void *dst,
diff --git a/include/asm-avr32/dma-mapping.h b/include/asm-avr32/dma-mapping.h
index 0580b5d62bb..115813e48fe 100644
--- a/include/asm-avr32/dma-mapping.h
+++ b/include/asm-avr32/dma-mapping.h
@@ -32,6 +32,14 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask)
return 0;
}
+/*
+ * dma_map_single can't fail as it is implemented now.
+ */
+static inline int dma_mapping_error(dma_addr_t addr)
+{
+ return 0;
+}
+
/**
* dma_alloc_coherent - allocate consistent memory for DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
@@ -109,7 +117,7 @@ static inline dma_addr_t
dma_map_single(struct device *dev, void *cpu_addr, size_t size,
enum dma_data_direction direction)
{
- dma_cache_sync(cpu_addr, size, direction);
+ dma_cache_sync(dev, cpu_addr, size, direction);
return virt_to_bus(cpu_addr);
}
@@ -211,7 +219,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset;
virt = page_address(sg[i].page) + sg[i].offset;
- dma_cache_sync(virt, sg[i].length, direction);
+ dma_cache_sync(dev, virt, sg[i].length, direction);
}
return nents;
@@ -256,14 +264,14 @@ static inline void
dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction direction)
{
- dma_cache_sync(bus_to_virt(dma_handle), size, direction);
+ dma_cache_sync(dev, bus_to_virt(dma_handle), size, direction);
}
static inline void
dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction direction)
{
- dma_cache_sync(bus_to_virt(dma_handle), size, direction);
+ dma_cache_sync(dev, bus_to_virt(dma_handle), size, direction);
}
/**
@@ -286,7 +294,7 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
int i;
for (i = 0; i < nents; i++) {
- dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+ dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
sg[i].length, direction);
}
}
@@ -298,7 +306,7 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
int i;
for (i = 0; i < nents; i++) {
- dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+ dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
sg[i].length, direction);
}
}
diff --git a/include/asm-avr32/gpio.h b/include/asm-avr32/gpio.h
new file mode 100644
index 00000000000..19e8ccc77db
--- /dev/null
+++ b/include/asm-avr32/gpio.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_AVR32_GPIO_H
+#define __ASM_AVR32_GPIO_H
+
+#include <asm/arch/gpio.h>
+
+#endif /* __ASM_AVR32_GPIO_H */
diff --git a/include/asm-avr32/irq.h b/include/asm-avr32/irq.h
index f7e725707dd..83e6549d778 100644
--- a/include/asm-avr32/irq.h
+++ b/include/asm-avr32/irq.h
@@ -2,8 +2,12 @@
#define __ASM_AVR32_IRQ_H
#define NR_INTERNAL_IRQS 64
-#define NR_EXTERNAL_IRQS 64
-#define NR_IRQS (NR_INTERNAL_IRQS + NR_EXTERNAL_IRQS)
+
+#include <asm/arch/irq.h>
+
+#ifndef NR_IRQS
+#define NR_IRQS (NR_INTERNAL_IRQS)
+#endif
#define irq_canonicalize(i) (i)
diff --git a/include/asm-avr32/pgalloc.h b/include/asm-avr32/pgalloc.h
index 7492cfb92ce..bb82e70cde8 100644
--- a/include/asm-avr32/pgalloc.h
+++ b/include/asm-avr32/pgalloc.h
@@ -28,7 +28,7 @@ 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);
+ pgd_t *pgd = kmalloc(pgd_size, GFP_KERNEL);
if (pgd)
memset(pgd, 0, pgd_size);
diff --git a/include/asm-avr32/posix_types.h b/include/asm-avr32/posix_types.h
index 2831b039b34..9e255b99963 100644
--- a/include/asm-avr32/posix_types.h
+++ b/include/asm-avr32/posix_types.h
@@ -23,7 +23,7 @@ typedef unsigned short __kernel_ipc_pid_t;
typedef unsigned int __kernel_uid_t;
typedef unsigned int __kernel_gid_t;
typedef unsigned long __kernel_size_t;
-typedef int __kernel_ssize_t;
+typedef long __kernel_ssize_t;
typedef int __kernel_ptrdiff_t;
typedef long __kernel_time_t;
typedef long __kernel_suseconds_t;
diff --git a/include/asm-avr32/termbits.h b/include/asm-avr32/termbits.h
index 9dc6eacafa3..c215fafdae4 100644
--- a/include/asm-avr32/termbits.h
+++ b/include/asm-avr32/termbits.h
@@ -17,6 +17,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-avr32/uaccess.h b/include/asm-avr32/uaccess.h
index 821deb5a9d2..74a679e9098 100644
--- a/include/asm-avr32/uaccess.h
+++ b/include/asm-avr32/uaccess.h
@@ -68,12 +68,6 @@ static inline void set_fs(mm_segment_t s)
#define access_ok(type, addr, size) (likely(__range_ok(addr, size) == 0))
-static inline int
-verify_area(int type, const void __user *addr, unsigned long size)
-{
- return access_ok(type, addr, size) ? 0 : -EFAULT;
-}
-
/* Generic arbitrary sized copy. Return the number of bytes NOT copied */
extern __kernel_size_t __copy_user(void *to, const void *from,
__kernel_size_t n);
diff --git a/include/asm-cris/cacheflush.h b/include/asm-cris/cacheflush.h
index 72cc71dffe7..01af2de27c5 100644
--- a/include/asm-cris/cacheflush.h
+++ b/include/asm-cris/cacheflush.h
@@ -9,6 +9,7 @@
*/
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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)
diff --git a/include/asm-cris/io.h b/include/asm-cris/io.h
index 716c69bc58f..d196dd6b2df 100644
--- a/include/asm-cris/io.h
+++ b/include/asm-cris/io.h
@@ -121,11 +121,6 @@ static inline void writel(unsigned int b, volatile void __iomem *addr)
#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
-/*
- * Again, CRIS does not require mem IO specific function.
- */
-
-#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void __force *)(b),(c),(d))
/* The following is junk needed for the arch-independent code but which
* we never use in the CRIS port
diff --git a/include/asm-cris/termbits.h b/include/asm-cris/termbits.h
index be0836d2f28..8d8cec225fe 100644
--- a/include/asm-cris/termbits.h
+++ b/include/asm-cris/termbits.h
@@ -19,6 +19,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-frv/Kbuild b/include/asm-frv/Kbuild
index c68e1680da0..966a9836d55 100644
--- a/include/asm-frv/Kbuild
+++ b/include/asm-frv/Kbuild
@@ -1 +1,7 @@
include include/asm-generic/Kbuild.asm
+
+header-y += registers.h
+
+unifdef-y += termios.h
+unifdef-y += ptrace.h
+unifdef-y += page.h
diff --git a/include/asm-frv/bitops.h b/include/asm-frv/bitops.h
index 1f70d47148b..f8560edf59f 100644
--- a/include/asm-frv/bitops.h
+++ b/include/asm-frv/bitops.h
@@ -256,6 +256,50 @@ int __ffs(unsigned long x)
return 31 - bit;
}
+/*
+ * special slimline version of fls() for calculating ilog2_u32()
+ * - note: no protection against n == 0
+ */
+#define ARCH_HAS_ILOG2_U32
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+ int bit;
+ asm("scan %1,gr0,%0" : "=r"(bit) : "r"(n));
+ return 31 - bit;
+}
+
+/*
+ * special slimline version of fls64() for calculating ilog2_u64()
+ * - note: no protection against n == 0
+ */
+#define ARCH_HAS_ILOG2_U64
+static inline __attribute__((const))
+int __ilog2_u64(u64 n)
+{
+ union {
+ u64 ll;
+ struct { u32 h, l; };
+ } _;
+ int bit, x, y;
+
+ _.ll = n;
+
+ asm(" subcc %3,gr0,gr0,icc0 \n"
+ " ckeq icc0,cc4 \n"
+ " cscan.p %3,gr0,%0 ,cc4,0 \n"
+ " setlos #63,%1 \n"
+ " cscan.p %4,gr0,%0 ,cc4,1 \n"
+ " setlos #31,%2 \n"
+ " csub.p %1,%0,%0 ,cc4,0 \n"
+ " csub %2,%0,%0 ,cc4,1 \n"
+ : "=&r"(bit), "=r"(x), "=r"(y)
+ : "0r"(_.h), "r"(_.l)
+ : "icc0", "cc4"
+ );
+ return bit;
+}
+
#include <asm-generic/bitops/sched.h>
#include <asm-generic/bitops/hweight.h>
diff --git a/include/asm-frv/cacheflush.h b/include/asm-frv/cacheflush.h
index eaa5826bc1c..02500405a6f 100644
--- a/include/asm-frv/cacheflush.h
+++ b/include/asm-frv/cacheflush.h
@@ -20,6 +20,7 @@
*/
#define flush_cache_all() do {} while(0)
#define flush_cache_mm(mm) do {} while(0)
+#define flush_cache_dup_mm(mm) do {} while(0)
#define flush_cache_range(mm, start, end) do {} while(0)
#define flush_cache_page(vma, vmaddr, pfn) do {} while(0)
#define flush_cache_vmap(start, end) do {} while(0)
diff --git a/include/asm-frv/page.h b/include/asm-frv/page.h
index 134cc0cdf6c..213d92fd652 100644
--- a/include/asm-frv/page.h
+++ b/include/asm-frv/page.h
@@ -76,8 +76,6 @@ extern unsigned long max_pfn;
#endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
-
#ifdef CONFIG_CONTIGUOUS_PAGE_ALLOC
#define WANT_PAGE_VIRTUAL 1
#endif
@@ -85,4 +83,6 @@ extern unsigned long max_pfn;
#include <asm-generic/memory_model.h>
#include <asm-generic/page.h>
+#endif /* __KERNEL__ */
+
#endif /* _ASM_PAGE_H */
diff --git a/include/asm-frv/ptrace.h b/include/asm-frv/ptrace.h
index 9a2241b8eb1..cf6934012b6 100644
--- a/include/asm-frv/ptrace.h
+++ b/include/asm-frv/ptrace.h
@@ -12,9 +12,11 @@
#define _ASM_PTRACE_H
#include <asm/registers.h>
+#ifdef __KERNEL__
#include <asm/irq_regs.h>
#define in_syscall(regs) (((regs)->tbr & TBR_TT) == TBR_TT_TRAP0)
+#endif
#define PT_PSR 0
@@ -60,6 +62,7 @@
#define PTRACE_GETFDPIC_EXEC 0 /* [addr] request the executable loadmap */
#define PTRACE_GETFDPIC_INTERP 1 /* [addr] request the interpreter loadmap */
+#ifdef __KERNEL__
#ifndef __ASSEMBLY__
/*
@@ -74,6 +77,7 @@ register struct pt_regs *__frame asm("gr28");
extern unsigned long user_stack(const struct pt_regs *);
extern void show_regs(struct pt_regs *);
#define profile_pc(regs) ((regs)->pc)
+#endif
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_PTRACE_H */
diff --git a/include/asm-frv/termbits.h b/include/asm-frv/termbits.h
index 74f20d6e292..2d6d389cff4 100644
--- a/include/asm-frv/termbits.h
+++ b/include/asm-frv/termbits.h
@@ -17,6 +17,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-frv/termios.h b/include/asm-frv/termios.h
index b4a664e7f55..8840cf95e8d 100644
--- a/include/asm-frv/termios.h
+++ b/include/asm-frv/termios.h
@@ -69,6 +69,8 @@ struct termio {
#define N_SYNC_PPP 14
#define N_HCI 15 /* Bluetooth HCI UART */
+#ifdef __KERNEL__
#include <asm-generic/termios.h>
+#endif
#endif /* _ASM_TERMIOS_H */
diff --git a/include/asm-frv/thread_info.h b/include/asm-frv/thread_info.h
index d66c48e6ef1..d881f518e6a 100644
--- a/include/asm-frv/thread_info.h
+++ b/include/asm-frv/thread_info.h
@@ -116,6 +116,7 @@ register struct thread_info *__current_thread_info asm("gr15");
#define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */
#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 17 /* OOM killer killed process */
+#define TIF_FREEZE 18 /* freezing for suspend */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
@@ -125,6 +126,7 @@ register struct thread_info *__current_thread_info asm("gr15");
#define _TIF_IRET (1 << TIF_IRET)
#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
+#define _TIF_FREEZE (1 << TIF_FREEZE)
#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */
#define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index c92ae0f166f..14fae1fa87d 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -4,6 +4,22 @@
#include <linux/compiler.h>
#ifdef CONFIG_BUG
+
+#ifdef CONFIG_GENERIC_BUG
+#ifndef __ASSEMBLY__
+struct bug_entry {
+ unsigned long bug_addr;
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+ const char *file;
+ unsigned short line;
+#endif
+ unsigned short flags;
+};
+#endif /* __ASSEMBLY__ */
+
+#define BUGFLAG_WARNING (1<<0)
+#endif /* CONFIG_GENERIC_BUG */
+
#ifndef HAVE_ARCH_BUG
#define BUG() do { \
printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \
@@ -19,7 +35,7 @@
#define WARN_ON(condition) ({ \
typeof(condition) __ret_warn_on = (condition); \
if (unlikely(__ret_warn_on)) { \
- printk("BUG: warning at %s:%d/%s()\n", __FILE__, \
+ printk("BUG: at %s:%d %s()\n", __FILE__, \
__LINE__, __FUNCTION__); \
dump_stack(); \
} \
diff --git a/include/asm-generic/libata-portmap.h b/include/asm-generic/libata-portmap.h
index 9202fd02d5b..62fb3618293 100644
--- a/include/asm-generic/libata-portmap.h
+++ b/include/asm-generic/libata-portmap.h
@@ -3,10 +3,10 @@
#define ATA_PRIMARY_CMD 0x1F0
#define ATA_PRIMARY_CTL 0x3F6
-#define ATA_PRIMARY_IRQ 14
+#define ATA_PRIMARY_IRQ(dev) 14
#define ATA_SECONDARY_CMD 0x170
#define ATA_SECONDARY_CTL 0x376
-#define ATA_SECONDARY_IRQ 15
+#define ATA_SECONDARY_IRQ(dev) 15
#endif
diff --git a/include/asm-generic/page.h b/include/asm-generic/page.h
index a96b5d986b6..b55052ce233 100644
--- a/include/asm-generic/page.h
+++ b/include/asm-generic/page.h
@@ -4,21 +4,51 @@
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
-#include <linux/compiler.h>
+#include <linux/log2.h>
-/* Pure 2^n version of get_order */
-static __inline__ __attribute_const__ int get_order(unsigned long size)
+/*
+ * non-const pure 2^n version of get_order
+ * - the arch may override these in asm/bitops.h if they can be implemented
+ * more efficiently than using the arch log2 routines
+ * - we use the non-const log2() instead if the arch has defined one suitable
+ */
+#ifndef ARCH_HAS_GET_ORDER
+static inline __attribute__((const))
+int __get_order(unsigned long size, int page_shift)
{
+#if BITS_PER_LONG == 32 && defined(ARCH_HAS_ILOG2_U32)
+ int order = __ilog2_u32(size) - page_shift;
+ return order >= 0 ? order : 0;
+#elif BITS_PER_LONG == 64 && defined(ARCH_HAS_ILOG2_U64)
+ int order = __ilog2_u64(size) - page_shift;
+ return order >= 0 ? order : 0;
+#else
int order;
- size = (size - 1) >> (PAGE_SHIFT - 1);
+ size = (size - 1) >> (page_shift - 1);
order = -1;
do {
size >>= 1;
order++;
} while (size);
return order;
+#endif
}
+#endif
+
+/**
+ * get_order - calculate log2(pages) to hold a block of the specified size
+ * @n - size
+ *
+ * calculate allocation order based on the current page size
+ * - this can be used to initialise global variables from constant data
+ */
+#define get_order(n) \
+( \
+ __builtin_constant_p(n) ? \
+ ((n < (1UL << PAGE_SHIFT)) ? 0 : ilog2(n) - PAGE_SHIFT) : \
+ __get_order(n, PAGE_SHIFT) \
+ )
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-generic/termios.h b/include/asm-generic/termios.h
index 1e58ca39592..3769e6bd63b 100644
--- a/include/asm-generic/termios.h
+++ b/include/asm-generic/termios.h
@@ -11,7 +11,7 @@
/*
* Translate a "termio" structure into a "termios". Ugh.
*/
-static inline int user_termio_to_kernel_termios(struct termios *termios,
+static inline int user_termio_to_kernel_termios(struct ktermios *termios,
struct termio __user *termio)
{
unsigned short tmp;
@@ -48,7 +48,7 @@ static inline int user_termio_to_kernel_termios(struct termios *termios,
* Translate a "termios" structure into a "termio". Ugh.
*/
static inline int kernel_termios_to_user_termio(struct termio __user *termio,
- struct termios *termios)
+ struct ktermios *termios)
{
if (put_user(termios->c_iflag, &termio->c_iflag) < 0 ||
put_user(termios->c_oflag, &termio->c_oflag) < 0 ||
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 4d4c62d1105..9fcc8d9fbb1 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -35,6 +35,9 @@
VMLINUX_SYMBOL(__start_pci_fixups_enable) = .; \
*(.pci_fixup_enable) \
VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \
+ VMLINUX_SYMBOL(__start_pci_fixups_resume) = .; \
+ *(.pci_fixup_resume) \
+ VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \
} \
\
/* RapidIO route ops */ \
@@ -119,8 +122,6 @@
*(__ksymtab_strings) \
} \
\
- EH_FRAME \
- \
/* Built-in module parameters. */ \
__param : AT(ADDR(__param) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___param) = .; \
@@ -160,26 +161,6 @@
*(.kprobes.text) \
VMLINUX_SYMBOL(__kprobes_text_end) = .;
-#ifdef CONFIG_STACK_UNWIND
-#define EH_FRAME \
- /* Unwind data binary search table */ \
- . = ALIGN(8); \
- .eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - LOAD_OFFSET) { \
- VMLINUX_SYMBOL(__start_unwind_hdr) = .; \
- *(.eh_frame_hdr) \
- VMLINUX_SYMBOL(__end_unwind_hdr) = .; \
- } \
- /* Unwind data */ \
- . = ALIGN(8); \
- .eh_frame : AT(ADDR(.eh_frame) - LOAD_OFFSET) { \
- VMLINUX_SYMBOL(__start_unwind) = .; \
- *(.eh_frame) \
- VMLINUX_SYMBOL(__end_unwind) = .; \
- }
-#else
-#define EH_FRAME
-#endif
-
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to
the beginning of the section so we begin them at 0. */
@@ -218,6 +199,14 @@
.stab.indexstr 0 : { *(.stab.indexstr) } \
.comment 0 : { *(.comment) }
+#define BUG_TABLE \
+ . = ALIGN(8); \
+ __bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) { \
+ __start___bug_table = .; \
+ *(__bug_table) \
+ __stop___bug_table = .; \
+ }
+
#define NOTES \
.notes : { *(.note.*) } :note
@@ -234,6 +223,7 @@
*(.initcall4s.init) \
*(.initcall5.init) \
*(.initcall5s.init) \
+ *(.initcallrootfs.init) \
*(.initcall6.init) \
*(.initcall6s.init) \
*(.initcall7.init) \
diff --git a/include/asm-h8300/cacheflush.h b/include/asm-h8300/cacheflush.h
index 1e4d95bb5ec..71210d141b6 100644
--- a/include/asm-h8300/cacheflush.h
+++ b/include/asm-h8300/cacheflush.h
@@ -12,6 +12,7 @@
#define flush_cache_all()
#define flush_cache_mm(mm)
+#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma,a,b)
#define flush_cache_page(vma,p,pfn)
#define flush_dcache_page(page)
diff --git a/include/asm-h8300/termbits.h b/include/asm-h8300/termbits.h
index fa69ae00eda..6a1f4d3807b 100644
--- a/include/asm-h8300/termbits.h
+++ b/include/asm-h8300/termbits.h
@@ -17,6 +17,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h
index c80b3a94511..5e657eb8946 100644
--- a/include/asm-i386/acpi.h
+++ b/include/asm-i386/acpi.h
@@ -39,7 +39,7 @@
* Calling conventions:
*
* ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads)
- * ACPI_EXTERNAL_XFACE - External ACPI interfaces
+ * ACPI_EXTERNAL_XFACE - External ACPI interfaces
* ACPI_INTERNAL_XFACE - Internal ACPI interfaces
* ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces
*/
@@ -56,36 +56,14 @@
#define ACPI_ENABLE_IRQS() local_irq_enable()
#define ACPI_FLUSH_CPU_CACHE() wbinvd()
+int __acpi_acquire_global_lock(unsigned int *lock);
+int __acpi_release_global_lock(unsigned int *lock);
-static inline int
-__acpi_acquire_global_lock (unsigned int *lock)
-{
- unsigned int old, new, val;
- do {
- old = *lock;
- new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
- val = cmpxchg(lock, old, new);
- } while (unlikely (val != old));
- return (new < 3) ? -1 : 0;
-}
-
-static inline int
-__acpi_release_global_lock (unsigned int *lock)
-{
- unsigned int old, new, val;
- do {
- old = *lock;
- new = old & ~0x3;
- val = cmpxchg(lock, old, new);
- } while (unlikely (val != old));
- return old & 0x1;
-}
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
+ ((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
-#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
- ((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr))
-
-#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
- ((Acq) = __acpi_release_global_lock((unsigned int *) GLptr))
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
+ ((Acq) = __acpi_release_global_lock(&facs->global_lock))
/*
* Math helper asm macros
@@ -109,7 +87,7 @@ extern void check_acpi_pci(void);
static inline void check_acpi_pci(void) { }
#endif
-#ifdef CONFIG_ACPI
+#ifdef CONFIG_ACPI
extern int acpi_lapic;
extern int acpi_ioapic;
extern int acpi_noirq;
@@ -117,9 +95,9 @@ extern int acpi_strict;
extern int acpi_disabled;
extern int acpi_ht;
extern int acpi_pci_disabled;
-static inline void disable_acpi(void)
-{
- acpi_disabled = 1;
+static inline void disable_acpi(void)
+{
+ acpi_disabled = 1;
acpi_ht = 0;
acpi_pci_disabled = 1;
acpi_noirq = 1;
@@ -136,9 +114,9 @@ extern int acpi_use_timer_override;
#endif
static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
-static inline void acpi_disable_pci(void)
+static inline void acpi_disable_pci(void)
{
- acpi_pci_disabled = 1;
+ acpi_pci_disabled = 1;
acpi_noirq_set();
}
extern int acpi_irq_balance_set(char *str);
@@ -166,8 +144,6 @@ extern void acpi_reserve_bootmem(void);
#endif /*CONFIG_ACPI_SLEEP*/
-extern u8 x86_acpiid_to_apicid[];
-
#define ARCH_HAS_POWER_INIT 1
#endif /*__KERNEL__*/
diff --git a/include/asm-i386/boot.h b/include/asm-i386/boot.h
index 8ce79a6fa89..e7686d0a841 100644
--- a/include/asm-i386/boot.h
+++ b/include/asm-i386/boot.h
@@ -13,7 +13,8 @@
#define ASK_VGA 0xfffd /* ask for it at bootup */
/* Physical address where kenrel should be loaded. */
-#define LOAD_PHYSICAL_ADDR ((0x100000 + CONFIG_PHYSICAL_ALIGN - 1) \
+#define LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \
+ + (CONFIG_PHYSICAL_ALIGN - 1)) \
& ~(CONFIG_PHYSICAL_ALIGN - 1))
#endif /* _LINUX_BOOT_H */
diff --git a/include/asm-i386/bug.h b/include/asm-i386/bug.h
index 8062cdbf258..b0fd78ca261 100644
--- a/include/asm-i386/bug.h
+++ b/include/asm-i386/bug.h
@@ -4,20 +4,32 @@
/*
* Tell the user there is some problem.
- * The offending file and line are encoded after the "officially
- * undefined" opcode for parsing in the trap handler.
+ * The offending file and line are encoded encoded in the __bug_table section.
*/
#ifdef CONFIG_BUG
#define HAVE_ARCH_BUG
+
#ifdef CONFIG_DEBUG_BUGVERBOSE
-#define BUG() \
- __asm__ __volatile__( "ud2\n" \
- "\t.word %c0\n" \
- "\t.long %c1\n" \
- : : "i" (__LINE__), "i" (__FILE__))
+#define BUG() \
+ do { \
+ asm volatile("1:\tud2\n" \
+ ".pushsection __bug_table,\"a\"\n" \
+ "2:\t.long 1b, %c0\n" \
+ "\t.word %c1, 0\n" \
+ "\t.org 2b+%c2\n" \
+ ".popsection" \
+ : : "i" (__FILE__), "i" (__LINE__), \
+ "i" (sizeof(struct bug_entry))); \
+ for(;;) ; \
+ } while(0)
+
#else
-#define BUG() __asm__ __volatile__("ud2\n")
+#define BUG() \
+ do { \
+ asm volatile("ud2"); \
+ for(;;) ; \
+ } while(0)
#endif
#endif
diff --git a/include/asm-i386/cacheflush.h b/include/asm-i386/cacheflush.h
index 7199f7b326f..74e03c8f2e5 100644
--- a/include/asm-i386/cacheflush.h
+++ b/include/asm-i386/cacheflush.h
@@ -7,6 +7,7 @@
/* Caches aren't brain-dead on the intel. */
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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)
diff --git a/include/asm-i386/e820.h b/include/asm-i386/e820.h
index 395077aba58..c5b8fc6109d 100644
--- a/include/asm-i386/e820.h
+++ b/include/asm-i386/e820.h
@@ -40,7 +40,7 @@ extern int e820_all_mapped(unsigned long start, unsigned long end,
unsigned type);
extern void find_max_pfn(void);
extern void register_bootmem_low_pages(unsigned long max_low_pfn);
-extern void register_memory(void);
+extern void e820_register_memory(void);
extern void limit_regions(unsigned long long size);
extern void print_memory_map(char *who);
diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h
index 45d21a0c95b..369035dfe4b 100644
--- a/include/asm-i386/elf.h
+++ b/include/asm-i386/elf.h
@@ -143,11 +143,8 @@ extern int dump_task_extended_fpu (struct task_struct *, struct user_fxsr_struct
# define VDSO_PRELINK 0
#endif
-#define VDSO_COMPAT_SYM(x) \
- (VDSO_COMPAT_BASE + (unsigned long)(x) - VDSO_PRELINK)
-
#define VDSO_SYM(x) \
- (VDSO_BASE + (unsigned long)(x) - VDSO_PRELINK)
+ (VDSO_COMPAT_BASE + (unsigned long)(x) - VDSO_PRELINK)
#define VDSO_HIGH_EHDR ((const struct elfhdr *) VDSO_HIGH_BASE)
#define VDSO_EHDR ((const struct elfhdr *) VDSO_COMPAT_BASE)
@@ -156,10 +153,12 @@ extern void __kernel_vsyscall;
#define VDSO_ENTRY VDSO_SYM(&__kernel_vsyscall)
+#ifndef CONFIG_COMPAT_VDSO
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
struct linux_binprm;
extern int arch_setup_additional_pages(struct linux_binprm *bprm,
int executable_stack);
+#endif
extern unsigned int vdso_enabled;
@@ -169,50 +168,6 @@ do if (vdso_enabled) { \
NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_COMPAT_BASE); \
} while (0)
-/*
- * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
- * extra segments containing the vsyscall DSO contents. Dumping its
- * contents makes post-mortem fully interpretable later without matching up
- * the same kernel and hardware config to see what PC values meant.
- * Dumping its extra ELF program headers includes all the other information
- * a debugger needs to easily find how the vsyscall DSO was being used.
- */
-#define ELF_CORE_EXTRA_PHDRS (VDSO_HIGH_EHDR->e_phnum)
-#define ELF_CORE_WRITE_EXTRA_PHDRS \
-do { \
- const struct elf_phdr *const vsyscall_phdrs = \
- (const struct elf_phdr *) (VDSO_HIGH_BASE \
- + VDSO_HIGH_EHDR->e_phoff); \
- int i; \
- Elf32_Off ofs = 0; \
- for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) { \
- struct elf_phdr phdr = vsyscall_phdrs[i]; \
- if (phdr.p_type == PT_LOAD) { \
- BUG_ON(ofs != 0); \
- ofs = phdr.p_offset = offset; \
- phdr.p_memsz = PAGE_ALIGN(phdr.p_memsz); \
- phdr.p_filesz = phdr.p_memsz; \
- offset += phdr.p_filesz; \
- } \
- else \
- phdr.p_offset += ofs; \
- phdr.p_paddr = 0; /* match other core phdrs */ \
- DUMP_WRITE(&phdr, sizeof(phdr)); \
- } \
-} while (0)
-#define ELF_CORE_WRITE_EXTRA_DATA \
-do { \
- const struct elf_phdr *const vsyscall_phdrs = \
- (const struct elf_phdr *) (VDSO_HIGH_BASE \
- + VDSO_HIGH_EHDR->e_phoff); \
- int i; \
- for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) { \
- if (vsyscall_phdrs[i].p_type == PT_LOAD) \
- DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr, \
- PAGE_ALIGN(vsyscall_phdrs[i].p_memsz)); \
- } \
-} while (0)
-
#endif
#endif
diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
index 02428cb3662..3e9f610c35d 100644
--- a/include/asm-i386/fixmap.h
+++ b/include/asm-i386/fixmap.h
@@ -23,6 +23,8 @@
extern unsigned long __FIXADDR_TOP;
#else
#define __FIXADDR_TOP 0xfffff000
+#define FIXADDR_USER_START __fix_to_virt(FIX_VDSO)
+#define FIXADDR_USER_END __fix_to_virt(FIX_VDSO - 1)
#endif
#ifndef __ASSEMBLY__
diff --git a/include/asm-i386/ide.h b/include/asm-i386/ide.h
index 73465d2892b..0fc240c80f4 100644
--- a/include/asm-i386/ide.h
+++ b/include/asm-i386/ide.h
@@ -40,13 +40,14 @@ static __inline__ int ide_default_irq(unsigned long base)
static __inline__ unsigned long ide_default_io_base(int index)
{
+ struct pci_dev *pdev;
/*
* If PCI is present then it is not safe to poke around
* the other legacy IDE ports. Only 0x1f0 and 0x170 are
* defined compatibility mode ports for PCI. A user can
* override this using ide= but we must default safe.
*/
- if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) == NULL) {
+ if ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL)) == NULL) {
switch(index) {
case 2: return 0x1e8;
case 3: return 0x168;
@@ -54,6 +55,7 @@ static __inline__ unsigned long ide_default_io_base(int index)
case 5: return 0x160;
}
}
+ pci_dev_put(pdev);
switch (index) {
case 0: return 0x1f0;
case 1: return 0x170;
diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
index 86ff5e83be2..59fe616933c 100644
--- a/include/asm-i386/io.h
+++ b/include/asm-i386/io.h
@@ -219,12 +219,6 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int
#define __ISA_IO_base ((char __iomem *)(PAGE_OFFSET))
/*
- * Again, i386 does not require mem IO specific function.
- */
-
-#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void __force *)(b),(c),(d))
-
-/*
* Cache management
*
* This needed for two cases
diff --git a/include/asm-i386/mach-es7000/mach_mpparse.h b/include/asm-i386/mach-es7000/mach_mpparse.h
index 99f66be240b..24990e546da 100644
--- a/include/asm-i386/mach-es7000/mach_mpparse.h
+++ b/include/asm-i386/mach-es7000/mach_mpparse.h
@@ -3,13 +3,13 @@
#include <linux/acpi.h>
-static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name,
+static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name,
struct mpc_config_translation *translation)
{
Dprintk("Bus #%d is %s\n", m->mpc_busid, name);
}
-static inline void mpc_oem_pci_bus(struct mpc_config_bus *m,
+static inline void mpc_oem_pci_bus(struct mpc_config_bus *m,
struct mpc_config_translation *translation)
{
}
@@ -22,7 +22,7 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
char *productid)
{
if (mpc->mpc_oemptr) {
- struct mp_config_oemtable *oem_table =
+ struct mp_config_oemtable *oem_table =
(struct mp_config_oemtable *)mpc->mpc_oemptr;
if (!strncmp(oem, "UNISYS", 6))
return parse_unisys_oem((char *)oem_table);
@@ -31,12 +31,13 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
}
#ifdef CONFIG_ACPI
+
static inline int es7000_check_dsdt(void)
{
- struct acpi_table_header *header = NULL;
- if(!acpi_get_table_header_early(ACPI_DSDT, &header))
- acpi_table_print(header, 0);
- if (!strncmp(header->oem_id, "UNISYS", 6))
+ struct acpi_table_header header;
+ memcpy(&header, 0, sizeof(struct acpi_table_header));
+ acpi_get_table_header(ACPI_SIG_DSDT, 0, &header);
+ if (!strncmp(header.oem_id, "UNISYS", 6))
return 1;
return 0;
}
@@ -44,7 +45,7 @@ static inline int es7000_check_dsdt(void)
/* Hook from generic ACPI tables.c */
static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
- unsigned long oem_addr;
+ unsigned long oem_addr;
if (!find_unisys_acpi_oem_table(&oem_addr)) {
if (es7000_check_dsdt())
return parse_unisys_oem((char *)oem_addr);
diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h
index 5679d499307..609a3899475 100644
--- a/include/asm-i386/msr.h
+++ b/include/asm-i386/msr.h
@@ -100,6 +100,8 @@ static inline void wrmsrl (unsigned long msr, unsigned long long val)
#define MSR_P6_PERFCTR0 0xc1
#define MSR_P6_PERFCTR1 0xc2
+#define MSR_FSB_FREQ 0xcd
+
#define MSR_IA32_BBL_CR_CTL 0x119
@@ -130,6 +132,9 @@ static inline void wrmsrl (unsigned long msr, unsigned long long val)
#define MSR_IA32_PERF_STATUS 0x198
#define MSR_IA32_PERF_CTL 0x199
+#define MSR_IA32_MPERF 0xE7
+#define MSR_IA32_APERF 0xE8
+
#define MSR_IA32_THERM_CONTROL 0x19a
#define MSR_IA32_THERM_INTERRUPT 0x19b
#define MSR_IA32_THERM_STATUS 0x19c
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h
index fd3f64ace24..7b19f454761 100644
--- a/include/asm-i386/page.h
+++ b/include/asm-i386/page.h
@@ -143,7 +143,9 @@ extern int page_is_ram(unsigned long pagenr);
#include <asm-generic/memory_model.h>
#include <asm-generic/page.h>
+#ifndef CONFIG_COMPAT_VDSO
#define __HAVE_ARCH_GATE_AREA 1
+#endif
#endif /* __KERNEL__ */
#endif /* _I386_PAGE_H */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index a52d6544042..359f10b54f5 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -743,6 +743,7 @@ extern void enable_sep_cpu(void);
extern int sysenter_setup(void);
extern int init_gdt(int cpu, struct task_struct *idle);
+extern void cpu_set_gdt(int);
extern void secondary_cpu_init(void);
#endif /* __ASM_I386_PROCESSOR_H */
diff --git a/include/asm-i386/termbits.h b/include/asm-i386/termbits.h
index 72c10e3190f..12baf1d6343 100644
--- a/include/asm-i386/termbits.h
+++ b/include/asm-i386/termbits.h
@@ -17,6 +17,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
index 46d32ad9208..4b187bb377b 100644
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -134,6 +134,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_MEMDIE 16
#define TIF_DEBUG 17 /* uses debug registers */
#define TIF_IO_BITMAP 18 /* uses I/O bitmap */
+#define TIF_FREEZE 19 /* is freezing for suspend */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
@@ -147,6 +148,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_DEBUG (1<<TIF_DEBUG)
#define _TIF_IO_BITMAP (1<<TIF_IO_BITMAP)
+#define _TIF_FREEZE (1<<TIF_FREEZE)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK \
diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h
index 978d0959613..ac58580ad66 100644
--- a/include/asm-i386/topology.h
+++ b/include/asm-i386/topology.h
@@ -89,6 +89,7 @@ static inline int node_to_first_cpu(int node)
.flags = SD_LOAD_BALANCE \
| SD_BALANCE_EXEC \
| SD_BALANCE_FORK \
+ | SD_SERIALIZE \
| SD_WAKE_BALANCE, \
.last_balance = jiffies, \
.balance_interval = 1, \
diff --git a/include/asm-i386/unwind.h b/include/asm-i386/unwind.h
index aa2c931e30d..43c70c3de2f 100644
--- a/include/asm-i386/unwind.h
+++ b/include/asm-i386/unwind.h
@@ -1,95 +1,6 @@
#ifndef _ASM_I386_UNWIND_H
#define _ASM_I386_UNWIND_H
-/*
- * Copyright (C) 2002-2006 Novell, Inc.
- * Jan Beulich <jbeulich@novell.com>
- * This code is released under version 2 of the GNU GPL.
- */
-
-#ifdef CONFIG_STACK_UNWIND
-
-#include <linux/sched.h>
-#include <asm/fixmap.h>
-#include <asm/ptrace.h>
-#include <asm/uaccess.h>
-
-struct unwind_frame_info
-{
- struct pt_regs regs;
- struct task_struct *task;
- unsigned call_frame:1;
-};
-
-#define UNW_PC(frame) (frame)->regs.eip
-#define UNW_SP(frame) (frame)->regs.esp
-#ifdef CONFIG_FRAME_POINTER
-#define UNW_FP(frame) (frame)->regs.ebp
-#define FRAME_RETADDR_OFFSET 4
-#define FRAME_LINK_OFFSET 0
-#define STACK_BOTTOM(tsk) STACK_LIMIT((tsk)->thread.esp0)
-#define STACK_TOP(tsk) ((tsk)->thread.esp0)
-#else
-#define UNW_FP(frame) ((void)(frame), 0)
-#endif
-#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1))
-
-#define UNW_REGISTER_INFO \
- PTREGS_INFO(eax), \
- PTREGS_INFO(ecx), \
- PTREGS_INFO(edx), \
- PTREGS_INFO(ebx), \
- PTREGS_INFO(esp), \
- PTREGS_INFO(ebp), \
- PTREGS_INFO(esi), \
- PTREGS_INFO(edi), \
- PTREGS_INFO(eip)
-
-#define UNW_DEFAULT_RA(raItem, dataAlign) \
- ((raItem).where == Memory && \
- !((raItem).value * (dataAlign) + 4))
-
-static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
- /*const*/ struct pt_regs *regs)
-{
- if (user_mode_vm(regs))
- info->regs = *regs;
- else {
- memcpy(&info->regs, regs, offsetof(struct pt_regs, esp));
- info->regs.esp = (unsigned long)&regs->esp;
- info->regs.xss = __KERNEL_DS;
- }
-}
-
-static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
-{
- memset(&info->regs, 0, sizeof(info->regs));
- info->regs.eip = info->task->thread.eip;
- info->regs.xcs = __KERNEL_CS;
- __get_user(info->regs.ebp, (long *)info->task->thread.esp);
- info->regs.esp = info->task->thread.esp;
- info->regs.xss = __KERNEL_DS;
- info->regs.xds = __USER_DS;
- info->regs.xes = __USER_DS;
- info->regs.xgs = __KERNEL_PDA;
-}
-
-extern asmlinkage int arch_unwind_init_running(struct unwind_frame_info *,
- asmlinkage int (*callback)(struct unwind_frame_info *,
- void *arg),
- void *arg);
-
-static inline int arch_unw_user_mode(/*const*/ struct unwind_frame_info *info)
-{
- return user_mode_vm(&info->regs)
- || info->regs.eip < PAGE_OFFSET
- || (info->regs.eip >= __fix_to_virt(FIX_VDSO)
- && info->regs.eip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE)
- || info->regs.esp < PAGE_OFFSET;
-}
-
-#else
-
#define UNW_PC(frame) ((void)(frame), 0)
#define UNW_SP(frame) ((void)(frame), 0)
#define UNW_FP(frame) ((void)(frame), 0)
@@ -99,6 +10,4 @@ static inline int arch_unw_user_mode(const void *info)
return 0;
}
-#endif
-
#endif /* _ASM_I386_UNWIND_H */
diff --git a/include/asm-ia64/acpi.h b/include/asm-ia64/acpi.h
index 09a5dd0e44a..5d03792d4f6 100644
--- a/include/asm-ia64/acpi.h
+++ b/include/asm-ia64/acpi.h
@@ -82,11 +82,11 @@ ia64_acpi_release_global_lock (unsigned int *lock)
return old & 0x1;
}
-#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
- ((Acq) = ia64_acpi_acquire_global_lock((unsigned int *) GLptr))
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
+ ((Acq) = ia64_acpi_acquire_global_lock(&facs->global_lock))
-#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
- ((Acq) = ia64_acpi_release_global_lock((unsigned int *) GLptr))
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
+ ((Acq) = ia64_acpi_release_global_lock(&facs->global_lock))
#define acpi_disabled 0 /* ACPI always enabled on IA64 */
#define acpi_noirq 0 /* ACPI always enabled on IA64 */
@@ -119,8 +119,6 @@ extern int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS];
extern int __initdata nid_to_pxm_map[MAX_NUMNODES];
#endif
-extern u16 ia64_acpiid_to_sapicid[];
-
/*
* Refer Intel ACPI _PDC support document for bit definitions
*/
diff --git a/include/asm-ia64/break.h b/include/asm-ia64/break.h
index 8167828edc4..f0340203989 100644
--- a/include/asm-ia64/break.h
+++ b/include/asm-ia64/break.h
@@ -12,8 +12,8 @@
* OS-specific debug break numbers:
*/
#define __IA64_BREAK_KDB 0x80100
-#define __IA64_BREAK_KPROBE 0x80200
-#define __IA64_BREAK_JPROBE 0x80300
+#define __IA64_BREAK_KPROBE 0x81000 /* .. 0x81fff */
+#define __IA64_BREAK_JPROBE 0x82000
/*
* OS-specific break numbers:
diff --git a/include/asm-ia64/cacheflush.h b/include/asm-ia64/cacheflush.h
index f2dacb4245e..4906916d715 100644
--- a/include/asm-ia64/cacheflush.h
+++ b/include/asm-ia64/cacheflush.h
@@ -18,6 +18,7 @@
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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_icache_page(vma,page) do { } while (0)
diff --git a/include/asm-ia64/checksum.h b/include/asm-ia64/checksum.h
index 2b78582cbd6..97af155057e 100644
--- a/include/asm-ia64/checksum.h
+++ b/include/asm-ia64/checksum.h
@@ -72,8 +72,8 @@ static inline __sum16 csum_fold(__wsum csum)
#define _HAVE_ARCH_IPV6_CSUM 1
struct in6_addr;
-extern unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
- struct in6_addr *daddr, __u32 len, unsigned short proto,
- unsigned int csum);
+extern __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+ const struct in6_addr *daddr, __u32 len, unsigned short proto,
+ __wsum csum);
#endif /* _ASM_IA64_CHECKSUM_H */
diff --git a/include/asm-ia64/dma.h b/include/asm-ia64/dma.h
index dad3a735df8..4d97f60f1ef 100644
--- a/include/asm-ia64/dma.h
+++ b/include/asm-ia64/dma.h
@@ -19,4 +19,6 @@ extern unsigned long MAX_DMA_ADDRESS;
#define free_dma(x)
+void dma_mark_clean(void *addr, size_t size);
+
#endif /* _ASM_IA64_DMA_H */
diff --git a/include/asm-ia64/esi.h b/include/asm-ia64/esi.h
index 84aac0e0b58..40991c6ba64 100644
--- a/include/asm-ia64/esi.h
+++ b/include/asm-ia64/esi.h
@@ -19,7 +19,6 @@ enum esi_proc_type {
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,
diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h
index 1b45b71c79b..828ae00e47c 100644
--- a/include/asm-ia64/kprobes.h
+++ b/include/asm-ia64/kprobes.h
@@ -115,6 +115,7 @@ struct arch_specific_insn {
#define INST_FLAG_BREAK_INST 4
unsigned long inst_flag;
unsigned short target_br_reg;
+ unsigned short slot;
};
extern int kprobe_exceptions_notify(struct notifier_block *self,
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
index a3891eb3f21..3c96ac19154 100644
--- a/include/asm-ia64/machvec.h
+++ b/include/asm-ia64/machvec.h
@@ -21,6 +21,7 @@ struct mm_struct;
struct pci_bus;
struct task_struct;
struct pci_dev;
+struct msi_desc;
typedef void ia64_mv_setup_t (char **);
typedef void ia64_mv_cpu_init_t (void);
@@ -79,7 +80,7 @@ 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_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev);
+typedef int ia64_mv_setup_msi_irq_t (struct pci_dev *pdev, struct msi_desc *);
typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq);
static inline void
diff --git a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h
index c8df7590108..6dd476b652c 100644
--- a/include/asm-ia64/meminit.h
+++ b/include/asm-ia64/meminit.h
@@ -51,12 +51,13 @@ extern void efi_memmap_init(unsigned long *, unsigned long *);
#define IGNORE_PFN0 1 /* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */
+extern int register_active_ranges(u64 start, u64 end, void *arg);
+
#ifdef CONFIG_VIRTUAL_MEM_MAP
# define LARGE_GAP 0x40000000 /* Use virtual mem map if hole is > than this */
extern unsigned long vmalloc_end;
extern struct page *vmem_map;
extern int find_largest_hole (u64 start, u64 end, void *arg);
- extern int 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/pci.h b/include/asm-ia64/pci.h
index 825eb7d882e..5160233bbfa 100644
--- a/include/asm-ia64/pci.h
+++ b/include/asm-ia64/pci.h
@@ -78,9 +78,6 @@ pcibios_penalize_isa_irq (int irq, int active)
#define pci_dac_dma_sync_single_for_cpu(dev,dma_addr,len,dir) do { } while (0)
#define pci_dac_dma_sync_single_for_device(dev,dma_addr,len,dir) do { mb(); } while (0)
-#define sg_dma_len(sg) ((sg)->dma_length)
-#define sg_dma_address(sg) ((sg)->dma_address)
-
#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
@@ -170,4 +167,10 @@ pcibios_select_root(struct pci_dev *pdev, struct resource *res)
#define pcibios_scan_all_fns(a, b) 0
+#define HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ
+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+ return channel ? 15 : 14;
+}
+
#endif /* _ASM_IA64_PCI_H */
diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h
index 393e04c42a2..560c287b123 100644
--- a/include/asm-ia64/pgalloc.h
+++ b/include/asm-ia64/pgalloc.h
@@ -137,7 +137,8 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t * pmd_entry, pte_t * pte)
static inline struct page *pte_alloc_one(struct mm_struct *mm,
unsigned long addr)
{
- return virt_to_page(pgtable_quicklist_alloc());
+ void *pg = pgtable_quicklist_alloc();
+ return pg ? virt_to_page(pg) : NULL;
}
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
diff --git a/include/asm-ia64/posix_types.h b/include/asm-ia64/posix_types.h
index adb62272694..17885567b73 100644
--- a/include/asm-ia64/posix_types.h
+++ b/include/asm-ia64/posix_types.h
@@ -54,7 +54,7 @@ typedef unsigned int __kernel_old_dev_t;
#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
#define __FD_ISSET(d, set) (((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) != 0)
#define __FD_ZERO(set) \
- ((void) memset ((__ptr_t) (set), 0, sizeof (__kernel_fd_set)))
+ ((void) memset ((void *) (set), 0, sizeof (__kernel_fd_set)))
# else /* !__GNUC__ */
diff --git a/include/asm-ia64/scatterlist.h b/include/asm-ia64/scatterlist.h
index 834a189ef18..9dbea8844d5 100644
--- a/include/asm-ia64/scatterlist.h
+++ b/include/asm-ia64/scatterlist.h
@@ -25,4 +25,7 @@ struct scatterlist {
*/
#define ISA_DMA_THRESHOLD 0xffffffff
+#define sg_dma_len(sg) ((sg)->dma_length)
+#define sg_dma_address(sg) ((sg)->dma_address)
+
#endif /* _ASM_IA64_SCATTERLIST_H */
diff --git a/include/asm-ia64/sn/acpi.h b/include/asm-ia64/sn/acpi.h
index 2850a7ef5e7..9ce2801cbd5 100644
--- a/include/asm-ia64/sn/acpi.h
+++ b/include/asm-ia64/sn/acpi.h
@@ -11,6 +11,7 @@
#include "acpi/acglobal.h"
-#define SN_ACPI_BASE_SUPPORT() (acpi_gbl_DSDT->oem_revision >= 0x20101)
+extern int sn_acpi_rev;
+#define SN_ACPI_BASE_SUPPORT() (sn_acpi_rev >= 0x20101)
#endif /* _ASM_IA64_SN_ACPI_H */
diff --git a/include/asm-ia64/sn/pcibr_provider.h b/include/asm-ia64/sn/pcibr_provider.h
index da3eade0cae..17cb6cc3f21 100644
--- a/include/asm-ia64/sn/pcibr_provider.h
+++ b/include/asm-ia64/sn/pcibr_provider.h
@@ -142,7 +142,7 @@ extern int pcibr_ate_alloc(struct pcibus_info *, int);
extern void pcibr_ate_free(struct pcibus_info *, int);
extern void ate_write(struct pcibus_info *, int, int, u64);
extern int sal_pcibr_slot_enable(struct pcibus_info *soft, int device,
- void *resp);
+ void *resp, char **ssdt);
extern int sal_pcibr_slot_disable(struct pcibus_info *soft, int device,
int action, void *resp);
extern u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus);
diff --git a/include/asm-ia64/sn/pcidev.h b/include/asm-ia64/sn/pcidev.h
index 9fe89a93d88..1c2382cea80 100644
--- a/include/asm-ia64/sn/pcidev.h
+++ b/include/asm-ia64/sn/pcidev.h
@@ -70,10 +70,16 @@ extern void sn_irq_fixup(struct pci_dev *pci_dev,
struct sn_irq_info *sn_irq_info);
extern void sn_irq_unfixup(struct pci_dev *pci_dev);
extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *);
+extern void sn_bus_fixup(struct pci_bus *);
+extern void sn_acpi_bus_fixup(struct pci_bus *);
+extern void sn_common_bus_fixup(struct pci_bus *, struct pcibus_bussoft *);
extern void sn_bus_store_sysdata(struct pci_dev *dev);
extern void sn_bus_free_sysdata(void);
extern void sn_generate_path(struct pci_bus *pci_bus, char *address);
-extern void sn_pci_fixup_slot(struct pci_dev *dev);
+extern void sn_io_slot_fixup(struct pci_dev *);
+extern void sn_acpi_slot_fixup(struct pci_dev *);
+extern void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *,
+ struct sn_irq_info *);
extern void sn_pci_unfixup_slot(struct pci_dev *dev);
extern void sn_irq_lh_init(void);
#endif /* _ASM_IA64_SN_PCI_PCIDEV_H */
diff --git a/include/asm-ia64/sn/xpc.h b/include/asm-ia64/sn/xpc.h
index 1d45e1518fb..e52b8508083 100644
--- a/include/asm-ia64/sn/xpc.h
+++ b/include/asm-ia64/sn/xpc.h
@@ -673,7 +673,7 @@ 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);
-extern void xpc_create_kthreads(struct xpc_channel *, int);
+extern void xpc_create_kthreads(struct xpc_channel *, int, int);
extern void xpc_disconnect_wait(int);
diff --git a/include/asm-ia64/swiotlb.h b/include/asm-ia64/swiotlb.h
new file mode 100644
index 00000000000..452c162dee4
--- /dev/null
+++ b/include/asm-ia64/swiotlb.h
@@ -0,0 +1,9 @@
+#ifndef _ASM_SWIOTLB_H
+#define _ASM_SWIOTLB_H 1
+
+#include <asm/machvec.h>
+
+#define SWIOTLB_ARCH_NEED_LATE_INIT
+#define SWIOTLB_ARCH_NEED_ALLOC
+
+#endif /* _ASM_SWIOTLB_H */
diff --git a/include/asm-ia64/termbits.h b/include/asm-ia64/termbits.h
index b9e843f7dc4..4531a511bde 100644
--- a/include/asm-ia64/termbits.h
+++ b/include/asm-ia64/termbits.h
@@ -26,6 +26,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h
index 8adcde0934c..91698599f91 100644
--- a/include/asm-ia64/thread_info.h
+++ b/include/asm-ia64/thread_info.h
@@ -84,20 +84,24 @@ struct thread_info {
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
#define TIF_SYSCALL_TRACE 3 /* syscall trace active */
#define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */
+#define TIF_SINGLESTEP 5 /* restore singlestep on return to user mode */
#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 17
#define TIF_MCA_INIT 18 /* this task is processing MCA or INIT */
#define TIF_DB_DISABLED 19 /* debug trap disabled for fsyscall */
+#define TIF_FREEZE 20 /* is freezing for suspend */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
-#define _TIF_SYSCALL_TRACEAUDIT (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
+#define _TIF_SYSCALL_TRACEAUDIT (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_MCA_INIT (1 << TIF_MCA_INIT)
#define _TIF_DB_DISABLED (1 << TIF_DB_DISABLED)
+#define _TIF_FREEZE (1 << TIF_FREEZE)
/* "work to do on user-return" bits */
#define TIF_ALLWORK_MASK (_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h
index a6e38565ab4..22ed6749557 100644
--- a/include/asm-ia64/topology.h
+++ b/include/asm-ia64/topology.h
@@ -101,6 +101,7 @@ void build_cpu_to_node_map(void);
.flags = SD_LOAD_BALANCE \
| SD_BALANCE_EXEC \
| SD_BALANCE_FORK \
+ | SD_SERIALIZE \
| SD_WAKE_BALANCE, \
.last_balance = jiffies, \
.balance_interval = 64, \
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
index 53c5c0ee122..a9e1fa4cac4 100644
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -291,11 +291,13 @@
#define __NR_sync_file_range 1300
#define __NR_tee 1301
#define __NR_vmsplice 1302
+/* 1303 reserved for move_pages */
+#define __NR_getcpu 1304
#ifdef __KERNEL__
-#define NR_syscalls 279 /* length of syscall table */
+#define NR_syscalls 281 /* length of syscall table */
#define __ARCH_WANT_SYS_RT_SIGACTION
diff --git a/include/asm-m32r/cacheflush.h b/include/asm-m32r/cacheflush.h
index 8b261b49149..56961a9511b 100644
--- a/include/asm-m32r/cacheflush.h
+++ b/include/asm-m32r/cacheflush.h
@@ -9,6 +9,7 @@ extern void _flush_cache_copyback_all(void);
#if defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_OPSP) || defined(CONFIG_CHIP_M32104)
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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)
@@ -29,6 +30,7 @@ extern void smp_flush_cache_all(void);
#elif defined(CONFIG_CHIP_M32102)
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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)
@@ -41,6 +43,7 @@ extern void smp_flush_cache_all(void);
#else
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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)
diff --git a/include/asm-m32r/ide.h b/include/asm-m32r/ide.h
index 219a0f74eff..c82ebe8f250 100644
--- a/include/asm-m32r/ide.h
+++ b/include/asm-m32r/ide.h
@@ -32,7 +32,8 @@
static __inline__ int ide_default_irq(unsigned long base)
{
switch (base) {
-#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2)
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) \
+ || defined(CONFIG_PLAT_OPSPUT)
case 0x1f0: return PLD_IRQ_CFIREQ;
default:
return 0;
diff --git a/include/asm-m32r/m32102.h b/include/asm-m32r/m32102.h
index a1f0d1fe9eb..52807f8db16 100644
--- a/include/asm-m32r/m32102.h
+++ b/include/asm-m32r/m32102.h
@@ -104,7 +104,8 @@
#define M32R_MFT5RLD_PORTL (0x0C+M32R_MFT5_OFFSET) /* MFT4 reload */
#define M32R_MFT5CMPRLD_PORTL (0x10+M32R_MFT5_OFFSET) /* MFT4 compare reload */
-#if defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32104)
+#if (defined(CONFIG_CHIP_M32700) && !defined(CONFIG_PLAT_MAPPI2)) \
+ || defined(CONFIG_CHIP_M32104)
#define M32R_MFTCR_MFT0MSK (1UL<<31) /* b0 */
#define M32R_MFTCR_MFT1MSK (1UL<<30) /* b1 */
#define M32R_MFTCR_MFT2MSK (1UL<<29) /* b2 */
@@ -117,7 +118,7 @@
#define M32R_MFTCR_MFT3EN (1UL<<20) /* b11 */
#define M32R_MFTCR_MFT4EN (1UL<<19) /* b12 */
#define M32R_MFTCR_MFT5EN (1UL<<18) /* b13 */
-#else /* not CONFIG_CHIP_M32700 && not CONFIG_CHIP_M32104 */
+#else
#define M32R_MFTCR_MFT0MSK (1UL<<15) /* b16 */
#define M32R_MFTCR_MFT1MSK (1UL<<14) /* b17 */
#define M32R_MFTCR_MFT2MSK (1UL<<13) /* b18 */
@@ -130,7 +131,7 @@
#define M32R_MFTCR_MFT3EN (1UL<<4) /* b27 */
#define M32R_MFTCR_MFT4EN (1UL<<3) /* b28 */
#define M32R_MFTCR_MFT5EN (1UL<<2) /* b29 */
-#endif /* not CONFIG_CHIP_M32700 && not CONFIG_CHIP_M32104 */
+#endif
#define M32R_MFTMOD_CC_MASK (1UL<<15) /* b16 */
#define M32R_MFTMOD_TCCR (1UL<<13) /* b18 */
diff --git a/include/asm-m32r/ptrace.h b/include/asm-m32r/ptrace.h
index 2d2a6c97331..632b4ce4269 100644
--- a/include/asm-m32r/ptrace.h
+++ b/include/asm-m32r/ptrace.h
@@ -33,21 +33,10 @@
#define PT_R15 PT_SP
/* processor status and miscellaneous context registers. */
-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
#define PT_ACC0H 15
#define PT_ACC0L 16
-#define PT_ACC1H 17
-#define PT_ACC1L 18
-#define PT_ACCH PT_ACC0H
-#define PT_ACCL PT_ACC0L
-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
-#define PT_ACCH 15
-#define PT_ACCL 16
-#define PT_DUMMY_ACC1H 17
-#define PT_DUMMY_ACC1L 18
-#else
-#error unknown isa conifiguration
-#endif
+#define PT_ACC1H 17 /* ISA_DSP_LEVEL2 only */
+#define PT_ACC1L 18 /* ISA_DSP_LEVEL2 only */
#define PT_PSW 19
#define PT_BPC 20
#define PT_BBPSW 21
@@ -103,19 +92,10 @@ struct pt_regs {
long syscall_nr;
/* Saved main processor status and miscellaneous context registers. */
-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
unsigned long acc0h;
unsigned long acc0l;
- unsigned long acc1h;
- unsigned long acc1l;
-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
- unsigned long acch;
- unsigned long accl;
- unsigned long dummy_acc1h;
- unsigned long dummy_acc1l;
-#else
-#error unknown isa configuration
-#endif
+ unsigned long acc1h; /* ISA_DSP_LEVEL2 only */
+ unsigned long acc1l; /* ISA_DSP_LEVEL2 only */
unsigned long psw;
unsigned long bpc; /* saved PC for TRAP syscalls */
unsigned long bbpsw;
diff --git a/include/asm-m32r/sigcontext.h b/include/asm-m32r/sigcontext.h
index 73025c0c41a..62537dc4dec 100644
--- a/include/asm-m32r/sigcontext.h
+++ b/include/asm-m32r/sigcontext.h
@@ -23,19 +23,10 @@ struct sigcontext {
unsigned long sc_r12;
/* Saved main processor status and miscellaneous context registers. */
-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
unsigned long sc_acc0h;
unsigned long sc_acc0l;
- unsigned long sc_acc1h;
- unsigned long sc_acc1l;
-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
- unsigned long sc_acch;
- unsigned long sc_accl;
- unsigned long sc_dummy_acc1h;
- unsigned long sc_dummy_acc1l;
-#else
-#error unknown isa configuration
-#endif
+ unsigned long sc_acc1h; /* ISA_DSP_LEVEL2 only */
+ unsigned long sc_acc1l; /* ISA_DSP_LEVEL2 only */
unsigned long sc_psw;
unsigned long sc_bpc; /* saved PC for TRAP syscalls */
unsigned long sc_bbpsw;
diff --git a/include/asm-m32r/termbits.h b/include/asm-m32r/termbits.h
index 5ace3702df7..faf2bd0504c 100644
--- a/include/asm-m32r/termbits.h
+++ b/include/asm-m32r/termbits.h
@@ -19,6 +19,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-m68k/cacheflush.h b/include/asm-m68k/cacheflush.h
index 24d3ff44913..16bf375fdbe 100644
--- a/include/asm-m68k/cacheflush.h
+++ b/include/asm-m68k/cacheflush.h
@@ -89,6 +89,8 @@ static inline void flush_cache_mm(struct mm_struct *mm)
__flush_cache_030();
}
+#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
+
/* flush_cache_range/flush_cache_page must be macros to avoid
a dependency on linux/mm.h, which includes this file... */
static inline void flush_cache_range(struct vm_area_struct *vma,
diff --git a/include/asm-m68k/sun3-head.h b/include/asm-m68k/sun3-head.h
index f799d95bad5..e74f384e269 100644
--- a/include/asm-m68k/sun3-head.h
+++ b/include/asm-m68k/sun3-head.h
@@ -4,7 +4,6 @@
#define KERNBASE 0xE000000 /* First address the kernel will eventually be */
#define LOAD_ADDR 0x4000 /* prom jumps to us here unless this is elf /boot */
-#define BI_START (KERNBASE + 0x3000) /* beginning of the bootinfo records */
#define FC_CONTROL 3
#define FC_SUPERD 5
#define FC_CPU 7
diff --git a/include/asm-m68k/sun3ints.h b/include/asm-m68k/sun3ints.h
index de91fa071b9..309d6e6a137 100644
--- a/include/asm-m68k/sun3ints.h
+++ b/include/asm-m68k/sun3ints.h
@@ -16,6 +16,7 @@
#include <asm/intersil.h>
#include <asm/oplib.h>
#include <asm/traps.h>
+#include <asm/irq.h>
#define SUN3_INT_VECS 192
diff --git a/include/asm-m68k/swim_iop.h b/include/asm-m68k/swim_iop.h
deleted file mode 100644
index f29b67876b0..00000000000
--- a/include/asm-m68k/swim_iop.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * SWIM access through the IOP
- * Written by Joshua M. Thompson
- */
-
-/* IOP number and channel number for the SWIM */
-
-#define SWIM_IOP IOP_NUM_ISM
-#define SWIM_CHAN 1
-
-/* Command code: */
-
-#define CMD_INIT 0x01 /* Initialize */
-#define CMD_SHUTDOWN 0x02 /* Shutdown */
-#define CMD_START_POLL 0x03 /* Start insert/eject polling */
-#define CMD_STOP_POLL 0x04 /* Stop insert/eject polling */
-#define CMD_SETHFSTAG 0x05 /* Set HFS tag buffer address */
-#define CMD_STATUS 0x06 /* Status */
-#define CMD_EJECT 0x07 /* Eject */
-#define CMD_FORMAT 0x08 /* Format */
-#define CMD_FORMAT_VERIFY 0x09 /* Format and Verify */
-#define CMD_WRITE 0x0A /* Write */
-#define CMD_READ 0x0B /* Read */
-#define CMD_READ_VERIFY 0x0C /* Read and Verify */
-#define CMD_CACHE_CTRL 0x0D /* Cache control */
-#define CMD_TAGBUFF_CTRL 0x0E /* Tag buffer control */
-#define CMD_GET_ICON 0x0F /* Get Icon */
-
-/* Drive types: */
-
-/* note: apple sez DRV_FDHD is 4, but I get back a type */
-/* of 5 when I do a drive status check on my FDHD */
-
-#define DRV_NONE 0 /* No drive */
-#define DRV_UNKNOWN 1 /* Unspecified drive */
-#define DRV_400K 2 /* 400K */
-#define DRV_800K 3 /* 400K/800K */
-#define DRV_FDHD 5 /* 400K/800K/720K/1440K */
-#define DRV_HD20 7 /* Apple HD20 */
-
-/* Format types: */
-
-#define FMT_HD20 0x0001 /* Apple HD20 */
-#define FMT_400K 0x0002 /* 400K (GCR) */
-#define FMT_800K 0x0004 /* 800K (GCR) */
-#define FMT_720K 0x0008 /* 720K (MFM) */
-#define FMT_1440K 0x0010 /* 1.44M (MFM) */
-
-#define FMD_KIND_400K 1
-#define FMD_KIND_800K 2
-#define FMD_KIND_720K 3
-#define FMD_KIND_1440K 1
-
-/* Icon Flags: */
-
-#define ICON_MEDIA 0x01 /* Have IOP supply media icon */
-#define ICON_DRIVE 0x01 /* Have IOP supply drive icon */
-
-/* Error codes: */
-
-#define gcrOnMFMErr -400 /* GCR (400/800K) on HD media */
-#define verErr -84 /* verify failed */
-#define fmt2Err -83 /* can't get enough sync during format */
-#define fmt1Err -82 /* can't find sector 0 after track format */
-#define sectNFErr -81 /* can't find sector */
-#define seekErr -80 /* drive error during seek */
-#define spdAdjErr -79 /* can't set drive speed */
-#define twoSideErr -78 /* drive is single-sided */
-#define initIWMErr -77 /* error during initialization */
-#define tk0badErr -76 /* track zero is bad */
-#define cantStepErr -75 /* drive error during step */
-#define wrUnderrun -74 /* write underrun occurred */
-#define badDBtSlp -73 /* bad data bitslip marks */
-#define badDCksum -72 /* bad data checksum */
-#define noDtaMkErr -71 /* can't find data mark */
-#define badBtSlpErr -70 /* bad address bitslip marks */
-#define badCksmErr -69 /* bad address-mark checksum */
-#define dataVerErr -68 /* read-verify failed */
-#define noAdrMkErr -67 /* can't find an address mark */
-#define noNybErr -66 /* no nybbles? disk is probably degaussed */
-#define offLinErr -65 /* no disk in drive */
-#define noDriveErr -64 /* drive isn't connected */
-#define nsDrvErr -56 /* no such drive */
-#define paramErr -50 /* bad positioning information */
-#define wPrErr -44 /* write protected */
-#define openErr -23 /* already initialized */
-
-#ifndef __ASSEMBLY__
-
-struct swim_drvstatus {
- __u16 curr_track; /* Current track number */
- __u8 write_prot; /* 0x80 if disk is write protected */
- __u8 disk_in_drive; /* 0x01 or 0x02 if a disk is in the drive */
- __u8 installed; /* 0x01 if drive installed, 0xFF if not */
- __u8 num_sides; /* 0x80 if two-sided format supported */
- __u8 two_sided; /* 0xff if two-sided format diskette */
- __u8 new_interface; /* 0x00 if old 400K drive, 0xFF if newer */
- __u16 errors; /* Disk error count */
- struct { /* 32 bits */
- __u16 reserved;
- __u16 :4;
- __u16 external:1; /* Drive is external */
- __u16 scsi:1; /* Drive is a SCSI drive */
- __u16 fixed:1; /* Drive has fixed media */
- __u16 secondary:1; /* Drive is secondary drive */
- __u8 type; /* Drive type */
- } info;
- __u8 mfm_drive; /* 0xFF if this is an FDHD drive */
- __u8 mfm_disk; /* 0xFF if 720K/1440K (MFM) disk */
- __u8 mfm_format; /* 0x00 if 720K, 0xFF if 1440K */
- __u8 ctlr_type; /* 0x00 if IWM, 0xFF if SWIM */
- __u16 curr_format; /* Current format type */
- __u16 allowed_fmt; /* Allowed format types */
- __u32 num_blocks; /* Number of blocks on disk */
- __u8 icon_flags; /* Icon flags */
- __u8 unusued;
-};
-
-/* Commands issued from the host to the IOP: */
-
-struct swimcmd_init {
- __u8 code; /* CMD_INIT */
- __u8 unusued;
- __u16 error;
- __u8 drives[28]; /* drive type list */
-};
-
-struct swimcmd_startpoll {
- __u8 code; /* CMD_START_POLL */
- __u8 unusued;
- __u16 error;
-};
-
-struct swimcmd_sethfstag {
- __u8 code; /* CMD_SETHFSTAG */
- __u8 unusued;
- __u16 error;
- caddr_t tagbuf; /* HFS tag buffer address */
-};
-
-struct swimcmd_status {
- __u8 code; /* CMD_STATUS */
- __u8 drive_num;
- __u16 error;
- struct swim_drvstatus status;
-};
-
-struct swimcmd_eject {
- __u8 code; /* CMD_EJECT */
- __u8 drive_num;
- __u16 error;
- struct swim_drvstatus status;
-};
-
-struct swimcmd_format {
- __u8 code; /* CMD_FORMAT */
- __u8 drive_num;
- __u16 error;
- union {
- struct {
- __u16 fmt; /* format kind */
- __u8 hdrbyte; /* fmt byte for hdr (0=default) */
- __u8 interleave; /* interleave (0 = default) */
- caddr_t databuf; /* sector data buff (0=default */
- caddr_t tagbuf; /* tag data buffer (0=default) */
- } f;
- struct swim_drvstatus status;
- } p;
-};
-
-struct swimcmd_fmtverify {
- __u8 code; /* CMD_FORMAT_VERIFY */
- __u8 drive_num;
- __u16 error;
-};
-
-struct swimcmd_rw {
- __u8 code; /* CMD_READ, CMD_WRITE or CMD_READ_VERIFY */
- __u8 drive_num;
- __u16 error;
- caddr_t buffer; /* R/W buffer address */
- __u32 first_block; /* Starting block */
- __u32 num_blocks; /* Number of blocks */
- __u8 tag[12]; /* tag data */
-};
-
-struct swimcmd_cachectl {
- __u8 code; /* CMD_CACHE_CTRL */
- __u8 unused;
- __u16 error;
- __u8 enable; /* Nonzero to enable cache */
- __u8 install; /* +1 = install, -1 = remove, 0 = neither */
-};
-
-struct swimcmd_tagbufctl {
- __u8 code; /* CMD_TAGBUFF_CTRL */
- __u8 unused;
- __u16 error;
- caddr_t buf; /* buffer address or 0 to disable */
-};
-
-struct swimcmd_geticon {
- __u8 code; /* CMD_GET_ICON */
- __u8 drive_num;
- __u16 error;
- caddr_t buffer; /* Nuffer address */
- __u16 kind; /* 0 = media icon, 1 = drive icon */
- __u16 unused;
- __u16 max_bytes; /* maximum byte count */
-};
-
-/* Messages from the SWIM IOP to the host CPU: */
-
-struct swimmsg_status {
- __u8 code; /* 1 = insert, 2 = eject, 3 = status changed */
- __u8 drive_num;
- __u16 error;
- struct swim_drvstatus status;
-};
-
-#endif /* __ASSEMBLY__ */
diff --git a/include/asm-m68k/termbits.h b/include/asm-m68k/termbits.h
index e9eec3eb071..a194092240f 100644
--- a/include/asm-m68k/termbits.h
+++ b/include/asm-m68k/termbits.h
@@ -17,6 +17,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-m68k/uaccess.h b/include/asm-m68k/uaccess.h
index e4c9f080ff2..6a4cf208151 100644
--- a/include/asm-m68k/uaccess.h
+++ b/include/asm-m68k/uaccess.h
@@ -7,6 +7,7 @@
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/types.h>
+#include <linux/sched.h>
#include <asm/segment.h>
#define VERIFY_READ 0
diff --git a/include/asm-m68knommu/bitops.h b/include/asm-m68knommu/bitops.h
index d7fa7d9c0e0..7d6075d9b5c 100644
--- a/include/asm-m68knommu/bitops.h
+++ b/include/asm-m68knommu/bitops.h
@@ -7,7 +7,6 @@
#include <linux/compiler.h>
#include <asm/byteorder.h> /* swab32 */
-#include <asm/system.h> /* save_flags */
#ifdef __KERNEL__
diff --git a/include/asm-m68knommu/cacheflush.h b/include/asm-m68knommu/cacheflush.h
index c3aadf3b0d8..163dcb1a968 100644
--- a/include/asm-m68knommu/cacheflush.h
+++ b/include/asm-m68knommu/cacheflush.h
@@ -8,6 +8,7 @@
#define flush_cache_all() __flush_cache_all()
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) __flush_cache_all()
#define flush_cache_page(vma, vmaddr) do { } while (0)
#define flush_dcache_range(start,len) __flush_cache_all()
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index 1e5ccdad3b0..c7c945baf1e 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -131,6 +131,7 @@
#define MACH_PHILIPS_NINO 0 /* Nino */
#define MACH_PHILIPS_VELO 1 /* Velo */
#define MACH_PHILIPS_JBS 2 /* JBS */
+#define MACH_PHILIPS_STB810 3 /* STB810 */
/*
* Valid machtype for group SIBYTE
@@ -242,6 +243,10 @@ extern struct boot_mem_map boot_mem_map;
extern void add_memory_region(phys_t start, phys_t size, long type);
extern void prom_init(void);
+extern void prom_free_prom_memory(void);
+
+extern void free_init_pages(const char *what,
+ unsigned long begin, unsigned long end);
/*
* Initial kernel command line, usually setup by prom_init()
diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h
index e3c9925876a..0ddada3bb0b 100644
--- a/include/asm-mips/cacheflush.h
+++ b/include/asm-mips/cacheflush.h
@@ -17,6 +17,7 @@
*
* - flush_cache_all() flushes entire cache
* - flush_cache_mm(mm) flushes the specified mm context's cache lines
+ * - flush_cache_dup mm(mm) handles cache flushing when forking
* - flush_cache_page(mm, vmaddr, pfn) flushes a single page
* - flush_cache_range(vma, start, end) flushes a range of pages
* - flush_icache_range(start, end) flush a range of instructions
@@ -31,6 +32,7 @@
extern void (*flush_cache_all)(void);
extern void (*__flush_cache_all)(void);
extern void (*flush_cache_mm)(struct mm_struct *mm);
+#define flush_cache_dup_mm(mm) do { (void) (mm); } while (0)
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 page, unsigned long pfn);
diff --git a/include/asm-mips/checksum.h b/include/asm-mips/checksum.h
index 9b768c3b96b..20a81e1548f 100644
--- a/include/asm-mips/checksum.h
+++ b/include/asm-mips/checksum.h
@@ -29,31 +29,38 @@
*/
__wsum csum_partial(const void *buff, int len, __wsum sum);
+__wsum __csum_partial_copy_user(const void *src, void *dst,
+ int len, __wsum sum, int *err_ptr);
+
/*
* this is a new version of the above that records errors it finds in *errp,
* but continues and zeros the rest of the buffer.
*/
-__wsum csum_partial_copy_from_user(const void __user *src,
- void *dst, int len,
- __wsum sum, int *errp);
+static inline
+__wsum csum_partial_copy_from_user(const void __user *src, void *dst, int len,
+ __wsum sum, int *err_ptr)
+{
+ might_sleep();
+ return __csum_partial_copy_user((__force void *)src, dst,
+ len, sum, err_ptr);
+}
/*
* Copy and checksum to user
*/
#define HAVE_CSUM_COPY_USER
-static inline __wsum csum_and_copy_to_user (const void *src, void __user *dst,
- int len, __wsum sum,
- int *err_ptr)
+static inline
+__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,
+ __wsum sum, int *err_ptr)
{
might_sleep();
- sum = csum_partial(src, len, sum);
-
- if (copy_to_user(dst, src, len)) {
+ if (access_ok(VERIFY_WRITE, dst, len))
+ return __csum_partial_copy_user(src, (__force void *)dst,
+ len, sum, err_ptr);
+ if (len)
*err_ptr = -EFAULT;
- return (__force __wsum)-1;
- }
- return sum;
+ return (__force __wsum)-1; /* invalid checksum */
}
/*
@@ -152,7 +159,8 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr,
#endif
" .set pop"
: "=r" (sum)
- : "0" (daddr), "r"(saddr),
+ : "0" ((__force unsigned long)daddr),
+ "r" ((__force unsigned long)saddr),
#ifdef __MIPSEL__
"r" ((proto + len) << 8),
#else
diff --git a/include/asm-mips/compat.h b/include/asm-mips/compat.h
index 55a0152feb0..432653d7ae0 100644
--- a/include/asm-mips/compat.h
+++ b/include/asm-mips/compat.h
@@ -5,6 +5,7 @@
*/
#include <linux/types.h>
#include <asm/page.h>
+#include <asm/ptrace.h>
#define COMPAT_USER_HZ 100
diff --git a/include/asm-mips/ddb5xxx/ddb5477.h b/include/asm-mips/ddb5xxx/ddb5477.h
index c5af4b73fdd..6cf177caf6d 100644
--- a/include/asm-mips/ddb5xxx/ddb5477.h
+++ b/include/asm-mips/ddb5xxx/ddb5477.h
@@ -17,6 +17,7 @@
#ifndef __ASM_DDB5XXX_DDB5477_H
#define __ASM_DDB5XXX_DDB5477_H
+#include <irq.h>
/*
* This contains macros that are specific to DDB5477 or renamed from
@@ -251,14 +252,10 @@ extern void ll_vrc5477_irq_disable(int vrc5477_irq);
*/
#define NUM_CPU_IRQ 8
-#define NUM_I8259_IRQ 16
#define NUM_VRC5477_IRQ 32
-#define DDB_IRQ_BASE 0
-
-#define I8259_IRQ_BASE DDB_IRQ_BASE
-#define VRC5477_IRQ_BASE (I8259_IRQ_BASE + NUM_I8259_IRQ)
-#define CPU_IRQ_BASE (VRC5477_IRQ_BASE + NUM_VRC5477_IRQ)
+#define CPU_IRQ_BASE MIPS_CPU_IRQ_BASE
+#define VRC5477_IRQ_BASE (CPU_IRQ_BASE + NUM_CPU_IRQ)
/*
* vrc5477 irq defs
@@ -300,22 +297,22 @@ extern void ll_vrc5477_irq_disable(int vrc5477_irq);
/*
* i2859 irq assignment
*/
-#define I8259_IRQ_RESERVED_0 (0 + I8259_IRQ_BASE)
-#define I8259_IRQ_KEYBOARD (1 + I8259_IRQ_BASE) /* M1543 default */
-#define I8259_IRQ_CASCADE (2 + I8259_IRQ_BASE)
-#define I8259_IRQ_UART_B (3 + I8259_IRQ_BASE) /* M1543 default, may conflict with RTC according to schematic diagram */
-#define I8259_IRQ_UART_A (4 + I8259_IRQ_BASE) /* M1543 default */
-#define I8259_IRQ_PARALLEL (5 + I8259_IRQ_BASE) /* M1543 default */
-#define I8259_IRQ_RESERVED_6 (6 + I8259_IRQ_BASE)
-#define I8259_IRQ_RESERVED_7 (7 + I8259_IRQ_BASE)
-#define I8259_IRQ_RTC (8 + I8259_IRQ_BASE) /* who set this? */
-#define I8259_IRQ_USB (9 + I8259_IRQ_BASE) /* ddb_setup */
-#define I8259_IRQ_PMU (10 + I8259_IRQ_BASE) /* ddb_setup */
-#define I8259_IRQ_RESERVED_11 (11 + I8259_IRQ_BASE)
-#define I8259_IRQ_RESERVED_12 (12 + I8259_IRQ_BASE) /* m1543_irq_setup */
-#define I8259_IRQ_RESERVED_13 (13 + I8259_IRQ_BASE)
-#define I8259_IRQ_HDC1 (14 + I8259_IRQ_BASE) /* default and ddb_setup */
-#define I8259_IRQ_HDC2 (15 + I8259_IRQ_BASE) /* default */
+#define I8259_IRQ_RESERVED_0 (0 + I8259A_IRQ_BASE)
+#define I8259_IRQ_KEYBOARD (1 + I8259A_IRQ_BASE) /* M1543 default */
+#define I8259_IRQ_CASCADE (2 + I8259A_IRQ_BASE)
+#define I8259_IRQ_UART_B (3 + I8259A_IRQ_BASE) /* M1543 default, may conflict with RTC according to schematic diagram */
+#define I8259_IRQ_UART_A (4 + I8259A_IRQ_BASE) /* M1543 default */
+#define I8259_IRQ_PARALLEL (5 + I8259A_IRQ_BASE) /* M1543 default */
+#define I8259_IRQ_RESERVED_6 (6 + I8259A_IRQ_BASE)
+#define I8259_IRQ_RESERVED_7 (7 + I8259A_IRQ_BASE)
+#define I8259_IRQ_RTC (8 + I8259A_IRQ_BASE) /* who set this? */
+#define I8259_IRQ_USB (9 + I8259A_IRQ_BASE) /* ddb_setup */
+#define I8259_IRQ_PMU (10 + I8259A_IRQ_BASE) /* ddb_setup */
+#define I8259_IRQ_RESERVED_11 (11 + I8259A_IRQ_BASE)
+#define I8259_IRQ_RESERVED_12 (12 + I8259A_IRQ_BASE) /* m1543_irq_setup */
+#define I8259_IRQ_RESERVED_13 (13 + I8259A_IRQ_BASE)
+#define I8259_IRQ_HDC1 (14 + I8259A_IRQ_BASE) /* default and ddb_setup */
+#define I8259_IRQ_HDC2 (15 + I8259A_IRQ_BASE) /* default */
/*
diff --git a/include/asm-mips/dec/interrupts.h b/include/asm-mips/dec/interrupts.h
index 273e4d65bfe..e10d341067c 100644
--- a/include/asm-mips/dec/interrupts.h
+++ b/include/asm-mips/dec/interrupts.h
@@ -14,6 +14,7 @@
#ifndef __ASM_DEC_INTERRUPTS_H
#define __ASM_DEC_INTERRUPTS_H
+#include <irq.h>
#include <asm/mipsregs.h>
@@ -87,7 +88,7 @@
#define DEC_CPU_INR_SW1 1 /* software #1 */
#define DEC_CPU_INR_SW0 0 /* software #0 */
-#define DEC_CPU_IRQ_BASE 0 /* first IRQ assigned to CPU */
+#define DEC_CPU_IRQ_BASE MIPS_CPU_IRQ_BASE /* first IRQ assigned to CPU */
#define DEC_CPU_IRQ_NR(n) ((n) + DEC_CPU_IRQ_BASE)
#define DEC_CPU_IRQ_MASK(n) (1 << ((n) + CAUSEB_IP))
diff --git a/include/asm-mips/dec/system.h b/include/asm-mips/dec/system.h
index 78af51fbc79..b2afaccd683 100644
--- a/include/asm-mips/dec/system.h
+++ b/include/asm-mips/dec/system.h
@@ -3,7 +3,7 @@
*
* Generic DECstation/DECsystem bits.
*
- * Copyright (C) 2005 Maciej W. Rozycki
+ * Copyright (C) 2005, 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
@@ -14,5 +14,6 @@
#define __ASM_DEC_SYSTEM_H
extern unsigned long dec_kn_slot_base, dec_kn_slot_size;
+extern int dec_tc_bus;
#endif /* __ASM_DEC_SYSTEM_H */
diff --git a/include/asm-mips/dec/tc.h b/include/asm-mips/dec/tc.h
deleted file mode 100644
index 9cb51f24d42..00000000000
--- a/include/asm-mips/dec/tc.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Interface to the TURBOchannel related routines
- *
- * 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) 1998 Harald Koerfgen
- */
-#ifndef __ASM_DEC_TC_H
-#define __ASM_DEC_TC_H
-
-/*
- * Search for a TURBOchannel Option Module
- * with a certain name. Returns slot number
- * of the first card not in use or -ENODEV
- * if none found.
- */
-extern int search_tc_card(const char *);
-/*
- * Marks the card in slot as used
- */
-extern void claim_tc_card(int);
-/*
- * Marks the card in slot as free
- */
-extern void release_tc_card(int);
-/*
- * Return base address of card in slot
- */
-extern unsigned long get_tc_base_addr(int);
-/*
- * Return interrupt number of slot
- */
-extern unsigned long get_tc_irq_nr(int);
-/*
- * Return TURBOchannel clock frequency in Hz
- */
-extern unsigned long get_tc_speed(void);
-
-#endif /* __ASM_DEC_TC_H */
diff --git a/include/asm-mips/dec/tcinfo.h b/include/asm-mips/dec/tcinfo.h
deleted file mode 100644
index cc23509ee77..00000000000
--- a/include/asm-mips/dec/tcinfo.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Various TURBOchannel related stuff
- *
- * 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.
- *
- * Information obtained through the get_tcinfo prom call
- * created from:
- *
- * TURBOchannel Firmware Specification
- *
- * EK-TCAAD-FS-004
- * from Digital Equipment Corporation
- *
- * Copyright (c) 1998 Harald Koerfgen
- */
-
-typedef struct {
- int revision;
- int clk_period;
- int slot_size;
- int io_timeout;
- int dma_range;
- int max_dma_burst;
- int parity;
- int reserved[4];
-} tcinfo;
-
-#define MAX_SLOT 7
-
-typedef struct {
- unsigned long base_addr;
- unsigned char name[9];
- unsigned char vendor[9];
- unsigned char firmware[9];
- int interrupt;
- int flags;
-} slot_info;
-
-/*
- * Values for flags
- */
-#define FREE 1<<0
-#define IN_USE 1<<1
-
-
diff --git a/include/asm-mips/dec/tcmodule.h b/include/asm-mips/dec/tcmodule.h
deleted file mode 100644
index 6268e8915d8..00000000000
--- a/include/asm-mips/dec/tcmodule.h
+++ /dev/null
@@ -1,39 +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.
- *
- * Offsets for the ROM header locations for
- * TURBOchannel cards
- *
- * created from:
- *
- * TURBOchannel Firmware Specification
- *
- * EK-TCAAD-FS-004
- * from Digital Equipment Corporation
- *
- * Jan.1998 Harald Koerfgen
- */
-#ifndef __ASM_DEC_TCMODULE_H
-#define __ASM_DEC_TCMODULE_H
-
-#define OLDCARD 0x3c0000
-#define NEWCARD 0x000000
-
-#define TC_ROM_WIDTH 0x3e0
-#define TC_ROM_STRIDE 0x3e4
-#define TC_ROM_SIZE 0x3e8
-#define TC_SLOT_SIZE 0x3ec
-#define TC_PATTERN0 0x3f0
-#define TC_PATTERN1 0x3f4
-#define TC_PATTERN2 0x3f8
-#define TC_PATTERN3 0x3fc
-#define TC_FIRM_VER 0x400
-#define TC_VENDOR 0x420
-#define TC_MODULE 0x440
-#define TC_FIRM_TYPE 0x460
-#define TC_FLAGS 0x470
-#define TC_ROM_OBJECTS 0x480
-
-#endif /* __ASM_DEC_TCMODULE_H */
diff --git a/include/asm-mips/dma.h b/include/asm-mips/dma.h
index 23f789c8084..e06ef0776d4 100644
--- a/include/asm-mips/dma.h
+++ b/include/asm-mips/dma.h
@@ -91,6 +91,7 @@
#else
#define MAX_DMA_ADDRESS (PAGE_OFFSET + 0x01000000)
#endif
+#define MAX_DMA_PFN PFN_DOWN(virt_to_phys((void *)MAX_DMA_ADDRESS))
/* 8237 DMA controllers */
#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
diff --git a/include/asm-mips/emma2rh/emma2rh.h b/include/asm-mips/emma2rh/emma2rh.h
index 4fb8df71caa..6a1af0af51e 100644
--- a/include/asm-mips/emma2rh/emma2rh.h
+++ b/include/asm-mips/emma2rh/emma2rh.h
@@ -24,6 +24,8 @@
#ifndef __ASM_EMMA2RH_EMMA2RH_H
#define __ASM_EMMA2RH_EMMA2RH_H
+#include <irq.h>
+
/*
* EMMA2RH registers
*/
@@ -104,7 +106,8 @@
#define NUM_EMMA2RH_IRQ 96
#define CPU_EMMA2RH_CASCADE 2
-#define EMMA2RH_IRQ_BASE 0
+#define CPU_IRQ_BASE MIPS_CPU_IRQ_BASE
+#define EMMA2RH_IRQ_BASE (CPU_IRQ_BASE + NUM_CPU_IRQ)
/*
* emma2rh irq defs
diff --git a/include/asm-mips/emma2rh/markeins.h b/include/asm-mips/emma2rh/markeins.h
index 8fa76679507..973b0628490 100644
--- a/include/asm-mips/emma2rh/markeins.h
+++ b/include/asm-mips/emma2rh/markeins.h
@@ -33,7 +33,6 @@
#define EMMA2RH_SW_IRQ_BASE (EMMA2RH_IRQ_BASE + NUM_EMMA2RH_IRQ)
#define EMMA2RH_GPIO_IRQ_BASE (EMMA2RH_SW_IRQ_BASE + NUM_EMMA2RH_IRQ_SW)
-#define CPU_IRQ_BASE (EMMA2RH_GPIO_IRQ_BASE + NUM_EMMA2RH_IRQ_GPIO)
#define EMMA2RH_SW_IRQ_INT0 (0+EMMA2RH_SW_IRQ_BASE)
#define EMMA2RH_SW_IRQ_INT1 (1+EMMA2RH_SW_IRQ_BASE)
diff --git a/include/asm-mips/hazards.h b/include/asm-mips/hazards.h
index 0fe02945feb..50073157a61 100644
--- a/include/asm-mips/hazards.h
+++ b/include/asm-mips/hazards.h
@@ -157,7 +157,7 @@ ASMMACRO(back_to_back_c0_hazard,
* processors.
*/
ASMMACRO(mtc0_tlbw_hazard,
- nop
+ nop; nop
)
ASMMACRO(tlbw_use_hazard,
nop; nop; nop
diff --git a/include/asm-mips/i8259.h b/include/asm-mips/i8259.h
index 4df8d8b118c..e88a01607fe 100644
--- a/include/asm-mips/i8259.h
+++ b/include/asm-mips/i8259.h
@@ -18,6 +18,7 @@
#include <linux/spinlock.h>
#include <asm/io.h>
+#include <irq.h>
/* i8259A PIC registers */
#define PIC_MASTER_CMD 0x20
@@ -42,8 +43,6 @@ extern void disable_8259A_irq(unsigned int irq);
extern void init_i8259_irqs(void);
-#define I8259A_IRQ_BASE 0
-
/*
* Do the traditional i8259 interrupt polling thing. This is for the few
* cases where no better interrupt acknowledge method is available and we
diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h
index d77b657c09c..b6a2eb81662 100644
--- a/include/asm-mips/io.h
+++ b/include/asm-mips/io.h
@@ -115,7 +115,7 @@ static inline void set_io_port_base(unsigned long base)
*/
static inline unsigned long virt_to_phys(volatile const void *address)
{
- return (unsigned long)address - PAGE_OFFSET;
+ return (unsigned long)address - PAGE_OFFSET + PHYS_OFFSET;
}
/*
@@ -132,7 +132,7 @@ static inline unsigned long virt_to_phys(volatile const void *address)
*/
static inline void * phys_to_virt(unsigned long address)
{
- return (void *)(address + PAGE_OFFSET);
+ return (void *)(address + PAGE_OFFSET - PHYS_OFFSET);
}
/*
@@ -556,12 +556,6 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
#define __ISA_IO_base ((char *)(isa_slot_offset))
/*
- * We don't have csum_partial_copy_fromio() yet, so we cheat here and
- * just copy it. The net code will then do the checksum later.
- */
-#define eth_io_copy_and_sum(skb,src,len,unused) memcpy_fromio((skb)->data,(src),(len))
-
-/*
* 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 67657089efa..91803ba30ff 100644
--- a/include/asm-mips/irq.h
+++ b/include/asm-mips/irq.h
@@ -18,7 +18,7 @@
#ifdef CONFIG_I8259
static inline int irq_canonicalize(int irq)
{
- return ((irq == 2) ? 9 : irq);
+ return ((irq == I8259A_IRQ_BASE + 2) ? I8259A_IRQ_BASE + 9 : irq);
}
#else
#define irq_canonicalize(irq) (irq) /* Sane hardware, sane code ... */
@@ -31,14 +31,14 @@ static inline int irq_canonicalize(int irq)
* functions will take over re-enabling the low-level mask.
* Otherwise it will be done on return from exception.
*/
-#define __DO_IRQ_SMTC_HOOK() \
+#define __DO_IRQ_SMTC_HOOK(irq) \
do { \
if (irq_hwmask[irq] & 0x0000ff00) \
write_c0_tccontext(read_c0_tccontext() & \
~(irq_hwmask[irq] & 0x0000ff00)); \
} while (0)
#else
-#define __DO_IRQ_SMTC_HOOK() do { } while (0)
+#define __DO_IRQ_SMTC_HOOK(irq) do { } while (0)
#endif
/*
@@ -52,7 +52,7 @@ do { \
#define do_IRQ(irq) \
do { \
irq_enter(); \
- __DO_IRQ_SMTC_HOOK(); \
+ __DO_IRQ_SMTC_HOOK(irq); \
generic_handle_irq(irq); \
irq_exit(); \
} while (0)
diff --git a/include/asm-mips/irq_cpu.h b/include/asm-mips/irq_cpu.h
index ed3d1e3d09e..ef6a07cddb2 100644
--- a/include/asm-mips/irq_cpu.h
+++ b/include/asm-mips/irq_cpu.h
@@ -13,8 +13,8 @@
#ifndef _ASM_IRQ_CPU_H
#define _ASM_IRQ_CPU_H
-extern void mips_cpu_irq_init(int irq_base);
-extern void rm7k_cpu_irq_init(int irq_base);
-extern void rm9k_cpu_irq_init(int irq_base);
+extern void mips_cpu_irq_init(void);
+extern void rm7k_cpu_irq_init(void);
+extern void rm9k_cpu_irq_init(void);
#endif /* _ASM_IRQ_CPU_H */
diff --git a/include/asm-mips/irqflags.h b/include/asm-mips/irqflags.h
index 46bf5de5ac7..af3b07dfad4 100644
--- a/include/asm-mips/irqflags.h
+++ b/include/asm-mips/irqflags.h
@@ -15,6 +15,27 @@
#include <asm/hazards.h>
+/*
+ * CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY does prompt replay of deferred IPIs,
+ * at the cost of branch and call overhead on each local_irq_restore()
+ */
+
+#ifdef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY
+
+extern void smtc_ipi_replay(void);
+
+#define irq_restore_epilog(flags) \
+do { \
+ if (!(flags & 0x0400)) \
+ smtc_ipi_replay(); \
+} while (0)
+
+#else
+
+#define irq_restore_epilog(ignore) do { } while (0)
+
+#endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */
+
__asm__ (
" .macro raw_local_irq_enable \n"
" .set push \n"
@@ -193,6 +214,7 @@ do { \
: "=r" (__tmp1) \
: "0" (flags) \
: "memory"); \
+ irq_restore_epilog(flags); \
} while(0)
static inline int raw_irqs_disabled_flags(unsigned long flags)
diff --git a/include/asm-mips/mach-au1x00/au1000.h b/include/asm-mips/mach-au1x00/au1000.h
index 582acd8adb8..58fca8a5a9a 100644
--- a/include/asm-mips/mach-au1x00/au1000.h
+++ b/include/asm-mips/mach-au1x00/au1000.h
@@ -39,6 +39,7 @@
#ifndef _LANGUAGE_ASSEMBLY
#include <linux/delay.h>
+#include <linux/types.h>
#include <asm/io.h>
/* cpu pipeline flush */
diff --git a/include/asm-mips/mach-cobalt/cobalt.h b/include/asm-mips/mach-cobalt/cobalt.h
index 00b0fc68d5c..24a8d51a55a 100644
--- a/include/asm-mips/mach-cobalt/cobalt.h
+++ b/include/asm-mips/mach-cobalt/cobalt.h
@@ -12,6 +12,8 @@
#ifndef __ASM_COBALT_H
#define __ASM_COBALT_H
+#include <irq.h>
+
/*
* i8259 legacy interrupts used on Cobalt:
*
@@ -25,7 +27,7 @@
/*
* CPU IRQs are 16 ... 23
*/
-#define COBALT_CPU_IRQ 16
+#define COBALT_CPU_IRQ MIPS_CPU_IRQ_BASE
#define COBALT_GALILEO_IRQ (COBALT_CPU_IRQ + 2)
#define COBALT_SCC_IRQ (COBALT_CPU_IRQ + 3) /* pre-production has 85C30 */
diff --git a/include/asm-mips/mach-emma2rh/irq.h b/include/asm-mips/mach-emma2rh/irq.h
index bce64244b80..5439eb85646 100644
--- a/include/asm-mips/mach-emma2rh/irq.h
+++ b/include/asm-mips/mach-emma2rh/irq.h
@@ -10,4 +10,6 @@
#define NR_IRQS 256
+#include_next <irq.h>
+
#endif /* __ASM_MACH_EMMA2RH_IRQ_H */
diff --git a/include/asm-mips/mach-generic/irq.h b/include/asm-mips/mach-generic/irq.h
index 500e10ff24d..70d9a25132c 100644
--- a/include/asm-mips/mach-generic/irq.h
+++ b/include/asm-mips/mach-generic/irq.h
@@ -8,6 +8,38 @@
#ifndef __ASM_MACH_GENERIC_IRQ_H
#define __ASM_MACH_GENERIC_IRQ_H
+#ifndef NR_IRQS
#define NR_IRQS 128
+#endif
+
+#ifdef CONFIG_I8259
+#ifndef I8259A_IRQ_BASE
+#define I8259A_IRQ_BASE 0
+#endif
+#endif
+
+#ifdef CONFIG_IRQ_CPU
+
+#ifndef MIPS_CPU_IRQ_BASE
+#ifdef CONFIG_I8259
+#define MIPS_CPU_IRQ_BASE 16
+#else
+#define MIPS_CPU_IRQ_BASE 0
+#endif /* CONFIG_I8259 */
+#endif
+
+#ifdef CONFIG_IRQ_CPU_RM7K
+#ifndef RM7K_CPU_IRQ_BASE
+#define RM7K_CPU_IRQ_BASE (MIPS_CPU_IRQ_BASE+8)
+#endif
+#endif
+
+#ifdef CONFIG_IRQ_CPU_RM9K
+#ifndef RM9K_CPU_IRQ_BASE
+#define RM9K_CPU_IRQ_BASE (MIPS_CPU_IRQ_BASE+12)
+#endif
+#endif
+
+#endif /* CONFIG_IRQ_CPU */
#endif /* __ASM_MACH_GENERIC_IRQ_H */
diff --git a/include/asm-mips/mach-ip27/irq.h b/include/asm-mips/mach-ip27/irq.h
index 806213ce31b..25f0c3f39ad 100644
--- a/include/asm-mips/mach-ip27/irq.h
+++ b/include/asm-mips/mach-ip27/irq.h
@@ -10,8 +10,6 @@
#ifndef __ASM_MACH_IP27_IRQ_H
#define __ASM_MACH_IP27_IRQ_H
-#include <asm/sn/arch.h>
-
/*
* A hardwired interrupt number is completly stupid for this system - a
* large configuration might have thousands if not tenthousands of
diff --git a/include/asm-mips/mach-ip27/topology.h b/include/asm-mips/mach-ip27/topology.h
index a13b715fd9c..44790fdc5d0 100644
--- a/include/asm-mips/mach-ip27/topology.h
+++ b/include/asm-mips/mach-ip27/topology.h
@@ -1,7 +1,6 @@
#ifndef _ASM_MACH_TOPOLOGY_H
#define _ASM_MACH_TOPOLOGY_H 1
-#include <asm/sn/arch.h>
#include <asm/sn/hub.h>
#include <asm/mmzone.h>
diff --git a/include/asm-mips/mach-mips/irq.h b/include/asm-mips/mach-mips/irq.h
index e994b0c0122..9b9da26683c 100644
--- a/include/asm-mips/mach-mips/irq.h
+++ b/include/asm-mips/mach-mips/irq.h
@@ -4,4 +4,6 @@
#define NR_IRQS 256
+#include_next <irq.h>
+
#endif /* __ASM_MACH_MIPS_IRQ_H */
diff --git a/include/asm-mips/mach-rm200/cpu-feature-overrides.h b/include/asm-mips/mach-rm/cpu-feature-overrides.h
index 11410ae10d3..11410ae10d3 100644
--- a/include/asm-mips/mach-rm200/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-rm/cpu-feature-overrides.h
diff --git a/include/asm-mips/mach-rm200/mc146818rtc.h b/include/asm-mips/mach-rm/mc146818rtc.h
index d37ae68dc6a..d37ae68dc6a 100644
--- a/include/asm-mips/mach-rm200/mc146818rtc.h
+++ b/include/asm-mips/mach-rm/mc146818rtc.h
diff --git a/include/asm-mips/mach-rm200/timex.h b/include/asm-mips/mach-rm/timex.h
index 11ff6cb0f21..11ff6cb0f21 100644
--- a/include/asm-mips/mach-rm200/timex.h
+++ b/include/asm-mips/mach-rm/timex.h
diff --git a/include/asm-mips/mach-vr41xx/irq.h b/include/asm-mips/mach-vr41xx/irq.h
new file mode 100644
index 00000000000..84881229605
--- /dev/null
+++ b/include/asm-mips/mach-vr41xx/irq.h
@@ -0,0 +1,11 @@
+#ifndef __ASM_MACH_VR41XX_IRQ_H
+#define __ASM_MACH_VR41XX_IRQ_H
+
+#include <asm/vr41xx/irq.h> /* for MIPS_CPU_IRQ_BASE */
+#ifdef CONFIG_NEC_CMBVR4133
+#include <asm/vr41xx/cmbvr4133.h> /* for I8259A_IRQ_BASE */
+#endif
+
+#include_next <irq.h>
+
+#endif /* __ASM_MACH_VR41XX_IRQ_H */
diff --git a/include/asm-mips/mips-boards/atlasint.h b/include/asm-mips/mips-boards/atlasint.h
index b15e4ea0b09..76add42e486 100644
--- a/include/asm-mips/mips-boards/atlasint.h
+++ b/include/asm-mips/mips-boards/atlasint.h
@@ -26,10 +26,12 @@
#ifndef _MIPS_ATLASINT_H
#define _MIPS_ATLASINT_H
+#include <irq.h>
+
/*
* Interrupts 0..7 are used for Atlas CPU interrupts (nonEIC mode)
*/
-#define MIPSCPU_INT_BASE 0
+#define MIPSCPU_INT_BASE MIPS_CPU_IRQ_BASE
/* CPU interrupt offsets */
#define MIPSCPU_INT_SW0 0
diff --git a/include/asm-mips/mips-boards/maltaint.h b/include/asm-mips/mips-boards/maltaint.h
index da6cc2fbbc7..9180d646611 100644
--- a/include/asm-mips/mips-boards/maltaint.h
+++ b/include/asm-mips/mips-boards/maltaint.h
@@ -25,6 +25,8 @@
#ifndef _MIPS_MALTAINT_H
#define _MIPS_MALTAINT_H
+#include <irq.h>
+
/*
* Interrupts 0..15 are used for Malta ISA compatible interrupts
*/
@@ -33,7 +35,7 @@
/*
* Interrupts 16..23 are used for Malta CPU interrupts (nonEIC mode)
*/
-#define MIPSCPU_INT_BASE 16
+#define MIPSCPU_INT_BASE MIPS_CPU_IRQ_BASE
/* CPU interrupt offsets */
#define MIPSCPU_INT_SW0 0
diff --git a/include/asm-mips/mips-boards/prom.h b/include/asm-mips/mips-boards/prom.h
index 4168c7fcd43..7bf6f5f6ab9 100644
--- a/include/asm-mips/mips-boards/prom.h
+++ b/include/asm-mips/mips-boards/prom.h
@@ -33,7 +33,6 @@ extern void prom_printf(char *fmt, ...);
extern void prom_init_cmdline(void);
extern void prom_meminit(void);
extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem);
-extern unsigned long prom_free_prom_memory (void);
extern void mips_display_message(const char *str);
extern void mips_display_word(unsigned int num);
extern int get_ethernet_addr(char *ethernet_addr);
diff --git a/include/asm-mips/mips-boards/seadint.h b/include/asm-mips/mips-boards/seadint.h
index 365c2a3c64f..4f6a3933699 100644
--- a/include/asm-mips/mips-boards/seadint.h
+++ b/include/asm-mips/mips-boards/seadint.h
@@ -20,10 +20,12 @@
#ifndef _MIPS_SEADINT_H
#define _MIPS_SEADINT_H
+#include <irq.h>
+
/*
* Interrupts 0..7 are used for SEAD CPU interrupts
*/
-#define MIPSCPU_INT_BASE 0
+#define MIPSCPU_INT_BASE MIPS_CPU_IRQ_BASE
#define MIPSCPU_INT_UART0 2
#define MIPSCPU_INT_UART1 3
diff --git a/include/asm-mips/mips-boards/simint.h b/include/asm-mips/mips-boards/simint.h
index 4952e0b3bf1..54f2fe621d6 100644
--- a/include/asm-mips/mips-boards/simint.h
+++ b/include/asm-mips/mips-boards/simint.h
@@ -17,10 +17,11 @@
#ifndef _MIPS_SIMINT_H
#define _MIPS_SIMINT_H
+#include <irq.h>
#define SIM_INT_BASE 0
#define MIPSCPU_INT_MB0 2
-#define MIPSCPU_INT_BASE 16
+#define MIPSCPU_INT_BASE MIPS_CPU_IRQ_BASE
#define MIPS_CPU_TIMER_IRQ 7
diff --git a/include/asm-mips/mipsmtregs.h b/include/asm-mips/mipsmtregs.h
index 3e9468f424f..294bca12cd3 100644
--- a/include/asm-mips/mipsmtregs.h
+++ b/include/asm-mips/mipsmtregs.h
@@ -165,8 +165,6 @@
#ifndef __ASSEMBLY__
-extern void mips_mt_regdump(unsigned long previous_mvpcontrol_value);
-
static inline unsigned int dvpe(void)
{
int res = 0;
diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h
index 0dc1a45c27e..d3fbd83ff54 100644
--- a/include/asm-mips/page.h
+++ b/include/asm-mips/page.h
@@ -34,8 +34,21 @@
#ifndef __ASSEMBLY__
+/*
+ * This gives the physical RAM offset.
+ */
+#ifndef PHYS_OFFSET
+#define PHYS_OFFSET 0UL
+#endif
+
+/*
+ * It's normally defined only for FLATMEM config but it's
+ * used in our early mem init code for all memory models.
+ * So always define it.
+ */
+#define ARCH_PFN_OFFSET PFN_UP(PHYS_OFFSET)
+
#include <linux/pfn.h>
-#include <asm/cpu-features.h>
#include <asm/io.h>
extern void clear_page(void * page);
@@ -61,16 +74,13 @@ static inline void clear_user_page(void *addr, unsigned long vaddr,
flush_data_cache_page((unsigned long)addr);
}
-static inline void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
- struct page *to)
-{
- extern void (*flush_data_cache_page)(unsigned long addr);
+extern void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
+ struct page *to);
+struct vm_area_struct;
+extern void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma);
- copy_page(vto, vfrom);
- if (!cpu_has_ic_fills_f_dc ||
- pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
- flush_data_cache_page((unsigned long)vto);
-}
+#define __HAVE_ARCH_COPY_USER_HIGHPAGE
/*
* These are used to make use of C type-checking..
@@ -136,20 +146,23 @@ typedef struct { unsigned long pgprot; } pgprot_t;
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
+/*
+ * __pa()/__va() should be used only during mem init.
+ */
#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
#define __pa_page_offset(x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)
#else
#define __pa_page_offset(x) PAGE_OFFSET
#endif
-#define __pa(x) ((unsigned long)(x) - __pa_page_offset(x))
-#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x),0))
-#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
+#define __pa(x) ((unsigned long)(x) - __pa_page_offset(x) + PHYS_OFFSET)
+#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
+#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x),0))
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
#ifdef CONFIG_FLATMEM
-#define pfn_valid(pfn) ((pfn) < max_mapnr)
+#define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && (pfn) < max_mapnr)
#elif defined(CONFIG_SPARSEMEM)
diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h
index c4d68bebdca..7f0f120ca07 100644
--- a/include/asm-mips/pci.h
+++ b/include/asm-mips/pci.h
@@ -187,4 +187,10 @@ static inline void pcibios_add_platform_entries(struct pci_dev *dev)
/* Do platform specific device initialization at pci_enable_device() time */
extern int pcibios_plat_dev_init(struct pci_dev *dev);
+/* Chances are this interrupt is wired PC-style ... */
+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+ return channel ? 15 : 14;
+}
+
#endif /* _ASM_PCI_H */
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index f2e1325fec6..3fcfd7979de 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -69,16 +69,6 @@ extern unsigned long zero_page_mask;
#define ZERO_PAGE(vaddr) \
(virt_to_page((void *)(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask))))
-#define __HAVE_ARCH_MOVE_PTE
-#define move_pte(pte, prot, old_addr, new_addr) \
-({ \
- pte_t newpte = (pte); \
- if (pte_present(pte) && pfn_valid(pte_pfn(pte)) && \
- pte_page(pte) == ZERO_PAGE(old_addr)) \
- newpte = mk_pte(ZERO_PAGE(new_addr), (prot)); \
- newpte; \
-})
-
extern void paging_init(void);
/*
diff --git a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h
index 30bf555faea..8a1f2b6f04a 100644
--- a/include/asm-mips/ptrace.h
+++ b/include/asm-mips/ptrace.h
@@ -82,6 +82,14 @@ struct pt_regs {
extern asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit);
+extern NORET_TYPE void die(const char *, struct pt_regs *);
+
+static inline void die_if_kernel(const char *str, struct pt_regs *regs)
+{
+ if (unlikely(!user_mode(regs)))
+ die(str, regs);
+}
+
#endif
#endif /* _ASM_PTRACE_H */
diff --git a/include/asm-mips/rtlx.h b/include/asm-mips/rtlx.h
index 76cd51c6be3..59162f74a79 100644
--- a/include/asm-mips/rtlx.h
+++ b/include/asm-mips/rtlx.h
@@ -6,9 +6,10 @@
#ifndef __ASM_RTLX_H
#define __ASM_RTLX_H_
+#include <irq.h>
+
#define LX_NODE_BASE 10
-#define MIPSCPU_INT_BASE 16
#define MIPS_CPU_RTLX_IRQ 0
#define RTLX_VERSION 2
diff --git a/include/asm-mips/sections.h b/include/asm-mips/sections.h
index f7016278b26..b7e37262c24 100644
--- a/include/asm-mips/sections.h
+++ b/include/asm-mips/sections.h
@@ -3,6 +3,4 @@
#include <asm-generic/sections.h>
-extern char _fdata;
-
#endif /* _ASM_SECTIONS_H */
diff --git a/include/asm-mips/sgi/ip22.h b/include/asm-mips/sgi/ip22.h
index bbfc05c3cab..6592f3bd199 100644
--- a/include/asm-mips/sgi/ip22.h
+++ b/include/asm-mips/sgi/ip22.h
@@ -21,15 +21,16 @@
* HAL2 driver). This will prevent many complications, trust me ;-)
*/
+#include <irq.h>
#include <asm/sgi/ioc.h>
#define SGINT_EISA 0 /* 16 EISA irq levels (Indigo2) */
-#define SGINT_CPU 16 /* MIPS CPU define 8 interrupt sources */
-#define SGINT_LOCAL0 24 /* 8 local0 irq levels */
-#define SGINT_LOCAL1 32 /* 8 local1 irq levels */
-#define SGINT_LOCAL2 40 /* 8 local2 vectored irq levels */
-#define SGINT_LOCAL3 48 /* 8 local3 vectored irq levels */
-#define SGINT_END 56 /* End of 'spaces' */
+#define SGINT_CPU MIPS_CPU_IRQ_BASE /* MIPS CPU define 8 interrupt sources */
+#define SGINT_LOCAL0 (SGINT_CPU+8) /* 8 local0 irq levels */
+#define SGINT_LOCAL1 (SGINT_CPU+16) /* 8 local1 irq levels */
+#define SGINT_LOCAL2 (SGINT_CPU+24) /* 8 local2 vectored irq levels */
+#define SGINT_LOCAL3 (SGINT_CPU+32) /* 8 local3 vectored irq levels */
+#define SGINT_END (SGINT_CPU+40) /* End of 'spaces' */
/*
* Individual interrupt definitions for the Indy and Indigo2
diff --git a/include/asm-mips/smtc_ipi.h b/include/asm-mips/smtc_ipi.h
index f22c3e2f993..55f3419f654 100644
--- a/include/asm-mips/smtc_ipi.h
+++ b/include/asm-mips/smtc_ipi.h
@@ -44,9 +44,6 @@ struct smtc_ipi_q {
int depth;
};
-extern struct smtc_ipi_q IPIQ[NR_CPUS];
-extern struct smtc_ipi_q freeIPIq;
-
static inline void smtc_ipi_nq(struct smtc_ipi_q *q, struct smtc_ipi *p)
{
long flags;
diff --git a/include/asm-mips/sn/arch.h b/include/asm-mips/sn/arch.h
index 51174af6ac5..da523de628b 100644
--- a/include/asm-mips/sn/arch.h
+++ b/include/asm-mips/sn/arch.h
@@ -18,7 +18,6 @@
#endif
typedef u64 hubreg_t;
-typedef u64 nic_t;
#define cputonasid(cpu) (cpu_data[(cpu)].p_nasid)
#define cputoslice(cpu) (cpu_data[(cpu)].p_slice)
diff --git a/include/asm-mips/sn/klconfig.h b/include/asm-mips/sn/klconfig.h
index 15d70ca5618..82aeb9e322d 100644
--- a/include/asm-mips/sn/klconfig.h
+++ b/include/asm-mips/sn/klconfig.h
@@ -61,6 +61,8 @@
#endif /* CONFIG_SGI_IP35 */
#endif /* CONFIG_SGI_IP27 || CONFIG_SGI_IP35 */
+typedef u64 nic_t;
+
#define KLCFGINFO_MAGIC 0xbeedbabe
typedef s32 klconf_off_t;
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 9428057a50c..5e1289c85ed 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -19,7 +19,6 @@
#include <asm/barrier.h>
#include <asm/cpu-features.h>
#include <asm/dsp.h>
-#include <asm/ptrace.h>
#include <asm/war.h>
@@ -336,14 +335,6 @@ extern void *set_except_vector(int n, void *addr);
extern unsigned long ebase;
extern void per_cpu_trap_init(void);
-extern NORET_TYPE void die(const char *, struct pt_regs *);
-
-static inline void die_if_kernel(const char *str, struct pt_regs *regs)
-{
- if (unlikely(!user_mode(regs)))
- die(str, regs);
-}
-
extern int stop_a_enabled;
/*
diff --git a/include/asm-mips/termbits.h b/include/asm-mips/termbits.h
index b62ec7c521c..0bbe07b42a0 100644
--- a/include/asm-mips/termbits.h
+++ b/include/asm-mips/termbits.h
@@ -30,6 +30,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0 /* Interrupt character [ISIG]. */
#define VQUIT 1 /* Quit character [ISIG]. */
diff --git a/include/asm-mips/thread_info.h b/include/asm-mips/thread_info.h
index e475c45ea26..fbcda820447 100644
--- a/include/asm-mips/thread_info.h
+++ b/include/asm-mips/thread_info.h
@@ -118,6 +118,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
#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_FREEZE 19
#define TIF_SYSCALL_TRACE 31 /* syscall trace active */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -129,6 +130,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+#define _TIF_FREEZE (1<<TIF_FREEZE)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK (0x0000ffef & ~_TIF_SECCOMP)
diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h
index 1cdd4eeb2f7..c12ebc53ef3 100644
--- a/include/asm-mips/uaccess.h
+++ b/include/asm-mips/uaccess.h
@@ -488,7 +488,8 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n);
})
/*
- * __copy_from_user: - Copy a block of data from user space, with less checking. * @to: Destination address, in kernel space.
+ * __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.
*
diff --git a/include/asm-mips/vr41xx/cmbvr4133.h b/include/asm-mips/vr41xx/cmbvr4133.h
index 9490ade58b4..42300037d59 100644
--- a/include/asm-mips/vr41xx/cmbvr4133.h
+++ b/include/asm-mips/vr41xx/cmbvr4133.h
@@ -35,8 +35,8 @@
#define CMBVR41XX_INTD_IRQ GIU_IRQ(CMBVR41XX_INTD_PIN)
#define CMBVR41XX_INTE_IRQ GIU_IRQ(CMBVR41XX_INTE_PIN)
-#define I8259_IRQ_BASE 72
-#define I8259_IRQ(x) (I8259_IRQ_BASE + (x))
+#define I8259A_IRQ_BASE 72
+#define I8259_IRQ(x) (I8259A_IRQ_BASE + (x))
#define TIMER_IRQ I8259_IRQ(0)
#define KEYBOARD_IRQ I8259_IRQ(1)
#define I8259_SLAVE_IRQ I8259_IRQ(2)
@@ -52,6 +52,5 @@
#define AUX_IRQ I8259_IRQ(12)
#define IDE_PRIMARY_IRQ I8259_IRQ(14)
#define IDE_SECONDARY_IRQ I8259_IRQ(15)
-#define I8259_IRQ_LAST IDE_SECONDARY_IRQ
#endif /* __NEC_CMBVR4133_H */
diff --git a/include/asm-mips/war.h b/include/asm-mips/war.h
index 3ac146c019c..13a3502eef4 100644
--- a/include/asm-mips/war.h
+++ b/include/asm-mips/war.h
@@ -76,7 +76,7 @@
/*
* But the RM200C seems to have been shipped only with V2.0 R4600s
*/
-#ifdef CONFIG_SNI_RM200_PCI
+#ifdef CONFIG_SNI_RM
#define R4600_V2_HIT_CACHEOP_WAR 1
diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h
index 2bc41f2e027..a799dd8ef39 100644
--- a/include/asm-parisc/cacheflush.h
+++ b/include/asm-parisc/cacheflush.h
@@ -15,6 +15,8 @@
#define flush_cache_mm(mm) flush_cache_all_local()
#endif
+#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
+
#define flush_kernel_dcache_range(start,size) \
flush_kernel_dcache_range_asm((start), (start)+(size));
@@ -184,7 +186,7 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
}
static inline void
-flush_anon_page(struct page *page, unsigned long vmaddr)
+flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
{
if (PageAnon(page))
flush_user_dcache_page(vmaddr);
diff --git a/include/asm-parisc/io.h b/include/asm-parisc/io.h
index c1963ce19dd..ca46e7cc094 100644
--- a/include/asm-parisc/io.h
+++ b/include/asm-parisc/io.h
@@ -191,15 +191,6 @@ void memset_io(volatile void __iomem *addr, unsigned char val, int count);
void memcpy_fromio(void *dst, const volatile void __iomem *src, int count);
void memcpy_toio(volatile void __iomem *dst, const void *src, int count);
-/*
- * XXX - We don't have csum_partial_copy_fromio() yet, so we cheat here and
- * just copy it. The net code will then do the checksum later. Presently
- * only used by some shared memory 8390 Ethernet cards anyway.
- */
-
-#define eth_io_copy_and_sum(skb,src,len,unused) \
- memcpy_fromio((skb)->data,(src),(len))
-
/* Port-space IO */
#define inb_p inb
diff --git a/include/asm-parisc/termbits.h b/include/asm-parisc/termbits.h
index 372b634892c..a46e299a939 100644
--- a/include/asm-parisc/termbits.h
+++ b/include/asm-parisc/termbits.h
@@ -17,6 +17,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-powerpc/Kbuild b/include/asm-powerpc/Kbuild
index 1e637381c11..703970fb0ec 100644
--- a/include/asm-powerpc/Kbuild
+++ b/include/asm-powerpc/Kbuild
@@ -17,7 +17,6 @@ header-y += ipc.h
header-y += poll.h
header-y += shmparam.h
header-y += sockios.h
-header-y += spu_info.h
header-y += ucontext.h
header-y += ioctl.h
header-y += linkage.h
@@ -37,6 +36,7 @@ unifdef-y += posix_types.h
unifdef-y += ptrace.h
unifdef-y += seccomp.h
unifdef-y += signal.h
+unifdef-y += spu_info.h
unifdef-y += termios.h
unifdef-y += types.h
unifdef-y += unistd.h
diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h
index 53283e2540b..f038e33e6d4 100644
--- a/include/asm-powerpc/atomic.h
+++ b/include/asm-powerpc/atomic.h
@@ -207,7 +207,8 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
/*
* Atomically test *v and decrement if it is greater than 0.
- * The function returns the old value of *v minus 1.
+ * The function returns the old value of *v minus 1, even if
+ * the atomic variable, v, was not decremented.
*/
static __inline__ int atomic_dec_if_positive(atomic_t *v)
{
@@ -216,14 +217,15 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v)
__asm__ __volatile__(
LWSYNC_ON_SMP
"1: lwarx %0,0,%1 # atomic_dec_if_positive\n\
- addic. %0,%0,-1\n\
+ cmpwi %0,1\n\
+ addi %0,%0,-1\n\
blt- 2f\n"
PPC405_ERR77(0,%1)
" stwcx. %0,0,%1\n\
bne- 1b"
ISYNC_ON_SMP
"\n\
-2:" : "=&r" (t)
+2:" : "=&b" (t)
: "r" (&v->counter)
: "cc", "memory");
diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h
index c341063d080..8f757f6246e 100644
--- a/include/asm-powerpc/bitops.h
+++ b/include/asm-powerpc/bitops.h
@@ -190,7 +190,8 @@ static __inline__ void set_bits(unsigned long mask, unsigned long *addr)
* Return the zero-based bit position (LE, not IBM bit numbering) of
* the most significant 1-bit in a double word.
*/
-static __inline__ int __ilog2(unsigned long x)
+static __inline__ __attribute__((const))
+int __ilog2(unsigned long x)
{
int lz;
@@ -198,6 +199,24 @@ static __inline__ int __ilog2(unsigned long x)
return BITS_PER_LONG - 1 - lz;
}
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+ int bit;
+ asm ("cntlzw %0,%1" : "=r" (bit) : "r" (n));
+ return 31 - bit;
+}
+
+#ifdef __powerpc64__
+static inline __attribute__((const))
+int __ilog2_u64(u64 n)
+{
+ int bit;
+ asm ("cntlzd %0,%1" : "=r" (bit) : "r" (n));
+ return 63 - bit;
+}
+#endif
+
/*
* Determines the bit position of the least significant 0 bit in the
* specified double word. The returned bit position will be
diff --git a/include/asm-powerpc/bug.h b/include/asm-powerpc/bug.h
index 978b2c7e84e..f6fa3947484 100644
--- a/include/asm-powerpc/bug.h
+++ b/include/asm-powerpc/bug.h
@@ -11,24 +11,48 @@
#define BUG_OPCODE .long 0x00b00b00 /* For asm */
#define BUG_ILLEGAL_INSTR "0x00b00b00" /* For BUG macro */
-#ifndef __ASSEMBLY__
-
-struct bug_entry {
- unsigned long bug_addr;
- long line;
- const char *file;
- const char *function;
-};
-
-struct bug_entry *find_bug(unsigned long bugaddr);
+#ifdef CONFIG_BUG
-/*
- * If this bit is set in the line number it means that the trap
- * is for WARN_ON rather than BUG or BUG_ON.
- */
-#define BUG_WARNING_TRAP 0x1000000
+#ifdef __ASSEMBLY__
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+.macro EMIT_BUG_ENTRY addr,file,line,flags
+ .section __bug_table,"a"
+5001: PPC_LONG \addr, 5002f
+ .short \line, \flags
+ .org 5001b+BUG_ENTRY_SIZE
+ .previous
+ .section .rodata,"a"
+5002: .asciz "\file"
+ .previous
+.endm
+#else
+ .macro EMIT_BUG_ENTRY addr,file,line,flags
+ .section __bug_table,"a"
+5001: PPC_LONG \addr
+ .short \flags
+ .org 5001b+BUG_ENTRY_SIZE
+ .previous
+.endm
+#endif /* verbose */
-#ifdef CONFIG_BUG
+#else /* !__ASSEMBLY__ */
+/* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and
+ sizeof(struct bug_entry), respectively */
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define _EMIT_BUG_ENTRY \
+ ".section __bug_table,\"a\"\n" \
+ "2:\t" PPC_LONG "1b, %0\n" \
+ "\t.short %1, %2\n" \
+ ".org 2b+%3\n" \
+ ".previous\n"
+#else
+#define _EMIT_BUG_ENTRY \
+ ".section __bug_table,\"a\"\n" \
+ "2:\t" PPC_LONG "1b\n" \
+ "\t.short %2\n" \
+ ".org 2b+%3\n" \
+ ".previous\n"
+#endif
/*
* BUG_ON() and WARN_ON() do their best to cooperate with compile-time
@@ -36,13 +60,13 @@ struct bug_entry *find_bug(unsigned long bugaddr);
* some compiler versions may not produce optimal results.
*/
-#define BUG() do { \
- __asm__ __volatile__( \
- "1: twi 31,0,0\n" \
- ".section __bug_table,\"a\"\n" \
- "\t"PPC_LONG" 1b,%0,%1,%2\n" \
- ".previous" \
- : : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \
+#define BUG() do { \
+ __asm__ __volatile__( \
+ "1: twi 31,0,0\n" \
+ _EMIT_BUG_ENTRY \
+ : : "i" (__FILE__), "i" (__LINE__), \
+ "i" (0), "i" (sizeof(struct bug_entry))); \
+ for(;;) ; \
} while (0)
#define BUG_ON(x) do { \
@@ -51,23 +75,21 @@ struct bug_entry *find_bug(unsigned long bugaddr);
BUG(); \
} else { \
__asm__ __volatile__( \
- "1: "PPC_TLNEI" %0,0\n" \
- ".section __bug_table,\"a\"\n" \
- "\t"PPC_LONG" 1b,%1,%2,%3\n" \
- ".previous" \
- : : "r" ((long)(x)), "i" (__LINE__), \
- "i" (__FILE__), "i" (__FUNCTION__)); \
+ "1: "PPC_TLNEI" %4,0\n" \
+ _EMIT_BUG_ENTRY \
+ : : "i" (__FILE__), "i" (__LINE__), "i" (0), \
+ "i" (sizeof(struct bug_entry)), \
+ "r" ((long)(x))); \
} \
} while (0)
#define __WARN() do { \
__asm__ __volatile__( \
"1: twi 31,0,0\n" \
- ".section __bug_table,\"a\"\n" \
- "\t"PPC_LONG" 1b,%0,%1,%2\n" \
- ".previous" \
- : : "i" (__LINE__ + BUG_WARNING_TRAP), \
- "i" (__FILE__), "i" (__FUNCTION__)); \
+ _EMIT_BUG_ENTRY \
+ : : "i" (__FILE__), "i" (__LINE__), \
+ "i" (BUGFLAG_WARNING), \
+ "i" (sizeof(struct bug_entry))); \
} while (0)
#define WARN_ON(x) ({ \
@@ -77,13 +99,12 @@ struct bug_entry *find_bug(unsigned long bugaddr);
__WARN(); \
} else { \
__asm__ __volatile__( \
- "1: "PPC_TLNEI" %0,0\n" \
- ".section __bug_table,\"a\"\n" \
- "\t"PPC_LONG" 1b,%1,%2,%3\n" \
- ".previous" \
- : : "r" (__ret_warn_on), \
- "i" (__LINE__ + BUG_WARNING_TRAP), \
- "i" (__FILE__), "i" (__FUNCTION__)); \
+ "1: "PPC_TLNEI" %4,0\n" \
+ _EMIT_BUG_ENTRY \
+ : : "i" (__FILE__), "i" (__LINE__), \
+ "i" (BUGFLAG_WARNING), \
+ "i" (sizeof(struct bug_entry)), \
+ "r" (__ret_warn_on)); \
} \
unlikely(__ret_warn_on); \
})
@@ -91,8 +112,8 @@ struct bug_entry *find_bug(unsigned long bugaddr);
#define HAVE_ARCH_BUG
#define HAVE_ARCH_BUG_ON
#define HAVE_ARCH_WARN_ON
-#endif /* CONFIG_BUG */
#endif /* __ASSEMBLY __ */
+#endif /* CONFIG_BUG */
#include <asm-generic/bug.h>
diff --git a/include/asm-powerpc/cacheflush.h b/include/asm-powerpc/cacheflush.h
index 8a740c88d93..08e93e78921 100644
--- a/include/asm-powerpc/cacheflush.h
+++ b/include/asm-powerpc/cacheflush.h
@@ -18,6 +18,7 @@
*/
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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_icache_page(vma, page) do { } while (0)
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index 6fe5c9d4ca3..e870b539317 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -50,6 +50,12 @@ enum powerpc_oprofile_type {
PPC_OPROFILE_CELL = 5,
};
+enum powerpc_pmc_type {
+ PPC_PMC_DEFAULT = 0,
+ PPC_PMC_IBM = 1,
+ PPC_PMC_PA6T = 2,
+};
+
struct cpu_spec {
/* CPU is matched via (PVR & pvr_mask) == pvr_value */
unsigned int pvr_mask;
@@ -65,6 +71,7 @@ struct cpu_spec {
/* number of performance monitor counters */
unsigned int num_pmcs;
+ enum powerpc_pmc_type pmc_type;
/* this is called to initialize various CPU bits like L1 cache,
* BHT, SPD, etc... from head.S before branching to identify_machine
@@ -126,6 +133,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
#define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000000000100000)
#define CPU_FTR_PPC_LE ASM_CONST(0x0000000000200000)
#define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000)
+#define CPU_FTR_FPU_UNAVAILABLE ASM_CONST(0x0000000000800000)
/*
* Add the 64-bit processor unique features in the top half of the word;
@@ -152,6 +160,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
#define CPU_FTR_PURR LONG_ASM_CONST(0x0000400000000000)
#define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000800000000000)
#define CPU_FTR_SPURR LONG_ASM_CONST(0x0001000000000000)
+#define CPU_FTR_DSCR LONG_ASM_CONST(0x0002000000000000)
#ifndef __ASSEMBLY__
@@ -295,6 +304,9 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
#define CPU_FTRS_E300 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
CPU_FTR_COMMON)
+#define CPU_FTRS_E300C2 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
+ CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
+ CPU_FTR_COMMON | CPU_FTR_FPU_UNAVAILABLE)
#define CPU_FTRS_CLASSIC32 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE)
#define CPU_FTRS_8XX (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB)
@@ -330,13 +342,8 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
- CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE)
-#define CPU_FTRS_POWER6X (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
- CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
- CPU_FTR_MMCRA | CPU_FTR_SMT | \
- CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
- CPU_FTR_PURR | CPU_FTR_CI_LARGE_PAGE | \
- CPU_FTR_SPURR | CPU_FTR_REAL_LE)
+ CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
+ CPU_FTR_DSCR)
#define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -364,7 +371,8 @@ enum {
CPU_FTRS_7450_21 | CPU_FTRS_7450_23 | CPU_FTRS_7455_1 |
CPU_FTRS_7455_20 | CPU_FTRS_7455 | CPU_FTRS_7447_10 |
CPU_FTRS_7447 | CPU_FTRS_7447A | CPU_FTRS_82XX |
- CPU_FTRS_G2_LE | CPU_FTRS_E300 | CPU_FTRS_CLASSIC32 |
+ CPU_FTRS_G2_LE | CPU_FTRS_E300 | CPU_FTRS_E300C2 |
+ CPU_FTRS_CLASSIC32 |
#else
CPU_FTRS_GENERIC_32 |
#endif
@@ -403,7 +411,8 @@ enum {
CPU_FTRS_7450_21 & CPU_FTRS_7450_23 & CPU_FTRS_7455_1 &
CPU_FTRS_7455_20 & CPU_FTRS_7455 & CPU_FTRS_7447_10 &
CPU_FTRS_7447 & CPU_FTRS_7447A & CPU_FTRS_82XX &
- CPU_FTRS_G2_LE & CPU_FTRS_E300 & CPU_FTRS_CLASSIC32 &
+ CPU_FTRS_G2_LE & CPU_FTRS_E300 & CPU_FTRS_E300C2 &
+ CPU_FTRS_CLASSIC32 &
#else
CPU_FTRS_GENERIC_32 &
#endif
diff --git a/include/asm-powerpc/dcr-native.h b/include/asm-powerpc/dcr-native.h
index fd4a5f5e33d..d7a1bc1551c 100644
--- a/include/asm-powerpc/dcr-native.h
+++ b/include/asm-powerpc/dcr-native.h
@@ -20,8 +20,7 @@
#ifndef _ASM_POWERPC_DCR_NATIVE_H
#define _ASM_POWERPC_DCR_NATIVE_H
#ifdef __KERNEL__
-
-#include <asm/reg.h>
+#ifndef __ASSEMBLY__
typedef struct {} dcr_host_t;
@@ -32,7 +31,41 @@ typedef struct {} dcr_host_t;
#define dcr_read(host, dcr_n) mfdcr(dcr_n)
#define dcr_write(host, dcr_n, value) mtdcr(dcr_n, value)
+/* Device Control Registers */
+void __mtdcr(int reg, unsigned int val);
+unsigned int __mfdcr(int reg);
+#define mfdcr(rn) \
+ ({unsigned int rval; \
+ if (__builtin_constant_p(rn)) \
+ asm volatile("mfdcr %0," __stringify(rn) \
+ : "=r" (rval)); \
+ else \
+ rval = __mfdcr(rn); \
+ rval;})
+
+#define mtdcr(rn, v) \
+do { \
+ if (__builtin_constant_p(rn)) \
+ asm volatile("mtdcr " __stringify(rn) ",%0" \
+ : : "r" (v)); \
+ else \
+ __mtdcr(rn, v); \
+} while (0)
+
+/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
+#define mfdcri(base, reg) \
+({ \
+ mtdcr(base ## _CFGADDR, base ## _ ## reg); \
+ mfdcr(base ## _CFGDATA); \
+})
+
+#define mtdcri(base, reg, data) \
+do { \
+ mtdcr(base ## _CFGADDR, base ## _ ## reg); \
+ mtdcr(base ## _CFGDATA, data); \
+} while (0)
+#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_DCR_NATIVE_H */
diff --git a/include/asm-powerpc/dcr.h b/include/asm-powerpc/dcr.h
index 473f2c7fd89..9338d50538f 100644
--- a/include/asm-powerpc/dcr.h
+++ b/include/asm-powerpc/dcr.h
@@ -20,6 +20,7 @@
#ifndef _ASM_POWERPC_DCR_H
#define _ASM_POWERPC_DCR_H
#ifdef __KERNEL__
+#ifdef CONFIG_PPC_DCR
#ifdef CONFIG_PPC_DCR_NATIVE
#include <asm/dcr-native.h>
@@ -32,11 +33,13 @@
* base from the device-tree
*/
#ifdef CONFIG_PPC_MERGE
+struct device_node;
extern unsigned int dcr_resource_start(struct device_node *np,
unsigned int index);
extern unsigned int dcr_resource_len(struct device_node *np,
unsigned int index);
#endif /* CONFIG_PPC_MERGE */
+#endif /* CONFIG_PPC_DCR */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_DCR_H */
diff --git a/include/asm-powerpc/dma-mapping.h b/include/asm-powerpc/dma-mapping.h
index 7c7de87bd8a..a19a6f1a1cf 100644
--- a/include/asm-powerpc/dma-mapping.h
+++ b/include/asm-powerpc/dma-mapping.h
@@ -37,9 +37,9 @@ extern void __dma_sync_page(struct page *page, unsigned long offset,
*/
#define __dma_alloc_coherent(gfp, size, handle) NULL
-#define __dma_free_coherent(size, addr) do { } while (0)
-#define __dma_sync(addr, size, rw) do { } while (0)
-#define __dma_sync_page(pg, off, sz, rw) do { } while (0)
+#define __dma_free_coherent(size, addr) ((void)0)
+#define __dma_sync(addr, size, rw) ((void)0)
+#define __dma_sync_page(pg, off, sz, rw) ((void)0)
#endif /* ! CONFIG_NOT_COHERENT_CACHE */
@@ -251,7 +251,7 @@ dma_map_single(struct device *dev, void *ptr, size_t size,
}
/* We do nothing. */
-#define dma_unmap_single(dev, addr, size, dir) do { } while (0)
+#define dma_unmap_single(dev, addr, size, dir) ((void)0)
static inline dma_addr_t
dma_map_page(struct device *dev, struct page *page,
@@ -266,7 +266,7 @@ dma_map_page(struct device *dev, struct page *page,
}
/* We do nothing. */
-#define dma_unmap_page(dev, handle, size, dir) do { } while (0)
+#define dma_unmap_page(dev, handle, size, dir) ((void)0)
static inline int
dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
@@ -286,7 +286,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
}
/* We don't do anything here. */
-#define dma_unmap_sg(dev, sg, nents, dir) do { } while (0)
+#define dma_unmap_sg(dev, sg, nents, dir) ((void)0)
#endif /* CONFIG_PPC64 */
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index d36426c01b6..de507995c7b 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -173,7 +173,7 @@ typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32];
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */
-#define ELF_ET_DYN_BASE (0x08000000)
+#define ELF_ET_DYN_BASE (0x20000000)
/* Common routine for both 32-bit and 64-bit processes */
static inline void ppc_elf_core_copy_regs(elf_gregset_t elf_regs,
diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h
index 98f7b62422c..3671c128f27 100644
--- a/include/asm-powerpc/firmware.h
+++ b/include/asm-powerpc/firmware.h
@@ -43,6 +43,8 @@
#define FW_FEATURE_ISERIES ASM_CONST(0x0000000000200000)
#define FW_FEATURE_LPAR ASM_CONST(0x0000000000400000)
#define FW_FEATURE_PS3_LV1 ASM_CONST(0x0000000000800000)
+#define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000)
+#define FW_FEATURE_BULK_REMOVE ASM_CONST(0x0000000002000000)
#ifndef __ASSEMBLY__
@@ -61,6 +63,8 @@ enum {
FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
FW_FEATURE_PS3_ALWAYS = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
+ FW_FEATURE_CELLEB_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_BEAT,
+ FW_FEATURE_CELLEB_ALWAYS = FW_FEATURE_LPAR | FW_FEATURE_BEAT,
FW_FEATURE_NATIVE_POSSIBLE = 0,
FW_FEATURE_NATIVE_ALWAYS = 0,
FW_FEATURE_POSSIBLE =
@@ -73,6 +77,9 @@ enum {
#ifdef CONFIG_PPC_PS3
FW_FEATURE_PS3_POSSIBLE |
#endif
+#ifdef CONFIG_PPC_CELLEB
+ FW_FEATURE_CELLEB_POSSIBLE |
+#endif
#ifdef CONFIG_PPC_NATIVE
FW_FEATURE_NATIVE_ALWAYS |
#endif
@@ -87,6 +94,9 @@ enum {
#ifdef CONFIG_PPC_PS3
FW_FEATURE_PS3_ALWAYS &
#endif
+#ifdef CONFIG_PPC_CELLEB
+ FW_FEATURE_CELLEB_ALWAYS &
+#endif
#ifdef CONFIG_PPC_NATIVE
FW_FEATURE_NATIVE_ALWAYS &
#endif
diff --git a/include/asm-powerpc/fs_pd.h b/include/asm-powerpc/fs_pd.h
index 3d0e819d37f..c624915b757 100644
--- a/include/asm-powerpc/fs_pd.h
+++ b/include/asm-powerpc/fs_pd.h
@@ -11,19 +11,17 @@
#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();
-}
+#ifdef CONFIG_CPM2
+#include <asm/cpm2.h>
-static inline int uart_clock(void)
-{
- return ppc_proc_freq;
-}
+#if defined(CONFIG_8260)
+#include <asm/mpc8260.h>
+#elif defined(CONFIG_85xx)
+#include <asm/mpc85xx.h>
+#endif
#define cpm2_map(member) \
({ \
@@ -41,5 +39,38 @@ static inline int uart_clock(void)
})
#define cpm2_unmap(addr) iounmap(addr)
+#endif
+
+#ifdef CONFIG_8xx
+#include <asm/8xx_immap.h>
+#include <asm/mpc8xx.h>
+
+#define immr_map(member) \
+({ \
+ u32 offset = offsetof(immap_t, member); \
+ void *addr = ioremap (IMAP_ADDR + offset, \
+ sizeof( ((immap_t*)0)->member)); \
+ addr; \
+})
+
+#define immr_map_size(member, size) \
+({ \
+ u32 offset = offsetof(immap_t, member); \
+ void *addr = ioremap (IMAP_ADDR + offset, size); \
+ addr; \
+})
+
+#define immr_unmap(addr) iounmap(addr)
+#endif
+
+static inline int uart_baudrate(void)
+{
+ return get_baudrate();
+}
+
+static inline int uart_clock(void)
+{
+ return ppc_proc_freq;
+}
#endif
diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h
index 257d1cecb8c..60977806d2f 100644
--- a/include/asm-powerpc/hvcall.h
+++ b/include/asm-powerpc/hvcall.h
@@ -168,6 +168,7 @@
#define H_FREE_LOGICAL_LAN 0x118
#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
#define H_SEND_LOGICAL_LAN 0x120
+#define H_BULK_REMOVE 0x124
#define H_MULTICAST_CTRL 0x130
#define H_SET_XDABR 0x134
#define H_STUFF_TCE 0x138
@@ -252,8 +253,6 @@ struct hcall_stats {
unsigned long tb_total; /* total wall time (mftb) of calls. */
unsigned long purr_total; /* total cpu time (PURR) of calls. */
};
-void update_hcall_stats(unsigned long opcode, unsigned long tb_delta,
- unsigned long purr_delta);
#define HCALL_STAT_ARRAY_SIZE ((MAX_HCALL_OPCODE >> 2) + 1)
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h
index d604863d72f..9e4dd98eb22 100644
--- a/include/asm-powerpc/hw_irq.h
+++ b/include/asm-powerpc/hw_irq.h
@@ -107,25 +107,6 @@ static inline void local_irq_save_ptr(unsigned long *flags)
#endif /* CONFIG_PPC64 */
-#define mask_irq(irq) \
- ({ \
- irq_desc_t *desc = get_irq_desc(irq); \
- if (desc->chip && desc->chip->disable) \
- desc->chip->disable(irq); \
- })
-#define unmask_irq(irq) \
- ({ \
- irq_desc_t *desc = get_irq_desc(irq); \
- if (desc->chip && desc->chip->enable) \
- desc->chip->enable(irq); \
- })
-#define ack_irq(irq) \
- ({ \
- irq_desc_t *desc = get_irq_desc(irq); \
- if (desc->chip && desc->chip->ack) \
- desc->chip->ack(irq); \
- })
-
/*
* interrupt-retrigger: should we handle this via lost interrupts and IPIs
* or should we not care like we do now ? --BenH.
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index 1cd532379c3..301c9bb308b 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -732,6 +732,12 @@ static inline void * bus_to_virt(unsigned long address)
#endif /* CONFIG_PPC32 */
+/* access ports */
+#define setbits32(_addr, _v) out_be32((_addr), in_be32(_addr) | (_v))
+#define clrbits32(_addr, _v) out_be32((_addr), in_be32(_addr) & ~(_v))
+
+#define setbits16(_addr, _v) out_be16((_addr), in_be16(_addr) | (_v))
+#define clrbits16(_addr, _v) out_be16((_addr), in_be16(_addr) & ~(_v))
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h
index f85dbd30555..b2e56b30306 100644
--- a/include/asm-powerpc/iommu.h
+++ b/include/asm-powerpc/iommu.h
@@ -99,6 +99,7 @@ extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
extern void iommu_init_early_pSeries(void);
extern void iommu_init_early_iSeries(void);
extern void iommu_init_early_dart(void);
+extern void iommu_init_early_pasemi(void);
#ifdef CONFIG_PCI
extern void pci_iommu_init(void);
diff --git a/include/asm-powerpc/ipic.h b/include/asm-powerpc/ipic.h
index 9fbb0341586..edec79dcb7c 100644
--- a/include/asm-powerpc/ipic.h
+++ b/include/asm-powerpc/ipic.h
@@ -78,7 +78,7 @@ extern u32 ipic_get_mcp_status(void);
extern void ipic_clear_mcp_status(u32 mask);
#ifdef CONFIG_PPC_MERGE
-extern void ipic_init(struct device_node *node, unsigned int flags);
+extern struct ipic * ipic_init(struct device_node *node, unsigned int flags);
extern unsigned int ipic_get_irq(void);
#else
extern void ipic_init(phys_addr_t phys_addr, unsigned int flags,
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
index 46476e9a494..4734cc178db 100644
--- a/include/asm-powerpc/irq.h
+++ b/include/asm-powerpc/irq.h
@@ -89,6 +89,9 @@ struct irq_host_ops {
/* Dispose of such a mapping */
void (*unmap)(struct irq_host *h, unsigned int virq);
+ /* Update of such a mapping */
+ void (*remap)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
+
/* Translate device-tree interrupt specifier from raw format coming
* from the firmware to a irq_hw_number_t (interrupt line number) and
* type (sense) that can be passed to set_irq_type(). In the absence
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index 2dafa376a63..3a5dd492588 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -44,6 +44,7 @@ typedef unsigned int kprobe_opcode_t;
#define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000)
#define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000)
+#ifdef CONFIG_PPC64
/*
* 64bit powerpc uses function descriptors.
* Handle cases where:
@@ -67,9 +68,13 @@ typedef unsigned int kprobe_opcode_t;
}
#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry)
-
#define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \
IS_TWI(instr) || IS_TDI(instr))
+#else
+/* Use stock kprobe_lookup_name since ppc32 doesn't use function descriptors */
+#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)(pentry)
+#define is_trap(instr) (IS_TW(instr) || IS_TWI(instr))
+#endif
#define ARCH_SUPPORTS_KRETPROBES
#define ARCH_INACTIVE_KPROBE_COUNT 1
diff --git a/include/asm-powerpc/libata-portmap.h b/include/asm-powerpc/libata-portmap.h
new file mode 100644
index 00000000000..4d8518049f4
--- /dev/null
+++ b/include/asm-powerpc/libata-portmap.h
@@ -0,0 +1,12 @@
+#ifndef __ASM_POWERPC_LIBATA_PORTMAP_H
+#define __ASM_POWERPC_LIBATA_PORTMAP_H
+
+#define ATA_PRIMARY_CMD 0x1F0
+#define ATA_PRIMARY_CTL 0x3F6
+#define ATA_PRIMARY_IRQ(dev) pci_get_legacy_ide_irq(dev, 0)
+
+#define ATA_SECONDARY_CMD 0x170
+#define ATA_SECONDARY_CTL 0x376
+#define ATA_SECONDARY_IRQ(dev) pci_get_legacy_ide_irq(dev, 1)
+
+#endif
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h
index 41c8c9c5a25..200055a4b82 100644
--- a/include/asm-powerpc/mmu.h
+++ b/include/asm-powerpc/mmu.h
@@ -247,6 +247,7 @@ extern void htab_initialize_secondary(void);
extern void hpte_init_native(void);
extern void hpte_init_lpar(void);
extern void hpte_init_iSeries(void);
+extern void hpte_init_beat(void);
extern void stabs_alloc(void);
extern void slb_initialize(void);
diff --git a/include/asm-powerpc/module.h b/include/asm-powerpc/module.h
index 584fabfb4f0..e5f14b13ccf 100644
--- a/include/asm-powerpc/module.h
+++ b/include/asm-powerpc/module.h
@@ -46,8 +46,6 @@ struct mod_arch_specific {
unsigned int num_bugs;
};
-extern struct bug_entry *module_find_bug(unsigned long bugaddr);
-
/*
* Select ELF headers.
* Make empty section for module_frob_arch_sections to expand.
diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h
index 4a28a850998..7afd5bf9452 100644
--- a/include/asm-powerpc/mpc52xx.h
+++ b/include/asm-powerpc/mpc52xx.h
@@ -244,10 +244,13 @@ struct mpc52xx_cdm {
extern void __iomem * mpc52xx_find_and_map(const char *);
extern unsigned int mpc52xx_find_ipb_freq(struct device_node *node);
extern void mpc52xx_setup_cpu(void);
+extern void mpc52xx_declare_of_platform_devices(void);
extern void mpc52xx_init_irq(void);
extern unsigned int mpc52xx_get_irq(void);
+extern int __init mpc52xx_add_bridge(struct device_node *node);
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_POWERPC_MPC52xx_H__ */
diff --git a/include/asm-powerpc/mpc8260.h b/include/asm-powerpc/mpc8260.h
new file mode 100644
index 00000000000..f1b83b09ab2
--- /dev/null
+++ b/include/asm-powerpc/mpc8260.h
@@ -0,0 +1,24 @@
+/*
+ * Since there are many different boards and no standard configuration,
+ * we have a unique include file for each. Rather than change every
+ * file that has to include MPC8260 configuration, they all include
+ * this one and the configuration switching is done here.
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_PPC_MPC8260_H__
+#define __ASM_PPC_MPC8260_H__
+
+
+#ifdef CONFIG_8260
+
+#if defined(CONFIG_PQ2ADS) || defined (CONFIG_PQ2FADS)
+#include <platforms/82xx/pq2ads.h>
+#endif
+
+#ifdef CONFIG_PCI_8260
+#include <platforms/82xx/m82xx_pci.h>
+#endif
+
+#endif /* CONFIG_8260 */
+#endif /* !__ASM_PPC_MPC8260_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/mpc8xx.h b/include/asm-powerpc/mpc8xx.h
new file mode 100644
index 00000000000..580371120e1
--- /dev/null
+++ b/include/asm-powerpc/mpc8xx.h
@@ -0,0 +1,28 @@
+/* This is the single file included by all MPC8xx build options.
+ * Since there are many different boards and no standard configuration,
+ * we have a unique include file for each. Rather than change every
+ * file that has to include MPC8xx configuration, they all include
+ * this one and the configuration switching is done here.
+ */
+#ifdef __KERNEL__
+#ifndef __CONFIG_8xx_DEFS
+#define __CONFIG_8xx_DEFS
+
+
+#ifdef CONFIG_8xx
+
+#ifdef CONFIG_FADS
+#include <platforms/fads.h>
+#endif
+
+#if defined(CONFIG_MPC86XADS)
+#include <platforms/8xx/mpc86xads.h>
+#endif
+
+#if defined(CONFIG_MPC885ADS)
+#include <platforms/8xx/mpc885ads.h>
+#endif
+
+#endif /* CONFIG_8xx */
+#endif /* __CONFIG_8xx_DEFS */
+#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index b71e7b32a55..cb204a71e91 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -103,21 +103,6 @@
#define MPIC_MAX_ISU 32
/*
- * Special vector numbers (internal use only)
- */
-#define MPIC_VEC_SPURRIOUS 255
-#define MPIC_VEC_IPI_3 254
-#define MPIC_VEC_IPI_2 253
-#define MPIC_VEC_IPI_1 252
-#define MPIC_VEC_IPI_0 251
-
-/* unused */
-#define MPIC_VEC_TIMER_3 250
-#define MPIC_VEC_TIMER_2 249
-#define MPIC_VEC_TIMER_1 248
-#define MPIC_VEC_TIMER_0 247
-
-/*
* Tsi108 implementation of MPIC has many differences from the original one
*/
@@ -276,6 +261,13 @@ struct mpic
unsigned char *senses;
unsigned int senses_count;
+ /* vector numbers used for internal sources (ipi/timers) */
+ unsigned int ipi_vecs[4];
+ unsigned int timer_vecs[4];
+
+ /* Spurious vector to program into unused sources */
+ unsigned int spurious_vec;
+
#ifdef CONFIG_MPIC_BROKEN_U3
/* The fixup table */
struct mpic_irq_fixup *fixups;
@@ -332,6 +324,8 @@ struct mpic
#define MPIC_NO_PTHROU_DIS 0x00000040
/* DCR based MPIC */
#define MPIC_USES_DCR 0x00000080
+/* MPIC has 11-bit vector fields (or larger) */
+#define MPIC_LARGE_VECTORS 0x00000100
/* MPIC HW modification ID */
#define MPIC_REGSET_MASK 0xf0000000
diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
index 71043bf3641..94c0ad2bff9 100644
--- a/include/asm-powerpc/oprofile_impl.h
+++ b/include/asm-powerpc/oprofile_impl.h
@@ -58,10 +58,8 @@ extern struct op_powerpc_model op_model_power4;
extern struct op_powerpc_model op_model_7450;
extern struct op_powerpc_model op_model_cell;
-#ifndef CONFIG_FSL_BOOKE
-
/* All the classic PPC parts use these */
-static inline unsigned int ctr_read(unsigned int i)
+static inline unsigned int classic_ctr_read(unsigned int i)
{
switch(i) {
case 0:
@@ -89,7 +87,7 @@ static inline unsigned int ctr_read(unsigned int i)
}
}
-static inline void ctr_write(unsigned int i, unsigned int val)
+static inline void classic_ctr_write(unsigned int i, unsigned int val)
{
switch(i) {
case 0:
@@ -124,89 +122,6 @@ static inline void ctr_write(unsigned int i, unsigned int val)
break;
}
}
-#else /* CONFIG_FSL_BOOKE */
-static inline u32 get_pmlca(int ctr)
-{
- u32 pmlca;
-
- switch (ctr) {
- case 0:
- pmlca = mfpmr(PMRN_PMLCA0);
- break;
- case 1:
- pmlca = mfpmr(PMRN_PMLCA1);
- break;
- case 2:
- pmlca = mfpmr(PMRN_PMLCA2);
- break;
- case 3:
- pmlca = mfpmr(PMRN_PMLCA3);
- break;
- default:
- panic("Bad ctr number\n");
- }
-
- return pmlca;
-}
-
-static inline void set_pmlca(int ctr, u32 pmlca)
-{
- switch (ctr) {
- case 0:
- mtpmr(PMRN_PMLCA0, pmlca);
- break;
- case 1:
- mtpmr(PMRN_PMLCA1, pmlca);
- break;
- case 2:
- mtpmr(PMRN_PMLCA2, pmlca);
- break;
- case 3:
- mtpmr(PMRN_PMLCA3, pmlca);
- break;
- default:
- panic("Bad ctr number\n");
- }
-}
-
-static inline unsigned int ctr_read(unsigned int i)
-{
- switch(i) {
- case 0:
- return mfpmr(PMRN_PMC0);
- case 1:
- return mfpmr(PMRN_PMC1);
- case 2:
- return mfpmr(PMRN_PMC2);
- case 3:
- return mfpmr(PMRN_PMC3);
- default:
- return 0;
- }
-}
-
-static inline void ctr_write(unsigned int i, unsigned int val)
-{
- switch(i) {
- case 0:
- mtpmr(PMRN_PMC0, val);
- break;
- case 1:
- mtpmr(PMRN_PMC1, val);
- break;
- case 2:
- mtpmr(PMRN_PMC2, val);
- break;
- case 3:
- mtpmr(PMRN_PMC3, val);
- break;
- default:
- break;
- }
-}
-
-
-#endif /* CONFIG_FSL_BOOKE */
extern void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth);
diff --git a/include/asm-powerpc/page_32.h b/include/asm-powerpc/page_32.h
index 2677bad70f4..07f6d3cf5e5 100644
--- a/include/asm-powerpc/page_32.h
+++ b/include/asm-powerpc/page_32.h
@@ -26,15 +26,7 @@ extern void clear_pages(void *page, int order);
static inline void clear_page(void *page) { clear_pages(page, 0); }
extern void copy_page(void *to, void *from);
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
- int lz;
-
- size = (size-1) >> PAGE_SHIFT;
- asm ("cntlzw %0,%1" : "=r" (lz) : "r" (size));
- return 32 - lz;
-}
+#include <asm-generic/page.h>
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
index 7bb7f900980..d9bf5aba96c 100644
--- a/include/asm-powerpc/pci-bridge.h
+++ b/include/asm-powerpc/pci-bridge.h
@@ -31,12 +31,12 @@ struct pci_controller {
int last_busno;
void __iomem *io_base_virt;
- unsigned long io_base_phys;
+ resource_size_t io_base_phys;
/* Some machines have a non 1:1 mapping of
* the PCI memory space in the CPU bus space
*/
- unsigned long pci_mem_offset;
+ resource_size_t pci_mem_offset;
unsigned long pci_io_size;
struct pci_ops *ops;
@@ -53,6 +53,8 @@ struct pci_controller {
unsigned long buid;
unsigned long dma_window_base_cur;
unsigned long dma_window_size;
+
+ void *private_data;
};
/*
diff --git a/include/asm-powerpc/pci.h b/include/asm-powerpc/pci.h
index 16f13319c76..ac656ee6bb1 100644
--- a/include/asm-powerpc/pci.h
+++ b/include/asm-powerpc/pci.h
@@ -143,8 +143,13 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
#define HAVE_PCI_MMAP 1
-#ifdef CONFIG_PPC64
-/* pci_unmap_{single,page} is not a nop, thus... */
+#if defined(CONFIG_PPC64) || defined(CONFIG_NOT_COHERENT_CACHE)
+/*
+ * For 64-bit kernels, pci_unmap_{single,page} is not a nop.
+ * For 32-bit non-coherent kernels, pci_dma_sync_single_for_cpu() and
+ * so on are not nops.
+ * and thus...
+ */
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
dma_addr_t ADDR_NAME;
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
@@ -158,6 +163,20 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
(((PTR)->LEN_NAME) = (VAL))
+#else /* 32-bit && coherent */
+
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME) (0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME) (0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
+
+#endif /* CONFIG_PPC64 || CONFIG_NOT_COHERENT_CACHE */
+
+#ifdef CONFIG_PPC64
+
/* The PCI address space does not equal the physical memory address
* space (we have an IOMMU). The IDE and SCSI device layers use
* this boolean for bounce buffer decisions.
@@ -172,16 +191,8 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
*/
#define PCI_DMA_BUS_IS_PHYS (1)
-/* pci_unmap_{page,single} is a nop so... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME) (0)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0)
-#define pci_unmap_len(PTR, LEN_NAME) (0)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
-
#endif /* CONFIG_PPC64 */
-
+
extern void pcibios_resource_to_bus(struct pci_dev *dev,
struct pci_bus_region *region,
struct resource *res);
diff --git a/include/asm-powerpc/posix_types.h b/include/asm-powerpc/posix_types.h
index c6391077224..2f2288f520b 100644
--- a/include/asm-powerpc/posix_types.h
+++ b/include/asm-powerpc/posix_types.h
@@ -60,7 +60,7 @@ typedef struct {
#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
#define __FD_ISSET(d, set) (((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) != 0)
#define __FD_ZERO(set) \
- ((void) memset ((__ptr_t) (set), 0, sizeof (__kernel_fd_set)))
+ ((void) memset ((void *) (set), 0, sizeof (__kernel_fd_set)))
#else /* __GNUC__ */
diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
index 52a69ed0d90..4f5a1e01fda 100644
--- a/include/asm-powerpc/ps3.h
+++ b/include/asm-powerpc/ps3.h
@@ -21,11 +21,33 @@
#if !defined(_ASM_POWERPC_PS3_H)
#define _ASM_POWERPC_PS3_H
-#include <linux/compiler.h> /* for __deprecated */
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
+union ps3_firmware_version {
+ u64 raw;
+ struct {
+ u16 pad;
+ u16 major;
+ u16 minor;
+ u16 rev;
+ };
+};
+
+int ps3_get_firmware_version(union ps3_firmware_version *v);
+
+/* 'Other OS' area */
+
+enum ps3_param_av_multi_out {
+ PS3_PARAM_AV_MULTI_OUT_NTSC = 0,
+ PS3_PARAM_AV_MULTI_OUT_PAL_RGB = 1,
+ PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR = 2,
+ PS3_PARAM_AV_MULTI_OUT_SECAM = 3,
+};
+
+enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void);
+
/**
* struct ps3_device_id - HV bus device identifier from the system repository
* @bus_id: HV bus id, {1..} (zero invalid)
@@ -139,20 +161,32 @@ unsigned long ps3_mm_phys_to_lpar(unsigned long phys_addr);
/* inrerrupt routines */
-int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq);
+enum ps3_cpu_binding {
+ PS3_BINDING_CPU_ANY = -1,
+ PS3_BINDING_CPU_0 = 0,
+ PS3_BINDING_CPU_1 = 1,
+};
+
+int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+ unsigned int *virq);
int ps3_free_io_irq(unsigned int virq);
-int ps3_alloc_event_irq(unsigned int *virq);
+int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq);
int ps3_free_event_irq(unsigned int virq);
int ps3_send_event_locally(unsigned int virq);
-int ps3_connect_event_irq(const struct ps3_device_id *did,
- unsigned int interrupt_id, unsigned int *virq);
+int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
+ const struct ps3_device_id *did, unsigned int interrupt_id,
+ unsigned int *virq);
int ps3_disconnect_event_irq(const struct ps3_device_id *did,
unsigned int interrupt_id, unsigned int virq);
-int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq);
-int ps3_free_vuart_irq(unsigned int virq);
-int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class,
+int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
unsigned int *virq);
+int ps3_free_vuart_irq(unsigned int virq);
+int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
+ unsigned int class, unsigned int *virq);
int ps3_free_spe_irq(unsigned int virq);
+int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
+ unsigned int *virq);
+int ps3_free_irq(unsigned int virq);
/* lv1 result codes */
@@ -247,146 +281,6 @@ static inline const char* ps3_result(int result)
#endif
}
-/* repository bus info */
-
-enum ps3_bus_type {
- PS3_BUS_TYPE_SB = 4,
- PS3_BUS_TYPE_STORAGE = 5,
-};
-
-enum ps3_dev_type {
- PS3_DEV_TYPE_SB_GELIC = 3,
- PS3_DEV_TYPE_SB_USB = 4,
- PS3_DEV_TYPE_SB_GPIO = 6,
-};
-
-int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
- u64 *value);
-int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id);
-int ps3_repository_read_bus_type(unsigned int bus_index,
- enum ps3_bus_type *bus_type);
-int ps3_repository_read_bus_num_dev(unsigned int bus_index,
- unsigned int *num_dev);
-
-/* repository bus device info */
-
-enum ps3_interrupt_type {
- PS3_INTERRUPT_TYPE_EVENT_PORT = 2,
- PS3_INTERRUPT_TYPE_SB_OHCI = 3,
- PS3_INTERRUPT_TYPE_SB_EHCI = 4,
- PS3_INTERRUPT_TYPE_OTHER = 5,
-};
-
-enum ps3_region_type {
- PS3_REGION_TYPE_SB_OHCI = 3,
- PS3_REGION_TYPE_SB_EHCI = 4,
- PS3_REGION_TYPE_SB_GPIO = 5,
-};
-
-int ps3_repository_read_dev_str(unsigned int bus_index,
- unsigned int dev_index, const char *dev_str, u64 *value);
-int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index,
- unsigned int *dev_id);
-int ps3_repository_read_dev_type(unsigned int bus_index,
- unsigned int dev_index, enum ps3_dev_type *dev_type);
-int ps3_repository_read_dev_intr(unsigned int bus_index,
- unsigned int dev_index, unsigned int intr_index,
- enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id);
-int ps3_repository_read_dev_reg_type(unsigned int bus_index,
- unsigned int dev_index, unsigned int reg_index,
- enum ps3_region_type *reg_type);
-int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
- unsigned int dev_index, unsigned int reg_index, u64 *bus_addr,
- u64 *len);
-int ps3_repository_read_dev_reg(unsigned int bus_index,
- unsigned int dev_index, unsigned int reg_index,
- enum ps3_region_type *reg_type, u64 *bus_addr, u64 *len);
-
-/* repository bus enumerators */
-
-struct ps3_repository_device {
- unsigned int bus_index;
- unsigned int dev_index;
- struct ps3_device_id did;
-};
-
-int ps3_repository_find_device(enum ps3_bus_type bus_type,
- enum ps3_dev_type dev_type,
- const struct ps3_repository_device *start_dev,
- struct ps3_repository_device *dev);
-static inline int ps3_repository_find_first_device(
- enum ps3_bus_type bus_type, enum ps3_dev_type dev_type,
- struct ps3_repository_device *dev)
-{
- return ps3_repository_find_device(bus_type, dev_type, NULL, dev);
-}
-int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
- enum ps3_interrupt_type intr_type, unsigned int *interrupt_id);
-int ps3_repository_find_region(const struct ps3_repository_device *dev,
- enum ps3_region_type reg_type, u64 *bus_addr, u64 *len);
-
-/* repository block device info */
-
-int ps3_repository_read_dev_port(unsigned int bus_index,
- unsigned int dev_index, u64 *port);
-int ps3_repository_read_dev_blk_size(unsigned int bus_index,
- unsigned int dev_index, u64 *blk_size);
-int ps3_repository_read_dev_num_blocks(unsigned int bus_index,
- unsigned int dev_index, u64 *num_blocks);
-int ps3_repository_read_dev_num_regions(unsigned int bus_index,
- unsigned int dev_index, unsigned int *num_regions);
-int ps3_repository_read_dev_region_id(unsigned int bus_index,
- unsigned int dev_index, unsigned int region_index,
- unsigned int *region_id);
-int ps3_repository_read_dev_region_size(unsigned int bus_index,
- unsigned int dev_index, unsigned int region_index, u64 *region_size);
-int ps3_repository_read_dev_region_start(unsigned int bus_index,
- unsigned int dev_index, unsigned int region_index, u64 *region_start);
-
-/* repository pu and memory info */
-
-int ps3_repository_read_num_pu(unsigned int *num_pu);
-int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id);
-int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base);
-int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size);
-int ps3_repository_read_region_total(u64 *region_total);
-int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
- u64 *region_total);
-
-/* repository pme info */
-
-int ps3_repository_read_num_be(unsigned int *num_be);
-int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id);
-int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq);
-int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq);
-
-/* repository 'Other OS' area */
-
-int ps3_repository_read_boot_dat_addr(u64 *lpar_addr);
-int ps3_repository_read_boot_dat_size(unsigned int *size);
-int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size);
-
-/* repository spu info */
-
-/**
- * enum spu_resource_type - Type of spu resource.
- * @spu_resource_type_shared: Logical spu is shared with other partions.
- * @spu_resource_type_exclusive: Logical spu is not shared with other partions.
- *
- * Returned by ps3_repository_read_spu_resource_id().
- */
-
-enum ps3_spu_resource_type {
- PS3_SPU_RESOURCE_TYPE_SHARED = 0,
- PS3_SPU_RESOURCE_TYPE_EXCLUSIVE = 0x8000000000000000UL,
-};
-
-int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved);
-int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id);
-int ps3_repository_read_spu_resource_id(unsigned int res_index,
- enum ps3_spu_resource_type* resource_type, unsigned int *resource_id);
-
-
/* system bus routines */
enum ps3_match_id {
@@ -459,4 +353,39 @@ static inline void *ps3_system_bus_get_driver_data(
extern struct bus_type ps3_system_bus_type;
+/* vuart routines */
+
+struct ps3_vuart_stats {
+ unsigned long bytes_written;
+ unsigned long bytes_read;
+ unsigned long tx_interrupts;
+ unsigned long rx_interrupts;
+ unsigned long disconnect_interrupts;
+};
+
+/**
+ * struct ps3_vuart_port_device - a device on a vuart port
+ */
+
+struct ps3_vuart_port_device {
+ enum ps3_match_id match_id;
+ struct device core;
+
+ /* private driver variables */
+ unsigned int port_number;
+ u64 interrupt_mask;
+ struct {
+ spinlock_t lock;
+ struct list_head head;
+ } tx_list;
+ struct {
+ unsigned long bytes_held;
+ spinlock_t lock;
+ struct list_head head;
+ } rx_list;
+ struct ps3_vuart_stats stats;
+};
+
+int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
+
#endif
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index 6faae7b14d5..0d7f0164ed8 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -143,6 +143,7 @@
/* Special Purpose Registers (SPRNs)*/
#define SPRN_CTR 0x009 /* Count Register */
+#define SPRN_DSCR 0x11
#define SPRN_CTRLF 0x088
#define SPRN_CTRLT 0x098
#define CTRL_CT 0xc0000000 /* current thread */
@@ -163,7 +164,9 @@
#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */
#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */
#define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */
+#define SPRN_SPURR 0x134 /* Scaled PURR */
#define SPRN_HIOR 0x137 /* 970 Hypervisor interrupt offset */
+#define SPRN_LPCR 0x13E /* LPAR Control Register */
#define SPRN_DBAT0L 0x219 /* Data BAT 0 Lower Register */
#define SPRN_DBAT0U 0x218 /* Data BAT 0 Upper Register */
#define SPRN_DBAT1L 0x21B /* Data BAT 1 Lower Register */
@@ -389,6 +392,12 @@
#define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */
#define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */
+#define SPRN_TBCTL 0x35f /* PA6T Timebase control register */
+#define TBCTL_FREEZE 0x0000000000000000ull /* Freeze all tbs */
+#define TBCTL_RESTART 0x0000000100000000ull /* Restart all tbs */
+#define TBCTL_UPDATE_UPPER 0x0000000200000000ull /* Set upper 32 bits */
+#define TBCTL_UPDATE_LOWER 0x0000000300000000ull /* Set lower 32 bits */
+
#ifndef SPRN_SVR
#define SPRN_SVR 0x11E /* System Version Register */
#endif
@@ -460,6 +469,13 @@
#define SPRN_SIAR 780
#define SPRN_SDAR 781
+#define PA6T_SPRN_PMC0 787
+#define PA6T_SPRN_PMC1 788
+#define PA6T_SPRN_PMC2 789
+#define PA6T_SPRN_PMC3 790
+#define PA6T_SPRN_PMC4 791
+#define PA6T_SPRN_PMC5 792
+
#else /* 32-bit */
#define SPRN_MMCR0 952 /* Monitor Mode Control Register 0 */
#define MMCR0_FC 0x80000000UL /* freeze counters */
diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h
index 5a0c136c041..8eaa7b28d9d 100644
--- a/include/asm-powerpc/rtas.h
+++ b/include/asm-powerpc/rtas.h
@@ -159,6 +159,7 @@ extern struct rtas_t rtas;
extern void enter_rtas(unsigned long);
extern int rtas_token(const char *service);
+extern int rtas_service_present(const char *service);
extern int rtas_call(int token, int, int, int *, ...);
extern void rtas_restart(char *cmd);
extern void rtas_power_off(void);
@@ -221,8 +222,6 @@ extern int rtas_get_error_log_max(void);
extern spinlock_t rtas_data_buf_lock;
extern char rtas_data_buf[RTAS_DATA_BUF_SIZE];
-extern void rtas_stop_self(void);
-
/* RMO buffer reserved for user-space RTAS use */
extern unsigned long rtas_rmo_buf;
diff --git a/include/asm-powerpc/smp.h b/include/asm-powerpc/smp.h
index 20ea7c70bc3..01717f266dc 100644
--- a/include/asm-powerpc/smp.h
+++ b/include/asm-powerpc/smp.h
@@ -75,6 +75,7 @@ extern cpumask_t cpu_sibling_map[NR_CPUS];
void smp_init_iSeries(void);
void smp_init_pSeries(void);
void smp_init_cell(void);
+void smp_init_celleb(void);
void smp_setup_cpu_maps(void);
extern int __cpu_disable(void);
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index fdad4267b44..b634e16575f 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -104,6 +104,7 @@
struct spu_context;
struct spu_runqueue;
+struct device_node;
struct spu {
const char *name;
@@ -142,7 +143,19 @@ struct spu {
char irq_c1[8];
char irq_c2[8];
+ u64 spe_id;
+
void* pdata; /* platform private data */
+
+ /* of based platforms only */
+ struct device_node *devnode;
+
+ /* native only */
+ struct spu_priv1 __iomem *priv1;
+
+ /* beat only */
+ u64 shadow_int_mask_RW[3];
+
struct sys_device sysdev;
};
@@ -161,6 +174,7 @@ struct spu_syscall_block {
extern long spu_sys_callback(struct spu_syscall_block *s);
/* syscalls implemented in spufs */
+struct file;
extern struct spufs_calls {
asmlinkage long (*create_thread)(const char __user *name,
unsigned int flags, mode_t mode);
@@ -232,6 +246,7 @@ void spu_remove_sysdev_attr_group(struct attribute_group *attrs);
* to object-id spufs file from user space and the notifer
* function can assume that spu->ctx is valid.
*/
+struct notifier_block;
int spu_switch_event_register(struct notifier_block * n);
int spu_switch_event_unregister(struct notifier_block * n);
diff --git a/include/asm-powerpc/spu_priv1.h b/include/asm-powerpc/spu_priv1.h
index 69dcb0c5388..7e78f6a1ab8 100644
--- a/include/asm-powerpc/spu_priv1.h
+++ b/include/asm-powerpc/spu_priv1.h
@@ -206,6 +206,8 @@ spu_destroy_spu (struct spu *spu)
*/
extern const struct spu_priv1_ops spu_priv1_mmio_ops;
+extern const struct spu_priv1_ops spu_priv1_beat_ops;
+
extern const struct spu_management_ops spu_management_of_ops;
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/sstep.h b/include/asm-powerpc/sstep.h
index 630a9889c07..f593b0f9b62 100644
--- a/include/asm-powerpc/sstep.h
+++ b/include/asm-powerpc/sstep.h
@@ -21,6 +21,7 @@ struct pt_regs;
*/
#define IS_MTMSRD(instr) (((instr) & 0xfc0007be) == 0x7c000124)
#define IS_RFID(instr) (((instr) & 0xfc0007fe) == 0x4c000024)
+#define IS_RFI(instr) (((instr) & 0xfc0007fe) == 0x4c000064)
/* Emulate instructions that cause a transfer of control. */
extern int emulate_step(struct pt_regs *regs, unsigned int instr);
diff --git a/include/asm-powerpc/termbits.h b/include/asm-powerpc/termbits.h
index 6d533b07aaf..5e79198f7d1 100644
--- a/include/asm-powerpc/termbits.h
+++ b/include/asm-powerpc/termbits.h
@@ -30,6 +30,19 @@ struct termios {
speed_t c_ospeed; /* output speed */
};
+/* For PowerPC the termios and ktermios are the same */
+
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_cc[NCCS]; /* control characters */
+ cc_t c_line; /* line discipline (== c_cc[19]) */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h
index d339e2e88b1..3f32ca8bfec 100644
--- a/include/asm-powerpc/thread_info.h
+++ b/include/asm-powerpc/thread_info.h
@@ -122,6 +122,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_RESTOREALL 12 /* Restore all regs (implies NOERROR) */
#define TIF_NOERROR 14 /* Force successful syscall return */
#define TIF_RESTORE_SIGMASK 15 /* Restore signal mask in do_signal */
+#define TIF_FREEZE 16 /* Freezing for suspend */
/* as above, but as bit values */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -138,6 +139,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_RESTOREALL (1<<TIF_RESTOREALL)
#define _TIF_NOERROR (1<<TIF_NOERROR)
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
+#define _TIF_FREEZE (1<<TIF_FREEZE)
#define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
#define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h
index 4cff977ad52..3fd57c048f5 100644
--- a/include/asm-powerpc/time.h
+++ b/include/asm-powerpc/time.h
@@ -39,6 +39,8 @@ extern void generic_calibrate_decr(void);
extern void wakeup_decrementer(void);
extern void snapshot_timebase(void);
+extern void set_dec_cpu6(unsigned int val);
+
/* Some sane defaults: 125 MHz timebase, 1GHz processor */
extern unsigned long ppc_proc_freq;
#define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8)
diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h
index 50c014007de..6610495f5f1 100644
--- a/include/asm-powerpc/topology.h
+++ b/include/asm-powerpc/topology.h
@@ -66,6 +66,7 @@ static inline int pcibus_to_node(struct pci_bus *bus)
| SD_BALANCE_EXEC \
| SD_BALANCE_NEWIDLE \
| SD_WAKE_IDLE \
+ | SD_SERIALIZE \
| SD_WAKE_BALANCE, \
.last_balance = jiffies, \
.balance_interval = 1, \
diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h
index 55e57844fa7..4cbc313aa02 100644
--- a/include/asm-powerpc/udbg.h
+++ b/include/asm-powerpc/udbg.h
@@ -41,9 +41,11 @@ extern void __init udbg_early_init(void);
extern void __init udbg_init_debug_lpar(void);
extern void __init udbg_init_pmac_realmode(void);
extern void __init udbg_init_maple_realmode(void);
+extern void __init udbg_init_pas_realmode(void);
extern void __init udbg_init_iseries(void);
extern void __init udbg_init_rtas_panel(void);
extern void __init udbg_init_rtas_console(void);
+extern void __init udbg_init_debug_beat(void);
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_UDBG_H */
diff --git a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h
index 7b06b4e6bf3..4f99df1bafd 100644
--- a/include/asm-ppc/commproc.h
+++ b/include/asm-ppc/commproc.h
@@ -77,6 +77,7 @@ extern int cpm_dpfree(uint offset);
extern uint cpm_dpalloc_fixed(uint offset, uint size, uint align);
extern void cpm_dpdump(void);
extern void *cpm_dpram_addr(uint offset);
+extern uint cpm_dpram_phys(u8* addr);
extern void cpm_setbrg(uint brg, uint rate);
extern uint m8xx_cpm_hostalloc(uint size);
diff --git a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h
index 499c14691c7..7a64ede53bb 100644
--- a/include/asm-ppc/ibm4xx.h
+++ b/include/asm-ppc/ibm4xx.h
@@ -15,6 +15,7 @@
#define __ASM_IBM4XX_H__
#include <asm/types.h>
+#include <asm/dcr.h>
#ifdef CONFIG_40x
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
index ccf1a9bb2e4..95d590423cf 100644
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -358,8 +358,6 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int
}
#endif
-#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void __force *)(void __iomem *)(b),(c),(d))
-
/*
* Map in an area of physical address space, for accessing
* I/O devices etc.
diff --git a/include/asm-ppc/m48t35.h b/include/asm-ppc/m48t35.h
deleted file mode 100644
index a5277ea4b19..00000000000
--- a/include/asm-ppc/m48t35.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Registers for the SGS-Thomson M48T35 Timekeeper RAM chip
- * and
- * Registers for the SGS-Thomson M48T37 Timekeeper RAM chip
- * The 37 is the 35 plus alarm and century thus the offsets
- * are shifted by the extra registers.
- */
-
-#ifndef __PPC_M48T35_H
-#define __PPC_M48T35_H
-
-/* RTC offsets */
-#define M48T35_RTC_FLAGS (-8) /* the negative regs are really T37 only */
-#define M48T35_RTC_CENTURY (-7)
-#define M48T35_RTC_AL_SEC (-6)
-#define M48T35_RTC_AL_MIN (-5)
-#define M48T35_RTC_AL_HRS (-4)
-#define M48T35_RTC_AL_DOM (-3)
-#define M48T35_RTC_INTERRUPT (-2)
-#define M48T35_RTC_WATCHDOG (-1)
-#define M48T35_RTC_CONTROL 0 /* T35 starts here */
-#define M48T35_RTC_SECONDS 1
-#define M48T35_RTC_MINUTES 2
-#define M48T35_RTC_HOURS 3
-#define M48T35_RTC_DAY 4
-#define M48T35_RTC_DOM 5
-#define M48T35_RTC_MONTH 6
-#define M48T35_RTC_YEAR 7
-
-/* this way help us know which bits go with which regs */
-#define M48T35_RTC_FLAGS_BL 0x10
-#define M48T35_RTC_FLAGS_AF 0x40
-#define M48T35_RTC_FLAGS_WDF 0x80
-
-#define M48T35_RTC_INTERRUPT_AFE 0x80
-#define M48T35_RTC_INTERRUPT_ABE 0x20
-#define M48T35_RTC_INTERRUPT_ALL (M48T35_RTC_INTERRUPT_AFE|M48T35_RTC_INTERRUPT_ABE)
-
-#define M48T35_RTC_WATCHDOG_RB 0x03
-#define M48T35_RTC_WATCHDOG_BMB 0x7c
-#define M48T35_RTC_WATCHDOG_WDS 0x80
-#define M48T35_RTC_WATCHDOG_ALL (M48T35_RTC_WATCHDOG_RB|M48T35_RTC_WATCHDOG_BMB|M48T35_RTC_W)
-
-#define M48T35_RTC_CONTROL_WRITE 0x80
-#define M48T35_RTC_CONTROL_READ 0x40
-#define M48T35_RTC_CONTROL_CAL_SIGN 0x20
-#define M48T35_RTC_CONTROL_CAL_VALUE 0x1f
-#define M48T35_RTC_CONTROL_LOCKED (M48T35_RTC_WRITE|M48T35_RTC_READ)
-#define M48T35_RTC_CONTROL_CALIBRATION (M48T35_RTC_CONTROL_CAL_SIGN|M48T35_RTC_CONTROL_CAL_VALUE)
-
-#define M48T35_RTC_SECONDS_SEC_1 0x0f
-#define M48T35_RTC_SECONDS_SEC_10 0x70
-#define M48T35_RTC_SECONDS_ST 0x80
-#define M48T35_RTC_SECONDS_SEC_ALL (M48T35_RTC_SECONDS_SEC_1|M48T35_RTC_SECONDS_SEC_10)
-
-#define M48T35_RTC_MINUTES_MIN_1 0x0f
-#define M48T35_RTC_MINUTES_MIN_10 0x70
-#define M48T35_RTC_MINUTES_MIN_ALL (M48T35_RTC_MINUTES_MIN_1|M48T35_RTC_MINUTES_MIN_10)
-
-#define M48T35_RTC_HOURS_HRS_1 0x0f
-#define M48T35_RTC_HOURS_HRS_10 0x30
-#define M48T35_RTC_HOURS_HRS_ALL (M48T35_RTC_HOURS_HRS_1|M48T35_RTC_HOURS_HRS_10)
-
-#define M48T35_RTC_DAY_DAY_1 0x03
-#define M48T35_RTC_DAY_FT 0x40
-
-#define M48T35_RTC_ALARM_OFF 0x00
-#define M48T35_RTC_WATCHDOG_OFF 0x00
-
-
-/* legacy */
-#define M48T35_RTC_SET 0x80
-#define M48T35_RTC_STOPPED 0x80
-#define M48T35_RTC_READ 0x40
-
-
-#endif
diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
index 6c955d0c1ef..4d35b844bc5 100644
--- a/include/asm-ppc/pci-bridge.h
+++ b/include/asm-ppc/pci-bridge.h
@@ -20,8 +20,8 @@ extern unsigned long pci_bus_mem_base_phys(unsigned int bus);
extern struct pci_controller* pcibios_alloc_controller(void);
/* Helper function for setting up resources */
-extern void pci_init_resource(struct resource *res, unsigned long start,
- unsigned long end, int flags, char *name);
+extern void pci_init_resource(struct resource *res, resource_size_t start,
+ resource_size_t end, int flags, char *name);
/* Get the PCI host controller for a bus */
extern struct pci_controller* pci_bus_to_hose(int bus);
@@ -50,12 +50,12 @@ struct pci_controller {
int bus_offset;
void __iomem *io_base_virt;
- unsigned long io_base_phys;
+ resource_size_t io_base_phys;
/* Some machines (PReP) have a non 1:1 mapping of
* the PCI memory space in the CPU bus space
*/
- unsigned long pci_mem_offset;
+ resource_size_t pci_mem_offset;
struct pci_ops *ops;
volatile unsigned int __iomem *cfg_addr;
diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
index 11ffaaa5da1..9d162028dab 100644
--- a/include/asm-ppc/pci.h
+++ b/include/asm-ppc/pci.h
@@ -61,6 +61,27 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
*/
#define PCI_DMA_BUS_IS_PHYS (1)
+#ifdef CONFIG_NOT_COHERENT_CACHE
+/*
+ * pci_unmap_{page,single} are NOPs but pci_dma_sync_single_for_cpu()
+ * and so on are not, so...
+ */
+
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
+ dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
+ __u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME) \
+ ((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
+ (((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME) \
+ ((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
+ (((PTR)->LEN_NAME) = (VAL))
+
+#else /* coherent */
+
/* pci_unmap_{page,single} is a nop so... */
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
@@ -69,6 +90,8 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
+#endif /* CONFIG_NOT_COHERENT_CACHE */
+
#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
diff --git a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h
index 602fbadeaf4..82948ed2744 100644
--- a/include/asm-ppc/reg_booke.h
+++ b/include/asm-ppc/reg_booke.h
@@ -10,40 +10,6 @@
#define __ASM_PPC_REG_BOOKE_H__
#ifndef __ASSEMBLY__
-/* Device Control Registers */
-void __mtdcr(int reg, unsigned int val);
-unsigned int __mfdcr(int reg);
-#define mfdcr(rn) \
- ({unsigned int rval; \
- if (__builtin_constant_p(rn)) \
- asm volatile("mfdcr %0," __stringify(rn) \
- : "=r" (rval)); \
- else \
- rval = __mfdcr(rn); \
- rval;})
-
-#define mtdcr(rn, v) \
-do { \
- if (__builtin_constant_p(rn)) \
- asm volatile("mtdcr " __stringify(rn) ",%0" \
- : : "r" (v)); \
- else \
- __mtdcr(rn, v); \
-} while (0)
-
-/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
-#define mfdcri(base, reg) \
-({ \
- mtdcr(base ## _CFGADDR, base ## _ ## reg); \
- mfdcr(base ## _CFGDATA); \
-})
-
-#define mtdcri(base, reg, data) \
-do { \
- mtdcr(base ## _CFGADDR, base ## _ ## reg); \
- mtdcr(base ## _CFGDATA, data); \
-} while (0)
-
/* Performance Monitor Registers */
#define mfpmr(rn) ({unsigned int rval; \
asm volatile("mfpmr %0," __stringify(rn) \
diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
index 8a59f8871f3..8fc1b546613 100644
--- a/include/asm-ppc/serial.h
+++ b/include/asm-ppc/serial.h
@@ -11,8 +11,6 @@
#include <platforms/ev64260.h>
#elif defined(CONFIG_CHESTNUT)
#include <platforms/chestnut.h>
-#elif defined(CONFIG_GEMINI)
-#include <platforms/gemini_serial.h>
#elif defined(CONFIG_POWERPMC250)
#include <platforms/powerpmc250.h>
#elif defined(CONFIG_LOPEC)
diff --git a/include/asm-s390/cacheflush.h b/include/asm-s390/cacheflush.h
index e399a8ba2ed..f7cade8083f 100644
--- a/include/asm-s390/cacheflush.h
+++ b/include/asm-s390/cacheflush.h
@@ -7,6 +7,7 @@
/* Caches aren't brain-dead on the s390. */
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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)
diff --git a/include/asm-s390/compat.h b/include/asm-s390/compat.h
index 356a0b18353..296f4f1a20e 100644
--- a/include/asm-s390/compat.h
+++ b/include/asm-s390/compat.h
@@ -6,6 +6,34 @@
#include <linux/types.h>
#include <linux/sched.h>
+#define PSW32_MASK_PER 0x40000000UL
+#define PSW32_MASK_DAT 0x04000000UL
+#define PSW32_MASK_IO 0x02000000UL
+#define PSW32_MASK_EXT 0x01000000UL
+#define PSW32_MASK_KEY 0x00F00000UL
+#define PSW32_MASK_MCHECK 0x00040000UL
+#define PSW32_MASK_WAIT 0x00020000UL
+#define PSW32_MASK_PSTATE 0x00010000UL
+#define PSW32_MASK_ASC 0x0000C000UL
+#define PSW32_MASK_CC 0x00003000UL
+#define PSW32_MASK_PM 0x00000f00UL
+
+#define PSW32_ADDR_AMODE31 0x80000000UL
+#define PSW32_ADDR_INSN 0x7FFFFFFFUL
+
+#define PSW32_BASE_BITS 0x00080000UL
+
+#define PSW32_ASC_PRIMARY 0x00000000UL
+#define PSW32_ASC_ACCREG 0x00004000UL
+#define PSW32_ASC_SECONDARY 0x00008000UL
+#define PSW32_ASC_HOME 0x0000C000UL
+
+#define PSW32_MASK_MERGE(CURRENT,NEW) \
+ (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
+ ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
+
+extern long psw32_user_bits;
+
#define COMPAT_USER_HZ 100
typedef u32 compat_size_t;
diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h
index c042f957808..604f68fa6f5 100644
--- a/include/asm-s390/dasd.h
+++ b/include/asm-s390/dasd.h
@@ -69,11 +69,13 @@ typedef struct dasd_information2_t {
* 0x01: readonly (ro)
* 0x02: use diag discipline (diag)
* 0x04: set the device initially online (internal use only)
+ * 0x08: enable ERP related logging
*/
#define DASD_FEATURE_DEFAULT 0x00
#define DASD_FEATURE_READONLY 0x01
#define DASD_FEATURE_USEDIAG 0x02
#define DASD_FEATURE_INITIAL_ONLINE 0x04
+#define DASD_FEATURE_ERPLOG 0x08
#define DASD_PARTN_BITS 2
diff --git a/include/asm-s390/etr.h b/include/asm-s390/etr.h
new file mode 100644
index 00000000000..b498f19bb9a
--- /dev/null
+++ b/include/asm-s390/etr.h
@@ -0,0 +1,219 @@
+/*
+ * include/asm-s390/etr.h
+ *
+ * Copyright IBM Corp. 2006
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+#ifndef __S390_ETR_H
+#define __S390_ETR_H
+
+/* ETR attachment control register */
+struct etr_eacr {
+ unsigned int e0 : 1; /* port 0 stepping control */
+ unsigned int e1 : 1; /* port 1 stepping control */
+ unsigned int _pad0 : 5; /* must be 00100 */
+ unsigned int dp : 1; /* data port control */
+ unsigned int p0 : 1; /* port 0 change recognition control */
+ unsigned int p1 : 1; /* port 1 change recognition control */
+ unsigned int _pad1 : 3; /* must be 000 */
+ unsigned int ea : 1; /* ETR alert control */
+ unsigned int es : 1; /* ETR sync check control */
+ unsigned int sl : 1; /* switch to local control */
+} __attribute__ ((packed));
+
+/* Port state returned by steai */
+enum etr_psc {
+ etr_psc_operational = 0,
+ etr_psc_semi_operational = 1,
+ etr_psc_protocol_error = 4,
+ etr_psc_no_symbols = 8,
+ etr_psc_no_signal = 12,
+ etr_psc_pps_mode = 13
+};
+
+/* Logical port state returned by stetr */
+enum etr_lpsc {
+ etr_lpsc_operational_step = 0,
+ etr_lpsc_operational_alt = 1,
+ etr_lpsc_semi_operational = 2,
+ etr_lpsc_protocol_error = 4,
+ etr_lpsc_no_symbol_sync = 8,
+ etr_lpsc_no_signal = 12,
+ etr_lpsc_pps_mode = 13
+};
+
+/* ETR status words */
+struct etr_esw {
+ struct etr_eacr eacr; /* attachment control register */
+ unsigned int y : 1; /* stepping mode */
+ unsigned int _pad0 : 5; /* must be 00000 */
+ unsigned int p : 1; /* stepping port number */
+ unsigned int q : 1; /* data port number */
+ unsigned int psc0 : 4; /* port 0 state code */
+ unsigned int psc1 : 4; /* port 1 state code */
+} __attribute__ ((packed));
+
+/* Second level data register status word */
+struct etr_slsw {
+ unsigned int vv1 : 1; /* copy of validity bit data frame 1 */
+ unsigned int vv2 : 1; /* copy of validity bit data frame 2 */
+ unsigned int vv3 : 1; /* copy of validity bit data frame 3 */
+ unsigned int vv4 : 1; /* copy of validity bit data frame 4 */
+ unsigned int _pad0 : 19; /* must by all zeroes */
+ unsigned int n : 1; /* EAF port number */
+ unsigned int v1 : 1; /* validity bit ETR data frame 1 */
+ unsigned int v2 : 1; /* validity bit ETR data frame 2 */
+ unsigned int v3 : 1; /* validity bit ETR data frame 3 */
+ unsigned int v4 : 1; /* validity bit ETR data frame 4 */
+ unsigned int _pad1 : 4; /* must be 0000 */
+} __attribute__ ((packed));
+
+/* ETR data frames */
+struct etr_edf1 {
+ unsigned int u : 1; /* untuned bit */
+ unsigned int _pad0 : 1; /* must be 0 */
+ unsigned int r : 1; /* service request bit */
+ unsigned int _pad1 : 4; /* must be 0000 */
+ unsigned int a : 1; /* time adjustment bit */
+ unsigned int net_id : 8; /* ETR network id */
+ unsigned int etr_id : 8; /* id of ETR which sends data frames */
+ unsigned int etr_pn : 8; /* port number of ETR output port */
+} __attribute__ ((packed));
+
+struct etr_edf2 {
+ unsigned int etv : 32; /* Upper 32 bits of TOD. */
+} __attribute__ ((packed));
+
+struct etr_edf3 {
+ unsigned int rc : 8; /* failure reason code */
+ unsigned int _pad0 : 3; /* must be 000 */
+ unsigned int c : 1; /* ETR coupled bit */
+ unsigned int tc : 4; /* ETR type code */
+ unsigned int blto : 8; /* biased local time offset */
+ /* (blto - 128) * 15 = minutes */
+ unsigned int buo : 8; /* biased utc offset */
+ /* (buo - 128) = leap seconds */
+} __attribute__ ((packed));
+
+struct etr_edf4 {
+ unsigned int ed : 8; /* ETS device dependent data */
+ unsigned int _pad0 : 1; /* must be 0 */
+ unsigned int buc : 5; /* biased ut1 correction */
+ /* (buc - 16) * 0.1 seconds */
+ unsigned int em : 6; /* ETS error magnitude */
+ unsigned int dc : 6; /* ETS drift code */
+ unsigned int sc : 6; /* ETS steering code */
+} __attribute__ ((packed));
+
+/*
+ * ETR attachment information block, two formats
+ * format 1 has 4 reserved words with a size of 64 bytes
+ * format 2 has 16 reserved words with a size of 96 bytes
+ */
+struct etr_aib {
+ struct etr_esw esw;
+ struct etr_slsw slsw;
+ unsigned long long tsp;
+ struct etr_edf1 edf1;
+ struct etr_edf2 edf2;
+ struct etr_edf3 edf3;
+ struct etr_edf4 edf4;
+ unsigned int reserved[16];
+} __attribute__ ((packed,aligned(8)));
+
+/* ETR interruption parameter */
+struct etr_interruption_parameter {
+ unsigned int _pad0 : 8;
+ unsigned int pc0 : 1; /* port 0 state change */
+ unsigned int pc1 : 1; /* port 1 state change */
+ unsigned int _pad1 : 3;
+ unsigned int eai : 1; /* ETR alert indication */
+ unsigned int _pad2 : 18;
+} __attribute__ ((packed));
+
+/* Query TOD offset result */
+struct etr_ptff_qto {
+ unsigned long long physical_clock;
+ unsigned long long tod_offset;
+ unsigned long long logical_tod_offset;
+ unsigned long long tod_epoch_difference;
+} __attribute__ ((packed));
+
+/* Inline assembly helper functions */
+static inline int etr_setr(struct etr_eacr *ctrl)
+{
+ int rc = -ENOSYS;
+
+ asm volatile(
+ " .insn s,0xb2160000,0(%2)\n"
+ "0: la %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "+d" (rc) : "m" (*ctrl), "a" (ctrl));
+ return rc;
+}
+
+/* Stores a format 1 aib with 64 bytes */
+static inline int etr_stetr(struct etr_aib *aib)
+{
+ int rc = -ENOSYS;
+
+ asm volatile(
+ " .insn s,0xb2170000,0(%2)\n"
+ "0: la %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "+d" (rc) : "m" (*aib), "a" (aib));
+ return rc;
+}
+
+/* Stores a format 2 aib with 96 bytes for specified port */
+static inline int etr_steai(struct etr_aib *aib, unsigned int func)
+{
+ register unsigned int reg0 asm("0") = func;
+ int rc = -ENOSYS;
+
+ asm volatile(
+ " .insn s,0xb2b30000,0(%2)\n"
+ "0: la %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "+d" (rc) : "m" (*aib), "a" (aib), "d" (reg0));
+ return rc;
+}
+
+/* Function codes for the steai instruction. */
+#define ETR_STEAI_STEPPING_PORT 0x10
+#define ETR_STEAI_ALTERNATE_PORT 0x11
+#define ETR_STEAI_PORT_0 0x12
+#define ETR_STEAI_PORT_1 0x13
+
+static inline int etr_ptff(void *ptff_block, unsigned int func)
+{
+ register unsigned int reg0 asm("0") = func;
+ register unsigned long reg1 asm("1") = (unsigned long) ptff_block;
+ int rc = -ENOSYS;
+
+ asm volatile(
+ " .word 0x0104\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (rc), "=m" (ptff_block)
+ : "d" (reg0), "d" (reg1), "m" (ptff_block) : "cc");
+ return rc;
+}
+
+/* Function codes for the ptff instruction. */
+#define ETR_PTFF_QAF 0x00 /* query available functions */
+#define ETR_PTFF_QTO 0x01 /* query tod offset */
+#define ETR_PTFF_QSI 0x02 /* query steering information */
+#define ETR_PTFF_ATO 0x40 /* adjust tod offset */
+#define ETR_PTFF_STO 0x41 /* set tod offset */
+#define ETR_PTFF_SFS 0x42 /* set fine steering rate */
+#define ETR_PTFF_SGS 0x43 /* set gross steering rate */
+
+/* Functions needed by the machine check handler */
+extern void etr_switch_to_local(void);
+extern void etr_sync_check(void);
+
+#endif /* __S390_ETR_H */
diff --git a/include/asm-s390/futex.h b/include/asm-s390/futex.h
index 5e261e1de67..5c5d02de49e 100644
--- a/include/asm-s390/futex.h
+++ b/include/asm-s390/futex.h
@@ -4,8 +4,8 @@
#ifdef __KERNEL__
#include <linux/futex.h>
+#include <linux/uaccess.h>
#include <asm/errno.h>
-#include <asm/uaccess.h>
static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
{
@@ -21,7 +21,9 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;
+ pagefault_disable();
ret = uaccess.futex_atomic_op(op, uaddr, oparg, &oldval);
+ pagefault_enable();
if (!ret) {
switch (cmp) {
diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h
index c2f6a8782d3..31beb18cb3d 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(void);
+extern void account_ticks(u64 time);
#endif /* __ASM_HARDIRQ_H */
diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h
index efb7de9c1c6..a4c2d550dad 100644
--- a/include/asm-s390/io.h
+++ b/include/asm-s390/io.h
@@ -28,11 +28,7 @@ static inline unsigned long virt_to_phys(volatile void * address)
{
unsigned long real_address;
asm volatile(
-#ifndef __s390x__
" lra %0,0(%1)\n"
-#else /* __s390x__ */
- " lrag %0,0(%1)\n"
-#endif /* __s390x__ */
" jz 0f\n"
" la %0,0\n"
"0:"
diff --git a/include/asm-s390/kdebug.h b/include/asm-s390/kdebug.h
index 40cc68025e0..1b50f89819a 100644
--- a/include/asm-s390/kdebug.h
+++ b/include/asm-s390/kdebug.h
@@ -26,7 +26,6 @@ extern int register_page_fault_notifier(struct notifier_block *);
extern int unregister_page_fault_notifier(struct notifier_block *);
extern struct atomic_notifier_head s390die_chain;
-
enum die_val {
DIE_OOPS = 1,
DIE_BPT,
@@ -56,4 +55,6 @@ static inline int notify_die(enum die_val val, const char *str,
return atomic_notifier_call_chain(&s390die_chain, val, &args);
}
+extern void die(const char *, struct pt_regs *, long);
+
#endif
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
index 74f7389bd3e..4a31d0a7ee8 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -220,7 +220,8 @@ struct _lowcore
__u32 kernel_asce; /* 0xc4c */
__u32 user_asce; /* 0xc50 */
__u32 panic_stack; /* 0xc54 */
- __u8 pad10[0xc60-0xc58]; /* 0xc58 */
+ __u32 user_exec_asce; /* 0xc58 */
+ __u8 pad10[0xc60-0xc5c]; /* 0xc5c */
/* entry.S sensitive area start */
struct cpuinfo_S390 cpu_data; /* 0xc60 */
__u32 ipl_device; /* 0xc7c */
@@ -310,7 +311,8 @@ struct _lowcore
__u64 kernel_asce; /* 0xd58 */
__u64 user_asce; /* 0xd60 */
__u64 panic_stack; /* 0xd68 */
- __u8 pad10[0xd80-0xd70]; /* 0xd70 */
+ __u64 user_exec_asce; /* 0xd70 */
+ __u8 pad10[0xd80-0xd78]; /* 0xd78 */
/* entry.S sensitive area start */
struct cpuinfo_S390 cpu_data; /* 0xd80 */
__u32 ipl_device; /* 0xdb8 */
diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
index bcf24a87387..1d21da220d4 100644
--- a/include/asm-s390/mmu_context.h
+++ b/include/asm-s390/mmu_context.h
@@ -9,6 +9,7 @@
#ifndef __S390_MMU_CONTEXT_H
#define __S390_MMU_CONTEXT_H
+#include <asm/pgalloc.h>
/*
* get a new mmu context.. S390 don't know about contexts.
*/
@@ -16,29 +17,44 @@
#define destroy_context(mm) do { } while (0)
+#ifndef __s390x__
+#define LCTL_OPCODE "lctl"
+#define PGTABLE_BITS (_SEGMENT_TABLE|USER_STD_MASK)
+#else
+#define LCTL_OPCODE "lctlg"
+#define PGTABLE_BITS (_REGION_TABLE|USER_STD_MASK)
+#endif
+
static inline void enter_lazy_tlb(struct mm_struct *mm,
struct task_struct *tsk)
{
}
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
- struct task_struct *tsk)
+ struct task_struct *tsk)
{
- if (prev != next) {
-#ifndef __s390x__
- S390_lowcore.user_asce = (__pa(next->pgd)&PAGE_MASK) |
- (_SEGMENT_TABLE|USER_STD_MASK);
- /* Load home space page table origin. */
- asm volatile("lctl 13,13,%0"
- : : "m" (S390_lowcore.user_asce) );
-#else /* __s390x__ */
- S390_lowcore.user_asce = (__pa(next->pgd) & PAGE_MASK) |
- (_REGION_TABLE|USER_STD_MASK);
- /* Load home space page table origin. */
- asm volatile("lctlg 13,13,%0"
- : : "m" (S390_lowcore.user_asce) );
-#endif /* __s390x__ */
- }
+ pgd_t *shadow_pgd = get_shadow_pgd(next->pgd);
+
+ if (prev != next) {
+ S390_lowcore.user_asce = (__pa(next->pgd) & PAGE_MASK) |
+ PGTABLE_BITS;
+ if (shadow_pgd) {
+ /* Load primary/secondary space page table origin. */
+ S390_lowcore.user_exec_asce =
+ (__pa(shadow_pgd) & PAGE_MASK) | PGTABLE_BITS;
+ asm volatile(LCTL_OPCODE" 1,1,%0\n"
+ LCTL_OPCODE" 7,7,%1"
+ : : "m" (S390_lowcore.user_exec_asce),
+ "m" (S390_lowcore.user_asce) );
+ } else if (switch_amode) {
+ /* Load primary space page table origin. */
+ asm volatile(LCTL_OPCODE" 1,1,%0"
+ : : "m" (S390_lowcore.user_asce) );
+ } else
+ /* Load home space page table origin. */
+ asm volatile(LCTL_OPCODE" 13,13,%0"
+ : : "m" (S390_lowcore.user_asce) );
+ }
cpu_set(smp_processor_id(), next->cpu_vm_mask);
}
@@ -51,4 +67,4 @@ static inline void activate_mm(struct mm_struct *prev,
set_fs(current->thread.mm_segment);
}
-#endif
+#endif /* __S390_MMU_CONTEXT_H */
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h
index 363ea761d5e..05ea6f17278 100644
--- a/include/asm-s390/page.h
+++ b/include/asm-s390/page.h
@@ -127,6 +127,26 @@ page_get_storage_key(unsigned long addr)
return skey;
}
+extern unsigned long max_pfn;
+
+static inline int pfn_valid(unsigned long pfn)
+{
+ unsigned long dummy;
+ int ccode;
+
+ if (pfn >= max_pfn)
+ return 0;
+
+ asm volatile(
+ " lra %0,0(%2)\n"
+ " ipm %1\n"
+ " srl %1,28\n"
+ : "=d" (dummy), "=d" (ccode)
+ : "a" (pfn << PAGE_SHIFT)
+ : "cc");
+ return !ccode;
+}
+
#endif /* !__ASSEMBLY__ */
/* to align the pointer to the (next) page boundary */
@@ -138,8 +158,6 @@ page_get_storage_key(unsigned long addr)
#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)
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h
index 28619de5eca..56c8a6c80e2 100644
--- a/include/asm-s390/pgalloc.h
+++ b/include/asm-s390/pgalloc.h
@@ -25,8 +25,11 @@ extern void diag10(unsigned long addr);
* Page allocation orders.
*/
#ifndef __s390x__
+# define PTE_ALLOC_ORDER 0
+# define PMD_ALLOC_ORDER 0
# define PGD_ALLOC_ORDER 1
#else /* __s390x__ */
+# define PTE_ALLOC_ORDER 0
# define PMD_ALLOC_ORDER 2
# define PGD_ALLOC_ORDER 2
#endif /* __s390x__ */
@@ -44,6 +47,17 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
if (!pgd)
return NULL;
+ if (s390_noexec) {
+ pgd_t *shadow_pgd = (pgd_t *)
+ __get_free_pages(GFP_KERNEL, PGD_ALLOC_ORDER);
+ struct page *page = virt_to_page(pgd);
+
+ if (!shadow_pgd) {
+ free_pages((unsigned long) pgd, PGD_ALLOC_ORDER);
+ return NULL;
+ }
+ page->lru.next = (void *) shadow_pgd;
+ }
for (i = 0; i < PTRS_PER_PGD; i++)
#ifndef __s390x__
pmd_clear(pmd_offset(pgd + i, i*PGDIR_SIZE));
@@ -55,6 +69,10 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
static inline void pgd_free(pgd_t *pgd)
{
+ pgd_t *shadow_pgd = get_shadow_pgd(pgd);
+
+ if (shadow_pgd)
+ free_pages((unsigned long) shadow_pgd, PGD_ALLOC_ORDER);
free_pages((unsigned long) pgd, PGD_ALLOC_ORDER);
}
@@ -68,6 +86,7 @@ static inline void pgd_free(pgd_t *pgd)
#define pmd_free(x) do { } while (0)
#define __pmd_free_tlb(tlb,x) do { } while (0)
#define pgd_populate(mm, pmd, pte) BUG()
+#define pgd_populate_kernel(mm, pmd, pte) BUG()
#else /* __s390x__ */
static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
{
@@ -76,6 +95,17 @@ static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
if (!pmd)
return NULL;
+ if (s390_noexec) {
+ pmd_t *shadow_pmd = (pmd_t *)
+ __get_free_pages(GFP_KERNEL, PMD_ALLOC_ORDER);
+ struct page *page = virt_to_page(pmd);
+
+ if (!shadow_pmd) {
+ free_pages((unsigned long) pmd, PMD_ALLOC_ORDER);
+ return NULL;
+ }
+ page->lru.next = (void *) shadow_pmd;
+ }
for (i=0; i < PTRS_PER_PMD; i++)
pmd_clear(pmd + i);
return pmd;
@@ -83,6 +113,10 @@ static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
static inline void pmd_free (pmd_t *pmd)
{
+ pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+
+ if (shadow_pmd)
+ free_pages((unsigned long) shadow_pmd, PMD_ALLOC_ORDER);
free_pages((unsigned long) pmd, PMD_ALLOC_ORDER);
}
@@ -92,11 +126,22 @@ static inline void pmd_free (pmd_t *pmd)
pmd_free(pmd); \
} while (0)
-static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+static inline void
+pgd_populate_kernel(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
{
pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd);
}
+static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+{
+ pgd_t *shadow_pgd = get_shadow_pgd(pgd);
+ pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+
+ if (shadow_pgd && shadow_pmd)
+ pgd_populate_kernel(mm, shadow_pgd, shadow_pmd);
+ pgd_populate_kernel(mm, pgd, pmd);
+}
+
#endif /* __s390x__ */
static inline void
@@ -116,7 +161,13 @@ 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_to_phys(page));
+ pte_t *pte = (pte_t *)page_to_phys(page);
+ pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+ pte_t *shadow_pte = get_shadow_pte(pte);
+
+ pmd_populate_kernel(mm, pmd, pte);
+ if (shadow_pmd && shadow_pte)
+ pmd_populate_kernel(mm, shadow_pmd, shadow_pte);
}
/*
@@ -130,6 +181,17 @@ pte_alloc_one_kernel(struct mm_struct *mm, unsigned long vmaddr)
if (!pte)
return NULL;
+ if (s390_noexec) {
+ pte_t *shadow_pte = (pte_t *)
+ __get_free_page(GFP_KERNEL|__GFP_REPEAT);
+ struct page *page = virt_to_page(pte);
+
+ if (!shadow_pte) {
+ free_page((unsigned long) pte);
+ return NULL;
+ }
+ page->lru.next = (void *) shadow_pte;
+ }
for (i=0; i < PTRS_PER_PTE; i++) {
pte_clear(mm, vmaddr, pte + i);
vmaddr += PAGE_SIZE;
@@ -148,14 +210,30 @@ pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
static inline void pte_free_kernel(pte_t *pte)
{
- free_page((unsigned long) pte);
+ pte_t *shadow_pte = get_shadow_pte(pte);
+
+ if (shadow_pte)
+ free_page((unsigned long) shadow_pte);
+ free_page((unsigned long) pte);
}
static inline void pte_free(struct page *pte)
{
- __free_page(pte);
+ struct page *shadow_page = get_shadow_page(pte);
+
+ if (shadow_page)
+ __free_page(shadow_page);
+ __free_page(pte);
}
-#define __pte_free_tlb(tlb,pte) tlb_remove_page(tlb,pte)
+#define __pte_free_tlb(tlb, pte) \
+({ \
+ struct mmu_gather *__tlb = (tlb); \
+ struct page *__pte = (pte); \
+ struct page *shadow_page = get_shadow_page(__pte); \
+ if (shadow_page) \
+ tlb_remove_page(__tlb, shadow_page); \
+ tlb_remove_page(__tlb, __pte); \
+})
#endif /* _S390_PGALLOC_H */
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index 2d968a69ed1..13c16546eff 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -40,6 +40,7 @@ struct mm_struct;
extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
extern void paging_init(void);
+extern void vmem_map_init(void);
/*
* The S390 doesn't have any external MMU info: the kernel page
@@ -107,23 +108,25 @@ extern char empty_zero_page[PAGE_SIZE];
* The vmalloc() routines leaves a hole of 4kB between each vmalloced
* area for the same reason. ;)
*/
+extern unsigned long vmalloc_end;
#define VMALLOC_OFFSET (8*1024*1024)
#define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) \
& ~(VMALLOC_OFFSET-1))
+#define VMALLOC_END vmalloc_end
/*
* We need some free virtual space to be able to do vmalloc.
* VMALLOC_MIN_SIZE defines the minimum size of the vmalloc
* area. On a machine with 2GB memory we make sure that we
* have at least 128MB free space for vmalloc. On a machine
- * with 4TB we make sure we have at least 1GB.
+ * with 4TB we make sure we have at least 128GB.
*/
#ifndef __s390x__
#define VMALLOC_MIN_SIZE 0x8000000UL
-#define VMALLOC_END 0x80000000UL
+#define VMALLOC_END_INIT 0x80000000UL
#else /* __s390x__ */
-#define VMALLOC_MIN_SIZE 0x40000000UL
-#define VMALLOC_END 0x40000000000UL
+#define VMALLOC_MIN_SIZE 0x2000000000UL
+#define VMALLOC_END_INIT 0x40000000000UL
#endif /* __s390x__ */
/*
@@ -221,6 +224,8 @@ extern char empty_zero_page[PAGE_SIZE];
#define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */
#define _PAGE_TYPE_RO 0x200
#define _PAGE_TYPE_RW 0x000
+#define _PAGE_TYPE_EX_RO 0x202
+#define _PAGE_TYPE_EX_RW 0x002
/*
* PTE type bits are rather complicated. handle_pte_fault uses pte_present,
@@ -241,11 +246,13 @@ extern char empty_zero_page[PAGE_SIZE];
* _PAGE_TYPE_FILE 11?1 -> 11?1
* _PAGE_TYPE_RO 0100 -> 1100
* _PAGE_TYPE_RW 0000 -> 1000
+ * _PAGE_TYPE_EX_RO 0110 -> 1110
+ * _PAGE_TYPE_EX_RW 0010 -> 1010
*
- * pte_none is true for bits combinations 1000, 1100
+ * pte_none is true for bits combinations 1000, 1010, 1100, 1110
* 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.
+ * swap pte is 1011 and 0001, 0011, 0101, 0111 are invalid.
*/
#ifndef __s390x__
@@ -310,33 +317,100 @@ extern char empty_zero_page[PAGE_SIZE];
#define PAGE_NONE __pgprot(_PAGE_TYPE_NONE)
#define PAGE_RO __pgprot(_PAGE_TYPE_RO)
#define PAGE_RW __pgprot(_PAGE_TYPE_RW)
+#define PAGE_EX_RO __pgprot(_PAGE_TYPE_EX_RO)
+#define PAGE_EX_RW __pgprot(_PAGE_TYPE_EX_RW)
#define PAGE_KERNEL PAGE_RW
#define PAGE_COPY PAGE_RO
/*
- * The S390 can't do page protection for execute, and considers that the
- * same are read. Also, write permissions imply read permissions. This is
- * the closest we can get..
+ * Dependent on the EXEC_PROTECT option s390 can do execute protection.
+ * Write permission always implies read permission. In theory with a
+ * primary/secondary page table execute only can be implemented but
+ * it would cost an additional bit in the pte to distinguish all the
+ * different pte types. To avoid that execute permission currently
+ * implies read permission as well.
*/
/*xwr*/
#define __P000 PAGE_NONE
#define __P001 PAGE_RO
#define __P010 PAGE_RO
#define __P011 PAGE_RO
-#define __P100 PAGE_RO
-#define __P101 PAGE_RO
-#define __P110 PAGE_RO
-#define __P111 PAGE_RO
+#define __P100 PAGE_EX_RO
+#define __P101 PAGE_EX_RO
+#define __P110 PAGE_EX_RO
+#define __P111 PAGE_EX_RO
#define __S000 PAGE_NONE
#define __S001 PAGE_RO
#define __S010 PAGE_RW
#define __S011 PAGE_RW
-#define __S100 PAGE_RO
-#define __S101 PAGE_RO
-#define __S110 PAGE_RW
-#define __S111 PAGE_RW
+#define __S100 PAGE_EX_RO
+#define __S101 PAGE_EX_RO
+#define __S110 PAGE_EX_RW
+#define __S111 PAGE_EX_RW
+
+#ifndef __s390x__
+# define PMD_SHADOW_SHIFT 1
+# define PGD_SHADOW_SHIFT 1
+#else /* __s390x__ */
+# define PMD_SHADOW_SHIFT 2
+# define PGD_SHADOW_SHIFT 2
+#endif /* __s390x__ */
+
+static inline struct page *get_shadow_page(struct page *page)
+{
+ if (s390_noexec && !list_empty(&page->lru))
+ return virt_to_page(page->lru.next);
+ return NULL;
+}
+
+static inline pte_t *get_shadow_pte(pte_t *ptep)
+{
+ unsigned long pteptr = (unsigned long) (ptep);
+
+ if (s390_noexec) {
+ unsigned long offset = pteptr & (PAGE_SIZE - 1);
+ void *addr = (void *) (pteptr ^ offset);
+ struct page *page = virt_to_page(addr);
+ if (!list_empty(&page->lru))
+ return (pte_t *) ((unsigned long) page->lru.next |
+ offset);
+ }
+ return NULL;
+}
+
+static inline pmd_t *get_shadow_pmd(pmd_t *pmdp)
+{
+ unsigned long pmdptr = (unsigned long) (pmdp);
+
+ if (s390_noexec) {
+ unsigned long offset = pmdptr &
+ ((PAGE_SIZE << PMD_SHADOW_SHIFT) - 1);
+ void *addr = (void *) (pmdptr ^ offset);
+ struct page *page = virt_to_page(addr);
+ if (!list_empty(&page->lru))
+ return (pmd_t *) ((unsigned long) page->lru.next |
+ offset);
+ }
+ return NULL;
+}
+
+static inline pgd_t *get_shadow_pgd(pgd_t *pgdp)
+{
+ unsigned long pgdptr = (unsigned long) (pgdp);
+
+ if (s390_noexec) {
+ unsigned long offset = pgdptr &
+ ((PAGE_SIZE << PGD_SHADOW_SHIFT) - 1);
+ void *addr = (void *) (pgdptr ^ offset);
+ struct page *page = virt_to_page(addr);
+ if (!list_empty(&page->lru))
+ return (pgd_t *) ((unsigned long) page->lru.next |
+ offset);
+ }
+ return NULL;
+}
/*
* Certain architectures need to do special things when PTEs
@@ -345,7 +419,16 @@ extern char empty_zero_page[PAGE_SIZE];
*/
static inline void set_pte(pte_t *pteptr, pte_t pteval)
{
+ pte_t *shadow_pte = get_shadow_pte(pteptr);
+
*pteptr = pteval;
+ if (shadow_pte) {
+ if (!(pte_val(pteval) & _PAGE_INVALID) &&
+ (pte_val(pteval) & _PAGE_SWX))
+ pte_val(*shadow_pte) = pte_val(pteval) | _PAGE_RO;
+ else
+ pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY;
+ }
}
#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
@@ -463,7 +546,7 @@ static inline int pte_read(pte_t pte)
static inline void pgd_clear(pgd_t * pgdp) { }
-static inline void pmd_clear(pmd_t * pmdp)
+static inline void pmd_clear_kernel(pmd_t * pmdp)
{
pmd_val(pmdp[0]) = _PAGE_TABLE_INV;
pmd_val(pmdp[1]) = _PAGE_TABLE_INV;
@@ -471,24 +554,55 @@ static inline void pmd_clear(pmd_t * pmdp)
pmd_val(pmdp[3]) = _PAGE_TABLE_INV;
}
+static inline void pmd_clear(pmd_t * pmdp)
+{
+ pmd_t *shadow_pmd = get_shadow_pmd(pmdp);
+
+ pmd_clear_kernel(pmdp);
+ if (shadow_pmd)
+ pmd_clear_kernel(shadow_pmd);
+}
+
#else /* __s390x__ */
-static inline void pgd_clear(pgd_t * pgdp)
+static inline void pgd_clear_kernel(pgd_t * pgdp)
{
pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY;
}
-static inline void pmd_clear(pmd_t * pmdp)
+static inline void pgd_clear(pgd_t * pgdp)
+{
+ pgd_t *shadow_pgd = get_shadow_pgd(pgdp);
+
+ pgd_clear_kernel(pgdp);
+ if (shadow_pgd)
+ pgd_clear_kernel(shadow_pgd);
+}
+
+static inline void pmd_clear_kernel(pmd_t * pmdp)
{
pmd_val(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
pmd_val1(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
}
+static inline void pmd_clear(pmd_t * pmdp)
+{
+ pmd_t *shadow_pmd = get_shadow_pmd(pmdp);
+
+ pmd_clear_kernel(pmdp);
+ if (shadow_pmd)
+ pmd_clear_kernel(shadow_pmd);
+}
+
#endif /* __s390x__ */
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
+ pte_t *shadow_pte = get_shadow_pte(ptep);
+
pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+ if (shadow_pte)
+ pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY;
}
/*
@@ -606,8 +720,11 @@ ptep_clear_flush(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep)
{
pte_t pte = *ptep;
+ pte_t *shadow_pte = get_shadow_pte(ptep);
__ptep_ipte(address, ptep);
+ if (shadow_pte)
+ __ptep_ipte(address, shadow_pte);
return pte;
}
@@ -815,11 +932,17 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
#define kern_addr_valid(addr) (1)
+extern int add_shared_memory(unsigned long start, unsigned long size);
+extern int remove_shared_memory(unsigned long start, unsigned long size);
+
/*
* No page table caches to initialise
*/
#define pgtable_cache_init() do { } while (0)
+#define __HAVE_ARCH_MEMMAP_INIT
+extern void memmap_init(unsigned long, int, unsigned long, unsigned long);
+
#define __HAVE_ARCH_PTEP_ESTABLISH
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
diff --git a/include/asm-s390/posix_types.h b/include/asm-s390/posix_types.h
index b94c98856e1..397d93fba3a 100644
--- a/include/asm-s390/posix_types.h
+++ b/include/asm-s390/posix_types.h
@@ -104,7 +104,7 @@ static inline int __FD_ISSET(unsigned long fd, const __kernel_fd_set *fdsetp)
#undef __FD_ZERO
#define __FD_ZERO(fdsetp) \
- ((void) memset ((__ptr_t) (fdsetp), 0, sizeof (__kernel_fd_set)))
+ ((void) memset ((void *) (fdsetp), 0, sizeof (__kernel_fd_set)))
#endif /* __KERNEL__ */
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
index cbbedc63ba2..4c1b7394035 100644
--- a/include/asm-s390/processor.h
+++ b/include/asm-s390/processor.h
@@ -50,6 +50,7 @@ struct cpuinfo_S390
unsigned long pgtable_cache_sz;
};
+extern void s390_adjust_jiffies(void);
extern void print_cpu_info(struct cpuinfo_S390 *);
/* Lazy FPU handling on uni-processor */
@@ -144,7 +145,8 @@ struct stack_frame {
#ifndef __s390x__
#define start_thread(regs, new_psw, new_stackp) do { \
- regs->psw.mask = PSW_USER_BITS; \
+ set_fs(USER_DS); \
+ regs->psw.mask = psw_user_bits; \
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
regs->gprs[15] = new_stackp ; \
} while (0)
@@ -152,13 +154,15 @@ struct stack_frame {
#else /* __s390x__ */
#define start_thread(regs, new_psw, new_stackp) do { \
- regs->psw.mask = PSW_USER_BITS; \
+ set_fs(USER_DS); \
+ regs->psw.mask = psw_user_bits; \
regs->psw.addr = new_psw; \
regs->gprs[15] = new_stackp; \
} while (0)
#define start_thread31(regs, new_psw, new_stackp) do { \
- regs->psw.mask = PSW_USER32_BITS; \
+ set_fs(USER_DS); \
+ regs->psw.mask = psw_user32_bits; \
regs->psw.addr = new_psw; \
regs->gprs[15] = new_stackp; \
} while (0)
@@ -201,9 +205,8 @@ 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");
- else
- barrier();
+ asm volatile("diag 0,0,68");
+ barrier();
}
/*
@@ -328,6 +331,18 @@ static inline void disabled_wait(unsigned long code)
}
/*
+ * Basic Machine Check/Program Check Handler.
+ */
+
+extern void s390_base_mcck_handler(void);
+extern void s390_base_pgm_handler(void);
+extern void s390_base_ext_handler(void);
+
+extern void (*s390_base_mcck_handler_fn)(void);
+extern void (*s390_base_pgm_handler_fn)(void);
+extern void (*s390_base_ext_handler_fn)(void);
+
+/*
* CPU idle notifier chain.
*/
#define CPU_IDLE 0
diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
index 7b768c5c68a..fa6ca87080e 100644
--- a/include/asm-s390/ptrace.h
+++ b/include/asm-s390/ptrace.h
@@ -266,17 +266,12 @@ typedef struct
#define PSW_ASC_SECONDARY 0x0000800000000000UL
#define PSW_ASC_HOME 0x0000C00000000000UL
-#define PSW_USER32_BITS (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
- PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
- PSW_MASK_PSTATE | PSW_DEFAULT_KEY)
+extern long psw_user32_bits;
#endif /* __s390x__ */
-#define PSW_KERNEL_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \
- PSW_MASK_MCHECK | PSW_DEFAULT_KEY)
-#define PSW_USER_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
- PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
- PSW_MASK_PSTATE | PSW_DEFAULT_KEY)
+extern long psw_kernel_bits;
+extern long psw_user_bits;
/* This macro merges a NEW PSW mask specified by the user into
the currently active PSW mask CURRENT, modifying only those
diff --git a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h
index 7189c79bc67..127f72e7741 100644
--- a/include/asm-s390/qdio.h
+++ b/include/asm-s390/qdio.h
@@ -34,6 +34,7 @@
#define QDIO_QETH_QFMT 0
#define QDIO_ZFCP_QFMT 1
#define QDIO_IQDIO_QFMT 2
+#define QDIO_IQDIO_QFMT_ASYNCH 3
struct qdio_buffer_element{
unsigned int flags;
diff --git a/include/asm-s390/reset.h b/include/asm-s390/reset.h
index 9b439cf6780..f584f4a5258 100644
--- a/include/asm-s390/reset.h
+++ b/include/asm-s390/reset.h
@@ -18,6 +18,4 @@ struct reset_call {
extern void register_reset_call(struct reset_call *reset);
extern void unregister_reset_call(struct reset_call *reset);
extern void s390_reset_system(void);
-extern void (*s390_reset_mcck_handler)(void);
-
#endif /* _ASM_S390_RESET_H */
diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h
new file mode 100644
index 00000000000..468b9701840
--- /dev/null
+++ b/include/asm-s390/sclp.h
@@ -0,0 +1,39 @@
+/*
+ * include/asm-s390/sclp.h
+ *
+ * Copyright IBM Corp. 2007
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#ifndef _ASM_S390_SCLP_H
+#define _ASM_S390_SCLP_H
+
+#include <linux/types.h>
+
+struct sccb_header {
+ u16 length;
+ u8 function_code;
+ u8 control_mask[3];
+ u16 response_code;
+} __attribute__((packed));
+
+#define LOADPARM_LEN 8
+
+struct sclp_readinfo_sccb {
+ struct sccb_header header; /* 0-7 */
+ u16 rnmax; /* 8-9 */
+ u8 rnsize; /* 10 */
+ u8 _reserved0[24 - 11]; /* 11-23 */
+ u8 loadparm[LOADPARM_LEN]; /* 24-31 */
+ u8 _reserved1[91 - 32]; /* 32-90 */
+ u8 flags; /* 91 */
+ u8 _reserved2[100 - 92]; /* 92-99 */
+ u32 rnsize2; /* 100-103 */
+ u64 rnmax2; /* 104-111 */
+ u8 _reserved3[4096 - 112]; /* 112-4095 */
+} __attribute__((packed, aligned(4096)));
+
+extern struct sclp_readinfo_sccb s390_readinfo_sccb;
+extern void sclp_readinfo_early(void);
+
+#endif /* _ASM_S390_SCLP_H */
diff --git a/include/asm-s390/sections.h b/include/asm-s390/sections.h
index 3a0b8ffeab7..1c5a2c4ccda 100644
--- a/include/asm-s390/sections.h
+++ b/include/asm-s390/sections.h
@@ -3,4 +3,6 @@
#include <asm-generic/sections.h>
+extern char _eshared[];
+
#endif
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h
index 9574fe80a04..3388bb52597 100644
--- a/include/asm-s390/setup.h
+++ b/include/asm-s390/setup.h
@@ -42,6 +42,18 @@ struct mem_chunk {
extern struct mem_chunk memory_chunk[];
+#ifdef CONFIG_S390_SWITCH_AMODE
+extern unsigned int switch_amode;
+#else
+#define switch_amode (0)
+#endif
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+extern unsigned int s390_noexec;
+#else
+#define s390_noexec (0)
+#endif
+
/*
* Machine features detected in head.S
*/
@@ -74,6 +86,9 @@ extern unsigned int console_mode;
extern unsigned int console_devno;
extern unsigned int console_irq;
+extern char vmhalt_cmd[];
+extern char vmpoff_cmd[];
+
#define CONSOLE_IS_UNDEFINED (console_mode == 0)
#define CONSOLE_IS_SCLP (console_mode == 1)
#define CONSOLE_IS_3215 (console_mode == 2)
@@ -141,13 +156,19 @@ struct ipl_parameter_block {
extern u32 ipl_flags;
extern u16 ipl_devno;
-void do_reipl(void);
+extern void do_reipl(void);
+extern void ipl_save_parameters(void);
enum {
IPL_DEVNO_VALID = 1,
IPL_PARMBLOCK_VALID = 2,
+ IPL_NSS_VALID = 4,
};
+#define NSS_NAME_SIZE 8
+
+extern char kernel_nss_name[];
+
#define IPL_PARMBLOCK_START ((struct ipl_parameter_block *) \
IPL_PARMBLOCK_ORIGIN)
#define IPL_PARMBLOCK_SIZE (IPL_PARMBLOCK_START->hdr.len)
diff --git a/arch/s390/math-emu/sfp-util.h b/include/asm-s390/sfp-util.h
index 5b6ca4570ea..8cabcd23d97 100644
--- a/arch/s390/math-emu/sfp-util.h
+++ b/include/asm-s390/sfp-util.h
@@ -52,12 +52,12 @@
})
#define udiv_qrnnd(q, r, n1, n0, d) \
- do { unsigned long __r; \
+ do { unsigned int __r; \
(q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \
(r) = __r; \
} while (0)
-extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long,
- unsigned long , unsigned long);
+extern unsigned long __udiv_qrnnd (unsigned int *, unsigned int,
+ unsigned int , unsigned int);
#define UDIV_NEEDS_NORMALIZATION 0
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
index 7097c96ed02..b957e4cda46 100644
--- a/include/asm-s390/smp.h
+++ b/include/asm-s390/smp.h
@@ -31,6 +31,10 @@ typedef struct
__u16 cpu;
} sigp_info;
+extern void machine_restart_smp(char *);
+extern void machine_halt_smp(void);
+extern void machine_power_off_smp(void);
+
extern void smp_setup_cpu_possible_map(void);
extern int smp_call_function_on(void (*func) (void *info), void *info,
int nonatomic, int wait, int cpu);
@@ -106,7 +110,7 @@ smp_call_function_on(void (*func) (void *info), void *info,
static inline void smp_send_stop(void)
{
/* Disable all interrupts/machine checks */
- __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK);
+ __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
}
#define smp_cpu_not_running(cpu) 1
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index bd0b05ae87d..bbe137c3ed6 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -373,8 +373,8 @@ __set_psw_mask(unsigned long mask)
__load_psw_mask(mask | (__raw_local_irq_stosm(0x00) & ~(-1UL >> 8)));
}
-#define local_mcck_enable() __set_psw_mask(PSW_KERNEL_BITS)
-#define local_mcck_disable() __set_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK)
+#define local_mcck_enable() __set_psw_mask(psw_kernel_bits)
+#define local_mcck_disable() __set_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK)
#ifdef CONFIG_SMP
diff --git a/include/asm-s390/tape390.h b/include/asm-s390/tape390.h
index f1d66ba0dee..884fba48f1f 100644
--- a/include/asm-s390/tape390.h
+++ b/include/asm-s390/tape390.h
@@ -1,11 +1,11 @@
/*************************************************************************
*
* tape390.h
- * enables user programs to display messages on the tape device
+ * enables user programs to display messages and control encryption
+ * on s390 tape devices
*
- * S390 and zSeries version
- * Copyright (C) 2001 IBM Corporation
- * Author(s): Despina Papadopoulou <despina_p@de.ibm.com>
+ * Copyright IBM Corp. 2001,2006
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
*
*************************************************************************/
@@ -36,4 +36,68 @@ typedef struct display_struct {
char message2[8];
} display_struct;
+/*
+ * Tape encryption support
+ */
+
+struct tape390_crypt_info {
+ char capability;
+ char status;
+ char medium_status;
+} __attribute__ ((packed));
+
+
+/* Macros for "capable" field */
+#define TAPE390_CRYPT_SUPPORTED_MASK 0x01
+#define TAPE390_CRYPT_SUPPORTED(x) \
+ ((x.capability & TAPE390_CRYPT_SUPPORTED_MASK))
+
+/* Macros for "status" field */
+#define TAPE390_CRYPT_ON_MASK 0x01
+#define TAPE390_CRYPT_ON(x) (((x.status) & TAPE390_CRYPT_ON_MASK))
+
+/* Macros for "medium status" field */
+#define TAPE390_MEDIUM_LOADED_MASK 0x01
+#define TAPE390_MEDIUM_ENCRYPTED_MASK 0x02
+#define TAPE390_MEDIUM_ENCRYPTED(x) \
+ (((x.medium_status) & TAPE390_MEDIUM_ENCRYPTED_MASK))
+#define TAPE390_MEDIUM_LOADED(x) \
+ (((x.medium_status) & TAPE390_MEDIUM_LOADED_MASK))
+
+/*
+ * The TAPE390_CRYPT_SET ioctl is used to switch on/off encryption.
+ * The "encryption_capable" and "tape_status" fields are ignored for this ioctl!
+ */
+#define TAPE390_CRYPT_SET _IOW('d', 2, struct tape390_crypt_info)
+
+/*
+ * The TAPE390_CRYPT_QUERY ioctl is used to query the encryption state.
+ */
+#define TAPE390_CRYPT_QUERY _IOR('d', 3, struct tape390_crypt_info)
+
+/* Values for "kekl1/2_type" and "kekl1/2_type_on_tape" fields */
+#define TAPE390_KEKL_TYPE_NONE 0
+#define TAPE390_KEKL_TYPE_LABEL 1
+#define TAPE390_KEKL_TYPE_HASH 2
+
+struct tape390_kekl {
+ unsigned char type;
+ unsigned char type_on_tape;
+ char label[65];
+} __attribute__ ((packed));
+
+struct tape390_kekl_pair {
+ struct tape390_kekl kekl[2];
+} __attribute__ ((packed));
+
+/*
+ * The TAPE390_KEKL_SET ioctl is used to set Key Encrypting Key labels.
+ */
+#define TAPE390_KEKL_SET _IOW('d', 4, struct tape390_kekl_pair)
+
+/*
+ * The TAPE390_KEKL_QUERY ioctl is used to query Key Encrypting Key labels.
+ */
+#define TAPE390_KEKL_QUERY _IOR('d', 5, struct tape390_kekl_pair)
+
#endif
diff --git a/include/asm-s390/termbits.h b/include/asm-s390/termbits.h
index eb3f8bfabf6..585c78a6e40 100644
--- a/include/asm-s390/termbits.h
+++ b/include/asm-s390/termbits.h
@@ -25,6 +25,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-s390/timer.h b/include/asm-s390/timer.h
index 30e5cbe570f..adb34860a54 100644
--- a/include/asm-s390/timer.h
+++ b/include/asm-s390/timer.h
@@ -45,6 +45,9 @@ extern void add_virt_timer_periodic(void *new);
extern int mod_virt_timer(struct vtimer_list *timer, __u64 expires);
extern int del_virt_timer(struct vtimer_list *timer);
+extern void init_cpu_vtimer(void);
+extern void vtime_init(void);
+
#endif /* __KERNEL__ */
#endif /* _ASM_S390_TIMER_H */
diff --git a/include/asm-s390/timex.h b/include/asm-s390/timex.h
index 4df4a41029a..98229db2431 100644
--- a/include/asm-s390/timex.h
+++ b/include/asm-s390/timex.h
@@ -11,6 +11,41 @@
#ifndef _ASM_S390_TIMEX_H
#define _ASM_S390_TIMEX_H
+/* Inline functions for clock register access. */
+static inline int set_clock(__u64 time)
+{
+ int cc;
+
+ asm volatile(
+ " sck 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (cc) : "m" (time), "a" (&time) : "cc");
+ return cc;
+}
+
+static inline int store_clock(__u64 *time)
+{
+ int cc;
+
+ asm volatile(
+ " stck 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (cc), "=m" (*time) : "a" (time) : "cc");
+ return cc;
+}
+
+static inline void set_clock_comparator(__u64 time)
+{
+ asm volatile("sckc 0(%1)" : : "m" (time), "a" (&time));
+}
+
+static inline void store_clock_comparator(__u64 *time)
+{
+ asm volatile("stckc 0(%1)" : "=m" (*time) : "a" (time));
+}
+
#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
typedef unsigned long long cycles_t;
@@ -27,9 +62,24 @@ static inline unsigned long long get_clock (void)
return clk;
}
+static inline void get_clock_extended(void *dest)
+{
+ typedef struct { unsigned long long clk[2]; } __clock_t;
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+ asm volatile("stcke %0" : "=Q" (*((__clock_t *)dest)) : : "cc");
+#else /* __GNUC__ */
+ asm volatile("stcke 0(%1)" : "=m" (*((__clock_t *)dest))
+ : "a" ((__clock_t *)dest) : "cc");
+#endif /* __GNUC__ */
+}
+
static inline cycles_t get_cycles(void)
{
return (cycles_t) get_clock() >> 2;
}
+int get_sync_clock(unsigned long long *clock);
+void init_cpu_timer(void);
+
#endif
diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h
index fa4dc916a9b..66793f55c8b 100644
--- a/include/asm-s390/tlbflush.h
+++ b/include/asm-s390/tlbflush.h
@@ -3,6 +3,7 @@
#include <linux/mm.h>
#include <asm/processor.h>
+#include <asm/pgalloc.h>
/*
* TLB flushing:
@@ -102,6 +103,14 @@ static inline void __flush_tlb_mm(struct mm_struct * mm)
if (unlikely(cpus_empty(mm->cpu_vm_mask)))
return;
if (MACHINE_HAS_IDTE) {
+ pgd_t *shadow_pgd = get_shadow_pgd(mm->pgd);
+
+ if (shadow_pgd) {
+ asm volatile(
+ " .insn rrf,0xb98e0000,0,%0,%1,0"
+ : : "a" (2048),
+ "a" (__pa(shadow_pgd) & PAGE_MASK) : "cc" );
+ }
asm volatile(
" .insn rrf,0xb98e0000,0,%0,%1,0"
: : "a" (2048), "a" (__pa(mm->pgd)&PAGE_MASK) : "cc");
diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h
index 73ac4e82217..0235970278f 100644
--- a/include/asm-s390/uaccess.h
+++ b/include/asm-s390/uaccess.h
@@ -90,6 +90,8 @@ struct uaccess_ops {
extern struct uaccess_ops uaccess;
extern struct uaccess_ops uaccess_std;
extern struct uaccess_ops uaccess_mvcos;
+extern struct uaccess_ops uaccess_mvcos_switch;
+extern struct uaccess_ops uaccess_pt;
static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
{
diff --git a/include/asm-sh/apm.h b/include/asm-sh/apm.h
deleted file mode 100644
index 8b091e93651..00000000000
--- a/include/asm-sh/apm.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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-irq.h b/include/asm-sh/atomic-irq.h
new file mode 100644
index 00000000000..74f7943cff6
--- /dev/null
+++ b/include/asm-sh/atomic-irq.h
@@ -0,0 +1,71 @@
+#ifndef __ASM_SH_ATOMIC_IRQ_H
+#define __ASM_SH_ATOMIC_IRQ_H
+
+/*
+ * To get proper branch prediction for the main line, we must branch
+ * 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)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *(long *)v += i;
+ local_irq_restore(flags);
+}
+
+static inline void atomic_sub(int i, atomic_t *v)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *(long *)v -= i;
+ local_irq_restore(flags);
+}
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+ unsigned long temp, flags;
+
+ local_irq_save(flags);
+ temp = *(long *)v;
+ temp += i;
+ *(long *)v = temp;
+ local_irq_restore(flags);
+
+ return temp;
+}
+
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+ unsigned long temp, flags;
+
+ local_irq_save(flags);
+ temp = *(long *)v;
+ temp -= i;
+ *(long *)v = temp;
+ local_irq_restore(flags);
+
+ return temp;
+}
+
+static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *(long *)v &= ~mask;
+ local_irq_restore(flags);
+}
+
+static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *(long *)v |= mask;
+ local_irq_restore(flags);
+}
+
+#endif /* __ASM_SH_ATOMIC_IRQ_H */
diff --git a/include/asm-sh/atomic-llsc.h b/include/asm-sh/atomic-llsc.h
new file mode 100644
index 00000000000..4b00b78e3f4
--- /dev/null
+++ b/include/asm-sh/atomic-llsc.h
@@ -0,0 +1,107 @@
+#ifndef __ASM_SH_ATOMIC_LLSC_H
+#define __ASM_SH_ATOMIC_LLSC_H
+
+/*
+ * To get proper branch prediction for the main line, we must branch
+ * 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)
+{
+ unsigned long tmp;
+
+ __asm__ __volatile__ (
+"1: movli.l @%2, %0 ! atomic_add \n"
+" add %1, %0 \n"
+" movco.l %0, @%2 \n"
+" bf 1b \n"
+ : "=&z" (tmp)
+ : "r" (i), "r" (&v->counter)
+ : "t");
+}
+
+static inline void atomic_sub(int i, atomic_t *v)
+{
+ unsigned long tmp;
+
+ __asm__ __volatile__ (
+"1: movli.l @%2, %0 ! atomic_sub \n"
+" sub %1, %0 \n"
+" movco.l %0, @%2 \n"
+" bf 1b \n"
+ : "=&z" (tmp)
+ : "r" (i), "r" (&v->counter)
+ : "t");
+}
+
+/*
+ * 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;
+
+ __asm__ __volatile__ (
+"1: movli.l @%2, %0 ! atomic_add_return \n"
+" add %1, %0 \n"
+" movco.l %0, @%2 \n"
+" bf 1b \n"
+" synco \n"
+ : "=&z" (temp)
+ : "r" (i), "r" (&v->counter)
+ : "t");
+
+ return temp;
+}
+
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+ unsigned long temp;
+
+ __asm__ __volatile__ (
+"1: movli.l @%2, %0 ! atomic_sub_return \n"
+" sub %1, %0 \n"
+" movco.l %0, @%2 \n"
+" bf 1b \n"
+" synco \n"
+ : "=&z" (temp)
+ : "r" (i), "r" (&v->counter)
+ : "t");
+
+ return temp;
+}
+
+static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
+{
+ unsigned long tmp;
+
+ __asm__ __volatile__ (
+"1: movli.l @%2, %0 ! atomic_clear_mask \n"
+" and %1, %0 \n"
+" movco.l %0, @%2 \n"
+" bf 1b \n"
+ : "=&z" (tmp)
+ : "r" (~mask), "r" (&v->counter)
+ : "t");
+}
+
+static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
+{
+ unsigned long tmp;
+
+ __asm__ __volatile__ (
+"1: movli.l @%2, %0 ! atomic_set_mask \n"
+" or %1, %0 \n"
+" movco.l %0, @%2 \n"
+" bf 1b \n"
+ : "=&z" (tmp)
+ : "r" (mask), "r" (&v->counter)
+ : "t");
+}
+
+#endif /* __ASM_SH_ATOMIC_LLSC_H */
diff --git a/include/asm-sh/atomic.h b/include/asm-sh/atomic.h
index 28305c3cbdd..e12570b9339 100644
--- a/include/asm-sh/atomic.h
+++ b/include/asm-sh/atomic.h
@@ -17,119 +17,14 @@ typedef struct { volatile int counter; } atomic_t;
#include <linux/compiler.h>
#include <asm/system.h>
-/*
- * To get proper branch prediction for the main line, we must branch
- * 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)
-{
#ifdef CONFIG_CPU_SH4A
- unsigned long tmp;
-
- __asm__ __volatile__ (
-"1: movli.l @%2, %0 ! atomic_add \n"
-" add %1, %0 \n"
-" movco.l %0, @%2 \n"
-" bf 1b \n"
- : "=&z" (tmp)
- : "r" (i), "r" (&v->counter)
- : "t");
+#include <asm/atomic-llsc.h>
#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)
-{
-#ifdef CONFIG_CPU_SH4A
- unsigned long tmp;
-
- __asm__ __volatile__ (
-"1: movli.l @%2, %0 ! atomic_sub \n"
-" sub %1, %0 \n"
-" movco.l %0, @%2 \n"
-" bf 1b \n"
- : "=&z" (tmp)
- : "r" (i), "r" (&v->counter)
- : "t");
-#else
- unsigned long flags;
-
- local_irq_save(flags);
- *(long *)v -= i;
- local_irq_restore(flags);
+#include <asm/atomic-irq.h>
#endif
-}
-
-/*
- * 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;
-
-#ifdef CONFIG_CPU_SH4A
- __asm__ __volatile__ (
-"1: movli.l @%2, %0 ! atomic_add_return \n"
-" add %1, %0 \n"
-" movco.l %0, @%2 \n"
-" bf 1b \n"
-" synco \n"
- : "=&z" (temp)
- : "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)
-{
- unsigned long temp;
-
-#ifdef CONFIG_CPU_SH4A
- __asm__ __volatile__ (
-"1: movli.l @%2, %0 ! atomic_sub_return \n"
-" sub %1, %0 \n"
-" movco.l %0, @%2 \n"
-" bf 1b \n"
-" synco \n"
- : "=&z" (temp)
- : "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_dec_return(v) atomic_sub_return(1,(v))
#define atomic_inc_return(v) atomic_add_return(1,(v))
@@ -180,50 +75,6 @@ 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)
-{
-#ifdef CONFIG_CPU_SH4A
- unsigned long tmp;
-
- __asm__ __volatile__ (
-"1: movli.l @%2, %0 ! atomic_clear_mask \n"
-" and %1, %0 \n"
-" movco.l %0, @%2 \n"
-" bf 1b \n"
- : "=&z" (tmp)
- : "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)
-{
-#ifdef CONFIG_CPU_SH4A
- unsigned long tmp;
-
- __asm__ __volatile__ (
-"1: movli.l @%2, %0 ! atomic_set_mask \n"
-" or %1, %0 \n"
-" movco.l %0, @%2 \n"
-" bf 1b \n"
- : "=&z" (tmp)
- : "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 */
#define smp_mb__before_atomic_dec() barrier()
#define smp_mb__after_atomic_dec() barrier()
diff --git a/include/asm-sh/bug.h b/include/asm-sh/bug.h
index 1b4fc52a59e..2f89dd06d0c 100644
--- a/include/asm-sh/bug.h
+++ b/include/asm-sh/bug.h
@@ -1,19 +1,54 @@
#ifndef __ASM_SH_BUG_H
#define __ASM_SH_BUG_H
-
#ifdef CONFIG_BUG
-/*
- * Tell the user there is some problem.
- */
-#define BUG() do { \
- printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
- *(volatile int *)0 = 0; \
+
+struct bug_frame {
+ unsigned short opcode;
+ unsigned short line;
+ const char *file;
+ const char *func;
+};
+
+struct pt_regs;
+
+extern void handle_BUG(struct pt_regs *);
+
+#define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+
+#define BUG() \
+do { \
+ __asm__ __volatile__ ( \
+ ".align 2\n\t" \
+ ".short %O0\n\t" \
+ ".short %O1\n\t" \
+ ".long %O2\n\t" \
+ ".long %O3\n\t" \
+ : \
+ : "n" (TRAPA_BUG_OPCODE), \
+ "i" (__LINE__), "X" (__FILE__), \
+ "X" (__FUNCTION__)); \
+} while (0)
+
+#else
+
+#define BUG() \
+do { \
+ __asm__ __volatile__ ( \
+ ".align 2\n\t" \
+ ".short %O0\n\t" \
+ : \
+ : "n" (TRAPA_BUG_OPCODE)); \
} while (0)
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
+
#define HAVE_ARCH_BUG
-#endif
+
+#endif /* CONFIG_BUG */
#include <asm-generic/bug.h>
-#endif
+#endif /* __ASM_SH_BUG_H */
diff --git a/include/asm-sh/bugs.h b/include/asm-sh/bugs.h
index 795047da5e1..a294997a841 100644
--- a/include/asm-sh/bugs.h
+++ b/include/asm-sh/bugs.h
@@ -16,9 +16,8 @@
static void __init check_bugs(void)
{
- extern char *get_cpu_subtype(void);
extern unsigned long loops_per_jiffy;
- char *p= &init_utsname()->machine[2]; /* "sh" */
+ char *p = &init_utsname()->machine[2]; /* "sh" */
cpu_data->loops_per_jiffy = loops_per_jiffy;
@@ -40,6 +39,15 @@ static void __init check_bugs(void)
*p++ = '4';
*p++ = 'a';
break;
+ case CPU_SH73180 ... CPU_SH7722:
+ *p++ = '4';
+ *p++ = 'a';
+ *p++ = 'l';
+ *p++ = '-';
+ *p++ = 'd';
+ *p++ = 's';
+ *p++ = 'p';
+ break;
default:
*p++ = '?';
*p++ = '!';
diff --git a/include/asm-sh/checksum.h b/include/asm-sh/checksum.h
index d44344c88e7..4bc8357e889 100644
--- a/include/asm-sh/checksum.h
+++ b/include/asm-sh/checksum.h
@@ -34,25 +34,26 @@ asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
*/
asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,
- int len, __wsum sum, int *src_err_ptr, int *dst_err_ptr);
+ int len, __wsum sum,
+ int *src_err_ptr, int *dst_err_ptr);
/*
* Note: when you get a NULL pointer exception here this means someone
- * passed in an incorrect kernel address to one of these functions.
- *
- * If you use these functions directly please don't forget the
+ * passed in an incorrect kernel address to one of these functions.
+ *
+ * If you use these functions directly please don't forget the
* access_ok().
*/
-static __inline__
+static inline
__wsum csum_partial_copy_nocheck(const void *src, void *dst,
- int len, __wsum sum)
+ int len, __wsum sum)
{
- return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
+ return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL);
}
-static __inline__
+static inline
__wsum csum_partial_copy_from_user(const void __user *src, void *dst,
- int len, __wsum sum, int *err_ptr)
+ int len, __wsum sum, int *err_ptr)
{
return csum_partial_copy_generic((__force const void *)src, dst,
len, sum, err_ptr, NULL);
@@ -62,7 +63,7 @@ __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
* Fold a partial checksum
*/
-static __inline__ __sum16 csum_fold(__wsum sum)
+static inline __sum16 csum_fold(__wsum sum)
{
unsigned int __dummy;
__asm__("swap.w %0, %1\n\t"
@@ -85,7 +86,7 @@ static __inline__ __sum16 csum_fold(__wsum sum)
* i386 version by Jorge Cwik <jorge@laser.satlink.net>, adapted
* for linux by * Arnt Gulbrandsen.
*/
-static __inline__ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
unsigned int sum, __dummy0, __dummy1;
@@ -113,10 +114,10 @@ static __inline__ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
return csum_fold(sum);
}
-static __inline__ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
- unsigned short len,
- unsigned short proto,
- __wsum sum)
+static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
+ unsigned short len,
+ unsigned short proto,
+ __wsum sum)
{
#ifdef __LITTLE_ENDIAN__
unsigned long len_proto = (proto + len) << 8;
@@ -132,6 +133,7 @@ static __inline__ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
: "=r" (sum), "=r" (len_proto)
: "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum)
: "t");
+
return sum;
}
@@ -139,30 +141,28 @@ static __inline__ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
* computes the checksum of the TCP/UDP pseudo-header
* returns a 16-bit checksum, already complemented
*/
-static __inline__ __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
- unsigned short len,
- unsigned short proto,
- __wsum sum)
+static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
+ unsigned short len,
+ unsigned short proto,
+ __wsum sum)
{
- return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+ return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
}
/*
* this routine is used for miscellaneous IP-like checksums, mainly
* in icmp.c
*/
-
-static __inline__ __sum16 ip_compute_csum(const void *buff, int len)
+static inline __sum16 ip_compute_csum(const void *buff, int len)
{
- return csum_fold (csum_partial(buff, len, 0));
+ return csum_fold(csum_partial(buff, len, 0));
}
#define _HAVE_ARCH_IPV6_CSUM
-#ifdef CONFIG_IPV6
-static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
- const struct in6_addr *daddr,
- __u32 len, unsigned short proto,
- __wsum sum)
+static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+ const struct in6_addr *daddr,
+ __u32 len, unsigned short proto,
+ __wsum sum)
{
unsigned int __dummy;
__asm__("clrt\n\t"
@@ -187,22 +187,21 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
"movt %1\n\t"
"add %1, %0\n"
: "=r" (sum), "=&r" (__dummy)
- : "r" (saddr), "r" (daddr),
+ : "r" (saddr), "r" (daddr),
"r" (htonl(len)), "r" (htonl(proto)), "0" (sum)
: "t");
return csum_fold(sum);
}
-#endif
-/*
+/*
* Copy and checksum to user
*/
#define HAVE_CSUM_COPY_USER
-static __inline__ __wsum csum_and_copy_to_user (const void *src,
- void __user *dst,
- int len, __wsum sum,
- int *err_ptr)
+static inline __wsum csum_and_copy_to_user(const void *src,
+ void __user *dst,
+ int len, __wsum sum,
+ int *err_ptr)
{
if (access_ok(VERIFY_WRITE, dst, len))
return csum_partial_copy_generic((__force const void *)src,
diff --git a/include/asm-sh/cpu-sh2/cacheflush.h b/include/asm-sh/cpu-sh2/cacheflush.h
index f556fa80ea9..2979efb26de 100644
--- a/include/asm-sh/cpu-sh2/cacheflush.h
+++ b/include/asm-sh/cpu-sh2/cacheflush.h
@@ -15,6 +15,7 @@
*
* - flush_cache_all() flushes entire cache
* - flush_cache_mm(mm) flushes the specified mm context's cache lines
+ * - flush_cache_dup mm(mm) handles cache flushing when forking
* - flush_cache_page(mm, vmaddr, pfn) flushes a single page
* - flush_cache_range(vma, start, end) flushes a range of pages
*
@@ -27,6 +28,7 @@
*/
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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)
diff --git a/include/asm-sh/cpu-sh3/cacheflush.h b/include/asm-sh/cpu-sh3/cacheflush.h
index 03fde97a7fd..f70d8ef76a1 100644
--- a/include/asm-sh/cpu-sh3/cacheflush.h
+++ b/include/asm-sh/cpu-sh3/cacheflush.h
@@ -15,6 +15,7 @@
*
* - flush_cache_all() flushes entire cache
* - flush_cache_mm(mm) flushes the specified mm context's cache lines
+ * - flush_cache_dup mm(mm) handles cache flushing when forking
* - flush_cache_page(mm, vmaddr, pfn) flushes a single page
* - flush_cache_range(vma, start, end) flushes a range of pages
*
@@ -39,6 +40,7 @@
void flush_cache_all(void);
void flush_cache_mm(struct mm_struct *mm);
+#define flush_cache_dup_mm(mm) flush_cache_mm(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);
@@ -48,6 +50,7 @@ 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_dup_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)
diff --git a/include/asm-sh/cpu-sh4/cache.h b/include/asm-sh/cpu-sh4/cache.h
index 6e9c7e6ee8e..f92b20a0983 100644
--- a/include/asm-sh/cpu-sh4/cache.h
+++ b/include/asm-sh/cpu-sh4/cache.h
@@ -22,7 +22,7 @@
#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
+#ifndef CONFIG_CPU_SH4A
#define CCR_CACHE_EMODE 0x80000000 /* EMODE Enable */
#endif
diff --git a/include/asm-sh/cpu-sh4/cacheflush.h b/include/asm-sh/cpu-sh4/cacheflush.h
index 515fd574267..b01a10f3122 100644
--- a/include/asm-sh/cpu-sh4/cacheflush.h
+++ b/include/asm-sh/cpu-sh4/cacheflush.h
@@ -18,6 +18,7 @@
*/
void flush_cache_all(void);
void flush_cache_mm(struct mm_struct *mm);
+#define flush_cache_dup_mm(mm) flush_cache_mm(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,
diff --git a/include/asm-sh/cpu-sh4/freq.h b/include/asm-sh/cpu-sh4/freq.h
index ef2b9b1ae41..602d061ca2d 100644
--- a/include/asm-sh/cpu-sh4/freq.h
+++ b/include/asm-sh/cpu-sh4/freq.h
@@ -10,7 +10,7 @@
#ifndef __ASM_CPU_SH4_FREQ_H
#define __ASM_CPU_SH4_FREQ_H
-#if defined(CONFIG_CPU_SUBTYPE_SH73180)
+#if defined(CONFIG_CPU_SUBTYPE_SH73180) || defined(CONFIG_CPU_SUBTYPE_SH7722)
#define FRQCR 0xa4150000
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
#define FRQCR 0xffc80000
diff --git a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h
index 37ab0c131a4..8d0867b98e0 100644
--- a/include/asm-sh/dma-mapping.h
+++ b/include/asm-sh/dma-mapping.h
@@ -67,7 +67,7 @@ static inline dma_addr_t dma_map_single(struct device *dev,
if (dev->bus == &pci_bus_type)
return virt_to_bus(ptr);
#endif
- dma_cache_sync(ptr, size, dir);
+ dma_cache_sync(dev, ptr, size, dir);
return virt_to_bus(ptr);
}
@@ -81,7 +81,7 @@ static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
for (i = 0; i < nents; i++) {
#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+ dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
sg[i].length, dir);
#endif
sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
@@ -112,7 +112,7 @@ static inline void dma_sync_single(struct device *dev, dma_addr_t dma_handle,
if (dev->bus == &pci_bus_type)
return;
#endif
- dma_cache_sync(bus_to_virt(dma_handle), size, dir);
+ dma_cache_sync(dev, bus_to_virt(dma_handle), size, dir);
}
static inline void dma_sync_single_range(struct device *dev,
@@ -124,7 +124,7 @@ static inline void dma_sync_single_range(struct device *dev,
if (dev->bus == &pci_bus_type)
return;
#endif
- dma_cache_sync(bus_to_virt(dma_handle) + offset, size, dir);
+ dma_cache_sync(dev, bus_to_virt(dma_handle) + offset, size, dir);
}
static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
@@ -134,7 +134,7 @@ static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
for (i = 0; i < nelems; i++) {
#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+ dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
sg[i].length, dir);
#endif
sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h
index fd576088e47..bff965ef4b9 100644
--- a/include/asm-sh/irq.h
+++ b/include/asm-sh/irq.h
@@ -37,7 +37,8 @@
# define ONCHIP_NR_IRQS 144
#elif defined(CONFIG_CPU_SUBTYPE_SH7300) || \
defined(CONFIG_CPU_SUBTYPE_SH73180) || \
- defined(CONFIG_CPU_SUBTYPE_SH7343)
+ defined(CONFIG_CPU_SUBTYPE_SH7343) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7722)
# define ONCHIP_NR_IRQS 109
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
# define ONCHIP_NR_IRQS 111
@@ -79,6 +80,8 @@
# define OFFCHIP_NR_IRQS 16
#elif defined(CONFIG_SH_7343_SOLUTION_ENGINE)
# define OFFCHIP_NR_IRQS 12
+#elif defined(CONFIG_SH_7722_SOLUTION_ENGINE)
+# define OFFCHIP_NR_IRQS 14
#elif defined(CONFIG_SH_UNKNOWN)
# define OFFCHIP_NR_IRQS 16 /* Must also be last */
#else
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
index c84901dbd8e..036ca284386 100644
--- a/include/asm-sh/pgtable.h
+++ b/include/asm-sh/pgtable.h
@@ -508,16 +508,50 @@ struct vm_area_struct;
extern void update_mmu_cache(struct vm_area_struct * vma,
unsigned long address, pte_t pte);
-/* Encode and de-code a swap entry */
/*
+ * Encode and de-code a swap entry
+ *
+ * Constraints:
+ * _PAGE_FILE at bit 0
+ * _PAGE_PRESENT at bit 8
+ * _PAGE_PROTNONE at bit 9
+ *
+ * For the normal case, we encode the swap type into bits 0:7 and the
+ * swap offset into bits 10:30. For the 64-bit PTE case, we keep the
+ * preserved bits in the low 32-bits and use the upper 32 as the swap
+ * offset (along with a 5-bit type), following the same approach as x86
+ * PAE. This keeps the logic quite simple, and allows for a full 32
+ * PTE_FILE_MAX_BITS, as opposed to the 29-bits we're constrained with
+ * in the pte_low case.
+ *
+ * As is evident by the Alpha code, if we ever get a 64-bit unsigned
+ * long (swp_entry_t) to match up with the 64-bit PTEs, this all becomes
+ * much cleaner..
+ *
* NOTE: We should set ZEROs at the position of _PAGE_PRESENT
* and _PAGE_PROTNONE bits
*/
-#define __swp_type(x) ((x).val & 0xff)
-#define __swp_offset(x) ((x).val >> 10)
-#define __swp_entry(type, offset) ((swp_entry_t) { (type) | ((offset) << 10) })
-#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 1 })
-#define __swp_entry_to_pte(x) ((pte_t) { (x).val << 1 })
+#ifdef CONFIG_X2TLB
+#define __swp_type(x) ((x).val & 0x1f)
+#define __swp_offset(x) ((x).val >> 5)
+#define __swp_entry(type, offset) ((swp_entry_t){ (type) | (offset) << 5})
+#define __pte_to_swp_entry(pte) ((swp_entry_t){ (pte).pte_high })
+#define __swp_entry_to_pte(x) ((pte_t){ 0, (x).val })
+
+/*
+ * Encode and decode a nonlinear file mapping entry
+ */
+#define pte_to_pgoff(pte) ((pte).pte_high)
+#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) })
+
+#define PTE_FILE_MAX_BITS 32
+#else
+#define __swp_type(x) ((x).val & 0xff)
+#define __swp_offset(x) ((x).val >> 10)
+#define __swp_entry(type, offset) ((swp_entry_t){(type) | (offset) <<10})
+
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 1 })
+#define __swp_entry_to_pte(x) ((pte_t) { (x).val << 1 })
/*
* Encode and decode a nonlinear file mapping entry
@@ -525,6 +559,7 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
#define PTE_FILE_MAX_BITS 29
#define pte_to_pgoff(pte) (pte_val(pte) >> 1)
#define pgoff_to_pte(off) ((pte_t) { ((off) << 1) | _PAGE_FILE })
+#endif
typedef pte_t *pte_addr_t;
diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h
index 6f1dd7ca1b1..e29f2abb92d 100644
--- a/include/asm-sh/processor.h
+++ b/include/asm-sh/processor.h
@@ -27,6 +27,8 @@
#define CCN_CVR 0xff000040
#define CCN_PRR 0xff000044
+const char *get_cpu_subtype(void);
+
/*
* CPU type and hardware bug flags. Kept separately for each CPU.
*
@@ -52,8 +54,10 @@ enum cpu_type {
CPU_SH7760, CPU_ST40RA, CPU_ST40GX1, CPU_SH4_202, CPU_SH4_501,
/* SH-4A types */
- CPU_SH73180, CPU_SH7343, CPU_SH7770, CPU_SH7780, CPU_SH7781,
- CPU_SH7785,
+ CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785,
+
+ /* SH4AL-DSP types */
+ CPU_SH73180, CPU_SH7343, CPU_SH7722,
/* Unknown subtype */
CPU_SH_NONE
diff --git a/include/asm-sh/push-switch.h b/include/asm-sh/push-switch.h
index dfc6bad567f..4903f9e52dd 100644
--- a/include/asm-sh/push-switch.h
+++ b/include/asm-sh/push-switch.h
@@ -4,6 +4,7 @@
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
+#include <linux/platform_device.h>
struct push_switch {
/* switch state */
@@ -12,6 +13,8 @@ struct push_switch {
struct timer_list debounce;
/* workqueue */
struct work_struct work;
+ /* platform device, for workqueue handler */
+ struct platform_device *pdev;
};
struct push_switch_platform_info {
diff --git a/include/asm-sh/termbits.h b/include/asm-sh/termbits.h
index 4f9822a8e7b..f1b7b46f4e9 100644
--- a/include/asm-sh/termbits.h
+++ b/include/asm-sh/termbits.h
@@ -17,6 +17,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h
index 0c01dc55081..879f741105d 100644
--- a/include/asm-sh/thread_info.h
+++ b/include/asm-sh/thread_info.h
@@ -106,6 +106,7 @@ static inline struct thread_info *current_thread_info(void)
#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_FREEZE 19
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
@@ -114,6 +115,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+#define _TIF_FREEZE (1<<TIF_FREEZE)
#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-sh64/cacheflush.h b/include/asm-sh64/cacheflush.h
index 55f71aa0aa6..1e53a47bdc9 100644
--- a/include/asm-sh64/cacheflush.h
+++ b/include/asm-sh64/cacheflush.h
@@ -21,6 +21,8 @@ extern void flush_icache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long addr,
int len);
+#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
+
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
diff --git a/include/asm-sh64/pgalloc.h b/include/asm-sh64/pgalloc.h
index b29dd468817..cb803e56cb6 100644
--- a/include/asm-sh64/pgalloc.h
+++ b/include/asm-sh64/pgalloc.h
@@ -41,7 +41,7 @@ static inline void pgd_init(unsigned long page)
static inline pgd_t *get_pgd_slow(void)
{
unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t));
- pgd_t *ret = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL);
+ pgd_t *ret = kmalloc(pgd_size, GFP_KERNEL);
return ret;
}
diff --git a/include/asm-sparc/bitops.h b/include/asm-sparc/bitops.h
index 04aa3318f76..329e696e775 100644
--- a/include/asm-sparc/bitops.h
+++ b/include/asm-sparc/bitops.h
@@ -14,6 +14,10 @@
#ifdef __KERNEL__
+extern unsigned long ___set_bit(unsigned long *addr, unsigned long mask);
+extern unsigned long ___clear_bit(unsigned long *addr, unsigned long mask);
+extern unsigned long ___change_bit(unsigned long *addr, unsigned long mask);
+
/*
* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
* is in the highest of the four bytes and bit '31' is the high bit
@@ -22,134 +26,62 @@
*/
static inline int test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
{
- register unsigned long mask asm("g2");
- register unsigned long *ADDR asm("g1");
- register int tmp1 asm("g3");
- register int tmp2 asm("g4");
- register int tmp3 asm("g5");
- register int tmp4 asm("g7");
+ unsigned long *ADDR, mask;
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
- __asm__ __volatile__(
- "mov %%o7, %%g4\n\t"
- "call ___set_bit\n\t"
- " add %%o7, 8, %%o7\n"
- : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
- : "0" (mask), "r" (ADDR)
- : "memory", "cc");
-
- return mask != 0;
+ return ___set_bit(ADDR, mask) != 0;
}
static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
{
- register unsigned long mask asm("g2");
- register unsigned long *ADDR asm("g1");
- register int tmp1 asm("g3");
- register int tmp2 asm("g4");
- register int tmp3 asm("g5");
- register int tmp4 asm("g7");
+ unsigned long *ADDR, mask;
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
- __asm__ __volatile__(
- "mov %%o7, %%g4\n\t"
- "call ___set_bit\n\t"
- " add %%o7, 8, %%o7\n"
- : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
- : "0" (mask), "r" (ADDR)
- : "memory", "cc");
+ (void) ___set_bit(ADDR, mask);
}
static inline int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
{
- register unsigned long mask asm("g2");
- register unsigned long *ADDR asm("g1");
- register int tmp1 asm("g3");
- register int tmp2 asm("g4");
- register int tmp3 asm("g5");
- register int tmp4 asm("g7");
+ unsigned long *ADDR, mask;
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
- __asm__ __volatile__(
- "mov %%o7, %%g4\n\t"
- "call ___clear_bit\n\t"
- " add %%o7, 8, %%o7\n"
- : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
- : "0" (mask), "r" (ADDR)
- : "memory", "cc");
-
- return mask != 0;
+ return ___clear_bit(ADDR, mask) != 0;
}
static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
{
- register unsigned long mask asm("g2");
- register unsigned long *ADDR asm("g1");
- register int tmp1 asm("g3");
- register int tmp2 asm("g4");
- register int tmp3 asm("g5");
- register int tmp4 asm("g7");
+ unsigned long *ADDR, mask;
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
- __asm__ __volatile__(
- "mov %%o7, %%g4\n\t"
- "call ___clear_bit\n\t"
- " add %%o7, 8, %%o7\n"
- : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
- : "0" (mask), "r" (ADDR)
- : "memory", "cc");
+ (void) ___clear_bit(ADDR, mask);
}
static inline int test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
{
- register unsigned long mask asm("g2");
- register unsigned long *ADDR asm("g1");
- register int tmp1 asm("g3");
- register int tmp2 asm("g4");
- register int tmp3 asm("g5");
- register int tmp4 asm("g7");
+ unsigned long *ADDR, mask;
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
- __asm__ __volatile__(
- "mov %%o7, %%g4\n\t"
- "call ___change_bit\n\t"
- " add %%o7, 8, %%o7\n"
- : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
- : "0" (mask), "r" (ADDR)
- : "memory", "cc");
-
- return mask != 0;
+ return ___change_bit(ADDR, mask) != 0;
}
static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
{
- register unsigned long mask asm("g2");
- register unsigned long *ADDR asm("g1");
- register int tmp1 asm("g3");
- register int tmp2 asm("g4");
- register int tmp3 asm("g5");
- register int tmp4 asm("g7");
+ unsigned long *ADDR, mask;
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
- __asm__ __volatile__(
- "mov %%o7, %%g4\n\t"
- "call ___change_bit\n\t"
- " add %%o7, 8, %%o7\n"
- : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
- : "0" (mask), "r" (ADDR)
- : "memory", "cc");
+ (void) ___change_bit(ADDR, mask);
}
#include <asm-generic/bitops/non-atomic.h>
diff --git a/include/asm-sparc/cacheflush.h b/include/asm-sparc/cacheflush.h
index fc632f811cd..68ac1091027 100644
--- a/include/asm-sparc/cacheflush.h
+++ b/include/asm-sparc/cacheflush.h
@@ -48,6 +48,7 @@ BTFIXUPDEF_CALL(void, flush_cache_page, struct vm_area_struct *, unsigned long)
#define flush_cache_all() BTFIXUP_CALL(flush_cache_all)()
#define flush_cache_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm)
+#define flush_cache_dup_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm)
#define flush_cache_range(vma,start,end) BTFIXUP_CALL(flush_cache_range)(vma,start,end)
#define flush_cache_page(vma,addr,pfn) BTFIXUP_CALL(flush_cache_page)(vma,addr)
#define flush_icache_range(start, end) do { } while (0)
diff --git a/include/asm-sparc/checksum.h b/include/asm-sparc/checksum.h
index 267e631e9bb..34518ea7bf1 100644
--- a/include/asm-sparc/checksum.h
+++ b/include/asm-sparc/checksum.h
@@ -151,7 +151,7 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
"xnor\t%%g0, %0, %0"
: "=r" (sum), "=&r" (iph)
: "r" (ihl), "1" (iph)
- : "g2", "g3", "g4", "cc");
+ : "g2", "g3", "g4", "cc", "memory");
return sum;
}
diff --git a/include/asm-sparc/of_device.h b/include/asm-sparc/of_device.h
index 80ea31f6e17..7cb00c1b09c 100644
--- a/include/asm-sparc/of_device.h
+++ b/include/asm-sparc/of_device.h
@@ -33,7 +33,7 @@ struct of_device
#define to_of_device(d) container_of(d, struct of_device, dev)
extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
-extern void of_iounmap(void __iomem *base, unsigned long size);
+extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
extern struct of_device *of_find_device_by_node(struct device_node *);
diff --git a/include/asm-sparc/termbits.h b/include/asm-sparc/termbits.h
index 1794d71134b..5eb00a105d7 100644
--- a/include/asm-sparc/termbits.h
+++ b/include/asm-sparc/termbits.h
@@ -31,6 +31,18 @@ struct termios {
#endif
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ cc_t _x_cc[2]; /* We need them to hold vmin/vtime */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-sparc64/cacheflush.h b/include/asm-sparc64/cacheflush.h
index 745d1ab6037..122e4058dd9 100644
--- a/include/asm-sparc64/cacheflush.h
+++ b/include/asm-sparc64/cacheflush.h
@@ -12,6 +12,7 @@
/* These are the same regardless of whether this is an SMP kernel or not. */
#define flush_cache_mm(__mm) \
do { if ((__mm) == current->mm) flushw_user(); } while(0)
+#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
#define flush_cache_range(vma, start, end) \
flush_cache_mm((vma)->vm_mm)
#define flush_cache_page(vma, page, pfn) \
diff --git a/include/asm-sparc64/dma.h b/include/asm-sparc64/dma.h
index 27f65972b3b..93e5a062df8 100644
--- a/include/asm-sparc64/dma.h
+++ b/include/asm-sparc64/dma.h
@@ -152,9 +152,9 @@ extern void dvma_init(struct sbus_bus *);
#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
/* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs) (((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs) (((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
-#define DMA_WRITE_P(regs) (((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE))
+#define DMA_ERROR_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR))
+#define DMA_IRQ_P(regs) ((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
+#define DMA_WRITE_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE))
#define DMA_OFF(__regs) \
do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
tmp &= ~DMA_ENABLE; \
diff --git a/include/asm-sparc64/hw_irq.h b/include/asm-sparc64/hw_irq.h
index 599b3b07345..8e44a836082 100644
--- a/include/asm-sparc64/hw_irq.h
+++ b/include/asm-sparc64/hw_irq.h
@@ -1,6 +1,4 @@
#ifndef __ASM_SPARC64_HW_IRQ_H
#define __ASM_SPARC64_HW_IRQ_H
-extern void hw_resend_irq(struct hw_interrupt_type *handler, unsigned int virt_irq);
-
#endif
diff --git a/include/asm-sparc64/irqflags.h b/include/asm-sparc64/irqflags.h
new file mode 100644
index 00000000000..024fc54d068
--- /dev/null
+++ b/include/asm-sparc64/irqflags.h
@@ -0,0 +1,89 @@
+/*
+ * include/asm-sparc64/irqflags.h
+ *
+ * IRQ flags handling
+ *
+ * This file gets included from lowlevel asm headers too, to provide
+ * wrapped versions of the local_irq_*() APIs, based on the
+ * raw_local_irq_*() functions from the lowlevel headers.
+ */
+#ifndef _ASM_IRQFLAGS_H
+#define _ASM_IRQFLAGS_H
+
+#ifndef __ASSEMBLY__
+
+static inline unsigned long __raw_local_save_flags(void)
+{
+ unsigned long flags;
+
+ __asm__ __volatile__(
+ "rdpr %%pil, %0"
+ : "=r" (flags)
+ );
+
+ return flags;
+}
+
+#define raw_local_save_flags(flags) \
+ do { (flags) = __raw_local_save_flags(); } while (0)
+
+static inline void raw_local_irq_restore(unsigned long flags)
+{
+ __asm__ __volatile__(
+ "wrpr %0, %%pil"
+ : /* no output */
+ : "r" (flags)
+ : "memory"
+ );
+}
+
+static inline void raw_local_irq_disable(void)
+{
+ __asm__ __volatile__(
+ "wrpr 15, %%pil"
+ : /* no outputs */
+ : /* no inputs */
+ : "memory"
+ );
+}
+
+static inline void raw_local_irq_enable(void)
+{
+ __asm__ __volatile__(
+ "wrpr 0, %%pil"
+ : /* no outputs */
+ : /* no inputs */
+ : "memory"
+ );
+}
+
+static inline int raw_irqs_disabled_flags(unsigned long flags)
+{
+ return (flags > 0);
+}
+
+static inline int raw_irqs_disabled(void)
+{
+ unsigned long flags = __raw_local_save_flags();
+
+ return raw_irqs_disabled_flags(flags);
+}
+
+/*
+ * For spinlocks, etc:
+ */
+static inline unsigned long __raw_local_irq_save(void)
+{
+ unsigned long flags = __raw_local_save_flags();
+
+ raw_local_irq_disable();
+
+ return flags;
+}
+
+#define raw_local_irq_save(flags) \
+ do { (flags) = __raw_local_irq_save(); } while (0)
+
+#endif /* (__ASSEMBLY__) */
+
+#endif /* !(_ASM_IRQFLAGS_H) */
diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h
index c9f5c34d318..becc38fa06c 100644
--- a/include/asm-sparc64/kprobes.h
+++ b/include/asm-sparc64/kprobes.h
@@ -13,7 +13,11 @@ typedef u32 kprobe_opcode_t;
#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry
#define arch_remove_kprobe(p) do {} while (0)
#define ARCH_INACTIVE_KPROBE_COUNT 0
-#define flush_insn_slot(p) do { } while (0)
+
+#define flush_insn_slot(p) \
+do { flushi(&(p)->ainsn.insn[0]); \
+ flushi(&(p)->ainsn.insn[1]); \
+} while (0)
/* Architecture specific copy of original instruction*/
struct arch_specific_insn {
@@ -23,7 +27,7 @@ struct arch_specific_insn {
struct prev_kprobe {
struct kprobe *kp;
- unsigned int status;
+ unsigned long status;
unsigned long orig_tnpc;
unsigned long orig_tstate_pil;
};
@@ -33,10 +37,7 @@ struct kprobe_ctlblk {
unsigned long kprobe_status;
unsigned long kprobe_orig_tnpc;
unsigned long kprobe_orig_tstate_pil;
- long *jprobe_saved_esp;
struct pt_regs jprobe_saved_regs;
- struct pt_regs *jprobe_saved_regs_location;
- struct sparc_stackf jprobe_saved_stack;
struct prev_kprobe prev_kprobe;
};
diff --git a/include/asm-sparc64/of_device.h b/include/asm-sparc64/of_device.h
index a62c7b997d6..60e9173c9ac 100644
--- a/include/asm-sparc64/of_device.h
+++ b/include/asm-sparc64/of_device.h
@@ -34,7 +34,7 @@ struct of_device
#define to_of_device(d) container_of(d, struct of_device, dev)
extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
-extern void of_iounmap(void __iomem *base, unsigned long size);
+extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
extern struct of_device *of_find_device_by_node(struct device_node *);
diff --git a/include/asm-sparc64/percpu.h b/include/asm-sparc64/percpu.h
index ced8cbde046..0d3df76aa47 100644
--- a/include/asm-sparc64/percpu.h
+++ b/include/asm-sparc64/percpu.h
@@ -5,6 +5,16 @@
#ifdef CONFIG_SMP
+#ifdef CONFIG_MODULES
+# define PERCPU_MODULE_RESERVE 8192
+#else
+# define PERCPU_MODULE_RESERVE 0
+#endif
+
+#define PERCPU_ENOUGH_ROOM \
+ (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \
+ PERCPU_MODULE_RESERVE)
+
extern void setup_per_cpu_areas(void);
extern unsigned long __per_cpu_base;
diff --git a/include/asm-sparc64/rwsem.h b/include/asm-sparc64/rwsem.h
index cef5e827042..1294b7ce5d0 100644
--- a/include/asm-sparc64/rwsem.h
+++ b/include/asm-sparc64/rwsem.h
@@ -23,20 +23,33 @@ struct rw_semaphore {
signed int count;
spinlock_t wait_lock;
struct list_head wait_list;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ struct lockdep_map dep_map;
+#endif
};
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
+#else
+# define __RWSEM_DEP_MAP_INIT(lockname)
+#endif
+
#define __RWSEM_INITIALIZER(name) \
-{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) }
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
+ __RWSEM_DEP_MAP_INIT(name) }
#define DECLARE_RWSEM(name) \
struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-static __inline__ void init_rwsem(struct rw_semaphore *sem)
-{
- sem->count = RWSEM_UNLOCKED_VALUE;
- spin_lock_init(&sem->wait_lock);
- INIT_LIST_HEAD(&sem->wait_list);
-}
+extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
+ struct lock_class_key *key);
+
+#define init_rwsem(sem) \
+do { \
+ static struct lock_class_key __key; \
+ \
+ __init_rwsem((sem), #sem, &__key); \
+} while (0)
extern void __down_read(struct rw_semaphore *sem);
extern int __down_read_trylock(struct rw_semaphore *sem);
@@ -46,6 +59,11 @@ extern void __up_read(struct rw_semaphore *sem);
extern void __up_write(struct rw_semaphore *sem);
extern void __downgrade_write(struct rw_semaphore *sem);
+static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+{
+ __down_write(sem);
+}
+
static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
{
return atomic_add_return(delta, (atomic_t *)(&sem->count));
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index a8b7432c9a7..32281acb878 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -7,6 +7,9 @@
#include <asm/visasm.h>
#ifndef __ASSEMBLY__
+
+#include <linux/irqflags.h>
+
/*
* Sparc (general) CPU types
*/
@@ -72,52 +75,6 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
#endif
-#define setipl(__new_ipl) \
- __asm__ __volatile__("wrpr %0, %%pil" : : "r" (__new_ipl) : "memory")
-
-#define local_irq_disable() \
- __asm__ __volatile__("wrpr 15, %%pil" : : : "memory")
-
-#define local_irq_enable() \
- __asm__ __volatile__("wrpr 0, %%pil" : : : "memory")
-
-#define getipl() \
-({ unsigned long retval; __asm__ __volatile__("rdpr %%pil, %0" : "=r" (retval)); retval; })
-
-#define swap_pil(__new_pil) \
-({ unsigned long retval; \
- __asm__ __volatile__("rdpr %%pil, %0\n\t" \
- "wrpr %1, %%pil" \
- : "=&r" (retval) \
- : "r" (__new_pil) \
- : "memory"); \
- retval; \
-})
-
-#define read_pil_and_cli() \
-({ unsigned long retval; \
- __asm__ __volatile__("rdpr %%pil, %0\n\t" \
- "wrpr 15, %%pil" \
- : "=r" (retval) \
- : : "memory"); \
- retval; \
-})
-
-#define local_save_flags(flags) ((flags) = getipl())
-#define local_irq_save(flags) ((flags) = read_pil_and_cli())
-#define local_irq_restore(flags) setipl((flags))
-
-/* On sparc64 IRQ flags are the PIL register. A value of zero
- * means all interrupt levels are enabled, any other value means
- * only IRQ levels greater than that value will be received.
- * Consequently this means that the lowest IRQ level is one.
- */
-#define irqs_disabled() \
-({ unsigned long flags; \
- local_save_flags(flags);\
- (flags > 0); \
-})
-
#define nop() __asm__ __volatile__ ("nop")
#define read_barrier_depends() do { } while(0)
diff --git a/include/asm-sparc64/termbits.h b/include/asm-sparc64/termbits.h
index b07715273ed..705cd44b417 100644
--- a/include/asm-sparc64/termbits.h
+++ b/include/asm-sparc64/termbits.h
@@ -33,6 +33,18 @@ struct termios {
#endif
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ cc_t _x_cc[2]; /* We need them to hold vmin/vtime */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h
index f2352606a79..c2a16e18849 100644
--- a/include/asm-sparc64/ttable.h
+++ b/include/asm-sparc64/ttable.h
@@ -137,10 +137,49 @@
#endif
#define BREAKPOINT_TRAP TRAP(breakpoint_trap)
+#ifdef CONFIG_TRACE_IRQFLAGS
+
+#define TRAP_IRQ(routine, level) \
+ rdpr %pil, %g2; \
+ wrpr %g0, 15, %pil; \
+ sethi %hi(1f-4), %g7; \
+ ba,pt %xcc, etrap_irq; \
+ or %g7, %lo(1f-4), %g7; \
+ nop; \
+ nop; \
+ nop; \
+ .subsection 2; \
+1: call trace_hardirqs_off; \
+ nop; \
+ mov level, %o0; \
+ call routine; \
+ add %sp, PTREGS_OFF, %o1; \
+ ba,a,pt %xcc, rtrap_irq; \
+ .previous;
+
+#define TICK_SMP_IRQ \
+ rdpr %pil, %g2; \
+ wrpr %g0, 15, %pil; \
+ sethi %hi(1f-4), %g7; \
+ ba,pt %xcc, etrap_irq; \
+ or %g7, %lo(1f-4), %g7; \
+ nop; \
+ nop; \
+ nop; \
+ .subsection 2; \
+1: call trace_hardirqs_off; \
+ nop; \
+ call smp_percpu_timer_interrupt; \
+ add %sp, PTREGS_OFF, %o0; \
+ ba,a,pt %xcc, rtrap_irq; \
+ .previous;
+
+#else
+
#define TRAP_IRQ(routine, level) \
rdpr %pil, %g2; \
wrpr %g0, 15, %pil; \
- b,pt %xcc, etrap_irq; \
+ ba,pt %xcc, etrap_irq; \
rd %pc, %g7; \
mov level, %o0; \
call routine; \
@@ -151,12 +190,14 @@
rdpr %pil, %g2; \
wrpr %g0, 15, %pil; \
sethi %hi(109f), %g7; \
- b,pt %xcc, etrap_irq; \
+ ba,pt %xcc, etrap_irq; \
109: or %g7, %lo(109b), %g7; \
call smp_percpu_timer_interrupt; \
add %sp, PTREGS_OFF, %o0; \
ba,a,pt %xcc, rtrap_irq;
+#endif
+
#define TRAP_IVEC TRAP_NOSAVE(do_ivec)
#define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
diff --git a/include/asm-um/bug.h b/include/asm-um/bug.h
index 1e22fa26ff0..3357c5e2468 100644
--- a/include/asm-um/bug.h
+++ b/include/asm-um/bug.h
@@ -1,4 +1,6 @@
#ifndef __UM_BUG_H
#define __UM_BUG_H
-#include <asm-generic/bug.h>
+
+#include <asm/arch/bug.h>
+
#endif
diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
index 188f7262177..e57ff136ee5 100644
--- a/include/asm-um/pgtable.h
+++ b/include/asm-um/pgtable.h
@@ -408,6 +408,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#include <asm-generic/pgtable-nopud.h>
+#ifdef CONFIG_HIGHMEM
+/* 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)
+#endif
+
#endif
#endif
diff --git a/include/asm-v850/cacheflush.h b/include/asm-v850/cacheflush.h
index e1a87f82f1a..9ece05a202e 100644
--- a/include/asm-v850/cacheflush.h
+++ b/include/asm-v850/cacheflush.h
@@ -24,6 +24,7 @@
systems with MMUs, so we don't need them. */
#define flush_cache_all() ((void)0)
#define flush_cache_mm(mm) ((void)0)
+#define flush_cache_dup_mm(mm) ((void)0)
#define flush_cache_range(vma, start, end) ((void)0)
#define flush_cache_page(vma, vmaddr, pfn) ((void)0)
#define flush_dcache_page(page) ((void)0)
diff --git a/include/asm-v850/termbits.h b/include/asm-v850/termbits.h
index 212d4e27926..f3b43303208 100644
--- a/include/asm-v850/termbits.h
+++ b/include/asm-v850/termbits.h
@@ -17,6 +17,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
index 9d1916e59c0..a29f05087a3 100644
--- a/include/asm-x86_64/acpi.h
+++ b/include/asm-x86_64/acpi.h
@@ -37,7 +37,7 @@
* Calling conventions:
*
* ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads)
- * ACPI_EXTERNAL_XFACE - External ACPI interfaces
+ * ACPI_EXTERNAL_XFACE - External ACPI interfaces
* ACPI_INTERNAL_XFACE - Internal ACPI interfaces
* ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces
*/
@@ -54,36 +54,14 @@
#define ACPI_ENABLE_IRQS() local_irq_enable()
#define ACPI_FLUSH_CPU_CACHE() wbinvd()
+int __acpi_acquire_global_lock(unsigned int *lock);
+int __acpi_release_global_lock(unsigned int *lock);
-static inline int
-__acpi_acquire_global_lock (unsigned int *lock)
-{
- unsigned int old, new, val;
- do {
- old = *lock;
- new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
- val = cmpxchg(lock, old, new);
- } while (unlikely (val != old));
- return (new < 3) ? -1 : 0;
-}
-
-static inline int
-__acpi_release_global_lock (unsigned int *lock)
-{
- unsigned int old, new, val;
- do {
- old = *lock;
- new = old & ~0x3;
- val = cmpxchg(lock, old, new);
- } while (unlikely (val != old));
- return old & 0x1;
-}
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
+ ((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
-#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
- ((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr))
-
-#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
- ((Acq) = __acpi_release_global_lock((unsigned int *) GLptr))
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
+ ((Acq) = __acpi_release_global_lock(&facs->global_lock))
/*
* Math helper asm macros
@@ -109,10 +87,10 @@ extern int acpi_strict;
extern int acpi_disabled;
extern int acpi_pci_disabled;
extern int acpi_ht;
-static inline void disable_acpi(void)
-{
- acpi_disabled = 1;
- acpi_ht = 0;
+static inline void disable_acpi(void)
+{
+ acpi_disabled = 1;
+ acpi_ht = 0;
acpi_pci_disabled = 1;
acpi_noirq = 1;
}
@@ -122,9 +100,9 @@ static inline void disable_acpi(void)
extern int acpi_gsi_to_irq(u32 gsi, unsigned int *irq);
static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
-static inline void acpi_disable_pci(void)
+static inline void acpi_disable_pci(void)
{
- acpi_pci_disabled = 1;
+ acpi_pci_disabled = 1;
acpi_noirq_set();
}
extern int acpi_irq_balance_set(char *str);
@@ -158,8 +136,6 @@ extern void acpi_reserve_bootmem(void);
extern int acpi_disabled;
extern int acpi_pci_disabled;
-extern u8 x86_acpiid_to_apicid[];
-
#define ARCH_HAS_POWER_INIT 1
extern int acpi_skip_timer_override;
diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h
index 5b535eaf530..8da9609070f 100644
--- a/include/asm-x86_64/bitops.h
+++ b/include/asm-x86_64/bitops.h
@@ -7,7 +7,13 @@
#include <asm/alternative.h>
-#define ADDR (*(volatile long *) addr)
+#if __GNUC__ < 4 || __GNUC_MINOR__ < 1
+/* Technically wrong, but this avoids compilation errors on some gcc
+ versions. */
+#define ADDR "=m" (*(volatile long *) addr)
+#else
+#define ADDR "+m" (*(volatile long *) addr)
+#endif
/**
* set_bit - Atomically set a bit in memory
@@ -23,7 +29,7 @@ static __inline__ void set_bit(int nr, volatile void * addr)
{
__asm__ __volatile__( LOCK_PREFIX
"btsl %1,%0"
- :"+m" (ADDR)
+ :ADDR
:"dIr" (nr) : "memory");
}
@@ -40,7 +46,7 @@ static __inline__ void __set_bit(int nr, volatile void * addr)
{
__asm__ volatile(
"btsl %1,%0"
- :"+m" (ADDR)
+ :ADDR
:"dIr" (nr) : "memory");
}
@@ -58,7 +64,7 @@ static __inline__ void clear_bit(int nr, volatile void * addr)
{
__asm__ __volatile__( LOCK_PREFIX
"btrl %1,%0"
- :"+m" (ADDR)
+ :ADDR
:"dIr" (nr));
}
@@ -66,7 +72,7 @@ static __inline__ void __clear_bit(int nr, volatile void * addr)
{
__asm__ __volatile__(
"btrl %1,%0"
- :"+m" (ADDR)
+ :ADDR
:"dIr" (nr));
}
@@ -86,7 +92,7 @@ static __inline__ void __change_bit(int nr, volatile void * addr)
{
__asm__ __volatile__(
"btcl %1,%0"
- :"+m" (ADDR)
+ :ADDR
:"dIr" (nr));
}
@@ -103,7 +109,7 @@ static __inline__ void change_bit(int nr, volatile void * addr)
{
__asm__ __volatile__( LOCK_PREFIX
"btcl %1,%0"
- :"+m" (ADDR)
+ :ADDR
:"dIr" (nr));
}
@@ -121,7 +127,7 @@ static __inline__ int test_and_set_bit(int nr, volatile void * addr)
__asm__ __volatile__( LOCK_PREFIX
"btsl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
+ :"=r" (oldbit),ADDR
:"dIr" (nr) : "memory");
return oldbit;
}
@@ -141,7 +147,7 @@ static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
__asm__(
"btsl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
+ :"=r" (oldbit),ADDR
:"dIr" (nr));
return oldbit;
}
@@ -160,7 +166,7 @@ static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
__asm__ __volatile__( LOCK_PREFIX
"btrl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
+ :"=r" (oldbit),ADDR
:"dIr" (nr) : "memory");
return oldbit;
}
@@ -180,7 +186,7 @@ static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
__asm__(
"btrl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
+ :"=r" (oldbit),ADDR
:"dIr" (nr));
return oldbit;
}
@@ -192,7 +198,7 @@ static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
__asm__ __volatile__(
"btcl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
+ :"=r" (oldbit),ADDR
:"dIr" (nr) : "memory");
return oldbit;
}
@@ -211,7 +217,7 @@ static __inline__ int test_and_change_bit(int nr, volatile void * addr)
__asm__ __volatile__( LOCK_PREFIX
"btcl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
+ :"=r" (oldbit),ADDR
:"dIr" (nr) : "memory");
return oldbit;
}
@@ -237,7 +243,7 @@ static __inline__ int variable_test_bit(int nr, volatile const void * addr)
__asm__ __volatile__(
"btl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit)
- :"m" (ADDR),"dIr" (nr));
+ :"m" (*(volatile long *)addr),"dIr" (nr));
return oldbit;
}
diff --git a/include/asm-x86_64/bug.h b/include/asm-x86_64/bug.h
index 80ac1fe966a..68260641491 100644
--- a/include/asm-x86_64/bug.h
+++ b/include/asm-x86_64/bug.h
@@ -1,30 +1,30 @@
#ifndef __ASM_X8664_BUG_H
#define __ASM_X8664_BUG_H 1
-#include <linux/stringify.h>
-
-/*
- * Tell the user there is some problem. The exception handler decodes
- * this frame.
- */
-struct bug_frame {
- unsigned char ud2[2];
- unsigned char push;
- signed int filename;
- unsigned char ret;
- unsigned short line;
-} __attribute__((packed));
-
#ifdef CONFIG_BUG
#define HAVE_ARCH_BUG
-/* We turn the bug frame into valid instructions to not confuse
- the disassembler. Thanks to Jan Beulich & Suresh Siddha
- for nice instruction selection.
- The magic numbers generate mov $64bitimm,%eax ; ret $offset. */
-#define BUG() \
- asm volatile( \
- "ud2 ; pushq $%c1 ; ret $%c0" :: \
- "i"(__LINE__), "i" (__FILE__))
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define BUG() \
+ do { \
+ asm volatile("1:\tud2\n" \
+ ".pushsection __bug_table,\"a\"\n" \
+ "2:\t.quad 1b, %c0\n" \
+ "\t.word %c1, 0\n" \
+ "\t.org 2b+%c2\n" \
+ ".popsection" \
+ : : "i" (__FILE__), "i" (__LINE__), \
+ "i" (sizeof(struct bug_entry))); \
+ for(;;) ; \
+ } while(0)
+#else
+#define BUG() \
+ do { \
+ asm volatile("ud2"); \
+ for(;;) ; \
+ } while(0)
+#endif
+
void out_of_line_bug(void);
#else
static inline void out_of_line_bug(void) { }
diff --git a/include/asm-x86_64/cacheflush.h b/include/asm-x86_64/cacheflush.h
index d32f7f58752..ab1cb5c7dc9 100644
--- a/include/asm-x86_64/cacheflush.h
+++ b/include/asm-x86_64/cacheflush.h
@@ -7,6 +7,7 @@
/* Caches aren't brain-dead on the intel. */
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_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)
diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h
index be9ec689072..49dbab09ef2 100644
--- a/include/asm-x86_64/dma-mapping.h
+++ b/include/asm-x86_64/dma-mapping.h
@@ -63,6 +63,9 @@ static inline int dma_mapping_error(dma_addr_t dma_addr)
return (dma_addr == bad_dma_address);
}
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+
extern void *dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp);
extern void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h
index 6ee9fadaaac..f5d84bb7c94 100644
--- a/include/asm-x86_64/io.h
+++ b/include/asm-x86_64/io.h
@@ -248,12 +248,6 @@ void memset_io(volatile void __iomem *a, int b, size_t c);
*/
#define __ISA_IO_base ((char __iomem *)(PAGE_OFFSET))
-/*
- * Again, x86-64 does not require mem IO specific function.
- */
-
-#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d))
-
/* Nothing to do */
#define dma_cache_inv(_start,_size) do { } while (0)
diff --git a/include/asm-x86_64/ioctls.h b/include/asm-x86_64/ioctls.h
index 62caf8b6e4e..3fc0b15a0d7 100644
--- a/include/asm-x86_64/ioctls.h
+++ b/include/asm-x86_64/ioctls.h
@@ -46,6 +46,10 @@
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TCSETS2 _IOW('T',0x2B, struct termios2)
+#define TCSETSW2 _IOW('T',0x2C, struct termios2)
+#define TCSETSF2 _IOW('T',0x2D, struct termios2)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h
index 952783d35c7..3227bc93d69 100644
--- a/include/asm-x86_64/msr.h
+++ b/include/asm-x86_64/msr.h
@@ -189,6 +189,7 @@ static inline unsigned int cpuid_edx(unsigned int op)
#define MSR_IA32_PERFCTR0 0xc1
#define MSR_IA32_PERFCTR1 0xc2
+#define MSR_FSB_FREQ 0xcd
#define MSR_MTRRcap 0x0fe
#define MSR_IA32_BBL_CR_CTL 0x119
@@ -311,6 +312,9 @@ static inline unsigned int cpuid_edx(unsigned int op)
#define MSR_IA32_PERF_STATUS 0x198
#define MSR_IA32_PERF_CTL 0x199
+#define MSR_IA32_MPERF 0xE7
+#define MSR_IA32_APERF 0xE8
+
#define MSR_IA32_THERM_CONTROL 0x19a
#define MSR_IA32_THERM_INTERRUPT 0x19b
#define MSR_IA32_THERM_STATUS 0x19c
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index 6d324b83897..a6d2ff5c69b 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -81,7 +81,6 @@ extern void swap_low_mappings(void);
extern void __show_regs(struct pt_regs * regs);
extern void show_regs(struct pt_regs * regs);
-extern char *syscall32_page;
extern void syscall32_cpu_init(void);
extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end);
diff --git a/include/asm-x86_64/swiotlb.h b/include/asm-x86_64/swiotlb.h
index ba94ab3d267..ab913ffcad5 100644
--- a/include/asm-x86_64/swiotlb.h
+++ b/include/asm-x86_64/swiotlb.h
@@ -1,6 +1,5 @@
#ifndef _ASM_SWIOTLB_H
-#define _ASM_SWTIOLB_H 1
-
+#define _ASM_SWIOTLB_H 1
#include <asm/dma-mapping.h>
@@ -45,6 +44,7 @@ extern void swiotlb_init(void);
extern int swiotlb_force;
#ifdef CONFIG_SWIOTLB
+#define SWIOTLB_ARCH_NEED_ALLOC
extern int swiotlb;
#else
#define swiotlb 0
@@ -52,4 +52,6 @@ extern int swiotlb;
extern void pci_swiotlb_init(void);
-#endif /* _ASM_SWTIOLB_H */
+static inline void dma_mark_clean(void *addr, size_t size) {}
+
+#endif /* _ASM_SWIOTLB_H */
diff --git a/include/asm-x86_64/termbits.h b/include/asm-x86_64/termbits.h
index bd950946e52..6cfc3bb10c1 100644
--- a/include/asm-x86_64/termbits.h
+++ b/include/asm-x86_64/termbits.h
@@ -17,6 +17,28 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct termios2 {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
@@ -118,6 +140,7 @@ struct termios {
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
+#define BOTHER 0010000 /* non standard rate */
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
@@ -133,10 +156,12 @@ struct termios {
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
-#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CIBAUD 002003600000 /* input baud rate */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
+#define IBSHIFT 8 /* Shift from CBAUD to CIBAUD */
+
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
diff --git a/include/asm-x86_64/termios.h b/include/asm-x86_64/termios.h
index 041a91f7ddf..443b225537f 100644
--- a/include/asm-x86_64/termios.h
+++ b/include/asm-x86_64/termios.h
@@ -98,8 +98,10 @@ struct termio {
copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
})
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
#endif /* __KERNEL__ */
diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h
index 787a08114b4..74a6c74397f 100644
--- a/include/asm-x86_64/thread_info.h
+++ b/include/asm-x86_64/thread_info.h
@@ -122,6 +122,7 @@ static inline struct thread_info *stack_thread_info(void)
#define TIF_MEMDIE 20
#define TIF_DEBUG 21 /* uses debug registers */
#define TIF_IO_BITMAP 22 /* uses I/O bitmap */
+#define TIF_FREEZE 23 /* is freezing for suspend */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
@@ -137,6 +138,7 @@ static inline struct thread_info *stack_thread_info(void)
#define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)
#define _TIF_DEBUG (1<<TIF_DEBUG)
#define _TIF_IO_BITMAP (1<<TIF_IO_BITMAP)
+#define _TIF_FREEZE (1<<TIF_FREEZE)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK \
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
index 5c8f49280db..2facec5914d 100644
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -47,6 +47,7 @@ extern int __node_distance(int, int);
.flags = SD_LOAD_BALANCE \
| SD_BALANCE_FORK \
| SD_BALANCE_EXEC \
+ | SD_SERIALIZE \
| SD_WAKE_BALANCE, \
.last_balance = jiffies, \
.balance_interval = 1, \
diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h
index d5dbc87274f..c0eac519840 100644
--- a/include/asm-x86_64/uaccess.h
+++ b/include/asm-x86_64/uaccess.h
@@ -157,7 +157,7 @@ do { \
case 1: __put_user_asm(x,ptr,retval,"b","b","iq",-EFAULT); break;\
case 2: __put_user_asm(x,ptr,retval,"w","w","ir",-EFAULT); break;\
case 4: __put_user_asm(x,ptr,retval,"l","k","ir",-EFAULT); break;\
- case 8: __put_user_asm(x,ptr,retval,"q","","ir",-EFAULT); break;\
+ case 8: __put_user_asm(x,ptr,retval,"q","","Zr",-EFAULT); break;\
default: __put_user_bad(); \
} \
} while (0)
diff --git a/include/asm-x86_64/unwind.h b/include/asm-x86_64/unwind.h
index 2f6349e4871..02710f6a456 100644
--- a/include/asm-x86_64/unwind.h
+++ b/include/asm-x86_64/unwind.h
@@ -1,100 +1,6 @@
#ifndef _ASM_X86_64_UNWIND_H
#define _ASM_X86_64_UNWIND_H
-/*
- * Copyright (C) 2002-2006 Novell, Inc.
- * Jan Beulich <jbeulich@novell.com>
- * This code is released under version 2 of the GNU GPL.
- */
-
-#ifdef CONFIG_STACK_UNWIND
-
-#include <linux/sched.h>
-#include <asm/ptrace.h>
-#include <asm/uaccess.h>
-#include <asm/vsyscall.h>
-
-struct unwind_frame_info
-{
- struct pt_regs regs;
- struct task_struct *task;
- unsigned call_frame:1;
-};
-
-#define UNW_PC(frame) (frame)->regs.rip
-#define UNW_SP(frame) (frame)->regs.rsp
-#ifdef CONFIG_FRAME_POINTER
-#define UNW_FP(frame) (frame)->regs.rbp
-#define FRAME_RETADDR_OFFSET 8
-#define FRAME_LINK_OFFSET 0
-#define STACK_BOTTOM(tsk) (((tsk)->thread.rsp0 - 1) & ~(THREAD_SIZE - 1))
-#define STACK_TOP(tsk) ((tsk)->thread.rsp0)
-#endif
-/* Might need to account for the special exception and interrupt handling
- stacks here, since normally
- EXCEPTION_STACK_ORDER < THREAD_ORDER < IRQSTACK_ORDER,
- but the construct is needed only for getting across the stack switch to
- the interrupt stack - thus considering the IRQ stack itself is unnecessary,
- and the overhead of comparing against all exception handling stacks seems
- not desirable. */
-#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1))
-
-#define UNW_REGISTER_INFO \
- PTREGS_INFO(rax), \
- PTREGS_INFO(rdx), \
- PTREGS_INFO(rcx), \
- PTREGS_INFO(rbx), \
- PTREGS_INFO(rsi), \
- PTREGS_INFO(rdi), \
- PTREGS_INFO(rbp), \
- PTREGS_INFO(rsp), \
- PTREGS_INFO(r8), \
- PTREGS_INFO(r9), \
- PTREGS_INFO(r10), \
- PTREGS_INFO(r11), \
- PTREGS_INFO(r12), \
- PTREGS_INFO(r13), \
- PTREGS_INFO(r14), \
- PTREGS_INFO(r15), \
- PTREGS_INFO(rip)
-
-#define UNW_DEFAULT_RA(raItem, dataAlign) \
- ((raItem).where == Memory && \
- !((raItem).value * (dataAlign) + 8))
-
-static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
- /*const*/ struct pt_regs *regs)
-{
- info->regs = *regs;
-}
-
-static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
-{
- extern const char thread_return[];
-
- memset(&info->regs, 0, sizeof(info->regs));
- info->regs.rip = (unsigned long)thread_return;
- info->regs.cs = __KERNEL_CS;
- __get_user(info->regs.rbp, (unsigned long *)info->task->thread.rsp);
- info->regs.rsp = info->task->thread.rsp;
- info->regs.ss = __KERNEL_DS;
-}
-
-extern int arch_unwind_init_running(struct unwind_frame_info *,
- int (*callback)(struct unwind_frame_info *,
- void *arg),
- void *arg);
-
-static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
-{
- return user_mode(&info->regs)
- || (long)info->regs.rip >= 0
- || (info->regs.rip >= VSYSCALL_START && info->regs.rip < VSYSCALL_END)
- || (long)info->regs.rsp >= 0;
-}
-
-#else
-
#define UNW_PC(frame) ((void)(frame), 0UL)
#define UNW_SP(frame) ((void)(frame), 0UL)
@@ -103,6 +9,4 @@ static inline int arch_unw_user_mode(const void *info)
return 0;
}
-#endif
-
#endif /* _ASM_X86_64_UNWIND_H */
diff --git a/include/asm-xtensa/asmmacro.h b/include/asm-xtensa/asmmacro.h
new file mode 100644
index 00000000000..76915cabad1
--- /dev/null
+++ b/include/asm-xtensa/asmmacro.h
@@ -0,0 +1,153 @@
+/*
+ * include/asm-xtensa/asmmacro.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_ASMMACRO_H
+#define _XTENSA_ASMMACRO_H
+
+#include <asm/variant/core.h>
+
+/*
+ * Some little helpers for loops. Use zero-overhead-loops
+ * where applicable and if supported by the processor.
+ *
+ * __loopi ar, at, size, inc
+ * ar register initialized with the start address
+ * at scratch register used by macro
+ * size size immediate value
+ * inc increment
+ *
+ * __loops ar, as, at, inc_log2[, mask_log2][, cond][, ncond]
+ * ar register initialized with the start address
+ * as register initialized with the size
+ * at scratch register use by macro
+ * inc_log2 increment [in log2]
+ * mask_log2 mask [in log2]
+ * cond true condition (used in loop'cond')
+ * ncond false condition (used in b'ncond')
+ *
+ * __loop as
+ * restart loop. 'as' register must not have been modified!
+ *
+ * __endla ar, at, incr
+ * ar start address (modified)
+ * as scratch register used by macro
+ * inc increment
+ */
+
+/*
+ * loop for given size as immediate
+ */
+
+ .macro __loopi ar, at, size, incr
+
+#if XCHAL_HAVE_LOOPS
+ movi \at, ((\size + \incr - 1) / (\incr))
+ loop \at, 99f
+#else
+ addi \at, \ar, \size
+ 98:
+#endif
+
+ .endm
+
+/*
+ * loop for given size in register
+ */
+
+ .macro __loops ar, as, at, incr_log2, mask_log2, cond, ncond
+
+#if XCHAL_HAVE_LOOPS
+ .ifgt \incr_log2 - 1
+ addi \at, \as, (1 << \incr_log2) - 1
+ .ifnc \mask_log2,
+ extui \at, \at, \incr_log2, \mask_log2
+ .else
+ srli \at, \at, \incr_log2
+ .endif
+ .endif
+ loop\cond \at, 99f
+#else
+ .ifnc \mask_log2,
+ extui \at, \as, \incr_log2, \mask_log2
+ .else
+ .ifnc \ncond,
+ srli \at, \as, \incr_log2
+ .endif
+ .endif
+ .ifnc \ncond,
+ b\ncond \at, 99f
+
+ .endif
+ .ifnc \mask_log2,
+ slli \at, \at, \incr_log2
+ add \at, \ar, \at
+ .else
+ add \at, \ar, \as
+ .endif
+#endif
+ 98:
+
+ .endm
+
+/*
+ * loop from ar to ax
+ */
+
+ .macro __loopt ar, as, at, incr_log2
+
+#if XCHAL_HAVE_LOOPS
+ sub \at, \as, \ar
+ .ifgt \incr_log2 - 1
+ addi \at, \at, (1 << \incr_log2) - 1
+ srli \at, \at, \incr_log2
+ .endif
+ loop \at, 99f
+#else
+ 98:
+#endif
+
+ .endm
+
+/*
+ * restart loop. registers must be unchanged
+ */
+
+ .macro __loop as
+
+#if XCHAL_HAVE_LOOPS
+ loop \as, 99f
+#else
+ 98:
+#endif
+
+ .endm
+
+/*
+ * end of loop with no increment of the address.
+ */
+
+ .macro __endl ar, as
+#if !XCHAL_HAVE_LOOPS
+ bltu \ar, \as, 98b
+#endif
+ 99:
+ .endm
+
+/*
+ * end of loop with increment of the address.
+ */
+
+ .macro __endla ar, as, incr
+ addi \ar, \ar, \incr
+ __endl \ar \as
+ .endm
+
+
+#endif /* _XTENSA_ASMMACRO_H */
diff --git a/include/asm-xtensa/bug.h b/include/asm-xtensa/bug.h
index 56703659b20..3e52d72712f 100644
--- a/include/asm-xtensa/bug.h
+++ b/include/asm-xtensa/bug.h
@@ -13,29 +13,6 @@
#ifndef _XTENSA_BUG_H
#define _XTENSA_BUG_H
-#include <linux/stringify.h>
-
-#define ILL __asm__ __volatile__ (".byte 0,0,0\n")
-
-#ifdef CONFIG_KALLSYMS
-# define BUG() do { \
- printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
- ILL; \
-} while (0)
-#else
-# define BUG() do { \
- printk("kernel BUG!\n"); \
- ILL; \
-} while (0)
-#endif
-
-#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
-#define PAGE_BUG(page) do { BUG(); } while (0)
-#define WARN_ON(condition) do { \
- if (unlikely((condition)!=0)) { \
- printk ("Warning in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
- dump_stack(); \
- } \
-} while (0)
+#include <asm-generic/bug.h>
#endif /* _XTENSA_BUG_H */
diff --git a/include/asm-xtensa/byteorder.h b/include/asm-xtensa/byteorder.h
index 0b1552569aa..0f540a5f4c0 100644
--- a/include/asm-xtensa/byteorder.h
+++ b/include/asm-xtensa/byteorder.h
@@ -11,10 +11,9 @@
#ifndef _XTENSA_BYTEORDER_H
#define _XTENSA_BYTEORDER_H
-#include <asm/processor.h>
#include <asm/types.h>
-static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x)
{
__u32 res;
/* instruction sequence from Xtensa ISA release 2/2000 */
@@ -29,7 +28,7 @@ static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
return res;
}
-static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x)
{
/* Given that 'short' values are signed (i.e., can be negative),
* we cannot assume that the upper 16-bits of the register are
diff --git a/include/asm-xtensa/cache.h b/include/asm-xtensa/cache.h
index 1e79c0e2746..1c4a78f29ae 100644
--- a/include/asm-xtensa/cache.h
+++ b/include/asm-xtensa/cache.h
@@ -4,7 +4,6 @@
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
- * 2 of the License, or (at your option) any later version.
*
* (C) 2001 - 2005 Tensilica Inc.
*/
@@ -12,21 +11,14 @@
#ifndef _XTENSA_CACHE_H
#define _XTENSA_CACHE_H
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
-#if XCHAL_ICACHE_SIZE > 0
-# if (XCHAL_ICACHE_SIZE % (XCHAL_ICACHE_LINESIZE*XCHAL_ICACHE_WAYS*4)) != 0
-# error cache configuration outside expected/supported range!
-# endif
-#endif
+#define L1_CACHE_SHIFT XCHAL_DCACHE_LINEWIDTH
+#define L1_CACHE_BYTES XCHAL_DCACHE_LINESIZE
+#define SMP_CACHE_BYTES L1_CACHE_BYTES
-#if XCHAL_DCACHE_SIZE > 0
-# if (XCHAL_DCACHE_SIZE % (XCHAL_DCACHE_LINESIZE*XCHAL_DCACHE_WAYS*4)) != 0
-# error cache configuration outside expected/supported range!
-# endif
-#endif
+#define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE/XCHAL_DCACHE_WAYS)
+#define ICACHE_WAY_SIZE (XCHAL_ICACHE_SIZE/XCHAL_ICACHE_WAYS)
-#define L1_CACHE_SHIFT XCHAL_CACHE_LINEWIDTH_MAX
-#define L1_CACHE_BYTES XCHAL_CACHE_LINESIZE_MAX
#endif /* _XTENSA_CACHE_H */
diff --git a/include/asm-xtensa/cacheasm.h b/include/asm-xtensa/cacheasm.h
new file mode 100644
index 00000000000..2c20a58f94c
--- /dev/null
+++ b/include/asm-xtensa/cacheasm.h
@@ -0,0 +1,177 @@
+/*
+ * include/asm-xtensa/cacheasm.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006 Tensilica Inc.
+ */
+
+#include <asm/cache.h>
+#include <asm/asmmacro.h>
+#include <linux/stringify.h>
+
+/*
+ * Define cache functions as macros here so that they can be used
+ * by the kernel and boot loader. We should consider moving them to a
+ * library that can be linked by both.
+ *
+ * Locking
+ *
+ * ___unlock_dcache_all
+ * ___unlock_icache_all
+ *
+ * Flush and invaldating
+ *
+ * ___flush_invalidate_dcache_{all|range|page}
+ * ___flush_dcache_{all|range|page}
+ * ___invalidate_dcache_{all|range|page}
+ * ___invalidate_icache_{all|range|page}
+ *
+ */
+
+ .macro __loop_cache_all ar at insn size line_width
+
+ movi \ar, 0
+
+ __loopi \ar, \at, \size, (4 << (\line_width))
+ \insn \ar, 0 << (\line_width)
+ \insn \ar, 1 << (\line_width)
+ \insn \ar, 2 << (\line_width)
+ \insn \ar, 3 << (\line_width)
+ __endla \ar, \at, 4 << (\line_width)
+
+ .endm
+
+
+ .macro __loop_cache_range ar as at insn line_width
+
+ extui \at, \ar, 0, \line_width
+ add \as, \as, \at
+
+ __loops \ar, \as, \at, \line_width
+ \insn \ar, 0
+ __endla \ar, \at, (1 << (\line_width))
+
+ .endm
+
+
+ .macro __loop_cache_page ar at insn line_width
+
+ __loopi \ar, \at, PAGE_SIZE, 4 << (\line_width)
+ \insn \ar, 0 << (\line_width)
+ \insn \ar, 1 << (\line_width)
+ \insn \ar, 2 << (\line_width)
+ \insn \ar, 3 << (\line_width)
+ __endla \ar, \at, 4 << (\line_width)
+
+ .endm
+
+
+#if XCHAL_DCACHE_LINE_LOCKABLE
+
+ .macro ___unlock_dcache_all ar at
+
+ __loop_cache_all \ar \at diu XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH
+
+ .endm
+
+#endif
+
+#if XCHAL_ICACHE_LINE_LOCKABLE
+
+ .macro ___unlock_icache_all ar at
+
+ __loop_cache_all \ar \at iiu XCHAL_ICACHE_SIZE XCHAL_ICACHE_LINEWIDTH
+
+ .endm
+#endif
+
+ .macro ___flush_invalidate_dcache_all ar at
+
+ __loop_cache_all \ar \at diwbi XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH
+
+ .endm
+
+
+ .macro ___flush_dcache_all ar at
+
+ __loop_cache_all \ar \at diwb XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH
+
+ .endm
+
+
+ .macro ___invalidate_dcache_all ar at
+
+ __loop_cache_all \ar \at dii __stringify(DCACHE_WAY_SIZE) \
+ XCHAL_DCACHE_LINEWIDTH
+
+ .endm
+
+
+ .macro ___invalidate_icache_all ar at
+
+ __loop_cache_all \ar \at iii __stringify(ICACHE_WAY_SIZE) \
+ XCHAL_ICACHE_LINEWIDTH
+
+ .endm
+
+
+
+ .macro ___flush_invalidate_dcache_range ar as at
+
+ __loop_cache_range \ar \as \at dhwbi XCHAL_DCACHE_LINEWIDTH
+
+ .endm
+
+
+ .macro ___flush_dcache_range ar as at
+
+ __loop_cache_range \ar \as \at dhwb XCHAL_DCACHE_LINEWIDTH
+
+ .endm
+
+
+ .macro ___invalidate_dcache_range ar as at
+
+ __loop_cache_range \ar \as \at dhi XCHAL_DCACHE_LINEWIDTH
+
+ .endm
+
+
+ .macro ___invalidate_icache_range ar as at
+
+ __loop_cache_range \ar \as \at ihi XCHAL_ICACHE_LINEWIDTH
+
+ .endm
+
+
+
+ .macro ___flush_invalidate_dcache_page ar as
+
+ __loop_cache_page \ar \as dhwbi XCHAL_DCACHE_LINEWIDTH
+
+ .endm
+
+
+ .macro ___flush_dcache_page ar as
+
+ __loop_cache_page \ar \as dhwb XCHAL_DCACHE_LINEWIDTH
+
+ .endm
+
+
+ .macro ___invalidate_dcache_page ar as
+
+ __loop_cache_page \ar \as dhi XCHAL_DCACHE_LINEWIDTH
+
+ .endm
+
+
+ .macro ___invalidate_icache_page ar as
+
+ __loop_cache_page \ar \as ihi XCHAL_ICACHE_LINEWIDTH
+
+ .endm
+
diff --git a/include/asm-xtensa/cacheflush.h b/include/asm-xtensa/cacheflush.h
index 44a36e08784..22ef901b784 100644
--- a/include/asm-xtensa/cacheflush.h
+++ b/include/asm-xtensa/cacheflush.h
@@ -5,7 +5,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * (C) 2001 - 2005 Tensilica Inc.
+ * (C) 2001 - 2006 Tensilica Inc.
*/
#ifndef _XTENSA_CACHEFLUSH_H
@@ -75,6 +75,7 @@ extern void __flush_invalidate_dcache_range(unsigned long, unsigned long);
#define flush_cache_all() __flush_invalidate_cache_all();
#define flush_cache_mm(mm) __flush_invalidate_cache_all();
+#define flush_cache_dup_mm(mm) __flush_invalidate_cache_all();
#define flush_cache_vmap(start,end) __flush_invalidate_cache_all();
#define flush_cache_vunmap(start,end) __flush_invalidate_cache_all();
@@ -88,6 +89,7 @@ extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned lon
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_vmap(start,end) do { } while (0)
#define flush_cache_vunmap(start,end) do { } while (0)
diff --git a/include/asm-xtensa/checksum.h b/include/asm-xtensa/checksum.h
index 5435aff9a4b..23534c60b3a 100644
--- a/include/asm-xtensa/checksum.h
+++ b/include/asm-xtensa/checksum.h
@@ -12,7 +12,7 @@
#define _XTENSA_CHECKSUM_H
#include <linux/in6.h>
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
/*
* computes the checksum of a memory block at buff, length len,
diff --git a/include/asm-xtensa/coprocessor.h b/include/asm-xtensa/coprocessor.h
index 5093034723b..bd09ec02d57 100644
--- a/include/asm-xtensa/coprocessor.h
+++ b/include/asm-xtensa/coprocessor.h
@@ -11,7 +11,16 @@
#ifndef _XTENSA_COPROCESSOR_H
#define _XTENSA_COPROCESSOR_H
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
+#include <asm/variant/tie.h>
+
+#if !XCHAL_HAVE_CP
+
+#define XTENSA_CP_EXTRA_OFFSET 0
+#define XTENSA_CP_EXTRA_ALIGN 1 /* must be a power of 2 */
+#define XTENSA_CP_EXTRA_SIZE 0
+
+#else
#define XTOFS(last_start,last_size,align) \
((last_start+last_size+align-1) & -align)
@@ -67,4 +76,6 @@ extern void save_coprocessor_registers(void*, int);
# endif
#endif
+#endif
+
#endif /* _XTENSA_COPROCESSOR_H */
diff --git a/include/asm-xtensa/dma.h b/include/asm-xtensa/dma.h
index db2633f6778..e30f3abf48f 100644
--- a/include/asm-xtensa/dma.h
+++ b/include/asm-xtensa/dma.h
@@ -12,7 +12,6 @@
#define _XTENSA_DMA_H
#include <asm/io.h> /* need byte IO */
-#include <xtensa/config/core.h>
/*
* This is only to be defined if we have PC-like DMA.
@@ -44,7 +43,9 @@
* enters another area, and virt_to_phys() may not return
* the value desired).
*/
-#define MAX_DMA_ADDRESS (PAGE_OFFSET + XCHAL_KSEG_CACHED_SIZE - 1)
+
+#define MAX_DMA_ADDRESS (PAGE_OFFSET + XCHAL_KIO_SIZE - 1)
+
/* Reserve and release a DMA channel */
extern int request_dma(unsigned int dmanr, const char * device_id);
diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h
index de0667453b2..f0f9fd8560a 100644
--- a/include/asm-xtensa/elf.h
+++ b/include/asm-xtensa/elf.h
@@ -13,9 +13,8 @@
#ifndef _XTENSA_ELF_H
#define _XTENSA_ELF_H
+#include <asm/variant/core.h>
#include <asm/ptrace.h>
-#include <asm/coprocessor.h>
-#include <xtensa/config/core.h>
/* Xtensa processor ELF architecture-magic number */
@@ -118,11 +117,15 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
* using memcpy(). But we do allow space for such alignment,
* to allow optimizations of layout and copying.
*/
-
+#if 0
#define TOTAL_FPREGS_SIZE \
(4 + XTENSA_CPE_LTABLE_SIZE + XTENSA_CP_EXTRA_SIZE)
#define ELF_NFPREG \
((TOTAL_FPREGS_SIZE + sizeof(elf_fpreg_t) - 1) / sizeof(elf_fpreg_t))
+#else
+#define TOTAL_FPREGS_SIZE 0
+#define ELF_NFPREG 0
+#endif
typedef unsigned int elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
diff --git a/include/asm-xtensa/fcntl.h b/include/asm-xtensa/fcntl.h
index ec066ae96ca..0609fc691b7 100644
--- a/include/asm-xtensa/fcntl.h
+++ b/include/asm-xtensa/fcntl.h
@@ -14,48 +14,86 @@
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
located on an ext2 file system */
-#define O_APPEND 0x0008
-#define O_SYNC 0x0010
-#define O_NONBLOCK 0x0080
-#define O_CREAT 0x0100 /* not fcntl */
-#define O_EXCL 0x0400 /* not fcntl */
-#define O_NOCTTY 0x0800 /* not fcntl */
-#define FASYNC 0x1000 /* fcntl, for BSD compatibility */
-#define O_LARGEFILE 0x2000 /* allow large file opens - currently ignored */
-#define O_DIRECT 0x8000 /* direct disk access hint - currently ignored*/
-#define O_NOATIME 0x100000
-
-#define F_GETLK 14
-#define F_GETLK64 15
+#define O_ACCMODE 0003
+#define O_RDONLY 00
+#define O_WRONLY 01
+#define O_RDWR 02
+#define O_CREAT 0100 /* not fcntl */
+#define O_EXCL 0200 /* not fcntl */
+#define O_NOCTTY 0400 /* not fcntl */
+#define O_TRUNC 01000 /* not fcntl */
+#define O_APPEND 02000
+#define O_NONBLOCK 04000
+#define O_NDELAY O_NONBLOCK
+#define O_SYNC 010000
+#define FASYNC 020000 /* fcntl, for BSD compatibility */
+#define O_DIRECT 040000 /* direct disk access hint */
+#define O_LARGEFILE 0100000
+#define O_DIRECTORY 0200000 /* must be a directory */
+#define O_NOFOLLOW 0400000 /* don't follow links */
+#define O_NOATIME 01000000
+
+#define F_DUPFD 0 /* dup */
+#define F_GETFD 1 /* get close_on_exec */
+#define F_SETFD 2 /* set/clear close_on_exec */
+#define F_GETFL 3 /* get file->f_flags */
+#define F_SETFL 4 /* set file->f_flags */
+#define F_GETLK 5
#define F_SETLK 6
#define F_SETLKW 7
-#define F_SETLK64 16
-#define F_SETLKW64 17
-#define F_SETOWN 24 /* for sockets. */
-#define F_GETOWN 23 /* for sockets. */
+#define F_SETOWN 8 /* for sockets. */
+#define F_GETOWN 9 /* for sockets. */
+#define F_SETSIG 10 /* for sockets. */
+#define F_GETSIG 11 /* for sockets. */
+
+#define F_GETLK64 12 /* using 'struct flock64' */
+#define F_SETLK64 13
+#define F_SETLKW64 14
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK 0
+#define F_WRLCK 1
+#define F_UNLCK 2
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK 4 /* or 3 */
+#define F_SHLCK 8 /* or 4 */
-typedef struct flock {
+/* for leases */
+#define F_INPROGRESS 16
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH 1 /* shared lock */
+#define LOCK_EX 2 /* exclusive lock */
+#define LOCK_NB 4 /* or'd with one of the above to prevent
+ blocking */
+#define LOCK_UN 8 /* remove lock */
+
+#define LOCK_MAND 32 /* This is a mandatory flock */
+#define LOCK_READ 64 /* ... Which allows concurrent read operations */
+#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
+#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
+
+struct flock {
short l_type;
short l_whence;
- __kernel_off_t l_start;
- __kernel_off_t l_len;
- long l_sysid;
- __kernel_pid_t l_pid;
- long pad[4];
-} flock_t;
+ off_t l_start;
+ off_t l_len;
+ pid_t l_pid;
+};
struct flock64 {
short l_type;
short l_whence;
- __kernel_off_t l_start;
- __kernel_off_t l_len;
+ loff_t l_start;
+ loff_t l_len;
pid_t l_pid;
};
-#define HAVE_ARCH_STRUCT_FLOCK
-#define HAVE_ARCH_STRUCT_FLOCK64
-
-#include <asm-generic/fcntl.h>
+#define F_LINUX_SPECIFIC_BASE 1024
#endif /* _XTENSA_FCNTL_H */
diff --git a/include/asm-xtensa/fixmap.h b/include/asm-xtensa/fixmap.h
deleted file mode 100644
index 4423b8ad495..00000000000
--- a/include/asm-xtensa/fixmap.h
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * include/asm-xtensa/fixmap.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_FIXMAP_H
-#define _XTENSA_FIXMAP_H
-
-#include <asm/processor.h>
-
-#ifdef CONFIG_MMU
-
-/*
- * Here we define all the compile-time virtual addresses.
- */
-
-#if XCHAL_SEG_MAPPABLE_VADDR != 0
-# error "Current port requires virtual user space starting at 0"
-#endif
-#if XCHAL_SEG_MAPPABLE_SIZE < 0x80000000
-# error "Current port requires at least 0x8000000 bytes for user space"
-#endif
-
-/* Verify instruction/data ram/rom and xlmi don't overlay vmalloc space. */
-
-#define __IN_VMALLOC(addr) \
- (((addr) >= VMALLOC_START) && ((addr) < VMALLOC_END))
-#define __SPAN_VMALLOC(start,end) \
- (((start) < VMALLOC_START) && ((end) >= VMALLOC_END))
-#define INSIDE_VMALLOC(start,end) \
- (__IN_VMALLOC((start)) || __IN_VMALLOC(end) || __SPAN_VMALLOC((start),(end)))
-
-#if XCHAL_NUM_INSTROM
-# if XCHAL_NUM_INSTROM == 1
-# if INSIDE_VMALLOC(XCHAL_INSTROM0_VADDR,XCHAL_INSTROM0_VADDR+XCHAL_INSTROM0_SIZE)
-# error vmalloc range conflicts with instrom0
-# endif
-# endif
-# if XCHAL_NUM_INSTROM == 2
-# if INSIDE_VMALLOC(XCHAL_INSTROM1_VADDR,XCHAL_INSTROM1_VADDR+XCHAL_INSTROM1_SIZE)
-# error vmalloc range conflicts with instrom1
-# endif
-# endif
-#endif
-
-#if XCHAL_NUM_INSTRAM
-# if XCHAL_NUM_INSTRAM == 1
-# if INSIDE_VMALLOC(XCHAL_INSTRAM0_VADDR,XCHAL_INSTRAM0_VADDR+XCHAL_INSTRAM0_SIZE)
-# error vmalloc range conflicts with instram0
-# endif
-# endif
-# if XCHAL_NUM_INSTRAM == 2
-# if INSIDE_VMALLOC(XCHAL_INSTRAM1_VADDR,XCHAL_INSTRAM1_VADDR+XCHAL_INSTRAM1_SIZE)
-# error vmalloc range conflicts with instram1
-# endif
-# endif
-#endif
-
-#if XCHAL_NUM_DATAROM
-# if XCHAL_NUM_DATAROM == 1
-# if INSIDE_VMALLOC(XCHAL_DATAROM0_VADDR,XCHAL_DATAROM0_VADDR+XCHAL_DATAROM0_SIZE)
-# error vmalloc range conflicts with datarom0
-# endif
-# endif
-# if XCHAL_NUM_DATAROM == 2
-# if INSIDE_VMALLOC(XCHAL_DATAROM1_VADDR,XCHAL_DATAROM1_VADDR+XCHAL_DATAROM1_SIZE)
-# error vmalloc range conflicts with datarom1
-# endif
-# endif
-#endif
-
-#if XCHAL_NUM_DATARAM
-# if XCHAL_NUM_DATARAM == 1
-# if INSIDE_VMALLOC(XCHAL_DATARAM0_VADDR,XCHAL_DATARAM0_VADDR+XCHAL_DATARAM0_SIZE)
-# error vmalloc range conflicts with dataram0
-# endif
-# endif
-# if XCHAL_NUM_DATARAM == 2
-# if INSIDE_VMALLOC(XCHAL_DATARAM1_VADDR,XCHAL_DATARAM1_VADDR+XCHAL_DATARAM1_SIZE)
-# error vmalloc range conflicts with dataram1
-# endif
-# endif
-#endif
-
-#if XCHAL_NUM_XLMI
-# if XCHAL_NUM_XLMI == 1
-# if INSIDE_VMALLOC(XCHAL_XLMI0_VADDR,XCHAL_XLMI0_VADDR+XCHAL_XLMI0_SIZE)
-# error vmalloc range conflicts with xlmi0
-# endif
-# endif
-# if XCHAL_NUM_XLMI == 2
-# if INSIDE_VMALLOC(XCHAL_XLMI1_VADDR,XCHAL_XLMI1_VADDR+XCHAL_XLMI1_SIZE)
-# error vmalloc range conflicts with xlmi1
-# endif
-# endif
-#endif
-
-#if (XCHAL_NUM_INSTROM > 2) || \
- (XCHAL_NUM_INSTRAM > 2) || \
- (XCHAL_NUM_DATARAM > 2) || \
- (XCHAL_NUM_DATAROM > 2) || \
- (XCHAL_NUM_XLMI > 2)
-# error Insufficient checks on vmalloc above for more than 2 devices
-#endif
-
-/*
- * USER_VM_SIZE does not necessarily equal TASK_SIZE. We bumped
- * TASK_SIZE down to 0x4000000 to simplify the handling of windowed
- * call instructions (currently limited to a range of 1 GByte). User
- * tasks may very well reclaim the VM space from 0x40000000 to
- * 0x7fffffff in the future, so we do not want the kernel becoming
- * accustomed to having any of its stuff (e.g., page tables) in this
- * region. This VM region is no-man's land for now.
- */
-
-#define USER_VM_START XCHAL_SEG_MAPPABLE_VADDR
-#define USER_VM_SIZE 0x80000000
-
-/* Size of page table: */
-
-#define PGTABLE_SIZE_BITS (32 - XCHAL_MMU_MIN_PTE_PAGE_SIZE + 2)
-#define PGTABLE_SIZE (1L << PGTABLE_SIZE_BITS)
-
-/* All kernel-mappable space: */
-
-#define KERNEL_ALLMAP_START (USER_VM_START + USER_VM_SIZE)
-#define KERNEL_ALLMAP_SIZE (XCHAL_SEG_MAPPABLE_SIZE - KERNEL_ALLMAP_START)
-
-/* Carve out page table at start of kernel-mappable area: */
-
-#if KERNEL_ALLMAP_SIZE < PGTABLE_SIZE
-#error "Gimme some space for page table!"
-#endif
-#define PGTABLE_START KERNEL_ALLMAP_START
-
-/* Remaining kernel-mappable space: */
-
-#define KERNEL_MAPPED_START (KERNEL_ALLMAP_START + PGTABLE_SIZE)
-#define KERNEL_MAPPED_SIZE (KERNEL_ALLMAP_SIZE - PGTABLE_SIZE)
-
-#if KERNEL_MAPPED_SIZE < 0x01000000 /* 16 MB is arbitrary for now */
-# error "Shouldn't the kernel have at least *some* mappable space?"
-#endif
-
-#define MAX_LOW_MEMORY XCHAL_KSEG_CACHED_SIZE
-
-#endif
-
-/*
- * Some constants used elsewhere, but perhaps only in Xtensa header
- * files, so maybe we can get rid of some and access compile-time HAL
- * directly...
- *
- * Note: We assume that system RAM is located at the very start of the
- * kernel segments !!
- */
-#define KERNEL_VM_LOW XCHAL_KSEG_CACHED_VADDR
-#define KERNEL_VM_HIGH XCHAL_KSEG_BYPASS_VADDR
-#define KERNEL_SPACE XCHAL_KSEG_CACHED_VADDR
-
-/*
- * Returns the physical/virtual addresses of the kernel space
- * (works with the cached kernel segment only, which is the
- * one normally used for kernel operation).
- */
-
-/* PHYSICAL BYPASS CACHED
- *
- * bypass vaddr bypass paddr * cached vaddr
- * cached vaddr cached paddr bypass vaddr *
- * bypass paddr * bypass vaddr cached vaddr
- * cached paddr * bypass vaddr cached vaddr
- * other * * *
- */
-
-#define PHYSADDR(a) \
-(((unsigned)(a) >= XCHAL_KSEG_BYPASS_VADDR \
- && (unsigned)(a) < XCHAL_KSEG_BYPASS_VADDR + XCHAL_KSEG_BYPASS_SIZE) ? \
- (unsigned)(a) - XCHAL_KSEG_BYPASS_VADDR + XCHAL_KSEG_BYPASS_PADDR : \
- ((unsigned)(a) >= XCHAL_KSEG_CACHED_VADDR \
- && (unsigned)(a) < XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_CACHED_SIZE) ? \
- (unsigned)(a) - XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_CACHED_PADDR : \
- (unsigned)(a))
-
-#define BYPASS_ADDR(a) \
-(((unsigned)(a) >= XCHAL_KSEG_BYPASS_PADDR \
- && (unsigned)(a) < XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_SIZE) ? \
- (unsigned)(a) - XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_VADDR : \
- ((unsigned)(a) >= XCHAL_KSEG_CACHED_PADDR \
- && (unsigned)(a) < XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_SIZE) ? \
- (unsigned)(a) - XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_BYPASS_VADDR : \
- ((unsigned)(a) >= XCHAL_KSEG_CACHED_VADDR \
- && (unsigned)(a) < XCHAL_KSEG_CACHED_VADDR+XCHAL_KSEG_CACHED_SIZE)? \
- (unsigned)(a) - XCHAL_KSEG_CACHED_VADDR+XCHAL_KSEG_BYPASS_VADDR: \
- (unsigned)(a))
-
-#define CACHED_ADDR(a) \
-(((unsigned)(a) >= XCHAL_KSEG_BYPASS_PADDR \
- && (unsigned)(a) < XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_SIZE) ? \
- (unsigned)(a) - XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_CACHED_VADDR : \
- ((unsigned)(a) >= XCHAL_KSEG_CACHED_PADDR \
- && (unsigned)(a) < XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_SIZE) ? \
- (unsigned)(a) - XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_VADDR : \
- ((unsigned)(a) >= XCHAL_KSEG_BYPASS_VADDR \
- && (unsigned)(a) < XCHAL_KSEG_BYPASS_VADDR+XCHAL_KSEG_BYPASS_SIZE) ? \
- (unsigned)(a) - XCHAL_KSEG_BYPASS_VADDR+XCHAL_KSEG_CACHED_VADDR : \
- (unsigned)(a))
-
-#define PHYSADDR_IO(a) \
-(((unsigned)(a) >= XCHAL_KIO_BYPASS_VADDR \
- && (unsigned)(a) < XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_SIZE) ? \
- (unsigned)(a) - XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_PADDR : \
- ((unsigned)(a) >= XCHAL_KIO_CACHED_VADDR \
- && (unsigned)(a) < XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_SIZE) ? \
- (unsigned)(a) - XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_PADDR : \
- (unsigned)(a))
-
-#define BYPASS_ADDR_IO(a) \
-(((unsigned)(a) >= XCHAL_KIO_BYPASS_PADDR \
- && (unsigned)(a) < XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_SIZE) ? \
- (unsigned)(a) - XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_VADDR : \
- ((unsigned)(a) >= XCHAL_KIO_CACHED_PADDR \
- && (unsigned)(a) < XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_SIZE) ? \
- (unsigned)(a) - XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_BYPASS_VADDR : \
- ((unsigned)(a) >= XCHAL_KIO_CACHED_VADDR \
- && (unsigned)(a) < XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_SIZE) ? \
- (unsigned)(a) - XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_BYPASS_VADDR : \
- (unsigned)(a))
-
-#define CACHED_ADDR_IO(a) \
-(((unsigned)(a) >= XCHAL_KIO_BYPASS_PADDR \
- && (unsigned)(a) < XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_SIZE) ? \
- (unsigned)(a) - XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_CACHED_VADDR : \
- ((unsigned)(a) >= XCHAL_KIO_CACHED_PADDR \
- && (unsigned)(a) < XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_SIZE) ? \
- (unsigned)(a) - XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_VADDR : \
- ((unsigned)(a) >= XCHAL_KIO_BYPASS_VADDR \
- && (unsigned)(a) < XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_SIZE) ? \
- (unsigned)(a) - XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_CACHED_VADDR : \
- (unsigned)(a))
-
-#endif /* _XTENSA_ADDRSPACE_H */
-
-
-
-
-
diff --git a/include/asm-xtensa/io.h b/include/asm-xtensa/io.h
index 556e5eed34f..31ffc3f119c 100644
--- a/include/asm-xtensa/io.h
+++ b/include/asm-xtensa/io.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-xtensa/io.h
+ * include/asm-xtensa/io.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
@@ -15,10 +15,11 @@
#include <asm/byteorder.h>
#include <linux/types.h>
-#include <asm/fixmap.h>
-
-#define _IO_BASE 0
+#define XCHAL_KIO_CACHED_VADDR 0xf0000000
+#define XCHAL_KIO_BYPASS_VADDR 0xf8000000
+#define XCHAL_KIO_PADDR 0xf0000000
+#define XCHAL_KIO_SIZE 0x08000000
/*
* swap functions to change byte order from little-endian to big-endian and
@@ -42,40 +43,43 @@ static inline unsigned int _swapl (unsigned int v)
static inline unsigned long virt_to_phys(volatile void * address)
{
- return PHYSADDR((unsigned long)address);
+ return __pa(address);
}
static inline void * phys_to_virt(unsigned long address)
{
- return (void*) CACHED_ADDR(address);
+ return __va(address);
}
/*
- * IO bus memory addresses are also 1:1 with the physical address
+ * virt_to_bus and bus_to_virt are deprecated.
*/
-static inline unsigned long virt_to_bus(volatile void * address)
-{
- return PHYSADDR((unsigned long)address);
-}
-
-static inline void * bus_to_virt (unsigned long address)
-{
- return (void *) CACHED_ADDR(address);
-}
+#define virt_to_bus(x) virt_to_phys(x)
+#define bus_to_virt(x) phys_to_virt(x)
/*
- * Change "struct page" to physical address.
+ * Return the virtual (cached) address for the specified bus memory.
+ * Note that we currently don't support any address outside the KIO segment.
*/
static inline void *ioremap(unsigned long offset, unsigned long size)
{
- return (void *) CACHED_ADDR_IO(offset);
+ if (offset >= XCHAL_KIO_PADDR
+ && offset < XCHAL_KIO_PADDR + XCHAL_KIO_SIZE)
+ return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_BYPASS_VADDR);
+
+ else
+ BUG();
}
static inline void *ioremap_nocache(unsigned long offset, unsigned long size)
{
- return (void *) BYPASS_ADDR_IO(offset);
+ if (offset >= XCHAL_KIO_PADDR
+ && offset < XCHAL_KIO_PADDR + XCHAL_KIO_SIZE)
+ return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_CACHED_VADDR);
+ else
+ BUG();
}
static inline void iounmap(void *addr)
@@ -121,9 +125,6 @@ static inline void __raw_writel(__u32 b, volatile void __iomem *addr)
*(__force volatile __u32 *)(addr) = b;
}
-
-
-
/* These are the definitions for the x86 IO instructions
* inb/inw/inl/outb/outw/outl, the "string" versions
* insb/insw/insl/outsb/outsw/outsl, and the "pausing" versions
@@ -131,11 +132,11 @@ static inline void __raw_writel(__u32 b, volatile void __iomem *addr)
* The macros don't do byte-swapping.
*/
-#define inb(port) readb((u8 *)((port)+_IO_BASE))
-#define outb(val, port) writeb((val),(u8 *)((unsigned long)(port)+_IO_BASE))
-#define inw(port) readw((u16 *)((port)+_IO_BASE))
-#define outw(val, port) writew((val),(u16 *)((unsigned long)(port)+_IO_BASE))
-#define inl(port) readl((u32 *)((port)+_IO_BASE))
+#define inb(port) readb((u8 *)((port)))
+#define outb(val, port) writeb((val),(u8 *)((unsigned long)(port)))
+#define inw(port) readw((u16 *)((port)))
+#define outw(val, port) writew((val),(u16 *)((unsigned long)(port)))
+#define inl(port) readl((u32 *)((port)))
#define outl(val, port) writel((val),(u32 *)((unsigned long)(port)))
#define inb_p(port) inb((port))
@@ -180,14 +181,13 @@ extern void outsl (unsigned long port, const void *src, unsigned long count);
/*
- * * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * * access
- * */
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem access
+ */
#define xlate_dev_mem_ptr(p) __va(p)
/*
- * * Convert a virtual cached pointer to an uncached pointer
- * */
+ * Convert a virtual cached pointer to an uncached pointer
+ */
#define xlate_dev_kmem_ptr(p) p
diff --git a/include/asm-xtensa/irq.h b/include/asm-xtensa/irq.h
index 049fde7e752..fc73b7f11af 100644
--- a/include/asm-xtensa/irq.h
+++ b/include/asm-xtensa/irq.h
@@ -12,8 +12,7 @@
#define _XTENSA_IRQ_H
#include <asm/platform/hardware.h>
-
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
#ifndef PLATFORM_NR_IRQS
# define PLATFORM_NR_IRQS 0
@@ -27,10 +26,5 @@ static __inline__ int irq_canonicalize(int irq)
}
struct irqaction;
-#if 0 // FIXME
-extern void disable_irq_nosync(unsigned int);
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-#endif
#endif /* _XTENSA_IRQ_H */
diff --git a/include/asm-xtensa/irq_regs.h b/include/asm-xtensa/irq_regs.h
new file mode 100644
index 00000000000..3dd9c0b7027
--- /dev/null
+++ b/include/asm-xtensa/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-xtensa/mmu_context.h b/include/asm-xtensa/mmu_context.h
index af683a74a4e..f14851f086c 100644
--- a/include/asm-xtensa/mmu_context.h
+++ b/include/asm-xtensa/mmu_context.h
@@ -16,187 +16,32 @@
#include <linux/stringify.h>
#include <asm/pgtable.h>
-#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
-/*
- * Linux was ported to Xtensa assuming all auto-refill ways in set 0
- * had the same properties (a very likely assumption). Multiple sets
- * of auto-refill ways will still work properly, but not as optimally
- * as the Xtensa designer may have assumed.
- *
- * We make this case a hard #error, killing the kernel build, to alert
- * the developer to this condition (which is more likely an error).
- * You super-duper clever developers can change it to a warning or
- * remove it altogether if you think you know what you're doing. :)
- */
+#define XCHAL_MMU_ASID_BITS 8
#if (XCHAL_HAVE_TLBS != 1)
# error "Linux must have an MMU!"
#endif
-#if ((XCHAL_ITLB_ARF_WAYS == 0) || (XCHAL_DTLB_ARF_WAYS == 0))
-# error "MMU must have auto-refill ways"
-#endif
-
-#if ((XCHAL_ITLB_ARF_SETS != 1) || (XCHAL_DTLB_ARF_SETS != 1))
-# error Linux may not use all auto-refill ways as efficiently as you think
-#endif
-
-#if (XCHAL_MMU_MAX_PTE_PAGE_SIZE != XCHAL_MMU_MIN_PTE_PAGE_SIZE)
-# error Only one page size allowed!
-#endif
-
extern unsigned long asid_cache;
-extern pgd_t *current_pgd;
-
-/*
- * Define the number of entries per auto-refill way in set 0 of both I and D
- * TLBs. We deal only with set 0 here (an assumption further explained in
- * assertions.h). Also, define the total number of ARF entries in both TLBs.
- */
-
-#define ITLB_ENTRIES_PER_ARF_WAY (XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,ENTRIES))
-#define DTLB_ENTRIES_PER_ARF_WAY (XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,ENTRIES))
-
-#define ITLB_ENTRIES \
- (ITLB_ENTRIES_PER_ARF_WAY * (XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,WAYS)))
-#define DTLB_ENTRIES \
- (DTLB_ENTRIES_PER_ARF_WAY * (XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,WAYS)))
-
-
-/*
- * SMALLEST_NTLB_ENTRIES is the smaller of ITLB_ENTRIES and DTLB_ENTRIES.
- * In practice, they are probably equal. This macro simplifies function
- * flush_tlb_range().
- */
-
-#if (DTLB_ENTRIES < ITLB_ENTRIES)
-# define SMALLEST_NTLB_ENTRIES DTLB_ENTRIES
-#else
-# define SMALLEST_NTLB_ENTRIES ITLB_ENTRIES
-#endif
-
-
-/*
- * asid_cache tracks only the ASID[USER_RING] field of the RASID special
- * register, which is the current user-task asid allocation value.
- * mm->context has the same meaning. When it comes time to write the
- * asid_cache or mm->context values to the RASID special register, we first
- * shift the value left by 8, then insert the value.
- * ASID[0] always contains the kernel's asid value, and we reserve three
- * other asid values that we never assign to user tasks.
- */
-
-#define ASID_INC 0x1
-#define ASID_MASK ((1 << XCHAL_MMU_ASID_BITS) - 1)
-
-/*
- * XCHAL_MMU_ASID_INVALID is a configurable Xtensa processor constant
- * indicating invalid address space. XCHAL_MMU_ASID_KERNEL is a configurable
- * Xtensa processor constant indicating the kernel address space. They can
- * be arbitrary values.
- *
- * We identify three more unique, reserved ASID values to use in the unused
- * ring positions. No other user process will be assigned these reserved
- * ASID values.
- *
- * For example, given that
- *
- * XCHAL_MMU_ASID_INVALID == 0
- * XCHAL_MMU_ASID_KERNEL == 1
- *
- * the following maze of #if statements would generate
- *
- * ASID_RESERVED_1 == 2
- * ASID_RESERVED_2 == 3
- * ASID_RESERVED_3 == 4
- * ASID_FIRST_NONRESERVED == 5
- */
-
-#if (XCHAL_MMU_ASID_INVALID != XCHAL_MMU_ASID_KERNEL + 1)
-# define ASID_RESERVED_1 ((XCHAL_MMU_ASID_KERNEL + 1) & ASID_MASK)
-#else
-# define ASID_RESERVED_1 ((XCHAL_MMU_ASID_KERNEL + 2) & ASID_MASK)
-#endif
-
-#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_1 + 1)
-# define ASID_RESERVED_2 ((ASID_RESERVED_1 + 1) & ASID_MASK)
-#else
-# define ASID_RESERVED_2 ((ASID_RESERVED_1 + 2) & ASID_MASK)
-#endif
-
-#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_2 + 1)
-# define ASID_RESERVED_3 ((ASID_RESERVED_2 + 1) & ASID_MASK)
-#else
-# define ASID_RESERVED_3 ((ASID_RESERVED_2 + 2) & ASID_MASK)
-#endif
-
-#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_3 + 1)
-# define ASID_FIRST_NONRESERVED ((ASID_RESERVED_3 + 1) & ASID_MASK)
-#else
-# define ASID_FIRST_NONRESERVED ((ASID_RESERVED_3 + 2) & ASID_MASK)
-#endif
-
-#define ASID_ALL_RESERVED ( ((ASID_RESERVED_1) << 24) + \
- ((ASID_RESERVED_2) << 16) + \
- ((ASID_RESERVED_3) << 8) + \
- ((XCHAL_MMU_ASID_KERNEL)) )
-
/*
* NO_CONTEXT is the invalid ASID value that we don't ever assign to
- * any user or kernel context. NO_CONTEXT is a better mnemonic than
- * XCHAL_MMU_ASID_INVALID, so we use it in code instead.
- */
-
-#define NO_CONTEXT XCHAL_MMU_ASID_INVALID
-
-#if (KERNEL_RING != 0)
-# error The KERNEL_RING really should be zero.
-#endif
-
-#if (USER_RING >= XCHAL_MMU_RINGS)
-# error USER_RING cannot be greater than the highest numbered ring.
-#endif
-
-#if (USER_RING == KERNEL_RING)
-# error The user and kernel rings really should not be equal.
-#endif
-
-#if (USER_RING == 1)
-#define ASID_INSERT(x) ( ((ASID_RESERVED_1) << 24) + \
- ((ASID_RESERVED_2) << 16) + \
- (((x) & (ASID_MASK)) << 8) + \
- ((XCHAL_MMU_ASID_KERNEL)) )
-
-#elif (USER_RING == 2)
-#define ASID_INSERT(x) ( ((ASID_RESERVED_1) << 24) + \
- (((x) & (ASID_MASK)) << 16) + \
- ((ASID_RESERVED_2) << 8) + \
- ((XCHAL_MMU_ASID_KERNEL)) )
-
-#elif (USER_RING == 3)
-#define ASID_INSERT(x) ( (((x) & (ASID_MASK)) << 24) + \
- ((ASID_RESERVED_1) << 16) + \
- ((ASID_RESERVED_2) << 8) + \
- ((XCHAL_MMU_ASID_KERNEL)) )
-
-#else
-#error Goofy value for USER_RING
-
-#endif /* USER_RING == 1 */
-
-
-/*
- * All unused by hardware upper bits will be considered
- * as a software asid extension.
+ * any user or kernel context.
+ *
+ * 0 invalid
+ * 1 kernel
+ * 2 reserved
+ * 3 reserved
+ * 4...255 available
*/
-#define ASID_VERSION_MASK ((unsigned long)~(ASID_MASK|(ASID_MASK-1)))
-#define ASID_FIRST_VERSION \
- ((unsigned long)(~ASID_VERSION_MASK) + 1 + ASID_FIRST_NONRESERVED)
+#define NO_CONTEXT 0
+#define ASID_USER_FIRST 4
+#define ASID_MASK ((1 << XCHAL_MMU_ASID_BITS) - 1)
+#define ASID_INSERT(x) (0x03020001 | (((x) & ASID_MASK) << 8))
static inline void set_rasid_register (unsigned long val)
{
@@ -207,67 +52,28 @@ static inline void set_rasid_register (unsigned long val)
static inline unsigned long get_rasid_register (void)
{
unsigned long tmp;
- __asm__ __volatile__ (" rsr %0, "__stringify(RASID)"\n\t" : "=a" (tmp));
+ __asm__ __volatile__ (" rsr %0,"__stringify(RASID)"\n\t" : "=a" (tmp));
return tmp;
}
-
-#if ((XCHAL_MMU_ASID_INVALID == 0) && (XCHAL_MMU_ASID_KERNEL == 1))
-
static inline void
-get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
+__get_new_mmu_context(struct mm_struct *mm)
{
extern void flush_tlb_all(void);
- if (! ((asid += ASID_INC) & ASID_MASK) ) {
+ if (! (++asid_cache & ASID_MASK) ) {
flush_tlb_all(); /* start new asid cycle */
- if (!asid) /* fix version if needed */
- asid = ASID_FIRST_VERSION - ASID_FIRST_NONRESERVED;
- asid += ASID_FIRST_NONRESERVED;
+ asid_cache += ASID_USER_FIRST;
}
- mm->context = asid_cache = asid;
-}
-
-#else
-#warning ASID_{INVALID,KERNEL} values impose non-optimal get_new_mmu_context implementation
-
-/* XCHAL_MMU_ASID_INVALID == 0 and XCHAL_MMU_ASID_KERNEL ==1 are
- really the best, but if you insist... */
-
-static inline int validate_asid (unsigned long asid)
-{
- switch (asid) {
- case XCHAL_MMU_ASID_INVALID:
- case XCHAL_MMU_ASID_KERNEL:
- case ASID_RESERVED_1:
- case ASID_RESERVED_2:
- case ASID_RESERVED_3:
- return 0; /* can't use these values as ASIDs */
- }
- return 1; /* valid */
+ mm->context = asid_cache;
}
static inline void
-get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
+__load_mmu_context(struct mm_struct *mm)
{
- extern void flush_tlb_all(void);
- while (1) {
- asid += ASID_INC;
- if ( ! (asid & ASID_MASK) ) {
- flush_tlb_all(); /* start new asid cycle */
- if (!asid) /* fix version if needed */
- asid = ASID_FIRST_VERSION - ASID_FIRST_NONRESERVED;
- asid += ASID_FIRST_NONRESERVED;
- break; /* no need to validate here */
- }
- if (validate_asid (asid & ASID_MASK))
- break;
- }
- mm->context = asid_cache = asid;
+ set_rasid_register(ASID_INSERT(mm->context));
+ invalidate_page_directory();
}
-#endif
-
-
/*
* Initialize the context related info for a new mm_struct
* instance.
@@ -280,6 +86,20 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
return 0;
}
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+static inline void
+activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+ /* Unconditionally get a new ASID. */
+
+ __get_new_mmu_context(next);
+ __load_mmu_context(next);
+}
+
+
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
@@ -287,11 +107,10 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
/* Check if our ASID is of an older version and thus invalid */
- if ((next->context ^ asid) & ASID_VERSION_MASK)
- get_new_mmu_context(next, asid);
+ if (next->context == NO_CONTEXT || ((next->context^asid) & ~ASID_MASK))
+ __get_new_mmu_context(next);
- set_rasid_register (ASID_INSERT(next->context));
- invalidate_page_directory();
+ __load_mmu_context(next);
}
#define deactivate_mm(tsk, mm) do { } while(0)
@@ -302,20 +121,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
*/
static inline void destroy_context(struct mm_struct *mm)
{
- /* Nothing to do. */
-}
-
-/*
- * After we have set current->mm to a new value, this activates
- * the context for the new mm so we see the new mappings.
- */
-static inline void
-activate_mm(struct mm_struct *prev, struct mm_struct *next)
-{
- /* Unconditionally get a new ASID. */
-
- get_new_mmu_context(next, asid_cache);
- set_rasid_register (ASID_INSERT(next->context));
invalidate_page_directory();
}
diff --git a/include/asm-xtensa/page.h b/include/asm-xtensa/page.h
index 40f4c6c3f58..c631d006194 100644
--- a/include/asm-xtensa/page.h
+++ b/include/asm-xtensa/page.h
@@ -15,18 +15,24 @@
#include <asm/processor.h>
+#define XCHAL_KSEG_CACHED_VADDR 0xd0000000
+#define XCHAL_KSEG_BYPASS_VADDR 0xd8000000
+#define XCHAL_KSEG_PADDR 0x00000000
+#define XCHAL_KSEG_SIZE 0x08000000
+
/*
* PAGE_SHIFT determines the page size
* PAGE_ALIGN(x) aligns the pointer to the (next) page boundary
*/
-#define PAGE_SHIFT XCHAL_MMU_MIN_PTE_PAGE_SIZE
+#define PAGE_SHIFT 12
#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE - 1) & PAGE_MASK)
-#define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS)
#define PAGE_OFFSET XCHAL_KSEG_CACHED_VADDR
+#define MAX_MEM_PFN XCHAL_KSEG_SIZE
+#define PGTABLE_START 0x80000000
#ifdef __ASSEMBLY__
diff --git a/include/asm-xtensa/param.h b/include/asm-xtensa/param.h
index c0eec8260b0..6f281392e3f 100644
--- a/include/asm-xtensa/param.h
+++ b/include/asm-xtensa/param.h
@@ -11,7 +11,7 @@
#ifndef _XTENSA_PARAM_H
#define _XTENSA_PARAM_H
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
#ifdef __KERNEL__
# define HZ 100 /* internal timer frequency */
diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h
index b4318934b10..2d4b5db6ea6 100644
--- a/include/asm-xtensa/pgtable.h
+++ b/include/asm-xtensa/pgtable.h
@@ -14,45 +14,6 @@
#include <asm-generic/pgtable-nopmd.h>
#include <asm/page.h>
-/* Assertions. */
-
-#ifdef CONFIG_MMU
-
-
-#if (XCHAL_MMU_RINGS < 2)
-# error Linux build assumes at least 2 ring levels.
-#endif
-
-#if (XCHAL_MMU_CA_BITS != 4)
-# error We assume exactly four bits for CA.
-#endif
-
-#if (XCHAL_MMU_SR_BITS != 0)
-# error We have no room for SR bits.
-#endif
-
-/*
- * Use the first min-wired way for mapping page-table pages.
- * Page coloring requires a second min-wired way.
- */
-
-#if (XCHAL_DTLB_MINWIRED_SETS == 0)
-# error Need a min-wired way for mapping page-table pages
-#endif
-
-#define DTLB_WAY_PGTABLE XCHAL_DTLB_SET(XCHAL_DTLB_MINWIRED_SET0, WAY)
-
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
-# if XCHAL_DTLB_SET(XCHAL_DTLB_MINWIRED_SET0, WAYS) >= 2
-# define DTLB_WAY_DCACHE_ALIAS0 (DTLB_WAY_PGTABLE + 1)
-# define DTLB_WAY_DCACHE_ALIAS1 (DTLB_WAY_PGTABLE + 2)
-# else
-# error Page coloring requires its own wired dtlb way!
-# endif
-#endif
-
-#endif /* CONFIG_MMU */
-
/*
* We only use two ring levels, user and kernel space.
*/
@@ -97,7 +58,7 @@
#define PGD_ORDER 0
#define PMD_ORDER 0
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
-#define FIRST_USER_ADDRESS XCHAL_SEG_MAPPABLE_VADDR
+#define FIRST_USER_ADDRESS 0
#define FIRST_USER_PGD_NR (FIRST_USER_ADDRESS >> PGDIR_SHIFT)
/* virtual memory area. We keep a distance to other memory regions to be
diff --git a/include/asm-xtensa/platform-iss/hardware.h b/include/asm-xtensa/platform-iss/hardware.h
index 22240f00180..6930c12adc1 100644
--- a/include/asm-xtensa/platform-iss/hardware.h
+++ b/include/asm-xtensa/platform-iss/hardware.h
@@ -12,18 +12,18 @@
* This file contains the default configuration of ISS.
*/
-#ifndef __ASM_XTENSA_ISS_HARDWARE
-#define __ASM_XTENSA_ISS_HARDWARE
+#ifndef _XTENSA_PLATFORM_ISS_HARDWARE_H
+#define _XTENSA_PLATFORM_ISS_HARDWARE_H
/*
* Memory configuration.
*/
-#define PLATFORM_DEFAULT_MEM_START XSHAL_RAM_PADDR
-#define PLATFORM_DEFAULT_MEM_SIZE XSHAL_RAM_VSIZE
+#define PLATFORM_DEFAULT_MEM_START 0x00000000
+#define PLATFORM_DEFAULT_MEM_SIZE 0x08000000
/*
* Interrupt configuration.
*/
-#endif /* __ASM_XTENSA_ISS_HARDWARE */
+#endif /* _XTENSA_PLATFORM_ISS_HARDWARE_H */
diff --git a/include/asm-xtensa/platform-iss/simcall.h b/include/asm-xtensa/platform-iss/simcall.h
new file mode 100644
index 00000000000..6acb572759a
--- /dev/null
+++ b/include/asm-xtensa/platform-iss/simcall.h
@@ -0,0 +1,62 @@
+/*
+ * include/asm-xtensa/platform-iss/hardware.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PLATFORM_ISS_SIMCALL_H
+#define _XTENSA_PLATFORM_ISS_SIMCALL_H
+
+
+/*
+ * System call like services offered by the simulator host.
+ */
+
+#define SYS_nop 0 /* unused */
+#define SYS_exit 1 /*x*/
+#define SYS_fork 2
+#define SYS_read 3 /*x*/
+#define SYS_write 4 /*x*/
+#define SYS_open 5 /*x*/
+#define SYS_close 6 /*x*/
+#define SYS_rename 7 /*x 38 - waitpid */
+#define SYS_creat 8 /*x*/
+#define SYS_link 9 /*x (not implemented on WIN32) */
+#define SYS_unlink 10 /*x*/
+#define SYS_execv 11 /* n/a - execve */
+#define SYS_execve 12 /* 11 - chdir */
+#define SYS_pipe 13 /* 42 - time */
+#define SYS_stat 14 /* 106 - mknod */
+#define SYS_chmod 15
+#define SYS_chown 16 /* 202 - lchown */
+#define SYS_utime 17 /* 30 - break */
+#define SYS_wait 18 /* n/a - oldstat */
+#define SYS_lseek 19 /*x*/
+#define SYS_getpid 20
+#define SYS_isatty 21 /* n/a - mount */
+#define SYS_fstat 22 /* 108 - oldumount */
+#define SYS_time 23 /* 13 - setuid */
+#define SYS_gettimeofday 24 /*x 78 - getuid (not implemented on WIN32) */
+#define SYS_times 25 /*X 43 - stime (Xtensa-specific implementation) */
+#define SYS_socket 26
+#define SYS_sendto 27
+#define SYS_recvfrom 28
+#define SYS_select_one 29 /* not compitible select, one file descriptor at the time */
+#define SYS_bind 30
+#define SYS_ioctl 31
+
+/*
+ * SYS_select_one specifiers
+ */
+
+#define XTISS_SELECT_ONE_READ 1
+#define XTISS_SELECT_ONE_WRITE 2
+#define XTISS_SELECT_ONE_EXCEPT 3
+
+
+#endif /* _XTENSA_PLATFORM_ISS_SIMCALL_H */
+
diff --git a/include/asm-xtensa/posix_types.h b/include/asm-xtensa/posix_types.h
index 2c816b0e776..4ad77dda6d5 100644
--- a/include/asm-xtensa/posix_types.h
+++ b/include/asm-xtensa/posix_types.h
@@ -21,7 +21,7 @@
typedef unsigned long __kernel_ino_t;
typedef unsigned int __kernel_mode_t;
-typedef unsigned short __kernel_nlink_t;
+typedef unsigned long __kernel_nlink_t;
typedef long __kernel_off_t;
typedef int __kernel_pid_t;
typedef unsigned short __kernel_ipc_pid_t;
@@ -60,7 +60,7 @@ typedef struct {
#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
#define __FD_ZERO(set) \
- ((void) memset ((__ptr_t) (set), 0, sizeof (__kernel_fd_set)))
+ ((void) memset ((void *) (set), 0, sizeof (__kernel_fd_set)))
#else /* __GNUC__ */
diff --git a/include/asm-xtensa/processor.h b/include/asm-xtensa/processor.h
index 8b96e77c9d8..4feb9f7f35a 100644
--- a/include/asm-xtensa/processor.h
+++ b/include/asm-xtensa/processor.h
@@ -11,24 +11,18 @@
#ifndef _XTENSA_PROCESSOR_H
#define _XTENSA_PROCESSOR_H
-#ifdef __ASSEMBLY__
-#define _ASMLANGUAGE
-#endif
-
-#include <xtensa/config/core.h>
-#include <xtensa/config/specreg.h>
-#include <xtensa/config/tie.h>
-#include <xtensa/config/system.h>
+#include <asm/variant/core.h>
+#include <asm/coprocessor.h>
#include <linux/compiler.h>
#include <asm/ptrace.h>
#include <asm/types.h>
-#include <asm/coprocessor.h>
+#include <asm/regs.h>
/* Assertions. */
#if (XCHAL_HAVE_WINDOWED != 1)
-#error Linux requires the Xtensa Windowed Registers Option.
+# error Linux requires the Xtensa Windowed Registers Option.
#endif
/*
@@ -145,11 +139,11 @@ struct thread_struct {
* Note: We set-up ps as if we did a call4 to the new pc.
* set_thread_state in signal.c depends on it.
*/
-#define USER_PS_VALUE ( (1 << XCHAL_PS_WOE_SHIFT) + \
- (1 << XCHAL_PS_CALLINC_SHIFT) + \
- (USER_RING << XCHAL_PS_RING_SHIFT) + \
- (1 << XCHAL_PS_PROGSTACK_SHIFT) + \
- (1 << XCHAL_PS_EXCM_SHIFT) )
+#define USER_PS_VALUE ((1 << PS_WOE_BIT) | \
+ (1 << PS_CALLINC_SHIFT) | \
+ (USER_RING << PS_RING_SHIFT) | \
+ (1 << PS_UM_BIT) | \
+ (1 << PS_EXCM_BIT))
/* Clearing a0 terminates the backtrace. */
#define start_thread(regs, new_pc, new_sp) \
diff --git a/include/asm-xtensa/ptrace.h b/include/asm-xtensa/ptrace.h
index a5ac71a5205..1b7fe363fad 100644
--- a/include/asm-xtensa/ptrace.h
+++ b/include/asm-xtensa/ptrace.h
@@ -11,7 +11,7 @@
#ifndef _XTENSA_PTRACE_H
#define _XTENSA_PTRACE_H
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
/*
* Kernel stack
diff --git a/include/asm-xtensa/regs.h b/include/asm-xtensa/regs.h
new file mode 100644
index 00000000000..c913d259faa
--- /dev/null
+++ b/include/asm-xtensa/regs.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2006 Tensilica, Inc. All Rights Reserved.
+ *
+ * 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 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+#ifndef _XTENSA_REGS_H
+#define _XTENSA_REGS_H
+
+/* Special registers. */
+
+#define LBEG 0
+#define LEND 1
+#define LCOUNT 2
+#define SAR 3
+#define BR 4
+#define SCOMPARE1 12
+#define ACCHI 16
+#define ACCLO 17
+#define MR 32
+#define WINDOWBASE 72
+#define WINDOWSTART 73
+#define PTEVADDR 83
+#define RASID 90
+#define ITLBCFG 91
+#define DTLBCFG 92
+#define IBREAKENABLE 96
+#define DDR 104
+#define IBREAKA 128
+#define DBREAKA 144
+#define DBREAKC 160
+#define EPC 176
+#define EPC_1 177
+#define DEPC 192
+#define EPS 192
+#define EPS_1 193
+#define EXCSAVE 208
+#define EXCSAVE_1 209
+#define INTERRUPT 226
+#define INTENABLE 228
+#define PS 230
+#define THREADPTR 231
+#define EXCCAUSE 232
+#define DEBUGCAUSE 233
+#define CCOUNT 234
+#define PRID 235
+#define ICOUNT 236
+#define ICOUNTLEVEL 237
+#define EXCVADDR 238
+#define CCOMPARE 240
+#define MISC 244
+
+/* Special names for read-only and write-only interrupt registers. */
+
+#define INTREAD 226
+#define INTSET 226
+#define INTCLEAR 227
+
+/* EXCCAUSE register fields */
+
+#define EXCCAUSE_EXCCAUSE_SHIFT 0
+#define EXCCAUSE_EXCCAUSE_MASK 0x3F
+
+#define EXCCAUSE_ILLEGAL_INSTRUCTION 0
+#define EXCCAUSE_SYSTEM_CALL 1
+#define EXCCAUSE_INSTRUCTION_FETCH_ERROR 2
+#define EXCCAUSE_LOAD_STORE_ERROR 3
+#define EXCCAUSE_LEVEL1_INTERRUPT 4
+#define EXCCAUSE_ALLOCA 5
+#define EXCCAUSE_INTEGER_DIVIDE_BY_ZERO 6
+#define EXCCAUSE_SPECULATION 7
+#define EXCCAUSE_PRIVILEGED 8
+#define EXCCAUSE_UNALIGNED 9
+#define EXCCAUSE_ITLB_MISS 16
+#define EXCCAUSE_ITLB_MULTIHIT 17
+#define EXCCAUSE_ITLB_PRIVILEGE 18
+#define EXCCAUSE_ITLB_SIZE_RESTRICTION 19
+#define EXCCAUSE_FETCH_CACHE_ATTRIBUTE 20
+#define EXCCAUSE_DTLB_MISS 24
+#define EXCCAUSE_DTLB_MULTIHIT 25
+#define EXCCAUSE_DTLB_PRIVILEGE 26
+#define EXCCAUSE_DTLB_SIZE_RESTRICTION 27
+#define EXCCAUSE_LOAD_CACHE_ATTRIBUTE 28
+#define EXCCAUSE_STORE_CACHE_ATTRIBUTE 29
+#define EXCCAUSE_FLOATING_POINT 40
+
+/* PS register fields. */
+
+#define PS_WOE_BIT 18
+#define PS_CALLINC_SHIFT 16
+#define PS_CALLINC_MASK 0x00030000
+#define PS_OWB_SHIFT 8
+#define PS_OWB_MASK 0x00000F00
+#define PS_RING_SHIFT 6
+#define PS_RING_MASK 0x000000C0
+#define PS_UM_BIT 5
+#define PS_EXCM_BIT 4
+#define PS_INTLEVEL_SHIFT 0
+#define PS_INTLEVEL_MASK 0x0000000F
+
+/* DBREAKCn register fields. */
+
+#define DBREAKC_MASK_BIT 0
+#define DBREAKC_MASK_MASK 0x0000003F
+#define DBREAKC_LOAD_BIT 30
+#define DBREAKC_LOAD_MASK 0x40000000
+#define DBREAKC_STOR_BIT 31
+#define DBREAKC_STOR_MASK 0x80000000
+
+/* DEBUGCAUSE register fields. */
+
+#define DEBUGCAUSE_DEBUGINT_BIT 5 /* External debug interrupt */
+#define DEBUGCAUSE_BREAKN_BIT 4 /* BREAK.N instruction */
+#define DEBUGCAUSE_BREAK_BIT 3 /* BREAK instruction */
+#define DEBUGCAUSE_DBREAK_BIT 2 /* DBREAK match */
+#define DEBUGCAUSE_IBREAK_BIT 1 /* IBREAK match */
+#define DEBUGCAUSE_ICOUNT_BIT 0 /* ICOUNT would incr. to zero */
+
+#endif /* _XTENSA_SPECREG_H */
+
diff --git a/include/asm-xtensa/sembuf.h b/include/asm-xtensa/sembuf.h
index 2d26c47666f..c15870493b3 100644
--- a/include/asm-xtensa/sembuf.h
+++ b/include/asm-xtensa/sembuf.h
@@ -25,7 +25,7 @@
struct semid64_ds {
struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
-#if XCHAL_HAVE_LE
+#ifdef __XTENSA_EL__
__kernel_time_t sem_otime; /* last semop time */
unsigned long __unused1;
__kernel_time_t sem_ctime; /* last change time */
diff --git a/include/asm-xtensa/shmbuf.h b/include/asm-xtensa/shmbuf.h
index a30b81a4b93..ad4b0121782 100644
--- a/include/asm-xtensa/shmbuf.h
+++ b/include/asm-xtensa/shmbuf.h
@@ -19,6 +19,7 @@
#ifndef _XTENSA_SHMBUF_H
#define _XTENSA_SHMBUF_H
+#if defined (__XTENSA_EL__)
struct shmid64_ds {
struct ipc64_perm shm_perm; /* operation perms */
size_t shm_segsz; /* size of segment (bytes) */
@@ -34,6 +35,26 @@ struct shmid64_ds {
unsigned long __unused4;
unsigned long __unused5;
};
+#elif defined (__XTENSA_EB__)
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+ size_t shm_segsz; /* size of segment (bytes) */
+ __kernel_time_t shm_atime; /* last attach time */
+ unsigned long __unused1;
+ __kernel_time_t shm_dtime; /* last detach time */
+ unsigned long __unused2;
+ __kernel_time_t shm_ctime; /* last change time */
+ unsigned long __unused3;
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+#else
+# error endian order not defined
+#endif
+
struct shminfo64 {
unsigned long shmmax;
diff --git a/include/asm-xtensa/stat.h b/include/asm-xtensa/stat.h
index 2f4662ff6c3..149f4bce092 100644
--- a/include/asm-xtensa/stat.h
+++ b/include/asm-xtensa/stat.h
@@ -13,93 +13,57 @@
#include <linux/types.h>
-struct __old_kernel_stat {
- unsigned short st_dev;
- unsigned short st_ino;
- unsigned short st_mode;
- unsigned short st_nlink;
- unsigned short st_uid;
- unsigned short st_gid;
- unsigned short st_rdev;
- unsigned long st_size;
- unsigned long st_atime;
- unsigned long st_mtime;
- unsigned long st_ctime;
-};
-
#define STAT_HAVE_NSEC 1
struct stat {
- unsigned short st_dev;
- unsigned short __pad1;
- unsigned long st_ino;
- unsigned short st_mode;
- unsigned short st_nlink;
- unsigned short st_uid;
- unsigned short st_gid;
- unsigned short st_rdev;
- unsigned short __pad2;
- unsigned long st_size;
- unsigned long st_blksize;
- unsigned long st_blocks;
- unsigned long st_atime;
- unsigned long st_atime_nsec;
- unsigned long st_mtime;
- unsigned long st_mtime_nsec;
- unsigned long st_ctime;
- unsigned long st_ctime_nsec;
- unsigned long __unused4;
- unsigned long __unused5;
+ unsigned long st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ unsigned int st_rdev;
+ off_t st_size;
+ unsigned long st_blksize;
+ unsigned long st_blocks;
+ unsigned long st_atime;
+ unsigned long st_atime_nsec;
+ unsigned long st_mtime;
+ unsigned long st_mtime_nsec;
+ unsigned long st_ctime;
+ unsigned long st_ctime_nsec;
+ unsigned long __unused4;
+ unsigned long __unused5;
};
-/* This matches struct stat64 in glibc-2.2.3. */
+/* This matches struct stat64 in glibc-2.3 */
struct stat64 {
-#ifdef __XTENSA_EL__
- unsigned short st_dev; /* Device */
- unsigned char __pad0[10];
-#else
- unsigned char __pad0[6];
- unsigned short st_dev;
- unsigned char __pad1[2];
-#endif
-
-#define STAT64_HAS_BROKEN_ST_INO 1
- unsigned long __st_ino; /* 32bit file serial number. */
-
+ unsigned long long st_dev; /* Device */
+ unsigned long long st_ino; /* File serial number */
unsigned int st_mode; /* File mode. */
unsigned int st_nlink; /* Link count. */
unsigned int st_uid; /* User ID of the file's owner. */
unsigned int st_gid; /* Group ID of the file's group. */
-
-#ifdef __XTENSA_EL__
- unsigned short st_rdev; /* Device number, if device. */
- unsigned char __pad3[10];
-#else
- unsigned char __pad2[6];
- unsigned short st_rdev;
- unsigned char __pad3[2];
-#endif
-
- long long int st_size; /* Size of file, in bytes. */
- long int st_blksize; /* Optimal block size for I/O. */
-
-#ifdef __XTENSA_EL__
- unsigned long st_blocks; /* Number 512-byte blocks allocated. */
- unsigned long __pad4;
+ unsigned long long st_rdev; /* Device number, if device. */
+ long long st_size; /* Size of file, in bytes. */
+ long st_blksize; /* Optimal block size for I/O. */
+ unsigned long __unused2;
+#ifdef __XTENSA_EB__
+ unsigned long __unused3;
+ long st_blocks; /* Number 512-byte blocks allocated. */
#else
- unsigned long __pad4;
- unsigned long st_blocks;
+ long st_blocks; /* Number 512-byte blocks allocated. */
+ unsigned long __unused3;
#endif
-
- unsigned long __pad5;
- long int st_atime; /* Time of last access. */
- unsigned long st_atime_nsec;
- long int st_mtime; /* Time of last modification. */
- unsigned long st_mtime_nsec;
- long int st_ctime; /* Time of last status change. */
- unsigned long st_ctime_nsec;
- unsigned long long int st_ino; /* File serial number. */
+ long st_atime; /* Time of last access. */
+ unsigned long st_atime_nsec;
+ long st_mtime; /* Time of last modification. */
+ unsigned long st_mtime_nsec;
+ long st_ctime; /* Time of last status change. */
+ unsigned long st_ctime_nsec;
+ unsigned long __unused4;
+ unsigned long __unused5;
};
#endif /* _XTENSA_STAT_H */
diff --git a/include/asm-xtensa/syscall.h b/include/asm-xtensa/syscall.h
new file mode 100644
index 00000000000..6cb0d42f11c
--- /dev/null
+++ b/include/asm-xtensa/syscall.h
@@ -0,0 +1,20 @@
+struct pt_regs;
+struct sigaction;
+asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*);
+asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*);
+asmlinkage long xtensa_pipe(int __user *);
+asmlinkage long xtensa_mmap2(unsigned long, unsigned long, unsigned long,
+ unsigned long, unsigned long, unsigned long);
+asmlinkage long xtensa_ptrace(long, long, long, long);
+asmlinkage long xtensa_sigreturn(struct pt_regs*);
+asmlinkage long xtensa_rt_sigreturn(struct pt_regs*);
+asmlinkage long xtensa_sigsuspend(struct pt_regs*);
+asmlinkage long xtensa_rt_sigsuspend(struct pt_regs*);
+asmlinkage long xtensa_sigaction(int, const struct old_sigaction*,
+ struct old_sigaction*);
+asmlinkage long xtensa_sigaltstack(struct pt_regs *regs);
+asmlinkage long sys_rt_sigaction(int,
+ const struct sigaction __user *,
+ struct sigaction __user *,
+ size_t);
+asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg);
diff --git a/include/asm-xtensa/system.h b/include/asm-xtensa/system.h
index 932bda92a21..4aaed7fe6cf 100644
--- a/include/asm-xtensa/system.h
+++ b/include/asm-xtensa/system.h
@@ -213,7 +213,7 @@ static inline void spill_registers(void)
unsigned int a0, ps;
__asm__ __volatile__ (
- "movi a14," __stringify (PS_EXCM_MASK) " | 1\n\t"
+ "movi a14," __stringify (PS_EXCM_BIT) " | 1\n\t"
"mov a12, a0\n\t"
"rsr a13," __stringify(SAR) "\n\t"
"xsr a14," __stringify(PS) "\n\t"
diff --git a/include/asm-xtensa/termbits.h b/include/asm-xtensa/termbits.h
index c780593ff5f..057b9a3d8f8 100644
--- a/include/asm-xtensa/termbits.h
+++ b/include/asm-xtensa/termbits.h
@@ -30,6 +30,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
diff --git a/include/asm-xtensa/timex.h b/include/asm-xtensa/timex.h
index c7b705e6665..28c7985a400 100644
--- a/include/asm-xtensa/timex.h
+++ b/include/asm-xtensa/timex.h
@@ -16,17 +16,22 @@
#include <asm/processor.h>
#include <linux/stringify.h>
-#if XCHAL_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) == 1
+#define _INTLEVEL(x) XCHAL_INT ## x ## _LEVEL
+#define INTLEVEL(x) _INTLEVEL(x)
+
+#if INTLEVEL(XCHAL_TIMER0_INTERRUPT) == 1
# define LINUX_TIMER 0
-#elif XCHAL_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) == 1
+# define LINUX_TIMER_INT XCHAL_TIMER0_INTERRUPT
+#elif INTLEVEL(XCHAL_TIMER1_INTERRUPT) == 1
# define LINUX_TIMER 1
-#elif XCHAL_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) == 1
+# define LINUX_TIMER_INT XCHAL_TIMER1_INTERRUPT
+#elif INTLEVEL(XCHAL_TIMER2_INTERRUPT) == 1
# define LINUX_TIMER 2
+# define LINUX_TIMER_INT XCHAL_TIMER2_INTERRUPT
#else
# error "Bad timer number for Linux configurations!"
#endif
-#define LINUX_TIMER_INT XCHAL_TIMER_INTERRUPT(LINUX_TIMER)
#define LINUX_TIMER_MASK (1L << LINUX_TIMER_INT)
#define CLOCK_TICK_RATE 1193180 /* (everyone is using this value) */
@@ -60,8 +65,8 @@ extern cycles_t cacheflush_time;
#define WSR_CCOUNT(r) __asm__("wsr %0,"__stringify(CCOUNT) :: "a" (r))
#define RSR_CCOUNT(r) __asm__("rsr %0,"__stringify(CCOUNT) : "=a" (r))
-#define WSR_CCOMPARE(x,r) __asm__("wsr %0,"__stringify(CCOMPARE_0)"+"__stringify(x) :: "a"(r))
-#define RSR_CCOMPARE(x,r) __asm__("rsr %0,"__stringify(CCOMPARE_0)"+"__stringify(x) : "=a"(r))
+#define WSR_CCOMPARE(x,r) __asm__("wsr %0,"__stringify(CCOMPARE)"+"__stringify(x) :: "a"(r))
+#define RSR_CCOMPARE(x,r) __asm__("rsr %0,"__stringify(CCOMPARE)"+"__stringify(x) : "=a"(r))
static inline unsigned long get_ccount (void)
{
diff --git a/include/asm-xtensa/tlbflush.h b/include/asm-xtensa/tlbflush.h
index 43f6ec859af..7c637b3c352 100644
--- a/include/asm-xtensa/tlbflush.h
+++ b/include/asm-xtensa/tlbflush.h
@@ -11,12 +11,20 @@
#ifndef _XTENSA_TLBFLUSH_H
#define _XTENSA_TLBFLUSH_H
-#define DEBUG_TLB
-
#ifdef __KERNEL__
-#include <asm/processor.h>
#include <linux/stringify.h>
+#include <asm/processor.h>
+
+#define DTLB_WAY_PGD 7
+
+#define ITLB_ARF_WAYS 4
+#define DTLB_ARF_WAYS 4
+
+#define ITLB_HIT_BIT 3
+#define DTLB_HIT_BIT 4
+
+#ifndef __ASSEMBLY__
/* TLB flushing:
*
@@ -46,11 +54,6 @@ static inline void flush_tlb_pgtables(struct mm_struct *mm,
/* TLB operations. */
-#define ITLB_WAYS_LOG2 XCHAL_ITLB_WAY_BITS
-#define DTLB_WAYS_LOG2 XCHAL_DTLB_WAY_BITS
-#define ITLB_PROBE_SUCCESS (1 << ITLB_WAYS_LOG2)
-#define DTLB_PROBE_SUCCESS (1 << DTLB_WAYS_LOG2)
-
static inline unsigned long itlb_probe(unsigned long addr)
{
unsigned long tmp;
@@ -131,29 +134,30 @@ static inline void write_itlb_entry (pte_t entry, int way)
static inline void invalidate_page_directory (void)
{
- invalidate_dtlb_entry (DTLB_WAY_PGTABLE);
+ invalidate_dtlb_entry (DTLB_WAY_PGD);
+ invalidate_dtlb_entry (DTLB_WAY_PGD+1);
+ invalidate_dtlb_entry (DTLB_WAY_PGD+2);
}
static inline void invalidate_itlb_mapping (unsigned address)
{
unsigned long tlb_entry;
- while ((tlb_entry = itlb_probe (address)) & ITLB_PROBE_SUCCESS)
- invalidate_itlb_entry (tlb_entry);
+ if (((tlb_entry = itlb_probe(address)) & (1 << ITLB_HIT_BIT)) != 0)
+ invalidate_itlb_entry(tlb_entry);
}
static inline void invalidate_dtlb_mapping (unsigned address)
{
unsigned long tlb_entry;
- while ((tlb_entry = dtlb_probe (address)) & DTLB_PROBE_SUCCESS)
- invalidate_dtlb_entry (tlb_entry);
+ if (((tlb_entry = dtlb_probe(address)) & (1 << DTLB_HIT_BIT)) != 0)
+ invalidate_dtlb_entry(tlb_entry);
}
#define check_pgt_cache() do { } while (0)
-#ifdef DEBUG_TLB
-
-/* DO NOT USE THESE FUNCTIONS. These instructions aren't part of the Xtensa
+/*
+ * DO NOT USE THESE FUNCTIONS. These instructions aren't part of the Xtensa
* ISA and exist only for test purposes..
* You may find it helpful for MMU debugging, however.
*
@@ -193,8 +197,6 @@ static inline unsigned long read_itlb_translation (int way)
return tmp;
}
-#endif /* DEBUG_TLB */
-
-
+#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
-#endif /* _XTENSA_PGALLOC_H */
+#endif /* _XTENSA_TLBFLUSH_H */
diff --git a/include/asm-xtensa/uaccess.h b/include/asm-xtensa/uaccess.h
index 88a64e1144d..d6352da05b1 100644
--- a/include/asm-xtensa/uaccess.h
+++ b/include/asm-xtensa/uaccess.h
@@ -23,7 +23,6 @@
#ifdef __ASSEMBLY__
-#define _ASMLANGUAGE
#include <asm/current.h>
#include <asm/asm-offsets.h>
#include <asm/processor.h>
diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h
index 2e1a1b997e7..8a7fb6964ce 100644
--- a/include/asm-xtensa/unistd.h
+++ b/include/asm-xtensa/unistd.h
@@ -11,212 +11,593 @@
#ifndef _XTENSA_UNISTD_H
#define _XTENSA_UNISTD_H
-#define __NR_spill 0
-#define __NR_exit 1
-#define __NR_read 3
-#define __NR_write 4
-#define __NR_open 5
-#define __NR_close 6
-#define __NR_creat 8
-#define __NR_link 9
-#define __NR_unlink 10
-#define __NR_execve 11
-#define __NR_chdir 12
-#define __NR_mknod 14
-#define __NR_chmod 15
-#define __NR_lchown 16
-#define __NR_break 17
-#define __NR_lseek 19
-#define __NR_getpid 20
-#define __NR_mount 21
-#define __NR_setuid 23
-#define __NR_getuid 24
-#define __NR_ptrace 26
-#define __NR_utime 30
-#define __NR_stty 31
-#define __NR_gtty 32
-#define __NR_access 33
-#define __NR_ftime 35
-#define __NR_sync 36
-#define __NR_kill 37
-#define __NR_rename 38
-#define __NR_mkdir 39
-#define __NR_rmdir 40
-#define __NR_dup 41
-#define __NR_pipe 42
-#define __NR_times 43
-#define __NR_prof 44
-#define __NR_brk 45
-#define __NR_setgid 46
-#define __NR_getgid 47
-#define __NR_signal 48
-#define __NR_geteuid 49
-#define __NR_getegid 50
-#define __NR_acct 51
-#define __NR_lock 53
-#define __NR_ioctl 54
-#define __NR_fcntl 55
-#define __NR_setpgid 57
-#define __NR_ulimit 58
-#define __NR_umask 60
-#define __NR_chroot 61
-#define __NR_ustat 62
-#define __NR_dup2 63
-#define __NR_getppid 64
-#define __NR_setsid 66
-#define __NR_sigaction 67
-#define __NR_setreuid 70
-#define __NR_setregid 71
-#define __NR_sigsuspend 72
-#define __NR_sigpending 73
-#define __NR_sethostname 74
-#define __NR_setrlimit 75
-#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
-#define __NR_getrusage 77
-#define __NR_gettimeofday 78
-#define __NR_settimeofday 79
-#define __NR_getgroups 80
-#define __NR_setgroups 81
-#define __NR_select 82
-#define __NR_symlink 83
-#define __NR_readlink 85
-#define __NR_uselib 86
-#define __NR_swapon 87
-#define __NR_reboot 88
-#define __NR_munmap 91
-#define __NR_truncate 92
-#define __NR_ftruncate 93
-#define __NR_fchmod 94
-#define __NR_fchown 95
-#define __NR_getpriority 96
-#define __NR_setpriority 97
-#define __NR_profil 98
-#define __NR_statfs 99
-#define __NR_fstatfs 100
-#define __NR_ioperm 101
-#define __NR_syslog 103
-#define __NR_setitimer 104
-#define __NR_getitimer 105
-#define __NR_stat 106
-#define __NR_lstat 107
-#define __NR_fstat 108
-#define __NR_iopl 110
-#define __NR_vhangup 111
-#define __NR_idle 112
-#define __NR_wait4 114
-#define __NR_swapoff 115
-#define __NR_sysinfo 116
-#define __NR_fsync 118
-#define __NR_sigreturn 119
-#define __NR_clone 120
-#define __NR_setdomainname 121
-#define __NR_uname 122
-#define __NR_modify_ldt 123
-#define __NR_adjtimex 124
-#define __NR_mprotect 125
-#define __NR_create_module 127
-#define __NR_init_module 128
-#define __NR_delete_module 129
-#define __NR_quotactl 131
-#define __NR_getpgid 132
-#define __NR_fchdir 133
-#define __NR_bdflush 134
-#define __NR_sysfs 135
-#define __NR_personality 136
-#define __NR_setfsuid 138
-#define __NR_setfsgid 139
-#define __NR__llseek 140
-#define __NR_getdents 141
-#define __NR__newselect 142
-#define __NR_flock 143
-#define __NR_msync 144
-#define __NR_readv 145
-#define __NR_writev 146
-#define __NR_cacheflush 147
-#define __NR_cachectl 148
-#define __NR_sysxtensa 149
-#define __NR_sysdummy 150
-#define __NR_getsid 151
-#define __NR_fdatasync 152
-#define __NR__sysctl 153
-#define __NR_mlock 154
-#define __NR_munlock 155
-#define __NR_mlockall 156
-#define __NR_munlockall 157
-#define __NR_sched_setparam 158
-#define __NR_sched_getparam 159
-#define __NR_sched_setscheduler 160
-#define __NR_sched_getscheduler 161
-#define __NR_sched_yield 162
-#define __NR_sched_get_priority_max 163
-#define __NR_sched_get_priority_min 164
-#define __NR_sched_rr_get_interval 165
-#define __NR_nanosleep 166
-#define __NR_mremap 167
-#define __NR_accept 168
-#define __NR_bind 169
-#define __NR_connect 170
-#define __NR_getpeername 171
-#define __NR_getsockname 172
-#define __NR_getsockopt 173
-#define __NR_listen 174
-#define __NR_recv 175
-#define __NR_recvfrom 176
-#define __NR_recvmsg 177
-#define __NR_send 178
-#define __NR_sendmsg 179
-#define __NR_sendto 180
-#define __NR_setsockopt 181
-#define __NR_shutdown 182
-#define __NR_socket 183
-#define __NR_socketpair 184
-#define __NR_setresuid 185
-#define __NR_getresuid 186
-#define __NR_query_module 187
-#define __NR_poll 188
-#define __NR_nfsservctl 189
-#define __NR_setresgid 190
-#define __NR_getresgid 191
-#define __NR_prctl 192
-#define __NR_rt_sigreturn 193
-#define __NR_rt_sigaction 194
-#define __NR_rt_sigprocmask 195
-#define __NR_rt_sigpending 196
-#define __NR_rt_sigtimedwait 197
-#define __NR_rt_sigqueueinfo 198
-#define __NR_rt_sigsuspend 199
-#define __NR_pread 200
-#define __NR_pwrite 201
-#define __NR_chown 202
-#define __NR_getcwd 203
-#define __NR_capget 204
-#define __NR_capset 205
-#define __NR_sigaltstack 206
-#define __NR_sendfile 207
-#define __NR_mmap2 210
-#define __NR_truncate64 211
-#define __NR_ftruncate64 212
-#define __NR_stat64 213
-#define __NR_lstat64 214
-#define __NR_fstat64 215
-#define __NR_pivot_root 216
-#define __NR_mincore 217
-#define __NR_madvise 218
-#define __NR_getdents64 219
-
-/* Keep this last; should always equal the last valid call number. */
-#define __NR_Linux_syscalls 220
-
-/* user-visible error numbers are in the range -1 - -125: see
- * <asm-xtensa/errno.h> */
-
-#define SYSXTENSA_RESERVED 0 /* don't use this */
-#define SYSXTENSA_ATOMIC_SET 1 /* set variable */
-#define SYSXTENSA_ATOMIC_EXG_ADD 2 /* exchange memory and add */
-#define SYSXTENSA_ATOMIC_ADD 3 /* add to memory */
-#define SYSXTENSA_ATOMIC_CMP_SWP 4 /* compare and swap */
-
-#define SYSXTENSA_COUNT 5 /* count of syscall0 functions*/
+#ifndef __SYSCALL
+# define __SYSCALL(nr,func,nargs)
+#endif
+
+#define __NR_spill 0
+__SYSCALL( 0, sys_ni_syscall, 0)
+#define __NR_xtensa 1
+__SYSCALL( 1, sys_ni_syscall, 0)
+#define __NR_available4 2
+__SYSCALL( 2, sys_ni_syscall, 0)
+#define __NR_available5 3
+__SYSCALL( 3, sys_ni_syscall, 0)
+#define __NR_available6 4
+__SYSCALL( 4, sys_ni_syscall, 0)
+#define __NR_available7 5
+__SYSCALL( 5, sys_ni_syscall, 0)
+#define __NR_available8 6
+__SYSCALL( 6, sys_ni_syscall, 0)
+#define __NR_available9 7
+__SYSCALL( 7, sys_ni_syscall, 0)
+
+/* File Operations */
+
+#define __NR_open 8
+__SYSCALL( 8, sys_open, 3)
+#define __NR_close 9
+__SYSCALL( 9, sys_close, 1)
+#define __NR_dup 10
+__SYSCALL( 10, sys_dup, 1)
+#define __NR_dup2 11
+__SYSCALL( 11, sys_dup2, 2)
+#define __NR_read 12
+__SYSCALL( 12, sys_read, 3)
+#define __NR_write 13
+__SYSCALL( 13, sys_write, 3)
+#define __NR_select 14
+__SYSCALL( 14, sys_select, 5)
+#define __NR_lseek 15
+__SYSCALL( 15, sys_lseek, 3)
+#define __NR_poll 16
+__SYSCALL( 16, sys_poll, 3)
+#define __NR__llseek 17
+__SYSCALL( 17, sys_llseek, 5)
+#define __NR_epoll_wait 18
+__SYSCALL( 18, sys_epoll_wait, 4)
+#define __NR_epoll_ctl 19
+__SYSCALL( 19, sys_epoll_ctl, 4)
+#define __NR_epoll_create 20
+__SYSCALL( 20, sys_epoll_create, 1)
+#define __NR_creat 21
+__SYSCALL( 21, sys_creat, 2)
+#define __NR_truncate 22
+__SYSCALL( 22, sys_truncate, 2)
+#define __NR_ftruncate 23
+__SYSCALL( 23, sys_ftruncate, 2)
+#define __NR_readv 24
+__SYSCALL( 24, sys_readv, 3)
+#define __NR_writev 25
+__SYSCALL( 25, sys_writev, 3)
+#define __NR_fsync 26
+__SYSCALL( 26, sys_fsync, 1)
+#define __NR_fdatasync 27
+__SYSCALL( 27, sys_fdatasync, 1)
+#define __NR_truncate64 28
+__SYSCALL( 28, sys_truncate64, 2)
+#define __NR_ftruncate64 29
+__SYSCALL( 29, sys_ftruncate64, 2)
+#define __NR_pread64 30
+__SYSCALL( 30, sys_pread64, 6)
+#define __NR_pwrite64 31
+__SYSCALL( 31, sys_pwrite64, 6)
+
+#define __NR_link 32
+__SYSCALL( 32, sys_link, 2)
+#define __NR_rename 33
+__SYSCALL( 33, sys_rename, 2)
+#define __NR_symlink 34
+__SYSCALL( 34, sys_symlink, 2)
+#define __NR_readlink 35
+__SYSCALL( 35, sys_readlink, 3)
+#define __NR_mknod 36
+__SYSCALL( 36, sys_mknod, 3)
+#define __NR_pipe 37
+__SYSCALL( 37, xtensa_pipe, 1)
+#define __NR_unlink 38
+__SYSCALL( 38, sys_unlink, 1)
+#define __NR_rmdir 39
+__SYSCALL( 39, sys_rmdir, 1)
+
+#define __NR_mkdir 40
+__SYSCALL( 40, sys_mkdir, 2)
+#define __NR_chdir 41
+__SYSCALL( 41, sys_chdir, 1)
+#define __NR_fchdir 42
+__SYSCALL( 42, sys_fchdir, 1)
+#define __NR_getcwd 43
+__SYSCALL( 43, sys_getcwd, 2)
+
+#define __NR_chmod 44
+__SYSCALL( 44, sys_chmod, 2)
+#define __NR_chown 45
+__SYSCALL( 45, sys_chown, 3)
+#define __NR_stat 46
+__SYSCALL( 46, sys_newstat, 2)
+#define __NR_stat64 47
+__SYSCALL( 47, sys_stat64, 2)
+
+#define __NR_lchown 48
+__SYSCALL( 48, sys_lchown, 3)
+#define __NR_lstat 49
+__SYSCALL( 49, sys_newlstat, 2)
+#define __NR_lstat64 50
+__SYSCALL( 50, sys_lstat64, 2)
+#define __NR_available51 51
+__SYSCALL( 51, sys_ni_syscall, 0)
+
+#define __NR_fchmod 52
+__SYSCALL( 52, sys_fchmod, 2)
+#define __NR_fchown 53
+__SYSCALL( 53, sys_fchown, 3)
+#define __NR_fstat 54
+__SYSCALL( 54, sys_newfstat, 2)
+#define __NR_fstat64 55
+__SYSCALL( 55, sys_fstat64, 2)
+
+#define __NR_flock 56
+__SYSCALL( 56, sys_flock, 2)
+#define __NR_access 57
+__SYSCALL( 57, sys_access, 2)
+#define __NR_umask 58
+__SYSCALL( 58, sys_umask, 1)
+#define __NR_getdents 59
+__SYSCALL( 59, sys_getdents, 3)
+#define __NR_getdents64 60
+__SYSCALL( 60, sys_getdents64, 3)
+#define __NR_fcntl64 61
+__SYSCALL( 61, sys_fcntl64, 3)
+#define __NR_available62 62
+__SYSCALL( 62, sys_ni_syscall, 0)
+#define __NR_fadvise64_64 63
+__SYSCALL( 63, sys_fadvise64_64, 6)
+#define __NR_utime 64 /* glibc 2.3.3 ?? */
+__SYSCALL( 64, sys_utime, 2)
+#define __NR_utimes 65
+__SYSCALL( 65, sys_utimes, 2)
+#define __NR_ioctl 66
+__SYSCALL( 66, sys_ioctl, 3)
+#define __NR_fcntl 67
+__SYSCALL( 67, sys_fcntl, 3)
+
+#define __NR_setxattr 68
+__SYSCALL( 68, sys_setxattr, 5)
+#define __NR_getxattr 69
+__SYSCALL( 69, sys_getxattr, 4)
+#define __NR_listxattr 70
+__SYSCALL( 70, sys_listxattr, 3)
+#define __NR_removexattr 71
+__SYSCALL( 71, sys_removexattr, 2)
+#define __NR_lsetxattr 72
+__SYSCALL( 72, sys_lsetxattr, 5)
+#define __NR_lgetxattr 73
+__SYSCALL( 73, sys_lgetxattr, 4)
+#define __NR_llistxattr 74
+__SYSCALL( 74, sys_llistxattr, 3)
+#define __NR_lremovexattr 75
+__SYSCALL( 75, sys_lremovexattr, 2)
+#define __NR_fsetxattr 76
+__SYSCALL( 76, sys_fsetxattr, 5)
+#define __NR_fgetxattr 77
+__SYSCALL( 77, sys_fgetxattr, 4)
+#define __NR_flistxattr 78
+__SYSCALL( 78, sys_flistxattr, 3)
+#define __NR_fremovexattr 79
+__SYSCALL( 79, sys_fremovexattr, 2)
+
+/* File Map / Shared Memory Operations */
+
+#define __NR_mmap2 80
+__SYSCALL( 80, xtensa_mmap2, 6)
+#define __NR_munmap 81
+__SYSCALL( 81, sys_munmap, 2)
+#define __NR_mprotect 82
+__SYSCALL( 82, sys_mprotect, 3)
+#define __NR_brk 83
+__SYSCALL( 83, sys_brk, 1)
+#define __NR_mlock 84
+__SYSCALL( 84, sys_mlock, 2)
+#define __NR_munlock 85
+__SYSCALL( 85, sys_munlock, 2)
+#define __NR_mlockall 86
+__SYSCALL( 86, sys_mlockall, 1)
+#define __NR_munlockall 87
+__SYSCALL( 87, sys_munlockall, 0)
+#define __NR_mremap 88
+__SYSCALL( 88, sys_mremap, 4)
+#define __NR_msync 89
+__SYSCALL( 89, sys_msync, 3)
+#define __NR_mincore 90
+__SYSCALL( 90, sys_mincore, 3)
+#define __NR_madvise 91
+__SYSCALL( 91, sys_madvise, 3)
+#define __NR_shmget 92
+__SYSCALL( 92, sys_shmget, 4)
+#define __NR_shmat 93
+__SYSCALL( 93, xtensa_shmat, 4)
+#define __NR_shmctl 94
+__SYSCALL( 94, sys_shmctl, 4)
+#define __NR_shmdt 95
+__SYSCALL( 95, sys_shmdt, 4)
+
+/* Socket Operations */
+
+#define __NR_socket 96
+__SYSCALL( 96, sys_socket, 3)
+#define __NR_setsockopt 97
+__SYSCALL( 97, sys_setsockopt, 5)
+#define __NR_getsockopt 98
+__SYSCALL( 98, sys_getsockopt, 5)
+#define __NR_shutdown 99
+__SYSCALL( 99, sys_shutdown, 2)
+
+#define __NR_bind 100
+__SYSCALL(100, sys_bind, 3)
+#define __NR_connect 101
+__SYSCALL(101, sys_connect, 3)
+#define __NR_listen 102
+__SYSCALL(102, sys_listen, 2)
+#define __NR_accept 103
+__SYSCALL(103, sys_accept, 3)
+
+#define __NR_getsockname 104
+__SYSCALL(104, sys_getsockname, 3)
+#define __NR_getpeername 105
+__SYSCALL(105, sys_getpeername, 3)
+#define __NR_sendmsg 106
+__SYSCALL(106, sys_sendmsg, 3)
+#define __NR_recvmsg 107
+__SYSCALL(107, sys_recvmsg, 3)
+#define __NR_send 108
+__SYSCALL(108, sys_send, 4)
+#define __NR_recv 109
+__SYSCALL(109, sys_recv, 4)
+#define __NR_sendto 110
+__SYSCALL(110, sys_sendto, 6)
+#define __NR_recvfrom 111
+__SYSCALL(111, sys_recvfrom, 6)
+
+#define __NR_socketpair 112
+__SYSCALL(112, sys_socketpair, 4)
+#define __NR_sendfile 113
+__SYSCALL(113, sys_sendfile, 4)
+#define __NR_sendfile64 114
+__SYSCALL(114, sys_sendfile64, 4)
+#define __NR_available115 115
+__SYSCALL(115, sys_ni_syscall, 0)
+
+/* Process Operations */
+
+#define __NR_clone 116
+__SYSCALL(116, xtensa_clone, 5)
+#define __NR_execve 117
+__SYSCALL(117, xtensa_execve, 3)
+#define __NR_exit 118
+__SYSCALL(118, sys_exit, 1)
+#define __NR_exit_group 119
+__SYSCALL(119, sys_exit_group, 1)
+#define __NR_getpid 120
+__SYSCALL(120, sys_getpid, 0)
+#define __NR_wait4 121
+__SYSCALL(121, sys_wait4, 4)
+#define __NR_waitid 122
+__SYSCALL(122, sys_waitid, 5)
+#define __NR_kill 123
+__SYSCALL(123, sys_kill, 2)
+#define __NR_tkill 124
+__SYSCALL(124, sys_tkill, 2)
+#define __NR_tgkill 125
+__SYSCALL(125, sys_tgkill, 3)
+#define __NR_set_tid_address 126
+__SYSCALL(126, sys_set_tid_address, 1)
+#define __NR_gettid 127
+__SYSCALL(127, sys_gettid, 0)
+#define __NR_setsid 128
+__SYSCALL(128, sys_setsid, 0)
+#define __NR_getsid 129
+__SYSCALL(129, sys_getsid, 1)
+#define __NR_prctl 130
+__SYSCALL(130, sys_prctl, 5)
+#define __NR_personality 131
+__SYSCALL(131, sys_personality, 1)
+#define __NR_getpriority 132
+__SYSCALL(132, sys_getpriority, 2)
+#define __NR_setpriority 133
+__SYSCALL(133, sys_setpriority, 3)
+#define __NR_setitimer 134
+__SYSCALL(134, sys_setitimer, 3)
+#define __NR_getitimer 135
+__SYSCALL(135, sys_getitimer, 2)
+#define __NR_setuid 136
+__SYSCALL(136, sys_setuid, 1)
+#define __NR_getuid 137
+__SYSCALL(137, sys_getuid, 0)
+#define __NR_setgid 138
+__SYSCALL(138, sys_setgid, 1)
+#define __NR_getgid 139
+__SYSCALL(139, sys_getgid, 0)
+#define __NR_geteuid 140
+__SYSCALL(140, sys_geteuid, 0)
+#define __NR_getegid 141
+__SYSCALL(141, sys_getegid, 0)
+#define __NR_setreuid 142
+__SYSCALL(142, sys_setreuid, 2)
+#define __NR_setregid 143
+__SYSCALL(143, sys_setregid, 2)
+#define __NR_setresuid 144
+__SYSCALL(144, sys_setresuid, 3)
+#define __NR_getresuid 145
+__SYSCALL(145, sys_getresuid, 3)
+#define __NR_setresgid 146
+__SYSCALL(146, sys_setresgid, 3)
+#define __NR_getresgid 147
+__SYSCALL(147, sys_getresgid, 3)
+#define __NR_setpgid 148
+__SYSCALL(148, sys_setpgid, 2)
+#define __NR_getpgid 149
+__SYSCALL(149, sys_getpgid, 1)
+#define __NR_getppid 150
+__SYSCALL(150, sys_getppid, 0)
+#define __NR_available151 151
+__SYSCALL(151, sys_ni_syscall, 0)
+
+#define __NR_reserved152 152 /* set_thread_area */
+__SYSCALL(152, sys_ni_syscall, 0)
+#define __NR_reserved153 153 /* get_thread_area */
+__SYSCALL(153, sys_ni_syscall, 0)
+#define __NR_times 154
+__SYSCALL(154, sys_times, 1)
+#define __NR_acct 155
+__SYSCALL(155, sys_acct, 1)
+#define __NR_sched_setaffinity 156
+__SYSCALL(156, sys_sched_setaffinity, 3)
+#define __NR_sched_getaffinity 157
+__SYSCALL(157, sys_sched_getaffinity, 3)
+#define __NR_capget 158
+__SYSCALL(158, sys_capget, 2)
+#define __NR_capset 159
+__SYSCALL(159, sys_capset, 2)
+#define __NR_ptrace 160
+__SYSCALL(160, sys_ptrace, 4)
+#define __NR_semtimedop 161
+__SYSCALL(161, sys_semtimedop, 5)
+#define __NR_semget 162
+__SYSCALL(162, sys_semget, 4)
+#define __NR_semop 163
+__SYSCALL(163, sys_semop, 4)
+#define __NR_semctl 164
+__SYSCALL(164, sys_semctl, 4)
+#define __NR_available165 165
+__SYSCALL(165, sys_ni_syscall, 0)
+#define __NR_msgget 166
+__SYSCALL(166, sys_msgget, 4)
+#define __NR_msgsnd 167
+__SYSCALL(167, sys_msgsnd, 4)
+#define __NR_msgrcv 168
+__SYSCALL(168, sys_msgrcv, 4)
+#define __NR_msgctl 169
+__SYSCALL(169, sys_msgctl, 4)
+#define __NR_available170 170
+__SYSCALL(170, sys_ni_syscall, 0)
+#define __NR_available171 171
+__SYSCALL(171, sys_ni_syscall, 0)
+
+/* File System */
+
+#define __NR_mount 172
+__SYSCALL(172, sys_mount, 5)
+#define __NR_swapon 173
+__SYSCALL(173, sys_swapon, 2)
+#define __NR_chroot 174
+__SYSCALL(174, sys_chroot, 1)
+#define __NR_pivot_root 175
+__SYSCALL(175, sys_pivot_root, 2)
+#define __NR_umount 176
+__SYSCALL(176, sys_umount, 2)
+#define __NR_swapoff 177
+__SYSCALL(177, sys_swapoff, 1)
+#define __NR_sync 178
+__SYSCALL(178, sys_sync, 0)
+#define __NR_available179 179
+__SYSCALL(179, sys_ni_syscall, 0)
+#define __NR_setfsuid 180
+__SYSCALL(180, sys_setfsuid, 1)
+#define __NR_setfsgid 181
+__SYSCALL(181, sys_setfsgid, 1)
+#define __NR_sysfs 182
+__SYSCALL(182, sys_sysfs, 3)
+#define __NR_ustat 183
+__SYSCALL(183, sys_ustat, 2)
+#define __NR_statfs 184
+__SYSCALL(184, sys_statfs, 2)
+#define __NR_fstatfs 185
+__SYSCALL(185, sys_fstatfs, 2)
+#define __NR_statfs64 186
+__SYSCALL(186, sys_statfs64, 3)
+#define __NR_fstatfs64 187
+__SYSCALL(187, sys_fstatfs64, 3)
+
+/* System */
+
+#define __NR_setrlimit 188
+__SYSCALL(188, sys_setrlimit, 2)
+#define __NR_getrlimit 189
+__SYSCALL(189, sys_getrlimit, 2)
+#define __NR_getrusage 190
+__SYSCALL(190, sys_getrusage, 2)
+#define __NR_futex 191
+__SYSCALL(191, sys_futex, 5)
+#define __NR_gettimeofday 192
+__SYSCALL(192, sys_gettimeofday, 2)
+#define __NR_settimeofday 193
+__SYSCALL(193, sys_settimeofday, 2)
+#define __NR_adjtimex 194
+__SYSCALL(194, sys_adjtimex, 1)
+#define __NR_nanosleep 195
+__SYSCALL(195, sys_nanosleep, 2)
+#define __NR_getgroups 196
+__SYSCALL(196, sys_getgroups, 2)
+#define __NR_setgroups 197
+__SYSCALL(197, sys_setgroups, 2)
+#define __NR_sethostname 198
+__SYSCALL(198, sys_sethostname, 2)
+#define __NR_setdomainname 199
+__SYSCALL(199, sys_setdomainname, 2)
+#define __NR_syslog 200
+__SYSCALL(200, sys_syslog, 3)
+#define __NR_vhangup 201
+__SYSCALL(201, sys_vhangup, 0)
+#define __NR_uselib 202
+__SYSCALL(202, sys_uselib, 1)
+#define __NR_reboot 203
+__SYSCALL(203, sys_reboot, 3)
+#define __NR_quotactl 204
+__SYSCALL(204, sys_quotactl, 4)
+#define __NR_nfsservctl 205
+__SYSCALL(205, sys_nfsservctl, 3)
+#define __NR__sysctl 206
+__SYSCALL(206, sys_sysctl, 1)
+#define __NR_bdflush 207
+__SYSCALL(207, sys_bdflush, 2)
+#define __NR_uname 208
+__SYSCALL(208, sys_newuname, 1)
+#define __NR_sysinfo 209
+__SYSCALL(209, sys_sysinfo, 1)
+#define __NR_init_module 210
+__SYSCALL(210, sys_init_module, 2)
+#define __NR_delete_module 211
+__SYSCALL(211, sys_delete_module, 1)
+
+#define __NR_sched_setparam 212
+__SYSCALL(212, sys_sched_setparam, 2)
+#define __NR_sched_getparam 213
+__SYSCALL(213, sys_sched_getparam, 2)
+#define __NR_sched_setscheduler 214
+__SYSCALL(214, sys_sched_setscheduler, 3)
+#define __NR_sched_getscheduler 215
+__SYSCALL(215, sys_sched_getscheduler, 1)
+#define __NR_sched_get_priority_max 216
+__SYSCALL(216, sys_sched_get_priority_max, 1)
+#define __NR_sched_get_priority_min 217
+__SYSCALL(217, sys_sched_get_priority_min, 1)
+#define __NR_sched_rr_get_interval 218
+__SYSCALL(218, sys_sched_rr_get_interval, 2)
+#define __NR_sched_yield 219
+__SYSCALL(219, sys_sched_yield, 0)
+#define __NR_sigreturn 222
+__SYSCALL(222, xtensa_sigreturn, 0)
+
+/* Signal Handling */
+
+#define __NR_restart_syscall 223
+__SYSCALL(223, sys_restart_syscall, 0)
+#define __NR_sigaltstack 224
+__SYSCALL(224, xtensa_sigaltstack, 2)
+#define __NR_rt_sigreturn 225
+__SYSCALL(225, xtensa_rt_sigreturn, 1)
+#define __NR_rt_sigaction 226
+__SYSCALL(226, sys_rt_sigaction, 4)
+#define __NR_rt_sigprocmask 227
+__SYSCALL(227, sys_rt_sigprocmask, 4)
+#define __NR_rt_sigpending 228
+__SYSCALL(228, sys_rt_sigpending, 2)
+#define __NR_rt_sigtimedwait 229
+__SYSCALL(229, sys_rt_sigtimedwait, 4)
+#define __NR_rt_sigqueueinfo 230
+__SYSCALL(230, sys_rt_sigqueueinfo, 3)
+#define __NR_rt_sigsuspend 231
+__SYSCALL(231, xtensa_rt_sigsuspend, 2)
+
+/* Message */
+
+#define __NR_mq_open 232
+__SYSCALL(232, sys_mq_open, 4)
+#define __NR_mq_unlink 233
+__SYSCALL(233, sys_mq_unlink, 1)
+#define __NR_mq_timedsend 234
+__SYSCALL(234, sys_mq_timedsend, 5)
+#define __NR_mq_timedreceive 235
+__SYSCALL(235, sys_mq_timedreceive, 5)
+#define __NR_mq_notify 236
+__SYSCALL(236, sys_mq_notify, 2)
+#define __NR_mq_getsetattr 237
+__SYSCALL(237, sys_mq_getsetattr, 3)
+#define __NR_available238 238
+__SYSCALL(238, sys_ni_syscall, 0)
+
+/* IO */
+
+#define __NR_io_setup 239
+__SYSCALL(239, sys_io_setup, 2)
+#define __NR_io_destroy 240
+__SYSCALL(240, sys_io_destroy, 1)
+#define __NR_io_submit 241
+__SYSCALL(241, sys_io_submit, 3)
+#define __NR_io_getevents 242
+__SYSCALL(242, sys_io_getevents, 5)
+#define __NR_io_cancel 243
+__SYSCALL(243, sys_io_cancel, 3)
+#define __NR_clock_settime 244
+__SYSCALL(244, sys_clock_settime, 2)
+#define __NR_clock_gettime 245
+__SYSCALL(245, sys_clock_gettime, 2)
+#define __NR_clock_getres 246
+__SYSCALL(246, sys_clock_getres, 2)
+#define __NR_clock_nanosleep 247
+__SYSCALL(247, sys_clock_nanosleep, 4)
+
+/* Timer */
+
+#define __NR_timer_create 248
+__SYSCALL(248, sys_timer_create, 3)
+#define __NR_timer_delete 249
+__SYSCALL(249, sys_timer_delete, 1)
+#define __NR_timer_settime 250
+__SYSCALL(250, sys_timer_settime, 4)
+#define __NR_timer_gettime 251
+__SYSCALL(251, sys_timer_gettime, 2)
+#define __NR_timer_getoverrun 252
+__SYSCALL(252, sys_timer_getoverrun, 1)
+
+/* System */
+
+#define __NR_reserved244 253
+__SYSCALL(253, sys_ni_syscall, 0)
+#define __NR_lookup_dcookie 254
+__SYSCALL(254, sys_lookup_dcookie, 4)
+#define __NR_available255 255
+__SYSCALL(255, sys_ni_syscall, 0)
+#define __NR_add_key 256
+__SYSCALL(256, sys_add_key, 5)
+#define __NR_request_key 257
+__SYSCALL(257, sys_request_key, 5)
+#define __NR_keyctl 258
+__SYSCALL(258, sys_keyctl, 5)
+#define __NR_available259 259
+__SYSCALL(259, sys_ni_syscall, 0)
+
+#define __NR_syscall_count 261
+
+/*
+ * sysxtensa syscall handler
+ *
+ * int sysxtensa (SYS_XTENSA_ATOMIC_SET, ptr, val, unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_ADD, ptr, val, unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val, unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
+ * a2 a6 a3 a4 a5
+ */
+
+#define SYS_XTENSA_RESERVED 0 /* don't use this */
+#define SYS_XTENSA_ATOMIC_SET 1 /* set variable */
+#define SYS_XTENSA_ATOMIC_EXG_ADD 2 /* exchange memory and add */
+#define SYS_XTENSA_ATOMIC_ADD 3 /* add to memory */
+#define SYS_XTENSA_ATOMIC_CMP_SWP 4 /* compare and swap */
+
+#define SYS_XTENSA_COUNT 5 /* count */
+
+#ifdef __KERNEL__
/*
* "Conditional" syscalls
@@ -230,6 +611,9 @@
#define __ARCH_WANT_SYS_UTIME
#define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_RT_SIGACTION
-#endif /* __KERNEL__ */
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+
+#endif /* __KERNEL__ */
#endif /* _XTENSA_UNISTD_H */
+
diff --git a/include/asm-xtensa/variant-fsf/core.h b/include/asm-xtensa/variant-fsf/core.h
new file mode 100644
index 00000000000..2f337605c74
--- /dev/null
+++ b/include/asm-xtensa/variant-fsf/core.h
@@ -0,0 +1,359 @@
+/*
+ * Xtensa processor core configuration 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.
+ *
+ * Copyright (C) 1999-2006 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CORE_H
+#define _XTENSA_CORE_H
+
+
+/****************************************************************************
+ Parameters Useful for Any Code, USER or PRIVILEGED
+ ****************************************************************************/
+
+/*
+ * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is
+ * configured, and a value of 0 otherwise. These macros are always defined.
+ */
+
+
+/*----------------------------------------------------------------------
+ ISA
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_BE 1 /* big-endian byte ordering */
+#define XCHAL_HAVE_WINDOWED 1 /* windowed registers option */
+#define XCHAL_NUM_AREGS 64 /* num of physical addr regs */
+#define XCHAL_NUM_AREGS_LOG2 6 /* log2(XCHAL_NUM_AREGS) */
+#define XCHAL_MAX_INSTRUCTION_SIZE 3 /* max instr bytes (3..8) */
+#define XCHAL_HAVE_DEBUG 1 /* debug option */
+#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */
+#define XCHAL_HAVE_LOOPS 1 /* zero-overhead loops */
+#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */
+#define XCHAL_HAVE_MINMAX 0 /* MIN/MAX instructions */
+#define XCHAL_HAVE_SEXT 0 /* SEXT instruction */
+#define XCHAL_HAVE_CLAMPS 0 /* CLAMPS instruction */
+#define XCHAL_HAVE_MUL16 0 /* MUL16S/MUL16U instructions */
+#define XCHAL_HAVE_MUL32 0 /* MULL instruction */
+#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */
+#define XCHAL_HAVE_L32R 1 /* L32R instruction */
+#define XCHAL_HAVE_ABSOLUTE_LITERALS 1 /* non-PC-rel (extended) L32R */
+#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */
+#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */
+#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */
+#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */
+#define XCHAL_HAVE_CALL4AND12 1 /* (obsolete option) */
+#define XCHAL_HAVE_ABS 1 /* ABS instruction */
+/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */
+/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */
+#define XCHAL_HAVE_RELEASE_SYNC 0 /* L32AI/S32RI instructions */
+#define XCHAL_HAVE_S32C1I 0 /* S32C1I instruction */
+#define XCHAL_HAVE_SPECULATION 0 /* speculation */
+#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */
+#define XCHAL_NUM_CONTEXTS 1 /* */
+#define XCHAL_NUM_MISC_REGS 2 /* num of scratch regs (0..4) */
+#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */
+#define XCHAL_HAVE_PRID 1 /* processor ID register */
+#define XCHAL_HAVE_THREADPTR 1 /* THREADPTR register */
+#define XCHAL_HAVE_BOOLEANS 0 /* boolean registers */
+#define XCHAL_HAVE_CP 0 /* CPENABLE reg (coprocessor) */
+#define XCHAL_CP_MAXCFG 0 /* max allowed cp id plus one */
+#define XCHAL_HAVE_MAC16 0 /* MAC16 package */
+#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */
+#define XCHAL_HAVE_FP 0 /* floating point pkg */
+#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */
+#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */
+#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */
+
+
+/*----------------------------------------------------------------------
+ MISC
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_WRITEBUFFER_ENTRIES 4 /* size of write buffer */
+#define XCHAL_INST_FETCH_WIDTH 4 /* instr-fetch width in bytes */
+#define XCHAL_DATA_WIDTH 4 /* data width in bytes */
+/* In T1050, applies to selected core load and store instructions (see ISA): */
+#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */
+#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/
+
+#define XCHAL_CORE_ID "fsf" /* alphanum core name
+ (CoreID) set in the Xtensa
+ Processor Generator */
+
+#define XCHAL_BUILD_UNIQUE_ID 0x00006700 /* 22-bit sw build ID */
+
+/*
+ * These definitions describe the hardware targeted by this software.
+ */
+#define XCHAL_HW_CONFIGID0 0xC103C3FF /* ConfigID hi 32 bits*/
+#define XCHAL_HW_CONFIGID1 0x0C006700 /* ConfigID lo 32 bits*/
+#define XCHAL_HW_VERSION_NAME "LX2.0.0" /* full version name */
+#define XCHAL_HW_VERSION_MAJOR 2200 /* major ver# of targeted hw */
+#define XCHAL_HW_VERSION_MINOR 0 /* minor ver# of targeted hw */
+#define XTHAL_HW_REL_LX2 1
+#define XTHAL_HW_REL_LX2_0 1
+#define XTHAL_HW_REL_LX2_0_0 1
+#define XCHAL_HW_CONFIGID_RELIABLE 1
+/* If software targets a *range* of hardware versions, these are the bounds: */
+#define XCHAL_HW_MIN_VERSION_MAJOR 2200 /* major v of earliest tgt hw */
+#define XCHAL_HW_MIN_VERSION_MINOR 0 /* minor v of earliest tgt hw */
+#define XCHAL_HW_MAX_VERSION_MAJOR 2200 /* major v of latest tgt hw */
+#define XCHAL_HW_MAX_VERSION_MINOR 0 /* minor v of latest tgt hw */
+
+
+/*----------------------------------------------------------------------
+ CACHE
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_ICACHE_LINESIZE 16 /* I-cache line size in bytes */
+#define XCHAL_DCACHE_LINESIZE 16 /* D-cache line size in bytes */
+#define XCHAL_ICACHE_LINEWIDTH 4 /* log2(I line size in bytes) */
+#define XCHAL_DCACHE_LINEWIDTH 4 /* log2(D line size in bytes) */
+
+#define XCHAL_ICACHE_SIZE 8192 /* I-cache size in bytes or 0 */
+#define XCHAL_DCACHE_SIZE 8192 /* D-cache size in bytes or 0 */
+
+#define XCHAL_DCACHE_IS_WRITEBACK 0 /* writeback feature */
+
+
+
+
+/****************************************************************************
+ Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code
+ ****************************************************************************/
+
+
+#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY
+
+/*----------------------------------------------------------------------
+ CACHE
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */
+
+/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */
+
+/* Number of cache sets in log2(lines per way): */
+#define XCHAL_ICACHE_SETWIDTH 8
+#define XCHAL_DCACHE_SETWIDTH 8
+
+/* Cache set associativity (number of ways): */
+#define XCHAL_ICACHE_WAYS 2
+#define XCHAL_DCACHE_WAYS 2
+
+/* Cache features: */
+#define XCHAL_ICACHE_LINE_LOCKABLE 0
+#define XCHAL_DCACHE_LINE_LOCKABLE 0
+#define XCHAL_ICACHE_ECC_PARITY 0
+#define XCHAL_DCACHE_ECC_PARITY 0
+
+/* Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits): */
+#define XCHAL_CA_BITS 4
+
+
+/*----------------------------------------------------------------------
+ INTERNAL I/D RAM/ROMs and XLMI
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_INSTROM 0 /* number of core instr. ROMs */
+#define XCHAL_NUM_INSTRAM 0 /* number of core instr. RAMs */
+#define XCHAL_NUM_DATAROM 0 /* number of core data ROMs */
+#define XCHAL_NUM_DATARAM 0 /* number of core data RAMs */
+#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/
+#define XCHAL_NUM_XLMI 0 /* number of core XLMI ports */
+
+
+/*----------------------------------------------------------------------
+ INTERRUPTS and TIMERS
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */
+#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */
+#define XCHAL_HAVE_NMI 0 /* non-maskable interrupt */
+#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */
+#define XCHAL_NUM_TIMERS 3 /* number of CCOMPAREn regs */
+#define XCHAL_NUM_INTERRUPTS 17 /* number of interrupts */
+#define XCHAL_NUM_INTERRUPTS_LOG2 5 /* ceil(log2(NUM_INTERRUPTS)) */
+#define XCHAL_NUM_EXTINTERRUPTS 10 /* num of external interrupts */
+#define XCHAL_NUM_INTLEVELS 4 /* number of interrupt levels
+ (not including level zero) */
+#define XCHAL_EXCM_LEVEL 1 /* level masked by PS.EXCM */
+ /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */
+
+/* Masks of interrupts at each interrupt level: */
+#define XCHAL_INTLEVEL1_MASK 0x000064F9
+#define XCHAL_INTLEVEL2_MASK 0x00008902
+#define XCHAL_INTLEVEL3_MASK 0x00011204
+#define XCHAL_INTLEVEL4_MASK 0x00000000
+#define XCHAL_INTLEVEL5_MASK 0x00000000
+#define XCHAL_INTLEVEL6_MASK 0x00000000
+#define XCHAL_INTLEVEL7_MASK 0x00000000
+
+/* Masks of interrupts at each range 1..n of interrupt levels: */
+#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x000064F9
+#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x0000EDFB
+#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x0001FFFF
+
+/* Level of each interrupt: */
+#define XCHAL_INT0_LEVEL 1
+#define XCHAL_INT1_LEVEL 2
+#define XCHAL_INT2_LEVEL 3
+#define XCHAL_INT3_LEVEL 1
+#define XCHAL_INT4_LEVEL 1
+#define XCHAL_INT5_LEVEL 1
+#define XCHAL_INT6_LEVEL 1
+#define XCHAL_INT7_LEVEL 1
+#define XCHAL_INT8_LEVEL 2
+#define XCHAL_INT9_LEVEL 3
+#define XCHAL_INT10_LEVEL 1
+#define XCHAL_INT11_LEVEL 2
+#define XCHAL_INT12_LEVEL 3
+#define XCHAL_INT13_LEVEL 1
+#define XCHAL_INT14_LEVEL 1
+#define XCHAL_INT15_LEVEL 2
+#define XCHAL_INT16_LEVEL 3
+#define XCHAL_DEBUGLEVEL 4 /* debug interrupt level */
+#define XCHAL_HAVE_DEBUG_EXTERN_INT 0 /* OCD external db interrupt */
+
+/* Type of each interrupt: */
+#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT6_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT7_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT10_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT11_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT12_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT13_TYPE XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT14_TYPE XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT15_TYPE XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT16_TYPE XTHAL_INTTYPE_SOFTWARE
+
+/* Masks of interrupts for each type of interrupt: */
+#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFE0000
+#define XCHAL_INTTYPE_MASK_SOFTWARE 0x0001E000
+#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00000380
+#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000007F
+#define XCHAL_INTTYPE_MASK_TIMER 0x00001C00
+#define XCHAL_INTTYPE_MASK_NMI 0x00000000
+#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000
+
+/* Interrupt numbers assigned to specific interrupt sources: */
+#define XCHAL_TIMER0_INTERRUPT 10 /* CCOMPARE0 */
+#define XCHAL_TIMER1_INTERRUPT 11 /* CCOMPARE1 */
+#define XCHAL_TIMER2_INTERRUPT 12 /* CCOMPARE2 */
+#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED
+
+/* Interrupt numbers for levels at which only one interrupt is configured: */
+/* (There are many interrupts each at level(s) 1, 2, 3.) */
+
+
+/*
+ * External interrupt vectors/levels.
+ * These macros describe how Xtensa processor interrupt numbers
+ * (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
+ * map to external BInterrupt<n> pins, for those interrupts
+ * configured as external (level-triggered, edge-triggered, or NMI).
+ * See the Xtensa processor databook for more details.
+ */
+
+/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */
+#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */
+#define XCHAL_EXTINT1_NUM 1 /* (intlevel 2) */
+#define XCHAL_EXTINT2_NUM 2 /* (intlevel 3) */
+#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */
+#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */
+#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */
+#define XCHAL_EXTINT6_NUM 6 /* (intlevel 1) */
+#define XCHAL_EXTINT7_NUM 7 /* (intlevel 1) */
+#define XCHAL_EXTINT8_NUM 8 /* (intlevel 2) */
+#define XCHAL_EXTINT9_NUM 9 /* (intlevel 3) */
+
+
+/*----------------------------------------------------------------------
+ EXCEPTIONS and VECTORS
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture
+ number: 1 == XEA1 (old)
+ 2 == XEA2 (new)
+ 0 == XEAX (extern) */
+#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */
+#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */
+#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */
+#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */
+#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */
+
+#define XCHAL_RESET_VECTOR_VADDR 0xFE000020
+#define XCHAL_RESET_VECTOR_PADDR 0xFE000020
+#define XCHAL_USER_VECTOR_VADDR 0xD0000220
+#define XCHAL_USER_VECTOR_PADDR 0x00000220
+#define XCHAL_KERNEL_VECTOR_VADDR 0xD0000200
+#define XCHAL_KERNEL_VECTOR_PADDR 0x00000200
+#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0xD0000290
+#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x00000290
+#define XCHAL_WINDOW_VECTORS_VADDR 0xD0000000
+#define XCHAL_WINDOW_VECTORS_PADDR 0x00000000
+#define XCHAL_INTLEVEL2_VECTOR_VADDR 0xD0000240
+#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x00000240
+#define XCHAL_INTLEVEL3_VECTOR_VADDR 0xD0000250
+#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x00000250
+#define XCHAL_INTLEVEL4_VECTOR_VADDR 0xFE000520
+#define XCHAL_INTLEVEL4_VECTOR_PADDR 0xFE000520
+#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL4_VECTOR_VADDR
+#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL4_VECTOR_PADDR
+
+
+/*----------------------------------------------------------------------
+ DEBUG
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */
+#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */
+#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */
+#define XCHAL_HAVE_OCD_DIR_ARRAY 1 /* faster OCD option */
+
+
+/*----------------------------------------------------------------------
+ MMU
+ ----------------------------------------------------------------------*/
+
+/* See <xtensa/config/core-matmap.h> header file for more details. */
+
+#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */
+#define XCHAL_HAVE_SPANNING_WAY 0 /* one way maps I+D 4GB vaddr */
+#define XCHAL_HAVE_IDENTITY_MAP 0 /* vaddr == paddr always */
+#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */
+#define XCHAL_HAVE_MIMIC_CACHEATTR 0 /* region protection */
+#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */
+#define XCHAL_HAVE_PTP_MMU 1 /* full MMU (with page table
+ [autorefill] and protection)
+ usable for an MMU-based OS */
+/* If none of the above last 4 are set, it's a custom TLB configuration. */
+#define XCHAL_ITLB_ARF_ENTRIES_LOG2 2 /* log2(autorefill way size) */
+#define XCHAL_DTLB_ARF_ENTRIES_LOG2 2 /* log2(autorefill way size) */
+
+#define XCHAL_MMU_ASID_BITS 8 /* number of bits in ASIDs */
+#define XCHAL_MMU_RINGS 4 /* number of rings (1..4) */
+#define XCHAL_MMU_RING_BITS 2 /* num of bits in RING field */
+
+#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */
+
+
+#endif /* _XTENSA_CORE_CONFIGURATION_H */
+
diff --git a/include/asm-xtensa/variant-fsf/tie.h b/include/asm-xtensa/variant-fsf/tie.h
new file mode 100644
index 00000000000..a73c7166491
--- /dev/null
+++ b/include/asm-xtensa/variant-fsf/tie.h
@@ -0,0 +1,22 @@
+/*
+ * Xtensa processor core configuration 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.
+ *
+ * Copyright (C) 1999-2006 Tensilica Inc.
+ */
+
+#ifndef XTENSA_TIE_H
+#define XTENSA_TIE_H
+
+/*----------------------------------------------------------------------
+ COPROCESSORS and EXTRA STATE
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_CP_NUM 0 /* number of coprocessors */
+#define XCHAL_CP_MASK 0x00
+
+#endif /*XTENSA_CONFIG_TIE_H*/
+
diff --git a/include/asm-xtensa/xtensa/cacheasm.h b/include/asm-xtensa/xtensa/cacheasm.h
deleted file mode 100644
index 0cdbb0bf180..00000000000
--- a/include/asm-xtensa/xtensa/cacheasm.h
+++ /dev/null
@@ -1,708 +0,0 @@
-#ifndef XTENSA_CACHEASM_H
-#define XTENSA_CACHEASM_H
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/cacheasm.h -- assembler-specific cache
- * related definitions that depend on CORE configuration.
- *
- * 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) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/coreasm.h>
-
-
-/*
- * This header file defines assembler macros of the form:
- * <x>cache_<func>
- * where <x> is 'i' or 'd' for instruction and data caches,
- * and <func> indicates the function of the macro.
- *
- * The following functions <func> are defined,
- * and apply only to the specified cache (I or D):
- *
- * reset
- * Resets the cache.
- *
- * sync
- * Makes sure any previous cache instructions have been completed;
- * ie. makes sure any previous cache control operations
- * have had full effect and been synchronized to memory.
- * Eg. any invalidate completed [so as not to generate a hit],
- * any writebacks or other pipelined writes written to memory, etc.
- *
- * invalidate_line (single cache line)
- * invalidate_region (specified memory range)
- * invalidate_all (entire cache)
- * Invalidates all cache entries that cache
- * data from the specified memory range.
- * NOTE: locked entries are not invalidated.
- *
- * writeback_line (single cache line)
- * writeback_region (specified memory range)
- * writeback_all (entire cache)
- * Writes back to memory all dirty cache entries
- * that cache data from the specified memory range,
- * and marks these entries as clean.
- * NOTE: on some future implementations, this might
- * also invalidate.
- * NOTE: locked entries are written back, but never invalidated.
- * NOTE: instruction caches never implement writeback.
- *
- * writeback_inv_line (single cache line)
- * writeback_inv_region (specified memory range)
- * writeback_inv_all (entire cache)
- * Writes back to memory all dirty cache entries
- * that cache data from the specified memory range,
- * and invalidates these entries (including all clean
- * cache entries that cache data from that range).
- * NOTE: locked entries are written back but not invalidated.
- * NOTE: instruction caches never implement writeback.
- *
- * lock_line (single cache line)
- * lock_region (specified memory range)
- * Prefetch and lock the specified memory range into cache.
- * NOTE: if any part of the specified memory range cannot
- * be locked, a ??? exception occurs. These macros don't
- * do anything special (yet anyway) to handle this situation.
- *
- * unlock_line (single cache line)
- * unlock_region (specified memory range)
- * unlock_all (entire cache)
- * Unlock cache entries that cache the specified memory range.
- * Entries not already locked are unaffected.
- */
-
-
-
-/*************************** GENERIC -- ALL CACHES ***************************/
-
-
-/*
- * The following macros assume the following cache size/parameter limits
- * in the current Xtensa core implementation:
- * cache size: 1024 bytes minimum
- * line size: 16 - 64 bytes
- * way count: 1 - 4
- *
- * Minimum entries per way (ie. per associativity) = 1024 / 64 / 4 = 4
- * Hence the assumption that each loop can execute four cache instructions.
- *
- * Correspondingly, the offset range of instructions is assumed able to cover
- * four lines, ie. offsets {0,1,2,3} * line_size are assumed valid for
- * both hit and indexed cache instructions. Ie. these offsets are all
- * valid: 0, 16, 32, 48, 64, 96, 128, 192 (for line sizes 16, 32, 64).
- * This is true of all original cache instructions
- * (dhi, ihi, dhwb, dhwbi, dii, iii) which have offsets
- * of 0 to 1020 in multiples of 4 (ie. 8 bits shifted by 2).
- * This is also true of subsequent cache instructions
- * (dhu, ihu, diu, iiu, diwb, diwbi, dpfl, ipfl) which have offsets
- * of 0 to 240 in multiples of 16 (ie. 4 bits shifted by 4).
- *
- * (Maximum cache size, currently 32k, doesn't affect the following macros.
- * Cache ways > MMU min page size cause aliasing but that's another matter.)
- */
-
-
-
-/*
- * Macro to apply an 'indexed' cache instruction to the entire cache.
- *
- * Parameters:
- * cainst instruction/ that takes an address register parameter
- * and an offset parameter (in range 0 .. 3*linesize).
- * size size of cache in bytes
- * linesize size of cache line in bytes
- * assoc_or1 number of associativities (ways/sets) in cache
- * if all sets affected by cainst,
- * or 1 if only one set (or not all sets) of the cache
- * is affected by cainst (eg. DIWB or DIWBI [not yet ISA defined]).
- * aa, ab unique address registers (temporaries)
- */
-
- .macro cache_index_all cainst, size, linesize, assoc_or1, aa, ab
-
- // Sanity-check on cache parameters:
- .ifne (\size % (\linesize * \assoc_or1 * 4))
- .err // cache configuration outside expected/supported range!
- .endif
-
- // \size byte cache, \linesize byte lines, \assoc_or1 way(s) affected by each \cainst.
- movi \aa, (\size / (\linesize * \assoc_or1 * 4))
- // Possible improvement: need only loop if \aa > 1 ;
- // however that particular condition is highly unlikely.
- movi \ab, 0 // to iterate over cache
- floop \aa, cachex\@
- \cainst \ab, 0*\linesize
- \cainst \ab, 1*\linesize
- \cainst \ab, 2*\linesize
- \cainst \ab, 3*\linesize
- addi \ab, \ab, 4*\linesize // move to next line
- floopend \aa, cachex\@
-
- .endm
-
-
-/*
- * Macro to apply a 'hit' cache instruction to a memory region,
- * ie. to any cache entries that cache a specified portion (region) of memory.
- * Takes care of the unaligned cases, ie. may apply to one
- * more cache line than $asize / lineSize if $aaddr is not aligned.
- *
- *
- * Parameters are:
- * cainst instruction/macro that takes an address register parameter
- * and an offset parameter (currently always zero)
- * and generates a cache instruction (eg. "dhi", "dhwb", "ihi", etc.)
- * linesize_log2 log2(size of cache line in bytes)
- * addr register containing start address of region (clobbered)
- * asize register containing size of the region in bytes (clobbered)
- * askew unique register used as temporary
- *
- * !?!?! 2DO: optimization: iterate max(cache_size and \asize) / linesize
- */
-
- .macro cache_hit_region cainst, linesize_log2, addr, asize, askew
-
- // Make \asize the number of iterations:
- extui \askew, \addr, 0, \linesize_log2 // get unalignment amount of \addr
- add \asize, \asize, \askew // ... and add it to \asize
- addi \asize, \asize, (1 << \linesize_log2) - 1 // round up!
- srli \asize, \asize, \linesize_log2
-
- // Iterate over region:
- floopnez \asize, cacheh\@
- \cainst \addr, 0
- addi \addr, \addr, (1 << \linesize_log2) // move to next line
- floopend \asize, cacheh\@
-
- .endm
-
-
-
-
-
-/*************************** INSTRUCTION CACHE ***************************/
-
-
-/*
- * Reset/initialize the instruction cache by simply invalidating it:
- * (need to unlock first also, if cache locking implemented):
- *
- * Parameters:
- * aa, ab unique address registers (temporaries)
- */
- .macro icache_reset aa, ab
- icache_unlock_all \aa, \ab
- icache_invalidate_all \aa, \ab
- .endm
-
-
-/*
- * Synchronize after an instruction cache operation,
- * to be sure everything is in sync with memory as to be
- * expected following any previous instruction cache control operations.
- *
- * Parameters are:
- * ar an address register (temporary) (currently unused, but may be used in future)
- */
- .macro icache_sync ar
-#if XCHAL_ICACHE_SIZE > 0
- isync
-#endif
- .endm
-
-
-
-/*
- * Invalidate a single line of the instruction cache.
- * Parameters are:
- * ar address register that contains (virtual) address to invalidate
- * (may get clobbered in a future implementation, but not currently)
- * offset (optional) offset to add to \ar to compute effective address to invalidate
- * (note: some number of lsbits are ignored)
- */
- .macro icache_invalidate_line ar, offset
-#if XCHAL_ICACHE_SIZE > 0
- ihi \ar, \offset // invalidate icache line
- /*
- * NOTE: in some version of the silicon [!!!SHOULD HAVE BEEN DOCUMENTED!!!]
- * 'ihi' doesn't work, so it had been replaced with 'iii'
- * (which would just invalidate more than it should,
- * which should be okay other than the performance hit
- * because cache locking did not exist in that version,
- * unless user somehow relies on something being cached).
- * [WHAT VERSION IS IT!!?!?
- * IS THERE ANY WAY TO TEST FOR THAT HERE, TO OUTPUT 'III' ONLY IF NEEDED!?!?].
- *
- * iii \ar, \offset
- */
- icache_sync \ar
-#endif
- .endm
-
-
-
-
-/*
- * Invalidate instruction cache entries that cache a specified portion of memory.
- * Parameters are:
- * astart start address (register gets clobbered)
- * asize size of the region in bytes (register gets clobbered)
- * ac unique register used as temporary
- */
- .macro icache_invalidate_region astart, asize, ac
-#if XCHAL_ICACHE_SIZE > 0
- // Instruction cache region invalidation:
- cache_hit_region ihi, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
- icache_sync \ac
- // End of instruction cache region invalidation
-#endif
- .endm
-
-
-
-/*
- * Invalidate entire instruction cache.
- *
- * Parameters:
- * aa, ab unique address registers (temporaries)
- */
- .macro icache_invalidate_all aa, ab
-#if XCHAL_ICACHE_SIZE > 0
- // Instruction cache invalidation:
- cache_index_all iii, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, XCHAL_ICACHE_WAYS, \aa, \ab
- icache_sync \aa
- // End of instruction cache invalidation
-#endif
- .endm
-
-
-
-/*
- * Lock (prefetch & lock) a single line of the instruction cache.
- *
- * Parameters are:
- * ar address register that contains (virtual) address to lock
- * (may get clobbered in a future implementation, but not currently)
- * offset offset to add to \ar to compute effective address to lock
- * (note: some number of lsbits are ignored)
- */
- .macro icache_lock_line ar, offset
-#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
- ipfl \ar, \offset /* prefetch and lock icache line */
- icache_sync \ar
-#endif
- .endm
-
-
-
-/*
- * Lock (prefetch & lock) a specified portion of memory into the instruction cache.
- * Parameters are:
- * astart start address (register gets clobbered)
- * asize size of the region in bytes (register gets clobbered)
- * ac unique register used as temporary
- */
- .macro icache_lock_region astart, asize, ac
-#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
- // Instruction cache region lock:
- cache_hit_region ipfl, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
- icache_sync \ac
- // End of instruction cache region lock
-#endif
- .endm
-
-
-
-/*
- * Unlock a single line of the instruction cache.
- *
- * Parameters are:
- * ar address register that contains (virtual) address to unlock
- * (may get clobbered in a future implementation, but not currently)
- * offset offset to add to \ar to compute effective address to unlock
- * (note: some number of lsbits are ignored)
- */
- .macro icache_unlock_line ar, offset
-#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
- ihu \ar, \offset /* unlock icache line */
- icache_sync \ar
-#endif
- .endm
-
-
-
-/*
- * Unlock a specified portion of memory from the instruction cache.
- * Parameters are:
- * astart start address (register gets clobbered)
- * asize size of the region in bytes (register gets clobbered)
- * ac unique register used as temporary
- */
- .macro icache_unlock_region astart, asize, ac
-#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
- // Instruction cache region unlock:
- cache_hit_region ihu, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
- icache_sync \ac
- // End of instruction cache region unlock
-#endif
- .endm
-
-
-
-/*
- * Unlock entire instruction cache.
- *
- * Parameters:
- * aa, ab unique address registers (temporaries)
- */
- .macro icache_unlock_all aa, ab
-#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
- // Instruction cache unlock:
- cache_index_all iiu, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, 1, \aa, \ab
- icache_sync \aa
- // End of instruction cache unlock
-#endif
- .endm
-
-
-
-
-
-/*************************** DATA CACHE ***************************/
-
-
-
-/*
- * Reset/initialize the data cache by simply invalidating it
- * (need to unlock first also, if cache locking implemented):
- *
- * Parameters:
- * aa, ab unique address registers (temporaries)
- */
- .macro dcache_reset aa, ab
- dcache_unlock_all \aa, \ab
- dcache_invalidate_all \aa, \ab
- .endm
-
-
-
-
-/*
- * Synchronize after a data cache operation,
- * to be sure everything is in sync with memory as to be
- * expected following any previous data cache control operations.
- *
- * Parameters are:
- * ar an address register (temporary) (currently unused, but may be used in future)
- */
- .macro dcache_sync ar
-#if XCHAL_DCACHE_SIZE > 0
- // This previous sequence errs on the conservative side (too much so); a DSYNC should be sufficient:
- //memw // synchronize data cache changes relative to subsequent memory accesses
- //isync // be conservative and ISYNC as well (just to be sure)
-
- dsync
-#endif
- .endm
-
-
-
-/*
- * Synchronize after a data store operation,
- * to be sure the stored data is completely off the processor
- * (and assuming there is no buffering outside the processor,
- * that the data is in memory). This may be required to
- * ensure that the processor's write buffers are emptied.
- * A MEMW followed by a read guarantees this, by definition.
- * We also try to make sure the read itself completes.
- *
- * Parameters are:
- * ar an address register (temporary)
- */
- .macro write_sync ar
- memw // ensure previous memory accesses are complete prior to subsequent memory accesses
- l32i \ar, sp, 0 // completing this read ensures any previous write has completed, because of MEMW
- //slot
- add \ar, \ar, \ar // use the result of the read to help ensure the read completes (in future architectures)
- .endm
-
-
-/*
- * Invalidate a single line of the data cache.
- * Parameters are:
- * ar address register that contains (virtual) address to invalidate
- * (may get clobbered in a future implementation, but not currently)
- * offset (optional) offset to add to \ar to compute effective address to invalidate
- * (note: some number of lsbits are ignored)
- */
- .macro dcache_invalidate_line ar, offset
-#if XCHAL_DCACHE_SIZE > 0
- dhi \ar, \offset
- dcache_sync \ar
-#endif
- .endm
-
-
-
-
-
-/*
- * Invalidate data cache entries that cache a specified portion of memory.
- * Parameters are:
- * astart start address (register gets clobbered)
- * asize size of the region in bytes (register gets clobbered)
- * ac unique register used as temporary
- */
- .macro dcache_invalidate_region astart, asize, ac
-#if XCHAL_DCACHE_SIZE > 0
- // Data cache region invalidation:
- cache_hit_region dhi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
- dcache_sync \ac
- // End of data cache region invalidation
-#endif
- .endm
-
-
-
-#if 0
-/*
- * This is a work-around for a bug in SiChip1 (???).
- * There should be a proper mechanism for not outputting
- * these instructions when not needed.
- * To enable work-around, uncomment this and replace 'dii'
- * with 'dii_s1' everywhere, eg. in dcache_invalidate_all
- * macro below.
- */
- .macro dii_s1 ar, offset
- dii \ar, \offset
- or \ar, \ar, \ar
- or \ar, \ar, \ar
- or \ar, \ar, \ar
- or \ar, \ar, \ar
- .endm
-#endif
-
-
-/*
- * Invalidate entire data cache.
- *
- * Parameters:
- * aa, ab unique address registers (temporaries)
- */
- .macro dcache_invalidate_all aa, ab
-#if XCHAL_DCACHE_SIZE > 0
- // Data cache invalidation:
- cache_index_all dii, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, XCHAL_DCACHE_WAYS, \aa, \ab
- dcache_sync \aa
- // End of data cache invalidation
-#endif
- .endm
-
-
-
-/*
- * Writeback a single line of the data cache.
- * Parameters are:
- * ar address register that contains (virtual) address to writeback
- * (may get clobbered in a future implementation, but not currently)
- * offset offset to add to \ar to compute effective address to writeback
- * (note: some number of lsbits are ignored)
- */
- .macro dcache_writeback_line ar, offset
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
- dhwb \ar, \offset
- dcache_sync \ar
-#endif
- .endm
-
-
-
-/*
- * Writeback dirty data cache entries that cache a specified portion of memory.
- * Parameters are:
- * astart start address (register gets clobbered)
- * asize size of the region in bytes (register gets clobbered)
- * ac unique register used as temporary
- */
- .macro dcache_writeback_region astart, asize, ac
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
- // Data cache region writeback:
- cache_hit_region dhwb, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
- dcache_sync \ac
- // End of data cache region writeback
-#endif
- .endm
-
-
-
-/*
- * Writeback entire data cache.
- * Parameters:
- * aa, ab unique address registers (temporaries)
- */
- .macro dcache_writeback_all aa, ab
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
- // Data cache writeback:
- cache_index_all diwb, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
- dcache_sync \aa
- // End of data cache writeback
-#endif
- .endm
-
-
-
-/*
- * Writeback and invalidate a single line of the data cache.
- * Parameters are:
- * ar address register that contains (virtual) address to writeback and invalidate
- * (may get clobbered in a future implementation, but not currently)
- * offset offset to add to \ar to compute effective address to writeback and invalidate
- * (note: some number of lsbits are ignored)
- */
- .macro dcache_writeback_inv_line ar, offset
-#if XCHAL_DCACHE_SIZE > 0
- dhwbi \ar, \offset /* writeback and invalidate dcache line */
- dcache_sync \ar
-#endif
- .endm
-
-
-
-/*
- * Writeback and invalidate data cache entries that cache a specified portion of memory.
- * Parameters are:
- * astart start address (register gets clobbered)
- * asize size of the region in bytes (register gets clobbered)
- * ac unique register used as temporary
- */
- .macro dcache_writeback_inv_region astart, asize, ac
-#if XCHAL_DCACHE_SIZE > 0
- // Data cache region writeback and invalidate:
- cache_hit_region dhwbi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
- dcache_sync \ac
- // End of data cache region writeback and invalidate
-#endif
- .endm
-
-
-
-/*
- * Writeback and invalidate entire data cache.
- * Parameters:
- * aa, ab unique address registers (temporaries)
- */
- .macro dcache_writeback_inv_all aa, ab
-#if XCHAL_DCACHE_SIZE > 0
- // Data cache writeback and invalidate:
-#if XCHAL_DCACHE_IS_WRITEBACK
- cache_index_all diwbi, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
- dcache_sync \aa
-#else /*writeback*/
- // Data cache does not support writeback, so just invalidate: */
- dcache_invalidate_all \aa, \ab
-#endif /*writeback*/
- // End of data cache writeback and invalidate
-#endif
- .endm
-
-
-
-
-/*
- * Lock (prefetch & lock) a single line of the data cache.
- *
- * Parameters are:
- * ar address register that contains (virtual) address to lock
- * (may get clobbered in a future implementation, but not currently)
- * offset offset to add to \ar to compute effective address to lock
- * (note: some number of lsbits are ignored)
- */
- .macro dcache_lock_line ar, offset
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
- dpfl \ar, \offset /* prefetch and lock dcache line */
- dcache_sync \ar
-#endif
- .endm
-
-
-
-/*
- * Lock (prefetch & lock) a specified portion of memory into the data cache.
- * Parameters are:
- * astart start address (register gets clobbered)
- * asize size of the region in bytes (register gets clobbered)
- * ac unique register used as temporary
- */
- .macro dcache_lock_region astart, asize, ac
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
- // Data cache region lock:
- cache_hit_region dpfl, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
- dcache_sync \ac
- // End of data cache region lock
-#endif
- .endm
-
-
-
-/*
- * Unlock a single line of the data cache.
- *
- * Parameters are:
- * ar address register that contains (virtual) address to unlock
- * (may get clobbered in a future implementation, but not currently)
- * offset offset to add to \ar to compute effective address to unlock
- * (note: some number of lsbits are ignored)
- */
- .macro dcache_unlock_line ar, offset
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
- dhu \ar, \offset /* unlock dcache line */
- dcache_sync \ar
-#endif
- .endm
-
-
-
-/*
- * Unlock a specified portion of memory from the data cache.
- * Parameters are:
- * astart start address (register gets clobbered)
- * asize size of the region in bytes (register gets clobbered)
- * ac unique register used as temporary
- */
- .macro dcache_unlock_region astart, asize, ac
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
- // Data cache region unlock:
- cache_hit_region dhu, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
- dcache_sync \ac
- // End of data cache region unlock
-#endif
- .endm
-
-
-
-/*
- * Unlock entire data cache.
- *
- * Parameters:
- * aa, ab unique address registers (temporaries)
- */
- .macro dcache_unlock_all aa, ab
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
- // Data cache unlock:
- cache_index_all diu, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
- dcache_sync \aa
- // End of data cache unlock
-#endif
- .endm
-
-
-#endif /*XTENSA_CACHEASM_H*/
-
diff --git a/include/asm-xtensa/xtensa/cacheattrasm.h b/include/asm-xtensa/xtensa/cacheattrasm.h
deleted file mode 100644
index 1c3e117b359..00000000000
--- a/include/asm-xtensa/xtensa/cacheattrasm.h
+++ /dev/null
@@ -1,432 +0,0 @@
-#ifndef XTENSA_CACHEATTRASM_H
-#define XTENSA_CACHEATTRASM_H
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/cacheattrasm.h -- assembler-specific
- * CACHEATTR register related definitions that depend on CORE
- * configuration.
- *
- * 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) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/coreasm.h>
-
-
-/*
- * This header file defines assembler macros of the form:
- * <x>cacheattr_<func>
- * where:
- * <x> is 'i', 'd' or absent for instruction, data
- * or both caches; and
- * <func> indicates the function of the macro.
- *
- * The following functions are defined:
- *
- * icacheattr_get
- * Reads I-cache CACHEATTR into a2 (clobbers a3-a5).
- *
- * dcacheattr_get
- * Reads D-cache CACHEATTR into a2 (clobbers a3-a5).
- * (Note: for configs with a real CACHEATTR register, the
- * above two macros are identical.)
- *
- * cacheattr_set
- * Writes both I-cache and D-cache CACHEATTRs from a2 (a3-a8 clobbered).
- * Works even when changing one's own code's attributes.
- *
- * icacheattr_is_enabled label
- * Branches to \label if I-cache appears to have been enabled
- * (eg. if CACHEATTR contains a cache-enabled attribute).
- * (clobbers a2-a5,SAR)
- *
- * dcacheattr_is_enabled label
- * Branches to \label if D-cache appears to have been enabled
- * (eg. if CACHEATTR contains a cache-enabled attribute).
- * (clobbers a2-a5,SAR)
- *
- * cacheattr_is_enabled label
- * Branches to \label if either I-cache or D-cache appears to have been enabled
- * (eg. if CACHEATTR contains a cache-enabled attribute).
- * (clobbers a2-a5,SAR)
- *
- * The following macros are only defined under certain conditions:
- *
- * icacheattr_set (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR)
- * Writes I-cache CACHEATTR from a2 (a3-a8 clobbered).
- *
- * dcacheattr_set (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR)
- * Writes D-cache CACHEATTR from a2 (a3-a8 clobbered).
- */
-
-
-
-/*************************** GENERIC -- ALL CACHES ***************************/
-
-/*
- * _cacheattr_get
- *
- * (Internal macro.)
- * Returns value of CACHEATTR register (or closest equivalent) in a2.
- *
- * Entry:
- * (none)
- * Exit:
- * a2 value read from CACHEATTR
- * a3-a5 clobbered (temporaries)
- */
- .macro _cacheattr_get tlb
-#if XCHAL_HAVE_CACHEATTR
- rsr a2, CACHEATTR
-#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
- // We have a config that "mimics" CACHEATTR using a simplified
- // "MMU" composed of a single statically-mapped way.
- // DTLB and ITLB are independent, so there's no single
- // cache attribute that can describe both. So for now
- // just return the DTLB state.
- movi a5, 0xE0000000
- movi a2, 0
- movi a3, 0
-1: add a3, a3, a5 // next segment
- r&tlb&1 a4, a3 // get PPN+CA of segment at 0xE0000000, 0xC0000000, ..., 0
- dsync // interlock???
- slli a2, a2, 4
- extui a4, a4, 0, 4 // extract CA
- or a2, a2, a4
- bnez a3, 1b
-#else
- // This macro isn't applicable to arbitrary MMU configurations.
- // Just return zero.
- movi a2, 0
-#endif
- .endm
-
- .macro icacheattr_get
- _cacheattr_get itlb
- .endm
-
- .macro dcacheattr_get
- _cacheattr_get dtlb
- .endm
-
-
-#define XCHAL_CACHEATTR_ALL_BYPASS 0x22222222 /* default (powerup/reset) value of CACHEATTR, all BYPASS
- mode (ie. disabled/bypassed caches) */
-
-#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
-
-#define XCHAL_FCA_ENAMASK 0x001A /* bitmap of fetch attributes that require enabled icache */
-#define XCHAL_LCA_ENAMASK 0x0003 /* bitmap of load attributes that require enabled dcache */
-#define XCHAL_SCA_ENAMASK 0x0003 /* bitmap of store attributes that require enabled dcache */
-#define XCHAL_LSCA_ENAMASK (XCHAL_LCA_ENAMASK|XCHAL_SCA_ENAMASK) /* l/s attrs requiring enabled dcache */
-#define XCHAL_ALLCA_ENAMASK (XCHAL_FCA_ENAMASK|XCHAL_LSCA_ENAMASK) /* all attrs requiring enabled caches */
-
-/*
- * _cacheattr_is_enabled
- *
- * (Internal macro.)
- * Branches to \label if CACHEATTR in a2 indicates an enabled
- * cache, using mask in a3.
- *
- * Parameters:
- * label where to branch to if cache is enabled
- * Entry:
- * a2 contains CACHEATTR value used to determine whether
- * caches are enabled
- * a3 16-bit constant where each bit correspond to
- * one of the 16 possible CA values (in a CACHEATTR mask);
- * CA values that indicate the cache is enabled
- * have their corresponding bit set in this mask
- * (eg. use XCHAL_xCA_ENAMASK , above)
- * Exit:
- * a2,a4,a5 clobbered
- * SAR clobbered
- */
- .macro _cacheattr_is_enabled label
- movi a4, 8 // loop 8 times
-.Lcaife\@:
- extui a5, a2, 0, 4 // get CA nibble
- ssr a5 // index into mask according to CA...
- srl a5, a3 // ...and get CA's mask bit in a5 bit 0
- bbsi.l a5, 0, \label // if CA indicates cache enabled, jump to label
- srli a2, a2, 4 // next nibble
- addi a4, a4, -1
- bnez a4, .Lcaife\@ // loop for each nibble
- .endm
-
-#else /* XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
- .macro _cacheattr_is_enabled label
- j \label // macro not applicable, assume caches always enabled
- .endm
-#endif /* XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
-
-
-
-/*
- * icacheattr_is_enabled
- *
- * Branches to \label if I-cache is enabled.
- *
- * Parameters:
- * label where to branch to if icache is enabled
- * Entry:
- * (none)
- * Exit:
- * a2-a5, SAR clobbered (temporaries)
- */
- .macro icacheattr_is_enabled label
-#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
- icacheattr_get
- movi a3, XCHAL_FCA_ENAMASK
-#endif
- _cacheattr_is_enabled \label
- .endm
-
-/*
- * dcacheattr_is_enabled
- *
- * Branches to \label if D-cache is enabled.
- *
- * Parameters:
- * label where to branch to if dcache is enabled
- * Entry:
- * (none)
- * Exit:
- * a2-a5, SAR clobbered (temporaries)
- */
- .macro dcacheattr_is_enabled label
-#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
- dcacheattr_get
- movi a3, XCHAL_LSCA_ENAMASK
-#endif
- _cacheattr_is_enabled \label
- .endm
-
-/*
- * cacheattr_is_enabled
- *
- * Branches to \label if either I-cache or D-cache is enabled.
- *
- * Parameters:
- * label where to branch to if a cache is enabled
- * Entry:
- * (none)
- * Exit:
- * a2-a5, SAR clobbered (temporaries)
- */
- .macro cacheattr_is_enabled label
-#if XCHAL_HAVE_CACHEATTR
- rsr a2, CACHEATTR
- movi a3, XCHAL_ALLCA_ENAMASK
-#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
- icacheattr_get
- movi a3, XCHAL_FCA_ENAMASK
- _cacheattr_is_enabled \label
- dcacheattr_get
- movi a3, XCHAL_LSCA_ENAMASK
-#endif
- _cacheattr_is_enabled \label
- .endm
-
-
-
-/*
- * The ISA does not have a defined way to change the
- * instruction cache attributes of the running code,
- * ie. of the memory area that encloses the current PC.
- * However, each micro-architecture (or class of
- * configurations within a micro-architecture)
- * provides a way to deal with this issue.
- *
- * Here are a few macros used to implement the relevant
- * approach taken.
- */
-
-#if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
- // We have a config that "mimics" CACHEATTR using a simplified
- // "MMU" composed of a single statically-mapped way.
-
-/*
- * icacheattr_set
- *
- * Entry:
- * a2 cacheattr value to set
- * Exit:
- * a2 unchanged
- * a3-a8 clobbered (temporaries)
- */
- .macro icacheattr_set
-
- movi a5, 0xE0000000 // mask of upper 3 bits
- movi a6, 3f // PC where ITLB is set
- movi a3, 0 // start at region 0 (0 .. 7)
- and a6, a6, a5 // upper 3 bits of local PC area
- mov a7, a2 // copy a2 so it doesn't get clobbered
- j 3f
-
-# if XCHAL_HAVE_XLT_CACHEATTR
- // Can do translations, use generic method:
-1: sub a6, a3, a5 // address of some other segment
- ritlb1 a8, a6 // save its PPN+CA
- dsync // interlock??
- witlb a4, a6 // make it translate to this code area
- movi a6, 5f // where to jump into it
- isync
- sub a6, a6, a5 // adjust jump address within that other segment
- jx a6
-
- // Note that in the following code snippet, which runs at a different virtual
- // address than it is assembled for, we avoid using literals (eg. via movi/l32r)
- // just in case literals end up in a different 512 MB segment, and we avoid
- // instructions that rely on the current PC being what is expected.
- //
- .align 4
- _j 6f // this is at label '5' minus 4 bytes
- .align 4
-5: witlb a4, a3 // we're in other segment, now can write previous segment's CA
- isync
- add a6, a6, a5 // back to previous segment
- addi a6, a6, -4 // next jump label
- jx a6
-
-6: sub a6, a3, a5 // address of some other segment
- witlb a8, a6 // restore PPN+CA of other segment
- mov a6, a3 // restore a6
- isync
-# else /* XCHAL_HAVE_XLT_CACHEATTR */
- // Use micro-architecture specific method.
- // The following 4-instruction sequence is aligned such that
- // it all fits within a single I-cache line. Sixteen byte
- // alignment is sufficient for this (using XCHAL_ICACHE_LINESIZE
- // actually causes problems because that can be greater than
- // the alignment of the reset vector, where this macro is often
- // invoked, which would cause the linker to align the reset
- // vector code away from the reset vector!!).
- .align 16 /*XCHAL_ICACHE_LINESIZE*/
-1: _witlb a4, a3 // write wired PTE (CA, no PPN) of 512MB segment to ITLB
- _isync
- nop
- nop
-# endif /* XCHAL_HAVE_XLT_CACHEATTR */
- beq a3, a5, 4f // done?
-
- // Note that in the WITLB loop, we don't do any load/stores
- // (may not be an issue here, but it is important in the DTLB case).
-2: srli a7, a7, 4 // next CA
- sub a3, a3, a5 // next segment (add 0x20000000)
-3:
-# if XCHAL_HAVE_XLT_CACHEATTR /* if have translation, preserve it */
- ritlb1 a8, a3 // get current PPN+CA of segment
- dsync // interlock???
- extui a4, a7, 0, 4 // extract CA to set
- srli a8, a8, 4 // clear CA but keep PPN ...
- slli a8, a8, 4 // ...
- add a4, a4, a8 // combine new CA with PPN to preserve
-# else
- extui a4, a7, 0, 4 // extract CA
-# endif
- beq a3, a6, 1b // current PC's region? if so, do it in a safe way
- witlb a4, a3 // write wired PTE (CA [+PPN]) of 512MB segment to ITLB
- bne a3, a5, 2b
- isync // make sure all ifetch changes take effect
-4:
- .endm // icacheattr_set
-
-
-/*
- * dcacheattr_set
- *
- * Entry:
- * a2 cacheattr value to set
- * Exit:
- * a2 unchanged
- * a3-a8 clobbered (temporaries)
- */
-
- .macro dcacheattr_set
-
- movi a5, 0xE0000000 // mask of upper 3 bits
- movi a3, 0 // start at region 0 (0 .. 7)
- mov a7, a2 // copy a2 so it doesn't get clobbered
- j 3f
- // Note that in the WDTLB loop, we don't do any load/stores
- // (including implicit l32r via movi) because it isn't safe.
-2: srli a7, a7, 4 // next CA
- sub a3, a3, a5 // next segment (add 0x20000000)
-3:
-# if XCHAL_HAVE_XLT_CACHEATTR /* if have translation, preserve it */
- rdtlb1 a8, a3 // get current PPN+CA of segment
- dsync // interlock???
- extui a4, a7, 0, 4 // extract CA to set
- srli a8, a8, 4 // clear CA but keep PPN ...
- slli a8, a8, 4 // ...
- add a4, a4, a8 // combine new CA with PPN to preserve
-# else
- extui a4, a7, 0, 4 // extract CA to set
-# endif
- wdtlb a4, a3 // write wired PTE (CA [+PPN]) of 512MB segment to DTLB
- bne a3, a5, 2b
- dsync // make sure all data path changes take effect
- .endm // dcacheattr_set
-
-#endif /* XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
-
-
-
-/*
- * cacheattr_set
- *
- * Macro that sets the current CACHEATTR safely
- * (both i and d) according to the current contents of a2.
- * It works even when changing the cache attributes of
- * the currently running code.
- *
- * Entry:
- * a2 cacheattr value to set
- * Exit:
- * a2 unchanged
- * a3-a8 clobbered (temporaries)
- */
- .macro cacheattr_set
-
-#if XCHAL_HAVE_CACHEATTR
-# if XCHAL_ICACHE_LINESIZE < 4
- // No i-cache, so can always safely write to CACHEATTR:
- wsr a2, CACHEATTR
-# else
- // The Athens micro-architecture, when using the old
- // exception architecture option (ie. with the CACHEATTR register)
- // allows changing the cache attributes of the running code
- // using the following exact sequence aligned to be within
- // an instruction cache line. (NOTE: using XCHAL_ICACHE_LINESIZE
- // alignment actually causes problems because that can be greater
- // than the alignment of the reset vector, where this macro is often
- // invoked, which would cause the linker to align the reset
- // vector code away from the reset vector!!).
- j 1f
- .align 16 /*XCHAL_ICACHE_LINESIZE*/ // align to within an I-cache line
-1: _wsr a2, CACHEATTR
- _isync
- nop
- nop
-# endif
-#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
- // DTLB and ITLB are independent, but to keep semantics
- // of this macro we simply write to both.
- icacheattr_set
- dcacheattr_set
-#else
- // This macro isn't applicable to arbitrary MMU configurations.
- // Do nothing in this case.
-#endif
- .endm
-
-
-#endif /*XTENSA_CACHEATTRASM_H*/
-
diff --git a/include/asm-xtensa/xtensa/config-linux_be/core.h b/include/asm-xtensa/xtensa/config-linux_be/core.h
deleted file mode 100644
index d54fe5eb106..00000000000
--- a/include/asm-xtensa/xtensa/config-linux_be/core.h
+++ /dev/null
@@ -1,1270 +0,0 @@
-/*
- * xtensa/config/core.h -- HAL definitions that are dependent on CORE configuration
- *
- * This header file is sometimes referred to as the "compile-time HAL" or CHAL.
- * It was generated for a specific Xtensa processor configuration.
- *
- * Source for configuration-independent binaries (which link in a
- * configuration-specific HAL library) must NEVER include this file.
- * It is perfectly normal, however, for the HAL source itself to include this file.
- */
-
-/*
- * Copyright (c) 2003 Tensilica, Inc. All Rights Reserved.
- *
- * 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 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- */
-
-
-#ifndef XTENSA_CONFIG_CORE_H
-#define XTENSA_CONFIG_CORE_H
-
-#include <xtensa/hal.h>
-
-
-/*----------------------------------------------------------------------
- GENERAL
- ----------------------------------------------------------------------*/
-
-/*
- * Separators for macros that expand into arrays.
- * These can be predefined by files that #include this one,
- * when different separators are required.
- */
-/* Element separator for macros that expand into 1-dimensional arrays: */
-#ifndef XCHAL_SEP
-#define XCHAL_SEP ,
-#endif
-/* Array separator for macros that expand into 2-dimensional arrays: */
-#ifndef XCHAL_SEP2
-#define XCHAL_SEP2 },{
-#endif
-
-
-/*----------------------------------------------------------------------
- ENDIANNESS
- ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_BE 1
-#define XCHAL_HAVE_LE 0
-#define XCHAL_MEMORY_ORDER XTHAL_BIGENDIAN
-
-
-/*----------------------------------------------------------------------
- REGISTER WINDOWS
- ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_WINDOWED 1 /* 1 if windowed registers option configured, 0 otherwise */
-#define XCHAL_NUM_AREGS 64 /* number of physical address regs */
-#define XCHAL_NUM_AREGS_LOG2 6 /* log2(XCHAL_NUM_AREGS) */
-
-
-/*----------------------------------------------------------------------
- ADDRESS ALIGNMENT
- ----------------------------------------------------------------------*/
-
-/* These apply to a selected set of core load and store instructions only (see ISA): */
-#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* 1 if unaligned loads cause an exception, 0 otherwise */
-#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* 1 if unaligned stores cause an exception, 0 otherwise */
-
-
-/*----------------------------------------------------------------------
- INTERRUPTS
- ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_INTERRUPTS 1 /* 1 if interrupt option configured, 0 otherwise */
-#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* 1 if high-priority interrupt option configured, 0 otherwise */
-#define XCHAL_HAVE_HIGHLEVEL_INTERRUPTS XCHAL_HAVE_HIGHPRI_INTERRUPTS
-#define XCHAL_HAVE_NMI 0 /* 1 if NMI option configured, 0 otherwise */
-#define XCHAL_NUM_INTERRUPTS 17 /* number of interrupts */
-#define XCHAL_NUM_INTERRUPTS_LOG2 5 /* number of bits to hold an interrupt number: roundup(log2(number of interrupts)) */
-#define XCHAL_NUM_EXTINTERRUPTS 10 /* number of external interrupts */
-#define XCHAL_NUM_INTLEVELS 4 /* number of interrupt levels (not including level zero!) */
-#define XCHAL_NUM_LOWPRI_LEVELS 1 /* number of low-priority interrupt levels (always 1) */
-#define XCHAL_FIRST_HIGHPRI_LEVEL (XCHAL_NUM_LOWPRI_LEVELS+1) /* level of first high-priority interrupt (always 2) */
-#define XCHAL_EXCM_LEVEL 1 /* level of interrupts masked by PS.EXCM (XEA2 only; always 1 in T10xx);
- for XEA1, where there is no PS.EXCM, this is always 1;
- interrupts at levels FIRST_HIGHPRI <= n <= EXCM_LEVEL, if any,
- are termed "medium priority" interrupts (post T10xx only) */
-/* Note: 1 <= LOWPRI_LEVELS <= EXCM_LEVEL < DEBUGLEVEL <= NUM_INTLEVELS < NMILEVEL <= 15 */
-
-/* Masks of interrupts at each interrupt level: */
-#define XCHAL_INTLEVEL0_MASK 0x00000000
-#define XCHAL_INTLEVEL1_MASK 0x000064F9
-#define XCHAL_INTLEVEL2_MASK 0x00008902
-#define XCHAL_INTLEVEL3_MASK 0x00011204
-#define XCHAL_INTLEVEL4_MASK 0x00000000
-#define XCHAL_INTLEVEL5_MASK 0x00000000
-#define XCHAL_INTLEVEL6_MASK 0x00000000
-#define XCHAL_INTLEVEL7_MASK 0x00000000
-#define XCHAL_INTLEVEL8_MASK 0x00000000
-#define XCHAL_INTLEVEL9_MASK 0x00000000
-#define XCHAL_INTLEVEL10_MASK 0x00000000
-#define XCHAL_INTLEVEL11_MASK 0x00000000
-#define XCHAL_INTLEVEL12_MASK 0x00000000
-#define XCHAL_INTLEVEL13_MASK 0x00000000
-#define XCHAL_INTLEVEL14_MASK 0x00000000
-#define XCHAL_INTLEVEL15_MASK 0x00000000
-/* As an array of entries (eg. for C constant arrays): */
-#define XCHAL_INTLEVEL_MASKS 0x00000000 XCHAL_SEP \
- 0x000064F9 XCHAL_SEP \
- 0x00008902 XCHAL_SEP \
- 0x00011204 XCHAL_SEP \
- 0x00000000 XCHAL_SEP \
- 0x00000000 XCHAL_SEP \
- 0x00000000 XCHAL_SEP \
- 0x00000000 XCHAL_SEP \
- 0x00000000 XCHAL_SEP \
- 0x00000000 XCHAL_SEP \
- 0x00000000 XCHAL_SEP \
- 0x00000000 XCHAL_SEP \
- 0x00000000 XCHAL_SEP \
- 0x00000000 XCHAL_SEP \
- 0x00000000 XCHAL_SEP \
- 0x00000000
-
-/* Masks of interrupts at each range 1..n of interrupt levels: */
-#define XCHAL_INTLEVEL0_ANDBELOW_MASK 0x00000000
-#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x000064F9
-#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x0000EDFB
-#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL8_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL9_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL10_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL11_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL12_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL13_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL14_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL15_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_LOWPRI_MASK XCHAL_INTLEVEL1_ANDBELOW_MASK /* mask of all low-priority interrupts */
-#define XCHAL_EXCM_MASK XCHAL_INTLEVEL1_ANDBELOW_MASK /* mask of all interrupts masked by PS.EXCM (or CEXCM) */
-/* As an array of entries (eg. for C constant arrays): */
-#define XCHAL_INTLEVEL_ANDBELOW_MASKS 0x00000000 XCHAL_SEP \
- 0x000064F9 XCHAL_SEP \
- 0x0000EDFB XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF XCHAL_SEP \
- 0x0001FFFF
-
-/* Interrupt numbers for each interrupt level at which only one interrupt was configured: */
-/*#define XCHAL_INTLEVEL1_NUM ...more than one interrupt at this level...*/
-/*#define XCHAL_INTLEVEL2_NUM ...more than one interrupt at this level...*/
-/*#define XCHAL_INTLEVEL3_NUM ...more than one interrupt at this level...*/
-
-/* Level of each interrupt: */
-#define XCHAL_INT0_LEVEL 1
-#define XCHAL_INT1_LEVEL 2
-#define XCHAL_INT2_LEVEL 3
-#define XCHAL_INT3_LEVEL 1
-#define XCHAL_INT4_LEVEL 1
-#define XCHAL_INT5_LEVEL 1
-#define XCHAL_INT6_LEVEL 1
-#define XCHAL_INT7_LEVEL 1
-#define XCHAL_INT8_LEVEL 2
-#define XCHAL_INT9_LEVEL 3
-#define XCHAL_INT10_LEVEL 1
-#define XCHAL_INT11_LEVEL 2
-#define XCHAL_INT12_LEVEL 3
-#define XCHAL_INT13_LEVEL 1
-#define XCHAL_INT14_LEVEL 1
-#define XCHAL_INT15_LEVEL 2
-#define XCHAL_INT16_LEVEL 3
-#define XCHAL_INT17_LEVEL 0
-#define XCHAL_INT18_LEVEL 0
-#define XCHAL_INT19_LEVEL 0
-#define XCHAL_INT20_LEVEL 0
-#define XCHAL_INT21_LEVEL 0
-#define XCHAL_INT22_LEVEL 0
-#define XCHAL_INT23_LEVEL 0
-#define XCHAL_INT24_LEVEL 0
-#define XCHAL_INT25_LEVEL 0
-#define XCHAL_INT26_LEVEL 0
-#define XCHAL_INT27_LEVEL 0
-#define XCHAL_INT28_LEVEL 0
-#define XCHAL_INT29_LEVEL 0
-#define XCHAL_INT30_LEVEL 0
-#define XCHAL_INT31_LEVEL 0
-/* As an array of entries (eg. for C constant arrays): */
-#define XCHAL_INT_LEVELS 1 XCHAL_SEP \
- 2 XCHAL_SEP \
- 3 XCHAL_SEP \
- 1 XCHAL_SEP \
- 1 XCHAL_SEP \
- 1 XCHAL_SEP \
- 1 XCHAL_SEP \
- 1 XCHAL_SEP \
- 2 XCHAL_SEP \
- 3 XCHAL_SEP \
- 1 XCHAL_SEP \
- 2 XCHAL_SEP \
- 3 XCHAL_SEP \
- 1 XCHAL_SEP \
- 1 XCHAL_SEP \
- 2 XCHAL_SEP \
- 3 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0 XCHAL_SEP \
- 0
-
-/* Type of each interrupt: */
-#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT6_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT7_TYPE XTHAL_INTTYPE_EXTERN_EDGE
-#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_EDGE
-#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_EDGE
-#define XCHAL_INT10_TYPE XTHAL_INTTYPE_TIMER
-#define XCHAL_INT11_TYPE XTHAL_INTTYPE_TIMER
-#define XCHAL_INT12_TYPE XTHAL_INTTYPE_TIMER
-#define XCHAL_INT13_TYPE XTHAL_INTTYPE_SOFTWARE
-#define XCHAL_INT14_TYPE XTHAL_INTTYPE_SOFTWARE
-#define XCHAL_INT15_TYPE XTHAL_INTTYPE_SOFTWARE
-#define XCHAL_INT16_TYPE XTHAL_INTTYPE_SOFTWARE
-#define XCHAL_INT17_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT18_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT19_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT20_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT21_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT22_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT23_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT24_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT25_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT26_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT27_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT28_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT29_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT30_TYPE XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT31_TYPE XTHAL_INTTYPE_UNCONFIGURED
-/* As an array of entries (eg. for C constant arrays): */
-#define XCHAL_INT_TYPES XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
- XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
- XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
- XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
- XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
- XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
- XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
- XTHAL_INTTYPE_EXTERN_EDGE XCHAL_SEP \
- XTHAL_INTTYPE_EXTERN_EDGE XCHAL_SEP \
- XTHAL_INTTYPE_EXTERN_EDGE XCHAL_SEP \
- XTHAL_INTTYPE_TIMER XCHAL_SEP \
- XTHAL_INTTYPE_TIMER XCHAL_SEP \
- XTHAL_INTTYPE_TIMER XCHAL_SEP \
- XTHAL_INTTYPE_SOFTWARE XCHAL_SEP \
- XTHAL_INTTYPE_SOFTWARE XCHAL_SEP \
- XTHAL_INTTYPE_SOFTWARE XCHAL_SEP \
- XTHAL_INTTYPE_SOFTWARE XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
- XTHAL_INTTYPE_UNCONFIGURED
-
-/* Masks of interrupts for each type of interrupt: */
-#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFE0000
-#define XCHAL_INTTYPE_MASK_SOFTWARE 0x0001E000
-#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00000380
-#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000007F
-#define XCHAL_INTTYPE_MASK_TIMER 0x00001C00
-#define XCHAL_INTTYPE_MASK_NMI 0x00000000
-/* As an array of entries (eg. for C constant arrays): */
-#define XCHAL_INTTYPE_MASKS 0xFFFE0000 XCHAL_SEP \
- 0x0001E000 XCHAL_SEP \
- 0x00000380 XCHAL_SEP \
- 0x0000007F XCHAL_SEP \
- 0x00001C00 XCHAL_SEP \
- 0x00000000
-
-/* Interrupts assigned to each timer (CCOMPARE0 to CCOMPARE3), -1 if unassigned */
-#define XCHAL_TIMER0_INTERRUPT 10
-#define XCHAL_TIMER1_INTERRUPT 11
-#define XCHAL_TIMER2_INTERRUPT 12
-#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED
-/* As an array of entries (eg. for C constant arrays): */
-#define XCHAL_TIMER_INTERRUPTS 10 XCHAL_SEP \
- 11 XCHAL_SEP \
- 12 XCHAL_SEP \
- XTHAL_TIMER_UNCONFIGURED
-
-/* Indexing macros: */
-#define _XCHAL_INTLEVEL_MASK(n) XCHAL_INTLEVEL ## n ## _MASK
-#define XCHAL_INTLEVEL_MASK(n) _XCHAL_INTLEVEL_MASK(n) /* n = 0 .. 15 */
-#define _XCHAL_INTLEVEL_ANDBELOWMASK(n) XCHAL_INTLEVEL ## n ## _ANDBELOW_MASK
-#define XCHAL_INTLEVEL_ANDBELOW_MASK(n) _XCHAL_INTLEVEL_ANDBELOWMASK(n) /* n = 0 .. 15 */
-#define _XCHAL_INT_LEVEL(n) XCHAL_INT ## n ## _LEVEL
-#define XCHAL_INT_LEVEL(n) _XCHAL_INT_LEVEL(n) /* n = 0 .. 31 */
-#define _XCHAL_INT_TYPE(n) XCHAL_INT ## n ## _TYPE
-#define XCHAL_INT_TYPE(n) _XCHAL_INT_TYPE(n) /* n = 0 .. 31 */
-#define _XCHAL_TIMER_INTERRUPT(n) XCHAL_TIMER ## n ## _INTERRUPT
-#define XCHAL_TIMER_INTERRUPT(n) _XCHAL_TIMER_INTERRUPT(n) /* n = 0 .. 3 */
-
-
-
-/*
- * External interrupt vectors/levels.
- * These macros describe how Xtensa processor interrupt numbers
- * (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
- * map to external BInterrupt<n> pins, for those interrupts
- * configured as external (level-triggered, edge-triggered, or NMI).
- * See the Xtensa processor databook for more details.
- */
-
-/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */
-#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */
-#define XCHAL_EXTINT1_NUM 1 /* (intlevel 2) */
-#define XCHAL_EXTINT2_NUM 2 /* (intlevel 3) */
-#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */
-#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */
-#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */
-#define XCHAL_EXTINT6_NUM 6 /* (intlevel 1) */
-#define XCHAL_EXTINT7_NUM 7 /* (intlevel 1) */
-#define XCHAL_EXTINT8_NUM 8 /* (intlevel 2) */
-#define XCHAL_EXTINT9_NUM 9 /* (intlevel 3) */
-
-/* Corresponding interrupt masks: */
-#define XCHAL_EXTINT0_MASK 0x00000001
-#define XCHAL_EXTINT1_MASK 0x00000002
-#define XCHAL_EXTINT2_MASK 0x00000004
-#define XCHAL_EXTINT3_MASK 0x00000008
-#define XCHAL_EXTINT4_MASK 0x00000010
-#define XCHAL_EXTINT5_MASK 0x00000020
-#define XCHAL_EXTINT6_MASK 0x00000040
-#define XCHAL_EXTINT7_MASK 0x00000080
-#define XCHAL_EXTINT8_MASK 0x00000100
-#define XCHAL_EXTINT9_MASK 0x00000200
-
-/* Core config interrupt levels mapped to each external interrupt: */
-#define XCHAL_EXTINT0_LEVEL 1 /* (int number 0) */
-#define XCHAL_EXTINT1_LEVEL 2 /* (int number 1) */
-#define XCHAL_EXTINT2_LEVEL 3 /* (int number 2) */
-#define XCHAL_EXTINT3_LEVEL 1 /* (int number 3) */
-#define XCHAL_EXTINT4_LEVEL 1 /* (int number 4) */
-#define XCHAL_EXTINT5_LEVEL 1 /* (int number 5) */
-#define XCHAL_EXTINT6_LEVEL 1 /* (int number 6) */
-#define XCHAL_EXTINT7_LEVEL 1 /* (int number 7) */
-#define XCHAL_EXTINT8_LEVEL 2 /* (int number 8) */
-#define XCHAL_EXTINT9_LEVEL 3 /* (int number 9) */
-
-
-/*----------------------------------------------------------------------
- EXCEPTIONS and VECTORS
- ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_EXCEPTIONS 1 /* 1 if exception option configured, 0 otherwise */
-
-#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture number: 1 for XEA1 (old), 2 for XEA2 (new) */
-#define XCHAL_HAVE_XEA1 0 /* 1 if XEA1, 0 otherwise */
-#define XCHAL_HAVE_XEA2 1 /* 1 if XEA2, 0 otherwise */
-/* For backward compatibility ONLY -- DO NOT USE (will be removed in future release): */
-#define XCHAL_HAVE_OLD_EXC_ARCH XCHAL_HAVE_XEA1 /* (DEPRECATED) 1 if old exception architecture (XEA1), 0 otherwise (eg. XEA2) */
-#define XCHAL_HAVE_EXCM XCHAL_HAVE_XEA2 /* (DEPRECATED) 1 if PS.EXCM bit exists (currently equals XCHAL_HAVE_TLBS) */
-
-#define XCHAL_RESET_VECTOR_VADDR 0xFE000020
-#define XCHAL_RESET_VECTOR_PADDR 0xFE000020
-#define XCHAL_USER_VECTOR_VADDR 0xD0000220
-#define XCHAL_PROGRAMEXC_VECTOR_VADDR XCHAL_USER_VECTOR_VADDR /* for backward compatibility */
-#define XCHAL_USEREXC_VECTOR_VADDR XCHAL_USER_VECTOR_VADDR /* for backward compatibility */
-#define XCHAL_USER_VECTOR_PADDR 0x00000220
-#define XCHAL_PROGRAMEXC_VECTOR_PADDR XCHAL_USER_VECTOR_PADDR /* for backward compatibility */
-#define XCHAL_USEREXC_VECTOR_PADDR XCHAL_USER_VECTOR_PADDR /* for backward compatibility */
-#define XCHAL_KERNEL_VECTOR_VADDR 0xD0000200
-#define XCHAL_STACKEDEXC_VECTOR_VADDR XCHAL_KERNEL_VECTOR_VADDR /* for backward compatibility */
-#define XCHAL_KERNELEXC_VECTOR_VADDR XCHAL_KERNEL_VECTOR_VADDR /* for backward compatibility */
-#define XCHAL_KERNEL_VECTOR_PADDR 0x00000200
-#define XCHAL_STACKEDEXC_VECTOR_PADDR XCHAL_KERNEL_VECTOR_PADDR /* for backward compatibility */
-#define XCHAL_KERNELEXC_VECTOR_PADDR XCHAL_KERNEL_VECTOR_PADDR /* for backward compatibility */
-#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0xD0000290
-#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x00000290
-#define XCHAL_WINDOW_VECTORS_VADDR 0xD0000000
-#define XCHAL_WINDOW_VECTORS_PADDR 0x00000000
-#define XCHAL_INTLEVEL2_VECTOR_VADDR 0xD0000240
-#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x00000240
-#define XCHAL_INTLEVEL3_VECTOR_VADDR 0xD0000250
-#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x00000250
-#define XCHAL_INTLEVEL4_VECTOR_VADDR 0xFE000520
-#define XCHAL_INTLEVEL4_VECTOR_PADDR 0xFE000520
-#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL4_VECTOR_VADDR
-#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL4_VECTOR_PADDR
-
-/* Indexing macros: */
-#define _XCHAL_INTLEVEL_VECTOR_VADDR(n) XCHAL_INTLEVEL ## n ## _VECTOR_VADDR
-#define XCHAL_INTLEVEL_VECTOR_VADDR(n) _XCHAL_INTLEVEL_VECTOR_VADDR(n) /* n = 0 .. 15 */
-
-/*
- * General Exception Causes
- * (values of EXCCAUSE special register set by general exceptions,
- * which vector to the user, kernel, or double-exception vectors):
- */
-#define XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION 0 /* Illegal Instruction (IllegalInstruction) */
-#define XCHAL_EXCCAUSE_SYSTEM_CALL 1 /* System Call (SystemCall) */
-#define XCHAL_EXCCAUSE_INSTRUCTION_FETCH_ERROR 2 /* Instruction Fetch Error (InstructionFetchError) */
-#define XCHAL_EXCCAUSE_LOAD_STORE_ERROR 3 /* Load Store Error (LoadStoreError) */
-#define XCHAL_EXCCAUSE_LEVEL1_INTERRUPT 4 /* Level 1 Interrupt (Level1Interrupt) */
-#define XCHAL_EXCCAUSE_ALLOCA 5 /* Stack Extension Assist (Alloca) */
-#define XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO 6 /* Integer Divide by Zero (IntegerDivideByZero) */
-#define XCHAL_EXCCAUSE_SPECULATION 7 /* Speculation (Speculation) */
-#define XCHAL_EXCCAUSE_PRIVILEGED 8 /* Privileged Instruction (Privileged) */
-#define XCHAL_EXCCAUSE_UNALIGNED 9 /* Unaligned Load Store (Unaligned) */
-#define XCHAL_EXCCAUSE_ITLB_MISS 16 /* ITlb Miss Exception (ITlbMiss) */
-#define XCHAL_EXCCAUSE_ITLB_MULTIHIT 17 /* ITlb Mutltihit Exception (ITlbMultihit) */
-#define XCHAL_EXCCAUSE_ITLB_PRIVILEGE 18 /* ITlb Privilege Exception (ITlbPrivilege) */
-#define XCHAL_EXCCAUSE_ITLB_SIZE_RESTRICTION 19 /* ITlb Size Restriction Exception (ITlbSizeRestriction) */
-#define XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE 20 /* Fetch Cache Attribute Exception (FetchCacheAttribute) */
-#define XCHAL_EXCCAUSE_DTLB_MISS 24 /* DTlb Miss Exception (DTlbMiss) */
-#define XCHAL_EXCCAUSE_DTLB_MULTIHIT 25 /* DTlb Multihit Exception (DTlbMultihit) */
-#define XCHAL_EXCCAUSE_DTLB_PRIVILEGE 26 /* DTlb Privilege Exception (DTlbPrivilege) */
-#define XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION 27 /* DTlb Size Restriction Exception (DTlbSizeRestriction) */
-#define XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE 28 /* Load Cache Attribute Exception (LoadCacheAttribute) */
-#define XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE 29 /* Store Cache Attribute Exception (StoreCacheAttribute) */
-#define XCHAL_EXCCAUSE_FLOATING_POINT 40 /* Floating Point Exception (FloatingPoint) */
-
-
-
-/*----------------------------------------------------------------------
- TIMERS
- ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_CCOUNT 1 /* 1 if have CCOUNT, 0 otherwise */
-/*#define XCHAL_HAVE_TIMERS XCHAL_HAVE_CCOUNT*/
-#define XCHAL_NUM_TIMERS 3 /* number of CCOMPAREn regs */
-
-
-
-/*----------------------------------------------------------------------
- DEBUG
- ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_DEBUG 1 /* 1 if debug option configured, 0 otherwise */
-#define XCHAL_HAVE_OCD 1 /* 1 if OnChipDebug option configured, 0 otherwise */
-#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */
-#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */
-#define XCHAL_DEBUGLEVEL 4 /* debug interrupt level */
-/*DebugExternalInterrupt 0 0|1*/
-/*DebugUseDIRArray 0 0|1*/
-
-
-
-
-/*----------------------------------------------------------------------
- COPROCESSORS and EXTRA STATE
- ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_CP 0 /* 1 if coprocessor option configured (CPENABLE present) */
-#define XCHAL_CP_MAXCFG 0 /* max allowed cp id plus one (per cfg) */
-
-#include <xtensa/config/tie.h>
-
-
-
-
-/*----------------------------------------------------------------------
- INTERNAL I/D RAM/ROMs and XLMI
- ----------------------------------------------------------------------*/
-
-#define XCHAL_NUM_INSTROM 0 /* number of core instruction ROMs configured */
-#define XCHAL_NUM_INSTRAM 0 /* number of core instruction RAMs configured */
-#define XCHAL_NUM_DATAROM 0 /* number of core data ROMs configured */
-#define XCHAL_NUM_DATARAM 0 /* number of core data RAMs configured */
-#define XCHAL_NUM_XLMI 0 /* number of core XLMI ports configured */
-#define XCHAL_NUM_IROM XCHAL_NUM_INSTROM /* (DEPRECATED) */
-#define XCHAL_NUM_IRAM XCHAL_NUM_INSTRAM /* (DEPRECATED) */
-#define XCHAL_NUM_DROM XCHAL_NUM_DATAROM /* (DEPRECATED) */
-#define XCHAL_NUM_DRAM XCHAL_NUM_DATARAM /* (DEPRECATED) */
-
-
-
-/*----------------------------------------------------------------------
- CACHE
- ----------------------------------------------------------------------*/
-
-/* Size of the cache lines in log2(bytes): */
-#define XCHAL_ICACHE_LINEWIDTH 4
-#define XCHAL_DCACHE_LINEWIDTH 4
-/* Size of the cache lines in bytes: */
-#define XCHAL_ICACHE_LINESIZE 16
-#define XCHAL_DCACHE_LINESIZE 16
-/* Max for both I-cache and D-cache (used for general alignment): */
-#define XCHAL_CACHE_LINEWIDTH_MAX 4
-#define XCHAL_CACHE_LINESIZE_MAX 16
-
-/* Number of cache sets in log2(lines per way): */
-#define XCHAL_ICACHE_SETWIDTH 8
-#define XCHAL_DCACHE_SETWIDTH 8
-/* Max for both I-cache and D-cache (used for general cache-coherency page alignment): */
-#define XCHAL_CACHE_SETWIDTH_MAX 8
-#define XCHAL_CACHE_SETSIZE_MAX 256
-
-/* Cache set associativity (number of ways): */
-#define XCHAL_ICACHE_WAYS 2
-#define XCHAL_DCACHE_WAYS 2
-
-/* Size of the caches in bytes (ways * 2^(linewidth + setwidth)): */
-#define XCHAL_ICACHE_SIZE 8192
-#define XCHAL_DCACHE_SIZE 8192
-
-/* Cache features: */
-#define XCHAL_DCACHE_IS_WRITEBACK 0
-/* Whether cache locking feature is available: */
-#define XCHAL_ICACHE_LINE_LOCKABLE 0
-#define XCHAL_DCACHE_LINE_LOCKABLE 0
-
-/* Number of (encoded) cache attribute bits: */
-#define XCHAL_CA_BITS 4 /* number of bits needed to hold cache attribute encoding */
-/* (The number of access mode bits (decoded cache attribute bits) is defined by the architecture; see xtensa/hal.h?) */
-
-
-/* Cache Attribute encodings -- lists of access modes for each cache attribute: */
-#define XCHAL_FCA_LIST XTHAL_FAM_EXCEPTION XCHAL_SEP \
- XTHAL_FAM_BYPASS XCHAL_SEP \
- XTHAL_FAM_EXCEPTION XCHAL_SEP \
- XTHAL_FAM_BYPASS XCHAL_SEP \
- XTHAL_FAM_EXCEPTION XCHAL_SEP \
- XTHAL_FAM_CACHED XCHAL_SEP \
- XTHAL_FAM_EXCEPTION XCHAL_SEP \
- XTHAL_FAM_CACHED XCHAL_SEP \
- XTHAL_FAM_EXCEPTION XCHAL_SEP \
- XTHAL_FAM_CACHED XCHAL_SEP \
- XTHAL_FAM_EXCEPTION XCHAL_SEP \
- XTHAL_FAM_CACHED XCHAL_SEP \
- XTHAL_FAM_EXCEPTION XCHAL_SEP \
- XTHAL_FAM_EXCEPTION XCHAL_SEP \
- XTHAL_FAM_EXCEPTION XCHAL_SEP \
- XTHAL_FAM_EXCEPTION
-#define XCHAL_LCA_LIST XTHAL_LAM_EXCEPTION XCHAL_SEP \
- XTHAL_LAM_BYPASSG XCHAL_SEP \
- XTHAL_LAM_EXCEPTION XCHAL_SEP \
- XTHAL_LAM_BYPASSG XCHAL_SEP \
- XTHAL_LAM_EXCEPTION XCHAL_SEP \
- XTHAL_LAM_CACHED XCHAL_SEP \
- XTHAL_LAM_EXCEPTION XCHAL_SEP \
- XTHAL_LAM_CACHED XCHAL_SEP \
- XTHAL_LAM_EXCEPTION XCHAL_SEP \
- XTHAL_LAM_NACACHED XCHAL_SEP \
- XTHAL_LAM_EXCEPTION XCHAL_SEP \
- XTHAL_LAM_NACACHED XCHAL_SEP \
- XTHAL_LAM_EXCEPTION XCHAL_SEP \
- XTHAL_LAM_ISOLATE XCHAL_SEP \
- XTHAL_LAM_EXCEPTION XCHAL_SEP \
- XTHAL_LAM_CACHED
-#define XCHAL_SCA_LIST XTHAL_SAM_EXCEPTION XCHAL_SEP \
- XTHAL_SAM_EXCEPTION XCHAL_SEP \
- XTHAL_SAM_EXCEPTION XCHAL_SEP \
- XTHAL_SAM_BYPASS XCHAL_SEP \
- XTHAL_SAM_EXCEPTION XCHAL_SEP \
- XTHAL_SAM_EXCEPTION XCHAL_SEP \
- XTHAL_SAM_EXCEPTION XCHAL_SEP \
- XTHAL_SAM_WRITETHRU XCHAL_SEP \
- XTHAL_SAM_EXCEPTION XCHAL_SEP \
- XTHAL_SAM_EXCEPTION XCHAL_SEP \
- XTHAL_SAM_EXCEPTION XCHAL_SEP \
- XTHAL_SAM_WRITETHRU XCHAL_SEP \
- XTHAL_SAM_EXCEPTION XCHAL_SEP \
- XTHAL_SAM_ISOLATE XCHAL_SEP \
- XTHAL_SAM_EXCEPTION XCHAL_SEP \
- XTHAL_SAM_WRITETHRU
-
-/* Test:
- read/only: 0 + 1 + 2 + 4 + 5 + 6 + 8 + 9 + 10 + 12 + 14
- read/only: 0 + 1 + 2 + 4 + 5 + 6 + 8 + 9 + 10 + 12 + 14
- all: 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15
- fault: 0 + 2 + 4 + 6 + 8 + 10 + 12 + 14
- r/w/x cached:
- r/w/x dcached:
- I-bypass: 1 + 3
-
- load guard bit set: 1 + 3
- load guard bit clr: 0 + 2 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15
- hit-cache r/w/x: 7 + 11
-
- fams: 5
- fams: 0 / 6 / 18 / 1 / 2
- fams: Bypass / Isolate / Cached / Exception / NACached
-
- MMU okay: yes
-*/
-
-
-/*----------------------------------------------------------------------
- MMU
- ----------------------------------------------------------------------*/
-
-/*
- * General notes on MMU parameters.
- *
- * Terminology:
- * ASID = address-space ID (acts as an "extension" of virtual addresses)
- * VPN = virtual page number
- * PPN = physical page number
- * CA = encoded cache attribute (access modes)
- * TLB = translation look-aside buffer (term is stretched somewhat here)
- * I = instruction (fetch accesses)
- * D = data (load and store accesses)
- * way = each TLB (ITLB and DTLB) consists of a number of "ways"
- * that simultaneously match the virtual address of an access;
- * a TLB successfully translates a virtual address if exactly
- * one way matches the vaddr; if none match, it is a miss;
- * if multiple match, one gets a "multihit" exception;
- * each way can be independently configured in terms of number of
- * entries, page sizes, which fields are writable or constant, etc.
- * set = group of contiguous ways with exactly identical parameters
- * ARF = auto-refill; hardware services a 1st-level miss by loading a PTE
- * from the page table and storing it in one of the auto-refill ways;
- * if this PTE load also misses, a miss exception is posted for s/w.
- * min-wired = a "min-wired" way can be used to map a single (minimum-sized)
- * page arbitrarily under program control; it has a single entry,
- * is non-auto-refill (some other way(s) must be auto-refill),
- * all its fields (VPN, PPN, ASID, CA) are all writable, and it
- * supports the XCHAL_MMU_MIN_PTE_PAGE_SIZE page size (a current
- * restriction is that this be the only page size it supports).
- *
- * TLB way entries are virtually indexed.
- * TLB ways that support multiple page sizes:
- * - must have all writable VPN and PPN fields;
- * - can only use one page size at any given time (eg. setup at startup),
- * selected by the respective ITLBCFG or DTLBCFG special register,
- * whose bits n*4+3 .. n*4 index the list of page sizes for way n
- * (XCHAL_xTLB_SETm_PAGESZ_LOG2_LIST for set m corresponding to way n);
- * this list may be sparse for auto-refill ways because auto-refill
- * ways have independent lists of supported page sizes sharing a
- * common encoding with PTE entries; the encoding is the index into
- * this list; unsupported sizes for a given way are zero in the list;
- * selecting unsupported sizes results in undefined hardware behaviour;
- * - is only possible for ways 0 thru 7 (due to ITLBCFG/DTLBCFG definition).
- */
-
-#define XCHAL_HAVE_CACHEATTR 0 /* 1 if CACHEATTR register present, 0 if TLBs present instead */
-#define XCHAL_HAVE_TLBS 1 /* 1 if TLBs present, 0 if CACHEATTR present instead */
-#define XCHAL_HAVE_MMU XCHAL_HAVE_TLBS /* (DEPRECATED; use XCHAL_HAVE_TLBS instead; will be removed in future release) */
-#define XCHAL_HAVE_SPANNING_WAY 0 /* 1 if single way maps entire virtual address space in I+D */
-#define XCHAL_HAVE_IDENTITY_MAP 0 /* 1 if virtual addr == physical addr always, 0 otherwise */
-#define XCHAL_HAVE_MIMIC_CACHEATTR 0 /* 1 if have MMU that mimics a CACHEATTR config (CaMMU) */
-#define XCHAL_HAVE_XLT_CACHEATTR 0 /* 1 if have MMU that mimics a CACHEATTR config, but with translation (CaXltMMU) */
-
-#define XCHAL_MMU_ASID_BITS 8 /* number of bits in ASIDs (address space IDs) */
-#define XCHAL_MMU_ASID_INVALID 0 /* ASID value indicating invalid address space */
-#define XCHAL_MMU_ASID_KERNEL 1 /* ASID value indicating kernel (ring 0) address space */
-#define XCHAL_MMU_RINGS 4 /* number of rings supported (1..4) */
-#define XCHAL_MMU_RING_BITS 2 /* number of bits needed to hold ring number */
-#define XCHAL_MMU_SR_BITS 0 /* number of size-restriction bits supported */
-#define XCHAL_MMU_CA_BITS 4 /* number of bits needed to hold cache attribute encoding */
-#define XCHAL_MMU_MAX_PTE_PAGE_SIZE 12 /* max page size in a PTE structure (log2) */
-#define XCHAL_MMU_MIN_PTE_PAGE_SIZE 12 /* min page size in a PTE structure (log2) */
-
-
-/*** Instruction TLB: ***/
-
-#define XCHAL_ITLB_WAY_BITS 3 /* number of bits holding the ways */
-#define XCHAL_ITLB_WAYS 7 /* number of ways (n-way set-associative TLB) */
-#define XCHAL_ITLB_ARF_WAYS 4 /* number of auto-refill ways */
-#define XCHAL_ITLB_SETS 4 /* number of sets (groups of ways with identical settings) */
-
-/* Way set to which each way belongs: */
-#define XCHAL_ITLB_WAY0_SET 0
-#define XCHAL_ITLB_WAY1_SET 0
-#define XCHAL_ITLB_WAY2_SET 0
-#define XCHAL_ITLB_WAY3_SET 0
-#define XCHAL_ITLB_WAY4_SET 1
-#define XCHAL_ITLB_WAY5_SET 2
-#define XCHAL_ITLB_WAY6_SET 3
-
-/* Ways sets that are used by hardware auto-refill (ARF): */
-#define XCHAL_ITLB_ARF_SETS 1 /* number of auto-refill sets */
-#define XCHAL_ITLB_ARF_SET0 0 /* index of n'th auto-refill set */
-
-/* Way sets that are "min-wired" (see terminology comment above): */
-#define XCHAL_ITLB_MINWIRED_SETS 0 /* number of "min-wired" sets */
-
-
-/* ITLB way set 0 (group of ways 0 thru 3): */
-#define XCHAL_ITLB_SET0_WAY 0 /* index of first way in this way set */
-#define XCHAL_ITLB_SET0_WAYS 4 /* number of (contiguous) ways in this way set */
-#define XCHAL_ITLB_SET0_ENTRIES_LOG2 2 /* log2(number of entries in this way) */
-#define XCHAL_ITLB_SET0_ENTRIES 4 /* number of entries in this way (always a power of 2) */
-#define XCHAL_ITLB_SET0_ARF 1 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_ITLB_SET0_PAGESIZES 1 /* number of supported page sizes in this way */
-#define XCHAL_ITLB_SET0_PAGESZ_BITS 0 /* number of bits to encode the page size */
-#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MIN 12 /* log2(minimum supported page size) */
-#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MAX 12 /* log2(maximum supported page size) */
-#define XCHAL_ITLB_SET0_PAGESZ_LOG2_LIST 12 /* list of log2(page size)s, separated by XCHAL_SEP;
- 2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_ITLB_SET0_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */
-#define XCHAL_ITLB_SET0_VPN_CONSTMASK 0 /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET0_PPN_CONSTMASK 0 /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET0_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */
-#define XCHAL_ITLB_SET0_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET0_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET0_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET0_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
-
-/* ITLB way set 1 (group of ways 4 thru 4): */
-#define XCHAL_ITLB_SET1_WAY 4 /* index of first way in this way set */
-#define XCHAL_ITLB_SET1_WAYS 1 /* number of (contiguous) ways in this way set */
-#define XCHAL_ITLB_SET1_ENTRIES_LOG2 2 /* log2(number of entries in this way) */
-#define XCHAL_ITLB_SET1_ENTRIES 4 /* number of entries in this way (always a power of 2) */
-#define XCHAL_ITLB_SET1_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_ITLB_SET1_PAGESIZES 4 /* number of supported page sizes in this way */
-#define XCHAL_ITLB_SET1_PAGESZ_BITS 2 /* number of bits to encode the page size */
-#define XCHAL_ITLB_SET1_PAGESZ_LOG2_MIN 20 /* log2(minimum supported page size) */
-#define XCHAL_ITLB_SET1_PAGESZ_LOG2_MAX 26 /* log2(maximum supported page size) */
-#define XCHAL_ITLB_SET1_PAGESZ_LOG2_LIST 20 XCHAL_SEP 22 XCHAL_SEP 24 XCHAL_SEP 26 /* list of log2(page size)s, separated by XCHAL_SEP;
- 2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_ITLB_SET1_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */
-#define XCHAL_ITLB_SET1_VPN_CONSTMASK 0 /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET1_PPN_CONSTMASK 0 /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET1_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */
-#define XCHAL_ITLB_SET1_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET1_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET1_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET1_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
-
-/* ITLB way set 2 (group of ways 5 thru 5): */
-#define XCHAL_ITLB_SET2_WAY 5 /* index of first way in this way set */
-#define XCHAL_ITLB_SET2_WAYS 1 /* number of (contiguous) ways in this way set */
-#define XCHAL_ITLB_SET2_ENTRIES_LOG2 1 /* log2(number of entries in this way) */
-#define XCHAL_ITLB_SET2_ENTRIES 2 /* number of entries in this way (always a power of 2) */
-#define XCHAL_ITLB_SET2_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_ITLB_SET2_PAGESIZES 1 /* number of supported page sizes in this way */
-#define XCHAL_ITLB_SET2_PAGESZ_BITS 0 /* number of bits to encode the page size */
-#define XCHAL_ITLB_SET2_PAGESZ_LOG2_MIN 27 /* log2(minimum supported page size) */
-#define XCHAL_ITLB_SET2_PAGESZ_LOG2_MAX 27 /* log2(maximum supported page size) */
-#define XCHAL_ITLB_SET2_PAGESZ_LOG2_LIST 27 /* list of log2(page size)s, separated by XCHAL_SEP;
- 2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_ITLB_SET2_ASID_CONSTMASK 0xFF /* constant ASID bits; 0 if all writable */
-#define XCHAL_ITLB_SET2_VPN_CONSTMASK 0xF0000000 /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET2_PPN_CONSTMASK 0xF8000000 /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET2_CA_CONSTMASK 0x0000000F /* constant CA bits; 0 if all writable */
-#define XCHAL_ITLB_SET2_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET2_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET2_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET2_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
-/* Constant ASID values for each entry of ITLB way set 2 (because ASID_CONSTMASK is non-zero): */
-#define XCHAL_ITLB_SET2_E0_ASID_CONST 0x01
-#define XCHAL_ITLB_SET2_E1_ASID_CONST 0x01
-/* Constant VPN values for each entry of ITLB way set 2 (because VPN_CONSTMASK is non-zero): */
-#define XCHAL_ITLB_SET2_E0_VPN_CONST 0xD0000000
-#define XCHAL_ITLB_SET2_E1_VPN_CONST 0xD8000000
-/* Constant PPN values for each entry of ITLB way set 2 (because PPN_CONSTMASK is non-zero): */
-#define XCHAL_ITLB_SET2_E0_PPN_CONST 0x00000000
-#define XCHAL_ITLB_SET2_E1_PPN_CONST 0x00000000
-/* Constant CA values for each entry of ITLB way set 2 (because CA_CONSTMASK is non-zero): */
-#define XCHAL_ITLB_SET2_E0_CA_CONST 0x07
-#define XCHAL_ITLB_SET2_E1_CA_CONST 0x03
-
-/* ITLB way set 3 (group of ways 6 thru 6): */
-#define XCHAL_ITLB_SET3_WAY 6 /* index of first way in this way set */
-#define XCHAL_ITLB_SET3_WAYS 1 /* number of (contiguous) ways in this way set */
-#define XCHAL_ITLB_SET3_ENTRIES_LOG2 1 /* log2(number of entries in this way) */
-#define XCHAL_ITLB_SET3_ENTRIES 2 /* number of entries in this way (always a power of 2) */
-#define XCHAL_ITLB_SET3_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_ITLB_SET3_PAGESIZES 1 /* number of supported page sizes in this way */
-#define XCHAL_ITLB_SET3_PAGESZ_BITS 0 /* number of bits to encode the page size */
-#define XCHAL_ITLB_SET3_PAGESZ_LOG2_MIN 28 /* log2(minimum supported page size) */
-#define XCHAL_ITLB_SET3_PAGESZ_LOG2_MAX 28 /* log2(maximum supported page size) */
-#define XCHAL_ITLB_SET3_PAGESZ_LOG2_LIST 28 /* list of log2(page size)s, separated by XCHAL_SEP;
- 2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_ITLB_SET3_ASID_CONSTMASK 0xFF /* constant ASID bits; 0 if all writable */
-#define XCHAL_ITLB_SET3_VPN_CONSTMASK 0xE0000000 /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET3_PPN_CONSTMASK 0xF0000000 /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET3_CA_CONSTMASK 0x0000000F /* constant CA bits; 0 if all writable */
-#define XCHAL_ITLB_SET3_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET3_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET3_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET3_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
-/* Constant ASID values for each entry of ITLB way set 3 (because ASID_CONSTMASK is non-zero): */
-#define XCHAL_ITLB_SET3_E0_ASID_CONST 0x01
-#define XCHAL_ITLB_SET3_E1_ASID_CONST 0x01
-/* Constant VPN values for each entry of ITLB way set 3 (because VPN_CONSTMASK is non-zero): */
-#define XCHAL_ITLB_SET3_E0_VPN_CONST 0xE0000000
-#define XCHAL_ITLB_SET3_E1_VPN_CONST 0xF0000000
-/* Constant PPN values for each entry of ITLB way set 3 (because PPN_CONSTMASK is non-zero): */
-#define XCHAL_ITLB_SET3_E0_PPN_CONST 0xF0000000
-#define XCHAL_ITLB_SET3_E1_PPN_CONST 0xF0000000
-/* Constant CA values for each entry of ITLB way set 3 (because CA_CONSTMASK is non-zero): */
-#define XCHAL_ITLB_SET3_E0_CA_CONST 0x07
-#define XCHAL_ITLB_SET3_E1_CA_CONST 0x03
-
-/* Indexing macros: */
-#define _XCHAL_ITLB_SET(n,_what) XCHAL_ITLB_SET ## n ## _what
-#define XCHAL_ITLB_SET(n,what) _XCHAL_ITLB_SET(n, _ ## what )
-#define _XCHAL_ITLB_SET_E(n,i,_what) XCHAL_ITLB_SET ## n ## _E ## i ## _what
-#define XCHAL_ITLB_SET_E(n,i,what) _XCHAL_ITLB_SET_E(n,i, _ ## what )
-/*
- * Example use: XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,ENTRIES)
- * to get the value of XCHAL_ITLB_SET<n>_ENTRIES where <n> is the first auto-refill set.
- */
-
-
-/*** Data TLB: ***/
-
-#define XCHAL_DTLB_WAY_BITS 4 /* number of bits holding the ways */
-#define XCHAL_DTLB_WAYS 10 /* number of ways (n-way set-associative TLB) */
-#define XCHAL_DTLB_ARF_WAYS 4 /* number of auto-refill ways */
-#define XCHAL_DTLB_SETS 5 /* number of sets (groups of ways with identical settings) */
-
-/* Way set to which each way belongs: */
-#define XCHAL_DTLB_WAY0_SET 0
-#define XCHAL_DTLB_WAY1_SET 0
-#define XCHAL_DTLB_WAY2_SET 0
-#define XCHAL_DTLB_WAY3_SET 0
-#define XCHAL_DTLB_WAY4_SET 1
-#define XCHAL_DTLB_WAY5_SET 2
-#define XCHAL_DTLB_WAY6_SET 3
-#define XCHAL_DTLB_WAY7_SET 4
-#define XCHAL_DTLB_WAY8_SET 4
-#define XCHAL_DTLB_WAY9_SET 4
-
-/* Ways sets that are used by hardware auto-refill (ARF): */
-#define XCHAL_DTLB_ARF_SETS 1 /* number of auto-refill sets */
-#define XCHAL_DTLB_ARF_SET0 0 /* index of n'th auto-refill set */
-
-/* Way sets that are "min-wired" (see terminology comment above): */
-#define XCHAL_DTLB_MINWIRED_SETS 1 /* number of "min-wired" sets */
-#define XCHAL_DTLB_MINWIRED_SET0 4 /* index of n'th "min-wired" set */
-
-
-/* DTLB way set 0 (group of ways 0 thru 3): */
-#define XCHAL_DTLB_SET0_WAY 0 /* index of first way in this way set */
-#define XCHAL_DTLB_SET0_WAYS 4 /* number of (contiguous) ways in this way set */
-#define XCHAL_DTLB_SET0_ENTRIES_LOG2 2 /* log2(number of entries in this way) */
-#define XCHAL_DTLB_SET0_ENTRIES 4 /* number of entries in this way (always a power of 2) */
-#define XCHAL_DTLB_SET0_ARF 1 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_DTLB_SET0_PAGESIZES 1 /* number of supported page sizes in this way */
-#define XCHAL_DTLB_SET0_PAGESZ_BITS 0 /* number of bits to encode the page size */
-#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MIN 12 /* log2(minimum supported page size) */
-#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MAX 12 /* log2(maximum supported page size) */
-#define XCHAL_DTLB_SET0_PAGESZ_LOG2_LIST 12 /* list of log2(page size)s, separated by XCHAL_SEP;
- 2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_DTLB_SET0_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */
-#define XCHAL_DTLB_SET0_VPN_CONSTMASK 0 /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET0_PPN_CONSTMASK 0 /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET0_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */
-#define XCHAL_DTLB_SET0_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET0_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET0_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET0_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
-
-/* DTLB way set 1 (group of ways 4 thru 4): */
-#define XCHAL_DTLB_SET1_WAY 4 /* index of first way in this way set */
-#define XCHAL_DTLB_SET1_WAYS 1 /* number of (contiguous) ways in this way set */
-#define XCHAL_DTLB_SET1_ENTRIES_LOG2 2 /* log2(number of entries in this way) */
-#define XCHAL_DTLB_SET1_ENTRIES 4 /* number of entries in this way (always a power of 2) */
-#define XCHAL_DTLB_SET1_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_DTLB_SET1_PAGESIZES 4 /* number of supported page sizes in this way */
-#define XCHAL_DTLB_SET1_PAGESZ_BITS 2 /* number of bits to encode the page size */
-#define XCHAL_DTLB_SET1_PAGESZ_LOG2_MIN 20 /* log2(minimum supported page size) */
-#define XCHAL_DTLB_SET1_PAGESZ_LOG2_MAX 26 /* log2(maximum supported page size) */
-#define XCHAL_DTLB_SET1_PAGESZ_LOG2_LIST 20 XCHAL_SEP 22 XCHAL_SEP 24 XCHAL_SEP 26 /* list of log2(page size)s, separated by XCHAL_SEP;
- 2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_DTLB_SET1_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */
-#define XCHAL_DTLB_SET1_VPN_CONSTMASK 0 /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET1_PPN_CONSTMASK 0 /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET1_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */
-#define XCHAL_DTLB_SET1_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET1_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET1_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET1_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
-
-/* DTLB way set 2 (group of ways 5 thru 5): */
-#define XCHAL_DTLB_SET2_WAY 5 /* index of first way in this way set */
-#define XCHAL_DTLB_SET2_WAYS 1 /* number of (contiguous) ways in this way set */
-#define XCHAL_DTLB_SET2_ENTRIES_LOG2 1 /* log2(number of entries in this way) */
-#define XCHAL_DTLB_SET2_ENTRIES 2 /* number of entries in this way (always a power of 2) */
-#define XCHAL_DTLB_SET2_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_DTLB_SET2_PAGESIZES 1 /* number of supported page sizes in this way */
-#define XCHAL_DTLB_SET2_PAGESZ_BITS 0 /* number of bits to encode the page size */
-#define XCHAL_DTLB_SET2_PAGESZ_LOG2_MIN 27 /* log2(minimum supported page size) */
-#define XCHAL_DTLB_SET2_PAGESZ_LOG2_MAX 27 /* log2(maximum supported page size) */
-#define XCHAL_DTLB_SET2_PAGESZ_LOG2_LIST 27 /* list of log2(page size)s, separated by XCHAL_SEP;
- 2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_DTLB_SET2_ASID_CONSTMASK 0xFF /* constant ASID bits; 0 if all writable */
-#define XCHAL_DTLB_SET2_VPN_CONSTMASK 0xF0000000 /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET2_PPN_CONSTMASK 0xF8000000 /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET2_CA_CONSTMASK 0x0000000F /* constant CA bits; 0 if all writable */
-#define XCHAL_DTLB_SET2_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET2_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET2_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET2_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
-/* Constant ASID values for each entry of DTLB way set 2 (because ASID_CONSTMASK is non-zero): */
-#define XCHAL_DTLB_SET2_E0_ASID_CONST 0x01
-#define XCHAL_DTLB_SET2_E1_ASID_CONST 0x01
-/* Constant VPN values for each entry of DTLB way set 2 (because VPN_CONSTMASK is non-zero): */
-#define XCHAL_DTLB_SET2_E0_VPN_CONST 0xD0000000
-#define XCHAL_DTLB_SET2_E1_VPN_CONST 0xD8000000
-/* Constant PPN values for each entry of DTLB way set 2 (because PPN_CONSTMASK is non-zero): */
-#define XCHAL_DTLB_SET2_E0_PPN_CONST 0x00000000
-#define XCHAL_DTLB_SET2_E1_PPN_CONST 0x00000000
-/* Constant CA values for each entry of DTLB way set 2 (because CA_CONSTMASK is non-zero): */
-#define XCHAL_DTLB_SET2_E0_CA_CONST 0x07
-#define XCHAL_DTLB_SET2_E1_CA_CONST 0x03
-
-/* DTLB way set 3 (group of ways 6 thru 6): */
-#define XCHAL_DTLB_SET3_WAY 6 /* index of first way in this way set */
-#define XCHAL_DTLB_SET3_WAYS 1 /* number of (contiguous) ways in this way set */
-#define XCHAL_DTLB_SET3_ENTRIES_LOG2 1 /* log2(number of entries in this way) */
-#define XCHAL_DTLB_SET3_ENTRIES 2 /* number of entries in this way (always a power of 2) */
-#define XCHAL_DTLB_SET3_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_DTLB_SET3_PAGESIZES 1 /* number of supported page sizes in this way */
-#define XCHAL_DTLB_SET3_PAGESZ_BITS 0 /* number of bits to encode the page size */
-#define XCHAL_DTLB_SET3_PAGESZ_LOG2_MIN 28 /* log2(minimum supported page size) */
-#define XCHAL_DTLB_SET3_PAGESZ_LOG2_MAX 28 /* log2(maximum supported page size) */
-#define XCHAL_DTLB_SET3_PAGESZ_LOG2_LIST 28 /* list of log2(page size)s, separated by XCHAL_SEP;
- 2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_DTLB_SET3_ASID_CONSTMASK 0xFF /* constant ASID bits; 0 if all writable */
-#define XCHAL_DTLB_SET3_VPN_CONSTMASK 0xE0000000 /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET3_PPN_CONSTMASK 0xF0000000 /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET3_CA_CONSTMASK 0x0000000F /* constant CA bits; 0 if all writable */
-#define XCHAL_DTLB_SET3_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET3_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET3_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET3_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
-/* Constant ASID values for each entry of DTLB way set 3 (because ASID_CONSTMASK is non-zero): */
-#define XCHAL_DTLB_SET3_E0_ASID_CONST 0x01
-#define XCHAL_DTLB_SET3_E1_ASID_CONST 0x01
-/* Constant VPN values for each entry of DTLB way set 3 (because VPN_CONSTMASK is non-zero): */
-#define XCHAL_DTLB_SET3_E0_VPN_CONST 0xE0000000
-#define XCHAL_DTLB_SET3_E1_VPN_CONST 0xF0000000
-/* Constant PPN values for each entry of DTLB way set 3 (because PPN_CONSTMASK is non-zero): */
-#define XCHAL_DTLB_SET3_E0_PPN_CONST 0xF0000000
-#define XCHAL_DTLB_SET3_E1_PPN_CONST 0xF0000000
-/* Constant CA values for each entry of DTLB way set 3 (because CA_CONSTMASK is non-zero): */
-#define XCHAL_DTLB_SET3_E0_CA_CONST 0x07
-#define XCHAL_DTLB_SET3_E1_CA_CONST 0x03
-
-/* DTLB way set 4 (group of ways 7 thru 9): */
-#define XCHAL_DTLB_SET4_WAY 7 /* index of first way in this way set */
-#define XCHAL_DTLB_SET4_WAYS 3 /* number of (contiguous) ways in this way set */
-#define XCHAL_DTLB_SET4_ENTRIES_LOG2 0 /* log2(number of entries in this way) */
-#define XCHAL_DTLB_SET4_ENTRIES 1 /* number of entries in this way (always a power of 2) */
-#define XCHAL_DTLB_SET4_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_DTLB_SET4_PAGESIZES 1 /* number of supported page sizes in this way */
-#define XCHAL_DTLB_SET4_PAGESZ_BITS 0 /* number of bits to encode the page size */
-#define XCHAL_DTLB_SET4_PAGESZ_LOG2_MIN 12 /* log2(minimum supported page size) */
-#define XCHAL_DTLB_SET4_PAGESZ_LOG2_MAX 12 /* log2(maximum supported page size) */
-#define XCHAL_DTLB_SET4_PAGESZ_LOG2_LIST 12 /* list of log2(page size)s, separated by XCHAL_SEP;
- 2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_DTLB_SET4_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */
-#define XCHAL_DTLB_SET4_VPN_CONSTMASK 0 /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET4_PPN_CONSTMASK 0 /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET4_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */
-#define XCHAL_DTLB_SET4_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET4_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET4_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET4_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
-
-/* Indexing macros: */
-#define _XCHAL_DTLB_SET(n,_what) XCHAL_DTLB_SET ## n ## _what
-#define XCHAL_DTLB_SET(n,what) _XCHAL_DTLB_SET(n, _ ## what )
-#define _XCHAL_DTLB_SET_E(n,i,_what) XCHAL_DTLB_SET ## n ## _E ## i ## _what
-#define XCHAL_DTLB_SET_E(n,i,what) _XCHAL_DTLB_SET_E(n,i, _ ## what )
-/*
- * Example use: XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,ENTRIES)
- * to get the value of XCHAL_DTLB_SET<n>_ENTRIES where <n> is the first auto-refill set.
- */
-
-
-/*
- * Determine whether we have a full MMU (with Page Table and Protection)
- * usable for an MMU-based OS:
- */
-#if XCHAL_HAVE_TLBS && !XCHAL_HAVE_SPANNING_WAY && XCHAL_ITLB_ARF_WAYS > 0 && XCHAL_DTLB_ARF_WAYS > 0 && XCHAL_MMU_RINGS >= 2
-# define XCHAL_HAVE_PTP_MMU 1 /* have full MMU (with page table [autorefill] and protection) */
-#else
-# define XCHAL_HAVE_PTP_MMU 0 /* don't have full MMU */
-#endif
-
-/*
- * For full MMUs, report kernel RAM segment and kernel I/O segment static page mappings:
- */
-#if XCHAL_HAVE_PTP_MMU
-#define XCHAL_KSEG_CACHED_VADDR 0xD0000000 /* virt.addr of kernel RAM cached static map */
-#define XCHAL_KSEG_CACHED_PADDR 0x00000000 /* phys.addr of kseg_cached */
-#define XCHAL_KSEG_CACHED_SIZE 0x08000000 /* size in bytes of kseg_cached (assumed power of 2!!!) */
-#define XCHAL_KSEG_BYPASS_VADDR 0xD8000000 /* virt.addr of kernel RAM bypass (uncached) static map */
-#define XCHAL_KSEG_BYPASS_PADDR 0x00000000 /* phys.addr of kseg_bypass */
-#define XCHAL_KSEG_BYPASS_SIZE 0x08000000 /* size in bytes of kseg_bypass (assumed power of 2!!!) */
-
-#define XCHAL_KIO_CACHED_VADDR 0xE0000000 /* virt.addr of kernel I/O cached static map */
-#define XCHAL_KIO_CACHED_PADDR 0xF0000000 /* phys.addr of kio_cached */
-#define XCHAL_KIO_CACHED_SIZE 0x10000000 /* size in bytes of kio_cached (assumed power of 2!!!) */
-#define XCHAL_KIO_BYPASS_VADDR 0xF0000000 /* virt.addr of kernel I/O bypass (uncached) static map */
-#define XCHAL_KIO_BYPASS_PADDR 0xF0000000 /* phys.addr of kio_bypass */
-#define XCHAL_KIO_BYPASS_SIZE 0x10000000 /* size in bytes of kio_bypass (assumed power of 2!!!) */
-
-#define XCHAL_SEG_MAPPABLE_VADDR 0x00000000 /* start of largest non-static-mapped virtual addr area */
-#define XCHAL_SEG_MAPPABLE_SIZE 0xD0000000 /* size in bytes of " */
-/* define XCHAL_SEG_MAPPABLE2_xxx if more areas present, sorted in order of descending size. */
-#endif
-
-
-/*----------------------------------------------------------------------
- MISC
- ----------------------------------------------------------------------*/
-
-#define XCHAL_NUM_WRITEBUFFER_ENTRIES 4 /* number of write buffer entries */
-
-#define XCHAL_CORE_ID "linux_be" /* configuration's alphanumeric core identifier
- (CoreID) set in the Xtensa Processor Generator */
-
-#define XCHAL_BUILD_UNIQUE_ID 0x00003256 /* software build-unique ID (22-bit) */
-
-/* These definitions describe the hardware targeted by this software: */
-#define XCHAL_HW_CONFIGID0 0xC103D1FF /* config ID reg 0 value (upper 32 of 64 bits) */
-#define XCHAL_HW_CONFIGID1 0x00803256 /* config ID reg 1 value (lower 32 of 64 bits) */
-#define XCHAL_CONFIGID0 XCHAL_HW_CONFIGID0 /* for backward compatibility only -- don't use! */
-#define XCHAL_CONFIGID1 XCHAL_HW_CONFIGID1 /* for backward compatibility only -- don't use! */
-#define XCHAL_HW_RELEASE_MAJOR 1050 /* major release of targeted hardware */
-#define XCHAL_HW_RELEASE_MINOR 1 /* minor release of targeted hardware */
-#define XCHAL_HW_RELEASE_NAME "T1050.1" /* full release name of targeted hardware */
-#define XTHAL_HW_REL_T1050 1
-#define XTHAL_HW_REL_T1050_1 1
-#define XCHAL_HW_CONFIGID_RELIABLE 1
-
-
-/*
- * Miscellaneous special register fields:
- */
-
-
-/* DBREAKC (special register number 160): */
-#define XCHAL_DBREAKC_VALIDMASK 0xC000003F /* bits of DBREAKC that are defined */
-/* MASK field: */
-#define XCHAL_DBREAKC_MASK_BITS 6 /* number of bits in MASK field */
-#define XCHAL_DBREAKC_MASK_NUM 64 /* max number of possible causes (2^bits) */
-#define XCHAL_DBREAKC_MASK_SHIFT 0 /* position of MASK bits in DBREAKC, starting from lsbit */
-#define XCHAL_DBREAKC_MASK_MASK 0x0000003F /* mask of bits in MASK field of DBREAKC */
-/* LOADBREAK field: */
-#define XCHAL_DBREAKC_LOADBREAK_BITS 1 /* number of bits in LOADBREAK field */
-#define XCHAL_DBREAKC_LOADBREAK_NUM 2 /* max number of possible causes (2^bits) */
-#define XCHAL_DBREAKC_LOADBREAK_SHIFT 30 /* position of LOADBREAK bits in DBREAKC, starting from lsbit */
-#define XCHAL_DBREAKC_LOADBREAK_MASK 0x40000000 /* mask of bits in LOADBREAK field of DBREAKC */
-/* STOREBREAK field: */
-#define XCHAL_DBREAKC_STOREBREAK_BITS 1 /* number of bits in STOREBREAK field */
-#define XCHAL_DBREAKC_STOREBREAK_NUM 2 /* max number of possible causes (2^bits) */
-#define XCHAL_DBREAKC_STOREBREAK_SHIFT 31 /* position of STOREBREAK bits in DBREAKC, starting from lsbit */
-#define XCHAL_DBREAKC_STOREBREAK_MASK 0x80000000 /* mask of bits in STOREBREAK field of DBREAKC */
-
-/* PS (special register number 230): */
-#define XCHAL_PS_VALIDMASK 0x00070FFF /* bits of PS that are defined */
-/* INTLEVEL field: */
-#define XCHAL_PS_INTLEVEL_BITS 4 /* number of bits in INTLEVEL field */
-#define XCHAL_PS_INTLEVEL_NUM 16 /* max number of possible causes (2^bits) */
-#define XCHAL_PS_INTLEVEL_SHIFT 0 /* position of INTLEVEL bits in PS, starting from lsbit */
-#define XCHAL_PS_INTLEVEL_MASK 0x0000000F /* mask of bits in INTLEVEL field of PS */
-/* EXCM field: */
-#define XCHAL_PS_EXCM_BITS 1 /* number of bits in EXCM field */
-#define XCHAL_PS_EXCM_NUM 2 /* max number of possible causes (2^bits) */
-#define XCHAL_PS_EXCM_SHIFT 4 /* position of EXCM bits in PS, starting from lsbit */
-#define XCHAL_PS_EXCM_MASK 0x00000010 /* mask of bits in EXCM field of PS */
-/* PROGSTACK field: */
-#define XCHAL_PS_PROGSTACK_BITS 1 /* number of bits in PROGSTACK field */
-#define XCHAL_PS_PROGSTACK_NUM 2 /* max number of possible causes (2^bits) */
-#define XCHAL_PS_PROGSTACK_SHIFT 5 /* position of PROGSTACK bits in PS, starting from lsbit */
-#define XCHAL_PS_PROGSTACK_MASK 0x00000020 /* mask of bits in PROGSTACK field of PS */
-/* RING field: */
-#define XCHAL_PS_RING_BITS 2 /* number of bits in RING field */
-#define XCHAL_PS_RING_NUM 4 /* max number of possible causes (2^bits) */
-#define XCHAL_PS_RING_SHIFT 6 /* position of RING bits in PS, starting from lsbit */
-#define XCHAL_PS_RING_MASK 0x000000C0 /* mask of bits in RING field of PS */
-/* OWB field: */
-#define XCHAL_PS_OWB_BITS 4 /* number of bits in OWB field */
-#define XCHAL_PS_OWB_NUM 16 /* max number of possible causes (2^bits) */
-#define XCHAL_PS_OWB_SHIFT 8 /* position of OWB bits in PS, starting from lsbit */
-#define XCHAL_PS_OWB_MASK 0x00000F00 /* mask of bits in OWB field of PS */
-/* CALLINC field: */
-#define XCHAL_PS_CALLINC_BITS 2 /* number of bits in CALLINC field */
-#define XCHAL_PS_CALLINC_NUM 4 /* max number of possible causes (2^bits) */
-#define XCHAL_PS_CALLINC_SHIFT 16 /* position of CALLINC bits in PS, starting from lsbit */
-#define XCHAL_PS_CALLINC_MASK 0x00030000 /* mask of bits in CALLINC field of PS */
-/* WOE field: */
-#define XCHAL_PS_WOE_BITS 1 /* number of bits in WOE field */
-#define XCHAL_PS_WOE_NUM 2 /* max number of possible causes (2^bits) */
-#define XCHAL_PS_WOE_SHIFT 18 /* position of WOE bits in PS, starting from lsbit */
-#define XCHAL_PS_WOE_MASK 0x00040000 /* mask of bits in WOE field of PS */
-
-/* EXCCAUSE (special register number 232): */
-#define XCHAL_EXCCAUSE_VALIDMASK 0x0000003F /* bits of EXCCAUSE that are defined */
-/* EXCCAUSE field: */
-#define XCHAL_EXCCAUSE_BITS 6 /* number of bits in EXCCAUSE register */
-#define XCHAL_EXCCAUSE_NUM 64 /* max number of possible causes (2^bits) */
-#define XCHAL_EXCCAUSE_SHIFT 0 /* position of EXCCAUSE bits in register, starting from lsbit */
-#define XCHAL_EXCCAUSE_MASK 0x0000003F /* mask of bits in EXCCAUSE register */
-
-/* DEBUGCAUSE (special register number 233): */
-#define XCHAL_DEBUGCAUSE_VALIDMASK 0x0000003F /* bits of DEBUGCAUSE that are defined */
-/* ICOUNT field: */
-#define XCHAL_DEBUGCAUSE_ICOUNT_BITS 1 /* number of bits in ICOUNT field */
-#define XCHAL_DEBUGCAUSE_ICOUNT_NUM 2 /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_ICOUNT_SHIFT 0 /* position of ICOUNT bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_ICOUNT_MASK 0x00000001 /* mask of bits in ICOUNT field of DEBUGCAUSE */
-/* IBREAK field: */
-#define XCHAL_DEBUGCAUSE_IBREAK_BITS 1 /* number of bits in IBREAK field */
-#define XCHAL_DEBUGCAUSE_IBREAK_NUM 2 /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_IBREAK_SHIFT 1 /* position of IBREAK bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_IBREAK_MASK 0x00000002 /* mask of bits in IBREAK field of DEBUGCAUSE */
-/* DBREAK field: */
-#define XCHAL_DEBUGCAUSE_DBREAK_BITS 1 /* number of bits in DBREAK field */
-#define XCHAL_DEBUGCAUSE_DBREAK_NUM 2 /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_DBREAK_SHIFT 2 /* position of DBREAK bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_DBREAK_MASK 0x00000004 /* mask of bits in DBREAK field of DEBUGCAUSE */
-/* BREAK field: */
-#define XCHAL_DEBUGCAUSE_BREAK_BITS 1 /* number of bits in BREAK field */
-#define XCHAL_DEBUGCAUSE_BREAK_NUM 2 /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_BREAK_SHIFT 3 /* position of BREAK bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_BREAK_MASK 0x00000008 /* mask of bits in BREAK field of DEBUGCAUSE */
-/* BREAKN field: */
-#define XCHAL_DEBUGCAUSE_BREAKN_BITS 1 /* number of bits in BREAKN field */
-#define XCHAL_DEBUGCAUSE_BREAKN_NUM 2 /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_BREAKN_SHIFT 4 /* position of BREAKN bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_BREAKN_MASK 0x00000010 /* mask of bits in BREAKN field of DEBUGCAUSE */
-/* DEBUGINT field: */
-#define XCHAL_DEBUGCAUSE_DEBUGINT_BITS 1 /* number of bits in DEBUGINT field */
-#define XCHAL_DEBUGCAUSE_DEBUGINT_NUM 2 /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_DEBUGINT_SHIFT 5 /* position of DEBUGINT bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_DEBUGINT_MASK 0x00000020 /* mask of bits in DEBUGINT field of DEBUGCAUSE */
-
-
-
-/*----------------------------------------------------------------------
- ISA
- ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_DENSITY 1 /* 1 if density option configured, 0 otherwise */
-#define XCHAL_HAVE_LOOPS 1 /* 1 if zero-overhead loops option configured, 0 otherwise */
-/* Misc instructions: */
-#define XCHAL_HAVE_NSA 0 /* 1 if NSA/NSAU instructions option configured, 0 otherwise */
-#define XCHAL_HAVE_MINMAX 0 /* 1 if MIN/MAX instructions option configured, 0 otherwise */
-#define XCHAL_HAVE_SEXT 0 /* 1 if sign-extend instruction option configured, 0 otherwise */
-#define XCHAL_HAVE_CLAMPS 0 /* 1 if CLAMPS instruction option configured, 0 otherwise */
-#define XCHAL_HAVE_MAC16 0 /* 1 if MAC16 option configured, 0 otherwise */
-#define XCHAL_HAVE_MUL16 0 /* 1 if 16-bit integer multiply option configured, 0 otherwise */
-/*#define XCHAL_HAVE_POPC 0*/ /* 1 if CRC instruction option configured, 0 otherwise */
-/*#define XCHAL_HAVE_CRC 0*/ /* 1 if POPC instruction option configured, 0 otherwise */
-
-#define XCHAL_HAVE_SPECULATION 0 /* 1 if speculation option configured, 0 otherwise */
-/*#define XCHAL_HAVE_MP_SYNC 0*/ /* 1 if multiprocessor sync. option configured, 0 otherwise */
-#define XCHAL_HAVE_PRID 0 /* 1 if processor ID register configured, 0 otherwise */
-
-#define XCHAL_NUM_MISC_REGS 2 /* number of miscellaneous registers (0..4) */
-
-/* These relate a bit more to TIE: */
-#define XCHAL_HAVE_BOOLEANS 0 /* 1 if booleans option configured, 0 otherwise */
-#define XCHAL_HAVE_MUL32 0 /* 1 if 32-bit integer multiply option configured, 0 otherwise */
-#define XCHAL_HAVE_MUL32_HIGH 0 /* 1 if MUL32 option includes MULUH and MULSH, 0 otherwise */
-#define XCHAL_HAVE_FP 0 /* 1 if floating point option configured, 0 otherwise */
-
-
-/*----------------------------------------------------------------------
- DERIVED
- ----------------------------------------------------------------------*/
-
-#if XCHAL_HAVE_BE
-#define XCHAL_INST_ILLN 0xD60F /* 2-byte illegal instruction, msb-first */
-#define XCHAL_INST_ILLN_BYTE0 0xD6 /* 2-byte illegal instruction, 1st byte */
-#define XCHAL_INST_ILLN_BYTE1 0x0F /* 2-byte illegal instruction, 2nd byte */
-#else
-#define XCHAL_INST_ILLN 0xF06D /* 2-byte illegal instruction, lsb-first */
-#define XCHAL_INST_ILLN_BYTE0 0x6D /* 2-byte illegal instruction, 1st byte */
-#define XCHAL_INST_ILLN_BYTE1 0xF0 /* 2-byte illegal instruction, 2nd byte */
-#endif
-/* Belongs in xtensa/hal.h: */
-#define XTHAL_INST_ILL 0x000000 /* 3-byte illegal instruction */
-
-
-/*
- * Because information as to exactly which hardware release is targeted
- * by a given software build is not always available, compile-time HAL
- * Hardware-Release "_AT" macros are fuzzy (return 0, 1, or XCHAL_MAYBE):
- */
-#ifndef XCHAL_HW_RELEASE_MAJOR
-# define XCHAL_HW_CONFIGID_RELIABLE 0
-#endif
-#if XCHAL_HW_CONFIGID_RELIABLE
-# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor) (XTHAL_REL_LE( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
-# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor) (XTHAL_REL_GE( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
-# define XCHAL_HW_RELEASE_AT(major,minor) (XTHAL_REL_EQ( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
-# define XCHAL_HW_RELEASE_MAJOR_AT(major) ((XCHAL_HW_RELEASE_MAJOR == (major)) ? 1 : 0)
-#else
-# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor) ( ((major) < 1040 && XCHAL_HAVE_XEA2) ? 0 \
- : ((major) > 1050 && XCHAL_HAVE_XEA1) ? 1 \
- : XTHAL_MAYBE )
-# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor) ( ((major) >= 2000 && XCHAL_HAVE_XEA1) ? 0 \
- : (XTHAL_REL_LE(major,minor, 1040,0) && XCHAL_HAVE_XEA2) ? 1 \
- : XTHAL_MAYBE )
-# define XCHAL_HW_RELEASE_AT(major,minor) ( (((major) < 1040 && XCHAL_HAVE_XEA2) || \
- ((major) >= 2000 && XCHAL_HAVE_XEA1)) ? 0 : XTHAL_MAYBE)
-# define XCHAL_HW_RELEASE_MAJOR_AT(major) XCHAL_HW_RELEASE_AT(major,0)
-#endif
-
-/*
- * Specific errata:
- */
-
-/*
- * Erratum T1020.H13, T1030.H7, T1040.H10, T1050.H4 (fixed in T1040.3 and T1050.1;
- * relevant only in XEA1, kernel-vector mode, level-one interrupts and overflows enabled):
- */
-#define XCHAL_MAYHAVE_ERRATUM_XEA1KWIN (XCHAL_HAVE_XEA1 && \
- (XCHAL_HW_RELEASE_AT_OR_BELOW(1040,2) != 0 \
- || XCHAL_HW_RELEASE_AT(1050,0)))
-
-
-
-#endif /*XTENSA_CONFIG_CORE_H*/
-
diff --git a/include/asm-xtensa/xtensa/config-linux_be/defs.h b/include/asm-xtensa/xtensa/config-linux_be/defs.h
deleted file mode 100644
index f7c58b27337..00000000000
--- a/include/asm-xtensa/xtensa/config-linux_be/defs.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/* Definitions for Xtensa instructions, types, and protos. */
-
-/*
- * Copyright (c) 2003 Tensilica, Inc. All Rights Reserved.
- *
- * 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 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- */
-
-/* Do not modify. This is automatically generated.*/
-
-#ifndef _XTENSA_BASE_HEADER
-#define _XTENSA_BASE_HEADER
-
-#ifdef __XTENSA__
-#if defined(__GNUC__) && !defined(__XCC__)
-
-#define L8UI_ASM(arr, ars, imm) { \
- __asm__ volatile("l8ui %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
-}
-
-#define XT_L8UI(ars, imm) \
-({ \
- unsigned char _arr; \
- const unsigned char *_ars = ars; \
- L8UI_ASM(_arr, _ars, imm); \
- _arr; \
-})
-
-#define L16UI_ASM(arr, ars, imm) { \
- __asm__ volatile("l16ui %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
-}
-
-#define XT_L16UI(ars, imm) \
-({ \
- unsigned short _arr; \
- const unsigned short *_ars = ars; \
- L16UI_ASM(_arr, _ars, imm); \
- _arr; \
-})
-
-#define L16SI_ASM(arr, ars, imm) {\
- __asm__ volatile("l16si %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
-}
-
-#define XT_L16SI(ars, imm) \
-({ \
- signed short _arr; \
- const signed short *_ars = ars; \
- L16SI_ASM(_arr, _ars, imm); \
- _arr; \
-})
-
-#define L32I_ASM(arr, ars, imm) { \
- __asm__ volatile("l32i %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
-}
-
-#define XT_L32I(ars, imm) \
-({ \
- unsigned _arr; \
- const unsigned *_ars = ars; \
- L32I_ASM(_arr, _ars, imm); \
- _arr; \
-})
-
-#define S8I_ASM(arr, ars, imm) {\
- __asm__ volatile("s8i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
-}
-
-#define XT_S8I(arr, ars, imm) \
-({ \
- signed char _arr = arr; \
- const signed char *_ars = ars; \
- S8I_ASM(_arr, _ars, imm); \
-})
-
-#define S16I_ASM(arr, ars, imm) {\
- __asm__ volatile("s16i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
-}
-
-#define XT_S16I(arr, ars, imm) \
-({ \
- signed short _arr = arr; \
- const signed short *_ars = ars; \
- S16I_ASM(_arr, _ars, imm); \
-})
-
-#define S32I_ASM(arr, ars, imm) { \
- __asm__ volatile("s32i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
-}
-
-#define XT_S32I(arr, ars, imm) \
-({ \
- signed int _arr = arr; \
- const signed int *_ars = ars; \
- S32I_ASM(_arr, _ars, imm); \
-})
-
-#define ADDI_ASM(art, ars, imm) {\
- __asm__ ("addi %0, %1, %2" : "=a" (art) : "a" (ars), "i" (imm)); \
-}
-
-#define XT_ADDI(ars, imm) \
-({ \
- unsigned _art; \
- unsigned _ars = ars; \
- ADDI_ASM(_art, _ars, imm); \
- _art; \
-})
-
-#define ABS_ASM(arr, art) {\
- __asm__ ("abs %0, %1" : "=a" (arr) : "a" (art)); \
-}
-
-#define XT_ABS(art) \
-({ \
- unsigned _arr; \
- signed _art = art; \
- ABS_ASM(_arr, _art); \
- _arr; \
-})
-
-/* Note: In the following macros that reference SAR, the magic "state"
- register is used to capture the dependency on SAR. This is because
- SAR is a 5-bit register and thus there are no C types that can be
- used to represent it. It doesn't appear that the SAR register is
- even relevant to GCC, but it is marked as "clobbered" just in
- case. */
-
-#define SRC_ASM(arr, ars, art) {\
- register int _xt_sar __asm__ ("state"); \
- __asm__ ("src %0, %1, %2" \
- : "=a" (arr) : "a" (ars), "a" (art), "t" (_xt_sar)); \
-}
-
-#define XT_SRC(ars, art) \
-({ \
- unsigned _arr; \
- unsigned _ars = ars; \
- unsigned _art = art; \
- SRC_ASM(_arr, _ars, _art); \
- _arr; \
-})
-
-#define SSR_ASM(ars) {\
- register int _xt_sar __asm__ ("state"); \
- __asm__ ("ssr %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
-}
-
-#define XT_SSR(ars) \
-({ \
- unsigned _ars = ars; \
- SSR_ASM(_ars); \
-})
-
-#define SSL_ASM(ars) {\
- register int _xt_sar __asm__ ("state"); \
- __asm__ ("ssl %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
-}
-
-#define XT_SSL(ars) \
-({ \
- unsigned _ars = ars; \
- SSL_ASM(_ars); \
-})
-
-#define SSA8B_ASM(ars) {\
- register int _xt_sar __asm__ ("state"); \
- __asm__ ("ssa8b %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
-}
-
-#define XT_SSA8B(ars) \
-({ \
- unsigned _ars = ars; \
- SSA8B_ASM(_ars); \
-})
-
-#define SSA8L_ASM(ars) {\
- register int _xt_sar __asm__ ("state"); \
- __asm__ ("ssa8l %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
-}
-
-#define XT_SSA8L(ars) \
-({ \
- unsigned _ars = ars; \
- SSA8L_ASM(_ars); \
-})
-
-#define SSAI_ASM(imm) {\
- register int _xt_sar __asm__ ("state"); \
- __asm__ ("ssai %1" : "=t" (_xt_sar) : "i" (imm) : "sar"); \
-}
-
-#define XT_SSAI(imm) \
-({ \
- SSAI_ASM(imm); \
-})
-
-
-
-
-
-
-
-
-#endif /* __GNUC__ && !__XCC__ */
-
-#ifdef __XCC__
-
-/* Core load/store instructions */
-extern unsigned char _TIE_L8UI(const unsigned char * ars, immediate imm);
-extern unsigned short _TIE_L16UI(const unsigned short * ars, immediate imm);
-extern signed short _TIE_L16SI(const signed short * ars, immediate imm);
-extern unsigned _TIE_L32I(const unsigned * ars, immediate imm);
-extern void _TIE_S8I(unsigned char arr, unsigned char * ars, immediate imm);
-extern void _TIE_S16I(unsigned short arr, unsigned short * ars, immediate imm);
-extern void _TIE_S32I(unsigned arr, unsigned * ars, immediate imm);
-
-#define XT_L8UI _TIE_L8UI
-#define XT_L16UI _TIE_L16UI
-#define XT_L16SI _TIE_L16SI
-#define XT_L32I _TIE_L32I
-#define XT_S8I _TIE_S8I
-#define XT_S16I _TIE_S16I
-#define XT_S32I _TIE_S32I
-
-/* Add-immediate instruction */
-extern unsigned _TIE_ADDI(unsigned ars, immediate imm);
-#define XT_ADDI _TIE_ADDI
-
-/* Absolute value instruction */
-extern unsigned _TIE_ABS(int art);
-#define XT_ABS _TIE_ABS
-
-/* funnel shift instructions */
-extern unsigned _TIE_SRC(unsigned ars, unsigned art);
-#define XT_SRC _TIE_SRC
-extern void _TIE_SSR(unsigned ars);
-#define XT_SSR _TIE_SSR
-extern void _TIE_SSL(unsigned ars);
-#define XT_SSL _TIE_SSL
-extern void _TIE_SSA8B(unsigned ars);
-#define XT_SSA8B _TIE_SSA8B
-extern void _TIE_SSA8L(unsigned ars);
-#define XT_SSA8L _TIE_SSA8L
-extern void _TIE_SSAI(immediate imm);
-#define XT_SSAI _TIE_SSAI
-
-
-#endif /* __XCC__ */
-
-#endif /* __XTENSA__ */
-#endif /* !_XTENSA_BASE_HEADER */
diff --git a/include/asm-xtensa/xtensa/config-linux_be/specreg.h b/include/asm-xtensa/xtensa/config-linux_be/specreg.h
deleted file mode 100644
index fa4106aa9a0..00000000000
--- a/include/asm-xtensa/xtensa/config-linux_be/specreg.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Xtensa Special Register symbolic names
- */
-
-/* $Id: specreg.h,v 1.2 2003/03/07 19:15:18 joetaylor Exp $ */
-
-/*
- * Copyright (c) 2003 Tensilica, Inc. All Rights Reserved.
- *
- * 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 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- */
-
-#ifndef XTENSA_SPECREG_H
-#define XTENSA_SPECREG_H
-
-/* Include these special register bitfield definitions, for historical reasons: */
-#include <xtensa/corebits.h>
-
-
-/* Special registers: */
-#define LBEG 0
-#define LEND 1
-#define LCOUNT 2
-#define SAR 3
-#define WINDOWBASE 72
-#define WINDOWSTART 73
-#define PTEVADDR 83
-#define RASID 90
-#define ITLBCFG 91
-#define DTLBCFG 92
-#define IBREAKENABLE 96
-#define DDR 104
-#define IBREAKA_0 128
-#define IBREAKA_1 129
-#define DBREAKA_0 144
-#define DBREAKA_1 145
-#define DBREAKC_0 160
-#define DBREAKC_1 161
-#define EPC_1 177
-#define EPC_2 178
-#define EPC_3 179
-#define EPC_4 180
-#define DEPC 192
-#define EPS_2 194
-#define EPS_3 195
-#define EPS_4 196
-#define EXCSAVE_1 209
-#define EXCSAVE_2 210
-#define EXCSAVE_3 211
-#define EXCSAVE_4 212
-#define INTERRUPT 226
-#define INTENABLE 228
-#define PS 230
-#define EXCCAUSE 232
-#define DEBUGCAUSE 233
-#define CCOUNT 234
-#define ICOUNT 236
-#define ICOUNTLEVEL 237
-#define EXCVADDR 238
-#define CCOMPARE_0 240
-#define CCOMPARE_1 241
-#define CCOMPARE_2 242
-#define MISC_REG_0 244
-#define MISC_REG_1 245
-
-/* Special cases (bases of special register series): */
-#define IBREAKA 128
-#define DBREAKA 144
-#define DBREAKC 160
-#define EPC 176
-#define EPS 192
-#define EXCSAVE 208
-#define CCOMPARE 240
-
-/* Special names for read-only and write-only interrupt registers: */
-#define INTREAD 226
-#define INTSET 226
-#define INTCLEAR 227
-
-#endif /* XTENSA_SPECREG_H */
-
diff --git a/include/asm-xtensa/xtensa/config-linux_be/system.h b/include/asm-xtensa/xtensa/config-linux_be/system.h
deleted file mode 100644
index cf9d4d308e3..00000000000
--- a/include/asm-xtensa/xtensa/config-linux_be/system.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * xtensa/config/system.h -- HAL definitions that are dependent on SYSTEM configuration
- *
- * NOTE: The location and contents of this file are highly subject to change.
- *
- * Source for configuration-independent binaries (which link in a
- * configuration-specific HAL library) must NEVER include this file.
- * The HAL itself has historically included this file in some instances,
- * but this is not appropriate either, because the HAL is meant to be
- * core-specific but system independent.
- */
-
-/*
- * Copyright (c) 2003 Tensilica, Inc. All Rights Reserved.
- *
- * 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 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- */
-
-
-#ifndef XTENSA_CONFIG_SYSTEM_H
-#define XTENSA_CONFIG_SYSTEM_H
-
-/*#include <xtensa/hal.h>*/
-
-
-
-/*----------------------------------------------------------------------
- DEVICE ADDRESSES
- ----------------------------------------------------------------------*/
-
-/*
- * Strange place to find these, but the configuration GUI
- * allows moving these around to account for various core
- * configurations. Specific boards (and their BSP software)
- * will have specific meanings for these components.
- */
-
-/* I/O Block areas: */
-#define XSHAL_IOBLOCK_CACHED_VADDR 0xE0000000
-#define XSHAL_IOBLOCK_CACHED_PADDR 0xF0000000
-#define XSHAL_IOBLOCK_CACHED_SIZE 0x0E000000
-
-#define XSHAL_IOBLOCK_BYPASS_VADDR 0xF0000000
-#define XSHAL_IOBLOCK_BYPASS_PADDR 0xF0000000
-#define XSHAL_IOBLOCK_BYPASS_SIZE 0x0E000000
-
-/* System ROM: */
-#define XSHAL_ROM_VADDR 0xEE000000
-#define XSHAL_ROM_PADDR 0xFE000000
-#define XSHAL_ROM_SIZE 0x00400000
-/* Largest available area (free of vectors): */
-#define XSHAL_ROM_AVAIL_VADDR 0xEE00052C
-#define XSHAL_ROM_AVAIL_VSIZE 0x003FFAD4
-
-/* System RAM: */
-#define XSHAL_RAM_VADDR 0xD0000000
-#define XSHAL_RAM_PADDR 0x00000000
-#define XSHAL_RAM_VSIZE 0x08000000
-#define XSHAL_RAM_PSIZE 0x10000000
-#define XSHAL_RAM_SIZE XSHAL_RAM_PSIZE
-/* Largest available area (free of vectors): */
-#define XSHAL_RAM_AVAIL_VADDR 0xD0000370
-#define XSHAL_RAM_AVAIL_VSIZE 0x07FFFC90
-
-/*
- * Shadow system RAM (same device as system RAM, at different address).
- * (Emulation boards need this for the SONIC Ethernet driver
- * when data caches are configured for writeback mode.)
- * NOTE: on full MMU configs, this points to the BYPASS virtual address
- * of system RAM, ie. is the same as XSHAL_RAM_* except that virtual
- * addresses are viewed through the BYPASS static map rather than
- * the CACHED static map.
- */
-#define XSHAL_RAM_BYPASS_VADDR 0xD8000000
-#define XSHAL_RAM_BYPASS_PADDR 0x00000000
-#define XSHAL_RAM_BYPASS_PSIZE 0x08000000
-
-/* Alternate system RAM (different device than system RAM): */
-#define XSHAL_ALTRAM_VADDR 0xCEE00000
-#define XSHAL_ALTRAM_PADDR 0xC0000000
-#define XSHAL_ALTRAM_SIZE 0x00200000
-
-
-/*----------------------------------------------------------------------
- * DEVICE-ADDRESS DEPENDENT...
- *
- * Values written to CACHEATTR special register (or its equivalent)
- * to enable and disable caches in various modes.
- *----------------------------------------------------------------------*/
-
-/*----------------------------------------------------------------------
- BACKWARD COMPATIBILITY ...
- ----------------------------------------------------------------------*/
-
-/*
- * NOTE: the following two macros are DEPRECATED. Use the latter
- * board-specific macros instead, which are specially tuned for the
- * particular target environments' memory maps.
- */
-#define XSHAL_CACHEATTR_BYPASS XSHAL_XT2000_CACHEATTR_BYPASS /* disable caches in bypass mode */
-#define XSHAL_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_DEFAULT /* default setting to enable caches (no writeback!) */
-
-/*----------------------------------------------------------------------
- ISS (Instruction Set Simulator) SPECIFIC ...
- ----------------------------------------------------------------------*/
-
-#define XSHAL_ISS_CACHEATTR_WRITEBACK 0x1122222F /* enable caches in write-back mode */
-#define XSHAL_ISS_CACHEATTR_WRITEALLOC 0x1122222F /* enable caches in write-allocate mode */
-#define XSHAL_ISS_CACHEATTR_WRITETHRU 0x1122222F /* enable caches in write-through mode */
-#define XSHAL_ISS_CACHEATTR_BYPASS 0x2222222F /* disable caches in bypass mode */
-#define XSHAL_ISS_CACHEATTR_DEFAULT XSHAL_ISS_CACHEATTR_WRITEBACK /* default setting to enable caches */
-
-/* For Coware only: */
-#define XSHAL_COWARE_CACHEATTR_WRITEBACK 0x11222222 /* enable caches in write-back mode */
-#define XSHAL_COWARE_CACHEATTR_WRITEALLOC 0x11222222 /* enable caches in write-allocate mode */
-#define XSHAL_COWARE_CACHEATTR_WRITETHRU 0x11222222 /* enable caches in write-through mode */
-#define XSHAL_COWARE_CACHEATTR_BYPASS 0x22222222 /* disable caches in bypass mode */
-#define XSHAL_COWARE_CACHEATTR_DEFAULT XSHAL_COWARE_CACHEATTR_WRITEBACK /* default setting to enable caches */
-
-/* For BFM and other purposes: */
-#define XSHAL_ALLVALID_CACHEATTR_WRITEBACK 0x11222222 /* enable caches without any invalid regions */
-#define XSHAL_ALLVALID_CACHEATTR_DEFAULT XSHAL_ALLVALID_CACHEATTR_WRITEBACK /* default setting for caches without any invalid regions */
-
-#define XSHAL_ISS_PIPE_REGIONS 0
-#define XSHAL_ISS_SDRAM_REGIONS 0
-
-
-/*----------------------------------------------------------------------
- XT2000 BOARD SPECIFIC ...
- ----------------------------------------------------------------------*/
-
-#define XSHAL_XT2000_CACHEATTR_WRITEBACK 0x22FFFFFF /* enable caches in write-back mode */
-#define XSHAL_XT2000_CACHEATTR_WRITEALLOC 0x22FFFFFF /* enable caches in write-allocate mode */
-#define XSHAL_XT2000_CACHEATTR_WRITETHRU 0x22FFFFFF /* enable caches in write-through mode */
-#define XSHAL_XT2000_CACHEATTR_BYPASS 0x22FFFFFF /* disable caches in bypass mode */
-#define XSHAL_XT2000_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_WRITEBACK /* default setting to enable caches */
-
-#define XSHAL_XT2000_PIPE_REGIONS 0x00001000 /* BusInt pipeline regions */
-#define XSHAL_XT2000_SDRAM_REGIONS 0x00000005 /* BusInt SDRAM regions */
-
-
-/*----------------------------------------------------------------------
- VECTOR SIZES
- ----------------------------------------------------------------------*/
-
-/*
- * Sizes allocated to vectors by the system (memory map) configuration.
- * These sizes are constrained by core configuration (eg. one vector's
- * code cannot overflow into another vector) but are dependent on the
- * system or board (or LSP) memory map configuration.
- *
- * Whether or not each vector happens to be in a system ROM is also
- * a system configuration matter, sometimes useful, included here also:
- */
-#define XSHAL_RESET_VECTOR_SIZE 0x000004E0
-#define XSHAL_RESET_VECTOR_ISROM 1
-#define XSHAL_USER_VECTOR_SIZE 0x0000001C
-#define XSHAL_USER_VECTOR_ISROM 0
-#define XSHAL_PROGRAMEXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE /* for backward compatibility */
-#define XSHAL_USEREXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE /* for backward compatibility */
-#define XSHAL_KERNEL_VECTOR_SIZE 0x0000001C
-#define XSHAL_KERNEL_VECTOR_ISROM 0
-#define XSHAL_STACKEDEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE /* for backward compatibility */
-#define XSHAL_KERNELEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE /* for backward compatibility */
-#define XSHAL_DOUBLEEXC_VECTOR_SIZE 0x000000E0
-#define XSHAL_DOUBLEEXC_VECTOR_ISROM 0
-#define XSHAL_WINDOW_VECTORS_SIZE 0x00000180
-#define XSHAL_WINDOW_VECTORS_ISROM 0
-#define XSHAL_INTLEVEL2_VECTOR_SIZE 0x0000000C
-#define XSHAL_INTLEVEL2_VECTOR_ISROM 0
-#define XSHAL_INTLEVEL3_VECTOR_SIZE 0x0000000C
-#define XSHAL_INTLEVEL3_VECTOR_ISROM 0
-#define XSHAL_INTLEVEL4_VECTOR_SIZE 0x0000000C
-#define XSHAL_INTLEVEL4_VECTOR_ISROM 1
-#define XSHAL_DEBUG_VECTOR_SIZE XSHAL_INTLEVEL4_VECTOR_SIZE
-#define XSHAL_DEBUG_VECTOR_ISROM XSHAL_INTLEVEL4_VECTOR_ISROM
-
-
-#endif /*XTENSA_CONFIG_SYSTEM_H*/
-
diff --git a/include/asm-xtensa/xtensa/config-linux_be/tie.h b/include/asm-xtensa/xtensa/config-linux_be/tie.h
deleted file mode 100644
index 3c2e514602f..00000000000
--- a/include/asm-xtensa/xtensa/config-linux_be/tie.h
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * xtensa/config/tie.h -- HAL definitions that are dependent on CORE and TIE configuration
- *
- * This header file is sometimes referred to as the "compile-time HAL" or CHAL.
- * It was generated for a specific Xtensa processor configuration,
- * and furthermore for a specific set of TIE source files that extend
- * basic core functionality.
- *
- * Source for configuration-independent binaries (which link in a
- * configuration-specific HAL library) must NEVER include this file.
- * It is perfectly normal, however, for the HAL source itself to include this file.
- */
-
-/*
- * Copyright (c) 2003 Tensilica, Inc. All Rights Reserved.
- *
- * 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 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- */
-
-
-#ifndef XTENSA_CONFIG_TIE_H
-#define XTENSA_CONFIG_TIE_H
-
-#include <xtensa/hal.h>
-
-
-/*----------------------------------------------------------------------
- GENERAL
- ----------------------------------------------------------------------*/
-
-/*
- * Separators for macros that expand into arrays.
- * These can be predefined by files that #include this one,
- * when different separators are required.
- */
-/* Element separator for macros that expand into 1-dimensional arrays: */
-#ifndef XCHAL_SEP
-#define XCHAL_SEP ,
-#endif
-/* Array separator for macros that expand into 2-dimensional arrays: */
-#ifndef XCHAL_SEP2
-#define XCHAL_SEP2 },{
-#endif
-
-
-
-
-
-
-/*----------------------------------------------------------------------
- COPROCESSORS and EXTRA STATE
- ----------------------------------------------------------------------*/
-
-#define XCHAL_CP_NUM 0 /* number of coprocessors */
-#define XCHAL_CP_MAX 0 /* max coprocessor id plus one (0 if none) */
-#define XCHAL_CP_MASK 0x00 /* bitmask of coprocessors by id */
-
-/* Space for coprocessors' state save areas: */
-#define XCHAL_CP0_SA_SIZE 0
-#define XCHAL_CP1_SA_SIZE 0
-#define XCHAL_CP2_SA_SIZE 0
-#define XCHAL_CP3_SA_SIZE 0
-#define XCHAL_CP4_SA_SIZE 0
-#define XCHAL_CP5_SA_SIZE 0
-#define XCHAL_CP6_SA_SIZE 0
-#define XCHAL_CP7_SA_SIZE 0
-/* Minimum required alignments of CP state save areas: */
-#define XCHAL_CP0_SA_ALIGN 1
-#define XCHAL_CP1_SA_ALIGN 1
-#define XCHAL_CP2_SA_ALIGN 1
-#define XCHAL_CP3_SA_ALIGN 1
-#define XCHAL_CP4_SA_ALIGN 1
-#define XCHAL_CP5_SA_ALIGN 1
-#define XCHAL_CP6_SA_ALIGN 1
-#define XCHAL_CP7_SA_ALIGN 1
-
-/* Indexing macros: */
-#define _XCHAL_CP_SA_SIZE(n) XCHAL_CP ## n ## _SA_SIZE
-#define XCHAL_CP_SA_SIZE(n) _XCHAL_CP_SA_SIZE(n) /* n = 0 .. 7 */
-#define _XCHAL_CP_SA_ALIGN(n) XCHAL_CP ## n ## _SA_ALIGN
-#define XCHAL_CP_SA_ALIGN(n) _XCHAL_CP_SA_ALIGN(n) /* n = 0 .. 7 */
-
-
-/* Space for "extra" state (user special registers and non-cp TIE) save area: */
-#define XCHAL_EXTRA_SA_SIZE 0
-#define XCHAL_EXTRA_SA_ALIGN 1
-
-/* Total save area size (extra + all coprocessors) */
-/* (not useful until xthal_{save,restore}_all_extra() is implemented, */
-/* but included for Tor2 beta; doesn't account for alignment!): */
-#define XCHAL_CPEXTRA_SA_SIZE_TOR2 0 /* Tor2Beta temporary definition -- do not use */
-
-/* Combined required alignment for all CP and EXTRA state save areas */
-/* (does not include required alignment for any base config registers): */
-#define XCHAL_CPEXTRA_SA_ALIGN 1
-
-/* ... */
-
-
-#ifdef _ASMLANGUAGE
-/*
- * Assembly-language specific definitions (assembly macros, etc.).
- */
-#include <xtensa/config/specreg.h>
-
-/********************
- * Macros to save and restore the non-coprocessor TIE portion of EXTRA state.
- */
-
-/* (none) */
-
-
-/********************
- * Macros to create functions that save and restore all EXTRA (non-coprocessor) state
- * (does not include zero-overhead loop registers and non-optional registers).
- */
-
- /*
- * Macro that expands to the body of a function that
- * stores the extra (non-coprocessor) optional/custom state.
- * Entry: a2 = ptr to save area in which to save extra state
- * Exit: any register a2-a15 (?) may have been clobbered.
- */
- .macro xchal_extra_store_funcbody
- .endm
-
-
- /*
- * Macro that expands to the body of a function that
- * loads the extra (non-coprocessor) optional/custom state.
- * Entry: a2 = ptr to save area from which to restore extra state
- * Exit: any register a2-a15 (?) may have been clobbered.
- */
- .macro xchal_extra_load_funcbody
- .endm
-
-
-/********************
- * Macros to save and restore the state of each TIE coprocessor.
- */
-
-
-
-/********************
- * Macros to create functions that save and restore the state of *any* TIE coprocessor.
- */
-
- /*
- * Macro that expands to the body of a function
- * that stores the selected coprocessor's state (registers etc).
- * Entry: a2 = ptr to save area in which to save cp state
- * a3 = coprocessor number
- * Exit: any register a2-a15 (?) may have been clobbered.
- */
- .macro xchal_cpi_store_funcbody
- .endm
-
-
- /*
- * Macro that expands to the body of a function
- * that loads the selected coprocessor's state (registers etc).
- * Entry: a2 = ptr to save area from which to restore cp state
- * a3 = coprocessor number
- * Exit: any register a2-a15 (?) may have been clobbered.
- */
- .macro xchal_cpi_load_funcbody
- .endm
-
-#endif /*_ASMLANGUAGE*/
-
-
-/*
- * Contents of save areas in terms of libdb register numbers.
- * NOTE: CONTENTS_LIBDB_{UREG,REGF} macros are not defined in this file;
- * it is up to the user of this header file to define these macros
- * usefully before each expansion of the CONTENTS_LIBDB macros.
- * (Fields rsv[123] are reserved for future additions; they are currently
- * set to zero but may be set to some useful values in the future.)
- *
- * CONTENTS_LIBDB_SREG(libdbnum, offset, size, align, rsv1, name, sregnum, bitmask, rsv2, rsv3)
- * CONTENTS_LIBDB_UREG(libdbnum, offset, size, align, rsv1, name, uregnum, bitmask, rsv2, rsv3)
- * CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, numentries, contentsize, regname_base, regfile_name, rsv2, rsv3)
- */
-
-#define XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM 0
-#define XCHAL_EXTRA_SA_CONTENTS_LIBDB /* empty */
-
-#define XCHAL_CP0_SA_CONTENTS_LIBDB_NUM 0
-#define XCHAL_CP0_SA_CONTENTS_LIBDB /* empty */
-
-#define XCHAL_CP1_SA_CONTENTS_LIBDB_NUM 0
-#define XCHAL_CP1_SA_CONTENTS_LIBDB /* empty */
-
-#define XCHAL_CP2_SA_CONTENTS_LIBDB_NUM 0
-#define XCHAL_CP2_SA_CONTENTS_LIBDB /* empty */
-
-#define XCHAL_CP3_SA_CONTENTS_LIBDB_NUM 0
-#define XCHAL_CP3_SA_CONTENTS_LIBDB /* empty */
-
-#define XCHAL_CP4_SA_CONTENTS_LIBDB_NUM 0
-#define XCHAL_CP4_SA_CONTENTS_LIBDB /* empty */
-
-#define XCHAL_CP5_SA_CONTENTS_LIBDB_NUM 0
-#define XCHAL_CP5_SA_CONTENTS_LIBDB /* empty */
-
-#define XCHAL_CP6_SA_CONTENTS_LIBDB_NUM 0
-#define XCHAL_CP6_SA_CONTENTS_LIBDB /* empty */
-
-#define XCHAL_CP7_SA_CONTENTS_LIBDB_NUM 0
-#define XCHAL_CP7_SA_CONTENTS_LIBDB /* empty */
-
-
-
-
-
-
-/*----------------------------------------------------------------------
- MISC
- ----------------------------------------------------------------------*/
-
-#if 0 /* is there something equivalent for user TIE? */
-#define XCHAL_CORE_ID "linux_be" /* configuration's alphanumeric core identifier
- (CoreID) set in the Xtensa Processor Generator */
-
-#define XCHAL_BUILD_UNIQUE_ID 0x00003256 /* software build-unique ID (22-bit) */
-
-/* These definitions describe the hardware targeted by this software: */
-#define XCHAL_HW_CONFIGID0 0xC103D1FF /* config ID reg 0 value (upper 32 of 64 bits) */
-#define XCHAL_HW_CONFIGID1 0x00803256 /* config ID reg 1 value (lower 32 of 64 bits) */
-#define XCHAL_CONFIGID0 XCHAL_HW_CONFIGID0 /* for backward compatibility only -- don't use! */
-#define XCHAL_CONFIGID1 XCHAL_HW_CONFIGID1 /* for backward compatibility only -- don't use! */
-#define XCHAL_HW_RELEASE_MAJOR 1050 /* major release of targeted hardware */
-#define XCHAL_HW_RELEASE_MINOR 1 /* minor release of targeted hardware */
-#define XCHAL_HW_RELEASE_NAME "T1050.1" /* full release name of targeted hardware */
-#define XTHAL_HW_REL_T1050 1
-#define XTHAL_HW_REL_T1050_1 1
-#define XCHAL_HW_CONFIGID_RELIABLE 1
-#endif /*0*/
-
-
-
-/*----------------------------------------------------------------------
- ISA
- ----------------------------------------------------------------------*/
-
-#if 0 /* these probably don't belong here, but are related to or implemented using TIE */
-#define XCHAL_HAVE_BOOLEANS 0 /* 1 if booleans option configured, 0 otherwise */
-/* Misc instructions: */
-#define XCHAL_HAVE_MUL32 0 /* 1 if 32-bit integer multiply option configured, 0 otherwise */
-#define XCHAL_HAVE_MUL32_HIGH 0 /* 1 if MUL32 option includes MULUH and MULSH, 0 otherwise */
-
-#define XCHAL_HAVE_FP 0 /* 1 if floating point option configured, 0 otherwise */
-#endif /*0*/
-
-
-#endif /*XTENSA_CONFIG_TIE_H*/
-
diff --git a/include/asm-xtensa/xtensa/coreasm.h b/include/asm-xtensa/xtensa/coreasm.h
deleted file mode 100644
index a8cfb54c20a..00000000000
--- a/include/asm-xtensa/xtensa/coreasm.h
+++ /dev/null
@@ -1,526 +0,0 @@
-#ifndef XTENSA_COREASM_H
-#define XTENSA_COREASM_H
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/coreasm.h -- assembler-specific
- * definitions that depend on CORE configuration.
- *
- * Source for configuration-independent binaries (which link in a
- * configuration-specific HAL library) must NEVER include this file.
- * It is perfectly normal, however, for the HAL itself to include this
- * file.
- *
- * This file must NOT include xtensa/config/system.h. Any assembler
- * header file that depends on system information should likely go in
- * a new systemasm.h (or sysasm.h) header file.
- *
- * NOTE: macro beqi32 is NOT configuration-dependent, and is placed
- * here til we will have configuration-independent header file.
- *
- * 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) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/config/core.h>
-#include <xtensa/config/specreg.h>
-
-/*
- * Assembly-language specific definitions (assembly macros, etc.).
- */
-
-/*----------------------------------------------------------------------
- * find_ms_setbit
- *
- * This macro finds the most significant bit that is set in <as>
- * and return its index + <base> in <ad>, or <base> - 1 if <as> is zero.
- * The index counts starting at zero for the lsbit, so the return
- * value ranges from <base>-1 (no bit set) to <base>+31 (msbit set).
- *
- * Parameters:
- * <ad> destination address register (any register)
- * <as> source address register
- * <at> temporary address register (must be different than <as>)
- * <base> constant value added to result (usually 0 or 1)
- * On entry:
- * <ad> = undefined if different than <as>
- * <as> = value whose most significant set bit is to be found
- * <at> = undefined
- * no other registers are used by this macro.
- * On exit:
- * <ad> = <base> + index of msbit set in original <as>,
- * = <base> - 1 if original <as> was zero.
- * <as> clobbered (if not <ad>)
- * <at> clobbered (if not <ad>)
- * Example:
- * find_ms_setbit a0, a4, a0, 0 -- return in a0 index of msbit set in a4
- */
-
- .macro find_ms_setbit ad, as, at, base
-#if XCHAL_HAVE_NSA
- movi \at, 31+\base
- nsau \as, \as // get index of \as, numbered from msbit (32 if absent)
- sub \ad, \at, \as // get numbering from lsbit (0..31, -1 if absent)
-#else /* XCHAL_HAVE_NSA */
- movi \at, \base // start with result of 0 (point to lsbit of 32)
-
- beqz \as, 2f // special case for zero argument: return -1
- bltui \as, 0x10000, 1f // is it one of the 16 lsbits? (if so, check lower 16 bits)
- addi \at, \at, 16 // no, increment result to upper 16 bits (of 32)
- //srli \as, \as, 16 // check upper half (shift right 16 bits)
- extui \as, \as, 16, 16 // check upper half (shift right 16 bits)
-1: bltui \as, 0x100, 1f // is it one of the 8 lsbits? (if so, check lower 8 bits)
- addi \at, \at, 8 // no, increment result to upper 8 bits (of 16)
- srli \as, \as, 8 // shift right to check upper 8 bits
-1: bltui \as, 0x10, 1f // is it one of the 4 lsbits? (if so, check lower 4 bits)
- addi \at, \at, 4 // no, increment result to upper 4 bits (of 8)
- srli \as, \as, 4 // shift right 4 bits to check upper half
-1: bltui \as, 0x4, 1f // is it one of the 2 lsbits? (if so, check lower 2 bits)
- addi \at, \at, 2 // no, increment result to upper 2 bits (of 4)
- srli \as, \as, 2 // shift right 2 bits to check upper half
-1: bltui \as, 0x2, 1f // is it the lsbit?
- addi \at, \at, 2 // no, increment result to upper bit (of 2)
-2: addi \at, \at, -1 // (from just above: add 1; from beqz: return -1)
- //srli \as, \as, 1
-1: // done! \at contains index of msbit set (or -1 if none set)
- .if 0x\ad - 0x\at // destination different than \at ? (works because regs are a0-a15)
- mov \ad, \at // then move result to \ad
- .endif
-#endif /* XCHAL_HAVE_NSA */
- .endm // find_ms_setbit
-
-/*----------------------------------------------------------------------
- * find_ls_setbit
- *
- * This macro finds the least significant bit that is set in <as>,
- * and return its index in <ad>.
- * Usage is the same as for the find_ms_setbit macro.
- * Example:
- * find_ls_setbit a0, a4, a0, 0 -- return in a0 index of lsbit set in a4
- */
-
- .macro find_ls_setbit ad, as, at, base
- neg \at, \as // keep only the least-significant bit that is set...
- and \as, \at, \as // ... in \as
- find_ms_setbit \ad, \as, \at, \base
- .endm // find_ls_setbit
-
-/*----------------------------------------------------------------------
- * find_ls_one
- *
- * Same as find_ls_setbit with base zero.
- * Source (as) and destination (ad) registers must be different.
- * Provided for backward compatibility.
- */
-
- .macro find_ls_one ad, as
- find_ls_setbit \ad, \as, \ad, 0
- .endm // find_ls_one
-
-/*----------------------------------------------------------------------
- * floop, floopnez, floopgtz, floopend
- *
- * These macros are used for fast inner loops that
- * work whether or not the Loops options is configured.
- * If the Loops option is configured, they simply use
- * the zero-overhead LOOP instructions; otherwise
- * they use explicit decrement and branch instructions.
- *
- * They are used in pairs, with floop, floopnez or floopgtz
- * at the beginning of the loop, and floopend at the end.
- *
- * Each pair of loop macro calls must be given the loop count
- * address register and a unique label for that loop.
- *
- * Example:
- *
- * movi a3, 16 // loop 16 times
- * floop a3, myloop1
- * :
- * bnez a7, end1 // exit loop if a7 != 0
- * :
- * floopend a3, myloop1
- * end1:
- *
- * Like the LOOP instructions, these macros cannot be
- * nested, must include at least one instruction,
- * cannot call functions inside the loop, etc.
- * The loop can be exited by jumping to the instruction
- * following floopend (or elsewhere outside the loop),
- * or continued by jumping to a NOP instruction placed
- * immediately before floopend.
- *
- * Unlike LOOP instructions, the register passed to floop*
- * cannot be used inside the loop, because it is used as
- * the loop counter if the Loops option is not configured.
- * And its value is undefined after exiting the loop.
- * And because the loop counter register is active inside
- * the loop, you can't easily use this construct to loop
- * across a register file using ROTW as you might with LOOP
- * instructions, unless you copy the loop register along.
- */
-
- /* Named label version of the macros: */
-
- .macro floop ar, endlabel
- floop_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
- .endm
-
- .macro floopnez ar, endlabel
- floopnez_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
- .endm
-
- .macro floopgtz ar, endlabel
- floopgtz_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
- .endm
-
- .macro floopend ar, endlabel
- floopend_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
- .endm
-
- /* Numbered local label version of the macros: */
-#if 0 /*UNTESTED*/
- .macro floop89 ar
- floop_ \ar, 8, 9f
- .endm
-
- .macro floopnez89 ar
- floopnez_ \ar, 8, 9f
- .endm
-
- .macro floopgtz89 ar
- floopgtz_ \ar, 8, 9f
- .endm
-
- .macro floopend89 ar
- floopend_ \ar, 8b, 9
- .endm
-#endif /*0*/
-
- /* Underlying version of the macros: */
-
- .macro floop_ ar, startlabel, endlabelref
- .ifdef _infloop_
- .if _infloop_
- .err // Error: floop cannot be nested
- .endif
- .endif
- .set _infloop_, 1
-#if XCHAL_HAVE_LOOPS
- loop \ar, \endlabelref
-#else /* XCHAL_HAVE_LOOPS */
-\startlabel:
- addi \ar, \ar, -1
-#endif /* XCHAL_HAVE_LOOPS */
- .endm // floop_
-
- .macro floopnez_ ar, startlabel, endlabelref
- .ifdef _infloop_
- .if _infloop_
- .err // Error: floopnez cannot be nested
- .endif
- .endif
- .set _infloop_, 1
-#if XCHAL_HAVE_LOOPS
- loopnez \ar, \endlabelref
-#else /* XCHAL_HAVE_LOOPS */
- beqz \ar, \endlabelref
-\startlabel:
- addi \ar, \ar, -1
-#endif /* XCHAL_HAVE_LOOPS */
- .endm // floopnez_
-
- .macro floopgtz_ ar, startlabel, endlabelref
- .ifdef _infloop_
- .if _infloop_
- .err // Error: floopgtz cannot be nested
- .endif
- .endif
- .set _infloop_, 1
-#if XCHAL_HAVE_LOOPS
- loopgtz \ar, \endlabelref
-#else /* XCHAL_HAVE_LOOPS */
- bltz \ar, \endlabelref
- beqz \ar, \endlabelref
-\startlabel:
- addi \ar, \ar, -1
-#endif /* XCHAL_HAVE_LOOPS */
- .endm // floopgtz_
-
-
- .macro floopend_ ar, startlabelref, endlabel
- .ifndef _infloop_
- .err // Error: floopend without matching floopXXX
- .endif
- .ifeq _infloop_
- .err // Error: floopend without matching floopXXX
- .endif
- .set _infloop_, 0
-#if ! XCHAL_HAVE_LOOPS
- bnez \ar, \startlabelref
-#endif /* XCHAL_HAVE_LOOPS */
-\endlabel:
- .endm // floopend_
-
-/*----------------------------------------------------------------------
- * crsil -- conditional RSIL (read/set interrupt level)
- *
- * Executes the RSIL instruction if it exists, else just reads PS.
- * The RSIL instruction does not exist in the new exception architecture
- * if the interrupt option is not selected.
- */
-
- .macro crsil ar, newlevel
-#if XCHAL_HAVE_OLD_EXC_ARCH || XCHAL_HAVE_INTERRUPTS
- rsil \ar, \newlevel
-#else
- rsr \ar, PS
-#endif
- .endm // crsil
-
-/*----------------------------------------------------------------------
- * window_spill{4,8,12}
- *
- * These macros spill callers' register windows to the stack.
- * They work for both privileged and non-privileged tasks.
- * Must be called from a windowed ABI context, eg. within
- * a windowed ABI function (ie. valid stack frame, window
- * exceptions enabled, not in exception mode, etc).
- *
- * This macro requires a single invocation of the window_spill_common
- * macro in the same assembly unit and section.
- *
- * Note that using window_spill{4,8,12} macros is more efficient
- * than calling a function implemented using window_spill_function,
- * because the latter needs extra code to figure out the size of
- * the call to the spilling function.
- *
- * Example usage:
- *
- * .text
- * .align 4
- * .global some_function
- * .type some_function,@function
- * some_function:
- * entry a1, 16
- * :
- * :
- *
- * window_spill4 // spill windows of some_function's callers; preserves a0..a3 only;
- * // to use window_spill{8,12} in this example function we'd have
- * // to increase space allocated by the entry instruction, because
- * // 16 bytes only allows call4; 32 or 48 bytes (+locals) are needed
- * // for call8/window_spill8 or call12/window_spill12 respectively.
- * :
- *
- * retw
- *
- * window_spill_common // instantiates code used by window_spill4
- *
- *
- * On entry:
- * none (if window_spill4)
- * stack frame has enough space allocated for call8 (if window_spill8)
- * stack frame has enough space allocated for call12 (if window_spill12)
- * On exit:
- * a4..a15 clobbered (if window_spill4)
- * a8..a15 clobbered (if window_spill8)
- * a12..a15 clobbered (if window_spill12)
- * no caller windows are in live registers
- */
-
- .macro window_spill4
-#if XCHAL_HAVE_WINDOWED
-# if XCHAL_NUM_AREGS == 16
- movi a15, 0 // for 16-register files, no need to call to reach the end
-# elif XCHAL_NUM_AREGS == 32
- call4 .L__wdwspill_assist28 // call deep enough to clear out any live callers
-# elif XCHAL_NUM_AREGS == 64
- call4 .L__wdwspill_assist60 // call deep enough to clear out any live callers
-# endif
-#endif
- .endm // window_spill4
-
- .macro window_spill8
-#if XCHAL_HAVE_WINDOWED
-# if XCHAL_NUM_AREGS == 16
- movi a15, 0 // for 16-register files, no need to call to reach the end
-# elif XCHAL_NUM_AREGS == 32
- call8 .L__wdwspill_assist24 // call deep enough to clear out any live callers
-# elif XCHAL_NUM_AREGS == 64
- call8 .L__wdwspill_assist56 // call deep enough to clear out any live callers
-# endif
-#endif
- .endm // window_spill8
-
- .macro window_spill12
-#if XCHAL_HAVE_WINDOWED
-# if XCHAL_NUM_AREGS == 16
- movi a15, 0 // for 16-register files, no need to call to reach the end
-# elif XCHAL_NUM_AREGS == 32
- call12 .L__wdwspill_assist20 // call deep enough to clear out any live callers
-# elif XCHAL_NUM_AREGS == 64
- call12 .L__wdwspill_assist52 // call deep enough to clear out any live callers
-# endif
-#endif
- .endm // window_spill12
-
-/*----------------------------------------------------------------------
- * window_spill_function
- *
- * This macro outputs a function that will spill its caller's callers'
- * register windows to the stack. Eg. it could be used to implement
- * a version of xthal_window_spill() that works in non-privileged tasks.
- * This works for both privileged and non-privileged tasks.
- *
- * Typical usage:
- *
- * .text
- * .align 4
- * .global my_spill_function
- * .type my_spill_function,@function
- * my_spill_function:
- * window_spill_function
- *
- * On entry to resulting function:
- * none
- * On exit from resulting function:
- * none (no caller windows are in live registers)
- */
-
- .macro window_spill_function
-#if XCHAL_HAVE_WINDOWED
-# if XCHAL_NUM_AREGS == 32
- entry sp, 48
- bbci.l a0, 31, 1f // branch if called with call4
- bbsi.l a0, 30, 2f // branch if called with call12
- call8 .L__wdwspill_assist16 // called with call8, only need another 8
- retw
-1: call12 .L__wdwspill_assist16 // called with call4, only need another 12
- retw
-2: call4 .L__wdwspill_assist16 // called with call12, only need another 4
- retw
-# elif XCHAL_NUM_AREGS == 64
- entry sp, 48
- bbci.l a0, 31, 1f // branch if called with call4
- bbsi.l a0, 30, 2f // branch if called with call12
- call4 .L__wdwspill_assist52 // called with call8, only need a call4
- retw
-1: call8 .L__wdwspill_assist52 // called with call4, only need a call8
- retw
-2: call12 .L__wdwspill_assist40 // called with call12, can skip a call12
- retw
-# elif XCHAL_NUM_AREGS == 16
- entry sp, 16
- bbci.l a0, 31, 1f // branch if called with call4
- bbsi.l a0, 30, 2f // branch if called with call12
- movi a7, 0 // called with call8
- retw
-1: movi a11, 0 // called with call4
-2: retw // if called with call12, everything already spilled
-
-// movi a15, 0 // trick to spill all but the direct caller
-// j 1f
-// // The entry instruction is magical in the assembler (gets auto-aligned)
-// // so we have to jump to it to avoid falling through the padding.
-// // We need entry/retw to know where to return.
-//1: entry sp, 16
-// retw
-# else
-# error "unrecognized address register file size"
-# endif
-#endif /* XCHAL_HAVE_WINDOWED */
- window_spill_common
- .endm // window_spill_function
-
-/*----------------------------------------------------------------------
- * window_spill_common
- *
- * Common code used by any number of invocations of the window_spill##
- * and window_spill_function macros.
- *
- * Must be instantiated exactly once within a given assembly unit,
- * within call/j range of and same section as window_spill##
- * macro invocations for that assembly unit.
- * (Is automatically instantiated by the window_spill_function macro.)
- */
-
- .macro window_spill_common
-#if XCHAL_HAVE_WINDOWED && (XCHAL_NUM_AREGS == 32 || XCHAL_NUM_AREGS == 64)
- .ifndef .L__wdwspill_defined
-# if XCHAL_NUM_AREGS >= 64
-.L__wdwspill_assist60:
- entry sp, 32
- call8 .L__wdwspill_assist52
- retw
-.L__wdwspill_assist56:
- entry sp, 16
- call4 .L__wdwspill_assist52
- retw
-.L__wdwspill_assist52:
- entry sp, 48
- call12 .L__wdwspill_assist40
- retw
-.L__wdwspill_assist40:
- entry sp, 48
- call12 .L__wdwspill_assist28
- retw
-# endif
-.L__wdwspill_assist28:
- entry sp, 48
- call12 .L__wdwspill_assist16
- retw
-.L__wdwspill_assist24:
- entry sp, 32
- call8 .L__wdwspill_assist16
- retw
-.L__wdwspill_assist20:
- entry sp, 16
- call4 .L__wdwspill_assist16
- retw
-.L__wdwspill_assist16:
- entry sp, 16
- movi a15, 0
- retw
- .set .L__wdwspill_defined, 1
- .endif
-#endif /* XCHAL_HAVE_WINDOWED with 32 or 64 aregs */
- .endm // window_spill_common
-
-/*----------------------------------------------------------------------
- * beqi32
- *
- * macro implements version of beqi for arbitrary 32-bit immidiate value
- *
- * beqi32 ax, ay, imm32, label
- *
- * Compares value in register ax with imm32 value and jumps to label if
- * equal. Clobberes register ay if needed
- *
- */
- .macro beqi32 ax, ay, imm, label
- .ifeq ((\imm-1) & ~7) // 1..8 ?
- beqi \ax, \imm, \label
- .else
- .ifeq (\imm+1) // -1 ?
- beqi \ax, \imm, \label
- .else
- .ifeq (\imm) // 0 ?
- beqz \ax, \label
- .else
- // We could also handle immediates 10,12,16,32,64,128,256
- // but it would be a long macro...
- movi \ay, \imm
- beq \ax, \ay, \label
- .endif
- .endif
- .endif
- .endm // beqi32
-
-#endif /*XTENSA_COREASM_H*/
-
diff --git a/include/asm-xtensa/xtensa/corebits.h b/include/asm-xtensa/xtensa/corebits.h
deleted file mode 100644
index e578ade4163..00000000000
--- a/include/asm-xtensa/xtensa/corebits.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef XTENSA_COREBITS_H
-#define XTENSA_COREBITS_H
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * xtensa/corebits.h - Xtensa Special Register field positions and masks.
- *
- * (In previous releases, these were defined in specreg.h, a generated file.
- * This file is not generated, i.e. it is processor configuration independent.)
- */
-
-
-/* EXCCAUSE register fields: */
-#define EXCCAUSE_EXCCAUSE_SHIFT 0
-#define EXCCAUSE_EXCCAUSE_MASK 0x3F
-/* Exception causes (mostly incomplete!): */
-#define EXCCAUSE_ILLEGAL 0
-#define EXCCAUSE_SYSCALL 1
-#define EXCCAUSE_IFETCHERROR 2
-#define EXCCAUSE_LOADSTOREERROR 3
-#define EXCCAUSE_LEVEL1INTERRUPT 4
-#define EXCCAUSE_ALLOCA 5
-
-/* PS register fields: */
-#define PS_WOE_SHIFT 18
-#define PS_WOE_MASK 0x00040000
-#define PS_WOE PS_WOE_MASK
-#define PS_CALLINC_SHIFT 16
-#define PS_CALLINC_MASK 0x00030000
-#define PS_CALLINC(n) (((n)&3)<<PS_CALLINC_SHIFT) /* n = 0..3 */
-#define PS_OWB_SHIFT 8
-#define PS_OWB_MASK 0x00000F00
-#define PS_OWB(n) (((n)&15)<<PS_OWB_SHIFT) /* n = 0..15 (or 0..7) */
-#define PS_RING_SHIFT 6
-#define PS_RING_MASK 0x000000C0
-#define PS_RING(n) (((n)&3)<<PS_RING_SHIFT) /* n = 0..3 */
-#define PS_UM_SHIFT 5
-#define PS_UM_MASK 0x00000020
-#define PS_UM PS_UM_MASK
-#define PS_EXCM_SHIFT 4
-#define PS_EXCM_MASK 0x00000010
-#define PS_EXCM PS_EXCM_MASK
-#define PS_INTLEVEL_SHIFT 0
-#define PS_INTLEVEL_MASK 0x0000000F
-#define PS_INTLEVEL(n) ((n)&PS_INTLEVEL_MASK) /* n = 0..15 */
-/* Backward compatibility (deprecated): */
-#define PS_PROGSTACK_SHIFT PS_UM_SHIFT
-#define PS_PROGSTACK_MASK PS_UM_MASK
-#define PS_PROG_SHIFT PS_UM_SHIFT
-#define PS_PROG_MASK PS_UM_MASK
-#define PS_PROG PS_UM
-
-/* DBREAKCn register fields: */
-#define DBREAKC_MASK_SHIFT 0
-#define DBREAKC_MASK_MASK 0x0000003F
-#define DBREAKC_LOADBREAK_SHIFT 30
-#define DBREAKC_LOADBREAK_MASK 0x40000000
-#define DBREAKC_STOREBREAK_SHIFT 31
-#define DBREAKC_STOREBREAK_MASK 0x80000000
-
-/* DEBUGCAUSE register fields: */
-#define DEBUGCAUSE_DEBUGINT_SHIFT 5
-#define DEBUGCAUSE_DEBUGINT_MASK 0x20 /* debug interrupt */
-#define DEBUGCAUSE_BREAKN_SHIFT 4
-#define DEBUGCAUSE_BREAKN_MASK 0x10 /* BREAK.N instruction */
-#define DEBUGCAUSE_BREAK_SHIFT 3
-#define DEBUGCAUSE_BREAK_MASK 0x08 /* BREAK instruction */
-#define DEBUGCAUSE_DBREAK_SHIFT 2
-#define DEBUGCAUSE_DBREAK_MASK 0x04 /* DBREAK match */
-#define DEBUGCAUSE_IBREAK_SHIFT 1
-#define DEBUGCAUSE_IBREAK_MASK 0x02 /* IBREAK match */
-#define DEBUGCAUSE_ICOUNT_SHIFT 0
-#define DEBUGCAUSE_ICOUNT_MASK 0x01 /* ICOUNT would increment to zero */
-
-#endif /*XTENSA_COREBITS_H*/
-
diff --git a/include/asm-xtensa/xtensa/hal.h b/include/asm-xtensa/xtensa/hal.h
deleted file mode 100644
index d1047250545..00000000000
--- a/include/asm-xtensa/xtensa/hal.h
+++ /dev/null
@@ -1,822 +0,0 @@
-#ifndef XTENSA_HAL_H
-#define XTENSA_HAL_H
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/hal.h -- contains a definition of the
- * Core HAL interface.
- *
- * All definitions in this header file are independent of any specific
- * Xtensa processor configuration. Thus an OS or other software can
- * include this header file and be compiled into configuration-
- * independent objects that can be distributed and eventually linked
- * to the HAL library (libhal.a) to create a configuration-specific
- * final executable.
- *
- * Certain definitions, however, are release-specific -- such as the
- * XTHAL_RELEASE_xxx macros (or additions made in later releases).
- *
- * 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) 2002 Tensilica Inc.
- */
-
-
-/*----------------------------------------------------------------------
- Constant Definitions
- (shared with assembly)
- ----------------------------------------------------------------------*/
-
-/* Software release information (not configuration-specific!): */
-#define XTHAL_RELEASE_MAJOR 1050
-#define XTHAL_RELEASE_MINOR 0
-#define XTHAL_RELEASE_NAME "T1050.0-2002-08-06-eng0"
-#define XTHAL_RELEASE_INTERNAL "2002-08-06-eng0"
-#define XTHAL_REL_T1050 1
-#define XTHAL_REL_T1050_0 1
-#define XTHAL_REL_T1050_0_2002 1
-#define XTHAL_REL_T1050_0_2002_08 1
-#define XTHAL_REL_T1050_0_2002_08_06 1
-#define XTHAL_REL_T1050_0_2002_08_06_ENG0 1
-
-/* HAL version numbers (these names are for backward compatibility): */
-#define XTHAL_MAJOR_REV XTHAL_RELEASE_MAJOR
-#define XTHAL_MINOR_REV XTHAL_RELEASE_MINOR
-/*
- * A bit of software release history on values of XTHAL_{MAJOR,MINOR}_REV:
- *
- * Release MAJOR MINOR Comment
- * ======= ===== ===== =======
- * T1015.n n/a n/a (HAL not yet available)
- * T1020.{0,1,2} 0 1 (HAL beta)
- * T1020.{3,4} 0 2 First release.
- * T1020.n (n>4) 0 2 or >3 (TBD)
- * T1030.0 0 1 (HAL beta)
- * T1030.{1,2} 0 3 Equivalent to first release.
- * T1030.n (n>=3) 0 >= 3 (TBD)
- * T1040.n 1040 n Full CHAL available from T1040.2
- * T1050.n 1050 n Current release.
- *
- *
- * Note: there is a distinction between the software release with
- * which something is compiled (accessible using XTHAL_RELEASE_* macros)
- * and the software release with which the HAL library was compiled
- * (accessible using Xthal_release_* global variables). This
- * distinction is particularly relevant for vendors that distribute
- * configuration-independent binaries (eg. an OS), where their customer
- * might link it with a HAL of a different Xtensa software release.
- * In this case, it may be appropriate for the OS to verify at run-time
- * whether XTHAL_RELEASE_* and Xthal_release_* are compatible.
- * [Guidelines as to which release is compatible with which are not
- * currently provided explicitly, but might be inferred from reading
- * OSKit documentation for all releases -- compatibility is also highly
- * dependent on which HAL features are used. Each release is usually
- * backward compatible, with very few exceptions if any.]
- *
- * Notes:
- * Tornado 2.0 supported in T1020.3+, T1030.1+, and T1040.{0,1} only.
- * Tornado 2.0.2 supported in T1040.2+, and T1050.
- * Compile-time HAL port of NucleusPlus supported by T1040.2+ and T1050.
- */
-
-
-/*
- * Architectural limits, independent of configuration.
- * Note that these are ISA-defined limits, not micro-architecture implementation
- * limits enforced by the Xtensa Processor Generator (which may be stricter than
- * these below).
- */
-#define XTHAL_MAX_CPS 8 /* max number of coprocessors (0..7) */
-#define XTHAL_MAX_INTERRUPTS 32 /* max number of interrupts (0..31) */
-#define XTHAL_MAX_INTLEVELS 16 /* max number of interrupt levels (0..15) */
- /* (as of T1040, implementation limit is 7: 0..6) */
-#define XTHAL_MAX_TIMERS 4 /* max number of timers (CCOMPARE0..CCOMPARE3) */
- /* (as of T1040, implementation limit is 3: 0..2) */
-
-/* Misc: */
-#define XTHAL_LITTLEENDIAN 0
-#define XTHAL_BIGENDIAN 1
-
-
-/* Interrupt types: */
-#define XTHAL_INTTYPE_UNCONFIGURED 0
-#define XTHAL_INTTYPE_SOFTWARE 1
-#define XTHAL_INTTYPE_EXTERN_EDGE 2
-#define XTHAL_INTTYPE_EXTERN_LEVEL 3
-#define XTHAL_INTTYPE_TIMER 4
-#define XTHAL_INTTYPE_NMI 5
-#define XTHAL_MAX_INTTYPES 6 /* number of interrupt types */
-
-/* Timer related: */
-#define XTHAL_TIMER_UNCONFIGURED -1 /* Xthal_timer_interrupt[] value for non-existent timers */
-#define XTHAL_TIMER_UNASSIGNED XTHAL_TIMER_UNCONFIGURED /* (for backwards compatibility only) */
-
-
-/* Access Mode bits (tentative): */ /* bit abbr unit short_name PPC equ - Description */
-#define XTHAL_AMB_EXCEPTION 0 /* 001 E EX fls: EXception none - generate exception on any access (aka "illegal") */
-#define XTHAL_AMB_HITCACHE 1 /* 002 C CH fls: use Cache on Hit ~(I CI) - use cache on hit -- way from tag match [or H HC, or U UC] (ISA: same, except for Isolate case) */
-#define XTHAL_AMB_ALLOCATE 2 /* 004 A AL fl?: ALlocate none - refill cache on miss -- way from LRU [or F FI fill] (ISA: Read/Write Miss Refill) */
-#define XTHAL_AMB_WRITETHRU 3 /* 008 W WT --s: WriteThrough W WT - store immediately to memory (ISA: same) */
-#define XTHAL_AMB_ISOLATE 4 /* 010 I IS fls: ISolate none - use cache regardless of hit-vs-miss -- way from vaddr (ISA: use-cache-on-miss+hit) */
-#define XTHAL_AMB_GUARD 5 /* 020 G GU ?l?: GUard G * - non-speculative; spec/replay refs not permitted */
-#if 0
-#define XTHAL_AMB_ORDERED x /* 000 O OR fls: ORdered G * - mem accesses cannot be out of order */
-#define XTHAL_AMB_FUSEWRITES x /* 000 F FW --s: FuseWrites none - allow combining/merging multiple writes (to same datapath data unit) into one (implied by writeback) */
-#define XTHAL_AMB_COHERENT x /* 000 M MC fl?: Mem/MP Coherent M - on reads, other CPUs/bus-masters may need to supply data */
-#define XTHAL_AMB_TRUSTED x /* 000 T TR ?l?: TRusted none - memory will not bus error (if it does, handle as fatal imprecise interrupt) */
-#define XTHAL_AMB_PREFETCH x /* 000 P PR fl?: PRefetch none - on refill, read line+1 into prefetch buffers */
-#define XTHAL_AMB_STREAM x /* 000 S ST ???: STreaming none - access one of N stream buffers */
-#endif /*0*/
-
-#define XTHAL_AM_EXCEPTION (1<<XTHAL_AMB_EXCEPTION)
-#define XTHAL_AM_HITCACHE (1<<XTHAL_AMB_HITCACHE)
-#define XTHAL_AM_ALLOCATE (1<<XTHAL_AMB_ALLOCATE)
-#define XTHAL_AM_WRITETHRU (1<<XTHAL_AMB_WRITETHRU)
-#define XTHAL_AM_ISOLATE (1<<XTHAL_AMB_ISOLATE)
-#define XTHAL_AM_GUARD (1<<XTHAL_AMB_GUARD)
-#if 0
-#define XTHAL_AM_ORDERED (1<<XTHAL_AMB_ORDERED)
-#define XTHAL_AM_FUSEWRITES (1<<XTHAL_AMB_FUSEWRITES)
-#define XTHAL_AM_COHERENT (1<<XTHAL_AMB_COHERENT)
-#define XTHAL_AM_TRUSTED (1<<XTHAL_AMB_TRUSTED)
-#define XTHAL_AM_PREFETCH (1<<XTHAL_AMB_PREFETCH)
-#define XTHAL_AM_STREAM (1<<XTHAL_AMB_STREAM)
-#endif /*0*/
-
-/*
- * Allowed Access Modes (bit combinations).
- *
- * Columns are:
- * "FOGIWACE"
- * Access mode bits (see XTHAL_AMB_xxx above).
- * <letter> = bit is set
- * '-' = bit is clear
- * '.' = bit is irrelevant / don't care, as follows:
- * E=1 makes all others irrelevant
- * W,F relevant only for stores
- * "2345"
- * Indicates which Xtensa releases support the corresponding
- * access mode. Releases for each character column are:
- * 2 = prior to T1020.2: T1015 (V1.5), T1020.0, T1020.1
- * 3 = T1020.2 and later: T1020.2+, T1030
- * 4 = T1040
- * 5 = T1050 (maybe)
- * And the character column contents are:
- * <number> = support by release(s)
- * "." = unsupported by release(s)
- * "?" = support unknown
- */
- /* FOGIWACE 2345 */
-/* For instruction fetch: */
-#define XTHAL_FAM_EXCEPTION 0x001 /* .......E 2345 exception */
-#define XTHAL_FAM_ISOLATE 0x012 /* .--I.-C- .... isolate */
-#define XTHAL_FAM_BYPASS 0x000 /* .---.--- 2345 bypass */
-#define XTHAL_FAM_NACACHED 0x002 /* .---.-C- .... cached no-allocate (frozen) */
-#define XTHAL_FAM_CACHED 0x006 /* .---.AC- 2345 cached */
-/* For data load: */
-#define XTHAL_LAM_EXCEPTION 0x001 /* .......E 2345 exception */
-#define XTHAL_LAM_ISOLATE 0x012 /* .--I.-C- 2345 isolate */
-#define XTHAL_LAM_BYPASS 0x000 /* .O--.--- 2... bypass speculative */
-#define XTHAL_LAM_BYPASSG 0x020 /* .OG-.--- .345 bypass guarded */
-#define XTHAL_LAM_NACACHED 0x002 /* .O--.-C- 2... cached no-allocate speculative */
-#define XTHAL_LAM_NACACHEDG 0x022 /* .OG-.-C- .345 cached no-allocate guarded */
-#define XTHAL_LAM_CACHED 0x006 /* .---.AC- 2345 cached speculative */
-#define XTHAL_LAM_CACHEDG 0x026 /* .?G-.AC- .... cached guarded */
-/* For data store: */
-#define XTHAL_SAM_EXCEPTION 0x001 /* .......E 2345 exception */
-#define XTHAL_SAM_ISOLATE 0x032 /* .-GI--C- 2345 isolate */
-#define XTHAL_SAM_BYPASS 0x028 /* -OG-W--- 2345 bypass */
-/*efine XTHAL_SAM_BYPASSF 0x028*/ /* F-G-W--- ...? bypass write-combined */
-#define XTHAL_SAM_WRITETHRU 0x02A /* -OG-W-C- 234? writethrough */
-/*efine XTHAL_SAM_WRITETHRUF 0x02A*/ /* F-G-W-C- ...5 writethrough write-combined */
-#define XTHAL_SAM_WRITEALLOC 0x02E /* -OG-WAC- ...? writethrough-allocate */
-/*efine XTHAL_SAM_WRITEALLOCF 0x02E*/ /* F-G-WAC- ...? writethrough-allocate write-combined */
-#define XTHAL_SAM_WRITEBACK 0x026 /* F-G--AC- ...5 writeback */
-
-#if 0
-/*
- Cache attribute encoding for CACHEATTR (per ISA):
- (Note: if this differs from ISA Ref Manual, ISA has precedence)
-
- Inst-fetches Loads Stores
- ------------- ------------ -------------
-0x0 FCA_EXCEPTION ?LCA_NACACHED_G* SCA_WRITETHRU "uncached"
-0x1 FCA_CACHED LCA_CACHED SCA_WRITETHRU cached
-0x2 FCA_BYPASS LCA_BYPASS_G* SCA_BYPASS bypass
-0x3 FCA_CACHED LCA_CACHED SCA_WRITEALLOCF write-allocate
- or LCA_EXCEPTION SCA_EXCEPTION (if unimplemented)
-0x4 FCA_CACHED LCA_CACHED SCA_WRITEBACK write-back
- or LCA_EXCEPTION SCA_EXCEPTION (if unimplemented)
-0x5..D FCA_EXCEPTION LCA_EXCEPTION SCA_EXCEPTION (reserved)
-0xE FCA_EXCEPTION LCA_ISOLATE SCA_ISOLATE isolate
-0xF FCA_EXCEPTION LCA_EXCEPTION SCA_EXCEPTION illegal
- * Prior to T1020.2?, guard feature not supported, this defaulted to speculative (no _G)
-*/
-#endif /*0*/
-
-
-#if !defined(__ASSEMBLY__) && !defined(_NOCLANGUAGE)
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*----------------------------------------------------------------------
- HAL
- ----------------------------------------------------------------------*/
-
-/* Constant to be checked in build = (XTHAL_MAJOR_REV<<16)|XTHAL_MINOR_REV */
-extern const unsigned int Xthal_rev_no;
-
-
-/*----------------------------------------------------------------------
- Processor State
- ----------------------------------------------------------------------*/
-/* save & restore the extra processor state */
-extern void xthal_save_extra(void *base);
-extern void xthal_restore_extra(void *base);
-
-extern void xthal_save_cpregs(void *base, int);
-extern void xthal_restore_cpregs(void *base, int);
-
-/*extern void xthal_save_all_extra(void *base);*/
-/*extern void xthal_restore_all_extra(void *base);*/
-
-/* space for processor state */
-extern const unsigned int Xthal_extra_size;
-extern const unsigned int Xthal_extra_align;
-/* space for TIE register files */
-extern const unsigned int Xthal_cpregs_size[XTHAL_MAX_CPS];
-extern const unsigned int Xthal_cpregs_align[XTHAL_MAX_CPS];
-
-/* total of space for the processor state (for Tor2) */
-extern const unsigned int Xthal_all_extra_size;
-extern const unsigned int Xthal_all_extra_align;
-
-/* initialize the extra processor */
-/*extern void xthal_init_extra(void);*/
-/* initialize the TIE coprocessor */
-/*extern void xthal_init_cp(int);*/
-
-/* initialize the extra processor */
-extern void xthal_init_mem_extra(void *);
-/* initialize the TIE coprocessor */
-extern void xthal_init_mem_cp(void *, int);
-
-/* validate & invalidate the TIE register file */
-extern void xthal_validate_cp(int);
-extern void xthal_invalidate_cp(int);
-
-/* the number of TIE coprocessors contiguous from zero (for Tor2) */
-extern const unsigned int Xthal_num_coprocessors;
-
-/* actual number of coprocessors */
-extern const unsigned char Xthal_cp_num;
-/* index of highest numbered coprocessor, plus one */
-extern const unsigned char Xthal_cp_max;
-/* index of highest allowed coprocessor number, per cfg, plus one */
-/*extern const unsigned char Xthal_cp_maxcfg;*/
-/* bitmask of which coprocessors are present */
-extern const unsigned int Xthal_cp_mask;
-
-/* read and write cpenable register */
-extern void xthal_set_cpenable(unsigned);
-extern unsigned xthal_get_cpenable(void);
-
-/* read & write extra state register */
-/*extern int xthal_read_extra(void *base, unsigned reg, unsigned *value);*/
-/*extern int xthal_write_extra(void *base, unsigned reg, unsigned value);*/
-
-/* read & write a TIE coprocessor register */
-/*extern int xthal_read_cpreg(void *base, int cp, unsigned reg, unsigned *value);*/
-/*extern int xthal_write_cpreg(void *base, int cp, unsigned reg, unsigned value);*/
-
-/* return coprocessor number based on register */
-/*extern int xthal_which_cp(unsigned reg);*/
-
-/*----------------------------------------------------------------------
- Interrupts
- ----------------------------------------------------------------------*/
-
-/* the number of interrupt levels */
-extern const unsigned char Xthal_num_intlevels;
-/* the number of interrupts */
-extern const unsigned char Xthal_num_interrupts;
-
-/* mask for level of interrupts */
-extern const unsigned int Xthal_intlevel_mask[XTHAL_MAX_INTLEVELS];
-/* mask for level 0 to N interrupts */
-extern const unsigned int Xthal_intlevel_andbelow_mask[XTHAL_MAX_INTLEVELS];
-
-/* level of each interrupt */
-extern const unsigned char Xthal_intlevel[XTHAL_MAX_INTERRUPTS];
-
-/* type per interrupt */
-extern const unsigned char Xthal_inttype[XTHAL_MAX_INTERRUPTS];
-
-/* masks of each type of interrupt */
-extern const unsigned int Xthal_inttype_mask[XTHAL_MAX_INTTYPES];
-
-/* interrupt numbers assigned to each timer interrupt */
-extern const int Xthal_timer_interrupt[XTHAL_MAX_TIMERS];
-
-/*** Virtual interrupt prioritization: ***/
-
-/* Convert between interrupt levels (as per PS.INTLEVEL) and virtual interrupt priorities: */
-extern unsigned xthal_vpri_to_intlevel(unsigned vpri);
-extern unsigned xthal_intlevel_to_vpri(unsigned intlevel);
-
-/* Enables/disables given set (mask) of interrupts; returns previous enabled-mask of all ints: */
-extern unsigned xthal_int_enable(unsigned);
-extern unsigned xthal_int_disable(unsigned);
-
-/* Set/get virtual priority of an interrupt: */
-extern int xthal_set_int_vpri(int intnum, int vpri);
-extern int xthal_get_int_vpri(int intnum);
-
-/* Set/get interrupt lockout level for exclusive access to virtual priority data structures: */
-extern void xthal_set_vpri_locklevel(unsigned intlevel);
-extern unsigned xthal_get_vpri_locklevel(void);
-
-/* Set/get current virtual interrupt priority: */
-extern unsigned xthal_set_vpri(unsigned vpri);
-extern unsigned xthal_get_vpri(unsigned vpri);
-extern unsigned xthal_set_vpri_intlevel(unsigned intlevel);
-extern unsigned xthal_set_vpri_lock(void);
-
-
-
-/*----------------------------------------------------------------------
- Generic Interrupt Trampolining Support
- ----------------------------------------------------------------------*/
-
-typedef void (XtHalVoidFunc)(void);
-
-/*
- * Bitmask of interrupts currently trampolining down:
- */
-extern unsigned Xthal_tram_pending;
-
-/*
- * Bitmask of which interrupts currently trampolining down
- * synchronously are actually enabled; this bitmask is necessary
- * because INTENABLE cannot hold that state (sync-trampolining
- * interrupts must be kept disabled while trampolining);
- * in the current implementation, any bit set here is not set
- * in INTENABLE, and vice-versa; once a sync-trampoline is
- * handled (at level one), its enable bit must be moved from
- * here to INTENABLE:
- */
-extern unsigned Xthal_tram_enabled;
-
-/*
- * Bitmask of interrupts configured for sync trampolining:
- */
-extern unsigned Xthal_tram_sync;
-
-
-/* Trampoline support functions: */
-extern unsigned xthal_tram_pending_to_service( void );
-extern void xthal_tram_done( unsigned serviced_mask );
-extern int xthal_tram_set_sync( int intnum, int sync );
-extern XtHalVoidFunc* xthal_set_tram_trigger_func( XtHalVoidFunc *trigger_fn );
-
-/* INTENABLE,INTREAD,INTSET,INTCLEAR register access functions: */
-extern unsigned xthal_get_intenable( void );
-extern void xthal_set_intenable( unsigned );
-extern unsigned xthal_get_intread( void );
-extern void xthal_set_intset( unsigned );
-extern void xthal_set_intclear( unsigned );
-
-
-/*----------------------------------------------------------------------
- Register Windows
- ----------------------------------------------------------------------*/
-
-/* number of registers in register window */
-extern const unsigned int Xthal_num_aregs;
-extern const unsigned char Xthal_num_aregs_log2;
-
-/* This spill any live register windows (other than the caller's): */
-extern void xthal_window_spill( void );
-
-
-/*----------------------------------------------------------------------
- Cache
- ----------------------------------------------------------------------*/
-
-/* size of the cache lines in log2(bytes) */
-extern const unsigned char Xthal_icache_linewidth;
-extern const unsigned char Xthal_dcache_linewidth;
-/* size of the cache lines in bytes */
-extern const unsigned short Xthal_icache_linesize;
-extern const unsigned short Xthal_dcache_linesize;
-/* number of cache sets in log2(lines per way) */
-extern const unsigned char Xthal_icache_setwidth;
-extern const unsigned char Xthal_dcache_setwidth;
-/* cache set associativity (number of ways) */
-extern const unsigned int Xthal_icache_ways;
-extern const unsigned int Xthal_dcache_ways;
-/* size of the caches in bytes (ways * 2^(linewidth + setwidth)) */
-extern const unsigned int Xthal_icache_size;
-extern const unsigned int Xthal_dcache_size;
-/* cache features */
-extern const unsigned char Xthal_dcache_is_writeback;
-extern const unsigned char Xthal_icache_line_lockable;
-extern const unsigned char Xthal_dcache_line_lockable;
-
-/* cache attribute register control (used by other HAL routines) */
-extern unsigned xthal_get_cacheattr( void );
-extern unsigned xthal_get_icacheattr( void );
-extern unsigned xthal_get_dcacheattr( void );
-extern void xthal_set_cacheattr( unsigned );
-extern void xthal_set_icacheattr( unsigned );
-extern void xthal_set_dcacheattr( unsigned );
-
-/* initialize cache support (must be called once at startup, before all other cache calls) */
-/*extern void xthal_cache_startinit( void );*/
-/* reset caches */
-/*extern void xthal_icache_reset( void );*/
-/*extern void xthal_dcache_reset( void );*/
-/* enable caches */
-extern void xthal_icache_enable( void ); /* DEPRECATED */
-extern void xthal_dcache_enable( void ); /* DEPRECATED */
-/* disable caches */
-extern void xthal_icache_disable( void ); /* DEPRECATED */
-extern void xthal_dcache_disable( void ); /* DEPRECATED */
-
-/* invalidate the caches */
-extern void xthal_icache_all_invalidate( void );
-extern void xthal_dcache_all_invalidate( void );
-extern void xthal_icache_region_invalidate( void *addr, unsigned size );
-extern void xthal_dcache_region_invalidate( void *addr, unsigned size );
-extern void xthal_icache_line_invalidate(void *addr);
-extern void xthal_dcache_line_invalidate(void *addr);
-/* write dirty data back */
-extern void xthal_dcache_all_writeback( void );
-extern void xthal_dcache_region_writeback( void *addr, unsigned size );
-extern void xthal_dcache_line_writeback(void *addr);
-/* write dirty data back and invalidate */
-extern void xthal_dcache_all_writeback_inv( void );
-extern void xthal_dcache_region_writeback_inv( void *addr, unsigned size );
-extern void xthal_dcache_line_writeback_inv(void *addr);
-/* prefetch and lock specified memory range into cache */
-extern void xthal_icache_region_lock( void *addr, unsigned size );
-extern void xthal_dcache_region_lock( void *addr, unsigned size );
-extern void xthal_icache_line_lock(void *addr);
-extern void xthal_dcache_line_lock(void *addr);
-/* unlock from cache */
-extern void xthal_icache_all_unlock( void );
-extern void xthal_dcache_all_unlock( void );
-extern void xthal_icache_region_unlock( void *addr, unsigned size );
-extern void xthal_dcache_region_unlock( void *addr, unsigned size );
-extern void xthal_icache_line_unlock(void *addr);
-extern void xthal_dcache_line_unlock(void *addr);
-
-
-/* sync icache and memory */
-extern void xthal_icache_sync( void );
-/* sync dcache and memory */
-extern void xthal_dcache_sync( void );
-
-/*----------------------------------------------------------------------
- Debug
- ----------------------------------------------------------------------*/
-
-/* 1 if debug option configured, 0 if not: */
-extern const int Xthal_debug_configured;
-
-/* Number of instruction and data break registers: */
-extern const int Xthal_num_ibreak;
-extern const int Xthal_num_dbreak;
-
-/* Set (plant) and remove software breakpoint, both synchronizing cache: */
-extern unsigned int xthal_set_soft_break(void *addr);
-extern void xthal_remove_soft_break(void *addr, unsigned int);
-
-
-/*----------------------------------------------------------------------
- Disassembler
- ----------------------------------------------------------------------*/
-
-/* Max expected size of the return buffer for a disassembled instruction (hint only): */
-#define XTHAL_DISASM_BUFSIZE 80
-
-/* Disassembly option bits for selecting what to return: */
-#define XTHAL_DISASM_OPT_ADDR 0x0001 /* display address */
-#define XTHAL_DISASM_OPT_OPHEX 0x0002 /* display opcode bytes in hex */
-#define XTHAL_DISASM_OPT_OPCODE 0x0004 /* display opcode name (mnemonic) */
-#define XTHAL_DISASM_OPT_PARMS 0x0008 /* display parameters */
-#define XTHAL_DISASM_OPT_ALL 0x0FFF /* display everything */
-
-/* routine to get a string for the disassembled instruction */
-extern int xthal_disassemble( unsigned char *instr_buf, void *tgt_addr,
- char *buffer, unsigned buflen, unsigned options );
-
-/* routine to get the size of the next instruction. Returns 0 for
- illegal instruction */
-extern int xthal_disassemble_size( unsigned char *instr_buf );
-
-
-/*----------------------------------------------------------------------
- Core Counter
- ----------------------------------------------------------------------*/
-
-/* counter info */
-extern const unsigned char Xthal_have_ccount; /* set if CCOUNT register present */
-extern const unsigned char Xthal_num_ccompare; /* number of CCOMPAREn registers */
-
-/* get CCOUNT register (if not present return 0) */
-extern unsigned xthal_get_ccount(void);
-
-/* set and get CCOMPAREn registers (if not present, get returns 0) */
-extern void xthal_set_ccompare(int, unsigned);
-extern unsigned xthal_get_ccompare(int);
-
-
-/*----------------------------------------------------------------------
- Instruction/Data RAM/ROM Access
- ----------------------------------------------------------------------*/
-
-extern void* xthal_memcpy(void *dst, const void *src, unsigned len);
-extern void* xthal_bcopy(const void *src, void *dst, unsigned len);
-
-/*----------------------------------------------------------------------
- MP Synchronization
- ----------------------------------------------------------------------*/
-extern int xthal_compare_and_set( int *addr, int test_val, int compare_val );
-extern unsigned xthal_get_prid( void );
-
-/*extern const char Xthal_have_s32c1i;*/
-extern const unsigned char Xthal_have_prid;
-
-
-/*----------------------------------------------------------------------
- Miscellaneous
- ----------------------------------------------------------------------*/
-
-extern const unsigned int Xthal_release_major;
-extern const unsigned int Xthal_release_minor;
-extern const char * const Xthal_release_name;
-extern const char * const Xthal_release_internal;
-
-extern const unsigned char Xthal_memory_order;
-extern const unsigned char Xthal_have_windowed;
-extern const unsigned char Xthal_have_density;
-extern const unsigned char Xthal_have_booleans;
-extern const unsigned char Xthal_have_loops;
-extern const unsigned char Xthal_have_nsa;
-extern const unsigned char Xthal_have_minmax;
-extern const unsigned char Xthal_have_sext;
-extern const unsigned char Xthal_have_clamps;
-extern const unsigned char Xthal_have_mac16;
-extern const unsigned char Xthal_have_mul16;
-extern const unsigned char Xthal_have_fp;
-extern const unsigned char Xthal_have_speculation;
-extern const unsigned char Xthal_have_exceptions;
-extern const unsigned char Xthal_xea_version;
-extern const unsigned char Xthal_have_interrupts;
-extern const unsigned char Xthal_have_highlevel_interrupts;
-extern const unsigned char Xthal_have_nmi;
-
-extern const unsigned short Xthal_num_writebuffer_entries;
-
-extern const unsigned int Xthal_build_unique_id;
-/* Release info for hardware targeted by software upgrades: */
-extern const unsigned int Xthal_hw_configid0;
-extern const unsigned int Xthal_hw_configid1;
-extern const unsigned int Xthal_hw_release_major;
-extern const unsigned int Xthal_hw_release_minor;
-extern const char * const Xthal_hw_release_name;
-extern const char * const Xthal_hw_release_internal;
-
-
-/* Internal memories... */
-
-extern const unsigned char Xthal_num_instrom;
-extern const unsigned char Xthal_num_instram;
-extern const unsigned char Xthal_num_datarom;
-extern const unsigned char Xthal_num_dataram;
-extern const unsigned char Xthal_num_xlmi;
-extern const unsigned int Xthal_instrom_vaddr[1];
-extern const unsigned int Xthal_instrom_paddr[1];
-extern const unsigned int Xthal_instrom_size [1];
-extern const unsigned int Xthal_instram_vaddr[1];
-extern const unsigned int Xthal_instram_paddr[1];
-extern const unsigned int Xthal_instram_size [1];
-extern const unsigned int Xthal_datarom_vaddr[1];
-extern const unsigned int Xthal_datarom_paddr[1];
-extern const unsigned int Xthal_datarom_size [1];
-extern const unsigned int Xthal_dataram_vaddr[1];
-extern const unsigned int Xthal_dataram_paddr[1];
-extern const unsigned int Xthal_dataram_size [1];
-extern const unsigned int Xthal_xlmi_vaddr[1];
-extern const unsigned int Xthal_xlmi_paddr[1];
-extern const unsigned int Xthal_xlmi_size [1];
-
-
-
-/*----------------------------------------------------------------------
- Memory Management Unit
- ----------------------------------------------------------------------*/
-
-extern const unsigned char Xthal_have_spanning_way;
-extern const unsigned char Xthal_have_identity_map;
-extern const unsigned char Xthal_have_mimic_cacheattr;
-extern const unsigned char Xthal_have_xlt_cacheattr;
-extern const unsigned char Xthal_have_cacheattr;
-extern const unsigned char Xthal_have_tlbs;
-
-extern const unsigned char Xthal_mmu_asid_bits; /* 0 .. 8 */
-extern const unsigned char Xthal_mmu_asid_kernel;
-extern const unsigned char Xthal_mmu_rings; /* 1 .. 4 (perhaps 0 if no MMU and/or no protection?) */
-extern const unsigned char Xthal_mmu_ring_bits;
-extern const unsigned char Xthal_mmu_sr_bits;
-extern const unsigned char Xthal_mmu_ca_bits;
-extern const unsigned int Xthal_mmu_max_pte_page_size;
-extern const unsigned int Xthal_mmu_min_pte_page_size;
-
-extern const unsigned char Xthal_itlb_way_bits;
-extern const unsigned char Xthal_itlb_ways;
-extern const unsigned char Xthal_itlb_arf_ways;
-extern const unsigned char Xthal_dtlb_way_bits;
-extern const unsigned char Xthal_dtlb_ways;
-extern const unsigned char Xthal_dtlb_arf_ways;
-
-/* Convert between virtual and physical addresses (through static maps only): */
-/*** WARNING: these two functions may go away in a future release; don't depend on them! ***/
-extern int xthal_static_v2p( unsigned vaddr, unsigned *paddrp );
-extern int xthal_static_p2v( unsigned paddr, unsigned *vaddrp, unsigned cached );
-
-#if 0
-/******************* EXPERIMENTAL AND TENTATIVE ONLY ********************/
-
-#define XTHAL_MMU_PAGESZ_COUNT_MAX 8 /* maximum number of different page sizes */
-extern const char Xthal_mmu_pagesz_count; /* 0 .. 8 number of different page sizes configured */
-
-/* Note: the following table doesn't necessarily have page sizes in increasing order: */
-extern const char Xthal_mmu_pagesz_log2[XTHAL_MMU_PAGESZ_COUNT_MAX]; /* 10 .. 28 (0 past count) */
-
-/* Sorted (increasing) table of page sizes, that indexes into the above table: */
-extern const char Xthal_mmu_pagesz_sorted[XTHAL_MMU_PAGESZ_COUNT_MAX]; /* 0 .. 7 (0 past count) */
-
-/*u32 Xthal_virtual_exceptions;*/ /* bitmask of which exceptions execute in virtual mode... */
-
-extern const char Xthal_mmu_pte_pagesz_log2_min; /* ?? minimum page size in PTEs */
-extern const char Xthal_mmu_pte_pagesz_log2_max; /* ?? maximum page size in PTEs */
-
-/* Cache Attribute Bits Implemented by the Cache (part of the cache abstraction) */
-extern const char Xthal_icache_fca_bits_implemented; /* ITLB/UTLB only! */
-extern const char Xthal_dcache_lca_bits_implemented; /* DTLB/UTLB only! */
-extern const char Xthal_dcache_sca_bits_implemented; /* DTLB/UTLB only! */
-
-/* Per TLB Parameters (Instruction, Data, Unified) */
-struct XtHalMmuTlb Xthal_itlb; /* description of MMU I-TLB generic features */
-struct XtHalMmuTlb Xthal_dtlb; /* description of MMU D-TLB generic features */
-struct XtHalMmuTlb Xthal_utlb; /* description of MMU U-TLB generic features */
-
-#define XTHAL_MMU_WAYS_MAX 8 /* maximum number of ways (associativities) for each TLB */
-
-/* Structure for common information described for each possible TLB (instruction, data and unified): */
-typedef struct XtHalMmuTlb {
- u8 va_bits; /* 32 (number of virtual address bits) */
- u8 pa_bits; /* 32 (number of physical address bits) */
- bool tlb_va_indexed; /* 1 (set if TLB is indexed by virtual address) */
- bool tlb_va_tagged; /* 0 (set if TLB is tagged by virtual address) */
- bool cache_va_indexed; /* 1 (set if cache is indexed by virtual address) */
- bool cache_va_tagged; /* 0 (set if cache is tagged by virtual address) */
- /*bool (whether page tables are traversed in vaddr sorted order, paddr sorted order, ...) */
- /*u8 (set of available page attribute bits, other than cache attribute bits defined above) */
- /*u32 (various masks for pages, MMU table/TLB entries, etc.) */
- u8 way_count; /* 0 .. 8 (number of ways, a.k.a. associativities, for this TLB) */
- XtHalMmuTlbWay * ways[XTHAL_MMU_WAYS_MAX]; /* pointers to per-way parms for each way */
-} XtHalMmuTlb;
-
-/* Per TLB Way (Per Associativity) Parameters */
-typedef struct XtHalMmuTlbWay {
- u32 index_count_log2; /* 0 .. 4 */
- u32 pagesz_mask; /* 0 .. 2^pagesz_count - 1 (each bit corresponds to a size */
- /* defined in the Xthal_mmu_pagesz_log2[] table) */
- u32 vpn_const_mask;
- u32 vpn_const_value;
- u64 ppn_const_mask; /* future may support pa_bits > 32 */
- u64 ppn_const_value;
- u32 ppn_id_mask; /* paddr bits taken directly from vaddr */
- bool backgnd_match; /* 0 or 1 */
- /* These are defined in terms of the XTHAL_CACHE_xxx bits: */
- u8 fca_const_mask; /* ITLB/UTLB only! */
- u8 fca_const_value; /* ITLB/UTLB only! */
- u8 lca_const_mask; /* DTLB/UTLB only! */
- u8 lca_const_value; /* DTLB/UTLB only! */
- u8 sca_const_mask; /* DTLB/UTLB only! */
- u8 sca_const_value; /* DTLB/UTLB only! */
- /* These define an encoding that map 5 bits in TLB and PTE entries to */
- /* 8 bits (FCA, ITLB), 16 bits (LCA+SCA, DTLB) or 24 bits (FCA+LCA+SCA, UTLB): */
- /* (they may be moved to struct XtHalMmuTlb) */
- u8 ca_bits; /* number of bits in TLB/PTE entries for cache attributes */
- u32 * ca_map; /* pointer to array of 2^ca_bits entries of FCA+LCA+SCA bits */
-} XtHalMmuTlbWay;
-
-/*
- * The way to determine whether protection support is present in core
- * is to [look at Xthal_mmu_rings ???].
- * Give info on memory requirements for MMU tables and other in-memory
- * data structures (globally, per task, base and per page, etc.) - whatever bounds can be calculated.
- */
-
-
-/* Default vectors: */
-xthal_immu_fetch_miss_vector
-xthal_dmmu_load_miss_vector
-xthal_dmmu_store_miss_vector
-
-/* Functions called when a fault is detected: */
-typedef void (XtHalMmuFaultFunc)( unsigned vaddr, ...context... );
-/* Or, */
-/* a? = vaddr */
-/* a? = context... */
-/* PS.xxx = xxx */
-XtHalMMuFaultFunc *Xthal_immu_fetch_fault_func;
-XtHalMMuFaultFunc *Xthal_dmmu_load_fault_func;
-XtHalMMuFaultFunc *Xthal_dmmu_store_fault_func;
-
-/* Default Handlers: */
-/* The user and/or kernel exception handlers may jump to these handlers to handle the relevant exceptions,
- * according to the value of EXCCAUSE. The exact register state on entry to these handlers is TBD. */
-/* When multiple TLB entries match (hit) on the same access: */
-xthal_immu_fetch_multihit_handler
-xthal_dmmu_load_multihit_handler
-xthal_dmmu_store_multihit_handler
-/* Protection violations according to cache attributes, and other cache attribute mismatches: */
-xthal_immu_fetch_attr_handler
-xthal_dmmu_load_attr_handler
-xthal_dmmu_store_attr_handler
-/* Protection violations due to insufficient ring level: */
-xthal_immu_fetch_priv_handler
-xthal_dmmu_load_priv_handler
-xthal_dmmu_store_priv_handler
-/* Alignment exception handlers (if supported by the particular Xtensa MMU configuration): */
-xthal_dmmu_load_align_handler
-xthal_dmmu_store_align_handler
-
-/* Or, alternatively, the OS user and/or kernel exception handlers may simply jump to the
- * following entry points which will handle any values of EXCCAUSE not handled by the OS: */
-xthal_user_exc_default_handler
-xthal_kernel_exc_default_handler
-
-#endif /*0*/
-
-#ifdef INCLUDE_DEPRECATED_HAL_CODE
-extern const unsigned char Xthal_have_old_exc_arch;
-extern const unsigned char Xthal_have_mmu;
-extern const unsigned int Xthal_num_regs;
-extern const unsigned char Xthal_num_iroms;
-extern const unsigned char Xthal_num_irams;
-extern const unsigned char Xthal_num_droms;
-extern const unsigned char Xthal_num_drams;
-extern const unsigned int Xthal_configid0;
-extern const unsigned int Xthal_configid1;
-#endif
-
-#ifdef INCLUDE_DEPRECATED_HAL_DEBUG_CODE
-#define XTHAL_24_BIT_BREAK 0x80000000
-#define XTHAL_16_BIT_BREAK 0x40000000
-extern const unsigned short Xthal_ill_inst_16[16];
-#define XTHAL_DEST_REG 0xf0000000 /* Mask for destination register */
-#define XTHAL_DEST_REG_INST 0x08000000 /* Branch address is in register */
-#define XTHAL_DEST_REL_INST 0x04000000 /* Branch address is relative */
-#define XTHAL_RFW_INST 0x00000800
-#define XTHAL_RFUE_INST 0x00000400
-#define XTHAL_RFI_INST 0x00000200
-#define XTHAL_RFE_INST 0x00000100
-#define XTHAL_RET_INST 0x00000080
-#define XTHAL_BREAK_INST 0x00000040
-#define XTHAL_SYSCALL_INST 0x00000020
-#define XTHAL_LOOP_END 0x00000010 /* Not set by xthal_inst_type */
-#define XTHAL_JUMP_INST 0x00000008 /* Call or jump instruction */
-#define XTHAL_BRANCH_INST 0x00000004 /* Branch instruction */
-#define XTHAL_24_BIT_INST 0x00000002
-#define XTHAL_16_BIT_INST 0x00000001
-typedef struct xthal_state {
- unsigned pc;
- unsigned ar[16];
- unsigned lbeg;
- unsigned lend;
- unsigned lcount;
- unsigned extra_ptr;
- unsigned cpregs_ptr[XTHAL_MAX_CPS];
-} XTHAL_STATE;
-extern unsigned int xthal_inst_type(void *addr);
-extern unsigned int xthal_branch_addr(void *addr);
-extern unsigned int xthal_get_npc(XTHAL_STATE *user_state);
-#endif /* INCLUDE_DEPRECATED_HAL_DEBUG_CODE */
-
-#ifdef __cplusplus
-}
-#endif
-#endif /*!__ASSEMBLY__ */
-
-#endif /*XTENSA_HAL_H*/
-
diff --git a/include/asm-xtensa/xtensa/simcall.h b/include/asm-xtensa/xtensa/simcall.h
deleted file mode 100644
index a2b868929a4..00000000000
--- a/include/asm-xtensa/xtensa/simcall.h
+++ /dev/null
@@ -1,130 +0,0 @@
-#ifndef SIMCALL_INCLUDED
-#define SIMCALL_INCLUDED
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/simcall.h - Simulator call numbers
- *
- * 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) 2002 Tensilica Inc.
- */
-
-
-/*
- * System call like services offered by the simulator host.
- * These are modeled after the Linux 2.4 kernel system calls
- * for Xtensa processors. However not all system calls and
- * not all functionality of a given system call are implemented,
- * or necessarily have well defined or equivalent semantics in
- * the context of a simulation (as opposed to a Unix kernel).
- *
- * These services behave largely as if they had been invoked
- * as a task in the simulator host's operating system
- * (eg. files accessed are those of the simulator host).
- * However, these SIMCALLs model a virtual operating system
- * so that various definitions, bit assignments etc
- * (eg. open mode bits, errno values, etc) are independent
- * of the host operating system used to run the simulation.
- * Rather these definitions are specific to the Xtensa ISS.
- * This way Xtensa ISA code written to use these SIMCALLs
- * can (in principle) be simulated on any host.
- *
- * Up to 6 parameters are passed in registers a3 to a8
- * (note the 6th parameter isn't passed on the stack,
- * unlike windowed function calling conventions).
- * The return value is in a2. A negative value in the
- * range -4096 to -1 indicates a negated error code to be
- * reported in errno with a return value of -1, otherwise
- * the value in a2 is returned as is.
- */
-
-/* These #defines need to match what's in Xtensa/OS/vxworks/xtiss/simcalls.c */
-
-#define SYS_nop 0 /* n/a - setup; used to flush register windows */
-#define SYS_exit 1 /*x*/
-#define SYS_fork 2
-#define SYS_read 3 /*x*/
-#define SYS_write 4 /*x*/
-#define SYS_open 5 /*x*/
-#define SYS_close 6 /*x*/
-#define SYS_rename 7 /*x 38 - waitpid */
-#define SYS_creat 8 /*x*/
-#define SYS_link 9 /*x (not implemented on WIN32) */
-#define SYS_unlink 10 /*x*/
-#define SYS_execv 11 /* n/a - execve */
-#define SYS_execve 12 /* 11 - chdir */
-#define SYS_pipe 13 /* 42 - time */
-#define SYS_stat 14 /* 106 - mknod */
-#define SYS_chmod 15
-#define SYS_chown 16 /* 202 - lchown */
-#define SYS_utime 17 /* 30 - break */
-#define SYS_wait 18 /* n/a - oldstat */
-#define SYS_lseek 19 /*x*/
-#define SYS_getpid 20
-#define SYS_isatty 21 /* n/a - mount */
-#define SYS_fstat 22 /* 108 - oldumount */
-#define SYS_time 23 /* 13 - setuid */
-#define SYS_gettimeofday 24 /*x 78 - getuid (not implemented on WIN32) */
-#define SYS_times 25 /*X 43 - stime (Xtensa-specific implementation) */
-#define SYS_socket 26
-#define SYS_sendto 27
-#define SYS_recvfrom 28
-#define SYS_select_one 29 /* not compitible select, one file descriptor at the time */
-#define SYS_bind 30
-#define SYS_ioctl 31
-
-/*
- * Other...
- */
-#define SYS_iss_argc 1000 /* returns value of argc */
-#define SYS_iss_argv_size 1001 /* bytes needed for argv & arg strings */
-#define SYS_iss_set_argv 1002 /* saves argv & arg strings at given addr */
-
-/*
- * SIMCALLs for the ferret memory debugger. All are invoked by
- * libferret.a ... ( Xtensa/Target-Libs/ferret )
- */
-#define SYS_ferret 1010
-#define SYS_malloc 1011
-#define SYS_free 1012
-#define SYS_more_heap 1013
-#define SYS_no_heap 1014
-
-
-/*
- * Extra SIMCALLs for GDB:
- */
-#define SYS_gdb_break -1 /* invoked by XTOS on user exceptions if EPC points
- to a break.n/break, regardless of cause! */
-#define SYS_xmon_out -2 /* invoked by XMON: ... */
-#define SYS_xmon_in -3 /* invoked by XMON: ... */
-#define SYS_xmon_flush -4 /* invoked by XMON: ... */
-#define SYS_gdb_abort -5 /* invoked by XTOS in _xtos_panic() */
-#define SYS_gdb_illegal_inst -6 /* invoked by XTOS for illegal instructions (too deeply) */
-#define SYS_xmon_init -7 /* invoked by XMON: ... */
-#define SYS_gdb_enter_sktloop -8 /* invoked by XTOS on debug exceptions */
-
-/*
- * SIMCALLs for vxWorks xtiss BSP:
- */
-#define SYS_setup_ppp_pipes -83
-#define SYS_log_msg -84
-
-/*
- * Test SIMCALLs:
- */
-#define SYS_test_write_state -100
-#define SYS_test_read_state -101
-
-/*
- * SYS_select_one specifiers
- */
-#define XTISS_SELECT_ONE_READ 1
-#define XTISS_SELECT_ONE_WRITE 2
-#define XTISS_SELECT_ONE_EXCEPT 3
-
-#endif /* !SIMCALL_INCLUDED */
diff --git a/include/asm-xtensa/xtensa/xt2000-uart.h b/include/asm-xtensa/xtensa/xt2000-uart.h
deleted file mode 100644
index 0154460f0ed..00000000000
--- a/include/asm-xtensa/xtensa/xt2000-uart.h
+++ /dev/null
@@ -1,155 +0,0 @@
-#ifndef _uart_h_included_
-#define _uart_h_included_
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/xt2000-uart.h -- NatSemi PC16552D DUART
- * definitions
- *
- * 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) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/xt2000.h>
-
-
-/* 16550 UART DEVICE REGISTERS
- The XT2000 board aligns each register to a 32-bit word but the UART device only uses
- one byte of the word, which is the least-significant byte regardless of the
- endianness of the core (ie. byte offset 0 for little-endian and 3 for big-endian).
- So if using word accesses then endianness doesn't matter.
- The macros provided here do that.
-*/
-struct uart_dev_s {
- union {
- unsigned int rxb; /* DLAB=0: receive buffer, read-only */
- unsigned int txb; /* DLAB=0: transmit buffer, write-only */
- unsigned int dll; /* DLAB=1: divisor, least-significant byte latch (was write-only?) */
- } w0;
- union {
- unsigned int ier; /* DLAB=0: interrupt-enable register (was write-only?) */
- unsigned int dlm; /* DLAB=1: divisor, most-significant byte latch (was write-only?) */
- } w1;
-
- union {
- unsigned int isr; /* DLAB=0: interrupt status register, read-only */
- unsigned int fcr; /* DLAB=0: FIFO control register, write-only */
- unsigned int afr; /* DLAB=1: alternate function register */
- } w2;
-
- unsigned int lcr; /* line control-register, write-only */
- unsigned int mcr; /* modem control-regsiter, write-only */
- unsigned int lsr; /* line status register, read-only */
- unsigned int msr; /* modem status register, read-only */
- unsigned int scr; /* scratch regsiter, read/write */
-};
-
-#define _RXB(u) ((u)->w0.rxb)
-#define _TXB(u) ((u)->w0.txb)
-#define _DLL(u) ((u)->w0.dll)
-#define _IER(u) ((u)->w1.ier)
-#define _DLM(u) ((u)->w1.dlm)
-#define _ISR(u) ((u)->w2.isr)
-#define _FCR(u) ((u)->w2.fcr)
-#define _AFR(u) ((u)->w2.afr)
-#define _LCR(u) ((u)->lcr)
-#define _MCR(u) ((u)->mcr)
-#define _LSR(u) ((u)->lsr)
-#define _MSR(u) ((u)->msr)
-#define _SCR(u) ((u)->scr)
-
-typedef volatile struct uart_dev_s uart_dev_t;
-
-/* IER bits */
-#define RCVR_DATA_REG_INTENABLE 0x01
-#define XMIT_HOLD_REG_INTENABLE 0x02
-#define RCVR_STATUS_INTENABLE 0x04
-#define MODEM_STATUS_INTENABLE 0x08
-
-/* FCR bits */
-#define _FIFO_ENABLE 0x01
-#define RCVR_FIFO_RESET 0x02
-#define XMIT_FIFO_RESET 0x04
-#define DMA_MODE_SELECT 0x08
-#define RCVR_TRIGGER_LSB 0x40
-#define RCVR_TRIGGER_MSB 0x80
-
-/* AFR bits */
-#define AFR_CONC_WRITE 0x01
-#define AFR_BAUDOUT_SEL 0x02
-#define AFR_RXRDY_SEL 0x04
-
-/* ISR bits */
-#define INT_STATUS(r) ((r)&1)
-#define INT_PRIORITY(r) (((r)>>1)&0x7)
-
-/* LCR bits */
-#define WORD_LENGTH(n) (((n)-5)&0x3)
-#define STOP_BIT_ENABLE 0x04
-#define PARITY_ENABLE 0x08
-#define EVEN_PARITY 0x10
-#define FORCE_PARITY 0x20
-#define XMIT_BREAK 0x40
-#define DLAB_ENABLE 0x80
-
-/* MCR bits */
-#define _DTR 0x01
-#define _RTS 0x02
-#define _OP1 0x04
-#define _OP2 0x08
-#define LOOP_BACK 0x10
-
-/* LSR Bits */
-#define RCVR_DATA_READY 0x01
-#define OVERRUN_ERROR 0x02
-#define PARITY_ERROR 0x04
-#define FRAMING_ERROR 0x08
-#define BREAK_INTERRUPT 0x10
-#define XMIT_HOLD_EMPTY 0x20
-#define XMIT_EMPTY 0x40
-#define FIFO_ERROR 0x80
-#define RCVR_READY(u) (_LSR(u)&RCVR_DATA_READY)
-#define XMIT_READY(u) (_LSR(u)&XMIT_HOLD_EMPTY)
-
-/* MSR bits */
-#define _RDR 0x01
-#define DELTA_DSR 0x02
-#define DELTA_RI 0x04
-#define DELTA_CD 0x08
-#define _CTS 0x10
-#define _DSR 0x20
-#define _RI 0x40
-#define _CD 0x80
-
-/* prototypes */
-void uart_init( uart_dev_t *u, int bitrate );
-void uart_out( uart_dev_t *u, char c );
-void uart_puts( uart_dev_t *u, char *s );
-char uart_in( uart_dev_t *u );
-void uart_enable_rcvr_int( uart_dev_t *u );
-void uart_disable_rcvr_int( uart_dev_t *u );
-
-#ifdef DUART16552_1_VADDR
-/* DUART present. */
-#define DUART_1_BASE (*(uart_dev_t*)DUART16552_1_VADDR)
-#define DUART_2_BASE (*(uart_dev_t*)DUART16552_2_VADDR)
-#define UART1_PUTS(s) uart_puts( &DUART_1_BASE, s )
-#define UART2_PUTS(s) uart_puts( &DUART_2_BASE, s )
-#else
-/* DUART not configured, use dummy placeholders to allow compiles to work. */
-#define DUART_1_BASE (*(uart_dev_t*)0)
-#define DUART_2_BASE (*(uart_dev_t*)0)
-#define UART1_PUTS(s)
-#define UART2_PUTS(s)
-#endif
-
-/* Compute 16-bit divisor for baudrate generator, with rounding: */
-#define DUART_DIVISOR(crystal,speed) (((crystal)/16 + (speed)/2)/(speed))
-
-#endif /*_uart_h_included_*/
-
diff --git a/include/asm-xtensa/xtensa/xt2000.h b/include/asm-xtensa/xtensa/xt2000.h
deleted file mode 100644
index 703a45002f8..00000000000
--- a/include/asm-xtensa/xtensa/xt2000.h
+++ /dev/null
@@ -1,408 +0,0 @@
-#ifndef _INC_XT2000_H_
-#define _INC_XT2000_H_
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/xt2000.h - Definitions specific to the
- * Tensilica XT2000 Emulation 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.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/config/core.h>
-#include <xtensa/config/system.h>
-
-
-/*
- * Default assignment of XT2000 devices to external interrupts.
- */
-
-/* Ethernet interrupt: */
-#ifdef XCHAL_EXTINT3_NUM
-#define SONIC83934_INTNUM XCHAL_EXTINT3_NUM
-#define SONIC83934_INTLEVEL XCHAL_EXTINT3_LEVEL
-#define SONIC83934_INTMASK XCHAL_EXTINT3_MASK
-#else
-#define SONIC83934_INTMASK 0
-#endif
-
-/* DUART channel 1 interrupt (P1 - console): */
-#ifdef XCHAL_EXTINT4_NUM
-#define DUART16552_1_INTNUM XCHAL_EXTINT4_NUM
-#define DUART16552_1_INTLEVEL XCHAL_EXTINT4_LEVEL
-#define DUART16552_1_INTMASK XCHAL_EXTINT4_MASK
-#else
-#define DUART16552_1_INTMASK 0
-#endif
-
-/* DUART channel 2 interrupt (P2 - 2nd serial port): */
-#ifdef XCHAL_EXTINT5_NUM
-#define DUART16552_2_INTNUM XCHAL_EXTINT5_NUM
-#define DUART16552_2_INTLEVEL XCHAL_EXTINT5_LEVEL
-#define DUART16552_2_INTMASK XCHAL_EXTINT5_MASK
-#else
-#define DUART16552_2_INTMASK 0
-#endif
-
-/* FPGA-combined PCI/etc interrupts: */
-#ifdef XCHAL_EXTINT6_NUM
-#define XT2000_FPGAPCI_INTNUM XCHAL_EXTINT6_NUM
-#define XT2000_FPGAPCI_INTLEVEL XCHAL_EXTINT6_LEVEL
-#define XT2000_FPGAPCI_INTMASK XCHAL_EXTINT6_MASK
-#else
-#define XT2000_FPGAPCI_INTMASK 0
-#endif
-
-
-
-/*
- * Device addresses.
- *
- * Note: for endianness-independence, use 32-bit loads and stores for all
- * register accesses to Ethernet, DUART and LED devices. Undefined bits
- * may need to be masked out if needed when reading if the actual register
- * size is smaller than 32 bits.
- *
- * Note: XT2000 bus byte lanes are defined in terms of msbyte and lsbyte
- * relative to the processor. So 32-bit registers are accessed consistently
- * from both big and little endian processors. However, this means byte
- * sequences are not consistent between big and little endian processors.
- * This is fine for RAM, and for ROM if ROM is created for a specific
- * processor (and thus has correct byte sequences). However this may be
- * unexpected for Flash, which might contain a file-system that one wants
- * to use for multiple processor configurations (eg. the Flash might contain
- * the Ethernet card's address, endianness-independent application data, etc).
- * That is, byte sequences written in Flash by a core of a given endianness
- * will be byte-swapped when seen by a core of the other endianness.
- * Someone implementing an endianness-independent Flash file system will
- * likely handle this byte-swapping issue in the Flash driver software.
- */
-
-#define DUART16552_XTAL_FREQ 18432000 /* crystal frequency in Hz */
-#define XTBOARD_FLASH_MAXSIZE 0x4000000 /* 64 MB (max; depends on what is socketed!) */
-#define XTBOARD_EPROM_MAXSIZE 0x0400000 /* 4 MB (max; depends on what is socketed!) */
-#define XTBOARD_EEPROM_MAXSIZE 0x0080000 /* 512 kB (max; depends on what is socketed!) */
-#define XTBOARD_ASRAM_SIZE 0x0100000 /* 1 MB */
-#define XTBOARD_PCI_MEM_SIZE 0x8000000 /* 128 MB (allocated) */
-#define XTBOARD_PCI_IO_SIZE 0x1000000 /* 16 MB (allocated) */
-
-#ifdef XSHAL_IOBLOCK_BYPASS_PADDR
-/* PCI memory space: */
-# define XTBOARD_PCI_MEM_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0x0000000)
-/* Socketed Flash (eg. 2 x 16-bit devices): */
-# define XTBOARD_FLASH_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0x8000000)
-/* PCI I/O space: */
-# define XTBOARD_PCI_IO_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xC000000)
-/* V3 PCI interface chip register/config space: */
-# define XTBOARD_V3PCI_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD000000)
-/* Bus Interface registers: */
-# define XTBOARD_BUSINT_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD010000)
-/* FPGA registers: */
-# define XT2000_FPGAREGS_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD020000)
-/* SONIC SN83934 Ethernet controller/transceiver: */
-# define SONIC83934_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD030000)
-/* 8-character bitmapped LED display: */
-# define XTBOARD_LED_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD040000)
-/* National-Semi PC16552D DUART: */
-# define DUART16552_1_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD050020) /* channel 1 (P1 - console) */
-# define DUART16552_2_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD050000) /* channel 2 (P2) */
-/* Asynchronous Static RAM: */
-# define XTBOARD_ASRAM_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD400000)
-/* 8-bit EEPROM: */
-# define XTBOARD_EEPROM_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD600000)
-/* 2 x 16-bit EPROMs: */
-# define XTBOARD_EPROM_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD800000)
-#endif /* XSHAL_IOBLOCK_BYPASS_PADDR */
-
-/* These devices might be accessed cached: */
-#ifdef XSHAL_IOBLOCK_CACHED_PADDR
-# define XTBOARD_PCI_MEM_CACHED_PADDR (XSHAL_IOBLOCK_CACHED_PADDR+0x0000000)
-# define XTBOARD_FLASH_CACHED_PADDR (XSHAL_IOBLOCK_CACHED_PADDR+0x8000000)
-# define XTBOARD_ASRAM_CACHED_PADDR (XSHAL_IOBLOCK_CACHED_PADDR+0xD400000)
-# define XTBOARD_EEPROM_CACHED_PADDR (XSHAL_IOBLOCK_CACHED_PADDR+0xD600000)
-# define XTBOARD_EPROM_CACHED_PADDR (XSHAL_IOBLOCK_CACHED_PADDR+0xD800000)
-#endif /* XSHAL_IOBLOCK_CACHED_PADDR */
-
-
-/*** Same thing over again, this time with virtual addresses: ***/
-
-#ifdef XSHAL_IOBLOCK_BYPASS_VADDR
-/* PCI memory space: */
-# define XTBOARD_PCI_MEM_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0x0000000)
-/* Socketed Flash (eg. 2 x 16-bit devices): */
-# define XTBOARD_FLASH_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0x8000000)
-/* PCI I/O space: */
-# define XTBOARD_PCI_IO_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xC000000)
-/* V3 PCI interface chip register/config space: */
-# define XTBOARD_V3PCI_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD000000)
-/* Bus Interface registers: */
-# define XTBOARD_BUSINT_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD010000)
-/* FPGA registers: */
-# define XT2000_FPGAREGS_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD020000)
-/* SONIC SN83934 Ethernet controller/transceiver: */
-# define SONIC83934_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD030000)
-/* 8-character bitmapped LED display: */
-# define XTBOARD_LED_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD040000)
-/* National-Semi PC16552D DUART: */
-# define DUART16552_1_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD050020) /* channel 1 (P1 - console) */
-# define DUART16552_2_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD050000) /* channel 2 (P2) */
-/* Asynchronous Static RAM: */
-# define XTBOARD_ASRAM_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD400000)
-/* 8-bit EEPROM: */
-# define XTBOARD_EEPROM_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD600000)
-/* 2 x 16-bit EPROMs: */
-# define XTBOARD_EPROM_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD800000)
-#endif /* XSHAL_IOBLOCK_BYPASS_VADDR */
-
-/* These devices might be accessed cached: */
-#ifdef XSHAL_IOBLOCK_CACHED_VADDR
-# define XTBOARD_PCI_MEM_CACHED_VADDR (XSHAL_IOBLOCK_CACHED_VADDR+0x0000000)
-# define XTBOARD_FLASH_CACHED_VADDR (XSHAL_IOBLOCK_CACHED_VADDR+0x8000000)
-# define XTBOARD_ASRAM_CACHED_VADDR (XSHAL_IOBLOCK_CACHED_VADDR+0xD400000)
-# define XTBOARD_EEPROM_CACHED_VADDR (XSHAL_IOBLOCK_CACHED_VADDR+0xD600000)
-# define XTBOARD_EPROM_CACHED_VADDR (XSHAL_IOBLOCK_CACHED_VADDR+0xD800000)
-#endif /* XSHAL_IOBLOCK_CACHED_VADDR */
-
-
-/* System ROM: */
-#define XTBOARD_ROM_SIZE XSHAL_ROM_SIZE
-#ifdef XSHAL_ROM_VADDR
-#define XTBOARD_ROM_VADDR XSHAL_ROM_VADDR
-#endif
-#ifdef XSHAL_ROM_PADDR
-#define XTBOARD_ROM_PADDR XSHAL_ROM_PADDR
-#endif
-
-/* System RAM: */
-#define XTBOARD_RAM_SIZE XSHAL_RAM_SIZE
-#ifdef XSHAL_RAM_VADDR
-#define XTBOARD_RAM_VADDR XSHAL_RAM_VADDR
-#endif
-#ifdef XSHAL_RAM_PADDR
-#define XTBOARD_RAM_PADDR XSHAL_RAM_PADDR
-#endif
-#define XTBOARD_RAM_BYPASS_VADDR XSHAL_RAM_BYPASS_VADDR
-#define XTBOARD_RAM_BYPASS_PADDR XSHAL_RAM_BYPASS_PADDR
-
-
-
-/*
- * Things that depend on device addresses.
- */
-
-
-#define XTBOARD_CACHEATTR_WRITEBACK XSHAL_XT2000_CACHEATTR_WRITEBACK
-#define XTBOARD_CACHEATTR_WRITEALLOC XSHAL_XT2000_CACHEATTR_WRITEALLOC
-#define XTBOARD_CACHEATTR_WRITETHRU XSHAL_XT2000_CACHEATTR_WRITETHRU
-#define XTBOARD_CACHEATTR_BYPASS XSHAL_XT2000_CACHEATTR_BYPASS
-#define XTBOARD_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_DEFAULT
-
-#define XTBOARD_BUSINT_PIPE_REGIONS XSHAL_XT2000_PIPE_REGIONS
-#define XTBOARD_BUSINT_SDRAM_REGIONS XSHAL_XT2000_SDRAM_REGIONS
-
-
-
-/*
- * BusLogic (FPGA) registers.
- * All these registers are normally accessed using 32-bit loads/stores.
- */
-
-/* Register offsets: */
-#define XT2000_DATECD_OFS 0x00 /* date code (read-only) */
-#define XT2000_STSREG_OFS 0x04 /* status (read-only) */
-#define XT2000_SYSLED_OFS 0x08 /* system LED */
-#define XT2000_WRPROT_OFS 0x0C /* write protect */
-#define XT2000_SWRST_OFS 0x10 /* software reset */
-#define XT2000_SYSRST_OFS 0x14 /* system (peripherals) reset */
-#define XT2000_IMASK_OFS 0x18 /* interrupt mask */
-#define XT2000_ISTAT_OFS 0x1C /* interrupt status */
-#define XT2000_V3CFG_OFS 0x20 /* V3 config (V320 PCI) */
-
-/* Physical register addresses: */
-#ifdef XT2000_FPGAREGS_PADDR
-#define XT2000_DATECD_PADDR (XT2000_FPGAREGS_PADDR+XT2000_DATECD_OFS)
-#define XT2000_STSREG_PADDR (XT2000_FPGAREGS_PADDR+XT2000_STSREG_OFS)
-#define XT2000_SYSLED_PADDR (XT2000_FPGAREGS_PADDR+XT2000_SYSLED_OFS)
-#define XT2000_WRPROT_PADDR (XT2000_FPGAREGS_PADDR+XT2000_WRPROT_OFS)
-#define XT2000_SWRST_PADDR (XT2000_FPGAREGS_PADDR+XT2000_SWRST_OFS)
-#define XT2000_SYSRST_PADDR (XT2000_FPGAREGS_PADDR+XT2000_SYSRST_OFS)
-#define XT2000_IMASK_PADDR (XT2000_FPGAREGS_PADDR+XT2000_IMASK_OFS)
-#define XT2000_ISTAT_PADDR (XT2000_FPGAREGS_PADDR+XT2000_ISTAT_OFS)
-#define XT2000_V3CFG_PADDR (XT2000_FPGAREGS_PADDR+XT2000_V3CFG_OFS)
-#endif
-
-/* Virtual register addresses: */
-#ifdef XT2000_FPGAREGS_VADDR
-#define XT2000_DATECD_VADDR (XT2000_FPGAREGS_VADDR+XT2000_DATECD_OFS)
-#define XT2000_STSREG_VADDR (XT2000_FPGAREGS_VADDR+XT2000_STSREG_OFS)
-#define XT2000_SYSLED_VADDR (XT2000_FPGAREGS_VADDR+XT2000_SYSLED_OFS)
-#define XT2000_WRPROT_VADDR (XT2000_FPGAREGS_VADDR+XT2000_WRPROT_OFS)
-#define XT2000_SWRST_VADDR (XT2000_FPGAREGS_VADDR+XT2000_SWRST_OFS)
-#define XT2000_SYSRST_VADDR (XT2000_FPGAREGS_VADDR+XT2000_SYSRST_OFS)
-#define XT2000_IMASK_VADDR (XT2000_FPGAREGS_VADDR+XT2000_IMASK_OFS)
-#define XT2000_ISTAT_VADDR (XT2000_FPGAREGS_VADDR+XT2000_ISTAT_OFS)
-#define XT2000_V3CFG_VADDR (XT2000_FPGAREGS_VADDR+XT2000_V3CFG_OFS)
-/* Register access (for C code): */
-#define XT2000_DATECD_REG (*(volatile unsigned*) XT2000_DATECD_VADDR)
-#define XT2000_STSREG_REG (*(volatile unsigned*) XT2000_STSREG_VADDR)
-#define XT2000_SYSLED_REG (*(volatile unsigned*) XT2000_SYSLED_VADDR)
-#define XT2000_WRPROT_REG (*(volatile unsigned*) XT2000_WRPROT_VADDR)
-#define XT2000_SWRST_REG (*(volatile unsigned*) XT2000_SWRST_VADDR)
-#define XT2000_SYSRST_REG (*(volatile unsigned*) XT2000_SYSRST_VADDR)
-#define XT2000_IMASK_REG (*(volatile unsigned*) XT2000_IMASK_VADDR)
-#define XT2000_ISTAT_REG (*(volatile unsigned*) XT2000_ISTAT_VADDR)
-#define XT2000_V3CFG_REG (*(volatile unsigned*) XT2000_V3CFG_VADDR)
-#endif
-
-/* DATECD (date code) bit fields: */
-
-/* BCD-coded month (01..12): */
-#define XT2000_DATECD_MONTH_SHIFT 24
-#define XT2000_DATECD_MONTH_BITS 8
-#define XT2000_DATECD_MONTH_MASK 0xFF000000
-/* BCD-coded day (01..31): */
-#define XT2000_DATECD_DAY_SHIFT 16
-#define XT2000_DATECD_DAY_BITS 8
-#define XT2000_DATECD_DAY_MASK 0x00FF0000
-/* BCD-coded year (2001..9999): */
-#define XT2000_DATECD_YEAR_SHIFT 0
-#define XT2000_DATECD_YEAR_BITS 16
-#define XT2000_DATECD_YEAR_MASK 0x0000FFFF
-
-/* STSREG (status) bit fields: */
-
-/* Switch SW3 setting bit fields (0=off/up, 1=on/down): */
-#define XT2000_STSREG_SW3_SHIFT 0
-#define XT2000_STSREG_SW3_BITS 4
-#define XT2000_STSREG_SW3_MASK 0x0000000F
-/* Boot-select bits of switch SW3: */
-#define XT2000_STSREG_BOOTSEL_SHIFT 0
-#define XT2000_STSREG_BOOTSEL_BITS 2
-#define XT2000_STSREG_BOOTSEL_MASK 0x00000003
-/* Boot-select values: */
-#define XT2000_STSREG_BOOTSEL_FLASH 0
-#define XT2000_STSREG_BOOTSEL_EPROM16 1
-#define XT2000_STSREG_BOOTSEL_PROM8 2
-#define XT2000_STSREG_BOOTSEL_ASRAM 3
-/* User-defined bits of switch SW3: */
-#define XT2000_STSREG_SW3_2_SHIFT 2
-#define XT2000_STSREG_SW3_2_MASK 0x00000004
-#define XT2000_STSREG_SW3_3_SHIFT 3
-#define XT2000_STSREG_SW3_3_MASK 0x00000008
-
-/* SYSLED (system LED) bit fields: */
-
-/* LED control bit (0=off, 1=on): */
-#define XT2000_SYSLED_LEDON_SHIFT 0
-#define XT2000_SYSLED_LEDON_MASK 0x00000001
-
-/* WRPROT (write protect) bit fields (0=writable, 1=write-protected [default]): */
-
-/* Flash write protect: */
-#define XT2000_WRPROT_FLWP_SHIFT 0
-#define XT2000_WRPROT_FLWP_MASK 0x00000001
-/* Reserved but present write protect bits: */
-#define XT2000_WRPROT_WRP_SHIFT 1
-#define XT2000_WRPROT_WRP_BITS 7
-#define XT2000_WRPROT_WRP_MASK 0x000000FE
-
-/* SWRST (software reset; allows s/w to generate power-on equivalent reset): */
-
-/* Software reset bits: */
-#define XT2000_SWRST_SWR_SHIFT 0
-#define XT2000_SWRST_SWR_BITS 16
-#define XT2000_SWRST_SWR_MASK 0x0000FFFF
-/* Software reset value -- writing this value resets the board: */
-#define XT2000_SWRST_RESETVALUE 0x0000DEAD
-
-/* SYSRST (system reset; controls reset of individual peripherals): */
-
-/* All-device reset: */
-#define XT2000_SYSRST_ALL_SHIFT 0
-#define XT2000_SYSRST_ALL_BITS 4
-#define XT2000_SYSRST_ALL_MASK 0x0000000F
-/* HDSP-2534 LED display reset (1=reset, 0=nothing): */
-#define XT2000_SYSRST_LED_SHIFT 0
-#define XT2000_SYSRST_LED_MASK 0x00000001
-/* Sonic DP83934 Ethernet controller reset (1=reset, 0=nothing): */
-#define XT2000_SYSRST_SONIC_SHIFT 1
-#define XT2000_SYSRST_SONIC_MASK 0x00000002
-/* DP16552 DUART reset (1=reset, 0=nothing): */
-#define XT2000_SYSRST_DUART_SHIFT 2
-#define XT2000_SYSRST_DUART_MASK 0x00000004
-/* V3 V320 PCI bridge controller reset (1=reset, 0=nothing): */
-#define XT2000_SYSRST_V3_SHIFT 3
-#define XT2000_SYSRST_V3_MASK 0x00000008
-
-/* IMASK (interrupt mask; 0=disable, 1=enable): */
-/* ISTAT (interrupt status; 0=inactive, 1=pending): */
-
-/* PCI INTP interrupt: */
-#define XT2000_INTMUX_PCI_INTP_SHIFT 2
-#define XT2000_INTMUX_PCI_INTP_MASK 0x00000004
-/* PCI INTS interrupt: */
-#define XT2000_INTMUX_PCI_INTS_SHIFT 3
-#define XT2000_INTMUX_PCI_INTS_MASK 0x00000008
-/* PCI INTD interrupt: */
-#define XT2000_INTMUX_PCI_INTD_SHIFT 4
-#define XT2000_INTMUX_PCI_INTD_MASK 0x00000010
-/* V320 PCI controller interrupt: */
-#define XT2000_INTMUX_V3_SHIFT 5
-#define XT2000_INTMUX_V3_MASK 0x00000020
-/* PCI ENUM interrupt: */
-#define XT2000_INTMUX_PCI_ENUM_SHIFT 6
-#define XT2000_INTMUX_PCI_ENUM_MASK 0x00000040
-/* PCI DEG interrupt: */
-#define XT2000_INTMUX_PCI_DEG_SHIFT 7
-#define XT2000_INTMUX_PCI_DEG_MASK 0x00000080
-
-/* V3CFG (V3 config, V320 PCI controller): */
-
-/* V3 address control (0=pass-thru, 1=V3 address bits 31:28 set to 4'b0001 [default]): */
-#define XT2000_V3CFG_V3ADC_SHIFT 0
-#define XT2000_V3CFG_V3ADC_MASK 0x00000001
-
-/* I2C Devices */
-
-#define XT2000_I2C_RTC_ID 0x68
-#define XT2000_I2C_NVRAM0_ID 0x56 /* 1st 256 byte block */
-#define XT2000_I2C_NVRAM1_ID 0x57 /* 2nd 256 byte block */
-
-/* NVRAM Board Info structure: */
-
-#define XT2000_NVRAM_SIZE 512
-
-#define XT2000_NVRAM_BINFO_START 0x100
-#define XT2000_NVRAM_BINFO_SIZE 0x20
-#define XT2000_NVRAM_BINFO_VERSION 0x10 /* version 1.0 */
-#if 0
-#define XT2000_NVRAM_BINFO_VERSION_OFFSET 0x00
-#define XT2000_NVRAM_BINFO_VERSION_SIZE 0x1
-#define XT2000_NVRAM_BINFO_ETH_ADDR_OFFSET 0x02
-#define XT2000_NVRAM_BINFO_ETH_ADDR_SIZE 0x6
-#define XT2000_NVRAM_BINFO_SN_OFFSET 0x10
-#define XT2000_NVRAM_BINFO_SN_SIZE 0xE
-#define XT2000_NVRAM_BINFO_CRC_OFFSET 0x1E
-#define XT2000_NVRAM_BINFO_CRC_SIZE 0x2
-#endif /*0*/
-
-#if !defined(__ASSEMBLY__) && !defined(_NOCLANGUAGE)
-typedef struct xt2000_nvram_binfo {
- unsigned char version;
- unsigned char reserved1;
- unsigned char eth_addr[6];
- unsigned char reserved8[8];
- unsigned char serialno[14];
- unsigned char crc[2]; /* 16-bit CRC */
-} xt2000_nvram_binfo;
-#endif /*!__ASSEMBLY__ && !_NOCLANGUAGE*/
-
-
-#endif /*_INC_XT2000_H_*/
-
diff --git a/include/asm-xtensa/xtensa/xtboard.h b/include/asm-xtensa/xtensa/xtboard.h
deleted file mode 100644
index 22469c17530..00000000000
--- a/include/asm-xtensa/xtensa/xtboard.h
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifndef _xtboard_h_included_
-#define _xtboard_h_included_
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * xtboard.h -- Routines for getting useful information from the 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.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/xt2000.h>
-
-#define XTBOARD_RTC_ERROR -1
-#define XTBOARD_RTC_STOPPED -2
-
-
-/* xt2000-i2cdev.c: */
-typedef void XtboardDelayFunc( unsigned );
-extern XtboardDelayFunc* xtboard_set_nsdelay_func( XtboardDelayFunc *delay_fn );
-extern int xtboard_i2c_read (unsigned id, unsigned char *buf, unsigned addr, unsigned size);
-extern int xtboard_i2c_write(unsigned id, unsigned char *buf, unsigned addr, unsigned size);
-extern int xtboard_i2c_wait_nvram_ack(unsigned id, unsigned swtimer);
-
-/* xtboard.c: */
-extern int xtboard_nvram_read (unsigned addr, unsigned len, unsigned char *buf);
-extern int xtboard_nvram_write(unsigned addr, unsigned len, unsigned char *buf);
-extern int xtboard_nvram_binfo_read (xt2000_nvram_binfo *buf);
-extern int xtboard_nvram_binfo_write(xt2000_nvram_binfo *buf);
-extern int xtboard_nvram_binfo_valid(xt2000_nvram_binfo *buf);
-extern int xtboard_ethermac_get(unsigned char *buf);
-extern int xtboard_ethermac_set(unsigned char *buf);
-
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_get_rtc_time
-/
-/ Description: Get time stored in real-time clock.
-/
-/ Returns: time in seconds stored in real-time clock.
-/-**----------------------------------------------------------------------------*/
-
-extern unsigned xtboard_get_rtc_time(void);
-
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_set_rtc_time
-/
-/ Description: Set time stored in real-time clock.
-/
-/ Parameters: time -- time in seconds to store to real-time clock
-/
-/ Returns: 0 on success, xtboard_i2c_write() error code otherwise.
-/-**----------------------------------------------------------------------------*/
-
-extern int xtboard_set_rtc_time(unsigned time);
-
-
-/* xtfreq.c: */
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_measure_sys_clk
-/
-/ Description: Get frequency of system clock.
-/
-/ Parameters: none
-/
-/ Returns: frequency of system clock.
-/-**----------------------------------------------------------------------------*/
-
-extern unsigned xtboard_measure_sys_clk(void);
-
-
-#if 0 /* old stuff from xtboard.c: */
-
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_nvram valid
-/
-/ Description: Determines if data in NVRAM is valid.
-/
-/ Parameters: delay -- 10us delay function
-/
-/ Returns: 1 if NVRAM is valid, 0 otherwise
-/-**----------------------------------------------------------------------------*/
-
-extern unsigned xtboard_nvram_valid(void (*delay)( void ));
-
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_get_nvram_contents
-/
-/ Description: Returns contents of NVRAM.
-/
-/ Parameters: buf -- buffer to NVRAM contents.
-/ delay -- 10us delay function
-/
-/ Returns: 1 if NVRAM is valid, 0 otherwise
-/-**----------------------------------------------------------------------------*/
-
-extern unsigned xtboard_get_nvram_contents(unsigned char *buf, void (*delay)( void ));
-
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_get_ether_addr
-/
-/ Description: Returns ethernet address of board.
-/
-/ Parameters: buf -- buffer to store ethernet address
-/ delay -- 10us delay function
-/
-/ Returns: nothing.
-/-**----------------------------------------------------------------------------*/
-
-extern void xtboard_get_ether_addr(unsigned char *buf, void (*delay)( void ));
-
-#endif /*0*/
-
-
-#endif /*_xtboard_h_included_*/
-
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 5748aecdb41..4e05e93ff68 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -18,8 +18,8 @@ struct module;
struct seq_file;
struct crypto_type {
- unsigned int (*ctxsize)(struct crypto_alg *alg);
- int (*init)(struct crypto_tfm *tfm);
+ unsigned int (*ctxsize)(struct crypto_alg *alg, u32 type, u32 mask);
+ int (*init)(struct crypto_tfm *tfm, u32 type, u32 mask);
void (*exit)(struct crypto_tfm *tfm);
void (*show)(struct seq_file *m, struct crypto_alg *alg);
};
@@ -93,7 +93,8 @@ struct crypto_template *crypto_lookup_template(const char *name);
int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
struct crypto_instance *inst);
void crypto_drop_spawn(struct crypto_spawn *spawn);
-struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn);
+struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
+ u32 mask);
struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len,
u32 type, u32 mask);
@@ -132,11 +133,28 @@ static inline void *crypto_blkcipher_ctx_aligned(struct crypto_blkcipher *tfm)
return crypto_tfm_ctx_aligned(&tfm->base);
}
+static inline struct crypto_cipher *crypto_spawn_cipher(
+ struct crypto_spawn *spawn)
+{
+ u32 type = CRYPTO_ALG_TYPE_CIPHER;
+ u32 mask = CRYPTO_ALG_TYPE_MASK;
+
+ return __crypto_cipher_cast(crypto_spawn_tfm(spawn, type, mask));
+}
+
static inline struct cipher_alg *crypto_cipher_alg(struct crypto_cipher *tfm)
{
return &crypto_cipher_tfm(tfm)->__crt_alg->cra_cipher;
}
+static inline struct crypto_hash *crypto_spawn_hash(struct crypto_spawn *spawn)
+{
+ u32 type = CRYPTO_ALG_TYPE_HASH;
+ u32 mask = CRYPTO_ALG_TYPE_HASH_MASK;
+
+ return __crypto_hash_cast(crypto_spawn_tfm(spawn, type, mask));
+}
+
static inline void *crypto_hash_ctx_aligned(struct crypto_hash *tfm)
{
return crypto_tfm_ctx_aligned(&tfm->base);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index e618b25b5ad..683513e310d 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -11,6 +11,7 @@ header-y += netfilter_arp/
header-y += netfilter_bridge/
header-y += netfilter_ipv4/
header-y += netfilter_ipv6/
+header-y += usb/
header-y += affs_hardblocks.h
header-y += aio_abi.h
@@ -61,7 +62,6 @@ header-y += fd.h
header-y += fdreg.h
header-y += fib_rules.h
header-y += fuse.h
-header-y += futex.h
header-y += genetlink.h
header-y += gen_stats.h
header-y += gigaset_dev.h
@@ -70,7 +70,6 @@ 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
@@ -80,7 +79,6 @@ 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
@@ -120,7 +118,6 @@ 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
header-y += personality.h
header-y += pfkeyv2.h
@@ -131,7 +128,6 @@ header-y += posix_types.h
header-y += ppdev.h
header-y += prctl.h
header-y += ps2esdi.h
-header-y += qic117.h
header-y += qnxtypes.h
header-y += quotaio_v1.h
header-y += quotaio_v2.h
@@ -139,7 +135,6 @@ header-y += radeonfb.h
header-y += raw.h
header-y += resource.h
header-y += rose.h
-header-y += sctp.h
header-y += smbno.h
header-y += snmp.h
header-y += sockios.h
@@ -163,7 +158,6 @@ header-y += vt.h
header-y += wireless.h
header-y += xattr.h
header-y += x25.h
-header-y += zorro_ids.h
unifdef-y += acct.h
unifdef-y += adb.h
@@ -203,6 +197,7 @@ unifdef-y += fb.h
unifdef-y += fcntl.h
unifdef-y += filter.h
unifdef-y += flat.h
+unifdef-y += futex.h
unifdef-y += fs.h
unifdef-y += gameport.h
unifdef-y += generic_serial.h
@@ -217,6 +212,7 @@ unifdef-y += hpet.h
unifdef-y += i2c.h
unifdef-y += i2o-dev.h
unifdef-y += icmpv6.h
+unifdef-y += if_addr.h
unifdef-y += if_bridge.h
unifdef-y += if_ec.h
unifdef-y += if_eql.h
@@ -224,6 +220,7 @@ unifdef-y += if_ether.h
unifdef-y += if_fddi.h
unifdef-y += if_frad.h
unifdef-y += if_ltalk.h
+unifdef-y += if_link.h
unifdef-y += if_pppox.h
unifdef-y += if_shaper.h
unifdef-y += if_tr.h
@@ -330,7 +327,6 @@ unifdef-y += udp.h
unifdef-y += uinput.h
unifdef-y += uio.h
unifdef-y += unistd.h
-unifdef-y += usb_ch9.h
unifdef-y += usbdevice_fs.h
unifdef-y += user.h
unifdef-y += utsname.h
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 2b0c955590f..815f1fb4ce2 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -47,171 +47,12 @@ enum acpi_irq_model_id {
ACPI_IRQ_MODEL_PIC = 0,
ACPI_IRQ_MODEL_IOAPIC,
ACPI_IRQ_MODEL_IOSAPIC,
+ ACPI_IRQ_MODEL_PLATFORM,
ACPI_IRQ_MODEL_COUNT
};
extern enum acpi_irq_model_id acpi_irq_model;
-
-/* Root System Description Pointer (RSDP) */
-
-struct acpi_table_rsdp {
- char signature[8];
- u8 checksum;
- char oem_id[6];
- u8 revision;
- u32 rsdt_address;
-} __attribute__ ((packed));
-
-struct acpi20_table_rsdp {
- char signature[8];
- u8 checksum;
- char oem_id[6];
- u8 revision;
- u32 rsdt_address;
- u32 length;
- u64 xsdt_address;
- u8 ext_checksum;
- u8 reserved[3];
-} __attribute__ ((packed));
-
-typedef struct {
- u8 type;
- u8 length;
-} __attribute__ ((packed)) acpi_table_entry_header;
-
-/* Root System Description Table (RSDT) */
-
-struct acpi_table_rsdt {
- struct acpi_table_header header;
- u32 entry[8];
-} __attribute__ ((packed));
-
-/* Extended System Description Table (XSDT) */
-
-struct acpi_table_xsdt {
- struct acpi_table_header header;
- u64 entry[1];
-} __attribute__ ((packed));
-
-/* Fixed ACPI Description Table (FADT) */
-
-struct acpi_table_fadt {
- struct acpi_table_header header;
- u32 facs_addr;
- u32 dsdt_addr;
- /* ... */
-} __attribute__ ((packed));
-
-/* Multiple APIC Description Table (MADT) */
-
-struct acpi_table_madt {
- struct acpi_table_header header;
- u32 lapic_address;
- struct {
- u32 pcat_compat:1;
- u32 reserved:31;
- } flags;
-} __attribute__ ((packed));
-
-enum acpi_madt_entry_id {
- ACPI_MADT_LAPIC = 0,
- ACPI_MADT_IOAPIC,
- ACPI_MADT_INT_SRC_OVR,
- ACPI_MADT_NMI_SRC,
- ACPI_MADT_LAPIC_NMI,
- ACPI_MADT_LAPIC_ADDR_OVR,
- ACPI_MADT_IOSAPIC,
- ACPI_MADT_LSAPIC,
- ACPI_MADT_PLAT_INT_SRC,
- ACPI_MADT_ENTRY_COUNT
-};
-
-typedef struct {
- u16 polarity:2;
- u16 trigger:2;
- u16 reserved:12;
-} __attribute__ ((packed)) acpi_interrupt_flags;
-
-struct acpi_table_lapic {
- acpi_table_entry_header header;
- u8 acpi_id;
- u8 id;
- struct {
- u32 enabled:1;
- u32 reserved:31;
- } flags;
-} __attribute__ ((packed));
-
-struct acpi_table_ioapic {
- acpi_table_entry_header header;
- u8 id;
- u8 reserved;
- u32 address;
- u32 global_irq_base;
-} __attribute__ ((packed));
-
-struct acpi_table_int_src_ovr {
- acpi_table_entry_header header;
- u8 bus;
- u8 bus_irq;
- u32 global_irq;
- acpi_interrupt_flags flags;
-} __attribute__ ((packed));
-
-struct acpi_table_nmi_src {
- acpi_table_entry_header header;
- acpi_interrupt_flags flags;
- u32 global_irq;
-} __attribute__ ((packed));
-
-struct acpi_table_lapic_nmi {
- acpi_table_entry_header header;
- u8 acpi_id;
- acpi_interrupt_flags flags;
- u8 lint;
-} __attribute__ ((packed));
-
-struct acpi_table_lapic_addr_ovr {
- acpi_table_entry_header header;
- u8 reserved[2];
- u64 address;
-} __attribute__ ((packed));
-
-struct acpi_table_iosapic {
- acpi_table_entry_header header;
- u8 id;
- u8 reserved;
- u32 global_irq_base;
- u64 address;
-} __attribute__ ((packed));
-
-struct acpi_table_lsapic {
- acpi_table_entry_header header;
- u8 acpi_id;
- u8 id;
- u8 eid;
- u8 reserved[3];
- struct {
- u32 enabled:1;
- u32 reserved:31;
- } flags;
-} __attribute__ ((packed));
-
-struct acpi_table_plat_int_src {
- acpi_table_entry_header header;
- acpi_interrupt_flags flags;
- u8 type; /* See acpi_interrupt_type */
- u8 id;
- u8 eid;
- u8 iosapic_vector;
- u32 global_irq;
- struct {
- u32 cpei_override_flag:1;
- u32 reserved:31;
- } plint_flags;
-} __attribute__ ((packed));
-
enum acpi_interrupt_id {
ACPI_INTERRUPT_PMI = 1,
ACPI_INTERRUPT_INIT,
@@ -221,89 +62,6 @@ enum acpi_interrupt_id {
#define ACPI_SPACE_MEM 0
-struct acpi_gen_regaddr {
- u8 space_id;
- u8 bit_width;
- u8 bit_offset;
- u8 resv;
- u32 addrl;
- u32 addrh;
-} __attribute__ ((packed));
-
-struct acpi_table_hpet {
- struct acpi_table_header header;
- u32 id;
- struct acpi_gen_regaddr addr;
- u8 number;
- u16 min_tick;
- u8 page_protect;
-} __attribute__ ((packed));
-
-/*
- * Simple Boot Flags
- * http://www.microsoft.com/whdc/hwdev/resources/specs/simp_bios.mspx
- */
-struct acpi_table_sbf
-{
- u8 sbf_signature[4];
- u32 sbf_len;
- u8 sbf_revision;
- u8 sbf_csum;
- u8 sbf_oemid[6];
- u8 sbf_oemtable[8];
- u8 sbf_revdata[4];
- u8 sbf_creator[4];
- u8 sbf_crearev[4];
- u8 sbf_cmos;
- u8 sbf_spare[3];
-} __attribute__ ((packed));
-
-/*
- * System Resource Affinity Table (SRAT)
- * http://www.microsoft.com/whdc/hwdev/platform/proc/SRAT.mspx
- */
-
-struct acpi_table_srat {
- struct acpi_table_header header;
- u32 table_revision;
- u64 reserved;
-} __attribute__ ((packed));
-
-enum acpi_srat_entry_id {
- ACPI_SRAT_PROCESSOR_AFFINITY = 0,
- ACPI_SRAT_MEMORY_AFFINITY,
- ACPI_SRAT_ENTRY_COUNT
-};
-
-struct acpi_table_processor_affinity {
- acpi_table_entry_header header;
- u8 proximity_domain;
- u8 apic_id;
- struct {
- u32 enabled:1;
- u32 reserved:31;
- } flags;
- u8 lsapic_eid;
- u8 reserved[7];
-} __attribute__ ((packed));
-
-struct acpi_table_memory_affinity {
- acpi_table_entry_header header;
- u8 proximity_domain;
- u8 reserved1[5];
- u32 base_addr_lo;
- u32 base_addr_hi;
- u32 length_lo;
- u32 length_hi;
- u32 memory_type; /* See acpi_address_range_id */
- struct {
- u32 enabled:1;
- u32 hot_pluggable:1;
- u32 reserved:30;
- } flags;
- u64 reserved2;
-} __attribute__ ((packed));
-
enum acpi_address_range_id {
ACPI_ADDRESS_RANGE_MEMORY = 1,
ACPI_ADDRESS_RANGE_RESERVED = 2,
@@ -312,84 +70,12 @@ enum acpi_address_range_id {
ACPI_ADDRESS_RANGE_COUNT
};
-/*
- * System Locality Information Table (SLIT)
- * see http://devresource.hp.com/devresource/docs/techpapers/ia64/slit.pdf
- */
-
-struct acpi_table_slit {
- struct acpi_table_header header;
- u64 localities;
- u8 entry[1]; /* real size = localities^2 */
-} __attribute__ ((packed));
-
-/* Smart Battery Description Table (SBST) */
-
-struct acpi_table_sbst {
- struct acpi_table_header header;
- u32 warning; /* Warn user */
- u32 low; /* Critical sleep */
- u32 critical; /* Critical shutdown */
-} __attribute__ ((packed));
-
-/* Embedded Controller Boot Resources Table (ECDT) */
-
-struct acpi_table_ecdt {
- struct acpi_table_header header;
- struct acpi_generic_address ec_control;
- struct acpi_generic_address ec_data;
- u32 uid;
- u8 gpe_bit;
- char ec_id[0];
-} __attribute__ ((packed));
-
-/* PCI MMCONFIG */
-
-/* Defined in PCI Firmware Specification 3.0 */
-struct acpi_table_mcfg_config {
- u32 base_address;
- u32 base_reserved;
- u16 pci_segment_group_number;
- u8 start_bus_number;
- u8 end_bus_number;
- u8 reserved[4];
-} __attribute__ ((packed));
-struct acpi_table_mcfg {
- struct acpi_table_header header;
- u8 reserved[8];
- struct acpi_table_mcfg_config config[0];
-} __attribute__ ((packed));
/* Table Handlers */
-enum acpi_table_id {
- ACPI_TABLE_UNKNOWN = 0,
- ACPI_APIC,
- ACPI_BOOT,
- ACPI_DBGP,
- ACPI_DSDT,
- ACPI_ECDT,
- ACPI_ETDT,
- ACPI_FADT,
- ACPI_FACS,
- ACPI_OEMX,
- ACPI_PSDT,
- ACPI_SBST,
- ACPI_SLIT,
- ACPI_SPCR,
- ACPI_SRAT,
- ACPI_SSDT,
- ACPI_SPMI,
- ACPI_HPET,
- ACPI_MCFG,
- ACPI_TABLE_COUNT
-};
-
-typedef int (*acpi_table_handler) (unsigned long phys_addr, unsigned long size);
-
-extern acpi_table_handler acpi_table_ops[ACPI_TABLE_COUNT];
+typedef int (*acpi_table_handler) (struct acpi_table_header *table);
-typedef int (*acpi_madt_entry_handler) (acpi_table_entry_header *header, const unsigned long end);
+typedef int (*acpi_madt_entry_handler) (struct acpi_subtable_header *header, const unsigned long end);
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
unsigned long acpi_find_rsdp (void);
@@ -398,14 +84,12 @@ int acpi_boot_table_init (void);
int acpi_numa_init (void);
int acpi_table_init (void);
-int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler);
-int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header);
-int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
-int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
-int acpi_parse_mcfg (unsigned long phys_addr, unsigned long size);
-void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr);
-void acpi_table_print_madt_entry (acpi_table_entry_header *madt);
-void acpi_table_print_srat_entry (acpi_table_entry_header *srat);
+int acpi_table_parse (char *id, acpi_table_handler handler);
+int acpi_table_parse_madt (enum acpi_madt_type id, acpi_madt_entry_handler handler, unsigned int max_entries);
+int acpi_table_parse_srat (enum acpi_srat_type id, acpi_madt_entry_handler handler, unsigned int max_entries);
+int acpi_parse_mcfg (struct acpi_table_header *header);
+void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
+void acpi_table_print_srat_entry (struct acpi_subtable_header *srat);
/* the following four functions are architecture-dependent */
#ifdef CONFIG_HAVE_ARCH_PARSE_SRAT
@@ -416,8 +100,8 @@ void acpi_table_print_srat_entry (acpi_table_entry_header *srat);
#define acpi_numa_arch_fixup() do {} while (0)
#else
void acpi_numa_slit_init (struct acpi_table_slit *slit);
-void acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa);
-void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma);
+void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa);
+void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);
void acpi_numa_arch_fixup(void);
#endif
@@ -432,7 +116,7 @@ int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base);
extern int acpi_mp_config;
-extern struct acpi_table_mcfg_config *pci_mmcfg_config;
+extern struct acpi_mcfg_allocation *pci_mmcfg_config;
extern int pci_mmcfg_config_num;
extern int sbf_port;
diff --git a/include/linux/aio.h b/include/linux/aio.h
index 3372ec6bf53..a30ef13c9e6 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -105,6 +105,7 @@ struct kiocb {
wait_queue_t ki_wait;
loff_t ki_pos;
+ atomic_t ki_bio_count; /* num bio used for this iocb */
void *private;
/* State that we remember to be able to restart/retry */
unsigned short ki_opcode;
diff --git a/include/asm-mips/apm.h b/include/linux/apm-emulation.h
index 4b99ffc1152..e6d800358dd 100644
--- a/include/asm-mips/apm.h
+++ b/include/linux/apm-emulation.h
@@ -7,11 +7,9 @@
* based on arch/arm/kernel/apm.c
* factor out the information needed by architectures to provide
* apm status
- *
- *
*/
-#ifndef MIPS_ASM_SA1100_APM_H
-#define MIPS_ASM_SA1100_APM_H
+#ifndef __LINUX_APM_EMULATION_H
+#define __LINUX_APM_EMULATION_H
#include <linux/apm_bios.h>
@@ -61,4 +59,4 @@ extern void (*apm_get_power_status)(struct apm_power_info *);
*/
void apm_queue_event(apm_event_t event);
-#endif
+#endif /* __LINUX_APM_EMULATION_H */
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 1df941648a5..18e401ff7ea 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -44,9 +44,9 @@ enum {
ATA_MAX_SECTORS_LBA48 = 65535,/* TODO: 65536? */
ATA_ID_WORDS = 256,
- ATA_ID_SERNO_OFS = 10,
- ATA_ID_FW_REV_OFS = 23,
- ATA_ID_PROD_OFS = 27,
+ ATA_ID_SERNO = 10,
+ ATA_ID_FW_REV = 23,
+ ATA_ID_PROD = 27,
ATA_ID_OLD_PIO_MODES = 51,
ATA_ID_FIELD_VALID = 53,
ATA_ID_MWDMA_MODES = 63,
@@ -58,8 +58,11 @@ enum {
ATA_ID_MAJOR_VER = 80,
ATA_ID_PIO4 = (1 << 1),
+ ATA_ID_SERNO_LEN = 20,
+ ATA_ID_FW_REV_LEN = 8,
+ ATA_ID_PROD_LEN = 40,
+
ATA_PCI_CTL_OFS = 2,
- ATA_SERNO_LEN = 20,
ATA_UDMA0 = (1 << 0),
ATA_UDMA1 = ATA_UDMA0 | (1 << 1),
ATA_UDMA2 = ATA_UDMA1 | (1 << 2),
@@ -296,6 +299,8 @@ struct ata_taskfile {
#define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1)
#define ata_id_removeable(id) ((id)[0] & (1 << 7))
#define ata_id_has_dword_io(id) ((id)[50] & (1 << 0))
+#define ata_id_iordy_disable(id) ((id)[49] & (1 << 10))
+#define ata_id_has_iordy(id) ((id)[49] & (1 << 9))
#define ata_id_u32(id,n) \
(((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)]))
#define ata_id_u64(id,n) \
diff --git a/include/linux/atmarp.h b/include/linux/atmarp.h
index ee108f9e9cb..231f4bdec73 100644
--- a/include/linux/atmarp.h
+++ b/include/linux/atmarp.h
@@ -6,9 +6,7 @@
#ifndef _LINUX_ATMARP_H
#define _LINUX_ATMARP_H
-#ifdef __KERNEL__
#include <linux/types.h>
-#endif
#include <linux/atmapi.h>
#include <linux/atmioc.h>
diff --git a/include/linux/backlight.h b/include/linux/backlight.h
index 75e91f5b6a0..a5cf1beacb4 100644
--- a/include/linux/backlight.h
+++ b/include/linux/backlight.h
@@ -54,7 +54,7 @@ struct backlight_device {
};
extern struct backlight_device *backlight_device_register(const char *name,
- void *devdata, struct backlight_properties *bp);
+ struct device *dev,void *devdata,struct backlight_properties *bp);
extern void backlight_device_unregister(struct backlight_device *bd);
#define to_backlight_device(obj) container_of(obj, struct backlight_device, class_dev)
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 092dbd0e765..08daf3272c0 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -309,6 +309,7 @@ extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int,
gfp_t);
extern void bio_set_pages_dirty(struct bio *bio);
extern void bio_check_pages_dirty(struct bio *bio);
+extern void bio_release_pages(struct bio *bio);
extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int);
extern int bio_uncopy_user(struct bio *);
void zero_fill_bio(struct bio *bio);
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index 5d1eabcde5d..638165f571d 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -31,9 +31,8 @@ static inline unsigned long hweight_long(unsigned long w)
return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
}
-/*
+/**
* rol32 - rotate a 32-bit value left
- *
* @word: value to rotate
* @shift: bits to roll
*/
@@ -42,9 +41,8 @@ static inline __u32 rol32(__u32 word, unsigned int shift)
return (word << shift) | (word >> (32 - shift));
}
-/*
+/**
* ror32 - rotate a 32-bit value right
- *
* @word: value to rotate
* @shift: bits to roll
*/
diff --git a/include/linux/bitrev.h b/include/linux/bitrev.h
new file mode 100644
index 00000000000..05e540d6963
--- /dev/null
+++ b/include/linux/bitrev.h
@@ -0,0 +1,15 @@
+#ifndef _LINUX_BITREV_H
+#define _LINUX_BITREV_H
+
+#include <linux/types.h>
+
+extern u8 const byte_rev_table[256];
+
+static inline u8 bitrev8(u8 byte)
+{
+ return byte_rev_table[byte];
+}
+
+extern u32 bitrev32(u32 in);
+
+#endif /* _LINUX_BITREV_H */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index e1c7286165f..36a6eacefe2 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -331,10 +331,6 @@ struct request_pm_state
#include <linux/elevator.h>
-typedef int (merge_request_fn) (request_queue_t *, struct request *,
- struct bio *);
-typedef int (merge_requests_fn) (request_queue_t *, struct request *,
- struct request *);
typedef void (request_fn_proc) (request_queue_t *q);
typedef int (make_request_fn) (request_queue_t *q, struct bio *bio);
typedef int (prep_rq_fn) (request_queue_t *, struct request *);
@@ -342,7 +338,6 @@ typedef void (unplug_fn) (request_queue_t *);
struct bio_vec;
typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *);
-typedef void (activity_fn) (void *data, int rw);
typedef int (issue_flush_fn) (request_queue_t *, struct gendisk *, sector_t *);
typedef void (prepare_flush_fn) (request_queue_t *, struct request *);
typedef void (softirq_done_fn)(struct request *);
@@ -377,14 +372,10 @@ struct request_queue
struct request_list rq;
request_fn_proc *request_fn;
- merge_request_fn *back_merge_fn;
- merge_request_fn *front_merge_fn;
- merge_requests_fn *merge_requests_fn;
make_request_fn *make_request_fn;
prep_rq_fn *prep_rq_fn;
unplug_fn *unplug_fn;
merge_bvec_fn *merge_bvec_fn;
- activity_fn *activity_fn;
issue_flush_fn *issue_flush_fn;
prepare_flush_fn *prepare_flush_fn;
softirq_done_fn *softirq_done_fn;
@@ -411,8 +402,6 @@ struct request_queue
*/
void *queuedata;
- void *activity_data;
-
/*
* queue needs bounce pages for pages above this limit
*/
@@ -653,6 +642,11 @@ extern int sg_scsi_ioctl(struct file *, struct request_queue *,
struct gendisk *, struct scsi_ioctl_command __user *);
/*
+ * Temporary export, until SCSI gets fixed up.
+ */
+extern int ll_back_merge_fn(request_queue_t *, struct request *, struct bio *);
+
+/*
* 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.
@@ -677,9 +671,8 @@ 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 long);
-extern int blk_rq_unmap_user(struct request *);
+extern int blk_rq_unmap_user(struct bio *);
extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t);
extern int blk_rq_map_user_iov(request_queue_t *, struct request *,
struct sg_iovec *, int, unsigned int);
diff --git a/include/linux/bug.h b/include/linux/bug.h
new file mode 100644
index 00000000000..42aa0a54b6f
--- /dev/null
+++ b/include/linux/bug.h
@@ -0,0 +1,47 @@
+#ifndef _LINUX_BUG_H
+#define _LINUX_BUG_H
+
+#include <linux/module.h>
+#include <asm/bug.h>
+
+enum bug_trap_type {
+ BUG_TRAP_TYPE_NONE = 0,
+ BUG_TRAP_TYPE_WARN = 1,
+ BUG_TRAP_TYPE_BUG = 2,
+};
+
+#ifdef CONFIG_GENERIC_BUG
+#include <asm-generic/bug.h>
+
+static inline int is_warning_bug(const struct bug_entry *bug)
+{
+ return bug->flags & BUGFLAG_WARNING;
+}
+
+const struct bug_entry *find_bug(unsigned long bugaddr);
+
+enum bug_trap_type report_bug(unsigned long bug_addr);
+
+int module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *,
+ struct module *);
+void module_bug_cleanup(struct module *);
+
+/* These are defined by the architecture */
+int is_valid_bugaddr(unsigned long addr);
+
+#else /* !CONFIG_GENERIC_BUG */
+
+static inline enum bug_trap_type report_bug(unsigned long bug_addr)
+{
+ return BUG_TRAP_TYPE_BUG;
+}
+static inline int module_bug_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *mod)
+{
+ return 0;
+}
+static inline void module_bug_cleanup(struct module *mod) {}
+
+#endif /* CONFIG_GENERIC_BUG */
+#endif /* _LINUX_BUG_H */
diff --git a/include/linux/cdev.h b/include/linux/cdev.h
index f309b00e986..1e29b13d006 100644
--- a/include/linux/cdev.h
+++ b/include/linux/cdev.h
@@ -6,6 +6,10 @@
#include <linux/kdev_t.h>
#include <linux/list.h>
+struct file_operations;
+struct inode;
+struct module;
+
struct cdev {
struct kobject kobj;
struct module *owner;
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index d852024ed09..1622d23a8dc 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -159,7 +159,7 @@ static inline s64 cyc2ns(struct clocksource *cs, cycle_t cycles)
* Unless you're the timekeeping code, you should not be using this!
*/
static inline void clocksource_calculate_interval(struct clocksource *c,
- unsigned long length_nsec)
+ unsigned long length_nsec)
{
u64 tmp;
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index be512cc9879..4c2632a8d31 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -64,7 +64,7 @@ void coda_sysctl_clean(void);
#define CODA_ALLOC(ptr, cast, size) do { \
if (size < PAGE_SIZE) \
- ptr = (cast)kmalloc((unsigned long) size, GFP_KERNEL); \
+ ptr = kmalloc((unsigned long) size, GFP_KERNEL); \
else \
ptr = (cast)vmalloc((unsigned long) size); \
if (!ptr) \
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 538423d4a86..aca66984aaf 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -40,7 +40,7 @@ extern void __chk_io_ptr(void __iomem *);
#error no compiler-gcc.h file for this gcc version
#elif __GNUC__ == 4
# include <linux/compiler-gcc4.h>
-#elif __GNUC__ == 3
+#elif __GNUC__ == 3 && __GNUC_MINOR__ >= 2
# include <linux/compiler-gcc3.h>
#else
# error Sorry, your compiler is too old/not recognized.
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index a7f01502753..fef6f3d0a4a 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -160,31 +160,6 @@ struct configfs_group_operations {
void (*drop_item)(struct config_group *group, struct config_item *item);
};
-
-
-/**
- * Use these macros to make defining attributes easier. See include/linux/device.h
- * for examples..
- */
-
-#if 0
-#define __ATTR(_name,_mode,_show,_store) { \
- .attr = {.ca_name = __stringify(_name), .ca_mode = _mode, .ca_owner = THIS_MODULE }, \
- .show = _show, \
- .store = _store, \
-}
-
-#define __ATTR_RO(_name) { \
- .attr = { .ca_name = __stringify(_name), .ca_mode = 0444, .ca_owner = THIS_MODULE }, \
- .show = _name##_show, \
-}
-
-#define __ATTR_NULL { .attr = { .name = NULL } }
-
-#define attr_name(_attr) (_attr).attr.name
-#endif
-
-
struct configfs_subsystem {
struct config_group su_group;
struct semaphore su_sem;
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 3ea1cd58de9..10eb56b2940 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -133,7 +133,7 @@ struct cn_callback_data {
struct cn_callback_entry {
struct list_head callback_entry;
struct cn_callback *cb;
- struct delayed_work work;
+ struct work_struct work;
struct cn_queue_dev *pdev;
struct cn_callback_id id;
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 4ea39fee99c..7f008f6bfdc 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -172,6 +172,8 @@ extern int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int relation);
+extern int cpufreq_driver_getavg(struct cpufreq_policy *policy);
+
int cpufreq_register_governor(struct cpufreq_governor *governor);
void cpufreq_unregister_governor(struct cpufreq_governor *governor);
@@ -204,6 +206,7 @@ struct cpufreq_driver {
unsigned int (*get) (unsigned int cpu);
/* optional */
+ unsigned int (*getavg) (unsigned int cpu);
int (*exit) (struct cpufreq_policy *policy);
int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg);
int (*resume) (struct cpufreq_policy *policy);
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index 8821e1f75b4..fd404416f31 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -30,10 +30,19 @@ void cpuset_update_task_memory_state(void);
nodes_subset((nodes), current->mems_allowed)
int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl);
-extern int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask);
-static int inline cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
+extern int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask);
+extern int __cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask);
+
+static int inline cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
+{
+ return number_of_cpusets <= 1 ||
+ __cpuset_zone_allowed_softwall(z, gfp_mask);
+}
+
+static int inline cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
{
- return number_of_cpusets <= 1 || __cpuset_zone_allowed(z, gfp_mask);
+ return number_of_cpusets <= 1 ||
+ __cpuset_zone_allowed_hardwall(z, gfp_mask);
}
extern int cpuset_excl_nodes_overlap(const struct task_struct *p);
@@ -46,7 +55,7 @@ extern int cpuset_excl_nodes_overlap(const struct task_struct *p);
extern int cpuset_memory_pressure_enabled;
extern void __cpuset_memory_pressure_bump(void);
-extern const struct file_operations proc_cpuset_operations;
+extern struct file_operations proc_cpuset_operations;
extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer);
extern void cpuset_lock(void);
@@ -94,7 +103,12 @@ static inline int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl)
return 1;
}
-static inline int cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
+static inline int cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
+{
+ return 1;
+}
+
+static inline int cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
{
return 1;
}
diff --git a/include/linux/crc32.h b/include/linux/crc32.h
index 56c0645789a..e20dd1f9b40 100644
--- a/include/linux/crc32.h
+++ b/include/linux/crc32.h
@@ -6,10 +6,10 @@
#define _LINUX_CRC32_H
#include <linux/types.h>
+#include <linux/bitrev.h>
extern u32 crc32_le(u32 crc, unsigned char const *p, size_t len);
extern u32 crc32_be(u32 crc, unsigned char const *p, size_t len);
-extern u32 bitreverse(u32 in);
#define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)data, length)
@@ -21,7 +21,7 @@ extern u32 bitreverse(u32 in);
* is in bit nr 0], thus it must be reversed before use. Except for
* nics that bit swap the result internally...
*/
-#define ether_crc(length, data) bitreverse(crc32_le(~0, data, length))
+#define ether_crc(length, data) bitrev32(crc32_le(~0, data, length))
#define ether_crc_le(length, data) crc32_le(~0, data, length)
#endif /* _LINUX_CRC32_H */
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 4aa9046601d..779aa78ee64 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -51,15 +51,9 @@
/*
* Transform masks and values (for crt_flags).
*/
-#define CRYPTO_TFM_MODE_MASK 0x000000ff
#define CRYPTO_TFM_REQ_MASK 0x000fff00
#define CRYPTO_TFM_RES_MASK 0xfff00000
-#define CRYPTO_TFM_MODE_ECB 0x00000001
-#define CRYPTO_TFM_MODE_CBC 0x00000002
-#define CRYPTO_TFM_MODE_CFB 0x00000004
-#define CRYPTO_TFM_MODE_CTR 0x00000008
-
#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100
#define CRYPTO_TFM_REQ_MAY_SLEEP 0x00000200
#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000
@@ -71,12 +65,8 @@
/*
* Miscellaneous stuff.
*/
-#define CRYPTO_UNSPEC 0
#define CRYPTO_MAX_ALG_NAME 64
-#define CRYPTO_DIR_ENCRYPT 1
-#define CRYPTO_DIR_DECRYPT 0
-
/*
* The macro CRYPTO_MINALIGN_ATTR (along with the void * type in the actual
* declaration) is used to ensure that the crypto_tfm context structure is
@@ -148,19 +138,6 @@ struct cipher_alg {
unsigned int keylen);
void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-
- unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc,
- u8 *dst, const u8 *src,
- unsigned int nbytes) __deprecated;
- unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc,
- u8 *dst, const u8 *src,
- unsigned int nbytes) __deprecated;
- unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc,
- u8 *dst, const u8 *src,
- unsigned int nbytes) __deprecated;
- unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc,
- u8 *dst, const u8 *src,
- unsigned int nbytes) __deprecated;
};
struct digest_alg {
@@ -243,11 +220,6 @@ int crypto_unregister_alg(struct crypto_alg *alg);
#ifdef CONFIG_CRYPTO
int crypto_has_alg(const char *name, u32 type, u32 mask);
#else
-static inline int crypto_alg_available(const char *name, u32 flags)
-{
- return 0;
-}
-
static inline int crypto_has_alg(const char *name, u32 type, u32 mask)
{
return 0;
@@ -339,13 +311,18 @@ struct crypto_tfm {
void *__crt_ctx[] CRYPTO_MINALIGN_ATTR;
};
-#define crypto_cipher crypto_tfm
-#define crypto_comp crypto_tfm
-
struct crypto_blkcipher {
struct crypto_tfm base;
};
+struct crypto_cipher {
+ struct crypto_tfm base;
+};
+
+struct crypto_comp {
+ struct crypto_tfm base;
+};
+
struct crypto_hash {
struct crypto_tfm base;
};
@@ -395,40 +372,11 @@ static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm)
return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK;
}
-static unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm)
- __deprecated;
-static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->__crt_alg->cra_cipher.cia_min_keysize;
-}
-
-static unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm)
- __deprecated;
-static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->__crt_alg->cra_cipher.cia_max_keysize;
-}
-
-static unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) __deprecated;
-static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->crt_cipher.cit_ivsize;
-}
-
static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm)
{
return tfm->__crt_alg->cra_blocksize;
}
-static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
- return tfm->__crt_alg->cra_digest.dia_digestsize;
-}
-
static inline unsigned int crypto_tfm_alg_alignmask(struct crypto_tfm *tfm)
{
return tfm->__crt_alg->cra_alignmask;
@@ -633,7 +581,7 @@ static inline struct crypto_cipher *crypto_alloc_cipher(const char *alg_name,
static inline struct crypto_tfm *crypto_cipher_tfm(struct crypto_cipher *tfm)
{
- return tfm;
+ return &tfm->base;
}
static inline void crypto_free_cipher(struct crypto_cipher *tfm)
@@ -809,76 +757,6 @@ static inline int crypto_hash_setkey(struct crypto_hash *hash,
return crypto_hash_crt(hash)->setkey(hash, key, keylen);
}
-static int crypto_cipher_encrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes) __deprecated;
-static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes);
-}
-
-static int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv) __deprecated;
-static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv);
-}
-
-static int crypto_cipher_decrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes) __deprecated;
-static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes);
-}
-
-static int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv) __deprecated;
-static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv);
-}
-
-static void crypto_cipher_set_iv(struct crypto_tfm *tfm,
- const u8 *src, unsigned int len) __deprecated;
-static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm,
- const u8 *src, unsigned int len)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- memcpy(tfm->crt_cipher.cit_iv, src, len);
-}
-
-static void crypto_cipher_get_iv(struct crypto_tfm *tfm,
- u8 *dst, unsigned int len) __deprecated;
-static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm,
- u8 *dst, unsigned int len)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- memcpy(dst, tfm->crt_cipher.cit_iv, len);
-}
-
static inline struct crypto_comp *__crypto_comp_cast(struct crypto_tfm *tfm)
{
return (struct crypto_comp *)tfm;
@@ -903,7 +781,7 @@ static inline struct crypto_comp *crypto_alloc_comp(const char *alg_name,
static inline struct crypto_tfm *crypto_comp_tfm(struct crypto_comp *tfm)
{
- return tfm;
+ return &tfm->base;
}
static inline void crypto_free_comp(struct crypto_comp *tfm)
@@ -934,14 +812,16 @@ static inline int crypto_comp_compress(struct crypto_comp *tfm,
const u8 *src, unsigned int slen,
u8 *dst, unsigned int *dlen)
{
- return crypto_comp_crt(tfm)->cot_compress(tfm, src, slen, dst, dlen);
+ return crypto_comp_crt(tfm)->cot_compress(crypto_comp_tfm(tfm),
+ src, slen, dst, dlen);
}
static inline int crypto_comp_decompress(struct crypto_comp *tfm,
const u8 *src, unsigned int slen,
u8 *dst, unsigned int *dlen)
{
- return crypto_comp_crt(tfm)->cot_decompress(tfm, src, slen, dst, dlen);
+ return crypto_comp_crt(tfm)->cot_decompress(crypto_comp_tfm(tfm),
+ src, slen, dst, dlen);
}
#endif /* _LINUX_CRYPTO_H */
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index ed6cc8962d8..1cb054bd93f 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,20 +176,20 @@ enum {
};
/* DCCP features (RFC 4340 section 6.4) */
- enum {
- DCCPF_RESERVED = 0,
- DCCPF_CCID = 1,
+enum {
+ DCCPF_RESERVED = 0,
+ DCCPF_CCID = 1,
DCCPF_SHORT_SEQNOS = 2, /* XXX: not yet implemented */
- DCCPF_SEQUENCE_WINDOW = 3,
+ DCCPF_SEQUENCE_WINDOW = 3,
DCCPF_ECN_INCAPABLE = 4, /* XXX: not yet implemented */
- DCCPF_ACK_RATIO = 5,
- DCCPF_SEND_ACK_VECTOR = 6,
- DCCPF_SEND_NDP_COUNT = 7,
+ DCCPF_ACK_RATIO = 5,
+ DCCPF_SEND_ACK_VECTOR = 6,
+ DCCPF_SEND_NDP_COUNT = 7,
DCCPF_MIN_CSUM_COVER = 8,
DCCPF_DATA_CHECKSUM = 9, /* XXX: not yet implemented */
- /* 10-127 reserved */
- DCCPF_MIN_CCID_SPECIFIC = 128,
- DCCPF_MAX_CCID_SPECIFIC = 255,
+ /* 10-127 reserved */
+ DCCPF_MIN_CCID_SPECIFIC = 128,
+ DCCPF_MAX_CCID_SPECIFIC = 255,
};
/* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
@@ -427,7 +427,7 @@ struct dccp_service_list {
};
#define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1)
-#define DCCP_SERVICE_CODE_IS_ABSENT 0
+#define DCCP_SERVICE_CODE_IS_ABSENT 0
static inline int dccp_list_has_service(const struct dccp_service_list *sl,
const __be32 service)
@@ -436,7 +436,7 @@ static inline int dccp_list_has_service(const struct dccp_service_list *sl,
u32 i = sl->dccpsl_nr;
while (i--)
if (sl->dccpsl_list[i] == service)
- return 1;
+ return 1;
}
return 0;
}
@@ -511,7 +511,7 @@ struct dccp_sock {
__u8 dccps_hc_tx_insert_options:1;
struct timer_list dccps_xmit_timer;
};
-
+
static inline struct dccp_sock *dccp_sk(const struct sock *sk)
{
return (struct dccp_sock *)sk;
diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h
index a1c10b0c4cf..1678a5de701 100644
--- a/include/linux/debug_locks.h
+++ b/include/linux/debug_locks.h
@@ -24,7 +24,7 @@ extern int debug_locks_off(void);
int __ret = 0; \
\
if (unlikely(c)) { \
- if (debug_locks_silent || debug_locks_off()) \
+ if (debug_locks_off() && !debug_locks_silent) \
WARN_ON(1); \
__ret = 1; \
} \
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 03ef41c1eaa..499f5373e21 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -39,7 +39,8 @@ typedef void (*dm_dtr_fn) (struct dm_target *ti);
* The map function must return:
* < 0: error
* = 0: The target will handle the io by resubmitting it later
- * > 0: simple remap complete
+ * = 1: simple remap complete
+ * = 2: The target wants to push back the io
*/
typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio,
union map_info *map_context);
@@ -50,6 +51,7 @@ typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio,
* 0 : ended successfully
* 1 : for some reason the io has still not completed (eg,
* multipath target might want to requeue a failed io).
+ * 2 : The target wants to push back the io
*/
typedef int (*dm_endio_fn) (struct dm_target *ti,
struct bio *bio, int error,
@@ -173,7 +175,7 @@ void *dm_get_mdptr(struct mapped_device *md);
/*
* A device can still be used while suspended, but I/O is deferred.
*/
-int dm_suspend(struct mapped_device *md, int with_lockfs);
+int dm_suspend(struct mapped_device *md, unsigned suspend_flags);
int dm_resume(struct mapped_device *md);
/*
@@ -188,6 +190,7 @@ int dm_wait_event(struct mapped_device *md, int event_nr);
const char *dm_device_name(struct mapped_device *md);
struct gendisk *dm_disk(struct mapped_device *md);
int dm_suspended(struct mapped_device *md);
+int dm_noflush_suspending(struct dm_target *ti);
/*
* Geometry functions.
diff --git a/include/linux/device.h b/include/linux/device.h
index 49ab53ce92d..26e4692f2d1 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -126,6 +126,7 @@ struct device_driver {
struct klist_node knode_bus;
struct module * owner;
+ const char * mod_name; /* used for built-in modules */
int (*probe) (struct device * dev);
int (*remove) (struct device * dev);
@@ -327,6 +328,13 @@ extern struct class_device *class_device_create(struct class *cls,
__attribute__((format(printf,5,6)));
extern void class_device_destroy(struct class *cls, dev_t devt);
+struct device_type {
+ struct device_attribute *attrs;
+ int (*uevent)(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size);
+ void (*release)(struct device *dev);
+};
+
/* interface for exporting device attributes */
struct device_attribute {
struct attribute attr;
@@ -346,6 +354,41 @@ extern int __must_check device_create_bin_file(struct device *dev,
struct bin_attribute *attr);
extern void device_remove_bin_file(struct device *dev,
struct bin_attribute *attr);
+
+/* device resource management */
+typedef void (*dr_release_t)(struct device *dev, void *res);
+typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data);
+
+#ifdef CONFIG_DEBUG_DEVRES
+extern void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
+ const char *name);
+#define devres_alloc(release, size, gfp) \
+ __devres_alloc(release, size, gfp, #release)
+#else
+extern void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp);
+#endif
+extern void devres_free(void *res);
+extern void devres_add(struct device *dev, void *res);
+extern void * devres_find(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data);
+extern void * devres_get(struct device *dev, void *new_res,
+ dr_match_t match, void *match_data);
+extern void * devres_remove(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data);
+extern int devres_destroy(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data);
+
+/* devres group */
+extern void * __must_check devres_open_group(struct device *dev, void *id,
+ gfp_t gfp);
+extern void devres_close_group(struct device *dev, void *id);
+extern void devres_remove_group(struct device *dev, void *id);
+extern int devres_release_group(struct device *dev, void *id);
+
+/* managed kzalloc/kfree for device drivers, no kmalloc, always use kzalloc */
+extern void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp);
+extern void devm_kfree(struct device *dev, void *p);
+
struct device {
struct klist klist_children;
struct klist_node knode_parent; /* node in sibling list */
@@ -355,6 +398,7 @@ struct device {
struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
+ struct device_type *type;
unsigned is_registered:1;
struct device_attribute uevent_attr;
struct device_attribute *devt_attr;
@@ -388,11 +432,15 @@ struct device {
/* arch specific additions */
struct dev_archdata archdata;
+ spinlock_t devres_lock;
+ struct list_head devres_head;
+
/* class_device migration path */
struct list_head node;
- struct class *class; /* optional*/
+ struct class *class;
dev_t devt; /* dev_t, creates the sysfs "dev" */
struct attribute_group **groups; /* optional groups */
+ int uevent_suppress;
void (*release)(struct device * dev);
};
@@ -433,6 +481,8 @@ static inline int device_is_registered(struct device *dev)
return dev->is_registered;
}
+void driver_init(void);
+
/*
* High level routines for use by the bus drivers
*/
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h
index 8853fc4d1c5..b9348610782 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 10
+#define DM_VERSION_MINOR 11
#define DM_VERSION_PATCHLEVEL 0
-#define DM_VERSION_EXTRA "-ioctl (2006-09-14)"
+#define DM_VERSION_EXTRA "-ioctl (2006-10-12)"
/* Status bits */
#define DM_READONLY_FLAG (1 << 0) /* In/Out */
@@ -323,4 +323,9 @@ typedef char ioctl_struct[308];
*/
#define DM_SKIP_LOCKFS_FLAG (1 << 10) /* In */
+/*
+ * Set this to suspend without flushing queued ios.
+ */
+#define DM_NOFLUSH_FLAG (1 << 11) /* In */
+
#endif /* _LINUX_DM_IOCTL_H */
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index ff203c465fe..9a663c6db16 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -66,6 +66,33 @@ dma_mark_declared_memory_occupied(struct device *dev,
}
#endif
-#endif
+/*
+ * Managed DMA API
+ */
+extern void *dmam_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp);
+extern void dmam_free_coherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle);
+extern void *dmam_alloc_noncoherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp);
+extern void dmam_free_noncoherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle);
+#ifdef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
+extern int dmam_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
+ dma_addr_t device_addr, size_t size,
+ int flags);
+extern void dmam_release_declared_memory(struct device *dev);
+#else /* ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY */
+static inline int dmam_declare_coherent_memory(struct device *dev,
+ dma_addr_t bus_addr, dma_addr_t device_addr,
+ size_t size, gfp_t gfp)
+{
+ return 0;
+}
+static inline void dmam_release_declared_memory(struct device *dev)
+{
+}
+#endif /* ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY */
+#endif
diff --git a/include/linux/dmapool.h b/include/linux/dmapool.h
index 76f12f46db7..022e34fcbd1 100644
--- a/include/linux/dmapool.h
+++ b/include/linux/dmapool.h
@@ -24,5 +24,12 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr);
+/*
+ * Managed DMA pool
+ */
+struct dma_pool *dmam_pool_create(const char *name, struct device *dev,
+ size_t size, size_t align, size_t allocation);
+void dmam_pool_destroy(struct dma_pool *pool);
+
#endif
diff --git a/include/linux/efi.h b/include/linux/efi.h
index df1c91855f0..f8ebd7c1ddb 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -301,7 +301,7 @@ extern int __init efi_uart_console_only (void);
extern void efi_initialize_iomem_resources(struct resource *code_resource,
struct resource *data_resource);
extern unsigned long efi_get_time(void);
-extern int __init efi_set_rtc_mmss(unsigned long nowtime);
+extern int efi_set_rtc_mmss(unsigned long nowtime);
extern int is_available_memory(efi_memory_desc_t * md);
extern struct efi_memory_map memmap;
diff --git a/include/linux/eisa.h b/include/linux/eisa.h
index 1ff7c139252..fe806b6f030 100644
--- a/include/linux/eisa.h
+++ b/include/linux/eisa.h
@@ -61,10 +61,20 @@ struct eisa_driver {
#define to_eisa_driver(drv) container_of(drv,struct eisa_driver, driver)
+/* These external functions are only available when EISA support is enabled. */
+#ifdef CONFIG_EISA
+
extern struct bus_type eisa_bus_type;
int eisa_driver_register (struct eisa_driver *edrv);
void eisa_driver_unregister (struct eisa_driver *edrv);
+#else /* !CONFIG_EISA */
+
+static inline int eisa_driver_register (struct eisa_driver *edrv) { return 0; }
+static inline void eisa_driver_unregister (struct eisa_driver *edrv) { }
+
+#endif /* !CONFIG_EISA */
+
/* Mimics pci.h... */
static inline void *eisa_get_drvdata (struct eisa_device *edev)
{
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index a24931d2440..e88fcbc77f8 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -12,6 +12,8 @@ typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struc
typedef void (elevator_merged_fn) (request_queue_t *, struct request *, int);
+typedef int (elevator_allow_merge_fn) (request_queue_t *, struct request *, struct bio *);
+
typedef int (elevator_dispatch_fn) (request_queue_t *, int);
typedef void (elevator_add_req_fn) (request_queue_t *, struct request *);
@@ -33,6 +35,7 @@ struct elevator_ops
elevator_merge_fn *elevator_merge_fn;
elevator_merged_fn *elevator_merged_fn;
elevator_merge_req_fn *elevator_merge_req_fn;
+ elevator_allow_merge_fn *elevator_allow_merge_fn;
elevator_dispatch_fn *elevator_dispatch_fn;
elevator_add_req_fn *elevator_add_req_fn;
diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h
new file mode 100644
index 00000000000..32368c4f032
--- /dev/null
+++ b/include/linux/fault-inject.h
@@ -0,0 +1,84 @@
+#ifndef _LINUX_FAULT_INJECT_H
+#define _LINUX_FAULT_INJECT_H
+
+#ifdef CONFIG_FAULT_INJECTION
+
+#include <linux/types.h>
+#include <linux/debugfs.h>
+#include <asm/atomic.h>
+
+/*
+ * For explanation of the elements of this struct, see
+ * Documentation/fault-injection/fault-injection.txt
+ */
+struct fault_attr {
+ unsigned long probability;
+ unsigned long interval;
+ atomic_t times;
+ atomic_t space;
+ unsigned long verbose;
+ u32 task_filter;
+ unsigned long stacktrace_depth;
+ unsigned long require_start;
+ unsigned long require_end;
+ unsigned long reject_start;
+ unsigned long reject_end;
+
+ unsigned long count;
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+ struct {
+ struct dentry *dir;
+
+ struct dentry *probability_file;
+ struct dentry *interval_file;
+ struct dentry *times_file;
+ struct dentry *space_file;
+ struct dentry *verbose_file;
+ struct dentry *task_filter_file;
+ struct dentry *stacktrace_depth_file;
+ struct dentry *require_start_file;
+ struct dentry *require_end_file;
+ struct dentry *reject_start_file;
+ struct dentry *reject_end_file;
+ } dentries;
+
+#endif
+};
+
+#define FAULT_ATTR_INITIALIZER { \
+ .interval = 1, \
+ .times = ATOMIC_INIT(1), \
+ .require_end = ULONG_MAX, \
+ .stacktrace_depth = 32, \
+ .verbose = 2, \
+ }
+
+#define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER
+int setup_fault_attr(struct fault_attr *attr, char *str);
+void should_fail_srandom(unsigned long entropy);
+bool should_fail(struct fault_attr *attr, ssize_t size);
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+int init_fault_attr_dentries(struct fault_attr *attr, const char *name);
+void cleanup_fault_attr_dentries(struct fault_attr *attr);
+
+#else /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+static inline int init_fault_attr_dentries(struct fault_attr *attr,
+ const char *name)
+{
+ return -ENODEV;
+}
+
+static inline void cleanup_fault_attr_dentries(struct fault_attr *attr)
+{
+}
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+#endif /* CONFIG_FAULT_INJECTION */
+
+#endif /* _LINUX_FAULT_INJECT_H */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index fa23e0671bb..64177ec9a01 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -929,8 +929,6 @@ extern void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
#define FB_MODE_IS_FIRST 16
#define FB_MODE_IS_FROM_VAR 32
-extern int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal,
- const struct fb_info *fb_info);
extern int fbmon_dpms(const struct fb_info *fb_info);
extern int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
struct fb_info *info);
@@ -970,11 +968,11 @@ extern struct fb_videomode *fb_find_best_display(struct fb_monspecs *specs,
/* drivers/video/fbcmap.c */
extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp);
extern void fb_dealloc_cmap(struct fb_cmap *cmap);
-extern int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to);
-extern int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to);
+extern int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to);
+extern int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to);
extern int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *fb_info);
extern int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *fb_info);
-extern struct fb_cmap *fb_default_cmap(int len);
+extern const struct fb_cmap *fb_default_cmap(int len);
extern void fb_invert_cmaps(void);
struct fb_videomode {
diff --git a/include/linux/file.h b/include/linux/file.h
index 6e77b9177f9..a59001e9ea5 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -26,19 +26,12 @@ struct embedded_fd_set {
unsigned long fds_bits[1];
};
-/*
- * More than this number of fds: we use a separately allocated fd_set
- */
-#define EMBEDDED_FD_SET_SIZE (BITS_PER_BYTE * sizeof(struct embedded_fd_set))
-
struct fdtable {
unsigned int max_fds;
- int max_fdset;
struct file ** fd; /* current fd array */
fd_set *close_on_exec;
fd_set *open_fds;
struct rcu_head rcu;
- struct files_struct *free_files;
struct fdtable *next;
};
@@ -83,16 +76,15 @@ extern int get_unused_fd(void);
extern void FASTCALL(put_unused_fd(unsigned int fd));
struct kmem_cache;
-extern struct file ** alloc_fd_array(int);
-extern void free_fd_array(struct file **, int);
-
-extern fd_set *alloc_fdset(int);
-extern void free_fdset(fd_set *, int);
-
extern int expand_files(struct files_struct *, int nr);
-extern void free_fdtable(struct fdtable *fdt);
+extern void free_fdtable_rcu(struct rcu_head *rcu);
extern void __init files_defer_init(void);
+static inline void free_fdtable(struct fdtable *fdt)
+{
+ call_rcu(&fdt->rcu, free_fdtable_rcu);
+}
+
static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
{
struct file * file = NULL;
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index 6e05e3e7ce3..5e75e26d478 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -1,5 +1,7 @@
/* Freezer declarations */
+#include <linux/sched.h>
+
#ifdef CONFIG_PM
/*
* Check if a process has been frozen
@@ -14,16 +16,15 @@ static inline int frozen(struct task_struct *p)
*/
static inline int freezing(struct task_struct *p)
{
- return p->flags & PF_FREEZE;
+ return test_tsk_thread_flag(p, TIF_FREEZE);
}
/*
* Request that a process be frozen
- * FIXME: SMP problem. We may not modify other process' flags!
*/
static inline void freeze(struct task_struct *p)
{
- p->flags |= PF_FREEZE;
+ set_tsk_thread_flag(p, TIF_FREEZE);
}
/*
@@ -31,7 +32,7 @@ static inline void freeze(struct task_struct *p)
*/
static inline void do_not_freeze(struct task_struct *p)
{
- p->flags &= ~PF_FREEZE;
+ clear_tsk_thread_flag(p, TIF_FREEZE);
}
/*
@@ -52,7 +53,9 @@ static inline int thaw_process(struct task_struct *p)
*/
static inline void frozen_process(struct task_struct *p)
{
- p->flags = (p->flags & ~PF_FREEZE) | PF_FROZEN;
+ p->flags |= PF_FROZEN;
+ wmb();
+ clear_tsk_thread_flag(p, TIF_FREEZE);
}
extern void refrigerator(void);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 70b99fbb560..1410e5330c8 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -120,6 +120,7 @@ extern int dir_notify_enable;
#define MS_PRIVATE (1<<18) /* change to private */
#define MS_SLAVE (1<<19) /* change to slave */
#define MS_SHARED (1<<20) /* change to shared */
+#define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */
#define MS_ACTIVE (1<<30)
#define MS_NOUSER (1<<31)
@@ -269,6 +270,7 @@ extern int dir_notify_enable;
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/dcache.h>
+#include <linux/namei.h>
#include <linux/stat.h>
#include <linux/cache.h>
#include <linux/kobject.h>
@@ -424,6 +426,7 @@ struct address_space_operations {
/* migrate the contents of a page to the specified target */
int (*migratepage) (struct address_space *,
struct page *, struct page *);
+ int (*launder_page) (struct page *);
};
struct backing_dev_info;
@@ -456,7 +459,7 @@ struct block_device {
struct inode * bd_inode; /* will die */
int bd_openers;
struct mutex bd_mutex; /* open/close mutex */
- struct mutex bd_mount_mutex; /* mount mutex */
+ struct semaphore bd_mount_sem;
struct list_head bd_inodes;
void * bd_holder;
int bd_holders;
@@ -482,21 +485,6 @@ struct block_device {
};
/*
- * bdev->bd_mutex nesting subclasses for the lock validator:
- *
- * 0: normal
- * 1: 'whole'
- * 2: 'partition'
- */
-enum bdev_bd_mutex_lock_class
-{
- BD_MUTEX_NORMAL,
- BD_MUTEX_WHOLE,
- BD_MUTEX_PARTITION
-};
-
-
-/*
* Radix-tree tags, for tagging dirty and writeback pages within the pagecache
* radix trees
*/
@@ -726,8 +714,9 @@ struct file {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
- struct dentry *f_dentry;
- struct vfsmount *f_vfsmnt;
+ struct path f_path;
+#define f_dentry f_path.dentry
+#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;
atomic_t f_count;
unsigned int f_flags;
@@ -1239,7 +1228,7 @@ extern void touch_atime(struct vfsmount *mnt, struct dentry *dentry);
static inline void file_accessed(struct file *file)
{
if (!(file->f_flags & O_NOATIME))
- touch_atime(file->f_vfsmnt, file->f_dentry);
+ touch_atime(file->f_path.mnt, file->f_path.dentry);
}
int sync_inode(struct inode *inode, struct writeback_control *wbc);
@@ -1499,7 +1488,6 @@ extern void bd_set_size(struct block_device *, loff_t size);
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 address_space_operations def_blk_aops;
#else
static inline void bd_forget(struct inode *inode) {}
@@ -1517,7 +1505,6 @@ extern int blkdev_driver_ioctl(struct inode *inode, struct file *file,
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 *);
-extern int blkdev_put_partition(struct block_device *);
extern int bd_claim(struct block_device *, void *);
extern void bd_release(struct block_device *);
#ifdef CONFIG_SYSFS
@@ -1632,7 +1619,7 @@ static inline void put_write_access(struct inode * inode)
static inline void allow_write_access(struct file *file)
{
if (file)
- atomic_inc(&file->f_dentry->d_inode->i_writecount);
+ atomic_inc(&file->f_path.dentry->d_inode->i_writecount);
}
extern int do_pipe(int *);
extern struct file *create_read_pipe(struct file *f);
diff --git a/include/linux/fs_stack.h b/include/linux/fs_stack.h
new file mode 100644
index 00000000000..bb516ceeefc
--- /dev/null
+++ b/include/linux/fs_stack.h
@@ -0,0 +1,31 @@
+#ifndef _LINUX_FS_STACK_H
+#define _LINUX_FS_STACK_H
+
+/* This file defines generic functions used primarily by stackable
+ * filesystems; none of these functions require i_mutex to be held.
+ */
+
+#include <linux/fs.h>
+
+/* externs for fs/stack.c */
+extern void fsstack_copy_attr_all(struct inode *dest, const struct inode *src,
+ int (*get_nlinks)(struct inode *));
+
+extern void fsstack_copy_inode_size(struct inode *dst, const struct inode *src);
+
+/* inlines */
+static inline void fsstack_copy_attr_atime(struct inode *dest,
+ const struct inode *src)
+{
+ dest->i_atime = src->i_atime;
+}
+
+static inline void fsstack_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;
+}
+
+#endif /* _LINUX_FS_STACK_H */
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 3da29e2d524..abb64c437f6 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -19,6 +19,7 @@
#define _FSL_DEVICE_H_
#include <linux/types.h>
+#include <linux/phy.h>
/*
* Some conventions on how we handle peripherals on Freescale chips
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index d4f219ffaa5..dfc4e4f68da 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -164,7 +164,7 @@ static inline void fsnotify_open(struct dentry *dentry)
*/
static inline void fsnotify_close(struct file *file)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
const char *name = dentry->d_name.name;
mode_t mode = file->f_mode;
diff --git a/include/linux/futex.h b/include/linux/futex.h
index d097b5b72bc..3f153b4e156 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -93,6 +93,7 @@ struct robust_list_head {
*/
#define ROBUST_LIST_LIMIT 2048
+#ifdef __KERNEL__
long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
u32 __user *uaddr2, u32 val2, u32 val3);
@@ -110,6 +111,7 @@ static inline void exit_pi_state_list(struct task_struct *curr)
{
}
#endif
+#endif /* __KERNEL__ */
#define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */
#define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */
diff --git a/include/linux/gameport.h b/include/linux/gameport.h
index 2cdba0c2395..afad9527284 100644
--- a/include/linux/gameport.h
+++ b/include/linux/gameport.h
@@ -105,7 +105,7 @@ static inline void gameport_set_phys(struct gameport *gameport,
static inline struct gameport *gameport_allocate_port(void)
{
- struct gameport *gameport = kcalloc(1, sizeof(struct gameport), GFP_KERNEL);
+ struct gameport *gameport = kzalloc(sizeof(struct gameport), GFP_KERNEL);
return gameport;
}
diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h
index e2538456195..5412da28fa4 100644
--- a/include/linux/generic_serial.h
+++ b/include/linux/generic_serial.h
@@ -91,7 +91,7 @@ void gs_hangup(struct tty_struct *tty);
int gs_block_til_ready(void *port, struct file *filp);
void gs_close(struct tty_struct *tty, struct file *filp);
void gs_set_termios (struct tty_struct * tty,
- struct termios * old_termios);
+ struct ktermios * old_termios);
int gs_init_port(struct gs_port *port);
int gs_setserial(struct gs_port *port, struct serial_struct __user *sp);
int gs_getserial(struct gs_port *port, struct serial_struct __user *sp);
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 41f276fdd18..0a022b2f63f 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -83,6 +83,9 @@ struct hd_struct {
struct kobject *holder_dir;
unsigned ios[2], sectors[2]; /* READs and WRITEs */
int policy, partno;
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+ int make_it_fail;
+#endif
};
#define GENHD_FL_REMOVABLE 1
@@ -90,6 +93,7 @@ struct hd_struct {
#define GENHD_FL_CD 8
#define GENHD_FL_UP 16
#define GENHD_FL_SUPPRESS_PARTITION_INFO 32
+#define GENHD_FL_FAIL 64
struct disk_stats {
unsigned long sectors[2]; /* READs and WRITEs */
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 00c314aedab..063799ea6be 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -70,7 +70,7 @@ struct vm_area_struct;
#ifdef CONFIG_NUMA
#define GFP_THISNODE (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY)
#else
-#define GFP_THISNODE 0
+#define GFP_THISNODE ((__force gfp_t)0)
#endif
diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h
index 2b54eac738e..818c6afc109 100644
--- a/include/linux/hdreg.h
+++ b/include/linux/hdreg.h
@@ -60,13 +60,15 @@
#define TAG_MASK 0xf8
#endif /* __KERNEL__ */
+#include <linux/types.h>
+
/*
* Command Header sizes for IOCTL commands
*/
-#define HDIO_DRIVE_CMD_HDR_SIZE (4 * sizeof(u8))
-#define HDIO_DRIVE_HOB_HDR_SIZE (8 * sizeof(u8))
-#define HDIO_DRIVE_TASK_HDR_SIZE (8 * sizeof(u8))
+#define HDIO_DRIVE_CMD_HDR_SIZE (4 * sizeof(__u8))
+#define HDIO_DRIVE_HOB_HDR_SIZE (8 * sizeof(__u8))
+#define HDIO_DRIVE_TASK_HDR_SIZE (8 * sizeof(__u8))
#define IDE_DRIVE_TASK_INVALID -1
#define IDE_DRIVE_TASK_NO_DATA 0
diff --git a/include/linux/hid-debug.h b/include/linux/hid-debug.h
new file mode 100644
index 00000000000..50d568ec178
--- /dev/null
+++ b/include/linux/hid-debug.h
@@ -0,0 +1,45 @@
+#ifndef __HID_DEBUG_H
+#define __HID_DEBUG_H
+
+/*
+ * Copyright (c) 2007 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * 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
+ *
+ */
+
+#ifdef CONFIG_HID_DEBUG
+
+void hid_dump_input(struct hid_usage *, __s32);
+void hid_dump_device(struct hid_device *);
+void hid_dump_field(struct hid_field *, int);
+void hid_resolv_usage(unsigned);
+void hid_resolv_event(__u8, __u16);
+
+#else
+
+#define hid_dump_input(a,b) do { } while (0)
+#define hid_dump_device(c) do { } while (0)
+#define hid_dump_field(a,b) do { } while (0)
+#define hid_resolv_usage(a) do { } while (0)
+#define hid_resolv_event(a,b) do { } while (0)
+
+#endif /* CONFIG_HID_DEBUG */
+
+
+#endif
+
diff --git a/drivers/usb/input/hid.h b/include/linux/hid.h
index 76ad68d9edf..d26b08f461f 100644
--- a/drivers/usb/input/hid.h
+++ b/include/linux/hid.h
@@ -6,6 +6,7 @@
*
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2001 Vojtech Pavlik
+ * Copyright (c) 2006 Jiri Kosina
*/
/*
@@ -33,6 +34,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
+#include <linux/input.h>
/*
* USB HID (Human Interface Device) interface class code
@@ -260,8 +262,11 @@ struct hid_item {
#define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000
#define HID_QUIRK_POWERBOOK_FN_ON 0x00002000
#define HID_QUIRK_INVERT_HWHEEL 0x00004000
-#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000
+#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000
#define HID_QUIRK_BAD_RELATIVE_KEYS 0x00010000
+#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000
+#define HID_QUIRK_IGNORE_MOUSE 0x00040000
+#define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000
/*
* This is the global environment of the parser. This information is
@@ -401,42 +406,14 @@ struct hid_device { /* device report descriptor */
unsigned collection_size; /* Number of allocated hid_collections */
unsigned maxcollection; /* Number of parsed collections */
unsigned maxapplication; /* Number of applications */
+ unsigned short bus; /* BUS ID */
+ unsigned short vendor; /* Vendor ID */
+ unsigned short product; /* Product ID */
unsigned version; /* HID version */
unsigned country; /* HID country */
struct hid_report_enum report_enum[HID_REPORT_TYPES];
- struct usb_device *dev; /* USB device */
- struct usb_interface *intf; /* USB interface */
- int ifnum; /* USB interface number */
-
- unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
- struct timer_list io_retry; /* Retry timer */
- unsigned long stop_retry; /* Time to give up, in jiffies */
- unsigned int retry_delay; /* Delay length in ms */
- struct work_struct reset_work; /* Task context for resets */
-
- unsigned int bufsize; /* URB buffer size */
-
- struct urb *urbin; /* Input URB */
- char *inbuf; /* Input buffer */
- dma_addr_t inbuf_dma; /* Input buffer dma */
- spinlock_t inlock; /* Input fifo spinlock */
-
- struct urb *urbctrl; /* Control URB */
- struct usb_ctrlrequest *cr; /* Control request struct */
- dma_addr_t cr_dma; /* Control request struct dma */
- struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */
- unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */
- char *ctrlbuf; /* Control buffer */
- dma_addr_t ctrlbuf_dma; /* Control buffer dma */
- spinlock_t ctrllock; /* Control fifo spinlock */
-
- struct urb *urbout; /* Output URB */
- struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
- unsigned char outhead, outtail; /* Output pipe fifo head & tail */
- char *outbuf; /* Output buffer */
- dma_addr_t outbuf_dma; /* Output buffer dma */
- spinlock_t outlock; /* Output fifo spinlock */
+ struct device *dev; /* device */
unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */
@@ -452,6 +429,17 @@ struct hid_device { /* device report descriptor */
char phys[64]; /* Device physical location */
char uniq[64]; /* Device unique identifier (serial #) */
+ void *driver_data;
+
+ /* device-specific function pointers */
+ int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int);
+ int (*hid_open) (struct hid_device *);
+ void (*hid_close) (struct hid_device *);
+
+ /* hiddev event handler */
+ void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
+ struct hid_usage *, __s32);
+ void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
@@ -486,46 +474,29 @@ struct hid_descriptor {
struct hid_class_descriptor desc[1];
} __attribute__ ((packed));
-#ifdef DEBUG
-#include "hid-debug.h"
-#else
-#define hid_dump_input(a,b) do { } while (0)
-#define hid_dump_device(c) do { } while (0)
-#define hid_dump_field(a,b) do { } while (0)
-#define resolv_usage(a) do { } while (0)
-#define resolv_event(a,b) do { } while (0)
-#endif
-
-#endif
-
-#ifdef CONFIG_USB_HIDINPUT
/* 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))
+
+/* HID core API */
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) { }
-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) { }
-#endif
-int hid_open(struct hid_device *);
-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);
-int hid_wait_io(struct hid_device* hid);
-
+int hid_input_report(struct hid_device *, int type, u8 *, int, int);
+int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
+void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt);
+void hid_output_report(struct hid_report *report, __u8 *data);
+void hid_free_device(struct hid_device *device);
+struct hid_device *hid_parse_report(__u8 *start, unsigned size);
#ifdef CONFIG_HID_FF
int hid_ff_init(struct hid_device *hid);
int hid_lgff_init(struct hid_device *hid);
+int hid_plff_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
@@ -537,4 +508,14 @@ static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; }
#else
static inline int hid_ff_init(struct hid_device *hid) { return -1; }
#endif
+#ifdef DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , \
+ __FILE__ , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
+ __FILE__ , ## arg)
+#endif
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 3d8768b619e..645d440807c 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -8,7 +8,7 @@
#include <asm/cacheflush.h>
#ifndef ARCH_HAS_FLUSH_ANON_PAGE
-static inline void flush_anon_page(struct page *page, unsigned long vmaddr)
+static inline void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
{
}
#endif
@@ -96,7 +96,10 @@ static inline void memclear_highpage_flush(struct page *page, unsigned int offse
kunmap_atomic(kaddr, KM_USER0);
}
-static inline void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr)
+#ifndef __HAVE_ARCH_COPY_USER_HIGHPAGE
+
+static inline void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma)
{
char *vfrom, *vto;
@@ -109,6 +112,8 @@ static inline void copy_user_highpage(struct page *to, struct page *from, unsign
smp_wmb();
}
+#endif
+
static inline void copy_highpage(struct page *to, struct page *from)
{
char *vfrom, *vto;
diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h
index c8f8df25c7e..937da70cb4c 100644
--- a/include/linux/i2c-algo-bit.h
+++ b/include/linux/i2c-algo-bit.h
@@ -26,9 +26,9 @@
/* --- Defines for bit-adapters --------------------------------------- */
/*
- * This struct contains the hw-dependent functions of bit-style adapters to
+ * This struct contains the hw-dependent functions of bit-style adapters to
* manipulate the line states, and to init any hw-specific features. This is
- * only used if you have more than one hw-type of adapter running.
+ * only used if you have more than one hw-type of adapter running.
*/
struct i2c_algo_bit_data {
void *data; /* private data for lowlevel routines */
@@ -44,6 +44,5 @@ struct i2c_algo_bit_data {
};
int i2c_bit_add_bus(struct i2c_adapter *);
-int i2c_bit_del_bus(struct i2c_adapter *);
#endif /* _LINUX_I2C_ALGO_BIT_H */
diff --git a/include/linux/i2c-algo-ite.h b/include/linux/i2c-algo-ite.h
deleted file mode 100644
index 0073fe96c76..00000000000
--- a/include/linux/i2c-algo-ite.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* ------------------------------------------------------------------------- */
-/* i2c-algo-ite.h i2c driver algorithms for ITE IIC adapters */
-/* ------------------------------------------------------------------------- */
-/* Copyright (C) 1995-97 Simon G. Vogl
- 1998-99 Hans Berglund
-
- This program is free software; you can redistribute it and/or modify
- 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> */
-
-/* Modifications by MontaVista Software, 2001
- Changes made to support the ITE IIC peripheral */
-
-
-#ifndef I2C_ALGO_ITE_H
-#define I2C_ALGO_ITE_H 1
-
-#include <linux/types.h>
-
-/* Example of a sequential read request:
- struct i2c_iic_msg s_msg;
-
- s_msg.addr=device_address;
- s_msg.len=length;
- s_msg.buf=buffer;
- s_msg.waddr=word_address;
- ioctl(file,I2C_SREAD, &s_msg);
- */
-#define I2C_SREAD 0x780 /* SREAD ioctl command */
-
-struct i2c_iic_msg {
- __u16 addr; /* device address */
- __u16 waddr; /* word address */
- short len; /* msg length */
- char *buf; /* pointer to msg data */
-};
-
-#ifdef __KERNEL__
-struct i2c_adapter;
-
-struct i2c_algo_iic_data {
- void *data; /* private data for lolevel routines */
- void (*setiic) (void *data, int ctl, int val);
- int (*getiic) (void *data, int ctl);
- int (*getown) (void *data);
- int (*getclock) (void *data);
- void (*waitforpin) (void);
-
- /* local settings */
- int udelay;
- int mdelay;
- int timeout;
-};
-
-int i2c_iic_add_bus(struct i2c_adapter *);
-int i2c_iic_del_bus(struct i2c_adapter *);
-#endif /* __KERNEL__ */
-#endif /* I2C_ALGO_ITE_H */
diff --git a/include/linux/i2c-algo-pca.h b/include/linux/i2c-algo-pca.h
index 226693e0d88..fce47c051bb 100644
--- a/include/linux/i2c-algo-pca.h
+++ b/include/linux/i2c-algo-pca.h
@@ -10,6 +10,5 @@ struct i2c_algo_pca_data {
};
int i2c_pca_add_bus(struct i2c_adapter *);
-int i2c_pca_del_bus(struct i2c_adapter *);
#endif /* _LINUX_I2C_ALGO_PCA_H */
diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h
index 9908f3fc483..994eb86f882 100644
--- a/include/linux/i2c-algo-pcf.h
+++ b/include/linux/i2c-algo-pcf.h
@@ -31,7 +31,7 @@ struct i2c_algo_pcf_data {
int (*getpcf) (void *data, int ctl);
int (*getown) (void *data);
int (*getclock) (void *data);
- void (*waitforpin) (void);
+ void (*waitforpin) (void);
/* local settings */
int udelay;
@@ -39,6 +39,5 @@ struct i2c_algo_pcf_data {
};
int i2c_pcf_add_bus(struct i2c_adapter *);
-int i2c_pcf_del_bus(struct i2c_adapter *);
#endif /* _LINUX_I2C_ALGO_PCF_H */
diff --git a/include/linux/i2c-algo-sgi.h b/include/linux/i2c-algo-sgi.h
index 4a0113d6406..3b7715024e6 100644
--- a/include/linux/i2c-algo-sgi.h
+++ b/include/linux/i2c-algo-sgi.h
@@ -22,6 +22,5 @@ struct i2c_algo_sgi_data {
};
int i2c_sgi_add_bus(struct i2c_adapter *);
-int i2c_sgi_del_bus(struct i2c_adapter *);
#endif /* I2C_ALGO_SGI_H */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 0a8f750cbed..6e7ec4c7617 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
-/* */
+/* */
/* i2c-id.h - identifier values for i2c drivers and adapters */
-/* */
+/* */
/* ------------------------------------------------------------------------- */
/* Copyright (C) 1995-1999 Simon G. Vogl
@@ -40,10 +40,10 @@
#define I2C_DRIVERID_SAA7120 11 /* video encoder */
#define I2C_DRIVERID_SAA7121 12 /* video encoder */
#define I2C_DRIVERID_SAA7185B 13 /* video encoder */
-#define I2C_DRIVERID_CH7003 14 /* digital pc to tv encoder */
+#define I2C_DRIVERID_CH7003 14 /* digital pc to tv encoder */
#define I2C_DRIVERID_PCF8574A 15 /* i2c expander - 8 bit in/out */
#define I2C_DRIVERID_PCF8582C 16 /* eeprom */
-#define I2C_DRIVERID_AT24Cxx 17 /* eeprom 1/2/4/8/16 K */
+#define I2C_DRIVERID_AT24Cxx 17 /* eeprom 1/2/4/8/16 K */
#define I2C_DRIVERID_TEA6300 18 /* audio mixer */
#define I2C_DRIVERID_BT829 19 /* pc to tv encoder */
#define I2C_DRIVERID_TDA9850 20 /* audio mixer */
@@ -82,9 +82,8 @@
#define I2C_DRIVERID_STM41T00 52 /* real time clock */
#define I2C_DRIVERID_UDA1342 53 /* UDA1342 audio codec */
#define I2C_DRIVERID_ADV7170 54 /* video encoder */
-#define I2C_DRIVERID_RADEON 55 /* I2C bus on Radeon boards */
#define I2C_DRIVERID_MAX1617 56 /* temp sensor */
-#define I2C_DRIVERID_SAA7191 57 /* video encoder */
+#define I2C_DRIVERID_SAA7191 57 /* video decoder */
#define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */
#define I2C_DRIVERID_BT832 59 /* CMOS camera video processor */
#define I2C_DRIVERID_TDA9887 60 /* TDA988x IF-PLL demodulator */
@@ -116,6 +115,8 @@
#define I2C_DRIVERID_KS0127 86 /* Samsung ks0127 video decoder */
#define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */
#define I2C_DRIVERID_ISL1208 88 /* Intersil ISL1208 RTC */
+#define I2C_DRIVERID_WM8731 89 /* Wolfson WM8731 audio codec */
+#define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */
#define I2C_DRIVERID_I2CDEV 900
#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
@@ -132,7 +133,6 @@
#define I2C_DRIVERID_ADM1021 1008
#define I2C_DRIVERID_ADM9240 1009
#define I2C_DRIVERID_LTC1710 1010
-#define I2C_DRIVERID_ICSPLL 1012
#define I2C_DRIVERID_BT869 1013
#define I2C_DRIVERID_MAXILIFE 1014
#define I2C_DRIVERID_MATORB 1015
@@ -144,7 +144,6 @@
#define I2C_DRIVERID_MTP008 1023
#define I2C_DRIVERID_DS1621 1024
#define I2C_DRIVERID_ADM1024 1025
-#define I2C_DRIVERID_IT87 1026
#define I2C_DRIVERID_CH700X 1027 /* single driver for CH7003-7009 digital pc to tv encoders */
#define I2C_DRIVERID_FSCPOS 1028
#define I2C_DRIVERID_FSCSCY 1029
@@ -159,12 +158,13 @@
#define I2C_DRIVERID_ASB100 1043
#define I2C_DRIVERID_FSCHER 1046
#define I2C_DRIVERID_W83L785TS 1047
+#define I2C_DRIVERID_OV7670 1048 /* Omnivision 7670 camera */
/*
* ---- Adapter types ----------------------------------------------------
*/
-/* --- Bit algorithm adapters */
+/* --- Bit algorithm adapters */
#define I2C_HW_B_LP 0x010000 /* Parallel port Philips style */
#define I2C_HW_B_SER 0x010002 /* Serial line interface */
#define I2C_HW_B_BT848 0x010005 /* BT848 video boards */
@@ -212,9 +212,6 @@
/* --- MPC8xx PowerPC adapters */
#define I2C_HW_MPC8XX_EPON 0x110000 /* Eponymous MPC8xx I2C adapter */
-/* --- ITE based algorithms */
-#define I2C_HW_I_IIC 0x080000 /* controller on the ITE */
-
/* --- PowerPC on-chip adapters */
#define I2C_HW_OCP 0x120000 /* IBM on-chip I2C adapter */
@@ -250,6 +247,7 @@
#define I2C_HW_SMBUS_OV518 0x04000f /* OV518(+) USB 1.1 webcam ICs */
#define I2C_HW_SMBUS_OV519 0x040010 /* OV519 USB 1.1 webcam IC */
#define I2C_HW_SMBUS_OVFX2 0x040011 /* Cypress/OmniVision FX2 webcam */
+#define I2C_HW_SMBUS_CAFE 0x040012 /* Marvell 88ALP01 "CAFE" cam */
/* --- ISA pseudo-adapter */
#define I2C_HW_ISA 0x050000
diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h
new file mode 100644
index 00000000000..e6e9c814da6
--- /dev/null
+++ b/include/linux/i2c-pnx.h
@@ -0,0 +1,43 @@
+/*
+ * Header file for I2C support on PNX010x/4008.
+ *
+ * Author: Dennis Kovalev <dkovalev@ru.mvista.com>
+ *
+ * 2004-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.
+ */
+
+#ifndef __I2C_PNX_H__
+#define __I2C_PNX_H__
+
+#include <asm/arch/i2c.h>
+
+struct i2c_pnx_mif {
+ int ret; /* Return value */
+ int mode; /* Interface mode */
+ struct completion complete; /* I/O completion */
+ struct timer_list timer; /* Timeout */
+ char * buf; /* Data buffer */
+ int len; /* Length of data buffer */
+};
+
+struct i2c_pnx_algo_data {
+ u32 base;
+ u32 ioaddr;
+ int irq;
+ struct i2c_pnx_mif mif;
+ int last;
+};
+
+struct i2c_pnx_data {
+ int (*suspend) (struct platform_device *pdev, pm_message_t state);
+ int (*resume) (struct platform_device *pdev);
+ u32 (*calculate_input_freq) (struct platform_device *pdev);
+ int (*set_clock_run) (struct platform_device *pdev);
+ int (*set_clock_stop) (struct platform_device *pdev);
+ struct i2c_adapter *adapter;
+};
+
+#endif /* __I2C_PNX_H__ */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 9b5d04768c2..71e50d3e492 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
-/* */
+/* */
/* i2c.h - definitions for the i2c-bus interface */
-/* */
+/* */
/* ------------------------------------------------------------------------- */
/* Copyright (C) 1995-2000 Simon G. Vogl
@@ -27,7 +27,7 @@
#define _LINUX_I2C_H
#include <linux/types.h>
-#ifdef __KERNEL__
+#ifdef __KERNEL__
#include <linux/module.h>
#include <linux/i2c-id.h>
#include <linux/mod_devicetable.h>
@@ -53,8 +53,8 @@ union i2c_smbus_data;
/*
* The master routines are the ones normally used to transmit data to devices
- * on a bus (or read from them). Apart from two basic transfer functions to
- * transmit one message at a time, a more complex version can be used to
+ * on a bus (or read from them). Apart from two basic transfer functions to
+ * transmit one message at a time, a more complex version can be used to
* transmit an arbitrary number of messages without interruption.
*/
extern int i2c_master_send(struct i2c_client *,const char* ,int);
@@ -67,10 +67,10 @@ extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
/* 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,
- and probably just as fast.
+ and probably just as fast.
Note that we use i2c_adapter here, because you do not need a specific
smbus adapter to call this function. */
-extern s32 i2c_smbus_xfer (struct i2c_adapter * adapter, u16 addr,
+extern s32 i2c_smbus_xfer (struct i2c_adapter * adapter, u16 addr,
unsigned short flags,
char read_write, u8 command, int size,
union i2c_smbus_data * data);
@@ -112,14 +112,14 @@ struct i2c_driver {
/* Notifies the driver that a new bus has appeared. This routine
* can be used by the driver to test if the bus meets its conditions
- * & seek for the presence of the chip(s) it supports. If found, it
+ * & seek for the presence of the chip(s) it supports. If found, it
* registers the client(s) that are on the bus to the i2c admin. via
* i2c_attach_client.
*/
int (*attach_adapter)(struct i2c_adapter *);
int (*detach_adapter)(struct i2c_adapter *);
- /* tells the driver that a client is about to be deleted & gives it
+ /* tells the driver that a client is about to be deleted & gives it
* the chance to remove its private data. Also, if the client struct
* has been dynamically allocated by the driver in the function above,
* it must be freed here.
@@ -139,13 +139,13 @@ struct i2c_driver {
#define I2C_NAME_SIZE 50
/*
- * i2c_client identifies a single device (i.e. chip) that is connected to an
+ * i2c_client identifies a single device (i.e. chip) that is connected to an
* i2c bus. The behaviour is defined by the routines of the driver. This
* function is mainly used for lookup & other admin. functions.
*/
struct i2c_client {
unsigned int flags; /* div., see below */
- unsigned short addr; /* chip address - NOTE: 7bit */
+ unsigned short addr; /* chip address - NOTE: 7bit */
/* addresses are stored in the */
/* _LOWER_ 7 bits */
struct i2c_adapter *adapter; /* the adapter we sit on */
@@ -182,14 +182,14 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data)
*/
struct i2c_algorithm {
/* If an adapter algorithm can't do I2C-level access, set master_xfer
- to NULL. If an adapter algorithm can do SMBus access, set
+ to NULL. If an adapter algorithm can do SMBus access, set
smbus_xfer. If set to NULL, the SMBus protocol is simulated
using common I2C messages */
/* master_xfer should return the number of messages successfully
processed, or a negative value on error */
- int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,
+ int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,
int num);
- int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
+ int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data * data);
@@ -216,6 +216,7 @@ struct i2c_adapter {
int (*client_unregister)(struct i2c_client *);
/* data fields that are valid for all devices */
+ u8 level; /* nesting level for lockdep */
struct mutex bus_lock;
struct mutex clist_lock;
@@ -316,7 +317,7 @@ extern int i2c_check_addr (struct i2c_adapter *adapter, int addr);
* It will only call found_proc if some client is connected at the
* specific address (unless a 'force' matched);
*/
-extern int i2c_probe(struct i2c_adapter *adapter,
+extern int i2c_probe(struct i2c_adapter *adapter,
struct i2c_client_address_data *address_data,
int (*found_proc) (struct i2c_adapter *, int, int));
@@ -352,15 +353,15 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
*/
struct i2c_msg {
__u16 addr; /* slave address */
- __u16 flags;
+ __u16 flags;
#define I2C_M_TEN 0x10 /* we have a ten bit chip address */
#define I2C_M_RD 0x01
#define I2C_M_NOSTART 0x4000
#define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK 0x1000
#define I2C_M_NO_RD_ACK 0x0800
- __u16 len; /* msg length */
- __u8 *buf; /* pointer to msg data */
+ __u16 len; /* msg length */
+ __u8 *buf; /* pointer to msg data */
};
/* To determine what functionality is present */
@@ -370,16 +371,16 @@ struct i2c_msg {
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
#define I2C_FUNC_SMBUS_HWPEC_CALC 0x00000008 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
-#define I2C_FUNC_SMBUS_QUICK 0x00010000
-#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
-#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
-#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
-#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
-#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
-#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
-#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
-#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
-#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
+#define I2C_FUNC_SMBUS_QUICK 0x00010000
+#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
+#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
+#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
+#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
+#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
+#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
+#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
+#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
+#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */
@@ -406,10 +407,10 @@ struct i2c_msg {
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK)
-/*
- * Data for SMBus Messages
+/*
+ * Data for SMBus Messages
*/
-#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
+#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
union i2c_smbus_data {
__u8 byte;
__u16 word;
@@ -421,11 +422,11 @@ union i2c_smbus_data {
#define I2C_SMBUS_READ 1
#define I2C_SMBUS_WRITE 0
-/* SMBus transaction types (size parameter in the above functions)
+/* SMBus transaction types (size parameter in the above functions)
Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
#define I2C_SMBUS_QUICK 0
#define I2C_SMBUS_BYTE 1
-#define I2C_SMBUS_BYTE_DATA 2
+#define I2C_SMBUS_BYTE_DATA 2
#define I2C_SMBUS_WORD_DATA 3
#define I2C_SMBUS_PROC_CALL 4
#define I2C_SMBUS_BLOCK_DATA 5
@@ -434,15 +435,15 @@ union i2c_smbus_data {
/* ----- commands for the ioctl like i2c_command call:
- * note that additional calls are defined in the algorithm and hw
- * dependent layers - these can be listed here, or see the
+ * note that additional calls are defined in the algorithm and hw
+ * dependent layers - these can be listed here, or see the
* corresponding header files.
*/
/* -> bit-adapter specific ioctls */
#define I2C_RETRIES 0x0701 /* number of times a device address */
/* should be polled when not */
- /* acknowledging */
-#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */
+ /* acknowledging */
+#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */
/* this is for i2c-dev.c */
diff --git a/include/linux/i2o-dev.h b/include/linux/i2o-dev.h
index c2519df1b6d..a0b23dd4523 100644
--- a/include/linux/i2o-dev.h
+++ b/include/linux/i2o-dev.h
@@ -24,12 +24,13 @@
#define MAX_I2O_CONTROLLERS 32
#include <linux/ioctl.h>
+#include <linux/types.h>
/*
* I2O Control IOCTLs and structures
*/
#define I2O_MAGIC_NUMBER 'i'
-#define I2OGETIOPS _IOR(I2O_MAGIC_NUMBER,0,u8[MAX_I2O_CONTROLLERS])
+#define I2OGETIOPS _IOR(I2O_MAGIC_NUMBER,0,__u8[MAX_I2O_CONTROLLERS])
#define I2OHRTGET _IOWR(I2O_MAGIC_NUMBER,1,struct i2o_cmd_hrtlct)
#define I2OLCTGET _IOWR(I2O_MAGIC_NUMBER,2,struct i2o_cmd_hrtlct)
#define I2OPARMSET _IOWR(I2O_MAGIC_NUMBER,3,struct i2o_cmd_psetget)
@@ -37,7 +38,7 @@
#define I2OSWDL _IOWR(I2O_MAGIC_NUMBER,5,struct i2o_sw_xfer)
#define I2OSWUL _IOWR(I2O_MAGIC_NUMBER,6,struct i2o_sw_xfer)
#define I2OSWDEL _IOWR(I2O_MAGIC_NUMBER,7,struct i2o_sw_xfer)
-#define I2OVALIDATE _IOR(I2O_MAGIC_NUMBER,8,u32)
+#define I2OVALIDATE _IOR(I2O_MAGIC_NUMBER,8,__u32)
#define I2OHTML _IOWR(I2O_MAGIC_NUMBER,9,struct i2o_html)
#define I2OEVTREG _IOW(I2O_MAGIC_NUMBER,10,struct i2o_evt_id)
#define I2OEVTGET _IOR(I2O_MAGIC_NUMBER,11,struct i2o_evt_info)
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 9c2050293f1..04e0fa97ac9 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -18,6 +18,9 @@
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/completion.h>
+#ifdef CONFIG_BLK_DEV_IDEACPI
+#include <acpi/acpi.h>
+#endif
#include <asm/byteorder.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -541,6 +544,11 @@ typedef enum {
struct ide_driver_s;
struct ide_settings_s;
+#ifdef CONFIG_BLK_DEV_IDEACPI
+struct ide_acpi_drive_link;
+struct ide_acpi_hwif_link;
+#endif
+
typedef struct ide_drive_s {
char name[4]; /* drive name, such as "hda" */
char driver_req[10]; /* requests specific driver */
@@ -637,6 +645,9 @@ typedef struct ide_drive_s {
int lun; /* logical unit */
int crc_count; /* crc counter to reduce drive speed */
+#ifdef CONFIG_BLK_DEV_IDEACPI
+ struct ide_acpi_drive_link *acpidata;
+#endif
struct list_head list;
struct device gendev;
struct completion gendev_rel_comp; /* to deal with device release() */
@@ -796,6 +807,7 @@ typedef struct hwif_s {
unsigned sg_mapped : 1; /* sg_table and sg_nents are ready */
unsigned no_io_32bit : 1; /* 1 = can not do 32-bit IO ops */
unsigned err_stops_fifo : 1; /* 1=data FIFO is cleared by an error */
+ unsigned atapi_irq_bogon : 1; /* Generates spurious DMA interrupts in PIO mode */
struct device gendev;
struct completion gendev_rel_comp; /* To deal with device release() */
@@ -804,7 +816,9 @@ typedef struct hwif_s {
unsigned dma;
- void (*led_act)(void *data, int rw);
+#ifdef CONFIG_BLK_DEV_IDEACPI
+ struct ide_acpi_hwif_link *acpidata;
+#endif
} ____cacheline_internodealigned_in_smp ide_hwif_t;
/*
@@ -1193,8 +1207,8 @@ void ide_init_disk(struct gendisk *, ide_drive_t *);
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 int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name);
+#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME)
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);
@@ -1299,6 +1313,18 @@ static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
static inline void ide_release_dma(ide_hwif_t *drive) {;}
#endif
+#ifdef CONFIG_BLK_DEV_IDEACPI
+extern int ide_acpi_exec_tfs(ide_drive_t *drive);
+extern void ide_acpi_get_timing(ide_hwif_t *hwif);
+extern void ide_acpi_push_timing(ide_hwif_t *hwif);
+extern void ide_acpi_init(ide_hwif_t *hwif);
+#else
+static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
+static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
+#endif
+
extern int ide_hwif_request_regions(ide_hwif_t *hwif);
extern void ide_hwif_release_regions(ide_hwif_t* hwif);
extern void ide_unregister (unsigned int index);
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
index dbe8f6120a4..d557e4ce9b6 100644
--- a/include/linux/if_addr.h
+++ b/include/linux/if_addr.h
@@ -52,4 +52,10 @@ struct ifa_cacheinfo
__u32 tstamp; /* updated timestamp, hundredths of seconds */
};
+/* backwards compatibility for userspace */
+#ifndef __KERNEL__
+#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+#endif
+
#endif
diff --git a/include/linux/if_fddi.h b/include/linux/if_fddi.h
index e0a15004620..4aba6b0ad41 100644
--- a/include/linux/if_fddi.h
+++ b/include/linux/if_fddi.h
@@ -103,6 +103,8 @@ struct fddihdr
} __attribute__ ((packed));
#ifdef __KERNEL__
+#include <linux/netdevice.h>
+
/* Define FDDI statistics structure */
struct fddi_statistics {
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index e963a077e6f..35ed3b5467f 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -82,6 +82,12 @@ enum
#define IFLA_MAX (__IFLA_MAX - 1)
+/* backwards compatibility for userspace */
+#ifndef __KERNEL__
+#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+#endif
+
/* ifi_flags.
IFF_* flags.
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h
index 99393ef3af3..f3de05c3067 100644
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -41,6 +41,7 @@ struct sockaddr_ll
#define PACKET_RX_RING 5
#define PACKET_STATISTICS 6
#define PACKET_COPY_THRESH 7
+#define PACKET_AUXDATA 8
struct tpacket_stats
{
@@ -48,6 +49,15 @@ struct tpacket_stats
unsigned int tp_drops;
};
+struct tpacket_auxdata
+{
+ __u32 tp_status;
+ __u32 tp_len;
+ __u32 tp_snaplen;
+ __u16 tp_mac;
+ __u16 tp_net;
+};
+
struct tpacket_hdr
{
unsigned long tp_status;
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 8de079ba110..660b5010c2d 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -1,6 +1,8 @@
#ifndef _IF_TUNNEL_H_
#define _IF_TUNNEL_H_
+#include <linux/types.h>
+
#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0)
#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1)
#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2)
diff --git a/include/linux/init.h b/include/linux/init.h
index 5eb5d24b768..5a593a1dec1 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -111,6 +111,7 @@ extern void setup_arch(char **);
#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
+#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall("7",fn,7)
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 733790d4f7d..6383d2d83bb 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -7,16 +7,15 @@
#include <linux/utsname.h>
#include <linux/lockdep.h>
#include <linux/ipc.h>
+#include <linux/pid_namespace.h>
#define INIT_FDTABLE \
{ \
.max_fds = NR_OPEN_DEFAULT, \
- .max_fdset = EMBEDDED_FD_SET_SIZE, \
.fd = &init_files.fd_array[0], \
.close_on_exec = (fd_set *)&init_files.close_on_exec_init, \
.open_fds = (fd_set *)&init_files.open_fds_init, \
.rcu = RCU_HEAD_INIT, \
- .free_files = NULL, \
.next = NULL, \
}
@@ -57,25 +56,27 @@
.cpu_vm_mask = CPU_MASK_ALL, \
}
-#define INIT_SIGNALS(sig) { \
- .count = ATOMIC_INIT(1), \
+#define INIT_SIGNALS(sig) { \
+ .count = ATOMIC_INIT(1), \
.wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\
- .shared_pending = { \
+ .shared_pending = { \
.list = LIST_HEAD_INIT(sig.shared_pending.list), \
- .signal = {{0}}}, \
+ .signal = {{0}}}, \
.posix_timers = LIST_HEAD_INIT(sig.posix_timers), \
.cpu_timers = INIT_CPU_TIMERS(sig.cpu_timers), \
.rlim = INIT_RLIMITS, \
.pgrp = 1, \
- .session = 1, \
+ .tty_old_pgrp = 0, \
+ { .__session = 1}, \
}
extern struct nsproxy init_nsproxy;
#define INIT_NSPROXY(nsproxy) { \
+ .pid_ns = &init_pid_ns, \
.count = ATOMIC_INIT(1), \
.nslock = __SPIN_LOCK_UNLOCKED(nsproxy.nslock), \
.uts_ns = &init_uts_ns, \
- .namespace = NULL, \
+ .mnt_ns = NULL, \
INIT_IPC_NS(ipc_ns) \
}
diff --git a/include/linux/input.h b/include/linux/input.h
index 4e61158b06a..bde65c8a351 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -491,6 +491,21 @@ struct input_absinfo {
#define KEY_DIGITS 0x19d
#define KEY_TEEN 0x19e
#define KEY_TWEN 0x19f
+#define KEY_VIDEOPHONE 0x1a0
+#define KEY_GAMES 0x1a1
+#define KEY_ZOOMIN 0x1a2
+#define KEY_ZOOMOUT 0x1a3
+#define KEY_ZOOMRESET 0x1a4
+#define KEY_WORDPROCESSOR 0x1a5
+#define KEY_EDITOR 0x1a6
+#define KEY_SPREADSHEET 0x1a7
+#define KEY_GRAPHICSEDITOR 0x1a8
+#define KEY_PRESENTATION 0x1a9
+#define KEY_DATABASE 0x1aa
+#define KEY_NEWS 0x1ab
+#define KEY_VOICEMAIL 0x1ac
+#define KEY_ADDRESSBOOK 0x1ad
+#define KEY_MESSENGER 0x1ae
#define KEY_DEL_EOL 0x1c0
#define KEY_DEL_EOS 0x1c1
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index de7593f4e89..5a8ba0b8ccb 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -12,6 +12,7 @@
#include <linux/sched.h>
#include <linux/irqflags.h>
#include <linux/bottom_half.h>
+#include <linux/device.h>
#include <asm/atomic.h>
#include <asm/ptrace.h>
#include <asm/system.h>
@@ -83,6 +84,11 @@ extern int request_irq(unsigned int, irq_handler_t handler,
unsigned long, const char *, void *);
extern void free_irq(unsigned int, void *);
+extern int devm_request_irq(struct device *dev, unsigned int irq,
+ irq_handler_t handler, unsigned long irqflags,
+ const char *devname, void *dev_id);
+extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
+
/*
* On lockdep we dont want to enable hardirqs in hardirq
* context. Use local_irq_enable_in_hardirq() to annotate
@@ -231,7 +237,8 @@ enum
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
BLOCK_SOFTIRQ,
- TASKLET_SOFTIRQ
+ TASKLET_SOFTIRQ,
+ SCHED_SOFTIRQ,
};
/* softirq mask and active fields moved to irq_cpustat_t in
diff --git a/include/linux/io.h b/include/linux/io.h
index 81877ea3930..9e419ebfc98 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -22,12 +22,33 @@
#include <asm/io.h>
#include <asm/page.h>
+struct device;
+
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);
+/*
+ * Managed iomap interface
+ */
+void __iomem * devm_ioport_map(struct device *dev, unsigned long port,
+ unsigned int nr);
+void devm_ioport_unmap(struct device *dev, void __iomem *addr);
+
+void __iomem * devm_ioremap(struct device *dev, unsigned long offset,
+ unsigned long size);
+void __iomem * devm_ioremap_nocache(struct device *dev, unsigned long offset,
+ unsigned long size);
+void devm_iounmap(struct device *dev, void __iomem *addr);
+
+void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
+void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr);
+void __iomem * const * pcim_iomap_table(struct pci_dev *pdev);
+
+int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name);
+
/**
* check_signature - find BIOS signatures
* @io_addr: mmio address to check
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index cf8696d4a13..6859a3b1408 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -91,6 +91,9 @@ struct resource_list {
#define IORESOURCE_ROM_COPY (1<<2) /* ROM is alloc'd copy, resource field overlaid */
#define IORESOURCE_ROM_BIOS_COPY (1<<3) /* ROM is BIOS copy, resource field overlaid */
+/* PCI control bits. Shares IORESOURCE_BITS with above PCI ROM. */
+#define IORESOURCE_PCI_FIXED (1<<4) /* Do not move resource */
+
/* PC/ISA/whatever - the normal PC address spaces: IO and memory */
extern struct resource ioport_resource;
extern struct resource iomem_resource;
@@ -134,4 +137,24 @@ static inline int __deprecated check_region(resource_size_t s,
{
return __check_region(&ioport_resource, s, n);
}
+
+/* Wrappers for managed devices */
+struct device;
+#define devm_request_region(dev,start,n,name) \
+ __devm_request_region(dev, &ioport_resource, (start), (n), (name))
+#define devm_request_mem_region(dev,start,n,name) \
+ __devm_request_region(dev, &iomem_resource, (start), (n), (name))
+
+extern struct resource * __devm_request_region(struct device *dev,
+ struct resource *parent, resource_size_t start,
+ resource_size_t n, const char *name);
+
+#define devm_release_region(start,n) \
+ __devm_release_region(dev, &ioport_resource, (start), (n))
+#define devm_release_mem_region(start,n) \
+ __devm_release_region(dev, &iomem_resource, (start), (n))
+
+extern void __devm_release_region(struct device *dev, struct resource *parent,
+ resource_size_t start, resource_size_t n);
+
#endif /* _LINUX_IOPORT_H */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 52fc4052a0a..5504b671357 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -68,6 +68,7 @@ typedef void fastcall (*irq_flow_handler_t)(unsigned int irq,
#define IRQ_MOVE_PENDING 0x40000000 /* need to re-target IRQ destination */
struct proc_dir_entry;
+struct msi_desc;
/**
* struct irq_chip - hardware interrupt chip descriptor
@@ -148,6 +149,7 @@ struct irq_chip {
struct irq_desc {
irq_flow_handler_t handle_irq;
struct irq_chip *chip;
+ struct msi_desc *msi_desc;
void *handler_data;
void *chip_data;
struct irqaction *action; /* IRQ action list */
@@ -373,10 +375,12 @@ 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);
extern int set_irq_type(unsigned int irq, unsigned int type);
+extern int set_irq_msi(unsigned int irq, struct msi_desc *entry);
#define get_irq_chip(irq) (irq_desc[irq].chip)
#define get_irq_chip_data(irq) (irq_desc[irq].chip_data)
#define get_irq_data(irq) (irq_desc[irq].handler_data)
+#define get_irq_msi(irq) (irq_desc[irq].msi_desc)
#endif /* CONFIG_GENERIC_HARDIRQS */
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index 62991148d5a..3c7875b7ab5 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -511,8 +511,8 @@ typedef struct modem_info {
#endif
struct tty_struct *tty; /* Pointer to corresponding tty */
atemu emu; /* AT-emulator data */
- struct termios normal_termios; /* For saving termios structs */
- struct termios callout_termios;
+ struct ktermios normal_termios; /* For saving termios structs */
+ struct ktermios callout_termios;
wait_queue_head_t open_wait, close_wait;
struct semaphore write_sem;
spinlock_t readlock;
@@ -525,8 +525,8 @@ typedef struct _isdn_modem {
int refcount; /* Number of opens */
struct tty_driver *tty_modem; /* tty-device */
struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */
- struct termios *modem_termios[ISDN_MAX_CHANNELS];
- struct termios *modem_termios_locked[ISDN_MAX_CHANNELS];
+ struct ktermios *modem_termios[ISDN_MAX_CHANNELS];
+ struct ktermios *modem_termios_locked[ISDN_MAX_CHANNELS];
modem_info info[ISDN_MAX_CHANNELS]; /* Private data */
} isdn_modem_t;
diff --git a/include/linux/istallion.h b/include/linux/istallion.h
index b55e2a03560..106a5e85e5c 100644
--- a/include/linux/istallion.h
+++ b/include/linux/istallion.h
@@ -49,13 +49,13 @@
* communication with the slave board will always be on a per port
* basis.
*/
-typedef struct {
+struct stliport {
unsigned long magic;
- int portnr;
- int panelnr;
- int brdnr;
+ unsigned int portnr;
+ unsigned int panelnr;
+ unsigned int brdnr;
unsigned long state;
- int devnr;
+ unsigned int devnr;
int flags;
int baud_base;
int custom_divisor;
@@ -72,7 +72,7 @@ typedef struct {
wait_queue_head_t close_wait;
wait_queue_head_t raw_wait;
struct work_struct tqhangup;
- asysigs_t asig;
+ struct asysigs asig;
unsigned long addr;
unsigned long rxoffset;
unsigned long txoffset;
@@ -83,31 +83,31 @@ typedef struct {
unsigned char reqbit;
unsigned char portidx;
unsigned char portbit;
-} stliport_t;
+};
/*
* Use a structure of function pointers to do board level operations.
* These include, enable/disable, paging shared memory, interrupting, etc.
*/
-typedef struct stlibrd {
+struct stlibrd {
unsigned long magic;
- int brdnr;
- int brdtype;
- int state;
- int nrpanels;
- int nrports;
- int nrdevs;
+ unsigned int brdnr;
+ unsigned int brdtype;
+ unsigned int state;
+ unsigned int nrpanels;
+ unsigned int nrports;
+ unsigned int nrdevs;
unsigned int iobase;
int iosize;
unsigned long memaddr;
void __iomem *membase;
- int memsize;
+ unsigned long memsize;
int pagesize;
int hostoffset;
int slaveoffset;
int bitsize;
int enabval;
- int panels[STL_MAXPANELS];
+ unsigned int panels[STL_MAXPANELS];
int panelids[STL_MAXPANELS];
void (*init)(struct stlibrd *brdp);
void (*enable)(struct stlibrd *brdp);
@@ -116,8 +116,8 @@ typedef struct stlibrd {
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];
-} stlibrd_t;
+ struct stliport *ports[STL_MAXPORTS];
+};
/*
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 6738283ac38..63fb18dcac3 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -13,10 +13,12 @@
#include <linux/types.h>
#include <linux/compiler.h>
#include <linux/bitops.h>
+#include <linux/log2.h>
#include <asm/byteorder.h>
#include <asm/bug.h>
extern const char linux_banner[];
+extern const char linux_proc_banner[];
#define INT_MAX ((int)(~0U>>1))
#define INT_MIN (-INT_MAX - 1)
@@ -157,20 +159,6 @@ static inline int printk(const char *s, ...) { return 0; }
unsigned long int_sqrt(unsigned long);
-static inline int __attribute_pure__ long_log2(unsigned long x)
-{
- int r = 0;
- for (x >>= 1; x > 0; x >>= 1)
- r++;
- return r;
-}
-
-static inline unsigned long
-__attribute_const__ roundup_pow_of_two(unsigned long x)
-{
- return 1UL << fls_long(x - 1);
-}
-
extern int printk_ratelimit(void);
extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst);
extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index d1c8d28fa92..b850e031053 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -74,9 +74,13 @@ extern void kobject_init(struct kobject *);
extern void kobject_cleanup(struct kobject *);
extern int __must_check kobject_add(struct kobject *);
+extern int __must_check kobject_shadow_add(struct kobject *, struct dentry *);
extern void kobject_del(struct kobject *);
extern int __must_check kobject_rename(struct kobject *, const char *new_name);
+extern int __must_check kobject_shadow_rename(struct kobject *kobj,
+ struct dentry *new_parent,
+ const char *new_name);
extern int __must_check kobject_move(struct kobject *, struct kobject *);
extern int __must_check kobject_register(struct kobject *);
@@ -265,8 +269,8 @@ extern int __must_check subsys_create_file(struct subsystem * ,
struct subsys_attribute *);
#if defined(CONFIG_HOTPLUG)
-void kobject_uevent(struct kobject *kobj, enum kobject_action action);
-void kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
+int kobject_uevent(struct kobject *kobj, enum kobject_action action);
+int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
char *envp[]);
int add_uevent_var(char **envp, int num_envp, int *cur_index,
@@ -274,11 +278,12 @@ int add_uevent_var(char **envp, int num_envp, int *cur_index,
const char *format, ...)
__attribute__((format (printf, 7, 8)));
#else
-static inline void kobject_uevent(struct kobject *kobj, enum kobject_action action) { }
-static inline void kobject_uevent_env(struct kobject *kobj,
+static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action)
+{ return 0; }
+static inline int kobject_uevent_env(struct kobject *kobj,
enum kobject_action action,
char *envp[])
-{ }
+{ return 0; }
static inline int add_uevent_var(char **envp, int num_envp, int *cur_index,
char *buffer, int buffer_size, int *cur_len,
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
new file mode 100644
index 00000000000..1be148f0fce
--- /dev/null
+++ b/include/linux/kvm.h
@@ -0,0 +1,240 @@
+#ifndef __LINUX_KVM_H
+#define __LINUX_KVM_H
+
+/*
+ * Userspace interface for /dev/kvm - kernel based virtual machine
+ *
+ * Note: this interface is considered experimental and may change without
+ * notice.
+ */
+
+#include <asm/types.h>
+#include <linux/ioctl.h>
+
+#define KVM_API_VERSION 2
+
+/*
+ * Architectural interrupt line count, and the size of the bitmap needed
+ * to hold them.
+ */
+#define KVM_NR_INTERRUPTS 256
+#define KVM_IRQ_BITMAP_SIZE_BYTES ((KVM_NR_INTERRUPTS + 7) / 8)
+#define KVM_IRQ_BITMAP_SIZE(type) (KVM_IRQ_BITMAP_SIZE_BYTES / sizeof(type))
+
+
+/* for KVM_CREATE_MEMORY_REGION */
+struct kvm_memory_region {
+ __u32 slot;
+ __u32 flags;
+ __u64 guest_phys_addr;
+ __u64 memory_size; /* bytes */
+};
+
+/* for kvm_memory_region::flags */
+#define KVM_MEM_LOG_DIRTY_PAGES 1UL
+
+
+#define KVM_EXIT_TYPE_FAIL_ENTRY 1
+#define KVM_EXIT_TYPE_VM_EXIT 2
+
+enum kvm_exit_reason {
+ KVM_EXIT_UNKNOWN = 0,
+ KVM_EXIT_EXCEPTION = 1,
+ KVM_EXIT_IO = 2,
+ KVM_EXIT_CPUID = 3,
+ KVM_EXIT_DEBUG = 4,
+ KVM_EXIT_HLT = 5,
+ KVM_EXIT_MMIO = 6,
+ KVM_EXIT_IRQ_WINDOW_OPEN = 7,
+ KVM_EXIT_SHUTDOWN = 8,
+};
+
+/* for KVM_RUN */
+struct kvm_run {
+ /* in */
+ __u32 vcpu;
+ __u32 emulated; /* skip current instruction */
+ __u32 mmio_completed; /* mmio request completed */
+ __u8 request_interrupt_window;
+ __u8 padding1[3];
+
+ /* out */
+ __u32 exit_type;
+ __u32 exit_reason;
+ __u32 instruction_length;
+ __u8 ready_for_interrupt_injection;
+ __u8 if_flag;
+ __u16 padding2;
+ __u64 cr8;
+ __u64 apic_base;
+
+ union {
+ /* KVM_EXIT_UNKNOWN */
+ struct {
+ __u32 hardware_exit_reason;
+ } hw;
+ /* KVM_EXIT_EXCEPTION */
+ struct {
+ __u32 exception;
+ __u32 error_code;
+ } ex;
+ /* KVM_EXIT_IO */
+ struct {
+#define KVM_EXIT_IO_IN 0
+#define KVM_EXIT_IO_OUT 1
+ __u8 direction;
+ __u8 size; /* bytes */
+ __u8 string;
+ __u8 string_down;
+ __u8 rep;
+ __u8 pad;
+ __u16 port;
+ __u64 count;
+ union {
+ __u64 address;
+ __u32 value;
+ };
+ } io;
+ struct {
+ } debug;
+ /* KVM_EXIT_MMIO */
+ struct {
+ __u64 phys_addr;
+ __u8 data[8];
+ __u32 len;
+ __u8 is_write;
+ } mmio;
+ };
+};
+
+/* for KVM_GET_REGS and KVM_SET_REGS */
+struct kvm_regs {
+ /* in */
+ __u32 vcpu;
+ __u32 padding;
+
+ /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+ __u64 rax, rbx, rcx, rdx;
+ __u64 rsi, rdi, rsp, rbp;
+ __u64 r8, r9, r10, r11;
+ __u64 r12, r13, r14, r15;
+ __u64 rip, rflags;
+};
+
+struct kvm_segment {
+ __u64 base;
+ __u32 limit;
+ __u16 selector;
+ __u8 type;
+ __u8 present, dpl, db, s, l, g, avl;
+ __u8 unusable;
+ __u8 padding;
+};
+
+struct kvm_dtable {
+ __u64 base;
+ __u16 limit;
+ __u16 padding[3];
+};
+
+/* for KVM_GET_SREGS and KVM_SET_SREGS */
+struct kvm_sregs {
+ /* in */
+ __u32 vcpu;
+ __u32 padding;
+
+ /* out (KVM_GET_SREGS) / in (KVM_SET_SREGS) */
+ struct kvm_segment cs, ds, es, fs, gs, ss;
+ struct kvm_segment tr, ldt;
+ struct kvm_dtable gdt, idt;
+ __u64 cr0, cr2, cr3, cr4, cr8;
+ __u64 efer;
+ __u64 apic_base;
+ __u64 interrupt_bitmap[KVM_IRQ_BITMAP_SIZE(__u64)];
+};
+
+struct kvm_msr_entry {
+ __u32 index;
+ __u32 reserved;
+ __u64 data;
+};
+
+/* for KVM_GET_MSRS and KVM_SET_MSRS */
+struct kvm_msrs {
+ __u32 vcpu;
+ __u32 nmsrs; /* number of msrs in entries */
+
+ struct kvm_msr_entry entries[0];
+};
+
+/* for KVM_GET_MSR_INDEX_LIST */
+struct kvm_msr_list {
+ __u32 nmsrs; /* number of msrs in entries */
+ __u32 indices[0];
+};
+
+/* for KVM_TRANSLATE */
+struct kvm_translation {
+ /* in */
+ __u64 linear_address;
+ __u32 vcpu;
+ __u32 padding;
+
+ /* out */
+ __u64 physical_address;
+ __u8 valid;
+ __u8 writeable;
+ __u8 usermode;
+};
+
+/* for KVM_INTERRUPT */
+struct kvm_interrupt {
+ /* in */
+ __u32 vcpu;
+ __u32 irq;
+};
+
+struct kvm_breakpoint {
+ __u32 enabled;
+ __u32 padding;
+ __u64 address;
+};
+
+/* for KVM_DEBUG_GUEST */
+struct kvm_debug_guest {
+ /* int */
+ __u32 vcpu;
+ __u32 enabled;
+ struct kvm_breakpoint breakpoints[4];
+ __u32 singlestep;
+};
+
+/* for KVM_GET_DIRTY_LOG */
+struct kvm_dirty_log {
+ __u32 slot;
+ __u32 padding;
+ union {
+ void __user *dirty_bitmap; /* one bit per page */
+ __u64 padding;
+ };
+};
+
+#define KVMIO 0xAE
+
+#define KVM_GET_API_VERSION _IO(KVMIO, 1)
+#define KVM_RUN _IOWR(KVMIO, 2, struct kvm_run)
+#define KVM_GET_REGS _IOWR(KVMIO, 3, struct kvm_regs)
+#define KVM_SET_REGS _IOW(KVMIO, 4, struct kvm_regs)
+#define KVM_GET_SREGS _IOWR(KVMIO, 5, struct kvm_sregs)
+#define KVM_SET_SREGS _IOW(KVMIO, 6, struct kvm_sregs)
+#define KVM_TRANSLATE _IOWR(KVMIO, 7, struct kvm_translation)
+#define KVM_INTERRUPT _IOW(KVMIO, 8, struct kvm_interrupt)
+#define KVM_DEBUG_GUEST _IOW(KVMIO, 9, struct kvm_debug_guest)
+#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 10, struct kvm_memory_region)
+#define KVM_CREATE_VCPU _IOW(KVMIO, 11, int /* vcpu_slot */)
+#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 12, struct kvm_dirty_log)
+#define KVM_GET_MSRS _IOWR(KVMIO, 13, struct kvm_msrs)
+#define KVM_SET_MSRS _IOWR(KVMIO, 14, struct kvm_msrs)
+#define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 15, struct kvm_msr_list)
+
+#endif
diff --git a/include/linux/libata.h b/include/linux/libata.h
index ab275483032..596e0c18887 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -31,7 +31,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <asm/scatterlist.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/ata.h>
#include <linux/workqueue.h>
#include <scsi/scsi_host.h>
@@ -54,8 +54,6 @@
#undef ATA_VERBOSE_DEBUG /* yet more debugging output */
#undef ATA_IRQ_TRAP /* define to ack screaming irqs */
#undef ATA_NDEBUG /* define to disable quick runtime checks */
-#define ATA_ENABLE_PATA /* define to enable PATA support in some
- * low-level drivers */
/* note: prints function name for you */
@@ -109,10 +107,6 @@ 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;
@@ -177,6 +171,7 @@ enum {
* Register FIS clearing BSY */
ATA_FLAG_DEBUGMSG = (1 << 13),
ATA_FLAG_SETXFER_POLLING= (1 << 14), /* use polling for SETXFER */
+ ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */
/* The following flag belongs to ap->pflags but is kept in
* ap->flags because it's referenced in many LLDs and will be
@@ -307,7 +302,7 @@ enum {
* most devices.
*/
ATA_SPINUP_WAIT = 8000,
-
+
/* Horkage types. May be set by libata or controller on drives
(some horkage may be drive/controller pair dependant */
@@ -351,21 +346,21 @@ typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes);
typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes);
struct ata_ioports {
- unsigned long cmd_addr;
- unsigned long data_addr;
- unsigned long error_addr;
- unsigned long feature_addr;
- unsigned long nsect_addr;
- unsigned long lbal_addr;
- unsigned long lbam_addr;
- unsigned long lbah_addr;
- unsigned long device_addr;
- unsigned long status_addr;
- unsigned long command_addr;
- unsigned long altstatus_addr;
- unsigned long ctl_addr;
- unsigned long bmdma_addr;
- unsigned long scr_addr;
+ void __iomem *cmd_addr;
+ void __iomem *data_addr;
+ void __iomem *error_addr;
+ void __iomem *feature_addr;
+ void __iomem *nsect_addr;
+ void __iomem *lbal_addr;
+ void __iomem *lbam_addr;
+ void __iomem *lbah_addr;
+ void __iomem *device_addr;
+ void __iomem *status_addr;
+ void __iomem *command_addr;
+ void __iomem *altstatus_addr;
+ void __iomem *ctl_addr;
+ void __iomem *bmdma_addr;
+ void __iomem *scr_addr;
};
struct ata_probe_ent {
@@ -384,7 +379,7 @@ struct ata_probe_ent {
unsigned int irq_flags;
unsigned long port_flags;
unsigned long _host_flags;
- void __iomem *mmio_base;
+ void __iomem * const *iomap;
void *private_data;
/* port_info for the secondary port. Together with irq2, it's
@@ -401,7 +396,7 @@ struct ata_host {
struct device *dev;
unsigned long irq;
unsigned long irq2;
- void __iomem *mmio_base;
+ void __iomem * const *iomap;
unsigned int n_ports;
void *private_data;
const struct ata_port_operations *ops;
@@ -430,9 +425,6 @@ struct ata_queued_cmd {
unsigned int pad_len;
- unsigned int nsect;
- unsigned int cursect;
-
unsigned int nbytes;
unsigned int curbytes;
@@ -612,11 +604,11 @@ struct ata_port_operations {
void (*dev_select)(struct ata_port *ap, unsigned int device);
void (*phy_reset) (struct ata_port *ap); /* obsolete */
- void (*set_mode) (struct ata_port *ap);
+ int (*set_mode) (struct ata_port *ap, struct ata_device **r_failed_dev);
void (*post_set_mode) (struct ata_port *ap);
- int (*check_atapi_dma) (struct ata_queued_cmd *qc);
+ int (*check_atapi_dma) (struct ata_queued_cmd *qc);
void (*bmdma_setup) (struct ata_queued_cmd *qc);
void (*bmdma_start) (struct ata_queued_cmd *qc);
@@ -638,6 +630,8 @@ struct ata_port_operations {
irq_handler_t irq_handler;
void (*irq_clear) (struct ata_port *);
+ u8 (*irq_on) (struct ata_port *);
+ u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq);
u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
@@ -719,20 +713,18 @@ extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_i
unsigned int n_ports);
extern void ata_pci_remove_one (struct pci_dev *pdev);
extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg);
-extern void ata_pci_device_do_resume(struct pci_dev *pdev);
+extern int __must_check ata_pci_device_do_resume(struct pci_dev *pdev);
extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
extern int ata_pci_device_resume(struct pci_dev *pdev);
extern int ata_pci_clear_simplex(struct pci_dev *pdev);
#endif /* CONFIG_PCI */
extern int ata_device_add(const struct ata_probe_ent *ent);
-extern void ata_port_detach(struct ata_port *ap);
+extern void ata_host_detach(struct ata_host *host);
extern void ata_host_init(struct ata_host *, struct device *,
unsigned long, const struct ata_port_operations *);
-extern void ata_host_remove(struct ata_host *host);
extern int ata_scsi_detect(struct scsi_host_template *sht);
extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
-extern int ata_scsi_release(struct Scsi_Host *host);
extern void ata_sas_port_destroy(struct ata_port *);
extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
struct ata_port_info *, struct Scsi_Host *);
@@ -775,15 +767,11 @@ extern u8 ata_check_status(struct ata_port *ap);
extern u8 ata_altstatus(struct ata_port *ap);
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);
-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,
- unsigned int buflen, int write_data);
-extern void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data);
+extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data);
+extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data);
extern void ata_qc_prep(struct ata_queued_cmd *qc);
extern void ata_noop_qc_prep(struct ata_queued_cmd *qc);
extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc);
@@ -825,6 +813,10 @@ extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
int queue_depth);
extern struct ata_device *ata_dev_pair(struct ata_device *adev);
+extern u8 ata_irq_on(struct ata_port *ap);
+extern u8 ata_dummy_irq_on(struct ata_port *ap);
+extern u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq);
+extern u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq);
/*
* Timing helpers
@@ -863,7 +855,6 @@ struct pci_bits {
unsigned long val;
};
-extern void ata_pci_host_stop (struct ata_host *host);
extern struct ata_probe_ent *
ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask);
extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits);
@@ -1053,6 +1044,8 @@ static inline void ata_pause(struct ata_port *ap)
/**
* ata_busy_wait - Wait for a port status register
* @ap: Port to wait for.
+ * @bits: bits that must be clear
+ * @max: number of 10uS waits to perform
*
* Waits up to max*10 microseconds for the selected bits in the port's
* status register to be cleared.
@@ -1093,10 +1086,9 @@ static inline u8 ata_wait_idle(struct ata_port *ap)
u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ))) {
- unsigned long l = ap->ioaddr.status_addr;
if (ata_msg_warn(ap))
- printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%lX\n",
- status, l);
+ printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%p\n",
+ status, ap->ioaddr.status_addr);
}
return status;
@@ -1143,12 +1135,14 @@ static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf)
static inline void ata_qc_reinit(struct ata_queued_cmd *qc)
{
+ qc->dma_dir = DMA_NONE;
qc->__sg = NULL;
qc->flags = 0;
- qc->cursect = qc->cursg = qc->cursg_ofs = 0;
- qc->nsect = 0;
+ qc->cursg = qc->cursg_ofs = 0;
qc->nbytes = qc->curbytes = 0;
+ qc->n_elem = 0;
qc->err_mask = 0;
+ qc->pad_len = 0;
ata_tf_init(qc->dev, &qc->tf);
@@ -1157,51 +1151,6 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc)
qc->result_tf.feature = 0;
}
-/**
- * ata_irq_ack - Acknowledge a device interrupt.
- * @ap: Port on which interrupts are enabled.
- *
- * Wait up to 10 ms for legacy IDE device to become idle (BUSY
- * or BUSY+DRQ clear). Obtain dma status and port status from
- * device. Clear the interrupt. Return port status.
- *
- * LOCKING:
- */
-
-static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
-{
- unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
- u8 host_stat, post_stat, status;
-
- status = ata_busy_wait(ap, bits, 1000);
- if (status & bits)
- if (ata_msg_err(ap))
- printk(KERN_ERR "abnormal status 0x%X\n", status);
-
- /* get controller status; clear intr, err bits */
- if (ap->flags & ATA_FLAG_MMIO) {
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
- host_stat = readb(mmio + ATA_DMA_STATUS);
- writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
- mmio + ATA_DMA_STATUS);
-
- post_stat = readb(mmio + ATA_DMA_STATUS);
- } else {
- host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
- ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-
- post_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- }
-
- if (ata_msg_intr(ap))
- printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
- __FUNCTION__,
- host_stat, post_stat, status);
-
- return status;
-}
-
static inline int ata_try_flush_cache(const struct ata_device *dev)
{
return ata_id_wcache_enabled(dev->id) ||
@@ -1229,14 +1178,14 @@ static inline unsigned int __ac_err_mask(u8 status)
static inline int ata_pad_alloc(struct ata_port *ap, struct device *dev)
{
ap->pad_dma = 0;
- ap->pad = dma_alloc_coherent(dev, ATA_DMA_PAD_BUF_SZ,
- &ap->pad_dma, GFP_KERNEL);
+ ap->pad = dmam_alloc_coherent(dev, ATA_DMA_PAD_BUF_SZ,
+ &ap->pad_dma, GFP_KERNEL);
return (ap->pad == NULL) ? -ENOMEM : 0;
}
static inline void ata_pad_free(struct ata_port *ap, struct device *dev)
{
- dma_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma);
+ dmam_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma);
}
static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host)
diff --git a/include/linux/list.h b/include/linux/list.h
index a9c90287c0f..611059d633f 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -227,13 +227,13 @@ static inline void list_replace_init(struct list_head *old,
INIT_LIST_HEAD(old);
}
-/*
+/**
* list_replace_rcu - replace old entry by new one
* @old : the element to be replaced
* @new : the new element to insert
*
- * The old entry will be replaced with the new entry atomically.
- * Note: 'old' should not be empty.
+ * The @old entry will be replaced with the @new entry atomically.
+ * Note: @old should not be empty.
*/
static inline void list_replace_rcu(struct list_head *old,
struct list_head *new)
@@ -680,12 +680,12 @@ static inline void hlist_del_init(struct hlist_node *n)
}
}
-/*
+/**
* hlist_replace_rcu - replace old entry by new one
* @old : the element to be replaced
* @new : the new element to insert
*
- * The old entry will be replaced with the new entry atomically.
+ * The @old entry will be replaced with the @new entry atomically.
*/
static inline void hlist_replace_rcu(struct hlist_node *old,
struct hlist_node *new)
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index aa50d89eacd..246de1d84a2 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -23,7 +23,7 @@ struct svc_rqst;
* This is the set of functions for lockd->nfsd communication
*/
struct nlmsvc_binding {
- u32 (*fopen)(struct svc_rqst *,
+ __be32 (*fopen)(struct svc_rqst *,
struct nfs_fh *,
struct file **);
void (*fclose)(struct file *);
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 8c39654549d..ac25b5649c5 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -191,7 +191,7 @@ __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 *,
nlm_host_match_fn_t match);
-void nlmsvc_grant_reply(struct nlm_cookie *, u32);
+void nlmsvc_grant_reply(struct nlm_cookie *, __be32);
/*
* File handling for the server personality
@@ -206,7 +206,7 @@ void nlmsvc_invalidate_all(void);
static __inline__ struct inode *
nlmsvc_file_inode(struct nlm_file *file)
{
- return file->f_file->f_dentry->d_inode;
+ return file->f_file->f_path.dentry->d_inode;
}
/*
diff --git a/include/linux/lockd/sm_inter.h b/include/linux/lockd/sm_inter.h
index fc61d40964d..22a645828f2 100644
--- a/include/linux/lockd/sm_inter.h
+++ b/include/linux/lockd/sm_inter.h
@@ -24,7 +24,7 @@
* Arguments for all calls to statd
*/
struct nsm_args {
- u32 addr; /* remote address */
+ __be32 addr; /* remote address */
u32 prog; /* RPC callback info */
u32 vers;
u32 proc;
diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
index 29e7d9fc9da..83a1f9f6237 100644
--- a/include/linux/lockd/xdr.h
+++ b/include/linux/lockd/xdr.h
@@ -69,7 +69,7 @@ typedef struct nlm_args nlm_args;
*/
struct nlm_res {
struct nlm_cookie cookie;
- u32 status;
+ __be32 status;
struct nlm_lock lock;
};
@@ -80,9 +80,9 @@ struct nlm_reboot {
char * mon;
int len;
u32 state;
- u32 addr;
- u32 vers;
- u32 proto;
+ __be32 addr;
+ __be32 vers;
+ __be32 proto;
};
/*
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 498bfbd3b4e..ea097dddc44 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -281,15 +281,25 @@ struct lock_class_key { };
#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS)
extern void early_init_irq_lock_class(void);
#else
-# define early_init_irq_lock_class() do { } while (0)
+static inline void early_init_irq_lock_class(void)
+{
+}
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
extern void early_boot_irqs_off(void);
extern void early_boot_irqs_on(void);
+extern void print_irqtrace_events(struct task_struct *curr);
#else
-# define early_boot_irqs_off() do { } while (0)
-# define early_boot_irqs_on() do { } while (0)
+static inline void early_boot_irqs_off(void)
+{
+}
+static inline void early_boot_irqs_on(void)
+{
+}
+static inline void print_irqtrace_events(struct task_struct *curr)
+{
+}
#endif
/*
diff --git a/include/linux/log2.h b/include/linux/log2.h
new file mode 100644
index 00000000000..99922bedfcc
--- /dev/null
+++ b/include/linux/log2.h
@@ -0,0 +1,168 @@
+/* Integer base 2 logarithm calculation
+ *
+ * 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 _LINUX_LOG2_H
+#define _LINUX_LOG2_H
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+/*
+ * deal with unrepresentable constant logarithms
+ */
+extern __attribute__((const, noreturn))
+int ____ilog2_NaN(void);
+
+/*
+ * non-constant log of base 2 calculators
+ * - the arch may override these in asm/bitops.h if they can be implemented
+ * more efficiently than using fls() and fls64()
+ * - the arch is not required to handle n==0 if implementing the fallback
+ */
+#ifndef CONFIG_ARCH_HAS_ILOG2_U32
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+ return fls(n) - 1;
+}
+#endif
+
+#ifndef CONFIG_ARCH_HAS_ILOG2_U64
+static inline __attribute__((const))
+int __ilog2_u64(u64 n)
+{
+ return fls64(n) - 1;
+}
+#endif
+
+/*
+ * Determine whether some value is a power of two, where zero is
+ * *not* considered a power of two.
+ */
+
+static inline __attribute__((const))
+bool is_power_of_2(unsigned long n)
+{
+ return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+/*
+ * round up to nearest power of two
+ */
+static inline __attribute__((const))
+unsigned long __roundup_pow_of_two(unsigned long n)
+{
+ return 1UL << fls_long(n - 1);
+}
+
+/**
+ * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
+ * @n - parameter
+ *
+ * constant-capable log of base 2 calculation
+ * - this can be used to initialise global variables from constant data, hence
+ * the massive ternary operator construction
+ *
+ * selects the appropriately-sized optimised version depending on sizeof(n)
+ */
+#define ilog2(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ (n) < 1 ? ____ilog2_NaN() : \
+ (n) & (1ULL << 63) ? 63 : \
+ (n) & (1ULL << 62) ? 62 : \
+ (n) & (1ULL << 61) ? 61 : \
+ (n) & (1ULL << 60) ? 60 : \
+ (n) & (1ULL << 59) ? 59 : \
+ (n) & (1ULL << 58) ? 58 : \
+ (n) & (1ULL << 57) ? 57 : \
+ (n) & (1ULL << 56) ? 56 : \
+ (n) & (1ULL << 55) ? 55 : \
+ (n) & (1ULL << 54) ? 54 : \
+ (n) & (1ULL << 53) ? 53 : \
+ (n) & (1ULL << 52) ? 52 : \
+ (n) & (1ULL << 51) ? 51 : \
+ (n) & (1ULL << 50) ? 50 : \
+ (n) & (1ULL << 49) ? 49 : \
+ (n) & (1ULL << 48) ? 48 : \
+ (n) & (1ULL << 47) ? 47 : \
+ (n) & (1ULL << 46) ? 46 : \
+ (n) & (1ULL << 45) ? 45 : \
+ (n) & (1ULL << 44) ? 44 : \
+ (n) & (1ULL << 43) ? 43 : \
+ (n) & (1ULL << 42) ? 42 : \
+ (n) & (1ULL << 41) ? 41 : \
+ (n) & (1ULL << 40) ? 40 : \
+ (n) & (1ULL << 39) ? 39 : \
+ (n) & (1ULL << 38) ? 38 : \
+ (n) & (1ULL << 37) ? 37 : \
+ (n) & (1ULL << 36) ? 36 : \
+ (n) & (1ULL << 35) ? 35 : \
+ (n) & (1ULL << 34) ? 34 : \
+ (n) & (1ULL << 33) ? 33 : \
+ (n) & (1ULL << 32) ? 32 : \
+ (n) & (1ULL << 31) ? 31 : \
+ (n) & (1ULL << 30) ? 30 : \
+ (n) & (1ULL << 29) ? 29 : \
+ (n) & (1ULL << 28) ? 28 : \
+ (n) & (1ULL << 27) ? 27 : \
+ (n) & (1ULL << 26) ? 26 : \
+ (n) & (1ULL << 25) ? 25 : \
+ (n) & (1ULL << 24) ? 24 : \
+ (n) & (1ULL << 23) ? 23 : \
+ (n) & (1ULL << 22) ? 22 : \
+ (n) & (1ULL << 21) ? 21 : \
+ (n) & (1ULL << 20) ? 20 : \
+ (n) & (1ULL << 19) ? 19 : \
+ (n) & (1ULL << 18) ? 18 : \
+ (n) & (1ULL << 17) ? 17 : \
+ (n) & (1ULL << 16) ? 16 : \
+ (n) & (1ULL << 15) ? 15 : \
+ (n) & (1ULL << 14) ? 14 : \
+ (n) & (1ULL << 13) ? 13 : \
+ (n) & (1ULL << 12) ? 12 : \
+ (n) & (1ULL << 11) ? 11 : \
+ (n) & (1ULL << 10) ? 10 : \
+ (n) & (1ULL << 9) ? 9 : \
+ (n) & (1ULL << 8) ? 8 : \
+ (n) & (1ULL << 7) ? 7 : \
+ (n) & (1ULL << 6) ? 6 : \
+ (n) & (1ULL << 5) ? 5 : \
+ (n) & (1ULL << 4) ? 4 : \
+ (n) & (1ULL << 3) ? 3 : \
+ (n) & (1ULL << 2) ? 2 : \
+ (n) & (1ULL << 1) ? 1 : \
+ (n) & (1ULL << 0) ? 0 : \
+ ____ilog2_NaN() \
+ ) : \
+ (sizeof(n) <= 4) ? \
+ __ilog2_u32(n) : \
+ __ilog2_u64(n) \
+ )
+
+/**
+ * roundup_pow_of_two - round the given value up to nearest power of two
+ * @n - parameter
+ *
+ * round the given balue up to the nearest power of two
+ * - the result is undefined when n == 0
+ * - this can be used to initialise global variables from constant data
+ */
+#define roundup_pow_of_two(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ (n == 1) ? 0 : \
+ (1UL << (ilog2((n) - 1) + 1)) \
+ ) : \
+ __roundup_pow_of_two(n) \
+ )
+
+#endif /* _LINUX_LOG2_H */
diff --git a/include/linux/magic.h b/include/linux/magic.h
index 156c40fc664..b78bbf42135 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -3,6 +3,7 @@
#define ADFS_SUPER_MAGIC 0xadf5
#define AFFS_SUPER_MAGIC 0xadff
+#define AFS_SUPER_MAGIC 0x5346414F
#define AUTOFS_SUPER_MAGIC 0x0187
#define CODA_SUPER_MAGIC 0x73757245
#define EFS_SUPER_MAGIC 0x414A53
diff --git a/include/linux/mm.h b/include/linux/mm.h
index a17b147c61e..bb793a4c8e9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -168,6 +168,7 @@ extern unsigned int kobjsize(const void *objp);
#define VM_NONLINEAR 0x00800000 /* Is non-linear (remap_file_pages) */
#define VM_MAPPED_COPY 0x01000000 /* T if mapped copy of data (nommu mmap) */
#define VM_INSERTPAGE 0x02000000 /* The vma has had "vm_insert_page()" done on it */
+#define VM_ALWAYSDUMP 0x04000000 /* Always include in core dumps */
#ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */
#define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
@@ -978,7 +979,8 @@ 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 memmap_init_zone(unsigned long, int, unsigned long,
+ unsigned long, enum memmap_context);
extern void setup_per_zone_pages_min(void);
extern void mem_init(void);
extern void show_mem(void);
@@ -1028,6 +1030,9 @@ extern struct vm_area_struct *copy_vma(struct vm_area_struct **,
unsigned long addr, unsigned long len, pgoff_t pgoff);
extern void exit_mmap(struct mm_struct *);
extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
+extern int install_special_mapping(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long flags, struct page **pages);
extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index d0e6a549761..e45712acfac 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -71,6 +71,7 @@ struct mmc_card {
#define MMC_STATE_SDCARD (1<<3) /* is an SD card */
#define MMC_STATE_READONLY (1<<4) /* card is read-only */
#define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */
+#define MMC_STATE_BLOCKADDR (1<<6) /* card uses block-addressing */
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */
@@ -87,6 +88,7 @@ struct mmc_card {
#define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED)
+#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD)
@@ -94,6 +96,7 @@ struct mmc_card {
#define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
#define mmc_card_name(c) ((c)->cid.prod_name)
#define mmc_card_id(c) ((c)->dev.bus_id)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index c15ae1986b9..913e5752569 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -92,8 +92,10 @@ struct mmc_host {
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */
unsigned short max_phys_segs; /* see blk_queue_max_phys_segments */
- unsigned short max_sectors; /* see blk_queue_max_sectors */
unsigned short unused;
+ unsigned int max_req_size; /* maximum number of bytes in one req */
+ unsigned int max_blk_size; /* maximum size of one mmc block */
+ unsigned int max_blk_count; /* maximum number of blocks in one req */
/* private data */
struct mmc_ios ios; /* current io bus settings */
@@ -106,8 +108,9 @@ struct mmc_host {
struct list_head cards; /* devices attached to this host */
wait_queue_head_t wq;
- spinlock_t lock; /* card_busy lock */
- struct mmc_card *card_busy; /* the MMC card claiming host */
+ spinlock_t lock; /* claimed lock */
+ unsigned int claimed:1; /* host exclusively claimed */
+
struct mmc_card *card_selected; /* the selected MMC card */
struct delayed_work detect;
@@ -126,6 +129,7 @@ static inline void *mmc_priv(struct mmc_host *host)
}
#define mmc_dev(x) ((x)->parent)
+#define mmc_classdev(x) (&(x)->class_dev)
#define mmc_hostname(x) ((x)->class_dev.bus_id)
extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index a3594dfd696..cdc54be804f 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -42,7 +42,8 @@ struct mmc_command {
#define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
#define MMC_RSP_R3 (MMC_RSP_PRESENT)
-#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC)
+#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
index 2dce60c43f4..c90b6768329 100644
--- a/include/linux/mmc/protocol.h
+++ b/include/linux/mmc/protocol.h
@@ -79,9 +79,12 @@
#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */
/* SD commands type argument response */
- /* class 8 */
+ /* class 0 */
/* This is basically the same command as for MMC with some quirks. */
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
+#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
+
+ /* class 10 */
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
/* Application commands */
@@ -115,6 +118,14 @@
*/
/*
+ * SD_SEND_IF_COND argument format:
+ *
+ * [31:12] Reserved (0)
+ * [11:8] Host Voltage Supply Flags
+ * [7:0] Check Pattern (0xAA)
+ */
+
+/*
MMC status in R1
Type
e : error bit
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index e339a7345f2..b262f47961f 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -450,9 +450,13 @@ void build_all_zonelists(void);
void wakeup_kswapd(struct zone *zone, int order);
int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
int classzone_idx, int alloc_flags);
-
+enum memmap_context {
+ MEMMAP_EARLY,
+ MEMMAP_HOTPLUG,
+};
extern int init_currently_empty_zone(struct zone *zone, unsigned long start_pfn,
- unsigned long size);
+ unsigned long size,
+ enum memmap_context context);
#ifdef CONFIG_HAVE_MEMORY_PRESENT
void memory_present(int nid, unsigned long start, unsigned long end);
diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h
new file mode 100644
index 00000000000..4af0b1fc282
--- /dev/null
+++ b/include/linux/mnt_namespace.h
@@ -0,0 +1,42 @@
+#ifndef _NAMESPACE_H_
+#define _NAMESPACE_H_
+#ifdef __KERNEL__
+
+#include <linux/mount.h>
+#include <linux/sched.h>
+#include <linux/nsproxy.h>
+
+struct mnt_namespace {
+ atomic_t count;
+ struct vfsmount * root;
+ struct list_head list;
+ wait_queue_head_t poll;
+ int event;
+};
+
+extern int copy_mnt_ns(int, struct task_struct *);
+extern void __put_mnt_ns(struct mnt_namespace *ns);
+extern struct mnt_namespace *dup_mnt_ns(struct task_struct *,
+ struct fs_struct *);
+
+static inline void put_mnt_ns(struct mnt_namespace *ns)
+{
+ if (atomic_dec_and_lock(&ns->count, &vfsmount_lock))
+ /* releases vfsmount_lock */
+ __put_mnt_ns(ns);
+}
+
+static inline void exit_mnt_ns(struct task_struct *p)
+{
+ struct mnt_namespace *ns = p->nsproxy->mnt_ns;
+ if (ns)
+ put_mnt_ns(ns);
+}
+
+static inline void get_mnt_ns(struct mnt_namespace *ns)
+{
+ atomic_inc(&ns->count);
+}
+
+#endif
+#endif
diff --git a/include/linux/module.h b/include/linux/module.h
index d33df2408e0..419d3ef293d 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -58,6 +58,7 @@ struct module_kobject
{
struct kobject kobj;
struct module *mod;
+ struct kobject *drivers_dir;
};
/* These are either module local, or the kernel's dummy ones. */
@@ -263,7 +264,7 @@ struct module
struct module_attribute *modinfo_attrs;
const char *version;
const char *srcversion;
- struct kobject *drivers_dir;
+ struct kobject *holders_dir;
/* Exported symbols */
const struct kernel_symbol *syms;
@@ -319,6 +320,13 @@ struct module
unsigned int taints; /* same bits as kernel:tainted */
+#ifdef CONFIG_GENERIC_BUG
+ /* Support for BUG */
+ struct list_head bug_list;
+ struct bug_entry *bug_table;
+ unsigned num_bugs;
+#endif
+
#ifdef CONFIG_MODULE_UNLOAD
/* Reference counts */
struct module_ref ref[NR_CPUS];
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 403d1a97c51..1b7e178b0d8 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -20,13 +20,14 @@
struct super_block;
struct vfsmount;
struct dentry;
-struct namespace;
+struct mnt_namespace;
#define MNT_NOSUID 0x01
#define MNT_NODEV 0x02
#define MNT_NOEXEC 0x04
#define MNT_NOATIME 0x08
#define MNT_NODIRATIME 0x10
+#define MNT_RELATIME 0x20
#define MNT_SHRINKABLE 0x100
@@ -52,7 +53,7 @@ struct vfsmount {
struct list_head mnt_slave_list;/* list of slave mounts */
struct list_head mnt_slave; /* slave list entry */
struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */
- struct namespace *mnt_namespace; /* containing namespace */
+ struct mnt_namespace *mnt_ns; /* containing namespace */
int mnt_pinned;
};
diff --git a/include/linux/msi.h b/include/linux/msi.h
index c7ef9434367..74c8a2ecc9d 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -7,11 +7,10 @@ struct msi_msg {
u32 data; /* 16 bits of msi message data */
};
-/* Heper functions */
+/* Helper 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 {
@@ -42,7 +41,7 @@ struct msi_desc {
/*
* The arch hook for setup up msi irqs
*/
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev);
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
void arch_teardown_msi_irq(unsigned int irq);
diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h
index 72fc68c5ee9..9a6e2f953cb 100644
--- a/include/linux/mtd/blktrans.h
+++ b/include/linux/mtd/blktrans.h
@@ -24,7 +24,6 @@ struct mtd_blktrans_dev {
struct mtd_info *mtd;
struct mutex lock;
int devnum;
- int blksize;
unsigned long size;
int readonly;
void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */
@@ -36,6 +35,8 @@ struct mtd_blktrans_ops {
char *name;
int major;
int part_bits;
+ int blksize;
+ int blkshift;
/* Access functions */
int (*readsect)(struct mtd_blktrans_dev *dev,
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 94a443d4525..d644e57703a 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -23,7 +23,7 @@
#define MTD_CHAR_MAJOR 90
#define MTD_BLOCK_MAJOR 31
-#define MAX_MTD_DEVICES 16
+#define MAX_MTD_DEVICES 32
#define MTD_ERASE_PENDING 0x01
#define MTD_ERASING 0x02
@@ -75,15 +75,12 @@ typedef enum {
* struct mtd_oob_ops - oob operation operands
* @mode: operation mode
*
- * @len: number of bytes to write/read. When a data buffer is given
- * (datbuf != NULL) this is the number of data bytes. When
- * no data buffer is available this is the number of oob bytes.
+ * @len: number of data bytes to write/read
*
- * @retlen: number of bytes written/read. When a data buffer is given
- * (datbuf != NULL) this is the number of data bytes. When
- * no data buffer is available this is the number of oob bytes.
+ * @retlen: number of data bytes written/read
*
- * @ooblen: number of oob bytes per page
+ * @ooblen: number of oob bytes to write/read
+ * @oobretlen: number of oob bytes written/read
* @ooboffs: offset of oob data in the oob area (only relevant when
* mode = MTD_OOB_PLACE)
* @datbuf: data buffer - if NULL only oob data are read/written
@@ -94,6 +91,7 @@ struct mtd_oob_ops {
size_t len;
size_t retlen;
size_t ooblen;
+ size_t oobretlen;
uint32_t ooboffs;
uint8_t *datbuf;
uint8_t *oobbuf;
@@ -202,11 +200,20 @@ struct mtd_info {
/* ECC status information */
struct mtd_ecc_stats ecc_stats;
+ /* Subpage shift (NAND) */
+ int subpage_sft;
void *priv;
struct module *owner;
int usecount;
+
+ /* If the driver is something smart, like UBI, it may need to maintain
+ * its own reference counting. The below functions are only for driver.
+ * The driver may register its callbacks. These callbacks are not
+ * supposed to be called by MTD users */
+ int (*get_device) (struct mtd_info *mtd);
+ void (*put_device) (struct mtd_info *mtd);
};
@@ -216,6 +223,7 @@ extern int add_mtd_device(struct mtd_info *mtd);
extern int del_mtd_device (struct mtd_info *mtd);
extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num);
+extern struct mtd_info *get_mtd_device_nm(const char *name);
extern void put_mtd_device(struct mtd_info *mtd);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 8b3ef418721..2071b02f052 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -166,6 +166,9 @@ typedef enum {
* for all large page devices, as they do not support
* autoincrement.*/
#define NAND_NO_READRDY 0x00000100
+/* Chip does not allow subpage writes */
+#define NAND_NO_SUBPAGE_WRITE 0x00000200
+
/* Options valid for Samsung large page devices */
#define NAND_SAMSUNG_LP_OPTIONS \
@@ -193,6 +196,9 @@ typedef enum {
/* Nand scan has allocated controller struct */
#define NAND_CONTROLLER_ALLOC 0x80000000
+/* Cell info constants */
+#define NAND_CI_CHIPNR_MSK 0x03
+#define NAND_CI_CELLTYPE_MSK 0x0C
/*
* nand_state_t - chip states
@@ -286,9 +292,7 @@ struct nand_ecc_ctrl {
* struct nand_buffers - buffer structure for read/write
* @ecccalc: buffer for calculated ecc
* @ecccode: buffer for ecc read from flash
- * @oobwbuf: buffer for write oob data
* @databuf: buffer for data - dynamically sized
- * @oobrbuf: buffer to read oob data
*
* Do not change the order of buffers. databuf and oobrbuf must be in
* consecutive order.
@@ -296,9 +300,7 @@ struct nand_ecc_ctrl {
struct nand_buffers {
uint8_t ecccalc[NAND_MAX_OOBSIZE];
uint8_t ecccode[NAND_MAX_OOBSIZE];
- uint8_t oobwbuf[NAND_MAX_OOBSIZE];
- uint8_t databuf[NAND_MAX_PAGESIZE];
- uint8_t oobrbuf[NAND_MAX_OOBSIZE];
+ uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
};
/**
@@ -345,6 +347,7 @@ struct nand_buffers {
* @chipsize: [INTERN] the size of one chip for multichip arrays
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
* @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf
+ * @subpagesize: [INTERN] holds the subpagesize
* @ecclayout: [REPLACEABLE] the default ecc placement scheme
* @bbt: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup
@@ -392,6 +395,8 @@ struct nand_chip {
unsigned long chipsize;
int pagemask;
int pagebuf;
+ int subpagesize;
+ uint8_t cellinfo;
int badblockpos;
nand_state_t state;
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 6f045b586e7..f775a7af389 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -13,6 +13,7 @@
#define __LINUX_MTD_ONENAND_H
#include <linux/spinlock.h>
+#include <linux/completion.h>
#include <linux/mtd/onenand_regs.h>
#include <linux/mtd/bbm.h>
@@ -33,7 +34,6 @@ typedef enum {
FL_WRITING,
FL_ERASING,
FL_SYNCING,
- FL_UNLOCKING,
FL_LOCKING,
FL_RESETING,
FL_OTPING,
@@ -88,6 +88,7 @@ struct onenand_bufferram {
* operation is in progress
* @state: [INTERN] the current state of the OneNAND device
* @page_buf: data buffer
+ * @subpagesize: [INTERN] holds the subpagesize
* @ecclayout: [REPLACEABLE] the default ecc placement scheme
* @bbm: [REPLACEABLE] pointer to Bad Block Management
* @priv: [OPTIONAL] pointer to private chip date
@@ -120,11 +121,15 @@ struct onenand_chip {
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
int (*scan_bbt)(struct mtd_info *mtd);
+ struct completion complete;
+ int irq;
+
spinlock_t chip_lock;
wait_queue_head_t wq;
onenand_state_t state;
unsigned char *page_buf;
+ int subpagesize;
struct nand_ecclayout *ecclayout;
void *bbm;
@@ -138,6 +143,7 @@ struct onenand_chip {
#define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index)
#define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1)
#define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1)
+#define ONENAND_SET_PREV_BUFFERRAM(this) (this->bufferram_index ^= 1)
#define ONENAND_GET_SYS_CFG1(this) \
(this->read_word(this->base + ONENAND_REG_SYS_CFG1))
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
index 9e409fe6ded..e31c8f5d427 100644
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -179,6 +179,7 @@
* ECC Status Reigser FF00h (R)
*/
#define ONENAND_ECC_1BIT (1 << 0)
+#define ONENAND_ECC_1BIT_ALL (0x5555)
#define ONENAND_ECC_2BIT (1 << 1)
#define ONENAND_ECC_2BIT_ALL (0xAAAA)
diff --git a/include/linux/mtio.h b/include/linux/mtio.h
index 8c66151821e..6f8d2d45a8f 100644
--- a/include/linux/mtio.h
+++ b/include/linux/mtio.h
@@ -10,7 +10,6 @@
#include <linux/types.h>
#include <linux/ioctl.h>
-#include <linux/qic117.h>
/*
* Structures and definitions for mag tape io control commands
@@ -116,32 +115,6 @@ struct mtget {
#define MT_ISFTAPE_UNKNOWN 0x800000 /* obsolete */
#define MT_ISFTAPE_FLAG 0x800000
-struct mt_tape_info {
- long t_type; /* device type id (mt_type) */
- char *t_name; /* descriptive name */
-};
-
-#define MT_TAPE_INFO { \
- {MT_ISUNKNOWN, "Unknown type of tape device"}, \
- {MT_ISQIC02, "Generic QIC-02 tape streamer"}, \
- {MT_ISWT5150, "Wangtek 5150, QIC-150"}, \
- {MT_ISARCHIVE_5945L2, "Archive 5945L-2"}, \
- {MT_ISCMSJ500, "CMS Jumbo 500"}, \
- {MT_ISTDC3610, "Tandberg TDC 3610, QIC-24"}, \
- {MT_ISARCHIVE_VP60I, "Archive VP60i, QIC-02"}, \
- {MT_ISARCHIVE_2150L, "Archive Viper 2150L"}, \
- {MT_ISARCHIVE_2060L, "Archive Viper 2060L"}, \
- {MT_ISARCHIVESC499, "Archive SC-499 QIC-36 controller"}, \
- {MT_ISQIC02_ALL_FEATURES, "Generic QIC-02 tape, all features"}, \
- {MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \
- {MT_ISTEAC_MT2ST, "Teac MT-2ST 155mb data cassette drive"}, \
- {MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \
- {MT_ISONSTREAM_SC, "OnStream SC-, DI-, DP-, or USB tape drive"}, \
- {MT_ISSCSI1, "Generic SCSI-1 tape"}, \
- {MT_ISSCSI2, "Generic SCSI-2 tape"}, \
- {0, NULL} \
-}
-
/* structure for MTIOCPOS - mag tape get position command */
@@ -150,130 +123,11 @@ struct mtpos {
};
-/* structure for MTIOCVOLINFO, query information about the volume
- * currently positioned at (zftape)
- */
-struct mtvolinfo {
- unsigned int mt_volno; /* vol-number */
- unsigned int mt_blksz; /* blocksize used when recording */
- unsigned int mt_rawsize; /* raw tape space consumed, in kb */
- unsigned int mt_size; /* volume size after decompression, in kb */
- unsigned int mt_cmpr:1; /* this volume has been compressed */
-};
-
-/* raw access to a floppy drive, read and write an arbitrary segment.
- * For ftape/zftape to support formatting etc.
- */
-#define MT_FT_RD_SINGLE 0
-#define MT_FT_RD_AHEAD 1
-#define MT_FT_WR_ASYNC 0 /* start tape only when all buffers are full */
-#define MT_FT_WR_MULTI 1 /* start tape, continue until buffers are empty */
-#define MT_FT_WR_SINGLE 2 /* write a single segment and stop afterwards */
-#define MT_FT_WR_DELETE 3 /* write deleted data marks, one segment at time */
-
-struct mtftseg
-{
- unsigned mt_segno; /* the segment to read or write */
- unsigned mt_mode; /* modes for read/write (sync/async etc.) */
- int mt_result; /* result of r/w request, not of the ioctl */
- void __user *mt_data; /* User space buffer: must be 29kb */
-};
-
-/* get tape capacity (ftape/zftape)
- */
-struct mttapesize {
- unsigned long mt_capacity; /* entire, uncompressed capacity
- * of a cartridge
- */
- unsigned long mt_used; /* what has been used so far, raw
- * uncompressed amount
- */
-};
-
-/* possible values of the ftfmt_op field
- */
-#define FTFMT_SET_PARMS 1 /* set software parms */
-#define FTFMT_GET_PARMS 2 /* get software parms */
-#define FTFMT_FORMAT_TRACK 3 /* start formatting a tape track */
-#define FTFMT_STATUS 4 /* monitor formatting a tape track */
-#define FTFMT_VERIFY 5 /* verify the given segment */
-
-struct ftfmtparms {
- unsigned char ft_qicstd; /* QIC-40/QIC-80/QIC-3010/QIC-3020 */
- unsigned char ft_fmtcode; /* Refer to the QIC specs */
- unsigned char ft_fhm; /* floppy head max */
- unsigned char ft_ftm; /* floppy track max */
- unsigned short ft_spt; /* segments per track */
- unsigned short ft_tpc; /* tracks per cartridge */
-};
-
-struct ftfmttrack {
- unsigned int ft_track; /* track to format */
- unsigned char ft_gap3; /* size of gap3, for FORMAT_TRK */
-};
-
-struct ftfmtstatus {
- unsigned int ft_segment; /* segment currently being formatted */
-};
-
-struct ftfmtverify {
- unsigned int ft_segment; /* segment to verify */
- unsigned long ft_bsm; /* bsm as result of VERIFY cmd */
-};
-
-struct mtftformat {
- unsigned int fmt_op; /* operation to perform */
- union fmt_arg {
- struct ftfmtparms fmt_parms; /* format parameters */
- struct ftfmttrack fmt_track; /* ctrl while formatting */
- struct ftfmtstatus fmt_status;
- struct ftfmtverify fmt_verify; /* for verifying */
- } fmt_arg;
-};
-
-struct mtftcmd {
- unsigned int ft_wait_before; /* timeout to wait for drive to get ready
- * before command is sent. Milliseconds
- */
- qic117_cmd_t ft_cmd; /* command to send */
- unsigned char ft_parm_cnt; /* zero: no parm is sent. */
- unsigned char ft_parms[3]; /* parameter(s) to send to
- * the drive. The parms are nibbles
- * driver sends cmd + 2 step pulses */
- unsigned int ft_result_bits; /* if non zero, number of bits
- * returned by the tape drive
- */
- unsigned int ft_result; /* the result returned by the tape drive*/
- unsigned int ft_wait_after; /* timeout to wait for drive to get ready
- * after command is sent. 0: don't wait */
- int ft_status; /* status returned by ready wait
- * undefined if timeout was 0.
- */
- int ft_error; /* error code if error status was set by
- * command
- */
-};
-
/* mag tape io control commands */
#define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */
#define MTIOCGET _IOR('m', 2, struct mtget) /* get tape status */
#define MTIOCPOS _IOR('m', 3, struct mtpos) /* get tape position */
-/* The next two are used by the QIC-02 driver for runtime reconfiguration.
- * See tpqic02.h for struct mtconfiginfo.
- */
-#define MTIOCGETCONFIG _IOR('m', 4, struct mtconfiginfo) /* get tape config */
-#define MTIOCSETCONFIG _IOW('m', 5, struct mtconfiginfo) /* set tape config */
-
-/* the next six are used by the floppy ftape drivers and its frontends
- * sorry, but MTIOCTOP commands are write only.
- */
-#define MTIOCRDFTSEG _IOWR('m', 6, struct mtftseg) /* read a segment */
-#define MTIOCWRFTSEG _IOWR('m', 7, struct mtftseg) /* write a segment */
-#define MTIOCVOLINFO _IOR('m', 8, struct mtvolinfo) /* info about volume */
-#define MTIOCGETSIZE _IOR('m', 9, struct mttapesize)/* get cartridge size*/
-#define MTIOCFTFORMAT _IOWR('m', 10, struct mtftformat) /* format ftape */
-#define MTIOCFTCMD _IOWR('m', 11, struct mtftcmd) /* send QIC-117 cmd */
/* Generic Mag Tape (device independent) status macros for examining
* mt_gstat -- HP-UX compatible.
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index b2b91c47756..b81bc2adaef 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -105,7 +105,7 @@ do { \
extern void __mutex_init(struct mutex *lock, const char *name,
struct lock_class_key *key);
-/***
+/**
* mutex_is_locked - is the mutex locked
* @lock: the mutex to be queried
*
@@ -125,8 +125,10 @@ extern int fastcall mutex_lock_interruptible(struct mutex *lock);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
+extern int mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass);
#else
# define mutex_lock_nested(lock, subclass) mutex_lock(lock)
+# define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
#endif
/*
diff --git a/include/linux/n_r3964.h b/include/linux/n_r3964.h
index db4f3776978..de24af79ebd 100644
--- a/include/linux/n_r3964.h
+++ b/include/linux/n_r3964.h
@@ -116,7 +116,7 @@ struct r3964_message;
struct r3964_client_info {
spinlock_t lock;
- pid_t pid;
+ struct pid *pid;
unsigned int sig_flags;
struct r3964_client_info *next;
diff --git a/include/linux/namei.h b/include/linux/namei.h
index f5f19606eff..d39a5a67e97 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -29,6 +29,11 @@ struct nameidata {
} intent;
};
+struct path {
+ struct vfsmount *mnt;
+ struct dentry *dentry;
+};
+
/*
* Type of the last component on LOOKUP_PARENT
*/
diff --git a/include/linux/namespace.h b/include/linux/namespace.h
deleted file mode 100644
index d137009f0b2..00000000000
--- a/include/linux/namespace.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef _NAMESPACE_H_
-#define _NAMESPACE_H_
-#ifdef __KERNEL__
-
-#include <linux/mount.h>
-#include <linux/sched.h>
-#include <linux/nsproxy.h>
-
-struct namespace {
- atomic_t count;
- struct vfsmount * root;
- struct list_head list;
- wait_queue_head_t poll;
- int event;
-};
-
-extern int copy_namespace(int, struct task_struct *);
-extern void __put_namespace(struct namespace *namespace);
-extern struct namespace *dup_namespace(struct task_struct *, struct fs_struct *);
-
-static inline void put_namespace(struct namespace *namespace)
-{
- if (atomic_dec_and_lock(&namespace->count, &vfsmount_lock))
- /* releases vfsmount_lock */
- __put_namespace(namespace);
-}
-
-static inline void exit_namespace(struct task_struct *p)
-{
- struct namespace *namespace = p->nsproxy->namespace;
- if (namespace) {
- put_namespace(namespace);
- }
-}
-
-static inline void get_namespace(struct namespace *namespace)
-{
- atomic_inc(&namespace->count);
-}
-
-#endif
-#endif
diff --git a/include/linux/ncp_mount.h b/include/linux/ncp_mount.h
index f46bddcdbd3..a2b549eb1ec 100644
--- a/include/linux/ncp_mount.h
+++ b/include/linux/ncp_mount.h
@@ -75,7 +75,7 @@ struct ncp_mount_data_kernel {
unsigned int int_flags; /* internal flags */
#define NCP_IMOUNT_LOGGEDIN_POSSIBLE 0x0001
__kernel_uid32_t mounted_uid; /* Who may umount() this filesystem? */
- __kernel_pid_t wdog_pid; /* Who cares for our watchdog packets? */
+ struct pid *wdog_pid; /* Who cares for our watchdog packets? */
unsigned int ncp_fd; /* The socket to the ncp port */
unsigned int time_out; /* How long should I wait after
sending a NCP request? */
diff --git a/include/linux/net.h b/include/linux/net.h
index 6f0dfeba509..4db21e63d8d 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -19,13 +19,12 @@
#define _LINUX_NET_H
#include <linux/wait.h>
-#include <linux/random.h>
#include <asm/socket.h>
struct poll_table_struct;
struct inode;
-#define NPROTO 32 /* should be enough for now.. */
+#define NPROTO 33 /* should be enough for now.. */
#define SYS_SOCKET 1 /* sys_socket(2) */
#define SYS_BIND 2 /* sys_bind(2) */
@@ -57,6 +56,7 @@ typedef enum {
#ifdef __KERNEL__
#include <linux/stringify.h>
+#include <linux/random.h>
#define SOCK_ASYNC_NOSPACE 0
#define SOCK_ASYNC_WAITDATA 1
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c57088f575a..1a528548cd1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -193,13 +193,20 @@ struct hh_cache
{
struct hh_cache *hh_next; /* Next entry */
atomic_t hh_refcnt; /* number of users */
- __be16 hh_type; /* protocol identifier, f.e ETH_P_IP
+/*
+ * We want hh_output, hh_len, hh_lock and hh_data be a in a separate
+ * cache line on SMP.
+ * They are mostly read, but hh_refcnt may be changed quite frequently,
+ * incurring cache line ping pongs.
+ */
+ __be16 hh_type ____cacheline_aligned_in_smp;
+ /* protocol identifier, f.e ETH_P_IP
* NOTE: For VLANs, this will be the
* encapuslated type. --BLG
*/
u16 hh_len; /* length of header */
int (*hh_output)(struct sk_buff *skb);
- rwlock_t hh_lock;
+ seqlock_t hh_lock;
/* cached hardware header; allow for machine alignment needs. */
#define HH_DATA_MOD 16
@@ -522,10 +529,11 @@ struct net_device
struct net_bridge_port *br_port;
/* class/net/name entry */
- struct class_device class_dev;
+ struct device dev;
/* space for optional statistics and wireless sysfs groups */
struct attribute_group *sysfs_groups[3];
};
+#define to_net_dev(d) container_of(d, struct net_device, dev)
#define NETDEV_ALIGN 32
#define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1)
@@ -541,7 +549,7 @@ static inline void *netdev_priv(struct net_device *dev)
/* Set the sysfs physical device reference for the network logical device
* if set prior to registration will cause a symlink during initialization.
*/
-#define SET_NETDEV_DEV(net, pdev) ((net)->class_dev.dev = (pdev))
+#define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev))
struct packet_type {
__be16 type; /* This is really htons(ether_type). */
@@ -581,7 +589,7 @@ extern int dev_open(struct net_device *dev);
extern int dev_close(struct net_device *dev);
extern int dev_queue_xmit(struct sk_buff *skb);
extern int register_netdevice(struct net_device *dev);
-extern int unregister_netdevice(struct net_device *dev);
+extern void unregister_netdevice(struct net_device *dev);
extern void free_netdev(struct net_device *dev);
extern void synchronize_net(void);
extern int register_netdevice_notifier(struct notifier_block *nb);
@@ -899,6 +907,7 @@ static inline void netif_poll_disable(struct net_device *dev)
static inline void netif_poll_enable(struct net_device *dev)
{
+ smp_mb__before_clear_bit();
clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
}
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild
index 6328175a1c3..43397a414cd 100644
--- a/include/linux/netfilter/Kbuild
+++ b/include/linux/netfilter/Kbuild
@@ -33,6 +33,7 @@ header-y += xt_tcpmss.h
header-y += xt_tcpudp.h
header-y += xt_SECMARK.h
header-y += xt_CONNSECMARK.h
+header-y += xt_TCPMSS.h
unifdef-y += nf_conntrack_common.h
unifdef-y += nf_conntrack_ftp.h
diff --git a/include/linux/netfilter/nf_conntrack_sane.h b/include/linux/netfilter/nf_conntrack_sane.h
new file mode 100644
index 00000000000..4767d6e23e9
--- /dev/null
+++ b/include/linux/netfilter/nf_conntrack_sane.h
@@ -0,0 +1,21 @@
+#ifndef _NF_CONNTRACK_SANE_H
+#define _NF_CONNTRACK_SANE_H
+/* SANE tracking. */
+
+#ifdef __KERNEL__
+
+#define SANE_PORT 6566
+
+enum sane_state {
+ SANE_STATE_NORMAL,
+ SANE_STATE_START_REQUESTED,
+};
+
+/* This structure exists only once per master */
+struct nf_ct_sane_master {
+ enum sane_state state;
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _NF_CONNTRACK_SANE_H */
diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h
index 6b01ba29772..007af4c2770 100644
--- a/include/linux/netfilter/nf_conntrack_tcp.h
+++ b/include/linux/netfilter/nf_conntrack_tcp.h
@@ -25,7 +25,10 @@ enum tcp_conntrack {
#define IP_CT_TCP_FLAG_SACK_PERM 0x02
/* This sender sent FIN first */
-#define IP_CT_TCP_FLAG_CLOSE_INIT 0x03
+#define IP_CT_TCP_FLAG_CLOSE_INIT 0x04
+
+/* Be liberal in window checking */
+#define IP_CT_TCP_FLAG_BE_LIBERAL 0x08
#ifdef __KERNEL__
@@ -34,7 +37,6 @@ struct ip_ct_tcp_state {
u_int32_t td_maxend; /* max of ack + max(win, 1) */
u_int32_t td_maxwin; /* max(win) */
u_int8_t td_scale; /* window scale factor */
- u_int8_t loose; /* used when connection picked up from the middle */
u_int8_t flags; /* per direction options */
};
diff --git a/include/linux/netfilter/xt_TCPMSS.h b/include/linux/netfilter/xt_TCPMSS.h
new file mode 100644
index 00000000000..53a292cd47f
--- /dev/null
+++ b/include/linux/netfilter/xt_TCPMSS.h
@@ -0,0 +1,10 @@
+#ifndef _XT_TCPMSS_H
+#define _XT_TCPMSS_H
+
+struct xt_tcpmss_info {
+ u_int16_t mss;
+};
+
+#define XT_TCPMSS_CLAMP_PMTU 0xffff
+
+#endif /* _XT_TCPMSS_H */
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
index 0be235418a2..24c8786d12e 100644
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -190,6 +190,7 @@ struct arpt_replace
/* The argument to ARPT_SO_ADD_COUNTERS. */
#define arpt_counters_info xt_counters_info
+#define arpt_counters xt_counters
/* The argument to ARPT_SO_GET_ENTRIES. */
struct arpt_get_entries
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
index 6c4613f8ad7..55689f39f77 100644
--- a/include/linux/netfilter_bridge.h
+++ b/include/linux/netfilter_bridge.h
@@ -68,7 +68,6 @@ struct bridge_skb_cb {
} daddr;
};
-extern int brnf_deferred_hooks;
#else
#define nf_bridge_maybe_copy_header(skb) (0)
#define nf_bridge_pad(skb) (0)
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index 5821eb5a0a3..ceae87a4c89 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -57,10 +57,8 @@ enum nf_ip_hook_priorities {
NF_IP_PRI_RAW = -300,
NF_IP_PRI_SELINUX_FIRST = -225,
NF_IP_PRI_CONNTRACK = -200,
- NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
NF_IP_PRI_MANGLE = -150,
NF_IP_PRI_NAT_DST = -100,
- NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT = -50,
NF_IP_PRI_FILTER = 0,
NF_IP_PRI_NAT_SRC = 100,
NF_IP_PRI_SELINUX_LAST = 225,
diff --git a/include/linux/netfilter_ipv4/ip_nat.h b/include/linux/netfilter_ipv4/ip_nat.h
index bdf553620ca..bbca89aab81 100644
--- a/include/linux/netfilter_ipv4/ip_nat.h
+++ b/include/linux/netfilter_ipv4/ip_nat.h
@@ -16,6 +16,7 @@ enum ip_nat_manip_type
#define IP_NAT_RANGE_MAP_IPS 1
#define IP_NAT_RANGE_PROTO_SPECIFIED 2
+#define IP_NAT_RANGE_PROTO_RANDOM 4 /* add randomness to "port" selection */
/* NAT sequence number modifications */
struct ip_nat_seq {
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index 4f06dad0bde..9527296595c 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -28,7 +28,7 @@
#include <linux/netfilter/x_tables.h>
#define IPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
-#define IPT_TABLE_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define IPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
#define ipt_match xt_match
#define ipt_target xt_target
#define ipt_table xt_table
@@ -272,25 +272,9 @@ ipt_get_target(struct ipt_entry *e)
#include <linux/init.h>
extern void ipt_init(void) __init;
-#define ipt_register_target(tgt) \
-({ (tgt)->family = AF_INET; \
- xt_register_target(tgt); })
-#define ipt_unregister_target(tgt) xt_unregister_target(tgt)
-
-#define ipt_register_match(mtch) \
-({ (mtch)->family = AF_INET; \
- xt_register_match(mtch); })
-#define ipt_unregister_match(mtch) xt_unregister_match(mtch)
-
-//#define ipt_register_table(tbl, repl) xt_register_table(AF_INET, tbl, repl)
-//#define ipt_unregister_table(tbl) xt_unregister_table(AF_INET, tbl)
-
-extern int ipt_register_table(struct ipt_table *table,
+extern int ipt_register_table(struct xt_table *table,
const struct ipt_replace *repl);
-extern void ipt_unregister_table(struct ipt_table *table);
-
-/* net/sched/ipt.c: Gimme access to your targets! Gets target->me. */
-extern struct ipt_target *ipt_find_target(const char *name, u8 revision);
+extern void ipt_unregister_table(struct xt_table *table);
/* Standard entry. */
struct ipt_standard
@@ -315,7 +299,7 @@ extern unsigned int ipt_do_table(struct sk_buff **pskb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
- struct ipt_table *table);
+ struct xt_table *table);
#define IPT_ALIGN(s) XT_ALIGN(s)
diff --git a/include/linux/netfilter_ipv4/ipt_TCPMSS.h b/include/linux/netfilter_ipv4/ipt_TCPMSS.h
index aadb39580cd..7a850f94582 100644
--- a/include/linux/netfilter_ipv4/ipt_TCPMSS.h
+++ b/include/linux/netfilter_ipv4/ipt_TCPMSS.h
@@ -1,10 +1,9 @@
#ifndef _IPT_TCPMSS_H
#define _IPT_TCPMSS_H
-struct ipt_tcpmss_info {
- u_int16_t mss;
-};
+#include <linux/netfilter/xt_TCPMSS.h>
-#define IPT_TCPMSS_CLAMP_PMTU 0xffff
+#define ipt_tcpmss_info xt_tcpmss_info
+#define IPT_TCPMSS_CLAMP_PMTU XT_TCPMSS_CLAMP_PMTU
#endif /*_IPT_TCPMSS_H*/
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h
index ab81a6dc94e..66ca8e3100d 100644
--- a/include/linux/netfilter_ipv6.h
+++ b/include/linux/netfilter_ipv6.h
@@ -62,10 +62,8 @@ enum nf_ip6_hook_priorities {
NF_IP6_PRI_CONNTRACK_DEFRAG = -400,
NF_IP6_PRI_SELINUX_FIRST = -225,
NF_IP6_PRI_CONNTRACK = -200,
- NF_IP6_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
NF_IP6_PRI_MANGLE = -150,
NF_IP6_PRI_NAT_DST = -100,
- NF_IP6_PRI_BRIDGE_SABOTAGE_LOCAL_OUT = -50,
NF_IP6_PRI_FILTER = 0,
NF_IP6_PRI_NAT_SRC = 100,
NF_IP6_PRI_SELINUX_LAST = 225,
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 4aed340401d..61aa10412fc 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -104,6 +104,25 @@ struct ip6t_entry
unsigned char elems[0];
};
+/* Standard entry */
+struct ip6t_standard
+{
+ struct ip6t_entry entry;
+ struct ip6t_standard_target target;
+};
+
+struct ip6t_error_target
+{
+ struct ip6t_entry_target target;
+ char errorname[IP6T_FUNCTION_MAXNAMELEN];
+};
+
+struct ip6t_error
+{
+ struct ip6t_entry entry;
+ struct ip6t_error_target target;
+};
+
/*
* New IP firewall options for [gs]etsockopt at the RAW IP level.
* Unlike BSD Linux inherits IP options so you don't have to use
@@ -286,24 +305,14 @@ ip6t_get_target(struct ip6t_entry *e)
#include <linux/init.h>
extern void ip6t_init(void) __init;
-#define ip6t_register_target(tgt) \
-({ (tgt)->family = AF_INET6; \
- xt_register_target(tgt); })
-#define ip6t_unregister_target(tgt) xt_unregister_target(tgt)
-
-#define ip6t_register_match(match) \
-({ (match)->family = AF_INET6; \
- xt_register_match(match); })
-#define ip6t_unregister_match(match) xt_unregister_match(match)
-
-extern int ip6t_register_table(struct ip6t_table *table,
+extern int ip6t_register_table(struct xt_table *table,
const struct ip6t_replace *repl);
-extern void ip6t_unregister_table(struct ip6t_table *table);
+extern void ip6t_unregister_table(struct xt_table *table);
extern unsigned int ip6t_do_table(struct sk_buff **pskb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
- struct ip6t_table *table);
+ struct xt_table *table);
/* Check for an extension */
extern int ip6t_ext_hdr(u8 nexthdr);
diff --git a/include/linux/netfilter_ipv6/ip6t_mh.h b/include/linux/netfilter_ipv6/ip6t_mh.h
new file mode 100644
index 00000000000..b9ca9a5f74d
--- /dev/null
+++ b/include/linux/netfilter_ipv6/ip6t_mh.h
@@ -0,0 +1,15 @@
+#ifndef _IP6T_MH_H
+#define _IP6T_MH_H
+
+/* MH matching stuff */
+struct ip6t_mh
+{
+ u_int8_t types[2]; /* MH type range */
+ u_int8_t invflags; /* Inverse flags */
+};
+
+/* Values for "invflags" field in struct ip6t_mh. */
+#define IP6T_MH_INV_TYPE 0x01 /* Invert the sense of type. */
+#define IP6T_MH_INV_MASK 0x01 /* All possible flags. */
+
+#endif /*_IP6T_MH_H*/
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 04963063e62..c5d4084773e 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -308,6 +308,7 @@ extern int nfs_attribute_timeout(struct inode *inode);
extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
+extern int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping);
extern int nfs_setattr(struct dentry *, struct iattr *);
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
extern void nfs_begin_attr_update(struct inode *);
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index edb54c3171b..4b7c4b568f6 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -52,8 +52,6 @@
struct readdir_cd {
__be32 err; /* 0, nfserr, or nfserr_eof */
};
-typedef int (*encode_dent_fn)(struct readdir_cd *, const char *,
- int, loff_t, ino_t, unsigned int);
typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
extern struct svc_program nfsd_program;
@@ -117,7 +115,7 @@ __be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
int nfsd_truncate(struct svc_rqst *, struct svc_fh *,
unsigned long size);
__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
- loff_t *, struct readdir_cd *, encode_dent_fn);
+ loff_t *, struct readdir_cd *, filldir_t);
__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
struct kstatfs *);
@@ -275,12 +273,12 @@ static inline int is_fsid(struct svc_fh *fh, struct knfsd_fh *reffh)
* we might process an operation with side effects, and be unable to
* tell the client that the operation succeeded.
*
- * COMPOUND_SLACK_SPACE - this is the minimum amount of buffer space
+ * COMPOUND_SLACK_SPACE - this is the minimum bytes of buffer space
* needed to encode an "ordinary" _successful_ operation. (GETATTR,
* READ, READDIR, and READLINK have their own buffer checks.) if we
* fall below this level, we fail the next operation with NFS4ERR_RESOURCE.
*
- * COMPOUND_ERR_SLACK_SPACE - this is the minimum amount of buffer space
+ * COMPOUND_ERR_SLACK_SPACE - this is the minimum bytes of buffer space
* needed to encode an operation which has failed with NFS4ERR_RESOURCE.
* care is taken to ensure that we never fall below this level for any
* reason.
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
index f3b51d62ec7..d9c6c382165 100644
--- a/include/linux/nfsd/nfsfh.h
+++ b/include/linux/nfsd/nfsfh.h
@@ -217,11 +217,7 @@ void fh_put(struct svc_fh *);
static __inline__ struct svc_fh *
fh_copy(struct svc_fh *dst, struct svc_fh *src)
{
- if (src->fh_dentry || src->fh_locked) {
- struct dentry *dentry = src->fh_dentry;
- printk(KERN_ERR "fh_copy: copying %s/%s, already verified!\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- }
+ WARN_ON(src->fh_dentry || src->fh_locked);
*dst = *src;
return dst;
@@ -300,10 +296,8 @@ fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
dfprintk(FILEOP, "nfsd: fh_lock(%s) locked = %d\n",
SVCFH_fmt(fhp), fhp->fh_locked);
- if (!fhp->fh_dentry) {
- printk(KERN_ERR "fh_lock: fh not verified!\n");
- return;
- }
+ BUG_ON(!dentry);
+
if (fhp->fh_locked) {
printk(KERN_WARNING "fh_lock: %s/%s already locked!\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -328,8 +322,7 @@ fh_lock(struct svc_fh *fhp)
static inline void
fh_unlock(struct svc_fh *fhp)
{
- if (!fhp->fh_dentry)
- printk(KERN_ERR "fh_unlock: fh not verified!\n");
+ BUG_ON(!fhp->fh_dentry);
if (fhp->fh_locked) {
fill_post_wcc(fhp);
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index c3673f487e8..ab5c236bd9a 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -273,7 +273,6 @@ struct nfs4_stateid {
((err) != nfserr_stale_stateid) && \
((err) != nfserr_bad_stateid))
-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);
diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h
index 877192d3ae7..67885d5e6e5 100644
--- a/include/linux/nfsd/xdr.h
+++ b/include/linux/nfsd/xdr.h
@@ -165,8 +165,8 @@ 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_encode_entry(void *, const char *name,
+ int namlen, loff_t offset, u64 ino, unsigned int);
int nfssvc_release_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h
index 79963867b0d..89d9d6061a6 100644
--- a/include/linux/nfsd/xdr3.h
+++ b/include/linux/nfsd/xdr3.h
@@ -331,11 +331,11 @@ int nfs3svc_release_fhandle(struct svc_rqst *, __be32 *,
struct nfsd3_attrstat *);
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,
+int nfs3svc_encode_entry(void *, const char *name,
+ int namlen, loff_t offset, u64 ino,
unsigned int);
-int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name,
- int namlen, loff_t offset, ino_t ino,
+int nfs3svc_encode_entry_plus(void *, const char *name,
+ int namlen, loff_t offset, u64 ino,
unsigned int);
/* Helper functions for NFSv3 ACL code */
__be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p,
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index 45ca01b5f84..09799bcee0a 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -44,6 +44,12 @@
#define NFSD4_MAX_TAGLEN 128
#define XDR_LEN(n) (((n) + 3) & ~3)
+struct nfsd4_compound_state {
+ struct svc_fh current_fh;
+ struct svc_fh save_fh;
+ struct nfs4_stateowner *replay_owner;
+};
+
struct nfsd4_change_info {
u32 atomic;
u32 before_ctime_sec;
@@ -430,35 +436,39 @@ __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 __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *,
struct nfsd4_setclientid *setclid);
extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *,
struct nfsd4_setclientid_confirm *setclientid_confirm);
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 __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
- struct svc_fh *current_fh, struct nfsd4_open_confirm *oc,
- struct nfs4_stateowner **);
-extern __be32 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh,
- struct nfsd4_close *close,
- struct nfs4_stateowner **replay_owner);
+ struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc);
+extern __be32 nfsd4_close(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *,
+ struct nfsd4_close *close);
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 __be32 nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh,
- struct nfsd4_lock *lock,
- struct nfs4_stateowner **replay_owner);
-extern __be32 nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+ struct nfsd4_compound_state *,
+ struct nfsd4_open_downgrade *od);
+extern __be32 nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *,
+ struct nfsd4_lock *lock);
+extern __be32 nfsd4_lockt(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *,
struct nfsd4_lockt *lockt);
-extern __be32 nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh,
- struct nfsd4_locku *locku,
- struct nfs4_stateowner **replay_owner);
+extern __be32 nfsd4_locku(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *,
+ struct nfsd4_locku *locku);
extern __be32
nfsd4_release_lockowner(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *,
struct nfsd4_release_lockowner *rlockowner);
extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *);
extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
- struct svc_fh *current_fh, struct nfsd4_delegreturn *dr);
+ struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
+extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *, clientid_t *clid);
#endif
/*
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index 971d1c6dfc4..0b9f0dc30d6 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -4,9 +4,10 @@
#include <linux/spinlock.h>
#include <linux/sched.h>
-struct namespace;
+struct mnt_namespace;
struct uts_namespace;
struct ipc_namespace;
+struct pid_namespace;
/*
* A structure to contain pointers to all per-process
@@ -25,7 +26,8 @@ struct nsproxy {
spinlock_t nslock;
struct uts_namespace *uts_ns;
struct ipc_namespace *ipc_ns;
- struct namespace *namespace;
+ struct mnt_namespace *mnt_ns;
+ struct pid_namespace *pid_ns;
};
extern struct nsproxy init_nsproxy;
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 4830a3bedfb..350878a2d84 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -253,15 +253,11 @@ static inline void SetPageUptodate(struct page *page)
struct page; /* forward declaration */
-int test_clear_page_dirty(struct page *page);
+extern void cancel_dirty_page(struct page *page, unsigned int account_size);
+
int test_clear_page_writeback(struct page *page);
int test_set_page_writeback(struct page *page);
-static inline void clear_page_dirty(struct page *page)
-{
- test_clear_page_dirty(page);
-}
-
static inline void set_page_writeback(struct page *page)
{
test_set_page_writeback(page);
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index c3e255bf859..7a8dcb82a69 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -76,8 +76,6 @@ extern struct page * find_get_page(struct address_space *mapping,
unsigned long index);
extern struct page * find_lock_page(struct address_space *mapping,
unsigned long index);
-extern __deprecated_for_modules struct page * find_trylock_page(
- struct address_space *mapping, unsigned long index);
extern struct page * find_or_create_page(struct address_space *mapping,
unsigned long index, gfp_t gfp_mask);
unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 01c707261f9..9e3042e7e1c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -20,9 +20,6 @@
/* Include the pci register defines */
#include <linux/pci_regs.h>
-/* Include the ID list */
-#include <linux/pci_ids.h>
-
/*
* The PCI interface treats multi-function devices as independent
* devices. The slot/function address of each device is encoded
@@ -54,6 +51,9 @@
#include <asm/atomic.h>
#include <linux/device.h>
+/* Include the ID list */
+#include <linux/pci_ids.h>
+
/* File state for mmap()s on /proc/bus/pci/X/Y */
enum pci_mmap_state {
pci_mmap_io,
@@ -167,6 +167,7 @@ struct pci_dev {
unsigned int broken_parity_status:1; /* Device generates false positive parity */
unsigned int msi_enabled:1;
unsigned int msix_enabled:1;
+ unsigned int is_managed:1;
atomic_t enable_cnt; /* pci_enable_device has been called */
u32 saved_config_space[16]; /* config space saved at suspend time */
@@ -174,6 +175,9 @@ struct pci_dev {
struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */
int rom_attr_enabled; /* has display of the rom attribute been enabled? */
struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
+#ifdef CONFIG_PCI_MSI
+ unsigned int first_msi_irq;
+#endif
};
#define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
@@ -181,6 +185,11 @@ struct pci_dev {
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
#define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
+static inline int pci_channel_offline(struct pci_dev *pdev)
+{
+ return (pdev->error_state != pci_channel_io_normal);
+}
+
static inline struct pci_cap_saved_state *pci_find_saved_cap(
struct pci_dev *pci_dev,char cap)
{
@@ -396,6 +405,21 @@ struct pci_driver {
*/
#define pci_module_init pci_register_driver
+/**
+ * PCI_VDEVICE - macro used to describe a specific pci device in short form
+ * @vend: the vendor name
+ * @dev: the 16 bit PCI Device ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific PCI device. The subvendor, and subdevice fields will be set
+ * to PCI_ANY_ID. The macro allows the next field to follow as the device
+ * private data.
+ */
+
+#define PCI_VDEVICE(vendor, device) \
+ PCI_VENDOR_ID_##vendor, (device), \
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0
+
/* these external functions are only available when PCI support is enabled */
#ifdef CONFIG_PCI
@@ -448,12 +472,13 @@ extern void pci_sort_breadthfirst(void);
/* Generic PCI functions exported to card drivers */
-struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from);
-struct pci_dev *pci_find_device_reverse (unsigned int vendor, unsigned int device, const struct pci_dev *from);
+struct pci_dev __deprecated *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from);
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);
+int pci_find_ht_capability (struct pci_dev *dev, int ht_cap);
+int pci_find_next_ht_capability (struct pci_dev *dev, int pos, int ht_cap);
struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
@@ -468,6 +493,7 @@ 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);
+const struct pci_device_id *pci_find_present(const struct pci_device_id *ids);
int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
@@ -503,6 +529,14 @@ static inline int pci_write_config_dword(struct pci_dev *dev, int where, u32 val
int __must_check pci_enable_device(struct pci_dev *dev);
int __must_check pci_enable_device_bars(struct pci_dev *dev, int mask);
+int __must_check pcim_enable_device(struct pci_dev *pdev);
+void pcim_pin_device(struct pci_dev *pdev);
+
+static inline int pci_is_managed(struct pci_dev *pdev)
+{
+ return pdev->is_managed;
+}
+
void pci_disable_device(struct pci_dev *dev);
void pci_set_master(struct pci_dev *dev);
#define HAVE_PCI_SET_MWI
@@ -515,6 +549,7 @@ void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
int __must_check pci_assign_resource(struct pci_dev *dev, int i);
int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i);
void pci_restore_bars(struct pci_dev *dev);
+int pci_select_bars(struct pci_dev *dev, unsigned long flags);
/* ROM control related routines */
void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size);
@@ -543,6 +578,8 @@ int __must_check pci_request_regions(struct pci_dev *, const char *);
void pci_release_regions(struct pci_dev *);
int __must_check pci_request_region(struct pci_dev *, int, const char *);
void pci_release_region(struct pci_dev *, int);
+int pci_request_selected_regions(struct pci_dev *, int, const char *);
+void pci_release_selected_regions(struct pci_dev *, int);
/* drivers/pci/bus.c */
int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
@@ -555,10 +592,11 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
void pci_enable_bridges(struct pci_bus *bus);
/* Proper probing supporting hot-pluggable devices */
-int __must_check __pci_register_driver(struct pci_driver *, struct module *);
+int __must_check __pci_register_driver(struct pci_driver *, struct module *,
+ const char *mod_name);
static inline int __must_check pci_register_driver(struct pci_driver *driver)
{
- return __pci_register_driver(driver, THIS_MODULE);
+ return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
}
void pci_unregister_driver(struct pci_driver *);
@@ -593,10 +631,6 @@ enum pci_dma_burst_strategy {
strategy_parameter byte boundaries */
};
-#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
-extern struct pci_dev *isa_bridge;
-#endif
-
struct msix_entry {
u16 vector; /* kernel uses to write allocated vector */
u16 entry; /* driver uses to specify entry, OS writes */
@@ -604,7 +638,6 @@ struct msix_entry {
#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;}
static inline void pci_disable_msi(struct pci_dev *dev) {}
static inline int pci_enable_msix(struct pci_dev* dev,
@@ -612,7 +645,6 @@ static inline int pci_enable_msix(struct pci_dev* dev,
static inline void pci_disable_msix(struct pci_dev *dev) {}
static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
#else
-extern void pci_scan_msi_device(struct pci_dev *dev);
extern int pci_enable_msi(struct pci_dev *dev);
extern void pci_disable_msi(struct pci_dev *dev);
extern int pci_enable_msix(struct pci_dev* dev,
@@ -681,6 +713,7 @@ static inline struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *
{ return NULL; }
#define pci_dev_present(ids) (0)
+#define pci_find_present(ids) (NULL)
#define pci_dev_put(dev) do { } while (0)
static inline void pci_set_master(struct pci_dev *dev) { }
@@ -703,8 +736,6 @@ static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) {
static inline pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { return PCI_D0; }
static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { return 0; }
-#define isa_bridge ((struct pci_dev *)NULL)
-
#define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
static inline void pci_block_user_cfg_access(struct pci_dev *dev) { }
@@ -783,6 +814,7 @@ enum pci_fixup_pass {
pci_fixup_header, /* After reading configuration header */
pci_fixup_final, /* Final phase of device fixups */
pci_fixup_enable, /* pci_enable_device() time */
+ pci_fixup_resume, /* pci_enable_device() time */
};
/* Anonymous variables would be nice... */
@@ -801,6 +833,9 @@ enum pci_fixup_pass {
#define DECLARE_PCI_FIXUP_ENABLE(vendor, device, hook) \
DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable, \
vendor##device##hook, vendor, device, hook)
+#define DECLARE_PCI_FIXUP_RESUME(vendor, device, hook) \
+ DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume, \
+ resume##vendor##device##hook, vendor, device, hook)
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 4d972bbef31..e67b68ca235 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -15,6 +15,8 @@
#define PCI_CLASS_STORAGE_FLOPPY 0x0102
#define PCI_CLASS_STORAGE_IPI 0x0103
#define PCI_CLASS_STORAGE_RAID 0x0104
+#define PCI_CLASS_STORAGE_SATA 0x0106
+#define PCI_CLASS_STORAGE_SATA_AHCI 0x010601
#define PCI_CLASS_STORAGE_SAS 0x0107
#define PCI_CLASS_STORAGE_OTHER 0x0180
@@ -95,6 +97,7 @@
#define PCI_BASE_CLASS_SERIAL 0x0c
#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00
+#define PCI_CLASS_SERIAL_FIREWIRE_OHCI 0x0c0010
#define PCI_CLASS_SERIAL_ACCESS 0x0c01
#define PCI_CLASS_SERIAL_SSA 0x0c02
#define PCI_CLASS_SERIAL_USB 0x0c03
@@ -104,6 +107,10 @@
#define PCI_CLASS_SERIAL_FIBER 0x0c04
#define PCI_CLASS_SERIAL_SMBUS 0x0c05
+#define PCI_BASE_CLASS_WIRELESS 0x0d
+#define PCI_CLASS_WIRELESS_RF_CONTROLLER 0x0d10
+#define PCI_CLASS_WIRELESS_WHCI 0x0d1010
+
#define PCI_BASE_CLASS_INTELLIGENT 0x0e
#define PCI_CLASS_INTELLIGENT_I2O 0x0e00
@@ -731,9 +738,11 @@
#define PCI_DEVICE_ID_TI_TVP4020 0x3d07
#define PCI_DEVICE_ID_TI_4450 0x8011
#define PCI_DEVICE_ID_TI_XX21_XX11 0x8031
+#define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033
#define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034
#define PCI_DEVICE_ID_TI_X515 0x8036
#define PCI_DEVICE_ID_TI_XX12 0x8039
+#define PCI_DEVICE_ID_TI_XX12_FM 0x803b
#define PCI_DEVICE_ID_TI_1130 0xac12
#define PCI_DEVICE_ID_TI_1031 0xac13
#define PCI_DEVICE_ID_TI_1131 0xac15
@@ -761,6 +770,7 @@
#define PCI_DEVICE_ID_TI_1510 0xac56
#define PCI_DEVICE_ID_TI_X620 0xac8d
#define PCI_DEVICE_ID_TI_X420 0xac8e
+#define PCI_DEVICE_ID_TI_XX20_FM 0xac8f
#define PCI_VENDOR_ID_SONY 0x104d
@@ -1273,12 +1283,13 @@
#define PCI_DEVICE_ID_VIA_3296_0 0x0296
#define PCI_DEVICE_ID_VIA_8363_0 0x0305
#define PCI_DEVICE_ID_VIA_P4M800CE 0x0314
+#define PCI_DEVICE_ID_VIA_P4M890 0x0327
+#define PCI_DEVICE_ID_VIA_VT3336 0x0336
#define PCI_DEVICE_ID_VIA_8371_0 0x0391
#define PCI_DEVICE_ID_VIA_8501_0 0x0501
#define PCI_DEVICE_ID_VIA_82C561 0x0561
#define PCI_DEVICE_ID_VIA_82C586_1 0x0571
#define PCI_DEVICE_ID_VIA_82C576 0x0576
-#define PCI_DEVICE_ID_VIA_SATA_EIDE 0x0581
#define PCI_DEVICE_ID_VIA_82C586_0 0x0586
#define PCI_DEVICE_ID_VIA_82C596 0x0596
#define PCI_DEVICE_ID_VIA_82C597_0 0x0597
@@ -1321,6 +1332,8 @@
#define PCI_DEVICE_ID_VIA_8237 0x3227
#define PCI_DEVICE_ID_VIA_8251 0x3287
#define PCI_DEVICE_ID_VIA_8237A 0x3337
+#define PCI_DEVICE_ID_VIA_8237S 0x3372
+#define PCI_DEVICE_ID_VIA_SATA_EIDE 0x5324
#define PCI_DEVICE_ID_VIA_8231 0x8231
#define PCI_DEVICE_ID_VIA_8231_4 0x8235
#define PCI_DEVICE_ID_VIA_8365_1 0x8305
@@ -1444,6 +1457,7 @@
#define PCI_VENDOR_ID_TOSHIBA_2 0x102f
#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE 0x0105
#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108
#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
@@ -1621,6 +1635,7 @@
#define PCI_VENDOR_ID_ITE 0x1283
#define PCI_DEVICE_ID_ITE_8211 0x8211
#define PCI_DEVICE_ID_ITE_8212 0x8212
+#define PCI_DEVICE_ID_ITE_8213 0x8213
#define PCI_DEVICE_ID_ITE_8872 0x8872
#define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886
@@ -1785,14 +1800,17 @@
#define PCI_DEVICE_ID_MOXA_C104 0x1040
#define PCI_DEVICE_ID_MOXA_CP104U 0x1041
#define PCI_DEVICE_ID_MOXA_CP104JU 0x1042
+#define PCI_DEVICE_ID_MOXA_CP104EL 0x1043
#define PCI_DEVICE_ID_MOXA_CT114 0x1140
#define PCI_DEVICE_ID_MOXA_CP114 0x1141
#define PCI_DEVICE_ID_MOXA_CP118U 0x1180
+#define PCI_DEVICE_ID_MOXA_CP118EL 0x1181
#define PCI_DEVICE_ID_MOXA_CP132 0x1320
#define PCI_DEVICE_ID_MOXA_CP132U 0x1321
#define PCI_DEVICE_ID_MOXA_CP134U 0x1340
#define PCI_DEVICE_ID_MOXA_C168 0x1680
#define PCI_DEVICE_ID_MOXA_CP168U 0x1681
+#define PCI_DEVICE_ID_MOXA_CP168EL 0x1682
#define PCI_VENDOR_ID_CCD 0x1397
#define PCI_DEVICE_ID_CCD_2BD0 0x2bd0
@@ -1961,6 +1979,7 @@
#define PCI_DEVICE_ID_TOPIC_TP560 0x0000
#define PCI_VENDOR_ID_ENE 0x1524
+#define PCI_DEVICE_ID_ENE_CB712_SD 0x0550
#define PCI_DEVICE_ID_ENE_1211 0x1211
#define PCI_DEVICE_ID_ENE_1225 0x1225
#define PCI_DEVICE_ID_ENE_1410 0x1410
@@ -2056,6 +2075,10 @@
#define PCI_VENDOR_ID_TDI 0x192E
#define PCI_DEVICE_ID_TDI_EHCI 0x0101
+#define PCI_VENDOR_ID_PASEMI 0x1959
+
+#define PCI_VENDOR_ID_ATTANSIC 0x1969
+
#define PCI_VENDOR_ID_JMICRON 0x197B
#define PCI_DEVICE_ID_JMICRON_JMB360 0x2360
#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361
@@ -2064,6 +2087,10 @@
#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366
#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368
+#define PCI_VENDOR_ID_KORENIX 0x1982
+#define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600
+#define PCI_DEVICE_ID_KORENIX_JETCARDF1 0x16ff
+
#define PCI_VENDOR_ID_TEKRAM 0x1de1
#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index 064b1dc71c2..7a6d34ee5ab 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -475,15 +475,32 @@
#define PCI_PWR_CAP 12 /* Capability */
#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */
-/* Hypertransport sub capability types */
+/*
+ * Hypertransport sub capability types
+ *
+ * Unfortunately there are both 3 bit and 5 bit capability types defined
+ * in the HT spec, catering for that is a little messy. You probably don't
+ * want to use these directly, just use pci_find_ht_capability() and it
+ * will do the right thing for you.
+ */
+#define HT_3BIT_CAP_MASK 0xE0
#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */
#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */
+
+#define HT_5BIT_CAP_MASK 0xF8
#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_MSI_FLAGS 0x02 /* Offset to flags */
+#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */
+#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */
+#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */
+#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */
+#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */
+#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */
#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 */
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
index 265bafab649..d9db5f62ee4 100644
--- a/include/linux/pfkeyv2.h
+++ b/include/linux/pfkeyv2.h
@@ -251,7 +251,8 @@ struct sadb_x_sec_ctx {
#define SADB_X_SPDEXPIRE 21
#define SADB_X_SPDDELETE2 22
#define SADB_X_NAT_T_NEW_MAPPING 23
-#define SADB_MAX 23
+#define SADB_X_MIGRATE 24
+#define SADB_MAX 24
/* Security Association flags */
#define SADB_SAFLAGS_PFS 1
@@ -297,6 +298,7 @@ struct sadb_x_sec_ctx {
#define SADB_X_EALG_BLOWFISHCBC 7
#define SADB_EALG_NULL 11
#define SADB_X_EALG_AESCBC 12
+#define SADB_X_EALG_CAMELLIACBC 22
#define SADB_EALG_MAX 253 /* last EALG */
/* private allocations should use 249-255 (RFC2407) */
#define SADB_X_EALG_SERPENTCBC 252 /* draft-ietf-ipsec-ciph-aes-cbc-00 */
diff --git a/include/linux/pid.h b/include/linux/pid.h
index 2c0007d1721..4dec047b183 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -35,8 +35,9 @@ enum pid_type
*
* Holding a reference to struct pid solves both of these problems.
* It is small so holding a reference does not consume a lot of
- * resources, and since a new struct pid is allocated when the numeric
- * pid value is reused we don't mistakenly refer to new processes.
+ * resources, and since a new struct pid is allocated when the numeric pid
+ * value is reused (when pids wrap around) we don't mistakenly refer to new
+ * processes.
*/
struct pid
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
new file mode 100644
index 00000000000..2833806d42c
--- /dev/null
+++ b/include/linux/pid_namespace.h
@@ -0,0 +1,45 @@
+#ifndef _LINUX_PID_NS_H
+#define _LINUX_PID_NS_H
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/threads.h>
+#include <linux/pid.h>
+#include <linux/nsproxy.h>
+#include <linux/kref.h>
+
+struct pidmap {
+ atomic_t nr_free;
+ void *page;
+};
+
+#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8)
+
+struct pid_namespace {
+ struct kref kref;
+ struct pidmap pidmap[PIDMAP_ENTRIES];
+ int last_pid;
+ struct task_struct *child_reaper;
+};
+
+extern struct pid_namespace init_pid_ns;
+
+static inline void get_pid_ns(struct pid_namespace *ns)
+{
+ kref_get(&ns->kref);
+}
+
+extern int copy_pid_ns(int flags, struct task_struct *tsk);
+extern void free_pid_ns(struct kref *kref);
+
+static inline void put_pid_ns(struct pid_namespace *ns)
+{
+ kref_put(&ns->kref, free_pid_ns);
+}
+
+static inline struct task_struct *child_reaper(struct task_struct *tsk)
+{
+ return init_pid_ns.child_reaper;
+}
+
+#endif /* _LINUX_PID_NS_H */
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index ea4f7cd7bfd..2e19478e9e8 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -12,7 +12,7 @@
struct pipe_buffer {
struct page *page;
unsigned int offset, len;
- struct pipe_buf_operations *ops;
+ const struct pipe_buf_operations *ops;
unsigned int flags;
};
@@ -41,9 +41,7 @@ struct pipe_buf_operations {
struct pipe_inode_info {
wait_queue_head_t wait;
unsigned int nrbufs, curbuf;
- struct pipe_buffer bufs[PIPE_BUFFERS];
struct page *tmp_page;
- unsigned int start;
unsigned int readers;
unsigned int writers;
unsigned int waiting_writers;
@@ -52,6 +50,7 @@ struct pipe_inode_info {
struct fasync_struct *fasync_readers;
struct fasync_struct *fasync_writers;
struct inode *inode;
+ struct pipe_buffer bufs[PIPE_BUFFERS];
};
/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual
diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h
index 8a94c717c26..5ea4f05683f 100644
--- a/include/linux/pktcdvd.h
+++ b/include/linux/pktcdvd.h
@@ -111,6 +111,13 @@ struct pkt_ctrl_command {
#include <linux/blkdev.h>
#include <linux/completion.h>
#include <linux/cdrom.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+
+/* default bio write queue congestion marks */
+#define PKT_WRITE_CONGESTION_ON 10000
+#define PKT_WRITE_CONGESTION_OFF 9000
+
struct packet_settings
{
@@ -241,6 +248,14 @@ struct packet_stacked_data
};
#define PSD_POOL_SIZE 64
+struct pktcdvd_kobj
+{
+ struct kobject kobj;
+ struct pktcdvd_device *pd;
+};
+#define to_pktcdvdkobj(_k) \
+ ((struct pktcdvd_kobj*)container_of(_k,struct pktcdvd_kobj,kobj))
+
struct pktcdvd_device
{
struct block_device *bdev; /* dev attached */
@@ -271,6 +286,16 @@ struct pktcdvd_device
struct packet_iosched iosched;
struct gendisk *disk;
+
+ int write_congestion_off;
+ int write_congestion_on;
+
+ struct class_device *clsdev; /* sysfs pktcdvd[0-7] class dev */
+ struct pktcdvd_kobj *kobj_stat; /* sysfs pktcdvd[0-7]/stat/ */
+ struct pktcdvd_kobj *kobj_wqueue; /* sysfs pktcdvd[0-7]/write_queue/ */
+
+ struct dentry *dfs_d_root; /* debugfs: devname directory */
+ struct dentry *dfs_f_info; /* debugfs: info file */
};
#endif /* __KERNEL__ */
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 20f47b81d3f..8bbd459eafd 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -39,7 +39,7 @@ extern struct platform_device *platform_device_register_simple(char *, unsigned
extern struct platform_device *platform_device_alloc(const char *name, unsigned int id);
extern int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num);
-extern int platform_device_add_data(struct platform_device *pdev, void *data, size_t size);
+extern int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size);
extern int platform_device_add(struct platform_device *pdev);
extern void platform_device_del(struct platform_device *pdev);
extern void platform_device_put(struct platform_device *pdev);
diff --git a/include/linux/profile.h b/include/linux/profile.h
index 5670b340c4e..eec48f5f934 100644
--- a/include/linux/profile.h
+++ b/include/linux/profile.h
@@ -15,6 +15,7 @@ extern int prof_on __read_mostly;
#define CPU_PROFILING 1
#define SCHED_PROFILING 2
#define SLEEP_PROFILING 3
+#define KVM_PROFILING 4
struct proc_dir_entry;
struct pt_regs;
diff --git a/include/linux/pspace.h b/include/linux/pspace.h
deleted file mode 100644
index 91d48b8b2d9..00000000000
--- a/include/linux/pspace.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#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/qic117.h b/include/linux/qic117.h
deleted file mode 100644
index 07b537e5d35..00000000000
--- a/include/linux/qic117.h
+++ /dev/null
@@ -1,290 +0,0 @@
-#ifndef _QIC117_H
-#define _QIC117_H
-
-/*
- * Copyright (C) 1993-1996 Bas Laarhoven,
- * (C) 1997 Claus-Justus Heine.
-
- This program is free software; you can redistribute 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; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- *
- * $Source: /homes/cvs/ftape-stacked/include/linux/qic117.h,v $
- * $Revision: 1.2 $
- * $Date: 1997/10/05 19:19:32 $
- *
- * This file contains QIC-117 spec. related definitions for the
- * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
- *
- * These data were taken from the Quarter-Inch Cartridge
- * Drive Standards, Inc. document titled:
- * `Common Command Set Interface Specification for Flexible
- * Disk Controller Based Minicartridge Tape Drives'
- * document QIC-117 Revision J, 28 Aug 96.
- * For more information, contact:
- * Quarter-Inch Cartridge Drive Standards, Inc.
- * 311 East Carrillo Street
- * Santa Barbara, California 93101
- * Telephone (805) 963-3853
- * Fax (805) 962-1541
- * WWW http://www.qic.org
- *
- * Current QIC standard revisions (of interest) are:
- * QIC-40-MC, Rev. M, 2 Sep 92.
- * QIC-80-MC, Rev. N, 20 Mar 96.
- * QIC-80-MC, Rev. K, 15 Dec 94.
- * QIC-113, Rev. G, 15 Jun 95.
- * QIC-117, Rev. J, 28 Aug 96.
- * QIC-122, Rev. B, 6 Mar 91.
- * QIC-130, Rev. C, 2 Sep 92.
- * QIC-3010-MC, Rev. F, 14 Jun 95.
- * QIC-3020-MC, Rev. G, 31 Aug 95.
- * QIC-CRF3, Rev. B, 15 Jun 95.
- * */
-
-/*
- * QIC-117 common command set rev. J.
- * These commands are sent to the tape unit
- * as number of pulses over the step line.
- */
-
-typedef enum {
- QIC_NO_COMMAND = 0,
- QIC_RESET = 1,
- QIC_REPORT_NEXT_BIT = 2,
- QIC_PAUSE = 3,
- QIC_MICRO_STEP_PAUSE = 4,
- QIC_ALTERNATE_TIMEOUT = 5,
- QIC_REPORT_DRIVE_STATUS = 6,
- QIC_REPORT_ERROR_CODE = 7,
- QIC_REPORT_DRIVE_CONFIGURATION = 8,
- QIC_REPORT_ROM_VERSION = 9,
- QIC_LOGICAL_FORWARD = 10,
- QIC_PHYSICAL_REVERSE = 11,
- QIC_PHYSICAL_FORWARD = 12,
- QIC_SEEK_HEAD_TO_TRACK = 13,
- QIC_SEEK_LOAD_POINT = 14,
- QIC_ENTER_FORMAT_MODE = 15,
- QIC_WRITE_REFERENCE_BURST = 16,
- QIC_ENTER_VERIFY_MODE = 17,
- QIC_STOP_TAPE = 18,
-/* commands 19-20: reserved */
- QIC_MICRO_STEP_HEAD_UP = 21,
- QIC_MICRO_STEP_HEAD_DOWN = 22,
- QIC_SOFT_SELECT = 23,
- QIC_SOFT_DESELECT = 24,
- QIC_SKIP_REVERSE = 25,
- QIC_SKIP_FORWARD = 26,
- QIC_SELECT_RATE = 27,
-/* command 27, in ccs2: Select Rate or Format */
- QIC_ENTER_DIAGNOSTIC_1 = 28,
- QIC_ENTER_DIAGNOSTIC_2 = 29,
- QIC_ENTER_PRIMARY_MODE = 30,
-/* command 31: vendor unique */
- QIC_REPORT_VENDOR_ID = 32,
- QIC_REPORT_TAPE_STATUS = 33,
- QIC_SKIP_EXTENDED_REVERSE = 34,
- QIC_SKIP_EXTENDED_FORWARD = 35,
- QIC_CALIBRATE_TAPE_LENGTH = 36,
- QIC_REPORT_FORMAT_SEGMENTS = 37,
- QIC_SET_FORMAT_SEGMENTS = 38,
-/* commands 39-45: reserved */
- QIC_PHANTOM_SELECT = 46,
- QIC_PHANTOM_DESELECT = 47
-} qic117_cmd_t;
-
-typedef enum {
- discretional = 0, required, ccs1, ccs2
-} qic_compatibility;
-
-typedef enum {
- unused, mode, motion, report
-} command_types;
-
-struct qic117_command_table {
- char *name;
- __u8 mask;
- __u8 state;
- __u8 cmd_type;
- __u8 non_intr;
- __u8 level;
-};
-
-#define QIC117_COMMANDS {\
-/* command mask state cmd_type */\
-/* | name | | | non_intr */\
-/* | | | | | | level */\
-/* 0*/ {NULL, 0x00, 0x00, mode, 0, discretional},\
-/* 1*/ {"soft reset", 0x00, 0x00, motion, 1, required},\
-/* 2*/ {"report next bit", 0x00, 0x00, report, 0, required},\
-/* 3*/ {"pause", 0x36, 0x24, motion, 1, required},\
-/* 4*/ {"micro step pause", 0x36, 0x24, motion, 1, required},\
-/* 5*/ {"alternate command timeout", 0x00, 0x00, mode, 0, required},\
-/* 6*/ {"report drive status", 0x00, 0x00, report, 0, required},\
-/* 7*/ {"report error code", 0x01, 0x01, report, 0, required},\
-/* 8*/ {"report drive configuration",0x00, 0x00, report, 0, required},\
-/* 9*/ {"report rom version", 0x00, 0x00, report, 0, required},\
-/*10*/ {"logical forward", 0x37, 0x25, motion, 0, required},\
-/*11*/ {"physical reverse", 0x17, 0x05, motion, 0, required},\
-/*12*/ {"physical forward", 0x17, 0x05, motion, 0, required},\
-/*13*/ {"seek head to track", 0x37, 0x25, motion, 0, required},\
-/*14*/ {"seek load point", 0x17, 0x05, motion, 1, required},\
-/*15*/ {"enter format mode", 0x1f, 0x05, mode, 0, required},\
-/*16*/ {"write reference burst", 0x1f, 0x05, motion, 1, required},\
-/*17*/ {"enter verify mode", 0x37, 0x25, mode, 0, required},\
-/*18*/ {"stop tape", 0x00, 0x00, motion, 1, required},\
-/*19*/ {"reserved (19)", 0x00, 0x00, unused, 0, discretional},\
-/*20*/ {"reserved (20)", 0x00, 0x00, unused, 0, discretional},\
-/*21*/ {"micro step head up", 0x02, 0x00, motion, 0, required},\
-/*22*/ {"micro step head down", 0x02, 0x00, motion, 0, required},\
-/*23*/ {"soft select", 0x00, 0x00, mode, 0, discretional},\
-/*24*/ {"soft deselect", 0x00, 0x00, mode, 0, discretional},\
-/*25*/ {"skip segments reverse", 0x36, 0x24, motion, 1, required},\
-/*26*/ {"skip segments forward", 0x36, 0x24, motion, 1, required},\
-/*27*/ {"select rate or format", 0x03, 0x01, mode, 0, required /* [ccs2] */},\
-/*28*/ {"enter diag mode 1", 0x00, 0x00, mode, 0, discretional},\
-/*29*/ {"enter diag mode 2", 0x00, 0x00, mode, 0, discretional},\
-/*30*/ {"enter primary mode", 0x00, 0x00, mode, 0, required},\
-/*31*/ {"vendor unique (31)", 0x00, 0x00, unused, 0, discretional},\
-/*32*/ {"report vendor id", 0x00, 0x00, report, 0, required},\
-/*33*/ {"report tape status", 0x04, 0x04, report, 0, ccs1},\
-/*34*/ {"skip extended reverse", 0x36, 0x24, motion, 1, ccs1},\
-/*35*/ {"skip extended forward", 0x36, 0x24, motion, 1, ccs1},\
-/*36*/ {"calibrate tape length", 0x17, 0x05, motion, 1, ccs2},\
-/*37*/ {"report format segments", 0x17, 0x05, report, 0, ccs2},\
-/*38*/ {"set format segments", 0x17, 0x05, mode, 0, ccs2},\
-/*39*/ {"reserved (39)", 0x00, 0x00, unused, 0, discretional},\
-/*40*/ {"vendor unique (40)", 0x00, 0x00, unused, 0, discretional},\
-/*41*/ {"vendor unique (41)", 0x00, 0x00, unused, 0, discretional},\
-/*42*/ {"vendor unique (42)", 0x00, 0x00, unused, 0, discretional},\
-/*43*/ {"vendor unique (43)", 0x00, 0x00, unused, 0, discretional},\
-/*44*/ {"vendor unique (44)", 0x00, 0x00, unused, 0, discretional},\
-/*45*/ {"vendor unique (45)", 0x00, 0x00, unused, 0, discretional},\
-/*46*/ {"phantom select", 0x00, 0x00, mode, 0, discretional},\
-/*47*/ {"phantom deselect", 0x00, 0x00, mode, 0, discretional},\
-}
-
-/*
- * Status bits returned by QIC_REPORT_DRIVE_STATUS
- */
-
-#define QIC_STATUS_READY 0x01 /* Drive is ready or idle. */
-#define QIC_STATUS_ERROR 0x02 /* Error detected, must read
- error code to clear this */
-#define QIC_STATUS_CARTRIDGE_PRESENT 0x04 /* Tape is present */
-#define QIC_STATUS_WRITE_PROTECT 0x08 /* Tape is write protected */
-#define QIC_STATUS_NEW_CARTRIDGE 0x10 /* New cartridge inserted, must
- read error status to clear. */
-#define QIC_STATUS_REFERENCED 0x20 /* Cartridge appears to have been
- formatted. */
-#define QIC_STATUS_AT_BOT 0x40 /* Cartridge is at physical
- beginning of tape. */
-#define QIC_STATUS_AT_EOT 0x80 /* Cartridge is at physical end
- of tape. */
-/*
- * Status bits returned by QIC_REPORT_DRIVE_CONFIGURATION
- */
-
-#define QIC_CONFIG_RATE_MASK 0x18
-#define QIC_CONFIG_RATE_SHIFT 3
-#define QIC_CONFIG_RATE_250 0
-#define QIC_CONFIG_RATE_500 2
-#define QIC_CONFIG_RATE_1000 3
-#define QIC_CONFIG_RATE_2000 1
-#define QIC_CONFIG_RATE_4000 0 /* since QIC-117 Rev. J */
-
-#define QIC_CONFIG_LONG 0x40 /* Extra Length Tape Detected */
-#define QIC_CONFIG_80 0x80 /* QIC-80 detected. */
-
-/*
- * Status bits returned by QIC_REPORT_TAPE_STATUS
- */
-
-#define QIC_TAPE_STD_MASK 0x0f
-#define QIC_TAPE_QIC40 0x01
-#define QIC_TAPE_QIC80 0x02
-#define QIC_TAPE_QIC3020 0x03
-#define QIC_TAPE_QIC3010 0x04
-
-#define QIC_TAPE_LEN_MASK 0x70
-#define QIC_TAPE_205FT 0x10
-#define QIC_TAPE_307FT 0x20
-#define QIC_TAPE_VARIABLE 0x30
-#define QIC_TAPE_1100FT 0x40
-#define QIC_TAPE_FLEX 0x60
-
-#define QIC_TAPE_WIDE 0x80
-
-/* Define a value (in feet) slightly higher than
- * the possible maximum tape length.
- */
-#define QIC_TOP_TAPE_LEN 1500
-
-/*
- * Errors: List of error codes, and their severity.
- */
-
-typedef struct {
- char *message; /* Text describing the error. */
- unsigned int fatal:1; /* Non-zero if the error is fatal. */
-} ftape_error;
-
-#define QIC117_ERRORS {\
- /* 0*/ { "No error", 0, },\
- /* 1*/ { "Command Received while Drive Not Ready", 0, },\
- /* 2*/ { "Cartridge Not Present or Removed", 1, },\
- /* 3*/ { "Motor Speed Error (not within 1%)", 1, },\
- /* 4*/ { "Motor Speed Fault (jammed, or gross speed error", 1, },\
- /* 5*/ { "Cartridge Write Protected", 1, },\
- /* 6*/ { "Undefined or Reserved Command Code", 1, },\
- /* 7*/ { "Illegal Track Address Specified for Seek", 1, },\
- /* 8*/ { "Illegal Command in Report Subcontext", 0, },\
- /* 9*/ { "Illegal Entry into a Diagnostic Mode", 1, },\
- /*10*/ { "Broken Tape Detected (based on hole sensor)", 1, },\
- /*11*/ { "Warning--Read Gain Setting Error", 1, },\
- /*12*/ { "Command Received While Error Status Pending (obs)", 1, },\
- /*13*/ { "Command Received While New Cartridge Pending", 1, },\
- /*14*/ { "Command Illegal or Undefined in Primary Mode", 1, },\
- /*15*/ { "Command Illegal or Undefined in Format Mode", 1, },\
- /*16*/ { "Command Illegal or Undefined in Verify Mode", 1, },\
- /*17*/ { "Logical Forward Not at Logical BOT or no Format Segments in Format Mode", 1, },\
- /*18*/ { "Logical EOT Before All Segments generated", 1, },\
- /*19*/ { "Command Illegal When Cartridge Not Referenced", 1, },\
- /*20*/ { "Self-Diagnostic Failed (cannot be cleared)", 1, },\
- /*21*/ { "Warning EEPROM Not Initialized, Defaults Set", 1, },\
- /*22*/ { "EEPROM Corrupted or Hardware Failure", 1, },\
- /*23*/ { "Motion Time-out Error", 1, },\
- /*24*/ { "Data Segment Too Long -- Logical Forward or Pause", 1, },\
- /*25*/ { "Transmit Overrun (obs)", 1, },\
- /*26*/ { "Power On Reset Occurred", 0, },\
- /*27*/ { "Software Reset Occurred", 0, },\
- /*28*/ { "Diagnostic Mode 1 Error", 1, },\
- /*29*/ { "Diagnostic Mode 2 Error", 1, },\
- /*30*/ { "Command Received During Non-Interruptible Process", 1, },\
- /*31*/ { "Rate or Format Selection Error", 1, },\
- /*32*/ { "Illegal Command While in High Speed Mode", 1, },\
- /*33*/ { "Illegal Seek Segment Value", 1, },\
- /*34*/ { "Invalid Media", 1, },\
- /*35*/ { "Head Positioning Failure", 1, },\
- /*36*/ { "Write Reference Burst Failure", 1, },\
- /*37*/ { "Prom Code Missing", 1, },\
- /*38*/ { "Invalid Format", 1, },\
- /*39*/ { "EOT/BOT System Failure", 1, },\
- /*40*/ { "Prom A Checksum Error", 1, },\
- /*41*/ { "Drive Wakeup Reset Occurred", 1, },\
- /*42*/ { "Prom B Checksum Error", 1, },\
- /*43*/ { "Illegal Entry into Format Mode", 1, },\
-}
-
-#endif /* _QIC117_H */
diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h
index ebd42a3710b..6db9a4c1535 100644
--- a/include/linux/raid/bitmap.h
+++ b/include/linux/raid/bitmap.h
@@ -247,6 +247,7 @@ struct bitmap {
atomic_t pending_writes; /* pending writes to the bitmap file */
wait_queue_head_t write_wait;
+ wait_queue_head_t overflow_wait;
};
diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h
index 866a1e2b0ce..fbaeda79b2e 100644
--- a/include/linux/raid/md.h
+++ b/include/linux/raid/md.h
@@ -94,7 +94,7 @@ extern int sync_page_io(struct block_device *bdev, sector_t sector, int size,
struct page *page, int rw);
extern void md_do_sync(mddev_t *mddev);
extern void md_new_event(mddev_t *mddev);
-
+extern void md_allow_write(mddev_t *mddev);
#endif /* CONFIG_MD */
#endif
diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h
index 03636d7918f..d8286db60b9 100644
--- a/include/linux/raid/raid5.h
+++ b/include/linux/raid/raid5.h
@@ -227,7 +227,10 @@ struct raid5_private_data {
struct list_head handle_list; /* stripes needing handling */
struct list_head delayed_list; /* stripes that have plugged requests */
struct list_head bitmap_list; /* stripes delaying awaiting bitmap update */
+ struct bio *retry_read_aligned; /* currently retrying aligned bios */
+ struct bio *retry_read_aligned_list; /* aligned bios retry list */
atomic_t preread_active_stripes; /* stripes with scheduled io */
+ atomic_t active_aligned_reads;
atomic_t reshape_stripes; /* stripes with pending writes for reshape */
/* unfortunately we need two cache names as we temporarily have
diff --git a/include/linux/reciprocal_div.h b/include/linux/reciprocal_div.h
new file mode 100644
index 00000000000..f9c90b33285
--- /dev/null
+++ b/include/linux/reciprocal_div.h
@@ -0,0 +1,32 @@
+#ifndef _LINUX_RECIPROCAL_DIV_H
+#define _LINUX_RECIPROCAL_DIV_H
+
+#include <linux/types.h>
+
+/*
+ * This file describes reciprocical division.
+ *
+ * This optimizes the (A/B) problem, when A and B are two u32
+ * and B is a known value (but not known at compile time)
+ *
+ * The math principle used is :
+ * Let RECIPROCAL_VALUE(B) be (((1LL << 32) + (B - 1))/ B)
+ * Then A / B = (u32)(((u64)(A) * (R)) >> 32)
+ *
+ * This replaces a divide by a multiply (and a shift), and
+ * is generally less expensive in CPU cycles.
+ */
+
+/*
+ * Computes the reciprocal value (R) for the value B of the divisor.
+ * Should not be called before each reciprocal_divide(),
+ * or else the performance is slower than a normal divide.
+ */
+extern u32 reciprocal_value(u32 B);
+
+
+static inline u32 reciprocal_divide(u32 A, u32 R)
+{
+ return (u32)(((u64)A * R) >> 32);
+}
+#endif
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index d0e4dce33ad..c3fc6caaad3 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -1159,7 +1159,7 @@ znodes are the way! */
#define PATH_READA 0x1 /* do read ahead */
#define PATH_READA_BACK 0x2 /* read backwards */
-struct path {
+struct treepath {
int path_length; /* Length of the array above. */
int reada;
struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */
@@ -1169,7 +1169,7 @@ struct path {
#define pos_in_item(path) ((path)->pos_in_item)
#define INITIALIZE_PATH(var) \
-struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
+struct treepath var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
/* Get path element by path and path position. */
#define PATH_OFFSET_PELEMENT(p_s_path,n_offset) ((p_s_path)->path_elements +(n_offset))
@@ -1327,7 +1327,7 @@ struct tree_balance {
int need_balance_dirty;
struct super_block *tb_sb;
struct reiserfs_transaction_handle *transaction_handle;
- struct path *tb_path;
+ struct treepath *tb_path;
struct buffer_head *L[MAX_HEIGHT]; /* array of left neighbors of nodes in the path */
struct buffer_head *R[MAX_HEIGHT]; /* array of right neighbors of nodes in the path */
struct buffer_head *FL[MAX_HEIGHT]; /* array of fathers of the left neighbors */
@@ -1793,41 +1793,41 @@ static inline void copy_key(struct reiserfs_key *to,
memcpy(to, from, KEY_SIZE);
}
-int comp_items(const struct item_head *stored_ih, const struct path *p_s_path);
-const struct reiserfs_key *get_rkey(const struct path *p_s_chk_path,
+int comp_items(const struct item_head *stored_ih, const struct treepath *p_s_path);
+const struct reiserfs_key *get_rkey(const struct treepath *p_s_chk_path,
const struct super_block *p_s_sb);
int search_by_key(struct super_block *, const struct cpu_key *,
- struct path *, int);
+ struct treepath *, int);
#define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL)
int search_for_position_by_key(struct super_block *p_s_sb,
const struct cpu_key *p_s_cpu_key,
- struct path *p_s_search_path);
+ struct treepath *p_s_search_path);
extern void decrement_bcount(struct buffer_head *p_s_bh);
-void decrement_counters_in_path(struct path *p_s_search_path);
-void pathrelse(struct path *p_s_search_path);
-int reiserfs_check_path(struct path *p);
-void pathrelse_and_restore(struct super_block *s, struct path *p_s_search_path);
+void decrement_counters_in_path(struct treepath *p_s_search_path);
+void pathrelse(struct treepath *p_s_search_path);
+int reiserfs_check_path(struct treepath *p);
+void pathrelse_and_restore(struct super_block *s, struct treepath *p_s_search_path);
int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
- struct path *path,
+ struct treepath *path,
const struct cpu_key *key,
struct item_head *ih,
struct inode *inode, const char *body);
int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th,
- struct path *path,
+ struct treepath *path,
const struct cpu_key *key,
struct inode *inode,
const char *body, int paste_size);
int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
- struct path *path,
+ struct treepath *path,
struct cpu_key *key,
struct inode *inode,
struct page *page, loff_t new_file_size);
int reiserfs_delete_item(struct reiserfs_transaction_handle *th,
- struct path *path,
+ struct treepath *path,
const struct cpu_key *key,
struct inode *inode, struct buffer_head *p_s_un_bh);
@@ -1858,7 +1858,7 @@ void padd_item(char *item, int total_length, int length);
#define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */
int restart_transaction(struct reiserfs_transaction_handle *th,
- struct inode *inode, struct path *path);
+ struct inode *inode, struct treepath *path);
void reiserfs_read_locked_inode(struct inode *inode,
struct reiserfs_iget_args *args);
int reiserfs_find_actor(struct inode *inode, void *p);
@@ -1905,7 +1905,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr);
/* namei.c */
void set_de_name_and_namelen(struct reiserfs_dir_entry *de);
int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
- struct path *path, struct reiserfs_dir_entry *de);
+ struct treepath *path, struct reiserfs_dir_entry *de);
struct dentry *reiserfs_get_parent(struct dentry *);
/* procfs.c */
@@ -1956,9 +1956,9 @@ extern const struct file_operations reiserfs_dir_operations;
/* tail_conversion.c */
int direct2indirect(struct reiserfs_transaction_handle *, struct inode *,
- struct path *, struct buffer_head *, loff_t);
+ struct treepath *, struct buffer_head *, loff_t);
int indirect2direct(struct reiserfs_transaction_handle *, struct inode *,
- struct page *, struct path *, const struct cpu_key *,
+ struct page *, struct treepath *, const struct cpu_key *,
loff_t, char *);
void reiserfs_unmap_buffer(struct buffer_head *);
@@ -2045,7 +2045,7 @@ struct __reiserfs_blocknr_hint {
struct inode *inode; /* inode passed to allocator, if we allocate unf. nodes */
long block; /* file offset, in blocks */
struct in_core_key key;
- struct path *path; /* search path, used by allocator to deternine search_start by
+ struct treepath *path; /* search path, used by allocator to deternine search_start by
* various ways */
struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and
* bitmap blocks changes */
@@ -2101,7 +2101,7 @@ static inline int reiserfs_new_form_blocknrs(struct tree_balance *tb,
static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle
*th, struct inode *inode,
b_blocknr_t * new_blocknrs,
- struct path *path, long block)
+ struct treepath *path, long block)
{
reiserfs_blocknr_hint_t hint = {
.th = th,
@@ -2118,7 +2118,7 @@ static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle
static inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle
*th, struct inode *inode,
b_blocknr_t * new_blocknrs,
- struct path *path, long block)
+ struct treepath *path, long block)
{
reiserfs_blocknr_hint_t hint = {
.th = th,
diff --git a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h
index 5b3b297aa2c..ce3663fb010 100644
--- a/include/linux/reiserfs_fs_i.h
+++ b/include/linux/reiserfs_fs_i.h
@@ -25,6 +25,7 @@ typedef enum {
i_link_saved_truncate_mask = 0x0020,
i_has_xattr_dir = 0x0040,
i_data_log = 0x0080,
+ i_ever_mapped = 0x0100
} reiserfs_inode_flags;
struct reiserfs_inode_info {
@@ -52,6 +53,7 @@ struct reiserfs_inode_info {
** flushed */
unsigned long i_trans_id;
struct reiserfs_journal_list *i_jl;
+ struct mutex i_mmap;
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
struct posix_acl *i_acl_access;
struct posix_acl *i_acl_default;
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 36f850373d2..bdd277223af 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -72,7 +72,7 @@ void __anon_vma_link(struct vm_area_struct *);
void page_add_anon_rmap(struct page *, struct vm_area_struct *, unsigned long);
void page_add_new_anon_rmap(struct page *, struct vm_area_struct *, unsigned long);
void page_add_file_rmap(struct page *);
-void page_remove_rmap(struct page *);
+void page_remove_rmap(struct page *, struct vm_area_struct *);
/**
* page_dup_rmap - duplicate pte mapping to a page
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 09ff4c3e271..5e22d4510d1 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -106,6 +106,7 @@ extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year
extern int rtc_valid_tm(struct rtc_time *tm);
extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
+extern void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm);
#include <linux/device.h>
#include <linux/seq_file.h>
diff --git a/include/linux/rtmutex.h b/include/linux/rtmutex.h
index b0090e9f788..382bb795116 100644
--- a/include/linux/rtmutex.h
+++ b/include/linux/rtmutex.h
@@ -16,7 +16,7 @@
#include <linux/plist.h>
#include <linux/spinlock_types.h>
-/*
+/**
* The rt_mutex structure
*
* @wait_lock: spinlock to protect the structure
@@ -71,7 +71,7 @@ struct hrtimer_sleeper;
#define DEFINE_RT_MUTEX(mutexname) \
struct rt_mutex mutexname = __RT_MUTEX_INITIALIZER(mutexname)
-/***
+/**
* rt_mutex_is_locked - is the mutex locked
* @lock: the mutex to be queried
*
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 493297acdae..4a629ea70cc 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -3,6 +3,8 @@
#include <linux/netlink.h>
#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
/****
* Routing/neighbour discovery messages.
diff --git a/include/linux/sched.h b/include/linux/sched.h
index dede82c6344..44637353519 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -82,6 +82,7 @@ struct sched_param {
#include <linux/resource.h>
#include <linux/timer.h>
#include <linux/hrtimer.h>
+#include <linux/task_io_accounting.h>
#include <asm/processor.h>
@@ -436,7 +437,12 @@ struct signal_struct {
/* job control IDs */
pid_t pgrp;
pid_t tty_old_pgrp;
- pid_t session;
+
+ union {
+ pid_t session __deprecated;
+ pid_t __session;
+ };
+
/* boolean value for session group leader */
int leader;
@@ -642,6 +648,7 @@ enum idle_type
#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 SD_SERIALIZE 1024 /* Only a single load balancing instance */
#define BALANCE_FOR_MC_POWER \
(sched_smt_power_savings ? SD_POWERSAVINGS_BALANCE : 0)
@@ -1008,6 +1015,7 @@ struct task_struct {
wait_queue_t *io_wait;
/* i/o counters(bytes read/written, #syscalls */
u64 rchar, wchar, syscr, syscw;
+ struct task_io_accounting ioac;
#if defined(CONFIG_TASK_XACCT)
u64 acct_rss_mem1; /* accumulated rss usage */
u64 acct_vm_mem1; /* accumulated virtual memory usage */
@@ -1040,6 +1048,9 @@ struct task_struct {
#ifdef CONFIG_TASK_DELAY_ACCT
struct task_delay_info *delays;
#endif
+#ifdef CONFIG_FAULT_INJECTION
+ int make_it_fail;
+#endif
};
static inline pid_t process_group(struct task_struct *tsk)
@@ -1047,6 +1058,21 @@ static inline pid_t process_group(struct task_struct *tsk)
return tsk->signal->pgrp;
}
+static inline pid_t signal_session(struct signal_struct *sig)
+{
+ return sig->__session;
+}
+
+static inline pid_t process_session(struct task_struct *tsk)
+{
+ return signal_session(tsk->signal);
+}
+
+static inline void set_signal_session(struct signal_struct *sig, pid_t session)
+{
+ sig->__session = session;
+}
+
static inline struct pid *task_pid(struct task_struct *task)
{
return task->pids[PIDTYPE_PID].pid;
@@ -1118,7 +1144,6 @@ static inline void put_task_struct(struct task_struct *t)
#define PF_MEMALLOC 0x00000800 /* Allocating memory */
#define PF_FLUSHER 0x00001000 /* responsible for disk writeback */
#define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */
-#define PF_FREEZE 0x00004000 /* this task is being frozen for suspend now */
#define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */
#define PF_FROZEN 0x00010000 /* frozen for system suspend */
#define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */
@@ -1240,7 +1265,6 @@ extern struct mm_struct init_mm;
#define find_task_by_pid(nr) find_task_by_pid_type(PIDTYPE_PID, nr)
extern struct task_struct *find_task_by_pid_type(int type, int pid);
-extern void set_special_pids(pid_t session, pid_t pgrp);
extern void __set_special_pids(pid_t session, pid_t pgrp);
/* per-UID process charging. */
@@ -1381,7 +1405,6 @@ extern NORET_TYPE void do_group_exit(int);
extern void daemonize(const char *, ...);
extern int allow_signal(int);
extern int disallow_signal(int);
-extern struct task_struct *child_reaper;
extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *);
extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
diff --git a/include/linux/sctp.h b/include/linux/sctp.h
index 35108fe7a68..d4f86560bff 100644
--- a/include/linux/sctp.h
+++ b/include/linux/sctp.h
@@ -180,7 +180,7 @@ typedef enum {
SCTP_PARAM_ERR_CAUSE = __constant_htons(0xc003),
SCTP_PARAM_SET_PRIMARY = __constant_htons(0xc004),
SCTP_PARAM_SUCCESS_REPORT = __constant_htons(0xc005),
- SCTP_PARAM_ADAPTION_LAYER_IND = __constant_htons(0xc006),
+ SCTP_PARAM_ADAPTATION_LAYER_IND = __constant_htons(0xc006),
} sctp_param_t; /* enum */
@@ -281,11 +281,11 @@ typedef struct sctp_ecn_capable_param {
sctp_paramhdr_t param_hdr;
} __attribute__((packed)) sctp_ecn_capable_param_t;
-/* ADDIP Section 3.2.6 Adaption Layer Indication */
-typedef struct sctp_adaption_ind_param {
+/* ADDIP Section 3.2.6 Adaptation Layer Indication */
+typedef struct sctp_adaptation_ind_param {
struct sctp_paramhdr param_hdr;
- __be32 adaption_ind;
-} __attribute__((packed)) sctp_adaption_ind_param_t;
+ __be32 adaptation_ind;
+} __attribute__((packed)) sctp_adaptation_ind_param_t;
/* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2):
* The INIT ACK chunk is used to acknowledge the initiation of an SCTP
diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index 46000936f8f..6b0648cfdff 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -44,8 +44,11 @@ typedef struct {
#define SEQLOCK_UNLOCKED \
__SEQLOCK_UNLOCKED(old_style_seqlock_init)
-#define seqlock_init(x) \
- do { *(x) = (seqlock_t) __SEQLOCK_UNLOCKED(x); } while (0)
+#define seqlock_init(x) \
+ do { \
+ (x)->sequence = 0; \
+ spin_lock_init(&(x)->lock); \
+ } while (0)
#define DEFINE_SEQLOCK(x) \
seqlock_t x = __SEQLOCK_UNLOCKED(x)
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 82767213664..cf23813cbec 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -166,8 +166,8 @@ struct uart_ops {
void (*break_ctl)(struct uart_port *, int ctl);
int (*startup)(struct uart_port *);
void (*shutdown)(struct uart_port *);
- void (*set_termios)(struct uart_port *, struct termios *new,
- struct termios *old);
+ void (*set_termios)(struct uart_port *, struct ktermios *new,
+ struct ktermios *old);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int oldstate);
int (*set_wake)(struct uart_port *, unsigned int state);
@@ -361,8 +361,8 @@ void uart_write_wakeup(struct uart_port *port);
*/
void uart_update_timeout(struct uart_port *port, unsigned int cflag,
unsigned int baud);
-unsigned int uart_get_baud_rate(struct uart_port *port, struct termios *termios,
- struct termios *old, unsigned int min,
+unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old, unsigned int min,
unsigned int max);
unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud);
diff --git a/include/linux/serio.h b/include/linux/serio.h
index 0f478a8791a..ac2c70e7f76 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -86,6 +86,11 @@ static inline void serio_register_port(struct serio *serio)
void serio_unregister_port(struct serio *serio);
void serio_unregister_child_port(struct serio *serio);
+int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name);
+static inline int serio_register_driver(struct serio_driver *drv)
+{
+ return __serio_register_driver(drv, THIS_MODULE, KBUILD_MODNAME);
+}
int serio_register_driver(struct serio_driver *drv);
void serio_unregister_driver(struct serio_driver *drv);
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 2271886744f..1ef822e31c7 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -1,7 +1,9 @@
/*
- * linux/include/linux/slab.h
- * Written by Mark Hemment, 1996.
- * (markhe@nextd.demon.co.uk)
+ * Written by Mark Hemment, 1996 (markhe@nextd.demon.co.uk).
+ *
+ * (C) SGI 2006, Christoph Lameter <clameter@sgi.com>
+ * Cleaned up and restructured to ease the addition of alternative
+ * implementations of SLAB allocators.
*/
#ifndef _LINUX_SLAB_H
@@ -10,64 +12,95 @@
#ifdef __KERNEL__
#include <linux/gfp.h>
-#include <linux/init.h>
#include <linux/types.h>
-#include <asm/page.h> /* kmalloc_sizes.h needs PAGE_SIZE */
-#include <asm/cache.h> /* kmalloc_sizes.h needs L1_CACHE_BYTES */
-#include <linux/compiler.h>
-/* kmem_cache_t exists for legacy reasons and is not used by code in mm */
typedef struct kmem_cache kmem_cache_t __deprecated;
-/* flags to pass to kmem_cache_create().
- * The first 3 are only valid when the allocator as been build
- * SLAB_DEBUG_SUPPORT.
+/*
+ * Flags to pass to kmem_cache_create().
+ * The ones marked DEBUG are only valid if CONFIG_SLAB_DEBUG is set.
*/
-#define SLAB_DEBUG_FREE 0x00000100UL /* Peform (expensive) checks on free */
-#define SLAB_DEBUG_INITIAL 0x00000200UL /* Call constructor (as verifier) */
-#define SLAB_RED_ZONE 0x00000400UL /* Red zone objs in a cache */
-#define SLAB_POISON 0x00000800UL /* Poison objects */
-#define SLAB_HWCACHE_ALIGN 0x00002000UL /* align objs on a h/w cache lines */
-#define SLAB_CACHE_DMA 0x00004000UL /* use GFP_DMA memory */
-#define SLAB_MUST_HWCACHE_ALIGN 0x00008000UL /* force alignment */
-#define SLAB_STORE_USER 0x00010000UL /* store the last owner for bug hunting */
-#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* track pages allocated to indicate
- what is reclaimable later*/
-#define SLAB_PANIC 0x00040000UL /* panic if kmem_cache_create() fails */
-#define SLAB_DESTROY_BY_RCU 0x00080000UL /* defer freeing pages to RCU */
+#define SLAB_DEBUG_FREE 0x00000100UL /* DEBUG: Perform (expensive) checks on free */
+#define SLAB_DEBUG_INITIAL 0x00000200UL /* DEBUG: Call constructor (as verifier) */
+#define SLAB_RED_ZONE 0x00000400UL /* DEBUG: Red zone objs in a cache */
+#define SLAB_POISON 0x00000800UL /* DEBUG: Poison objects */
+#define SLAB_HWCACHE_ALIGN 0x00002000UL /* Align objs on cache lines */
+#define SLAB_CACHE_DMA 0x00004000UL /* Use GFP_DMA memory */
+#define SLAB_MUST_HWCACHE_ALIGN 0x00008000UL /* Force alignment even if debuggin is active */
+#define SLAB_STORE_USER 0x00010000UL /* DEBUG: Store the last owner for bug hunting */
+#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */
+#define SLAB_PANIC 0x00040000UL /* Panic if kmem_cache_create() fails */
+#define SLAB_DESTROY_BY_RCU 0x00080000UL /* Defer freeing slabs to RCU */
#define SLAB_MEM_SPREAD 0x00100000UL /* Spread some memory over cpuset */
-/* flags passed to a constructor func */
-#define SLAB_CTOR_CONSTRUCTOR 0x001UL /* if not set, then deconstructor */
-#define SLAB_CTOR_ATOMIC 0x002UL /* tell constructor it can't sleep */
-#define SLAB_CTOR_VERIFY 0x004UL /* tell constructor it's a verify call */
+/* Flags passed to a constructor functions */
+#define SLAB_CTOR_CONSTRUCTOR 0x001UL /* If not set, then deconstructor */
+#define SLAB_CTOR_ATOMIC 0x002UL /* Tell constructor it can't sleep */
+#define SLAB_CTOR_VERIFY 0x004UL /* Tell constructor it's a verify call */
-#ifndef CONFIG_SLOB
-
-/* prototypes */
-extern void __init kmem_cache_init(void);
+/*
+ * struct kmem_cache related prototypes
+ */
+void __init kmem_cache_init(void);
+extern int slab_is_available(void);
-extern struct kmem_cache *kmem_cache_create(const char *, size_t, size_t,
+struct kmem_cache *kmem_cache_create(const char *, size_t, size_t,
unsigned long,
void (*)(void *, struct kmem_cache *, unsigned long),
void (*)(void *, struct kmem_cache *, unsigned long));
-extern void kmem_cache_destroy(struct kmem_cache *);
-extern int kmem_cache_shrink(struct kmem_cache *);
-extern void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
-extern void *kmem_cache_zalloc(struct kmem_cache *, gfp_t);
-extern void kmem_cache_free(struct kmem_cache *, void *);
-extern unsigned int kmem_cache_size(struct kmem_cache *);
-extern const char *kmem_cache_name(struct kmem_cache *);
+void kmem_cache_destroy(struct kmem_cache *);
+int kmem_cache_shrink(struct kmem_cache *);
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
+void *kmem_cache_zalloc(struct kmem_cache *, gfp_t);
+void kmem_cache_free(struct kmem_cache *, void *);
+unsigned int kmem_cache_size(struct kmem_cache *);
+const char *kmem_cache_name(struct kmem_cache *);
+int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr);
+
+#ifdef CONFIG_NUMA
+extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
+#else
+static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
+ gfp_t flags, int node)
+{
+ return kmem_cache_alloc(cachep, flags);
+}
+#endif
+
+/*
+ * Common kmalloc functions provided by all allocators
+ */
+void *__kmalloc(size_t, gfp_t);
+void *__kzalloc(size_t, gfp_t);
+void kfree(const void *);
+unsigned int ksize(const void *);
+
+/**
+ * kcalloc - allocate memory for an array. The memory is set to zero.
+ * @n: number of elements.
+ * @size: element size.
+ * @flags: the type of memory to allocate.
+ */
+static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
+{
+ if (n != 0 && size > ULONG_MAX / n)
+ return NULL;
+ return __kzalloc(n * size, flags);
+}
-/* Size description struct for general caches. */
-struct cache_sizes {
- size_t cs_size;
- struct kmem_cache *cs_cachep;
- struct kmem_cache *cs_dmacachep;
-};
-extern struct cache_sizes malloc_sizes[];
+/*
+ * Allocator specific definitions. These are mainly used to establish optimized
+ * ways to convert kmalloc() calls to kmem_cache_alloc() invocations by selecting
+ * the appropriate general cache at compile time.
+ */
-extern void *__kmalloc(size_t, gfp_t);
+#ifdef CONFIG_SLAB
+#include <linux/slab_def.h>
+#else
+/*
+ * Fallback definitions for an allocator not wanting to provide
+ * its own optimized kmalloc definitions (like SLOB).
+ */
/**
* kmalloc - allocate memory
@@ -116,46 +149,9 @@ extern void *__kmalloc(size_t, gfp_t);
*/
static inline void *kmalloc(size_t size, gfp_t flags)
{
- if (__builtin_constant_p(size)) {
- int i = 0;
-#define CACHE(x) \
- if (size <= x) \
- goto found; \
- else \
- i++;
-#include "kmalloc_sizes.h"
-#undef CACHE
- {
- extern void __you_cannot_kmalloc_that_much(void);
- __you_cannot_kmalloc_that_much();
- }
-found:
- return kmem_cache_alloc((flags & GFP_DMA) ?
- malloc_sizes[i].cs_dmacachep :
- malloc_sizes[i].cs_cachep, flags);
- }
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);
-
/**
* kzalloc - allocate memory. The memory is set to zero.
* @size: how many bytes of memory are required.
@@ -163,72 +159,41 @@ extern void *__kzalloc(size_t, gfp_t);
*/
static inline void *kzalloc(size_t size, gfp_t flags)
{
- if (__builtin_constant_p(size)) {
- int i = 0;
-#define CACHE(x) \
- if (size <= x) \
- goto found; \
- else \
- i++;
-#include "kmalloc_sizes.h"
-#undef CACHE
- {
- extern void __you_cannot_kzalloc_that_much(void);
- __you_cannot_kzalloc_that_much();
- }
-found:
- return kmem_cache_zalloc((flags & GFP_DMA) ?
- malloc_sizes[i].cs_dmacachep :
- malloc_sizes[i].cs_cachep, flags);
- }
return __kzalloc(size, flags);
}
+#endif
-/**
- * kcalloc - allocate memory for an array. The memory is set to zero.
- * @n: number of elements.
- * @size: element size.
- * @flags: the type of memory to allocate.
- */
-static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
+#ifndef CONFIG_NUMA
+static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
{
- if (n != 0 && size > ULONG_MAX / n)
- return NULL;
- return kzalloc(n * size, flags);
+ return kmalloc(size, flags);
}
-extern void kfree(const void *);
-extern unsigned int ksize(const void *);
-extern int slab_is_available(void);
-
-#ifdef CONFIG_NUMA
-extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
-extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
-
-static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
+static inline void *__kmalloc_node(size_t size, gfp_t flags, int node)
{
- if (__builtin_constant_p(size)) {
- int i = 0;
-#define CACHE(x) \
- if (size <= x) \
- goto found; \
- else \
- i++;
-#include "kmalloc_sizes.h"
-#undef CACHE
- {
- extern void __you_cannot_kmalloc_that_much(void);
- __you_cannot_kmalloc_that_much();
- }
-found:
- return kmem_cache_alloc_node((flags & GFP_DMA) ?
- malloc_sizes[i].cs_dmacachep :
- malloc_sizes[i].cs_cachep, flags, node);
- }
- return __kmalloc_node(size, flags, node);
+ return __kmalloc(size, flags);
}
+#endif /* !CONFIG_NUMA */
/*
+ * 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.
+ */
+#ifdef CONFIG_DEBUG_SLAB
+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))
+#else
+#define kmalloc_track_caller(size, flags) \
+ __kmalloc(size, flags)
+#endif /* DEBUG_SLAB */
+
+#ifdef CONFIG_NUMA
+/*
* kmalloc_node_track_caller is a special version of kmalloc_node that
* records the calling function of the routine calling it for slab leak
* tracking instead of just the calling function (confusing, eh?).
@@ -236,70 +201,23 @@ found:
* standard allocator where we care about the real place the memory
* allocation request comes from.
*/
-#ifndef CONFIG_DEBUG_SLAB
-#define kmalloc_node_track_caller(size, flags, node) \
- __kmalloc_node(size, flags, node)
-#else
+#ifdef CONFIG_DEBUG_SLAB
extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, void *);
#define kmalloc_node_track_caller(size, flags, node) \
__kmalloc_node_track_caller(size, flags, node, \
__builtin_return_address(0))
+#else
+#define kmalloc_node_track_caller(size, flags, node) \
+ __kmalloc_node(size, flags, node)
#endif
+
#else /* CONFIG_NUMA */
-static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
- gfp_t flags, int node)
-{
- return kmem_cache_alloc(cachep, flags);
-}
-static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
-{
- return kmalloc(size, flags);
-}
#define kmalloc_node_track_caller(size, flags, node) \
kmalloc_track_caller(size, flags)
-#endif
-extern int FASTCALL(kmem_cache_reap(int));
-extern int FASTCALL(kmem_ptr_validate(struct kmem_cache *cachep, void *ptr));
-
-#else /* CONFIG_SLOB */
-
-/* SLOB allocator routines */
-
-void kmem_cache_init(void);
-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));
-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);
-const char *kmem_cache_name(struct kmem_cache *);
-void *kmalloc(size_t size, gfp_t flags);
-void *__kzalloc(size_t size, gfp_t flags);
-void kfree(const void *m);
-unsigned int ksize(const void *m);
-unsigned int kmem_cache_size(struct kmem_cache *c);
-
-static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
-{
- return __kzalloc(n * size, flags);
-}
-
-#define kmem_cache_shrink(d) (0)
-#define kmem_cache_reap(a)
-#define kmem_ptr_validate(a, b) (0)
-#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_track_caller kmalloc
-
-#define kmalloc_node_track_caller kmalloc_node
-
-#endif /* CONFIG_SLOB */
+#endif /* DEBUG_SLAB */
#endif /* __KERNEL__ */
-
#endif /* _LINUX_SLAB_H */
+
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h
new file mode 100644
index 00000000000..4b463e66dde
--- /dev/null
+++ b/include/linux/slab_def.h
@@ -0,0 +1,100 @@
+#ifndef _LINUX_SLAB_DEF_H
+#define _LINUX_SLAB_DEF_H
+
+/*
+ * Definitions unique to the original Linux SLAB allocator.
+ *
+ * What we provide here is a way to optimize the frequent kmalloc
+ * calls in the kernel by selecting the appropriate general cache
+ * if kmalloc was called with a size that can be established at
+ * compile time.
+ */
+
+#include <linux/init.h>
+#include <asm/page.h> /* kmalloc_sizes.h needs PAGE_SIZE */
+#include <asm/cache.h> /* kmalloc_sizes.h needs L1_CACHE_BYTES */
+#include <linux/compiler.h>
+
+/* Size description struct for general caches. */
+struct cache_sizes {
+ size_t cs_size;
+ struct kmem_cache *cs_cachep;
+ struct kmem_cache *cs_dmacachep;
+};
+extern struct cache_sizes malloc_sizes[];
+
+static inline void *kmalloc(size_t size, gfp_t flags)
+{
+ if (__builtin_constant_p(size)) {
+ int i = 0;
+#define CACHE(x) \
+ if (size <= x) \
+ goto found; \
+ else \
+ i++;
+#include "kmalloc_sizes.h"
+#undef CACHE
+ {
+ extern void __you_cannot_kmalloc_that_much(void);
+ __you_cannot_kmalloc_that_much();
+ }
+found:
+ return kmem_cache_alloc((flags & GFP_DMA) ?
+ malloc_sizes[i].cs_dmacachep :
+ malloc_sizes[i].cs_cachep, flags);
+ }
+ return __kmalloc(size, flags);
+}
+
+static inline void *kzalloc(size_t size, gfp_t flags)
+{
+ if (__builtin_constant_p(size)) {
+ int i = 0;
+#define CACHE(x) \
+ if (size <= x) \
+ goto found; \
+ else \
+ i++;
+#include "kmalloc_sizes.h"
+#undef CACHE
+ {
+ extern void __you_cannot_kzalloc_that_much(void);
+ __you_cannot_kzalloc_that_much();
+ }
+found:
+ return kmem_cache_zalloc((flags & GFP_DMA) ?
+ malloc_sizes[i].cs_dmacachep :
+ malloc_sizes[i].cs_cachep, flags);
+ }
+ return __kzalloc(size, flags);
+}
+
+#ifdef CONFIG_NUMA
+extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
+
+static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
+{
+ if (__builtin_constant_p(size)) {
+ int i = 0;
+#define CACHE(x) \
+ if (size <= x) \
+ goto found; \
+ else \
+ i++;
+#include "kmalloc_sizes.h"
+#undef CACHE
+ {
+ extern void __you_cannot_kmalloc_that_much(void);
+ __you_cannot_kmalloc_that_much();
+ }
+found:
+ return kmem_cache_alloc_node((flags & GFP_DMA) ?
+ malloc_sizes[i].cs_dmacachep :
+ malloc_sizes[i].cs_cachep, flags, node);
+ }
+ return __kmalloc_node(size, flags, node);
+}
+
+#endif /* CONFIG_NUMA */
+
+#endif /* _LINUX_SLAB_DEF_H */
diff --git a/include/linux/smb_fs_sb.h b/include/linux/smb_fs_sb.h
index 5b4ae2cc445..3aa97aa4277 100644
--- a/include/linux/smb_fs_sb.h
+++ b/include/linux/smb_fs_sb.h
@@ -55,7 +55,7 @@ struct smb_sb_info {
* generation is incremented.
*/
unsigned int generation;
- pid_t conn_pid;
+ struct pid *conn_pid;
struct smb_conn_opt opt;
wait_queue_head_t conn_wq;
int conn_complete;
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 92cd38efad7..fcd35a210e7 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -187,7 +187,8 @@ struct ucred {
#define AF_LLC 26 /* Linux LLC */
#define AF_TIPC 30 /* TIPC sockets */
#define AF_BLUETOOTH 31 /* Bluetooth sockets */
-#define AF_MAX 32 /* For now.. */
+#define AF_IUCV 32 /* IUCV sockets */
+#define AF_MAX 33 /* For now.. */
/* Protocol families, same as address families. */
#define PF_UNSPEC AF_UNSPEC
@@ -220,6 +221,7 @@ struct ucred {
#define PF_LLC AF_LLC
#define PF_TIPC AF_TIPC
#define PF_BLUETOOTH AF_BLUETOOTH
+#define PF_IUCV AF_IUCV
#define PF_MAX AF_MAX
/* Maximum queue length specifiable by listen. */
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index c8bb68099eb..176f6e36dbf 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -289,7 +289,7 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
* the data being transferred; that may reduce overhead, when the
* underlying driver uses dma.
*
- * If the transmit buffer is null, undefined data will be shifted out
+ * If the transmit buffer is null, zeroes will be shifted out
* while filling rx_buf. If the receive buffer is null, the data
* shifted in will be discarded. Only "len" bytes shift out (or in).
* It's an error to try to shift out a partial word. (For example, by
diff --git a/include/linux/stallion.h b/include/linux/stallion.h
index 13a37f137ea..4a0a329beaf 100644
--- a/include/linux/stallion.h
+++ b/include/linux/stallion.h
@@ -52,11 +52,11 @@
* protection - since "write" code only needs to change the head, and
* interrupt code only needs to change the tail.
*/
-typedef struct {
+struct stlrq {
char *buf;
char *head;
char *tail;
-} stlrq_t;
+};
/*
* Port, panel and board structures to hold status info about each.
@@ -67,14 +67,14 @@ typedef struct {
* is associated with, this makes it (fairly) easy to get back to the
* board/panel info for a port.
*/
-typedef struct stlport {
+struct stlport {
unsigned long magic;
- int portnr;
- int panelnr;
- int brdnr;
+ unsigned int portnr;
+ unsigned int panelnr;
+ unsigned int brdnr;
int ioaddr;
int uartaddr;
- int pagenr;
+ unsigned int pagenr;
long istate;
int flags;
int baud_base;
@@ -97,31 +97,31 @@ typedef struct stlport {
wait_queue_head_t close_wait;
struct work_struct tqueue;
comstats_t stats;
- stlrq_t tx;
-} stlport_t;
+ struct stlrq tx;
+};
-typedef struct stlpanel {
+struct stlpanel {
unsigned long magic;
- int panelnr;
- int brdnr;
- int pagenr;
- int nrports;
+ unsigned int panelnr;
+ unsigned int brdnr;
+ unsigned int pagenr;
+ unsigned int nrports;
int iobase;
void *uartp;
void (*isr)(struct stlpanel *panelp, unsigned int iobase);
unsigned int hwid;
unsigned int ackmask;
- stlport_t *ports[STL_PORTSPERPANEL];
-} stlpanel_t;
+ struct stlport *ports[STL_PORTSPERPANEL];
+};
-typedef struct stlbrd {
+struct stlbrd {
unsigned long magic;
- int brdnr;
- int brdtype;
- int state;
- int nrpanels;
- int nrports;
- int nrbnks;
+ unsigned int brdnr;
+ unsigned int brdtype;
+ unsigned int state;
+ unsigned int nrpanels;
+ unsigned int nrports;
+ unsigned int nrbnks;
int irq;
int irqtype;
int (*isr)(struct stlbrd *brdp);
@@ -136,9 +136,9 @@ typedef struct stlbrd {
unsigned long clk;
unsigned int bnkpageaddr[STL_MAXBANKS];
unsigned int bnkstataddr[STL_MAXBANKS];
- stlpanel_t *bnk2panel[STL_MAXBANKS];
- stlpanel_t *panels[STL_MAXPANELS];
-} stlbrd_t;
+ struct stlpanel *bnk2panel[STL_MAXBANKS];
+ struct stlpanel *panels[STL_MAXPANELS];
+};
/*
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 97c76165258..8b6ce60ea05 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -250,7 +250,6 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
int flags, const struct rpc_call_ops *ops,
void *data);
void rpc_put_task(struct rpc_task *);
-void rpc_release_task(struct rpc_task *);
void rpc_exit_task(struct rpc_task *);
void rpc_release_calldata(const struct rpc_call_ops *, void *);
void rpc_killall_tasks(struct rpc_clnt *);
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 965d6c20086..64f3d60c72a 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -144,8 +144,11 @@ extern u32 svc_max_payload(const struct svc_rqst *rqstp);
*
* Each request/reply pair can have at most one "payload", plus two pages,
* one for the request, and one for the reply.
+ * We using ->sendfile to return read data, we might need one extra page
+ * if the request is not page-aligned. So add another '1'.
*/
-#define RPCSVC_MAXPAGES ((RPCSVC_MAXPAYLOAD+PAGE_SIZE-1)/PAGE_SIZE + 2)
+#define RPCSVC_MAXPAGES ((RPCSVC_MAXPAYLOAD+PAGE_SIZE-1)/PAGE_SIZE \
+ + 2 + 1)
static inline u32 svc_getnl(struct kvec *iov)
{
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 98b21ad370f..db312a1e2ee 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -63,7 +63,7 @@ struct svc_sock {
* Function prototypes.
*/
int svc_makesock(struct svc_serv *, int, unsigned short);
-void svc_delete_socket(struct svc_sock *);
+void svc_close_socket(struct svc_sock *);
int svc_recv(struct svc_rqst *, long);
int svc_send(struct svc_rqst *);
void svc_drop(struct svc_rqst *);
diff --git a/include/linux/swap.h b/include/linux/swap.h
index add51cebc8d..5423559a44a 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -245,7 +245,7 @@ extern int swap_duplicate(swp_entry_t);
extern int valid_swaphandles(swp_entry_t, unsigned long *);
extern void swap_free(swp_entry_t);
extern void free_swap_and_cache(swp_entry_t);
-extern int swap_type_of(dev_t, sector_t);
+extern int swap_type_of(dev_t, sector_t, struct block_device **);
extern unsigned int count_swap_pages(int, int);
extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t);
extern sector_t swapdev_block(int, pgoff_t);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 94316a98e0d..665412c4f4b 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -11,7 +11,7 @@
** the sysctl() binary interface. Do *NOT* change the
** numbering of any existing values here, and do not change
** any numbers within any one set of values. If you have to
- ** have to redefine an existing interface, use a new number for it.
+ ** redefine an existing interface, use a new number for it.
** The kernel will then return -ENOTDIR to any application using
** the old binary interface.
**
@@ -699,7 +699,8 @@ enum {
NET_X25_CALL_REQUEST_TIMEOUT=2,
NET_X25_RESET_REQUEST_TIMEOUT=3,
NET_X25_CLEAR_REQUEST_TIMEOUT=4,
- NET_X25_ACK_HOLD_BACK_TIMEOUT=5
+ NET_X25_ACK_HOLD_BACK_TIMEOUT=5,
+ NET_X25_FORWARD=6
};
/* /proc/sys/net/token-ring */
@@ -918,8 +919,7 @@ typedef struct ctl_table ctl_table;
typedef int ctl_handler (ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context);
+ void __user *newval, size_t newlen);
typedef int proc_handler (ctl_table *ctl, int write, struct file * filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
@@ -950,7 +950,7 @@ extern int do_sysctl (int __user *name, int nlen,
extern int do_sysctl_strategy (ctl_table *table,
int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void ** context);
+ void __user *newval, size_t newlen);
extern ctl_handler sysctl_string;
extern ctl_handler sysctl_intvec;
diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h
index 166a2e58c28..389ccf858d3 100644
--- a/include/linux/sysdev.h
+++ b/include/linux/sysdev.h
@@ -98,12 +98,16 @@ struct sysdev_attribute {
};
-#define SYSDEV_ATTR(_name,_mode,_show,_store) \
-struct sysdev_attribute attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
+#define _SYSDEV_ATTR(_name,_mode,_show,_store) \
+{ \
+ .attr = { .name = __stringify(_name), .mode = _mode, \
+ .owner = THIS_MODULE }, \
.show = _show, \
.store = _store, \
-};
+}
+
+#define SYSDEV_ATTR(_name,_mode,_show,_store) \
+struct sysdev_attribute attr_##_name = _SYSDEV_ATTR(_name,_mode,_show,_store);
extern int sysdev_create_file(struct sys_device *, struct sysdev_attribute *);
extern void sysdev_remove_file(struct sys_device *, struct sysdev_attribute *);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 2129d1b6c87..192de3afa96 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -11,10 +11,12 @@
#define _SYSFS_H_
#include <linux/compiler.h>
+#include <linux/list.h>
#include <asm/atomic.h>
struct kobject;
struct module;
+struct nameidata;
struct attribute {
const char * name;
@@ -88,13 +90,13 @@ struct sysfs_dirent {
#ifdef CONFIG_SYSFS
extern int __must_check
-sysfs_create_dir(struct kobject *);
+sysfs_create_dir(struct kobject *, struct dentry *);
extern void
sysfs_remove_dir(struct kobject *);
extern int __must_check
-sysfs_rename_dir(struct kobject *, const char *new_name);
+sysfs_rename_dir(struct kobject *, struct dentry *, const char *new_name);
extern int __must_check
sysfs_move_dir(struct kobject *, struct kobject *);
@@ -126,11 +128,17 @@ int __must_check sysfs_create_group(struct kobject *,
void sysfs_remove_group(struct kobject *, const struct attribute_group *);
void sysfs_notify(struct kobject * k, char *dir, char *attr);
+
+extern int sysfs_make_shadowed_dir(struct kobject *kobj,
+ void * (*follow_link)(struct dentry *, struct nameidata *));
+extern struct dentry *sysfs_create_shadow_dir(struct kobject *kobj);
+extern void sysfs_remove_shadow_dir(struct dentry *dir);
+
extern int __must_check sysfs_init(void);
#else /* CONFIG_SYSFS */
-static inline int sysfs_create_dir(struct kobject * k)
+static inline int sysfs_create_dir(struct kobject * k, struct dentry *shadow)
{
return 0;
}
@@ -140,7 +148,9 @@ static inline void sysfs_remove_dir(struct kobject * k)
;
}
-static inline int sysfs_rename_dir(struct kobject * k, const char *new_name)
+static inline int sysfs_rename_dir(struct kobject * k,
+ struct dentry *new_parent,
+ const char *new_name)
{
return 0;
}
@@ -204,6 +214,12 @@ static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
{
}
+static inline int sysfs_make_shadowed_dir(struct kobject *kobj,
+ void * (*follow_link)(struct dentry *, struct nameidata *))
+{
+ return 0;
+}
+
static inline int __must_check sysfs_init(void)
{
return 0;
diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h
index 9df8833670c..98a1d8cfb73 100644
--- a/include/linux/sysrq.h
+++ b/include/linux/sysrq.h
@@ -37,23 +37,37 @@ struct sysrq_key_op {
#ifdef CONFIG_MAGIC_SYSRQ
+extern int sysrq_on(void);
+
+/*
+ * Do not use this one directly:
+ */
+extern int __sysrq_enabled;
+
/* Generic SysRq interface -- you may call it from any device driver, supplying
* ASCII code of the key, pointer to registers and kbd/tty structs (if they
* are available -- else NULL's).
*/
-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 *);
+void handle_sysrq(int key, struct tty_struct *tty);
+void __handle_sysrq(int key, struct tty_struct *tty, int check_mask);
+int register_sysrq_key(int key, struct sysrq_key_op *op);
+int unregister_sysrq_key(int key, struct sysrq_key_op *op);
struct sysrq_key_op *__sysrq_get_key_op(int key);
#else
+static inline int sysrq_on(void)
+{
+ return 0;
+}
static inline int __reterr(void)
{
return -EINVAL;
}
+static inline void handle_sysrq(int key, struct tty_struct *tty)
+{
+}
#define register_sysrq_key(ig,nore) __reterr()
#define unregister_sysrq_key(ig,nore) __reterr()
diff --git a/include/linux/task_io_accounting.h b/include/linux/task_io_accounting.h
new file mode 100644
index 00000000000..44d00e9ccee
--- /dev/null
+++ b/include/linux/task_io_accounting.h
@@ -0,0 +1,37 @@
+/*
+ * task_io_accounting: a structure which is used for recording a single task's
+ * IO statistics.
+ *
+ * Don't include this header file directly - it is designed to be dragged in via
+ * sched.h.
+ *
+ * Blame akpm@osdl.org for all this.
+ */
+
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+struct task_io_accounting {
+ /*
+ * The number of bytes which this task has caused to be read from
+ * storage.
+ */
+ u64 read_bytes;
+
+ /*
+ * The number of bytes which this task has caused, or shall cause to be
+ * written to disk.
+ */
+ u64 write_bytes;
+
+ /*
+ * A task can cause "negative" IO too. If this task truncates some
+ * dirty pagecache, some IO which another task has been accounted for
+ * (in its write_bytes) will not be happening. We _could_ just
+ * subtract that from the truncating task's write_bytes, but there is
+ * information loss in doing that.
+ */
+ u64 cancelled_write_bytes;
+};
+#else
+struct task_io_accounting {
+};
+#endif
diff --git a/include/linux/task_io_accounting_ops.h b/include/linux/task_io_accounting_ops.h
new file mode 100644
index 00000000000..df2a319106b
--- /dev/null
+++ b/include/linux/task_io_accounting_ops.h
@@ -0,0 +1,47 @@
+/*
+ * Task I/O accounting operations
+ */
+#ifndef __TASK_IO_ACCOUNTING_OPS_INCLUDED
+#define __TASK_IO_ACCOUNTING_OPS_INCLUDED
+
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+static inline void task_io_account_read(size_t bytes)
+{
+ current->ioac.read_bytes += bytes;
+}
+
+static inline void task_io_account_write(size_t bytes)
+{
+ current->ioac.write_bytes += bytes;
+}
+
+static inline void task_io_account_cancelled_write(size_t bytes)
+{
+ current->ioac.cancelled_write_bytes += bytes;
+}
+
+static inline void task_io_accounting_init(struct task_struct *tsk)
+{
+ memset(&tsk->ioac, 0, sizeof(tsk->ioac));
+}
+
+#else
+
+static inline void task_io_account_read(size_t bytes)
+{
+}
+
+static inline void task_io_account_write(size_t bytes)
+{
+}
+
+static inline void task_io_account_cancelled_write(size_t bytes)
+{
+}
+
+static inline void task_io_accounting_init(struct task_struct *tsk)
+{
+}
+
+#endif /* CONFIG_TASK_IO_ACCOUNTING */
+#endif /* __TASK_IO_ACCOUNTING_OPS_INCLUDED */
diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h
index 45248806ae9..3fced479825 100644
--- a/include/linux/taskstats.h
+++ b/include/linux/taskstats.h
@@ -31,7 +31,7 @@
*/
-#define TASKSTATS_VERSION 2
+#define TASKSTATS_VERSION 3
#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN
* in linux/sched.h */
@@ -115,31 +115,37 @@ struct taskstats {
__u64 ac_majflt; /* Major Page Fault Count */
/* Basic Accounting Fields end */
- /* Extended accounting fields start */
+ /* 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 */
+ __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 */
+ __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 */
+ __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 */
+ __u64 read_char; /* bytes read */
+ __u64 write_char; /* bytes written */
+ __u64 read_syscalls; /* read syscalls */
+ __u64 write_syscalls; /* write syscalls */
+ /* Extended accounting fields end */
+
+#define TASKSTATS_HAS_IO_ACCOUNTING
+ /* Per-task storage I/O accounting starts */
+ __u64 read_bytes; /* bytes of read I/O */
+ __u64 write_bytes; /* bytes of write I/O */
+ __u64 cancelled_write_bytes; /* bytes of cancelled write I/O */
};
diff --git a/include/linux/tc.h b/include/linux/tc.h
new file mode 100644
index 00000000000..f92511e57cd
--- /dev/null
+++ b/include/linux/tc.h
@@ -0,0 +1,141 @@
+/*
+ * Interface to the TURBOchannel related routines.
+ *
+ * Copyright (c) 1998 Harald Koerfgen
+ * Copyright (c) 2005 James Simmons
+ * Copyright (c) 2006 Maciej W. Rozycki
+ *
+ * Based on:
+ *
+ * "TURBOchannel Firmware Specification", EK-TCAAD-FS-004
+ *
+ * from Digital Equipment Corporation.
+ *
+ * This file is subject to the terms and conditions of the GNU
+ * General Public License. See the file "COPYING" in the main
+ * directory of this archive for more details.
+ */
+#ifndef _LINUX_TC_H
+#define _LINUX_TC_H
+
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+
+/*
+ * Offsets for the ROM header locations for TURBOchannel cards.
+ */
+#define TC_OLDCARD 0x3c0000
+#define TC_NEWCARD 0x000000
+
+#define TC_ROM_WIDTH 0x3e0
+#define TC_ROM_STRIDE 0x3e4
+#define TC_ROM_SIZE 0x3e8
+#define TC_SLOT_SIZE 0x3ec
+#define TC_PATTERN0 0x3f0
+#define TC_PATTERN1 0x3f4
+#define TC_PATTERN2 0x3f8
+#define TC_PATTERN3 0x3fc
+#define TC_FIRM_VER 0x400
+#define TC_VENDOR 0x420
+#define TC_MODULE 0x440
+#define TC_FIRM_TYPE 0x460
+#define TC_FLAGS 0x470
+#define TC_ROM_OBJECTS 0x480
+
+/*
+ * Information obtained through the get_tcinfo() PROM call.
+ */
+struct tcinfo {
+ s32 revision; /* Hardware revision level. */
+ s32 clk_period; /* Clock period in nanoseconds. */
+ s32 slot_size; /* Slot size in megabytes. */
+ s32 io_timeout; /* I/O timeout in cycles. */
+ s32 dma_range; /* DMA address range in megabytes. */
+ s32 max_dma_burst; /* Maximum DMA burst length. */
+ s32 parity; /* System module supports TC parity. */
+ s32 reserved[4];
+};
+
+/*
+ * TURBOchannel bus.
+ */
+struct tc_bus {
+ struct list_head devices; /* List of devices on this bus. */
+ struct resource resource[2]; /* Address space routed to this bus. */
+
+ struct device dev;
+ char name[13];
+ resource_size_t slot_base;
+ resource_size_t ext_slot_base;
+ resource_size_t ext_slot_size;
+ int num_tcslots;
+ struct tcinfo info;
+};
+
+/*
+ * TURBOchannel device.
+ */
+struct tc_dev {
+ struct list_head node; /* Node in list of all TC devices. */
+ struct tc_bus *bus; /* Bus this device is on. */
+ struct tc_driver *driver; /* Which driver has allocated this
+ device. */
+ struct device dev; /* Generic device interface. */
+ struct resource resource; /* Address space of this device. */
+ char vendor[9];
+ char name[9];
+ char firmware[9];
+ int interrupt;
+ int slot;
+};
+
+#define to_tc_dev(n) container_of(n, struct tc_dev, dev)
+
+struct tc_device_id {
+ char vendor[9];
+ char name[9];
+};
+
+/*
+ * TURBOchannel driver.
+ */
+struct tc_driver {
+ struct list_head node;
+ const struct tc_device_id *id_table;
+ struct device_driver driver;
+};
+
+#define to_tc_driver(drv) container_of(drv, struct tc_driver, driver)
+
+/*
+ * Return TURBOchannel clock frequency in Hz.
+ */
+static inline unsigned long tc_get_speed(struct tc_bus *tbus)
+{
+ return 100000 * (10000 / (unsigned long)tbus->info.clk_period);
+}
+
+#ifdef CONFIG_TC
+
+extern struct bus_type tc_bus_type;
+
+extern int tc_register_driver(struct tc_driver *tdrv);
+extern void tc_unregister_driver(struct tc_driver *tdrv);
+
+#else /* !CONFIG_TC */
+
+static inline int tc_register_driver(struct tc_driver *tdrv) { return 0; }
+static inline void tc_unregister_driver(struct tc_driver *tdrv) { }
+
+#endif /* CONFIG_TC */
+
+/*
+ * These have to be provided by the architecture.
+ */
+extern int tc_preadb(u8 *valp, void __iomem *addr);
+extern int tc_bus_get_info(struct tc_bus *tbus);
+extern void tc_device_get_irq(struct tc_dev *tdev);
+
+#endif /* _LINUX_TC_H */
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 3cc70d1a350..29d3089038a 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -316,7 +316,7 @@ struct tcp_sock {
struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */
struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
- struct tcp_sack_block recv_sack_cache[4];
+ struct tcp_sack_block_wire recv_sack_cache[4];
/* from STCP, retrans queue hinting */
struct sk_buff* lost_skb_hint;
diff --git a/include/linux/tfrc.h b/include/linux/tfrc.h
index 31a9b25276f..8a8462b4a4d 100644
--- a/include/linux/tfrc.h
+++ b/include/linux/tfrc.h
@@ -37,10 +37,14 @@ struct tfrc_rx_info {
* @tfrctx_p: current loss event rate (5.4)
* @tfrctx_rto: estimate of RTO, equals 4*RTT (4.3)
* @tfrctx_ipi: inter-packet interval (4.6)
+ *
+ * Note: X and X_recv are both maintained in units of 64 * bytes/second. This
+ * enables a finer resolution of sending rates and avoids problems with
+ * integer arithmetic; u32 is not sufficient as scaling consumes 6 bits.
*/
struct tfrc_tx_info {
- __u32 tfrctx_x;
- __u32 tfrctx_x_recv;
+ __u64 tfrctx_x;
+ __u64 tfrctx_x_recv;
__u32 tfrctx_x_calc;
__u32 tfrctx_rtt;
__u32 tfrctx_p;
diff --git a/include/linux/tifm.h b/include/linux/tifm.h
index dfb8052eee5..3deb0a6c137 100644
--- a/include/linux/tifm.h
+++ b/include/linux/tifm.h
@@ -17,7 +17,7 @@
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/pci.h>
-#include <linux/scatterlist.h>
+#include <linux/kthread.h>
/* Host registers (relative to pci base address): */
enum {
@@ -62,11 +62,10 @@ enum {
#define TIFM_IRQ_ENABLE 0x80000000
-#define TIFM_IRQ_SOCKMASK 0x00000001
-#define TIFM_IRQ_CARDMASK 0x00000100
-#define TIFM_IRQ_FIFOMASK 0x00010000
+#define TIFM_IRQ_SOCKMASK(x) (x)
+#define TIFM_IRQ_CARDMASK(x) ((x) << 8)
+#define TIFM_IRQ_FIFOMASK(x) ((x) << 16)
#define TIFM_IRQ_SETALL 0xffffffff
-#define TIFM_IRQ_SETALLSOCK 0x0000000f
#define TIFM_CTRL_LED 0x00000040
#define TIFM_CTRL_FAST_CLK 0x00000100
@@ -89,10 +88,9 @@ 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 socket_id;
- unsigned int (*signal_irq)(struct tifm_dev *sock,
+ void (*signal_irq)(struct tifm_dev *sock,
unsigned int sock_irq_status);
struct tifm_driver *drv;
@@ -103,24 +101,23 @@ struct tifm_driver {
tifm_media_id *id_table;
int (*probe)(struct tifm_dev *dev);
void (*remove)(struct tifm_dev *dev);
+ int (*suspend)(struct tifm_dev *dev,
+ pm_message_t state);
+ int (*resume)(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 irq_status;
+ unsigned int socket_change_set;
+ wait_queue_head_t change_set_notify;
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;
+ unsigned int num_sockets;
struct tifm_dev **sockets;
+ struct task_struct *media_switcher;
struct class_device cdev;
struct device *dev;
@@ -130,9 +127,9 @@ struct tifm_adapter {
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);
+int tifm_add_adapter(struct tifm_adapter *fm, int (*mediathreadfn)(void *data));
void tifm_remove_adapter(struct tifm_adapter *fm);
-struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id);
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm);
int tifm_register_driver(struct tifm_driver *drv);
void tifm_unregister_driver(struct tifm_driver *drv);
void tifm_eject(struct tifm_dev *sock);
diff --git a/include/linux/timer.h b/include/linux/timer.h
index c982304dbaf..fb5edaaf0eb 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -41,7 +41,7 @@ static inline void setup_timer(struct timer_list * timer,
init_timer(timer);
}
-/***
+/**
* timer_pending - is a timer pending?
* @timer: the timer in question
*
@@ -63,7 +63,7 @@ extern int mod_timer(struct timer_list *timer, unsigned long expires);
extern unsigned long next_timer_interrupt(void);
-/***
+/**
* add_timer - start a timer
* @timer: the timer to be added
*
@@ -98,4 +98,10 @@ extern void run_local_timers(void);
struct hrtimer;
extern int it_real_fn(struct hrtimer *);
+unsigned long __round_jiffies(unsigned long j, int cpu);
+unsigned long __round_jiffies_relative(unsigned long j, int cpu);
+unsigned long round_jiffies(unsigned long j);
+unsigned long round_jiffies_relative(unsigned long j);
+
+
#endif
diff --git a/include/linux/topology.h b/include/linux/topology.h
index da508d1998e..6c5a6e6e813 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -93,7 +93,7 @@
.groups = NULL, \
.min_interval = 1, \
.max_interval = 2, \
- .busy_factor = 8, \
+ .busy_factor = 64, \
.imbalance_pct = 110, \
.cache_nice_tries = 0, \
.per_cpu_gain = 25, \
@@ -194,7 +194,8 @@
.wake_idx = 0, /* unused */ \
.forkexec_idx = 0, /* unused */ \
.per_cpu_gain = 100, \
- .flags = SD_LOAD_BALANCE, \
+ .flags = SD_LOAD_BALANCE \
+ | SD_SERIALIZE, \
.last_balance = jiffies, \
.balance_interval = 64, \
.nr_balance_failed = 0, \
diff --git a/include/linux/tty.h b/include/linux/tty.h
index f717f089823..65cbcf22c31 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -175,7 +175,7 @@ struct tty_struct {
int index;
struct tty_ldisc ldisc;
struct mutex termios_mutex;
- struct termios *termios, *termios_locked;
+ struct ktermios *termios, *termios_locked;
char name[64];
int pgrp;
int session;
@@ -258,7 +258,7 @@ struct tty_struct {
extern void tty_write_flush(struct tty_struct *);
-extern struct termios tty_std_termios;
+extern struct ktermios tty_std_termios;
extern int kmsg_redirect;
@@ -293,8 +293,9 @@ extern int tty_hung_up_p(struct file * filp);
extern void do_SAK(struct tty_struct *tty);
extern void disassociate_ctty(int priv);
extern void tty_flip_buffer_push(struct tty_struct *tty);
-extern int tty_get_baud_rate(struct tty_struct *tty);
-extern int tty_termios_baud_rate(struct termios *termios);
+extern speed_t tty_get_baud_rate(struct tty_struct *tty);
+extern speed_t tty_termios_baud_rate(struct ktermios *termios);
+extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
extern void tty_ldisc_deref(struct tty_ldisc *);
@@ -309,6 +310,12 @@ 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 dev_t tty_devnum(struct tty_struct *tty);
+extern void proc_clear_tty(struct task_struct *p);
+extern void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+extern void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+extern struct tty_struct *get_current_tty(void);
+
extern struct mutex tty_mutex;
/* n_tty.c */
@@ -335,10 +342,5 @@ extern void console_print(const char *);
extern int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
-static inline dev_t tty_devnum(struct tty_struct *tty)
-{
- return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
-}
-
#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 5c8473bb688..659487e3ebe 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -53,7 +53,7 @@
* device-specific ioctl's. If the ioctl number passed in cmd
* is not recognized by the driver, it should return ENOIOCTLCMD.
*
- * void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ * void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
*
* This routine allows the tty driver to be notified when
* device's termios settings have changed. Note that a
@@ -132,7 +132,7 @@ struct tty_operations {
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
- void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
void (*stop)(struct tty_struct *tty);
@@ -165,7 +165,7 @@ struct tty_driver {
int num; /* number of devices allocated */
short type; /* type of tty driver */
short subtype; /* subtype of tty driver */
- struct termios init_termios; /* Initial termios */
+ struct ktermios init_termios; /* Initial termios */
int flags; /* tty driver flags */
int refcount; /* for loadable tty drivers */
struct proc_dir_entry *proc_entry; /* /proc fs entry */
@@ -175,8 +175,8 @@ struct tty_driver {
* Pointer to the tty data structures
*/
struct tty_struct **ttys;
- struct termios **termios;
- struct termios **termios_locked;
+ struct ktermios **termios;
+ struct ktermios **termios_locked;
void *driver_state; /* only used for the PTY driver */
/*
@@ -193,7 +193,7 @@ struct tty_driver {
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
- void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
void (*stop)(struct tty_struct *tty);
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index 83c6e6c10eb..d75932e2771 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -59,7 +59,7 @@
* low-level driver can "grab" an ioctl request before the line
* discpline has a chance to see it.
*
- * void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ * void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
*
* This function notifies the line discpline that a change has
* been made to the termios structure.
@@ -118,7 +118,7 @@ struct tty_ldisc {
const unsigned char * buf, size_t nr);
int (*ioctl)(struct tty_struct * tty, struct file * file,
unsigned int cmd, unsigned long arg);
- void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
unsigned int (*poll)(struct tty_struct *, struct file *,
struct poll_table_struct *);
int (*hangup)(struct tty_struct *tty);
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
index 28967eda9d7..d3a4f994a5d 100644
--- a/include/linux/ufs_fs.h
+++ b/include/linux/ufs_fs.h
@@ -789,6 +789,7 @@ struct ufs_sb_private_info {
__u32 s_maxsymlinklen;/* upper limit on fast symlinks' size */
__s32 fs_magic; /* filesystem magic */
+ unsigned int s_dirblksize;
};
/*
diff --git a/include/linux/unwind.h b/include/linux/unwind.h
index 749928c161f..7760860fa17 100644
--- a/include/linux/unwind.h
+++ b/include/linux/unwind.h
@@ -14,63 +14,6 @@
struct module;
-#ifdef CONFIG_STACK_UNWIND
-
-#include <asm/unwind.h>
-
-#ifndef ARCH_UNWIND_SECTION_NAME
-#define ARCH_UNWIND_SECTION_NAME ".eh_frame"
-#endif
-
-/*
- * Initialize unwind support.
- */
-extern void unwind_init(void);
-extern void unwind_setup(void);
-
-#ifdef CONFIG_MODULES
-
-extern void *unwind_add_table(struct module *,
- const void *table_start,
- unsigned long table_size);
-
-extern void unwind_remove_table(void *handle, int init_only);
-
-#endif
-
-extern int unwind_init_frame_info(struct unwind_frame_info *,
- struct task_struct *,
- /*const*/ struct pt_regs *);
-
-/*
- * Prepare to unwind a blocked task.
- */
-extern int unwind_init_blocked(struct unwind_frame_info *,
- struct task_struct *);
-
-/*
- * Prepare to unwind the currently running thread.
- */
-extern int unwind_init_running(struct unwind_frame_info *,
- asmlinkage int (*callback)(struct unwind_frame_info *,
- void *arg),
- void *arg);
-
-/*
- * Unwind to previous to frame. Returns 0 if successful, negative
- * number in case of an error.
- */
-extern int unwind(struct unwind_frame_info *);
-
-/*
- * Unwind until the return pointer is in user-land (or until an error
- * occurs). Returns 0 if successful, negative number in case of
- * error.
- */
-extern int unwind_to_user(struct unwind_frame_info *);
-
-#else
-
struct unwind_frame_info {};
static inline void unwind_init(void) {}
@@ -85,12 +28,12 @@ static inline void *unwind_add_table(struct module *mod,
return NULL;
}
-#endif
-
static inline void unwind_remove_table(void *handle, int init_only)
{
}
+#endif
+
static inline int unwind_init_frame_info(struct unwind_frame_info *info,
struct task_struct *tsk,
const struct pt_regs *regs)
@@ -122,6 +65,4 @@ static inline int unwind_to_user(struct unwind_frame_info *info)
return -ENOSYS;
}
-#endif
-
#endif /* _LINUX_UNWIND_H */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index aab5b1b7202..b5c226a87ed 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -2,7 +2,7 @@
#define __LINUX_USB_H
#include <linux/mod_devicetable.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#define USB_MAJOR 180
#define USB_DEVICE_MAJOR 189
@@ -107,7 +107,8 @@ enum usb_interface_condition {
* @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.
+ * @usb_dev: if an interface is bound to the USB major, this will point
+ * to the sysfs representation for that device.
* @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
* allowed unless the counter is 0.
*
@@ -152,7 +153,7 @@ struct usb_interface {
unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
struct device dev; /* interface specific device info */
- struct class_device *class_dev;
+ struct device *usb_dev; /* pointer to the usb class's device, if any */
int pm_usage_cnt; /* usage counter for autosuspend */
};
#define to_usb_interface(d) container_of(d, struct usb_interface, dev)
@@ -372,7 +373,7 @@ struct usb_device {
char *serial; /* iSerialNumber string, if present */
struct list_head filelist;
- struct class_device *class_dev;
+ struct device *usbfs_dev;
struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */
/*
@@ -475,6 +476,8 @@ extern void usb_driver_release_interface(struct usb_driver *driver,
struct usb_interface *iface);
const struct usb_device_id *usb_match_id(struct usb_interface *interface,
const struct usb_device_id *id);
+extern int usb_match_one_id(struct usb_interface *interface,
+ const struct usb_device_id *id);
extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
int minor);
@@ -554,6 +557,18 @@ static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *e
}
/**
+ * usb_endpoint_xfer_control - check if the endpoint has control transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type control, otherwise it returns false.
+ */
+static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_CONTROL);
+}
+
+/**
* usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
* @epd: endpoint to be checked
*
@@ -723,11 +738,21 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
/* ----------------------------------------------------------------------- */
+/* Stuff for dynamic usb ids */
struct usb_dynids {
spinlock_t lock;
struct list_head list;
};
+struct usb_dynid {
+ struct list_head node;
+ struct usb_device_id id;
+};
+
+extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
+ struct device_driver *driver,
+ const char *buf, size_t count);
+
/**
* struct usbdrv_wrap - wrapper for driver-model structure
* @driver: The driver-model core driver structure.
@@ -868,10 +893,11 @@ struct usb_class_driver {
* use these in module_init()/module_exit()
* and don't forget MODULE_DEVICE_TABLE(usb, ...)
*/
-extern int usb_register_driver(struct usb_driver *, struct module *);
+extern int usb_register_driver(struct usb_driver *, struct module *,
+ const char *);
static inline int usb_register(struct usb_driver *driver)
{
- return usb_register_driver(driver, THIS_MODULE);
+ return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
}
extern void usb_deregister(struct usb_driver *);
@@ -1085,7 +1111,6 @@ struct urb
struct kref kref; /* reference count of the URB */
spinlock_t lock; /* lock for the URB */
void *hcpriv; /* private data for host controller */
- int bandwidth; /* bandwidth for INT/ISO request */
atomic_t use_count; /* concurrent submissions counter */
u8 reject; /* submissions will fail */
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
new file mode 100644
index 00000000000..43f160cfe00
--- /dev/null
+++ b/include/linux/usb/Kbuild
@@ -0,0 +1,5 @@
+unifdef-y += audio.h
+unifdef-y += cdc.h
+unifdef-y += ch9.h
+unifdef-y += midi.h
+
diff --git a/include/linux/usb_ch9.h b/include/linux/usb/ch9.h
index c720d107ff2..ae7833749fa 100644
--- a/include/linux/usb_ch9.h
+++ b/include/linux/usb/ch9.h
@@ -224,6 +224,7 @@ struct usb_device_descriptor {
#define USB_CLASS_CONTENT_SEC 0x0d /* content security */
#define USB_CLASS_VIDEO 0x0e
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
+#define USB_CLASS_MISC 0xef
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 91b3ea2bbb1..33dcd857669 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -179,6 +179,9 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
* memory structure allocation at this point in time.
* @shutdown: pointer to the driver's shutdown function. This will be
* called when the device is removed from the system.
+ * @usb_driver: pointer to the struct usb_driver that controls this
+ * device. This is necessary to allow dynamic ids to be added to
+ * the driver from sysfs.
*
* This structure is defines a USB Serial driver. It provides all of
* the information that the USB serial core code needs. If the function
@@ -202,6 +205,8 @@ struct usb_serial_driver {
struct list_head driver_list;
struct device_driver driver;
+ struct usb_driver *usb_driver;
+ struct usb_dynids dynids;
int (*probe) (struct usb_serial *serial, const struct usb_device_id *id);
int (*attach) (struct usb_serial *serial);
@@ -218,7 +223,7 @@ struct usb_serial_driver {
int (*write) (struct usb_serial_port *port, const unsigned char *buf, int count);
int (*write_room) (struct usb_serial_port *port);
int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
- void (*set_termios) (struct usb_serial_port *port, struct termios * old);
+ void (*set_termios) (struct usb_serial_port *port, struct ktermios * old);
void (*break_ctl) (struct usb_serial_port *port, int break_state);
int (*chars_in_buffer) (struct usb_serial_port *port);
void (*throttle) (struct usb_serial_port *port);
diff --git a/include/linux/usb_gadgetfs.h b/include/linux/usb_gadgetfs.h
index b53d6ae8e55..8086d5a9b94 100644
--- a/include/linux/usb_gadgetfs.h
+++ b/include/linux/usb_gadgetfs.h
@@ -2,7 +2,7 @@
#include <asm/types.h>
#include <asm/ioctl.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
/*
* Filesystem based user-mode API to USB Gadget controller hardware
diff --git a/include/linux/video_output.h b/include/linux/video_output.h
new file mode 100644
index 00000000000..e63e0c03ee0
--- /dev/null
+++ b/include/linux/video_output.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright (C) 2006 Luming Yu <luming.yu@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; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _LINUX_VIDEO_OUTPUT_H
+#define _LINUX_VIDEO_OUTPUT_H
+#include <linux/device.h>
+struct output_device;
+struct output_properties {
+ int (*set_state)(struct output_device *);
+ int (*get_status)(struct output_device *);
+};
+struct output_device {
+ int request_state;
+ struct output_properties *props;
+ struct class_device class_dev;
+};
+#define to_output_device(obj) container_of(obj, struct output_device, class_dev)
+struct output_device *video_output_register(const char *name,
+ struct device *dev,
+ void *devdata,
+ struct output_properties *op);
+void video_output_unregister(struct output_device *dev);
+#endif
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index df5c4654360..d94e2683be5 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -244,6 +244,7 @@ struct v4l2_pix_format
#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:2:0 16x16 macroblocks */
+#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R','4','4','4') /* 16 xxxxrrrr ggggbbbb */
/* see http://www.siliconimaging.com/RGB%20Bayer.htm */
#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */
@@ -661,6 +662,15 @@ typedef __u64 v4l2_std_id;
#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000)
#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000)
+/* FIXME:
+ Although std_id is 64 bits, there is an issue on PPC32 architecture that
+ makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding
+ this value to 32 bits.
+ As, currently, the max value is for V4L2_STD_ATSC_16_VSB (30 bits wide),
+ it should work fine. However, if needed to add more than two standards,
+ v4l2-common.c should be fixed.
+ */
+
/* some merged standards */
#define V4L2_STD_MN (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
#define V4L2_STD_B (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index c89df55f6e0..5e9803ed17f 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -10,8 +10,9 @@
/*
* Light weight per cpu counter implementation.
*
- * Counters should only be incremented and no critical kernel component
- * should rely on the counter values.
+ * Counters should only be incremented. You need to set EMBEDDED
+ * to disable VM_EVENT_COUNTERS. Things like procps (vmstat,
+ * top, etc) use /proc/vmstat and depend on these counters.
*
* Counters are handled completely inline. On many platforms the code
* generated will simply be the increment of a global address.
@@ -73,7 +74,13 @@ static inline void count_vm_events(enum vm_event_item item, long delta)
}
extern void all_vm_events(unsigned long *);
+#ifdef CONFIG_HOTPLUG
extern void vm_events_fold_cpu(int cpu);
+#else
+static inline void vm_events_fold_cpu(int cpu)
+{
+}
+#endif
#else
diff --git a/include/linux/wanrouter.h b/include/linux/wanrouter.h
index 2cd05013edf..3add87465b1 100644
--- a/include/linux/wanrouter.h
+++ b/include/linux/wanrouter.h
@@ -516,9 +516,6 @@ struct wan_device {
/* Public functions available for device drivers */
extern int register_wan_device(struct wan_device *wandev);
extern int unregister_wan_device(char *name);
-__be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev);
-int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev,
- unsigned short type);
/* Proc interface functions. These must not be called by the drivers! */
extern int wanrouter_proc_init(void);
@@ -527,11 +524,6 @@ extern int wanrouter_proc_add(struct wan_device *wandev);
extern int wanrouter_proc_delete(struct wan_device *wandev);
extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-extern void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
-extern void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
-
-
-
/* Public Data */
/* list of registered devices */
extern struct wan_device *wanrouter_router_devlist;
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index edef8d50b26..2a7b38d8701 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -8,16 +8,21 @@
#include <linux/timer.h>
#include <linux/linkage.h>
#include <linux/bitops.h>
+#include <asm/atomic.h>
struct workqueue_struct;
struct work_struct;
typedef void (*work_func_t)(struct work_struct *work);
+/*
+ * The first word is the work queue pointer and the flags rolled into
+ * one
+ */
+#define work_data_bits(work) ((unsigned long *)(&(work)->data))
+
struct work_struct {
- /* the first word is the work queue pointer and the flags rolled into
- * one */
- unsigned long management;
+ atomic_long_t data;
#define WORK_STRUCT_PENDING 0 /* T if work item pending execution */
#define WORK_STRUCT_NOAUTOREL 1 /* F if work item automatically released on exec */
#define WORK_STRUCT_FLAG_MASK (3UL)
@@ -26,6 +31,9 @@ struct work_struct {
work_func_t func;
};
+#define WORK_DATA_INIT(autorelease) \
+ ATOMIC_LONG_INIT((autorelease) << WORK_STRUCT_NOAUTOREL)
+
struct delayed_work {
struct work_struct work;
struct timer_list timer;
@@ -36,13 +44,13 @@ struct execute_work {
};
#define __WORK_INITIALIZER(n, f) { \
- .management = 0, \
+ .data = WORK_DATA_INIT(0), \
.entry = { &(n).entry, &(n).entry }, \
.func = (f), \
}
#define __WORK_INITIALIZER_NAR(n, f) { \
- .management = (1 << WORK_STRUCT_NOAUTOREL), \
+ .data = WORK_DATA_INIT(1), \
.entry = { &(n).entry, &(n).entry }, \
.func = (f), \
}
@@ -82,17 +90,21 @@ struct execute_work {
/*
* initialize all of a work item in one go
+ *
+ * NOTE! No point in using "atomic_long_set()": useing a direct
+ * assignment of the work data initializer allows the compiler
+ * to generate better code.
*/
#define INIT_WORK(_work, _func) \
do { \
- (_work)->management = 0; \
+ (_work)->data = (atomic_long_t) WORK_DATA_INIT(0); \
INIT_LIST_HEAD(&(_work)->entry); \
PREPARE_WORK((_work), (_func)); \
} while (0)
#define INIT_WORK_NAR(_work, _func) \
do { \
- (_work)->management = (1 << WORK_STRUCT_NOAUTOREL); \
+ (_work)->data = (atomic_long_t) WORK_DATA_INIT(1); \
INIT_LIST_HEAD(&(_work)->entry); \
PREPARE_WORK((_work), (_func)); \
} while (0)
@@ -114,15 +126,15 @@ struct execute_work {
* @work: The work item in question
*/
#define work_pending(work) \
- test_bit(WORK_STRUCT_PENDING, &(work)->management)
+ test_bit(WORK_STRUCT_PENDING, work_data_bits(work))
/**
* delayed_work_pending - Find out whether a delayable work item is currently
* pending
* @work: The work item in question
*/
-#define delayed_work_pending(work) \
- test_bit(WORK_STRUCT_PENDING, &(work)->work.management)
+#define delayed_work_pending(w) \
+ work_pending(&(w)->work)
/**
* work_release - Release a work item under execution
@@ -143,7 +155,7 @@ struct execute_work {
* This should also be used to release a delayed work item.
*/
#define work_release(work) \
- clear_bit(WORK_STRUCT_PENDING, &(work)->management)
+ clear_bit(WORK_STRUCT_PENDING, work_data_bits(work))
extern struct workqueue_struct *__create_workqueue(const char *name,
@@ -188,7 +200,7 @@ static inline int cancel_delayed_work(struct delayed_work *work)
ret = del_timer_sync(&work->timer);
if (ret)
- clear_bit(WORK_STRUCT_PENDING, &work->work.management);
+ work_release(&work->work);
return ret;
}
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 088ba8113f7..15ca89e9961 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -178,6 +178,9 @@ enum {
XFRM_MSG_REPORT,
#define XFRM_MSG_REPORT XFRM_MSG_REPORT
+ XFRM_MSG_MIGRATE,
+#define XFRM_MSG_MIGRATE XFRM_MSG_MIGRATE
+
__XFRM_MSG_MAX
};
#define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -256,6 +259,7 @@ enum xfrm_attr_type_t {
XFRMA_COADDR, /* xfrm_address_t */
XFRMA_LASTUSED,
XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */
+ XFRMA_MIGRATE,
__XFRMA_MAX
#define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -351,13 +355,26 @@ struct xfrm_user_report {
struct xfrm_selector sel;
};
+struct xfrm_user_migrate {
+ xfrm_address_t old_daddr;
+ xfrm_address_t old_saddr;
+ xfrm_address_t new_daddr;
+ xfrm_address_t new_saddr;
+ __u8 proto;
+ __u8 mode;
+ __u16 reserved;
+ __u32 reqid;
+ __u16 old_family;
+ __u16 new_family;
+};
+
#ifndef __KERNEL__
/* backwards compatibility for userspace */
#define XFRMGRP_ACQUIRE 1
#define XFRMGRP_EXPIRE 2
#define XFRMGRP_SA 4
#define XFRMGRP_POLICY 8
-#define XFRMGRP_REPORT 0x10
+#define XFRMGRP_REPORT 0x20
#endif
enum xfrm_nlgroups {
@@ -375,6 +392,8 @@ enum xfrm_nlgroups {
#define XFRMNLGRP_AEVENTS XFRMNLGRP_AEVENTS
XFRMNLGRP_REPORT,
#define XFRMNLGRP_REPORT XFRMNLGRP_REPORT
+ XFRMNLGRP_MIGRATE,
+#define XFRMNLGRP_MIGRATE XFRMNLGRP_MIGRATE
__XFRMNLGRP_MAX
};
#define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1)
diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h
index d91d88f93c8..ecad55bf016 100644
--- a/include/media/cx2341x.h
+++ b/include/media/cx2341x.h
@@ -49,7 +49,7 @@ struct cx2341x_mpeg_params {
enum v4l2_mpeg_audio_mode_extension audio_mode_extension;
enum v4l2_mpeg_audio_emphasis audio_emphasis;
enum v4l2_mpeg_audio_crc audio_crc;
- u8 audio_properties;
+ u16 audio_properties;
/* video */
enum v4l2_mpeg_video_encoding video_encoding;
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index 8f58406533c..4bb0ad81017 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -24,6 +24,7 @@
#define _IR_COMMON
#include <linux/input.h>
+#include <linux/workqueue.h>
#define IR_TYPE_RC5 1
#define IR_TYPE_PD 2 /* Pulse distance encoded IR */
@@ -92,6 +93,7 @@ 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];
+extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE];
#endif
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index fee579f10b3..796bcf151a3 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -42,10 +42,6 @@ extern unsigned int saa7146_debug;
#define DEB_INT(x) if (0!=(DEBUG_VARIABLE&0x20)) { DEBUG_PROLOG; printk x; } /* interrupt debug messages */
#define DEB_CAP(x) if (0!=(DEBUG_VARIABLE&0x40)) { DEBUG_PROLOG; printk x; } /* capture debug messages */
-#define SAA7146_IER_DISABLE(x,y) \
- saa7146_write(x, IER, saa7146_read(x, IER) & ~(y));
-#define SAA7146_IER_ENABLE(x,y) \
- saa7146_write(x, IER, saa7146_read(x, IER) | (y));
#define SAA7146_ISR_CLEAR(x,y) \
saa7146_write(x, ISR, (y));
@@ -441,4 +437,20 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
#define SAA7146_I2C_BUS_BIT_RATE_80 (0x200)
#define SAA7146_I2C_BUS_BIT_RATE_60 (0x300)
+static inline void SAA7146_IER_DISABLE(struct saa7146_dev *x, unsigned y)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&x->int_slock, flags);
+ saa7146_write(x, IER, saa7146_read(x, IER) & ~y);
+ spin_unlock_irqrestore(&x->int_slock, flags);
+}
+
+static inline void SAA7146_IER_ENABLE(struct saa7146_dev *x, unsigned y)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&x->int_slock, flags);
+ saa7146_write(x, IER, saa7146_read(x, IER) | y);
+ spin_unlock_irqrestore(&x->int_slock, flags);
+}
+
#endif
diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h
index 37dad07a843..e5ad3fcfe98 100644
--- a/include/media/tuner-types.h
+++ b/include/media/tuner-types.h
@@ -50,6 +50,10 @@ struct tuner_params {
sensitivity. If this setting is 1, then set PORT2 to 1 to
get proper FM reception. */
unsigned int port2_fm_high_sensitivity:1;
+ /* Some Philips tuners use tda9887 cGainNormal to select the FM radio
+ sensitivity. If this setting is 1, e register will use cGainNormal
+ instead of cGainLow. */
+ unsigned int fm_gain_normal:1;
/* Most tuners with a tda9887 use QSS mode. Some (cheaper) tuners
use Intercarrier mode. If this setting is 1, then the tuner
needs to be set to intercarrier mode. */
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 3116e750132..99acf847365 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -145,6 +145,7 @@ extern int tuner_debug;
#define TDA9887_DEEMPHASIS_75 (3<<16)
#define TDA9887_AUTOMUTE (1<<18)
#define TDA9887_GATING_18 (1<<19)
+#define TDA9887_GAIN_NORMAL (1<<20)
#ifdef __KERNEL__
diff --git a/include/media/tveeprom.h b/include/media/tveeprom.h
index e9fc1a78549..5660ea24996 100644
--- a/include/media/tveeprom.h
+++ b/include/media/tveeprom.h
@@ -3,7 +3,7 @@
struct tveeprom {
u32 has_radio;
- u32 has_ir; /* 0: no IR, 1: IR present, 2: unknown */
+ u32 has_ir; /* bit 0: IR receiver present, bit 1: IR transmitter (blaster) present. -1 == unknown */
u32 has_MAC_address; /* 0: no MAC, 1: MAC present, 2: unknown */
u32 tuner_type;
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index aecc946980a..91b19921f95 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -144,6 +144,9 @@ enum v4l2_chip_ident {
V4L2_IDENT_CX25841 = 241,
V4L2_IDENT_CX25842 = 242,
V4L2_IDENT_CX25843 = 243,
+
+ /* OmniVision sensors - range 250-299 */
+ V4L2_IDENT_OV7670 = 250,
};
/* audio ioctls */
@@ -251,4 +254,8 @@ struct v4l2_crystal_freq {
If the frequency is not supported, then -EINVAL is returned. */
#define VIDIOC_INT_S_CRYSTAL_FREQ _IOW ('d', 113, struct v4l2_crystal_freq)
+/* Initialize the sensor registors to some sort of reasonable
+ default values. */
+#define VIDIOC_INT_INIT _IOW ('d', 114, u32)
+
#endif /* V4L2_COMMON_H_ */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 6a11d772700..fb96472a1bd 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -43,6 +43,7 @@
/* Video standard functions */
extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
+extern char *v4l2_norm_to_name(v4l2_std_id id);
extern int v4l2_video_std_construct(struct v4l2_standard *vs,
int id, char *name);
@@ -81,12 +82,6 @@ extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
* This version moves redundant code from video device code to
* the common handler
*/
-struct v4l2_tvnorm {
- char *name;
- v4l2_std_id id;
-
- void *priv_data;
-};
struct video_device
{
@@ -104,9 +99,8 @@ struct video_device
int debug; /* Activates debug level*/
/* Video standard vars */
- int tvnormsize; /* Size of tvnorm array */
- v4l2_std_id current_norm; /* Current tvnorm */
- struct v4l2_tvnorm *tvnorms;
+ v4l2_std_id tvnorms; /* Supported tv norms */
+ v4l2_std_id current_norm; /* Current tvnorm */
/* callbacks */
void (*release)(struct video_device *vfd);
@@ -211,7 +205,7 @@ struct video_device
/* Standard handling
G_STD and ENUMSTD are handled by videodev.c
*/
- int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id a);
+ int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm);
int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);
/* Input handling */
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 69374cd1a85..5ae10dd2e32 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -277,20 +277,24 @@ struct sock *ax25_get_socket(ax25_address *, ax25_address *, int);
extern ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, struct net_device *);
extern void ax25_send_to_raw(ax25_address *, struct sk_buff *, int);
extern void ax25_destroy_socket(ax25_cb *);
-extern ax25_cb *ax25_create_cb(void);
+extern ax25_cb * __must_check ax25_create_cb(void);
extern void ax25_fillin_cb(ax25_cb *, ax25_dev *);
extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *);
/* ax25_addr.c */
-extern ax25_address null_ax25_address;
-extern char *ax2asc(char *buf, ax25_address *);
-extern void asc2ax(ax25_address *addr, char *callsign);
-extern int ax25cmp(ax25_address *, ax25_address *);
-extern int ax25digicmp(ax25_digi *, ax25_digi *);
-extern unsigned char *ax25_addr_parse(unsigned char *, int, ax25_address *, ax25_address *, ax25_digi *, int *, int *);
-extern int ax25_addr_build(unsigned char *, ax25_address *, ax25_address *, ax25_digi *, int, int);
-extern int ax25_addr_size(ax25_digi *);
-extern void ax25_digi_invert(ax25_digi *, ax25_digi *);
+extern const ax25_address ax25_bcast;
+extern const ax25_address ax25_defaddr;
+extern const ax25_address null_ax25_address;
+extern char *ax2asc(char *buf, const ax25_address *);
+extern void asc2ax(ax25_address *addr, const char *callsign);
+extern int ax25cmp(const ax25_address *, const ax25_address *);
+extern int ax25digicmp(const ax25_digi *, const ax25_digi *);
+extern const unsigned char *ax25_addr_parse(const unsigned char *, int,
+ ax25_address *, ax25_address *, ax25_digi *, int *, int *);
+extern int ax25_addr_build(unsigned char *, const ax25_address *,
+ const ax25_address *, const ax25_digi *, int, int);
+extern int ax25_addr_size(const ax25_digi *);
+extern void ax25_digi_invert(const ax25_digi *, ax25_digi *);
/* ax25_dev.c */
extern ax25_dev *ax25_dev_list;
@@ -329,11 +333,25 @@ extern void ax25_ds_t3timer_expiry(ax25_cb *);
extern void ax25_ds_idletimer_expiry(ax25_cb *);
/* ax25_iface.c */
-extern int ax25_protocol_register(unsigned int, int (*)(struct sk_buff *, ax25_cb *));
+
+struct ax25_protocol {
+ struct ax25_protocol *next;
+ unsigned int pid;
+ int (*func)(struct sk_buff *, ax25_cb *);
+};
+
+extern void ax25_register_pid(struct ax25_protocol *ap);
extern void ax25_protocol_release(unsigned int);
-extern int ax25_linkfail_register(void (*)(ax25_cb *, int));
-extern void ax25_linkfail_release(void (*)(ax25_cb *, int));
-extern int ax25_listen_register(ax25_address *, struct net_device *);
+
+struct ax25_linkfail {
+ struct hlist_node lf_node;
+ void (*func)(ax25_cb *, int);
+};
+
+extern void ax25_linkfail_register(struct ax25_linkfail *lf);
+extern void ax25_linkfail_release(struct ax25_linkfail *lf);
+extern int __must_check ax25_listen_register(ax25_address *,
+ struct net_device *);
extern void ax25_listen_release(ax25_address *, struct net_device *);
extern int (*ax25_protocol_function(unsigned int))(struct sk_buff *, ax25_cb *);
extern int ax25_listen_mine(ax25_address *, struct net_device *);
@@ -411,7 +429,7 @@ extern unsigned long ax25_display_timer(struct timer_list *);
/* ax25_uid.c */
extern int ax25_uid_policy;
extern ax25_uid_assoc *ax25_findbyuid(uid_t);
-extern int ax25_uid_ioctl(int, struct sockaddr_ax25 *);
+extern int __must_check ax25_uid_ioctl(int, struct sockaddr_ax25 *);
extern struct file_operations ax25_uid_fops;
extern void ax25_uid_free(void);
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 10a3eec191f..41456c14884 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -739,13 +739,13 @@ struct sockaddr_hci {
struct hci_filter {
unsigned long type_mask;
unsigned long event_mask[2];
- __u16 opcode;
+ __le16 opcode;
};
struct hci_ufilter {
__u32 type_mask;
__u32 event_mask[2];
- __u16 opcode;
+ __le16 opcode;
};
#define HCI_FLT_TYPE_BITS 31
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index e6af381e206..e02d85f56e6 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -218,7 +218,7 @@ struct ieee80211_snap_hdr {
#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
-#define WLAN_GET_SEQ_SEQ(seq) ((seq) & IEEE80211_SCTL_SEQ)
+#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
diff --git a/include/net/inet6_connection_sock.h b/include/net/inet6_connection_sock.h
index 16aa96a6a53..f13ddc2543b 100644
--- a/include/net/inet6_connection_sock.h
+++ b/include/net/inet6_connection_sock.h
@@ -38,5 +38,5 @@ extern void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
extern void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr);
-extern int inet6_csk_xmit(struct sk_buff *skb, struct sock *sk, int ipfragok);
+extern int inet6_csk_xmit(struct sk_buff *skb, int ipfragok);
#endif /* _INET6_CONNECTION_SOCK_H */
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index bf16d98d372..133cf30d2d7 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -37,8 +37,7 @@ struct tcp_congestion_ops;
* (i.e. things that depend on the address family)
*/
struct inet_connection_sock_af_ops {
- int (*queue_xmit)(struct sk_buff *skb, struct sock *sk,
- int ipfragok);
+ int (*queue_xmit)(struct sk_buff *skb, int ipfragok);
void (*send_check)(struct sock *sk, int len,
struct sk_buff *skb);
int (*rebuild_header)(struct sock *sk);
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 34cc76e3ddb..d27ee8c0da3 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -34,12 +34,13 @@
#include <asm/byteorder.h>
/* This is for all connections with a full identity, no wildcards.
- * New scheme, half the table is for TIME_WAIT, the other half is
- * for the rest. I'll experiment with dynamic table growth later.
+ * One chain is dedicated to TIME_WAIT sockets.
+ * I'll experiment with dynamic table growth later.
*/
struct inet_ehash_bucket {
rwlock_t lock;
struct hlist_head chain;
+ struct hlist_head twchain;
};
/* There are a few simple rules, which allow for local port reuse by
@@ -97,8 +98,7 @@ struct inet_hashinfo {
*
* TCP_ESTABLISHED <= sk->sk_state < TCP_CLOSE
*
- * First half of the table is for sockets not in TIME_WAIT, second half
- * is for TIME_WAIT sockets only.
+ * TIME_WAIT sockets use a separate chain (twchain).
*/
struct inet_ehash_bucket *ehash;
@@ -369,7 +369,7 @@ static inline struct sock *
}
/* Must check for a TIME_WAIT'er before going to listener hash. */
- sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
+ sk_for_each(sk, node, &head->twchain) {
if (INET_TW_MATCH(sk, hash, acookie, saddr, daddr, ports, dif))
goto hit;
}
diff --git a/include/net/ip.h b/include/net/ip.h
index 83cb9ac5554..e79c3e3aa4f 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -97,7 +97,7 @@ extern int ip_mc_output(struct sk_buff *skb);
extern int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
extern int ip_do_nat(struct sk_buff *skb);
extern void ip_send_check(struct iphdr *ip);
-extern int ip_queue_xmit(struct sk_buff *skb, struct sock *sk, int ipfragok);
+extern int ip_queue_xmit(struct sk_buff *skb, int ipfragok);
extern void ip_init(void);
extern int ip_append_data(struct sock *sk,
int getfrag(void *from, char *to, int offset, int len,
@@ -376,8 +376,7 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write,
size_t *lenp, loff_t *ppos);
int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context);
+ void __user *newval, size_t newlen);
#ifdef CONFIG_PROC_FS
extern int ip_misc_proc_init(void);
#endif
diff --git a/include/net/ip6_checksum.h b/include/net/ip6_checksum.h
index 68e2b32cf1d..bc1b0fda2b0 100644
--- a/include/net/ip6_checksum.h
+++ b/include/net/ip6_checksum.h
@@ -87,7 +87,7 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
carry = (sum < uproto);
sum += carry;
- return csum_fold((__force __wsum)csum);
+ return csum_fold((__force __wsum)sum);
}
#endif
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index f9cde44f93b..7be4f4e3a0f 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -50,9 +50,9 @@ struct fib6_node
struct fib6_node *parent;
struct fib6_node *left;
struct fib6_node *right;
-
+#ifdef CONFIG_IPV6_SUBTREES
struct fib6_node *subtree;
-
+#endif
struct rt6_info *leaf;
__u16 fn_bit; /* bit key */
diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h
index 87699cb4ef8..8dabdd603fe 100644
--- a/include/net/irda/ircomm_tty.h
+++ b/include/net/irda/ircomm_tty.h
@@ -126,7 +126,7 @@ extern int ircomm_tty_tiocmset(struct tty_struct *tty, struct file *file,
extern int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
extern void ircomm_tty_set_termios(struct tty_struct *tty,
- struct termios *old_termios);
+ struct ktermios *old_termios);
extern hashbin_t *ircomm_tty;
#endif
diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h
new file mode 100644
index 00000000000..04d1abb72d2
--- /dev/null
+++ b/include/net/iucv/af_iucv.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2006 IBM Corporation
+ * IUCV protocol stack for Linux on zSeries
+ * Version 1.0
+ * Author(s): Jennifer Hunt <jenhunt@us.ibm.com>
+ *
+ */
+
+#ifndef __AFIUCV_H
+#define __AFIUCV_H
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/socket.h>
+
+#ifndef AF_IUCV
+#define AF_IUCV 32
+#define PF_IUCV AF_IUCV
+#endif
+
+/* Connection and socket states */
+enum {
+ IUCV_CONNECTED = 1,
+ IUCV_OPEN,
+ IUCV_BOUND,
+ IUCV_LISTEN,
+ IUCV_SEVERED,
+ IUCV_DISCONN,
+ IUCV_CLOSED
+};
+
+#define IUCV_QUEUELEN_DEFAULT 65535
+#define IUCV_CONN_TIMEOUT (HZ * 40)
+#define IUCV_DISCONN_TIMEOUT (HZ * 2)
+#define IUCV_CONN_IDLE_TIMEOUT (HZ * 60)
+#define IUCV_BUFSIZE_DEFAULT 32768
+
+/* IUCV socket address */
+struct sockaddr_iucv {
+ sa_family_t siucv_family;
+ unsigned short siucv_port; /* Reserved */
+ unsigned int siucv_addr; /* Reserved */
+ char siucv_nodeid[8]; /* Reserved */
+ char siucv_user_id[8]; /* Guest User Id */
+ char siucv_name[8]; /* Application Name */
+};
+
+
+/* Common socket structures and functions */
+
+#define iucv_sk(__sk) ((struct iucv_sock *) __sk)
+
+struct iucv_sock {
+ struct sock sk;
+ char src_user_id[8];
+ char src_name[8];
+ char dst_user_id[8];
+ char dst_name[8];
+ struct list_head accept_q;
+ struct sock *parent;
+ struct iucv_path *path;
+ struct sk_buff_head send_skb_q;
+ unsigned int send_tag;
+};
+
+struct iucv_sock_list {
+ struct hlist_head head;
+ rwlock_t lock;
+ atomic_t autobind_name;
+};
+
+static void iucv_sock_destruct(struct sock *sk);
+static void iucv_sock_cleanup_listen(struct sock *parent);
+static void iucv_sock_kill(struct sock *sk);
+static void iucv_sock_close(struct sock *sk);
+static int iucv_sock_create(struct socket *sock, int proto);
+static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr,
+ int addr_len);
+static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
+ int alen, int flags);
+static int iucv_sock_listen(struct socket *sock, int backlog);
+static int iucv_sock_accept(struct socket *sock, struct socket *newsock,
+ int flags);
+static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr,
+ int *len, int peer);
+static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t len);
+static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t len, int flags);
+unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
+ poll_table *wait);
+static int iucv_sock_release(struct socket *sock);
+static int iucv_sock_shutdown(struct socket *sock, int how);
+
+void iucv_sock_link(struct iucv_sock_list *l, struct sock *s);
+void iucv_sock_unlink(struct iucv_sock_list *l, struct sock *s);
+int iucv_sock_wait_state(struct sock *sk, int state, int state2,
+ unsigned long timeo);
+int iucv_sock_wait_cnt(struct sock *sk, unsigned long timeo);
+void iucv_accept_enqueue(struct sock *parent, struct sock *sk);
+void iucv_accept_unlink(struct sock *sk);
+struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock);
+
+#endif /* __IUCV_H */
diff --git a/include/net/iucv/iucv.h b/include/net/iucv/iucv.h
new file mode 100644
index 00000000000..746e7416261
--- /dev/null
+++ b/include/net/iucv/iucv.h
@@ -0,0 +1,415 @@
+/*
+ * drivers/s390/net/iucv.h
+ * IUCV base support.
+ *
+ * S390 version
+ * Copyright 2000, 2006 IBM Corporation
+ * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com)
+ * Xenia Tkatschow (xenia@us.ibm.com)
+ * Rewritten for af_iucv:
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ *
+ * Functionality:
+ * To explore any of the IUCV functions, one must first register their
+ * program using iucv_register(). Once your program has successfully
+ * completed a register, it can exploit the other functions.
+ * For furthur reference on all IUCV functionality, refer to the
+ * CP Programming Services book, also available on the web thru
+ * www.ibm.com/s390/vm/pubs, manual # SC24-5760
+ *
+ * Definition of Return Codes
+ * - All positive return codes including zero are reflected back
+ * from CP. The definition of each return code can be found in
+ * CP Programming Services book.
+ * - Return Code of:
+ * -EINVAL: Invalid value
+ * -ENOMEM: storage allocation failed
+ */
+
+#include <linux/types.h>
+#include <asm/debug.h>
+
+/*
+ * IUCV option flags usable by device drivers:
+ *
+ * IUCV_IPRMDATA Indicates that your program can handle a message in the
+ * parameter list / a message is sent in the parameter list.
+ * Used for iucv_path_accept, iucv_path_connect,
+ * iucv_message_reply, iucv_message_send, iucv_message_send2way.
+ * IUCV_IPQUSCE Indicates that you do not want to receive messages on this
+ * path until an iucv_path_resume is issued.
+ * Used for iucv_path_accept, iucv_path_connect.
+ * IUCV_IPBUFLST Indicates that an address list is used for the message data.
+ * Used for iucv_message_receive, iucv_message_send,
+ * iucv_message_send2way.
+ * IUCV_IPPRTY Specifies that you want to send priority messages.
+ * Used for iucv_path_accept, iucv_path_connect,
+ * iucv_message_reply, iucv_message_send, iucv_message_send2way.
+ * IUCV_IPSYNC Indicates a synchronous send request.
+ * Used for iucv_message_send, iucv_message_send2way.
+ * IUCV_IPANSLST Indicates that an address list is used for the reply data.
+ * Used for iucv_message_reply, iucv_message_send2way.
+ * IUCV_IPLOCAL Specifies that the communication partner has to be on the
+ * local system. If local is specified no target class can be
+ * specified.
+ * Used for iucv_path_connect.
+ *
+ * All flags are defined in the input field IPFLAGS1 of each function
+ * and can be found in CP Programming Services.
+ */
+#define IUCV_IPRMDATA 0x80
+#define IUCV_IPQUSCE 0x40
+#define IUCV_IPBUFLST 0x40
+#define IUCV_IPPRTY 0x20
+#define IUCV_IPANSLST 0x08
+#define IUCV_IPSYNC 0x04
+#define IUCV_IPLOCAL 0x01
+
+/*
+ * iucv_array : Defines buffer array.
+ * Inside the array may be 31- bit addresses and 31-bit lengths.
+ * Use a pointer to an iucv_array as the buffer, reply or answer
+ * parameter on iucv_message_send, iucv_message_send2way, iucv_message_receive
+ * and iucv_message_reply if IUCV_IPBUFLST or IUCV_IPANSLST are used.
+ */
+struct iucv_array {
+ u32 address;
+ u32 length;
+} __attribute__ ((aligned (8)));
+
+extern struct bus_type iucv_bus;
+extern struct device *iucv_root;
+
+/*
+ * struct iucv_path
+ * pathid: 16 bit path identification
+ * msglim: 16 bit message limit
+ * flags: properties of the path: IPRMDATA, IPQUSCE, IPPRTY
+ * handler: address of iucv handler structure
+ * private: private information of the handler associated with the path
+ * list: list_head for the iucv_handler path list.
+ */
+struct iucv_path {
+ u16 pathid;
+ u16 msglim;
+ u8 flags;
+ void *private;
+ struct iucv_handler *handler;
+ struct list_head list;
+};
+
+/*
+ * struct iucv_message
+ * id: 32 bit message id
+ * audit: 32 bit error information of purged or replied messages
+ * class: 32 bit target class of a message (source class for replies)
+ * tag: 32 bit tag to be associated with the message
+ * length: 32 bit length of the message / reply
+ * reply_size: 32 bit maximum allowed length of the reply
+ * rmmsg: 8 byte inline message
+ * flags: message properties (IUCV_IPPRTY)
+ */
+struct iucv_message {
+ u32 id;
+ u32 audit;
+ u32 class;
+ u32 tag;
+ u32 length;
+ u32 reply_size;
+ u8 rmmsg[8];
+ u8 flags;
+};
+
+/*
+ * struct iucv_handler
+ *
+ * A vector of functions that handle IUCV interrupts. Each functions gets
+ * a parameter area as defined by the CP Programming Services and private
+ * pointer that is provided by the user of the interface.
+ */
+struct iucv_handler {
+ /*
+ * The path_pending function is called after an iucv interrupt
+ * type 0x01 has been received. The base code allocates a path
+ * structure and "asks" the handler if this path belongs to the
+ * handler. To accept the path the path_pending function needs
+ * to call iucv_path_accept and return 0. If the callback returns
+ * a value != 0 the iucv base code will continue with the next
+ * handler. The order in which the path_pending functions are
+ * called is the order of the registration of the iucv handlers
+ * to the base code.
+ */
+ int (*path_pending)(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
+ /*
+ * The path_complete function is called after an iucv interrupt
+ * type 0x02 has been received for a path that has been established
+ * for this handler with iucv_path_connect and got accepted by the
+ * peer with iucv_path_accept.
+ */
+ void (*path_complete)(struct iucv_path *, u8 ipuser[16]);
+ /*
+ * The path_severed function is called after an iucv interrupt
+ * type 0x03 has been received. The communication peer shutdown
+ * his end of the communication path. The path still exists and
+ * remaining messages can be received until a iucv_path_sever
+ * shuts down the other end of the path as well.
+ */
+ void (*path_severed)(struct iucv_path *, u8 ipuser[16]);
+ /*
+ * The path_quiesced function is called after an icuv interrupt
+ * type 0x04 has been received. The communication peer has quiesced
+ * the path. Delivery of messages is stopped until iucv_path_resume
+ * has been called.
+ */
+ void (*path_quiesced)(struct iucv_path *, u8 ipuser[16]);
+ /*
+ * The path_resumed function is called after an icuv interrupt
+ * type 0x05 has been received. The communication peer has resumed
+ * the path.
+ */
+ void (*path_resumed)(struct iucv_path *, u8 ipuser[16]);
+ /*
+ * The message_pending function is called after an icuv interrupt
+ * type 0x06 or type 0x07 has been received. A new message is
+ * availabe and can be received with iucv_message_receive.
+ */
+ void (*message_pending)(struct iucv_path *, struct iucv_message *);
+ /*
+ * The message_complete function is called after an icuv interrupt
+ * type 0x08 or type 0x09 has been received. A message send with
+ * iucv_message_send2way has been replied to. The reply can be
+ * received with iucv_message_receive.
+ */
+ void (*message_complete)(struct iucv_path *, struct iucv_message *);
+
+ struct list_head list;
+ struct list_head paths;
+};
+
+/**
+ * iucv_register:
+ * @handler: address of iucv handler structure
+ * @smp: != 0 indicates that the handler can deal with out of order messages
+ *
+ * Registers a driver with IUCV.
+ *
+ * Returns 0 on success, -ENOMEM if the memory allocation for the pathid
+ * table failed, or -EIO if IUCV_DECLARE_BUFFER failed on all cpus.
+ */
+int iucv_register(struct iucv_handler *handler, int smp);
+
+/**
+ * iucv_unregister
+ * @handler: address of iucv handler structure
+ * @smp: != 0 indicates that the handler can deal with out of order messages
+ *
+ * Unregister driver from IUCV.
+ */
+void iucv_unregister(struct iucv_handler *handle, int smp);
+
+/**
+ * iucv_path_alloc
+ * @msglim: initial message limit
+ * @flags: initial flags
+ * @gfp: kmalloc allocation flag
+ *
+ * Allocate a new path structure for use with iucv_connect.
+ *
+ * Returns NULL if the memory allocation failed or a pointer to the
+ * path structure.
+ */
+static inline struct iucv_path *iucv_path_alloc(u16 msglim, u8 flags, gfp_t gfp)
+{
+ struct iucv_path *path;
+
+ path = kzalloc(sizeof(struct iucv_path), gfp);
+ if (path) {
+ path->msglim = msglim;
+ path->flags = flags;
+ }
+ return path;
+}
+
+/**
+ * iucv_path_free
+ * @path: address of iucv path structure
+ *
+ * Frees a path structure.
+ */
+static inline void iucv_path_free(struct iucv_path *path)
+{
+ kfree(path);
+}
+
+/**
+ * iucv_path_accept
+ * @path: address of iucv path structure
+ * @handler: address of iucv handler structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ * @private: private data passed to interrupt handlers for this path
+ *
+ * This function is issued after the user received a connection pending
+ * external interrupt and now wishes to complete the IUCV communication path.
+ *
+ * Returns the result of the CP IUCV call.
+ */
+int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
+ u8 userdata[16], void *private);
+
+/**
+ * iucv_path_connect
+ * @path: address of iucv path structure
+ * @handler: address of iucv handler structure
+ * @userid: 8-byte user identification
+ * @system: 8-byte target system identification
+ * @userdata: 16 bytes of data reflected to the communication partner
+ * @private: private data passed to interrupt handlers for this path
+ *
+ * This function establishes an IUCV path. Although the connect may complete
+ * successfully, you are not able to use the path until you receive an IUCV
+ * Connection Complete external interrupt.
+ *
+ * Returns the result of the CP IUCV call.
+ */
+int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
+ u8 userid[8], u8 system[8], u8 userdata[16],
+ void *private);
+
+/**
+ * iucv_path_quiesce:
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function temporarily suspends incoming messages on an IUCV path.
+ * You can later reactivate the path by invoking the iucv_resume function.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]);
+
+/**
+ * iucv_path_resume:
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function resumes incoming messages on an IUCV path that has
+ * been stopped with iucv_path_quiesce.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_resume(struct iucv_path *path, u8 userdata[16]);
+
+/**
+ * iucv_path_sever
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function terminates an IUCV path.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_sever(struct iucv_path *path, u8 userdata[16]);
+
+/**
+ * iucv_message_purge
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @srccls: source class of message
+ *
+ * Cancels a message you have sent.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
+ u32 srccls);
+
+/**
+ * iucv_message_receive
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: flags that affect how the message is received (IUCV_IPBUFLST)
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of data buffer
+ * @residual:
+ *
+ * This function receives messages that are being sent to you over
+ * established paths. This function will deal with RMDATA messages
+ * embedded in struct iucv_message as well.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, void *buffer, size_t size, size_t *residual);
+
+/**
+ * iucv_message_reject
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ *
+ * The reject function refuses a specified message. Between the time you
+ * are notified of a message and the time that you complete the message,
+ * the message may be rejected.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg);
+
+/**
+ * iucv_message_reply
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the reply is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
+ * @reply: address of data buffer or address of struct iucv_array
+ * @size: length of reply data buffer
+ *
+ * This function responds to the two-way messages that you receive. You
+ * must identify completely the message to which you wish to reply. ie,
+ * pathid, msgid, and trgcls. Prmmsg signifies the data is moved into
+ * the parameter list.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, void *reply, size_t size);
+
+/**
+ * iucv_message_send
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
+ * @srccls: source class of message
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of send buffer
+ *
+ * This function transmits data to another application. Data to be
+ * transmitted is in a buffer and this is a one-way message and the
+ * receiver will not reply to the message.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, u32 srccls, void *buffer, size_t size);
+
+/**
+ * iucv_message_send2way
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is sent and the reply is received
+ * (IUCV_IPRMDATA, IUCV_IPBUFLST, IUCV_IPPRTY, IUCV_ANSLST)
+ * @srccls: source class of message
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of send buffer
+ * @ansbuf: address of answer buffer or address of struct iucv_array
+ * @asize: size of reply buffer
+ *
+ * This function transmits data to another application. Data to be
+ * transmitted is in a buffer. The receiver of the send is expected to
+ * reply to the message and a buffer is provided into which IUCV moves
+ * the reply to this message.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, u32 srccls, void *buffer, size_t size,
+ void *answer, size_t asize, size_t *residual);
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 23967031ddb..3725b93c52f 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -309,6 +309,24 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
return 0;
}
+static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
+{
+ unsigned seq;
+ int hh_len;
+
+ do {
+ int hh_alen;
+
+ seq = read_seqbegin(&hh->hh_lock);
+ hh_len = hh->hh_len;
+ hh_alen = HH_DATA_ALIGN(hh_len);
+ memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
+ } while (read_seqretry(&hh->hh_lock, seq));
+
+ skb_push(skb, hh_len);
+ return hh->hh_output(skb);
+}
+
static inline struct neighbour *
__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat)
{
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index bd01b4633ee..68ec27490c2 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -45,6 +45,7 @@ union nf_conntrack_expect_proto {
#include <linux/netfilter/nf_conntrack_ftp.h>
#include <linux/netfilter/nf_conntrack_pptp.h>
#include <linux/netfilter/nf_conntrack_h323.h>
+#include <linux/netfilter/nf_conntrack_sane.h>
/* per conntrack: application helper private data */
union nf_conntrack_help {
@@ -52,6 +53,7 @@ union nf_conntrack_help {
struct nf_ct_ftp_master ct_ftp_info;
struct nf_ct_pptp_master ct_pptp_info;
struct nf_ct_h323_master ct_h323_info;
+ struct nf_ct_sane_master ct_sane_info;
};
#include <linux/types.h>
diff --git a/include/net/netfilter/nf_conntrack_compat.h b/include/net/netfilter/nf_conntrack_compat.h
index f1b1482d720..6f84c1f7fcd 100644
--- a/include/net/netfilter/nf_conntrack_compat.h
+++ b/include/net/netfilter/nf_conntrack_compat.h
@@ -6,6 +6,7 @@
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/socket.h>
#ifdef CONFIG_IP_NF_CONNTRACK_MARK
static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb,
@@ -64,6 +65,16 @@ static inline int nf_ct_get_ctinfo(const struct sk_buff *skb,
return (ct != NULL);
}
+static inline int nf_ct_l3proto_try_module_get(unsigned short l3proto)
+{
+ need_conntrack();
+ return l3proto == PF_INET ? 0 : -1;
+}
+
+static inline void nf_ct_l3proto_module_put(unsigned short l3proto)
+{
+}
+
#else /* CONFIG_IP_NF_CONNTRACK */
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h
index 61c62068ca6..bc57dd7b9b5 100644
--- a/include/net/netfilter/nf_nat.h
+++ b/include/net/netfilter/nf_nat.h
@@ -16,6 +16,7 @@ enum nf_nat_manip_type
#define IP_NAT_RANGE_MAP_IPS 1
#define IP_NAT_RANGE_PROTO_SPECIFIED 2
+#define IP_NAT_RANGE_PROTO_RANDOM 4
/* NAT sequence number modifications */
struct nf_nat_seq {
diff --git a/include/net/rose.h b/include/net/rose.h
index 012b09ed240..4c05a88b921 100644
--- a/include/net/rose.h
+++ b/include/net/rose.h
@@ -188,13 +188,13 @@ extern void rose_kick(struct sock *);
extern void rose_enquiry_response(struct sock *);
/* rose_route.c */
-extern struct rose_neigh *rose_loopback_neigh;
+extern struct rose_neigh rose_loopback_neigh;
extern struct file_operations rose_neigh_fops;
extern struct file_operations rose_nodes_fops;
extern struct file_operations rose_routes_fops;
-extern int rose_add_loopback_neigh(void);
-extern int rose_add_loopback_node(rose_address *);
+extern void rose_add_loopback_neigh(void);
+extern int __must_check rose_add_loopback_node(rose_address *);
extern void rose_del_loopback_node(rose_address *);
extern void rose_rt_device_down(struct net_device *);
extern void rose_link_device_down(struct net_device *);
diff --git a/include/net/route.h b/include/net/route.h
index 486e37aff06..1440bdb5a27 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -146,7 +146,8 @@ static inline char rt_tos2priority(u8 tos)
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)
+ __be16 sport, __be16 dport, struct sock *sk,
+ int flags)
{
struct flowi fl = { .oif = oif,
.nl_u = { .ip4_u = { .daddr = dst,
@@ -168,7 +169,7 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
*rp = NULL;
}
security_sk_classify_flow(sk, &fl);
- return ip_route_output_flow(rp, &fl, sk, 0);
+ return ip_route_output_flow(rp, &fl, sk, flags);
}
static inline int ip_route_newports(struct rtable **rp, u8 protocol,
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 215461f18db..28af6805952 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -128,8 +128,6 @@ extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
int flags);
extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
-int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
- void *ptr);
/*
* sctp/socket.c
@@ -368,7 +366,7 @@ static inline void sctp_sysctl_register(void) { return; }
static inline void sctp_sysctl_unregister(void) { return; }
static inline int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context) {
+ void __user *newval, size_t newlen) {
return -ENOSYS;
}
#endif
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
index 3269ed1cc22..73cb9943c8a 100644
--- a/include/net/sctp/sm.h
+++ b/include/net/sctp/sm.h
@@ -134,6 +134,7 @@ sctp_state_fn_t sctp_sf_violation;
sctp_state_fn_t sctp_sf_discard_chunk;
sctp_state_fn_t sctp_sf_do_5_2_1_siminit;
sctp_state_fn_t sctp_sf_do_5_2_2_dupinit;
+sctp_state_fn_t sctp_sf_do_5_2_3_initack;
sctp_state_fn_t sctp_sf_do_5_2_4_dupcook;
sctp_state_fn_t sctp_sf_unk_chunk;
sctp_state_fn_t sctp_sf_do_8_5_1_E_sa;
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index c089f93ba59..31a8e88f1a7 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -201,13 +201,12 @@ extern struct sctp_globals {
struct sctp_bind_hashbucket *port_hashtable;
/* This is the global local address list.
- * We actively maintain this complete list of interfaces on
- * the system by catching routing events.
+ * We actively maintain this complete list of addresses on
+ * the system by catching address add/delete events.
*
* It is a list of sctp_sockaddr_entry.
*/
struct list_head local_addr_list;
- spinlock_t local_addr_lock;
/* Flag to indicate if addip is enabled. */
int addip_enable;
@@ -243,7 +242,6 @@ extern struct sctp_globals {
#define sctp_port_alloc_lock (sctp_globals.port_alloc_lock)
#define sctp_port_hashtable (sctp_globals.port_hashtable)
#define sctp_local_addr_list (sctp_globals.local_addr_list)
-#define sctp_local_addr_lock (sctp_globals.local_addr_lock)
#define sctp_addip_enable (sctp_globals.addip_enable)
#define sctp_prsctp_enable (sctp_globals.prsctp_enable)
@@ -277,6 +275,7 @@ struct sctp_sock {
__u16 default_flags;
__u32 default_context;
__u32 default_timetolive;
+ __u32 default_rcv_context;
/* Heartbeat interval: The endpoint sends out a Heartbeat chunk to
* the destination address every heartbeat interval. This value
@@ -307,7 +306,7 @@ struct sctp_sock {
__u8 disable_fragments;
__u8 pd_mode;
__u8 v4mapped;
- __u32 adaption_ind;
+ __u32 adaptation_ind;
/* Receive to here while partial delivery is in effect. */
struct sk_buff_head pd_lobby;
@@ -389,7 +388,7 @@ struct sctp_cookie {
/* Padding for future use */
__u8 padding;
- __u32 adaption_ind;
+ __u32 adaptation_ind;
/* This is a shim for my peer's INIT packet, followed by
@@ -432,7 +431,7 @@ union sctp_params {
struct sctp_ipv4addr_param *v4;
struct sctp_ipv6addr_param *v6;
union sctp_addr_param *addr;
- struct sctp_adaption_ind_param *aind;
+ struct sctp_adaptation_ind_param *aind;
};
/* RFC 2960. Section 3.3.5 Heartbeat.
@@ -1484,7 +1483,7 @@ struct sctp_association {
__u8 asconf_capable; /* Does peer support ADDIP? */
__u8 prsctp_capable; /* Can peer do PR-SCTP? */
- __u32 adaption_ind; /* Adaption Code point. */
+ __u32 adaptation_ind; /* Adaptation Code point. */
/* This mask is used to disable sending the ASCONF chunk
* with specified parameter to peer.
@@ -1659,6 +1658,9 @@ struct sctp_association {
__u32 default_context;
__u32 default_timetolive;
+ /* Default receive parameters */
+ __u32 default_rcv_context;
+
/* This tracks outbound ssn for a given stream. */
struct sctp_ssnmap *ssnmap;
diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h
index 1a4ddc1ec7d..2923e3d31a0 100644
--- a/include/net/sctp/ulpevent.h
+++ b/include/net/sctp/ulpevent.h
@@ -120,7 +120,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
const struct sctp_association *asoc,
__u32 indication, gfp_t gfp);
-struct sctp_ulpevent *sctp_ulpevent_make_adaption_indication(
+struct sctp_ulpevent *sctp_ulpevent_make_adaptation_indication(
const struct sctp_association *asoc, gfp_t gfp);
struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
index 1b7aae6cdd8..67a30eb2b3a 100644
--- a/include/net/sctp/user.h
+++ b/include/net/sctp/user.h
@@ -75,8 +75,8 @@ enum sctp_optname {
#define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR
SCTP_PRIMARY_ADDR,
#define SCTP_PRIMARY_ADDR SCTP_PRIMARY_ADDR
- SCTP_ADAPTION_LAYER,
-#define SCTP_ADAPTION_LAYER SCTP_ADAPTION_LAYER
+ SCTP_ADAPTATION_LAYER,
+#define SCTP_ADAPTATION_LAYER SCTP_ADAPTATION_LAYER
SCTP_DISABLE_FRAGMENTS,
#define SCTP_DISABLE_FRAGMENTS SCTP_DISABLE_FRAGMENTS
SCTP_PEER_ADDR_PARAMS,
@@ -95,6 +95,8 @@ enum sctp_optname {
#define SCTP_GET_PEER_ADDR_INFO SCTP_GET_PEER_ADDR_INFO
SCTP_DELAYED_ACK_TIME,
#define SCTP_DELAYED_ACK_TIME SCTP_DELAYED_ACK_TIME
+ SCTP_CONTEXT, /* Receive Context */
+#define SCTP_CONTEXT SCTP_CONTEXT
/* Internal Socket Options. Some of the sctp library functions are
* implemented using these socket options.
@@ -329,17 +331,17 @@ struct sctp_shutdown_event {
};
/*
- * 5.3.1.6 SCTP_ADAPTION_INDICATION
+ * 5.3.1.6 SCTP_ADAPTATION_INDICATION
*
- * When a peer sends a Adaption Layer Indication parameter , SCTP
+ * When a peer sends a Adaptation Layer Indication parameter , SCTP
* delivers this notification to inform the application
- * that of the peers requested adaption layer.
+ * that of the peers requested adaptation layer.
*/
-struct sctp_adaption_event {
+struct sctp_adaptation_event {
__u16 sai_type;
__u16 sai_flags;
__u32 sai_length;
- __u32 sai_adaption_ind;
+ __u32 sai_adaptation_ind;
sctp_assoc_t sai_assoc_id;
};
@@ -372,7 +374,7 @@ struct sctp_event_subscribe {
__u8 sctp_peer_error_event;
__u8 sctp_shutdown_event;
__u8 sctp_partial_delivery_event;
- __u8 sctp_adaption_layer_event;
+ __u8 sctp_adaptation_layer_event;
};
/*
@@ -393,7 +395,7 @@ union sctp_notification {
struct sctp_remote_error sn_remote_error;
struct sctp_send_failed sn_send_failed;
struct sctp_shutdown_event sn_shutdown_event;
- struct sctp_adaption_event sn_adaption_event;
+ struct sctp_adaptation_event sn_adaptation_event;
struct sctp_pdapi_event sn_pdapi_event;
};
@@ -410,7 +412,7 @@ enum sctp_sn_type {
SCTP_REMOTE_ERROR,
SCTP_SHUTDOWN_EVENT,
SCTP_PARTIAL_DELIVERY_EVENT,
- SCTP_ADAPTION_INDICATION,
+ SCTP_ADAPTATION_INDICATION,
};
/* Notification error codes used to fill up the error fields in some
@@ -486,13 +488,13 @@ struct sctp_prim {
} __attribute__((packed, aligned(4)));
/*
- * 7.1.11 Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER)
+ * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER)
*
- * Requests that the local endpoint set the specified Adaption Layer
+ * Requests that the local endpoint set the specified Adaptation Layer
* Indication parameter for all future INIT and INIT-ACK exchanges.
*/
-struct sctp_setadaption {
- __u32 ssb_adaption_ind;
+struct sctp_setadaptation {
+ __u32 ssb_adaptation_ind;
};
/*
diff --git a/include/net/tcp.h b/include/net/tcp.h
index c99774f15eb..5c472f255b7 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -244,12 +244,7 @@ static inline int before(__u32 seq1, __u32 seq2)
{
return (__s32)(seq1-seq2) < 0;
}
-
-static inline int after(__u32 seq1, __u32 seq2)
-{
- return (__s32)(seq2-seq1) < 0;
-}
-
+#define after(seq2, seq1) before(seq1, seq2)
/* is s2<=s1<=s3 ? */
static inline int between(__u32 seq1, __u32 seq2, __u32 seq3)
@@ -807,9 +802,8 @@ static inline void tcp_update_wl(struct tcp_sock *tp, u32 ack, u32 seq)
/*
* Calculate(/check) TCP checksum
*/
-static inline __sum16 tcp_v4_check(struct tcphdr *th, int len,
- __be32 saddr, __be32 daddr,
- __wsum base)
+static inline __sum16 tcp_v4_check(int len, __be32 saddr,
+ __be32 daddr, __wsum base)
{
return csum_tcpudp_magic(saddr,daddr,len,IPPROTO_TCP,base);
}
diff --git a/include/net/x25.h b/include/net/x25.h
index 0ad90ebcf86..fc3f03d976f 100644
--- a/include/net/x25.h
+++ b/include/net/x25.h
@@ -161,6 +161,14 @@ struct x25_sock {
unsigned long vc_facil_mask; /* inc_call facilities mask */
};
+struct x25_forward {
+ struct list_head node;
+ unsigned int lci;
+ struct net_device *dev1;
+ struct net_device *dev2;
+ atomic_t refcnt;
+};
+
static inline struct x25_sock *x25_sk(const struct sock *sk)
{
return (struct x25_sock *)sk;
@@ -172,6 +180,7 @@ extern int sysctl_x25_call_request_timeout;
extern int sysctl_x25_reset_request_timeout;
extern int sysctl_x25_clear_request_timeout;
extern int sysctl_x25_ack_holdback_timeout;
+extern int sysctl_x25_forward;
extern int x25_addr_ntoa(unsigned char *, struct x25_address *,
struct x25_address *);
@@ -198,6 +207,13 @@ extern int x25_negotiate_facilities(struct sk_buff *, struct sock *,
struct x25_dte_facilities *);
extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);
+/* x25_forward.c */
+extern void x25_clear_forward_by_lci(unsigned int lci);
+extern void x25_clear_forward_by_dev(struct net_device *);
+extern int x25_forward_data(int, struct x25_neigh *, struct sk_buff *);
+extern int x25_forward_call(struct x25_address *, struct x25_neigh *,
+ struct sk_buff *, int);
+
/* x25_in.c */
extern int x25_process_rx_frame(struct sock *, struct sk_buff *);
extern int x25_backlog_rcv(struct sock *, struct sk_buff *);
@@ -259,6 +275,7 @@ extern int x25_decode(struct sock *, struct sk_buff *, int *, int *, int *, int
extern void x25_disconnect(struct sock *, int, unsigned char, unsigned char);
/* x25_timer.c */
+extern void x25_init_timers(struct sock *sk);
extern void x25_start_heartbeat(struct sock *);
extern void x25_start_t2timer(struct sock *);
extern void x25_start_t21timer(struct sock *);
@@ -281,6 +298,8 @@ extern struct hlist_head x25_list;
extern rwlock_t x25_list_lock;
extern struct list_head x25_route_list;
extern rwlock_t x25_route_list_lock;
+extern struct list_head x25_forward_list;
+extern rwlock_t x25_forward_list_lock;
extern int x25_proc_init(void);
extern void x25_proc_exit(void);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index e4765413cf8..16924cb772c 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -252,10 +252,13 @@ struct xfrm_state_afinfo {
xfrm_address_t *daddr, xfrm_address_t *saddr);
int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n);
int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n);
+ int (*output)(struct sk_buff *skb);
};
extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo);
extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo);
+extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
+extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
extern void xfrm_state_delete_tunnel(struct xfrm_state *x);
@@ -359,6 +362,19 @@ struct xfrm_policy
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
};
+struct xfrm_migrate {
+ xfrm_address_t old_daddr;
+ xfrm_address_t old_saddr;
+ xfrm_address_t new_daddr;
+ xfrm_address_t new_saddr;
+ u8 proto;
+ u8 mode;
+ u16 reserved;
+ u32 reqid;
+ u16 old_family;
+ u16 new_family;
+};
+
#define XFRM_KM_TIMEOUT 30
/* which seqno */
#define XFRM_REPLAY_SEQ 1
@@ -385,6 +401,7 @@ struct xfrm_mgr
int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
int (*report)(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
+ int (*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles);
};
extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -985,6 +1002,16 @@ 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);
+#ifdef CONFIG_XFRM_MIGRATE
+extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+ struct xfrm_migrate *m, int num_bundles);
+extern struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m);
+extern struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
+ struct xfrm_migrate *m);
+extern int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+ struct xfrm_migrate *m, int num_bundles);
+#endif
+
extern wait_queue_head_t km_waitq;
extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid);
@@ -1050,5 +1077,25 @@ static inline void xfrm_aevent_doreplay(struct xfrm_state *x)
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
}
+#ifdef CONFIG_XFRM_MIGRATE
+static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig)
+{
+ return (struct xfrm_algo *)kmemdup(orig, sizeof(*orig) + orig->alg_key_len, GFP_KERNEL);
+}
+
+static inline void xfrm_states_put(struct xfrm_state **states, int n)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ xfrm_state_put(*(states + i));
+}
+
+static inline void xfrm_states_delete(struct xfrm_state **states, int n)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ xfrm_state_delete(*(states + i));
+}
+#endif
#endif /* _NET_XFRM_H */
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index 623a0fc0dae..6e84258b94d 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -284,7 +284,7 @@ struct pcmcia_socket {
#endif
/* socket device */
- struct class_device dev;
+ struct device dev;
void *driver_data; /* data internal to the socket driver */
};
diff --git a/include/rdma/ib_marshall.h b/include/rdma/ib_marshall.h
index 66bf4d7d0df..db037205c9e 100644
--- a/include/rdma/ib_marshall.h
+++ b/include/rdma/ib_marshall.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Intel Corporation. All rights reserved.
+ * Copyright (c) 2005-2006 Intel Corporation. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -41,6 +41,9 @@
void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
struct ib_qp_attr *src);
+void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst,
+ struct ib_ah_attr *src);
+
void ib_copy_path_rec_to_user(struct ib_user_path_rec *dst,
struct ib_sa_path_rec *src);
diff --git a/include/rdma/ib_user_mad.h b/include/rdma/ib_user_mad.h
index 44537aa32e6..d66b15ea82c 100644
--- a/include/rdma/ib_user_mad.h
+++ b/include/rdma/ib_user_mad.h
@@ -98,7 +98,7 @@ struct ib_user_mad_hdr {
*/
struct ib_user_mad {
struct ib_user_mad_hdr hdr;
- __u8 data[0];
+ __u64 data[0];
};
/**
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 8eacc351099..765589f4d16 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -43,6 +43,9 @@
#include <linux/types.h>
#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/kref.h>
#include <asm/atomic.h>
#include <asm/scatterlist.h>
@@ -417,8 +420,8 @@ struct ib_wc {
enum ib_wc_opcode opcode;
u32 vendor_err;
u32 byte_len;
+ struct ib_qp *qp;
__be32 imm_data;
- u32 qp_num;
u32 src_qp;
int wc_flags;
u16 pkey_index;
@@ -848,6 +851,49 @@ struct ib_cache {
u8 *lmc_cache;
};
+struct ib_dma_mapping_ops {
+ int (*mapping_error)(struct ib_device *dev,
+ u64 dma_addr);
+ u64 (*map_single)(struct ib_device *dev,
+ void *ptr, size_t size,
+ enum dma_data_direction direction);
+ void (*unmap_single)(struct ib_device *dev,
+ u64 addr, size_t size,
+ enum dma_data_direction direction);
+ u64 (*map_page)(struct ib_device *dev,
+ struct page *page, unsigned long offset,
+ size_t size,
+ enum dma_data_direction direction);
+ void (*unmap_page)(struct ib_device *dev,
+ u64 addr, size_t size,
+ enum dma_data_direction direction);
+ int (*map_sg)(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction);
+ void (*unmap_sg)(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction);
+ u64 (*dma_address)(struct ib_device *dev,
+ struct scatterlist *sg);
+ unsigned int (*dma_len)(struct ib_device *dev,
+ struct scatterlist *sg);
+ void (*sync_single_for_cpu)(struct ib_device *dev,
+ u64 dma_handle,
+ size_t size,
+ enum dma_data_direction dir);
+ void (*sync_single_for_device)(struct ib_device *dev,
+ u64 dma_handle,
+ size_t size,
+ enum dma_data_direction dir);
+ void *(*alloc_coherent)(struct ib_device *dev,
+ size_t size,
+ u64 *dma_handle,
+ gfp_t flag);
+ void (*free_coherent)(struct ib_device *dev,
+ size_t size, void *cpu_addr,
+ u64 dma_handle);
+};
+
struct iw_cm_verbs;
struct ib_device {
@@ -992,6 +1038,8 @@ struct ib_device {
struct ib_mad *in_mad,
struct ib_mad *out_mad);
+ struct ib_dma_mapping_ops *dma_ops;
+
struct module *owner;
struct class_device class_dev;
struct kobject ports_parent;
@@ -1395,10 +1443,231 @@ static inline int ib_req_ncomp_notif(struct ib_cq *cq, int wc_cnt)
* usable for DMA.
* @pd: The protection domain associated with the memory region.
* @mr_access_flags: Specifies the memory access rights.
+ *
+ * Note that the ib_dma_*() functions defined below must be used
+ * to create/destroy addresses used with the Lkey or Rkey returned
+ * by ib_get_dma_mr().
*/
struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags);
/**
+ * ib_dma_mapping_error - check a DMA addr for error
+ * @dev: The device for which the dma_addr was created
+ * @dma_addr: The DMA address to check
+ */
+static inline int ib_dma_mapping_error(struct ib_device *dev, u64 dma_addr)
+{
+ if (dev->dma_ops)
+ return dev->dma_ops->mapping_error(dev, dma_addr);
+ return dma_mapping_error(dma_addr);
+}
+
+/**
+ * ib_dma_map_single - Map a kernel virtual address to DMA address
+ * @dev: The device for which the dma_addr is to be created
+ * @cpu_addr: The kernel virtual address
+ * @size: The size of the region in bytes
+ * @direction: The direction of the DMA
+ */
+static inline u64 ib_dma_map_single(struct ib_device *dev,
+ void *cpu_addr, size_t size,
+ enum dma_data_direction direction)
+{
+ if (dev->dma_ops)
+ return dev->dma_ops->map_single(dev, cpu_addr, size, direction);
+ return dma_map_single(dev->dma_device, cpu_addr, size, direction);
+}
+
+/**
+ * ib_dma_unmap_single - Destroy a mapping created by ib_dma_map_single()
+ * @dev: The device for which the DMA address was created
+ * @addr: The DMA address
+ * @size: The size of the region in bytes
+ * @direction: The direction of the DMA
+ */
+static inline void ib_dma_unmap_single(struct ib_device *dev,
+ u64 addr, size_t size,
+ enum dma_data_direction direction)
+{
+ if (dev->dma_ops)
+ dev->dma_ops->unmap_single(dev, addr, size, direction);
+ else
+ dma_unmap_single(dev->dma_device, addr, size, direction);
+}
+
+/**
+ * ib_dma_map_page - Map a physical page to DMA address
+ * @dev: The device for which the dma_addr is to be created
+ * @page: The page to be mapped
+ * @offset: The offset within the page
+ * @size: The size of the region in bytes
+ * @direction: The direction of the DMA
+ */
+static inline u64 ib_dma_map_page(struct ib_device *dev,
+ struct page *page,
+ unsigned long offset,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ if (dev->dma_ops)
+ return dev->dma_ops->map_page(dev, page, offset, size, direction);
+ return dma_map_page(dev->dma_device, page, offset, size, direction);
+}
+
+/**
+ * ib_dma_unmap_page - Destroy a mapping created by ib_dma_map_page()
+ * @dev: The device for which the DMA address was created
+ * @addr: The DMA address
+ * @size: The size of the region in bytes
+ * @direction: The direction of the DMA
+ */
+static inline void ib_dma_unmap_page(struct ib_device *dev,
+ u64 addr, size_t size,
+ enum dma_data_direction direction)
+{
+ if (dev->dma_ops)
+ dev->dma_ops->unmap_page(dev, addr, size, direction);
+ else
+ dma_unmap_page(dev->dma_device, addr, size, direction);
+}
+
+/**
+ * ib_dma_map_sg - Map a scatter/gather list to DMA addresses
+ * @dev: The device for which the DMA addresses are to be created
+ * @sg: The array of scatter/gather entries
+ * @nents: The number of scatter/gather entries
+ * @direction: The direction of the DMA
+ */
+static inline int ib_dma_map_sg(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ if (dev->dma_ops)
+ return dev->dma_ops->map_sg(dev, sg, nents, direction);
+ return dma_map_sg(dev->dma_device, sg, nents, direction);
+}
+
+/**
+ * ib_dma_unmap_sg - Unmap a scatter/gather list of DMA addresses
+ * @dev: The device for which the DMA addresses were created
+ * @sg: The array of scatter/gather entries
+ * @nents: The number of scatter/gather entries
+ * @direction: The direction of the DMA
+ */
+static inline void ib_dma_unmap_sg(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ if (dev->dma_ops)
+ dev->dma_ops->unmap_sg(dev, sg, nents, direction);
+ else
+ dma_unmap_sg(dev->dma_device, sg, nents, direction);
+}
+
+/**
+ * ib_sg_dma_address - Return the DMA address from a scatter/gather entry
+ * @dev: The device for which the DMA addresses were created
+ * @sg: The scatter/gather entry
+ */
+static inline u64 ib_sg_dma_address(struct ib_device *dev,
+ struct scatterlist *sg)
+{
+ if (dev->dma_ops)
+ return dev->dma_ops->dma_address(dev, sg);
+ return sg_dma_address(sg);
+}
+
+/**
+ * ib_sg_dma_len - Return the DMA length from a scatter/gather entry
+ * @dev: The device for which the DMA addresses were created
+ * @sg: The scatter/gather entry
+ */
+static inline unsigned int ib_sg_dma_len(struct ib_device *dev,
+ struct scatterlist *sg)
+{
+ if (dev->dma_ops)
+ return dev->dma_ops->dma_len(dev, sg);
+ return sg_dma_len(sg);
+}
+
+/**
+ * ib_dma_sync_single_for_cpu - Prepare DMA region to be accessed by CPU
+ * @dev: The device for which the DMA address was created
+ * @addr: The DMA address
+ * @size: The size of the region in bytes
+ * @dir: The direction of the DMA
+ */
+static inline void ib_dma_sync_single_for_cpu(struct ib_device *dev,
+ u64 addr,
+ size_t size,
+ enum dma_data_direction dir)
+{
+ if (dev->dma_ops)
+ dev->dma_ops->sync_single_for_cpu(dev, addr, size, dir);
+ else
+ dma_sync_single_for_cpu(dev->dma_device, addr, size, dir);
+}
+
+/**
+ * ib_dma_sync_single_for_device - Prepare DMA region to be accessed by device
+ * @dev: The device for which the DMA address was created
+ * @addr: The DMA address
+ * @size: The size of the region in bytes
+ * @dir: The direction of the DMA
+ */
+static inline void ib_dma_sync_single_for_device(struct ib_device *dev,
+ u64 addr,
+ size_t size,
+ enum dma_data_direction dir)
+{
+ if (dev->dma_ops)
+ dev->dma_ops->sync_single_for_device(dev, addr, size, dir);
+ else
+ dma_sync_single_for_device(dev->dma_device, addr, size, dir);
+}
+
+/**
+ * ib_dma_alloc_coherent - Allocate memory and map it for DMA
+ * @dev: The device for which the DMA address is requested
+ * @size: The size of the region to allocate in bytes
+ * @dma_handle: A pointer for returning the DMA address of the region
+ * @flag: memory allocator flags
+ */
+static inline void *ib_dma_alloc_coherent(struct ib_device *dev,
+ size_t size,
+ u64 *dma_handle,
+ gfp_t flag)
+{
+ if (dev->dma_ops)
+ return dev->dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+ else {
+ dma_addr_t handle;
+ void *ret;
+
+ ret = dma_alloc_coherent(dev->dma_device, size, &handle, flag);
+ *dma_handle = handle;
+ return ret;
+ }
+}
+
+/**
+ * ib_dma_free_coherent - Free memory allocated by ib_dma_alloc_coherent()
+ * @dev: The device for which the DMA addresses were allocated
+ * @size: The size of the region
+ * @cpu_addr: the address returned by ib_dma_alloc_coherent()
+ * @dma_handle: the DMA address returned by ib_dma_alloc_coherent()
+ */
+static inline void ib_dma_free_coherent(struct ib_device *dev,
+ size_t size, void *cpu_addr,
+ u64 dma_handle)
+{
+ if (dev->dma_ops)
+ dev->dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+ else
+ dma_free_coherent(dev->dma_device, size, cpu_addr, dma_handle);
+}
+
+/**
* ib_reg_phys_mr - Prepares a virtually addressed memory region for use
* by an HCA.
* @pd: The protection domain associated assigned to the registered region.
diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h
index deb5a0a4cee..36cd8a8526a 100644
--- a/include/rdma/rdma_cm.h
+++ b/include/rdma/rdma_cm.h
@@ -77,11 +77,34 @@ struct rdma_route {
int num_paths;
};
+struct rdma_conn_param {
+ const void *private_data;
+ u8 private_data_len;
+ u8 responder_resources;
+ u8 initiator_depth;
+ u8 flow_control;
+ u8 retry_count; /* ignored when accepting */
+ u8 rnr_retry_count;
+ /* Fields below ignored if a QP is created on the rdma_cm_id. */
+ u8 srq;
+ u32 qp_num;
+};
+
+struct rdma_ud_param {
+ const void *private_data;
+ u8 private_data_len;
+ struct ib_ah_attr ah_attr;
+ u32 qp_num;
+ u32 qkey;
+};
+
struct rdma_cm_event {
enum rdma_cm_event_type event;
int status;
- void *private_data;
- u8 private_data_len;
+ union {
+ struct rdma_conn_param conn;
+ struct rdma_ud_param ud;
+ } param;
};
struct rdma_cm_id;
@@ -204,25 +227,17 @@ void rdma_destroy_qp(struct rdma_cm_id *id);
int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
int *qp_attr_mask);
-struct rdma_conn_param {
- const void *private_data;
- u8 private_data_len;
- u8 responder_resources;
- u8 initiator_depth;
- u8 flow_control;
- u8 retry_count; /* ignored when accepting */
- u8 rnr_retry_count;
- /* Fields below ignored if a QP is created on the rdma_cm_id. */
- u8 srq;
- u32 qp_num;
- enum ib_qp_type qp_type;
-};
-
/**
* rdma_connect - Initiate an active connection request.
+ * @id: Connection identifier to connect.
+ * @conn_param: Connection information used for connected QPs.
*
* Users must have resolved a route for the rdma_cm_id to connect with
* by having called rdma_resolve_route before calling this routine.
+ *
+ * This call will either connect to a remote QP or obtain remote QP
+ * information for unconnected rdma_cm_id's. The actual operation is
+ * based on the rdma_cm_id's port space.
*/
int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param);
@@ -253,6 +268,21 @@ int rdma_listen(struct rdma_cm_id *id, int backlog);
int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param);
/**
+ * rdma_notify - Notifies the RDMA CM of an asynchronous event that has
+ * occurred on the connection.
+ * @id: Connection identifier to transition to established.
+ * @event: Asynchronous event.
+ *
+ * This routine should be invoked by users to notify the CM of relevant
+ * communication events. Events that should be reported to the CM and
+ * when to report them are:
+ *
+ * IB_EVENT_COMM_EST - Used when a message is received on a connected
+ * QP before an RTU has been received.
+ */
+int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event);
+
+/**
* rdma_reject - Called to reject a connection request or response.
*/
int rdma_reject(struct rdma_cm_id *id, const void *private_data,
diff --git a/include/rdma/rdma_cm_ib.h b/include/rdma/rdma_cm_ib.h
index e8c3af1804d..9b176df1d66 100644
--- a/include/rdma/rdma_cm_ib.h
+++ b/include/rdma/rdma_cm_ib.h
@@ -44,4 +44,7 @@
int rdma_set_ib_paths(struct rdma_cm_id *id,
struct ib_sa_path_rec *path_rec, int num_paths);
+/* Global qkey for UD QPs and multicast groups. */
+#define RDMA_UD_QKEY 0x01234567
+
#endif /* RDMA_CM_IB_H */
diff --git a/include/rdma/rdma_user_cm.h b/include/rdma/rdma_user_cm.h
new file mode 100644
index 00000000000..9572ab8eeac
--- /dev/null
+++ b/include/rdma/rdma_user_cm.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2005-2006 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef RDMA_USER_CM_H
+#define RDMA_USER_CM_H
+
+#include <linux/types.h>
+#include <linux/in6.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_user_sa.h>
+
+#define RDMA_USER_CM_ABI_VERSION 3
+
+#define RDMA_MAX_PRIVATE_DATA 256
+
+enum {
+ RDMA_USER_CM_CMD_CREATE_ID,
+ RDMA_USER_CM_CMD_DESTROY_ID,
+ RDMA_USER_CM_CMD_BIND_ADDR,
+ RDMA_USER_CM_CMD_RESOLVE_ADDR,
+ RDMA_USER_CM_CMD_RESOLVE_ROUTE,
+ RDMA_USER_CM_CMD_QUERY_ROUTE,
+ RDMA_USER_CM_CMD_CONNECT,
+ RDMA_USER_CM_CMD_LISTEN,
+ RDMA_USER_CM_CMD_ACCEPT,
+ RDMA_USER_CM_CMD_REJECT,
+ RDMA_USER_CM_CMD_DISCONNECT,
+ RDMA_USER_CM_CMD_INIT_QP_ATTR,
+ RDMA_USER_CM_CMD_GET_EVENT,
+ RDMA_USER_CM_CMD_GET_OPTION,
+ RDMA_USER_CM_CMD_SET_OPTION,
+ RDMA_USER_CM_CMD_NOTIFY
+};
+
+/*
+ * command ABI structures.
+ */
+struct rdma_ucm_cmd_hdr {
+ __u32 cmd;
+ __u16 in;
+ __u16 out;
+};
+
+struct rdma_ucm_create_id {
+ __u64 uid;
+ __u64 response;
+ __u16 ps;
+ __u8 reserved[6];
+};
+
+struct rdma_ucm_create_id_resp {
+ __u32 id;
+};
+
+struct rdma_ucm_destroy_id {
+ __u64 response;
+ __u32 id;
+ __u32 reserved;
+};
+
+struct rdma_ucm_destroy_id_resp {
+ __u32 events_reported;
+};
+
+struct rdma_ucm_bind_addr {
+ __u64 response;
+ struct sockaddr_in6 addr;
+ __u32 id;
+};
+
+struct rdma_ucm_resolve_addr {
+ struct sockaddr_in6 src_addr;
+ struct sockaddr_in6 dst_addr;
+ __u32 id;
+ __u32 timeout_ms;
+};
+
+struct rdma_ucm_resolve_route {
+ __u32 id;
+ __u32 timeout_ms;
+};
+
+struct rdma_ucm_query_route {
+ __u64 response;
+ __u32 id;
+ __u32 reserved;
+};
+
+struct rdma_ucm_query_route_resp {
+ __u64 node_guid;
+ struct ib_user_path_rec ib_route[2];
+ struct sockaddr_in6 src_addr;
+ struct sockaddr_in6 dst_addr;
+ __u32 num_paths;
+ __u8 port_num;
+ __u8 reserved[3];
+};
+
+struct rdma_ucm_conn_param {
+ __u32 qp_num;
+ __u32 reserved;
+ __u8 private_data[RDMA_MAX_PRIVATE_DATA];
+ __u8 private_data_len;
+ __u8 srq;
+ __u8 responder_resources;
+ __u8 initiator_depth;
+ __u8 flow_control;
+ __u8 retry_count;
+ __u8 rnr_retry_count;
+ __u8 valid;
+};
+
+struct rdma_ucm_ud_param {
+ __u32 qp_num;
+ __u32 qkey;
+ struct ib_uverbs_ah_attr ah_attr;
+ __u8 private_data[RDMA_MAX_PRIVATE_DATA];
+ __u8 private_data_len;
+ __u8 reserved[7];
+};
+
+struct rdma_ucm_connect {
+ struct rdma_ucm_conn_param conn_param;
+ __u32 id;
+ __u32 reserved;
+};
+
+struct rdma_ucm_listen {
+ __u32 id;
+ __u32 backlog;
+};
+
+struct rdma_ucm_accept {
+ __u64 uid;
+ struct rdma_ucm_conn_param conn_param;
+ __u32 id;
+ __u32 reserved;
+};
+
+struct rdma_ucm_reject {
+ __u32 id;
+ __u8 private_data_len;
+ __u8 reserved[3];
+ __u8 private_data[RDMA_MAX_PRIVATE_DATA];
+};
+
+struct rdma_ucm_disconnect {
+ __u32 id;
+};
+
+struct rdma_ucm_init_qp_attr {
+ __u64 response;
+ __u32 id;
+ __u32 qp_state;
+};
+
+struct rdma_ucm_notify {
+ __u32 id;
+ __u32 event;
+};
+
+struct rdma_ucm_get_event {
+ __u64 response;
+};
+
+struct rdma_ucm_event_resp {
+ __u64 uid;
+ __u32 id;
+ __u32 event;
+ __u32 status;
+ union {
+ struct rdma_ucm_conn_param conn;
+ struct rdma_ucm_ud_param ud;
+ } param;
+};
+
+#endif /* RDMA_USER_CM_H */
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index 02f6e4b9e69..4a44278ed76 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -40,6 +40,14 @@
}
#define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;}
+/* initiator tags; opaque for target */
+typedef uint32_t __bitwise__ itt_t;
+/* below makes sense only for initiator that created this tag */
+#define build_itt(itt, id, age) ((__force itt_t)\
+ ((itt) | ((id) << ISCSI_CID_SHIFT) | ((age) << ISCSI_AGE_SHIFT)))
+#define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK)
+#define RESERVED_ITT ((__force itt_t)0xffffffff)
+
/*
* iSCSI Template Message Header
*/
@@ -50,7 +58,7 @@ struct iscsi_hdr {
uint8_t hlength; /* AHSs total length */
uint8_t dlength[3]; /* Data length */
uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag, opaque for target */
__be32 ttt; /* Target Task Tag */
__be32 statsn;
__be32 exp_statsn;
@@ -111,7 +119,7 @@ struct iscsi_cmd {
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be32 data_length;
__be32 cmdsn;
__be32 exp_statsn;
@@ -148,7 +156,7 @@ struct iscsi_cmd_rsp {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd[8];
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be32 rsvd1;
__be32 statsn;
__be32 exp_cmdsn;
@@ -206,7 +214,7 @@ struct iscsi_nopout {
uint8_t rsvd3;
uint8_t dlength[3];
uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be32 ttt; /* Target Transfer Tag */
__be32 cmdsn;
__be32 exp_statsn;
@@ -221,7 +229,7 @@ struct iscsi_nopin {
uint8_t rsvd3;
uint8_t dlength[3];
uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be32 ttt; /* Target Transfer Tag */
__be32 statsn;
__be32 exp_cmdsn;
@@ -237,8 +245,8 @@ struct iscsi_tm {
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
- __be32 rtt; /* Reference Task Tag */
+ itt_t itt; /* Initiator Task Tag */
+ itt_t rtt; /* Reference Task Tag */
__be32 cmdsn;
__be32 exp_statsn;
__be32 refcmdsn;
@@ -267,8 +275,8 @@ struct iscsi_tm_rsp {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd2[8];
- __be32 itt; /* Initiator Task Tag */
- __be32 rtt; /* Reference Task Tag */
+ itt_t itt; /* Initiator Task Tag */
+ itt_t rtt; /* Reference Task Tag */
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
@@ -293,7 +301,7 @@ struct iscsi_r2t_rsp {
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be32 ttt; /* Target Transfer Tag */
__be32 statsn;
__be32 exp_cmdsn;
@@ -311,7 +319,7 @@ struct iscsi_data {
uint8_t rsvd3;
uint8_t dlength[3];
uint8_t lun[8];
- __be32 itt;
+ itt_t itt;
__be32 ttt;
__be32 rsvd4;
__be32 exp_statsn;
@@ -331,7 +339,7 @@ struct iscsi_data_rsp {
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
- __be32 itt;
+ itt_t itt;
__be32 ttt;
__be32 statsn;
__be32 exp_cmdsn;
@@ -355,7 +363,7 @@ struct iscsi_text {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd4[8];
- __be32 itt;
+ itt_t itt;
__be32 ttt;
__be32 cmdsn;
__be32 exp_statsn;
@@ -373,7 +381,7 @@ struct iscsi_text_rsp {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd4[8];
- __be32 itt;
+ itt_t itt;
__be32 ttt;
__be32 statsn;
__be32 exp_cmdsn;
@@ -392,7 +400,7 @@ struct iscsi_login {
uint8_t dlength[3];
uint8_t isid[6]; /* Initiator Session ID */
__be16 tsih; /* Target Session Handle */
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be16 cid;
__be16 rsvd3;
__be32 cmdsn;
@@ -421,7 +429,7 @@ struct iscsi_login_rsp {
uint8_t dlength[3];
uint8_t isid[6]; /* Initiator Session ID */
__be16 tsih; /* Target Session Handle */
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be32 rsvd3;
__be32 statsn;
__be32 exp_cmdsn;
@@ -478,7 +486,7 @@ struct iscsi_logout {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd2[8];
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be16 cid;
uint8_t rsvd3[2];
__be32 cmdsn;
@@ -505,7 +513,7 @@ struct iscsi_logout_rsp {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd3[8];
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be32 rsvd4;
__be32 statsn;
__be32 exp_cmdsn;
@@ -528,7 +536,7 @@ struct iscsi_snack {
uint8_t opcode;
uint8_t flags;
uint8_t rsvd2[14];
- __be32 itt;
+ itt_t itt;
__be32 begrun;
__be32 runlength;
__be32 exp_statsn;
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 33720397a90..246ac23534b 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -375,6 +375,7 @@
#define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */
#define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */
#define AC97_SCAP_EAPD_LED (1<<10) /* EAPD as mute LED */
+#define AC97_SCAP_POWER_SAVE (1<<11) /* capable for aggresive power-saving */
/* ac97->flags */
#define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */
@@ -425,6 +426,7 @@ struct snd_ac97_build_ops {
struct snd_ac97_bus_ops {
void (*reset) (struct snd_ac97 *ac97);
+ void (*warm_reset)(struct snd_ac97 *ac97);
void (*write) (struct snd_ac97 *ac97, unsigned short reg, unsigned short val);
unsigned short (*read) (struct snd_ac97 *ac97, unsigned short reg);
void (*wait) (struct snd_ac97 *ac97);
@@ -501,6 +503,7 @@ struct snd_ac97 {
unsigned short id[3]; // codec IDs (lower 16-bit word)
unsigned short pcmreg[3]; // PCM registers
unsigned short codec_cfg[3]; // CODEC_CFG bits
+ unsigned char swap_mic_linein; // AD1986/AD1986A only
} ad18xx;
unsigned int dev_flags; /* device specific */
} spec;
@@ -510,7 +513,6 @@ struct snd_ac97 {
#ifdef CONFIG_SND_AC97_POWER_SAVE
unsigned int power_up; /* power states */
- struct workqueue_struct *power_workq;
struct delayed_work power_work;
#endif
struct device dev;
diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h
index c8de6f83338..b2c3f00a9b3 100644
--- a/include/sound/ad1848.h
+++ b/include/sound/ad1848.h
@@ -185,7 +185,7 @@ struct ad1848_mix_elem {
int index;
int type;
unsigned long private_value;
- unsigned int *tlv;
+ const unsigned int *tlv;
};
#define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \
diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h
index 2ee061625fd..c149d3b2558 100644
--- a/include/sound/ak4114.h
+++ b/include/sound/ak4114.h
@@ -181,7 +181,6 @@ struct ak4114 {
unsigned long ccrc_errors;
unsigned char rcs0;
unsigned char rcs1;
- struct workqueue_struct *workqueue;
struct delayed_work work;
void *change_callback_private;
void (*change_callback)(struct ak4114 *ak4114, unsigned char c0, unsigned char c1);
@@ -189,7 +188,7 @@ struct ak4114 {
int snd_ak4114_create(struct snd_card *card,
ak4114_read_t *read, ak4114_write_t *write,
- unsigned char pgm[7], unsigned char txcsb[5],
+ const unsigned char pgm[7], const unsigned char txcsb[5],
void *private_data, struct ak4114 **r_ak4114);
void snd_ak4114_reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char mask, unsigned char val);
void snd_ak4114_reinit(struct ak4114 *ak4114);
diff --git a/include/sound/ak4117.h b/include/sound/ak4117.h
index 2b96c32f06f..d650d52e3d2 100644
--- a/include/sound/ak4117.h
+++ b/include/sound/ak4117.h
@@ -178,7 +178,7 @@ struct ak4117 {
};
int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write,
- unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117);
+ const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117);
void snd_ak4117_reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char mask, unsigned char val);
void snd_ak4117_reinit(struct ak4117 *ak4117);
int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *capture_substream);
diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h
index d0deca669b9..aa49dda4f41 100644
--- a/include/sound/ak4xxx-adda.h
+++ b/include/sound/ak4xxx-adda.h
@@ -50,6 +50,8 @@ struct snd_akm4xxx_adc_channel {
char *name; /* capture gain volume label */
char *switch_name; /* capture switch */
unsigned int num_channels;
+ char *selector_name; /* capture source select label */
+ const char **input_names; /* capture source names (NULL terminated) */
};
struct snd_akm4xxx {
@@ -69,8 +71,8 @@ struct snd_akm4xxx {
} type;
/* (array) information of combined codecs */
- struct snd_akm4xxx_dac_channel *dac_info;
- struct snd_akm4xxx_adc_channel *adc_info;
+ const struct snd_akm4xxx_dac_channel *dac_info;
+ const struct snd_akm4xxx_adc_channel *adc_info;
struct snd_ak4xxx_ops ops;
};
diff --git a/include/sound/control.h b/include/sound/control.h
index 1de148b0fd9..72e759f619b 100644
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -49,7 +49,7 @@ struct snd_kcontrol_new {
snd_kcontrol_put_t *put;
union {
snd_kcontrol_tlv_rw_t *c;
- unsigned int *p;
+ const unsigned int *p;
} tlv;
unsigned long private_value;
};
@@ -69,7 +69,7 @@ struct snd_kcontrol {
snd_kcontrol_put_t *put;
union {
snd_kcontrol_tlv_rw_t *c;
- unsigned int *p;
+ const unsigned int *p;
} tlv;
unsigned long private_value;
void *private_data;
@@ -108,7 +108,6 @@ typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card,
void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id);
-struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol * kcontrol, unsigned int access);
struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data);
void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);
diff --git a/include/sound/core.h b/include/sound/core.h
index a994bea09cd..4b9e609975a 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -132,8 +132,10 @@ struct snd_card {
int shutdown; /* this card is going down */
int free_on_last_close; /* free in context of file_release */
wait_queue_head_t shutdown_sleep;
- struct device *parent;
- struct device *dev;
+ struct device *dev; /* device assigned to this card */
+#ifndef CONFIG_SYSFS_DEPRECATED
+ struct device *card_dev; /* cardX object for sysfs */
+#endif
#ifdef CONFIG_PM
unsigned int power_state; /* power state */
@@ -191,6 +193,16 @@ struct snd_minor {
struct device *dev; /* device for sysfs */
};
+/* return a device pointer linked to each sound device as a parent */
+static inline struct device *snd_card_get_device_link(struct snd_card *card)
+{
+#ifdef CONFIG_SYSFS_DEPRECATED
+ return card ? card->dev : NULL;
+#else
+ return card ? card->card_dev : NULL;
+#endif
+}
+
/* sound.c */
extern int snd_major;
@@ -199,9 +211,40 @@ extern struct class *sound_class;
void snd_request_card(int card);
-int snd_register_device(int type, struct snd_card *card, int dev,
- const struct file_operations *f_ops, void *private_data,
- const char *name);
+int snd_register_device_for_dev(int type, struct snd_card *card,
+ int dev,
+ const struct file_operations *f_ops,
+ void *private_data,
+ const char *name,
+ struct device *device);
+
+/**
+ * snd_register_device - Register the ALSA device file for the card
+ * @type: the device type, SNDRV_DEVICE_TYPE_XXX
+ * @card: the card instance
+ * @dev: the device index
+ * @f_ops: the file operations
+ * @private_data: user pointer for f_ops->open()
+ * @name: the device file name
+ *
+ * Registers an ALSA device file for the given card.
+ * The operators have to be set in reg parameter.
+ *
+ * This function uses the card's device pointer to link to the
+ * correct &struct device.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ */
+static inline int snd_register_device(int type, struct snd_card *card, int dev,
+ const struct file_operations *f_ops,
+ void *private_data,
+ const char *name)
+{
+ return snd_register_device_for_dev(type, card, dev, f_ops,
+ private_data, name,
+ snd_card_get_device_link(card));
+}
+
int snd_unregister_device(int type, struct snd_card *card, int dev);
void *snd_lookup_minor_data(unsigned int minor, int type);
int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
@@ -257,7 +300,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file);
int snd_card_file_remove(struct snd_card *card, struct file *file);
#ifndef snd_card_set_dev
-#define snd_card_set_dev(card,devptr) ((card)->parent = (devptr))
+#define snd_card_set_dev(card,devptr) ((card)->dev = (devptr))
#endif
/* device.c */
@@ -384,6 +427,29 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
#endif
#endif
-#include "typedefs.h"
+/* PCI quirk list helper */
+struct snd_pci_quirk {
+ unsigned short subvendor; /* PCI subvendor ID */
+ unsigned short subdevice; /* PCI subdevice ID */
+ int value; /* value */
+#ifdef CONFIG_SND_DEBUG_DETECT
+ const char *name; /* name of the device (optional) */
+#endif
+};
+
+#define _SND_PCI_QUIRK_ID(vend,dev) \
+ .subvendor = (vend), .subdevice = (dev)
+#define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)}
+#ifdef CONFIG_SND_DEBUG_DETECT
+#define SND_PCI_QUIRK(vend,dev,xname,val) \
+ {_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)}
+#else
+#define SND_PCI_QUIRK(vend,dev,xname,val) \
+ {_SND_PCI_QUIRK_ID(vend, dev), .value = (val)}
+#endif
+
+const struct snd_pci_quirk *
+snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list);
+
#endif /* __SOUND_CORE_H */
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 3d3c1514cf7..eb7ce96ddf3 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -188,7 +188,35 @@
#define HCFG_LEGACYINT 0x00200000 /* 1 = legacy event captured. Write 1 to clear. */
/* NOTE: The rest of the bits in this register */
/* _are_ relevant under Linux. */
-#define HCFG_CODECFORMAT_MASK 0x00070000 /* CODEC format */
+#define HCFG_PUSH_BUTTON_ENABLE 0x00100000 /* Enables Volume Inc/Dec and Mute functions */
+#define HCFG_BAUD_RATE 0x00080000 /* 0 = 48kHz, 1 = 44.1kHz */
+#define HCFG_EXPANDED_MEM 0x00040000 /* 1 = any 16M of 4G addr, 0 = 32M of 2G addr */
+#define HCFG_CODECFORMAT_MASK 0x00030000 /* CODEC format */
+
+/* Specific to Alice2, CA0102 */
+#define HCFG_CODECFORMAT_AC97_1 0x00000000 /* AC97 CODEC format -- Ver 1.03 */
+#define HCFG_CODECFORMAT_AC97_2 0x00010000 /* AC97 CODEC format -- Ver 2.1 */
+#define HCFG_AUTOMUTE_ASYNC 0x00008000 /* When set, the async sample rate convertors */
+ /* will automatically mute their output when */
+ /* they are not rate-locked to the external */
+ /* async audio source */
+#define HCFG_AUTOMUTE_SPDIF 0x00004000 /* When set, the async sample rate convertors */
+ /* will automatically mute their output when */
+ /* the SPDIF V-bit indicates invalid audio */
+#define HCFG_EMU32_SLAVE 0x00002000 /* 0 = Master, 1 = Slave. Slave for EMU1010 */
+#define HCFG_SLOW_RAMP 0x00001000 /* Increases Send Smoothing time constant */
+/* 0x00000800 not used on Alice2 */
+#define HCFG_PHASE_TRACK_MASK 0x00000700 /* When set, forces corresponding input to */
+ /* phase track the previous input. */
+ /* I2S0 can phase track the last S/PDIF input */
+#define HCFG_I2S_ASRC_ENABLE 0x00000070 /* When set, enables asynchronous sample rate */
+ /* conversion for the corresponding */
+ /* I2S format input */
+/* Rest of HCFG 0x0000000f same as below. LOCKSOUNDCACHE etc. */
+
+
+
+/* Older chips */
#define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */
#define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */
#define HCFG_GPINPUT0 0x00004000 /* External pin112 */
@@ -432,6 +460,7 @@
#define FXRT_CHANNELC 0x0f000000 /* Effects send bus number for channel's effects send C */
#define FXRT_CHANNELD 0xf0000000 /* Effects send bus number for channel's effects send D */
+#define A_HR 0x0b /* High Resolution. 24bit playback from host to DSP. */
#define MAPA 0x0c /* Cache map A */
#define MAPB 0x0d /* Cache map B */
@@ -439,6 +468,8 @@
#define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */
#define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */
+/* 0x0e, 0x0f: Not used */
+
#define ENVVOL 0x10 /* Volume envelope register */
#define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */
/* 0x8000-n == 666*n usec delay */
@@ -527,7 +558,7 @@
/* NOTE: All channels contain internal variables; do */
/* not write to these locations. */
-/* 1f something */
+/* 0x1f: not used */
#define CD0 0x20 /* Cache data 0 register */
#define CD1 0x21 /* Cache data 1 register */
@@ -597,6 +628,8 @@
#define FXWC_SPDIFLEFT (1<<22) /* 0x00400000 */
#define FXWC_SPDIFRIGHT (1<<23) /* 0x00800000 */
+#define A_TBLSZ ` 0x43 /* Effects Tank Internal Table Size. Only low byte or register used */
+
#define TCBS 0x44 /* Tank cache buffer size register */
#define TCBS_MASK 0x00000007 /* Tank cache buffer size field */
#define TCBS_BUFFSIZE_16K 0x00000000
@@ -617,7 +650,7 @@
#define FXBA 0x47 /* FX Buffer Address */
#define FXBA_MASK 0xfffff000 /* 20 bit base address */
-/* 0x48 something - word access, defaults to 3f */
+#define A_HWM 0x48 /* High PCI Water Mark - word access, defaults to 3f */
#define MICBS 0x49 /* Microphone buffer size register */
@@ -661,6 +694,18 @@
#define ADCBS_BUFSIZE_57344 0x0000001e
#define ADCBS_BUFSIZE_65536 0x0000001f
+/* Current Send B, A Amounts */
+#define A_CSBA 0x4c
+
+/* Current Send D, C Amounts */
+#define A_CSDC 0x4d
+
+/* Current Send F, E Amounts */
+#define A_CSFE 0x4e
+
+/* Current Send H, G Amounts */
+#define A_CSHG 0x4f
+
#define CDCS 0x50 /* CD-ROM digital channel status register */
@@ -668,6 +713,9 @@
#define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
+/* S/PDIF Input C Channel Status */
+#define A_SPSC 0x52
+
#define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
#define A_DBG 0x53
@@ -708,6 +756,8 @@
#define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */
#define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */
+/* 0x57: Not used */
+
/* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */
#define CLIEL 0x58 /* Channel loop interrupt enable low register */
@@ -733,6 +783,9 @@
#define AC97SLOT_CNTR 0x10 /* Center enable */
#define AC97SLOT_LFE 0x20 /* LFE enable */
+/* PCB Revision */
+#define A_PCB 0x5f
+
// NOTE: 0x60,61,62: 64-bit
#define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */
@@ -780,9 +833,18 @@
#define HLIPH 0x69 /* Channel half loop interrupt pending high register */
-// 0x6a,6b,6c used for some recording
-// 0x6d unused
-// 0x6e,6f - tanktable base / offset
+/* S/PDIF Host Record Index (bypasses SRC) */
+#define A_SPRI 0x6a
+/* S/PDIF Host Record Address */
+#define A_SPRA 0x6b
+/* S/PDIF Host Record Control */
+#define A_SPRC 0x6c
+/* Delayed Interrupt Counter & Enable */
+#define A_DICE 0x6d
+/* Tank Table Base */
+#define A_TTB 0x6e
+/* Tank Delay Offset */
+#define A_TDOF 0x6f
/* This is the MPU port on the card (via the game port) */
#define A_MUDATA1 0x70
@@ -800,6 +862,7 @@
#define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */
#define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */
+/* Extended Hardware Control */
#define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */
#define A_SAMPLE_RATE 0x76 /* Various sample rate settings. */
#define A_SAMPLE_RATE_NOT_USED 0x0ffc111e /* Bits that are not used and cannot be set. */
@@ -822,8 +885,20 @@
#define A_PCM_96000 0x00004000
#define A_PCM_44100 0x00008000
-/* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell */
-/* 0x7a, 0x7b - lookup tables */
+/* I2S0 Sample Rate Tracker Status */
+#define A_SRT3 0x77
+
+/* I2S1 Sample Rate Tracker Status */
+#define A_SRT4 0x78
+
+/* I2S2 Sample Rate Tracker Status */
+#define A_SRT5 0x79
+/* - default to 0x01080000 on my audigy 2 ZS --rlrevell */
+
+/* Tank Table DMA Address */
+#define A_TTDA 0x7a
+/* Tank Table DMA Data */
+#define A_TTDD 0x7b
#define A_FXRT2 0x7c
#define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */
@@ -845,7 +920,7 @@
#define A_FXRT_CHANNELC 0x003f0000
#define A_FXRT_CHANNELD 0x3f000000
-
+/* 0x7f: Not used */
/* Each FX general purpose register is 32 bits in length, all bits are used */
#define FXGPREGBASE 0x100 /* FX general purpose registers base */
#define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */
@@ -886,6 +961,293 @@
#define A_HIWORD_RESULT_MASK 0x007ff000
#define A_HIWORD_OPA_MASK 0x000007ff
+/************************************************************************************************/
+/* EMU1010m HANA FPGA registers */
+/************************************************************************************************/
+#define EMU_HANA_DESTHI 0x00 /* 0000xxx 3 bits Link Destination */
+#define EMU_HANA_DESTLO 0x01 /* 00xxxxx 5 bits */
+#define EMU_HANA_SRCHI 0x02 /* 0000xxx 3 bits Link Source */
+#define EMU_HANA_SRCLO 0x03 /* 00xxxxx 5 bits */
+#define EMU_HANA_DOCK_PWR 0x04 /* 000000x 1 bits Audio Dock power */
+#define EMU_HANA_DOCK_PWR_ON 0x01 /* Audio Dock power on */
+#define EMU_HANA_WCLOCK 0x05 /* 0000xxx 3 bits Word Clock source select */
+ /* Must be written after power on to reset DLL */
+ /* One is unable to detect the Audio dock without this */
+#define EMU_HANA_WCLOCK_SRC_MASK 0x07
+#define EMU_HANA_WCLOCK_INT_48K 0x00
+#define EMU_HANA_WCLOCK_INT_44_1K 0x01
+#define EMU_HANA_WCLOCK_HANA_SPDIF_IN 0x02
+#define EMU_HANA_WCLOCK_HANA_ADAT_IN 0x03
+#define EMU_HANA_WCLOCK_SYNC_BNCN 0x04
+#define EMU_HANA_WCLOCK_2ND_HANA 0x05
+#define EMU_HANA_WCLOCK_SRC_RESERVED 0x06
+#define EMU_HANA_WCLOCK_OFF 0x07 /* For testing, forces fallback to DEFCLOCK */
+#define EMU_HANA_WCLOCK_MULT_MASK 0x18
+#define EMU_HANA_WCLOCK_1X 0x00
+#define EMU_HANA_WCLOCK_2X 0x08
+#define EMU_HANA_WCLOCK_4X 0x10
+#define EMU_HANA_WCLOCK_MULT_RESERVED 0x18
+
+#define EMU_HANA_DEFCLOCK 0x06 /* 000000x 1 bits Default Word Clock */
+#define EMU_HANA_DEFCLOCK_48K 0x00
+#define EMU_HANA_DEFCLOCK_44_1K 0x01
+
+#define EMU_HANA_UNMUTE 0x07 /* 000000x 1 bits Mute all audio outputs */
+#define EMU_MUTE 0x00
+#define EMU_UNMUTE 0x01
+
+#define EMU_HANA_FPGA_CONFIG 0x08 /* 00000xx 2 bits Config control of FPGAs */
+#define EMU_HANA_FPGA_CONFIG_AUDIODOCK 0x01 /* Set in order to program FPGA on Audio Dock */
+#define EMU_HANA_FPGA_CONFIG_HANA 0x02 /* Set in order to program FPGA on Hana */
+
+#define EMU_HANA_IRQ_ENABLE 0x09 /* 000xxxx 4 bits IRQ Enable */
+#define EMU_HANA_IRQ_WCLK_CHANGED 0x01
+#define EMU_HANA_IRQ_ADAT 0x02
+#define EMU_HANA_IRQ_DOCK 0x04
+#define EMU_HANA_IRQ_DOCK_LOST 0x08
+
+#define EMU_HANA_SPDIF_MODE 0x0a /* 00xxxxx 5 bits SPDIF MODE */
+#define EMU_HANA_SPDIF_MODE_TX_COMSUMER 0x00
+#define EMU_HANA_SPDIF_MODE_TX_PRO 0x01
+#define EMU_HANA_SPDIF_MODE_TX_NOCOPY 0x02
+#define EMU_HANA_SPDIF_MODE_RX_COMSUMER 0x00
+#define EMU_HANA_SPDIF_MODE_RX_PRO 0x04
+#define EMU_HANA_SPDIF_MODE_RX_NOCOPY 0x08
+#define EMU_HANA_SPDIF_MODE_RX_INVALID 0x10
+
+#define EMU_HANA_OPTICAL_TYPE 0x0b /* 00000xx 2 bits ADAT or SPDIF in/out */
+#define EMU_HANA_OPTICAL_IN_SPDIF 0x00
+#define EMU_HANA_OPTICAL_IN_ADAT 0x01
+#define EMU_HANA_OPTICAL_OUT_SPDIF 0x00
+#define EMU_HANA_OPTICAL_OUT_ADAT 0x02
+
+#define EMU_HANA_MIDI_IN 0x0c /* 000000x 1 bit Control MIDI */
+#define EMU_HANA_MIDI_IN_FROM_HAMOA 0x00 /* HAMOA MIDI in to Alice 2 MIDI B */
+#define EMU_HANA_MIDI_IN_FROM_DOCK 0x01 /* Audio Dock MIDI in to Alice 2 MIDI B */
+
+#define EMU_HANA_DOCK_LEDS_1 0x0d /* 000xxxx 4 bit Audio Dock LEDs */
+#define EMU_HANA_DOCK_LEDS_1_MIDI1 0x01 /* MIDI 1 LED on */
+#define EMU_HANA_DOCK_LEDS_1_MIDI2 0x02 /* MIDI 2 LED on */
+#define EMU_HANA_DOCK_LEDS_1_SMPTE_IN 0x04 /* SMPTE IN LED on */
+#define EMU_HANA_DOCK_LEDS_1_SMPTE_OUT 0x08 /* SMPTE OUT LED on */
+
+#define EMU_HANA_DOCK_LEDS_2 0x0e /* 0xxxxxx 6 bit Audio Dock LEDs */
+#define EMU_HANA_DOCK_LEDS_2_44K 0x01 /* 44.1 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_48K 0x02 /* 48 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_96K 0x04 /* 96 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_192K 0x08 /* 192 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_LOCK 0x10 /* LOCK LED on */
+#define EMU_HANA_DOCK_LEDS_2_EXT 0x20 /* EXT LED on */
+
+#define EMU_HANA_DOCK_LEDS_3 0x0f /* 0xxxxxx 6 bit Audio Dock LEDs */
+#define EMU_HANA_DOCK_LEDS_3_CLIP_A 0x01 /* Mic A Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_CLIP_B 0x02 /* Mic B Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_SIGNAL_A 0x04 /* Signal A Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_SIGNAL_B 0x08 /* Signal B Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_MANUAL_CLIP 0x10 /* Manual Clip detection */
+#define EMU_HANA_DOCK_LEDS_3_MANUAL_SIGNAL 0x20 /* Manual Signal detection */
+
+#define EMU_HANA_ADC_PADS 0x10 /* 0000xxx 3 bit Audio Dock ADC 14dB pads */
+#define EMU_HANA_DOCK_ADC_PAD1 0x01 /* 14dB Attenuation on Audio Dock ADC 1 */
+#define EMU_HANA_DOCK_ADC_PAD2 0x02 /* 14dB Attenuation on Audio Dock ADC 2 */
+#define EMU_HANA_DOCK_ADC_PAD3 0x04 /* 14dB Attenuation on Audio Dock ADC 3 */
+#define EMU_HANA_0202_ADC_PAD1 0x08 /* 14dB Attenuation on 0202 ADC 1 */
+
+#define EMU_HANA_DOCK_MISC 0x11 /* 0xxxxxx 6 bit Audio Dock misc bits */
+#define EMU_HANA_DOCK_DAC1_MUTE 0x01 /* DAC 1 Mute */
+#define EMU_HANA_DOCK_DAC2_MUTE 0x02 /* DAC 2 Mute */
+#define EMU_HANA_DOCK_DAC3_MUTE 0x04 /* DAC 3 Mute */
+#define EMU_HANA_DOCK_DAC4_MUTE 0x08 /* DAC 4 Mute */
+#define EMU_HANA_DOCK_PHONES_192_DAC1 0x00 /* DAC 1 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC2 0x10 /* DAC 2 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC3 0x20 /* DAC 3 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC4 0x30 /* DAC 4 Headphones source at 192kHz */
+
+#define EMU_HANA_MIDI_OUT 0x12 /* 00xxxxx 5 bit Source for each MIDI out port */
+#define EMU_HANA_MIDI_OUT_0202 0x01 /* 0202 MIDI from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_DOCK1 0x02 /* Audio Dock MIDI1 front, from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_DOCK2 0x04 /* Audio Dock MIDI2 rear, from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_SYNC2 0x08 /* Sync card. Not the actual MIDI out jack. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_LOOP 0x10 /* 0 = bits (3:0) normal. 1 = MIDI loopback enabled. */
+
+#define EMU_HANA_DAC_PADS 0x13 /* 00xxxxx 5 bit DAC 14dB attenuation pads */
+#define EMU_HANA_DOCK_DAC_PAD1 0x01 /* 14dB Attenuation on AudioDock DAC 1. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD2 0x02 /* 14dB Attenuation on AudioDock DAC 2. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD3 0x04 /* 14dB Attenuation on AudioDock DAC 3. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD4 0x08 /* 14dB Attenuation on AudioDock DAC 4. Left and Right */
+#define EMU_HANA_0202_DAC_PAD1 0x10 /* 14dB Attenuation on 0202 DAC 1. Left and Right */
+
+/* 0x14 - 0x1f Unused R/W registers */
+#define EMU_HANA_IRQ_STATUS 0x20 /* 000xxxx 4 bits IRQ Status */
+#if 0 /* Already defined for reg 0x09 IRQ_ENABLE */
+#define EMU_HANA_IRQ_WCLK_CHANGED 0x01
+#define EMU_HANA_IRQ_ADAT 0x02
+#define EMU_HANA_IRQ_DOCK 0x04
+#define EMU_HANA_IRQ_DOCK_LOST 0x08
+#endif
+
+#define EMU_HANA_OPTION_CARDS 0x21 /* 000xxxx 4 bits Presence of option cards */
+#define EMU_HANA_OPTION_HAMOA 0x01 /* HAMOA card present */
+#define EMU_HANA_OPTION_SYNC 0x02 /* Sync card present */
+#define EMU_HANA_OPTION_DOCK_ONLINE 0x04 /* Audio Dock online and FPGA configured */
+#define EMU_HANA_OPTION_DOCK_OFFLINE 0x08 /* Audio Dock online and FPGA not configured */
+
+#define EMU_HANA_ID 0x22 /* 1010101 7 bits ID byte & 0x7f = 0x55 */
+
+#define EMU_HANA_MAJOR_REV 0x23 /* 0000xxx 3 bit Hana FPGA Major rev */
+#define EMU_HANA_MINOR_REV 0x24 /* 0000xxx 3 bit Hana FPGA Minor rev */
+
+#define EMU_DOCK_MAJOR_REV 0x25 /* 0000xxx 3 bit Audio Dock FPGA Major rev */
+#define EMU_DOCK_MINOR_REV 0x26 /* 0000xxx 3 bit Audio Dock FPGA Minor rev */
+
+#define EMU_DOCK_BOARD_ID 0x27 /* 00000xx 2 bits Audio Dock ID pins */
+#define EMU_DOCK_BOARD_ID0 0x00 /* ID bit 0 */
+#define EMU_DOCK_BOARD_ID1 0x03 /* ID bit 1 */
+
+#define EMU_HANA_WC_SPDIF_HI 0x28 /* 0xxxxxx 6 bit SPDIF IN Word clock, upper 6 bits */
+#define EMU_HANA_WC_SPDIF_LO 0x29 /* 0xxxxxx 6 bit SPDIF IN Word clock, lower 6 bits */
+
+#define EMU_HANA_WC_ADAT_HI 0x2a /* 0xxxxxx 6 bit ADAT IN Word clock, upper 6 bits */
+#define EMU_HANA_WC_ADAT_LO 0x2b /* 0xxxxxx 6 bit ADAT IN Word clock, lower 6 bits */
+
+#define EMU_HANA_WC_BNC_LO 0x2c /* 0xxxxxx 6 bit BNC IN Word clock, lower 6 bits */
+#define EMU_HANA_WC_BNC_HI 0x2d /* 0xxxxxx 6 bit BNC IN Word clock, upper 6 bits */
+
+#define EMU_HANA2_WC_SPDIF_HI 0x2e /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, upper 6 bits */
+#define EMU_HANA2_WC_SPDIF_LO 0x2f /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, lower 6 bits */
+/* 0x30 - 0x3f Unused Read only registers */
+
+/************************************************************************************************/
+/* EMU1010m HANA Destinations */
+/************************************************************************************************/
+#define EMU_DST_ALICE2_EMU32_0 0x000f /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_1 0x0000 /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_2 0x0001 /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_3 0x0002 /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_4 0x0003 /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_5 0x0004 /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_6 0x0005 /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_7 0x0006 /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_8 0x0007 /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_9 0x0008 /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_A 0x0009 /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_B 0x000a /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_C 0x000b /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_D 0x000c /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_E 0x000d /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_F 0x000e /* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_DOCK_DAC1_LEFT1 0x0100 /* Audio Dock DAC1 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC1_LEFT2 0x0101 /* Audio Dock DAC1 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC1_LEFT3 0x0102 /* Audio Dock DAC1 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC1_LEFT4 0x0103 /* Audio Dock DAC1 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT1 0x0104 /* Audio Dock DAC1 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC1_RIGHT2 0x0105 /* Audio Dock DAC1 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT3 0x0106 /* Audio Dock DAC1 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT4 0x0107 /* Audio Dock DAC1 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC2_LEFT1 0x0108 /* Audio Dock DAC2 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC2_LEFT2 0x0109 /* Audio Dock DAC2 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC2_LEFT3 0x010a /* Audio Dock DAC2 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC2_LEFT4 0x010b /* Audio Dock DAC2 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT1 0x010c /* Audio Dock DAC2 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC2_RIGHT2 0x010d /* Audio Dock DAC2 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT3 0x010e /* Audio Dock DAC2 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT4 0x010f /* Audio Dock DAC2 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC3_LEFT1 0x0110 /* Audio Dock DAC1 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC3_LEFT2 0x0111 /* Audio Dock DAC1 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_LEFT3 0x0112 /* Audio Dock DAC1 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC3_LEFT4 0x0113 /* Audio Dock DAC1 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_PHONES_LEFT1 0x0112 /* Audio Dock PHONES Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_PHONES_LEFT2 0x0113 /* Audio Dock PHONES Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT1 0x0114 /* Audio Dock DAC1 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC3_RIGHT2 0x0115 /* Audio Dock DAC1 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT3 0x0116 /* Audio Dock DAC1 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT4 0x0117 /* Audio Dock DAC1 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_PHONES_RIGHT1 0x0116 /* Audio Dock PHONES Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_PHONES_RIGHT2 0x0117 /* Audio Dock PHONES Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_LEFT1 0x0118 /* Audio Dock DAC2 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC4_LEFT2 0x0119 /* Audio Dock DAC2 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_LEFT3 0x011a /* Audio Dock DAC2 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC4_LEFT4 0x011b /* Audio Dock DAC2 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_SPDIF_LEFT1 0x011a /* Audio Dock SPDIF Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_SPDIF_LEFT2 0x011b /* Audio Dock SPDIF Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT1 0x011c /* Audio Dock DAC2 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC4_RIGHT2 0x011d /* Audio Dock DAC2 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT3 0x011e /* Audio Dock DAC2 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT4 0x011f /* Audio Dock DAC2 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_SPDIF_RIGHT1 0x011e /* Audio Dock SPDIF Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_SPDIF_RIGHT2 0x011f /* Audio Dock SPDIF Right, 2nd or 96kHz */
+#define EMU_DST_HANA_SPDIF_LEFT1 0x0200 /* Hana SPDIF Left, 1st or 48kHz only */
+#define EMU_DST_HANA_SPDIF_LEFT2 0x0202 /* Hana SPDIF Left, 2nd or 96kHz */
+#define EMU_DST_HANA_SPDIF_RIGHT1 0x0201 /* Hana SPDIF Right, 1st or 48kHz only */
+#define EMU_DST_HANA_SPDIF_RIGHT2 0x0203 /* Hana SPDIF Right, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_LEFT1 0x0300 /* Hamoa DAC Left, 1st or 48kHz only */
+#define EMU_DST_HAMOA_DAC_LEFT2 0x0302 /* Hamoa DAC Left, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_LEFT3 0x0304 /* Hamoa DAC Left, 3rd or 192kHz */
+#define EMU_DST_HAMOA_DAC_LEFT4 0x0306 /* Hamoa DAC Left, 4th or 192kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT1 0x0301 /* Hamoa DAC Right, 1st or 48kHz only */
+#define EMU_DST_HAMOA_DAC_RIGHT2 0x0303 /* Hamoa DAC Right, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT3 0x0305 /* Hamoa DAC Right, 3rd or 192kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT4 0x0307 /* Hamoa DAC Right, 4th or 192kHz */
+#define EMU_DST_HANA_ADAT 0x0400 /* Hana ADAT 8 channel out +0 to +7 */
+#define EMU_DST_ALICE_I2S0_LEFT 0x0500 /* Alice2 I2S0 Left */
+#define EMU_DST_ALICE_I2S0_RIGHT 0x0501 /* Alice2 I2S0 Right */
+#define EMU_DST_ALICE_I2S1_LEFT 0x0600 /* Alice2 I2S1 Left */
+#define EMU_DST_ALICE_I2S1_RIGHT 0x0601 /* Alice2 I2S1 Right */
+#define EMU_DST_ALICE_I2S2_LEFT 0x0700 /* Alice2 I2S2 Left */
+#define EMU_DST_ALICE_I2S2_RIGHT 0x0701 /* Alice2 I2S2 Right */
+
+/************************************************************************************************/
+/* EMU1010m HANA Sources */
+/************************************************************************************************/
+#define EMU_SRC_SILENCE 0x0000 /* Silence */
+#define EMU_SRC_DOCK_MIC_A1 0x0100 /* Audio Dock Mic A, 1st or 48kHz only */
+#define EMU_SRC_DOCK_MIC_A2 0x0101 /* Audio Dock Mic A, 2nd or 96kHz */
+#define EMU_SRC_DOCK_MIC_A3 0x0102 /* Audio Dock Mic A, 3rd or 192kHz */
+#define EMU_SRC_DOCK_MIC_A4 0x0103 /* Audio Dock Mic A, 4th or 192kHz */
+#define EMU_SRC_DOCK_MIC_B1 0x0104 /* Audio Dock Mic B, 1st or 48kHz only */
+#define EMU_SRC_DOCK_MIC_B2 0x0105 /* Audio Dock Mic B, 2nd or 96kHz */
+#define EMU_SRC_DOCK_MIC_B3 0x0106 /* Audio Dock Mic B, 3rd or 192kHz */
+#define EMU_SRC_DOCK_MIC_B4 0x0107 /* Audio Dock Mic B, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT1 0x0108 /* Audio Dock ADC1 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC1_LEFT2 0x0109 /* Audio Dock ADC1 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT3 0x010a /* Audio Dock ADC1 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT4 0x010b /* Audio Dock ADC1 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT1 0x010c /* Audio Dock ADC1 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC1_RIGHT2 0x010d /* Audio Dock ADC1 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT3 0x010e /* Audio Dock ADC1 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT4 0x010f /* Audio Dock ADC1 Right, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT1 0x0110 /* Audio Dock ADC2 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC2_LEFT2 0x0111 /* Audio Dock ADC2 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT3 0x0112 /* Audio Dock ADC2 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT4 0x0113 /* Audio Dock ADC2 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT1 0x0114 /* Audio Dock ADC2 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC2_RIGHT2 0x0115 /* Audio Dock ADC2 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT3 0x0116 /* Audio Dock ADC2 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT4 0x0117 /* Audio Dock ADC2 Right, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT1 0x0118 /* Audio Dock ADC3 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC3_LEFT2 0x0119 /* Audio Dock ADC3 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT3 0x011a /* Audio Dock ADC3 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT4 0x011b /* Audio Dock ADC3 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT1 0x011c /* Audio Dock ADC3 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC3_RIGHT2 0x011d /* Audio Dock ADC3 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT3 0x011e /* Audio Dock ADC3 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT4 0x011f /* Audio Dock ADC3 Right, 4th or 192kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT1 0x0200 /* Hamoa ADC Left, 1st or 48kHz only */
+#define EMU_SRC_HAMOA_ADC_LEFT2 0x0202 /* Hamoa ADC Left, 2nd or 96kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT3 0x0204 /* Hamoa ADC Left, 3rd or 192kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT4 0x0206 /* Hamoa ADC Left, 4th or 192kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT1 0x0201 /* Hamoa ADC Right, 1st or 48kHz only */
+#define EMU_SRC_HAMOA_ADC_RIGHT2 0x0203 /* Hamoa ADC Right, 2nd or 96kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT3 0x0205 /* Hamoa ADC Right, 3rd or 192kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT4 0x0207 /* Hamoa ADC Right, 4th or 192kHz */
+#define EMU_SRC_ALICE_EMU32A 0x0300 /* Alice2 EMU32a 16 outputs. +0 to +0xf */
+#define EMU_SRC_ALICE_EMU32B 0x0310 /* Alice2 EMU32b 16 outputs. +0 to +0xf */
+#define EMU_SRC_HANA_ADAT 0x0400 /* Hana ADAT 8 channel in +0 to +7 */
+#define EMU_SRC_HANA_SPDIF_LEFT1 0x0500 /* Hana SPDIF Left, 1st or 48kHz only */
+#define EMU_SRC_HANA_SPDIF_LEFT2 0x0502 /* Hana SPDIF Left, 2nd or 96kHz */
+#define EMU_SRC_HANA_SPDIF_RIGHT1 0x0501 /* Hana SPDIF Right, 1st or 48kHz only */
+#define EMU_SRC_HANA_SPDIF_RIGHT2 0x0503 /* Hana SPDIF Right, 2nd or 96kHz */
+/* 0x600 and 0x700 no used */
/* ------------------- STRUCTURES -------------------- */
@@ -1063,7 +1425,7 @@ struct snd_emu_chip_details {
unsigned char spdif_bug; /* Has Spdif phasing bug */
unsigned char ac97_chip; /* Has an AC97 chip: 1 = mandatory, 2 = optional */
unsigned char ecard; /* APS EEPROM */
- unsigned char emu1212m; /* EMU 1212m card */
+ unsigned char emu1010; /* EMU 1010m card */
unsigned char spi_dac; /* SPI interface for DAC */
unsigned char i2c_adc; /* I2C interface for ADC */
unsigned char adc_1361t; /* Use Philips 1361T ADC */
@@ -1072,6 +1434,14 @@ struct snd_emu_chip_details {
const char *id; /* for backward compatibility - can be NULL if not needed */
};
+struct snd_emu1010 {
+ unsigned int output_source[64];
+ unsigned int input_source[64];
+ unsigned int adc_pads; /* bit mask */
+ unsigned int dac_pads; /* bit mask */
+ unsigned int internal_clock; /* 44100 or 48000 */
+};
+
struct snd_emu10k1 {
int irq;
@@ -1079,6 +1449,7 @@ struct snd_emu10k1 {
unsigned int tos_link: 1, /* tos link detected */
rear_ac97: 1, /* rear channels are on AC'97 */
enable_ir: 1;
+ unsigned int support_tlv :1;
/* Contains profile of card capabilities */
const struct snd_emu_chip_details *card_capabilities;
unsigned int audigy; /* is Audigy? */
@@ -1104,6 +1475,8 @@ struct snd_emu10k1 {
spinlock_t memblk_lock;
unsigned int spdif_bits[3]; /* s/pdif out setup */
+ unsigned int i2c_capture_source;
+ u8 i2c_capture_volume[4][2];
struct snd_emu10k1_fx8010 fx8010; /* FX8010 info */
int gpr_base;
@@ -1132,6 +1505,7 @@ struct snd_emu10k1 {
int p16v_device_offset;
u32 p16v_capture_source;
u32 p16v_capture_channel;
+ struct snd_emu1010 emu1010;
struct snd_emu10k1_pcm_mixer pcm_mixer[32];
struct snd_emu10k1_pcm_mixer efx_pcm_mixer[NUM_EFX_PLAYBACK];
struct snd_kcontrol *ctl_send_routing;
@@ -1208,6 +1582,10 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
+int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
+int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value);
+int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value);
+int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src);
unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb);
@@ -1524,11 +1902,20 @@ struct snd_emu10k1_fx8010_control_gpr {
unsigned int value[32]; /* initial values */
unsigned int min; /* minimum range */
unsigned int max; /* maximum range */
- union {
- snd_kcontrol_tlv_rw_t *c;
- unsigned int *p;
- } tlv;
unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
+ const unsigned int *tlv;
+};
+
+/* old ABI without TLV support */
+struct snd_emu10k1_fx8010_control_old_gpr {
+ struct snd_ctl_elem_id id;
+ unsigned int vcount;
+ unsigned int count;
+ unsigned short gpr[32];
+ unsigned int value[32];
+ unsigned int min;
+ unsigned int max;
+ unsigned int translation;
};
struct snd_emu10k1_fx8010_code {
@@ -1579,6 +1966,8 @@ struct snd_emu10k1_fx8010_pcm_rec {
unsigned int res2; /* reserved */
};
+#define SNDRV_EMU10K1_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1)
+
#define SNDRV_EMU10K1_IOCTL_INFO _IOR ('H', 0x10, struct snd_emu10k1_fx8010_info)
#define SNDRV_EMU10K1_IOCTL_CODE_POKE _IOW ('H', 0x11, struct snd_emu10k1_fx8010_code)
#define SNDRV_EMU10K1_IOCTL_CODE_PEEK _IOWR('H', 0x12, struct snd_emu10k1_fx8010_code)
@@ -1587,6 +1976,7 @@ struct snd_emu10k1_fx8010_pcm_rec {
#define SNDRV_EMU10K1_IOCTL_TRAM_PEEK _IOWR('H', 0x22, struct snd_emu10k1_fx8010_tram)
#define SNDRV_EMU10K1_IOCTL_PCM_POKE _IOW ('H', 0x30, struct snd_emu10k1_fx8010_pcm_rec)
#define SNDRV_EMU10K1_IOCTL_PCM_PEEK _IOWR('H', 0x31, struct snd_emu10k1_fx8010_pcm_rec)
+#define SNDRV_EMU10K1_IOCTL_PVERSION _IOR ('H', 0x40, int)
#define SNDRV_EMU10K1_IOCTL_STOP _IO ('H', 0x80)
#define SNDRV_EMU10K1_IOCTL_CONTINUE _IO ('H', 0x81)
#define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 2f645dfd7f7..ee6bc2d0680 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -56,6 +56,8 @@ struct snd_pcm_hardware {
size_t fifo_size; /* fifo size in bytes */
};
+struct snd_pcm_substream;
+
struct snd_pcm_ops {
int (*open)(struct snd_pcm_substream *substream);
int (*close)(struct snd_pcm_substream *substream);
@@ -384,6 +386,7 @@ struct snd_pcm_substream {
struct snd_info_entry *proc_sw_params_entry;
struct snd_info_entry *proc_status_entry;
struct snd_info_entry *proc_prealloc_entry;
+ struct snd_info_entry *proc_prealloc_max_entry;
#endif
/* misc flags */
unsigned int hw_opened: 1;
@@ -427,6 +430,7 @@ struct snd_pcm {
wait_queue_head_t open_wait;
void *private_data;
void (*private_free) (struct snd_pcm *pcm);
+ struct device *dev; /* actual hw device this belongs to */
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
struct snd_pcm_oss oss;
#endif
diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h
index c854647b6f3..1cd4f64cdf3 100644
--- a/include/sound/pcm_oss.h
+++ b/include/sound/pcm_oss.h
@@ -56,6 +56,7 @@ struct snd_pcm_oss_runtime {
size_t mmap_bytes;
char *buffer; /* vmallocated period */
size_t buffer_used; /* used length from period buffer */
+ struct mutex params_lock;
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
struct snd_pcm_plugin *plugin_first;
struct snd_pcm_plugin *plugin_last;
diff --git a/include/sound/pt2258.h b/include/sound/pt2258.h
new file mode 100644
index 00000000000..160f812faa4
--- /dev/null
+++ b/include/sound/pt2258.h
@@ -0,0 +1,37 @@
+/*
+ * ALSA Driver for the PT2258 volume controller.
+ *
+ * Copyright (c) 2006 Jochen Voss <voss@seehuhn.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __SOUND_PT2258_H
+#define __SOUND_PT2258_H
+
+struct snd_pt2258 {
+ struct snd_card *card;
+ struct snd_i2c_bus *i2c_bus;
+ struct snd_i2c_device *i2c_dev;
+
+ unsigned char volume[6];
+ int mute;
+};
+
+extern int snd_pt2258_reset(struct snd_pt2258 *pt);
+extern int snd_pt2258_build_controls(struct snd_pt2258 *pt);
+
+#endif /* __SOUND_PT2258_H */
diff --git a/include/sound/sb16_csp.h b/include/sound/sb16_csp.h
index caf6fe21514..736eac71d05 100644
--- a/include/sound/sb16_csp.h
+++ b/include/sound/sb16_csp.h
@@ -114,9 +114,21 @@ struct snd_sb_csp_info {
#ifdef __KERNEL__
#include "sb.h"
#include "hwdep.h"
+#include <linux/firmware.h>
struct snd_sb_csp;
+/* indices for the known CSP programs */
+enum {
+ CSP_PROGRAM_MULAW,
+ CSP_PROGRAM_ALAW,
+ CSP_PROGRAM_ADPCM_INIT,
+ CSP_PROGRAM_ADPCM_PLAYBACK,
+ CSP_PROGRAM_ADPCM_CAPTURE,
+
+ CSP_PROGRAM_COUNT
+};
+
/*
* CSP operators
*/
@@ -159,6 +171,8 @@ struct snd_sb_csp {
struct snd_kcontrol *qsound_space;
struct mutex access_mutex; /* locking */
+
+ const struct firmware *csp_programs[CSP_PROGRAM_COUNT];
};
int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep);
diff --git a/include/sound/snd_wavefront.h b/include/sound/snd_wavefront.h
index 0b9e5de94ff..9688d4be918 100644
--- a/include/sound/snd_wavefront.h
+++ b/include/sound/snd_wavefront.h
@@ -85,6 +85,7 @@ struct _snd_wavefront {
char hw_version[2]; /* major = [0], minor = [1] */
char israw; /* needs Motorola microcode */
char has_fx; /* has FX processor (Tropez+) */
+ char fx_initialized; /* FX's register pages initialized */
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_* */
@@ -94,6 +95,7 @@ struct _snd_wavefront {
spinlock_t irq_lock;
wait_queue_head_t interrupt_sleeper;
snd_wavefront_midi_t midi; /* ICS2115 MIDI interface */
+ struct snd_card *card;
};
struct _snd_wavefront_card {
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
new file mode 100644
index 00000000000..2b1ae8edc43
--- /dev/null
+++ b/include/sound/soc-dapm.h
@@ -0,0 +1,286 @@
+/*
+ * linux/sound/soc-dapm.h -- ALSA SoC Dynamic Audio Power Management
+ *
+ * Author: Liam Girdwood
+ * Created: Aug 11th 2005
+ * Copyright: Wolfson Microelectronics. PLC.
+ *
+ * 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 __LINUX_SND_SOC_DAPM_H
+#define __LINUX_SND_SOC_DAPM_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+
+/* widget has no PM register bit */
+#define SND_SOC_NOPM -1
+
+/*
+ * SoC dynamic audio power managment
+ *
+ * We can have upto 4 power domains
+ * 1. Codec domain - VREF, VMID
+ * Usually controlled at codec probe/remove, although can be set
+ * at stream time if power is not needed for sidetone, etc.
+ * 2. Platform/Machine domain - physically connected inputs and outputs
+ * Is platform/machine and user action specific, is set in the machine
+ * driver and by userspace e.g when HP are inserted
+ * 3. Path domain - Internal codec path mixers
+ * Are automatically set when mixer and mux settings are
+ * changed by the user.
+ * 4. Stream domain - DAC's and ADC's.
+ * Enabled when stream playback/capture is started.
+ */
+
+/* codec domain */
+#define SND_SOC_DAPM_VMID(wname) \
+{ .id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0}
+
+/* platform domain */
+#define SND_SOC_DAPM_INPUT(wname) \
+{ .id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0}
+#define SND_SOC_DAPM_OUTPUT(wname) \
+{ .id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0}
+#define SND_SOC_DAPM_MIC(wname, wevent) \
+{ .id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0, .event = wevent, \
+ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
+#define SND_SOC_DAPM_HP(wname, wevent) \
+{ .id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0, .event = wevent, \
+ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
+#define SND_SOC_DAPM_SPK(wname, wevent) \
+{ .id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0, .event = wevent, \
+ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
+#define SND_SOC_DAPM_LINE(wname, wevent) \
+{ .id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0, .event = wevent, \
+ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
+
+/* path domain */
+#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
+ wcontrols, wncontrols) \
+{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
+ .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
+ wcontrols, wncontrols)\
+{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
+ .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+#define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
+{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
+ .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0}
+#define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
+{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
+ .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
+{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
+ .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+
+/* path domain with event - event handler must return 0 for success */
+#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
+ wncontrols, wevent, wflags) \
+{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
+ .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+ .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
+ wncontrols, wevent, wflags) \
+{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
+ .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+ .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
+{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
+ .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \
+ .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
+ wevent, wflags) \
+{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
+ .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1 \
+ .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
+ wevent, wflags) \
+{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
+ .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+ .event = wevent, .event_flags = wflags}
+
+/* events that are pre and post DAPM */
+#define SND_SOC_DAPM_PRE(wname, wevent) \
+{ .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0, .event = wevent, \
+ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
+#define SND_SOC_DAPM_POST(wname, wevent) \
+{ .id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \
+ .num_kcontrols = 0, .event = wevent, \
+ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
+
+/* stream domain */
+#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
+{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
+ .shift = wshift, .invert = winvert}
+#define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
+{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
+ .shift = wshift, .invert = winvert}
+
+/* dapm kcontrol types */
+#define SOC_DAPM_SINGLE(xname, reg, shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_volsw, \
+ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+ .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) }
+#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, mask, invert, \
+ power) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = snd_soc_info_volsw, \
+ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+ .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
+ ((mask) << 16) | ((invert) << 24) }
+#define SOC_DAPM_ENUM(xname, xenum) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_enum_double, \
+ .get = snd_soc_dapm_get_enum_double, \
+ .put = snd_soc_dapm_put_enum_double, \
+ .private_value = (unsigned long)&xenum }
+
+/* dapm stream operations */
+#define SND_SOC_DAPM_STREAM_NOP 0x0
+#define SND_SOC_DAPM_STREAM_START 0x1
+#define SND_SOC_DAPM_STREAM_STOP 0x2
+#define SND_SOC_DAPM_STREAM_SUSPEND 0x4
+#define SND_SOC_DAPM_STREAM_RESUME 0x8
+#define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10
+#define SND_SOC_DAPM_STREAM_PAUSE_RELEASE 0x20
+
+/* dapm event types */
+#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
+#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
+#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
+#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
+#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
+#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
+
+/* convenience event type detection */
+#define SND_SOC_DAPM_EVENT_ON(e) \
+ (e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
+#define SND_SOC_DAPM_EVENT_OFF(e) \
+ (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
+
+struct snd_soc_dapm_widget;
+enum snd_soc_dapm_type;
+struct snd_soc_dapm_path;
+struct snd_soc_dapm_pin;
+
+/* dapm controls */
+int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
+ const struct snd_soc_dapm_widget *widget);
+
+/* dapm path setup */
+int snd_soc_dapm_connect_input(struct snd_soc_codec *codec,
+ const char *sink_name, const char *control_name, const char *src_name);
+int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
+void snd_soc_dapm_free(struct snd_soc_device *socdev);
+
+/* dapm events */
+int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
+ int event);
+
+/* dapm sys fs - used by the core */
+int snd_soc_dapm_sys_add(struct device *dev);
+
+/* dapm audio endpoint control */
+int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
+ char *pin, int status);
+int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec);
+
+/* dapm widget types */
+enum snd_soc_dapm_type {
+ snd_soc_dapm_input = 0, /* input pin */
+ snd_soc_dapm_output, /* output pin */
+ snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
+ snd_soc_dapm_mixer, /* mixes several analog signals together */
+ snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
+ snd_soc_dapm_adc, /* analog to digital converter */
+ snd_soc_dapm_dac, /* digital to analog converter */
+ snd_soc_dapm_micbias, /* microphone bias (power) */
+ snd_soc_dapm_mic, /* microphone */
+ snd_soc_dapm_hp, /* headphones */
+ snd_soc_dapm_spk, /* speaker */
+ snd_soc_dapm_line, /* line input/output */
+ snd_soc_dapm_switch, /* analog switch */
+ snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */
+ snd_soc_dapm_pre, /* machine specific pre widget - exec first */
+ snd_soc_dapm_post, /* machine specific post widget - exec last */
+};
+
+/* dapm audio path between two widgets */
+struct snd_soc_dapm_path {
+ char *name;
+ char *long_name;
+
+ /* source (input) and sink (output) widgets */
+ struct snd_soc_dapm_widget *source;
+ struct snd_soc_dapm_widget *sink;
+ struct snd_kcontrol *kcontrol;
+
+ /* status */
+ u32 connect:1; /* source and sink widgets are connected */
+ u32 walked:1; /* path has been walked */
+
+ struct list_head list_source;
+ struct list_head list_sink;
+ struct list_head list;
+};
+
+/* dapm widget */
+struct snd_soc_dapm_widget {
+ enum snd_soc_dapm_type id;
+ char *name; /* widget name */
+ char *sname; /* stream name */
+ struct snd_soc_codec *codec;
+ struct list_head list;
+
+ /* dapm control */
+ short reg; /* negative reg = no direct dapm */
+ unsigned char shift; /* bits to shift */
+ unsigned int saved_value; /* widget saved value */
+ unsigned int value; /* widget current value */
+ unsigned char power:1; /* block power status */
+ unsigned char invert:1; /* invert the power bit */
+ unsigned char active:1; /* active stream on DAC, ADC's */
+ unsigned char connected:1; /* connected codec pin */
+ unsigned char new:1; /* cnew complete */
+ unsigned char ext:1; /* has external widgets */
+ unsigned char muted:1; /* muted for pop reduction */
+ unsigned char suspend:1; /* was active before suspend */
+ unsigned char pmdown:1; /* waiting for timeout */
+
+ /* external events */
+ unsigned short event_flags; /* flags to specify event types */
+ int (*event)(struct snd_soc_dapm_widget*, int);
+
+ /* kcontrols that relate to this widget */
+ int num_kcontrols;
+ const struct snd_kcontrol_new *kcontrols;
+
+ /* widget input and outputs */
+ struct list_head sources;
+ struct list_head sinks;
+};
+
+#endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
new file mode 100644
index 00000000000..b1dc364b8f7
--- /dev/null
+++ b/include/sound/soc.h
@@ -0,0 +1,461 @@
+/*
+ * linux/sound/soc.h -- ALSA SoC Layer
+ *
+ * Author: Liam Girdwood
+ * Created: Aug 11th 2005
+ * Copyright: Wolfson Microelectronics. PLC.
+ *
+ * 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 __LINUX_SND_SOC_H
+#define __LINUX_SND_SOC_H
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/control.h>
+#include <sound/ac97_codec.h>
+
+#define SND_SOC_VERSION "0.13.0"
+
+/*
+ * Convenience kcontrol builders
+ */
+#define SOC_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) |\
+ ((shift) << 12) | ((mask) << 16) | ((invert) << 24))
+#define SOC_SINGLE_VALUE_EXT(reg,mask,invert) ((reg) | ((mask) << 16) |\
+ ((invert) << 31))
+#define SOC_SINGLE(xname, reg, shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+ .put = snd_soc_put_volsw, \
+ .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) }
+#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
+ .put = snd_soc_put_volsw, \
+ .private_value = (reg) | ((shift_left) << 8) | \
+ ((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) }
+#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = snd_soc_info_volsw_2r, \
+ .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
+ .private_value = (reg_left) | ((shift) << 8) | \
+ ((mask) << 12) | ((invert) << 20) | ((reg_right) << 24) }
+#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
+{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
+ .mask = xmask, .texts = xtexts }
+#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \
+ SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts)
+#define SOC_ENUM_SINGLE_EXT(xmask, xtexts) \
+{ .mask = xmask, .texts = xtexts }
+#define SOC_ENUM(xname, xenum) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
+ .info = snd_soc_info_enum_double, \
+ .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
+ .private_value = (unsigned long)&xenum }
+#define SOC_SINGLE_EXT(xname, xreg, xshift, xmask, xinvert,\
+ xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_volsw, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
+#define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_bool_ext, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = xdata }
+#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_enum_ext, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = (unsigned long)&xenum }
+
+/*
+ * Digital Audio Interface (DAI) types
+ */
+#define SND_SOC_DAI_AC97 0x1
+#define SND_SOC_DAI_I2S 0x2
+#define SND_SOC_DAI_PCM 0x4
+
+/*
+ * DAI hardware audio formats
+ */
+#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */
+#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right justified mode */
+#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */
+#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM or LRC */
+#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM or LRC */
+#define SND_SOC_DAIFMT_AC97 5 /* AC97 */
+
+#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
+#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J
+
+/*
+ * DAI Gating
+ */
+#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */
+#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated when not Tx/Rx */
+
+/*
+ * DAI hardware signal inversions
+ */
+#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */
+#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */
+#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */
+#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */
+
+/*
+ * DAI hardware clock masters
+ * This is wrt the codec, the inverse is true for the interface
+ * i.e. if the codec is clk and frm master then the interface is
+ * clk and frame slave.
+ */
+#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */
+#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */
+#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */
+#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */
+
+#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
+#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
+#define SND_SOC_DAIFMT_INV_MASK 0x0f00
+#define SND_SOC_DAIFMT_MASTER_MASK 0xf000
+
+
+/*
+ * Master Clock Directions
+ */
+#define SND_SOC_CLOCK_IN 0
+#define SND_SOC_CLOCK_OUT 1
+
+/*
+ * AC97 codec ID's bitmask
+ */
+#define SND_SOC_DAI_AC97_ID0 (1 << 0)
+#define SND_SOC_DAI_AC97_ID1 (1 << 1)
+#define SND_SOC_DAI_AC97_ID2 (1 << 2)
+#define SND_SOC_DAI_AC97_ID3 (1 << 3)
+
+struct snd_soc_device;
+struct snd_soc_pcm_stream;
+struct snd_soc_ops;
+struct snd_soc_dai_mode;
+struct snd_soc_pcm_runtime;
+struct snd_soc_codec_dai;
+struct snd_soc_cpu_dai;
+struct snd_soc_codec;
+struct snd_soc_machine_config;
+struct soc_enum;
+struct snd_soc_ac97_ops;
+struct snd_soc_clock_info;
+
+typedef int (*hw_write_t)(void *,const char* ,int);
+typedef int (*hw_read_t)(void *,char* ,int);
+
+extern struct snd_ac97_bus_ops soc_ac97_ops;
+
+/* pcm <-> DAI connect */
+void snd_soc_free_pcms(struct snd_soc_device *socdev);
+int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
+int snd_soc_register_card(struct snd_soc_device *socdev);
+
+/* set runtime hw params */
+int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
+ const struct snd_pcm_hardware *hw);
+
+/* codec IO */
+#define snd_soc_read(codec, reg) codec->read(codec, reg)
+#define snd_soc_write(codec, reg, value) codec->write(codec, reg, value)
+
+/* codec register bit access */
+int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
+ unsigned short mask, unsigned short value);
+int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
+ unsigned short mask, unsigned short value);
+
+int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
+ struct snd_ac97_bus_ops *ops, int num);
+void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
+
+/*
+ *Controls
+ */
+struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
+ void *data, char *long_name);
+int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+
+/* SoC PCM stream information */
+struct snd_soc_pcm_stream {
+ char *stream_name;
+ u64 formats; /* SNDRV_PCM_FMTBIT_* */
+ unsigned int rates; /* SNDRV_PCM_RATE_* */
+ unsigned int rate_min; /* min rate */
+ unsigned int rate_max; /* max rate */
+ unsigned int channels_min; /* min channels */
+ unsigned int channels_max; /* max channels */
+ unsigned int active:1; /* stream is in use */
+};
+
+/* SoC audio ops */
+struct snd_soc_ops {
+ int (*startup)(struct snd_pcm_substream *);
+ void (*shutdown)(struct snd_pcm_substream *);
+ int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
+ int (*hw_free)(struct snd_pcm_substream *);
+ int (*prepare)(struct snd_pcm_substream *);
+ int (*trigger)(struct snd_pcm_substream *, int);
+};
+
+/* ASoC codec DAI ops */
+struct snd_soc_codec_ops {
+ /* codec DAI clocking configuration */
+ int (*set_sysclk)(struct snd_soc_codec_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir);
+ int (*set_pll)(struct snd_soc_codec_dai *codec_dai,
+ int pll_id, unsigned int freq_in, unsigned int freq_out);
+ int (*set_clkdiv)(struct snd_soc_codec_dai *codec_dai,
+ int div_id, int div);
+
+ /* CPU DAI format configuration */
+ int (*set_fmt)(struct snd_soc_codec_dai *codec_dai,
+ unsigned int fmt);
+ int (*set_tdm_slot)(struct snd_soc_codec_dai *codec_dai,
+ unsigned int mask, int slots);
+ int (*set_tristate)(struct snd_soc_codec_dai *, int tristate);
+
+ /* digital mute */
+ int (*digital_mute)(struct snd_soc_codec_dai *, int mute);
+};
+
+/* ASoC cpu DAI ops */
+struct snd_soc_cpu_ops {
+ /* CPU DAI clocking configuration */
+ int (*set_sysclk)(struct snd_soc_cpu_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir);
+ int (*set_clkdiv)(struct snd_soc_cpu_dai *cpu_dai,
+ int div_id, int div);
+ int (*set_pll)(struct snd_soc_cpu_dai *cpu_dai,
+ int pll_id, unsigned int freq_in, unsigned int freq_out);
+
+ /* CPU DAI format configuration */
+ int (*set_fmt)(struct snd_soc_cpu_dai *cpu_dai,
+ unsigned int fmt);
+ int (*set_tdm_slot)(struct snd_soc_cpu_dai *cpu_dai,
+ unsigned int mask, int slots);
+ int (*set_tristate)(struct snd_soc_cpu_dai *, int tristate);
+};
+
+/* SoC Codec DAI */
+struct snd_soc_codec_dai {
+ char *name;
+ int id;
+
+ /* DAI capabilities */
+ struct snd_soc_pcm_stream playback;
+ struct snd_soc_pcm_stream capture;
+
+ /* DAI runtime info */
+ struct snd_soc_codec *codec;
+ unsigned int active;
+ unsigned char pop_wait:1;
+
+ /* ops */
+ struct snd_soc_ops ops;
+ struct snd_soc_codec_ops dai_ops;
+
+ /* DAI private data */
+ void *private_data;
+};
+
+/* SoC CPU DAI */
+struct snd_soc_cpu_dai {
+
+ /* DAI description */
+ char *name;
+ unsigned int id;
+ unsigned char type;
+
+ /* DAI callbacks */
+ int (*probe)(struct platform_device *pdev);
+ void (*remove)(struct platform_device *pdev);
+ int (*suspend)(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *cpu_dai);
+ int (*resume)(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *cpu_dai);
+
+ /* ops */
+ struct snd_soc_ops ops;
+ struct snd_soc_cpu_ops dai_ops;
+
+ /* DAI capabilities */
+ struct snd_soc_pcm_stream capture;
+ struct snd_soc_pcm_stream playback;
+
+ /* DAI runtime info */
+ struct snd_pcm_runtime *runtime;
+ unsigned char active:1;
+ void *dma_data;
+
+ /* DAI private data */
+ void *private_data;
+};
+
+/* SoC Audio Codec */
+struct snd_soc_codec {
+ char *name;
+ struct module *owner;
+ struct mutex mutex;
+
+ /* callbacks */
+ int (*dapm_event)(struct snd_soc_codec *codec, int event);
+
+ /* runtime */
+ struct snd_card *card;
+ struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
+ unsigned int active;
+ unsigned int pcm_devs;
+ void *private_data;
+
+ /* codec IO */
+ void *control_data; /* codec control (i2c/3wire) data */
+ unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+ int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+ hw_write_t hw_write;
+ hw_read_t hw_read;
+ void *reg_cache;
+ short reg_cache_size;
+ short reg_cache_step;
+
+ /* dapm */
+ struct list_head dapm_widgets;
+ struct list_head dapm_paths;
+ unsigned int dapm_state;
+ unsigned int suspend_dapm_state;
+ struct delayed_work delayed_work;
+
+ /* codec DAI's */
+ struct snd_soc_codec_dai *dai;
+ unsigned int num_dai;
+};
+
+/* codec device */
+struct snd_soc_codec_device {
+ int (*probe)(struct platform_device *pdev);
+ int (*remove)(struct platform_device *pdev);
+ int (*suspend)(struct platform_device *pdev, pm_message_t state);
+ int (*resume)(struct platform_device *pdev);
+};
+
+/* SoC platform interface */
+struct snd_soc_platform {
+ char *name;
+
+ int (*probe)(struct platform_device *pdev);
+ int (*remove)(struct platform_device *pdev);
+ int (*suspend)(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *cpu_dai);
+ int (*resume)(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *cpu_dai);
+
+ /* pcm creation and destruction */
+ int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *,
+ struct snd_pcm *);
+ void (*pcm_free)(struct snd_pcm *);
+
+ /* platform stream ops */
+ struct snd_pcm_ops *pcm_ops;
+};
+
+/* SoC machine DAI configuration, glues a codec and cpu DAI together */
+struct snd_soc_dai_link {
+ char *name; /* Codec name */
+ char *stream_name; /* Stream name */
+
+ /* DAI */
+ struct snd_soc_codec_dai *codec_dai;
+ struct snd_soc_cpu_dai *cpu_dai;
+
+ /* machine stream operations */
+ struct snd_soc_ops *ops;
+
+ /* codec/machine specific init - e.g. add machine controls */
+ int (*init)(struct snd_soc_codec *codec);
+};
+
+/* SoC machine */
+struct snd_soc_machine {
+ char *name;
+
+ int (*probe)(struct platform_device *pdev);
+ int (*remove)(struct platform_device *pdev);
+
+ /* the pre and post PM functions are used to do any PM work before and
+ * after the codec and DAI's do any PM work. */
+ int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
+ int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
+ int (*resume_pre)(struct platform_device *pdev);
+ int (*resume_post)(struct platform_device *pdev);
+
+ /* CPU <--> Codec DAI links */
+ struct snd_soc_dai_link *dai_link;
+ int num_links;
+};
+
+/* SoC Device - the audio subsystem */
+struct snd_soc_device {
+ struct device *dev;
+ struct snd_soc_machine *machine;
+ struct snd_soc_platform *platform;
+ struct snd_soc_codec *codec;
+ struct snd_soc_codec_device *codec_dev;
+ struct delayed_work delayed_work;
+ void *codec_data;
+};
+
+/* runtime channel data */
+struct snd_soc_pcm_runtime {
+ struct snd_soc_dai_link *dai;
+ struct snd_soc_device *socdev;
+};
+
+/* enumerated kcontrol */
+struct soc_enum {
+ unsigned short reg;
+ unsigned short reg2;
+ unsigned char shift_l;
+ unsigned char shift_r;
+ unsigned int mask;
+ const char **texts;
+ void *dapm;
+};
+
+#endif
diff --git a/include/sound/typedefs.h b/include/sound/typedefs.h
deleted file mode 100644
index f454b0206b9..00000000000
--- a/include/sound/typedefs.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Typedef's for backward compatibility (for out-of-kernel drivers)
- *
- * This file will be removed soon in future
- */
-
-/* core stuff */
-typedef struct snd_card snd_card_t;
-typedef struct snd_device snd_device_t;
-typedef struct snd_device_ops snd_device_ops_t;
-typedef enum snd_card_type snd_card_type_t;
-typedef struct snd_minor snd_minor_t;
-
-/* info */
-typedef struct snd_info_entry snd_info_entry_t;
-typedef struct snd_info_buffer snd_info_buffer_t;
-
-/* control */
-typedef struct snd_ctl_file snd_ctl_file_t;
-typedef struct snd_kcontrol snd_kcontrol_t;
-typedef struct snd_kcontrol_new snd_kcontrol_new_t;
-typedef struct snd_kcontrol_volatile snd_kcontrol_volatile_t;
-typedef struct snd_kctl_event snd_kctl_event_t;
-typedef struct snd_aes_iec958 snd_aes_iec958_t;
-typedef struct snd_ctl_card_info snd_ctl_card_info_t;
-typedef struct snd_ctl_elem_id snd_ctl_elem_id_t;
-typedef struct snd_ctl_elem_list snd_ctl_elem_list_t;
-typedef struct snd_ctl_elem_info snd_ctl_elem_info_t;
-typedef struct snd_ctl_elem_value snd_ctl_elem_value_t;
-typedef struct snd_ctl_event snd_ctl_event_t;
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
-typedef struct snd_mixer_oss snd_mixer_oss_t;
-#endif
-
-/* timer */
-typedef struct snd_timer snd_timer_t;
-typedef struct snd_timer_instance snd_timer_instance_t;
-typedef struct snd_timer_id snd_timer_id_t;
-typedef struct snd_timer_ginfo snd_timer_ginfo_t;
-typedef struct snd_timer_gparams snd_timer_gparams_t;
-typedef struct snd_timer_gstatus snd_timer_gstatus_t;
-typedef struct snd_timer_select snd_timer_select_t;
-typedef struct snd_timer_info snd_timer_info_t;
-typedef struct snd_timer_params snd_timer_params_t;
-typedef struct snd_timer_status snd_timer_status_t;
-typedef struct snd_timer_read snd_timer_read_t;
-typedef struct snd_timer_tread snd_timer_tread_t;
-
-/* PCM */
-typedef struct snd_pcm snd_pcm_t;
-typedef struct snd_pcm_str snd_pcm_str_t;
-typedef struct snd_pcm_substream snd_pcm_substream_t;
-typedef struct snd_pcm_info snd_pcm_info_t;
-typedef struct snd_pcm_hw_params snd_pcm_hw_params_t;
-typedef struct snd_pcm_sw_params snd_pcm_sw_params_t;
-typedef struct snd_pcm_channel_info snd_pcm_channel_info_t;
-typedef struct snd_pcm_status snd_pcm_status_t;
-typedef struct snd_pcm_mmap_status snd_pcm_mmap_status_t;
-typedef struct snd_pcm_mmap_control snd_pcm_mmap_control_t;
-typedef struct snd_mask snd_mask_t;
-typedef struct snd_sg_buf snd_pcm_sgbuf_t;
-
-typedef struct snd_interval snd_interval_t;
-typedef struct snd_xferi snd_xferi_t;
-typedef struct snd_xfern snd_xfern_t;
-typedef struct snd_xferv snd_xferv_t;
-
-typedef struct snd_pcm_file snd_pcm_file_t;
-typedef struct snd_pcm_runtime snd_pcm_runtime_t;
-typedef struct snd_pcm_hardware snd_pcm_hardware_t;
-typedef struct snd_pcm_ops snd_pcm_ops_t;
-typedef struct snd_pcm_hw_rule snd_pcm_hw_rule_t;
-typedef struct snd_pcm_hw_constraints snd_pcm_hw_constraints_t;
-typedef struct snd_ratnum ratnum_t;
-typedef struct snd_ratden ratden_t;
-typedef struct snd_pcm_hw_constraint_ratnums snd_pcm_hw_constraint_ratnums_t;
-typedef struct snd_pcm_hw_constraint_ratdens snd_pcm_hw_constraint_ratdens_t;
-typedef struct snd_pcm_hw_constraint_list snd_pcm_hw_constraint_list_t;
-typedef struct snd_pcm_group snd_pcm_group_t;
-typedef struct snd_pcm_notify snd_pcm_notify_t;
-
-/* rawmidi */
-typedef struct snd_rawmidi snd_rawmidi_t;
-typedef struct snd_rawmidi_info snd_rawmidi_info_t;
-typedef struct snd_rawmidi_params snd_rawmidi_params_t;
-typedef struct snd_rawmidi_status snd_rawmidi_status_t;
-typedef struct snd_rawmidi_runtime snd_rawmidi_runtime_t;
-typedef struct snd_rawmidi_substream snd_rawmidi_substream_t;
-typedef struct snd_rawmidi_str snd_rawmidi_str_t;
-typedef struct snd_rawmidi_ops snd_rawmidi_ops_t;
-typedef struct snd_rawmidi_global_ops snd_rawmidi_global_ops_t;
-typedef struct snd_rawmidi_file snd_rawmidi_file_t;
-
-/* hwdep */
-typedef struct snd_hwdep snd_hwdep_t;
-typedef struct snd_hwdep_info snd_hwdep_info_t;
-typedef struct snd_hwdep_dsp_status snd_hwdep_dsp_status_t;
-typedef struct snd_hwdep_dsp_image snd_hwdep_dsp_image_t;
-typedef struct snd_hwdep_ops snd_hwdep_ops_t;
-
-/* sequencer */
-typedef struct snd_seq_port_info snd_seq_port_info_t;
-typedef struct snd_seq_port_subscribe snd_seq_port_subscribe_t;
-typedef struct snd_seq_event snd_seq_event_t;
-typedef struct snd_seq_addr snd_seq_addr_t;
-typedef struct snd_seq_ev_volume snd_seq_ev_volume_t;
-typedef struct snd_seq_ev_loop snd_seq_ev_loop_t;
-typedef struct snd_seq_remove_events snd_seq_remove_events_t;
-typedef struct snd_seq_query_subs snd_seq_query_subs_t;
-typedef struct snd_seq_system_info snd_seq_system_info_t;
-typedef struct snd_seq_client_info snd_seq_client_info_t;
-typedef struct snd_seq_queue_info snd_seq_queue_info_t;
-typedef struct snd_seq_queue_status snd_seq_queue_status_t;
-typedef struct snd_seq_queue_tempo snd_seq_queue_tempo_t;
-typedef struct snd_seq_queue_owner snd_seq_queue_owner_t;
-typedef struct snd_seq_queue_timer snd_seq_queue_timer_t;
-typedef struct snd_seq_queue_client snd_seq_queue_client_t;
-typedef struct snd_seq_client_pool snd_seq_client_pool_t;
-typedef struct snd_seq_instr snd_seq_instr_t;
-typedef struct snd_seq_instr_data snd_seq_instr_data_t;
-typedef struct snd_seq_instr_header snd_seq_instr_header_t;
-
-typedef struct snd_seq_user_client user_client_t;
-typedef struct snd_seq_kernel_client kernel_client_t;
-typedef struct snd_seq_client client_t;
-typedef struct snd_seq_queue queue_t;
-
-/* seq_device */
-typedef struct snd_seq_device snd_seq_device_t;
-typedef struct snd_seq_dev_ops snd_seq_dev_ops_t;
-
-/* seq_midi */
-typedef struct snd_midi_event snd_midi_event_t;
-
-/* seq_midi_emul */
-typedef struct snd_midi_channel snd_midi_channel_t;
-typedef struct snd_midi_channel_set snd_midi_channel_set_t;
-typedef struct snd_midi_op snd_midi_op_t;
-
-/* seq_oss */
-typedef struct snd_seq_oss_arg snd_seq_oss_arg_t;
-typedef struct snd_seq_oss_callback snd_seq_oss_callback_t;
-typedef struct snd_seq_oss_reg snd_seq_oss_reg_t;
-
-/* virmidi */
-typedef struct snd_virmidi_dev snd_virmidi_dev_t;
-typedef struct snd_virmidi snd_virmidi_t;
-
-/* seq_instr */
-typedef struct snd_seq_kcluster snd_seq_kcluster_t;
-typedef struct snd_seq_kinstr_ops snd_seq_kinstr_ops_t;
-typedef struct snd_seq_kinstr snd_seq_kinstr_t;
-typedef struct snd_seq_kinstr_list snd_seq_kinstr_list_t;
-
-/* ac97 */
-typedef struct snd_ac97_bus ac97_bus_t;
-typedef struct snd_ac97_bus_ops ac97_bus_ops_t;
-typedef struct snd_ac97_template ac97_template_t;
-typedef struct snd_ac97 ac97_t;
-
-/* opl3/4 */
-typedef struct snd_opl3 opl3_t;
-typedef struct snd_opl4 opl4_t;
-
-/* mpu401 */
-typedef struct snd_mpu401 mpu401_t;
-
-/* i2c */
-typedef struct snd_i2c_device snd_i2c_device_t;
-typedef struct snd_i2c_bus snd_i2c_bus_t;
-
-typedef struct snd_ak4531 ak4531_t;
-
diff --git a/include/sound/version.h b/include/sound/version.h
index 17137f3a3b6..c39b3802cf1 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
/* include/version.h. Generated by alsa/ksync script. */
-#define CONFIG_SND_VERSION "1.0.13"
-#define CONFIG_SND_DATE " (Tue Nov 28 14:07:24 2006 UTC)"
+#define CONFIG_SND_VERSION "1.0.14rc2"
+#define CONFIG_SND_DATE " (Fri Feb 09 13:50:10 2007 UTC)"
diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h
index 21739465209..4830651cc4c 100644
--- a/include/sound/vx_core.h
+++ b/include/sound/vx_core.h
@@ -128,7 +128,7 @@ struct snd_vx_hardware {
unsigned int num_ins;
unsigned int num_outs;
unsigned int output_level_max;
- unsigned int *output_level_db_scale;
+ const unsigned int *output_level_db_scale;
};
/* hwdep id string */
diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h
index d41cda97e95..203d2b45b78 100644
--- a/include/sound/ymfpci.h
+++ b/include/sound/ymfpci.h
@@ -270,6 +270,7 @@ struct snd_ymfpci_pcm {
struct snd_pcm_substream *substream;
struct snd_ymfpci_voice *voices[2]; /* playback only */
unsigned int running: 1,
+ use_441_slot: 1,
output_front: 1,
output_rear: 1,
swap_rear: 1;
@@ -286,7 +287,7 @@ struct snd_ymfpci {
int irq;
unsigned int device_id; /* PCI device ID */
- unsigned int rev; /* PCI revision */
+ unsigned char rev; /* PCI revision */
unsigned long reg_area_phys;
void __iomem *reg_area_virt;
struct resource *res_reg_area;
@@ -324,6 +325,7 @@ struct snd_ymfpci {
u32 active_bank;
struct snd_ymfpci_voice voices[64];
+ int src441_used;
struct snd_ac97_bus *ac97_bus;
struct snd_ac97 *ac97;
@@ -345,9 +347,8 @@ struct snd_ymfpci {
struct snd_kcontrol *spdif_pcm_ctl;
int mode_dup4ch;
int rear_opened;
- int rear_swap;
int spdif_opened;
- struct {
+ struct snd_ymfpci_pcm_mixer {
u16 left;
u16 right;
struct snd_kcontrol *ctl;
@@ -358,6 +359,8 @@ struct snd_ymfpci {
wait_queue_head_t interrupt_sleep;
atomic_t interrupt_sleep_count;
struct snd_info_entry *proc_entry;
+ const struct firmware *dsp_microcode;
+ const struct firmware *controller_microcode;
#ifdef CONFIG_PM
u32 *saved_regs;
@@ -378,7 +381,7 @@ int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch, int rear_swap);
+int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch);
int snd_ymfpci_timer(struct snd_ymfpci *chip, int device);
#endif /* __SOUND_YMFPCI_H */
diff --git a/include/video/mbxfb.h b/include/video/mbxfb.h
index 3bde0f5cd55..20b9002712e 100644
--- a/include/video/mbxfb.h
+++ b/include/video/mbxfb.h
@@ -1,6 +1,9 @@
#ifndef __MBX_FB_H
#define __MBX_FB_H
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
struct mbxfb_val {
unsigned int defval;
unsigned int min;
@@ -25,4 +28,32 @@ struct mbxfb_platform_data {
int (*remove)(struct fb_info *fb);
};
+/* planar */
+#define MBXFB_FMT_YUV12 0
+
+/* packed */
+#define MBXFB_FMT_UY0VY1 1
+#define MBXFB_FMT_VY0UY1 2
+#define MBXFB_FMT_Y0UY1V 3
+#define MBXFB_FMT_Y0VY1U 4
+struct mbxfb_overlaySetup {
+ __u32 enable;
+ __u32 x, y;
+ __u32 width, height;
+ __u32 alpha;
+ __u32 fmt;
+ __u32 mem_offset;
+ __u32 scaled_width;
+ __u32 scaled_height;
+
+ /* Filled by the driver */
+ __u32 U_offset;
+ __u32 V_offset;
+
+ __u16 Y_stride;
+ __u16 UV_stride;
+};
+
+#define MBXFB_IOCX_OVERLAY _IOWR(0xF4, 0x00,struct mbxfb_overlaySetup)
+
#endif /* __MBX_FB_H */
diff --git a/include/video/pm3fb.h b/include/video/pm3fb.h
index ac021379ac4..94c7d2da90e 100644
--- a/include/video/pm3fb.h
+++ b/include/video/pm3fb.h
@@ -607,16 +607,16 @@
#define PM3FBDestReadModeOr 0xac98
#define PM3FBDestReadMode_ReadDisable 0<<0
#define PM3FBDestReadMode_ReadEnable 1<<0
- #define PM3FBDestReadMode_StripePitch(sp) (((sp)&0x7)<<2
- #define PM3FBDestReadMode_StripeHeight(sh) (((sh)&0x7)<<7
+ #define PM3FBDestReadMode_StripePitch(sp) (((sp)&0x7)<<2)
+ #define PM3FBDestReadMode_StripeHeight(sh) (((sh)&0x7)<<7)
#define PM3FBDestReadMode_Enable0 1<<8
#define PM3FBDestReadMode_Enable1 1<<9
#define PM3FBDestReadMode_Enable2 1<<10
#define PM3FBDestReadMode_Enable3 1<<11
- #define PM3FBDestReadMode_Layout0(l) (((l)&0x3)<<12
- #define PM3FBDestReadMode_Layout1(l) (((l)&0x3)<<14
- #define PM3FBDestReadMode_Layout2(l) (((l)&0x3)<<16
- #define PM3FBDestReadMode_Layout3(l) (((l)&0x3)<<18
+ #define PM3FBDestReadMode_Layout0(l) (((l)&0x3)<<12)
+ #define PM3FBDestReadMode_Layout1(l) (((l)&0x3)<<14)
+ #define PM3FBDestReadMode_Layout2(l) (((l)&0x3)<<16)
+ #define PM3FBDestReadMode_Layout3(l) (((l)&0x3)<<18)
#define PM3FBDestReadMode_Origin0 1<<20
#define PM3FBDestReadMode_Origin1 1<<21
#define PM3FBDestReadMode_Origin2 1<<22
@@ -640,16 +640,16 @@
#define PM3FBSourceReadModeOr 0xaca8
#define PM3FBSourceReadMode_ReadDisable (0<<0)
#define PM3FBSourceReadMode_ReadEnable (1<<0)
- #define PM3FBSourceReadMode_StripePitch(sp) (((sp)&0x7)<<2
- #define PM3FBSourceReadMode_StripeHeight(sh) (((sh)&0x7)<<7
- #define PM3FBSourceReadMode_Layout(l) (((l)&0x3)<<8
+ #define PM3FBSourceReadMode_StripePitch(sp) (((sp)&0x7)<<2)
+ #define PM3FBSourceReadMode_StripeHeight(sh) (((sh)&0x7)<<7)
+ #define PM3FBSourceReadMode_Layout(l) (((l)&0x3)<<8)
#define PM3FBSourceReadMode_Origin 1<<10
#define PM3FBSourceReadMode_Blocking 1<<11
#define PM3FBSourceReadMode_UserTexelCoord 1<<13
#define PM3FBSourceReadMode_WrapXEnable 1<<14
#define PM3FBSourceReadMode_WrapYEnable 1<<15
- #define PM3FBSourceReadMode_WrapX(w) (((w)&0xf)<<16
- #define PM3FBSourceReadMode_WrapY(w) (((w)&0xf)<<20
+ #define PM3FBSourceReadMode_WrapX(w) (((w)&0xf)<<16)
+ #define PM3FBSourceReadMode_WrapY(w) (((w)&0xf)<<20)
#define PM3FBSourceReadMode_ExternalSourceData 1<<24
#define PM3FBWriteBufferAddr0 0xb000
#define PM3FBWriteBufferAddr1 0xb008
@@ -942,7 +942,7 @@
#define PM3Window 0x8980
#define PM3Window_ForceLBUpdate 1<<3
#define PM3Window_LBUpdateSource 1<<4
- #define PM3Window_FrameCount(c) (((c)&0xff)<<9
+ #define PM3Window_FrameCount(c) (((c)&0xff)<<9)
#define PM3Window_StencilFCP 1<<17
#define PM3Window_DepthFCP 1<<18
#define PM3Window_OverrideWriteFiltering 1<<19
diff --git a/include/video/sstfb.h b/include/video/sstfb.h
index 5dbf5e7e50a..baa163f770a 100644
--- a/include/video/sstfb.h
+++ b/include/video/sstfb.h
@@ -119,7 +119,7 @@
#define BACKPORCH 0x0208
#define VIDEODIMENSIONS 0x020c
#define FBIINIT0 0x0210 /* misc+fifo controls */
-# define EN_VGA_PASSTHROUGH BIT(0)
+# define DIS_VGA_PASSTHROUGH BIT(0)
# define FBI_RESET BIT(1)
# define FIFO_RESET BIT(2)
#define FBIINIT1 0x0214 /* PCI + video controls */
@@ -251,7 +251,7 @@
# define DACREG_ICS_CLK1_A 0 /* bit4 */
/* sst default init registers */
-#define FBIINIT0_DEFAULT EN_VGA_PASSTHROUGH
+#define FBIINIT0_DEFAULT DIS_VGA_PASSTHROUGH
#define FBIINIT1_DEFAULT \
( \
@@ -296,6 +296,11 @@
*
*/
+/* ioctl to enable/disable VGA passthrough */
+#define SSTFB_SET_VGAPASS _IOW('F', 0xdd, __u32)
+#define SSTFB_GET_VGAPASS _IOR('F', 0xdd, __u32)
+
+
/* used to know witch clock to set */
enum {
VID_CLOCK=0,
@@ -317,7 +322,7 @@ struct pll_timing {
};
struct dac_switch {
- char * name;
+ const char *name;
int (*detect) (struct fb_info *info);
int (*set_pll) (struct fb_info *info, const struct pll_timing *t, const int clock);
void (*set_vidmod) (struct fb_info *info, const int bpp);
@@ -345,7 +350,7 @@ struct sstfb_par {
struct pci_dev *dev;
int type;
u8 revision;
- int gfx_clock; /* status */
+ u8 vgapass; /* VGA pass through: 1=enabled, 0=disabled */
};
#endif /* _SSTFB_H_ */
diff --git a/init/Kconfig b/init/Kconfig
index 14d484606fa..a3f83e2c825 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -304,6 +304,15 @@ config TASK_XACCT
Say N if unsure.
+config TASK_IO_ACCOUNTING
+ bool "Enable per-task storage I/O accounting (EXPERIMENTAL)"
+ depends on TASK_XACCT
+ help
+ Collect information on the number of bytes of storage I/O which this
+ task has caused.
+
+ Say N if unsure.
+
config SYSCTL
bool
@@ -339,7 +348,7 @@ config SYSCTL_SYSCALL
If unsure say Y here.
config KALLSYMS
- bool "Load all symbols for debugging/kksymoops" if EMBEDDED
+ bool "Load all symbols for debugging/ksymoops" if EMBEDDED
default y
help
Say Y here to let the kernel print out symbolic crash information and
@@ -441,7 +450,7 @@ config SHMEM
config SLAB
default y
- bool "Use full SLAB allocator" if EMBEDDED
+ bool "Use full SLAB allocator" if (EMBEDDED && !SMP && !SPARSEMEM)
help
Disabling this replaces the advanced SLAB allocator and
kmalloc support with the drastically simpler SLOB allocator.
@@ -452,10 +461,10 @@ config VM_EVENT_COUNTERS
default y
bool "Enable VM event counters for /proc/vmstat" if EMBEDDED
help
- VM event counters are only needed to for event counts to be
- shown. They have no function for the kernel itself. This
- option allows the disabling of the VM event counters.
- /proc/vmstat will only show page counts.
+ VM event counters are needed for event counts to be shown.
+ This option allows the disabling of the VM event counters
+ on EMBEDDED systems. /proc/vmstat will only show page counts
+ if VM event counters are disabled.
endmenu # General setup
diff --git a/init/initramfs.c b/init/initramfs.c
index 85f04037ade..4fa0f7977de 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -526,7 +526,7 @@ static void __init free_initrd(void)
#endif
-void __init populate_rootfs(void)
+static int __init populate_rootfs(void)
{
char *err = unpack_to_rootfs(__initramfs_start,
__initramfs_end - __initramfs_start, 0);
@@ -544,7 +544,7 @@ void __init populate_rootfs(void)
unpack_to_rootfs((char *)initrd_start,
initrd_end - initrd_start, 0);
free_initrd();
- return;
+ return 0;
}
printk("it isn't (%s); looks like an initrd\n", err);
fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
@@ -565,4 +565,6 @@ void __init populate_rootfs(void)
#endif
}
#endif
+ return 0;
}
+rootfs_initcall(populate_rootfs);
diff --git a/init/main.c b/init/main.c
index 1174ae3aec8..8b4a7d76916 100644
--- a/init/main.c
+++ b/init/main.c
@@ -50,6 +50,8 @@
#include <linux/buffer_head.h>
#include <linux/debug_locks.h>
#include <linux/lockdep.h>
+#include <linux/pid_namespace.h>
+#include <linux/device.h>
#include <asm/io.h>
#include <asm/bugs.h>
@@ -91,8 +93,6 @@ extern void pidmap_init(void);
extern void prio_tree_init(void);
extern void radix_tree_init(void);
extern void free_initmem(void);
-extern void populate_rootfs(void);
-extern void driver_init(void);
extern void prepare_namespace(void);
#ifdef CONFIG_ACPI
extern void acpi_early_init(void);
@@ -530,6 +530,11 @@ asmlinkage void __init start_kernel(void)
parse_args("Booting kernel", command_line, __start___param,
__stop___param - __start___param,
&unknown_bootoption);
+ if (!irqs_disabled()) {
+ printk(KERN_WARNING "start_kernel(): bug: interrupts were "
+ "enabled *very* early, fixing it\n");
+ local_irq_disable();
+ }
sort_main_extable();
trap_init();
rcu_init();
@@ -624,8 +629,6 @@ static int __init initcall_debug_setup(char *str)
}
__setup("initcall_debug", initcall_debug_setup);
-struct task_struct *child_reaper = &init_task;
-
extern initcall_t __initcall_start[], __initcall_end[];
static void __init do_initcalls(void)
@@ -692,7 +695,7 @@ static void __init do_basic_setup(void)
do_initcalls();
}
-static void do_pre_smp_initcalls(void)
+static void __init do_pre_smp_initcalls(void)
{
extern int spawn_ksoftirqd(void);
#ifdef CONFIG_SMP
@@ -725,7 +728,7 @@ static int init(void * unused)
* assumptions about where in the task array this
* can be found.
*/
- child_reaper = current;
+ init_pid_ns.child_reaper = current;
cad_pid = task_pid(current);
@@ -738,12 +741,6 @@ static int init(void * unused)
cpuset_init_smp();
- /*
- * Do this before initcalls, because some drivers want to access
- * firmware files.
- */
- populate_rootfs();
-
do_basic_setup();
/*
diff --git a/init/version.c b/init/version.c
index 8f28344d9c7..6c01ec1cc48 100644
--- a/init/version.c
+++ b/init/version.c
@@ -34,6 +34,12 @@ struct uts_namespace init_uts_ns = {
};
EXPORT_SYMBOL_GPL(init_uts_ns);
+/* FIXED STRINGS! Don't touch! */
const char linux_banner[] =
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
+
+const char linux_proc_banner[] =
+ "%s version %s"
+ " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")"
+ " (" LINUX_COMPILER ") %s\n";
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 3acc1661e51..02717f71d8d 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -322,7 +322,7 @@ static int mqueue_unlink(struct inode *dir, struct dentry *dentry)
static ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
size_t count, loff_t * off)
{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+ struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode);
char buffer[FILENT_SIZE];
size_t slen;
loff_t o;
@@ -354,13 +354,13 @@ static ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
return -EFAULT;
*off = o + count;
- filp->f_dentry->d_inode->i_atime = filp->f_dentry->d_inode->i_ctime = CURRENT_TIME;
+ filp->f_path.dentry->d_inode->i_atime = filp->f_path.dentry->d_inode->i_ctime = CURRENT_TIME;
return count;
}
static int mqueue_flush_file(struct file *filp, fl_owner_t id)
{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+ struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode);
spin_lock(&info->lock);
if (task_tgid(current) == info->notify_owner)
@@ -372,7 +372,7 @@ static int mqueue_flush_file(struct file *filp, fl_owner_t id)
static unsigned int mqueue_poll_file(struct file *filp, struct poll_table_struct *poll_tab)
{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+ struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode);
int retval = 0;
poll_wait(filp, &info->wait_q, poll_tab);
@@ -836,7 +836,7 @@ asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
if (unlikely(!filp))
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations))
goto out_fput;
info = MQUEUE_I(inode);
@@ -919,7 +919,7 @@ asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
if (unlikely(!filp))
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations))
goto out_fput;
info = MQUEUE_I(inode);
@@ -1056,7 +1056,7 @@ retry:
if (!filp)
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations))
goto out_fput;
info = MQUEUE_I(inode);
@@ -1126,7 +1126,7 @@ asmlinkage long sys_mq_getsetattr(mqd_t mqdes,
if (!filp)
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations))
goto out_fput;
info = MQUEUE_I(inode);
diff --git a/ipc/msgutil.c b/ipc/msgutil.c
index 0992616eeed..c82c215693d 100644
--- a/ipc/msgutil.c
+++ b/ipc/msgutil.c
@@ -36,7 +36,7 @@ struct msg_msg *load_msg(const void __user *src, int len)
if (alen > DATALEN_MSG)
alen = DATALEN_MSG;
- msg = (struct msg_msg *)kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
+ msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
if (msg == NULL)
return ERR_PTR(-ENOMEM);
@@ -56,7 +56,7 @@ struct msg_msg *load_msg(const void __user *src, int len)
alen = len;
if (alen > DATALEN_SEG)
alen = DATALEN_SEG;
- seg = (struct msg_msgseg *)kmalloc(sizeof(*seg) + alen,
+ seg = kmalloc(sizeof(*seg) + alen,
GFP_KERNEL);
if (seg == NULL) {
err = -ENOMEM;
diff --git a/ipc/shm.c b/ipc/shm.c
index d1198dd07a1..f8e10a25ad7 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -168,7 +168,7 @@ static inline void shm_inc(struct ipc_namespace *ns, int id)
static void shm_open(struct vm_area_struct *shmd)
{
shm_inc(shm_file_ns(shmd->vm_file),
- shmd->vm_file->f_dentry->d_inode->i_ino);
+ shmd->vm_file->f_path.dentry->d_inode->i_ino);
}
/*
@@ -187,7 +187,7 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
if (!is_file_hugepages(shp->shm_file))
shmem_lock(shp->shm_file, 0, shp->mlock_user);
else
- user_shm_unlock(shp->shm_file->f_dentry->d_inode->i_size,
+ user_shm_unlock(shp->shm_file->f_path.dentry->d_inode->i_size,
shp->mlock_user);
fput (shp->shm_file);
security_shm_free(shp);
@@ -203,7 +203,7 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
static void shm_close (struct vm_area_struct *shmd)
{
struct file * file = shmd->vm_file;
- int id = file->f_dentry->d_inode->i_ino;
+ int id = file->f_path.dentry->d_inode->i_ino;
struct shmid_kernel *shp;
struct ipc_namespace *ns;
@@ -233,7 +233,7 @@ 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(shm_file_ns(file), file->f_dentry->d_inode->i_ino);
+ shm_inc(shm_file_ns(file), file->f_path.dentry->d_inode->i_ino);
}
return ret;
@@ -279,7 +279,7 @@ static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size)
if (size < SHMMIN || size > ns->shm_ctlmax)
return -EINVAL;
- if (ns->shm_tot + numpages >= ns->shm_ctlall)
+ if (ns->shm_tot + numpages > ns->shm_ctlall)
return -ENOSPC;
shp = ipc_rcu_alloc(sizeof(*shp));
@@ -330,7 +330,7 @@ static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size)
shp->shm_nattch = 0;
shp->id = shm_buildid(ns, id, shp->shm_perm.seq);
shp->shm_file = file;
- file->f_dentry->d_inode->i_ino = shp->id;
+ file->f_path.dentry->d_inode->i_ino = shp->id;
shm_file_ns(file) = get_ipc_ns(ns);
@@ -495,7 +495,7 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
if(!shp)
continue;
- inode = shp->shm_file->f_dentry->d_inode;
+ inode = shp->shm_file->f_path.dentry->d_inode;
if (is_file_hugepages(shp->shm_file)) {
struct address_space *mapping = inode->i_mapping;
@@ -843,7 +843,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
}
file = shp->shm_file;
- size = i_size_read(file->f_dentry->d_inode);
+ size = i_size_read(file->f_path.dentry->d_inode);
shp->shm_nattch++;
shm_unlock(shp);
@@ -948,7 +948,7 @@ asmlinkage long sys_shmdt(char __user *shmaddr)
(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
- size = vma->vm_file->f_dentry->d_inode->i_size;
+ size = vma->vm_file->f_path.dentry->d_inode->i_size;
do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
/*
* We discovered the size of the shm segment, so
diff --git a/kernel/Makefile b/kernel/Makefile
index 5e3f3b75563..14f4d45e0ae 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -31,7 +31,6 @@ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
-obj-$(CONFIG_STACK_UNWIND) += unwind.o
obj-$(CONFIG_PM) += power/
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
obj-$(CONFIG_KEXEC) += kexec.o
diff --git a/kernel/acct.c b/kernel/acct.c
index dc12db8600e..70d0d88e555 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -118,7 +118,7 @@ static int check_free_space(struct file *file)
spin_unlock(&acct_globals.lock);
/* May block */
- if (vfs_statfs(file->f_dentry, &sbuf))
+ if (vfs_statfs(file->f_path.dentry, &sbuf))
return res;
suspend = sbuf.f_blocks * SUSPEND;
resume = sbuf.f_blocks * RESUME;
@@ -194,7 +194,7 @@ static void acct_file_reopen(struct file *file)
add_timer(&acct_globals.timer);
}
if (old_acct) {
- mnt_unpin(old_acct->f_vfsmnt);
+ mnt_unpin(old_acct->f_path.mnt);
spin_unlock(&acct_globals.lock);
do_acct_process(old_acct);
filp_close(old_acct, NULL);
@@ -212,7 +212,7 @@ static int acct_on(char *name)
if (IS_ERR(file))
return PTR_ERR(file);
- if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {
+ if (!S_ISREG(file->f_path.dentry->d_inode->i_mode)) {
filp_close(file, NULL);
return -EACCES;
}
@@ -229,11 +229,11 @@ static int acct_on(char *name)
}
spin_lock(&acct_globals.lock);
- mnt_pin(file->f_vfsmnt);
+ mnt_pin(file->f_path.mnt);
acct_file_reopen(file);
spin_unlock(&acct_globals.lock);
- mntput(file->f_vfsmnt); /* it's pinned, now give up active reference */
+ mntput(file->f_path.mnt); /* it's pinned, now give up active reference */
return 0;
}
@@ -283,7 +283,7 @@ asmlinkage long sys_acct(const char __user *name)
void acct_auto_close_mnt(struct vfsmount *m)
{
spin_lock(&acct_globals.lock);
- if (acct_globals.file && acct_globals.file->f_vfsmnt == m)
+ if (acct_globals.file && acct_globals.file->f_path.mnt == m)
acct_file_reopen(NULL);
spin_unlock(&acct_globals.lock);
}
@@ -299,7 +299,7 @@ void acct_auto_close(struct super_block *sb)
{
spin_lock(&acct_globals.lock);
if (acct_globals.file &&
- acct_globals.file->f_vfsmnt->mnt_sb == sb) {
+ acct_globals.file->f_path.mnt->mnt_sb == sb) {
acct_file_reopen(NULL);
}
spin_unlock(&acct_globals.lock);
@@ -428,6 +428,7 @@ static void do_acct_process(struct file *file)
u64 elapsed;
u64 run_time;
struct timespec uptime;
+ struct tty_struct *tty;
/*
* First check to see if there is enough free_space to continue
@@ -484,16 +485,9 @@ static void do_acct_process(struct file *file)
ac.ac_ppid = current->parent->tgid;
#endif
- 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);
+ tty = current->signal->tty;
+ ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0;
ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime)));
ac.ac_flag = pacct->ac_flag;
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 2e896f8ae29..9c8c23227c7 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -800,8 +800,8 @@ static inline int audit_dupe_selinux_field(struct audit_field *df,
/* our own copy of se_str */
se_str = kstrdup(sf->se_str, GFP_KERNEL);
- if (unlikely(IS_ERR(se_str)))
- return -ENOMEM;
+ if (unlikely(!se_str))
+ return -ENOMEM;
df->se_str = se_str;
/* our own (refreshed) copy of se_rule */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 40722e26de9..298897559ca 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -781,8 +781,8 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
if ((vma->vm_flags & VM_EXECUTABLE) &&
vma->vm_file) {
audit_log_d_path(ab, "exe=",
- vma->vm_file->f_dentry,
- vma->vm_file->f_vfsmnt);
+ vma->vm_file->f_path.dentry,
+ vma->vm_file->f_path.mnt);
break;
}
vma = vma->vm_next;
@@ -826,10 +826,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
context->return_code);
mutex_lock(&tty_mutex);
+ read_lock(&tasklist_lock);
if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
tty = tsk->signal->tty->name;
else
tty = "(none)";
+ read_unlock(&tasklist_lock);
audit_log_format(ab,
" a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
" ppid=%d pid=%d auid=%u uid=%u gid=%u"
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 9124669f458..7406fe6966f 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -204,7 +204,7 @@ int cpu_down(unsigned int cpu)
#endif /*CONFIG_HOTPLUG_CPU*/
/* Requires cpu_add_remove_lock to be held */
-static int __devinit _cpu_up(unsigned int cpu)
+static int __cpuinit _cpu_up(unsigned int cpu)
{
int ret;
void *hcpu = (void *)(long)cpu;
@@ -239,7 +239,7 @@ out_notify:
return ret;
}
-int __devinit cpu_up(unsigned int cpu)
+int __cpuinit cpu_up(unsigned int cpu)
{
int err = 0;
@@ -258,7 +258,7 @@ static cpumask_t frozen_cpus;
int disable_nonboot_cpus(void)
{
- int cpu, first_cpu, error;
+ int cpu, first_cpu, error = 0;
mutex_lock(&cpu_add_remove_lock);
first_cpu = first_cpu(cpu_present_map);
@@ -294,7 +294,7 @@ int disable_nonboot_cpus(void)
/* Make sure the CPUs won't be enabled by someone else */
cpu_hotplug_disabled = 1;
} else {
- printk(KERN_ERR "Non-boot CPUs are not disabled");
+ printk(KERN_ERR "Non-boot CPUs are not disabled\n");
}
out:
mutex_unlock(&cpu_add_remove_lock);
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 0a6b4d89f9a..6b05dc69c95 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -413,8 +413,8 @@ static struct file_system_type cpuset_fs_type = {
*
*
* When reading/writing to a file:
- * - the cpuset to use in file->f_dentry->d_parent->d_fsdata
- * - the 'cftype' of the file is file->f_dentry->d_fsdata
+ * - the cpuset to use in file->f_path.dentry->d_parent->d_fsdata
+ * - the 'cftype' of the file is file->f_path.dentry->d_fsdata
*/
struct cftype {
@@ -1284,8 +1284,8 @@ static ssize_t cpuset_common_file_write(struct file *file,
const char __user *userbuf,
size_t nbytes, loff_t *unused_ppos)
{
- struct cpuset *cs = __d_cs(file->f_dentry->d_parent);
- struct cftype *cft = __d_cft(file->f_dentry);
+ struct cpuset *cs = __d_cs(file->f_path.dentry->d_parent);
+ struct cftype *cft = __d_cft(file->f_path.dentry);
cpuset_filetype_t type = cft->private;
char *buffer;
char *pathbuf = NULL;
@@ -1367,7 +1367,7 @@ static ssize_t cpuset_file_write(struct file *file, const char __user *buf,
size_t nbytes, loff_t *ppos)
{
ssize_t retval = 0;
- struct cftype *cft = __d_cft(file->f_dentry);
+ struct cftype *cft = __d_cft(file->f_path.dentry);
if (!cft)
return -ENODEV;
@@ -1417,8 +1417,8 @@ static int cpuset_sprintf_memlist(char *page, struct cpuset *cs)
static ssize_t cpuset_common_file_read(struct file *file, char __user *buf,
size_t nbytes, loff_t *ppos)
{
- struct cftype *cft = __d_cft(file->f_dentry);
- struct cpuset *cs = __d_cs(file->f_dentry->d_parent);
+ struct cftype *cft = __d_cft(file->f_path.dentry);
+ struct cpuset *cs = __d_cs(file->f_path.dentry->d_parent);
cpuset_filetype_t type = cft->private;
char *page;
ssize_t retval = 0;
@@ -1476,7 +1476,7 @@ static ssize_t cpuset_file_read(struct file *file, char __user *buf, size_t nbyt
loff_t *ppos)
{
ssize_t retval = 0;
- struct cftype *cft = __d_cft(file->f_dentry);
+ struct cftype *cft = __d_cft(file->f_path.dentry);
if (!cft)
return -ENODEV;
@@ -1498,7 +1498,7 @@ static int cpuset_file_open(struct inode *inode, struct file *file)
if (err)
return err;
- cft = __d_cft(file->f_dentry);
+ cft = __d_cft(file->f_path.dentry);
if (!cft)
return -ENODEV;
if (cft->open)
@@ -1511,7 +1511,7 @@ static int cpuset_file_open(struct inode *inode, struct file *file)
static int cpuset_file_release(struct inode *inode, struct file *file)
{
- struct cftype *cft = __d_cft(file->f_dentry);
+ struct cftype *cft = __d_cft(file->f_path.dentry);
if (cft->release)
return cft->release(inode, file);
return 0;
@@ -1700,7 +1700,7 @@ static int pid_array_to_buf(char *buf, int sz, pid_t *a, int npids)
*/
static int cpuset_tasks_open(struct inode *unused, struct file *file)
{
- struct cpuset *cs = __d_cs(file->f_dentry->d_parent);
+ struct cpuset *cs = __d_cs(file->f_path.dentry->d_parent);
struct ctr_struct *ctr;
pid_t *pidarray;
int npids;
@@ -2342,32 +2342,48 @@ static const struct cpuset *nearest_exclusive_ancestor(const struct cpuset *cs)
}
/**
- * cpuset_zone_allowed - Can we allocate memory on zone z's memory node?
+ * cpuset_zone_allowed_softwall - Can we allocate on zone z's memory node?
* @z: is this zone on an allowed node?
- * @gfp_mask: memory allocation flags (we use __GFP_HARDWALL)
+ * @gfp_mask: memory allocation flags
*
- * If we're in interrupt, yes, we can always allocate. If zone
+ * If we're in interrupt, yes, we can always allocate. If
+ * __GFP_THISNODE is set, yes, we can always allocate. If zone
* z's node is in our tasks mems_allowed, yes. If it's not a
* __GFP_HARDWALL request and this zone's nodes is in the nearest
* mem_exclusive cpuset ancestor to this tasks cpuset, yes.
* Otherwise, no.
*
+ * If __GFP_HARDWALL is set, cpuset_zone_allowed_softwall()
+ * reduces to cpuset_zone_allowed_hardwall(). Otherwise,
+ * cpuset_zone_allowed_softwall() might sleep, and might allow a zone
+ * from an enclosing cpuset.
+ *
+ * cpuset_zone_allowed_hardwall() only handles the simpler case of
+ * hardwall cpusets, and never sleeps.
+ *
+ * The __GFP_THISNODE placement logic is really handled elsewhere,
+ * by forcibly using a zonelist starting at a specified node, and by
+ * (in get_page_from_freelist()) refusing to consider the zones for
+ * any node on the zonelist except the first. By the time any such
+ * calls get to this routine, we should just shut up and say 'yes'.
+ *
* GFP_USER allocations are marked with the __GFP_HARDWALL bit,
* and do not allow allocations outside the current tasks cpuset.
* GFP_KERNEL allocations are not so marked, so can escape to the
- * nearest mem_exclusive ancestor cpuset.
+ * nearest enclosing mem_exclusive ancestor cpuset.
*
- * Scanning up parent cpusets requires callback_mutex. The __alloc_pages()
- * routine only calls here with __GFP_HARDWALL bit _not_ set if
- * it's a GFP_KERNEL allocation, and all nodes in the current tasks
- * mems_allowed came up empty on the first pass over the zonelist.
- * So only GFP_KERNEL allocations, if all nodes in the cpuset are
- * short of memory, might require taking the callback_mutex mutex.
+ * Scanning up parent cpusets requires callback_mutex. The
+ * __alloc_pages() routine only calls here with __GFP_HARDWALL bit
+ * _not_ set if it's a GFP_KERNEL allocation, and all nodes in the
+ * current tasks mems_allowed came up empty on the first pass over
+ * the zonelist. So only GFP_KERNEL allocations, if all nodes in the
+ * cpuset are short of memory, might require taking the callback_mutex
+ * mutex.
*
* The first call here from mm/page_alloc:get_page_from_freelist()
- * has __GFP_HARDWALL set in gfp_mask, enforcing hardwall cpusets, so
- * no allocation on a node outside the cpuset is allowed (unless in
- * interrupt, of course).
+ * has __GFP_HARDWALL set in gfp_mask, enforcing hardwall cpusets,
+ * so no allocation on a node outside the cpuset is allowed (unless
+ * in interrupt, of course).
*
* The second pass through get_page_from_freelist() doesn't even call
* here for GFP_ATOMIC calls. For those calls, the __alloc_pages()
@@ -2380,12 +2396,12 @@ static const struct cpuset *nearest_exclusive_ancestor(const struct cpuset *cs)
* GFP_USER - only nodes in current tasks mems allowed ok.
*
* Rule:
- * Don't call cpuset_zone_allowed() if you can't sleep, unless you
+ * Don't call cpuset_zone_allowed_softwall if you can't sleep, unless you
* pass in the __GFP_HARDWALL flag set in gfp_flag, which disables
* the code that might scan up ancestor cpusets and sleep.
- **/
+ */
-int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
+int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
{
int node; /* node that zone z is on */
const struct cpuset *cs; /* current cpuset ancestors */
@@ -2415,6 +2431,40 @@ int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
return allowed;
}
+/*
+ * cpuset_zone_allowed_hardwall - Can we allocate on zone z's memory node?
+ * @z: is this zone on an allowed node?
+ * @gfp_mask: memory allocation flags
+ *
+ * If we're in interrupt, yes, we can always allocate.
+ * If __GFP_THISNODE is set, yes, we can always allocate. If zone
+ * z's node is in our tasks mems_allowed, yes. Otherwise, no.
+ *
+ * The __GFP_THISNODE placement logic is really handled elsewhere,
+ * by forcibly using a zonelist starting at a specified node, and by
+ * (in get_page_from_freelist()) refusing to consider the zones for
+ * any node on the zonelist except the first. By the time any such
+ * calls get to this routine, we should just shut up and say 'yes'.
+ *
+ * Unlike the cpuset_zone_allowed_softwall() variant, above,
+ * this variant requires that the zone be in the current tasks
+ * mems_allowed or that we're in interrupt. It does not scan up the
+ * cpuset hierarchy for the nearest enclosing mem_exclusive cpuset.
+ * It never sleeps.
+ */
+
+int __cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
+{
+ int node; /* node that zone z is on */
+
+ if (in_interrupt() || (gfp_mask & __GFP_THISNODE))
+ return 1;
+ node = zone_to_nid(z);
+ if (node_isset(node, current->mems_allowed))
+ return 1;
+ return 0;
+}
+
/**
* cpuset_lock - lock out any changes to cpuset structures
*
@@ -2606,7 +2656,7 @@ static int cpuset_open(struct inode *inode, struct file *file)
return single_open(file, proc_cpuset_show, pid);
}
-const struct file_operations proc_cpuset_operations = {
+struct file_operations proc_cpuset_operations = {
.open = cpuset_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/kernel/exit.c b/kernel/exit.c
index 4e3f919edc4..fec12eb1247 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -13,7 +13,7 @@
#include <linux/completion.h>
#include <linux/personality.h>
#include <linux/tty.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/key.h>
#include <linux/security.h>
#include <linux/cpu.h>
@@ -22,6 +22,7 @@
#include <linux/file.h>
#include <linux/binfmts.h>
#include <linux/nsproxy.h>
+#include <linux/pid_namespace.h>
#include <linux/ptrace.h>
#include <linux/profile.h>
#include <linux/mount.h>
@@ -48,7 +49,6 @@
#include <asm/mmu_context.h>
extern void sem_exit (void);
-extern struct task_struct *child_reaper;
static void exit_mm(struct task_struct * tsk);
@@ -189,21 +189,18 @@ repeat:
int session_of_pgrp(int pgrp)
{
struct task_struct *p;
- int sid = -1;
+ int sid = 0;
read_lock(&tasklist_lock);
- do_each_task_pid(pgrp, PIDTYPE_PGID, p) {
- if (p->signal->session > 0) {
- sid = p->signal->session;
- goto out;
- }
- } while_each_task_pid(pgrp, PIDTYPE_PGID, p);
- p = find_task_by_pid(pgrp);
- if (p)
- sid = p->signal->session;
-out:
+
+ p = find_task_by_pid_type(PIDTYPE_PGID, pgrp);
+ if (p == NULL)
+ p = find_task_by_pid(pgrp);
+ if (p != NULL)
+ sid = process_session(p);
+
read_unlock(&tasklist_lock);
-
+
return sid;
}
@@ -225,8 +222,8 @@ static int will_become_orphaned_pgrp(int pgrp, struct task_struct *ignored_task)
|| p->exit_state
|| is_init(p->real_parent))
continue;
- if (process_group(p->real_parent) != pgrp
- && p->real_parent->signal->session == p->signal->session) {
+ if (process_group(p->real_parent) != pgrp &&
+ process_session(p->real_parent) == process_session(p)) {
ret = 0;
break;
}
@@ -260,7 +257,8 @@ static int has_stopped_jobs(int pgrp)
}
/**
- * reparent_to_init - Reparent the calling kernel thread to the init task.
+ * reparent_to_init - Reparent the calling kernel thread to the init task
+ * of the pid space that the thread belongs to.
*
* If a kernel thread is launched as a result of a system call, or if
* it ever exits, it should generally reparent itself to init so that
@@ -278,8 +276,8 @@ static void reparent_to_init(void)
ptrace_unlink(current);
/* Reparent to init */
remove_parent(current);
- current->parent = child_reaper;
- current->real_parent = child_reaper;
+ current->parent = child_reaper(current);
+ current->real_parent = child_reaper(current);
add_parent(current);
/* Set the exit signal to SIGCHLD so we signal init on exit */
@@ -302,9 +300,9 @@ void __set_special_pids(pid_t session, pid_t pgrp)
{
struct task_struct *curr = current->group_leader;
- if (curr->signal->session != session) {
+ if (process_session(curr) != session) {
detach_pid(curr, PIDTYPE_SID);
- curr->signal->session = session;
+ set_signal_session(curr->signal, session);
attach_pid(curr, PIDTYPE_SID, session);
}
if (process_group(curr) != pgrp) {
@@ -314,7 +312,7 @@ void __set_special_pids(pid_t session, pid_t pgrp)
}
}
-void set_special_pids(pid_t session, pid_t pgrp)
+static void set_special_pids(pid_t session, pid_t pgrp)
{
write_lock_irq(&tasklist_lock);
__set_special_pids(session, pgrp);
@@ -384,9 +382,7 @@ void daemonize(const char *name, ...)
exit_mm(current);
set_special_pids(1, 1);
- mutex_lock(&tty_mutex);
- current->signal->tty = NULL;
- mutex_unlock(&tty_mutex);
+ proc_clear_tty(current);
/* Block and flush all signals */
sigfillset(&blocked);
@@ -429,7 +425,7 @@ static void close_files(struct files_struct * files)
for (;;) {
unsigned long set;
i = j * __NFDBITS;
- if (i >= fdt->max_fdset || i >= fdt->max_fds)
+ if (i >= fdt->max_fds)
break;
set = fdt->open_fds->fds_bits[j++];
while (set) {
@@ -470,9 +466,7 @@ void fastcall put_files_struct(struct files_struct *files)
* you can free files immediately.
*/
fdt = files_fdtable(files);
- if (fdt == &files->fdtab)
- fdt->free_files = files;
- else
+ if (fdt != &files->fdtab)
kmem_cache_free(files_cachep, files);
free_fdtable(fdt);
}
@@ -603,10 +597,6 @@ choose_new_parent(struct task_struct *p, struct task_struct *reaper)
static void
reparent_thread(struct task_struct *p, struct task_struct *father, int traced)
{
- /* We don't want people slaying init. */
- if (p->exit_signal != -1)
- p->exit_signal = SIGCHLD;
-
if (p->pdeath_signal)
/* We already hold the tasklist_lock here. */
group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p);
@@ -626,13 +616,7 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced)
p->parent = p->real_parent;
add_parent(p);
- /* If we'd notified the old parent about this child's death,
- * also notify the new parent.
- */
- if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 &&
- thread_group_empty(p))
- do_notify_parent(p, p->exit_signal);
- else if (p->state == TASK_TRACED) {
+ if (p->state == TASK_TRACED) {
/*
* If it was at a trace stop, turn it into
* a normal stop since it's no longer being
@@ -642,6 +626,23 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced)
}
}
+ /* If this is a threaded reparent there is no need to
+ * notify anyone anything has happened.
+ */
+ if (p->real_parent->group_leader == father->group_leader)
+ return;
+
+ /* We don't want people slaying init. */
+ if (p->exit_signal != -1)
+ p->exit_signal = SIGCHLD;
+
+ /* If we'd notified the old parent about this child's death,
+ * also notify the new parent.
+ */
+ if (!traced && p->exit_state == EXIT_ZOMBIE &&
+ p->exit_signal != -1 && thread_group_empty(p))
+ do_notify_parent(p, p->exit_signal);
+
/*
* process group orphan check
* Case ii: Our child is in a different pgrp
@@ -649,10 +650,11 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced)
* outside, so the child pgrp is now orphaned.
*/
if ((process_group(p) != process_group(father)) &&
- (p->signal->session == father->signal->session)) {
+ (process_session(p) == process_session(father))) {
int pgrp = process_group(p);
- if (will_become_orphaned_pgrp(pgrp, NULL) && has_stopped_jobs(pgrp)) {
+ if (will_become_orphaned_pgrp(pgrp, NULL) &&
+ has_stopped_jobs(pgrp)) {
__kill_pg_info(SIGHUP, SEND_SIG_PRIV, pgrp);
__kill_pg_info(SIGCONT, SEND_SIG_PRIV, pgrp);
}
@@ -663,7 +665,8 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced)
* When we die, we re-parent all our children.
* Try to give them to another thread in our thread
* group, and if no such member exists, give it to
- * the global child reaper process (ie "init")
+ * the child reaper process (ie "init") in our pid
+ * space.
*/
static void
forget_original_parent(struct task_struct *father, struct list_head *to_release)
@@ -674,7 +677,7 @@ forget_original_parent(struct task_struct *father, struct list_head *to_release)
do {
reaper = next_thread(reaper);
if (reaper == father) {
- reaper = child_reaper;
+ reaper = child_reaper(father);
break;
}
} while (reaper->exit_state);
@@ -786,7 +789,7 @@ static void exit_notify(struct task_struct *tsk)
t = tsk->real_parent;
if ((process_group(t) != process_group(tsk)) &&
- (t->signal->session == tsk->signal->session) &&
+ (process_session(t) == process_session(tsk)) &&
will_become_orphaned_pgrp(process_group(tsk), tsk) &&
has_stopped_jobs(process_group(tsk))) {
__kill_pg_info(SIGHUP, SEND_SIG_PRIV, process_group(tsk));
@@ -860,8 +863,13 @@ fastcall NORET_TYPE void do_exit(long code)
panic("Aiee, killing interrupt handler!");
if (unlikely(!tsk->pid))
panic("Attempted to kill the idle task!");
- if (unlikely(tsk == child_reaper))
- panic("Attempted to kill init!");
+ if (unlikely(tsk == child_reaper(tsk))) {
+ if (tsk->nsproxy->pid_ns != &init_pid_ns)
+ tsk->nsproxy->pid_ns->child_reaper = init_pid_ns.child_reaper;
+ else
+ panic("Attempted to kill init!");
+ }
+
if (unlikely(current->ptrace & PT_TRACE_EXIT)) {
current->ptrace_message = code;
@@ -930,8 +938,8 @@ fastcall NORET_TYPE void do_exit(long code)
tsk->exit_code = code;
proc_exit_connector(tsk);
- exit_notify(tsk);
exit_task_namespaces(tsk);
+ exit_notify(tsk);
#ifdef CONFIG_NUMA
mpol_free(tsk->mempolicy);
tsk->mempolicy = NULL;
diff --git a/kernel/fork.c b/kernel/fork.c
index 7f2e31ba33a..d57118da73f 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -18,7 +18,7 @@
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/completion.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/personality.h>
#include <linux/mempolicy.h>
#include <linux/sem.h>
@@ -36,6 +36,7 @@
#include <linux/syscalls.h>
#include <linux/jiffies.h>
#include <linux/futex.h>
+#include <linux/task_io_accounting_ops.h>
#include <linux/rcupdate.h>
#include <linux/ptrace.h>
#include <linux/mount.h>
@@ -202,7 +203,7 @@ static inline int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
struct mempolicy *pol;
down_write(&oldmm->mmap_sem);
- flush_cache_mm(oldmm);
+ flush_cache_dup_mm(oldmm);
/*
* Not linked in yet - no deadlock potential:
*/
@@ -252,7 +253,7 @@ static inline int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
anon_vma_link(tmp);
file = tmp->vm_file;
if (file) {
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
get_file(file);
if (tmp->vm_flags & VM_DENYWRITE)
atomic_dec(&inode->i_writecount);
@@ -613,7 +614,7 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk)
static int count_open_files(struct fdtable *fdt)
{
- int size = fdt->max_fdset;
+ int size = fdt->max_fds;
int i;
/* Find the last open fd */
@@ -640,12 +641,10 @@ static struct files_struct *alloc_files(void)
newf->next_fd = 0;
fdt = &newf->fdtab;
fdt->max_fds = NR_OPEN_DEFAULT;
- fdt->max_fdset = EMBEDDED_FD_SET_SIZE;
fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init;
fdt->open_fds = (fd_set *)&newf->open_fds_init;
fdt->fd = &newf->fd_array[0];
INIT_RCU_HEAD(&fdt->rcu);
- fdt->free_files = NULL;
fdt->next = NULL;
rcu_assign_pointer(newf->fdt, fdt);
out:
@@ -661,7 +660,7 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
{
struct files_struct *newf;
struct file **old_fds, **new_fds;
- int open_files, size, i, expand;
+ int open_files, size, i;
struct fdtable *old_fdt, *new_fdt;
*errorp = -ENOMEM;
@@ -672,25 +671,14 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
spin_lock(&oldf->file_lock);
old_fdt = files_fdtable(oldf);
new_fdt = files_fdtable(newf);
- size = old_fdt->max_fdset;
open_files = count_open_files(old_fdt);
- expand = 0;
/*
- * Check whether we need to allocate a larger fd array or fd set.
- * Note: we're not a clone task, so the open count won't change.
+ * Check whether we need to allocate a larger fd array and fd set.
+ * Note: we're not a clone task, so the open count won't change.
*/
- if (open_files > new_fdt->max_fdset) {
- new_fdt->max_fdset = 0;
- expand = 1;
- }
if (open_files > new_fdt->max_fds) {
new_fdt->max_fds = 0;
- expand = 1;
- }
-
- /* if the old fdset gets grown now, we'll only copy up to "size" fds */
- if (expand) {
spin_unlock(&oldf->file_lock);
spin_lock(&newf->file_lock);
*errorp = expand_files(newf, open_files-1);
@@ -710,8 +698,10 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
old_fds = old_fdt->fd;
new_fds = new_fdt->fd;
- memcpy(new_fdt->open_fds->fds_bits, old_fdt->open_fds->fds_bits, open_files/8);
- memcpy(new_fdt->close_on_exec->fds_bits, old_fdt->close_on_exec->fds_bits, open_files/8);
+ memcpy(new_fdt->open_fds->fds_bits,
+ old_fdt->open_fds->fds_bits, open_files/8);
+ memcpy(new_fdt->close_on_exec->fds_bits,
+ old_fdt->close_on_exec->fds_bits, open_files/8);
for (i = open_files; i != 0; i--) {
struct file *f = *old_fds++;
@@ -736,22 +726,19 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
/* This is long word aligned thus could use a optimized version */
memset(new_fds, 0, size);
- if (new_fdt->max_fdset > open_files) {
- int left = (new_fdt->max_fdset-open_files)/8;
+ if (new_fdt->max_fds > open_files) {
+ int left = (new_fdt->max_fds-open_files)/8;
int start = open_files / (8 * sizeof(unsigned long));
memset(&new_fdt->open_fds->fds_bits[start], 0, left);
memset(&new_fdt->close_on_exec->fds_bits[start], 0, left);
}
-out:
return newf;
out_release:
- free_fdset (new_fdt->close_on_exec, new_fdt->max_fdset);
- free_fdset (new_fdt->open_fds, new_fdt->max_fdset);
- free_fd_array(new_fdt->fd, new_fdt->max_fds);
kmem_cache_free(files_cachep, newf);
+out:
return NULL;
}
@@ -1055,6 +1042,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->wchar = 0; /* I/O counter: bytes written */
p->syscr = 0; /* I/O counter: read syscalls */
p->syscw = 0; /* I/O counter: write syscalls */
+ task_io_accounting_init(p);
acct_clear_integrals(p);
p->it_virt_expires = cputime_zero;
@@ -1259,9 +1247,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
if (thread_group_leader(p)) {
p->signal->tty = current->signal->tty;
p->signal->pgrp = process_group(current);
- p->signal->session = current->signal->session;
+ set_signal_session(p->signal, process_session(current));
attach_pid(p, PIDTYPE_PGID, process_group(p));
- attach_pid(p, PIDTYPE_SID, p->signal->session);
+ attach_pid(p, PIDTYPE_SID, process_session(p));
list_add_tail_rcu(&p->tasks, &init_task.tasks);
__get_cpu_var(process_counts)++;
@@ -1325,7 +1313,7 @@ noinline struct pt_regs * __devinit __attribute__((weak)) idle_regs(struct pt_re
return regs;
}
-struct task_struct * __devinit fork_idle(int cpu)
+struct task_struct * __cpuinit fork_idle(int cpu)
{
struct task_struct *task;
struct pt_regs regs;
@@ -1525,17 +1513,18 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
}
/*
- * Unshare the namespace structure if it is being shared
+ * Unshare the mnt_namespace structure if it is being shared
*/
-static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs)
+static int unshare_mnt_namespace(unsigned long unshare_flags,
+ struct mnt_namespace **new_nsp, struct fs_struct *new_fs)
{
- struct namespace *ns = current->nsproxy->namespace;
+ struct mnt_namespace *ns = current->nsproxy->mnt_ns;
if ((unshare_flags & CLONE_NEWNS) && ns) {
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- *new_nsp = dup_namespace(current, new_fs ? new_fs : current->fs);
+ *new_nsp = dup_mnt_ns(current, new_fs ? new_fs : current->fs);
if (!*new_nsp)
return -ENOMEM;
}
@@ -1544,15 +1533,13 @@ static int unshare_namespace(unsigned long unshare_flags, struct namespace **new
}
/*
- * Unsharing of sighand for tasks created with CLONE_SIGHAND is not
- * supported yet
+ * Unsharing of sighand is not supported yet
*/
static int unshare_sighand(unsigned long unshare_flags, struct sighand_struct **new_sighp)
{
struct sighand_struct *sigh = current->sighand;
- if ((unshare_flags & CLONE_SIGHAND) &&
- (sigh && atomic_read(&sigh->count) > 1))
+ if ((unshare_flags & CLONE_SIGHAND) && atomic_read(&sigh->count) > 1)
return -EINVAL;
else
return 0;
@@ -1625,8 +1612,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
{
int err = 0;
struct fs_struct *fs, *new_fs = NULL;
- struct namespace *ns, *new_ns = NULL;
- struct sighand_struct *sigh, *new_sigh = NULL;
+ struct mnt_namespace *ns, *new_ns = NULL;
+ struct sighand_struct *new_sigh = NULL;
struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL;
struct files_struct *fd, *new_fd = NULL;
struct sem_undo_list *new_ulist = NULL;
@@ -1647,7 +1634,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
goto bad_unshare_out;
if ((err = unshare_fs(unshare_flags, &new_fs)))
goto bad_unshare_cleanup_thread;
- if ((err = unshare_namespace(unshare_flags, &new_ns, new_fs)))
+ if ((err = unshare_mnt_namespace(unshare_flags, &new_ns, new_fs)))
goto bad_unshare_cleanup_fs;
if ((err = unshare_sighand(unshare_flags, &new_sigh)))
goto bad_unshare_cleanup_ns;
@@ -1671,7 +1658,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
}
}
- if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist ||
+ if (new_fs || new_ns || new_mm || new_fd || new_ulist ||
new_uts || new_ipc) {
task_lock(current);
@@ -1688,17 +1675,11 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
}
if (new_ns) {
- ns = current->nsproxy->namespace;
- current->nsproxy->namespace = new_ns;
+ ns = current->nsproxy->mnt_ns;
+ current->nsproxy->mnt_ns = new_ns;
new_ns = ns;
}
- if (new_sigh) {
- sigh = current->sighand;
- rcu_assign_pointer(current->sighand, new_sigh);
- new_sigh = sigh;
- }
-
if (new_mm) {
mm = current->mm;
active_mm = current->active_mm;
@@ -1756,7 +1737,7 @@ bad_unshare_cleanup_sigh:
bad_unshare_cleanup_ns:
if (new_ns)
- put_namespace(new_ns);
+ put_mnt_ns(new_ns);
bad_unshare_cleanup_fs:
if (new_fs)
diff --git a/kernel/futex.c b/kernel/futex.c
index 95989a3b416..5a737de857d 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -166,7 +166,7 @@ static inline int match_futex(union futex_key *key1, union futex_key *key2)
/*
* Get parameters which are the keys for a futex.
*
- * For shared mappings, it's (page->index, vma->vm_file->f_dentry->d_inode,
+ * For shared mappings, it's (page->index, vma->vm_file->f_path.dentry->d_inode,
* offset_within_page). For private mappings, it's (uaddr, current->mm).
* We can usually work out the index without swapping in the page.
*
@@ -223,7 +223,7 @@ static int get_futex_key(u32 __user *uaddr, union futex_key *key)
/*
* Linear file mappings are also simple.
*/
- key->shared.inode = vma->vm_file->f_dentry->d_inode;
+ key->shared.inode = vma->vm_file->f_path.dentry->d_inode;
key->both.offset++; /* Bit 0 of offset indicates inode-based key. */
if (likely(!(vma->vm_flags & VM_NONLINEAR))) {
key->shared.pgoff = (((address - vma->vm_start) >> PAGE_SHIFT)
@@ -1528,9 +1528,9 @@ static int futex_fd(u32 __user *uaddr, int signal)
goto out;
}
filp->f_op = &futex_fops;
- filp->f_vfsmnt = mntget(futex_mnt);
- filp->f_dentry = dget(futex_mnt->mnt_root);
- filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+ filp->f_path.mnt = mntget(futex_mnt);
+ filp->f_path.dentry = dget(futex_mnt->mnt_root);
+ filp->f_mapping = filp->f_path.dentry->d_inode->i_mapping;
if (signal) {
err = __f_setown(filp, task_pid(current), PIDTYPE_PID, 1);
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index ebfd24a4185..475e8a71bcd 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -39,6 +39,7 @@ void dynamic_irq_init(unsigned int irq)
desc->chip = &no_irq_chip;
desc->handle_irq = handle_bad_irq;
desc->depth = 1;
+ desc->msi_desc = NULL;
desc->handler_data = NULL;
desc->chip_data = NULL;
desc->action = NULL;
@@ -74,6 +75,9 @@ void dynamic_irq_cleanup(unsigned int irq)
WARN_ON(1);
return;
}
+ desc->msi_desc = NULL;
+ desc->handler_data = NULL;
+ desc->chip_data = NULL;
desc->handle_irq = handle_bad_irq;
desc->chip = &no_irq_chip;
spin_unlock_irqrestore(&desc->lock, flags);
@@ -162,6 +166,30 @@ int set_irq_data(unsigned int irq, void *data)
EXPORT_SYMBOL(set_irq_data);
/**
+ * set_irq_data - set irq type data for an irq
+ * @irq: Interrupt number
+ * @data: Pointer to interrupt specific data
+ *
+ * Set the hardware irq controller data for an irq
+ */
+int set_irq_msi(unsigned int irq, struct msi_desc *entry)
+{
+ struct irq_desc *desc;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS) {
+ printk(KERN_ERR
+ "Trying to install msi data for IRQ%d\n", irq);
+ return -EINVAL;
+ }
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock, flags);
+ desc->msi_desc = entry;
+ spin_unlock_irqrestore(&desc->lock, flags);
+ return 0;
+}
+
+/**
* set_irq_chip_data - set irq chip data for an irq
* @irq: Interrupt number
* @data: Pointer to chip specific data
@@ -517,10 +545,9 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
if (!handle)
handle = handle_bad_irq;
-
- if (desc->chip == &no_irq_chip) {
+ else if (desc->chip == &no_irq_chip) {
printk(KERN_WARNING "Trying to install %sinterrupt handler "
- "for IRQ%d\n", is_chained ? "chained " : " ", irq);
+ "for IRQ%d\n", is_chained ? "chained " : "", irq);
/*
* Some ARM implementations install a handler for really dumb
* interrupt hardware without setting an irq_chip. This worked
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index b385878c6e8..c4b7ed1cebf 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -315,6 +315,9 @@ int setup_irq(unsigned int irq, struct irqaction *new)
/* Undo nested disables: */
desc->depth = 1;
}
+ /* Reset broken irq detection when installing new handler */
+ desc->irq_count = 0;
+ desc->irqs_unhandled = 0;
spin_unlock_irqrestore(&desc->lock, flags);
new->irq = irq;
@@ -479,3 +482,89 @@ int request_irq(unsigned int irq, irq_handler_t handler,
return retval;
}
EXPORT_SYMBOL(request_irq);
+
+/*
+ * Device resource management aware IRQ request/free implementation.
+ */
+struct irq_devres {
+ unsigned int irq;
+ void *dev_id;
+};
+
+static void devm_irq_release(struct device *dev, void *res)
+{
+ struct irq_devres *this = res;
+
+ free_irq(this->irq, this->dev_id);
+}
+
+static int devm_irq_match(struct device *dev, void *res, void *data)
+{
+ struct irq_devres *this = res, *match = data;
+
+ return this->irq == match->irq && this->dev_id == match->dev_id;
+}
+
+/**
+ * devm_request_irq - allocate an interrupt line for a managed device
+ * @dev: device to request interrupt for
+ * @irq: Interrupt line to allocate
+ * @handler: Function to be called when the IRQ occurs
+ * @irqflags: Interrupt type flags
+ * @devname: An ascii name for the claiming device
+ * @dev_id: A cookie passed back to the handler function
+ *
+ * Except for the extra @dev argument, this function takes the
+ * same arguments and performs the same function as
+ * request_irq(). IRQs requested with this function will be
+ * automatically freed on driver detach.
+ *
+ * If an IRQ allocated with this function needs to be freed
+ * separately, dev_free_irq() must be used.
+ */
+int devm_request_irq(struct device *dev, unsigned int irq,
+ irq_handler_t handler, unsigned long irqflags,
+ const char *devname, void *dev_id)
+{
+ struct irq_devres *dr;
+ int rc;
+
+ dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres),
+ GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ rc = request_irq(irq, handler, irqflags, devname, dev_id);
+ if (rc) {
+ kfree(dr);
+ return rc;
+ }
+
+ dr->irq = irq;
+ dr->dev_id = dev_id;
+ devres_add(dev, dr);
+
+ return 0;
+}
+EXPORT_SYMBOL(devm_request_irq);
+
+/**
+ * devm_free_irq - free an interrupt
+ * @dev: device to free interrupt for
+ * @irq: Interrupt line to free
+ * @dev_id: Device identity to free
+ *
+ * Except for the extra @dev argument, this function takes the
+ * same arguments and performs the same function as free_irq().
+ * This function instead of free_irq() should be used to manually
+ * free IRQs allocated with dev_request_irq().
+ */
+void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id)
+{
+ struct irq_devres match_data = { irq, dev_id };
+
+ free_irq(irq, dev_id);
+ WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match,
+ &match_data));
+}
+EXPORT_SYMBOL(devm_free_irq);
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 9a352667007..61f5c717a8f 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -54,7 +54,8 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
unsigned int irq = (int)(long)data, full_count = count, err;
cpumask_t new_value, tmp;
- if (!irq_desc[irq].chip->set_affinity || no_irq_affinity)
+ if (!irq_desc[irq].chip->set_affinity || no_irq_affinity ||
+ CHECK_IRQ_PER_CPU(irq_desc[irq].status))
return -EIO;
err = cpumask_parse_user(buffer, count, new_value);
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 543ea2e5ad9..9d8c79b4882 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -176,7 +176,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
int noirqdebug __read_mostly;
-int __init noirqdebug_setup(char *str)
+int noirqdebug_setup(char *str)
{
noirqdebug = 1;
printk(KERN_INFO "IRQ lockup detection disabled\n");
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index ab63cfc4299..6f294ff4f9e 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -31,14 +31,14 @@
#endif
/* These will be re-linked against their real values during the second link stage */
-extern unsigned long kallsyms_addresses[] __attribute__((weak));
-extern unsigned long kallsyms_num_syms __attribute__((weak,section("data")));
-extern u8 kallsyms_names[] __attribute__((weak));
+extern const unsigned long kallsyms_addresses[] __attribute__((weak));
+extern const unsigned long kallsyms_num_syms __attribute__((weak));
+extern const u8 kallsyms_names[] __attribute__((weak));
-extern u8 kallsyms_token_table[] __attribute__((weak));
-extern u16 kallsyms_token_index[] __attribute__((weak));
+extern const u8 kallsyms_token_table[] __attribute__((weak));
+extern const u16 kallsyms_token_index[] __attribute__((weak));
-extern unsigned long kallsyms_markers[] __attribute__((weak));
+extern const unsigned long kallsyms_markers[] __attribute__((weak));
static inline int is_kernel_inittext(unsigned long addr)
{
@@ -84,7 +84,7 @@ static int is_ksym_addr(unsigned long addr)
static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
{
int len, skipped_first = 0;
- u8 *tptr, *data;
+ const u8 *tptr, *data;
/* get the compressed symbol length from the first symbol byte */
data = &kallsyms_names[off];
@@ -132,7 +132,7 @@ static char kallsyms_get_symbol_type(unsigned int off)
* kallsyms array */
static unsigned int get_symbol_offset(unsigned long pos)
{
- u8 *name;
+ const u8 *name;
int i;
/* use the closest marker we have. We have markers every 256 positions,
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 8d2bea09a4e..3a7379aa31c 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -25,7 +25,7 @@
#include <linux/kmod.h>
#include <linux/smp_lock.h>
#include <linux/slab.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/completion.h>
#include <linux/file.h>
#include <linux/workqueue.h>
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 17ec4afb099..6fcf8dd148d 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -87,6 +87,12 @@ struct kprobe_insn_page {
int ngarbage;
};
+enum kprobe_slot_state {
+ SLOT_CLEAN = 0,
+ SLOT_DIRTY = 1,
+ SLOT_USED = 2,
+};
+
static struct hlist_head kprobe_insn_pages;
static int kprobe_garbage_slots;
static int collect_garbage_slots(void);
@@ -130,8 +136,8 @@ kprobe_opcode_t __kprobes *get_insn_slot(void)
if (kip->nused < INSNS_PER_PAGE) {
int i;
for (i = 0; i < INSNS_PER_PAGE; i++) {
- if (!kip->slot_used[i]) {
- kip->slot_used[i] = 1;
+ if (kip->slot_used[i] == SLOT_CLEAN) {
+ kip->slot_used[i] = SLOT_USED;
kip->nused++;
return kip->insns + (i * MAX_INSN_SIZE);
}
@@ -163,8 +169,8 @@ kprobe_opcode_t __kprobes *get_insn_slot(void)
}
INIT_HLIST_NODE(&kip->hlist);
hlist_add_head(&kip->hlist, &kprobe_insn_pages);
- memset(kip->slot_used, 0, INSNS_PER_PAGE);
- kip->slot_used[0] = 1;
+ memset(kip->slot_used, SLOT_CLEAN, INSNS_PER_PAGE);
+ kip->slot_used[0] = SLOT_USED;
kip->nused = 1;
kip->ngarbage = 0;
return kip->insns;
@@ -173,7 +179,7 @@ kprobe_opcode_t __kprobes *get_insn_slot(void)
/* Return 1 if all garbages are collected, otherwise 0. */
static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx)
{
- kip->slot_used[idx] = 0;
+ kip->slot_used[idx] = SLOT_CLEAN;
kip->nused--;
if (kip->nused == 0) {
/*
@@ -212,7 +218,7 @@ static int __kprobes collect_garbage_slots(void)
continue;
kip->ngarbage = 0; /* we will collect all garbages */
for (i = 0; i < INSNS_PER_PAGE; i++) {
- if (kip->slot_used[i] == -1 &&
+ if (kip->slot_used[i] == SLOT_DIRTY &&
collect_one_slot(kip, i))
break;
}
@@ -232,7 +238,7 @@ void __kprobes free_insn_slot(kprobe_opcode_t * slot, int dirty)
slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) {
int i = (slot - kip->insns) / MAX_INSN_SIZE;
if (dirty) {
- kip->slot_used[i] = -1;
+ kip->slot_used[i] = SLOT_DIRTY;
kip->ngarbage++;
} else {
collect_one_slot(kip, i);
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index b02032476dc..509efd49540 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -43,13 +43,49 @@
#include "lockdep_internals.h"
/*
- * hash_lock: protects the lockdep hashes and class/list/hash allocators.
+ * lockdep_lock: protects the lockdep graph, the hashes and the
+ * class/list/hash allocators.
*
* This is one of the rare exceptions where it's justified
* to use a raw spinlock - we really dont want the spinlock
- * code to recurse back into the lockdep code.
+ * code to recurse back into the lockdep code...
*/
-static raw_spinlock_t hash_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
+static raw_spinlock_t lockdep_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
+
+static int graph_lock(void)
+{
+ __raw_spin_lock(&lockdep_lock);
+ /*
+ * Make sure that if another CPU detected a bug while
+ * walking the graph we dont change it (while the other
+ * CPU is busy printing out stuff with the graph lock
+ * dropped already)
+ */
+ if (!debug_locks) {
+ __raw_spin_unlock(&lockdep_lock);
+ return 0;
+ }
+ return 1;
+}
+
+static inline int graph_unlock(void)
+{
+ __raw_spin_unlock(&lockdep_lock);
+ return 0;
+}
+
+/*
+ * Turn lock debugging off and return with 0 if it was off already,
+ * and also release the graph lock:
+ */
+static inline int debug_locks_off_graph_unlock(void)
+{
+ int ret = debug_locks_off();
+
+ __raw_spin_unlock(&lockdep_lock);
+
+ return ret;
+}
static int lockdep_initialized;
@@ -57,14 +93,15 @@ unsigned long nr_list_entries;
static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES];
/*
- * Allocate a lockdep entry. (assumes hash_lock held, returns
+ * Allocate a lockdep entry. (assumes the graph_lock held, returns
* with NULL on failure)
*/
static struct lock_list *alloc_list_entry(void)
{
if (nr_list_entries >= MAX_LOCKDEP_ENTRIES) {
- __raw_spin_unlock(&hash_lock);
- debug_locks_off();
+ if (!debug_locks_off_graph_unlock())
+ return NULL;
+
printk("BUG: MAX_LOCKDEP_ENTRIES too low!\n");
printk("turning off the locking correctness validator.\n");
return NULL;
@@ -145,9 +182,7 @@ EXPORT_SYMBOL(lockdep_on);
*/
#define VERBOSE 0
-#ifdef VERBOSE
-# define VERY_VERBOSE 0
-#endif
+#define VERY_VERBOSE 0
#if VERBOSE
# define HARDIRQ_VERBOSE 1
@@ -172,8 +207,8 @@ static int class_filter(struct lock_class *class)
!strcmp(class->name, "&struct->lockfield"))
return 1;
#endif
- /* Allow everything else. 0 would be filter everything else */
- return 1;
+ /* Filter everything else. 1 would be to allow everything else */
+ return 0;
}
#endif
@@ -207,7 +242,7 @@ static int softirq_verbose(struct lock_class *class)
/*
* Stack-trace: tightly packed array of stack backtrace
- * addresses. Protected by the hash_lock.
+ * addresses. Protected by the graph_lock.
*/
unsigned long nr_stack_trace_entries;
static unsigned long stack_trace[MAX_STACK_TRACE_ENTRIES];
@@ -226,18 +261,15 @@ static int save_trace(struct stack_trace *trace)
trace->max_entries = trace->nr_entries;
nr_stack_trace_entries += trace->nr_entries;
- if (DEBUG_LOCKS_WARN_ON(nr_stack_trace_entries > MAX_STACK_TRACE_ENTRIES)) {
- __raw_spin_unlock(&hash_lock);
- return 0;
- }
if (nr_stack_trace_entries == MAX_STACK_TRACE_ENTRIES) {
- __raw_spin_unlock(&hash_lock);
- if (debug_locks_off()) {
- printk("BUG: MAX_STACK_TRACE_ENTRIES too low!\n");
- printk("turning off the locking correctness validator.\n");
- dump_stack();
- }
+ if (!debug_locks_off_graph_unlock())
+ return 0;
+
+ printk("BUG: MAX_STACK_TRACE_ENTRIES too low!\n");
+ printk("turning off the locking correctness validator.\n");
+ dump_stack();
+
return 0;
}
@@ -526,9 +558,7 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth)
{
struct task_struct *curr = current;
- __raw_spin_unlock(&hash_lock);
- debug_locks_off();
- if (debug_locks_silent)
+ if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return 0;
printk("\n=======================================================\n");
@@ -556,12 +586,10 @@ static noinline int print_circular_bug_tail(void)
if (debug_locks_silent)
return 0;
- /* hash_lock unlocked by the header */
- __raw_spin_lock(&hash_lock);
this.class = check_source->class;
if (!save_trace(&this.trace))
return 0;
- __raw_spin_unlock(&hash_lock);
+
print_circular_bug_entry(&this, 0);
printk("\nother info that might help us debug this:\n\n");
@@ -577,8 +605,10 @@ static noinline int print_circular_bug_tail(void)
static int noinline print_infinite_recursion_bug(void)
{
- __raw_spin_unlock(&hash_lock);
- DEBUG_LOCKS_WARN_ON(1);
+ if (!debug_locks_off_graph_unlock())
+ return 0;
+
+ WARN_ON(1);
return 0;
}
@@ -713,9 +743,7 @@ print_bad_irq_dependency(struct task_struct *curr,
enum lock_usage_bit bit2,
const char *irqclass)
{
- __raw_spin_unlock(&hash_lock);
- debug_locks_off();
- if (debug_locks_silent)
+ if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return 0;
printk("\n======================================================\n");
@@ -796,9 +824,7 @@ static int
print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
struct held_lock *next)
{
- debug_locks_off();
- __raw_spin_unlock(&hash_lock);
- if (debug_locks_silent)
+ if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return 0;
printk("\n=============================================\n");
@@ -974,14 +1000,14 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
* Debugging printouts:
*/
if (verbose(prev->class) || verbose(next->class)) {
- __raw_spin_unlock(&hash_lock);
+ graph_unlock();
printk("\n new dependency: ");
print_lock_name(prev->class);
printk(" => ");
print_lock_name(next->class);
printk("\n");
dump_stack();
- __raw_spin_lock(&hash_lock);
+ return graph_lock();
}
return 1;
}
@@ -1046,8 +1072,10 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)
}
return 1;
out_bug:
- __raw_spin_unlock(&hash_lock);
- DEBUG_LOCKS_WARN_ON(1);
+ if (!debug_locks_off_graph_unlock())
+ return 0;
+
+ WARN_ON(1);
return 0;
}
@@ -1201,7 +1229,10 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
hash_head = classhashentry(key);
raw_local_irq_save(flags);
- __raw_spin_lock(&hash_lock);
+ if (!graph_lock()) {
+ raw_local_irq_restore(flags);
+ return NULL;
+ }
/*
* We have to do the hash-walk again, to avoid races
* with another CPU:
@@ -1214,9 +1245,12 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
* the hash:
*/
if (nr_lock_classes >= MAX_LOCKDEP_KEYS) {
- __raw_spin_unlock(&hash_lock);
+ if (!debug_locks_off_graph_unlock()) {
+ raw_local_irq_restore(flags);
+ return NULL;
+ }
raw_local_irq_restore(flags);
- debug_locks_off();
+
printk("BUG: MAX_LOCKDEP_KEYS too low!\n");
printk("turning off the locking correctness validator.\n");
return NULL;
@@ -1237,18 +1271,23 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
list_add_tail_rcu(&class->hash_entry, hash_head);
if (verbose(class)) {
- __raw_spin_unlock(&hash_lock);
+ graph_unlock();
raw_local_irq_restore(flags);
+
printk("\nnew class %p: %s", class->key, class->name);
if (class->name_version > 1)
printk("#%d", class->name_version);
printk("\n");
dump_stack();
+
raw_local_irq_save(flags);
- __raw_spin_lock(&hash_lock);
+ if (!graph_lock()) {
+ raw_local_irq_restore(flags);
+ return NULL;
+ }
}
out_unlock_set:
- __raw_spin_unlock(&hash_lock);
+ graph_unlock();
raw_local_irq_restore(flags);
if (!subclass || force)
@@ -1264,7 +1303,7 @@ out_unlock_set:
* add it and return 0 - in this case the new dependency chain is
* validated. If the key is already hashed, return 1.
*/
-static inline int lookup_chain_cache(u64 chain_key)
+static inline int lookup_chain_cache(u64 chain_key, struct lock_class *class)
{
struct list_head *hash_head = chainhashentry(chain_key);
struct lock_chain *chain;
@@ -1278,34 +1317,36 @@ static inline int lookup_chain_cache(u64 chain_key)
if (chain->chain_key == chain_key) {
cache_hit:
debug_atomic_inc(&chain_lookup_hits);
- /*
- * In the debugging case, force redundant checking
- * by returning 1:
- */
-#ifdef CONFIG_DEBUG_LOCKDEP
- __raw_spin_lock(&hash_lock);
- return 1;
-#endif
+ if (very_verbose(class))
+ printk("\nhash chain already cached, key: "
+ "%016Lx tail class: [%p] %s\n",
+ (unsigned long long)chain_key,
+ class->key, class->name);
return 0;
}
}
+ if (very_verbose(class))
+ printk("\nnew hash chain, key: %016Lx tail class: [%p] %s\n",
+ (unsigned long long)chain_key, class->key, class->name);
/*
* Allocate a new chain entry from the static array, and add
* it to the hash:
*/
- __raw_spin_lock(&hash_lock);
+ if (!graph_lock())
+ return 0;
/*
* We have to walk the chain again locked - to avoid duplicates:
*/
list_for_each_entry(chain, hash_head, entry) {
if (chain->chain_key == chain_key) {
- __raw_spin_unlock(&hash_lock);
+ graph_unlock();
goto cache_hit;
}
}
if (unlikely(nr_lock_chains >= MAX_LOCKDEP_CHAINS)) {
- __raw_spin_unlock(&hash_lock);
- debug_locks_off();
+ if (!debug_locks_off_graph_unlock())
+ return 0;
+
printk("BUG: MAX_LOCKDEP_CHAINS too low!\n");
printk("turning off the locking correctness validator.\n");
return 0;
@@ -1381,9 +1422,7 @@ print_irq_inversion_bug(struct task_struct *curr, struct lock_class *other,
struct held_lock *this, int forwards,
const char *irqclass)
{
- __raw_spin_unlock(&hash_lock);
- debug_locks_off();
- if (debug_locks_silent)
+ if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return 0;
printk("\n=========================================================\n");
@@ -1453,7 +1492,7 @@ check_usage_backwards(struct task_struct *curr, struct held_lock *this,
return print_irq_inversion_bug(curr, backwards_match, this, 0, irqclass);
}
-static inline void print_irqtrace_events(struct task_struct *curr)
+void print_irqtrace_events(struct task_struct *curr)
{
printk("irq event stamp: %u\n", curr->irq_events);
printk("hardirqs last enabled at (%u): ", curr->hardirq_enable_event);
@@ -1466,19 +1505,13 @@ static inline void print_irqtrace_events(struct task_struct *curr)
print_ip_sym(curr->softirq_disable_ip);
}
-#else
-static inline void print_irqtrace_events(struct task_struct *curr)
-{
-}
#endif
static int
print_usage_bug(struct task_struct *curr, struct held_lock *this,
enum lock_usage_bit prev_bit, enum lock_usage_bit new_bit)
{
- __raw_spin_unlock(&hash_lock);
- debug_locks_off();
- if (debug_locks_silent)
+ if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return 0;
printk("\n=================================\n");
@@ -1539,12 +1572,13 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
if (likely(this->class->usage_mask & new_mask))
return 1;
- __raw_spin_lock(&hash_lock);
+ if (!graph_lock())
+ return 0;
/*
* Make sure we didnt race:
*/
if (unlikely(this->class->usage_mask & new_mask)) {
- __raw_spin_unlock(&hash_lock);
+ graph_unlock();
return 1;
}
@@ -1730,16 +1764,16 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
debug_atomic_dec(&nr_unused_locks);
break;
default:
- __raw_spin_unlock(&hash_lock);
- debug_locks_off();
+ if (!debug_locks_off_graph_unlock())
+ return 0;
WARN_ON(1);
return 0;
}
- __raw_spin_unlock(&hash_lock);
+ graph_unlock();
/*
- * We must printk outside of the hash_lock:
+ * We must printk outside of the graph_lock:
*/
if (ret == 2) {
printk("\nmarked lock as {%s}:\n", usage_str[new_bit]);
@@ -2137,9 +2171,9 @@ out_calc_hash:
* We look up the chain_key and do the O(N^2) check and update of
* the dependencies only if this is a new dependency chain.
* (If lookup_chain_cache() returns with 1 it acquires
- * hash_lock for us)
+ * graph_lock for us)
*/
- if (!trylock && (check == 2) && lookup_chain_cache(chain_key)) {
+ if (!trylock && (check == 2) && lookup_chain_cache(chain_key, class)) {
/*
* Check whether last held lock:
*
@@ -2170,7 +2204,7 @@ out_calc_hash:
if (!chain_head && ret != 2)
if (!check_prevs_add(curr, hlock))
return 0;
- __raw_spin_unlock(&hash_lock);
+ graph_unlock();
}
curr->lockdep_depth++;
check_chain_key(curr);
@@ -2433,6 +2467,7 @@ EXPORT_SYMBOL_GPL(lock_release);
void lockdep_reset(void)
{
unsigned long flags;
+ int i;
raw_local_irq_save(flags);
current->curr_chain_key = 0;
@@ -2443,6 +2478,8 @@ void lockdep_reset(void)
nr_softirq_chains = 0;
nr_process_chains = 0;
debug_locks = 1;
+ for (i = 0; i < CHAINHASH_SIZE; i++)
+ INIT_LIST_HEAD(chainhash_table + i);
raw_local_irq_restore(flags);
}
@@ -2479,7 +2516,7 @@ void lockdep_free_key_range(void *start, unsigned long size)
int i;
raw_local_irq_save(flags);
- __raw_spin_lock(&hash_lock);
+ graph_lock();
/*
* Unhash all classes that were created by this module:
@@ -2493,7 +2530,7 @@ void lockdep_free_key_range(void *start, unsigned long size)
zap_class(class);
}
- __raw_spin_unlock(&hash_lock);
+ graph_unlock();
raw_local_irq_restore(flags);
}
@@ -2521,20 +2558,20 @@ void lockdep_reset_lock(struct lockdep_map *lock)
* Debug check: in the end all mapped classes should
* be gone.
*/
- __raw_spin_lock(&hash_lock);
+ graph_lock();
for (i = 0; i < CLASSHASH_SIZE; i++) {
head = classhash_table + i;
if (list_empty(head))
continue;
list_for_each_entry_safe(class, next, head, hash_entry) {
if (unlikely(class == lock->class_cache)) {
- __raw_spin_unlock(&hash_lock);
- DEBUG_LOCKS_WARN_ON(1);
+ if (debug_locks_off_graph_unlock())
+ WARN_ON(1);
goto out_restore;
}
}
}
- __raw_spin_unlock(&hash_lock);
+ graph_unlock();
out_restore:
raw_local_irq_restore(flags);
diff --git a/kernel/module.c b/kernel/module.c
index d9eae45d014..8a94e054230 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -537,6 +537,8 @@ static int already_uses(struct module *a, struct module *b)
static int use_module(struct module *a, struct module *b)
{
struct module_use *use;
+ int no_warn;
+
if (b == NULL || already_uses(a, b)) return 1;
if (!strong_try_module_get(b))
@@ -552,6 +554,7 @@ static int use_module(struct module *a, struct module *b)
use->module_which_uses = a;
list_add(&use->list, &b->modules_which_use_me);
+ no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name);
return 1;
}
@@ -569,6 +572,7 @@ static void module_unload_free(struct module *mod)
module_put(i);
list_del(&use->list);
kfree(use);
+ sysfs_remove_link(i->holders_dir, mod->name);
/* There can be at most one match. */
break;
}
@@ -824,9 +828,34 @@ static inline void module_unload_init(struct module *mod)
}
#endif /* CONFIG_MODULE_UNLOAD */
+static ssize_t show_initstate(struct module_attribute *mattr,
+ struct module *mod, char *buffer)
+{
+ const char *state = "unknown";
+
+ switch (mod->state) {
+ case MODULE_STATE_LIVE:
+ state = "live";
+ break;
+ case MODULE_STATE_COMING:
+ state = "coming";
+ break;
+ case MODULE_STATE_GOING:
+ state = "going";
+ break;
+ }
+ return sprintf(buffer, "%s\n", state);
+}
+
+static struct module_attribute initstate = {
+ .attr = { .name = "initstate", .mode = 0444, .owner = THIS_MODULE },
+ .show = show_initstate,
+};
+
static struct module_attribute *modinfo_attrs[] = {
&modinfo_version,
&modinfo_srcversion,
+ &initstate,
#ifdef CONFIG_MODULE_UNLOAD
&refcnt,
#endif
@@ -1081,9 +1110,7 @@ static void module_remove_modinfo_attrs(struct module *mod)
kfree(mod->modinfo_attrs);
}
-static int mod_sysfs_setup(struct module *mod,
- struct kernel_param *kparam,
- unsigned int num_params)
+static int mod_sysfs_init(struct module *mod)
{
int err;
@@ -1100,19 +1127,30 @@ static int mod_sysfs_setup(struct module *mod,
kobj_set_kset_s(&mod->mkobj, module_subsys);
mod->mkobj.mod = mod;
- /* delay uevent until full sysfs population */
kobject_init(&mod->mkobj.kobj);
+
+out:
+ return err;
+}
+
+static int mod_sysfs_setup(struct module *mod,
+ struct kernel_param *kparam,
+ unsigned int num_params)
+{
+ int err;
+
+ /* delay uevent until full sysfs population */
err = kobject_add(&mod->mkobj.kobj);
if (err)
goto out;
- mod->drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers");
- if (!mod->drivers_dir)
+ mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders");
+ if (!mod->holders_dir)
goto out_unreg;
err = module_param_sysfs_setup(mod, kparam, num_params);
if (err)
- goto out_unreg_drivers;
+ goto out_unreg_holders;
err = module_add_modinfo_attrs(mod);
if (err)
@@ -1121,10 +1159,10 @@ static int mod_sysfs_setup(struct module *mod,
kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
return 0;
-out_unreg_drivers:
- kobject_unregister(mod->drivers_dir);
out_unreg_param:
module_param_sysfs_remove(mod);
+out_unreg_holders:
+ kobject_unregister(mod->holders_dir);
out_unreg:
kobject_del(&mod->mkobj.kobj);
kobject_put(&mod->mkobj.kobj);
@@ -1136,7 +1174,10 @@ static void mod_kobject_remove(struct module *mod)
{
module_remove_modinfo_attrs(mod);
module_param_sysfs_remove(mod);
- kobject_unregister(mod->drivers_dir);
+ if (mod->mkobj.drivers_dir)
+ kobject_unregister(mod->mkobj.drivers_dir);
+ if (mod->holders_dir)
+ kobject_unregister(mod->holders_dir);
kobject_unregister(&mod->mkobj.kobj);
}
@@ -1741,6 +1782,10 @@ static struct module *load_module(void __user *umod,
/* Now we've moved module, initialize linked lists, etc. */
module_unload_init(mod);
+ /* Initialize kobject, so we can reference it. */
+ if (mod_sysfs_init(mod) != 0)
+ goto cleanup;
+
/* Set up license info based on the info section */
set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
@@ -2300,26 +2345,78 @@ void print_modules(void)
printk("\n");
}
+static char *make_driver_name(struct device_driver *drv)
+{
+ char *driver_name;
+
+ driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2,
+ GFP_KERNEL);
+ if (!driver_name)
+ return NULL;
+
+ sprintf(driver_name, "%s:%s", drv->bus->name, drv->name);
+ return driver_name;
+}
+
+static void module_create_drivers_dir(struct module_kobject *mk)
+{
+ if (!mk || mk->drivers_dir)
+ return;
+
+ mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers");
+}
+
void module_add_driver(struct module *mod, struct device_driver *drv)
{
+ char *driver_name;
int no_warn;
+ struct module_kobject *mk = NULL;
+
+ if (!drv)
+ return;
+
+ if (mod)
+ mk = &mod->mkobj;
+ else if (drv->mod_name) {
+ struct kobject *mkobj;
+
+ /* Lookup built-in module entry in /sys/modules */
+ mkobj = kset_find_obj(&module_subsys.kset, drv->mod_name);
+ if (mkobj)
+ mk = container_of(mkobj, struct module_kobject, kobj);
+ }
- if (!mod || !drv)
+ if (!mk)
return;
/* Don't check return codes; these calls are idempotent */
- no_warn = sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module");
- no_warn = sysfs_create_link(mod->drivers_dir, &drv->kobj, drv->name);
+ no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module");
+ driver_name = make_driver_name(drv);
+ if (driver_name) {
+ module_create_drivers_dir(mk);
+ no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj,
+ driver_name);
+ kfree(driver_name);
+ }
}
EXPORT_SYMBOL(module_add_driver);
void module_remove_driver(struct device_driver *drv)
{
+ char *driver_name;
+
if (!drv)
return;
+
sysfs_remove_link(&drv->kobj, "module");
- if (drv->owner && drv->owner->drivers_dir)
- sysfs_remove_link(drv->owner->drivers_dir, drv->name);
+ if (drv->owner && drv->owner->mkobj.drivers_dir) {
+ driver_name = make_driver_name(drv);
+ if (driver_name) {
+ sysfs_remove_link(drv->owner->mkobj.drivers_dir,
+ driver_name);
+ kfree(driver_name);
+ }
+ }
}
EXPORT_SYMBOL(module_remove_driver);
diff --git a/kernel/mutex.c b/kernel/mutex.c
index 8c71cf72a49..e7cbbb82765 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -206,6 +206,15 @@ mutex_lock_nested(struct mutex *lock, unsigned int subclass)
}
EXPORT_SYMBOL_GPL(mutex_lock_nested);
+
+int __sched
+mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
+{
+ might_sleep();
+ return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, subclass);
+}
+
+EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested);
#endif
/*
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index 674aceb7335..f5b9ee6f6bb 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -17,8 +17,9 @@
#include <linux/version.h>
#include <linux/nsproxy.h>
#include <linux/init_task.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/utsname.h>
+#include <linux/pid_namespace.h>
struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy);
@@ -60,12 +61,14 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig)
struct nsproxy *ns = clone_namespaces(orig);
if (ns) {
- if (ns->namespace)
- get_namespace(ns->namespace);
+ if (ns->mnt_ns)
+ get_mnt_ns(ns->mnt_ns);
if (ns->uts_ns)
get_uts_ns(ns->uts_ns);
if (ns->ipc_ns)
get_ipc_ns(ns->ipc_ns);
+ if (ns->pid_ns)
+ get_pid_ns(ns->pid_ns);
}
return ns;
@@ -97,7 +100,7 @@ int copy_namespaces(int flags, struct task_struct *tsk)
tsk->nsproxy = new_ns;
- err = copy_namespace(flags, tsk);
+ err = copy_mnt_ns(flags, tsk);
if (err)
goto out_ns;
@@ -109,16 +112,23 @@ int copy_namespaces(int flags, struct task_struct *tsk)
if (err)
goto out_ipc;
+ err = copy_pid_ns(flags, tsk);
+ if (err)
+ goto out_pid;
+
out:
put_nsproxy(old_ns);
return err;
+out_pid:
+ if (new_ns->ipc_ns)
+ put_ipc_ns(new_ns->ipc_ns);
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);
+ if (new_ns->mnt_ns)
+ put_mnt_ns(new_ns->mnt_ns);
out_ns:
tsk->nsproxy = old_ns;
kfree(new_ns);
@@ -127,11 +137,13 @@ out_ns:
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);
+ if (ns->mnt_ns)
+ put_mnt_ns(ns->mnt_ns);
+ if (ns->uts_ns)
+ put_uts_ns(ns->uts_ns);
+ if (ns->ipc_ns)
+ put_ipc_ns(ns->ipc_ns);
+ if (ns->pid_ns)
+ put_pid_ns(ns->pid_ns);
+ kfree(ns);
}
diff --git a/kernel/params.c b/kernel/params.c
index f406655d665..553cf7d6a4b 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -30,6 +30,8 @@
#define DEBUGP(fmt, a...)
#endif
+static struct kobj_type module_ktype;
+
static inline char dash2underscore(char c)
{
if (c == '-')
@@ -143,9 +145,15 @@ int parse_args(const char *name,
while (*args) {
int ret;
+ int irq_was_disabled;
args = next_arg(args, &param, &val);
+ irq_was_disabled = irqs_disabled();
ret = parse_one(param, val, params, num, unknown);
+ if (irq_was_disabled && !irqs_disabled()) {
+ printk(KERN_WARNING "parse_args(): option '%s' enabled "
+ "irq's!\n", param);
+ }
switch (ret) {
case -ENOENT:
printk(KERN_ERR "%s: Unknown parameter `%s'\n",
@@ -555,14 +563,11 @@ 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);
- ret = kobject_register(&mk->kobj);
+ kobject_init(&mk->kobj);
+ ret = kobject_add(&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)) {
- kobject_unregister(&mk->kobj);
- kfree(mk);
- }
+ param_sysfs_setup(mk, kparam, num_params, name_skip);
+ kobject_uevent(&mk->kobj, KOBJ_ADD);
}
/*
@@ -668,6 +673,19 @@ static struct sysfs_ops module_sysfs_ops = {
.store = module_attr_store,
};
+static int uevent_filter(struct kset *kset, struct kobject *kobj)
+{
+ struct kobj_type *ktype = get_ktype(kobj);
+
+ if (ktype == &module_ktype)
+ return 1;
+ return 0;
+}
+
+static struct kset_uevent_ops module_uevent_ops = {
+ .filter = uevent_filter,
+};
+
#else
static struct sysfs_ops module_sysfs_ops = {
.show = NULL,
@@ -679,7 +697,7 @@ static struct kobj_type module_ktype = {
.sysfs_ops = &module_sysfs_ops,
};
-decl_subsys(module, &module_ktype, NULL);
+decl_subsys(module, &module_ktype, &module_uevent_ops);
/*
* param_sysfs_init - wrapper for built-in params support
diff --git a/kernel/pid.c b/kernel/pid.c
index a48879b0b92..78f2aee90f5 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -26,7 +26,7 @@
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/hash.h>
-#include <linux/pspace.h>
+#include <linux/pid_namespace.h>
#define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift)
static struct hlist_head *pid_hash;
@@ -43,9 +43,10 @@ int pid_max_max = PID_MAX_LIMIT;
#define BITS_PER_PAGE (PAGE_SIZE*8)
#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1)
-static inline int mk_pid(struct pspace *pspace, struct pidmap *map, int off)
+static inline int mk_pid(struct pid_namespace *pid_ns,
+ struct pidmap *map, int off)
{
- return (map - pspace->pidmap)*BITS_PER_PAGE + off;
+ return (map - pid_ns->pidmap)*BITS_PER_PAGE + off;
}
#define find_next_offset(map, off) \
@@ -57,11 +58,15 @@ static inline int mk_pid(struct pspace *pspace, struct pidmap *map, int off)
* value does not cause lots of bitmaps to be allocated, but
* the scheme scales to up to 4 million PIDs, runtime.
*/
-struct pspace init_pspace = {
+struct pid_namespace init_pid_ns = {
+ .kref = {
+ .refcount = ATOMIC_INIT(2),
+ },
.pidmap = {
[ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL }
},
- .last_pid = 0
+ .last_pid = 0,
+ .child_reaper = &init_task
};
/*
@@ -80,25 +85,25 @@ struct pspace init_pspace = {
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock);
-static fastcall void free_pidmap(struct pspace *pspace, int pid)
+static fastcall void free_pidmap(struct pid_namespace *pid_ns, int pid)
{
- struct pidmap *map = pspace->pidmap + pid / BITS_PER_PAGE;
+ struct pidmap *map = pid_ns->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(struct pspace *pspace)
+static int alloc_pidmap(struct pid_namespace *pid_ns)
{
- int i, offset, max_scan, pid, last = pspace->last_pid;
+ int i, offset, max_scan, pid, last = pid_ns->last_pid;
struct pidmap *map;
pid = last + 1;
if (pid >= pid_max)
pid = RESERVED_PIDS;
offset = pid & BITS_PER_PAGE_MASK;
- map = &pspace->pidmap[pid/BITS_PER_PAGE];
+ map = &pid_ns->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)) {
@@ -120,11 +125,11 @@ static int alloc_pidmap(struct pspace *pspace)
do {
if (!test_and_set_bit(offset, map->page)) {
atomic_dec(&map->nr_free);
- pspace->last_pid = pid;
+ pid_ns->last_pid = pid;
return pid;
}
offset = find_next_offset(map, offset);
- pid = mk_pid(pspace, map, offset);
+ pid = mk_pid(pid_ns, map, offset);
/*
* find_next_offset() found a bit, the pid from it
* is in-bounds, and if we fell back to the last
@@ -135,34 +140,34 @@ static int alloc_pidmap(struct pspace *pspace)
(i != max_scan || pid < last ||
!((last+1) & BITS_PER_PAGE_MASK)));
}
- if (map < &pspace->pidmap[(pid_max-1)/BITS_PER_PAGE]) {
+ if (map < &pid_ns->pidmap[(pid_max-1)/BITS_PER_PAGE]) {
++map;
offset = 0;
} else {
- map = &pspace->pidmap[0];
+ map = &pid_ns->pidmap[0];
offset = RESERVED_PIDS;
if (unlikely(last == offset))
break;
}
- pid = mk_pid(pspace, map, offset);
+ pid = mk_pid(pid_ns, map, offset);
}
return -1;
}
-static int next_pidmap(struct pspace *pspace, int last)
+static int next_pidmap(struct pid_namespace *pid_ns, 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];
+ map = &pid_ns->pidmap[(last + 1)/BITS_PER_PAGE];
+ end = &pid_ns->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 mk_pid(pid_ns, map, offset);
}
return -1;
}
@@ -192,7 +197,7 @@ fastcall void free_pid(struct pid *pid)
hlist_del_rcu(&pid->pid_chain);
spin_unlock_irqrestore(&pidmap_lock, flags);
- free_pidmap(&init_pspace, pid->nr);
+ free_pidmap(&init_pid_ns, pid->nr);
call_rcu(&pid->rcu, delayed_put_pid);
}
@@ -206,7 +211,7 @@ struct pid *alloc_pid(void)
if (!pid)
goto out;
- nr = alloc_pidmap(&init_pspace);
+ nr = alloc_pidmap(current->nsproxy->pid_ns);
if (nr < 0)
goto out_free;
@@ -348,13 +353,33 @@ struct pid *find_ge_pid(int nr)
pid = find_pid(nr);
if (pid)
break;
- nr = next_pidmap(&init_pspace, nr);
+ nr = next_pidmap(current->nsproxy->pid_ns, nr);
} while (nr > 0);
return pid;
}
EXPORT_SYMBOL_GPL(find_get_pid);
+int copy_pid_ns(int flags, struct task_struct *tsk)
+{
+ struct pid_namespace *old_ns = tsk->nsproxy->pid_ns;
+ int err = 0;
+
+ if (!old_ns)
+ return 0;
+
+ get_pid_ns(old_ns);
+ return err;
+}
+
+void free_pid_ns(struct kref *kref)
+{
+ struct pid_namespace *ns;
+
+ ns = container_of(kref, struct pid_namespace, kref);
+ kfree(ns);
+}
+
/*
* 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
@@ -382,10 +407,10 @@ void __init pidhash_init(void)
void __init pidmap_init(void)
{
- init_pspace.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ init_pid_ns.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL);
/* Reserve PID 0. We never call free_pidmap(0) */
- set_bit(0, init_pspace.pidmap[0].page);
- atomic_dec(&init_pspace.pidmap[0].nr_free);
+ set_bit(0, init_pid_ns.pidmap[0].page);
+ atomic_dec(&init_pid_ns.pidmap[0].nr_free);
pid_cachep = kmem_cache_create("pid", sizeof(struct pid),
__alignof__(struct pid),
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 710ed084e7c..95f6657fff7 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -20,13 +20,14 @@ config PM
sending the processor to sleep and saving power.
config PM_LEGACY
- bool "Legacy Power Management API"
+ bool "Legacy Power Management API (DEPRECATED)"
depends on PM
- default y
+ default n
---help---
- Support for pm_register() and friends.
+ Support for pm_register() and friends. This old API is obsoleted
+ by the driver model.
- If unsure, say Y.
+ If unsure, say N.
config PM_DEBUG
bool "Power Management Debug Support"
@@ -130,3 +131,29 @@ config SUSPEND_SMP
bool
depends on HOTPLUG_CPU && X86 && PM
default y
+
+config APM_EMULATION
+ tristate "Advanced Power Management Emulation"
+ depends on PM && SYS_SUPPORTS_APM_EMULATION
+ help
+ APM is a BIOS specification for saving power using several different
+ techniques. This is mostly useful for battery powered laptops with
+ APM compliant BIOSes. If you say Y here, the system time will be
+ reset after a RESUME operation, the /proc/apm device will provide
+ battery status information, and user-space programs will receive
+ notification of APM "events" (e.g. battery status change).
+
+ In order to use APM, you will need supporting software. For location
+ and more information, read <file:Documentation/pm.txt> and the
+ Battery Powered Linux mini-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ This driver does not spin down disk drives (see the hdparm(8)
+ manpage ("man 8 hdparm") for that), and it doesn't turn off
+ VESA-compliant "green" monitors.
+
+ Generally, if you don't have a battery in your machine, there isn't
+ much point in using this driver and you should say N. If you get
+ random kernel OOPSes or reboots that don't seem to be related to
+ anything, try disabling/enabling this option (or disabling/enabling
+ APM in your BIOS).
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 0b00f56c2ad..88fc5d7ac73 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -60,9 +60,11 @@ static void power_down(suspend_disk_method_t mode)
{
switch(mode) {
case PM_DISK_PLATFORM:
- kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
- pm_ops->enter(PM_SUSPEND_DISK);
- break;
+ if (pm_ops && pm_ops->enter) {
+ kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
+ pm_ops->enter(PM_SUSPEND_DISK);
+ break;
+ }
case PM_DISK_SHUTDOWN:
kernel_power_off();
break;
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 500eb87f643..ff3a6182f5f 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -29,7 +29,7 @@
DEFINE_MUTEX(pm_mutex);
struct pm_ops *pm_ops;
-suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
+suspend_disk_method_t pm_disk_mode = PM_DISK_PLATFORM;
/**
* pm_set_ops - Set the global power method table.
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 99eeb119b06..6d566bf7085 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -28,8 +28,7 @@ static inline int freezeable(struct task_struct * p)
if ((p == current) ||
(p->flags & PF_NOFREEZE) ||
(p->exit_state == EXIT_ZOMBIE) ||
- (p->exit_state == EXIT_DEAD) ||
- (p->state == TASK_STOPPED))
+ (p->exit_state == EXIT_DEAD))
return 0;
return 1;
}
@@ -61,10 +60,16 @@ static inline void freeze_process(struct task_struct *p)
unsigned long flags;
if (!freezing(p)) {
- freeze(p);
- spin_lock_irqsave(&p->sighand->siglock, flags);
- signal_wake_up(p, 0);
- spin_unlock_irqrestore(&p->sighand->siglock, flags);
+ rmb();
+ if (!frozen(p)) {
+ if (p->state == TASK_STOPPED)
+ force_sig_specific(SIGSTOP, p);
+
+ freeze(p);
+ spin_lock_irqsave(&p->sighand->siglock, flags);
+ signal_wake_up(p, p->state == TASK_STOPPED);
+ spin_unlock_irqrestore(&p->sighand->siglock, flags);
+ }
}
}
@@ -103,9 +108,7 @@ static unsigned int try_to_freeze_tasks(int freeze_user_space)
if (frozen(p))
continue;
- if (p->state == TASK_TRACED &&
- (frozen(p->parent) ||
- p->parent->state == TASK_STOPPED)) {
+ if (p->state == TASK_TRACED && frozen(p->parent)) {
cancel_freezing(p);
continue;
}
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index f133d4a6d81..3581f8f86ac 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -165,14 +165,15 @@ static int swsusp_swap_check(void) /* This is called before saving image */
{
int res;
- res = swap_type_of(swsusp_resume_device, swsusp_resume_block);
+ res = swap_type_of(swsusp_resume_device, swsusp_resume_block,
+ &resume_bdev);
if (res < 0)
return res;
root_swap = res;
- resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_WRITE);
- if (IS_ERR(resume_bdev))
- return PTR_ERR(resume_bdev);
+ res = blkdev_get(resume_bdev, FMODE_WRITE, O_RDWR);
+ if (res)
+ return res;
res = set_blocksize(resume_bdev, PAGE_SIZE);
if (res < 0)
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 89443b85163..f7b7a785a5c 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -57,7 +57,7 @@ static int snapshot_open(struct inode *inode, struct file *filp)
memset(&data->handle, 0, sizeof(struct snapshot_handle));
if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
data->swap = swsusp_resume_device ?
- swap_type_of(swsusp_resume_device, 0) : -1;
+ swap_type_of(swsusp_resume_device, 0, NULL) : -1;
data->mode = O_RDONLY;
} else {
data->swap = -1;
@@ -268,7 +268,8 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
* so we need to recode them
*/
if (old_decode_dev(arg)) {
- data->swap = swap_type_of(old_decode_dev(arg), 0);
+ data->swap = swap_type_of(old_decode_dev(arg),
+ 0, NULL);
if (data->swap < 0)
error = -ENODEV;
} else {
@@ -365,7 +366,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
swdev = old_decode_dev(swap_area.dev);
if (swdev) {
offset = swap_area.offset;
- data->swap = swap_type_of(swdev, offset);
+ data->swap = swap_type_of(swdev, offset, NULL);
if (data->swap < 0)
error = -ENODEV;
} else {
diff --git a/kernel/printk.c b/kernel/printk.c
index 185bb45eacf..c770e1a4e88 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -335,7 +335,7 @@ static void __call_console_drivers(unsigned long start, unsigned long end)
static int __read_mostly ignore_loglevel;
-int __init ignore_loglevel_setup(char *str)
+static int __init ignore_loglevel_setup(char *str)
{
ignore_loglevel = 1;
printk(KERN_INFO "debug: ignoring loglevel setting.\n");
diff --git a/kernel/profile.c b/kernel/profile.c
index fb5e03d57e9..d6579d51106 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -40,7 +40,10 @@ int (*timer_hook)(struct pt_regs *) __read_mostly;
static atomic_t *prof_buffer;
static unsigned long prof_len, prof_shift;
+
int prof_on __read_mostly;
+EXPORT_SYMBOL_GPL(prof_on);
+
static cpumask_t prof_cpu_mask = CPU_MASK_ALL;
#ifdef CONFIG_SMP
static DEFINE_PER_CPU(struct profile_hit *[2], cpu_profile_hits);
@@ -52,6 +55,7 @@ static int __init profile_setup(char * str)
{
static char __initdata schedstr[] = "schedule";
static char __initdata sleepstr[] = "sleep";
+ static char __initdata kvmstr[] = "kvm";
int par;
if (!strncmp(str, sleepstr, strlen(sleepstr))) {
@@ -63,7 +67,7 @@ static int __init profile_setup(char * str)
printk(KERN_INFO
"kernel sleep profiling enabled (shift: %ld)\n",
prof_shift);
- } else if (!strncmp(str, sleepstr, strlen(sleepstr))) {
+ } else if (!strncmp(str, schedstr, strlen(schedstr))) {
prof_on = SCHED_PROFILING;
if (str[strlen(schedstr)] == ',')
str += strlen(schedstr) + 1;
@@ -72,6 +76,15 @@ static int __init profile_setup(char * str)
printk(KERN_INFO
"kernel schedule profiling enabled (shift: %ld)\n",
prof_shift);
+ } else if (!strncmp(str, kvmstr, strlen(kvmstr))) {
+ prof_on = KVM_PROFILING;
+ if (str[strlen(kvmstr)] == ',')
+ str += strlen(kvmstr) + 1;
+ if (get_option(&str, &par))
+ prof_shift = par;
+ printk(KERN_INFO
+ "kernel KVM profiling enabled (shift: %ld)\n",
+ prof_shift);
} else if (get_option(&str, &par)) {
prof_shift = par;
prof_on = CPU_PROFILING;
@@ -387,6 +400,8 @@ void profile_hits(int type, void *__pc, unsigned int nr_hits)
}
#endif /* !CONFIG_SMP */
+EXPORT_SYMBOL_GPL(profile_hits);
+
void profile_tick(int type)
{
struct pt_regs *regs = get_irq_regs();
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index c52f981ea00..482b11ff65c 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -522,6 +522,7 @@ rcu_torture_writer(void *arg)
VERBOSE_PRINTK_STRING("rcu_torture_writer task started");
set_user_nice(current, 19);
+ current->flags |= PF_NOFREEZE;
do {
schedule_timeout_uninterruptible(1);
@@ -561,6 +562,7 @@ rcu_torture_fakewriter(void *arg)
VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
set_user_nice(current, 19);
+ current->flags |= PF_NOFREEZE;
do {
schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
@@ -591,6 +593,7 @@ rcu_torture_reader(void *arg)
VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
set_user_nice(current, 19);
+ current->flags |= PF_NOFREEZE;
do {
idx = cur_ops->readlock();
diff --git a/kernel/relay.c b/kernel/relay.c
index 75a3a9a7efc..284e2e8b4ee 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -138,7 +138,7 @@ depopulate:
*/
struct rchan_buf *relay_create_buf(struct rchan *chan)
{
- struct rchan_buf *buf = kcalloc(1, sizeof(struct rchan_buf), GFP_KERNEL);
+ struct rchan_buf *buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL);
if (!buf)
return NULL;
@@ -302,7 +302,7 @@ static struct rchan_callbacks default_channel_callbacks = {
/**
* wakeup_readers - wake up readers waiting on a channel
- * @private: the channel buffer
+ * @work: work struct that contains the the channel buffer
*
* This is the work function used to defer reader waking. The
* reason waking is deferred is that calling directly from write
@@ -322,7 +322,7 @@ static void wakeup_readers(struct work_struct *work)
*
* See relay_reset for description of effect.
*/
-static inline void __relay_reset(struct rchan_buf *buf, unsigned int init)
+static void __relay_reset(struct rchan_buf *buf, unsigned int init)
{
size_t i;
@@ -418,7 +418,7 @@ static struct rchan_buf *relay_open_buf(struct rchan *chan,
* The channel buffer and channel buffer data structure are then freed
* automatically when the last reference is given up.
*/
-static inline void relay_close_buf(struct rchan_buf *buf)
+static void relay_close_buf(struct rchan_buf *buf)
{
buf->finalized = 1;
cancel_delayed_work(&buf->wake_readers);
@@ -426,7 +426,7 @@ static inline void relay_close_buf(struct rchan_buf *buf)
kref_put(&buf->kref, relay_remove_buf);
}
-static inline void setup_callbacks(struct rchan *chan,
+static void setup_callbacks(struct rchan *chan,
struct rchan_callbacks *cb)
{
if (!cb) {
@@ -479,7 +479,7 @@ struct rchan *relay_open(const char *base_filename,
if (!(subbuf_size && n_subbufs))
return NULL;
- chan = kcalloc(1, sizeof(struct rchan), GFP_KERNEL);
+ chan = kzalloc(sizeof(struct rchan), GFP_KERNEL);
if (!chan)
return NULL;
@@ -946,11 +946,10 @@ typedef int (*subbuf_actor_t) (size_t read_start,
/*
* relay_file_read_subbufs - read count bytes, bridging subbuf boundaries
*/
-static inline ssize_t relay_file_read_subbufs(struct file *filp,
- loff_t *ppos,
- subbuf_actor_t subbuf_actor,
- read_actor_t actor,
- read_descriptor_t *desc)
+static ssize_t relay_file_read_subbufs(struct file *filp, loff_t *ppos,
+ subbuf_actor_t subbuf_actor,
+ read_actor_t actor,
+ read_descriptor_t *desc)
{
struct rchan_buf *buf = filp->private_data;
size_t read_start, avail;
@@ -959,7 +958,7 @@ static inline ssize_t relay_file_read_subbufs(struct file *filp,
if (!desc->count)
return 0;
- mutex_lock(&filp->f_dentry->d_inode->i_mutex);
+ mutex_lock(&filp->f_path.dentry->d_inode->i_mutex);
do {
if (!relay_file_read_avail(buf, *ppos))
break;
@@ -979,7 +978,7 @@ static inline ssize_t relay_file_read_subbufs(struct file *filp,
*ppos = relay_file_read_end_pos(buf, read_start, ret);
}
} while (desc->count && ret);
- mutex_unlock(&filp->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex);
return desc->written;
}
diff --git a/kernel/resource.c b/kernel/resource.c
index 7b9a497419d..2a3f8863658 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -17,6 +17,7 @@
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/device.h>
#include <asm/io.h>
@@ -618,6 +619,67 @@ void __release_region(struct resource *parent, resource_size_t start,
EXPORT_SYMBOL(__release_region);
/*
+ * Managed region resource
+ */
+struct region_devres {
+ struct resource *parent;
+ resource_size_t start;
+ resource_size_t n;
+};
+
+static void devm_region_release(struct device *dev, void *res)
+{
+ struct region_devres *this = res;
+
+ __release_region(this->parent, this->start, this->n);
+}
+
+static int devm_region_match(struct device *dev, void *res, void *match_data)
+{
+ struct region_devres *this = res, *match = match_data;
+
+ return this->parent == match->parent &&
+ this->start == match->start && this->n == match->n;
+}
+
+struct resource * __devm_request_region(struct device *dev,
+ struct resource *parent, resource_size_t start,
+ resource_size_t n, const char *name)
+{
+ struct region_devres *dr = NULL;
+ struct resource *res;
+
+ dr = devres_alloc(devm_region_release, sizeof(struct region_devres),
+ GFP_KERNEL);
+ if (!dr)
+ return NULL;
+
+ dr->parent = parent;
+ dr->start = start;
+ dr->n = n;
+
+ res = __request_region(parent, start, n, name);
+ if (res)
+ devres_add(dev, dr);
+ else
+ devres_free(dr);
+
+ return res;
+}
+EXPORT_SYMBOL(__devm_request_region);
+
+void __devm_release_region(struct device *dev, struct resource *parent,
+ resource_size_t start, resource_size_t n)
+{
+ struct region_devres match_data = { parent, start, n };
+
+ __release_region(parent, start, n);
+ WARN_ON(devres_destroy(dev, devm_region_release, devm_region_match,
+ &match_data));
+}
+EXPORT_SYMBOL(__devm_release_region);
+
+/*
* Called from init/main.c to reserve IO ports.
*/
#define MAXRESERVE 4
diff --git a/kernel/sched.c b/kernel/sched.c
index f385eff4682..cca93cc0dd7 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -225,8 +225,10 @@ struct rq {
unsigned long nr_uninterruptible;
unsigned long expired_timestamp;
- unsigned long long timestamp_last_tick;
+ /* Cached timestamp set by update_cpu_clock() */
+ unsigned long long most_recent_timestamp;
struct task_struct *curr, *idle;
+ unsigned long next_balance;
struct mm_struct *prev_mm;
struct prio_array *active, *expired, arrays[2];
int best_expired_prio;
@@ -426,7 +428,7 @@ static inline void task_rq_unlock(struct rq *rq, unsigned long *flags)
* bump this up when changing the output format or the meaning of an existing
* format, so that tools can adapt (or abort)
*/
-#define SCHEDSTAT_VERSION 12
+#define SCHEDSTAT_VERSION 14
static int show_schedstat(struct seq_file *seq, void *v)
{
@@ -464,7 +466,8 @@ static int show_schedstat(struct seq_file *seq, void *v)
seq_printf(seq, "domain%d %s", dcnt++, mask_str);
for (itype = SCHED_IDLE; itype < MAX_IDLE_TYPES;
itype++) {
- seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu",
+ seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu "
+ "%lu",
sd->lb_cnt[itype],
sd->lb_balanced[itype],
sd->lb_failed[itype],
@@ -474,11 +477,13 @@ static int show_schedstat(struct seq_file *seq, void *v)
sd->lb_nobusyq[itype],
sd->lb_nobusyg[itype]);
}
- seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
+ seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu"
+ " %lu %lu %lu\n",
sd->alb_cnt, sd->alb_failed, sd->alb_pushed,
sd->sbe_cnt, sd->sbe_balanced, sd->sbe_pushed,
sd->sbf_cnt, sd->sbf_balanced, sd->sbf_pushed,
- sd->ttwu_wake_remote, sd->ttwu_move_affine, sd->ttwu_move_balance);
+ sd->ttwu_wake_remote, sd->ttwu_move_affine,
+ sd->ttwu_move_balance);
}
preempt_enable();
#endif
@@ -547,7 +552,7 @@ rq_sched_info_depart(struct rq *rq, unsigned long delta_jiffies)
#endif
/*
- * rq_lock - lock a given runqueue and disable interrupts.
+ * this_rq_lock - lock this runqueue and disable interrupts.
*/
static inline struct rq *this_rq_lock(void)
__acquires(rq->lock)
@@ -938,13 +943,16 @@ static void activate_task(struct task_struct *p, struct rq *rq, int local)
{
unsigned long long now;
+ if (rt_task(p))
+ goto out;
+
now = sched_clock();
#ifdef CONFIG_SMP
if (!local) {
/* Compensate for drifting sched_clock */
struct rq *this_rq = this_rq();
- now = (now - this_rq->timestamp_last_tick)
- + rq->timestamp_last_tick;
+ now = (now - this_rq->most_recent_timestamp)
+ + rq->most_recent_timestamp;
}
#endif
@@ -959,8 +967,7 @@ static void activate_task(struct task_struct *p, struct rq *rq, int local)
(now - p->timestamp) >> 20);
}
- if (!rt_task(p))
- p->prio = recalc_task_prio(p, now);
+ p->prio = recalc_task_prio(p, now);
/*
* This checks to make sure it's not an uninterruptible task
@@ -985,7 +992,7 @@ static void activate_task(struct task_struct *p, struct rq *rq, int local)
}
}
p->timestamp = now;
-
+out:
__activate_task(p, rq);
}
@@ -1450,7 +1457,9 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
if (this_sd->flags & SD_WAKE_AFFINE) {
unsigned long tl = this_load;
- unsigned long tl_per_task = cpu_avg_load_per_task(this_cpu);
+ unsigned long tl_per_task;
+
+ tl_per_task = cpu_avg_load_per_task(this_cpu);
/*
* If sync wakeup then subtract the (maximum possible)
@@ -1558,6 +1567,7 @@ int fastcall wake_up_state(struct task_struct *p, unsigned int state)
return try_to_wake_up(p, state, 0);
}
+static void task_running_tick(struct rq *rq, struct task_struct *p);
/*
* Perform scheduler related setup for a newly forked process p.
* p is forked by current.
@@ -1618,7 +1628,7 @@ void fastcall sched_fork(struct task_struct *p, int clone_flags)
* runqueue lock is not a problem.
*/
current->time_slice = 1;
- scheduler_tick();
+ task_running_tick(cpu_rq(cpu), current);
}
local_irq_enable();
put_cpu();
@@ -1688,8 +1698,8 @@ void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
* Not the local CPU - must adjust timestamp. This should
* get optimised away in the !CONFIG_SMP case.
*/
- p->timestamp = (p->timestamp - this_rq->timestamp_last_tick)
- + rq->timestamp_last_tick;
+ p->timestamp = (p->timestamp - this_rq->most_recent_timestamp)
+ + rq->most_recent_timestamp;
__activate_task(p, rq);
if (TASK_PREEMPTS_CURR(p, rq))
resched_task(rq->curr);
@@ -1952,6 +1962,7 @@ static void double_rq_lock(struct rq *rq1, struct rq *rq2)
__acquires(rq1->lock)
__acquires(rq2->lock)
{
+ BUG_ON(!irqs_disabled());
if (rq1 == rq2) {
spin_lock(&rq1->lock);
__acquire(rq2->lock); /* Fake it out ;) */
@@ -1991,6 +2002,11 @@ static void double_lock_balance(struct rq *this_rq, struct rq *busiest)
__acquires(busiest->lock)
__acquires(this_rq->lock)
{
+ if (unlikely(!irqs_disabled())) {
+ /* printk() doesn't work good under rq->lock */
+ spin_unlock(&this_rq->lock);
+ BUG_ON(1);
+ }
if (unlikely(!spin_trylock(&busiest->lock))) {
if (busiest < this_rq) {
spin_unlock(&this_rq->lock);
@@ -2061,8 +2077,8 @@ static void pull_task(struct rq *src_rq, struct prio_array *src_array,
set_task_cpu(p, this_cpu);
inc_nr_running(p, this_rq);
enqueue_task(p, this_array);
- p->timestamp = (p->timestamp - src_rq->timestamp_last_tick)
- + this_rq->timestamp_last_tick;
+ p->timestamp = (p->timestamp - src_rq->most_recent_timestamp)
+ + this_rq->most_recent_timestamp;
/*
* Note that idle threads have a prio of MAX_PRIO, for this test
* to be always true for them.
@@ -2098,10 +2114,15 @@ int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu,
* 2) too many balance attempts have failed.
*/
- if (sd->nr_balance_failed > sd->cache_nice_tries)
+ if (sd->nr_balance_failed > sd->cache_nice_tries) {
+#ifdef CONFIG_SCHEDSTATS
+ if (task_hot(p, rq->most_recent_timestamp, sd))
+ schedstat_inc(sd, lb_hot_gained[idle]);
+#endif
return 1;
+ }
- if (task_hot(p, rq->timestamp_last_tick, sd))
+ if (task_hot(p, rq->most_recent_timestamp, sd))
return 0;
return 1;
}
@@ -2199,11 +2220,6 @@ skip_queue:
goto skip_bitmap;
}
-#ifdef CONFIG_SCHEDSTATS
- if (task_hot(tmp, busiest->timestamp_last_tick, sd))
- schedstat_inc(sd, lb_hot_gained[idle]);
-#endif
-
pull_task(busiest, array, tmp, this_rq, dst_array, this_cpu);
pulled++;
rem_load_move -= tmp->load_weight;
@@ -2241,7 +2257,7 @@ out:
static struct sched_group *
find_busiest_group(struct sched_domain *sd, int this_cpu,
unsigned long *imbalance, enum idle_type idle, int *sd_idle,
- cpumask_t *cpus)
+ cpumask_t *cpus, int *balance)
{
struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups;
unsigned long max_load, avg_load, total_load, this_load, total_pwr;
@@ -2270,10 +2286,14 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
unsigned long load, group_capacity;
int local_group;
int i;
+ unsigned int balance_cpu = -1, first_idle_cpu = 0;
unsigned long sum_nr_running, sum_weighted_load;
local_group = cpu_isset(this_cpu, group->cpumask);
+ if (local_group)
+ balance_cpu = first_cpu(group->cpumask);
+
/* Tally up the load of all CPUs in the group */
sum_weighted_load = sum_nr_running = avg_load = 0;
@@ -2289,9 +2309,14 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
*sd_idle = 0;
/* Bias balancing toward cpus of our domain */
- if (local_group)
+ if (local_group) {
+ if (idle_cpu(i) && !first_idle_cpu) {
+ first_idle_cpu = 1;
+ balance_cpu = i;
+ }
+
load = target_load(i, load_idx);
- else
+ } else
load = source_load(i, load_idx);
avg_load += load;
@@ -2299,6 +2324,16 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
sum_weighted_load += rq->raw_weighted_load;
}
+ /*
+ * First idle cpu or the first cpu(busiest) in this sched group
+ * is eligible for doing load balancing at this and above
+ * domains.
+ */
+ if (local_group && balance_cpu != this_cpu && balance) {
+ *balance = 0;
+ goto ret;
+ }
+
total_load += avg_load;
total_pwr += group->cpu_power;
@@ -2458,18 +2493,21 @@ small_imbalance:
pwr_now /= SCHED_LOAD_SCALE;
/* Amount of load we'd subtract */
- tmp = busiest_load_per_task*SCHED_LOAD_SCALE/busiest->cpu_power;
+ tmp = busiest_load_per_task * SCHED_LOAD_SCALE /
+ busiest->cpu_power;
if (max_load > tmp)
pwr_move += busiest->cpu_power *
min(busiest_load_per_task, max_load - tmp);
/* Amount of load we'd add */
- if (max_load*busiest->cpu_power <
- busiest_load_per_task*SCHED_LOAD_SCALE)
- tmp = max_load*busiest->cpu_power/this->cpu_power;
+ if (max_load * busiest->cpu_power <
+ busiest_load_per_task * SCHED_LOAD_SCALE)
+ tmp = max_load * busiest->cpu_power / this->cpu_power;
else
- tmp = busiest_load_per_task*SCHED_LOAD_SCALE/this->cpu_power;
- pwr_move += this->cpu_power*min(this_load_per_task, this_load + tmp);
+ tmp = busiest_load_per_task * SCHED_LOAD_SCALE /
+ this->cpu_power;
+ pwr_move += this->cpu_power *
+ min(this_load_per_task, this_load + tmp);
pwr_move /= SCHED_LOAD_SCALE;
/* Move if we gain throughput */
@@ -2490,8 +2528,8 @@ out_balanced:
*imbalance = min_load_per_task;
return group_min;
}
-ret:
#endif
+ret:
*imbalance = 0;
return NULL;
}
@@ -2540,17 +2578,17 @@ static inline unsigned long minus_1_or_zero(unsigned long n)
/*
* Check this_cpu to ensure it is balanced within domain. Attempt to move
* tasks if there is an imbalance.
- *
- * Called with this_rq unlocked.
*/
static int load_balance(int this_cpu, struct rq *this_rq,
- struct sched_domain *sd, enum idle_type idle)
+ struct sched_domain *sd, enum idle_type idle,
+ int *balance)
{
int nr_moved, all_pinned = 0, active_balance = 0, sd_idle = 0;
struct sched_group *group;
unsigned long imbalance;
struct rq *busiest;
cpumask_t cpus = CPU_MASK_ALL;
+ unsigned long flags;
/*
* When power savings policy is enabled for the parent domain, idle
@@ -2566,7 +2604,11 @@ static int load_balance(int this_cpu, struct rq *this_rq,
redo:
group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle,
- &cpus);
+ &cpus, balance);
+
+ if (*balance == 0)
+ goto out_balanced;
+
if (!group) {
schedstat_inc(sd, lb_nobusyg[idle]);
goto out_balanced;
@@ -2590,11 +2632,13 @@ redo:
* still unbalanced. nr_moved simply stays zero, so it is
* correctly treated as an imbalance.
*/
+ local_irq_save(flags);
double_rq_lock(this_rq, busiest);
nr_moved = move_tasks(this_rq, this_cpu, busiest,
minus_1_or_zero(busiest->nr_running),
imbalance, sd, idle, &all_pinned);
double_rq_unlock(this_rq, busiest);
+ local_irq_restore(flags);
/* All tasks on this runqueue were pinned by CPU affinity */
if (unlikely(all_pinned)) {
@@ -2611,13 +2655,13 @@ redo:
if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) {
- spin_lock(&busiest->lock);
+ spin_lock_irqsave(&busiest->lock, flags);
/* don't kick the migration_thread, if the curr
* task on busiest cpu can't be moved to this_cpu
*/
if (!cpu_isset(this_cpu, busiest->curr->cpus_allowed)) {
- spin_unlock(&busiest->lock);
+ spin_unlock_irqrestore(&busiest->lock, flags);
all_pinned = 1;
goto out_one_pinned;
}
@@ -2627,7 +2671,7 @@ redo:
busiest->push_cpu = this_cpu;
active_balance = 1;
}
- spin_unlock(&busiest->lock);
+ spin_unlock_irqrestore(&busiest->lock, flags);
if (active_balance)
wake_up_process(busiest->migration_thread);
@@ -2706,7 +2750,7 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd)
schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
redo:
group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE,
- &sd_idle, &cpus);
+ &sd_idle, &cpus, NULL);
if (!group) {
schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]);
goto out_balanced;
@@ -2766,14 +2810,28 @@ out_balanced:
static void idle_balance(int this_cpu, struct rq *this_rq)
{
struct sched_domain *sd;
+ int pulled_task = 0;
+ unsigned long next_balance = jiffies + 60 * HZ;
for_each_domain(this_cpu, sd) {
if (sd->flags & SD_BALANCE_NEWIDLE) {
/* If we've pulled tasks over stop searching: */
- if (load_balance_newidle(this_cpu, this_rq, sd))
+ pulled_task = load_balance_newidle(this_cpu,
+ this_rq, sd);
+ if (time_after(next_balance,
+ sd->last_balance + sd->balance_interval))
+ next_balance = sd->last_balance
+ + sd->balance_interval;
+ if (pulled_task)
break;
}
}
+ if (!pulled_task)
+ /*
+ * We are going idle. next_balance may be set based on
+ * a busy processor. So reset next_balance.
+ */
+ this_rq->next_balance = next_balance;
}
/*
@@ -2826,26 +2884,9 @@ static void active_load_balance(struct rq *busiest_rq, int busiest_cpu)
spin_unlock(&target_rq->lock);
}
-/*
- * rebalance_tick will get called every timer tick, on every CPU.
- *
- * It checks each scheduling domain to see if it is due to be balanced,
- * and initiates a balancing operation if so.
- *
- * Balancing parameters are set up in arch_init_sched_domains.
- */
-
-/* Don't have all balancing operations going off at once: */
-static inline unsigned long cpu_offset(int cpu)
-{
- return jiffies + cpu * HZ / NR_CPUS;
-}
-
-static void
-rebalance_tick(int this_cpu, struct rq *this_rq, enum idle_type idle)
+static void update_load(struct rq *this_rq)
{
- unsigned long this_load, interval, j = cpu_offset(this_cpu);
- struct sched_domain *sd;
+ unsigned long this_load;
int i, scale;
this_load = this_rq->raw_weighted_load;
@@ -2865,6 +2906,32 @@ rebalance_tick(int this_cpu, struct rq *this_rq, enum idle_type idle)
new_load += scale-1;
this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) / scale;
}
+}
+
+/*
+ * run_rebalance_domains is triggered when needed from the scheduler tick.
+ *
+ * It checks each scheduling domain to see if it is due to be balanced,
+ * and initiates a balancing operation if so.
+ *
+ * Balancing parameters are set up in arch_init_sched_domains.
+ */
+static DEFINE_SPINLOCK(balancing);
+
+static void run_rebalance_domains(struct softirq_action *h)
+{
+ int this_cpu = smp_processor_id(), balance = 1;
+ struct rq *this_rq = cpu_rq(this_cpu);
+ unsigned long interval;
+ struct sched_domain *sd;
+ /*
+ * We are idle if there are no processes running. This
+ * is valid even if we are the idle process (SMT).
+ */
+ enum idle_type idle = !this_rq->nr_running ?
+ SCHED_IDLE : NOT_IDLE;
+ /* Earliest time when we have to call run_rebalance_domains again */
+ unsigned long next_balance = jiffies + 60*HZ;
for_each_domain(this_cpu, sd) {
if (!(sd->flags & SD_LOAD_BALANCE))
@@ -2879,8 +2946,13 @@ rebalance_tick(int this_cpu, struct rq *this_rq, enum idle_type idle)
if (unlikely(!interval))
interval = 1;
- if (j - sd->last_balance >= interval) {
- if (load_balance(this_cpu, this_rq, sd, idle)) {
+ if (sd->flags & SD_SERIALIZE) {
+ if (!spin_trylock(&balancing))
+ goto out;
+ }
+
+ if (time_after_eq(jiffies, sd->last_balance + interval)) {
+ if (load_balance(this_cpu, this_rq, sd, idle, &balance)) {
/*
* We've pulled tasks over so either we're no
* longer idle, or one of our SMT siblings is
@@ -2888,39 +2960,48 @@ rebalance_tick(int this_cpu, struct rq *this_rq, enum idle_type idle)
*/
idle = NOT_IDLE;
}
- sd->last_balance += interval;
+ sd->last_balance = jiffies;
}
+ if (sd->flags & SD_SERIALIZE)
+ spin_unlock(&balancing);
+out:
+ if (time_after(next_balance, sd->last_balance + interval))
+ next_balance = sd->last_balance + interval;
+
+ /*
+ * Stop the load balance at this level. There is another
+ * CPU in our sched group which is doing load balancing more
+ * actively.
+ */
+ if (!balance)
+ break;
}
+ this_rq->next_balance = next_balance;
}
#else
/*
* on UP we do not need to balance between CPUs:
*/
-static inline void rebalance_tick(int cpu, struct rq *rq, enum idle_type idle)
-{
-}
static inline void idle_balance(int cpu, struct rq *rq)
{
}
#endif
-static inline int wake_priority_sleeper(struct rq *rq)
+static inline void wake_priority_sleeper(struct rq *rq)
{
- int ret = 0;
-
#ifdef CONFIG_SCHED_SMT
+ if (!rq->nr_running)
+ return;
+
spin_lock(&rq->lock);
/*
* If an SMT sibling task has been put to sleep for priority
* reasons reschedule the idle task to see if it can now run.
*/
- if (rq->nr_running) {
+ if (rq->nr_running)
resched_task(rq->idle);
- ret = 1;
- }
spin_unlock(&rq->lock);
#endif
- return ret;
}
DEFINE_PER_CPU(struct kernel_stat, kstat);
@@ -2934,7 +3015,8 @@ EXPORT_PER_CPU_SYMBOL(kstat);
static inline void
update_cpu_clock(struct task_struct *p, struct rq *rq, unsigned long long now)
{
- p->sched_time += now - max(p->timestamp, rq->timestamp_last_tick);
+ p->sched_time += now - p->last_ran;
+ p->last_ran = rq->most_recent_timestamp = now;
}
/*
@@ -2947,8 +3029,7 @@ unsigned long long current_sched_time(const struct task_struct *p)
unsigned long flags;
local_irq_save(flags);
- ns = max(p->timestamp, task_rq(p)->timestamp_last_tick);
- ns = p->sched_time + sched_clock() - ns;
+ ns = p->sched_time + sched_clock() - p->last_ran;
local_irq_restore(flags);
return ns;
@@ -3048,35 +3129,12 @@ void account_steal_time(struct task_struct *p, cputime_t steal)
cpustat->steal = cputime64_add(cpustat->steal, tmp);
}
-/*
- * This function gets called by the timer code, with HZ frequency.
- * We call it with interrupts disabled.
- *
- * It also gets called by the fork code, when changing the parent's
- * timeslices.
- */
-void scheduler_tick(void)
+static void task_running_tick(struct rq *rq, struct task_struct *p)
{
- unsigned long long now = sched_clock();
- struct task_struct *p = current;
- int cpu = smp_processor_id();
- struct rq *rq = cpu_rq(cpu);
-
- update_cpu_clock(p, rq, now);
-
- rq->timestamp_last_tick = now;
-
- if (p == rq->idle) {
- if (wake_priority_sleeper(rq))
- goto out;
- rebalance_tick(cpu, rq, SCHED_IDLE);
- return;
- }
-
- /* Task might have expired already, but not scheduled off yet */
if (p->array != rq->active) {
+ /* Task has expired but was not scheduled yet */
set_tsk_need_resched(p);
- goto out;
+ return;
}
spin_lock(&rq->lock);
/*
@@ -3144,8 +3202,34 @@ void scheduler_tick(void)
}
out_unlock:
spin_unlock(&rq->lock);
-out:
- rebalance_tick(cpu, rq, NOT_IDLE);
+}
+
+/*
+ * This function gets called by the timer code, with HZ frequency.
+ * We call it with interrupts disabled.
+ *
+ * It also gets called by the fork code, when changing the parent's
+ * timeslices.
+ */
+void scheduler_tick(void)
+{
+ unsigned long long now = sched_clock();
+ struct task_struct *p = current;
+ int cpu = smp_processor_id();
+ struct rq *rq = cpu_rq(cpu);
+
+ update_cpu_clock(p, rq, now);
+
+ if (p == rq->idle)
+ /* Task on the idle queue */
+ wake_priority_sleeper(rq);
+ else
+ task_running_tick(rq, p);
+#ifdef CONFIG_SMP
+ update_load(rq);
+ if (time_after_eq(jiffies, rq->next_balance))
+ raise_softirq(SCHED_SOFTIRQ);
+#endif
}
#ifdef CONFIG_SCHED_SMT
@@ -3291,7 +3375,8 @@ void fastcall add_preempt_count(int val)
/*
* Spinlock count overflowing soon?
*/
- DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >= PREEMPT_MASK-10);
+ DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >=
+ PREEMPT_MASK - 10);
}
EXPORT_SYMBOL(add_preempt_count);
@@ -3345,6 +3430,8 @@ asmlinkage void __sched schedule(void)
"%s/0x%08x/%d\n",
current->comm, preempt_count(), current->pid);
debug_show_held_locks(current);
+ if (irqs_disabled())
+ print_irqtrace_events(current);
dump_stack();
}
profile_hit(SCHED_PROFILING, __builtin_return_address(0));
@@ -4530,15 +4617,6 @@ asmlinkage long sys_sched_yield(void)
return 0;
}
-static inline int __resched_legal(int expected_preempt_count)
-{
- if (unlikely(preempt_count() != expected_preempt_count))
- return 0;
- if (unlikely(system_state != SYSTEM_RUNNING))
- return 0;
- return 1;
-}
-
static void __cond_resched(void)
{
#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
@@ -4558,7 +4636,8 @@ static void __cond_resched(void)
int __sched cond_resched(void)
{
- if (need_resched() && __resched_legal(0)) {
+ if (need_resched() && !(preempt_count() & PREEMPT_ACTIVE) &&
+ system_state == SYSTEM_RUNNING) {
__cond_resched();
return 1;
}
@@ -4584,7 +4663,7 @@ int cond_resched_lock(spinlock_t *lock)
ret = 1;
spin_lock(lock);
}
- if (need_resched() && __resched_legal(1)) {
+ if (need_resched() && system_state == SYSTEM_RUNNING) {
spin_release(&lock->dep_map, 1, _THIS_IP_);
_raw_spin_unlock(lock);
preempt_enable_no_resched();
@@ -4600,7 +4679,7 @@ int __sched cond_resched_softirq(void)
{
BUG_ON(!in_softirq());
- if (need_resched() && __resched_legal(0)) {
+ if (need_resched() && system_state == SYSTEM_RUNNING) {
raw_local_irq_disable();
_local_bh_enable();
raw_local_irq_enable();
@@ -4990,8 +5069,8 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
* afterwards, and pretending it was a local activate.
* This way is cleaner and logically correct.
*/
- p->timestamp = p->timestamp - rq_src->timestamp_last_tick
- + rq_dest->timestamp_last_tick;
+ p->timestamp = p->timestamp - rq_src->most_recent_timestamp
+ + rq_dest->most_recent_timestamp;
deactivate_task(p, rq_src);
__activate_task(p, rq_dest);
if (TASK_PREEMPTS_CURR(p, rq_dest))
@@ -5067,7 +5146,10 @@ wait_to_die:
}
#ifdef CONFIG_HOTPLUG_CPU
-/* Figure out where task on dead CPU should go, use force if neccessary. */
+/*
+ * Figure out where task on dead CPU should go, use force if neccessary.
+ * NOTE: interrupts should be disabled by the caller
+ */
static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *p)
{
unsigned long flags;
@@ -5187,6 +5269,7 @@ void idle_task_exit(void)
mmdrop(mm);
}
+/* called under rq->lock with disabled interrupts */
static void migrate_dead(unsigned int dead_cpu, struct task_struct *p)
{
struct rq *rq = cpu_rq(dead_cpu);
@@ -5203,10 +5286,11 @@ static void migrate_dead(unsigned int dead_cpu, struct task_struct *p)
* Drop lock around migration; if someone else moves it,
* that's OK. No task can be added to this CPU, so iteration is
* fine.
+ * NOTE: interrupts should be left disabled --dev@
*/
- spin_unlock_irq(&rq->lock);
+ spin_unlock(&rq->lock);
move_task_off_dead_cpu(dead_cpu, p);
- spin_lock_irq(&rq->lock);
+ spin_lock(&rq->lock);
put_task_struct(p);
}
@@ -5359,16 +5443,19 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
if (!(sd->flags & SD_LOAD_BALANCE)) {
printk("does not load-balance\n");
if (sd->parent)
- printk(KERN_ERR "ERROR: !SD_LOAD_BALANCE domain has parent");
+ printk(KERN_ERR "ERROR: !SD_LOAD_BALANCE domain"
+ " has parent");
break;
}
printk("span %s\n", str);
if (!cpu_isset(cpu, sd->span))
- printk(KERN_ERR "ERROR: domain->span does not contain CPU%d\n", cpu);
+ printk(KERN_ERR "ERROR: domain->span does not contain "
+ "CPU%d\n", cpu);
if (!cpu_isset(cpu, group->cpumask))
- printk(KERN_ERR "ERROR: domain->groups does not contain CPU%d\n", cpu);
+ printk(KERN_ERR "ERROR: domain->groups does not contain"
+ " CPU%d\n", cpu);
printk(KERN_DEBUG);
for (i = 0; i < level + 2; i++)
@@ -5383,7 +5470,8 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
if (!group->cpu_power) {
printk("\n");
- printk(KERN_ERR "ERROR: domain->cpu_power not set\n");
+ printk(KERN_ERR "ERROR: domain->cpu_power not "
+ "set\n");
}
if (!cpus_weight(group->cpumask)) {
@@ -5406,15 +5494,17 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
printk("\n");
if (!cpus_equal(sd->span, groupmask))
- printk(KERN_ERR "ERROR: groups don't span domain->span\n");
+ printk(KERN_ERR "ERROR: groups don't span "
+ "domain->span\n");
level++;
sd = sd->parent;
+ if (!sd)
+ continue;
- if (sd) {
- if (!cpus_subset(groupmask, sd->span))
- printk(KERN_ERR "ERROR: parent span is not a superset of domain->span\n");
- }
+ if (!cpus_subset(groupmask, sd->span))
+ printk(KERN_ERR "ERROR: parent span is not a superset "
+ "of domain->span\n");
} while (sd);
}
@@ -5510,7 +5600,7 @@ static void cpu_attach_domain(struct sched_domain *sd, int cpu)
}
/* cpus with isolated domains */
-static cpumask_t __cpuinitdata cpu_isolated_map = CPU_MASK_NONE;
+static cpumask_t cpu_isolated_map = CPU_MASK_NONE;
/* Setup the mask of cpus configured for isolated domains */
static int __init isolated_cpu_setup(char *str)
@@ -5528,28 +5618,27 @@ static int __init isolated_cpu_setup(char *str)
__setup ("isolcpus=", isolated_cpu_setup);
/*
- * init_sched_build_groups takes an array of groups, the cpumask we wish
- * to span, and a pointer to a function which identifies what group a CPU
- * belongs to. The return value of group_fn must be a valid index into the
- * groups[] array, and must be >= 0 and < NR_CPUS (due to the fact that we
- * keep track of groups covered with a cpumask_t).
+ * init_sched_build_groups takes the cpumask we wish to span, and a pointer
+ * to a function which identifies what group(along with sched group) a CPU
+ * belongs to. The return value of group_fn must be a >= 0 and < NR_CPUS
+ * (due to the fact that we keep track of groups covered with a cpumask_t).
*
* init_sched_build_groups will build a circular linked list of the groups
* 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,
- const cpumask_t *cpu_map,
- int (*group_fn)(int cpu, const cpumask_t *cpu_map))
+init_sched_build_groups(cpumask_t span, const cpumask_t *cpu_map,
+ int (*group_fn)(int cpu, const cpumask_t *cpu_map,
+ struct sched_group **sg))
{
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, cpu_map);
- struct sched_group *sg = &groups[group];
+ struct sched_group *sg;
+ int group = group_fn(i, cpu_map, &sg);
int j;
if (cpu_isset(i, covered))
@@ -5559,7 +5648,7 @@ 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, cpu_map) != group)
+ if (group_fn(j, cpu_map, NULL) != group)
continue;
cpu_set(j, covered);
@@ -5733,8 +5822,9 @@ __setup("max_cache_size=", setup_max_cache_size);
*/
static void touch_cache(void *__cache, unsigned long __size)
{
- unsigned long size = __size/sizeof(long), chunk1 = size/3,
- chunk2 = 2*size/3;
+ unsigned long size = __size / sizeof(long);
+ unsigned long chunk1 = size / 3;
+ unsigned long chunk2 = 2 * size / 3;
unsigned long *cache = __cache;
int i;
@@ -5843,11 +5933,11 @@ measure_cost(int cpu1, int cpu2, void *cache, unsigned int size)
*/
measure_one(cache, size, cpu1, cpu2);
for (i = 0; i < ITERATIONS; i++)
- cost1 += measure_one(cache, size - i*1024, cpu1, cpu2);
+ cost1 += measure_one(cache, size - i * 1024, cpu1, cpu2);
measure_one(cache, size, cpu2, cpu1);
for (i = 0; i < ITERATIONS; i++)
- cost1 += measure_one(cache, size - i*1024, cpu2, cpu1);
+ cost1 += measure_one(cache, size - i * 1024, cpu2, cpu1);
/*
* (We measure the non-migrating [cached] cost on both
@@ -5857,17 +5947,17 @@ measure_cost(int cpu1, int cpu2, void *cache, unsigned int size)
measure_one(cache, size, cpu1, cpu1);
for (i = 0; i < ITERATIONS; i++)
- cost2 += measure_one(cache, size - i*1024, cpu1, cpu1);
+ cost2 += measure_one(cache, size - i * 1024, cpu1, cpu1);
measure_one(cache, size, cpu2, cpu2);
for (i = 0; i < ITERATIONS; i++)
- cost2 += measure_one(cache, size - i*1024, cpu2, cpu2);
+ cost2 += measure_one(cache, size - i * 1024, cpu2, cpu2);
/*
* Get the per-iteration migration cost:
*/
- do_div(cost1, 2*ITERATIONS);
- do_div(cost2, 2*ITERATIONS);
+ do_div(cost1, 2 * ITERATIONS);
+ do_div(cost2, 2 * ITERATIONS);
return cost1 - cost2;
}
@@ -5905,7 +5995,7 @@ static unsigned long long measure_migration_cost(int cpu1, int cpu2)
*/
cache = vmalloc(max_size);
if (!cache) {
- printk("could not vmalloc %d bytes for cache!\n", 2*max_size);
+ printk("could not vmalloc %d bytes for cache!\n", 2 * max_size);
return 1000000; /* return 1 msec on very small boxen */
}
@@ -5930,7 +6020,8 @@ static unsigned long long measure_migration_cost(int cpu1, int cpu2)
avg_fluct = (avg_fluct + fluct)/2;
if (migration_debug)
- printk("-> [%d][%d][%7d] %3ld.%ld [%3ld.%ld] (%ld): (%8Ld %8Ld)\n",
+ printk("-> [%d][%d][%7d] %3ld.%ld [%3ld.%ld] (%ld): "
+ "(%8Ld %8Ld)\n",
cpu1, cpu2, size,
(long)cost / 1000000,
((long)cost / 100000) % 10,
@@ -6025,20 +6116,18 @@ static void calibrate_migration_costs(const cpumask_t *cpu_map)
-1
#endif
);
- if (system_state == SYSTEM_BOOTING) {
- 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");
+ if (system_state == SYSTEM_BOOTING && 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");
}
j1 = jiffies;
if (migration_debug)
- printk("migration: %ld seconds\n", (j1-j0)/HZ);
+ printk("migration: %ld seconds\n", (j1-j0) / HZ);
/*
* Move back to the original CPU. NUMA-Q gets confused
@@ -6135,10 +6224,13 @@ int sched_smt_power_savings = 0, sched_mc_power_savings = 0;
*/
#ifdef CONFIG_SCHED_SMT
static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
-static struct sched_group sched_group_cpus[NR_CPUS];
+static DEFINE_PER_CPU(struct sched_group, sched_group_cpus);
-static int cpu_to_cpu_group(int cpu, const cpumask_t *cpu_map)
+static int cpu_to_cpu_group(int cpu, const cpumask_t *cpu_map,
+ struct sched_group **sg)
{
+ if (sg)
+ *sg = &per_cpu(sched_group_cpus, cpu);
return cpu;
}
#endif
@@ -6148,39 +6240,52 @@ static int cpu_to_cpu_group(int cpu, const cpumask_t *cpu_map)
*/
#ifdef CONFIG_SCHED_MC
static DEFINE_PER_CPU(struct sched_domain, core_domains);
-static struct sched_group sched_group_core[NR_CPUS];
+static DEFINE_PER_CPU(struct sched_group, sched_group_core);
#endif
#if defined(CONFIG_SCHED_MC) && defined(CONFIG_SCHED_SMT)
-static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map)
+static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map,
+ struct sched_group **sg)
{
+ int group;
cpumask_t mask = cpu_sibling_map[cpu];
cpus_and(mask, mask, *cpu_map);
- return first_cpu(mask);
+ group = first_cpu(mask);
+ if (sg)
+ *sg = &per_cpu(sched_group_core, group);
+ return group;
}
#elif defined(CONFIG_SCHED_MC)
-static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map)
+static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map,
+ struct sched_group **sg)
{
+ if (sg)
+ *sg = &per_cpu(sched_group_core, cpu);
return cpu;
}
#endif
static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-static struct sched_group sched_group_phys[NR_CPUS];
+static DEFINE_PER_CPU(struct sched_group, sched_group_phys);
-static int cpu_to_phys_group(int cpu, const cpumask_t *cpu_map)
+static int cpu_to_phys_group(int cpu, const cpumask_t *cpu_map,
+ struct sched_group **sg)
{
+ int group;
#ifdef CONFIG_SCHED_MC
cpumask_t mask = cpu_coregroup_map(cpu);
cpus_and(mask, mask, *cpu_map);
- return first_cpu(mask);
+ group = first_cpu(mask);
#elif defined(CONFIG_SCHED_SMT)
cpumask_t mask = cpu_sibling_map[cpu];
cpus_and(mask, mask, *cpu_map);
- return first_cpu(mask);
+ group = first_cpu(mask);
#else
- return cpu;
+ group = cpu;
#endif
+ if (sg)
+ *sg = &per_cpu(sched_group_phys, group);
+ return group;
}
#ifdef CONFIG_NUMA
@@ -6193,12 +6298,22 @@ static DEFINE_PER_CPU(struct sched_domain, node_domains);
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 DEFINE_PER_CPU(struct sched_group, sched_group_allnodes);
-static int cpu_to_allnodes_group(int cpu, const cpumask_t *cpu_map)
+static int cpu_to_allnodes_group(int cpu, const cpumask_t *cpu_map,
+ struct sched_group **sg)
{
- return cpu_to_node(cpu);
+ cpumask_t nodemask = node_to_cpumask(cpu_to_node(cpu));
+ int group;
+
+ cpus_and(nodemask, nodemask, *cpu_map);
+ group = first_cpu(nodemask);
+
+ if (sg)
+ *sg = &per_cpu(sched_group_allnodes, group);
+ return group;
}
+
static void init_numa_sched_groups_power(struct sched_group *group_head)
{
struct sched_group *sg = group_head;
@@ -6234,16 +6349,9 @@ static void free_sched_groups(const cpumask_t *cpu_map)
int cpu, i;
for_each_cpu_mask(cpu, *cpu_map) {
- struct sched_group *sched_group_allnodes
- = sched_group_allnodes_bycpu[cpu];
struct sched_group **sched_group_nodes
= sched_group_nodes_bycpu[cpu];
- if (sched_group_allnodes) {
- kfree(sched_group_allnodes);
- sched_group_allnodes_bycpu[cpu] = NULL;
- }
-
if (!sched_group_nodes)
continue;
@@ -6337,7 +6445,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
struct sched_domain *sd;
#ifdef CONFIG_NUMA
struct sched_group **sched_group_nodes = NULL;
- struct sched_group *sched_group_allnodes = NULL;
+ int sd_allnodes = 0;
/*
* Allocate the per-node list of sched groups
@@ -6355,7 +6463,6 @@ static int build_sched_domains(const cpumask_t *cpu_map)
* Set up domains for cpus specified by the cpu_map.
*/
for_each_cpu_mask(i, *cpu_map) {
- int group;
struct sched_domain *sd = NULL, *p;
cpumask_t nodemask = node_to_cpumask(cpu_to_node(i));
@@ -6364,26 +6471,12 @@ static int build_sched_domains(const cpumask_t *cpu_map)
#ifdef CONFIG_NUMA
if (cpus_weight(*cpu_map)
> SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
- if (!sched_group_allnodes) {
- sched_group_allnodes
- = 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");
- goto error;
- }
- sched_group_allnodes_bycpu[i]
- = sched_group_allnodes;
- }
sd = &per_cpu(allnodes_domains, i);
*sd = SD_ALLNODES_INIT;
sd->span = *cpu_map;
- group = cpu_to_allnodes_group(i, cpu_map);
- sd->groups = &sched_group_allnodes[group];
+ cpu_to_allnodes_group(i, cpu_map, &sd->groups);
p = sd;
+ sd_allnodes = 1;
} else
p = NULL;
@@ -6398,36 +6491,33 @@ static int build_sched_domains(const cpumask_t *cpu_map)
p = sd;
sd = &per_cpu(phys_domains, 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];
+ cpu_to_phys_group(i, cpu_map, &sd->groups);
#ifdef CONFIG_SCHED_MC
p = sd;
sd = &per_cpu(core_domains, 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];
+ cpu_to_core_group(i, cpu_map, &sd->groups);
#endif
#ifdef CONFIG_SCHED_SMT
p = sd;
sd = &per_cpu(cpu_domains, 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];
+ cpu_to_cpu_group(i, cpu_map, &sd->groups);
#endif
}
@@ -6439,8 +6529,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
if (i != first_cpu(this_sibling_map))
continue;
- init_sched_build_groups(sched_group_cpus, this_sibling_map,
- cpu_map, &cpu_to_cpu_group);
+ init_sched_build_groups(this_sibling_map, cpu_map, &cpu_to_cpu_group);
}
#endif
@@ -6451,8 +6540,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
cpus_and(this_core_map, this_core_map, *cpu_map);
if (i != first_cpu(this_core_map))
continue;
- init_sched_build_groups(sched_group_core, this_core_map,
- cpu_map, &cpu_to_core_group);
+ init_sched_build_groups(this_core_map, cpu_map, &cpu_to_core_group);
}
#endif
@@ -6465,15 +6553,13 @@ static int build_sched_domains(const cpumask_t *cpu_map)
if (cpus_empty(nodemask))
continue;
- init_sched_build_groups(sched_group_phys, nodemask,
- cpu_map, &cpu_to_phys_group);
+ init_sched_build_groups(nodemask, 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_map, &cpu_to_allnodes_group);
+ if (sd_allnodes)
+ init_sched_build_groups(*cpu_map, cpu_map, &cpu_to_allnodes_group);
for (i = 0; i < MAX_NUMNODES; i++) {
/* Set up node groups */
@@ -6565,10 +6651,10 @@ static int build_sched_domains(const cpumask_t *cpu_map)
for (i = 0; i < MAX_NUMNODES; i++)
init_numa_sched_groups_power(sched_group_nodes[i]);
- if (sched_group_allnodes) {
- int group = cpu_to_allnodes_group(first_cpu(*cpu_map), cpu_map);
- struct sched_group *sg = &sched_group_allnodes[group];
+ if (sd_allnodes) {
+ struct sched_group *sg;
+ cpu_to_allnodes_group(first_cpu(*cpu_map), cpu_map, &sg);
init_numa_sched_groups_power(sg);
}
#endif
@@ -6779,7 +6865,7 @@ void __init sched_init_smp(void)
lock_cpu_hotplug();
arch_init_sched_domains(&cpu_online_map);
- cpus_andnot(non_isolated_cpus, cpu_online_map, cpu_isolated_map);
+ cpus_andnot(non_isolated_cpus, cpu_possible_map, cpu_isolated_map);
if (cpus_empty(non_isolated_cpus))
cpu_set(smp_processor_id(), non_isolated_cpus);
unlock_cpu_hotplug();
@@ -6847,6 +6933,10 @@ void __init sched_init(void)
set_load_weight(&init_task);
+#ifdef CONFIG_SMP
+ open_softirq(SCHED_SOFTIRQ, run_rebalance_domains, NULL);
+#endif
+
#ifdef CONFIG_RT_MUTEXES
plist_head_init(&init_task.pi_waiters, &init_task.pi_lock);
#endif
@@ -6882,6 +6972,8 @@ void __might_sleep(char *file, int line)
printk("in_atomic():%d, irqs_disabled():%d\n",
in_atomic(), irqs_disabled());
debug_show_held_locks(current);
+ if (irqs_disabled())
+ print_irqtrace_events(current);
dump_stack();
}
#endif
diff --git a/kernel/signal.c b/kernel/signal.c
index ec81defde33..5630255d2e2 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -24,6 +24,9 @@
#include <linux/signal.h>
#include <linux/capability.h>
#include <linux/freezer.h>
+#include <linux/pid_namespace.h>
+#include <linux/nsproxy.h>
+
#include <asm/param.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -583,7 +586,7 @@ static int check_kill_permission(int sig, struct siginfo *info,
error = -EPERM;
if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info)))
&& ((sig != SIGCONT) ||
- (current->signal->session != t->signal->session))
+ (process_session(current) != process_session(t)))
&& (current->euid ^ t->suid) && (current->euid ^ t->uid)
&& (current->uid ^ t->suid) && (current->uid ^ t->uid)
&& !capable(CAP_KILL))
@@ -1702,7 +1705,9 @@ finish_stop(int stop_count)
read_unlock(&tasklist_lock);
}
- schedule();
+ do {
+ schedule();
+ } while (try_to_freeze());
/*
* Now we don't run again until continued.
*/
@@ -1877,8 +1882,12 @@ relock:
if (sig_kernel_ignore(signr)) /* Default is nothing. */
continue;
- /* Init gets no signals it doesn't want. */
- if (current == child_reaper)
+ /*
+ * Init of a pid space gets no signals it doesn't want from
+ * within that pid space. It can of course get signals from
+ * its parent pid space.
+ */
+ if (current == child_reaper(current))
continue;
if (sig_kernel_stop(signr)) {
diff --git a/kernel/sys.c b/kernel/sys.c
index a0c1a29a507..6e2101dec0f 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -323,11 +323,18 @@ EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v)
{
- int ret;
+ int ret = NOTIFY_DONE;
- down_read(&nh->rwsem);
- ret = notifier_call_chain(&nh->head, val, v);
- up_read(&nh->rwsem);
+ /*
+ * We check the head outside the lock, but if this access is
+ * racy then it does not matter what the result of the test
+ * is, we re-check the list after having taken the lock anyway:
+ */
+ if (rcu_dereference(nh->head)) {
+ down_read(&nh->rwsem);
+ ret = notifier_call_chain(&nh->head, val, v);
+ up_read(&nh->rwsem);
+ }
return ret;
}
@@ -1381,7 +1388,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
if (p->real_parent == group_leader) {
err = -EPERM;
- if (p->signal->session != group_leader->signal->session)
+ if (process_session(p) != process_session(group_leader))
goto out;
err = -EACCES;
if (p->did_exec)
@@ -1397,16 +1404,13 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
goto out;
if (pgid != pid) {
- struct task_struct *p;
+ struct task_struct *g =
+ find_task_by_pid_type(PIDTYPE_PGID, pgid);
- do_each_task_pid(pgid, PIDTYPE_PGID, p) {
- if (p->signal->session == group_leader->signal->session)
- goto ok_pgid;
- } while_each_task_pid(pgid, PIDTYPE_PGID, p);
- goto out;
+ if (!g || process_session(g) != process_session(group_leader))
+ goto out;
}
-ok_pgid:
err = security_task_setpgid(p, pgid);
if (err)
goto out;
@@ -1459,7 +1463,7 @@ asmlinkage long sys_getpgrp(void)
asmlinkage long sys_getsid(pid_t pid)
{
if (!pid)
- return current->signal->session;
+ return process_session(current);
else {
int retval;
struct task_struct *p;
@@ -1471,7 +1475,7 @@ asmlinkage long sys_getsid(pid_t pid)
if (p) {
retval = security_task_getsid(p);
if (!retval)
- retval = p->signal->session;
+ retval = process_session(p);
}
read_unlock(&tasklist_lock);
return retval;
@@ -1484,7 +1488,6 @@ asmlinkage long sys_setsid(void)
pid_t session;
int err = -EPERM;
- mutex_lock(&tty_mutex);
write_lock_irq(&tasklist_lock);
/* Fail if I am already a session leader */
@@ -1504,12 +1507,15 @@ asmlinkage long sys_setsid(void)
group_leader->signal->leader = 1;
__set_special_pids(session, session);
+
+ spin_lock(&group_leader->sighand->siglock);
group_leader->signal->tty = NULL;
group_leader->signal->tty_old_pgrp = 0;
+ spin_unlock(&group_leader->sighand->siglock);
+
err = process_group(group_leader);
out:
write_unlock_irq(&tasklist_lock);
- mutex_unlock(&tty_mutex);
return err;
}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 8e9f00fd6d1..600b33358de 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -65,7 +65,6 @@ extern int sysctl_overcommit_memory;
extern int sysctl_overcommit_ratio;
extern int sysctl_panic_on_oom;
extern int max_threads;
-extern int sysrq_enabled;
extern int core_uses_pid;
extern int suid_dumpable;
extern char core_pattern[];
@@ -92,7 +91,9 @@ extern char modprobe_path[];
extern int sg_big_buff;
#endif
#ifdef CONFIG_SYSVIPC
-static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp,
+static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
#endif
@@ -131,12 +132,22 @@ extern int max_lock_depth;
#ifdef CONFIG_SYSCTL_SYSCALL
static int parse_table(int __user *, int, void __user *, size_t __user *,
- void __user *, size_t, ctl_table *, void **);
+ void __user *, size_t, ctl_table *);
#endif
static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
+static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen);
+
+#ifdef CONFIG_SYSVIPC
+static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen);
+#endif
+
#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);
@@ -163,6 +174,40 @@ extern ctl_table inotify_table[];
int sysctl_legacy_va_layout;
#endif
+static void *get_uts(ctl_table *table, int write)
+{
+ char *which = table->data;
+#ifdef CONFIG_UTS_NS
+ struct uts_namespace *uts_ns = current->nsproxy->uts_ns;
+ which = (which - (char *)&init_uts_ns) + (char *)uts_ns;
+#endif
+ if (!write)
+ down_read(&uts_sem);
+ else
+ down_write(&uts_sem);
+ return which;
+}
+
+static void put_uts(ctl_table *table, int write, void *which)
+{
+ if (!write)
+ up_read(&uts_sem);
+ else
+ up_write(&uts_sem);
+}
+
+#ifdef CONFIG_SYSVIPC
+static void *get_ipc(ctl_table *table, int write)
+{
+ char *which = table->data;
+ struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
+ which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
+ return which;
+}
+#else
+#define get_ipc(T,W) ((T)->data)
+#endif
+
/* /proc declarations: */
#ifdef CONFIG_PROC_SYSCTL
@@ -229,7 +274,6 @@ static ctl_table root_table[] = {
};
static ctl_table kern_table[] = {
-#ifndef CONFIG_UTS_NS
{
.ctl_name = KERN_OSTYPE,
.procname = "ostype",
@@ -237,7 +281,7 @@ static ctl_table kern_table[] = {
.maxlen = sizeof(init_uts_ns.name.sysname),
.mode = 0444,
.proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
+ .strategy = &sysctl_uts_string,
},
{
.ctl_name = KERN_OSRELEASE,
@@ -246,7 +290,7 @@ static ctl_table kern_table[] = {
.maxlen = sizeof(init_uts_ns.name.release),
.mode = 0444,
.proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
+ .strategy = &sysctl_uts_string,
},
{
.ctl_name = KERN_VERSION,
@@ -255,7 +299,7 @@ static ctl_table kern_table[] = {
.maxlen = sizeof(init_uts_ns.name.version),
.mode = 0444,
.proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
+ .strategy = &sysctl_uts_string,
},
{
.ctl_name = KERN_NODENAME,
@@ -264,7 +308,7 @@ static ctl_table kern_table[] = {
.maxlen = sizeof(init_uts_ns.name.nodename),
.mode = 0644,
.proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
+ .strategy = &sysctl_uts_string,
},
{
.ctl_name = KERN_DOMAINNAME,
@@ -273,56 +317,8 @@ static ctl_table kern_table[] = {
.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 = NULL,
- /* could maybe use __NEW_UTS_LEN here? */
- .maxlen = FIELD_SIZEOF(struct new_utsname, sysname),
- .mode = 0444,
- .proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
- },
- {
- .ctl_name = KERN_OSRELEASE,
- .procname = "osrelease",
- .data = NULL,
- .maxlen = FIELD_SIZEOF(struct new_utsname, release),
- .mode = 0444,
- .proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
- },
- {
- .ctl_name = KERN_VERSION,
- .procname = "version",
- .data = NULL,
- .maxlen = FIELD_SIZEOF(struct new_utsname, version),
- .mode = 0444,
- .proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
- },
- {
- .ctl_name = KERN_NODENAME,
- .procname = "hostname",
- .data = NULL,
- .maxlen = FIELD_SIZEOF(struct new_utsname, nodename),
- .mode = 0644,
- .proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
- },
- {
- .ctl_name = KERN_DOMAINNAME,
- .procname = "domainname",
- .data = NULL,
- .maxlen = FIELD_SIZEOF(struct new_utsname, domainname),
- .mode = 0644,
- .proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
+ .strategy = &sysctl_uts_string,
},
-#endif /* !CONFIG_UTS_NS */
{
.ctl_name = KERN_PANIC,
.procname = "panic",
@@ -481,65 +477,72 @@ static ctl_table kern_table[] = {
{
.ctl_name = KERN_SHMMAX,
.procname = "shmmax",
- .data = NULL,
- .maxlen = sizeof (size_t),
+ .data = &init_ipc_ns.shm_ctlmax,
+ .maxlen = sizeof (init_ipc_ns.shm_ctlmax),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_doulongvec_minmax,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_SHMALL,
.procname = "shmall",
- .data = NULL,
- .maxlen = sizeof (size_t),
+ .data = &init_ipc_ns.shm_ctlall,
+ .maxlen = sizeof (init_ipc_ns.shm_ctlall),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_doulongvec_minmax,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_SHMMNI,
.procname = "shmmni",
- .data = NULL,
- .maxlen = sizeof (int),
+ .data = &init_ipc_ns.shm_ctlmni,
+ .maxlen = sizeof (init_ipc_ns.shm_ctlmni),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_dointvec,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_MSGMAX,
.procname = "msgmax",
- .data = NULL,
- .maxlen = sizeof (int),
+ .data = &init_ipc_ns.msg_ctlmax,
+ .maxlen = sizeof (init_ipc_ns.msg_ctlmax),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_dointvec,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_MSGMNI,
.procname = "msgmni",
- .data = NULL,
- .maxlen = sizeof (int),
+ .data = &init_ipc_ns.msg_ctlmni,
+ .maxlen = sizeof (init_ipc_ns.msg_ctlmni),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_dointvec,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_MSGMNB,
.procname = "msgmnb",
- .data = NULL,
- .maxlen = sizeof (int),
+ .data = &init_ipc_ns.msg_ctlmnb,
+ .maxlen = sizeof (init_ipc_ns.msg_ctlmnb),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_dointvec,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_SEM,
.procname = "sem",
- .data = NULL,
+ .data = &init_ipc_ns.sem_ctls,
.maxlen = 4*sizeof (int),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_dointvec,
+ .strategy = sysctl_ipc_data,
},
#endif
#ifdef CONFIG_MAGIC_SYSRQ
{
.ctl_name = KERN_SYSRQ,
.procname = "sysrq",
- .data = &sysrq_enabled,
+ .data = &__sysrq_enabled,
.maxlen = sizeof (int),
.mode = 0644,
.proc_handler = &proc_dointvec,
@@ -1239,7 +1242,6 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
do {
struct ctl_table_header *head =
list_entry(tmp, struct ctl_table_header, ctl_entry);
- void *context = NULL;
if (!use_table(head))
continue;
@@ -1247,9 +1249,7 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
spin_unlock(&sysctl_lock);
error = parse_table(name, nlen, oldval, oldlenp,
- newval, newlen, head->ctl_table,
- &context);
- kfree(context);
+ newval, newlen, head->ctl_table);
spin_lock(&sysctl_lock);
unuse_table(head);
@@ -1305,7 +1305,7 @@ static inline int ctl_perm(ctl_table *table, int op)
static int parse_table(int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen,
- ctl_table *table, void **context)
+ ctl_table *table)
{
int n;
repeat:
@@ -1325,7 +1325,7 @@ repeat:
error = table->strategy(
table, name, nlen,
oldval, oldlenp,
- newval, newlen, context);
+ newval, newlen);
if (error)
return error;
}
@@ -1336,7 +1336,7 @@ repeat:
}
error = do_sysctl_strategy(table, name, nlen,
oldval, oldlenp,
- newval, newlen, context);
+ newval, newlen);
return error;
}
}
@@ -1347,7 +1347,7 @@ repeat:
int do_sysctl_strategy (ctl_table *table,
int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
int op = 0, rc;
size_t len;
@@ -1361,7 +1361,7 @@ int do_sysctl_strategy (ctl_table *table,
if (table->strategy) {
rc = table->strategy(table, name, nlen, oldval, oldlenp,
- newval, newlen, context);
+ newval, newlen);
if (rc < 0)
return rc;
if (rc > 0)
@@ -1614,7 +1614,7 @@ static ssize_t do_rw_proc(int write, struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
int op;
- struct proc_dir_entry *de = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *de = PDE(file->f_path.dentry->d_inode);
struct ctl_table *table;
size_t res;
ssize_t error = -ENOTDIR;
@@ -1753,66 +1753,17 @@ int proc_dostring(ctl_table *table, int write, struct file *filp,
* Special case of dostring for the UTS structure. This has locks
* to observe. Should this be in kernel/sys.c ????
*/
-
-#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;
- if (!write) {
- down_read(&uts_sem);
- r=proc_dostring(table,0,filp,buffer,lenp, ppos);
- up_read(&uts_sem);
- } else {
- down_write(&uts_sem);
- r=proc_dostring(table,1,filp,buffer,lenp, ppos);
- up_write(&uts_sem);
- }
- 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:
+ void *which;
+ which = get_uts(table, write);
+ r = _proc_do_string(which, table->maxlen,write,filp,buffer,lenp, ppos);
+ put_uts(table, write, which);
return r;
}
-#endif /* !CONFIG_UTS_NS */
static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
int *valp,
@@ -1976,9 +1927,6 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp,
#define OP_SET 0
#define OP_AND 1
-#define OP_OR 2
-#define OP_MAX 3
-#define OP_MIN 4
static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
int *valp,
@@ -1990,13 +1938,6 @@ static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
switch(op) {
case OP_SET: *valp = val; break;
case OP_AND: *valp &= val; break;
- case OP_OR: *valp |= val; break;
- case OP_MAX: if(*valp < val)
- *valp = val;
- break;
- case OP_MIN: if(*valp > val)
- *valp = val;
- break;
}
} else {
int val = *valp;
@@ -2391,46 +2332,24 @@ int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp,
}
#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)
+static int proc_ipc_dointvec(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,
+ void *which;
+ which = get_ipc(table, write);
+ return __do_proc_dointvec(which, table, write, filp, buffer,
lenp, ppos, NULL, NULL);
-proc_minmax:
- return __do_proc_doulongvec_minmax(data, table, write, filp, buffer,
+}
+
+static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
+ struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ void *which;
+ which = get_ipc(table, write);
+ return __do_proc_doulongvec_minmax(which, table, write, filp, buffer,
lenp, ppos, 1l, 1l);
}
+
#endif
static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp,
@@ -2475,6 +2394,17 @@ static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp,
{
return -ENOSYS;
}
+static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return -ENOSYS;
+}
+static int proc_ipc_doulongvec_minmax(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,
@@ -2539,7 +2469,7 @@ int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
/* The generic string strategy routine: */
int sysctl_string(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
if (!table->data || !table->maxlen)
return -ENOTDIR;
@@ -2585,7 +2515,7 @@ int sysctl_string(ctl_table *table, int __user *name, int nlen,
*/
int sysctl_intvec(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
if (newval && newlen) {
@@ -2621,7 +2551,7 @@ int sysctl_intvec(ctl_table *table, int __user *name, int nlen,
/* Strategy function to convert jiffies to seconds */
int sysctl_jiffies(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
if (oldval) {
size_t olen;
@@ -2649,7 +2579,7 @@ int sysctl_jiffies(ctl_table *table, int __user *name, int nlen,
/* Strategy function to convert jiffies to seconds */
int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
if (oldval) {
size_t olen;
@@ -2674,6 +2604,64 @@ int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen,
return 1;
}
+
+/* The generic string strategy routine: */
+static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen)
+{
+ struct ctl_table uts_table;
+ int r, write;
+ write = newval && newlen;
+ memcpy(&uts_table, table, sizeof(uts_table));
+ uts_table.data = get_uts(table, write);
+ r = sysctl_string(&uts_table, name, nlen,
+ oldval, oldlenp, newval, newlen);
+ put_uts(table, write, uts_table.data);
+ return r;
+}
+
+#ifdef CONFIG_SYSVIPC
+/* The generic sysctl ipc data routine. */
+static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen)
+{
+ size_t len;
+ void *data;
+
+ /* Get out of I don't have a variable */
+ if (!table->data || !table->maxlen)
+ return -ENOTDIR;
+
+ data = get_ipc(table, 1);
+ if (!data)
+ return -ENOTDIR;
+
+ if (oldval && oldlenp) {
+ if (get_user(len, oldlenp))
+ return -EFAULT;
+ if (len) {
+ if (len > table->maxlen)
+ len = table->maxlen;
+ if (copy_to_user(oldval, data, len))
+ return -EFAULT;
+ if (put_user(len, oldlenp))
+ return -EFAULT;
+ }
+ }
+
+ if (newval && newlen) {
+ if (newlen > table->maxlen)
+ newlen = table->maxlen;
+
+ if (copy_from_user(data, newval, newlen))
+ return -EFAULT;
+ }
+ return 1;
+}
+#endif
+
#else /* CONFIG_SYSCTL_SYSCALL */
@@ -2712,32 +2700,44 @@ out:
int sysctl_string(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
return -ENOSYS;
}
int sysctl_intvec(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
return -ENOSYS;
}
int sysctl_jiffies(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
return -ENOSYS;
}
int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
+ void __user *newval, size_t newlen)
{
return -ENOSYS;
}
+static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen)
+{
+ return -ENOSYS;
+}
+static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen)
+{
+ return -ENOSYS;
+}
#endif /* CONFIG_SYSCTL_SYSCALL */
/*
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 74eca5939bd..22504afc0d3 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -156,7 +156,7 @@ int clocksource_register(struct clocksource *c)
/* check if clocksource is already registered */
if (is_registered_source(c)) {
printk("register_clocksource: Cannot register %s. "
- "Already registered!", c->name);
+ "Already registered!", c->name);
ret = -EBUSY;
} else {
/* register it */
@@ -186,6 +186,7 @@ void clocksource_reselect(void)
}
EXPORT_SYMBOL(clocksource_reselect);
+#ifdef CONFIG_SYSFS
/**
* sysfs_show_current_clocksources - sysfs interface for current clocksource
* @dev: unused
@@ -275,10 +276,10 @@ sysfs_show_available_clocksources(struct sys_device *dev, char *buf)
* Sysfs setup bits:
*/
static SYSDEV_ATTR(current_clocksource, 0600, sysfs_show_current_clocksources,
- sysfs_override_clocksource);
+ sysfs_override_clocksource);
static SYSDEV_ATTR(available_clocksource, 0600,
- sysfs_show_available_clocksources, NULL);
+ sysfs_show_available_clocksources, NULL);
static struct sysdev_class clocksource_sysclass = {
set_kset_name("clocksource"),
@@ -307,6 +308,7 @@ static int __init init_clocksource_sysfs(void)
}
device_initcall(init_clocksource_sysfs);
+#endif /* CONFIG_SYSFS */
/**
* boot_override_clocksource - boot clock override
diff --git a/kernel/timer.c b/kernel/timer.c
index c1c7fbcffec..c2a8ccfc288 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -80,6 +80,138 @@ tvec_base_t boot_tvec_bases;
EXPORT_SYMBOL(boot_tvec_bases);
static DEFINE_PER_CPU(tvec_base_t *, tvec_bases) = &boot_tvec_bases;
+/**
+ * __round_jiffies - function to round jiffies to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ * @cpu: the processor number on which the timeout will happen
+ *
+ * __round_jiffies rounds an absolute time in the future (in jiffies)
+ * up or down to (approximately) full seconds. This is useful for timers
+ * for which the exact time they fire does not matter too much, as long as
+ * they fire approximately every X seconds.
+ *
+ * By rounding these timers to whole seconds, all such timers will fire
+ * at the same time, rather than at various times spread out. The goal
+ * of this is to have the CPU wake up less, which saves power.
+ *
+ * The exact rounding is skewed for each processor to avoid all
+ * processors firing at the exact same time, which could lead
+ * to lock contention or spurious cache line bouncing.
+ *
+ * The return value is the rounded version of the "j" parameter.
+ */
+unsigned long __round_jiffies(unsigned long j, int cpu)
+{
+ int rem;
+ unsigned long original = j;
+
+ /*
+ * We don't want all cpus firing their timers at once hitting the
+ * same lock or cachelines, so we skew each extra cpu with an extra
+ * 3 jiffies. This 3 jiffies came originally from the mm/ code which
+ * already did this.
+ * The skew is done by adding 3*cpunr, then round, then subtract this
+ * extra offset again.
+ */
+ j += cpu * 3;
+
+ rem = j % HZ;
+
+ /*
+ * If the target jiffie is just after a whole second (which can happen
+ * due to delays of the timer irq, long irq off times etc etc) then
+ * we should round down to the whole second, not up. Use 1/4th second
+ * as cutoff for this rounding as an extreme upper bound for this.
+ */
+ if (rem < HZ/4) /* round down */
+ j = j - rem;
+ else /* round up */
+ j = j - rem + HZ;
+
+ /* now that we have rounded, subtract the extra skew again */
+ j -= cpu * 3;
+
+ if (j <= jiffies) /* rounding ate our timeout entirely; */
+ return original;
+ return j;
+}
+EXPORT_SYMBOL_GPL(__round_jiffies);
+
+/**
+ * __round_jiffies_relative - function to round jiffies to a full second
+ * @j: the time in (relative) jiffies that should be rounded
+ * @cpu: the processor number on which the timeout will happen
+ *
+ * __round_jiffies_relative rounds a time delta in the future (in jiffies)
+ * up or down to (approximately) full seconds. This is useful for timers
+ * for which the exact time they fire does not matter too much, as long as
+ * they fire approximately every X seconds.
+ *
+ * By rounding these timers to whole seconds, all such timers will fire
+ * at the same time, rather than at various times spread out. The goal
+ * of this is to have the CPU wake up less, which saves power.
+ *
+ * The exact rounding is skewed for each processor to avoid all
+ * processors firing at the exact same time, which could lead
+ * to lock contention or spurious cache line bouncing.
+ *
+ * The return value is the rounded version of the "j" parameter.
+ */
+unsigned long __round_jiffies_relative(unsigned long j, int cpu)
+{
+ /*
+ * In theory the following code can skip a jiffy in case jiffies
+ * increments right between the addition and the later subtraction.
+ * However since the entire point of this function is to use approximate
+ * timeouts, it's entirely ok to not handle that.
+ */
+ return __round_jiffies(j + jiffies, cpu) - jiffies;
+}
+EXPORT_SYMBOL_GPL(__round_jiffies_relative);
+
+/**
+ * round_jiffies - function to round jiffies to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ *
+ * round_jiffies rounds an absolute time in the future (in jiffies)
+ * up or down to (approximately) full seconds. This is useful for timers
+ * for which the exact time they fire does not matter too much, as long as
+ * they fire approximately every X seconds.
+ *
+ * By rounding these timers to whole seconds, all such timers will fire
+ * at the same time, rather than at various times spread out. The goal
+ * of this is to have the CPU wake up less, which saves power.
+ *
+ * The return value is the rounded version of the "j" parameter.
+ */
+unsigned long round_jiffies(unsigned long j)
+{
+ return __round_jiffies(j, raw_smp_processor_id());
+}
+EXPORT_SYMBOL_GPL(round_jiffies);
+
+/**
+ * round_jiffies_relative - function to round jiffies to a full second
+ * @j: the time in (relative) jiffies that should be rounded
+ *
+ * round_jiffies_relative rounds a time delta in the future (in jiffies)
+ * up or down to (approximately) full seconds. This is useful for timers
+ * for which the exact time they fire does not matter too much, as long as
+ * they fire approximately every X seconds.
+ *
+ * By rounding these timers to whole seconds, all such timers will fire
+ * at the same time, rather than at various times spread out. The goal
+ * of this is to have the CPU wake up less, which saves power.
+ *
+ * The return value is the rounded version of the "j" parameter.
+ */
+unsigned long round_jiffies_relative(unsigned long j)
+{
+ return __round_jiffies_relative(j, raw_smp_processor_id());
+}
+EXPORT_SYMBOL_GPL(round_jiffies_relative);
+
+
static inline void set_running_timer(tvec_base_t *base,
struct timer_list *timer)
{
@@ -714,7 +846,7 @@ static int change_clocksource(void)
clock = new;
clock->cycle_last = now;
printk(KERN_INFO "Time: %s clocksource has been installed.\n",
- clock->name);
+ clock->name);
return 1;
} else if (clock->update_callback) {
return clock->update_callback();
@@ -722,7 +854,10 @@ static int change_clocksource(void)
return 0;
}
#else
-#define change_clocksource() (0)
+static inline int change_clocksource(void)
+{
+ return 0;
+}
#endif
/**
@@ -820,7 +955,8 @@ device_initcall(timekeeping_init_device);
* If the error is already larger, we look ahead even further
* to compensate for late or lost adjustments.
*/
-static __always_inline int clocksource_bigadjust(s64 error, s64 *interval, s64 *offset)
+static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
+ s64 *offset)
{
s64 tick_error, i;
u32 look_ahead, adj;
@@ -844,7 +980,8 @@ static __always_inline int clocksource_bigadjust(s64 error, s64 *interval, s64 *
* Now calculate the error in (1 << look_ahead) ticks, but first
* remove the single look ahead already included in the error.
*/
- tick_error = current_tick_length() >> (TICK_LENGTH_SHIFT - clock->shift + 1);
+ tick_error = current_tick_length() >>
+ (TICK_LENGTH_SHIFT - clock->shift + 1);
tick_error -= clock->xtime_interval >> 1;
error = ((error - tick_error) >> look_ahead) + tick_error;
@@ -896,7 +1033,8 @@ static void clocksource_adjust(struct clocksource *clock, s64 offset)
clock->mult += adj;
clock->xtime_interval += interval;
clock->xtime_nsec -= offset;
- clock->error -= (interval - offset) << (TICK_LENGTH_SHIFT - clock->shift);
+ clock->error -= (interval - offset) <<
+ (TICK_LENGTH_SHIFT - clock->shift);
}
/**
@@ -1008,11 +1146,15 @@ static inline void calc_load(unsigned long ticks)
unsigned long active_tasks; /* fixed-point */
static int count = LOAD_FREQ;
- 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);
+ count -= ticks;
+ if (unlikely(count < 0)) {
+ active_tasks = count_active_tasks();
+ do {
+ CALC_LOAD(avenrun[0], EXP_1, active_tasks);
+ CALC_LOAD(avenrun[1], EXP_5, active_tasks);
+ CALC_LOAD(avenrun[2], EXP_15, active_tasks);
+ count += LOAD_FREQ;
+ } while (count < 0);
}
}
@@ -1202,11 +1344,10 @@ fastcall signed long __sched schedule_timeout(signed long timeout)
* should never happens anyway). You just have the printk()
* that will tell you if something is gone wrong and where.
*/
- if (timeout < 0)
- {
+ if (timeout < 0) {
printk(KERN_ERR "schedule_timeout: wrong timeout "
- "value %lx from %p\n", timeout,
- __builtin_return_address(0));
+ "value %lx\n", timeout);
+ dump_stack();
current->state = TASK_RUNNING;
goto out;
}
diff --git a/kernel/tsacct.c b/kernel/tsacct.c
index 96f77013d3f..baacc369141 100644
--- a/kernel/tsacct.c
+++ b/kernel/tsacct.c
@@ -96,6 +96,15 @@ void xacct_add_tsk(struct taskstats *stats, struct task_struct *p)
stats->write_char = p->wchar;
stats->read_syscalls = p->syscr;
stats->write_syscalls = p->syscw;
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+ stats->read_bytes = p->ioac.read_bytes;
+ stats->write_bytes = p->ioac.write_bytes;
+ stats->cancelled_write_bytes = p->ioac.cancelled_write_bytes;
+#else
+ stats->read_bytes = 0;
+ stats->write_bytes = 0;
+ stats->cancelled_write_bytes = 0;
+#endif
}
#undef KB
#undef MB
diff --git a/kernel/unwind.c b/kernel/unwind.c
deleted file mode 100644
index 09c26132924..00000000000
--- a/kernel/unwind.c
+++ /dev/null
@@ -1,1305 +0,0 @@
-/*
- * Copyright (C) 2002-2006 Novell, Inc.
- * Jan Beulich <jbeulich@novell.com>
- * This code is released under version 2 of the GNU GPL.
- *
- * A simple API for unwinding kernel stacks. This is used for
- * debugging and error reporting purposes. The kernel doesn't need
- * full-blown stack unwinding with all the bells and whistles, so there
- * is not much point in implementing the full Dwarf2 unwind API.
- */
-
-#include <linux/unwind.h>
-#include <linux/module.h>
-#include <linux/bootmem.h>
-#include <linux/sort.h>
-#include <linux/stop_machine.h>
-#include <linux/uaccess.h>
-#include <asm/sections.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
-
-extern const char __start_unwind[], __end_unwind[];
-extern const u8 __start_unwind_hdr[], __end_unwind_hdr[];
-
-#define MAX_STACK_DEPTH 8
-
-#define EXTRA_INFO(f) { \
- BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \
- % FIELD_SIZEOF(struct unwind_frame_info, f)) \
- + offsetof(struct unwind_frame_info, f) \
- / FIELD_SIZEOF(struct unwind_frame_info, f), \
- FIELD_SIZEOF(struct unwind_frame_info, f) \
- }
-#define PTREGS_INFO(f) EXTRA_INFO(regs.f)
-
-static const struct {
- unsigned offs:BITS_PER_LONG / 2;
- unsigned width:BITS_PER_LONG / 2;
-} reg_info[] = {
- UNW_REGISTER_INFO
-};
-
-#undef PTREGS_INFO
-#undef EXTRA_INFO
-
-#ifndef REG_INVALID
-#define REG_INVALID(r) (reg_info[r].width == 0)
-#endif
-
-#define DW_CFA_nop 0x00
-#define DW_CFA_set_loc 0x01
-#define DW_CFA_advance_loc1 0x02
-#define DW_CFA_advance_loc2 0x03
-#define DW_CFA_advance_loc4 0x04
-#define DW_CFA_offset_extended 0x05
-#define DW_CFA_restore_extended 0x06
-#define DW_CFA_undefined 0x07
-#define DW_CFA_same_value 0x08
-#define DW_CFA_register 0x09
-#define DW_CFA_remember_state 0x0a
-#define DW_CFA_restore_state 0x0b
-#define DW_CFA_def_cfa 0x0c
-#define DW_CFA_def_cfa_register 0x0d
-#define DW_CFA_def_cfa_offset 0x0e
-#define DW_CFA_def_cfa_expression 0x0f
-#define DW_CFA_expression 0x10
-#define DW_CFA_offset_extended_sf 0x11
-#define DW_CFA_def_cfa_sf 0x12
-#define DW_CFA_def_cfa_offset_sf 0x13
-#define DW_CFA_val_offset 0x14
-#define DW_CFA_val_offset_sf 0x15
-#define DW_CFA_val_expression 0x16
-#define DW_CFA_lo_user 0x1c
-#define DW_CFA_GNU_window_save 0x2d
-#define DW_CFA_GNU_args_size 0x2e
-#define DW_CFA_GNU_negative_offset_extended 0x2f
-#define DW_CFA_hi_user 0x3f
-
-#define DW_EH_PE_FORM 0x07
-#define DW_EH_PE_native 0x00
-#define DW_EH_PE_leb128 0x01
-#define DW_EH_PE_data2 0x02
-#define DW_EH_PE_data4 0x03
-#define DW_EH_PE_data8 0x04
-#define DW_EH_PE_signed 0x08
-#define DW_EH_PE_ADJUST 0x70
-#define DW_EH_PE_abs 0x00
-#define DW_EH_PE_pcrel 0x10
-#define DW_EH_PE_textrel 0x20
-#define DW_EH_PE_datarel 0x30
-#define DW_EH_PE_funcrel 0x40
-#define DW_EH_PE_aligned 0x50
-#define DW_EH_PE_indirect 0x80
-#define DW_EH_PE_omit 0xff
-
-typedef unsigned long uleb128_t;
-typedef signed long sleb128_t;
-#define sleb128abs __builtin_labs
-
-static struct unwind_table {
- struct {
- unsigned long pc;
- unsigned long range;
- } core, init;
- const void *address;
- unsigned long size;
- const unsigned char *header;
- unsigned long hdrsz;
- struct unwind_table *link;
- const char *name;
-} root_table;
-
-struct unwind_item {
- enum item_location {
- Nowhere,
- Memory,
- Register,
- Value
- } where;
- uleb128_t value;
-};
-
-struct unwind_state {
- uleb128_t loc, org;
- const u8 *cieStart, *cieEnd;
- uleb128_t codeAlign;
- sleb128_t dataAlign;
- struct cfa {
- uleb128_t reg, offs;
- } cfa;
- struct unwind_item regs[ARRAY_SIZE(reg_info)];
- unsigned stackDepth:8;
- unsigned version:8;
- const u8 *label;
- const u8 *stack[MAX_STACK_DEPTH];
-};
-
-static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
-
-static unsigned unwind_debug;
-static int __init unwind_debug_setup(char *s)
-{
- unwind_debug = simple_strtoul(s, NULL, 0);
- return 1;
-}
-__setup("unwind_debug=", unwind_debug_setup);
-#define dprintk(lvl, fmt, args...) \
- ((void)(lvl > unwind_debug \
- || printk(KERN_DEBUG "unwind: " fmt "\n", ##args)))
-
-static struct unwind_table *find_table(unsigned long pc)
-{
- struct unwind_table *table;
-
- for (table = &root_table; table; table = table->link)
- if ((pc >= table->core.pc
- && pc < table->core.pc + table->core.range)
- || (pc >= table->init.pc
- && pc < table->init.pc + table->init.range))
- break;
-
- return table;
-}
-
-static unsigned long read_pointer(const u8 **pLoc,
- const void *end,
- signed ptrType,
- unsigned long text_base,
- unsigned long data_base);
-
-static void init_unwind_table(struct unwind_table *table,
- const char *name,
- const void *core_start,
- unsigned long core_size,
- const void *init_start,
- unsigned long init_size,
- const void *table_start,
- 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], 0, 0)
- != table_start
- || !read_pointer(&ptr, end, header_start[2], 0, 0)
- || !read_pointer(&ptr, end, header_start[3], 0,
- (unsigned long)header_start)
- || !read_pointer(&ptr, end, header_start[3], 0,
- (unsigned long)header_start))
- header_start = NULL;
- table->hdrsz = header_size;
- smp_wmb();
- table->header = header_start;
- table->link = NULL;
- table->name = name;
-}
-
-void __init unwind_init(void)
-{
- init_unwind_table(&root_table, "kernel",
- _text, _end - _text,
- NULL, 0,
- __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, 0, 0))
- return;
- ++n;
- }
-
- if (tableSize || !n)
- return;
-
- hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
- + 2 * n * sizeof(unsigned long);
- dprintk(2, "Binary lookup table size for %s: %lu bytes", table->name, hdrSize);
- 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), 0, 0);
- 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,
- unsigned long table_size)
-{
- struct unwind_table *table;
-
- if (table_size <= 0)
- return NULL;
-
- table = kmalloc(sizeof(*table), GFP_KERNEL);
- if (!table)
- return NULL;
-
- init_unwind_table(table, module->name,
- module->module_core, module->core_size,
- module->module_init, module->init_size,
- table_start, table_size,
- NULL, 0);
-
- if (last_table)
- last_table->link = table;
- else
- root_table.link = table;
- last_table = table;
-
- return table;
-}
-
-struct unlink_table_info
-{
- struct unwind_table *table;
- int init_only;
-};
-
-static int unlink_table(void *arg)
-{
- struct unlink_table_info *info = arg;
- struct unwind_table *table = info->table, *prev;
-
- for (prev = &root_table; prev->link && prev->link != table; prev = prev->link)
- ;
-
- if (prev->link) {
- if (info->init_only) {
- table->init.pc = 0;
- table->init.range = 0;
- info->table = NULL;
- } else {
- prev->link = table->link;
- if (!prev->link)
- last_table = prev;
- }
- } else
- info->table = NULL;
-
- return 0;
-}
-
-/* Must be called with module_mutex held. */
-void unwind_remove_table(void *handle, int init_only)
-{
- struct unwind_table *table = handle;
- struct unlink_table_info info;
-
- if (!table || table == &root_table)
- return;
-
- if (init_only && table == last_table) {
- table->init.pc = 0;
- table->init.range = 0;
- return;
- }
-
- info.table = table;
- info.init_only = init_only;
- stop_machine_run(unlink_table, &info, NR_CPUS);
-
- if (info.table)
- kfree(table);
-}
-
-#endif /* CONFIG_MODULES */
-
-static uleb128_t get_uleb128(const u8 **pcur, const u8 *end)
-{
- const u8 *cur = *pcur;
- uleb128_t value;
- unsigned shift;
-
- for (shift = 0, value = 0; cur < end; shift += 7) {
- if (shift + 7 > 8 * sizeof(value)
- && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
- cur = end + 1;
- break;
- }
- value |= (uleb128_t)(*cur & 0x7f) << shift;
- if (!(*cur++ & 0x80))
- break;
- }
- *pcur = cur;
-
- return value;
-}
-
-static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
-{
- const u8 *cur = *pcur;
- sleb128_t value;
- unsigned shift;
-
- for (shift = 0, value = 0; cur < end; shift += 7) {
- if (shift + 7 > 8 * sizeof(value)
- && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
- cur = end + 1;
- break;
- }
- value |= (sleb128_t)(*cur & 0x7f) << shift;
- if (!(*cur & 0x80)) {
- value |= -(*cur++ & 0x40) << shift;
- break;
- }
- }
- *pcur = cur;
-
- 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,
- unsigned long text_base,
- unsigned long data_base)
-{
- unsigned long value = 0;
- union {
- const u8 *p8;
- const u16 *p16u;
- const s16 *p16s;
- const u32 *p32u;
- const s32 *p32s;
- const unsigned long *pul;
- } ptr;
-
- if (ptrType < 0 || ptrType == DW_EH_PE_omit) {
- dprintk(1, "Invalid pointer encoding %02X (%p,%p).", ptrType, *pLoc, end);
- return 0;
- }
- ptr.p8 = *pLoc;
- switch(ptrType & DW_EH_PE_FORM) {
- case DW_EH_PE_data2:
- if (end < (const void *)(ptr.p16u + 1)) {
- dprintk(1, "Data16 overrun (%p,%p).", ptr.p8, end);
- return 0;
- }
- if(ptrType & DW_EH_PE_signed)
- value = get_unaligned(ptr.p16s++);
- else
- value = get_unaligned(ptr.p16u++);
- break;
- case DW_EH_PE_data4:
-#ifdef CONFIG_64BIT
- if (end < (const void *)(ptr.p32u + 1)) {
- dprintk(1, "Data32 overrun (%p,%p).", ptr.p8, end);
- return 0;
- }
- if(ptrType & DW_EH_PE_signed)
- value = get_unaligned(ptr.p32s++);
- else
- value = get_unaligned(ptr.p32u++);
- break;
- case DW_EH_PE_data8:
- BUILD_BUG_ON(sizeof(u64) != sizeof(value));
-#else
- BUILD_BUG_ON(sizeof(u32) != sizeof(value));
-#endif
- case DW_EH_PE_native:
- if (end < (const void *)(ptr.pul + 1)) {
- dprintk(1, "DataUL overrun (%p,%p).", ptr.p8, end);
- return 0;
- }
- value = get_unaligned(ptr.pul++);
- break;
- case DW_EH_PE_leb128:
- BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value));
- value = ptrType & DW_EH_PE_signed
- ? get_sleb128(&ptr.p8, end)
- : get_uleb128(&ptr.p8, end);
- if ((const void *)ptr.p8 > end) {
- dprintk(1, "DataLEB overrun (%p,%p).", ptr.p8, end);
- return 0;
- }
- break;
- default:
- dprintk(2, "Cannot decode pointer type %02X (%p,%p).",
- ptrType, ptr.p8, end);
- return 0;
- }
- switch(ptrType & DW_EH_PE_ADJUST) {
- case DW_EH_PE_abs:
- break;
- case DW_EH_PE_pcrel:
- value += (unsigned long)*pLoc;
- break;
- case DW_EH_PE_textrel:
- if (likely(text_base)) {
- value += text_base;
- break;
- }
- dprintk(2, "Text-relative encoding %02X (%p,%p), but zero text base.",
- ptrType, *pLoc, end);
- return 0;
- case DW_EH_PE_datarel:
- if (likely(data_base)) {
- value += data_base;
- break;
- }
- dprintk(2, "Data-relative encoding %02X (%p,%p), but zero data base.",
- ptrType, *pLoc, end);
- return 0;
- default:
- dprintk(2, "Cannot adjust pointer type %02X (%p,%p).",
- ptrType, *pLoc, end);
- return 0;
- }
- if ((ptrType & DW_EH_PE_indirect)
- && probe_kernel_address((unsigned long *)value, value)) {
- dprintk(1, "Cannot read indirect value %lx (%p,%p).",
- value, *pLoc, end);
- return 0;
- }
- *pLoc = ptr.p8;
-
- return value;
-}
-
-static signed fde_pointer_type(const u32 *cie)
-{
- const u8 *ptr = (const u8 *)(cie + 2);
- unsigned version = *ptr;
-
- if (version != 1)
- return -1; /* unsupported */
- if (*++ptr) {
- const char *aug;
- const u8 *end = (const u8 *)(cie + 1) + *cie;
- uleb128_t len;
-
- /* check if augmentation size is first (and thus present) */
- if (*ptr != 'z')
- return -1;
- /* check if augmentation string is nul-terminated */
- if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL)
- return -1;
- ++ptr; /* skip terminator */
- get_uleb128(&ptr, end); /* skip code alignment */
- get_sleb128(&ptr, end); /* skip data alignment */
- /* skip return address column */
- version <= 1 ? (void)++ptr : (void)get_uleb128(&ptr, end);
- len = get_uleb128(&ptr, end); /* augmentation length */
- if (ptr + len < ptr || ptr + len > end)
- return -1;
- end = ptr + len;
- while (*++aug) {
- if (ptr >= end)
- return -1;
- switch(*aug) {
- case 'L':
- ++ptr;
- break;
- case 'P': {
- signed ptrType = *ptr++;
-
- if (!read_pointer(&ptr, end, ptrType, 0, 0)
- || ptr > end)
- return -1;
- }
- break;
- case 'R':
- return *ptr;
- default:
- return -1;
- }
- }
- }
- return DW_EH_PE_native|DW_EH_PE_abs;
-}
-
-static int advance_loc(unsigned long delta, struct unwind_state *state)
-{
- state->loc += delta * state->codeAlign;
-
- return delta > 0;
-}
-
-static void set_rule(uleb128_t reg,
- enum item_location where,
- uleb128_t value,
- struct unwind_state *state)
-{
- if (reg < ARRAY_SIZE(state->regs)) {
- state->regs[reg].where = where;
- state->regs[reg].value = value;
- }
-}
-
-static int processCFI(const u8 *start,
- const u8 *end,
- unsigned long targetLoc,
- signed ptrType,
- struct unwind_state *state)
-{
- union {
- const u8 *p8;
- const u16 *p16;
- const u32 *p32;
- } ptr;
- int result = 1;
-
- if (start != state->cieStart) {
- state->loc = state->org;
- result = processCFI(state->cieStart, state->cieEnd, 0, ptrType, state);
- if (targetLoc == 0 && state->label == NULL)
- return result;
- }
- for (ptr.p8 = start; result && ptr.p8 < end; ) {
- switch(*ptr.p8 >> 6) {
- uleb128_t value;
-
- case 0:
- switch(*ptr.p8++) {
- case DW_CFA_nop:
- break;
- case DW_CFA_set_loc:
- state->loc = read_pointer(&ptr.p8, end, ptrType, 0, 0);
- if (state->loc == 0)
- result = 0;
- break;
- case DW_CFA_advance_loc1:
- result = ptr.p8 < end && advance_loc(*ptr.p8++, state);
- break;
- case DW_CFA_advance_loc2:
- result = ptr.p8 <= end + 2
- && advance_loc(*ptr.p16++, state);
- break;
- case DW_CFA_advance_loc4:
- result = ptr.p8 <= end + 4
- && advance_loc(*ptr.p32++, state);
- break;
- case DW_CFA_offset_extended:
- value = get_uleb128(&ptr.p8, end);
- set_rule(value, Memory, get_uleb128(&ptr.p8, end), state);
- break;
- case DW_CFA_val_offset:
- value = get_uleb128(&ptr.p8, end);
- set_rule(value, Value, get_uleb128(&ptr.p8, end), state);
- break;
- case DW_CFA_offset_extended_sf:
- value = get_uleb128(&ptr.p8, end);
- set_rule(value, Memory, get_sleb128(&ptr.p8, end), state);
- break;
- case DW_CFA_val_offset_sf:
- value = get_uleb128(&ptr.p8, end);
- set_rule(value, Value, get_sleb128(&ptr.p8, end), state);
- break;
- case DW_CFA_restore_extended:
- case DW_CFA_undefined:
- case DW_CFA_same_value:
- set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0, state);
- break;
- case DW_CFA_register:
- value = get_uleb128(&ptr.p8, end);
- set_rule(value,
- Register,
- get_uleb128(&ptr.p8, end), state);
- break;
- case DW_CFA_remember_state:
- if (ptr.p8 == state->label) {
- state->label = NULL;
- return 1;
- }
- if (state->stackDepth >= MAX_STACK_DEPTH) {
- dprintk(1, "State stack overflow (%p,%p).", ptr.p8, end);
- return 0;
- }
- state->stack[state->stackDepth++] = ptr.p8;
- break;
- case DW_CFA_restore_state:
- if (state->stackDepth) {
- const uleb128_t loc = state->loc;
- const u8 *label = state->label;
-
- state->label = state->stack[state->stackDepth - 1];
- memcpy(&state->cfa, &badCFA, sizeof(state->cfa));
- memset(state->regs, 0, sizeof(state->regs));
- state->stackDepth = 0;
- result = processCFI(start, end, 0, ptrType, state);
- state->loc = loc;
- state->label = label;
- } else {
- dprintk(1, "State stack underflow (%p,%p).", ptr.p8, end);
- return 0;
- }
- break;
- case DW_CFA_def_cfa:
- state->cfa.reg = get_uleb128(&ptr.p8, end);
- /*nobreak*/
- case DW_CFA_def_cfa_offset:
- state->cfa.offs = get_uleb128(&ptr.p8, end);
- break;
- case DW_CFA_def_cfa_sf:
- state->cfa.reg = get_uleb128(&ptr.p8, end);
- /*nobreak*/
- case DW_CFA_def_cfa_offset_sf:
- state->cfa.offs = get_sleb128(&ptr.p8, end)
- * state->dataAlign;
- break;
- case DW_CFA_def_cfa_register:
- state->cfa.reg = get_uleb128(&ptr.p8, end);
- break;
- /*todo case DW_CFA_def_cfa_expression: */
- /*todo case DW_CFA_expression: */
- /*todo case DW_CFA_val_expression: */
- case DW_CFA_GNU_args_size:
- get_uleb128(&ptr.p8, end);
- break;
- case DW_CFA_GNU_negative_offset_extended:
- value = get_uleb128(&ptr.p8, end);
- set_rule(value,
- Memory,
- (uleb128_t)0 - get_uleb128(&ptr.p8, end), state);
- break;
- case DW_CFA_GNU_window_save:
- default:
- dprintk(1, "Unrecognized CFI op %02X (%p,%p).", ptr.p8[-1], ptr.p8 - 1, end);
- result = 0;
- break;
- }
- break;
- case 1:
- result = advance_loc(*ptr.p8++ & 0x3f, state);
- break;
- case 2:
- value = *ptr.p8++ & 0x3f;
- set_rule(value, Memory, get_uleb128(&ptr.p8, end), state);
- break;
- case 3:
- set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
- break;
- }
- if (ptr.p8 > end) {
- dprintk(1, "Data overrun (%p,%p).", ptr.p8, end);
- result = 0;
- }
- if (result && targetLoc != 0 && targetLoc < state->loc)
- return 1;
- }
-
- if (result && ptr.p8 < end)
- dprintk(1, "Data underrun (%p,%p).", ptr.p8, end);
-
- return result
- && ptr.p8 == end
- && (targetLoc == 0
- || (/*todo While in theory this should apply, gcc in practice omits
- everything past the function prolog, and hence the location
- never reaches the end of the function.
- targetLoc < state->loc &&*/ state->label == NULL));
-}
-
-/* Unwind to previous to frame. Returns 0 if successful, negative
- * number in case of an error. */
-int unwind(struct unwind_frame_info *frame)
-{
-#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
- const u32 *fde = NULL, *cie = NULL;
- const u8 *ptr = NULL, *end = NULL;
- unsigned long pc = UNW_PC(frame) - frame->call_frame, sp;
- unsigned long startLoc = 0, endLoc = 0, cfa;
- unsigned i;
- signed ptrType = -1;
- uleb128_t retAddrReg = 0;
- 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))) {
- 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], 0, 0)
- == (unsigned long)table->address
- && (i = read_pointer(&ptr, end, hdr[2], 0, 0)) > 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], 0,
- (unsigned long)hdr);
- 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,
- (unsigned long)hdr)) != 0
- && pc >= startLoc)
- fde = (void *)read_pointer(&ptr,
- ptr + tableSize,
- hdr[3], 0,
- (unsigned long)hdr);
- }
- }
- if(hdr && !fde)
- dprintk(3, "Binary lookup for %lx failed.", pc);
-
- if (fde != NULL) {
- cie = cie_for_fde(fde, table);
- ptr = (const u8 *)(fde + 2);
- if(cie != NULL
- && cie != &bad_cie
- && cie != &not_fde
- && (ptrType = fde_pointer_type(cie)) >= 0
- && read_pointer(&ptr,
- (const u8 *)(fde + 1) + *fde,
- ptrType, 0, 0) == 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, 0, 0);
- if(pc >= endLoc)
- fde = NULL;
- } else
- fde = NULL;
- if(!fde)
- dprintk(1, "Binary lookup result for %lx discarded.", pc);
- }
- 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, 0, 0);
- 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, 0, 0);
- if (pc >= startLoc && pc < endLoc)
- break;
- }
- if(!fde)
- dprintk(3, "Linear lookup for %lx failed.", pc);
- }
- }
- if (cie != NULL) {
- memset(&state, 0, sizeof(state));
- state.cieEnd = ptr; /* keep here temporarily */
- ptr = (const u8 *)(cie + 2);
- end = (const u8 *)(cie + 1) + *cie;
- frame->call_frame = 1;
- if ((state.version = *ptr) != 1)
- cie = NULL; /* unsupported version */
- else if (*++ptr) {
- /* check if augmentation size is first (and thus present) */
- if (*ptr == 'z') {
- while (++ptr < end && *ptr) {
- switch(*ptr) {
- /* check for ignorable (or already handled)
- * nul-terminated augmentation string */
- case 'L':
- case 'P':
- case 'R':
- continue;
- case 'S':
- frame->call_frame = 0;
- continue;
- default:
- break;
- }
- break;
- }
- }
- if (ptr >= end || *ptr)
- cie = NULL;
- }
- if(!cie)
- dprintk(1, "CIE unusable (%p,%p).", ptr, end);
- ++ptr;
- }
- if (cie != NULL) {
- /* get code aligment factor */
- state.codeAlign = get_uleb128(&ptr, end);
- /* get data aligment factor */
- state.dataAlign = get_sleb128(&ptr, end);
- if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
- cie = NULL;
- else if (UNW_PC(frame) % state.codeAlign
- || UNW_SP(frame) % sleb128abs(state.dataAlign)) {
- dprintk(1, "Input pointer(s) misaligned (%lx,%lx).",
- UNW_PC(frame), UNW_SP(frame));
- return -EPERM;
- } else {
- retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end);
- /* skip augmentation */
- if (((const char *)(cie + 2))[1] == 'z') {
- uleb128_t augSize = get_uleb128(&ptr, end);
-
- ptr += augSize;
- }
- if (ptr > end
- || retAddrReg >= ARRAY_SIZE(reg_info)
- || REG_INVALID(retAddrReg)
- || reg_info[retAddrReg].width != sizeof(unsigned long))
- cie = NULL;
- }
- if(!cie)
- dprintk(1, "CIE validation failed (%p,%p).", ptr, end);
- }
- if (cie != NULL) {
- state.cieStart = ptr;
- ptr = state.cieEnd;
- state.cieEnd = end;
- end = (const u8 *)(fde + 1) + *fde;
- /* skip augmentation */
- if (((const char *)(cie + 2))[1] == 'z') {
- uleb128_t augSize = get_uleb128(&ptr, end);
-
- if ((ptr += augSize) > end)
- fde = NULL;
- }
- if(!fde)
- dprintk(1, "FDE validation failed (%p,%p).", ptr, end);
- }
- if (cie == NULL || fde == NULL) {
-#ifdef CONFIG_FRAME_POINTER
- unsigned long top, bottom;
-
- if ((UNW_SP(frame) | UNW_FP(frame)) % sizeof(unsigned long))
- return -EPERM;
- top = STACK_TOP(frame->task);
- bottom = STACK_BOTTOM(frame->task);
-# if FRAME_RETADDR_OFFSET < 0
- if (UNW_SP(frame) < top
- && UNW_FP(frame) <= UNW_SP(frame)
- && bottom < UNW_FP(frame)
-# else
- if (UNW_SP(frame) > top
- && UNW_FP(frame) >= UNW_SP(frame)
- && bottom > UNW_FP(frame)
-# endif
- && !((UNW_SP(frame) | UNW_FP(frame))
- & (sizeof(unsigned long) - 1))) {
- unsigned long link;
-
- if (!probe_kernel_address(
- (unsigned long *)(UNW_FP(frame)
- + FRAME_LINK_OFFSET),
- link)
-# if FRAME_RETADDR_OFFSET < 0
- && link > bottom && link < UNW_FP(frame)
-# else
- && link > UNW_FP(frame) && link < bottom
-# endif
- && !(link & (sizeof(link) - 1))
- && !probe_kernel_address(
- (unsigned long *)(UNW_FP(frame)
- + FRAME_RETADDR_OFFSET), UNW_PC(frame))) {
- UNW_SP(frame) = UNW_FP(frame) + FRAME_RETADDR_OFFSET
-# if FRAME_RETADDR_OFFSET < 0
- -
-# else
- +
-# endif
- sizeof(UNW_PC(frame));
- UNW_FP(frame) = link;
- return 0;
- }
- }
-#endif
- return -ENXIO;
- }
- state.org = startLoc;
- memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
- /* process instructions */
- if (!processCFI(ptr, end, pc, ptrType, &state)
- || state.loc > endLoc
- || state.regs[retAddrReg].where == Nowhere
- || state.cfa.reg >= ARRAY_SIZE(reg_info)
- || reg_info[state.cfa.reg].width != sizeof(unsigned long)
- || FRAME_REG(state.cfa.reg, unsigned long) % sizeof(unsigned long)
- || state.cfa.offs % sizeof(unsigned long)) {
- dprintk(1, "Unusable unwind info (%p,%p).", ptr, end);
- return -EIO;
- }
- /* update frame */
-#ifndef CONFIG_AS_CFI_SIGNAL_FRAME
- if(frame->call_frame
- && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
- frame->call_frame = 0;
-#endif
- cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
- startLoc = min((unsigned long)UNW_SP(frame), cfa);
- endLoc = max((unsigned long)UNW_SP(frame), cfa);
- if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
- startLoc = min(STACK_LIMIT(cfa), cfa);
- endLoc = max(STACK_LIMIT(cfa), cfa);
- }
-#ifndef CONFIG_64BIT
-# define CASES CASE(8); CASE(16); CASE(32)
-#else
-# define CASES CASE(8); CASE(16); CASE(32); CASE(64)
-#endif
- pc = UNW_PC(frame);
- sp = UNW_SP(frame);
- for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
- if (REG_INVALID(i)) {
- if (state.regs[i].where == Nowhere)
- continue;
- dprintk(1, "Cannot restore register %u (%d).",
- i, state.regs[i].where);
- return -EIO;
- }
- switch(state.regs[i].where) {
- default:
- break;
- case Register:
- if (state.regs[i].value >= ARRAY_SIZE(reg_info)
- || REG_INVALID(state.regs[i].value)
- || reg_info[i].width > reg_info[state.regs[i].value].width) {
- dprintk(1, "Cannot restore register %u from register %lu.",
- i, state.regs[i].value);
- return -EIO;
- }
- switch(reg_info[state.regs[i].value].width) {
-#define CASE(n) \
- case sizeof(u##n): \
- state.regs[i].value = FRAME_REG(state.regs[i].value, \
- const u##n); \
- break
- CASES;
-#undef CASE
- default:
- dprintk(1, "Unsupported register size %u (%lu).",
- reg_info[state.regs[i].value].width,
- state.regs[i].value);
- return -EIO;
- }
- break;
- }
- }
- for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
- if (REG_INVALID(i))
- continue;
- switch(state.regs[i].where) {
- case Nowhere:
- if (reg_info[i].width != sizeof(UNW_SP(frame))
- || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
- != &UNW_SP(frame))
- continue;
- UNW_SP(frame) = cfa;
- break;
- case Register:
- switch(reg_info[i].width) {
-#define CASE(n) case sizeof(u##n): \
- FRAME_REG(i, u##n) = state.regs[i].value; \
- break
- CASES;
-#undef CASE
- default:
- dprintk(1, "Unsupported register size %u (%u).",
- reg_info[i].width, i);
- return -EIO;
- }
- break;
- case Value:
- if (reg_info[i].width != sizeof(unsigned long)) {
- dprintk(1, "Unsupported value size %u (%u).",
- reg_info[i].width, i);
- return -EIO;
- }
- FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
- * state.dataAlign;
- break;
- case Memory: {
- unsigned long addr = cfa + state.regs[i].value
- * state.dataAlign;
-
- if ((state.regs[i].value * state.dataAlign)
- % sizeof(unsigned long)
- || addr < startLoc
- || addr + sizeof(unsigned long) < addr
- || addr + sizeof(unsigned long) > endLoc) {
- dprintk(1, "Bad memory location %lx (%lx).",
- addr, state.regs[i].value);
- return -EIO;
- }
- switch(reg_info[i].width) {
-#define CASE(n) case sizeof(u##n): \
- probe_kernel_address((u##n *)addr, FRAME_REG(i, u##n)); \
- break
- CASES;
-#undef CASE
- default:
- dprintk(1, "Unsupported memory size %u (%u).",
- reg_info[i].width, i);
- return -EIO;
- }
- }
- break;
- }
- }
-
- if (UNW_PC(frame) % state.codeAlign
- || UNW_SP(frame) % sleb128abs(state.dataAlign)) {
- dprintk(1, "Output pointer(s) misaligned (%lx,%lx).",
- UNW_PC(frame), UNW_SP(frame));
- return -EIO;
- }
- if (pc == UNW_PC(frame) && sp == UNW_SP(frame)) {
- dprintk(1, "No progress (%lx,%lx).", pc, sp);
- return -EIO;
- }
-
- return 0;
-#undef CASES
-#undef FRAME_REG
-}
-EXPORT_SYMBOL(unwind);
-
-int unwind_init_frame_info(struct unwind_frame_info *info,
- struct task_struct *tsk,
- /*const*/ struct pt_regs *regs)
-{
- info->task = tsk;
- info->call_frame = 0;
- arch_unw_init_frame_info(info, regs);
-
- return 0;
-}
-EXPORT_SYMBOL(unwind_init_frame_info);
-
-/*
- * Prepare to unwind a blocked task.
- */
-int unwind_init_blocked(struct unwind_frame_info *info,
- struct task_struct *tsk)
-{
- info->task = tsk;
- info->call_frame = 0;
- arch_unw_init_blocked(info);
-
- return 0;
-}
-EXPORT_SYMBOL(unwind_init_blocked);
-
-/*
- * Prepare to unwind the currently running thread.
- */
-int unwind_init_running(struct unwind_frame_info *info,
- asmlinkage int (*callback)(struct unwind_frame_info *,
- void *arg),
- void *arg)
-{
- info->task = current;
- info->call_frame = 0;
-
- return arch_unwind_init_running(info, callback, arg);
-}
-EXPORT_SYMBOL(unwind_init_running);
-
-/*
- * Unwind until the return pointer is in user-land (or until an error
- * occurs). Returns 0 if successful, negative number in case of
- * error.
- */
-int unwind_to_user(struct unwind_frame_info *info)
-{
- while (!arch_unw_user_mode(info)) {
- int err = unwind(info);
-
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(unwind_to_user);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 6b186750e9b..a3da07c5af2 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -85,27 +85,24 @@ static inline int is_single_threaded(struct workqueue_struct *wq)
return list_empty(&wq->list);
}
+/*
+ * Set the workqueue on which a work item is to be run
+ * - Must *only* be called if the pending flag is set
+ */
static inline void set_wq_data(struct work_struct *work, void *wq)
{
- unsigned long new, old, res;
+ unsigned long new;
+
+ BUG_ON(!work_pending(work));
- /* assume the pending flag is already set and that the task has already
- * been queued on this workqueue */
new = (unsigned long) wq | (1UL << WORK_STRUCT_PENDING);
- res = work->management;
- if (res != new) {
- do {
- old = res;
- new = (unsigned long) wq;
- new |= (old & WORK_STRUCT_FLAG_MASK);
- res = cmpxchg(&work->management, old, new);
- } while (res != old);
- }
+ new |= WORK_STRUCT_FLAG_MASK & *work_data_bits(work);
+ atomic_long_set(&work->data, new);
}
static inline void *get_wq_data(struct work_struct *work)
{
- return (void *) (work->management & WORK_STRUCT_WQ_DATA_MASK);
+ return (void *) (atomic_long_read(&work->data) & WORK_STRUCT_WQ_DATA_MASK);
}
static int __run_work(struct cpu_workqueue_struct *cwq, struct work_struct *work)
@@ -136,7 +133,7 @@ static int __run_work(struct cpu_workqueue_struct *cwq, struct work_struct *work
list_del_init(&work->entry);
spin_unlock_irqrestore(&cwq->lock, flags);
- if (!test_bit(WORK_STRUCT_NOAUTOREL, &work->management))
+ if (!test_bit(WORK_STRUCT_NOAUTOREL, work_data_bits(work)))
work_release(work);
f(work);
@@ -209,7 +206,7 @@ int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work)
{
int ret = 0, cpu = get_cpu();
- if (!test_and_set_bit(WORK_STRUCT_PENDING, &work->management)) {
+ if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
if (unlikely(is_single_threaded(wq)))
cpu = singlethread_cpu;
BUG_ON(!list_empty(&work->entry));
@@ -236,7 +233,7 @@ static void delayed_work_timer_fn(unsigned long __data)
/**
* queue_delayed_work - queue work on a workqueue after delay
* @wq: workqueue to use
- * @work: delayable work to queue
+ * @dwork: delayable work to queue
* @delay: number of jiffies to wait before queueing
*
* Returns 0 if @work was already on a queue, non-zero otherwise.
@@ -251,7 +248,7 @@ int fastcall queue_delayed_work(struct workqueue_struct *wq,
if (delay == 0)
return queue_work(wq, work);
- if (!test_and_set_bit(WORK_STRUCT_PENDING, &work->management)) {
+ if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
BUG_ON(timer_pending(timer));
BUG_ON(!list_empty(&work->entry));
@@ -271,7 +268,7 @@ EXPORT_SYMBOL_GPL(queue_delayed_work);
* queue_delayed_work_on - queue work on specific CPU after delay
* @cpu: CPU number to execute work on
* @wq: workqueue to use
- * @work: work to queue
+ * @dwork: work to queue
* @delay: number of jiffies to wait before queueing
*
* Returns 0 if @work was already on a queue, non-zero otherwise.
@@ -283,7 +280,7 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
struct timer_list *timer = &dwork->timer;
struct work_struct *work = &dwork->work;
- if (!test_and_set_bit(WORK_STRUCT_PENDING, &work->management)) {
+ if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
BUG_ON(timer_pending(timer));
BUG_ON(!list_empty(&work->entry));
@@ -324,7 +321,7 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq)
spin_unlock_irqrestore(&cwq->lock, flags);
BUG_ON(get_wq_data(work) != cwq);
- if (!test_bit(WORK_STRUCT_NOAUTOREL, &work->management))
+ if (!test_bit(WORK_STRUCT_NOAUTOREL, work_data_bits(work)))
work_release(work);
f(work);
@@ -640,9 +637,11 @@ int schedule_on_each_cpu(work_func_t func)
mutex_lock(&workqueue_mutex);
for_each_online_cpu(cpu) {
- INIT_WORK(per_cpu_ptr(works, cpu), func);
- __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu),
- per_cpu_ptr(works, cpu));
+ struct work_struct *work = per_cpu_ptr(works, cpu);
+
+ INIT_WORK(work, func);
+ set_bit(WORK_STRUCT_PENDING, work_data_bits(work));
+ __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), work);
}
mutex_unlock(&workqueue_mutex);
flush_workqueue(keventd_wq);
diff --git a/lib/Kconfig b/lib/Kconfig
index 734ce95a93d..9b03581cdec 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -4,6 +4,9 @@
menu "Library routines"
+config BITREVERSE
+ tristate
+
config CRC_CCITT
tristate "CRC-CCITT functions"
help
@@ -23,6 +26,7 @@ config CRC16
config CRC32
tristate "CRC32 functions"
default y
+ select BITREVERSE
help
This option is provided for the case where no in-kernel-tree
modules require CRC32 functions, but a module built outside the
@@ -97,4 +101,9 @@ config TEXTSEARCH_FSM
config PLIST
boolean
+config IOMAP_COPY
+ boolean
+ depends on !UML
+ default y
+
endmenu
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index b75fed737f2..5c2681875b9 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -47,6 +47,30 @@ config UNUSED_SYMBOLS
you really need it, and what the merge plan to the mainline kernel for
your module is.
+config DEBUG_FS
+ bool "Debug Filesystem"
+ depends on SYSFS
+ help
+ debugfs is a virtual file system that kernel developers use to put
+ debugging files into. Enable this option to be able to read and
+ write to these files.
+
+ If unsure, say N.
+
+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 DEBUG_KERNEL
bool "Kernel debugging"
help
@@ -285,7 +309,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 || SUPERH
+ depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || FRV || SUPERH || GENERIC_BUG
default !EMBEDDED
help
Say Y here to make BUG() panics output the file name and line number
@@ -302,16 +326,6 @@ config DEBUG_INFO
If unsure, say N.
-config DEBUG_FS
- bool "Debug Filesystem"
- depends on SYSFS
- help
- debugfs is a virtual file system that kernel developers use to put
- debugging files into. Enable this option to be able to read and
- write to these files.
-
- If unsure, say N.
-
config DEBUG_VM
bool "Debug VM"
depends on DEBUG_KERNEL
@@ -340,24 +354,6 @@ config FRAME_POINTER
some architectures or if you use external debuggers.
If you don't debug the kernel, you can say N.
-config UNWIND_INFO
- bool "Compile the kernel with frame unwind information"
- depends on !IA64 && !PARISC && !ARM
- depends on !MODULES || !(MIPS || PPC || SUPERH || V850)
- help
- If you say Y here the resulting kernel image will be slightly larger
- but not slower, and 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 unwind information or frame pointers.
-
-config STACK_UNWIND
- bool "Stack unwind support"
- depends on UNWIND_INFO
- depends on X86
- help
- This enables more precise stack traces, omitting all unrelated
- occurrences of pointers into kernel code from the dump.
-
config FORCED_INLINING
bool "Force gcc to inline functions marked 'inline'"
depends on DEBUG_KERNEL
@@ -372,20 +368,6 @@ 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
@@ -402,6 +384,7 @@ config RCU_TORTURE_TEST
config LKDTM
tristate "Linux Kernel Dump Test Tool Module"
+ depends on DEBUG_KERNEL
depends on KPROBES
default n
help
@@ -413,3 +396,36 @@ config LKDTM
Documentation on how to use the module can be found in
drivers/misc/lkdtm.c
+
+config FAULT_INJECTION
+ bool "Fault-injection framework"
+ depends on DEBUG_KERNEL
+ depends on STACKTRACE
+ select FRAME_POINTER
+ help
+ Provide fault-injection framework.
+ For more details, see Documentation/fault-injection/.
+
+config FAILSLAB
+ bool "Fault-injection capability for kmalloc"
+ depends on FAULT_INJECTION
+ help
+ Provide fault-injection capability for kmalloc.
+
+config FAIL_PAGE_ALLOC
+ bool "Fault-injection capabilitiy for alloc_pages()"
+ depends on FAULT_INJECTION
+ help
+ Provide fault-injection capability for alloc_pages().
+
+config FAIL_MAKE_REQUEST
+ bool "Fault-injection capability for disk IO"
+ depends on FAULT_INJECTION
+ help
+ Provide fault-injection capability for disk IO.
+
+config FAULT_INJECTION_DEBUG_FS
+ bool "Debugfs entries for fault-injection capabilities"
+ depends on FAULT_INJECTION && SYSFS && DEBUG_FS
+ help
+ Enable configuration of fault-injection capabilities via debugfs.
diff --git a/lib/Makefile b/lib/Makefile
index fea8f9035f0..3b605da448f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,20 +5,21 @@
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 irq_regs.o
+ sha1.o irq_regs.o reciprocal_div.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 random32.o
+obj-y += sort.o parser.o halfmd4.o debug_locks.o random32.o iomap.o
ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG
CFLAGS_kobject_uevent.o += -DDEBUG
endif
+obj-$(CONFIG_IOMAP_COPY) += iomap_copy.o
obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o
lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
@@ -35,11 +36,11 @@ ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
lib-y += dec_and_lock.o
endif
+obj-$(CONFIG_BITREVERSE) += bitrev.o
obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
obj-$(CONFIG_CRC16) += crc16.o
obj-$(CONFIG_CRC32) += crc32.o
obj-$(CONFIG_LIBCRC32C) += libcrc32c.o
-obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
@@ -54,6 +55,9 @@ obj-$(CONFIG_SMP) += percpu_counter.o
obj-$(CONFIG_AUDIT_GENERIC) += audit.o
obj-$(CONFIG_SWIOTLB) += swiotlb.o
+obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
+
+lib-$(CONFIG_GENERIC_BUG) += bug.o
hostprogs-y := gen_crc32table
clean-files := crc32table.h
diff --git a/lib/bitrev.c b/lib/bitrev.c
new file mode 100644
index 00000000000..989aff73f88
--- /dev/null
+++ b/lib/bitrev.c
@@ -0,0 +1,58 @@
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/bitrev.h>
+
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
+MODULE_DESCRIPTION("Bit ordering reversal functions");
+MODULE_LICENSE("GPL");
+
+const u8 byte_rev_table[256] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+EXPORT_SYMBOL_GPL(byte_rev_table);
+
+static __always_inline u16 bitrev16(u16 x)
+{
+ return (bitrev8(x & 0xff) << 8) | bitrev8(x >> 8);
+}
+
+/**
+ * bitrev32 - reverse the order of bits in a u32 value
+ * @x: value to be bit-reversed
+ */
+u32 bitrev32(u32 x)
+{
+ return (bitrev16(x & 0xffff) << 16) | bitrev16(x >> 16);
+}
+EXPORT_SYMBOL(bitrev32);
diff --git a/lib/bug.c b/lib/bug.c
new file mode 100644
index 00000000000..014b582c5c4
--- /dev/null
+++ b/lib/bug.c
@@ -0,0 +1,163 @@
+/*
+ Generic support for BUG()
+
+ This respects the following config options:
+
+ CONFIG_BUG - emit BUG traps. Nothing happens without this.
+ CONFIG_GENERIC_BUG - enable this code.
+ CONFIG_DEBUG_BUGVERBOSE - emit full file+line information for each BUG
+
+ CONFIG_BUG and CONFIG_DEBUG_BUGVERBOSE are potentially user-settable
+ (though they're generally always on).
+
+ CONFIG_GENERIC_BUG is set by each architecture using this code.
+
+ To use this, your architecture must:
+
+ 1. Set up the config options:
+ - Enable CONFIG_GENERIC_BUG if CONFIG_BUG
+
+ 2. Implement BUG (and optionally BUG_ON, WARN, WARN_ON)
+ - Define HAVE_ARCH_BUG
+ - Implement BUG() to generate a faulting instruction
+ - NOTE: struct bug_entry does not have "file" or "line" entries
+ when CONFIG_DEBUG_BUGVERBOSE is not enabled, so you must generate
+ the values accordingly.
+
+ 3. Implement the trap
+ - In the illegal instruction trap handler (typically), verify
+ that the fault was in kernel mode, and call report_bug()
+ - report_bug() will return whether it was a false alarm, a warning,
+ or an actual bug.
+ - You must implement the is_valid_bugaddr(bugaddr) callback which
+ returns true if the eip is a real kernel address, and it points
+ to the expected BUG trap instruction.
+
+ Jeremy Fitzhardinge <jeremy@goop.org> 2006
+ */
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/bug.h>
+
+extern const struct bug_entry __start___bug_table[], __stop___bug_table[];
+
+#ifdef CONFIG_MODULES
+static LIST_HEAD(module_bug_list);
+
+static const struct bug_entry *module_find_bug(unsigned long bugaddr)
+{
+ struct module *mod;
+
+ list_for_each_entry(mod, &module_bug_list, bug_list) {
+ const struct bug_entry *bug = mod->bug_table;
+ unsigned i;
+
+ for (i = 0; i < mod->num_bugs; ++i, ++bug)
+ if (bugaddr == bug->bug_addr)
+ return bug;
+ }
+ return NULL;
+}
+
+int module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+ struct module *mod)
+{
+ char *secstrings;
+ unsigned int i;
+
+ mod->bug_table = NULL;
+ mod->num_bugs = 0;
+
+ /* Find the __bug_table section, if present */
+ secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+ for (i = 1; i < hdr->e_shnum; i++) {
+ if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table"))
+ continue;
+ mod->bug_table = (void *) sechdrs[i].sh_addr;
+ mod->num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry);
+ break;
+ }
+
+ /*
+ * Strictly speaking this should have a spinlock to protect against
+ * traversals, but since we only traverse on BUG()s, a spinlock
+ * could potentially lead to deadlock and thus be counter-productive.
+ */
+ list_add(&mod->bug_list, &module_bug_list);
+
+ return 0;
+}
+
+void module_bug_cleanup(struct module *mod)
+{
+ list_del(&mod->bug_list);
+}
+
+#else
+
+static inline const struct bug_entry *module_find_bug(unsigned long bugaddr)
+{
+ return NULL;
+}
+#endif
+
+const struct bug_entry *find_bug(unsigned long bugaddr)
+{
+ const struct bug_entry *bug;
+
+ for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
+ if (bugaddr == bug->bug_addr)
+ return bug;
+
+ return module_find_bug(bugaddr);
+}
+
+enum bug_trap_type report_bug(unsigned long bugaddr)
+{
+ const struct bug_entry *bug;
+ const char *file;
+ unsigned line, warning;
+
+ if (!is_valid_bugaddr(bugaddr))
+ return BUG_TRAP_TYPE_NONE;
+
+ bug = find_bug(bugaddr);
+
+ printk(KERN_EMERG "------------[ cut here ]------------\n");
+
+ file = NULL;
+ line = 0;
+ warning = 0;
+
+ if (bug) {
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+ file = bug->file;
+ line = bug->line;
+#endif
+ warning = (bug->flags & BUGFLAG_WARNING) != 0;
+ }
+
+ if (warning) {
+ /* this is a WARN_ON rather than BUG/BUG_ON */
+ if (file)
+ printk(KERN_ERR "Badness at %s:%u\n",
+ file, line);
+ else
+ printk(KERN_ERR "Badness at %p "
+ "[verbose debug info unavailable]\n",
+ (void *)bugaddr);
+
+ dump_stack();
+ return BUG_TRAP_TYPE_WARN;
+ }
+
+ if (file)
+ printk(KERN_CRIT "kernel BUG at %s:%u!\n",
+ file, line);
+ else
+ printk(KERN_CRIT "Kernel BUG at %p "
+ "[verbose debug info unavailable]\n",
+ (void *)bugaddr);
+
+ return BUG_TRAP_TYPE_BUG;
+}
diff --git a/lib/crc32.c b/lib/crc32.c
index 285fd9bc61b..bfc33314c72 100644
--- a/lib/crc32.c
+++ b/lib/crc32.c
@@ -235,23 +235,8 @@ u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
}
#endif
-/**
- * bitreverse - reverse the order of bits in a u32 value
- * @x: value to be bit-reversed
- */
-u32 bitreverse(u32 x)
-{
- x = (x >> 16) | (x << 16);
- x = (x >> 8 & 0x00ff00ff) | (x << 8 & 0xff00ff00);
- x = (x >> 4 & 0x0f0f0f0f) | (x << 4 & 0xf0f0f0f0);
- x = (x >> 2 & 0x33333333) | (x << 2 & 0xcccccccc);
- x = (x >> 1 & 0x55555555) | (x << 1 & 0xaaaaaaaa);
- return x;
-}
-
EXPORT_SYMBOL(crc32_le);
EXPORT_SYMBOL(crc32_be);
-EXPORT_SYMBOL(bitreverse);
/*
* A brief CRC tutorial.
@@ -400,10 +385,7 @@ buf_dump(char const *prefix, unsigned char const *buf, size_t len)
static void bytereverse(unsigned char *buf, size_t len)
{
while (len--) {
- unsigned char x = *buf;
- x = (x >> 4) | (x << 4);
- x = (x >> 2 & 0x33) | (x << 2 & 0xcc);
- x = (x >> 1 & 0x55) | (x << 1 & 0xaa);
+ unsigned char x = bitrev8(*buf);
*buf++ = x;
}
}
@@ -460,11 +442,11 @@ static u32 test_step(u32 init, unsigned char *buf, size_t len)
/* Now swap it around for the other test */
bytereverse(buf, len + 4);
- init = bitreverse(init);
- crc2 = bitreverse(crc1);
- if (crc1 != bitreverse(crc2))
+ init = bitrev32(init);
+ crc2 = bitrev32(crc1);
+ if (crc1 != bitrev32(crc2))
printf("\nBit reversal fail: 0x%08x -> 0x%08x -> 0x%08x\n",
- crc1, crc2, bitreverse(crc2));
+ crc1, crc2, bitrev32(crc2));
crc1 = crc32_le(init, buf, len);
if (crc1 != crc2)
printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1,
diff --git a/lib/fault-inject.c b/lib/fault-inject.c
new file mode 100644
index 00000000000..b5a90fc056d
--- /dev/null
+++ b/lib/fault-inject.c
@@ -0,0 +1,306 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/stat.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/unwind.h>
+#include <linux/stacktrace.h>
+#include <linux/kallsyms.h>
+#include <linux/fault-inject.h>
+
+/*
+ * setup_fault_attr() is a helper function for various __setup handlers, so it
+ * returns 0 on error, because that is what __setup handlers do.
+ */
+int __init setup_fault_attr(struct fault_attr *attr, char *str)
+{
+ unsigned long probability;
+ unsigned long interval;
+ int times;
+ int space;
+
+ /* "<interval>,<probability>,<space>,<times>" */
+ if (sscanf(str, "%lu,%lu,%d,%d",
+ &interval, &probability, &space, &times) < 4) {
+ printk(KERN_WARNING
+ "FAULT_INJECTION: failed to parse arguments\n");
+ return 0;
+ }
+
+ attr->probability = probability;
+ attr->interval = interval;
+ atomic_set(&attr->times, times);
+ atomic_set(&attr->space, space);
+
+ return 1;
+}
+
+static void fail_dump(struct fault_attr *attr)
+{
+ if (attr->verbose > 0)
+ printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure\n");
+ if (attr->verbose > 1)
+ dump_stack();
+}
+
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
+
+static bool fail_task(struct fault_attr *attr, struct task_struct *task)
+{
+ return !in_interrupt() && task->make_it_fail;
+}
+
+#define MAX_STACK_TRACE_DEPTH 32
+
+#if defined(CONFIG_STACKTRACE)
+
+static bool fail_stacktrace(struct fault_attr *attr)
+{
+ struct stack_trace trace;
+ int depth = attr->stacktrace_depth;
+ unsigned long entries[MAX_STACK_TRACE_DEPTH];
+ int n;
+ bool found = (attr->require_start == 0 && attr->require_end == ULONG_MAX);
+
+ if (depth == 0)
+ return found;
+
+ trace.nr_entries = 0;
+ trace.entries = entries;
+ trace.max_entries = depth;
+ trace.skip = 1;
+ trace.all_contexts = 0;
+
+ save_stack_trace(&trace, NULL);
+ for (n = 0; n < trace.nr_entries; n++) {
+ if (attr->reject_start <= entries[n] &&
+ entries[n] < attr->reject_end)
+ return false;
+ if (attr->require_start <= entries[n] &&
+ entries[n] < attr->require_end)
+ found = true;
+ }
+ return found;
+}
+
+#else
+
+static inline bool fail_stacktrace(struct fault_attr *attr)
+{
+ static bool firsttime = true;
+
+ if (firsttime) {
+ printk(KERN_WARNING
+ "This architecture does not implement save_stack_trace()\n");
+ firsttime = false;
+ }
+ return false;
+}
+
+#endif
+
+/*
+ * This code is stolen from failmalloc-1.0
+ * http://www.nongnu.org/failmalloc/
+ */
+
+bool should_fail(struct fault_attr *attr, ssize_t size)
+{
+ if (attr->task_filter && !fail_task(attr, current))
+ return false;
+
+ if (atomic_read(&attr->times) == 0)
+ return false;
+
+ if (atomic_read(&attr->space) > size) {
+ atomic_sub(size, &attr->space);
+ return false;
+ }
+
+ if (attr->interval > 1) {
+ attr->count++;
+ if (attr->count % attr->interval)
+ return false;
+ }
+
+ if (attr->probability <= random32() % 100)
+ return false;
+
+ if (!fail_stacktrace(attr))
+ return false;
+
+ fail_dump(attr);
+
+ if (atomic_read(&attr->times) != -1)
+ atomic_dec_not_zero(&attr->times);
+
+ return true;
+}
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+static void debugfs_ul_set(void *data, u64 val)
+{
+ *(unsigned long *)data = val;
+}
+
+static void debugfs_ul_set_MAX_STACK_TRACE_DEPTH(void *data, u64 val)
+{
+ *(unsigned long *)data =
+ val < MAX_STACK_TRACE_DEPTH ?
+ val : MAX_STACK_TRACE_DEPTH;
+}
+
+static u64 debugfs_ul_get(void *data)
+{
+ return *(unsigned long *)data;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_ul, debugfs_ul_get, debugfs_ul_set, "%llu\n");
+
+static struct dentry *debugfs_create_ul(const char *name, mode_t mode,
+ struct dentry *parent, unsigned long *value)
+{
+ return debugfs_create_file(name, mode, parent, value, &fops_ul);
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_ul_MAX_STACK_TRACE_DEPTH, debugfs_ul_get,
+ debugfs_ul_set_MAX_STACK_TRACE_DEPTH, "%llu\n");
+
+static struct dentry *debugfs_create_ul_MAX_STACK_TRACE_DEPTH(
+ const char *name, mode_t mode,
+ struct dentry *parent, unsigned long *value)
+{
+ return debugfs_create_file(name, mode, parent, value,
+ &fops_ul_MAX_STACK_TRACE_DEPTH);
+}
+
+static void debugfs_atomic_t_set(void *data, u64 val)
+{
+ atomic_set((atomic_t *)data, val);
+}
+
+static u64 debugfs_atomic_t_get(void *data)
+{
+ return atomic_read((atomic_t *)data);
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get,
+ debugfs_atomic_t_set, "%lld\n");
+
+static struct dentry *debugfs_create_atomic_t(const char *name, mode_t mode,
+ struct dentry *parent, atomic_t *value)
+{
+ return debugfs_create_file(name, mode, parent, value, &fops_atomic_t);
+}
+
+void cleanup_fault_attr_dentries(struct fault_attr *attr)
+{
+ debugfs_remove(attr->dentries.probability_file);
+ attr->dentries.probability_file = NULL;
+
+ debugfs_remove(attr->dentries.interval_file);
+ attr->dentries.interval_file = NULL;
+
+ debugfs_remove(attr->dentries.times_file);
+ attr->dentries.times_file = NULL;
+
+ debugfs_remove(attr->dentries.space_file);
+ attr->dentries.space_file = NULL;
+
+ debugfs_remove(attr->dentries.verbose_file);
+ attr->dentries.verbose_file = NULL;
+
+ debugfs_remove(attr->dentries.task_filter_file);
+ attr->dentries.task_filter_file = NULL;
+
+ debugfs_remove(attr->dentries.stacktrace_depth_file);
+ attr->dentries.stacktrace_depth_file = NULL;
+
+ debugfs_remove(attr->dentries.require_start_file);
+ attr->dentries.require_start_file = NULL;
+
+ debugfs_remove(attr->dentries.require_end_file);
+ attr->dentries.require_end_file = NULL;
+
+ debugfs_remove(attr->dentries.reject_start_file);
+ attr->dentries.reject_start_file = NULL;
+
+ debugfs_remove(attr->dentries.reject_end_file);
+ attr->dentries.reject_end_file = NULL;
+
+ if (attr->dentries.dir)
+ WARN_ON(!simple_empty(attr->dentries.dir));
+
+ debugfs_remove(attr->dentries.dir);
+ attr->dentries.dir = NULL;
+}
+
+int init_fault_attr_dentries(struct fault_attr *attr, const char *name)
+{
+ mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+ struct dentry *dir;
+
+ memset(&attr->dentries, 0, sizeof(attr->dentries));
+
+ dir = debugfs_create_dir(name, NULL);
+ if (!dir)
+ goto fail;
+ attr->dentries.dir = dir;
+
+ attr->dentries.probability_file =
+ debugfs_create_ul("probability", mode, dir, &attr->probability);
+
+ attr->dentries.interval_file =
+ debugfs_create_ul("interval", mode, dir, &attr->interval);
+
+ attr->dentries.times_file =
+ debugfs_create_atomic_t("times", mode, dir, &attr->times);
+
+ attr->dentries.space_file =
+ debugfs_create_atomic_t("space", mode, dir, &attr->space);
+
+ attr->dentries.verbose_file =
+ debugfs_create_ul("verbose", mode, dir, &attr->verbose);
+
+ attr->dentries.task_filter_file = debugfs_create_bool("task-filter",
+ mode, dir, &attr->task_filter);
+
+ attr->dentries.stacktrace_depth_file =
+ debugfs_create_ul_MAX_STACK_TRACE_DEPTH(
+ "stacktrace-depth", mode, dir, &attr->stacktrace_depth);
+
+ attr->dentries.require_start_file =
+ debugfs_create_ul("require-start", mode, dir, &attr->require_start);
+
+ attr->dentries.require_end_file =
+ debugfs_create_ul("require-end", mode, dir, &attr->require_end);
+
+ attr->dentries.reject_start_file =
+ debugfs_create_ul("reject-start", mode, dir, &attr->reject_start);
+
+ attr->dentries.reject_end_file =
+ debugfs_create_ul("reject-end", mode, dir, &attr->reject_end);
+
+
+ if (!attr->dentries.probability_file || !attr->dentries.interval_file
+ || !attr->dentries.times_file || !attr->dentries.space_file
+ || !attr->dentries.verbose_file || !attr->dentries.task_filter_file
+ || !attr->dentries.stacktrace_depth_file
+ || !attr->dentries.require_start_file
+ || !attr->dentries.require_end_file
+ || !attr->dentries.reject_start_file
+ || !attr->dentries.reject_end_file
+ )
+ goto fail;
+
+ return 0;
+fail:
+ cleanup_fault_attr_dentries(attr);
+ return -ENOMEM;
+}
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
diff --git a/lib/iomap.c b/lib/iomap.c
index d6ccdd85df5..4990c736bc4 100644
--- a/lib/iomap.c
+++ b/lib/iomap.c
@@ -4,8 +4,10 @@
* (C) Copyright 2004 Linus Torvalds
*/
#include <linux/pci.h>
+#include <linux/io.h>
+
+#ifdef CONFIG_GENERIC_IOMAP
#include <linux/module.h>
-#include <asm/io.h>
/*
* Read/write from/to an (offsettable) iomem cookie. It might be a PIO
@@ -254,3 +256,298 @@ void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
}
EXPORT_SYMBOL(pci_iomap);
EXPORT_SYMBOL(pci_iounmap);
+
+#endif /* CONFIG_GENERIC_IOMAP */
+
+/*
+ * Generic iomap devres
+ */
+static void devm_ioport_map_release(struct device *dev, void *res)
+{
+ ioport_unmap(*(void __iomem **)res);
+}
+
+static int devm_ioport_map_match(struct device *dev, void *res,
+ void *match_data)
+{
+ return *(void **)res == match_data;
+}
+
+/**
+ * devm_ioport_map - Managed ioport_map()
+ * @dev: Generic device to map ioport for
+ * @port: Port to map
+ * @nr: Number of ports to map
+ *
+ * Managed ioport_map(). Map is automatically unmapped on driver
+ * detach.
+ */
+void __iomem * devm_ioport_map(struct device *dev, unsigned long port,
+ unsigned int nr)
+{
+ void __iomem **ptr, *addr;
+
+ ptr = devres_alloc(devm_ioport_map_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ addr = ioport_map(port, nr);
+ if (addr) {
+ *ptr = addr;
+ devres_add(dev, ptr);
+ } else
+ devres_free(ptr);
+
+ return addr;
+}
+EXPORT_SYMBOL(devm_ioport_map);
+
+/**
+ * devm_ioport_unmap - Managed ioport_unmap()
+ * @dev: Generic device to unmap for
+ * @addr: Address to unmap
+ *
+ * Managed ioport_unmap(). @addr must have been mapped using
+ * devm_ioport_map().
+ */
+void devm_ioport_unmap(struct device *dev, void __iomem *addr)
+{
+ ioport_unmap(addr);
+ WARN_ON(devres_destroy(dev, devm_ioport_map_release,
+ devm_ioport_map_match, (void *)addr));
+}
+EXPORT_SYMBOL(devm_ioport_unmap);
+
+static void devm_ioremap_release(struct device *dev, void *res)
+{
+ iounmap(*(void __iomem **)res);
+}
+
+static int devm_ioremap_match(struct device *dev, void *res, void *match_data)
+{
+ return *(void **)res == match_data;
+}
+
+/**
+ * devm_ioremap - Managed ioremap()
+ * @dev: Generic device to remap IO address for
+ * @offset: BUS offset to map
+ * @size: Size of map
+ *
+ * Managed ioremap(). Map is automatically unmapped on driver detach.
+ */
+void __iomem *devm_ioremap(struct device *dev, unsigned long offset,
+ unsigned long size)
+{
+ void __iomem **ptr, *addr;
+
+ ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ addr = ioremap(offset, size);
+ if (addr) {
+ *ptr = addr;
+ devres_add(dev, ptr);
+ } else
+ devres_free(ptr);
+
+ return addr;
+}
+EXPORT_SYMBOL(devm_ioremap);
+
+/**
+ * devm_ioremap_nocache - Managed ioremap_nocache()
+ * @dev: Generic device to remap IO address for
+ * @offset: BUS offset to map
+ * @size: Size of map
+ *
+ * Managed ioremap_nocache(). Map is automatically unmapped on driver
+ * detach.
+ */
+void __iomem *devm_ioremap_nocache(struct device *dev, unsigned long offset,
+ unsigned long size)
+{
+ void __iomem **ptr, *addr;
+
+ ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ addr = ioremap_nocache(offset, size);
+ if (addr) {
+ *ptr = addr;
+ devres_add(dev, ptr);
+ } else
+ devres_free(ptr);
+
+ return addr;
+}
+EXPORT_SYMBOL(devm_ioremap_nocache);
+
+/**
+ * devm_iounmap - Managed iounmap()
+ * @dev: Generic device to unmap for
+ * @addr: Address to unmap
+ *
+ * Managed iounmap(). @addr must have been mapped using devm_ioremap*().
+ */
+void devm_iounmap(struct device *dev, void __iomem *addr)
+{
+ iounmap(addr);
+ WARN_ON(devres_destroy(dev, devm_ioremap_release, devm_ioremap_match,
+ (void *)addr));
+}
+EXPORT_SYMBOL(devm_iounmap);
+
+/*
+ * PCI iomap devres
+ */
+#define PCIM_IOMAP_MAX PCI_ROM_RESOURCE
+
+struct pcim_iomap_devres {
+ void __iomem *table[PCIM_IOMAP_MAX];
+};
+
+static void pcim_iomap_release(struct device *gendev, void *res)
+{
+ struct pci_dev *dev = container_of(gendev, struct pci_dev, dev);
+ struct pcim_iomap_devres *this = res;
+ int i;
+
+ for (i = 0; i < PCIM_IOMAP_MAX; i++)
+ if (this->table[i])
+ pci_iounmap(dev, this->table[i]);
+}
+
+/**
+ * pcim_iomap_table - access iomap allocation table
+ * @pdev: PCI device to access iomap table for
+ *
+ * Access iomap allocation table for @dev. If iomap table doesn't
+ * exist and @pdev is managed, it will be allocated. All iomaps
+ * recorded in the iomap table are automatically unmapped on driver
+ * detach.
+ *
+ * This function might sleep when the table is first allocated but can
+ * be safely called without context and guaranteed to succed once
+ * allocated.
+ */
+void __iomem * const * pcim_iomap_table(struct pci_dev *pdev)
+{
+ struct pcim_iomap_devres *dr, *new_dr;
+
+ dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL);
+ if (dr)
+ return dr->table;
+
+ new_dr = devres_alloc(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL);
+ if (!new_dr)
+ return NULL;
+ dr = devres_get(&pdev->dev, new_dr, NULL, NULL);
+ return dr->table;
+}
+EXPORT_SYMBOL(pcim_iomap_table);
+
+/**
+ * pcim_iomap - Managed pcim_iomap()
+ * @pdev: PCI device to iomap for
+ * @bar: BAR to iomap
+ * @maxlen: Maximum length of iomap
+ *
+ * Managed pci_iomap(). Map is automatically unmapped on driver
+ * detach.
+ */
+void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
+{
+ void __iomem **tbl;
+
+ BUG_ON(bar >= PCIM_IOMAP_MAX);
+
+ tbl = (void __iomem **)pcim_iomap_table(pdev);
+ if (!tbl || tbl[bar]) /* duplicate mappings not allowed */
+ return NULL;
+
+ tbl[bar] = pci_iomap(pdev, bar, maxlen);
+ return tbl[bar];
+}
+EXPORT_SYMBOL(pcim_iomap);
+
+/**
+ * pcim_iounmap - Managed pci_iounmap()
+ * @pdev: PCI device to iounmap for
+ * @addr: Address to unmap
+ *
+ * Managed pci_iounmap(). @addr must have been mapped using pcim_iomap().
+ */
+void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr)
+{
+ void __iomem **tbl;
+ int i;
+
+ pci_iounmap(pdev, addr);
+
+ tbl = (void __iomem **)pcim_iomap_table(pdev);
+ BUG_ON(!tbl);
+
+ for (i = 0; i < PCIM_IOMAP_MAX; i++)
+ if (tbl[i] == addr) {
+ tbl[i] = NULL;
+ return;
+ }
+ WARN_ON(1);
+}
+EXPORT_SYMBOL(pcim_iounmap);
+
+/**
+ * pcim_iomap_regions - Request and iomap PCI BARs
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to request and iomap
+ * @name: Name used when requesting regions
+ *
+ * Request and iomap regions specified by @mask.
+ */
+int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name)
+{
+ void __iomem * const *iomap;
+ int i, rc;
+
+ iomap = pcim_iomap_table(pdev);
+ if (!iomap)
+ return -ENOMEM;
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ unsigned long len;
+
+ if (!(mask & (1 << i)))
+ continue;
+
+ rc = -EINVAL;
+ len = pci_resource_len(pdev, i);
+ if (!len)
+ goto err_inval;
+
+ rc = pci_request_region(pdev, i, name);
+ if (rc)
+ goto err_region;
+
+ rc = -ENOMEM;
+ if (!pcim_iomap(pdev, i, 0))
+ goto err_iomap;
+ }
+
+ return 0;
+
+ err_iomap:
+ pcim_iounmap(pdev, iomap[i]);
+ err_region:
+ pci_release_region(pdev, i);
+ err_inval:
+ while (--i >= 0) {
+ pcim_iounmap(pdev, iomap[i]);
+ pci_release_region(pdev, i);
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL(pcim_iomap_regions);
diff --git a/lib/ioremap.c b/lib/ioremap.c
index 99fa277f9f7..a9e4415b02d 100644
--- a/lib/ioremap.c
+++ b/lib/ioremap.c
@@ -5,7 +5,6 @@
*
* (C) Copyright 1995 1996 Linus Torvalds
*/
-#include <linux/io.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
diff --git a/lib/kobject.c b/lib/kobject.c
index 7ce6dc138e9..c2917ffe8bf 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -44,11 +44,11 @@ static int populate_dir(struct kobject * kobj)
return error;
}
-static int create_dir(struct kobject * kobj)
+static int create_dir(struct kobject * kobj, struct dentry *shadow_parent)
{
int error = 0;
if (kobject_name(kobj)) {
- error = sysfs_create_dir(kobj);
+ error = sysfs_create_dir(kobj, shadow_parent);
if (!error) {
if ((error = populate_dir(kobj)))
sysfs_remove_dir(kobj);
@@ -126,6 +126,8 @@ EXPORT_SYMBOL_GPL(kobject_get_path);
*/
void kobject_init(struct kobject * kobj)
{
+ if (!kobj)
+ return;
kref_init(&kobj->kref);
INIT_LIST_HEAD(&kobj->entry);
init_waitqueue_head(&kobj->poll);
@@ -156,9 +158,10 @@ static void unlink(struct kobject * kobj)
/**
* kobject_add - add an object to the hierarchy.
* @kobj: object.
+ * @shadow_parent: sysfs directory to add to.
*/
-int kobject_add(struct kobject * kobj)
+int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
{
int error = 0;
struct kobject * parent;
@@ -189,12 +192,11 @@ int kobject_add(struct kobject * kobj)
}
kobj->parent = parent;
- error = create_dir(kobj);
+ error = create_dir(kobj, shadow_parent);
if (error) {
/* unlink does the kobject_put() for us */
unlink(kobj);
- if (parent)
- kobject_put(parent);
+ kobject_put(parent);
/* be noisy on error issues */
if (error == -EEXIST)
@@ -211,6 +213,15 @@ int kobject_add(struct kobject * kobj)
return error;
}
+/**
+ * kobject_add - add an object to the hierarchy.
+ * @kobj: object.
+ */
+int kobject_add(struct kobject * kobj)
+{
+ return kobject_shadow_add(kobj, NULL);
+}
+
/**
* kobject_register - initialize and add an object.
@@ -303,7 +314,29 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
kobj = kobject_get(kobj);
if (!kobj)
return -EINVAL;
- error = sysfs_rename_dir(kobj, new_name);
+ if (!kobj->parent)
+ return -EINVAL;
+ error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name);
+ kobject_put(kobj);
+
+ return error;
+}
+
+/**
+ * kobject_rename - change the name of an object
+ * @kobj: object in question.
+ * @new_name: object's new name
+ */
+
+int kobject_shadow_rename(struct kobject * kobj, struct dentry *new_parent,
+ const char *new_name)
+{
+ int error = 0;
+
+ kobj = kobject_get(kobj);
+ if (!kobj)
+ return -EINVAL;
+ error = sysfs_rename_dir(kobj, new_parent, new_name);
kobject_put(kobj);
return error;
@@ -312,7 +345,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
/**
* kobject_move - move object to another parent
* @kobj: object in question.
- * @new_parent: object's new parent
+ * @new_parent: object's new parent (can be NULL)
*/
int kobject_move(struct kobject *kobj, struct kobject *new_parent)
@@ -328,8 +361,8 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent)
return -EINVAL;
new_parent = kobject_get(new_parent);
if (!new_parent) {
- error = -EINVAL;
- goto out;
+ if (kobj->kset)
+ new_parent = kobject_get(&kobj->kset->kobj);
}
/* old object path */
devpath = kobject_get_path(kobj, GFP_KERNEL);
@@ -366,6 +399,8 @@ out:
void kobject_del(struct kobject * kobj)
{
+ if (!kobj)
+ return;
sysfs_remove_dir(kobj);
unlink(kobj);
}
@@ -377,6 +412,8 @@ void kobject_del(struct kobject * kobj)
void kobject_unregister(struct kobject * kobj)
{
+ if (!kobj)
+ return;
pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
kobject_uevent(kobj, KOBJ_REMOVE);
kobject_del(kobj);
@@ -414,8 +451,7 @@ void kobject_cleanup(struct kobject * kobj)
t->release(kobj);
if (s)
kset_put(s);
- if (parent)
- kobject_put(parent);
+ kobject_put(parent);
}
static void kobject_release(struct kref *kref)
@@ -523,6 +559,8 @@ int kset_add(struct kset * k)
int kset_register(struct kset * k)
{
+ if (!k)
+ return -EINVAL;
kset_init(k);
return kset_add(k);
}
@@ -535,6 +573,8 @@ int kset_register(struct kset * k)
void kset_unregister(struct kset * k)
{
+ if (!k)
+ return;
kobject_unregister(&k->kobj);
}
@@ -586,6 +626,9 @@ int subsystem_register(struct subsystem * s)
{
int error;
+ if (!s)
+ return -EINVAL;
+
subsystem_init(s);
pr_debug("subsystem %s: registering\n",s->kset.kobj.name);
@@ -598,6 +641,8 @@ int subsystem_register(struct subsystem * s)
void subsystem_unregister(struct subsystem * s)
{
+ if (!s)
+ return;
pr_debug("subsystem %s: unregistering\n",s->kset.kobj.name);
kset_unregister(&s->kset);
}
@@ -612,6 +657,10 @@ void subsystem_unregister(struct subsystem * s)
int subsys_create_file(struct subsystem * s, struct subsys_attribute * a)
{
int error = 0;
+
+ if (!s || !a)
+ return -EINVAL;
+
if (subsys_get(s)) {
error = sysfs_create_file(&s->kset.kobj,&a->attr);
subsys_put(s);
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index a1922765ff3..84272ed77f0 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -63,8 +63,11 @@ static char *action_to_string(enum kobject_action action)
* @action: action that is happening (usually KOBJ_MOVE)
* @kobj: struct kobject that the action is happening to
* @envp_ext: pointer to environmental data
+ *
+ * Returns 0 if kobject_uevent() is completed with success or the
+ * corresponding error when it fails.
*/
-void kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
+int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
char *envp_ext[])
{
char **envp;
@@ -79,14 +82,16 @@ void kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
u64 seq;
char *seq_buff;
int i = 0;
- int retval;
+ int retval = 0;
int j;
pr_debug("%s\n", __FUNCTION__);
action_string = action_to_string(action);
- if (!action_string)
- return;
+ if (!action_string) {
+ pr_debug("kobject attempted to send uevent without action_string!\n");
+ return -EINVAL;
+ }
/* search the kset we belong to */
top_kobj = kobj;
@@ -95,31 +100,39 @@ void kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
top_kobj = top_kobj->parent;
} while (!top_kobj->kset && top_kobj->parent);
}
- if (!top_kobj->kset)
- return;
+ if (!top_kobj->kset) {
+ pr_debug("kobject attempted to send uevent without kset!\n");
+ return -EINVAL;
+ }
kset = top_kobj->kset;
uevent_ops = kset->uevent_ops;
/* skip the event, if the filter returns zero. */
if (uevent_ops && uevent_ops->filter)
- if (!uevent_ops->filter(kset, kobj))
- return;
+ if (!uevent_ops->filter(kset, kobj)) {
+ pr_debug("kobject filter function caused the event to drop!\n");
+ return 0;
+ }
/* environment index */
envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
if (!envp)
- return;
+ return -ENOMEM;
/* environment values */
buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
- if (!buffer)
+ if (!buffer) {
+ retval = -ENOMEM;
goto exit;
+ }
/* complete object path */
devpath = kobject_get_path(kobj, GFP_KERNEL);
- if (!devpath)
+ if (!devpath) {
+ retval = -ENOENT;
goto exit;
+ }
/* originating subsystem */
if (uevent_ops && uevent_ops->name)
@@ -204,7 +217,7 @@ exit:
kfree(devpath);
kfree(buffer);
kfree(envp);
- return;
+ return retval;
}
EXPORT_SYMBOL_GPL(kobject_uevent_env);
@@ -214,10 +227,13 @@ EXPORT_SYMBOL_GPL(kobject_uevent_env);
*
* @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE)
* @kobj: struct kobject that the action is happening to
+ *
+ * Returns 0 if kobject_uevent() is completed with success or the
+ * corresponding error when it fails.
*/
-void kobject_uevent(struct kobject *kobj, enum kobject_action action)
+int kobject_uevent(struct kobject *kobj, enum kobject_action action)
{
- kobject_uevent_env(kobj, action, NULL);
+ return kobject_uevent_env(kobj, action, NULL);
}
EXPORT_SYMBOL_GPL(kobject_uevent);
diff --git a/lib/kref.c b/lib/kref.c
index 4a467faf136..0d07cc31c81 100644
--- a/lib/kref.c
+++ b/lib/kref.c
@@ -52,12 +52,7 @@ int kref_put(struct kref *kref, void (*release)(struct kref *kref))
WARN_ON(release == NULL);
WARN_ON(release == (void (*)(struct kref *))kfree);
- /*
- * if current count is one, we are the last user and can release object
- * right now, avoiding an atomic operation on 'refcount'
- */
- if ((atomic_read(&kref->refcount) == 1) ||
- (atomic_dec_and_test(&kref->refcount))) {
+ if (atomic_dec_and_test(&kref->refcount)) {
release(kref);
return 1;
}
diff --git a/lib/reciprocal_div.c b/lib/reciprocal_div.c
new file mode 100644
index 00000000000..6a3bd48fa2a
--- /dev/null
+++ b/lib/reciprocal_div.c
@@ -0,0 +1,9 @@
+#include <asm/div64.h>
+#include <linux/reciprocal_div.h>
+
+u32 reciprocal_value(u32 k)
+{
+ u64 val = (1LL << 32) + (k - 1);
+ do_div(val, k);
+ return (u32)val;
+}
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 10625785eef..50a43801018 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -1,7 +1,7 @@
/*
* Dynamic DMA mapping support.
*
- * This implementation is for IA-64 and EM64T platforms that do not support
+ * This implementation is a fallback for platforms that do not support
* I/O TLBs (aka DMA address translation hardware).
* Copyright (C) 2000 Asit Mallick <Asit.K.Mallick@intel.com>
* Copyright (C) 2000 Goutham Rao <goutham.rao@intel.com>
@@ -28,6 +28,7 @@
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/scatterlist.h>
+#include <asm/swiotlb.h>
#include <linux/init.h>
#include <linux/bootmem.h>
@@ -35,8 +36,10 @@
#define OFFSET(val,align) ((unsigned long) \
( (val) & ( (align) - 1)))
+#ifndef SG_ENT_VIRT_ADDRESS
#define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset)
-#define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
+#define SG_ENT_PHYS_ADDRESS(sg) virt_to_bus(SG_ENT_VIRT_ADDRESS(sg))
+#endif
/*
* Maximum allowable number of contiguous slabs to map,
@@ -101,13 +104,25 @@ static unsigned int io_tlb_index;
* We need to save away the original address corresponding to a mapped entry
* for the sync operations.
*/
-static unsigned char **io_tlb_orig_addr;
+#ifndef SWIOTLB_ARCH_HAS_IO_TLB_ADDR_T
+typedef char *io_tlb_addr_t;
+#define swiotlb_orig_addr_null(buffer) (!(buffer))
+#define ptr_to_io_tlb_addr(ptr) (ptr)
+#define page_to_io_tlb_addr(pg, off) (page_address(pg) + (off))
+#define sg_to_io_tlb_addr(sg) SG_ENT_VIRT_ADDRESS(sg)
+#endif
+static io_tlb_addr_t *io_tlb_orig_addr;
/*
* Protect the above data structures in the map and unmap calls
*/
static DEFINE_SPINLOCK(io_tlb_lock);
+#ifdef SWIOTLB_EXTRA_VARIABLES
+SWIOTLB_EXTRA_VARIABLES;
+#endif
+
+#ifndef SWIOTLB_ARCH_HAS_SETUP_IO_TLB_NPAGES
static int __init
setup_io_tlb_npages(char *str)
{
@@ -122,30 +137,50 @@ setup_io_tlb_npages(char *str)
swiotlb_force = 1;
return 1;
}
+#endif
__setup("swiotlb=", setup_io_tlb_npages);
/* make io_tlb_overflow tunable too? */
+#ifndef swiotlb_adjust_size
+#define swiotlb_adjust_size(size) ((void)0)
+#endif
+
+#ifndef swiotlb_adjust_seg
+#define swiotlb_adjust_seg(start, size) ((void)0)
+#endif
+
+#ifndef swiotlb_print_info
+#define swiotlb_print_info(bytes) \
+ printk(KERN_INFO "Placing %luMB software IO TLB between 0x%lx - " \
+ "0x%lx\n", bytes >> 20, \
+ virt_to_bus(io_tlb_start), virt_to_bus(io_tlb_end))
+#endif
+
/*
* Statically reserve bounce buffer space and initialize bounce buffer data
* structures for the software IO TLB used to implement the DMA API.
*/
-void
-swiotlb_init_with_default_size (size_t default_size)
+void __init
+swiotlb_init_with_default_size(size_t default_size)
{
- unsigned long i;
+ unsigned long i, bytes;
if (!io_tlb_nslabs) {
io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
}
+ swiotlb_adjust_size(io_tlb_nslabs);
+ swiotlb_adjust_size(io_tlb_overflow);
+
+ bytes = io_tlb_nslabs << IO_TLB_SHIFT;
/*
* Get IO TLB memory from the low pages
*/
- io_tlb_start = alloc_bootmem_low_pages(io_tlb_nslabs * (1 << IO_TLB_SHIFT));
+ io_tlb_start = alloc_bootmem_low_pages(bytes);
if (!io_tlb_start)
panic("Cannot allocate SWIOTLB buffer");
- io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT);
+ io_tlb_end = io_tlb_start + bytes;
/*
* Allocate and initialize the free list array. This array is used
@@ -153,34 +188,45 @@ swiotlb_init_with_default_size (size_t default_size)
* between io_tlb_start and io_tlb_end.
*/
io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int));
- for (i = 0; i < io_tlb_nslabs; i++)
+ for (i = 0; i < io_tlb_nslabs; i++) {
+ if ( !(i % IO_TLB_SEGSIZE) )
+ swiotlb_adjust_seg(io_tlb_start + (i << IO_TLB_SHIFT),
+ IO_TLB_SEGSIZE << IO_TLB_SHIFT);
io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
+ }
io_tlb_index = 0;
- io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *));
+ io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(io_tlb_addr_t));
/*
* Get the overflow emergency buffer
*/
io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow);
- printk(KERN_INFO "Placing software IO TLB between 0x%lx - 0x%lx\n",
- virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end));
+ if (!io_tlb_overflow_buffer)
+ panic("Cannot allocate SWIOTLB overflow buffer!\n");
+ swiotlb_adjust_seg(io_tlb_overflow_buffer, io_tlb_overflow);
+
+ swiotlb_print_info(bytes);
}
+#ifndef __swiotlb_init_with_default_size
+#define __swiotlb_init_with_default_size swiotlb_init_with_default_size
+#endif
-void
-swiotlb_init (void)
+void __init
+swiotlb_init(void)
{
- swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */
+ __swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */
}
+#ifdef SWIOTLB_ARCH_NEED_LATE_INIT
/*
* Systems with larger DMA zones (those that don't support ISA) can
* initialize the swiotlb later using the slab allocator if needed.
* This should be just like above, but with some error catching.
*/
int
-swiotlb_late_init_with_default_size (size_t default_size)
+swiotlb_late_init_with_default_size(size_t default_size)
{
- unsigned long i, req_nslabs = io_tlb_nslabs;
+ unsigned long i, bytes, req_nslabs = io_tlb_nslabs;
unsigned int order;
if (!io_tlb_nslabs) {
@@ -191,8 +237,9 @@ swiotlb_late_init_with_default_size (size_t default_size)
/*
* Get IO TLB memory from the low pages
*/
- order = get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT));
+ order = get_order(io_tlb_nslabs << IO_TLB_SHIFT);
io_tlb_nslabs = SLABS_PER_PAGE << order;
+ bytes = io_tlb_nslabs << IO_TLB_SHIFT;
while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
io_tlb_start = (char *)__get_free_pages(GFP_DMA | __GFP_NOWARN,
@@ -205,13 +252,14 @@ swiotlb_late_init_with_default_size (size_t default_size)
if (!io_tlb_start)
goto cleanup1;
- if (order != get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT))) {
+ if (order != get_order(bytes)) {
printk(KERN_WARNING "Warning: only able to allocate %ld MB "
"for software IO TLB\n", (PAGE_SIZE << order) >> 20);
io_tlb_nslabs = SLABS_PER_PAGE << order;
+ bytes = io_tlb_nslabs << IO_TLB_SHIFT;
}
- io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT);
- memset(io_tlb_start, 0, io_tlb_nslabs * (1 << IO_TLB_SHIFT));
+ io_tlb_end = io_tlb_start + bytes;
+ memset(io_tlb_start, 0, bytes);
/*
* Allocate and initialize the free list array. This array is used
@@ -227,12 +275,12 @@ swiotlb_late_init_with_default_size (size_t default_size)
io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
io_tlb_index = 0;
- io_tlb_orig_addr = (unsigned char **)__get_free_pages(GFP_KERNEL,
- get_order(io_tlb_nslabs * sizeof(char *)));
+ io_tlb_orig_addr = (io_tlb_addr_t *)__get_free_pages(GFP_KERNEL,
+ get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t)));
if (!io_tlb_orig_addr)
goto cleanup3;
- memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(char *));
+ memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(io_tlb_addr_t));
/*
* Get the overflow emergency buffer
@@ -242,29 +290,29 @@ swiotlb_late_init_with_default_size (size_t default_size)
if (!io_tlb_overflow_buffer)
goto cleanup4;
- printk(KERN_INFO "Placing %ldMB software IO TLB between 0x%lx - "
- "0x%lx\n", (io_tlb_nslabs * (1 << IO_TLB_SHIFT)) >> 20,
- virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end));
+ swiotlb_print_info(bytes);
return 0;
cleanup4:
- free_pages((unsigned long)io_tlb_orig_addr, get_order(io_tlb_nslabs *
- sizeof(char *)));
+ free_pages((unsigned long)io_tlb_orig_addr,
+ get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t)));
io_tlb_orig_addr = NULL;
cleanup3:
- free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *
- sizeof(int)));
+ free_pages((unsigned long)io_tlb_list,
+ get_order(io_tlb_nslabs * sizeof(int)));
io_tlb_list = NULL;
- io_tlb_end = NULL;
cleanup2:
+ io_tlb_end = NULL;
free_pages((unsigned long)io_tlb_start, order);
io_tlb_start = NULL;
cleanup1:
io_tlb_nslabs = req_nslabs;
return -ENOMEM;
}
+#endif
+#ifndef SWIOTLB_ARCH_HAS_NEEDS_MAPPING
static inline int
address_needs_mapping(struct device *hwdev, dma_addr_t addr)
{
@@ -275,11 +323,35 @@ address_needs_mapping(struct device *hwdev, dma_addr_t addr)
return (addr & ~mask) != 0;
}
+static inline int range_needs_mapping(const void *ptr, size_t size)
+{
+ return swiotlb_force;
+}
+
+static inline int order_needs_mapping(unsigned int order)
+{
+ return 0;
+}
+#endif
+
+static void
+__sync_single(io_tlb_addr_t buffer, char *dma_addr, size_t size, int dir)
+{
+#ifndef SWIOTLB_ARCH_HAS_SYNC_SINGLE
+ if (dir == DMA_TO_DEVICE)
+ memcpy(dma_addr, buffer, size);
+ else
+ memcpy(buffer, dma_addr, size);
+#else
+ __swiotlb_arch_sync_single(buffer, dma_addr, size, dir);
+#endif
+}
+
/*
* Allocates bounce buffer and returns its kernel virtual address.
*/
static void *
-map_single(struct device *hwdev, char *buffer, size_t size, int dir)
+map_single(struct device *hwdev, io_tlb_addr_t buffer, size_t size, int dir)
{
unsigned long flags;
char *dma_addr;
@@ -352,7 +424,7 @@ map_single(struct device *hwdev, char *buffer, size_t size, int dir)
*/
io_tlb_orig_addr[index] = buffer;
if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
- memcpy(dma_addr, buffer, size);
+ __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE);
return dma_addr;
}
@@ -366,17 +438,18 @@ unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
unsigned long flags;
int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
- char *buffer = io_tlb_orig_addr[index];
+ io_tlb_addr_t buffer = io_tlb_orig_addr[index];
/*
* First, sync the memory before unmapping the entry
*/
- if (buffer && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
+ if (!swiotlb_orig_addr_null(buffer)
+ && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
/*
* bounce... copy the data back into the original buffer * and
* delete the bounce buffer.
*/
- memcpy(buffer, dma_addr, size);
+ __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE);
/*
* Return the buffer to the free list by setting the corresponding
@@ -409,18 +482,18 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
int dir, int target)
{
int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
- char *buffer = io_tlb_orig_addr[index];
+ io_tlb_addr_t buffer = io_tlb_orig_addr[index];
switch (target) {
case SYNC_FOR_CPU:
if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
- memcpy(buffer, dma_addr, size);
+ __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE);
else
BUG_ON(dir != DMA_TO_DEVICE);
break;
case SYNC_FOR_DEVICE:
if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
- memcpy(dma_addr, buffer, size);
+ __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE);
else
BUG_ON(dir != DMA_FROM_DEVICE);
break;
@@ -429,11 +502,13 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
}
}
+#ifdef SWIOTLB_ARCH_NEED_ALLOC
+
void *
swiotlb_alloc_coherent(struct device *hwdev, size_t size,
dma_addr_t *dma_handle, gfp_t flags)
{
- unsigned long dev_addr;
+ dma_addr_t dev_addr;
void *ret;
int order = get_order(size);
@@ -444,8 +519,11 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
*/
flags |= GFP_DMA;
- ret = (void *)__get_free_pages(flags, order);
- if (ret && address_needs_mapping(hwdev, virt_to_phys(ret))) {
+ if (!order_needs_mapping(order))
+ ret = (void *)__get_free_pages(flags, order);
+ else
+ ret = NULL;
+ if (ret && address_needs_mapping(hwdev, virt_to_bus(ret))) {
/*
* The allocated memory isn't reachable by the device.
* Fall back on swiotlb_map_single().
@@ -465,22 +543,24 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
if (swiotlb_dma_mapping_error(handle))
return NULL;
- ret = phys_to_virt(handle);
+ ret = bus_to_virt(handle);
}
memset(ret, 0, size);
- dev_addr = virt_to_phys(ret);
+ dev_addr = virt_to_bus(ret);
/* Confirm address can be DMA'd by device */
if (address_needs_mapping(hwdev, dev_addr)) {
- printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016lx\n",
- (unsigned long long)*hwdev->dma_mask, dev_addr);
+ printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n",
+ (unsigned long long)*hwdev->dma_mask,
+ (unsigned long long)dev_addr);
panic("swiotlb_alloc_coherent: allocated memory is out of "
"range for device");
}
*dma_handle = dev_addr;
return ret;
}
+EXPORT_SYMBOL(swiotlb_alloc_coherent);
void
swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
@@ -493,6 +573,9 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
/* DMA_TO_DEVICE to avoid memcpy in unmap_single */
swiotlb_unmap_single (hwdev, dma_handle, size, DMA_TO_DEVICE);
}
+EXPORT_SYMBOL(swiotlb_free_coherent);
+
+#endif
static void
swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
@@ -504,7 +587,7 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
* When the mapping is small enough return a static buffer to limit
* the damage, or panic when the transfer is too big.
*/
- printk(KERN_ERR "DMA: Out of SW-IOMMU space for %lu bytes at "
+ printk(KERN_ERR "DMA: Out of SW-IOMMU space for %zu bytes at "
"device %s\n", size, dev ? dev->bus_id : "?");
if (size > io_tlb_overflow && do_panic) {
@@ -525,7 +608,7 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
dma_addr_t
swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
{
- unsigned long dev_addr = virt_to_phys(ptr);
+ dma_addr_t dev_addr = virt_to_bus(ptr);
void *map;
BUG_ON(dir == DMA_NONE);
@@ -534,19 +617,20 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
* we can safely return the device addr and not worry about bounce
* buffering it.
*/
- if (!address_needs_mapping(hwdev, dev_addr) && !swiotlb_force)
+ if (!range_needs_mapping(ptr, size)
+ && !address_needs_mapping(hwdev, dev_addr))
return dev_addr;
/*
* Oh well, have to allocate and map a bounce buffer.
*/
- map = map_single(hwdev, ptr, size, dir);
+ map = map_single(hwdev, ptr_to_io_tlb_addr(ptr), size, dir);
if (!map) {
swiotlb_full(hwdev, size, dir, 1);
map = io_tlb_overflow_buffer;
}
- dev_addr = virt_to_phys(map);
+ dev_addr = virt_to_bus(map);
/*
* Ensure that the address returned is DMA'ble
@@ -558,25 +642,6 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
}
/*
- * Since DMA is i-cache coherent, any (complete) pages that were written via
- * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
- * flush them when they get mapped into an executable vm-area.
- */
-static void
-mark_clean(void *addr, size_t size)
-{
- unsigned long pg_addr, end;
-
- pg_addr = PAGE_ALIGN((unsigned long) addr);
- end = (unsigned long) addr + size;
- while (pg_addr + PAGE_SIZE <= end) {
- struct page *page = virt_to_page(pg_addr);
- set_bit(PG_arch_1, &page->flags);
- pg_addr += PAGE_SIZE;
- }
-}
-
-/*
* Unmap a single streaming mode DMA translation. The dma_addr and size must
* match what was provided for in a previous swiotlb_map_single call. All
* other usages are undefined.
@@ -588,13 +653,13 @@ void
swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size,
int dir)
{
- char *dma_addr = phys_to_virt(dev_addr);
+ char *dma_addr = bus_to_virt(dev_addr);
BUG_ON(dir == DMA_NONE);
if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
unmap_single(hwdev, dma_addr, size, dir);
else if (dir == DMA_FROM_DEVICE)
- mark_clean(dma_addr, size);
+ dma_mark_clean(dma_addr, size);
}
/*
@@ -611,13 +676,13 @@ static inline void
swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
size_t size, int dir, int target)
{
- char *dma_addr = phys_to_virt(dev_addr);
+ char *dma_addr = bus_to_virt(dev_addr);
BUG_ON(dir == DMA_NONE);
if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
sync_single(hwdev, dma_addr, size, dir, target);
else if (dir == DMA_FROM_DEVICE)
- mark_clean(dma_addr, size);
+ dma_mark_clean(dma_addr, size);
}
void
@@ -642,13 +707,13 @@ swiotlb_sync_single_range(struct device *hwdev, dma_addr_t dev_addr,
unsigned long offset, size_t size,
int dir, int target)
{
- char *dma_addr = phys_to_virt(dev_addr) + offset;
+ char *dma_addr = bus_to_virt(dev_addr) + offset;
BUG_ON(dir == DMA_NONE);
if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
sync_single(hwdev, dma_addr, size, dir, target);
else if (dir == DMA_FROM_DEVICE)
- mark_clean(dma_addr, size);
+ dma_mark_clean(dma_addr, size);
}
void
@@ -687,18 +752,16 @@ int
swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
int dir)
{
- void *addr;
- unsigned long dev_addr;
+ dma_addr_t dev_addr;
int i;
BUG_ON(dir == DMA_NONE);
for (i = 0; i < nelems; i++, sg++) {
- addr = SG_ENT_VIRT_ADDRESS(sg);
- dev_addr = virt_to_phys(addr);
- if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) {
- void *map = map_single(hwdev, addr, sg->length, dir);
- sg->dma_address = virt_to_bus(map);
+ dev_addr = SG_ENT_PHYS_ADDRESS(sg);
+ if (range_needs_mapping(SG_ENT_VIRT_ADDRESS(sg), sg->length)
+ || address_needs_mapping(hwdev, dev_addr)) {
+ void *map = map_single(hwdev, sg_to_io_tlb_addr(sg), sg->length, dir);
if (!map) {
/* Don't panic here, we expect map_sg users
to do proper error handling. */
@@ -707,6 +770,7 @@ swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
sg[0].dma_length = 0;
return 0;
}
+ sg->dma_address = virt_to_bus(map);
} else
sg->dma_address = dev_addr;
sg->dma_length = sg->length;
@@ -728,9 +792,10 @@ swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
for (i = 0; i < nelems; i++, sg++)
if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
- unmap_single(hwdev, (void *) phys_to_virt(sg->dma_address), sg->dma_length, dir);
+ unmap_single(hwdev, bus_to_virt(sg->dma_address),
+ sg->dma_length, dir);
else if (dir == DMA_FROM_DEVICE)
- mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
+ dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
}
/*
@@ -750,8 +815,10 @@ swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sg,
for (i = 0; i < nelems; i++, sg++)
if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
- sync_single(hwdev, (void *) sg->dma_address,
+ sync_single(hwdev, bus_to_virt(sg->dma_address),
sg->dma_length, dir, target);
+ else if (dir == DMA_FROM_DEVICE)
+ dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
}
void
@@ -768,10 +835,48 @@ swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_DEVICE);
}
+#ifdef SWIOTLB_ARCH_NEED_MAP_PAGE
+
+dma_addr_t
+swiotlb_map_page(struct device *hwdev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ dma_addr_t dev_addr;
+ char *map;
+
+ dev_addr = page_to_bus(page) + offset;
+ if (address_needs_mapping(hwdev, dev_addr)) {
+ map = map_single(hwdev, page_to_io_tlb_addr(page, offset), size, direction);
+ if (!map) {
+ swiotlb_full(hwdev, size, direction, 1);
+ map = io_tlb_overflow_buffer;
+ }
+ dev_addr = virt_to_bus(map);
+ }
+
+ return dev_addr;
+}
+
+void
+swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
+ size_t size, enum dma_data_direction direction)
+{
+ char *dma_addr = bus_to_virt(dev_addr);
+
+ BUG_ON(direction == DMA_NONE);
+ if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
+ unmap_single(hwdev, dma_addr, size, direction);
+ else if (direction == DMA_FROM_DEVICE)
+ dma_mark_clean(dma_addr, size);
+}
+
+#endif
+
int
swiotlb_dma_mapping_error(dma_addr_t dma_addr)
{
- return (dma_addr == virt_to_phys(io_tlb_overflow_buffer));
+ return (dma_addr == virt_to_bus(io_tlb_overflow_buffer));
}
/*
@@ -780,10 +885,13 @@ swiotlb_dma_mapping_error(dma_addr_t dma_addr)
* during bus mastering, then you would pass 0x00ffffff as the mask to
* this function.
*/
+#ifndef __swiotlb_dma_supported
+#define __swiotlb_dma_supported(hwdev, mask) (virt_to_bus(io_tlb_end - 1) <= (mask))
+#endif
int
-swiotlb_dma_supported (struct device *hwdev, u64 mask)
+swiotlb_dma_supported(struct device *hwdev, u64 mask)
{
- return (virt_to_phys (io_tlb_end) - 1) <= mask;
+ return __swiotlb_dma_supported(hwdev, mask);
}
EXPORT_SYMBOL(swiotlb_init);
@@ -798,6 +906,4 @@ EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device);
EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu);
EXPORT_SYMBOL(swiotlb_sync_sg_for_device);
EXPORT_SYMBOL(swiotlb_dma_mapping_error);
-EXPORT_SYMBOL(swiotlb_alloc_coherent);
-EXPORT_SYMBOL(swiotlb_free_coherent);
EXPORT_SYMBOL(swiotlb_dma_supported);
diff --git a/mm/bounce.c b/mm/bounce.c
index e4b62d2a402..643efbe8240 100644
--- a/mm/bounce.c
+++ b/mm/bounce.c
@@ -237,6 +237,8 @@ static void __blk_queue_bounce(request_queue_t *q, struct bio **bio_orig,
if (!bio)
return;
+ blk_add_trace_bio(q, *bio_orig, BLK_TA_BOUNCE);
+
/*
* at least one page was bounced, fill in possible non-highmem
* pages
@@ -291,8 +293,6 @@ void blk_queue_bounce(request_queue_t *q, struct bio **bio_orig)
pool = isa_page_pool;
}
- blk_add_trace_bio(q, *bio_orig, BLK_TA_BOUNCE);
-
/*
* slow path
*/
diff --git a/mm/fadvise.c b/mm/fadvise.c
index 168c78a121b..0df4c899e97 100644
--- a/mm/fadvise.c
+++ b/mm/fadvise.c
@@ -38,7 +38,7 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
if (!file)
return -EBADF;
- if (S_ISFIFO(file->f_dentry->d_inode->i_mode)) {
+ if (S_ISFIFO(file->f_path.dentry->d_inode->i_mode)) {
ret = -ESPIPE;
goto out;
}
diff --git a/mm/filemap.c b/mm/filemap.c
index af7e2f5caea..f30ef28405d 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -606,26 +606,6 @@ struct page * find_get_page(struct address_space *mapping, unsigned long offset)
EXPORT_SYMBOL(find_get_page);
/**
- * find_trylock_page - find and lock a page
- * @mapping: the address_space to search
- * @offset: the page index
- *
- * Same as find_get_page(), but trylock it instead of incrementing the count.
- */
-struct page *find_trylock_page(struct address_space *mapping, unsigned long offset)
-{
- struct page *page;
-
- read_lock_irq(&mapping->tree_lock);
- page = radix_tree_lookup(&mapping->page_tree, offset);
- if (page && TestSetPageLocked(page))
- page = NULL;
- read_unlock_irq(&mapping->tree_lock);
- return page;
-}
-EXPORT_SYMBOL(find_trylock_page);
-
-/**
* find_lock_page - locate, pin and lock a pagecache page
* @mapping: the address_space to search
* @offset: the page index
@@ -1181,8 +1161,6 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
if (pos < size) {
retval = generic_file_direct_IO(READ, iocb,
iov, pos, nr_segs);
- if (retval > 0 && !is_sync_kiocb(iocb))
- retval = -EIOCBQUEUED;
if (retval > 0)
*ppos = pos + retval;
}
@@ -2047,15 +2025,14 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
* Sync the fs metadata but not the minor inode changes and
* of course not the data as we did direct DMA for the IO.
* i_mutex is held, which protects generic_osync_inode() from
- * livelocking.
+ * livelocking. AIO O_DIRECT ops attempt to sync metadata here.
*/
- if (written >= 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
+ if ((written >= 0 || written == -EIOCBQUEUED) &&
+ ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
int err = generic_osync_inode(inode, mapping, OSYNC_METADATA);
if (err < 0)
written = err;
}
- if (written == count && !is_sync_kiocb(iocb))
- written = -EIOCBQUEUED;
return written;
}
EXPORT_SYMBOL(generic_file_direct_write);
@@ -2269,7 +2246,7 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
if (count == 0)
goto out;
- err = remove_suid(file->f_dentry);
+ err = remove_suid(file->f_path.dentry);
if (err)
goto out;
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
index b4fd0d7c9bf..9dd9fbb7513 100644
--- a/mm/filemap_xip.c
+++ b/mm/filemap_xip.c
@@ -183,13 +183,13 @@ __xip_unmap (struct address_space * mapping,
address = vma->vm_start +
((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
BUG_ON(address < vma->vm_start || address >= vma->vm_end);
- page = ZERO_PAGE(address);
+ page = ZERO_PAGE(0);
pte = page_check_address(page, mm, address, &ptl);
if (pte) {
/* Nuke the page table entry. */
flush_cache_page(vma, address, pte_pfn(*pte));
pteval = ptep_clear_flush(vma, address, pte);
- page_remove_rmap(page);
+ page_remove_rmap(page, vma);
dec_mm_counter(mm, file_rss);
BUG_ON(pte_dirty(pteval));
pte_unmap_unlock(pte, ptl);
@@ -246,7 +246,7 @@ xip_file_nopage(struct vm_area_struct * area,
__xip_unmap(mapping, pgoff);
} else {
/* not shared and writable, use ZERO_PAGE() */
- page = ZERO_PAGE(address);
+ page = ZERO_PAGE(0);
}
out:
@@ -379,7 +379,7 @@ xip_file_write(struct file *filp, const char __user *buf, size_t len,
if (count == 0)
goto out_backing;
- ret = remove_suid(filp->f_dentry);
+ ret = remove_suid(filp->f_path.dentry);
if (ret)
goto out_backing;
diff --git a/mm/fremap.c b/mm/fremap.c
index b77a002c335..4e3f53dd5fd 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -33,7 +33,7 @@ static int zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
if (page) {
if (pte_dirty(pte))
set_page_dirty(page);
- page_remove_rmap(page);
+ page_remove_rmap(page, vma);
page_cache_release(page);
}
} else {
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 0ccc7f23025..36db012b38d 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -44,14 +44,14 @@ static void clear_huge_page(struct page *page, unsigned long addr)
}
static void copy_huge_page(struct page *dst, struct page *src,
- unsigned long addr)
+ unsigned long addr, struct vm_area_struct *vma)
{
int i;
might_sleep();
for (i = 0; i < HPAGE_SIZE/PAGE_SIZE; i++) {
cond_resched();
- copy_user_highpage(dst + i, src + i, addr + i*PAGE_SIZE);
+ copy_user_highpage(dst + i, src + i, addr + i*PAGE_SIZE, vma);
}
}
@@ -73,7 +73,7 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma,
for (z = zonelist->zones; *z; z++) {
nid = zone_to_nid(*z);
- if (cpuset_zone_allowed(*z, GFP_HIGHUSER) &&
+ if (cpuset_zone_allowed_softwall(*z, GFP_HIGHUSER) &&
!list_empty(&hugepage_freelists[nid]))
break;
}
@@ -389,6 +389,8 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
continue;
page = pte_page(pte);
+ if (pte_dirty(pte))
+ set_page_dirty(page);
list_add(&page->lru, &page_list);
}
spin_unlock(&mm->page_table_lock);
@@ -442,7 +444,7 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
}
spin_unlock(&mm->page_table_lock);
- copy_huge_page(new_page, old_page, address);
+ copy_huge_page(new_page, old_page, address, vma);
spin_lock(&mm->page_table_lock);
ptep = huge_pte_offset(mm, address & HPAGE_MASK);
diff --git a/mm/memory.c b/mm/memory.c
index 4198df0dff1..ef09f0acb1d 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -681,7 +681,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
mark_page_accessed(page);
file_rss--;
}
- page_remove_rmap(page);
+ page_remove_rmap(page, vma);
tlb_remove_page(tlb, page);
continue;
}
@@ -1091,7 +1091,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
if (pages) {
pages[i] = page;
- flush_anon_page(page, start);
+ flush_anon_page(vma, page, start);
flush_dcache_page(page);
}
if (vmas)
@@ -1110,23 +1110,29 @@ static int zeromap_pte_range(struct mm_struct *mm, pmd_t *pmd,
{
pte_t *pte;
spinlock_t *ptl;
+ int err = 0;
pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
if (!pte)
- return -ENOMEM;
+ return -EAGAIN;
arch_enter_lazy_mmu_mode();
do {
struct page *page = ZERO_PAGE(addr);
pte_t zero_pte = pte_wrprotect(mk_pte(page, prot));
+
+ if (unlikely(!pte_none(*pte))) {
+ err = -EEXIST;
+ pte++;
+ break;
+ }
page_cache_get(page);
page_add_file_rmap(page);
inc_mm_counter(mm, file_rss);
- 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;
+ return err;
}
static inline int zeromap_pmd_range(struct mm_struct *mm, pud_t *pud,
@@ -1134,16 +1140,18 @@ static inline int zeromap_pmd_range(struct mm_struct *mm, pud_t *pud,
{
pmd_t *pmd;
unsigned long next;
+ int err;
pmd = pmd_alloc(mm, pud, addr);
if (!pmd)
- return -ENOMEM;
+ return -EAGAIN;
do {
next = pmd_addr_end(addr, end);
- if (zeromap_pte_range(mm, pmd, addr, next, prot))
- return -ENOMEM;
+ err = zeromap_pte_range(mm, pmd, addr, next, prot);
+ if (err)
+ break;
} while (pmd++, addr = next, addr != end);
- return 0;
+ return err;
}
static inline int zeromap_pud_range(struct mm_struct *mm, pgd_t *pgd,
@@ -1151,16 +1159,18 @@ static inline int zeromap_pud_range(struct mm_struct *mm, pgd_t *pgd,
{
pud_t *pud;
unsigned long next;
+ int err;
pud = pud_alloc(mm, pgd, addr);
if (!pud)
- return -ENOMEM;
+ return -EAGAIN;
do {
next = pud_addr_end(addr, end);
- if (zeromap_pmd_range(mm, pud, addr, next, prot))
- return -ENOMEM;
+ err = zeromap_pmd_range(mm, pud, addr, next, prot);
+ if (err)
+ break;
} while (pud++, addr = next, addr != end);
- return 0;
+ return err;
}
int zeromap_page_range(struct vm_area_struct *vma,
@@ -1431,7 +1441,7 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
return pte;
}
-static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va)
+static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va, struct vm_area_struct *vma)
{
/*
* If the source page was a PFN mapping, we don't have
@@ -1454,9 +1464,9 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo
kunmap_atomic(kaddr, KM_USER0);
flush_dcache_page(dst);
return;
-
+
}
- copy_user_highpage(dst, src, va);
+ copy_user_highpage(dst, src, va, vma);
}
/*
@@ -1567,7 +1577,7 @@ gotten:
new_page = alloc_page_vma(GFP_HIGHUSER, vma, address);
if (!new_page)
goto oom;
- cow_user_page(new_page, old_page, address);
+ cow_user_page(new_page, old_page, address, vma);
}
/*
@@ -1576,7 +1586,7 @@ gotten:
page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
if (likely(pte_same(*page_table, orig_pte))) {
if (old_page) {
- page_remove_rmap(old_page);
+ page_remove_rmap(old_page, vma);
if (!PageAnon(old_page)) {
dec_mm_counter(mm, file_rss);
inc_mm_counter(mm, anon_rss);
@@ -2190,7 +2200,7 @@ retry:
page = alloc_page_vma(GFP_HIGHUSER, vma, address);
if (!page)
goto oom;
- copy_user_highpage(page, new_page, address);
+ copy_user_highpage(page, new_page, address, vma);
page_cache_release(new_page);
new_page = page;
anon = 1;
@@ -2596,8 +2606,15 @@ static int __init gate_vma_init(void)
gate_vma.vm_mm = NULL;
gate_vma.vm_start = FIXADDR_USER_START;
gate_vma.vm_end = FIXADDR_USER_END;
- gate_vma.vm_page_prot = PAGE_READONLY;
- gate_vma.vm_flags = 0;
+ gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
+ gate_vma.vm_page_prot = __P101;
+ /*
+ * Make sure the vDSO gets into every core dump.
+ * Dumping its contents makes post-mortem fully interpretable later
+ * without matching up the same kernel and hardware config to see
+ * what PC values meant.
+ */
+ gate_vma.vm_flags |= VM_ALWAYSDUMP;
return 0;
}
__initcall(gate_vma_init);
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 0c055a090f4..84279127fcd 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -67,11 +67,13 @@ static int __add_zone(struct zone *zone, unsigned long phys_start_pfn)
zone_type = zone - pgdat->node_zones;
if (!populated_zone(zone)) {
int ret = 0;
- ret = init_currently_empty_zone(zone, phys_start_pfn, nr_pages);
+ ret = init_currently_empty_zone(zone, phys_start_pfn,
+ nr_pages, MEMMAP_HOTPLUG);
if (ret < 0)
return ret;
}
- memmap_init_zone(nr_pages, nid, zone_type, phys_start_pfn);
+ memmap_init_zone(nr_pages, nid, zone_type,
+ phys_start_pfn, MEMMAP_HOTPLUG);
return 0;
}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index b917d6fdc1b..c2aec0e1090 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -884,6 +884,10 @@ asmlinkage long sys_mbind(unsigned long start, unsigned long len,
err = get_nodes(&nodes, nmask, maxnode);
if (err)
return err;
+#ifdef CONFIG_CPUSETS
+ /* Restrict the nodes to the allowed nodes in the cpuset */
+ nodes_and(nodes, nodes, current->mems_allowed);
+#endif
return do_mbind(start, len, mode, &nodes, flags);
}
@@ -1857,7 +1861,7 @@ int show_numa_map(struct seq_file *m, void *v)
if (file) {
seq_printf(m, " file=");
- seq_path(m, file->f_vfsmnt, file->f_dentry, "\n\t= ");
+ seq_path(m, file->f_path.mnt, file->f_path.dentry, "\n\t= ");
} else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
seq_printf(m, " heap");
} else if (vma->vm_start <= mm->start_stack &&
diff --git a/mm/mincore.c b/mm/mincore.c
index 72890780c1c..8aca6f7167b 100644
--- a/mm/mincore.c
+++ b/mm/mincore.c
@@ -1,7 +1,7 @@
/*
* linux/mm/mincore.c
*
- * Copyright (C) 1994-1999 Linus Torvalds
+ * Copyright (C) 1994-2006 Linus Torvalds
*/
/*
@@ -38,46 +38,51 @@ static unsigned char mincore_page(struct vm_area_struct * vma,
return present;
}
-static long mincore_vma(struct vm_area_struct * vma,
- unsigned long start, unsigned long end, unsigned char __user * vec)
+/*
+ * Do a chunk of "sys_mincore()". We've already checked
+ * all the arguments, we hold the mmap semaphore: we should
+ * just return the amount of info we're asked for.
+ */
+static long do_mincore(unsigned long addr, unsigned char *vec, unsigned long pages)
{
- long error, i, remaining;
- unsigned char * tmp;
-
- error = -ENOMEM;
- if (!vma->vm_file)
- return error;
-
- start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
- if (end > vma->vm_end)
- end = vma->vm_end;
- end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+ unsigned long i, nr, pgoff;
+ struct vm_area_struct *vma = find_vma(current->mm, addr);
- error = -EAGAIN;
- tmp = (unsigned char *) __get_free_page(GFP_KERNEL);
- if (!tmp)
- return error;
+ /*
+ * find_vma() didn't find anything above us, or we're
+ * in an unmapped hole in the address space: ENOMEM.
+ */
+ if (!vma || addr < vma->vm_start)
+ return -ENOMEM;
- /* (end - start) is # of pages, and also # of bytes in "vec */
- remaining = (end - start),
+ /*
+ * Ok, got it. But check whether it's a segment we support
+ * mincore() on. Right now, we don't do any anonymous mappings.
+ *
+ * FIXME: This is just stupid. And returning ENOMEM is
+ * stupid too. We should just look at the page tables. But
+ * this is what we've traditionally done, so we'll just
+ * continue doing it.
+ */
+ if (!vma->vm_file)
+ return -ENOMEM;
- error = 0;
- for (i = 0; remaining > 0; remaining -= PAGE_SIZE, i++) {
- int j = 0;
- long thispiece = (remaining < PAGE_SIZE) ?
- remaining : PAGE_SIZE;
+ /*
+ * Calculate how many pages there are left in the vma, and
+ * what the pgoff is for our address.
+ */
+ nr = (vma->vm_end - addr) >> PAGE_SHIFT;
+ if (nr > pages)
+ nr = pages;
- while (j < thispiece)
- tmp[j++] = mincore_page(vma, start++);
+ pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
+ pgoff += vma->vm_pgoff;
- if (copy_to_user(vec + PAGE_SIZE * i, tmp, thispiece)) {
- error = -EFAULT;
- break;
- }
- }
+ /* And then we just fill the sucker in.. */
+ for (i = 0 ; i < nr; i++, pgoff++)
+ vec[i] = mincore_page(vma, pgoff);
- free_page((unsigned long) tmp);
- return error;
+ return nr;
}
/*
@@ -107,82 +112,50 @@ static long mincore_vma(struct vm_area_struct * vma,
asmlinkage long sys_mincore(unsigned long start, size_t len,
unsigned char __user * vec)
{
- int index = 0;
- unsigned long end, limit;
- struct vm_area_struct * vma;
- size_t max;
- int unmapped_error = 0;
- long error;
-
- /* check the arguments */
- if (start & ~PAGE_CACHE_MASK)
- goto einval;
-
- limit = TASK_SIZE;
- if (start >= limit)
- goto enomem;
-
- if (!len)
- return 0;
-
- max = limit - start;
- len = PAGE_CACHE_ALIGN(len);
- if (len > max || !len)
- goto enomem;
+ long retval;
+ unsigned long pages;
+ unsigned char *tmp;
- end = start + len;
+ /* Check the start address: needs to be page-aligned.. */
+ if (start & ~PAGE_CACHE_MASK)
+ return -EINVAL;
- /* check the output buffer whilst holding the lock */
- error = -EFAULT;
- down_read(&current->mm->mmap_sem);
+ /* ..and we need to be passed a valid user-space range */
+ if (!access_ok(VERIFY_READ, (void __user *) start, len))
+ return -ENOMEM;
- if (!access_ok(VERIFY_WRITE, vec, len >> PAGE_SHIFT))
- goto out;
+ /* This also avoids any overflows on PAGE_CACHE_ALIGN */
+ pages = len >> PAGE_SHIFT;
+ pages += (len & ~PAGE_MASK) != 0;
- /*
- * If the interval [start,end) covers some unmapped address
- * ranges, just ignore them, but return -ENOMEM at the end.
- */
- error = 0;
-
- vma = find_vma(current->mm, start);
- while (vma) {
- /* Here start < vma->vm_end. */
- if (start < vma->vm_start) {
- unmapped_error = -ENOMEM;
- start = vma->vm_start;
- }
+ if (!access_ok(VERIFY_WRITE, vec, pages))
+ return -EFAULT;
- /* Here vma->vm_start <= start < vma->vm_end. */
- if (end <= vma->vm_end) {
- if (start < end) {
- error = mincore_vma(vma, start, end,
- &vec[index]);
- if (error)
- goto out;
- }
- error = unmapped_error;
- goto out;
+ tmp = (void *) __get_free_page(GFP_USER);
+ if (!tmp)
+ return -EAGAIN;
+
+ retval = 0;
+ while (pages) {
+ /*
+ * Do at most PAGE_SIZE entries per iteration, due to
+ * the temporary buffer size.
+ */
+ down_read(&current->mm->mmap_sem);
+ retval = do_mincore(start, tmp, min(pages, PAGE_SIZE));
+ up_read(&current->mm->mmap_sem);
+
+ if (retval <= 0)
+ break;
+ if (copy_to_user(vec, tmp, retval)) {
+ retval = -EFAULT;
+ break;
}
-
- /* Here vma->vm_start <= start < vma->vm_end < end. */
- error = mincore_vma(vma, start, vma->vm_end, &vec[index]);
- if (error)
- goto out;
- index += (vma->vm_end - start) >> PAGE_CACHE_SHIFT;
- start = vma->vm_end;
- vma = vma->vm_next;
+ pages -= retval;
+ vec += retval;
+ start += retval << PAGE_SHIFT;
+ retval = 0;
}
-
- /* we found a hole in the area queried if we arrive here */
- error = -ENOMEM;
-
-out:
- up_read(&current->mm->mmap_sem);
- return error;
-
-einval:
- return -EINVAL;
-enomem:
- return -ENOMEM;
+ free_page((unsigned long) tmp);
+ return retval;
}
diff --git a/mm/mmap.c b/mm/mmap.c
index 7be110e98d4..eb509ae7655 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -188,7 +188,7 @@ static void __remove_shared_vm_struct(struct vm_area_struct *vma,
struct file *file, struct address_space *mapping)
{
if (vma->vm_flags & VM_DENYWRITE)
- atomic_inc(&file->f_dentry->d_inode->i_writecount);
+ atomic_inc(&file->f_path.dentry->d_inode->i_writecount);
if (vma->vm_flags & VM_SHARED)
mapping->i_mmap_writable--;
@@ -399,7 +399,7 @@ static inline void __vma_link_file(struct vm_area_struct *vma)
struct address_space *mapping = file->f_mapping;
if (vma->vm_flags & VM_DENYWRITE)
- atomic_dec(&file->f_dentry->d_inode->i_writecount);
+ atomic_dec(&file->f_path.dentry->d_inode->i_writecount);
if (vma->vm_flags & VM_SHARED)
mapping->i_mmap_writable++;
@@ -907,7 +907,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
* mounted, in which case we dont add PROT_EXEC.)
*/
if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
- if (!(file && (file->f_vfsmnt->mnt_flags & MNT_NOEXEC)))
+ if (!(file && (file->f_path.mnt->mnt_flags & MNT_NOEXEC)))
prot |= PROT_EXEC;
if (!len)
@@ -960,7 +960,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
return -EAGAIN;
}
- inode = file ? file->f_dentry->d_inode : NULL;
+ inode = file ? file->f_path.dentry->d_inode : NULL;
if (file) {
switch (flags & MAP_TYPE) {
@@ -989,7 +989,7 @@ 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 (file->f_path.mnt->mnt_flags & MNT_NOEXEC) {
if (vm_flags & VM_EXEC)
return -EPERM;
vm_flags &= ~VM_MAYEXEC;
@@ -1477,6 +1477,7 @@ static int acct_stack_growth(struct vm_area_struct * vma, unsigned long size, un
{
struct mm_struct *mm = vma->vm_mm;
struct rlimit *rlim = current->signal->rlim;
+ unsigned long new_start;
/* address space limit tests */
if (!may_expand_vm(mm, grow))
@@ -1496,6 +1497,12 @@ static int acct_stack_growth(struct vm_area_struct * vma, unsigned long size, un
return -ENOMEM;
}
+ /* Check to ensure the stack will not grow into a hugetlb-only region */
+ new_start = (vma->vm_flags & VM_GROWSUP) ? vma->vm_start :
+ vma->vm_end - size;
+ if (is_hugepage_only_range(vma->vm_mm, new_start, size))
+ return -EFAULT;
+
/*
* Overcommit.. This must be the final test, as it will
* update security statistics.
@@ -2094,3 +2101,75 @@ int may_expand_vm(struct mm_struct *mm, unsigned long npages)
return 0;
return 1;
}
+
+
+static struct page *special_mapping_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ struct page **pages;
+
+ BUG_ON(address < vma->vm_start || address >= vma->vm_end);
+
+ address -= vma->vm_start;
+ for (pages = vma->vm_private_data; address > 0 && *pages; ++pages)
+ address -= PAGE_SIZE;
+
+ if (*pages) {
+ struct page *page = *pages;
+ get_page(page);
+ return page;
+ }
+
+ return NOPAGE_SIGBUS;
+}
+
+/*
+ * Having a close hook prevents vma merging regardless of flags.
+ */
+static void special_mapping_close(struct vm_area_struct *vma)
+{
+}
+
+static struct vm_operations_struct special_mapping_vmops = {
+ .close = special_mapping_close,
+ .nopage = special_mapping_nopage,
+};
+
+/*
+ * Called with mm->mmap_sem held for writing.
+ * Insert a new vma covering the given region, with the given flags.
+ * Its pages are supplied by the given array of struct page *.
+ * The array can be shorter than len >> PAGE_SHIFT if it's null-terminated.
+ * The region past the last page supplied will always produce SIGBUS.
+ * The array pointer and the pages it points to are assumed to stay alive
+ * for as long as this mapping might exist.
+ */
+int install_special_mapping(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long vm_flags, struct page **pages)
+{
+ struct vm_area_struct *vma;
+
+ vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
+ if (unlikely(vma == NULL))
+ return -ENOMEM;
+
+ vma->vm_mm = mm;
+ vma->vm_start = addr;
+ vma->vm_end = addr + len;
+
+ vma->vm_flags = vm_flags | mm->def_flags;
+ vma->vm_page_prot = protection_map[vma->vm_flags & 7];
+
+ vma->vm_ops = &special_mapping_vmops;
+ vma->vm_private_data = pages;
+
+ if (unlikely(insert_vm_struct(mm, vma))) {
+ kmem_cache_free(vm_area_cachep, vma);
+ return -ENOMEM;
+ }
+
+ mm->total_vm += len >> PAGE_SHIFT;
+
+ return 0;
+}
diff --git a/mm/mremap.c b/mm/mremap.c
index 9c769fa29f3..5d4bd4f95b8 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -105,7 +105,6 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
if (pte_none(*old_pte))
continue;
pte = ptep_clear_flush(vma, old_addr, old_pte);
- /* ZERO_PAGE can be dependant on virtual addr */
pte = move_pte(pte, new_vma->vm_page_prot, old_addr, new_addr);
set_pte_at(mm, new_addr, new_pte, pte);
}
diff --git a/mm/nommu.c b/mm/nommu.c
index af874569d0f..23fb033e596 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -523,7 +523,7 @@ static int validate_mmap_request(struct file *file,
*/
mapping = file->f_mapping;
if (!mapping)
- mapping = file->f_dentry->d_inode->i_mapping;
+ mapping = file->f_path.dentry->d_inode->i_mapping;
capabilities = 0;
if (mapping && mapping->backing_dev_info)
@@ -532,7 +532,7 @@ static int validate_mmap_request(struct file *file,
if (!capabilities) {
/* no explicit capabilities set, so assume some
* defaults */
- switch (file->f_dentry->d_inode->i_mode & S_IFMT) {
+ switch (file->f_path.dentry->d_inode->i_mode & S_IFMT) {
case S_IFREG:
case S_IFBLK:
capabilities = BDI_CAP_MAP_COPY;
@@ -563,11 +563,11 @@ static int validate_mmap_request(struct file *file,
!(file->f_mode & FMODE_WRITE))
return -EACCES;
- if (IS_APPEND(file->f_dentry->d_inode) &&
+ if (IS_APPEND(file->f_path.dentry->d_inode) &&
(file->f_mode & FMODE_WRITE))
return -EACCES;
- if (locks_verify_locked(file->f_dentry->d_inode))
+ if (locks_verify_locked(file->f_path.dentry->d_inode))
return -EAGAIN;
if (!(capabilities & BDI_CAP_MAP_DIRECT))
@@ -598,7 +598,7 @@ static int validate_mmap_request(struct file *file,
/* handle executable mappings and implied executable
* mappings */
- if (file->f_vfsmnt->mnt_flags & MNT_NOEXEC) {
+ if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) {
if (prot & PROT_EXEC)
return -EPERM;
}
@@ -833,7 +833,7 @@ unsigned long do_mmap_pgoff(struct file *file,
continue;
/* search for overlapping mappings on the same file */
- if (vma->vm_file->f_dentry->d_inode != file->f_dentry->d_inode)
+ if (vma->vm_file->f_path.dentry->d_inode != file->f_path.dentry->d_inode)
continue;
if (vma->vm_pgoff >= pgoff + pglen)
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 223d9ccb7d6..b278b8d60ee 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -61,12 +61,6 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
}
/*
- * swapoff can easily use up all memory, so kill those first.
- */
- if (p->flags & PF_SWAPOFF)
- return ULONG_MAX;
-
- /*
* The memory size of the process is the basis for the badness.
*/
points = mm->total_vm;
@@ -77,6 +71,12 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
task_unlock(p);
/*
+ * swapoff can easily use up all memory, so kill those first.
+ */
+ if (p->flags & PF_SWAPOFF)
+ return ULONG_MAX;
+
+ /*
* Processes which fork a lot of child processes are likely
* a good choice. We add half the vmsize of the children if they
* have an own mm. This prevents forking servers to flood the
@@ -174,10 +174,15 @@ static inline int constrained_alloc(struct zonelist *zonelist, gfp_t gfp_mask)
{
#ifdef CONFIG_NUMA
struct zone **z;
- nodemask_t nodes = node_online_map;
+ nodemask_t nodes;
+ int node;
+ /* node has memory ? */
+ for_each_online_node(node)
+ if (NODE_DATA(node)->node_present_pages)
+ node_set(node, nodes);
for (z = zonelist->zones; *z; z++)
- if (cpuset_zone_allowed(*z, gfp_mask))
+ if (cpuset_zone_allowed_softwall(*z, gfp_mask))
node_clear(zone_to_nid(*z), nodes);
else
return CONSTRAINT_CPUSET;
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 8d9b19f239c..be0efbde499 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -21,6 +21,7 @@
#include <linux/writeback.h>
#include <linux/init.h>
#include <linux/backing-dev.h>
+#include <linux/task_io_accounting_ops.h>
#include <linux/blkdev.h>
#include <linux/mpage.h>
#include <linux/rmap.h>
@@ -132,11 +133,9 @@ get_dirty_limits(long *pbackground, long *pdirty,
#ifdef CONFIG_HIGHMEM
/*
- * If this mapping can only allocate from low memory,
- * we exclude high memory from our count.
+ * We always exclude high memory from our count.
*/
- if (mapping && !(mapping_gfp_mask(mapping) & __GFP_HIGHMEM))
- available_memory -= totalhigh_pages;
+ available_memory -= totalhigh_pages;
#endif
@@ -525,28 +524,25 @@ static struct notifier_block __cpuinitdata ratelimit_nb = {
};
/*
- * If the machine has a large highmem:lowmem ratio then scale back the default
- * dirty memory thresholds: allowing too much dirty highmem pins an excessive
- * number of buffer_heads.
+ * Called early on to tune the page writeback dirty limits.
+ *
+ * We used to scale dirty pages according to how total memory
+ * related to pages that could be allocated for buffers (by
+ * comparing nr_free_buffer_pages() to vm_total_pages.
+ *
+ * However, that was when we used "dirty_ratio" to scale with
+ * all memory, and we don't do that any more. "dirty_ratio"
+ * is now applied to total non-HIGHPAGE memory (by subtracting
+ * totalhigh_pages from vm_total_pages), and as such we can't
+ * get into the old insane situation any more where we had
+ * large amounts of dirty pages compared to a small amount of
+ * non-HIGHMEM memory.
+ *
+ * But we might still want to scale the dirty_ratio by how
+ * much memory the box has..
*/
void __init page_writeback_init(void)
{
- long buffer_pages = nr_free_buffer_pages();
- long correction;
-
- correction = (100 * 4 * buffer_pages) / vm_total_pages;
-
- if (correction < 100) {
- dirty_background_ratio *= correction;
- dirty_background_ratio /= 100;
- vm_dirty_ratio *= correction;
- vm_dirty_ratio /= 100;
-
- if (dirty_background_ratio <= 0)
- dirty_background_ratio = 1;
- if (vm_dirty_ratio <= 0)
- vm_dirty_ratio = 1;
- }
mod_timer(&wb_timer, jiffies + dirty_writeback_interval);
writeback_set_ratelimit();
register_cpu_notifier(&ratelimit_nb);
@@ -761,23 +757,24 @@ int __set_page_dirty_nobuffers(struct page *page)
struct address_space *mapping = page_mapping(page);
struct address_space *mapping2;
- if (mapping) {
- write_lock_irq(&mapping->tree_lock);
- mapping2 = page_mapping(page);
- if (mapping2) { /* Race with truncate? */
- BUG_ON(mapping2 != mapping);
- if (mapping_cap_account_dirty(mapping))
- __inc_zone_page_state(page,
- NR_FILE_DIRTY);
- radix_tree_tag_set(&mapping->page_tree,
- page_index(page), PAGECACHE_TAG_DIRTY);
- }
- write_unlock_irq(&mapping->tree_lock);
- if (mapping->host) {
- /* !PageAnon && !swapper_space */
- __mark_inode_dirty(mapping->host,
- I_DIRTY_PAGES);
+ if (!mapping)
+ return 1;
+
+ write_lock_irq(&mapping->tree_lock);
+ mapping2 = page_mapping(page);
+ if (mapping2) { /* Race with truncate? */
+ BUG_ON(mapping2 != mapping);
+ if (mapping_cap_account_dirty(mapping)) {
+ __inc_zone_page_state(page, NR_FILE_DIRTY);
+ task_io_account_write(PAGE_CACHE_SIZE);
}
+ radix_tree_tag_set(&mapping->page_tree,
+ page_index(page), PAGECACHE_TAG_DIRTY);
+ }
+ write_unlock_irq(&mapping->tree_lock);
+ if (mapping->host) {
+ /* !PageAnon && !swapper_space */
+ __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
}
return 1;
}
@@ -843,39 +840,6 @@ int set_page_dirty_lock(struct page *page)
EXPORT_SYMBOL(set_page_dirty_lock);
/*
- * Clear a page's dirty flag, while caring for dirty memory accounting.
- * Returns true if the page was previously dirty.
- */
-int test_clear_page_dirty(struct page *page)
-{
- struct address_space *mapping = page_mapping(page);
- unsigned long flags;
-
- if (mapping) {
- write_lock_irqsave(&mapping->tree_lock, flags);
- if (TestClearPageDirty(page)) {
- radix_tree_tag_clear(&mapping->page_tree,
- page_index(page),
- PAGECACHE_TAG_DIRTY);
- write_unlock_irqrestore(&mapping->tree_lock, flags);
- /*
- * We can continue to use `mapping' here because the
- * page is locked, which pins the address_space
- */
- if (mapping_cap_account_dirty(mapping)) {
- page_mkclean(page);
- dec_zone_page_state(page, NR_FILE_DIRTY);
- }
- return 1;
- }
- write_unlock_irqrestore(&mapping->tree_lock, flags);
- return 0;
- }
- return TestClearPageDirty(page);
-}
-EXPORT_SYMBOL(test_clear_page_dirty);
-
-/*
* Clear a page's dirty flag, while caring for dirty memory accounting.
* Returns true if the page was previously dirty.
*
@@ -893,12 +857,41 @@ int clear_page_dirty_for_io(struct page *page)
{
struct address_space *mapping = page_mapping(page);
- if (mapping) {
+ if (mapping && mapping_cap_account_dirty(mapping)) {
+ /*
+ * Yes, Virginia, this is indeed insane.
+ *
+ * We use this sequence to make sure that
+ * (a) we account for dirty stats properly
+ * (b) we tell the low-level filesystem to
+ * mark the whole page dirty if it was
+ * dirty in a pagetable. Only to then
+ * (c) clean the page again and return 1 to
+ * cause the writeback.
+ *
+ * This way we avoid all nasty races with the
+ * dirty bit in multiple places and clearing
+ * them concurrently from different threads.
+ *
+ * Note! Normally the "set_page_dirty(page)"
+ * has no effect on the actual dirty bit - since
+ * that will already usually be set. But we
+ * need the side effects, and it can help us
+ * avoid races.
+ *
+ * We basically use the page "master dirty bit"
+ * as a serialization point for all the different
+ * threads doing their things.
+ *
+ * FIXME! We still have a race here: if somebody
+ * adds the page back to the page tables in
+ * between the "page_mkclean()" and the "TestClearPageDirty()",
+ * we might have it mapped without the dirty bit set.
+ */
+ if (page_mkclean(page))
+ set_page_dirty(page);
if (TestClearPageDirty(page)) {
- if (mapping_cap_account_dirty(mapping)) {
- page_mkclean(page);
- dec_zone_page_state(page, NR_FILE_DIRTY);
- }
+ dec_zone_page_state(page, NR_FILE_DIRTY);
return 1;
}
return 0;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index cace22b3ac2..f12052dc23f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -40,6 +40,7 @@
#include <linux/sort.h>
#include <linux/pfn.h>
#include <linux/backing-dev.h>
+#include <linux/fault-inject.h>
#include <asm/tlbflush.h>
#include <asm/div64.h>
@@ -710,6 +711,9 @@ static void __drain_pages(unsigned int cpu)
for_each_zone(zone) {
struct per_cpu_pageset *pset;
+ if (!populated_zone(zone))
+ continue;
+
pset = zone_pcp(zone, cpu);
for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
struct per_cpu_pages *pcp;
@@ -892,6 +896,91 @@ failed:
#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */
#define ALLOC_CPUSET 0x40 /* check for correct cpuset */
+#ifdef CONFIG_FAIL_PAGE_ALLOC
+
+static struct fail_page_alloc_attr {
+ struct fault_attr attr;
+
+ u32 ignore_gfp_highmem;
+ u32 ignore_gfp_wait;
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+ struct dentry *ignore_gfp_highmem_file;
+ struct dentry *ignore_gfp_wait_file;
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+} fail_page_alloc = {
+ .attr = FAULT_ATTR_INITIALIZER,
+ .ignore_gfp_wait = 1,
+ .ignore_gfp_highmem = 1,
+};
+
+static int __init setup_fail_page_alloc(char *str)
+{
+ return setup_fault_attr(&fail_page_alloc.attr, str);
+}
+__setup("fail_page_alloc=", setup_fail_page_alloc);
+
+static int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
+{
+ if (gfp_mask & __GFP_NOFAIL)
+ return 0;
+ if (fail_page_alloc.ignore_gfp_highmem && (gfp_mask & __GFP_HIGHMEM))
+ return 0;
+ if (fail_page_alloc.ignore_gfp_wait && (gfp_mask & __GFP_WAIT))
+ return 0;
+
+ return should_fail(&fail_page_alloc.attr, 1 << order);
+}
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+static int __init fail_page_alloc_debugfs(void)
+{
+ mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+ struct dentry *dir;
+ int err;
+
+ err = init_fault_attr_dentries(&fail_page_alloc.attr,
+ "fail_page_alloc");
+ if (err)
+ return err;
+ dir = fail_page_alloc.attr.dentries.dir;
+
+ fail_page_alloc.ignore_gfp_wait_file =
+ debugfs_create_bool("ignore-gfp-wait", mode, dir,
+ &fail_page_alloc.ignore_gfp_wait);
+
+ fail_page_alloc.ignore_gfp_highmem_file =
+ debugfs_create_bool("ignore-gfp-highmem", mode, dir,
+ &fail_page_alloc.ignore_gfp_highmem);
+
+ if (!fail_page_alloc.ignore_gfp_wait_file ||
+ !fail_page_alloc.ignore_gfp_highmem_file) {
+ err = -ENOMEM;
+ debugfs_remove(fail_page_alloc.ignore_gfp_wait_file);
+ debugfs_remove(fail_page_alloc.ignore_gfp_highmem_file);
+ cleanup_fault_attr_dentries(&fail_page_alloc.attr);
+ }
+
+ return err;
+}
+
+late_initcall(fail_page_alloc_debugfs);
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+#else /* CONFIG_FAIL_PAGE_ALLOC */
+
+static inline int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
+{
+ return 0;
+}
+
+#endif /* CONFIG_FAIL_PAGE_ALLOC */
+
/*
* Return 1 if free pages are above 'mark'. This takes into account the order
* of the allocation.
@@ -900,8 +989,7 @@ 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 */
- unsigned long min = mark;
- long free_pages = z->free_pages - (1 << order) + 1;
+ long min = mark, free_pages = z->free_pages - (1 << order) + 1;
int o;
if (alloc_flags & ALLOC_HIGH)
@@ -1076,7 +1164,7 @@ zonelist_scan:
zone->zone_pgdat != zonelist->zones[0]->zone_pgdat))
break;
if ((alloc_flags & ALLOC_CPUSET) &&
- !cpuset_zone_allowed(zone, gfp_mask))
+ !cpuset_zone_allowed_softwall(zone, gfp_mask))
goto try_next_zone;
if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
@@ -1136,6 +1224,9 @@ __alloc_pages(gfp_t gfp_mask, unsigned int order,
might_sleep_if(wait);
+ if (should_fail_alloc_page(gfp_mask, order))
+ return NULL;
+
restart:
z = zonelist->zones; /* the list of zones suitable for gfp_mask */
@@ -1488,8 +1579,8 @@ void show_free_areas(void)
get_zone_counts(&active, &inactive, &free);
- printk("Active:%lu inactive:%lu dirty:%lu writeback:%lu "
- "unstable:%lu free:%u slab:%lu mapped:%lu pagetables:%lu\n",
+ printk("Active:%lu inactive:%lu dirty:%lu writeback:%lu unstable:%lu\n"
+ " free:%u slab:%lu mapped:%lu pagetables:%lu bounce:%lu\n",
active,
inactive,
global_page_state(NR_FILE_DIRTY),
@@ -1499,7 +1590,8 @@ void show_free_areas(void)
global_page_state(NR_SLAB_RECLAIMABLE) +
global_page_state(NR_SLAB_UNRECLAIMABLE),
global_page_state(NR_FILE_MAPPED),
- global_page_state(NR_PAGETABLE));
+ global_page_state(NR_PAGETABLE),
+ global_page_state(NR_BOUNCE));
for_each_zone(zone) {
int i;
@@ -1864,17 +1956,24 @@ static inline unsigned long wait_table_bits(unsigned long size)
* done. Non-atomic initialization, single-pass.
*/
void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
- unsigned long start_pfn)
+ unsigned long start_pfn, enum memmap_context context)
{
struct page *page;
unsigned long end_pfn = start_pfn + size;
unsigned long pfn;
for (pfn = start_pfn; pfn < end_pfn; pfn++) {
- if (!early_pfn_valid(pfn))
- continue;
- if (!early_pfn_in_nid(pfn, nid))
- continue;
+ /*
+ * There can be holes in boot-time mem_map[]s
+ * handed to this function. They do not
+ * exist on hotplugged memory.
+ */
+ if (context == MEMMAP_EARLY) {
+ 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);
@@ -1901,7 +2000,7 @@ void zone_init_free_lists(struct pglist_data *pgdat, struct zone *zone,
#ifndef __HAVE_ARCH_MEMMAP_INIT
#define memmap_init(size, nid, zone, start_pfn) \
- memmap_init_zone((size), (nid), (zone), (start_pfn))
+ memmap_init_zone((size), (nid), (zone), (start_pfn), MEMMAP_EARLY)
#endif
static int __cpuinit zone_batchsize(struct zone *zone)
@@ -2147,7 +2246,8 @@ static __meminit void zone_pcp_init(struct zone *zone)
__meminit int init_currently_empty_zone(struct zone *zone,
unsigned long zone_start_pfn,
- unsigned long size)
+ unsigned long size,
+ enum memmap_context context)
{
struct pglist_data *pgdat = zone->zone_pgdat;
int ret;
@@ -2591,7 +2691,8 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat,
if (!size)
continue;
- ret = init_currently_empty_zone(zone, zone_start_pfn, size);
+ ret = init_currently_empty_zone(zone, zone_start_pfn,
+ size, MEMMAP_EARLY);
BUG_ON(ret);
zone_start_pfn += size;
}
@@ -3232,6 +3333,10 @@ void *__init alloc_large_system_hash(const char *tablename,
numentries >>= (scale - PAGE_SHIFT);
else
numentries <<= (PAGE_SHIFT - scale);
+
+ /* Make sure we've got at least a 0-order allocation.. */
+ if (unlikely((numentries * bucketsize) < PAGE_SIZE))
+ numentries = PAGE_SIZE / bucketsize;
}
numentries = roundup_pow_of_two(numentries);
@@ -3244,7 +3349,7 @@ void *__init alloc_large_system_hash(const char *tablename,
if (numentries > max)
numentries = max;
- log2qty = long_log2(numentries);
+ log2qty = ilog2(numentries);
do {
size = bucketsize << log2qty;
@@ -3266,7 +3371,7 @@ void *__init alloc_large_system_hash(const char *tablename,
printk("%s hash table entries: %d (order: %d, %lu bytes)\n",
tablename,
(1U << log2qty),
- long_log2(size) - PAGE_SHIFT,
+ ilog2(size) - PAGE_SHIFT,
size);
if (_hash_shift)
diff --git a/mm/readahead.c b/mm/readahead.c
index a386f2b6b33..0f539e8e827 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
+#include <linux/task_io_accounting_ops.h>
#include <linux/pagevec.h>
void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
@@ -151,6 +152,7 @@ int read_cache_pages(struct address_space *mapping, struct list_head *pages,
put_pages_list(pages);
break;
}
+ task_io_account_read(PAGE_CACHE_SIZE);
}
pagevec_lru_add(&lru_pvec);
return ret;
@@ -450,7 +452,7 @@ static int make_ahead_window(struct address_space *mapping, struct file *filp,
*
* Note that @filp is purely used for passing on to the ->readpage[s]()
* handler: it may refer to a different file from @mapping (so we may not use
- * @filp->f_mapping or @filp->f_dentry->d_inode here).
+ * @filp->f_mapping or @filp->f_path.dentry->d_inode here).
* Also, @ra may not be equal to &@filp->f_ra.
*
*/
diff --git a/mm/rmap.c b/mm/rmap.c
index d8a842a586d..669acb22b57 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -47,6 +47,7 @@
#include <linux/rmap.h>
#include <linux/rcupdate.h>
#include <linux/module.h>
+#include <linux/kallsyms.h>
#include <asm/tlbflush.h>
@@ -432,7 +433,7 @@ static int page_mkclean_one(struct page *page, struct vm_area_struct *vma)
{
struct mm_struct *mm = vma->vm_mm;
unsigned long address;
- pte_t *pte, entry;
+ pte_t *pte;
spinlock_t *ptl;
int ret = 0;
@@ -444,17 +445,18 @@ static int page_mkclean_one(struct page *page, struct vm_area_struct *vma)
if (!pte)
goto out;
- if (!pte_dirty(*pte) && !pte_write(*pte))
- goto unlock;
+ if (pte_dirty(*pte) || pte_write(*pte)) {
+ pte_t entry;
- entry = ptep_get_and_clear(mm, address, pte);
- entry = pte_mkclean(entry);
- entry = pte_wrprotect(entry);
- ptep_establish(vma, address, pte, entry);
- lazy_mmu_prot_update(entry);
- ret = 1;
+ flush_cache_page(vma, address, pte_pfn(*pte));
+ entry = ptep_clear_flush(vma, address, pte);
+ entry = pte_wrprotect(entry);
+ entry = pte_mkclean(entry);
+ set_pte_at(mm, address, pte, entry);
+ lazy_mmu_prot_update(entry);
+ ret = 1;
+ }
-unlock:
pte_unmap_unlock(pte, ptl);
out:
return ret;
@@ -489,6 +491,8 @@ int page_mkclean(struct page *page)
if (mapping)
ret = page_mkclean_file(mapping, page);
}
+ if (page_test_and_clear_dirty(page))
+ ret = 1;
return ret;
}
@@ -567,14 +571,20 @@ void page_add_file_rmap(struct page *page)
*
* The caller needs to hold the pte lock.
*/
-void page_remove_rmap(struct page *page)
+void page_remove_rmap(struct page *page, struct vm_area_struct *vma)
{
if (atomic_add_negative(-1, &page->_mapcount)) {
if (unlikely(page_mapcount(page) < 0)) {
printk (KERN_EMERG "Eeek! page_mapcount(page) went negative! (%d)\n", page_mapcount(page));
+ printk (KERN_EMERG " page pfn = %lx\n", page_to_pfn(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);
+ print_symbol (KERN_EMERG " vma->vm_ops = %s\n", (unsigned long)vma->vm_ops);
+ if (vma->vm_ops)
+ print_symbol (KERN_EMERG " vma->vm_ops->nopage = %s\n", (unsigned long)vma->vm_ops->nopage);
+ if (vma->vm_file && vma->vm_file->f_op)
+ print_symbol (KERN_EMERG " vma->vm_file->f_op->mmap = %s\n", (unsigned long)vma->vm_file->f_op->mmap);
BUG();
}
@@ -679,7 +689,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
dec_mm_counter(mm, file_rss);
- page_remove_rmap(page);
+ page_remove_rmap(page, vma);
page_cache_release(page);
out_unmap:
@@ -769,7 +779,7 @@ static void try_to_unmap_cluster(unsigned long cursor,
if (pte_dirty(pteval))
set_page_dirty(page);
- page_remove_rmap(page);
+ page_remove_rmap(page, vma);
page_cache_release(page);
dec_mm_counter(mm, file_rss);
(*mapcount)--;
diff --git a/mm/shmem.c b/mm/shmem.c
index c820b4f77b8..70da7a0981b 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -515,7 +515,12 @@ static void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end)
size = SHMEM_NR_DIRECT;
nr_swaps_freed = shmem_free_swp(ptr+idx, ptr+size);
}
- if (!topdir)
+
+ /*
+ * If there are no indirect blocks or we are punching a hole
+ * below indirect blocks, nothing to be done.
+ */
+ if (!topdir || (punch_hole && (limit <= SHMEM_NR_DIRECT)))
goto done2;
BUG_ON(limit <= SHMEM_NR_DIRECT);
@@ -1225,7 +1230,7 @@ failed:
struct page *shmem_nopage(struct vm_area_struct *vma, unsigned long address, int *type)
{
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
struct page *page = NULL;
unsigned long idx;
int error;
@@ -1248,7 +1253,7 @@ static int shmem_populate(struct vm_area_struct *vma,
unsigned long addr, unsigned long len,
pgprot_t prot, unsigned long pgoff, int nonblock)
{
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
struct mm_struct *mm = vma->vm_mm;
enum sgp_type sgp = nonblock? SGP_QUICK: SGP_CACHE;
unsigned long size;
@@ -1293,14 +1298,14 @@ static int shmem_populate(struct vm_area_struct *vma,
#ifdef CONFIG_NUMA
int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
{
- struct inode *i = vma->vm_file->f_dentry->d_inode;
+ struct inode *i = vma->vm_file->f_path.dentry->d_inode;
return mpol_set_shared_policy(&SHMEM_I(i)->policy, vma, new);
}
struct mempolicy *
shmem_get_policy(struct vm_area_struct *vma, unsigned long addr)
{
- struct inode *i = vma->vm_file->f_dentry->d_inode;
+ struct inode *i = vma->vm_file->f_path.dentry->d_inode;
unsigned long idx;
idx = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
@@ -1310,7 +1315,7 @@ shmem_get_policy(struct vm_area_struct *vma, unsigned long addr)
int shmem_lock(struct file *file, int lock, struct user_struct *user)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct shmem_inode_info *info = SHMEM_I(inode);
int retval = -ENOMEM;
@@ -1422,7 +1427,7 @@ shmem_prepare_write(struct file *file, struct page *page, unsigned offset, unsig
static ssize_t
shmem_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
loff_t pos;
unsigned long written;
ssize_t err;
@@ -1442,7 +1447,7 @@ shmem_file_write(struct file *file, const char __user *buf, size_t count, loff_t
if (err || !count)
goto out;
- err = remove_suid(file->f_dentry);
+ err = remove_suid(file->f_path.dentry);
if (err)
goto out;
@@ -1524,7 +1529,7 @@ out:
static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_t *desc, read_actor_t actor)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct address_space *mapping = inode->i_mapping;
unsigned long index, offset;
@@ -2493,8 +2498,8 @@ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags)
d_instantiate(dentry, inode);
inode->i_size = size;
inode->i_nlink = 0; /* It is unlinked */
- file->f_vfsmnt = mntget(shm_mnt);
- file->f_dentry = dentry;
+ file->f_path.mnt = mntget(shm_mnt);
+ file->f_path.dentry = dentry;
file->f_mapping = inode->i_mapping;
file->f_op = &shmem_file_operations;
file->f_mode = FMODE_WRITE | FMODE_READ;
diff --git a/mm/slab.c b/mm/slab.c
index 068cb4503c1..c6100628a6e 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -107,7 +107,9 @@
#include <linux/nodemask.h>
#include <linux/mempolicy.h>
#include <linux/mutex.h>
+#include <linux/fault-inject.h>
#include <linux/rtmutex.h>
+#include <linux/reciprocal_div.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
@@ -385,6 +387,7 @@ struct kmem_cache {
unsigned int shared;
unsigned int buffer_size;
+ u32 reciprocal_buffer_size;
/* 3) touched by every alloc & free from the backend */
struct kmem_list3 *nodelists[MAX_NUMNODES];
@@ -626,10 +629,17 @@ static inline void *index_to_obj(struct kmem_cache *cache, struct slab *slab,
return slab->s_mem + cache->buffer_size * idx;
}
-static inline unsigned int obj_to_index(struct kmem_cache *cache,
- struct slab *slab, void *obj)
+/*
+ * We want to avoid an expensive divide : (offset / cache->buffer_size)
+ * Using the fact that buffer_size is a constant for a particular cache,
+ * we can replace (offset / cache->buffer_size) by
+ * reciprocal_divide(offset, cache->reciprocal_buffer_size)
+ */
+static inline unsigned int obj_to_index(const struct kmem_cache *cache,
+ const struct slab *slab, void *obj)
{
- return (unsigned)(obj - slab->s_mem) / cache->buffer_size;
+ u32 offset = (obj - slab->s_mem);
+ return reciprocal_divide(offset, cache->reciprocal_buffer_size);
}
/*
@@ -945,7 +955,8 @@ static void __devinit start_cpu_timer(int cpu)
if (keventd_up() && reap_work->work.func == NULL) {
init_reap_node(cpu);
INIT_DELAYED_WORK(reap_work, cache_reap);
- schedule_delayed_work_on(cpu, reap_work, HZ + 3 * cpu);
+ schedule_delayed_work_on(cpu, reap_work,
+ __round_jiffies_relative(HZ, cpu));
}
}
@@ -1425,6 +1436,8 @@ void __init kmem_cache_init(void)
cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,
cache_line_size());
+ cache_cache.reciprocal_buffer_size =
+ reciprocal_value(cache_cache.buffer_size);
for (order = 0; order < MAX_ORDER; order++) {
cache_estimate(order, cache_cache.buffer_size,
@@ -2311,6 +2324,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
if (flags & SLAB_CACHE_DMA)
cachep->gfpflags |= GFP_DMA;
cachep->buffer_size = size;
+ cachep->reciprocal_buffer_size = reciprocal_value(size);
if (flags & CFLGS_OFF_SLAB) {
cachep->slabp_cache = kmem_find_general_cachep(slab_size, 0u);
@@ -3088,12 +3102,89 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
#define cache_alloc_debugcheck_after(a,b,objp,d) (objp)
#endif
+#ifdef CONFIG_FAILSLAB
+
+static struct failslab_attr {
+
+ struct fault_attr attr;
+
+ u32 ignore_gfp_wait;
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+ struct dentry *ignore_gfp_wait_file;
+#endif
+
+} failslab = {
+ .attr = FAULT_ATTR_INITIALIZER,
+ .ignore_gfp_wait = 1,
+};
+
+static int __init setup_failslab(char *str)
+{
+ return setup_fault_attr(&failslab.attr, str);
+}
+__setup("failslab=", setup_failslab);
+
+static int should_failslab(struct kmem_cache *cachep, gfp_t flags)
+{
+ if (cachep == &cache_cache)
+ return 0;
+ if (flags & __GFP_NOFAIL)
+ return 0;
+ if (failslab.ignore_gfp_wait && (flags & __GFP_WAIT))
+ return 0;
+
+ return should_fail(&failslab.attr, obj_size(cachep));
+}
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+static int __init failslab_debugfs(void)
+{
+ mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+ struct dentry *dir;
+ int err;
+
+ err = init_fault_attr_dentries(&failslab.attr, "failslab");
+ if (err)
+ return err;
+ dir = failslab.attr.dentries.dir;
+
+ failslab.ignore_gfp_wait_file =
+ debugfs_create_bool("ignore-gfp-wait", mode, dir,
+ &failslab.ignore_gfp_wait);
+
+ if (!failslab.ignore_gfp_wait_file) {
+ err = -ENOMEM;
+ debugfs_remove(failslab.ignore_gfp_wait_file);
+ cleanup_fault_attr_dentries(&failslab.attr);
+ }
+
+ return err;
+}
+
+late_initcall(failslab_debugfs);
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+#else /* CONFIG_FAILSLAB */
+
+static inline int should_failslab(struct kmem_cache *cachep, gfp_t flags)
+{
+ return 0;
+}
+
+#endif /* CONFIG_FAILSLAB */
+
static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
{
void *objp;
struct array_cache *ac;
check_irq_off();
+
+ if (should_failslab(cachep, flags))
+ return NULL;
+
ac = cpu_cache_get(cachep);
if (likely(ac->avail)) {
STATS_INC_ALLOCHIT(cachep);
@@ -3173,6 +3264,7 @@ void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
struct zone **z;
void *obj = NULL;
int nid;
+ gfp_t local_flags = (flags & GFP_LEVEL_MASK);
retry:
/*
@@ -3182,21 +3274,26 @@ retry:
for (z = zonelist->zones; *z && !obj; z++) {
nid = zone_to_nid(*z);
- if (cpuset_zone_allowed(*z, flags) &&
+ if (cpuset_zone_allowed_hardwall(*z, flags) &&
cache->nodelists[nid] &&
cache->nodelists[nid]->free_objects)
obj = ____cache_alloc_node(cache,
flags | GFP_THISNODE, nid);
}
- if (!obj) {
+ if (!obj && !(flags & __GFP_NO_GROW)) {
/*
* This allocation will be performed within the constraints
* of the current cpuset / memory policy requirements.
* We may trigger various forms of reclaim on the allowed
* set and go into memory reserves if necessary.
*/
+ if (local_flags & __GFP_WAIT)
+ local_irq_enable();
+ kmem_flagcheck(cache, flags);
obj = kmem_getpages(cache, flags, -1);
+ if (local_flags & __GFP_WAIT)
+ local_irq_disable();
if (obj) {
/*
* Insert into the appropriate per node queues
@@ -3213,7 +3310,7 @@ retry:
*/
goto retry;
} else {
- kmem_freepages(cache, obj);
+ /* cache_grow already freed obj */
obj = NULL;
}
}
@@ -3456,7 +3553,7 @@ EXPORT_SYMBOL(kmem_cache_zalloc);
*
* Currently only used for dentry validation.
*/
-int fastcall kmem_ptr_validate(struct kmem_cache *cachep, void *ptr)
+int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr)
{
unsigned long addr = (unsigned long)ptr;
unsigned long min_addr = PAGE_OFFSET;
@@ -3490,6 +3587,7 @@ out:
* @cachep: The cache to allocate from.
* @flags: See kmalloc().
* @nodeid: node number of the target node.
+ * @caller: return address of caller, used for debug information
*
* Identical to kmem_cache_alloc but it will allocate memory on the given
* node, which can improve the performance for cpu bound structures.
@@ -3928,7 +4026,7 @@ static void cache_reap(struct work_struct *unused)
if (!mutex_trylock(&cache_chain_mutex)) {
/* Give up. Setup the next iteration. */
schedule_delayed_work(&__get_cpu_var(reap_work),
- REAPTIMEOUT_CPUC);
+ round_jiffies_relative(REAPTIMEOUT_CPUC));
return;
}
@@ -3974,7 +4072,8 @@ next:
next_reap_node();
refresh_cpu_vm_stats(smp_processor_id());
/* Set up the next iteration */
- schedule_delayed_work(&__get_cpu_var(reap_work), REAPTIMEOUT_CPUC);
+ schedule_delayed_work(&__get_cpu_var(reap_work),
+ round_jiffies_relative(REAPTIMEOUT_CPUC));
}
#ifdef CONFIG_PROC_FS
diff --git a/mm/slob.c b/mm/slob.c
index 542394184a5..5adc29cb58d 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -60,6 +60,8 @@ static DEFINE_SPINLOCK(slob_lock);
static DEFINE_SPINLOCK(block_lock);
static void slob_free(void *b, int size);
+static void slob_timer_cbk(void);
+
static void *slob_alloc(size_t size, gfp_t gfp, int align)
{
@@ -157,7 +159,7 @@ static int fastcall find_order(int size)
return order;
}
-void *kmalloc(size_t size, gfp_t gfp)
+void *__kmalloc(size_t size, gfp_t gfp)
{
slob_t *m;
bigblock_t *bb;
@@ -186,8 +188,7 @@ void *kmalloc(size_t size, gfp_t gfp)
slob_free(bb, sizeof(bigblock_t));
return 0;
}
-
-EXPORT_SYMBOL(kmalloc);
+EXPORT_SYMBOL(__kmalloc);
void kfree(const void *block)
{
@@ -327,9 +328,25 @@ const char *kmem_cache_name(struct kmem_cache *c)
EXPORT_SYMBOL(kmem_cache_name);
static struct timer_list slob_timer = TIMER_INITIALIZER(
- (void (*)(unsigned long))kmem_cache_init, 0, 0);
+ (void (*)(unsigned long))slob_timer_cbk, 0, 0);
+
+int kmem_cache_shrink(struct kmem_cache *d)
+{
+ return 0;
+}
+EXPORT_SYMBOL(kmem_cache_shrink);
+
+int kmem_ptr_validate(struct kmem_cache *a, const void *b)
+{
+ return 0;
+}
+
+void __init kmem_cache_init(void)
+{
+ slob_timer_cbk();
+}
-void kmem_cache_init(void)
+static void slob_timer_cbk(void)
{
void *p = slob_alloc(PAGE_SIZE, 0, PAGE_SIZE-1);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index c5431072f42..a2d9bb4e80d 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -434,7 +434,7 @@ void free_swap_and_cache(swp_entry_t entry)
*
* This is needed for the suspend to disk (aka swsusp).
*/
-int swap_type_of(dev_t device, sector_t offset)
+int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
{
struct block_device *bdev = NULL;
int i;
@@ -450,6 +450,9 @@ int swap_type_of(dev_t device, sector_t offset)
continue;
if (!bdev) {
+ if (bdev_p)
+ *bdev_p = sis->bdev;
+
spin_unlock(&swap_lock);
return i;
}
@@ -459,6 +462,9 @@ int swap_type_of(dev_t device, sector_t offset)
se = list_entry(sis->extent_list.next,
struct swap_extent, list);
if (se->start_block == offset) {
+ if (bdev_p)
+ *bdev_p = sis->bdev;
+
spin_unlock(&swap_lock);
bdput(bdev);
return i;
@@ -1357,10 +1363,10 @@ static int swap_show(struct seq_file *swap, void *v)
}
file = ptr->swap_file;
- len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
+ len = seq_path(swap, file->f_path.mnt, file->f_path.dentry, " \t\n\\");
seq_printf(swap, "%*s%s\t%u\t%u\t%d\n",
len < 40 ? 40 - len : 1, " ",
- S_ISBLK(file->f_dentry->d_inode->i_mode) ?
+ S_ISBLK(file->f_path.dentry->d_inode->i_mode) ?
"partition" : "file\t",
ptr->pages << (PAGE_SHIFT - 10),
ptr->inuse_pages << (PAGE_SHIFT - 10),
diff --git a/mm/tiny-shmem.c b/mm/tiny-shmem.c
index 5f2cbf0f153..c7f6e1914bc 100644
--- a/mm/tiny-shmem.c
+++ b/mm/tiny-shmem.c
@@ -79,8 +79,8 @@ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags)
d_instantiate(dentry, inode);
inode->i_nlink = 0; /* It is unlinked */
- file->f_vfsmnt = mntget(shm_mnt);
- file->f_dentry = dentry;
+ file->f_path.mnt = mntget(shm_mnt);
+ file->f_path.dentry = dentry;
file->f_mapping = inode->i_mapping;
file->f_op = &ramfs_file_operations;
file->f_mode = FMODE_WRITE | FMODE_READ;
diff --git a/mm/truncate.c b/mm/truncate.c
index e07b1e682c3..5df947de765 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
+#include <linux/task_io_accounting_ops.h>
#include <linux/buffer_head.h> /* grr. try_to_release_page,
do_invalidatepage */
@@ -51,6 +52,33 @@ static inline void truncate_partial_page(struct page *page, unsigned partial)
}
/*
+ * This cancels just the dirty bit on the kernel page itself, it
+ * does NOT actually remove dirty bits on any mmap's that may be
+ * around. It also leaves the page tagged dirty, so any sync
+ * activity will still find it on the dirty lists, and in particular,
+ * clear_page_dirty_for_io() will still look at the dirty bits in
+ * the VM.
+ *
+ * Doing this should *normally* only ever be done when a page
+ * is truncated, and is not actually mapped anywhere at all. However,
+ * fs/buffer.c does this when it notices that somebody has cleaned
+ * out all the buffers on a page without actually doing it through
+ * the VM. Can you say "ext3 is horribly ugly"? Tought you could.
+ */
+void cancel_dirty_page(struct page *page, unsigned int account_size)
+{
+ if (TestClearPageDirty(page)) {
+ struct address_space *mapping = page->mapping;
+ if (mapping && mapping_cap_account_dirty(mapping)) {
+ dec_zone_page_state(page, NR_FILE_DIRTY);
+ if (account_size)
+ task_io_account_cancelled_write(account_size);
+ }
+ }
+}
+EXPORT_SYMBOL(cancel_dirty_page);
+
+/*
* If truncate cannot remove the fs-private metadata from the page, the page
* becomes anonymous. It will be left on the LRU and may even be mapped into
* user pagetables if we're racing with filemap_nopage().
@@ -66,10 +94,11 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
if (page->mapping != mapping)
return;
+ cancel_dirty_page(page, PAGE_CACHE_SIZE);
+
if (PagePrivate(page))
do_invalidatepage(page, 0);
- clear_page_dirty(page);
ClearPageUptodate(page);
ClearPageMappedToDisk(page);
remove_from_page_cache(page);
@@ -319,6 +348,15 @@ failed:
return 0;
}
+static int do_launder_page(struct address_space *mapping, struct page *page)
+{
+ if (!PageDirty(page))
+ return 0;
+ if (page->mapping != mapping || mapping->a_ops->launder_page == NULL)
+ return 0;
+ return mapping->a_ops->launder_page(page);
+}
+
/**
* invalidate_inode_pages2_range - remove range of pages from an address_space
* @mapping: the address_space
@@ -348,7 +386,6 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
for (i = 0; !ret && i < pagevec_count(&pvec); i++) {
struct page *page = pvec.pages[i];
pgoff_t page_index;
- int was_dirty;
lock_page(page);
if (page->mapping != mapping) {
@@ -384,18 +421,14 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
PAGE_CACHE_SIZE, 0);
}
}
- was_dirty = test_clear_page_dirty(page);
- if (!invalidate_complete_page2(mapping, page)) {
- if (was_dirty)
- set_page_dirty(page);
+ ret = do_launder_page(mapping, page);
+ if (ret == 0 && !invalidate_complete_page2(mapping, page))
ret = -EIO;
- }
unlock_page(page);
}
pagevec_release(&pvec);
cond_resched();
}
- WARN_ON_ONCE(ret);
return ret;
}
EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 093f5fe6dd7..7430df68cb6 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -692,7 +692,7 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
__count_vm_events(KSWAPD_STEAL, nr_freed);
} else
__count_zone_vm_events(PGSCAN_DIRECT, zone, nr_scan);
- __count_vm_events(PGACTIVATE, nr_freed);
+ __count_zone_vm_events(PGSTEAL, zone, nr_freed);
if (nr_taken == 0)
goto done;
@@ -984,7 +984,7 @@ static unsigned long shrink_zones(int priority, struct zone **zones,
if (!populated_zone(zone))
continue;
- if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
+ if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
continue;
note_zone_scanning_priority(zone, priority);
@@ -1034,7 +1034,7 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask)
for (i = 0; zones[i] != NULL; i++) {
struct zone *zone = zones[i];
- if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
+ if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
continue;
lru_pages += zone->nr_active + zone->nr_inactive;
@@ -1089,7 +1089,7 @@ out:
for (i = 0; zones[i] != 0; i++) {
struct zone *zone = zones[i];
- if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
+ if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
continue;
zone->prev_priority = priority;
@@ -1354,7 +1354,7 @@ void wakeup_kswapd(struct zone *zone, int order)
return;
if (pgdat->kswapd_max_order < order)
pgdat->kswapd_max_order = order;
- if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
+ if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
return;
if (!waitqueue_active(&pgdat->kswapd_wait))
return;
@@ -1369,8 +1369,8 @@ void wakeup_kswapd(struct zone *zone, int order)
*
* For pass > 3 we also try to shrink the LRU lists that contain a few pages
*/
-static unsigned long shrink_all_zones(unsigned long nr_pages, int pass,
- int prio, struct scan_control *sc)
+static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
+ int pass, struct scan_control *sc)
{
struct zone *zone;
unsigned long nr_to_scan, ret = 0;
@@ -1406,6 +1406,16 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int pass,
return ret;
}
+static unsigned long count_lru_pages(void)
+{
+ struct zone *zone;
+ unsigned long ret = 0;
+
+ for_each_zone(zone)
+ ret += zone->nr_active + zone->nr_inactive;
+ return ret;
+}
+
/*
* Try to free `nr_pages' of memory, system-wide, and return the number of
* freed pages.
@@ -1420,7 +1430,6 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
unsigned long ret = 0;
int pass;
struct reclaim_state reclaim_state;
- struct zone *zone;
struct scan_control sc = {
.gfp_mask = GFP_KERNEL,
.may_swap = 0,
@@ -1431,10 +1440,7 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
current->reclaim_state = &reclaim_state;
- lru_pages = 0;
- for_each_zone(zone)
- lru_pages += zone->nr_active + zone->nr_inactive;
-
+ lru_pages = count_lru_pages();
nr_slab = global_page_state(NR_SLAB_RECLAIMABLE);
/* If slab caches are huge, it's better to hit them first */
while (nr_slab >= lru_pages) {
@@ -1461,13 +1467,6 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
for (pass = 0; pass < 5; pass++) {
int prio;
- /* Needed for shrinking slab caches later on */
- if (!lru_pages)
- for_each_zone(zone) {
- lru_pages += zone->nr_active;
- lru_pages += zone->nr_inactive;
- }
-
/* Force reclaiming mapped pages in the passes #3 and #4 */
if (pass > 2) {
sc.may_swap = 1;
@@ -1483,7 +1482,8 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
goto out;
reclaim_state.reclaimed_slab = 0;
- shrink_slab(sc.nr_scanned, sc.gfp_mask, lru_pages);
+ shrink_slab(sc.nr_scanned, sc.gfp_mask,
+ count_lru_pages());
ret += reclaim_state.reclaimed_slab;
if (ret >= nr_pages)
goto out;
@@ -1491,20 +1491,19 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
if (sc.nr_scanned && prio < DEF_PRIORITY - 2)
congestion_wait(WRITE, HZ / 10);
}
-
- lru_pages = 0;
}
/*
* If ret = 0, we could not shrink LRUs, but there may be something
* in slab caches
*/
- if (!ret)
+ if (!ret) {
do {
reclaim_state.reclaimed_slab = 0;
- shrink_slab(nr_pages, sc.gfp_mask, lru_pages);
+ shrink_slab(nr_pages, sc.gfp_mask, count_lru_pages());
ret += reclaim_state.reclaimed_slab;
} while (ret < nr_pages && reclaim_state.reclaimed_slab > 0);
+ }
out:
current->reclaim_state = NULL;
diff --git a/net/Kconfig b/net/Kconfig
index 7dfc9492069..915657832d9 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -37,6 +37,7 @@ config NETDEBUG
source "net/packet/Kconfig"
source "net/unix/Kconfig"
source "net/xfrm/Kconfig"
+source "net/iucv/Kconfig"
config INET
bool "TCP/IP networking"
diff --git a/net/Makefile b/net/Makefile
index ad4d14f4bb2..4854ac50631 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_IP_SCTP) += sctp/
obj-$(CONFIG_IEEE80211) += ieee80211/
obj-$(CONFIG_TIPC) += tipc/
obj-$(CONFIG_NETLABEL) += netlabel/
+obj-$(CONFIG_IUCV) += iucv/
ifeq ($(CONFIG_NET),y)
obj-$(CONFIG_SYSCTL) += sysctl_net.o
diff --git a/net/atm/common.c b/net/atm/common.c
index fbabff49446..a2878e92c3a 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -816,7 +816,8 @@ static void __exit atm_exit(void)
proto_unregister(&vcc_proto);
}
-module_init(atm_init);
+subsys_initcall(atm_init);
+
module_exit(atm_exit);
MODULE_LICENSE("GPL");
diff --git a/net/atm/proc.c b/net/atm/proc.c
index 91fe5f53ff1..739866bfe9e 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -393,7 +393,7 @@ static ssize_t proc_dev_atm_read(struct file *file, char __user *buf,
if (count == 0) return 0;
page = get_zeroed_page(GFP_KERNEL);
if (!page) return -ENOMEM;
- dev = PDE(file->f_dentry->d_inode)->data;
+ dev = PDE(file->f_path.dentry->d_inode)->data;
if (!dev->ops->proc_read)
length = -EINVAL;
else {
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 6cabf6d8a75..42233df2b09 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1088,8 +1088,8 @@ out:
/*
* FIXME: nonblock behaviour looks like it may have a bug.
*/
-static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
- int addr_len, int flags)
+static int __must_check ax25_connect(struct socket *sock,
+ struct sockaddr *uaddr, int addr_len, int flags)
{
struct sock *sk = sock->sk;
ax25_cb *ax25 = ax25_sk(sk), *ax25t;
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c
index 5f0896ad004..97a49c79c60 100644
--- a/net/ax25/ax25_addr.c
+++ b/net/ax25/ax25_addr.c
@@ -29,17 +29,26 @@
#include <linux/interrupt.h>
/*
- * The null address is defined as a callsign of all spaces with an
- * SSID of zero.
+ * The default broadcast address of an interface is QST-0; the default address
+ * is LINUX-1. The null address is defined as a callsign of all spaces with
+ * an SSID of zero.
*/
-ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}};
+const ax25_address ax25_bcast =
+ {{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}};
+const ax25_address ax25_defaddr =
+ {{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, 1 << 1}};
+const ax25_address null_ax25_address =
+ {{' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}};
+
+EXPORT_SYMBOL_GPL(ax25_bcast);
+EXPORT_SYMBOL_GPL(ax25_defaddr);
EXPORT_SYMBOL(null_ax25_address);
/*
* ax25 -> ascii conversion
*/
-char *ax2asc(char *buf, ax25_address *a)
+char *ax2asc(char *buf, const ax25_address *a)
{
char c, *s;
int n;
@@ -72,9 +81,9 @@ EXPORT_SYMBOL(ax2asc);
/*
* ascii -> ax25 conversion
*/
-void asc2ax(ax25_address *addr, char *callsign)
+void asc2ax(ax25_address *addr, const char *callsign)
{
- char *s;
+ const char *s;
int n;
for (s = callsign, n = 0; n < 6; n++) {
@@ -107,7 +116,7 @@ EXPORT_SYMBOL(asc2ax);
/*
* Compare two ax.25 addresses
*/
-int ax25cmp(ax25_address *a, ax25_address *b)
+int ax25cmp(const ax25_address *a, const ax25_address *b)
{
int ct = 0;
@@ -128,7 +137,7 @@ EXPORT_SYMBOL(ax25cmp);
/*
* Compare two AX.25 digipeater paths.
*/
-int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2)
+int ax25digicmp(const ax25_digi *digi1, const ax25_digi *digi2)
{
int i;
@@ -149,7 +158,9 @@ int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2)
* Given an AX.25 address pull of to, from, digi list, command/response and the start of data
*
*/
-unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, int *dama)
+const unsigned char *ax25_addr_parse(const unsigned char *buf, int len,
+ ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags,
+ int *dama)
{
int d = 0;
@@ -204,7 +215,8 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
/*
* Assemble an AX.25 header from the bits
*/
-int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus)
+int ax25_addr_build(unsigned char *buf, const ax25_address *src,
+ const ax25_address *dest, const ax25_digi *d, int flag, int modulus)
{
int len = 0;
int ct = 0;
@@ -261,7 +273,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a
return len;
}
-int ax25_addr_size(ax25_digi *dp)
+int ax25_addr_size(const ax25_digi *dp)
{
if (dp == NULL)
return 2 * AX25_ADDR_LEN;
@@ -272,7 +284,7 @@ int ax25_addr_size(ax25_digi *dp)
/*
* Reverse Digipeat List. May not pass both parameters as same struct
*/
-void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
+void ax25_digi_invert(const ax25_digi *in, ax25_digi *out)
{
int ct;
diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c
index 07ac0207eb6..aff3e652c2d 100644
--- a/net/ax25/ax25_iface.c
+++ b/net/ax25/ax25_iface.c
@@ -29,17 +29,10 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
-static struct protocol_struct {
- struct protocol_struct *next;
- unsigned int pid;
- int (*func)(struct sk_buff *, ax25_cb *);
-} *protocol_list = NULL;
+static struct ax25_protocol *protocol_list;
static DEFINE_RWLOCK(protocol_list_lock);
-static struct linkfail_struct {
- struct linkfail_struct *next;
- void (*func)(ax25_cb *, int);
-} *linkfail_list = NULL;
+static HLIST_HEAD(ax25_linkfail_list);
static DEFINE_SPINLOCK(linkfail_lock);
static struct listen_struct {
@@ -49,36 +42,23 @@ static struct listen_struct {
} *listen_list = NULL;
static DEFINE_SPINLOCK(listen_lock);
-int ax25_protocol_register(unsigned int pid,
- int (*func)(struct sk_buff *, ax25_cb *))
+/*
+ * Do not register the internal protocols AX25_P_TEXT, AX25_P_SEGMENT,
+ * AX25_P_IP or AX25_P_ARP ...
+ */
+void ax25_register_pid(struct ax25_protocol *ap)
{
- struct protocol_struct *protocol;
-
- if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT)
- return 0;
-#ifdef CONFIG_INET
- if (pid == AX25_P_IP || pid == AX25_P_ARP)
- return 0;
-#endif
- if ((protocol = kmalloc(sizeof(*protocol), GFP_ATOMIC)) == NULL)
- return 0;
-
- protocol->pid = pid;
- protocol->func = func;
-
write_lock_bh(&protocol_list_lock);
- protocol->next = protocol_list;
- protocol_list = protocol;
+ ap->next = protocol_list;
+ protocol_list = ap;
write_unlock_bh(&protocol_list_lock);
-
- return 1;
}
-EXPORT_SYMBOL(ax25_protocol_register);
+EXPORT_SYMBOL_GPL(ax25_register_pid);
void ax25_protocol_release(unsigned int pid)
{
- struct protocol_struct *s, *protocol;
+ struct ax25_protocol *s, *protocol;
write_lock_bh(&protocol_list_lock);
protocol = protocol_list;
@@ -110,54 +90,19 @@ void ax25_protocol_release(unsigned int pid)
EXPORT_SYMBOL(ax25_protocol_release);
-int ax25_linkfail_register(void (*func)(ax25_cb *, int))
+void ax25_linkfail_register(struct ax25_linkfail *lf)
{
- struct linkfail_struct *linkfail;
-
- if ((linkfail = kmalloc(sizeof(*linkfail), GFP_ATOMIC)) == NULL)
- return 0;
-
- linkfail->func = func;
-
spin_lock_bh(&linkfail_lock);
- linkfail->next = linkfail_list;
- linkfail_list = linkfail;
+ hlist_add_head(&lf->lf_node, &ax25_linkfail_list);
spin_unlock_bh(&linkfail_lock);
-
- return 1;
}
EXPORT_SYMBOL(ax25_linkfail_register);
-void ax25_linkfail_release(void (*func)(ax25_cb *, int))
+void ax25_linkfail_release(struct ax25_linkfail *lf)
{
- struct linkfail_struct *s, *linkfail;
-
spin_lock_bh(&linkfail_lock);
- linkfail = linkfail_list;
- if (linkfail == NULL) {
- spin_unlock_bh(&linkfail_lock);
- return;
- }
-
- if (linkfail->func == func) {
- linkfail_list = linkfail->next;
- spin_unlock_bh(&linkfail_lock);
- kfree(linkfail);
- return;
- }
-
- while (linkfail != NULL && linkfail->next != NULL) {
- if (linkfail->next->func == func) {
- s = linkfail->next;
- linkfail->next = linkfail->next->next;
- spin_unlock_bh(&linkfail_lock);
- kfree(s);
- return;
- }
-
- linkfail = linkfail->next;
- }
+ hlist_del_init(&lf->lf_node);
spin_unlock_bh(&linkfail_lock);
}
@@ -171,7 +116,7 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
return 0;
if ((listen = kmalloc(sizeof(*listen), GFP_ATOMIC)) == NULL)
- return 0;
+ return -ENOMEM;
listen->callsign = *callsign;
listen->dev = dev;
@@ -181,7 +126,7 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
listen_list = listen;
spin_unlock_bh(&listen_lock);
- return 1;
+ return 0;
}
EXPORT_SYMBOL(ax25_listen_register);
@@ -223,7 +168,7 @@ EXPORT_SYMBOL(ax25_listen_release);
int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
{
int (*res)(struct sk_buff *, ax25_cb *) = NULL;
- struct protocol_struct *protocol;
+ struct ax25_protocol *protocol;
read_lock(&protocol_list_lock);
for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
@@ -242,7 +187,8 @@ int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
spin_lock_bh(&listen_lock);
for (listen = listen_list; listen != NULL; listen = listen->next)
- if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) {
+ if (ax25cmp(&listen->callsign, callsign) == 0 &&
+ (listen->dev == dev || listen->dev == NULL)) {
spin_unlock_bh(&listen_lock);
return 1;
}
@@ -253,17 +199,18 @@ int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
void ax25_link_failed(ax25_cb *ax25, int reason)
{
- struct linkfail_struct *linkfail;
+ struct ax25_linkfail *lf;
+ struct hlist_node *node;
spin_lock_bh(&linkfail_lock);
- for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next)
- (linkfail->func)(ax25, reason);
+ hlist_for_each_entry(lf, node, &ax25_linkfail_list, lf_node)
+ lf->func(ax25, reason);
spin_unlock_bh(&linkfail_lock);
}
int ax25_protocol_is_registered(unsigned int pid)
{
- struct protocol_struct *protocol;
+ struct ax25_protocol *protocol;
int res = 0;
read_lock_bh(&protocol_list_lock);
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 8580356ace5..0a0381622b1 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -71,7 +71,7 @@ void ax25_rt_device_down(struct net_device *dev)
write_unlock(&ax25_route_lock);
}
-static int ax25_rt_add(struct ax25_routes_struct *route)
+static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
{
ax25_route *ax25_rt;
ax25_dev *ax25_dev;
diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c
index be04e9fb11f..ab166b48ce8 100644
--- a/net/bluetooth/cmtp/capi.c
+++ b/net/bluetooth/cmtp/capi.c
@@ -196,6 +196,9 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
switch (CAPIMSG_SUBCOMMAND(skb->data)) {
case CAPI_CONF:
+ if (skb->len < CAPI_MSG_BASELEN + 10)
+ break;
+
func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
@@ -226,6 +229,9 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
break;
case CAPI_FUNCTION_GET_PROFILE:
+ if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
+ break;
+
controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
msgnum = CAPIMSG_MSGID(skb->data);
@@ -246,17 +252,26 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
break;
case CAPI_FUNCTION_GET_MANUFACTURER:
+ if (skb->len < CAPI_MSG_BASELEN + 15)
+ break;
+
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
if (!info && ctrl) {
+ int len = min_t(uint, CAPI_MANUFACTURER_LEN,
+ skb->data[CAPI_MSG_BASELEN + 14]);
+
+ memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
strncpy(ctrl->manu,
- skb->data + CAPI_MSG_BASELEN + 15,
- skb->data[CAPI_MSG_BASELEN + 14]);
+ skb->data + CAPI_MSG_BASELEN + 15, len);
}
break;
case CAPI_FUNCTION_GET_VERSION:
+ if (skb->len < CAPI_MSG_BASELEN + 32)
+ break;
+
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
if (!info && ctrl) {
@@ -269,13 +284,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
break;
case CAPI_FUNCTION_GET_SERIAL_NUMBER:
+ if (skb->len < CAPI_MSG_BASELEN + 17)
+ break;
+
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
if (!info && ctrl) {
+ int len = min_t(uint, CAPI_SERIAL_LEN,
+ skb->data[CAPI_MSG_BASELEN + 16]);
+
memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
strncpy(ctrl->serial,
- skb->data + CAPI_MSG_BASELEN + 17,
- skb->data[CAPI_MSG_BASELEN + 16]);
+ skb->data + CAPI_MSG_BASELEN + 17, len);
}
break;
@@ -284,14 +304,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
break;
case CAPI_IND:
+ if (skb->len < CAPI_MSG_BASELEN + 6)
+ break;
+
func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
if (func == CAPI_FUNCTION_LOOPBACK) {
+ int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
+ skb->data[CAPI_MSG_BASELEN + 5]);
appl = CAPIMSG_APPID(skb->data);
msgnum = CAPIMSG_MSGID(skb->data);
cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
- skb->data + CAPI_MSG_BASELEN + 6,
- skb->data[CAPI_MSG_BASELEN + 5]);
+ skb->data + CAPI_MSG_BASELEN + 6, len);
}
break;
@@ -309,6 +333,9 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
BT_DBG("session %p skb %p len %d", session, skb, skb->len);
+ if (skb->len < CAPI_MSG_BASELEN)
+ return;
+
if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
cmtp_recv_interopmsg(session, skb);
return;
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 711a085eca5..dbf98c49dba 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -123,10 +123,10 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
if (flt->opcode &&
((evt == HCI_EV_CMD_COMPLETE &&
flt->opcode !=
- get_unaligned((__u16 *)(skb->data + 3))) ||
+ get_unaligned((__le16 *)(skb->data + 3))) ||
(evt == HCI_EV_CMD_STATUS &&
flt->opcode !=
- get_unaligned((__u16 *)(skb->data + 4)))))
+ get_unaligned((__le16 *)(skb->data + 4)))))
continue;
}
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index d4c935692cc..801d687ea4e 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -242,7 +242,7 @@ static void add_conn(struct work_struct *work)
struct hci_conn *conn = container_of(work, struct hci_conn, work);
int i;
- if (device_register(&conn->dev) < 0) {
+ if (device_add(&conn->dev) < 0) {
BT_ERR("Failed to register connection device");
return;
}
@@ -272,6 +272,8 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
dev_set_drvdata(&conn->dev, conn);
+ device_initialize(&conn->dev);
+
INIT_WORK(&conn->work, add_conn);
schedule_work(&conn->work);
@@ -287,6 +289,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
{
BT_DBG("conn %p", conn);
+ if (!device_is_registered(&conn->dev))
+ return;
+
INIT_WORK(&conn->work, del_conn);
schedule_work(&conn->work);
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index c2775f587d2..c8dfacd40a0 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -86,7 +86,7 @@ struct hidp_connadd_req {
int intr_sock; // Connteted interrupt socket
__u16 parser;
__u16 rd_size;
- __u8 *rd_data;
+ __u8 __user *rd_data;
__u8 country;
__u8 subclass;
__u16 vendor;
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index 407fba43c1b..93cf9e58617 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -189,7 +189,7 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
uca = compat_alloc_user_space(sizeof(*uca));
- if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
+ if (copy_from_user(&ca, (void __user *) arg, sizeof(ca)))
return -EFAULT;
if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 29a8fa4d372..f8c25d50015 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -585,6 +585,12 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_
goto done;
}
+ if (la->l2_psm > 0 && btohs(la->l2_psm) < 0x1001 &&
+ !capable(CAP_NET_BIND_SERVICE)) {
+ err = -EACCES;
+ goto done;
+ }
+
write_lock_bh(&l2cap_sk_list.lock);
if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
@@ -2150,8 +2156,8 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
- sk->sk_state, pi->psm, pi->scid, pi->dcid, pi->imtu,
- pi->omtu, pi->link_mode);
+ sk->sk_state, btohs(pi->psm), pi->scid, pi->dcid,
+ pi->imtu, pi->omtu, pi->link_mode);
}
read_unlock_bh(&l2cap_sk_list.lock);
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 544d65b7baa..cb7e855f082 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -557,7 +557,6 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
struct sock *sk = sock->sk;
struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
struct sk_buff *skb;
- int err;
int sent = 0;
if (msg->msg_flags & MSG_OOB)
@@ -572,6 +571,7 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
while (len) {
size_t size = min_t(size_t, len, d->mtu);
+ int err;
skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
msg->msg_flags & MSG_DONTWAIT, &err);
@@ -582,13 +582,16 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
if (err) {
kfree_skb(skb);
- sent = err;
+ if (sent == 0)
+ sent = err;
break;
}
err = rfcomm_dlc_send(d, skb);
if (err < 0) {
kfree_skb(skb);
+ if (sent == 0)
+ sent = err;
break;
}
@@ -598,7 +601,7 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
release_sock(sk);
- return sent ? sent : err;
+ return sent;
}
static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 1fb5d42f37a..eb2b52484c7 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -697,9 +697,13 @@ static int rfcomm_tty_write_room(struct tty_struct *tty)
BT_DBG("tty %p", tty);
+ if (!dev || !dev->dlc)
+ return 0;
+
room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
if (room < 0)
room = 0;
+
return room;
}
@@ -752,9 +756,9 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned
return -ENOIOCTLCMD;
}
-static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
+static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
- struct termios *new = (struct termios *) tty->termios;
+ struct ktermios *new = tty->termios;
int old_baud_rate = tty_termios_baud_rate(old);
int new_baud_rate = tty_termios_baud_rate(new);
@@ -915,12 +919,14 @@ static void rfcomm_tty_unthrottle(struct tty_struct *tty)
static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
{
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
- struct rfcomm_dlc *dlc = dev->dlc;
BT_DBG("tty %p dev %p", tty, dev);
- if (!skb_queue_empty(&dlc->tx_queue))
- return dlc->mtu;
+ if (!dev || !dev->dlc)
+ return 0;
+
+ if (!skb_queue_empty(&dev->dlc->tx_queue))
+ return dev->dlc->mtu;
return 0;
}
@@ -928,11 +934,12 @@ static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
{
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
- if (!dev)
- return;
BT_DBG("tty %p dev %p", tty, dev);
+ if (!dev || !dev->dlc)
+ return;
+
skb_queue_purge(&dev->dlc->tx_queue);
if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
@@ -952,11 +959,12 @@ static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
static void rfcomm_tty_hangup(struct tty_struct *tty)
{
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
- if (!dev)
- return;
BT_DBG("tty %p dev %p", tty, dev);
+ if (!dev)
+ return;
+
rfcomm_tty_flush_buffer(tty);
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 55bb2634c08..2b7c2c7dad4 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -286,7 +286,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
kobject_init(&p->kobj);
kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR);
p->kobj.ktype = &brport_ktype;
- p->kobj.parent = &(dev->class_dev.kobj);
+ p->kobj.parent = &(dev->dev.kobj);
p->kobj.kset = NULL;
return p;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index bd221ad52ea..a25fa8cb528 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -61,9 +61,6 @@ static int brnf_filter_vlan_tagged __read_mostly = 1;
#define brnf_filter_vlan_tagged 1
#endif
-int brnf_deferred_hooks;
-EXPORT_SYMBOL_GPL(brnf_deferred_hooks);
-
static __be16 inline vlan_proto(const struct sk_buff *skb)
{
return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
@@ -685,110 +682,50 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
return NF_STOLEN;
}
-/* PF_BRIDGE/LOCAL_OUT ***********************************************/
-static int br_nf_local_out_finish(struct sk_buff *skb)
-{
- if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_push(skb, VLAN_HLEN);
- skb->nh.raw -= VLAN_HLEN;
- }
-
- NF_HOOK_THRESH(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
- br_forward_finish, NF_BR_PRI_FIRST + 1);
-
- return 0;
-}
-
-/* This function sees both locally originated IP packets and forwarded
+/* PF_BRIDGE/LOCAL_OUT ***********************************************
+ *
+ * This function sees both locally originated IP packets and forwarded
* IP packets (in both cases the destination device is a bridge
* device). It also sees bridged-and-DNAT'ed packets.
- * To be able to filter on the physical bridge devices (with the physdev
- * module), we steal packets destined to a bridge device away from the
- * PF_INET/FORWARD and PF_INET/OUTPUT hook functions, and give them back later,
- * when we have determined the real output device. This is done in here.
*
* If (nf_bridge->mask & BRNF_BRIDGED_DNAT) then the packet is bridged
* and we fake the PF_BRIDGE/FORWARD hook. The function br_nf_forward()
* will then fake the PF_INET/FORWARD hook. br_nf_local_out() has priority
* NF_BR_PRI_FIRST, so no relevant PF_BRIDGE/INPUT functions have been nor
* will be executed.
- * Otherwise, if nf_bridge->physindev is NULL, the bridge-nf code never touched
- * this packet before, and so the packet was locally originated. We fake
- * the PF_INET/LOCAL_OUT hook.
- * Finally, if nf_bridge->physindev isn't NULL, then the packet was IP routed,
- * so we fake the PF_INET/FORWARD hook. ip_sabotage_out() makes sure
- * even routed packets that didn't arrive on a bridge interface have their
- * nf_bridge->physindev set. */
+ */
static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct net_device *realindev, *realoutdev;
+ struct net_device *realindev;
struct sk_buff *skb = *pskb;
struct nf_bridge_info *nf_bridge;
- int pf;
if (!skb->nf_bridge)
return NF_ACCEPT;
- if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb))
- pf = PF_INET;
- else
- pf = PF_INET6;
-
nf_bridge = skb->nf_bridge;
- nf_bridge->physoutdev = skb->dev;
- realindev = nf_bridge->physindev;
+ if (!(nf_bridge->mask & BRNF_BRIDGED_DNAT))
+ return NF_ACCEPT;
/* Bridged, take PF_BRIDGE/FORWARD.
* (see big note in front of br_nf_pre_routing_finish) */
- if (nf_bridge->mask & BRNF_BRIDGED_DNAT) {
- if (nf_bridge->mask & BRNF_PKT_TYPE) {
- skb->pkt_type = PACKET_OTHERHOST;
- nf_bridge->mask ^= BRNF_PKT_TYPE;
- }
- if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_push(skb, VLAN_HLEN);
- skb->nh.raw -= VLAN_HLEN;
- }
+ nf_bridge->physoutdev = skb->dev;
+ realindev = nf_bridge->physindev;
- NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev,
- skb->dev, br_forward_finish);
- goto out;
+ if (nf_bridge->mask & BRNF_PKT_TYPE) {
+ skb->pkt_type = PACKET_OTHERHOST;
+ nf_bridge->mask ^= BRNF_PKT_TYPE;
}
- realoutdev = bridge_parent(skb->dev);
- if (!realoutdev)
- return NF_DROP;
-
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
- /* iptables should match -o br0.x */
- if (nf_bridge->netoutdev)
- realoutdev = nf_bridge->netoutdev;
-#endif
if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_pull(skb, VLAN_HLEN);
- (*pskb)->nh.raw += VLAN_HLEN;
- }
- /* IP forwarded traffic has a physindev, locally
- * generated traffic hasn't. */
- if (realindev != NULL) {
- if (!(nf_bridge->mask & BRNF_DONT_TAKE_PARENT)) {
- struct net_device *parent = bridge_parent(realindev);
- if (parent)
- realindev = parent;
- }
-
- NF_HOOK_THRESH(pf, NF_IP_FORWARD, skb, realindev,
- realoutdev, br_nf_local_out_finish,
- NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD + 1);
- } else {
- NF_HOOK_THRESH(pf, NF_IP_LOCAL_OUT, skb, realindev,
- realoutdev, br_nf_local_out_finish,
- NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT + 1);
+ skb_push(skb, VLAN_HLEN);
+ skb->nh.raw -= VLAN_HLEN;
}
-out:
+ NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev, skb->dev,
+ br_forward_finish);
return NF_STOLEN;
}
@@ -894,69 +831,6 @@ static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff **pskb,
return NF_ACCEPT;
}
-/* Postpone execution of PF_INET(6)/FORWARD, PF_INET(6)/LOCAL_OUT
- * and PF_INET(6)/POST_ROUTING until we have done the forwarding
- * decision in the bridge code and have determined nf_bridge->physoutdev. */
-static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
-{
- struct sk_buff *skb = *pskb;
-
- if ((out->hard_start_xmit == br_dev_xmit &&
- okfn != br_nf_forward_finish &&
- okfn != br_nf_local_out_finish && okfn != br_nf_dev_queue_xmit)
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
- || ((out->priv_flags & IFF_802_1Q_VLAN) &&
- VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit)
-#endif
- ) {
- struct nf_bridge_info *nf_bridge;
-
- if (!skb->nf_bridge) {
-#ifdef CONFIG_SYSCTL
- /* This code is executed while in the IP(v6) stack,
- the version should be 4 or 6. We can't use
- skb->protocol because that isn't set on
- PF_INET(6)/LOCAL_OUT. */
- struct iphdr *ip = skb->nh.iph;
-
- if (ip->version == 4 && !brnf_call_iptables)
- return NF_ACCEPT;
- else if (ip->version == 6 && !brnf_call_ip6tables)
- return NF_ACCEPT;
- else if (!brnf_deferred_hooks)
- return NF_ACCEPT;
-#endif
- if (hook == NF_IP_POST_ROUTING)
- return NF_ACCEPT;
- if (!nf_bridge_alloc(skb))
- return NF_DROP;
- }
-
- nf_bridge = skb->nf_bridge;
-
- /* This frame will arrive on PF_BRIDGE/LOCAL_OUT and we
- * will need the indev then. For a brouter, the real indev
- * can be a bridge port, so we make sure br_nf_local_out()
- * doesn't use the bridge parent of the indev by using
- * the BRNF_DONT_TAKE_PARENT mask. */
- if (hook == NF_IP_FORWARD && nf_bridge->physindev == NULL) {
- nf_bridge->mask |= BRNF_DONT_TAKE_PARENT;
- nf_bridge->physindev = (struct net_device *)in;
- }
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
- /* the iptables outdev is br0.x, not br0 */
- if (out->priv_flags & IFF_802_1Q_VLAN)
- nf_bridge->netoutdev = (struct net_device *)out;
-#endif
- return NF_STOP;
- }
-
- return NF_ACCEPT;
-}
-
/* For br_nf_local_out we need (prio = NF_BR_PRI_FIRST), to insure that innocent
* PF_BRIDGE/NF_BR_LOCAL_OUT functions don't get bridged traffic as input.
* For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
@@ -1002,36 +876,6 @@ static struct nf_hook_ops br_nf_ops[] = {
.pf = PF_INET6,
.hooknum = NF_IP6_PRE_ROUTING,
.priority = NF_IP6_PRI_FIRST, },
- { .hook = ip_sabotage_out,
- .owner = THIS_MODULE,
- .pf = PF_INET,
- .hooknum = NF_IP_FORWARD,
- .priority = NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD, },
- { .hook = ip_sabotage_out,
- .owner = THIS_MODULE,
- .pf = PF_INET6,
- .hooknum = NF_IP6_FORWARD,
- .priority = NF_IP6_PRI_BRIDGE_SABOTAGE_FORWARD, },
- { .hook = ip_sabotage_out,
- .owner = THIS_MODULE,
- .pf = PF_INET,
- .hooknum = NF_IP_LOCAL_OUT,
- .priority = NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT, },
- { .hook = ip_sabotage_out,
- .owner = THIS_MODULE,
- .pf = PF_INET6,
- .hooknum = NF_IP6_LOCAL_OUT,
- .priority = NF_IP6_PRI_BRIDGE_SABOTAGE_LOCAL_OUT, },
- { .hook = ip_sabotage_out,
- .owner = THIS_MODULE,
- .pf = PF_INET,
- .hooknum = NF_IP_POST_ROUTING,
- .priority = NF_IP_PRI_FIRST, },
- { .hook = ip_sabotage_out,
- .owner = THIS_MODULE,
- .pf = PF_INET6,
- .hooknum = NF_IP6_POST_ROUTING,
- .priority = NF_IP6_PRI_FIRST, },
};
#ifdef CONFIG_SYSCTL
@@ -1105,44 +949,29 @@ static ctl_table brnf_net_table[] = {
};
#endif
-int br_netfilter_init(void)
+int __init br_netfilter_init(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++) {
- int ret;
-
- if ((ret = nf_register_hook(&br_nf_ops[i])) >= 0)
- continue;
-
- while (i--)
- nf_unregister_hook(&br_nf_ops[i]);
+ int ret;
+ ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+ if (ret < 0)
return ret;
- }
-
#ifdef CONFIG_SYSCTL
brnf_sysctl_header = register_sysctl_table(brnf_net_table, 0);
if (brnf_sysctl_header == NULL) {
printk(KERN_WARNING
"br_netfilter: can't register to sysctl.\n");
- for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++)
- nf_unregister_hook(&br_nf_ops[i]);
- return -EFAULT;
+ nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+ return -ENOMEM;
}
#endif
-
printk(KERN_NOTICE "Bridge firewalling registered\n");
-
return 0;
}
void br_netfilter_fini(void)
{
- int i;
-
- for (i = ARRAY_SIZE(br_nf_ops) - 1; i >= 0; i--)
- nf_unregister_hook(&br_nf_ops[i]);
+ nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
#ifdef CONFIG_SYSCTL
unregister_sysctl_table(brnf_sysctl_header);
#endif
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index a9139682c49..7d68b24b565 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -45,7 +45,7 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
hdr = nlmsg_data(nlh);
hdr->ifi_family = AF_BRIDGE;
@@ -72,7 +72,8 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
return nlmsg_end(skb, nlh);
nla_put_failure:
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
/*
@@ -89,9 +90,12 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
goto errout;
err = br_fill_ifinfo(skb, port, 0, 0, event, 0);
- /* failure implies BUG in br_nlmsg_size() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in br_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
errout:
if (err < 0)
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index de9d1a9473f..ce10464716a 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -21,18 +21,17 @@
#include "br_private.h"
-#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
+#define to_dev(obj) container_of(obj, struct device, kobj)
#define to_bridge(cd) ((struct net_bridge *)(to_net_dev(cd)->priv))
/*
* Common code for storing bridge parameters.
*/
-static ssize_t store_bridge_parm(struct class_device *cd,
+static ssize_t store_bridge_parm(struct device *d,
const char *buf, size_t len,
void (*set)(struct net_bridge *, unsigned long))
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
char *endp;
unsigned long val;
@@ -50,9 +49,10 @@ static ssize_t store_bridge_parm(struct class_device *cd,
}
-static ssize_t show_forward_delay(struct class_device *cd, char *buf)
+static ssize_t show_forward_delay(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
}
@@ -64,18 +64,20 @@ static void set_forward_delay(struct net_bridge *br, unsigned long val)
br->bridge_forward_delay = delay;
}
-static ssize_t store_forward_delay(struct class_device *cd, const char *buf,
- size_t len)
+static ssize_t store_forward_delay(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
- return store_bridge_parm(cd, buf, len, set_forward_delay);
+ return store_bridge_parm(d, buf, len, set_forward_delay);
}
-static CLASS_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
- show_forward_delay, store_forward_delay);
+static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
+ show_forward_delay, store_forward_delay);
-static ssize_t show_hello_time(struct class_device *cd, char *buf)
+static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%lu\n",
- jiffies_to_clock_t(to_bridge(cd)->hello_time));
+ jiffies_to_clock_t(to_bridge(d)->hello_time));
}
static void set_hello_time(struct net_bridge *br, unsigned long val)
@@ -86,19 +88,20 @@ static void set_hello_time(struct net_bridge *br, unsigned long val)
br->bridge_hello_time = t;
}
-static ssize_t store_hello_time(struct class_device *cd, const char *buf,
+static ssize_t store_hello_time(struct device *d,
+ struct device_attribute *attr, const char *buf,
size_t len)
{
- return store_bridge_parm(cd, buf, len, set_hello_time);
+ return store_bridge_parm(d, buf, len, set_hello_time);
}
+static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
+ store_hello_time);
-static CLASS_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
- store_hello_time);
-
-static ssize_t show_max_age(struct class_device *cd, char *buf)
+static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%lu\n",
- jiffies_to_clock_t(to_bridge(cd)->max_age));
+ jiffies_to_clock_t(to_bridge(d)->max_age));
}
static void set_max_age(struct net_bridge *br, unsigned long val)
@@ -109,18 +112,17 @@ static void set_max_age(struct net_bridge *br, unsigned long val)
br->bridge_max_age = t;
}
-static ssize_t store_max_age(struct class_device *cd, const char *buf,
- size_t len)
+static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len)
{
- return store_bridge_parm(cd, buf, len, set_max_age);
+ return store_bridge_parm(d, buf, len, set_max_age);
}
+static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
-static CLASS_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age,
- store_max_age);
-
-static ssize_t show_ageing_time(struct class_device *cd, char *buf)
+static ssize_t show_ageing_time(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
}
@@ -129,17 +131,19 @@ static void set_ageing_time(struct net_bridge *br, unsigned long val)
br->ageing_time = clock_t_to_jiffies(val);
}
-static ssize_t store_ageing_time(struct class_device *cd, const char *buf,
- size_t len)
+static ssize_t store_ageing_time(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
- return store_bridge_parm(cd, buf, len, set_ageing_time);
+ return store_bridge_parm(d, buf, len, set_ageing_time);
}
+static DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
+ store_ageing_time);
-static CLASS_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
- store_ageing_time);
-static ssize_t show_stp_state(struct class_device *cd, char *buf)
+static ssize_t show_stp_state(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%d\n", br->stp_enabled);
}
@@ -148,18 +152,19 @@ static void set_stp_state(struct net_bridge *br, unsigned long val)
br->stp_enabled = val;
}
-static ssize_t store_stp_state(struct class_device *cd,
- const char *buf, size_t len)
+static ssize_t store_stp_state(struct device *d,
+ struct device_attribute *attr, const char *buf,
+ size_t len)
{
- return store_bridge_parm(cd, buf, len, set_stp_state);
+ return store_bridge_parm(d, buf, len, set_stp_state);
}
+static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
+ store_stp_state);
-static CLASS_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
- store_stp_state);
-
-static ssize_t show_priority(struct class_device *cd, char *buf)
+static ssize_t show_priority(struct device *d, struct device_attribute *attr,
+ char *buf)
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%d\n",
(br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
}
@@ -169,92 +174,107 @@ static void set_priority(struct net_bridge *br, unsigned long val)
br_stp_set_bridge_priority(br, (u16) val);
}
-static ssize_t store_priority(struct class_device *cd,
+static ssize_t store_priority(struct device *d, struct device_attribute *attr,
const char *buf, size_t len)
{
- return store_bridge_parm(cd, buf, len, set_priority);
+ return store_bridge_parm(d, buf, len, set_priority);
}
-static CLASS_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority,
- store_priority);
+static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
-static ssize_t show_root_id(struct class_device *cd, char *buf)
+static ssize_t show_root_id(struct device *d, struct device_attribute *attr,
+ char *buf)
{
- return br_show_bridge_id(buf, &to_bridge(cd)->designated_root);
+ return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
}
-static CLASS_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
+static DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
-static ssize_t show_bridge_id(struct class_device *cd, char *buf)
+static ssize_t show_bridge_id(struct device *d, struct device_attribute *attr,
+ char *buf)
{
- return br_show_bridge_id(buf, &to_bridge(cd)->bridge_id);
+ return br_show_bridge_id(buf, &to_bridge(d)->bridge_id);
}
-static CLASS_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
+static DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
-static ssize_t show_root_port(struct class_device *cd, char *buf)
+static ssize_t show_root_port(struct device *d, struct device_attribute *attr,
+ char *buf)
{
- return sprintf(buf, "%d\n", to_bridge(cd)->root_port);
+ return sprintf(buf, "%d\n", to_bridge(d)->root_port);
}
-static CLASS_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
+static DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
-static ssize_t show_root_path_cost(struct class_device *cd, char *buf)
+static ssize_t show_root_path_cost(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%d\n", to_bridge(cd)->root_path_cost);
+ return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
}
-static CLASS_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
+static DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
-static ssize_t show_topology_change(struct class_device *cd, char *buf)
+static ssize_t show_topology_change(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%d\n", to_bridge(cd)->topology_change);
+ return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
}
-static CLASS_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
+static DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
-static ssize_t show_topology_change_detected(struct class_device *cd, char *buf)
+static ssize_t show_topology_change_detected(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%d\n", br->topology_change_detected);
}
-static CLASS_DEVICE_ATTR(topology_change_detected, S_IRUGO, show_topology_change_detected, NULL);
+static DEVICE_ATTR(topology_change_detected, S_IRUGO,
+ show_topology_change_detected, NULL);
-static ssize_t show_hello_timer(struct class_device *cd, char *buf)
+static ssize_t show_hello_timer(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
}
-static CLASS_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
+static DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
-static ssize_t show_tcn_timer(struct class_device *cd, char *buf)
+static ssize_t show_tcn_timer(struct device *d, struct device_attribute *attr,
+ char *buf)
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
}
-static CLASS_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
+static DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
-static ssize_t show_topology_change_timer(struct class_device *cd, char *buf)
+static ssize_t show_topology_change_timer(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
}
-static CLASS_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, NULL);
+static DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
+ NULL);
-static ssize_t show_gc_timer(struct class_device *cd, char *buf)
+static ssize_t show_gc_timer(struct device *d, struct device_attribute *attr,
+ char *buf)
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer));
}
-static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
+static DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
-static ssize_t show_group_addr(struct class_device *cd, char *buf)
+static ssize_t show_group_addr(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%x:%x:%x:%x:%x:%x\n",
br->group_addr[0], br->group_addr[1],
br->group_addr[2], br->group_addr[3],
br->group_addr[4], br->group_addr[5]);
}
-static ssize_t store_group_addr(struct class_device *cd, const char *buf,
- size_t len)
+static ssize_t store_group_addr(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
- struct net_bridge *br = to_bridge(cd);
+ struct net_bridge *br = to_bridge(d);
unsigned new_addr[6];
int i;
@@ -286,28 +306,28 @@ static ssize_t store_group_addr(struct class_device *cd, const char *buf,
return len;
}
-static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
- show_group_addr, store_group_addr);
+static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
+ show_group_addr, store_group_addr);
static struct attribute *bridge_attrs[] = {
- &class_device_attr_forward_delay.attr,
- &class_device_attr_hello_time.attr,
- &class_device_attr_max_age.attr,
- &class_device_attr_ageing_time.attr,
- &class_device_attr_stp_state.attr,
- &class_device_attr_priority.attr,
- &class_device_attr_bridge_id.attr,
- &class_device_attr_root_id.attr,
- &class_device_attr_root_path_cost.attr,
- &class_device_attr_root_port.attr,
- &class_device_attr_topology_change.attr,
- &class_device_attr_topology_change_detected.attr,
- &class_device_attr_hello_timer.attr,
- &class_device_attr_tcn_timer.attr,
- &class_device_attr_topology_change_timer.attr,
- &class_device_attr_gc_timer.attr,
- &class_device_attr_group_addr.attr,
+ &dev_attr_forward_delay.attr,
+ &dev_attr_hello_time.attr,
+ &dev_attr_max_age.attr,
+ &dev_attr_ageing_time.attr,
+ &dev_attr_stp_state.attr,
+ &dev_attr_priority.attr,
+ &dev_attr_bridge_id.attr,
+ &dev_attr_root_id.attr,
+ &dev_attr_root_path_cost.attr,
+ &dev_attr_root_port.attr,
+ &dev_attr_topology_change.attr,
+ &dev_attr_topology_change_detected.attr,
+ &dev_attr_hello_timer.attr,
+ &dev_attr_tcn_timer.attr,
+ &dev_attr_topology_change_timer.attr,
+ &dev_attr_gc_timer.attr,
+ &dev_attr_group_addr.attr,
NULL
};
@@ -325,8 +345,8 @@ static struct attribute_group bridge_group = {
static ssize_t brforward_read(struct kobject *kobj, char *buf,
loff_t off, size_t count)
{
- struct class_device *cdev = to_class_dev(kobj);
- struct net_bridge *br = to_bridge(cdev);
+ struct device *dev = to_dev(kobj);
+ struct net_bridge *br = to_bridge(dev);
int n;
/* must read whole records */
@@ -363,7 +383,7 @@ static struct bin_attribute bridge_forward = {
*/
int br_sysfs_addbr(struct net_device *dev)
{
- struct kobject *brobj = &dev->class_dev.kobj;
+ struct kobject *brobj = &dev->dev.kobj;
struct net_bridge *br = netdev_priv(dev);
int err;
@@ -395,9 +415,9 @@ int br_sysfs_addbr(struct net_device *dev)
}
return 0;
out3:
- sysfs_remove_bin_file(&dev->class_dev.kobj, &bridge_forward);
+ sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward);
out2:
- sysfs_remove_group(&dev->class_dev.kobj, &bridge_group);
+ sysfs_remove_group(&dev->dev.kobj, &bridge_group);
out1:
return err;
@@ -405,7 +425,7 @@ int br_sysfs_addbr(struct net_device *dev)
void br_sysfs_delbr(struct net_device *dev)
{
- struct kobject *kobj = &dev->class_dev.kobj;
+ struct kobject *kobj = &dev->dev.kobj;
struct net_bridge *br = netdev_priv(dev);
kobject_unregister(&br->ifobj);
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index c51c9e42aeb..0bc2aef8f9f 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -211,7 +211,7 @@ int br_sysfs_addif(struct net_bridge_port *p)
struct brport_attribute **a;
int err;
- err = sysfs_create_link(&p->kobj, &br->dev->class_dev.kobj,
+ err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj,
SYSFS_BRIDGE_PORT_LINK);
if (err)
goto out2;
diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c
index e4c642448e1..6afa4d017d4 100644
--- a/net/bridge/netfilter/ebt_ip.c
+++ b/net/bridge/netfilter/ebt_ip.c
@@ -93,6 +93,7 @@ static int ebt_ip_check(const char *tablename, unsigned int hookmask,
return -EINVAL;
if (info->protocol != IPPROTO_TCP &&
info->protocol != IPPROTO_UDP &&
+ info->protocol != IPPROTO_UDPLITE &&
info->protocol != IPPROTO_SCTP &&
info->protocol != IPPROTO_DCCP)
return -EINVAL;
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index a184f879f25..985df82e427 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -96,6 +96,7 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
NIPQUAD(ih->daddr), ih->tos, ih->protocol);
if (ih->protocol == IPPROTO_TCP ||
ih->protocol == IPPROTO_UDP ||
+ ih->protocol == IPPROTO_UDPLITE ||
ih->protocol == IPPROTO_SCTP ||
ih->protocol == IPPROTO_DCCP) {
struct tcpudphdr _ports, *pptr;
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index bee558a4180..6c84ccb8c9d 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -610,7 +610,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
struct ebt_entry_target *t;
struct ebt_target *target;
unsigned int i, j, hook = 0, hookmask = 0;
- size_t gap = e->next_offset - e->target_offset;
+ size_t gap;
int ret;
/* don't mess with the struct ebt_entries */
@@ -660,6 +660,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
if (ret != 0)
goto cleanup_watchers;
t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
+ gap = e->next_offset - e->target_offset;
target = find_target_lock(t->u.name, &ret, &ebt_mutex);
if (!target)
goto cleanup_watchers;
diff --git a/net/core/dev.c b/net/core/dev.c
index e660cb57e42..1e94a1b9a0f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -751,7 +751,7 @@ int dev_change_name(struct net_device *dev, char *newname)
else
strlcpy(dev->name, newname, IFNAMSIZ);
- err = class_device_rename(&dev->class_dev, dev->name);
+ err = device_rename(&dev->dev, dev->name);
if (!err) {
hlist_del(&dev->name_hlist);
hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
@@ -3221,8 +3221,8 @@ void free_netdev(struct net_device *dev)
BUG_ON(dev->reg_state != NETREG_UNREGISTERED);
dev->reg_state = NETREG_RELEASED;
- /* will free via class release */
- class_device_put(&dev->class_dev);
+ /* will free via device release */
+ put_device(&dev->dev);
#else
kfree((char *)dev - dev->padded);
#endif
@@ -3247,7 +3247,7 @@ void synchronize_net(void)
* unregister_netdev() instead of this.
*/
-int unregister_netdevice(struct net_device *dev)
+void unregister_netdevice(struct net_device *dev)
{
struct net_device *d, **dp;
@@ -3258,7 +3258,9 @@ int unregister_netdevice(struct net_device *dev)
if (dev->reg_state == NETREG_UNINITIALIZED) {
printk(KERN_DEBUG "unregister_netdevice: device %s/%p never "
"was registered\n", dev->name, dev);
- return -ENODEV;
+
+ WARN_ON(1);
+ return;
}
BUG_ON(dev->reg_state != NETREG_REGISTERED);
@@ -3280,11 +3282,7 @@ int unregister_netdevice(struct net_device *dev)
break;
}
}
- if (!d) {
- printk(KERN_ERR "unregister net_device: '%s' not found\n",
- dev->name);
- return -ENODEV;
- }
+ BUG_ON(!d);
dev->reg_state = NETREG_UNREGISTERING;
@@ -3316,7 +3314,6 @@ int unregister_netdevice(struct net_device *dev)
synchronize_net();
dev_put(dev);
- return 0;
}
/**
diff --git a/net/core/dst.c b/net/core/dst.c
index 836ec660692..1a53fb39b7e 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -99,7 +99,14 @@ static void dst_run_gc(unsigned long dummy)
printk("dst_total: %d/%d %ld\n",
atomic_read(&dst_total), delayed, dst_gc_timer_expires);
#endif
- mod_timer(&dst_gc_timer, jiffies + dst_gc_timer_expires);
+ /* if the next desired timer is more than 4 seconds in the future
+ * then round the timer to whole seconds
+ */
+ if (dst_gc_timer_expires > 4*HZ)
+ mod_timer(&dst_gc_timer,
+ round_jiffies(jiffies + dst_gc_timer_expires));
+ else
+ mod_timer(&dst_gc_timer, jiffies + dst_gc_timer_expires);
out:
spin_unlock(&dst_lock);
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 1df6cd4568d..215f1bff048 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -331,7 +331,7 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*frh), flags);
if (nlh == NULL)
- return -1;
+ return -EMSGSIZE;
frh = nlmsg_data(nlh);
frh->table = rule->table;
@@ -359,7 +359,8 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
return nlmsg_end(skb, nlh);
nla_put_failure:
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
int fib_rules_dump(struct sk_buff *skb, struct netlink_callback *cb, int family)
@@ -405,9 +406,12 @@ static void notify_rule_change(int event, struct fib_rule *rule,
goto errout;
err = fib_nl_fill_rule(skb, rule, pid, nlh->nlmsg_seq, event, 0, ops);
- /* failure implies BUG in fib_rule_nlmsg_size() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in fib_rule_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL);
errout:
if (err < 0)
diff --git a/net/core/flow.c b/net/core/flow.c
index d137f971f97..5d25697920b 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -231,22 +231,16 @@ nocache:
err = resolver(key, family, dir, &obj, &obj_ref);
- if (fle) {
- 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);
- }
+ if (fle && !err) {
+ 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();
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 0ab1987b934..054d46493d2 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -577,9 +577,10 @@ void neigh_destroy(struct neighbour *neigh)
while ((hh = neigh->hh) != NULL) {
neigh->hh = hh->hh_next;
hh->hh_next = NULL;
- write_lock_bh(&hh->hh_lock);
+
+ write_seqlock_bh(&hh->hh_lock);
hh->hh_output = neigh_blackhole;
- write_unlock_bh(&hh->hh_lock);
+ write_sequnlock_bh(&hh->hh_lock);
if (atomic_dec_and_test(&hh->hh_refcnt))
kfree(hh);
}
@@ -695,7 +696,10 @@ next_elt:
if (!expire)
expire = 1;
- mod_timer(&tbl->gc_timer, now + expire);
+ if (expire>HZ)
+ mod_timer(&tbl->gc_timer, round_jiffies(now + expire));
+ else
+ mod_timer(&tbl->gc_timer, now + expire);
write_unlock(&tbl->lock);
}
@@ -897,9 +901,9 @@ static void neigh_update_hhs(struct neighbour *neigh)
if (update) {
for (hh = neigh->hh; hh; hh = hh->hh_next) {
- write_lock_bh(&hh->hh_lock);
+ write_seqlock_bh(&hh->hh_lock);
update(hh, neigh->dev, neigh->ha);
- write_unlock_bh(&hh->hh_lock);
+ write_sequnlock_bh(&hh->hh_lock);
}
}
}
@@ -1089,7 +1093,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
break;
if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) {
- rwlock_init(&hh->hh_lock);
+ seqlock_init(&hh->hh_lock);
hh->hh_type = protocol;
atomic_set(&hh->hh_refcnt, 0);
hh->hh_next = NULL;
@@ -1636,7 +1640,7 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
ndtmsg = nlmsg_data(nlh);
@@ -1705,7 +1709,8 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
nla_put_failure:
read_unlock_bh(&tbl->lock);
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
static int neightbl_fill_param_info(struct sk_buff *skb,
@@ -1719,7 +1724,7 @@ static int neightbl_fill_param_info(struct sk_buff *skb,
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
ndtmsg = nlmsg_data(nlh);
@@ -1736,7 +1741,8 @@ static int neightbl_fill_param_info(struct sk_buff *skb,
return nlmsg_end(skb, nlh);
errout:
read_unlock_bh(&tbl->lock);
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
@@ -1954,7 +1960,7 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
ndm = nlmsg_data(nlh);
ndm->ndm_family = neigh->ops->family;
@@ -1986,7 +1992,8 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
return nlmsg_end(skb, nlh);
nla_put_failure:
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
@@ -2428,9 +2435,12 @@ static void __neigh_notify(struct neighbour *n, int type, int flags)
goto errout;
err = neigh_fill_info(skb, n, 0, 0, type, flags);
- /* failure implies BUG in neigh_nlmsg_size() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
errout:
if (err < 0)
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index f47f319bb7d..44db095a8f7 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -18,9 +18,6 @@
#include <linux/wireless.h>
#include <net/iw_handler.h>
-#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
-
static const char fmt_hex[] = "%#x\n";
static const char fmt_long_hex[] = "%#lx\n";
static const char fmt_dec[] = "%d\n";
@@ -32,10 +29,11 @@ static inline int dev_isalive(const struct net_device *dev)
}
/* use same locking rules as GIF* ioctl's */
-static ssize_t netdev_show(const struct class_device *cd, char *buf,
+static ssize_t netdev_show(const struct device *dev,
+ struct device_attribute *attr, char *buf,
ssize_t (*format)(const struct net_device *, char *))
{
- struct net_device *net = to_net_dev(cd);
+ struct net_device *net = to_net_dev(dev);
ssize_t ret = -EINVAL;
read_lock(&dev_base_lock);
@@ -52,14 +50,15 @@ static ssize_t format_##field(const struct net_device *net, char *buf) \
{ \
return sprintf(buf, format_string, net->field); \
} \
-static ssize_t show_##field(struct class_device *cd, char *buf) \
+static ssize_t show_##field(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
{ \
- return netdev_show(cd, buf, format_##field); \
+ return netdev_show(dev, attr, buf, format_##field); \
}
/* use same locking and permission rules as SIF* ioctl's */
-static ssize_t netdev_store(struct class_device *dev,
+static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t len,
int (*set)(struct net_device *, unsigned long))
{
@@ -104,7 +103,8 @@ static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
return cp - buf;
}
-static ssize_t show_address(struct class_device *dev, char *buf)
+static ssize_t show_address(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct net_device *net = to_net_dev(dev);
ssize_t ret = -EINVAL;
@@ -116,7 +116,8 @@ static ssize_t show_address(struct class_device *dev, char *buf)
return ret;
}
-static ssize_t show_broadcast(struct class_device *dev, char *buf)
+static ssize_t show_broadcast(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct net_device *net = to_net_dev(dev);
if (dev_isalive(net))
@@ -124,7 +125,8 @@ static ssize_t show_broadcast(struct class_device *dev, char *buf)
return -EINVAL;
}
-static ssize_t show_carrier(struct class_device *dev, char *buf)
+static ssize_t show_carrier(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct net_device *netdev = to_net_dev(dev);
if (netif_running(netdev)) {
@@ -133,7 +135,8 @@ static ssize_t show_carrier(struct class_device *dev, char *buf)
return -EINVAL;
}
-static ssize_t show_dormant(struct class_device *dev, char *buf)
+static ssize_t show_dormant(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct net_device *netdev = to_net_dev(dev);
@@ -153,7 +156,8 @@ static const char *operstates[] = {
"up"
};
-static ssize_t show_operstate(struct class_device *dev, char *buf)
+static ssize_t show_operstate(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
const struct net_device *netdev = to_net_dev(dev);
unsigned char operstate;
@@ -178,9 +182,10 @@ static int change_mtu(struct net_device *net, unsigned long new_mtu)
return dev_set_mtu(net, (int) new_mtu);
}
-static ssize_t store_mtu(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_mtu(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
{
- return netdev_store(dev, buf, len, change_mtu);
+ return netdev_store(dev, attr, buf, len, change_mtu);
}
NETDEVICE_SHOW(flags, fmt_hex);
@@ -190,9 +195,10 @@ static int change_flags(struct net_device *net, unsigned long new_flags)
return dev_change_flags(net, (unsigned) new_flags);
}
-static ssize_t store_flags(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_flags(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
{
- return netdev_store(dev, buf, len, change_flags);
+ return netdev_store(dev, attr, buf, len, change_flags);
}
NETDEVICE_SHOW(tx_queue_len, fmt_ulong);
@@ -203,9 +209,11 @@ static int change_tx_queue_len(struct net_device *net, unsigned long new_len)
return 0;
}
-static ssize_t store_tx_queue_len(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_tx_queue_len(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
- return netdev_store(dev, buf, len, change_tx_queue_len);
+ return netdev_store(dev, attr, buf, len, change_tx_queue_len);
}
NETDEVICE_SHOW(weight, fmt_dec);
@@ -216,12 +224,13 @@ static int change_weight(struct net_device *net, unsigned long new_weight)
return 0;
}
-static ssize_t store_weight(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_weight(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
{
- return netdev_store(dev, buf, len, change_weight);
+ return netdev_store(dev, attr, buf, len, change_weight);
}
-static struct class_device_attribute net_class_attributes[] = {
+static struct device_attribute net_class_attributes[] = {
__ATTR(addr_len, S_IRUGO, show_addr_len, NULL),
__ATTR(iflink, S_IRUGO, show_iflink, NULL),
__ATTR(ifindex, S_IRUGO, show_ifindex, NULL),
@@ -242,10 +251,11 @@ static struct class_device_attribute net_class_attributes[] = {
};
/* Show a given an attribute in the statistics group */
-static ssize_t netstat_show(const struct class_device *cd, char *buf,
+static ssize_t netstat_show(const struct device *d,
+ struct device_attribute *attr, char *buf,
unsigned long offset)
{
- struct net_device *dev = to_net_dev(cd);
+ struct net_device *dev = to_net_dev(d);
struct net_device_stats *stats;
ssize_t ret = -EINVAL;
@@ -265,12 +275,13 @@ static ssize_t netstat_show(const struct class_device *cd, char *buf,
/* generate a read-only statistics attribute */
#define NETSTAT_ENTRY(name) \
-static ssize_t show_##name(struct class_device *cd, char *buf) \
+static ssize_t show_##name(struct device *d, \
+ struct device_attribute *attr, char *buf) \
{ \
- return netstat_show(cd, buf, \
+ return netstat_show(d, attr, buf, \
offsetof(struct net_device_stats, name)); \
} \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
NETSTAT_ENTRY(rx_packets);
NETSTAT_ENTRY(tx_packets);
@@ -297,29 +308,29 @@ NETSTAT_ENTRY(rx_compressed);
NETSTAT_ENTRY(tx_compressed);
static struct attribute *netstat_attrs[] = {
- &class_device_attr_rx_packets.attr,
- &class_device_attr_tx_packets.attr,
- &class_device_attr_rx_bytes.attr,
- &class_device_attr_tx_bytes.attr,
- &class_device_attr_rx_errors.attr,
- &class_device_attr_tx_errors.attr,
- &class_device_attr_rx_dropped.attr,
- &class_device_attr_tx_dropped.attr,
- &class_device_attr_multicast.attr,
- &class_device_attr_collisions.attr,
- &class_device_attr_rx_length_errors.attr,
- &class_device_attr_rx_over_errors.attr,
- &class_device_attr_rx_crc_errors.attr,
- &class_device_attr_rx_frame_errors.attr,
- &class_device_attr_rx_fifo_errors.attr,
- &class_device_attr_rx_missed_errors.attr,
- &class_device_attr_tx_aborted_errors.attr,
- &class_device_attr_tx_carrier_errors.attr,
- &class_device_attr_tx_fifo_errors.attr,
- &class_device_attr_tx_heartbeat_errors.attr,
- &class_device_attr_tx_window_errors.attr,
- &class_device_attr_rx_compressed.attr,
- &class_device_attr_tx_compressed.attr,
+ &dev_attr_rx_packets.attr,
+ &dev_attr_tx_packets.attr,
+ &dev_attr_rx_bytes.attr,
+ &dev_attr_tx_bytes.attr,
+ &dev_attr_rx_errors.attr,
+ &dev_attr_tx_errors.attr,
+ &dev_attr_rx_dropped.attr,
+ &dev_attr_tx_dropped.attr,
+ &dev_attr_multicast.attr,
+ &dev_attr_collisions.attr,
+ &dev_attr_rx_length_errors.attr,
+ &dev_attr_rx_over_errors.attr,
+ &dev_attr_rx_crc_errors.attr,
+ &dev_attr_rx_frame_errors.attr,
+ &dev_attr_rx_fifo_errors.attr,
+ &dev_attr_rx_missed_errors.attr,
+ &dev_attr_tx_aborted_errors.attr,
+ &dev_attr_tx_carrier_errors.attr,
+ &dev_attr_tx_fifo_errors.attr,
+ &dev_attr_tx_heartbeat_errors.attr,
+ &dev_attr_tx_window_errors.attr,
+ &dev_attr_rx_compressed.attr,
+ &dev_attr_tx_compressed.attr,
NULL
};
@@ -331,11 +342,11 @@ static struct attribute_group netstat_group = {
#ifdef WIRELESS_EXT
/* helper function that does all the locking etc for wireless stats */
-static ssize_t wireless_show(struct class_device *cd, char *buf,
+static ssize_t wireless_show(struct device *d, char *buf,
ssize_t (*format)(const struct iw_statistics *,
char *))
{
- struct net_device *dev = to_net_dev(cd);
+ struct net_device *dev = to_net_dev(d);
const struct iw_statistics *iw = NULL;
ssize_t ret = -EINVAL;
@@ -358,11 +369,12 @@ static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \
{ \
return sprintf(buf, format_string, iw->field); \
} \
-static ssize_t show_iw_##name(struct class_device *cd, char *buf) \
+static ssize_t show_iw_##name(struct device *d, \
+ struct device_attribute *attr, char *buf) \
{ \
- return wireless_show(cd, buf, format_iw_##name); \
+ return wireless_show(d, buf, format_iw_##name); \
} \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL)
WIRELESS_SHOW(status, status, fmt_hex);
WIRELESS_SHOW(link, qual.qual, fmt_dec);
@@ -376,16 +388,16 @@ WIRELESS_SHOW(retries, discard.retries, fmt_dec);
WIRELESS_SHOW(beacon, miss.beacon, fmt_dec);
static struct attribute *wireless_attrs[] = {
- &class_device_attr_status.attr,
- &class_device_attr_link.attr,
- &class_device_attr_level.attr,
- &class_device_attr_noise.attr,
- &class_device_attr_nwid.attr,
- &class_device_attr_crypt.attr,
- &class_device_attr_fragment.attr,
- &class_device_attr_retries.attr,
- &class_device_attr_misc.attr,
- &class_device_attr_beacon.attr,
+ &dev_attr_status.attr,
+ &dev_attr_link.attr,
+ &dev_attr_level.attr,
+ &dev_attr_noise.attr,
+ &dev_attr_nwid.attr,
+ &dev_attr_crypt.attr,
+ &dev_attr_fragment.attr,
+ &dev_attr_retries.attr,
+ &dev_attr_misc.attr,
+ &dev_attr_beacon.attr,
NULL
};
@@ -396,10 +408,10 @@ static struct attribute_group wireless_group = {
#endif
#ifdef CONFIG_HOTPLUG
-static int netdev_uevent(struct class_device *cd, char **envp,
+static int netdev_uevent(struct device *d, char **envp,
int num_envp, char *buf, int size)
{
- struct net_device *dev = to_net_dev(cd);
+ struct net_device *dev = to_net_dev(d);
int i = 0;
int n;
@@ -419,12 +431,11 @@ static int netdev_uevent(struct class_device *cd, char **envp,
/*
* netdev_release -- destroy and free a dead device.
- * Called when last reference to class_device kobject is gone.
+ * Called when last reference to device kobject is gone.
*/
-static void netdev_release(struct class_device *cd)
+static void netdev_release(struct device *d)
{
- struct net_device *dev
- = container_of(cd, struct net_device, class_dev);
+ struct net_device *dev = to_net_dev(d);
BUG_ON(dev->reg_state != NETREG_RELEASED);
@@ -433,31 +444,31 @@ static void netdev_release(struct class_device *cd)
static struct class net_class = {
.name = "net",
- .release = netdev_release,
- .class_dev_attrs = net_class_attributes,
+ .dev_release = netdev_release,
+ .dev_attrs = net_class_attributes,
#ifdef CONFIG_HOTPLUG
- .uevent = netdev_uevent,
+ .dev_uevent = netdev_uevent,
#endif
};
void netdev_unregister_sysfs(struct net_device * net)
{
- class_device_del(&(net->class_dev));
+ device_del(&(net->dev));
}
/* Create sysfs entries for network device. */
int netdev_register_sysfs(struct net_device *net)
{
- struct class_device *class_dev = &(net->class_dev);
+ struct device *dev = &(net->dev);
struct attribute_group **groups = net->sysfs_groups;
- class_device_initialize(class_dev);
- class_dev->class = &net_class;
- class_dev->class_data = net;
- class_dev->groups = groups;
+ device_initialize(dev);
+ dev->class = &net_class;
+ dev->platform_data = net;
+ dev->groups = groups;
BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ);
- strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE);
+ strlcpy(dev->bus_id, net->name, BUS_ID_SIZE);
if (net->get_stats)
*groups++ = &netstat_group;
@@ -467,7 +478,7 @@ int netdev_register_sysfs(struct net_device *net)
*groups++ = &wireless_group;
#endif
- return class_device_add(class_dev);
+ return device_add(dev);
}
int netdev_sysfs_init(void)
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index b3c559b9ac3..823215d8e90 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -55,6 +55,7 @@ static void queue_process(struct work_struct *work)
struct netpoll_info *npinfo =
container_of(work, struct netpoll_info, tx_work.work);
struct sk_buff *skb;
+ unsigned long flags;
while ((skb = skb_dequeue(&npinfo->txq))) {
struct net_device *dev = skb->dev;
@@ -64,15 +65,19 @@ static void queue_process(struct work_struct *work)
continue;
}
- netif_tx_lock_bh(dev);
+ local_irq_save(flags);
+ netif_tx_lock(dev);
if (netif_queue_stopped(dev) ||
dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) {
skb_queue_head(&npinfo->txq, skb);
- netif_tx_unlock_bh(dev);
+ netif_tx_unlock(dev);
+ local_irq_restore(flags);
schedule_delayed_work(&npinfo->tx_work, HZ/10);
return;
}
+ netif_tx_unlock(dev);
+ local_irq_restore(flags);
}
}
@@ -242,22 +247,28 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
/* don't get messages out of order, and no recursion */
if (skb_queue_len(&npinfo->txq) == 0 &&
- npinfo->poll_owner != smp_processor_id() &&
- netif_tx_trylock(dev)) {
- /* try until next clock tick */
- for (tries = jiffies_to_usecs(1)/USEC_PER_POLL; tries > 0; --tries) {
- if (!netif_queue_stopped(dev))
- status = dev->hard_start_xmit(skb, dev);
+ npinfo->poll_owner != smp_processor_id()) {
+ unsigned long flags;
- if (status == NETDEV_TX_OK)
- break;
+ local_irq_save(flags);
+ if (netif_tx_trylock(dev)) {
+ /* try until next clock tick */
+ for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
+ tries > 0; --tries) {
+ if (!netif_queue_stopped(dev))
+ status = dev->hard_start_xmit(skb, dev);
- /* tickle device maybe there is some cleanup */
- netpoll_poll(np);
+ if (status == NETDEV_TX_OK)
+ break;
+
+ /* tickle device maybe there is some cleanup */
+ netpoll_poll(np);
- udelay(USEC_PER_POLL);
+ udelay(USEC_PER_POLL);
+ }
+ netif_tx_unlock(dev);
}
- netif_tx_unlock(dev);
+ local_irq_restore(flags);
}
if (status != NETDEV_TX_OK) {
@@ -330,6 +341,7 @@ static void arp_reply(struct sk_buff *skb)
unsigned char *arp_ptr;
int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
__be32 sip, tip;
+ unsigned char *sha;
struct sk_buff *send_skb;
struct netpoll *np = NULL;
@@ -356,9 +368,14 @@ static void arp_reply(struct sk_buff *skb)
arp->ar_op != htons(ARPOP_REQUEST))
return;
- arp_ptr = (unsigned char *)(arp+1) + skb->dev->addr_len;
+ arp_ptr = (unsigned char *)(arp+1);
+ /* save the location of the src hw addr */
+ sha = arp_ptr;
+ arp_ptr += skb->dev->addr_len;
memcpy(&sip, arp_ptr, 4);
- arp_ptr += 4 + skb->dev->addr_len;
+ arp_ptr += 4;
+ /* if we actually cared about dst hw addr, it would get copied here */
+ arp_ptr += skb->dev->addr_len;
memcpy(&tip, arp_ptr, 4);
/* Should we ignore arp? */
@@ -381,7 +398,7 @@ static void arp_reply(struct sk_buff *skb)
if (np->dev->hard_header &&
np->dev->hard_header(send_skb, skb->dev, ptype,
- np->remote_mac, np->local_mac,
+ sha, np->local_mac,
send_skb->len) < 0) {
kfree_skb(send_skb);
return;
@@ -405,7 +422,7 @@ static void arp_reply(struct sk_buff *skb)
arp_ptr += np->dev->addr_len;
memcpy(arp_ptr, &tip, 4);
arp_ptr += 4;
- memcpy(arp_ptr, np->remote_mac, np->dev->addr_len);
+ memcpy(arp_ptr, sha, np->dev->addr_len);
arp_ptr += np->dev->addr_len;
memcpy(arp_ptr, &sip, 4);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 1897a3a385d..04d4b93c68e 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -148,6 +148,7 @@
#include <linux/seq_file.h>
#include <linux/wait.h>
#include <linux/etherdevice.h>
+#include <linux/kthread.h>
#include <net/checksum.h>
#include <net/ipv6.h>
#include <net/addrconf.h>
@@ -360,8 +361,7 @@ struct pktgen_thread {
spinlock_t if_lock;
struct list_head if_list; /* All device here */
struct list_head th_list;
- int removed;
- char name[32];
+ struct task_struct *tsk;
char result[512];
u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */
@@ -1689,7 +1689,7 @@ static int pktgen_thread_show(struct seq_file *seq, void *v)
BUG_ON(!t);
seq_printf(seq, "Name: %s max_before_softirq: %d\n",
- t->name, t->max_before_softirq);
+ t->tsk->comm, t->max_before_softirq);
seq_printf(seq, "Running: ");
@@ -3112,7 +3112,7 @@ static void pktgen_rem_thread(struct pktgen_thread *t)
{
/* Remove from the thread list */
- remove_proc_entry(t->name, pg_proc_dir);
+ remove_proc_entry(t->tsk->comm, pg_proc_dir);
mutex_lock(&pktgen_thread_lock);
@@ -3260,58 +3260,40 @@ out:;
* Main loop of the thread goes here
*/
-static void pktgen_thread_worker(struct pktgen_thread *t)
+static int pktgen_thread_worker(void *arg)
{
DEFINE_WAIT(wait);
+ struct pktgen_thread *t = arg;
struct pktgen_dev *pkt_dev = NULL;
int cpu = t->cpu;
- sigset_t tmpsig;
u32 max_before_softirq;
u32 tx_since_softirq = 0;
- daemonize("pktgen/%d", cpu);
-
- /* Block all signals except SIGKILL, SIGSTOP and SIGTERM */
-
- spin_lock_irq(&current->sighand->siglock);
- tmpsig = current->blocked;
- siginitsetinv(&current->blocked,
- sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGTERM));
-
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- /* Migrate to the right CPU */
- set_cpus_allowed(current, cpumask_of_cpu(cpu));
- if (smp_processor_id() != cpu)
- BUG();
+ BUG_ON(smp_processor_id() != cpu);
init_waitqueue_head(&t->queue);
- t->control &= ~(T_TERMINATE);
- t->control &= ~(T_RUN);
- t->control &= ~(T_STOP);
- t->control &= ~(T_REMDEVALL);
- t->control &= ~(T_REMDEV);
-
t->pid = current->pid;
PG_DEBUG(printk("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid));
max_before_softirq = t->max_before_softirq;
- __set_current_state(TASK_INTERRUPTIBLE);
- mb();
+ set_current_state(TASK_INTERRUPTIBLE);
- while (1) {
-
- __set_current_state(TASK_RUNNING);
+ while (!kthread_should_stop()) {
+ pkt_dev = next_to_run(t);
- /*
- * Get next dev to xmit -- if any.
- */
+ if (!pkt_dev &&
+ (t->control & (T_STOP | T_RUN | T_REMDEVALL | T_REMDEV))
+ == 0) {
+ prepare_to_wait(&(t->queue), &wait,
+ TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ / 10);
+ finish_wait(&(t->queue), &wait);
+ }
- pkt_dev = next_to_run(t);
+ __set_current_state(TASK_RUNNING);
if (pkt_dev) {
@@ -3329,21 +3311,8 @@ static void pktgen_thread_worker(struct pktgen_thread *t)
do_softirq();
tx_since_softirq = 0;
}
- } else {
- prepare_to_wait(&(t->queue), &wait, TASK_INTERRUPTIBLE);
- schedule_timeout(HZ / 10);
- finish_wait(&(t->queue), &wait);
}
- /*
- * Back from sleep, either due to the timeout or signal.
- * We check if we have any "posted" work for us.
- */
-
- if (t->control & T_TERMINATE || signal_pending(current))
- /* we received a request to terminate ourself */
- break;
-
if (t->control & T_STOP) {
pktgen_stop(t);
t->control &= ~(T_STOP);
@@ -3364,20 +3333,19 @@ static void pktgen_thread_worker(struct pktgen_thread *t)
t->control &= ~(T_REMDEV);
}
- if (need_resched())
- schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
}
- PG_DEBUG(printk("pktgen: %s stopping all device\n", t->name));
+ PG_DEBUG(printk("pktgen: %s stopping all device\n", t->tsk->comm));
pktgen_stop(t);
- PG_DEBUG(printk("pktgen: %s removing all device\n", t->name));
+ PG_DEBUG(printk("pktgen: %s removing all device\n", t->tsk->comm));
pktgen_rem_all_ifs(t);
- PG_DEBUG(printk("pktgen: %s removing thread.\n", t->name));
+ PG_DEBUG(printk("pktgen: %s removing thread.\n", t->tsk->comm));
pktgen_rem_thread(t);
- t->removed = 1;
+ return 0;
}
static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
@@ -3495,37 +3463,11 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
return add_dev_to_thread(t, pkt_dev);
}
-static struct pktgen_thread *__init pktgen_find_thread(const char *name)
+static int __init pktgen_create_thread(int cpu)
{
struct pktgen_thread *t;
-
- mutex_lock(&pktgen_thread_lock);
-
- list_for_each_entry(t, &pktgen_threads, th_list)
- if (strcmp(t->name, name) == 0) {
- mutex_unlock(&pktgen_thread_lock);
- return t;
- }
-
- mutex_unlock(&pktgen_thread_lock);
- return NULL;
-}
-
-static int __init pktgen_create_thread(const char *name, int cpu)
-{
- int err;
- struct pktgen_thread *t = NULL;
struct proc_dir_entry *pe;
-
- if (strlen(name) > 31) {
- printk("pktgen: ERROR: Thread name cannot be more than 31 characters.\n");
- return -EINVAL;
- }
-
- if (pktgen_find_thread(name)) {
- printk("pktgen: ERROR: thread: %s already exists\n", name);
- return -EINVAL;
- }
+ struct task_struct *p;
t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL);
if (!t) {
@@ -3533,14 +3475,29 @@ static int __init pktgen_create_thread(const char *name, int cpu)
return -ENOMEM;
}
- strcpy(t->name, name);
spin_lock_init(&t->if_lock);
t->cpu = cpu;
- pe = create_proc_entry(t->name, 0600, pg_proc_dir);
+ INIT_LIST_HEAD(&t->if_list);
+
+ list_add_tail(&t->th_list, &pktgen_threads);
+
+ p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
+ if (IS_ERR(p)) {
+ printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu);
+ list_del(&t->th_list);
+ kfree(t);
+ return PTR_ERR(p);
+ }
+ kthread_bind(p, cpu);
+ t->tsk = p;
+
+ pe = create_proc_entry(t->tsk->comm, 0600, pg_proc_dir);
if (!pe) {
printk("pktgen: cannot create %s/%s procfs entry.\n",
- PG_PROC_DIR, t->name);
+ PG_PROC_DIR, t->tsk->comm);
+ kthread_stop(p);
+ list_del(&t->th_list);
kfree(t);
return -EINVAL;
}
@@ -3548,21 +3505,7 @@ static int __init pktgen_create_thread(const char *name, int cpu)
pe->proc_fops = &pktgen_thread_fops;
pe->data = t;
- INIT_LIST_HEAD(&t->if_list);
-
- list_add_tail(&t->th_list, &pktgen_threads);
-
- t->removed = 0;
-
- err = kernel_thread((void *)pktgen_thread_worker, (void *)t,
- CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
- if (err < 0) {
- printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu);
- remove_proc_entry(t->name, pg_proc_dir);
- list_del(&t->th_list);
- kfree(t);
- return err;
- }
+ wake_up_process(p);
return 0;
}
@@ -3643,10 +3586,8 @@ static int __init pg_init(void)
for_each_online_cpu(cpu) {
int err;
- char buf[30];
- sprintf(buf, "kpktgend_%i", cpu);
- err = pktgen_create_thread(buf, cpu);
+ err = pktgen_create_thread(cpu);
if (err)
printk("pktgen: WARNING: Cannot create thread for cpu %d (%d)\n",
cpu, err);
@@ -3674,9 +3615,8 @@ static void __exit pg_cleanup(void)
list_for_each_safe(q, n, &pktgen_threads) {
t = list_entry(q, struct pktgen_thread, th_list);
- t->control |= (T_TERMINATE);
-
- wait_event_interruptible_timeout(queue, (t->removed == 1), HZ);
+ kthread_stop(t->tsk);
+ kfree(t);
}
/* Un-register us from receiving netdevice events */
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index e76539a5eb5..9bf9ae05f15 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -320,7 +320,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
ifm = nlmsg_data(nlh);
ifm->ifi_family = AF_UNSPEC;
@@ -384,7 +384,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
return nlmsg_end(skb, nlh);
nla_put_failure:
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
@@ -633,9 +634,12 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK,
NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0);
- /* failure impilies BUG in if_nlmsg_size or wireless_rtnetlink_get */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in if_nlmsg_size */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(nskb);
+ goto errout;
+ }
err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
errout:
kfree(iw_buf);
@@ -678,9 +682,12 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
goto errout;
err = rtnl_fill_ifinfo(skb, dev, NULL, 0, type, 0, 0, change, 0);
- /* failure implies BUG in if_nlmsg_size() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in if_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
errout:
if (err < 0)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index de7801d589e..f3404ae9f19 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -268,7 +268,7 @@ nodata:
struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
unsigned int length, gfp_t gfp_mask)
{
- int node = dev->class_dev.dev ? dev_to_node(dev->class_dev.dev) : -1;
+ int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
struct sk_buff *skb;
skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node);
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 1f4727ddbdb..a086c6312d3 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -223,7 +223,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av,
gap = -new_head;
}
new_head += DCCP_MAX_ACKVEC_LEN;
- }
+ }
av->dccpav_buf_head = new_head;
@@ -336,7 +336,7 @@ out_duplicate:
void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, int len)
{
dccp_pr_debug_cat("ACK vector len=%d, ackno=%llu |", len,
- (unsigned long long)ackno);
+ (unsigned long long)ackno);
while (len--) {
const u8 state = (*vector & DCCP_ACKVEC_STATE_MASK) >> 6;
diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h
index bcc2d12ae81..c65cb2453e4 100644
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -43,8 +43,6 @@ struct ccid_operations {
unsigned char* value);
int (*ccid_hc_rx_insert_options)(struct sock *sk,
struct sk_buff *skb);
- int (*ccid_hc_tx_insert_options)(struct sock *sk,
- struct sk_buff *skb);
void (*ccid_hc_tx_packet_recv)(struct sock *sk,
struct sk_buff *skb);
int (*ccid_hc_tx_parse_options)(struct sock *sk,
@@ -146,14 +144,6 @@ static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk,
return rc;
}
-static inline int ccid_hc_tx_insert_options(struct ccid *ccid, struct sock *sk,
- struct sk_buff *skb)
-{
- if (ccid->ccid_ops->ccid_hc_tx_insert_options != NULL)
- return ccid->ccid_ops->ccid_hc_tx_insert_options(sk, skb);
- return 0;
-}
-
static inline int ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
struct sk_buff *skb)
{
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index 2555be8f479..fd38b05d6f7 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -351,7 +351,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
while (seqp != hctx->ccid2hctx_seqh) {
ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
- (unsigned long long)seqp->ccid2s_seq,
+ (unsigned long long)seqp->ccid2s_seq,
seqp->ccid2s_acked, seqp->ccid2s_sent);
seqp = seqp->ccid2s_next;
}
@@ -473,7 +473,7 @@ static inline void ccid2_new_ack(struct sock *sk,
/* first measurement */
if (hctx->ccid2hctx_srtt == -1) {
ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n",
- r, jiffies,
+ r, jiffies,
(unsigned long long)seqp->ccid2s_seq);
ccid2_change_srtt(hctx, r);
hctx->ccid2hctx_rttvar = r >> 1;
@@ -518,8 +518,8 @@ static inline void ccid2_new_ack(struct sock *sk,
hctx->ccid2hctx_lastrtt = jiffies;
ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n",
- hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar,
- hctx->ccid2hctx_rto, HZ, r);
+ hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar,
+ hctx->ccid2hctx_rto, HZ, r);
hctx->ccid2hctx_sent = 0;
}
@@ -667,9 +667,9 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
/* new packet received or marked */
if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED &&
!seqp->ccid2s_acked) {
- if (state ==
+ if (state ==
DCCP_ACKVEC_STATE_ECN_MARKED) {
- ccid2_congestion_event(hctx,
+ ccid2_congestion_event(hctx,
seqp);
} else
ccid2_new_ack(sk, seqp,
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index 66a27b9688c..5c452a3ec4d 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -41,27 +41,6 @@
#include "lib/tfrc.h"
#include "ccid3.h"
-/*
- * Reason for maths here is to avoid 32 bit overflow when a is big.
- * With this we get close to the limit.
- */
-static u32 usecs_div(const u32 a, const u32 b)
-{
- const u32 div = a < (UINT_MAX / (USEC_PER_SEC / 10)) ? 10 :
- a < (UINT_MAX / (USEC_PER_SEC / 50)) ? 50 :
- a < (UINT_MAX / (USEC_PER_SEC / 100)) ? 100 :
- a < (UINT_MAX / (USEC_PER_SEC / 500)) ? 500 :
- a < (UINT_MAX / (USEC_PER_SEC / 1000)) ? 1000 :
- a < (UINT_MAX / (USEC_PER_SEC / 5000)) ? 5000 :
- a < (UINT_MAX / (USEC_PER_SEC / 10000)) ? 10000 :
- a < (UINT_MAX / (USEC_PER_SEC / 50000)) ? 50000 :
- 100000;
- const u32 tmp = a * (USEC_PER_SEC / div);
- return (b >= 2 * div) ? tmp / (b / div) : tmp;
-}
-
-
-
#ifdef CONFIG_IP_DCCP_CCID3_DEBUG
static int ccid3_debug;
#define ccid3_pr_debug(format, a...) DCCP_PR_DEBUG(ccid3_debug, format, ##a)
@@ -108,8 +87,9 @@ static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx)
{
timeval_sub_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi);
- /* Calculate new t_ipi (inter packet interval) by t_ipi = s / X_inst */
- hctx->ccid3hctx_t_ipi = usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_x);
+ /* Calculate new t_ipi = s / X_inst (X_inst is in 64 * bytes/second) */
+ hctx->ccid3hctx_t_ipi = scaled_div(hctx->ccid3hctx_s,
+ hctx->ccid3hctx_x >> 6);
/* Update nominal send time with regard to the new t_ipi */
timeval_add_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi);
@@ -128,40 +108,44 @@ static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx)
* X = max(min(2 * X, 2 * X_recv), s / R);
* tld = now;
*
+ * Note: X and X_recv are both stored in units of 64 * bytes/second, to support
+ * fine-grained resolution of sending rates. This requires scaling by 2^6
+ * throughout the code. Only X_calc is unscaled (in bytes/second).
+ *
* If X has changed, we also update the scheduled send time t_now,
* the inter-packet interval t_ipi, and the delta value.
- */
+ */
static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now)
{
struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
- const __u32 old_x = hctx->ccid3hctx_x;
+ const __u64 old_x = hctx->ccid3hctx_x;
if (hctx->ccid3hctx_p > 0) {
- hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s,
- hctx->ccid3hctx_rtt,
- hctx->ccid3hctx_p);
- hctx->ccid3hctx_x = max_t(u32, min(hctx->ccid3hctx_x_calc,
- hctx->ccid3hctx_x_recv * 2),
- hctx->ccid3hctx_s / TFRC_T_MBI);
-
- } else if (timeval_delta(now, &hctx->ccid3hctx_t_ld) >=
- hctx->ccid3hctx_rtt) {
- hctx->ccid3hctx_x = max(min(hctx->ccid3hctx_x_recv,
- hctx->ccid3hctx_x ) * 2,
- usecs_div(hctx->ccid3hctx_s,
- hctx->ccid3hctx_rtt) );
+
+ hctx->ccid3hctx_x = min(((__u64)hctx->ccid3hctx_x_calc) << 6,
+ hctx->ccid3hctx_x_recv * 2);
+ hctx->ccid3hctx_x = max(hctx->ccid3hctx_x,
+ (((__u64)hctx->ccid3hctx_s) << 6) /
+ TFRC_T_MBI);
+
+ } else if (timeval_delta(now, &hctx->ccid3hctx_t_ld) -
+ (suseconds_t)hctx->ccid3hctx_rtt >= 0) {
+
+ hctx->ccid3hctx_x =
+ max(2 * min(hctx->ccid3hctx_x, hctx->ccid3hctx_x_recv),
+ scaled_div(((__u64)hctx->ccid3hctx_s) << 6,
+ hctx->ccid3hctx_rtt));
hctx->ccid3hctx_t_ld = *now;
- } else
- ccid3_pr_debug("Not changing X\n");
+ }
if (hctx->ccid3hctx_x != old_x)
ccid3_update_send_time(hctx);
}
/*
- * Track the mean packet size `s' (cf. RFC 4342, 5.3 and RFC 3448, 4.1)
- * @len: DCCP packet payload size in bytes
+ * Track the mean packet size `s' (cf. RFC 4342, 5.3 and RFC 3448, 4.1)
+ * @len: DCCP packet payload size in bytes
*/
static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len)
{
@@ -178,6 +162,33 @@ static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len)
*/
}
+/*
+ * Update Window Counter using the algorithm from [RFC 4342, 8.1].
+ * The algorithm is not applicable if RTT < 4 microseconds.
+ */
+static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx,
+ struct timeval *now)
+{
+ suseconds_t delta;
+ u32 quarter_rtts;
+
+ if (unlikely(hctx->ccid3hctx_rtt < 4)) /* avoid divide-by-zero */
+ return;
+
+ delta = timeval_delta(now, &hctx->ccid3hctx_t_last_win_count);
+ DCCP_BUG_ON(delta < 0);
+
+ quarter_rtts = (u32)delta / (hctx->ccid3hctx_rtt / 4);
+
+ if (quarter_rtts > 0) {
+ hctx->ccid3hctx_t_last_win_count = *now;
+ hctx->ccid3hctx_last_win_count += min_t(u32, quarter_rtts, 5);
+ hctx->ccid3hctx_last_win_count &= 0xF; /* mod 16 */
+
+ ccid3_pr_debug("now at %#X\n", hctx->ccid3hctx_last_win_count);
+ }
+}
+
static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
{
struct sock *sk = (struct sock *)data;
@@ -191,20 +202,20 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
goto restart_timer;
}
- ccid3_pr_debug("%s, sk=%p, state=%s\n", dccp_role(sk), sk,
+ ccid3_pr_debug("%s(%p, state=%s) - entry \n", dccp_role(sk), sk,
ccid3_tx_state_name(hctx->ccid3hctx_state));
-
+
switch (hctx->ccid3hctx_state) {
case TFRC_SSTATE_NO_FBACK:
/* RFC 3448, 4.4: Halve send rate directly */
- hctx->ccid3hctx_x = min_t(u32, hctx->ccid3hctx_x / 2,
- hctx->ccid3hctx_s / TFRC_T_MBI);
+ hctx->ccid3hctx_x = max(hctx->ccid3hctx_x / 2,
+ (((__u64)hctx->ccid3hctx_s) << 6) /
+ TFRC_T_MBI);
- ccid3_pr_debug("%s, sk=%p, state=%s, updated tx rate to %d "
- "bytes/s\n",
- dccp_role(sk), sk,
+ ccid3_pr_debug("%s(%p, state=%s), updated tx rate to %u "
+ "bytes/s\n", dccp_role(sk), sk,
ccid3_tx_state_name(hctx->ccid3hctx_state),
- hctx->ccid3hctx_x);
+ (unsigned)(hctx->ccid3hctx_x >> 6));
/* The value of R is still undefined and so we can not recompute
* the timout value. Keep initial value as per [RFC 4342, 5]. */
t_nfb = TFRC_INITIAL_TIMEOUT;
@@ -213,34 +224,46 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
case TFRC_SSTATE_FBACK:
/*
* Check if IDLE since last timeout and recv rate is less than
- * 4 packets per RTT
+ * 4 packets (in units of 64*bytes/sec) per RTT
*/
if (!hctx->ccid3hctx_idle ||
- (hctx->ccid3hctx_x_recv >=
- 4 * usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt))) {
+ (hctx->ccid3hctx_x_recv >= 4 *
+ scaled_div(((__u64)hctx->ccid3hctx_s) << 6,
+ hctx->ccid3hctx_rtt))) {
struct timeval now;
- ccid3_pr_debug("%s, sk=%p, state=%s, not idle\n",
+ ccid3_pr_debug("%s(%p, state=%s), not idle\n",
dccp_role(sk), sk,
- ccid3_tx_state_name(hctx->ccid3hctx_state));
- /* Halve sending rate */
+ ccid3_tx_state_name(hctx->ccid3hctx_state));
- /* If (p == 0 || X_calc > 2 * X_recv)
+ /*
+ * Modify the cached value of X_recv [RFC 3448, 4.4]
+ *
+ * If (p == 0 || X_calc > 2 * X_recv)
* X_recv = max(X_recv / 2, s / (2 * t_mbi));
* Else
* X_recv = X_calc / 4;
+ *
+ * Note that X_recv is scaled by 2^6 while X_calc is not
*/
BUG_ON(hctx->ccid3hctx_p && !hctx->ccid3hctx_x_calc);
if (hctx->ccid3hctx_p == 0 ||
- hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv)
- hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2,
- hctx->ccid3hctx_s / (2 * TFRC_T_MBI));
- else
- hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc / 4;
-
- /* Update sending rate */
- dccp_timestamp(sk, &now);
+ (hctx->ccid3hctx_x_calc >
+ (hctx->ccid3hctx_x_recv >> 5))) {
+
+ hctx->ccid3hctx_x_recv =
+ max(hctx->ccid3hctx_x_recv / 2,
+ (((__u64)hctx->ccid3hctx_s) << 6) /
+ (2 * TFRC_T_MBI));
+
+ if (hctx->ccid3hctx_p == 0)
+ dccp_timestamp(sk, &now);
+ } else {
+ hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc;
+ hctx->ccid3hctx_x_recv <<= 4;
+ }
+ /* Now recalculate X [RFC 3448, 4.3, step (4)] */
ccid3_hc_tx_update_x(sk, &now);
}
/*
@@ -251,7 +274,7 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi);
break;
case TFRC_SSTATE_NO_SENT:
- DCCP_BUG("Illegal %s state NO_SENT, sk=%p", dccp_role(sk), sk);
+ DCCP_BUG("%s(%p) - Illegal state NO_SENT", dccp_role(sk), sk);
/* fall through */
case TFRC_SSTATE_TERM:
goto out;
@@ -277,9 +300,8 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
- struct dccp_tx_hist_entry *new_packet;
struct timeval now;
- long delay;
+ suseconds_t delay;
BUG_ON(hctx == NULL);
@@ -291,34 +313,21 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
if (unlikely(skb->len == 0))
return -EBADMSG;
- /* See if last packet allocated was not sent */
- new_packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);
- if (new_packet == NULL || new_packet->dccphtx_sent) {
- new_packet = dccp_tx_hist_entry_new(ccid3_tx_hist,
- GFP_ATOMIC);
-
- if (unlikely(new_packet == NULL)) {
- DCCP_WARN("%s, sk=%p, not enough mem to add to history,"
- "send refused\n", dccp_role(sk), sk);
- return -ENOBUFS;
- }
-
- dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, new_packet);
- }
-
dccp_timestamp(sk, &now);
switch (hctx->ccid3hctx_state) {
case TFRC_SSTATE_NO_SENT:
sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
- jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT));
+ (jiffies +
+ usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
hctx->ccid3hctx_last_win_count = 0;
hctx->ccid3hctx_t_last_win_count = now;
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
- /* Set initial sending rate to 1 packet per second */
+ /* Set initial sending rate X/s to 1pps (X is scaled by 2^6) */
ccid3_hc_tx_update_s(hctx, skb->len);
- hctx->ccid3hctx_x = hctx->ccid3hctx_s;
+ hctx->ccid3hctx_x = hctx->ccid3hctx_s;
+ hctx->ccid3hctx_x <<= 6;
/* First timeout, according to [RFC 3448, 4.2], is 1 second */
hctx->ccid3hctx_t_ipi = USEC_PER_SEC;
@@ -332,77 +341,57 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
case TFRC_SSTATE_FBACK:
delay = timeval_delta(&hctx->ccid3hctx_t_nom, &now);
/*
- * Scheduling of packet transmissions [RFC 3448, 4.6]
+ * Scheduling of packet transmissions [RFC 3448, 4.6]
*
* if (t_now > t_nom - delta)
* // send the packet now
* else
* // send the packet in (t_nom - t_now) milliseconds.
*/
- if (delay - (long)hctx->ccid3hctx_delta >= 0)
+ if (delay - (suseconds_t)hctx->ccid3hctx_delta >= 0)
return delay / 1000L;
+
+ ccid3_hc_tx_update_win_count(hctx, &now);
break;
case TFRC_SSTATE_TERM:
- DCCP_BUG("Illegal %s state TERM, sk=%p", dccp_role(sk), sk);
+ DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
return -EINVAL;
}
/* prepare to send now (add options etc.) */
dp->dccps_hc_tx_insert_options = 1;
- new_packet->dccphtx_ccval = DCCP_SKB_CB(skb)->dccpd_ccval =
- hctx->ccid3hctx_last_win_count;
+ DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
+
+ /* set the nominal send time for the next following packet */
timeval_add_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi);
return 0;
}
-static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
+static void ccid3_hc_tx_packet_sent(struct sock *sk, int more,
+ unsigned int len)
{
- const struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
struct timeval now;
- unsigned long quarter_rtt;
struct dccp_tx_hist_entry *packet;
BUG_ON(hctx == NULL);
- dccp_timestamp(sk, &now);
-
ccid3_hc_tx_update_s(hctx, len);
- packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);
+ packet = dccp_tx_hist_entry_new(ccid3_tx_hist, GFP_ATOMIC);
if (unlikely(packet == NULL)) {
- DCCP_WARN("packet doesn't exist in history!\n");
- return;
- }
- if (unlikely(packet->dccphtx_sent)) {
- DCCP_WARN("no unsent packet in history!\n");
+ DCCP_CRIT("packet history - out of memory!");
return;
}
- packet->dccphtx_tstamp = now;
- packet->dccphtx_seqno = dp->dccps_gss;
- /*
- * Check if win_count have changed
- * Algorithm in "8.1. Window Counter Value" in RFC 4342.
- */
- quarter_rtt = timeval_delta(&now, &hctx->ccid3hctx_t_last_win_count);
- if (likely(hctx->ccid3hctx_rtt > 8))
- quarter_rtt /= hctx->ccid3hctx_rtt / 4;
-
- if (quarter_rtt > 0) {
- hctx->ccid3hctx_t_last_win_count = now;
- hctx->ccid3hctx_last_win_count = (hctx->ccid3hctx_last_win_count +
- min_t(unsigned long, quarter_rtt, 5)) % 16;
- ccid3_pr_debug("%s, sk=%p, window changed from "
- "%u to %u!\n",
- dccp_role(sk), sk,
- packet->dccphtx_ccval,
- hctx->ccid3hctx_last_win_count);
- }
+ dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, packet);
- hctx->ccid3hctx_idle = 0;
- packet->dccphtx_rtt = hctx->ccid3hctx_rtt;
- packet->dccphtx_sent = 1;
+ dccp_timestamp(sk, &now);
+ packet->dccphtx_tstamp = now;
+ packet->dccphtx_seqno = dccp_sk(sk)->dccps_gss;
+ packet->dccphtx_rtt = hctx->ccid3hctx_rtt;
+ packet->dccphtx_sent = 1;
+ hctx->ccid3hctx_idle = 0;
}
static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
@@ -414,7 +403,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
struct timeval now;
unsigned long t_nfb;
u32 pinv;
- long r_sample, t_elapsed;
+ suseconds_t r_sample, t_elapsed;
BUG_ON(hctx == NULL);
@@ -430,44 +419,44 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
case TFRC_SSTATE_FBACK:
/* get packet from history to look up t_recvdata */
packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist,
- DCCP_SKB_CB(skb)->dccpd_ack_seq);
+ DCCP_SKB_CB(skb)->dccpd_ack_seq);
if (unlikely(packet == NULL)) {
DCCP_WARN("%s(%p), seqno %llu(%s) doesn't exist "
"in history!\n", dccp_role(sk), sk,
(unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq,
- dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
+ dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
return;
}
- /* Update receive rate */
+ /* Update receive rate in units of 64 * bytes/second */
hctx->ccid3hctx_x_recv = opt_recv->ccid3or_receive_rate;
+ hctx->ccid3hctx_x_recv <<= 6;
/* Update loss event rate */
pinv = opt_recv->ccid3or_loss_event_rate;
- if (pinv == ~0U || pinv == 0)
+ if (pinv == ~0U || pinv == 0) /* see RFC 4342, 8.5 */
hctx->ccid3hctx_p = 0;
- else
- hctx->ccid3hctx_p = 1000000 / pinv;
+ else /* can not exceed 100% */
+ hctx->ccid3hctx_p = 1000000 / pinv;
dccp_timestamp(sk, &now);
/*
* Calculate new round trip sample as per [RFC 3448, 4.3] by
- * R_sample = (now - t_recvdata) - t_elapsed
+ * R_sample = (now - t_recvdata) - t_elapsed
*/
r_sample = timeval_delta(&now, &packet->dccphtx_tstamp);
t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10;
- if (unlikely(r_sample <= 0)) {
- DCCP_WARN("WARNING: R_sample (%ld) <= 0!\n", r_sample);
- r_sample = 0;
- } else if (unlikely(r_sample <= t_elapsed))
- DCCP_WARN("WARNING: r_sample=%ldus <= t_elapsed=%ldus\n",
- r_sample, t_elapsed);
+ DCCP_BUG_ON(r_sample < 0);
+ if (unlikely(r_sample <= t_elapsed))
+ DCCP_WARN("WARNING: r_sample=%dus <= t_elapsed=%dus\n",
+ (int)r_sample, (int)t_elapsed);
else
r_sample -= t_elapsed;
+ CCID3_RTT_SANITY_CHECK(r_sample);
- /* Update RTT estimate by
+ /* Update RTT estimate by
* If (No feedback recv)
* R = R_sample;
* Else
@@ -476,34 +465,46 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* q is a constant, RFC 3448 recomments 0.9
*/
if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) {
- /* Use Larger Initial Windows [RFC 4342, sec. 5]
- * We deviate in that we use `s' instead of `MSS'. */
- u16 w_init = max( 4 * hctx->ccid3hctx_s,
- max(2 * hctx->ccid3hctx_s, 4380));
+ /*
+ * Larger Initial Windows [RFC 4342, sec. 5]
+ * We deviate in that we use `s' instead of `MSS'.
+ */
+ __u64 w_init = min(4 * hctx->ccid3hctx_s,
+ max(2 * hctx->ccid3hctx_s, 4380));
hctx->ccid3hctx_rtt = r_sample;
- hctx->ccid3hctx_x = usecs_div(w_init, r_sample);
+ hctx->ccid3hctx_x = scaled_div(w_init << 6, r_sample);
hctx->ccid3hctx_t_ld = now;
ccid3_update_send_time(hctx);
- ccid3_pr_debug("%s(%p), s=%u, w_init=%u, "
- "R_sample=%ldus, X=%u\n", dccp_role(sk),
- sk, hctx->ccid3hctx_s, w_init, r_sample,
- hctx->ccid3hctx_x);
+ ccid3_pr_debug("%s(%p), s=%u, w_init=%llu, "
+ "R_sample=%dus, X=%u\n", dccp_role(sk),
+ sk, hctx->ccid3hctx_s,
+ (unsigned long long)w_init,
+ (int)r_sample,
+ (unsigned)(hctx->ccid3hctx_x >> 6));
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK);
} else {
hctx->ccid3hctx_rtt = (9 * hctx->ccid3hctx_rtt +
- (u32)r_sample ) / 10;
-
+ (u32)r_sample) / 10;
+
+ /* Update sending rate (step 4 of [RFC 3448, 4.3]) */
+ if (hctx->ccid3hctx_p > 0)
+ hctx->ccid3hctx_x_calc =
+ tfrc_calc_x(hctx->ccid3hctx_s,
+ hctx->ccid3hctx_rtt,
+ hctx->ccid3hctx_p);
ccid3_hc_tx_update_x(sk, &now);
- ccid3_pr_debug("%s(%p), RTT=%uus (sample=%ldus), s=%u, "
- "p=%u, X_calc=%u, X=%u\n", dccp_role(sk),
- sk, hctx->ccid3hctx_rtt, r_sample,
+ ccid3_pr_debug("%s(%p), RTT=%uus (sample=%dus), s=%u, "
+ "p=%u, X_calc=%u, X_recv=%u, X=%u\n",
+ dccp_role(sk),
+ sk, hctx->ccid3hctx_rtt, (int)r_sample,
hctx->ccid3hctx_s, hctx->ccid3hctx_p,
hctx->ccid3hctx_x_calc,
- hctx->ccid3hctx_x);
+ (unsigned)(hctx->ccid3hctx_x_recv >> 6),
+ (unsigned)(hctx->ccid3hctx_x >> 6));
}
/* unschedule no feedback timer */
@@ -513,57 +514,48 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
dccp_tx_hist_purge_older(ccid3_tx_hist,
&hctx->ccid3hctx_hist, packet);
/*
- * As we have calculated new ipi, delta, t_nom it is possible that
- * we now can send a packet, so wake up dccp_wait_for_ccid
+ * As we have calculated new ipi, delta, t_nom it is possible
+ * that we now can send a packet, so wake up dccp_wait_for_ccid
*/
sk->sk_write_space(sk);
/*
* Update timeout interval for the nofeedback timer.
* We use a configuration option to increase the lower bound.
- * This can help avoid triggering the nofeedback timer too often
- * ('spinning') on LANs with small RTTs.
+ * This can help avoid triggering the nofeedback timer too
+ * often ('spinning') on LANs with small RTTs.
*/
hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt,
CONFIG_IP_DCCP_CCID3_RTO *
- (USEC_PER_SEC/1000) );
+ (USEC_PER_SEC/1000));
/*
* Schedule no feedback timer to expire in
* max(t_RTO, 2 * s/X) = max(t_RTO, 2 * t_ipi)
*/
t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi);
-
- ccid3_pr_debug("%s, sk=%p, Scheduled no feedback timer to "
+
+ ccid3_pr_debug("%s(%p), Scheduled no feedback timer to "
"expire in %lu jiffies (%luus)\n",
- dccp_role(sk), sk,
- usecs_to_jiffies(t_nfb), t_nfb);
+ dccp_role(sk),
+ sk, usecs_to_jiffies(t_nfb), t_nfb);
- sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
+ sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
jiffies + usecs_to_jiffies(t_nfb));
/* set idle flag */
- hctx->ccid3hctx_idle = 1;
+ hctx->ccid3hctx_idle = 1;
break;
case TFRC_SSTATE_NO_SENT:
- if (dccp_sk(sk)->dccps_role == DCCP_ROLE_CLIENT)
- DCCP_WARN("Illegal ACK received - no packet sent\n");
+ /*
+ * XXX when implementing bidirectional rx/tx check this again
+ */
+ DCCP_WARN("Illegal ACK received - no packet sent\n");
/* fall through */
case TFRC_SSTATE_TERM: /* ignore feedback when closing */
break;
}
}
-static int ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
-{
- const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
-
- BUG_ON(hctx == NULL);
-
- if (sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)
- DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
- return 0;
-}
-
static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
unsigned char len, u16 idx,
unsigned char *value)
@@ -588,13 +580,14 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
switch (option) {
case TFRC_OPT_LOSS_EVENT_RATE:
if (unlikely(len != 4)) {
- DCCP_WARN("%s, sk=%p, invalid len %d "
+ DCCP_WARN("%s(%p), invalid len %d "
"for TFRC_OPT_LOSS_EVENT_RATE\n",
dccp_role(sk), sk, len);
rc = -EINVAL;
} else {
- opt_recv->ccid3or_loss_event_rate = ntohl(*(__be32 *)value);
- ccid3_pr_debug("%s, sk=%p, LOSS_EVENT_RATE=%u\n",
+ opt_recv->ccid3or_loss_event_rate =
+ ntohl(*(__be32 *)value);
+ ccid3_pr_debug("%s(%p), LOSS_EVENT_RATE=%u\n",
dccp_role(sk), sk,
opt_recv->ccid3or_loss_event_rate);
}
@@ -602,20 +595,21 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
case TFRC_OPT_LOSS_INTERVALS:
opt_recv->ccid3or_loss_intervals_idx = idx;
opt_recv->ccid3or_loss_intervals_len = len;
- ccid3_pr_debug("%s, sk=%p, LOSS_INTERVALS=(%u, %u)\n",
+ ccid3_pr_debug("%s(%p), LOSS_INTERVALS=(%u, %u)\n",
dccp_role(sk), sk,
opt_recv->ccid3or_loss_intervals_idx,
opt_recv->ccid3or_loss_intervals_len);
break;
case TFRC_OPT_RECEIVE_RATE:
if (unlikely(len != 4)) {
- DCCP_WARN("%s, sk=%p, invalid len %d "
+ DCCP_WARN("%s(%p), invalid len %d "
"for TFRC_OPT_RECEIVE_RATE\n",
dccp_role(sk), sk, len);
rc = -EINVAL;
} else {
- opt_recv->ccid3or_receive_rate = ntohl(*(__be32 *)value);
- ccid3_pr_debug("%s, sk=%p, RECEIVE_RATE=%u\n",
+ opt_recv->ccid3or_receive_rate =
+ ntohl(*(__be32 *)value);
+ ccid3_pr_debug("%s(%p), RECEIVE_RATE=%u\n",
dccp_role(sk), sk,
opt_recv->ccid3or_receive_rate);
}
@@ -630,10 +624,12 @@ static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid);
hctx->ccid3hctx_s = 0;
+ hctx->ccid3hctx_rtt = 0;
hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
INIT_LIST_HEAD(&hctx->ccid3hctx_hist);
- hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer;
+ hctx->ccid3hctx_no_feedback_timer.function =
+ ccid3_hc_tx_no_feedback_timer;
hctx->ccid3hctx_no_feedback_timer.data = (unsigned long)sk;
init_timer(&hctx->ccid3hctx_no_feedback_timer);
@@ -698,8 +694,9 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
struct dccp_sock *dp = dccp_sk(sk);
struct dccp_rx_hist_entry *packet;
struct timeval now;
+ suseconds_t delta;
- ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
+ ccid3_pr_debug("%s(%p) - entry \n", dccp_role(sk), sk);
dccp_timestamp(sk, &now);
@@ -707,21 +704,21 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
case TFRC_RSTATE_NO_DATA:
hcrx->ccid3hcrx_x_recv = 0;
break;
- case TFRC_RSTATE_DATA: {
- const u32 delta = timeval_delta(&now,
- &hcrx->ccid3hcrx_tstamp_last_feedback);
- hcrx->ccid3hcrx_x_recv = usecs_div(hcrx->ccid3hcrx_bytes_recv,
- delta);
- }
+ case TFRC_RSTATE_DATA:
+ delta = timeval_delta(&now,
+ &hcrx->ccid3hcrx_tstamp_last_feedback);
+ DCCP_BUG_ON(delta < 0);
+ hcrx->ccid3hcrx_x_recv =
+ scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
break;
case TFRC_RSTATE_TERM:
- DCCP_BUG("Illegal %s state TERM, sk=%p", dccp_role(sk), sk);
+ DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
return;
}
packet = dccp_rx_hist_find_data_packet(&hcrx->ccid3hcrx_hist);
if (unlikely(packet == NULL)) {
- DCCP_WARN("%s, sk=%p, no data packet in history!\n",
+ DCCP_WARN("%s(%p), no data packet in history!\n",
dccp_role(sk), sk);
return;
}
@@ -730,13 +727,19 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
hcrx->ccid3hcrx_ccval_last_counter = packet->dccphrx_ccval;
hcrx->ccid3hcrx_bytes_recv = 0;
- /* Convert to multiples of 10us */
- hcrx->ccid3hcrx_elapsed_time =
- timeval_delta(&now, &packet->dccphrx_tstamp) / 10;
+ /* Elapsed time information [RFC 4340, 13.2] in units of 10 * usecs */
+ delta = timeval_delta(&now, &packet->dccphrx_tstamp);
+ DCCP_BUG_ON(delta < 0);
+ hcrx->ccid3hcrx_elapsed_time = delta / 10;
+
if (hcrx->ccid3hcrx_p == 0)
- hcrx->ccid3hcrx_pinv = ~0;
- else
+ hcrx->ccid3hcrx_pinv = ~0U; /* see RFC 4342, 8.5 */
+ else if (hcrx->ccid3hcrx_p > 1000000) {
+ DCCP_WARN("p (%u) > 100%%\n", hcrx->ccid3hcrx_p);
+ hcrx->ccid3hcrx_pinv = 1; /* use 100% in this case */
+ } else
hcrx->ccid3hcrx_pinv = 1000000 / hcrx->ccid3hcrx_p;
+
dp->dccps_hc_rx_insert_options = 1;
dccp_send_ack(sk);
}
@@ -764,9 +767,9 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
hcrx->ccid3hcrx_elapsed_time)) ||
dccp_insert_option_timestamp(sk, skb) ||
dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
- &pinv, sizeof(pinv)) ||
+ &pinv, sizeof(pinv)) ||
dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
- &x_recv, sizeof(x_recv)))
+ &x_recv, sizeof(x_recv)))
return -1;
return 0;
@@ -780,12 +783,13 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
{
struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
struct dccp_rx_hist_entry *entry, *next, *tail = NULL;
- u32 rtt, delta, x_recv, fval, p, tmp2;
+ u32 x_recv, p;
+ suseconds_t rtt, delta;
struct timeval tstamp = { 0, };
int interval = 0;
int win_count = 0;
int step = 0;
- u64 tmp1;
+ u64 fval;
list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
dccphrx_node) {
@@ -810,13 +814,13 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
}
if (unlikely(step == 0)) {
- DCCP_WARN("%s, sk=%p, packet history has no data packets!\n",
+ DCCP_WARN("%s(%p), packet history has no data packets!\n",
dccp_role(sk), sk);
return ~0;
}
if (unlikely(interval == 0)) {
- DCCP_WARN("%s, sk=%p, Could not find a win_count interval > 0."
+ DCCP_WARN("%s(%p), Could not find a win_count interval > 0."
"Defaulting to 1\n", dccp_role(sk), sk);
interval = 1;
}
@@ -825,41 +829,51 @@ found:
DCCP_CRIT("tail is null\n");
return ~0;
}
- rtt = timeval_delta(&tstamp, &tail->dccphrx_tstamp) * 4 / interval;
- ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n",
- dccp_role(sk), sk, rtt);
- if (rtt == 0) {
- DCCP_WARN("RTT==0, setting to 1\n");
- rtt = 1;
+ delta = timeval_delta(&tstamp, &tail->dccphrx_tstamp);
+ DCCP_BUG_ON(delta < 0);
+
+ rtt = delta * 4 / interval;
+ ccid3_pr_debug("%s(%p), approximated RTT to %dus\n",
+ dccp_role(sk), sk, (int)rtt);
+
+ /*
+ * Determine the length of the first loss interval via inverse lookup.
+ * Assume that X_recv can be computed by the throughput equation
+ * s
+ * X_recv = --------
+ * R * fval
+ * Find some p such that f(p) = fval; return 1/p [RFC 3448, 6.3.1].
+ */
+ if (rtt == 0) { /* would result in divide-by-zero */
+ DCCP_WARN("RTT==0\n");
+ return ~0;
}
dccp_timestamp(sk, &tstamp);
delta = timeval_delta(&tstamp, &hcrx->ccid3hcrx_tstamp_last_feedback);
- x_recv = usecs_div(hcrx->ccid3hcrx_bytes_recv, delta);
-
- if (x_recv == 0)
- x_recv = hcrx->ccid3hcrx_x_recv;
-
- tmp1 = (u64)x_recv * (u64)rtt;
- do_div(tmp1,10000000);
- tmp2 = (u32)tmp1;
-
- if (!tmp2) {
- DCCP_CRIT("tmp2 = 0, x_recv = %u, rtt =%u\n", x_recv, rtt);
- return ~0;
+ DCCP_BUG_ON(delta <= 0);
+
+ x_recv = scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
+ if (x_recv == 0) { /* would also trigger divide-by-zero */
+ DCCP_WARN("X_recv==0\n");
+ if ((x_recv = hcrx->ccid3hcrx_x_recv) == 0) {
+ DCCP_BUG("stored value of X_recv is zero");
+ return ~0;
+ }
}
- fval = (hcrx->ccid3hcrx_s * 100000) / tmp2;
- /* do not alter order above or you will get overflow on 32 bit */
+ fval = scaled_div(hcrx->ccid3hcrx_s, rtt);
+ fval = scaled_div32(fval, x_recv);
p = tfrc_calc_x_reverse_lookup(fval);
- ccid3_pr_debug("%s, sk=%p, receive rate=%u bytes/s, implied "
+
+ ccid3_pr_debug("%s(%p), receive rate=%u bytes/s, implied "
"loss rate=%u\n", dccp_role(sk), sk, x_recv, p);
if (p == 0)
return ~0;
else
- return 1000000 / p;
+ return 1000000 / p;
}
static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss)
@@ -913,7 +927,8 @@ static int ccid3_hc_rx_detect_loss(struct sock *sk,
struct dccp_rx_hist_entry *packet)
{
struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
- struct dccp_rx_hist_entry *rx_hist = dccp_rx_hist_head(&hcrx->ccid3hcrx_hist);
+ struct dccp_rx_hist_entry *rx_hist =
+ dccp_rx_hist_head(&hcrx->ccid3hcrx_hist);
u64 seqno = packet->dccphrx_seqno;
u64 tmp_seqno;
int loss = 0;
@@ -941,7 +956,7 @@ static int ccid3_hc_rx_detect_loss(struct sock *sk,
dccp_inc_seqno(&tmp_seqno);
while (dccp_rx_hist_find_entry(&hcrx->ccid3hcrx_hist,
tmp_seqno, &ccval)) {
- hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno;
+ hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno;
hcrx->ccid3hcrx_ccval_nonloss = ccval;
dccp_inc_seqno(&tmp_seqno);
}
@@ -967,7 +982,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
const struct dccp_options_received *opt_recv;
struct dccp_rx_hist_entry *packet;
struct timeval now;
- u32 p_prev, rtt_prev, r_sample, t_elapsed;
+ u32 p_prev, rtt_prev;
+ suseconds_t r_sample, t_elapsed;
int loss, payload_size;
BUG_ON(hcrx == NULL);
@@ -987,11 +1003,13 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
r_sample = timeval_usecs(&now);
t_elapsed = opt_recv->dccpor_elapsed_time * 10;
+ DCCP_BUG_ON(r_sample < 0);
if (unlikely(r_sample <= t_elapsed))
- DCCP_WARN("r_sample=%uus, t_elapsed=%uus\n",
- r_sample, t_elapsed);
+ DCCP_WARN("r_sample=%ldus, t_elapsed=%ldus\n",
+ (long)r_sample, (long)t_elapsed);
else
r_sample -= t_elapsed;
+ CCID3_RTT_SANITY_CHECK(r_sample);
if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)
hcrx->ccid3hcrx_rtt = r_sample;
@@ -1000,8 +1018,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
r_sample / 10;
if (rtt_prev != hcrx->ccid3hcrx_rtt)
- ccid3_pr_debug("%s, New RTT=%uus, elapsed time=%u\n",
- dccp_role(sk), hcrx->ccid3hcrx_rtt,
+ ccid3_pr_debug("%s(%p), New RTT=%uus, elapsed time=%u\n",
+ dccp_role(sk), sk, hcrx->ccid3hcrx_rtt,
opt_recv->dccpor_elapsed_time);
break;
case DCCP_PKT_DATA:
@@ -1013,7 +1031,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
packet = dccp_rx_hist_entry_new(ccid3_rx_hist, sk, opt_recv->dccpor_ndp,
skb, GFP_ATOMIC);
if (unlikely(packet == NULL)) {
- DCCP_WARN("%s, sk=%p, Not enough mem to add rx packet "
+ DCCP_WARN("%s(%p), Not enough mem to add rx packet "
"to history, consider it lost!\n", dccp_role(sk), sk);
return;
}
@@ -1028,9 +1046,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
switch (hcrx->ccid3hcrx_state) {
case TFRC_RSTATE_NO_DATA:
- ccid3_pr_debug("%s, sk=%p(%s), skb=%p, sending initial "
- "feedback\n",
- dccp_role(sk), sk,
+ ccid3_pr_debug("%s(%p, state=%s), skb=%p, sending initial "
+ "feedback\n", dccp_role(sk), sk,
dccp_state_name(sk->sk_state), skb);
ccid3_hc_rx_send_feedback(sk);
ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA);
@@ -1041,19 +1058,19 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
break;
dccp_timestamp(sk, &now);
- if (timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) >=
- hcrx->ccid3hcrx_rtt) {
+ if ((timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) -
+ (suseconds_t)hcrx->ccid3hcrx_rtt) >= 0) {
hcrx->ccid3hcrx_tstamp_last_ack = now;
ccid3_hc_rx_send_feedback(sk);
}
return;
case TFRC_RSTATE_TERM:
- DCCP_BUG("Illegal %s state TERM, sk=%p", dccp_role(sk), sk);
+ DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
return;
}
/* Dealing with packet loss */
- ccid3_pr_debug("%s, sk=%p(%s), data loss! Reacting...\n",
+ ccid3_pr_debug("%s(%p, state=%s), data loss! Reacting...\n",
dccp_role(sk), sk, dccp_state_name(sk->sk_state));
p_prev = hcrx->ccid3hcrx_p;
@@ -1078,7 +1095,7 @@ static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
{
struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid);
- ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
+ ccid3_pr_debug("entry\n");
hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA;
INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist);
@@ -1086,7 +1103,7 @@ static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
dccp_timestamp(sk, &hcrx->ccid3hcrx_tstamp_last_ack);
hcrx->ccid3hcrx_tstamp_last_feedback = hcrx->ccid3hcrx_tstamp_last_ack;
hcrx->ccid3hcrx_s = 0;
- hcrx->ccid3hcrx_rtt = 5000; /* XXX 5ms for now... */
+ hcrx->ccid3hcrx_rtt = 0;
return 0;
}
@@ -1115,9 +1132,9 @@ static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
BUG_ON(hcrx == NULL);
- info->tcpi_ca_state = hcrx->ccid3hcrx_state;
- info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
- info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt;
+ info->tcpi_ca_state = hcrx->ccid3hcrx_state;
+ info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
+ info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt;
}
static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
@@ -1198,7 +1215,6 @@ static struct ccid_operations ccid3 = {
.ccid_hc_tx_send_packet = ccid3_hc_tx_send_packet,
.ccid_hc_tx_packet_sent = ccid3_hc_tx_packet_sent,
.ccid_hc_tx_packet_recv = ccid3_hc_tx_packet_recv,
- .ccid_hc_tx_insert_options = ccid3_hc_tx_insert_options,
.ccid_hc_tx_parse_options = ccid3_hc_tx_parse_options,
.ccid_hc_rx_obj_size = sizeof(struct ccid3_hc_rx_sock),
.ccid_hc_rx_init = ccid3_hc_rx_init,
@@ -1210,7 +1226,7 @@ static struct ccid_operations ccid3 = {
.ccid_hc_rx_getsockopt = ccid3_hc_rx_getsockopt,
.ccid_hc_tx_getsockopt = ccid3_hc_tx_getsockopt,
};
-
+
#ifdef CONFIG_IP_DCCP_CCID3_DEBUG
module_param(ccid3_debug, int, 0444);
MODULE_PARM_DESC(ccid3_debug, "Enable debug messages");
@@ -1233,7 +1249,7 @@ static __init int ccid3_module_init(void)
goto out_free_tx;
rc = ccid_register(&ccid3);
- if (rc != 0)
+ if (rc != 0)
goto out_free_loss_interval_history;
out:
return rc;
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h
index 07596d704ef..15776a88c09 100644
--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -51,6 +51,16 @@
/* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */
#define TFRC_T_MBI 64
+/* What we think is a reasonable upper limit on RTT values */
+#define CCID3_SANE_RTT_MAX ((suseconds_t)(4 * USEC_PER_SEC))
+
+#define CCID3_RTT_SANITY_CHECK(rtt) do { \
+ if (rtt > CCID3_SANE_RTT_MAX) { \
+ DCCP_CRIT("RTT (%d) too large, substituting %d", \
+ (int)rtt, (int)CCID3_SANE_RTT_MAX); \
+ rtt = CCID3_SANE_RTT_MAX; \
+ } } while (0)
+
enum ccid3_options {
TFRC_OPT_LOSS_EVENT_RATE = 192,
TFRC_OPT_LOSS_INTERVALS = 193,
@@ -67,7 +77,7 @@ struct ccid3_options_received {
/* TFRC sender states */
enum ccid3_hc_tx_states {
- TFRC_SSTATE_NO_SENT = 1,
+ TFRC_SSTATE_NO_SENT = 1,
TFRC_SSTATE_NO_FBACK,
TFRC_SSTATE_FBACK,
TFRC_SSTATE_TERM,
@@ -75,23 +85,23 @@ enum ccid3_hc_tx_states {
/** struct ccid3_hc_tx_sock - CCID3 sender half-connection socket
*
- * @ccid3hctx_x - Current sending rate
- * @ccid3hctx_x_recv - Receive rate
- * @ccid3hctx_x_calc - Calculated send rate (RFC 3448, 3.1)
+ * @ccid3hctx_x - Current sending rate in 64 * bytes per second
+ * @ccid3hctx_x_recv - Receive rate in 64 * bytes per second
+ * @ccid3hctx_x_calc - Calculated rate in bytes per second
* @ccid3hctx_rtt - Estimate of current round trip time in usecs
* @ccid3hctx_p - Current loss event rate (0-1) scaled by 1000000
- * @ccid3hctx_s - Packet size
- * @ccid3hctx_t_rto - Retransmission Timeout (RFC 3448, 3.1)
- * @ccid3hctx_t_ipi - Interpacket (send) interval (RFC 3448, 4.6)
+ * @ccid3hctx_s - Packet size in bytes
+ * @ccid3hctx_t_rto - Nofeedback Timer setting in usecs
+ * @ccid3hctx_t_ipi - Interpacket (send) interval (RFC 3448, 4.6) in usecs
* @ccid3hctx_state - Sender state, one of %ccid3_hc_tx_states
* @ccid3hctx_last_win_count - Last window counter sent
* @ccid3hctx_t_last_win_count - Timestamp of earliest packet
- * with last_win_count value sent
+ * with last_win_count value sent
* @ccid3hctx_no_feedback_timer - Handle to no feedback timer
* @ccid3hctx_idle - Flag indicating that sender is idling
* @ccid3hctx_t_ld - Time last doubled during slow start
* @ccid3hctx_t_nom - Nominal send time of next packet
- * @ccid3hctx_delta - Send timer delta
+ * @ccid3hctx_delta - Send timer delta (RFC 3448, 4.6) in usecs
* @ccid3hctx_hist - Packet history
* @ccid3hctx_options_received - Parsed set of retrieved options
*/
@@ -105,7 +115,7 @@ struct ccid3_hc_tx_sock {
#define ccid3hctx_t_rto ccid3hctx_tfrc.tfrctx_rto
#define ccid3hctx_t_ipi ccid3hctx_tfrc.tfrctx_ipi
u16 ccid3hctx_s;
- enum ccid3_hc_tx_states ccid3hctx_state:8;
+ enum ccid3_hc_tx_states ccid3hctx_state:8;
u8 ccid3hctx_last_win_count;
u8 ccid3hctx_idle;
struct timeval ccid3hctx_t_last_win_count;
@@ -119,7 +129,7 @@ struct ccid3_hc_tx_sock {
/* TFRC receiver states */
enum ccid3_hc_rx_states {
- TFRC_RSTATE_NO_DATA = 1,
+ TFRC_RSTATE_NO_DATA = 1,
TFRC_RSTATE_DATA,
TFRC_RSTATE_TERM = 127,
};
@@ -147,18 +157,18 @@ struct ccid3_hc_rx_sock {
#define ccid3hcrx_x_recv ccid3hcrx_tfrc.tfrcrx_x_recv
#define ccid3hcrx_rtt ccid3hcrx_tfrc.tfrcrx_rtt
#define ccid3hcrx_p ccid3hcrx_tfrc.tfrcrx_p
- u64 ccid3hcrx_seqno_nonloss:48,
+ u64 ccid3hcrx_seqno_nonloss:48,
ccid3hcrx_ccval_nonloss:4,
ccid3hcrx_ccval_last_counter:4;
enum ccid3_hc_rx_states ccid3hcrx_state:8;
- u32 ccid3hcrx_bytes_recv;
- struct timeval ccid3hcrx_tstamp_last_feedback;
- struct timeval ccid3hcrx_tstamp_last_ack;
+ u32 ccid3hcrx_bytes_recv;
+ struct timeval ccid3hcrx_tstamp_last_feedback;
+ struct timeval ccid3hcrx_tstamp_last_ack;
struct list_head ccid3hcrx_hist;
struct list_head ccid3hcrx_li_hist;
- u16 ccid3hcrx_s;
- u32 ccid3hcrx_pinv;
- u32 ccid3hcrx_elapsed_time;
+ u16 ccid3hcrx_s;
+ u32 ccid3hcrx_pinv;
+ u32 ccid3hcrx_elapsed_time;
};
static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk)
diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c
index b876c9c81c6..2e8ef42721e 100644
--- a/net/dccp/ccids/lib/packet_history.c
+++ b/net/dccp/ccids/lib/packet_history.c
@@ -36,9 +36,100 @@
#include <linux/module.h>
#include <linux/string.h>
-
#include "packet_history.h"
+/*
+ * Transmitter History Routines
+ */
+struct dccp_tx_hist *dccp_tx_hist_new(const char *name)
+{
+ struct dccp_tx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
+ static const char dccp_tx_hist_mask[] = "tx_hist_%s";
+ char *slab_name;
+
+ if (hist == NULL)
+ goto out;
+
+ slab_name = kmalloc(strlen(name) + sizeof(dccp_tx_hist_mask) - 1,
+ GFP_ATOMIC);
+ if (slab_name == NULL)
+ goto out_free_hist;
+
+ sprintf(slab_name, dccp_tx_hist_mask, name);
+ hist->dccptxh_slab = kmem_cache_create(slab_name,
+ sizeof(struct dccp_tx_hist_entry),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (hist->dccptxh_slab == NULL)
+ goto out_free_slab_name;
+out:
+ return hist;
+out_free_slab_name:
+ kfree(slab_name);
+out_free_hist:
+ kfree(hist);
+ hist = NULL;
+ goto out;
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_new);
+
+void dccp_tx_hist_delete(struct dccp_tx_hist *hist)
+{
+ const char* name = kmem_cache_name(hist->dccptxh_slab);
+
+ kmem_cache_destroy(hist->dccptxh_slab);
+ kfree(name);
+ kfree(hist);
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_delete);
+
+struct dccp_tx_hist_entry *
+ dccp_tx_hist_find_entry(const struct list_head *list, const u64 seq)
+{
+ struct dccp_tx_hist_entry *packet = NULL, *entry;
+
+ list_for_each_entry(entry, list, dccphtx_node)
+ if (entry->dccphtx_seqno == seq) {
+ packet = entry;
+ break;
+ }
+
+ return packet;
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_find_entry);
+
+void dccp_tx_hist_purge(struct dccp_tx_hist *hist, struct list_head *list)
+{
+ struct dccp_tx_hist_entry *entry, *next;
+
+ list_for_each_entry_safe(entry, next, list, dccphtx_node) {
+ list_del_init(&entry->dccphtx_node);
+ dccp_tx_hist_entry_delete(hist, entry);
+ }
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_purge);
+
+void dccp_tx_hist_purge_older(struct dccp_tx_hist *hist,
+ struct list_head *list,
+ struct dccp_tx_hist_entry *packet)
+{
+ struct dccp_tx_hist_entry *next;
+
+ list_for_each_entry_safe_continue(packet, next, list, dccphtx_node) {
+ list_del_init(&packet->dccphtx_node);
+ dccp_tx_hist_entry_delete(hist, packet);
+ }
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_purge_older);
+
+/*
+ * Receiver History Routines
+ */
struct dccp_rx_hist *dccp_rx_hist_new(const char *name)
{
struct dccp_rx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
@@ -83,18 +174,24 @@ void dccp_rx_hist_delete(struct dccp_rx_hist *hist)
EXPORT_SYMBOL_GPL(dccp_rx_hist_delete);
-void dccp_rx_hist_purge(struct dccp_rx_hist *hist, struct list_head *list)
+int dccp_rx_hist_find_entry(const struct list_head *list, const u64 seq,
+ u8 *ccval)
{
- struct dccp_rx_hist_entry *entry, *next;
+ struct dccp_rx_hist_entry *packet = NULL, *entry;
- list_for_each_entry_safe(entry, next, list, dccphrx_node) {
- list_del_init(&entry->dccphrx_node);
- kmem_cache_free(hist->dccprxh_slab, entry);
- }
-}
+ list_for_each_entry(entry, list, dccphrx_node)
+ if (entry->dccphrx_seqno == seq) {
+ packet = entry;
+ break;
+ }
-EXPORT_SYMBOL_GPL(dccp_rx_hist_purge);
+ if (packet)
+ *ccval = packet->dccphrx_ccval;
+ return packet != NULL;
+}
+
+EXPORT_SYMBOL_GPL(dccp_rx_hist_find_entry);
struct dccp_rx_hist_entry *
dccp_rx_hist_find_data_packet(const struct list_head *list)
{
@@ -184,110 +281,18 @@ void dccp_rx_hist_add_packet(struct dccp_rx_hist *hist,
EXPORT_SYMBOL_GPL(dccp_rx_hist_add_packet);
-struct dccp_tx_hist *dccp_tx_hist_new(const char *name)
-{
- struct dccp_tx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
- static const char dccp_tx_hist_mask[] = "tx_hist_%s";
- char *slab_name;
-
- if (hist == NULL)
- goto out;
-
- slab_name = kmalloc(strlen(name) + sizeof(dccp_tx_hist_mask) - 1,
- GFP_ATOMIC);
- if (slab_name == NULL)
- goto out_free_hist;
-
- sprintf(slab_name, dccp_tx_hist_mask, name);
- hist->dccptxh_slab = kmem_cache_create(slab_name,
- sizeof(struct dccp_tx_hist_entry),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (hist->dccptxh_slab == NULL)
- goto out_free_slab_name;
-out:
- return hist;
-out_free_slab_name:
- kfree(slab_name);
-out_free_hist:
- kfree(hist);
- hist = NULL;
- goto out;
-}
-
-EXPORT_SYMBOL_GPL(dccp_tx_hist_new);
-
-void dccp_tx_hist_delete(struct dccp_tx_hist *hist)
-{
- const char* name = kmem_cache_name(hist->dccptxh_slab);
-
- kmem_cache_destroy(hist->dccptxh_slab);
- kfree(name);
- kfree(hist);
-}
-
-EXPORT_SYMBOL_GPL(dccp_tx_hist_delete);
-
-struct dccp_tx_hist_entry *
- dccp_tx_hist_find_entry(const struct list_head *list, const u64 seq)
-{
- struct dccp_tx_hist_entry *packet = NULL, *entry;
-
- list_for_each_entry(entry, list, dccphtx_node)
- if (entry->dccphtx_seqno == seq) {
- packet = entry;
- break;
- }
-
- return packet;
-}
-
-EXPORT_SYMBOL_GPL(dccp_tx_hist_find_entry);
-
-int dccp_rx_hist_find_entry(const struct list_head *list, const u64 seq,
- u8 *ccval)
-{
- struct dccp_rx_hist_entry *packet = NULL, *entry;
-
- list_for_each_entry(entry, list, dccphrx_node)
- if (entry->dccphrx_seqno == seq) {
- packet = entry;
- break;
- }
-
- if (packet)
- *ccval = packet->dccphrx_ccval;
-
- return packet != NULL;
-}
-
-EXPORT_SYMBOL_GPL(dccp_rx_hist_find_entry);
-
-void dccp_tx_hist_purge_older(struct dccp_tx_hist *hist,
- struct list_head *list,
- struct dccp_tx_hist_entry *packet)
+void dccp_rx_hist_purge(struct dccp_rx_hist *hist, struct list_head *list)
{
- struct dccp_tx_hist_entry *next;
+ struct dccp_rx_hist_entry *entry, *next;
- list_for_each_entry_safe_continue(packet, next, list, dccphtx_node) {
- list_del_init(&packet->dccphtx_node);
- dccp_tx_hist_entry_delete(hist, packet);
+ list_for_each_entry_safe(entry, next, list, dccphrx_node) {
+ list_del_init(&entry->dccphrx_node);
+ kmem_cache_free(hist->dccprxh_slab, entry);
}
}
-EXPORT_SYMBOL_GPL(dccp_tx_hist_purge_older);
-
-void dccp_tx_hist_purge(struct dccp_tx_hist *hist, struct list_head *list)
-{
- struct dccp_tx_hist_entry *entry, *next;
-
- list_for_each_entry_safe(entry, next, list, dccphtx_node) {
- list_del_init(&entry->dccphtx_node);
- dccp_tx_hist_entry_delete(hist, entry);
- }
-}
+EXPORT_SYMBOL_GPL(dccp_rx_hist_purge);
-EXPORT_SYMBOL_GPL(dccp_tx_hist_purge);
MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>, "
"Arnaldo Carvalho de Melo <acme@ghostprotocols.net>");
diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h
index 9a8bcf224aa..1f960c19ea1 100644
--- a/net/dccp/ccids/lib/packet_history.h
+++ b/net/dccp/ccids/lib/packet_history.h
@@ -49,43 +49,27 @@
#define TFRC_WIN_COUNT_PER_RTT 4
#define TFRC_WIN_COUNT_LIMIT 16
+/*
+ * Transmitter History data structures and declarations
+ */
struct dccp_tx_hist_entry {
struct list_head dccphtx_node;
u64 dccphtx_seqno:48,
- dccphtx_ccval:4,
dccphtx_sent:1;
u32 dccphtx_rtt;
struct timeval dccphtx_tstamp;
};
-struct dccp_rx_hist_entry {
- struct list_head dccphrx_node;
- u64 dccphrx_seqno:48,
- dccphrx_ccval:4,
- dccphrx_type:4;
- u32 dccphrx_ndp; /* In fact it is from 8 to 24 bits */
- struct timeval dccphrx_tstamp;
-};
-
struct dccp_tx_hist {
struct kmem_cache *dccptxh_slab;
};
extern struct dccp_tx_hist *dccp_tx_hist_new(const char *name);
-extern void dccp_tx_hist_delete(struct dccp_tx_hist *hist);
-
-struct dccp_rx_hist {
- struct kmem_cache *dccprxh_slab;
-};
-
-extern struct dccp_rx_hist *dccp_rx_hist_new(const char *name);
-extern void dccp_rx_hist_delete(struct dccp_rx_hist *hist);
-extern struct dccp_rx_hist_entry *
- dccp_rx_hist_find_data_packet(const struct list_head *list);
+extern void dccp_tx_hist_delete(struct dccp_tx_hist *hist);
static inline struct dccp_tx_hist_entry *
- dccp_tx_hist_entry_new(struct dccp_tx_hist *hist,
- const gfp_t prio)
+ dccp_tx_hist_entry_new(struct dccp_tx_hist *hist,
+ const gfp_t prio)
{
struct dccp_tx_hist_entry *entry = kmem_cache_alloc(hist->dccptxh_slab,
prio);
@@ -96,18 +80,20 @@ static inline struct dccp_tx_hist_entry *
return entry;
}
-static inline void dccp_tx_hist_entry_delete(struct dccp_tx_hist *hist,
- struct dccp_tx_hist_entry *entry)
+static inline struct dccp_tx_hist_entry *
+ dccp_tx_hist_head(struct list_head *list)
{
- if (entry != NULL)
- kmem_cache_free(hist->dccptxh_slab, entry);
+ struct dccp_tx_hist_entry *head = NULL;
+
+ if (!list_empty(list))
+ head = list_entry(list->next, struct dccp_tx_hist_entry,
+ dccphtx_node);
+ return head;
}
extern struct dccp_tx_hist_entry *
dccp_tx_hist_find_entry(const struct list_head *list,
const u64 seq);
-extern int dccp_rx_hist_find_entry(const struct list_head *list, const u64 seq,
- u8 *ccval);
static inline void dccp_tx_hist_add_entry(struct list_head *list,
struct dccp_tx_hist_entry *entry)
@@ -115,30 +101,45 @@ static inline void dccp_tx_hist_add_entry(struct list_head *list,
list_add(&entry->dccphtx_node, list);
}
+static inline void dccp_tx_hist_entry_delete(struct dccp_tx_hist *hist,
+ struct dccp_tx_hist_entry *entry)
+{
+ if (entry != NULL)
+ kmem_cache_free(hist->dccptxh_slab, entry);
+}
+
+extern void dccp_tx_hist_purge(struct dccp_tx_hist *hist,
+ struct list_head *list);
+
extern void dccp_tx_hist_purge_older(struct dccp_tx_hist *hist,
struct list_head *list,
struct dccp_tx_hist_entry *next);
-extern void dccp_tx_hist_purge(struct dccp_tx_hist *hist,
- struct list_head *list);
+/*
+ * Receiver History data structures and declarations
+ */
+struct dccp_rx_hist_entry {
+ struct list_head dccphrx_node;
+ u64 dccphrx_seqno:48,
+ dccphrx_ccval:4,
+ dccphrx_type:4;
+ u32 dccphrx_ndp; /* In fact it is from 8 to 24 bits */
+ struct timeval dccphrx_tstamp;
+};
-static inline struct dccp_tx_hist_entry *
- dccp_tx_hist_head(struct list_head *list)
-{
- struct dccp_tx_hist_entry *head = NULL;
+struct dccp_rx_hist {
+ struct kmem_cache *dccprxh_slab;
+};
- if (!list_empty(list))
- head = list_entry(list->next, struct dccp_tx_hist_entry,
- dccphtx_node);
- return head;
-}
+extern struct dccp_rx_hist *dccp_rx_hist_new(const char *name);
+extern void dccp_rx_hist_delete(struct dccp_rx_hist *hist);
static inline struct dccp_rx_hist_entry *
- dccp_rx_hist_entry_new(struct dccp_rx_hist *hist,
- const struct sock *sk,
- const u32 ndp,
- const struct sk_buff *skb,
- const gfp_t prio)
+ dccp_rx_hist_entry_new(struct dccp_rx_hist *hist,
+ const struct sock *sk,
+ const u32 ndp,
+ const struct sk_buff *skb,
+ const gfp_t prio)
{
struct dccp_rx_hist_entry *entry = kmem_cache_alloc(hist->dccprxh_slab,
prio);
@@ -156,18 +157,8 @@ static inline struct dccp_rx_hist_entry *
return entry;
}
-static inline void dccp_rx_hist_entry_delete(struct dccp_rx_hist *hist,
- struct dccp_rx_hist_entry *entry)
-{
- if (entry != NULL)
- kmem_cache_free(hist->dccprxh_slab, entry);
-}
-
-extern void dccp_rx_hist_purge(struct dccp_rx_hist *hist,
- struct list_head *list);
-
static inline struct dccp_rx_hist_entry *
- dccp_rx_hist_head(struct list_head *list)
+ dccp_rx_hist_head(struct list_head *list)
{
struct dccp_rx_hist_entry *head = NULL;
@@ -177,6 +168,27 @@ static inline struct dccp_rx_hist_entry *
return head;
}
+extern int dccp_rx_hist_find_entry(const struct list_head *list, const u64 seq,
+ u8 *ccval);
+extern struct dccp_rx_hist_entry *
+ dccp_rx_hist_find_data_packet(const struct list_head *list);
+
+extern void dccp_rx_hist_add_packet(struct dccp_rx_hist *hist,
+ struct list_head *rx_list,
+ struct list_head *li_list,
+ struct dccp_rx_hist_entry *packet,
+ u64 nonloss_seqno);
+
+static inline void dccp_rx_hist_entry_delete(struct dccp_rx_hist *hist,
+ struct dccp_rx_hist_entry *entry)
+{
+ if (entry != NULL)
+ kmem_cache_free(hist->dccprxh_slab, entry);
+}
+
+extern void dccp_rx_hist_purge(struct dccp_rx_hist *hist,
+ struct list_head *list);
+
static inline int
dccp_rx_hist_entry_data_packet(const struct dccp_rx_hist_entry *entry)
{
@@ -184,12 +196,6 @@ static inline int
entry->dccphrx_type == DCCP_PKT_DATAACK;
}
-extern void dccp_rx_hist_add_packet(struct dccp_rx_hist *hist,
- struct list_head *rx_list,
- struct list_head *li_list,
- struct dccp_rx_hist_entry *packet,
- u64 nonloss_seqno);
-
extern u64 dccp_rx_hist_detect_loss(struct list_head *rx_list,
struct list_head *li_list, u8 *win_loss);
diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h
index 45f30f59ea2..faf5f7e219e 100644
--- a/net/dccp/ccids/lib/tfrc.h
+++ b/net/dccp/ccids/lib/tfrc.h
@@ -13,8 +13,29 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
-
#include <linux/types.h>
+#include <asm/div64.h>
+
+/* integer-arithmetic divisions of type (a * 1000000)/b */
+static inline u64 scaled_div(u64 a, u32 b)
+{
+ BUG_ON(b==0);
+ a *= 1000000;
+ do_div(a, b);
+ return a;
+}
+
+static inline u32 scaled_div32(u64 a, u32 b)
+{
+ u64 result = scaled_div(a, b);
+
+ if (result > UINT_MAX) {
+ DCCP_CRIT("Overflow: a(%llu)/b(%u) > ~0U",
+ (unsigned long long)a, b);
+ return UINT_MAX;
+ }
+ return result;
+}
extern u32 tfrc_calc_x(u16 s, u32 R, u32 p);
extern u32 tfrc_calc_x_reverse_lookup(u32 fvalue);
diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c
index ddac2c511e2..90009fd77e1 100644
--- a/net/dccp/ccids/lib/tfrc_equation.c
+++ b/net/dccp/ccids/lib/tfrc_equation.c
@@ -13,7 +13,6 @@
*/
#include <linux/module.h>
-#include <asm/div64.h>
#include "../../dccp.h"
#include "tfrc.h"
@@ -616,15 +615,12 @@ static inline u32 tfrc_binsearch(u32 fval, u8 small)
* @R: RTT scaled by 1000000 (i.e., microseconds)
* @p: loss ratio estimate scaled by 1000000
* Returns X_calc in bytes per second (not scaled).
- *
- * Note: DO NOT alter this code unless you run test cases against it,
- * as the code has been optimized to stop underflow/overflow.
*/
u32 tfrc_calc_x(u16 s, u32 R, u32 p)
{
- int index;
+ u16 index;
u32 f;
- u64 tmp1, tmp2;
+ u64 result;
/* check against invalid parameters and divide-by-zero */
BUG_ON(p > 1000000); /* p must not exceed 100% */
@@ -650,15 +646,17 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p)
f = tfrc_calc_x_lookup[index][0];
}
- /* The following computes X = s/(R*f(p)) in bytes per second. Since f(p)
- * and R are both scaled by 1000000, we need to multiply by 1000000^2.
- * ==> DO NOT alter this unless you test against overflow on 32 bit */
- tmp1 = ((u64)s * 100000000);
- tmp2 = ((u64)R * (u64)f);
- do_div(tmp2, 10000);
- do_div(tmp1, tmp2);
-
- return (u32)tmp1;
+ /*
+ * Compute X = s/(R*f(p)) in bytes per second.
+ * Since f(p) and R are both scaled by 1000000, we need to multiply by
+ * 1000000^2. To avoid overflow, the result is computed in two stages.
+ * This works under almost all reasonable operational conditions, for a
+ * wide range of parameters. Yet, should some strange combination of
+ * parameters result in overflow, the use of scaled_div32 will catch
+ * this and return UINT_MAX - which is a logically adequate consequence.
+ */
+ result = scaled_div(s, R);
+ return scaled_div32(result, f);
}
EXPORT_SYMBOL_GPL(tfrc_calc_x);
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 68886986c8e..a0900bf98e6 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -80,8 +80,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
#define DCCP_RTO_MAX ((unsigned)(120 * HZ)) /* FIXME: using TCP value */
-#define DCCP_XMIT_TIMEO 30000 /* Time/msecs for blocking transmit per packet */
-
/* sysctl variables for DCCP */
extern int sysctl_dccp_request_retries;
extern int sysctl_dccp_retries1;
@@ -434,6 +432,7 @@ static inline void timeval_sub_usecs(struct timeval *tv,
tv->tv_sec--;
tv->tv_usec += USEC_PER_SEC;
}
+ DCCP_BUG_ON(tv->tv_sec < 0);
}
#ifdef CONFIG_SYSCTL
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 4dc487f27a1..95b6927ec65 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -329,7 +329,7 @@ static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
switch (type) {
case DCCPO_CHANGE_L: opt->dccpop_type = DCCPO_CONFIRM_R; break;
case DCCPO_CHANGE_R: opt->dccpop_type = DCCPO_CONFIRM_L; break;
- default: DCCP_WARN("invalid type %d\n", type); return;
+ default: DCCP_WARN("invalid type %d\n", type); return;
}
opt->dccpop_feat = feature;
@@ -427,7 +427,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
switch (type) {
case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break;
case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break;
- default: DCCP_WARN("invalid type %d\n", type);
+ default: DCCP_WARN("invalid type %d\n", type);
return 1;
}
@@ -610,7 +610,7 @@ const char *dccp_feat_typename(const u8 type)
case DCCPO_CHANGE_R: return("ChangeR");
case DCCPO_CONFIRM_R: return("ConfirmR");
/* the following case must not appear in feature negotation */
- default: dccp_pr_debug("unknown type %d [BUG!]\n", type);
+ default: dccp_pr_debug("unknown type %d [BUG!]\n", type);
}
return NULL;
}
diff --git a/net/dccp/input.c b/net/dccp/input.c
index 7371a2f3acf..565bc80557c 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -1,6 +1,6 @@
/*
* net/dccp/input.c
- *
+ *
* An implementation of the DCCP protocol
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
@@ -82,7 +82,7 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
* Otherwise,
* Drop packet and return
*/
- if (dh->dccph_type == DCCP_PKT_SYNC ||
+ if (dh->dccph_type == DCCP_PKT_SYNC ||
dh->dccph_type == DCCP_PKT_SYNCACK) {
if (between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
dp->dccps_awl, dp->dccps_awh) &&
@@ -185,8 +185,8 @@ static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
dccp_rcv_close(sk, skb);
return 0;
case DCCP_PKT_REQUEST:
- /* Step 7
- * or (S.is_server and P.type == Response)
+ /* Step 7
+ * or (S.is_server and P.type == Response)
* or (S.is_client and P.type == Request)
* or (S.state >= OPEN and P.type == Request
* and P.seqno >= S.OSR)
@@ -248,8 +248,18 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
DCCP_ACKVEC_STATE_RECEIVED))
goto discard;
- ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
- ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
+ /*
+ * Deliver to the CCID module in charge.
+ * FIXME: Currently DCCP operates one-directional only, i.e. a listening
+ * server is not at the same time a connecting client. There is
+ * not much sense in delivering to both rx/tx sides at the moment
+ * (only one is active at a time); when moving to bidirectional
+ * service, this needs to be revised.
+ */
+ if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER)
+ ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
+ else
+ ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
return __dccp_rcv_established(sk, skb, dh, len);
discard:
@@ -264,7 +274,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
const struct dccp_hdr *dh,
const unsigned len)
{
- /*
+ /*
* Step 4: Prepare sequence numbers in REQUEST
* If S.state == REQUEST,
* If (P.type == Response or P.type == Reset)
@@ -332,7 +342,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
* from the Response * /
* S.state := PARTOPEN
* Set PARTOPEN timer
- * Continue with S.state == PARTOPEN
+ * Continue with S.state == PARTOPEN
* / * Step 12 will send the Ack completing the
* three-way handshake * /
*/
@@ -363,7 +373,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
*/
__kfree_skb(skb);
return 0;
- }
+ }
dccp_send_ack(sk);
return -1;
}
@@ -371,7 +381,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
out_invalid_packet:
/* dccp_v4_do_rcv will send a reset */
DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
- return 1;
+ return 1;
}
static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
@@ -478,14 +488,17 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
dccp_event_ack_recv(sk, skb);
- if (dccp_msk(sk)->dccpms_send_ack_vector &&
+ if (dccp_msk(sk)->dccpms_send_ack_vector &&
dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
- DCCP_SKB_CB(skb)->dccpd_seq,
- DCCP_ACKVEC_STATE_RECEIVED))
- goto discard;
+ DCCP_SKB_CB(skb)->dccpd_seq,
+ DCCP_ACKVEC_STATE_RECEIVED))
+ goto discard;
- ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
- ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
+ /* XXX see the comments in dccp_rcv_established about this */
+ if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER)
+ ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
+ else
+ ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
}
/*
@@ -567,7 +580,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
}
}
- if (!queued) {
+ if (!queued) {
discard:
__kfree_skb(skb);
}
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index ff81679c9f1..fa2c982d430 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -72,7 +72,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
tmp = ip_route_connect(&rt, nexthop, inet->saddr,
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
IPPROTO_DCCP,
- inet->sport, usin->sin_port, sk);
+ inet->sport, usin->sin_port, sk, 1);
if (tmp < 0)
return tmp;
@@ -157,7 +157,7 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk,
/* We don't check in the destentry if pmtu discovery is forbidden
* on this route. We just assume that no packet_to_big packets
* are send back when pmtu discovery is not active.
- * There is a small race when the user changes this flag in the
+ * There is a small race when the user changes this flag in the
* route, but I think that's acceptable.
*/
if ((dst = __sk_dst_check(sk, 0)) == NULL)
@@ -467,7 +467,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
.uli_u = { .ports =
{ .sport = dccp_hdr(skb)->dccph_dport,
.dport = dccp_hdr(skb)->dccph_sport }
- }
+ }
};
security_skb_classify_flow(skb, &fl);
@@ -595,7 +595,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
struct inet_request_sock *ireq;
struct request_sock *req;
struct dccp_request_sock *dreq;
- const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
+ const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
__u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
@@ -609,7 +609,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
if (dccp_bad_service_code(sk, service)) {
reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
goto drop;
- }
+ }
/*
* TW buckets are converted to open requests without
* limitations, they conserve resources and peer is
@@ -644,7 +644,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
ireq->rmt_addr = skb->nh.iph->saddr;
ireq->opt = NULL;
- /*
+ /*
* Step 3: Process LISTEN state
*
* Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
@@ -846,15 +846,15 @@ static int dccp_v4_rcv(struct sk_buff *skb)
}
/* Step 2:
- * Look up flow ID in table and get corresponding socket */
+ * Look up flow ID in table and get corresponding socket */
sk = __inet_lookup(&dccp_hashinfo,
skb->nh.iph->saddr, dh->dccph_sport,
skb->nh.iph->daddr, dh->dccph_dport,
inet_iif(skb));
- /*
+ /*
* Step 2:
- * If no socket ...
+ * If no socket ...
*/
if (sk == NULL) {
dccp_pr_debug("failed to look up flow ID in table and "
@@ -862,9 +862,9 @@ static int dccp_v4_rcv(struct sk_buff *skb)
goto no_dccp_socket;
}
- /*
+ /*
* Step 2:
- * ... or S.state == TIMEWAIT,
+ * ... or S.state == TIMEWAIT,
* Generate Reset(No Connection) unless P.type == Reset
* Drop packet and return
*/
@@ -876,8 +876,8 @@ static int dccp_v4_rcv(struct sk_buff *skb)
/*
* RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
- * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
- * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
+ * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
+ * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
*/
min_cov = dccp_sk(sk)->dccps_pcrlen;
if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
@@ -900,7 +900,7 @@ no_dccp_socket:
goto discard_it;
/*
* Step 2:
- * If no socket ...
+ * If no socket ...
* Generate Reset(No Connection) unless P.type == Reset
* Drop packet and return
*/
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index c7aaa2574f5..79140b3e592 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -77,7 +77,7 @@ static inline void dccp_v6_send_check(struct sock *sk, int unused_value,
}
static inline __u32 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
- __be16 sport, __be16 dport )
+ __be16 sport, __be16 dport )
{
return secure_tcpv6_sequence_number(saddr, daddr, sport, dport);
}
@@ -329,7 +329,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header,
GFP_ATOMIC);
if (skb == NULL)
- return;
+ return;
skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header);
@@ -353,7 +353,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
dccp_csum_outgoing(skb);
dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr,
- &rxskb->nh.ipv6h->daddr);
+ &rxskb->nh.ipv6h->daddr);
memset(&fl, 0, sizeof(fl));
ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr);
@@ -424,7 +424,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
struct dccp_request_sock *dreq;
struct inet6_request_sock *ireq6;
struct ipv6_pinfo *np = inet6_sk(sk);
- const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
+ const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
__u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
@@ -437,7 +437,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
if (dccp_bad_service_code(sk, service)) {
reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
goto drop;
- }
+ }
/*
* There are no SYN attacks on IPv6, yet...
*/
@@ -787,7 +787,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
* otherwise we just shortcircuit this and continue with
* the new socket..
*/
- if (nsk != sk) {
+ if (nsk != sk) {
if (dccp_child_process(sk, nsk, skb))
goto reset;
if (opt_skb != NULL)
@@ -843,14 +843,14 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
/* Step 2:
- * Look up flow ID in table and get corresponding socket */
+ * Look up flow ID in table and get corresponding socket */
sk = __inet6_lookup(&dccp_hashinfo, &skb->nh.ipv6h->saddr,
dh->dccph_sport,
&skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport),
inet6_iif(skb));
/*
* Step 2:
- * If no socket ...
+ * If no socket ...
*/
if (sk == NULL) {
dccp_pr_debug("failed to look up flow ID in table and "
@@ -860,7 +860,7 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
/*
* Step 2:
- * ... or S.state == TIMEWAIT,
+ * ... or S.state == TIMEWAIT,
* Generate Reset(No Connection) unless P.type == Reset
* Drop packet and return
*/
@@ -872,8 +872,8 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
/*
* RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
- * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
- * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
+ * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
+ * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
*/
min_cov = dccp_sk(sk)->dccps_pcrlen;
if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
@@ -893,7 +893,7 @@ no_dccp_socket:
goto discard_it;
/*
* Step 2:
- * If no socket ...
+ * If no socket ...
* Generate Reset(No Connection) unless P.type == Reset
* Drop packet and return
*/
@@ -1041,7 +1041,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
- err = xfrm_lookup(&dst, &fl, sk, 0);
+ err = xfrm_lookup(&dst, &fl, sk, 1);
if (err < 0)
goto failure;
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
index 4c9e26775f7..6656bb497c7 100644
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -182,7 +182,7 @@ out_free:
EXPORT_SYMBOL_GPL(dccp_create_openreq_child);
-/*
+/*
* Process an incoming packet for RESPOND sockets represented
* as an request_sock.
*/
diff --git a/net/dccp/options.c b/net/dccp/options.c
index f398b43bc05..c03ba61eb6d 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -557,11 +557,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
return -1;
dp->dccps_hc_rx_insert_options = 0;
}
- if (dp->dccps_hc_tx_insert_options) {
- if (ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb))
- return -1;
- dp->dccps_hc_tx_insert_options = 0;
- }
/* Feature negotiation */
/* Data packets can't do feat negotiation */
diff --git a/net/dccp/output.c b/net/dccp/output.c
index 400c30b6fca..3435542e965 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -1,6 +1,6 @@
/*
* net/dccp/output.c
- *
+ *
* An implementation of the DCCP protocol
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
@@ -124,7 +124,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
- err = icsk->icsk_af_ops->queue_xmit(skb, sk, 0);
+ err = icsk->icsk_af_ops->queue_xmit(skb, 0);
return net_xmit_eval(err);
}
return -ENOBUFS;
@@ -175,14 +175,12 @@ void dccp_write_space(struct sock *sk)
/**
* dccp_wait_for_ccid - Wait for ccid to tell us we can send a packet
* @sk: socket to wait for
- * @timeo: for how long
*/
-static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb,
- long *timeo)
+static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
DEFINE_WAIT(wait);
- long delay;
+ unsigned long delay;
int rc;
while (1) {
@@ -190,8 +188,6 @@ static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb,
if (sk->sk_err)
goto do_error;
- if (!*timeo)
- goto do_nonblock;
if (signal_pending(current))
goto do_interrupted;
@@ -199,12 +195,9 @@ static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb,
if (rc <= 0)
break;
delay = msecs_to_jiffies(rc);
- if (delay > *timeo || delay < 0)
- goto do_nonblock;
-
sk->sk_write_pending++;
release_sock(sk);
- *timeo -= schedule_timeout(delay);
+ schedule_timeout(delay);
lock_sock(sk);
sk->sk_write_pending--;
}
@@ -215,11 +208,8 @@ out:
do_error:
rc = -EPIPE;
goto out;
-do_nonblock:
- rc = -EAGAIN;
- goto out;
do_interrupted:
- rc = sock_intr_errno(*timeo);
+ rc = -EINTR;
goto out;
}
@@ -240,8 +230,6 @@ void dccp_write_xmit(struct sock *sk, int block)
{
struct dccp_sock *dp = dccp_sk(sk);
struct sk_buff *skb;
- long timeo = DCCP_XMIT_TIMEO; /* If a packet is taking longer than
- this we have other issues */
while ((skb = skb_peek(&sk->sk_write_queue))) {
int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);
@@ -251,11 +239,9 @@ void dccp_write_xmit(struct sock *sk, int block)
sk_reset_timer(sk, &dp->dccps_xmit_timer,
msecs_to_jiffies(err)+jiffies);
break;
- } else {
- err = dccp_wait_for_ccid(sk, skb, &timeo);
- timeo = DCCP_XMIT_TIMEO;
- }
- if (err)
+ } else
+ err = dccp_wait_for_ccid(sk, skb);
+ if (err && err != -EINTR)
DCCP_BUG("err=%d after dccp_wait_for_ccid", err);
}
@@ -281,8 +267,10 @@ void dccp_write_xmit(struct sock *sk, int block)
if (err)
DCCP_BUG("err=%d after ccid_hc_tx_packet_sent",
err);
- } else
+ } else {
+ dccp_pr_debug("packet discarded\n");
kfree(skb);
+ }
}
}
@@ -350,7 +338,6 @@ EXPORT_SYMBOL_GPL(dccp_make_response);
static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
const enum dccp_reset_codes code)
-
{
struct dccp_hdr *dh;
struct dccp_sock *dp = dccp_sk(sk);
@@ -409,7 +396,7 @@ int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code)
code);
if (skb != NULL) {
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
- err = inet_csk(sk)->icsk_af_ops->queue_xmit(skb, sk, 0);
+ err = inet_csk(sk)->icsk_af_ops->queue_xmit(skb, 0);
return net_xmit_eval(err);
}
}
@@ -431,14 +418,14 @@ static inline void dccp_connect_init(struct sock *sk)
dccp_sync_mss(sk, dst_mtu(dst));
- /*
+ /*
* SWL and AWL are initially adjusted so that they are not less than
* the initial Sequence Numbers received and sent, respectively:
* SWL := max(GSR + 1 - floor(W/4), ISR),
* AWL := max(GSS - W' + 1, ISS).
* These adjustments MUST be applied only at the beginning of the
* connection.
- */
+ */
dccp_update_gss(sk, dp->dccps_iss);
dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss));
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 5ec47d9ee44..48438565d70 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -196,7 +196,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
sk, GFP_KERNEL);
dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
sk, GFP_KERNEL);
- if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
+ if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
dp->dccps_hc_tx_ccid == NULL)) {
ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
@@ -390,7 +390,7 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
struct dccp_sock *dp = dccp_sk(sk);
struct dccp_service_list *sl = NULL;
- if (service == DCCP_SERVICE_INVALID_VALUE ||
+ if (service == DCCP_SERVICE_INVALID_VALUE ||
optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32))
return -EINVAL;
@@ -830,7 +830,7 @@ EXPORT_SYMBOL_GPL(inet_dccp_listen);
static const unsigned char dccp_new_state[] = {
/* current state: new state: action: */
[0] = DCCP_CLOSED,
- [DCCP_OPEN] = DCCP_CLOSING | DCCP_ACTION_FIN,
+ [DCCP_OPEN] = DCCP_CLOSING | DCCP_ACTION_FIN,
[DCCP_REQUESTING] = DCCP_CLOSED,
[DCCP_PARTOPEN] = DCCP_CLOSING | DCCP_ACTION_FIN,
[DCCP_LISTEN] = DCCP_CLOSED,
@@ -1024,7 +1024,6 @@ static int __init dccp_init(void)
do {
dccp_hashinfo.ehash_size = (1UL << ehash_order) * PAGE_SIZE /
sizeof(struct inet_ehash_bucket);
- dccp_hashinfo.ehash_size >>= 1;
while (dccp_hashinfo.ehash_size &
(dccp_hashinfo.ehash_size - 1))
dccp_hashinfo.ehash_size--;
@@ -1037,9 +1036,10 @@ static int __init dccp_init(void)
goto out_free_bind_bucket_cachep;
}
- for (i = 0; i < (dccp_hashinfo.ehash_size << 1); i++) {
+ for (i = 0; i < dccp_hashinfo.ehash_size; i++) {
rwlock_init(&dccp_hashinfo.ehash[i].lock);
INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].chain);
+ INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].twchain);
}
bhash_order = ehash_order;
diff --git a/net/dccp/timer.c b/net/dccp/timer.c
index e8f519e7f48..e5348f369c6 100644
--- a/net/dccp/timer.c
+++ b/net/dccp/timer.c
@@ -1,6 +1,6 @@
/*
* net/dccp/timer.c
- *
+ *
* An implementation of the DCCP protocol
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
@@ -102,13 +102,13 @@ static void dccp_retransmit_timer(struct sock *sk)
* sk->sk_send_head has to have one skb with
* DCCP_SKB_CB(skb)->dccpd_type set to one of the retransmittable DCCP
* packet types. The only packets eligible for retransmission are:
- * -- Requests in client-REQUEST state (sec. 8.1.1)
- * -- Acks in client-PARTOPEN state (sec. 8.1.5)
- * -- CloseReq in server-CLOSEREQ state (sec. 8.3)
- * -- Close in node-CLOSING state (sec. 8.3) */
+ * -- Requests in client-REQUEST state (sec. 8.1.1)
+ * -- Acks in client-PARTOPEN state (sec. 8.1.5)
+ * -- CloseReq in server-CLOSEREQ state (sec. 8.3)
+ * -- Close in node-CLOSING state (sec. 8.3) */
BUG_TRAP(sk->sk_send_head != NULL);
- /*
+ /*
* More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
* sent, no need to retransmit, this sock is dead.
*/
@@ -200,7 +200,7 @@ static void dccp_keepalive_timer(unsigned long data)
/* Only process if socket is not in use. */
bh_lock_sock(sk);
if (sock_owned_by_user(sk)) {
- /* Try again later. */
+ /* Try again later. */
inet_csk_reset_keepalive_timer(sk, HZ / 20);
goto out;
}
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 0b9d4c95515..90b3dfd72b4 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -167,8 +167,7 @@ static int dn_forwarding_proc(ctl_table *, int, struct file *,
void __user *, size_t *, loff_t *);
static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context);
+ void __user *newval, size_t newlen);
static struct dn_dev_sysctl_table {
struct ctl_table_header *sysctl_header;
@@ -347,8 +346,7 @@ static int dn_forwarding_proc(ctl_table *table, int write,
static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
+ void __user *newval, size_t newlen)
{
#ifdef CONFIG_DECNET_ROUTER
struct net_device *dev = table->extra1;
@@ -751,7 +749,7 @@ static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
ifm = nlmsg_data(nlh);
ifm->ifa_family = AF_DECnet;
@@ -770,7 +768,8 @@ static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
return nlmsg_end(skb, nlh);
nla_put_failure:
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
@@ -783,9 +782,12 @@ static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
goto errout;
err = dn_nl_fill_ifaddr(skb, ifa, 0, 0, event, 0);
- /* failure implies BUG in dn_ifaddr_nlmsg_size() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in dn_ifaddr_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
errout:
if (err < 0)
@@ -1147,16 +1149,23 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
init_timer(&dn_db->timer);
dn_db->uptime = jiffies;
+
+ dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
+ if (!dn_db->neigh_parms) {
+ dev->dn_ptr = NULL;
+ kfree(dn_db);
+ return NULL;
+ }
+
if (dn_db->parms.up) {
if (dn_db->parms.up(dev) < 0) {
+ neigh_parms_release(&dn_neigh_table, dn_db->neigh_parms);
dev->dn_ptr = NULL;
kfree(dn_db);
return NULL;
}
}
- dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
-
dn_dev_sysctl_register(dev, &dn_db->parms);
dn_dev_set_timer(dev);
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index 13b2421991b..c1f0cc1b1c6 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -350,7 +350,7 @@ static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
nlmsg_failure:
rtattr_failure:
skb_trim(skb, b - skb->data);
- return -1;
+ return -EMSGSIZE;
}
@@ -368,9 +368,12 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id,
f->fn_type, f->fn_scope, &f->fn_key, z,
DN_FIB_INFO(f), 0);
- /* failure implies BUG in dn_fib_nlmsg_size() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in dn_fib_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
errout:
if (err < 0)
diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c
index e246f054f36..a4065eb1341 100644
--- a/net/decnet/sysctl_net_decnet.c
+++ b/net/decnet/sysctl_net_decnet.c
@@ -134,8 +134,7 @@ static int parse_addr(__le16 *addr, char *str)
static int dn_node_address_strategy(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
+ void __user *newval, size_t newlen)
{
size_t len;
__le16 addr;
@@ -220,8 +219,7 @@ static int dn_node_address_handler(ctl_table *table, int write,
static int dn_def_dev_strategy(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
+ void __user *newval, size_t newlen)
{
size_t len;
struct net_device *dev;
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index eec1a1dd91d..a824852909e 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -167,7 +167,7 @@ static void
ieee80211softmac_assoc_notify_scan(struct net_device *dev, int event_type, void *context)
{
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
- ieee80211softmac_assoc_work((void*)mac);
+ ieee80211softmac_assoc_work(&mac->associnfo.work.work);
}
static void
@@ -177,7 +177,7 @@ ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void
switch (event_type) {
case IEEE80211SOFTMAC_EVENT_AUTHENTICATED:
- ieee80211softmac_assoc_work((void*)mac);
+ ieee80211softmac_assoc_work(&mac->associnfo.work.work);
break;
case IEEE80211SOFTMAC_EVENT_AUTH_FAILED:
case IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT:
@@ -438,7 +438,7 @@ ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac)
spin_lock_irqsave(&mac->lock, flags);
mac->associnfo.associating = 1;
- schedule_work(&mac->associnfo.work);
+ schedule_delayed_work(&mac->associnfo.work, 0);
spin_unlock_irqrestore(&mac->lock, flags);
}
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 480d72c7a42..fb58e03b3fb 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -265,6 +265,12 @@ ieee80211softmac_wx_get_rate(struct net_device *net_dev,
int err = -EINVAL;
spin_lock_irqsave(&mac->lock, flags);
+
+ if (unlikely(!mac->running)) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
switch (mac->txrates.default_rate) {
case IEEE80211_CCK_RATE_1MB:
data->bitrate.value = 1000000;
@@ -463,7 +469,7 @@ ieee80211softmac_wx_get_genie(struct net_device *dev,
err = -E2BIG;
}
spin_unlock_irqrestore(&mac->lock, flags);
- mutex_lock(&mac->associnfo.mutex);
+ mutex_unlock(&mac->associnfo.mutex);
return err;
}
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 1144900d37f..5750a2b2a0d 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -305,7 +305,7 @@ lookup_protocol:
sk->sk_reuse = 1;
inet = inet_sk(sk);
- inet->is_icsk = INET_PROTOSW_ICSK & answer_flags;
+ inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
if (SOCK_RAW == sock->type) {
inet->num = protocol;
@@ -1007,7 +1007,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
RT_CONN_FLAGS(sk),
sk->sk_bound_dev_if,
sk->sk_protocol,
- inet->sport, inet->dport, sk);
+ inet->sport, inet->dport, sk, 0);
if (err)
return err;
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
index 7b068a89195..0072d79f0c2 100644
--- a/net/ipv4/datagram.c
+++ b/net/ipv4/datagram.c
@@ -49,7 +49,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr,
RT_CONN_FLAGS(sk), oif,
sk->sk_protocol,
- inet->sport, usin->sin_port, sk);
+ inet->sport, usin->sin_port, sk, 1);
if (err)
return err;
if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) {
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 2fd899160f8..c4020364096 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -165,9 +165,8 @@ struct in_device *inetdev_init(struct net_device *dev)
NET_IPV4_NEIGH, "ipv4", NULL, NULL);
#endif
- /* Account for reference dev->ip_ptr */
+ /* Account for reference dev->ip_ptr (below) */
in_dev_hold(in_dev);
- rcu_assign_pointer(dev->ip_ptr, in_dev);
#ifdef CONFIG_SYSCTL
devinet_sysctl_register(in_dev, &in_dev->cnf);
@@ -175,6 +174,9 @@ struct in_device *inetdev_init(struct net_device *dev)
ip_mc_init_dev(in_dev);
if (dev->flags & IFF_UP)
ip_mc_up(in_dev);
+
+ /* we can receive as soon as ip_ptr is set -- do this last */
+ rcu_assign_pointer(dev->ip_ptr, in_dev);
out:
return in_dev;
out_kfree:
@@ -1138,7 +1140,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
ifm = nlmsg_data(nlh);
ifm->ifa_family = AF_INET;
@@ -1165,7 +1167,8 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
return nlmsg_end(skb, nlh);
nla_put_failure:
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
@@ -1223,9 +1226,12 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
goto errout;
err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
- /* failure implies BUG in inet_nlmsg_size() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in inet_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
errout:
if (err < 0)
@@ -1303,8 +1309,7 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write,
int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
+ void __user *newval, size_t newlen)
{
int *valp = table->data;
int new;
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index e63b8a98fb4..be1028c9933 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -314,9 +314,12 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
err = fib_dump_info(skb, info->pid, seq, event, tb_id,
fa->fa_type, fa->fa_scope, key, dst_len,
fa->fa_tos, fa->fa_info, 0);
- /* failure implies BUG in fib_nlmsg_size() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in fib_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE,
info->nlh, GFP_KERNEL);
errout:
@@ -960,7 +963,7 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
rtm = nlmsg_data(nlh);
rtm->rtm_family = AF_INET;
@@ -1031,7 +1034,8 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
return nlmsg_end(skb, nlh);
nla_put_failure:
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
/*
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index cfb249cc0a5..1e589b91605 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1989,6 +1989,10 @@ static struct node *fib_trie_get_next(struct fib_trie_iter *iter)
unsigned cindex = iter->index;
struct tnode *p;
+ /* A single entry routing table */
+ if (!tn)
+ return NULL;
+
pr_debug("get_next iter={node=%p index=%d depth=%d}\n",
iter->tnode, iter->index, iter->depth);
rescan:
@@ -2037,11 +2041,18 @@ static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
if(!iter)
return NULL;
- if (n && IS_TNODE(n)) {
- iter->tnode = (struct tnode *) n;
- iter->trie = t;
- iter->index = 0;
- iter->depth = 1;
+ if (n) {
+ if (IS_TNODE(n)) {
+ iter->tnode = (struct tnode *) n;
+ iter->trie = t;
+ iter->index = 0;
+ iter->depth = 1;
+ } else {
+ iter->tnode = NULL;
+ iter->trie = t;
+ iter->index = 0;
+ iter->depth = 0;
+ }
return n;
}
return NULL;
@@ -2279,16 +2290,17 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
if (v == SEQ_START_TOKEN)
return 0;
+ if (!NODE_PARENT(n)) {
+ if (iter->trie == trie_local)
+ seq_puts(seq, "<local>:\n");
+ else
+ seq_puts(seq, "<main>:\n");
+ }
+
if (IS_TNODE(n)) {
struct tnode *tn = (struct tnode *) n;
__be32 prf = htonl(MASK_PFX(tn->key, tn->pos));
- if (!NODE_PARENT(n)) {
- if (iter->trie == trie_local)
- seq_puts(seq, "<local>:\n");
- else
- seq_puts(seq, "<main>:\n");
- }
seq_indent(seq, iter->depth-1);
seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n",
NIPQUAD(prf), tn->pos, tn->bits, tn->full_children,
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 0017ccb01d6..024ae56cab2 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -455,6 +455,8 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
skb = add_grhead(skb, pmc, type, &pgr);
first = 0;
}
+ if (!skb)
+ return NULL;
psrc = (__be32 *)skb_put(skb, sizeof(__be32));
*psrc = psf->sf_inaddr;
scount++; stotal++;
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 77761ac4f7b..8aa7d51e688 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -153,7 +153,7 @@ static int inet_csk_diag_fill(struct sock *sk,
rtattr_failure:
nlmsg_failure:
skb_trim(skb, b - skb->data);
- return -1;
+ return -EMSGSIZE;
}
static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
@@ -209,7 +209,7 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
return skb->len;
nlmsg_failure:
skb_trim(skb, previous_tail - skb->data);
- return -1;
+ return -EMSGSIZE;
}
static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
@@ -274,11 +274,14 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
if (!rep)
goto out;
- if (sk_diag_fill(sk, rep, req->idiag_ext,
- NETLINK_CB(in_skb).pid,
- nlh->nlmsg_seq, 0, nlh) <= 0)
- BUG();
-
+ err = sk_diag_fill(sk, rep, req->idiag_ext,
+ NETLINK_CB(in_skb).pid,
+ nlh->nlmsg_seq, 0, nlh);
+ if (err < 0) {
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(rep);
+ goto out;
+ }
err = netlink_unicast(idiagnl, rep, NETLINK_CB(in_skb).pid,
MSG_DONTWAIT);
if (err > 0)
@@ -775,7 +778,7 @@ next_normal:
struct inet_timewait_sock *tw;
inet_twsk_for_each(tw, node,
- &hashinfo->ehash[i + hashinfo->ehash_size].chain) {
+ &head->twchain) {
if (num < s_num)
goto next_dying;
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 8c79c8a4ea5..150ace18dc7 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -212,7 +212,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
write_lock(&head->lock);
/* Check TIME-WAIT sockets first. */
- sk_for_each(sk2, node, &(head + hinfo->ehash_size)->chain) {
+ sk_for_each(sk2, node, &head->twchain) {
tw = inet_twsk(sk2);
if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) {
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index 9f414e35c48..a73cf93cee3 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -78,8 +78,8 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
if (__sk_del_node_init(sk))
sock_prot_dec_use(sk->sk_prot);
- /* Step 3: Hash TW into TIMEWAIT half of established hash table. */
- inet_twsk_add_node(tw, &(ehead + hashinfo->ehash_size)->chain);
+ /* Step 3: Hash TW into TIMEWAIT chain. */
+ inet_twsk_add_node(tw, &ehead->twchain);
atomic_inc(&tw->tw_refcnt);
write_unlock(&ehead->lock);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 74046efdf87..8ce00d3703d 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -565,7 +565,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
} else {
struct sk_buff *free_it = next;
- /* Old fragmnet is completely overridden with
+ /* Old fragment is completely overridden with
* new one drop it.
*/
next = next->next;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 476cb6084c7..51c83500790 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1008,7 +1008,8 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
goto done;
dev = t->dev;
}
- err = unregister_netdevice(dev);
+ unregister_netdevice(dev);
+ err = 0;
break;
default:
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index a35209d517a..a0f2008584b 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -164,7 +164,6 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
static inline int ip_finish_output2(struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
- struct hh_cache *hh = dst->hh;
struct net_device *dev = dst->dev;
int hh_len = LL_RESERVED_SPACE(dev);
@@ -183,16 +182,9 @@ static inline int ip_finish_output2(struct sk_buff *skb)
skb = skb2;
}
- if (hh) {
- int hh_alen;
-
- read_lock_bh(&hh->hh_lock);
- hh_alen = HH_DATA_ALIGN(hh->hh_len);
- memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
- read_unlock_bh(&hh->hh_lock);
- skb_push(skb, hh->hh_len);
- return hh->hh_output(skb);
- } else if (dst->neighbour)
+ if (dst->hh)
+ return neigh_hh_output(dst->hh, skb);
+ else if (dst->neighbour)
return dst->neighbour->output(skb);
if (net_ratelimit())
@@ -289,8 +281,9 @@ int ip_output(struct sk_buff *skb)
!(IPCB(skb)->flags & IPSKB_REROUTED));
}
-int ip_queue_xmit(struct sk_buff *skb, struct sock *sk, int ipfragok)
+int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
{
+ struct sock *sk = skb->sk;
struct inet_sock *inet = inet_sk(sk);
struct ip_options *opt = inet->opt;
struct rtable *rt;
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 9d719d664e5..da8bbd20c7e 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -754,7 +754,8 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
goto done;
dev = t->dev;
}
- err = unregister_netdevice(dev);
+ unregister_netdevice(dev);
+ err = 0;
break;
default:
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index 91a075edd68..7ea2d981a93 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -657,7 +657,7 @@ static void sync_master_loop(void)
if (stop_master_sync)
break;
- ssleep(1);
+ msleep_interruptible(1000);
}
/* clean up the sync_buff queue */
@@ -714,7 +714,7 @@ static void sync_backup_loop(void)
if (stop_backup_sync)
break;
- ssleep(1);
+ msleep_interruptible(1000);
}
/* release the sending multicast socket */
@@ -826,7 +826,7 @@ static int fork_sync_thread(void *startup)
if ((pid = kernel_thread(sync_thread, startup, 0)) < 0) {
IP_VS_ERR("could not create sync_thread due to %d... "
"retrying.\n", pid);
- ssleep(1);
+ msleep_interruptible(1000);
goto repeat;
}
@@ -849,10 +849,12 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
ip_vs_sync_state |= state;
if (state == IP_VS_STATE_MASTER) {
- strlcpy(ip_vs_master_mcast_ifn, mcast_ifn, sizeof(ip_vs_master_mcast_ifn));
+ strlcpy(ip_vs_master_mcast_ifn, mcast_ifn,
+ sizeof(ip_vs_master_mcast_ifn));
ip_vs_master_syncid = syncid;
} else {
- strlcpy(ip_vs_backup_mcast_ifn, mcast_ifn, sizeof(ip_vs_backup_mcast_ifn));
+ strlcpy(ip_vs_backup_mcast_ifn, mcast_ifn,
+ sizeof(ip_vs_backup_mcast_ifn));
ip_vs_backup_syncid = syncid;
}
@@ -860,7 +862,7 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0) {
IP_VS_ERR("could not create fork_sync_thread due to %d... "
"retrying.\n", pid);
- ssleep(1);
+ msleep_interruptible(1000);
goto repeat;
}
@@ -880,7 +882,8 @@ int stop_sync_thread(int state)
IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, current->pid);
IP_VS_INFO("stopping sync thread %d ...\n",
- (state == IP_VS_STATE_MASTER) ? sync_master_pid : sync_backup_pid);
+ (state == IP_VS_STATE_MASTER) ?
+ sync_master_pid : sync_backup_pid);
__set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&stop_sync_wait, &wait);
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index a68966059b5..c47ce7076bd 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -15,16 +15,19 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
struct flowi fl = {};
struct dst_entry *odst;
unsigned int hh_len;
+ unsigned int type;
+ type = inet_addr_type(iph->saddr);
if (addr_type == RTN_UNSPEC)
- addr_type = inet_addr_type(iph->saddr);
+ addr_type = type;
/* 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 (addr_type == RTN_LOCAL) {
fl.nl_u.ip4_u.daddr = iph->daddr;
- fl.nl_u.ip4_u.saddr = iph->saddr;
+ if (type == RTN_LOCAL)
+ fl.nl_u.ip4_u.saddr = iph->saddr;
fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
fl.mark = (*pskb)->mark;
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 363df9976c9..9b08e7ad71b 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -6,8 +6,8 @@ menu "IP: Netfilter Configuration"
depends on INET && NETFILTER
config NF_CONNTRACK_IPV4
- tristate "IPv4 connection tracking support (required for NAT) (EXPERIMENTAL)"
- depends on EXPERIMENTAL && NF_CONNTRACK
+ tristate "IPv4 connection tracking support (required for NAT)"
+ depends on NF_CONNTRACK
---help---
Connection tracking keeps a record of what packets have passed
through your machine, in order to figure out how they are related
@@ -361,32 +361,6 @@ config IP_NF_TARGET_ULOG
To compile it as a module, choose M here. If unsure, say N.
-config IP_NF_TARGET_TCPMSS
- tristate "TCPMSS target support"
- depends on IP_NF_IPTABLES
- ---help---
- This option adds a `TCPMSS' target, which allows you to alter the
- MSS value of TCP SYN packets, to control the maximum size for that
- connection (usually limiting it to your outgoing interface's MTU
- minus 40).
-
- This is used to overcome criminally braindead ISPs or servers which
- block ICMP Fragmentation Needed packets. The symptoms of this
- problem are that everything works fine from your Linux
- firewall/router, but machines behind it can never exchange large
- packets:
- 1) Web browsers connect, then hang with no data received.
- 2) Small mail works fine, but large emails hang.
- 3) ssh works fine, but scp hangs after initial handshaking.
-
- Workaround: activate this option and add a rule to your firewall
- configuration like:
-
- iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
- -j TCPMSS --clamp-mss-to-pmtu
-
- To compile it as a module, choose M here. If unsure, say N.
-
# NAT + specific targets: ip_conntrack
config IP_NF_NAT
tristate "Full NAT"
@@ -401,7 +375,7 @@ config IP_NF_NAT
# NAT + specific targets: nf_conntrack
config NF_NAT
tristate "Full NAT"
- depends on IP_NF_IPTABLES && NF_CONNTRACK
+ depends on IP_NF_IPTABLES && NF_CONNTRACK_IPV4
help
The Full NAT option allows masquerading, port forwarding and other
forms of full Network Address Port Translation. It is controlled by
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 15e741aeb29..6625ec68180 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -4,6 +4,14 @@
# objects for the standalone - connection tracking / NAT
ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
+# objects for l3 independent conntrack
+nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o
+ifeq ($(CONFIG_NF_CONNTRACK_PROC_COMPAT),y)
+ifeq ($(CONFIG_PROC_FS),y)
+nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o
+endif
+endif
+
ip_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o
ifneq ($(CONFIG_NF_NAT),)
@@ -20,6 +28,8 @@ ip_nat_h323-objs := ip_nat_helper_h323.o
# connection tracking
obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
+obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
+
obj-$(CONFIG_IP_NF_NAT) += ip_nat.o
obj-$(CONFIG_NF_NAT) += nf_nat.o
@@ -93,7 +103,6 @@ obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
-obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
@@ -106,13 +115,3 @@ obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
-# objects for l3 independent conntrack
-nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o
-ifeq ($(CONFIG_NF_CONNTRACK_PROC_COMPAT),y)
-ifeq ($(CONFIG_PROC_FS),y)
-nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o
-endif
-endif
-
-# l3 independent conntrack
-obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 71b76ade00e..9aa22398b3d 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -358,6 +358,7 @@ static int mark_source_chains(struct xt_table_info *newinfo,
for (;;) {
struct arpt_standard_target *t
= (void *)arpt_get_target(e);
+ int visited = e->comefrom & (1 << hook);
if (e->comefrom & (1 << NF_ARP_NUMHOOKS)) {
printk("arptables: loop hook %u pos %u %08X.\n",
@@ -368,11 +369,11 @@ static int mark_source_chains(struct xt_table_info *newinfo,
|= ((1 << hook) | (1 << NF_ARP_NUMHOOKS));
/* Unconditional return/END. */
- if (e->target_offset == sizeof(struct arpt_entry)
+ if ((e->target_offset == sizeof(struct arpt_entry)
&& (strcmp(t->target.u.user.name,
ARPT_STANDARD_TARGET) == 0)
&& t->verdict < 0
- && unconditional(&e->arp)) {
+ && unconditional(&e->arp)) || visited) {
unsigned int oldpos, size;
if (t->verdict < -NF_MAX_VERDICT - 1) {
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index 5fcf91d617c..7f70b0886b8 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -374,9 +374,11 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
&& ctnetlink_dump_helpinfo(skb, ct) < 0)
goto nfattr_failure;
+#ifdef CONFIG_IP_NF_CONNTRACK_MARK
if ((events & IPCT_MARK || ct->mark)
&& ctnetlink_dump_mark(skb, ct) < 0)
goto nfattr_failure;
+#endif
if (events & IPCT_COUNTER_FILLING &&
(ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
@@ -959,7 +961,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
if (cda[CTA_PROTOINFO-1]) {
err = ctnetlink_change_protoinfo(ct, cda);
if (err < 0)
- return err;
+ goto err;
}
#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index 06e4e8a6dd9..c34f48fe547 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -50,12 +50,9 @@ static DEFINE_RWLOCK(tcp_lock);
If it's non-zero, we mark only out of window RST segments as INVALID. */
int ip_ct_tcp_be_liberal __read_mostly = 0;
-/* When connection is picked up from the middle, how many packets are required
- to pass in each direction when we assume we are in sync - if any side uses
- window scaling, we lost the game.
- If it is set to zero, we disable picking up already established
+/* If it is set to zero, we disable picking up already established
connections. */
-int ip_ct_tcp_loose __read_mostly = 3;
+int ip_ct_tcp_loose __read_mostly = 1;
/* Max number of the retransmitted packets without receiving an (acceptable)
ACK from the destination. If this number is reached, a shorter timer
@@ -694,11 +691,10 @@ static int tcp_in_window(struct ip_ct_tcp *state,
before(sack, receiver->td_end + 1),
after(ack, receiver->td_end - MAXACKWINDOW(sender)));
- if (sender->loose || receiver->loose ||
- (before(seq, sender->td_maxend + 1) &&
- after(end, sender->td_end - receiver->td_maxwin - 1) &&
- before(sack, receiver->td_end + 1) &&
- after(ack, receiver->td_end - MAXACKWINDOW(sender)))) {
+ if (before(seq, sender->td_maxend + 1) &&
+ after(end, sender->td_end - receiver->td_maxwin - 1) &&
+ before(sack, receiver->td_end + 1) &&
+ after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
/*
* Take into account window scaling (RFC 1323).
*/
@@ -743,15 +739,13 @@ static int tcp_in_window(struct ip_ct_tcp *state,
state->retrans = 0;
}
}
- /*
- * Close the window of disabled window tracking :-)
- */
- if (sender->loose)
- sender->loose--;
-
res = 1;
} else {
- if (LOG_INVALID(IPPROTO_TCP))
+ res = 0;
+ if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
+ ip_ct_tcp_be_liberal)
+ res = 1;
+ if (!res && LOG_INVALID(IPPROTO_TCP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
"ip_ct_tcp: %s ",
before(seq, sender->td_maxend + 1) ?
@@ -762,8 +756,6 @@ static int tcp_in_window(struct ip_ct_tcp *state,
: "ACK is over the upper bound (ACKed data not seen yet)"
: "SEQ is under the lower bound (already ACKed data retransmitted)"
: "SEQ is over the upper bound (over the window of the receiver)");
-
- res = ip_ct_tcp_be_liberal;
}
DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
@@ -1105,8 +1097,6 @@ static int tcp_new(struct ip_conntrack *conntrack,
tcp_options(skb, iph, th, &conntrack->proto.tcp.seen[0]);
conntrack->proto.tcp.seen[1].flags = 0;
- conntrack->proto.tcp.seen[0].loose =
- conntrack->proto.tcp.seen[1].loose = 0;
} else if (ip_ct_tcp_loose == 0) {
/* Don't try to pick up connections. */
return 0;
@@ -1127,11 +1117,11 @@ static int tcp_new(struct ip_conntrack *conntrack,
conntrack->proto.tcp.seen[0].td_maxwin;
conntrack->proto.tcp.seen[0].td_scale = 0;
- /* We assume SACK. Should we assume window scaling too? */
+ /* We assume SACK and liberal window checking to handle
+ * window scaling */
conntrack->proto.tcp.seen[0].flags =
- conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM;
- conntrack->proto.tcp.seen[0].loose =
- conntrack->proto.tcp.seen[1].loose = ip_ct_tcp_loose;
+ conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
+ IP_CT_TCP_FLAG_BE_LIBERAL;
}
conntrack->proto.tcp.seen[1].td_end = 0;
diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c
index 3a26d63eed8..11c588a10e6 100644
--- a/net/ipv4/netfilter/ip_conntrack_sip.c
+++ b/net/ipv4/netfilter/ip_conntrack_sip.c
@@ -283,10 +283,16 @@ static int skp_epaddr_len(const char *dptr, const char *limit, int *shift)
{
int s = *shift;
- for (; dptr <= limit && *dptr != '@'; dptr++)
+ /* Search for @, but stop at the end of the line.
+ * We are inside a sip: URI, so we don't need to worry about
+ * continuation lines. */
+ while (dptr <= limit &&
+ *dptr != '@' && *dptr != '\r' && *dptr != '\n') {
(*shift)++;
+ dptr++;
+ }
- if (*dptr == '@') {
+ if (dptr <= limit && *dptr == '@') {
dptr++;
(*shift)++;
} else
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
index 9d1a5175dcd..5e08c2bf887 100644
--- a/net/ipv4/netfilter/ip_nat_core.c
+++ b/net/ipv4/netfilter/ip_nat_core.c
@@ -246,8 +246,9 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple,
if (maniptype == IP_NAT_MANIP_SRC) {
if (find_appropriate_src(orig_tuple, tuple, range)) {
DEBUGP("get_unique_tuple: Found current src map\n");
- if (!ip_nat_used_tuple(tuple, conntrack))
- return;
+ if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
+ if (!ip_nat_used_tuple(tuple, conntrack))
+ return;
}
}
@@ -261,6 +262,13 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple,
proto = ip_nat_proto_find_get(orig_tuple->dst.protonum);
+ /* Change protocol info to have some randomization */
+ if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
+ proto->unique_tuple(tuple, range, maniptype, conntrack);
+ ip_nat_proto_put(proto);
+ return;
+ }
+
/* Only bother mapping if it's not already in range and unique */
if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
|| proto->in_range(tuple, maniptype, &range->min, &range->max))
diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c
index ee80feb4b2a..2e5c4bc52a6 100644
--- a/net/ipv4/netfilter/ip_nat_helper.c
+++ b/net/ipv4/netfilter/ip_nat_helper.c
@@ -183,7 +183,7 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
datalen = (*pskb)->len - iph->ihl*4;
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
tcph->check = 0;
- tcph->check = tcp_v4_check(tcph, datalen,
+ tcph->check = tcp_v4_check(datalen,
iph->saddr, iph->daddr,
csum_partial((char *)tcph,
datalen, 0));
diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c
index b586d18b3fb..14ff24f53a7 100644
--- a/net/ipv4/netfilter/ip_nat_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/random.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
#include <linux/tcp.h>
@@ -75,6 +76,10 @@ tcp_unique_tuple(struct ip_conntrack_tuple *tuple,
range_size = ntohs(range->max.tcp.port) - min + 1;
}
+ /* Start from random port to avoid prediction */
+ if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
+ port = net_random();
+
for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size);
if (!ip_nat_used_tuple(tuple, conntrack)) {
diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c
index 5ced0877b32..dfd52167289 100644
--- a/net/ipv4/netfilter/ip_nat_proto_udp.c
+++ b/net/ipv4/netfilter/ip_nat_proto_udp.c
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/random.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
#include <linux/udp.h>
@@ -74,6 +75,10 @@ udp_unique_tuple(struct ip_conntrack_tuple *tuple,
range_size = ntohs(range->max.udp.port) - min + 1;
}
+ /* Start from random port to avoid prediction */
+ if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
+ port = net_random();
+
for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size);
if (!ip_nat_used_tuple(tuple, conntrack))
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
index a176aa3031e..e1c8a05f3dc 100644
--- a/net/ipv4/netfilter/ip_nat_rule.c
+++ b/net/ipv4/netfilter/ip_nat_rule.c
@@ -86,7 +86,7 @@ static struct
}
};
-static struct ipt_table nat_table = {
+static struct xt_table nat_table = {
.name = "nat",
.valid_hooks = NAT_VALID_HOOKS,
.lock = RW_LOCK_UNLOCKED,
@@ -99,7 +99,7 @@ static unsigned int ipt_snat_target(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
- const struct ipt_target *target,
+ const struct xt_target *target,
const void *targinfo)
{
struct ip_conntrack *ct;
@@ -141,7 +141,7 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
- const struct ipt_target *target,
+ const struct xt_target *target,
const void *targinfo)
{
struct ip_conntrack *ct;
@@ -166,7 +166,7 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb,
static int ipt_snat_checkentry(const char *tablename,
const void *entry,
- const struct ipt_target *target,
+ const struct xt_target *target,
void *targinfo,
unsigned int hook_mask)
{
@@ -182,7 +182,7 @@ static int ipt_snat_checkentry(const char *tablename,
static int ipt_dnat_checkentry(const char *tablename,
const void *entry,
- const struct ipt_target *target,
+ const struct xt_target *target,
void *targinfo,
unsigned int hook_mask)
{
@@ -193,6 +193,10 @@ static int ipt_dnat_checkentry(const char *tablename,
printk("DNAT: multiple ranges no longer supported\n");
return 0;
}
+ if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
+ printk("DNAT: port randomization not supported\n");
+ return 0;
+ }
return 1;
}
@@ -257,8 +261,9 @@ int ip_nat_rule_find(struct sk_buff **pskb,
return ret;
}
-static struct ipt_target ipt_snat_reg = {
+static struct xt_target ipt_snat_reg = {
.name = "SNAT",
+ .family = AF_INET,
.target = ipt_snat_target,
.targetsize = sizeof(struct ip_nat_multi_range_compat),
.table = "nat",
@@ -266,8 +271,9 @@ static struct ipt_target ipt_snat_reg = {
.checkentry = ipt_snat_checkentry,
};
-static struct ipt_target ipt_dnat_reg = {
+static struct xt_target ipt_dnat_reg = {
.name = "DNAT",
+ .family = AF_INET,
.target = ipt_dnat_target,
.targetsize = sizeof(struct ip_nat_multi_range_compat),
.table = "nat",
@@ -282,27 +288,27 @@ int __init ip_nat_rule_init(void)
ret = ipt_register_table(&nat_table, &nat_initial_table.repl);
if (ret != 0)
return ret;
- ret = ipt_register_target(&ipt_snat_reg);
+ ret = xt_register_target(&ipt_snat_reg);
if (ret != 0)
goto unregister_table;
- ret = ipt_register_target(&ipt_dnat_reg);
+ ret = xt_register_target(&ipt_dnat_reg);
if (ret != 0)
goto unregister_snat;
return ret;
unregister_snat:
- ipt_unregister_target(&ipt_snat_reg);
+ xt_unregister_target(&ipt_snat_reg);
unregister_table:
- ipt_unregister_table(&nat_table);
+ xt_unregister_table(&nat_table);
return ret;
}
void ip_nat_rule_cleanup(void)
{
- ipt_unregister_target(&ipt_dnat_reg);
- ipt_unregister_target(&ipt_snat_reg);
+ xt_unregister_target(&ipt_dnat_reg);
+ xt_unregister_target(&ipt_snat_reg);
ipt_unregister_table(&nat_table);
}
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 0ff2956d35e..5a7b3a34138 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -216,7 +216,7 @@ ipt_do_table(struct sk_buff **pskb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
- struct ipt_table *table)
+ struct xt_table *table)
{
static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
u_int16_t offset;
@@ -384,6 +384,7 @@ mark_source_chains(struct xt_table_info *newinfo,
for (;;) {
struct ipt_standard_target *t
= (void *)ipt_get_target(e);
+ int visited = e->comefrom & (1 << hook);
if (e->comefrom & (1 << NF_IP_NUMHOOKS)) {
printk("iptables: loop hook %u pos %u %08X.\n",
@@ -394,11 +395,11 @@ mark_source_chains(struct xt_table_info *newinfo,
|= ((1 << hook) | (1 << NF_IP_NUMHOOKS));
/* Unconditional return/END. */
- if (e->target_offset == sizeof(struct ipt_entry)
+ if ((e->target_offset == sizeof(struct ipt_entry)
&& (strcmp(t->target.u.user.name,
IPT_STANDARD_TARGET) == 0)
&& t->verdict < 0
- && unconditional(&e->ip)) {
+ && unconditional(&e->ip)) || visited) {
unsigned int oldpos, size;
if (t->verdict < -NF_MAX_VERDICT - 1) {
@@ -484,39 +485,68 @@ cleanup_match(struct ipt_entry_match *m, unsigned int *i)
}
static inline int
-check_match(struct ipt_entry_match *m,
+check_entry(struct ipt_entry *e, const char *name)
+{
+ struct ipt_entry_target *t;
+
+ if (!ip_checkentry(&e->ip)) {
+ duprintf("ip_tables: ip check failed %p %s.\n", e, name);
+ return -EINVAL;
+ }
+
+ if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset)
+ return -EINVAL;
+
+ t = ipt_get_target(e);
+ if (e->target_offset + t->u.target_size > e->next_offset)
+ return -EINVAL;
+
+ return 0;
+}
+
+static inline int check_match(struct ipt_entry_match *m, const char *name,
+ const struct ipt_ip *ip, unsigned int hookmask)
+{
+ struct xt_match *match;
+ int ret;
+
+ match = m->u.kernel.match;
+ ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
+ name, hookmask, ip->proto,
+ ip->invflags & IPT_INV_PROTO);
+ if (!ret && m->u.kernel.match->checkentry
+ && !m->u.kernel.match->checkentry(name, ip, match, m->data,
+ hookmask)) {
+ duprintf("ip_tables: check failed for `%s'.\n",
+ m->u.kernel.match->name);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static inline int
+find_check_match(struct ipt_entry_match *m,
const char *name,
const struct ipt_ip *ip,
unsigned int hookmask,
unsigned int *i)
{
- struct ipt_match *match;
+ struct xt_match *match;
int ret;
match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
m->u.user.revision),
"ipt_%s", m->u.user.name);
if (IS_ERR(match) || !match) {
- duprintf("check_match: `%s' not found\n", m->u.user.name);
+ duprintf("find_check_match: `%s' not found\n", m->u.user.name);
return match ? PTR_ERR(match) : -ENOENT;
}
m->u.kernel.match = match;
- ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
- name, hookmask, ip->proto,
- ip->invflags & IPT_INV_PROTO);
+ ret = check_match(m, name, ip, hookmask);
if (ret)
goto err;
- if (m->u.kernel.match->checkentry
- && !m->u.kernel.match->checkentry(name, ip, match, m->data,
- hookmask)) {
- duprintf("ip_tables: check failed for `%s'.\n",
- m->u.kernel.match->name);
- ret = -EINVAL;
- goto err;
- }
-
(*i)++;
return 0;
err:
@@ -524,60 +554,62 @@ err:
return ret;
}
-static struct ipt_target ipt_standard_target;
+static inline int check_target(struct ipt_entry *e, const char *name)
+{
+ struct ipt_entry_target *t;
+ struct xt_target *target;
+ int ret;
+
+ t = ipt_get_target(e);
+ target = t->u.kernel.target;
+ ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
+ name, e->comefrom, e->ip.proto,
+ e->ip.invflags & IPT_INV_PROTO);
+ if (!ret && t->u.kernel.target->checkentry
+ && !t->u.kernel.target->checkentry(name, e, target,
+ t->data, e->comefrom)) {
+ duprintf("ip_tables: check failed for `%s'.\n",
+ t->u.kernel.target->name);
+ ret = -EINVAL;
+ }
+ return ret;
+}
static inline int
-check_entry(struct ipt_entry *e, const char *name, unsigned int size,
+find_check_entry(struct ipt_entry *e, const char *name, unsigned int size,
unsigned int *i)
{
struct ipt_entry_target *t;
- struct ipt_target *target;
+ struct xt_target *target;
int ret;
unsigned int j;
- if (!ip_checkentry(&e->ip)) {
- duprintf("ip_tables: ip check failed %p %s.\n", e, name);
- return -EINVAL;
- }
-
- if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset)
- return -EINVAL;
+ ret = check_entry(e, name);
+ if (ret)
+ return ret;
j = 0;
- ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
+ ret = IPT_MATCH_ITERATE(e, find_check_match, name, &e->ip,
+ e->comefrom, &j);
if (ret != 0)
goto cleanup_matches;
t = ipt_get_target(e);
- ret = -EINVAL;
- if (e->target_offset + t->u.target_size > e->next_offset)
- goto cleanup_matches;
target = try_then_request_module(xt_find_target(AF_INET,
t->u.user.name,
t->u.user.revision),
"ipt_%s", t->u.user.name);
if (IS_ERR(target) || !target) {
- duprintf("check_entry: `%s' not found\n", t->u.user.name);
+ duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
ret = target ? PTR_ERR(target) : -ENOENT;
goto cleanup_matches;
}
t->u.kernel.target = target;
- ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
- name, e->comefrom, e->ip.proto,
- e->ip.invflags & IPT_INV_PROTO);
+ ret = check_target(e, name);
if (ret)
goto err;
- if (t->u.kernel.target->checkentry
- && !t->u.kernel.target->checkentry(name, e, target, t->data,
- e->comefrom)) {
- duprintf("ip_tables: check failed for `%s'.\n",
- t->u.kernel.target->name);
- ret = -EINVAL;
- goto err;
- }
-
(*i)++;
return 0;
err:
@@ -712,7 +744,7 @@ translate_table(const char *name,
/* Finally, each sanity check must pass */
i = 0;
ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
- check_entry, name, size, &i);
+ find_check_entry, name, size, &i);
if (ret != 0) {
IPT_ENTRY_ITERATE(entry0, newinfo->size,
@@ -786,7 +818,7 @@ get_counters(const struct xt_table_info *t,
}
}
-static inline struct xt_counters * alloc_counters(struct ipt_table *table)
+static inline struct xt_counters * alloc_counters(struct xt_table *table)
{
unsigned int countersize;
struct xt_counters *counters;
@@ -811,7 +843,7 @@ static inline struct xt_counters * alloc_counters(struct ipt_table *table)
static int
copy_entries_to_user(unsigned int total_size,
- struct ipt_table *table,
+ struct xt_table *table,
void __user *userptr)
{
unsigned int off, num;
@@ -887,13 +919,13 @@ copy_entries_to_user(unsigned int total_size,
#ifdef CONFIG_COMPAT
struct compat_delta {
struct compat_delta *next;
- u_int16_t offset;
+ unsigned int offset;
short delta;
};
static struct compat_delta *compat_offsets = NULL;
-static int compat_add_offset(u_int16_t offset, short delta)
+static int compat_add_offset(unsigned int offset, short delta)
{
struct compat_delta *tmp;
@@ -925,7 +957,7 @@ static void compat_flush_offsets(void)
}
}
-static short compat_calc_jump(u_int16_t offset)
+static short compat_calc_jump(unsigned int offset)
{
struct compat_delta *tmp;
short delta;
@@ -965,7 +997,7 @@ static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
void *base, struct xt_table_info *newinfo)
{
struct ipt_entry_target *t;
- u_int16_t entry_offset;
+ unsigned int entry_offset;
int off, i, ret;
off = 0;
@@ -1014,7 +1046,7 @@ static int compat_table_info(struct xt_table_info *info,
static int get_info(void __user *user, int *len, int compat)
{
char name[IPT_TABLE_MAXNAMELEN];
- struct ipt_table *t;
+ struct xt_table *t;
int ret;
if (*len != sizeof(struct ipt_getinfo)) {
@@ -1075,7 +1107,7 @@ get_entries(struct ipt_get_entries __user *uptr, int *len)
{
int ret;
struct ipt_get_entries get;
- struct ipt_table *t;
+ struct xt_table *t;
if (*len < sizeof(get)) {
duprintf("get_entries: %u < %d\n", *len,
@@ -1119,7 +1151,7 @@ __do_replace(const char *name, unsigned int valid_hooks,
void __user *counters_ptr)
{
int ret;
- struct ipt_table *t;
+ struct xt_table *t;
struct xt_table_info *oldinfo;
struct xt_counters *counters;
void *loc_cpu_old_entry;
@@ -1270,7 +1302,7 @@ do_add_counters(void __user *user, unsigned int len, int compat)
char *name;
int size;
void *ptmp;
- struct ipt_table *t;
+ struct xt_table *t;
struct xt_table_info *private;
int ret = 0;
void *loc_cpu_entry;
@@ -1405,7 +1437,7 @@ compat_check_calc_match(struct ipt_entry_match *m,
unsigned int hookmask,
int *size, int *i)
{
- struct ipt_match *match;
+ struct xt_match *match;
match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
m->u.user.revision),
@@ -1434,8 +1466,8 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
const char *name)
{
struct ipt_entry_target *t;
- struct ipt_target *target;
- u_int16_t entry_offset;
+ struct xt_target *target;
+ unsigned int entry_offset;
int ret, off, h, j;
duprintf("check_compat_entry_size_and_hooks %p\n", e);
@@ -1452,14 +1484,9 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
return -EINVAL;
}
- if (!ip_checkentry(&e->ip)) {
- duprintf("ip_tables: ip check failed %p %s.\n", e, name);
- return -EINVAL;
- }
-
- if (e->target_offset + sizeof(struct compat_xt_entry_target) >
- e->next_offset)
- return -EINVAL;
+ ret = check_entry(e, name);
+ if (ret)
+ return ret;
off = 0;
entry_offset = (void *)e - (void *)base;
@@ -1470,15 +1497,13 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
goto cleanup_matches;
t = ipt_get_target(e);
- ret = -EINVAL;
- if (e->target_offset + t->u.target_size > e->next_offset)
- goto cleanup_matches;
target = try_then_request_module(xt_find_target(AF_INET,
t->u.user.name,
t->u.user.revision),
"ipt_%s", t->u.user.name);
if (IS_ERR(target) || !target) {
- duprintf("check_entry: `%s' not found\n", t->u.user.name);
+ duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
+ t->u.user.name);
ret = target ? PTR_ERR(target) : -ENOENT;
goto cleanup_matches;
}
@@ -1525,7 +1550,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
struct xt_table_info *newinfo, unsigned char *base)
{
struct ipt_entry_target *t;
- struct ipt_target *target;
+ struct xt_target *target;
struct ipt_entry *de;
unsigned int origsize;
int ret, h;
@@ -1555,57 +1580,15 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
return ret;
}
-static inline int compat_check_match(struct ipt_entry_match *m, const char *name,
- const struct ipt_ip *ip, unsigned int hookmask)
-{
- struct ipt_match *match;
- int ret;
-
- match = m->u.kernel.match;
- ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
- name, hookmask, ip->proto,
- ip->invflags & IPT_INV_PROTO);
- if (!ret && m->u.kernel.match->checkentry
- && !m->u.kernel.match->checkentry(name, ip, match, m->data,
- hookmask)) {
- duprintf("ip_tables: compat: check failed for `%s'.\n",
- m->u.kernel.match->name);
- ret = -EINVAL;
- }
- return ret;
-}
-
-static inline int compat_check_target(struct ipt_entry *e, const char *name)
-{
- struct ipt_entry_target *t;
- struct ipt_target *target;
- int ret;
-
- t = ipt_get_target(e);
- target = t->u.kernel.target;
- ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
- name, e->comefrom, e->ip.proto,
- e->ip.invflags & IPT_INV_PROTO);
- if (!ret && t->u.kernel.target->checkentry
- && !t->u.kernel.target->checkentry(name, e, target,
- t->data, e->comefrom)) {
- duprintf("ip_tables: compat: check failed for `%s'.\n",
- t->u.kernel.target->name);
- ret = -EINVAL;
- }
- return ret;
-}
-
static inline int compat_check_entry(struct ipt_entry *e, const char *name)
{
int ret;
- ret = IPT_MATCH_ITERATE(e, compat_check_match, name, &e->ip,
- e->comefrom);
+ ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom);
if (ret)
return ret;
- return compat_check_target(e, name);
+ return check_target(e, name);
}
static int
@@ -1812,7 +1795,7 @@ struct compat_ipt_get_entries
};
static int compat_copy_entries_to_user(unsigned int total_size,
- struct ipt_table *table, void __user *userptr)
+ struct xt_table *table, void __user *userptr)
{
unsigned int off, num;
struct compat_ipt_entry e;
@@ -1886,7 +1869,7 @@ compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
{
int ret;
struct compat_ipt_get_entries get;
- struct ipt_table *t;
+ struct xt_table *t;
if (*len < sizeof(get)) {
@@ -2069,7 +2052,7 @@ int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
return 0;
}
-void ipt_unregister_table(struct ipt_table *table)
+void ipt_unregister_table(struct xt_table *table)
{
struct xt_table_info *private;
void *loc_cpu_entry;
@@ -2141,7 +2124,7 @@ icmp_checkentry(const char *tablename,
}
/* The built-in targets: standard (NULL) and error. */
-static struct ipt_target ipt_standard_target = {
+static struct xt_target ipt_standard_target = {
.name = IPT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = AF_INET,
@@ -2152,7 +2135,7 @@ static struct ipt_target ipt_standard_target = {
#endif
};
-static struct ipt_target ipt_error_target = {
+static struct xt_target ipt_error_target = {
.name = IPT_ERROR_TARGET,
.target = ipt_error,
.targetsize = IPT_FUNCTION_MAXNAMELEN,
@@ -2175,7 +2158,7 @@ static struct nf_sockopt_ops ipt_sockopts = {
#endif
};
-static struct ipt_match icmp_matchstruct = {
+static struct xt_match icmp_matchstruct = {
.name = "icmp",
.match = icmp_match,
.matchsize = sizeof(struct ipt_icmp),
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 09836506223..343c2abdc1a 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -26,6 +26,7 @@
#include <linux/netfilter_arp.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
#include <net/netfilter/nf_conntrack_compat.h>
@@ -247,6 +248,7 @@ clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config)
switch (iph->protocol) {
case IPPROTO_TCP:
case IPPROTO_UDP:
+ case IPPROTO_UDPLITE:
case IPPROTO_SCTP:
case IPPROTO_DCCP:
case IPPROTO_ICMP:
@@ -329,7 +331,7 @@ target(struct sk_buff **pskb,
if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
&& (ctinfo == IP_CT_RELATED
|| ctinfo == IP_CT_RELATED+IP_CT_IS_REPLY))
- return IPT_CONTINUE;
+ return XT_CONTINUE;
/* ip_conntrack_icmp guarantees us that we only have ICMP_ECHO,
* TIMESTAMP, INFO_REQUEST or ADDRESS type icmp packets from here
@@ -367,7 +369,7 @@ target(struct sk_buff **pskb,
* actually a unicast IP packet. TCP doesn't like PACKET_MULTICAST */
(*pskb)->pkt_type = PACKET_HOST;
- return IPT_CONTINUE;
+ return XT_CONTINUE;
}
static int
@@ -447,6 +449,12 @@ checkentry(const char *tablename,
cipinfo->config = config;
}
+ if (nf_ct_l3proto_try_module_get(target->family) < 0) {
+ printk(KERN_WARNING "can't load conntrack support for "
+ "proto=%d\n", target->family);
+ return 0;
+ }
+
return 1;
}
@@ -460,10 +468,13 @@ static void destroy(const struct xt_target *target, void *targinfo)
clusterip_config_entry_put(cipinfo->config);
clusterip_config_put(cipinfo->config);
+
+ nf_ct_l3proto_module_put(target->family);
}
-static struct ipt_target clusterip_tgt = {
+static struct xt_target clusterip_tgt = {
.name = "CLUSTERIP",
+ .family = AF_INET,
.target = target,
.targetsize = sizeof(struct ipt_clusterip_tgt_info),
.checkentry = checkentry,
@@ -683,7 +694,7 @@ static ssize_t clusterip_proc_write(struct file *file, const char __user *input,
{
#define PROC_WRITELEN 10
char buffer[PROC_WRITELEN+1];
- struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
struct clusterip_config *c = pde->data;
unsigned long nodenum;
@@ -719,7 +730,7 @@ static int __init ipt_clusterip_init(void)
{
int ret;
- ret = ipt_register_target(&clusterip_tgt);
+ ret = xt_register_target(&clusterip_tgt);
if (ret < 0)
return ret;
@@ -745,7 +756,7 @@ cleanup_hook:
nf_unregister_hook(&cip_arp_ops);
#endif /* CONFIG_PROC_FS */
cleanup_target:
- ipt_unregister_target(&clusterip_tgt);
+ xt_unregister_target(&clusterip_tgt);
return ret;
}
@@ -757,7 +768,7 @@ static void __exit ipt_clusterip_fini(void)
remove_proc_entry(clusterip_procdir->name, clusterip_procdir->parent);
#endif
nf_unregister_hook(&cip_arp_ops);
- ipt_unregister_target(&clusterip_tgt);
+ xt_unregister_target(&clusterip_tgt);
}
module_init(ipt_clusterip_init);
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index b55d670a24d..b5ca5938d1f 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -9,12 +9,14 @@
* ipt_ECN.c,v 1.5 2002/08/18 19:36:51 laforge Exp
*/
+#include <linux/in.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <net/checksum.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_ECN.h>
@@ -95,7 +97,7 @@ target(struct sk_buff **pskb,
if (!set_ect_tcp(pskb, einfo))
return NF_DROP;
- return IPT_CONTINUE;
+ return XT_CONTINUE;
}
static int
@@ -119,7 +121,7 @@ checkentry(const char *tablename,
return 0;
}
if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
- && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO))) {
+ && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) {
printk(KERN_WARNING "ECN: cannot use TCP operations on a "
"non-tcp rule\n");
return 0;
@@ -127,8 +129,9 @@ checkentry(const char *tablename,
return 1;
}
-static struct ipt_target ipt_ecn_reg = {
+static struct xt_target ipt_ecn_reg = {
.name = "ECN",
+ .family = AF_INET,
.target = target,
.targetsize = sizeof(struct ipt_ECN_info),
.table = "mangle",
@@ -138,12 +141,12 @@ static struct ipt_target ipt_ecn_reg = {
static int __init ipt_ecn_init(void)
{
- return ipt_register_target(&ipt_ecn_reg);
+ return xt_register_target(&ipt_ecn_reg);
}
static void __exit ipt_ecn_fini(void)
{
- ipt_unregister_target(&ipt_ecn_reg);
+ xt_unregister_target(&ipt_ecn_reg);
}
module_init(ipt_ecn_init);
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index c96de16fefa..f68370ffb43 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -20,7 +20,7 @@
#include <net/route.h>
#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_LOG.h>
MODULE_LICENSE("GPL");
@@ -432,7 +432,7 @@ ipt_log_target(struct sk_buff **pskb,
ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li,
loginfo->prefix);
- return IPT_CONTINUE;
+ return XT_CONTINUE;
}
static int ipt_log_checkentry(const char *tablename,
@@ -455,8 +455,9 @@ static int ipt_log_checkentry(const char *tablename,
return 1;
}
-static struct ipt_target ipt_log_reg = {
+static struct xt_target ipt_log_reg = {
.name = "LOG",
+ .family = AF_INET,
.target = ipt_log_target,
.targetsize = sizeof(struct ipt_log_info),
.checkentry = ipt_log_checkentry,
@@ -471,8 +472,11 @@ static struct nf_logger ipt_log_logger ={
static int __init ipt_log_init(void)
{
- if (ipt_register_target(&ipt_log_reg))
- return -EINVAL;
+ int ret;
+
+ ret = xt_register_target(&ipt_log_reg);
+ if (ret < 0)
+ return ret;
if (nf_log_register(PF_INET, &ipt_log_logger) < 0) {
printk(KERN_WARNING "ipt_LOG: not logging via system console "
"since somebody else already registered for PF_INET\n");
@@ -486,7 +490,7 @@ static int __init ipt_log_init(void)
static void __exit ipt_log_fini(void)
{
nf_log_unregister_logger(&ipt_log_logger);
- ipt_unregister_target(&ipt_log_reg);
+ xt_unregister_target(&ipt_log_reg);
}
module_init(ipt_log_init);
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index 28b9233956b..91c42efcd53 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -25,7 +25,7 @@
#else
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#endif
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -127,10 +127,13 @@ masquerade_target(struct sk_buff **pskb,
static inline int
device_cmp(struct ip_conntrack *i, void *ifindex)
{
+ int ret;
#ifdef CONFIG_NF_NAT_NEEDED
struct nf_conn_nat *nat = nfct_nat(i);
+
+ if (!nat)
+ return 0;
#endif
- int ret;
read_lock_bh(&masq_lock);
#ifdef CONFIG_NF_NAT_NEEDED
@@ -187,8 +190,9 @@ static struct notifier_block masq_inet_notifier = {
.notifier_call = masq_inet_event,
};
-static struct ipt_target masquerade = {
+static struct xt_target masquerade = {
.name = "MASQUERADE",
+ .family = AF_INET,
.target = masquerade_target,
.targetsize = sizeof(struct ip_nat_multi_range_compat),
.table = "nat",
@@ -201,7 +205,7 @@ static int __init ipt_masquerade_init(void)
{
int ret;
- ret = ipt_register_target(&masquerade);
+ ret = xt_register_target(&masquerade);
if (ret == 0) {
/* Register for device down reports */
@@ -215,7 +219,7 @@ static int __init ipt_masquerade_init(void)
static void __exit ipt_masquerade_fini(void)
{
- ipt_unregister_target(&masquerade);
+ xt_unregister_target(&masquerade);
unregister_netdevice_notifier(&masq_dev_notifier);
unregister_inetaddr_notifier(&masq_inet_notifier);
}
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index 9390e90f2b2..b4acc241d89 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -15,6 +15,7 @@
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/x_tables.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat_rule.h>
#else
@@ -88,8 +89,9 @@ target(struct sk_buff **pskb,
return ip_nat_setup_info(ct, &newrange, hooknum);
}
-static struct ipt_target target_module = {
+static struct xt_target target_module = {
.name = MODULENAME,
+ .family = AF_INET,
.target = target,
.targetsize = sizeof(struct ip_nat_multi_range_compat),
.table = "nat",
@@ -101,12 +103,12 @@ static struct ipt_target target_module = {
static int __init ipt_netmap_init(void)
{
- return ipt_register_target(&target_module);
+ return xt_register_target(&target_module);
}
static void __exit ipt_netmap_fini(void)
{
- ipt_unregister_target(&target_module);
+ xt_unregister_target(&target_module);
}
module_init(ipt_netmap_init);
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index 462eceb3a1b..54cd021aa5a 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -18,6 +18,7 @@
#include <net/protocol.h>
#include <net/checksum.h>
#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/x_tables.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat_rule.h>
#else
@@ -104,8 +105,9 @@ redirect_target(struct sk_buff **pskb,
return ip_nat_setup_info(ct, &newrange, hooknum);
}
-static struct ipt_target redirect_reg = {
+static struct xt_target redirect_reg = {
.name = "REDIRECT",
+ .family = AF_INET,
.target = redirect_target,
.targetsize = sizeof(struct ip_nat_multi_range_compat),
.table = "nat",
@@ -116,12 +118,12 @@ static struct ipt_target redirect_reg = {
static int __init ipt_redirect_init(void)
{
- return ipt_register_target(&redirect_reg);
+ return xt_register_target(&redirect_reg);
}
static void __exit ipt_redirect_fini(void)
{
- ipt_unregister_target(&redirect_reg);
+ xt_unregister_target(&redirect_reg);
}
module_init(ipt_redirect_init);
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index f0319e5ee43..e4a1ddb386a 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -22,6 +22,7 @@
#include <net/tcp.h>
#include <net/route.h>
#include <net/dst.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_REJECT.h>
#ifdef CONFIG_BRIDGE_NETFILTER
@@ -116,7 +117,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
/* Adjust TCP checksum */
tcph->check = 0;
- tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
+ tcph->check = tcp_v4_check(sizeof(struct tcphdr),
nskb->nh.iph->saddr,
nskb->nh.iph->daddr,
csum_partial((char *)tcph,
@@ -230,7 +231,7 @@ static int check(const char *tablename,
} else if (rejinfo->with == IPT_TCP_RESET) {
/* Must specify that it's a TCP packet */
if (e->ip.proto != IPPROTO_TCP
- || (e->ip.invflags & IPT_INV_PROTO)) {
+ || (e->ip.invflags & XT_INV_PROTO)) {
DEBUGP("REJECT: TCP_RESET invalid for non-tcp\n");
return 0;
}
@@ -238,8 +239,9 @@ static int check(const char *tablename,
return 1;
}
-static struct ipt_target ipt_reject_reg = {
+static struct xt_target ipt_reject_reg = {
.name = "REJECT",
+ .family = AF_INET,
.target = reject,
.targetsize = sizeof(struct ipt_reject_info),
.table = "filter",
@@ -251,12 +253,12 @@ static struct ipt_target ipt_reject_reg = {
static int __init ipt_reject_init(void)
{
- return ipt_register_target(&ipt_reject_reg);
+ return xt_register_target(&ipt_reject_reg);
}
static void __exit ipt_reject_fini(void)
{
- ipt_unregister_target(&ipt_reject_reg);
+ xt_unregister_target(&ipt_reject_reg);
}
module_init(ipt_reject_init);
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c
index 3dcf2941133..a1cdd1262de 100644
--- a/net/ipv4/netfilter/ipt_SAME.c
+++ b/net/ipv4/netfilter/ipt_SAME.c
@@ -34,6 +34,7 @@
#include <net/protocol.h>
#include <net/checksum.h>
#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/x_tables.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat_rule.h>
#else
@@ -186,8 +187,9 @@ same_target(struct sk_buff **pskb,
return ip_nat_setup_info(ct, &newrange, hooknum);
}
-static struct ipt_target same_reg = {
+static struct xt_target same_reg = {
.name = "SAME",
+ .family = AF_INET,
.target = same_target,
.targetsize = sizeof(struct ipt_same_info),
.table = "nat",
@@ -199,12 +201,12 @@ static struct ipt_target same_reg = {
static int __init ipt_same_init(void)
{
- return ipt_register_target(&same_reg);
+ return xt_register_target(&same_reg);
}
static void __exit ipt_same_fini(void)
{
- ipt_unregister_target(&same_reg);
+ xt_unregister_target(&same_reg);
}
module_init(ipt_same_init);
diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c
deleted file mode 100644
index 93eb5c3c188..00000000000
--- a/net/ipv4/netfilter/ipt_TCPMSS.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * This is a module which is used for setting the MSS option in TCP packets.
- *
- * Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
- *
- * 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/skbuff.h>
-
-#include <linux/ip.h>
-#include <net/tcp.h>
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_TCPMSS.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_DESCRIPTION("iptables TCP MSS modification module");
-
-static inline unsigned int
-optlen(const u_int8_t *opt, unsigned int offset)
-{
- /* Beware zero-length options: make finite progress */
- if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
- return 1;
- else
- return opt[offset+1];
-}
-
-static unsigned int
-ipt_tcpmss_target(struct sk_buff **pskb,
- const struct net_device *in,
- const struct net_device *out,
- unsigned int hooknum,
- const struct xt_target *target,
- const void *targinfo)
-{
- const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
- struct tcphdr *tcph;
- struct iphdr *iph;
- u_int16_t tcplen, newmss;
- __be16 newtotlen, oldval;
- unsigned int i;
- u_int8_t *opt;
-
- if (!skb_make_writable(pskb, (*pskb)->len))
- return NF_DROP;
-
- iph = (*pskb)->nh.iph;
- tcplen = (*pskb)->len - iph->ihl*4;
- tcph = (void *)iph + iph->ihl*4;
-
- /* Since it passed flags test in tcp match, we know it is is
- not a fragment, and has data >= tcp header length. SYN
- packets should not contain data: if they did, then we risk
- running over MTU, sending Frag Needed and breaking things
- badly. --RR */
- if (tcplen != tcph->doff*4) {
- if (net_ratelimit())
- printk(KERN_ERR
- "ipt_tcpmss_target: bad length (%d bytes)\n",
- (*pskb)->len);
- return NF_DROP;
- }
-
- if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) {
- if (dst_mtu((*pskb)->dst) <= sizeof(struct iphdr) +
- sizeof(struct tcphdr)) {
- if (net_ratelimit())
- printk(KERN_ERR "ipt_tcpmss_target: "
- "unknown or invalid path-MTU (%d)\n",
- dst_mtu((*pskb)->dst));
- return NF_DROP; /* or IPT_CONTINUE ?? */
- }
-
- newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) -
- sizeof(struct tcphdr);
- } else
- newmss = tcpmssinfo->mss;
-
- opt = (u_int8_t *)tcph;
- for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
- if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
- opt[i+1] == TCPOLEN_MSS) {
- u_int16_t oldmss;
-
- oldmss = (opt[i+2] << 8) | opt[i+3];
-
- if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU &&
- oldmss <= newmss)
- return IPT_CONTINUE;
-
- opt[i+2] = (newmss & 0xff00) >> 8;
- opt[i+3] = (newmss & 0x00ff);
-
- nf_proto_csum_replace2(&tcph->check, *pskb,
- htons(oldmss), htons(newmss), 0);
- return IPT_CONTINUE;
- }
- }
-
- /*
- * MSS Option not found ?! add it..
- */
- if (skb_tailroom((*pskb)) < TCPOLEN_MSS) {
- struct sk_buff *newskb;
-
- newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
- TCPOLEN_MSS, GFP_ATOMIC);
- if (!newskb)
- return NF_DROP;
- kfree_skb(*pskb);
- *pskb = newskb;
- iph = (*pskb)->nh.iph;
- tcph = (void *)iph + iph->ihl*4;
- }
-
- skb_put((*pskb), TCPOLEN_MSS);
-
- opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
- memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
-
- nf_proto_csum_replace2(&tcph->check, *pskb,
- htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
- opt[0] = TCPOPT_MSS;
- opt[1] = TCPOLEN_MSS;
- opt[2] = (newmss & 0xff00) >> 8;
- opt[3] = (newmss & 0x00ff);
-
- nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0);
-
- oldval = ((__be16 *)tcph)[6];
- tcph->doff += TCPOLEN_MSS/4;
- nf_proto_csum_replace2(&tcph->check, *pskb,
- oldval, ((__be16 *)tcph)[6], 0);
-
- newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS);
- nf_csum_replace2(&iph->check, iph->tot_len, newtotlen);
- iph->tot_len = newtotlen;
- return IPT_CONTINUE;
-}
-
-#define TH_SYN 0x02
-
-static inline int find_syn_match(const struct ipt_entry_match *m)
-{
- const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data;
-
- if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
- tcpinfo->flg_cmp & TH_SYN &&
- !(tcpinfo->invflags & IPT_TCP_INV_FLAGS))
- return 1;
-
- return 0;
-}
-
-/* Must specify -p tcp --syn/--tcp-flags SYN */
-static int
-ipt_tcpmss_checkentry(const char *tablename,
- const void *e_void,
- const struct xt_target *target,
- void *targinfo,
- unsigned int hook_mask)
-{
- const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
- const struct ipt_entry *e = e_void;
-
- if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU &&
- (hook_mask & ~((1 << NF_IP_FORWARD) |
- (1 << NF_IP_LOCAL_OUT) |
- (1 << NF_IP_POST_ROUTING))) != 0) {
- printk("TCPMSS: path-MTU clamping only supported in "
- "FORWARD, OUTPUT and POSTROUTING hooks\n");
- return 0;
- }
-
- if (IPT_MATCH_ITERATE(e, find_syn_match))
- return 1;
- printk("TCPMSS: Only works on TCP SYN packets\n");
- return 0;
-}
-
-static struct ipt_target ipt_tcpmss_reg = {
- .name = "TCPMSS",
- .target = ipt_tcpmss_target,
- .targetsize = sizeof(struct ipt_tcpmss_info),
- .proto = IPPROTO_TCP,
- .checkentry = ipt_tcpmss_checkentry,
- .me = THIS_MODULE,
-};
-
-static int __init ipt_tcpmss_init(void)
-{
- return ipt_register_target(&ipt_tcpmss_reg);
-}
-
-static void __exit ipt_tcpmss_fini(void)
-{
- ipt_unregister_target(&ipt_tcpmss_reg);
-}
-
-module_init(ipt_tcpmss_init);
-module_exit(ipt_tcpmss_fini);
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
index 18e74ac4d42..29b05a6bd10 100644
--- a/net/ipv4/netfilter/ipt_TOS.c
+++ b/net/ipv4/netfilter/ipt_TOS.c
@@ -13,7 +13,7 @@
#include <linux/ip.h>
#include <net/checksum.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_TOS.h>
MODULE_LICENSE("GPL");
@@ -40,7 +40,7 @@ target(struct sk_buff **pskb,
iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos));
}
- return IPT_CONTINUE;
+ return XT_CONTINUE;
}
static int
@@ -63,8 +63,9 @@ checkentry(const char *tablename,
return 1;
}
-static struct ipt_target ipt_tos_reg = {
+static struct xt_target ipt_tos_reg = {
.name = "TOS",
+ .family = AF_INET,
.target = target,
.targetsize = sizeof(struct ipt_tos_target_info),
.table = "mangle",
@@ -74,12 +75,12 @@ static struct ipt_target ipt_tos_reg = {
static int __init ipt_tos_init(void)
{
- return ipt_register_target(&ipt_tos_reg);
+ return xt_register_target(&ipt_tos_reg);
}
static void __exit ipt_tos_fini(void)
{
- ipt_unregister_target(&ipt_tos_reg);
+ xt_unregister_target(&ipt_tos_reg);
}
module_init(ipt_tos_init);
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
index fffe5ca82e9..d2b6fa3f9dc 100644
--- a/net/ipv4/netfilter/ipt_TTL.c
+++ b/net/ipv4/netfilter/ipt_TTL.c
@@ -12,7 +12,7 @@
#include <linux/ip.h>
#include <net/checksum.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_TTL.h>
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
@@ -59,7 +59,7 @@ ipt_ttl_target(struct sk_buff **pskb,
iph->ttl = new_ttl;
}
- return IPT_CONTINUE;
+ return XT_CONTINUE;
}
static int ipt_ttl_checkentry(const char *tablename,
@@ -80,8 +80,9 @@ static int ipt_ttl_checkentry(const char *tablename,
return 1;
}
-static struct ipt_target ipt_TTL = {
+static struct xt_target ipt_TTL = {
.name = "TTL",
+ .family = AF_INET,
.target = ipt_ttl_target,
.targetsize = sizeof(struct ipt_TTL_info),
.table = "mangle",
@@ -91,12 +92,12 @@ static struct ipt_target ipt_TTL = {
static int __init ipt_ttl_init(void)
{
- return ipt_register_target(&ipt_TTL);
+ return xt_register_target(&ipt_TTL);
}
static void __exit ipt_ttl_fini(void)
{
- ipt_unregister_target(&ipt_TTL);
+ xt_unregister_target(&ipt_TTL);
}
module_init(ipt_ttl_init);
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index dbd34783a64..7af57a3a1f3 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -57,7 +57,7 @@
#include <linux/mm.h>
#include <linux/moduleparam.h>
#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_ULOG.h>
#include <net/sock.h>
#include <linux/bitops.h>
@@ -132,7 +132,6 @@ static void ulog_send(unsigned int nlgroupnum)
ub->qlen = 0;
ub->skb = NULL;
ub->lastnlh = NULL;
-
}
@@ -314,7 +313,7 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL);
- return IPT_CONTINUE;
+ return XT_CONTINUE;
}
static void ipt_logfn(unsigned int pf,
@@ -363,8 +362,9 @@ static int ipt_ulog_checkentry(const char *tablename,
return 1;
}
-static struct ipt_target ipt_ulog_reg = {
+static struct xt_target ipt_ulog_reg = {
.name = "ULOG",
+ .family = AF_INET,
.target = ipt_ulog_target,
.targetsize = sizeof(struct ipt_ulog_info),
.checkentry = ipt_ulog_checkentry,
@@ -379,7 +379,7 @@ static struct nf_logger ipt_ulog_logger = {
static int __init ipt_ulog_init(void)
{
- int i;
+ int ret, i;
DEBUGP("ipt_ULOG: init module\n");
@@ -400,9 +400,10 @@ static int __init ipt_ulog_init(void)
if (!nflognl)
return -ENOMEM;
- if (ipt_register_target(&ipt_ulog_reg) != 0) {
+ ret = xt_register_target(&ipt_ulog_reg);
+ if (ret < 0) {
sock_release(nflognl->sk_socket);
- return -EINVAL;
+ return ret;
}
if (nflog)
nf_log_register(PF_INET, &ipt_ulog_logger);
@@ -419,7 +420,7 @@ static void __exit ipt_ulog_fini(void)
if (nflog)
nf_log_unregister_logger(&ipt_ulog_logger);
- ipt_unregister_target(&ipt_ulog_reg);
+ xt_unregister_target(&ipt_ulog_reg);
sock_release(nflognl->sk_socket);
/* remove pending timers and free allocated skb's */
@@ -435,7 +436,6 @@ static void __exit ipt_ulog_fini(void)
ub->skb = NULL;
}
}
-
}
module_init(ipt_ulog_init);
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index 7b60eb74788..648f555c4d1 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -16,7 +16,7 @@
#include <net/route.h>
#include <linux/netfilter_ipv4/ipt_addrtype.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
@@ -44,8 +44,9 @@ static int match(const struct sk_buff *skb,
return ret;
}
-static struct ipt_match addrtype_match = {
+static struct xt_match addrtype_match = {
.name = "addrtype",
+ .family = AF_INET,
.match = match,
.matchsize = sizeof(struct ipt_addrtype_info),
.me = THIS_MODULE
@@ -53,12 +54,12 @@ static struct ipt_match addrtype_match = {
static int __init ipt_addrtype_init(void)
{
- return ipt_register_match(&addrtype_match);
+ return xt_register_match(&addrtype_match);
}
static void __exit ipt_addrtype_fini(void)
{
- ipt_unregister_match(&addrtype_match);
+ xt_unregister_match(&addrtype_match);
}
module_init(ipt_addrtype_init);
diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
index 1798f86bc53..42f41224a43 100644
--- a/net/ipv4/netfilter/ipt_ah.c
+++ b/net/ipv4/netfilter/ipt_ah.c
@@ -6,12 +6,13 @@
* published by the Free Software Foundation.
*/
+#include <linux/in.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/netfilter_ipv4/ipt_ah.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yon Uriarte <yon@astaro.de>");
@@ -86,8 +87,9 @@ checkentry(const char *tablename,
return 1;
}
-static struct ipt_match ah_match = {
+static struct xt_match ah_match = {
.name = "ah",
+ .family = AF_INET,
.match = match,
.matchsize = sizeof(struct ipt_ah),
.proto = IPPROTO_AH,
@@ -97,12 +99,12 @@ static struct ipt_match ah_match = {
static int __init ipt_ah_init(void)
{
- return ipt_register_match(&ah_match);
+ return xt_register_match(&ah_match);
}
static void __exit ipt_ah_fini(void)
{
- ipt_unregister_match(&ah_match);
+ xt_unregister_match(&ah_match);
}
module_init(ipt_ah_init);
diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c
index dafbdec0efc..37508b2cfea 100644
--- a/net/ipv4/netfilter/ipt_ecn.c
+++ b/net/ipv4/netfilter/ipt_ecn.c
@@ -9,10 +9,13 @@
* published by the Free Software Foundation.
*/
+#include <linux/in.h>
+#include <linux/ip.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/tcp.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_ecn.h>
@@ -109,8 +112,9 @@ static int checkentry(const char *tablename, const void *ip_void,
return 1;
}
-static struct ipt_match ecn_match = {
+static struct xt_match ecn_match = {
.name = "ecn",
+ .family = AF_INET,
.match = match,
.matchsize = sizeof(struct ipt_ecn_info),
.checkentry = checkentry,
@@ -119,12 +123,12 @@ static struct ipt_match ecn_match = {
static int __init ipt_ecn_init(void)
{
- return ipt_register_match(&ecn_match);
+ return xt_register_match(&ecn_match);
}
static void __exit ipt_ecn_fini(void)
{
- ipt_unregister_match(&ecn_match);
+ xt_unregister_match(&ecn_match);
}
module_init(ipt_ecn_init);
diff --git a/net/ipv4/netfilter/ipt_iprange.c b/net/ipv4/netfilter/ipt_iprange.c
index 5202edd8d33..05de593be94 100644
--- a/net/ipv4/netfilter/ipt_iprange.c
+++ b/net/ipv4/netfilter/ipt_iprange.c
@@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_iprange.h>
MODULE_LICENSE("GPL");
@@ -63,22 +63,22 @@ match(const struct sk_buff *skb,
return 1;
}
-static struct ipt_match iprange_match = {
+static struct xt_match iprange_match = {
.name = "iprange",
+ .family = AF_INET,
.match = match,
.matchsize = sizeof(struct ipt_iprange_info),
- .destroy = NULL,
.me = THIS_MODULE
};
static int __init ipt_iprange_init(void)
{
- return ipt_register_match(&iprange_match);
+ return xt_register_match(&iprange_match);
}
static void __exit ipt_iprange_fini(void)
{
- ipt_unregister_match(&iprange_match);
+ xt_unregister_match(&iprange_match);
}
module_init(ipt_iprange_init);
diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c
index 78c336f12a9..9f496ac834b 100644
--- a/net/ipv4/netfilter/ipt_owner.c
+++ b/net/ipv4/netfilter/ipt_owner.c
@@ -15,7 +15,7 @@
#include <net/sock.h>
#include <linux/netfilter_ipv4/ipt_owner.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
@@ -68,8 +68,9 @@ checkentry(const char *tablename,
return 1;
}
-static struct ipt_match owner_match = {
+static struct xt_match owner_match = {
.name = "owner",
+ .family = AF_INET,
.match = match,
.matchsize = sizeof(struct ipt_owner_info),
.hooks = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING),
@@ -79,12 +80,12 @@ static struct ipt_match owner_match = {
static int __init ipt_owner_init(void)
{
- return ipt_register_match(&owner_match);
+ return xt_register_match(&owner_match);
}
static void __exit ipt_owner_fini(void)
{
- ipt_unregister_match(&owner_match);
+ xt_unregister_match(&owner_match);
}
module_init(ipt_owner_init);
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
index 126db44e71a..6b97b679617 100644
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -12,6 +12,7 @@
* Copyright 2002-2003, Stephen Frost, 2.5.x port by laforge@netfilter.org
*/
#include <linux/init.h>
+#include <linux/ip.h>
#include <linux/moduleparam.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
@@ -24,7 +25,7 @@
#include <linux/skbuff.h>
#include <linux/inet.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_recent.h>
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
@@ -401,7 +402,7 @@ static int recent_seq_open(struct inode *inode, struct file *file)
static ssize_t recent_proc_write(struct file *file, const char __user *input,
size_t size, loff_t *loff)
{
- struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
struct recent_table *t = pde->data;
struct recent_entry *e;
char buf[sizeof("+255.255.255.255")], *c = buf;
@@ -462,8 +463,9 @@ static struct file_operations recent_fops = {
};
#endif /* CONFIG_PROC_FS */
-static struct ipt_match recent_match = {
+static struct xt_match recent_match = {
.name = "recent",
+ .family = AF_INET,
.match = ipt_recent_match,
.matchsize = sizeof(struct ipt_recent_info),
.checkentry = ipt_recent_checkentry,
@@ -479,13 +481,13 @@ static int __init ipt_recent_init(void)
return -EINVAL;
ip_list_hash_size = 1 << fls(ip_list_tot);
- err = ipt_register_match(&recent_match);
+ err = xt_register_match(&recent_match);
#ifdef CONFIG_PROC_FS
if (err)
return err;
proc_dir = proc_mkdir("ipt_recent", proc_net);
if (proc_dir == NULL) {
- ipt_unregister_match(&recent_match);
+ xt_unregister_match(&recent_match);
err = -ENOMEM;
}
#endif
@@ -495,7 +497,7 @@ static int __init ipt_recent_init(void)
static void __exit ipt_recent_exit(void)
{
BUG_ON(!list_empty(&tables));
- ipt_unregister_match(&recent_match);
+ xt_unregister_match(&recent_match);
#ifdef CONFIG_PROC_FS
remove_proc_entry("ipt_recent", proc_net);
#endif
diff --git a/net/ipv4/netfilter/ipt_tos.c b/net/ipv4/netfilter/ipt_tos.c
index 5549c39c785..5d33b51d49d 100644
--- a/net/ipv4/netfilter/ipt_tos.c
+++ b/net/ipv4/netfilter/ipt_tos.c
@@ -8,11 +8,12 @@
* published by the Free Software Foundation.
*/
+#include <linux/ip.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ipt_tos.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("iptables TOS match module");
@@ -32,8 +33,9 @@ match(const struct sk_buff *skb,
return (skb->nh.iph->tos == info->tos) ^ info->invert;
}
-static struct ipt_match tos_match = {
+static struct xt_match tos_match = {
.name = "tos",
+ .family = AF_INET,
.match = match,
.matchsize = sizeof(struct ipt_tos_info),
.me = THIS_MODULE,
@@ -41,12 +43,12 @@ static struct ipt_match tos_match = {
static int __init ipt_multiport_init(void)
{
- return ipt_register_match(&tos_match);
+ return xt_register_match(&tos_match);
}
static void __exit ipt_multiport_fini(void)
{
- ipt_unregister_match(&tos_match);
+ xt_unregister_match(&tos_match);
}
module_init(ipt_multiport_init);
diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c
index a5243bdb87d..d5cd984e5ed 100644
--- a/net/ipv4/netfilter/ipt_ttl.c
+++ b/net/ipv4/netfilter/ipt_ttl.c
@@ -9,11 +9,12 @@
* published by the Free Software Foundation.
*/
+#include <linux/ip.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ipt_ttl.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("IP tables TTL matching module");
@@ -48,8 +49,9 @@ static int match(const struct sk_buff *skb,
return 0;
}
-static struct ipt_match ttl_match = {
+static struct xt_match ttl_match = {
.name = "ttl",
+ .family = AF_INET,
.match = match,
.matchsize = sizeof(struct ipt_ttl_info),
.me = THIS_MODULE,
@@ -57,13 +59,12 @@ static struct ipt_match ttl_match = {
static int __init ipt_ttl_init(void)
{
- return ipt_register_match(&ttl_match);
+ return xt_register_match(&ttl_match);
}
static void __exit ipt_ttl_fini(void)
{
- ipt_unregister_match(&ttl_match);
-
+ xt_unregister_match(&ttl_match);
}
module_init(ipt_ttl_init);
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index e2e7dd8d790..51053cb42f4 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -74,7 +74,7 @@ static struct
}
};
-static struct ipt_table packet_filter = {
+static struct xt_table packet_filter = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.lock = RW_LOCK_UNLOCKED,
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index af293988944..a532e4d8433 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -103,7 +103,7 @@ static struct
}
};
-static struct ipt_table packet_mangler = {
+static struct xt_table packet_mangler = {
.name = "mangle",
.valid_hooks = MANGLE_VALID_HOOKS,
.lock = RW_LOCK_UNLOCKED,
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index bcbeb4aeacd..5277550fa6b 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -79,7 +79,7 @@ static struct
}
};
-static struct ipt_table packet_raw = {
+static struct xt_table packet_raw = {
.name = "raw",
.valid_hooks = RAW_VALID_HOOKS,
.lock = RW_LOCK_UNLOCKED,
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 86a92272b05..998b2557692 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -254,8 +254,9 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
if (maniptype == IP_NAT_MANIP_SRC) {
if (find_appropriate_src(orig_tuple, tuple, range)) {
DEBUGP("get_unique_tuple: Found current src map\n");
- if (!nf_nat_used_tuple(tuple, ct))
- return;
+ if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
+ if (!nf_nat_used_tuple(tuple, ct))
+ return;
}
}
@@ -269,6 +270,13 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
proto = nf_nat_proto_find_get(orig_tuple->dst.protonum);
+ /* Change protocol info to have some randomization */
+ if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
+ proto->unique_tuple(tuple, range, maniptype, ct);
+ nf_nat_proto_put(proto);
+ return;
+ }
+
/* Only bother mapping if it's not already in range and unique */
if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
proto->in_range(tuple, maniptype, &range->min, &range->max)) &&
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index 98fbfc84d18..dc6738bdfab 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -176,7 +176,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
datalen = (*pskb)->len - iph->ihl*4;
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
tcph->check = 0;
- tcph->check = tcp_v4_check(tcph, datalen,
+ tcph->check = tcp_v4_check(datalen,
iph->saddr, iph->daddr,
csum_partial((char *)tcph,
datalen, 0));
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index 0ae45b79a4e..5df4fcae3ab 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -72,9 +72,9 @@ static void pptp_nat_expected(struct nf_conn *ct,
DEBUGP("we are PAC->PNS\n");
/* build tuple for PNS->PAC */
t.src.l3num = AF_INET;
- t.src.u3.ip = master->tuplehash[exp->dir].tuple.src.u3.ip;
+ t.src.u3.ip = master->tuplehash[!exp->dir].tuple.src.u3.ip;
t.src.u.gre.key = nat_pptp_info->pns_call_id;
- t.dst.u3.ip = master->tuplehash[exp->dir].tuple.dst.u3.ip;
+ t.dst.u3.ip = master->tuplehash[!exp->dir].tuple.dst.u3.ip;
t.dst.u.gre.key = nat_pptp_info->pac_call_id;
t.dst.protonum = IPPROTO_GRE;
}
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c
index 7e26a7e9bee..439164c7a62 100644
--- a/net/ipv4/netfilter/nf_nat_proto_tcp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/random.h>
#include <linux/ip.h>
#include <linux/tcp.h>
@@ -75,6 +76,9 @@ tcp_unique_tuple(struct nf_conntrack_tuple *tuple,
range_size = ntohs(range->max.tcp.port) - min + 1;
}
+ if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
+ port = net_random();
+
for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size);
if (!nf_nat_used_tuple(tuple, ct))
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c
index ab0ce4c8699..8cae6e063bb 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_udp.c
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/random.h>
#include <linux/ip.h>
#include <linux/udp.h>
@@ -73,6 +74,9 @@ udp_unique_tuple(struct nf_conntrack_tuple *tuple,
range_size = ntohs(range->max.udp.port) - min + 1;
}
+ if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
+ port = net_random();
+
for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size);
if (!nf_nat_used_tuple(tuple, ct))
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index b868ee0195d..7f95b4e2eb3 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -119,7 +119,7 @@ static struct
}
};
-static struct ipt_table nat_table = {
+static struct xt_table nat_table = {
.name = "nat",
.valid_hooks = NAT_VALID_HOOKS,
.lock = RW_LOCK_UNLOCKED,
@@ -226,6 +226,10 @@ static int ipt_dnat_checkentry(const char *tablename,
printk("DNAT: multiple ranges no longer supported\n");
return 0;
}
+ if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
+ printk("DNAT: port randomization not supported\n");
+ return 0;
+ }
return 1;
}
@@ -290,7 +294,7 @@ int nf_nat_rule_find(struct sk_buff **pskb,
return ret;
}
-static struct ipt_target ipt_snat_reg = {
+static struct xt_target ipt_snat_reg = {
.name = "SNAT",
.target = ipt_snat_target,
.targetsize = sizeof(struct nf_nat_multi_range_compat),
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index 730a7a44c88..5a964a167c1 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -32,12 +32,6 @@
#define DEBUGP(format, args...)
#endif
-#define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \
- : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \
- : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \
- : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \
- : "*ERROR*")))
-
#ifdef CONFIG_XFRM
static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
{
@@ -123,7 +117,7 @@ nf_nat_fn(unsigned int hooknum,
nat = nfct_nat(ct);
if (!nat)
- return NF_DROP;
+ return NF_ACCEPT;
switch (ctinfo) {
case IP_CT_RELATED:
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index a6c63bbd9dd..fed6a1e7af9 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -489,7 +489,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
}
security_sk_classify_flow(sk, &fl);
- err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
+ err = ip_route_output_flow(&rt, &fl, sk, 1);
}
if (err)
goto done;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 11c167118e8..baee304a3cb 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1325,7 +1325,8 @@ void ip_rt_send_redirect(struct sk_buff *skb)
/* Check for load limit; set rate_last to the latest sent
* redirect.
*/
- if (time_after(jiffies,
+ if (rt->u.dst.rate_tokens == 0 ||
+ time_after(jiffies,
(rt->u.dst.rate_last +
(ip_rt_redirect_load << rt->u.dst.rate_tokens)))) {
icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
@@ -2634,7 +2635,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
r = nlmsg_data(nlh);
r->rtm_family = AF_INET;
@@ -2717,7 +2718,8 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
return nlmsg_end(skb, nlh);
nla_put_failure:
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
@@ -2872,8 +2874,7 @@ static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table,
void __user *oldval,
size_t __user *oldlenp,
void __user *newval,
- size_t newlen,
- void **context)
+ size_t newlen)
{
int delay;
if (newlen != sizeof(int))
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index dfcf47f10f8..fabf69a9108 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -51,8 +51,7 @@ int ipv4_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
static int ipv4_sysctl_forward_strategy(ctl_table *table,
int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
+ void __user *newval, size_t newlen)
{
int *valp = table->data;
int new;
@@ -111,8 +110,7 @@ static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file *
static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
int nlen, void __user *oldval,
size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
+ void __user *newval, size_t newlen)
{
char val[TCP_CA_NAME_MAX];
ctl_table tbl = {
@@ -122,8 +120,7 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
int ret;
tcp_get_default_congestion_control(val);
- ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen,
- context);
+ ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen);
if (ret == 0 && newval && newlen)
ret = tcp_set_default_congestion_control(val);
return ret;
@@ -169,8 +166,8 @@ static int proc_allowed_congestion_control(ctl_table *ctl,
static int strategy_allowed_congestion_control(ctl_table *table, int __user *name,
int nlen, void __user *oldval,
size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
+ void __user *newval,
+ size_t newlen)
{
ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX };
int ret;
@@ -180,8 +177,7 @@ static int strategy_allowed_congestion_control(ctl_table *table, int __user *nam
return -ENOMEM;
tcp_get_available_congestion_control(tbl.data, tbl.maxlen);
- ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen,
- context);
+ ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen);
if (ret == 0 && newval && newlen)
ret = tcp_set_allowed_congestion_control(tbl.data);
kfree(tbl.data);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 090c690627e..5bd43d7294f 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2364,8 +2364,9 @@ struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu)
EXPORT_SYMBOL(__tcp_get_md5sig_pool);
-void __tcp_put_md5sig_pool(void) {
- __tcp_free_md5sig_pool(tcp_md5sig_pool);
+void __tcp_put_md5sig_pool(void)
+{
+ tcp_free_md5sig_pool();
}
EXPORT_SYMBOL(__tcp_put_md5sig_pool);
@@ -2414,10 +2415,11 @@ void __init tcp_init(void)
&tcp_hashinfo.ehash_size,
NULL,
0);
- tcp_hashinfo.ehash_size = (1 << tcp_hashinfo.ehash_size) >> 1;
- for (i = 0; i < (tcp_hashinfo.ehash_size << 1); i++) {
+ tcp_hashinfo.ehash_size = 1 << tcp_hashinfo.ehash_size;
+ for (i = 0; i < tcp_hashinfo.ehash_size; i++) {
rwlock_init(&tcp_hashinfo.ehash[i].lock);
INIT_HLIST_HEAD(&tcp_hashinfo.ehash[i].chain);
+ INIT_HLIST_HEAD(&tcp_hashinfo.ehash[i].twchain);
}
tcp_hashinfo.bhash =
@@ -2474,7 +2476,7 @@ void __init tcp_init(void)
printk(KERN_INFO "TCP: Hash tables configured "
"(established %d bind %d)\n",
- tcp_hashinfo.ehash_size << 1, tcp_hashinfo.bhash_size);
+ tcp_hashinfo.ehash_size, tcp_hashinfo.bhash_size);
tcp_register_congestion_control(&tcp_reno);
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index c701f6abbfc..c6109895bb5 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -936,28 +936,58 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
struct tcp_sock *tp = tcp_sk(sk);
unsigned char *ptr = ack_skb->h.raw + TCP_SKB_CB(ack_skb)->sacked;
struct tcp_sack_block_wire *sp = (struct tcp_sack_block_wire *)(ptr+2);
+ struct sk_buff *cached_skb;
int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
int reord = tp->packets_out;
int prior_fackets;
u32 lost_retrans = 0;
int flag = 0;
int dup_sack = 0;
+ int cached_fack_count;
int i;
+ int first_sack_index;
if (!tp->sacked_out)
tp->fackets_out = 0;
prior_fackets = tp->fackets_out;
+ /* Check for D-SACK. */
+ if (before(ntohl(sp[0].start_seq), TCP_SKB_CB(ack_skb)->ack_seq)) {
+ dup_sack = 1;
+ tp->rx_opt.sack_ok |= 4;
+ NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV);
+ } else if (num_sacks > 1 &&
+ !after(ntohl(sp[0].end_seq), ntohl(sp[1].end_seq)) &&
+ !before(ntohl(sp[0].start_seq), ntohl(sp[1].start_seq))) {
+ dup_sack = 1;
+ tp->rx_opt.sack_ok |= 4;
+ NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV);
+ }
+
+ /* D-SACK for already forgotten data...
+ * Do dumb counting. */
+ if (dup_sack &&
+ !after(ntohl(sp[0].end_seq), prior_snd_una) &&
+ after(ntohl(sp[0].end_seq), tp->undo_marker))
+ tp->undo_retrans--;
+
+ /* Eliminate too old ACKs, but take into
+ * account more or less fresh ones, they can
+ * contain valid SACK info.
+ */
+ if (before(TCP_SKB_CB(ack_skb)->ack_seq, prior_snd_una - tp->max_window))
+ return 0;
+
/* SACK fastpath:
* if the only SACK change is the increase of the end_seq of
* the first block then only apply that SACK block
* and use retrans queue hinting otherwise slowpath */
flag = 1;
- for (i = 0; i< num_sacks; i++) {
- __u32 start_seq = ntohl(sp[i].start_seq);
- __u32 end_seq = ntohl(sp[i].end_seq);
+ for (i = 0; i < num_sacks; i++) {
+ __be32 start_seq = sp[i].start_seq;
+ __be32 end_seq = sp[i].end_seq;
- if (i == 0){
+ if (i == 0) {
if (tp->recv_sack_cache[i].start_seq != start_seq)
flag = 0;
} else {
@@ -967,39 +997,14 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
}
tp->recv_sack_cache[i].start_seq = start_seq;
tp->recv_sack_cache[i].end_seq = end_seq;
-
- /* Check for D-SACK. */
- if (i == 0) {
- u32 ack = TCP_SKB_CB(ack_skb)->ack_seq;
-
- if (before(start_seq, ack)) {
- dup_sack = 1;
- tp->rx_opt.sack_ok |= 4;
- NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV);
- } else if (num_sacks > 1 &&
- !after(end_seq, ntohl(sp[1].end_seq)) &&
- !before(start_seq, ntohl(sp[1].start_seq))) {
- dup_sack = 1;
- tp->rx_opt.sack_ok |= 4;
- NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV);
- }
-
- /* D-SACK for already forgotten data...
- * Do dumb counting. */
- if (dup_sack &&
- !after(end_seq, prior_snd_una) &&
- after(end_seq, tp->undo_marker))
- tp->undo_retrans--;
-
- /* Eliminate too old ACKs, but take into
- * account more or less fresh ones, they can
- * contain valid SACK info.
- */
- if (before(ack, prior_snd_una - tp->max_window))
- return 0;
- }
+ }
+ /* Clear the rest of the cache sack blocks so they won't match mistakenly. */
+ for (; i < ARRAY_SIZE(tp->recv_sack_cache); i++) {
+ tp->recv_sack_cache[i].start_seq = 0;
+ tp->recv_sack_cache[i].end_seq = 0;
}
+ first_sack_index = 0;
if (flag)
num_sacks = 1;
else {
@@ -1011,10 +1016,15 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
for (j = 0; j < i; j++){
if (after(ntohl(sp[j].start_seq),
ntohl(sp[j+1].start_seq))){
- sp[j].start_seq = htonl(tp->recv_sack_cache[j+1].start_seq);
- sp[j].end_seq = htonl(tp->recv_sack_cache[j+1].end_seq);
- sp[j+1].start_seq = htonl(tp->recv_sack_cache[j].start_seq);
- sp[j+1].end_seq = htonl(tp->recv_sack_cache[j].end_seq);
+ struct tcp_sack_block_wire tmp;
+
+ tmp = sp[j];
+ sp[j] = sp[j+1];
+ sp[j+1] = tmp;
+
+ /* Track where the first SACK block goes to */
+ if (j == first_sack_index)
+ first_sack_index = j+1;
}
}
@@ -1024,20 +1034,22 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
/* clear flag as used for different purpose in following code */
flag = 0;
+ /* Use SACK fastpath hint if valid */
+ cached_skb = tp->fastpath_skb_hint;
+ cached_fack_count = tp->fastpath_cnt_hint;
+ if (!cached_skb) {
+ cached_skb = sk->sk_write_queue.next;
+ cached_fack_count = 0;
+ }
+
for (i=0; i<num_sacks; i++, sp++) {
struct sk_buff *skb;
__u32 start_seq = ntohl(sp->start_seq);
__u32 end_seq = ntohl(sp->end_seq);
int fack_count;
- /* Use SACK fastpath hint if valid */
- if (tp->fastpath_skb_hint) {
- skb = tp->fastpath_skb_hint;
- fack_count = tp->fastpath_cnt_hint;
- } else {
- skb = sk->sk_write_queue.next;
- fack_count = 0;
- }
+ skb = cached_skb;
+ fack_count = cached_fack_count;
/* Event "B" in the comment above. */
if (after(end_seq, tp->high_seq))
@@ -1047,8 +1059,12 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
int in_sack, pcount;
u8 sacked;
- tp->fastpath_skb_hint = skb;
- tp->fastpath_cnt_hint = fack_count;
+ cached_skb = skb;
+ cached_fack_count = fack_count;
+ if (i == first_sack_index) {
+ tp->fastpath_skb_hint = skb;
+ tp->fastpath_cnt_hint = fack_count;
+ }
/* The retransmission queue is always in order, so
* we can short-circuit the walk early.
@@ -4420,9 +4436,11 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
* But, this leaves one open to an easy denial of
* service attack, and SYN cookies can't defend
* against this problem. So, we drop the data
- * in the interest of security over speed.
+ * in the interest of security over speed unless
+ * it's still in use.
*/
- goto discard;
+ kfree_skb(skb);
+ return 0;
}
goto discard;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index a1222d6968c..f51d6404c61 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -191,7 +191,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
tmp = ip_route_connect(&rt, nexthop, inet->saddr,
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
IPPROTO_TCP,
- inet->sport, usin->sin_port, sk);
+ inet->sport, usin->sin_port, sk, 1);
if (tmp < 0)
return tmp;
@@ -502,11 +502,11 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
struct tcphdr *th = skb->h.th;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- th->check = ~tcp_v4_check(th, len,
- inet->saddr, inet->daddr, 0);
+ th->check = ~tcp_v4_check(len, inet->saddr,
+ inet->daddr, 0);
skb->csum_offset = offsetof(struct tcphdr, check);
} else {
- th->check = tcp_v4_check(th, len, inet->saddr, inet->daddr,
+ th->check = tcp_v4_check(len, inet->saddr, inet->daddr,
csum_partial((char *)th,
th->doff << 2,
skb->csum));
@@ -525,7 +525,7 @@ int tcp_v4_gso_send_check(struct sk_buff *skb)
th = skb->h.th;
th->check = 0;
- th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0);
+ th->check = ~tcp_v4_check(skb->len, iph->saddr, iph->daddr, 0);
skb->csum_offset = offsetof(struct tcphdr, check);
skb->ip_summed = CHECKSUM_PARTIAL;
return 0;
@@ -648,7 +648,7 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
TCPOLEN_TIMESTAMP);
rep.opt[1] = htonl(tcp_time_stamp);
rep.opt[2] = htonl(ts);
- arg.iov[0].iov_len = TCPOLEN_TSTAMP_ALIGNED;
+ arg.iov[0].iov_len += TCPOLEN_TSTAMP_ALIGNED;
}
/* Swap the send and the receive. */
@@ -747,7 +747,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
if (skb) {
struct tcphdr *th = skb->h.th;
- th->check = tcp_v4_check(th, skb->len,
+ th->check = tcp_v4_check(skb->len,
ireq->loc_addr,
ireq->rmt_addr,
csum_partial((char *)th, skb->len,
@@ -928,6 +928,7 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr)
if (tp->md5sig_info->entries4 == 0) {
kfree(tp->md5sig_info->keys4);
tp->md5sig_info->keys4 = NULL;
+ tp->md5sig_info->alloced4 = 0;
} else if (tp->md5sig_info->entries4 != i) {
/* Need to do some manipulation */
memcpy(&tp->md5sig_info->keys4[i],
@@ -1185,7 +1186,7 @@ done_opts:
return 0;
if (hash_expected && !hash_location) {
- LIMIT_NETDEBUG(KERN_INFO "MD5 Hash NOT expected but found "
+ LIMIT_NETDEBUG(KERN_INFO "MD5 Hash expected but NOT found "
"(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)\n",
NIPQUAD(iph->saddr), ntohs(th->source),
NIPQUAD(iph->daddr), ntohs(th->dest));
@@ -1513,7 +1514,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
static __sum16 tcp_v4_checksum_init(struct sk_buff *skb)
{
if (skb->ip_summed == CHECKSUM_COMPLETE) {
- if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr,
+ if (!tcp_v4_check(skb->len, skb->nh.iph->saddr,
skb->nh.iph->daddr, skb->csum)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
return 0;
@@ -2050,7 +2051,7 @@ static void *established_get_first(struct seq_file *seq)
}
st->state = TCP_SEQ_STATE_TIME_WAIT;
inet_twsk_for_each(tw, node,
- &tcp_hashinfo.ehash[st->bucket + tcp_hashinfo.ehash_size].chain) {
+ &tcp_hashinfo.ehash[st->bucket].twchain) {
if (tw->tw_family != st->family) {
continue;
}
@@ -2106,7 +2107,7 @@ get_tw:
}
st->state = TCP_SEQ_STATE_TIME_WAIT;
- tw = tw_head(&tcp_hashinfo.ehash[st->bucket + tcp_hashinfo.ehash_size].chain);
+ tw = tw_head(&tcp_hashinfo.ehash[st->bucket].twchain);
goto get_tw;
found:
cur = sk;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 32c1a972fa3..58b7111523f 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -467,6 +467,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
th = (struct tcphdr *) skb_push(skb, tcp_header_size);
skb->h.th = th;
+ skb_set_owner_w(skb, sk);
/* Build TCP header and checksum it. */
th->source = inet->sport;
@@ -540,7 +541,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq)
TCP_INC_STATS(TCP_MIB_OUTSEGS);
- err = icsk->icsk_af_ops->queue_xmit(skb, sk, 0);
+ err = icsk->icsk_af_ops->queue_xmit(skb, 0);
if (likely(err <= 0))
return err;
@@ -964,7 +965,8 @@ static inline unsigned int tcp_cwnd_test(struct tcp_sock *tp, struct sk_buff *sk
u32 in_flight, cwnd;
/* Don't be strict about the congestion window for the final FIN. */
- if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
+ if ((TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
+ tcp_skb_pcount(skb) == 1)
return 1;
in_flight = tcp_packets_in_flight(tp);
@@ -1650,7 +1652,8 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size);
- skb->ip_summed = next_skb->ip_summed;
+ if (next_skb->ip_summed == CHECKSUM_PARTIAL)
+ skb->ip_summed = CHECKSUM_PARTIAL;
if (skb->ip_summed != CHECKSUM_PARTIAL)
skb->csum = csum_block_add(skb->csum, next_skb->csum, skb_size);
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index f230eeecf09..41c15784818 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -30,7 +30,7 @@
#include <net/tcp.h>
-MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
+MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
MODULE_DESCRIPTION("TCP cwnd snooper");
MODULE_LICENSE("GPL");
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 035915fc9ed..8b54c68a0d1 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -165,11 +165,14 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
goto gotit;
}
size = 0;
- sk_for_each(sk2, node, head)
- if (++size < best_size_so_far) {
- best_size_so_far = size;
- best = result;
- }
+ sk_for_each(sk2, node, head) {
+ if (++size >= best_size_so_far)
+ goto next;
+ }
+ best_size_so_far = size;
+ best = result;
+ next:
+ ;
}
result = best;
for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) {
@@ -626,7 +629,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
{ .sport = inet->sport,
.dport = dport } } };
security_sk_classify_flow(sk, &fl);
- err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
+ err = ip_route_output_flow(&rt, &fl, sk, 1);
if (err)
goto out;
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index e23c21d31a5..e54c5494c88 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -23,6 +23,12 @@ static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
IP_ECN_set_ce(inner_iph);
}
+static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
+{
+ if (INET_ECN_is_ce(iph->tos))
+ IP6_ECN_set_ce(skb->nh.ipv6h);
+}
+
/* Add encapsulation header.
*
* The top IP header will be constructed per RFC 2401. The following fields
@@ -36,6 +42,7 @@ static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
+ struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
struct iphdr *iph, *top_iph;
int flags;
@@ -48,15 +55,27 @@ static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
top_iph->ihl = 5;
top_iph->version = 4;
+ flags = x->props.flags;
+
/* DS disclosed */
- top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos);
+ if (xdst->route->ops->family == AF_INET) {
+ top_iph->protocol = IPPROTO_IPIP;
+ top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos);
+ top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
+ 0 : (iph->frag_off & htons(IP_DF));
+ }
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ else {
+ struct ipv6hdr *ipv6h = (struct ipv6hdr*)iph;
+ top_iph->protocol = IPPROTO_IPV6;
+ top_iph->tos = INET_ECN_encapsulate(iph->tos, ipv6_get_dsfield(ipv6h));
+ top_iph->frag_off = 0;
+ }
+#endif
- flags = x->props.flags;
if (flags & XFRM_STATE_NOECN)
IP_ECN_clear(top_iph);
- top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
- 0 : (iph->frag_off & htons(IP_DF));
if (!top_iph->frag_off)
__ip_select_ident(top_iph, dst->child, 0);
@@ -64,7 +83,6 @@ static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
top_iph->saddr = x->props.saddr.a4;
top_iph->daddr = x->id.daddr.a4;
- top_iph->protocol = IPPROTO_IPIP;
memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
return 0;
@@ -75,8 +93,16 @@ static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
struct iphdr *iph = skb->nh.iph;
int err = -EINVAL;
- if (iph->protocol != IPPROTO_IPIP)
- goto out;
+ switch(iph->protocol){
+ case IPPROTO_IPIP:
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ case IPPROTO_IPV6:
+ break;
+#endif
+ default:
+ goto out;
+ }
+
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto out;
@@ -84,10 +110,19 @@ static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
(err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
goto out;
- if (x->props.flags & XFRM_STATE_DECAP_DSCP)
- ipv4_copy_dscp(iph, skb->h.ipiph);
- if (!(x->props.flags & XFRM_STATE_NOECN))
- ipip_ecn_decapsulate(skb);
+ if (iph->protocol == IPPROTO_IPIP) {
+ if (x->props.flags & XFRM_STATE_DECAP_DSCP)
+ ipv4_copy_dscp(iph, skb->h.ipiph);
+ if (!(x->props.flags & XFRM_STATE_NOECN))
+ ipip_ecn_decapsulate(skb);
+ }
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ else {
+ if (!(x->props.flags & XFRM_STATE_NOECN))
+ ipip6_ecn_decapsulate(iph, skb);
+ skb->protocol = htons(ETH_P_IPV6);
+ }
+#endif
skb->mac.raw = memmove(skb->data - skb->mac_len,
skb->mac.raw, skb->mac_len);
skb->nh.raw = skb->data;
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index fb9f69c616f..699f27ce62a 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -72,13 +72,11 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
struct dst_entry *dst, *dst_prev;
struct rtable *rt0 = (struct rtable*)(*dst_p);
struct rtable *rt = rt0;
- __be32 remote = fl->fl4_dst;
- __be32 local = fl->fl4_src;
struct flowi fl_tunnel = {
.nl_u = {
.ip4_u = {
- .saddr = local,
- .daddr = remote,
+ .saddr = fl->fl4_src,
+ .daddr = fl->fl4_dst,
.tos = fl->fl4_tos
}
}
@@ -94,7 +92,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
for (i = 0; i < nx; i++) {
struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);
struct xfrm_dst *xdst;
- int tunnel = 0;
if (unlikely(dst1 == NULL)) {
err = -ENOBUFS;
@@ -116,19 +113,28 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst1->next = dst_prev;
dst_prev = dst1;
- if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
- remote = xfrm[i]->id.daddr.a4;
- local = xfrm[i]->props.saddr.a4;
- tunnel = 1;
- }
+
header_len += xfrm[i]->props.header_len;
trailer_len += xfrm[i]->props.trailer_len;
- if (tunnel) {
- fl_tunnel.fl4_src = local;
- fl_tunnel.fl4_dst = remote;
+ if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) {
+ unsigned short encap_family = xfrm[i]->props.family;
+ switch(encap_family) {
+ case AF_INET:
+ fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
+ fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
+ break;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6);
+ ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6);
+ break;
+#endif
+ default:
+ BUG_ON(1);
+ }
err = xfrm_dst_lookup((struct xfrm_dst **)&rt,
- &fl_tunnel, AF_INET);
+ &fl_tunnel, encap_family);
if (err)
goto error;
} else
@@ -145,6 +151,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
i = 0;
for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
+ struct xfrm_state_afinfo *afinfo;
x->u.rt.fl = *fl;
dst_prev->xfrm = xfrm[i++];
@@ -162,8 +169,18 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
/* Copy neighbout for reachability confirmation */
dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour);
dst_prev->input = rt->u.dst.input;
- dst_prev->output = xfrm4_output;
- if (rt->peer)
+ /* XXX: When IPv6 module can be unloaded, we should manage reference
+ * to xfrm6_output in afinfo->output. Miyazawa
+ * */
+ afinfo = xfrm_state_get_afinfo(dst_prev->xfrm->props.family);
+ if (!afinfo) {
+ dst = *dst_p;
+ err = -EAFNOSUPPORT;
+ goto error;
+ }
+ dst_prev->output = afinfo->output;
+ xfrm_state_put_afinfo(afinfo);
+ if (dst_prev->xfrm->props.family == AF_INET && rt->peer)
atomic_inc(&rt->peer->refcnt);
x->u.rt.peer = rt->peer;
/* Sheit... I remember I did this right. Apparently,
@@ -274,7 +291,7 @@ static void xfrm4_dst_destroy(struct dst_entry *dst)
if (likely(xdst->u.rt.idev))
in_dev_put(xdst->u.rt.idev);
- if (likely(xdst->u.rt.peer))
+ if (dst->xfrm->props.family == AF_INET && likely(xdst->u.rt.peer))
inet_putpeer(xdst->u.rt.peer);
xfrm_dst_destroy(xdst);
}
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 3cc3df0c6ec..93e2c061cdd 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -51,6 +51,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
.family = AF_INET,
.init_flags = xfrm4_init_flags,
.init_tempsel = __xfrm4_init_tempsel,
+ .output = xfrm4_output,
};
void __init xfrm4_state_init(void)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index a5e8d207a51..fe5e1d83387 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -341,6 +341,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
{
struct inet6_dev *ndev;
+ struct in6_addr maddr;
ASSERT_RTNL();
@@ -413,8 +414,6 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
if (netif_carrier_ok(dev))
ndev->if_flags |= IF_READY;
- /* protected by rtnl_lock */
- rcu_assign_pointer(dev->ip6_ptr, ndev);
ipv6_mc_init_dev(ndev);
ndev->tstamp = jiffies;
@@ -425,6 +424,13 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
NULL);
addrconf_sysctl_register(ndev, &ndev->cnf);
#endif
+ /* protected by rtnl_lock */
+ rcu_assign_pointer(dev->ip6_ptr, ndev);
+
+ /* Join all-node multicast group */
+ ipv6_addr_all_nodes(&maddr);
+ ipv6_dev_mc_inc(dev, &maddr);
+
return ndev;
}
@@ -3111,7 +3117,7 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope),
ifa->idev->dev->ifindex);
@@ -3131,8 +3137,10 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
}
if (nla_put(skb, IFA_ADDRESS, 16, &ifa->addr) < 0 ||
- put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0)
- return nlmsg_cancel(skb, nlh);
+ put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) {
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+ }
return nlmsg_end(skb, nlh);
}
@@ -3149,13 +3157,15 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca,
nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex);
if (nla_put(skb, IFA_MULTICAST, 16, &ifmca->mca_addr) < 0 ||
put_cacheinfo(skb, ifmca->mca_cstamp, ifmca->mca_tstamp,
- INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0)
- return nlmsg_cancel(skb, nlh);
+ INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) {
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+ }
return nlmsg_end(skb, nlh);
}
@@ -3172,13 +3182,15 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,
nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex);
if (nla_put(skb, IFA_ANYCAST, 16, &ifaca->aca_addr) < 0 ||
put_cacheinfo(skb, ifaca->aca_cstamp, ifaca->aca_tstamp,
- INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0)
- return nlmsg_cancel(skb, nlh);
+ INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) {
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+ }
return nlmsg_end(skb, nlh);
}
@@ -3328,9 +3340,12 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid,
nlh->nlmsg_seq, RTM_NEWADDR, 0);
- /* failure implies BUG in inet6_ifaddr_msgsize() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout_ifa;
+ }
err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
errout_ifa:
in6_ifa_put(ifa);
@@ -3348,9 +3363,12 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
goto errout;
err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0);
- /* failure implies BUG in inet6_ifaddr_msgsize() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout:
if (err < 0)
@@ -3387,7 +3405,7 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
#ifdef CONFIG_IPV6_ROUTER_PREF
array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref;
array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval;
-#ifdef CONFIV_IPV6_ROUTE_INFO
+#ifdef CONFIG_IPV6_ROUTE_INFO
array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
#endif
#endif
@@ -3420,7 +3438,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
hdr = nlmsg_data(nlh);
hdr->ifi_family = AF_INET6;
@@ -3463,7 +3481,8 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
return nlmsg_end(skb, nlh);
nla_put_failure:
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
@@ -3501,9 +3520,12 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
goto errout;
err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0);
- /* failure implies BUG in inet6_if_nlmsg_size() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in inet6_if_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout:
if (err < 0)
@@ -3527,7 +3549,7 @@ static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev,
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*pmsg), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
pmsg = nlmsg_data(nlh);
pmsg->prefix_family = AF_INET6;
@@ -3552,7 +3574,8 @@ static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev,
return nlmsg_end(skb, nlh);
nla_put_failure:
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
static void inet6_prefix_notify(int event, struct inet6_dev *idev,
@@ -3566,9 +3589,12 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
goto errout;
err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0);
- /* failure implies BUG in inet6_prefix_nlmsg_size() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in inet6_prefix_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
errout:
if (err < 0)
@@ -3656,8 +3682,7 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
int __user *name, int nlen,
void __user *oldval,
size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
+ void __user *newval, size_t newlen)
{
int *valp = table->data;
int new;
@@ -3893,7 +3918,7 @@ static struct addrconf_sysctl_table
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
-#ifdef CONFIV_IPV6_ROUTE_INFO
+#ifdef CONFIG_IPV6_ROUTE_INFO
{
.ctl_name = NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,
.procname = "accept_ra_rt_info_max_plen",
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index e5cd83b2205..0e0e4262f4d 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -171,7 +171,7 @@ lookup_protocol:
sk->sk_reuse = 1;
inet = inet_sk(sk);
- inet->is_icsk = INET_PROTOSW_ICSK & answer_flags;
+ inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
if (SOCK_RAW == sock->type) {
inet->num = protocol;
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 5c94fea90e9..ecde30140f4 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -178,7 +178,7 @@ ipv4_connected:
if (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, 1)) < 0)
goto out;
/* source address lookup done in ip6_dst_lookup */
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index c700302ad51..116f94a4907 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -139,8 +139,9 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
-int inet6_csk_xmit(struct sk_buff *skb, struct sock *sk, int ipfragok)
+int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
{
+ struct sock *sk = skb->sk;
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct flowi fl;
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index b7e5bae0e34..e61116949be 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -79,7 +79,7 @@ struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
goto hit; /* You sunk my battleship! */
}
/* Must check for a TIME_WAIT'er before going to listener hash. */
- sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
+ sk_for_each(sk, node, &head->twchain) {
const struct inet_timewait_sock *tw = inet_twsk(sk);
if(*((__portpair *)&(tw->tw_dport)) == ports &&
@@ -183,7 +183,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
write_lock(&head->lock);
/* Check TIME-WAIT sockets first. */
- sk_for_each(sk2, node, &(head + hinfo->ehash_size)->chain) {
+ sk_for_each(sk2, node, &head->twchain) {
const struct inet6_timewait_sock *tw6 = inet6_twsk(sk2);
tw = inet_twsk(sk2);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index e9212c7ff5c..7b7bd44fbf4 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -72,20 +72,11 @@ static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *f
static inline int ip6_output_finish(struct sk_buff *skb)
{
-
struct dst_entry *dst = skb->dst;
- struct hh_cache *hh = dst->hh;
-
- if (hh) {
- int hh_alen;
-
- read_lock_bh(&hh->hh_lock);
- hh_alen = HH_DATA_ALIGN(hh->hh_len);
- memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
- read_unlock_bh(&hh->hh_lock);
- skb_push(skb, hh->hh_len);
- return hh->hh_output(skb);
- } else if (dst->neighbour)
+
+ if (dst->hh)
+ return neigh_hh_output(dst->hh, skb);
+ else if (dst->neighbour)
return dst->neighbour->output(skb);
IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 8d918348f5b..2b9e3bb7da6 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -999,7 +999,8 @@ ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
break;
dev = t->dev;
}
- err = unregister_netdevice(dev);
+ err = 0;
+ unregister_netdevice(dev);
break;
default:
err = -EINVAL;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 1eafcfc95e8..352690e2ab8 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -978,12 +978,27 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
break;
case IPV6_UNICAST_HOPS:
- val = np->hop_limit;
- break;
-
case IPV6_MULTICAST_HOPS:
- val = np->mcast_hops;
+ {
+ struct dst_entry *dst;
+
+ if (optname == IPV6_UNICAST_HOPS)
+ val = np->hop_limit;
+ else
+ val = np->mcast_hops;
+
+ dst = sk_dst_get(sk);
+ if (dst) {
+ if (val < 0)
+ val = dst_metric(dst, RTAX_HOPLIMIT);
+ if (val < 0)
+ val = ipv6_get_hoplimit(dst->dev);
+ dst_release(dst);
+ }
+ if (val < 0)
+ val = ipv6_devconf.hop_limit;
break;
+ }
case IPV6_MULTICAST_LOOP:
val = np->mc_loop;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index a1c231a04ac..e3ec2169583 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1582,6 +1582,8 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
skb = add_grhead(skb, pmc, type, &pgr);
first = 0;
}
+ if (!skb)
+ return NULL;
psrc = (struct in6_addr *)skb_put(skb, sizeof(*psrc));
*psrc = psf->sf_addr;
scount++; stotal++;
@@ -2258,8 +2260,6 @@ void ipv6_mc_up(struct inet6_dev *idev)
void ipv6_mc_init_dev(struct inet6_dev *idev)
{
- struct in6_addr maddr;
-
write_lock_bh(&idev->lock);
rwlock_init(&idev->mc_lock);
idev->mc_gq_running = 0;
@@ -2275,10 +2275,6 @@ void ipv6_mc_init_dev(struct inet6_dev *idev)
idev->mc_maxdelay = IGMP6_UNSOLICITED_IVAL;
idev->mc_v1_seen = 0;
write_unlock_bh(&idev->lock);
-
- /* Add all-nodes address. */
- ipv6_addr_all_nodes(&maddr);
- ipv6_dev_mc_inc(idev->dev, &maddr);
}
/*
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index be7dd7db65d..681bb077eac 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -89,7 +89,6 @@ static int mip6_mh_len(int type)
int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
{
struct ip6_mh *mh;
- int mhlen;
if (!pskb_may_pull(skb, (skb->h.raw - skb->data) + 8) ||
!pskb_may_pull(skb, (skb->h.raw - skb->data) + ((skb->h.raw[1] + 1) << 3)))
@@ -103,31 +102,6 @@ int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
mip6_param_prob(skb, 0, (&mh->ip6mh_hdrlen) - skb->nh.raw);
return -1;
}
- mhlen = (mh->ip6mh_hdrlen + 1) << 3;
-
- if (skb->ip_summed == CHECKSUM_COMPLETE) {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
- &skb->nh.ipv6h->daddr,
- mhlen, IPPROTO_MH,
- skb->csum)) {
- LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH hw checksum failed\n");
- skb->ip_summed = CHECKSUM_NONE;
- }
- }
- if (skb->ip_summed == CHECKSUM_NONE) {
- if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
- &skb->nh.ipv6h->daddr,
- mhlen, IPPROTO_MH,
- skb_checksum(skb, 0, mhlen, 0))) {
- LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH checksum failed "
- "[" NIP6_FMT " > " NIP6_FMT "]\n",
- NIP6(skb->nh.ipv6h->saddr),
- NIP6(skb->nh.ipv6h->daddr));
- return -1;
- }
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- }
if (mh->ip6mh_proto != IPPROTO_NONE) {
LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n",
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 56ea9283730..39bb658f3c4 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1413,6 +1413,13 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
return;
}
+ if (!ipv6_addr_equal(&skb->nh.ipv6h->daddr, target) &&
+ !(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) {
+ ND_PRINTK2(KERN_WARNING
+ "ICMPv6 Redirect: target address is not link-local.\n");
+ return;
+ }
+
ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr,
dev->ifindex);
@@ -1667,8 +1674,7 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * f
static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
int nlen, void __user *oldval,
size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
+ void __user *newval, size_t newlen)
{
struct net_device *dev = ctl->extra1;
struct inet6_dev *idev;
@@ -1681,14 +1687,12 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
switch (ctl->ctl_name) {
case NET_NEIGH_REACHABLE_TIME:
ret = sysctl_jiffies(ctl, name, nlen,
- oldval, oldlenp, newval, newlen,
- context);
+ oldval, oldlenp, newval, newlen);
break;
case NET_NEIGH_RETRANS_TIME_MS:
case NET_NEIGH_REACHABLE_TIME_MS:
ret = sysctl_ms_jiffies(ctl, name, nlen,
- oldval, oldlenp, newval, newlen,
- context);
+ oldval, oldlenp, newval, newlen);
break;
default:
ret = 0;
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index fc3e5eb4bc3..cd549aea84f 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -7,7 +7,7 @@ menu "IPv6: Netfilter Configuration (EXPERIMENTAL)"
config NF_CONNTRACK_IPV6
tristate "IPv6 connection tracking support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && NF_CONNTRACK
+ depends on INET && IPV6 && EXPERIMENTAL && NF_CONNTRACK
---help---
Connection tracking keeps a record of what packets have passed
through your machine, in order to figure out how they are related
@@ -21,6 +21,7 @@ config NF_CONNTRACK_IPV6
config IP6_NF_QUEUE
tristate "IP6 Userspace queueing via NETLINK (OBSOLETE)"
+ depends on INET && IPV6 && NETFILTER && EXPERIMENTAL
---help---
This option adds a queue handler to the kernel for IPv6
@@ -41,7 +42,7 @@ config IP6_NF_QUEUE
config IP6_NF_IPTABLES
tristate "IP6 tables support (required for filtering)"
- depends on NETFILTER_XTABLES
+ depends on INET && IPV6 && EXPERIMENTAL && NETFILTER_XTABLES
help
ip6tables is a general, extensible packet identification framework.
Currently only the packet filtering and packet mangling subsystem
@@ -113,6 +114,14 @@ config IP6_NF_MATCH_AH
To compile it as a module, choose M here. If unsure, say N.
+config IP6_NF_MATCH_MH
+ tristate "MH match support"
+ depends on IP6_NF_IPTABLES
+ help
+ This module allows one to match MH packets.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP6_NF_MATCH_EUI64
tristate "EUI64 address check"
depends on IP6_NF_IPTABLES
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index ac1dfebde17..4513eab7739 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
+obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o
# objects for l3 independent conntrack
nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 4eec4b3988b..7083e1cfb2f 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -413,6 +413,7 @@ mark_source_chains(struct xt_table_info *newinfo,
unsigned int pos = newinfo->hook_entry[hook];
struct ip6t_entry *e
= (struct ip6t_entry *)(entry0 + pos);
+ int visited = e->comefrom & (1 << hook);
if (!(valid_hooks & (1 << hook)))
continue;
@@ -433,11 +434,11 @@ mark_source_chains(struct xt_table_info *newinfo,
|= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
/* Unconditional return/END. */
- if (e->target_offset == sizeof(struct ip6t_entry)
+ if ((e->target_offset == sizeof(struct ip6t_entry)
&& (strcmp(t->target.u.user.name,
IP6T_STANDARD_TARGET) == 0)
&& t->verdict < 0
- && unconditional(&e->ipv6)) {
+ && unconditional(&e->ipv6)) || visited) {
unsigned int oldpos, size;
if (t->verdict < -NF_MAX_VERDICT - 1) {
@@ -529,7 +530,7 @@ check_match(struct ip6t_entry_match *m,
unsigned int hookmask,
unsigned int *i)
{
- struct ip6t_match *match;
+ struct xt_match *match;
int ret;
match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
@@ -563,14 +564,14 @@ err:
return ret;
}
-static struct ip6t_target ip6t_standard_target;
+static struct xt_target ip6t_standard_target;
static inline int
check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
unsigned int *i)
{
struct ip6t_entry_target *t;
- struct ip6t_target *target;
+ struct xt_target *target;
int ret;
unsigned int j;
@@ -1347,13 +1348,13 @@ icmp6_checkentry(const char *tablename,
}
/* The built-in targets: standard (NULL) and error. */
-static struct ip6t_target ip6t_standard_target = {
+static struct xt_target ip6t_standard_target = {
.name = IP6T_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = AF_INET6,
};
-static struct ip6t_target ip6t_error_target = {
+static struct xt_target ip6t_error_target = {
.name = IP6T_ERROR_TARGET,
.target = ip6t_error,
.targetsize = IP6T_FUNCTION_MAXNAMELEN,
@@ -1370,7 +1371,7 @@ static struct nf_sockopt_ops ip6t_sockopts = {
.get = do_ip6t_get_ctl,
};
-static struct ip6t_match icmp6_matchstruct = {
+static struct xt_match icmp6_matchstruct = {
.name = "icmp6",
.match = &icmp6_match,
.matchsize = sizeof(struct ip6t_icmp),
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
index 435750f664d..04e500172fb 100644
--- a/net/ipv6/netfilter/ip6t_HL.c
+++ b/net/ipv6/netfilter/ip6t_HL.c
@@ -9,12 +9,13 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
+#include <linux/ipv6.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6t_HL.h>
MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
-MODULE_DESCRIPTION("IP tables Hop Limit modification module");
+MODULE_DESCRIPTION("IP6 tables Hop Limit modification module");
MODULE_LICENSE("GPL");
static unsigned int ip6t_hl_target(struct sk_buff **pskb,
@@ -52,10 +53,9 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb,
break;
}
- if (new_hl != ip6h->hop_limit)
- ip6h->hop_limit = new_hl;
+ ip6h->hop_limit = new_hl;
- return IP6T_CONTINUE;
+ return XT_CONTINUE;
}
static int ip6t_hl_checkentry(const char *tablename,
@@ -79,8 +79,9 @@ static int ip6t_hl_checkentry(const char *tablename,
return 1;
}
-static struct ip6t_target ip6t_HL = {
+static struct xt_target ip6t_HL = {
.name = "HL",
+ .family = AF_INET6,
.target = ip6t_hl_target,
.targetsize = sizeof(struct ip6t_HL_info),
.table = "mangle",
@@ -90,12 +91,12 @@ static struct ip6t_target ip6t_HL = {
static int __init ip6t_hl_init(void)
{
- return ip6t_register_target(&ip6t_HL);
+ return xt_register_target(&ip6t_HL);
}
static void __exit ip6t_hl_fini(void)
{
- ip6t_unregister_target(&ip6t_HL);
+ xt_unregister_target(&ip6t_HL);
}
module_init(ip6t_hl_init);
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index 33b1faa90d7..5587a77b884 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -21,6 +21,7 @@
#include <net/tcp.h>
#include <net/ipv6.h>
#include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
@@ -442,7 +443,7 @@ ip6t_log_target(struct sk_buff **pskb,
ip6t_log_packet(PF_INET6, hooknum, *pskb, in, out, &li,
loginfo->prefix);
- return IP6T_CONTINUE;
+ return XT_CONTINUE;
}
@@ -466,8 +467,9 @@ static int ip6t_log_checkentry(const char *tablename,
return 1;
}
-static struct ip6t_target ip6t_log_reg = {
+static struct xt_target ip6t_log_reg = {
.name = "LOG",
+ .family = AF_INET6,
.target = ip6t_log_target,
.targetsize = sizeof(struct ip6t_log_info),
.checkentry = ip6t_log_checkentry,
@@ -482,8 +484,11 @@ static struct nf_logger ip6t_logger = {
static int __init ip6t_log_init(void)
{
- if (ip6t_register_target(&ip6t_log_reg))
- return -EINVAL;
+ int ret;
+
+ ret = xt_register_target(&ip6t_log_reg);
+ if (ret < 0)
+ return ret;
if (nf_log_register(PF_INET6, &ip6t_logger) < 0) {
printk(KERN_WARNING "ip6t_LOG: not logging via system console "
"since somebody else already registered for PF_INET6\n");
@@ -497,7 +502,7 @@ static int __init ip6t_log_init(void)
static void __exit ip6t_log_fini(void)
{
nf_log_unregister_logger(&ip6t_logger);
- ip6t_unregister_target(&ip6t_log_reg);
+ xt_unregister_target(&ip6t_log_reg);
}
module_init(ip6t_log_init);
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index 311eae82feb..278349c1879 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -26,6 +26,7 @@
#include <net/ip6_fib.h>
#include <net/ip6_route.h>
#include <net/flow.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_REJECT.h>
@@ -234,7 +235,7 @@ static int check(const char *tablename,
} else if (rejinfo->with == IP6T_TCP_RESET) {
/* Must specify that it's a TCP packet */
if (e->ipv6.proto != IPPROTO_TCP
- || (e->ipv6.invflags & IP6T_INV_PROTO)) {
+ || (e->ipv6.invflags & XT_INV_PROTO)) {
DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
return 0;
}
@@ -242,8 +243,9 @@ static int check(const char *tablename,
return 1;
}
-static struct ip6t_target ip6t_reject_reg = {
+static struct xt_target ip6t_reject_reg = {
.name = "REJECT",
+ .family = AF_INET6,
.target = reject6_target,
.targetsize = sizeof(struct ip6t_reject_info),
.table = "filter",
@@ -255,12 +257,12 @@ static struct ip6t_target ip6t_reject_reg = {
static int __init ip6t_reject_init(void)
{
- return ip6t_register_target(&ip6t_reject_reg);
+ return xt_register_target(&ip6t_reject_reg);
}
static void __exit ip6t_reject_fini(void)
{
- ip6t_unregister_target(&ip6t_reject_reg);
+ xt_unregister_target(&ip6t_reject_reg);
}
module_init(ip6t_reject_init);
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
index 46486645eb7..456c76adcbf 100644
--- a/net/ipv6/netfilter/ip6t_ah.c
+++ b/net/ipv6/netfilter/ip6t_ah.c
@@ -15,6 +15,7 @@
#include <net/checksum.h>
#include <net/ipv6.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_ah.h>
@@ -118,8 +119,9 @@ checkentry(const char *tablename,
return 1;
}
-static struct ip6t_match ah_match = {
+static struct xt_match ah_match = {
.name = "ah",
+ .family = AF_INET6,
.match = match,
.matchsize = sizeof(struct ip6t_ah),
.checkentry = checkentry,
@@ -128,12 +130,12 @@ static struct ip6t_match ah_match = {
static int __init ip6t_ah_init(void)
{
- return ip6t_register_match(&ah_match);
+ return xt_register_match(&ah_match);
}
static void __exit ip6t_ah_fini(void)
{
- ip6t_unregister_match(&ah_match);
+ xt_unregister_match(&ah_match);
}
module_init(ip6t_ah_init);
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
index 4f6b84c8f4a..967bed71d4a 100644
--- a/net/ipv6/netfilter/ip6t_eui64.c
+++ b/net/ipv6/netfilter/ip6t_eui64.c
@@ -12,6 +12,7 @@
#include <linux/ipv6.h>
#include <linux/if_ether.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
MODULE_DESCRIPTION("IPv6 EUI64 address checking match");
@@ -61,8 +62,9 @@ match(const struct sk_buff *skb,
return 0;
}
-static struct ip6t_match eui64_match = {
+static struct xt_match eui64_match = {
.name = "eui64",
+ .family = AF_INET6,
.match = match,
.matchsize = sizeof(int),
.hooks = (1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
@@ -72,12 +74,12 @@ static struct ip6t_match eui64_match = {
static int __init ip6t_eui64_init(void)
{
- return ip6t_register_match(&eui64_match);
+ return xt_register_match(&eui64_match);
}
static void __exit ip6t_eui64_fini(void)
{
- ip6t_unregister_match(&eui64_match);
+ xt_unregister_match(&eui64_match);
}
module_init(ip6t_eui64_init);
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
index cd22eaaccdc..5a5da71321b 100644
--- a/net/ipv6/netfilter/ip6t_frag.c
+++ b/net/ipv6/netfilter/ip6t_frag.c
@@ -14,6 +14,7 @@
#include <net/checksum.h>
#include <net/ipv6.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_frag.h>
@@ -135,8 +136,9 @@ checkentry(const char *tablename,
return 1;
}
-static struct ip6t_match frag_match = {
+static struct xt_match frag_match = {
.name = "frag",
+ .family = AF_INET6,
.match = match,
.matchsize = sizeof(struct ip6t_frag),
.checkentry = checkentry,
@@ -145,12 +147,12 @@ static struct ip6t_match frag_match = {
static int __init ip6t_frag_init(void)
{
- return ip6t_register_match(&frag_match);
+ return xt_register_match(&frag_match);
}
static void __exit ip6t_frag_fini(void)
{
- ip6t_unregister_match(&frag_match);
+ xt_unregister_match(&frag_match);
}
module_init(ip6t_frag_init);
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index 3f25babe044..d2373c7cd35 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -16,6 +16,7 @@
#include <asm/byteorder.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h>
diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c
index 44a729e17c4..601cc1211c6 100644
--- a/net/ipv6/netfilter/ip6t_hl.c
+++ b/net/ipv6/netfilter/ip6t_hl.c
@@ -8,11 +8,12 @@
* published by the Free Software Foundation.
*/
+#include <linux/ipv6.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv6/ip6t_hl.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
MODULE_DESCRIPTION("IP tables Hop Limit matching module");
@@ -48,8 +49,9 @@ static int match(const struct sk_buff *skb,
return 0;
}
-static struct ip6t_match hl_match = {
+static struct xt_match hl_match = {
.name = "hl",
+ .family = AF_INET6,
.match = match,
.matchsize = sizeof(struct ip6t_hl_info),
.me = THIS_MODULE,
@@ -57,13 +59,12 @@ static struct ip6t_match hl_match = {
static int __init ip6t_hl_init(void)
{
- return ip6t_register_match(&hl_match);
+ return xt_register_match(&hl_match);
}
static void __exit ip6t_hl_fini(void)
{
- ip6t_unregister_match(&hl_match);
-
+ xt_unregister_match(&hl_match);
}
module_init(ip6t_hl_init);
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c
index 3093c398002..26ac084adef 100644
--- a/net/ipv6/netfilter/ip6t_ipv6header.c
+++ b/net/ipv6/netfilter/ip6t_ipv6header.c
@@ -18,6 +18,7 @@
#include <net/checksum.h>
#include <net/ipv6.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_ipv6header.h>
@@ -140,8 +141,9 @@ ipv6header_checkentry(const char *tablename,
return 1;
}
-static struct ip6t_match ip6t_ipv6header_match = {
+static struct xt_match ip6t_ipv6header_match = {
.name = "ipv6header",
+ .family = AF_INET6,
.match = &ipv6header_match,
.matchsize = sizeof(struct ip6t_ipv6header_info),
.checkentry = &ipv6header_checkentry,
@@ -151,12 +153,12 @@ static struct ip6t_match ip6t_ipv6header_match = {
static int __init ipv6header_init(void)
{
- return ip6t_register_match(&ip6t_ipv6header_match);
+ return xt_register_match(&ip6t_ipv6header_match);
}
static void __exit ipv6header_exit(void)
{
- ip6t_unregister_match(&ip6t_ipv6header_match);
+ xt_unregister_match(&ip6t_ipv6header_match);
}
module_init(ipv6header_init);
diff --git a/net/ipv6/netfilter/ip6t_mh.c b/net/ipv6/netfilter/ip6t_mh.c
new file mode 100644
index 00000000000..2c7efc6a506
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_mh.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * 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.
+ *
+ * Author:
+ * Masahide NAKAMURA @USAGI <masahide.nakamura.cz@hitachi.com>
+ *
+ * Based on net/netfilter/xt_tcpudp.c
+ *
+ */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <net/mip6.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv6/ip6t_mh.h>
+
+MODULE_DESCRIPTION("ip6t_tables match for MH");
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_IP_FIREWALL_USER
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+/* Returns 1 if the type is matched by the range, 0 otherwise */
+static inline int
+type_match(u_int8_t min, u_int8_t max, u_int8_t type, int invert)
+{
+ int ret;
+
+ ret = (type >= min && type <= max) ^ invert;
+ return ret;
+}
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ int *hotdrop)
+{
+ struct ip6_mh _mh, *mh;
+ const struct ip6t_mh *mhinfo = matchinfo;
+
+ /* Must not be a fragment. */
+ if (offset)
+ return 0;
+
+ mh = skb_header_pointer(skb, protoff, sizeof(_mh), &_mh);
+ if (mh == NULL) {
+ /* We've been asked to examine this packet, and we
+ can't. Hence, no choice but to drop. */
+ duprintf("Dropping evil MH tinygram.\n");
+ *hotdrop = 1;
+ return 0;
+ }
+
+ return type_match(mhinfo->types[0], mhinfo->types[1], mh->ip6mh_type,
+ !!(mhinfo->invflags & IP6T_MH_INV_TYPE));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+mh_checkentry(const char *tablename,
+ const void *entry,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int hook_mask)
+{
+ const struct ip6t_mh *mhinfo = matchinfo;
+
+ /* Must specify no unknown invflags */
+ return !(mhinfo->invflags & ~IP6T_MH_INV_MASK);
+}
+
+static struct xt_match mh_match = {
+ .name = "mh",
+ .family = AF_INET6,
+ .checkentry = mh_checkentry,
+ .match = match,
+ .matchsize = sizeof(struct ip6t_mh),
+ .proto = IPPROTO_MH,
+ .me = THIS_MODULE,
+};
+
+static int __init ip6t_mh_init(void)
+{
+ return xt_register_match(&mh_match);
+}
+
+static void __exit ip6t_mh_fini(void)
+{
+ xt_unregister_match(&mh_match);
+}
+
+module_init(ip6t_mh_init);
+module_exit(ip6t_mh_fini);
diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c
index 4eb9bbc4ebc..43738bba00b 100644
--- a/net/ipv6/netfilter/ip6t_owner.c
+++ b/net/ipv6/netfilter/ip6t_owner.c
@@ -16,6 +16,7 @@
#include <linux/netfilter_ipv6/ip6t_owner.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
MODULE_DESCRIPTION("IP6 tables owner matching module");
@@ -69,8 +70,9 @@ checkentry(const char *tablename,
return 1;
}
-static struct ip6t_match owner_match = {
+static struct xt_match owner_match = {
.name = "owner",
+ .family = AF_INET6,
.match = match,
.matchsize = sizeof(struct ip6t_owner_info),
.hooks = (1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING),
@@ -80,12 +82,12 @@ static struct ip6t_match owner_match = {
static int __init ip6t_owner_init(void)
{
- return ip6t_register_match(&owner_match);
+ return xt_register_match(&owner_match);
}
static void __exit ip6t_owner_fini(void)
{
- ip6t_unregister_match(&owner_match);
+ xt_unregister_match(&owner_match);
}
module_init(ip6t_owner_init);
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index 54d7d14134f..81ab00d8c18 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -16,6 +16,7 @@
#include <asm/byteorder.h>
+#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_rt.h>
@@ -221,8 +222,9 @@ checkentry(const char *tablename,
return 1;
}
-static struct ip6t_match rt_match = {
+static struct xt_match rt_match = {
.name = "rt",
+ .family = AF_INET6,
.match = match,
.matchsize = sizeof(struct ip6t_rt),
.checkentry = checkentry,
@@ -231,12 +233,12 @@ static struct ip6t_match rt_match = {
static int __init ip6t_rt_init(void)
{
- return ip6t_register_match(&rt_match);
+ return xt_register_match(&rt_match);
}
static void __exit ip6t_rt_fini(void)
{
- ip6t_unregister_match(&rt_match);
+ xt_unregister_match(&rt_match);
}
module_init(ip6t_rt_init);
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index 2fc07c74dec..112a21d0c6d 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -19,25 +19,6 @@ MODULE_DESCRIPTION("ip6tables filter table");
#define FILTER_VALID_HOOKS ((1 << NF_IP6_LOCAL_IN) | (1 << NF_IP6_FORWARD) | (1 << NF_IP6_LOCAL_OUT))
-/* Standard entry. */
-struct ip6t_standard
-{
- struct ip6t_entry entry;
- struct ip6t_standard_target target;
-};
-
-struct ip6t_error_target
-{
- struct ip6t_entry_target target;
- char errorname[IP6T_FUNCTION_MAXNAMELEN];
-};
-
-struct ip6t_error
-{
- struct ip6t_entry entry;
- struct ip6t_error_target target;
-};
-
static struct
{
struct ip6t_replace repl;
@@ -92,7 +73,7 @@ static struct
}
};
-static struct ip6t_table packet_filter = {
+static struct xt_table packet_filter = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.lock = RW_LOCK_UNLOCKED,
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 6250e86a6dd..5f5aa0e5147 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -29,25 +29,6 @@ MODULE_DESCRIPTION("ip6tables mangle table");
#define DEBUGP(x, args...)
#endif
-/* Standard entry. */
-struct ip6t_standard
-{
- struct ip6t_entry entry;
- struct ip6t_standard_target target;
-};
-
-struct ip6t_error_target
-{
- struct ip6t_entry_target target;
- char errorname[IP6T_FUNCTION_MAXNAMELEN];
-};
-
-struct ip6t_error
-{
- struct ip6t_entry entry;
- struct ip6t_error_target target;
-};
-
static struct
{
struct ip6t_replace repl;
@@ -122,7 +103,7 @@ static struct
}
};
-static struct ip6t_table packet_mangler = {
+static struct xt_table packet_mangler = {
.name = "mangle",
.valid_hooks = MANGLE_VALID_HOOKS,
.lock = RW_LOCK_UNLOCKED,
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index b4154da575c..277bf34638b 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -14,25 +14,6 @@
#define DEBUGP(x, args...)
#endif
-/* Standard entry. */
-struct ip6t_standard
-{
- struct ip6t_entry entry;
- struct ip6t_standard_target target;
-};
-
-struct ip6t_error_target
-{
- struct ip6t_entry_target target;
- char errorname[IP6T_FUNCTION_MAXNAMELEN];
-};
-
-struct ip6t_error
-{
- struct ip6t_entry entry;
- struct ip6t_error_target target;
-};
-
static struct
{
struct ip6t_replace repl;
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 37e5fca923a..d9c15402ba6 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -835,6 +835,8 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
s->nfct_reasm = skb;
s2 = s->next;
+ s->next = NULL;
+
NF_HOOK_THRESH(PF_INET6, hooknum, s, in, out, okfn,
NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
s = s2;
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4ae1b19ada5..c2d8059e754 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -815,7 +815,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (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, 1)) < 0)
goto out;
if (hlimit < 0) {
@@ -1094,10 +1094,19 @@ static void rawv6_close(struct sock *sk, long timeout)
static int rawv6_init_sk(struct sock *sk)
{
- if (inet_sk(sk)->num == IPPROTO_ICMPV6) {
- struct raw6_sock *rp = raw6_sk(sk);
+ struct raw6_sock *rp = raw6_sk(sk);
+
+ switch (inet_sk(sk)->num) {
+ case IPPROTO_ICMPV6:
rp->checksum = 1;
rp->offset = 2;
+ break;
+ case IPPROTO_MH:
+ rp->checksum = 1;
+ rp->offset = 4;
+ break;
+ default:
+ break;
}
return(0);
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 9f80518aacb..19c906f6efa 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -311,12 +311,21 @@ static inline void rt6_probe(struct rt6_info *rt)
static int inline rt6_check_dev(struct rt6_info *rt, int oif)
{
struct net_device *dev = rt->rt6i_dev;
- if (!oif || dev->ifindex == oif)
+ int ret = 0;
+
+ if (!oif)
return 2;
- if ((dev->flags & IFF_LOOPBACK) &&
- rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
- return 1;
- return 0;
+ if (dev->flags & IFF_LOOPBACK) {
+ if (!WARN_ON(rt->rt6i_idev == NULL) &&
+ rt->rt6i_idev->dev->ifindex == oif)
+ ret = 1;
+ else
+ return 0;
+ }
+ if (dev->ifindex == oif)
+ return 2;
+
+ return ret;
}
static int inline rt6_check_neigh(struct rt6_info *rt)
@@ -494,7 +503,7 @@ do { \
goto out; \
pn = fn->parent; \
if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \
- fn = fib6_lookup(pn->subtree, NULL, saddr); \
+ fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr); \
else \
fn = pn; \
if (fn->fn_flags & RTN_RTINFO) \
@@ -2017,6 +2026,7 @@ static inline size_t rt6_nlmsg_size(void)
+ nla_total_size(4) /* RTA_IIF */
+ nla_total_size(4) /* RTA_OIF */
+ nla_total_size(4) /* RTA_PRIORITY */
+ + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
+ nla_total_size(sizeof(struct rta_cacheinfo));
}
@@ -2039,7 +2049,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtm), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
rtm = nlmsg_data(nlh);
rtm->rtm_family = AF_INET6;
@@ -2110,7 +2120,8 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
return nlmsg_end(skb, nlh);
nla_put_failure:
- return nlmsg_cancel(skb, nlh);
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
int rt6_dump_route(struct rt6_info *rt, void *p_arg)
@@ -2221,9 +2232,12 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
goto errout;
err = rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0);
- /* failure implies BUG in rt6_nlmsg_size() */
- BUG_ON(err < 0);
-
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
err = rtnl_notify(skb, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any());
errout:
if (err < 0)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 77b7b091143..47cfeadac6d 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -686,7 +686,8 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
goto done;
dev = t->dev;
}
- err = unregister_netdevice(dev);
+ unregister_netdevice(dev);
+ err = 0;
break;
default:
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index c25e930c2c6..dcb7b00a737 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -265,7 +265,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
if (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, 1)) < 0)
goto failure;
if (saddr == NULL) {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index f52a5c3cc0a..15e5195549c 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -736,7 +736,7 @@ do_udp_sendmsg:
if (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, 1)) < 0)
goto out;
if (hlimit < 0) {
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 5e7d8a7d641..0bc866c0d83 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -25,6 +25,12 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
IP6_ECN_set_ce(inner_iph);
}
+static inline void ip6ip_ecn_decapsulate(struct sk_buff *skb)
+{
+ if (INET_ECN_is_ce(ipv6_get_dsfield(skb->nh.ipv6h)))
+ IP_ECN_set_ce(skb->h.ipiph);
+}
+
/* Add encapsulation header.
*
* The top IP header will be constructed per RFC 2401. The following fields
@@ -40,6 +46,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
+ struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
struct ipv6hdr *iph, *top_iph;
int dsfield;
@@ -52,16 +59,24 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
skb->h.ipv6h = top_iph + 1;
top_iph->version = 6;
- top_iph->priority = iph->priority;
- top_iph->flow_lbl[0] = iph->flow_lbl[0];
- top_iph->flow_lbl[1] = iph->flow_lbl[1];
- top_iph->flow_lbl[2] = iph->flow_lbl[2];
+ if (xdst->route->ops->family == AF_INET6) {
+ top_iph->priority = iph->priority;
+ top_iph->flow_lbl[0] = iph->flow_lbl[0];
+ top_iph->flow_lbl[1] = iph->flow_lbl[1];
+ top_iph->flow_lbl[2] = iph->flow_lbl[2];
+ top_iph->nexthdr = IPPROTO_IPV6;
+ } else {
+ top_iph->priority = 0;
+ top_iph->flow_lbl[0] = 0;
+ top_iph->flow_lbl[1] = 0;
+ top_iph->flow_lbl[2] = 0;
+ top_iph->nexthdr = IPPROTO_IPIP;
+ }
dsfield = ipv6_get_dsfield(top_iph);
dsfield = INET_ECN_encapsulate(dsfield, dsfield);
if (x->props.flags & XFRM_STATE_NOECN)
dsfield &= ~INET_ECN_MASK;
ipv6_change_dsfield(top_iph, 0, dsfield);
- top_iph->nexthdr = IPPROTO_IPV6;
top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
@@ -72,7 +87,8 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
{
int err = -EINVAL;
- if (skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPV6)
+ if (skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPV6
+ && skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPIP)
goto out;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
goto out;
@@ -81,10 +97,16 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
(err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
goto out;
- if (x->props.flags & XFRM_STATE_DECAP_DSCP)
- ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h);
- if (!(x->props.flags & XFRM_STATE_NOECN))
- ipip6_ecn_decapsulate(skb);
+ if (skb->nh.raw[IP6CB(skb)->nhoff] == IPPROTO_IPV6) {
+ if (x->props.flags & XFRM_STATE_DECAP_DSCP)
+ ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h);
+ if (!(x->props.flags & XFRM_STATE_NOECN))
+ ipip6_ecn_decapsulate(skb);
+ } else {
+ if (!(x->props.flags & XFRM_STATE_NOECN))
+ ip6ip_ecn_decapsulate(skb);
+ skb->protocol = htons(ETH_P_IP);
+ }
skb->mac.raw = memmove(skb->data - skb->mac_len,
skb->mac.raw, skb->mac_len);
skb->nh.raw = skb->data;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 8dffd4daae9..59480e92177 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -131,13 +131,11 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
struct dst_entry *dst, *dst_prev;
struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
struct rt6_info *rt = rt0;
- struct in6_addr *remote = &fl->fl6_dst;
- struct in6_addr *local = &fl->fl6_src;
struct flowi fl_tunnel = {
.nl_u = {
.ip6_u = {
- .saddr = *local,
- .daddr = *remote
+ .saddr = fl->fl6_src,
+ .daddr = fl->fl6_dst,
}
}
};
@@ -153,7 +151,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
for (i = 0; i < nx; i++) {
struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops);
struct xfrm_dst *xdst;
- int tunnel = 0;
if (unlikely(dst1 == NULL)) {
err = -ENOBUFS;
@@ -177,19 +174,27 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst1->next = dst_prev;
dst_prev = dst1;
- if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
- remote = __xfrm6_bundle_addr_remote(xfrm[i], remote);
- local = __xfrm6_bundle_addr_local(xfrm[i], local);
- tunnel = 1;
- }
+
__xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]);
trailer_len += xfrm[i]->props.trailer_len;
- if (tunnel) {
- ipv6_addr_copy(&fl_tunnel.fl6_dst, remote);
- ipv6_addr_copy(&fl_tunnel.fl6_src, local);
+ if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) {
+ unsigned short encap_family = xfrm[i]->props.family;
+ switch(encap_family) {
+ case AF_INET:
+ fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
+ fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
+ break;
+ case AF_INET6:
+ ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6);
+ ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6);
+ break;
+ default:
+ BUG_ON(1);
+ }
+
err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
- &fl_tunnel, AF_INET6);
+ &fl_tunnel, encap_family);
if (err)
goto error;
} else
@@ -208,6 +213,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
i = 0;
for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
+ struct xfrm_state_afinfo *afinfo;
dst_prev->xfrm = xfrm[i++];
dst_prev->dev = rt->u.dst.dev;
@@ -224,7 +230,17 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
/* Copy neighbour for reachability confirmation */
dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour);
dst_prev->input = rt->u.dst.input;
- dst_prev->output = xfrm6_output;
+ /* XXX: When IPv4 is implemented as module and can be unloaded,
+ * we should manage reference to xfrm4_output in afinfo->output.
+ * Miyazawa
+ */
+ afinfo = xfrm_state_get_afinfo(dst_prev->xfrm->props.family);
+ if (!afinfo) {
+ dst = *dst_p;
+ goto error;
+ };
+ dst_prev->output = afinfo->output;
+ xfrm_state_put_afinfo(afinfo);
/* Sheit... I remember I did this right. Apparently,
* it was magically lost, so this code needs audit */
x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index 9ddaa9d4153..60ad5f074e0 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -171,6 +171,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = {
.init_tempsel = __xfrm6_init_tempsel,
.tmpl_sort = __xfrm6_tmpl_sort,
.state_sort = __xfrm6_state_sort,
+ .output = xfrm6_output,
};
void __init xfrm6_state_init(void)
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index 76c661566df..89f283c51df 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -2035,19 +2035,27 @@ static void __exit ipx_proto_finito(void)
ipxitf_cleanup();
- unregister_snap_client(pSNAP_datalink);
- pSNAP_datalink = NULL;
+ if (pSNAP_datalink) {
+ unregister_snap_client(pSNAP_datalink);
+ pSNAP_datalink = NULL;
+ }
- unregister_8022_client(p8022_datalink);
- p8022_datalink = NULL;
+ if (p8022_datalink) {
+ unregister_8022_client(p8022_datalink);
+ p8022_datalink = NULL;
+ }
dev_remove_pack(&ipx_8023_packet_type);
- destroy_8023_client(p8023_datalink);
- p8023_datalink = NULL;
+ if (p8023_datalink) {
+ destroy_8023_client(p8023_datalink);
+ p8023_datalink = NULL;
+ }
dev_remove_pack(&ipx_dix_packet_type);
- destroy_EII_client(pEII_datalink);
- pEII_datalink = NULL;
+ if (pEII_datalink) {
+ destroy_EII_client(pEII_datalink);
+ pEII_datalink = NULL;
+ }
proto_unregister(&ipx_proto);
sock_unregister(ipx_family_ops.family);
diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c
index 197e3e7ed7e..75e39ea599d 100644
--- a/net/irda/ircomm/ircomm_tty_ioctl.c
+++ b/net/irda/ircomm/ircomm_tty_ioctl.c
@@ -146,7 +146,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
* do something rational.
*/
void ircomm_tty_set_termios(struct tty_struct *tty,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned int cflag = tty->termios->c_cflag;
diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
index b1ee99a59c0..2a571b43ebe 100644
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -91,6 +91,12 @@ struct ias_object *irias_new_object( char *name, int id)
obj->magic = IAS_OBJECT_MAGIC;
obj->name = strndup(name, IAS_MAX_CLASSNAME);
+ if (!obj->name) {
+ IRDA_WARNING("%s(), Unable to allocate name!\n",
+ __FUNCTION__);
+ kfree(obj);
+ return NULL;
+ }
obj->id = id;
/* Locking notes : the attrib spinlock has lower precendence
@@ -101,6 +107,7 @@ struct ias_object *irias_new_object( char *name, int id)
if (obj->attribs == NULL) {
IRDA_WARNING("%s(), Unable to allocate attribs!\n",
__FUNCTION__);
+ kfree(obj->name);
kfree(obj);
return NULL;
}
@@ -357,6 +364,15 @@ void irias_add_integer_attrib(struct ias_object *obj, char *name, int value,
/* Insert value */
attrib->value = irias_new_integer_value(value);
+ if (!attrib->name || !attrib->value) {
+ IRDA_WARNING("%s: Unable to allocate attribute!\n",
+ __FUNCTION__);
+ if (attrib->value)
+ irias_delete_value(attrib->value);
+ kfree(attrib->name);
+ kfree(attrib);
+ return;
+ }
irias_add_attrib(obj, attrib, owner);
}
@@ -391,6 +407,15 @@ void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
attrib->value = irias_new_octseq_value( octets, len);
+ if (!attrib->name || !attrib->value) {
+ IRDA_WARNING("%s: Unable to allocate attribute!\n",
+ __FUNCTION__);
+ if (attrib->value)
+ irias_delete_value(attrib->value);
+ kfree(attrib->name);
+ kfree(attrib);
+ return;
+ }
irias_add_attrib(obj, attrib, owner);
}
@@ -424,6 +449,15 @@ void irias_add_string_attrib(struct ias_object *obj, char *name, char *value,
attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
attrib->value = irias_new_string_value(value);
+ if (!attrib->name || !attrib->value) {
+ IRDA_WARNING("%s: Unable to allocate attribute!\n",
+ __FUNCTION__);
+ if (attrib->value)
+ irias_delete_value(attrib->value);
+ kfree(attrib->name);
+ kfree(attrib);
+ return;
+ }
irias_add_attrib(obj, attrib, owner);
}
@@ -473,6 +507,12 @@ struct ias_value *irias_new_string_value(char *string)
value->type = IAS_STRING;
value->charset = CS_ASCII;
value->t.string = strndup(string, IAS_MAX_STRING);
+ if (!value->t.string) {
+ IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+ kfree(value);
+ return NULL;
+ }
+
value->len = strlen(value->t.string);
return value;
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index 2bb04ac0932..310776dd610 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -144,12 +144,18 @@ static int __init irlan_init(void)
/* Register with IrLMP as a client */
ckey = irlmp_register_client(hints, &irlan_client_discovery_indication,
NULL, NULL);
-
+ if (!ckey)
+ goto err_ckey;
+
/* Register with IrLMP as a service */
- skey = irlmp_register_service(hints);
+ skey = irlmp_register_service(hints);
+ if (!skey)
+ goto err_skey;
/* Start the master IrLAN instance (the only one for now) */
- new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY);
+ new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY);
+ if (!new)
+ goto err_open;
/* The master will only open its (listen) control TSAP */
irlan_provider_open_ctrl_tsap(new);
@@ -158,6 +164,17 @@ static int __init irlan_init(void)
irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
return 0;
+
+err_open:
+ irlmp_unregister_service(skey);
+err_skey:
+ irlmp_unregister_client(ckey);
+err_ckey:
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("irlan", proc_irda);
+#endif /* CONFIG_PROC_FS */
+
+ return -ENOMEM;
}
static void __exit irlan_cleanup(void)
diff --git a/net/iucv/Kconfig b/net/iucv/Kconfig
new file mode 100644
index 00000000000..f8fcc3d1032
--- /dev/null
+++ b/net/iucv/Kconfig
@@ -0,0 +1,15 @@
+config IUCV
+ tristate "IUCV support (VM only)"
+ depends on S390
+ help
+ Select this option if you want to use inter-user communication under
+ VM or VIF sockets. If you run on z/VM, say "Y" to enable a fast
+ communication link between VM guests.
+
+config AFIUCV
+ tristate "AF_IUCV support (VM only)"
+ depends on IUCV
+ help
+ Select this option if you want to use inter-user communication under
+ VM or VIF sockets. If you run on z/VM, say "Y" to enable a fast
+ communication link between VM guests.
diff --git a/net/iucv/Makefile b/net/iucv/Makefile
new file mode 100644
index 00000000000..7bfdc853267
--- /dev/null
+++ b/net/iucv/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for IUCV
+#
+
+obj-$(CONFIG_IUCV) += iucv.o
+obj-$(CONFIG_AFIUCV) += af_iucv.o
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
new file mode 100644
index 00000000000..acc94214bde
--- /dev/null
+++ b/net/iucv/af_iucv.c
@@ -0,0 +1,1077 @@
+/*
+ * linux/net/iucv/af_iucv.c
+ *
+ * IUCV protocol stack for Linux on zSeries
+ *
+ * Copyright 2006 IBM Corporation
+ *
+ * Author(s): Jennifer Hunt <jenhunt@us.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <net/sock.h>
+#include <asm/ebcdic.h>
+#include <asm/cpcmd.h>
+#include <linux/kmod.h>
+
+#include <net/iucv/iucv.h>
+#include <net/iucv/af_iucv.h>
+
+#define CONFIG_IUCV_SOCK_DEBUG 1
+
+#define IPRMDATA 0x80
+#define VERSION "1.0"
+
+static char iucv_userid[80];
+
+static struct proto_ops iucv_sock_ops;
+
+static struct proto iucv_proto = {
+ .name = "AF_IUCV",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct iucv_sock),
+};
+
+/* Call Back functions */
+static void iucv_callback_rx(struct iucv_path *, struct iucv_message *);
+static void iucv_callback_txdone(struct iucv_path *, struct iucv_message *);
+static void iucv_callback_connack(struct iucv_path *, u8 ipuser[16]);
+static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
+static void iucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);
+
+static struct iucv_sock_list iucv_sk_list = {
+ .lock = RW_LOCK_UNLOCKED,
+ .autobind_name = ATOMIC_INIT(0)
+};
+
+static struct iucv_handler af_iucv_handler = {
+ .path_pending = iucv_callback_connreq,
+ .path_complete = iucv_callback_connack,
+ .path_severed = iucv_callback_connrej,
+ .message_pending = iucv_callback_rx,
+ .message_complete = iucv_callback_txdone
+};
+
+static inline void high_nmcpy(unsigned char *dst, char *src)
+{
+ memcpy(dst, src, 8);
+}
+
+static inline void low_nmcpy(unsigned char *dst, char *src)
+{
+ memcpy(&dst[8], src, 8);
+}
+
+/* Timers */
+static void iucv_sock_timeout(unsigned long arg)
+{
+ struct sock *sk = (struct sock *)arg;
+
+ bh_lock_sock(sk);
+ sk->sk_err = ETIMEDOUT;
+ sk->sk_state_change(sk);
+ bh_unlock_sock(sk);
+
+ iucv_sock_kill(sk);
+ sock_put(sk);
+}
+
+static void iucv_sock_clear_timer(struct sock *sk)
+{
+ sk_stop_timer(sk, &sk->sk_timer);
+}
+
+static void iucv_sock_init_timer(struct sock *sk)
+{
+ init_timer(&sk->sk_timer);
+ sk->sk_timer.function = iucv_sock_timeout;
+ sk->sk_timer.data = (unsigned long)sk;
+}
+
+static struct sock *__iucv_get_sock_by_name(char *nm)
+{
+ struct sock *sk;
+ struct hlist_node *node;
+
+ sk_for_each(sk, node, &iucv_sk_list.head)
+ if (!memcmp(&iucv_sk(sk)->src_name, nm, 8))
+ return sk;
+
+ return NULL;
+}
+
+static void iucv_sock_destruct(struct sock *sk)
+{
+ skb_queue_purge(&sk->sk_receive_queue);
+ skb_queue_purge(&sk->sk_write_queue);
+}
+
+/* Cleanup Listen */
+static void iucv_sock_cleanup_listen(struct sock *parent)
+{
+ struct sock *sk;
+
+ /* Close non-accepted connections */
+ while ((sk = iucv_accept_dequeue(parent, NULL))) {
+ iucv_sock_close(sk);
+ iucv_sock_kill(sk);
+ }
+
+ parent->sk_state = IUCV_CLOSED;
+ sock_set_flag(parent, SOCK_ZAPPED);
+}
+
+/* Kill socket */
+static void iucv_sock_kill(struct sock *sk)
+{
+ if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
+ return;
+
+ iucv_sock_unlink(&iucv_sk_list, sk);
+ sock_set_flag(sk, SOCK_DEAD);
+ sock_put(sk);
+}
+
+/* Close an IUCV socket */
+static void iucv_sock_close(struct sock *sk)
+{
+ unsigned char user_data[16];
+ struct iucv_sock *iucv = iucv_sk(sk);
+ int err;
+
+ iucv_sock_clear_timer(sk);
+ lock_sock(sk);
+
+ switch(sk->sk_state) {
+ case IUCV_LISTEN:
+ iucv_sock_cleanup_listen(sk);
+ break;
+
+ case IUCV_CONNECTED:
+ case IUCV_DISCONN:
+ err = 0;
+ if (iucv->path) {
+ low_nmcpy(user_data, iucv->src_name);
+ high_nmcpy(user_data, iucv->dst_name);
+ ASCEBC(user_data, sizeof(user_data));
+ err = iucv_path_sever(iucv->path, user_data);
+ iucv_path_free(iucv->path);
+ iucv->path = NULL;
+ }
+
+ sk->sk_state = IUCV_CLOSED;
+ sk->sk_state_change(sk);
+ sk->sk_err = ECONNRESET;
+ sk->sk_state_change(sk);
+
+ skb_queue_purge(&iucv->send_skb_q);
+
+ sock_set_flag(sk, SOCK_ZAPPED);
+ break;
+
+ default:
+ sock_set_flag(sk, SOCK_ZAPPED);
+ break;
+ };
+
+ release_sock(sk);
+ iucv_sock_kill(sk);
+}
+
+static void iucv_sock_init(struct sock *sk, struct sock *parent)
+{
+ if (parent)
+ sk->sk_type = parent->sk_type;
+}
+
+static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio)
+{
+ struct sock *sk;
+
+ sk = sk_alloc(PF_IUCV, prio, &iucv_proto, 1);
+ if (!sk)
+ return NULL;
+
+ sock_init_data(sock, sk);
+ INIT_LIST_HEAD(&iucv_sk(sk)->accept_q);
+ skb_queue_head_init(&iucv_sk(sk)->send_skb_q);
+ iucv_sk(sk)->send_tag = 0;
+
+ sk->sk_destruct = iucv_sock_destruct;
+ sk->sk_sndtimeo = IUCV_CONN_TIMEOUT;
+ sk->sk_allocation = GFP_DMA;
+
+ sock_reset_flag(sk, SOCK_ZAPPED);
+
+ sk->sk_protocol = proto;
+ sk->sk_state = IUCV_OPEN;
+
+ iucv_sock_init_timer(sk);
+
+ iucv_sock_link(&iucv_sk_list, sk);
+ return sk;
+}
+
+/* Create an IUCV socket */
+static int iucv_sock_create(struct socket *sock, int protocol)
+{
+ struct sock *sk;
+
+ if (sock->type != SOCK_STREAM)
+ return -ESOCKTNOSUPPORT;
+
+ sock->state = SS_UNCONNECTED;
+ sock->ops = &iucv_sock_ops;
+
+ sk = iucv_sock_alloc(sock, protocol, GFP_KERNEL);
+ if (!sk)
+ return -ENOMEM;
+
+ iucv_sock_init(sk, NULL);
+
+ return 0;
+}
+
+void iucv_sock_link(struct iucv_sock_list *l, struct sock *sk)
+{
+ write_lock_bh(&l->lock);
+ sk_add_node(sk, &l->head);
+ write_unlock_bh(&l->lock);
+}
+
+void iucv_sock_unlink(struct iucv_sock_list *l, struct sock *sk)
+{
+ write_lock_bh(&l->lock);
+ sk_del_node_init(sk);
+ write_unlock_bh(&l->lock);
+}
+
+void iucv_accept_enqueue(struct sock *parent, struct sock *sk)
+{
+ sock_hold(sk);
+ list_add_tail(&iucv_sk(sk)->accept_q, &iucv_sk(parent)->accept_q);
+ iucv_sk(sk)->parent = parent;
+ parent->sk_ack_backlog++;
+}
+
+void iucv_accept_unlink(struct sock *sk)
+{
+ list_del_init(&iucv_sk(sk)->accept_q);
+ iucv_sk(sk)->parent->sk_ack_backlog--;
+ iucv_sk(sk)->parent = NULL;
+ sock_put(sk);
+}
+
+struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock)
+{
+ struct iucv_sock *isk, *n;
+ struct sock *sk;
+
+ list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q){
+ sk = (struct sock *) isk;
+ lock_sock(sk);
+
+ if (sk->sk_state == IUCV_CLOSED) {
+ release_sock(sk);
+ iucv_accept_unlink(sk);
+ continue;
+ }
+
+ if (sk->sk_state == IUCV_CONNECTED ||
+ sk->sk_state == IUCV_SEVERED ||
+ !newsock) {
+ iucv_accept_unlink(sk);
+ if (newsock)
+ sock_graft(sk, newsock);
+
+ if (sk->sk_state == IUCV_SEVERED)
+ sk->sk_state = IUCV_DISCONN;
+
+ release_sock(sk);
+ return sk;
+ }
+
+ release_sock(sk);
+ }
+ return NULL;
+}
+
+int iucv_sock_wait_state(struct sock *sk, int state, int state2,
+ unsigned long timeo)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int err = 0;
+
+ add_wait_queue(sk->sk_sleep, &wait);
+ while (sk->sk_state != state && sk->sk_state != state2) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (!timeo) {
+ err = -EAGAIN;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ err = sock_intr_errno(timeo);
+ break;
+ }
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
+
+ err = sock_error(sk);
+ if (err)
+ break;
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(sk->sk_sleep, &wait);
+ return err;
+}
+
+/* Bind an unbound socket */
+static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr,
+ int addr_len)
+{
+ struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr;
+ struct sock *sk = sock->sk;
+ struct iucv_sock *iucv;
+ int err;
+
+ /* Verify the input sockaddr */
+ if (!addr || addr->sa_family != AF_IUCV)
+ return -EINVAL;
+
+ lock_sock(sk);
+ if (sk->sk_state != IUCV_OPEN) {
+ err = -EBADFD;
+ goto done;
+ }
+
+ write_lock_bh(&iucv_sk_list.lock);
+
+ iucv = iucv_sk(sk);
+ if (__iucv_get_sock_by_name(sa->siucv_name)) {
+ err = -EADDRINUSE;
+ goto done_unlock;
+ }
+ if (iucv->path) {
+ err = 0;
+ goto done_unlock;
+ }
+
+ /* Bind the socket */
+ memcpy(iucv->src_name, sa->siucv_name, 8);
+
+ /* Copy the user id */
+ memcpy(iucv->src_user_id, iucv_userid, 8);
+ sk->sk_state = IUCV_BOUND;
+ err = 0;
+
+done_unlock:
+ /* Release the socket list lock */
+ write_unlock_bh(&iucv_sk_list.lock);
+done:
+ release_sock(sk);
+ return err;
+}
+
+/* Automatically bind an unbound socket */
+static int iucv_sock_autobind(struct sock *sk)
+{
+ struct iucv_sock *iucv = iucv_sk(sk);
+ char query_buffer[80];
+ char name[12];
+ int err = 0;
+
+ /* Set the userid and name */
+ cpcmd("QUERY USERID", query_buffer, sizeof(query_buffer), &err);
+ if (unlikely(err))
+ return -EPROTO;
+
+ memcpy(iucv->src_user_id, query_buffer, 8);
+
+ write_lock_bh(&iucv_sk_list.lock);
+
+ sprintf(name, "%08x", atomic_inc_return(&iucv_sk_list.autobind_name));
+ while (__iucv_get_sock_by_name(name)) {
+ sprintf(name, "%08x",
+ atomic_inc_return(&iucv_sk_list.autobind_name));
+ }
+
+ write_unlock_bh(&iucv_sk_list.lock);
+
+ memcpy(&iucv->src_name, name, 8);
+
+ return err;
+}
+
+/* Connect an unconnected socket */
+static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
+ int alen, int flags)
+{
+ struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr;
+ struct sock *sk = sock->sk;
+ struct iucv_sock *iucv;
+ unsigned char user_data[16];
+ int err;
+
+ if (addr->sa_family != AF_IUCV || alen < sizeof(struct sockaddr_iucv))
+ return -EINVAL;
+
+ if (sk->sk_state != IUCV_OPEN && sk->sk_state != IUCV_BOUND)
+ return -EBADFD;
+
+ if (sk->sk_type != SOCK_STREAM)
+ return -EINVAL;
+
+ iucv = iucv_sk(sk);
+
+ if (sk->sk_state == IUCV_OPEN) {
+ err = iucv_sock_autobind(sk);
+ if (unlikely(err))
+ return err;
+ }
+
+ lock_sock(sk);
+
+ /* Set the destination information */
+ memcpy(iucv_sk(sk)->dst_user_id, sa->siucv_user_id, 8);
+ memcpy(iucv_sk(sk)->dst_name, sa->siucv_name, 8);
+
+ high_nmcpy(user_data, sa->siucv_name);
+ low_nmcpy(user_data, iucv_sk(sk)->src_name);
+ ASCEBC(user_data, sizeof(user_data));
+
+ iucv = iucv_sk(sk);
+ /* Create path. */
+ iucv->path = iucv_path_alloc(IUCV_QUEUELEN_DEFAULT,
+ IPRMDATA, GFP_KERNEL);
+ err = iucv_path_connect(iucv->path, &af_iucv_handler,
+ sa->siucv_user_id, NULL, user_data, sk);
+ if (err) {
+ iucv_path_free(iucv->path);
+ iucv->path = NULL;
+ err = -ECONNREFUSED;
+ goto done;
+ }
+
+ if (sk->sk_state != IUCV_CONNECTED) {
+ err = iucv_sock_wait_state(sk, IUCV_CONNECTED, IUCV_DISCONN,
+ sock_sndtimeo(sk, flags & O_NONBLOCK));
+ }
+
+ if (sk->sk_state == IUCV_DISCONN) {
+ release_sock(sk);
+ return -ECONNREFUSED;
+ }
+done:
+ release_sock(sk);
+ return err;
+}
+
+/* Move a socket into listening state. */
+static int iucv_sock_listen(struct socket *sock, int backlog)
+{
+ struct sock *sk = sock->sk;
+ int err;
+
+ lock_sock(sk);
+
+ err = -EINVAL;
+ if (sk->sk_state != IUCV_BOUND || sock->type != SOCK_STREAM)
+ goto done;
+
+ sk->sk_max_ack_backlog = backlog;
+ sk->sk_ack_backlog = 0;
+ sk->sk_state = IUCV_LISTEN;
+ err = 0;
+
+done:
+ release_sock(sk);
+ return err;
+}
+
+/* Accept a pending connection */
+static int iucv_sock_accept(struct socket *sock, struct socket *newsock,
+ int flags)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct sock *sk = sock->sk, *nsk;
+ long timeo;
+ int err = 0;
+
+ lock_sock(sk);
+
+ if (sk->sk_state != IUCV_LISTEN) {
+ err = -EBADFD;
+ goto done;
+ }
+
+ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+
+ /* Wait for an incoming connection */
+ add_wait_queue_exclusive(sk->sk_sleep, &wait);
+ while (!(nsk = iucv_accept_dequeue(sk, newsock))){
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!timeo) {
+ err = -EAGAIN;
+ break;
+ }
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
+
+ if (sk->sk_state != IUCV_LISTEN) {
+ err = -EBADFD;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ err = sock_intr_errno(timeo);
+ break;
+ }
+ }
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(sk->sk_sleep, &wait);
+
+ if (err)
+ goto done;
+
+ newsock->state = SS_CONNECTED;
+
+done:
+ release_sock(sk);
+ return err;
+}
+
+static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr,
+ int *len, int peer)
+{
+ struct sockaddr_iucv *siucv = (struct sockaddr_iucv *) addr;
+ struct sock *sk = sock->sk;
+
+ addr->sa_family = AF_IUCV;
+ *len = sizeof(struct sockaddr_iucv);
+
+ if (peer) {
+ memcpy(siucv->siucv_user_id, iucv_sk(sk)->dst_user_id, 8);
+ memcpy(siucv->siucv_name, &iucv_sk(sk)->dst_name, 8);
+ } else {
+ memcpy(siucv->siucv_user_id, iucv_sk(sk)->src_user_id, 8);
+ memcpy(siucv->siucv_name, iucv_sk(sk)->src_name, 8);
+ }
+ memset(&siucv->siucv_port, 0, sizeof(siucv->siucv_port));
+ memset(&siucv->siucv_addr, 0, sizeof(siucv->siucv_addr));
+ memset(siucv->siucv_nodeid, 0, sizeof(siucv->siucv_nodeid));
+
+ return 0;
+}
+
+static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t len)
+{
+ struct sock *sk = sock->sk;
+ struct iucv_sock *iucv = iucv_sk(sk);
+ struct sk_buff *skb;
+ struct iucv_message txmsg;
+ int err;
+
+ err = sock_error(sk);
+ if (err)
+ return err;
+
+ if (msg->msg_flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
+ lock_sock(sk);
+
+ if (sk->sk_shutdown & SEND_SHUTDOWN) {
+ err = -EPIPE;
+ goto out;
+ }
+
+ if (sk->sk_state == IUCV_CONNECTED){
+ if(!(skb = sock_alloc_send_skb(sk, len,
+ msg->msg_flags & MSG_DONTWAIT,
+ &err)))
+ return err;
+
+ if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)){
+ err = -EFAULT;
+ goto fail;
+ }
+
+ txmsg.class = 0;
+ txmsg.tag = iucv->send_tag++;
+ memcpy(skb->cb, &txmsg.tag, 4);
+ skb_queue_tail(&iucv->send_skb_q, skb);
+ err = iucv_message_send(iucv->path, &txmsg, 0, 0,
+ (void *) skb->data, skb->len);
+ if (err) {
+ if (err == 3)
+ printk(KERN_ERR "AF_IUCV msg limit exceeded\n");
+ skb_unlink(skb, &iucv->send_skb_q);
+ err = -EPIPE;
+ goto fail;
+ }
+
+ } else {
+ err = -ENOTCONN;
+ goto out;
+ }
+
+ release_sock(sk);
+ return len;
+
+fail:
+ kfree_skb(skb);
+out:
+ release_sock(sk);
+ return err;
+}
+
+static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t len, int flags)
+{
+ int noblock = flags & MSG_DONTWAIT;
+ struct sock *sk = sock->sk;
+ int target, copied = 0;
+ struct sk_buff *skb;
+ int err = 0;
+
+ if (flags & (MSG_OOB))
+ return -EOPNOTSUPP;
+
+ target = sock_rcvlowat(sk, flags & MSG_WAITALL, len);
+
+ skb = skb_recv_datagram(sk, flags, noblock, &err);
+ if (!skb) {
+ if (sk->sk_shutdown & RCV_SHUTDOWN)
+ return 0;
+ return err;
+ }
+
+ copied = min_t(unsigned int, skb->len, len);
+
+ if (memcpy_toiovec(msg->msg_iov, skb->data, copied)) {
+ skb_queue_head(&sk->sk_receive_queue, skb);
+ if (copied == 0)
+ return -EFAULT;
+ }
+
+ len -= copied;
+
+ /* Mark read part of skb as used */
+ if (!(flags & MSG_PEEK)) {
+ skb_pull(skb, copied);
+
+ if (skb->len) {
+ skb_queue_head(&sk->sk_receive_queue, skb);
+ goto done;
+ }
+
+ kfree_skb(skb);
+ } else
+ skb_queue_head(&sk->sk_receive_queue, skb);
+
+done:
+ return err ? : copied;
+}
+
+static inline unsigned int iucv_accept_poll(struct sock *parent)
+{
+ struct iucv_sock *isk, *n;
+ struct sock *sk;
+
+ list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q){
+ sk = (struct sock *) isk;
+
+ if (sk->sk_state == IUCV_CONNECTED)
+ return POLLIN | POLLRDNORM;
+ }
+
+ return 0;
+}
+
+unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
+ poll_table *wait)
+{
+ struct sock *sk = sock->sk;
+ unsigned int mask = 0;
+
+ poll_wait(file, sk->sk_sleep, wait);
+
+ if (sk->sk_state == IUCV_LISTEN)
+ return iucv_accept_poll(sk);
+
+ if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
+ mask |= POLLERR;
+
+ if (sk->sk_shutdown & RCV_SHUTDOWN)
+ mask |= POLLRDHUP;
+
+ if (sk->sk_shutdown == SHUTDOWN_MASK)
+ mask |= POLLHUP;
+
+ if (!skb_queue_empty(&sk->sk_receive_queue) ||
+ (sk->sk_shutdown & RCV_SHUTDOWN))
+ mask |= POLLIN | POLLRDNORM;
+
+ if (sk->sk_state == IUCV_CLOSED)
+ mask |= POLLHUP;
+
+ if (sock_writeable(sk))
+ mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+ else
+ set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+
+ return mask;
+}
+
+static int iucv_sock_shutdown(struct socket *sock, int how)
+{
+ struct sock *sk = sock->sk;
+ struct iucv_sock *iucv = iucv_sk(sk);
+ struct iucv_message txmsg;
+ int err = 0;
+ u8 prmmsg[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+ how++;
+
+ if ((how & ~SHUTDOWN_MASK) || !how)
+ return -EINVAL;
+
+ lock_sock(sk);
+ switch(sk->sk_state) {
+ case IUCV_CLOSED:
+ err = -ENOTCONN;
+ goto fail;
+
+ default:
+ sk->sk_shutdown |= how;
+ break;
+ }
+
+ if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
+ txmsg.class = 0;
+ txmsg.tag = 0;
+ err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0,
+ (void *) prmmsg, 8);
+ if (err) {
+ switch(err) {
+ case 1:
+ err = -ENOTCONN;
+ break;
+ case 2:
+ err = -ECONNRESET;
+ break;
+ default:
+ err = -ENOTCONN;
+ break;
+ }
+ }
+ }
+
+ if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
+ err = iucv_path_quiesce(iucv_sk(sk)->path, NULL);
+ if (err)
+ err = -ENOTCONN;
+
+ skb_queue_purge(&sk->sk_receive_queue);
+ }
+
+ /* Wake up anyone sleeping in poll */
+ sk->sk_state_change(sk);
+
+fail:
+ release_sock(sk);
+ return err;
+}
+
+static int iucv_sock_release(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+ int err = 0;
+
+ if (!sk)
+ return 0;
+
+ iucv_sock_close(sk);
+
+ /* Unregister with IUCV base support */
+ if (iucv_sk(sk)->path) {
+ iucv_path_sever(iucv_sk(sk)->path, NULL);
+ iucv_path_free(iucv_sk(sk)->path);
+ iucv_sk(sk)->path = NULL;
+ }
+
+ if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime){
+ lock_sock(sk);
+ err = iucv_sock_wait_state(sk, IUCV_CLOSED, 0,
+ sk->sk_lingertime);
+ release_sock(sk);
+ }
+
+ sock_orphan(sk);
+ iucv_sock_kill(sk);
+ return err;
+}
+
+/* Callback wrappers - called from iucv base support */
+static int iucv_callback_connreq(struct iucv_path *path,
+ u8 ipvmid[8], u8 ipuser[16])
+{
+ unsigned char user_data[16];
+ unsigned char nuser_data[16];
+ unsigned char src_name[8];
+ struct hlist_node *node;
+ struct sock *sk, *nsk;
+ struct iucv_sock *iucv, *niucv;
+ int err;
+
+ memcpy(src_name, ipuser, 8);
+ EBCASC(src_name, 8);
+ /* Find out if this path belongs to af_iucv. */
+ read_lock(&iucv_sk_list.lock);
+ iucv = NULL;
+ sk_for_each(sk, node, &iucv_sk_list.head)
+ if (sk->sk_state == IUCV_LISTEN &&
+ !memcmp(&iucv_sk(sk)->src_name, src_name, 8)) {
+ /*
+ * Found a listening socket with
+ * src_name == ipuser[0-7].
+ */
+ iucv = iucv_sk(sk);
+ break;
+ }
+ read_unlock(&iucv_sk_list.lock);
+ if (!iucv)
+ /* No socket found, not one of our paths. */
+ return -EINVAL;
+
+ bh_lock_sock(sk);
+
+ /* Check if parent socket is listening */
+ low_nmcpy(user_data, iucv->src_name);
+ high_nmcpy(user_data, iucv->dst_name);
+ ASCEBC(user_data, sizeof(user_data));
+ if (sk->sk_state != IUCV_LISTEN) {
+ err = iucv_path_sever(path, user_data);
+ goto fail;
+ }
+
+ /* Check for backlog size */
+ if (sk_acceptq_is_full(sk)) {
+ err = iucv_path_sever(path, user_data);
+ goto fail;
+ }
+
+ /* Create the new socket */
+ nsk = iucv_sock_alloc(NULL, SOCK_STREAM, GFP_ATOMIC);
+ if (!nsk){
+ err = iucv_path_sever(path, user_data);
+ goto fail;
+ }
+
+ niucv = iucv_sk(nsk);
+ iucv_sock_init(nsk, sk);
+
+ /* Set the new iucv_sock */
+ memcpy(niucv->dst_name, ipuser + 8, 8);
+ EBCASC(niucv->dst_name, 8);
+ memcpy(niucv->dst_user_id, ipvmid, 8);
+ memcpy(niucv->src_name, iucv->src_name, 8);
+ memcpy(niucv->src_user_id, iucv->src_user_id, 8);
+ niucv->path = path;
+
+ /* Call iucv_accept */
+ high_nmcpy(nuser_data, ipuser + 8);
+ memcpy(nuser_data + 8, niucv->src_name, 8);
+ ASCEBC(nuser_data + 8, 8);
+
+ path->msglim = IUCV_QUEUELEN_DEFAULT;
+ err = iucv_path_accept(path, &af_iucv_handler, nuser_data, nsk);
+ if (err){
+ err = iucv_path_sever(path, user_data);
+ goto fail;
+ }
+
+ iucv_accept_enqueue(sk, nsk);
+
+ /* Wake up accept */
+ nsk->sk_state = IUCV_CONNECTED;
+ sk->sk_data_ready(sk, 1);
+ err = 0;
+fail:
+ bh_unlock_sock(sk);
+ return 0;
+}
+
+static void iucv_callback_connack(struct iucv_path *path, u8 ipuser[16])
+{
+ struct sock *sk = path->private;
+
+ sk->sk_state = IUCV_CONNECTED;
+ sk->sk_state_change(sk);
+}
+
+static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
+{
+ struct sock *sk = path->private;
+ struct sk_buff *skb;
+ int rc;
+
+ if (sk->sk_shutdown & RCV_SHUTDOWN)
+ return;
+
+ skb = alloc_skb(msg->length, GFP_ATOMIC | GFP_DMA);
+ if (!skb) {
+ iucv_message_reject(path, msg);
+ return;
+ }
+
+ if (msg->flags & IPRMDATA) {
+ skb->data = NULL;
+ skb->len = 0;
+ } else {
+ rc = iucv_message_receive(path, msg, 0, skb->data,
+ msg->length, NULL);
+ if (rc) {
+ kfree_skb(skb);
+ return;
+ }
+
+ skb->h.raw = skb->data;
+ skb->nh.raw = skb->data;
+ skb->len = msg->length;
+ }
+
+ if (sock_queue_rcv_skb(sk, skb))
+ kfree_skb(skb);
+}
+
+static void iucv_callback_txdone(struct iucv_path *path,
+ struct iucv_message *msg)
+{
+ struct sock *sk = path->private;
+ struct sk_buff *this;
+ struct sk_buff_head *list = &iucv_sk(sk)->send_skb_q;
+ struct sk_buff *list_skb = list->next;
+ unsigned long flags;
+
+ spin_lock_irqsave(&list->lock, flags);
+
+ do {
+ this = list_skb;
+ list_skb = list_skb->next;
+ } while (memcmp(&msg->tag, this->cb, 4));
+
+ spin_unlock_irqrestore(&list->lock, flags);
+
+ skb_unlink(this, &iucv_sk(sk)->send_skb_q);
+ kfree_skb(this);
+}
+
+static void iucv_callback_connrej(struct iucv_path *path, u8 ipuser[16])
+{
+ struct sock *sk = path->private;
+
+ if (!list_empty(&iucv_sk(sk)->accept_q))
+ sk->sk_state = IUCV_SEVERED;
+ else
+ sk->sk_state = IUCV_DISCONN;
+
+ sk->sk_state_change(sk);
+}
+
+static struct proto_ops iucv_sock_ops = {
+ .family = PF_IUCV,
+ .owner = THIS_MODULE,
+ .release = iucv_sock_release,
+ .bind = iucv_sock_bind,
+ .connect = iucv_sock_connect,
+ .listen = iucv_sock_listen,
+ .accept = iucv_sock_accept,
+ .getname = iucv_sock_getname,
+ .sendmsg = iucv_sock_sendmsg,
+ .recvmsg = iucv_sock_recvmsg,
+ .poll = iucv_sock_poll,
+ .ioctl = sock_no_ioctl,
+ .mmap = sock_no_mmap,
+ .socketpair = sock_no_socketpair,
+ .shutdown = iucv_sock_shutdown,
+ .setsockopt = sock_no_setsockopt,
+ .getsockopt = sock_no_getsockopt
+};
+
+static struct net_proto_family iucv_sock_family_ops = {
+ .family = AF_IUCV,
+ .owner = THIS_MODULE,
+ .create = iucv_sock_create,
+};
+
+static int afiucv_init(void)
+{
+ int err;
+
+ if (!MACHINE_IS_VM) {
+ printk(KERN_ERR "AF_IUCV connection needs VM as base\n");
+ err = -EPROTONOSUPPORT;
+ goto out;
+ }
+ cpcmd("QUERY USERID", iucv_userid, sizeof(iucv_userid), &err);
+ if (unlikely(err)) {
+ printk(KERN_ERR "AF_IUCV needs the VM userid\n");
+ err = -EPROTONOSUPPORT;
+ goto out;
+ }
+
+ err = iucv_register(&af_iucv_handler, 0);
+ if (err)
+ goto out;
+ err = proto_register(&iucv_proto, 0);
+ if (err)
+ goto out_iucv;
+ err = sock_register(&iucv_sock_family_ops);
+ if (err)
+ goto out_proto;
+ printk(KERN_INFO "AF_IUCV lowlevel driver initialized\n");
+ return 0;
+
+out_proto:
+ proto_unregister(&iucv_proto);
+out_iucv:
+ iucv_unregister(&af_iucv_handler, 0);
+out:
+ return err;
+}
+
+static void __exit afiucv_exit(void)
+{
+ sock_unregister(PF_IUCV);
+ proto_unregister(&iucv_proto);
+ iucv_unregister(&af_iucv_handler, 0);
+
+ printk(KERN_INFO "AF_IUCV lowlevel driver unloaded\n");
+}
+
+module_init(afiucv_init);
+module_exit(afiucv_exit);
+
+MODULE_AUTHOR("Jennifer Hunt <jenhunt@us.ibm.com>");
+MODULE_DESCRIPTION("IUCV Sockets ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETPROTO(PF_IUCV);
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
new file mode 100644
index 00000000000..1b10d576f22
--- /dev/null
+++ b/net/iucv/iucv.c
@@ -0,0 +1,1619 @@
+/*
+ * IUCV base infrastructure.
+ *
+ * Copyright 2001, 2006 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s):
+ * Original source:
+ * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000
+ * Xenia Tkatschow (xenia@us.ibm.com)
+ * 2Gb awareness and general cleanup:
+ * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
+ * Rewritten for af_iucv:
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ * Documentation used:
+ * The original source
+ * CP Programming Service, IBM document # SC24-5760
+ *
+ * This program is free software; you can redistribute 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/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/cpu.h>
+#include <net/iucv/iucv.h>
+#include <asm/atomic.h>
+#include <asm/ebcdic.h>
+#include <asm/io.h>
+#include <asm/s390_ext.h>
+#include <asm/s390_rdev.h>
+#include <asm/smp.h>
+
+/*
+ * FLAGS:
+ * All flags are defined in the field IPFLAGS1 of each function
+ * and can be found in CP Programming Services.
+ * IPSRCCLS - Indicates you have specified a source class.
+ * IPTRGCLS - Indicates you have specified a target class.
+ * IPFGPID - Indicates you have specified a pathid.
+ * IPFGMID - Indicates you have specified a message ID.
+ * IPNORPY - Indicates a one-way message. No reply expected.
+ * IPALL - Indicates that all paths are affected.
+ */
+#define IUCV_IPSRCCLS 0x01
+#define IUCV_IPTRGCLS 0x01
+#define IUCV_IPFGPID 0x02
+#define IUCV_IPFGMID 0x04
+#define IUCV_IPNORPY 0x10
+#define IUCV_IPALL 0x80
+
+static int iucv_bus_match (struct device *dev, struct device_driver *drv)
+{
+ return 0;
+}
+
+struct bus_type iucv_bus = {
+ .name = "iucv",
+ .match = iucv_bus_match,
+};
+
+struct device *iucv_root;
+static int iucv_available;
+
+/* General IUCV interrupt structure */
+struct iucv_irq_data {
+ u16 ippathid;
+ u8 ipflags1;
+ u8 iptype;
+ u32 res2[8];
+};
+
+struct iucv_work {
+ struct list_head list;
+ struct iucv_irq_data data;
+};
+
+static LIST_HEAD(iucv_work_queue);
+static DEFINE_SPINLOCK(iucv_work_lock);
+
+static struct iucv_irq_data *iucv_irq_data;
+static cpumask_t iucv_buffer_cpumask = CPU_MASK_NONE;
+static cpumask_t iucv_irq_cpumask = CPU_MASK_NONE;
+
+static void iucv_tasklet_handler(unsigned long);
+static DECLARE_TASKLET(iucv_tasklet, iucv_tasklet_handler,0);
+
+enum iucv_command_codes {
+ IUCV_QUERY = 0,
+ IUCV_RETRIEVE_BUFFER = 2,
+ IUCV_SEND = 4,
+ IUCV_RECEIVE = 5,
+ IUCV_REPLY = 6,
+ IUCV_REJECT = 8,
+ IUCV_PURGE = 9,
+ IUCV_ACCEPT = 10,
+ IUCV_CONNECT = 11,
+ IUCV_DECLARE_BUFFER = 12,
+ IUCV_QUIESCE = 13,
+ IUCV_RESUME = 14,
+ IUCV_SEVER = 15,
+ IUCV_SETMASK = 16,
+};
+
+/*
+ * Error messages that are used with the iucv_sever function. They get
+ * converted to EBCDIC.
+ */
+static char iucv_error_no_listener[16] = "NO LISTENER";
+static char iucv_error_no_memory[16] = "NO MEMORY";
+static char iucv_error_pathid[16] = "INVALID PATHID";
+
+/*
+ * iucv_handler_list: List of registered handlers.
+ */
+static LIST_HEAD(iucv_handler_list);
+
+/*
+ * iucv_path_table: an array of iucv_path structures.
+ */
+static struct iucv_path **iucv_path_table;
+static unsigned long iucv_max_pathid;
+
+/*
+ * iucv_lock: spinlock protecting iucv_handler_list and iucv_pathid_table
+ */
+static DEFINE_SPINLOCK(iucv_table_lock);
+
+/*
+ * iucv_tasklet_cpu: contains the number of the cpu executing the tasklet.
+ * Needed for iucv_path_sever called from tasklet.
+ */
+static int iucv_tasklet_cpu = -1;
+
+/*
+ * Mutex and wait queue for iucv_register/iucv_unregister.
+ */
+static DEFINE_MUTEX(iucv_register_mutex);
+
+/*
+ * Counter for number of non-smp capable handlers.
+ */
+static int iucv_nonsmp_handler;
+
+/*
+ * IUCV control data structure. Used by iucv_path_accept, iucv_path_connect,
+ * iucv_path_quiesce and iucv_path_sever.
+ */
+struct iucv_cmd_control {
+ u16 ippathid;
+ u8 ipflags1;
+ u8 iprcode;
+ u16 ipmsglim;
+ u16 res1;
+ u8 ipvmid[8];
+ u8 ipuser[16];
+ u8 iptarget[8];
+} __attribute__ ((packed,aligned(8)));
+
+/*
+ * Data in parameter list iucv structure. Used by iucv_message_send,
+ * iucv_message_send2way and iucv_message_reply.
+ */
+struct iucv_cmd_dpl {
+ u16 ippathid;
+ u8 ipflags1;
+ u8 iprcode;
+ u32 ipmsgid;
+ u32 iptrgcls;
+ u8 iprmmsg[8];
+ u32 ipsrccls;
+ u32 ipmsgtag;
+ u32 ipbfadr2;
+ u32 ipbfln2f;
+ u32 res;
+} __attribute__ ((packed,aligned(8)));
+
+/*
+ * Data in buffer iucv structure. Used by iucv_message_receive,
+ * iucv_message_reject, iucv_message_send, iucv_message_send2way
+ * and iucv_declare_cpu.
+ */
+struct iucv_cmd_db {
+ u16 ippathid;
+ u8 ipflags1;
+ u8 iprcode;
+ u32 ipmsgid;
+ u32 iptrgcls;
+ u32 ipbfadr1;
+ u32 ipbfln1f;
+ u32 ipsrccls;
+ u32 ipmsgtag;
+ u32 ipbfadr2;
+ u32 ipbfln2f;
+ u32 res;
+} __attribute__ ((packed,aligned(8)));
+
+/*
+ * Purge message iucv structure. Used by iucv_message_purge.
+ */
+struct iucv_cmd_purge {
+ u16 ippathid;
+ u8 ipflags1;
+ u8 iprcode;
+ u32 ipmsgid;
+ u8 ipaudit[3];
+ u8 res1[5];
+ u32 res2;
+ u32 ipsrccls;
+ u32 ipmsgtag;
+ u32 res3[3];
+} __attribute__ ((packed,aligned(8)));
+
+/*
+ * Set mask iucv structure. Used by iucv_enable_cpu.
+ */
+struct iucv_cmd_set_mask {
+ u8 ipmask;
+ u8 res1[2];
+ u8 iprcode;
+ u32 res2[9];
+} __attribute__ ((packed,aligned(8)));
+
+union iucv_param {
+ struct iucv_cmd_control ctrl;
+ struct iucv_cmd_dpl dpl;
+ struct iucv_cmd_db db;
+ struct iucv_cmd_purge purge;
+ struct iucv_cmd_set_mask set_mask;
+};
+
+/*
+ * Anchor for per-cpu IUCV command parameter block.
+ */
+static union iucv_param *iucv_param;
+
+/**
+ * iucv_call_b2f0
+ * @code: identifier of IUCV call to CP.
+ * @parm: pointer to a struct iucv_parm block
+ *
+ * Calls CP to execute IUCV commands.
+ *
+ * Returns the result of the CP IUCV call.
+ */
+static inline int iucv_call_b2f0(int command, union iucv_param *parm)
+{
+ register unsigned long reg0 asm ("0");
+ register unsigned long reg1 asm ("1");
+ int ccode;
+
+ reg0 = command;
+ reg1 = virt_to_phys(parm);
+ asm volatile(
+ " .long 0xb2f01000\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (ccode), "=m" (*parm), "+d" (reg0), "+a" (reg1)
+ : "m" (*parm) : "cc");
+ return (ccode == 1) ? parm->ctrl.iprcode : ccode;
+}
+
+/**
+ * iucv_query_maxconn
+ *
+ * Determines the maximum number of connections that may be established.
+ *
+ * Returns the maximum number of connections or -EPERM is IUCV is not
+ * available.
+ */
+static int iucv_query_maxconn(void)
+{
+ register unsigned long reg0 asm ("0");
+ register unsigned long reg1 asm ("1");
+ void *param;
+ int ccode;
+
+ param = kzalloc(sizeof(union iucv_param), GFP_KERNEL|GFP_DMA);
+ if (!param)
+ return -ENOMEM;
+ reg0 = IUCV_QUERY;
+ reg1 = (unsigned long) param;
+ asm volatile (
+ " .long 0xb2f01000\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc");
+ if (ccode == 0)
+ iucv_max_pathid = reg0;
+ kfree(param);
+ return ccode ? -EPERM : 0;
+}
+
+/**
+ * iucv_allow_cpu
+ * @data: unused
+ *
+ * Allow iucv interrupts on this cpu.
+ */
+static void iucv_allow_cpu(void *data)
+{
+ int cpu = smp_processor_id();
+ union iucv_param *parm;
+
+ /*
+ * Enable all iucv interrupts.
+ * ipmask contains bits for the different interrupts
+ * 0x80 - Flag to allow nonpriority message pending interrupts
+ * 0x40 - Flag to allow priority message pending interrupts
+ * 0x20 - Flag to allow nonpriority message completion interrupts
+ * 0x10 - Flag to allow priority message completion interrupts
+ * 0x08 - Flag to allow IUCV control interrupts
+ */
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ parm->set_mask.ipmask = 0xf8;
+ iucv_call_b2f0(IUCV_SETMASK, parm);
+
+ /* Set indication that iucv interrupts are allowed for this cpu. */
+ cpu_set(cpu, iucv_irq_cpumask);
+}
+
+/**
+ * iucv_block_cpu
+ * @data: unused
+ *
+ * Block iucv interrupts on this cpu.
+ */
+static void iucv_block_cpu(void *data)
+{
+ int cpu = smp_processor_id();
+ union iucv_param *parm;
+
+ /* Disable all iucv interrupts. */
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ iucv_call_b2f0(IUCV_SETMASK, parm);
+
+ /* Clear indication that iucv interrupts are allowed for this cpu. */
+ cpu_clear(cpu, iucv_irq_cpumask);
+}
+
+/**
+ * iucv_declare_cpu
+ * @data: unused
+ *
+ * Declare a interupt buffer on this cpu.
+ */
+static void iucv_declare_cpu(void *data)
+{
+ int cpu = smp_processor_id();
+ union iucv_param *parm;
+ int rc;
+
+ if (cpu_isset(cpu, iucv_buffer_cpumask))
+ return;
+
+ /* Declare interrupt buffer. */
+ parm = percpu_ptr(iucv_param, cpu);
+ memset(parm, 0, sizeof(union iucv_param));
+ parm->db.ipbfadr1 = virt_to_phys(percpu_ptr(iucv_irq_data, cpu));
+ rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm);
+ if (rc) {
+ char *err = "Unknown";
+ switch(rc) {
+ case 0x03:
+ err = "Directory error";
+ break;
+ case 0x0a:
+ err = "Invalid length";
+ break;
+ case 0x13:
+ err = "Buffer already exists";
+ break;
+ case 0x3e:
+ err = "Buffer overlap";
+ break;
+ case 0x5c:
+ err = "Paging or storage error";
+ break;
+ }
+ printk(KERN_WARNING "iucv_register: iucv_declare_buffer "
+ "on cpu %i returned error 0x%02x (%s)\n", cpu, rc, err);
+ return;
+ }
+
+ /* Set indication that an iucv buffer exists for this cpu. */
+ cpu_set(cpu, iucv_buffer_cpumask);
+
+ if (iucv_nonsmp_handler == 0 || cpus_empty(iucv_irq_cpumask))
+ /* Enable iucv interrupts on this cpu. */
+ iucv_allow_cpu(NULL);
+ else
+ /* Disable iucv interrupts on this cpu. */
+ iucv_block_cpu(NULL);
+}
+
+/**
+ * iucv_retrieve_cpu
+ * @data: unused
+ *
+ * Retrieve interrupt buffer on this cpu.
+ */
+static void iucv_retrieve_cpu(void *data)
+{
+ int cpu = smp_processor_id();
+ union iucv_param *parm;
+
+ if (!cpu_isset(cpu, iucv_buffer_cpumask))
+ return;
+
+ /* Block iucv interrupts. */
+ iucv_block_cpu(NULL);
+
+ /* Retrieve interrupt buffer. */
+ parm = percpu_ptr(iucv_param, cpu);
+ iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm);
+
+ /* Clear indication that an iucv buffer exists for this cpu. */
+ cpu_clear(cpu, iucv_buffer_cpumask);
+}
+
+/**
+ * iucv_setmask_smp
+ *
+ * Allow iucv interrupts on all cpus.
+ */
+static void iucv_setmask_mp(void)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ /* Enable all cpus with a declared buffer. */
+ if (cpu_isset(cpu, iucv_buffer_cpumask) &&
+ !cpu_isset(cpu, iucv_irq_cpumask))
+ smp_call_function_on(iucv_allow_cpu, NULL, 0, 1, cpu);
+}
+
+/**
+ * iucv_setmask_up
+ *
+ * Allow iucv interrupts on a single cpus.
+ */
+static void iucv_setmask_up(void)
+{
+ cpumask_t cpumask;
+ int cpu;
+
+ /* Disable all cpu but the first in cpu_irq_cpumask. */
+ cpumask = iucv_irq_cpumask;
+ cpu_clear(first_cpu(iucv_irq_cpumask), cpumask);
+ for_each_cpu_mask(cpu, cpumask)
+ smp_call_function_on(iucv_block_cpu, NULL, 0, 1, cpu);
+}
+
+/**
+ * iucv_enable
+ *
+ * This function makes iucv ready for use. It allocates the pathid
+ * table, declares an iucv interrupt buffer and enables the iucv
+ * interrupts. Called when the first user has registered an iucv
+ * handler.
+ */
+static int iucv_enable(void)
+{
+ size_t alloc_size;
+ int cpu, rc;
+
+ rc = -ENOMEM;
+ alloc_size = iucv_max_pathid * sizeof(struct iucv_path);
+ iucv_path_table = kzalloc(alloc_size, GFP_KERNEL);
+ if (!iucv_path_table)
+ goto out;
+ /* Declare per cpu buffers. */
+ rc = -EIO;
+ for_each_online_cpu(cpu)
+ smp_call_function_on(iucv_declare_cpu, NULL, 0, 1, cpu);
+ if (cpus_empty(iucv_buffer_cpumask))
+ /* No cpu could declare an iucv buffer. */
+ goto out_path;
+ return 0;
+
+out_path:
+ kfree(iucv_path_table);
+out:
+ return rc;
+}
+
+/**
+ * iucv_disable
+ *
+ * This function shuts down iucv. It disables iucv interrupts, retrieves
+ * the iucv interrupt buffer and frees the pathid table. Called after the
+ * last user unregister its iucv handler.
+ */
+static void iucv_disable(void)
+{
+ on_each_cpu(iucv_retrieve_cpu, NULL, 0, 1);
+ kfree(iucv_path_table);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ cpumask_t cpumask;
+ long cpu = (long) hcpu;
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ if (!percpu_populate(iucv_irq_data,
+ sizeof(struct iucv_irq_data),
+ GFP_KERNEL|GFP_DMA, cpu))
+ return NOTIFY_BAD;
+ if (!percpu_populate(iucv_param, sizeof(union iucv_param),
+ GFP_KERNEL|GFP_DMA, cpu)) {
+ percpu_depopulate(iucv_irq_data, cpu);
+ return NOTIFY_BAD;
+ }
+ break;
+ case CPU_UP_CANCELED:
+ case CPU_DEAD:
+ percpu_depopulate(iucv_param, cpu);
+ percpu_depopulate(iucv_irq_data, cpu);
+ break;
+ case CPU_ONLINE:
+ case CPU_DOWN_FAILED:
+ smp_call_function_on(iucv_declare_cpu, NULL, 0, 1, cpu);
+ break;
+ case CPU_DOWN_PREPARE:
+ cpumask = iucv_buffer_cpumask;
+ cpu_clear(cpu, cpumask);
+ if (cpus_empty(cpumask))
+ /* Can't offline last IUCV enabled cpu. */
+ return NOTIFY_BAD;
+ smp_call_function_on(iucv_retrieve_cpu, NULL, 0, 1, cpu);
+ if (cpus_empty(iucv_irq_cpumask))
+ smp_call_function_on(iucv_allow_cpu, NULL, 0, 1,
+ first_cpu(iucv_buffer_cpumask));
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block iucv_cpu_notifier = {
+ .notifier_call = iucv_cpu_notify,
+};
+#endif
+
+/**
+ * iucv_sever_pathid
+ * @pathid: path identification number.
+ * @userdata: 16-bytes of user data.
+ *
+ * Sever an iucv path to free up the pathid. Used internally.
+ */
+static int iucv_sever_pathid(u16 pathid, u8 userdata[16])
+{
+ union iucv_param *parm;
+
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ if (userdata)
+ memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
+ parm->ctrl.ippathid = pathid;
+ return iucv_call_b2f0(IUCV_SEVER, parm);
+}
+
+/**
+ * __iucv_cleanup_pathid
+ * @dummy: unused dummy argument
+ *
+ * Nop function called via smp_call_function to force work items from
+ * pending external iucv interrupts to the work queue.
+ */
+static void __iucv_cleanup_pathid(void *dummy)
+{
+}
+
+/**
+ * iucv_cleanup_pathid
+ * @pathid: 16 bit pathid
+ *
+ * Function called after a path has been severed to find all remaining
+ * work items for the now stale pathid. The caller needs to hold the
+ * iucv_table_lock.
+ */
+static void iucv_cleanup_pathid(u16 pathid)
+{
+ struct iucv_work *p, *n;
+
+ /*
+ * Path is severed, the pathid can be reused immediatly on
+ * a iucv connect or a connection pending interrupt.
+ * iucv_path_connect and connection pending interrupt will
+ * wait until the iucv_table_lock is released before the
+ * recycled pathid enters the system.
+ * Force remaining interrupts to the work queue, then
+ * scan the work queue for items of this path.
+ */
+ smp_call_function(__iucv_cleanup_pathid, NULL, 0, 1);
+ spin_lock_irq(&iucv_work_lock);
+ list_for_each_entry_safe(p, n, &iucv_work_queue, list) {
+ /* Remove work items for pathid except connection pending */
+ if (p->data.ippathid == pathid && p->data.iptype != 0x01) {
+ list_del(&p->list);
+ kfree(p);
+ }
+ }
+ spin_unlock_irq(&iucv_work_lock);
+}
+
+/**
+ * iucv_register:
+ * @handler: address of iucv handler structure
+ * @smp: != 0 indicates that the handler can deal with out of order messages
+ *
+ * Registers a driver with IUCV.
+ *
+ * Returns 0 on success, -ENOMEM if the memory allocation for the pathid
+ * table failed, or -EIO if IUCV_DECLARE_BUFFER failed on all cpus.
+ */
+int iucv_register(struct iucv_handler *handler, int smp)
+{
+ int rc;
+
+ if (!iucv_available)
+ return -ENOSYS;
+ mutex_lock(&iucv_register_mutex);
+ if (!smp)
+ iucv_nonsmp_handler++;
+ if (list_empty(&iucv_handler_list)) {
+ rc = iucv_enable();
+ if (rc)
+ goto out_mutex;
+ } else if (!smp && iucv_nonsmp_handler == 1)
+ iucv_setmask_up();
+ INIT_LIST_HEAD(&handler->paths);
+
+ spin_lock_irq(&iucv_table_lock);
+ list_add_tail(&handler->list, &iucv_handler_list);
+ spin_unlock_irq(&iucv_table_lock);
+ rc = 0;
+out_mutex:
+ mutex_unlock(&iucv_register_mutex);
+ return rc;
+}
+
+/**
+ * iucv_unregister
+ * @handler: address of iucv handler structure
+ * @smp: != 0 indicates that the handler can deal with out of order messages
+ *
+ * Unregister driver from IUCV.
+ */
+void iucv_unregister(struct iucv_handler *handler, int smp)
+{
+ struct iucv_path *p, *n;
+
+ mutex_lock(&iucv_register_mutex);
+ spin_lock_bh(&iucv_table_lock);
+ /* Remove handler from the iucv_handler_list. */
+ list_del_init(&handler->list);
+ /* Sever all pathids still refering to the handler. */
+ list_for_each_entry_safe(p, n, &handler->paths, list) {
+ iucv_sever_pathid(p->pathid, NULL);
+ iucv_path_table[p->pathid] = NULL;
+ list_del(&p->list);
+ iucv_cleanup_pathid(p->pathid);
+ iucv_path_free(p);
+ }
+ spin_unlock_bh(&iucv_table_lock);
+ if (!smp)
+ iucv_nonsmp_handler--;
+ if (list_empty(&iucv_handler_list))
+ iucv_disable();
+ else if (!smp && iucv_nonsmp_handler == 0)
+ iucv_setmask_mp();
+ mutex_unlock(&iucv_register_mutex);
+}
+
+/**
+ * iucv_path_accept
+ * @path: address of iucv path structure
+ * @handler: address of iucv handler structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ * @private: private data passed to interrupt handlers for this path
+ *
+ * This function is issued after the user received a connection pending
+ * external interrupt and now wishes to complete the IUCV communication path.
+ *
+ * Returns the result of the CP IUCV call.
+ */
+int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
+ u8 userdata[16], void *private)
+{
+ union iucv_param *parm;
+ int rc;
+
+ local_bh_disable();
+ /* Prepare parameter block. */
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ parm->ctrl.ippathid = path->pathid;
+ parm->ctrl.ipmsglim = path->msglim;
+ if (userdata)
+ memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
+ parm->ctrl.ipflags1 = path->flags;
+
+ rc = iucv_call_b2f0(IUCV_ACCEPT, parm);
+ if (!rc) {
+ path->private = private;
+ path->msglim = parm->ctrl.ipmsglim;
+ path->flags = parm->ctrl.ipflags1;
+ }
+ local_bh_enable();
+ return rc;
+}
+
+/**
+ * iucv_path_connect
+ * @path: address of iucv path structure
+ * @handler: address of iucv handler structure
+ * @userid: 8-byte user identification
+ * @system: 8-byte target system identification
+ * @userdata: 16 bytes of data reflected to the communication partner
+ * @private: private data passed to interrupt handlers for this path
+ *
+ * This function establishes an IUCV path. Although the connect may complete
+ * successfully, you are not able to use the path until you receive an IUCV
+ * Connection Complete external interrupt.
+ *
+ * Returns the result of the CP IUCV call.
+ */
+int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
+ u8 userid[8], u8 system[8], u8 userdata[16],
+ void *private)
+{
+ union iucv_param *parm;
+ int rc;
+
+ preempt_disable();
+ if (iucv_tasklet_cpu != smp_processor_id())
+ spin_lock_bh(&iucv_table_lock);
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ parm->ctrl.ipmsglim = path->msglim;
+ parm->ctrl.ipflags1 = path->flags;
+ if (userid) {
+ memcpy(parm->ctrl.ipvmid, userid, sizeof(parm->ctrl.ipvmid));
+ ASCEBC(parm->ctrl.ipvmid, sizeof(parm->ctrl.ipvmid));
+ EBC_TOUPPER(parm->ctrl.ipvmid, sizeof(parm->ctrl.ipvmid));
+ }
+ if (system) {
+ memcpy(parm->ctrl.iptarget, system,
+ sizeof(parm->ctrl.iptarget));
+ ASCEBC(parm->ctrl.iptarget, sizeof(parm->ctrl.iptarget));
+ EBC_TOUPPER(parm->ctrl.iptarget, sizeof(parm->ctrl.iptarget));
+ }
+ if (userdata)
+ memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
+
+ rc = iucv_call_b2f0(IUCV_CONNECT, parm);
+ if (!rc) {
+ if (parm->ctrl.ippathid < iucv_max_pathid) {
+ path->pathid = parm->ctrl.ippathid;
+ path->msglim = parm->ctrl.ipmsglim;
+ path->flags = parm->ctrl.ipflags1;
+ path->handler = handler;
+ path->private = private;
+ list_add_tail(&path->list, &handler->paths);
+ iucv_path_table[path->pathid] = path;
+ } else {
+ iucv_sever_pathid(parm->ctrl.ippathid,
+ iucv_error_pathid);
+ rc = -EIO;
+ }
+ }
+ if (iucv_tasklet_cpu != smp_processor_id())
+ spin_unlock_bh(&iucv_table_lock);
+ preempt_enable();
+ return rc;
+}
+
+/**
+ * iucv_path_quiesce:
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function temporarily suspends incoming messages on an IUCV path.
+ * You can later reactivate the path by invoking the iucv_resume function.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16])
+{
+ union iucv_param *parm;
+ int rc;
+
+ local_bh_disable();
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ if (userdata)
+ memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
+ parm->ctrl.ippathid = path->pathid;
+ rc = iucv_call_b2f0(IUCV_QUIESCE, parm);
+ local_bh_enable();
+ return rc;
+}
+
+/**
+ * iucv_path_resume:
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function resumes incoming messages on an IUCV path that has
+ * been stopped with iucv_path_quiesce.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_resume(struct iucv_path *path, u8 userdata[16])
+{
+ union iucv_param *parm;
+ int rc;
+
+ local_bh_disable();
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ if (userdata)
+ memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
+ parm->ctrl.ippathid = path->pathid;
+ rc = iucv_call_b2f0(IUCV_RESUME, parm);
+ local_bh_enable();
+ return rc;
+}
+
+/**
+ * iucv_path_sever
+ * @path: address of iucv path structure
+ * @userdata: 16 bytes of data reflected to the communication partner
+ *
+ * This function terminates an IUCV path.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_path_sever(struct iucv_path *path, u8 userdata[16])
+{
+ int rc;
+
+
+ preempt_disable();
+ if (iucv_tasklet_cpu != smp_processor_id())
+ spin_lock_bh(&iucv_table_lock);
+ rc = iucv_sever_pathid(path->pathid, userdata);
+ if (!rc) {
+ iucv_path_table[path->pathid] = NULL;
+ list_del_init(&path->list);
+ iucv_cleanup_pathid(path->pathid);
+ }
+ if (iucv_tasklet_cpu != smp_processor_id())
+ spin_unlock_bh(&iucv_table_lock);
+ preempt_enable();
+ return rc;
+}
+
+/**
+ * iucv_message_purge
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @srccls: source class of message
+ *
+ * Cancels a message you have sent.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
+ u32 srccls)
+{
+ union iucv_param *parm;
+ int rc;
+
+ local_bh_disable();
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ parm->purge.ippathid = path->pathid;
+ parm->purge.ipmsgid = msg->id;
+ parm->purge.ipsrccls = srccls;
+ parm->purge.ipflags1 = IUCV_IPSRCCLS | IUCV_IPFGMID | IUCV_IPFGPID;
+ rc = iucv_call_b2f0(IUCV_PURGE, parm);
+ if (!rc) {
+ msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8;
+ msg->tag = parm->purge.ipmsgtag;
+ }
+ local_bh_enable();
+ return rc;
+}
+
+/**
+ * iucv_message_receive
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is received (IUCV_IPBUFLST)
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of data buffer
+ * @residual:
+ *
+ * This function receives messages that are being sent to you over
+ * established paths. This function will deal with RMDATA messages
+ * embedded in struct iucv_message as well.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, void *buffer, size_t size, size_t *residual)
+{
+ union iucv_param *parm;
+ struct iucv_array *array;
+ u8 *rmmsg;
+ size_t copy;
+ int rc;
+
+ if (msg->flags & IUCV_IPRMDATA) {
+ /*
+ * Message is 8 bytes long and has been stored to the
+ * message descriptor itself.
+ */
+ rc = (size < 8) ? 5 : 0;
+ if (residual)
+ *residual = abs(size - 8);
+ rmmsg = msg->rmmsg;
+ if (flags & IUCV_IPBUFLST) {
+ /* Copy to struct iucv_array. */
+ size = (size < 8) ? size : 8;
+ for (array = buffer; size > 0; array++) {
+ copy = min_t(size_t, size, array->length);
+ memcpy((u8 *)(addr_t) array->address,
+ rmmsg, copy);
+ rmmsg += copy;
+ size -= copy;
+ }
+ } else {
+ /* Copy to direct buffer. */
+ memcpy(buffer, rmmsg, min_t(size_t, size, 8));
+ }
+ return 0;
+ }
+
+ local_bh_disable();
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ parm->db.ipbfadr1 = (u32)(addr_t) buffer;
+ parm->db.ipbfln1f = (u32) size;
+ parm->db.ipmsgid = msg->id;
+ parm->db.ippathid = path->pathid;
+ parm->db.iptrgcls = msg->class;
+ parm->db.ipflags1 = (flags | IUCV_IPFGPID |
+ IUCV_IPFGMID | IUCV_IPTRGCLS);
+ rc = iucv_call_b2f0(IUCV_RECEIVE, parm);
+ if (!rc || rc == 5) {
+ msg->flags = parm->db.ipflags1;
+ if (residual)
+ *residual = parm->db.ipbfln1f;
+ }
+ local_bh_enable();
+ return rc;
+}
+
+/**
+ * iucv_message_reject
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ *
+ * The reject function refuses a specified message. Between the time you
+ * are notified of a message and the time that you complete the message,
+ * the message may be rejected.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg)
+{
+ union iucv_param *parm;
+ int rc;
+
+ local_bh_disable();
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ parm->db.ippathid = path->pathid;
+ parm->db.ipmsgid = msg->id;
+ parm->db.iptrgcls = msg->class;
+ parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID);
+ rc = iucv_call_b2f0(IUCV_REJECT, parm);
+ local_bh_enable();
+ return rc;
+}
+
+/**
+ * iucv_message_reply
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the reply is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
+ * @reply: address of reply data buffer or address of struct iucv_array
+ * @size: length of reply data buffer
+ *
+ * This function responds to the two-way messages that you receive. You
+ * must identify completely the message to which you wish to reply. ie,
+ * pathid, msgid, and trgcls. Prmmsg signifies the data is moved into
+ * the parameter list.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, void *reply, size_t size)
+{
+ union iucv_param *parm;
+ int rc;
+
+ local_bh_disable();
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ if (flags & IUCV_IPRMDATA) {
+ parm->dpl.ippathid = path->pathid;
+ parm->dpl.ipflags1 = flags;
+ parm->dpl.ipmsgid = msg->id;
+ parm->dpl.iptrgcls = msg->class;
+ memcpy(parm->dpl.iprmmsg, reply, min_t(size_t, size, 8));
+ } else {
+ parm->db.ipbfadr1 = (u32)(addr_t) reply;
+ parm->db.ipbfln1f = (u32) size;
+ parm->db.ippathid = path->pathid;
+ parm->db.ipflags1 = flags;
+ parm->db.ipmsgid = msg->id;
+ parm->db.iptrgcls = msg->class;
+ }
+ rc = iucv_call_b2f0(IUCV_REPLY, parm);
+ local_bh_enable();
+ return rc;
+}
+
+/**
+ * iucv_message_send
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
+ * @srccls: source class of message
+ * @buffer: address of send buffer or address of struct iucv_array
+ * @size: length of send buffer
+ *
+ * This function transmits data to another application. Data to be
+ * transmitted is in a buffer and this is a one-way message and the
+ * receiver will not reply to the message.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, u32 srccls, void *buffer, size_t size)
+{
+ union iucv_param *parm;
+ int rc;
+
+ local_bh_disable();
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ if (flags & IUCV_IPRMDATA) {
+ /* Message of 8 bytes can be placed into the parameter list. */
+ parm->dpl.ippathid = path->pathid;
+ parm->dpl.ipflags1 = flags | IUCV_IPNORPY;
+ parm->dpl.iptrgcls = msg->class;
+ parm->dpl.ipsrccls = srccls;
+ parm->dpl.ipmsgtag = msg->tag;
+ memcpy(parm->dpl.iprmmsg, buffer, 8);
+ } else {
+ parm->db.ipbfadr1 = (u32)(addr_t) buffer;
+ parm->db.ipbfln1f = (u32) size;
+ parm->db.ippathid = path->pathid;
+ parm->db.ipflags1 = flags | IUCV_IPNORPY;
+ parm->db.iptrgcls = msg->class;
+ parm->db.ipsrccls = srccls;
+ parm->db.ipmsgtag = msg->tag;
+ }
+ rc = iucv_call_b2f0(IUCV_SEND, parm);
+ if (!rc)
+ msg->id = parm->db.ipmsgid;
+ local_bh_enable();
+ return rc;
+}
+
+/**
+ * iucv_message_send2way
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is sent and the reply is received
+ * (IUCV_IPRMDATA, IUCV_IPBUFLST, IUCV_IPPRTY, IUCV_ANSLST)
+ * @srccls: source class of message
+ * @buffer: address of send buffer or address of struct iucv_array
+ * @size: length of send buffer
+ * @ansbuf: address of answer buffer or address of struct iucv_array
+ * @asize: size of reply buffer
+ *
+ * This function transmits data to another application. Data to be
+ * transmitted is in a buffer. The receiver of the send is expected to
+ * reply to the message and a buffer is provided into which IUCV moves
+ * the reply to this message.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, u32 srccls, void *buffer, size_t size,
+ void *answer, size_t asize, size_t *residual)
+{
+ union iucv_param *parm;
+ int rc;
+
+ local_bh_disable();
+ parm = percpu_ptr(iucv_param, smp_processor_id());
+ memset(parm, 0, sizeof(union iucv_param));
+ if (flags & IUCV_IPRMDATA) {
+ parm->dpl.ippathid = path->pathid;
+ parm->dpl.ipflags1 = path->flags; /* priority message */
+ parm->dpl.iptrgcls = msg->class;
+ parm->dpl.ipsrccls = srccls;
+ parm->dpl.ipmsgtag = msg->tag;
+ parm->dpl.ipbfadr2 = (u32)(addr_t) answer;
+ parm->dpl.ipbfln2f = (u32) asize;
+ memcpy(parm->dpl.iprmmsg, buffer, 8);
+ } else {
+ parm->db.ippathid = path->pathid;
+ parm->db.ipflags1 = path->flags; /* priority message */
+ parm->db.iptrgcls = msg->class;
+ parm->db.ipsrccls = srccls;
+ parm->db.ipmsgtag = msg->tag;
+ parm->db.ipbfadr1 = (u32)(addr_t) buffer;
+ parm->db.ipbfln1f = (u32) size;
+ parm->db.ipbfadr2 = (u32)(addr_t) answer;
+ parm->db.ipbfln2f = (u32) asize;
+ }
+ rc = iucv_call_b2f0(IUCV_SEND, parm);
+ if (!rc)
+ msg->id = parm->db.ipmsgid;
+ local_bh_enable();
+ return rc;
+}
+
+/**
+ * iucv_path_pending
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process connection pending work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_path_pending {
+ u16 ippathid;
+ u8 ipflags1;
+ u8 iptype;
+ u16 ipmsglim;
+ u16 res1;
+ u8 ipvmid[8];
+ u8 ipuser[16];
+ u32 res3;
+ u8 ippollfg;
+ u8 res4[3];
+} __attribute__ ((packed));
+
+static void iucv_path_pending(struct iucv_irq_data *data)
+{
+ struct iucv_path_pending *ipp = (void *) data;
+ struct iucv_handler *handler;
+ struct iucv_path *path;
+ char *error;
+
+ BUG_ON(iucv_path_table[ipp->ippathid]);
+ /* New pathid, handler found. Create a new path struct. */
+ error = iucv_error_no_memory;
+ path = iucv_path_alloc(ipp->ipmsglim, ipp->ipflags1, GFP_ATOMIC);
+ if (!path)
+ goto out_sever;
+ path->pathid = ipp->ippathid;
+ iucv_path_table[path->pathid] = path;
+ EBCASC(ipp->ipvmid, 8);
+
+ /* Call registered handler until one is found that wants the path. */
+ list_for_each_entry(handler, &iucv_handler_list, list) {
+ if (!handler->path_pending)
+ continue;
+ /*
+ * Add path to handler to allow a call to iucv_path_sever
+ * inside the path_pending function. If the handler returns
+ * an error remove the path from the handler again.
+ */
+ list_add(&path->list, &handler->paths);
+ path->handler = handler;
+ if (!handler->path_pending(path, ipp->ipvmid, ipp->ipuser))
+ return;
+ list_del(&path->list);
+ path->handler = NULL;
+ }
+ /* No handler wanted the path. */
+ iucv_path_table[path->pathid] = NULL;
+ iucv_path_free(path);
+ error = iucv_error_no_listener;
+out_sever:
+ iucv_sever_pathid(ipp->ippathid, error);
+}
+
+/**
+ * iucv_path_complete
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process connection complete work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_path_complete {
+ u16 ippathid;
+ u8 ipflags1;
+ u8 iptype;
+ u16 ipmsglim;
+ u16 res1;
+ u8 res2[8];
+ u8 ipuser[16];
+ u32 res3;
+ u8 ippollfg;
+ u8 res4[3];
+} __attribute__ ((packed));
+
+static void iucv_path_complete(struct iucv_irq_data *data)
+{
+ struct iucv_path_complete *ipc = (void *) data;
+ struct iucv_path *path = iucv_path_table[ipc->ippathid];
+
+ BUG_ON(!path || !path->handler);
+ if (path->handler->path_complete)
+ path->handler->path_complete(path, ipc->ipuser);
+}
+
+/**
+ * iucv_path_severed
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process connection severed work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_path_severed {
+ u16 ippathid;
+ u8 res1;
+ u8 iptype;
+ u32 res2;
+ u8 res3[8];
+ u8 ipuser[16];
+ u32 res4;
+ u8 ippollfg;
+ u8 res5[3];
+} __attribute__ ((packed));
+
+static void iucv_path_severed(struct iucv_irq_data *data)
+{
+ struct iucv_path_severed *ips = (void *) data;
+ struct iucv_path *path = iucv_path_table[ips->ippathid];
+
+ BUG_ON(!path || !path->handler);
+ if (path->handler->path_severed)
+ path->handler->path_severed(path, ips->ipuser);
+ else {
+ iucv_sever_pathid(path->pathid, NULL);
+ iucv_path_table[path->pathid] = NULL;
+ list_del_init(&path->list);
+ iucv_cleanup_pathid(path->pathid);
+ iucv_path_free(path);
+ }
+}
+
+/**
+ * iucv_path_quiesced
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process connection quiesced work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_path_quiesced {
+ u16 ippathid;
+ u8 res1;
+ u8 iptype;
+ u32 res2;
+ u8 res3[8];
+ u8 ipuser[16];
+ u32 res4;
+ u8 ippollfg;
+ u8 res5[3];
+} __attribute__ ((packed));
+
+static void iucv_path_quiesced(struct iucv_irq_data *data)
+{
+ struct iucv_path_quiesced *ipq = (void *) data;
+ struct iucv_path *path = iucv_path_table[ipq->ippathid];
+
+ BUG_ON(!path || !path->handler);
+ if (path->handler->path_quiesced)
+ path->handler->path_quiesced(path, ipq->ipuser);
+}
+
+/**
+ * iucv_path_resumed
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process connection resumed work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_path_resumed {
+ u16 ippathid;
+ u8 res1;
+ u8 iptype;
+ u32 res2;
+ u8 res3[8];
+ u8 ipuser[16];
+ u32 res4;
+ u8 ippollfg;
+ u8 res5[3];
+} __attribute__ ((packed));
+
+static void iucv_path_resumed(struct iucv_irq_data *data)
+{
+ struct iucv_path_resumed *ipr = (void *) data;
+ struct iucv_path *path = iucv_path_table[ipr->ippathid];
+
+ BUG_ON(!path || !path->handler);
+ if (path->handler->path_resumed)
+ path->handler->path_resumed(path, ipr->ipuser);
+}
+
+/**
+ * iucv_message_complete
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process message complete work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_message_complete {
+ u16 ippathid;
+ u8 ipflags1;
+ u8 iptype;
+ u32 ipmsgid;
+ u32 ipaudit;
+ u8 iprmmsg[8];
+ u32 ipsrccls;
+ u32 ipmsgtag;
+ u32 res;
+ u32 ipbfln2f;
+ u8 ippollfg;
+ u8 res2[3];
+} __attribute__ ((packed));
+
+static void iucv_message_complete(struct iucv_irq_data *data)
+{
+ struct iucv_message_complete *imc = (void *) data;
+ struct iucv_path *path = iucv_path_table[imc->ippathid];
+ struct iucv_message msg;
+
+ BUG_ON(!path || !path->handler);
+ if (path->handler->message_complete) {
+ msg.flags = imc->ipflags1;
+ msg.id = imc->ipmsgid;
+ msg.audit = imc->ipaudit;
+ memcpy(msg.rmmsg, imc->iprmmsg, 8);
+ msg.class = imc->ipsrccls;
+ msg.tag = imc->ipmsgtag;
+ msg.length = imc->ipbfln2f;
+ path->handler->message_complete(path, &msg);
+ }
+}
+
+/**
+ * iucv_message_pending
+ * @data: Pointer to external interrupt buffer
+ *
+ * Process message pending work item. Called from tasklet while holding
+ * iucv_table_lock.
+ */
+struct iucv_message_pending {
+ u16 ippathid;
+ u8 ipflags1;
+ u8 iptype;
+ u32 ipmsgid;
+ u32 iptrgcls;
+ union {
+ u32 iprmmsg1_u32;
+ u8 iprmmsg1[4];
+ } ln1msg1;
+ union {
+ u32 ipbfln1f;
+ u8 iprmmsg2[4];
+ } ln1msg2;
+ u32 res1[3];
+ u32 ipbfln2f;
+ u8 ippollfg;
+ u8 res2[3];
+} __attribute__ ((packed));
+
+static void iucv_message_pending(struct iucv_irq_data *data)
+{
+ struct iucv_message_pending *imp = (void *) data;
+ struct iucv_path *path = iucv_path_table[imp->ippathid];
+ struct iucv_message msg;
+
+ BUG_ON(!path || !path->handler);
+ if (path->handler->message_pending) {
+ msg.flags = imp->ipflags1;
+ msg.id = imp->ipmsgid;
+ msg.class = imp->iptrgcls;
+ if (imp->ipflags1 & IUCV_IPRMDATA) {
+ memcpy(msg.rmmsg, imp->ln1msg1.iprmmsg1, 8);
+ msg.length = 8;
+ } else
+ msg.length = imp->ln1msg2.ipbfln1f;
+ msg.reply_size = imp->ipbfln2f;
+ path->handler->message_pending(path, &msg);
+ }
+}
+
+/**
+ * iucv_tasklet_handler:
+ *
+ * This tasklet loops over the queue of irq buffers created by
+ * iucv_external_interrupt, calls the appropriate action handler
+ * and then frees the buffer.
+ */
+static void iucv_tasklet_handler(unsigned long ignored)
+{
+ typedef void iucv_irq_fn(struct iucv_irq_data *);
+ static iucv_irq_fn *irq_fn[] = {
+ [0x01] = iucv_path_pending,
+ [0x02] = iucv_path_complete,
+ [0x03] = iucv_path_severed,
+ [0x04] = iucv_path_quiesced,
+ [0x05] = iucv_path_resumed,
+ [0x06] = iucv_message_complete,
+ [0x07] = iucv_message_complete,
+ [0x08] = iucv_message_pending,
+ [0x09] = iucv_message_pending,
+ };
+ struct iucv_work *p;
+
+ /* Serialize tasklet, iucv_path_sever and iucv_path_connect. */
+ spin_lock(&iucv_table_lock);
+ iucv_tasklet_cpu = smp_processor_id();
+
+ spin_lock_irq(&iucv_work_lock);
+ while (!list_empty(&iucv_work_queue)) {
+ p = list_entry(iucv_work_queue.next, struct iucv_work, list);
+ list_del_init(&p->list);
+ spin_unlock_irq(&iucv_work_lock);
+ irq_fn[p->data.iptype](&p->data);
+ kfree(p);
+ spin_lock_irq(&iucv_work_lock);
+ }
+ spin_unlock_irq(&iucv_work_lock);
+
+ iucv_tasklet_cpu = -1;
+ spin_unlock(&iucv_table_lock);
+}
+
+/**
+ * iucv_external_interrupt
+ * @code: irq code
+ *
+ * Handles external interrupts coming in from CP.
+ * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
+ */
+static void iucv_external_interrupt(u16 code)
+{
+ struct iucv_irq_data *p;
+ struct iucv_work *work;
+
+ p = percpu_ptr(iucv_irq_data, smp_processor_id());
+ if (p->ippathid >= iucv_max_pathid) {
+ printk(KERN_WARNING "iucv_do_int: Got interrupt with "
+ "pathid %d > max_connections (%ld)\n",
+ p->ippathid, iucv_max_pathid - 1);
+ iucv_sever_pathid(p->ippathid, iucv_error_no_listener);
+ return;
+ }
+ if (p->iptype < 0x01 || p->iptype > 0x09) {
+ printk(KERN_ERR "iucv_do_int: unknown iucv interrupt\n");
+ return;
+ }
+ work = kmalloc(sizeof(struct iucv_work), GFP_ATOMIC);
+ if (!work) {
+ printk(KERN_WARNING "iucv_external_interrupt: out of memory\n");
+ return;
+ }
+ memcpy(&work->data, p, sizeof(work->data));
+ spin_lock(&iucv_work_lock);
+ list_add_tail(&work->list, &iucv_work_queue);
+ spin_unlock(&iucv_work_lock);
+ tasklet_schedule(&iucv_tasklet);
+}
+
+/**
+ * iucv_init
+ *
+ * Allocates and initializes various data structures.
+ */
+static int iucv_init(void)
+{
+ int rc;
+
+ if (!MACHINE_IS_VM) {
+ rc = -EPROTONOSUPPORT;
+ goto out;
+ }
+ rc = iucv_query_maxconn();
+ if (rc)
+ goto out;
+ rc = register_external_interrupt (0x4000, iucv_external_interrupt);
+ if (rc)
+ goto out;
+ rc = bus_register(&iucv_bus);
+ if (rc)
+ goto out_int;
+ iucv_root = s390_root_dev_register("iucv");
+ if (IS_ERR(iucv_root)) {
+ rc = PTR_ERR(iucv_root);
+ goto out_bus;
+ }
+ /* Note: GFP_DMA used used to get memory below 2G */
+ iucv_irq_data = percpu_alloc(sizeof(struct iucv_irq_data),
+ GFP_KERNEL|GFP_DMA);
+ if (!iucv_irq_data) {
+ rc = -ENOMEM;
+ goto out_root;
+ }
+ /* Allocate parameter blocks. */
+ iucv_param = percpu_alloc(sizeof(union iucv_param),
+ GFP_KERNEL|GFP_DMA);
+ if (!iucv_param) {
+ rc = -ENOMEM;
+ goto out_extint;
+ }
+ register_hotcpu_notifier(&iucv_cpu_notifier);
+ ASCEBC(iucv_error_no_listener, 16);
+ ASCEBC(iucv_error_no_memory, 16);
+ ASCEBC(iucv_error_pathid, 16);
+ iucv_available = 1;
+ return 0;
+
+out_extint:
+ percpu_free(iucv_irq_data);
+out_root:
+ s390_root_dev_unregister(iucv_root);
+out_bus:
+ bus_unregister(&iucv_bus);
+out_int:
+ unregister_external_interrupt(0x4000, iucv_external_interrupt);
+out:
+ return rc;
+}
+
+/**
+ * iucv_exit
+ *
+ * Frees everything allocated from iucv_init.
+ */
+static void iucv_exit(void)
+{
+ struct iucv_work *p, *n;
+
+ spin_lock_irq(&iucv_work_lock);
+ list_for_each_entry_safe(p, n, &iucv_work_queue, list)
+ kfree(p);
+ spin_unlock_irq(&iucv_work_lock);
+ unregister_hotcpu_notifier(&iucv_cpu_notifier);
+ percpu_free(iucv_param);
+ percpu_free(iucv_irq_data);
+ s390_root_dev_unregister(iucv_root);
+ bus_unregister(&iucv_bus);
+ unregister_external_interrupt(0x4000, iucv_external_interrupt);
+}
+
+subsys_initcall(iucv_init);
+module_exit(iucv_exit);
+
+/**
+ * Export all public stuff
+ */
+EXPORT_SYMBOL (iucv_bus);
+EXPORT_SYMBOL (iucv_root);
+EXPORT_SYMBOL (iucv_register);
+EXPORT_SYMBOL (iucv_unregister);
+EXPORT_SYMBOL (iucv_path_accept);
+EXPORT_SYMBOL (iucv_path_connect);
+EXPORT_SYMBOL (iucv_path_quiesce);
+EXPORT_SYMBOL (iucv_path_sever);
+EXPORT_SYMBOL (iucv_message_purge);
+EXPORT_SYMBOL (iucv_message_receive);
+EXPORT_SYMBOL (iucv_message_reject);
+EXPORT_SYMBOL (iucv_message_reply);
+EXPORT_SYMBOL (iucv_message_send);
+EXPORT_SYMBOL (iucv_message_send2way);
+
+MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
+MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");
+MODULE_LICENSE("GPL");
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 5dd5094659a..b4e444063d1 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -2345,6 +2345,196 @@ out:
return err;
}
+#ifdef CONFIG_NET_KEY_MIGRATE
+static int pfkey_sockaddr_pair_size(sa_family_t family)
+{
+ switch (family) {
+ case AF_INET:
+ return PFKEY_ALIGN8(sizeof(struct sockaddr_in) * 2);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ return PFKEY_ALIGN8(sizeof(struct sockaddr_in6) * 2);
+#endif
+ default:
+ return 0;
+ }
+ /* NOTREACHED */
+}
+
+static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq,
+ xfrm_address_t *saddr, xfrm_address_t *daddr,
+ u16 *family)
+{
+ struct sockaddr *sa = (struct sockaddr *)(rq + 1);
+ if (rq->sadb_x_ipsecrequest_len <
+ pfkey_sockaddr_pair_size(sa->sa_family))
+ return -EINVAL;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin;
+ sin = (struct sockaddr_in *)sa;
+ if ((sin+1)->sin_family != AF_INET)
+ return -EINVAL;
+ memcpy(&saddr->a4, &sin->sin_addr, sizeof(saddr->a4));
+ sin++;
+ memcpy(&daddr->a4, &sin->sin_addr, sizeof(daddr->a4));
+ *family = AF_INET;
+ break;
+ }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6;
+ sin6 = (struct sockaddr_in6 *)sa;
+ if ((sin6+1)->sin6_family != AF_INET6)
+ return -EINVAL;
+ memcpy(&saddr->a6, &sin6->sin6_addr,
+ sizeof(saddr->a6));
+ sin6++;
+ memcpy(&daddr->a6, &sin6->sin6_addr,
+ sizeof(daddr->a6));
+ *family = AF_INET6;
+ break;
+ }
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
+ struct xfrm_migrate *m)
+{
+ int err;
+ struct sadb_x_ipsecrequest *rq2;
+
+ if (len <= sizeof(struct sadb_x_ipsecrequest) ||
+ len < rq1->sadb_x_ipsecrequest_len)
+ return -EINVAL;
+
+ /* old endoints */
+ err = parse_sockaddr_pair(rq1, &m->old_saddr, &m->old_daddr,
+ &m->old_family);
+ if (err)
+ return err;
+
+ rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len);
+ len -= rq1->sadb_x_ipsecrequest_len;
+
+ if (len <= sizeof(struct sadb_x_ipsecrequest) ||
+ len < rq2->sadb_x_ipsecrequest_len)
+ return -EINVAL;
+
+ /* new endpoints */
+ err = parse_sockaddr_pair(rq2, &m->new_saddr, &m->new_daddr,
+ &m->new_family);
+ if (err)
+ return err;
+
+ if (rq1->sadb_x_ipsecrequest_proto != rq2->sadb_x_ipsecrequest_proto ||
+ rq1->sadb_x_ipsecrequest_mode != rq2->sadb_x_ipsecrequest_mode ||
+ rq1->sadb_x_ipsecrequest_reqid != rq2->sadb_x_ipsecrequest_reqid)
+ return -EINVAL;
+
+ m->proto = rq1->sadb_x_ipsecrequest_proto;
+ m->mode = rq1->sadb_x_ipsecrequest_mode - 1;
+ m->reqid = rq1->sadb_x_ipsecrequest_reqid;
+
+ return ((int)(rq1->sadb_x_ipsecrequest_len +
+ rq2->sadb_x_ipsecrequest_len));
+}
+
+static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
+ struct sadb_msg *hdr, void **ext_hdrs)
+{
+ int i, len, ret, err = -EINVAL;
+ u8 dir;
+ struct sadb_address *sa;
+ struct sadb_x_policy *pol;
+ struct sadb_x_ipsecrequest *rq;
+ struct xfrm_selector sel;
+ struct xfrm_migrate m[XFRM_MAX_DEPTH];
+
+ if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1],
+ ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) ||
+ !ext_hdrs[SADB_X_EXT_POLICY - 1]) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ pol = ext_hdrs[SADB_X_EXT_POLICY - 1];
+ if (!pol) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ dir = pol->sadb_x_policy_dir - 1;
+ memset(&sel, 0, sizeof(sel));
+
+ /* set source address info of selector */
+ sa = ext_hdrs[SADB_EXT_ADDRESS_SRC - 1];
+ sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr);
+ sel.prefixlen_s = sa->sadb_address_prefixlen;
+ 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;
+
+ /* set destination address info of selector */
+ sa = ext_hdrs[SADB_EXT_ADDRESS_DST - 1],
+ pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr);
+ sel.prefixlen_d = sa->sadb_address_prefixlen;
+ 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;
+
+ rq = (struct sadb_x_ipsecrequest *)(pol + 1);
+
+ /* extract ipsecrequests */
+ i = 0;
+ len = pol->sadb_x_policy_len * 8 - sizeof(struct sadb_x_policy);
+
+ while (len > 0 && i < XFRM_MAX_DEPTH) {
+ ret = ipsecrequests_to_migrate(rq, len, &m[i]);
+ if (ret < 0) {
+ err = ret;
+ goto out;
+ } else {
+ rq = (struct sadb_x_ipsecrequest *)((u8 *)rq + ret);
+ len -= ret;
+ i++;
+ }
+ }
+
+ if (!i || len > 0) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i);
+
+ out:
+ return err;
+}
+#else
+static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
+ struct sadb_msg *hdr, void **ext_hdrs)
+{
+ return -ENOPROTOOPT;
+}
+#endif
+
+
static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
unsigned int dir;
@@ -2473,6 +2663,7 @@ static pfkey_handler pfkey_funcs[SADB_MAX + 1] = {
[SADB_X_SPDFLUSH] = pfkey_spdflush,
[SADB_X_SPDSETIDX] = pfkey_spdadd,
[SADB_X_SPDDELETE2] = pfkey_spdget,
+ [SADB_X_MIGRATE] = pfkey_migrate,
};
static int pfkey_process(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr)
@@ -3118,6 +3309,236 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
}
+#ifdef CONFIG_NET_KEY_MIGRATE
+static int set_sadb_address(struct sk_buff *skb, int sasize, int type,
+ struct xfrm_selector *sel)
+{
+ struct sadb_address *addr;
+ struct sockaddr_in *sin;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct sockaddr_in6 *sin6;
+#endif
+ addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize);
+ addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8;
+ addr->sadb_address_exttype = type;
+ addr->sadb_address_proto = sel->proto;
+ addr->sadb_address_reserved = 0;
+
+ switch (type) {
+ case SADB_EXT_ADDRESS_SRC:
+ if (sel->family == AF_INET) {
+ addr->sadb_address_prefixlen = sel->prefixlen_s;
+ sin = (struct sockaddr_in *)(addr + 1);
+ sin->sin_family = AF_INET;
+ memcpy(&sin->sin_addr.s_addr, &sel->saddr,
+ sizeof(sin->sin_addr.s_addr));
+ sin->sin_port = 0;
+ memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+ }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ else if (sel->family == AF_INET6) {
+ addr->sadb_address_prefixlen = sel->prefixlen_s;
+ sin6 = (struct sockaddr_in6 *)(addr + 1);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = 0;
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+ memcpy(&sin6->sin6_addr.s6_addr, &sel->saddr,
+ sizeof(sin6->sin6_addr.s6_addr));
+ }
+#endif
+ break;
+ case SADB_EXT_ADDRESS_DST:
+ if (sel->family == AF_INET) {
+ addr->sadb_address_prefixlen = sel->prefixlen_d;
+ sin = (struct sockaddr_in *)(addr + 1);
+ sin->sin_family = AF_INET;
+ memcpy(&sin->sin_addr.s_addr, &sel->daddr,
+ sizeof(sin->sin_addr.s_addr));
+ sin->sin_port = 0;
+ memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+ }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ else if (sel->family == AF_INET6) {
+ addr->sadb_address_prefixlen = sel->prefixlen_d;
+ sin6 = (struct sockaddr_in6 *)(addr + 1);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = 0;
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+ memcpy(&sin6->sin6_addr.s6_addr, &sel->daddr,
+ sizeof(sin6->sin6_addr.s6_addr));
+ }
+#endif
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int set_ipsecrequest(struct sk_buff *skb,
+ uint8_t proto, uint8_t mode, int level,
+ uint32_t reqid, uint8_t family,
+ xfrm_address_t *src, xfrm_address_t *dst)
+{
+ struct sadb_x_ipsecrequest *rq;
+ struct sockaddr_in *sin;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct sockaddr_in6 *sin6;
+#endif
+ int size_req;
+
+ size_req = sizeof(struct sadb_x_ipsecrequest) +
+ pfkey_sockaddr_pair_size(family);
+
+ rq = (struct sadb_x_ipsecrequest *)skb_put(skb, size_req);
+ memset(rq, 0, size_req);
+ rq->sadb_x_ipsecrequest_len = size_req;
+ rq->sadb_x_ipsecrequest_proto = proto;
+ rq->sadb_x_ipsecrequest_mode = mode;
+ rq->sadb_x_ipsecrequest_level = level;
+ rq->sadb_x_ipsecrequest_reqid = reqid;
+
+ switch (family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)(rq + 1);
+ sin->sin_family = AF_INET;
+ memcpy(&sin->sin_addr.s_addr, src,
+ sizeof(sin->sin_addr.s_addr));
+ sin++;
+ sin->sin_family = AF_INET;
+ memcpy(&sin->sin_addr.s_addr, dst,
+ sizeof(sin->sin_addr.s_addr));
+ break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)(rq + 1);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = 0;
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+ memcpy(&sin6->sin6_addr.s6_addr, src,
+ sizeof(sin6->sin6_addr.s6_addr));
+ sin6++;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = 0;
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+ memcpy(&sin6->sin6_addr.s6_addr, dst,
+ sizeof(sin6->sin6_addr.s6_addr));
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_NET_KEY_MIGRATE
+static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+ struct xfrm_migrate *m, int num_bundles)
+{
+ int i;
+ int sasize_sel;
+ int size = 0;
+ int size_pol = 0;
+ struct sk_buff *skb;
+ struct sadb_msg *hdr;
+ struct sadb_x_policy *pol;
+ struct xfrm_migrate *mp;
+
+ if (type != XFRM_POLICY_TYPE_MAIN)
+ return 0;
+
+ if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH)
+ return -EINVAL;
+
+ /* selector */
+ sasize_sel = pfkey_sockaddr_size(sel->family);
+ if (!sasize_sel)
+ return -EINVAL;
+ size += (sizeof(struct sadb_address) + sasize_sel) * 2;
+
+ /* policy info */
+ size_pol += sizeof(struct sadb_x_policy);
+
+ /* ipsecrequests */
+ for (i = 0, mp = m; i < num_bundles; i++, mp++) {
+ /* old locator pair */
+ size_pol += sizeof(struct sadb_x_ipsecrequest) +
+ pfkey_sockaddr_pair_size(mp->old_family);
+ /* new locator pair */
+ size_pol += sizeof(struct sadb_x_ipsecrequest) +
+ pfkey_sockaddr_pair_size(mp->new_family);
+ }
+
+ size += sizeof(struct sadb_msg) + size_pol;
+
+ /* alloc buffer */
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+
+ hdr = (struct sadb_msg *)skb_put(skb, sizeof(struct sadb_msg));
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_type = SADB_X_MIGRATE;
+ hdr->sadb_msg_satype = pfkey_proto2satype(m->proto);
+ hdr->sadb_msg_len = size / 8;
+ hdr->sadb_msg_errno = 0;
+ hdr->sadb_msg_reserved = 0;
+ hdr->sadb_msg_seq = 0;
+ hdr->sadb_msg_pid = 0;
+
+ /* selector src */
+ set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel);
+
+ /* selector dst */
+ set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_DST, sel);
+
+ /* policy information */
+ pol = (struct sadb_x_policy *)skb_put(skb, sizeof(struct sadb_x_policy));
+ pol->sadb_x_policy_len = size_pol / 8;
+ pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
+ pol->sadb_x_policy_dir = dir + 1;
+ pol->sadb_x_policy_id = 0;
+ pol->sadb_x_policy_priority = 0;
+
+ for (i = 0, mp = m; i < num_bundles; i++, mp++) {
+ /* old ipsecrequest */
+ if (set_ipsecrequest(skb, mp->proto, mp->mode + 1,
+ (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE),
+ mp->reqid, mp->old_family,
+ &mp->old_saddr, &mp->old_daddr) < 0) {
+ return -EINVAL;
+ }
+
+ /* new ipsecrequest */
+ if (set_ipsecrequest(skb, mp->proto, mp->mode + 1,
+ (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE),
+ mp->reqid, mp->new_family,
+ &mp->new_saddr, &mp->new_daddr) < 0) {
+ return -EINVAL;
+ }
+ }
+
+ /* broadcast migrate message to sockets */
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+
+ return 0;
+}
+#else
+static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+ struct xfrm_migrate *m, int num_bundles)
+{
+ return -ENOPROTOOPT;
+}
+#endif
+
static int pfkey_sendmsg(struct kiocb *kiocb,
struct socket *sock, struct msghdr *msg, size_t len)
{
@@ -3287,6 +3708,7 @@ static struct xfrm_mgr pfkeyv2_mgr =
.compile_policy = pfkey_compile_policy,
.new_mapping = pfkey_send_new_mapping,
.notify_policy = pfkey_send_policy_notify,
+ .migrate = pfkey_send_migrate,
};
static void __exit ipsec_pfkey_exit(void)
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 3a66878a182..748f7f00909 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -1,5 +1,5 @@
menu "Core Netfilter Configuration"
- depends on NET && NETFILTER
+ depends on NET && INET && NETFILTER
config NETFILTER_NETLINK
tristate "Netfilter netlink interface"
@@ -44,8 +44,7 @@ choice
depends on NF_CONNTRACK_ENABLED
config NF_CONNTRACK_SUPPORT
- bool "Layer 3 Independent Connection tracking (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "Layer 3 Independent Connection tracking"
help
Layer 3 independent connection tracking is experimental scheme
which generalize ip_conntrack to support other layer 3 protocols.
@@ -122,7 +121,7 @@ config NF_CONNTRACK_EVENTS
config NF_CT_PROTO_GRE
tristate
- depends on EXPERIMENTAL && NF_CONNTRACK
+ depends on NF_CONNTRACK
config NF_CT_PROTO_SCTP
tristate 'SCTP protocol connection tracking support (EXPERIMENTAL)'
@@ -136,8 +135,8 @@ config NF_CT_PROTO_SCTP
Documentation/modules.txt. If unsure, say `N'.
config NF_CONNTRACK_AMANDA
- tristate "Amanda backup protocol support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && NF_CONNTRACK
+ tristate "Amanda backup protocol support"
+ depends on NF_CONNTRACK
select TEXTSEARCH
select TEXTSEARCH_KMP
help
@@ -151,8 +150,8 @@ config NF_CONNTRACK_AMANDA
To compile it as a module, choose M here. If unsure, say N.
config NF_CONNTRACK_FTP
- tristate "FTP protocol support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && NF_CONNTRACK
+ tristate "FTP protocol support"
+ depends on NF_CONNTRACK
help
Tracking FTP connections is problematic: special helpers are
required for tracking them, and doing masquerading and other forms
@@ -166,7 +165,7 @@ config NF_CONNTRACK_FTP
config NF_CONNTRACK_H323
tristate "H.323 protocol support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && NF_CONNTRACK
+ depends on EXPERIMENTAL && NF_CONNTRACK && (IPV6 || IPV6=n)
help
H.323 is a VoIP signalling protocol from ITU-T. As one of the most
important VoIP protocols, it is widely used by voice hardware and
@@ -184,8 +183,8 @@ config NF_CONNTRACK_H323
To compile it as a module, choose M here. If unsure, say N.
config NF_CONNTRACK_IRC
- tristate "IRC protocol support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && NF_CONNTRACK
+ tristate "IRC protocol support"
+ depends on NF_CONNTRACK
help
There is a commonly-used extension to IRC called
Direct Client-to-Client Protocol (DCC). This enables users to send
@@ -218,8 +217,8 @@ config NF_CONNTRACK_NETBIOS_NS
To compile it as a module, choose M here. If unsure, say N.
config NF_CONNTRACK_PPTP
- tristate "PPtP protocol support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && NF_CONNTRACK
+ tristate "PPtP protocol support"
+ depends on NF_CONNTRACK
select NF_CT_PROTO_GRE
help
This module adds support for PPTP (Point to Point Tunnelling
@@ -236,6 +235,19 @@ config NF_CONNTRACK_PPTP
To compile it as a module, choose M here. If unsure, say N.
+config NF_CONNTRACK_SANE
+ tristate "SANE protocol support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && NF_CONNTRACK
+ help
+ SANE is a protocol for remote access to scanners as implemented
+ by the 'saned' daemon. Like FTP, it uses separate control and
+ data connections.
+
+ With this module you can support SANE on a connection tracking
+ firewall.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NF_CONNTRACK_SIP
tristate "SIP protocol support (EXPERIMENTAL)"
depends on EXPERIMENTAL && NF_CONNTRACK
@@ -249,8 +261,8 @@ config NF_CONNTRACK_SIP
To compile it as a module, choose M here. If unsure, say N.
config NF_CONNTRACK_TFTP
- tristate "TFTP protocol support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && NF_CONNTRACK
+ tristate "TFTP protocol support"
+ depends on NF_CONNTRACK
help
TFTP connection tracking helper, this is required depending
on how restrictive your ruleset is.
@@ -383,6 +395,32 @@ config NETFILTER_XT_TARGET_CONNSECMARK
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_TARGET_TCPMSS
+ tristate '"TCPMSS" target support'
+ depends on NETFILTER_XTABLES && (IPV6 || IPV6=n)
+ ---help---
+ This option adds a `TCPMSS' target, which allows you to alter the
+ MSS value of TCP SYN packets, to control the maximum size for that
+ connection (usually limiting it to your outgoing interface's MTU
+ minus 40).
+
+ This is used to overcome criminally braindead ISPs or servers which
+ block ICMP Fragmentation Needed packets. The symptoms of this
+ problem are that everything works fine from your Linux
+ firewall/router, but machines behind it can never exchange large
+ packets:
+ 1) Web browsers connect, then hang with no data received.
+ 2) Small mail works fine, but large emails hang.
+ 3) ssh works fine, but scp hangs after initial handshaking.
+
+ Workaround: activate this option and add a rule to your firewall
+ configuration like:
+
+ iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
+ -j TCPMSS --clamp-mss-to-pmtu
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_MATCH_COMMENT
tristate '"comment" match support'
depends on NETFILTER_XTABLES
@@ -629,7 +667,7 @@ config NETFILTER_XT_MATCH_TCPMSS
config NETFILTER_XT_MATCH_HASHLIMIT
tristate '"hashlimit" match support'
- depends on NETFILTER_XTABLES
+ depends on NETFILTER_XTABLES && (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n)
help
This option adds a `hashlimit' match.
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 5dc5574f7e9..b2b5c7566b2 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o
obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o
obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o
obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o
+obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o
obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o
obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o
@@ -44,6 +45,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
# matches
diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c
index a5b234e444d..2a48efdf0d6 100644
--- a/net/netfilter/nf_conntrack_netbios_ns.c
+++ b/net/netfilter/nf_conntrack_netbios_ns.c
@@ -89,6 +89,7 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
exp->expectfn = NULL;
exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->helper = NULL;
nf_conntrack_expect_related(exp);
nf_conntrack_expect_put(exp);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index bd1d2de75e4..c64f029f705 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -389,9 +389,11 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
&& ctnetlink_dump_helpinfo(skb, ct) < 0)
goto nfattr_failure;
+#ifdef CONFIG_NF_CONNTRACK_MARK
if ((events & IPCT_MARK || ct->mark)
&& ctnetlink_dump_mark(skb, ct) < 0)
goto nfattr_failure;
+#endif
if (events & IPCT_COUNTER_FILLING &&
(ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
@@ -981,7 +983,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
if (cda[CTA_PROTOINFO-1]) {
err = ctnetlink_change_protoinfo(ct, cda);
if (err < 0)
- return err;
+ goto err;
}
#if defined(CONFIG_NF_CONNTRACK_MARK)
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index f0ff00e0d05..c59df3bc2bb 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -113,7 +113,7 @@ static void pptp_expectfn(struct nf_conn *ct,
rcu_read_lock();
nf_nat_pptp_expectfn = rcu_dereference(nf_nat_pptp_hook_expectfn);
- if (nf_nat_pptp_expectfn && ct->status & IPS_NAT_MASK)
+ if (nf_nat_pptp_expectfn && ct->master->status & IPS_NAT_MASK)
nf_nat_pptp_expectfn(ct, exp);
else {
struct nf_conntrack_tuple inv_t;
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 626b0011dd8..6fccdcf43e0 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -60,12 +60,9 @@ static DEFINE_RWLOCK(tcp_lock);
If it's non-zero, we mark only out of window RST segments as INVALID. */
int nf_ct_tcp_be_liberal __read_mostly = 0;
-/* When connection is picked up from the middle, how many packets are required
- to pass in each direction when we assume we are in sync - if any side uses
- window scaling, we lost the game.
- If it is set to zero, we disable picking up already established
+/* If it is set to zero, we disable picking up already established
connections. */
-int nf_ct_tcp_loose __read_mostly = 3;
+int nf_ct_tcp_loose __read_mostly = 1;
/* Max number of the retransmitted packets without receiving an (acceptable)
ACK from the destination. If this number is reached, a shorter timer
@@ -650,11 +647,10 @@ static int tcp_in_window(struct ip_ct_tcp *state,
before(sack, receiver->td_end + 1),
after(ack, receiver->td_end - MAXACKWINDOW(sender)));
- if (sender->loose || receiver->loose ||
- (before(seq, sender->td_maxend + 1) &&
- after(end, sender->td_end - receiver->td_maxwin - 1) &&
- before(sack, receiver->td_end + 1) &&
- after(ack, receiver->td_end - MAXACKWINDOW(sender)))) {
+ if (before(seq, sender->td_maxend + 1) &&
+ after(end, sender->td_end - receiver->td_maxwin - 1) &&
+ before(sack, receiver->td_end + 1) &&
+ after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
/*
* Take into account window scaling (RFC 1323).
*/
@@ -699,15 +695,13 @@ static int tcp_in_window(struct ip_ct_tcp *state,
state->retrans = 0;
}
}
- /*
- * Close the window of disabled window tracking :-)
- */
- if (sender->loose)
- sender->loose--;
-
res = 1;
} else {
- if (LOG_INVALID(IPPROTO_TCP))
+ res = 0;
+ if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
+ nf_ct_tcp_be_liberal)
+ res = 1;
+ if (!res && LOG_INVALID(IPPROTO_TCP))
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: %s ",
before(seq, sender->td_maxend + 1) ?
@@ -718,8 +712,6 @@ static int tcp_in_window(struct ip_ct_tcp *state,
: "ACK is over the upper bound (ACKed data not seen yet)"
: "SEQ is under the lower bound (already ACKed data retransmitted)"
: "SEQ is over the upper bound (over the window of the receiver)");
-
- res = nf_ct_tcp_be_liberal;
}
DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
@@ -1063,8 +1055,6 @@ static int tcp_new(struct nf_conn *conntrack,
tcp_options(skb, dataoff, th, &conntrack->proto.tcp.seen[0]);
conntrack->proto.tcp.seen[1].flags = 0;
- conntrack->proto.tcp.seen[0].loose =
- conntrack->proto.tcp.seen[1].loose = 0;
} else if (nf_ct_tcp_loose == 0) {
/* Don't try to pick up connections. */
return 0;
@@ -1085,11 +1075,11 @@ static int tcp_new(struct nf_conn *conntrack,
conntrack->proto.tcp.seen[0].td_maxwin;
conntrack->proto.tcp.seen[0].td_scale = 0;
- /* We assume SACK. Should we assume window scaling too? */
+ /* We assume SACK and liberal window checking to handle
+ * window scaling */
conntrack->proto.tcp.seen[0].flags =
- conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM;
- conntrack->proto.tcp.seen[0].loose =
- conntrack->proto.tcp.seen[1].loose = nf_ct_tcp_loose;
+ conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
+ IP_CT_TCP_FLAG_BE_LIBERAL;
}
conntrack->proto.tcp.seen[1].td_end = 0;
diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c
new file mode 100644
index 00000000000..eb2d1dc46d4
--- /dev/null
+++ b/net/netfilter/nf_conntrack_sane.c
@@ -0,0 +1,242 @@
+/* SANE connection tracking helper
+ * (SANE = Scanner Access Now Easy)
+ * For documentation about the SANE network protocol see
+ * http://www.sane-project.org/html/doc015.html
+ */
+
+/* Copyright (C) 2007 Red Hat, Inc.
+ * Author: Michal Schmidt <mschmidt@redhat.com>
+ * Based on the FTP conntrack helper (net/netfilter/nf_conntrack_ftp.c):
+ * (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
+ * (C) 2003 Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
+ *
+ * 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/moduleparam.h>
+#include <linux/netfilter.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_expect.h>
+#include <linux/netfilter/nf_conntrack_sane.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>");
+MODULE_DESCRIPTION("SANE connection tracking helper");
+
+static char *sane_buffer;
+
+static DEFINE_SPINLOCK(nf_sane_lock);
+
+#define MAX_PORTS 8
+static u_int16_t ports[MAX_PORTS];
+static unsigned int ports_c;
+module_param_array(ports, ushort, &ports_c, 0400);
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+struct sane_request {
+ __be32 RPC_code;
+#define SANE_NET_START 7 /* RPC code */
+
+ __be32 handle;
+};
+
+struct sane_reply_net_start {
+ __be32 status;
+#define SANE_STATUS_SUCCESS 0
+
+ __be16 zero;
+ __be16 port;
+ /* other fields aren't interesting for conntrack */
+};
+
+static int help(struct sk_buff **pskb,
+ unsigned int protoff,
+ struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ unsigned int dataoff, datalen;
+ struct tcphdr _tcph, *th;
+ char *sb_ptr;
+ int ret = NF_ACCEPT;
+ int dir = CTINFO2DIR(ctinfo);
+ struct nf_ct_sane_master *ct_sane_info;
+ struct nf_conntrack_expect *exp;
+ struct nf_conntrack_tuple *tuple;
+ struct sane_request *req;
+ struct sane_reply_net_start *reply;
+ int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
+
+ ct_sane_info = &nfct_help(ct)->help.ct_sane_info;
+ /* Until there's been traffic both ways, don't look in packets. */
+ if (ctinfo != IP_CT_ESTABLISHED &&
+ ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY)
+ return NF_ACCEPT;
+
+ /* Not a full tcp header? */
+ th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph);
+ if (th == NULL)
+ return NF_ACCEPT;
+
+ /* No data? */
+ dataoff = protoff + th->doff * 4;
+ if (dataoff >= (*pskb)->len)
+ return NF_ACCEPT;
+
+ datalen = (*pskb)->len - dataoff;
+
+ spin_lock_bh(&nf_sane_lock);
+ sb_ptr = skb_header_pointer(*pskb, dataoff, datalen, sane_buffer);
+ BUG_ON(sb_ptr == NULL);
+
+ if (dir == IP_CT_DIR_ORIGINAL) {
+ if (datalen != sizeof(struct sane_request))
+ goto out;
+
+ req = (struct sane_request *)sb_ptr;
+ if (req->RPC_code != htonl(SANE_NET_START)) {
+ /* Not an interesting command */
+ ct_sane_info->state = SANE_STATE_NORMAL;
+ goto out;
+ }
+
+ /* We're interested in the next reply */
+ ct_sane_info->state = SANE_STATE_START_REQUESTED;
+ goto out;
+ }
+
+ /* Is it a reply to an uninteresting command? */
+ if (ct_sane_info->state != SANE_STATE_START_REQUESTED)
+ goto out;
+
+ /* It's a reply to SANE_NET_START. */
+ ct_sane_info->state = SANE_STATE_NORMAL;
+
+ if (datalen < sizeof(struct sane_reply_net_start)) {
+ DEBUGP("nf_ct_sane: NET_START reply too short\n");
+ goto out;
+ }
+
+ reply = (struct sane_reply_net_start *)sb_ptr;
+ if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
+ /* saned refused the command */
+ DEBUGP("nf_ct_sane: unsuccessful SANE_STATUS = %u\n",
+ ntohl(reply->status));
+ goto out;
+ }
+
+ /* Invalid saned reply? Ignore it. */
+ if (reply->zero != 0)
+ goto out;
+
+ exp = nf_conntrack_expect_alloc(ct);
+ if (exp == NULL) {
+ ret = NF_DROP;
+ goto out;
+ }
+
+ tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+ nf_conntrack_expect_init(exp, family,
+ &tuple->src.u3, &tuple->dst.u3,
+ IPPROTO_TCP,
+ NULL, &reply->port);
+
+ DEBUGP("nf_ct_sane: expect: ");
+ NF_CT_DUMP_TUPLE(&exp->tuple);
+ NF_CT_DUMP_TUPLE(&exp->mask);
+
+ /* Can't expect this? Best to drop packet now. */
+ if (nf_conntrack_expect_related(exp) != 0)
+ ret = NF_DROP;
+
+ nf_conntrack_expect_put(exp);
+
+out:
+ spin_unlock_bh(&nf_sane_lock);
+ return ret;
+}
+
+static struct nf_conntrack_helper sane[MAX_PORTS][2];
+static char sane_names[MAX_PORTS][2][sizeof("sane-65535")];
+
+/* don't make this __exit, since it's called from __init ! */
+static void nf_conntrack_sane_fini(void)
+{
+ int i, j;
+
+ for (i = 0; i < ports_c; i++) {
+ for (j = 0; j < 2; j++) {
+ DEBUGP("nf_ct_sane: unregistering helper for pf: %d "
+ "port: %d\n",
+ sane[i][j].tuple.src.l3num, ports[i]);
+ nf_conntrack_helper_unregister(&sane[i][j]);
+ }
+ }
+
+ kfree(sane_buffer);
+}
+
+static int __init nf_conntrack_sane_init(void)
+{
+ int i, j = -1, ret = 0;
+ char *tmpname;
+
+ sane_buffer = kmalloc(65536, GFP_KERNEL);
+ if (!sane_buffer)
+ return -ENOMEM;
+
+ if (ports_c == 0)
+ ports[ports_c++] = SANE_PORT;
+
+ /* FIXME should be configurable whether IPv4 and IPv6 connections
+ are tracked or not - YK */
+ for (i = 0; i < ports_c; i++) {
+ sane[i][0].tuple.src.l3num = PF_INET;
+ sane[i][1].tuple.src.l3num = PF_INET6;
+ for (j = 0; j < 2; j++) {
+ sane[i][j].tuple.src.u.tcp.port = htons(ports[i]);
+ sane[i][j].tuple.dst.protonum = IPPROTO_TCP;
+ sane[i][j].mask.src.u.tcp.port = 0xFFFF;
+ sane[i][j].mask.dst.protonum = 0xFF;
+ sane[i][j].max_expected = 1;
+ sane[i][j].timeout = 5 * 60; /* 5 Minutes */
+ sane[i][j].me = THIS_MODULE;
+ sane[i][j].help = help;
+ tmpname = &sane_names[i][j][0];
+ if (ports[i] == SANE_PORT)
+ sprintf(tmpname, "sane");
+ else
+ sprintf(tmpname, "sane-%d", ports[i]);
+ sane[i][j].name = tmpname;
+
+ DEBUGP("nf_ct_sane: registering helper for pf: %d "
+ "port: %d\n",
+ sane[i][j].tuple.src.l3num, ports[i]);
+ ret = nf_conntrack_helper_register(&sane[i][j]);
+ if (ret) {
+ printk(KERN_ERR "nf_ct_sane: failed to "
+ "register helper for pf: %d port: %d\n",
+ sane[i][j].tuple.src.l3num, ports[i]);
+ nf_conntrack_sane_fini();
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+module_init(nf_conntrack_sane_init);
+module_exit(nf_conntrack_sane_fini);
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index eb2a2411f97..9dec1153467 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -303,10 +303,16 @@ static int skp_epaddr_len(struct nf_conn *ct, const char *dptr,
{
int s = *shift;
- for (; dptr <= limit && *dptr != '@'; dptr++)
+ /* Search for @, but stop at the end of the line.
+ * We are inside a sip: URI, so we don't need to worry about
+ * continuation lines. */
+ while (dptr <= limit &&
+ *dptr != '@' && *dptr != '\r' && *dptr != '\n') {
(*shift)++;
+ dptr++;
+ }
- if (*dptr == '@') {
+ if (dptr <= limit && *dptr == '@') {
dptr++;
(*shift)++;
} else
diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c
index 50de965bb10..195e92990da 100644
--- a/net/netfilter/xt_CLASSIFY.c
+++ b/net/netfilter/xt_CLASSIFY.c
@@ -33,9 +33,7 @@ target(struct sk_buff **pskb,
{
const struct xt_classify_target_info *clinfo = targinfo;
- if ((*pskb)->priority != clinfo->priority)
- (*pskb)->priority = clinfo->priority;
-
+ (*pskb)->priority = clinfo->priority;
return XT_CONTINUE;
}
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c
index b5548239d41..795c058b16a 100644
--- a/net/netfilter/xt_CONNMARK.c
+++ b/net/netfilter/xt_CONNMARK.c
@@ -61,7 +61,7 @@ target(struct sk_buff **pskb,
#else
nf_conntrack_event_cache(IPCT_MARK, *pskb);
#endif
- }
+ }
break;
case XT_CONNMARK_SAVE:
newmark = (*ctmark & ~markinfo->mask) |
@@ -78,8 +78,7 @@ target(struct sk_buff **pskb,
case XT_CONNMARK_RESTORE:
mark = (*pskb)->mark;
diff = (*ctmark ^ mark) & markinfo->mask;
- if (diff != 0)
- (*pskb)->mark = mark ^ diff;
+ (*pskb)->mark = mark ^ diff;
break;
}
}
@@ -96,6 +95,11 @@ checkentry(const char *tablename,
{
struct xt_connmark_target_info *matchinfo = targinfo;
+ if (nf_ct_l3proto_try_module_get(target->family) < 0) {
+ printk(KERN_WARNING "can't load conntrack support for "
+ "proto=%d\n", target->family);
+ return 0;
+ }
if (matchinfo->mode == XT_CONNMARK_RESTORE) {
if (strcmp(tablename, "mangle") != 0) {
printk(KERN_WARNING "CONNMARK: restore can only be "
@@ -111,6 +115,12 @@ checkentry(const char *tablename,
return 1;
}
+static void
+destroy(const struct xt_target *target, void *targinfo)
+{
+ nf_ct_l3proto_module_put(target->family);
+}
+
#ifdef CONFIG_COMPAT
struct compat_xt_connmark_target_info {
compat_ulong_t mark, mask;
@@ -147,6 +157,7 @@ static struct xt_target xt_connmark_target[] = {
.name = "CONNMARK",
.family = AF_INET,
.checkentry = checkentry,
+ .destroy = destroy,
.target = target,
.targetsize = sizeof(struct xt_connmark_target_info),
#ifdef CONFIG_COMPAT
@@ -160,6 +171,7 @@ static struct xt_target xt_connmark_target[] = {
.name = "CONNMARK",
.family = AF_INET6,
.checkentry = checkentry,
+ .destroy = destroy,
.target = target,
.targetsize = sizeof(struct xt_connmark_target_info),
.me = THIS_MODULE
@@ -168,7 +180,6 @@ static struct xt_target xt_connmark_target[] = {
static int __init xt_connmark_init(void)
{
- need_conntrack();
return xt_register_targets(xt_connmark_target,
ARRAY_SIZE(xt_connmark_target));
}
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index 46738626667..1ab0db641f9 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -41,8 +41,7 @@ static void secmark_save(struct sk_buff *skb)
connsecmark = nf_ct_get_secmark(skb, &ctinfo);
if (connsecmark && !*connsecmark)
- if (*connsecmark != skb->secmark)
- *connsecmark = skb->secmark;
+ *connsecmark = skb->secmark;
}
}
@@ -58,8 +57,7 @@ static void secmark_restore(struct sk_buff *skb)
connsecmark = nf_ct_get_secmark(skb, &ctinfo);
if (connsecmark && *connsecmark)
- if (skb->secmark != *connsecmark)
- skb->secmark = *connsecmark;
+ skb->secmark = *connsecmark;
}
}
@@ -93,6 +91,11 @@ static int checkentry(const char *tablename, const void *entry,
{
struct xt_connsecmark_target_info *info = targinfo;
+ if (nf_ct_l3proto_try_module_get(target->family) < 0) {
+ printk(KERN_WARNING "can't load conntrack support for "
+ "proto=%d\n", target->family);
+ return 0;
+ }
switch (info->mode) {
case CONNSECMARK_SAVE:
case CONNSECMARK_RESTORE:
@@ -106,11 +109,18 @@ static int checkentry(const char *tablename, const void *entry,
return 1;
}
+static void
+destroy(const struct xt_target *target, void *targinfo)
+{
+ nf_ct_l3proto_module_put(target->family);
+}
+
static struct xt_target xt_connsecmark_target[] = {
{
.name = "CONNSECMARK",
.family = AF_INET,
.checkentry = checkentry,
+ .destroy = destroy,
.target = target,
.targetsize = sizeof(struct xt_connsecmark_target_info),
.table = "mangle",
@@ -120,6 +130,7 @@ static struct xt_target xt_connsecmark_target[] = {
.name = "CONNSECMARK",
.family = AF_INET6,
.checkentry = checkentry,
+ .destroy = destroy,
.target = target,
.targetsize = sizeof(struct xt_connsecmark_target_info),
.table = "mangle",
@@ -129,7 +140,6 @@ static struct xt_target xt_connsecmark_target[] = {
static int __init xt_connsecmark_init(void)
{
- need_conntrack();
return xt_register_targets(xt_connsecmark_target,
ARRAY_SIZE(xt_connsecmark_target));
}
diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c
index 0b48547e8d6..cfc45af357d 100644
--- a/net/netfilter/xt_MARK.c
+++ b/net/netfilter/xt_MARK.c
@@ -31,9 +31,7 @@ target_v0(struct sk_buff **pskb,
{
const struct xt_mark_target_info *markinfo = targinfo;
- if((*pskb)->mark != markinfo->mark)
- (*pskb)->mark = markinfo->mark;
-
+ (*pskb)->mark = markinfo->mark;
return XT_CONTINUE;
}
@@ -62,9 +60,7 @@ target_v1(struct sk_buff **pskb,
break;
}
- if((*pskb)->mark != mark)
- (*pskb)->mark = mark;
-
+ (*pskb)->mark = mark;
return XT_CONTINUE;
}
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index add75219629..f1131c3a9db 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -47,9 +47,7 @@ static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
BUG();
}
- if ((*pskb)->secmark != secmark)
- (*pskb)->secmark = secmark;
-
+ (*pskb)->secmark = secmark;
return XT_CONTINUE;
}
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
new file mode 100644
index 00000000000..db7e38c08de
--- /dev/null
+++ b/net/netfilter/xt_TCPMSS.c
@@ -0,0 +1,296 @@
+/*
+ * This is a module which is used for setting the MSS option in TCP packets.
+ *
+ * Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
+ *
+ * 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/skbuff.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+#include <linux/netfilter/xt_TCPMSS.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
+MODULE_DESCRIPTION("x_tables TCP MSS modification module");
+MODULE_ALIAS("ipt_TCPMSS");
+MODULE_ALIAS("ip6t_TCPMSS");
+
+static inline unsigned int
+optlen(const u_int8_t *opt, unsigned int offset)
+{
+ /* Beware zero-length options: make finite progress */
+ if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
+ return 1;
+ else
+ return opt[offset+1];
+}
+
+static int
+tcpmss_mangle_packet(struct sk_buff **pskb,
+ const struct xt_tcpmss_info *info,
+ unsigned int tcphoff,
+ unsigned int minlen)
+{
+ struct tcphdr *tcph;
+ unsigned int tcplen, i;
+ __be16 oldval;
+ u16 newmss;
+ u8 *opt;
+
+ if (!skb_make_writable(pskb, (*pskb)->len))
+ return -1;
+
+ tcplen = (*pskb)->len - tcphoff;
+ tcph = (struct tcphdr *)((*pskb)->nh.raw + tcphoff);
+
+ /* Since it passed flags test in tcp match, we know it is is
+ not a fragment, and has data >= tcp header length. SYN
+ packets should not contain data: if they did, then we risk
+ running over MTU, sending Frag Needed and breaking things
+ badly. --RR */
+ if (tcplen != tcph->doff*4) {
+ if (net_ratelimit())
+ printk(KERN_ERR "xt_TCPMSS: bad length (%u bytes)\n",
+ (*pskb)->len);
+ return -1;
+ }
+
+ if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
+ if (dst_mtu((*pskb)->dst) <= minlen) {
+ if (net_ratelimit())
+ printk(KERN_ERR "xt_TCPMSS: "
+ "unknown or invalid path-MTU (%u)\n",
+ dst_mtu((*pskb)->dst));
+ return -1;
+ }
+ newmss = dst_mtu((*pskb)->dst) - minlen;
+ } else
+ newmss = info->mss;
+
+ opt = (u_int8_t *)tcph;
+ for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
+ if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
+ opt[i+1] == TCPOLEN_MSS) {
+ u_int16_t oldmss;
+
+ oldmss = (opt[i+2] << 8) | opt[i+3];
+
+ if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+ oldmss <= newmss)
+ return 0;
+
+ opt[i+2] = (newmss & 0xff00) >> 8;
+ opt[i+3] = (newmss & 0x00ff);
+
+ nf_proto_csum_replace2(&tcph->check, *pskb,
+ htons(oldmss), htons(newmss), 0);
+ return 0;
+ }
+ }
+
+ /*
+ * MSS Option not found ?! add it..
+ */
+ if (skb_tailroom((*pskb)) < TCPOLEN_MSS) {
+ struct sk_buff *newskb;
+
+ newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
+ TCPOLEN_MSS, GFP_ATOMIC);
+ if (!newskb)
+ return -1;
+ kfree_skb(*pskb);
+ *pskb = newskb;
+ tcph = (struct tcphdr *)((*pskb)->nh.raw + tcphoff);
+ }
+
+ skb_put((*pskb), TCPOLEN_MSS);
+
+ opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
+ memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
+
+ nf_proto_csum_replace2(&tcph->check, *pskb,
+ htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
+ opt[0] = TCPOPT_MSS;
+ opt[1] = TCPOLEN_MSS;
+ opt[2] = (newmss & 0xff00) >> 8;
+ opt[3] = (newmss & 0x00ff);
+
+ nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0);
+
+ oldval = ((__be16 *)tcph)[6];
+ tcph->doff += TCPOLEN_MSS/4;
+ nf_proto_csum_replace2(&tcph->check, *pskb,
+ oldval, ((__be16 *)tcph)[6], 0);
+ return TCPOLEN_MSS;
+}
+
+static unsigned int
+xt_tcpmss_target4(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+ const void *targinfo)
+{
+ struct iphdr *iph = (*pskb)->nh.iph;
+ __be16 newlen;
+ int ret;
+
+ ret = tcpmss_mangle_packet(pskb, targinfo, iph->ihl * 4,
+ sizeof(*iph) + sizeof(struct tcphdr));
+ if (ret < 0)
+ return NF_DROP;
+ if (ret > 0) {
+ iph = (*pskb)->nh.iph;
+ newlen = htons(ntohs(iph->tot_len) + ret);
+ nf_csum_replace2(&iph->check, iph->tot_len, newlen);
+ iph->tot_len = newlen;
+ }
+ return XT_CONTINUE;
+}
+
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+static unsigned int
+xt_tcpmss_target6(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+ const void *targinfo)
+{
+ struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h;
+ u8 nexthdr;
+ int tcphoff;
+ int ret;
+
+ nexthdr = ipv6h->nexthdr;
+ tcphoff = ipv6_skip_exthdr(*pskb, sizeof(*ipv6h), &nexthdr);
+ if (tcphoff < 0) {
+ WARN_ON(1);
+ return NF_DROP;
+ }
+ ret = tcpmss_mangle_packet(pskb, targinfo, tcphoff,
+ sizeof(*ipv6h) + sizeof(struct tcphdr));
+ if (ret < 0)
+ return NF_DROP;
+ if (ret > 0) {
+ ipv6h = (*pskb)->nh.ipv6h;
+ ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) + ret);
+ }
+ return XT_CONTINUE;
+}
+#endif
+
+#define TH_SYN 0x02
+
+/* Must specify -p tcp --syn */
+static inline int find_syn_match(const struct xt_entry_match *m)
+{
+ const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
+
+ if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
+ tcpinfo->flg_cmp & TH_SYN &&
+ !(tcpinfo->invflags & XT_TCP_INV_FLAGS))
+ return 1;
+
+ return 0;
+}
+
+static int
+xt_tcpmss_checkentry4(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask)
+{
+ const struct xt_tcpmss_info *info = targinfo;
+ const struct ipt_entry *e = entry;
+
+ if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+ (hook_mask & ~((1 << NF_IP_FORWARD) |
+ (1 << NF_IP_LOCAL_OUT) |
+ (1 << NF_IP_POST_ROUTING))) != 0) {
+ printk("xt_TCPMSS: path-MTU clamping only supported in "
+ "FORWARD, OUTPUT and POSTROUTING hooks\n");
+ return 0;
+ }
+ if (IPT_MATCH_ITERATE(e, find_syn_match))
+ return 1;
+ printk("xt_TCPMSS: Only works on TCP SYN packets\n");
+ return 0;
+}
+
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+static int
+xt_tcpmss_checkentry6(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask)
+{
+ const struct xt_tcpmss_info *info = targinfo;
+ const struct ip6t_entry *e = entry;
+
+ if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+ (hook_mask & ~((1 << NF_IP6_FORWARD) |
+ (1 << NF_IP6_LOCAL_OUT) |
+ (1 << NF_IP6_POST_ROUTING))) != 0) {
+ printk("xt_TCPMSS: path-MTU clamping only supported in "
+ "FORWARD, OUTPUT and POSTROUTING hooks\n");
+ return 0;
+ }
+ if (IP6T_MATCH_ITERATE(e, find_syn_match))
+ return 1;
+ printk("xt_TCPMSS: Only works on TCP SYN packets\n");
+ return 0;
+}
+#endif
+
+static struct xt_target xt_tcpmss_reg[] = {
+ {
+ .family = AF_INET,
+ .name = "TCPMSS",
+ .checkentry = xt_tcpmss_checkentry4,
+ .target = xt_tcpmss_target4,
+ .targetsize = sizeof(struct xt_tcpmss_info),
+ .proto = IPPROTO_TCP,
+ .me = THIS_MODULE,
+ },
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+ {
+ .family = AF_INET6,
+ .name = "TCPMSS",
+ .checkentry = xt_tcpmss_checkentry6,
+ .target = xt_tcpmss_target6,
+ .targetsize = sizeof(struct xt_tcpmss_info),
+ .proto = IPPROTO_TCP,
+ .me = THIS_MODULE,
+ },
+#endif
+};
+
+static int __init xt_tcpmss_init(void)
+{
+ return xt_register_targets(xt_tcpmss_reg, ARRAY_SIZE(xt_tcpmss_reg));
+}
+
+static void __exit xt_tcpmss_fini(void)
+{
+ xt_unregister_targets(xt_tcpmss_reg, ARRAY_SIZE(xt_tcpmss_reg));
+}
+
+module_init(xt_tcpmss_init);
+module_exit(xt_tcpmss_fini);
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index dcc497ea818..5e32dfa2668 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -52,6 +52,8 @@ match(const struct sk_buff *skb,
{
const struct xt_connbytes_info *sinfo = matchinfo;
u_int64_t what = 0; /* initialize to make gcc happy */
+ u_int64_t bytes = 0;
+ u_int64_t pkts = 0;
const struct ip_conntrack_counter *counters;
if (!(counters = nf_ct_get_counters(skb)))
@@ -89,29 +91,22 @@ match(const struct sk_buff *skb,
case XT_CONNBYTES_AVGPKT:
switch (sinfo->direction) {
case XT_CONNBYTES_DIR_ORIGINAL:
- what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes,
- counters[IP_CT_DIR_ORIGINAL].packets);
+ bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
+ pkts = counters[IP_CT_DIR_ORIGINAL].packets;
break;
case XT_CONNBYTES_DIR_REPLY:
- what = div64_64(counters[IP_CT_DIR_REPLY].bytes,
- counters[IP_CT_DIR_REPLY].packets);
+ bytes = counters[IP_CT_DIR_REPLY].bytes;
+ pkts = counters[IP_CT_DIR_REPLY].packets;
break;
case XT_CONNBYTES_DIR_BOTH:
- {
- u_int64_t bytes;
- u_int64_t pkts;
- bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
- counters[IP_CT_DIR_REPLY].bytes;
- pkts = counters[IP_CT_DIR_ORIGINAL].packets+
- counters[IP_CT_DIR_REPLY].packets;
-
- /* FIXME_THEORETICAL: what to do if sum
- * overflows ? */
-
- what = div64_64(bytes, pkts);
- }
+ bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
+ counters[IP_CT_DIR_REPLY].bytes;
+ pkts = counters[IP_CT_DIR_ORIGINAL].packets +
+ counters[IP_CT_DIR_REPLY].packets;
break;
}
+ if (pkts != 0)
+ what = div64_64(bytes, pkts);
break;
}
@@ -139,15 +134,28 @@ static int check(const char *tablename,
sinfo->direction != XT_CONNBYTES_DIR_BOTH)
return 0;
+ if (nf_ct_l3proto_try_module_get(match->family) < 0) {
+ printk(KERN_WARNING "can't load conntrack support for "
+ "proto=%d\n", match->family);
+ return 0;
+ }
+
return 1;
}
+static void
+destroy(const struct xt_match *match, void *matchinfo)
+{
+ nf_ct_l3proto_module_put(match->family);
+}
+
static struct xt_match xt_connbytes_match[] = {
{
.name = "connbytes",
.family = AF_INET,
.checkentry = check,
.match = match,
+ .destroy = destroy,
.matchsize = sizeof(struct xt_connbytes_info),
.me = THIS_MODULE
},
@@ -156,6 +164,7 @@ static struct xt_match xt_connbytes_match[] = {
.family = AF_INET6,
.checkentry = check,
.match = match,
+ .destroy = destroy,
.matchsize = sizeof(struct xt_connbytes_info),
.me = THIS_MODULE
},
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index a8f03057dbd..36c2defff23 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -63,22 +63,18 @@ checkentry(const char *tablename,
printk(KERN_WARNING "connmark: only support 32bit mark\n");
return 0;
}
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
if (nf_ct_l3proto_try_module_get(match->family) < 0) {
- printk(KERN_WARNING "can't load nf_conntrack support for "
+ printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", match->family);
return 0;
}
-#endif
return 1;
}
static void
destroy(const struct xt_match *match, void *matchinfo)
{
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
nf_ct_l3proto_module_put(match->family);
-#endif
}
#ifdef CONFIG_COMPAT
@@ -140,7 +136,6 @@ static struct xt_match xt_connmark_match[] = {
static int __init xt_connmark_init(void)
{
- need_conntrack();
return xt_register_matches(xt_connmark_match,
ARRAY_SIZE(xt_connmark_match));
}
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 0ea501a2fda..3dc2357b8de 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -20,6 +20,7 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_conntrack.h>
+#include <net/netfilter/nf_conntrack_compat.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
@@ -228,21 +229,17 @@ checkentry(const char *tablename,
void *matchinfo,
unsigned int hook_mask)
{
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
if (nf_ct_l3proto_try_module_get(match->family) < 0) {
- printk(KERN_WARNING "can't load nf_conntrack support for "
+ printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", match->family);
return 0;
}
-#endif
return 1;
}
static void destroy(const struct xt_match *match, void *matchinfo)
{
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
nf_ct_l3proto_module_put(match->family);
-#endif
}
static struct xt_match conntrack_match = {
@@ -257,7 +254,6 @@ static struct xt_match conntrack_match = {
static int __init xt_conntrack_init(void)
{
- need_conntrack();
return xt_register_match(&conntrack_match);
}
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index a5a6e192ac2..bd1f7a2048d 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -414,6 +414,7 @@ hashlimit_init_dst(struct xt_hashlimit_htable *hinfo, struct dsthash_dst *dst,
switch (nexthdr) {
case IPPROTO_TCP:
case IPPROTO_UDP:
+ case IPPROTO_UDPLITE:
case IPPROTO_SCTP:
case IPPROTO_DCCP:
ports = skb_header_pointer(skb, protoff, sizeof(_ports),
@@ -745,7 +746,7 @@ static int __init xt_hashlimit_init(void)
}
hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", proc_net);
if (!hashlimit_procdir6) {
- printk(KERN_ERR "xt_hashlimit: tnable to create proc dir "
+ printk(KERN_ERR "xt_hashlimit: unable to create proc dir "
"entry\n");
goto err4;
}
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c
index 5d7818b73e3..04bc32ba719 100644
--- a/net/netfilter/xt_helper.c
+++ b/net/netfilter/xt_helper.c
@@ -24,6 +24,7 @@
#endif
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_helper.h>
+#include <net/netfilter/nf_conntrack_compat.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Martin Josefsson <gandalf@netfilter.org>");
@@ -143,13 +144,11 @@ static int check(const char *tablename,
{
struct xt_helper_info *info = matchinfo;
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
if (nf_ct_l3proto_try_module_get(match->family) < 0) {
- printk(KERN_WARNING "can't load nf_conntrack support for "
+ printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", match->family);
return 0;
}
-#endif
info->name[29] = '\0';
return 1;
}
@@ -157,9 +156,7 @@ static int check(const char *tablename,
static void
destroy(const struct xt_match *match, void *matchinfo)
{
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
nf_ct_l3proto_module_put(match->family);
-#endif
}
static struct xt_match xt_helper_match[] = {
@@ -185,7 +182,6 @@ static struct xt_match xt_helper_match[] = {
static int __init xt_helper_init(void)
{
- need_conntrack();
return xt_register_matches(xt_helper_match,
ARRAY_SIZE(xt_helper_match));
}
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c
index fd8f954cded..b9b3ffc5451 100644
--- a/net/netfilter/xt_physdev.c
+++ b/net/netfilter/xt_physdev.c
@@ -113,20 +113,16 @@ checkentry(const char *tablename,
if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
info->bitmask & ~XT_PHYSDEV_OP_MASK)
return 0;
- if (brnf_deferred_hooks == 0 &&
- info->bitmask & XT_PHYSDEV_OP_OUT &&
+ if (info->bitmask & XT_PHYSDEV_OP_OUT &&
(!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||
info->invert & XT_PHYSDEV_OP_BRIDGED) &&
hook_mask & ((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
(1 << NF_IP_POST_ROUTING))) {
printk(KERN_WARNING "physdev match: using --physdev-out in the "
"OUTPUT, FORWARD and POSTROUTING chains for non-bridged "
- "traffic is deprecated and breaks other things, it will "
- "be removed in January 2007. See Documentation/"
- "feature-removal-schedule.txt for details. This doesn't "
- "affect you in case you're using it for purely bridged "
- "traffic.\n");
- brnf_deferred_hooks = 1;
+ "traffic is not supported anymore.\n");
+ if (hook_mask & (1 << NF_IP_LOCAL_OUT))
+ return 0;
}
return 1;
}
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
index d9010b16a1f..df37b912163 100644
--- a/net/netfilter/xt_state.c
+++ b/net/netfilter/xt_state.c
@@ -50,22 +50,18 @@ static int check(const char *tablename,
void *matchinfo,
unsigned int hook_mask)
{
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
if (nf_ct_l3proto_try_module_get(match->family) < 0) {
- printk(KERN_WARNING "can't load nf_conntrack support for "
+ printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", match->family);
return 0;
}
-#endif
return 1;
}
static void
destroy(const struct xt_match *match, void *matchinfo)
{
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
nf_ct_l3proto_module_put(match->family);
-#endif
}
static struct xt_match xt_state_match[] = {
@@ -91,7 +87,6 @@ static struct xt_match xt_state_match[] = {
static int __init xt_state_init(void)
{
- need_conntrack();
return xt_register_matches(xt_state_match, ARRAY_SIZE(xt_state_match));
}
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index 743b05734a4..73e0ff469bf 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -130,12 +130,12 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
if (nla->nla_type == NLBL_CIPSOV4_A_TAG) {
- if (iter > CIPSO_V4_TAG_MAXCNT)
+ if (iter >= CIPSO_V4_TAG_MAXCNT)
return -EINVAL;
doi_def->tags[iter++] = nla_get_u8(nla);
}
- if (iter < CIPSO_V4_TAG_MAXCNT)
- doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
+ while (iter < CIPSO_V4_TAG_MAXCNT)
+ doi_def->tags[iter++] = CIPSO_V4_TAG_INVALID;
return 0;
}
@@ -162,6 +162,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
struct nlattr *nla_b;
int nla_a_rem;
int nla_b_rem;
+ u32 iter;
if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
!info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
@@ -185,20 +186,31 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
ret_val = netlbl_cipsov4_add_common(info, doi_def);
if (ret_val != 0)
goto add_std_failure;
+ ret_val = -EINVAL;
nla_for_each_nested(nla_a,
info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
nla_a_rem)
if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
+ if (nla_validate_nested(nla_a,
+ NLBL_CIPSOV4_A_MAX,
+ netlbl_cipsov4_genl_policy) != 0)
+ goto add_std_failure;
nla_for_each_nested(nla_b, nla_a, nla_b_rem)
switch (nla_b->nla_type) {
case NLBL_CIPSOV4_A_MLSLVLLOC:
+ if (nla_get_u32(nla_b) >
+ CIPSO_V4_MAX_LOC_LVLS)
+ goto add_std_failure;
if (nla_get_u32(nla_b) >=
doi_def->map.std->lvl.local_size)
doi_def->map.std->lvl.local_size =
nla_get_u32(nla_b) + 1;
break;
case NLBL_CIPSOV4_A_MLSLVLREM:
+ if (nla_get_u32(nla_b) >
+ CIPSO_V4_MAX_REM_LVLS)
+ goto add_std_failure;
if (nla_get_u32(nla_b) >=
doi_def->map.std->lvl.cipso_size)
doi_def->map.std->lvl.cipso_size =
@@ -206,9 +218,6 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
break;
}
}
- if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS ||
- doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS)
- goto add_std_failure;
doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
sizeof(u32),
GFP_KERNEL);
@@ -223,6 +232,10 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
ret_val = -ENOMEM;
goto add_std_failure;
}
+ for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
+ doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
+ for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
+ doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
nla_for_each_nested(nla_a,
info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
nla_a_rem)
@@ -230,11 +243,6 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
struct nlattr *lvl_loc;
struct nlattr *lvl_rem;
- if (nla_validate_nested(nla_a,
- NLBL_CIPSOV4_A_MAX,
- netlbl_cipsov4_genl_policy) != 0)
- goto add_std_failure;
-
lvl_loc = nla_find_nested(nla_a,
NLBL_CIPSOV4_A_MLSLVLLOC);
lvl_rem = nla_find_nested(nla_a,
@@ -264,12 +272,18 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
nla_for_each_nested(nla_b, nla_a, nla_b_rem)
switch (nla_b->nla_type) {
case NLBL_CIPSOV4_A_MLSCATLOC:
+ if (nla_get_u32(nla_b) >
+ CIPSO_V4_MAX_LOC_CATS)
+ goto add_std_failure;
if (nla_get_u32(nla_b) >=
doi_def->map.std->cat.local_size)
doi_def->map.std->cat.local_size =
nla_get_u32(nla_b) + 1;
break;
case NLBL_CIPSOV4_A_MLSCATREM:
+ if (nla_get_u32(nla_b) >
+ CIPSO_V4_MAX_REM_CATS)
+ goto add_std_failure;
if (nla_get_u32(nla_b) >=
doi_def->map.std->cat.cipso_size)
doi_def->map.std->cat.cipso_size =
@@ -277,9 +291,6 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
break;
}
}
- if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS ||
- doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS)
- goto add_std_failure;
doi_def->map.std->cat.local = kcalloc(
doi_def->map.std->cat.local_size,
sizeof(u32),
@@ -296,6 +307,10 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
ret_val = -ENOMEM;
goto add_std_failure;
}
+ for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
+ doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
+ for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
+ doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
nla_for_each_nested(nla_a,
info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
nla_a_rem)
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 3baafb10f8f..383dd4e82ee 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -472,8 +472,7 @@ static int netlink_release(struct socket *sock)
NETLINK_URELEASE, &n);
}
- if (nlk->module)
- module_put(nlk->module);
+ module_put(nlk->module);
netlink_table_grab();
if (nlk->flags & NETLINK_KERNEL_SOCKET) {
@@ -699,7 +698,7 @@ static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid)
struct sock *netlink_getsockbyfilp(struct file *filp)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct sock *sock;
if (!S_ISSOCK(inode->i_mode))
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 1d50f801f18..43bbe2c9e49 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1377,6 +1377,15 @@ static struct notifier_block nr_dev_notifier = {
static struct net_device **dev_nr;
+static struct ax25_protocol nr_pid = {
+ .pid = AX25_P_NETROM,
+ .func = nr_route_frame
+};
+
+static struct ax25_linkfail nr_linkfail_notifier = {
+ .func = nr_link_failed,
+};
+
static int __init nr_proto_init(void)
{
int i;
@@ -1424,8 +1433,8 @@ static int __init nr_proto_init(void)
register_netdevice_notifier(&nr_dev_notifier);
- ax25_protocol_register(AX25_P_NETROM, nr_route_frame);
- ax25_linkfail_register(nr_link_failed);
+ ax25_register_pid(&nr_pid);
+ ax25_linkfail_register(&nr_linkfail_notifier);
#ifdef CONFIG_SYSCTL
nr_register_sysctl();
@@ -1474,7 +1483,7 @@ static void __exit nr_exit(void)
nr_unregister_sysctl();
#endif
- ax25_linkfail_release(nr_link_failed);
+ ax25_linkfail_release(&nr_linkfail_notifier);
ax25_protocol_release(AX25_P_NETROM);
unregister_netdevice_notifier(&nr_dev_notifier);
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
index 9b8eb54971a..4700d5225b7 100644
--- a/net/netrom/nr_dev.c
+++ b/net/netrom/nr_dev.c
@@ -128,25 +128,37 @@ static int nr_header(struct sk_buff *skb, struct net_device *dev, unsigned short
return -37;
}
-static int nr_set_mac_address(struct net_device *dev, void *addr)
+static int __must_check nr_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *sa = addr;
+ int err;
+
+ if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len))
+ return 0;
+
+ if (dev->flags & IFF_UP) {
+ err = ax25_listen_register((ax25_address *)sa->sa_data, NULL);
+ if (err)
+ return err;
- if (dev->flags & IFF_UP)
ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
+ }
memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
- if (dev->flags & IFF_UP)
- ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
-
return 0;
}
static int nr_open(struct net_device *dev)
{
+ int err;
+
+ err = ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
+ if (err)
+ return err;
+
netif_start_queue(dev);
- ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
+
return 0;
}
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index 0096105bcd4..8f88964099e 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -87,8 +87,9 @@ static void nr_remove_neigh(struct nr_neigh *);
* Add a new route to a node, and in the process add the node and the
* neighbour if it is new.
*/
-static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax25,
- ax25_digi *ax25_digi, struct net_device *dev, int quality, int obs_count)
+static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
+ ax25_address *ax25, ax25_digi *ax25_digi, struct net_device *dev,
+ int quality, int obs_count)
{
struct nr_node *nr_node;
struct nr_neigh *nr_neigh;
@@ -406,7 +407,8 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
/*
* Lock a neighbour with a quality.
*/
-static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
+static int __must_check nr_add_neigh(ax25_address *callsign,
+ ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
{
struct nr_neigh *nr_neigh;
@@ -777,9 +779,13 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
nr_src = (ax25_address *)(skb->data + 0);
nr_dest = (ax25_address *)(skb->data + 7);
- if (ax25 != NULL)
- nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
- ax25->ax25_dev->dev, 0, sysctl_netrom_obsolescence_count_initialiser);
+ if (ax25 != NULL) {
+ ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
+ ax25->ax25_dev->dev, 0,
+ sysctl_netrom_obsolescence_count_initialiser);
+ if (ret)
+ return ret;
+ }
if ((dev = nr_dev_get(nr_dest)) != NULL) { /* Its for me */
if (ax25 == NULL) /* Its from me */
@@ -844,6 +850,7 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
ret = (nr_neigh->ax25 != NULL);
nr_node_unlock(nr_node);
nr_node_put(nr_node);
+
return ret;
}
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index da73e8a8c18..a6fa48788e8 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -60,6 +60,7 @@
#include <linux/netdevice.h>
#include <linux/if_packet.h>
#include <linux/wireless.h>
+#include <linux/kernel.h>
#include <linux/kmod.h>
#include <net/ip.h>
#include <net/protocol.h>
@@ -200,7 +201,8 @@ struct packet_sock {
#endif
struct packet_type prot_hook;
spinlock_t bind_lock;
- char running; /* prot_hook is attached*/
+ unsigned int running:1, /* prot_hook is attached*/
+ auxdata:1;
int ifindex; /* bound device */
__be16 num;
#ifdef CONFIG_PACKET_MULTICAST
@@ -214,6 +216,16 @@ struct packet_sock {
#endif
};
+struct packet_skb_cb {
+ unsigned int origlen;
+ union {
+ struct sockaddr_pkt pkt;
+ struct sockaddr_ll ll;
+ } sa;
+};
+
+#define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb))
+
#ifdef CONFIG_PACKET_MMAP
static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position)
@@ -293,7 +305,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct
/* drop conntrack reference */
nf_reset(skb);
- spkt = (struct sockaddr_pkt*)skb->cb;
+ spkt = &PACKET_SKB_CB(skb)->sa.pkt;
skb_push(skb, skb->data-skb->mac.raw);
@@ -359,6 +371,10 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
if (dev == NULL)
goto out_unlock;
+ err = -ENETDOWN;
+ if (!(dev->flags & IFF_UP))
+ goto out_unlock;
+
/*
* You may not queue a frame bigger than the mtu. This is the lowest level
* raw protocol and you must do your own fragmentation at this level.
@@ -407,10 +423,6 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
if (err)
goto out_free;
- err = -ENETDOWN;
- if (!(dev->flags & IFF_UP))
- goto out_free;
-
/*
* Now send it
*/
@@ -428,24 +440,18 @@ out_unlock:
}
#endif
-static inline int run_filter(struct sk_buff *skb, struct sock *sk,
- unsigned *snaplen)
+static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk,
+ unsigned int res)
{
struct sk_filter *filter;
- int err = 0;
rcu_read_lock_bh();
filter = rcu_dereference(sk->sk_filter);
- if (filter != NULL) {
- err = sk_run_filter(skb, filter->insns, filter->len);
- if (!err)
- err = -EPERM;
- else if (*snaplen > err)
- *snaplen = err;
- }
+ if (filter != NULL)
+ res = sk_run_filter(skb, filter->insns, filter->len);
rcu_read_unlock_bh();
- return err;
+ return res;
}
/*
@@ -467,7 +473,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
struct packet_sock *po;
u8 * skb_head = skb->data;
int skb_len = skb->len;
- unsigned snaplen;
+ unsigned int snaplen, res;
if (skb->pkt_type == PACKET_LOOPBACK)
goto drop;
@@ -495,8 +501,11 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
snaplen = skb->len;
- if (run_filter(skb, sk, &snaplen) < 0)
+ res = run_filter(skb, sk, snaplen);
+ if (!res)
goto drop_n_restore;
+ if (snaplen > res)
+ snaplen = res;
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
(unsigned)sk->sk_rcvbuf)
@@ -515,7 +524,10 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
skb = nskb;
}
- sll = (struct sockaddr_ll*)skb->cb;
+ BUILD_BUG_ON(sizeof(*PACKET_SKB_CB(skb)) + MAX_ADDR_LEN - 8 >
+ sizeof(skb->cb));
+
+ sll = &PACKET_SKB_CB(skb)->sa.ll;
sll->sll_family = AF_PACKET;
sll->sll_hatype = dev->type;
sll->sll_protocol = skb->protocol;
@@ -526,6 +538,8 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
if (dev->hard_header_parse)
sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
+ PACKET_SKB_CB(skb)->origlen = skb->len;
+
if (pskb_trim(skb, snaplen))
goto drop_n_acct;
@@ -568,7 +582,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
struct tpacket_hdr *h;
u8 * skb_head = skb->data;
int skb_len = skb->len;
- unsigned snaplen;
+ unsigned int snaplen, res;
unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER;
unsigned short macoff, netoff;
struct sk_buff *copy_skb = NULL;
@@ -585,15 +599,19 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
else if (skb->pkt_type == PACKET_OUTGOING) {
/* Special case: outgoing packets have ll header at head */
skb_pull(skb, skb->nh.raw - skb->data);
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- status |= TP_STATUS_CSUMNOTREADY;
}
}
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ status |= TP_STATUS_CSUMNOTREADY;
+
snaplen = skb->len;
- if (run_filter(skb, sk, &snaplen) < 0)
+ res = run_filter(skb, sk, snaplen);
+ if (!res)
goto drop_n_restore;
+ if (snaplen > res)
+ snaplen = res;
if (sk->sk_type == SOCK_DGRAM) {
macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16;
@@ -738,6 +756,10 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock,
if (sock->type == SOCK_RAW)
reserve = dev->hard_header_len;
+ err = -ENETDOWN;
+ if (!(dev->flags & IFF_UP))
+ goto out_unlock;
+
err = -EMSGSIZE;
if (len > dev->mtu+reserve)
goto out_unlock;
@@ -770,10 +792,6 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock,
skb->dev = dev;
skb->priority = sk->sk_priority;
- err = -ENETDOWN;
- if (!(dev->flags & IFF_UP))
- goto out_free;
-
/*
* Now send it
*/
@@ -1092,7 +1110,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
* it in now.
*/
- sll = (struct sockaddr_ll*)skb->cb;
+ sll = &PACKET_SKB_CB(skb)->sa.ll;
if (sock->type == SOCK_PACKET)
msg->msg_namelen = sizeof(struct sockaddr_pkt);
else
@@ -1117,7 +1135,22 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
sock_recv_timestamp(msg, sk, skb);
if (msg->msg_name)
- memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
+ memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,
+ msg->msg_namelen);
+
+ if (pkt_sk(sk)->auxdata) {
+ struct tpacket_auxdata aux;
+
+ aux.tp_status = TP_STATUS_USER;
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ aux.tp_status |= TP_STATUS_CSUMNOTREADY;
+ aux.tp_len = PACKET_SKB_CB(skb)->origlen;
+ aux.tp_snaplen = skb->len;
+ aux.tp_mac = 0;
+ aux.tp_net = skb->nh.raw - skb->data;
+
+ put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
+ }
/*
* Free or return the buffer as appropriate. Again this
@@ -1317,6 +1350,7 @@ static int
packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
{
struct sock *sk = sock->sk;
+ struct packet_sock *po = pkt_sk(sk);
int ret;
if (level != SOL_PACKET)
@@ -1369,6 +1403,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
return 0;
}
#endif
+ case PACKET_AUXDATA:
+ {
+ int val;
+
+ if (optlen < sizeof(val))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, sizeof(val)))
+ return -EFAULT;
+
+ po->auxdata = !!val;
+ return 0;
+ }
default:
return -ENOPROTOOPT;
}
@@ -1378,8 +1424,11 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
int len;
+ int val;
struct sock *sk = sock->sk;
struct packet_sock *po = pkt_sk(sk);
+ void *data;
+ struct tpacket_stats st;
if (level != SOL_PACKET)
return -ENOPROTOOPT;
@@ -1392,9 +1441,6 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
switch(optname) {
case PACKET_STATISTICS:
- {
- struct tpacket_stats st;
-
if (len > sizeof(struct tpacket_stats))
len = sizeof(struct tpacket_stats);
spin_lock_bh(&sk->sk_receive_queue.lock);
@@ -1403,16 +1449,23 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
spin_unlock_bh(&sk->sk_receive_queue.lock);
st.tp_packets += st.tp_drops;
- if (copy_to_user(optval, &st, len))
- return -EFAULT;
+ data = &st;
+ break;
+ case PACKET_AUXDATA:
+ if (len > sizeof(int))
+ len = sizeof(int);
+ val = po->auxdata;
+
+ data = &val;
break;
- }
default:
return -ENOPROTOOPT;
}
if (put_user(len, optlen))
return -EFAULT;
+ if (copy_to_user(optval, data, len))
+ return -EFAULT;
return 0;
}
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 08a54285565..9e279464c9d 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1314,7 +1314,8 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
if (copy_from_user(&rose_callsign, argp, sizeof(ax25_address)))
return -EFAULT;
if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
- ax25_listen_register(&rose_callsign, NULL);
+ return ax25_listen_register(&rose_callsign, NULL);
+
return 0;
case SIOCRSGL2CALL:
@@ -1481,6 +1482,15 @@ static struct notifier_block rose_dev_notifier = {
static struct net_device **dev_rose;
+static struct ax25_protocol rose_pid = {
+ .pid = AX25_P_ROSE,
+ .func = rose_route_frame
+};
+
+static struct ax25_linkfail rose_linkfail_notifier = {
+ .func = rose_link_failed
+};
+
static int __init rose_proto_init(void)
{
int i;
@@ -1530,8 +1540,8 @@ static int __init rose_proto_init(void)
sock_register(&rose_family_ops);
register_netdevice_notifier(&rose_dev_notifier);
- ax25_protocol_register(AX25_P_ROSE, rose_route_frame);
- ax25_linkfail_register(rose_link_failed);
+ ax25_register_pid(&rose_pid);
+ ax25_linkfail_register(&rose_linkfail_notifier);
#ifdef CONFIG_SYSCTL
rose_register_sysctl();
@@ -1579,7 +1589,7 @@ static void __exit rose_exit(void)
rose_rt_free();
ax25_protocol_release(AX25_P_ROSE);
- ax25_linkfail_release(rose_link_failed);
+ ax25_linkfail_release(&rose_linkfail_notifier);
if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
ax25_listen_release(&rose_callsign, NULL);
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c
index 7c279e2659e..50824d345fa 100644
--- a/net/rose/rose_dev.c
+++ b/net/rose/rose_dev.c
@@ -93,20 +93,34 @@ static int rose_rebuild_header(struct sk_buff *skb)
static int rose_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *sa = addr;
+ int err;
- rose_del_loopback_node((rose_address *)dev->dev_addr);
+ if (!memcpy(dev->dev_addr, sa->sa_data, dev->addr_len))
+ return 0;
- memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+ if (dev->flags & IFF_UP) {
+ err = rose_add_loopback_node((rose_address *)dev->dev_addr);
+ if (err)
+ return err;
+
+ rose_del_loopback_node((rose_address *)dev->dev_addr);
+ }
- rose_add_loopback_node((rose_address *)dev->dev_addr);
+ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
return 0;
}
static int rose_open(struct net_device *dev)
{
+ int err;
+
+ err = rose_add_loopback_node((rose_address *)dev->dev_addr);
+ if (err)
+ return err;
+
netif_start_queue(dev);
- rose_add_loopback_node((rose_address *)dev->dev_addr);
+
return 0;
}
diff --git a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c
index 103b4d38f88..3e41bd93ab9 100644
--- a/net/rose/rose_loopback.c
+++ b/net/rose/rose_loopback.c
@@ -79,7 +79,8 @@ static void rose_loopback_timer(unsigned long param)
skb->h.raw = skb->data;
- if ((sk = rose_find_socket(lci_o, rose_loopback_neigh)) != NULL) {
+ sk = rose_find_socket(lci_o, &rose_loopback_neigh);
+ if (sk) {
if (rose_process_rx_frame(sk, skb) == 0)
kfree_skb(skb);
continue;
@@ -87,7 +88,7 @@ static void rose_loopback_timer(unsigned long param)
if (frametype == ROSE_CALL_REQUEST) {
if ((dev = rose_dev_get(dest)) != NULL) {
- if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0)
+ if (rose_rx_call_request(skb, dev, &rose_loopback_neigh, lci_o) == 0)
kfree_skb(skb);
} else {
kfree_skb(skb);
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index 7252344779a..8028c0d425d 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -46,13 +46,13 @@ static DEFINE_SPINLOCK(rose_neigh_list_lock);
static struct rose_route *rose_route_list;
static DEFINE_SPINLOCK(rose_route_list_lock);
-struct rose_neigh *rose_loopback_neigh;
+struct rose_neigh rose_loopback_neigh;
/*
* Add a new route to a node, and in the process add the node and the
* neighbour if it is new.
*/
-static int rose_add_node(struct rose_route_struct *rose_route,
+static int __must_check rose_add_node(struct rose_route_struct *rose_route,
struct net_device *dev)
{
struct rose_node *rose_node, *rose_tmpn, *rose_tmpp;
@@ -361,33 +361,30 @@ out:
/*
* Add the loopback neighbour.
*/
-int rose_add_loopback_neigh(void)
+void rose_add_loopback_neigh(void)
{
- if ((rose_loopback_neigh = kmalloc(sizeof(struct rose_neigh), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
+ struct rose_neigh *sn = &rose_loopback_neigh;
- rose_loopback_neigh->callsign = null_ax25_address;
- rose_loopback_neigh->digipeat = NULL;
- rose_loopback_neigh->ax25 = NULL;
- rose_loopback_neigh->dev = NULL;
- rose_loopback_neigh->count = 0;
- rose_loopback_neigh->use = 0;
- rose_loopback_neigh->dce_mode = 1;
- rose_loopback_neigh->loopback = 1;
- rose_loopback_neigh->number = rose_neigh_no++;
- rose_loopback_neigh->restarted = 1;
+ sn->callsign = null_ax25_address;
+ sn->digipeat = NULL;
+ sn->ax25 = NULL;
+ sn->dev = NULL;
+ sn->count = 0;
+ sn->use = 0;
+ sn->dce_mode = 1;
+ sn->loopback = 1;
+ sn->number = rose_neigh_no++;
+ sn->restarted = 1;
- skb_queue_head_init(&rose_loopback_neigh->queue);
+ skb_queue_head_init(&sn->queue);
- init_timer(&rose_loopback_neigh->ftimer);
- init_timer(&rose_loopback_neigh->t0timer);
+ init_timer(&sn->ftimer);
+ init_timer(&sn->t0timer);
spin_lock_bh(&rose_neigh_list_lock);
- rose_loopback_neigh->next = rose_neigh_list;
- rose_neigh_list = rose_loopback_neigh;
+ sn->next = rose_neigh_list;
+ rose_neigh_list = sn;
spin_unlock_bh(&rose_neigh_list_lock);
-
- return 0;
}
/*
@@ -421,13 +418,13 @@ int rose_add_loopback_node(rose_address *address)
rose_node->mask = 10;
rose_node->count = 1;
rose_node->loopback = 1;
- rose_node->neighbour[0] = rose_loopback_neigh;
+ rose_node->neighbour[0] = &rose_loopback_neigh;
/* Insert at the head of list. Address is always mask=10 */
rose_node->next = rose_node_list;
rose_node_list = rose_node;
- rose_loopback_neigh->count++;
+ rose_loopback_neigh.count++;
out:
spin_unlock_bh(&rose_node_list_lock);
@@ -458,7 +455,7 @@ void rose_del_loopback_node(rose_address *address)
rose_remove_node(rose_node);
- rose_loopback_neigh->count--;
+ rose_loopback_neigh.count--;
out:
spin_unlock_bh(&rose_node_list_lock);
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index a9608064a4c..4c68c718f5e 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -52,10 +52,11 @@ static struct tcf_hashinfo ipt_hash_info = {
static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
{
- struct ipt_target *target;
+ struct xt_target *target;
int ret = 0;
- target = xt_find_target(AF_INET, t->u.user.name, t->u.user.revision);
+ target = xt_request_find_target(AF_INET, t->u.user.name,
+ t->u.user.revision);
if (!target)
return -ENOENT;
@@ -63,9 +64,10 @@ static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int
ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
table, hook, 0, 0);
- if (ret)
+ if (ret) {
+ module_put(t->u.kernel.target->me);
return ret;
-
+ }
if (t->u.kernel.target->checkentry
&& !t->u.kernel.target->checkentry(table, NULL,
t->u.kernel.target, t->data,
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index ba82dfab604..f79a4f3d0a9 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -371,8 +371,6 @@ static void cbq_deactivate_class(struct cbq_class *this)
return;
}
}
-
- cl = cl_prev->next_alive;
return;
}
} while ((cl_prev = cl) != q->active[prio]);
@@ -1258,6 +1256,8 @@ static unsigned int cbq_drop(struct Qdisc* sch)
do {
if (cl->q->ops->drop && (len = cl->q->ops->drop(cl->q))) {
sch->q.qlen--;
+ if (!cl->q->q.qlen)
+ cbq_deactivate_class(cl);
return len;
}
} while ((cl = cl->next_alive) != cl_head);
@@ -1685,8 +1685,7 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
#endif
}
sch_tree_lock(sch);
- *old = cl->q;
- cl->q = new;
+ *old = xchg(&cl->q, new);
qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
qdisc_reset(*old);
sch_tree_unlock(sch);
@@ -1704,6 +1703,14 @@ cbq_leaf(struct Qdisc *sch, unsigned long arg)
return cl ? cl->q : NULL;
}
+static void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg)
+{
+ struct cbq_class *cl = (struct cbq_class *)arg;
+
+ if (cl->q->q.qlen == 0)
+ cbq_deactivate_class(cl);
+}
+
static unsigned long cbq_get(struct Qdisc *sch, u32 classid)
{
struct cbq_sched_data *q = qdisc_priv(sch);
@@ -1988,12 +1995,17 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
{
struct cbq_sched_data *q = qdisc_priv(sch);
struct cbq_class *cl = (struct cbq_class*)arg;
+ unsigned int qlen;
if (cl->filters || cl->children || cl == &q->link)
return -EBUSY;
sch_tree_lock(sch);
+ qlen = cl->q->q.qlen;
+ qdisc_reset(cl->q);
+ qdisc_tree_decrease_qlen(cl->q, qlen);
+
if (cl->next_alive)
cbq_deactivate_class(cl);
@@ -2084,6 +2096,7 @@ static void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
static struct Qdisc_class_ops cbq_class_ops = {
.graft = cbq_graft,
.leaf = cbq_leaf,
+ .qlen_notify = cbq_qlen_notify,
.get = cbq_get,
.put = cbq_put,
.change = cbq_change_class,
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index bc116bd6937..3b6e6a78092 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -209,7 +209,7 @@ static void dev_watchdog(unsigned long arg)
dev->name);
dev->tx_timeout(dev);
}
- if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
+ if (!mod_timer(&dev->watchdog_timer, round_jiffies(jiffies + dev->watchdog_timeo)))
dev_hold(dev);
}
}
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 215e68c2b61..15f23c5511a 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -147,6 +147,10 @@ struct htb_class {
psched_tdiff_t mbuffer; /* max wait time */
long tokens, ctokens; /* current number of tokens */
psched_time_t t_c; /* checkpoint time */
+
+ int prio; /* For parent to leaf return possible here */
+ int quantum; /* we do backup. Finally full replacement */
+ /* of un.leaf originals should be done. */
};
/* TODO: maybe compute rate when size is too large .. or drop ? */
@@ -1271,6 +1275,38 @@ static void htb_destroy_filters(struct tcf_proto **fl)
}
}
+static inline int htb_parent_last_child(struct htb_class *cl)
+{
+ if (!cl->parent)
+ /* the root class */
+ return 0;
+
+ if (!(cl->parent->children.next == &cl->sibling &&
+ cl->parent->children.prev == &cl->sibling))
+ /* not the last child */
+ return 0;
+
+ return 1;
+}
+
+static void htb_parent_to_leaf(struct htb_class *cl, struct Qdisc *new_q)
+{
+ struct htb_class *parent = cl->parent;
+
+ BUG_TRAP(!cl->level && cl->un.leaf.q && !cl->prio_activity);
+
+ parent->level = 0;
+ memset(&parent->un.inner, 0, sizeof(parent->un.inner));
+ INIT_LIST_HEAD(&parent->un.leaf.drop_list);
+ parent->un.leaf.q = new_q ? new_q : &noop_qdisc;
+ parent->un.leaf.quantum = parent->quantum;
+ parent->un.leaf.prio = parent->prio;
+ parent->tokens = parent->buffer;
+ parent->ctokens = parent->cbuffer;
+ PSCHED_GET_TIME(parent->t_c);
+ parent->cmode = HTB_CAN_SEND;
+}
+
static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl)
{
struct htb_sched *q = qdisc_priv(sch);
@@ -1328,6 +1364,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
struct htb_sched *q = qdisc_priv(sch);
struct htb_class *cl = (struct htb_class *)arg;
unsigned int qlen;
+ struct Qdisc *new_q = NULL;
+ int last_child = 0;
// TODO: why don't allow to delete subtree ? references ? does
// tc subsys quarantee us that in htb_destroy it holds no class
@@ -1335,6 +1373,12 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
if (!list_empty(&cl->children) || cl->filter_cnt)
return -EBUSY;
+ if (!cl->level && htb_parent_last_child(cl)) {
+ new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+ cl->parent->classid);
+ last_child = 1;
+ }
+
sch_tree_lock(sch);
/* delete from hash and active; remainder in destroy_class */
@@ -1349,6 +1393,9 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
if (cl->prio_activity)
htb_deactivate(q, cl);
+ if (last_child)
+ htb_parent_to_leaf(cl, new_q);
+
if (--cl->refcnt == 0)
htb_destroy_class(sch, cl);
@@ -1483,6 +1530,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
cl->un.leaf.quantum = hopt->quantum;
if ((cl->un.leaf.prio = hopt->prio) >= TC_HTB_NUMPRIO)
cl->un.leaf.prio = TC_HTB_NUMPRIO - 1;
+
+ /* backup for htb_parent_to_leaf */
+ cl->quantum = cl->un.leaf.quantum;
+ cl->prio = cl->un.leaf.prio;
}
cl->buffer = hopt->buffer;
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 2567b4c96c1..000e043ebd6 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -372,6 +372,20 @@ static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *
return 0;
}
+static int prio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
+ struct gnet_dump *d)
+{
+ struct prio_sched_data *q = qdisc_priv(sch);
+ struct Qdisc *cl_q;
+
+ cl_q = q->queues[cl - 1];
+ if (gnet_stats_copy_basic(d, &cl_q->bstats) < 0 ||
+ gnet_stats_copy_queue(d, &cl_q->qstats) < 0)
+ return -1;
+
+ return 0;
+}
+
static void prio_walk(struct Qdisc *sch, struct qdisc_walker *arg)
{
struct prio_sched_data *q = qdisc_priv(sch);
@@ -414,6 +428,7 @@ static struct Qdisc_class_ops prio_class_ops = {
.bind_tcf = prio_bind,
.unbind_tcf = prio_put,
.dump = prio_dump_class,
+ .dump_stats = prio_dump_class_stats,
};
static struct Qdisc_ops prio_qdisc_ops = {
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 459cda258a5..82844801e42 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -143,6 +143,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
(iph->protocol == IPPROTO_TCP ||
iph->protocol == IPPROTO_UDP ||
+ iph->protocol == IPPROTO_UDPLITE ||
iph->protocol == IPPROTO_SCTP ||
iph->protocol == IPPROTO_DCCP ||
iph->protocol == IPPROTO_ESP))
@@ -156,6 +157,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
h2 = iph->saddr.s6_addr32[3]^iph->nexthdr;
if (iph->nexthdr == IPPROTO_TCP ||
iph->nexthdr == IPPROTO_UDP ||
+ iph->nexthdr == IPPROTO_UDPLITE ||
iph->nexthdr == IPPROTO_SCTP ||
iph->nexthdr == IPPROTO_DCCP ||
iph->nexthdr == IPPROTO_ESP)
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index ad0057db0f9..5db95caed0a 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -298,6 +298,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
asoc->default_flags = sp->default_flags;
asoc->default_context = sp->default_context;
asoc->default_timetolive = sp->default_timetolive;
+ asoc->default_rcv_context = sp->default_rcv_context;
return asoc;
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 3c3e560087c..ef36be073a1 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -78,8 +78,44 @@
#include <asm/uaccess.h>
+/* Event handler for inet6 address addition/deletion events. */
+static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
+ void *ptr)
+{
+ struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
+ struct sctp_sockaddr_entry *addr;
+ struct list_head *pos, *temp;
+
+ switch (ev) {
+ case NETDEV_UP:
+ addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
+ if (addr) {
+ addr->a.v6.sin6_family = AF_INET6;
+ addr->a.v6.sin6_port = 0;
+ memcpy(&addr->a.v6.sin6_addr, &ifa->addr,
+ sizeof(struct in6_addr));
+ addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
+ list_add_tail(&addr->list, &sctp_local_addr_list);
+ }
+ break;
+ case NETDEV_DOWN:
+ list_for_each_safe(pos, temp, &sctp_local_addr_list) {
+ addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ if (ipv6_addr_equal(&addr->a.v6.sin6_addr, &ifa->addr)) {
+ list_del(pos);
+ kfree(addr);
+ break;
+ }
+ }
+
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
static struct notifier_block sctp_inet6addr_notifier = {
- .notifier_call = sctp_inetaddr_event,
+ .notifier_call = sctp_inet6addr_event,
};
/* ICMP error handler. */
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index f2ba8615895..0ef48126b11 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -163,7 +163,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
/* Extract our IP addresses from the system and stash them in the
* protocol structure.
*/
-static void __sctp_get_local_addr_list(void)
+static void sctp_get_local_addr_list(void)
{
struct net_device *dev;
struct list_head *pos;
@@ -179,17 +179,8 @@ static void __sctp_get_local_addr_list(void)
read_unlock(&dev_base_lock);
}
-static void sctp_get_local_addr_list(void)
-{
- unsigned long flags;
-
- sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
- __sctp_get_local_addr_list();
- sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
-}
-
/* Free the existing local addresses. */
-static void __sctp_free_local_addr_list(void)
+static void sctp_free_local_addr_list(void)
{
struct sctp_sockaddr_entry *addr;
struct list_head *pos, *temp;
@@ -201,27 +192,15 @@ static void __sctp_free_local_addr_list(void)
}
}
-/* Free the existing local addresses. */
-static void sctp_free_local_addr_list(void)
-{
- unsigned long flags;
-
- sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
- __sctp_free_local_addr_list();
- sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
-}
-
/* Copy the local addresses which are valid for 'scope' into 'bp'. */
int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
gfp_t gfp, int copy_flags)
{
struct sctp_sockaddr_entry *addr;
int error = 0;
- struct list_head *pos;
- unsigned long flags;
+ struct list_head *pos, *temp;
- sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
- list_for_each(pos, &sctp_local_addr_list) {
+ list_for_each_safe(pos, temp, &sctp_local_addr_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list);
if (sctp_in_scope(&addr->a, scope)) {
/* Now that the address is in scope, check to see if
@@ -242,7 +221,6 @@ int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
}
end_copy:
- sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
return error;
}
@@ -622,18 +600,36 @@ static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr));
}
-/* Event handler for inet address addition/deletion events.
- * Basically, whenever there is an event, we re-build our local address list.
- */
-int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
- void *ptr)
+/* Event handler for inet address addition/deletion events. */
+static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
+ void *ptr)
{
- unsigned long flags;
+ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+ struct sctp_sockaddr_entry *addr;
+ struct list_head *pos, *temp;
- sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
- __sctp_free_local_addr_list();
- __sctp_get_local_addr_list();
- sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
+ switch (ev) {
+ case NETDEV_UP:
+ addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
+ if (addr) {
+ addr->a.v4.sin_family = AF_INET;
+ addr->a.v4.sin_port = 0;
+ addr->a.v4.sin_addr.s_addr = ifa->ifa_local;
+ list_add_tail(&addr->list, &sctp_local_addr_list);
+ }
+ break;
+ case NETDEV_DOWN:
+ list_for_each_safe(pos, temp, &sctp_local_addr_list) {
+ addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ if (addr->a.v4.sin_addr.s_addr == ifa->ifa_local) {
+ list_del(pos);
+ kfree(addr);
+ break;
+ }
+ }
+
+ break;
+ }
return NOTIFY_DONE;
}
@@ -808,7 +804,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
NIPQUAD(((struct rtable *)skb->dst)->rt_dst));
SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
- return ip_queue_xmit(skb, skb->sk, ipfragok);
+ return ip_queue_xmit(skb, ipfragok);
}
static struct sctp_af sctp_ipv4_specific;
@@ -1172,13 +1168,12 @@ SCTP_STATIC __init int sctp_init(void)
/* Initialize the local address list. */
INIT_LIST_HEAD(&sctp_local_addr_list);
- spin_lock_init(&sctp_local_addr_lock);
+
+ sctp_get_local_addr_list();
/* Register notifier for inet address additions/deletions. */
register_inetaddr_notifier(&sctp_inetaddr_notifier);
- sctp_get_local_addr_list();
-
__unsafe(THIS_MODULE);
status = 0;
out:
@@ -1263,6 +1258,7 @@ module_exit(sctp_exit);
* __stringify doesn't likes enums, so use IPPROTO_SCTP value (132) directly.
*/
MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-132");
+MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-132");
MODULE_AUTHOR("Linux Kernel SCTP developers <lksctp-developers@lists.sourceforge.net>");
MODULE_DESCRIPTION("Support for the SCTP protocol (RFC2960)");
MODULE_LICENSE("GPL");
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 30927d3a597..0b1ddb1005a 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -124,8 +124,8 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,
padlen = len % 4;
err.length = htons(len);
len += padlen;
- sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err);
- chunk->subh.err_hdr = sctp_addto_chunk(chunk, paylen, payload);
+ chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err);
+ sctp_addto_chunk(chunk, paylen, payload);
}
/* 3.3.2 Initiation (INIT) (1)
@@ -184,7 +184,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
struct sctp_sock *sp;
sctp_supported_addrs_param_t sat;
__be16 types[2];
- sctp_adaption_ind_param_t aiparam;
+ sctp_adaptation_ind_param_t aiparam;
/* RFC 2960 3.3.2 Initiation (INIT) (1)
*
@@ -249,9 +249,9 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
if (sctp_prsctp_enable)
sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
- aiparam.param_hdr.type = SCTP_PARAM_ADAPTION_LAYER_IND;
+ aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
aiparam.param_hdr.length = htons(sizeof(aiparam));
- aiparam.adaption_ind = htonl(sp->adaption_ind);
+ aiparam.adaptation_ind = htonl(sp->adaptation_ind);
sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
nodata:
kfree(addrs.v);
@@ -269,7 +269,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
sctp_cookie_param_t *cookie;
int cookie_len;
size_t chunksize;
- sctp_adaption_ind_param_t aiparam;
+ sctp_adaptation_ind_param_t aiparam;
retval = NULL;
@@ -323,9 +323,9 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
if (asoc->peer.prsctp_capable)
sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
- aiparam.param_hdr.type = SCTP_PARAM_ADAPTION_LAYER_IND;
+ aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
aiparam.param_hdr.length = htons(sizeof(aiparam));
- aiparam.adaption_ind = htonl(sctp_sk(asoc->base.sk)->adaption_ind);
+ aiparam.adaptation_ind = htonl(sctp_sk(asoc->base.sk)->adaptation_ind);
sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
/* We need to remove the const qualifier at this point. */
@@ -1300,8 +1300,8 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
/* Remember PR-SCTP capability. */
cookie->c.prsctp_capable = asoc->peer.prsctp_capable;
- /* Save adaption indication in the cookie. */
- cookie->c.adaption_ind = asoc->peer.adaption_ind;
+ /* Save adaptation indication in the cookie. */
+ cookie->c.adaptation_ind = asoc->peer.adaptation_ind;
/* Set an expiration time for the cookie. */
do_gettimeofday(&cookie->c.expiration);
@@ -1512,7 +1512,7 @@ no_hmac:
retval->addip_serial = retval->c.initial_tsn;
retval->adv_peer_ack_point = retval->ctsn_ack_point;
retval->peer.prsctp_capable = retval->c.prsctp_capable;
- retval->peer.adaption_ind = retval->c.adaption_ind;
+ retval->peer.adaptation_ind = retval->c.adaptation_ind;
/* The INIT stuff will be done by the side effects. */
return retval;
@@ -1562,7 +1562,7 @@ static int sctp_process_missing_param(const struct sctp_association *asoc,
if (*errp) {
report.num_missing = htonl(1);
report.type = paramtype;
- sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM,
+ sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM,
&report, sizeof(report));
}
@@ -1743,7 +1743,7 @@ static int sctp_verify_param(const struct sctp_association *asoc,
case SCTP_PARAM_HEARTBEAT_INFO:
case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
case SCTP_PARAM_ECN_CAPABLE:
- case SCTP_PARAM_ADAPTION_LAYER_IND:
+ case SCTP_PARAM_ADAPTATION_LAYER_IND:
break;
case SCTP_PARAM_HOST_NAME_ADDRESS:
@@ -1775,7 +1775,9 @@ int sctp_verify_init(const struct sctp_association *asoc,
/* Verify stream values are non-zero. */
if ((0 == peer_init->init_hdr.num_outbound_streams) ||
- (0 == peer_init->init_hdr.num_inbound_streams)) {
+ (0 == peer_init->init_hdr.num_inbound_streams) ||
+ (0 == peer_init->init_hdr.init_tag) ||
+ (SCTP_DEFAULT_MINWINDOW > ntohl(peer_init->init_hdr.a_rwnd))) {
sctp_process_inv_mandatory(asoc, chunk, errp);
return 0;
@@ -2098,8 +2100,8 @@ static int sctp_process_param(struct sctp_association *asoc,
asoc->peer.ecn_capable = 1;
break;
- case SCTP_PARAM_ADAPTION_LAYER_IND:
- asoc->peer.adaption_ind = param.aind->adaption_ind;
+ case SCTP_PARAM_ADAPTATION_LAYER_IND:
+ asoc->peer.adaptation_ind = param.aind->adaptation_ind;
break;
case SCTP_PARAM_FWD_TSN_SUPPORT:
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 7bbc6156e45..6db77d1329f 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -217,7 +217,7 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force,
asoc->peer.sack_needed = 0;
- error = sctp_outq_tail(&asoc->outqueue, sack);
+ sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(sack));
/* Stop the SACK timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
@@ -621,7 +621,13 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
/* The receiver of the HEARTBEAT ACK should also perform an
* RTT measurement for that destination transport address
* using the time value carried in the HEARTBEAT ACK chunk.
+ * If the transport's rto_pending variable has been cleared,
+ * it was most likely due to a retransmit. However, we want
+ * to re-enable it to properly update the rto.
*/
+ if (t->rto_pending == 0)
+ t->rto_pending = 1;
+
hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;
sctp_transport_update_rto(t, (jiffies - hbinfo->sent_at));
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 27cc444aaf1..fbbc9e6a3b7 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -440,7 +440,6 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
{
struct sctp_chunk *chunk = arg;
sctp_init_chunk_t *initchunk;
- __u32 init_tag;
struct sctp_chunk *err_chunk;
struct sctp_packet *packet;
sctp_error_t error;
@@ -462,24 +461,6 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
/* Grab the INIT header. */
chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
- init_tag = ntohl(chunk->subh.init_hdr->init_tag);
-
- /* Verification Tag: 3.3.3
- * If the value of the Initiate Tag in a received INIT ACK
- * chunk is found to be 0, the receiver MUST treat it as an
- * error and close the association by transmitting an ABORT.
- */
- if (!init_tag) {
- struct sctp_chunk *reply = sctp_make_abort(asoc, chunk, 0);
- if (!reply)
- goto nomem;
-
- sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
- return sctp_stop_t1_and_abort(commands, SCTP_ERROR_INV_PARAM,
- ECONNREFUSED, asoc,
- chunk->transport);
- }
-
/* Verify the INIT chunk before processing it. */
err_chunk = NULL;
if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
@@ -550,9 +531,6 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
SCTP_CHUNK(err_chunk));
return SCTP_DISPOSITION_CONSUME;
-
-nomem:
- return SCTP_DISPOSITION_NOMEM;
}
/*
@@ -688,12 +666,12 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
goto nomem_ev;
/* Sockets API Draft Section 5.3.1.6
- * When a peer sends a Adaption Layer Indication parameter , SCTP
+ * When a peer sends a Adaptation Layer Indication parameter , SCTP
* delivers this notification to inform the application that of the
- * peers requested adaption layer.
+ * peers requested adaptation layer.
*/
- if (new_asoc->peer.adaption_ind) {
- ai_ev = sctp_ulpevent_make_adaption_indication(new_asoc,
+ if (new_asoc->peer.adaptation_ind) {
+ ai_ev = sctp_ulpevent_make_adaptation_indication(new_asoc,
GFP_ATOMIC);
if (!ai_ev)
goto nomem_aiev;
@@ -820,12 +798,12 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
/* Sockets API Draft Section 5.3.1.6
- * When a peer sends a Adaption Layer Indication parameter , SCTP
+ * When a peer sends a Adaptation Layer Indication parameter , SCTP
* delivers this notification to inform the application that of the
- * peers requested adaption layer.
+ * peers requested adaptation layer.
*/
- if (asoc->peer.adaption_ind) {
- ev = sctp_ulpevent_make_adaption_indication(asoc, GFP_ATOMIC);
+ if (asoc->peer.adaptation_ind) {
+ ev = sctp_ulpevent_make_adaptation_indication(asoc, GFP_ATOMIC);
if (!ev)
goto nomem;
@@ -1553,6 +1531,28 @@ sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const struct sctp_endpoint *ep,
}
+/*
+ * Unexpected INIT-ACK handler.
+ *
+ * Section 5.2.3
+ * If an INIT ACK received by an endpoint in any state other than the
+ * COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk.
+ * An unexpected INIT ACK usually indicates the processing of an old or
+ * duplicated INIT chunk.
+*/
+sctp_disposition_t sctp_sf_do_5_2_3_initack(const struct sctp_endpoint *ep,
+ const struct sctp_association *asoc,
+ const sctp_subtype_t type,
+ void *arg, sctp_cmd_seq_t *commands)
+{
+ /* Per the above section, we'll discard the chunk if we have an
+ * endpoint. If this is an OOTB INIT-ACK, treat it as such.
+ */
+ if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
+ return sctp_sf_ootb(ep, asoc, type, arg, commands);
+ else
+ return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+}
/* Unexpected COOKIE-ECHO handler for peer restart (Table 2, action 'A')
*
@@ -1698,12 +1698,12 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
/* Sockets API Draft Section 5.3.1.6
- * When a peer sends a Adaption Layer Indication parameter , SCTP
+ * When a peer sends a Adaptation Layer Indication parameter , SCTP
* delivers this notification to inform the application that of the
- * peers requested adaption layer.
+ * peers requested adaptation layer.
*/
- if (asoc->peer.adaption_ind) {
- ev = sctp_ulpevent_make_adaption_indication(asoc, GFP_ATOMIC);
+ if (asoc->peer.adaptation_ind) {
+ ev = sctp_ulpevent_make_adaptation_indication(asoc, GFP_ATOMIC);
if (!ev)
goto nomem_ev;
@@ -1791,12 +1791,12 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
goto nomem;
/* Sockets API Draft Section 5.3.1.6
- * When a peer sends a Adaption Layer Indication parameter,
+ * When a peer sends a Adaptation Layer Indication parameter,
* SCTP delivers this notification to inform the application
- * that of the peers requested adaption layer.
+ * that of the peers requested adaptation layer.
*/
- if (asoc->peer.adaption_ind) {
- ai_ev = sctp_ulpevent_make_adaption_indication(asoc,
+ if (asoc->peer.adaptation_ind) {
+ ai_ev = sctp_ulpevent_make_adaptation_indication(asoc,
GFP_ATOMIC);
if (!ai_ev)
goto nomem;
diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c
index 733dd87b3a7..5f6cc7aa661 100644
--- a/net/sctp/sm_statetable.c
+++ b/net/sctp/sm_statetable.c
@@ -152,7 +152,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_EMPTY */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \
- TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
+ TYPE_SCTP_FUNC(sctp_sf_do_5_2_3_initack), \
/* SCTP_STATE_COOKIE_WAIT */ \
TYPE_SCTP_FUNC(sctp_sf_do_5_1C_ack), \
/* SCTP_STATE_COOKIE_ECHOED */ \
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 1e8132b8c4d..388d0fb1a37 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2731,17 +2731,57 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
return err;
}
-static int sctp_setsockopt_adaption_layer(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval,
int optlen)
{
- struct sctp_setadaption adaption;
+ struct sctp_setadaptation adaptation;
- if (optlen != sizeof(struct sctp_setadaption))
+ if (optlen != sizeof(struct sctp_setadaptation))
return -EINVAL;
- if (copy_from_user(&adaption, optval, optlen))
+ if (copy_from_user(&adaptation, optval, optlen))
return -EFAULT;
- sctp_sk(sk)->adaption_ind = adaption.ssb_adaption_ind;
+ sctp_sk(sk)->adaptation_ind = adaptation.ssb_adaptation_ind;
+
+ return 0;
+}
+
+/*
+ * 7.1.29. Set or Get the default context (SCTP_CONTEXT)
+ *
+ * The context field in the sctp_sndrcvinfo structure is normally only
+ * used when a failed message is retrieved holding the value that was
+ * sent down on the actual send call. This option allows the setting of
+ * a default context on an association basis that will be received on
+ * reading messages from the peer. This is especially helpful in the
+ * one-2-many model for an application to keep some reference to an
+ * internal state machine that is processing messages on the
+ * association. Note that the setting of this value only effects
+ * received messages from the peer and does not effect the value that is
+ * saved with outbound messages.
+ */
+static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
+ int optlen)
+{
+ struct sctp_assoc_value params;
+ struct sctp_sock *sp;
+ struct sctp_association *asoc;
+
+ if (optlen != sizeof(struct sctp_assoc_value))
+ return -EINVAL;
+ if (copy_from_user(&params, optval, optlen))
+ return -EFAULT;
+
+ sp = sctp_sk(sk);
+
+ if (params.assoc_id != 0) {
+ asoc = sctp_id2assoc(sk, params.assoc_id);
+ if (!asoc)
+ return -EINVAL;
+ asoc->default_rcv_context = params.assoc_value;
+ } else {
+ sp->default_rcv_context = params.assoc_value;
+ }
return 0;
}
@@ -2854,8 +2894,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_MAXSEG:
retval = sctp_setsockopt_maxseg(sk, optval, optlen);
break;
- case SCTP_ADAPTION_LAYER:
- retval = sctp_setsockopt_adaption_layer(sk, optval, optlen);
+ case SCTP_ADAPTATION_LAYER:
+ retval = sctp_setsockopt_adaptation_layer(sk, optval, optlen);
+ break;
+ case SCTP_CONTEXT:
+ retval = sctp_setsockopt_context(sk, optval, optlen);
break;
default:
@@ -3016,6 +3059,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->default_context = 0;
sp->default_timetolive = 0;
+ sp->default_rcv_context = 0;
+
/* Initialize default setup parameters. These parameters
* can be modified with the SCTP_INITMSG socket option or
* overridden by the SCTP_INIT CMSG.
@@ -3078,7 +3123,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* User specified fragmentation limit. */
sp->user_frag = 0;
- sp->adaption_ind = 0;
+ sp->adaptation_ind = 0;
sp->pf = sctp_get_pf_specific(sk->sk_family);
@@ -3821,10 +3866,9 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
sctp_assoc_t id;
struct sctp_bind_addr *bp;
struct sctp_association *asoc;
- struct list_head *pos;
+ struct list_head *pos, *temp;
struct sctp_sockaddr_entry *addr;
rwlock_t *addr_lock;
- unsigned long flags;
int cnt = 0;
if (len != sizeof(sctp_assoc_t))
@@ -3859,8 +3903,7 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
addr = list_entry(bp->address_list.next,
struct sctp_sockaddr_entry, list);
if (sctp_is_any(&addr->a)) {
- sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
- list_for_each(pos, &sctp_local_addr_list) {
+ list_for_each_safe(pos, temp, &sctp_local_addr_list) {
addr = list_entry(pos,
struct sctp_sockaddr_entry,
list);
@@ -3869,8 +3912,6 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
continue;
cnt++;
}
- sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
- flags);
} else {
cnt = 1;
}
@@ -3892,15 +3933,13 @@ done:
static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs,
void __user *to)
{
- struct list_head *pos;
+ struct list_head *pos, *next;
struct sctp_sockaddr_entry *addr;
- unsigned long flags;
union sctp_addr temp;
int cnt = 0;
int addrlen;
- sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
- list_for_each(pos, &sctp_local_addr_list) {
+ list_for_each_safe(pos, next, &sctp_local_addr_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list);
if ((PF_INET == sk->sk_family) &&
(AF_INET6 == addr->a.sa.sa_family))
@@ -3909,16 +3948,13 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
&temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
- if (copy_to_user(to, &temp, addrlen)) {
- sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
- flags);
+ if (copy_to_user(to, &temp, addrlen))
return -EFAULT;
- }
+
to += addrlen;
cnt ++;
if (cnt >= max_addrs) break;
}
- sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
return cnt;
}
@@ -3926,15 +3962,13 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
void __user **to, size_t space_left)
{
- struct list_head *pos;
+ struct list_head *pos, *next;
struct sctp_sockaddr_entry *addr;
- unsigned long flags;
union sctp_addr temp;
int cnt = 0;
int addrlen;
- sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
- list_for_each(pos, &sctp_local_addr_list) {
+ list_for_each_safe(pos, next, &sctp_local_addr_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list);
if ((PF_INET == sk->sk_family) &&
(AF_INET6 == addr->a.sa.sa_family))
@@ -3945,16 +3979,13 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
if(space_left<addrlen)
return -ENOMEM;
- if (copy_to_user(*to, &temp, addrlen)) {
- sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
- flags);
+ if (copy_to_user(*to, &temp, addrlen))
return -EFAULT;
- }
+
*to += addrlen;
cnt ++;
space_left -= addrlen;
}
- sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
return cnt;
}
@@ -4179,21 +4210,21 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
}
/*
- * 7.1.11 Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER)
+ * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER)
*
- * Requests that the local endpoint set the specified Adaption Layer
+ * Requests that the local endpoint set the specified Adaptation Layer
* Indication parameter for all future INIT and INIT-ACK exchanges.
*/
-static int sctp_getsockopt_adaption_layer(struct sock *sk, int len,
+static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
char __user *optval, int __user *optlen)
{
- struct sctp_setadaption adaption;
+ struct sctp_setadaptation adaptation;
- if (len != sizeof(struct sctp_setadaption))
+ if (len != sizeof(struct sctp_setadaptation))
return -EINVAL;
- adaption.ssb_adaption_ind = sctp_sk(sk)->adaption_ind;
- if (copy_to_user(optval, &adaption, len))
+ adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind;
+ if (copy_to_user(optval, &adaptation, len))
return -EFAULT;
return 0;
@@ -4435,6 +4466,42 @@ static int sctp_getsockopt_mappedv4(struct sock *sk, int len,
}
/*
+ * 7.1.29. Set or Get the default context (SCTP_CONTEXT)
+ * (chapter and verse is quoted at sctp_setsockopt_context())
+ */
+static int sctp_getsockopt_context(struct sock *sk, int len,
+ char __user *optval, int __user *optlen)
+{
+ struct sctp_assoc_value params;
+ struct sctp_sock *sp;
+ struct sctp_association *asoc;
+
+ if (len != sizeof(struct sctp_assoc_value))
+ return -EINVAL;
+
+ if (copy_from_user(&params, optval, len))
+ return -EFAULT;
+
+ sp = sctp_sk(sk);
+
+ if (params.assoc_id != 0) {
+ asoc = sctp_id2assoc(sk, params.assoc_id);
+ if (!asoc)
+ return -EINVAL;
+ params.assoc_value = asoc->default_rcv_context;
+ } else {
+ params.assoc_value = sp->default_rcv_context;
+ }
+
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, &params, len))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
* 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
*
* This socket option specifies the maximum size to put in any outgoing
@@ -4568,10 +4635,13 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
retval = sctp_getsockopt_peer_addr_info(sk, len, optval,
optlen);
break;
- case SCTP_ADAPTION_LAYER:
- retval = sctp_getsockopt_adaption_layer(sk, len, optval,
+ case SCTP_ADAPTATION_LAYER:
+ retval = sctp_getsockopt_adaptation_layer(sk, len, optval,
optlen);
break;
+ case SCTP_CONTEXT:
+ retval = sctp_getsockopt_context(sk, len, optval, optlen);
+ break;
default:
retval = -ENOPROTOOPT;
break;
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index e255a709f1b..445e07a7ac4 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -609,31 +609,31 @@ fail:
return NULL;
}
-/* Create and initialize a SCTP_ADAPTION_INDICATION notification.
+/* Create and initialize a SCTP_ADAPTATION_INDICATION notification.
*
* Socket Extensions for SCTP
- * 5.3.1.6 SCTP_ADAPTION_INDICATION
+ * 5.3.1.6 SCTP_ADAPTATION_INDICATION
*/
-struct sctp_ulpevent *sctp_ulpevent_make_adaption_indication(
+struct sctp_ulpevent *sctp_ulpevent_make_adaptation_indication(
const struct sctp_association *asoc, gfp_t gfp)
{
struct sctp_ulpevent *event;
- struct sctp_adaption_event *sai;
+ struct sctp_adaptation_event *sai;
struct sk_buff *skb;
- event = sctp_ulpevent_new(sizeof(struct sctp_adaption_event),
+ event = sctp_ulpevent_new(sizeof(struct sctp_adaptation_event),
MSG_NOTIFICATION, gfp);
if (!event)
goto fail;
skb = sctp_event2skb(event);
- sai = (struct sctp_adaption_event *)
- skb_put(skb, sizeof(struct sctp_adaption_event));
+ sai = (struct sctp_adaptation_event *)
+ skb_put(skb, sizeof(struct sctp_adaptation_event));
- sai->sai_type = SCTP_ADAPTION_INDICATION;
+ sai->sai_type = SCTP_ADAPTATION_INDICATION;
sai->sai_flags = 0;
- sai->sai_length = sizeof(struct sctp_adaption_event);
- sai->sai_adaption_ind = asoc->peer.adaption_ind;
+ sai->sai_length = sizeof(struct sctp_adaptation_event);
+ sai->sai_adaptation_ind = asoc->peer.adaptation_ind;
sctp_ulpevent_set_owner(event, asoc);
sai->sai_assoc_id = sctp_assoc2id(asoc);
@@ -849,8 +849,10 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
*/
sinfo.sinfo_assoc_id = sctp_assoc2id(event->asoc);
+ /* context value that is set via SCTP_CONTEXT socket option. */
+ sinfo.sinfo_context = event->asoc->default_rcv_context;
+
/* These fields are not used while receiving. */
- sinfo.sinfo_context = 0;
sinfo.sinfo_timetolive = 0;
put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
diff --git a/net/socket.c b/net/socket.c
index 29ea1de43ec..5f374e1ff52 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -362,20 +362,20 @@ static int sock_attach_fd(struct socket *sock, struct file *file)
this.name = name;
this.hash = 0;
- file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
- if (unlikely(!file->f_dentry))
+ file->f_path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
+ if (unlikely(!file->f_path.dentry))
return -ENOMEM;
- file->f_dentry->d_op = &sockfs_dentry_operations;
+ file->f_path.dentry->d_op = &sockfs_dentry_operations;
/*
* We dont want to push this dentry into global dentry hash table.
* We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
* This permits a working /proc/$pid/fd/XXX on sockets
*/
- file->f_dentry->d_flags &= ~DCACHE_UNHASHED;
- d_instantiate(file->f_dentry, SOCK_INODE(sock));
- file->f_vfsmnt = mntget(sock_mnt);
- file->f_mapping = file->f_dentry->d_inode->i_mapping;
+ file->f_path.dentry->d_flags &= ~DCACHE_UNHASHED;
+ d_instantiate(file->f_path.dentry, SOCK_INODE(sock));
+ file->f_path.mnt = mntget(sock_mnt);
+ file->f_mapping = file->f_path.dentry->d_inode->i_mapping;
sock->file = file;
file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
@@ -407,24 +407,11 @@ int sock_map_fd(struct socket *sock)
static struct socket *sock_from_file(struct file *file, int *err)
{
- struct inode *inode;
- struct socket *sock;
-
if (file->f_op == &socket_file_ops)
return file->private_data; /* set in sock_map_fd */
- inode = file->f_dentry->d_inode;
- if (!S_ISSOCK(inode->i_mode)) {
- *err = -ENOTSOCK;
- return NULL;
- }
-
- sock = SOCKET_I(inode);
- if (sock->file != file) {
- printk(KERN_ERR "socki_lookup: socket file changed!\n");
- sock->file = file;
- }
- return sock;
+ *err = -ENOTSOCK;
+ return NULL;
}
/**
@@ -1527,8 +1514,9 @@ asmlinkage long sys_sendto(int fd, void __user *buff, size_t len,
struct file *sock_file;
sock_file = fget_light(fd, &fput_needed);
+ err = -EBADF;
if (!sock_file)
- return -EBADF;
+ goto out;
sock = sock_from_file(sock_file, &err);
if (!sock)
@@ -1555,6 +1543,7 @@ asmlinkage long sys_sendto(int fd, void __user *buff, size_t len,
out_put:
fput_light(sock_file, fput_needed);
+out:
return err;
}
@@ -1586,12 +1575,13 @@ asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size,
int fput_needed;
sock_file = fget_light(fd, &fput_needed);
+ err = -EBADF;
if (!sock_file)
- return -EBADF;
+ goto out;
sock = sock_from_file(sock_file, &err);
if (!sock)
- goto out;
+ goto out_put;
msg.msg_control = NULL;
msg.msg_controllen = 0;
@@ -1610,8 +1600,9 @@ asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size,
if (err2 < 0)
err = err2;
}
-out:
+out_put:
fput_light(sock_file, fput_needed);
+out:
return err;
}
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index a02ecc1f230..e1a104abb78 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -501,7 +501,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
if (!buf)
goto out;
- clnt = RPC_I(filp->f_dentry->d_inode)->private;
+ clnt = RPC_I(filp->f_path.dentry->d_inode)->private;
err = -EFAULT;
if (copy_from_user(buf, src, mlen))
goto err;
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
index 41465072d0b..8ef3f1c1943 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
@@ -228,7 +228,7 @@ static int __init init_spkm3_module(void)
status = gss_mech_register(&gss_spkm3_mech);
if (status)
printk("Failed to register spkm3 gss mechanism!\n");
- return 0;
+ return status;
}
static void __exit cleanup_spkm3_module(void)
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 700353b330f..066c64a97fd 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -804,19 +804,19 @@ unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
integ_len = svc_getnl(&buf->head[0]);
if (integ_len & 3)
- goto out;
+ return stat;
if (integ_len > buf->len)
- goto out;
+ return stat;
if (xdr_buf_subsegment(buf, &integ_buf, 0, integ_len))
BUG();
/* copy out mic... */
if (read_u32_from_xdr_buf(buf, integ_len, &mic.len))
BUG();
if (mic.len > RPC_MAX_AUTH_SIZE)
- goto out;
+ return stat;
mic.data = kmalloc(mic.len, GFP_KERNEL);
if (!mic.data)
- goto out;
+ return stat;
if (read_bytes_from_xdr_buf(buf, integ_len + 4, mic.data, mic.len))
goto out;
maj_stat = gss_verify_mic(ctx, &integ_buf, &mic);
@@ -826,6 +826,7 @@ unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
goto out;
stat = 0;
out:
+ kfree(mic.data);
return stat;
}
@@ -1065,7 +1066,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
}
switch(cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
case -EAGAIN:
- goto drop;
+ case -ETIMEDOUT:
case -ENOENT:
goto drop;
case 0:
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index d96fd466a9a..14274490f92 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -34,7 +34,7 @@
#define RPCDBG_FACILITY RPCDBG_CACHE
-static void cache_defer_req(struct cache_req *req, struct cache_head *item);
+static int cache_defer_req(struct cache_req *req, struct cache_head *item);
static void cache_revisit_request(struct cache_head *item);
static void cache_init(struct cache_head *h)
@@ -185,6 +185,7 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h);
*
* Returns 0 if the cache_head can be used, or cache_puts it and returns
* -EAGAIN if upcall is pending,
+ * -ETIMEDOUT if upcall failed and should be retried,
* -ENOENT if cache entry was negative
*/
int cache_check(struct cache_detail *detail,
@@ -236,7 +237,8 @@ int cache_check(struct cache_detail *detail,
}
if (rv == -EAGAIN)
- cache_defer_req(rqstp, h);
+ if (cache_defer_req(rqstp, h) != 0)
+ rv = -ETIMEDOUT;
if (rv)
cache_put(h, detail);
@@ -523,14 +525,21 @@ static LIST_HEAD(cache_defer_list);
static struct list_head cache_defer_hash[DFR_HASHSIZE];
static int cache_defer_cnt;
-static void cache_defer_req(struct cache_req *req, struct cache_head *item)
+static int cache_defer_req(struct cache_req *req, struct cache_head *item)
{
struct cache_deferred_req *dreq;
int hash = DFR_HASH(item);
+ if (cache_defer_cnt >= DFR_MAX) {
+ /* too much in the cache, randomly drop this one,
+ * or continue and drop the oldest below
+ */
+ if (net_random()&1)
+ return -ETIMEDOUT;
+ }
dreq = req->defer(req);
if (dreq == NULL)
- return;
+ return -ETIMEDOUT;
dreq->item = item;
dreq->recv_time = get_seconds();
@@ -546,17 +555,8 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item)
/* it is in, now maybe clean up */
dreq = NULL;
if (++cache_defer_cnt > DFR_MAX) {
- /* too much in the cache, randomly drop
- * first or last
- */
- if (net_random()&1)
- dreq = list_entry(cache_defer_list.next,
- struct cache_deferred_req,
- recent);
- else
- dreq = list_entry(cache_defer_list.prev,
- struct cache_deferred_req,
- recent);
+ dreq = list_entry(cache_defer_list.prev,
+ struct cache_deferred_req, recent);
list_del(&dreq->recent);
list_del(&dreq->hash);
cache_defer_cnt--;
@@ -571,6 +571,7 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item)
/* must have just been validated... */
cache_revisit_request(item);
}
+ return 0;
}
static void cache_revisit_request(struct cache_head *item)
@@ -670,7 +671,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
struct cache_reader *rp = filp->private_data;
struct cache_request *rq;
- struct cache_detail *cd = PDE(filp->f_dentry->d_inode)->data;
+ struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
int err;
if (count == 0)
@@ -747,7 +748,7 @@ cache_write(struct file *filp, const char __user *buf, size_t count,
loff_t *ppos)
{
int err;
- struct cache_detail *cd = PDE(filp->f_dentry->d_inode)->data;
+ struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
if (count == 0)
return 0;
@@ -778,7 +779,7 @@ cache_poll(struct file *filp, poll_table *wait)
unsigned int mask;
struct cache_reader *rp = filp->private_data;
struct cache_queue *cq;
- struct cache_detail *cd = PDE(filp->f_dentry->d_inode)->data;
+ struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
poll_wait(filp, &queue_wait, wait);
@@ -1254,7 +1255,7 @@ static struct file_operations content_file_operations = {
static ssize_t read_flush(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct cache_detail *cd = PDE(file->f_dentry->d_inode)->data;
+ struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data;
char tbuf[20];
unsigned long p = *ppos;
int len;
@@ -1275,7 +1276,7 @@ static ssize_t read_flush(struct file *file, char __user *buf,
static ssize_t write_flush(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
- struct cache_detail *cd = PDE(file->f_dentry->d_inode)->data;
+ struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data;
char tbuf[20];
char *ep;
long flushtime;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index aba528b9ae7..16c9fbc1db6 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -490,16 +490,14 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
/* Set up the call info struct and execute the task */
status = task->tk_status;
- if (status != 0) {
- rpc_release_task(task);
+ if (status != 0)
goto out;
- }
atomic_inc(&task->tk_count);
status = rpc_execute(task);
if (status == 0)
status = task->tk_status;
- rpc_put_task(task);
out:
+ rpc_put_task(task);
rpc_restore_sigmask(&oldset);
return status;
}
@@ -537,7 +535,7 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
if (status == 0)
rpc_execute(task);
else
- rpc_release_task(task);
+ rpc_put_task(task);
rpc_restore_sigmask(&oldset);
return status;
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 19703aa9659..89273d35e0c 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -214,7 +214,7 @@ out:
static ssize_t
rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct rpc_inode *rpci = RPC_I(inode);
struct rpc_pipe_msg *msg;
int res = 0;
@@ -257,7 +257,7 @@ out_unlock:
static ssize_t
rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct rpc_inode *rpci = RPC_I(inode);
int res;
@@ -275,7 +275,7 @@ rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait)
struct rpc_inode *rpci;
unsigned int mask = 0;
- rpci = RPC_I(filp->f_dentry->d_inode);
+ rpci = RPC_I(filp->f_path.dentry->d_inode);
poll_wait(filp, &rpci->waitq, wait);
mask = POLLOUT | POLLWRNORM;
@@ -290,7 +290,7 @@ static int
rpc_pipe_ioctl(struct inode *ino, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
+ struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
int len;
switch (cmd) {
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 79bc4cdf5d4..fc083f0b354 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -42,6 +42,7 @@ static mempool_t *rpc_buffer_mempool __read_mostly;
static void __rpc_default_timer(struct rpc_task *task);
static void rpciod_killall(void);
static void rpc_async_schedule(struct work_struct *);
+static void rpc_release_task(struct rpc_task *task);
/*
* RPC tasks sit here while waiting for conditions to improve.
@@ -896,7 +897,7 @@ void rpc_put_task(struct rpc_task *task)
}
EXPORT_SYMBOL(rpc_put_task);
-void rpc_release_task(struct rpc_task *task)
+static void rpc_release_task(struct rpc_task *task)
{
#ifdef RPC_DEBUG
BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index eb44ec929ca..c1f878131ac 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -26,7 +26,6 @@
#include <linux/sunrpc/clnt.h>
#define RPCDBG_FACILITY RPCDBG_SVCDSP
-#define RPC_PARANOIA 1
/*
* Mode for mapping cpus to pools.
@@ -308,7 +307,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
serv->sv_nrpools = npools;
serv->sv_pools =
- kcalloc(sizeof(struct svc_pool), serv->sv_nrpools,
+ kcalloc(serv->sv_nrpools, sizeof(struct svc_pool),
GFP_KERNEL);
if (!serv->sv_pools) {
kfree(serv);
@@ -387,7 +386,7 @@ svc_destroy(struct svc_serv *serv)
svsk = list_entry(serv->sv_tempsocks.next,
struct svc_sock,
sk_list);
- svc_delete_socket(svsk);
+ svc_close_socket(svsk);
}
if (serv->sv_shutdown)
serv->sv_shutdown(serv);
@@ -396,7 +395,7 @@ svc_destroy(struct svc_serv *serv)
svsk = list_entry(serv->sv_permsocks.next,
struct svc_sock,
sk_list);
- svc_delete_socket(svsk);
+ svc_close_socket(svsk);
}
cache_clean_deferred(serv);
@@ -872,15 +871,15 @@ svc_process(struct svc_rqst *rqstp)
return 0;
err_short_len:
-#ifdef RPC_PARANOIA
- printk("svc: short len %Zd, dropping request\n", argv->iov_len);
-#endif
+ if (net_ratelimit())
+ printk("svc: short len %Zd, dropping request\n", argv->iov_len);
+
goto dropit; /* drop request */
err_bad_dir:
-#ifdef RPC_PARANOIA
- printk("svc: bad direction %d, dropping request\n", dir);
-#endif
+ if (net_ratelimit())
+ printk("svc: bad direction %d, dropping request\n", dir);
+
serv->sv_stats->rpcbadfmt++;
goto dropit; /* drop request */
@@ -909,9 +908,10 @@ err_bad_prog:
goto sendit;
err_bad_vers:
-#ifdef RPC_PARANOIA
- printk("svc: unknown version (%d)\n", vers);
-#endif
+ if (net_ratelimit())
+ printk("svc: unknown version (%d for prog %d, %s)\n",
+ vers, prog, progp->pg_name);
+
serv->sv_stats->rpcbadfmt++;
svc_putnl(resv, RPC_PROG_MISMATCH);
svc_putnl(resv, progp->pg_lovers);
@@ -919,17 +919,17 @@ err_bad_vers:
goto sendit;
err_bad_proc:
-#ifdef RPC_PARANOIA
- printk("svc: unknown procedure (%d)\n", proc);
-#endif
+ if (net_ratelimit())
+ printk("svc: unknown procedure (%d)\n", proc);
+
serv->sv_stats->rpcbadfmt++;
svc_putnl(resv, RPC_PROC_UNAVAIL);
goto sendit;
err_garbage:
-#ifdef RPC_PARANOIA
- printk("svc: failed to decode args\n");
-#endif
+ if (net_ratelimit())
+ printk("svc: failed to decode args\n");
+
rpc_stat = rpc_garbage_args;
err_bad:
serv->sv_stats->rpcbadfmt++;
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index a0a953a430c..0d1e8fb83b9 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -53,6 +53,10 @@ struct auth_domain *unix_domain_find(char *name)
return NULL;
kref_init(&new->h.ref);
new->h.name = kstrdup(name, GFP_KERNEL);
+ if (new->h.name == NULL) {
+ kfree(new);
+ return NULL;
+ }
new->h.flavour = &svcauth_unix;
new->addr_changes = 0;
rv = auth_domain_lookup(name, &new->h);
@@ -435,6 +439,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
default:
BUG();
case -EAGAIN:
+ case -ETIMEDOUT:
return SVC_DROP;
case -ENOENT:
return SVC_DENIED;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 99f54fb6d66..cf93cd1d857 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -62,6 +62,12 @@
* after a clear, the socket must be read/accepted
* if this succeeds, it must be set again.
* SK_CLOSE can set at any time. It is never cleared.
+ * sk_inuse contains a bias of '1' until SK_DEAD is set.
+ * so when sk_inuse hits zero, we know the socket is dead
+ * and no-one is using it.
+ * SK_DEAD can only be set while SK_BUSY is held which ensures
+ * no other thread will be using the socket or will try to
+ * set SK_DEAD.
*
*/
@@ -70,6 +76,7 @@
static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
int *errp, int pmap_reg);
+static void svc_delete_socket(struct svc_sock *svsk);
static void svc_udp_data_ready(struct sock *, int);
static int svc_udp_recvfrom(struct svc_rqst *);
static int svc_udp_sendto(struct svc_rqst *);
@@ -329,8 +336,9 @@ void svc_reserve(struct svc_rqst *rqstp, int space)
static inline void
svc_sock_put(struct svc_sock *svsk)
{
- if (atomic_dec_and_test(&svsk->sk_inuse) &&
- test_bit(SK_DEAD, &svsk->sk_flags)) {
+ if (atomic_dec_and_test(&svsk->sk_inuse)) {
+ BUG_ON(! test_bit(SK_DEAD, &svsk->sk_flags));
+
dprintk("svc: releasing dead socket\n");
if (svsk->sk_sock->file)
sockfd_put(svsk->sk_sock);
@@ -520,7 +528,7 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
if (!serv)
return 0;
- spin_lock(&serv->sv_lock);
+ spin_lock_bh(&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)
@@ -528,12 +536,12 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
else
len += onelen;
}
- spin_unlock(&serv->sv_lock);
+ spin_unlock_bh(&serv->sv_lock);
if (closesk)
/* Should unregister with portmap, but you cannot
* unregister just one protocol...
*/
- svc_delete_socket(closesk);
+ svc_close_socket(closesk);
else if (toclose)
return -ENOENT;
return len;
@@ -683,6 +691,11 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
return svc_deferred_recv(rqstp);
}
+ if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
+ svc_delete_socket(svsk);
+ return 0;
+ }
+
clear_bit(SK_DATA, &svsk->sk_flags);
while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
if (err == -EAGAIN) {
@@ -1062,15 +1075,19 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
* bit set in the fragment length header.
* But apparently no known nfs clients send fragmented
* records. */
- printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (non-terminal)\n",
- (unsigned long) svsk->sk_reclen);
+ if (net_ratelimit())
+ printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
+ " (non-terminal)\n",
+ (unsigned long) svsk->sk_reclen);
goto err_delete;
}
svsk->sk_reclen &= 0x7fffffff;
dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
if (svsk->sk_reclen > serv->sv_max_mesg) {
- printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (large)\n",
- (unsigned long) svsk->sk_reclen);
+ if (net_ratelimit())
+ printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
+ " (large)\n",
+ (unsigned long) svsk->sk_reclen);
goto err_delete;
}
}
@@ -1172,7 +1189,8 @@ svc_tcp_sendto(struct svc_rqst *rqstp)
rqstp->rq_sock->sk_server->sv_name,
(sent<0)?"got error":"sent only",
sent, xbufp->len);
- svc_delete_socket(rqstp->rq_sock);
+ set_bit(SK_CLOSE, &rqstp->rq_sock->sk_flags);
+ svc_sock_enqueue(rqstp->rq_sock);
sent = -EAGAIN;
}
return sent;
@@ -1278,6 +1296,8 @@ svc_recv(struct svc_rqst *rqstp, long timeout)
schedule_timeout_uninterruptible(msecs_to_jiffies(500));
rqstp->rq_pages[i] = p;
}
+ rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */
+ BUG_ON(pages >= RPCSVC_MAXPAGES);
/* Make arg->head point to first page and arg->pages point to rest */
arg = &rqstp->rq_arg;
@@ -1489,7 +1509,7 @@ 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);
+ atomic_set(&svsk->sk_inuse, 1);
svsk->sk_lastrecv = get_seconds();
spin_lock_init(&svsk->sk_defer_lock);
INIT_LIST_HEAD(&svsk->sk_deferred);
@@ -1612,7 +1632,7 @@ bummer:
/*
* Remove a dead socket
*/
-void
+static void
svc_delete_socket(struct svc_sock *svsk)
{
struct svc_serv *serv;
@@ -1638,16 +1658,26 @@ svc_delete_socket(struct svc_sock *svsk)
* 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_and_set_bit(SK_DEAD, &svsk->sk_flags)) {
+ BUG_ON(atomic_read(&svsk->sk_inuse)<2);
+ atomic_dec(&svsk->sk_inuse);
if (test_bit(SK_TEMP, &svsk->sk_flags))
serv->sv_tmpcnt--;
+ }
- /* This atomic_inc should be needed - svc_delete_socket
- * should have the semantic of dropping a reference.
- * But it doesn't yet....
- */
- atomic_inc(&svsk->sk_inuse);
spin_unlock_bh(&serv->sv_lock);
+}
+
+void svc_close_socket(struct svc_sock *svsk)
+{
+ set_bit(SK_CLOSE, &svsk->sk_flags);
+ if (test_and_set_bit(SK_BUSY, &svsk->sk_flags))
+ /* someone else will have to effect the close */
+ return;
+
+ atomic_inc(&svsk->sk_inuse);
+ svc_delete_socket(svsk);
+ clear_bit(SK_BUSY, &svsk->sk_flags);
svc_sock_put(svsk);
}
diff --git a/net/tipc/config.c b/net/tipc/config.c
index 458a2c46cef..baf55c459c8 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -208,7 +208,7 @@ static void cfg_cmd_event(struct tipc_cmd_msg *msg,
if (mng.link_subscriptions > 64)
break;
- sub = (struct subscr_data *)kmalloc(sizeof(*sub),
+ sub = kmalloc(sizeof(*sub),
GFP_ATOMIC);
if (sub == NULL) {
warn("Memory squeeze; dropped remote link subscription\n");
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 746c2f4a5fa..f14ad6635fc 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -96,7 +96,7 @@ atomic_t unix_tot_inflight = ATOMIC_INIT(0);
static struct sock *unix_get_socket(struct file *filp)
{
struct sock *u_sock = NULL;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
/*
* Socket ?
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 769cdd62c1b..4d90a179aed 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -86,8 +86,8 @@ static int wanrouter_device_del_if(struct wan_device *wandev,
static struct wan_device *wanrouter_find_device(char *name);
static int wanrouter_delete_interface(struct wan_device *wandev, char *name);
-void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
-void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
+static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
+static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
@@ -104,8 +104,8 @@ struct wan_device* wanrouter_router_devlist; /* list of registered devices */
* Organize Unique Identifiers for encapsulation/decapsulation
*/
-static unsigned char wanrouter_oui_ether[] = { 0x00, 0x00, 0x00 };
#if 0
+static unsigned char wanrouter_oui_ether[] = { 0x00, 0x00, 0x00 };
static unsigned char wanrouter_oui_802_2[] = { 0x00, 0x80, 0xC2 };
#endif
@@ -246,6 +246,8 @@ int unregister_wan_device(char *name)
return 0;
}
+#if 0
+
/*
* Encapsulate packet.
*
@@ -341,6 +343,7 @@ __be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev)
return ethertype;
}
+#endif /* 0 */
/*
* WAN device IOCTL.
@@ -799,23 +802,19 @@ static int wanrouter_delete_interface(struct wan_device *wandev, char *name)
return 0;
}
-void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
+static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
{
spin_lock_irqsave(lock, *smp_flags);
}
-void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
+static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
{
spin_unlock_irqrestore(lock, *smp_flags);
}
EXPORT_SYMBOL(register_wan_device);
EXPORT_SYMBOL(unregister_wan_device);
-EXPORT_SYMBOL(wanrouter_encapsulate);
-EXPORT_SYMBOL(wanrouter_type_trans);
-EXPORT_SYMBOL(lock_adapter_irq);
-EXPORT_SYMBOL(unlock_adapter_irq);
MODULE_LICENSE("GPL");
diff --git a/net/x25/Makefile b/net/x25/Makefile
index 587a71aa411..a2c34ab6f19 100644
--- a/net/x25/Makefile
+++ b/net/x25/Makefile
@@ -6,5 +6,5 @@ obj-$(CONFIG_X25) += x25.o
x25-y := af_x25.o x25_dev.o x25_facilities.o x25_in.o \
x25_link.o x25_out.o x25_route.o x25_subr.o \
- x25_timer.o x25_proc.o
+ x25_timer.o x25_proc.o x25_forward.o
x25-$(CONFIG_SYSCTL) += sysctl_net_x25.o
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 52a2726d327..b37d894358e 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -63,6 +63,7 @@ int sysctl_x25_call_request_timeout = X25_DEFAULT_T21;
int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22;
int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23;
int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2;
+int sysctl_x25_forward = 0;
HLIST_HEAD(x25_list);
DEFINE_RWLOCK(x25_list_lock);
@@ -484,8 +485,6 @@ out:
return sk;
}
-void x25_init_timers(struct sock *sk);
-
static int x25_create(struct socket *sock, int protocol)
{
struct sock *sk;
@@ -848,7 +847,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
struct x25_address source_addr, dest_addr;
struct x25_facilities facilities;
struct x25_dte_facilities dte_facilities;
- int len, rc;
+ int len, addr_len, rc;
/*
* Remove the LCI and frame type.
@@ -859,7 +858,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
* Extract the X.25 addresses and convert them to ASCII strings,
* and remove them.
*/
- skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
+ addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr);
+ skb_pull(skb, addr_len);
/*
* Get the length of the facilities, skip past them for the moment
@@ -875,11 +875,28 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
sk = x25_find_listener(&source_addr,skb);
skb_push(skb,len);
+ if (sk != NULL && sk_acceptq_is_full(sk)) {
+ goto out_sock_put;
+ }
+
/*
- * We can't accept the Call Request.
+ * We dont have any listeners for this incoming call.
+ * Try forwarding it.
*/
- if (sk == NULL || sk_acceptq_is_full(sk))
- goto out_clear_request;
+ if (sk == NULL) {
+ skb_push(skb, addr_len + X25_STD_MIN_LEN);
+ if (sysctl_x25_forward &&
+ x25_forward_call(&dest_addr, nb, skb, lci) > 0)
+ {
+ /* Call was forwarded, dont process it any more */
+ kfree_skb(skb);
+ rc = 1;
+ goto out;
+ } else {
+ /* No listeners, can't forward, clear the call */
+ goto out_clear_request;
+ }
+ }
/*
* Try to reach a compromise on the requested facilities.
@@ -1600,6 +1617,9 @@ void x25_kill_by_neigh(struct x25_neigh *nb)
x25_disconnect(s, ENETUNREACH, 0, 0);
write_unlock_bh(&x25_list_lock);
+
+ /* Remove any related forwards */
+ x25_clear_forward_by_dev(nb->dev);
}
static int __init x25_init(void)
diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
index aabda59c824..2b2e7fd689f 100644
--- a/net/x25/sysctl_net_x25.c
+++ b/net/x25/sysctl_net_x25.c
@@ -73,6 +73,14 @@ static struct ctl_table x25_table[] = {
.extra1 = &min_timer,
.extra2 = &max_timer,
},
+ {
+ .ctl_name = NET_X25_FORWARD,
+ .procname = "x25_forward",
+ .data = &sysctl_x25_forward,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
{ 0, },
};
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index 47b68a30167..f099fd6a7c0 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -56,6 +56,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
sk_add_backlog(sk, skb);
}
bh_unlock_sock(sk);
+ sock_put(sk);
return queued;
}
@@ -66,9 +67,18 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
return x25_rx_call_request(skb, nb, lci);
/*
- * Its not a Call Request, nor is it a control frame.
- * Let caller throw it away.
+ * Its not a Call Request, nor is it a control frame.
+ * Can we forward it?
*/
+
+ if (x25_forward_data(lci, nb, skb)) {
+ if (frametype == X25_CLEAR_CONFIRMATION) {
+ x25_clear_forward_by_lci(lci);
+ }
+ kfree_skb(skb);
+ return 1;
+ }
+
/*
x25_transmit_clear_request(nb, lci, 0x0D);
*/
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
index 9f42b9c9de3..27f5cc7966f 100644
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -254,7 +254,7 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
* They want reverse charging, we won't accept it.
*/
if ((theirs.reverse & 0x01 ) && (ours->reverse & 0x01)) {
- SOCK_DEBUG(sk, "X.25: rejecting reverse charging request");
+ SOCK_DEBUG(sk, "X.25: rejecting reverse charging request\n");
return -1;
}
@@ -262,29 +262,29 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
if (theirs.throughput) {
if (theirs.throughput < ours->throughput) {
- SOCK_DEBUG(sk, "X.25: throughput negotiated down");
+ SOCK_DEBUG(sk, "X.25: throughput negotiated down\n");
new->throughput = theirs.throughput;
}
}
if (theirs.pacsize_in && theirs.pacsize_out) {
if (theirs.pacsize_in < ours->pacsize_in) {
- SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down");
+ SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down\n");
new->pacsize_in = theirs.pacsize_in;
}
if (theirs.pacsize_out < ours->pacsize_out) {
- SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down");
+ SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down\n");
new->pacsize_out = theirs.pacsize_out;
}
}
if (theirs.winsize_in && theirs.winsize_out) {
if (theirs.winsize_in < ours->winsize_in) {
- SOCK_DEBUG(sk, "X.25: window size inwards negotiated down");
+ SOCK_DEBUG(sk, "X.25: window size inwards negotiated down\n");
new->winsize_in = theirs.winsize_in;
}
if (theirs.winsize_out < ours->winsize_out) {
- SOCK_DEBUG(sk, "X.25: window size outwards negotiated down");
+ SOCK_DEBUG(sk, "X.25: window size outwards negotiated down\n");
new->winsize_out = theirs.winsize_out;
}
}
diff --git a/net/x25/x25_forward.c b/net/x25/x25_forward.c
new file mode 100644
index 00000000000..d339e0c810a
--- /dev/null
+++ b/net/x25/x25_forward.c
@@ -0,0 +1,163 @@
+/*
+ * This module:
+ * This module is free software; you can redistribute it and/or
+ * modify 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.
+ *
+ * History
+ * 03-01-2007 Added forwarding for x.25 Andrew Hendry
+ */
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <net/x25.h>
+
+struct list_head x25_forward_list = LIST_HEAD_INIT(x25_forward_list);
+DEFINE_RWLOCK(x25_forward_list_lock);
+
+int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from,
+ struct sk_buff *skb, int lci)
+{
+ struct x25_route *rt;
+ struct x25_neigh *neigh_new = NULL;
+ struct list_head *entry;
+ struct x25_forward *x25_frwd, *new_frwd;
+ struct sk_buff *skbn;
+ short same_lci = 0;
+ int rc = 0;
+
+ if ((rt = x25_get_route(dest_addr)) != NULL) {
+
+ if ((neigh_new = x25_get_neigh(rt->dev)) == NULL) {
+ /* This shouldnt happen, if it occurs somehow
+ * do something sensible
+ */
+ goto out_put_route;
+ }
+
+ /* Avoid a loop. This is the normal exit path for a
+ * system with only one x.25 iface and default route
+ */
+ if (rt->dev == from->dev) {
+ goto out_put_nb;
+ }
+
+ /* Remote end sending a call request on an already
+ * established LCI? It shouldnt happen, just in case..
+ */
+ read_lock_bh(&x25_forward_list_lock);
+ list_for_each(entry, &x25_forward_list) {
+ x25_frwd = list_entry(entry, struct x25_forward, node);
+ if (x25_frwd->lci == lci) {
+ printk(KERN_WARNING "X.25: call request for lci which is already registered!, transmitting but not registering new pair\n");
+ same_lci = 1;
+ }
+ }
+ read_unlock_bh(&x25_forward_list_lock);
+
+ /* Save the forwarding details for future traffic */
+ if (!same_lci){
+ if ((new_frwd = kmalloc(sizeof(struct x25_forward),
+ GFP_ATOMIC)) == NULL){
+ rc = -ENOMEM;
+ goto out_put_nb;
+ }
+ new_frwd->lci = lci;
+ new_frwd->dev1 = rt->dev;
+ new_frwd->dev2 = from->dev;
+ write_lock_bh(&x25_forward_list_lock);
+ list_add(&new_frwd->node, &x25_forward_list);
+ write_unlock_bh(&x25_forward_list_lock);
+ }
+
+ /* Forward the call request */
+ if ( (skbn = skb_clone(skb, GFP_ATOMIC)) == NULL){
+ goto out_put_nb;
+ }
+ x25_transmit_link(skbn, neigh_new);
+ rc = 1;
+ }
+
+
+out_put_nb:
+ x25_neigh_put(neigh_new);
+
+out_put_route:
+ x25_route_put(rt);
+ return rc;
+}
+
+
+int x25_forward_data(int lci, struct x25_neigh *from, struct sk_buff *skb) {
+
+ struct x25_forward *frwd;
+ struct list_head *entry;
+ struct net_device *peer = NULL;
+ struct x25_neigh *nb;
+ struct sk_buff *skbn;
+ int rc = 0;
+
+ read_lock_bh(&x25_forward_list_lock);
+ list_for_each(entry, &x25_forward_list) {
+ frwd = list_entry(entry, struct x25_forward, node);
+ if (frwd->lci == lci) {
+ /* The call is established, either side can send */
+ if (from->dev == frwd->dev1) {
+ peer = frwd->dev2;
+ } else {
+ peer = frwd->dev1;
+ }
+ break;
+ }
+ }
+ read_unlock_bh(&x25_forward_list_lock);
+
+ if ( (nb = x25_get_neigh(peer)) == NULL)
+ goto out;
+
+ if ( (skbn = pskb_copy(skb, GFP_ATOMIC)) == NULL){
+ goto out;
+
+ }
+ x25_transmit_link(skbn, nb);
+
+ x25_neigh_put(nb);
+ rc = 1;
+out:
+ return rc;
+}
+
+void x25_clear_forward_by_lci(unsigned int lci)
+{
+ struct x25_forward *fwd;
+ struct list_head *entry, *tmp;
+
+ write_lock_bh(&x25_forward_list_lock);
+
+ list_for_each_safe(entry, tmp, &x25_forward_list) {
+ fwd = list_entry(entry, struct x25_forward, node);
+ if (fwd->lci == lci) {
+ list_del(&fwd->node);
+ kfree(fwd);
+ }
+ }
+ write_unlock_bh(&x25_forward_list_lock);
+}
+
+
+void x25_clear_forward_by_dev(struct net_device *dev)
+{
+ struct x25_forward *fwd;
+ struct list_head *entry, *tmp;
+
+ write_lock_bh(&x25_forward_list_lock);
+
+ list_for_each_safe(entry, tmp, &x25_forward_list) {
+ fwd = list_entry(entry, struct x25_forward, node);
+ if ((fwd->dev1 == dev) || (fwd->dev2 == dev)){
+ list_del(&fwd->node);
+ kfree(fwd);
+ }
+ }
+ write_unlock_bh(&x25_forward_list_lock);
+}
diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c
index a11837d361d..e0470bd8c2f 100644
--- a/net/x25/x25_proc.c
+++ b/net/x25/x25_proc.c
@@ -165,6 +165,75 @@ out:
return 0;
}
+static __inline__ struct x25_forward *x25_get_forward_idx(loff_t pos)
+{
+ struct x25_forward *f;
+ struct list_head *entry;
+
+ list_for_each(entry, &x25_forward_list) {
+ f = list_entry(entry, struct x25_forward, node);
+ if (!pos--)
+ goto found;
+ }
+
+ f = NULL;
+found:
+ return f;
+}
+
+static void *x25_seq_forward_start(struct seq_file *seq, loff_t *pos)
+{
+ loff_t l = *pos;
+
+ read_lock_bh(&x25_forward_list_lock);
+ return l ? x25_get_forward_idx(--l) : SEQ_START_TOKEN;
+}
+
+static void *x25_seq_forward_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct x25_forward *f;
+
+ ++*pos;
+ if (v == SEQ_START_TOKEN) {
+ f = NULL;
+ if (!list_empty(&x25_forward_list))
+ f = list_entry(x25_forward_list.next,
+ struct x25_forward, node);
+ goto out;
+ }
+ f = v;
+ if (f->node.next != &x25_forward_list)
+ f = list_entry(f->node.next, struct x25_forward, node);
+ else
+ f = NULL;
+out:
+ return f;
+
+}
+
+static void x25_seq_forward_stop(struct seq_file *seq, void *v)
+{
+ read_unlock_bh(&x25_forward_list_lock);
+}
+
+static int x25_seq_forward_show(struct seq_file *seq, void *v)
+{
+ struct x25_forward *f;
+
+ if (v == SEQ_START_TOKEN) {
+ seq_printf(seq, "lci dev1 dev2\n");
+ goto out;
+ }
+
+ f = v;
+
+ seq_printf(seq, "%d %-10s %-10s\n",
+ f->lci, f->dev1->name, f->dev2->name);
+
+out:
+ return 0;
+}
+
static struct seq_operations x25_seq_route_ops = {
.start = x25_seq_route_start,
.next = x25_seq_route_next,
@@ -179,6 +248,13 @@ static struct seq_operations x25_seq_socket_ops = {
.show = x25_seq_socket_show,
};
+static struct seq_operations x25_seq_forward_ops = {
+ .start = x25_seq_forward_start,
+ .next = x25_seq_forward_next,
+ .stop = x25_seq_forward_stop,
+ .show = x25_seq_forward_show,
+};
+
static int x25_seq_socket_open(struct inode *inode, struct file *file)
{
return seq_open(file, &x25_seq_socket_ops);
@@ -189,6 +265,11 @@ static int x25_seq_route_open(struct inode *inode, struct file *file)
return seq_open(file, &x25_seq_route_ops);
}
+static int x25_seq_forward_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &x25_seq_forward_ops);
+}
+
static struct file_operations x25_seq_socket_fops = {
.owner = THIS_MODULE,
.open = x25_seq_socket_open,
@@ -205,6 +286,14 @@ static struct file_operations x25_seq_route_fops = {
.release = seq_release,
};
+static struct file_operations x25_seq_forward_fops = {
+ .owner = THIS_MODULE,
+ .open = x25_seq_forward_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static struct proc_dir_entry *x25_proc_dir;
int __init x25_proc_init(void)
@@ -225,9 +314,17 @@ int __init x25_proc_init(void)
if (!p)
goto out_socket;
p->proc_fops = &x25_seq_socket_fops;
+
+ p = create_proc_entry("forward", S_IRUGO, x25_proc_dir);
+ if (!p)
+ goto out_forward;
+ p->proc_fops = &x25_seq_forward_fops;
rc = 0;
+
out:
return rc;
+out_forward:
+ remove_proc_entry("socket", x25_proc_dir);
out_socket:
remove_proc_entry("route", x25_proc_dir);
out_route:
@@ -237,6 +334,7 @@ out_route:
void __exit x25_proc_exit(void)
{
+ remove_proc_entry("forward", x25_proc_dir);
remove_proc_entry("route", x25_proc_dir);
remove_proc_entry("socket", x25_proc_dir);
remove_proc_entry("x25", proc_net);
diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c
index 2a3fe986b24..883a848bca5 100644
--- a/net/x25/x25_route.c
+++ b/net/x25/x25_route.c
@@ -119,6 +119,9 @@ void x25_route_device_down(struct net_device *dev)
__x25_remove_route(rt);
}
write_unlock_bh(&x25_route_list_lock);
+
+ /* Remove any related forwarding */
+ x25_clear_forward_by_dev(dev);
}
/*
diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig
index 0faab633258..577a4f821b9 100644
--- a/net/xfrm/Kconfig
+++ b/net/xfrm/Kconfig
@@ -24,6 +24,17 @@ config XFRM_SUB_POLICY
If unsure, say N.
+config XFRM_MIGRATE
+ bool "Transformation migrate database (EXPERIMENTAL)"
+ depends on XFRM && EXPERIMENTAL
+ ---help---
+ A feature to update locator(s) of a given IPsec security
+ association dynamically. This feature is required, for
+ instance, in a Mobile IPv6 environment with IPsec configuration
+ where mobile nodes change their attachment point to the Internet.
+
+ If unsure, say N.
+
config NET_KEY
tristate "PF_KEY sockets"
select XFRM
@@ -34,4 +45,19 @@ config NET_KEY
Say Y unless you know what you are doing.
+config NET_KEY_MIGRATE
+ bool "PF_KEY MIGRATE (EXPERIMENTAL)"
+ depends on NET_KEY && EXPERIMENTAL
+ select XFRM_MIGRATE
+ ---help---
+ Add a PF_KEY MIGRATE message to PF_KEYv2 socket family.
+ The PF_KEY MIGRATE message is used to dynamically update
+ locator(s) of a given IPsec security association.
+ This feature is required, for instance, in a Mobile IPv6
+ environment with IPsec configuration where mobile nodes
+ change their attachment point to the Internet. Detail
+ information can be found in the internet-draft
+ <draft-sugimoto-mip6-pfkey-migrate>.
+
+ If unsure, say N.
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index 6b381fc0383..248f94814df 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -266,6 +266,23 @@ static struct xfrm_algo_desc ealg_list[] = {
}
},
{
+ .name = "cbc(camellia)",
+
+ .uinfo = {
+ .encr = {
+ .blockbits = 128,
+ .defkeybits = 128,
+ }
+ },
+
+ .desc = {
+ .sadb_alg_id = SADB_X_EALG_CAMELLIACBC,
+ .sadb_alg_ivlen = 8,
+ .sadb_alg_minbits = 128,
+ .sadb_alg_maxbits = 256
+ }
+},
+{
.name = "cbc(twofish)",
.compat = "twofish",
@@ -399,7 +416,8 @@ static struct xfrm_algo_desc *xfrm_get_byname(struct xfrm_algo_desc *list,
if (!probe)
break;
- status = crypto_has_alg(name, type, mask | CRYPTO_ALG_ASYNC);
+ status = crypto_has_alg(list[i].name, type,
+ mask | CRYPTO_ALG_ASYNC);
if (!status)
break;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index bebd40e5a62..fa7ce060b45 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -650,19 +650,18 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
struct xfrm_policy *pol;
struct xfrm_policy *delpol;
struct hlist_head *chain;
- struct hlist_node *entry, *newpos, *last;
+ struct hlist_node *entry, *newpos;
struct dst_entry *gc_list;
write_lock_bh(&xfrm_policy_lock);
chain = policy_hash_bysel(&policy->selector, policy->family, dir);
delpol = NULL;
newpos = NULL;
- last = NULL;
hlist_for_each_entry(pol, entry, chain, bydst) {
- if (!delpol &&
- pol->type == policy->type &&
+ if (pol->type == policy->type &&
!selector_cmp(&pol->selector, &policy->selector) &&
- xfrm_sec_ctx_match(pol->security, policy->security)) {
+ xfrm_sec_ctx_match(pol->security, policy->security) &&
+ !WARN_ON(delpol)) {
if (excl) {
write_unlock_bh(&xfrm_policy_lock);
return -EEXIST;
@@ -671,17 +670,12 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
if (policy->priority > pol->priority)
continue;
} else if (policy->priority >= pol->priority) {
- last = &pol->bydst;
+ newpos = &pol->bydst;
continue;
}
- if (!newpos)
- newpos = &pol->bydst;
if (delpol)
break;
- last = &pol->bydst;
}
- if (!newpos)
- newpos = last;
if (newpos)
hlist_add_after(newpos, &policy->bydst);
else
@@ -2242,3 +2236,234 @@ void __init xfrm_init(void)
xfrm_input_init();
}
+#ifdef CONFIG_XFRM_MIGRATE
+static int xfrm_migrate_selector_match(struct xfrm_selector *sel_cmp,
+ struct xfrm_selector *sel_tgt)
+{
+ if (sel_cmp->proto == IPSEC_ULPROTO_ANY) {
+ if (sel_tgt->family == sel_cmp->family &&
+ xfrm_addr_cmp(&sel_tgt->daddr, &sel_cmp->daddr,
+ sel_cmp->family) == 0 &&
+ xfrm_addr_cmp(&sel_tgt->saddr, &sel_cmp->saddr,
+ sel_cmp->family) == 0 &&
+ sel_tgt->prefixlen_d == sel_cmp->prefixlen_d &&
+ sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) {
+ return 1;
+ }
+ } else {
+ if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static struct xfrm_policy * xfrm_migrate_policy_find(struct xfrm_selector *sel,
+ u8 dir, u8 type)
+{
+ struct xfrm_policy *pol, *ret = NULL;
+ struct hlist_node *entry;
+ struct hlist_head *chain;
+ u32 priority = ~0U;
+
+ read_lock_bh(&xfrm_policy_lock);
+ chain = policy_hash_direct(&sel->daddr, &sel->saddr, sel->family, dir);
+ hlist_for_each_entry(pol, entry, chain, bydst) {
+ if (xfrm_migrate_selector_match(sel, &pol->selector) &&
+ pol->type == type) {
+ ret = pol;
+ priority = ret->priority;
+ break;
+ }
+ }
+ chain = &xfrm_policy_inexact[dir];
+ hlist_for_each_entry(pol, entry, chain, bydst) {
+ if (xfrm_migrate_selector_match(sel, &pol->selector) &&
+ pol->type == type &&
+ pol->priority < priority) {
+ ret = pol;
+ break;
+ }
+ }
+
+ if (ret)
+ xfrm_pol_hold(ret);
+
+ read_unlock_bh(&xfrm_policy_lock);
+
+ return ret;
+}
+
+static int migrate_tmpl_match(struct xfrm_migrate *m, struct xfrm_tmpl *t)
+{
+ int match = 0;
+
+ if (t->mode == m->mode && t->id.proto == m->proto &&
+ (m->reqid == 0 || t->reqid == m->reqid)) {
+ switch (t->mode) {
+ case XFRM_MODE_TUNNEL:
+ case XFRM_MODE_BEET:
+ if (xfrm_addr_cmp(&t->id.daddr, &m->old_daddr,
+ m->old_family) == 0 &&
+ xfrm_addr_cmp(&t->saddr, &m->old_saddr,
+ m->old_family) == 0) {
+ match = 1;
+ }
+ break;
+ case XFRM_MODE_TRANSPORT:
+ /* in case of transport mode, template does not store
+ any IP addresses, hence we just compare mode and
+ protocol */
+ match = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ return match;
+}
+
+/* update endpoint address(es) of template(s) */
+static int xfrm_policy_migrate(struct xfrm_policy *pol,
+ struct xfrm_migrate *m, int num_migrate)
+{
+ struct xfrm_migrate *mp;
+ struct dst_entry *dst;
+ int i, j, n = 0;
+
+ write_lock_bh(&pol->lock);
+ if (unlikely(pol->dead)) {
+ /* target policy has been deleted */
+ write_unlock_bh(&pol->lock);
+ return -ENOENT;
+ }
+
+ for (i = 0; i < pol->xfrm_nr; i++) {
+ for (j = 0, mp = m; j < num_migrate; j++, mp++) {
+ if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i]))
+ continue;
+ n++;
+ if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL)
+ continue;
+ /* update endpoints */
+ memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr,
+ sizeof(pol->xfrm_vec[i].id.daddr));
+ memcpy(&pol->xfrm_vec[i].saddr, &mp->new_saddr,
+ sizeof(pol->xfrm_vec[i].saddr));
+ pol->xfrm_vec[i].encap_family = mp->new_family;
+ /* flush bundles */
+ while ((dst = pol->bundles) != NULL) {
+ pol->bundles = dst->next;
+ dst_free(dst);
+ }
+ }
+ }
+
+ write_unlock_bh(&pol->lock);
+
+ if (!n)
+ return -ENODATA;
+
+ return 0;
+}
+
+static int xfrm_migrate_check(struct xfrm_migrate *m, int num_migrate)
+{
+ int i, j;
+
+ if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH)
+ return -EINVAL;
+
+ for (i = 0; i < num_migrate; i++) {
+ if ((xfrm_addr_cmp(&m[i].old_daddr, &m[i].new_daddr,
+ m[i].old_family) == 0) &&
+ (xfrm_addr_cmp(&m[i].old_saddr, &m[i].new_saddr,
+ m[i].old_family) == 0))
+ return -EINVAL;
+ if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) ||
+ xfrm_addr_any(&m[i].new_saddr, m[i].new_family))
+ return -EINVAL;
+
+ /* check if there is any duplicated entry */
+ for (j = i + 1; j < num_migrate; j++) {
+ if (!memcmp(&m[i].old_daddr, &m[j].old_daddr,
+ sizeof(m[i].old_daddr)) &&
+ !memcmp(&m[i].old_saddr, &m[j].old_saddr,
+ sizeof(m[i].old_saddr)) &&
+ m[i].proto == m[j].proto &&
+ m[i].mode == m[j].mode &&
+ m[i].reqid == m[j].reqid &&
+ m[i].old_family == m[j].old_family)
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+ struct xfrm_migrate *m, int num_migrate)
+{
+ int i, err, nx_cur = 0, nx_new = 0;
+ struct xfrm_policy *pol = NULL;
+ struct xfrm_state *x, *xc;
+ struct xfrm_state *x_cur[XFRM_MAX_DEPTH];
+ struct xfrm_state *x_new[XFRM_MAX_DEPTH];
+ struct xfrm_migrate *mp;
+
+ if ((err = xfrm_migrate_check(m, num_migrate)) < 0)
+ goto out;
+
+ /* Stage 1 - find policy */
+ if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ /* Stage 2 - find and update state(s) */
+ for (i = 0, mp = m; i < num_migrate; i++, mp++) {
+ if ((x = xfrm_migrate_state_find(mp))) {
+ x_cur[nx_cur] = x;
+ nx_cur++;
+ if ((xc = xfrm_state_migrate(x, mp))) {
+ x_new[nx_new] = xc;
+ nx_new++;
+ } else {
+ err = -ENODATA;
+ goto restore_state;
+ }
+ }
+ }
+
+ /* Stage 3 - update policy */
+ if ((err = xfrm_policy_migrate(pol, m, num_migrate)) < 0)
+ goto restore_state;
+
+ /* Stage 4 - delete old state(s) */
+ if (nx_cur) {
+ xfrm_states_put(x_cur, nx_cur);
+ xfrm_states_delete(x_cur, nx_cur);
+ }
+
+ /* Stage 5 - announce */
+ km_migrate(sel, dir, type, m, num_migrate);
+
+ xfrm_pol_put(pol);
+
+ return 0;
+out:
+ return err;
+
+restore_state:
+ if (pol)
+ xfrm_pol_put(pol);
+ if (nx_cur)
+ xfrm_states_put(x_cur, nx_cur);
+ if (nx_new)
+ xfrm_states_delete(x_new, nx_new);
+
+ return err;
+}
+EXPORT_SYMBOL(xfrm_migrate);
+#endif
+
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index fdb08d9f34a..91b02687db5 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -183,9 +183,6 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock);
int __xfrm_state_delete(struct xfrm_state *x);
-static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
-static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
-
int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
@@ -831,6 +828,160 @@ out:
}
EXPORT_SYMBOL(xfrm_state_add);
+#ifdef CONFIG_XFRM_MIGRATE
+struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
+{
+ int err = -ENOMEM;
+ struct xfrm_state *x = xfrm_state_alloc();
+ if (!x)
+ goto error;
+
+ memcpy(&x->id, &orig->id, sizeof(x->id));
+ memcpy(&x->sel, &orig->sel, sizeof(x->sel));
+ memcpy(&x->lft, &orig->lft, sizeof(x->lft));
+ x->props.mode = orig->props.mode;
+ x->props.replay_window = orig->props.replay_window;
+ x->props.reqid = orig->props.reqid;
+ x->props.family = orig->props.family;
+ x->props.saddr = orig->props.saddr;
+
+ if (orig->aalg) {
+ x->aalg = xfrm_algo_clone(orig->aalg);
+ if (!x->aalg)
+ goto error;
+ }
+ x->props.aalgo = orig->props.aalgo;
+
+ if (orig->ealg) {
+ x->ealg = xfrm_algo_clone(orig->ealg);
+ if (!x->ealg)
+ goto error;
+ }
+ x->props.ealgo = orig->props.ealgo;
+
+ if (orig->calg) {
+ x->calg = xfrm_algo_clone(orig->calg);
+ if (!x->calg)
+ goto error;
+ }
+ x->props.calgo = orig->props.calgo;
+
+ if (orig->encap) {
+ x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);
+ if (!x->encap)
+ goto error;
+ }
+
+ if (orig->coaddr) {
+ x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
+ GFP_KERNEL);
+ if (!x->coaddr)
+ goto error;
+ }
+
+ err = xfrm_init_state(x);
+ if (err)
+ goto error;
+
+ x->props.flags = orig->props.flags;
+
+ x->curlft.add_time = orig->curlft.add_time;
+ x->km.state = orig->km.state;
+ x->km.seq = orig->km.seq;
+
+ return x;
+
+ error:
+ if (errp)
+ *errp = err;
+ if (x) {
+ kfree(x->aalg);
+ kfree(x->ealg);
+ kfree(x->calg);
+ kfree(x->encap);
+ kfree(x->coaddr);
+ }
+ kfree(x);
+ return NULL;
+}
+EXPORT_SYMBOL(xfrm_state_clone);
+
+/* xfrm_state_lock is held */
+struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
+{
+ unsigned int h;
+ struct xfrm_state *x;
+ struct hlist_node *entry;
+
+ if (m->reqid) {
+ h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
+ m->reqid, m->old_family);
+ hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
+ if (x->props.mode != m->mode ||
+ x->id.proto != m->proto)
+ continue;
+ if (m->reqid && x->props.reqid != m->reqid)
+ continue;
+ if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
+ m->old_family) ||
+ xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
+ m->old_family))
+ continue;
+ xfrm_state_hold(x);
+ return x;
+ }
+ } else {
+ h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
+ m->old_family);
+ hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
+ if (x->props.mode != m->mode ||
+ x->id.proto != m->proto)
+ continue;
+ if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,
+ m->old_family) ||
+ xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,
+ m->old_family))
+ continue;
+ xfrm_state_hold(x);
+ return x;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(xfrm_migrate_state_find);
+
+struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
+ struct xfrm_migrate *m)
+{
+ struct xfrm_state *xc;
+ int err;
+
+ xc = xfrm_state_clone(x, &err);
+ if (!xc)
+ return NULL;
+
+ memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
+ memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
+
+ /* add state */
+ if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {
+ /* a care is needed when the destination address of the
+ state is to be updated as it is a part of triplet */
+ xfrm_state_insert(xc);
+ } else {
+ if ((err = xfrm_state_add(xc)) < 0)
+ goto error;
+ }
+
+ return xc;
+error:
+ kfree(xc);
+ return NULL;
+}
+EXPORT_SYMBOL(xfrm_state_migrate);
+#endif
+
int xfrm_state_update(struct xfrm_state *x)
{
struct xfrm_state *x1;
@@ -1345,6 +1496,26 @@ void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
}
EXPORT_SYMBOL(km_policy_expired);
+int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+ struct xfrm_migrate *m, int num_migrate)
+{
+ int err = -EINVAL;
+ int ret;
+ struct xfrm_mgr *km;
+
+ read_lock(&xfrm_km_lock);
+ list_for_each_entry(km, &xfrm_km_list, list) {
+ if (km->migrate) {
+ ret = km->migrate(sel, dir, type, m, num_migrate);
+ if (!ret)
+ err = ret;
+ }
+ }
+ read_unlock(&xfrm_km_lock);
+ return err;
+}
+EXPORT_SYMBOL(km_migrate);
+
int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
{
int err = -EINVAL;
@@ -1458,7 +1629,7 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
}
EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
-static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family)
+struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family)
{
struct xfrm_state_afinfo *afinfo;
if (unlikely(family >= NPROTO))
@@ -1470,11 +1641,14 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family)
return afinfo;
}
-static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
+void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
{
read_unlock(&xfrm_state_afinfo_lock);
}
+EXPORT_SYMBOL(xfrm_state_get_afinfo);
+EXPORT_SYMBOL(xfrm_state_put_afinfo);
+
/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
void xfrm_state_delete_tunnel(struct xfrm_state *x)
{
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index e5372b11fc8..079a5d31575 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -434,18 +434,19 @@ error_no_put:
return NULL;
}
-static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct xfrm_usersa_info *p = NLMSG_DATA(nlh);
struct xfrm_state *x;
int err;
struct km_event c;
- err = verify_newsa_info(p, (struct rtattr **)xfrma);
+ err = verify_newsa_info(p, xfrma);
if (err)
return err;
- x = xfrm_state_construct(p, (struct rtattr **)xfrma, &err);
+ x = xfrm_state_construct(p, xfrma, &err);
if (!x)
return err;
@@ -507,14 +508,15 @@ static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p,
return x;
}
-static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct xfrm_state *x;
int err = -ESRCH;
struct km_event c;
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
- x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err);
+ x = xfrm_user_state_lookup(p, xfrma, &err);
if (x == NULL)
return err;
@@ -672,14 +674,15 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
return skb;
}
-static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
struct xfrm_state *x;
struct sk_buff *resp_skb;
int err = -ESRCH;
- x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err);
+ x = xfrm_user_state_lookup(p, xfrma, &err);
if (x == NULL)
goto out_noput;
@@ -718,7 +721,8 @@ static int verify_userspi_info(struct xfrm_userspi_info *p)
return 0;
}
-static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct xfrm_state *x;
struct xfrm_userspi_info *p;
@@ -1013,7 +1017,8 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p,
return NULL;
}
-static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh);
struct xfrm_policy *xp;
@@ -1024,11 +1029,11 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
err = verify_newpolicy_info(p);
if (err)
return err;
- err = verify_sec_ctx_len((struct rtattr **)xfrma);
+ err = verify_sec_ctx_len(xfrma);
if (err)
return err;
- xp = xfrm_policy_construct(p, (struct rtattr **)xfrma, &err);
+ xp = xfrm_policy_construct(p, xfrma, &err);
if (!xp)
return err;
@@ -1227,7 +1232,8 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
return skb;
}
-static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct xfrm_policy *xp;
struct xfrm_userpolicy_id *p;
@@ -1239,7 +1245,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
p = NLMSG_DATA(nlh);
delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
- err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma);
+ err = copy_from_user_policy_type(&type, xfrma);
if (err)
return err;
@@ -1250,11 +1256,10 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
if (p->index)
xp = xfrm_policy_byid(type, p->dir, p->index, delete);
else {
- struct rtattr **rtattrs = (struct rtattr **)xfrma;
- struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1];
+ struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1];
struct xfrm_policy tmp;
- err = verify_sec_ctx_len(rtattrs);
+ err = verify_sec_ctx_len(xfrma);
if (err)
return err;
@@ -1302,7 +1307,8 @@ out:
return err;
}
-static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct km_event c;
struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);
@@ -1367,7 +1373,8 @@ nlmsg_failure:
return -1;
}
-static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct xfrm_state *x;
struct sk_buff *r_skb;
@@ -1415,7 +1422,8 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
return err;
}
-static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct xfrm_state *x;
struct km_event c;
@@ -1439,7 +1447,7 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
goto out;
spin_lock_bh(&x->lock);
- err = xfrm_update_ae_params(x,(struct rtattr **)xfrma);
+ err = xfrm_update_ae_params(x, xfrma);
spin_unlock_bh(&x->lock);
if (err < 0)
goto out;
@@ -1455,14 +1463,15 @@ out:
return err;
}
-static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct km_event c;
u8 type = XFRM_POLICY_TYPE_MAIN;
int err;
struct xfrm_audit audit_info;
- err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma);
+ err = copy_from_user_policy_type(&type, xfrma);
if (err)
return err;
@@ -1477,7 +1486,8 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **x
return 0;
}
-static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct xfrm_policy *xp;
struct xfrm_user_polexpire *up = NLMSG_DATA(nlh);
@@ -1485,18 +1495,17 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void *
u8 type = XFRM_POLICY_TYPE_MAIN;
int err = -ENOENT;
- err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma);
+ err = copy_from_user_policy_type(&type, xfrma);
if (err)
return err;
if (p->index)
xp = xfrm_policy_byid(type, p->dir, p->index, 0);
else {
- struct rtattr **rtattrs = (struct rtattr **)xfrma;
- struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1];
+ struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1];
struct xfrm_policy tmp;
- err = verify_sec_ctx_len(rtattrs);
+ err = verify_sec_ctx_len(xfrma);
if (err)
return err;
@@ -1537,7 +1546,8 @@ out:
return err;
}
-static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct xfrm_state *x;
int err;
@@ -1568,7 +1578,8 @@ out:
return err;
}
-static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
{
struct xfrm_policy *xp;
struct xfrm_user_tmpl *ut;
@@ -1621,6 +1632,176 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xf
return 0;
}
+#ifdef CONFIG_XFRM_MIGRATE
+static int verify_user_migrate(struct rtattr **xfrma)
+{
+ struct rtattr *rt = xfrma[XFRMA_MIGRATE-1];
+ struct xfrm_user_migrate *um;
+
+ if (!rt)
+ return -EINVAL;
+
+ if ((rt->rta_len - sizeof(*rt)) < sizeof(*um))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int copy_from_user_migrate(struct xfrm_migrate *ma,
+ struct rtattr **xfrma, int *num)
+{
+ struct rtattr *rt = xfrma[XFRMA_MIGRATE-1];
+ struct xfrm_user_migrate *um;
+ int i, num_migrate;
+
+ um = RTA_DATA(rt);
+ num_migrate = (rt->rta_len - sizeof(*rt)) / sizeof(*um);
+
+ if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH)
+ return -EINVAL;
+
+ for (i = 0; i < num_migrate; i++, um++, ma++) {
+ memcpy(&ma->old_daddr, &um->old_daddr, sizeof(ma->old_daddr));
+ memcpy(&ma->old_saddr, &um->old_saddr, sizeof(ma->old_saddr));
+ memcpy(&ma->new_daddr, &um->new_daddr, sizeof(ma->new_daddr));
+ memcpy(&ma->new_saddr, &um->new_saddr, sizeof(ma->new_saddr));
+
+ ma->proto = um->proto;
+ ma->mode = um->mode;
+ ma->reqid = um->reqid;
+
+ ma->old_family = um->old_family;
+ ma->new_family = um->new_family;
+ }
+
+ *num = i;
+ return 0;
+}
+
+static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
+{
+ struct xfrm_userpolicy_id *pi = NLMSG_DATA(nlh);
+ struct xfrm_migrate m[XFRM_MAX_DEPTH];
+ u8 type;
+ int err;
+ int n = 0;
+
+ err = verify_user_migrate((struct rtattr **)xfrma);
+ if (err)
+ return err;
+
+ err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma);
+ if (err)
+ return err;
+
+ err = copy_from_user_migrate((struct xfrm_migrate *)m,
+ (struct rtattr **)xfrma, &n);
+ if (err)
+ return err;
+
+ if (!n)
+ return 0;
+
+ xfrm_migrate(&pi->sel, pi->dir, type, m, n);
+
+ return 0;
+}
+#else
+static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
+{
+ return -ENOPROTOOPT;
+}
+#endif
+
+#ifdef CONFIG_XFRM_MIGRATE
+static int copy_to_user_migrate(struct xfrm_migrate *m, struct sk_buff *skb)
+{
+ struct xfrm_user_migrate um;
+
+ memset(&um, 0, sizeof(um));
+ um.proto = m->proto;
+ um.mode = m->mode;
+ um.reqid = m->reqid;
+ um.old_family = m->old_family;
+ memcpy(&um.old_daddr, &m->old_daddr, sizeof(um.old_daddr));
+ memcpy(&um.old_saddr, &m->old_saddr, sizeof(um.old_saddr));
+ um.new_family = m->new_family;
+ memcpy(&um.new_daddr, &m->new_daddr, sizeof(um.new_daddr));
+ memcpy(&um.new_saddr, &m->new_saddr, sizeof(um.new_saddr));
+
+ RTA_PUT(skb, XFRMA_MIGRATE, sizeof(um), &um);
+ return 0;
+
+rtattr_failure:
+ return -1;
+}
+
+static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m,
+ int num_migrate, struct xfrm_selector *sel,
+ u8 dir, u8 type)
+{
+ struct xfrm_migrate *mp;
+ struct xfrm_userpolicy_id *pol_id;
+ struct nlmsghdr *nlh;
+ unsigned char *b = skb->tail;
+ int i;
+
+ nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id));
+ pol_id = NLMSG_DATA(nlh);
+ nlh->nlmsg_flags = 0;
+
+ /* copy data from selector, dir, and type to the pol_id */
+ memset(pol_id, 0, sizeof(*pol_id));
+ memcpy(&pol_id->sel, sel, sizeof(pol_id->sel));
+ pol_id->dir = dir;
+
+ if (copy_to_user_policy_type(type, skb) < 0)
+ goto nlmsg_failure;
+
+ for (i = 0, mp = m ; i < num_migrate; i++, mp++) {
+ if (copy_to_user_migrate(mp, skb) < 0)
+ goto nlmsg_failure;
+ }
+
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+nlmsg_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+
+static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+ struct xfrm_migrate *m, int num_migrate)
+{
+ struct sk_buff *skb;
+ size_t len;
+
+ len = RTA_SPACE(sizeof(struct xfrm_user_migrate) * num_migrate);
+ len += NLMSG_SPACE(sizeof(struct xfrm_userpolicy_id));
+#ifdef CONFIG_XFRM_SUB_POLICY
+ len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type));
+#endif
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+
+ /* build migrate */
+ if (build_migrate(skb, m, num_migrate, sel, dir, type) < 0)
+ BUG();
+
+ NETLINK_CB(skb).dst_group = XFRMNLGRP_MIGRATE;
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE,
+ GFP_ATOMIC);
+}
+#else
+static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
+ struct xfrm_migrate *m, int num_migrate)
+{
+ return -ENOPROTOOPT;
+}
+#endif
#define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type))
@@ -1642,12 +1823,13 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
[XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
[XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
[XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
+ [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
};
#undef XMSGSIZE
static struct xfrm_link {
- int (*doit)(struct sk_buff *, struct nlmsghdr *, void **);
+ int (*doit)(struct sk_buff *, struct nlmsghdr *, struct rtattr **);
int (*dump)(struct sk_buff *, struct netlink_callback *);
} xfrm_dispatch[XFRM_NR_MSGTYPES] = {
[XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
@@ -1668,6 +1850,7 @@ static struct xfrm_link {
[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy },
[XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae },
[XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae },
+ [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },
};
static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
@@ -1735,7 +1918,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err
if (link->doit == NULL)
goto err_einval;
- *errp = link->doit(skb, nlh, (void **) &xfrma);
+ *errp = link->doit(skb, nlh, xfrma);
return *errp;
@@ -2274,6 +2457,7 @@ static struct xfrm_mgr netlink_mgr = {
.compile_policy = xfrm_compile_policy,
.notify_policy = xfrm_send_policy_notify,
.report = xfrm_send_report,
+ .migrate = xfrm_send_migrate,
};
static int __init xfrm_user_init(void)
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 4f5ff19b992..06c1a377c4c 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -1,7 +1,7 @@
####
# kbuild: Generic definitions
-# Convinient variables
+# Convenient variables
comma := ,
squote := '
empty :=
@@ -56,30 +56,43 @@ endef
# gcc support functions
# See documentation in Documentation/kbuild/makefiles.txt
+# output directory for tests below
+TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
+
+# try-run
+# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
+# Exit code chooses option. "$$TMP" is can be used as temporary file and
+# is automatically cleaned up.
+try-run = $(shell set -e; \
+ TMP="$(TMPOUT).$$$$.tmp"; \
+ if ($(1)) >/dev/null 2>&1; \
+ then echo "$(2)"; \
+ else echo "$(3)"; \
+ fi; \
+ rm -f "$$TMP")
+
# as-option
-# Usage: cflags-y += $(call as-option, -Wa$(comma)-isa=foo,)
+# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
-as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \
- -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \
- else echo "$(2)"; fi ;)
+as-option = $(call try-run,\
+ $(CC) $(CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2))
# as-instr
-# Usage: cflags-y += $(call as-instr, instr, option1, option2)
+# Usage: cflags-y += $(call as-instr,instr,option1,option2)
-as-instr = $(shell if echo -e "$(1)" | $(AS) >/dev/null 2>&1 -W -Z -o astest$$$$.out ; \
- then echo "$(2)"; else echo "$(3)"; fi; \
- rm -f astest$$$$.out)
+as-instr = $(call try-run,\
+ echo -e "$(1)" | $(CC) $(AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
# cc-option
-# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586)
+# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
-cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
- > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
+cc-option = $(call try-run,\
+ $(CC) $(CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",$(1),$(2))
# cc-option-yn
-# Usage: flag := $(call cc-option-yn, -march=winchip-c6)
-cc-option-yn = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
- > /dev/null 2>&1; then echo "y"; else echo "n"; fi;)
+# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
+cc-option-yn = $(call try-run,\
+ $(CC) $(CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
# cc-option-align
# Prefix align with either -falign or -malign
@@ -87,20 +100,19 @@ cc-option-align = $(subst -functions=0,,\
$(call cc-option,-falign-functions=0,-malign-functions=0))
# cc-version
-# Usage gcc-ver := $(call cc-version, $(CC))
+# Usage gcc-ver := $(call cc-version,$(CC))
cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
# cc-ifversion
# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
-cc-ifversion = $(shell if [ $(call cc-version, $(CC)) $(1) $(2) ]; then \
- echo $(3); fi;)
+cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3))
# ld-option
# Usage: ldflags += $(call ld-option, -Wl$(comma)--hash-style=both)
-ld-option = $(shell if $(CC) $(1) \
- -nostdlib -o ldtest$$$$.out -xc /dev/null \
- > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi; \
- rm -f ldtest$$$$.out)
+ld-option = $(call try-run,\
+ $(CC) $(1) -nostdlib -xc /dev/null -o "$$TMP",$(1),$(2))
+
+######
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
@@ -108,19 +120,25 @@ ld-option = $(shell if $(CC) $(1) \
# $(Q)$(MAKE) $(build)=dir
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
-# Prefix -I with $(srctree) if it is not an absolute path
+# Prefix -I with $(srctree) if it is not an absolute path.
addtree = $(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1)
+
# Find all -I options and call addtree
flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
-# If quiet is set, only print short version of command
+# echo command.
+# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
+echo-cmd = $(if $($(quiet)cmd_$(1)),\
+ echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
+
+# printing commands
cmd = @$(echo-cmd) $(cmd_$(1))
-# Add $(obj)/ for paths that is not absolute
+# Add $(obj)/ for paths that are not absolute
objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
###
-# if_changed - execute command if any prerequisite is newer than
+# if_changed - execute command if any prerequisite is newer than
# target, or command line has changed
# if_changed_dep - as if_changed, but uses fixdep to reveal dependencies
# including used config symbols
@@ -128,16 +146,12 @@ objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
# See Documentation/kbuild/makefiles.txt for more info
ifneq ($(KBUILD_NOCMDDEP),1)
-# Check if both arguments has same arguments. Result in empty string if equal
+# Check if both arguments has same arguments. Result is empty string if equal.
# User may override this check using make KBUILD_NOCMDDEP=1
arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
$(filter-out $(cmd_$@), $(cmd_$(1))) )
endif
-# echo command. Short version is $(quiet) equals quiet, otherwise full command
-echo-cmd = $(if $($(quiet)cmd_$(1)), \
- echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
-
# >'< substitution is for echo to work,
# >$< substitution to preserve $ when reloading .cmd file
# note: when using inline perl scripts [perl -e '...$$t=1;...']
@@ -148,15 +162,14 @@ make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))
# PHONY targets skipped in both cases.
any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
-# Execute command if command has changed or prerequisitei(s) are updated
+# Execute command if command has changed or prerequisite(s) are updated.
#
if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
@set -e; \
$(echo-cmd) $(cmd_$(1)); \
echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
-# execute the command and also postprocess generated .d dependencies
-# file
+# Execute the command and also postprocess generated .d dependencies file.
if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \
@set -e; \
$(echo-cmd) $(cmd_$(1)); \
@@ -165,8 +178,8 @@ if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \
mv -f $(dot-target).tmp $(dot-target).cmd)
# Usage: $(call if_changed_rule,foo)
-# will check if $(cmd_foo) changed, or any of the prequisites changed,
-# and if so will execute $(rule_foo)
+# Will check if $(cmd_foo) or any of the prerequisites changed,
+# and if so will execute $(rule_foo).
if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \
@set -e; \
$(rule_$(1)))
diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst
index 4241e0dfeea..f7b6705fd6a 100644
--- a/scripts/Makefile.headersinst
+++ b/scripts/Makefile.headersinst
@@ -109,7 +109,7 @@ quiet_cmd_mkdir = MKDIR $(patsubst $(INSTALL_HDR_PATH)/%,%,$@)
quiet_cmd_gen = GEN $(patsubst $(INSTALL_HDR_PATH)/%,%,$@)
cmd_gen = \
FNAME=$(patsubst $(INSTALL_HDR_PATH)/$(_dst)/%,%,$@) \
-STUBDEF=__ASM_STUB_`echo $$FNAME | tr a-z. A-Z_`; \
+STUBDEF=__ASM_STUB_`echo $$FNAME | tr a-z.- A-Z__`; \
(echo "/* File autogenerated by 'make headers_install' */" ; \
echo "\#ifndef $$STUBDEF" ; \
echo "\#define $$STUBDEF" ; \
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index 4c723fd1864..43f75d6e4d9 100644
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
-# Copyright (c) 2006 Sam Ravnborg <sam@ravnborg.org>
+# Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
#
# Released under the terms of the GNU GPL
#
@@ -17,15 +17,15 @@ cat << EOF
Usage:
$0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
-o <file> Create gzipped initramfs file named <file> using
- gen_init_cpio and gzip
+ gen_init_cpio and gzip
-u <uid> User ID to map to user ID 0 (root).
- <uid> is only meaningful if <cpio_source>
- is a directory.
+ <uid> is only meaningful if <cpio_source>
+ is a directory.
-g <gid> Group ID to map to group ID 0 (root).
- <gid> is only meaningful if <cpio_source>
- is a directory.
+ <gid> is only meaningful if <cpio_source>
+ is a directory.
<cpio_source> File list or directory for cpio archive.
- If <cpio_source> is a .cpio file it will be used
+ If <cpio_source> is a .cpio file it will be used
as direct input to initramfs.
-d Output the default cpio list.
@@ -36,6 +36,12 @@ to reset the root/group mapping.
EOF
}
+# awk style field access
+# $1 - field number; rest is argument string
+field() {
+ shift $1 ; echo $1
+}
+
list_default_initramfs() {
# echo usr/kinit/kinit
:
@@ -119,22 +125,17 @@ parse() {
str="${ftype} ${name} ${location} ${str}"
;;
"nod")
- local dev_type=
- local maj=$(LC_ALL=C ls -l "${location}" | \
- gawk '{sub(/,/, "", $5); print $5}')
- local min=$(LC_ALL=C ls -l "${location}" | \
- gawk '{print $6}')
-
- if [ -b "${location}" ]; then
- dev_type="b"
- else
- dev_type="c"
- fi
- str="${ftype} ${name} ${str} ${dev_type} ${maj} ${min}"
+ local dev=`LC_ALL=C ls -l "${location}"`
+ local maj=`field 5 ${dev}`
+ local min=`field 6 ${dev}`
+ maj=${maj%,}
+
+ [ -b "${location}" ] && dev="b" || dev="c"
+
+ str="${ftype} ${name} ${str} ${dev} ${maj} ${min}"
;;
"slink")
- local target=$(LC_ALL=C ls -l "${location}" | \
- gawk '{print $11}')
+ local target=`field 11 $(LC_ALL=C ls -l "${location}")`
str="${ftype} ${name} ${target} ${str}"
;;
*)
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index f359b730c2c..8b809b264d1 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -265,7 +265,7 @@ static void write_src(void)
printf("#define ALGN .align 4\n");
printf("#endif\n");
- printf(".data\n");
+ printf("\t.section .rodata, \"a\"\n");
/* Provide proper symbols relocatability by their '_text'
* relativeness. The symbol names cannot be used to construct
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 4dcb8867b5f..124b341a18c 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -600,7 +600,7 @@ int main(int ac, char **av)
input_mode = ask_silent;
valid_stdin = 1;
}
- } else if (sym_change_count) {
+ } else if (conf_get_changed()) {
name = getenv("KCONFIG_NOSILENTUPDATE");
if (name && *name) {
fprintf(stderr, _("\n*** Kernel configuration requires explicit update.\n\n"));
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 66b15ef0293..664fe29dace 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -100,7 +100,7 @@ int conf_read_simple(const char *name, int def)
in = zconf_fopen(name);
if (in)
goto load;
- sym_change_count++;
+ sym_add_change_count(1);
if (!sym_defconfig_list)
return 1;
@@ -312,7 +312,7 @@ int conf_read(const char *name)
struct expr *e;
int i, flags;
- sym_change_count = 0;
+ sym_set_change_count(0);
if (conf_read_simple(name, S_DEF_USER))
return 1;
@@ -364,7 +364,7 @@ int conf_read(const char *name)
sym->flags &= flags | ~SYMBOL_DEF_USER;
}
- sym_change_count += conf_warnings || conf_unsaved;
+ sym_add_change_count(conf_warnings || conf_unsaved);
return 0;
}
@@ -432,7 +432,7 @@ int conf_write(const char *name)
use_timestamp ? "# " : "",
use_timestamp ? ctime(&now) : "");
- if (!sym_change_count)
+ if (!conf_get_changed())
sym_clear_all_valid();
menu = rootmenu.list;
@@ -528,7 +528,7 @@ int conf_write(const char *name)
"# configuration written to %s\n"
"#\n"), newname);
- sym_change_count = 0;
+ sym_set_change_count(0);
return 0;
}
@@ -765,3 +765,30 @@ int conf_write_autoconf(void)
return 0;
}
+
+static int sym_change_count;
+static void (*conf_changed_callback)(void);
+
+void sym_set_change_count(int count)
+{
+ int _sym_change_count = sym_change_count;
+ sym_change_count = count;
+ if (conf_changed_callback &&
+ (bool)_sym_change_count != (bool)count)
+ conf_changed_callback();
+}
+
+void sym_add_change_count(int count)
+{
+ sym_set_change_count(count + sym_change_count);
+}
+
+bool conf_get_changed(void)
+{
+ return sym_change_count;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+ conf_changed_callback = fn;
+}
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
index 7b0d3a93d5c..61d8166166e 100644
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -38,8 +38,6 @@ static gboolean show_all = FALSE;
static gboolean show_debug = FALSE;
static gboolean resizeable = FALSE;
-static gboolean config_changed = FALSE;
-
static char nohelp_text[] =
N_("Sorry, no help available for this option yet.\n");
@@ -50,6 +48,8 @@ GtkWidget *text_w = NULL;
GtkWidget *hpaned = NULL;
GtkWidget *vpaned = NULL;
GtkWidget *back_btn = NULL;
+GtkWidget *save_btn = NULL;
+GtkWidget *save_menu_item = NULL;
GtkTextTag *tag1, *tag2;
GdkColor color;
@@ -75,7 +75,7 @@ static void display_tree_part(void);
static void update_tree(struct menu *src, GtkTreeIter * dst);
static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
static gchar **fill_row(struct menu *menu);
-
+static void conf_changed(void);
/* Helping/Debugging Functions */
@@ -224,6 +224,10 @@ void init_main_window(const gchar * glade_file)
gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
show_value);
+ save_btn = glade_xml_get_widget(xml, "button3");
+ save_menu_item = glade_xml_get_widget(xml, "save1");
+ conf_set_changed_callback(conf_changed);
+
style = gtk_widget_get_style(main_wnd);
widget = glade_xml_get_widget(xml, "toolbar1");
@@ -512,14 +516,14 @@ static void text_insert_msg(const char *title, const char *message)
/* Main Windows Callbacks */
-void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data);
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
gpointer user_data)
{
GtkWidget *dialog, *label;
gint result;
- if (config_changed == FALSE)
+ if (!conf_get_changed())
return FALSE;
dialog = gtk_dialog_new_with_buttons(_("Warning !"),
@@ -543,7 +547,7 @@ gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
result = gtk_dialog_run(GTK_DIALOG(dialog));
switch (result) {
case GTK_RESPONSE_YES:
- on_save1_activate(NULL, NULL);
+ on_save_activate(NULL, NULL);
return FALSE;
case GTK_RESPONSE_NO:
return FALSE;
@@ -621,12 +625,10 @@ void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
}
-void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data)
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
{
if (conf_write(NULL))
text_insert_msg(_("Error"), _("Unable to save configuration !"));
-
- config_changed = FALSE;
}
@@ -819,12 +821,6 @@ void on_load_clicked(GtkButton * button, gpointer user_data)
}
-void on_save_clicked(GtkButton * button, gpointer user_data)
-{
- on_save1_activate(NULL, user_data);
-}
-
-
void on_single_clicked(GtkButton * button, gpointer user_data)
{
view_mode = SINGLE_VIEW;
@@ -899,7 +895,6 @@ static void renderer_edited(GtkCellRendererText * cell,
sym_set_string_value(sym, new_def);
- config_changed = TRUE;
update_tree(&rootmenu, NULL);
gtk_tree_path_free(path);
@@ -930,7 +925,6 @@ static void change_sym_value(struct menu *menu, gint col)
if (!sym_tristate_within_range(sym, newval))
newval = yes;
sym_set_tristate_value(sym, newval);
- config_changed = TRUE;
if (view_mode == FULL_VIEW)
update_tree(&rootmenu, NULL);
else if (view_mode == SPLIT_VIEW) {
@@ -1633,3 +1627,10 @@ int main(int ac, char *av[])
return 0;
}
+
+static void conf_changed(void)
+{
+ bool changed = conf_get_changed();
+ gtk_widget_set_sensitive(save_btn, changed);
+ gtk_widget_set_sensitive(save_menu_item, changed);
+}
diff --git a/scripts/kconfig/gconf.glade b/scripts/kconfig/gconf.glade
index f8744ed6496..803233fdd6d 100644
--- a/scripts/kconfig/gconf.glade
+++ b/scripts/kconfig/gconf.glade
@@ -70,7 +70,7 @@
<property name="tooltip" translatable="yes">Save the config in .config</property>
<property name="label" translatable="yes">_Save</property>
<property name="use_underline">True</property>
- <signal name="activate" handler="on_save1_activate"/>
+ <signal name="activate" handler="on_save_activate"/>
<accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
@@ -380,7 +380,7 @@
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
- <signal name="clicked" handler="on_save_clicked"/>
+ <signal name="clicked" handler="on_save_activate"/>
</widget>
<packing>
<property name="expand">False</property>
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 2628023a1fe..9b2706a4154 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -65,6 +65,8 @@ char *zconf_curname(void);
/* confdata.c */
char *conf_get_default_confname(void);
+void sym_set_change_count(int count);
+void sym_add_change_count(int count);
/* kconfig_load.c */
void kconfig_load(void);
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index a263746cfa7..15030770d1a 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -5,6 +5,8 @@ P(conf_read,int,(const char *name));
P(conf_read_simple,int,(const char *name, int));
P(conf_write,int,(const char *name));
P(conf_write_autoconf,int,(void));
+P(conf_get_changed,bool,(void));
+P(conf_set_changed_callback, void,(void (*fn)(void)));
/* menu.c */
P(rootmenu,struct menu,);
@@ -16,7 +18,6 @@ P(menu_get_parent_menu,struct menu *,(struct menu *menu));
/* symbol.c */
P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
-P(sym_change_count,int,);
P(sym_lookup,struct symbol *,(const char *name, int isconst));
P(sym_find,struct symbol *,(const char *name));
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 08a4c7af93e..3f9a1321b3e 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -890,14 +890,19 @@ int main(int ac, char **av)
do {
conf(&rootmenu);
dialog_clear();
- res = dialog_yesno(NULL,
- _("Do you wish to save your "
- "new kernel configuration?\n"
- "<ESC><ESC> to continue."),
- 6, 60);
+ if (conf_get_changed())
+ res = dialog_yesno(NULL,
+ _("Do you wish to save your "
+ "new kernel configuration?\n"
+ "<ESC><ESC> to continue."),
+ 6, 60);
+ else
+ res = -1;
} while (res == KEY_ESC);
end_dialog();
- if (res == 0) {
+
+ switch (res) {
+ case 0:
if (conf_write(NULL)) {
fprintf(stderr, _("\n\n"
"Error during writing of the kernel configuration.\n"
@@ -905,11 +910,13 @@ int main(int ac, char **av)
"\n\n"));
return 1;
}
+ case -1:
printf(_("\n\n"
"*** End of Linux kernel configuration.\n"
"*** Execute 'make' to build the kernel or try 'make help'."
"\n\n"));
- } else {
+ break;
+ default:
fprintf(stderr, _("\n\n"
"Your kernel configuration changes were NOT saved."
"\n\n"));
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index f5628c57640..c0ae0a7ddb4 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -38,6 +38,8 @@
static QApplication *configApp;
static ConfigSettings *configSettings;
+QAction *ConfigMainWindow::saveAction;
+
static inline QString qgettext(const char* str)
{
return QString::fromLocal8Bit(gettext(str));
@@ -915,7 +917,7 @@ void ConfigView::updateListAll(void)
}
ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
- : Parent(parent, name), menu(0)
+ : Parent(parent, name), menu(0), sym(0)
{
if (name) {
configSettings->beginGroup(name);
@@ -951,6 +953,7 @@ void ConfigInfoView::setInfo(struct menu *m)
if (menu == m)
return;
menu = m;
+ sym = NULL;
if (!menu)
clear();
else
@@ -1306,8 +1309,11 @@ ConfigMainWindow::ConfigMainWindow(void)
connect(quitAction, SIGNAL(activated()), SLOT(close()));
QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this);
connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
- QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this);
+ saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this);
connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
+ conf_set_changed_callback(conf_changed);
+ // Set saveAction's initial state
+ conf_changed();
QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this);
connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
QAction *searchAction = new QAction("Search", "&Search", CTRL+Key_F, this);
@@ -1585,7 +1591,7 @@ void ConfigMainWindow::showFullView(void)
*/
void ConfigMainWindow::closeEvent(QCloseEvent* e)
{
- if (!sym_change_count) {
+ if (!conf_get_changed()) {
e->accept();
return;
}
@@ -1658,6 +1664,12 @@ void ConfigMainWindow::saveSettings(void)
configSettings->writeSizes("/split2", split2->sizes());
}
+void ConfigMainWindow::conf_changed(void)
+{
+ if (saveAction)
+ saveAction->setEnabled(conf_get_changed());
+}
+
void fixup_rootmenu(struct menu *menu)
{
struct menu *child;
diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
index 6a9e3b14c22..6fc1c5f1442 100644
--- a/scripts/kconfig/qconf.h
+++ b/scripts/kconfig/qconf.h
@@ -297,6 +297,9 @@ protected:
class ConfigMainWindow : public QMainWindow {
Q_OBJECT
+
+ static QAction *saveAction;
+ static void conf_changed(void);
public:
ConfigMainWindow(void);
public slots:
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index ee225ced2ce..8f06c474d80 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -30,7 +30,6 @@ struct symbol symbol_yes = {
.flags = SYMBOL_VALID,
};
-int sym_change_count;
struct symbol *sym_defconfig_list;
struct symbol *modules_sym;
tristate modules_val;
@@ -379,7 +378,7 @@ void sym_clear_all_valid(void)
for_all_symbols(i, sym)
sym->flags &= ~SYMBOL_VALID;
- sym_change_count++;
+ sym_add_change_count(1);
if (modules_sym)
sym_calc_value(modules_sym);
}
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index 2fb0a4fc61d..d777fe85627 100644
--- a/scripts/kconfig/zconf.tab.c_shipped
+++ b/scripts/kconfig/zconf.tab.c_shipped
@@ -2135,7 +2135,7 @@ void conf_parse(const char *name)
sym_check_deps(sym);
}
- sym_change_count = 1;
+ sym_set_change_count(1);
}
const char *zconf_tokenname(int token)
diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y
index ab44feb3c60..04a5864c03b 100644
--- a/scripts/kconfig/zconf.y
+++ b/scripts/kconfig/zconf.y
@@ -504,7 +504,7 @@ void conf_parse(const char *name)
sym_check_deps(sym);
}
- sym_change_count = 1;
+ sym_set_change_count(1);
}
const char *zconf_tokenname(int token)
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index df3b272f7ce..f50a70f550b 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -1469,6 +1469,7 @@ sub push_parameter($$$) {
my $param = shift;
my $type = shift;
my $file = shift;
+ my $anon = 0;
my $param_name = $param;
$param_name =~ s/\[.*//;
@@ -1484,9 +1485,20 @@ sub push_parameter($$$) {
$param="void";
$parameterdescs{void} = "no arguments";
}
+ elsif ($type eq "" && ($param eq "struct" or $param eq "union"))
+ # handle unnamed (anonymous) union or struct:
+ {
+ $type = $param;
+ $param = "{unnamed_" . $param. "}";
+ $parameterdescs{$param} = "anonymous\n";
+ $anon = 1;
+ }
+
# warn if parameter has no description
- # (but ignore ones starting with # as these are no parameters
- # but inline preprocessor statements
+ # (but ignore ones starting with # as these are not parameters
+ # but inline preprocessor statements);
+ # also ignore unnamed structs/unions;
+ if (!$anon) {
if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) {
$parameterdescs{$param_name} = $undescribed;
@@ -1500,6 +1512,7 @@ sub push_parameter($$$) {
" No description found for parameter '$param'\n";
++$warnings;
}
+ }
push @parameterlist, $param;
$parametertypes{$param} = $type;
diff --git a/scripts/makelst b/scripts/makelst
index 34bd7239123..4fc80f2b7e1 100755
--- a/scripts/makelst
+++ b/scripts/makelst
@@ -1,31 +1,31 @@
-#!/bin/bash
+#!/bin/sh
# A script to dump mixed source code & assembly
# with correct relocations from System.map
-# Requires the following lines in Rules.make.
-# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
-# William Stearns <wstearns@pobox.com>
+# Requires the following lines in makefile:
#%.lst: %.c
# $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
-# $(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP)
+# $(srctree)/scripts/makelst $*.o $(objtree)/System.map $(OBJDUMP)
#
-# Copyright (C) 2000 IBM Corporation
-# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+# Copyright (C) 2000 IBM Corporation
+# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+# William Stearns <wstearns@pobox.com>
#
-t1=`$3 --syms $1 | grep .text | grep " F " | head -n 1`
+# awk style field access
+field() {
+ shift $1 ; echo $1
+}
+
+t1=`$3 --syms $1 | grep .text | grep -m1 " F "`
if [ -n "$t1" ]; then
- t2=`echo $t1 | gawk '{ print $6 }'`
+ t2=`field 6 $t1`
if [ ! -r $2 ]; then
echo "No System.map" >&2
- t7=0
else
t3=`grep $t2 $2`
- t4=`echo $t3 | gawk '{ print $1 }'`
- t5=`echo $t1 | gawk '{ print $1 }'`
- t6=`echo $t4 - $t5 | tr a-f A-F`
- t7=`( echo ibase=16 ; echo $t6 ) | bc`
+ t4=`field 1 $t3`
+ t5=`field 1 $t1`
+ t6=`printf "%lu" $((0x$t4 - 0x$t5))`
fi
-else
- t7=0
fi
-$3 -r --source --adjust-vma=$t7 $1
+$3 -r --source --adjust-vma=${t6:-0} $1
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index ac0a5822299..2aa47623f5f 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -582,9 +582,19 @@ static int strrcmp(const char *s, const char *sub)
* tosec = .init.text | .exit.text | .init.data
* fromsec = .data
* atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one
+ *
+ * Pattern 3:
+ * Some symbols belong to init section but still it is ok to reference
+ * these from non-init sections as these symbols don't have any memory
+ * allocated for them and symbol address and value are same. So even
+ * if init section is freed, its ok to reference those symbols.
+ * For ex. symbols marking the init section boundaries.
+ * This pattern is identified by
+ * refsymname = __init_begin, _sinittext, _einittext
**/
static int secref_whitelist(const char *modname, const char *tosec,
- const char *fromsec, const char *atsym)
+ const char *fromsec, const char *atsym,
+ const char *refsymname)
{
int f1 = 1, f2 = 1;
const char **s;
@@ -595,6 +605,14 @@ static int secref_whitelist(const char *modname, const char *tosec,
"_ops",
"_probe",
"_probe_one",
+ "_console",
+ NULL
+ };
+
+ const char *pat3refsym[] = {
+ "__init_begin",
+ "_sinittext",
+ "_einittext",
NULL
};
@@ -628,6 +646,11 @@ static int secref_whitelist(const char *modname, const char *tosec,
if ((strcmp(fromsec, ".pci_fixup") == 0) &&
(strcmp(tosec, ".init.text") == 0))
return 1;
+
+ /* Check for pattern 3 */
+ for (s = pat3refsym; *s; s++)
+ if (strcmp(refsymname, *s) == 0)
+ return 1;
}
return 0;
}
@@ -737,7 +760,7 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
/* check whitelist - we may ignore it */
if (before &&
secref_whitelist(modname, secname, fromsec,
- elf->strtab + before->st_name))
+ elf->strtab + before->st_name, refsymname))
return;
if (before && after) {
@@ -997,6 +1020,7 @@ static int exit_section_ref_ok(const char *name)
"__bug_table", /* used by powerpc for BUG() */
".exitcall.exit",
".eh_frame",
+ ".parainstructions",
".stab",
"__ex_table",
".fixup",
diff --git a/security/keys/key.c b/security/keys/key.c
index ac9326c5f1d..700400d801d 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -188,6 +188,7 @@ static inline void key_alloc_serial(struct key *key)
spin_lock(&key_serial_lock);
+attempt_insertion:
parent = NULL;
p = &key_serial_tree.rb_node;
@@ -202,39 +203,33 @@ static inline void key_alloc_serial(struct key *key)
else
goto serial_exists;
}
- goto insert_here;
+
+ /* we've found a suitable hole - arrange for this key to occupy it */
+ rb_link_node(&key->serial_node, parent, p);
+ rb_insert_color(&key->serial_node, &key_serial_tree);
+
+ spin_unlock(&key_serial_lock);
+ return;
/* we found a key with the proposed serial number - walk the tree from
* that point looking for the next unused serial number */
serial_exists:
for (;;) {
key->serial++;
- if (key->serial < 2)
- key->serial = 2;
-
- if (!rb_parent(parent))
- p = &key_serial_tree.rb_node;
- else if (rb_parent(parent)->rb_left == parent)
- p = &(rb_parent(parent)->rb_left);
- else
- p = &(rb_parent(parent)->rb_right);
+ if (key->serial < 3) {
+ key->serial = 3;
+ goto attempt_insertion;
+ }
parent = rb_next(parent);
if (!parent)
- break;
+ goto attempt_insertion;
xkey = rb_entry(parent, struct key, serial_node);
if (key->serial < xkey->serial)
- goto insert_here;
+ goto attempt_insertion;
}
- /* we've found a suitable hole - arrange for this key to occupy it */
-insert_here:
- rb_link_node(&key->serial_node, parent, p);
- rb_insert_color(&key->serial_node, &key_serial_tree);
-
- spin_unlock(&key_serial_lock);
-
} /* end key_alloc_serial() */
/*****************************************************************************/
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 44e9cd47054..65fb5e8ea94 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1120,8 +1120,8 @@ static int file_has_perm(struct task_struct *tsk,
{
struct task_security_struct *tsec = tsk->security;
struct file_security_struct *fsec = file->f_security;
- struct vfsmount *mnt = file->f_vfsmnt;
- struct dentry *dentry = file->f_dentry;
+ struct vfsmount *mnt = file->f_path.mnt;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct avc_audit_data ad;
int rc;
@@ -1581,7 +1581,7 @@ static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
static int selinux_bprm_set_security(struct linux_binprm *bprm)
{
struct task_security_struct *tsec;
- struct inode *inode = bprm->file->f_dentry->d_inode;
+ struct inode *inode = bprm->file->f_path.dentry->d_inode;
struct inode_security_struct *isec;
struct bprm_security_struct *bsec;
u32 newsid;
@@ -1621,10 +1621,10 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
}
AVC_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.mnt = bprm->file->f_vfsmnt;
- ad.u.fs.dentry = bprm->file->f_dentry;
+ ad.u.fs.mnt = bprm->file->f_path.mnt;
+ ad.u.fs.dentry = bprm->file->f_path.dentry;
- if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
+ if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
newsid = tsec->sid;
if (tsec->sid == newsid) {
@@ -1695,9 +1695,10 @@ static inline void flush_unauthorized_files(struct files_struct * files)
struct tty_struct *tty;
struct fdtable *fdt;
long j = -1;
+ int drop_tty = 0;
mutex_lock(&tty_mutex);
- tty = current->signal->tty;
+ tty = get_current_tty();
if (tty) {
file_list_lock();
file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);
@@ -1707,15 +1708,17 @@ static inline void flush_unauthorized_files(struct files_struct * files)
than using file_has_perm, as this particular open
file may belong to another process and we are only
interested in the inode-based check here. */
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
if (inode_has_perm(current, inode,
FILE__READ | FILE__WRITE, NULL)) {
- /* Reset controlling tty. */
- current->signal->tty = NULL;
- current->signal->tty_old_pgrp = 0;
+ drop_tty = 1;
}
}
file_list_unlock();
+
+ /* Reset controlling tty. */
+ if (drop_tty)
+ proc_set_tty(current, NULL);
}
mutex_unlock(&tty_mutex);
@@ -1731,7 +1734,7 @@ static inline void flush_unauthorized_files(struct files_struct * files)
j++;
i = j * __NFDBITS;
fdt = files_fdtable(files);
- if (i >= fdt->max_fds || i >= fdt->max_fdset)
+ if (i >= fdt->max_fds)
break;
set = fdt->open_fds->fds_bits[j];
if (!set)
@@ -2417,7 +2420,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
static int selinux_file_permission(struct file *file, int mask)
{
int rc;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
if (!mask) {
/* No permission to check. Existence test. */
@@ -2594,7 +2597,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
switch (cmd) {
case F_SETFL:
- if (!file->f_dentry || !file->f_dentry->d_inode) {
+ if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
err = -EINVAL;
break;
}
@@ -2620,7 +2623,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
case F_SETLK64:
case F_SETLKW64:
#endif
- if (!file->f_dentry || !file->f_dentry->d_inode) {
+ if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
err = -EINVAL;
break;
}
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index 161eb571c82..31929e39f5c 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -37,6 +37,11 @@ int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,
int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
struct avc_audit_data *ad, u8 proto);
int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);
+
+static inline void selinux_xfrm_notify_policyload(void)
+{
+ atomic_inc(&flow_cache_genid);
+}
#else
static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
struct avc_audit_data *ad)
@@ -55,6 +60,10 @@ static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int
*sid = SECSID_NULL;
return 0;
}
+
+static inline void selinux_xfrm_notify_policyload(void)
+{
+}
#endif
static inline void selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index cd244419c98..c8bf6e172f6 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -448,7 +448,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
{
- ino_t ino = file->f_dentry->d_inode->i_ino;
+ ino_t ino = file->f_path.dentry->d_inode->i_ino;
char *data;
ssize_t rv;
@@ -805,7 +805,7 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
goto out;
}
- inode = filep->f_dentry->d_inode;
+ inode = filep->f_path.dentry->d_inode;
cur_enforcing = security_get_bool_value(inode->i_ino - BOOL_INO_OFFSET);
if (cur_enforcing < 0) {
ret = cur_enforcing;
@@ -864,7 +864,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
if (new_value)
new_value = 1;
- inode = filep->f_dentry->d_inode;
+ inode = filep->f_path.dentry->d_inode;
bool_pending_values[inode->i_ino - BOOL_INO_OFFSET] = new_value;
length = count;
@@ -965,7 +965,7 @@ static void sel_remove_bools(struct dentry *de)
file_list_lock();
list_for_each(p, &sb->s_files) {
struct file * filp = list_entry(p, struct file, f_u.fu_list);
- struct dentry * dentry = filp->f_dentry;
+ struct dentry * dentry = filp->f_path.dentry;
if (dentry->d_parent != de) {
continue;
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
index 0562bacb7b9..2eee0dab524 100644
--- a/security/selinux/ss/context.h
+++ b/security/selinux/ss/context.h
@@ -55,6 +55,29 @@ out:
return rc;
}
+/*
+ * Sets both levels in the MLS range of 'dst' to the low level of 'src'.
+ */
+static inline int mls_context_cpy_low(struct context *dst, struct context *src)
+{
+ int rc;
+
+ if (!selinux_mls_enabled)
+ return 0;
+
+ dst->range.level[0].sens = src->range.level[0].sens;
+ rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
+ if (rc)
+ goto out;
+
+ dst->range.level[1].sens = src->range.level[0].sens;
+ rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[0].cat);
+ if (rc)
+ ebitmap_destroy(&dst->range.level[0].cat);
+out:
+ return rc;
+}
+
static inline int mls_context_cmp(struct context *c1, struct context *c2)
{
if (!selinux_mls_enabled)
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index b4f682dc13f..4a8bab2f3c7 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -270,7 +270,7 @@ int mls_context_to_sid(char oldc,
if (!defcon)
goto out;
- rc = mls_copy_context(context, defcon);
+ rc = mls_context_cpy(context, defcon);
goto out;
}
@@ -401,26 +401,6 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
}
/*
- * Copies the effective MLS range from `src' into `dst'.
- */
-static inline int mls_scopy_context(struct context *dst,
- struct context *src)
-{
- int l, rc = 0;
-
- /* Copy the MLS range from the source context */
- for (l = 0; l < 2; l++) {
- dst->range.level[l].sens = src->range.level[0].sens;
- rc = ebitmap_cpy(&dst->range.level[l].cat,
- &src->range.level[0].cat);
- if (rc)
- break;
- }
-
- return rc;
-}
-
-/*
* Copies the MLS range `range' into `context'.
*/
static inline int mls_range_set(struct context *context,
@@ -552,19 +532,19 @@ int mls_compute_sid(struct context *scontext,
case AVTAB_CHANGE:
if (tclass == SECCLASS_PROCESS)
/* Use the process MLS attributes. */
- return mls_copy_context(newcontext, scontext);
+ return mls_context_cpy(newcontext, scontext);
else
/* Use the process effective MLS attributes. */
- return mls_scopy_context(newcontext, scontext);
+ return mls_context_cpy_low(newcontext, scontext);
case AVTAB_MEMBER:
/* Only polyinstantiate the MLS attributes if
the type is being polyinstantiated */
if (newcontext->type != tcontext->type) {
/* Use the process effective MLS attributes. */
- return mls_scopy_context(newcontext, scontext);
+ return mls_context_cpy_low(newcontext, scontext);
} else {
/* Use the related object MLS attributes. */
- return mls_copy_context(newcontext, tcontext);
+ return mls_context_cpy(newcontext, tcontext);
}
default:
return -EINVAL;
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 661d6fc7696..096d1b4ef7f 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -24,26 +24,6 @@
#include "context.h"
#include "policydb.h"
-/*
- * Copies the MLS range from `src' into `dst'.
- */
-static inline int mls_copy_context(struct context *dst,
- struct context *src)
-{
- int l, rc = 0;
-
- /* Copy the MLS range from the source context */
- for (l = 0; l < 2; l++) {
- dst->range.level[l].sens = src->range.level[l].sens;
- rc = ebitmap_cpy(&dst->range.level[l].cat,
- &src->range.level[l].cat);
- if (rc)
- break;
- }
-
- return rc;
-}
-
int mls_compute_context_len(struct context *context);
void mls_sid_to_context(struct context *context, char **scontext);
int mls_context_isvalid(struct policydb *p, struct context *c);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index bdb7070dd3d..ca9154dc5d8 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1299,6 +1299,7 @@ int security_load_policy(void *data, size_t len)
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
selinux_netlbl_cache_invalidate();
+ selinux_xfrm_notify_policyload();
return 0;
}
@@ -1354,6 +1355,7 @@ int security_load_policy(void *data, size_t len)
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
selinux_netlbl_cache_invalidate();
+ selinux_xfrm_notify_policyload();
return 0;
@@ -1853,6 +1855,7 @@ out:
if (!rc) {
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
+ selinux_xfrm_notify_policyload();
}
return rc;
}
@@ -1916,11 +1919,10 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
newcon.user = context1->user;
newcon.role = context1->role;
newcon.type = context1->type;
- rc = mls_copy_context(&newcon, context2);
+ rc = mls_context_cpy(&newcon, context2);
if (rc)
goto out_unlock;
-
/* Check the validity of the new context. */
if (!policydb_context_isvalid(&policydb, &newcon)) {
rc = convert_context_handle_invalid_context(&newcon);
@@ -2492,9 +2494,9 @@ static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
rc = netlbl_socket_setattr(sock, &secattr);
if (rc == 0) {
- spin_lock(&sksec->nlbl_lock);
+ spin_lock_bh(&sksec->nlbl_lock);
sksec->nlbl_state = NLBL_LABELED;
- spin_unlock(&sksec->nlbl_lock);
+ spin_unlock_bh(&sksec->nlbl_lock);
}
netlbl_socket_setsid_return:
@@ -2660,9 +2662,11 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
rcu_read_unlock();
return 0;
}
- lock_sock(sock->sk);
+ local_bh_disable();
+ bh_lock_sock_nested(sock->sk);
rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
- release_sock(sock->sk);
+ bh_unlock_sock(sock->sk);
+ local_bh_enable();
rcu_read_unlock();
return rc;
diff --git a/sound/Kconfig b/sound/Kconfig
index 95949b6806a..97532bbc2cc 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -76,6 +76,8 @@ source "sound/sparc/Kconfig"
source "sound/parisc/Kconfig"
+source "sound/soc/Kconfig"
+
endmenu
menu "Open Sound System"
@@ -93,4 +95,12 @@ endmenu
endif
+config AC97_BUS
+ tristate
+ help
+ This is used to avoid config and link hard dependencies between the
+ sound subsystem and other function drivers completely unrelated to
+ sound although they're sharing the AC97 bus. Concerned drivers
+ should "select" this.
+
endmenu
diff --git a/sound/Makefile b/sound/Makefile
index 5f6bef57e82..b7c7fb7c24c 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -5,9 +5,12 @@ 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/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
obj-$(CONFIG_SND_AOA) += aoa/
+# This one must be compilable even if sound is configured out
+obj-$(CONFIG_AC97_BUS) += ac97_bus.o
+
ifeq ($(CONFIG_SND),y)
obj-y += last.o
endif
diff --git a/sound/pci/ac97/ac97_bus.c b/sound/ac97_bus.c
index 66de2c2f155..7fa37e15f19 100644
--- a/sound/pci/ac97/ac97_bus.c
+++ b/sound/ac97_bus.c
@@ -26,6 +26,7 @@ static int ac97_bus_match(struct device *dev, struct device_driver *drv)
return 1;
}
+#ifdef CONFIG_PM
static int ac97_bus_suspend(struct device *dev, pm_message_t state)
{
int ret = 0;
@@ -45,12 +46,15 @@ static int ac97_bus_resume(struct device *dev)
return ret;
}
+#endif /* CONFIG_PM */
struct bus_type ac97_bus_type = {
.name = "ac97",
.match = ac97_bus_match,
+#ifdef CONFIG_PM
.suspend = ac97_bus_suspend,
.resume = ac97_bus_resume,
+#endif /* CONFIG_PM */
};
static int __init ac97_bus_init(void)
diff --git a/sound/aoa/aoa.h b/sound/aoa/aoa.h
index 378ef1e9879..541b908f3cd 100644
--- a/sound/aoa/aoa.h
+++ b/sound/aoa/aoa.h
@@ -99,7 +99,7 @@ struct aoa_fabric {
* that are not assigned yet are passed to the fabric
* again for reconsideration. */
extern int
-aoa_fabric_register(struct aoa_fabric *fabric);
+aoa_fabric_register(struct aoa_fabric *fabric, struct device *dev);
/* it is vital to call this when the fabric exits!
* When calling, the remove_codec will be called
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c
index 0b7650788f1..b00fc4842c9 100644
--- a/sound/aoa/codecs/snd-aoa-codec-onyx.c
+++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c
@@ -825,7 +825,16 @@ static int onyx_resume(struct codec_info_item *cii)
int err = -ENXIO;
mutex_lock(&onyx->mutex);
- /* take codec out of suspend */
+
+ /* reset codec */
+ onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+ msleep(1);
+ onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1);
+ msleep(1);
+ onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+ msleep(1);
+
+ /* take codec out of suspend (if it still is after reset) */
if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
goto out_unlock;
onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.h b/sound/aoa/codecs/snd-aoa-codec-onyx.h
index aeedda77369..ffd20254ff7 100644
--- a/sound/aoa/codecs/snd-aoa-codec-onyx.h
+++ b/sound/aoa/codecs/snd-aoa-codec-onyx.h
@@ -9,7 +9,6 @@
#define __SND_AOA_CODEC_ONYX_H
#include <stddef.h>
#include <linux/i2c.h>
-#include <linux/i2c-dev.h>
#include <asm/pmac_low_i2c.h>
#include <asm/prom.h>
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c
index 9de8485ba3f..2cd81fa07ce 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas.c
+++ b/sound/aoa/codecs/snd-aoa-codec-tas.c
@@ -61,7 +61,6 @@
*/
#include <stddef.h>
#include <linux/i2c.h>
-#include <linux/i2c-dev.h>
#include <asm/pmac_low_i2c.h>
#include <asm/prom.h>
#include <linux/delay.h>
diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/snd-aoa-alsa.c
index b42fdea77ed..17fe689ed28 100644
--- a/sound/aoa/core/snd-aoa-alsa.c
+++ b/sound/aoa/core/snd-aoa-alsa.c
@@ -14,7 +14,7 @@ MODULE_PARM_DESC(index, "index for AOA sound card.");
static struct aoa_card *aoa_card;
-int aoa_alsa_init(char *name, struct module *mod)
+int aoa_alsa_init(char *name, struct module *mod, struct device *dev)
{
struct snd_card *alsa_card;
int err;
@@ -28,6 +28,7 @@ int aoa_alsa_init(char *name, struct module *mod)
return -ENOMEM;
aoa_card = alsa_card->private_data;
aoa_card->alsa_card = alsa_card;
+ alsa_card->dev = dev;
strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver));
strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname));
strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname));
@@ -59,7 +60,7 @@ void aoa_alsa_cleanup(void)
}
int aoa_snd_device_new(snd_device_type_t type,
- void * device_data, struct snd_device_ops * ops)
+ void * device_data, struct snd_device_ops * ops)
{
struct snd_card *card = aoa_get_card();
int err;
diff --git a/sound/aoa/core/snd-aoa-alsa.h b/sound/aoa/core/snd-aoa-alsa.h
index 660d2f1793b..9669e4489ca 100644
--- a/sound/aoa/core/snd-aoa-alsa.h
+++ b/sound/aoa/core/snd-aoa-alsa.h
@@ -10,7 +10,7 @@
#define __SND_AOA_ALSA_H
#include "../aoa.h"
-extern int aoa_alsa_init(char *name, struct module *mod);
+extern int aoa_alsa_init(char *name, struct module *mod, struct device *dev);
extern void aoa_alsa_cleanup(void);
#endif /* __SND_AOA_ALSA_H */
diff --git a/sound/aoa/core/snd-aoa-core.c b/sound/aoa/core/snd-aoa-core.c
index ecd2d8263f2..19fdae40068 100644
--- a/sound/aoa/core/snd-aoa-core.c
+++ b/sound/aoa/core/snd-aoa-core.c
@@ -82,7 +82,7 @@ void aoa_codec_unregister(struct aoa_codec *codec)
}
EXPORT_SYMBOL_GPL(aoa_codec_unregister);
-int aoa_fabric_register(struct aoa_fabric *new_fabric)
+int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev)
{
struct aoa_codec *c;
int err;
@@ -98,7 +98,7 @@ int aoa_fabric_register(struct aoa_fabric *new_fabric)
if (!new_fabric)
return -EINVAL;
- err = aoa_alsa_init(new_fabric->name, new_fabric->owner);
+ err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev);
if (err)
return err;
diff --git a/sound/aoa/fabrics/Kconfig b/sound/aoa/fabrics/Kconfig
index c3bc7705c86..50d7021ff67 100644
--- a/sound/aoa/fabrics/Kconfig
+++ b/sound/aoa/fabrics/Kconfig
@@ -1,6 +1,6 @@
config SND_AOA_FABRIC_LAYOUT
tristate "layout-id fabric"
- depends SND_AOA
+ depends on SND_AOA
select SND_AOA_SOUNDBUS
select SND_AOA_SOUNDBUS_I2S
---help---
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
index 172eb95476c..1b94ba6dd27 100644
--- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c
+++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
@@ -1014,7 +1014,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
ldev->gpio.methods->init(&ldev->gpio);
- err = aoa_fabric_register(&layout_fabric);
+ err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev);
if (err && err != -EALREADY) {
printk(KERN_INFO "snd-aoa-fabric-layout: can't use,"
" another fabric is active!\n");
@@ -1034,9 +1034,9 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
list_del(&ldev->list);
layouts_list_items--;
outnodev:
- if (sound) of_node_put(sound);
+ of_node_put(sound);
layout_device = NULL;
- if (ldev) kfree(ldev);
+ kfree(ldev);
return -ENODEV;
}
@@ -1077,8 +1077,6 @@ static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t sta
{
struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
- printk("aoa_fabric_layout_suspend()\n");
-
if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
ldev->gpio.methods->all_amps_off(&ldev->gpio);
@@ -1089,8 +1087,6 @@ static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
{
struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
- printk("aoa_fabric_layout_resume()\n");
-
if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
ldev->gpio.methods->all_amps_restore(&ldev->gpio);
@@ -1107,6 +1103,9 @@ static struct soundbus_driver aoa_soundbus_driver = {
.suspend = aoa_fabric_layout_suspend,
.resume = aoa_fabric_layout_resume,
#endif
+ .driver = {
+ .owner = THIS_MODULE,
+ }
};
static int __init aoa_fabric_layout_init(void)
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
index e593a1333fe..e36f6aa448d 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
@@ -41,8 +41,8 @@ static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev,
struct dbdma_command_mem *r,
int numcmds)
{
- /* one more for rounding */
- r->size = (numcmds+1) * sizeof(struct dbdma_cmd);
+ /* one more for rounding, one for branch back, one for stop command */
+ r->size = (numcmds + 3) * sizeof(struct dbdma_cmd);
/* We use the PCI APIs for now until the generic one gets fixed
* enough or until we get some macio-specific versions
*/
@@ -377,11 +377,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
if (i2sdev->sound.pcm) {
/* Suspend PCM streams */
snd_pcm_suspend_all(i2sdev->sound.pcm);
- /* Probably useless as we handle
- * power transitions ourselves */
- snd_power_change_state(i2sdev->sound.pcm->card,
- SNDRV_CTL_POWER_D3hot);
}
+
/* Notify codecs */
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
err = 0;
@@ -390,7 +387,11 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
if (err)
ret = err;
}
+
+ /* wait until streams are stopped */
+ i2sbus_wait_for_stop_both(i2sdev);
}
+
return ret;
}
@@ -402,6 +403,9 @@ static int i2sbus_resume(struct macio_dev* dev)
int err, ret = 0;
list_for_each_entry(i2sdev, &control->list, item) {
+ /* reset i2s bus format etc. */
+ i2sbus_pcm_prepare_both(i2sdev);
+
/* Notify codecs so they can re-initialize */
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
err = 0;
@@ -410,12 +414,6 @@ static int i2sbus_resume(struct macio_dev* dev)
if (err)
ret = err;
}
- /* Notify Alsa */
- if (i2sdev->sound.pcm) {
- /* Same comment as above, probably useless */
- snd_power_change_state(i2sdev->sound.pcm->card,
- SNDRV_CTL_POWER_D0);
- }
}
return ret;
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
index 5eff30b1020..c6b42f9bdbc 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
@@ -125,7 +125,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
}
/* bus dependent stuff */
hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME;
+ SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_JOINT_DUPLEX;
CHECK_RATE(5512);
CHECK_RATE(8000);
@@ -245,18 +246,78 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
return err;
}
+static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev,
+ struct pcm_info *pi)
+{
+ unsigned long flags;
+ struct completion done;
+ long timeout;
+
+ spin_lock_irqsave(&i2sdev->low_lock, flags);
+ if (pi->dbdma_ring.stopping) {
+ init_completion(&done);
+ pi->stop_completion = &done;
+ spin_unlock_irqrestore(&i2sdev->low_lock, flags);
+ timeout = wait_for_completion_timeout(&done, HZ);
+ spin_lock_irqsave(&i2sdev->low_lock, flags);
+ pi->stop_completion = NULL;
+ if (timeout == 0) {
+ /* timeout expired, stop dbdma forcefully */
+ printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n");
+ /* make sure RUN, PAUSE and S0 bits are cleared */
+ out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
+ pi->dbdma_ring.stopping = 0;
+ timeout = 10;
+ while (in_le32(&pi->dbdma->status) & ACTIVE) {
+ if (--timeout <= 0)
+ break;
+ udelay(1);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&i2sdev->low_lock, flags);
+}
+
+#ifdef CONFIG_PM
+void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
+{
+ struct pcm_info *pi;
+
+ get_pcm_info(i2sdev, 0, &pi, NULL);
+ i2sbus_wait_for_stop(i2sdev, pi);
+ get_pcm_info(i2sdev, 1, &pi, NULL);
+ i2sbus_wait_for_stop(i2sdev, pi);
+}
+#endif
+
static int i2sbus_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
}
-static int i2sbus_hw_free(struct snd_pcm_substream *substream)
+static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
{
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+ struct pcm_info *pi;
+
+ get_pcm_info(i2sdev, in, &pi, NULL);
+ if (pi->dbdma_ring.stopping)
+ i2sbus_wait_for_stop(i2sdev, pi);
snd_pcm_lib_free_pages(substream);
return 0;
}
+static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
+{
+ return i2sbus_hw_free(substream, 0);
+}
+
+static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
+{
+ return i2sbus_hw_free(substream, 1);
+}
+
static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
{
/* whee. Hard work now. The user has selected a bitrate
@@ -264,7 +325,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
* I2S controller appropriately. */
struct snd_pcm_runtime *runtime;
struct dbdma_cmd *command;
- int i, periodsize;
+ int i, periodsize, nperiods;
dma_addr_t offset;
struct bus_info bi;
struct codec_info_item *cii;
@@ -274,6 +335,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
struct pcm_info *pi, *other;
int cnt;
int result = 0;
+ unsigned int cmd, stopaddr;
mutex_lock(&i2sdev->lock);
@@ -283,6 +345,13 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
result = -EBUSY;
goto out_unlock;
}
+ if (pi->dbdma_ring.stopping)
+ i2sbus_wait_for_stop(i2sdev, pi);
+
+ if (!pi->substream || !pi->substream->runtime) {
+ result = -EINVAL;
+ goto out_unlock;
+ }
runtime = pi->substream->runtime;
pi->active = 1;
@@ -297,24 +366,43 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
i2sdev->rate = runtime->rate;
periodsize = snd_pcm_lib_period_bytes(pi->substream);
+ nperiods = pi->substream->runtime->periods;
pi->current_period = 0;
/* generate dbdma command ring first */
command = pi->dbdma_ring.cmds;
+ memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd));
+
+ /* commands to DMA to/from the ring */
+ /*
+ * For input, we need to do a graceful stop; if we abort
+ * the DMA, we end up with leftover bytes that corrupt
+ * the next recording. To do this we set the S0 status
+ * bit and wait for the DMA controller to stop. Each
+ * command has a branch condition to
+ * make it branch to a stop command if S0 is set.
+ * On input we also need to wait for the S7 bit to be
+ * set before turning off the DMA controller.
+ * In fact we do the graceful stop for output as well.
+ */
offset = runtime->dma_addr;
- for (i = 0; i < pi->substream->runtime->periods;
- i++, command++, offset += periodsize) {
- memset(command, 0, sizeof(struct dbdma_cmd));
- command->command =
- cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS);
+ cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS;
+ stopaddr = pi->dbdma_ring.bus_cmd_start +
+ (nperiods + 1) * sizeof(struct dbdma_cmd);
+ for (i = 0; i < nperiods; i++, command++, offset += periodsize) {
+ command->command = cpu_to_le16(cmd);
+ command->cmd_dep = cpu_to_le32(stopaddr);
command->phy_addr = cpu_to_le32(offset);
command->req_count = cpu_to_le16(periodsize);
- command->xfer_status = cpu_to_le16(0);
}
- /* last one branches back to first */
- command--;
- command->command |= cpu_to_le16(BR_ALWAYS);
+
+ /* branch back to beginning of ring */
+ command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS);
command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start);
+ command++;
+
+ /* set stop command */
+ command->command = cpu_to_le16(DBDMA_STOP);
/* ok, let's set the serial format and stuff */
switch (runtime->format) {
@@ -435,16 +523,18 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
return result;
}
-static struct dbdma_cmd STOP_CMD = {
- .command = __constant_cpu_to_le16(DBDMA_STOP),
-};
+#ifdef CONFIG_PM
+void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev)
+{
+ i2sbus_pcm_prepare(i2sdev, 0);
+ i2sbus_pcm_prepare(i2sdev, 1);
+}
+#endif
static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
{
struct codec_info_item *cii;
struct pcm_info *pi;
- int timeout;
- struct dbdma_cmd tmp;
int result = 0;
unsigned long flags;
@@ -464,92 +554,50 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
cii->codec->start(cii, pi->substream);
pi->dbdma_ring.running = 1;
- /* reset dma engine */
- out_le32(&pi->dbdma->control,
- 0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
- timeout = 100;
- while (in_le32(&pi->dbdma->status) & RUN && timeout--)
- udelay(1);
- if (timeout <= 0) {
- printk(KERN_ERR
- "i2sbus: error waiting for dma reset\n");
- result = -ENXIO;
- goto out_unlock;
+ if (pi->dbdma_ring.stopping) {
+ /* Clear the S0 bit, then see if we stopped yet */
+ out_le32(&pi->dbdma->control, 1 << 16);
+ if (in_le32(&pi->dbdma->status) & ACTIVE) {
+ /* possible race here? */
+ udelay(10);
+ if (in_le32(&pi->dbdma->status) & ACTIVE) {
+ pi->dbdma_ring.stopping = 0;
+ goto out_unlock; /* keep running */
+ }
+ }
}
+ /* make sure RUN, PAUSE and S0 bits are cleared */
+ out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
+
+ /* set branch condition select register */
+ out_le32(&pi->dbdma->br_sel, (1 << 16) | 1);
+
/* write dma command buffer address to the dbdma chip */
out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
- /* post PCI write */
- mb();
- (void)in_le32(&pi->dbdma->status);
-
- /* change first command to STOP */
- tmp = *pi->dbdma_ring.cmds;
- *pi->dbdma_ring.cmds = STOP_CMD;
-
- /* set running state, remember that the first command is STOP */
- out_le32(&pi->dbdma->control, RUN | (RUN << 16));
- timeout = 100;
- /* wait for STOP to be executed */
- while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--)
- udelay(1);
- if (timeout <= 0) {
- printk(KERN_ERR "i2sbus: error waiting for dma stop\n");
- result = -ENXIO;
- goto out_unlock;
- }
- /* again, write dma command buffer address to the dbdma chip,
- * this time of the first real command */
- *pi->dbdma_ring.cmds = tmp;
- out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
- /* post write */
- mb();
- (void)in_le32(&pi->dbdma->status);
-
- /* reset dma engine again */
- out_le32(&pi->dbdma->control,
- 0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
- timeout = 100;
- while (in_le32(&pi->dbdma->status) & RUN && timeout--)
- udelay(1);
- if (timeout <= 0) {
- printk(KERN_ERR
- "i2sbus: error waiting for dma reset\n");
- result = -ENXIO;
- goto out_unlock;
- }
- /* wake up the chip with the next descriptor */
- out_le32(&pi->dbdma->control,
- (RUN | WAKE) | ((RUN | WAKE) << 16));
- /* get the frame count */
+ /* initialize the frame count and current period */
+ pi->current_period = 0;
pi->frame_count = in_le32(&i2sdev->intfregs->frame_count);
+ /* set the DMA controller running */
+ out_le32(&pi->dbdma->control, (RUN << 16) | RUN);
+
/* off you go! */
break;
+
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
if (!pi->dbdma_ring.running) {
result = -EALREADY;
goto out_unlock;
}
+ pi->dbdma_ring.running = 0;
- /* turn off all relevant bits */
- out_le32(&pi->dbdma->control,
- (RUN | WAKE | FLUSH | PAUSE) << 16);
- {
- /* FIXME: move to own function */
- int timeout = 5000;
- while ((in_le32(&pi->dbdma->status) & RUN)
- && --timeout > 0)
- udelay(1);
- if (!timeout)
- printk(KERN_ERR
- "i2sbus: timed out turning "
- "off dbdma engine!\n");
- }
+ /* Set the S0 bit to make the DMA branch to the stop cmd */
+ out_le32(&pi->dbdma->control, (1 << 16) | 1);
+ pi->dbdma_ring.stopping = 1;
- pi->dbdma_ring.running = 0;
list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
if (cii->codec->stop)
cii->codec->stop(cii, pi->substream);
@@ -574,70 +622,82 @@ static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in)
fc = in_le32(&i2sdev->intfregs->frame_count);
fc = fc - pi->frame_count;
- return (bytes_to_frames(pi->substream->runtime,
- pi->current_period *
- snd_pcm_lib_period_bytes(pi->substream))
- + fc) % pi->substream->runtime->buffer_size;
+ if (fc >= pi->substream->runtime->buffer_size)
+ fc %= pi->substream->runtime->buffer_size;
+ return fc;
}
static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
{
struct pcm_info *pi;
- u32 fc;
- u32 delta;
+ u32 fc, nframes;
+ u32 status;
+ int timeout, i;
+ int dma_stopped = 0;
+ struct snd_pcm_runtime *runtime;
spin_lock(&i2sdev->low_lock);
get_pcm_info(i2sdev, in, &pi, NULL);
-
- if (!pi->dbdma_ring.running) {
- /* there was still an interrupt pending
- * while we stopped. or maybe another
- * processor (not the one that was stopping
- * the DMA engine) was spinning above
- * waiting for the lock. */
+ if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping)
goto out_unlock;
- }
- fc = in_le32(&i2sdev->intfregs->frame_count);
- /* a counter overflow does not change the calculation. */
- delta = fc - pi->frame_count;
-
- /* update current_period */
- while (delta >= pi->substream->runtime->period_size) {
- pi->current_period++;
- delta = delta - pi->substream->runtime->period_size;
- }
-
- if (unlikely(delta)) {
- /* Some interrupt came late, so check the dbdma.
- * This special case exists to syncronize the frame_count with
- * the dbdma transfer, but is hit every once in a while. */
- int period;
-
- period = (in_le32(&pi->dbdma->cmdptr)
- - pi->dbdma_ring.bus_cmd_start)
- / sizeof(struct dbdma_cmd);
- pi->current_period = pi->current_period
- % pi->substream->runtime->periods;
-
- while (pi->current_period != period) {
- pi->current_period++;
- pi->current_period %= pi->substream->runtime->periods;
- /* Set delta to zero, as the frame_count value is too
- * high (otherwise the code path will not be executed).
- * This corrects the fact that the frame_count is too
- * low at the beginning due to buffering. */
- delta = 0;
+ i = pi->current_period;
+ runtime = pi->substream->runtime;
+ while (pi->dbdma_ring.cmds[i].xfer_status) {
+ if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT)
+ /*
+ * BT is the branch taken bit. If it took a branch
+ * it is because we set the S0 bit to make it
+ * branch to the stop command.
+ */
+ dma_stopped = 1;
+ pi->dbdma_ring.cmds[i].xfer_status = 0;
+
+ if (++i >= runtime->periods) {
+ i = 0;
+ pi->frame_count += runtime->buffer_size;
}
+ pi->current_period = i;
+
+ /*
+ * Check the frame count. The DMA tends to get a bit
+ * ahead of the frame counter, which confuses the core.
+ */
+ fc = in_le32(&i2sdev->intfregs->frame_count);
+ nframes = i * runtime->period_size;
+ if (fc < pi->frame_count + nframes)
+ pi->frame_count = fc - nframes;
}
- pi->frame_count = fc - delta;
- pi->current_period %= pi->substream->runtime->periods;
+ if (dma_stopped) {
+ timeout = 1000;
+ for (;;) {
+ status = in_le32(&pi->dbdma->status);
+ if (!(status & ACTIVE) && (!in || (status & 0x80)))
+ break;
+ if (--timeout <= 0) {
+ printk(KERN_ERR "i2sbus: timed out "
+ "waiting for DMA to stop!\n");
+ break;
+ }
+ udelay(1);
+ }
+
+ /* Turn off DMA controller, clear S0 bit */
+ out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
+
+ pi->dbdma_ring.stopping = 0;
+ if (pi->stop_completion)
+ complete(pi->stop_completion);
+ }
+ if (!pi->dbdma_ring.running)
+ goto out_unlock;
spin_unlock(&i2sdev->low_lock);
/* may call _trigger again, hence needs to be unlocked */
snd_pcm_period_elapsed(pi->substream);
return;
+
out_unlock:
spin_unlock(&i2sdev->low_lock);
}
@@ -718,7 +778,7 @@ static struct snd_pcm_ops i2sbus_playback_ops = {
.close = i2sbus_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = i2sbus_hw_params,
- .hw_free = i2sbus_hw_free,
+ .hw_free = i2sbus_playback_hw_free,
.prepare = i2sbus_playback_prepare,
.trigger = i2sbus_playback_trigger,
.pointer = i2sbus_playback_pointer,
@@ -788,7 +848,7 @@ static struct snd_pcm_ops i2sbus_record_ops = {
.close = i2sbus_record_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = i2sbus_hw_params,
- .hw_free = i2sbus_hw_free,
+ .hw_free = i2sbus_record_hw_free,
.prepare = i2sbus_record_prepare,
.trigger = i2sbus_record_trigger,
.pointer = i2sbus_record_pointer,
@@ -812,7 +872,6 @@ static void i2sbus_private_free(struct snd_pcm *pcm)
module_put(THIS_MODULE);
}
-/* FIXME: this function needs an error handling strategy with labels */
int
i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
struct codec_info *ci, void *data)
@@ -880,41 +939,31 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
if (!cii->sdev) {
printk(KERN_DEBUG
"i2sbus: failed to get soundbus dev reference\n");
- kfree(cii);
- return -ENODEV;
+ err = -ENODEV;
+ goto out_free_cii;
}
if (!try_module_get(THIS_MODULE)) {
printk(KERN_DEBUG "i2sbus: failed to get module reference!\n");
- soundbus_dev_put(dev);
- kfree(cii);
- return -EBUSY;
+ err = -EBUSY;
+ goto out_put_sdev;
}
if (!try_module_get(ci->owner)) {
printk(KERN_DEBUG
"i2sbus: failed to get module reference to codec owner!\n");
- module_put(THIS_MODULE);
- soundbus_dev_put(dev);
- kfree(cii);
- return -EBUSY;
+ err = -EBUSY;
+ goto out_put_this_module;
}
if (!dev->pcm) {
- err = snd_pcm_new(card,
- dev->pcmname,
- dev->pcmid,
- 0,
- 0,
+ err = snd_pcm_new(card, dev->pcmname, dev->pcmid, 0, 0,
&dev->pcm);
if (err) {
printk(KERN_DEBUG "i2sbus: failed to create pcm\n");
- kfree(cii);
- module_put(ci->owner);
- soundbus_dev_put(dev);
- module_put(THIS_MODULE);
- return err;
+ goto out_put_ci_module;
}
+ dev->pcm->dev = &dev->ofdev.dev;
}
/* ALSA yet again sucks.
@@ -926,20 +975,12 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
/* eh? */
printk(KERN_ERR
"Can't attach same bus to different cards!\n");
- module_put(ci->owner);
- kfree(cii);
- soundbus_dev_put(dev);
- module_put(THIS_MODULE);
- return -EINVAL;
- }
- if ((err =
- snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) {
- module_put(ci->owner);
- kfree(cii);
- soundbus_dev_put(dev);
- module_put(THIS_MODULE);
- return err;
+ err = -EINVAL;
+ goto out_put_ci_module;
}
+ err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
+ if (err)
+ goto out_put_ci_module;
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
&i2sbus_playback_ops);
i2sdev->out.created = 1;
@@ -949,20 +990,11 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
if (dev->pcm->card != card) {
printk(KERN_ERR
"Can't attach same bus to different cards!\n");
- module_put(ci->owner);
- kfree(cii);
- soundbus_dev_put(dev);
- module_put(THIS_MODULE);
- return -EINVAL;
- }
- if ((err =
- snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) {
- module_put(ci->owner);
- kfree(cii);
- soundbus_dev_put(dev);
- module_put(THIS_MODULE);
- return err;
+ goto out_put_ci_module;
}
+ err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
+ if (err)
+ goto out_put_ci_module;
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
&i2sbus_record_ops);
i2sdev->in.created = 1;
@@ -977,11 +1009,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
err = snd_device_register(card, dev->pcm);
if (err) {
printk(KERN_ERR "i2sbus: error registering new pcm\n");
- module_put(ci->owner);
- kfree(cii);
- soundbus_dev_put(dev);
- module_put(THIS_MODULE);
- return err;
+ goto out_put_ci_module;
}
/* no errors any more, so let's add this to our list */
list_add(&cii->list, &dev->codec_list);
@@ -996,6 +1024,15 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
64 * 1024, 64 * 1024);
return 0;
+ out_put_ci_module:
+ module_put(ci->owner);
+ out_put_this_module:
+ module_put(THIS_MODULE);
+ out_put_sdev:
+ soundbus_dev_put(dev);
+ out_free_cii:
+ kfree(cii);
+ return err;
}
void i2sbus_detach_codec(struct soundbus_dev *dev, void *data)
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h
index ec20ee615d7..ff29654782c 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus.h
+++ b/sound/aoa/soundbus/i2sbus/i2sbus.h
@@ -10,6 +10,7 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
+#include <linux/completion.h>
#include <sound/pcm.h>
@@ -34,6 +35,7 @@ struct dbdma_command_mem {
void *space;
int size;
u32 running:1;
+ u32 stopping:1;
};
struct pcm_info {
@@ -45,6 +47,7 @@ struct pcm_info {
u32 frame_count;
struct dbdma_command_mem dbdma_ring;
volatile struct dbdma_regs __iomem *dbdma;
+ struct completion *stop_completion;
};
enum {
@@ -101,6 +104,9 @@ i2sbus_tx_intr(int irq, void *devid);
extern irqreturn_t
i2sbus_rx_intr(int irq, void *devid);
+extern void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev);
+extern void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev);
+
/* control specific functions */
extern int i2sbus_control_init(struct macio_dev* dev,
struct i2sbus_control **c);
diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h
index 06295190606..9175ff9ded0 100644
--- a/sound/arm/aaci.h
+++ b/sound/arm/aaci.h
@@ -228,7 +228,7 @@ struct aaci {
/* AC'97 */
struct mutex ac97_sem;
- ac97_bus_t *ac97_bus;
+ struct snd_ac97_bus *ac97_bus;
u32 maincr;
spinlock_t lock;
diff --git a/sound/core/control.c b/sound/core/control.c
index 48ef0a09a7a..42bcf2794b2 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -108,7 +108,6 @@ static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
static int snd_ctl_release(struct inode *inode, struct file *file)
{
unsigned long flags;
- struct list_head *list;
struct snd_card *card;
struct snd_ctl_file *ctl;
struct snd_kcontrol *control;
@@ -122,12 +121,10 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
list_del(&ctl->list);
write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
down_write(&card->controls_rwsem);
- list_for_each(list, &card->controls) {
- control = snd_kcontrol(list);
+ list_for_each_entry(control, &card->controls, list)
for (idx = 0; idx < control->count; idx++)
if (control->vd[idx].owner == ctl)
control->vd[idx].owner = NULL;
- }
up_write(&card->controls_rwsem);
snd_ctl_empty_read_queue(ctl);
kfree(ctl);
@@ -140,7 +137,6 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
struct snd_ctl_elem_id *id)
{
unsigned long flags;
- struct list_head *flist;
struct snd_ctl_file *ctl;
struct snd_kctl_event *ev;
@@ -149,14 +145,11 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
card->mixer_oss_change_count++;
#endif
- list_for_each(flist, &card->ctl_files) {
- struct list_head *elist;
- ctl = snd_ctl_file(flist);
+ list_for_each_entry(ctl, &card->ctl_files, list) {
if (!ctl->subscribed)
continue;
spin_lock_irqsave(&ctl->read_lock, flags);
- list_for_each(elist, &ctl->events) {
- ev = snd_kctl_event(elist);
+ list_for_each_entry(ev, &ctl->events, list) {
if (ev->id.numid == id->numid) {
ev->mask |= mask;
goto _found;
@@ -190,7 +183,8 @@ EXPORT_SYMBOL(snd_ctl_notify);
*
* Returns the pointer of the new instance, or NULL on failure.
*/
-struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int access)
+static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
+ unsigned int access)
{
struct snd_kcontrol *kctl;
unsigned int idx;
@@ -208,8 +202,6 @@ struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int acce
return kctl;
}
-EXPORT_SYMBOL(snd_ctl_new);
-
/**
* snd_ctl_new1 - create a control instance from the template
* @ncontrol: the initialization record
@@ -277,11 +269,9 @@ EXPORT_SYMBOL(snd_ctl_free_one);
static unsigned int snd_ctl_hole_check(struct snd_card *card,
unsigned int count)
{
- struct list_head *list;
struct snd_kcontrol *kctl;
- list_for_each(list, &card->controls) {
- kctl = snd_kcontrol(list);
+ list_for_each_entry(kctl, &card->controls, list) {
if ((kctl->id.numid <= card->last_numid &&
kctl->id.numid + kctl->count > card->last_numid) ||
(kctl->id.numid <= card->last_numid + count - 1 &&
@@ -498,12 +488,10 @@ EXPORT_SYMBOL(snd_ctl_rename_id);
*/
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
{
- struct list_head *list;
struct snd_kcontrol *kctl;
snd_assert(card != NULL && numid != 0, return NULL);
- list_for_each(list, &card->controls) {
- kctl = snd_kcontrol(list);
+ list_for_each_entry(kctl, &card->controls, list) {
if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
return kctl;
}
@@ -527,14 +515,12 @@ EXPORT_SYMBOL(snd_ctl_find_numid);
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
struct snd_ctl_elem_id *id)
{
- struct list_head *list;
struct snd_kcontrol *kctl;
snd_assert(card != NULL && id != NULL, return NULL);
if (id->numid != 0)
return snd_ctl_find_numid(card, id->numid);
- list_for_each(list, &card->controls) {
- kctl = snd_kcontrol(list);
+ list_for_each_entry(kctl, &card->controls, list) {
if (kctl->id.iface != id->iface)
continue;
if (kctl->id.device != id->device)
@@ -1182,7 +1168,6 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
{
struct snd_ctl_file *ctl;
struct snd_card *card;
- struct list_head *list;
struct snd_kctl_ioctl *p;
void __user *argp = (void __user *)arg;
int __user *ip = argp;
@@ -1232,8 +1217,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
#endif
}
down_read(&snd_ioctl_rwsem);
- list_for_each(list, &snd_control_ioctls) {
- p = list_entry(list, struct snd_kctl_ioctl, list);
+ list_for_each_entry(p, &snd_control_ioctls, list) {
err = p->fioctl(card, ctl, cmd, arg);
if (err != -ENOIOCTLCMD) {
up_read(&snd_ioctl_rwsem);
@@ -1275,7 +1259,7 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer,
schedule();
remove_wait_queue(&ctl->change_sleep, &wait);
if (signal_pending(current))
- return result > 0 ? result : -ERESTARTSYS;
+ return -ERESTARTSYS;
spin_lock_irq(&ctl->read_lock);
}
kev = snd_kctl_event(ctl->events.next);
@@ -1357,13 +1341,11 @@ EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
struct list_head *lists)
{
- struct list_head *list;
struct snd_kctl_ioctl *p;
snd_assert(fcn != NULL, return -EINVAL);
down_write(&snd_ioctl_rwsem);
- list_for_each(list, lists) {
- p = list_entry(list, struct snd_kctl_ioctl, list);
+ list_for_each_entry(p, lists, list) {
if (p->fioctl == fcn) {
list_del(&p->list);
up_write(&snd_ioctl_rwsem);
@@ -1453,7 +1435,6 @@ static int snd_ctl_dev_register(struct snd_device *device)
static int snd_ctl_dev_disconnect(struct snd_device *device)
{
struct snd_card *card = device->device_data;
- struct list_head *flist;
struct snd_ctl_file *ctl;
int err, cardnum;
@@ -1462,8 +1443,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
down_read(&card->controls_rwsem);
- list_for_each(flist, &card->ctl_files) {
- ctl = snd_ctl_file(flist);
+ list_for_each_entry(ctl, &card->ctl_files, list) {
wake_up(&ctl->change_sleep);
kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
}
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index ab48962c48c..9311ca397bb 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -392,7 +392,7 @@ enum {
static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
struct snd_ctl_file *ctl;
- struct list_head *list;
+ struct snd_kctl_ioctl *p;
void __user *argp = compat_ptr(arg);
int err;
@@ -427,8 +427,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
}
down_read(&snd_ioctl_rwsem);
- list_for_each(list, &snd_control_compat_ioctls) {
- struct snd_kctl_ioctl *p = list_entry(list, struct snd_kctl_ioctl, list);
+ list_for_each_entry(p, &snd_control_compat_ioctls, list) {
if (p->fioctl) {
err = p->fioctl(ctl->card, ctl, cmd, arg);
if (err != -ENOIOCTLCMD) {
diff --git a/sound/core/device.c b/sound/core/device.c
index ccb25816ac9..5858b02b0b1 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -79,13 +79,11 @@ EXPORT_SYMBOL(snd_device_new);
*/
int snd_device_free(struct snd_card *card, void *device_data)
{
- struct list_head *list;
struct snd_device *dev;
snd_assert(card != NULL, return -ENXIO);
snd_assert(device_data != NULL, return -ENXIO);
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
+ list_for_each_entry(dev, &card->devices, list) {
if (dev->device_data != device_data)
continue;
/* unlink */
@@ -124,13 +122,11 @@ EXPORT_SYMBOL(snd_device_free);
*/
int snd_device_disconnect(struct snd_card *card, void *device_data)
{
- struct list_head *list;
struct snd_device *dev;
snd_assert(card != NULL, return -ENXIO);
snd_assert(device_data != NULL, return -ENXIO);
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
+ list_for_each_entry(dev, &card->devices, list) {
if (dev->device_data != device_data)
continue;
if (dev->state == SNDRV_DEV_REGISTERED &&
@@ -161,14 +157,12 @@ int snd_device_disconnect(struct snd_card *card, void *device_data)
*/
int snd_device_register(struct snd_card *card, void *device_data)
{
- struct list_head *list;
struct snd_device *dev;
int err;
snd_assert(card != NULL, return -ENXIO);
snd_assert(device_data != NULL, return -ENXIO);
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
+ list_for_each_entry(dev, &card->devices, list) {
if (dev->device_data != device_data)
continue;
if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
@@ -192,13 +186,11 @@ EXPORT_SYMBOL(snd_device_register);
*/
int snd_device_register_all(struct snd_card *card)
{
- struct list_head *list;
struct snd_device *dev;
int err;
snd_assert(card != NULL, return -ENXIO);
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
+ list_for_each_entry(dev, &card->devices, list) {
if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
if ((err = dev->ops->dev_register(dev)) < 0)
return err;
@@ -215,12 +207,10 @@ int snd_device_register_all(struct snd_card *card)
int snd_device_disconnect_all(struct snd_card *card)
{
struct snd_device *dev;
- struct list_head *list;
int err = 0;
snd_assert(card != NULL, return -ENXIO);
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
+ list_for_each_entry(dev, &card->devices, list) {
if (snd_device_disconnect(card, dev->device_data) < 0)
err = -ENXIO;
}
@@ -234,7 +224,6 @@ int snd_device_disconnect_all(struct snd_card *card)
int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
{
struct snd_device *dev;
- struct list_head *list;
int err;
unsigned int range_low, range_high;
@@ -242,8 +231,7 @@ int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
__again:
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
+ list_for_each_entry(dev, &card->devices, list) {
if (dev->type >= range_low && dev->type <= range_high) {
if ((err = snd_device_free(card, dev->device_data)) < 0)
return err;
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 46b47689362..39c03f3dfbf 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -47,14 +47,11 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device);
static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device)
{
- struct list_head *p;
struct snd_hwdep *hwdep;
- list_for_each(p, &snd_hwdep_devices) {
- hwdep = list_entry(p, struct snd_hwdep, list);
+ list_for_each_entry(hwdep, &snd_hwdep_devices, list)
if (hwdep->card == card && hwdep->device == device)
return hwdep;
- }
return NULL;
}
@@ -159,15 +156,16 @@ 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) {
+ if (hw->ops.release)
err = hw->ops.release(hw, file);
- wake_up(&hw->open_wait);
- }
if (hw->used > 0)
hw->used--;
- snd_card_file_remove(hw->card, file);
mutex_unlock(&hw->open_mutex);
+ wake_up(&hw->open_wait);
+
+ snd_card_file_remove(hw->card, file);
module_put(mod);
return err;
}
@@ -468,15 +466,12 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
static void snd_hwdep_proc_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- struct list_head *p;
struct snd_hwdep *hwdep;
mutex_lock(&register_mutex);
- list_for_each(p, &snd_hwdep_devices) {
- hwdep = list_entry(p, struct snd_hwdep, list);
+ list_for_each_entry(hwdep, &snd_hwdep_devices, list)
snd_iprintf(buffer, "%02i-%02i: %s\n",
hwdep->card->number, hwdep->device, hwdep->name);
- }
mutex_unlock(&register_mutex);
}
diff --git a/sound/core/info.c b/sound/core/info.c
index 0b4aab3225e..54591e2eb6e 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -488,7 +488,7 @@ static long snd_info_entry_ioctl(struct file *file, unsigned int cmd,
static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct snd_info_private_data *data;
struct snd_info_entry *entry;
diff --git a/sound/core/init.c b/sound/core/init.c
index 6152a7554df..db610373374 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -114,22 +114,28 @@ struct snd_card *snd_card_new(int idx, const char *xid,
if (idx < 0) {
int idx2;
for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+ /* idx == -1 == 0xffff means: take any free slot */
if (~snd_cards_lock & idx & 1<<idx2) {
idx = idx2;
if (idx >= snd_ecards_limit)
snd_ecards_limit = idx + 1;
break;
}
- } else if (idx < snd_ecards_limit) {
- if (snd_cards_lock & (1 << idx))
- err = -ENODEV; /* invalid */
- } else if (idx < SNDRV_CARDS)
- snd_ecards_limit = idx + 1; /* increase the limit */
- else
- err = -ENODEV;
+ } else {
+ if (idx < snd_ecards_limit) {
+ if (snd_cards_lock & (1 << idx))
+ err = -EBUSY; /* invalid */
+ } else {
+ if (idx < SNDRV_CARDS)
+ snd_ecards_limit = idx + 1; /* increase the limit */
+ else
+ err = -ENODEV;
+ }
+ }
if (idx < 0 || err < 0) {
mutex_unlock(&snd_card_mutex);
- snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1);
+ snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n",
+ idx, snd_ecards_limit - 1, err);
goto __error;
}
snd_cards_lock |= 1 << idx; /* lock it */
@@ -361,8 +367,10 @@ static int snd_card_do_free(struct snd_card *card)
snd_printk(KERN_WARNING "unable to free card info\n");
/* Not fatal error */
}
- if (card->dev)
- device_unregister(card->dev);
+#ifndef CONFIG_SYSFS_DEPRECATED
+ if (card->card_dev)
+ device_unregister(card->card_dev);
+#endif
kfree(card);
return 0;
}
@@ -497,12 +505,14 @@ int snd_card_register(struct snd_card *card)
int err;
snd_assert(card != NULL, return -EINVAL);
- if (!card->dev) {
- card->dev = device_create(sound_class, card->parent, 0,
- "card%i", card->number);
- if (IS_ERR(card->dev))
- card->dev = NULL;
+#ifndef CONFIG_SYSFS_DEPRECATED
+ if (!card->card_dev) {
+ card->card_dev = device_create(sound_class, card->dev, 0,
+ "card%i", card->number);
+ if (IS_ERR(card->card_dev))
+ card->card_dev = NULL;
}
+#endif
if ((err = snd_device_register_all(card)) < 0)
return err;
mutex_lock(&snd_card_mutex);
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index bc0bd0910a6..f057430db0d 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -406,19 +406,17 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
*/
size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
{
- struct list_head *p;
struct snd_mem_list *mem;
snd_assert(dmab, return 0);
mutex_lock(&list_mutex);
- list_for_each(p, &mem_list_head) {
- mem = list_entry(p, struct snd_mem_list, list);
+ list_for_each_entry(mem, &mem_list_head, list) {
if (mem->id == id &&
(mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
struct device *dev = dmab->dev.dev;
- list_del(p);
+ list_del(&mem->list);
*dmab = mem->buffer;
if (dmab->dev.dev == NULL)
dmab->dev.dev = dev;
@@ -488,7 +486,6 @@ static int snd_mem_proc_read(char *page, char **start, off_t off,
{
int len = 0;
long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
- struct list_head *p;
struct snd_mem_list *mem;
int devno;
static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
@@ -498,8 +495,7 @@ static int snd_mem_proc_read(char *page, char **start, off_t off,
"pages : %li bytes (%li pages per %likB)\n",
pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
devno = 0;
- list_for_each(p, &mem_list_head) {
- mem = list_entry(p, struct snd_mem_list, list);
+ list_for_each_entry(mem, &mem_list_head, list) {
devno++;
len += snprintf(page + len, count - len,
"buffer %d : ID %08x : type %s\n",
diff --git a/sound/core/misc.c b/sound/core/misc.c
index 03fc711f412..6db86a7c970 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -78,3 +78,31 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
EXPORT_SYMBOL(snd_verbose_printd);
#endif
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+/**
+ * snd_pci_quirk_lookup - look up a PCI SSID quirk list
+ * @pci: pci_dev handle
+ * @list: quirk list, terminated by a null entry
+ *
+ * Look through the given quirk list and finds a matching entry
+ * with the same PCI SSID. When subdevice is 0, all subdevice
+ * values may match.
+ *
+ * Returns the matched entry pointer, or NULL if nothing matched.
+ */
+const struct snd_pci_quirk *
+snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
+{
+ const struct snd_pci_quirk *q;
+
+ for (q = list; q->subvendor; q++)
+ if (q->subvendor == pci->subsystem_vendor &&
+ (!q->subdevice || q->subdevice == pci->subsystem_device))
+ return q;
+ return NULL;
+}
+
+EXPORT_SYMBOL(snd_pci_quirk_lookup);
+#endif
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index f4c67042e3a..3391f2a9b4d 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1023,7 +1023,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
}
up_read(&mixer->card->controls_rwsem);
if (slot.present != 0) {
- pslot = (struct slot *)kmalloc(sizeof(slot), GFP_KERNEL);
+ pslot = kmalloc(sizeof(slot), GFP_KERNEL);
if (! pslot)
return -ENOMEM;
*pslot = slot;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index e0821eb3d85..786a82e6889 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -810,6 +810,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
struct snd_mask sformat_mask;
struct snd_mask mask;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -EINTR;
sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL);
params = kmalloc(sizeof(*params), GFP_KERNEL);
sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
@@ -1020,6 +1022,7 @@ failure:
kfree(sw_params);
kfree(params);
kfree(sparams);
+ mutex_unlock(&runtime->oss.params_lock);
return err;
}
@@ -1307,14 +1310,17 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
return tmp;
+ mutex_lock(&runtime->oss.params_lock);
while (bytes > 0) {
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
tmp = bytes;
if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
tmp = runtime->oss.period_bytes - runtime->oss.buffer_used;
if (tmp > 0) {
- if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp))
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT;
+ if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp)) {
+ tmp = -EFAULT;
+ goto err;
+ }
}
runtime->oss.buffer_used += tmp;
buf += tmp;
@@ -1325,22 +1331,24 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr,
runtime->oss.buffer_used - runtime->oss.period_ptr, 1);
if (tmp <= 0)
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ goto err;
runtime->oss.bytes += tmp;
runtime->oss.period_ptr += tmp;
runtime->oss.period_ptr %= runtime->oss.period_bytes;
if (runtime->oss.period_ptr == 0 ||
runtime->oss.period_ptr == runtime->oss.buffer_used)
runtime->oss.buffer_used = 0;
- else if ((substream->f_flags & O_NONBLOCK) != 0)
- return xfer > 0 ? xfer : -EAGAIN;
+ else if ((substream->f_flags & O_NONBLOCK) != 0) {
+ tmp = -EAGAIN;
+ goto err;
+ }
}
} else {
tmp = snd_pcm_oss_write2(substream,
(const char __force *)buf,
runtime->oss.period_bytes, 0);
if (tmp <= 0)
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ goto err;
runtime->oss.bytes += tmp;
buf += tmp;
bytes -= tmp;
@@ -1350,7 +1358,12 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
break;
}
}
+ mutex_unlock(&runtime->oss.params_lock);
return xfer;
+
+ err:
+ mutex_unlock(&runtime->oss.params_lock);
+ return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
}
static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf, size_t bytes, int in_kernel)
@@ -1397,12 +1410,13 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
return tmp;
+ mutex_lock(&runtime->oss.params_lock);
while (bytes > 0) {
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
if (runtime->oss.buffer_used == 0) {
tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
if (tmp <= 0)
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ goto err;
runtime->oss.bytes += tmp;
runtime->oss.period_ptr = tmp;
runtime->oss.buffer_used = tmp;
@@ -1410,8 +1424,10 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
tmp = bytes;
if ((size_t) tmp > runtime->oss.buffer_used)
tmp = runtime->oss.buffer_used;
- if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp))
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT;
+ if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp)) {
+ tmp = -EFAULT;
+ goto err;
+ }
buf += tmp;
bytes -= tmp;
xfer += tmp;
@@ -1420,14 +1436,19 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
tmp = snd_pcm_oss_read2(substream, (char __force *)buf,
runtime->oss.period_bytes, 0);
if (tmp <= 0)
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ goto err;
runtime->oss.bytes += tmp;
buf += tmp;
bytes -= tmp;
xfer += tmp;
}
}
+ mutex_unlock(&runtime->oss.params_lock);
return xfer;
+
+ err:
+ mutex_unlock(&runtime->oss.params_lock);
+ return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
}
static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file)
@@ -1528,6 +1549,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
return err;
format = snd_pcm_oss_format_from(runtime->oss.format);
width = snd_pcm_format_physical_width(format);
+ mutex_lock(&runtime->oss.params_lock);
if (runtime->oss.buffer_used > 0) {
#ifdef OSS_DEBUG
printk("sync: buffer_used\n");
@@ -1537,8 +1559,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
runtime->oss.buffer + runtime->oss.buffer_used,
size);
err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
- if (err < 0)
+ if (err < 0) {
+ mutex_unlock(&runtime->oss.params_lock);
return err;
+ }
} else if (runtime->oss.period_ptr > 0) {
#ifdef OSS_DEBUG
printk("sync: period_ptr\n");
@@ -1548,8 +1572,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
runtime->oss.buffer,
size * 8 / width);
err = snd_pcm_oss_sync1(substream, size);
- if (err < 0)
+ if (err < 0) {
+ mutex_unlock(&runtime->oss.params_lock);
return err;
+ }
}
/*
* The ALSA's period might be a bit large than OSS one.
@@ -1579,6 +1605,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
snd_pcm_lib_writev(substream, buffers, size);
}
}
+ mutex_unlock(&runtime->oss.params_lock);
/*
* finish sync: drain the buffer
*/
@@ -2172,6 +2199,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
runtime->oss.params = 1;
runtime->oss.trigger = 1;
runtime->oss.rate = 8000;
+ mutex_init(&runtime->oss.params_lock);
switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
case SNDRV_MINOR_OSS_PCM_8:
runtime->oss.format = AFMT_U8;
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 5ac6e19ccb4..2743414fc8f 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -45,11 +45,9 @@ static int snd_pcm_dev_disconnect(struct snd_device *device);
static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
{
- struct list_head *p;
struct snd_pcm *pcm;
- list_for_each(p, &snd_pcm_devices) {
- pcm = list_entry(p, struct snd_pcm, list);
+ list_for_each_entry(pcm, &snd_pcm_devices, list) {
if (pcm->card == card && pcm->device == device)
return pcm;
}
@@ -640,6 +638,10 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
err = snd_pcm_substream_proc_init(substream);
if (err < 0) {
snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n");
+ if (prev == NULL)
+ pstr->substream = NULL;
+ else
+ prev->next = NULL;
kfree(substream);
return err;
}
@@ -778,7 +780,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
struct snd_pcm_runtime *runtime;
struct snd_ctl_file *kctl;
struct snd_card *card;
- struct list_head *list;
int prefer_subdevice = -1;
size_t size;
@@ -791,8 +792,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
card = pcm->card;
down_read(&card->controls_rwsem);
- list_for_each(list, &card->ctl_files) {
- kctl = snd_ctl_file(list);
+ list_for_each_entry(kctl, &card->ctl_files, list) {
if (kctl->pid == current->pid) {
prefer_subdevice = kctl->prefer_pcm_subdevice;
if (prefer_subdevice != -1)
@@ -937,9 +937,10 @@ static int snd_pcm_dev_register(struct snd_device *device)
{
int cidx, err;
struct snd_pcm_substream *substream;
- struct list_head *list;
+ struct snd_pcm_notify *notify;
char str[16];
struct snd_pcm *pcm = device->device_data;
+ struct device *dev;
snd_assert(pcm != NULL && device != NULL, return -ENXIO);
mutex_lock(&register_mutex);
@@ -962,11 +963,18 @@ static int snd_pcm_dev_register(struct snd_device *device)
devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
break;
}
- if ((err = snd_register_device(devtype, pcm->card,
- pcm->device,
- &snd_pcm_f_ops[cidx],
- pcm, str)) < 0)
- {
+ /* device pointer to use, pcm->dev takes precedence if
+ * it is assigned, otherwise fall back to card's device
+ * if possible */
+ dev = pcm->dev;
+ if (!dev)
+ dev = snd_card_get_device_link(pcm->card);
+ /* register pcm */
+ err = snd_register_device_for_dev(devtype, pcm->card,
+ pcm->device,
+ &snd_pcm_f_ops[cidx],
+ pcm, str, dev);
+ if (err < 0) {
list_del(&pcm->list);
mutex_unlock(&register_mutex);
return err;
@@ -976,11 +984,10 @@ static int snd_pcm_dev_register(struct snd_device *device)
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
snd_pcm_timer_init(substream);
}
- list_for_each(list, &snd_pcm_notify_list) {
- struct snd_pcm_notify *notify;
- notify = list_entry(list, struct snd_pcm_notify, list);
+
+ list_for_each_entry(notify, &snd_pcm_notify_list, list)
notify->n_register(pcm);
- }
+
mutex_unlock(&register_mutex);
return 0;
}
@@ -1023,7 +1030,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
{
- struct list_head *p;
+ struct snd_pcm *pcm;
snd_assert(notify != NULL &&
notify->n_register != NULL &&
@@ -1032,13 +1039,12 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
mutex_lock(&register_mutex);
if (nfree) {
list_del(&notify->list);
- list_for_each(p, &snd_pcm_devices)
- notify->n_unregister(list_entry(p,
- struct snd_pcm, list));
+ list_for_each_entry(pcm, &snd_pcm_devices, list)
+ notify->n_unregister(pcm);
} else {
list_add_tail(&notify->list, &snd_pcm_notify_list);
- list_for_each(p, &snd_pcm_devices)
- notify->n_register(list_entry(p, struct snd_pcm, list));
+ list_for_each_entry(pcm, &snd_pcm_devices, list)
+ notify->n_register(pcm);
}
mutex_unlock(&register_mutex);
return 0;
@@ -1054,12 +1060,10 @@ EXPORT_SYMBOL(snd_pcm_notify);
static void snd_pcm_proc_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- struct list_head *p;
struct snd_pcm *pcm;
mutex_lock(&register_mutex);
- list_for_each(p, &snd_pcm_devices) {
- pcm = list_entry(p, struct snd_pcm, list);
+ list_for_each_entry(pcm, &snd_pcm_devices, list) {
snd_iprintf(buffer, "%02i-%02i: %s : %s",
pcm->card->number, pcm->device, pcm->id, pcm->name);
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 0bb142a2853..9fefcaa2c32 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -79,19 +79,17 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
runtime->silence_filled -= frames;
if ((snd_pcm_sframes_t)runtime->silence_filled < 0) {
runtime->silence_filled = 0;
- runtime->silence_start = (ofs + frames) - runtime->buffer_size;
+ runtime->silence_start = new_hw_ptr;
} else {
- runtime->silence_start = ofs - runtime->silence_filled;
+ runtime->silence_start = ofs;
}
- if ((snd_pcm_sframes_t)runtime->silence_start < 0)
- runtime->silence_start += runtime->boundary;
}
frames = runtime->buffer_size - runtime->silence_filled;
}
snd_assert(frames <= runtime->buffer_size, return);
if (frames == 0)
return;
- ofs = (runtime->silence_start + runtime->silence_filled) % runtime->buffer_size;
+ ofs = runtime->silence_start % runtime->buffer_size;
while (frames > 0) {
transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
@@ -783,6 +781,11 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *
{
unsigned int k;
int changed = 0;
+
+ if (!count) {
+ i->empty = 1;
+ return -EINVAL;
+ }
for (k = 0; k < count; k++) {
if (mask && !(mask & (1 << k)))
continue;
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index be030cb4d37..95b1b2f0b1e 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -101,6 +101,8 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
{
snd_pcm_lib_preallocate_dma_free(substream);
#ifdef CONFIG_SND_VERBOSE_PROCFS
+ snd_info_free_entry(substream->proc_prealloc_max_entry);
+ substream->proc_prealloc_max_entry = NULL;
snd_info_free_entry(substream->proc_prealloc_entry);
substream->proc_prealloc_entry = NULL;
#endif
@@ -142,6 +144,18 @@ static void snd_pcm_lib_preallocate_proc_read(struct snd_info_entry *entry,
}
/*
+ * read callback for prealloc_max proc file
+ *
+ * prints the maximum allowed size in kB.
+ */
+static void snd_pcm_lib_preallocate_max_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_pcm_substream *substream = entry->private_data;
+ snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_max / 1024);
+}
+
+/*
* write callback for prealloc proc file
*
* accepts the preallocation size in kB.
@@ -203,6 +217,15 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream)
}
}
substream->proc_prealloc_entry = entry;
+ if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) {
+ entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read;
+ entry->private_data = substream;
+ if (snd_info_register(entry) < 0) {
+ snd_info_free_entry(entry);
+ entry = NULL;
+ }
+ }
+ substream->proc_prealloc_max_entry = entry;
}
#else /* !CONFIG_SND_VERBOSE_PROCFS */
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 6ea67b16c67..b52e89393fa 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1604,7 +1604,7 @@ static struct file *snd_pcm_file_fd(int fd)
file = fget(fd);
if (!file)
return NULL;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (!S_ISCHR(inode->i_mode) ||
imajor(inode) != snd_major) {
fput(file);
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 269c467ca9b..7e6ceec738d 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -61,14 +61,11 @@ static DEFINE_MUTEX(register_mutex);
static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
{
- struct list_head *p;
struct snd_rawmidi *rawmidi;
- list_for_each(p, &snd_rawmidi_devices) {
- rawmidi = list_entry(p, struct snd_rawmidi, list);
+ list_for_each_entry(rawmidi, &snd_rawmidi_devices, list)
if (rawmidi->card == card && rawmidi->device == device)
return rawmidi;
- }
return NULL;
}
@@ -389,7 +386,6 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
struct snd_rawmidi *rmidi;
struct snd_rawmidi_file *rawmidi_file;
wait_queue_t wait;
- struct list_head *list;
struct snd_ctl_file *kctl;
if (maj == snd_major) {
@@ -426,8 +422,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
while (1) {
subdevice = -1;
down_read(&card->controls_rwsem);
- list_for_each(list, &card->ctl_files) {
- kctl = snd_ctl_file(list);
+ list_for_each_entry(kctl, &card->ctl_files, list) {
if (kctl->pid == current->pid) {
subdevice = kctl->prefer_rawmidi_subdevice;
if (subdevice != -1)
@@ -575,7 +570,6 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *pstr;
struct snd_rawmidi_substream *substream;
- struct list_head *list;
mutex_lock(&register_mutex);
rmidi = snd_rawmidi_search(card, info->device);
@@ -589,8 +583,7 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info
return -ENOENT;
if (info->subdevice >= pstr->substream_count)
return -ENXIO;
- list_for_each(list, &pstr->substreams) {
- substream = list_entry(list, struct snd_rawmidi_substream, list);
+ list_for_each_entry(substream, &pstr->substreams, list) {
if ((unsigned int)substream->number == info->subdevice)
return snd_rawmidi_info(substream, info);
}
@@ -1313,14 +1306,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
struct snd_rawmidi *rmidi;
struct snd_rawmidi_substream *substream;
struct snd_rawmidi_runtime *runtime;
- struct list_head *list;
rmidi = entry->private_data;
snd_iprintf(buffer, "%s\n\n", rmidi->name);
mutex_lock(&rmidi->open_mutex);
if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
- list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
- substream = list_entry(list, struct snd_rawmidi_substream, list);
+ list_for_each_entry(substream,
+ &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
+ list) {
snd_iprintf(buffer,
"Output %d\n"
" Tx bytes : %lu\n",
@@ -1339,8 +1332,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
}
}
if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) {
- list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
- substream = list_entry(list, struct snd_rawmidi_substream, list);
+ list_for_each_entry(substream,
+ &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams,
+ list) {
snd_iprintf(buffer,
"Input %d\n"
" Rx bytes : %lu\n",
@@ -1385,7 +1379,6 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
struct snd_rawmidi_substream *substream;
int idx;
- INIT_LIST_HEAD(&stream->substreams);
for (idx = 0; idx < count; idx++) {
substream = kzalloc(sizeof(*substream), GFP_KERNEL);
if (substream == NULL) {
@@ -1440,6 +1433,9 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
rmidi->device = device;
mutex_init(&rmidi->open_mutex);
init_waitqueue_head(&rmidi->open_wait);
+ INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams);
+ INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams);
+
if (id != NULL)
strlcpy(rmidi->id, id, sizeof(rmidi->id));
if ((err = snd_rawmidi_alloc_substreams(rmidi,
@@ -1623,13 +1619,10 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
struct snd_rawmidi_ops *ops)
{
- struct list_head *list;
struct snd_rawmidi_substream *substream;
- list_for_each(list, &rmidi->streams[stream].substreams) {
- substream = list_entry(list, struct snd_rawmidi_substream, list);
+ list_for_each_entry(substream, &rmidi->streams[stream].substreams, list)
substream->ops = ops;
- }
}
/*
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 532a660df51..bb9dd9fa8e5 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -659,7 +659,6 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
int err = 0, num_ev = 0;
struct snd_seq_event event_saved;
struct snd_seq_client_port *src_port;
- struct list_head *p;
struct snd_seq_port_subs_info *grp;
src_port = snd_seq_port_use_ptr(client, event->source.port);
@@ -674,8 +673,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
read_lock(&grp->list_lock);
else
down_read(&grp->list_mutex);
- list_for_each(p, &grp->list_head) {
- subs = list_entry(p, struct snd_seq_subscribers, src_list);
+ list_for_each_entry(subs, &grp->list_head, src_list) {
event->dest = subs->info.dest;
if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
/* convert time according to flag with subscription */
@@ -709,15 +707,14 @@ static int port_broadcast_event(struct snd_seq_client *client,
{
int num_ev = 0, err = 0;
struct snd_seq_client *dest_client;
- struct list_head *p;
+ struct snd_seq_client_port *port;
dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST);
if (dest_client == NULL)
return 0; /* no matching destination */
read_lock(&dest_client->ports_lock);
- list_for_each(p, &dest_client->ports_list_head) {
- struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list);
+ list_for_each_entry(port, &dest_client->ports_list_head, list) {
event->dest.port = port->addr.port;
/* pass NULL as source client to avoid error bounce */
err = snd_seq_deliver_single_event(NULL, event,
@@ -2473,11 +2470,10 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,
static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,
struct snd_seq_client *client)
{
- struct list_head *l;
+ struct snd_seq_client_port *p;
mutex_lock(&client->ports_mutex);
- list_for_each(l, &client->ports_list_head) {
- struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
+ list_for_each_entry(p, &client->ports_list_head, list) {
snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n",
p->addr.port, p->name,
FLAG_PERM_RD(p->capability),
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index b79d011813c..37852cdace7 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -106,11 +106,10 @@ static void remove_drivers(void);
static void snd_seq_device_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- struct list_head *head;
+ struct ops_list *ops;
mutex_lock(&ops_mutex);
- list_for_each(head, &opslist) {
- struct ops_list *ops = list_entry(head, struct ops_list, list);
+ list_for_each_entry(ops, &opslist, list) {
snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
ops->id,
ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
@@ -143,7 +142,7 @@ void snd_seq_autoload_unlock(void)
void snd_seq_device_load_drivers(void)
{
#ifdef CONFIG_KMOD
- struct list_head *head;
+ struct ops_list *ops;
/* Calling request_module during module_init()
* may cause blocking.
@@ -155,8 +154,7 @@ void snd_seq_device_load_drivers(void)
return;
mutex_lock(&ops_mutex);
- list_for_each(head, &opslist) {
- struct ops_list *ops = list_entry(head, struct ops_list, list);
+ list_for_each_entry(ops, &opslist, list) {
if (! (ops->driver & DRIVER_LOADED) &&
! (ops->driver & DRIVER_REQUESTED)) {
ops->used++;
@@ -314,8 +312,8 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device)
int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
int argsize)
{
- struct list_head *head;
struct ops_list *ops;
+ struct snd_seq_device *dev;
if (id == NULL || entry == NULL ||
entry->init_device == NULL || entry->free_device == NULL)
@@ -341,8 +339,7 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
ops->argsize = argsize;
/* initialize existing devices if necessary */
- list_for_each(head, &ops->dev_list) {
- struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
+ list_for_each_entry(dev, &ops->dev_list, list) {
init_device(dev, ops);
}
mutex_unlock(&ops->reg_mutex);
@@ -394,8 +391,8 @@ static struct ops_list * create_driver(char *id)
*/
int snd_seq_device_unregister_driver(char *id)
{
- struct list_head *head;
struct ops_list *ops;
+ struct snd_seq_device *dev;
ops = find_driver(id, 0);
if (ops == NULL)
@@ -411,8 +408,7 @@ int snd_seq_device_unregister_driver(char *id)
/* close and release all devices associated with this driver */
mutex_lock(&ops->reg_mutex);
ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
- list_for_each(head, &ops->dev_list) {
- struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
+ list_for_each_entry(dev, &ops->dev_list, list) {
free_device(dev, ops);
}
@@ -512,11 +508,10 @@ static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
*/
static struct ops_list * find_driver(char *id, int create_if_empty)
{
- struct list_head *head;
+ struct ops_list *ops;
mutex_lock(&ops_mutex);
- list_for_each(head, &opslist) {
- struct ops_list *ops = list_entry(head, struct ops_list, list);
+ list_for_each_entry(ops, &opslist, list) {
if (strcmp(ops->id, id) == 0) {
ops->used++;
mutex_unlock(&ops_mutex);
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 4bffe509f71..a3dc5e01e9f 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -151,7 +151,7 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char
return len;
newlen = len;
if (size_aligned > 0)
- newlen = ((len + size_aligned - 1) / size_aligned) * size_aligned;
+ newlen = roundup(len, size_aligned);
if (count < newlen)
return -EAGAIN;
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 8c64b58ff77..eefd1cf872b 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -59,14 +59,12 @@ much elements are in array.
struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
int num)
{
- struct list_head *p;
struct snd_seq_client_port *port;
if (client == NULL)
return NULL;
read_lock(&client->ports_lock);
- list_for_each(p, &client->ports_list_head) {
- port = list_entry(p, struct snd_seq_client_port, list);
+ list_for_each_entry(port, &client->ports_list_head, list) {
if (port->addr.port == num) {
if (port->closing)
break; /* deleting now */
@@ -85,14 +83,12 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
struct snd_seq_port_info *pinfo)
{
int num;
- struct list_head *p;
struct snd_seq_client_port *port, *found;
num = pinfo->addr.port;
found = NULL;
read_lock(&client->ports_lock);
- list_for_each(p, &client->ports_list_head) {
- port = list_entry(p, struct snd_seq_client_port, list);
+ list_for_each_entry(port, &client->ports_list_head, list) {
if (port->addr.port < num)
continue;
if (port->addr.port == num) {
@@ -131,8 +127,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
int port)
{
unsigned long flags;
- struct snd_seq_client_port *new_port;
- struct list_head *l;
+ struct snd_seq_client_port *new_port, *p;
int num = -1;
/* sanity check */
@@ -161,15 +156,14 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
num = port >= 0 ? port : 0;
mutex_lock(&client->ports_mutex);
write_lock_irqsave(&client->ports_lock, flags);
- list_for_each(l, &client->ports_list_head) {
- struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
+ list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port > num)
break;
if (port < 0) /* auto-probe mode */
num = p->addr.port + 1;
}
/* insert the new port */
- list_add_tail(&new_port->list, l);
+ list_add_tail(&new_port->list, &p->list);
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
write_unlock_irqrestore(&client->ports_lock, flags);
@@ -251,9 +245,9 @@ static void clear_subscriber_list(struct snd_seq_client *client,
list_del(&subs->dest_list);
else
list_del(&subs->src_list);
+ up_write(&agrp->list_mutex);
unsubscribe_port(c, aport, agrp, &subs->info, 1);
kfree(subs);
- up_write(&agrp->list_mutex);
snd_seq_port_unlock(aport);
snd_seq_client_unlock(c);
}
@@ -287,16 +281,14 @@ static int port_delete(struct snd_seq_client *client,
int snd_seq_delete_port(struct snd_seq_client *client, int port)
{
unsigned long flags;
- struct list_head *l;
- struct snd_seq_client_port *found = NULL;
+ struct snd_seq_client_port *found = NULL, *p;
mutex_lock(&client->ports_mutex);
write_lock_irqsave(&client->ports_lock, flags);
- list_for_each(l, &client->ports_list_head) {
- struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
+ list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port) {
/* ok found. delete from the list at first */
- list_del(l);
+ list_del(&p->list);
client->num_ports--;
found = p;
break;
@@ -314,7 +306,8 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
int snd_seq_delete_all_ports(struct snd_seq_client *client)
{
unsigned long flags;
- struct list_head deleted_list, *p, *n;
+ struct list_head deleted_list;
+ struct snd_seq_client_port *port, *tmp;
/* move the port list to deleted_list, and
* clear the port list in the client data.
@@ -331,9 +324,8 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
write_unlock_irqrestore(&client->ports_lock, flags);
/* remove each port in deleted_list */
- list_for_each_safe(p, n, &deleted_list) {
- struct snd_seq_client_port *port = list_entry(p, struct snd_seq_client_port, list);
- list_del(p);
+ list_for_each_entry_safe(port, tmp, &deleted_list, list) {
+ list_del(&port->list);
snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
port_delete(client, port);
}
@@ -500,8 +492,7 @@ int snd_seq_port_connect(struct snd_seq_client *connector,
{
struct snd_seq_port_subs_info *src = &src_port->c_src;
struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
- struct snd_seq_subscribers *subs;
- struct list_head *p;
+ struct snd_seq_subscribers *subs, *s;
int err, src_called = 0;
unsigned long flags;
int exclusive;
@@ -525,13 +516,11 @@ int snd_seq_port_connect(struct snd_seq_client *connector,
if (src->exclusive || dest->exclusive)
goto __error;
/* check whether already exists */
- list_for_each(p, &src->list_head) {
- struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, src_list);
+ list_for_each_entry(s, &src->list_head, src_list) {
if (match_subs_info(info, &s->info))
goto __error;
}
- list_for_each(p, &dest->list_head) {
- struct snd_seq_subscribers *s = list_entry(p, struct snd_seq_subscribers, dest_list);
+ list_for_each_entry(s, &dest->list_head, dest_list) {
if (match_subs_info(info, &s->info))
goto __error;
}
@@ -582,7 +571,6 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
struct snd_seq_port_subs_info *src = &src_port->c_src;
struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
struct snd_seq_subscribers *subs;
- struct list_head *p;
int err = -ENOENT;
unsigned long flags;
@@ -590,8 +578,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
/* look for the connection */
- list_for_each(p, &src->list_head) {
- subs = list_entry(p, struct snd_seq_subscribers, src_list);
+ list_for_each_entry(subs, &src->list_head, src_list) {
if (match_subs_info(info, &subs->info)) {
write_lock_irqsave(&src->list_lock, flags);
// write_lock(&dest->list_lock); // no lock yet
@@ -620,12 +607,10 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
struct snd_seq_addr *dest_addr)
{
- struct list_head *p;
struct snd_seq_subscribers *s, *found = NULL;
down_read(&src_grp->list_mutex);
- list_for_each(p, &src_grp->list_head) {
- s = list_entry(p, struct snd_seq_subscribers, src_list);
+ list_for_each_entry(s, &src_grp->list_head, src_list) {
if (addr_match(dest_addr, &s->info.dest)) {
found = s;
break;
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 0cfa06c6b81..972f9340536 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -81,13 +81,11 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
struct snd_seq_event *ev)
{
struct snd_virmidi *vmidi;
- struct list_head *list;
unsigned char msg[4];
int len;
read_lock(&rdev->filelist_lock);
- list_for_each(list, &rdev->filelist) {
- vmidi = list_entry(list, struct snd_virmidi, list);
+ list_for_each_entry(vmidi, &rdev->filelist, list) {
if (!vmidi->trigger)
continue;
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
index c30669f14ac..cefd228cd2a 100644
--- a/sound/core/sgbuf.c
+++ b/sound/core/sgbuf.c
@@ -27,7 +27,7 @@
/* table entries are align to 32 */
#define SGBUF_TBL_ALIGN 32
-#define sgbuf_align_table(tbl) ((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
+#define sgbuf_align_table(tbl) ALIGN((tbl), SGBUF_TBL_ALIGN)
int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
{
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 282742022de..4084de06412 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -219,26 +219,27 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
#endif
/**
- * snd_register_device - Register the ALSA device file for the card
+ * snd_register_device_for_dev - Register the ALSA device file for the card
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
* @card: the card instance
* @dev: the device index
* @f_ops: the file operations
* @private_data: user pointer for f_ops->open()
* @name: the device file name
+ * @device: the &struct device to link this new device to
*
* Registers an ALSA device file for the given card.
* The operators have to be set in reg parameter.
*
- * Retrurns zero if successful, or a negative error code on failure.
+ * Returns zero if successful, or a negative error code on failure.
*/
-int snd_register_device(int type, struct snd_card *card, int dev,
- const struct file_operations *f_ops, void *private_data,
- const char *name)
+int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
+ const struct file_operations *f_ops,
+ void *private_data,
+ const char *name, struct device *device)
{
int minor;
struct snd_minor *preg;
- struct device *device = NULL;
snd_assert(name, return -EINVAL);
preg = kmalloc(sizeof *preg, GFP_KERNEL);
@@ -263,8 +264,6 @@ int snd_register_device(int type, struct snd_card *card, int dev,
return minor;
}
snd_minors[minor] = preg;
- if (card)
- device = card->dev;
preg->dev = device_create(sound_class, device, MKDEV(major, minor),
"%s", name);
if (preg->dev)
@@ -274,7 +273,7 @@ int snd_register_device(int type, struct snd_card *card, int dev,
return 0;
}
-EXPORT_SYMBOL(snd_register_device);
+EXPORT_SYMBOL(snd_register_device_for_dev);
/* find the matching minor record
* return the index of snd_minor, or -1 if not found
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index b2fc40aa520..4566df41912 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -106,7 +106,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
int cidx = SNDRV_MINOR_OSS_CARD(minor);
int track2 = -1;
int register1 = -1, register2 = -1;
- struct device *carddev = NULL;
+ struct device *carddev = snd_card_get_device_link(card);
if (card && card->number >= 8)
return 0; /* ignore silently */
@@ -134,8 +134,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
break;
}
- if (card)
- carddev = card->dev;
register1 = register_sound_special_device(f_ops, minor, carddev);
if (register1 != minor)
goto __end;
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 10a79aed33f..3e063835106 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -35,9 +35,6 @@
#include <sound/minors.h>
#include <sound/initval.h>
#include <linux/kmod.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
#if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE)
#define DEFAULT_TIMER_LIMIT 3
@@ -130,11 +127,8 @@ static struct snd_timer_instance *snd_timer_instance_new(char *owner,
static struct snd_timer *snd_timer_find(struct snd_timer_id *tid)
{
struct snd_timer *timer = NULL;
- struct list_head *p;
-
- list_for_each(p, &snd_timer_list) {
- timer = list_entry(p, struct snd_timer, device_list);
+ list_for_each_entry(timer, &snd_timer_list, device_list) {
if (timer->tmr_class != tid->dev_class)
continue;
if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD ||
@@ -184,13 +178,10 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
{
struct snd_timer *timer;
struct snd_timer_instance *master;
- struct list_head *p, *q;
/* FIXME: it's really dumb to look up all entries.. */
- list_for_each(p, &snd_timer_list) {
- timer = list_entry(p, struct snd_timer, device_list);
- list_for_each(q, &timer->open_list_head) {
- master = list_entry(q, struct snd_timer_instance, open_list);
+ list_for_each_entry(timer, &snd_timer_list, device_list) {
+ list_for_each_entry(master, &timer->open_list_head, open_list) {
if (slave->slave_class == master->slave_class &&
slave->slave_id == master->slave_id) {
list_del(&slave->open_list);
@@ -214,16 +205,13 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
*/
static void snd_timer_check_master(struct snd_timer_instance *master)
{
- struct snd_timer_instance *slave;
- struct list_head *p, *n;
+ struct snd_timer_instance *slave, *tmp;
/* check all pending slaves */
- list_for_each_safe(p, n, &snd_timer_slave_list) {
- slave = list_entry(p, struct snd_timer_instance, open_list);
+ list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
if (slave->slave_class == master->slave_class &&
slave->slave_id == master->slave_id) {
- list_del(p);
- list_add_tail(p, &master->slave_list_head);
+ list_move_tail(&slave->open_list, &master->slave_list_head);
spin_lock_irq(&slave_active_lock);
slave->master = master;
slave->timer = master->timer;
@@ -317,8 +305,7 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri,
int snd_timer_close(struct snd_timer_instance *timeri)
{
struct snd_timer *timer = NULL;
- struct list_head *p, *n;
- struct snd_timer_instance *slave;
+ struct snd_timer_instance *slave, *tmp;
snd_assert(timeri != NULL, return -ENXIO);
@@ -353,12 +340,11 @@ int snd_timer_close(struct snd_timer_instance *timeri)
timer->hw.close)
timer->hw.close(timer);
/* remove slave links */
- list_for_each_safe(p, n, &timeri->slave_list_head) {
- slave = list_entry(p, struct snd_timer_instance, open_list);
+ list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
+ open_list) {
spin_lock_irq(&slave_active_lock);
_snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION);
- list_del(p);
- list_add_tail(p, &snd_timer_slave_list);
+ list_move_tail(&slave->open_list, &snd_timer_slave_list);
slave->master = NULL;
slave->timer = NULL;
spin_unlock_irq(&slave_active_lock);
@@ -394,7 +380,6 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
unsigned long flags;
unsigned long resolution = 0;
struct snd_timer_instance *ts;
- struct list_head *n;
struct timespec tstamp;
getnstimeofday(&tstamp);
@@ -413,11 +398,9 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
return;
spin_lock_irqsave(&timer->lock, flags);
- list_for_each(n, &ti->slave_active_head) {
- ts = list_entry(n, struct snd_timer_instance, active_list);
+ list_for_each_entry(ts, &ti->slave_active_head, active_list)
if (ts->ccallback)
ts->ccallback(ti, event + 100, &tstamp, resolution);
- }
spin_unlock_irqrestore(&timer->lock, flags);
}
@@ -593,10 +576,8 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
{
struct snd_timer_instance *ti;
unsigned long ticks = ~0UL;
- struct list_head *p;
- list_for_each(p, &timer->active_list_head) {
- ti = list_entry(p, struct snd_timer_instance, active_list);
+ list_for_each_entry(ti, &timer->active_list_head, active_list) {
if (ti->flags & SNDRV_TIMER_IFLG_START) {
ti->flags &= ~SNDRV_TIMER_IFLG_START;
ti->flags |= SNDRV_TIMER_IFLG_RUNNING;
@@ -661,9 +642,9 @@ static void snd_timer_tasklet(unsigned long arg)
*/
void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
{
- struct snd_timer_instance *ti, *ts;
+ struct snd_timer_instance *ti, *ts, *tmp;
unsigned long resolution, ticks;
- struct list_head *p, *q, *n, *ack_list_head;
+ struct list_head *p, *ack_list_head;
unsigned long flags;
int use_tasklet = 0;
@@ -679,12 +660,12 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
resolution = timer->hw.resolution;
/* loop for all active instances
- * Here we cannot use list_for_each because the active_list of a
+ * Here we cannot use list_for_each_entry because the active_list of a
* processed instance is relinked to done_list_head before the callback
* is called.
*/
- list_for_each_safe(p, n, &timer->active_list_head) {
- ti = list_entry(p, struct snd_timer_instance, active_list);
+ list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
+ active_list) {
if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
continue;
ti->pticks += ticks_left;
@@ -700,7 +681,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
} else {
ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
if (--timer->running)
- list_del(p);
+ list_del(&ti->active_list);
}
if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
(ti->flags & SNDRV_TIMER_IFLG_FAST))
@@ -709,8 +690,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
ack_list_head = &timer->sack_list_head;
if (list_empty(&ti->ack_list))
list_add_tail(&ti->ack_list, ack_list_head);
- list_for_each(q, &ti->slave_active_head) {
- ts = list_entry(q, struct snd_timer_instance, active_list);
+ list_for_each_entry(ts, &ti->slave_active_head, active_list) {
ts->pticks = ti->pticks;
ts->resolution = resolution;
if (list_empty(&ts->ack_list))
@@ -844,7 +824,6 @@ static int snd_timer_dev_register(struct snd_device *dev)
{
struct snd_timer *timer = dev->device_data;
struct snd_timer *timer1;
- struct list_head *p;
snd_assert(timer != NULL && timer->hw.start != NULL &&
timer->hw.stop != NULL, return -ENXIO);
@@ -853,8 +832,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
return -EINVAL;
mutex_lock(&register_mutex);
- list_for_each(p, &snd_timer_list) {
- timer1 = list_entry(p, struct snd_timer, device_list);
+ list_for_each_entry(timer1, &snd_timer_list, device_list) {
if (timer1->tmr_class > timer->tmr_class)
break;
if (timer1->tmr_class < timer->tmr_class)
@@ -877,7 +855,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
mutex_unlock(&register_mutex);
return -EBUSY;
}
- list_add_tail(&timer->device_list, p);
+ list_add_tail(&timer->device_list, &timer1->device_list);
mutex_unlock(&register_mutex);
return 0;
}
@@ -896,7 +874,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
unsigned long flags;
unsigned long resolution = 0;
struct snd_timer_instance *ti, *ts;
- struct list_head *p, *n;
if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE))
return;
@@ -911,15 +888,12 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
else
resolution = timer->hw.resolution;
}
- list_for_each(p, &timer->active_list_head) {
- ti = list_entry(p, struct snd_timer_instance, active_list);
+ list_for_each_entry(ti, &timer->active_list_head, active_list) {
if (ti->ccallback)
ti->ccallback(ti, event, tstamp, resolution);
- list_for_each(n, &ti->slave_active_head) {
- ts = list_entry(n, struct snd_timer_instance, active_list);
+ list_for_each_entry(ts, &ti->slave_active_head, active_list)
if (ts->ccallback)
ts->ccallback(ts, event, tstamp, resolution);
- }
}
spin_unlock_irqrestore(&timer->lock, flags);
}
@@ -1057,11 +1031,9 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
{
struct snd_timer *timer;
struct snd_timer_instance *ti;
- struct list_head *p, *q;
mutex_lock(&register_mutex);
- list_for_each(p, &snd_timer_list) {
- timer = list_entry(p, struct snd_timer, device_list);
+ list_for_each_entry(timer, &snd_timer_list, device_list) {
switch (timer->tmr_class) {
case SNDRV_TIMER_CLASS_GLOBAL:
snd_iprintf(buffer, "G%i: ", timer->tmr_device);
@@ -1088,14 +1060,12 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
snd_iprintf(buffer, " SLAVE");
snd_iprintf(buffer, "\n");
- list_for_each(q, &timer->open_list_head) {
- ti = list_entry(q, struct snd_timer_instance, open_list);
+ list_for_each_entry(ti, &timer->open_list_head, open_list)
snd_iprintf(buffer, " Client %s : %s\n",
ti->owner ? ti->owner : "unknown",
ti->flags & (SNDRV_TIMER_IFLG_START |
SNDRV_TIMER_IFLG_RUNNING)
? "running" : "stopped");
- }
}
mutex_unlock(&register_mutex);
}
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index 7971285dfd5..83529b08d01 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -26,11 +26,7 @@ config SND_VX_LIB
config SND_AC97_CODEC
tristate
select SND_PCM
- select SND_AC97_BUS
-
-config SND_AC97_BUS
- tristate
-
+ select AC97_BUS
config SND_DUMMY
tristate "Dummy (/dev/null) soundcard"
@@ -113,4 +109,15 @@ config SND_MPU401
To compile this driver as a module, choose M here: the module
will be called snd-mpu401.
+config SND_PORTMAN2X4
+ tristate "Portman 2x4 driver"
+ depends on SND && PARPORT
+ select SND_RAWMIDI
+ help
+ Say Y here to include support for Midiman Portman 2x4 parallel
+ port MIDI device.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-portman2x4.
+
endmenu
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile
index c9bad6d67e7..04112642611 100644
--- a/sound/drivers/Makefile
+++ b/sound/drivers/Makefile
@@ -6,6 +6,7 @@
snd-dummy-objs := dummy.o
snd-mtpav-objs := mtpav.o
snd-mts64-objs := mts64.o
+snd-portman2x4-objs := portman2x4.o
snd-serial-u16550-objs := serial-u16550.o
snd-virmidi-objs := virmidi.o
@@ -15,5 +16,6 @@ obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
obj-$(CONFIG_SND_MTS64) += snd-mts64.o
+obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o
obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 42001efa9f3..8339bad969b 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -501,7 +501,7 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
#define DUMMY_CAPSRC(xname, xindex, addr) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
new file mode 100644
index 00000000000..6c48772aaef
--- /dev/null
+++ b/sound/drivers/portman2x4.c
@@ -0,0 +1,876 @@
+/*
+ * Driver for Midiman Portman2x4 parallel port midi interface
+ *
+ * Copyright (c) by Levent Guendogdu <levon@feature-it.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.
+ *
+ * ChangeLog
+ * Jan 24 2007 Matthias Koenig <mkoenig@suse.de>
+ * - cleanup and rewrite
+ * Sep 30 2004 Tobias Gehrig <tobias@gehrig.tk>
+ * - source code cleanup
+ * Sep 03 2004 Tobias Gehrig <tobias@gehrig.tk>
+ * - fixed compilation problem with alsa 1.0.6a (removed MODULE_CLASSES,
+ * MODULE_PARM_SYNTAX and changed MODULE_DEVICES to
+ * MODULE_SUPPORTED_DEVICE)
+ * Mar 24 2004 Tobias Gehrig <tobias@gehrig.tk>
+ * - added 2.6 kernel support
+ * Mar 18 2004 Tobias Gehrig <tobias@gehrig.tk>
+ * - added parport_unregister_driver to the startup routine if the driver fails to detect a portman
+ * - added support for all 4 output ports in portman_putmidi
+ * Mar 17 2004 Tobias Gehrig <tobias@gehrig.tk>
+ * - added checks for opened input device in interrupt handler
+ * Feb 20 2004 Tobias Gehrig <tobias@gehrig.tk>
+ * - ported from alsa 0.5 to 1.0
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/parport.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+#include <sound/control.h>
+
+#define CARD_NAME "Portman 2x4"
+#define DRIVER_NAME "portman"
+#define PLATFORM_DRIVER "snd_portman2x4"
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+static struct platform_device *platform_devices[SNDRV_CARDS];
+static int device_count;
+
+module_param_array(index, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+module_param_array(id, charp, NULL, S_IRUGO);
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, S_IRUGO);
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+
+MODULE_AUTHOR("Levent Guendogdu, Tobias Gehrig, Matthias Koenig");
+MODULE_DESCRIPTION("Midiman Portman2x4");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Midiman,Portman2x4}}");
+
+/*********************************************************************
+ * Chip specific
+ *********************************************************************/
+#define PORTMAN_NUM_INPUT_PORTS 2
+#define PORTMAN_NUM_OUTPUT_PORTS 4
+
+struct portman {
+ spinlock_t reg_lock;
+ struct snd_card *card;
+ struct snd_rawmidi *rmidi;
+ struct pardevice *pardev;
+ int pardev_claimed;
+
+ int open_count;
+ int mode[PORTMAN_NUM_INPUT_PORTS];
+ struct snd_rawmidi_substream *midi_input[PORTMAN_NUM_INPUT_PORTS];
+};
+
+static int portman_free(struct portman *pm)
+{
+ kfree(pm);
+ return 0;
+}
+
+static int __devinit portman_create(struct snd_card *card,
+ struct pardevice *pardev,
+ struct portman **rchip)
+{
+ struct portman *pm;
+
+ *rchip = NULL;
+
+ pm = kzalloc(sizeof(struct portman), GFP_KERNEL);
+ if (pm == NULL)
+ return -ENOMEM;
+
+ /* Init chip specific data */
+ spin_lock_init(&pm->reg_lock);
+ pm->card = card;
+ pm->pardev = pardev;
+
+ *rchip = pm;
+
+ return 0;
+}
+
+/*********************************************************************
+ * HW related constants
+ *********************************************************************/
+
+/* Standard PC parallel port status register equates. */
+#define PP_STAT_BSY 0x80 /* Busy status. Inverted. */
+#define PP_STAT_ACK 0x40 /* Acknowledge. Non-Inverted. */
+#define PP_STAT_POUT 0x20 /* Paper Out. Non-Inverted. */
+#define PP_STAT_SEL 0x10 /* Select. Non-Inverted. */
+#define PP_STAT_ERR 0x08 /* Error. Non-Inverted. */
+
+/* Standard PC parallel port command register equates. */
+#define PP_CMD_IEN 0x10 /* IRQ Enable. Non-Inverted. */
+#define PP_CMD_SELI 0x08 /* Select Input. Inverted. */
+#define PP_CMD_INIT 0x04 /* Init Printer. Non-Inverted. */
+#define PP_CMD_FEED 0x02 /* Auto Feed. Inverted. */
+#define PP_CMD_STB 0x01 /* Strobe. Inverted. */
+
+/* Parallel Port Command Register as implemented by PCP2x4. */
+#define INT_EN PP_CMD_IEN /* Interrupt enable. */
+#define STROBE PP_CMD_STB /* Command strobe. */
+
+/* The parallel port command register field (b1..b3) selects the
+ * various "registers" within the PC/P 2x4. These are the internal
+ * address of these "registers" that must be written to the parallel
+ * port command register.
+ */
+#define RXDATA0 (0 << 1) /* PCP RxData channel 0. */
+#define RXDATA1 (1 << 1) /* PCP RxData channel 1. */
+#define GEN_CTL (2 << 1) /* PCP General Control Register. */
+#define SYNC_CTL (3 << 1) /* PCP Sync Control Register. */
+#define TXDATA0 (4 << 1) /* PCP TxData channel 0. */
+#define TXDATA1 (5 << 1) /* PCP TxData channel 1. */
+#define TXDATA2 (6 << 1) /* PCP TxData channel 2. */
+#define TXDATA3 (7 << 1) /* PCP TxData channel 3. */
+
+/* Parallel Port Status Register as implemented by PCP2x4. */
+#define ESTB PP_STAT_POUT /* Echoed strobe. */
+#define INT_REQ PP_STAT_ACK /* Input data int request. */
+#define BUSY PP_STAT_ERR /* Interface Busy. */
+
+/* Parallel Port Status Register BUSY and SELECT lines are multiplexed
+ * between several functions. Depending on which 2x4 "register" is
+ * currently selected (b1..b3), the BUSY and SELECT lines are
+ * assigned as follows:
+ *
+ * SELECT LINE: A3 A2 A1
+ * --------
+ */
+#define RXAVAIL PP_STAT_SEL /* Rx Available, channel 0. 0 0 0 */
+// RXAVAIL1 PP_STAT_SEL /* Rx Available, channel 1. 0 0 1 */
+#define SYNC_STAT PP_STAT_SEL /* Reserved - Sync Status. 0 1 0 */
+// /* Reserved. 0 1 1 */
+#define TXEMPTY PP_STAT_SEL /* Tx Empty, channel 0. 1 0 0 */
+// TXEMPTY1 PP_STAT_SEL /* Tx Empty, channel 1. 1 0 1 */
+// TXEMPTY2 PP_STAT_SEL /* Tx Empty, channel 2. 1 1 0 */
+// TXEMPTY3 PP_STAT_SEL /* Tx Empty, channel 3. 1 1 1 */
+
+/* BUSY LINE: A3 A2 A1
+ * --------
+ */
+#define RXDATA PP_STAT_BSY /* Rx Input Data, channel 0. 0 0 0 */
+// RXDATA1 PP_STAT_BSY /* Rx Input Data, channel 1. 0 0 1 */
+#define SYNC_DATA PP_STAT_BSY /* Reserved - Sync Data. 0 1 0 */
+ /* Reserved. 0 1 1 */
+#define DATA_ECHO PP_STAT_BSY /* Parallel Port Data Echo. 1 0 0 */
+#define A0_ECHO PP_STAT_BSY /* Address 0 Echo. 1 0 1 */
+#define A1_ECHO PP_STAT_BSY /* Address 1 Echo. 1 1 0 */
+#define A2_ECHO PP_STAT_BSY /* Address 2 Echo. 1 1 1 */
+
+#define PORTMAN2X4_MODE_INPUT_TRIGGERED 0x01
+
+/*********************************************************************
+ * Hardware specific functions
+ *********************************************************************/
+static inline void portman_write_command(struct portman *pm, u8 value)
+{
+ parport_write_control(pm->pardev->port, value);
+}
+
+static inline u8 portman_read_command(struct portman *pm)
+{
+ return parport_read_control(pm->pardev->port);
+}
+
+static inline u8 portman_read_status(struct portman *pm)
+{
+ return parport_read_status(pm->pardev->port);
+}
+
+static inline u8 portman_read_data(struct portman *pm)
+{
+ return parport_read_data(pm->pardev->port);
+}
+
+static inline void portman_write_data(struct portman *pm, u8 value)
+{
+ parport_write_data(pm->pardev->port, value);
+}
+
+static void portman_write_midi(struct portman *pm,
+ int port, u8 mididata)
+{
+ int command = ((port + 4) << 1);
+
+ /* Get entering data byte and port number in BL and BH respectively.
+ * Set up Tx Channel address field for use with PP Cmd Register.
+ * Store address field in BH register.
+ * Inputs: AH = Output port number (0..3).
+ * AL = Data byte.
+ * command = TXDATA0 | INT_EN;
+ * Align port num with address field (b1...b3),
+ * set address for TXDatax, Strobe=0
+ */
+ command |= INT_EN;
+
+ /* Disable interrupts so that the process is not interrupted, then
+ * write the address associated with the current Tx channel to the
+ * PP Command Reg. Do not set the Strobe signal yet.
+ */
+
+ do {
+ portman_write_command(pm, command);
+
+ /* While the address lines settle, write parallel output data to
+ * PP Data Reg. This has no effect until Strobe signal is asserted.
+ */
+
+ portman_write_data(pm, mididata);
+
+ /* If PCP channel's TxEmpty is set (TxEmpty is read through the PP
+ * Status Register), then go write data. Else go back and wait.
+ */
+ } while ((portman_read_status(pm) & TXEMPTY) != TXEMPTY);
+
+ /* TxEmpty is set. Maintain PC/P destination address and assert
+ * Strobe through the PP Command Reg. This will Strobe data into
+ * the PC/P transmitter and set the PC/P BUSY signal.
+ */
+
+ portman_write_command(pm, command | STROBE);
+
+ /* Wait for strobe line to settle and echo back through hardware.
+ * Once it has echoed back, assume that the address and data lines
+ * have settled!
+ */
+
+ while ((portman_read_status(pm) & ESTB) == 0)
+ cpu_relax();
+
+ /* Release strobe and immediately re-allow interrupts. */
+ portman_write_command(pm, command);
+
+ while ((portman_read_status(pm) & ESTB) == ESTB)
+ cpu_relax();
+
+ /* PC/P BUSY is now set. We must wait until BUSY resets itself.
+ * We'll reenable ints while we're waiting.
+ */
+
+ while ((portman_read_status(pm) & BUSY) == BUSY)
+ cpu_relax();
+
+ /* Data sent. */
+}
+
+
+/*
+ * Read MIDI byte from port
+ * Attempt to read input byte from specified hardware input port (0..).
+ * Return -1 if no data
+ */
+static int portman_read_midi(struct portman *pm, int port)
+{
+ unsigned char midi_data = 0;
+ unsigned char cmdout; /* Saved address+IE bit. */
+
+ /* Make sure clocking edge is down before starting... */
+ portman_write_data(pm, 0); /* Make sure edge is down. */
+
+ /* Set destination address to PCP. */
+ cmdout = (port << 1) | INT_EN; /* Address + IE + No Strobe. */
+ portman_write_command(pm, cmdout);
+
+ while ((portman_read_status(pm) & ESTB) == ESTB)
+ cpu_relax(); /* Wait for strobe echo. */
+
+ /* After the address lines settle, check multiplexed RxAvail signal.
+ * If data is available, read it.
+ */
+ if ((portman_read_status(pm) & RXAVAIL) == 0)
+ return -1; /* No data. */
+
+ /* Set the Strobe signal to enable the Rx clocking circuitry. */
+ portman_write_command(pm, cmdout | STROBE); /* Write address+IE+Strobe. */
+
+ while ((portman_read_status(pm) & ESTB) == 0)
+ cpu_relax(); /* Wait for strobe echo. */
+
+ /* The first data bit (msb) is already sitting on the input line. */
+ midi_data = (portman_read_status(pm) & 128);
+ portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
+
+ /* Data bit 6. */
+ portman_write_data(pm, 0); /* Cause falling edge while data settles. */
+ midi_data |= (portman_read_status(pm) >> 1) & 64;
+ portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
+
+ /* Data bit 5. */
+ portman_write_data(pm, 0); /* Cause falling edge while data settles. */
+ midi_data |= (portman_read_status(pm) >> 2) & 32;
+ portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
+
+ /* Data bit 4. */
+ portman_write_data(pm, 0); /* Cause falling edge while data settles. */
+ midi_data |= (portman_read_status(pm) >> 3) & 16;
+ portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
+
+ /* Data bit 3. */
+ portman_write_data(pm, 0); /* Cause falling edge while data settles. */
+ midi_data |= (portman_read_status(pm) >> 4) & 8;
+ portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
+
+ /* Data bit 2. */
+ portman_write_data(pm, 0); /* Cause falling edge while data settles. */
+ midi_data |= (portman_read_status(pm) >> 5) & 4;
+ portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
+
+ /* Data bit 1. */
+ portman_write_data(pm, 0); /* Cause falling edge while data settles. */
+ midi_data |= (portman_read_status(pm) >> 6) & 2;
+ portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
+
+ /* Data bit 0. */
+ portman_write_data(pm, 0); /* Cause falling edge while data settles. */
+ midi_data |= (portman_read_status(pm) >> 7) & 1;
+ portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
+ portman_write_data(pm, 0); /* Return data clock low. */
+
+
+ /* De-assert Strobe and return data. */
+ portman_write_command(pm, cmdout); /* Output saved address+IE. */
+
+ /* Wait for strobe echo. */
+ while ((portman_read_status(pm) & ESTB) == ESTB)
+ cpu_relax();
+
+ return (midi_data & 255); /* Shift back and return value. */
+}
+
+/*
+ * Checks if any input data on the given channel is available
+ * Checks RxAvail
+ */
+static int portman_data_avail(struct portman *pm, int channel)
+{
+ int command = INT_EN;
+ switch (channel) {
+ case 0:
+ command |= RXDATA0;
+ break;
+ case 1:
+ command |= RXDATA1;
+ break;
+ }
+ /* Write hardware (assumme STROBE=0) */
+ portman_write_command(pm, command);
+ /* Check multiplexed RxAvail signal */
+ if ((portman_read_status(pm) & RXAVAIL) == RXAVAIL)
+ return 1; /* Data available */
+
+ /* No Data available */
+ return 0;
+}
+
+
+/*
+ * Flushes any input
+ */
+static void portman_flush_input(struct portman *pm, unsigned char port)
+{
+ /* Local variable for counting things */
+ unsigned int i = 0;
+ unsigned char command = 0;
+
+ switch (port) {
+ case 0:
+ command = RXDATA0;
+ break;
+ case 1:
+ command = RXDATA1;
+ break;
+ default:
+ snd_printk(KERN_WARNING
+ "portman_flush_input() Won't flush port %i\n",
+ port);
+ return;
+ }
+
+ /* Set address for specified channel in port and allow to settle. */
+ portman_write_command(pm, command);
+
+ /* Assert the Strobe and wait for echo back. */
+ portman_write_command(pm, command | STROBE);
+
+ /* Wait for ESTB */
+ while ((portman_read_status(pm) & ESTB) == 0)
+ cpu_relax();
+
+ /* Output clock cycles to the Rx circuitry. */
+ portman_write_data(pm, 0);
+
+ /* Flush 250 bits... */
+ for (i = 0; i < 250; i++) {
+ portman_write_data(pm, 1);
+ portman_write_data(pm, 0);
+ }
+
+ /* Deassert the Strobe signal of the port and wait for it to settle. */
+ portman_write_command(pm, command | INT_EN);
+
+ /* Wait for settling */
+ while ((portman_read_status(pm) & ESTB) == ESTB)
+ cpu_relax();
+}
+
+static int portman_probe(struct parport *p)
+{
+ /* Initialize the parallel port data register. Will set Rx clocks
+ * low in case we happen to be addressing the Rx ports at this time.
+ */
+ /* 1 */
+ parport_write_data(p, 0);
+
+ /* Initialize the parallel port command register, thus initializing
+ * hardware handshake lines to midi box:
+ *
+ * Strobe = 0
+ * Interrupt Enable = 0
+ */
+ /* 2 */
+ parport_write_control(p, 0);
+
+ /* Check if Portman PC/P 2x4 is out there. */
+ /* 3 */
+ parport_write_control(p, RXDATA0); /* Write Strobe=0 to command reg. */
+
+ /* Check for ESTB to be clear */
+ /* 4 */
+ if ((parport_read_status(p) & ESTB) == ESTB)
+ return 1; /* CODE 1 - Strobe Failure. */
+
+ /* Set for RXDATA0 where no damage will be done. */
+ /* 5 */
+ parport_write_control(p, RXDATA0 + STROBE); /* Write Strobe=1 to command reg. */
+
+ /* 6 */
+ if ((parport_read_status(p) & ESTB) != ESTB)
+ return 1; /* CODE 1 - Strobe Failure. */
+
+ /* 7 */
+ parport_write_control(p, 0); /* Reset Strobe=0. */
+
+ /* Check if Tx circuitry is functioning properly. If initialized
+ * unit TxEmpty is false, send out char and see if if goes true.
+ */
+ /* 8 */
+ parport_write_control(p, TXDATA0); /* Tx channel 0, strobe off. */
+
+ /* If PCP channel's TxEmpty is set (TxEmpty is read through the PP
+ * Status Register), then go write data. Else go back and wait.
+ */
+ /* 9 */
+ if ((parport_read_status(p) & TXEMPTY) == 0)
+ return 2;
+
+ /* Return OK status. */
+ return 0;
+}
+
+static int portman_device_init(struct portman *pm)
+{
+ portman_flush_input(pm, 0);
+ portman_flush_input(pm, 1);
+
+ return 0;
+}
+
+/*********************************************************************
+ * Rawmidi
+ *********************************************************************/
+static int snd_portman_midi_open(struct snd_rawmidi_substream *substream)
+{
+ return 0;
+}
+
+static int snd_portman_midi_close(struct snd_rawmidi_substream *substream)
+{
+ return 0;
+}
+
+static void snd_portman_midi_input_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ struct portman *pm = substream->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pm->reg_lock, flags);
+ if (up)
+ pm->mode[substream->number] |= PORTMAN2X4_MODE_INPUT_TRIGGERED;
+ else
+ pm->mode[substream->number] &= ~PORTMAN2X4_MODE_INPUT_TRIGGERED;
+ spin_unlock_irqrestore(&pm->reg_lock, flags);
+}
+
+static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ struct portman *pm = substream->rmidi->private_data;
+ unsigned long flags;
+ unsigned char byte;
+
+ spin_lock_irqsave(&pm->reg_lock, flags);
+ if (up) {
+ while ((snd_rawmidi_transmit(substream, &byte, 1) == 1))
+ portman_write_midi(pm, substream->number, byte);
+ }
+ spin_unlock_irqrestore(&pm->reg_lock, flags);
+}
+
+static struct snd_rawmidi_ops snd_portman_midi_output = {
+ .open = snd_portman_midi_open,
+ .close = snd_portman_midi_close,
+ .trigger = snd_portman_midi_output_trigger,
+};
+
+static struct snd_rawmidi_ops snd_portman_midi_input = {
+ .open = snd_portman_midi_open,
+ .close = snd_portman_midi_close,
+ .trigger = snd_portman_midi_input_trigger,
+};
+
+/* Create and initialize the rawmidi component */
+static int __devinit snd_portman_rawmidi_create(struct snd_card *card)
+{
+ struct portman *pm = card->private_data;
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_substream *substream;
+ int err;
+
+ err = snd_rawmidi_new(card, CARD_NAME, 0,
+ PORTMAN_NUM_OUTPUT_PORTS,
+ PORTMAN_NUM_INPUT_PORTS,
+ &rmidi);
+ if (err < 0)
+ return err;
+
+ rmidi->private_data = pm;
+ strcpy(rmidi->name, CARD_NAME);
+ rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_INPUT |
+ SNDRV_RAWMIDI_INFO_DUPLEX;
+
+ pm->rmidi = rmidi;
+
+ /* register rawmidi ops */
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &snd_portman_midi_output);
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &snd_portman_midi_input);
+
+ /* name substreams */
+ /* output */
+ list_for_each_entry(substream,
+ &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
+ list) {
+ sprintf(substream->name,
+ "Portman2x4 %d", substream->number+1);
+ }
+ /* input */
+ list_for_each_entry(substream,
+ &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams,
+ list) {
+ pm->midi_input[substream->number] = substream;
+ sprintf(substream->name,
+ "Portman2x4 %d", substream->number+1);
+ }
+
+ return err;
+}
+
+/*********************************************************************
+ * parport stuff
+ *********************************************************************/
+static void snd_portman_interrupt(int irq, void *userdata)
+{
+ unsigned char midivalue = 0;
+ struct portman *pm = ((struct snd_card*)userdata)->private_data;
+
+ spin_lock(&pm->reg_lock);
+
+ /* While any input data is waiting */
+ while ((portman_read_status(pm) & INT_REQ) == INT_REQ) {
+ /* If data available on channel 0,
+ read it and stuff it into the queue. */
+ if (portman_data_avail(pm, 0)) {
+ /* Read Midi */
+ midivalue = portman_read_midi(pm, 0);
+ /* put midi into queue... */
+ if (pm->mode[0] & PORTMAN2X4_MODE_INPUT_TRIGGERED)
+ snd_rawmidi_receive(pm->midi_input[0],
+ &midivalue, 1);
+
+ }
+ /* If data available on channel 1,
+ read it and stuff it into the queue. */
+ if (portman_data_avail(pm, 1)) {
+ /* Read Midi */
+ midivalue = portman_read_midi(pm, 1);
+ /* put midi into queue... */
+ if (pm->mode[1] & PORTMAN2X4_MODE_INPUT_TRIGGERED)
+ snd_rawmidi_receive(pm->midi_input[1],
+ &midivalue, 1);
+ }
+
+ }
+
+ spin_unlock(&pm->reg_lock);
+}
+
+static int __devinit snd_portman_probe_port(struct parport *p)
+{
+ struct pardevice *pardev;
+ int res;
+
+ pardev = parport_register_device(p, DRIVER_NAME,
+ NULL, NULL, NULL,
+ 0, NULL);
+ if (!pardev)
+ return -EIO;
+
+ if (parport_claim(pardev)) {
+ parport_unregister_device(pardev);
+ return -EIO;
+ }
+
+ res = portman_probe(p);
+
+ parport_release(pardev);
+ parport_unregister_device(pardev);
+
+ return res;
+}
+
+static void __devinit snd_portman_attach(struct parport *p)
+{
+ struct platform_device *device;
+
+ device = platform_device_alloc(PLATFORM_DRIVER, device_count);
+ if (!device)
+ return;
+
+ /* Temporary assignment to forward the parport */
+ platform_set_drvdata(device, p);
+
+ if (platform_device_register(device) < 0) {
+ platform_device_put(device);
+ return;
+ }
+
+ /* Since we dont get the return value of probe
+ * We need to check if device probing succeeded or not */
+ if (!platform_get_drvdata(device)) {
+ platform_device_unregister(device);
+ return;
+ }
+
+ /* register device in global table */
+ platform_devices[device_count] = device;
+ device_count++;
+}
+
+static void snd_portman_detach(struct parport *p)
+{
+ /* nothing to do here */
+}
+
+static struct parport_driver portman_parport_driver = {
+ .name = "portman2x4",
+ .attach = snd_portman_attach,
+ .detach = snd_portman_detach
+};
+
+/*********************************************************************
+ * platform stuff
+ *********************************************************************/
+static void snd_portman_card_private_free(struct snd_card *card)
+{
+ struct portman *pm = card->private_data;
+ struct pardevice *pardev = pm->pardev;
+
+ if (pardev) {
+ if (pm->pardev_claimed)
+ parport_release(pardev);
+ parport_unregister_device(pardev);
+ }
+
+ portman_free(pm);
+}
+
+static int __devinit snd_portman_probe(struct platform_device *pdev)
+{
+ struct pardevice *pardev;
+ struct parport *p;
+ int dev = pdev->id;
+ struct snd_card *card = NULL;
+ struct portman *pm = NULL;
+ int err;
+
+ p = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev])
+ return -ENOENT;
+
+ if ((err = snd_portman_probe_port(p)) < 0)
+ return err;
+
+ card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+ if (card == NULL) {
+ snd_printd("Cannot create card\n");
+ return -ENOMEM;
+ }
+ strcpy(card->driver, DRIVER_NAME);
+ strcpy(card->shortname, CARD_NAME);
+ sprintf(card->longname, "%s at 0x%lx, irq %i",
+ card->shortname, p->base, p->irq);
+
+ pardev = parport_register_device(p, /* port */
+ DRIVER_NAME, /* name */
+ NULL, /* preempt */
+ NULL, /* wakeup */
+ snd_portman_interrupt, /* ISR */
+ PARPORT_DEV_EXCL, /* flags */
+ (void *)card); /* private */
+ if (pardev == NULL) {
+ snd_printd("Cannot register pardevice\n");
+ err = -EIO;
+ goto __err;
+ }
+
+ if ((err = portman_create(card, pardev, &pm)) < 0) {
+ snd_printd("Cannot create main component\n");
+ parport_unregister_device(pardev);
+ goto __err;
+ }
+ card->private_data = pm;
+ card->private_free = snd_portman_card_private_free;
+
+ if ((err = snd_portman_rawmidi_create(card)) < 0) {
+ snd_printd("Creating Rawmidi component failed\n");
+ goto __err;
+ }
+
+ /* claim parport */
+ if (parport_claim(pardev)) {
+ snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);
+ err = -EIO;
+ goto __err;
+ }
+ pm->pardev_claimed = 1;
+
+ /* init device */
+ if ((err = portman_device_init(pm)) < 0)
+ goto __err;
+
+ platform_set_drvdata(pdev, card);
+
+ /* At this point card will be usable */
+ if ((err = snd_card_register(card)) < 0) {
+ snd_printd("Cannot register card\n");
+ goto __err;
+ }
+
+ snd_printk(KERN_INFO "Portman 2x4 on 0x%lx\n", p->base);
+ return 0;
+
+__err:
+ snd_card_free(card);
+ return err;
+}
+
+static int snd_portman_remove(struct platform_device *pdev)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+
+ if (card)
+ snd_card_free(card);
+
+ return 0;
+}
+
+
+static struct platform_driver snd_portman_driver = {
+ .probe = snd_portman_probe,
+ .remove = snd_portman_remove,
+ .driver = {
+ .name = PLATFORM_DRIVER
+ }
+};
+
+/*********************************************************************
+ * module init stuff
+ *********************************************************************/
+static void snd_portman_unregister_all(void)
+{
+ int i;
+
+ for (i = 0; i < SNDRV_CARDS; ++i) {
+ if (platform_devices[i]) {
+ platform_device_unregister(platform_devices[i]);
+ platform_devices[i] = NULL;
+ }
+ }
+ platform_driver_unregister(&snd_portman_driver);
+ parport_unregister_driver(&portman_parport_driver);
+}
+
+static int __init snd_portman_module_init(void)
+{
+ int err;
+
+ if ((err = platform_driver_register(&snd_portman_driver)) < 0)
+ return err;
+
+ if (parport_register_driver(&portman_parport_driver) != 0) {
+ platform_driver_unregister(&snd_portman_driver);
+ return -EIO;
+ }
+
+ if (device_count == 0) {
+ snd_portman_unregister_all();
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit snd_portman_module_exit(void)
+{
+ snd_portman_unregister_all();
+}
+
+module_init(snd_portman_module_init);
+module_exit(snd_portman_module_exit);
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 74028b2219c..3a86a582072 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -117,13 +117,13 @@ MODULE_PARM_DESC(adaptor, "Type of adaptor.");
#define SERIAL_MODE_INPUT_TRIGGERED (1 << 2)
#define SERIAL_MODE_OUTPUT_TRIGGERED (1 << 3)
-typedef struct _snd_uart16550 {
+struct snd_uart16550 {
struct snd_card *card;
struct snd_rawmidi *rmidi;
struct snd_rawmidi_substream *midi_output[SNDRV_SERIAL_MAX_OUTS];
struct snd_rawmidi_substream *midi_input[SNDRV_SERIAL_MAX_INS];
- int filemode; //open status of file
+ int filemode; /* open status of file */
spinlock_t open_lock;
@@ -140,39 +140,39 @@ typedef struct _snd_uart16550 {
unsigned char old_divisor_msb;
unsigned char old_line_ctrl_reg;
- // parameter for using of write loop
- short int fifo_limit; //used in uart16550
- short int fifo_count; //used in uart16550
+ /* parameter for using of write loop */
+ short int fifo_limit; /* used in uart16550 */
+ short int fifo_count; /* used in uart16550 */
- // type of adaptor
+ /* type of adaptor */
int adaptor;
- // inputs
+ /* inputs */
int prev_in;
unsigned char rstatus;
- // outputs
+ /* outputs */
int prev_out;
unsigned char prev_status[SNDRV_SERIAL_MAX_OUTS];
- // write buffer and its writing/reading position
+ /* write buffer and its writing/reading position */
unsigned char tx_buff[TX_BUFF_SIZE];
int buff_in_count;
int buff_in;
int buff_out;
int drop_on_full;
- // wait timer
+ /* wait timer */
unsigned int timer_running:1;
struct timer_list buffer_timer;
-} snd_uart16550_t;
+};
static struct platform_device *devices[SNDRV_CARDS];
-static inline void snd_uart16550_add_timer(snd_uart16550_t *uart)
+static inline void snd_uart16550_add_timer(struct snd_uart16550 *uart)
{
- if (! uart->timer_running) {
+ if (!uart->timer_running) {
/* timer 38600bps * 10bit * 16byte */
uart->buffer_timer.expires = jiffies + (HZ+255)/256;
uart->timer_running = 1;
@@ -180,7 +180,7 @@ static inline void snd_uart16550_add_timer(snd_uart16550_t *uart)
}
}
-static inline void snd_uart16550_del_timer(snd_uart16550_t *uart)
+static inline void snd_uart16550_del_timer(struct snd_uart16550 *uart)
{
if (uart->timer_running) {
del_timer(&uart->buffer_timer);
@@ -189,10 +189,10 @@ static inline void snd_uart16550_del_timer(snd_uart16550_t *uart)
}
/* This macro is only used in snd_uart16550_io_loop */
-static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart)
+static inline void snd_uart16550_buffer_output(struct snd_uart16550 *uart)
{
unsigned short buff_out = uart->buff_out;
- if( uart->buff_in_count > 0 ) {
+ if (uart->buff_in_count > 0) {
outb(uart->tx_buff[buff_out], uart->base + UART_TX);
uart->fifo_count++;
buff_out++;
@@ -206,7 +206,7 @@ static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart)
* We don't want to interrupt this,
* as we're already handling an interrupt
*/
-static void snd_uart16550_io_loop(snd_uart16550_t * uart)
+static void snd_uart16550_io_loop(struct snd_uart16550 * uart)
{
unsigned char c, status;
int substream;
@@ -220,9 +220,8 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
c = inb(uart->base + UART_RX);
/* keep track of last status byte */
- if (c & 0x80) {
+ if (c & 0x80)
uart->rstatus = c;
- }
/* handle stream switch */
if (uart->adaptor == SNDRV_SERIAL_GENERIC) {
@@ -230,14 +229,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
if (c <= SNDRV_SERIAL_MAX_INS && c > 0)
substream = c - 1;
if (c != 0xf5)
- uart->rstatus = 0; /* prevent future bytes from being interpreted as streams */
- }
- else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
- snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
- }
- } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
+ /* prevent future bytes from being
+ interpreted as streams */
+ uart->rstatus = 0;
+ } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN)
+ && uart->midi_input[substream])
+ snd_rawmidi_receive(uart->midi_input[substream],
+ &c, 1);
+ } else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) &&
+ uart->midi_input[substream])
snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
- }
if (status & UART_LSR_OE)
snd_printk("%s: Overrun on device at 0x%lx\n",
@@ -250,21 +251,20 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
/* no need of check SERIAL_MODE_OUTPUT_OPEN because if not,
buffer is never filled. */
/* Check write status */
- if (status & UART_LSR_THRE) {
+ if (status & UART_LSR_THRE)
uart->fifo_count = 0;
- }
if (uart->adaptor == SNDRV_SERIAL_MS124W_SA
|| uart->adaptor == SNDRV_SERIAL_GENERIC) {
/* Can't use FIFO, must send only when CTS is true */
status = inb(uart->base + UART_MSR);
- while( (uart->fifo_count == 0) && (status & UART_MSR_CTS) &&
- (uart->buff_in_count > 0) ) {
+ while (uart->fifo_count == 0 && (status & UART_MSR_CTS) &&
+ uart->buff_in_count > 0) {
snd_uart16550_buffer_output(uart);
- status = inb( uart->base + UART_MSR );
+ status = inb(uart->base + UART_MSR);
}
} else {
/* Write loop */
- while (uart->fifo_count < uart->fifo_limit /* Can we write ? */
+ while (uart->fifo_count < uart->fifo_limit /* Can we write ? */
&& uart->buff_in_count > 0) /* Do we want to? */
snd_uart16550_buffer_output(uart);
}
@@ -294,15 +294,16 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
*/
static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id)
{
- snd_uart16550_t *uart;
+ struct snd_uart16550 *uart;
- uart = (snd_uart16550_t *) dev_id;
+ uart = dev_id;
spin_lock(&uart->open_lock);
if (uart->filemode == SERIAL_MODE_NOT_OPENED) {
spin_unlock(&uart->open_lock);
return IRQ_NONE;
}
- inb(uart->base + UART_IIR); /* indicate to the UART that the interrupt has been serviced */
+ /* indicate to the UART that the interrupt has been serviced */
+ inb(uart->base + UART_IIR);
snd_uart16550_io_loop(uart);
spin_unlock(&uart->open_lock);
return IRQ_HANDLED;
@@ -312,9 +313,9 @@ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id)
static void snd_uart16550_buffer_timer(unsigned long data)
{
unsigned long flags;
- snd_uart16550_t *uart;
+ struct snd_uart16550 *uart;
- uart = (snd_uart16550_t *)data;
+ uart = (struct snd_uart16550 *)data;
spin_lock_irqsave(&uart->open_lock, flags);
snd_uart16550_del_timer(uart);
snd_uart16550_io_loop(uart);
@@ -326,7 +327,7 @@ static void snd_uart16550_buffer_timer(unsigned long data)
* return 0 if found
* return negative error if not found
*/
-static int __init snd_uart16550_detect(snd_uart16550_t *uart)
+static int __init snd_uart16550_detect(struct snd_uart16550 *uart)
{
unsigned long io_base = uart->base;
int ok;
@@ -343,7 +344,8 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart)
return -EBUSY;
}
- ok = 1; /* uart detected unless one of the following tests should fail */
+ /* uart detected unless one of the following tests should fail */
+ ok = 1;
/* 8 data-bits, 1 stop-bit, parity off, DLAB = 0 */
outb(UART_LCR_WLEN8, io_base + UART_LCR); /* Line Control Register */
c = inb(io_base + UART_IER);
@@ -368,7 +370,7 @@ static int __init snd_uart16550_detect(snd_uart16550_t *uart)
return ok;
}
-static void snd_uart16550_do_open(snd_uart16550_t * uart)
+static void snd_uart16550_do_open(struct snd_uart16550 * uart)
{
char byte;
@@ -460,7 +462,7 @@ static void snd_uart16550_do_open(snd_uart16550_t * uart)
inb(uart->base + UART_RX); /* Clear any pre-existing receive interrupt */
}
-static void snd_uart16550_do_close(snd_uart16550_t * uart)
+static void snd_uart16550_do_close(struct snd_uart16550 * uart)
{
if (uart->irq < 0)
snd_uart16550_del_timer(uart);
@@ -514,7 +516,7 @@ static void snd_uart16550_do_close(snd_uart16550_t * uart)
static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
- snd_uart16550_t *uart = substream->rmidi->private_data;
+ struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
@@ -528,7 +530,7 @@ static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream)
static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
- snd_uart16550_t *uart = substream->rmidi->private_data;
+ struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
uart->filemode &= ~SERIAL_MODE_INPUT_OPEN;
@@ -539,24 +541,24 @@ static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream)
return 0;
}
-static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream, int up)
+static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream,
+ int up)
{
unsigned long flags;
- snd_uart16550_t *uart = substream->rmidi->private_data;
+ struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
- if (up) {
+ if (up)
uart->filemode |= SERIAL_MODE_INPUT_TRIGGERED;
- } else {
+ else
uart->filemode &= ~SERIAL_MODE_INPUT_TRIGGERED;
- }
spin_unlock_irqrestore(&uart->open_lock, flags);
}
static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
- snd_uart16550_t *uart = substream->rmidi->private_data;
+ struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
@@ -570,7 +572,7 @@ static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream)
static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
- snd_uart16550_t *uart = substream->rmidi->private_data;
+ struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN;
@@ -581,18 +583,20 @@ static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream)
return 0;
};
-static inline int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num )
+static inline int snd_uart16550_buffer_can_write(struct snd_uart16550 *uart,
+ int Num)
{
- if( uart->buff_in_count + Num < TX_BUFF_SIZE )
+ if (uart->buff_in_count + Num < TX_BUFF_SIZE)
return 1;
else
return 0;
}
-static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte)
+static inline int snd_uart16550_write_buffer(struct snd_uart16550 *uart,
+ unsigned char byte)
{
unsigned short buff_in = uart->buff_in;
- if( uart->buff_in_count < TX_BUFF_SIZE ) {
+ if (uart->buff_in_count < TX_BUFF_SIZE) {
uart->tx_buff[buff_in] = byte;
buff_in++;
buff_in &= TX_BUFF_MASK;
@@ -605,12 +609,14 @@ static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned cha
return 0;
}
-static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_substream *substream, unsigned char midi_byte)
+static int snd_uart16550_output_byte(struct snd_uart16550 *uart,
+ struct snd_rawmidi_substream *substream,
+ unsigned char midi_byte)
{
- if (uart->buff_in_count == 0 /* Buffer empty? */
+ if (uart->buff_in_count == 0 /* Buffer empty? */
&& ((uart->adaptor != SNDRV_SERIAL_MS124W_SA &&
uart->adaptor != SNDRV_SERIAL_GENERIC) ||
- (uart->fifo_count == 0 /* FIFO empty? */
+ (uart->fifo_count == 0 /* FIFO empty? */
&& (inb(uart->base + UART_MSR) & UART_MSR_CTS)))) { /* CTS? */
/* Tx Buffer Empty - try to write immediately */
@@ -623,12 +629,13 @@ static int snd_uart16550_output_byte(snd_uart16550_t *uart, struct snd_rawmidi_s
uart->fifo_count++;
outb(midi_byte, uart->base + UART_TX);
} else {
- /* Cannot write (buffer empty) - put char in buffer */
+ /* Cannot write (buffer empty) -
+ * put char in buffer */
snd_uart16550_write_buffer(uart, midi_byte);
}
}
} else {
- if( !snd_uart16550_write_buffer(uart, midi_byte) ) {
+ if (!snd_uart16550_write_buffer(uart, midi_byte)) {
snd_printk("%s: Buffer overrun on device at 0x%lx\n",
uart->rmidi->name, uart->base);
return 0;
@@ -642,9 +649,9 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
unsigned char midi_byte, addr_byte;
- snd_uart16550_t *uart = substream->rmidi->private_data;
+ struct snd_uart16550 *uart = substream->rmidi->private_data;
char first;
- static unsigned long lasttime=0;
+ static unsigned long lasttime = 0;
/* Interupts are disabled during the updating of the tx_buff,
* since it is 'bad' to have two processes updating the same
@@ -653,7 +660,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
spin_lock_irqsave(&uart->open_lock, flags);
- if (uart->irq < 0) //polling
+ if (uart->irq < 0) /* polling */
snd_uart16550_io_loop(uart);
if (uart->adaptor == SNDRV_SERIAL_MS124W_MB) {
@@ -671,7 +678,8 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
/* select any combination of the four ports */
addr_byte = (substream->number << 4) | 0x08;
/* ...except none */
- if (addr_byte == 0x08) addr_byte = 0xf8;
+ if (addr_byte == 0x08)
+ addr_byte = 0xf8;
#endif
snd_uart16550_output_byte(uart, substream, addr_byte);
/* send midi byte */
@@ -679,31 +687,42 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
}
} else {
first = 0;
- while( 1 == snd_rawmidi_transmit_peek(substream, &midi_byte, 1) ) {
- /* Also send F5 after 3 seconds with no data to handle device disconnect */
- if (first == 0 && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS ||
- uart->adaptor == SNDRV_SERIAL_GENERIC) &&
- (uart->prev_out != substream->number || jiffies-lasttime > 3*HZ)) {
-
- if( snd_uart16550_buffer_can_write( uart, 3 ) ) {
+ while (snd_rawmidi_transmit_peek(substream, &midi_byte, 1) == 1) {
+ /* Also send F5 after 3 seconds with no data
+ * to handle device disconnect */
+ if (first == 0 &&
+ (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS ||
+ uart->adaptor == SNDRV_SERIAL_GENERIC) &&
+ (uart->prev_out != substream->number ||
+ jiffies-lasttime > 3*HZ)) {
+
+ if (snd_uart16550_buffer_can_write(uart, 3)) {
/* Roland Soundcanvas part selection */
- /* If this substream of the data is different previous
- substream in this uart, send the change part event */
+ /* If this substream of the data is
+ * different previous substream
+ * in this uart, send the change part
+ * event
+ */
uart->prev_out = substream->number;
/* change part */
- snd_uart16550_output_byte(uart, substream, 0xf5);
+ snd_uart16550_output_byte(uart, substream,
+ 0xf5);
/* data */
- snd_uart16550_output_byte(uart, substream, uart->prev_out + 1);
- /* If midi_byte is a data byte, send the previous status byte */
- if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS))
+ snd_uart16550_output_byte(uart, substream,
+ uart->prev_out + 1);
+ /* If midi_byte is a data byte,
+ * send the previous status byte */
+ if (midi_byte < 0x80 &&
+ uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS)
snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]);
- } else if( !uart->drop_on_full )
+ } else if (!uart->drop_on_full)
break;
}
/* send midi byte */
- if( !snd_uart16550_output_byte(uart, substream, midi_byte) && !uart->drop_on_full )
+ if (!snd_uart16550_output_byte(uart, substream, midi_byte) &&
+ !uart->drop_on_full )
break;
if (midi_byte >= 0x80 && midi_byte < 0xf0)
@@ -717,17 +736,17 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
spin_unlock_irqrestore(&uart->open_lock, flags);
}
-static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream, int up)
+static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream,
+ int up)
{
unsigned long flags;
- snd_uart16550_t *uart = substream->rmidi->private_data;
+ struct snd_uart16550 *uart = substream->rmidi->private_data;
spin_lock_irqsave(&uart->open_lock, flags);
- if (up) {
+ if (up)
uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED;
- } else {
+ else
uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED;
- }
spin_unlock_irqrestore(&uart->open_lock, flags);
if (up)
snd_uart16550_output_write(substream);
@@ -747,10 +766,10 @@ static struct snd_rawmidi_ops snd_uart16550_input =
.trigger = snd_uart16550_input_trigger,
};
-static int snd_uart16550_free(snd_uart16550_t *uart)
+static int snd_uart16550_free(struct snd_uart16550 *uart)
{
if (uart->irq >= 0)
- free_irq(uart->irq, (void *)uart);
+ free_irq(uart->irq, uart);
release_and_free_resource(uart->res_base);
kfree(uart);
return 0;
@@ -758,7 +777,7 @@ static int snd_uart16550_free(snd_uart16550_t *uart)
static int snd_uart16550_dev_free(struct snd_device *device)
{
- snd_uart16550_t *uart = device->device_data;
+ struct snd_uart16550 *uart = device->device_data;
return snd_uart16550_free(uart);
}
@@ -769,12 +788,12 @@ static int __init snd_uart16550_create(struct snd_card *card,
unsigned int base,
int adaptor,
int droponfull,
- snd_uart16550_t **ruart)
+ struct snd_uart16550 **ruart)
{
static struct snd_device_ops ops = {
.dev_free = snd_uart16550_dev_free,
};
- snd_uart16550_t *uart;
+ struct snd_uart16550 *uart;
int err;
@@ -795,7 +814,7 @@ static int __init snd_uart16550_create(struct snd_card *card,
if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {
if (request_irq(irq, snd_uart16550_interrupt,
- IRQF_DISABLED, "Serial MIDI", (void *) uart)) {
+ IRQF_DISABLED, "Serial MIDI", uart)) {
snd_printk("irq %d busy. Using Polling.\n", irq);
} else {
uart->irq = irq;
@@ -843,23 +862,28 @@ static int __init snd_uart16550_create(struct snd_card *card,
static void __init snd_uart16550_substreams(struct snd_rawmidi_str *stream)
{
- struct list_head *list;
+ struct snd_rawmidi_substream *substream;
- list_for_each(list, &stream->substreams) {
- struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list);
+ list_for_each_entry(substream, &stream->substreams, list) {
sprintf(substream->name, "Serial MIDI %d", substream->number + 1);
}
}
-static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, int ins, struct snd_rawmidi **rmidi)
+static int __init snd_uart16550_rmidi(struct snd_uart16550 *uart, int device,
+ int outs, int ins,
+ struct snd_rawmidi **rmidi)
{
struct snd_rawmidi *rrawmidi;
int err;
- if ((err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, outs, ins, &rrawmidi)) < 0)
+ err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device,
+ outs, ins, &rrawmidi);
+ if (err < 0)
return err;
- snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_uart16550_input);
- snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_uart16550_output);
+ snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &snd_uart16550_input);
+ snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &snd_uart16550_output);
strcpy(rrawmidi->name, "Serial MIDI");
snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
@@ -875,7 +899,7 @@ static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int out
static int __init snd_serial_probe(struct platform_device *devptr)
{
struct snd_card *card;
- snd_uart16550_t *uart;
+ struct snd_uart16550 *uart;
int err;
int dev = devptr->id;
@@ -929,7 +953,8 @@ static int __init snd_serial_probe(struct platform_device *devptr)
&uart)) < 0)
goto _err;
- if ((err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi)) < 0)
+ err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi);
+ if (err < 0)
goto _err;
sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d",
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index 1613ed844ac..f63152a6a22 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -716,7 +716,7 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
return 0;
}
-static DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0);
static struct snd_kcontrol_new vx_control_audio_gain = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile
index 816a2e7c88c..45902d48c89 100644
--- a/sound/i2c/Makefile
+++ b/sound/i2c/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_SND) += other/
# Toplevel Module Dependency
obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o
obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o
+obj-$(CONFIG_SND_ICE1724) += snd-i2c.o
diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile
index 2fe023ef00a..77a8a7c75dd 100644
--- a/sound/i2c/other/Makefile
+++ b/sound/i2c/other/Makefile
@@ -6,11 +6,11 @@
snd-ak4114-objs := ak4114.o
snd-ak4117-objs := ak4117.o
snd-ak4xxx-adda-objs := ak4xxx-adda.o
+snd-pt2258-objs := pt2258.o
snd-tea575x-tuner-objs := tea575x-tuner.o
# Module Dependency
obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
-obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o
-obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o
+obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o
obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index d2f2c5078e6..adbfd5884d0 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -42,8 +42,8 @@ static void reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char va
ak4114->write(ak4114->private_data, reg, val);
if (reg <= AK4114_REG_INT1_MASK)
ak4114->regmap[reg] = val;
- else if (reg >= AK4114_REG_RXCSB0 && reg <= AK4114_REG_TXCSB4)
- ak4114->txcsb[reg-AK4114_REG_RXCSB0] = val;
+ else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4)
+ ak4114->txcsb[reg-AK4114_REG_TXCSB0] = val;
}
static inline unsigned char reg_read(struct ak4114 *ak4114, unsigned char reg)
@@ -66,10 +66,8 @@ static void snd_ak4114_free(struct ak4114 *chip)
{
chip->init = 1; /* don't schedule new work */
mb();
- if (chip->workqueue != NULL) {
- flush_workqueue(chip->workqueue);
- destroy_workqueue(chip->workqueue);
- }
+ cancel_delayed_work(&chip->work);
+ flush_scheduled_work();
kfree(chip);
}
@@ -82,7 +80,7 @@ static int snd_ak4114_dev_free(struct snd_device *device)
int snd_ak4114_create(struct snd_card *card,
ak4114_read_t *read, ak4114_write_t *write,
- unsigned char pgm[7], unsigned char txcsb[5],
+ const unsigned char pgm[7], const unsigned char txcsb[5],
void *private_data, struct ak4114 **r_ak4114)
{
struct ak4114 *chip;
@@ -100,18 +98,13 @@ int snd_ak4114_create(struct snd_card *card,
chip->read = read;
chip->write = write;
chip->private_data = private_data;
+ INIT_DELAYED_WORK(&chip->work, ak4114_stats);
for (reg = 0; reg < 7; reg++)
chip->regmap[reg] = pgm[reg];
for (reg = 0; reg < 5; reg++)
chip->txcsb[reg] = txcsb[reg];
- chip->workqueue = create_workqueue("snd-ak4114");
- if (chip->workqueue == NULL) {
- kfree(chip);
- return -ENOMEM;
- }
-
snd_ak4114_reinit(chip);
chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT);
@@ -134,7 +127,8 @@ void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char
if (reg <= AK4114_REG_INT1_MASK)
reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val);
else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4)
- reg_write(chip, reg, (chip->txcsb[reg] & ~mask) | val);
+ reg_write(chip, reg,
+ (chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val);
}
void snd_ak4114_reinit(struct ak4114 *chip)
@@ -143,7 +137,7 @@ void snd_ak4114_reinit(struct ak4114 *chip)
chip->init = 1;
mb();
- flush_workqueue(chip->workqueue);
+ flush_scheduled_work();
/* bring the chip to reset state and powerdown state */
reg_write(chip, AK4114_REG_PWRDN, old & ~(AK4114_RST|AK4114_PWN));
udelay(200);
@@ -158,8 +152,7 @@ void snd_ak4114_reinit(struct ak4114 *chip)
reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN);
/* bring up statistics / event queing */
chip->init = 0;
- INIT_DELAYED_WORK(&chip->work, ak4114_stats);
- queue_delayed_work(chip->workqueue, &chip->work, HZ / 10);
+ schedule_delayed_work(&chip->work, HZ / 10);
}
static unsigned int external_rate(unsigned char rcs1)
@@ -568,7 +561,7 @@ static void ak4114_stats(struct work_struct *work)
if (chip->init)
return;
snd_ak4114_check_rate_and_errors(chip, 0);
- queue_delayed_work(chip->workqueue, &chip->work, HZ / 10);
+ schedule_delayed_work(&chip->work, HZ / 10);
}
EXPORT_SYMBOL(snd_ak4114_create);
diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c
index 4e45952dd95..c022f29da2f 100644
--- a/sound/i2c/other/ak4117.c
+++ b/sound/i2c/other/ak4117.c
@@ -74,7 +74,7 @@ static int snd_ak4117_dev_free(struct snd_device *device)
}
int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write,
- unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117)
+ const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117)
{
struct ak4117 *chip;
int err = 0;
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 5da49e2eb35..8805110017a 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset);
* Used for AK4524 input/ouput attenuation, AK4528, and
* AK5365 input attenuation
*/
-static unsigned char vol_cvt_datt[128] = {
+static const unsigned char vol_cvt_datt[128] = {
0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
@@ -162,17 +162,17 @@ static unsigned char vol_cvt_datt[128] = {
/*
* dB tables
*/
-static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
-static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
+static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
/*
* initialize all the ak4xxx chips
*/
void snd_akm4xxx_init(struct snd_akm4xxx *ak)
{
- static unsigned char inits_ak4524[] = {
+ static const unsigned char inits_ak4524[] = {
0x00, 0x07, /* 0: all power up */
0x01, 0x00, /* 1: ADC/DAC reset */
0x02, 0x60, /* 2: 24bit I2S */
@@ -184,7 +184,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x07, 0x00, /* 7: DAC right muted */
0xff, 0xff
};
- static unsigned char inits_ak4528[] = {
+ static const unsigned char inits_ak4528[] = {
0x00, 0x07, /* 0: all power up */
0x01, 0x00, /* 1: ADC/DAC reset */
0x02, 0x60, /* 2: 24bit I2S */
@@ -194,7 +194,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x05, 0x00, /* 5: ADC right muted */
0xff, 0xff
};
- static unsigned char inits_ak4529[] = {
+ static const unsigned char inits_ak4529[] = {
0x09, 0x01, /* 9: ATS=0, RSTN=1 */
0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
@@ -210,7 +210,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x08, 0x55, /* 8: deemphasis all off */
0xff, 0xff
};
- static unsigned char inits_ak4355[] = {
+ static const unsigned char inits_ak4355[] = {
0x01, 0x02, /* 1: reset and soft-mute */
0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
* disable DZF, sharp roll-off, RSTN#=0 */
@@ -227,7 +227,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x01, 0x01, /* 1: un-reset, unmute */
0xff, 0xff
};
- static unsigned char inits_ak4358[] = {
+ static const unsigned char inits_ak4358[] = {
0x01, 0x02, /* 1: reset and soft-mute */
0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
* disable DZF, sharp roll-off, RSTN#=0 */
@@ -246,7 +246,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x01, 0x01, /* 1: un-reset, unmute */
0xff, 0xff
};
- static unsigned char inits_ak4381[] = {
+ static const unsigned char inits_ak4381[] = {
0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
0x01, 0x02, /* 1: de-emphasis off, normal speed,
* sharp roll-off, DZF off */
@@ -259,7 +259,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
};
int chip, num_chips;
- unsigned char *ptr, reg, data, *inits;
+ const unsigned char *ptr, *inits;
+ unsigned char reg, data;
memset(ak->images, 0, sizeof(ak->images));
memset(ak->volumes, 0, sizeof(ak->volumes));
@@ -513,6 +514,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
return change;
}
+#define AK5365_NUM_INPUTS 5
+
+static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+ int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
+ const char **input_names;
+ int num_names, idx;
+
+ input_names = ak->adc_info[mixer_ch].input_names;
+
+ num_names = 0;
+ while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
+ ++num_names;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = num_names;
+ idx = uinfo->value.enumerated.item;
+ if (idx >= num_names)
+ return -EINVAL;
+ strncpy(uinfo->value.enumerated.name, input_names[idx],
+ sizeof(uinfo->value.enumerated.name));
+ return 0;
+}
+
+static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+ int chip = AK_GET_CHIP(kcontrol->private_value);
+ int addr = AK_GET_ADDR(kcontrol->private_value);
+ int mask = AK_GET_MASK(kcontrol->private_value);
+ unsigned char val;
+
+ val = snd_akm4xxx_get(ak, chip, addr) & mask;
+ ucontrol->value.enumerated.item[0] = val;
+ return 0;
+}
+
+static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+ int chip = AK_GET_CHIP(kcontrol->private_value);
+ int addr = AK_GET_ADDR(kcontrol->private_value);
+ int mask = AK_GET_MASK(kcontrol->private_value);
+ unsigned char oval, val;
+
+ oval = snd_akm4xxx_get(ak, chip, addr);
+ val = oval & ~mask;
+ val |= ucontrol->value.enumerated.item[0] & mask;
+ if (val != oval) {
+ snd_akm4xxx_write(ak, chip, addr, val);
+ return 1;
+ }
+ return 0;
+}
+
/*
* build AK4xxx controls
*/
@@ -647,9 +708,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
if (ak->type == SND_AK5365 && (idx % 2) == 0) {
if (! ak->adc_info ||
- ! ak->adc_info[mixer_ch].switch_name)
+ ! ak->adc_info[mixer_ch].switch_name) {
knew.name = "Capture Switch";
- else
+ knew.index = mixer_ch + ak->idx_offset * 2;
+ } else
knew.name = ak->adc_info[mixer_ch].switch_name;
knew.info = ak4xxx_switch_info;
knew.get = ak4xxx_switch_get;
@@ -662,6 +724,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
if (err < 0)
return err;
+
+ memset(&knew, 0, sizeof(knew));
+ knew.name = ak->adc_info[mixer_ch].selector_name;
+ if (!knew.name) {
+ knew.name = "Capture Channel";
+ knew.index = mixer_ch + ak->idx_offset * 2;
+ }
+
+ knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ knew.info = ak4xxx_capture_source_info;
+ knew.get = ak4xxx_capture_source_get;
+ knew.put = ak4xxx_capture_source_put;
+ knew.access = 0;
+ /* input selector control: reg. 1, bits 0-2.
+ * mis-use 'shift' to pass mixer_ch */
+ knew.private_value
+ = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
+ err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+ if (err < 0)
+ return err;
}
idx += num_stereo;
diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c
new file mode 100644
index 00000000000..e91cc3b44de
--- /dev/null
+++ b/sound/i2c/other/pt2258.c
@@ -0,0 +1,233 @@
+/*
+ * ALSA Driver for the PT2258 volume controller.
+ *
+ * Copyright (c) 2006 Jochen Voss <voss@seehuhn.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <sound/i2c.h>
+#include <sound/pt2258.h>
+
+MODULE_AUTHOR("Jochen Voss <voss@seehuhn.de>");
+MODULE_DESCRIPTION("PT2258 volume controller (Princeton Technology Corp.)");
+MODULE_LICENSE("GPL");
+
+#define PT2258_CMD_RESET 0xc0
+#define PT2258_CMD_UNMUTE 0xf8
+#define PT2258_CMD_MUTE 0xf9
+
+static const unsigned char pt2258_channel_code[12] = {
+ 0x80, 0x90, /* channel 1: -10dB, -1dB */
+ 0x40, 0x50, /* channel 2: -10dB, -1dB */
+ 0x00, 0x10, /* channel 3: -10dB, -1dB */
+ 0x20, 0x30, /* channel 4: -10dB, -1dB */
+ 0x60, 0x70, /* channel 5: -10dB, -1dB */
+ 0xa0, 0xb0 /* channel 6: -10dB, -1dB */
+};
+
+int snd_pt2258_reset(struct snd_pt2258 *pt)
+{
+ unsigned char bytes[2];
+ int i;
+
+ /* reset chip */
+ bytes[0] = PT2258_CMD_RESET;
+ snd_i2c_lock(pt->i2c_bus);
+ if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
+ goto __error;
+ snd_i2c_unlock(pt->i2c_bus);
+
+ /* mute all channels */
+ pt->mute = 1;
+ bytes[0] = PT2258_CMD_MUTE;
+ snd_i2c_lock(pt->i2c_bus);
+ if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
+ goto __error;
+ snd_i2c_unlock(pt->i2c_bus);
+
+ /* set all channels to 0dB */
+ for (i = 0; i < 6; ++i)
+ pt->volume[i] = 0;
+ bytes[0] = 0xd0;
+ bytes[1] = 0xe0;
+ snd_i2c_lock(pt->i2c_bus);
+ if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
+ goto __error;
+ snd_i2c_unlock(pt->i2c_bus);
+
+ return 0;
+
+ __error:
+ snd_i2c_unlock(pt->i2c_bus);
+ snd_printk(KERN_ERR "PT2258 reset failed\n");
+ return -EIO;
+}
+
+static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 79;
+ return 0;
+}
+
+static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pt2258 *pt = kcontrol->private_data;
+ int base = kcontrol->private_value;
+
+ /* chip does not support register reads */
+ ucontrol->value.integer.value[0] = 79 - pt->volume[base];
+ ucontrol->value.integer.value[1] = 79 - pt->volume[base + 1];
+ return 0;
+}
+
+static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pt2258 *pt = kcontrol->private_data;
+ int base = kcontrol->private_value;
+ unsigned char bytes[2];
+ int val0, val1;
+
+ val0 = 79 - ucontrol->value.integer.value[0];
+ val1 = 79 - ucontrol->value.integer.value[1];
+ if (val0 == pt->volume[base] && val1 == pt->volume[base + 1])
+ return 0;
+
+ pt->volume[base] = val0;
+ bytes[0] = pt2258_channel_code[2 * base] | (val0 / 10);
+ bytes[1] = pt2258_channel_code[2 * base + 1] | (val0 % 10);
+ snd_i2c_lock(pt->i2c_bus);
+ if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
+ goto __error;
+ snd_i2c_unlock(pt->i2c_bus);
+
+ pt->volume[base + 1] = val1;
+ bytes[0] = pt2258_channel_code[2 * base + 2] | (val1 / 10);
+ bytes[1] = pt2258_channel_code[2 * base + 3] | (val1 % 10);
+ snd_i2c_lock(pt->i2c_bus);
+ if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
+ goto __error;
+ snd_i2c_unlock(pt->i2c_bus);
+
+ return 1;
+
+ __error:
+ snd_i2c_unlock(pt->i2c_bus);
+ snd_printk(KERN_ERR "PT2258 access failed\n");
+ return -EIO;
+}
+
+static int pt2258_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int pt2258_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pt2258 *pt = kcontrol->private_data;
+
+ ucontrol->value.integer.value[0] = !pt->mute;
+ return 0;
+}
+
+static int pt2258_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pt2258 *pt = kcontrol->private_data;
+ unsigned char bytes[2];
+ int val;
+
+ val = !ucontrol->value.integer.value[0];
+ if (pt->mute == val)
+ return 0;
+
+ pt->mute = val;
+ bytes[0] = val ? PT2258_CMD_MUTE : PT2258_CMD_UNMUTE;
+ snd_i2c_lock(pt->i2c_bus);
+ if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
+ goto __error;
+ snd_i2c_unlock(pt->i2c_bus);
+
+ return 1;
+
+ __error:
+ snd_i2c_unlock(pt->i2c_bus);
+ snd_printk(KERN_ERR "PT2258 access failed 2\n");
+ return -EIO;
+}
+
+static const DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0);
+
+int snd_pt2258_build_controls(struct snd_pt2258 *pt)
+{
+ struct snd_kcontrol_new knew;
+ char *names[3] = {
+ "Mic Loopback Playback Volume",
+ "Line Loopback Playback Volume",
+ "CD Loopback Playback Volume"
+ };
+ int i, err;
+
+ for (i = 0; i < 3; ++i) {
+ memset(&knew, 0, sizeof(knew));
+ knew.name = names[i];
+ knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ knew.count = 1;
+ knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+ knew.private_value = 2 * i;
+ knew.info = pt2258_stereo_volume_info;
+ knew.get = pt2258_stereo_volume_get;
+ knew.put = pt2258_stereo_volume_put;
+ knew.tlv.p = pt2258_db_scale;
+
+ err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
+ if (err < 0)
+ return err;
+ }
+
+ memset(&knew, 0, sizeof(knew));
+ knew.name = "Loopback Switch";
+ knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ knew.info = pt2258_switch_info;
+ knew.get = pt2258_switch_get;
+ knew.put = pt2258_switch_put;
+ knew.access = 0;
+ err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(snd_pt2258_reset);
+EXPORT_SYMBOL(snd_pt2258_build_controls);
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 57371f1a441..4e3a9729f56 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -358,6 +358,7 @@ config SND_SBAWE
config SND_SB16_CSP
bool "Sound Blaster 16/AWE CSP support"
depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC)
+ select FW_LOADER
help
Say Y here to include support for the CSP core. This special
coprocessor can do variable tasks like various compression and
@@ -390,6 +391,7 @@ config SND_SSCAPE
config SND_WAVEFRONT
tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)"
depends on SND
+ select FW_LOADER
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_CS4231_LIB
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index b524e0d9ee4..ec9209cd517 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -906,11 +906,11 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = {
AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1),
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index 666b3bcc19f..8094282c2ae 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -1223,9 +1223,9 @@ int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip,
EXPORT_SYMBOL(snd_ad1848_add_ctl_elem);
-static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
static struct ad1848_mix_elem snd_ad1848_controls[] = {
AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
index b680fddf0d7..8ced5e81b9a 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -294,10 +294,10 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
gus->mix_cntrl_reg |= 4; /* enable MIC */
}
dma1 = gus->gf1.dma1;
- dma1 = dma1 < 0 ? -dma1 : dma1;
+ dma1 = abs(dma1);
dma1 = dmas[dma1 & 7];
dma2 = gus->gf1.dma2;
- dma2 = dma2 < 0 ? -dma2 : dma2;
+ dma2 = abs(dma2);
dma2 = dmas[dma2 & 7];
dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3);
@@ -306,7 +306,7 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
return -EINVAL;
}
irq = gus->gf1.irq;
- irq = irq < 0 ? -irq : irq;
+ irq = abs(irq);
irq = irqs[irq & 0x0f];
if (irq == 0) {
snd_printk(KERN_ERR "Error! IRQ isn't defined.\n");
diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c
index f50c276caee..7107753b85b 100644
--- a/sound/isa/gus/gus_mem.c
+++ b/sound/isa/gus/gus_mem.c
@@ -143,9 +143,8 @@ static int snd_gf1_mem_find(struct snd_gf1_mem * alloc,
struct snd_gf1_mem_block *pblock;
unsigned int ptr1, ptr2;
- align--;
- if (w_16 && align < 1)
- align = 1;
+ if (w_16 && align < 2)
+ align = 2;
block->flags = w_16 ? SNDRV_GF1_MEM_BLOCK_16BIT : 0;
block->owner = SNDRV_GF1_MEM_OWNER_DRIVER;
block->share = 0;
@@ -165,7 +164,7 @@ static int snd_gf1_mem_find(struct snd_gf1_mem * alloc,
if (pblock->next->ptr < boundary)
ptr2 = pblock->next->ptr;
}
- ptr1 = (pblock->ptr + pblock->size + align) & ~align;
+ ptr1 = ALIGN(pblock->ptr + pblock->size, align);
if (ptr1 >= ptr2)
continue;
size1 = ptr2 - ptr1;
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 419b4ebbf00..1e30713d2ca 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -486,8 +486,8 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
static struct snd_kcontrol_new snd_opl3sa2_controls[] = {
OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1),
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index fcd638090a9..3d9d7e0107c 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -161,10 +161,13 @@ int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep)
*/
static void snd_sb_csp_free(struct snd_hwdep *hwdep)
{
+ int i;
struct snd_sb_csp *p = hwdep->private_data;
if (p) {
if (p->running & SNDRV_SB_CSP_ST_RUNNING)
snd_sb_csp_stop(p);
+ for (i = 0; i < ARRAY_SIZE(p->csp_programs); ++i)
+ release_firmware(p->csp_programs[i]);
kfree(p);
}
}
@@ -687,8 +690,50 @@ static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __use
return err;
}
+#define FIRMWARE_IN_THE_KERNEL
+
+#ifdef FIRMWARE_IN_THE_KERNEL
#include "sb16_csp_codecs.h"
+static const struct firmware snd_sb_csp_static_programs[] = {
+ { .data = mulaw_main, .size = sizeof mulaw_main },
+ { .data = alaw_main, .size = sizeof alaw_main },
+ { .data = ima_adpcm_init, .size = sizeof ima_adpcm_init },
+ { .data = ima_adpcm_playback, .size = sizeof ima_adpcm_playback },
+ { .data = ima_adpcm_capture, .size = sizeof ima_adpcm_capture },
+};
+#endif
+
+static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags)
+{
+ static const char *const names[] = {
+ "sb16/mulaw_main.csp",
+ "sb16/alaw_main.csp",
+ "sb16/ima_adpcm_init.csp",
+ "sb16/ima_adpcm_playback.csp",
+ "sb16/ima_adpcm_capture.csp",
+ };
+ const struct firmware *program;
+ int err;
+
+ BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT);
+ program = p->csp_programs[index];
+ if (!program) {
+ err = request_firmware(&program, names[index],
+ p->chip->card->dev);
+ if (err >= 0)
+ p->csp_programs[index] = program;
+ else {
+#ifdef FIRMWARE_IN_THE_KERNEL
+ program = &snd_sb_csp_static_programs[index];
+#else
+ return err;
+#endif
+ }
+ }
+ return snd_sb_csp_load(p, program->data, program->size, flags);
+}
+
/*
* autoload hardware codec if necessary
* return 0 if CSP is loaded and ready to run (p->running != 0)
@@ -708,27 +753,27 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec
} else {
switch (pcm_sfmt) {
case SNDRV_PCM_FORMAT_MU_LAW:
- err = snd_sb_csp_load(p, &mulaw_main[0], sizeof(mulaw_main), 0);
+ err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_MULAW, 0);
p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;
p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
break;
case SNDRV_PCM_FORMAT_A_LAW:
- err = snd_sb_csp_load(p, &alaw_main[0], sizeof(alaw_main), 0);
+ err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ALAW, 0);
p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;
p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
break;
case SNDRV_PCM_FORMAT_IMA_ADPCM:
- err = snd_sb_csp_load(p, &ima_adpcm_init[0], sizeof(ima_adpcm_init),
- SNDRV_SB_CSP_LOAD_INITBLOCK);
+ err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ADPCM_INIT,
+ SNDRV_SB_CSP_LOAD_INITBLOCK);
if (err)
break;
if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) {
- err = snd_sb_csp_load(p, &ima_adpcm_playback[0],
- sizeof(ima_adpcm_playback), 0);
+ err = snd_sb_csp_firmware_load
+ (p, CSP_PROGRAM_ADPCM_PLAYBACK, 0);
p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE;
} else {
- err = snd_sb_csp_load(p, &ima_adpcm_capture[0],
- sizeof(ima_adpcm_capture), 0);
+ err = snd_sb_csp_firmware_load
+ (p, CSP_PROGRAM_ADPCM_CAPTURE, 0);
p->mode = SNDRV_SB_CSP_MODE_DSP_READ;
}
p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index c62a9e3d2ae..3094f385216 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -232,7 +232,7 @@ int snd_sbdsp_create(struct snd_card *card,
chip->port = port;
if (request_irq(irq, irq_handler, hardware == SB_HW_ALS4000 ?
- IRQF_DISABLED | IRQF_SHARED : IRQF_DISABLED,
+ IRQF_SHARED : IRQF_DISABLED,
"SoundBlaster", (void *) chip)) {
snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq);
snd_sbdsp_free(chip);
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index 85db535aea9..e2fdd5fd39d 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -402,6 +402,7 @@ static struct snd_card *snd_wavefront_card_new(int dev)
init_waitqueue_head(&acard->wavefront.interrupt_sleeper);
spin_lock_init(&acard->wavefront.midi.open);
spin_lock_init(&acard->wavefront.midi.virtual);
+ acard->wavefront.card = card;
card->private_free = snd_wavefront_free;
return card;
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
index 4f0846feb73..15331ed8819 100644
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/time.h>
#include <linux/wait.h>
+#include <linux/firmware.h>
#include <sound/core.h>
#include <sound/snd_wavefront.h>
#include <sound/initval.h>
@@ -32,325 +33,17 @@
#define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */
#define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */
-/* weird stuff, derived from port I/O tracing with dosemu */
-
-static unsigned char page_zero[] __devinitdata = {
-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
-};
-
-static unsigned char page_one[] __devinitdata = {
-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
-};
-
-static unsigned char page_two[] __devinitdata = {
-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
-};
-
-static unsigned char page_three[] __devinitdata = {
-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
-};
-
-static unsigned char page_four[] __devinitdata = {
-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
-};
-
-static unsigned char page_six[] __devinitdata = {
-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
-};
-
-static unsigned char page_seven[] __devinitdata = {
-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
-};
-
-static unsigned char page_zero_v2[] __devinitdata = {
-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
-};
-
-static unsigned char page_one_v2[] __devinitdata = {
-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
-};
-
-static unsigned char page_two_v2[] __devinitdata = {
-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
-};
-static unsigned char page_three_v2[] __devinitdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-static unsigned char page_four_v2[] __devinitdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
+#define WAIT_IDLE 0xff
-static unsigned char page_seven_v2[] __devinitdata = {
-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
-};
+#define FIRMWARE_IN_THE_KERNEL
-static unsigned char mod_v2[] __devinitdata = {
-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
-};
-static unsigned char coefficients[] __devinitdata = {
-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
-};
-static unsigned char coefficients2[] __devinitdata = {
-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
-};
-static unsigned char coefficients3[] __devinitdata = {
-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
+#ifdef FIRMWARE_IN_THE_KERNEL
+#include "yss225.c"
+static const struct firmware yss225_registers_firmware = {
+ .data = (u8 *)yss225_registers,
+ .size = sizeof yss225_registers
};
+#endif
static int
wavefront_fx_idle (snd_wavefront_t *dev)
@@ -555,465 +248,56 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file,
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
+ This is the 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.
+ that outputs it.
*/
-
int __devinit
snd_wavefront_fx_start (snd_wavefront_t *dev)
-
{
- unsigned int i, j;
+ unsigned int i;
+ int err;
+ const struct firmware *firmware;
- /* Set all bits for all channels on the MOD unit to zero */
- /* XXX But why do this twice ? */
+ if (dev->fx_initialized)
+ return 0;
- for (j = 0; j < 2; j++) {
- for (i = 0x10; i <= 0xff; i++) {
-
- if (!wavefront_fx_idle (dev)) {
- return (-1);
+ err = request_firmware(&firmware, "yamaha/yss225_registers.bin",
+ dev->card->dev);
+ if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+ firmware = &yss225_registers_firmware;
+#else
+ err = -1;
+ goto out;
+#endif
+ }
+
+ for (i = 0; i + 1 < firmware->size; i += 2) {
+ if (firmware->data[i] >= 8 && firmware->data[i] < 16) {
+ outb(firmware->data[i + 1],
+ dev->base + firmware->data[i]);
+ } else if (firmware->data[i] == WAIT_IDLE) {
+ if (!wavefront_fx_idle(dev)) {
+ err = -1;
+ goto out;
}
-
- outb (i, dev->fx_mod_addr);
- outb (0x0, dev->fx_mod_data);
- }
- }
-
- if (!wavefront_fx_idle (dev)) return (-1);
- outb (0x02, dev->fx_op); /* mute on */
-
- if (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) {
- return (-1);
+ } else {
+ snd_printk(KERN_ERR "invalid address"
+ " in register data\n");
+ err = -1;
+ goto out;
}
-
- 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) return (-1);
- outb (0x02, dev->fx_mod_addr);
- outb (0x00, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- }
-
- for (i = 0xb0; i <= 0xbf; i++) {
- outb (i, dev->fx_mod_addr);
- outb (0x20, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
}
- for (i = 0xf0; i <= 0xff; i++) {
- outb (i, dev->fx_mod_addr);
- outb (0x20, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- }
-
- for (i = 0x10; i <= 0x1d; i++) {
- outb (i, dev->fx_mod_addr);
- outb (0xff, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- }
-
- outb (0x1e, dev->fx_mod_addr);
- outb (0x40, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
-
- for (i = 0x1f; i <= 0x2d; i++) {
- outb (i, dev->fx_mod_addr);
- outb (0xff, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- }
-
- outb (0x2e, dev->fx_mod_addr);
- outb (0x00, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
-
- for (i = 0x2f; i <= 0x3e; i++) {
- outb (i, dev->fx_mod_addr);
- outb (0x00, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- }
-
- outb (0x3f, dev->fx_mod_addr);
- outb (0x20, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
-
- for (i = 0x40; i <= 0x4d; i++) {
- outb (i, dev->fx_mod_addr);
- outb (0x00, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- }
-
- outb (0x4e, dev->fx_mod_addr);
- outb (0x0e, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- outb (0x4f, dev->fx_mod_addr);
- outb (0x0e, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
-
-
- for (i = 0x50; i <= 0x6b; i++) {
- outb (i, dev->fx_mod_addr);
- outb (0x00, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- }
-
- outb (0x6c, dev->fx_mod_addr);
- outb (0x40, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
-
- outb (0x6d, dev->fx_mod_addr);
- outb (0x00, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
-
- outb (0x6e, dev->fx_mod_addr);
- outb (0x40, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
-
- outb (0x6f, dev->fx_mod_addr);
- outb (0x40, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
-
- for (i = 0x70; i <= 0x7f; i++) {
- outb (i, dev->fx_mod_addr);
- outb (0xc0, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- }
-
- for (i = 0x80; i <= 0xaf; i++) {
- outb (i, dev->fx_mod_addr);
- outb (0x00, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- }
-
- for (i = 0xc0; i <= 0xdd; i++) {
- outb (i, dev->fx_mod_addr);
- outb (0x00, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- }
-
- outb (0xde, dev->fx_mod_addr);
- outb (0x10, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- outb (0xdf, dev->fx_mod_addr);
- outb (0x10, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
-
- for (i = 0xe0; i <= 0xef; i++) {
- outb (i, dev->fx_mod_addr);
- outb (0x00, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) return (-1);
- }
-
- /* Some settings (?) that are too small to bundle into loops */
-
- if (!wavefront_fx_idle (dev)) return (-1);
- outb (0x1e, dev->fx_mod_addr);
- outb (0x14, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- outb (0xde, dev->fx_mod_addr);
- outb (0x20, dev->fx_mod_data);
- if (!wavefront_fx_idle (dev)) return (-1);
- outb (0xdf, dev->fx_mod_addr);
- outb (0x20, dev->fx_mod_data);
-
- /* some more coefficients */
-
- if (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) return (-1);
- }
-
- if (!wavefront_fx_idle (dev)) return (-1);
- if (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) return (-1);
- }
+ dev->fx_initialized = 1;
+ err = 0;
- 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 (!wavefront_fx_idle (dev)) 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 (!wavefront_fx_idle (dev)) return (-1);
-
- return (0);
+out:
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (firmware != &yss225_registers_firmware)
+#endif
+ release_firmware(firmware);
+ return err;
}
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index bed329edbdd..78020d832e0 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -1068,7 +1068,7 @@ wavefront_send_sample (snd_wavefront_t *dev,
blocksize = max_blksize;
} else {
/* round to nearest 16-byte value */
- blocksize = ((length-written+7)&~0x7);
+ blocksize = ALIGN(length - written, 8);
}
if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_BLOCK, NULL, NULL)) {
diff --git a/sound/isa/wavefront/yss225.c b/sound/isa/wavefront/yss225.c
new file mode 100644
index 00000000000..9f6be3ff8ec
--- /dev/null
+++ b/sound/isa/wavefront/yss225.c
@@ -0,0 +1,2739 @@
+/*
+ * Copyright (c) 1998-2002 by Paul Davis <pbd@op.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* weird stuff, derived from port I/O tracing with dosemu */
+
+static const struct {
+ unsigned char addr;
+ unsigned char data;
+} yss225_registers[] __devinitdata = {
+/* Set all bits for all channels on the MOD unit to zero */
+{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 },
+
+/* XXX But why do this twice? */
+{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 },
+
+/* mute on */
+{ WAIT_IDLE }, { 0x8, 0x02 },
+
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 },
+
+/* either because of stupidity by TB's programmers, or because it
+ actually does something, rezero the MOD page. */
+{ WAIT_IDLE }, { 0xe, 0x10 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x11 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x12 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x13 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x14 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x15 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x16 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x17 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x18 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x19 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x1f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x20 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x21 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x22 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x23 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x24 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x25 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x26 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x27 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x28 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x29 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x2f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x30 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x31 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x32 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x33 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x34 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x35 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x36 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x37 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x38 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x39 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x3f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x40 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x41 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x42 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x43 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x44 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x45 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x46 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x47 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x48 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x49 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x4f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x50 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x51 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x52 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x53 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x54 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x55 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x56 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x57 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x58 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x59 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x5f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x60 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x61 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x62 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x63 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x64 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x65 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x66 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x67 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x68 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x69 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x6f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x70 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x71 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x72 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x73 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x74 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x75 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x76 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x77 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x78 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x79 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x7f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x80 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x81 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x82 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x83 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x84 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x85 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x86 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x87 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x88 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x89 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x8f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x90 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x91 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x92 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x93 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x94 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x95 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x96 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x97 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x98 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x99 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9a }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9b }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9c }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9d }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9e }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0x9f }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xa9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xab }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xac }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xad }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xae }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xaf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xb9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xba }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xbf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xc9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xca }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xce }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xcf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xd9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xda }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xe9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xea }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xeb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xec }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xed }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xee }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xef }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf0 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf1 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf2 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf3 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf4 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf5 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf6 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf7 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf8 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xf9 }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfa }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfb }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfc }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfd }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xfe }, { 0xf, 0x00 },
+{ WAIT_IDLE }, { 0xe, 0xff }, { 0xf, 0x00 },
+
+/* load page zero */
+{ 0x9, 0x05 }, { 0xb, 0x00 }, { 0xa, 0x00 },
+
+{ 0xd, 0x01 }, { 0xc, 0x7c }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1e }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xf5 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x11 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x32 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x13 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x14 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x76 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x18 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x1a }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x17 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x10 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0xa0 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xd1 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0xf2 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x13 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xf4 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xe0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x15 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x16 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x17 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x50 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x71 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x92 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xb3 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xa0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xd4 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xf5 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x70 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0xa0 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x11 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x16 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x10 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x17 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1d }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xdf }, { WAIT_IDLE },
+
+/* Now load page one */
+{ 0x9, 0x05 }, { 0xb, 0x01 }, { 0xa, 0x00 },
+
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1f }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xd8 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x19 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x18 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0xfa }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1a }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xa0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xd7 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xf7 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1c }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x3c }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x3f }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xdf }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x5d }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x7d }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0x9e }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xbe }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x03 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xdb }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xdb }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xe0 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xfb }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1b }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x02 }, { 0xa, 0x00 },
+
+{ 0xc, 0xc4 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x25 }, { WAIT_IDLE },
+{ 0xc, 0x01 }, { WAIT_IDLE },
+{ 0xc, 0x06 }, { WAIT_IDLE },
+{ 0xc, 0xc4 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x25 }, { WAIT_IDLE },
+{ 0xc, 0x01 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x04 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x04 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x05 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x44 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x03 }, { 0xa, 0x00 },
+
+{ 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x47 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x06 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x70 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x42 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x42 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x42 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x42 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x40 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x04 }, { 0xa, 0x00 },
+
+{ 0xc, 0x63 }, { WAIT_IDLE },
+{ 0xc, 0x03 }, { WAIT_IDLE },
+{ 0xc, 0x26 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x2c }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x24 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x2e }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x01 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x22 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x22 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x22 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x62 }, { WAIT_IDLE },
+{ 0xc, 0x02 }, { WAIT_IDLE },
+{ 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xc, 0x01 }, { WAIT_IDLE },
+{ 0xc, 0x21 }, { WAIT_IDLE },
+{ 0xc, 0x01 }, { WAIT_IDLE },
+
+/* Load memory area (page six) */
+{ 0x9, 0x01 }, { 0xb, 0x06 },
+
+{ 0xa, 0x00 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x02 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x04 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x06 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x08 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x0a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x0c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x0e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x10 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x12 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x14 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x16 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x18 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x20 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x22 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x24 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x26 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x28 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x30 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x32 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x34 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x36 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x38 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x42 }, { 0xd, 0x03 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x44 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x46 }, { 0xd, 0x0a }, { 0xc, 0x21 }, { WAIT_IDLE },
+{ 0xa, 0x48 }, { 0xd, 0x0d }, { 0xc, 0x23 }, { WAIT_IDLE },
+{ 0xa, 0x4a }, { 0xd, 0x23 }, { 0xc, 0x1b }, { WAIT_IDLE },
+{ 0xa, 0x4c }, { 0xd, 0x37 }, { 0xc, 0x8f }, { WAIT_IDLE },
+{ 0xa, 0x4e }, { 0xd, 0x45 }, { 0xc, 0x77 }, { WAIT_IDLE },
+{ 0xa, 0x50 }, { 0xd, 0x52 }, { 0xc, 0xe2 }, { WAIT_IDLE },
+{ 0xa, 0x52 }, { 0xd, 0x1c }, { 0xc, 0x92 }, { WAIT_IDLE },
+{ 0xa, 0x54 }, { 0xd, 0x1c }, { 0xc, 0x52 }, { WAIT_IDLE },
+{ 0xa, 0x56 }, { 0xd, 0x07 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x58 }, { 0xd, 0x2f }, { 0xc, 0xc6 }, { WAIT_IDLE },
+{ 0xa, 0x5a }, { 0xd, 0x0b }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x5c }, { 0xd, 0x30 }, { 0xc, 0x06 }, { WAIT_IDLE },
+{ 0xa, 0x5e }, { 0xd, 0x17 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x60 }, { 0xd, 0x3d }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xa, 0x62 }, { 0xd, 0x29 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x64 }, { 0xd, 0x3e }, { 0xc, 0x41 }, { WAIT_IDLE },
+{ 0xa, 0x66 }, { 0xd, 0x39 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x68 }, { 0xd, 0x4c }, { 0xc, 0x48 }, { WAIT_IDLE },
+{ 0xa, 0x6a }, { 0xd, 0x49 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x6c }, { 0xd, 0x4c }, { 0xc, 0x6c }, { WAIT_IDLE },
+{ 0xa, 0x6e }, { 0xd, 0x11 }, { 0xc, 0xd2 }, { WAIT_IDLE },
+{ 0xa, 0x70 }, { 0xd, 0x16 }, { 0xc, 0x0c }, { WAIT_IDLE },
+{ 0xa, 0x72 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x74 }, { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xa, 0x76 }, { 0xd, 0x0f }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x78 }, { 0xd, 0x00 }, { 0xc, 0x80 }, { WAIT_IDLE },
+{ 0xa, 0x7a }, { 0xd, 0x13 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x7c }, { 0xd, 0x80 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x7e }, { 0xd, 0x80 }, { 0xc, 0x80 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x07 }, { 0xa, 0x00 },
+
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x08 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0xe9 }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x8c }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x8c }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x1a }, { 0xc, 0x75 }, { WAIT_IDLE },
+{ 0xd, 0x0d }, { 0xc, 0x8b }, { WAIT_IDLE },
+{ 0xd, 0x04 }, { 0xc, 0xe9 }, { WAIT_IDLE },
+{ 0xd, 0x0b }, { 0xc, 0x16 }, { WAIT_IDLE },
+{ 0xd, 0x1a }, { 0xc, 0x38 }, { WAIT_IDLE },
+{ 0xd, 0x0d }, { 0xc, 0xc8 }, { WAIT_IDLE },
+{ 0xd, 0x04 }, { 0xc, 0x6f }, { WAIT_IDLE },
+{ 0xd, 0x0b }, { 0xc, 0x91 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x8f }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x62 }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x62 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x7b }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x97 }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0x97 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x52 }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0xf6 }, { WAIT_IDLE },
+{ 0xd, 0x06 }, { 0xc, 0xf6 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x19 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x55 }, { WAIT_IDLE },
+{ 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+/* Now setup the MOD area. */
+{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x08 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x09 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0a }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0b }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0c }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0d }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0e }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0f }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+
+{ 0xe, 0xb0 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb1 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb2 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb3 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb4 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb5 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb6 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb7 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb8 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb9 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xba }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xbb }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xbc }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xbd }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xbe }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xbf }, { 0xf, 0x20 }, { WAIT_IDLE },
+
+{ 0xe, 0xf0 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf1 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf2 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf3 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf4 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf5 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf6 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf7 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf8 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf9 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xfa }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xfb }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xfc }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xfd }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xfe }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xff }, { 0xf, 0x20 }, { WAIT_IDLE },
+
+{ 0xe, 0x10 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x11 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x12 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x13 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x14 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x15 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x16 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x17 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x18 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x19 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x1a }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x1b }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x1c }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x1d }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x1e }, { 0xf, 0x40 }, { WAIT_IDLE },
+{ 0xe, 0x1f }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x20 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x21 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x22 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x23 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x24 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x25 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x26 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x27 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x28 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x29 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x2a }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x2b }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x2c }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x2d }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x2e }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x2f }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x30 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x31 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x32 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x33 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x34 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x35 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x36 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x37 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x38 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x39 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3c }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3e }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x3f }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0x40 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x41 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x42 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x43 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x44 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x45 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x46 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x47 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x48 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x49 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x4a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x4b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x4c }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x4d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x4e }, { 0xf, 0x0e }, { WAIT_IDLE },
+{ 0xe, 0x4f }, { 0xf, 0x0e }, { WAIT_IDLE },
+{ 0xe, 0x50 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x51 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x52 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x53 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x54 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x55 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x56 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x57 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x58 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x59 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5c }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5e }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x5f }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x60 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x61 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x62 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x63 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x64 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x65 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x66 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x67 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x68 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x69 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x6a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x6b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x6c }, { 0xf, 0x40 }, { WAIT_IDLE },
+{ 0xe, 0x6d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x6e }, { 0xf, 0x40 }, { WAIT_IDLE },
+{ 0xe, 0x6f }, { 0xf, 0x40 }, { WAIT_IDLE },
+{ 0xe, 0x70 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x71 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x72 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x73 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x74 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x75 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x76 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x77 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x78 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x79 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7a }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7b }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7c }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7d }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7e }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x7f }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x80 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x81 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x82 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x83 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x84 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x85 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x86 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x87 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x88 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x89 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8c }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8e }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x8f }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x90 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x91 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x92 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x93 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x94 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x95 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x96 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x97 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x98 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x99 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9a }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9b }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9c }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9d }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9e }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x9f }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa8 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa9 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xaa }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xab }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xac }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xad }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xae }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xaf }, { 0xf, 0x00 }, { WAIT_IDLE },
+
+{ 0xe, 0xc0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc8 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc9 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xca }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xcb }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xcc }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xcd }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xce }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xcf }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd8 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd9 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xda }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xdb }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xdc }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xdd }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xde }, { 0xf, 0x10 }, { WAIT_IDLE },
+{ 0xe, 0xdf }, { 0xf, 0x10 }, { WAIT_IDLE },
+{ 0xe, 0xe0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe8 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe9 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xea }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xeb }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xec }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xed }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xee }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xef }, { 0xf, 0x00 }, { WAIT_IDLE },
+
+{ 0xe, 0x01 }, { 0xf, 0x00 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x01 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x02 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x03 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x04 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x05 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x06 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x07 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x08 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x09 }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0a }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0b }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0c }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0d }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0e }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x0f }, { 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+
+/* mute on */
+{ 0x8, 0x02 },
+
+/* Now set the coefficients and so forth for the programs above */
+{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x4b }, { 0xd, 0x03 }, { 0xc, 0x11 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x4d }, { 0xd, 0x01 }, { 0xc, 0x32 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x01 }, { 0xa, 0x40 }, { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xb, 0x01 }, { 0xa, 0x41 }, { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x47 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x4a }, { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x00 }, { 0xd, 0x01 }, { 0xc, 0x1c }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x44 }, { 0xd, 0x01 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x42 }, { 0xd, 0x01 }, { 0xc, 0x1a }, { WAIT_IDLE },
+{ 0xb, 0x00 }, { 0xa, 0x43 }, { 0xd, 0x01 }, { 0xc, 0x20 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x01 }, { 0xa, 0x40 }, { 0xd, 0x02 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xb, 0x01 }, { 0xa, 0x41 }, { 0xd, 0x02 }, { 0xc, 0x60 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x44 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x42 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x43 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x40 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x41 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x51 }, { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x50 }, { 0xd, 0x06 }, { 0xc, 0x40 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4f }, { 0xd, 0x03 }, { 0xc, 0x81 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x53 }, { 0xd, 0x1a }, { 0xc, 0x76 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x54 }, { 0xd, 0x0d }, { 0xc, 0x8b }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x55 }, { 0xd, 0x04 }, { 0xc, 0xe9 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x56 }, { 0xd, 0x0b }, { 0xc, 0x17 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x57 }, { 0xd, 0x1a }, { 0xc, 0x38 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x58 }, { 0xd, 0x0d }, { 0xc, 0xc9 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x59 }, { 0xd, 0x04 }, { 0xc, 0x6f }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x5a }, { 0xd, 0x0b }, { 0xc, 0x91 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x73 }, { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x74 }, { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x75 }, { 0xd, 0x04 }, { 0xc, 0xd9 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x76 }, { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x77 }, { 0xd, 0x14 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x78 }, { 0xd, 0x0d }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x79 }, { 0xd, 0x04 }, { 0xc, 0xd9 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7a }, { 0xd, 0x05 }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x5e }, { 0xd, 0x03 }, { 0xc, 0x68 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x5c }, { 0xd, 0x04 }, { 0xc, 0x31 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x5d }, { 0xd, 0x04 }, { 0xc, 0x31 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x62 }, { 0xd, 0x03 }, { 0xc, 0x52 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x60 }, { 0xd, 0x04 }, { 0xc, 0x76 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x61 }, { 0xd, 0x04 }, { 0xc, 0x76 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x66 }, { 0xd, 0x03 }, { 0xc, 0x2e }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x64 }, { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x65 }, { 0xd, 0x04 }, { 0xc, 0xda }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x6a }, { 0xd, 0x02 }, { 0xc, 0xf6 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x68 }, { 0xd, 0x05 }, { 0xc, 0x62 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x69 }, { 0xd, 0x05 }, { 0xc, 0x62 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x46 }, { 0xd, 0x0a }, { 0xc, 0x22 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x48 }, { 0xd, 0x0d }, { 0xc, 0x24 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x6e }, { 0xd, 0x11 }, { 0xc, 0xd3 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x70 }, { 0xd, 0x15 }, { 0xc, 0xcb }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x52 }, { 0xd, 0x20 }, { 0xc, 0x93 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x54 }, { 0xd, 0x20 }, { 0xc, 0x54 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x4a }, { 0xd, 0x27 }, { 0xc, 0x1d }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x58 }, { 0xd, 0x2f }, { 0xc, 0xc8 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x5c }, { 0xd, 0x30 }, { 0xc, 0x07 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x4c }, { 0xd, 0x37 }, { 0xc, 0x90 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x60 }, { 0xd, 0x3d }, { 0xc, 0xdb }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x64 }, { 0xd, 0x3e }, { 0xc, 0x42 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x4e }, { 0xd, 0x45 }, { 0xc, 0x78 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x68 }, { 0xd, 0x4c }, { 0xc, 0x48 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x6c }, { 0xd, 0x4c }, { 0xc, 0x6c }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x50 }, { 0xd, 0x52 }, { 0xc, 0xe2 }, { WAIT_IDLE },
+{ 0xb, 0x06 }, { 0xa, 0x42 }, { 0xd, 0x02 }, { 0xc, 0xba }, { WAIT_IDLE },
+
+/* Some settings (?) */
+{ WAIT_IDLE }, { 0xe, 0x1e }, { 0xf, 0x14 },
+{ WAIT_IDLE }, { 0xe, 0xde }, { 0xf, 0x20 },
+{ WAIT_IDLE }, { 0xe, 0xdf }, { 0xf, 0x20 },
+
+/* some more coefficients */
+{ WAIT_IDLE }, { 0xb, 0x06 }, { 0xa, 0x78 }, { 0xd, 0x00 }, { 0xc, 0x40 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x03 }, { 0xd, 0x0f }, { 0xc, 0xff },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x0b }, { 0xd, 0x0f }, { 0xc, 0xff },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x02 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x0a }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ WAIT_IDLE }, { 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 },
+
+/* 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. */
+{ 0x9, 0x05 }, { 0xb, 0x00 }, { 0xa, 0x10 },
+
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x02 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x01 }, { 0xa, 0x10 },
+
+{ 0xd, 0x01 }, { 0xc, 0xc0 }, { WAIT_IDLE },
+{ 0xd, 0x01 }, { 0xc, 0xfa }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x1a }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+{ WAIT_IDLE }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x02 }, { 0xa, 0x10 },
+
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x46 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x03 }, { 0xa, 0x10 },
+
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x04 }, { 0xa, 0x10 },
+
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xc, 0x00 }, { WAIT_IDLE },
+
+/* Page six v.2 */
+{ 0x9, 0x01 }, { 0xb, 0x06 },
+
+{ 0xa, 0x10 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x12 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x14 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x16 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x18 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x1e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x20 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x22 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x24 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x26 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x28 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x2e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x30 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x32 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x34 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x36 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x38 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xa, 0x3e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0x9, 0x05 }, { 0xb, 0x07 }, { 0xa, 0x10 },
+
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xb0 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb1 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb2 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb3 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb4 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb5 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb6 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xb7 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf0 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf1 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf2 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf3 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf4 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf5 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf6 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0xf7 }, { 0xf, 0x20 }, { WAIT_IDLE },
+{ 0xe, 0x10 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x11 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x12 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x13 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x14 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x15 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x16 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x17 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x20 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x21 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x22 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x23 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x24 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x25 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x26 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x27 }, { 0xf, 0xff }, { WAIT_IDLE },
+{ 0xe, 0x30 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x31 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x32 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x33 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x34 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x35 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x36 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x37 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x40 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x41 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x42 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x43 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x44 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x45 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x46 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x47 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x50 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x51 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x52 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x53 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x54 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x55 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x56 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x57 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x60 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x61 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x62 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x63 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x64 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x65 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x66 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x67 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x70 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x71 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x72 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x73 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x74 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x75 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x76 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x77 }, { 0xf, 0xc0 }, { WAIT_IDLE },
+{ 0xe, 0x80 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x81 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x82 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x83 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x84 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x85 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x86 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x87 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x90 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x91 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x92 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x93 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x94 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x95 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x96 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x97 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xa7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xc7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xd7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe0 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe1 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe2 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe3 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe4 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe5 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe6 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0xe7 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x00 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x02 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x03 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x04 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x05 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x06 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+{ 0xe, 0x01 }, { 0xf, 0x07 }, { WAIT_IDLE },
+{ 0xe, 0x02 }, { 0xf, 0x01 }, { WAIT_IDLE },
+
+{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x45 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x48 }, { 0xd, 0x0f }, { 0xc, 0xff }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7b }, { 0xd, 0x04 }, { 0xc, 0xcc }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7d }, { 0xd, 0x04 }, { 0xc, 0xcc }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x7e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x46 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x49 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x47 }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4a }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x00 }, { WAIT_IDLE },
+
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x00 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x00 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x01 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x01 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x02 }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x02 }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x03 }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x03 }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x04 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x04 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x05 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x05 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x06 }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x06 }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x07 }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x07 }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x08 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x08 }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x09 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x09 }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0a }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0a }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0b }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0b }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x00 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x28 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x51 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0x7a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xa3 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xcc },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0c }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0c }, { 0xc, 0xf5 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x1e },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x47 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x70 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0x99 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0xc2 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0d }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0d }, { 0xc, 0xeb },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x14 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x3d },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x66 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0x8f },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0xb8 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0e }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0e }, { 0xc, 0xe1 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x0a },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x33 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x5c },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0x85 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xae },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xd7 },
+{ 0xb, 0x07 }, { 0xa, 0x4c }, { 0xd, 0x0f }, { 0xc, 0xff },
+{ 0xb, 0x07 }, { 0xa, 0x4e }, { 0xd, 0x0f }, { 0xc, 0xff },
+
+/* mute off */
+{ 0x8, 0x00 }, { WAIT_IDLE }
+};
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
index 0ffa9970bf0..7cf9913a47b 100644
--- a/sound/oss/ad1848.c
+++ b/sound/oss/ad1848.c
@@ -1992,7 +1992,7 @@ int ad1848_init (char *name, struct resource *ports, int irq, int dma_playback,
devc->audio_flags |= DMA_DUPLEX;
}
- portc = (ad1848_port_info *) kmalloc(sizeof(ad1848_port_info), GFP_KERNEL);
+ portc = kmalloc(sizeof(ad1848_port_info), GFP_KERNEL);
if(portc==NULL) {
release_region(devc->base, 4);
return -1;
diff --git a/sound/oss/cs4232.c b/sound/oss/cs4232.c
index b6924c7f148..de40e21bf27 100644
--- a/sound/oss/cs4232.c
+++ b/sound/oss/cs4232.c
@@ -408,7 +408,7 @@ static int __init cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_
{
struct address_info *isapnpcfg;
- isapnpcfg=(struct address_info*)kmalloc(sizeof(*isapnpcfg),GFP_KERNEL);
+ isapnpcfg = kmalloc(sizeof(*isapnpcfg),GFP_KERNEL);
if (!isapnpcfg)
return -ENOMEM;
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index 87bd3100aef..80b836e80d9 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -1051,7 +1051,7 @@ static int sq_release(struct inode *inode, struct file *file)
if (file->f_mode & FMODE_WRITE) {
if (write_sq.busy)
- rc = sq_fsync(file, file->f_dentry);
+ rc = sq_fsync(file, file->f_path.dentry);
sq_reset_output() ; /* make sure dma is stopped and all is quiet */
write_sq_release_buffers();
@@ -1217,7 +1217,7 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
if ((file->f_mode & FMODE_READ) && dmasound.mach.record)
sq_reset_input() ;
if (file->f_mode & FMODE_WRITE) {
- result = sq_fsync(file, file->f_dentry);
+ result = sq_fsync(file, file->f_path.dentry);
sq_reset_output() ;
}
/* if we are the shared resource owner then release them */
diff --git a/sound/oss/dmasound/tas3001c.c b/sound/oss/dmasound/tas3001c.c
index f227c9f688c..2f21a3c0037 100644
--- a/sound/oss/dmasound/tas3001c.c
+++ b/sound/oss/dmasound/tas3001c.c
@@ -50,6 +50,7 @@ struct tas3001c_data_t {
int output_id;
int speaker_id;
struct tas_drce_t drce_state;
+ struct work_struct change;
};
@@ -667,14 +668,13 @@ tas3001c_update_device_parameters(struct tas3001c_data_t *self)
}
static void
-tas3001c_device_change_handler(void *self)
+tas3001c_device_change_handler(struct work_struct *work)
{
- if (self)
- tas3001c_update_device_parameters(self);
+ struct tas3001c_data_t *self;
+ self = container_of(work, struct tas3001c_data_t, change);
+ tas3001c_update_device_parameters(self);
}
-static struct work_struct device_change;
-
static int
tas3001c_output_device_change( struct tas3001c_data_t *self,
int device_id,
@@ -685,7 +685,7 @@ tas3001c_output_device_change( struct tas3001c_data_t *self,
self->output_id=output_id;
self->speaker_id=speaker_id;
- schedule_work(&device_change);
+ schedule_work(&self->change);
return 0;
}
@@ -823,7 +823,7 @@ tas3001c_init(struct i2c_client *client)
tas3001c_write_biquad_shadow(self, i, j,
&tas3001c_eq_unity);
- INIT_WORK(&device_change, tas3001c_device_change_handler, self);
+ INIT_WORK(&self->change, tas3001c_device_change_handler);
return 0;
}
diff --git a/sound/oss/dmasound/tas3004.c b/sound/oss/dmasound/tas3004.c
index 82eaaca2db9..af34fb39bc2 100644
--- a/sound/oss/dmasound/tas3004.c
+++ b/sound/oss/dmasound/tas3004.c
@@ -48,6 +48,7 @@ struct tas3004_data_t {
int output_id;
int speaker_id;
struct tas_drce_t drce_state;
+ struct work_struct change;
};
#define MAKE_TIME(sec,usec) (((sec)<<12) + (50000+(usec/10)*(1<<12))/100000)
@@ -914,15 +915,13 @@ tas3004_update_device_parameters(struct tas3004_data_t *self)
}
static void
-tas3004_device_change_handler(void *self)
+tas3004_device_change_handler(struct work_struct *work)
{
- if (!self) return;
-
- tas3004_update_device_parameters((struct tas3004_data_t *)self);
+ struct tas3004_data_t *self;
+ self = container_of(work, struct tas3004_data_t, change);
+ tas3004_update_device_parameters(self);
}
-static struct work_struct device_change;
-
static int
tas3004_output_device_change( struct tas3004_data_t *self,
int device_id,
@@ -933,7 +932,7 @@ tas3004_output_device_change( struct tas3004_data_t *self,
self->output_id=output_id;
self->speaker_id=speaker_id;
- schedule_work(&device_change);
+ schedule_work(&self->change);
return 0;
}
@@ -1112,7 +1111,7 @@ tas3004_init(struct i2c_client *client)
tas3004_write_register(self, TAS3004_REG_MCR2, &mcr2, WRITE_SHADOW);
tas3004_write_register(self, TAS3004_REG_DRC, drce_init, WRITE_SHADOW);
- INIT_WORK(&device_change, tas3004_device_change_handler, self);
+ INIT_WORK(&self->change, tas3004_device_change_handler);
return 0;
}
diff --git a/sound/oss/emu10k1/audio.c b/sound/oss/emu10k1/audio.c
index 49f902f35c2..efcf589d708 100644
--- a/sound/oss/emu10k1/audio.c
+++ b/sound/oss/emu10k1/audio.c
@@ -1139,7 +1139,7 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file)
match:
- wave_dev = (struct emu10k1_wavedevice *) kmalloc(sizeof(struct emu10k1_wavedevice), GFP_KERNEL);
+ wave_dev = kmalloc(sizeof(struct emu10k1_wavedevice), GFP_KERNEL);
if (wave_dev == NULL) {
ERROR();
@@ -1155,7 +1155,7 @@ match:
/* Recording */
struct wiinst *wiinst;
- if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) {
+ if ((wiinst = kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) {
ERROR();
kfree(wave_dev);
return -ENOMEM;
@@ -1211,7 +1211,7 @@ match:
struct woinst *woinst;
int i;
- if ((woinst = (struct woinst *) kmalloc(sizeof(struct woinst), GFP_KERNEL)) == NULL) {
+ if ((woinst = kmalloc(sizeof(struct woinst), GFP_KERNEL)) == NULL) {
ERROR();
kfree(wave_dev);
return -ENOMEM;
diff --git a/sound/oss/emu10k1/cardmi.c b/sound/oss/emu10k1/cardmi.c
index 0545814cc67..57674f8c8a2 100644
--- a/sound/oss/emu10k1/cardmi.c
+++ b/sound/oss/emu10k1/cardmi.c
@@ -157,7 +157,7 @@ int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *card_mpuin, struct midi_hdr *
midihdr->flags |= MIDIBUF_INQUEUE; /* set */
midihdr->flags &= ~MIDIBUF_DONE; /* clear */
- if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) {
+ if ((midiq = kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) {
/* Message lost */
return -1;
}
diff --git a/sound/oss/emu10k1/cardmo.c b/sound/oss/emu10k1/cardmo.c
index 5938d31f9e2..a8cc75db3e4 100644
--- a/sound/oss/emu10k1/cardmo.c
+++ b/sound/oss/emu10k1/cardmo.c
@@ -117,7 +117,7 @@ int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihd
midihdr->flags |= MIDIBUF_INQUEUE;
midihdr->flags &= ~MIDIBUF_DONE;
- if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) {
+ if ((midiq = kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) {
/* Message lost */
return -1;
}
diff --git a/sound/oss/emu10k1/midi.c b/sound/oss/emu10k1/midi.c
index 8ac77df8639..cca3dad2bdf 100644
--- a/sound/oss/emu10k1/midi.c
+++ b/sound/oss/emu10k1/midi.c
@@ -58,7 +58,7 @@ static int midiin_add_buffer(struct emu10k1_mididevice *midi_dev, struct midi_hd
{
struct midi_hdr *midihdr;
- if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL) {
+ if ((midihdr = kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL) {
ERROR();
return -EINVAL;
}
@@ -128,7 +128,7 @@ match:
mutex_lock(&card->open_sem);
}
- if ((midi_dev = (struct emu10k1_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL)
+ if ((midi_dev = kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL)
return -EINVAL;
midi_dev->card = card;
@@ -328,7 +328,7 @@ static ssize_t emu10k1_midi_write(struct file *file, const char __user *buffer,
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
- if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
+ if ((midihdr = kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
return -EINVAL;
midihdr->bufferlength = count;
@@ -490,7 +490,7 @@ int emu10k1_seq_midi_open(int dev, int mode,
DPF(2, "emu10k1_seq_midi_open()\n");
- if ((midi_dev = (struct emu10k1_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL)
+ if ((midi_dev = kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL)
return -EINVAL;
midi_dev->card = card;
@@ -540,7 +540,7 @@ int emu10k1_seq_midi_out(int dev, unsigned char midi_byte)
card = midi_devs[dev]->devc;
- if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
+ if ((midihdr = kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
return -EINVAL;
midihdr->bufferlength = 1;
diff --git a/sound/oss/emu10k1/mixer.c b/sound/oss/emu10k1/mixer.c
index cbcaaa34189..6419796c2ed 100644
--- a/sound/oss/emu10k1/mixer.c
+++ b/sound/oss/emu10k1/mixer.c
@@ -194,7 +194,7 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
case SOUND_MIXER_PRIVATE3:
- ctl = (struct mixer_private_ioctl *) kmalloc(sizeof(struct mixer_private_ioctl), GFP_KERNEL);
+ ctl = kmalloc(sizeof(struct mixer_private_ioctl), GFP_KERNEL);
if (ctl == NULL)
return -ENOMEM;
diff --git a/sound/oss/hal2.c b/sound/oss/hal2.c
index 784bdd70705..d18286ccc14 100644
--- a/sound/oss/hal2.c
+++ b/sound/oss/hal2.c
@@ -1435,7 +1435,7 @@ static int hal2_init_card(struct hal2_card **phal2, struct hpc3_regs *hpc3)
int ret = 0;
struct hal2_card *hal2;
- hal2 = (struct hal2_card *) kmalloc(sizeof(struct hal2_card), GFP_KERNEL);
+ hal2 = kmalloc(sizeof(struct hal2_card), GFP_KERNEL);
if (!hal2)
return -ENOMEM;
memset(hal2, 0, sizeof(struct hal2_card));
diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c
index e9622054197..2796c0ef985 100644
--- a/sound/oss/mpu401.c
+++ b/sound/oss/mpu401.c
@@ -1023,7 +1023,7 @@ int attach_mpu401(struct address_info *hw_config, struct module *owner)
devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */
- mpu401_synth_operations[m] = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
+ mpu401_synth_operations[m] = kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
if (mpu401_synth_operations[m] == NULL)
{
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index d5146790f5e..24110d63b13 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -1007,7 +1007,7 @@ static int dsp_write(const char __user *buf, size_t len)
static ssize_t dev_read(struct file *file, char __user *buf, size_t count, loff_t *off)
{
- int minor = iminor(file->f_dentry->d_inode);
+ int minor = iminor(file->f_path.dentry->d_inode);
if (minor == dev.dsp_minor)
return dsp_read(buf, count);
else
@@ -1016,7 +1016,7 @@ static ssize_t dev_read(struct file *file, char __user *buf, size_t count, loff_
static ssize_t dev_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
{
- int minor = iminor(file->f_dentry->d_inode);
+ int minor = iminor(file->f_path.dentry->d_inode);
if (minor == dev.dsp_minor)
return dsp_write(buf, count);
else
diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c
index 4799bc77f98..2e8cfa5481f 100644
--- a/sound/oss/opl3.c
+++ b/sound/oss/opl3.c
@@ -166,7 +166,7 @@ int opl3_detect(int ioaddr, int *osp)
return 0;
}
- devc = (struct opl_devinfo *)kmalloc(sizeof(*devc), GFP_KERNEL);
+ devc = kmalloc(sizeof(*devc), GFP_KERNEL);
if (devc == NULL)
{
diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c
index 440537c7260..07cbacf6382 100644
--- a/sound/oss/sb_common.c
+++ b/sound/oss/sb_common.c
@@ -625,7 +625,7 @@ int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_
*/
- detected_devc = (sb_devc *)kmalloc(sizeof(sb_devc), GFP_KERNEL);
+ detected_devc = kmalloc(sizeof(sb_devc), GFP_KERNEL);
if (detected_devc == NULL)
{
printk(KERN_ERR "sb: Can't allocate memory for device information\n");
diff --git a/sound/oss/sb_midi.c b/sound/oss/sb_midi.c
index 2e3bc045cab..8b796704e11 100644
--- a/sound/oss/sb_midi.c
+++ b/sound/oss/sb_midi.c
@@ -173,7 +173,7 @@ void sb_dsp_midi_init(sb_devc * devc, struct module *owner)
return;
}
std_midi_synth.midi_dev = devc->my_mididev = dev;
- midi_devs[dev] = (struct midi_operations *)kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
+ midi_devs[dev] = kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
if (midi_devs[dev] == NULL)
{
printk(KERN_WARNING "Sound Blaster: failed to allocate MIDI memory.\n");
@@ -189,7 +189,7 @@ void sb_dsp_midi_init(sb_devc * devc, struct module *owner)
midi_devs[dev]->devc = devc;
- midi_devs[dev]->converter = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
+ midi_devs[dev]->converter = kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
if (midi_devs[dev]->converter == NULL)
{
printk(KERN_WARNING "Sound Blaster: failed to allocate MIDI memory.\n");
diff --git a/sound/oss/sb_mixer.c b/sound/oss/sb_mixer.c
index 238e2cf44b0..fad1a4f25ad 100644
--- a/sound/oss/sb_mixer.c
+++ b/sound/oss/sb_mixer.c
@@ -734,7 +734,7 @@ int sb_mixer_init(sb_devc * devc, struct module *owner)
if (m == -1)
return 0;
- mixer_devs[m] = (struct mixer_operations *)kmalloc(sizeof(struct mixer_operations), GFP_KERNEL);
+ mixer_devs[m] = kmalloc(sizeof(struct mixer_operations), GFP_KERNEL);
if (mixer_devs[m] == NULL)
{
printk(KERN_ERR "sb_mixer: Can't allocate memory\n");
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index 8fb8e7f9955..a89108cb74e 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -141,7 +141,7 @@ static int get_mixer_levels(void __user * arg)
static ssize_t sound_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
int ret = -EINVAL;
/*
@@ -174,7 +174,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
static ssize_t sound_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
int ret = -EINVAL;
lock_kernel();
@@ -393,7 +393,7 @@ static int sound_ioctl(struct inode *inode, struct file *file,
static unsigned int sound_poll(struct file *file, poll_table * wait)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int dev = iminor(inode);
DEB(printk("sound_poll(dev=%d)\n", dev));
@@ -418,7 +418,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
int dev_class;
unsigned long size;
struct dma_buffparms *dmap = NULL;
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
dev_class = dev & 0x0f;
dev >>= 4;
diff --git a/sound/oss/v_midi.c b/sound/oss/v_midi.c
index d952b2264da..103940fd5b4 100644
--- a/sound/oss/v_midi.c
+++ b/sound/oss/v_midi.c
@@ -183,7 +183,7 @@ static void __init attach_v_midi (struct address_info *hw_config)
return;
}
- m=(struct vmidi_memory *)kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL);
+ m = kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL);
if (m == NULL)
{
printk(KERN_WARNING "Loopback MIDI: Failed to allocate memory\n");
diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c
index c5bf363d32c..26a7c6af95b 100644
--- a/sound/oss/waveartist.c
+++ b/sound/oss/waveartist.c
@@ -1267,7 +1267,7 @@ static int __init waveartist_init(wavnc_info *devc)
conf_printf2(dev_name, devc->hw.io_base, devc->hw.irq,
devc->hw.dma, devc->hw.dma2);
- portc = (wavnc_port_info *)kmalloc(sizeof(wavnc_port_info), GFP_KERNEL);
+ portc = kmalloc(sizeof(wavnc_port_info), GFP_KERNEL);
if (portc == NULL)
goto nomem;
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 8a6b1803c76..1bcfb3aac18 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -236,7 +236,7 @@ config SND_CS5535AUDIO
config SND_DARLA20
tristate "(Echoaudio) Darla20"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Darla.
@@ -247,7 +247,7 @@ config SND_DARLA20
config SND_GINA20
tristate "(Echoaudio) Gina20"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Gina.
@@ -258,7 +258,7 @@ config SND_GINA20
config SND_LAYLA20
tristate "(Echoaudio) Layla20"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@@ -270,7 +270,7 @@ config SND_LAYLA20
config SND_DARLA24
tristate "(Echoaudio) Darla24"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Darla24.
@@ -281,7 +281,7 @@ config SND_DARLA24
config SND_GINA24
tristate "(Echoaudio) Gina24"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Gina24.
@@ -292,7 +292,7 @@ config SND_GINA24
config SND_LAYLA24
tristate "(Echoaudio) Layla24"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@@ -304,7 +304,7 @@ config SND_LAYLA24
config SND_MONA
tristate "(Echoaudio) Mona"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@@ -316,7 +316,7 @@ config SND_MONA
config SND_MIA
tristate "(Echoaudio) Mia"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@@ -328,7 +328,7 @@ config SND_MIA
config SND_ECHO3G
tristate "(Echoaudio) 3G cards"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_RAWMIDI
select SND_PCM
help
@@ -340,7 +340,7 @@ config SND_ECHO3G
config SND_INDIGO
tristate "(Echoaudio) Indigo"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Indigo.
@@ -351,7 +351,7 @@ config SND_INDIGO
config SND_INDIGOIO
tristate "(Echoaudio) Indigo IO"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Indigo IO.
@@ -362,7 +362,7 @@ config SND_INDIGOIO
config SND_INDIGODJ
tristate "(Echoaudio) Indigo DJ"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_PCM
help
Say 'Y' or 'M' to include support for Echoaudio Indigo DJ.
@@ -373,6 +373,7 @@ config SND_INDIGODJ
config SND_EMU10K1
tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)"
depends on SND
+ select FW_LOADER
select SND_HWDEP
select SND_RAWMIDI
select SND_AC97_CODEC
@@ -575,6 +576,7 @@ config SND_INTEL8X0M
config SND_KORG1212
tristate "Korg 1212 IO"
depends on SND
+ select FW_LOADER
select SND_PCM
help
Say Y here to include support for Korg 1212IO soundcards.
@@ -585,6 +587,7 @@ config SND_KORG1212
config SND_MAESTRO3
tristate "ESS Allegro/Maestro3"
depends on SND
+ select FW_LOADER
select SND_AC97_CODEC
help
Say Y here to include support for soundcards based on ESS Maestro 3
@@ -629,7 +632,7 @@ config SND_PCXHR
config SND_RIPTIDE
tristate "Conexant Riptide"
depends on SND
- depends on FW_LOADER
+ select FW_LOADER
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
@@ -734,6 +737,7 @@ config SND_VX222
config SND_YMFPCI
tristate "Yamaha YMF724/740/744/754"
depends on SND
+ select FW_LOADER
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
diff --git a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile
index 77b3482cb13..3c3222122d8 100644
--- a/sound/pci/ac97/Makefile
+++ b/sound/pci/ac97/Makefile
@@ -10,11 +10,9 @@ snd-ac97-codec-objs += ac97_proc.o
endif
snd-ak4531-codec-objs := ak4531_codec.o
-snd-ac97-bus-objs := ac97_bus.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o
obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o
-obj-$(CONFIG_SND_AC97_BUS) += snd-ac97-bus.o
obj-m := $(sort $(obj-m))
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 7abcb10b275..74ed8108147 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -111,7 +111,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL },
{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL },
{ 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL },
-{ 0x41445378, 0xffffffff, "AD1986", patch_ad1985, NULL },
+{ 0x41445378, 0xffffffff, "AD1986", patch_ad1986, NULL },
{ 0x414c4300, 0xffffff00, "ALC100,100P", NULL, NULL },
{ 0x414c4710, 0xfffffff0, "ALC200,200P", NULL, NULL },
{ 0x414c4721, 0xffffffff, "ALC650D", NULL, NULL }, /* already patched */
@@ -129,9 +129,9 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
{ 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL },
{ 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL },
{ 0x434d4969, 0xffffffff, "CMI9780", patch_cm9780, NULL },
-{ 0x434d4978, 0xffffffff, "CMI9761", patch_cm9761, NULL },
-{ 0x434d4982, 0xffffffff, "CMI9761", patch_cm9761, NULL },
-{ 0x434d4983, 0xffffffff, "CMI9761", patch_cm9761, NULL },
+{ 0x434d4978, 0xffffffff, "CMI9761A", patch_cm9761, NULL },
+{ 0x434d4982, 0xffffffff, "CMI9761B", patch_cm9761, NULL },
+{ 0x434d4983, 0xffffffff, "CMI9761A+", patch_cm9761, NULL },
{ 0x43525900, 0xfffffff8, "CS4297", NULL, NULL },
{ 0x43525910, 0xfffffff8, "CS4297A", patch_cirrus_spdif, NULL },
{ 0x43525920, 0xfffffff8, "CS4298", patch_cirrus_spdif, NULL },
@@ -194,6 +194,13 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
static void update_power_regs(struct snd_ac97 *ac97);
+#ifdef CONFIG_SND_AC97_POWER_SAVE
+#define ac97_is_power_save_mode(ac97) \
+ ((ac97->scaps & AC97_SCAP_POWER_SAVE) && power_save)
+#else
+#define ac97_is_power_save_mode(ac97) 0
+#endif
+
/*
* I/O routines
@@ -382,7 +389,7 @@ int snd_ac97_update_bits_nolock(struct snd_ac97 *ac97, unsigned short reg,
unsigned short old, new;
old = snd_ac97_read_cache(ac97, reg);
- new = (old & ~mask) | value;
+ new = (old & ~mask) | (value & mask);
change = old != new;
if (change) {
ac97->regs[reg] = new;
@@ -399,7 +406,7 @@ static int snd_ac97_ad18xx_update_pcm_bits(struct snd_ac97 *ac97, int codec, uns
mutex_lock(&ac97->page_mutex);
old = ac97->spec.ad18xx.pcmreg[codec];
- new = (old & ~mask) | value;
+ new = (old & ~mask) | (value & mask);
change = old != new;
if (change) {
mutex_lock(&ac97->reg_mutex);
@@ -982,8 +989,8 @@ static int snd_ac97_free(struct snd_ac97 *ac97)
{
if (ac97) {
#ifdef CONFIG_SND_AC97_POWER_SAVE
- if (ac97->power_workq)
- destroy_workqueue(ac97->power_workq);
+ cancel_delayed_work(&ac97->power_work);
+ flush_scheduled_work();
#endif
snd_ac97_proc_done(ac97);
if (ac97->bus)
@@ -1184,13 +1191,13 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
/*
* set dB information
*/
-static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
-static unsigned int *find_db_scale(unsigned int maxval)
+static const unsigned int *find_db_scale(unsigned int maxval)
{
switch (maxval) {
case 0x0f: return db_scale_4bit;
@@ -1200,8 +1207,8 @@ static unsigned int *find_db_scale(unsigned int maxval)
return NULL;
}
-static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv)
-{
+static void set_tlv_db_scale(struct snd_kcontrol *kctl, const unsigned int *tlv)
+{
kctl->tlv.p = tlv;
if (tlv)
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
@@ -1989,7 +1996,6 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
mutex_init(&ac97->reg_mutex);
mutex_init(&ac97->page_mutex);
#ifdef CONFIG_SND_AC97_POWER_SAVE
- ac97->power_workq = create_workqueue("ac97");
INIT_DELAYED_WORK(&ac97->power_work, do_update_power);
#endif
@@ -2275,15 +2281,13 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97)
udelay(100);
power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */
snd_ac97_write(ac97, AC97_POWERDOWN, power);
-#ifdef CONFIG_SND_AC97_POWER_SAVE
- if (power_save) {
+ if (ac97_is_power_save_mode(ac97)) {
udelay(100);
/* AC-link powerdown, internal Clk disable */
/* FIXME: this may cause click noises on some boards */
power |= AC97_PD_PR4 | AC97_PD_PR5;
snd_ac97_write(ac97, AC97_POWERDOWN, power);
}
-#endif
}
@@ -2337,14 +2341,16 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
}
}
- if (power_save && !powerup && ac97->power_workq)
+ if (ac97_is_power_save_mode(ac97) && !powerup)
/* adjust power-down bits after two seconds delay
* (for avoiding loud click noises for many (OSS) apps
* that open/close frequently)
*/
- queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2);
- else
+ schedule_delayed_work(&ac97->power_work, HZ*2);
+ else {
+ cancel_delayed_work(&ac97->power_work);
update_power_regs(ac97);
+ }
return 0;
}
@@ -2357,19 +2363,15 @@ static void update_power_regs(struct snd_ac97 *ac97)
unsigned int power_up, bits;
int i;
+ power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
+ power_up |= (1 << PWIDX_MIC);
+ if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
+ power_up |= (1 << PWIDX_SURR);
+ if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
+ power_up |= (1 << PWIDX_CLFE);
#ifdef CONFIG_SND_AC97_POWER_SAVE
- if (power_save)
+ if (ac97_is_power_save_mode(ac97))
power_up = ac97->power_up;
- else {
-#endif
- power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC);
- power_up |= (1 << PWIDX_MIC);
- if (ac97->scaps & AC97_SCAP_SURROUND_DAC)
- power_up |= (1 << PWIDX_SURR);
- if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)
- power_up |= (1 << PWIDX_CLFE);
-#ifdef CONFIG_SND_AC97_POWER_SAVE
- }
#endif
if (power_up) {
if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) {
@@ -2414,6 +2416,10 @@ void snd_ac97_suspend(struct snd_ac97 *ac97)
return;
if (ac97->build_ops->suspend)
ac97->build_ops->suspend(ac97);
+#ifdef CONFIG_SND_AC97_POWER_SAVE
+ cancel_delayed_work(&ac97->power_work);
+ flush_scheduled_work();
+#endif
snd_ac97_powerdown(ac97);
}
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 15be6ba87c8..641d0c8d659 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -54,7 +54,7 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro
/* replace with a new TLV */
static void reset_tlv(struct snd_ac97 *ac97, const char *name,
- unsigned int *tlv)
+ const unsigned int *tlv)
{
struct snd_ctl_elem_id sid;
struct snd_kcontrol *kctl;
@@ -190,14 +190,28 @@ static inline int is_clfe_on(struct snd_ac97 *ac97)
return ac97->channel_mode >= 2;
}
+/* system has shared jacks with surround out enabled */
+static inline int is_shared_surrout(struct snd_ac97 *ac97)
+{
+ return !ac97->indep_surround && is_surround_on(ac97);
+}
+
+/* system has shared jacks with center/lfe out enabled */
+static inline int is_shared_clfeout(struct snd_ac97 *ac97)
+{
+ return !ac97->indep_surround && is_clfe_on(ac97);
+}
+
+/* system has shared jacks with line in enabled */
static inline int is_shared_linein(struct snd_ac97 *ac97)
{
- return ! ac97->indep_surround && is_surround_on(ac97);
+ return !ac97->indep_surround && !is_surround_on(ac97);
}
+/* system has shared jacks with mic in enabled */
static inline int is_shared_micin(struct snd_ac97 *ac97)
{
- return ! ac97->indep_surround && is_clfe_on(ac97);
+ return !ac97->indep_surround && !is_clfe_on(ac97);
}
@@ -941,6 +955,9 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97)
{
int err;
+ /* the register bit is writable, but the function is not implemented: */
+ snd_ac97_remove_ctl(ac97, "PCM Out Path & Mute", NULL);
+
snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback");
if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0)
return err;
@@ -1467,7 +1484,9 @@ static void patch_ad1881_chained(struct snd_ac97 * ac97, int unchained_idx, int
snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0002); // ID1C
ac97->spec.ad18xx.codec_cfg[unchained_idx] = 0x0002;
if (cidx1 >= 0) {
- if (patch_ad1881_chained1(ac97, cidx1, 0x0006)) // SDIE | ID1C
+ if (cidx2 < 0)
+ patch_ad1881_chained1(ac97, cidx1, 0);
+ else if (patch_ad1881_chained1(ac97, cidx1, 0x0006)) // SDIE | ID1C
patch_ad1881_chained1(ac97, cidx2, 0);
else if (patch_ad1881_chained1(ac97, cidx2, 0x0006)) // SDIE | ID1C
patch_ad1881_chained1(ac97, cidx1, 0);
@@ -1550,7 +1569,7 @@ static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = {
AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */
};
-static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0);
static int patch_ad1885_specific(struct snd_ac97 * ac97)
{
@@ -1607,19 +1626,22 @@ int patch_ad1886(struct snd_ac97 * ac97)
return 0;
}
-/* MISC bits */
+/* MISC bits (AD1888/AD1980/AD1985 register 0x76) */
#define AC97_AD198X_MBC 0x0003 /* mic boost */
#define AC97_AD198X_MBC_20 0x0000 /* +20dB */
#define AC97_AD198X_MBC_10 0x0001 /* +10dB */
#define AC97_AD198X_MBC_30 0x0002 /* +30dB */
#define AC97_AD198X_VREFD 0x0004 /* VREF high-Z */
-#define AC97_AD198X_VREFH 0x0008 /* 2.25V, 3.7V */
-#define AC97_AD198X_VREF_0 0x000c /* 0V */
+#define AC97_AD198X_VREFH 0x0008 /* 0=2.25V, 1=3.7V */
+#define AC97_AD198X_VREF_0 0x000c /* 0V (AD1985 only) */
+#define AC97_AD198X_VREF_MASK (AC97_AD198X_VREFH | AC97_AD198X_VREFD)
+#define AC97_AD198X_VREF_SHIFT 2
#define AC97_AD198X_SRU 0x0010 /* sample rate unlock */
#define AC97_AD198X_LOSEL 0x0020 /* LINE_OUT amplifiers input select */
#define AC97_AD198X_2MIC 0x0040 /* 2-channel mic select */
#define AC97_AD198X_SPRD 0x0080 /* SPREAD enable */
-#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: 0 = 6-to-4, 1 = 6-to-2 downmix */
+#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: */
+ /* 0 = 6-to-4, 1 = 6-to-2 downmix */
#define AC97_AD198X_DMIX1 0x0200 /* downmix mode: 1 = enabled */
#define AC97_AD198X_HPSEL 0x0400 /* headphone amplifier input select */
#define AC97_AD198X_CLDIS 0x0800 /* center/lfe disable */
@@ -1628,6 +1650,83 @@ int patch_ad1886(struct snd_ac97 * ac97)
#define AC97_AD198X_AC97NC 0x4000 /* AC97 no compatible mode */
#define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */
+/* MISC 1 bits (AD1986 register 0x76) */
+#define AC97_AD1986_MBC 0x0003 /* mic boost */
+#define AC97_AD1986_MBC_20 0x0000 /* +20dB */
+#define AC97_AD1986_MBC_10 0x0001 /* +10dB */
+#define AC97_AD1986_MBC_30 0x0002 /* +30dB */
+#define AC97_AD1986_LISEL0 0x0004 /* LINE_IN select bit 0 */
+#define AC97_AD1986_LISEL1 0x0008 /* LINE_IN select bit 1 */
+#define AC97_AD1986_LISEL_MASK (AC97_AD1986_LISEL1 | AC97_AD1986_LISEL0)
+#define AC97_AD1986_LISEL_LI 0x0000 /* LINE_IN pins as LINE_IN source */
+#define AC97_AD1986_LISEL_SURR 0x0004 /* SURROUND pins as LINE_IN source */
+#define AC97_AD1986_LISEL_MIC 0x0008 /* MIC_1/2 pins as LINE_IN source */
+#define AC97_AD1986_SRU 0x0010 /* sample rate unlock */
+#define AC97_AD1986_SOSEL 0x0020 /* SURROUND_OUT amplifiers input sel */
+#define AC97_AD1986_2MIC 0x0040 /* 2-channel mic select */
+#define AC97_AD1986_SPRD 0x0080 /* SPREAD enable */
+#define AC97_AD1986_DMIX0 0x0100 /* downmix mode: */
+ /* 0 = 6-to-4, 1 = 6-to-2 downmix */
+#define AC97_AD1986_DMIX1 0x0200 /* downmix mode: 1 = enabled */
+#define AC97_AD1986_CLDIS 0x0800 /* center/lfe disable */
+#define AC97_AD1986_SODIS 0x1000 /* SURROUND_OUT disable */
+#define AC97_AD1986_MSPLT 0x2000 /* mute split (read only 1) */
+#define AC97_AD1986_AC97NC 0x4000 /* AC97 no compatible mode (r/o 1) */
+#define AC97_AD1986_DACZ 0x8000 /* DAC zero-fill mode */
+
+/* MISC 2 bits (AD1986 register 0x70) */
+#define AC97_AD_MISC2 0x70 /* Misc Control Bits 2 (AD1986) */
+
+#define AC97_AD1986_CVREF0 0x0004 /* C/LFE VREF_OUT 2.25V */
+#define AC97_AD1986_CVREF1 0x0008 /* C/LFE VREF_OUT 0V */
+#define AC97_AD1986_CVREF2 0x0010 /* C/LFE VREF_OUT 3.7V */
+#define AC97_AD1986_CVREF_MASK \
+ (AC97_AD1986_CVREF2 | AC97_AD1986_CVREF1 | AC97_AD1986_CVREF0)
+#define AC97_AD1986_JSMAP 0x0020 /* Jack Sense Mapping 1 = alternate */
+#define AC97_AD1986_MMDIS 0x0080 /* Mono Mute Disable */
+#define AC97_AD1986_MVREF0 0x0400 /* MIC VREF_OUT 2.25V */
+#define AC97_AD1986_MVREF1 0x0800 /* MIC VREF_OUT 0V */
+#define AC97_AD1986_MVREF2 0x1000 /* MIC VREF_OUT 3.7V */
+#define AC97_AD1986_MVREF_MASK \
+ (AC97_AD1986_MVREF2 | AC97_AD1986_MVREF1 | AC97_AD1986_MVREF0)
+
+/* MISC 3 bits (AD1986 register 0x7a) */
+#define AC97_AD_MISC3 0x7a /* Misc Control Bits 3 (AD1986) */
+
+#define AC97_AD1986_MMIX 0x0004 /* Mic Mix, left/right */
+#define AC97_AD1986_GPO 0x0008 /* General Purpose Out */
+#define AC97_AD1986_LOHPEN 0x0010 /* LINE_OUT headphone drive */
+#define AC97_AD1986_LVREF0 0x0100 /* LINE_OUT VREF_OUT 2.25V */
+#define AC97_AD1986_LVREF1 0x0200 /* LINE_OUT VREF_OUT 0V */
+#define AC97_AD1986_LVREF2 0x0400 /* LINE_OUT VREF_OUT 3.7V */
+#define AC97_AD1986_LVREF_MASK \
+ (AC97_AD1986_LVREF2 | AC97_AD1986_LVREF1 | AC97_AD1986_LVREF0)
+#define AC97_AD1986_JSINVA 0x0800 /* Jack Sense Invert SENSE_A */
+#define AC97_AD1986_LOSEL 0x1000 /* LINE_OUT amplifiers input select */
+#define AC97_AD1986_HPSEL0 0x2000 /* Headphone amplifiers */
+ /* input select Surround DACs */
+#define AC97_AD1986_HPSEL1 0x4000 /* Headphone amplifiers input */
+ /* select C/LFE DACs */
+#define AC97_AD1986_JSINVB 0x8000 /* Jack Sense Invert SENSE_B */
+
+/* Serial Config bits (AD1986 register 0x74) (incomplete) */
+#define AC97_AD1986_OMS0 0x0100 /* Optional Mic Selector bit 0 */
+#define AC97_AD1986_OMS1 0x0200 /* Optional Mic Selector bit 1 */
+#define AC97_AD1986_OMS2 0x0400 /* Optional Mic Selector bit 2 */
+#define AC97_AD1986_OMS_MASK \
+ (AC97_AD1986_OMS2 | AC97_AD1986_OMS1 | AC97_AD1986_OMS0)
+#define AC97_AD1986_OMS_M 0x0000 /* MIC_1/2 pins are MIC sources */
+#define AC97_AD1986_OMS_L 0x0100 /* LINE_IN pins are MIC sources */
+#define AC97_AD1986_OMS_C 0x0200 /* Center/LFE pins are MCI sources */
+#define AC97_AD1986_OMS_MC 0x0400 /* Mix of MIC and C/LFE pins */
+ /* are MIC sources */
+#define AC97_AD1986_OMS_ML 0x0500 /* MIX of MIC and LINE_IN pins */
+ /* are MIC sources */
+#define AC97_AD1986_OMS_LC 0x0600 /* MIX of LINE_IN and C/LFE pins */
+ /* are MIC sources */
+#define AC97_AD1986_OMS_MLC 0x0700 /* MIX of MIC, LINE_IN, C/LFE pins */
+ /* are MIC sources */
+
static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
@@ -1950,8 +2049,80 @@ int patch_ad1980(struct snd_ac97 * ac97)
return 0;
}
+static int snd_ac97_ad1985_vrefout_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[4] = {"High-Z", "3.7 V", "2.25 V", "0 V"};
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 4;
+ if (uinfo->value.enumerated.item > 3)
+ uinfo->value.enumerated.item = 3;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_ac97_ad1985_vrefout_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ static const int reg2ctrl[4] = {2, 0, 1, 3};
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short val;
+ val = (ac97->regs[AC97_AD_MISC] & AC97_AD198X_VREF_MASK)
+ >> AC97_AD198X_VREF_SHIFT;
+ ucontrol->value.enumerated.item[0] = reg2ctrl[val];
+ return 0;
+}
+
+static int snd_ac97_ad1985_vrefout_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ static const int ctrl2reg[4] = {1, 2, 0, 3};
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short val;
+
+ if (ucontrol->value.enumerated.item[0] > 3
+ || ucontrol->value.enumerated.item[0] < 0)
+ return -EINVAL;
+ val = ctrl2reg[ucontrol->value.enumerated.item[0]]
+ << AC97_AD198X_VREF_SHIFT;
+ return snd_ac97_update_bits(ac97, AC97_AD_MISC,
+ AC97_AD198X_VREF_MASK, val);
+}
+
static const struct snd_kcontrol_new snd_ac97_ad1985_controls[] = {
- AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0)
+ AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Exchange Front/Surround",
+ .info = snd_ac97_ad1888_lohpsel_info,
+ .get = snd_ac97_ad1888_lohpsel_get,
+ .put = snd_ac97_ad1888_lohpsel_put
+ },
+ AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
+ AC97_SINGLE("Spread Front to Surround and Center/LFE",
+ AC97_AD_MISC, 7, 1, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Downmix",
+ .info = snd_ac97_ad1888_downmix_info,
+ .get = snd_ac97_ad1888_downmix_get,
+ .put = snd_ac97_ad1888_downmix_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "V_REFOUT",
+ .info = snd_ac97_ad1985_vrefout_info,
+ .get = snd_ac97_ad1985_vrefout_get,
+ .put = snd_ac97_ad1985_vrefout_put
+ },
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
+
+ AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
+ AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0),
};
static void ad1985_update_jacks(struct snd_ac97 *ac97)
@@ -1965,9 +2136,16 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97)
{
int err;
- if ((err = patch_ad1980_specific(ac97)) < 0)
+ /* rename 0x04 as "Master" and 0x02 as "Master Surround" */
+ snd_ac97_rename_vol_ctl(ac97, "Master Playback",
+ "Master Surround Playback");
+ snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
+
+ if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
return err;
- return patch_build_controls(ac97, snd_ac97_ad1985_controls, ARRAY_SIZE(snd_ac97_ad1985_controls));
+
+ return patch_build_controls(ac97, snd_ac97_ad1985_controls,
+ ARRAY_SIZE(snd_ac97_ad1985_controls));
}
static struct snd_ac97_build_ops patch_ad1985_build_ops = {
@@ -1987,24 +2165,311 @@ int patch_ad1985(struct snd_ac97 * ac97)
ac97->build_ops = &patch_ad1985_build_ops;
misc = snd_ac97_read(ac97, AC97_AD_MISC);
/* switch front/surround line-out/hp-out */
- /* center/LFE, mic in 3.75V mode */
/* AD-compatible mode */
/* Stereo mutes enabled */
- /* in accordance with ADI driver: misc | 0x5c28 */
snd_ac97_write_cache(ac97, AC97_AD_MISC, misc |
- AC97_AD198X_VREFH |
AC97_AD198X_LOSEL |
AC97_AD198X_HPSEL |
- AC97_AD198X_CLDIS |
- AC97_AD198X_LODIS |
AC97_AD198X_MSPLT |
AC97_AD198X_AC97NC);
ac97->flags |= AC97_STEREO_MUTES;
+
+ /* update current jack configuration */
+ ad1985_update_jacks(ac97);
+
/* on AD1985 rev. 3, AC'97 revision bits are zero */
ac97->ext_id = (ac97->ext_id & ~AC97_EI_REV_MASK) | AC97_EI_REV_23;
return 0;
}
+static int snd_ac97_ad1986_bool_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short val;
+
+ val = ac97->regs[AC97_AD_MISC3];
+ ucontrol->value.integer.value[0] = (val & AC97_AD1986_LOSEL) != 0;
+ return 0;
+}
+
+static int snd_ac97_ad1986_lososel_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ int ret0;
+ int ret1;
+ int sprd = (ac97->regs[AC97_AD_MISC] & AC97_AD1986_SPRD) != 0;
+
+ ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC3, AC97_AD1986_LOSEL,
+ ucontrol->value.integer.value[0] != 0
+ ? AC97_AD1986_LOSEL : 0);
+ if (ret0 < 0)
+ return ret0;
+
+ /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
+ ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
+ (ucontrol->value.integer.value[0] != 0
+ || sprd)
+ ? AC97_AD1986_SOSEL : 0);
+ if (ret1 < 0)
+ return ret1;
+
+ return (ret0 > 0 || ret1 > 0) ? 1 : 0;
+}
+
+static int snd_ac97_ad1986_spread_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short val;
+
+ val = ac97->regs[AC97_AD_MISC];
+ ucontrol->value.integer.value[0] = (val & AC97_AD1986_SPRD) != 0;
+ return 0;
+}
+
+static int snd_ac97_ad1986_spread_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ int ret0;
+ int ret1;
+ int sprd = (ac97->regs[AC97_AD_MISC3] & AC97_AD1986_LOSEL) != 0;
+
+ ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SPRD,
+ ucontrol->value.integer.value[0] != 0
+ ? AC97_AD1986_SPRD : 0);
+ if (ret0 < 0)
+ return ret0;
+
+ /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
+ ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
+ (ucontrol->value.integer.value[0] != 0
+ || sprd)
+ ? AC97_AD1986_SOSEL : 0);
+ if (ret1 < 0)
+ return ret1;
+
+ return (ret0 > 0 || ret1 > 0) ? 1 : 0;
+}
+
+static int snd_ac97_ad1986_miclisel_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = ac97->spec.ad18xx.swap_mic_linein;
+ return 0;
+}
+
+static int snd_ac97_ad1986_miclisel_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned char swap = ucontrol->value.integer.value[0] != 0;
+
+ if (swap != ac97->spec.ad18xx.swap_mic_linein) {
+ ac97->spec.ad18xx.swap_mic_linein = swap;
+ if (ac97->build_ops->update_jacks)
+ ac97->build_ops->update_jacks(ac97);
+ return 1;
+ }
+ return 0;
+}
+
+static int snd_ac97_ad1986_vrefout_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* Use MIC_1/2 V_REFOUT as the "get" value */
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short val;
+ unsigned short reg = ac97->regs[AC97_AD_MISC2];
+ if ((reg & AC97_AD1986_MVREF0) != 0)
+ val = 2;
+ else if ((reg & AC97_AD1986_MVREF1) != 0)
+ val = 3;
+ else if ((reg & AC97_AD1986_MVREF2) != 0)
+ val = 1;
+ else
+ val = 0;
+ ucontrol->value.enumerated.item[0] = val;
+ return 0;
+}
+
+static int snd_ac97_ad1986_vrefout_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned short cval;
+ unsigned short lval;
+ unsigned short mval;
+ int cret;
+ int lret;
+ int mret;
+
+ switch (ucontrol->value.enumerated.item[0])
+ {
+ case 0: /* High-Z */
+ cval = 0;
+ lval = 0;
+ mval = 0;
+ break;
+ case 1: /* 3.7 V */
+ cval = AC97_AD1986_CVREF2;
+ lval = AC97_AD1986_LVREF2;
+ mval = AC97_AD1986_MVREF2;
+ break;
+ case 2: /* 2.25 V */
+ cval = AC97_AD1986_CVREF0;
+ lval = AC97_AD1986_LVREF0;
+ mval = AC97_AD1986_MVREF0;
+ break;
+ case 3: /* 0 V */
+ cval = AC97_AD1986_CVREF1;
+ lval = AC97_AD1986_LVREF1;
+ mval = AC97_AD1986_MVREF1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ cret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
+ AC97_AD1986_CVREF_MASK, cval);
+ if (cret < 0)
+ return cret;
+ lret = snd_ac97_update_bits(ac97, AC97_AD_MISC3,
+ AC97_AD1986_LVREF_MASK, lval);
+ if (lret < 0)
+ return lret;
+ mret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
+ AC97_AD1986_MVREF_MASK, mval);
+ if (mret < 0)
+ return mret;
+
+ return (cret > 0 || lret > 0 || mret > 0) ? 1 : 0;
+}
+
+static const struct snd_kcontrol_new snd_ac97_ad1986_controls[] = {
+ AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Exchange Front/Surround",
+ .info = snd_ac97_ad1986_bool_info,
+ .get = snd_ac97_ad1986_lososel_get,
+ .put = snd_ac97_ad1986_lososel_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Exchange Mic/Line In",
+ .info = snd_ac97_ad1986_bool_info,
+ .get = snd_ac97_ad1986_miclisel_get,
+ .put = snd_ac97_ad1986_miclisel_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Spread Front to Surround and Center/LFE",
+ .info = snd_ac97_ad1986_bool_info,
+ .get = snd_ac97_ad1986_spread_get,
+ .put = snd_ac97_ad1986_spread_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Downmix",
+ .info = snd_ac97_ad1888_downmix_info,
+ .get = snd_ac97_ad1888_downmix_get,
+ .put = snd_ac97_ad1888_downmix_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "V_REFOUT",
+ .info = snd_ac97_ad1985_vrefout_info,
+ .get = snd_ac97_ad1986_vrefout_get,
+ .put = snd_ac97_ad1986_vrefout_put
+ },
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
+
+ AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
+ AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0)
+};
+
+static void ad1986_update_jacks(struct snd_ac97 *ac97)
+{
+ unsigned short misc_val = 0;
+ unsigned short ser_val;
+
+ /* disable SURROUND and CENTER/LFE if not surround mode */
+ if (! is_surround_on(ac97))
+ misc_val |= AC97_AD1986_SODIS;
+ if (! is_clfe_on(ac97))
+ misc_val |= AC97_AD1986_CLDIS;
+
+ /* select line input (default=LINE_IN, SURROUND or MIC_1/2) */
+ if (is_shared_linein(ac97))
+ misc_val |= AC97_AD1986_LISEL_SURR;
+ else if (ac97->spec.ad18xx.swap_mic_linein != 0)
+ misc_val |= AC97_AD1986_LISEL_MIC;
+ snd_ac97_update_bits(ac97, AC97_AD_MISC,
+ AC97_AD1986_SODIS | AC97_AD1986_CLDIS |
+ AC97_AD1986_LISEL_MASK,
+ misc_val);
+
+ /* select microphone input (MIC_1/2, Center/LFE or LINE_IN) */
+ if (is_shared_micin(ac97))
+ ser_val = AC97_AD1986_OMS_C;
+ else if (ac97->spec.ad18xx.swap_mic_linein != 0)
+ ser_val = AC97_AD1986_OMS_L;
+ else
+ ser_val = AC97_AD1986_OMS_M;
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG,
+ AC97_AD1986_OMS_MASK,
+ ser_val);
+}
+
+static int patch_ad1986_specific(struct snd_ac97 *ac97)
+{
+ int err;
+
+ if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
+ return err;
+
+ return patch_build_controls(ac97, snd_ac97_ad1986_controls,
+ ARRAY_SIZE(snd_ac97_ad1985_controls));
+}
+
+static struct snd_ac97_build_ops patch_ad1986_build_ops = {
+ .build_post_spdif = patch_ad198x_post_spdif,
+ .build_specific = patch_ad1986_specific,
+#ifdef CONFIG_PM
+ .resume = ad18xx_resume,
+#endif
+ .update_jacks = ad1986_update_jacks,
+};
+
+int patch_ad1986(struct snd_ac97 * ac97)
+{
+ patch_ad1881(ac97);
+ ac97->build_ops = &patch_ad1986_build_ops;
+ ac97->flags |= AC97_STEREO_MUTES;
+
+ /* update current jack configuration */
+ ad1986_update_jacks(ac97);
+
+ return 0;
+}
+
+
/*
* realtek ALC65x/850 codecs
*/
@@ -2012,12 +2477,12 @@ static void alc650_update_jacks(struct snd_ac97 *ac97)
{
int shared;
- /* shared Line-In */
- shared = is_shared_linein(ac97);
+ /* shared Line-In / Surround Out */
+ shared = is_shared_surrout(ac97);
snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9,
shared ? (1 << 9) : 0);
- /* update shared Mic */
- shared = is_shared_micin(ac97);
+ /* update shared Mic In / Center/LFE Out */
+ shared = is_shared_clfeout(ac97);
/* disable/enable vref */
snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
shared ? (1 << 12) : 0);
@@ -2062,7 +2527,7 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_alc650[] = {
/* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
};
-static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0);
static int patch_alc650_specific(struct snd_ac97 * ac97)
{
@@ -2147,12 +2612,12 @@ static void alc655_update_jacks(struct snd_ac97 *ac97)
{
int shared;
- /* shared Line-In */
- shared = is_shared_linein(ac97);
+ /* shared Line-In / Surround Out */
+ shared = is_shared_surrout(ac97);
ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9,
shared ? (1 << 9) : 0, 0);
- /* update shared mic */
- shared = is_shared_micin(ac97);
+ /* update shared Mic In / Center/LFE Out */
+ shared = is_shared_clfeout(ac97);
/* misc control; vrefout disable */
snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
shared ? (1 << 12) : 0);
@@ -2261,7 +2726,9 @@ int patch_alc655(struct snd_ac97 * ac97)
else { /* ALC655 */
if (ac97->subsystem_vendor == 0x1462 &&
(ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */
- ac97->subsystem_device == 0x0161)) /* LG K1 Express */
+ ac97->subsystem_device == 0x0161 || /* LG K1 Express */
+ ac97->subsystem_device == 0x0351 || /* MSI L725 laptop */
+ ac97->subsystem_device == 0x0061)) /* MSI S250 laptop */
val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
else
val |= (1 << 1); /* Pin 47 is spdif input pin */
@@ -2294,16 +2761,16 @@ static void alc850_update_jacks(struct snd_ac97 *ac97)
{
int shared;
- /* shared Line-In */
- shared = is_shared_linein(ac97);
+ /* shared Line-In / Surround Out */
+ shared = is_shared_surrout(ac97);
/* SURR 1kOhm (bit4), Amp (bit5) */
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5),
shared ? (1<<5) : (1<<4));
/* LINE-IN = 0, SURROUND = 2 */
snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12,
shared ? (2<<12) : (0<<12));
- /* update shared mic */
- shared = is_shared_micin(ac97);
+ /* update shared Mic In / Center/LFE Out */
+ shared = is_shared_clfeout(ac97);
/* Vref disable (bit12), 1kOhm (bit13) */
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13),
shared ? (1<<12) : (1<<13));
@@ -2376,9 +2843,9 @@ int patch_alc850(struct snd_ac97 *ac97)
*/
static void cm9738_update_jacks(struct snd_ac97 *ac97)
{
- /* shared Line-In */
+ /* shared Line-In / Surround Out */
snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10,
- is_shared_linein(ac97) ? (1 << 10) : 0);
+ is_shared_surrout(ac97) ? (1 << 10) : 0);
}
static const struct snd_kcontrol_new snd_ac97_cm9738_controls[] = {
@@ -2460,12 +2927,12 @@ static const struct snd_kcontrol_new snd_ac97_cm9739_controls_spdif[] = {
static void cm9739_update_jacks(struct snd_ac97 *ac97)
{
- /* shared Line-In */
+ /* shared Line-In / Surround Out */
snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10,
- is_shared_linein(ac97) ? (1 << 10) : 0);
- /* shared Mic */
+ is_shared_surrout(ac97) ? (1 << 10) : 0);
+ /* shared Mic In / Center/LFE Out **/
snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000,
- is_shared_micin(ac97) ? 0x1000 : 0x2000);
+ is_shared_clfeout(ac97) ? 0x1000 : 0x2000);
}
static const struct snd_kcontrol_new snd_ac97_cm9739_controls[] = {
@@ -2577,8 +3044,8 @@ static void cm9761_update_jacks(struct snd_ac97 *ac97)
val |= surr_on[ac97->spec.dev_flags][is_surround_on(ac97)];
val |= clfe_on[ac97->spec.dev_flags][is_clfe_on(ac97)];
- val |= surr_shared[ac97->spec.dev_flags][is_shared_linein(ac97)];
- val |= clfe_shared[ac97->spec.dev_flags][is_shared_micin(ac97)];
+ val |= surr_shared[ac97->spec.dev_flags][is_shared_surrout(ac97)];
+ val |= clfe_shared[ac97->spec.dev_flags][is_shared_clfeout(ac97)];
snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3c88, val);
}
@@ -2818,6 +3285,7 @@ int patch_vt1617a(struct snd_ac97 * ac97)
snd_ac97_write_cache(ac97, 0x5c, 0x20);
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
+ ac97->build_ops = &patch_vt1616_ops;
return 0;
}
@@ -2825,12 +3293,12 @@ int patch_vt1617a(struct snd_ac97 * ac97)
*/
static void it2646_update_jacks(struct snd_ac97 *ac97)
{
- /* shared Line-In */
+ /* shared Line-In / Surround Out */
snd_ac97_update_bits(ac97, 0x76, 1 << 9,
- is_shared_linein(ac97) ? (1<<9) : 0);
- /* shared Mic */
+ is_shared_surrout(ac97) ? (1<<9) : 0);
+ /* shared Mic / Center/LFE Out */
snd_ac97_update_bits(ac97, 0x76, 1 << 10,
- is_shared_micin(ac97) ? (1<<10) : 0);
+ is_shared_clfeout(ac97) ? (1<<10) : 0);
}
static const struct snd_kcontrol_new snd_ac97_controls_it2646[] = {
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
index 74197921720..94340daaaf1 100644
--- a/sound/pci/ac97/ac97_patch.h
+++ b/sound/pci/ac97/ac97_patch.h
@@ -48,6 +48,7 @@ int patch_ad1980(struct snd_ac97 * ac97);
int patch_ad1981a(struct snd_ac97 * ac97);
int patch_ad1981b(struct snd_ac97 * ac97);
int patch_ad1985(struct snd_ac97 * ac97);
+int patch_ad1986(struct snd_ac97 * ac97);
int patch_alc650(struct snd_ac97 * ac97);
int patch_alc655(struct snd_ac97 * ac97);
int patch_alc850(struct snd_ac97 * ac97);
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c
index c153cb79c51..dc26820a03a 100644
--- a/sound/pci/ac97/ak4531_codec.c
+++ b/sound/pci/ac97/ak4531_codec.c
@@ -267,9 +267,9 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
static struct snd_kcontrol_new snd_ak4531_controls[] = {
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index cbf8331c3d3..98970d401be 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -858,7 +858,7 @@ snd_ad1889_free(struct snd_ad1889 *chip)
synchronize_irq(chip->irq);
if (chip->irq >= 0)
- free_irq(chip->irq, (void*)chip);
+ free_irq(chip->irq, chip);
skip_hw:
if (chip->iobase)
@@ -945,7 +945,7 @@ snd_ad1889_create(struct snd_card *card,
spin_lock_init(&chip->lock); /* only now can we call ad1889_free */
if (request_irq(pci->irq, snd_ad1889_interrupt,
- IRQF_DISABLED|IRQF_SHARED, card->driver, (void*)chip)) {
+ IRQF_SHARED, card->driver, chip)) {
printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq);
snd_ad1889_free(chip);
return -EBUSY;
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index a7edd56542d..9327ab2eccb 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -2095,7 +2095,7 @@ static int snd_ali_free(struct snd_ali * codec)
snd_ali_disable_address_interrupt(codec);
if (codec->irq >= 0) {
synchronize_irq(codec->irq);
- free_irq(codec->irq, (void *)codec);
+ free_irq(codec->irq, codec);
}
if (codec->port)
pci_release_regions(codec->pci);
@@ -2192,7 +2192,8 @@ static int __devinit snd_ali_resources(struct snd_ali *codec)
return err;
codec->port = pci_resource_start(codec->pci, 0);
- if (request_irq(codec->pci->irq, snd_ali_card_interrupt, IRQF_DISABLED|IRQF_SHARED, "ALI 5451", (void *)codec)) {
+ if (request_irq(codec->pci->irq, snd_ali_card_interrupt,
+ IRQF_SHARED, "ALI 5451", codec)) {
snd_printk(KERN_ERR "Unable to request irq.\n");
return -EBUSY;
}
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 95f70f3cc37..8afcb98ca7b 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -190,7 +190,7 @@ static int snd_als300_free(struct snd_als300 *chip)
snd_als300_dbgcallenter();
snd_als300_set_irq_flag(chip, IRQ_DISABLE);
if (chip->irq >= 0)
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, chip);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
@@ -444,7 +444,7 @@ static int snd_als300_capture_close(struct snd_pcm_substream *substream)
}
static int snd_als300_pcm_hw_params(struct snd_pcm_substream *substream,
- snd_pcm_hw_params_t * hw_params)
+ struct snd_pcm_hw_params *hw_params)
{
return snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
@@ -673,7 +673,7 @@ static void snd_als300_init(struct snd_als300 *chip)
snd_als300_dbgcallleave();
}
-static int __devinit snd_als300_create(snd_card_t *card,
+static int __devinit snd_als300_create(struct snd_card *card,
struct pci_dev *pci, int chip_type,
struct snd_als300 **rchip)
{
@@ -681,7 +681,7 @@ static int __devinit snd_als300_create(snd_card_t *card,
void *irq_handler;
int err;
- static snd_device_ops_t ops = {
+ static struct snd_device_ops ops = {
.dev_free = snd_als300_dev_free,
};
*rchip = NULL;
@@ -722,8 +722,8 @@ static int __devinit snd_als300_create(snd_card_t *card,
else
irq_handler = snd_als300_interrupt;
- if (request_irq(pci->irq, irq_handler, IRQF_DISABLED|IRQF_SHARED,
- card->shortname, (void *)chip)) {
+ if (request_irq(pci->irq, irq_handler, IRQF_SHARED,
+ card->shortname, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_als300_free(chip);
return -EBUSY;
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index e3e99f39671..7d8053b5e8d 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -45,6 +45,7 @@ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
static int ac97_clock = 48000;
static char *ac97_quirk;
static int spdif_aclink = 1;
+static int ac97_codec = -1;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for ATI IXP controller.");
@@ -54,6 +55,8 @@ module_param(ac97_clock, int, 0444);
MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
module_param(ac97_quirk, charp, 0444);
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
+module_param(ac97_codec, int, 0444);
+MODULE_PARM_DESC(ac97_codec, "Specify codec instead of probing.");
module_param(spdif_aclink, bool, 0444);
MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
@@ -293,6 +296,10 @@ static struct pci_device_id snd_atiixp_ids[] = {
MODULE_DEVICE_TABLE(pci, snd_atiixp_ids);
+static struct snd_pci_quirk atiixp_quirks[] __devinitdata = {
+ SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0),
+ { } /* terminator */
+};
/*
* lowlevel functions
@@ -553,11 +560,33 @@ static int snd_atiixp_aclink_down(struct atiixp *chip)
ATI_REG_ISR_CODEC2_NOT_READY)
#define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME)
+static int ac97_probing_bugs(struct pci_dev *pci)
+{
+ const struct snd_pci_quirk *q;
+
+ q = snd_pci_quirk_lookup(pci, atiixp_quirks);
+ if (q) {
+ snd_printdd(KERN_INFO "Atiixp quirk for %s. "
+ "Forcing codec %d\n", q->name, q->value);
+ return q->value;
+ }
+ /* this hardware doesn't need workarounds. Probe for codec */
+ return -1;
+}
+
static int snd_atiixp_codec_detect(struct atiixp *chip)
{
int timeout;
chip->codec_not_ready_bits = 0;
+ if (ac97_codec == -1)
+ ac97_codec = ac97_probing_bugs(chip->pci);
+ if (ac97_codec >= 0) {
+ chip->codec_not_ready_bits |=
+ CODEC_CHECK_BITS ^ (1 << (ac97_codec + 10));
+ return 0;
+ }
+
atiixp_write(chip, IER, CODEC_CHECK_BITS);
/* wait for the interrupts */
timeout = 50;
@@ -1396,7 +1425,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock,
ac97.private_data = chip;
ac97.pci = chip->pci;
ac97.num = i;
- ac97.scaps = AC97_SCAP_SKIP_MODEM;
+ ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE;
if (! chip->spdif_over_aclink)
ac97.scaps |= AC97_SCAP_NO_SPDIF;
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
@@ -1583,7 +1612,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card,
return -EIO;
}
- if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
card->shortname, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_atiixp_free(chip);
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index dc54f2c68ed..904023fe4f2 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1090,7 +1090,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
ac97.private_data = chip;
ac97.pci = chip->pci;
ac97.num = i;
- ac97.scaps = AC97_SCAP_SKIP_AUDIO;
+ ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
chip->ac97[i] = NULL; /* to be sure */
snd_printdd("atiixp-modem: codec %d not available for modem\n", i);
@@ -1256,7 +1256,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card,
return -EIO;
}
- if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
card->shortname, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_atiixp_free(chip);
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index 6ed5ad59f5b..238154bb7a2 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -198,7 +198,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
}
if ((err = request_irq(pci->irq, vortex_interrupt,
- IRQF_DISABLED | IRQF_SHARED, CARD_NAME_SHORT,
+ IRQF_SHARED, CARD_NAME_SHORT,
chip)) != 0) {
printk(KERN_ERR "cannot grab irq\n");
goto irq_out;
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 2414ee63075..43edd2839b5 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -1513,7 +1513,7 @@ snd_azf3328_free(struct snd_azf3328 *chip)
__end_hw:
snd_azf3328_free_joystick(chip);
if (chip->irq >= 0)
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, chip);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
@@ -1724,7 +1724,8 @@ snd_azf3328_create(struct snd_card *card,
chip->synth_port = pci_resource_start(pci, 3);
chip->mixer_port = pci_resource_start(pci, 4);
- if (request_irq(pci->irq, snd_azf3328_interrupt, IRQF_DISABLED|IRQF_SHARED, card->shortname, (void *)chip)) {
+ if (request_irq(pci->irq, snd_azf3328_interrupt,
+ IRQF_SHARED, card->shortname, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
err = -EBUSY;
goto out_err;
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index d33a37086df..c3f3da21123 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -699,7 +699,7 @@ static int __devinit snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *nam
SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci),
128 * 1024,
- (255 * 4092 + 1023) & ~1023);
+ ALIGN(255 * 4092, 1024));
}
static int __devinit snd_bt87x_create(struct snd_card *card,
@@ -747,7 +747,7 @@ static int __devinit snd_bt87x_create(struct snd_card *card,
snd_bt87x_writel(chip, REG_INT_MASK, 0);
snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS);
- if (request_irq(pci->irq, snd_bt87x_interrupt, IRQF_DISABLED | IRQF_SHARED,
+ if (request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED,
"Bt87x audio", chip)) {
snd_bt87x_free(chip);
snd_printk(KERN_ERR "cannot grab irq\n");
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index 9cb66c59f52..aaac6e5b476 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -590,7 +590,7 @@ struct snd_ca0106 {
struct resource *res_port;
int irq;
- unsigned int revision; /* chip revision */
+ unsigned char revision; /* chip revision */
unsigned int serial; /* serial number */
unsigned short model; /* subsystem id */
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 6fa4a302f7d..ea6712b63c9 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -154,6 +154,7 @@ MODULE_SUPPORTED_DEVICE("{{Creative,SB CA0106 chip}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the CA0106 soundcard.");
@@ -161,6 +162,8 @@ module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for the CA0106 soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable the CA0106 soundcard.");
+module_param_array(subsystem, uint, NULL, 0444);
+MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
#include "ca0106.h"
@@ -194,6 +197,17 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
.gpio_type = 1,
.i2c_adc = 1,
.spi_dac = 1 } ,
+ /* New Audigy LS. Has a different DAC. */
+ /* SB0570:
+ * CTRL:CA0106-DAT
+ * ADC: WM8775EDS
+ * DAC: WM8768GEDS
+ */
+ { .serial = 0x10111102,
+ .name = "Audigy SE OEM [SB0570a]",
+ .gpio_type = 1,
+ .i2c_adc = 1,
+ .spi_dac = 1 } ,
/* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
/* SB0438
* CTRL:CA0106-DAT
@@ -1046,7 +1060,7 @@ static int snd_ca0106_free(struct snd_ca0106 *chip)
// release the irq
if (chip->irq >= 0)
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, chip);
pci_disable_device(chip->pci);
kfree(chip);
return 0;
@@ -1223,7 +1237,7 @@ static unsigned int i2c_adc_init[][2] = {
{ 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */
};
-static int __devinit snd_ca0106_create(struct snd_card *card,
+static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
struct pci_dev *pci,
struct snd_ca0106 **rchip)
{
@@ -1267,8 +1281,7 @@ static int __devinit snd_ca0106_create(struct snd_card *card,
}
if (request_irq(pci->irq, snd_ca0106_interrupt,
- IRQF_DISABLED|IRQF_SHARED, "snd_ca0106",
- (void *)chip)) {
+ IRQF_SHARED, "snd_ca0106", chip)) {
snd_ca0106_free(chip);
printk(KERN_ERR "cannot grab irq\n");
return -EBUSY;
@@ -1283,21 +1296,29 @@ static int __devinit snd_ca0106_create(struct snd_card *card,
pci_set_master(pci);
/* read revision & serial */
- pci_read_config_byte(pci, PCI_REVISION_ID, (char *)&chip->revision);
+ pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
#if 1
- printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model,
+ printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model,
chip->revision, chip->serial);
#endif
strcpy(card->driver, "CA0106");
strcpy(card->shortname, "CA0106");
for (c = ca0106_chip_details; c->serial; c++) {
- if (c->serial == chip->serial)
+ if (subsystem[dev]) {
+ if (c->serial == subsystem[dev])
+ break;
+ } else if (c->serial == chip->serial)
break;
}
chip->details = c;
+ if (subsystem[dev]) {
+ printk(KERN_INFO "snd-ca0106: Sound card name=%s, subsystem=0x%x. Forced to subsystem=0x%x\n",
+ c->name, chip->serial, subsystem[dev]);
+ }
+
sprintf(card->longname, "%s at 0x%lx irq %i",
c->name, chip->port, chip->irq);
@@ -1361,7 +1382,6 @@ static int __devinit snd_ca0106_create(struct snd_card *card,
snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf);
snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */
chip->spdif_enable = 0; /* Set digital SPDIF output off */
- chip->capture_source = 3; /* Set CAPTURE_SOURCE */
//snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */
//snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */
@@ -1381,8 +1401,22 @@ static int __devinit snd_ca0106_create(struct snd_card *card,
snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */
snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */
}
- snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */
- chip->capture_source = 3; /* Set CAPTURE_SOURCE */
+ if (chip->details->i2c_adc == 1) {
+ /* Select MIC, Line in, TAD in, AUX in */
+ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
+ /* Default to CAPTURE_SOURCE to i2s in */
+ chip->capture_source = 3;
+ } else if (chip->details->ac97 == 1) {
+ /* Default to AC97 in */
+ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4);
+ /* Default to CAPTURE_SOURCE to AC97 in */
+ chip->capture_source = 4;
+ } else {
+ /* Select MIC, Line in, TAD in, AUX in */
+ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
+ /* Default to Set CAPTURE_SOURCE to i2s in */
+ chip->capture_source = 3;
+ }
if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */
/* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
@@ -1540,7 +1574,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci,
if (card == NULL)
return -ENOMEM;
- if ((err = snd_ca0106_create(card, pci, &chip)) < 0) {
+ if ((err = snd_ca0106_create(dev, card, pci, &chip)) < 0) {
snd_card_free(card);
return err;
}
@@ -1584,6 +1618,8 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci,
snd_ca0106_proc_init(chip);
#endif
+ snd_card_set_dev(card, &pci->dev);
+
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 9855f528ea7..b913a1fb8c2 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -74,8 +74,8 @@
#include "ca0106.h"
-static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
-static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
+static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@@ -482,19 +482,6 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
.private_value = ((chid) << 8) | (reg) \
}
-#define I2C_VOLUME(xname,chid) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
- SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
- .info = snd_ca0106_i2c_volume_info, \
- .get = snd_ca0106_i2c_volume_get, \
- .put = snd_ca0106_i2c_volume_put, \
- .tlv = { .p = snd_ca0106_db_scale2 }, \
- .private_value = chid \
-}
-
-
static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
CA_VOLUME("Analog Front Playback Volume",
CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2),
@@ -517,11 +504,6 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
CA_VOLUME("CAPTURE feedback Playback Volume",
1, CAPTURE_CONTROL),
- I2C_VOLUME("Phone Capture Volume", 0),
- I2C_VOLUME("Mic Capture Volume", 1),
- I2C_VOLUME("Line in Capture Volume", 2),
- I2C_VOLUME("Aux Capture Volume", 3),
-
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -539,14 +521,14 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Digital Capture Source",
+ .name = "Digital Source Capture Enum",
.info = snd_ca0106_capture_source_info,
.get = snd_ca0106_capture_source_get,
.put = snd_ca0106_capture_source_put
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
+ .name = "Analog Source Capture Enum",
.info = snd_ca0106_i2c_capture_source_info,
.get = snd_ca0106_i2c_capture_source_get,
.put = snd_ca0106_i2c_capture_source_put
@@ -561,6 +543,25 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
},
};
+#define I2C_VOLUME(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = snd_ca0106_i2c_volume_info, \
+ .get = snd_ca0106_i2c_volume_get, \
+ .put = snd_ca0106_i2c_volume_put, \
+ .tlv = { .p = snd_ca0106_db_scale2 }, \
+ .private_value = chid \
+}
+
+static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = {
+ I2C_VOLUME("Phone Capture Volume", 0),
+ I2C_VOLUME("Mic Capture Volume", 1),
+ I2C_VOLUME("Line in Capture Volume", 2),
+ I2C_VOLUME("Aux Capture Volume", 3),
+};
+
static int __devinit remove_ctl(struct snd_card *card, const char *name)
{
struct snd_ctl_elem_id id;
@@ -645,6 +646,11 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
return err;
}
if (emu->details->i2c_adc == 1) {
+ for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu));
+ if (err < 0)
+ return err;
+ }
if (emu->details->gpio_type == 1)
err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
else /* gpio_type == 2 */
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 0093cd1f92d..70face7e104 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -2198,7 +2198,8 @@ static int _snd_cmipci_uswitch_put(struct snd_kcontrol *kcontrol,
val = inb(cm->iobase + args->reg);
else
val = snd_cmipci_read(cm, args->reg);
- change = (val & args->mask) != (ucontrol->value.integer.value[0] ? args->mask : 0);
+ change = (val & args->mask) != (ucontrol->value.integer.value[0] ?
+ args->mask_on : (args->mask & ~args->mask_on));
if (change) {
val &= ~args->mask;
if (ucontrol->value.integer.value[0])
@@ -2862,7 +2863,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
cm->iobase = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_cmipci_interrupt,
- IRQF_DISABLED|IRQF_SHARED, card->driver, cm)) {
+ IRQF_SHARED, card->driver, cm)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_cmipci_free(cm);
return -EBUSY;
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 0905fa88129..44cf5460764 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1055,7 +1055,7 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol,
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
static struct snd_kcontrol_new snd_cs4281_fm_vol =
{
@@ -1391,7 +1391,7 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
return -ENOMEM;
}
- if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED,
"CS4281", chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_cs4281_free(chip);
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 2807b9756ef..2ae539b195f 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -3867,7 +3867,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card,
}
}
- if (request_irq(pci->irq, snd_cs46xx_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_cs46xx_interrupt, IRQF_SHARED,
"CS46XX", chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_cs46xx_free(chip);
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 2441238f200..b8e75ef9c1e 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -320,7 +320,7 @@ static int __devinit snd_cs5535audio_create(struct snd_card *card,
cs5535au->port = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_cs5535audio_interrupt,
- IRQF_DISABLED|IRQF_SHARED, "CS5535 Audio", cs5535au)) {
+ IRQF_SHARED, "CS5535 Audio", cs5535au)) {
snd_printk("unable to grab IRQ %d\n", pci->irq);
err = -EBUSY;
goto sndfail;
diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c
index b7108e29a66..8e7fe033270 100644
--- a/sound/pci/echoaudio/darla20.c
+++ b/sound/pci/echoaudio/darla20.c
@@ -47,6 +47,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c
index e59a982ee36..a13c623eb99 100644
--- a/sound/pci/echoaudio/darla24.c
+++ b/sound/pci/echoaudio/darla24.c
@@ -51,6 +51,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c
index 12099fe1547..8fb15823aca 100644
--- a/sound/pci/echoaudio/echo3g.c
+++ b/sound/pci/echoaudio/echo3g.c
@@ -58,6 +58,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c
index d26a1d1f3ed..48eb7c59911 100644
--- a/sound/pci/echoaudio/echo3g_dsp.c
+++ b/sound/pci/echoaudio/echo3g_dsp.c
@@ -39,7 +39,7 @@ static int set_phantom_power(struct echoaudio *chip, char on);
static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
char force);
-#include <linux/irq.h>
+#include <linux/interrupt.h>
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index e5e88fe54de..6a428b81dba 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -34,6 +34,7 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
+static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1);
static int get_firmware(const struct firmware **fw_entry,
const struct firmware *frm, struct echoaudio *chip)
@@ -1011,17 +1012,21 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = {
.name = "Line Playback Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_output_gain_info,
.get = snd_echo_output_gain_get,
.put = snd_echo_output_gain_put,
+ .tlv = {.p = db_scale_output_gain},
};
#else
static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
.name = "PCM Playback Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_output_gain_info,
.get = snd_echo_output_gain_get,
.put = snd_echo_output_gain_put,
+ .tlv = {.p = db_scale_output_gain},
};
#endif
@@ -1080,12 +1085,16 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
return changed;
}
+static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0);
+
static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = {
.name = "Line Capture Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_input_gain_info,
.get = snd_echo_input_gain_get,
.put = snd_echo_input_gain_put,
+ .tlv = {.p = db_scale_input_gain},
};
#endif /* ECHOCARD_HAS_INPUT_GAIN */
@@ -1277,9 +1286,11 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = {
.name = "Monitor Mixer Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_mixer_info,
.get = snd_echo_mixer_get,
.put = snd_echo_mixer_put,
+ .tlv = {.p = db_scale_output_gain},
};
#endif /* ECHOCARD_HAS_MONITOR */
@@ -1343,9 +1354,11 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = {
.name = "VMixer Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_vmixer_info,
.get = snd_echo_vmixer_get,
.put = snd_echo_vmixer_put,
+ .tlv = {.p = db_scale_output_gain},
};
#endif /* ECHOCARD_HAS_VMIXER */
@@ -1753,9 +1766,12 @@ static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol,
static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = {
.name = "VU-meters",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = snd_echo_vumeters_info,
.get = snd_echo_vumeters_get,
+ .tlv = {.p = db_scale_output_gain},
};
@@ -1872,7 +1888,7 @@ static int snd_echo_free(struct echoaudio *chip)
DE_INIT(("Stopped.\n"));
if (chip->irq >= 0)
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, chip);
if (chip->dsp_registers)
iounmap(chip->dsp_registers);
@@ -1950,8 +1966,8 @@ static __devinit int snd_echo_create(struct snd_card *card,
chip->dsp_registers = (volatile u32 __iomem *)
ioremap_nocache(chip->dsp_registers_phys, sz);
- if (request_irq(pci->irq, snd_echo_interrupt, IRQF_DISABLED | IRQF_SHARED,
- ECHOCARD_NAME, (void *)chip)) {
+ if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
+ ECHOCARD_NAME, chip)) {
snd_echo_free(chip);
snd_printk(KERN_ERR "cannot grab irq\n");
return -EBUSY;
diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c
index 29d6d12f80c..af4d32026e4 100644
--- a/sound/pci/echoaudio/gina20.c
+++ b/sound/pci/echoaudio/gina20.c
@@ -51,6 +51,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c
index e464d720d0b..9ff454a947e 100644
--- a/sound/pci/echoaudio/gina24.c
+++ b/sound/pci/echoaudio/gina24.c
@@ -57,6 +57,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c
index bfd2467099a..37eb726fd03 100644
--- a/sound/pci/echoaudio/indigo.c
+++ b/sound/pci/echoaudio/indigo.c
@@ -49,6 +49,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c
index 8ed7ff1fd87..dc8b9182418 100644
--- a/sound/pci/echoaudio/indigodj.c
+++ b/sound/pci/echoaudio/indigodj.c
@@ -49,6 +49,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c
index a8788e95917..eadf3263453 100644
--- a/sound/pci/echoaudio/indigoio.c
+++ b/sound/pci/echoaudio/indigoio.c
@@ -50,6 +50,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c
index e503d74b3ba..6cede497579 100644
--- a/sound/pci/echoaudio/layla20.c
+++ b/sound/pci/echoaudio/layla20.c
@@ -56,6 +56,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c
index d4581fdc841..44f735426aa 100644
--- a/sound/pci/echoaudio/layla24.c
+++ b/sound/pci/echoaudio/layla24.c
@@ -58,6 +58,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c
index be40c64263d..dc172d03ac3 100644
--- a/sound/pci/echoaudio/mia.c
+++ b/sound/pci/echoaudio/mia.c
@@ -56,6 +56,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
index e31f0f11e3a..91f5bff66d3 100644
--- a/sound/pci/echoaudio/midi.c
+++ b/sound/pci/echoaudio/midi.c
@@ -213,7 +213,7 @@ static void snd_echo_midi_output_write(unsigned long data)
sent = bytes = 0;
spin_lock_irqsave(&chip->lock, flags);
chip->midi_full = 0;
- if (chip->midi_out && !snd_rawmidi_transmit_empty(chip->midi_out)) {
+ if (!snd_rawmidi_transmit_empty(chip->midi_out)) {
bytes = snd_rawmidi_transmit_peek(chip->midi_out, buf,
MIDI_OUT_BUFFER_SIZE - 1);
DE_MID(("Try to send %d bytes...\n", bytes));
@@ -264,9 +264,11 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream
}
} else {
if (chip->tinuse) {
- del_timer(&chip->timer);
chip->tinuse = 0;
+ spin_unlock_irq(&chip->lock);
+ del_timer_sync(&chip->timer);
DE_MID(("Timer removed\n"));
+ return;
}
}
spin_unlock_irq(&chip->lock);
diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c
index 5dc512add37..c856ed50dd9 100644
--- a/sound/pci/echoaudio/mona.c
+++ b/sound/pci/echoaudio/mona.c
@@ -55,6 +55,7 @@
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 8bc4ffa6220..80aa585eade 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -3,8 +3,10 @@
* Creative Labs, Inc.
* Routines for control of EMU10K1 chips
*
- * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
+ * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
* Added support for Audigy 2 Value.
+ * Added EMU 1010 support.
+ * General bug fixes and enhancements.
*
*
* BUGS:
@@ -41,8 +43,10 @@
#include <sound/core.h>
#include <sound/emu10k1.h>
+#include <linux/firmware.h>
#include "p16v.h"
#include "tina2.h"
+#include "p17v.h"
/*************************************************************************
@@ -117,11 +121,28 @@ static unsigned int spi_dac_init[] = {
0x0622,
0x1400,
};
+
+static unsigned int i2c_adc_init[][2] = {
+ { 0x17, 0x00 }, /* Reset */
+ { 0x07, 0x00 }, /* Timeout */
+ { 0x0b, 0x22 }, /* Interface control */
+ { 0x0c, 0x22 }, /* Master mode control */
+ { 0x0d, 0x08 }, /* Powerdown control */
+ { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */
+ { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */
+ { 0x10, 0x7b }, /* ALC Control 1 */
+ { 0x11, 0x00 }, /* ALC Control 2 */
+ { 0x12, 0x32 }, /* ALC Control 3 */
+ { 0x13, 0x00 }, /* Noise gate control */
+ { 0x14, 0xa6 }, /* Limiter control */
+ { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */
+};
static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
{
unsigned int silent_page;
int ch;
+ u32 tmp;
/* disable audio and lock cache */
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE,
@@ -160,8 +181,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
/* Hacks for Alice3 to work independent of haP16V driver */
- u32 tmp;
-
//Setup SRCMulti_I2S SamplingRate
tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
tmp &= 0xfffff1ff;
@@ -181,8 +200,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
}
if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */
/* Hacks for Alice3 to work independent of haP16V driver */
- u32 tmp;
-
snd_printk(KERN_INFO "Audigy2 value: Special config.\n");
//Setup SRCMulti_I2S SamplingRate
tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
@@ -211,7 +228,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
int size, n;
size = ARRAY_SIZE(spi_dac_init);
- for (n=0; n < size; n++)
+ for (n = 0; n < size; n++)
snd_emu10k1_spi_write(emu, spi_dac_init[n]);
snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10);
@@ -228,6 +245,23 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */
}
+ if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */
+ int size, n;
+
+ snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f);
+ tmp = inl(emu->port + A_IOCFG);
+ outl(tmp | 0x4, emu->port + A_IOCFG); /* Set bit 2 for mic input */
+ tmp = inl(emu->port + A_IOCFG);
+ size = ARRAY_SIZE(i2c_adc_init);
+ for (n = 0; n < size; n++)
+ snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]);
+ for (n=0; n < 4; n++) {
+ emu->i2c_capture_volume[n][0]= 0xcf;
+ emu->i2c_capture_volume[n][1]= 0xcf;
+ }
+
+ }
+
snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);
snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */
@@ -239,6 +273,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page);
}
+ if (emu->card_capabilities->emu1010) {
+ outl(HCFG_AUTOMUTE_ASYNC |
+ HCFG_EMU32_SLAVE |
+ HCFG_AUDIOENABLE, emu->port + HCFG);
/*
* Hokay, setup HCFG
* Mute Disable Audio = 0
@@ -246,7 +284,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
* Lock Sound Memory = 0
* Auto Mute = 1
*/
- if (emu->audigy) {
+ } else if (emu->audigy) {
if (emu->revision == 4) /* audigy2 */
outl(HCFG_AUDIOENABLE |
HCFG_AC3ENABLE_CDSPDIF |
@@ -265,8 +303,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
if (enable_ir) { /* enable IR for SB Live */
- if ( emu->card_capabilities->emu1212m) {
- ; /* Disable all access to A_IOCFG for the emu1212m */
+ if (emu->card_capabilities->emu1010) {
+ ; /* Disable all access to A_IOCFG for the emu1010 */
+ } else if (emu->card_capabilities->i2c_adc) {
+ ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
} else if (emu->audigy) {
unsigned int reg = inl(emu->port + A_IOCFG);
outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG);
@@ -284,8 +324,10 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
}
}
- if ( emu->card_capabilities->emu1212m) {
- ; /* Disable all access to A_IOCFG for the emu1212m */
+ if (emu->card_capabilities->emu1010) {
+ ; /* Disable all access to A_IOCFG for the emu1010 */
+ } else if (emu->card_capabilities->i2c_adc) {
+ ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
} else if (emu->audigy) { /* enable analog output */
unsigned int reg = inl(emu->port + A_IOCFG);
outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG);
@@ -302,8 +344,10 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG);
/* Enable analog/digital outs on audigy */
- if ( emu->card_capabilities->emu1212m) {
- ; /* Disable all access to A_IOCFG for the emu1212m */
+ if (emu->card_capabilities->emu1010) {
+ ; /* Disable all access to A_IOCFG for the emu1010 */
+ } else if (emu->card_capabilities->i2c_adc) {
+ ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
} else if (emu->audigy) {
outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);
@@ -596,133 +640,423 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu)
return 0;
}
-static int snd_emu1212m_fpga_write(struct snd_emu10k1 * emu, int reg, int value)
+static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * filename)
{
- if (reg<0 || reg>0x3f)
- return 1;
- reg+=0x40; /* 0x40 upwards are registers. */
- if (value<0 || value>0x3f) /* 0 to 0x3f are values */
- return 1;
- outl(reg, emu->port + A_IOCFG);
- outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
- outl(value, emu->port + A_IOCFG);
- outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
-
- return 0;
-}
-
-static int snd_emu1212m_fpga_read(struct snd_emu10k1 * emu, int reg, int *value)
-{
- if (reg<0 || reg>0x3f)
- return 1;
- reg+=0x40; /* 0x40 upwards are registers. */
- outl(reg, emu->port + A_IOCFG);
- outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
- *value = inl(emu->port + A_IOCFG);
-
- return 0;
-}
+ int err;
+ int n, i;
+ int reg;
+ int value;
+ const struct firmware *fw_entry;
+
+ if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) {
+ snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err);
+ return err;
+ }
+ snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size);
+ if (fw_entry->size != 0x133a4) {
+ snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename);
+ return -EINVAL;
+ }
-static int snd_emu1212m_fpga_netlist_write(struct snd_emu10k1 * emu, int reg, int value)
-{
- snd_emu1212m_fpga_write(emu, 0x00, ((reg >> 8) & 0x3f) );
- snd_emu1212m_fpga_write(emu, 0x01, (reg & 0x3f) );
- snd_emu1212m_fpga_write(emu, 0x02, ((value >> 8) & 0x3f) );
- snd_emu1212m_fpga_write(emu, 0x03, (value & 0x3f) );
+ /* The FPGA is a Xilinx Spartan IIE XC2S50E */
+ /* GPIO7 -> FPGA PGMN
+ * GPIO6 -> FPGA CCLK
+ * GPIO5 -> FPGA DIN
+ * FPGA CONFIG OFF -> FPGA PGMN
+ */
+ outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */
+ udelay(1);
+ outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */
+ udelay(100); /* Allow FPGA memory to clean */
+ for(n = 0; n < fw_entry->size; n++) {
+ value=fw_entry->data[n];
+ for(i = 0; i < 8; i++) {
+ reg = 0x80;
+ if (value & 0x1)
+ reg = reg | 0x20;
+ value = value >> 1;
+ outl(reg, emu->port + A_IOCFG);
+ outl(reg | 0x40, emu->port + A_IOCFG);
+ }
+ }
+ /* After programming, set GPIO bit 4 high again. */
+ outl(0x10, emu->port + A_IOCFG);
+
+ release_firmware(fw_entry);
return 0;
}
-static int snd_emu10k1_emu1212m_init(struct snd_emu10k1 * emu)
+static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
{
unsigned int i;
- int tmp;
-
- snd_printk(KERN_ERR "emu1212m: Special config.\n");
+ int tmp,tmp2;
+ int reg;
+ int err;
+ const char *hana_filename = "emu/hana.fw";
+ const char *dock_filename = "emu/audio_dock.fw";
+
+ snd_printk(KERN_INFO "emu1010: Special config.\n");
+ /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+ * Lock Sound Memory Cache, Lock Tank Memory Cache,
+ * Mute all codecs.
+ */
outl(0x0005a00c, emu->port + HCFG);
- outl(0x0005a004, emu->port + HCFG);
+ /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+ * Lock Tank Memory Cache,
+ * Mute all codecs.
+ */
+ outl(0x0005a004, emu->port + HCFG);
+ /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+ * Mute all codecs.
+ */
outl(0x0005a000, emu->port + HCFG);
+ /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
+ * Mute all codecs.
+ */
outl(0x0005a000, emu->port + HCFG);
- snd_emu1212m_fpga_read(emu, 0x22, &tmp );
- snd_emu1212m_fpga_read(emu, 0x23, &tmp );
- snd_emu1212m_fpga_read(emu, 0x24, &tmp );
- snd_emu1212m_fpga_write(emu, 0x04, 0x01 );
- snd_emu1212m_fpga_read(emu, 0x0b, &tmp );
- snd_emu1212m_fpga_write(emu, 0x0b, 0x01 );
- snd_emu1212m_fpga_read(emu, 0x10, &tmp );
- snd_emu1212m_fpga_write(emu, 0x10, 0x00 );
- snd_emu1212m_fpga_read(emu, 0x11, &tmp );
- snd_emu1212m_fpga_write(emu, 0x11, 0x30 );
- snd_emu1212m_fpga_read(emu, 0x13, &tmp );
- snd_emu1212m_fpga_write(emu, 0x13, 0x0f );
- snd_emu1212m_fpga_read(emu, 0x11, &tmp );
- snd_emu1212m_fpga_write(emu, 0x11, 0x30 );
- snd_emu1212m_fpga_read(emu, 0x0a, &tmp );
- snd_emu1212m_fpga_write(emu, 0x0a, 0x10 );
- snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
- snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
- snd_emu1212m_fpga_write(emu, 0x09, 0x0f );
- snd_emu1212m_fpga_write(emu, 0x06, 0x00 );
- snd_emu1212m_fpga_write(emu, 0x05, 0x00 );
- snd_emu1212m_fpga_write(emu, 0x0e, 0x12 );
- snd_emu1212m_fpga_netlist_write(emu, 0x0000, 0x0200);
- snd_emu1212m_fpga_netlist_write(emu, 0x0001, 0x0201);
- snd_emu1212m_fpga_netlist_write(emu, 0x0002, 0x0500);
- snd_emu1212m_fpga_netlist_write(emu, 0x0003, 0x0501);
- snd_emu1212m_fpga_netlist_write(emu, 0x0004, 0x0400);
- snd_emu1212m_fpga_netlist_write(emu, 0x0005, 0x0401);
- snd_emu1212m_fpga_netlist_write(emu, 0x0006, 0x0402);
- snd_emu1212m_fpga_netlist_write(emu, 0x0007, 0x0403);
- snd_emu1212m_fpga_netlist_write(emu, 0x0008, 0x0404);
- snd_emu1212m_fpga_netlist_write(emu, 0x0009, 0x0405);
- snd_emu1212m_fpga_netlist_write(emu, 0x000a, 0x0406);
- snd_emu1212m_fpga_netlist_write(emu, 0x000b, 0x0407);
- snd_emu1212m_fpga_netlist_write(emu, 0x000c, 0x0100);
- snd_emu1212m_fpga_netlist_write(emu, 0x000d, 0x0104);
- snd_emu1212m_fpga_netlist_write(emu, 0x000e, 0x0200);
- snd_emu1212m_fpga_netlist_write(emu, 0x000f, 0x0201);
- for (i=0;i < 0x20;i++) {
- snd_emu1212m_fpga_netlist_write(emu, 0x0100+i, 0x0000);
+ /* Disable 48Volt power to Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 );
+
+ /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+ snd_printdd("reg1=0x%x\n",reg);
+ if (reg == 0x55) {
+ /* FPGA netlist already present so clear it */
+ /* Return to programming mode */
+
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02 );
}
- for (i=0;i < 4;i++) {
- snd_emu1212m_fpga_netlist_write(emu, 0x0200+i, 0x0000);
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+ snd_printdd("reg2=0x%x\n",reg);
+ if (reg == 0x55) {
+ /* FPGA failed to return to programming mode */
+ return -ENODEV;
}
- for (i=0;i < 7;i++) {
- snd_emu1212m_fpga_netlist_write(emu, 0x0300+i, 0x0000);
+ snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg);
+ if ((err = snd_emu1010_load_firmware(emu, hana_filename)) != 0) {
+ snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", hana_filename);
+ return err;
}
- for (i=0;i < 7;i++) {
- snd_emu1212m_fpga_netlist_write(emu, 0x0400+i, 0x0000);
+
+ /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+ if (reg != 0x55) {
+ /* FPGA failed to be programmed */
+ snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg);
+ return -ENODEV;
}
- snd_emu1212m_fpga_netlist_write(emu, 0x0500, 0x0108);
- snd_emu1212m_fpga_netlist_write(emu, 0x0501, 0x010c);
- snd_emu1212m_fpga_netlist_write(emu, 0x0600, 0x0110);
- snd_emu1212m_fpga_netlist_write(emu, 0x0601, 0x0114);
- snd_emu1212m_fpga_netlist_write(emu, 0x0700, 0x0118);
- snd_emu1212m_fpga_netlist_write(emu, 0x0701, 0x011c);
- snd_emu1212m_fpga_write(emu, 0x07, 0x01 );
- snd_emu1212m_fpga_read(emu, 0x21, &tmp );
+ snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n");
+ snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp );
+ snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 );
+ snd_printk("Hana ver:%d.%d\n",tmp ,tmp2);
+ /* Enable 48Volt power to Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON );
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
+ snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg);
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
+ snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg);
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp );
+ /* ADAT input. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x01 );
+ snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp );
+ /* Set no attenuation on Audio Dock pads. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 );
+ emu->emu1010.adc_pads = 0x00;
+ snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp );
+ /* Unmute Audio dock DACs, Headphone source DAC-4. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 );
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 );
+ snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp );
+ /* DAC PADs. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f );
+ emu->emu1010.dac_pads = 0x0f;
+ snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp );
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 );
+ snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp );
+ /* SPDIF Format. Set Consumer mode, 24bit, copy enable */
+ snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 );
+ /* MIDI routing */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 );
+ /* Unknown. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c );
+ /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */
+ /* IRQ Enable: All off */
+ snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 );
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
+ snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg);
+ /* Default WCLK set to 48kHz. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 );
+ /* Word Clock source, Internal 48kHz x1 */
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K );
+ //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X );
+ /* Audio Dock LEDs. */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 );
- outl(0x0000a000, emu->port + HCFG);
+#if 0
+ /* For 96kHz */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT2);
+#endif
+#if 0
+ /* For 192kHz */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_RIGHT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT3);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT3);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_6, EMU_SRC_HAMOA_ADC_LEFT4);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_7, EMU_SRC_HAMOA_ADC_RIGHT4);
+#endif
+#if 1
+ /* For 48kHz */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_0, EMU_SRC_DOCK_MIC_A1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_1, EMU_SRC_DOCK_MIC_B1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_4, EMU_SRC_DOCK_ADC1_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_5, EMU_SRC_DOCK_ADC1_RIGHT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1);
+#endif
+#if 0
+ /* Original */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_4, EMU_SRC_HANA_ADAT);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_5, EMU_SRC_HANA_ADAT + 1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_6, EMU_SRC_HANA_ADAT + 2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_7, EMU_SRC_HANA_ADAT + 3);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_8, EMU_SRC_HANA_ADAT + 4);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_9, EMU_SRC_HANA_ADAT + 5);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_A, EMU_SRC_HANA_ADAT + 6);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_B, EMU_SRC_HANA_ADAT + 7);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_MIC_A1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_MIC_B1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_E, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2);
+#endif
+ for (i = 0;i < 0x20; i++ ) {
+ /* AudioDock Elink <- Silence */
+ snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE);
+ }
+ for (i = 0;i < 4; i++) {
+ /* Hana SPDIF Out <- Silence */
+ snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE);
+ }
+ for (i = 0;i < 7; i++) {
+ /* Hamoa DAC <- Silence */
+ snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE);
+ }
+ for (i = 0;i < 7; i++) {
+ /* Hana ADAT Out <- Silence */
+ snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE);
+ }
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S0_LEFT, EMU_SRC_DOCK_ADC1_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S0_RIGHT, EMU_SRC_DOCK_ADC1_RIGHT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S1_LEFT, EMU_SRC_DOCK_ADC2_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S1_RIGHT, EMU_SRC_DOCK_ADC2_RIGHT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1);
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp );
+
+ /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave,
+ * Lock Sound Memory Cache, Lock Tank Memory Cache,
+ * Mute all codecs.
+ */
+ outl(0x0000a000, emu->port + HCFG);
+ /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave,
+ * Lock Sound Memory Cache, Lock Tank Memory Cache,
+ * Un-Mute all codecs.
+ */
outl(0x0000a001, emu->port + HCFG);
+
/* Initial boot complete. Now patches */
- snd_emu1212m_fpga_read(emu, 0x21, &tmp );
- snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
- snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
- snd_emu1212m_fpga_write(emu, 0x0c, 0x19 );
- snd_emu1212m_fpga_write(emu, 0x12, 0x0c );
- snd_emu1212m_fpga_read(emu, 0x0a, &tmp );
- snd_emu1212m_fpga_write(emu, 0x0a, 0x10 );
-
- snd_emu1212m_fpga_read(emu, 0x20, &tmp );
- snd_emu1212m_fpga_read(emu, 0x21, &tmp );
-
- snd_emu1212m_fpga_netlist_write(emu, 0x0300, 0x0312);
- snd_emu1212m_fpga_netlist_write(emu, 0x0301, 0x0313);
- snd_emu1212m_fpga_netlist_write(emu, 0x0200, 0x0302);
- snd_emu1212m_fpga_netlist_write(emu, 0x0201, 0x0303);
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp );
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */
+ snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */
+ snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp );
+ snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */
+
+ /* Delay to allow Audio Dock to settle */
+ msleep(100);
+ snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg ); /* OPTIONS: Which cards are attached to the EMU */
+ /* FIXME: The loading of this should be able to happen any time,
+ * as the user can plug/unplug it at any time
+ */
+ if (reg & (EMU_HANA_OPTION_DOCK_ONLINE | EMU_HANA_OPTION_DOCK_OFFLINE) ) {
+ /* Audio Dock attached */
+ /* Return to Audio Dock programming mode */
+ snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK );
+ if ((err = snd_emu1010_load_firmware(emu, dock_filename)) != 0) {
+ return err;
+ }
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 );
+ snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg );
+ snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg);
+ /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+ snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg);
+ if (reg != 0x55) {
+ /* FPGA failed to be programmed */
+ snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg);
+ return 0;
+ return -ENODEV;
+ }
+ snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp );
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 );
+ snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2);
+ }
+#if 0
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32B + 3); /* ALICE2 bus 0xa3 */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 2); /* ALICE2 bus 0xb2 */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */
+#endif
+ /* Default outputs */
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[0] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[1] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2);
+ emu->emu1010.output_source[2] = 23;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3);
+ emu->emu1010.output_source[3] = 24;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4);
+ emu->emu1010.output_source[4] = 25;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5);
+ emu->emu1010.output_source[5] = 26;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6);
+ emu->emu1010.output_source[6] = 27;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7);
+ emu->emu1010.output_source[7] = 28;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[8] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[9] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[10] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[11] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[12] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[13] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[14] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[15] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
+ emu->emu1010.output_source[16] = 21;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1);
+ emu->emu1010.output_source[17] = 22;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2);
+ emu->emu1010.output_source[18] = 23;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3);
+ emu->emu1010.output_source[19] = 24;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4);
+ emu->emu1010.output_source[20] = 25;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5);
+ emu->emu1010.output_source[21] = 26;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6);
+ emu->emu1010.output_source[22] = 27;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7);
+ emu->emu1010.output_source[23] = 28;
+
+ /* TEMP: Select SPDIF in/out */
+ snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */
+
+ /* TEMP: Select 48kHz SPDIF out */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */
+ /* Word Clock source, Internal 48kHz x1 */
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K );
+ //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X );
+ emu->emu1010.internal_clock = 1; /* 48000 */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */
+ //snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */
+ //snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */
+ //snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */
return 0;
}
@@ -747,6 +1081,10 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
}
snd_emu10k1_free_efx(emu);
}
+ if (emu->card_capabilities->emu1010) {
+ /* Disable 48Volt power to Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 );
+ }
if (emu->memhdr)
snd_util_memhdr_free(emu->memhdr);
if (emu->silent_page.area)
@@ -759,7 +1097,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
free_pm_buffer(emu);
#endif
if (emu->irq >= 0)
- free_irq(emu->irq, (void *)emu);
+ free_irq(emu->irq, emu);
if (emu->port)
pci_release_regions(emu->pci);
if (emu->card_capabilities->ca0151_chip) /* P16V */
@@ -838,10 +1176,11 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.adc_1361t = 1, /* 24 bit capture instead of 16bit */
.ac97_chip = 1} ,
/* Audigy 2 ZS Notebook Cardbus card.*/
- /* Tested by James@superbug.co.uk 22th December 2005 */
+ /* Tested by James@superbug.co.uk 6th November 2006 */
/* Audio output 7.1/Headphones working.
* Digital output working. (AC3 not checked, only PCM)
- * Audio inputs not tested.
+ * Audio Mic/Line inputs working.
+ * Digital input not tested.
*/
/* DSP: Tina2
* DAC: Wolfson WM8768/WM8568
@@ -849,6 +1188,25 @@ static struct snd_emu_chip_details emu_chip_details[] = {
* AC97: None
* CA0151: None
*/
+ /* Tested by James@superbug.co.uk 4th April 2006 */
+ /* A_IOCFG bits
+ * Output
+ * 0: Not Used
+ * 1: 0 = Mute all the 7.1 channel out. 1 = unmute.
+ * 2: Analog input 0 = line in, 1 = mic in
+ * 3: Not Used
+ * 4: Digital output 0 = off, 1 = on.
+ * 5: Not Used
+ * 6: Not Used
+ * 7: Not Used
+ * Input
+ * All bits 1 (0x3fxx) means nothing plugged in.
+ * 8-9: 0 = Line in/Mic, 2 = Optical in, 3 = Nothing.
+ * A-B: 0 = Headphones, 2 = Optical out, 3 = Nothing.
+ * C-D: 2 = Front/Rear/etc, 3 = nothing.
+ * E-F: Always 0
+ *
+ */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102,
.driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]",
.id = "Audigy2",
@@ -856,6 +1214,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.ca0108_chip = 1,
.ca_cardbus_chip = 1,
.spi_dac = 1,
+ .i2c_adc = 1,
.spk71 = 1} ,
{.vendor = 0x1102, .device = 0x0008,
.driver = "Audigy2", .name = "Audigy 2 Value [Unknown]",
@@ -865,11 +1224,12 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.ac97_chip = 1} ,
/* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
- .driver = "Audigy2", .name = "E-mu 1212m [4001]",
- .id = "EMU1212m",
+ .driver = "Audigy2", .name = "E-mu 1010 [4001]",
+ .id = "EMU1010",
.emu10k2_chip = 1,
.ca0102_chip = 1,
- .emu1212m = 1} ,
+ .spk71 = 1,
+ .emu1010 = 1} ,
/* Tested by James@superbug.co.uk 3rd July 2005 */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
.driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]",
@@ -1246,7 +1606,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
}
emu->port = pci_resource_start(pci, 0);
- if (request_irq(pci->irq, snd_emu10k1_interrupt, IRQF_DISABLED|IRQF_SHARED, "EMU10K1", (void *)emu)) {
+ if (request_irq(pci->irq, snd_emu10k1_interrupt, IRQF_SHARED,
+ "EMU10K1", emu)) {
err = -EBUSY;
goto error;
}
@@ -1296,8 +1657,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
} else if (emu->card_capabilities->ca_cardbus_chip) {
if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
goto error;
- } else if (emu->card_capabilities->emu1212m) {
- if ((err = snd_emu10k1_emu1212m_init(emu)) < 0) {
+ } else if (emu->card_capabilities->emu1010) {
+ if ((err = snd_emu10k1_emu1010_init(emu)) < 0) {
snd_emu10k1_free(emu);
return err;
}
@@ -1445,8 +1806,8 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu)
snd_emu10k1_ecard_init(emu);
else if (emu->card_capabilities->ca_cardbus_chip)
snd_emu10k1_cardbus_init(emu);
- else if (emu->card_capabilities->emu1212m)
- snd_emu10k1_emu1212m_init(emu);
+ else if (emu->card_capabilities->emu1010)
+ snd_emu10k1_emu1010_init(emu);
else
snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
snd_emu10k1_init(emu, emu->enable_ir, 1);
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index c46905a1117..bb0fec7f7e1 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -235,7 +235,7 @@ struct emu10k1x {
struct resource *res_port;
int irq;
- unsigned int revision; /* chip revision */
+ unsigned char revision; /* chip revision */
unsigned int serial; /* serial number */
unsigned short model; /* subsystem id */
@@ -460,7 +460,7 @@ static int snd_emu10k1x_pcm_prepare(struct snd_pcm_substream *substream)
u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size);
int i;
- for(i=0; i < runtime->periods; i++) {
+ for(i = 0; i < runtime->periods; i++) {
*table_base++=runtime->dma_addr+(i*period_size_bytes);
*table_base++=period_size_bytes<<16;
}
@@ -760,7 +760,7 @@ static int snd_emu10k1x_free(struct emu10k1x *chip)
// release the irq
if (chip->irq >= 0)
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, chip);
// release the DMA
if (chip->dma_buffer.area) {
@@ -927,8 +927,7 @@ static int __devinit snd_emu10k1x_create(struct snd_card *card,
}
if (request_irq(pci->irq, snd_emu10k1x_interrupt,
- IRQF_DISABLED|IRQF_SHARED, "EMU10K1X",
- (void *)chip)) {
+ IRQF_SHARED, "EMU10K1X", chip)) {
snd_printk(KERN_ERR "emu10k1x: cannot grab irq %d\n", pci->irq);
snd_emu10k1x_free(chip);
return -EBUSY;
@@ -943,7 +942,7 @@ static int __devinit snd_emu10k1x_create(struct snd_card *card,
pci_set_master(pci);
/* read revision & serial */
- pci_read_config_byte(pci, PCI_REVISION_ID, (char *)&chip->revision);
+ pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
snd_printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model,
@@ -1043,8 +1042,8 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry,
if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
continue;
- if ((reg < 0x49) && (reg >=0) && (val <= 0xffffffff)
- && (channel_id >=0) && (channel_id <= 2) )
+ if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff)
+ && (channel_id >= 0) && (channel_id <= 2) )
snd_emu10k1x_ptr_write(emu, reg, channel_id, val);
}
}
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 13cd6ce8981..c02012cccd8 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -3,6 +3,9 @@
* Creative Labs, Inc.
* Routines for effect processor FX8010
*
+ * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
+ * Added EMU 1010 support.
+ *
* BUGS:
* --
*
@@ -293,7 +296,7 @@ static const u32 db_table[101] = {
};
/* EMU10k1/EMU10k2 DSP control db gain */
-static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
+static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
static const u32 onoff_table[2] = {
0x00000000, 0x00000001
@@ -652,13 +655,66 @@ snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
return NULL;
}
+#define MAX_TLV_SIZE 256
+
+static unsigned int *copy_tlv(const unsigned int __user *_tlv)
+{
+ unsigned int data[2];
+ unsigned int *tlv;
+
+ if (!_tlv)
+ return NULL;
+ if (copy_from_user(data, _tlv, sizeof(data)))
+ return NULL;
+ if (data[1] >= MAX_TLV_SIZE)
+ return NULL;
+ tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL);
+ if (!tlv)
+ return NULL;
+ memcpy(tlv, data, sizeof(data));
+ if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
+ kfree(tlv);
+ return NULL;
+ }
+ return tlv;
+}
+
+static int copy_gctl(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_fx8010_control_gpr *gctl,
+ struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
+ int idx)
+{
+ struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
+
+ if (emu->support_tlv)
+ return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl));
+ octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
+ if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
+ return -EFAULT;
+ gctl->tlv = NULL;
+ return 0;
+}
+
+static int copy_gctl_to_user(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
+ struct snd_emu10k1_fx8010_control_gpr *gctl,
+ int idx)
+{
+ struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
+
+ if (emu->support_tlv)
+ return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl));
+
+ octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
+ return copy_to_user(&octl[idx], gctl, sizeof(*octl));
+}
+
static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
struct snd_emu10k1_fx8010_code *icode)
{
unsigned int i;
struct snd_ctl_elem_id __user *_id;
struct snd_ctl_elem_id id;
- struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
struct snd_emu10k1_fx8010_control_gpr *gctl;
int err;
@@ -673,9 +729,8 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
if (! gctl)
return -ENOMEM;
err = 0;
- for (i = 0, _gctl = icode->gpr_add_controls;
- i < icode->gpr_add_control_count; i++, _gctl++) {
- if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
+ for (i = 0; i < icode->gpr_add_control_count; i++) {
+ if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
err = -EFAULT;
goto __error;
}
@@ -694,10 +749,9 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
goto __error;
}
}
- for (i = 0, _gctl = icode->gpr_list_controls;
- i < icode->gpr_list_control_count; i++, _gctl++) {
+ for (i = 0; i < icode->gpr_list_control_count; i++) {
/* FIXME: we need to check the WRITE access */
- if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
+ if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) {
err = -EFAULT;
goto __error;
}
@@ -715,13 +769,14 @@ static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
kctl->private_value = 0;
list_del(&ctl->list);
kfree(ctl);
+ if (kctl->tlv.p)
+ kfree(kctl->tlv.p);
}
static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
struct snd_emu10k1_fx8010_code *icode)
{
unsigned int i, j;
- struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
struct snd_emu10k1_fx8010_control_gpr *gctl;
struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
struct snd_kcontrol_new knew;
@@ -737,9 +792,8 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
goto __error;
}
- for (i = 0, _gctl = icode->gpr_add_controls;
- i < icode->gpr_add_control_count; i++, _gctl++) {
- if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
+ for (i = 0; i < icode->gpr_add_control_count; i++) {
+ if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
err = -EFAULT;
goto __error;
}
@@ -760,11 +814,10 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
knew.device = gctl->id.device;
knew.subdevice = gctl->id.subdevice;
knew.info = snd_emu10k1_gpr_ctl_info;
- if (gctl->tlv.p) {
- knew.tlv.p = gctl->tlv.p;
+ knew.tlv.p = copy_tlv(gctl->tlv);
+ if (knew.tlv.p)
knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ;
- }
knew.get = snd_emu10k1_gpr_ctl_get;
knew.put = snd_emu10k1_gpr_ctl_put;
memset(nctl, 0, sizeof(*nctl));
@@ -782,12 +835,14 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
if (ctl == NULL) {
err = -ENOMEM;
+ kfree(knew.tlv.p);
goto __error;
}
knew.private_value = (unsigned long)ctl;
*ctl = *nctl;
if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
kfree(ctl);
+ kfree(knew.tlv.p);
goto __error;
}
kctl->private_free = snd_emu10k1_ctl_private_free;
@@ -838,7 +893,6 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
unsigned int i = 0, j;
unsigned int total = 0;
struct snd_emu10k1_fx8010_control_gpr *gctl;
- struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
struct snd_emu10k1_fx8010_ctl *ctl;
struct snd_ctl_elem_id *id;
struct list_head *list;
@@ -847,11 +901,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
if (! gctl)
return -ENOMEM;
- _gctl = icode->gpr_list_controls;
list_for_each(list, &emu->fx8010.gpr_ctl) {
ctl = emu10k1_gpr_ctl(list);
total++;
- if (_gctl && i < icode->gpr_list_control_count) {
+ if (icode->gpr_list_controls &&
+ i < icode->gpr_list_control_count) {
memset(gctl, 0, sizeof(*gctl));
id = &ctl->kcontrol->id;
gctl->id.iface = id->iface;
@@ -868,11 +922,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
gctl->min = ctl->min;
gctl->max = ctl->max;
gctl->translation = ctl->translation;
- if (copy_to_user(_gctl, gctl, sizeof(*gctl))) {
+ if (copy_gctl_to_user(emu, icode->gpr_list_controls,
+ gctl, i)) {
kfree(gctl);
return -EFAULT;
}
- _gctl++;
i++;
}
}
@@ -1023,7 +1077,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
ctl->min = 0;
ctl->max = 100;
- ctl->tlv.p = snd_emu10k1_db_scale1;
+ ctl->tlv = snd_emu10k1_db_scale1;
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
}
@@ -1038,7 +1092,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
ctl->min = 0;
ctl->max = 100;
- ctl->tlv.p = snd_emu10k1_db_scale1;
+ ctl->tlv = snd_emu10k1_db_scale1;
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
}
@@ -1069,6 +1123,21 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl
ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
}
+static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
+ struct snd_emu10k1_fx8010_code *icode,
+ u32 *ptr, int tmp, int bit_shifter16,
+ int reg_in, int reg_out)
+{
+ A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000);
+ A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000);
+ A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2));
+ A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000);
+ A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000);
+ A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000);
+ A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2));
+ A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000);
+ return 1;
+}
/*
* initial DSP configuration for Audigy
@@ -1077,6 +1146,7 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl
static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
{
int err, i, z, gpr, nctl;
+ int bit_shifter16;
const int playback = 10;
const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
const int stereo_mix = capture + 2;
@@ -1114,17 +1184,14 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
ptr = 0;
nctl = 0;
gpr = stereo_mix + 10;
+ gpr_map[gpr++] = 0x00007fff;
+ gpr_map[gpr++] = 0x00008000;
+ gpr_map[gpr++] = 0x0000ffff;
+ bit_shifter16 = gpr;
/* stop FX processor */
snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
-#if 0
- /* FIX: jcd test */
- for (z = 0; z < 80; z=z+2) {
- A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */
- A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */
- }
-#endif /* jcd test */
#if 1
/* PCM front Playback Volume (independent from stereo mix) */
A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
@@ -1182,13 +1249,20 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
gpr += 2;
-
+
/*
* inputs
*/
#define A_ADD_VOLUME_IN(var,vol,input) \
A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
+ /* emu1212 DSP 0 and DSP 1 Capture */
+ if (emu->card_capabilities->emu1010) {
+ A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
+ A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1));
+ snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
+ gpr += 2;
+ }
/* AC'97 Playback Volume - used only for mic (renamed later) */
A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
@@ -1429,6 +1503,13 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
/* digital outputs */
/* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
+ if (emu->card_capabilities->emu1010) {
+ /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
+ snd_printk("EMU outputs on\n");
+ for (z = 0; z < 8; z++) {
+ A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
+ }
+ }
/* IEC958 Optical Raw Playback Switch */
gpr_map[gpr++] = 0;
@@ -1466,9 +1547,57 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
#endif
- /* EFX capture - capture the 16 EXTINs */
- for (z = 0; z < 16; z++) {
- A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
+ if (emu->card_capabilities->emu1010) {
+ snd_printk("EMU inputs on\n");
+ /* Capture 8 channels of S32_LE sound */
+
+ /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */
+ /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
+ /* A_P16VIN(0) is delayed by one sample,
+ * so all other A_P16VIN channels will need to also be delayed
+ */
+ /* Left ADC in. 1 of 2 */
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
+ /* Right ADC in 1 of 2 */
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000);
+ /* For 96kHz mode */
+ /* Left ADC in. 2 of 2 */
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000);
+ /* Right ADC in 2 of 2 */
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
+
+#if 0
+ for (z = 4; z < 8; z++) {
+ A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
+ }
+ for (z = 0xc; z < 0x10; z++) {
+ A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
+ }
+#endif
+ } else {
+ /* EFX capture - capture the 16 EXTINs */
+ /* Capture 16 channels of S16_LE sound */
+ for (z = 0; z < 16; z++) {
+ A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
+ }
}
#endif /* JCD test */
@@ -1488,7 +1617,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
seg = snd_enter_user();
icode->gpr_add_control_count = nctl;
icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
+ emu->support_tlv = 1; /* support TLV */
err = snd_emu10k1_icode_poke(emu, icode);
+ emu->support_tlv = 0; /* clear again */
snd_leave_user(seg);
__err:
@@ -2105,7 +2236,9 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
seg = snd_enter_user();
icode->gpr_add_control_count = i;
icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
+ emu->support_tlv = 1; /* support TLV */
err = snd_emu10k1_icode_poke(emu, icode);
+ emu->support_tlv = 0; /* clear again */
snd_leave_user(seg);
if (err >= 0)
err = snd_emu10k1_ipcm_poke(emu, ipcm);
@@ -2138,7 +2271,7 @@ void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
}
-#if 0 // FIXME: who use them?
+#if 0 /* FIXME: who use them? */
int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
{
if (output < 0 || output >= 6)
@@ -2249,6 +2382,9 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un
int res;
switch (cmd) {
+ case SNDRV_EMU10K1_IOCTL_PVERSION:
+ emu->support_tlv = 1;
+ return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp);
case SNDRV_EMU10K1_IOCTL_INFO:
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index c31f3d0877f..4db6e1ca166 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -5,6 +5,9 @@
* Routines for control of EMU10K1 chips / mixer routines
* Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
*
+ * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
+ * Added EMU 1010 support.
+ *
* BUGS:
* --
*
@@ -32,9 +35,15 @@
#include <linux/init.h>
#include <sound/core.h>
#include <sound/emu10k1.h>
+#include <linux/delay.h>
+#include <sound/tlv.h>
+
+#include "p17v.h"
#define AC97_ID_STAC9758 0x83847658
+static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
+
static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
@@ -68,6 +77,669 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
return 0;
}
+static char *emu1010_src_texts[] = {
+ "Silence",
+ "Dock Mic A",
+ "Dock Mic B",
+ "Dock ADC1 Left",
+ "Dock ADC1 Right",
+ "Dock ADC2 Left",
+ "Dock ADC2 Right",
+ "Dock ADC3 Left",
+ "Dock ADC3 Right",
+ "0202 ADC Left",
+ "0202 ADC Right",
+ "0202 SPDIF Left",
+ "0202 SPDIF Right",
+ "ADAT 0",
+ "ADAT 1",
+ "ADAT 2",
+ "ADAT 3",
+ "ADAT 4",
+ "ADAT 5",
+ "ADAT 6",
+ "ADAT 7",
+ "DSP 0",
+ "DSP 1",
+ "DSP 2",
+ "DSP 3",
+ "DSP 4",
+ "DSP 5",
+ "DSP 6",
+ "DSP 7",
+ "DSP 8",
+ "DSP 9",
+ "DSP 10",
+ "DSP 11",
+ "DSP 12",
+ "DSP 13",
+ "DSP 14",
+ "DSP 15",
+ "DSP 16",
+ "DSP 17",
+ "DSP 18",
+ "DSP 19",
+ "DSP 20",
+ "DSP 21",
+ "DSP 22",
+ "DSP 23",
+ "DSP 24",
+ "DSP 25",
+ "DSP 26",
+ "DSP 27",
+ "DSP 28",
+ "DSP 29",
+ "DSP 30",
+ "DSP 31",
+};
+
+static unsigned int emu1010_src_regs[] = {
+ EMU_SRC_SILENCE,/* 0 */
+ EMU_SRC_DOCK_MIC_A1, /* 1 */
+ EMU_SRC_DOCK_MIC_B1, /* 2 */
+ EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */
+ EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */
+ EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */
+ EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */
+ EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */
+ EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */
+ EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */
+ EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */
+ EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */
+ EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */
+ EMU_SRC_HANA_ADAT, /* 13 */
+ EMU_SRC_HANA_ADAT+1, /* 14 */
+ EMU_SRC_HANA_ADAT+2, /* 15 */
+ EMU_SRC_HANA_ADAT+3, /* 16 */
+ EMU_SRC_HANA_ADAT+4, /* 17 */
+ EMU_SRC_HANA_ADAT+5, /* 18 */
+ EMU_SRC_HANA_ADAT+6, /* 19 */
+ EMU_SRC_HANA_ADAT+7, /* 20 */
+ EMU_SRC_ALICE_EMU32A, /* 21 */
+ EMU_SRC_ALICE_EMU32A+1, /* 22 */
+ EMU_SRC_ALICE_EMU32A+2, /* 23 */
+ EMU_SRC_ALICE_EMU32A+3, /* 24 */
+ EMU_SRC_ALICE_EMU32A+4, /* 25 */
+ EMU_SRC_ALICE_EMU32A+5, /* 26 */
+ EMU_SRC_ALICE_EMU32A+6, /* 27 */
+ EMU_SRC_ALICE_EMU32A+7, /* 28 */
+ EMU_SRC_ALICE_EMU32A+8, /* 29 */
+ EMU_SRC_ALICE_EMU32A+9, /* 30 */
+ EMU_SRC_ALICE_EMU32A+0xa, /* 31 */
+ EMU_SRC_ALICE_EMU32A+0xb, /* 32 */
+ EMU_SRC_ALICE_EMU32A+0xc, /* 33 */
+ EMU_SRC_ALICE_EMU32A+0xd, /* 34 */
+ EMU_SRC_ALICE_EMU32A+0xe, /* 35 */
+ EMU_SRC_ALICE_EMU32A+0xf, /* 36 */
+ EMU_SRC_ALICE_EMU32B, /* 37 */
+ EMU_SRC_ALICE_EMU32B+1, /* 38 */
+ EMU_SRC_ALICE_EMU32B+2, /* 39 */
+ EMU_SRC_ALICE_EMU32B+3, /* 40 */
+ EMU_SRC_ALICE_EMU32B+4, /* 41 */
+ EMU_SRC_ALICE_EMU32B+5, /* 42 */
+ EMU_SRC_ALICE_EMU32B+6, /* 43 */
+ EMU_SRC_ALICE_EMU32B+7, /* 44 */
+ EMU_SRC_ALICE_EMU32B+8, /* 45 */
+ EMU_SRC_ALICE_EMU32B+9, /* 46 */
+ EMU_SRC_ALICE_EMU32B+0xa, /* 47 */
+ EMU_SRC_ALICE_EMU32B+0xb, /* 48 */
+ EMU_SRC_ALICE_EMU32B+0xc, /* 49 */
+ EMU_SRC_ALICE_EMU32B+0xd, /* 50 */
+ EMU_SRC_ALICE_EMU32B+0xe, /* 51 */
+ EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
+};
+
+static unsigned int emu1010_output_dst[] = {
+ EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
+ EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
+ EMU_DST_DOCK_DAC2_LEFT1, /* 2 */
+ EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */
+ EMU_DST_DOCK_DAC3_LEFT1, /* 4 */
+ EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */
+ EMU_DST_DOCK_DAC4_LEFT1, /* 6 */
+ EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */
+ EMU_DST_DOCK_PHONES_LEFT1, /* 8 */
+ EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */
+ EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */
+ EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */
+ EMU_DST_HANA_SPDIF_LEFT1, /* 12 */
+ EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */
+ EMU_DST_HAMOA_DAC_LEFT1, /* 14 */
+ EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */
+ EMU_DST_HANA_ADAT, /* 16 */
+ EMU_DST_HANA_ADAT+1, /* 17 */
+ EMU_DST_HANA_ADAT+2, /* 18 */
+ EMU_DST_HANA_ADAT+3, /* 19 */
+ EMU_DST_HANA_ADAT+4, /* 20 */
+ EMU_DST_HANA_ADAT+5, /* 21 */
+ EMU_DST_HANA_ADAT+6, /* 22 */
+ EMU_DST_HANA_ADAT+7, /* 23 */
+};
+
+static unsigned int emu1010_input_dst[] = {
+ EMU_DST_ALICE2_EMU32_0,
+ EMU_DST_ALICE2_EMU32_1,
+ EMU_DST_ALICE2_EMU32_2,
+ EMU_DST_ALICE2_EMU32_3,
+ EMU_DST_ALICE2_EMU32_4,
+ EMU_DST_ALICE2_EMU32_5,
+ EMU_DST_ALICE2_EMU32_6,
+ EMU_DST_ALICE2_EMU32_7,
+ EMU_DST_ALICE2_EMU32_8,
+ EMU_DST_ALICE2_EMU32_9,
+ EMU_DST_ALICE2_EMU32_A,
+ EMU_DST_ALICE2_EMU32_B,
+ EMU_DST_ALICE2_EMU32_C,
+ EMU_DST_ALICE2_EMU32_D,
+ EMU_DST_ALICE2_EMU32_E,
+ EMU_DST_ALICE2_EMU32_F,
+ EMU_DST_ALICE_I2S0_LEFT,
+ EMU_DST_ALICE_I2S0_RIGHT,
+ EMU_DST_ALICE_I2S1_LEFT,
+ EMU_DST_ALICE_I2S1_RIGHT,
+ EMU_DST_ALICE_I2S2_LEFT,
+ EMU_DST_ALICE_I2S2_RIGHT,
+};
+
+static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 53;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ int channel;
+
+ channel = (kcontrol->private_value) & 0xff;
+ ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
+ return 0;
+}
+
+static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ int change = 0;
+ unsigned int val;
+ int channel;
+
+ channel = (kcontrol->private_value) & 0xff;
+ if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) {
+ val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0];
+ change = 1;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ emu1010_output_dst[channel], emu1010_src_regs[val]);
+ }
+ return change;
+}
+
+static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ int channel;
+
+ channel = (kcontrol->private_value) & 0xff;
+ ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
+ return 0;
+}
+
+static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ int change = 0;
+ unsigned int val;
+ int channel;
+
+ channel = (kcontrol->private_value) & 0xff;
+ if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) {
+ val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0];
+ change = 1;
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ emu1010_input_dst[channel], emu1010_src_regs[val]);
+ }
+ return change;
+}
+
+#define EMU1010_SOURCE_OUTPUT(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_emu1010_input_output_source_info, \
+ .get = snd_emu1010_output_source_get, \
+ .put = snd_emu1010_output_source_put, \
+ .private_value = chid \
+}
+
+static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
+ EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
+ EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
+ EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
+ EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
+ EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
+ EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
+ EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
+ EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
+ EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
+ EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
+ EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
+ EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
+ EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
+ EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
+ EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
+ EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
+ EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
+};
+
+#define EMU1010_SOURCE_INPUT(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_emu1010_input_output_source_info, \
+ .get = snd_emu1010_input_source_get, \
+ .put = snd_emu1010_input_source_put, \
+ .private_value = chid \
+}
+
+static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = {
+ EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
+ EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
+ EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
+ EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
+ EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
+ EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
+ EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
+ EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
+ EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
+ EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
+ EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
+ EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
+ EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
+ EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
+ EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
+ EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
+ EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
+ EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
+ EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
+ EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
+ EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
+ EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
+};
+
+
+
+
+static int snd_emu1010_adc_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = kcontrol->private_value & 0xff;
+ ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
+ return 0;
+}
+
+static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = kcontrol->private_value & 0xff;
+ unsigned int val, cache;
+ val = ucontrol->value.integer.value[0];
+ cache = emu->emu1010.adc_pads;
+ if (val == 1)
+ cache = cache | mask;
+ else
+ cache = cache & ~mask;
+ if (cache != emu->emu1010.adc_pads) {
+ snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
+ emu->emu1010.adc_pads = cache;
+ }
+
+ return 0;
+}
+
+
+
+#define EMU1010_ADC_PADS(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_emu1010_adc_pads_info, \
+ .get = snd_emu1010_adc_pads_get, \
+ .put = snd_emu1010_adc_pads_put, \
+ .private_value = chid \
+}
+
+static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = {
+ EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
+ EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
+ EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
+ EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
+};
+
+static int snd_emu1010_dac_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = kcontrol->private_value & 0xff;
+ ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
+ return 0;
+}
+
+static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = kcontrol->private_value & 0xff;
+ unsigned int val, cache;
+ val = ucontrol->value.integer.value[0];
+ cache = emu->emu1010.dac_pads;
+ if (val == 1)
+ cache = cache | mask;
+ else
+ cache = cache & ~mask;
+ if (cache != emu->emu1010.dac_pads) {
+ snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
+ emu->emu1010.dac_pads = cache;
+ }
+
+ return 0;
+}
+
+
+
+#define EMU1010_DAC_PADS(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_emu1010_dac_pads_info, \
+ .get = snd_emu1010_dac_pads_get, \
+ .put = snd_emu1010_dac_pads_put, \
+ .private_value = chid \
+}
+
+static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = {
+ EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
+ EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
+ EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
+ EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
+ EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
+};
+
+
+static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[2] = {
+ "44100", "48000"
+ };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
+ return 0;
+}
+
+static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ int change = 0;
+
+ val = ucontrol->value.enumerated.item[0] ;
+ change = (emu->emu1010.internal_clock != val);
+ if (change) {
+ emu->emu1010.internal_clock = val;
+ switch (val) {
+ case 0:
+ /* 44100 */
+ /* Mute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
+ /* Default fallback clock 48kHz */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
+ /* Word Clock source, Internal 44.1kHz x1 */
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
+ EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
+ /* Set LEDs on Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
+ EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
+ /* Allow DLL to settle */
+ msleep(10);
+ /* Unmute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
+ break;
+ case 1:
+ /* 48000 */
+ /* Mute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
+ /* Default fallback clock 48kHz */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
+ /* Word Clock source, Internal 48kHz x1 */
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
+ EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
+ /* Set LEDs on Audio Dock */
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
+ EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
+ /* Allow DLL to settle */
+ msleep(10);
+ /* Unmute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
+ break;
+ }
+ }
+ return change;
+}
+
+static struct snd_kcontrol_new snd_emu1010_internal_clock =
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Clock Internal Rate",
+ .count = 1,
+ .info = snd_emu1010_internal_clock_info,
+ .get = snd_emu1010_internal_clock_get,
+ .put = snd_emu1010_internal_clock_put
+};
+
+static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+#if 0
+ static char *texts[4] = {
+ "Unknown1", "Unknown2", "Mic", "Line"
+ };
+#endif
+ static char *texts[2] = {
+ "Mic", "Line"
+ };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
+ return 0;
+}
+
+static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int source_id;
+ unsigned int ngain, ogain;
+ u32 gpio;
+ int change = 0;
+ unsigned long flags;
+ u32 source;
+ /* If the capture source has changed,
+ * update the capture volume from the cached value
+ * for the particular source.
+ */
+ source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */
+ change = (emu->i2c_capture_source != source_id);
+ if (change) {
+ snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ gpio = inl(emu->port + A_IOCFG);
+ if (source_id==0)
+ outl(gpio | 0x4, emu->port + A_IOCFG);
+ else
+ outl(gpio & ~0x4, emu->port + A_IOCFG);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+
+ ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
+ ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
+ if (ngain != ogain)
+ snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
+ ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
+ ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
+ if (ngain != ogain)
+ snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
+
+ source = 1 << (source_id + 2);
+ snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
+ emu->i2c_capture_source = source_id;
+ }
+ return change;
+}
+
+static struct snd_kcontrol_new snd_audigy_i2c_capture_source =
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = snd_audigy_i2c_capture_source_info,
+ .get = snd_audigy_i2c_capture_source_get,
+ .put = snd_audigy_i2c_capture_source_put
+};
+
+static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 255;
+ return 0;
+}
+
+static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ int source_id;
+
+ source_id = kcontrol->private_value;
+
+ ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
+ ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
+ return 0;
+}
+
+static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int ogain;
+ unsigned int ngain;
+ int source_id;
+ int change = 0;
+
+ source_id = kcontrol->private_value;
+ ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
+ ngain = ucontrol->value.integer.value[0];
+ if (ngain > 0xff)
+ return 0;
+ if (ogain != ngain) {
+ if (emu->i2c_capture_source == source_id)
+ snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
+ emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
+ change = 1;
+ }
+ ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
+ ngain = ucontrol->value.integer.value[1];
+ if (ngain > 0xff)
+ return 0;
+ if (ogain != ngain) {
+ if (emu->i2c_capture_source == source_id)
+ snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
+ emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
+ change = 1;
+ }
+
+ return change;
+}
+
+#define I2C_VOLUME(xname,chid) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = snd_audigy_i2c_volume_info, \
+ .get = snd_audigy_i2c_volume_get, \
+ .put = snd_audigy_i2c_volume_put, \
+ .tlv = { .p = snd_audigy_db_scale2 }, \
+ .private_value = chid \
+}
+
+
+static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = {
+ I2C_VOLUME("Mic Capture Volume", 0),
+ I2C_VOLUME("Line Capture Volume", 0)
+};
+
#if 0
static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
@@ -668,7 +1340,9 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
int change = 0;
spin_lock_irqsave(&emu->reg_lock, flags);
- if (emu->audigy) {
+ if ( emu->card_capabilities->i2c_adc) {
+ /* Do nothing for Audigy 2 ZS Notebook */
+ } else if (emu->audigy) {
reg = inl(emu->port + A_IOCFG);
val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
change = (reg & A_IOCFG_GPOUT0) != val;
@@ -806,6 +1480,24 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
"AMic Playback Volume", "Mic Playback Volume",
NULL
};
+ static char *audigy_rename_ctls_i2c_adc[] = {
+ //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
+ "Line Capture Volume", "Analog Mix Capture Volume",
+ "Wave Playback Volume", "OLD PCM Playback Volume",
+ "Wave Master Playback Volume", "Master Playback Volume",
+ "AMic Playback Volume", "Old Mic Playback Volume",
+ "CD Capture Volume", "IEC958 Optical Capture Volume",
+ NULL
+ };
+ static char *audigy_remove_ctls_i2c_adc[] = {
+ /* On the Audigy2 ZS Notebook
+ * Capture via WM8775 */
+ "Mic Capture Volume",
+ "Analog Mix Capture Volume",
+ "Aux Capture Volume",
+ "IEC958 Optical Capture Volume",
+ NULL
+ };
static char *audigy_remove_ctls_1361t_adc[] = {
/* On the Audigy2 the AC97 playback is piped into
* the Philips ADC for 24bit capture */
@@ -890,6 +1582,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
if (emu->ac97->id == AC97_ID_STAC9758) {
emu->rear_ac97 = 1;
snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
+ snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
}
/* remove unused AC97 controls */
snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
@@ -898,6 +1591,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
}
for (; *c; c++)
remove_ctl(card, *c);
+ } else if (emu->card_capabilities->i2c_adc) {
+ c = audigy_remove_ctls_i2c_adc;
+ for (; *c; c++)
+ remove_ctl(card, *c);
} else {
no_ac97:
if (emu->card_capabilities->ecard)
@@ -911,6 +1608,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
if (emu->audigy)
if (emu->card_capabilities->adc_1361t)
c = audigy_rename_ctls_1361t_adc;
+ else if (emu->card_capabilities->i2c_adc)
+ c = audigy_rename_ctls_i2c_adc;
else
c = audigy_rename_ctls;
else
@@ -1021,7 +1720,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
return err;
}
- if ( emu->card_capabilities->emu1212m) {
+ if ( emu->card_capabilities->emu1010) {
; /* Disable the snd_audigy_spdif_shared_spdif */
} else if (emu->audigy) {
if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
@@ -1045,6 +1744,48 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
if ((err = snd_p16v_mixer(emu)))
return err;
}
+
+ if ( emu->card_capabilities->emu1010) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu));
+ if (err < 0)
+ return err;
+ }
+ for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu));
+ if (err < 0)
+ return err;
+ }
+ for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
+ if (err < 0)
+ return err;
+ }
+ for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
+ if (err < 0)
+ return err;
+ }
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu));
+ if (err < 0)
+ return err;
+ }
+
+ if ( emu->card_capabilities->i2c_adc) {
+ int i;
+
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
+ if (err < 0)
+ return err;
+ }
+ }
return 0;
}
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 717e92ec9e0..ab4f5df5241 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -147,7 +147,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic
1,
&epcm->extra);
if (err < 0) {
- // printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame);
+ /* printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); */
for (i = 0; i < voices; i++) {
snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
epcm->voices[i] = NULL;
@@ -339,7 +339,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
}
}
- // setup routing
+ /* setup routing */
if (emu->audigy) {
snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
snd_emu10k1_compose_audigy_fxrt1(send_routing));
@@ -353,12 +353,15 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
} else
snd_emu10k1_ptr_write(emu, FXRT, voice,
snd_emu10k1_compose_send_routing(send_routing));
- // Stop CA
- // Assumption that PT is already 0 so no harm overwriting
+ /* Stop CA */
+ /* Assumption that PT is already 0 so no harm overwriting */
snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]);
snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24));
snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24));
- pitch_target = emu10k1_calc_pitch_target(runtime->rate);
+ if (emu->card_capabilities->emu1010)
+ pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
+ else
+ pitch_target = emu10k1_calc_pitch_target(runtime->rate);
if (extra)
snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr |
emu10k1_select_interprom(pitch_target) |
@@ -367,14 +370,14 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) |
emu10k1_select_interprom(pitch_target) |
(w_16 ? 0 : CCCA_8BITSELECT));
- // Clear filter delay memory
+ /* Clear filter delay memory */
snd_emu10k1_ptr_write(emu, Z1, voice, 0);
snd_emu10k1_ptr_write(emu, Z2, voice, 0);
- // invalidate maps
+ /* invalidate maps */
silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK;
snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page);
snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page);
- // modulation envelope
+ /* modulation envelope */
snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff);
snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff);
snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0);
@@ -385,12 +388,12 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0);
snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0);
snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000);
- // volume envelope
+ /* volume envelope */
snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f);
snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000);
- // filter envelope
+ /* filter envelope */
snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f);
- // pitch envelope
+ /* pitch envelope */
snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0);
spin_unlock_irqrestore(&emu->reg_lock, flags);
@@ -468,7 +471,7 @@ static int snd_emu10k1_efx_playback_hw_free(struct snd_pcm_substream *substream)
snd_emu10k1_voice_free(epcm->emu, epcm->extra);
epcm->extra = NULL;
}
- for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+ for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
if (epcm->voices[i]) {
snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
epcm->voices[i] = NULL;
@@ -637,7 +640,7 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e
stereo = (!extra && runtime->channels == 2);
sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080;
ccis = emu10k1_ccis(stereo, sample == 0);
- // set cs to 2 * number of cache registers beside the invalidated
+ /* set cs to 2 * number of cache registers beside the invalidated */
cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1;
if (cs > 16) cs = 16;
for (i = 0; i < cs; i++) {
@@ -646,14 +649,14 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e
snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample);
}
}
- // reset cache
+ /* reset cache */
snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0);
snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra);
if (stereo) {
snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0);
snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra);
}
- // fill cache
+ /* fill cache */
snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis);
if (stereo) {
snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis);
@@ -698,7 +701,10 @@ static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct s
voice = evoice->number;
pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8;
- pitch_target = emu10k1_calc_pitch_target(runtime->rate);
+ if (emu->card_capabilities->emu1010)
+ pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
+ else
+ pitch_target = emu10k1_calc_pitch_target(runtime->rate);
snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target);
if (master || evoice->epcm->type == PLAYBACK_EFX)
snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target);
@@ -732,7 +738,7 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
struct snd_emu10k1_pcm_mixer *mix;
int result = 0;
- // printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream));
+ /* printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); */
spin_lock(&emu->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -778,10 +784,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
- // hmm this should cause full and half full interrupt to be raised?
+ /* hmm this should cause full and half full interrupt to be raised? */
outl(epcm->capture_ipr, emu->port + IPR);
snd_emu10k1_intr_enable(emu, epcm->capture_inte);
- // printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs);
+ /* printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); */
switch (epcm->type) {
case CAPTURE_AC97ADC:
snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val);
@@ -790,6 +796,7 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
if (emu->audigy) {
snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val);
snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2);
+ snd_printdd("cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, epcm->capture_cr_val2);
} else
snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val);
break;
@@ -851,7 +858,7 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *
ptr -= runtime->buffer_size;
}
#endif
- // printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size);
+ /* printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); */
return ptr;
}
@@ -868,7 +875,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
spin_lock(&emu->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- // prepare voices
+ /* prepare voices */
for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]);
}
@@ -917,7 +924,7 @@ static snd_pcm_uframes_t snd_emu10k1_capture_pointer(struct snd_pcm_substream *s
if (!epcm->running)
return 0;
if (epcm->first_ptr) {
- udelay(50); // hack, it takes awhile until capture is started
+ udelay(50); /* hack, it takes awhile until capture is started */
epcm->first_ptr = 0;
}
ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff;
@@ -972,6 +979,28 @@ static struct snd_pcm_hardware snd_emu10k1_capture =
.fifo_size = 0,
};
+static struct snd_pcm_hardware snd_emu10k1_capture_efx =
+{
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+ .rate_min = 44100,
+ .rate_max = 192000,
+ .channels_min = 8,
+ .channels_max = 8,
+ .buffer_bytes_max = (64*1024),
+ .period_bytes_min = 384,
+ .period_bytes_max = (64*1024),
+ .periods_min = 2,
+ .periods_max = 2,
+ .fifo_size = 0,
+};
+
/*
*
*/
@@ -1016,7 +1045,7 @@ static int snd_emu10k1_efx_playback_close(struct snd_pcm_substream *substream)
struct snd_emu10k1_pcm_mixer *mix;
int i;
- for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+ for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
mix = &emu->efx_pcm_mixer[i];
mix->epcm = NULL;
snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0);
@@ -1045,7 +1074,7 @@ static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_efx_playback;
- for (i=0; i < NUM_EFX_PLAYBACK; i++) {
+ for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
mix = &emu->efx_pcm_mixer[i];
mix->send_routing[0][0] = i;
memset(&mix->send_volume, 0, sizeof(mix->send_volume));
@@ -1199,15 +1228,69 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
epcm->capture_idx_reg = FXIDX;
substream->runtime->private_data = epcm;
substream->runtime->private_free = snd_emu10k1_pcm_free_substream;
- runtime->hw = snd_emu10k1_capture;
+ runtime->hw = snd_emu10k1_capture_efx;
runtime->hw.rates = SNDRV_PCM_RATE_48000;
runtime->hw.rate_min = runtime->hw.rate_max = 48000;
spin_lock_irq(&emu->reg_lock);
- runtime->hw.channels_min = runtime->hw.channels_max = 0;
- for (idx = 0; idx < nefx; idx++) {
- if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) {
- runtime->hw.channels_min++;
- runtime->hw.channels_max++;
+ if (emu->card_capabilities->emu1010) {
+ /* TODO
+ * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
+ * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000
+ * rate_min = 44100,
+ * rate_max = 192000,
+ * channels_min = 8,
+ * channels_max = 8,
+ * Need to add mixer control to fix sample rate
+ *
+ * There are 16 mono channels of 16bits each.
+ * 24bit Audio uses 2x channels over 16bit
+ * 96kHz uses 2x channels over 48kHz
+ * 192kHz uses 4x channels over 48kHz
+ * So, for 48kHz 24bit, one has 8 channels
+ * for 96kHz 24bit, one has 4 channels
+ * for 192kHz 24bit, one has 2 channels
+ */
+#if 1
+ switch (emu->emu1010.internal_clock) {
+ case 0:
+ /* For 44.1kHz */
+ runtime->hw.rates = SNDRV_PCM_RATE_44100;
+ runtime->hw.rate_min = runtime->hw.rate_max = 44100;
+ runtime->hw.channels_min = runtime->hw.channels_max = 8;
+ break;
+ case 1:
+ /* For 48kHz */
+ runtime->hw.rates = SNDRV_PCM_RATE_48000;
+ runtime->hw.rate_min = runtime->hw.rate_max = 48000;
+ runtime->hw.channels_min = runtime->hw.channels_max = 8;
+ break;
+ };
+#endif
+#if 0
+ /* For 96kHz */
+ runtime->hw.rates = SNDRV_PCM_RATE_96000;
+ runtime->hw.rate_min = runtime->hw.rate_max = 96000;
+ runtime->hw.channels_min = runtime->hw.channels_max = 4;
+#endif
+#if 0
+ /* For 192kHz */
+ runtime->hw.rates = SNDRV_PCM_RATE_192000;
+ runtime->hw.rate_min = runtime->hw.rate_max = 192000;
+ runtime->hw.channels_min = runtime->hw.channels_max = 2;
+#endif
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
+ /* efx_voices_mask[0] is expected to be zero
+ * efx_voices_mask[1] is expected to have 16bits set
+ */
+ } else {
+ runtime->hw.channels_min = runtime->hw.channels_max = 0;
+ for (idx = 0; idx < nefx; idx++) {
+ if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) {
+ runtime->hw.channels_min++;
+ runtime->hw.channels_max++;
+ }
}
}
epcm->capture_cr_val = emu->efx_voices_mask[0];
@@ -1460,7 +1543,7 @@ static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left,
unsigned int count,
unsigned int tram_shift)
{
- // printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count);
+ /* printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); */
if ((tram_shift & 1) == 0) {
while (count--) {
*dst_left-- = *src++;
@@ -1537,7 +1620,7 @@ static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substre
struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
unsigned int i;
- // printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2);
+ /* printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); */
memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec));
pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */
pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index b939e03aaed..2c1585991bc 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -3,6 +3,9 @@
* Creative Labs, Inc.
* Routines for control of EMU10K1 chips / proc interface routines
*
+ * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
+ * Added EMU 1010 support.
+ *
* BUGS:
* --
*
@@ -255,7 +258,7 @@ static void snd_emu10k1_proc_rates_read(struct snd_info_entry *entry,
unsigned int val, tmp, n;
val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0);
tmp = (val >> 16) & 0x8;
- for (n=0;n<4;n++) {
+ for (n = 0; n < 4; n++) {
tmp = val >> (16 + (n*4));
if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]);
else snd_iprintf(buffer, "Channel %d: No input\n", n);
@@ -372,6 +375,27 @@ static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry,
}
#ifdef CONFIG_SND_DEBUG
+static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_emu10k1 *emu = entry->private_data;
+ unsigned long value;
+ unsigned long flags;
+ unsigned long regs;
+ int i;
+ snd_iprintf(buffer, "EMU1010 Registers:\n\n");
+
+ for(i = 0; i < 0x30; i+=1) {
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ regs=i+0x40; /* 0x40 upwards are registers. */
+ outl(regs, emu->port + A_IOCFG);
+ outl(regs | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
+ value = inl(emu->port + A_IOCFG);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+ snd_iprintf(buffer, "%02X: %08lX, %02lX\n", i, value, (value >> 8) & 0x7f);
+ }
+}
+
static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
@@ -398,7 +422,7 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry,
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%x %x", &reg, &val) != 2)
continue;
- if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) {
+ if ((reg < 0x40) && (reg >= 0) && (val <= 0xffffffff) ) {
spin_lock_irqsave(&emu->emu_lock, flags);
outl(val, emu->port + (reg & 0xfffffffc));
spin_unlock_irqrestore(&emu->emu_lock, flags);
@@ -474,7 +498,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry,
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
continue;
- if ((reg < 0xa0) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) )
+ if ((reg < 0xa0) && (reg >= 0) && (val <= 0xffffffff) && (channel_id >= 0) && (channel_id <= 3) )
snd_ptr_write(emu, iobase, reg, channel_id, val);
}
}
@@ -531,6 +555,10 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu)
{
struct snd_info_entry *entry;
#ifdef CONFIG_SND_DEBUG
+ if ((emu->card_capabilities->emu1010) &&
+ snd_card_proc_new(emu->card, "emu1010_regs", &entry)) {
+ snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read);
+ }
if (! snd_card_proc_new(emu->card, "io_regs", &entry)) {
snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read);
entry->c.text.write = snd_emu_proc_io_reg_write;
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index 029e7856c43..116e1c8d936 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -30,6 +30,7 @@
#include <sound/core.h>
#include <sound/emu10k1.h>
#include <linux/delay.h>
+#include "p17v.h"
unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
{
@@ -167,6 +168,109 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
return 0;
}
+/* The ADC does not support i2c read, so only write is implemented */
+int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
+ u32 reg,
+ u32 value)
+{
+ u32 tmp;
+ int timeout = 0;
+ int status;
+ int retry;
+ if ((reg > 0x7f) || (value > 0x1ff)) {
+ snd_printk(KERN_ERR "i2c_write: invalid values.\n");
+ return -EINVAL;
+ }
+
+ tmp = reg << 25 | value << 16;
+ // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
+ /* Not sure what this I2C channel controls. */
+ /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */
+
+ /* This controls the I2C connected to the WM8775 ADC Codec */
+ snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
+ tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
+
+ for (retry = 0; retry < 10; retry++) {
+ /* Send the data to i2c */
+ //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
+ //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
+ tmp = 0;
+ tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
+ snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
+
+ /* Wait till the transaction ends */
+ while (1) {
+ udelay(10);
+ status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
+ // snd_printk("I2C:status=0x%x\n", status);
+ timeout++;
+ if ((status & I2C_A_ADC_START) == 0)
+ break;
+
+ if (timeout > 1000) {
+ snd_printk("emu10k1:I2C:timeout status=0x%x\n", status);
+ break;
+ }
+ }
+ //Read back and see if the transaction is successful
+ if ((status & I2C_A_ADC_ABORT) == 0)
+ break;
+ }
+
+ if (retry == 10) {
+ snd_printk(KERN_ERR "Writing to ADC failed!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value)
+{
+ if (reg < 0 || reg > 0x3f)
+ return 1;
+ reg += 0x40; /* 0x40 upwards are registers. */
+ if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
+ return 1;
+ outl(reg, emu->port + A_IOCFG);
+ udelay(10);
+ outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
+ udelay(10);
+ outl(value, emu->port + A_IOCFG);
+ udelay(10);
+ outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
+
+ return 0;
+}
+
+int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value)
+{
+ if (reg < 0 || reg > 0x3f)
+ return 1;
+ reg += 0x40; /* 0x40 upwards are registers. */
+ outl(reg, emu->port + A_IOCFG);
+ udelay(10);
+ outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
+ udelay(10);
+ *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
+
+ return 0;
+}
+
+/* Each Destination has one and only one Source,
+ * but one Source can feed any number of Destinations simultaneously.
+ */
+int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src)
+{
+ snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
+ snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
+ snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
+ snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
+
+ return 0;
+}
+
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
{
unsigned long flags;
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index 4e0f95438f4..465f8d50532 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -253,7 +253,7 @@ static int snd_p16v_pcm_close_playback(struct snd_pcm_substream *substream)
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
//struct snd_pcm_runtime *runtime = substream->runtime;
//struct snd_emu10k1_pcm *epcm = runtime->private_data;
- emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0;
+ emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use = 0;
/* FIXME: maybe zero others */
return 0;
}
@@ -264,7 +264,7 @@ static int snd_p16v_pcm_close_capture(struct snd_pcm_substream *substream)
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
//struct snd_pcm_runtime *runtime = substream->runtime;
//struct snd_emu10k1_pcm *epcm = runtime->private_data;
- emu->p16v_capture_voice.use=0;
+ emu->p16v_capture_voice.use = 0;
/* FIXME: maybe zero others */
return 0;
}
@@ -349,7 +349,7 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream)
break;
}
/* FIXME: Check emu->buffer.size before actually writing to it. */
- for(i=0; i < runtime->periods; i++) {
+ for(i = 0; i < runtime->periods; i++) {
table_base[i*2]=runtime->dma_addr+(i*period_size_bytes);
table_base[(i*2)+1]=period_size_bytes<<16;
}
@@ -394,7 +394,7 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream)
/* FIXME: Check emu->buffer.size before actually writing to it. */
snd_emu10k1_ptr20_write(emu, 0x13, channel, 0);
snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);
- snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes
+ snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size) << 16); // buffer size in bytes
snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0);
//snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */
//snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel));
@@ -437,7 +437,7 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream,
struct snd_pcm_substream *s;
u32 basic = 0;
u32 inte = 0;
- int running=0;
+ int running = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -445,7 +445,7 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_TRIGGER_STOP:
default:
- running=0;
+ running = 0;
break;
}
snd_pcm_group_for_each(pos, substream) {
@@ -785,7 +785,7 @@ static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol,
}
return change;
}
-static DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1);
+static const DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1);
#define P16V_VOL(xname,xreg,xhl) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h
index 7ddb5be632c..4ef5f68a9cd 100644
--- a/sound/pci/emu10k1/p17v.h
+++ b/sound/pci/emu10k1/p17v.h
@@ -43,6 +43,53 @@
#define P17V_I2C_ADDR 0x3d /* I2C Address */
#define P17V_I2C_0 0x3e /* I2C Data */
#define P17V_I2C_1 0x3f /* I2C Data */
+/* I2C values */
+#define I2C_A_ADC_ADD_MASK 0x000000fe /*The address is a 7 bit address */
+#define I2C_A_ADC_RW_MASK 0x00000001 /*bit mask for R/W */
+#define I2C_A_ADC_TRANS_MASK 0x00000010 /*Bit mask for I2c address DAC value */
+#define I2C_A_ADC_ABORT_MASK 0x00000020 /*Bit mask for I2C transaction abort flag */
+#define I2C_A_ADC_LAST_MASK 0x00000040 /*Bit mask for Last word transaction */
+#define I2C_A_ADC_BYTE_MASK 0x00000080 /*Bit mask for Byte Mode */
+
+#define I2C_A_ADC_ADD 0x00000034 /*This is the Device address for ADC */
+#define I2C_A_ADC_READ 0x00000001 /*To perform a read operation */
+#define I2C_A_ADC_START 0x00000100 /*Start I2C transaction */
+#define I2C_A_ADC_ABORT 0x00000200 /*I2C transaction abort */
+#define I2C_A_ADC_LAST 0x00000400 /*I2C last transaction */
+#define I2C_A_ADC_BYTE 0x00000800 /*I2C one byte mode */
+
+#define I2C_D_ADC_REG_MASK 0xfe000000 /*ADC address register */
+#define I2C_D_ADC_DAT_MASK 0x01ff0000 /*ADC data register */
+
+#define ADC_TIMEOUT 0x00000007 /*ADC Timeout Clock Disable */
+#define ADC_IFC_CTRL 0x0000000b /*ADC Interface Control */
+#define ADC_MASTER 0x0000000c /*ADC Master Mode Control */
+#define ADC_POWER 0x0000000d /*ADC PowerDown Control */
+#define ADC_ATTEN_ADCL 0x0000000e /*ADC Attenuation ADCL */
+#define ADC_ATTEN_ADCR 0x0000000f /*ADC Attenuation ADCR */
+#define ADC_ALC_CTRL1 0x00000010 /*ADC ALC Control 1 */
+#define ADC_ALC_CTRL2 0x00000011 /*ADC ALC Control 2 */
+#define ADC_ALC_CTRL3 0x00000012 /*ADC ALC Control 3 */
+#define ADC_NOISE_CTRL 0x00000013 /*ADC Noise Gate Control */
+#define ADC_LIMIT_CTRL 0x00000014 /*ADC Limiter Control */
+#define ADC_MUX 0x00000015 /*ADC Mux offset */
+#if 0
+/* FIXME: Not tested yet. */
+#define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain
+#define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB
+#define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute
+#define ADC_MUTE 0x000000c0 //Value to mute ADC
+#define ADC_OSR 0x00000008 //Mask for ADC oversample rate select
+#define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock
+#define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter
+#define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window
+#endif
+
+#define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux
+#define ADC_MUX_0 0x00000001 //Value to select Unknown at ADC Mux (Not used)
+#define ADC_MUX_1 0x00000002 //Value to select Unknown at ADC Mux (Not used)
+#define ADC_MUX_2 0x00000004 //Value to select Mic at ADC Mux
+#define ADC_MUX_3 0x00000008 //Value to select Line-In at ADC Mux
#define P17V_START_AUDIO 0x40 /* Start Audio bit */
/* 41 - 47: Reserved */
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c
index 94eca82dd4f..1db50fe6147 100644
--- a/sound/pci/emu10k1/voice.c
+++ b/sound/pci/emu10k1/voice.c
@@ -83,7 +83,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
if (first_voice == last_voice)
return -ENOMEM;
- for (i=0; i < number; i++) {
+ for (i = 0; i < number; i++) {
voice = &emu->voices[(first_voice + i) % NUM_G];
// printk("voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number);
voice->use = 1;
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index d2a811f222c..425b167522d 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -413,8 +413,6 @@ struct ensoniq {
} u;
struct pci_dev *pci;
- unsigned short subsystem_vendor_id;
- unsigned short subsystem_device_id;
struct snd_card *card;
struct snd_pcm *pcm1; /* DAC1/ADC PCM */
struct snd_pcm *pcm2; /* DAC2 PCM */
@@ -1607,11 +1605,26 @@ static void snd_ensoniq_mixer_free_ac97(struct snd_ac97 *ac97)
ensoniq->u.es1371.ac97 = NULL;
}
-static struct {
+struct es1371_quirk {
unsigned short vid; /* vendor ID */
unsigned short did; /* device ID */
unsigned char rev; /* revision */
-} es1371_spdif_present[] __devinitdata = {
+};
+
+static int __devinit es1371_quirk_lookup(struct ensoniq *ensoniq,
+ struct es1371_quirk *list)
+{
+ while (list->vid != (unsigned short)PCI_ANY_ID) {
+ if (ensoniq->pci->vendor == list->vid &&
+ ensoniq->pci->device == list->did &&
+ ensoniq->rev == list->rev)
+ return 1;
+ list++;
+ }
+ return 0;
+}
+
+static struct es1371_quirk es1371_spdif_present[] __devinitdata = {
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },
@@ -1620,12 +1633,19 @@ static struct {
{ .vid = PCI_ANY_ID, .did = PCI_ANY_ID }
};
-static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int has_line)
+static struct snd_pci_quirk ens1373_line_quirk[] __devinitdata = {
+ SND_PCI_QUIRK_ID(0x1274, 0x2000), /* GA-7DXR */
+ SND_PCI_QUIRK_ID(0x1458, 0xa000), /* GA-8IEXP */
+ { } /* end */
+};
+
+static int __devinit snd_ensoniq_1371_mixer(struct ensoniq *ensoniq,
+ int has_spdif, int has_line)
{
struct snd_card *card = ensoniq->card;
struct snd_ac97_bus *pbus;
struct snd_ac97_template ac97;
- int err, idx;
+ int err;
static struct snd_ac97_bus_ops ops = {
.write = snd_es1371_codec_write,
.read = snd_es1371_codec_read,
@@ -1641,33 +1661,28 @@ static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int h
ac97.scaps = AC97_SCAP_AUDIO;
if ((err = snd_ac97_mixer(pbus, &ac97, &ensoniq->u.es1371.ac97)) < 0)
return err;
- for (idx = 0; es1371_spdif_present[idx].vid != (unsigned short)PCI_ANY_ID; idx++)
- if ((ensoniq->pci->vendor == es1371_spdif_present[idx].vid &&
- ensoniq->pci->device == es1371_spdif_present[idx].did &&
- ensoniq->rev == es1371_spdif_present[idx].rev) || has_spdif > 0) {
- struct snd_kcontrol *kctl;
- int i, index = 0;
-
- if (has_spdif < 0)
- break;
-
- ensoniq->spdif_default = ensoniq->spdif_stream =
- SNDRV_PCM_DEFAULT_CON_SPDIF;
- outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS));
-
- if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF)
- index++;
-
- for (i = 0; i < (int)ARRAY_SIZE(snd_es1371_mixer_spdif); i++) {
- kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq);
- if (! kctl)
- return -ENOMEM;
- kctl->id.index = index;
- if ((err = snd_ctl_add(card, kctl)) < 0)
- return err;
- }
- break;
+ if (has_spdif > 0 ||
+ (!has_spdif && es1371_quirk_lookup(ensoniq, es1371_spdif_present))) {
+ struct snd_kcontrol *kctl;
+ int i, index = 0;
+
+ ensoniq->spdif_default = ensoniq->spdif_stream =
+ SNDRV_PCM_DEFAULT_CON_SPDIF;
+ outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS));
+
+ if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF)
+ index++;
+
+ for (i = 0; i < ARRAY_SIZE(snd_es1371_mixer_spdif); i++) {
+ kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->id.index = index;
+ err = snd_ctl_add(card, kctl);
+ if (err < 0)
+ return err;
}
+ }
if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SDAC) {
/* mirror rear to front speakers */
ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT24);
@@ -1676,12 +1691,10 @@ static int snd_ensoniq_1371_mixer(struct ensoniq * ensoniq, int has_spdif, int h
if (err < 0)
return err;
}
- if (((ensoniq->subsystem_vendor_id == 0x1274) &&
- (ensoniq->subsystem_device_id == 0x2000)) || /* GA-7DXR */
- ((ensoniq->subsystem_vendor_id == 0x1458) &&
- (ensoniq->subsystem_device_id == 0xa000)) || /* GA-8IEXP */
- has_line > 0) {
- err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line, ensoniq));
+ if (has_line > 0 ||
+ snd_pci_quirk_lookup(ensoniq->pci, ens1373_line_quirk)) {
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line,
+ ensoniq));
if (err < 0)
return err;
}
@@ -1956,21 +1969,15 @@ static int snd_ensoniq_dev_free(struct snd_device *device)
}
#ifdef CHIP1371
-static struct {
- unsigned short svid; /* subsystem vendor ID */
- unsigned short sdid; /* subsystem device ID */
-} es1371_amplifier_hack[] = {
- { .svid = 0x107b, .sdid = 0x2150 }, /* Gateway Solo 2150 */
- { .svid = 0x13bd, .sdid = 0x100c }, /* EV1938 on Mebius PC-MJ100V */
- { .svid = 0x1102, .sdid = 0x5938 }, /* Targa Xtender300 */
- { .svid = 0x1102, .sdid = 0x8938 }, /* IPC Topnote G notebook */
- { .svid = PCI_ANY_ID, .sdid = PCI_ANY_ID }
+static struct snd_pci_quirk es1371_amplifier_hack[] __devinitdata = {
+ SND_PCI_QUIRK_ID(0x107b, 0x2150), /* Gateway Solo 2150 */
+ SND_PCI_QUIRK_ID(0x13bd, 0x100c), /* EV1938 on Mebius PC-MJ100V */
+ SND_PCI_QUIRK_ID(0x1102, 0x5938), /* Targa Xtender300 */
+ SND_PCI_QUIRK_ID(0x1102, 0x8938), /* IPC Topnote G notebook */
+ { } /* end */
};
-static struct {
- unsigned short vid; /* vendor ID */
- unsigned short did; /* device ID */
- unsigned char rev; /* revision */
-} es1371_ac97_reset_hack[] = {
+
+static struct es1371_quirk es1371_ac97_reset_hack[] = {
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },
@@ -1984,7 +1991,6 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)
{
#ifdef CHIP1371
int idx;
- struct pci_dev *pci = ensoniq->pci;
#endif
/* this code was part of snd_ensoniq_create before intruduction
* of suspend/resume
@@ -1999,16 +2005,12 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)
outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
outl(0, ES_REG(ensoniq, 1371_LEGACY));
- for (idx = 0; es1371_ac97_reset_hack[idx].vid != (unsigned short)PCI_ANY_ID; idx++)
- if (pci->vendor == es1371_ac97_reset_hack[idx].vid &&
- pci->device == es1371_ac97_reset_hack[idx].did &&
- ensoniq->rev == es1371_ac97_reset_hack[idx].rev) {
- outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
- /* need to delay around 20ms(bleech) to give
- some CODECs enough time to wakeup */
- msleep(20);
- break;
- }
+ if (es1371_quirk_lookup(ensoniq, es1371_ac97_reset_hack)) {
+ outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
+ /* need to delay around 20ms(bleech) to give
+ some CODECs enough time to wakeup */
+ msleep(20);
+ }
/* AC'97 warm reset to start the bitclk */
outl(ensoniq->ctrl | ES_1371_SYNC_RES, ES_REG(ensoniq, CONTROL));
inl(ES_REG(ensoniq, CONTROL));
@@ -2112,11 +2114,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
struct ensoniq ** rensoniq)
{
struct ensoniq *ensoniq;
- unsigned short cmdw;
unsigned char cmdb;
-#ifdef CHIP1371
- int idx;
-#endif
int err;
static struct snd_device_ops ops = {
.dev_free = snd_ensoniq_dev_free,
@@ -2141,7 +2139,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
return err;
}
ensoniq->port = pci_resource_start(pci, 0);
- if (request_irq(pci->irq, snd_audiopci_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_audiopci_interrupt, IRQF_SHARED,
"Ensoniq AudioPCI", ensoniq)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_ensoniq_free(ensoniq);
@@ -2159,10 +2157,6 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
pci_set_master(pci);
pci_read_config_byte(pci, PCI_REVISION_ID, &cmdb);
ensoniq->rev = cmdb;
- pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &cmdw);
- ensoniq->subsystem_vendor_id = cmdw;
- pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &cmdw);
- ensoniq->subsystem_device_id = cmdw;
#ifdef CHIP1370
#if 0
ensoniq->ctrl = ES_1370_CDC_EN | ES_1370_SERR_DISABLE |
@@ -2175,19 +2169,11 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
ensoniq->ctrl = 0;
ensoniq->sctrl = 0;
ensoniq->cssr = 0;
- for (idx = 0; es1371_amplifier_hack[idx].svid != (unsigned short)PCI_ANY_ID; idx++)
- if (ensoniq->subsystem_vendor_id == es1371_amplifier_hack[idx].svid &&
- ensoniq->subsystem_device_id == es1371_amplifier_hack[idx].sdid) {
- ensoniq->ctrl |= ES_1371_GPIO_OUT(1); /* turn amplifier on */
- break;
- }
- for (idx = 0; es1371_ac97_reset_hack[idx].vid != (unsigned short)PCI_ANY_ID; idx++)
- if (pci->vendor == es1371_ac97_reset_hack[idx].vid &&
- pci->device == es1371_ac97_reset_hack[idx].did &&
- ensoniq->rev == es1371_ac97_reset_hack[idx].rev) {
- ensoniq->cssr |= ES_1371_ST_AC97_RST;
- break;
- }
+ if (snd_pci_quirk_lookup(pci, es1371_amplifier_hack))
+ ensoniq->ctrl |= ES_1371_GPIO_OUT(1); /* turn amplifier on */
+
+ if (es1371_quirk_lookup(ensoniq, es1371_ac97_reset_hack))
+ ensoniq->cssr |= ES_1371_ST_AC97_RST;
#endif
snd_ensoniq_chip_init(ensoniq);
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 1a8d36df4b5..fec29a10894 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1344,7 +1344,7 @@ static unsigned int db_scale_line[] = {
8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0),
};
-static DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0);
static struct snd_kcontrol_new snd_es1938_controls[] = {
ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0,
@@ -1508,7 +1508,7 @@ static int es1938_resume(struct pci_dev *pci)
}
if (request_irq(pci->irq, snd_es1938_interrupt,
- IRQF_DISABLED|IRQF_SHARED, "ES1938", chip)) {
+ IRQF_SHARED, "ES1938", chip)) {
printk(KERN_ERR "es1938: unable to grab IRQ %d, "
"disabling device\n", pci->irq);
snd_card_disconnect(card);
@@ -1631,7 +1631,7 @@ static int __devinit snd_es1938_create(struct snd_card *card,
chip->vc_port = pci_resource_start(pci, 2);
chip->mpu_port = pci_resource_start(pci, 3);
chip->game_port = pci_resource_start(pci, 4);
- if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED,
"ES1938", chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_es1938_free(chip);
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 092da53e146..dc84c189b05 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -1337,7 +1337,7 @@ static struct esm_memory *snd_es1968_new_memory(struct es1968 *chip, int size)
struct esm_memory *buf;
struct list_head *p;
- size = ((size + ESM_MEM_ALIGN - 1) / ESM_MEM_ALIGN) * ESM_MEM_ALIGN;
+ size = ALIGN(size, ESM_MEM_ALIGN);
mutex_lock(&chip->memory_mutex);
list_for_each(p, &chip->buf_list) {
buf = list_entry(p, struct esm_memory, list);
@@ -2462,7 +2462,7 @@ static int snd_es1968_free(struct es1968 *chip)
}
if (chip->irq >= 0)
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, chip);
snd_es1968_free_gameport(chip);
chip->master_switch = NULL;
chip->master_volume = NULL;
@@ -2552,8 +2552,8 @@ static int __devinit snd_es1968_create(struct snd_card *card,
return err;
}
chip->io_port = pci_resource_start(pci, 0);
- if (request_irq(pci->irq, snd_es1968_interrupt, IRQF_DISABLED|IRQF_SHARED,
- "ESS Maestro", (void*)chip)) {
+ if (request_irq(pci->irq, snd_es1968_interrupt, IRQF_SHARED,
+ "ESS Maestro", chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_es1968_free(chip);
return -EBUSY;
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 77e3d5c1830..6dc578bbeec 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1157,7 +1157,7 @@ static int snd_fm801_put_mux(struct snd_kcontrol *kcontrol,
return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val);
}
-static DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0);
#define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls)
@@ -1395,7 +1395,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
}
chip->port = pci_resource_start(pci, 0);
if ((tea575x_tuner & 0x0010) == 0) {
- if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
"FM801", chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
snd_fm801_free(chip);
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index dbacba6177d..60d7b05a204 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,5 +1,14 @@
snd-hda-intel-objs := hda_intel.o
-snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o
+snd-hda-codec-objs := hda_codec.o \
+ hda_generic.o \
+ patch_realtek.o \
+ patch_cmedia.o \
+ patch_analog.o \
+ patch_sigmatel.o \
+ patch_si3054.o \
+ patch_atihdmi.o \
+ patch_conexant.o \
+ patch_via.o
ifdef CONFIG_PROC_FS
snd-hda-codec-objs += hda_proc.o
endif
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 71482c15a85..8f34fb44798 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -52,6 +52,7 @@ struct hda_vendor_id {
static struct hda_vendor_id hda_vendor_ids[] = {
{ 0x10ec, "Realtek" },
{ 0x1057, "Motorola" },
+ { 0x1106, "VIA" },
{ 0x11d4, "Analog Devices" },
{ 0x13f6, "C-Media" },
{ 0x14f1, "Conexant" },
@@ -262,7 +263,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
unsol->queue[wp] = res;
unsol->queue[wp + 1] = res_ex;
- queue_work(unsol->workq, &unsol->work);
+ schedule_work(&unsol->work);
return 0;
}
@@ -309,12 +310,6 @@ static int init_unsol_queue(struct hda_bus *bus)
snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n");
return -ENOMEM;
}
- unsol->workq = create_singlethread_workqueue("hda_codec");
- if (! unsol->workq) {
- snd_printk(KERN_ERR "hda_codec: can't create workqueue\n");
- kfree(unsol);
- return -ENOMEM;
- }
INIT_WORK(&unsol->work, process_unsol_events);
unsol->bus = bus;
bus->unsol = unsol;
@@ -333,7 +328,7 @@ static int snd_hda_bus_free(struct hda_bus *bus)
if (! bus)
return 0;
if (bus->unsol) {
- destroy_workqueue(bus->unsol->workq);
+ flush_scheduled_work();
kfree(bus->unsol);
}
list_for_each_safe(p, n, &bus->codec_list) {
@@ -1367,9 +1362,6 @@ static struct hda_rate_tbl rate_bits[] = {
{ 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */
{ 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */
- /* not autodetected value */
- { 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */
-
{ 0 } /* terminator */
};
@@ -1717,6 +1709,8 @@ EXPORT_SYMBOL(snd_hda_build_pcms);
/**
* snd_hda_check_board_config - compare the current codec with the config table
* @codec: the HDA codec
+ * @num_configs: number of config enums
+ * @models: array of model name strings
* @tbl: configuration table, terminated by null entries
*
* Compares the modelname or PCI subsystem id of the current codec with the
@@ -1725,33 +1719,44 @@ EXPORT_SYMBOL(snd_hda_build_pcms);
*
* If no entries are matching, the function returns a negative value.
*/
-int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl)
-{
- const struct hda_board_config *c;
-
- if (codec->bus->modelname) {
- for (c = tbl; c->modelname || c->pci_subvendor; c++) {
- if (c->modelname &&
- ! strcmp(codec->bus->modelname, c->modelname)) {
- snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname);
- return c->config;
+int snd_hda_check_board_config(struct hda_codec *codec,
+ int num_configs, const char **models,
+ const struct snd_pci_quirk *tbl)
+{
+ if (codec->bus->modelname && models) {
+ int i;
+ for (i = 0; i < num_configs; i++) {
+ if (models[i] &&
+ !strcmp(codec->bus->modelname, models[i])) {
+ snd_printd(KERN_INFO "hda_codec: model '%s' is "
+ "selected\n", models[i]);
+ return i;
}
}
}
- if (codec->bus->pci) {
- u16 subsystem_vendor, subsystem_device;
- pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
- pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device);
- for (c = tbl; c->modelname || c->pci_subvendor; c++) {
- if (c->pci_subvendor == subsystem_vendor &&
- (! c->pci_subdevice /* all match */||
- (c->pci_subdevice == subsystem_device))) {
- snd_printdd(KERN_INFO "hda_codec: PCI %x:%x, codec config %d is selected\n",
- subsystem_vendor, subsystem_device, c->config);
- return c->config;
- }
+ if (!codec->bus->pci || !tbl)
+ return -1;
+
+ tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl);
+ if (!tbl)
+ return -1;
+ if (tbl->value >= 0 && tbl->value < num_configs) {
+#ifdef CONFIG_SND_DEBUG_DETECT
+ char tmp[10];
+ const char *model = NULL;
+ if (models)
+ model = models[tbl->value];
+ if (!model) {
+ sprintf(tmp, "#%d", tbl->value);
+ model = tmp;
}
+ snd_printdd(KERN_INFO "hda_codec: model '%s' is selected "
+ "for config %x:%x (%s)\n",
+ model, tbl->subvendor, tbl->subdevice,
+ (tbl->name ? tbl->name : "Unknown device"));
+#endif
+ return tbl->value;
}
return -1;
}
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 97e9af130b7..1589d2f2917 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -485,8 +485,9 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
return "Front Aux";
return "Aux";
case AC_JACK_MIC_IN:
- if (node->pin_caps &
- (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT))
+ if (pinctl &&
+ (node->pin_caps &
+ (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT)))
*pinctl |= AC_PINCTL_VREF_80;
if ((location & 0x0f) == AC_JACK_LOC_FRONT)
return "Front Mic";
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index e35cfd326df..b9a8e238b0a 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -83,6 +83,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, ICH7},"
"{Intel, ESB2},"
"{Intel, ICH8},"
+ "{Intel, ICH9},"
"{ATI, SB450},"
"{ATI, SB600},"
"{ATI, RS600},"
@@ -198,7 +199,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
/* STATESTS int mask: SD2,SD1,SD0 */
#define STATESTS_INT_MASK 0x07
-#define AZX_MAX_CODECS 4
+#define AZX_MAX_CODECS 3
/* SD_CTL bits */
#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
@@ -1284,7 +1285,7 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
- 1024 * 64, 1024 * 128);
+ 1024 * 64, 1024 * 1024);
chip->pcm[pcm_dev] = pcm;
if (chip->pcm_devs < pcm_dev + 1)
chip->pcm_devs = pcm_dev + 1;
@@ -1380,7 +1381,8 @@ static int __devinit azx_init_stream(struct azx *chip)
static int azx_acquire_irq(struct azx *chip, int do_disconnect)
{
- if (request_irq(chip->pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(chip->pci->irq, azx_interrupt,
+ chip->msi ? 0 : IRQF_SHARED,
"HDA Intel", chip)) {
printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
"disabling device\n", chip->pci->irq);
@@ -1389,6 +1391,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
return -1;
}
chip->irq = chip->pci->irq;
+ pci_intx(chip->pci, !chip->msi);
return 0;
}
@@ -1500,6 +1503,31 @@ static int azx_dev_free(struct snd_device *device)
}
/*
+ * white/black-listing for position_fix
+ */
+static const struct snd_pci_quirk position_fix_list[] __devinitdata = {
+ SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE),
+ {}
+};
+
+static int __devinit check_position_fix(struct azx *chip, int fix)
+{
+ const struct snd_pci_quirk *q;
+
+ if (fix == POS_FIX_AUTO) {
+ q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
+ if (q) {
+ snd_printdd(KERN_INFO
+ "hda_intel: position_fix set to %d "
+ "for device %04x:%04x\n",
+ q->value, q->subvendor, q->subdevice);
+ return q->value;
+ }
+ }
+ return fix;
+}
+
+/*
* constructor
*/
static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
@@ -1533,7 +1561,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->driver_type = driver_type;
chip->msi = enable_msi;
- chip->position_fix = position_fix;
+ chip->position_fix = check_position_fix(chip, position_fix);
+
chip->single_cmd = single_cmd;
#if BITS_PER_LONG != 64
@@ -1710,6 +1739,8 @@ static struct pci_device_id azx_ids[] = {
{ 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */
{ 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
{ 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
+ { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
+ { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
{ 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
{ 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
{ 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
@@ -1717,9 +1748,14 @@ static struct pci_device_id azx_ids[] = {
{ 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
{ 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
{ 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 */
+ { 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP51 */
+ { 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP55 */
+ { 0x10de, 0x03e4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP61 */
+ { 0x10de, 0x03f0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP61 */
+ { 0x10de, 0x044a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
+ { 0x10de, 0x044b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
+ { 0x10de, 0x055c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
+ { 0x10de, 0x055d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 9ca1baf860b..39718d6cdad 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -173,14 +173,9 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
/*
* Misc
*/
-struct hda_board_config {
- const char *modelname;
- int config;
- unsigned short pci_subvendor;
- unsigned short pci_subdevice;
-};
-
-int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl);
+int snd_hda_check_board_config(struct hda_codec *codec, int num_configs,
+ const char **modelnames,
+ const struct snd_pci_quirk *pci_list);
int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew);
/*
@@ -204,7 +199,6 @@ struct hda_bus_unsolicited {
unsigned int rp, wp;
/* workqueue */
- struct workqueue_struct *workq;
struct work_struct work;
struct hda_bus *bus;
};
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index 0b668793fac..9f9e9ae44a9 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -14,6 +14,10 @@ extern struct hda_codec_preset snd_hda_preset_sigmatel[];
extern struct hda_codec_preset snd_hda_preset_si3054[];
/* ATI HDMI codecs */
extern struct hda_codec_preset snd_hda_preset_atihdmi[];
+/* Conexant audio codec */
+extern struct hda_codec_preset snd_hda_preset_conexant[];
+/* VIA codecs */
+extern struct hda_codec_preset snd_hda_preset_via[];
static const struct hda_codec_preset *hda_preset_tables[] = {
snd_hda_preset_realtek,
@@ -22,5 +26,7 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
snd_hda_preset_sigmatel,
snd_hda_preset_si3054,
snd_hda_preset_atihdmi,
+ snd_hda_preset_conexant,
+ snd_hda_preset_via,
NULL
};
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index d737f17695a..17df4d0fe13 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -45,7 +45,7 @@ static const char *get_wid_type_name(unsigned int wid_value)
if (names[wid_value])
return names[wid_value];
else
- return "UNKOWN Widget";
+ return "UNKNOWN Widget";
}
static void print_amp_caps(struct snd_info_buffer *buffer,
@@ -88,6 +88,48 @@ static void print_amp_vals(struct snd_info_buffer *buffer,
snd_iprintf(buffer, "\n");
}
+static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm)
+{
+ static unsigned int rates[] = {
+ 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
+ 96000, 176400, 192000, 384000
+ };
+ int i;
+
+ pcm &= AC_SUPPCM_RATES;
+ snd_iprintf(buffer, " rates [0x%x]:", pcm);
+ for (i = 0; i < ARRAY_SIZE(rates); i++)
+ if (pcm & (1 << i))
+ snd_iprintf(buffer, " %d", rates[i]);
+ snd_iprintf(buffer, "\n");
+}
+
+static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm)
+{
+ static unsigned int bits[] = { 8, 16, 20, 24, 32 };
+ int i;
+
+ pcm = (pcm >> 16) & 0xff;
+ snd_iprintf(buffer, " bits [0x%x]:", pcm);
+ for (i = 0; i < ARRAY_SIZE(bits); i++)
+ if (pcm & (1 << i))
+ snd_iprintf(buffer, " %d", bits[i]);
+ snd_iprintf(buffer, "\n");
+}
+
+static void print_pcm_formats(struct snd_info_buffer *buffer,
+ unsigned int streams)
+{
+ snd_iprintf(buffer, " formats [0x%x]:", streams & 0xf);
+ if (streams & AC_SUPFMT_PCM)
+ snd_iprintf(buffer, " PCM");
+ if (streams & AC_SUPFMT_FLOAT32)
+ snd_iprintf(buffer, " FLOAT");
+ if (streams & AC_SUPFMT_AC3)
+ snd_iprintf(buffer, " AC3");
+ snd_iprintf(buffer, "\n");
+}
+
static void print_pcm_caps(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid)
{
@@ -97,8 +139,9 @@ static void print_pcm_caps(struct snd_info_buffer *buffer,
snd_iprintf(buffer, "N/A\n");
return;
}
- snd_iprintf(buffer, "rates 0x%03x, bits 0x%02x, types 0x%x\n",
- pcm & AC_SUPPCM_RATES, (pcm >> 16) & 0xff, stream & 0xf);
+ print_pcm_rates(buffer, pcm);
+ print_pcm_bits(buffer, pcm);
+ print_pcm_formats(buffer, stream);
}
static const char *get_jack_location(u32 cfg)
@@ -210,7 +253,7 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe
snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
if (! codec->afg)
return;
- snd_iprintf(buffer, "Default PCM: ");
+ snd_iprintf(buffer, "Default PCM:\n");
print_pcm_caps(buffer, codec, codec->afg);
snd_iprintf(buffer, "Default Amp-In caps: ");
print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
@@ -278,7 +321,7 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe
if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) &&
(wid_caps & AC_WCAP_FORMAT_OVRD)) {
- snd_iprintf(buffer, " PCM: ");
+ snd_iprintf(buffer, " PCM:\n");
print_pcm_caps(buffer, codec, nid);
}
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index edd22dec828..38977bce70e 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -782,50 +782,63 @@ static struct hda_channel_mode ad1986a_modes[3] = {
/* eapd initialization */
static struct hda_verb ad1986a_eapd_init_verbs[] = {
- {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00},
+ {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
{}
};
+/* Ultra initialization */
+static struct hda_verb ad1986a_ultra_init[] = {
+ /* eapd initialization */
+ { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
+ /* CLFE -> Mic in */
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
+ { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+ { } /* end */
+};
+
/* models */
-enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD };
-
-static struct hda_board_config ad1986a_cfg_tbl[] = {
- { .modelname = "6stack", .config = AD1986A_6STACK },
- { .modelname = "3stack", .config = AD1986A_3STACK },
- { .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84,
- .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3,
- .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb,
- .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */
- { .modelname = "laptop", .config = AD1986A_LAPTOP },
- { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e,
- .config = AD1986A_LAPTOP }, /* FSC V2060 */
- { .pci_subvendor = 0x17c0, .pci_subdevice = 0x2017,
- .config = AD1986A_LAPTOP }, /* Samsung M50 */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x818f,
- .config = AD1986A_LAPTOP }, /* ASUS P5GV-MX */
- { .modelname = "laptop-eapd", .config = AD1986A_LAPTOP_EAPD },
- { .pci_subvendor = 0x144d, .pci_subdevice = 0xc023,
- .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */
- { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024,
- .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */
- { .pci_subvendor = 0x144d, .pci_subdevice = 0xc026,
- .config = AD1986A_LAPTOP_EAPD }, /* Samsung X10-T2300 Culesa */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153,
- .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213,
- .config = AD1986A_LAPTOP_EAPD }, /* ASUS A6J */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x11f7,
- .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5A */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1263,
- .config = AD1986A_LAPTOP_EAPD }, /* ASUS U5F */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1297,
- .config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x30af,
- .config = AD1986A_LAPTOP_EAPD }, /* HP Compaq Presario B2800 */
- { .pci_subvendor = 0x17aa, .pci_subdevice = 0x2066,
- .config = AD1986A_LAPTOP_EAPD }, /* Lenovo 3000 N100-07684JU */
+enum {
+ AD1986A_6STACK,
+ AD1986A_3STACK,
+ AD1986A_LAPTOP,
+ AD1986A_LAPTOP_EAPD,
+ AD1986A_ULTRA,
+ AD1986A_MODELS
+};
+
+static const char *ad1986a_models[AD1986A_MODELS] = {
+ [AD1986A_6STACK] = "6stack",
+ [AD1986A_3STACK] = "3stack",
+ [AD1986A_LAPTOP] = "laptop",
+ [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
+ [AD1986A_ULTRA] = "ultra",
+};
+
+static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
+ SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
+ SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
+ SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
+ SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
{}
};
@@ -857,7 +870,9 @@ static int patch_ad1986a(struct hda_codec *codec)
codec->patch_ops = ad198x_patch_ops;
/* override some parameters */
- board_config = snd_hda_check_board_config(codec, ad1986a_cfg_tbl);
+ board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
+ ad1986a_models,
+ ad1986a_cfg_tbl);
switch (board_config) {
case AD1986A_3STACK:
spec->num_mixers = 2;
@@ -887,6 +902,15 @@ static int patch_ad1986a(struct hda_codec *codec)
spec->multiout.dig_out_nid = 0;
spec->input_mux = &ad1986a_laptop_eapd_capture_source;
break;
+ case AD1986A_ULTRA:
+ spec->mixers[0] = ad1986a_laptop_eapd_mixers;
+ spec->num_init_verbs = 2;
+ spec->init_verbs[1] = ad1986a_ultra_init;
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = 1;
+ spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
+ spec->multiout.dig_out_nid = 0;
+ break;
}
return 0;
@@ -1387,20 +1411,27 @@ static struct hda_input_mux ad1981_thinkpad_capture_source = {
};
/* models */
-enum { AD1981_BASIC, AD1981_HP, AD1981_THINKPAD };
+enum {
+ AD1981_BASIC,
+ AD1981_HP,
+ AD1981_THINKPAD,
+ AD1981_MODELS
+};
+
+static const char *ad1981_models[AD1981_MODELS] = {
+ [AD1981_HP] = "hp",
+ [AD1981_THINKPAD] = "thinkpad",
+ [AD1981_BASIC] = "basic",
+};
-static struct hda_board_config ad1981_cfg_tbl[] = {
- { .modelname = "hp", .config = AD1981_HP },
+static struct snd_pci_quirk ad1981_cfg_tbl[] = {
/* All HP models */
- { .pci_subvendor = 0x103c, .config = AD1981_HP },
- { .pci_subvendor = 0x30b0, .pci_subdevice = 0x103c,
- .config = AD1981_HP }, /* HP nx6320 (reversed SSID, H/W bug) */
- { .modelname = "thinkpad", .config = AD1981_THINKPAD },
+ SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
+ /* HP nx6320 (reversed SSID, H/W bug) */
+ SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
/* Lenovo Thinkpad T60/X60/Z6xx */
- { .pci_subvendor = 0x17aa, .config = AD1981_THINKPAD },
- { .pci_subvendor = 0x1014, .pci_subdevice = 0x0597,
- .config = AD1981_THINKPAD }, /* Z60m/t */
- { .modelname = "basic", .config = AD1981_BASIC },
+ SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD),
+ SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
{}
};
@@ -1433,7 +1464,9 @@ static int patch_ad1981(struct hda_codec *codec)
codec->patch_ops = ad198x_patch_ops;
/* override some parameters */
- board_config = snd_hda_check_board_config(codec, ad1981_cfg_tbl);
+ board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
+ ad1981_models,
+ ad1981_cfg_tbl);
switch (board_config) {
case AD1981_HP:
spec->mixers[0] = ad1981_hp_mixers;
@@ -1640,7 +1673,7 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
spec->num_channel_mode,
&spec->multiout.max_channels);
- if (! err && spec->need_dac_fix)
+ if (err >= 0 && spec->need_dac_fix)
spec->multiout.num_dacs = spec->multiout.max_channels / 2;
return err;
}
@@ -2561,15 +2594,14 @@ static int ad1988_auto_init(struct hda_codec *codec)
/*
*/
-static struct hda_board_config ad1988_cfg_tbl[] = {
- { .modelname = "6stack", .config = AD1988_6STACK },
- { .modelname = "6stack-dig", .config = AD1988_6STACK_DIG },
- { .modelname = "3stack", .config = AD1988_3STACK },
- { .modelname = "3stack-dig", .config = AD1988_3STACK_DIG },
- { .modelname = "laptop", .config = AD1988_LAPTOP },
- { .modelname = "laptop-dig", .config = AD1988_LAPTOP_DIG },
- { .modelname = "auto", .config = AD1988_AUTO },
- {}
+static const char *ad1988_models[AD1988_MODEL_LAST] = {
+ [AD1988_6STACK] = "6stack",
+ [AD1988_6STACK_DIG] = "6stack-dig",
+ [AD1988_3STACK] = "3stack",
+ [AD1988_3STACK_DIG] = "3stack-dig",
+ [AD1988_LAPTOP] = "laptop",
+ [AD1988_LAPTOP_DIG] = "laptop-dig",
+ [AD1988_AUTO] = "auto",
};
static int patch_ad1988(struct hda_codec *codec)
@@ -2587,8 +2619,9 @@ static int patch_ad1988(struct hda_codec *codec)
if (is_rev2(codec))
snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
- board_config = snd_hda_check_board_config(codec, ad1988_cfg_tbl);
- if (board_config < 0 || board_config >= AD1988_MODEL_LAST) {
+ board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
+ ad1988_models, NULL);
+ if (board_config < 0) {
printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n");
board_config = AD1988_AUTO;
}
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index d38ce22507a..5b9d3a31a1a 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -40,6 +40,7 @@ enum {
CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */
CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */
CMI_AUTO, /* let driver guess it */
+ CMI_MODELS
};
struct cmi_spec {
@@ -603,14 +604,17 @@ static void cmi9880_free(struct hda_codec *codec)
/*
*/
-static struct hda_board_config cmi9880_cfg_tbl[] = {
- { .modelname = "minimal", .config = CMI_MINIMAL },
- { .modelname = "min_fp", .config = CMI_MIN_FP },
- { .modelname = "full", .config = CMI_FULL },
- { .modelname = "full_dig", .config = CMI_FULL_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x813d, .config = CMI_FULL_DIG }, /* ASUS P5AD2 */
- { .modelname = "allout", .config = CMI_ALLOUT },
- { .modelname = "auto", .config = CMI_AUTO },
+static const char *cmi9880_models[CMI_MODELS] = {
+ [CMI_MINIMAL] = "minimal",
+ [CMI_MIN_FP] = "min_fp",
+ [CMI_FULL] = "full",
+ [CMI_FULL_DIG] = "full_dig",
+ [CMI_ALLOUT] = "allout",
+ [CMI_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk cmi9880_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG),
{} /* terminator */
};
@@ -633,7 +637,9 @@ static int patch_cmi9880(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;
- spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl);
+ spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS,
+ cmi9880_models,
+ cmi9880_cfg_tbl);
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
spec->board_config = CMI_AUTO; /* try everything */
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
new file mode 100644
index 00000000000..73f4668238c
--- /dev/null
+++ b/sound/pci/hda/patch_conexant.c
@@ -0,0 +1,1311 @@
+/*
+ * HD audio interface patch for Conexant HDA audio codec
+ *
+ * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com>
+ * Takashi Iwai <tiwai@suse.de>
+ * Tobin Davis <tdavis@dsl-only.net>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * 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 driver 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+#define CXT_PIN_DIR_IN 0x00
+#define CXT_PIN_DIR_OUT 0x01
+#define CXT_PIN_DIR_INOUT 0x02
+#define CXT_PIN_DIR_IN_NOMICBIAS 0x03
+#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04
+
+#define CONEXANT_HP_EVENT 0x37
+#define CONEXANT_MIC_EVENT 0x38
+
+
+
+struct conexant_spec {
+
+ struct snd_kcontrol_new *mixers[5];
+ int num_mixers;
+
+ const struct hda_verb *init_verbs[5]; /* initialization verbs
+ * don't forget NULL
+ * termination!
+ */
+ unsigned int num_init_verbs;
+
+ /* playback */
+ struct hda_multi_out multiout; /* playback set-up
+ * max_channels, dacs must be set
+ * dig_out_nid and hp_nid are optional
+ */
+ unsigned int cur_eapd;
+ unsigned int need_dac_fix;
+
+ /* capture */
+ unsigned int num_adc_nids;
+ hda_nid_t *adc_nids;
+ hda_nid_t dig_in_nid; /* digital-in NID; optional */
+
+ /* capture source */
+ const struct hda_input_mux *input_mux;
+ hda_nid_t *capsrc_nids;
+ unsigned int cur_mux[3];
+
+ /* channel model */
+ const struct hda_channel_mode *channel_mode;
+ int num_channel_mode;
+
+ /* PCM information */
+ struct hda_pcm pcm_rec[2]; /* used in build_pcms() */
+
+ struct mutex amp_mutex; /* PCM volume/mute control mutex */
+ unsigned int spdif_route;
+
+ /* dynamic controls, init_verbs and input_mux */
+ struct auto_pin_cfg autocfg;
+ unsigned int num_kctl_alloc, num_kctl_used;
+ struct snd_kcontrol_new *kctl_alloc;
+ struct hda_input_mux private_imux;
+ hda_nid_t private_dac_nids[4];
+
+};
+
+static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+ stream_tag,
+ format, substream);
+}
+
+static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+ stream_tag, 0, format);
+ return 0;
+}
+
+static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct conexant_spec *spec = codec->spec;
+ snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+ 0, 0, 0);
+ return 0;
+}
+
+
+
+static struct hda_pcm_stream conexant_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0, /* fill later */
+ .ops = {
+ .open = conexant_playback_pcm_open,
+ .prepare = conexant_playback_pcm_prepare,
+ .cleanup = conexant_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream conexant_pcm_analog_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0, /* fill later */
+ .ops = {
+ .prepare = conexant_capture_pcm_prepare,
+ .cleanup = conexant_capture_pcm_cleanup
+ },
+};
+
+
+static struct hda_pcm_stream conexant_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0, /* fill later */
+ .ops = {
+ .open = conexant_dig_playback_pcm_open,
+ .close = conexant_dig_playback_pcm_close
+ },
+};
+
+static struct hda_pcm_stream conexant_pcm_digital_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in alc_build_pcms */
+};
+
+static int conexant_build_pcms(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ struct hda_pcm *info = spec->pcm_rec;
+
+ codec->num_pcms = 1;
+ codec->pcm_info = info;
+
+ info->name = "CONEXANT Analog";
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+ spec->multiout.max_channels;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->multiout.dac_nids[0];
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+
+ if (spec->multiout.dig_out_nid) {
+ info++;
+ codec->num_pcms++;
+ info->name = "Conexant Digital";
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+ conexant_pcm_digital_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->multiout.dig_out_nid;
+ if (spec->dig_in_nid) {
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+ conexant_pcm_digital_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+ spec->dig_in_nid;
+ }
+ }
+
+ return 0;
+}
+
+static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+
+ return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+ ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+ return 0;
+}
+
+static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ spec->capsrc_nids[adc_idx],
+ &spec->cur_mux[adc_idx]);
+}
+
+static int conexant_init(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < spec->num_init_verbs; i++)
+ snd_hda_sequence_write(codec, spec->init_verbs[i]);
+ return 0;
+}
+
+static void conexant_free(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ unsigned int i;
+
+ if (spec->kctl_alloc) {
+ for (i = 0; i < spec->num_kctl_used; i++)
+ kfree(spec->kctl_alloc[i].name);
+ kfree(spec->kctl_alloc);
+ }
+
+ kfree(codec->spec);
+}
+
+#ifdef CONFIG_PM
+static int conexant_resume(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ int i;
+
+ codec->patch_ops.init(codec);
+ for (i = 0; i < spec->num_mixers; i++)
+ snd_hda_resume_ctls(codec, spec->mixers[i]);
+ if (spec->multiout.dig_out_nid)
+ snd_hda_resume_spdif_out(codec);
+ if (spec->dig_in_nid)
+ snd_hda_resume_spdif_in(codec);
+ return 0;
+}
+#endif
+
+static int conexant_build_controls(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < spec->num_mixers; i++) {
+ err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
+ if (err < 0)
+ return err;
+ }
+ if (spec->multiout.dig_out_nid) {
+ err = snd_hda_create_spdif_out_ctls(codec,
+ spec->multiout.dig_out_nid);
+ if (err < 0)
+ return err;
+ }
+ if (spec->dig_in_nid) {
+ err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static struct hda_codec_ops conexant_patch_ops = {
+ .build_controls = conexant_build_controls,
+ .build_pcms = conexant_build_pcms,
+ .init = conexant_init,
+ .free = conexant_free,
+#ifdef CONFIG_PM
+ .resume = conexant_resume,
+#endif
+};
+
+/*
+ * EAPD control
+ * the private value = nid | (invert << 8)
+ */
+
+static int conexant_eapd_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int conexant_eapd_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ int invert = (kcontrol->private_value >> 8) & 1;
+ if (invert)
+ ucontrol->value.integer.value[0] = !spec->cur_eapd;
+ else
+ ucontrol->value.integer.value[0] = spec->cur_eapd;
+ return 0;
+}
+
+static int conexant_eapd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ int invert = (kcontrol->private_value >> 8) & 1;
+ hda_nid_t nid = kcontrol->private_value & 0xff;
+ unsigned int eapd;
+ eapd = ucontrol->value.integer.value[0];
+ if (invert)
+ eapd = !eapd;
+ if (eapd == spec->cur_eapd && !codec->in_resume)
+ return 0;
+ spec->cur_eapd = eapd;
+ snd_hda_codec_write(codec, nid,
+ 0, AC_VERB_SET_EAPD_BTLENABLE,
+ eapd ? 0x02 : 0x00);
+ return 1;
+}
+
+/* controls for test mode */
+#ifdef CONFIG_SND_DEBUG
+
+static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
+ spec->num_channel_mode);
+}
+
+static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
+ spec->num_channel_mode,
+ spec->multiout.max_channels);
+}
+
+static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
+ spec->num_channel_mode,
+ &spec->multiout.max_channels);
+ if (err >= 0 && spec->need_dac_fix)
+ spec->multiout.num_dacs = spec->multiout.max_channels / 2;
+ return err;
+}
+
+#define CXT_PIN_MODE(xname, nid, dir) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
+ .info = conexant_ch_mode_info, \
+ .get = conexant_ch_mode_get, \
+ .put = conexant_ch_mode_put, \
+ .private_value = nid | (dir<<16) }
+
+static int cxt_gpio_data_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int cxt_gpio_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = kcontrol->private_value & 0xffff;
+ unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+ long *valp = ucontrol->value.integer.value;
+ unsigned int val = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPIO_DATA, 0x00);
+
+ *valp = (val & mask) != 0;
+ return 0;
+}
+
+static int cxt_gpio_data_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = kcontrol->private_value & 0xffff;
+ unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+ long val = *ucontrol->value.integer.value;
+ unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPIO_DATA,
+ 0x00);
+ unsigned int old_data = gpio_data;
+
+ /* Set/unset the masked GPIO bit(s) as needed */
+ if (val == 0)
+ gpio_data &= ~mask;
+ else
+ gpio_data |= mask;
+ if (gpio_data == old_data && !codec->in_resume)
+ return 0;
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data);
+ return 1;
+}
+
+#define CXT_GPIO_DATA_SWITCH(xname, nid, mask) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
+ .info = cxt_gpio_data_info, \
+ .get = cxt_gpio_data_get, \
+ .put = cxt_gpio_data_put, \
+ .private_value = nid | (mask<<16) }
+
+static int cxt_spdif_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int cxt_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = kcontrol->private_value & 0xffff;
+ unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+ long *valp = ucontrol->value.integer.value;
+ unsigned int val = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_DIGI_CONVERT, 0x00);
+
+ *valp = (val & mask) != 0;
+ return 0;
+}
+
+static int cxt_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ hda_nid_t nid = kcontrol->private_value & 0xffff;
+ unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+ long val = *ucontrol->value.integer.value;
+ unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_DIGI_CONVERT,
+ 0x00);
+ unsigned int old_data = ctrl_data;
+
+ /* Set/unset the masked control bit(s) as needed */
+ if (val == 0)
+ ctrl_data &= ~mask;
+ else
+ ctrl_data |= mask;
+ if (ctrl_data == old_data && !codec->in_resume)
+ return 0;
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+ ctrl_data);
+ return 1;
+}
+
+#define CXT_SPDIF_CTRL_SWITCH(xname, nid, mask) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
+ .info = cxt_spdif_ctrl_info, \
+ .get = cxt_spdif_ctrl_get, \
+ .put = cxt_spdif_ctrl_put, \
+ .private_value = nid | (mask<<16) }
+
+#endif /* CONFIG_SND_DEBUG */
+
+/* Conexant 5045 specific */
+
+static hda_nid_t cxt5045_dac_nids[1] = { 0x19 };
+static hda_nid_t cxt5045_adc_nids[1] = { 0x1a };
+static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a };
+#define CXT5045_SPDIF_OUT 0x13
+
+static struct hda_channel_mode cxt5045_modes[1] = {
+ { 2, NULL },
+};
+
+static struct hda_input_mux cxt5045_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "ExtMic", 0x1 },
+ { "LineIn", 0x2 },
+ }
+};
+
+/* turn on/off EAPD (+ mute HP) as a master switch */
+static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+
+ if (!conexant_eapd_put(kcontrol, ucontrol))
+ return 0;
+
+ /* toggle HP mute appropriately */
+ snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0,
+ 0x80, spec->cur_eapd ? 0 : 0x80);
+ snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0,
+ 0x80, spec->cur_eapd ? 0 : 0x80);
+ return 1;
+}
+
+/* bind volumes of both NID 0x10 and 0x11 */
+static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ long *valp = ucontrol->value.integer.value;
+ int change;
+
+ change = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0,
+ 0x7f, valp[0] & 0x7f);
+ change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0,
+ 0x7f, valp[1] & 0x7f);
+ snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0,
+ 0x7f, valp[0] & 0x7f);
+ snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0,
+ 0x7f, valp[1] & 0x7f);
+ return change;
+}
+
+
+/* mute internal speaker if HP is plugged */
+static void cxt5045_hp_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x11, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+}
+
+/* unsolicited event for HP jack sensing */
+static void cxt5045_hp_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ res >>= 26;
+ switch (res) {
+ case CONEXANT_HP_EVENT:
+ cxt5045_hp_automute(codec);
+ break;
+ }
+}
+
+static struct snd_kcontrol_new cxt5045_mixers[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = conexant_mux_enum_info,
+ .get = conexant_mux_enum_get,
+ .put = conexant_mux_enum_put
+ },
+ HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x17, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x17, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x02, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Volume",
+ .info = snd_hda_mixer_amp_volume_info,
+ .get = snd_hda_mixer_amp_volume_get,
+ .put = cxt5045_hp_master_vol_put,
+ .private_value = HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = conexant_eapd_info,
+ .get = conexant_eapd_get,
+ .put = cxt5045_hp_master_sw_put,
+ .private_value = 0x11,
+ },
+
+ {}
+};
+
+static struct hda_verb cxt5045_init_verbs[] = {
+ /* Line in, Mic */
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
+ /* HP, Amp */
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ {0x1A, AC_VERB_SET_CONNECT_SEL,0x01},
+ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00},
+ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03},
+ /* Record selector: Front mic */
+ {0x14, AC_VERB_SET_CONNECT_SEL,0x03},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
+ /* SPDIF route: PCM */
+ { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 },
+ /* pin sensing on HP and Mic jacks */
+ {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+ /* EAPD */
+ {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */
+ { } /* end */
+};
+
+#ifdef CONFIG_SND_DEBUG
+/* Test configuration for debugging, modelled after the ALC260 test
+ * configuration.
+ */
+static struct hda_input_mux cxt5045_test_capture_source = {
+ .num_items = 5,
+ .items = {
+ { "MIXER", 0x0 },
+ { "MIC1 pin", 0x1 },
+ { "LINE1 pin", 0x2 },
+ { "HP-OUT pin", 0x3 },
+ { "CD pin", 0x4 },
+ },
+};
+
+static struct snd_kcontrol_new cxt5045_test_mixer[] = {
+
+ /* Output controls */
+ HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x19, 0x00, HDA_OUTPUT),
+ HDA_CODEC_MUTE("OutAmp-1 Switch", 0x19,0x00, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+
+ /* Modes for retasking pin widgets */
+ CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT),
+ CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT),
+
+ /* Loopback mixer controls */
+ HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x17, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("MIC1 Playback Switch", 0x17, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("LINE loopback Playback Volume", 0x17, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("LINE loopback Playback Switch", 0x17, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x17, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x17, 0x03, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x04, HDA_INPUT),
+
+ /* Controls for GPIO pins, assuming they exist and are configured as outputs */
+ CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+#if 0 /* limit this to one GPIO pin for now */
+ CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+ CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+ CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+#endif
+ CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x13, 0x01),
+
+ HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .info = conexant_mux_enum_info,
+ .get = conexant_mux_enum_get,
+ .put = conexant_mux_enum_put,
+ },
+
+ { } /* end */
+};
+
+static struct hda_verb cxt5045_test_init_verbs[] = {
+ /* Enable all GPIOs as outputs with an initial value of 0 */
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
+
+ /* Enable retasking pins as output, initially without power amp */
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+ /* Disable digital (SPDIF) pins initially, but users can enable
+ * them via a mixer switch. In the case of SPDIF-out, this initverb
+ * payload also sets the generation to 0, output to be in "consumer"
+ * PCM format, copyright asserted, no pre-emphasis and no validity
+ * control.
+ */
+ {0x13, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+ /* Start with output sum widgets muted and their output gains at min */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+ /* Unmute retasking pin widget output buffers since the default
+ * state appears to be output. As the pin mode is changed by the
+ * user the pin mode control will take care of enabling the pin's
+ * input/output buffers as needed.
+ */
+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+ /* Mute capture amp left and right */
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+
+ /* Set ADC connection select to match default mixer setting (mic1
+ * pin)
+ */
+ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ /* Mute all inputs to mixer widget (even unconnected ones) */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+
+ { }
+};
+#endif
+
+
+/* initialize jack-sensing, too */
+static int cxt5045_init(struct hda_codec *codec)
+{
+ conexant_init(codec);
+ cxt5045_hp_automute(codec);
+ return 0;
+}
+
+
+enum {
+ CXT5045_LAPTOP, /* Laptops w/ EAPD support */
+#ifdef CONFIG_SND_DEBUG
+ CXT5045_TEST,
+#endif
+ CXT5045_MODELS
+};
+
+static const char *cxt5045_models[CXT5045_MODELS] = {
+ [CXT5045_LAPTOP] = "laptop",
+#ifdef CONFIG_SND_DEBUG
+ [CXT5045_TEST] = "test",
+#endif
+};
+
+static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP),
+ {}
+};
+
+static int patch_cxt5045(struct hda_codec *codec)
+{
+ struct conexant_spec *spec;
+ int board_config;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+ mutex_init(&spec->amp_mutex);
+ codec->spec = spec;
+
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids);
+ spec->multiout.dac_nids = cxt5045_dac_nids;
+ spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT;
+ spec->num_adc_nids = 1;
+ spec->adc_nids = cxt5045_adc_nids;
+ spec->capsrc_nids = cxt5045_capsrc_nids;
+ spec->input_mux = &cxt5045_capture_source;
+ spec->num_mixers = 1;
+ spec->mixers[0] = cxt5045_mixers;
+ spec->num_init_verbs = 1;
+ spec->init_verbs[0] = cxt5045_init_verbs;
+ spec->spdif_route = 0;
+ spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes),
+ spec->channel_mode = cxt5045_modes,
+
+
+ codec->patch_ops = conexant_patch_ops;
+ codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
+
+ board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
+ cxt5045_models,
+ cxt5045_cfg_tbl);
+ switch (board_config) {
+ case CXT5045_LAPTOP:
+ spec->input_mux = &cxt5045_capture_source;
+ spec->num_init_verbs = 2;
+ spec->init_verbs[1] = cxt5045_init_verbs;
+ spec->mixers[0] = cxt5045_mixers;
+ codec->patch_ops.init = cxt5045_init;
+ break;
+#ifdef CONFIG_SND_DEBUG
+ case CXT5045_TEST:
+ spec->input_mux = &cxt5045_test_capture_source;
+ spec->mixers[0] = cxt5045_test_mixer;
+ spec->init_verbs[0] = cxt5045_test_init_verbs;
+#endif
+ }
+ return 0;
+}
+
+
+/* Conexant 5047 specific */
+
+static hda_nid_t cxt5047_dac_nids[1] = { 0x10 };
+static hda_nid_t cxt5047_adc_nids[1] = { 0x12 };
+static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a };
+#define CXT5047_SPDIF_OUT 0x11
+
+static struct hda_channel_mode cxt5047_modes[1] = {
+ { 2, NULL },
+};
+
+static struct hda_input_mux cxt5047_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "ExtMic", 0x1 },
+ { "IntMic", 0x2 },
+ }
+};
+
+static struct hda_input_mux cxt5047_hp_capture_source = {
+ .num_items = 1,
+ .items = {
+ { "ExtMic", 0x1 },
+ }
+};
+
+/* turn on/off EAPD (+ mute HP) as a master switch */
+static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+
+ if (!conexant_eapd_put(kcontrol, ucontrol))
+ return 0;
+
+ /* toggle HP mute appropriately */
+ snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0,
+ 0x80, spec->cur_eapd ? 0 : 0x80);
+ snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0,
+ 0x80, spec->cur_eapd ? 0 : 0x80);
+ return 1;
+}
+
+#if 0
+/* bind volumes of both NID 0x13 and 0x1d */
+static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ long *valp = ucontrol->value.integer.value;
+ int change;
+
+ change = snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0,
+ 0x7f, valp[0] & 0x7f);
+ change |= snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0,
+ 0x7f, valp[1] & 0x7f);
+ snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0,
+ 0x7f, valp[0] & 0x7f);
+ snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0,
+ 0x7f, valp[1] & 0x7f);
+ return change;
+}
+#endif
+
+/* mute internal speaker if HP is plugged */
+static void cxt5047_hp_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x13, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+}
+
+/* toggle input of built-in and mic jack appropriately */
+static void cxt5047_hp_automic(struct hda_codec *codec)
+{
+ static struct hda_verb mic_jack_on[] = {
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ {}
+ };
+ static struct hda_verb mic_jack_off[] = {
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ {}
+ };
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x08, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ if (present)
+ snd_hda_sequence_write(codec, mic_jack_on);
+ else
+ snd_hda_sequence_write(codec, mic_jack_off);
+}
+
+/* unsolicited event for HP jack sensing */
+static void cxt5047_hp_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ res >>= 26;
+ switch (res) {
+ case CONEXANT_HP_EVENT:
+ cxt5047_hp_automute(codec);
+ break;
+ case CONEXANT_MIC_EVENT:
+ cxt5047_hp_automic(codec);
+ break;
+ }
+}
+
+static struct snd_kcontrol_new cxt5047_mixers[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = conexant_mux_enum_info,
+ .get = conexant_mux_enum_get,
+ .put = conexant_mux_enum_put
+ },
+ HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
+ HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = conexant_eapd_info,
+ .get = conexant_eapd_get,
+ .put = cxt5047_hp_master_sw_put,
+ .private_value = 0x13,
+ },
+
+ {}
+};
+
+static struct snd_kcontrol_new cxt5047_hp_mixers[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = conexant_mux_enum_info,
+ .get = conexant_mux_enum_get,
+ .put = conexant_mux_enum_put
+ },
+ HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19,0x02,HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
+ HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = conexant_eapd_info,
+ .get = conexant_eapd_get,
+ .put = cxt5047_hp_master_sw_put,
+ .private_value = 0x13,
+ },
+ { } /* end */
+};
+
+static struct hda_verb cxt5047_init_verbs[] = {
+ /* Line in, Mic, Built-in Mic */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
+ /* HP, Amp */
+ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ {0x1A, AC_VERB_SET_CONNECT_SEL,0x03},
+ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00},
+ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03},
+ /* Record selector: Front mic */
+ {0x12, AC_VERB_SET_CONNECT_SEL,0x03},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
+ /* SPDIF route: PCM */
+ { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 },
+ { } /* end */
+};
+
+/* configuration for Toshiba Laptops */
+static struct hda_verb cxt5047_toshiba_init_verbs[] = {
+ {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */
+ /* pin sensing on HP and Mic jacks */
+ {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+ {}
+};
+
+/* configuration for HP Laptops */
+static struct hda_verb cxt5047_hp_init_verbs[] = {
+ /* pin sensing on HP and Mic jacks */
+ {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+ {}
+};
+
+/* Test configuration for debugging, modelled after the ALC260 test
+ * configuration.
+ */
+#ifdef CONFIG_SND_DEBUG
+static struct hda_input_mux cxt5047_test_capture_source = {
+ .num_items = 5,
+ .items = {
+ { "MIXER", 0x0 },
+ { "LINE1 pin", 0x1 },
+ { "MIC1 pin", 0x2 },
+ { "MIC2 pin", 0x3 },
+ { "CD pin", 0x4 },
+ },
+};
+
+static struct snd_kcontrol_new cxt5047_test_mixer[] = {
+
+ /* Output only controls */
+ HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x00, HDA_OUTPUT),
+ HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x00, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x00, HDA_OUTPUT),
+ HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x00, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+
+ /* Modes for retasking pin widgets */
+ CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT),
+ CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT),
+
+ /* Loopback mixer controls */
+ HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x19, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("MIC1 Playback Switch", 0x19, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x19, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("MIC2 Playback Switch", 0x19, 0x03, HDA_INPUT),
+ HDA_CODEC_VOLUME("LINE Playback Volume", 0x19, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("LINE Playback Switch", 0x19, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x19, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x19, 0x04, HDA_INPUT),
+
+#if 0
+ /* Controls for GPIO pins, assuming they exist and are configured as outputs */
+ CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+ CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+ CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+ CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+#endif
+ CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x18, 0x01),
+
+ HDA_CODEC_VOLUME("Capture Volume", 0x19, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x19, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .info = conexant_mux_enum_info,
+ .get = conexant_mux_enum_get,
+ .put = conexant_mux_enum_put,
+ },
+
+ { } /* end */
+};
+
+static struct hda_verb cxt5047_test_init_verbs[] = {
+ /* Enable all GPIOs as outputs with an initial value of 0 */
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
+
+ /* Enable retasking pins as output, initially without power amp */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+ /* Disable digital (SPDIF) pins initially, but users can enable
+ * them via a mixer switch. In the case of SPDIF-out, this initverb
+ * payload also sets the generation to 0, output to be in "consumer"
+ * PCM format, copyright asserted, no pre-emphasis and no validity
+ * control.
+ */
+ {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+ /* Ensure mic1, mic2, line1 pin widgets take input from the
+ * OUT1 sum bus when acting as an output.
+ */
+ {0x1a, AC_VERB_SET_CONNECT_SEL, 0},
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0},
+
+ /* Start with output sum widgets muted and their output gains at min */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+ /* Unmute retasking pin widget output buffers since the default
+ * state appears to be output. As the pin mode is changed by the
+ * user the pin mode control will take care of enabling the pin's
+ * input/output buffers as needed.
+ */
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+ /* Mute capture amp left and right */
+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+
+ /* Set ADC connection select to match default mixer setting (mic1
+ * pin)
+ */
+ {0x12, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ /* Mute all inputs to mixer widget (even unconnected ones) */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+
+ { }
+};
+#endif
+
+
+/* initialize jack-sensing, too */
+static int cxt5047_hp_init(struct hda_codec *codec)
+{
+ conexant_init(codec);
+ cxt5047_hp_automute(codec);
+ cxt5047_hp_automic(codec);
+ return 0;
+}
+
+
+enum {
+ CXT5047_LAPTOP, /* Laptops w/o EAPD support */
+ CXT5047_LAPTOP_HP, /* Some HP laptops */
+ CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */
+#ifdef CONFIG_SND_DEBUG
+ CXT5047_TEST,
+#endif
+ CXT5047_MODELS
+};
+
+static const char *cxt5047_models[CXT5047_MODELS] = {
+ [CXT5047_LAPTOP] = "laptop",
+ [CXT5047_LAPTOP_HP] = "laptop-hp",
+ [CXT5047_LAPTOP_EAPD] = "laptop-eapd",
+#ifdef CONFIG_SND_DEBUG
+ [CXT5047_TEST] = "test",
+#endif
+};
+
+static struct snd_pci_quirk cxt5047_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP),
+ SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP),
+ SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
+ SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD),
+ {}
+};
+
+static int patch_cxt5047(struct hda_codec *codec)
+{
+ struct conexant_spec *spec;
+ int board_config;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+ mutex_init(&spec->amp_mutex);
+ codec->spec = spec;
+
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids);
+ spec->multiout.dac_nids = cxt5047_dac_nids;
+ spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT;
+ spec->num_adc_nids = 1;
+ spec->adc_nids = cxt5047_adc_nids;
+ spec->capsrc_nids = cxt5047_capsrc_nids;
+ spec->input_mux = &cxt5047_capture_source;
+ spec->num_mixers = 1;
+ spec->mixers[0] = cxt5047_mixers;
+ spec->num_init_verbs = 1;
+ spec->init_verbs[0] = cxt5047_init_verbs;
+ spec->spdif_route = 0;
+ spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes),
+ spec->channel_mode = cxt5047_modes,
+
+ codec->patch_ops = conexant_patch_ops;
+ codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
+
+ board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
+ cxt5047_models,
+ cxt5047_cfg_tbl);
+ switch (board_config) {
+ case CXT5047_LAPTOP:
+ break;
+ case CXT5047_LAPTOP_HP:
+ spec->input_mux = &cxt5047_hp_capture_source;
+ spec->num_init_verbs = 2;
+ spec->init_verbs[1] = cxt5047_hp_init_verbs;
+ spec->mixers[0] = cxt5047_hp_mixers;
+ codec->patch_ops.init = cxt5047_hp_init;
+ break;
+ case CXT5047_LAPTOP_EAPD:
+ spec->num_init_verbs = 2;
+ spec->init_verbs[1] = cxt5047_toshiba_init_verbs;
+ break;
+#ifdef CONFIG_SND_DEBUG
+ case CXT5047_TEST:
+ spec->input_mux = &cxt5047_test_capture_source;
+ spec->mixers[0] = cxt5047_test_mixer;
+ spec->init_verbs[0] = cxt5047_test_init_verbs;
+#endif
+ }
+ return 0;
+}
+
+struct hda_codec_preset snd_hda_preset_conexant[] = {
+ { .id = 0x14f15045, .name = "CXT5045", .patch = patch_cxt5045 },
+ { .id = 0x14f15047, .name = "CXT5047", .patch = patch_cxt5047 },
+ {} /* terminator */
+};
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index fb961448db1..145682b7807 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -32,6 +32,10 @@
#include "hda_codec.h"
#include "hda_local.h"
+#define ALC880_FRONT_EVENT 0x01
+#define ALC880_DCVOL_EVENT 0x02
+#define ALC880_HP_EVENT 0x04
+#define ALC880_MIC_EVENT 0x08
/* ALC880 board config type */
enum {
@@ -48,7 +52,10 @@ enum {
ALC880_ASUS_DIG,
ALC880_ASUS_W1V,
ALC880_ASUS_DIG2,
+ ALC880_FUJITSU,
ALC880_UNIWILL_DIG,
+ ALC880_UNIWILL,
+ ALC880_UNIWILL_P53,
ALC880_CLEVO,
ALC880_TCL_S700,
ALC880_LG,
@@ -77,8 +84,12 @@ enum {
/* ALC262 models */
enum {
ALC262_BASIC,
+ ALC262_HIPPO,
+ ALC262_HIPPO_1,
ALC262_FUJITSU,
ALC262_HP_BPC,
+ ALC262_HP_BPC_D7000_WL,
+ ALC262_HP_BPC_D7000_WF,
ALC262_BENQ_ED8,
ALC262_AUTO,
ALC262_MODEL_LAST /* last tag */
@@ -91,16 +102,30 @@ enum {
ALC861_3ST_DIG,
ALC861_6ST_DIG,
ALC861_UNIWILL_M31,
+ ALC861_TOSHIBA,
+ ALC861_ASUS,
+ ALC861_ASUS_LAPTOP,
ALC861_AUTO,
ALC861_MODEL_LAST,
};
+/* ALC861-VD models */
+enum {
+ ALC660VD_3ST,
+ ALC861VD_3ST,
+ ALC861VD_3ST_DIG,
+ ALC861VD_6ST_DIG,
+ ALC861VD_AUTO,
+ ALC861VD_MODEL_LAST,
+};
+
/* ALC882 models */
enum {
ALC882_3ST_DIG,
ALC882_6ST_DIG,
ALC882_ARIMA,
ALC882_AUTO,
+ ALC885_MACPRO,
ALC882_MODEL_LAST,
};
@@ -110,8 +135,12 @@ enum {
ALC883_3ST_6ch_DIG,
ALC883_3ST_6ch,
ALC883_6ST_DIG,
+ ALC883_TARGA_DIG,
+ ALC883_TARGA_2ch_DIG,
ALC888_DEMO_BOARD,
ALC883_ACER,
+ ALC883_MEDION,
+ ALC883_LAPTOP_EAPD,
ALC883_AUTO,
ALC883_MODEL_LAST,
};
@@ -271,7 +300,7 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
spec->num_channel_mode,
&spec->multiout.max_channels);
- if (! err && spec->need_dac_fix)
+ if (err >= 0 && spec->need_dac_fix)
spec->multiout.num_dacs = spec->multiout.max_channels / 2;
return err;
}
@@ -1015,6 +1044,60 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
{ } /* end */
};
+/* Uniwill */
+static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
+ HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = alc_ch_mode_info,
+ .get = alc_ch_mode_get,
+ .put = alc_ch_mode_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
+ HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ { } /* end */
+};
+
/*
* build control elements
*/
@@ -1248,6 +1331,159 @@ static struct hda_verb alc880_pin_6stack_init_verbs[] = {
{ }
};
+/*
+ * Uniwill pin configuration:
+ * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
+ * line = 0x1a
+ */
+static struct hda_verb alc880_uniwill_init_verbs[] = {
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
+ /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+
+ { }
+};
+
+/*
+* Uniwill P53
+* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
+ */
+static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+ {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
+
+ { }
+};
+
+static struct hda_verb alc880_beep_init_verbs[] = {
+ { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
+ { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc880_uniwill_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x14, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x16, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+
+ present = snd_hda_codec_read(codec, 0x18, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_write(codec, 0x0b, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
+}
+
+static void alc880_uniwill_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ /* Looks like the unsol event is incompatible with the standard
+ * definition. 4bit tag is placed at 28 bit!
+ */
+ if ((res >> 28) == ALC880_HP_EVENT ||
+ (res >> 28) == ALC880_MIC_EVENT)
+ alc880_uniwill_automute(codec);
+}
+
+static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x14, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+ snd_hda_codec_amp_update(codec, 0x15, 0, HDA_INPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x15, 1, HDA_INPUT, 0,
+ 0x80, present ? 0x80 : 0);
+}
+
+static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x21, 0,
+ AC_VERB_GET_VOLUME_KNOB_CONTROL, 0) & 0x7f;
+
+ snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0,
+ 0x7f, present);
+ snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0,
+ 0x7f, present);
+
+ snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0,
+ 0x7f, present);
+ snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0,
+ 0x7f, present);
+
+}
+static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ /* Looks like the unsol event is incompatible with the standard
+ * definition. 4bit tag is placed at 28 bit!
+ */
+ if ((res >> 28) == ALC880_HP_EVENT)
+ alc880_uniwill_p53_hp_automute(codec);
+ if ((res >> 28) == ALC880_DCVOL_EVENT)
+ alc880_uniwill_p53_dcvol_automute(codec);
+}
+
/* FIXME! */
/*
* F1734 pin configuration:
@@ -2125,159 +2361,112 @@ static struct hda_verb alc880_test_init_verbs[] = {
/*
*/
-static struct hda_board_config alc880_cfg_tbl[] = {
- /* Back 3 jack, front 2 jack */
- { .modelname = "3stack", .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe212, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe213, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe234, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST },
- /* TCL S700 */
- { .modelname = "tcl", .config = ALC880_TCL_S700 },
- { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 },
-
- /* Back 3 jack, front 2 jack (Internal add Aux-In) */
- { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST },
-
- /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
- { .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
-
- /* Clevo laptops */
- { .modelname = "clevo", .config = ALC880_CLEVO },
- { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520,
- .config = ALC880_CLEVO }, /* Clevo m520G NB */
- { .pci_subvendor = 0x1558, .pci_subdevice = 0x0660,
- .config = ALC880_CLEVO }, /* Clevo m665n */
-
- /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG },
-
- /* Back 5 jack, front 2 jack */
- { .modelname = "5stack", .config = ALC880_5ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST },
- { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST },
-
- /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */
- { .modelname = "5stack-digout", .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0xa0a0, .pci_subdevice = 0x0560,
- .config = ALC880_5ST_DIG }, /* Aopen i915GMm-HFS */
- /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */
- { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG },
- /* note subvendor = 0 below */
- /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */
-
- { .modelname = "w810", .config = ALC880_W810 },
- { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 },
-
- { .modelname = "z71v", .config = ALC880_Z71V },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V },
-
- { .modelname = "6stack", .config = ALC880_6ST },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x8196, .config = ALC880_6ST }, /* ASUS P5GD1-HVM */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b4, .config = ALC880_6ST },
- { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */
- { .pci_subvendor = 0x1458, .pci_subdevice = 0xa102, .config = ALC880_6ST }, /* Gigabyte K8N51 */
-
- { .modelname = "6stack-digout", .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1039, .pci_subdevice = 0x1234, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x0077, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG },
- { .pci_subvendor = 0x1297, .pci_subdevice = 0xc790, .config = ALC880_6ST_DIG }, /* Shuttle ST20G5 */
- { .pci_subvendor = 0x1509, .pci_subdevice = 0x925d, .config = ALC880_6ST_DIG }, /* FIC P4M-915GD1 */
- { .pci_subvendor = 0x1695, .pci_subdevice = 0x4012, .config = ALC880_5ST_DIG }, /* Epox EP-5LDA+ GLi */
-
- { .modelname = "asus", .config = ALC880_ASUS },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c2, .config = ALC880_ASUS_DIG }, /* Asus W6A */
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
- { .modelname = "asus-w1v", .config = ALC880_ASUS_W1V },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
- { .modelname = "asus-dig", .config = ALC880_ASUS_DIG },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */
- { .modelname = "asus-dig2", .config = ALC880_ASUS_DIG2 },
- { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 },
-
- { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
- { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG },
-
- { .modelname = "F1734", .config = ALC880_F1734 },
- { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 },
- { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 },
-
- { .modelname = "lg", .config = ALC880_LG },
- { .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG },
- { .pci_subvendor = 0x1854, .pci_subdevice = 0x0068, .config = ALC880_LG },
-
- { .modelname = "lg-lw", .config = ALC880_LG_LW },
- { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW },
- { .pci_subvendor = 0x1854, .pci_subdevice = 0x0077, .config = ALC880_LG_LW },
-
+static const char *alc880_models[ALC880_MODEL_LAST] = {
+ [ALC880_3ST] = "3stack",
+ [ALC880_TCL_S700] = "tcl",
+ [ALC880_3ST_DIG] = "3stack-digout",
+ [ALC880_CLEVO] = "clevo",
+ [ALC880_5ST] = "5stack",
+ [ALC880_5ST_DIG] = "5stack-digout",
+ [ALC880_W810] = "w810",
+ [ALC880_Z71V] = "z71v",
+ [ALC880_6ST] = "6stack",
+ [ALC880_6ST_DIG] = "6stack-digout",
+ [ALC880_ASUS] = "asus",
+ [ALC880_ASUS_W1V] = "asus-w1v",
+ [ALC880_ASUS_DIG] = "asus-dig",
+ [ALC880_ASUS_DIG2] = "asus-dig2",
+ [ALC880_UNIWILL_DIG] = "uniwill",
+ [ALC880_UNIWILL_P53] = "uniwill-p53",
+ [ALC880_FUJITSU] = "fujitsu",
+ [ALC880_F1734] = "F1734",
+ [ALC880_LG] = "lg",
+ [ALC880_LG_LW] = "lg-lw",
#ifdef CONFIG_SND_DEBUG
- { .modelname = "test", .config = ALC880_TEST },
+ [ALC880_TEST] = "test",
#endif
- { .modelname = "auto", .config = ALC880_AUTO },
+ [ALC880_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc880_cfg_tbl[] = {
+ /* Broken BIOS configuration */
+ SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
+
+ SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
+ SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
+ SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
+
+ SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
+
+ SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
+ SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
+ /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
+ SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS),
+ SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
+ SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
+ SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
+ SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS),
+
+ SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
+ SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
+ SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
+ SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
+ SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
+ SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
+ SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
+ SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
+ SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
+ SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
+ SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
+
+ SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
+ SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
+ SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
+ SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
+
+ SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
+ SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
+ SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
+
+ SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
+ SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
+ SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
+ SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
+
+ SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST),
{}
};
@@ -2438,7 +2627,8 @@ static struct alc_config_preset alc880_presets[] = {
},
[ALC880_UNIWILL_DIG] = {
.mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
- .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs },
+ .init_verbs = { alc880_volume_init_verbs,
+ alc880_pin_asus_init_verbs },
.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
.dac_nids = alc880_asus_dac_nids,
.dig_out_nid = ALC880_DIGOUT_NID,
@@ -2447,6 +2637,46 @@ static struct alc_config_preset alc880_presets[] = {
.need_dac_fix = 1,
.input_mux = &alc880_capture_source,
},
+ [ALC880_UNIWILL] = {
+ .mixers = { alc880_uniwill_mixer },
+ .init_verbs = { alc880_volume_init_verbs,
+ alc880_uniwill_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+ .dac_nids = alc880_asus_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
+ .channel_mode = alc880_threestack_modes,
+ .need_dac_fix = 1,
+ .input_mux = &alc880_capture_source,
+ .unsol_event = alc880_uniwill_unsol_event,
+ .init_hook = alc880_uniwill_automute,
+ },
+ [ALC880_UNIWILL_P53] = {
+ .mixers = { alc880_uniwill_p53_mixer },
+ .init_verbs = { alc880_volume_init_verbs,
+ alc880_uniwill_p53_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
+ .dac_nids = alc880_asus_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
+ .channel_mode = alc880_threestack_modes,
+ .input_mux = &alc880_capture_source,
+ .unsol_event = alc880_uniwill_p53_unsol_event,
+ .init_hook = alc880_uniwill_p53_hp_automute,
+ },
+ [ALC880_FUJITSU] = {
+ .mixers = { alc880_fujitsu_mixer,
+ alc880_pcbeep_mixer, },
+ .init_verbs = { alc880_volume_init_verbs,
+ alc880_uniwill_p53_init_verbs,
+ alc880_beep_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+ .dac_nids = alc880_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+ .channel_mode = alc880_2_jack_modes,
+ .input_mux = &alc880_capture_source,
+ .unsol_event = alc880_uniwill_p53_unsol_event,
+ .init_hook = alc880_uniwill_p53_hp_automute,
+ },
[ALC880_CLEVO] = {
.mixers = { alc880_three_stack_mixer },
.init_verbs = { alc880_volume_init_verbs,
@@ -2841,8 +3071,10 @@ static int patch_alc880(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
- if (board_config < 0 || board_config >= ALC880_MODEL_LAST) {
+ board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
+ alc880_models,
+ alc880_cfg_tbl);
+ if (board_config < 0) {
printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
"trying auto-probe from BIOS...\n");
board_config = ALC880_AUTO;
@@ -3090,11 +3322,20 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
* and the output jack. If this turns out to be the case for all such
* models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
* to ALC_PIN_DIR_INOUT_NOMICBIAS.
+ *
+ * The C20x Tablet series have a mono internal speaker which is controlled
+ * via the chip's Mono sum widget and pin complex, so include the necessary
+ * controls for such models. On models without a "mono speaker" the control
+ * won't do anything.
*/
static struct snd_kcontrol_new alc260_acer_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
+ HDA_CODEC_VOLUME_MONO("Mono Speaker Playback Volume", 0x0a, 1, 0x0,
+ HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Mono Speaker Playback Switch", 0x0a, 1, 2,
+ HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
@@ -3409,11 +3650,11 @@ static struct hda_verb alc260_acer_init_verbs[] = {
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
/* Line In jack is connected to Line1 pin */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
/* Ensure all other unused pins are disabled and muted. */
{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -3441,6 +3682,8 @@ static struct hda_verb alc260_acer_init_verbs[] = {
/* Unmute Line-out pin widget amp left and right (no equiv mixer ctrl) */
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Unmute Mic1 and Line1 pin widget input buffers since they start as
* inputs. If the pin mode is changed by the user the pin mode control
* will take care of enabling the pin's input/output buffers as needed.
@@ -3928,33 +4171,33 @@ static void alc260_auto_init(struct hda_codec *codec)
/*
* ALC260 configurations
*/
-static struct hda_board_config alc260_cfg_tbl[] = {
- { .modelname = "basic", .config = ALC260_BASIC },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb,
- .config = ALC260_BASIC }, /* Sony VAIO */
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cc,
- .config = ALC260_BASIC }, /* Sony VAIO VGN-S3HP */
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cd,
- .config = ALC260_BASIC }, /* Sony VAIO */
- { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729,
- .config = ALC260_BASIC }, /* CTL Travel Master U553W */
- { .modelname = "hp", .config = ALC260_HP },
- { .modelname = "hp-3013", .config = ALC260_HP_3013 },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP_3013 },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP },
- { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X },
- { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X },
- { .modelname = "acer", .config = ALC260_ACER },
- { .pci_subvendor = 0x1025, .pci_subdevice = 0x008f, .config = ALC260_ACER },
+static const char *alc260_models[ALC260_MODEL_LAST] = {
+ [ALC260_BASIC] = "basic",
+ [ALC260_HP] = "hp",
+ [ALC260_HP_3013] = "hp-3013",
+ [ALC260_FUJITSU_S702X] = "fujitsu",
+ [ALC260_ACER] = "acer",
#ifdef CONFIG_SND_DEBUG
- { .modelname = "test", .config = ALC260_TEST },
+ [ALC260_TEST] = "test",
#endif
- { .modelname = "auto", .config = ALC260_AUTO },
+ [ALC260_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc260_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
+ SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
+ SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
+ SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
+ SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
+ SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
+ SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
+ SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
+ SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
+ SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
+ SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
+ SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
+ SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
+ SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
{}
};
@@ -4053,8 +4296,10 @@ static int patch_alc260(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl);
- if (board_config < 0 || board_config >= ALC260_MODEL_LAST) {
+ board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
+ alc260_models,
+ alc260_cfg_tbl);
+ if (board_config < 0) {
snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
"trying auto-probe from BIOS...\n");
board_config = ALC260_AUTO;
@@ -4207,8 +4452,10 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4313,6 +4560,100 @@ static struct hda_verb alc882_eapd_verbs[] = {
{ }
};
+/* Mac Pro test */
+static struct snd_kcontrol_new alc882_macpro_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ { } /* end */
+};
+
+static struct hda_verb alc882_macpro_init_verbs[] = {
+ /* Front mixer: unmute input/output amp left and right (volume = 0) */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ /* Front Pin: output 0 (0x0c) */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* Front Mic pin: input vref at 80% */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Speaker: output */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
+ /* Headphone output (output 0 - 0x0c) */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ /* FIXME: use matrix-type input source selection */
+ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ /* Input mixer2 */
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ /* Input mixer3 */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ /* ADC1: mute amp left and right */
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* ADC2: mute amp left and right */
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* ADC3: mute amp left and right */
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ { }
+};
+static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
+{
+ unsigned int gpiostate, gpiomask, gpiodir;
+
+ gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_DATA, 0);
+
+ if (!muted)
+ gpiostate |= (1 << pin);
+ else
+ gpiostate &= ~(1 << pin);
+
+ gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_MASK, 0);
+ gpiomask |= (1 << pin);
+
+ gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_DIRECTION, 0);
+ gpiodir |= (1 << pin);
+
+
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_MASK, gpiomask);
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DIRECTION, gpiodir);
+
+ msleep(1);
+
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DATA, gpiostate);
+}
+
/*
* generic initialization of ADC, input mixers and output mixers
*/
@@ -4435,19 +4776,20 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = {
/*
* configuration and preset
*/
-static struct hda_board_config alc882_cfg_tbl[] = {
- { .modelname = "3stack-dig", .config = ALC882_3ST_DIG },
- { .modelname = "6stack-dig", .config = ALC882_6ST_DIG },
- { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668,
- .config = ALC882_6ST_DIG }, /* MSI */
- { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668,
- .config = ALC882_6ST_DIG }, /* Foxconn */
- { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
- .config = ALC882_6ST_DIG }, /* ECS to Intel*/
- { .modelname = "arima", .config = ALC882_ARIMA },
- { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054,
- .config = ALC882_ARIMA }, /* Arima W820Di1 */
- { .modelname = "auto", .config = ALC882_AUTO },
+static const char *alc882_models[ALC882_MODEL_LAST] = {
+ [ALC882_3ST_DIG] = "3stack-dig",
+ [ALC882_6ST_DIG] = "6stack-dig",
+ [ALC882_ARIMA] = "arima",
+ [ALC885_MACPRO] = "macpro",
+ [ALC882_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc882_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
+ SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
{}
};
@@ -4484,6 +4826,17 @@ static struct alc_config_preset alc882_presets[] = {
.channel_mode = alc882_sixstack_modes,
.input_mux = &alc882_capture_source,
},
+ [ALC885_MACPRO] = {
+ .mixers = { alc882_macpro_mixer },
+ .init_verbs = { alc882_macpro_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .dig_in_nid = ALC882_DIGIN_NID,
+ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+ .channel_mode = alc882_ch_modes,
+ .input_mux = &alc882_capture_source,
+ },
};
@@ -4584,7 +4937,9 @@ static int patch_alc882(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl);
+ board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
+ alc882_models,
+ alc882_cfg_tbl);
if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
@@ -4609,6 +4964,11 @@ static int patch_alc882(struct hda_codec *codec)
if (board_config != ALC882_AUTO)
setup_preset(spec, &alc882_presets[board_config]);
+ if (board_config == ALC885_MACPRO) {
+ alc882_gpio_mute(codec, 0, 0);
+ alc882_gpio_mute(codec, 1, 0);
+ }
+
spec->stream_name_analog = "ALC882 Analog";
spec->stream_analog_playback = &alc882_pcm_analog_playback;
spec->stream_analog_capture = &alc882_pcm_analog_capture;
@@ -4767,6 +5127,13 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = {
{ 8, alc883_sixstack_ch8_init },
};
+static struct hda_verb alc883_medion_eapd_verbs[] = {
+ /* eanable EAPD on medion laptop */
+ {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+ {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
+ { }
+};
+
/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
* Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
*/
@@ -4788,8 +5155,10 @@ static struct snd_kcontrol_new alc883_base_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4818,8 +5187,10 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4854,8 +5225,10 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
@@ -4875,6 +5248,101 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
{ } /* end */
};
+static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 1,
+ .info = alc883_mux_enum_info,
+ .get = alc883_mux_enum_get,
+ .put = alc883_mux_enum_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc883_tagra_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = alc883_mux_enum_info,
+ .get = alc883_mux_enum_get,
+ .put = alc883_mux_enum_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = alc883_mux_enum_info,
+ .get = alc883_mux_enum_get,
+ .put = alc883_mux_enum_put,
+ },
+ { } /* end */
+};
+
static struct snd_kcontrol_new alc883_chmode_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -4963,6 +5431,45 @@ static struct hda_verb alc883_init_verbs[] = {
{ }
};
+static struct hda_verb alc883_tagra_verbs[] = {
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+ {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
+
+ { } /* end */
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_tagra_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x14, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3);
+}
+
+static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ if ((res >> 26) == ALC880_HP_EVENT)
+ alc883_tagra_automute(codec);
+}
+
/*
* generic initialization of ADC, input mixers and output mixers
*/
@@ -5057,30 +5564,42 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = {
/*
* configuration and preset
*/
-static struct hda_board_config alc883_cfg_tbl[] = {
- { .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG },
- { .modelname = "3stack-6ch-dig", .config = ALC883_3ST_6ch_DIG },
- { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668,
- .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/
- { .modelname = "3stack-6ch", .config = ALC883_3ST_6ch },
- { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d,
- .config = ALC883_3ST_6ch },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xd601,
- .config = ALC883_3ST_6ch }, /* D102GGC */
- { .modelname = "6stack-dig", .config = ALC883_6ST_DIG },
- { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668,
- .config = ALC883_6ST_DIG }, /* MSI */
- { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668,
- .config = ALC883_6ST_DIG }, /* Foxconn */
- { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD },
- { .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 },
+static const char *alc883_models[ALC883_MODEL_LAST] = {
+ [ALC883_3ST_2ch_DIG] = "3stack-dig",
+ [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
+ [ALC883_3ST_6ch] = "3stack-6ch",
+ [ALC883_6ST_DIG] = "6stack-dig",
+ [ALC883_TARGA_DIG] = "targa-dig",
+ [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
+ [ALC888_DEMO_BOARD] = "6stack-dig-demo",
+ [ALC883_ACER] = "acer",
+ [ALC883_MEDION] = "medion",
+ [ALC883_LAPTOP_EAPD] = "laptop-eapd",
+ [ALC883_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc883_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
+ SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
+ SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
+ SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
+ SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER),
+ SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
+ SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
{}
};
@@ -5137,6 +5656,35 @@ static struct alc_config_preset alc883_presets[] = {
.channel_mode = alc883_sixstack_modes,
.input_mux = &alc883_capture_source,
},
+ [ALC883_TARGA_DIG] = {
+ .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
+ .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .dig_out_nid = ALC883_DIGOUT_NID,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+ .adc_nids = alc883_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+ .channel_mode = alc883_3ST_6ch_modes,
+ .need_dac_fix = 1,
+ .input_mux = &alc883_capture_source,
+ .unsol_event = alc883_tagra_unsol_event,
+ .init_hook = alc883_tagra_automute,
+ },
+ [ALC883_TARGA_2ch_DIG] = {
+ .mixers = { alc883_tagra_2ch_mixer},
+ .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .dig_out_nid = ALC883_DIGOUT_NID,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+ .adc_nids = alc883_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+ .channel_mode = alc883_3ST_2ch_modes,
+ .input_mux = &alc883_capture_source,
+ .unsol_event = alc883_tagra_unsol_event,
+ .init_hook = alc883_tagra_automute,
+ },
[ALC888_DEMO_BOARD] = {
.mixers = { alc883_base_mixer, alc883_chmode_mixer },
.init_verbs = { alc883_init_verbs },
@@ -5167,6 +5715,31 @@ static struct alc_config_preset alc883_presets[] = {
.channel_mode = alc883_3ST_2ch_modes,
.input_mux = &alc883_capture_source,
},
+ [ALC883_MEDION] = {
+ .mixers = { alc883_fivestack_mixer,
+ alc883_chmode_mixer },
+ .init_verbs = { alc883_init_verbs,
+ alc883_medion_eapd_verbs },
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+ .adc_nids = alc883_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+ .channel_mode = alc883_sixstack_modes,
+ .input_mux = &alc883_capture_source,
+ },
+ [ALC883_LAPTOP_EAPD] = {
+ .mixers = { alc883_base_mixer,
+ alc883_chmode_mixer },
+ .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+ .adc_nids = alc883_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+ .channel_mode = alc883_3ST_2ch_modes,
+ .input_mux = &alc883_capture_source,
+ },
};
@@ -5275,8 +5848,10 @@ static int patch_alc883(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, alc883_cfg_tbl);
- if (board_config < 0 || board_config >= ALC883_MODEL_LAST) {
+ board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
+ alc883_models,
+ alc883_cfg_tbl);
+ if (board_config < 0) {
printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
"trying auto-probe from BIOS...\n");
board_config = ALC883_AUTO;
@@ -5353,6 +5928,24 @@ static struct snd_kcontrol_new alc262_base_mixer[] = {
{ } /* end */
};
+static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
+ /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ { } /* end */
+};
+
static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -5375,6 +5968,30 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
{ } /* end */
};
+static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
+ HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ { } /* end */
+};
+
#define alc262_capture_mixer alc882_capture_mixer
#define alc262_capture_alt_mixer alc882_capture_alt_mixer
@@ -5457,6 +6074,103 @@ static struct hda_verb alc262_init_verbs[] = {
{ }
};
+static struct hda_verb alc262_hippo_unsol_verbs[] = {
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {}
+};
+
+static struct hda_verb alc262_hippo1_unsol_verbs[] = {
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+
+ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {}
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_hippo_automute(struct hda_codec *codec, int force)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int mute;
+
+ if (force || ! spec->sense_updated) {
+ unsigned int present;
+ /* need to execute and sync at first */
+ snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
+ present = snd_hda_codec_read(codec, 0x15, 0,
+ AC_VERB_GET_PIN_SENSE, 0);
+ spec->jack_present = (present & 0x80000000) != 0;
+ spec->sense_updated = 1;
+ }
+ if (spec->jack_present) {
+ /* mute internal speaker */
+ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+ 0x80, 0x80);
+ snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+ 0x80, 0x80);
+ } else {
+ /* unmute internal speaker if necessary */
+ mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
+ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+ 0x80, mute & 0x80);
+ mute = snd_hda_codec_amp_read(codec, 0x15, 1, HDA_OUTPUT, 0);
+ snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+ 0x80, mute & 0x80);
+ }
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_hippo_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ if ((res >> 26) != ALC880_HP_EVENT)
+ return;
+ alc262_hippo_automute(codec, 1);
+}
+
+static void alc262_hippo1_automute(struct hda_codec *codec, int force)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int mute;
+
+ if (force || ! spec->sense_updated) {
+ unsigned int present;
+ /* need to execute and sync at first */
+ snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
+ present = snd_hda_codec_read(codec, 0x1b, 0,
+ AC_VERB_GET_PIN_SENSE, 0);
+ spec->jack_present = (present & 0x80000000) != 0;
+ spec->sense_updated = 1;
+ }
+ if (spec->jack_present) {
+ /* mute internal speaker */
+ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+ 0x80, 0x80);
+ snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+ 0x80, 0x80);
+ } else {
+ /* unmute internal speaker if necessary */
+ mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
+ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+ 0x80, mute & 0x80);
+ mute = snd_hda_codec_amp_read(codec, 0x1b, 1, HDA_OUTPUT, 0);
+ snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+ 0x80, mute & 0x80);
+ }
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_hippo1_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ if ((res >> 26) != ALC880_HP_EVENT)
+ return;
+ alc262_hippo1_automute(codec, 1);
+}
+
/*
* fujitsu model
* 0x14 = headphone/spdif-out, 0x15 = internal speaker
@@ -5807,6 +6521,100 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = {
{ }
};
+static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
+ /*
+ * Unmute ADC0-2 and set the default input to mic-in
+ */
+ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ * Note: PASD motherboards uses the Line In 2 as the input for front
+ * panel mic (mic 2)
+ */
+ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)},
+ /*
+ * Set up output mixers (0x0c - 0x0e)
+ */
+ /* set vol=0 to output mixers */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /* set up input amps for analog loopback */
+ /* Amp Indices: DAC = 0, mixer = 1 */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
+
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+
+ /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
+
+ /* FIXME: use matrix-type input source selection */
+ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
+ /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
+ /* Input mixer2 */
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+ /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
+ /* Input mixer3 */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+ /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
+
+ { }
+};
+
/* pcm configuration: identiacal with ALC880 */
#define alc262_pcm_analog_playback alc880_pcm_analog_playback
#define alc262_pcm_analog_capture alc880_pcm_analog_capture
@@ -5864,24 +6672,35 @@ static void alc262_auto_init(struct hda_codec *codec)
/*
* configuration and preset
*/
-static struct hda_board_config alc262_cfg_tbl[] = {
- { .modelname = "basic", .config = ALC262_BASIC },
- { .modelname = "fujitsu", .config = ALC262_FUJITSU },
- { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397,
- .config = ALC262_FUJITSU },
- { .modelname = "hp-bpc", .config = ALC262_HP_BPC },
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x280c,
- .config = ALC262_HP_BPC }, /* xw4400 */
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014,
- .config = ALC262_HP_BPC }, /* xw6400 */
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015,
- .config = ALC262_HP_BPC }, /* xw8400 */
- { .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe,
- .config = ALC262_HP_BPC }, /* xw9400 */
- { .modelname = "benq", .config = ALC262_BENQ_ED8 },
- { .pci_subvendor = 0x17ff, .pci_subdevice = 0x0560,
- .config = ALC262_BENQ_ED8 },
- { .modelname = "auto", .config = ALC262_AUTO },
+static const char *alc262_models[ALC262_MODEL_LAST] = {
+ [ALC262_BASIC] = "basic",
+ [ALC262_HIPPO] = "hippo",
+ [ALC262_HIPPO_1] = "hippo_1",
+ [ALC262_FUJITSU] = "fujitsu",
+ [ALC262_HP_BPC] = "hp-bpc",
+ [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
+ [ALC262_BENQ_ED8] = "benq",
+ [ALC262_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc262_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
+ SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
+ SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
+ SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
+ SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
+ SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
+ SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
+ SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
+ SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
+ SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
+ SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
+ SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
+ SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
{}
};
@@ -5896,6 +6715,30 @@ static struct alc_config_preset alc262_presets[] = {
.channel_mode = alc262_modes,
.input_mux = &alc262_capture_source,
},
+ [ALC262_HIPPO] = {
+ .mixers = { alc262_base_mixer },
+ .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
+ .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+ .dac_nids = alc262_dac_nids,
+ .hp_nid = 0x03,
+ .dig_out_nid = ALC262_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc262_modes),
+ .channel_mode = alc262_modes,
+ .input_mux = &alc262_capture_source,
+ .unsol_event = alc262_hippo_unsol_event,
+ },
+ [ALC262_HIPPO_1] = {
+ .mixers = { alc262_hippo1_mixer },
+ .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
+ .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+ .dac_nids = alc262_dac_nids,
+ .hp_nid = 0x02,
+ .dig_out_nid = ALC262_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc262_modes),
+ .channel_mode = alc262_modes,
+ .input_mux = &alc262_capture_source,
+ .unsol_event = alc262_hippo1_unsol_event,
+ },
[ALC262_FUJITSU] = {
.mixers = { alc262_fujitsu_mixer },
.init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs },
@@ -5918,6 +6761,27 @@ static struct alc_config_preset alc262_presets[] = {
.channel_mode = alc262_modes,
.input_mux = &alc262_HP_capture_source,
},
+ [ALC262_HP_BPC_D7000_WF] = {
+ .mixers = { alc262_HP_BPC_WildWest_mixer },
+ .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+ .dac_nids = alc262_dac_nids,
+ .hp_nid = 0x03,
+ .num_channel_mode = ARRAY_SIZE(alc262_modes),
+ .channel_mode = alc262_modes,
+ .input_mux = &alc262_HP_capture_source,
+ },
+ [ALC262_HP_BPC_D7000_WL] = {
+ .mixers = { alc262_HP_BPC_WildWest_mixer,
+ alc262_HP_BPC_WildWest_option_mixer },
+ .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+ .dac_nids = alc262_dac_nids,
+ .hp_nid = 0x03,
+ .num_channel_mode = ARRAY_SIZE(alc262_modes),
+ .channel_mode = alc262_modes,
+ .input_mux = &alc262_HP_capture_source,
+ },
[ALC262_BENQ_ED8] = {
.mixers = { alc262_base_mixer },
.init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
@@ -5936,7 +6800,7 @@ static int patch_alc262(struct hda_codec *codec)
int board_config;
int err;
- spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
@@ -5952,9 +6816,11 @@ static int patch_alc262(struct hda_codec *codec)
}
#endif
- board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl);
-
- if (board_config < 0 || board_config >= ALC262_MODEL_LAST) {
+ board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
+ alc262_models,
+ alc262_cfg_tbl);
+
+ if (board_config < 0) {
printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
"trying auto-probe from BIOS...\n");
board_config = ALC262_AUTO;
@@ -6074,6 +6940,44 @@ static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
{ 4, alc861_uniwill_m31_ch4_init },
};
+/* Set mic1 and line-in as input and unmute the mixer */
+static struct hda_verb alc861_asus_ch2_init[] = {
+ /* set pin widget 1Ah (line in) for input */
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ /* set pin widget 18h (mic1/2) for input, for mic also enable the vref */
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
+#if 0
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
+#endif
+ { } /* end */
+};
+/* Set mic1 nad line-in as output and mute mixer */
+static struct hda_verb alc861_asus_ch6_init[] = {
+ /* set pin widget 1Ah (line in) for output (Back Surround)*/
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
+ /* set pin widget 18h (mic1) for output (CLFE)*/
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
+ { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
+
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+#if 0
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
+#endif
+ { } /* end */
+};
+
+static struct hda_channel_mode alc861_asus_modes[2] = {
+ { 2, alc861_asus_ch2_init },
+ { 6, alc861_asus_ch6_init },
+};
+
/* patch-ALC861 */
static struct snd_kcontrol_new alc861_base_mixer[] = {
@@ -6150,7 +7054,29 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = {
.private_value = ARRAY_SIZE(alc861_threestack_modes),
},
{ } /* end */
-};
+};
+
+static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
+ /* output mixer control */
+ HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+
+ /*Capture mixer control */
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .count = 1,
+ .info = alc_mux_enum_info,
+ .get = alc_mux_enum_get,
+ .put = alc_mux_enum_put,
+ },
+
+ { } /* end */
+};
+
static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
/* output mixer control */
HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
@@ -6192,7 +7118,58 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
},
{ } /* end */
};
-
+
+static struct snd_kcontrol_new alc861_asus_mixer[] = {
+ /* output mixer control */
+ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
+
+ /* Input mixer control */
+ HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), /* was HDA_INPUT (why?) */
+
+ /* Capture mixer control */
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .count = 1,
+ .info = alc_mux_enum_info,
+ .get = alc_mux_enum_get,
+ .put = alc_mux_enum_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = alc_ch_mode_info,
+ .get = alc_ch_mode_get,
+ .put = alc_ch_mode_put,
+ .private_value = ARRAY_SIZE(alc861_asus_modes),
+ },
+ { }
+};
+
+/* additional mixer */
+static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
+ { }
+};
+
/*
* generic initialization of ADC, input mixers and output mixers
*/
@@ -6213,7 +7190,7 @@ static struct hda_verb alc861_base_init_verbs[] = {
/* port-E for HP out (front panel) */
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
/* route front PCM to HP */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
/* port-F for mic-in (front panel) with vref */
{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
/* port-G for CLFE (rear panel) */
@@ -6277,7 +7254,7 @@ static struct hda_verb alc861_threestack_init_verbs[] = {
/* port-E for HP out (front panel) */
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
/* route front PCM to HP */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
/* port-F for mic-in (front panel) with vref */
{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
/* port-G for CLFE (rear panel) */
@@ -6337,7 +7314,7 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
/* port-E for HP out (front panel) */
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80
/* route front PCM to HP */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
/* port-F for mic-in (front panel) with vref */
{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
/* port-G for CLFE (rear panel) */
@@ -6381,6 +7358,74 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
{ }
};
+static struct hda_verb alc861_asus_init_verbs[] = {
+ /*
+ * Unmute ADC0 and set the default input to mic-in
+ */
+ /* port-A for surround (rear panel) | according to codec#0 this is the HP jack*/
+ { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
+ /* route front PCM to HP */
+ { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
+ /* port-B for mic-in (rear panel) with vref */
+ { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* port-C for line-in (rear panel) */
+ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ /* port-D for Front */
+ { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ /* port-E for HP out (front panel) */
+ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* this has to be set to VREF80 */
+ /* route front PCM to HP */
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+ /* port-F for mic-in (front panel) with vref */
+ { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+ /* port-G for CLFE (rear panel) */
+ { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* port-H for side (rear panel) */
+ { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+ /* CD-in */
+ { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+ /* route front mic to ADC1*/
+ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ /* Unmute DAC0~3 & spdif out*/
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Unmute Mixer 14 (mic) 1c (Line in)*/
+ {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+ /* Unmute Stereo Mixer 15 */
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, /* Output 0~12 step */
+
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, /* hp used DAC 3 (Front) */
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ { }
+};
+
+/* additional init verbs for ASUS laptops */
+static struct hda_verb alc861_asus_laptop_init_verbs[] = {
+ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
+ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
+ { }
+};
+
/*
* generic initialization of ADC, input mixers and output mixers
*/
@@ -6433,6 +7478,39 @@ static struct hda_verb alc861_auto_init_verbs[] = {
{ }
};
+static struct hda_verb alc861_toshiba_init_verbs[] = {
+ {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+
+ { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc861_toshiba_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x0f, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x16, 0, HDA_INPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x16, 1, HDA_INPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_INPUT, 3,
+ 0x80, present ? 0 : 0x80);
+ snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_INPUT, 3,
+ 0x80, present ? 0 : 0x80);
+}
+
+static void alc861_toshiba_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ /* Looks like the unsol event is incompatible with the standard
+ * definition. 6bit tag is placed at 26 bit!
+ */
+ if ((res >> 26) == ALC880_HP_EVENT)
+ alc861_toshiba_automute(codec);
+}
+
/* pcm configuration: identiacal with ALC880 */
#define alc861_pcm_analog_playback alc880_pcm_analog_playback
#define alc861_pcm_analog_capture alc880_pcm_analog_capture
@@ -6706,19 +7784,29 @@ static void alc861_auto_init(struct hda_codec *codec)
/*
* configuration and preset
*/
-static struct hda_board_config alc861_cfg_tbl[] = {
- { .modelname = "3stack", .config = ALC861_3ST },
- { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600,
- .config = ALC861_3ST },
- { .modelname = "3stack-660", .config = ALC660_3ST },
- { .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7,
- .config = ALC660_3ST },
- { .modelname = "3stack-dig", .config = ALC861_3ST_DIG },
- { .modelname = "6stack-dig", .config = ALC861_6ST_DIG },
- { .modelname = "uniwill-m31", .config = ALC861_UNIWILL_M31},
- { .pci_subvendor = 0x1584, .pci_subdevice = 0x9072,
- .config = ALC861_UNIWILL_M31 },
- { .modelname = "auto", .config = ALC861_AUTO },
+static const char *alc861_models[ALC861_MODEL_LAST] = {
+ [ALC861_3ST] = "3stack",
+ [ALC660_3ST] = "3stack-660",
+ [ALC861_3ST_DIG] = "3stack-dig",
+ [ALC861_6ST_DIG] = "6stack-dig",
+ [ALC861_UNIWILL_M31] = "uniwill-m31",
+ [ALC861_TOSHIBA] = "toshiba",
+ [ALC861_ASUS] = "asus",
+ [ALC861_ASUS_LAPTOP] = "asus-laptop",
+ [ALC861_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc861_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
+ SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
+ SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
+ SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
+ SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660_3ST),
+ SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
+ SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA),
+ SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
+ SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
+ SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
{}
};
@@ -6785,8 +7873,48 @@ static struct alc_config_preset alc861_presets[] = {
.adc_nids = alc861_adc_nids,
.input_mux = &alc861_capture_source,
},
-
-};
+ [ALC861_TOSHIBA] = {
+ .mixers = { alc861_toshiba_mixer },
+ .init_verbs = { alc861_base_init_verbs, alc861_toshiba_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+ .dac_nids = alc861_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+ .channel_mode = alc883_3ST_2ch_modes,
+ .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+ .adc_nids = alc861_adc_nids,
+ .input_mux = &alc861_capture_source,
+ .unsol_event = alc861_toshiba_unsol_event,
+ .init_hook = alc861_toshiba_automute,
+ },
+ [ALC861_ASUS] = {
+ .mixers = { alc861_asus_mixer },
+ .init_verbs = { alc861_asus_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+ .dac_nids = alc861_dac_nids,
+ .dig_out_nid = ALC861_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
+ .channel_mode = alc861_asus_modes,
+ .need_dac_fix = 1,
+ .hp_nid = 0x06,
+ .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+ .adc_nids = alc861_adc_nids,
+ .input_mux = &alc861_capture_source,
+ },
+ [ALC861_ASUS_LAPTOP] = {
+ .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
+ .init_verbs = { alc861_asus_init_verbs,
+ alc861_asus_laptop_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861_dac_nids),
+ .dac_nids = alc861_dac_nids,
+ .dig_out_nid = ALC861_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+ .channel_mode = alc883_3ST_2ch_modes,
+ .need_dac_fix = 1,
+ .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
+ .adc_nids = alc861_adc_nids,
+ .input_mux = &alc861_capture_source,
+ },
+};
static int patch_alc861(struct hda_codec *codec)
@@ -6795,15 +7923,17 @@ static int patch_alc861(struct hda_codec *codec)
int board_config;
int err;
- spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl);
+ board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
+ alc861_models,
+ alc861_cfg_tbl);
- if (board_config < 0 || board_config >= ALC861_MODEL_LAST) {
+ if (board_config < 0) {
printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
"trying auto-probe from BIOS...\n");
board_config = ALC861_AUTO;
@@ -6842,19 +7972,706 @@ static int patch_alc861(struct hda_codec *codec)
}
/*
+ * ALC861-VD support
+ *
+ * Based on ALC882
+ *
+ * In addition, an independent DAC
+ */
+#define ALC861VD_DIGOUT_NID 0x06
+
+static hda_nid_t alc861vd_dac_nids[4] = {
+ /* front, surr, clfe, side surr */
+ 0x02, 0x03, 0x04, 0x05
+};
+
+/* dac_nids for ALC660vd are in a different order - according to
+ * Realtek's driver.
+ * This should probably tesult in a different mixer for 6stack models
+ * of ALC660vd codecs, but for now there is only 3stack mixer
+ * - and it is the same as in 861vd.
+ * adc_nids in ALC660vd are (is) the same as in 861vd
+ */
+static hda_nid_t alc660vd_dac_nids[3] = {
+ /* front, rear, clfe, rear_surr */
+ 0x02, 0x04, 0x03
+};
+
+static hda_nid_t alc861vd_adc_nids[1] = {
+ /* ADC0 */
+ 0x09,
+};
+
+/* input MUX */
+/* FIXME: should be a matrix-type input source selection */
+static struct hda_input_mux alc861vd_capture_source = {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x0 },
+ { "Front Mic", 0x1 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ },
+};
+
+#define alc861vd_mux_enum_info alc_mux_enum_info
+#define alc861vd_mux_enum_get alc_mux_enum_get
+
+static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
+ const struct hda_input_mux *imux = spec->input_mux;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ static hda_nid_t capture_mixers[1] = { 0x22 };
+ hda_nid_t nid = capture_mixers[adc_idx];
+ unsigned int *cur_val = &spec->cur_mux[adc_idx];
+ unsigned int i, idx;
+
+ idx = ucontrol->value.enumerated.item[0];
+ if (idx >= imux->num_items)
+ idx = imux->num_items - 1;
+ if (*cur_val == idx && ! codec->in_resume)
+ return 0;
+ for (i = 0; i < imux->num_items; i++) {
+ unsigned int v = (i == idx) ? 0x7000 : 0x7080;
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ v | (imux->items[i].index << 8));
+ }
+ *cur_val = idx;
+ return 1;
+}
+
+/*
+ * 2ch mode
+ */
+static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
+ { 2, NULL }
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc861vd_6stack_ch6_init[] = {
+ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
+ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc861vd_6stack_ch8_init[] = {
+ { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { } /* end */
+};
+
+static struct hda_channel_mode alc861vd_6stack_modes[2] = {
+ { 6, alc861vd_6stack_ch6_init },
+ { 8, alc861vd_6stack_ch8_init },
+};
+
+static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = alc_ch_mode_info,
+ .get = alc_ch_mode_get,
+ .put = alc_ch_mode_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
+
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ *FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 1,
+ .info = alc861vd_mux_enum_info,
+ .get = alc861vd_mux_enum_get,
+ .put = alc861vd_mux_enum_put,
+ },
+ { } /* end */
+};
+
+/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
+ * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
+ */
+static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
+ HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
+ HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+
+ { } /* end */
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc861vd_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0 and set the default input to mic-in
+ */
+ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
+ * the analog-loopback mixer widget
+ */
+ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+ /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(8)},
+
+ /*
+ * Set up output mixers (0x02 - 0x05)
+ */
+ /* set vol=0 to output mixers */
+ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /* set up input amps for analog loopback */
+ /* Amp Indices: DAC = 0, mixer = 1 */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+ { }
+};
+
+/*
+ * 3-stack pin configuration:
+ * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
+ */
+static struct hda_verb alc861vd_3stack_init_verbs[] = {
+ /*
+ * Set pin mode and muting
+ */
+ /* set front pin widgets 0x14 for output */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ /* Mic (rear) pin: input vref at 80% */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Front Mic pin: input vref at 80% */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line In pin: input */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line-2 In: Headphone output (output 0 - 0x0c) */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* CD pin widget for input */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+ { }
+};
+
+/*
+ * 6-stack pin configuration:
+ */
+static struct hda_verb alc861vd_6stack_init_verbs[] = {
+ /*
+ * Set pin mode and muting
+ */
+ /* set front pin widgets 0x14 for output */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ /* Rear Pin: output 1 (0x0d) */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+ /* CLFE Pin: output 2 (0x0e) */
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+ /* Side Pin: output 3 (0x0f) */
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+
+ /* Mic (rear) pin: input vref at 80% */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Front Mic pin: input vref at 80% */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line In pin: input */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Line-2 In: Headphone output (output 0 - 0x0c) */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* CD pin widget for input */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+ { }
+};
+
+/* pcm configuration: identiacal with ALC880 */
+#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
+#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
+#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
+#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
+
+/*
+ * configuration and preset
+ */
+static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
+ [ALC660VD_3ST] = "3stack-660",
+ [ALC861VD_3ST] = "3stack",
+ [ALC861VD_3ST_DIG] = "3stack-digout",
+ [ALC861VD_6ST_DIG] = "6stack-digout",
+ [ALC861VD_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
+ SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
+ SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
+
+ SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_3ST),
+ {}
+};
+
+static struct alc_config_preset alc861vd_presets[] = {
+ [ALC660VD_3ST] = {
+ .mixers = { alc861vd_3st_mixer },
+ .init_verbs = { alc861vd_volume_init_verbs,
+ alc861vd_3stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+ .dac_nids = alc660vd_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
+ .adc_nids = alc861vd_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+ .channel_mode = alc861vd_3stack_2ch_modes,
+ .input_mux = &alc861vd_capture_source,
+ },
+ [ALC861VD_3ST] = {
+ .mixers = { alc861vd_3st_mixer },
+ .init_verbs = { alc861vd_volume_init_verbs,
+ alc861vd_3stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+ .dac_nids = alc861vd_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+ .channel_mode = alc861vd_3stack_2ch_modes,
+ .input_mux = &alc861vd_capture_source,
+ },
+ [ALC861VD_3ST_DIG] = {
+ .mixers = { alc861vd_3st_mixer },
+ .init_verbs = { alc861vd_volume_init_verbs,
+ alc861vd_3stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+ .dac_nids = alc861vd_dac_nids,
+ .dig_out_nid = ALC861VD_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+ .channel_mode = alc861vd_3stack_2ch_modes,
+ .input_mux = &alc861vd_capture_source,
+ },
+ [ALC861VD_6ST_DIG] = {
+ .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
+ .init_verbs = { alc861vd_volume_init_verbs,
+ alc861vd_6stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
+ .dac_nids = alc861vd_dac_nids,
+ .dig_out_nid = ALC861VD_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
+ .channel_mode = alc861vd_6stack_modes,
+ .input_mux = &alc861vd_capture_source,
+ },
+};
+
+/*
+ * BIOS auto configuration
+ */
+static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
+ hda_nid_t nid, int pin_type, int dac_idx)
+{
+ /* set as output */
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+}
+
+static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i <= HDA_SIDE; i++) {
+ hda_nid_t nid = spec->autocfg.line_out_pins[i];
+ if (nid)
+ alc861vd_auto_set_output_and_unmute(codec, nid,
+ PIN_OUT, i);
+ }
+}
+
+
+static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t pin;
+
+ pin = spec->autocfg.hp_pins[0];
+ if (pin) /* connect to front and use dac 0 */
+ alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+}
+
+#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
+#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
+
+static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ hda_nid_t nid = spec->autocfg.input_pins[i];
+ if (alc861vd_is_input_pin(nid)) {
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ i <= AUTO_PIN_FRONT_MIC ?
+ PIN_VREF80 : PIN_IN);
+ if (nid != ALC861VD_PIN_CD_NID)
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_MUTE);
+ }
+ }
+}
+
+#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
+#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
+
+/* add playback controls from the parsed DAC table */
+/* Based on ALC880 version. But ALC861VD has separate,
+ * different NIDs for mute/unmute switch and volume control */
+static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ char name[32];
+ static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
+ hda_nid_t nid_v, nid_s;
+ int i, err;
+
+ for (i = 0; i < cfg->line_outs; i++) {
+ if (! spec->multiout.dac_nids[i])
+ continue;
+ nid_v = alc861vd_idx_to_mixer_vol(
+ alc880_dac_to_idx(
+ spec->multiout.dac_nids[i]));
+ nid_s = alc861vd_idx_to_mixer_switch(
+ alc880_dac_to_idx(
+ spec->multiout.dac_nids[i]));
+
+ if (i == 2) {
+ /* Center/LFE */
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL,
+ "Center Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_v, 1,
+ 0, HDA_OUTPUT))) < 0)
+ return err;
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL,
+ "LFE Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_v, 2,
+ 0, HDA_OUTPUT))) < 0)
+ return err;
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE,
+ "Center Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_s, 1,
+ 2, HDA_INPUT))) < 0)
+ return err;
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE,
+ "LFE Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_s, 2,
+ 2, HDA_INPUT))) < 0)
+ return err;
+ } else {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid_v, 3,
+ 0, HDA_OUTPUT))) < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid_v, 3,
+ 2, HDA_INPUT))) < 0)
+ return err;
+ }
+ }
+ return 0;
+}
+
+/* add playback controls for speaker and HP outputs */
+/* Based on ALC880 version. But ALC861VD has separate,
+ * different NIDs for mute/unmute switch and volume control */
+static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
+ hda_nid_t pin, const char *pfx)
+{
+ hda_nid_t nid_v, nid_s;
+ int err;
+ char name[32];
+
+ if (! pin)
+ return 0;
+
+ if (alc880_is_fixed_pin(pin)) {
+ nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
+ /* specify the DAC as the extra output */
+ if (! spec->multiout.hp_nid)
+ spec->multiout.hp_nid = nid_v;
+ else
+ spec->multiout.extra_out_nid[0] = nid_v;
+ /* control HP volume/switch on the output mixer amp */
+ nid_v = alc861vd_idx_to_mixer_vol(
+ alc880_fixed_pin_idx(pin));
+ nid_s = alc861vd_idx_to_mixer_switch(
+ alc880_fixed_pin_idx(pin));
+
+ sprintf(name, "%s Playback Volume", pfx);
+ if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
+ HDA_OUTPUT))) < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", pfx);
+ if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
+ HDA_INPUT))) < 0)
+ return err;
+ } else if (alc880_is_multi_pin(pin)) {
+ /* set manual connection */
+ /* we have only a switch on HP-out PIN */
+ sprintf(name, "%s Playback Switch", pfx);
+ if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0,
+ HDA_OUTPUT))) < 0)
+ return err;
+ }
+ return 0;
+}
+
+/* parse the BIOS configuration and set up the alc_spec
+ * return 1 if successful, 0 if the proper config is not found,
+ * or a negative error code
+ * Based on ALC880 version - had to change it to override
+ * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
+static int alc861vd_parse_auto_config(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int err;
+ static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
+
+ if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+ alc861vd_ignore)) < 0)
+ return err;
+ if (! spec->autocfg.line_outs)
+ return 0; /* can't find valid BIOS pin config */
+
+ if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
+ (err = alc861vd_auto_create_multi_out_ctls(spec,
+ &spec->autocfg)) < 0 ||
+ (err = alc861vd_auto_create_extra_out(spec,
+ spec->autocfg.speaker_pins[0], "Speaker")) < 0 ||
+ (err = alc861vd_auto_create_extra_out(spec,
+ spec->autocfg.hp_pins[0], "Headphone")) < 0 ||
+ (err = alc880_auto_create_analog_input_ctls(spec,
+ &spec->autocfg)) < 0)
+ return err;
+
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+ if (spec->autocfg.dig_out_pin)
+ spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
+
+ if (spec->kctl_alloc)
+ spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+ spec->init_verbs[spec->num_init_verbs++]
+ = alc861vd_volume_init_verbs;
+
+ spec->num_mux_defs = 1;
+ spec->input_mux = &spec->private_imux;
+
+ return 1;
+}
+
+/* additional initialization for auto-configuration model */
+static void alc861vd_auto_init(struct hda_codec *codec)
+{
+ alc861vd_auto_init_multi_out(codec);
+ alc861vd_auto_init_hp_out(codec);
+ alc861vd_auto_init_analog_input(codec);
+}
+
+static int patch_alc861vd(struct hda_codec *codec)
+{
+ struct alc_spec *spec;
+ int err, board_config;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
+ alc861vd_models,
+ alc861vd_cfg_tbl);
+
+ if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
+ printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
+ "ALC861VD, trying auto-probe from BIOS...\n");
+ board_config = ALC861VD_AUTO;
+ }
+
+ if (board_config == ALC861VD_AUTO) {
+ /* automatic parse from the BIOS config */
+ err = alc861vd_parse_auto_config(codec);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ } else if (! err) {
+ printk(KERN_INFO
+ "hda_codec: Cannot set up configuration "
+ "from BIOS. Using base mode...\n");
+ board_config = ALC861VD_3ST;
+ }
+ }
+
+ if (board_config != ALC861VD_AUTO)
+ setup_preset(spec, &alc861vd_presets[board_config]);
+
+ spec->stream_name_analog = "ALC861VD Analog";
+ spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
+ spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
+
+ spec->stream_name_digital = "ALC861VD Digital";
+ spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
+ spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
+
+ spec->adc_nids = alc861vd_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
+
+ spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
+ spec->num_mixers++;
+
+ codec->patch_ops = alc_patch_ops;
+
+ if (board_config == ALC861VD_AUTO)
+ spec->init_hook = alc861vd_auto_init;
+
+ return 0;
+}
+
+/*
* patch entries
*/
struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
- { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
+ { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
+ .patch = patch_alc861 },
+ { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
+ { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
+ { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
+ { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
- { .id = 0x10ec0861, .rev = 0x100300, .name = "ALC861",
- .patch = patch_alc861 },
- { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
- .patch = patch_alc861 },
{} /* terminator */
};
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index cc87dff1eb5..ed5e45e3596 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -243,7 +243,8 @@ static int si3054_init(struct hda_codec *codec)
if((val&SI3054_MEI_READY) != SI3054_MEI_READY) {
snd_printk(KERN_ERR "si3054: cannot initialize. EXT MID = %04x\n", val);
- return -EACCES;
+ /* let's pray that this is no fatal error */
+ /* return -EACCES; */
}
SET_REG(codec, SI3054_GPIO_POLARITY, 0xffff);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index fe51ef3e49d..6f4a39273b9 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -37,14 +37,37 @@
#define NUM_CONTROL_ALLOC 32
#define STAC_HP_EVENT 0x37
-#define STAC_REF 0
-#define STAC_D945GTP3 1
-#define STAC_D945GTP5 2
-#define STAC_MACMINI 3
-#define STAC_922X_MODELS 4 /* number of 922x models */
-#define STAC_D965_3ST 4
-#define STAC_D965_5ST 5
-#define STAC_927X_MODELS 6 /* number of 922x models */
+enum {
+ STAC_REF,
+ STAC_9200_MODELS
+};
+
+enum {
+ STAC_9205_REF,
+ STAC_9205_MODELS
+};
+
+enum {
+ STAC_925x_REF,
+ STAC_M2_2,
+ STAC_MA6,
+ STAC_925x_MODELS
+};
+
+enum {
+ STAC_D945_REF,
+ STAC_D945GTP3,
+ STAC_D945GTP5,
+ STAC_MACMINI,
+ STAC_922X_MODELS
+};
+
+enum {
+ STAC_D965_REF,
+ STAC_D965_3ST,
+ STAC_D965_5ST,
+ STAC_927X_MODELS
+};
struct sigmatel_spec {
struct snd_kcontrol_new *mixers[4];
@@ -67,6 +90,9 @@ struct sigmatel_spec {
unsigned int num_adcs;
hda_nid_t *mux_nids;
unsigned int num_muxes;
+ hda_nid_t *dmic_nids;
+ unsigned int num_dmics;
+ hda_nid_t dmux_nid;
hda_nid_t dig_in_nid;
/* pin widgets */
@@ -80,6 +106,8 @@ struct sigmatel_spec {
struct snd_kcontrol_new *mixer;
/* capture source */
+ struct hda_input_mux *dinput_mux;
+ unsigned int cur_dmux;
struct hda_input_mux *input_mux;
unsigned int cur_mux[3];
@@ -92,6 +120,7 @@ struct sigmatel_spec {
struct auto_pin_cfg autocfg;
unsigned int num_kctl_alloc, num_kctl_used;
struct snd_kcontrol_new *kctl_alloc;
+ struct hda_input_mux private_dimux;
struct hda_input_mux private_imux;
};
@@ -107,6 +136,18 @@ static hda_nid_t stac9200_dac_nids[1] = {
0x02,
};
+static hda_nid_t stac925x_adc_nids[1] = {
+ 0x03,
+};
+
+static hda_nid_t stac925x_mux_nids[1] = {
+ 0x0f,
+};
+
+static hda_nid_t stac925x_dac_nids[1] = {
+ 0x02,
+};
+
static hda_nid_t stac922x_adc_nids[2] = {
0x06, 0x07,
};
@@ -131,11 +172,20 @@ static hda_nid_t stac9205_mux_nids[2] = {
0x19, 0x1a
};
+static hda_nid_t stac9205_dmic_nids[3] = {
+ 0x17, 0x18, 0
+};
+
static hda_nid_t stac9200_pin_nids[8] = {
0x08, 0x09, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12,
};
+static hda_nid_t stac925x_pin_nids[8] = {
+ 0x07, 0x08, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x10, 0x11,
+};
+
static hda_nid_t stac922x_pin_nids[10] = {
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x15, 0x1b,
@@ -154,6 +204,34 @@ static hda_nid_t stac9205_pin_nids[12] = {
};
+static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+ return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
+}
+
+static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+
+ ucontrol->value.enumerated.item[0] = spec->cur_dmux;
+ return 0;
+}
+
+static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+
+ return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
+ spec->dmux_nid, &spec->cur_dmux);
+}
+
static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -187,6 +265,12 @@ static struct hda_verb stac9200_core_init[] = {
{}
};
+static struct hda_verb stac925x_core_init[] = {
+ /* set dac0mux for dac converter */
+ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {}
+};
+
static struct hda_verb stac922x_core_init[] = {
/* set master volume and direct control */
{ 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -232,6 +316,23 @@ static struct snd_kcontrol_new stac9200_mixer[] = {
{ } /* end */
};
+static struct snd_kcontrol_new stac925x_mixer[] = {
+ HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .count = 1,
+ .info = stac92xx_mux_enum_info,
+ .get = stac92xx_mux_enum_get,
+ .put = stac92xx_mux_enum_put,
+ },
+ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
+ { } /* end */
+};
+
/* This needs to be generated dynamically based on sequence */
static struct snd_kcontrol_new stac922x_mixer[] = {
{
@@ -263,7 +364,7 @@ static struct snd_kcontrol_new stac9227_mixer[] = {
{ } /* end */
};
-static snd_kcontrol_new_t stac927x_mixer[] = {
+static struct snd_kcontrol_new stac927x_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Source",
@@ -278,7 +379,15 @@ static snd_kcontrol_new_t stac927x_mixer[] = {
{ } /* end */
};
-static snd_kcontrol_new_t stac9205_mixer[] = {
+static struct snd_kcontrol_new stac9205_mixer[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Digital Input Source",
+ .count = 1,
+ .info = stac92xx_dmux_enum_info,
+ .get = stac92xx_dmux_enum_get,
+ .put = stac92xx_dmux_enum_put,
+ },
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Source",
@@ -327,22 +436,64 @@ static unsigned int ref9200_pin_configs[8] = {
0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
};
-static unsigned int *stac9200_brd_tbl[] = {
- ref9200_pin_configs,
+static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
+ [STAC_REF] = ref9200_pin_configs,
+};
+
+static const char *stac9200_models[STAC_9200_MODELS] = {
+ [STAC_REF] = "ref",
};
-static struct hda_board_config stac9200_cfg_tbl[] = {
- { .modelname = "ref",
- .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2668, /* DFI LanParty */
- .config = STAC_REF },
+static struct snd_pci_quirk stac9200_cfg_tbl[] = {
+ /* SigmaTel reference board */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+ "DFI LanParty", STAC_REF),
/* Dell laptops have BIOS problem */
- { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01b5,
- .config = STAC_REF }, /* Dell Inspiron 630m */
- { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01c2,
- .config = STAC_REF }, /* Dell Latitude D620 */
- { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01cb,
- .config = STAC_REF }, /* Dell Latitude 120L */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
+ "Dell Inspiron 630m", STAC_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
+ "Dell Latitude D620", STAC_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
+ "Dell Latitude 120L", STAC_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
+ "Dell Latitude D820", STAC_REF),
+ {} /* terminator */
+};
+
+static unsigned int ref925x_pin_configs[8] = {
+ 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
+ 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925x_MA6_pin_configs[8] = {
+ 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
+ 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925xM2_2_pin_configs[8] = {
+ 0x40c003f3, 0x424503f2, 0x041800f4, 0x02a19020,
+ 0x50a103F0, 0x90100210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
+ [STAC_REF] = ref925x_pin_configs,
+ [STAC_M2_2] = stac925xM2_2_pin_configs,
+ [STAC_MA6] = stac925x_MA6_pin_configs,
+};
+
+static const char *stac925x_models[STAC_925x_MODELS] = {
+ [STAC_REF] = "ref",
+ [STAC_M2_2] = "m2-2",
+ [STAC_MA6] = "m6",
+};
+
+static struct snd_pci_quirk stac925x_cfg_tbl[] = {
+ /* SigmaTel reference board */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
+ SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
+ SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
+ SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
+ SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
{} /* terminator */
};
@@ -365,100 +516,80 @@ static unsigned int d945gtp5_pin_configs[10] = {
};
static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
- [STAC_REF] = ref922x_pin_configs,
+ [STAC_D945_REF] = ref922x_pin_configs,
[STAC_D945GTP3] = d945gtp3_pin_configs,
[STAC_D945GTP5] = d945gtp5_pin_configs,
[STAC_MACMINI] = d945gtp5_pin_configs,
};
-static struct hda_board_config stac922x_cfg_tbl[] = {
- { .modelname = "5stack", .config = STAC_D945GTP5 },
- { .modelname = "3stack", .config = STAC_D945GTP3 },
- { .modelname = "ref",
- .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2668, /* DFI LanParty */
- .config = STAC_REF }, /* SigmaTel reference board */
- /* Intel 945G based systems */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0101,
- .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0202,
- .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0606,
- .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0601,
- .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0111,
- .config = STAC_D945GTP3 }, /* Intel D945GZP - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x1115,
- .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x1116,
- .config = STAC_D945GTP3 }, /* Intel D945GBO - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x1117,
- .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x1118,
- .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x1119,
- .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x8826,
- .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x5049,
- .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x5055,
- .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x5048,
- .config = STAC_D945GTP3 }, /* Intel D945GPB - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0110,
- .config = STAC_D945GTP3 }, /* Intel D945GLR - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0404,
- .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0303,
- .config = STAC_D945GTP5 }, /* Intel D945GNT - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0013,
- .config = STAC_D945GTP5 }, /* Intel D955XBK - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0417,
- .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */
- /* Intel 945P based systems */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0b0b,
- .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0112,
- .config = STAC_D945GTP3 }, /* Intel D945PLN - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0d0d,
- .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0909,
- .config = STAC_D945GTP3 }, /* Intel D945PAW - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0505,
- .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x0707,
- .config = STAC_D945GTP5 }, /* Intel D945PSV - 5 Stack */
- /* other systems */
- { .pci_subvendor = 0x8384,
- .pci_subdevice = 0x7680,
- .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */
+static const char *stac922x_models[STAC_922X_MODELS] = {
+ [STAC_D945_REF] = "ref",
+ [STAC_D945GTP5] = "5stack",
+ [STAC_D945GTP3] = "3stack",
+ [STAC_MACMINI] = "macmini",
+};
+
+static struct snd_pci_quirk stac922x_cfg_tbl[] = {
+ /* SigmaTel reference board */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+ "DFI LanParty", STAC_D945_REF),
+ /* Intel 945G based systems */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
+ "Intel D945G", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
+ "Intel D945G", STAC_D945GTP3),
+ /* Intel D945G 5-stack systems */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
+ "Intel D945G", STAC_D945GTP5),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
+ "Intel D945G", STAC_D945GTP5),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
+ "Intel D945G", STAC_D945GTP5),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
+ "Intel D945G", STAC_D945GTP5),
+ /* Intel 945P based systems */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
+ "Intel D945P", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
+ "Intel D945P", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
+ "Intel D945P", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
+ "Intel D945P", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
+ "Intel D945P", STAC_D945GTP3),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
+ "Intel D945P", STAC_D945GTP5),
+ /* other systems */
+ /* Apple Mac Mini (early 2006) */
+ SND_PCI_QUIRK(0x8384, 0x7680,
+ "Mac Mini", STAC_MACMINI),
{} /* terminator */
};
@@ -484,120 +615,72 @@ static unsigned int d965_5st_pin_configs[14] = {
};
static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
- [STAC_REF] = ref927x_pin_configs,
+ [STAC_D965_REF] = ref927x_pin_configs,
[STAC_D965_3ST] = d965_3st_pin_configs,
[STAC_D965_5ST] = d965_5st_pin_configs,
};
-static struct hda_board_config stac927x_cfg_tbl[] = {
- { .modelname = "5stack", .config = STAC_D965_5ST },
- { .modelname = "3stack", .config = STAC_D965_3ST },
- { .modelname = "ref",
- .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2668, /* DFI LanParty */
- .config = STAC_REF }, /* SigmaTel reference board */
+static const char *stac927x_models[STAC_927X_MODELS] = {
+ [STAC_D965_REF] = "ref",
+ [STAC_D965_3ST] = "3stack",
+ [STAC_D965_5ST] = "5stack",
+};
+
+static struct snd_pci_quirk stac927x_cfg_tbl[] = {
+ /* SigmaTel reference board */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+ "DFI LanParty", STAC_D965_REF),
/* Intel 946 based systems */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x3d01,
- .config = STAC_D965_3ST }, /* D946 configuration */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0xa301,
- .config = STAC_D965_3ST }, /* Intel D946GZT - 3 stack */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
/* 965 based 3 stack systems */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2116,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2115,
- .config = STAC_D965_3ST }, /* Intel DQ965WC - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2114,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2113,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2112,
- .config = STAC_D965_3ST }, /* Intel DG965MS - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2111,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2110,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2009,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2008,
- .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2007,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2006,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2005,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2004,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2003,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2002,
- .config = STAC_D965_3ST }, /* Intel D965 3Stack config */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2001,
- .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
/* 965 based 5 stack systems */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2301,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2302,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2303,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2304,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2305,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2501,
- .config = STAC_D965_5ST }, /* Intel DG965MQ - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2502,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2503,
- .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */
- { .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2504,
- .config = STAC_D965_5ST }, /* Intel DQ965GF - 5 Stack */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
{} /* terminator */
};
static unsigned int ref9205_pin_configs[12] = {
0x40000100, 0x40000100, 0x01016011, 0x01014010,
- 0x01813122, 0x01a19021, 0x40000100, 0x40000100,
- 0x40000100, 0x40000100, 0x01441030, 0x01c41030
+ 0x01813122, 0x01a19021, 0x40000100, 0x40000100,
+ 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
};
-static unsigned int *stac9205_brd_tbl[] = {
+static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
ref9205_pin_configs,
};
-static struct hda_board_config stac9205_cfg_tbl[] = {
- { .modelname = "ref",
- .pci_subvendor = PCI_VENDOR_ID_INTEL,
- .pci_subdevice = 0x2668, /* DFI LanParty */
- .config = STAC_REF }, /* SigmaTel reference board */
+static const char *stac9205_models[STAC_9205_MODELS] = {
+ [STAC_9205_REF] = "ref",
+};
+
+static struct snd_pci_quirk stac9205_cfg_tbl[] = {
+ /* SigmaTel reference board */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+ "DFI LanParty", STAC_9205_REF),
{} /* terminator */
};
@@ -1154,6 +1237,58 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
return 0;
}
+/* labels for dmic mux inputs */
+static const char *stac92xx_dmic_labels[5] = {
+ "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
+ "Digital Mic 3", "Digital Mic 4"
+};
+
+/* create playback/capture controls for input pins on dmic capable codecs */
+static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
+ const struct auto_pin_cfg *cfg)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct hda_input_mux *dimux = &spec->private_dimux;
+ hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
+ int i, j;
+
+ dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
+ dimux->items[dimux->num_items].index = 0;
+ dimux->num_items++;
+
+ for (i = 0; i < spec->num_dmics; i++) {
+ int index;
+ int num_cons;
+ unsigned int def_conf;
+
+ def_conf = snd_hda_codec_read(codec,
+ spec->dmic_nids[i],
+ 0,
+ AC_VERB_GET_CONFIG_DEFAULT,
+ 0);
+ if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
+ continue;
+
+ num_cons = snd_hda_get_connections(codec,
+ spec->dmux_nid,
+ con_lst,
+ HDA_MAX_NUM_INPUTS);
+ for (j = 0; j < num_cons; j++)
+ if (con_lst[j] == spec->dmic_nids[i]) {
+ index = j;
+ goto found;
+ }
+ continue;
+found:
+ dimux->items[dimux->num_items].label =
+ stac92xx_dmic_labels[dimux->num_items];
+ dimux->items[dimux->num_items].index = index;
+ dimux->num_items++;
+ }
+
+ return 0;
+}
+
/* create playback/capture controls for input pins */
static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
{
@@ -1238,7 +1373,9 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
struct sigmatel_spec *spec = codec->spec;
int err;
- if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
+ if ((err = snd_hda_parse_pin_def_config(codec,
+ &spec->autocfg,
+ spec->dmic_nids)) < 0)
return err;
if (! spec->autocfg.line_outs)
return 0; /* can't find valid pin config */
@@ -1254,6 +1391,11 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
(err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
return err;
+ if (spec->num_dmics > 0)
+ if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
+ &spec->autocfg)) < 0)
+ return err;
+
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
if (spec->multiout.max_channels > 2)
spec->surr_switch = 1;
@@ -1267,6 +1409,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
spec->input_mux = &spec->private_imux;
+ spec->dinput_mux = &spec->private_dimux;
return 1;
}
@@ -1366,6 +1509,7 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
spec->input_mux = &spec->private_imux;
+ spec->dinput_mux = &spec->private_dimux;
return 1;
}
@@ -1448,6 +1592,11 @@ static int stac92xx_init(struct hda_codec *codec)
stac92xx_auto_set_pinctl(codec, nid, pinctl);
}
}
+ if (spec->num_dmics > 0)
+ for (i = 0; i < spec->num_dmics; i++)
+ stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
+ AC_PINCTL_IN_EN);
+
if (cfg->dig_out_pin)
stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
AC_PINCTL_OUT_EN);
@@ -1598,7 +1747,9 @@ static int patch_stac9200(struct hda_codec *codec)
codec->spec = spec;
spec->num_pins = 8;
spec->pin_nids = stac9200_pin_nids;
- spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl);
+ spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
+ stac9200_models,
+ stac9200_cfg_tbl);
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
@@ -1618,6 +1769,7 @@ static int patch_stac9200(struct hda_codec *codec)
spec->adc_nids = stac9200_adc_nids;
spec->mux_nids = stac9200_mux_nids;
spec->num_muxes = 1;
+ spec->num_dmics = 0;
spec->init = stac9200_core_init;
spec->mixer = stac9200_mixer;
@@ -1633,6 +1785,56 @@ static int patch_stac9200(struct hda_codec *codec)
return 0;
}
+static int patch_stac925x(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec;
+ int err;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+ spec->num_pins = 8;
+ spec->pin_nids = stac925x_pin_nids;
+ spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
+ stac925x_models,
+ stac925x_cfg_tbl);
+ if (spec->board_config < 0) {
+ snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x, using BIOS defaults\n");
+ err = stac92xx_save_bios_config_regs(codec);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
+ }
+ spec->pin_configs = spec->bios_pin_configs;
+ } else if (stac925x_brd_tbl[spec->board_config] != NULL){
+ spec->pin_configs = stac925x_brd_tbl[spec->board_config];
+ stac92xx_set_config_regs(codec);
+ }
+
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = 1;
+ spec->multiout.dac_nids = stac925x_dac_nids;
+ spec->adc_nids = stac925x_adc_nids;
+ spec->mux_nids = stac925x_mux_nids;
+ spec->num_muxes = 1;
+ spec->num_dmics = 0;
+
+ spec->init = stac925x_core_init;
+ spec->mixer = stac925x_mixer;
+
+ err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
+ }
+
+ codec->patch_ops = stac92xx_patch_ops;
+
+ return 0;
+}
+
static int patch_stac922x(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
@@ -1645,7 +1847,9 @@ static int patch_stac922x(struct hda_codec *codec)
codec->spec = spec;
spec->num_pins = 10;
spec->pin_nids = stac922x_pin_nids;
- spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl);
+ spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
+ stac922x_models,
+ stac922x_cfg_tbl);
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
"using BIOS defaults\n");
@@ -1663,6 +1867,7 @@ static int patch_stac922x(struct hda_codec *codec)
spec->adc_nids = stac922x_adc_nids;
spec->mux_nids = stac922x_mux_nids;
spec->num_muxes = 2;
+ spec->num_dmics = 0;
spec->init = stac922x_core_init;
spec->mixer = stac922x_mixer;
@@ -1695,7 +1900,9 @@ static int patch_stac927x(struct hda_codec *codec)
codec->spec = spec;
spec->num_pins = 14;
spec->pin_nids = stac927x_pin_nids;
- spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl);
+ spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
+ stac927x_models,
+ stac927x_cfg_tbl);
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
@@ -1714,6 +1921,7 @@ static int patch_stac927x(struct hda_codec *codec)
spec->adc_nids = stac927x_adc_nids;
spec->mux_nids = stac927x_mux_nids;
spec->num_muxes = 3;
+ spec->num_dmics = 0;
spec->init = d965_core_init;
spec->mixer = stac9227_mixer;
break;
@@ -1721,6 +1929,7 @@ static int patch_stac927x(struct hda_codec *codec)
spec->adc_nids = stac927x_adc_nids;
spec->mux_nids = stac927x_mux_nids;
spec->num_muxes = 3;
+ spec->num_dmics = 0;
spec->init = d965_core_init;
spec->mixer = stac9227_mixer;
break;
@@ -1728,6 +1937,7 @@ static int patch_stac927x(struct hda_codec *codec)
spec->adc_nids = stac927x_adc_nids;
spec->mux_nids = stac927x_mux_nids;
spec->num_muxes = 3;
+ spec->num_dmics = 0;
spec->init = stac927x_core_init;
spec->mixer = stac927x_mixer;
}
@@ -1757,7 +1967,9 @@ static int patch_stac9205(struct hda_codec *codec)
codec->spec = spec;
spec->num_pins = 14;
spec->pin_nids = stac9205_pin_nids;
- spec->board_config = snd_hda_check_board_config(codec, stac9205_cfg_tbl);
+ spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
+ stac9205_models,
+ stac9205_cfg_tbl);
if (spec->board_config < 0) {
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
@@ -1773,13 +1985,28 @@ static int patch_stac9205(struct hda_codec *codec)
spec->adc_nids = stac9205_adc_nids;
spec->mux_nids = stac9205_mux_nids;
- spec->num_muxes = 3;
+ spec->num_muxes = 2;
+ spec->dmic_nids = stac9205_dmic_nids;
+ spec->num_dmics = 2;
+ spec->dmux_nid = 0x1d;
spec->init = stac9205_core_init;
spec->mixer = stac9205_mixer;
spec->multiout.dac_nids = spec->dac_nids;
+ /* Configure GPIO0 as EAPD output */
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DIRECTION, 0x00000001);
+ /* Configure GPIO0 as CMOS */
+ snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
+ /* Assert GPIO0 high */
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DATA, 0x00000001);
+ /* Enable GPIO0 */
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_MASK, 0x00000001);
+
err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
if (err < 0) {
stac92xx_free(codec);
@@ -1963,18 +2190,19 @@ enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
/* Unknown. id=0x83847661 and subsys=0x104D1200. */
STAC9872K_VAIO,
/* AR Series. id=0x83847664 and subsys=104D1300 */
- CXD9872AKD_VAIO
- };
-
-static struct hda_board_config stac9872_cfg_tbl[] = {
- { .modelname = "vaio", .config = CXD9872RD_VAIO },
- { .modelname = "vaio-ar", .config = CXD9872AKD_VAIO },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6,
- .config = CXD9872RD_VAIO },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef,
- .config = CXD9872RD_VAIO },
- { .pci_subvendor = 0x104d, .pci_subdevice = 0x81fd,
- .config = CXD9872AKD_VAIO },
+ CXD9872AKD_VAIO,
+ STAC_9872_MODELS,
+};
+
+static const char *stac9872_models[STAC_9872_MODELS] = {
+ [CXD9872RD_VAIO] = "vaio",
+ [CXD9872AKD_VAIO] = "vaio-ar",
+};
+
+static struct snd_pci_quirk stac9872_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
+ SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
+ SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
{}
};
@@ -1983,7 +2211,9 @@ static int patch_stac9872(struct hda_codec *codec)
struct sigmatel_spec *spec;
int board_config;
- board_config = snd_hda_check_board_config(codec, stac9872_cfg_tbl);
+ board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
+ stac9872_models,
+ stac9872_cfg_tbl);
if (board_config < 0)
/* unknown config, let generic-parser do its job... */
return snd_hda_parse_generic_codec(codec);
@@ -2055,6 +2285,12 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
{ .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
{ .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
{ .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
+ { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
+ { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
+ { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
+ { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
+ { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
+ { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
/* The following does not take into account .id=0x83847661 when subsys =
* 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
* currently not fully supported.
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
new file mode 100644
index 00000000000..4c839b03172
--- /dev/null
+++ b/sound/pci/hda/patch_via.c
@@ -0,0 +1,1396 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for VIA VT1708 codec
+ *
+ * Copyright (c) 2006 Lydia Wang <lydiawang@viatech.com>
+ * Takashi Iwai <tiwai@suse.de>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * 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 driver 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
+ */
+
+/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
+/* */
+/* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */
+/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */
+/* 2006-08-02 Lydia Wang Add support to VT1709 codec */
+/* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */
+/* */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+
+/* amp values */
+#define AMP_VAL_IDX_SHIFT 19
+#define AMP_VAL_IDX_MASK (0x0f<<19)
+
+#define NUM_CONTROL_ALLOC 32
+#define NUM_VERB_ALLOC 32
+
+/* Pin Widget NID */
+#define VT1708_HP_NID 0x13
+#define VT1708_DIGOUT_NID 0x14
+#define VT1708_DIGIN_NID 0x16
+
+#define VT1709_HP_DAC_NID 0x28
+#define VT1709_DIGOUT_NID 0x13
+#define VT1709_DIGIN_NID 0x17
+
+#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b)
+#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713)
+#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717)
+
+
+enum {
+ VIA_CTL_WIDGET_VOL,
+ VIA_CTL_WIDGET_MUTE,
+};
+
+enum {
+ AUTO_SEQ_FRONT,
+ AUTO_SEQ_SURROUND,
+ AUTO_SEQ_CENLFE,
+ AUTO_SEQ_SIDE
+};
+
+static struct snd_kcontrol_new vt1708_control_templates[] = {
+ HDA_CODEC_VOLUME(NULL, 0, 0, 0),
+ HDA_CODEC_MUTE(NULL, 0, 0, 0),
+};
+
+
+struct via_spec {
+ /* codec parameterization */
+ struct snd_kcontrol_new *mixers[3];
+ unsigned int num_mixers;
+
+ struct hda_verb *init_verbs;
+
+ char *stream_name_analog;
+ struct hda_pcm_stream *stream_analog_playback;
+ struct hda_pcm_stream *stream_analog_capture;
+
+ char *stream_name_digital;
+ struct hda_pcm_stream *stream_digital_playback;
+ struct hda_pcm_stream *stream_digital_capture;
+
+ /* playback */
+ struct hda_multi_out multiout;
+
+ /* capture */
+ unsigned int num_adc_nids;
+ hda_nid_t *adc_nids;
+ hda_nid_t dig_in_nid;
+
+ /* capture source */
+ const struct hda_input_mux *input_mux;
+ unsigned int cur_mux[3];
+
+ /* PCM information */
+ struct hda_pcm pcm_rec[2];
+
+ /* dynamic controls, init_verbs and input_mux */
+ struct auto_pin_cfg autocfg;
+ unsigned int num_kctl_alloc, num_kctl_used;
+ struct snd_kcontrol_new *kctl_alloc;
+ struct hda_input_mux private_imux;
+ hda_nid_t private_dac_nids[4];
+};
+
+static hda_nid_t vt1708_adc_nids[2] = {
+ /* ADC1-2 */
+ 0x15, 0x27
+};
+
+static hda_nid_t vt1709_adc_nids[3] = {
+ /* ADC1-2 */
+ 0x14, 0x15, 0x16
+};
+
+/* add dynamic controls */
+static int via_add_control(struct via_spec *spec, int type, const char *name,
+ unsigned long val)
+{
+ struct snd_kcontrol_new *knew;
+
+ if (spec->num_kctl_used >= spec->num_kctl_alloc) {
+ int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
+
+ /* array + terminator */
+ knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
+ if (!knew)
+ return -ENOMEM;
+ if (spec->kctl_alloc) {
+ memcpy(knew, spec->kctl_alloc,
+ sizeof(*knew) * spec->num_kctl_alloc);
+ kfree(spec->kctl_alloc);
+ }
+ spec->kctl_alloc = knew;
+ spec->num_kctl_alloc = num;
+ }
+
+ knew = &spec->kctl_alloc[spec->num_kctl_used];
+ *knew = vt1708_control_templates[type];
+ knew->name = kstrdup(name, GFP_KERNEL);
+
+ if (!knew->name)
+ return -ENOMEM;
+ knew->private_value = val;
+ spec->num_kctl_used++;
+ return 0;
+}
+
+/* create input playback/capture controls for the given pin */
+static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
+ const char *ctlname, int idx, int mix_nid)
+{
+ char name[32];
+ int err;
+
+ sprintf(name, "%s Playback Volume", ctlname);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", ctlname);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static void via_auto_set_output_and_unmute(struct hda_codec *codec,
+ hda_nid_t nid, int pin_type,
+ int dac_idx)
+{
+ /* set as output */
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pin_type);
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_UNMUTE);
+}
+
+
+static void via_auto_init_multi_out(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+ hda_nid_t nid = spec->autocfg.line_out_pins[i];
+ if (nid)
+ via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
+ }
+}
+
+static void via_auto_init_hp_out(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ hda_nid_t pin;
+
+ pin = spec->autocfg.hp_pins[0];
+ if (pin) /* connect to front */
+ via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+}
+
+static void via_auto_init_analog_input(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ hda_nid_t nid = spec->autocfg.input_pins[i];
+
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ (i <= AUTO_PIN_FRONT_MIC ?
+ PIN_VREF50 : PIN_IN));
+
+ }
+}
+/*
+ * input MUX handling
+ */
+static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+ ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+ return 0;
+}
+
+static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ unsigned int vendor_id = codec->vendor_id;
+
+ /* AIW0 lydia 060801 add for correct sw0 input select */
+ if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
+ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ 0x18, &spec->cur_mux[adc_idx]);
+ else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
+ IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) )
+ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ 0x19, &spec->cur_mux[adc_idx]);
+ else
+ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+ spec->adc_nids[adc_idx],
+ &spec->cur_mux[adc_idx]);
+}
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1708_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ * FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 1,
+ .info = via_mux_enum_info,
+ .get = via_mux_enum_get,
+ .put = via_mux_enum_put,
+ },
+ { } /* end */
+};
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1708_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0-1 and set the default input to mic-in
+ */
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ */
+ /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+ /*
+ * Set up output mixers (0x19 - 0x1b)
+ */
+ /* set vol=0 to output mixers */
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /* Setup default input to PW4 */
+ {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
+ /* Set mic as default input of sw0 */
+ {0x18, AC_VERB_SET_CONNECT_SEL, 0x2},
+ /* PW9 Output enable */
+ {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+};
+
+static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+ stream_tag, format, substream);
+}
+
+static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+
+ snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+ stream_tag, 0, format);
+ return 0;
+}
+
+static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+ 0, 0, 0);
+ return 0;
+}
+
+static struct hda_pcm_stream vt1708_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 8,
+ .nid = 0x10, /* NID to query formats and rates */
+ .ops = {
+ .open = via_playback_pcm_open,
+ .prepare = via_playback_pcm_prepare,
+ .cleanup = via_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream vt1708_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x15, /* NID to query formats and rates */
+ .ops = {
+ .prepare = via_capture_pcm_prepare,
+ .cleanup = via_capture_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream vt1708_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in via_build_pcms */
+ .ops = {
+ .open = via_dig_playback_pcm_open,
+ .close = via_dig_playback_pcm_close
+ },
+};
+
+static struct hda_pcm_stream vt1708_pcm_digital_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
+static int via_build_controls(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int err;
+ int i;
+
+ for (i = 0; i < spec->num_mixers; i++) {
+ err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
+ if (err < 0)
+ return err;
+ }
+
+ if (spec->multiout.dig_out_nid) {
+ err = snd_hda_create_spdif_out_ctls(codec,
+ spec->multiout.dig_out_nid);
+ if (err < 0)
+ return err;
+ }
+ if (spec->dig_in_nid) {
+ err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int via_build_pcms(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ struct hda_pcm *info = spec->pcm_rec;
+
+ codec->num_pcms = 1;
+ codec->pcm_info = info;
+
+ info->name = spec->stream_name_analog;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+ spec->multiout.max_channels;
+
+ if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+ codec->num_pcms++;
+ info++;
+ info->name = spec->stream_name_digital;
+ if (spec->multiout.dig_out_nid) {
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+ *(spec->stream_digital_playback);
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->multiout.dig_out_nid;
+ }
+ if (spec->dig_in_nid) {
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+ *(spec->stream_digital_capture);
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+ spec->dig_in_nid;
+ }
+ }
+
+ return 0;
+}
+
+static void via_free(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ unsigned int i;
+
+ if (!spec)
+ return;
+
+ if (spec->kctl_alloc) {
+ for (i = 0; i < spec->num_kctl_used; i++)
+ kfree(spec->kctl_alloc[i].name);
+ kfree(spec->kctl_alloc);
+ }
+
+ kfree(codec->spec);
+}
+
+static int via_init(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ snd_hda_sequence_write(codec, spec->init_verbs);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * resume
+ */
+static int via_resume(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int i;
+
+ via_init(codec);
+ for (i = 0; i < spec->num_mixers; i++)
+ snd_hda_resume_ctls(codec, spec->mixers[i]);
+ if (spec->multiout.dig_out_nid)
+ snd_hda_resume_spdif_out(codec);
+ if (spec->dig_in_nid)
+ snd_hda_resume_spdif_in(codec);
+
+ return 0;
+}
+#endif
+
+/*
+ */
+static struct hda_codec_ops via_patch_ops = {
+ .build_controls = via_build_controls,
+ .build_pcms = via_build_pcms,
+ .init = via_init,
+ .free = via_free,
+#ifdef CONFIG_PM
+ .resume = via_resume,
+#endif
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ int i;
+ hda_nid_t nid;
+
+ spec->multiout.num_dacs = cfg->line_outs;
+
+ spec->multiout.dac_nids = spec->private_dac_nids;
+
+ for(i = 0; i < 4; i++) {
+ nid = cfg->line_out_pins[i];
+ if (nid) {
+ /* config dac list */
+ switch (i) {
+ case AUTO_SEQ_FRONT:
+ spec->multiout.dac_nids[i] = 0x10;
+ break;
+ case AUTO_SEQ_CENLFE:
+ spec->multiout.dac_nids[i] = 0x12;
+ break;
+ case AUTO_SEQ_SURROUND:
+ spec->multiout.dac_nids[i] = 0x13;
+ break;
+ case AUTO_SEQ_SIDE:
+ spec->multiout.dac_nids[i] = 0x11;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ char name[32];
+ static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ hda_nid_t nid, nid_vol = 0;
+ int i, err;
+
+ for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+ nid = cfg->line_out_pins[i];
+
+ if (!nid)
+ continue;
+
+ if (i != AUTO_SEQ_FRONT)
+ nid_vol = 0x1b - i + 1;
+
+ if (i == AUTO_SEQ_CENLFE) {
+ /* Center/LFE */
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Center Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "LFE Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Center Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "LFE Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else if (i == AUTO_SEQ_FRONT){
+ /* add control to mixer index 0 */
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Master Front Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Master Front Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+
+ /* add control to PW3 */
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+ int err;
+
+ if (!pin)
+ return 0;
+
+ spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Headphone Playback Volume",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Headphone Playback Switch",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ static char *labels[] = {
+ "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+ };
+ struct hda_input_mux *imux = &spec->private_imux;
+ int i, err, idx = 0;
+
+ /* for internal loopback recording select */
+ imux->items[imux->num_items].label = "Stereo Mixer";
+ imux->items[imux->num_items].index = idx;
+ imux->num_items++;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ if (!cfg->input_pins[i])
+ continue;
+
+ switch (cfg->input_pins[i]) {
+ case 0x1d: /* Mic */
+ idx = 2;
+ break;
+
+ case 0x1e: /* Line In */
+ idx = 3;
+ break;
+
+ case 0x21: /* Front Mic */
+ idx = 4;
+ break;
+
+ case 0x24: /* CD */
+ idx = 1;
+ break;
+ }
+ err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
+ idx, 0x17);
+ if (err < 0)
+ return err;
+ imux->items[imux->num_items].label = labels[i];
+ imux->items[imux->num_items].index = idx;
+ imux->num_items++;
+ }
+ return 0;
+}
+
+static int vt1708_parse_auto_config(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+ if (err < 0)
+ return err;
+ err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+ return 0; /* can't find valid BIOS pin config */
+
+ err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+ if (err < 0)
+ return err;
+ err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+ if (spec->autocfg.dig_out_pin)
+ spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
+ if (spec->autocfg.dig_in_pin)
+ spec->dig_in_nid = VT1708_DIGIN_NID;
+
+ if (spec->kctl_alloc)
+ spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+ spec->init_verbs = vt1708_volume_init_verbs;
+
+ spec->input_mux = &spec->private_imux;
+
+ return 1;
+}
+
+/* init callback for auto-configuration model -- overriding the default init */
+static int via_auto_init(struct hda_codec *codec)
+{
+ via_init(codec);
+ via_auto_init_multi_out(codec);
+ via_auto_init_hp_out(codec);
+ via_auto_init_analog_input(codec);
+ return 0;
+}
+
+static int patch_vt1708(struct hda_codec *codec)
+{
+ struct via_spec *spec;
+ int err;
+
+ /* create a codec specific record */
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ /* automatic parse from the BIOS config */
+ err = vt1708_parse_auto_config(codec);
+ if (err < 0) {
+ via_free(codec);
+ return err;
+ } else if (!err) {
+ printk(KERN_INFO "hda_codec: Cannot set up configuration "
+ "from BIOS. Using genenic mode...\n");
+ }
+
+
+ spec->stream_name_analog = "VT1708 Analog";
+ spec->stream_analog_playback = &vt1708_pcm_analog_playback;
+ spec->stream_analog_capture = &vt1708_pcm_analog_capture;
+
+ spec->stream_name_digital = "VT1708 Digital";
+ spec->stream_digital_playback = &vt1708_pcm_digital_playback;
+ spec->stream_digital_capture = &vt1708_pcm_digital_capture;
+
+
+ if (!spec->adc_nids && spec->input_mux) {
+ spec->adc_nids = vt1708_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
+ spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
+ spec->num_mixers++;
+ }
+
+ codec->patch_ops = via_patch_ops;
+
+ codec->patch_ops.init = via_auto_init;
+
+ return 0;
+}
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1709_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ * FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 1,
+ .info = via_mux_enum_info,
+ .get = via_mux_enum_get,
+ .put = via_mux_enum_put,
+ },
+ { } /* end */
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0-2 and set the default input to mic-in
+ */
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ */
+ /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+ /*
+ * Set up output selector (0x1a, 0x1b, 0x29)
+ */
+ /* set vol=0 to output mixers */
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /*
+ * Unmute PW3 and PW4
+ */
+ {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /* Set input of PW4 as AOW4 */
+ {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
+ /* Set mic as default input of sw0 */
+ {0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
+ /* PW9 Output enable */
+ {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ { }
+};
+
+static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 10,
+ .nid = 0x10, /* NID to query formats and rates */
+ .ops = {
+ .open = via_playback_pcm_open,
+ .prepare = via_playback_pcm_prepare,
+ .cleanup = via_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 6,
+ .nid = 0x10, /* NID to query formats and rates */
+ .ops = {
+ .open = via_playback_pcm_open,
+ .prepare = via_playback_pcm_prepare,
+ .cleanup = via_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream vt1709_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x14, /* NID to query formats and rates */
+ .ops = {
+ .prepare = via_capture_pcm_prepare,
+ .cleanup = via_capture_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream vt1709_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in via_build_pcms */
+ .ops = {
+ .open = via_dig_playback_pcm_open,
+ .close = via_dig_playback_pcm_close
+ },
+};
+
+static struct hda_pcm_stream vt1709_pcm_digital_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
+static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ int i;
+ hda_nid_t nid;
+
+ if (cfg->line_outs == 4) /* 10 channels */
+ spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
+ else if (cfg->line_outs == 3) /* 6 channels */
+ spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
+
+ spec->multiout.dac_nids = spec->private_dac_nids;
+
+ if (cfg->line_outs == 4) { /* 10 channels */
+ for (i = 0; i < cfg->line_outs; i++) {
+ nid = cfg->line_out_pins[i];
+ if (nid) {
+ /* config dac list */
+ switch (i) {
+ case AUTO_SEQ_FRONT:
+ /* AOW0 */
+ spec->multiout.dac_nids[i] = 0x10;
+ break;
+ case AUTO_SEQ_CENLFE:
+ /* AOW2 */
+ spec->multiout.dac_nids[i] = 0x12;
+ break;
+ case AUTO_SEQ_SURROUND:
+ /* AOW3 */
+ spec->multiout.dac_nids[i] = 0x27;
+ break;
+ case AUTO_SEQ_SIDE:
+ /* AOW1 */
+ spec->multiout.dac_nids[i] = 0x11;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
+
+ } else if (cfg->line_outs == 3) { /* 6 channels */
+ for(i = 0; i < cfg->line_outs; i++) {
+ nid = cfg->line_out_pins[i];
+ if (nid) {
+ /* config dac list */
+ switch(i) {
+ case AUTO_SEQ_FRONT:
+ /* AOW0 */
+ spec->multiout.dac_nids[i] = 0x10;
+ break;
+ case AUTO_SEQ_CENLFE:
+ /* AOW2 */
+ spec->multiout.dac_nids[i] = 0x12;
+ break;
+ case AUTO_SEQ_SURROUND:
+ /* AOW1 */
+ spec->multiout.dac_nids[i] = 0x11;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ char name[32];
+ static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ hda_nid_t nid = 0;
+ int i, err;
+
+ for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+ nid = cfg->line_out_pins[i];
+
+ if (!nid)
+ continue;
+
+ if (i == AUTO_SEQ_CENLFE) {
+ /* Center/LFE */
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Center Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "LFE Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Center Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "LFE Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else if (i == AUTO_SEQ_FRONT){
+ /* add control to mixer index 0 */
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Master Front Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Master Front Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+
+ /* add control to PW3 */
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else if (i == AUTO_SEQ_SURROUND) {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else if (i == AUTO_SEQ_SIDE) {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+ int err;
+
+ if (!pin)
+ return 0;
+
+ if (spec->multiout.num_dacs == 5) /* 10 channels */
+ spec->multiout.hp_nid = VT1709_HP_DAC_NID;
+ else if (spec->multiout.num_dacs == 3) /* 6 channels */
+ spec->multiout.hp_nid = 0;
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Headphone Playback Volume",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Headphone Playback Switch",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ static char *labels[] = {
+ "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+ };
+ struct hda_input_mux *imux = &spec->private_imux;
+ int i, err, idx = 0;
+
+ /* for internal loopback recording select */
+ imux->items[imux->num_items].label = "Stereo Mixer";
+ imux->items[imux->num_items].index = idx;
+ imux->num_items++;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ if (!cfg->input_pins[i])
+ continue;
+
+ switch (cfg->input_pins[i]) {
+ case 0x1d: /* Mic */
+ idx = 2;
+ break;
+
+ case 0x1e: /* Line In */
+ idx = 3;
+ break;
+
+ case 0x21: /* Front Mic */
+ idx = 4;
+ break;
+
+ case 0x23: /* CD */
+ idx = 1;
+ break;
+ }
+ err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
+ idx, 0x18);
+ if (err < 0)
+ return err;
+ imux->items[imux->num_items].label = labels[i];
+ imux->items[imux->num_items].index = idx;
+ imux->num_items++;
+ }
+ return 0;
+}
+
+static int vt1709_parse_auto_config(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+ if (err < 0)
+ return err;
+ err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+ return 0; /* can't find valid BIOS pin config */
+
+ err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+ if (err < 0)
+ return err;
+ err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+ if (spec->autocfg.dig_out_pin)
+ spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
+ if (spec->autocfg.dig_in_pin)
+ spec->dig_in_nid = VT1709_DIGIN_NID;
+
+ if (spec->kctl_alloc)
+ spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+ spec->input_mux = &spec->private_imux;
+
+ return 1;
+}
+
+static int patch_vt1709_10ch(struct hda_codec *codec)
+{
+ struct via_spec *spec;
+ int err;
+
+ /* create a codec specific record */
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ err = vt1709_parse_auto_config(codec);
+ if (err < 0) {
+ via_free(codec);
+ return err;
+ } else if (!err) {
+ printk(KERN_INFO "hda_codec: Cannot set up configuration. "
+ "Using genenic mode...\n");
+ }
+
+ spec->init_verbs = vt1709_10ch_volume_init_verbs;
+
+ spec->stream_name_analog = "VT1709 Analog";
+ spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
+ spec->stream_analog_capture = &vt1709_pcm_analog_capture;
+
+ spec->stream_name_digital = "VT1709 Digital";
+ spec->stream_digital_playback = &vt1709_pcm_digital_playback;
+ spec->stream_digital_capture = &vt1709_pcm_digital_capture;
+
+
+ if (!spec->adc_nids && spec->input_mux) {
+ spec->adc_nids = vt1709_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+ spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
+ spec->num_mixers++;
+ }
+
+ codec->patch_ops = via_patch_ops;
+
+ codec->patch_ops.init = via_auto_init;
+
+ return 0;
+}
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0-2 and set the default input to mic-in
+ */
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ */
+ /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+ /*
+ * Set up output selector (0x1a, 0x1b, 0x29)
+ */
+ /* set vol=0 to output mixers */
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /*
+ * Unmute PW3 and PW4
+ */
+ {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ /* Set input of PW4 as MW0 */
+ {0x20, AC_VERB_SET_CONNECT_SEL, 0},
+ /* Set mic as default input of sw0 */
+ {0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
+ /* PW9 Output enable */
+ {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ { }
+};
+
+static int patch_vt1709_6ch(struct hda_codec *codec)
+{
+ struct via_spec *spec;
+ int err;
+
+ /* create a codec specific record */
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ err = vt1709_parse_auto_config(codec);
+ if (err < 0) {
+ via_free(codec);
+ return err;
+ } else if (!err) {
+ printk(KERN_INFO "hda_codec: Cannot set up configuration. "
+ "Using genenic mode...\n");
+ }
+
+ spec->init_verbs = vt1709_6ch_volume_init_verbs;
+
+ spec->stream_name_analog = "VT1709 Analog";
+ spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
+ spec->stream_analog_capture = &vt1709_pcm_analog_capture;
+
+ spec->stream_name_digital = "VT1709 Digital";
+ spec->stream_digital_playback = &vt1709_pcm_digital_playback;
+ spec->stream_digital_capture = &vt1709_pcm_digital_capture;
+
+
+ if (!spec->adc_nids && spec->input_mux) {
+ spec->adc_nids = vt1709_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+ spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
+ spec->num_mixers++;
+ }
+
+ codec->patch_ops = via_patch_ops;
+
+ codec->patch_ops.init = via_auto_init;
+
+ return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_via[] = {
+ { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
+ { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
+ { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
+ { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
+ { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+ { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+ { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+ { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
+ { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+ { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+ { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+ { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+ {} /* terminator */
+};
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile
index 7837cef8855..6efdd62f683 100644
--- a/sound/pci/ice1712/Makefile
+++ b/sound/pci/ice1712/Makefile
@@ -5,7 +5,7 @@
snd-ice17xx-ak4xxx-objs := ak4xxx.o
snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
-snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o
+snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c
index 59c4078ad33..6e22d326df3 100644
--- a/sound/pci/ice1712/amp.c
+++ b/sound/pci/ice1712/amp.c
@@ -42,7 +42,7 @@ static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice)
{
- static unsigned short wm_inits[] = {
+ static const unsigned short wm_inits[] = {
WM_ATTEN_L, 0x0000, /* 0 db */
WM_ATTEN_R, 0x0000, /* 0 db */
WM_DAC_CTRL, 0x0008, /* 24bit I2S */
@@ -75,7 +75,7 @@ static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice)
/* entry point */
-struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_AV710,
.name = "Chaintech AV-710",
diff --git a/sound/pci/ice1712/amp.h b/sound/pci/ice1712/amp.h
index a0fc89b4812..7b667bad0c6 100644
--- a/sound/pci/ice1712/amp.h
+++ b/sound/pci/ice1712/amp.h
@@ -42,7 +42,7 @@
#define WM_DAC_CTRL 0x02
#define WM_INT_CTRL 0x03
-extern struct snd_ice1712_card_info snd_vt1724_amp_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_amp_cards[];
#endif /* __SOUND_AMP_H */
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 9e76cebd2d2..6941d85dfec 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -294,7 +294,7 @@ static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short r
static int aureon_ac97_init (struct snd_ice1712 *ice)
{
int i;
- static unsigned short ac97_defaults[] = {
+ static const unsigned short ac97_defaults[] = {
0x00, 0x9640,
0x02, 0x8000,
0x04, 0x8000,
@@ -474,7 +474,8 @@ static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned
tmp = snd_ice1712_gpio_read(ice);
- if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) {
+ if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
+ ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) {
snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
mosi = PRODIGY_SPI_MOSI;
clk = PRODIGY_SPI_CLK;
@@ -601,7 +602,9 @@ static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
{
aureon_spi_write(ice,
- (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ? PRODIGY_WM_CS : AUREON_WM_CS),
+ ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
+ ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ?
+ PRODIGY_WM_CS : AUREON_WM_CS),
(reg << 9) | (val & 0x1ff), 16);
}
@@ -661,17 +664,17 @@ static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
/*
* Logarithmic volume values for WM8770
* Computed as 20 * Log10(255 / x)
*/
-static unsigned char wm_vol[256] = {
+static const unsigned char wm_vol[256] = {
127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
@@ -1064,14 +1067,14 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
*/
static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {
+ static const char * const texts[] = {
"CD", //AIN1
"Aux", //AIN2
"Line", //AIN3
"Mic", //AIN4
"AC97" //AIN5
};
- static char *universe_texts[] = {
+ static const char * const universe_texts[] = {
"Aux1", //AIN1
"CD", //AIN2
"Phono", //AIN3
@@ -1137,11 +1140,11 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- static char *aureon_texts[] = {
+ static const char * const aureon_texts[] = {
"CD", //RXP0
"Optical" //RXP1
};
- static char *prodigy_texts[] = {
+ static const char * const prodigy_texts[] = {
"CD",
"Coax"
};
@@ -1288,12 +1291,14 @@ static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
tmp2 = tmp = snd_ice1712_gpio_read(ice);
if (enable)
- if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
+ if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+ ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
tmp |= AUREON_HP_SEL;
else
tmp |= PRODIGY_HP_SEL;
else
- if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
+ if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+ ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
tmp &= ~ AUREON_HP_SEL;
else
tmp &= ~ PRODIGY_HP_SEL;
@@ -1363,7 +1368,7 @@ static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
*/
static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "128x", "64x" };
+ static const char * const texts[2] = { "128x", "64x" };
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
@@ -1406,7 +1411,7 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl
* mixers
*/
-static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
+static const struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
@@ -1521,7 +1526,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
}
};
-static struct snd_kcontrol_new wm_controls[] __devinitdata = {
+static const struct snd_kcontrol_new wm_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Switch",
@@ -1587,7 +1592,7 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = {
}
};
-static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
+static const struct snd_kcontrol_new ac97_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "AC97 Playback Switch",
@@ -1692,7 +1697,7 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
}
};
-static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
+static const struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "AC97 Playback Switch",
@@ -1824,8 +1829,7 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
};
-
-static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
+static const struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
@@ -1870,7 +1874,6 @@ static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
}
};
-
static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
{
unsigned int i, counts;
@@ -1898,7 +1901,8 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
return err;
}
}
- else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
+ else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+ ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
if (err < 0)
@@ -1906,7 +1910,8 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
}
}
- if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
+ if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+ ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
unsigned char id;
snd_ice1712_save_gpio_status(ice);
id = aureon_cs8415_get(ice, CS8415_ID);
@@ -1936,7 +1941,7 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
*/
static int __devinit aureon_init(struct snd_ice1712 *ice)
{
- static unsigned short wm_inits_aureon[] = {
+ static const unsigned short wm_inits_aureon[] = {
/* These come first to reduce init pop noise */
0x1b, 0x044, /* ADC Mux (AC'97 source) */
0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
@@ -1972,7 +1977,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
0x1a, 0x000, /* -12dB ADC/R */
(unsigned short)-1
};
- static unsigned short wm_inits_prodigy[] = {
+ static const unsigned short wm_inits_prodigy[] = {
/* These come first to reduce init pop noise */
0x1b, 0x000, /* ADC Mux */
@@ -2014,7 +2019,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
(unsigned short)-1
};
- static unsigned short cs_inits[] = {
+ static const unsigned short cs_inits[] = {
0x0441, /* RUN */
0x0180, /* no mute, OMCK output on RMCK pin */
0x0201, /* S/PDIF source on RXP1 */
@@ -2022,7 +2027,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
(unsigned short)-1
};
unsigned int tmp;
- unsigned short *p;
+ const unsigned short *p;
int err, i;
if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
@@ -2062,7 +2067,8 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
/* initialize WM8770 codec */
if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
- ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT)
+ ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
+ ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
p = wm_inits_prodigy;
else
p = wm_inits_aureon;
@@ -2070,7 +2076,8 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
wm_put(ice, p[0], p[1]);
/* initialize CS8415A codec */
- if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
+ if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
+ ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
for (p = cs_inits; *p != (unsigned short)-1; p++)
aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
ice->spec.aureon.cs8415_mux = 1;
@@ -2100,73 +2107,58 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
* hence the driver needs to sets up it properly.
*/
-static unsigned char aureon51_eeprom[] __devinitdata = {
- 0x0a, /* SYSCONF: clock 512, spdif-in/ADC, 3DACs */
- 0x80, /* ACLINK: I2S */
- 0xfc, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x5f, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char aureon51_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x5f,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
-static unsigned char aureon71_eeprom[] __devinitdata = {
- 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
- 0x80, /* ACLINK: I2S */
- 0xfc, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x5f, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char aureon71_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x5f,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
-
-static unsigned char prodigy71_eeprom[] __devinitdata = {
- 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
- 0x80, /* ACLINK: I2S */
- 0xfc, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x5f, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
+#define prodigy71_eeprom aureon71_eeprom
+
+static const unsigned char prodigy71lt_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x5f,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
-
-static unsigned char prodigy71lt_eeprom[] __devinitdata = {
- 0x4b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
- 0x80, /* ACLINK: I2S */
- 0xfc, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x5f, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
-};
-
+#define prodigy71xt_eeprom prodigy71lt_eeprom
/* entry point */
-struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
.name = "Terratec Aureon 5.1-Sky",
@@ -2217,5 +2209,15 @@ struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
.eeprom_data = prodigy71lt_eeprom,
.driver = "Prodigy71LT",
},
+ {
+ .subvendor = VT1724_SUBDEVICE_PRODIGY71XT,
+ .name = "Audiotrak Prodigy 7.1 XT",
+ .model = "prodigy71xt",
+ .chip_init = aureon_init,
+ .build_controls = aureon_add_controls,
+ .eeprom_size = sizeof(prodigy71xt_eeprom),
+ .eeprom_data = prodigy71xt_eeprom,
+ .driver = "Prodigy71LT",
+ },
{ } /* terminator */
};
diff --git a/sound/pci/ice1712/aureon.h b/sound/pci/ice1712/aureon.h
index 3b7bea656c5..79e58e88ed4 100644
--- a/sound/pci/ice1712/aureon.h
+++ b/sound/pci/ice1712/aureon.h
@@ -28,15 +28,17 @@
"{Terratec,Aureon 7.1 Space},"\
"{Terratec,Aureon 7.1 Universe}," \
"{AudioTrak,Prodigy 7.1}," \
- "{AudioTrak,Prodigy 7.1 LT},"
+ "{AudioTrak,Prodigy 7.1 LT},"\
+ "{AudioTrak,Prodigy 7.1 XT},"
#define VT1724_SUBDEVICE_AUREON51_SKY 0x3b154711 /* Aureon 5.1 Sky */
#define VT1724_SUBDEVICE_AUREON71_SPACE 0x3b154511 /* Aureon 7.1 Space */
#define VT1724_SUBDEVICE_AUREON71_UNIVERSE 0x3b155311 /* Aureon 7.1 Universe */
#define VT1724_SUBDEVICE_PRODIGY71 0x33495345 /* PRODIGY 7.1 */
#define VT1724_SUBDEVICE_PRODIGY71LT 0x32315441 /* PRODIGY 7.1 LT */
+#define VT1724_SUBDEVICE_PRODIGY71XT 0x36315441 /* PRODIGY 7.1 XT*/
-extern struct snd_ice1712_card_info snd_vt1724_aureon_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_aureon_cards[];
/* GPIO bits */
#define AUREON_CS8415_CS (1 << 22)
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index af659800c9b..3eeb36c6e98 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -416,7 +416,7 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata =
{
.access = (SNDRV_CTL_ELEM_ACCESS_READ),
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -429,7 +429,7 @@ static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devini
* initialize the chips on M-Audio cards
*/
-static struct snd_akm4xxx akm_audiophile __devinitdata = {
+static const struct snd_akm4xxx akm_audiophile __devinitdata = {
.type = SND_AK4528,
.num_adcs = 2,
.num_dacs = 2,
@@ -438,7 +438,7 @@ static struct snd_akm4xxx akm_audiophile __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = {
.caddr = 2,
.cif = 0,
.data_mask = ICE1712_DELTA_AP_DOUT,
@@ -450,7 +450,7 @@ static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_delta410 __devinitdata = {
+static const struct snd_akm4xxx akm_delta410 __devinitdata = {
.type = SND_AK4529,
.num_adcs = 2,
.num_dacs = 8,
@@ -459,7 +459,7 @@ static struct snd_akm4xxx akm_delta410 __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_delta410_priv __devinitdata = {
.caddr = 0,
.cif = 0,
.data_mask = ICE1712_DELTA_AP_DOUT,
@@ -471,7 +471,7 @@ static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_delta1010lt __devinitdata = {
+static const struct snd_akm4xxx akm_delta1010lt __devinitdata = {
.type = SND_AK4524,
.num_adcs = 8,
.num_dacs = 8,
@@ -481,7 +481,7 @@ static struct snd_akm4xxx akm_delta1010lt __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = {
.caddr = 2,
.cif = 0, /* the default level of the CIF pin from AK4524 */
.data_mask = ICE1712_DELTA_1010LT_DOUT,
@@ -493,7 +493,7 @@ static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_delta44 __devinitdata = {
+static const struct snd_akm4xxx akm_delta44 __devinitdata = {
.type = SND_AK4524,
.num_adcs = 4,
.num_dacs = 4,
@@ -503,7 +503,7 @@ static struct snd_akm4xxx akm_delta44 __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_delta44_priv __devinitdata = {
.caddr = 2,
.cif = 0, /* the default level of the CIF pin from AK4524 */
.data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA,
@@ -515,7 +515,7 @@ static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_vx442 __devinitdata = {
+static const struct snd_akm4xxx akm_vx442 __devinitdata = {
.type = SND_AK4524,
.num_adcs = 4,
.num_dacs = 4,
@@ -525,7 +525,7 @@ static struct snd_akm4xxx akm_vx442 __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_vx442_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_vx442_priv __devinitdata = {
.caddr = 2,
.cif = 0,
.data_mask = ICE1712_VX442_DOUT,
@@ -650,15 +650,15 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
* additional controls for M-Audio cards
*/
-static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
-static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 0, 0);
-static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
-static struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
-static struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata =
ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
@@ -735,7 +735,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice)
/* entry point */
-struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
{
.subvendor = ICE1712_SUBDEVICE_DELTA1010,
.name = "M Audio Delta 1010",
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index 746ebde9452..e65d669af63 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -46,7 +46,7 @@
#define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100
/* entry point */
-extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
+extern const struct snd_ice1712_card_info snd_ice1712_delta_cards[];
/*
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index b135389fec6..9b7ff302c07 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -332,7 +332,7 @@ static void ews88_setup_spdif(struct snd_ice1712 *ice, int rate)
/*
*/
-static struct snd_akm4xxx akm_ews88mt __devinitdata = {
+static const struct snd_akm4xxx akm_ews88mt __devinitdata = {
.num_adcs = 8,
.num_dacs = 8,
.type = SND_AK4524,
@@ -342,7 +342,7 @@ static struct snd_akm4xxx akm_ews88mt __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = {
.caddr = 2,
.cif = 1, /* CIF high */
.data_mask = ICE1712_EWS88_SERIAL_DATA,
@@ -354,7 +354,7 @@ static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_ewx2496 __devinitdata = {
+static const struct snd_akm4xxx akm_ewx2496 __devinitdata = {
.num_adcs = 2,
.num_dacs = 2,
.type = SND_AK4524,
@@ -363,7 +363,7 @@ static struct snd_akm4xxx akm_ewx2496 __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = {
.caddr = 2,
.cif = 1, /* CIF high */
.data_mask = ICE1712_EWS88_SERIAL_DATA,
@@ -375,7 +375,7 @@ static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_6fire __devinitdata = {
+static const struct snd_akm4xxx akm_6fire __devinitdata = {
.num_adcs = 6,
.num_dacs = 6,
.type = SND_AK4524,
@@ -384,7 +384,7 @@ static struct snd_akm4xxx akm_6fire __devinitdata = {
}
};
-static struct snd_ak4xxx_private akm_6fire_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_6fire_priv __devinitdata = {
.caddr = 2,
.cif = 1, /* CIF high */
.data_mask = ICE1712_6FIRE_SERIAL_DATA,
@@ -578,7 +578,7 @@ static int snd_ice1712_ewx_io_sense_put(struct snd_kcontrol *kcontrol, struct sn
return val != nval;
}
-static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Sensitivity Switch",
@@ -678,7 +678,7 @@ static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, st
return ndata != data;
}
-static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Sensitivity Switch",
.info = snd_ice1712_ewx_io_sense_info,
@@ -687,7 +687,7 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = {
.count = 8,
};
-static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Output Sensitivity Switch",
.info = snd_ice1712_ewx_io_sense_info,
@@ -769,7 +769,7 @@ static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct
.private_value = xshift | (xinvert << 8),\
}
-static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = {
EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, 1, 0), /* inverted */
EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Output Optical", 1, 0, 0),
EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT External Master Clock", 2, 0, 0),
@@ -909,7 +909,7 @@ static int snd_ice1712_6fire_select_input_put(struct snd_kcontrol *kcontrol, str
.private_value = xshift | (xinvert << 8),\
}
-static struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Analog Input Select",
@@ -989,7 +989,7 @@ static int __devinit snd_ice1712_ews_add_controls(struct snd_ice1712 *ice)
/* entry point */
-struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = {
{
.subvendor = ICE1712_SUBDEVICE_EWX2496,
.name = "TerraTec EWX24/96",
diff --git a/sound/pci/ice1712/ews.h b/sound/pci/ice1712/ews.h
index a12a0b05355..df449b4741f 100644
--- a/sound/pci/ice1712/ews.h
+++ b/sound/pci/ice1712/ews.h
@@ -40,7 +40,7 @@
#define ICE1712_SUBDEVICE_PHASE88 0x3b155111
/* entry point */
-extern struct snd_ice1712_card_info snd_ice1712_ews_cards[];
+extern const struct snd_ice1712_card_info snd_ice1712_ews_cards[];
/* TerraTec EWX 24/96 configuration definitions */
diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c
index 3f27d04e7d3..df97313aaf8 100644
--- a/sound/pci/ice1712/hoontech.c
+++ b/sound/pci/ice1712/hoontech.c
@@ -239,7 +239,7 @@ static void stdsp24_ak4524_lock(struct snd_akm4xxx *ak, int chip)
static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice)
{
/* Hoontech STDSP24 with modified hardware */
- static struct snd_akm4xxx akm_stdsp24_mv __devinitdata = {
+ static const struct snd_akm4xxx akm_stdsp24_mv __devinitdata = {
.num_adcs = 2,
.num_dacs = 2,
.type = SND_AK4524,
@@ -248,7 +248,7 @@ static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice)
}
};
- static struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = {
+ static const struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = {
.caddr = 2,
.cif = 1, /* CIF high */
.data_mask = ICE1712_STDSP24_SERIAL_DATA,
@@ -298,7 +298,7 @@ static int __devinit snd_ice1712_ez8_init(struct snd_ice1712 *ice)
/* entry point */
-struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
{
.subvendor = ICE1712_SUBDEVICE_STDSP24,
.name = "Hoontech SoundTrack Audio DSP24",
@@ -325,4 +325,3 @@ struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
},
{ } /* terminator */
};
-
diff --git a/sound/pci/ice1712/hoontech.h b/sound/pci/ice1712/hoontech.h
index 1ee538b20fb..b62d6e4f6c7 100644
--- a/sound/pci/ice1712/hoontech.h
+++ b/sound/pci/ice1712/hoontech.h
@@ -35,7 +35,7 @@
#define ICE1712_SUBDEVICE_STDSP24_MEDIA7_1 0x16141217 /* Hoontech ST Audio DSP24 Media 7.1 */
#define ICE1712_SUBDEVICE_EVENT_EZ8 0x00010001 /* A dummy id for EZ8 */
-extern struct snd_ice1712_card_info snd_ice1712_hoontech_cards[];
+extern const struct snd_ice1712_card_info snd_ice1712_hoontech_cards[];
/* Hoontech SoundTrack Audio DSP 24 GPIO definitions */
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 8a576b78bee..830a1bbd711 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -107,7 +107,7 @@ module_param_array(dxr_enable, int, NULL, 0444);
MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE.");
-static struct pci_device_id snd_ice1712_ids[] = {
+static const struct pci_device_id snd_ice1712_ids[] = {
{ PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICE1712 */
{ 0, }
};
@@ -287,7 +287,7 @@ static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, stru
return val != nval;
}
-static struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Digital Mixer To AC97",
.info = snd_ice1712_digmix_route_ac97_info,
@@ -719,7 +719,7 @@ static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *s
return bytes_to_frames(substream->runtime, ptr);
}
-static struct snd_pcm_hardware snd_ice1712_playback =
+static const struct snd_pcm_hardware snd_ice1712_playback =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -739,7 +739,7 @@ static struct snd_pcm_hardware snd_ice1712_playback =
.fifo_size = 0,
};
-static struct snd_pcm_hardware snd_ice1712_playback_ds =
+static const struct snd_pcm_hardware snd_ice1712_playback_ds =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -759,7 +759,7 @@ static struct snd_pcm_hardware snd_ice1712_playback_ds =
.fifo_size = 0,
};
-static struct snd_pcm_hardware snd_ice1712_capture =
+static const struct snd_pcm_hardware snd_ice1712_capture =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -1133,7 +1133,7 @@ static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substrea
return bytes_to_frames(substream->runtime, ptr);
}
-static struct snd_pcm_hardware snd_ice1712_playback_pro =
+static const struct snd_pcm_hardware snd_ice1712_playback_pro =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -1153,7 +1153,7 @@ static struct snd_pcm_hardware snd_ice1712_playback_pro =
.fifo_size = 0,
};
-static struct snd_pcm_hardware snd_ice1712_capture_pro =
+static const struct snd_pcm_hardware snd_ice1712_capture_pro =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -1378,9 +1378,9 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0);
-static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Playback Switch",
@@ -1404,7 +1404,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata
},
};
-static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "H/W Multi Capture Switch",
.info = snd_ice1712_pro_mixer_switch_info,
@@ -1413,7 +1413,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinit
.private_value = 10,
};
-static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH),
.info = snd_ice1712_pro_mixer_switch_info,
@@ -1423,7 +1423,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitd
.count = 2,
};
-static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
@@ -1435,7 +1435,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinit
.tlv = { .p = db_scale_playback }
};
-static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME),
.info = snd_ice1712_pro_mixer_volume_info,
@@ -1627,7 +1627,7 @@ static int snd_ice1712_eeprom_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.name = "ICE1712 EEPROM",
.access = SNDRV_CTL_ELEM_ACCESS_READ,
@@ -1663,7 +1663,7 @@ static int snd_ice1712_spdif_default_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -1714,7 +1714,7 @@ static int snd_ice1712_spdif_maskp_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1723,7 +1723,7 @@ static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata =
.get = snd_ice1712_spdif_maskc_get,
};
-static struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1750,7 +1750,7 @@ static int snd_ice1712_spdif_stream_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata =
+static const struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata =
{
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_INACTIVE),
@@ -1811,7 +1811,7 @@ int snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol,
static int snd_ice1712_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {
+ static const char * const texts[] = {
"8000", /* 0: 6 */
"9600", /* 1: 3 */
"11025", /* 2: 10 */
@@ -1840,7 +1840,7 @@ static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- static unsigned char xlate[16] = {
+ static const unsigned char xlate[16] = {
9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 255, 255, 255, 10
};
unsigned char val;
@@ -1864,7 +1864,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- static unsigned int xrate[13] = {
+ static const unsigned int xrate[13] = {
8000, 9600, 11025, 12000, 16000, 22050, 24000,
32000, 44100, 48000, 64000, 88200, 96000
};
@@ -1891,7 +1891,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Internal Clock",
.info = snd_ice1712_pro_internal_clock_info,
@@ -1902,7 +1902,7 @@ static struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = {
static int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {
+ static const char * const texts[] = {
"8000", /* 0: 6 */
"9600", /* 1: 3 */
"11025", /* 2: 10 */
@@ -1931,7 +1931,7 @@ static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcont
struct snd_ctl_elem_value *ucontrol)
{
int val;
- static unsigned int xrate[13] = {
+ static const unsigned int xrate[13] = {
8000, 9600, 11025, 12000, 16000, 22050, 24000,
32000, 44100, 48000, 64000, 88200, 96000
};
@@ -1948,7 +1948,7 @@ static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcont
static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- static unsigned int xrate[13] = {
+ static const unsigned int xrate[13] = {
8000, 9600, 11025, 12000, 16000, 22050, 24000,
32000, 44100, 48000, 64000, 88200, 96000
};
@@ -1962,7 +1962,7 @@ static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcont
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Internal Clock Default",
.info = snd_ice1712_pro_internal_clock_default_info,
@@ -2001,7 +2001,7 @@ static int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Locking",
.info = snd_ice1712_pro_rate_locking_info,
@@ -2040,7 +2040,7 @@ static int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Reset",
.info = snd_ice1712_pro_rate_reset_info,
@@ -2054,7 +2054,7 @@ static struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = {
static int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {
+ static const char * const texts[] = {
"PCM Out", /* 0 */
"H/W In 0", "H/W In 1", "H/W In 2", "H/W In 3", /* 1-4 */
"H/W In 4", "H/W In 5", "H/W In 6", "H/W In 7", /* 5-8 */
@@ -2207,7 +2207,7 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "H/W Playback Route",
.info = snd_ice1712_pro_route_info,
@@ -2215,7 +2215,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata
.put = snd_ice1712_pro_route_analog_put,
};
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = snd_ice1712_pro_route_info,
@@ -2257,7 +2257,7 @@ static int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Volume Rate",
.info = snd_ice1712_pro_volume_rate_info,
@@ -2290,7 +2290,7 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Peak",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
@@ -2305,7 +2305,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = {
/*
* list of available boards
*/
-static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
+static const struct snd_ice1712_card_info *card_tables[] __devinitdata = {
snd_ice1712_hoontech_cards,
snd_ice1712_delta_cards,
snd_ice1712_ews_cards,
@@ -2329,7 +2329,7 @@ static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice,
{
int dev = 0xa0; /* EEPROM device address */
unsigned int i, size;
- struct snd_ice1712_card_info **tbl, *c;
+ const struct snd_ice1712_card_info **tbl, *c;
if (! modelname || ! *modelname) {
ice->eeprom.subvendor = 0;
@@ -2614,7 +2614,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
ice->dmapath_port = pci_resource_start(pci, 2);
ice->profi_port = pci_resource_start(pci, 3);
- if (request_irq(pci->irq, snd_ice1712_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_ice1712_interrupt, IRQF_SHARED,
"ICE1712", ice)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_ice1712_free(ice);
@@ -2658,7 +2658,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
*
*/
-static struct snd_ice1712_card_info no_matched __devinitdata;
+static const struct snd_ice1712_card_info no_matched __devinitdata;
static int __devinit snd_ice1712_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
@@ -2667,7 +2667,7 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
struct snd_card *card;
struct snd_ice1712 *ice;
int pcm_dev = 0, err;
- struct snd_ice1712_card_info **tbl, *c;
+ const struct snd_ice1712_card_info **tbl, *c;
if (dev >= SNDRV_CARDS)
return -ENODEV;
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index ce27eac40d4..c3d9feaaf57 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -28,6 +28,7 @@
#include <sound/i2c.h>
#include <sound/ak4xxx-adda.h>
#include <sound/ak4114.h>
+#include <sound/pt2258.h>
#include <sound/pcm.h>
#include <sound/mpu401.h>
@@ -381,6 +382,11 @@ struct snd_ice1712 {
unsigned short master[2];
unsigned short vol[8];
} phase28;
+ /* a non-standard I2C device for revo51 */
+ struct revo51_spec {
+ struct snd_i2c_device *dev;
+ struct snd_pt2258 *pt2258;
+ } revo51;
/* Hoontech-specific setting */
struct hoontech_spec {
unsigned char boxbits[4];
@@ -462,6 +468,14 @@ static inline void snd_ice1712_gpio_write_bits(struct snd_ice1712 *ice,
snd_ice1712_gpio_write(ice, mask & bits);
}
+static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice,
+ unsigned int mask)
+{
+ ice->gpio.direction &= ~mask;
+ snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+ return (snd_ice1712_gpio_read(ice) & mask);
+}
+
int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice);
int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template,
@@ -500,8 +514,8 @@ struct snd_ice1712_card_info {
unsigned int mpu401_2_info_flags;
const char *mpu401_1_name;
const char *mpu401_2_name;
- unsigned int eeprom_size;
- unsigned char *eeprom_data;
+ const unsigned int eeprom_size;
+ const unsigned char *eeprom_data;
};
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index e9cbfdf3705..1127ebdf5fe 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -50,7 +50,7 @@
#include "prodigy192.h"
#include "juli.h"
#include "phase.h"
-
+#include "wtm.h"
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)");
@@ -64,6 +64,7 @@ MODULE_SUPPORTED_DEVICE("{"
PRODIGY192_DEVICE_DESC
JULI_DEVICE_DESC
PHASE_DEVICE_DESC
+ WTM_DEVICE_DESC
"{VIA,VT1720},"
"{VIA,VT1724},"
"{ICEnsemble,Generic ICE1724},"
@@ -86,7 +87,7 @@ MODULE_PARM_DESC(model, "Use the given board model.");
/* Both VT1720 and VT1724 have the same PCI IDs */
-static struct pci_device_id snd_vt1724_ids[] = {
+static const struct pci_device_id snd_vt1724_ids[] = {
{ PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_VT1724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0, }
};
@@ -341,7 +342,7 @@ static int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
what = 0;
snd_pcm_group_for_each(pos, substream) {
- struct vt1724_pcm_reg *reg;
+ const struct vt1724_pcm_reg *reg;
s = snd_pcm_group_substream_entry(pos);
reg = s->runtime->private_data;
what |= reg->start;
@@ -605,7 +606,7 @@ static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substrea
static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
- struct vt1724_pcm_reg *reg = substream->runtime->private_data;
+ const struct vt1724_pcm_reg *reg = substream->runtime->private_data;
spin_lock_irq(&ice->reg_lock);
outl(substream->runtime->dma_addr, ice->profi_port + reg->addr);
@@ -620,7 +621,7 @@ static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream)
static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
- struct vt1724_pcm_reg *reg = substream->runtime->private_data;
+ const struct vt1724_pcm_reg *reg = substream->runtime->private_data;
size_t ptr;
if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & reg->start))
@@ -646,21 +647,21 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr
#endif
}
-static struct vt1724_pcm_reg vt1724_playback_pro_reg = {
+static const struct vt1724_pcm_reg vt1724_playback_pro_reg = {
.addr = VT1724_MT_PLAYBACK_ADDR,
.size = VT1724_MT_PLAYBACK_SIZE,
.count = VT1724_MT_PLAYBACK_COUNT,
.start = VT1724_PDMA0_START,
};
-static struct vt1724_pcm_reg vt1724_capture_pro_reg = {
+static const struct vt1724_pcm_reg vt1724_capture_pro_reg = {
.addr = VT1724_MT_CAPTURE_ADDR,
.size = VT1724_MT_CAPTURE_SIZE,
.count = VT1724_MT_CAPTURE_COUNT,
.start = VT1724_RDMA0_START,
};
-static struct snd_pcm_hardware snd_vt1724_playback_pro =
+static const struct snd_pcm_hardware snd_vt1724_playback_pro =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -679,7 +680,7 @@ static struct snd_pcm_hardware snd_vt1724_playback_pro =
.periods_max = 1024,
};
-static struct snd_pcm_hardware snd_vt1724_spdif =
+static const struct snd_pcm_hardware snd_vt1724_spdif =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -701,7 +702,7 @@ static struct snd_pcm_hardware snd_vt1724_spdif =
.periods_max = 1024,
};
-static struct snd_pcm_hardware snd_vt1724_2ch_stereo =
+static const struct snd_pcm_hardware snd_vt1724_2ch_stereo =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -773,7 +774,7 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
int chs;
- runtime->private_data = &vt1724_playback_pro_reg;
+ runtime->private_data = (void *)&vt1724_playback_pro_reg;
ice->playback_pro_substream = substream;
runtime->hw = snd_vt1724_playback_pro;
snd_pcm_set_sync(substream);
@@ -802,7 +803,7 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- runtime->private_data = &vt1724_capture_pro_reg;
+ runtime->private_data = (void *)&vt1724_capture_pro_reg;
ice->capture_pro_substream = substream;
runtime->hw = snd_vt1724_2ch_stereo;
snd_pcm_set_sync(substream);
@@ -888,14 +889,14 @@ static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 * ice, int device)
* SPDIF PCM
*/
-static struct vt1724_pcm_reg vt1724_playback_spdif_reg = {
+static const struct vt1724_pcm_reg vt1724_playback_spdif_reg = {
.addr = VT1724_MT_PDMA4_ADDR,
.size = VT1724_MT_PDMA4_SIZE,
.count = VT1724_MT_PDMA4_COUNT,
.start = VT1724_PDMA4_START,
};
-static struct vt1724_pcm_reg vt1724_capture_spdif_reg = {
+static const struct vt1724_pcm_reg vt1724_capture_spdif_reg = {
.addr = VT1724_MT_RDMA1_ADDR,
.size = VT1724_MT_RDMA1_SIZE,
.count = VT1724_MT_RDMA1_COUNT,
@@ -953,7 +954,7 @@ static int snd_vt1724_playback_spdif_open(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- runtime->private_data = &vt1724_playback_spdif_reg;
+ runtime->private_data = (void *)&vt1724_playback_spdif_reg;
ice->playback_con_substream = substream;
if (ice->force_pdma4) {
runtime->hw = snd_vt1724_2ch_stereo;
@@ -985,7 +986,7 @@ static int snd_vt1724_capture_spdif_open(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- runtime->private_data = &vt1724_capture_spdif_reg;
+ runtime->private_data = (void *)&vt1724_capture_spdif_reg;
ice->capture_con_substream = substream;
if (ice->force_rdma1) {
runtime->hw = snd_vt1724_2ch_stereo;
@@ -1090,7 +1091,7 @@ static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 * ice, int device)
* independent surround PCMs
*/
-static struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = {
+static const struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = {
{
.addr = VT1724_MT_PDMA1_ADDR,
.size = VT1724_MT_PDMA1_SIZE,
@@ -1136,7 +1137,7 @@ static int snd_vt1724_playback_indep_open(struct snd_pcm_substream *substream)
return -EBUSY; /* FIXME: should handle blocking mode properly */
}
mutex_unlock(&ice->open_mutex);
- runtime->private_data = &vt1724_playback_dma_regs[substream->number];
+ runtime->private_data = (void *)&vt1724_playback_dma_regs[substream->number];
ice->playback_con_substream_ds[substream->number] = substream;
runtime->hw = snd_vt1724_2ch_stereo;
snd_pcm_set_sync(substream);
@@ -1317,7 +1318,7 @@ static int snd_vt1724_eeprom_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.name = "ICE1724 EEPROM",
.access = SNDRV_CTL_ELEM_ACCESS_READ,
@@ -1430,7 +1431,7 @@ static int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol,
return (val != old);
}
-static struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -1462,7 +1463,7 @@ static int snd_vt1724_spdif_maskp_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1471,7 +1472,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata =
.get = snd_vt1724_spdif_maskc_get,
};
-static struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1516,7 +1517,7 @@ static int snd_vt1724_spdif_sw_put(struct snd_kcontrol *kcontrol,
return old != val;
}
-static struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata =
+static const struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
/* FIXME: the following conflict with IEC958 Playback Route */
@@ -1584,7 +1585,7 @@ int snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol,
static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts_1724[] = {
+ static const char * const texts_1724[] = {
"8000", /* 0: 6 */
"9600", /* 1: 3 */
"11025", /* 2: 10 */
@@ -1602,7 +1603,7 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
"192000", /* 14: 14 */
"IEC958 Input", /* 15: -- */
};
- static char *texts_1720[] = {
+ static const char * const texts_1720[] = {
"8000", /* 0: 6 */
"9600", /* 1: 3 */
"11025", /* 2: 10 */
@@ -1635,7 +1636,7 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- static unsigned char xlate[16] = {
+ static const unsigned char xlate[16] = {
9, 6, 3, 1, 7, 4, 0, 12, 8, 5, 2, 11, 13, 255, 14, 10
};
unsigned char val;
@@ -1694,7 +1695,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Internal Clock",
.info = snd_vt1724_pro_internal_clock_info,
@@ -1733,7 +1734,7 @@ static int snd_vt1724_pro_rate_locking_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Locking",
.info = snd_vt1724_pro_rate_locking_info,
@@ -1772,7 +1773,7 @@ static int snd_vt1724_pro_rate_reset_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Reset",
.info = snd_vt1724_pro_rate_reset_info,
@@ -1816,7 +1817,7 @@ static int get_route_val(struct snd_ice1712 *ice, int shift)
{
unsigned long val;
unsigned char eitem;
- static unsigned char xlate[8] = {
+ static const unsigned char xlate[8] = {
0, 255, 1, 2, 255, 255, 3, 4,
};
@@ -1835,7 +1836,7 @@ static int put_route_val(struct snd_ice1712 *ice, unsigned int val, int shift)
{
unsigned int old_val, nval;
int change;
- static unsigned char xroute[8] = {
+ static const unsigned char xroute[8] = {
0, /* PCM */
2, /* PSDIN0 Left */
3, /* PSDIN0 Right */
@@ -1891,7 +1892,7 @@ static int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol,
digital_route_shift(idx));
}
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "H/W Playback Route",
.info = snd_vt1724_pro_route_info,
@@ -1899,7 +1900,7 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata =
.put = snd_vt1724_pro_route_analog_put,
};
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = snd_vt1724_pro_route_info,
@@ -1935,7 +1936,7 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = {
+static const struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Peak",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
@@ -1947,9 +1948,9 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = {
*
*/
-static struct snd_ice1712_card_info no_matched __devinitdata;
+static const struct snd_ice1712_card_info no_matched __devinitdata;
-static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
+static const struct snd_ice1712_card_info *card_tables[] __devinitdata = {
snd_vt1724_revo_cards,
snd_vt1724_amp_cards,
snd_vt1724_aureon_cards,
@@ -1958,6 +1959,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
snd_vt1724_prodigy192_cards,
snd_vt1724_juli_cards,
snd_vt1724_phase_cards,
+ snd_vt1724_wtm_cards,
NULL,
};
@@ -2007,7 +2009,7 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
{
const int dev = 0xa0; /* EEPROM device address */
unsigned int i, size;
- struct snd_ice1712_card_info **tbl, *c;
+ const struct snd_ice1712_card_info **tbl, *c;
if (! modelname || ! *modelname) {
ice->eeprom.subvendor = 0;
@@ -2253,7 +2255,7 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
ice->profi_port = pci_resource_start(pci, 1);
if (request_irq(pci->irq, snd_vt1724_interrupt,
- IRQF_DISABLED|IRQF_SHARED, "ICE1724", ice)) {
+ IRQF_SHARED, "ICE1724", ice)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_vt1724_free(ice);
return -EIO;
@@ -2306,7 +2308,7 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
struct snd_card *card;
struct snd_ice1712 *ice;
int pcm_dev = 0, err;
- struct snd_ice1712_card_info **tbl, *c;
+ const struct snd_ice1712_card_info **tbl, *c;
if (dev >= SNDRV_CARDS)
return -ENODEV;
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index 5176b41ea9d..d88172fa95d 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -125,7 +125,7 @@ static void juli_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
snd_akm4xxx_reset(ak, 0);
}
-static struct snd_akm4xxx akm_juli_dac __devinitdata = {
+static const struct snd_akm4xxx akm_juli_dac __devinitdata = {
.type = SND_AK4358,
.num_dacs = 2,
.ops = {
@@ -146,7 +146,7 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice)
*/
static int __devinit juli_init(struct snd_ice1712 *ice)
{
- static unsigned char ak4114_init_vals[] = {
+ static const unsigned char ak4114_init_vals[] = {
/* AK4117_REG_PWRDN */ AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
/* AK4114_REQ_FORMAT */ AK4114_DIF_I24I2S,
/* AK4114_REG_IO0 */ AK4114_TX1E,
@@ -154,7 +154,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
/* AK4114_REG_INT0_MASK */ 0,
/* AK4114_REG_INT1_MASK */ 0
};
- static unsigned char ak4114_init_txcsb[] = {
+ static const unsigned char ak4114_init_txcsb[] = {
0x41, 0x02, 0x2c, 0x00, 0x00
};
int err;
@@ -206,24 +206,24 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
* hence the driver needs to sets up it properly.
*/
-static unsigned char juli_eeprom[] __devinitdata = {
- 0x20, /* SYSCONF: clock 512, mpu401, 1xADC, 1xDACs */
- 0x80, /* ACLINK: I2S */
- 0xf8, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0x9f, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x7f, /* GPIO_DIR2 */
- 0x9f, /* GPIO_MASK */
- 0xff, /* GPIO_MASK1 */
- 0x7f, /* GPIO_MASK2 */
- 0x16, /* GPIO_STATE: internal clock, multiple 1x, 48kHz */
- 0x80, /* GPIO_STATE1: mute */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char juli_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x20, /* clock 512, mpu401, 1xADC, 1xDACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0x9f,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x7f,
+ [ICE_EEP2_GPIO_MASK] = 0x9f,
+ [ICE_EEP2_GPIO_MASK1] = 0xff,
+ [ICE_EEP2_GPIO_MASK2] = 0x7f,
+ [ICE_EEP2_GPIO_STATE] = 0x16, /* internal clock, multiple 1x, 48kHz */
+ [ICE_EEP2_GPIO_STATE1] = 0x80, /* mute */
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
/* entry point */
-struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_JULI,
.name = "ESI Juli@",
diff --git a/sound/pci/ice1712/juli.h b/sound/pci/ice1712/juli.h
index d9f8534fd92..1b9294f8bce 100644
--- a/sound/pci/ice1712/juli.h
+++ b/sound/pci/ice1712/juli.h
@@ -5,6 +5,6 @@
#define VT1724_SUBDEVICE_JULI 0x31305345 /* Juli@ */
-extern struct snd_ice1712_card_info snd_vt1724_juli_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_juli_cards[];
#endif /* __SOUND_JULI_H */
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c
index e08d73f4ff8..0751718f4d7 100644
--- a/sound/pci/ice1712/phase.c
+++ b/sound/pci/ice1712/phase.c
@@ -71,7 +71,7 @@
* Logarithmic volume values for WM8770
* Computed as 20 * Log10(255 / x)
*/
-static unsigned char wm_vol[256] = {
+static const unsigned char wm_vol[256] = {
127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
@@ -89,13 +89,13 @@ static unsigned char wm_vol[256] = {
#define WM_VOL_MAX (sizeof(wm_vol) - 1)
#define WM_VOL_MUTE 0x8000
-static struct snd_akm4xxx akm_phase22 __devinitdata = {
+static const struct snd_akm4xxx akm_phase22 __devinitdata = {
.type = SND_AK4524,
.num_dacs = 2,
.num_adcs = 2,
};
-static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_phase22_priv __devinitdata = {
.caddr = 2,
.cif = 1,
.data_mask = 1 << 4,
@@ -152,36 +152,36 @@ static int __devinit phase22_add_controls(struct snd_ice1712 *ice)
return 0;
}
-static unsigned char phase22_eeprom[] __devinitdata = {
- 0x00, /* SYSCONF: 1xADC, 1xDACs */
- 0x80, /* ACLINK: I2S */
- 0xf8, /* I2S: vol, 96k, 24bit*/
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xFF, /* GPIO_DIR */
- 0xFF, /* GPIO_DIR1 */
- 0xFF, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE: */
- 0x00, /* GPIO_STATE1: */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char phase22_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x00, /* 1xADC, 1xDACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0xff,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
-static unsigned char phase28_eeprom[] __devinitdata = {
- 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
- 0x80, /* ACLINK: I2S */
- 0xfc, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x5f, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char phase28_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x5f,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
/*
@@ -343,7 +343,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
static int __devinit phase28_init(struct snd_ice1712 *ice)
{
- static unsigned short wm_inits_phase28[] = {
+ static const unsigned short wm_inits_phase28[] = {
/* These come first to reduce init pop noise */
0x1b, 0x044, /* ADC Mux (AC'97 source) */
0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
@@ -382,7 +382,7 @@ static int __devinit phase28_init(struct snd_ice1712 *ice)
unsigned int tmp;
struct snd_akm4xxx *ak;
- unsigned short *p;
+ const unsigned short *p;
int i;
ice->num_total_dacs = 8;
@@ -697,10 +697,10 @@ static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ct
return 0;
}
-static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
-static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
-static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
+static const struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
@@ -815,7 +815,7 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
}
};
-static struct snd_kcontrol_new wm_controls[] __devinitdata = {
+static const struct snd_kcontrol_new wm_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Switch",
@@ -870,7 +870,7 @@ static int __devinit phase28_add_controls(struct snd_ice1712 *ice)
return 0;
}
-struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_PHASE22,
.name = "Terratec PHASE 22",
diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h
index 13e841b5548..ad379a99bf9 100644
--- a/sound/pci/ice1712/phase.h
+++ b/sound/pci/ice1712/phase.h
@@ -31,7 +31,7 @@
#define VT1724_SUBDEVICE_PHASE28 0x3b154911
/* entry point */
-extern struct snd_ice1712_card_info snd_vt1724_phase_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_phase_cards[];
/* PHASE28 GPIO bits */
#define PHASE28_SPI_MISO (1 << 21)
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 6c74c2d2e7f..9552497f076 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -434,7 +434,7 @@ static unsigned int spi_read(struct snd_ice1712 *ice, unsigned int dev, unsigned
*/
static int cs_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {
+ static const char * const texts[] = {
"Coax", /* RXP0 */
"Optical", /* RXP1 */
"CD", /* RXP2 */
@@ -565,13 +565,13 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
return changed;
}
-static DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1);
/*
* mixers
*/
-static struct snd_kcontrol_new pontis_controls[] __devinitdata = {
+static const struct snd_kcontrol_new pontis_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
@@ -741,7 +741,7 @@ static int __devinit pontis_add_controls(struct snd_ice1712 *ice)
*/
static int __devinit pontis_init(struct snd_ice1712 *ice)
{
- static unsigned short wm_inits[] = {
+ static const unsigned short wm_inits[] = {
/* These come first to reduce init pop noise */
WM_ADC_MUX, 0x00c0, /* ADC mute */
WM_DAC_MUTE, 0x0001, /* DAC softmute */
@@ -750,7 +750,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice)
WM_POWERDOWN, 0x0008, /* All power-up except HP */
WM_RESET, 0x0000, /* reset */
};
- static unsigned short wm_inits2[] = {
+ static const unsigned short wm_inits2[] = {
WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */
WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */
WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */
@@ -776,7 +776,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice)
WM_DAC_MUTE, 0x0000, /* DAC unmute */
WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */
};
- static unsigned char cs_inits[] = {
+ static const unsigned char cs_inits[] = {
0x04, 0x80, /* RUN, RXP0 */
0x05, 0x05, /* slave, 24bit */
0x01, 0x00,
@@ -826,24 +826,24 @@ static int __devinit pontis_init(struct snd_ice1712 *ice)
* hence the driver needs to sets up it properly.
*/
-static unsigned char pontis_eeprom[] __devinitdata = {
- 0x08, /* SYSCONF: clock 256, mpu401, spdif-in/ADC, 1DAC */
- 0x80, /* ACLINK: I2S */
- 0xf8, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0x07, /* GPIO_DIR */
- 0x00, /* GPIO_DIR1 */
- 0x00, /* GPIO_DIR2 (ignored) */
- 0x0f, /* GPIO_MASK (4-7 reserved for CS8416) */
- 0xff, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 (ignored) */
- 0x06, /* GPIO_STATE (0-low, 1-high, 2-high) */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 (ignored) */
+static const unsigned char pontis_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x08, /* clock 256, mpu401, spdif-in/ADC, 1DAC */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0x07,
+ [ICE_EEP2_GPIO_DIR1] = 0x00,
+ [ICE_EEP2_GPIO_DIR2] = 0x00, /* ignored */
+ [ICE_EEP2_GPIO_MASK] = 0x0f, /* 4-7 reserved for CS8416 */
+ [ICE_EEP2_GPIO_MASK1] = 0xff,
+ [ICE_EEP2_GPIO_MASK2] = 0x00, /* ignored */
+ [ICE_EEP2_GPIO_STATE] = 0x06, /* 0-low, 1-high, 2-high */
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00, /* ignored */
};
/* entry point */
-struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = {
{
.subvendor = VT1720_SUBDEVICE_PONTIS_MS300,
.name = "Pontis MS300",
diff --git a/sound/pci/ice1712/pontis.h b/sound/pci/ice1712/pontis.h
index d0d1378b935..1a418255c19 100644
--- a/sound/pci/ice1712/pontis.h
+++ b/sound/pci/ice1712/pontis.h
@@ -28,6 +28,6 @@
#define VT1720_SUBDEVICE_PONTIS_MS300 0x00020002 /* a dummy id for MS300 */
-extern struct snd_ice1712_card_info snd_vt1720_pontis_cards[];
+extern const struct snd_ice1712_card_info snd_vt1720_pontis_cards[];
#endif /* __SOUND_PONTIS_H */
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
index 41b2605daa3..31cc66eb9f8 100644
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -357,14 +357,14 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl
}
#endif
-static DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
/*
* mixers
*/
-static struct snd_kcontrol_new stac_controls[] __devinitdata = {
+static const struct snd_kcontrol_new stac_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
@@ -475,7 +475,7 @@ static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice)
*/
static int __devinit prodigy192_init(struct snd_ice1712 *ice)
{
- static unsigned short stac_inits_prodigy[] = {
+ static const unsigned short stac_inits_prodigy[] = {
STAC946X_RESET, 0,
/* STAC946X_MASTER_VOLUME, 0,
STAC946X_LF_VOLUME, 0,
@@ -486,7 +486,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice)
STAC946X_LFE_VOLUME, 0,*/
(unsigned short)-1
};
- unsigned short *p;
+ const unsigned short *p;
/* prodigy 192 */
ice->num_total_dacs = 6;
@@ -506,25 +506,25 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice)
* hence the driver needs to sets up it properly.
*/
-static unsigned char prodigy71_eeprom[] __devinitdata = {
- 0x2b, /* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */
- 0x80, /* ACLINK: I2S */
- 0xf8, /* I2S: vol, 96k, 24bit, 192k */
- 0xc3, /* SPDIF: out-en, out-int, spdif-in */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0xbf, /* GPIO_DIR2 */
- 0x00, /* GPIO_MASK */
- 0x00, /* GPIO_MASK1 */
- 0x00, /* GPIO_MASK2 */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* GPIO_STATE2 */
+static const unsigned char prodigy71_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC, 4DACs */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0xbf,
+ [ICE_EEP2_GPIO_MASK] = 0x00,
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0x00,
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00,
};
/* entry point */
-struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_PRODIGY192VE,
.name = "Audiotrak Prodigy 192",
diff --git a/sound/pci/ice1712/prodigy192.h b/sound/pci/ice1712/prodigy192.h
index 94c824e24e0..2fa2e62b9e0 100644
--- a/sound/pci/ice1712/prodigy192.h
+++ b/sound/pci/ice1712/prodigy192.h
@@ -6,6 +6,6 @@
#define VT1724_SUBDEVICE_PRODIGY192VE 0x34495345 /* PRODIGY 192 VE */
-extern struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[];
#endif /* __SOUND_PRODIGY192_H */
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index bf98ea34feb..025a7e8497c 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -84,38 +84,142 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
}
/*
+ * I2C access to the PT2258 volume controller on GPIO 6/7 (Revolution 5.1)
+ */
+
+static void revo_i2c_start(struct snd_i2c_bus *bus)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ snd_ice1712_save_gpio_status(ice);
+}
+
+static void revo_i2c_stop(struct snd_i2c_bus *bus)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ snd_ice1712_restore_gpio_status(ice);
+}
+
+static void revo_i2c_direction(struct snd_i2c_bus *bus, int clock, int data)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ unsigned int mask, val;
+
+ val = 0;
+ if (clock)
+ val |= VT1724_REVO_I2C_CLOCK; /* write SCL */
+ if (data)
+ val |= VT1724_REVO_I2C_DATA; /* write SDA */
+ mask = VT1724_REVO_I2C_CLOCK | VT1724_REVO_I2C_DATA;
+ ice->gpio.direction &= ~mask;
+ ice->gpio.direction |= val;
+ snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+ snd_ice1712_gpio_set_mask(ice, ~mask);
+}
+
+static void revo_i2c_setlines(struct snd_i2c_bus *bus, int clk, int data)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ unsigned int val = 0;
+
+ if (clk)
+ val |= VT1724_REVO_I2C_CLOCK;
+ if (data)
+ val |= VT1724_REVO_I2C_DATA;
+ snd_ice1712_gpio_write_bits(ice,
+ VT1724_REVO_I2C_DATA |
+ VT1724_REVO_I2C_CLOCK, val);
+ udelay(5);
+}
+
+static int revo_i2c_getdata(struct snd_i2c_bus *bus, int ack)
+{
+ struct snd_ice1712 *ice = bus->private_data;
+ int bit;
+
+ if (ack)
+ udelay(5);
+ bit = snd_ice1712_gpio_read_bits(ice, VT1724_REVO_I2C_DATA) ? 1 : 0;
+ return bit;
+}
+
+static struct snd_i2c_bit_ops revo51_bit_ops = {
+ .start = revo_i2c_start,
+ .stop = revo_i2c_stop,
+ .direction = revo_i2c_direction,
+ .setlines = revo_i2c_setlines,
+ .getdata = revo_i2c_getdata,
+};
+
+static int revo51_i2c_init(struct snd_ice1712 *ice,
+ struct snd_pt2258 *pt)
+{
+ int err;
+
+ /* create the I2C bus */
+ err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c);
+ if (err < 0)
+ return err;
+
+ ice->i2c->private_data = ice;
+ ice->i2c->hw_ops.bit = &revo51_bit_ops;
+
+ /* create the I2C device */
+ err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40,
+ &ice->spec.revo51.dev);
+ if (err < 0)
+ return err;
+
+ pt->card = ice->card;
+ pt->i2c_bus = ice->i2c;
+ pt->i2c_dev = ice->spec.revo51.dev;
+ ice->spec.revo51.pt2258 = pt;
+
+ snd_pt2258_reset(pt);
+
+ return 0;
+}
+
+/*
* initialize the chips on M-Audio Revolution cards
*/
#define AK_DAC(xname,xch) { .name = xname, .num_channels = xch }
-static struct snd_akm4xxx_dac_channel revo71_front[] = {
+static const struct snd_akm4xxx_dac_channel revo71_front[] = {
AK_DAC("PCM Playback Volume", 2)
};
-static struct snd_akm4xxx_dac_channel revo71_surround[] = {
+static const struct snd_akm4xxx_dac_channel revo71_surround[] = {
AK_DAC("PCM Center Playback Volume", 1),
AK_DAC("PCM LFE Playback Volume", 1),
AK_DAC("PCM Side Playback Volume", 2),
AK_DAC("PCM Rear Playback Volume", 2),
};
-static struct snd_akm4xxx_dac_channel revo51_dac[] = {
+static const struct snd_akm4xxx_dac_channel revo51_dac[] = {
AK_DAC("PCM Playback Volume", 2),
AK_DAC("PCM Center Playback Volume", 1),
AK_DAC("PCM LFE Playback Volume", 1),
AK_DAC("PCM Rear Playback Volume", 2),
};
-static struct snd_akm4xxx_adc_channel revo51_adc[] = {
+static const char *revo51_adc_input_names[] = {
+ "Mic",
+ "Line",
+ "CD",
+ NULL
+};
+
+static const struct snd_akm4xxx_adc_channel revo51_adc[] = {
{
.name = "PCM Capture Volume",
.switch_name = "PCM Capture Switch",
- .num_channels = 2
+ .num_channels = 2,
+ .input_names = revo51_adc_input_names
},
};
-static struct snd_akm4xxx akm_revo_front __devinitdata = {
+static const struct snd_akm4xxx akm_revo_front __devinitdata = {
.type = SND_AK4381,
.num_dacs = 2,
.ops = {
@@ -124,7 +228,7 @@ static struct snd_akm4xxx akm_revo_front __devinitdata = {
.dac_info = revo71_front,
};
-static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
.caddr = 1,
.cif = 0,
.data_mask = VT1724_REVO_CDOUT,
@@ -136,7 +240,7 @@ static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_revo_surround __devinitdata = {
+static const struct snd_akm4xxx akm_revo_surround __devinitdata = {
.type = SND_AK4355,
.idx_offset = 1,
.num_dacs = 6,
@@ -146,7 +250,7 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = {
.dac_info = revo71_surround,
};
-static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
.caddr = 3,
.cif = 0,
.data_mask = VT1724_REVO_CDOUT,
@@ -158,7 +262,7 @@ static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = {
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_revo51 __devinitdata = {
+static const struct snd_akm4xxx akm_revo51 __devinitdata = {
.type = SND_AK4358,
.num_dacs = 6,
.ops = {
@@ -167,36 +271,213 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = {
.dac_info = revo51_dac,
};
-static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo51_priv __devinitdata = {
.caddr = 2,
.cif = 0,
.data_mask = VT1724_REVO_CDOUT,
.clk_mask = VT1724_REVO_CCLK,
- .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
- .cs_addr = VT1724_REVO_CS1 | VT1724_REVO_CS2,
- .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+ .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+ .cs_addr = VT1724_REVO_CS1,
+ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
.add_flags = VT1724_REVO_CCLK, /* high at init */
.mask_flags = 0,
};
-static struct snd_akm4xxx akm_revo51_adc __devinitdata = {
+static const struct snd_akm4xxx akm_revo51_adc __devinitdata = {
.type = SND_AK5365,
.num_adcs = 2,
.adc_info = revo51_adc,
};
-static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = {
+static const struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = {
.caddr = 2,
.cif = 0,
.data_mask = VT1724_REVO_CDOUT,
.clk_mask = VT1724_REVO_CCLK,
- .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
- .cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2,
- .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
+ .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+ .cs_addr = VT1724_REVO_CS0,
+ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
+ .add_flags = VT1724_REVO_CCLK, /* high at init */
+ .mask_flags = 0,
+};
+
+static struct snd_pt2258 ptc_revo51_volume;
+
+/* AK4358 for AP192 DAC, AK5385A for ADC */
+static void ap192_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
+{
+ struct snd_ice1712 *ice = ak->private_data[0];
+
+ revo_set_rate_val(ak, rate);
+
+#if 1 /* FIXME: do we need this procedure? */
+ /* reset DFS pin of AK5385A for ADC, too */
+ /* DFS0 (pin 18) -- GPIO10 pin 77 */
+ snd_ice1712_save_gpio_status(ice);
+ snd_ice1712_gpio_write_bits(ice, 1 << 10,
+ rate > 48000 ? (1 << 10) : 0);
+ snd_ice1712_restore_gpio_status(ice);
+#endif
+}
+
+static const struct snd_akm4xxx_dac_channel ap192_dac[] = {
+ AK_DAC("PCM Playback Volume", 2)
+};
+
+static const struct snd_akm4xxx akm_ap192 __devinitdata = {
+ .type = SND_AK4358,
+ .num_dacs = 2,
+ .ops = {
+ .set_rate_val = ap192_set_rate_val
+ },
+ .dac_info = ap192_dac,
+};
+
+static const struct snd_ak4xxx_private akm_ap192_priv __devinitdata = {
+ .caddr = 2,
+ .cif = 0,
+ .data_mask = VT1724_REVO_CDOUT,
+ .clk_mask = VT1724_REVO_CCLK,
+ .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS3,
+ .cs_addr = VT1724_REVO_CS3,
+ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS3,
.add_flags = VT1724_REVO_CCLK, /* high at init */
.mask_flags = 0,
};
+#if 0
+/* FIXME: ak4114 makes the sound much lower due to some confliction,
+ * so let's disable it right now...
+ */
+#define BUILD_AK4114_AP192
+#endif
+
+#ifdef BUILD_AK4114_AP192
+/* AK4114 support on Audiophile 192 */
+/* CDTO (pin 32) -- GPIO2 pin 52
+ * CDTI (pin 33) -- GPIO3 pin 53 (shared with AK4358)
+ * CCLK (pin 34) -- GPIO1 pin 51 (shared with AK4358)
+ * CSN (pin 35) -- GPIO7 pin 59
+ */
+#define AK4114_ADDR 0x00
+
+static void write_data(struct snd_ice1712 *ice, unsigned int gpio,
+ unsigned int data, int idx)
+{
+ for (; idx >= 0; idx--) {
+ /* drop clock */
+ gpio &= ~VT1724_REVO_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ /* set data */
+ if (data & (1 << idx))
+ gpio |= VT1724_REVO_CDOUT;
+ else
+ gpio &= ~VT1724_REVO_CDOUT;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ /* raise clock */
+ gpio |= VT1724_REVO_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ }
+}
+
+static unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio,
+ int idx)
+{
+ unsigned char data = 0;
+
+ for (; idx >= 0; idx--) {
+ /* drop clock */
+ gpio &= ~VT1724_REVO_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ /* read data */
+ if (snd_ice1712_gpio_read(ice) & VT1724_REVO_CDIN)
+ data |= (1 << idx);
+ udelay(1);
+ /* raise clock */
+ gpio |= VT1724_REVO_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ }
+ return data;
+}
+
+static unsigned char ap192_4wire_start(struct snd_ice1712 *ice)
+{
+ unsigned int tmp;
+
+ snd_ice1712_save_gpio_status(ice);
+ tmp = snd_ice1712_gpio_read(ice);
+ tmp |= VT1724_REVO_CCLK; /* high at init */
+ tmp |= VT1724_REVO_CS0;
+ tmp &= ~VT1724_REVO_CS3;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ return tmp;
+}
+
+static void ap192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp)
+{
+ tmp |= VT1724_REVO_CS3;
+ tmp |= VT1724_REVO_CS0;
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ snd_ice1712_restore_gpio_status(ice);
+}
+
+static void ap192_ak4114_write(void *private_data, unsigned char addr,
+ unsigned char data)
+{
+ struct snd_ice1712 *ice = private_data;
+ unsigned int tmp, addrdata;
+
+ tmp = ap192_4wire_start(ice);
+ addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f);
+ addrdata = (addrdata << 8) | data;
+ write_data(ice, tmp, addrdata, 15);
+ ap192_4wire_finish(ice, tmp);
+}
+
+static unsigned char ap192_ak4114_read(void *private_data, unsigned char addr)
+{
+ struct snd_ice1712 *ice = private_data;
+ unsigned int tmp;
+ unsigned char data;
+
+ tmp = ap192_4wire_start(ice);
+ write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7);
+ data = read_data(ice, tmp, 7);
+ ap192_4wire_finish(ice, tmp);
+ return data;
+}
+
+static int ap192_ak4114_init(struct snd_ice1712 *ice)
+{
+ static const unsigned char ak4114_init_vals[] = {
+ AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
+ AK4114_DIF_I24I2S,
+ AK4114_TX1E,
+ AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1),
+ 0,
+ 0
+ };
+ static const unsigned char ak4114_init_txcsb[] = {
+ 0x41, 0x02, 0x2c, 0x00, 0x00
+ };
+ struct ak4114 *ak;
+ int err;
+
+ return snd_ak4114_create(ice->card,
+ ap192_ak4114_read,
+ ap192_ak4114_write,
+ ak4114_init_vals, ak4114_init_txcsb,
+ ice, &ak);
+}
+#endif /* BUILD_AK4114_AP192 */
+
static int __devinit revo_init(struct snd_ice1712 *ice)
{
struct snd_akm4xxx *ak;
@@ -213,6 +494,10 @@ static int __devinit revo_init(struct snd_ice1712 *ice)
ice->num_total_dacs = 6;
ice->num_total_adcs = 2;
break;
+ case VT1724_SUBDEVICE_AUDIOPHILE192:
+ ice->num_total_dacs = 2;
+ ice->num_total_adcs = 2;
+ break;
default:
snd_BUG();
return -EINVAL;
@@ -235,14 +520,28 @@ static int __devinit revo_init(struct snd_ice1712 *ice)
break;
case VT1724_SUBDEVICE_REVOLUTION51:
ice->akm_codecs = 2;
- if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0)
+ err = snd_ice1712_akm4xxx_init(ak, &akm_revo51,
+ &akm_revo51_priv, ice);
+ if (err < 0)
return err;
- err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo51_adc,
+ err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo51_adc,
&akm_revo51_adc_priv, ice);
if (err < 0)
return err;
- /* unmute all codecs - needed! */
- snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE);
+ err = revo51_i2c_init(ice, &ptc_revo51_volume);
+ if (err < 0)
+ return err;
+ /* unmute all codecs */
+ snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
+ VT1724_REVO_MUTE);
+ break;
+ case VT1724_SUBDEVICE_AUDIOPHILE192:
+ ice->akm_codecs = 1;
+ err = snd_ice1712_akm4xxx_init(ak, &akm_ap192, &akm_ap192_priv,
+ ice);
+ if (err < 0)
+ return err;
+
break;
}
@@ -256,16 +555,34 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice)
switch (ice->eeprom.subvendor) {
case VT1724_SUBDEVICE_REVOLUTION71:
+ err = snd_ice1712_akm4xxx_build_controls(ice);
+ if (err < 0)
+ return err;
+ break;
case VT1724_SUBDEVICE_REVOLUTION51:
err = snd_ice1712_akm4xxx_build_controls(ice);
if (err < 0)
return err;
+ err = snd_pt2258_build_controls(ice->spec.revo51.pt2258);
+ if (err < 0)
+ return err;
+ break;
+ case VT1724_SUBDEVICE_AUDIOPHILE192:
+ err = snd_ice1712_akm4xxx_build_controls(ice);
+ if (err < 0)
+ return err;
+#ifdef BUILD_AK4114_AP192
+ err = ap192_ak4114_init(ice);
+ if (err < 0)
+ return err;
+#endif
+ break;
}
return 0;
}
/* entry point */
-struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = {
{
.subvendor = VT1724_SUBDEVICE_REVOLUTION71,
.name = "M Audio Revolution-7.1",
@@ -280,5 +597,12 @@ struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = {
.chip_init = revo_init,
.build_controls = revo_add_controls,
},
+ {
+ .subvendor = VT1724_SUBDEVICE_AUDIOPHILE192,
+ .name = "M Audio Audiophile192",
+ .model = "ap192",
+ .chip_init = revo_init,
+ .build_controls = revo_add_controls,
+ },
{ } /* terminator */
};
diff --git a/sound/pci/ice1712/revo.h b/sound/pci/ice1712/revo.h
index efbb86ec328..2a24488fad8 100644
--- a/sound/pci/ice1712/revo.h
+++ b/sound/pci/ice1712/revo.h
@@ -26,13 +26,15 @@
#define REVO_DEVICE_DESC \
"{MidiMan M Audio,Revolution 7.1},"\
- "{MidiMan M Audio,Revolution 5.1},"
+ "{MidiMan M Audio,Revolution 5.1},"\
+ "{MidiMan M Audio,Audiophile 192},"
#define VT1724_SUBDEVICE_REVOLUTION71 0x12143036
#define VT1724_SUBDEVICE_REVOLUTION51 0x12143136
+#define VT1724_SUBDEVICE_AUDIOPHILE192 0x12143236
/* entry point */
-extern struct snd_ice1712_card_info snd_vt1724_revo_cards[];
+extern const struct snd_ice1712_card_info snd_vt1724_revo_cards[];
/*
@@ -42,9 +44,12 @@ extern struct snd_ice1712_card_info snd_vt1724_revo_cards[];
#define VT1724_REVO_CCLK 0x02
#define VT1724_REVO_CDIN 0x04 /* not used */
#define VT1724_REVO_CDOUT 0x08
-#define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for Rev. 5.1 */
+#define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for (revo51) */
#define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */
-#define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */
+#define VT1724_REVO_CS2 0x40 /* surround AKM4355 CS (revo71) */
+#define VT1724_REVO_I2C_DATA 0x40 /* I2C: PT 2258 SDA (on revo51) */
+#define VT1724_REVO_I2C_CLOCK 0x80 /* I2C: PT 2258 SCL (on revo51) */
+#define VT1724_REVO_CS3 0x80 /* AK4114 for AP192 */
#define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */
#endif /* __SOUND_REVO_H */
diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c
index 7ca263c1309..72b060d63c2 100644
--- a/sound/pci/ice1712/vt1720_mobo.c
+++ b/sound/pci/ice1712/vt1720_mobo.c
@@ -30,6 +30,7 @@
#include <sound/core.h>
#include "ice1712.h"
+#include "envy24ht.h"
#include "vt1720_mobo.h"
@@ -55,41 +56,41 @@ static int __devinit k8x800_add_controls(struct snd_ice1712 *ice)
/* EEPROM image */
-static unsigned char k8x800_eeprom[] __devinitdata = {
- 0x01, /* SYSCONF: clock 256, 1ADC, 2DACs */
- 0x02, /* ACLINK: ACLINK, packed */
- 0x00, /* I2S: - */
- 0x00, /* SPDIF: - */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x00, /* - */
- 0xff, /* GPIO_MASK */
- 0xff, /* GPIO_MASK1 */
- 0x00, /* - */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* - */
+static const unsigned char k8x800_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */
+ [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */
+ [ICE_EEP2_I2S] = 0x00, /* - */
+ [ICE_EEP2_SPDIF] = 0x00, /* - */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x00, /* - */
+ [ICE_EEP2_GPIO_MASK] = 0xff,
+ [ICE_EEP2_GPIO_MASK1] = 0xff,
+ [ICE_EEP2_GPIO_MASK2] = 0x00, /* - */
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00, /* - */
};
-static unsigned char sn25p_eeprom[] __devinitdata = {
- 0x01, /* SYSCONF: clock 256, 1ADC, 2DACs */
- 0x02, /* ACLINK: ACLINK, packed */
- 0x00, /* I2S: - */
- 0x41, /* SPDIF: - */
- 0xff, /* GPIO_DIR */
- 0xff, /* GPIO_DIR1 */
- 0x00, /* - */
- 0xff, /* GPIO_MASK */
- 0xff, /* GPIO_MASK1 */
- 0x00, /* - */
- 0x00, /* GPIO_STATE */
- 0x00, /* GPIO_STATE1 */
- 0x00, /* - */
+static const unsigned char sn25p_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */
+ [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */
+ [ICE_EEP2_I2S] = 0x00, /* - */
+ [ICE_EEP2_SPDIF] = 0x41, /* - */
+ [ICE_EEP2_GPIO_DIR] = 0xff,
+ [ICE_EEP2_GPIO_DIR1] = 0xff,
+ [ICE_EEP2_GPIO_DIR2] = 0x00, /* - */
+ [ICE_EEP2_GPIO_MASK] = 0xff,
+ [ICE_EEP2_GPIO_MASK1] = 0xff,
+ [ICE_EEP2_GPIO_MASK2] = 0x00, /* - */
+ [ICE_EEP2_GPIO_STATE] = 0x00,
+ [ICE_EEP2_GPIO_STATE1] = 0x00,
+ [ICE_EEP2_GPIO_STATE2] = 0x00, /* - */
};
/* entry point */
-struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = {
+const struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = {
{
.subvendor = VT1720_SUBDEVICE_K8X800,
.name = "Albatron K8X800 Pro II",
diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h
index 0b1b0ee1bea..70af3ad64a5 100644
--- a/sound/pci/ice1712/vt1720_mobo.h
+++ b/sound/pci/ice1712/vt1720_mobo.h
@@ -36,6 +36,6 @@
#define VT1720_SUBDEVICE_9CJS 0x0f272327
#define VT1720_SUBDEVICE_SN25P 0x97123650
-extern struct snd_ice1712_card_info snd_vt1720_mobo_cards[];
+extern const struct snd_ice1712_card_info snd_vt1720_mobo_cards[];
#endif /* __SOUND_VT1720_MOBO_H */
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c
new file mode 100644
index 00000000000..4a706b16a0b
--- /dev/null
+++ b/sound/pci/ice1712/wtm.c
@@ -0,0 +1,542 @@
+/*
+ * ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ * Lowlevel functions for Ego Sys Waveterminal 192M
+ *
+ * Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com>
+ * Some functions are taken from the Prodigy192 driver
+ * source
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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 <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "wtm.h"
+#include "stac946x.h"
+
+
+/*
+ * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus
+ */
+static inline void stac9460_put(struct snd_ice1712 *ice, int reg,
+ unsigned char val)
+{
+ snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val);
+}
+
+static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg)
+{
+ return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg);
+}
+
+/*
+ * 2*ADC 2*DAC no2 ringbuffer r/w on i2c bus
+ */
+static inline void stac9460_2_put(struct snd_ice1712 *ice, int reg,
+ unsigned char val)
+{
+ snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val);
+}
+
+static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg)
+{
+ return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg);
+}
+
+
+/*
+ * DAC mute control
+ */
+static int stac9460_dac_mute_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ return 0;
+}
+
+static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char val;
+ int idx, id;
+
+ if (kcontrol->private_value) {
+ idx = STAC946X_MASTER_VOLUME;
+ id = 0;
+ } else {
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ idx = id + STAC946X_LF_VOLUME;
+ }
+ if (id < 6)
+ val = stac9460_get(ice, idx);
+ else
+ val = stac9460_2_get(ice,idx - 6);
+ ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
+ return 0;
+}
+
+static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char new, old;
+ int id, idx;
+ int change;
+
+ if (kcontrol->private_value) {
+ idx = STAC946X_MASTER_VOLUME;
+ old = stac9460_get(ice, idx);
+ new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
+ (old & ~0x80);
+ change = (new != old);
+ if (change) {
+ stac9460_put(ice, idx, new);
+ stac9460_2_put(ice, idx, new);
+ }
+ } else {
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ idx = id + STAC946X_LF_VOLUME;
+ if (id < 6)
+ old = stac9460_get(ice, idx);
+ else
+ old = stac9460_2_get(ice, idx - 6);
+ new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
+ (old & ~0x80);
+ change = (new != old);
+ if (change) {
+ if (id < 6)
+ stac9460_put(ice, idx, new);
+ else
+ stac9460_2_put(ice, idx - 6, new);
+ }
+ }
+ return change;
+}
+
+/*
+ * DAC volume attenuation mixer control
+ */
+static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0; /* mute */
+ uinfo->value.integer.max = 0x7f; /* 0dB */
+ return 0;
+}
+
+static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ int idx, id;
+ unsigned char vol;
+
+ if (kcontrol->private_value) {
+ idx = STAC946X_MASTER_VOLUME;
+ id = 0;
+ } else {
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ idx = id + STAC946X_LF_VOLUME;
+ }
+ if (id < 6)
+ vol = stac9460_get(ice, idx) & 0x7f;
+ else
+ vol = stac9460_2_get(ice, idx - 6) & 0x7f;
+ ucontrol->value.integer.value[0] = 0x7f - vol;
+ return 0;
+}
+
+static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ int idx, id;
+ unsigned char tmp, ovol, nvol;
+ int change;
+
+ if (kcontrol->private_value) {
+ idx = STAC946X_MASTER_VOLUME;
+ nvol = ucontrol->value.integer.value[0];
+ tmp = stac9460_get(ice, idx);
+ ovol = 0x7f - (tmp & 0x7f);
+ change = (ovol != nvol);
+ if (change) {
+ stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
+ stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
+ }
+ } else {
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ idx = id + STAC946X_LF_VOLUME;
+ nvol = ucontrol->value.integer.value[0];
+ if (id < 6)
+ tmp = stac9460_get(ice, idx);
+ else
+ tmp = stac9460_2_get(ice, idx - 6);
+ ovol = 0x7f - (tmp & 0x7f);
+ change = (ovol != nvol);
+ if (change) {
+ if (id < 6)
+ stac9460_put(ice, idx, (0x7f - nvol) |
+ (tmp & 0x80));
+ else
+ stac9460_2_put(ice, idx-6, (0x7f - nvol) |
+ (tmp & 0x80));
+ }
+ }
+ return change;
+}
+
+/*
+ * ADC mute control
+ */
+static int stac9460_adc_mute_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char val;
+ int i, id;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0) {
+ for (i = 0; i < 2; ++i) {
+ val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i);
+ ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
+ }
+ } else {
+ for (i = 0; i < 2; ++i) {
+ val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i);
+ ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
+ }
+ }
+ return 0;
+}
+
+static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char new, old;
+ int i, reg, id;
+ int change;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0) {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ old = stac9460_get(ice, reg);
+ new = (~ucontrol->value.integer.value[i]<<7&0x80) |
+ (old&~0x80);
+ change = (new != old);
+ if (change)
+ stac9460_put(ice, reg, new);
+ }
+ } else {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ old = stac9460_2_get(ice, reg);
+ new = (~ucontrol->value.integer.value[i]<<7&0x80) |
+ (old&~0x80);
+ change = (new != old);
+ if (change)
+ stac9460_2_put(ice, reg, new);
+ }
+ }
+ return change;
+}
+
+/*
+ *ADC gain mixer control
+ */
+static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0; /* 0dB */
+ uinfo->value.integer.max = 0x0f; /* 22.5dB */
+ return 0;
+}
+
+static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ int i, reg, id;
+ unsigned char vol;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0) {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ vol = stac9460_get(ice, reg) & 0x0f;
+ ucontrol->value.integer.value[i] = 0x0f - vol;
+ }
+ } else {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ vol = stac9460_2_get(ice, reg) & 0x0f;
+ ucontrol->value.integer.value[i] = 0x0f - vol;
+ }
+ }
+ return 0;
+}
+
+static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ int i, reg, id;
+ unsigned char ovol, nvol;
+ int change;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0) {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ nvol = ucontrol->value.integer.value[i];
+ ovol = 0x0f - stac9460_get(ice, reg);
+ change = ((ovol & 0x0f) != nvol);
+ if (change)
+ stac9460_put(ice, reg, (0x0f - nvol) |
+ (ovol & ~0x0f));
+ }
+ } else {
+ for (i = 0; i < 2; ++i) {
+ reg = STAC946X_MIC_L_VOLUME + i;
+ nvol = ucontrol->value.integer.value[i];
+ ovol = 0x0f - stac9460_2_get(ice, reg);
+ change = ((ovol & 0x0f) != nvol);
+ if (change)
+ stac9460_2_put(ice, reg, (0x0f - nvol) |
+ (ovol & ~0x0f));
+ }
+ }
+ return change;
+}
+
+/*
+ * MIC / LINE switch fonction
+ */
+
+static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char val;
+ int id;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0)
+ val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
+ else
+ val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
+ ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
+ return 0;
+}
+
+static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char new, old;
+ int change, id;
+
+ id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (id == 0)
+ old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
+ else
+ old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
+ new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80);
+ change = (new != old);
+ if (change) {
+ if (id == 0)
+ stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
+ else
+ stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new);
+ }
+ return change;
+}
+
+/*
+ * Control tabs
+ */
+static const struct snd_kcontrol_new stac9640_controls[] __devinitdata = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = stac9460_dac_mute_info,
+ .get = stac9460_dac_mute_get,
+ .put = stac9460_dac_mute_put,
+ .private_value = 1
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Volume",
+ .info = stac9460_dac_vol_info,
+ .get = stac9460_dac_vol_get,
+ .put = stac9460_dac_vol_put,
+ .private_value = 1,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "MIC/Line switch",
+ .count = 2,
+ .info = stac9460_mic_sw_info,
+ .get = stac9460_mic_sw_get,
+ .put = stac9460_mic_sw_put,
+
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "DAC Switch",
+ .count = 8,
+ .info = stac9460_dac_mute_info,
+ .get = stac9460_dac_mute_get,
+ .put = stac9460_dac_mute_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "DAC Volume",
+ .count = 8,
+ .info = stac9460_dac_vol_info,
+ .get = stac9460_dac_vol_get,
+ .put = stac9460_dac_vol_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "ADC Switch",
+ .count = 2,
+ .info = stac9460_adc_mute_info,
+ .get = stac9460_adc_mute_get,
+ .put = stac9460_adc_mute_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "ADC Volume",
+ .count = 2,
+ .info = stac9460_adc_vol_info,
+ .get = stac9460_adc_vol_get,
+ .put = stac9460_adc_vol_put,
+
+ }
+};
+
+
+
+/*INIT*/
+static int __devinit wtm_add_controls(struct snd_ice1712 *ice)
+{
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) {
+ err = snd_ctl_add(ice->card,
+ snd_ctl_new1(&stac9640_controls[i], ice));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int __devinit wtm_init(struct snd_ice1712 *ice)
+{
+ static unsigned short stac_inits_prodigy[] = {
+ STAC946X_RESET, 0,
+ (unsigned short)-1
+ };
+ unsigned short *p;
+
+ /*WTM 192M*/
+ ice->num_total_dacs = 8;
+ ice->num_total_adcs = 4;
+ ice->force_rdma1 = 1;
+
+ /*initialize codec*/
+ p = stac_inits_prodigy;
+ for (; *p != (unsigned short)-1; p += 2) {
+ stac9460_put(ice, p[0], p[1]);
+ stac9460_2_put(ice, p[0], p[1]);
+ }
+ return 0;
+}
+
+
+static unsigned char wtm_eeprom[] __devinitdata = {
+ 0x47, /*SYSCONF: clock 192KHz, 4ADC, 8DAC */
+ 0x80, /* ACLINK : I2S */
+ 0xf8, /* I2S: vol; 96k, 24bit, 192k */
+ 0xc1 /*SPDIF: out-en, spidf ext out*/,
+ 0x9f, /* GPIO_DIR */
+ 0xff, /* GPIO_DIR1 */
+ 0x7f, /* GPIO_DIR2 */
+ 0x9f, /* GPIO_MASK */
+ 0xff, /* GPIO_MASK1 */
+ 0x7f, /* GPIO_MASK2 */
+ 0x16, /* GPIO_STATE */
+ 0x80, /* GPIO_STATE1 */
+ 0x00, /* GPIO_STATE2 */
+};
+
+
+/*entry point*/
+struct snd_ice1712_card_info snd_vt1724_wtm_cards[] __devinitdata = {
+ {
+ .subvendor = VT1724_SUBDEVICE_WTM,
+ .name = "ESI Waveterminal 192M",
+ .model = "WT192M",
+ .chip_init = wtm_init,
+ .build_controls = wtm_add_controls,
+ .eeprom_size = sizeof(wtm_eeprom),
+ .eeprom_data = wtm_eeprom,
+ },
+ {} /*terminator*/
+};
diff --git a/sound/pci/ice1712/wtm.h b/sound/pci/ice1712/wtm.h
new file mode 100644
index 00000000000..03a394e442f
--- /dev/null
+++ b/sound/pci/ice1712/wtm.h
@@ -0,0 +1,20 @@
+#ifndef __SOUND_WTM_H
+#define __SOUND_WTM_H
+
+/* ID */
+#define WTM_DEVICE_DESC "{EGO SYS INC,WaveTerminal 192M},"
+#define VT1724_SUBDEVICE_WTM 0x36495345 /* WT192M ver1.0 */
+
+/*
+ *chip addresses on I2C bus
+ */
+
+#define AK4114_ADDR 0x20 /*S/PDIF receiver*/
+#define STAC9460_I2C_ADDR 0x54 /* ADC*2 | DAC*6 */
+#define STAC9460_2_I2C_ADDR 0x56 /* ADC|DAC *2 */
+
+
+extern struct snd_ice1712_card_info snd_vt1724_wtm_cards[];
+
+#endif /* __SOUND_WTM_H */
+
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 9c1bce7afa8..a289abfc717 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -71,6 +71,7 @@ static char *ac97_quirk;
static int buggy_semaphore;
static int buggy_irq = -1; /* auto-check */
static int xbox;
+static int spdif_aclink = -1;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard.");
@@ -86,6 +87,8 @@ module_param(buggy_irq, bool, 0444);
MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards.");
module_param(xbox, bool, 0444);
MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection.");
+module_param(spdif_aclink, int, 0444);
+MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
/* just for backward compatibility */
static int enable;
@@ -368,12 +371,8 @@ struct intel8x0 {
int irq;
- unsigned int mmio;
- unsigned long addr;
- void __iomem *remap_addr;
- unsigned int bm_mmio;
- unsigned long bmaddr;
- void __iomem *remap_bmaddr;
+ void __iomem *addr;
+ void __iomem *bmaddr;
struct pci_dev *pci;
struct snd_card *card;
@@ -446,72 +445,48 @@ MODULE_DEVICE_TABLE(pci, snd_intel8x0_ids);
* Lowlevel I/O - busmaster
*/
-static u8 igetbyte(struct intel8x0 *chip, u32 offset)
+static inline u8 igetbyte(struct intel8x0 *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readb(chip->remap_bmaddr + offset);
- else
- return inb(chip->bmaddr + offset);
+ return ioread8(chip->bmaddr + offset);
}
-static u16 igetword(struct intel8x0 *chip, u32 offset)
+static inline u16 igetword(struct intel8x0 *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readw(chip->remap_bmaddr + offset);
- else
- return inw(chip->bmaddr + offset);
+ return ioread16(chip->bmaddr + offset);
}
-static u32 igetdword(struct intel8x0 *chip, u32 offset)
+static inline u32 igetdword(struct intel8x0 *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readl(chip->remap_bmaddr + offset);
- else
- return inl(chip->bmaddr + offset);
+ return ioread32(chip->bmaddr + offset);
}
-static void iputbyte(struct intel8x0 *chip, u32 offset, u8 val)
+static inline void iputbyte(struct intel8x0 *chip, u32 offset, u8 val)
{
- if (chip->bm_mmio)
- writeb(val, chip->remap_bmaddr + offset);
- else
- outb(val, chip->bmaddr + offset);
+ iowrite8(val, chip->bmaddr + offset);
}
-static void iputword(struct intel8x0 *chip, u32 offset, u16 val)
+static inline void iputword(struct intel8x0 *chip, u32 offset, u16 val)
{
- if (chip->bm_mmio)
- writew(val, chip->remap_bmaddr + offset);
- else
- outw(val, chip->bmaddr + offset);
+ iowrite16(val, chip->bmaddr + offset);
}
-static void iputdword(struct intel8x0 *chip, u32 offset, u32 val)
+static inline void iputdword(struct intel8x0 *chip, u32 offset, u32 val)
{
- if (chip->bm_mmio)
- writel(val, chip->remap_bmaddr + offset);
- else
- outl(val, chip->bmaddr + offset);
+ iowrite32(val, chip->bmaddr + offset);
}
/*
* Lowlevel I/O - AC'97 registers
*/
-static u16 iagetword(struct intel8x0 *chip, u32 offset)
+static inline u16 iagetword(struct intel8x0 *chip, u32 offset)
{
- if (chip->mmio)
- return readw(chip->remap_addr + offset);
- else
- return inw(chip->addr + offset);
+ return ioread16(chip->addr + offset);
}
-static void iaputword(struct intel8x0 *chip, u32 offset, u16 val)
+static inline void iaputword(struct intel8x0 *chip, u32 offset, u16 val)
{
- if (chip->mmio)
- writew(val, chip->remap_addr + offset);
- else
- outw(val, chip->addr + offset);
+ iowrite16(val, chip->addr + offset);
}
/*
@@ -1606,10 +1581,14 @@ static int __devinit snd_intel8x0_pcm(struct intel8x0 *chip)
case DEVICE_INTEL_ICH4:
tbl = intel_pcms;
tblsize = ARRAY_SIZE(intel_pcms);
+ if (spdif_aclink)
+ tblsize--;
break;
case DEVICE_NFORCE:
tbl = nforce_pcms;
tblsize = ARRAY_SIZE(nforce_pcms);
+ if (spdif_aclink)
+ tblsize--;
break;
case DEVICE_ALI:
tbl = ali_pcms;
@@ -2068,24 +2047,26 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
};
chip->spdif_idx = -1; /* use PCMOUT (or disabled) */
- switch (chip->device_type) {
- case DEVICE_NFORCE:
- chip->spdif_idx = NVD_SPBAR;
- break;
- case DEVICE_ALI:
- chip->spdif_idx = ALID_AC97SPDIFOUT;
- break;
- case DEVICE_INTEL_ICH4:
- chip->spdif_idx = ICHD_SPBAR;
- break;
- };
+ if (!spdif_aclink) {
+ switch (chip->device_type) {
+ case DEVICE_NFORCE:
+ chip->spdif_idx = NVD_SPBAR;
+ break;
+ case DEVICE_ALI:
+ chip->spdif_idx = ALID_AC97SPDIFOUT;
+ break;
+ case DEVICE_INTEL_ICH4:
+ chip->spdif_idx = ICHD_SPBAR;
+ break;
+ };
+ }
chip->in_ac97_init = 1;
memset(&ac97, 0, sizeof(ac97));
ac97.private_data = chip;
ac97.private_free = snd_intel8x0_mixer_free_ac97;
- ac97.scaps = AC97_SCAP_SKIP_MODEM;
+ ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE;
if (chip->xbox)
ac97.scaps |= AC97_SCAP_DETECT_BY_VENDOR;
if (chip->device_type != DEVICE_ALI) {
@@ -2201,11 +2182,11 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
if ((igetdword(chip, ICHREG(GLOB_STA)) & ICH_SAMPLE_CAP) == ICH_SAMPLE_16_20)
chip->smp20bit = 1;
}
- if (chip->device_type == DEVICE_NFORCE) {
+ if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) {
/* 48kHz only */
chip->ichd[chip->spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000;
}
- if (chip->device_type == DEVICE_INTEL_ICH4) {
+ if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) {
/* use slot 10/11 for SPDIF */
u32 val;
val = igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK;
@@ -2333,7 +2314,7 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
/* unmute the output on SIS7012 */
iputword(chip, 0x4c, igetword(chip, 0x4c) | 1);
}
- if (chip->device_type == DEVICE_NFORCE) {
+ if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) {
/* enable SPDIF interrupt */
unsigned int val;
pci_read_config_dword(chip->pci, 0x4c, &val);
@@ -2426,7 +2407,7 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
/* reset channels */
for (i = 0; i < chip->bdbars_count; i++)
iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
- if (chip->device_type == DEVICE_NFORCE) {
+ if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) {
/* stop the spdif interrupt */
unsigned int val;
pci_read_config_dword(chip->pci, 0x4c, &val);
@@ -2443,10 +2424,10 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0);
snd_dma_free_pages(&chip->bdbars);
}
- if (chip->remap_addr)
- iounmap(chip->remap_addr);
- if (chip->remap_bmaddr)
- iounmap(chip->remap_bmaddr);
+ if (chip->addr)
+ pci_iounmap(chip->pci, chip->addr);
+ if (chip->bmaddr)
+ pci_iounmap(chip->pci, chip->bmaddr);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
@@ -2509,7 +2490,7 @@ static int intel8x0_resume(struct pci_dev *pci)
}
pci_set_master(pci);
if (request_irq(pci->irq, snd_intel8x0_interrupt,
- IRQF_DISABLED|IRQF_SHARED, card->shortname, chip)) {
+ IRQF_SHARED, card->shortname, chip)) {
printk(KERN_ERR "intel8x0: unable to grab IRQ %d, "
"disabling device\n", pci->irq);
snd_card_disconnect(card);
@@ -2520,7 +2501,7 @@ static int intel8x0_resume(struct pci_dev *pci)
snd_intel8x0_chip_init(chip, 0);
/* re-initialize mixer stuff */
- if (chip->device_type == DEVICE_INTEL_ICH4) {
+ if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) {
/* enable separate SDINs for ICH4 */
iputbyte(chip, ICHREG(SDM), chip->sdm_saved);
/* use slot 10/11 for SPDIF */
@@ -2793,35 +2774,27 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
if (device_type == DEVICE_ALI) {
/* ALI5455 has no ac97 region */
- chip->bmaddr = pci_resource_start(pci, 0);
+ chip->bmaddr = pci_iomap(pci, 0, 0);
goto port_inited;
}
- if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and Nforce */
- chip->mmio = 1;
- chip->addr = pci_resource_start(pci, 2);
- chip->remap_addr = ioremap_nocache(chip->addr,
- pci_resource_len(pci, 2));
- if (chip->remap_addr == NULL) {
- snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
- snd_intel8x0_free(chip);
- return -EIO;
- }
- } else {
- chip->addr = pci_resource_start(pci, 0);
- }
- if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) { /* ICH4 */
- chip->bm_mmio = 1;
- chip->bmaddr = pci_resource_start(pci, 3);
- chip->remap_bmaddr = ioremap_nocache(chip->bmaddr,
- pci_resource_len(pci, 3));
- if (chip->remap_bmaddr == NULL) {
- snd_printk(KERN_ERR "Controller space ioremap problem\n");
- snd_intel8x0_free(chip);
- return -EIO;
- }
- } else {
- chip->bmaddr = pci_resource_start(pci, 1);
+ if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */
+ chip->addr = pci_iomap(pci, 2, 0);
+ else
+ chip->addr = pci_iomap(pci, 0, 0);
+ if (!chip->addr) {
+ snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+ snd_intel8x0_free(chip);
+ return -EIO;
+ }
+ if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */
+ chip->bmaddr = pci_iomap(pci, 3, 0);
+ else
+ chip->bmaddr = pci_iomap(pci, 1, 0);
+ if (!chip->bmaddr) {
+ snd_printk(KERN_ERR "Controller space ioremap problem\n");
+ snd_intel8x0_free(chip);
+ return -EIO;
}
port_inited:
@@ -2887,7 +2860,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
/* request irq after initializaing int_sta_mask, etc */
if (request_irq(pci->irq, snd_intel8x0_interrupt,
- IRQF_DISABLED|IRQF_SHARED, card->shortname, chip)) {
+ IRQF_SHARED, card->shortname, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_intel8x0_free(chip);
return -EBUSY;
@@ -2964,6 +2937,29 @@ static struct shortname_table {
{ 0, NULL },
};
+static struct snd_pci_quirk spdif_aclink_defaults[] __devinitdata = {
+ SND_PCI_QUIRK(0x147b, 0x1c1a, "ASUS KN8", 1),
+ { } /* end */
+};
+
+/* look up white/black list for SPDIF over ac-link */
+static int __devinit check_default_spdif_aclink(struct pci_dev *pci)
+{
+ const struct snd_pci_quirk *w;
+
+ w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults);
+ if (w) {
+ if (w->value)
+ snd_printdd(KERN_INFO "intel8x0: Using SPDIF over "
+ "AC-Link for %s\n", w->name);
+ else
+ snd_printdd(KERN_INFO "intel8x0: Using integrated "
+ "SPDIF DMA for %s\n", w->name);
+ return w->value;
+ }
+ return 0;
+}
+
static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
@@ -2976,16 +2972,18 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
if (card == NULL)
return -ENOMEM;
- switch (pci_id->driver_data) {
- case DEVICE_NFORCE:
- strcpy(card->driver, "NFORCE");
- break;
- case DEVICE_INTEL_ICH4:
- strcpy(card->driver, "ICH4");
- break;
- default:
- strcpy(card->driver, "ICH");
- break;
+ if (spdif_aclink < 0)
+ spdif_aclink = check_default_spdif_aclink(pci);
+
+ strcpy(card->driver, "ICH");
+ if (!spdif_aclink) {
+ switch (pci_id->driver_data) {
+ case DEVICE_NFORCE:
+ strcpy(card->driver, "NFORCE");
+ break;
+ case DEVICE_INTEL_ICH4:
+ strcpy(card->driver, "ICH4");
+ }
}
strcpy(card->shortname, "Intel ICH");
@@ -3025,8 +3023,8 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
snd_intel8x0_proc_init(chip);
snprintf(card->longname, sizeof(card->longname),
- "%s with %s at %#lx, irq %i", card->shortname,
- snd_ac97_get_short_name(chip->ac97[0]), chip->addr, chip->irq);
+ "%s with %s at irq %i", card->shortname,
+ snd_ac97_get_short_name(chip->ac97[0]), chip->irq);
if (! ac97_clock)
intel8x0_measure_ac97_clock(chip);
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index bd467c50112..c155e1f3a0e 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -196,12 +196,8 @@ struct intel8x0m {
int irq;
- unsigned int mmio;
- unsigned long addr;
- void __iomem *remap_addr;
- unsigned int bm_mmio;
- unsigned long bmaddr;
- void __iomem *remap_bmaddr;
+ void __iomem *addr;
+ void __iomem *bmaddr;
struct pci_dev *pci;
struct snd_card *card;
@@ -253,72 +249,48 @@ MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids);
* Lowlevel I/O - busmaster
*/
-static u8 igetbyte(struct intel8x0m *chip, u32 offset)
+static inline u8 igetbyte(struct intel8x0m *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readb(chip->remap_bmaddr + offset);
- else
- return inb(chip->bmaddr + offset);
+ return ioread8(chip->bmaddr + offset);
}
-static u16 igetword(struct intel8x0m *chip, u32 offset)
+static inline u16 igetword(struct intel8x0m *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readw(chip->remap_bmaddr + offset);
- else
- return inw(chip->bmaddr + offset);
+ return ioread16(chip->bmaddr + offset);
}
-static u32 igetdword(struct intel8x0m *chip, u32 offset)
+static inline u32 igetdword(struct intel8x0m *chip, u32 offset)
{
- if (chip->bm_mmio)
- return readl(chip->remap_bmaddr + offset);
- else
- return inl(chip->bmaddr + offset);
+ return ioread32(chip->bmaddr + offset);
}
-static void iputbyte(struct intel8x0m *chip, u32 offset, u8 val)
+static inline void iputbyte(struct intel8x0m *chip, u32 offset, u8 val)
{
- if (chip->bm_mmio)
- writeb(val, chip->remap_bmaddr + offset);
- else
- outb(val, chip->bmaddr + offset);
+ iowrite8(val, chip->bmaddr + offset);
}
-static void iputword(struct intel8x0m *chip, u32 offset, u16 val)
+static inline void iputword(struct intel8x0m *chip, u32 offset, u16 val)
{
- if (chip->bm_mmio)
- writew(val, chip->remap_bmaddr + offset);
- else
- outw(val, chip->bmaddr + offset);
+ iowrite16(val, chip->bmaddr + offset);
}
-static void iputdword(struct intel8x0m *chip, u32 offset, u32 val)
+static inline void iputdword(struct intel8x0m *chip, u32 offset, u32 val)
{
- if (chip->bm_mmio)
- writel(val, chip->remap_bmaddr + offset);
- else
- outl(val, chip->bmaddr + offset);
+ iowrite32(val, chip->bmaddr + offset);
}
/*
* Lowlevel I/O - AC'97 registers
*/
-static u16 iagetword(struct intel8x0m *chip, u32 offset)
+static inline u16 iagetword(struct intel8x0m *chip, u32 offset)
{
- if (chip->mmio)
- return readw(chip->remap_addr + offset);
- else
- return inw(chip->addr + offset);
+ return ioread16(chip->addr + offset);
}
-static void iaputword(struct intel8x0m *chip, u32 offset, u16 val)
+static inline void iaputword(struct intel8x0m *chip, u32 offset, u16 val)
{
- if (chip->mmio)
- writew(val, chip->remap_addr + offset);
- else
- outw(val, chip->addr + offset);
+ iowrite16(val, chip->addr + offset);
}
/*
@@ -858,7 +830,7 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0m *chip, int ac97_clock)
memset(&ac97, 0, sizeof(ac97));
ac97.private_data = chip;
ac97.private_free = snd_intel8x0_mixer_free_ac97;
- ac97.scaps = AC97_SCAP_SKIP_AUDIO;
+ ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
glob_sta = igetdword(chip, ICHREG(GLOB_STA));
@@ -1019,10 +991,10 @@ static int snd_intel8x0_free(struct intel8x0m *chip)
__hw_end:
if (chip->bdbars.area)
snd_dma_free_pages(&chip->bdbars);
- if (chip->remap_addr)
- iounmap(chip->remap_addr);
- if (chip->remap_bmaddr)
- iounmap(chip->remap_bmaddr);
+ if (chip->addr)
+ pci_iounmap(chip->pci, chip->addr);
+ if (chip->bmaddr)
+ pci_iounmap(chip->pci, chip->bmaddr);
if (chip->irq >= 0)
free_irq(chip->irq, chip);
pci_release_regions(chip->pci);
@@ -1071,7 +1043,7 @@ static int intel8x0m_resume(struct pci_dev *pci)
}
pci_set_master(pci);
if (request_irq(pci->irq, snd_intel8x0_interrupt,
- IRQF_DISABLED|IRQF_SHARED, card->shortname, chip)) {
+ IRQF_SHARED, card->shortname, chip)) {
printk(KERN_ERR "intel8x0m: unable to grab IRQ %d, "
"disabling device\n", pci->irq);
snd_card_disconnect(card);
@@ -1173,39 +1145,31 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card,
if (device_type == DEVICE_ALI) {
/* ALI5455 has no ac97 region */
- chip->bmaddr = pci_resource_start(pci, 0);
+ chip->bmaddr = pci_iomap(pci, 0, 0);
goto port_inited;
}
- if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and Nforce */
- chip->mmio = 1;
- chip->addr = pci_resource_start(pci, 2);
- chip->remap_addr = ioremap_nocache(chip->addr,
- pci_resource_len(pci, 2));
- if (chip->remap_addr == NULL) {
- snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
- snd_intel8x0_free(chip);
- return -EIO;
- }
- } else {
- chip->addr = pci_resource_start(pci, 0);
+ if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */
+ chip->addr = pci_iomap(pci, 2, 0);
+ else
+ chip->addr = pci_iomap(pci, 0, 0);
+ if (!chip->addr) {
+ snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+ snd_intel8x0_free(chip);
+ return -EIO;
}
- if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) { /* ICH4 */
- chip->bm_mmio = 1;
- chip->bmaddr = pci_resource_start(pci, 3);
- chip->remap_bmaddr = ioremap_nocache(chip->bmaddr,
- pci_resource_len(pci, 3));
- if (chip->remap_bmaddr == NULL) {
- snd_printk(KERN_ERR "Controller space ioremap problem\n");
- snd_intel8x0_free(chip);
- return -EIO;
- }
- } else {
- chip->bmaddr = pci_resource_start(pci, 1);
+ if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */
+ chip->bmaddr = pci_iomap(pci, 3, 0);
+ else
+ chip->bmaddr = pci_iomap(pci, 1, 0);
+ if (!chip->bmaddr) {
+ snd_printk(KERN_ERR "Controller space ioremap problem\n");
+ snd_intel8x0_free(chip);
+ return -EIO;
}
port_inited:
- if (request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_SHARED,
card->shortname, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_intel8x0_free(chip);
@@ -1339,8 +1303,8 @@ static int __devinit snd_intel8x0m_probe(struct pci_dev *pci,
snd_intel8x0m_proc_init(chip);
- sprintf(card->longname, "%s at 0x%lx, irq %i",
- card->shortname, chip->addr, chip->irq);
+ sprintf(card->longname, "%s at irq %i",
+ card->shortname, chip->irq);
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index fa8cd8cecc2..21d0899ac38 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -28,6 +28,7 @@
#include <linux/wait.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
+#include <linux/firmware.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -263,7 +264,15 @@ enum MonitorModeSelector {
#define COMMAND_ACK_DELAY 13 // number of RTC ticks to wait for an acknowledgement
// from the card after sending a command.
+#define FIRMWARE_IN_THE_KERNEL
+
+#ifdef FIRMWARE_IN_THE_KERNEL
#include "korg1212-firmware.h"
+static const struct firmware static_dsp_code = {
+ .data = (u8 *)dspCode,
+ .size = sizeof dspCode
+};
+#endif
enum ClockSourceIndex {
K1212_CLKIDX_AdatAt44_1K = 0, // selects source as ADAT at 44.1 kHz
@@ -345,8 +354,6 @@ struct snd_korg1212 {
struct snd_dma_buffer dma_rec;
struct snd_dma_buffer dma_shared;
- u32 dspCodeSize;
-
u32 DataBufsSize;
struct KorgAudioBuffer * playDataBufsPtr;
@@ -1223,8 +1230,6 @@ static int snd_korg1212_downloadDSPCode(struct snd_korg1212 *korg1212)
snd_korg1212_setCardState(korg1212, K1212_STATE_DSP_IN_PROCESS);
- memcpy(korg1212->dma_dsp.area, dspCode, korg1212->dspCodeSize);
-
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_StartDSPDownload,
UpperWordSwap(korg1212->dma_dsp.addr),
0, 0, 0);
@@ -2156,6 +2161,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *
unsigned int i;
unsigned ioport_size, iomem_size, iomem2_size;
struct snd_korg1212 * korg1212;
+ const struct firmware *dsp_code;
static struct snd_device_ops ops = {
.dev_free = snd_korg1212_dev_free,
@@ -2233,7 +2239,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *
}
err = request_irq(pci->irq, snd_korg1212_interrupt,
- IRQF_DISABLED|IRQF_SHARED,
+ IRQF_SHARED,
"korg1212", korg1212);
if (err) {
@@ -2329,8 +2335,6 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *
#endif // K1212_LARGEALLOC
- korg1212->dspCodeSize = sizeof (dspCode);
-
korg1212->VolumeTablePhy = korg1212->sharedBufferPhy +
offsetof(struct KorgSharedBuffer, volumeData);
korg1212->RoutingTablePhy = korg1212->sharedBufferPhy +
@@ -2338,17 +2342,40 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *
korg1212->AdatTimeCodePhy = korg1212->sharedBufferPhy +
offsetof(struct KorgSharedBuffer, AdatTimeCode);
+ err = request_firmware(&dsp_code, "korg/k1212.dsp", &pci->dev);
+ if (err < 0) {
+ release_firmware(dsp_code);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ dsp_code = &static_dsp_code;
+#else
+ snd_printk(KERN_ERR "firmware not available\n");
+ snd_korg1212_free(korg1212);
+ return err;
+#endif
+ }
+
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
- korg1212->dspCodeSize, &korg1212->dma_dsp) < 0) {
- snd_printk(KERN_ERR "korg1212: can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize);
+ dsp_code->size, &korg1212->dma_dsp) < 0) {
+ snd_printk(KERN_ERR "korg1212: cannot allocate dsp code memory (%zd bytes)\n", dsp_code->size);
snd_korg1212_free(korg1212);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (dsp_code != &static_dsp_code)
+#endif
+ release_firmware(dsp_code);
return -ENOMEM;
}
K1212_DEBUG_PRINTK("K1212_DEBUG: DSP Code area = 0x%p (0x%08x) %d bytes [%s]\n",
- korg1212->dma_dsp.area, korg1212->dma_dsp.addr, korg1212->dspCodeSize,
+ korg1212->dma_dsp.area, korg1212->dma_dsp.addr, dsp_code->size,
stateName[korg1212->cardState]);
+ memcpy(korg1212->dma_dsp.area, dsp_code->data, dsp_code->size);
+
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (dsp_code != &static_dsp_code)
+#endif
+ release_firmware(dsp_code);
+
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_RebootCard, 0, 0, 0, 0);
if (rc)
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 8cab342bbaa..4526904e3f8 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -41,6 +41,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/moduleparam.h>
+#include <linux/firmware.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -48,6 +49,7 @@
#include <sound/mpu401.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
+#include <asm/byteorder.h>
MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("ESS Maestro3 PCI");
@@ -768,21 +770,6 @@ MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)");
/*
*/
-/* quirk lists */
-struct m3_quirk {
- const char *name; /* device name */
- u16 vendor, device; /* subsystem ids */
- int amp_gpio; /* gpio pin # for external amp, -1 = default */
- int irda_workaround; /* non-zero if avoid to touch 0x10 on GPIO_DIRECTION
- (e.g. for IrDA on Dell Inspirons) */
-};
-
-struct m3_hv_quirk {
- u16 vendor, device, subsystem_vendor, subsystem_device;
- u32 config; /* ALLEGRO_CONFIG hardware volume bits */
- int is_omnibook; /* Do HP OmniBook GPIO magic? */
-};
-
struct m3_list {
int curlen;
int mem_addr;
@@ -830,8 +817,6 @@ struct snd_m3 {
struct snd_pcm *pcm;
struct pci_dev *pci;
- const struct m3_quirk *quirk;
- const struct m3_hv_quirk *hv_quirk;
int dacs_active;
int timer_users;
@@ -845,7 +830,11 @@ struct snd_m3 {
u8 reset_state;
int external_amp;
- int amp_gpio;
+ int amp_gpio; /* gpio pin # for external amp, -1 = default */
+ unsigned int hv_config; /* hardware-volume config bits */
+ unsigned irda_workaround :1; /* avoid to touch 0x10 on GPIO_DIRECTION
+ (e.g. for IrDA on Dell Inspirons) */
+ unsigned is_omnibook :1; /* Do HP OmniBook GPIO magic? */
/* midi */
struct snd_rawmidi *rmidi;
@@ -864,6 +853,9 @@ struct snd_m3 {
#ifdef CONFIG_PM
u16 *suspend_mem;
#endif
+
+ const struct firmware *assp_kernel_image;
+ const struct firmware *assp_minisrc_image;
};
/*
@@ -891,127 +883,104 @@ static struct pci_device_id snd_m3_ids[] = {
MODULE_DEVICE_TABLE(pci, snd_m3_ids);
-static const struct m3_quirk m3_quirk_list[] = {
- /* panasonic CF-28 "toughbook" */
- {
- .name = "Panasonic CF-28",
- .vendor = 0x10f7,
- .device = 0x833e,
- .amp_gpio = 0x0d,
- },
- /* panasonic CF-72 "toughbook" */
- {
- .name = "Panasonic CF-72",
- .vendor = 0x10f7,
- .device = 0x833d,
- .amp_gpio = 0x0d,
- },
- /* Dell Inspiron 4000 */
- {
- .name = "Dell Inspiron 4000",
- .vendor = 0x1028,
- .device = 0x00b0,
- .amp_gpio = -1,
- .irda_workaround = 1,
- },
- /* Dell Inspiron 8000 */
- {
- .name = "Dell Inspiron 8000",
- .vendor = 0x1028,
- .device = 0x00a4,
- .amp_gpio = -1,
- .irda_workaround = 1,
- },
- /* Dell Inspiron 8100 */
- {
- .name = "Dell Inspiron 8100",
- .vendor = 0x1028,
- .device = 0x00e6,
- .amp_gpio = -1,
- .irda_workaround = 1,
- },
- /* NEC LM800J/7 */
- {
- .name = "NEC LM800J/7",
- .vendor = 0x1033,
- .device = 0x80f1,
- .amp_gpio = 0x03,
- },
- /* LEGEND ZhaoYang 3100CF */
- {
- .name = "LEGEND ZhaoYang 3100CF",
- .vendor = 0x1509,
- .device = 0x1740,
- .amp_gpio = 0x03,
- },
- /* END */
- { NULL }
+static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = {
+ SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d),
+ SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d),
+ SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03),
+ SND_PCI_QUIRK(0x1509, 0x1740, "LEGEND ZhaoYang 3100CF", 0x03),
+ { } /* END */
};
-/* These values came from the Windows driver. */
-static const struct m3_hv_quirk m3_hv_quirk_list[] = {
+static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = {
+ SND_PCI_QUIRK(0x1028, 0x00b0, "Dell Inspiron 4000", 1),
+ SND_PCI_QUIRK(0x1028, 0x00a4, "Dell Inspiron 8000", 1),
+ SND_PCI_QUIRK(0x1028, 0x00e6, "Dell Inspiron 8100", 1),
+ { } /* END */
+};
+
+/* hardware volume quirks */
+static struct snd_pci_quirk m3_hv_quirk_list[] __devinitdata = {
/* Allegro chips */
- { 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
- { 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */
- { 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 },
+ SND_PCI_QUIRK(0x0E11, 0x002E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x0E11, 0x0094, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x0E11, 0xB112, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x0E11, 0xB114, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x103C, 0x0012, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x103C, 0x0018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x103C, 0x001C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x103C, 0x001D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x103C, 0x001E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x107B, 0x3350, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x10F7, 0x8338, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x10F7, 0x833C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x10F7, 0x833D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x10F7, 0x833E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x10F7, 0x833F, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x13BD, 0x1018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x13BD, 0x1019, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x13BD, 0x101A, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x14FF, 0x0F03, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x14FF, 0x0F04, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x14FF, 0x0F05, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x156D, 0xB400, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x156D, 0xB795, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x156D, 0xB797, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x156D, 0xC700, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
+ SND_PCI_QUIRK(0x1033, 0x80F1, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x103C, 0x001A, NULL, /* HP OmniBook 6100 */
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x107B, 0x340A, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x107B, 0x3450, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x109F, 0x3134, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x109F, 0x3161, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0x3280, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0x3281, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0xC002, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0xC003, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x1509, 0x1740, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x1610, 0x0010, NULL,
+ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x1042, 0x1042, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x107B, 0x9500, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x14FF, 0x0F06, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x1558, 0x8586, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x161F, 0x2011, NULL, HV_CTRL_ENABLE),
/* Maestro3 chips */
- { 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */
- { 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */
- { 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 },
- { 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
- { 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
- { 0 }
+ SND_PCI_QUIRK(0x103C, 0x000E, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x103C, 0x0010, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x103C, 0x0011, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x103C, 0x001B, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x104D, 0x80A6, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x104D, 0x80AA, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x107B, 0x5300, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x110A, 0x1998, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x13BD, 0x1015, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x13BD, 0x101C, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x13BD, 0x1802, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x1599, 0x0715, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x5643, 0x5643, NULL, HV_CTRL_ENABLE),
+ SND_PCI_QUIRK(0x144D, 0x3260, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0x3261, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0xC000, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+ SND_PCI_QUIRK(0x144D, 0xC001, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
+ { } /* END */
+};
+
+/* HP Omnibook quirks */
+static struct snd_pci_quirk m3_omnibook_quirk_list[] __devinitdata = {
+ SND_PCI_QUIRK_ID(0x103c, 0x0010), /* HP OmniBook 6000 */
+ SND_PCI_QUIRK_ID(0x103c, 0x0011), /* HP OmniBook 500 */
+ { } /* END */
};
/*
@@ -2050,7 +2019,7 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip)
for (i = 0; i < 5; i++) {
dir = inw(io + GPIO_DIRECTION);
- if (! chip->quirk || ! chip->quirk->irda_workaround)
+ if (!chip->irda_workaround)
dir |= 0x10; /* assuming pci bus master? */
snd_m3_remote_codec_config(io, 0);
@@ -2132,6 +2101,10 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip)
}
+#define FIRMWARE_IN_THE_KERNEL
+
+#ifdef FIRMWARE_IN_THE_KERNEL
+
/*
* DSP Code images
*/
@@ -2260,6 +2233,30 @@ static const u16 assp_minisrc_image[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
};
+static const struct firmware assp_kernel = {
+ .data = (u8 *)assp_kernel_image,
+ .size = sizeof assp_kernel_image
+};
+static const struct firmware assp_minisrc = {
+ .data = (u8 *)assp_minisrc_image,
+ .size = sizeof assp_minisrc_image
+};
+
+#endif /* FIRMWARE_IN_THE_KERNEL */
+
+#ifdef __LITTLE_ENDIAN
+static inline void snd_m3_convert_from_le(const struct firmware *fw) { }
+#else
+static void snd_m3_convert_from_le(const struct firmware *fw)
+{
+ int i;
+ u16 *data = (u16 *)fw->data;
+
+ for (i = 0; i < fw->size / 2; ++i)
+ le16_to_cpus(&data[i]);
+}
+#endif
+
/*
* initialize ASSP
@@ -2274,6 +2271,7 @@ static const u16 minisrc_lpf[MINISRC_LPF_LEN] = {
static void snd_m3_assp_init(struct snd_m3 *chip)
{
unsigned int i;
+ u16 *data;
/* zero kernel data */
for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
@@ -2291,10 +2289,10 @@ static void snd_m3_assp_init(struct snd_m3 *chip)
KDATA_DMA_XFER0);
/* write kernel into code memory.. */
- for (i = 0 ; i < ARRAY_SIZE(assp_kernel_image); i++) {
+ data = (u16 *)chip->assp_kernel_image->data;
+ for (i = 0 ; i * 2 < chip->assp_kernel_image->size; i++) {
snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
- REV_B_CODE_MEMORY_BEGIN + i,
- assp_kernel_image[i]);
+ REV_B_CODE_MEMORY_BEGIN + i, data[i]);
}
/*
@@ -2303,10 +2301,10 @@ static void snd_m3_assp_init(struct snd_m3 *chip)
* drop it there. It seems that the minisrc doesn't
* need vectors, so we won't bother with them..
*/
- for (i = 0; i < ARRAY_SIZE(assp_minisrc_image); i++) {
+ data = (u16 *)chip->assp_minisrc_image->data;
+ for (i = 0; i * 2 < chip->assp_minisrc_image->size; i++) {
snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
- 0x400 + i,
- assp_minisrc_image[i]);
+ 0x400 + i, data[i]);
}
/*
@@ -2377,7 +2375,7 @@ static int __devinit snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma
* shifted list address is aligned.
* list address = (mem address >> 1) >> 7;
*/
- data_bytes = (data_bytes + 255) & ~255;
+ data_bytes = ALIGN(data_bytes, 256);
address = 0x1100 + ((data_bytes/2) * index);
if ((address + (data_bytes/2)) >= 0x1c00) {
@@ -2444,7 +2442,7 @@ snd_m3_chip_init(struct snd_m3 *chip)
DISABLE_LEGACY);
pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w);
- if (chip->hv_quirk && chip->hv_quirk->is_omnibook) {
+ if (chip->is_omnibook) {
/*
* Volume buttons on some HP OmniBook laptops don't work
* correctly. This makes them work for the most part.
@@ -2461,8 +2459,7 @@ snd_m3_chip_init(struct snd_m3 *chip)
}
pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD);
- if (chip->hv_quirk)
- n |= chip->hv_quirk->config;
+ n |= chip->hv_config;
/* For some reason we must always use reduced debounce. */
n |= REDUCED_DEBOUNCE;
n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
@@ -2510,7 +2507,7 @@ snd_m3_enable_ints(struct snd_m3 *chip)
/* TODO: MPU401 not supported yet */
val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/;
- if (chip->hv_quirk && (chip->hv_quirk->config & HV_CTRL_ENABLE))
+ if (chip->hv_config & HV_CTRL_ENABLE)
val |= HV_INT_ENABLE;
outw(val, io + HOST_INT_CTRL);
outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
@@ -2553,6 +2550,15 @@ static int snd_m3_free(struct snd_m3 *chip)
if (chip->iobase)
pci_release_regions(chip->pci);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (chip->assp_kernel_image != &assp_kernel)
+#endif
+ release_firmware(chip->assp_kernel_image);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (chip->assp_minisrc_image != &assp_minisrc)
+#endif
+ release_firmware(chip->assp_minisrc_image);
+
pci_disable_device(chip->pci);
kfree(chip);
return 0;
@@ -2665,8 +2671,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
{
struct snd_m3 *chip;
int i, err;
- const struct m3_quirk *quirk;
- const struct m3_hv_quirk *hv_quirk;
+ const struct snd_pci_quirk *quirk;
static struct snd_device_ops ops = {
.dev_free = snd_m3_dev_free,
};
@@ -2706,34 +2711,32 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
chip->pci = pci;
chip->irq = -1;
- for (quirk = m3_quirk_list; quirk->vendor; quirk++) {
- if (pci->subsystem_vendor == quirk->vendor &&
- pci->subsystem_device == quirk->device) {
- printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name);
- chip->quirk = quirk;
- break;
- }
- }
-
- for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) {
- if (pci->vendor == hv_quirk->vendor &&
- pci->device == hv_quirk->device &&
- pci->subsystem_vendor == hv_quirk->subsystem_vendor &&
- pci->subsystem_device == hv_quirk->subsystem_device) {
- chip->hv_quirk = hv_quirk;
- break;
- }
- }
-
chip->external_amp = enable_amp;
if (amp_gpio >= 0 && amp_gpio <= 0x0f)
chip->amp_gpio = amp_gpio;
- else if (chip->quirk && chip->quirk->amp_gpio >= 0)
- chip->amp_gpio = chip->quirk->amp_gpio;
- else if (chip->allegro_flag)
- chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
- else /* presumably this is for all 'maestro3's.. */
- chip->amp_gpio = GPO_EXT_AMP_M3;
+ else {
+ quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list);
+ if (quirk) {
+ snd_printdd(KERN_INFO "maestro3: set amp-gpio "
+ "for '%s'\n", quirk->name);
+ chip->amp_gpio = quirk->value;
+ } else if (chip->allegro_flag)
+ chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
+ else /* presumably this is for all 'maestro3's.. */
+ chip->amp_gpio = GPO_EXT_AMP_M3;
+ }
+
+ quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list);
+ if (quirk) {
+ snd_printdd(KERN_INFO "maestro3: enabled irda workaround "
+ "for '%s'\n", quirk->name);
+ chip->irda_workaround = 1;
+ }
+ quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list);
+ if (quirk)
+ chip->hv_config = quirk->value;
+ if (snd_pci_quirk_lookup(pci, m3_omnibook_quirk_list))
+ chip->is_omnibook = 1;
chip->num_substreams = NR_DSPS;
chip->substreams = kcalloc(chip->num_substreams, sizeof(struct m3_dma),
@@ -2744,6 +2747,30 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
return -ENOMEM;
}
+ err = request_firmware(&chip->assp_kernel_image,
+ "ess/maestro3_assp_kernel.fw", &pci->dev);
+ if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+ chip->assp_kernel_image = &assp_kernel;
+#else
+ snd_m3_free(chip);
+ return err;
+#endif
+ } else
+ snd_m3_convert_from_le(chip->assp_kernel_image);
+
+ err = request_firmware(&chip->assp_minisrc_image,
+ "ess/maestro3_assp_minisrc.fw", &pci->dev);
+ if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+ chip->assp_minisrc_image = &assp_minisrc;
+#else
+ snd_m3_free(chip);
+ return err;
+#endif
+ } else
+ snd_m3_convert_from_le(chip->assp_minisrc_image);
+
if ((err = pci_request_regions(pci, card->driver)) < 0) {
snd_m3_free(chip);
return err;
@@ -2762,7 +2789,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
- if (request_irq(pci->irq, snd_m3_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED,
card->driver, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_m3_free(chip);
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 216aee5f93e..21386da3bc8 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1066,7 +1066,7 @@ static int snd_mixart_free(struct mixart_mgr *mgr)
/* release irq */
if (mgr->irq >= 0)
- free_irq(mgr->irq, (void *)mgr);
+ free_irq(mgr->irq, mgr);
/* reset board if some firmware was loaded */
if(mgr->dsp_loaded) {
@@ -1319,7 +1319,8 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci,
pci_resource_len(pci, i));
}
- if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_DISABLED|IRQF_SHARED, CARD_NAME, (void *)mgr)) {
+ if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED,
+ CARD_NAME, mgr)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_mixart_free(mgr);
return -EBUSY;
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
index 13de0f71d4b..d7d15c036e0 100644
--- a/sound/pci/mixart/mixart_mixer.c
+++ b/sound/pci/mixart/mixart_mixer.c
@@ -389,7 +389,7 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
return changed;
}
-static DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0);
static struct snd_kcontrol_new mixart_control_analog_level = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -872,7 +872,7 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
return changed;
}
-static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
static struct snd_kcontrol_new snd_mixart_pcm_vol =
{
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 945d21bf187..03b3a4792f7 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -465,7 +465,7 @@ static int snd_nm256_acquire_irq(struct nm256 *chip)
{
mutex_lock(&chip->irq_mutex);
if (chip->irq < 0) {
- if (request_irq(chip->pci->irq, chip->interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(chip->pci->irq, chip->interrupt, IRQF_SHARED,
chip->card->driver, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq);
mutex_unlock(&chip->irq_mutex);
@@ -1628,23 +1628,15 @@ __error:
}
-struct nm256_quirk {
- unsigned short vendor;
- unsigned short device;
- int type;
-};
-
enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 };
-static struct nm256_quirk nm256_quirks[] __devinitdata = {
+static struct snd_pci_quirk nm256_quirks[] __devinitdata = {
/* HP omnibook 4150 has cs4232 codec internally */
- { .vendor = 0x103c, .device = 0x0007, .type = NM_BLACKLISTED },
- /* Sony PCG-F305 */
- { .vendor = 0x104d, .device = 0x8041, .type = NM_RESET_WORKAROUND },
- /* Dell Latitude LS */
- { .vendor = 0x1028, .device = 0x0080, .type = NM_RESET_WORKAROUND },
- /* Dell Latitude CSx */
- { .vendor = 0x1028, .device = 0x0091, .type = NM_RESET_WORKAROUND_2 },
+ SND_PCI_QUIRK(0x103c, 0x0007, "HP omnibook 4150", NM_BLACKLISTED),
+ /* Reset workarounds to avoid lock-ups */
+ SND_PCI_QUIRK(0x104d, 0x8041, "Sony PCG-F305", NM_RESET_WORKAROUND),
+ SND_PCI_QUIRK(0x1028, 0x0080, "Dell Latitude LS", NM_RESET_WORKAROUND),
+ SND_PCI_QUIRK(0x1028, 0x0091, "Dell Latitude CSx", NM_RESET_WORKAROUND_2),
{ } /* terminator */
};
@@ -1655,26 +1647,22 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci,
struct snd_card *card;
struct nm256 *chip;
int err;
- struct nm256_quirk *q;
- u16 subsystem_vendor, subsystem_device;
-
- pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
- pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);
-
- for (q = nm256_quirks; q->vendor; q++) {
- if (q->vendor == subsystem_vendor && q->device == subsystem_device) {
- switch (q->type) {
- case NM_BLACKLISTED:
- printk(KERN_INFO "nm256: The device is blacklisted. "
- "Loading stopped\n");
- return -ENODEV;
- case NM_RESET_WORKAROUND_2:
- reset_workaround_2 = 1;
- /* Fall-through */
- case NM_RESET_WORKAROUND:
- reset_workaround = 1;
- break;
- }
+ const struct snd_pci_quirk *q;
+
+ q = snd_pci_quirk_lookup(pci, nm256_quirks);
+ if (q) {
+ snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", q->name);
+ switch (q->value) {
+ case NM_BLACKLISTED:
+ printk(KERN_INFO "nm256: The device is blacklisted. "
+ "Loading stopped\n");
+ return -ENODEV;
+ case NM_RESET_WORKAROUND_2:
+ reset_workaround_2 = 1;
+ /* Fall-through */
+ case NM_RESET_WORKAROUND:
+ reset_workaround = 1;
+ break;
}
}
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index 533c672ae8f..d97413484ae 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -1250,7 +1250,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
mgr->pci = pci;
mgr->irq = -1;
- if (request_irq(pci->irq, pcxhr_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, pcxhr_interrupt, IRQF_SHARED,
card_name, mgr)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
pcxhr_free(mgr);
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
index b133ad9e095..d9cc8d2beb6 100644
--- a/sound/pci/pcxhr/pcxhr_mixer.c
+++ b/sound/pci/pcxhr/pcxhr_mixer.c
@@ -44,8 +44,8 @@
#define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */
#define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */
-static DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0);
static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel)
{
@@ -195,7 +195,7 @@ static struct snd_kcontrol_new pcxhr_control_output_switch = {
#define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */
#define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */
-static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0);
#define MORE_THAN_ONE_STREAM_LEVEL 0x000001
#define VALID_STREAM_PAN_LEVEL_MASK 0x800000
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 56e0c01123e..5e1d5d2b285 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -1899,9 +1899,8 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci,
hwport = (struct riptideport *)chip->port;
UNSET_AIE(hwport);
- if (request_irq
- (pci->irq, snd_riptide_interrupt, IRQF_DISABLED | IRQF_SHARED,
- "RIPTIDE", chip)) {
+ if (request_irq(pci->irq, snd_riptide_interrupt, IRQF_SHARED,
+ "RIPTIDE", chip)) {
snd_printk(KERN_ERR "Riptide: unable to grab IRQ %d\n",
pci->irq);
snd_riptide_free(chip);
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index dc8d1302e22..6bb7ac650ec 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1373,7 +1373,8 @@ static int __devinit snd_rme32_create(struct rme32 * rme32)
return -ENOMEM;
}
- if (request_irq(pci->irq, snd_rme32_interrupt, IRQF_DISABLED | IRQF_SHARED, "RME32", (void *) rme32)) {
+ if (request_irq(pci->irq, snd_rme32_interrupt, IRQF_SHARED,
+ "RME32", rme32)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
return -EBUSY;
}
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 106110a89a4..e3304b7ccbc 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -1587,7 +1587,8 @@ snd_rme96_create(struct rme96 *rme96)
return -ENOMEM;
}
- if (request_irq(pci->irq, snd_rme96_interrupt, IRQF_DISABLED|IRQF_SHARED, "RME96", (void *)rme96)) {
+ if (request_irq(pci->irq, snd_rme96_interrupt, IRQF_SHARED,
+ "RME96", rme96)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
return -EBUSY;
}
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 694aa057ed4..89b3c7ff503 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -80,6 +80,7 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
/* Write registers. These are defined as byte-offsets from the iobase value.
*/
#define HDSP_resetPointer 0
+#define HDSP_freqReg 0
#define HDSP_outputBufferAddress 32
#define HDSP_inputBufferAddress 36
#define HDSP_controlRegister 64
@@ -469,6 +470,7 @@ struct hdsp {
struct pci_dev *pci;
struct snd_kcontrol *spdif_ctl;
unsigned short mixer_matrix[HDSP_MATRIX_MIXER_SIZE];
+ unsigned int dds_value; /* last value written to freq register */
};
/* These tables map the ALSA channels 1..N to the channels that we
@@ -598,6 +600,7 @@ static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out)
return (64 * out) + (32 + (in));
case 0x96:
case 0x97:
+ case 0x98:
return (32 * out) + (16 + (in));
default:
return (52 * out) + (26 + (in));
@@ -611,6 +614,7 @@ static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out)
return (64 * out) + in;
case 0x96:
case 0x97:
+ case 0x98:
return (32 * out) + in;
default:
return (52 * out) + in;
@@ -938,6 +942,11 @@ static snd_pcm_uframes_t hdsp_hw_pointer(struct hdsp *hdsp)
static void hdsp_reset_hw_pointer(struct hdsp *hdsp)
{
hdsp_write (hdsp, HDSP_resetPointer, 0);
+ if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
+ /* HDSP_resetPointer = HDSP_freqReg, which is strange and
+ * requires (?) to write again DDS value after a reset pointer
+ * (at least, it works like this) */
+ hdsp_write (hdsp, HDSP_freqReg, hdsp->dds_value);
}
static void hdsp_start_audio(struct hdsp *s)
@@ -982,6 +991,30 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames)
return 0;
}
+static void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
+{
+ u64 n;
+ u32 r;
+
+ if (rate >= 112000)
+ rate /= 4;
+ else if (rate >= 56000)
+ rate /= 2;
+
+ /* RME says n = 104857600000000, but in the windows MADI driver, I see:
+// return 104857600000000 / rate; // 100 MHz
+ return 110100480000000 / rate; // 105 MHz
+ */
+ n = 104857600000000ULL; /* = 2^20 * 10^8 */
+ div64_32(&n, rate, &r);
+ /* n should be less than 2^32 for being written to FREQ register */
+ snd_assert((n >> 32) == 0);
+ /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS
+ value to write it after a reset */
+ hdsp->dds_value = n;
+ hdsp_write(hdsp, HDSP_freqReg, hdsp->dds_value);
+}
+
static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
{
int reject_if_open = 0;
@@ -1090,6 +1123,10 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
hdsp->control_register |= rate_bits;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+ /* For HDSP9632 rev 152, need to set DDS value in FREQ register */
+ if (hdsp->io_type == H9632 && hdsp->firmware_rev >= 152)
+ hdsp_set_dds_value(hdsp, rate);
+
if (rate >= 128000) {
hdsp->channel_map = channel_map_H9632_qs;
} else if (rate > 48000) {
@@ -3516,8 +3553,8 @@ static int __devinit snd_hdsp_initialize_memory(struct hdsp *hdsp)
/* Align to bus-space 64K boundary */
- cb_bus = (hdsp->capture_dma_buf.addr + 0xFFFF) & ~0xFFFFl;
- pb_bus = (hdsp->playback_dma_buf.addr + 0xFFFF) & ~0xFFFFl;
+ cb_bus = ALIGN(hdsp->capture_dma_buf.addr, 0x10000ul);
+ pb_bus = ALIGN(hdsp->playback_dma_buf.addr, 0x10000ul);
/* Tell the card where it is */
@@ -4934,14 +4971,16 @@ static int __devinit snd_hdsp_create(struct snd_card *card,
return -EBUSY;
}
- if (request_irq(pci->irq, snd_hdsp_interrupt, IRQF_DISABLED|IRQF_SHARED, "hdsp", (void *)hdsp)) {
+ if (request_irq(pci->irq, snd_hdsp_interrupt, IRQF_SHARED,
+ "hdsp", hdsp)) {
snd_printk(KERN_ERR "Hammerfall-DSP: unable to use IRQ %d\n", pci->irq);
return -EBUSY;
}
hdsp->irq = pci->irq;
- hdsp->precise_ptr = 1;
+ hdsp->precise_ptr = 0;
hdsp->use_midi_tasklet = 1;
+ hdsp->dds_value = 0;
if ((err = snd_hdsp_initialize_memory(hdsp)) < 0)
return err;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 7055d893855..e0215aca119 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -6,6 +6,8 @@
* code based on hdsp.c Paul Davis
* Marcus Andersson
* Thomas Charbonnel
+ * Modified 2006-06-01 for AES32 support by Remy Bruno
+ * <remy.bruno@trinnov.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
@@ -77,7 +79,8 @@ MODULE_PARM_DESC(enable_monitor,
MODULE_AUTHOR
("Winfried Ritsch <ritsch_AT_iem.at>, Paul Davis <paul@linuxaudiosystems.com>, "
- "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>");
+ "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, "
+ "Remy Bruno <remy.bruno@trinnov.com>");
MODULE_DESCRIPTION("RME HDSPM");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
@@ -107,7 +110,12 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
/* --- Read registers. ---
These are defined as byte-offsets from the iobase value */
#define HDSPM_statusRegister 0
-#define HDSPM_statusRegister2 96
+/*#define HDSPM_statusRegister2 96 */
+/* after RME Windows driver sources, status2 is 4-byte word # 48 = word at
+ * offset 192, for AES32 *and* MADI
+ * => need to check that offset 192 is working on MADI */
+#define HDSPM_statusRegister2 192
+#define HDSPM_timecodeRegister 128
#define HDSPM_midiDataIn0 360
#define HDSPM_midiDataIn1 364
@@ -140,37 +148,50 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */
#define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */
#define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */
-#define HDSPM_QuadSpeed (1<<31) /* quad speed bit, not implemented now */
+#define HDSPM_QuadSpeed (1<<31) /* quad speed bit */
+#define HDSPM_Professional (1<<9) /* Professional */ /* AES32 ONLY */
#define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1,
- 56channelMODE=0 */
+ 56channelMODE=0 */ /* MADI ONLY*/
+#define HDSPM_Emphasis (1<<10) /* Emphasis */ /* AES32 ONLY */
#define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode,
- 0=off, 1=on */
+ 0=off, 1=on */ /* MADI ONLY */
+#define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */
-#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */
+#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ /* MADI ONLY*/
#define HDSPM_InputSelect1 (1<<15) /* should be 0 */
#define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */
-#define HDSPM_SyncRef1 (1<<17) /* should be 0 */
+#define HDSPM_SyncRef1 (1<<17) /* for AES32: SyncRefN codes the AES # */
+#define HDSPM_SyncRef2 (1<<13)
+#define HDSPM_SyncRef3 (1<<25)
+#define HDSPM_SMUX (1<<18) /* Frame ??? */ /* MADI ONY */
#define HDSPM_clr_tms (1<<19) /* clear track marker, do not use
AES additional bits in
lower 5 Audiodatabits ??? */
+#define HDSPM_taxi_reset (1<<20) /* ??? */ /* MADI ONLY ? */
+#define HDSPM_WCK48 (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */
#define HDSPM_Midi0InterruptEnable (1<<22)
#define HDSPM_Midi1InterruptEnable (1<<23)
#define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */
+#define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */
+#define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */
+#define HDSPM_QS_QuadWire (1<<28) /* AES32 ONLY */
+
+#define HDSPM_wclk_sel (1<<30)
/* --- bit helper defines */
#define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2)
-#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1)
+#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|HDSPM_DoubleSpeed|HDSPM_QuadSpeed)
#define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1)
#define HDSPM_InputOptical 0
#define HDSPM_InputCoaxial (HDSPM_InputSelect0)
-#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1)
+#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|HDSPM_SyncRef2|HDSPM_SyncRef3)
#define HDSPM_SyncRef_Word 0
#define HDSPM_SyncRef_MADI (HDSPM_SyncRef0)
@@ -183,6 +204,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0)
#define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1)
#define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0)
+#define HDSPM_Frequency128KHz (HDSPM_QuadSpeed|HDSPM_Frequency0)
+#define HDSPM_Frequency176_4KHz (HDSPM_QuadSpeed|HDSPM_Frequency1)
+#define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|HDSPM_Frequency0)
/* --- for internal discrimination */
#define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */
@@ -229,7 +253,8 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_BIGENDIAN_MODE (1<<9)
#define HDSPM_RD_MULTIPLE (1<<10)
-/* --- Status Register bits --- */
+/* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and
+ that do not conflict with specific bits for AES32 seem to be valid also for the AES32 */
#define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */
#define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn. MODE=0 */
#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 (like inp0) */
@@ -263,7 +288,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_madiFreq176_4 (HDSPM_madiFreq3)
#define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0)
-/* Status2 Register bits */
+/* Status2 Register bits */ /* MADI ONLY */
#define HDSPM_version0 (1<<0) /* not realy defined but I guess */
#define HDSPM_version1 (1<<1) /* in former cards it was ??? */
@@ -297,6 +322,56 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0)
#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2)
+/*
+ For AES32, bits for status, status2 and timecode are different
+*/
+/* status */
+#define HDSPM_AES32_wcLock 0x0200000
+#define HDSPM_AES32_wcFreq_bit 22
+/* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function
+ HDSPM_bit2freq */
+#define HDSPM_AES32_syncref_bit 16
+/* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */
+
+#define HDSPM_AES32_AUTOSYNC_FROM_WORD 0
+#define HDSPM_AES32_AUTOSYNC_FROM_AES1 1
+#define HDSPM_AES32_AUTOSYNC_FROM_AES2 2
+#define HDSPM_AES32_AUTOSYNC_FROM_AES3 3
+#define HDSPM_AES32_AUTOSYNC_FROM_AES4 4
+#define HDSPM_AES32_AUTOSYNC_FROM_AES5 5
+#define HDSPM_AES32_AUTOSYNC_FROM_AES6 6
+#define HDSPM_AES32_AUTOSYNC_FROM_AES7 7
+#define HDSPM_AES32_AUTOSYNC_FROM_AES8 8
+#define HDSPM_AES32_AUTOSYNC_FROM_NONE -1
+
+/* status2 */
+/* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */
+#define HDSPM_LockAES 0x80
+#define HDSPM_LockAES1 0x80
+#define HDSPM_LockAES2 0x40
+#define HDSPM_LockAES3 0x20
+#define HDSPM_LockAES4 0x10
+#define HDSPM_LockAES5 0x8
+#define HDSPM_LockAES6 0x4
+#define HDSPM_LockAES7 0x2
+#define HDSPM_LockAES8 0x1
+/*
+ Timecode
+ After windows driver sources, bits 4*i to 4*i+3 give the input frequency on
+ AES i+1
+ bits 3210
+ 0001 32kHz
+ 0010 44.1kHz
+ 0011 48kHz
+ 0100 64kHz
+ 0101 88.2kHz
+ 0110 96kHz
+ 0111 128kHz
+ 1000 176.4kHz
+ 1001 192kHz
+ NB: Timecode register doesn't seem to work on AES32 card revision 230
+*/
+
/* Mixer Values */
#define UNITY_GAIN 32768 /* = 65536/2 */
#define MINUS_INFINITY_GAIN 0
@@ -314,10 +389,14 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
size is the same regardless of the number of channels, and
also the latency to use.
for one direction !!!
+ => need to mupltiply by 2!!
*/
-#define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
+#define HDSPM_DMA_AREA_BYTES (2 * HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
#define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024)
+/* revisions >= 230 indicate AES32 card */
+#define HDSPM_AESREVISION 230
+
struct hdspm_midi {
struct hdspm *hdspm;
int id;
@@ -336,7 +415,9 @@ struct hdspm {
struct snd_pcm_substream *playback_substream; /* and/or capture stream */
char *card_name; /* for procinfo */
- unsigned short firmware_rev; /* dont know if relevant */
+ unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/
+
+ unsigned char is_aes32; /* indicates if card is AES32 */
int precise_ptr; /* use precise pointers, to be tested */
int monitor_outs; /* set up monitoring outs init flag */
@@ -453,6 +534,15 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm);
static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf,
unsigned int reg, int channels);
+static inline int HDSPM_bit2freq(int n)
+{
+ static int bit2freq_tab[] = { 0, 32000, 44100, 48000, 64000, 88200,
+ 96000, 128000, 176400, 192000 };
+ if (n < 1 || n > 9)
+ return 0;
+ return bit2freq_tab[n];
+}
+
/* Write/read to/from HDSPM with Adresses in Bytes
not words but only 32Bit writes are allowed */
@@ -544,86 +634,105 @@ static inline int snd_hdspm_use_is_exclusive(struct hdspm * hdspm)
/* check for external sample rate */
static inline int hdspm_external_sample_rate(struct hdspm * hdspm)
{
- unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
- unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
- unsigned int rate_bits;
- int rate = 0;
+ if (hdspm->is_aes32) {
+ unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
+ unsigned int timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
+
+ int syncref = hdspm_autosync_ref(hdspm);
+
+ if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD &&
+ status & HDSPM_AES32_wcLock)
+ return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF);
+ if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 &&
+ syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 &&
+ status2 & (HDSPM_LockAES >>
+ (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)))
+ return HDSPM_bit2freq((timecode >>
+ (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF);
+ return 0;
+ } else {
+ unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
+ unsigned int rate_bits;
+ int rate = 0;
- /* if wordclock has synced freq and wordclock is valid */
- if ((status2 & HDSPM_wcLock) != 0 &&
- (status & HDSPM_SelSyncRef0) == 0) {
+ /* if wordclock has synced freq and wordclock is valid */
+ if ((status2 & HDSPM_wcLock) != 0 &&
+ (status & HDSPM_SelSyncRef0) == 0) {
- rate_bits = status2 & HDSPM_wcFreqMask;
+ rate_bits = status2 & HDSPM_wcFreqMask;
- switch (rate_bits) {
- case HDSPM_wcFreq32:
- rate = 32000;
- break;
- case HDSPM_wcFreq44_1:
- rate = 44100;
- break;
- case HDSPM_wcFreq48:
- rate = 48000;
- break;
- case HDSPM_wcFreq64:
- rate = 64000;
- break;
- case HDSPM_wcFreq88_2:
- rate = 88200;
- break;
- case HDSPM_wcFreq96:
- rate = 96000;
- break;
- /* Quadspeed Bit missing ???? */
- default:
- rate = 0;
- break;
+ switch (rate_bits) {
+ case HDSPM_wcFreq32:
+ rate = 32000;
+ break;
+ case HDSPM_wcFreq44_1:
+ rate = 44100;
+ break;
+ case HDSPM_wcFreq48:
+ rate = 48000;
+ break;
+ case HDSPM_wcFreq64:
+ rate = 64000;
+ break;
+ case HDSPM_wcFreq88_2:
+ rate = 88200;
+ break;
+ case HDSPM_wcFreq96:
+ rate = 96000;
+ break;
+ /* Quadspeed Bit missing ???? */
+ default:
+ rate = 0;
+ break;
+ }
}
- }
- /* if rate detected and Syncref is Word than have it, word has priority to MADI */
- if (rate != 0
- && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
- return rate;
+ /* if rate detected and Syncref is Word than have it, word has priority to MADI */
+ if (rate != 0 &&
+ (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
+ return rate;
- /* maby a madi input (which is taken if sel sync is madi) */
- if (status & HDSPM_madiLock) {
- rate_bits = status & HDSPM_madiFreqMask;
+ /* maby a madi input (which is taken if sel sync is madi) */
+ if (status & HDSPM_madiLock) {
+ rate_bits = status & HDSPM_madiFreqMask;
- switch (rate_bits) {
- case HDSPM_madiFreq32:
- rate = 32000;
- break;
- case HDSPM_madiFreq44_1:
- rate = 44100;
- break;
- case HDSPM_madiFreq48:
- rate = 48000;
- break;
- case HDSPM_madiFreq64:
- rate = 64000;
- break;
- case HDSPM_madiFreq88_2:
- rate = 88200;
- break;
- case HDSPM_madiFreq96:
- rate = 96000;
- break;
- case HDSPM_madiFreq128:
- rate = 128000;
- break;
- case HDSPM_madiFreq176_4:
- rate = 176400;
- break;
- case HDSPM_madiFreq192:
- rate = 192000;
- break;
- default:
- rate = 0;
- break;
+ switch (rate_bits) {
+ case HDSPM_madiFreq32:
+ rate = 32000;
+ break;
+ case HDSPM_madiFreq44_1:
+ rate = 44100;
+ break;
+ case HDSPM_madiFreq48:
+ rate = 48000;
+ break;
+ case HDSPM_madiFreq64:
+ rate = 64000;
+ break;
+ case HDSPM_madiFreq88_2:
+ rate = 88200;
+ break;
+ case HDSPM_madiFreq96:
+ rate = 96000;
+ break;
+ case HDSPM_madiFreq128:
+ rate = 128000;
+ break;
+ case HDSPM_madiFreq176_4:
+ rate = 176400;
+ break;
+ case HDSPM_madiFreq192:
+ rate = 192000;
+ break;
+ default:
+ rate = 0;
+ break;
+ }
}
+ return rate;
}
- return rate;
}
/* Latency function */
@@ -676,7 +785,8 @@ static inline void hdspm_silence_playback(struct hdspm * hdspm)
int n = hdspm->period_bytes;
void *buf = hdspm->playback_buffer;
- snd_assert(buf != NULL, return);
+ if (buf == NULL)
+ return;
for (i = 0; i < HDSPM_MAX_CHANNELS; i++) {
memset(buf, 0, n);
@@ -716,6 +826,7 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
int current_rate;
int rate_bits;
int not_set = 0;
+ int is_single, is_double, is_quad;
/* ASSUMPTION: hdspm->lock is either set, or there is no need for
it (e.g. during module initialization).
@@ -766,43 +877,56 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
changes in the read/write routines.
*/
+ is_single = (current_rate <= 48000);
+ is_double = (current_rate > 48000 && current_rate <= 96000);
+ is_quad = (current_rate > 96000);
+
switch (rate) {
case 32000:
- if (current_rate > 48000) {
+ if (!is_single)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency32KHz;
break;
case 44100:
- if (current_rate > 48000) {
+ if (!is_single)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency44_1KHz;
break;
case 48000:
- if (current_rate > 48000) {
+ if (!is_single)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency48KHz;
break;
case 64000:
- if (current_rate <= 48000) {
+ if (!is_double)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency64KHz;
break;
case 88200:
- if (current_rate <= 48000) {
+ if (!is_double)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency88_2KHz;
break;
case 96000:
- if (current_rate <= 48000) {
+ if (!is_double)
reject_if_open = 1;
- }
rate_bits = HDSPM_Frequency96KHz;
break;
+ case 128000:
+ if (!is_quad)
+ reject_if_open = 1;
+ rate_bits = HDSPM_Frequency128KHz;
+ break;
+ case 176400:
+ if (!is_quad)
+ reject_if_open = 1;
+ rate_bits = HDSPM_Frequency176_4KHz;
+ break;
+ case 192000:
+ if (!is_quad)
+ reject_if_open = 1;
+ rate_bits = HDSPM_Frequency192KHz;
+ break;
default:
return -EINVAL;
}
@@ -819,7 +943,7 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
hdspm->control_register |= rate_bits;
hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
- if (rate > 64000)
+ if (rate > 96000 /* 64000*/)
hdspm->channel_map = channel_map_madi_qs;
else if (rate > 48000)
hdspm->channel_map = channel_map_madi_ds;
@@ -1455,11 +1579,27 @@ static int hdspm_pref_sync_ref(struct hdspm * hdspm)
/* Notice that this looks at the requested sync source,
not the one actually in use.
*/
- switch (hdspm->control_register & HDSPM_SyncRefMask) {
- case HDSPM_SyncRef_Word:
- return HDSPM_SYNC_FROM_WORD;
- case HDSPM_SyncRef_MADI:
- return HDSPM_SYNC_FROM_MADI;
+ if (hdspm->is_aes32) {
+ switch (hdspm->control_register & HDSPM_SyncRefMask) {
+ /* number gives AES index, except for 0 which
+ corresponds to WordClock */
+ case 0: return 0;
+ case HDSPM_SyncRef0: return 1;
+ case HDSPM_SyncRef1: return 2;
+ case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3;
+ case HDSPM_SyncRef2: return 4;
+ case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5;
+ case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6;
+ case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0: return 7;
+ case HDSPM_SyncRef3: return 8;
+ }
+ } else {
+ switch (hdspm->control_register & HDSPM_SyncRefMask) {
+ case HDSPM_SyncRef_Word:
+ return HDSPM_SYNC_FROM_WORD;
+ case HDSPM_SyncRef_MADI:
+ return HDSPM_SYNC_FROM_MADI;
+ }
}
return HDSPM_SYNC_FROM_WORD;
@@ -1469,15 +1609,49 @@ static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref)
{
hdspm->control_register &= ~HDSPM_SyncRefMask;
- switch (pref) {
- case HDSPM_SYNC_FROM_MADI:
- hdspm->control_register |= HDSPM_SyncRef_MADI;
- break;
- case HDSPM_SYNC_FROM_WORD:
- hdspm->control_register |= HDSPM_SyncRef_Word;
- break;
- default:
- return -1;
+ if (hdspm->is_aes32) {
+ switch (pref) {
+ case 0:
+ hdspm->control_register |= 0;
+ break;
+ case 1:
+ hdspm->control_register |= HDSPM_SyncRef0;
+ break;
+ case 2:
+ hdspm->control_register |= HDSPM_SyncRef1;
+ break;
+ case 3:
+ hdspm->control_register |= HDSPM_SyncRef1+HDSPM_SyncRef0;
+ break;
+ case 4:
+ hdspm->control_register |= HDSPM_SyncRef2;
+ break;
+ case 5:
+ hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef0;
+ break;
+ case 6:
+ hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1;
+ break;
+ case 7:
+ hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0;
+ break;
+ case 8:
+ hdspm->control_register |= HDSPM_SyncRef3;
+ break;
+ default:
+ return -1;
+ }
+ } else {
+ switch (pref) {
+ case HDSPM_SYNC_FROM_MADI:
+ hdspm->control_register |= HDSPM_SyncRef_MADI;
+ break;
+ case HDSPM_SYNC_FROM_WORD:
+ hdspm->control_register |= HDSPM_SyncRef_Word;
+ break;
+ default:
+ return -1;
+ }
}
hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
return 0;
@@ -1486,18 +1660,36 @@ static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref)
static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "Word", "MADI" };
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
+ if (hdspm->is_aes32) {
+ static char *texts[] = { "Word", "AES1", "AES2", "AES3",
+ "AES4", "AES5", "AES6", "AES7", "AES8" };
- uinfo->value.enumerated.items = 2;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
+ uinfo->value.enumerated.items = 9;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ } else {
+ static char *texts[] = { "Word", "MADI" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+
+ uinfo->value.enumerated.items = 2;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ }
return 0;
}
@@ -1517,7 +1709,7 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
int change, max;
unsigned int val;
- max = 2;
+ max = hdspm->is_aes32 ? 9 : 2;
if (!snd_hdspm_use_is_exclusive(hdspm))
return -EBUSY;
@@ -1542,40 +1734,64 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
static int hdspm_autosync_ref(struct hdspm * hdspm)
{
- /* This looks at the autosync selected sync reference */
- unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
-
- switch (status2 & HDSPM_SelSyncRefMask) {
-
- case HDSPM_SelSyncRef_WORD:
- return HDSPM_AUTOSYNC_FROM_WORD;
-
- case HDSPM_SelSyncRef_MADI:
- return HDSPM_AUTOSYNC_FROM_MADI;
-
- case HDSPM_SelSyncRef_NVALID:
- return HDSPM_AUTOSYNC_FROM_NONE;
+ if (hdspm->is_aes32) {
+ unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
+ unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF;
+ if (syncref == 0)
+ return HDSPM_AES32_AUTOSYNC_FROM_WORD;
+ if (syncref <= 8)
+ return syncref;
+ return HDSPM_AES32_AUTOSYNC_FROM_NONE;
+ } else {
+ /* This looks at the autosync selected sync reference */
+ unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+
+ switch (status2 & HDSPM_SelSyncRefMask) {
+ case HDSPM_SelSyncRef_WORD:
+ return HDSPM_AUTOSYNC_FROM_WORD;
+ case HDSPM_SelSyncRef_MADI:
+ return HDSPM_AUTOSYNC_FROM_MADI;
+ case HDSPM_SelSyncRef_NVALID:
+ return HDSPM_AUTOSYNC_FROM_NONE;
+ default:
+ return 0;
+ }
- default:
return 0;
}
-
- return 0;
}
static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "WordClock", "MADI", "None" };
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
+ if (hdspm->is_aes32) {
+ static char *texts[] = { "WordClock", "AES1", "AES2", "AES3",
+ "AES4", "AES5", "AES6", "AES7", "AES8", "None"};
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 10;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ }
+ else
+ {
+ static char *texts[] = { "WordClock", "MADI", "None" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ }
return 0;
}
@@ -1841,6 +2057,195 @@ static int snd_hdspm_put_safe_mode(struct snd_kcontrol *kcontrol,
return change;
}
+#define HDSPM_EMPHASIS(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_emphasis, \
+ .get = snd_hdspm_get_emphasis, \
+ .put = snd_hdspm_put_emphasis \
+}
+
+static int hdspm_emphasis(struct hdspm * hdspm)
+{
+ return (hdspm->control_register & HDSPM_Emphasis) ? 1 : 0;
+}
+
+static int hdspm_set_emphasis(struct hdspm * hdspm, int emp)
+{
+ if (emp)
+ hdspm->control_register |= HDSPM_Emphasis;
+ else
+ hdspm->control_register &= ~HDSPM_Emphasis;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_emphasis(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_hdspm_get_emphasis(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.enumerated.item[0] = hdspm_emphasis(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_emphasis(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_emphasis(hdspm);
+ hdspm_set_emphasis(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_DOLBY(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_dolby, \
+ .get = snd_hdspm_get_dolby, \
+ .put = snd_hdspm_put_dolby \
+}
+
+static int hdspm_dolby(struct hdspm * hdspm)
+{
+ return (hdspm->control_register & HDSPM_Dolby) ? 1 : 0;
+}
+
+static int hdspm_set_dolby(struct hdspm * hdspm, int dol)
+{
+ if (dol)
+ hdspm->control_register |= HDSPM_Dolby;
+ else
+ hdspm->control_register &= ~HDSPM_Dolby;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_dolby(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_hdspm_get_dolby(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.enumerated.item[0] = hdspm_dolby(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_dolby(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_dolby(hdspm);
+ hdspm_set_dolby(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_PROFESSIONAL(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_professional, \
+ .get = snd_hdspm_get_professional, \
+ .put = snd_hdspm_put_professional \
+}
+
+static int hdspm_professional(struct hdspm * hdspm)
+{
+ return (hdspm->control_register & HDSPM_Professional) ? 1 : 0;
+}
+
+static int hdspm_set_professional(struct hdspm * hdspm, int dol)
+{
+ if (dol)
+ hdspm->control_register |= HDSPM_Professional;
+ else
+ hdspm->control_register &= ~HDSPM_Professional;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_professional(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_hdspm_get_professional(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.enumerated.item[0] = hdspm_professional(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_professional(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_professional(hdspm);
+ hdspm_set_professional(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
#define HDSPM_INPUT_SELECT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -1912,6 +2317,163 @@ static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol,
return change;
}
+#define HDSPM_DS_WIRE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_ds_wire, \
+ .get = snd_hdspm_get_ds_wire, \
+ .put = snd_hdspm_put_ds_wire \
+}
+
+static int hdspm_ds_wire(struct hdspm * hdspm)
+{
+ return (hdspm->control_register & HDSPM_DS_DoubleWire) ? 1 : 0;
+}
+
+static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds)
+{
+ if (ds)
+ hdspm->control_register |= HDSPM_DS_DoubleWire;
+ else
+ hdspm->control_register &= ~HDSPM_DS_DoubleWire;
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = { "Single", "Double" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_ds_wire(hdspm);
+ hdspm_set_ds_wire(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
+#define HDSPM_QS_WIRE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_qs_wire, \
+ .get = snd_hdspm_get_qs_wire, \
+ .put = snd_hdspm_put_qs_wire \
+}
+
+static int hdspm_qs_wire(struct hdspm * hdspm)
+{
+ if (hdspm->control_register & HDSPM_QS_DoubleWire)
+ return 1;
+ if (hdspm->control_register & HDSPM_QS_QuadWire)
+ return 2;
+ return 0;
+}
+
+static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode)
+{
+ hdspm->control_register &= ~(HDSPM_QS_DoubleWire | HDSPM_QS_QuadWire);
+ switch (mode) {
+ case 0:
+ break;
+ case 1:
+ hdspm->control_register |= HDSPM_QS_DoubleWire;
+ break;
+ case 2:
+ hdspm->control_register |= HDSPM_QS_QuadWire;
+ break;
+ }
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ return 0;
+}
+
+static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = { "Single", "Double", "Quad" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ spin_lock_irq(&hdspm->lock);
+ ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm);
+ spin_unlock_irq(&hdspm->lock);
+ return 0;
+}
+
+static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int change;
+ int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0];
+ if (val < 0)
+ val = 0;
+ if (val > 2)
+ val = 2;
+ spin_lock_irq(&hdspm->lock);
+ change = (int) val != hdspm_qs_wire(hdspm);
+ hdspm_set_qs_wire(hdspm, val);
+ spin_unlock_irq(&hdspm->lock);
+ return change;
+}
+
/* Simple Mixer
deprecated since to much faders ???
MIXER interface says output (source, destination, value)
@@ -2135,14 +2697,24 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
static int hdspm_wc_sync_check(struct hdspm * hdspm)
{
- int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
- if (status2 & HDSPM_wcLock) {
- if (status2 & HDSPM_wcSync)
+ if (hdspm->is_aes32) {
+ int status = hdspm_read(hdspm, HDSPM_statusRegister);
+ if (status & HDSPM_AES32_wcLock) {
+ /* I don't know how to differenciate sync from lock.
+ Doing as if sync for now */
return 2;
- else
- return 1;
+ }
+ return 0;
+ } else {
+ int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ if (status2 & HDSPM_wcLock) {
+ if (status2 & HDSPM_wcSync)
+ return 2;
+ else
+ return 1;
+ }
+ return 0;
}
- return 0;
}
static int snd_hdspm_get_wc_sync_check(struct snd_kcontrol *kcontrol,
@@ -2188,9 +2760,43 @@ static int snd_hdspm_get_madisync_sync_check(struct snd_kcontrol *kcontrol,
}
+#define HDSPM_AES_SYNC_CHECK(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_sync_check, \
+ .get = snd_hdspm_get_aes_sync_check \
+}
+
+static int hdspm_aes_sync_check(struct hdspm * hdspm, int idx)
+{
+ int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ if (status2 & (HDSPM_LockAES >> idx)) {
+ /* I don't know how to differenciate sync from lock.
+ Doing as if sync for now */
+ return 2;
+ }
+ return 0;
+}
+
+static int snd_hdspm_get_aes_sync_check(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int offset;
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ offset = ucontrol->id.index - 1;
+ if (offset < 0 || offset >= 8)
+ return -EINVAL;
+
+ ucontrol->value.enumerated.item[0] =
+ hdspm_aes_sync_check(hdspm, offset);
+ return 0;
+}
-static struct snd_kcontrol_new snd_hdspm_controls[] = {
+static struct snd_kcontrol_new snd_hdspm_controls_madi[] = {
HDSPM_MIXER("Mixer", 0),
/* 'Sample Clock Source' complies with the alsa control naming scheme */
@@ -2211,6 +2817,29 @@ static struct snd_kcontrol_new snd_hdspm_controls[] = {
HDSPM_INPUT_SELECT("Input Select", 0),
};
+static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
+
+ HDSPM_MIXER("Mixer", 0),
+/* 'Sample Clock Source' complies with the alsa control naming scheme */
+ HDSPM_CLOCK_SOURCE("Sample Clock Source", 0),
+
+ HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
+ HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
+ HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
+ HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
+/* 'External Rate' complies with the alsa control naming scheme */
+ HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
+ HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0),
+/* HDSPM_AES_SYNC_CHECK("AES Lock Status", 0),*/ /* created in snd_hdspm_create_controls() */
+ HDSPM_LINE_OUT("Line Out", 0),
+ HDSPM_EMPHASIS("Emphasis", 0),
+ HDSPM_DOLBY("Non Audio", 0),
+ HDSPM_PROFESSIONAL("Professional", 0),
+ HDSPM_C_TMS("Clear Track Marker", 0),
+ HDSPM_DS_WIRE("Double Speed Wire Mode", 0),
+ HDSPM_QS_WIRE("Quad Speed Wire Mode", 0),
+};
+
static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER;
@@ -2245,20 +2874,40 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm
struct snd_kcontrol *kctl;
/* add control list first */
-
- for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls); idx++) {
- if ((err =
- snd_ctl_add(card, kctl =
- snd_ctl_new1(&snd_hdspm_controls[idx],
- hdspm))) < 0) {
- return err;
+ if (hdspm->is_aes32) {
+ struct snd_kcontrol_new aes_sync_ctl =
+ HDSPM_AES_SYNC_CHECK("AES Lock Status", 0);
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_aes32);
+ idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_hdspm_controls_aes32[idx],
+ hdspm));
+ if (err < 0)
+ return err;
+ }
+ for (idx = 1; idx <= 8; idx++) {
+ aes_sync_ctl.index = idx;
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&aes_sync_ctl, hdspm));
+ if (err < 0)
+ return err;
+ }
+ } else {
+ for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_madi);
+ idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_hdspm_controls_madi[idx],
+ hdspm));
+ if (err < 0)
+ return err;
}
}
/* Channel playback mixer as default control
- Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer
- they are accesible via special IOCTL on hwdep
- and the mixer 2dimensional mixer control */
+Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer
+they are accesible via special IOCTL on hwdep
+and the mixer 2dimensional mixer control */
snd_hdspm_playback_mixer.name = "Chn";
limit = HDSPM_MAX_CHANNELS;
@@ -2289,7 +2938,8 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm
------------------------------------------------------------*/
static void
-snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer)
+snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
+ struct snd_info_buffer *buffer)
{
struct hdspm *hdspm = (struct hdspm *) entry->private_data;
unsigned int status;
@@ -2420,11 +3070,10 @@ snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffe
clock_source = "Error";
}
snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source);
- if (!(hdspm->control_register & HDSPM_ClockModeMaster)) {
+ if (!(hdspm->control_register & HDSPM_ClockModeMaster))
system_clock_mode = "Slave";
- } else {
+ else
system_clock_mode = "Master";
- }
snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode);
switch (hdspm_pref_sync_ref(hdspm)) {
@@ -2484,13 +3133,213 @@ snd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffe
snd_iprintf(buffer, "\n");
}
+static void
+snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdspm *hdspm = (struct hdspm *) entry->private_data;
+ unsigned int status;
+ unsigned int status2;
+ unsigned int timecode;
+ int pref_syncref;
+ char *autosync_ref;
+ char *system_clock_mode;
+ char *clock_source;
+ int x;
+
+ status = hdspm_read(hdspm, HDSPM_statusRegister);
+ status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
+
+ snd_iprintf(buffer, "%s (Card #%d) Rev.%x\n",
+ hdspm->card_name, hdspm->card->number + 1,
+ hdspm->firmware_rev);
+
+ snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
+ hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
+
+ snd_iprintf(buffer, "--- System ---\n");
+
+ snd_iprintf(buffer,
+ "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
+ status & HDSPM_audioIRQPending,
+ (status & HDSPM_midi0IRQPending) ? 1 : 0,
+ (status & HDSPM_midi1IRQPending) ? 1 : 0,
+ hdspm->irq_count);
+ snd_iprintf(buffer,
+ "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n",
+ ((status & HDSPM_BufferID) ? 1 : 0),
+ (status & HDSPM_BufferPositionMask),
+ (status & HDSPM_BufferPositionMask) % (2 *
+ (int)hdspm->
+ period_bytes),
+ ((status & HDSPM_BufferPositionMask) -
+ 64) % (2 * (int)hdspm->period_bytes),
+ (long) hdspm_hw_pointer(hdspm) * 4);
+
+ snd_iprintf(buffer,
+ "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
+ hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
+ snd_iprintf(buffer,
+ "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x, timecode=0x%x\n",
+ hdspm->control_register, hdspm->control2_register,
+ status, status2, timecode);
+
+ snd_iprintf(buffer, "--- Settings ---\n");
+
+ x = 1 << (6 +
+ hdspm_decode_latency(hdspm->
+ control_register &
+ HDSPM_LatencyMask));
+
+ snd_iprintf(buffer,
+ "Size (Latency): %d samples (2 periods of %lu bytes)\n",
+ x, (unsigned long) hdspm->period_bytes);
+
+ snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n",
+ (hdspm->
+ control_register & HDSPM_LineOut) ? "on " : "off",
+ (hdspm->precise_ptr) ? "on" : "off");
+
+ snd_iprintf(buffer,
+ "ClearTrackMarker %s, Emphasis %s, Dolby %s\n",
+ (hdspm->
+ control_register & HDSPM_clr_tms) ? "on" : "off",
+ (hdspm->
+ control_register & HDSPM_Emphasis) ? "on" : "off",
+ (hdspm->
+ control_register & HDSPM_Dolby) ? "on" : "off");
+
+ switch (hdspm_clock_source(hdspm)) {
+ case HDSPM_CLOCK_SOURCE_AUTOSYNC:
+ clock_source = "AutoSync";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ:
+ clock_source = "Internal 32 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ:
+ clock_source = "Internal 44.1 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ:
+ clock_source = "Internal 48 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ:
+ clock_source = "Internal 64 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ:
+ clock_source = "Internal 88.2 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ:
+ clock_source = "Internal 96 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ:
+ clock_source = "Internal 128 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ:
+ clock_source = "Internal 176.4 kHz";
+ break;
+ case HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ:
+ clock_source = "Internal 192 kHz";
+ break;
+ default:
+ clock_source = "Error";
+ }
+ snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source);
+ if (!(hdspm->control_register & HDSPM_ClockModeMaster))
+ system_clock_mode = "Slave";
+ else
+ system_clock_mode = "Master";
+ snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode);
+
+ pref_syncref = hdspm_pref_sync_ref(hdspm);
+ if (pref_syncref == 0)
+ snd_iprintf(buffer, "Preferred Sync Reference: Word Clock\n");
+ else
+ snd_iprintf(buffer, "Preferred Sync Reference: AES%d\n",
+ pref_syncref);
+
+ snd_iprintf(buffer, "System Clock Frequency: %d\n",
+ hdspm->system_sample_rate);
+
+ snd_iprintf(buffer, "Double speed: %s\n",
+ hdspm->control_register & HDSPM_DS_DoubleWire?
+ "Double wire" : "Single wire");
+ snd_iprintf(buffer, "Quad speed: %s\n",
+ hdspm->control_register & HDSPM_QS_DoubleWire?
+ "Double wire" :
+ hdspm->control_register & HDSPM_QS_QuadWire?
+ "Quad wire" : "Single wire");
+
+ snd_iprintf(buffer, "--- Status:\n");
+
+ snd_iprintf(buffer, "Word: %s Frequency: %d\n",
+ (status & HDSPM_AES32_wcLock)? "Sync " : "No Lock",
+ HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF));
+
+ for (x = 0; x < 8; x++) {
+ snd_iprintf(buffer, "AES%d: %s Frequency: %d\n",
+ x+1,
+ (status2 & (HDSPM_LockAES >> x))? "Sync ": "No Lock",
+ HDSPM_bit2freq((timecode >> (4*x)) & 0xF));
+ }
+
+ switch (hdspm_autosync_ref(hdspm)) {
+ case HDSPM_AES32_AUTOSYNC_FROM_NONE: autosync_ref="None"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_WORD: autosync_ref="Word Clock"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES1: autosync_ref="AES1"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES2: autosync_ref="AES2"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES3: autosync_ref="AES3"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES4: autosync_ref="AES4"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES5: autosync_ref="AES5"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES6: autosync_ref="AES6"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES7: autosync_ref="AES7"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES8: autosync_ref="AES8"; break;
+ default: autosync_ref = "---"; break;
+ }
+ snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref);
+
+ snd_iprintf(buffer, "\n");
+}
+
+#ifdef CONFIG_SND_DEBUG
+static void
+snd_hdspm_proc_read_debug(struct snd_info_entry * entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdspm *hdspm = (struct hdspm *)entry->private_data;
+
+ int j,i;
+
+ for (i = 0; i < 256 /* 1024*64 */; i += j)
+ {
+ snd_iprintf(buffer, "0x%08X: ", i);
+ for (j = 0; j < 16; j += 4)
+ snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j));
+ snd_iprintf(buffer, "\n");
+ }
+}
+#endif
+
+
+
static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm)
{
struct snd_info_entry *entry;
if (!snd_card_proc_new(hdspm->card, "hdspm", &entry))
snd_info_set_text_ops(entry, hdspm,
- snd_hdspm_proc_read);
+ hdspm->is_aes32 ?
+ snd_hdspm_proc_read_aes32 :
+ snd_hdspm_proc_read_madi);
+#ifdef CONFIG_SND_DEBUG
+ /* debug file to read all hdspm registers */
+ if (!snd_card_proc_new(hdspm->card, "debug", &entry))
+ snd_info_set_text_ops(entry, hdspm,
+ snd_hdspm_proc_read_debug);
+#endif
}
/*------------------------------------------------------------
@@ -2507,13 +3356,20 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
/* set defaults: */
- hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */
- hdspm_encode_latency(7) | /* latency maximum = 8192 samples */
- HDSPM_InputCoaxial | /* Input Coax not Optical */
- HDSPM_SyncRef_MADI | /* Madi is syncclock */
- HDSPM_LineOut | /* Analog output in */
- HDSPM_TX_64ch | /* transmit in 64ch mode */
- HDSPM_AutoInp; /* AutoInput chossing (takeover) */
+ if (hdspm->is_aes32)
+ hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */
+ hdspm_encode_latency(7) | /* latency maximum = 8192 samples */
+ HDSPM_SyncRef0 | /* AES1 is syncclock */
+ HDSPM_LineOut | /* Analog output in */
+ HDSPM_Professional; /* Professional mode */
+ else
+ hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */
+ hdspm_encode_latency(7) | /* latency maximum = 8192 samples */
+ HDSPM_InputCoaxial | /* Input Coax not Optical */
+ HDSPM_SyncRef_MADI | /* Madi is syncclock */
+ HDSPM_LineOut | /* Analog output in */
+ HDSPM_TX_64ch | /* transmit in 64ch mode */
+ HDSPM_AutoInp; /* AutoInput chossing (takeover) */
/* ! HDSPM_Frequency0|HDSPM_Frequency1 = 44.1khz */
/* ! HDSPM_DoubleSpeed HDSPM_QuadSpeed = normal speed */
@@ -2822,6 +3678,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
hdspm->playback_buffer =
(unsigned char *) substream->runtime->dma_area;
+ snd_printdd("Allocated sample buffer for playback at %p\n",
+ hdspm->playback_buffer);
} else {
hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn,
params_channels(params));
@@ -2831,7 +3689,15 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
hdspm->capture_buffer =
(unsigned char *) substream->runtime->dma_area;
+ snd_printdd("Allocated sample buffer for capture at %p\n",
+ hdspm->capture_buffer);
}
+ /*
+ snd_printdd("Allocated sample buffer for %s at 0x%08X\n",
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "playback" : "capture",
+ snd_pcm_sgbuf_get_addr(sgbuf, 0));
+ */
return 0;
}
@@ -2982,9 +3848,10 @@ static struct snd_pcm_hardware snd_hdspm_playback_subinfo = {
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_64000 |
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ),
.rate_min = 32000,
- .rate_max = 96000,
+ .rate_max = 192000,
.channels_min = 1,
.channels_max = HDSPM_MAX_CHANNELS,
.buffer_bytes_max =
@@ -3006,9 +3873,10 @@ static struct snd_pcm_hardware snd_hdspm_capture_subinfo = {
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_64000 |
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000),
.rate_min = 32000,
- .rate_max = 96000,
+ .rate_max = 192000,
.channels_min = 1,
.channels_max = HDSPM_MAX_CHANNELS,
.buffer_bytes_max =
@@ -3315,7 +4183,8 @@ static int __devinit snd_hdspm_preallocate_memory(struct hdspm * hdspm)
pcm = hdspm->pcm;
- wanted = HDSPM_DMA_AREA_BYTES + 4096; /* dont know why, but it works */
+/* wanted = HDSPM_DMA_AREA_BYTES + 4096;*/ /* dont know why, but it works */
+ wanted = HDSPM_DMA_AREA_BYTES;
if ((err =
snd_pcm_lib_preallocate_pages_for_all(pcm,
@@ -3467,9 +4336,16 @@ static int __devinit snd_hdspm_create(struct snd_card *card, struct hdspm * hdsp
pci_read_config_word(hdspm->pci,
PCI_CLASS_REVISION, &hdspm->firmware_rev);
- strcpy(card->driver, "HDSPM");
+ hdspm->is_aes32 = (hdspm->firmware_rev >= HDSPM_AESREVISION);
+
strcpy(card->mixername, "Xilinx FPGA");
- hdspm->card_name = "RME HDSPM MADI";
+ if (hdspm->is_aes32) {
+ strcpy(card->driver, "HDSPAES32");
+ hdspm->card_name = "RME HDSPM AES32";
+ } else {
+ strcpy(card->driver, "HDSPM");
+ hdspm->card_name = "RME HDSPM MADI";
+ }
if ((err = pci_enable_device(pci)) < 0)
return err;
@@ -3496,8 +4372,7 @@ static int __devinit snd_hdspm_create(struct snd_card *card, struct hdspm * hdsp
hdspm->port + io_extent - 1);
if (request_irq(pci->irq, snd_hdspm_interrupt,
- IRQF_DISABLED | IRQF_SHARED, "hdspm",
- (void *) hdspm)) {
+ IRQF_SHARED, "hdspm", hdspm)) {
snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq);
return -EBUSY;
}
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index cf0427b4bfd..cc3bdececce 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -1827,8 +1827,8 @@ static int __devinit snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652)
/* Align to bus-space 64K boundary */
- cb_bus = (rme9652->capture_dma_buf.addr + 0xFFFF) & ~0xFFFFl;
- pb_bus = (rme9652->playback_dma_buf.addr + 0xFFFF) & ~0xFFFFl;
+ cb_bus = ALIGN(rme9652->capture_dma_buf.addr, 0x10000ul);
+ pb_bus = ALIGN(rme9652->playback_dma_buf.addr, 0x10000ul);
/* Tell the card where it is */
@@ -2500,7 +2500,8 @@ static int __devinit snd_rme9652_create(struct snd_card *card,
return -EBUSY;
}
- if (request_irq(pci->irq, snd_rme9652_interrupt, IRQF_DISABLED|IRQF_SHARED, "rme9652", (void *)rme9652)) {
+ if (request_irq(pci->irq, snd_rme9652_interrupt, IRQF_SHARED,
+ "rme9652", rme9652)) {
snd_printk(KERN_ERR "unable to request IRQ %d\n", pci->irq);
return -EBUSY;
}
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index f9b8afabda9..9f25d93cbec 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -1195,7 +1195,7 @@ static int snd_sonicvibes_free(struct sonicvibes *sonic)
pci_write_config_dword(sonic->pci, 0x40, sonic->dmaa_port);
pci_write_config_dword(sonic->pci, 0x48, sonic->dmac_port);
if (sonic->irq >= 0)
- free_irq(sonic->irq, (void *)sonic);
+ free_irq(sonic->irq, sonic);
release_and_free_resource(sonic->res_dmaa);
release_and_free_resource(sonic->res_dmac);
pci_release_regions(sonic->pci);
@@ -1257,7 +1257,8 @@ static int __devinit snd_sonicvibes_create(struct snd_card *card,
sonic->midi_port = pci_resource_start(pci, 3);
sonic->game_port = pci_resource_start(pci, 4);
- if (request_irq(pci->irq, snd_sonicvibes_interrupt, IRQF_DISABLED|IRQF_SHARED, "S3 SonicVibes", (void *)sonic)) {
+ if (request_irq(pci->irq, snd_sonicvibes_interrupt, IRQF_SHARED,
+ "S3 SonicVibes", sonic)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_sonicvibes_free(sonic);
return -EBUSY;
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 1fbc4321122..3bff32167f6 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -2627,7 +2627,7 @@ static int snd_trident_vol_control_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0);
static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -2844,7 +2844,7 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol,
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1);
static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata =
{
@@ -3380,8 +3380,8 @@ static int __devinit snd_trident_tlb_alloc(struct snd_trident *trident)
snd_printk(KERN_ERR "trident: unable to allocate TLB buffer\n");
return -ENOMEM;
}
- trident->tlb.entries = (unsigned int*)(((unsigned long)trident->tlb.buffer.area + SNDRV_TRIDENT_MAX_PAGES * 4 - 1) & ~(SNDRV_TRIDENT_MAX_PAGES * 4 - 1));
- trident->tlb.entries_dmaaddr = (trident->tlb.buffer.addr + SNDRV_TRIDENT_MAX_PAGES * 4 - 1) & ~(SNDRV_TRIDENT_MAX_PAGES * 4 - 1);
+ trident->tlb.entries = (unsigned int*)ALIGN((unsigned long)trident->tlb.buffer.area, SNDRV_TRIDENT_MAX_PAGES * 4);
+ trident->tlb.entries_dmaaddr = ALIGN(trident->tlb.buffer.addr, SNDRV_TRIDENT_MAX_PAGES * 4);
/* allocate shadow TLB page table (virtual addresses) */
trident->tlb.shadow_entries = vmalloc(SNDRV_TRIDENT_MAX_PAGES*sizeof(unsigned long));
if (trident->tlb.shadow_entries == NULL) {
@@ -3608,7 +3608,7 @@ int __devinit snd_trident_create(struct snd_card *card,
}
trident->port = pci_resource_start(pci, 0);
- if (request_irq(pci->irq, snd_trident_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_trident_interrupt, IRQF_SHARED,
"Trident Audio", trident)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_trident_free(trident);
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 92b0736c0fd..a28992269f5 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1699,7 +1699,7 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol,
return change;
}
-static DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1);
static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = {
.name = "PCM Playback Volume",
@@ -1823,7 +1823,7 @@ static int __devinit snd_via82xx_mixer_new(struct via82xx *chip, const char *qui
ac97.private_data = chip;
ac97.private_free = snd_via82xx_mixer_free_ac97;
ac97.pci = chip->pci;
- ac97.scaps = AC97_SCAP_SKIP_MODEM;
+ ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE;
if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0)
return err;
@@ -2307,7 +2307,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card,
if (request_irq(pci->irq,
chip_type == TYPE_VIA8233 ?
snd_via8233_interrupt : snd_via686_interrupt,
- IRQF_DISABLED|IRQF_SHARED,
+ IRQF_SHARED,
card->driver, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_via82xx_free(chip);
@@ -2357,93 +2357,59 @@ static struct via823x_info via823x_cards[] __devinitdata = {
/*
* auto detection of DXS channel supports.
*/
-struct dxs_whitelist {
- unsigned short subvendor;
- unsigned short subdevice;
- unsigned short mask;
- short action; /* new dxs_support value */
+
+static struct snd_pci_quirk dxs_whitelist[] __devinitdata = {
+ SND_PCI_QUIRK(0x1005, 0x4710, "Avance Logic Mobo", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1019, 0x0996, "ESC Mobo", VIA_DXS_48K),
+ SND_PCI_QUIRK(0x1019, 0x0a81, "ECS K7VTA3 v8.0", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x1019, 0x0a85, "ECS L7VMM2", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x1019, 0, "ESC K8", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1019, 0xaa01, "ESC K8T890-A", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1025, 0x0033, "Acer Inspire 1353LM", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x1025, 0x0046, "Acer Aspire 1524 WLMi", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1043, 0, "ASUS A7/A8", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x1071, 0, "Diverse Notebook", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte GA-7VAXP", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1462, 0x7142, "MSI K8MM-V", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1462, 0, "MSI Mobo", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x147b, 0x1401, "ABIT KD7(-RAID)", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x147b, 0x1411, "ABIT VA-20", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x147b, 0x1413, "ABIT KV8 Pro", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x147b, 0x1415, "ABIT AV8", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x14ff, 0x0403, "Twinhead mobo", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x14ff, 0x0408, "Twinhead laptop", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1558, 0x4701, "Clevo D470", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1584, 0x8120, "Diverse Laptop", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1584, 0x8123, "Targa/Uniwill", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x161f, 0x202b, "Amira Notebook", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x161f, 0x2032, "m680x machines", VIA_DXS_48K),
+ SND_PCI_QUIRK(0x1631, 0xe004, "PB EasyNote 3174", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1695, 0x3005, "EPoX EP-8K9A", VIA_DXS_ENABLE),
+ SND_PCI_QUIRK(0x1695, 0, "EPoX mobo", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x16f3, 0, "Jetway K8", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1734, 0, "FSC Laptop", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1849, 0x3059, "ASRock K7VM2", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x1849, 0, "ASRock mobo", VIA_DXS_SRC),
+ SND_PCI_QUIRK(0x1919, 0x200a, "Soltek SL-K8", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK(0x4005, 0x4710, "MSI K7T266", VIA_DXS_SRC),
+ { } /* terminator */
};
static int __devinit check_dxs_list(struct pci_dev *pci, int revision)
{
- static struct dxs_whitelist whitelist[] = {
- { .subvendor = 0x1005, .subdevice = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */
- { .subvendor = 0x1019, .subdevice = 0x0996, .action = VIA_DXS_48K },
- { .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */
- { .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */
- { .subvendor = 0x1019, .subdevice = 0xa101, .action = VIA_DXS_SRC },
- { .subvendor = 0x1019, .subdevice = 0xaa01, .action = VIA_DXS_SRC }, /* ECS K8T890-A */
- { .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */
- { .subvendor = 0x1025, .subdevice = 0x0046, .action = VIA_DXS_SRC }, /* Acer Aspire 1524 WLMi */
- { .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
- { .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
- { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/
- { .subvendor = 0x1043, .subdevice = 0x810d, .action = VIA_DXS_SRC }, /* ASUS */
- { .subvendor = 0x1043, .subdevice = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */
- { .subvendor = 0x1043, .subdevice = 0x8174, .action = VIA_DXS_SRC }, /* ASUS */
- { .subvendor = 0x1043, .subdevice = 0x81b9, .action = VIA_DXS_SRC }, /* ASUS A8V-MX */
- { .subvendor = 0x1071, .subdevice = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */
- { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_NO_VRA }, /* Umax AB 595T (VIA K8N800A - VT8237) */
- { .subvendor = 0x10cf, .subdevice = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */
- { .subvendor = 0x1106, .subdevice = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */
- { .subvendor = 0x1106, .subdevice = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */
- { .subvendor = 0x1106, .subdevice = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */
- { .subvendor = 0x1106, .subdevice = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */
- { .subvendor = 0x1297, .subdevice = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */
- { .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
- { .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
- { .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */
- { .subvendor = 0x1462, .subdevice = 0x0430, .action = VIA_DXS_SRC }, /* MSI 7142 (K8MM-V) */
- { .subvendor = 0x1462, .subdevice = 0x0470, .action = VIA_DXS_SRC }, /* MSI KT880 Delta-FSR */
- { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
- { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
- { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_SRC }, /* MSI K8T Neo2-FI */
- { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
- { .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */
- { .subvendor = 0x1462, .subdevice = 0xb012, .action = VIA_DXS_SRC }, /* P4M800/VIA8237R */
- { .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
- { .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */
- { .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */
- { .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */
- { .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
- { .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_SRC }, /* Twinhead laptop */
- { .subvendor = 0x1558, .subdevice = 0x4701, .action = VIA_DXS_SRC }, /* Clevo D470 */
- { .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */
- { .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */
- { .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */
- { .subvendor = 0x161f, .subdevice = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */
- { .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */
- { .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
- { .subvendor = 0x1695, .subdevice = 0x300c, .action = VIA_DXS_SRC }, /* EPoX EP-8KRAI */
- { .subvendor = 0x1695, .subdevice = 0x300e, .action = VIA_DXS_SRC }, /* EPoX 9HEAI */
- { .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */
- { .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */
- { .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */
- { .subvendor = 0x1734, .subdevice = 0x10ab, .action = VIA_DXS_SRC }, /* FSC */
- { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
- { .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
- { .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
- { .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */
- { .subvendor = 0x4005, .subdevice = 0x4710, .action = VIA_DXS_SRC }, /* MSI K7T266 Pro2 (MS-6380 V2.0) BIOS 3.7 */
- { } /* terminator */
- };
- struct dxs_whitelist *w;
- unsigned short subsystem_vendor;
- unsigned short subsystem_device;
-
- pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
- pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);
+ const struct snd_pci_quirk *w;
- for (w = whitelist; w->subvendor; w++) {
- if (w->subvendor != subsystem_vendor)
- continue;
- if (w->mask) {
- if ((w->mask & subsystem_device) == w->subdevice)
- return w->action;
- } else {
- if (subsystem_device == w->subdevice)
- return w->action;
- }
+ w = snd_pci_quirk_lookup(pci, dxs_whitelist);
+ if (w) {
+ snd_printdd(KERN_INFO "via82xx: DXS white list for %s found\n",
+ w->name);
+ return w->value;
}
/* for newer revision, default to DXS_SRC */
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index feb27c96625..b338e15db0d 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -900,7 +900,7 @@ static int __devinit snd_via82xx_mixer_new(struct via82xx_modem *chip)
ac97.private_data = chip;
ac97.private_free = snd_via82xx_mixer_free_ac97;
ac97.pci = chip->pci;
- ac97.scaps = AC97_SCAP_SKIP_AUDIO;
+ ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
ac97.num = chip->ac97_secondary;
if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0)
@@ -1124,7 +1124,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card,
return err;
}
chip->port = pci_resource_start(pci, 0);
- if (request_irq(pci->irq, snd_via82xx_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pci->irq, snd_via82xx_interrupt, IRQF_SHARED,
card->driver, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_via82xx_free(chip);
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index af49e8aabf5..474eac9490a 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -73,8 +73,8 @@ MODULE_DEVICE_TABLE(pci, snd_vx222_ids);
/*
*/
-static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
-static DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0);
static struct snd_vx_hardware vx222_old_hw = {
@@ -169,8 +169,8 @@ static int __devinit snd_vx222_create(struct snd_card *card, struct pci_dev *pci
for (i = 0; i < 2; i++)
vx->port[i] = pci_resource_start(pci, i + 1);
- if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_DISABLED|IRQF_SHARED,
- CARD_NAME, (void *) chip)) {
+ if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED,
+ CARD_NAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_vx222_free(chip);
return -EBUSY;
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 5e51950e05f..55558bef716 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -846,7 +846,7 @@ static void vx2_set_input_level(struct snd_vx222 *chip)
#define MIC_LEVEL_MAX 0xff
-static DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0);
/*
* controls API for input levels
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 186453f7abe..fd9b7b83a88 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -49,7 +49,6 @@ static long mpu_port[SNDRV_CARDS];
static long joystick_port[SNDRV_CARDS];
#endif
static int rear_switch[SNDRV_CARDS];
-static int rear_swap[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the Yamaha DS-1 PCI soundcard.");
@@ -67,8 +66,6 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address");
#endif
module_param_array(rear_switch, bool, NULL, 0444);
MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch");
-module_param_array(rear_swap, bool, NULL, 0444);
-MODULE_PARM_DESC(rear_swap, "Swap rear channels (must be enabled for correct IEC958 (S/PDIF)) output");
static struct pci_device_id snd_ymfpci_ids[] = {
{ 0x1073, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* YMF724 */
@@ -298,7 +295,7 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
snd_card_free(card);
return err;
}
- if ((err = snd_ymfpci_mixer(chip, rear_switch[dev], rear_swap[dev])) < 0) {
+ if ((err = snd_ymfpci_mixer(chip, rear_switch[dev])) < 0) {
snd_card_free(card);
return err;
}
diff --git a/sound/pci/ymfpci/ymfpci_image.h b/sound/pci/ymfpci/ymfpci_image.h
index 1b074699166..112f2fff6c8 100644
--- a/sound/pci/ymfpci/ymfpci_image.h
+++ b/sound/pci/ymfpci/ymfpci_image.h
@@ -1,7 +1,7 @@
#ifndef _HWMCODE_
#define _HWMCODE_
-static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = {
+static u32 DspInst[YDSXG_DSPLENGTH / 4] = {
0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
@@ -12,7 +12,7 @@ static unsigned long DspInst[YDSXG_DSPLENGTH / 4] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000
};
-static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = {
+static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = {
0x000007, 0x240007, 0x0C0007, 0x1C0007,
0x060007, 0x700002, 0x000020, 0x030040,
0x007104, 0x004286, 0x030040, 0x000F0D,
@@ -791,7 +791,7 @@ static unsigned long CntrlInst[YDSXG_CTRLLENGTH / 4] = {
// 04/09 creat
// 04/12 stop nise fix
// 06/21 WorkingOff timming
-static unsigned long CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
+static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
0x000007, 0x240007, 0x0C0007, 0x1C0007,
0x060007, 0x700002, 0x000020, 0x030040,
0x007104, 0x004286, 0x030040, 0x000F0D,
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index a40c1085fd2..fd12674d039 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -2,12 +2,6 @@
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
* Routines for control of YMF724/740/744/754 chips
*
- * BUGS:
- * --
- *
- * TODO:
- * --
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -26,6 +20,7 @@
#include <sound/driver.h>
#include <linux/delay.h>
+#include <linux/firmware.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
@@ -42,10 +37,7 @@
#include <sound/mpu401.h>
#include <asm/io.h>
-
-/*
- * constants
- */
+#include <asm/byteorder.h>
/*
* common I/O routines
@@ -179,6 +171,17 @@ static u32 snd_ymfpci_calc_lpfQ(u32 rate)
return val[0];
}
+static void snd_ymfpci_pcm_441_volume_set(struct snd_ymfpci_pcm *ypcm)
+{
+ unsigned int value;
+ struct snd_ymfpci_pcm_mixer *mixer;
+
+ mixer = &ypcm->chip->pcm_mixer[ypcm->substream->number];
+ value = min_t(unsigned int, mixer->left, 0x7fff) >> 1;
+ value |= (min_t(unsigned int, mixer->right, 0x7fff) >> 1) << 16;
+ snd_ymfpci_writel(ypcm->chip, YDSXGR_BUF441OUTVOL, value);
+}
+
/*
* Hardware start management
*/
@@ -290,6 +293,10 @@ static int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voic
snd_assert(pvoice != NULL, return -EINVAL);
snd_ymfpci_hw_stop(chip);
spin_lock_irqsave(&chip->voice_lock, flags);
+ if (pvoice->number == chip->src441_used) {
+ chip->src441_used = -1;
+ pvoice->ypcm->use_441_slot = 0;
+ }
pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
pvoice->ypcm = NULL;
pvoice->interrupt = NULL;
@@ -394,7 +401,7 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
chip->ctrl_playback[ypcm->voices[0]->number + 1] = cpu_to_le32(ypcm->voices[0]->bank_addr);
- if (ypcm->voices[1] != NULL)
+ if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
chip->ctrl_playback[ypcm->voices[1]->number + 1] = cpu_to_le32(ypcm->voices[1]->bank_addr);
ypcm->running = 1;
break;
@@ -402,7 +409,7 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
- if (ypcm->voices[1] != NULL)
+ if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
chip->ctrl_playback[ypcm->voices[1]->number + 1] = 0;
ypcm->running = 0;
break;
@@ -489,6 +496,7 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int
unsigned int nbank;
u32 vol_left, vol_right;
u8 use_left, use_right;
+ unsigned long flags;
snd_assert(voice != NULL, return);
if (runtime->channels == 1) {
@@ -507,11 +515,27 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int
vol_left = cpu_to_le32(0x40000000);
vol_right = cpu_to_le32(0x40000000);
}
+ spin_lock_irqsave(&ypcm->chip->voice_lock, flags);
format = runtime->channels == 2 ? 0x00010000 : 0;
if (snd_pcm_format_width(runtime->format) == 8)
format |= 0x80000000;
+ else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 &&
+ runtime->rate == 44100 && runtime->channels == 2 &&
+ voiceidx == 0 && (ypcm->chip->src441_used == -1 ||
+ ypcm->chip->src441_used == voice->number)) {
+ ypcm->chip->src441_used = voice->number;
+ ypcm->use_441_slot = 1;
+ format |= 0x10000000;
+ snd_ymfpci_pcm_441_volume_set(ypcm);
+ }
+ if (ypcm->chip->src441_used == voice->number &&
+ (format & 0x10000000) == 0) {
+ ypcm->chip->src441_used = -1;
+ ypcm->use_441_slot = 0;
+ }
if (runtime->channels == 2 && (voiceidx & 1) != 0)
format |= 1;
+ spin_unlock_irqrestore(&ypcm->chip->voice_lock, flags);
for (nbank = 0; nbank < 2; nbank++) {
bank = &voice->bank[nbank];
memset(bank, 0, sizeof(*bank));
@@ -910,7 +934,7 @@ static int snd_ymfpci_playback_open(struct snd_pcm_substream *substream)
ypcm = runtime->private_data;
ypcm->output_front = 1;
ypcm->output_rear = chip->mode_dup4ch ? 1 : 0;
- ypcm->swap_rear = chip->rear_swap;
+ ypcm->swap_rear = 0;
spin_lock_irq(&chip->reg_lock);
if (ypcm->output_rear) {
ymfpci_open_extension(chip);
@@ -936,6 +960,7 @@ static int snd_ymfpci_playback_spdif_open(struct snd_pcm_substream *substream)
ypcm = runtime->private_data;
ypcm->output_front = 0;
ypcm->output_rear = 1;
+ ypcm->swap_rear = 1;
spin_lock_irq(&chip->reg_lock);
snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL,
snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) | 2);
@@ -963,6 +988,7 @@ static int snd_ymfpci_playback_4ch_open(struct snd_pcm_substream *substream)
ypcm = runtime->private_data;
ypcm->output_front = 0;
ypcm->output_rear = 1;
+ ypcm->swap_rear = 0;
spin_lock_irq(&chip->reg_lock);
ymfpci_open_extension(chip);
chip->rear_opened++;
@@ -1478,7 +1504,7 @@ static int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol,
return change;
}
-static DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0);
+static const DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0);
#define YMFPCI_DOUBLE(xname, xindex, reg) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
@@ -1720,7 +1746,10 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol,
spin_lock_irqsave(&chip->voice_lock, flags);
if (substream->runtime && substream->runtime->private_data) {
struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
- ypcm->update_pcm_vol = 2;
+ if (!ypcm->use_441_slot)
+ ypcm->update_pcm_vol = 2;
+ else
+ snd_ymfpci_pcm_441_volume_set(ypcm);
}
spin_unlock_irqrestore(&chip->voice_lock, flags);
return 1;
@@ -1755,7 +1784,7 @@ static void snd_ymfpci_mixer_free_ac97(struct snd_ac97 *ac97)
chip->ac97 = NULL;
}
-int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch, int rear_swap)
+int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch)
{
struct snd_ac97_template ac97;
struct snd_kcontrol *kctl;
@@ -1767,7 +1796,6 @@ int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch, int rea
.read = snd_ymfpci_codec_read,
};
- chip->rear_swap = rear_swap;
if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0)
return err;
chip->ac97_bus->private_free = snd_ymfpci_mixer_free_ac97_bus;
@@ -1970,13 +1998,94 @@ static void snd_ymfpci_disable_dsp(struct snd_ymfpci *chip)
}
}
+#define FIRMWARE_IN_THE_KERNEL
+
+#ifdef FIRMWARE_IN_THE_KERNEL
+
#include "ymfpci_image.h"
+static struct firmware snd_ymfpci_dsp_microcode = {
+ .size = YDSXG_DSPLENGTH,
+ .data = (u8 *)DspInst,
+};
+static struct firmware snd_ymfpci_controller_microcode = {
+ .size = YDSXG_CTRLLENGTH,
+ .data = (u8 *)CntrlInst,
+};
+static struct firmware snd_ymfpci_controller_1e_microcode = {
+ .size = YDSXG_CTRLLENGTH,
+ .data = (u8 *)CntrlInst1E,
+};
+#endif
+
+#ifdef __LITTLE_ENDIAN
+static inline void snd_ymfpci_convert_from_le(const struct firmware *fw) { }
+#else
+static void snd_ymfpci_convert_from_le(const struct firmware *fw)
+{
+ int i;
+ u32 *data = (u32 *)fw->data;
+
+ for (i = 0; i < fw->size / 4; ++i)
+ le32_to_cpus(&data[i]);
+}
+#endif
+
+static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
+{
+ int err, is_1e;
+ const char *name;
+
+ err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw",
+ &chip->pci->dev);
+ if (err >= 0) {
+ if (chip->dsp_microcode->size == YDSXG_DSPLENGTH)
+ snd_ymfpci_convert_from_le(chip->dsp_microcode);
+ else {
+ snd_printk(KERN_ERR "DSP microcode has wrong size\n");
+ err = -EINVAL;
+ }
+ }
+ if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+ chip->dsp_microcode = &snd_ymfpci_dsp_microcode;
+#else
+ return err;
+#endif
+ }
+ is_1e = chip->device_id == PCI_DEVICE_ID_YAMAHA_724F ||
+ chip->device_id == PCI_DEVICE_ID_YAMAHA_740C ||
+ chip->device_id == PCI_DEVICE_ID_YAMAHA_744 ||
+ chip->device_id == PCI_DEVICE_ID_YAMAHA_754;
+ name = is_1e ? "yamaha/ds1e_ctrl.fw" : "yamaha/ds1_ctrl.fw";
+ err = request_firmware(&chip->controller_microcode, name,
+ &chip->pci->dev);
+ if (err >= 0) {
+ if (chip->controller_microcode->size == YDSXG_CTRLLENGTH)
+ snd_ymfpci_convert_from_le(chip->controller_microcode);
+ else {
+ snd_printk(KERN_ERR "controller microcode"
+ " has wrong size\n");
+ err = -EINVAL;
+ }
+ }
+ if (err < 0) {
+#ifdef FIRMWARE_IN_THE_KERNEL
+ chip->controller_microcode =
+ is_1e ? &snd_ymfpci_controller_1e_microcode
+ : &snd_ymfpci_controller_microcode;
+#else
+ return err;
+#endif
+ }
+ return 0;
+}
+
static void snd_ymfpci_download_image(struct snd_ymfpci *chip)
{
int i;
u16 ctrl;
- unsigned long *inst;
+ u32 *inst;
snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
snd_ymfpci_disable_dsp(chip);
@@ -1991,21 +2100,12 @@ static void snd_ymfpci_download_image(struct snd_ymfpci *chip)
snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
/* setup DSP instruction code */
+ inst = (u32 *)chip->dsp_microcode->data;
for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
- snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]);
+ snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), inst[i]);
/* setup control instruction code */
- switch (chip->device_id) {
- case PCI_DEVICE_ID_YAMAHA_724F:
- case PCI_DEVICE_ID_YAMAHA_740C:
- case PCI_DEVICE_ID_YAMAHA_744:
- case PCI_DEVICE_ID_YAMAHA_754:
- inst = CntrlInst1E;
- break;
- default:
- inst = CntrlInst;
- break;
- }
+ inst = (u32 *)chip->controller_microcode->data;
for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]);
@@ -2025,10 +2125,10 @@ static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip)
chip->bank_size_effect = snd_ymfpci_readl(chip, YDSXGR_EFFCTRLSIZE) << 2;
chip->work_size = YDSXG_DEFAULT_WORK_SIZE;
- size = ((playback_ctrl_size + 0x00ff) & ~0x00ff) +
- ((chip->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0x00ff) & ~0x00ff) +
- ((chip->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0x00ff) & ~0x00ff) +
- ((chip->bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0x00ff) & ~0x00ff) +
+ size = ALIGN(playback_ctrl_size, 0x100) +
+ ALIGN(chip->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES, 0x100) +
+ ALIGN(chip->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES, 0x100) +
+ ALIGN(chip->bank_size_effect * 2 * YDSXG_EFFECT_VOICES, 0x100) +
chip->work_size;
/* work_ptr must be aligned to 256 bytes, but it's already
covered with the kernel page allocation mechanism */
@@ -2043,8 +2143,8 @@ static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip)
chip->bank_base_playback_addr = ptr_addr;
chip->ctrl_playback = (u32 *)ptr;
chip->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES);
- ptr += (playback_ctrl_size + 0x00ff) & ~0x00ff;
- ptr_addr += (playback_ctrl_size + 0x00ff) & ~0x00ff;
+ ptr += ALIGN(playback_ctrl_size, 0x100);
+ ptr_addr += ALIGN(playback_ctrl_size, 0x100);
for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) {
chip->voices[voice].number = voice;
chip->voices[voice].bank = (struct snd_ymfpci_playback_bank *)ptr;
@@ -2055,8 +2155,8 @@ static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip)
ptr_addr += chip->bank_size_playback;
}
}
- ptr = (char *)(((unsigned long)ptr + 0x00ff) & ~0x00ff);
- ptr_addr = (ptr_addr + 0x00ff) & ~0x00ff;
+ ptr = (char *)ALIGN((unsigned long)ptr, 0x100);
+ ptr_addr = ALIGN(ptr_addr, 0x100);
chip->bank_base_capture = ptr;
chip->bank_base_capture_addr = ptr_addr;
for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++)
@@ -2065,8 +2165,8 @@ static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip)
ptr += chip->bank_size_capture;
ptr_addr += chip->bank_size_capture;
}
- ptr = (char *)(((unsigned long)ptr + 0x00ff) & ~0x00ff);
- ptr_addr = (ptr_addr + 0x00ff) & ~0x00ff;
+ ptr = (char *)ALIGN((unsigned long)ptr, 0x100);
+ ptr_addr = ALIGN(ptr_addr, 0x100);
chip->bank_base_effect = ptr;
chip->bank_base_effect_addr = ptr_addr;
for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++)
@@ -2075,8 +2175,8 @@ static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip)
ptr += chip->bank_size_effect;
ptr_addr += chip->bank_size_effect;
}
- ptr = (char *)(((unsigned long)ptr + 0x00ff) & ~0x00ff);
- ptr_addr = (ptr_addr + 0x00ff) & ~0x00ff;
+ ptr = (char *)ALIGN((unsigned long)ptr, 0x100);
+ ptr_addr = ALIGN(ptr_addr, 0x100);
chip->work_base = ptr;
chip->work_base_addr = ptr_addr;
@@ -2153,12 +2253,21 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
snd_dma_free_pages(&chip->work_ptr);
if (chip->irq >= 0)
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, chip);
release_and_free_resource(chip->res_reg_area);
pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl);
pci_disable_device(chip->pci);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (chip->dsp_microcode != &snd_ymfpci_dsp_microcode)
+#endif
+ release_firmware(chip->dsp_microcode);
+#ifdef FIRMWARE_IN_THE_KERNEL
+ if (chip->controller_microcode != &snd_ymfpci_controller_microcode &&
+ chip->controller_microcode != &snd_ymfpci_controller_1e_microcode)
+#endif
+ release_firmware(chip->controller_microcode);
kfree(chip);
return 0;
}
@@ -2179,7 +2288,7 @@ static int saved_regs_index[] = {
YDSXGR_PRIADCLOOPVOL,
YDSXGR_NATIVEDACINVOL,
YDSXGR_NATIVEDACOUTVOL,
- // YDSXGR_BUF441OUTVOL,
+ YDSXGR_BUF441OUTVOL,
YDSXGR_NATIVEADCINVOL,
YDSXGR_SPDIFLOOPVOL,
YDSXGR_SPDIFOUTVOL,
@@ -2290,17 +2399,19 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
chip->pci = pci;
chip->irq = -1;
chip->device_id = pci->device;
- pci_read_config_byte(pci, PCI_REVISION_ID, (u8 *)&chip->rev);
+ pci_read_config_byte(pci, PCI_REVISION_ID, &chip->rev);
chip->reg_area_phys = pci_resource_start(pci, 0);
chip->reg_area_virt = ioremap_nocache(chip->reg_area_phys, 0x8000);
pci_set_master(pci);
+ chip->src441_used = -1;
if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) {
snd_printk(KERN_ERR "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1);
snd_ymfpci_free(chip);
return -EBUSY;
}
- if (request_irq(pci->irq, snd_ymfpci_interrupt, IRQF_DISABLED|IRQF_SHARED, "YMFPCI", (void *) chip)) {
+ if (request_irq(pci->irq, snd_ymfpci_interrupt, IRQF_SHARED,
+ "YMFPCI", chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_ymfpci_free(chip);
return -EBUSY;
@@ -2313,6 +2424,12 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
return -EIO;
}
+ err = snd_ymfpci_request_firmware(chip);
+ if (err < 0) {
+ snd_printk(KERN_ERR "firmware request failed: %d\n", err);
+ snd_ymfpci_free(chip);
+ return err;
+ }
snd_ymfpci_download_image(chip);
udelay(100); /* seems we need a delay after downloading image.. */
@@ -2322,7 +2439,6 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
return -EIO;
}
- chip->rear_swap = 1;
if ((err = snd_ymfpci_ac3_init(chip)) < 0) {
snd_ymfpci_free(chip);
return err;
diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c
index bced7b623b1..2b1f996c898 100644
--- a/sound/pcmcia/vx/vxp_mixer.c
+++ b/sound/pcmcia/vx/vxp_mixer.c
@@ -64,7 +64,7 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
return 0;
}
-static DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0);
static struct snd_kcontrol_new vx_control_mic_level = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index d7df59e9c64..363bcb5f08e 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -91,7 +91,7 @@ static int snd_vxpocket_dev_free(struct snd_device *device)
* Only output levels can be modified
*/
-static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
static struct snd_vx_hardware vxpocket_hw = {
.name = "VXPocket",
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
new file mode 100644
index 00000000000..ec821a57f84
--- /dev/null
+++ b/sound/soc/Kconfig
@@ -0,0 +1,32 @@
+#
+# SoC audio configuration
+#
+
+menu "SoC audio support"
+ depends on SND!=n
+
+config SND_SOC_AC97_BUS
+ bool
+
+config SND_SOC
+ tristate "SoC audio support"
+ ---help---
+
+ If you want SoC support, you should say Y here and also to the
+ specific driver for your SoC below. You will also need to select the
+ specific codec(s) attached to the SoC
+
+ This SoC audio support can also be built as a module. If so, the module
+ will be called snd-soc-core.
+
+# All the supported Soc's
+menu "SoC Platforms"
+depends on SND_SOC
+source "sound/soc/at91/Kconfig"
+source "sound/soc/pxa/Kconfig"
+endmenu
+
+# Supported codecs
+source "sound/soc/codecs/Kconfig"
+
+endmenu
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
new file mode 100644
index 00000000000..98e6f49dafc
--- /dev/null
+++ b/sound/soc/Makefile
@@ -0,0 +1,4 @@
+snd-soc-core-objs := soc-core.o soc-dapm.o
+
+obj-$(CONFIG_SND_SOC) += snd-soc-core.o
+obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig
new file mode 100644
index 00000000000..5bcf08b728b
--- /dev/null
+++ b/sound/soc/at91/Kconfig
@@ -0,0 +1,32 @@
+menu "SoC Audio for the Atmel AT91"
+
+config SND_AT91_SOC
+ tristate "SoC Audio for the Atmel AT91 System-on-Chip"
+ depends on ARCH_AT91 && SND
+ select SND_PCM
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the AT91 SSC interface. You will also need
+ to select the audio interfaces to support below.
+
+config SND_AT91_SOC_I2S
+ tristate
+
+config SND_AT91_SOC_ETI_B1_WM8731
+ tristate "SoC I2S Audio support for WM8731-based Endrelia ETI-B1 boards"
+ depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1)
+ select SND_AT91_SOC_I2S
+ select SND_SOC_WM8731
+ help
+ Say Y if you want to add support for SoC audio on WM8731-based
+ Endrelia Technologies Inc ETI-B1 or ETI-C1 boards.
+
+config SND_AT91_SOC_ETI_SLAVE
+ bool "Run codec in slave Mode on Endrelia boards"
+ depends on SND_AT91_SOC_ETI_B1_WM8731
+ default n
+ help
+ Say Y if you want to run with the AT91 SSC generating the BCLK
+ and LRC signals on Endrelia boards.
+
+endmenu
diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile
new file mode 100644
index 00000000000..b77b01ab202
--- /dev/null
+++ b/sound/soc/at91/Makefile
@@ -0,0 +1,11 @@
+# AT91 Platform Support
+snd-soc-at91-objs := at91-pcm.o
+snd-soc-at91-i2s-objs := at91-i2s.o
+
+obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o
+obj-$(CONFIG_SND_AT91_SOC_I2S) += snd-soc-at91-i2s.o
+
+# AT91 Machine Support
+snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o
+
+obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o
diff --git a/sound/soc/at91/at91-i2s.c b/sound/soc/at91/at91-i2s.c
new file mode 100644
index 00000000000..fcc544a96ba
--- /dev/null
+++ b/sound/soc/at91/at91-i2s.c
@@ -0,0 +1,720 @@
+/*
+ * at91-i2s.c -- ALSA SoC I2S Audio Layer Platform driver
+ *
+ * Author: Frank Mandarino <fmandarino@endrelia.com>
+ * Endrelia Technologies Inc.
+ *
+ * Based on pxa2xx Platform drivers by
+ * Liam Girdwood <liam.girdwood@wolfsonmicro.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/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_ssc.h>
+#include <asm/arch/at91_pdc.h>
+
+#include "at91-pcm.h"
+#include "at91-i2s.h"
+
+#if 0
+#define DBG(x...) printk(KERN_DEBUG "at91-i2s:" x)
+#else
+#define DBG(x...)
+#endif
+
+#if defined(CONFIG_ARCH_AT91SAM9260)
+#define NUM_SSC_DEVICES 1
+#else
+#define NUM_SSC_DEVICES 3
+#endif
+
+
+/*
+ * SSC PDC registers required by the PCM DMA engine.
+ */
+static struct at91_pdc_regs pdc_tx_reg = {
+ .xpr = AT91_PDC_TPR,
+ .xcr = AT91_PDC_TCR,
+ .xnpr = AT91_PDC_TNPR,
+ .xncr = AT91_PDC_TNCR,
+};
+
+static struct at91_pdc_regs pdc_rx_reg = {
+ .xpr = AT91_PDC_RPR,
+ .xcr = AT91_PDC_RCR,
+ .xnpr = AT91_PDC_RNPR,
+ .xncr = AT91_PDC_RNCR,
+};
+
+/*
+ * SSC & PDC status bits for transmit and receive.
+ */
+static struct at91_ssc_mask ssc_tx_mask = {
+ .ssc_enable = AT91_SSC_TXEN,
+ .ssc_disable = AT91_SSC_TXDIS,
+ .ssc_endx = AT91_SSC_ENDTX,
+ .ssc_endbuf = AT91_SSC_TXBUFE,
+ .pdc_enable = AT91_PDC_TXTEN,
+ .pdc_disable = AT91_PDC_TXTDIS,
+};
+
+static struct at91_ssc_mask ssc_rx_mask = {
+ .ssc_enable = AT91_SSC_RXEN,
+ .ssc_disable = AT91_SSC_RXDIS,
+ .ssc_endx = AT91_SSC_ENDRX,
+ .ssc_endbuf = AT91_SSC_RXBUFF,
+ .pdc_enable = AT91_PDC_RXTEN,
+ .pdc_disable = AT91_PDC_RXTDIS,
+};
+
+
+/*
+ * DMA parameters.
+ */
+static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
+ {{
+ .name = "SSC0/I2S PCM Stereo out",
+ .pdc = &pdc_tx_reg,
+ .mask = &ssc_tx_mask,
+ },
+ {
+ .name = "SSC0/I2S PCM Stereo in",
+ .pdc = &pdc_rx_reg,
+ .mask = &ssc_rx_mask,
+ }},
+#if NUM_SSC_DEVICES == 3
+ {{
+ .name = "SSC1/I2S PCM Stereo out",
+ .pdc = &pdc_tx_reg,
+ .mask = &ssc_tx_mask,
+ },
+ {
+ .name = "SSC1/I2S PCM Stereo in",
+ .pdc = &pdc_rx_reg,
+ .mask = &ssc_rx_mask,
+ }},
+ {{
+ .name = "SSC2/I2S PCM Stereo out",
+ .pdc = &pdc_tx_reg,
+ .mask = &ssc_tx_mask,
+ },
+ {
+ .name = "SSC1/I2S PCM Stereo in",
+ .pdc = &pdc_rx_reg,
+ .mask = &ssc_rx_mask,
+ }},
+#endif
+};
+
+struct at91_ssc_state {
+ u32 ssc_cmr;
+ u32 ssc_rcmr;
+ u32 ssc_rfmr;
+ u32 ssc_tcmr;
+ u32 ssc_tfmr;
+ u32 ssc_sr;
+ u32 ssc_imr;
+};
+
+static struct at91_ssc_info {
+ char *name;
+ struct at91_ssc_periph ssc;
+ spinlock_t lock; /* lock for dir_mask */
+ unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */
+ unsigned short initialized; /* 1=SSC has been initialized */
+ unsigned short daifmt;
+ unsigned short cmr_div;
+ unsigned short tcmr_period;
+ unsigned short rcmr_period;
+ struct at91_pcm_dma_params *dma_params[2];
+ struct at91_ssc_state ssc_state;
+
+} ssc_info[NUM_SSC_DEVICES] = {
+ {
+ .name = "ssc0",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .dir_mask = 0,
+ .initialized = 0,
+ },
+#if NUM_SSC_DEVICES == 3
+ {
+ .name = "ssc1",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .dir_mask = 0,
+ .initialized = 0,
+ },
+ {
+ .name = "ssc2",
+ .lock = SPIN_LOCK_UNLOCKED,
+ .dir_mask = 0,
+ .initialized = 0,
+ },
+#endif
+};
+
+static unsigned int at91_i2s_sysclk;
+
+/*
+ * SSC interrupt handler. Passes PDC interrupts to the DMA
+ * interrupt handler in the PCM driver.
+ */
+static irqreturn_t at91_i2s_interrupt(int irq, void *dev_id)
+{
+ struct at91_ssc_info *ssc_p = dev_id;
+ struct at91_pcm_dma_params *dma_params;
+ u32 ssc_sr;
+ int i;
+
+ ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)
+ & at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
+
+ /*
+ * Loop through the substreams attached to this SSC. If
+ * a DMA-related interrupt occurred on that substream, call
+ * the DMA interrupt handler function, if one has been
+ * registered in the dma_params structure by the PCM driver.
+ */
+ for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
+ dma_params = ssc_p->dma_params[i];
+
+ if (dma_params != NULL && dma_params->dma_intr_handler != NULL &&
+ (ssc_sr &
+ (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf)))
+
+ dma_params->dma_intr_handler(ssc_sr, dma_params->substream);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Startup. Only that one substream allowed in each direction.
+ */
+static int at91_i2s_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+ int dir_mask;
+
+ DBG("i2s_startup: SSC_SR=0x%08lx\n",
+ at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
+ dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2;
+
+ spin_lock_irq(&ssc_p->lock);
+ if (ssc_p->dir_mask & dir_mask) {
+ spin_unlock_irq(&ssc_p->lock);
+ return -EBUSY;
+ }
+ ssc_p->dir_mask |= dir_mask;
+ spin_unlock_irq(&ssc_p->lock);
+
+ return 0;
+}
+
+/*
+ * Shutdown. Clear DMA parameters and shutdown the SSC if there
+ * are no other substreams open.
+ */
+static void at91_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+ struct at91_pcm_dma_params *dma_params;
+ int dir, dir_mask;
+
+ dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+ dma_params = ssc_p->dma_params[dir];
+
+ if (dma_params != NULL) {
+ at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
+ dma_params->mask->ssc_disable);
+ DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"),
+ at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
+
+ dma_params->ssc_base = NULL;
+ dma_params->substream = NULL;
+ ssc_p->dma_params[dir] = NULL;
+ }
+
+ dir_mask = 1 << dir;
+
+ spin_lock_irq(&ssc_p->lock);
+ ssc_p->dir_mask &= ~dir_mask;
+ if (!ssc_p->dir_mask) {
+ /* Shutdown the SSC clock. */
+ DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
+ at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid);
+
+ if (ssc_p->initialized) {
+ free_irq(ssc_p->ssc.pid, ssc_p);
+ ssc_p->initialized = 0;
+ }
+
+ /* Reset the SSC */
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
+
+ /* Clear the SSC dividers */
+ ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
+ }
+ spin_unlock_irq(&ssc_p->lock);
+}
+
+/*
+ * Record the SSC system clock rate.
+ */
+static int at91_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ /*
+ * The only clock supplied to the SSC is the AT91 master clock,
+ * which is only used if the SSC is generating BCLK and/or
+ * LRC clocks.
+ */
+ switch (clk_id) {
+ case AT91_SYSCLK_MCK:
+ at91_i2s_sysclk = freq;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Record the DAI format for use in hw_params().
+ */
+static int at91_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+
+ if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)
+ return -EINVAL;
+
+ ssc_p->daifmt = fmt;
+ return 0;
+}
+
+/*
+ * Record SSC clock dividers for use in hw_params().
+ */
+static int at91_i2s_set_dai_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
+ int div_id, int div)
+{
+ struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+
+ switch (div_id) {
+ case AT91SSC_CMR_DIV:
+ /*
+ * The same master clock divider is used for both
+ * transmit and receive, so if a value has already
+ * been set, it must match this value.
+ */
+ if (ssc_p->cmr_div == 0)
+ ssc_p->cmr_div = div;
+ else
+ if (div != ssc_p->cmr_div)
+ return -EBUSY;
+ break;
+
+ case AT91SSC_TCMR_PERIOD:
+ ssc_p->tcmr_period = div;
+ break;
+
+ case AT91SSC_RCMR_PERIOD:
+ ssc_p->rcmr_period = div;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Configure the SSC.
+ */
+static int at91_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int id = rtd->dai->cpu_dai->id;
+ struct at91_ssc_info *ssc_p = &ssc_info[id];
+ struct at91_pcm_dma_params *dma_params;
+ int dir, channels, bits;
+ u32 tfmr, rfmr, tcmr, rcmr;
+ int start_event;
+ int ret;
+
+ /*
+ * Currently, there is only one set of dma params for
+ * each direction. If more are added, this code will
+ * have to be changed to select the proper set.
+ */
+ dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+
+ dma_params = &ssc_dma_params[id][dir];
+ dma_params->ssc_base = ssc_p->ssc.base;
+ dma_params->substream = substream;
+
+ ssc_p->dma_params[dir] = dma_params;
+
+ /*
+ * The cpu_dai->dma_data field is only used to communicate the
+ * appropriate DMA parameters to the pcm driver hw_params()
+ * function. It should not be used for other purposes
+ * as it is common to all substreams.
+ */
+ rtd->dai->cpu_dai->dma_data = dma_params;
+
+ channels = params_channels(params);
+
+ /*
+ * The SSC only supports up to 16-bit samples in I2S format, due
+ * to the size of the Frame Mode Register FSLEN field. Also, I2S
+ * implies signed data.
+ */
+ bits = 16;
+ dma_params->pdc_xfer_size = 2;
+
+ /*
+ * Compute SSC register settings.
+ */
+ switch (ssc_p->daifmt) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /*
+ * SSC provides BCLK and LRC clocks.
+ *
+ * The SSC transmit and receive clocks are generated from the
+ * MCK divider, and the BCLK signal is output on the SSC TK line.
+ */
+ rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD)
+ | (( 1 << 16) & AT91_SSC_STTDLY)
+ | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START)
+ | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI)
+ | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
+ | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS);
+
+ rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
+ | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS)
+ | (((bits - 1) << 16) & AT91_SSC_FSLEN)
+ | (((channels - 1) << 8) & AT91_SSC_DATNB)
+ | (( 1 << 7) & AT91_SSC_MSBF)
+ | (( 0 << 5) & AT91_SSC_LOOP)
+ | (((bits - 1) << 0) & AT91_SSC_DATALEN);
+
+ tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD)
+ | (( 1 << 16) & AT91_SSC_STTDLY)
+ | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START)
+ | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI)
+ | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO)
+ | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS);
+
+ tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
+ | (( 0 << 23) & AT91_SSC_FSDEN)
+ | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS)
+ | (((bits - 1) << 16) & AT91_SSC_FSLEN)
+ | (((channels - 1) << 8) & AT91_SSC_DATNB)
+ | (( 1 << 7) & AT91_SSC_MSBF)
+ | (( 0 << 5) & AT91_SSC_DATDEF)
+ | (((bits - 1) << 0) & AT91_SSC_DATALEN);
+ break;
+
+ case SND_SOC_DAIFMT_CBM_CFM:
+
+ /*
+ * CODEC supplies BCLK and LRC clocks.
+ *
+ * The SSC transmit clock is obtained from the BCLK signal on
+ * on the TK line, and the SSC receive clock is generated from the
+ * transmit clock.
+ *
+ * For single channel data, one sample is transferred on the falling
+ * edge of the LRC clock. For two channel data, one sample is
+ * transferred on both edges of the LRC clock.
+ */
+ start_event = channels == 1
+ ? AT91_SSC_START_FALLING_RF
+ : AT91_SSC_START_EDGE_RF;
+
+ rcmr = (( 0 << 24) & AT91_SSC_PERIOD)
+ | (( 1 << 16) & AT91_SSC_STTDLY)
+ | (( start_event ) & AT91_SSC_START)
+ | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI)
+ | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
+ | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS);
+
+ rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
+ | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS)
+ | (( 0 << 16) & AT91_SSC_FSLEN)
+ | (( 0 << 8) & AT91_SSC_DATNB)
+ | (( 1 << 7) & AT91_SSC_MSBF)
+ | (( 0 << 5) & AT91_SSC_LOOP)
+ | (((bits - 1) << 0) & AT91_SSC_DATALEN);
+
+ tcmr = (( 0 << 24) & AT91_SSC_PERIOD)
+ | (( 1 << 16) & AT91_SSC_STTDLY)
+ | (( start_event ) & AT91_SSC_START)
+ | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI)
+ | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
+ | (( AT91_SSC_CKS_PIN ) & AT91_SSC_CKS);
+
+ tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
+ | (( 0 << 23) & AT91_SSC_FSDEN)
+ | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS)
+ | (( 0 << 16) & AT91_SSC_FSLEN)
+ | (( 0 << 8) & AT91_SSC_DATNB)
+ | (( 1 << 7) & AT91_SSC_MSBF)
+ | (( 0 << 5) & AT91_SSC_DATDEF)
+ | (((bits - 1) << 0) & AT91_SSC_DATALEN);
+ break;
+
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ printk(KERN_WARNING "at91-i2s: unsupported DAI format 0x%x.\n",
+ ssc_p->daifmt);
+ return -EINVAL;
+ break;
+ }
+ DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr);
+
+ if (!ssc_p->initialized) {
+
+ /* Enable PMC peripheral clock for this SSC */
+ DBG("Starting pid %d clock\n", ssc_p->ssc.pid);
+ at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);
+
+ /* Reset the SSC and its PDC registers */
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
+
+ at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RPR, 0);
+ at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RCR, 0);
+ at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNPR, 0);
+ at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNCR, 0);
+ at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TPR, 0);
+ at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TCR, 0);
+ at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNPR, 0);
+ at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNCR, 0);
+
+ if ((ret = request_irq(ssc_p->ssc.pid, at91_i2s_interrupt,
+ 0, ssc_p->name, ssc_p)) < 0) {
+ printk(KERN_WARNING "at91-i2s: request_irq failure\n");
+
+ DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
+ at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);
+ return ret;
+ }
+
+ ssc_p->initialized = 1;
+ }
+
+ /* set SSC clock mode register */
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div);
+
+ /* set receive clock mode and format */
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr);
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr);
+
+ /* set transmit clock mode and format */
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr);
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr);
+
+ DBG("hw_params: SSC initialized\n");
+ return 0;
+}
+
+
+static int at91_i2s_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+ struct at91_pcm_dma_params *dma_params;
+ int dir;
+
+ dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+ dma_params = ssc_p->dma_params[dir];
+
+ at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
+ dma_params->mask->ssc_enable);
+
+ DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit",
+ at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR));
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int at91_i2s_suspend(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *cpu_dai)
+{
+ struct at91_ssc_info *ssc_p;
+
+ if(!cpu_dai->active)
+ return 0;
+
+ ssc_p = &ssc_info[cpu_dai->id];
+
+ /* Save the status register before disabling transmit and receive. */
+ ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR);
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
+ AT91_SSC_TXDIS | AT91_SSC_RXDIS);
+
+ /* Save the current interrupt mask, then disable unmasked interrupts. */
+ ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr);
+
+ ssc_p->ssc_state.ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR);
+ ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR);
+ ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR);
+ ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR);
+ ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR);
+
+ return 0;
+}
+
+static int at91_i2s_resume(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *cpu_dai)
+{
+ struct at91_ssc_info *ssc_p;
+
+ if(!cpu_dai->active)
+ return 0;
+
+ ssc_p = &ssc_info[cpu_dai->id];
+
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr);
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr);
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr);
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr);
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->ssc_state.ssc_cmr);
+
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->ssc_state.ssc_imr);
+
+ at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
+ ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) |
+ ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0));
+
+ return 0;
+}
+
+#else
+#define at91_i2s_suspend NULL
+#define at91_i2s_resume NULL
+#endif
+
+#define AT91_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000)
+
+struct snd_soc_cpu_dai at91_i2s_dai[NUM_SSC_DEVICES] = {
+ { .name = "at91_ssc0/i2s",
+ .id = 0,
+ .type = SND_SOC_DAI_I2S,
+ .suspend = at91_i2s_suspend,
+ .resume = at91_i2s_resume,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AT91_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AT91_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .startup = at91_i2s_startup,
+ .shutdown = at91_i2s_shutdown,
+ .prepare = at91_i2s_prepare,
+ .hw_params = at91_i2s_hw_params,},
+ .dai_ops = {
+ .set_sysclk = at91_i2s_set_dai_sysclk,
+ .set_fmt = at91_i2s_set_dai_fmt,
+ .set_clkdiv = at91_i2s_set_dai_clkdiv,},
+ .private_data = &ssc_info[0].ssc,
+ },
+#if NUM_SSC_DEVICES == 3
+ { .name = "at91_ssc1/i2s",
+ .id = 1,
+ .type = SND_SOC_DAI_I2S,
+ .suspend = at91_i2s_suspend,
+ .resume = at91_i2s_resume,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AT91_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AT91_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .startup = at91_i2s_startup,
+ .shutdown = at91_i2s_shutdown,
+ .prepare = at91_i2s_prepare,
+ .hw_params = at91_i2s_hw_params,},
+ .dai_ops = {
+ .set_sysclk = at91_i2s_set_dai_sysclk,
+ .set_fmt = at91_i2s_set_dai_fmt,
+ .set_clkdiv = at91_i2s_set_dai_clkdiv,},
+ .private_data = &ssc_info[1].ssc,
+ },
+ { .name = "at91_ssc2/i2s",
+ .id = 2,
+ .type = SND_SOC_DAI_I2S,
+ .suspend = at91_i2s_suspend,
+ .resume = at91_i2s_resume,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AT91_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AT91_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .startup = at91_i2s_startup,
+ .shutdown = at91_i2s_shutdown,
+ .prepare = at91_i2s_prepare,
+ .hw_params = at91_i2s_hw_params,},
+ .dai_ops = {
+ .set_sysclk = at91_i2s_set_dai_sysclk,
+ .set_fmt = at91_i2s_set_dai_fmt,
+ .set_clkdiv = at91_i2s_set_dai_clkdiv,},
+ .private_data = &ssc_info[2].ssc,
+ },
+#endif
+};
+
+EXPORT_SYMBOL_GPL(at91_i2s_dai);
+
+/* Module information */
+MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com");
+MODULE_DESCRIPTION("AT91 I2S ASoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/at91/at91-i2s.h b/sound/soc/at91/at91-i2s.h
new file mode 100644
index 00000000000..f8a875ba0cc
--- /dev/null
+++ b/sound/soc/at91/at91-i2s.h
@@ -0,0 +1,27 @@
+/*
+ * at91-i2s.h - ALSA I2S interface for the Atmel AT91 SoC
+ *
+ * Author: Frank Mandarino <fmandarino@endrelia.com>
+ * Endrelia Technologies Inc.
+ * Created: Jan 9, 2007
+ *
+ * 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 _AT91_I2S_H
+#define _AT91_I2S_H
+
+/* I2S system clock ids */
+#define AT91_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */
+
+/* I2S divider ids */
+#define AT91SSC_CMR_DIV 0 /* MCK divider for BCLK */
+#define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */
+#define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */
+
+extern struct snd_soc_cpu_dai at91_i2s_dai[];
+
+#endif /* _AT91_I2S_H */
+
diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c
new file mode 100644
index 00000000000..e88b12e7cc4
--- /dev/null
+++ b/sound/soc/at91/at91-pcm.c
@@ -0,0 +1,432 @@
+/*
+ * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC
+ *
+ * Author: Frank Mandarino <fmandarino@endrelia.com>
+ * Endrelia Technologies Inc.
+ * Created: Mar 3, 2006
+ *
+ * Based on pxa2xx-pcm.c by:
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 30, 2004
+ * Copyright: (C) 2004 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_ssc.h>
+#include <asm/arch/at91_pdc.h>
+
+#include "at91-pcm.h"
+
+#if 0
+#define DBG(x...) printk(KERN_INFO "at91-pcm: " x)
+#else
+#define DBG(x...)
+#endif
+
+static const struct snd_pcm_hardware at91_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8192,
+ .periods_min = 2,
+ .periods_max = 1024,
+ .buffer_bytes_max = 32 * 1024,
+};
+
+struct at91_runtime_data {
+ struct at91_pcm_dma_params *params;
+ dma_addr_t dma_buffer; /* physical address of dma buffer */
+ dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */
+ size_t period_size;
+ dma_addr_t period_ptr; /* physical address of next period */
+ u32 pdc_xpr_save; /* PDC register save */
+ u32 pdc_xcr_save;
+ u32 pdc_xnpr_save;
+ u32 pdc_xncr_save;
+};
+
+static void at91_pcm_dma_irq(u32 ssc_sr,
+ struct snd_pcm_substream *substream)
+{
+ struct at91_runtime_data *prtd = substream->runtime->private_data;
+ struct at91_pcm_dma_params *params = prtd->params;
+ static int count = 0;
+
+ count++;
+
+ if (ssc_sr & params->mask->ssc_endbuf) {
+
+ printk(KERN_WARNING
+ "at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+ ? "underrun" : "overrun",
+ params->name, ssc_sr, count);
+
+ /* re-start the PDC */
+ at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
+
+ prtd->period_ptr += prtd->period_size;
+ if (prtd->period_ptr >= prtd->dma_buffer_end) {
+ prtd->period_ptr = prtd->dma_buffer;
+ }
+
+ at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
+ at91_ssc_write(params->ssc_base + params->pdc->xcr,
+ prtd->period_size / params->pdc_xfer_size);
+
+ at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
+ }
+
+ if (ssc_sr & params->mask->ssc_endx) {
+
+ /* Load the PDC next pointer and counter registers */
+ prtd->period_ptr += prtd->period_size;
+ if (prtd->period_ptr >= prtd->dma_buffer_end) {
+ prtd->period_ptr = prtd->dma_buffer;
+ }
+ at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
+ at91_ssc_write(params->ssc_base + params->pdc->xncr,
+ prtd->period_size / params->pdc_xfer_size);
+ }
+
+ snd_pcm_period_elapsed(substream);
+}
+
+static int at91_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct at91_runtime_data *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ /* this may get called several times by oss emulation
+ * with different params */
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ runtime->dma_bytes = params_buffer_bytes(params);
+
+ prtd->params = rtd->dai->cpu_dai->dma_data;
+ prtd->params->dma_intr_handler = at91_pcm_dma_irq;
+
+ prtd->dma_buffer = runtime->dma_addr;
+ prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
+ prtd->period_size = params_period_bytes(params);
+
+ DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n",
+ prtd->params->name, runtime->dma_bytes, prtd->period_size);
+ return 0;
+}
+
+static int at91_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct at91_runtime_data *prtd = substream->runtime->private_data;
+ struct at91_pcm_dma_params *params = prtd->params;
+
+ if (params != NULL) {
+ at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
+ prtd->params->dma_intr_handler = NULL;
+ }
+
+ return 0;
+}
+
+static int at91_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct at91_runtime_data *prtd = substream->runtime->private_data;
+ struct at91_pcm_dma_params *params = prtd->params;
+
+ at91_ssc_write(params->ssc_base + AT91_SSC_IDR,
+ params->mask->ssc_endx | params->mask->ssc_endbuf);
+
+ at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
+ return 0;
+}
+
+static int at91_pcm_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct at91_runtime_data *prtd = substream->runtime->private_data;
+ struct at91_pcm_dma_params *params = prtd->params;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ prtd->period_ptr = prtd->dma_buffer;
+
+ at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
+ at91_ssc_write(params->ssc_base + params->pdc->xcr,
+ prtd->period_size / params->pdc_xfer_size);
+
+ prtd->period_ptr += prtd->period_size;
+ at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
+ at91_ssc_write(params->ssc_base + params->pdc->xncr,
+ prtd->period_size / params->pdc_xfer_size);
+
+ DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n",
+ (unsigned long) prtd->period_ptr,
+ at91_ssc_read(params->ssc_base + params->pdc->xpr),
+ at91_ssc_read(params->ssc_base + params->pdc->xcr),
+ at91_ssc_read(params->ssc_base + params->pdc->xnpr),
+ at91_ssc_read(params->ssc_base + params->pdc->xncr));
+
+ at91_ssc_write(params->ssc_base + AT91_SSC_IER,
+ params->mask->ssc_endx | params->mask->ssc_endbuf);
+
+ at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
+
+ DBG("sr=%lx imr=%lx\n", at91_ssc_read(params->ssc_base + AT91_SSC_SR),
+ at91_ssc_read(params->ssc_base + AT91_SSC_IER));
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t at91_pcm_pointer(
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct at91_runtime_data *prtd = runtime->private_data;
+ struct at91_pcm_dma_params *params = prtd->params;
+ dma_addr_t ptr;
+ snd_pcm_uframes_t x;
+
+ ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr);
+ x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
+
+ if (x == runtime->buffer_size)
+ x = 0;
+ return x;
+}
+
+static int at91_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct at91_runtime_data *prtd;
+ int ret = 0;
+
+ snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware);
+
+ /* ensure that buffer size is a multiple of period size */
+ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ goto out;
+
+ prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL);
+ if (prtd == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ runtime->private_data = prtd;
+
+ out:
+ return ret;
+}
+
+static int at91_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct at91_runtime_data *prtd = substream->runtime->private_data;
+
+ kfree(prtd);
+ return 0;
+}
+
+static int at91_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+struct snd_pcm_ops at91_pcm_ops = {
+ .open = at91_pcm_open,
+ .close = at91_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = at91_pcm_hw_params,
+ .hw_free = at91_pcm_hw_free,
+ .prepare = at91_pcm_prepare,
+ .trigger = at91_pcm_trigger,
+ .pointer = at91_pcm_pointer,
+ .mmap = at91_pcm_mmap,
+};
+
+static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+ int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = at91_pcm_hardware.buffer_bytes_max;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+
+ DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
+ (void *) buf->area,
+ (void *) buf->addr,
+ size);
+
+ if (!buf->area)
+ return -ENOMEM;
+
+ buf->bytes = size;
+ return 0;
+}
+
+static u64 at91_pcm_dmamask = 0xffffffff;
+
+static int at91_pcm_new(struct snd_card *card,
+ struct snd_soc_codec_dai *dai, struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &at91_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = 0xffffffff;
+
+ if (dai->playback.channels_min) {
+ ret = at91_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto out;
+ }
+
+ if (dai->capture.channels_min) {
+ ret = at91_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto out;
+ }
+ out:
+ return ret;
+}
+
+static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_writecombine(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
+}
+
+#ifdef CONFIG_PM
+static int at91_pcm_suspend(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *dai)
+{
+ struct snd_pcm_runtime *runtime = dai->runtime;
+ struct at91_runtime_data *prtd;
+ struct at91_pcm_dma_params *params;
+
+ if (!runtime)
+ return 0;
+
+ prtd = runtime->private_data;
+ params = prtd->params;
+
+ /* disable the PDC and save the PDC registers */
+
+ at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
+
+ prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr);
+ prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr);
+ prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr);
+ prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr);
+
+ return 0;
+}
+
+static int at91_pcm_resume(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *dai)
+{
+ struct snd_pcm_runtime *runtime = dai->runtime;
+ struct at91_runtime_data *prtd;
+ struct at91_pcm_dma_params *params;
+
+ if (!runtime)
+ return 0;
+
+ prtd = runtime->private_data;
+ params = prtd->params;
+
+ /* restore the PDC registers and enable the PDC */
+ at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->pdc_xpr_save);
+ at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->pdc_xcr_save);
+ at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save);
+ at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save);
+
+ at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
+ return 0;
+}
+#else
+#define at91_pcm_suspend NULL
+#define at91_pcm_resume NULL
+#endif
+
+struct snd_soc_platform at91_soc_platform = {
+ .name = "at91-audio",
+ .pcm_ops = &at91_pcm_ops,
+ .pcm_new = at91_pcm_new,
+ .pcm_free = at91_pcm_free_dma_buffers,
+ .suspend = at91_pcm_suspend,
+ .resume = at91_pcm_resume,
+};
+
+EXPORT_SYMBOL_GPL(at91_soc_platform);
+
+MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
+MODULE_DESCRIPTION("Atmel AT91 PCM module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h
new file mode 100644
index 00000000000..58d0f00a07b
--- /dev/null
+++ b/sound/soc/at91/at91-pcm.h
@@ -0,0 +1,72 @@
+/*
+ * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC
+ *
+ * Author: Frank Mandarino <fmandarino@endrelia.com>
+ * Endrelia Technologies Inc.
+ * Created: Mar 3, 2006
+ *
+ * Based on pxa2xx-pcm.h by:
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 30, 2004
+ * Copyright: 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 _AT91_PCM_H
+#define _AT91_PCM_H
+
+#include <asm/arch/hardware.h>
+
+struct at91_ssc_periph {
+ void __iomem *base;
+ u32 pid;
+};
+
+/*
+ * Registers and status bits that are required by the PCM driver.
+ */
+struct at91_pdc_regs {
+ unsigned int xpr; /* PDC recv/trans pointer */
+ unsigned int xcr; /* PDC recv/trans counter */
+ unsigned int xnpr; /* PDC next recv/trans pointer */
+ unsigned int xncr; /* PDC next recv/trans counter */
+ unsigned int ptcr; /* PDC transfer control */
+};
+
+struct at91_ssc_mask {
+ u32 ssc_enable; /* SSC recv/trans enable */
+ u32 ssc_disable; /* SSC recv/trans disable */
+ u32 ssc_endx; /* SSC ENDTX or ENDRX */
+ u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */
+ u32 pdc_enable; /* PDC recv/trans enable */
+ u32 pdc_disable; /* PDC recv/trans disable */
+};
+
+/*
+ * This structure, shared between the PCM driver and the interface,
+ * contains all information required by the PCM driver to perform the
+ * PDC DMA operation. All fields except dma_intr_handler() are initialized
+ * by the interface. The dms_intr_handler() pointer is set by the PCM
+ * driver and called by the interface SSC interrupt handler if it is
+ * non-NULL.
+ */
+struct at91_pcm_dma_params {
+ char *name; /* stream identifier */
+ int pdc_xfer_size; /* PDC counter increment in bytes */
+ void __iomem *ssc_base; /* SSC base address */
+ struct at91_pdc_regs *pdc; /* PDC receive or transmit registers */
+ struct at91_ssc_mask *mask;/* SSC & PDC status bits */
+ struct snd_pcm_substream *substream;
+ void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
+};
+
+extern struct snd_soc_platform at91_soc_platform;
+
+#define at91_ssc_read(a) ((unsigned long) __raw_readl(a))
+#define at91_ssc_write(a,v) __raw_writel((v),(a))
+
+#endif /* _AT91_PCM_H */
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c
new file mode 100644
index 00000000000..8179df3bb2f
--- /dev/null
+++ b/sound/soc/at91/eti_b1_wm8731.c
@@ -0,0 +1,375 @@
+/*
+ * eti_b1_wm8731 -- SoC audio for AT91RM9200-based Endrelia ETI_B1 board.
+ *
+ * Author: Frank Mandarino <fmandarino@endrelia.com>
+ * Endrelia Technologies Inc.
+ * Created: Mar 29, 2006
+ *
+ * Based on corgi.c by:
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Richard Purdie <richard@openedhand.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 <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_pio.h>
+#include <asm/arch/gpio.h>
+
+#include "../codecs/wm8731.h"
+#include "at91-pcm.h"
+#include "at91-i2s.h"
+
+#if 0
+#define DBG(x...) printk(KERN_INFO "eti_b1_wm8731: " x)
+#else
+#define DBG(x...)
+#endif
+
+#define AT91_PIO_TF1 (1 << (AT91_PIN_PB6 - PIN_BASE) % 32)
+#define AT91_PIO_TK1 (1 << (AT91_PIN_PB7 - PIN_BASE) % 32)
+#define AT91_PIO_TD1 (1 << (AT91_PIN_PB8 - PIN_BASE) % 32)
+#define AT91_PIO_RD1 (1 << (AT91_PIN_PB9 - PIN_BASE) % 32)
+#define AT91_PIO_RK1 (1 << (AT91_PIN_PB10 - PIN_BASE) % 32)
+#define AT91_PIO_RF1 (1 << (AT91_PIN_PB11 - PIN_BASE) % 32)
+
+static struct clk *pck1_clk;
+static struct clk *pllb_clk;
+
+
+static int eti_b1_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret;
+
+ /* cpu clock is the AT91 master clock sent to the SSC */
+ ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, AT91_SYSCLK_MCK,
+ 60000000, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* codec system clock is supplied by PCK1, set to 12MHz */
+ ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK,
+ 12000000, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* Start PCK1 clock. */
+ clk_enable(pck1_clk);
+ DBG("pck1 started\n");
+
+ return 0;
+}
+
+static void eti_b1_shutdown(struct snd_pcm_substream *substream)
+{
+ /* Stop PCK1 clock. */
+ clk_disable(pck1_clk);
+ DBG("pck1 stopped\n");
+}
+
+static int eti_b1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret;
+
+#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
+ unsigned int rate;
+ int cmr_div, period;
+
+ /* set codec DAI configuration */
+ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * The SSC clock dividers depend on the sample rate. The CMR.DIV
+ * field divides the system master clock MCK to drive the SSC TK
+ * signal which provides the codec BCLK. The TCMR.PERIOD and
+ * RCMR.PERIOD fields further divide the BCLK signal to drive
+ * the SSC TF and RF signals which provide the codec DACLRC and
+ * ADCLRC clocks.
+ *
+ * The dividers were determined through trial and error, where a
+ * CMR.DIV value is chosen such that the resulting BCLK value is
+ * divisible, or almost divisible, by (2 * sample rate), and then
+ * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
+ */
+ rate = params_rate(params);
+
+ switch (rate) {
+ case 8000:
+ cmr_div = 25; /* BCLK = 60MHz/(2*25) = 1.2MHz */
+ period = 74; /* LRC = BCLK/(2*(74+1)) = 8000Hz */
+ break;
+ case 32000:
+ cmr_div = 7; /* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */
+ period = 66; /* LRC = BCLK/(2*(66+1)) = 31982.942Hz */
+ break;
+ case 48000:
+ cmr_div = 13; /* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */
+ period = 23; /* LRC = BCLK/(2*(23+1)) = 48076.923Hz */
+ break;
+ default:
+ printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate);
+ return -EINVAL;
+ }
+
+ /* set the MCK divider for BCLK */
+ ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div);
+ if (ret < 0)
+ return ret;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* set the BCLK divider for DACLRC */
+ ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai,
+ AT91SSC_TCMR_PERIOD, period);
+ } else {
+ /* set the BCLK divider for ADCLRC */
+ ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai,
+ AT91SSC_RCMR_PERIOD, period);
+ }
+ if (ret < 0)
+ return ret;
+
+#else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
+ /*
+ * Codec in Master Mode.
+ */
+
+ /* set codec DAI configuration */
+ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+#endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
+
+ return 0;
+}
+
+static struct snd_soc_ops eti_b1_ops = {
+ .startup = eti_b1_startup,
+ .hw_params = eti_b1_hw_params,
+ .shutdown = eti_b1_shutdown,
+};
+
+
+static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = {
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const char *intercon[][3] = {
+
+ /* speaker connected to LHPOUT */
+ {"Ext Spk", NULL, "LHPOUT"},
+
+ /* mic is connected to Mic Jack, with WM8731 Mic Bias */
+ {"MICIN", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Int Mic"},
+
+ /* terminator */
+ {NULL, NULL, NULL},
+};
+
+/*
+ * Logic for a wm8731 as connected on a Endrelia ETI-B1 board.
+ */
+static int eti_b1_wm8731_init(struct snd_soc_codec *codec)
+{
+ int i;
+
+ DBG("eti_b1_wm8731_init() called\n");
+
+ /* Add specific widgets */
+ for(i = 0; i < ARRAY_SIZE(eti_b1_dapm_widgets); i++) {
+ snd_soc_dapm_new_control(codec, &eti_b1_dapm_widgets[i]);
+ }
+
+ /* Set up specific audio path interconnects */
+ for(i = 0; intercon[i][0] != NULL; i++) {
+ snd_soc_dapm_connect_input(codec, intercon[i][0],
+ intercon[i][1], intercon[i][2]);
+ }
+
+ /* not connected */
+ snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
+ snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
+
+ /* always connected */
+ snd_soc_dapm_set_endpoint(codec, "Int Mic", 1);
+ snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1);
+
+ snd_soc_dapm_sync_endpoints(codec);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link eti_b1_dai = {
+ .name = "WM8731",
+ .stream_name = "WM8731",
+ .cpu_dai = &at91_i2s_dai[1],
+ .codec_dai = &wm8731_dai,
+ .init = eti_b1_wm8731_init,
+ .ops = &eti_b1_ops,
+};
+
+static struct snd_soc_machine snd_soc_machine_eti_b1 = {
+ .name = "ETI_B1",
+ .dai_link = &eti_b1_dai,
+ .num_links = 1,
+};
+
+static struct wm8731_setup_data eti_b1_wm8731_setup = {
+ .i2c_address = 0x1a,
+};
+
+static struct snd_soc_device eti_b1_snd_devdata = {
+ .machine = &snd_soc_machine_eti_b1,
+ .platform = &at91_soc_platform,
+ .codec_dev = &soc_codec_dev_wm8731,
+ .codec_data = &eti_b1_wm8731_setup,
+};
+
+static struct platform_device *eti_b1_snd_device;
+
+static int __init eti_b1_init(void)
+{
+ int ret;
+ u32 ssc_pio_lines;
+ struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
+
+ if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) {
+ DBG("SSC1 memory region is busy\n");
+ return -EBUSY;
+ }
+
+ ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K);
+ if (!ssc->base) {
+ DBG("SSC1 memory ioremap failed\n");
+ ret = -ENOMEM;
+ goto fail_release_mem;
+ }
+
+ ssc->pid = AT91RM9200_ID_SSC1;
+
+ eti_b1_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!eti_b1_snd_device) {
+ DBG("platform device allocation failed\n");
+ ret = -ENOMEM;
+ goto fail_io_unmap;
+ }
+
+ platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata);
+ eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev;
+
+ ret = platform_device_add(eti_b1_snd_device);
+ if (ret) {
+ DBG("platform device add failed\n");
+ platform_device_put(eti_b1_snd_device);
+ goto fail_io_unmap;
+ }
+
+ ssc_pio_lines = AT91_PIO_TF1 | AT91_PIO_TK1 | AT91_PIO_TD1
+ | AT91_PIO_RD1 /* | AT91_PIO_RK1 */ | AT91_PIO_RF1;
+
+ /* Reset all PIO registers and assign lines to peripheral A */
+ at91_sys_write(AT91_PIOB + PIO_PDR, ssc_pio_lines);
+ at91_sys_write(AT91_PIOB + PIO_ODR, ssc_pio_lines);
+ at91_sys_write(AT91_PIOB + PIO_IFDR, ssc_pio_lines);
+ at91_sys_write(AT91_PIOB + PIO_CODR, ssc_pio_lines);
+ at91_sys_write(AT91_PIOB + PIO_IDR, ssc_pio_lines);
+ at91_sys_write(AT91_PIOB + PIO_MDDR, ssc_pio_lines);
+ at91_sys_write(AT91_PIOB + PIO_PUDR, ssc_pio_lines);
+ at91_sys_write(AT91_PIOB + PIO_ASR, ssc_pio_lines);
+ at91_sys_write(AT91_PIOB + PIO_OWDR, ssc_pio_lines);
+
+ /*
+ * Set PCK1 parent to PLLB and its rate to 12 Mhz.
+ */
+ pllb_clk = clk_get(NULL, "pllb");
+ pck1_clk = clk_get(NULL, "pck1");
+
+ clk_set_parent(pck1_clk, pllb_clk);
+ clk_set_rate(pck1_clk, 12000000);
+
+ DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk));
+
+ /* assign the GPIO pin to PCK1 */
+ at91_set_B_periph(AT91_PIN_PA24, 0);
+
+#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
+ printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n");
+#else
+ printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n");
+#endif
+ return ret;
+
+fail_io_unmap:
+ iounmap(ssc->base);
+fail_release_mem:
+ release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
+ return ret;
+}
+
+static void __exit eti_b1_exit(void)
+{
+ struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
+
+ clk_put(pck1_clk);
+ clk_put(pllb_clk);
+
+ platform_device_unregister(eti_b1_snd_device);
+
+ iounmap(ssc->base);
+ release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
+}
+
+module_init(eti_b1_init);
+module_exit(eti_b1_exit);
+
+/* Module information */
+MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
+MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
new file mode 100644
index 00000000000..78ac2688e12
--- /dev/null
+++ b/sound/soc/codecs/Kconfig
@@ -0,0 +1,15 @@
+config SND_SOC_AC97_CODEC
+ tristate
+ depends SND_SOC
+
+config SND_SOC_WM8731
+ tristate
+ depends SND_SOC
+
+config SND_SOC_WM8750
+ tristate
+ depends SND_SOC
+
+config SND_SOC_WM9712
+ tristate
+ depends SND_SOC
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
new file mode 100644
index 00000000000..3249a6e4f1d
--- /dev/null
+++ b/sound/soc/codecs/Makefile
@@ -0,0 +1,9 @@
+snd-soc-ac97-objs := ac97.o
+snd-soc-wm8731-objs := wm8731.o
+snd-soc-wm8750-objs := wm8750.o
+snd-soc-wm9712-objs := wm9712.o
+
+obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
+obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
+obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
+obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
new file mode 100644
index 00000000000..55bc55eb6e2
--- /dev/null
+++ b/sound/soc/codecs/ac97.c
@@ -0,0 +1,156 @@
+/*
+ * ac97.c -- ALSA Soc AC97 codec support
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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.
+ *
+ * Revision history
+ * 17th Oct 2005 Initial version.
+ *
+ * Generic AC97 support.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#define AC97_VERSION "0.6"
+
+static int ac97_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+
+ int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
+ return snd_ac97_set_rate(codec->ac97, reg, runtime->rate);
+}
+
+#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_codec_dai ac97_dai = {
+ .name = "AC97 HiFi",
+ .playback = {
+ .stream_name = "AC97 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = STD_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .stream_name = "AC97 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = STD_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .prepare = ac97_prepare,},
+};
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ return soc_ac97_ops.read(codec->ac97, reg);
+}
+
+static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int val)
+{
+ soc_ac97_ops.write(codec->ac97, reg, val);
+ return 0;
+}
+
+static int ac97_soc_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ struct snd_ac97_bus *ac97_bus;
+ struct snd_ac97_template ac97_template;
+ int ret = 0;
+
+ printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
+
+ socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (socdev->codec == NULL)
+ return -ENOMEM;
+ codec = socdev->codec;
+ mutex_init(&codec->mutex);
+
+ codec->name = "AC97";
+ codec->owner = THIS_MODULE;
+ codec->dai = &ac97_dai;
+ codec->num_dai = 1;
+ codec->write = ac97_write;
+ codec->read = ac97_read;
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if(ret < 0)
+ goto err;
+
+ /* add codec as bus device for standard ac97 */
+ ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus);
+ if(ret < 0)
+ goto bus_err;
+
+ memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
+ ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
+ if(ret < 0)
+ goto bus_err;
+
+ ret = snd_soc_register_card(socdev);
+ if (ret < 0)
+ goto bus_err;
+ return 0;
+
+bus_err:
+ snd_soc_free_pcms(socdev);
+
+err:
+ kfree(socdev->codec->reg_cache);
+ kfree(socdev->codec);
+ socdev->codec = NULL;
+ return ret;
+}
+
+static int ac97_soc_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+
+ if(codec == NULL)
+ return 0;
+
+ snd_soc_free_pcms(socdev);
+ kfree(socdev->codec->reg_cache);
+ kfree(socdev->codec);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ac97= {
+ .probe = ac97_soc_probe,
+ .remove = ac97_soc_remove,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
+
+MODULE_DESCRIPTION("Soc Generic AC97 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ac97.h b/sound/soc/codecs/ac97.h
new file mode 100644
index 00000000000..930ddfc2321
--- /dev/null
+++ b/sound/soc/codecs/ac97.h
@@ -0,0 +1,18 @@
+/*
+ * linux/sound/codecs/ac97.h -- ALSA SoC Layer
+ *
+ * Author: Liam Girdwood
+ * Created: Dec 1st 2005
+ * Copyright: Wolfson Microelectronics. PLC.
+ *
+ * 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 __LINUX_SND_SOC_AC97_H
+#define __LINUX_SND_SOC_AC97_H
+
+extern struct snd_soc_codec_device soc_codec_dev_ac97;
+
+#endif
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
new file mode 100644
index 00000000000..7ca0b526828
--- /dev/null
+++ b/sound/soc/codecs/wm8731.c
@@ -0,0 +1,758 @@
+/*
+ * wm8731.c -- WM8731 ALSA SoC Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.c by Liam Girdwood
+ *
+ * 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/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8731.h"
+
+#define AUDIO_NAME "wm8731"
+#define WM8731_VERSION "0.13"
+
+/*
+ * Debug
+ */
+
+#define WM8731_DEBUG 0
+
+#ifdef WM8731_DEBUG
+#define dbg(format, arg...) \
+ printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) \
+ printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
+#define info(format, arg...) \
+ printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
+#define warn(format, arg...) \
+ printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
+
+struct snd_soc_codec_device soc_codec_dev_wm8731;
+
+/* codec private data */
+struct wm8731_priv {
+ unsigned int sysclk;
+};
+
+/*
+ * wm8731 register cache
+ * We can't read the WM8731 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
+ 0x0097, 0x0097, 0x0079, 0x0079,
+ 0x000a, 0x0008, 0x009f, 0x000a,
+ 0x0000, 0x0000
+};
+
+/*
+ * read wm8731 register cache
+ */
+static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+ if (reg == WM8731_RESET)
+ return 0;
+ if (reg >= WM8731_CACHEREGNUM)
+ return -1;
+ return cache[reg];
+}
+
+/*
+ * write wm8731 register cache
+ */
+static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec,
+ u16 reg, unsigned int value)
+{
+ u16 *cache = codec->reg_cache;
+ if (reg >= WM8731_CACHEREGNUM)
+ return;
+ cache[reg] = value;
+}
+
+/*
+ * write to the WM8731 register space
+ */
+static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ u8 data[2];
+
+ /* data is
+ * D15..D9 WM8731 register offset
+ * D8...D0 register data
+ */
+ data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+ data[1] = value & 0x00ff;
+
+ wm8731_write_reg_cache (codec, reg, value);
+ if (codec->hw_write(codec->control_data, data, 2) == 2)
+ return 0;
+ else
+ return -EIO;
+}
+
+#define wm8731_reset(c) wm8731_write(c, WM8731_RESET, 0)
+
+static const char *wm8731_input_select[] = {"Line In", "Mic"};
+static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum wm8731_enum[] = {
+ SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select),
+ SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph),
+};
+
+static const struct snd_kcontrol_new wm8731_snd_controls[] = {
+
+SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V,
+ 0, 127, 0),
+SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V,
+ 7, 1, 0),
+
+SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0),
+SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1),
+
+SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0),
+SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1),
+
+SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1),
+
+SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
+SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
+
+SOC_ENUM("Playback De-emphasis", wm8731_enum[1]),
+};
+
+/* add non dapm controls */
+static int wm8731_add_controls(struct snd_soc_codec *codec)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) {
+ if ((err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&wm8731_snd_controls[i],codec, NULL))) < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Output Mixer */
+static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
+};
+
+/* Input mux */
+static const struct snd_kcontrol_new wm8731_input_mux_controls =
+SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
+
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
+ &wm8731_output_mixer_controls[0],
+ ARRAY_SIZE(wm8731_output_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1),
+SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8731_input_mux_controls),
+SND_SOC_DAPM_PGA("Line Input", WM8731_PWR, 0, 1, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias", WM8731_PWR, 1, 1),
+SND_SOC_DAPM_INPUT("MICIN"),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const char *intercon[][3] = {
+ /* output mixer */
+ {"Output Mixer", "Line Bypass Switch", "Line Input"},
+ {"Output Mixer", "HiFi Playback Switch", "DAC"},
+ {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
+
+ /* outputs */
+ {"RHPOUT", NULL, "Output Mixer"},
+ {"ROUT", NULL, "Output Mixer"},
+ {"LHPOUT", NULL, "Output Mixer"},
+ {"LOUT", NULL, "Output Mixer"},
+
+ /* input mux */
+ {"Input Mux", "Line In", "Line Input"},
+ {"Input Mux", "Mic", "Mic Bias"},
+ {"ADC", NULL, "Input Mux"},
+
+ /* inputs */
+ {"Line Input", NULL, "LLINEIN"},
+ {"Line Input", NULL, "RLINEIN"},
+ {"Mic Bias", NULL, "MICIN"},
+
+ /* terminator */
+ {NULL, NULL, NULL},
+};
+
+static int wm8731_add_widgets(struct snd_soc_codec *codec)
+{
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) {
+ snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
+ }
+
+ /* set up audio path interconnects */
+ for(i = 0; intercon[i][0] != NULL; i++) {
+ snd_soc_dapm_connect_input(codec, intercon[i][0],
+ intercon[i][1], intercon[i][2]);
+ }
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+struct _coeff_div {
+ u32 mclk;
+ u32 rate;
+ u16 fs;
+ u8 sr:4;
+ u8 bosr:1;
+ u8 usb:1;
+};
+
+/* codec mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+ /* 48k */
+ {12288000, 48000, 256, 0x0, 0x0, 0x0},
+ {18432000, 48000, 384, 0x0, 0x1, 0x0},
+ {12000000, 48000, 250, 0x0, 0x0, 0x1},
+
+ /* 32k */
+ {12288000, 32000, 384, 0x6, 0x0, 0x0},
+ {18432000, 32000, 576, 0x6, 0x1, 0x0},
+ {12000000, 32000, 375, 0x6, 0x0, 0x1},
+
+ /* 8k */
+ {12288000, 8000, 1536, 0x3, 0x0, 0x0},
+ {18432000, 8000, 2304, 0x3, 0x1, 0x0},
+ {11289600, 8000, 1408, 0xb, 0x0, 0x0},
+ {16934400, 8000, 2112, 0xb, 0x1, 0x0},
+ {12000000, 8000, 1500, 0x3, 0x0, 0x1},
+
+ /* 96k */
+ {12288000, 96000, 128, 0x7, 0x0, 0x0},
+ {18432000, 96000, 192, 0x7, 0x1, 0x0},
+ {12000000, 96000, 125, 0x7, 0x0, 0x1},
+
+ /* 44.1k */
+ {11289600, 44100, 256, 0x8, 0x0, 0x0},
+ {16934400, 44100, 384, 0x8, 0x1, 0x0},
+ {12000000, 44100, 272, 0x8, 0x1, 0x1},
+
+ /* 88.2k */
+ {11289600, 88200, 128, 0xf, 0x0, 0x0},
+ {16934400, 88200, 192, 0xf, 0x1, 0x0},
+ {12000000, 88200, 136, 0xf, 0x1, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+ return i;
+ }
+ return 0;
+}
+
+static int wm8731_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+ struct wm8731_priv *wm8731 = codec->private_data;
+ u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3;
+ int i = get_coeff(wm8731->sysclk, params_rate(params));
+ u16 srate = (coeff_div[i].sr << 2) |
+ (coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+ wm8731_write(codec, WM8731_SRATE, srate);
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface |= 0x0004;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iface |= 0x0008;
+ break;
+ }
+
+ wm8731_write(codec, WM8731_IFACE, iface);
+ return 0;
+}
+
+static int wm8731_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+
+ /* set active */
+ wm8731_write(codec, WM8731_ACTIVE, 0x0001);
+
+ return 0;
+}
+
+static void wm8731_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+
+ /* deactivate */
+ if (!codec->active) {
+ udelay(50);
+ wm8731_write(codec, WM8731_ACTIVE, 0x0);
+ }
+}
+
+static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7;
+
+ if (mute)
+ wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8);
+ else
+ wm8731_write(codec, WM8731_APDIGI, mute_reg);
+ return 0;
+}
+
+static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8731_priv *wm8731 = codec->private_data;
+
+ switch (freq) {
+ case 11289600:
+ case 12000000:
+ case 12288000:
+ case 16934400:
+ case 18432000:
+ wm8731->sysclk = freq;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 iface = 0;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ iface |= 0x0040;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ iface |= 0x0002;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface |= 0x0001;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface |= 0x0003;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ iface |= 0x0013;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ iface |= 0x0090;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= 0x0080;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ iface |= 0x0010;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set iface */
+ wm8731_write(codec, WM8731_IFACE, iface);
+ return 0;
+}
+
+static int wm8731_dapm_event(struct snd_soc_codec *codec, int event)
+{
+ u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;
+
+ switch (event) {
+ case SNDRV_CTL_POWER_D0: /* full On */
+ /* vref/mid, osc on, dac unmute */
+ wm8731_write(codec, WM8731_PWR, reg);
+ break;
+ case SNDRV_CTL_POWER_D1: /* partial On */
+ case SNDRV_CTL_POWER_D2: /* partial On */
+ break;
+ case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+ /* everything off except vref/vmid, */
+ wm8731_write(codec, WM8731_PWR, reg | 0x0040);
+ break;
+ case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+ /* everything off, dac mute, inactive */
+ wm8731_write(codec, WM8731_ACTIVE, 0x0);
+ wm8731_write(codec, WM8731_PWR, 0xffff);
+ break;
+ }
+ codec->dapm_state = event;
+ return 0;
+}
+
+#define WM8731_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000)
+
+#define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_codec_dai wm8731_dai = {
+ .name = "WM8731",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8731_RATES,
+ .formats = WM8731_FORMATS,},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8731_RATES,
+ .formats = WM8731_FORMATS,},
+ .ops = {
+ .prepare = wm8731_pcm_prepare,
+ .hw_params = wm8731_hw_params,
+ .shutdown = wm8731_shutdown,
+ },
+ .dai_ops = {
+ .digital_mute = wm8731_mute,
+ .set_sysclk = wm8731_set_dai_sysclk,
+ .set_fmt = wm8731_set_dai_fmt,
+ }
+};
+EXPORT_SYMBOL_GPL(wm8731_dai);
+
+static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+
+ wm8731_write(codec, WM8731_ACTIVE, 0x0);
+ wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+ return 0;
+}
+
+static int wm8731_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+ int i;
+ u8 data[2];
+ u16 *cache = codec->reg_cache;
+
+ /* Sync reg_cache with the hardware */
+ for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
+ data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+ data[1] = cache[i] & 0x00ff;
+ codec->hw_write(codec->control_data, data, 2);
+ }
+ wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+ wm8731_dapm_event(codec, codec->suspend_dapm_state);
+ return 0;
+}
+
+/*
+ * initialise the WM8731 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8731_init(struct snd_soc_device *socdev)
+{
+ struct snd_soc_codec *codec = socdev->codec;
+ int reg, ret = 0;
+
+ codec->name = "WM8731";
+ codec->owner = THIS_MODULE;
+ codec->read = wm8731_read_reg_cache;
+ codec->write = wm8731_write;
+ codec->dapm_event = wm8731_dapm_event;
+ codec->dai = &wm8731_dai;
+ codec->num_dai = 1;
+ codec->reg_cache_size = sizeof(wm8731_reg);
+ codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL);
+ if (codec->reg_cache == NULL)
+ return -ENOMEM;
+
+ wm8731_reset(codec);
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "wm8731: failed to create pcms\n");
+ goto pcm_err;
+ }
+
+ /* power on device */
+ wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+ /* set the update bits */
+ reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
+ wm8731_write(codec, WM8731_LOUT1V, reg | 0x0100);
+ reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
+ wm8731_write(codec, WM8731_ROUT1V, reg | 0x0100);
+ reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
+ wm8731_write(codec, WM8731_LINVOL, reg | 0x0100);
+ reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
+ wm8731_write(codec, WM8731_RINVOL, reg | 0x0100);
+
+ wm8731_add_controls(codec);
+ wm8731_add_widgets(codec);
+ ret = snd_soc_register_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "wm8731: failed to register card\n");
+ goto card_err;
+ }
+
+ return ret;
+
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+pcm_err:
+ kfree(codec->reg_cache);
+ return ret;
+}
+
+static struct snd_soc_device *wm8731_socdev;
+
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+
+/*
+ * WM8731 2 wire address is determined by GPIO5
+ * state during powerup.
+ * low = 0x1a
+ * high = 0x1b
+ */
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver wm8731_i2c_driver;
+static struct i2c_client client_template;
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+ around */
+
+static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+ struct snd_soc_device *socdev = wm8731_socdev;
+ struct wm8731_setup_data *setup = socdev->codec_data;
+ struct snd_soc_codec *codec = socdev->codec;
+ struct i2c_client *i2c;
+ int ret;
+
+ if (addr != setup->i2c_address)
+ return -ENODEV;
+
+ client_template.adapter = adap;
+ client_template.addr = addr;
+
+ i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+ if (i2c == NULL) {
+ kfree(codec);
+ return -ENOMEM;
+ }
+ i2c_set_clientdata(i2c, codec);
+ codec->control_data = i2c;
+
+ ret = i2c_attach_client(i2c);
+ if (ret < 0) {
+ err("failed to attach codec at addr %x\n", addr);
+ goto err;
+ }
+
+ ret = wm8731_init(socdev);
+ if (ret < 0) {
+ err("failed to initialise WM8731\n");
+ goto err;
+ }
+ return ret;
+
+err:
+ kfree(codec);
+ kfree(i2c);
+ return ret;
+}
+
+static int wm8731_i2c_detach(struct i2c_client *client)
+{
+ struct snd_soc_codec* codec = i2c_get_clientdata(client);
+ i2c_detach_client(client);
+ kfree(codec->reg_cache);
+ kfree(client);
+ return 0;
+}
+
+static int wm8731_i2c_attach(struct i2c_adapter *adap)
+{
+ return i2c_probe(adap, &addr_data, wm8731_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver wm8731_i2c_driver = {
+ .driver = {
+ .name = "WM8731 I2C Codec",
+ .owner = THIS_MODULE,
+ },
+ .id = I2C_DRIVERID_WM8731,
+ .attach_adapter = wm8731_i2c_attach,
+ .detach_client = wm8731_i2c_detach,
+ .command = NULL,
+};
+
+static struct i2c_client client_template = {
+ .name = "WM8731",
+ .driver = &wm8731_i2c_driver,
+};
+#endif
+
+static int wm8731_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct wm8731_setup_data *setup;
+ struct snd_soc_codec *codec;
+ struct wm8731_priv *wm8731;
+ int ret = 0;
+
+ info("WM8731 Audio Codec %s", WM8731_VERSION);
+
+ setup = socdev->codec_data;
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL)
+ return -ENOMEM;
+
+ wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
+ if (wm8731 == NULL) {
+ kfree(codec);
+ return -ENOMEM;
+ }
+
+ codec->private_data = wm8731;
+ socdev->codec = codec;
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ wm8731_socdev = socdev;
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+ if (setup->i2c_address) {
+ normal_i2c[0] = setup->i2c_address;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+ ret = i2c_add_driver(&wm8731_i2c_driver);
+ if (ret != 0)
+ printk(KERN_ERR "can't add i2c driver");
+ }
+#else
+ /* Add other interfaces here */
+#endif
+ return ret;
+}
+
+/* power down chip */
+static int wm8731_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+
+ if (codec->control_data)
+ wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8731_i2c_driver);
+#endif
+ kfree(codec->private_data);
+ kfree(codec);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8731 = {
+ .probe = wm8731_probe,
+ .remove = wm8731_remove,
+ .suspend = wm8731_suspend,
+ .resume = wm8731_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
+
+MODULE_DESCRIPTION("ASoC WM8731 driver");
+MODULE_AUTHOR("Richard Purdie");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h
new file mode 100644
index 00000000000..5bcab6a7afb
--- /dev/null
+++ b/sound/soc/codecs/wm8731.h
@@ -0,0 +1,44 @@
+/*
+ * wm8731.h -- WM8731 Soc Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.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.
+ */
+
+#ifndef _WM8731_H
+#define _WM8731_H
+
+/* WM8731 register space */
+
+#define WM8731_LINVOL 0x00
+#define WM8731_RINVOL 0x01
+#define WM8731_LOUT1V 0x02
+#define WM8731_ROUT1V 0x03
+#define WM8731_APANA 0x04
+#define WM8731_APDIGI 0x05
+#define WM8731_PWR 0x06
+#define WM8731_IFACE 0x07
+#define WM8731_SRATE 0x08
+#define WM8731_ACTIVE 0x09
+#define WM8731_RESET 0x0f
+
+#define WM8731_CACHEREGNUM 10
+
+#define WM8731_SYSCLK 0
+#define WM8731_DAI 0
+
+struct wm8731_setup_data {
+ unsigned short i2c_address;
+};
+
+extern struct snd_soc_codec_dai wm8731_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8731;
+
+#endif
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
new file mode 100644
index 00000000000..7073e8e294f
--- /dev/null
+++ b/sound/soc/codecs/wm8750.c
@@ -0,0 +1,1049 @@
+/*
+ * wm8750.c -- WM8750 ALSA SoC audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on WM8753.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8750.h"
+
+#define AUDIO_NAME "WM8750"
+#define WM8750_VERSION "0.12"
+
+/*
+ * Debug
+ */
+
+#define WM8750_DEBUG 0
+
+#ifdef WM8750_DEBUG
+#define dbg(format, arg...) \
+ printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) \
+ printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
+#define info(format, arg...) \
+ printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
+#define warn(format, arg...) \
+ printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
+
+/* codec private data */
+struct wm8750_priv {
+ unsigned int sysclk;
+};
+
+/*
+ * wm8750 register cache
+ * We can't read the WM8750 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const u16 wm8750_reg[] = {
+ 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */
+ 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */
+ 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */
+ 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */
+ 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */
+ 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */
+ 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */
+ 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */
+ 0x0079, 0x0079, 0x0079, /* 40 */
+};
+
+/*
+ * read wm8750 register cache
+ */
+static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+ if (reg > WM8750_CACHE_REGNUM)
+ return -1;
+ return cache[reg];
+}
+
+/*
+ * write wm8750 register cache
+ */
+static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int value)
+{
+ u16 *cache = codec->reg_cache;
+ if (reg > WM8750_CACHE_REGNUM)
+ return;
+ cache[reg] = value;
+}
+
+static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ u8 data[2];
+
+ /* data is
+ * D15..D9 WM8753 register offset
+ * D8...D0 register data
+ */
+ data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+ data[1] = value & 0x00ff;
+
+ wm8750_write_reg_cache (codec, reg, value);
+ if (codec->hw_write(codec->control_data, data, 2) == 2)
+ return 0;
+ else
+ return -EIO;
+}
+
+#define wm8750_reset(c) wm8750_write(c, WM8750_RESET, 0)
+
+/*
+ * WM8750 Controls
+ */
+static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"};
+static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
+static const char *wm8750_treble[] = {"8kHz", "4kHz"};
+static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"};
+static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"};
+static const char *wm8750_3d_func[] = {"Capture", "Playback"};
+static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"};
+static const char *wm8750_ng_type[] = {"Constant PGA Gain",
+ "Mute ADC Output"};
+static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA",
+ "Differential"};
+static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3",
+ "Differential"};
+static const char *wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut",
+ "ROUT1"};
+static const char *wm8750_diff_sel[] = {"Line 1", "Line 2"};
+static const char *wm8750_adcpol[] = {"Normal", "L Invert", "R Invert",
+ "L + R Invert"};
+static const char *wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+static const char *wm8750_mono_mux[] = {"Stereo", "Mono (Left)",
+ "Mono (Right)", "Digital Mono"};
+
+static const struct soc_enum wm8750_enum[] = {
+SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass),
+SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter),
+SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble),
+SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc),
+SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc),
+SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func),
+SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func),
+SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type),
+SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux),
+SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux),
+SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */
+SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel),
+SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3),
+SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel),
+SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol),
+SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph),
+SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */
+
+};
+
+static const struct snd_kcontrol_new wm8750_snd_controls[] = {
+
+SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0),
+SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0),
+SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1),
+
+SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8750_LOUT1V,
+ WM8750_ROUT1V, 7, 1, 0),
+SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8750_LOUT2V,
+ WM8750_ROUT2V, 7, 1, 0),
+
+SOC_ENUM("Playback De-emphasis", wm8750_enum[15]),
+
+SOC_ENUM("Capture Polarity", wm8750_enum[14]),
+SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0),
+SOC_SINGLE("Capture 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0),
+
+SOC_DOUBLE_R("PCM Volume", WM8750_LDAC, WM8750_RDAC, 0, 255, 0),
+
+SOC_ENUM("Bass Boost", wm8750_enum[0]),
+SOC_ENUM("Bass Filter", wm8750_enum[1]),
+SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1),
+
+SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 0),
+SOC_ENUM("Treble Cut-off", wm8750_enum[2]),
+
+SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0),
+SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0),
+SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]),
+SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]),
+SOC_ENUM("3D Mode", wm8750_enum[5]),
+
+SOC_SINGLE("ALC Capture Target Volume", WM8750_ALC1, 0, 7, 0),
+SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0),
+SOC_ENUM("ALC Capture Function", wm8750_enum[6]),
+SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0),
+SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0),
+SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0),
+SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0),
+SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0),
+SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]),
+SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0),
+
+SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0),
+SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0),
+
+SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0),
+SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0),
+
+SOC_SINGLE("Right Speaker Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0),
+
+/* Unimplemented */
+/* ADCDAC Bit 0 - ADCHPD */
+/* ADCDAC Bit 4 - HPOR */
+/* ADCTL1 Bit 2,3 - DATSEL */
+/* ADCTL1 Bit 4,5 - DMONOMIX */
+/* ADCTL1 Bit 6,7 - VSEL */
+/* ADCTL2 Bit 2 - LRCM */
+/* ADCTL2 Bit 3 - TRI */
+/* ADCTL3 Bit 5 - HPFLREN */
+/* ADCTL3 Bit 6 - VROI */
+/* ADCTL3 Bit 7,8 - ADCLRM */
+/* ADCIN Bit 4 - LDCM */
+/* ADCIN Bit 5 - RDCM */
+
+SOC_DOUBLE_R("Mic Boost", WM8750_LADCIN, WM8750_RADCIN, 4, 3, 0),
+
+SOC_DOUBLE_R("Bypass Left Playback Volume", WM8750_LOUTM1,
+ WM8750_LOUTM2, 4, 7, 1),
+SOC_DOUBLE_R("Bypass Right Playback Volume", WM8750_ROUTM1,
+ WM8750_ROUTM2, 4, 7, 1),
+SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1,
+ WM8750_MOUTM2, 4, 7, 1),
+
+SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0),
+
+SOC_DOUBLE_R("Headphone Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V,
+ 0, 127, 0),
+SOC_DOUBLE_R("Speaker Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V,
+ 0, 127, 0),
+
+SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0),
+
+};
+
+/* add non dapm controls */
+static int wm8750_add_controls(struct snd_soc_codec *codec)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) {
+ err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&wm8750_snd_controls[i],codec, NULL));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+/*
+ * DAPM Controls
+ */
+
+/* Left Mixer */
+static const struct snd_kcontrol_new wm8750_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("Playback Switch", WM8750_LOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new wm8750_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new wm8750_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0),
+};
+
+/* Left Line Mux */
+static const struct snd_kcontrol_new wm8750_left_line_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[8]);
+
+/* Right Line Mux */
+static const struct snd_kcontrol_new wm8750_right_line_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[9]);
+
+/* Left PGA Mux */
+static const struct snd_kcontrol_new wm8750_left_pga_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[10]);
+
+/* Right PGA Mux */
+static const struct snd_kcontrol_new wm8750_right_pga_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[11]);
+
+/* Out 3 Mux */
+static const struct snd_kcontrol_new wm8750_out3_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[12]);
+
+/* Differential Mux */
+static const struct snd_kcontrol_new wm8750_diffmux_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[13]);
+
+/* Mono ADC Mux */
+static const struct snd_kcontrol_new wm8750_monomux_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[16]);
+
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+ SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+ &wm8750_left_mixer_controls[0],
+ ARRAY_SIZE(wm8750_left_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+ &wm8750_right_mixer_controls[0],
+ ARRAY_SIZE(wm8750_right_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0,
+ &wm8750_mono_mixer_controls[0],
+ ARRAY_SIZE(wm8750_mono_mixer_controls)),
+
+ SND_SOC_DAPM_PGA("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0),
+ SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0),
+
+ SND_SOC_DAPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0),
+ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0),
+
+ SND_SOC_DAPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0,
+ &wm8750_left_pga_controls),
+ SND_SOC_DAPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0,
+ &wm8750_right_pga_controls),
+ SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+ &wm8750_left_line_controls),
+ SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+ &wm8750_right_line_controls),
+
+ SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8750_out3_controls),
+ SND_SOC_DAPM_PGA("Out 3", WM8750_PWR2, 1, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Mono Out 1", WM8750_PWR2, 2, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+ &wm8750_diffmux_controls),
+ SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+ &wm8750_monomux_controls),
+ SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+ &wm8750_monomux_controls),
+
+ SND_SOC_DAPM_OUTPUT("LOUT1"),
+ SND_SOC_DAPM_OUTPUT("ROUT1"),
+ SND_SOC_DAPM_OUTPUT("LOUT2"),
+ SND_SOC_DAPM_OUTPUT("ROUT2"),
+ SND_SOC_DAPM_OUTPUT("MONO"),
+ SND_SOC_DAPM_OUTPUT("OUT3"),
+
+ SND_SOC_DAPM_INPUT("LINPUT1"),
+ SND_SOC_DAPM_INPUT("LINPUT2"),
+ SND_SOC_DAPM_INPUT("LINPUT3"),
+ SND_SOC_DAPM_INPUT("RINPUT1"),
+ SND_SOC_DAPM_INPUT("RINPUT2"),
+ SND_SOC_DAPM_INPUT("RINPUT3"),
+};
+
+static const char *audio_map[][3] = {
+ /* left mixer */
+ {"Left Mixer", "Playback Switch", "Left DAC"},
+ {"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
+ {"Left Mixer", "Right Playback Switch", "Right DAC"},
+ {"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+ /* right mixer */
+ {"Right Mixer", "Left Playback Switch", "Left DAC"},
+ {"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
+ {"Right Mixer", "Playback Switch", "Right DAC"},
+ {"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+ /* left out 1 */
+ {"Left Out 1", NULL, "Left Mixer"},
+ {"LOUT1", NULL, "Left Out 1"},
+
+ /* left out 2 */
+ {"Left Out 2", NULL, "Left Mixer"},
+ {"LOUT2", NULL, "Left Out 2"},
+
+ /* right out 1 */
+ {"Right Out 1", NULL, "Right Mixer"},
+ {"ROUT1", NULL, "Right Out 1"},
+
+ /* right out 2 */
+ {"Right Out 2", NULL, "Right Mixer"},
+ {"ROUT2", NULL, "Right Out 2"},
+
+ /* mono mixer */
+ {"Mono Mixer", "Left Playback Switch", "Left DAC"},
+ {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
+ {"Mono Mixer", "Right Playback Switch", "Right DAC"},
+ {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+ /* mono out */
+ {"Mono Out 1", NULL, "Mono Mixer"},
+ {"MONO1", NULL, "Mono Out 1"},
+
+ /* out 3 */
+ {"Out3 Mux", "VREF", "VREF"},
+ {"Out3 Mux", "ROUT1 + Vol", "ROUT1"},
+ {"Out3 Mux", "ROUT1", "Right Mixer"},
+ {"Out3 Mux", "MonoOut", "MONO1"},
+ {"Out 3", NULL, "Out3 Mux"},
+ {"OUT3", NULL, "Out 3"},
+
+ /* Left Line Mux */
+ {"Left Line Mux", "Line 1", "LINPUT1"},
+ {"Left Line Mux", "Line 2", "LINPUT2"},
+ {"Left Line Mux", "Line 3", "LINPUT3"},
+ {"Left Line Mux", "PGA", "Left PGA Mux"},
+ {"Left Line Mux", "Differential", "Differential Mux"},
+
+ /* Right Line Mux */
+ {"Right Line Mux", "Line 1", "RINPUT1"},
+ {"Right Line Mux", "Line 2", "RINPUT2"},
+ {"Right Line Mux", "Line 3", "RINPUT3"},
+ {"Right Line Mux", "PGA", "Right PGA Mux"},
+ {"Right Line Mux", "Differential", "Differential Mux"},
+
+ /* Left PGA Mux */
+ {"Left PGA Mux", "Line 1", "LINPUT1"},
+ {"Left PGA Mux", "Line 2", "LINPUT2"},
+ {"Left PGA Mux", "Line 3", "LINPUT3"},
+ {"Left PGA Mux", "Differential", "Differential Mux"},
+
+ /* Right PGA Mux */
+ {"Right PGA Mux", "Line 1", "RINPUT1"},
+ {"Right PGA Mux", "Line 2", "RINPUT2"},
+ {"Right PGA Mux", "Line 3", "RINPUT3"},
+ {"Right PGA Mux", "Differential", "Differential Mux"},
+
+ /* Differential Mux */
+ {"Differential Mux", "Line 1", "LINPUT1"},
+ {"Differential Mux", "Line 1", "RINPUT1"},
+ {"Differential Mux", "Line 2", "LINPUT2"},
+ {"Differential Mux", "Line 2", "RINPUT2"},
+
+ /* Left ADC Mux */
+ {"Left ADC Mux", "Stereo", "Left PGA Mux"},
+ {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
+ {"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
+
+ /* Right ADC Mux */
+ {"Right ADC Mux", "Stereo", "Right PGA Mux"},
+ {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
+ {"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
+
+ /* ADC */
+ {"Left ADC", NULL, "Left ADC Mux"},
+ {"Right ADC", NULL, "Right ADC Mux"},
+
+ /* terminator */
+ {NULL, NULL, NULL},
+};
+
+static int wm8750_add_widgets(struct snd_soc_codec *codec)
+{
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) {
+ snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]);
+ }
+
+ /* set up audio path audio_mapnects */
+ for(i = 0; audio_map[i][0] != NULL; i++) {
+ snd_soc_dapm_connect_input(codec, audio_map[i][0],
+ audio_map[i][1], audio_map[i][2]);
+ }
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+struct _coeff_div {
+ u32 mclk;
+ u32 rate;
+ u16 fs;
+ u8 sr:5;
+ u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+ /* 8k */
+ {12288000, 8000, 1536, 0x6, 0x0},
+ {11289600, 8000, 1408, 0x16, 0x0},
+ {18432000, 8000, 2304, 0x7, 0x0},
+ {16934400, 8000, 2112, 0x17, 0x0},
+ {12000000, 8000, 1500, 0x6, 0x1},
+
+ /* 11.025k */
+ {11289600, 11025, 1024, 0x18, 0x0},
+ {16934400, 11025, 1536, 0x19, 0x0},
+ {12000000, 11025, 1088, 0x19, 0x1},
+
+ /* 16k */
+ {12288000, 16000, 768, 0xa, 0x0},
+ {18432000, 16000, 1152, 0xb, 0x0},
+ {12000000, 16000, 750, 0xa, 0x1},
+
+ /* 22.05k */
+ {11289600, 22050, 512, 0x1a, 0x0},
+ {16934400, 22050, 768, 0x1b, 0x0},
+ {12000000, 22050, 544, 0x1b, 0x1},
+
+ /* 32k */
+ {12288000, 32000, 384, 0xc, 0x0},
+ {18432000, 32000, 576, 0xd, 0x0},
+ {12000000, 32000, 375, 0xa, 0x1},
+
+ /* 44.1k */
+ {11289600, 44100, 256, 0x10, 0x0},
+ {16934400, 44100, 384, 0x11, 0x0},
+ {12000000, 44100, 272, 0x11, 0x1},
+
+ /* 48k */
+ {12288000, 48000, 256, 0x0, 0x0},
+ {18432000, 48000, 384, 0x1, 0x0},
+ {12000000, 48000, 250, 0x0, 0x1},
+
+ /* 88.2k */
+ {11289600, 88200, 128, 0x1e, 0x0},
+ {16934400, 88200, 192, 0x1f, 0x0},
+ {12000000, 88200, 136, 0x1f, 0x1},
+
+ /* 96k */
+ {12288000, 96000, 128, 0xe, 0x0},
+ {18432000, 96000, 192, 0xf, 0x0},
+ {12000000, 96000, 125, 0xe, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+ return i;
+ }
+
+ printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n",
+ mclk, rate);
+ return -EINVAL;
+}
+
+static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8750_priv *wm8750 = codec->private_data;
+
+ switch (freq) {
+ case 11289600:
+ case 12000000:
+ case 12288000:
+ case 16934400:
+ case 18432000:
+ wm8750->sysclk = freq;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int wm8750_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 iface = 0;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ iface = 0x0040;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ iface |= 0x0002;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface |= 0x0001;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface |= 0x0003;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ iface |= 0x0013;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ iface |= 0x0090;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= 0x0080;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ iface |= 0x0010;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ wm8750_write(codec, WM8750_IFACE, iface);
+ return 0;
+}
+
+static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+ struct wm8750_priv *wm8750 = codec->private_data;
+ u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3;
+ u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0;
+ int coeff = get_coeff(wm8750->sysclk, params_rate(params));
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface |= 0x0004;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iface |= 0x0008;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ iface |= 0x000c;
+ break;
+ }
+
+ /* set iface & srate */
+ wm8750_write(codec, WM8750_IFACE, iface);
+ if (coeff >= 0)
+ wm8750_write(codec, WM8750_SRATE, srate |
+ (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
+
+ return 0;
+}
+
+static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7;
+
+ if (mute)
+ wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8);
+ else
+ wm8750_write(codec, WM8750_ADCDAC, mute_reg);
+ return 0;
+}
+
+static int wm8750_dapm_event(struct snd_soc_codec *codec, int event)
+{
+ u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e;
+
+ switch (event) {
+ case SNDRV_CTL_POWER_D0: /* full On */
+ /* set vmid to 50k and unmute dac */
+ wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
+ break;
+ case SNDRV_CTL_POWER_D1: /* partial On */
+ case SNDRV_CTL_POWER_D2: /* partial On */
+ /* set vmid to 5k for quick power up */
+ wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
+ break;
+ case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+ /* mute dac and set vmid to 500k, enable VREF */
+ wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141);
+ break;
+ case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+ wm8750_write(codec, WM8750_PWR1, 0x0001);
+ break;
+ }
+ codec->dapm_state = event;
+ return 0;
+}
+
+#define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_codec_dai wm8750_dai = {
+ .name = "WM8750",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8750_RATES,
+ .formats = WM8750_FORMATS,},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8750_RATES,
+ .formats = WM8750_FORMATS,},
+ .ops = {
+ .hw_params = wm8750_pcm_hw_params,
+ },
+ .dai_ops = {
+ .digital_mute = wm8750_mute,
+ .set_fmt = wm8750_set_dai_fmt,
+ .set_sysclk = wm8750_set_dai_sysclk,
+ },
+};
+EXPORT_SYMBOL_GPL(wm8750_dai);
+
+static void wm8750_work(struct work_struct *work)
+{
+ struct snd_soc_codec *codec =
+ container_of(work, struct snd_soc_codec, delayed_work.work);
+ wm8750_dapm_event(codec, codec->dapm_state);
+}
+
+static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+
+ wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+ return 0;
+}
+
+static int wm8750_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+ int i;
+ u8 data[2];
+ u16 *cache = codec->reg_cache;
+
+ /* Sync reg_cache with the hardware */
+ for (i = 0; i < ARRAY_SIZE(wm8750_reg); i++) {
+ if (i == WM8750_RESET)
+ continue;
+ data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+ data[1] = cache[i] & 0x00ff;
+ codec->hw_write(codec->control_data, data, 2);
+ }
+
+ wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+ /* charge wm8750 caps */
+ if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) {
+ wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2);
+ codec->dapm_state = SNDRV_CTL_POWER_D0;
+ schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));
+ }
+
+ return 0;
+}
+
+/*
+ * initialise the WM8750 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8750_init(struct snd_soc_device *socdev)
+{
+ struct snd_soc_codec *codec = socdev->codec;
+ int reg, ret = 0;
+
+ codec->name = "WM8750";
+ codec->owner = THIS_MODULE;
+ codec->read = wm8750_read_reg_cache;
+ codec->write = wm8750_write;
+ codec->dapm_event = wm8750_dapm_event;
+ codec->dai = &wm8750_dai;
+ codec->num_dai = 1;
+ codec->reg_cache_size = sizeof(wm8750_reg);
+ codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KRENEL);
+ if (codec->reg_cache == NULL)
+ return -ENOMEM;
+
+ wm8750_reset(codec);
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "wm8750: failed to create pcms\n");
+ goto pcm_err;
+ }
+
+ /* charge output caps */
+ wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2);
+ codec->dapm_state = SNDRV_CTL_POWER_D3hot;
+ schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));
+
+ /* set the update bits */
+ reg = wm8750_read_reg_cache(codec, WM8750_LDAC);
+ wm8750_write(codec, WM8750_LDAC, reg | 0x0100);
+ reg = wm8750_read_reg_cache(codec, WM8750_RDAC);
+ wm8750_write(codec, WM8750_RDAC, reg | 0x0100);
+ reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V);
+ wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100);
+ reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V);
+ wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100);
+ reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V);
+ wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100);
+ reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V);
+ wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100);
+ reg = wm8750_read_reg_cache(codec, WM8750_LINVOL);
+ wm8750_write(codec, WM8750_LINVOL, reg | 0x0100);
+ reg = wm8750_read_reg_cache(codec, WM8750_RINVOL);
+ wm8750_write(codec, WM8750_RINVOL, reg | 0x0100);
+
+ wm8750_add_controls(codec);
+ wm8750_add_widgets(codec);
+ ret = snd_soc_register_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "wm8750: failed to register card\n");
+ goto card_err;
+ }
+ return ret;
+
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+pcm_err:
+ kfree(codec->reg_cache);
+ return ret;
+}
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+ around */
+static struct snd_soc_device *wm8750_socdev;
+
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+
+/*
+ * WM8731 2 wire address is determined by GPIO5
+ * state during powerup.
+ * low = 0x1a
+ * high = 0x1b
+ */
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver wm8750_i2c_driver;
+static struct i2c_client client_template;
+
+static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+ struct snd_soc_device *socdev = wm8750_socdev;
+ struct wm8750_setup_data *setup = socdev->codec_data;
+ struct snd_soc_codec *codec = socdev->codec;
+ struct i2c_client *i2c;
+ int ret;
+
+ if (addr != setup->i2c_address)
+ return -ENODEV;
+
+ client_template.adapter = adap;
+ client_template.addr = addr;
+
+ i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+ if (i2c == NULL) {
+ kfree(codec);
+ return -ENOMEM;
+ }
+ i2c_set_clientdata(i2c, codec);
+ codec->control_data = i2c;
+
+ ret = i2c_attach_client(i2c);
+ if (ret < 0) {
+ err("failed to attach codec at addr %x\n", addr);
+ goto err;
+ }
+
+ ret = wm8750_init(socdev);
+ if (ret < 0) {
+ err("failed to initialise WM8750\n");
+ goto err;
+ }
+ return ret;
+
+err:
+ kfree(codec);
+ kfree(i2c);
+ return ret;
+}
+
+static int wm8750_i2c_detach(struct i2c_client *client)
+{
+ struct snd_soc_codec *codec = i2c_get_clientdata(client);
+ i2c_detach_client(client);
+ kfree(codec->reg_cache);
+ kfree(client);
+ return 0;
+}
+
+static int wm8750_i2c_attach(struct i2c_adapter *adap)
+{
+ return i2c_probe(adap, &addr_data, wm8750_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver wm8750_i2c_driver = {
+ .driver = {
+ .name = "WM8750 I2C Codec",
+ .owner = THIS_MODULE,
+ },
+ .id = I2C_DRIVERID_WM8750,
+ .attach_adapter = wm8750_i2c_attach,
+ .detach_client = wm8750_i2c_detach,
+ .command = NULL,
+};
+
+static struct i2c_client client_template = {
+ .name = "WM8750",
+ .driver = &wm8750_i2c_driver,
+};
+#endif
+
+static int wm8750_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct wm8750_setup_data *setup = socdev->codec_data;
+ struct snd_soc_codec *codec;
+ struct wm8750_priv *wm8750;
+ int ret = 0;
+
+ info("WM8750 Audio Codec %s", WM8750_VERSION);
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL)
+ return -ENOMEM;
+
+ wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
+ if (wm8750 == NULL) {
+ kfree(codec);
+ return -ENOMEM;
+ }
+
+ codec->private_data = wm8750;
+ socdev->codec = codec;
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+ wm8750_socdev = socdev;
+ INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work);
+
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+ if (setup->i2c_address) {
+ normal_i2c[0] = setup->i2c_address;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+ ret = i2c_add_driver(&wm8750_i2c_driver);
+ if (ret != 0)
+ printk(KERN_ERR "can't add i2c driver");
+ }
+#else
+ /* Add other interfaces here */
+#endif
+
+ return ret;
+}
+
+/*
+ * This function forces any delayed work to be queued and run.
+ */
+static int run_delayed_work(struct delayed_work *dwork)
+{
+ int ret;
+
+ /* cancel any work waiting to be queued. */
+ ret = cancel_delayed_work(dwork);
+
+ /* if there was any work waiting then we run it now and
+ * wait for it's completion */
+ if (ret) {
+ schedule_delayed_work(dwork, 0);
+ flush_scheduled_work();
+ }
+ return ret;
+}
+
+/* power down chip */
+static int wm8750_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+
+ if (codec->control_data)
+ wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+ run_delayed_work(&codec->delayed_work);
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8750_i2c_driver);
+#endif
+ kfree(codec->private_data);
+ kfree(codec);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8750 = {
+ .probe = wm8750_probe,
+ .remove = wm8750_remove,
+ .suspend = wm8750_suspend,
+ .resume = wm8750_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750);
+
+MODULE_DESCRIPTION("ASoC WM8750 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h
new file mode 100644
index 00000000000..a97a54a6348
--- /dev/null
+++ b/sound/soc/codecs/wm8750.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on WM8753.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.
+ *
+ */
+
+#ifndef _WM8750_H
+#define _WM8750_H
+
+/* WM8750 register space */
+
+#define WM8750_LINVOL 0x00
+#define WM8750_RINVOL 0x01
+#define WM8750_LOUT1V 0x02
+#define WM8750_ROUT1V 0x03
+#define WM8750_ADCDAC 0x05
+#define WM8750_IFACE 0x07
+#define WM8750_SRATE 0x08
+#define WM8750_LDAC 0x0a
+#define WM8750_RDAC 0x0b
+#define WM8750_BASS 0x0c
+#define WM8750_TREBLE 0x0d
+#define WM8750_RESET 0x0f
+#define WM8750_3D 0x10
+#define WM8750_ALC1 0x11
+#define WM8750_ALC2 0x12
+#define WM8750_ALC3 0x13
+#define WM8750_NGATE 0x14
+#define WM8750_LADC 0x15
+#define WM8750_RADC 0x16
+#define WM8750_ADCTL1 0x17
+#define WM8750_ADCTL2 0x18
+#define WM8750_PWR1 0x19
+#define WM8750_PWR2 0x1a
+#define WM8750_ADCTL3 0x1b
+#define WM8750_ADCIN 0x1f
+#define WM8750_LADCIN 0x20
+#define WM8750_RADCIN 0x21
+#define WM8750_LOUTM1 0x22
+#define WM8750_LOUTM2 0x23
+#define WM8750_ROUTM1 0x24
+#define WM8750_ROUTM2 0x25
+#define WM8750_MOUTM1 0x26
+#define WM8750_MOUTM2 0x27
+#define WM8750_LOUT2V 0x28
+#define WM8750_ROUT2V 0x29
+#define WM8750_MOUTV 0x2a
+
+#define WM8750_CACHE_REGNUM 0x2a
+
+#define WM8750_SYSCLK 0
+
+struct wm8750_setup_data {
+ unsigned short i2c_address;
+};
+
+extern struct snd_soc_codec_dai wm8750_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8750;
+
+#endif
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
new file mode 100644
index 00000000000..92a64871bcd
--- /dev/null
+++ b/sound/soc/codecs/wm9712.c
@@ -0,0 +1,771 @@
+/*
+ * wm9712.c -- ALSA Soc WM9712 codec support
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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.
+ *
+ * Revision history
+ * 4th Feb 2006 Initial version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#define WM9712_VERSION "0.4"
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+ unsigned int reg);
+static int ac97_write(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int val);
+
+/*
+ * WM9712 register cache
+ */
+static const u16 wm9712_reg[] = {
+ 0x6174, 0x8000, 0x8000, 0x8000, // 6
+ 0xf0f0, 0xaaa0, 0xc008, 0x6808, // e
+ 0xe808, 0xaaa0, 0xad00, 0x8000, // 16
+ 0xe808, 0x3000, 0x8000, 0x0000, // 1e
+ 0x0000, 0x0000, 0x0000, 0x000f, // 26
+ 0x0405, 0x0410, 0xbb80, 0xbb80, // 2e
+ 0x0000, 0xbb80, 0x0000, 0x0000, // 36
+ 0x0000, 0x2000, 0x0000, 0x0000, // 3e
+ 0x0000, 0x0000, 0x0000, 0x0000, // 46
+ 0x0000, 0x0000, 0xf83e, 0xffff, // 4e
+ 0x0000, 0x0000, 0x0000, 0xf83e, // 56
+ 0x0008, 0x0000, 0x0000, 0x0000, // 5e
+ 0xb032, 0x3e00, 0x0000, 0x0000, // 66
+ 0x0000, 0x0000, 0x0000, 0x0000, // 6e
+ 0x0000, 0x0000, 0x0000, 0x0006, // 76
+ 0x0001, 0x0000, 0x574d, 0x4c12, // 7e
+ 0x0000, 0x0000 // virtual hp mixers
+};
+
+/* virtual HP mixers regs */
+#define HPL_MIXER 0x80
+#define HPR_MIXER 0x82
+
+static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"};
+static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"};
+static const char *wm9712_out3_src[] = {"Left", "VREF", "Left + Right",
+ "Mono"};
+static const char *wm9712_spk_src[] = {"Speaker Mix", "Headphone Mix"};
+static const char *wm9712_rec_adc[] = {"Stereo", "Left", "Right", "Mute"};
+static const char *wm9712_base[] = {"Linear Control", "Adaptive Boost"};
+static const char *wm9712_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
+static const char *wm9712_mic[] = {"Mic 1", "Differential", "Mic 2",
+ "Stereo"};
+static const char *wm9712_rec_sel[] = {"Mic", "NC", "NC", "Speaker Mixer",
+ "Line", "Headphone Mixer", "Phone Mixer", "Phone"};
+static const char *wm9712_ng_type[] = {"Constant Gain", "Mute"};
+static const char *wm9712_diff_sel[] = {"Mic", "Line"};
+
+static const struct soc_enum wm9712_enum[] = {
+SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9712_alc_select),
+SOC_ENUM_SINGLE(AC97_VIDEO, 12, 4, wm9712_alc_mux),
+SOC_ENUM_SINGLE(AC97_AUX, 9, 4, wm9712_out3_src),
+SOC_ENUM_SINGLE(AC97_AUX, 8, 2, wm9712_spk_src),
+SOC_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9712_rec_adc),
+SOC_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9712_base),
+SOC_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9712_rec_gain),
+SOC_ENUM_SINGLE(AC97_MIC, 5, 4, wm9712_mic),
+SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9712_rec_sel),
+SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9712_rec_sel),
+SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9712_ng_type),
+SOC_ENUM_SINGLE(0x5c, 8, 2, wm9712_diff_sel),
+};
+
+static const struct snd_kcontrol_new wm9712_snd_ac97_controls[] = {
+SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1),
+SOC_SINGLE("Speaker Playback Switch", AC97_MASTER, 15, 1, 1),
+SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
+SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE,15, 1, 1),
+
+SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0),
+SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0),
+SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0),
+SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
+SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 0),
+
+SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
+SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
+SOC_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0),
+SOC_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
+SOC_ENUM("ALC Function", wm9712_enum[0]),
+SOC_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
+SOC_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1),
+SOC_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
+SOC_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
+SOC_ENUM("ALC NG Type", wm9712_enum[10]),
+SOC_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1),
+
+SOC_SINGLE("Mic Headphone Volume", AC97_VIDEO, 12, 7, 1),
+SOC_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
+
+SOC_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
+SOC_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
+SOC_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
+
+SOC_SINGLE("PCBeep Bypass Headphone Volume", AC97_PC_BEEP, 12, 7, 1),
+SOC_SINGLE("PCBeep Bypass Speaker Volume", AC97_PC_BEEP, 8, 7, 1),
+SOC_SINGLE("PCBeep Bypass Phone Volume", AC97_PC_BEEP, 4, 7, 1),
+
+SOC_SINGLE("Aux Playback Headphone Volume", AC97_CD, 12, 7, 1),
+SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1),
+SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1),
+
+SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 0),
+SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1),
+
+SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0),
+SOC_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1),
+
+SOC_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
+SOC_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
+SOC_SINGLE("3D Playback Volume", AC97_3D_CONTROL, 0, 15, 0),
+
+SOC_ENUM("Bass Control", wm9712_enum[5]),
+SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
+SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
+SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
+SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 0),
+SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 0),
+
+SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1),
+SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
+SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1),
+SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
+
+SOC_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
+SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
+SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
+};
+
+/* add non dapm controls */
+static int wm9712_add_controls(struct snd_soc_codec *codec)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(wm9712_snd_ac97_controls); i++) {
+ err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&wm9712_snd_ac97_controls[i],codec, NULL));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+/* We have to create a fake left and right HP mixers because
+ * the codec only has a single control that is shared by both channels.
+ * This makes it impossible to determine the audio path.
+ */
+static int mixer_event (struct snd_soc_dapm_widget *w, int event)
+{
+ u16 l, r, beep, line, phone, mic, pcm, aux;
+
+ l = ac97_read(w->codec, HPL_MIXER);
+ r = ac97_read(w->codec, HPR_MIXER);
+ beep = ac97_read(w->codec, AC97_PC_BEEP);
+ mic = ac97_read(w->codec, AC97_VIDEO);
+ phone = ac97_read(w->codec, AC97_PHONE);
+ line = ac97_read(w->codec, AC97_LINE);
+ pcm = ac97_read(w->codec, AC97_PCM);
+ aux = ac97_read(w->codec, AC97_CD);
+
+ if (l & 0x1 || r & 0x1)
+ ac97_write(w->codec, AC97_VIDEO, mic & 0x7fff);
+ else
+ ac97_write(w->codec, AC97_VIDEO, mic | 0x8000);
+
+ if (l & 0x2 || r & 0x2)
+ ac97_write(w->codec, AC97_PCM, pcm & 0x7fff);
+ else
+ ac97_write(w->codec, AC97_PCM, pcm | 0x8000);
+
+ if (l & 0x4 || r & 0x4)
+ ac97_write(w->codec, AC97_LINE, line & 0x7fff);
+ else
+ ac97_write(w->codec, AC97_LINE, line | 0x8000);
+
+ if (l & 0x8 || r & 0x8)
+ ac97_write(w->codec, AC97_PHONE, phone & 0x7fff);
+ else
+ ac97_write(w->codec, AC97_PHONE, phone | 0x8000);
+
+ if (l & 0x10 || r & 0x10)
+ ac97_write(w->codec, AC97_CD, aux & 0x7fff);
+ else
+ ac97_write(w->codec, AC97_CD, aux | 0x8000);
+
+ if (l & 0x20 || r & 0x20)
+ ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff);
+ else
+ ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000);
+
+ return 0;
+}
+
+/* Left Headphone Mixers */
+static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = {
+ SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPL_MIXER, 5, 1, 0),
+ SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 4, 1, 0),
+ SOC_DAPM_SINGLE("Phone Bypass Switch", HPL_MIXER, 3, 1, 0),
+ SOC_DAPM_SINGLE("Line Bypass Switch", HPL_MIXER, 2, 1, 0),
+ SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0),
+ SOC_DAPM_SINGLE("Mic Sidetone Switch", HPL_MIXER, 0, 1, 0),
+};
+
+/* Right Headphone Mixers */
+static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = {
+ SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPR_MIXER, 5, 1, 0),
+ SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 4, 1, 0),
+ SOC_DAPM_SINGLE("Phone Bypass Switch", HPR_MIXER, 3, 1, 0),
+ SOC_DAPM_SINGLE("Line Bypass Switch", HPR_MIXER, 2, 1, 0),
+ SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0),
+ SOC_DAPM_SINGLE("Mic Sidetone Switch", HPR_MIXER, 0, 1, 0),
+};
+
+/* Speaker Mixer */
+static const struct snd_kcontrol_new wm9712_speaker_mixer_controls[] = {
+ SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 11, 1, 1),
+ SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 11, 1, 1),
+ SOC_DAPM_SINGLE("Phone Bypass Switch", AC97_PHONE, 14, 1, 1),
+ SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 14, 1, 1),
+ SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 14, 1, 1),
+};
+
+/* Phone Mixer */
+static const struct snd_kcontrol_new wm9712_phone_mixer_controls[] = {
+ SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 7, 1, 1),
+ SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 7, 1, 1),
+ SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 13, 1, 1),
+ SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 13, 1, 1),
+ SOC_DAPM_SINGLE("Mic 1 Sidetone Switch", AC97_MIC, 14, 1, 1),
+ SOC_DAPM_SINGLE("Mic 2 Sidetone Switch", AC97_MIC, 13, 1, 1),
+};
+
+/* ALC headphone mux */
+static const struct snd_kcontrol_new wm9712_alc_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[1]);
+
+/* out 3 mux */
+static const struct snd_kcontrol_new wm9712_out3_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[2]);
+
+/* spk mux */
+static const struct snd_kcontrol_new wm9712_spk_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[3]);
+
+/* Capture to Phone mux */
+static const struct snd_kcontrol_new wm9712_capture_phone_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[4]);
+
+/* Capture left select */
+static const struct snd_kcontrol_new wm9712_capture_selectl_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[8]);
+
+/* Capture right select */
+static const struct snd_kcontrol_new wm9712_capture_selectr_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[9]);
+
+/* Mic select */
+static const struct snd_kcontrol_new wm9712_mic_src_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[7]);
+
+/* diff select */
+static const struct snd_kcontrol_new wm9712_diff_sel_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[11]);
+
+static const struct snd_soc_dapm_widget wm9712_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("ALC Sidetone Mux", SND_SOC_NOPM, 0, 0,
+ &wm9712_alc_mux_controls),
+SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0,
+ &wm9712_out3_mux_controls),
+SND_SOC_DAPM_MUX("Speaker Mux", SND_SOC_NOPM, 0, 0,
+ &wm9712_spk_mux_controls),
+SND_SOC_DAPM_MUX("Capture Phone Mux", SND_SOC_NOPM, 0, 0,
+ &wm9712_capture_phone_mux_controls),
+SND_SOC_DAPM_MUX("Left Capture Select", SND_SOC_NOPM, 0, 0,
+ &wm9712_capture_selectl_controls),
+SND_SOC_DAPM_MUX("Right Capture Select", SND_SOC_NOPM, 0, 0,
+ &wm9712_capture_selectr_controls),
+SND_SOC_DAPM_MUX("Mic Select Source", SND_SOC_NOPM, 0, 0,
+ &wm9712_mic_src_controls),
+SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0,
+ &wm9712_diff_sel_controls),
+SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_INT_PAGING, 9, 1,
+ &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls),
+ mixer_event, SND_SOC_DAPM_POST_REG),
+SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_INT_PAGING, 8, 1,
+ &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls),
+ mixer_event, SND_SOC_DAPM_POST_REG),
+SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1,
+ &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)),
+SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1,
+ &wm9712_speaker_mixer_controls[0],
+ ARRAY_SIZE(wm9712_speaker_mixer_controls)),
+SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", AC97_INT_PAGING, 14, 1),
+SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", AC97_INT_PAGING, 13, 1),
+SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_INT_PAGING, 12, 1),
+SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_INT_PAGING, 11, 1),
+SND_SOC_DAPM_PGA("Headphone PGA", AC97_INT_PAGING, 4, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Speaker PGA", AC97_INT_PAGING, 3, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Out 3 PGA", AC97_INT_PAGING, 5, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Line PGA", AC97_INT_PAGING, 2, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Phone PGA", AC97_INT_PAGING, 1, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mic PGA", AC97_INT_PAGING, 0, 1, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_INT_PAGING, 10, 1),
+SND_SOC_DAPM_OUTPUT("MONOOUT"),
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+SND_SOC_DAPM_OUTPUT("LOUT2"),
+SND_SOC_DAPM_OUTPUT("ROUT2"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_INPUT("LINEINL"),
+SND_SOC_DAPM_INPUT("LINEINR"),
+SND_SOC_DAPM_INPUT("PHONE"),
+SND_SOC_DAPM_INPUT("PCBEEP"),
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+};
+
+static const char *audio_map[][3] = {
+ /* virtual mixer - mixes left & right channels for spk and mono */
+ {"AC97 Mixer", NULL, "Left DAC"},
+ {"AC97 Mixer", NULL, "Right DAC"},
+
+ /* Left HP mixer */
+ {"Left HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
+ {"Left HP Mixer", "Aux Playback Switch", "Aux DAC"},
+ {"Left HP Mixer", "Phone Bypass Switch", "Phone PGA"},
+ {"Left HP Mixer", "Line Bypass Switch", "Line PGA"},
+ {"Left HP Mixer", "PCM Playback Switch", "Left DAC"},
+ {"Left HP Mixer", "Mic Sidetone Switch", "Mic PGA"},
+ {"Left HP Mixer", NULL, "ALC Sidetone Mux"},
+ //{"Right HP Mixer", NULL, "HP Mixer"},
+
+ /* Right HP mixer */
+ {"Right HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
+ {"Right HP Mixer", "Aux Playback Switch", "Aux DAC"},
+ {"Right HP Mixer", "Phone Bypass Switch", "Phone PGA"},
+ {"Right HP Mixer", "Line Bypass Switch", "Line PGA"},
+ {"Right HP Mixer", "PCM Playback Switch", "Right DAC"},
+ {"Right HP Mixer", "Mic Sidetone Switch", "Mic PGA"},
+ {"Right HP Mixer", NULL, "ALC Sidetone Mux"},
+
+ /* speaker mixer */
+ {"Speaker Mixer", "PCBeep Bypass Switch", "PCBEEP"},
+ {"Speaker Mixer", "Line Bypass Switch", "Line PGA"},
+ {"Speaker Mixer", "PCM Playback Switch", "AC97 Mixer"},
+ {"Speaker Mixer", "Phone Bypass Switch", "Phone PGA"},
+ {"Speaker Mixer", "Aux Playback Switch", "Aux DAC"},
+
+ /* Phone mixer */
+ {"Phone Mixer", "PCBeep Bypass Switch", "PCBEEP"},
+ {"Phone Mixer", "Line Bypass Switch", "Line PGA"},
+ {"Phone Mixer", "Aux Playback Switch", "Aux DAC"},
+ {"Phone Mixer", "PCM Playback Switch", "AC97 Mixer"},
+ {"Phone Mixer", "Mic 1 Sidetone Switch", "Mic PGA"},
+ {"Phone Mixer", "Mic 2 Sidetone Switch", "Mic PGA"},
+
+ /* inputs */
+ {"Line PGA", NULL, "LINEINL"},
+ {"Line PGA", NULL, "LINEINR"},
+ {"Phone PGA", NULL, "PHONE"},
+ {"Mic PGA", NULL, "MIC1"},
+ {"Mic PGA", NULL, "MIC2"},
+
+ /* left capture selector */
+ {"Left Capture Select", "Mic", "MIC1"},
+ {"Left Capture Select", "Speaker Mixer", "Speaker Mixer"},
+ {"Left Capture Select", "Line", "LINEINL"},
+ {"Left Capture Select", "Headphone Mixer", "Left HP Mixer"},
+ {"Left Capture Select", "Phone Mixer", "Phone Mixer"},
+ {"Left Capture Select", "Phone", "PHONE"},
+
+ /* right capture selector */
+ {"Right Capture Select", "Mic", "MIC2"},
+ {"Right Capture Select", "Speaker Mixer", "Speaker Mixer"},
+ {"Right Capture Select", "Line", "LINEINR"},
+ {"Right Capture Select", "Headphone Mixer", "Right HP Mixer"},
+ {"Right Capture Select", "Phone Mixer", "Phone Mixer"},
+ {"Right Capture Select", "Phone", "PHONE"},
+
+ /* ALC Sidetone */
+ {"ALC Sidetone Mux", "Stereo", "Left Capture Select"},
+ {"ALC Sidetone Mux", "Stereo", "Right Capture Select"},
+ {"ALC Sidetone Mux", "Left", "Left Capture Select"},
+ {"ALC Sidetone Mux", "Right", "Right Capture Select"},
+
+ /* ADC's */
+ {"Left ADC", NULL, "Left Capture Select"},
+ {"Right ADC", NULL, "Right Capture Select"},
+
+ /* outputs */
+ {"MONOOUT", NULL, "Phone Mixer"},
+ {"HPOUTL", NULL, "Headphone PGA"},
+ {"Headphone PGA", NULL, "Left HP Mixer"},
+ {"HPOUTR", NULL, "Headphone PGA"},
+ {"Headphone PGA", NULL, "Right HP Mixer"},
+
+ /* mono hp mixer */
+ {"Mono HP Mixer", NULL, "Left HP Mixer"},
+ {"Mono HP Mixer", NULL, "Right HP Mixer"},
+
+ /* Out3 Mux */
+ {"Out3 Mux", "Left", "Left HP Mixer"},
+ {"Out3 Mux", "Mono", "Phone Mixer"},
+ {"Out3 Mux", "Left + Right", "Mono HP Mixer"},
+ {"Out 3 PGA", NULL, "Out3 Mux"},
+ {"OUT3", NULL, "Out 3 PGA"},
+
+ /* speaker Mux */
+ {"Speaker Mux", "Speaker Mix", "Speaker Mixer"},
+ {"Speaker Mux", "Headphone Mix", "Mono HP Mixer"},
+ {"Speaker PGA", NULL, "Speaker Mux"},
+ {"LOUT2", NULL, "Speaker PGA"},
+ {"ROUT2", NULL, "Speaker PGA"},
+
+ {NULL, NULL, NULL},
+};
+
+static int wm9712_add_widgets(struct snd_soc_codec *codec)
+{
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) {
+ snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]);
+ }
+
+ /* set up audio path audio_mapnects */
+ for(i = 0; audio_map[i][0] != NULL; i++) {
+ snd_soc_dapm_connect_input(codec, audio_map[i][0],
+ audio_map[i][1], audio_map[i][2]);
+ }
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+static unsigned int ac97_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+
+ if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
+ reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
+ reg == AC97_REC_GAIN)
+ return soc_ac97_ops.read(codec->ac97, reg);
+ else {
+ reg = reg >> 1;
+
+ if (reg > (ARRAY_SIZE(wm9712_reg)))
+ return -EIO;
+
+ return cache[reg];
+ }
+}
+
+static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int val)
+{
+ u16 *cache = codec->reg_cache;
+
+ soc_ac97_ops.write(codec->ac97, reg, val);
+ reg = reg >> 1;
+ if (reg <= (ARRAY_SIZE(wm9712_reg)))
+ cache[reg] = val;
+
+ return 0;
+}
+
+static int ac97_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+ int reg;
+ u16 vra;
+
+ vra = ac97_read(codec, AC97_EXTENDED_STATUS);
+ ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ reg = AC97_PCM_FRONT_DAC_RATE;
+ else
+ reg = AC97_PCM_LR_ADC_RATE;
+
+ return ac97_write(codec, reg, runtime->rate);
+}
+
+static int ac97_aux_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+ u16 vra, xsle;
+
+ vra = ac97_read(codec, AC97_EXTENDED_STATUS);
+ ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
+ xsle = ac97_read(codec, AC97_PCI_SID);
+ ac97_write(codec, AC97_PCI_SID, xsle | 0x8000);
+
+ if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return -ENODEV;
+
+ return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
+}
+
+#define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+struct snd_soc_codec_dai wm9712_dai[] = {
+{
+ .name = "AC97 HiFi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM9712_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM9712_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .prepare = ac97_prepare,},
+},
+{
+ .name = "AC97 Aux",
+ .playback = {
+ .stream_name = "Aux Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = WM9712_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .prepare = ac97_aux_prepare,},
+}
+};
+EXPORT_SYMBOL_GPL(wm9712_dai);
+
+static int wm9712_dapm_event(struct snd_soc_codec *codec, int event)
+{
+ u16 reg;
+
+ switch (event) {
+ case SNDRV_CTL_POWER_D0: /* full On */
+ /* liam - maybe enable thermal shutdown */
+ reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xdfff;
+ ac97_write(codec, AC97_EXTENDED_MID, reg);
+ break;
+ case SNDRV_CTL_POWER_D1: /* partial On */
+ case SNDRV_CTL_POWER_D2: /* partial On */
+ break;
+ case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+ /* enable master bias and vmid */
+ reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xbbff;
+ ac97_write(codec, AC97_EXTENDED_MID, reg);
+ ac97_write(codec, AC97_POWERDOWN, 0x0000);
+ break;
+ case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+ /* disable everything including AC link */
+ ac97_write(codec, AC97_EXTENDED_MID, 0xffff);
+ ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
+ ac97_write(codec, AC97_POWERDOWN, 0xffff);
+ break;
+ }
+ codec->dapm_state = event;
+ return 0;
+}
+
+static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
+{
+ if (try_warm && soc_ac97_ops.warm_reset) {
+ soc_ac97_ops.warm_reset(codec->ac97);
+ if (!(ac97_read(codec, 0) & 0x8000))
+ return 1;
+ }
+
+ soc_ac97_ops.reset(codec->ac97);
+ if (ac97_read(codec, 0) & 0x8000)
+ goto err;
+ return 0;
+
+err:
+ printk(KERN_ERR "WM9712 AC97 reset failed\n");
+ return -EIO;
+}
+
+static int wm9712_soc_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+
+ wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+ return 0;
+}
+
+static int wm9712_soc_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+ int i, ret;
+ u16 *cache = codec->reg_cache;
+
+ ret = wm9712_reset(codec, 1);
+ if (ret < 0){
+ printk(KERN_ERR "could not reset AC97 codec\n");
+ return ret;
+ }
+
+ wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+ if (ret == 0) {
+ /* Sync reg_cache with the hardware after cold reset */
+ for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i+=2) {
+ if (i == AC97_INT_PAGING || i == AC97_POWERDOWN ||
+ (i > 0x58 && i != 0x5c))
+ continue;
+ soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
+ }
+ }
+
+ if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0)
+ wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0);
+
+ return ret;
+}
+
+static int wm9712_soc_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION);
+
+ socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (socdev->codec == NULL)
+ return -ENOMEM;
+ codec = socdev->codec;
+ mutex_init(&codec->mutex);
+
+ codec->reg_cache =
+ kzalloc(sizeof(u16) * ARRAY_SIZE(wm9712_reg), GFP_KERNEL);
+ if (codec->reg_cache == NULL) {
+ ret = -ENOMEM;
+ goto cache_err;
+ }
+ memcpy(codec->reg_cache, wm9712_reg, sizeof(u16) * ARRAY_SIZE(wm9712_reg));
+ codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm9712_reg);
+ codec->reg_cache_step = 2;
+
+ codec->name = "WM9712";
+ codec->owner = THIS_MODULE;
+ codec->dai = wm9712_dai;
+ codec->num_dai = ARRAY_SIZE(wm9712_dai);
+ codec->write = ac97_write;
+ codec->read = ac97_read;
+ codec->dapm_event = wm9712_dapm_event;
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+ if (ret < 0) {
+ printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
+ goto codec_err;
+ }
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0)
+ goto pcm_err;
+
+ ret = wm9712_reset(codec, 0);
+ if (ret < 0) {
+ printk(KERN_ERR "AC97 link error\n");
+ goto reset_err;
+ }
+
+ /* set alc mux to none */
+ ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
+
+ wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+ wm9712_add_controls(codec);
+ wm9712_add_widgets(codec);
+ ret = snd_soc_register_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "wm9712: failed to register card\n");
+ goto reset_err;
+ }
+
+ return 0;
+
+reset_err:
+ snd_soc_free_pcms(socdev);
+
+pcm_err:
+ snd_soc_free_ac97_codec(codec);
+
+codec_err:
+ kfree(codec->reg_cache);
+
+cache_err:
+ kfree(socdev->codec);
+ socdev->codec = NULL;
+ return ret;
+}
+
+static int wm9712_soc_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+
+ if (codec == NULL)
+ return 0;
+
+ snd_soc_dapm_free(socdev);
+ snd_soc_free_pcms(socdev);
+ snd_soc_free_ac97_codec(codec);
+ kfree(codec->reg_cache);
+ kfree(codec);
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm9712 = {
+ .probe = wm9712_soc_probe,
+ .remove = wm9712_soc_remove,
+ .suspend = wm9712_soc_suspend,
+ .resume = wm9712_soc_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712);
+
+MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm9712.h b/sound/soc/codecs/wm9712.h
new file mode 100644
index 00000000000..719105d61e6
--- /dev/null
+++ b/sound/soc/codecs/wm9712.h
@@ -0,0 +1,14 @@
+/*
+ * wm9712.h -- WM9712 Soc Audio driver
+ */
+
+#ifndef _WM9712_H
+#define _WM9712_H
+
+#define WM9712_DAI_AC97_HIFI 0
+#define WM9712_DAI_AC97_AUX 1
+
+extern struct snd_soc_codec_dai wm9712_dai[2];
+extern struct snd_soc_codec_device soc_codec_dev_wm9712;
+
+#endif
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
new file mode 100644
index 00000000000..579e1c8d2b2
--- /dev/null
+++ b/sound/soc/pxa/Kconfig
@@ -0,0 +1,60 @@
+menu "SoC Audio for the Intel PXA2xx"
+
+config SND_PXA2XX_SOC
+ tristate "SoC Audio for the Intel PXA2xx chip"
+ depends on ARCH_PXA && SND
+ select SND_PCM
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the PXA2xx AC97, I2S or SSP interface. You will also need
+ to select the audio interfaces to support below.
+
+config SND_PXA2XX_AC97
+ tristate
+ select SND_AC97_CODEC
+
+config SND_PXA2XX_SOC_AC97
+ tristate
+ select AC97_BUS
+ select SND_SOC_AC97_BUS
+
+config SND_PXA2XX_SOC_I2S
+ tristate
+
+config SND_PXA2XX_SOC_CORGI
+ tristate "SoC Audio support for Sharp Zaurus SL-C7x0"
+ depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx
+ select SND_PXA2XX_SOC_I2S
+ select SND_SOC_WM8731
+ help
+ Say Y if you want to add support for SoC audio on Sharp
+ Zaurus SL-C7x0 models (Corgi, Shepherd, Husky).
+
+config SND_PXA2XX_SOC_SPITZ
+ tristate "SoC Audio support for Sharp Zaurus SL-Cxx00"
+ depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00
+ select SND_PXA2XX_SOC_I2S
+ select SND_SOC_WM8750
+ help
+ Say Y if you want to add support for SoC audio on Sharp
+ Zaurus SL-Cxx00 models (Spitz, Borzoi and Akita).
+
+config SND_PXA2XX_SOC_POODLE
+ tristate "SoC Audio support for Poodle"
+ depends on SND_PXA2XX_SOC && MACH_POODLE
+ select SND_PXA2XX_SOC_I2S
+ select SND_SOC_WM8731
+ help
+ Say Y if you want to add support for SoC audio on Sharp
+ Zaurus SL-5600 model (Poodle).
+
+config SND_PXA2XX_SOC_TOSA
+ tristate "SoC AC97 Audio support for Tosa"
+ depends on SND_PXA2XX_SOC && MACH_TOSA
+ select SND_PXA2XX_SOC_AC97
+ select SND_SOC_WM9712
+ help
+ Say Y if you want to add support for SoC audio on Sharp
+ Zaurus SL-C6000x models (Tosa).
+
+endmenu
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
new file mode 100644
index 00000000000..78e0d6b07d1
--- /dev/null
+++ b/sound/soc/pxa/Makefile
@@ -0,0 +1,20 @@
+# PXA Platform Support
+snd-soc-pxa2xx-objs := pxa2xx-pcm.o
+snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
+snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
+
+obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
+obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
+obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
+
+# PXA Machine Support
+snd-soc-corgi-objs := corgi.o
+snd-soc-poodle-objs := poodle.o
+snd-soc-tosa-objs := tosa.o
+snd-soc-spitz-objs := spitz.o
+
+obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
+obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
+obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o
+obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
+
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
new file mode 100644
index 00000000000..5ee51a994ac
--- /dev/null
+++ b/sound/soc/pxa/corgi.c
@@ -0,0 +1,383 @@
+/*
+ * corgi.c -- SoC audio for Corgi
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Richard Purdie <richard@openedhand.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.
+ *
+ * Revision history
+ * 30th Nov 2005 Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/corgi.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/wm8731.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+
+#define CORGI_HP 0
+#define CORGI_MIC 1
+#define CORGI_LINE 2
+#define CORGI_HEADSET 3
+#define CORGI_HP_OFF 4
+#define CORGI_SPK_ON 0
+#define CORGI_SPK_OFF 1
+
+ /* audio clock in Hz - rounded from 12.235MHz */
+#define CORGI_AUDIO_CLOCK 12288000
+
+static int corgi_jack_func;
+static int corgi_spk_func;
+
+static void corgi_ext_control(struct snd_soc_codec *codec)
+{
+ int spk = 0, mic = 0, line = 0, hp = 0, hs = 0;
+
+ /* set up jack connection */
+ switch (corgi_jack_func) {
+ case CORGI_HP:
+ hp = 1;
+ /* set = unmute headphone */
+ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ case CORGI_MIC:
+ mic = 1;
+ /* reset = mute headphone */
+ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ case CORGI_LINE:
+ line = 1;
+ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ case CORGI_HEADSET:
+ hs = 1;
+ mic = 1;
+ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ }
+
+ if (corgi_spk_func == CORGI_SPK_ON)
+ spk = 1;
+
+ /* set the enpoints to their new connetion states */
+ snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk);
+ snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic);
+ snd_soc_dapm_set_endpoint(codec, "Line Jack", line);
+ snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp);
+ snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs);
+
+ /* signal a DAPM event */
+ snd_soc_dapm_sync_endpoints(codec);
+}
+
+static int corgi_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->codec;
+
+ /* check the jack status at stream startup */
+ corgi_ext_control(codec);
+ return 0;
+}
+
+/* we need to unmute the HP at shutdown as the mute burns power on corgi */
+static int corgi_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->codec;
+
+ /* set = unmute headphone */
+ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ return 0;
+}
+
+static int corgi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+ unsigned int clk = 0;
+ int ret = 0;
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 48000:
+ case 96000:
+ clk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ clk = 11289600;
+ break;
+ }
+
+ /* set codec DAI configuration */
+ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set the I2S system clock as input (unused) */
+ ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops corgi_ops = {
+ .startup = corgi_startup,
+ .hw_params = corgi_hw_params,
+ .shutdown = corgi_shutdown,
+};
+
+static int corgi_get_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = corgi_jack_func;
+ return 0;
+}
+
+static int corgi_set_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (corgi_jack_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ corgi_jack_func = ucontrol->value.integer.value[0];
+ corgi_ext_control(codec);
+ return 1;
+}
+
+static int corgi_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = corgi_spk_func;
+ return 0;
+}
+
+static int corgi_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (corgi_spk_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ corgi_spk_func = ucontrol->value.integer.value[0];
+ corgi_ext_control(codec);
+ return 1;
+}
+
+static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+ else
+ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
+
+ return 0;
+}
+
+static int corgi_mic_event(struct snd_soc_dapm_widget *w, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
+ else
+ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
+
+ return 0;
+}
+
+/* corgi machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", NULL),
+SND_SOC_DAPM_MIC("Mic Jack", corgi_mic_event),
+SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event),
+SND_SOC_DAPM_LINE("Line Jack", NULL),
+SND_SOC_DAPM_HP("Headset Jack", NULL),
+};
+
+/* Corgi machine audio map (connections to the codec pins) */
+static const char *audio_map[][3] = {
+
+ /* headset Jack - in = micin, out = LHPOUT*/
+ {"Headset Jack", NULL, "LHPOUT"},
+
+ /* headphone connected to LHPOUT1, RHPOUT1 */
+ {"Headphone Jack", NULL, "LHPOUT"},
+ {"Headphone Jack", NULL, "RHPOUT"},
+
+ /* speaker connected to LOUT, ROUT */
+ {"Ext Spk", NULL, "ROUT"},
+ {"Ext Spk", NULL, "LOUT"},
+
+ /* mic is connected to MICIN (via right channel of headphone jack) */
+ {"MICIN", NULL, "Mic Jack"},
+
+ /* Same as the above but no mic bias for line signals */
+ {"MICIN", NULL, "Line Jack"},
+
+ {NULL, NULL, NULL},
+};
+
+static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
+ "Off"};
+static const char *spk_function[] = {"On", "Off"};
+static const struct soc_enum corgi_enum[] = {
+ SOC_ENUM_SINGLE_EXT(5, jack_function),
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
+ SOC_ENUM_EXT("Jack Function", corgi_enum[0], corgi_get_jack,
+ corgi_set_jack),
+ SOC_ENUM_EXT("Speaker Function", corgi_enum[1], corgi_get_spk,
+ corgi_set_spk),
+};
+
+/*
+ * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
+ */
+static int corgi_wm8731_init(struct snd_soc_codec *codec)
+{
+ int i, err;
+
+ snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
+ snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
+
+ /* Add corgi specific controls */
+ for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
+ err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&wm8731_corgi_controls[i],codec, NULL));
+ if (err < 0)
+ return err;
+ }
+
+ /* Add corgi specific widgets */
+ for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) {
+ snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
+ }
+
+ /* Set up corgi specific audio path audio_map */
+ for(i = 0; audio_map[i][0] != NULL; i++) {
+ snd_soc_dapm_connect_input(codec, audio_map[i][0],
+ audio_map[i][1], audio_map[i][2]);
+ }
+
+ snd_soc_dapm_sync_endpoints(codec);
+ return 0;
+}
+
+/* corgi digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link corgi_dai = {
+ .name = "WM8731",
+ .stream_name = "WM8731",
+ .cpu_dai = &pxa_i2s_dai,
+ .codec_dai = &wm8731_dai,
+ .init = corgi_wm8731_init,
+ .ops = &corgi_ops,
+};
+
+/* corgi audio machine driver */
+static struct snd_soc_machine snd_soc_machine_corgi = {
+ .name = "Corgi",
+ .dai_link = &corgi_dai,
+ .num_links = 1,
+};
+
+/* corgi audio private data */
+static struct wm8731_setup_data corgi_wm8731_setup = {
+ .i2c_address = 0x1b,
+};
+
+/* corgi audio subsystem */
+static struct snd_soc_device corgi_snd_devdata = {
+ .machine = &snd_soc_machine_corgi,
+ .platform = &pxa2xx_soc_platform,
+ .codec_dev = &soc_codec_dev_wm8731,
+ .codec_data = &corgi_wm8731_setup,
+};
+
+static struct platform_device *corgi_snd_device;
+
+static int __init corgi_init(void)
+{
+ int ret;
+
+ if (!(machine_is_corgi() || machine_is_shepherd() || machine_is_husky()))
+ return -ENODEV;
+
+ corgi_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!corgi_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(corgi_snd_device, &corgi_snd_devdata);
+ corgi_snd_devdata.dev = &corgi_snd_device->dev;
+ ret = platform_device_add(corgi_snd_device);
+
+ if (ret)
+ platform_device_put(corgi_snd_device);
+
+ return ret;
+}
+
+static void __exit corgi_exit(void)
+{
+ platform_device_unregister(corgi_snd_device);
+}
+
+module_init(corgi_init);
+module_exit(corgi_exit);
+
+/* Module information */
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Corgi");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
new file mode 100644
index 00000000000..0915cf74042
--- /dev/null
+++ b/sound/soc/pxa/poodle.c
@@ -0,0 +1,352 @@
+/*
+ * poodle.c -- SoC audio for Poodle
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Richard Purdie <richard@openedhand.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 <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/locomo.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/poodle.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/wm8731.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+
+#define POODLE_HP 1
+#define POODLE_HP_OFF 0
+#define POODLE_SPK_ON 1
+#define POODLE_SPK_OFF 0
+
+ /* audio clock in Hz - rounded from 12.235MHz */
+#define POODLE_AUDIO_CLOCK 12288000
+
+static int poodle_jack_func;
+static int poodle_spk_func;
+
+static void poodle_ext_control(struct snd_soc_codec *codec)
+{
+ int spk = 0;
+
+ /* set up jack connection */
+ if (poodle_jack_func == POODLE_HP) {
+ /* set = unmute headphone */
+ locomo_gpio_write(&poodle_locomo_device.dev,
+ POODLE_LOCOMO_GPIO_MUTE_L, 1);
+ locomo_gpio_write(&poodle_locomo_device.dev,
+ POODLE_LOCOMO_GPIO_MUTE_R, 1);
+ snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1);
+ } else {
+ locomo_gpio_write(&poodle_locomo_device.dev,
+ POODLE_LOCOMO_GPIO_MUTE_L, 0);
+ locomo_gpio_write(&poodle_locomo_device.dev,
+ POODLE_LOCOMO_GPIO_MUTE_R, 0);
+ snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+ }
+
+ if (poodle_spk_func == POODLE_SPK_ON)
+ spk = 1;
+
+ /* set the enpoints to their new connetion states */
+ snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk);
+
+ /* signal a DAPM event */
+ snd_soc_dapm_sync_endpoints(codec);
+}
+
+static int poodle_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->codec;
+
+ /* check the jack status at stream startup */
+ poodle_ext_control(codec);
+ return 0;
+}
+
+/* we need to unmute the HP at shutdown as the mute burns power on poodle */
+static int poodle_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->codec;
+
+ /* set = unmute headphone */
+ locomo_gpio_write(&poodle_locomo_device.dev,
+ POODLE_LOCOMO_GPIO_MUTE_L, 1);
+ locomo_gpio_write(&poodle_locomo_device.dev,
+ POODLE_LOCOMO_GPIO_MUTE_R, 1);
+ return 0;
+}
+
+static int poodle_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+ unsigned int clk = 0;
+ int ret = 0;
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 48000:
+ case 96000:
+ clk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ clk = 11289600;
+ break;
+ }
+
+ /* set codec DAI configuration */
+ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set the I2S system clock as input (unused) */
+ ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops poodle_ops = {
+ .startup = poodle_startup,
+ .hw_params = poodle_hw_params,
+ .shutdown = poodle_shutdown,
+};
+
+static int poodle_get_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = poodle_jack_func;
+ return 0;
+}
+
+static int poodle_set_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (poodle_jack_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ poodle_jack_func = ucontrol->value.integer.value[0];
+ poodle_ext_control(codec);
+ return 1;
+}
+
+static int poodle_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = poodle_spk_func;
+ return 0;
+}
+
+static int poodle_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (poodle_spk_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ poodle_spk_func = ucontrol->value.integer.value[0];
+ poodle_ext_control(codec);
+ return 1;
+}
+
+static int poodle_amp_event(struct snd_soc_dapm_widget *w, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ locomo_gpio_write(&poodle_locomo_device.dev,
+ POODLE_LOCOMO_GPIO_AMP_ON, 0);
+ else
+ locomo_gpio_write(&poodle_locomo_device.dev,
+ POODLE_LOCOMO_GPIO_AMP_ON, 1);
+
+ return 0;
+}
+
+/* poodle machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", NULL),
+SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event),
+};
+
+/* Corgi machine audio_mapnections to the codec pins */
+static const char *audio_map[][3] = {
+
+ /* headphone connected to LHPOUT1, RHPOUT1 */
+ {"Headphone Jack", NULL, "LHPOUT"},
+ {"Headphone Jack", NULL, "RHPOUT"},
+
+ /* speaker connected to LOUT, ROUT */
+ {"Ext Spk", NULL, "ROUT"},
+ {"Ext Spk", NULL, "LOUT"},
+
+ {NULL, NULL, NULL},
+};
+
+static const char *jack_function[] = {"Off", "Headphone"};
+static const char *spk_function[] = {"Off", "On"};
+static const struct soc_enum poodle_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, jack_function),
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const snd_kcontrol_new_t wm8731_poodle_controls[] = {
+ SOC_ENUM_EXT("Jack Function", poodle_enum[0], poodle_get_jack,
+ poodle_set_jack),
+ SOC_ENUM_EXT("Speaker Function", poodle_enum[1], poodle_get_spk,
+ poodle_set_spk),
+};
+
+/*
+ * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
+ */
+static int poodle_wm8731_init(struct snd_soc_codec *codec)
+{
+ int i, err;
+
+ snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
+ snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
+ snd_soc_dapm_set_endpoint(codec, "MICIN", 1);
+
+ /* Add poodle specific controls */
+ for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) {
+ err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&wm8731_poodle_controls[i],codec, NULL));
+ if (err < 0)
+ return err;
+ }
+
+ /* Add poodle specific widgets */
+ for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) {
+ snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
+ }
+
+ /* Set up poodle specific audio path audio_map */
+ for (i = 0; audio_map[i][0] != NULL; i++) {
+ snd_soc_dapm_connect_input(codec, audio_map[i][0],
+ audio_map[i][1], audio_map[i][2]);
+ }
+
+ snd_soc_dapm_sync_endpoints(codec);
+ return 0;
+}
+
+/* poodle digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link poodle_dai = {
+ .name = "WM8731",
+ .stream_name = "WM8731",
+ .cpu_dai = &pxa_i2s_dai,
+ .codec_dai = &wm8731_dai,
+ .init = poodle_wm8731_init,
+ .ops = &poodle_ops,
+};
+
+/* poodle audio machine driver */
+static struct snd_soc_machine snd_soc_machine_poodle = {
+ .name = "Poodle",
+ .dai_link = &poodle_dai,
+ .num_links = 1,
+};
+
+/* poodle audio private data */
+static struct wm8731_setup_data poodle_wm8731_setup = {
+ .i2c_address = 0x1b,
+};
+
+/* poodle audio subsystem */
+static struct snd_soc_device poodle_snd_devdata = {
+ .machine = &snd_soc_machine_poodle,
+ .platform = &pxa2xx_soc_platform,
+ .codec_dev = &soc_codec_dev_wm8731,
+ .codec_data = &poodle_wm8731_setup,
+};
+
+static struct platform_device *poodle_snd_device;
+
+static int __init poodle_init(void)
+{
+ int ret;
+
+ if (!machine_is_poodle())
+ return -ENODEV;
+
+ locomo_gpio_set_dir(&poodle_locomo_device.dev,
+ POODLE_LOCOMO_GPIO_AMP_ON, 0);
+ /* should we mute HP at startup - burning power ?*/
+ locomo_gpio_set_dir(&poodle_locomo_device.dev,
+ POODLE_LOCOMO_GPIO_MUTE_L, 0);
+ locomo_gpio_set_dir(&poodle_locomo_device.dev,
+ POODLE_LOCOMO_GPIO_MUTE_R, 0);
+
+ poodle_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!poodle_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(poodle_snd_device, &poodle_snd_devdata);
+ poodle_snd_devdata.dev = &poodle_snd_device->dev;
+ ret = platform_device_add(poodle_snd_device);
+
+ if (ret)
+ platform_device_put(poodle_snd_device);
+
+ return ret;
+}
+
+static void __exit poodle_exit(void)
+{
+ platform_device_unregister(poodle_snd_device);
+}
+
+module_init(poodle_init);
+module_exit(poodle_exit);
+
+/* Module information */
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Poodle");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
new file mode 100644
index 00000000000..1bbbeff84ef
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -0,0 +1,431 @@
+/*
+ * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip.
+ *
+ * Author: Nicolas Pitre
+ * Created: Dec 02, 2004
+ * Copyright: 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/irq.h>
+#include <linux/mutex.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/audio.h>
+
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+static DEFINE_MUTEX(car_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
+static volatile long gsr_bits;
+
+/*
+ * Beware PXA27x bugs:
+ *
+ * o Slot 12 read from modem space will hang controller.
+ * o CDONE, SDONE interrupt fails after any slot 12 IO.
+ *
+ * We therefore have an hybrid approach for waiting on SDONE (interrupt or
+ * 1 jiffy timeout if interrupt never comes).
+ */
+
+static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ unsigned short val = -1;
+ volatile u32 *reg_addr;
+
+ mutex_lock(&car_mutex);
+
+ /* set up primary or secondary codec/modem space */
+#ifdef CONFIG_PXA27x
+ reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+#else
+ if (reg == AC97_GPIO_STATUS)
+ reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
+ else
+ reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+#endif
+ reg_addr += (reg >> 1);
+
+#ifndef CONFIG_PXA27x
+ if (reg == AC97_GPIO_STATUS) {
+ /* read from controller cache */
+ val = *reg_addr;
+ goto out;
+ }
+#endif
+
+ /* start read access across the ac97 link */
+ GSR = GSR_CDONE | GSR_SDONE;
+ gsr_bits = 0;
+ val = *reg_addr;
+
+ wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
+ if (!((GSR | gsr_bits) & GSR_SDONE)) {
+ printk(KERN_ERR "%s: read error (ac97_reg=%x GSR=%#lx)\n",
+ __FUNCTION__, reg, GSR | gsr_bits);
+ val = -1;
+ goto out;
+ }
+
+ /* valid data now */
+ GSR = GSR_CDONE | GSR_SDONE;
+ gsr_bits = 0;
+ val = *reg_addr;
+ /* but we've just started another cycle... */
+ wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
+
+out: mutex_unlock(&car_mutex);
+ return val;
+}
+
+static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ volatile u32 *reg_addr;
+
+ mutex_lock(&car_mutex);
+
+ /* set up primary or secondary codec/modem space */
+#ifdef CONFIG_PXA27x
+ reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+#else
+ if (reg == AC97_GPIO_STATUS)
+ reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
+ else
+ reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
+#endif
+ reg_addr += (reg >> 1);
+
+ GSR = GSR_CDONE | GSR_SDONE;
+ gsr_bits = 0;
+ *reg_addr = val;
+ wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1);
+ if (!((GSR | gsr_bits) & GSR_CDONE))
+ printk(KERN_ERR "%s: write error (ac97_reg=%x GSR=%#lx)\n",
+ __FUNCTION__, reg, GSR | gsr_bits);
+
+ mutex_unlock(&car_mutex);
+}
+
+static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ gsr_bits = 0;
+
+#ifdef CONFIG_PXA27x
+ /* warm reset broken on Bulverde,
+ so manually keep AC97 reset high */
+ pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH);
+ udelay(10);
+ GCR |= GCR_WARM_RST;
+ pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+ udelay(500);
+#else
+ GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN;
+ wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+#endif
+
+ if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
+ printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
+ __FUNCTION__, gsr_bits);
+
+ GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+ GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
+}
+
+static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+ GCR &= GCR_COLD_RST; /* clear everything but nCRST */
+ GCR &= ~GCR_COLD_RST; /* then assert nCRST */
+
+ gsr_bits = 0;
+#ifdef CONFIG_PXA27x
+ /* PXA27x Developers Manual section 13.5.2.2.1 */
+ pxa_set_cken(1 << 31, 1);
+ udelay(5);
+ pxa_set_cken(1 << 31, 0);
+ GCR = GCR_COLD_RST;
+ udelay(50);
+#else
+ GCR = GCR_COLD_RST;
+ GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
+ wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+#endif
+
+ if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
+ printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
+ __FUNCTION__, gsr_bits);
+
+ GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+ GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
+}
+
+static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
+{
+ long status;
+
+ status = GSR;
+ if (status) {
+ GSR = status;
+ gsr_bits |= status;
+ wake_up(&gsr_wq);
+
+#ifdef CONFIG_PXA27x
+ /* Although we don't use those we still need to clear them
+ since they tend to spuriously trigger when MMC is used
+ (hardware bug? go figure)... */
+ MISR = MISR_EOC;
+ PISR = PISR_EOC;
+ MCSR = MCSR_EOC;
+#endif
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = pxa2xx_ac97_read,
+ .write = pxa2xx_ac97_write,
+ .warm_reset = pxa2xx_ac97_warm_reset,
+ .reset = pxa2xx_ac97_cold_reset,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = {
+ .name = "AC97 PCM Stereo out",
+ .dev_addr = __PREG(PCDR),
+ .drcmr = &DRCMRTXPCDR,
+ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
+ DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = {
+ .name = "AC97 PCM Stereo in",
+ .dev_addr = __PREG(PCDR),
+ .drcmr = &DRCMRRXPCDR,
+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
+ DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = {
+ .name = "AC97 Aux PCM (Slot 5) Mono out",
+ .dev_addr = __PREG(MODR),
+ .drcmr = &DRCMRTXMODR,
+ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
+ DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = {
+ .name = "AC97 Aux PCM (Slot 5) Mono in",
+ .dev_addr = __PREG(MODR),
+ .drcmr = &DRCMRRXMODR,
+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
+ DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = {
+ .name = "AC97 Mic PCM (Slot 6) Mono in",
+ .dev_addr = __PREG(MCDR),
+ .drcmr = &DRCMRRXMCDR,
+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
+ DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+#ifdef CONFIG_PM
+static int pxa2xx_ac97_suspend(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *dai)
+{
+ GCR |= GCR_ACLINK_OFF;
+ pxa_set_cken(CKEN2_AC97, 0);
+ return 0;
+}
+
+static int pxa2xx_ac97_resume(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *dai)
+{
+ pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
+ pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
+ pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
+ pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
+#ifdef CONFIG_PXA27x
+ /* Use GPIO 113 as AC97 Reset on Bulverde */
+ pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+#endif
+ pxa_set_cken(CKEN2_AC97, 1);
+ return 0;
+}
+
+#else
+#define pxa2xx_ac97_suspend NULL
+#define pxa2xx_ac97_resume NULL
+#endif
+
+static int pxa2xx_ac97_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL);
+ if (ret < 0)
+ goto err;
+
+ pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
+ pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
+ pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
+ pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
+#ifdef CONFIG_PXA27x
+ /* Use GPIO 113 as AC97 Reset on Bulverde */
+ pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+#endif
+ pxa_set_cken(CKEN2_AC97, 1);
+ return 0;
+
+ err:
+ if (CKEN & CKEN2_AC97) {
+ GCR |= GCR_ACLINK_OFF;
+ free_irq(IRQ_AC97, NULL);
+ pxa_set_cken(CKEN2_AC97, 0);
+ }
+ return ret;
+}
+
+static void pxa2xx_ac97_remove(struct platform_device *pdev)
+{
+ GCR |= GCR_ACLINK_OFF;
+ free_irq(IRQ_AC97, NULL);
+ pxa_set_cken(CKEN2_AC97, 0);
+}
+
+static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out;
+ else
+ cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in;
+
+ return 0;
+}
+
+static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out;
+ else
+ cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in;
+
+ return 0;
+}
+
+static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return -ENODEV;
+ else
+ cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in;
+
+ return 0;
+}
+
+#define PXA2XX_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000)
+
+/*
+ * There is only 1 physical AC97 interface for pxa2xx, but it
+ * has extra fifo's that can be used for aux DACs and ADCs.
+ */
+struct snd_soc_cpu_dai pxa_ac97_dai[] = {
+{
+ .name = "pxa2xx-ac97",
+ .id = 0,
+ .type = SND_SOC_DAI_AC97,
+ .probe = pxa2xx_ac97_probe,
+ .remove = pxa2xx_ac97_remove,
+ .suspend = pxa2xx_ac97_suspend,
+ .resume = pxa2xx_ac97_resume,
+ .playback = {
+ .stream_name = "AC97 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PXA2XX_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .stream_name = "AC97 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PXA2XX_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .hw_params = pxa2xx_ac97_hw_params,},
+},
+{
+ .name = "pxa2xx-ac97-aux",
+ .id = 1,
+ .type = SND_SOC_DAI_AC97,
+ .playback = {
+ .stream_name = "AC97 Aux Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = PXA2XX_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .stream_name = "AC97 Aux Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = PXA2XX_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .hw_params = pxa2xx_ac97_hw_aux_params,},
+},
+{
+ .name = "pxa2xx-ac97-mic",
+ .id = 2,
+ .type = SND_SOC_DAI_AC97,
+ .capture = {
+ .stream_name = "AC97 Mic Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = PXA2XX_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .hw_params = pxa2xx_ac97_hw_mic_params,},
+},
+};
+
+EXPORT_SYMBOL_GPL(pxa_ac97_dai);
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-ac97.h b/sound/soc/pxa/pxa2xx-ac97.h
new file mode 100644
index 00000000000..4c4b882316a
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-ac97.h
@@ -0,0 +1,22 @@
+/*
+ * linux/sound/arm/pxa2xx-ac97.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PXA2XX_AC97_H
+#define _PXA2XX_AC97_H
+
+/* pxa2xx DAI ID's */
+#define PXA2XX_DAI_AC97_HIFI 0
+#define PXA2XX_DAI_AC97_AUX 1
+#define PXA2XX_DAI_AC97_MIC 2
+
+extern struct snd_soc_cpu_dai pxa_ac97_dai[3];
+
+/* platform data */
+extern struct snd_ac97_bus_ops pxa2xx_ac97_ops;
+
+#endif
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
new file mode 100644
index 00000000000..575a6137c04
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -0,0 +1,318 @@
+/*
+ * pxa2xx-i2s.c -- ALSA Soc Audio Layer
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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.
+ *
+ * Revision history
+ * 12th Aug 2005 Initial version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/audio.h>
+
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+
+struct pxa_i2s_port {
+ u32 sadiv;
+ u32 sacr0;
+ u32 sacr1;
+ u32 saimr;
+ int master;
+ u32 fmt;
+};
+static struct pxa_i2s_port pxa_i2s;
+
+static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
+ .name = "I2S PCM Stereo out",
+ .dev_addr = __PREG(SADR),
+ .drcmr = &DRCMRTXSADR,
+ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
+ DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = {
+ .name = "I2S PCM Stereo in",
+ .dev_addr = __PREG(SADR),
+ .drcmr = &DRCMRRXSADR,
+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
+ DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct pxa2xx_gpio gpio_bus[] = {
+ { /* I2S SoC Slave */
+ .rx = GPIO29_SDATA_IN_I2S_MD,
+ .tx = GPIO30_SDATA_OUT_I2S_MD,
+ .clk = GPIO28_BITCLK_IN_I2S_MD,
+ .frm = GPIO31_SYNC_I2S_MD,
+ },
+ { /* I2S SoC Master */
+#ifdef CONFIG_PXA27x
+ .sys = GPIO113_I2S_SYSCLK_MD,
+#else
+ .sys = GPIO32_SYSCLK_I2S_MD,
+#endif
+ .rx = GPIO29_SDATA_IN_I2S_MD,
+ .tx = GPIO30_SDATA_OUT_I2S_MD,
+ .clk = GPIO28_BITCLK_OUT_I2S_MD,
+ .frm = GPIO31_SYNC_I2S_MD,
+ },
+};
+
+static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (!cpu_dai->active) {
+ SACR0 |= SACR0_RST;
+ SACR0 = 0;
+ }
+
+ return 0;
+}
+
+/* wait for I2S controller to be ready */
+static int pxa_i2s_wait(void)
+{
+ int i;
+
+ /* flush the Rx FIFO */
+ for(i = 0; i < 16; i++)
+ SADR;
+ return 0;
+}
+
+static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
+ unsigned int fmt)
+{
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ pxa_i2s.fmt = 0;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ pxa_i2s.fmt = SACR1_AMSL;
+ break;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ pxa_i2s.master = 1;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ pxa_i2s.master = 0;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ if (clk_id != PXA2XX_I2S_SYSCLK)
+ return -ENODEV;
+
+ if (pxa_i2s.master && dir == SND_SOC_CLOCK_OUT)
+ pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys);
+
+ return 0;
+}
+
+static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx);
+ pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx);
+ pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm);
+ pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk);
+ pxa_set_cken(CKEN8_I2S, 1);
+ pxa_i2s_wait();
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out;
+ else
+ cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in;
+
+ /* is port used by another stream */
+ if (!(SACR0 & SACR0_ENB)) {
+
+ SACR0 = 0;
+ SACR1 = 0;
+ if (pxa_i2s.master)
+ SACR0 |= SACR0_BCKD;
+
+ SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1);
+ SACR1 |= pxa_i2s.fmt;
+ }
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ SAIMR |= SAIMR_TFS;
+ else
+ SAIMR |= SAIMR_RFS;
+
+ switch (params_rate(params)) {
+ case 8000:
+ SADIV = 0x48;
+ break;
+ case 11025:
+ SADIV = 0x34;
+ break;
+ case 16000:
+ SADIV = 0x24;
+ break;
+ case 22050:
+ SADIV = 0x1a;
+ break;
+ case 44100:
+ SADIV = 0xd;
+ break;
+ case 48000:
+ SADIV = 0xc;
+ break;
+ case 96000: /* not in manual and possibly slightly inaccurate */
+ SADIV = 0x6;
+ break;
+ }
+
+ return 0;
+}
+
+static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ SACR0 |= SACR0_ENB;
+ break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ SACR1 |= SACR1_DRPL;
+ SAIMR &= ~SAIMR_TFS;
+ } else {
+ SACR1 |= SACR1_DREC;
+ SAIMR &= ~SAIMR_RFS;
+ }
+
+ if (SACR1 & (SACR1_DREC | SACR1_DRPL)) {
+ SACR0 &= ~SACR0_ENB;
+ pxa_i2s_wait();
+ pxa_set_cken(CKEN8_I2S, 0);
+ }
+}
+
+#ifdef CONFIG_PM
+static int pxa2xx_i2s_suspend(struct platform_device *dev,
+ struct snd_soc_cpu_dai *dai)
+{
+ if (!dai->active)
+ return 0;
+
+ /* store registers */
+ pxa_i2s.sacr0 = SACR0;
+ pxa_i2s.sacr1 = SACR1;
+ pxa_i2s.saimr = SAIMR;
+ pxa_i2s.sadiv = SADIV;
+
+ /* deactivate link */
+ SACR0 &= ~SACR0_ENB;
+ pxa_i2s_wait();
+ return 0;
+}
+
+static int pxa2xx_i2s_resume(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *dai)
+{
+ if (!dai->active)
+ return 0;
+
+ pxa_i2s_wait();
+
+ SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB;
+ SACR1 = pxa_i2s.sacr1;
+ SAIMR = pxa_i2s.saimr;
+ SADIV = pxa_i2s.sadiv;
+ SACR0 |= SACR0_ENB;
+
+ return 0;
+}
+
+#else
+#define pxa2xx_i2s_suspend NULL
+#define pxa2xx_i2s_resume NULL
+#endif
+
+#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+
+struct snd_soc_cpu_dai pxa_i2s_dai = {
+ .name = "pxa2xx-i2s",
+ .id = 0,
+ .type = SND_SOC_DAI_I2S,
+ .suspend = pxa2xx_i2s_suspend,
+ .resume = pxa2xx_i2s_resume,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PXA2XX_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PXA2XX_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .startup = pxa2xx_i2s_startup,
+ .shutdown = pxa2xx_i2s_shutdown,
+ .trigger = pxa2xx_i2s_trigger,
+ .hw_params = pxa2xx_i2s_hw_params,},
+ .dai_ops = {
+ .set_fmt = pxa2xx_i2s_set_dai_fmt,
+ .set_sysclk = pxa2xx_i2s_set_dai_sysclk,
+ },
+};
+
+EXPORT_SYMBOL_GPL(pxa_i2s_dai);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h
new file mode 100644
index 00000000000..a2484f0881f
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-i2s.h
@@ -0,0 +1,20 @@
+/*
+ * linux/sound/arm/pxa2xx-i2s.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PXA2XX_I2S_H
+#define _PXA2XX_I2S_H
+
+/* pxa2xx DAI ID's */
+#define PXA2XX_DAI_I2S 0
+
+/* I2S clock */
+#define PXA2XX_I2S_SYSCLK 0
+
+extern struct snd_soc_cpu_dai pxa_i2s_dai;
+
+#endif
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
new file mode 100644
index 00000000000..35e8fa3a469
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -0,0 +1,372 @@
+/*
+ * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 30, 2004
+ * Copyright: (C) 2004 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/audio.h>
+
+#include "pxa2xx-pcm.h"
+
+static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8192 - 32,
+ .periods_min = 1,
+ .periods_max = PAGE_SIZE/sizeof(pxa_dma_desc),
+ .buffer_bytes_max = 128 * 1024,
+ .fifo_size = 32,
+};
+
+struct pxa2xx_runtime_data {
+ int dma_ch;
+ struct pxa2xx_pcm_dma_params *params;
+ pxa_dma_desc *dma_desc_array;
+ dma_addr_t dma_desc_array_phys;
+};
+
+static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
+{
+ struct snd_pcm_substream *substream = dev_id;
+ struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+ int dcsr;
+
+ dcsr = DCSR(dma_ch);
+ DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
+
+ if (dcsr & DCSR_ENDINTR) {
+ snd_pcm_period_elapsed(substream);
+ } else {
+ printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
+ prtd->params->name, dma_ch, dcsr );
+ }
+}
+
+static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pxa2xx_runtime_data *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
+ size_t totsize = params_buffer_bytes(params);
+ size_t period = params_period_bytes(params);
+ pxa_dma_desc *dma_desc;
+ dma_addr_t dma_buff_phys, next_desc_phys;
+ int ret;
+
+ /* return if this is a bufferless transfer e.g.
+ * codec <--> BT codec or GSM modem -- lg FIXME */
+ if (!dma)
+ return 0;
+
+ /* this may get called several times by oss emulation
+ * with different params */
+ if (prtd->params == NULL) {
+ prtd->params = dma;
+ ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW,
+ pxa2xx_pcm_dma_irq, substream);
+ if (ret < 0)
+ return ret;
+ prtd->dma_ch = ret;
+ } else if (prtd->params != dma) {
+ pxa_free_dma(prtd->dma_ch);
+ prtd->params = dma;
+ ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW,
+ pxa2xx_pcm_dma_irq, substream);
+ if (ret < 0)
+ return ret;
+ prtd->dma_ch = ret;
+ }
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ runtime->dma_bytes = totsize;
+
+ dma_desc = prtd->dma_desc_array;
+ next_desc_phys = prtd->dma_desc_array_phys;
+ dma_buff_phys = runtime->dma_addr;
+ do {
+ next_desc_phys += sizeof(pxa_dma_desc);
+ dma_desc->ddadr = next_desc_phys;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dma_desc->dsadr = dma_buff_phys;
+ dma_desc->dtadr = prtd->params->dev_addr;
+ } else {
+ dma_desc->dsadr = prtd->params->dev_addr;
+ dma_desc->dtadr = dma_buff_phys;
+ }
+ if (period > totsize)
+ period = totsize;
+ dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN;
+ dma_desc++;
+ dma_buff_phys += period;
+ } while (totsize -= period);
+ dma_desc[-1].ddadr = prtd->dma_desc_array_phys;
+
+ return 0;
+}
+
+static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+
+ if (prtd && prtd->params)
+ *prtd->params->drcmr = 0;
+
+ if (prtd->dma_ch) {
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ pxa_free_dma(prtd->dma_ch);
+ prtd->dma_ch = 0;
+ }
+
+ return 0;
+}
+
+static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+
+ DCSR(prtd->dma_ch) &= ~DCSR_RUN;
+ DCSR(prtd->dma_ch) = 0;
+ DCMD(prtd->dma_ch) = 0;
+ *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD;
+
+ return 0;
+}
+
+static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
+ DCSR(prtd->dma_ch) = DCSR_RUN;
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ DCSR(prtd->dma_ch) &= ~DCSR_RUN;
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ DCSR(prtd->dma_ch) |= DCSR_RUN;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
+ DCSR(prtd->dma_ch) |= DCSR_RUN;
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t
+pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pxa2xx_runtime_data *prtd = runtime->private_data;
+
+ dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch);
+ snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
+
+ if (x == runtime->buffer_size)
+ x = 0;
+ return x;
+}
+
+static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pxa2xx_runtime_data *prtd;
+ int ret;
+
+ snd_soc_set_runtime_hwparams(substream, &pxa2xx_pcm_hardware);
+
+ /*
+ * For mysterious reasons (and despite what the manual says)
+ * playback samples are lost if the DMA count is not a multiple
+ * of the DMA burst size. Let's add a rule to enforce that.
+ */
+ ret = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+ if (ret)
+ goto out;
+
+ ret = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+ if (ret)
+ goto out;
+
+ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ goto out;
+
+ prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL);
+ if (prtd == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ prtd->dma_desc_array =
+ dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+ &prtd->dma_desc_array_phys, GFP_KERNEL);
+ if (!prtd->dma_desc_array) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ runtime->private_data = prtd;
+ return 0;
+
+ err1:
+ kfree(prtd);
+ out:
+ return ret;
+}
+
+static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pxa2xx_runtime_data *prtd = runtime->private_data;
+
+ dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+ prtd->dma_desc_array, prtd->dma_desc_array_phys);
+ kfree(prtd);
+ return 0;
+}
+
+static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+struct snd_pcm_ops pxa2xx_pcm_ops = {
+ .open = pxa2xx_pcm_open,
+ .close = pxa2xx_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pxa2xx_pcm_hw_params,
+ .hw_free = pxa2xx_pcm_hw_free,
+ .prepare = pxa2xx_pcm_prepare,
+ .trigger = pxa2xx_pcm_trigger,
+ .pointer = pxa2xx_pcm_pointer,
+ .mmap = pxa2xx_pcm_mmap,
+};
+
+static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+ buf->bytes = size;
+ return 0;
+}
+
+static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_writecombine(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
+}
+
+static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK;
+
+int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+ struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &pxa2xx_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+ if (dai->playback.channels_min) {
+ ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto out;
+ }
+
+ if (dai->capture.channels_min) {
+ ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto out;
+ }
+ out:
+ return ret;
+}
+
+struct snd_soc_platform pxa2xx_soc_platform = {
+ .name = "pxa2xx-audio",
+ .pcm_ops = &pxa2xx_pcm_ops,
+ .pcm_new = pxa2xx_pcm_new,
+ .pcm_free = pxa2xx_pcm_free_dma_buffers,
+};
+
+EXPORT_SYMBOL_GPL(pxa2xx_soc_platform);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h
new file mode 100644
index 00000000000..54c9c755e50
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-pcm.h
@@ -0,0 +1,34 @@
+/*
+ * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 30, 2004
+ * Copyright: 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 _PXA2XX_PCM_H
+#define _PXA2XX_PCM_H
+
+struct pxa2xx_pcm_dma_params {
+ char *name; /* stream identifier */
+ u32 dcmd; /* DMA descriptor dcmd field */
+ volatile u32 *drcmr; /* the DMA request channel to use */
+ u32 dev_addr; /* device physical address for DMA */
+};
+
+struct pxa2xx_gpio {
+ u32 sys;
+ u32 rx;
+ u32 tx;
+ u32 clk;
+ u32 frm;
+};
+
+/* platform data */
+extern struct snd_soc_platform pxa2xx_soc_platform;
+
+#endif
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
new file mode 100644
index 00000000000..80e82109fef
--- /dev/null
+++ b/sound/soc/pxa/spitz.c
@@ -0,0 +1,394 @@
+/*
+ * spitz.c -- SoC audio for Sharp SL-Cxx00 models Spitz, Borzoi and Akita
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Richard Purdie <richard@openedhand.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.
+ *
+ * Revision history
+ * 30th Nov 2005 Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/akita.h>
+#include <asm/arch/spitz.h>
+#include <asm/mach-types.h>
+#include "../codecs/wm8750.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+
+#define SPITZ_HP 0
+#define SPITZ_MIC 1
+#define SPITZ_LINE 2
+#define SPITZ_HEADSET 3
+#define SPITZ_HP_OFF 4
+#define SPITZ_SPK_ON 0
+#define SPITZ_SPK_OFF 1
+
+ /* audio clock in Hz - rounded from 12.235MHz */
+#define SPITZ_AUDIO_CLOCK 12288000
+
+static int spitz_jack_func;
+static int spitz_spk_func;
+
+static void spitz_ext_control(struct snd_soc_codec *codec)
+{
+ if (spitz_spk_func == SPITZ_SPK_ON)
+ snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1);
+ else
+ snd_soc_dapm_set_endpoint(codec, "Ext Spk", 0);
+
+ /* set up jack connection */
+ switch (spitz_jack_func) {
+ case SPITZ_HP:
+ /* enable and unmute hp jack, disable mic bias */
+ snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1);
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+ break;
+ case SPITZ_MIC:
+ /* enable mic jack and bias, mute hp */
+ snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+ break;
+ case SPITZ_LINE:
+ /* enable line jack, disable mic bias and mute hp */
+ snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Line Jack", 1);
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+ break;
+ case SPITZ_HEADSET:
+ /* enable and unmute headset jack enable mic bias, mute L hp */
+ snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
+ snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headset Jack", 1);
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+ break;
+ case SPITZ_HP_OFF:
+
+ /* jack removed, everything off */
+ snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
+ snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
+ break;
+ }
+ snd_soc_dapm_sync_endpoints(codec);
+}
+
+static int spitz_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->codec;
+
+ /* check the jack status at stream startup */
+ spitz_ext_control(codec);
+ return 0;
+}
+
+static int spitz_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+ unsigned int clk = 0;
+ int ret = 0;
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 48000:
+ case 96000:
+ clk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ clk = 11289600;
+ break;
+ }
+
+ /* set codec DAI configuration */
+ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set the I2S system clock as input (unused) */
+ ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops spitz_ops = {
+ .startup = spitz_startup,
+ .hw_params = spitz_hw_params,
+};
+
+static int spitz_get_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = spitz_jack_func;
+ return 0;
+}
+
+static int spitz_set_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (spitz_jack_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ spitz_jack_func = ucontrol->value.integer.value[0];
+ spitz_ext_control(codec);
+ return 1;
+}
+
+static int spitz_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = spitz_spk_func;
+ return 0;
+}
+
+static int spitz_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (spitz_spk_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ spitz_spk_func = ucontrol->value.integer.value[0];
+ spitz_ext_control(codec);
+ return 1;
+}
+
+static int spitz_mic_bias(struct snd_soc_dapm_widget *w, int event)
+{
+ if (machine_is_borzoi() || machine_is_spitz()) {
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ set_scoop_gpio(&spitzscoop2_device.dev,
+ SPITZ_SCP2_MIC_BIAS);
+ else
+ reset_scoop_gpio(&spitzscoop2_device.dev,
+ SPITZ_SCP2_MIC_BIAS);
+ }
+
+ if (machine_is_akita()) {
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ akita_set_ioexp(&akitaioexp_device.dev,
+ AKITA_IOEXP_MIC_BIAS);
+ else
+ akita_reset_ioexp(&akitaioexp_device.dev,
+ AKITA_IOEXP_MIC_BIAS);
+ }
+ return 0;
+}
+
+/* spitz machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_LINE("Line Jack", NULL),
+
+ /* headset is a mic and mono headphone */
+ SND_SOC_DAPM_HP("Headset Jack", NULL),
+};
+
+/* Spitz machine audio_map */
+static const char *audio_map[][3] = {
+
+ /* headphone connected to LOUT1, ROUT1 */
+ {"Headphone Jack", NULL, "LOUT1"},
+ {"Headphone Jack", NULL, "ROUT1"},
+
+ /* headset connected to ROUT1 and LINPUT1 with bias (def below) */
+ {"Headset Jack", NULL, "ROUT1"},
+
+ /* ext speaker connected to LOUT2, ROUT2 */
+ {"Ext Spk", NULL , "ROUT2"},
+ {"Ext Spk", NULL , "LOUT2"},
+
+ /* mic is connected to input 1 - with bias */
+ {"LINPUT1", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Mic Jack"},
+
+ /* line is connected to input 1 - no bias */
+ {"LINPUT1", NULL, "Line Jack"},
+
+ {NULL, NULL, NULL},
+};
+
+static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
+ "Off"};
+static const char *spk_function[] = {"On", "Off"};
+static const struct soc_enum spitz_enum[] = {
+ SOC_ENUM_SINGLE_EXT(5, jack_function),
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
+ SOC_ENUM_EXT("Jack Function", spitz_enum[0], spitz_get_jack,
+ spitz_set_jack),
+ SOC_ENUM_EXT("Speaker Function", spitz_enum[1], spitz_get_spk,
+ spitz_set_spk),
+};
+
+/*
+ * Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device
+ */
+static int spitz_wm8750_init(struct snd_soc_codec *codec)
+{
+ int i, err;
+
+ /* NC codec pins */
+ snd_soc_dapm_set_endpoint(codec, "RINPUT1", 0);
+ snd_soc_dapm_set_endpoint(codec, "LINPUT2", 0);
+ snd_soc_dapm_set_endpoint(codec, "RINPUT2", 0);
+ snd_soc_dapm_set_endpoint(codec, "LINPUT3", 0);
+ snd_soc_dapm_set_endpoint(codec, "RINPUT3", 0);
+ snd_soc_dapm_set_endpoint(codec, "OUT3", 0);
+ snd_soc_dapm_set_endpoint(codec, "MONO", 0);
+
+ /* Add spitz specific controls */
+ for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
+ err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&wm8750_spitz_controls[i], codec, NULL));
+ if (err < 0)
+ return err;
+ }
+
+ /* Add spitz specific widgets */
+ for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) {
+ snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]);
+ }
+
+ /* Set up spitz specific audio path audio_map */
+ for (i = 0; audio_map[i][0] != NULL; i++) {
+ snd_soc_dapm_connect_input(codec, audio_map[i][0],
+ audio_map[i][1], audio_map[i][2]);
+ }
+
+ snd_soc_dapm_sync_endpoints(codec);
+ return 0;
+}
+
+/* spitz digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link spitz_dai = {
+ .name = "wm8750",
+ .stream_name = "WM8750",
+ .cpu_dai = &pxa_i2s_dai,
+ .codec_dai = &wm8750_dai,
+ .init = spitz_wm8750_init,
+ .ops = &spitz_ops,
+};
+
+/* spitz audio machine driver */
+static struct snd_soc_machine snd_soc_machine_spitz = {
+ .name = "Spitz",
+ .dai_link = &spitz_dai,
+ .num_links = 1,
+};
+
+/* spitz audio private data */
+static struct wm8750_setup_data spitz_wm8750_setup = {
+ .i2c_address = 0x1b,
+};
+
+/* spitz audio subsystem */
+static struct snd_soc_device spitz_snd_devdata = {
+ .machine = &snd_soc_machine_spitz,
+ .platform = &pxa2xx_soc_platform,
+ .codec_dev = &soc_codec_dev_wm8750,
+ .codec_data = &spitz_wm8750_setup,
+};
+
+static struct platform_device *spitz_snd_device;
+
+static int __init spitz_init(void)
+{
+ int ret;
+
+ if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita()))
+ return -ENODEV;
+
+ spitz_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!spitz_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(spitz_snd_device, &spitz_snd_devdata);
+ spitz_snd_devdata.dev = &spitz_snd_device->dev;
+ ret = platform_device_add(spitz_snd_device);
+
+ if (ret)
+ platform_device_put(spitz_snd_device);
+
+ return ret;
+}
+
+static void __exit spitz_exit(void)
+{
+ platform_device_unregister(spitz_snd_device);
+}
+
+module_init(spitz_init);
+module_exit(spitz_exit);
+
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Spitz");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
new file mode 100644
index 00000000000..5504e30acf1
--- /dev/null
+++ b/sound/soc/pxa/tosa.c
@@ -0,0 +1,289 @@
+/*
+ * tosa.c -- SoC audio for Tosa
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Richard Purdie <richard@openedhand.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.
+ *
+ * Revision history
+ * 30th Nov 2005 Initial version.
+ *
+ * GPIO's
+ * 1 - Jack Insertion
+ * 5 - Hookswitch (headset answer/hang up switch)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/tmio.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/audio.h>
+#include <asm/arch/tosa.h>
+
+#include "../codecs/wm9712.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+static struct snd_soc_machine tosa;
+
+#define TOSA_HP 0
+#define TOSA_MIC_INT 1
+#define TOSA_HEADSET 2
+#define TOSA_HP_OFF 3
+#define TOSA_SPK_ON 0
+#define TOSA_SPK_OFF 1
+
+static int tosa_jack_func;
+static int tosa_spk_func;
+
+static void tosa_ext_control(struct snd_soc_codec *codec)
+{
+ int spk = 0, mic_int = 0, hp = 0, hs = 0;
+
+ /* set up jack connection */
+ switch (tosa_jack_func) {
+ case TOSA_HP:
+ hp = 1;
+ break;
+ case TOSA_MIC_INT:
+ mic_int = 1;
+ break;
+ case TOSA_HEADSET:
+ hs = 1;
+ break;
+ }
+
+ if (tosa_spk_func == TOSA_SPK_ON)
+ spk = 1;
+
+ snd_soc_dapm_set_endpoint(codec, "Speaker", spk);
+ snd_soc_dapm_set_endpoint(codec, "Mic (Internal)", mic_int);
+ snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp);
+ snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs);
+ snd_soc_dapm_sync_endpoints(codec);
+}
+
+static int tosa_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->codec;
+
+ /* check the jack status at stream startup */
+ tosa_ext_control(codec);
+ return 0;
+}
+
+static struct snd_soc_ops tosa_ops = {
+ .startup = tosa_startup,
+};
+
+static int tosa_get_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = tosa_jack_func;
+ return 0;
+}
+
+static int tosa_set_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (tosa_jack_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ tosa_jack_func = ucontrol->value.integer.value[0];
+ tosa_ext_control(codec);
+ return 1;
+}
+
+static int tosa_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = tosa_spk_func;
+ return 0;
+}
+
+static int tosa_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (tosa_spk_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ tosa_spk_func = ucontrol->value.integer.value[0];
+ tosa_ext_control(codec);
+ return 1;
+}
+
+/* tosa dapm event handlers */
+static int tosa_hp_event(struct snd_soc_dapm_widget *w, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ set_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE);
+ else
+ reset_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE);
+ return 0;
+}
+
+/* tosa machine dapm widgets */
+static const struct snd_soc_dapm_widget tosa_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", tosa_hp_event),
+SND_SOC_DAPM_HP("Headset Jack", NULL),
+SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+/* tosa audio map */
+static const char *audio_map[][3] = {
+
+ /* headphone connected to HPOUTL, HPOUTR */
+ {"Headphone Jack", NULL, "HPOUTL"},
+ {"Headphone Jack", NULL, "HPOUTR"},
+
+ /* ext speaker connected to LOUT2, ROUT2 */
+ {"Speaker", NULL, "LOUT2"},
+ {"Speaker", NULL, "ROUT2"},
+
+ /* internal mic is connected to mic1, mic2 differential - with bias */
+ {"MIC1", NULL, "Mic Bias"},
+ {"MIC2", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Mic (Internal)"},
+
+ /* headset is connected to HPOUTR, and LINEINR with bias */
+ {"Headset Jack", NULL, "HPOUTR"},
+ {"LINEINR", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Headset Jack"},
+
+ {NULL, NULL, NULL},
+};
+
+static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
+ "Off"};
+static const char *spk_function[] = {"On", "Off"};
+static const struct soc_enum tosa_enum[] = {
+ SOC_ENUM_SINGLE_EXT(5, jack_function),
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new tosa_controls[] = {
+ SOC_ENUM_EXT("Jack Function", tosa_enum[0], tosa_get_jack,
+ tosa_set_jack),
+ SOC_ENUM_EXT("Speaker Function", tosa_enum[1], tosa_get_spk,
+ tosa_set_spk),
+};
+
+static int tosa_ac97_init(struct snd_soc_codec *codec)
+{
+ int i, err;
+
+ snd_soc_dapm_set_endpoint(codec, "OUT3", 0);
+ snd_soc_dapm_set_endpoint(codec, "MONOOUT", 0);
+
+ /* add tosa specific controls */
+ for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) {
+ err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&tosa_controls[i],codec, NULL));
+ if (err < 0)
+ return err;
+ }
+
+ /* add tosa specific widgets */
+ for (i = 0; i < ARRAY_SIZE(tosa_dapm_widgets); i++) {
+ snd_soc_dapm_new_control(codec, &tosa_dapm_widgets[i]);
+ }
+
+ /* set up tosa specific audio path audio_map */
+ for (i = 0; audio_map[i][0] != NULL; i++) {
+ snd_soc_dapm_connect_input(codec, audio_map[i][0],
+ audio_map[i][1], audio_map[i][2]);
+ }
+
+ snd_soc_dapm_sync_endpoints(codec);
+ return 0;
+}
+
+static struct snd_soc_dai_link tosa_dai[] = {
+{
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+ .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .init = tosa_ac97_init,
+ .ops = &tosa_ops,
+},
+{
+ .name = "AC97 Aux",
+ .stream_name = "AC97 Aux",
+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+ .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+ .ops = &tosa_ops,
+},
+};
+
+static struct snd_soc_machine tosa = {
+ .name = "Tosa",
+ .dai_link = tosa_dai,
+ .num_links = ARRAY_SIZE(tosa_dai),
+};
+
+static struct snd_soc_device tosa_snd_devdata = {
+ .machine = &tosa,
+ .platform = &pxa2xx_soc_platform,
+ .codec_dev = &soc_codec_dev_wm9712,
+};
+
+static struct platform_device *tosa_snd_device;
+
+static int __init tosa_init(void)
+{
+ int ret;
+
+ if (!machine_is_tosa())
+ return -ENODEV;
+
+ tosa_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!tosa_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(tosa_snd_device, &tosa_snd_devdata);
+ tosa_snd_devdata.dev = &tosa_snd_device->dev;
+ ret = platform_device_add(tosa_snd_device);
+
+ if (ret)
+ platform_device_put(tosa_snd_device);
+
+ return ret;
+}
+
+static void __exit tosa_exit(void)
+{
+ platform_device_unregister(tosa_snd_device);
+}
+
+module_init(tosa_init);
+module_exit(tosa_exit);
+
+/* Module information */
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Tosa");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
new file mode 100644
index 00000000000..36519aef55d
--- /dev/null
+++ b/sound/soc/soc-core.c
@@ -0,0 +1,1587 @@
+/*
+ * soc-core.c -- ALSA SoC Audio Layer
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Liam Girdwood
+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * with code, comments and ideas from :-
+ * Richard Purdie <richard@openedhand.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.
+ *
+ * Revision history
+ * 12th Aug 2005 Initial version.
+ * 25th Oct 2005 Working Codec, Interface and Platform registration.
+ *
+ * TODO:
+ * o Add hw rules to enforce rates, etc.
+ * o More testing with other codecs/machines.
+ * o Add more codecs and platforms to ensure good API coverage.
+ * o Support TDM on PCM and I2S
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+/* debug */
+#define SOC_DEBUG 0
+#if SOC_DEBUG
+#define dbg(format, arg...) printk(format, ## arg)
+#else
+#define dbg(format, arg...)
+#endif
+
+static DEFINE_MUTEX(pcm_mutex);
+static DEFINE_MUTEX(io_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
+
+/*
+ * This is a timeout to do a DAPM powerdown after a stream is closed().
+ * It can be used to eliminate pops between different playback streams, e.g.
+ * between two audio tracks.
+ */
+static int pmdown_time = 5000;
+module_param(pmdown_time, int, 0);
+MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
+
+/*
+ * This function forces any delayed work to be queued and run.
+ */
+static int run_delayed_work(struct delayed_work *dwork)
+{
+ int ret;
+
+ /* cancel any work waiting to be queued. */
+ ret = cancel_delayed_work(dwork);
+
+ /* if there was any work waiting then we run it now and
+ * wait for it's completion */
+ if (ret) {
+ schedule_delayed_work(dwork, 0);
+ flush_scheduled_work();
+ }
+ return ret;
+}
+
+#ifdef CONFIG_SND_SOC_AC97_BUS
+/* unregister ac97 codec */
+static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
+{
+ if (codec->ac97->dev.bus)
+ device_unregister(&codec->ac97->dev);
+ return 0;
+}
+
+/* stop no dev release warning */
+static void soc_ac97_device_release(struct device *dev){}
+
+/* register ac97 codec to bus */
+static int soc_ac97_dev_register(struct snd_soc_codec *codec)
+{
+ int err;
+
+ codec->ac97->dev.bus = &ac97_bus_type;
+ codec->ac97->dev.parent = NULL;
+ codec->ac97->dev.release = soc_ac97_device_release;
+
+ snprintf(codec->ac97->dev.bus_id, BUS_ID_SIZE, "%d-%d:%s",
+ codec->card->number, 0, codec->name);
+ err = device_register(&codec->ac97->dev);
+ if (err < 0) {
+ snd_printk(KERN_ERR "Can't register ac97 bus\n");
+ codec->ac97->dev.bus = NULL;
+ return err;
+ }
+ return 0;
+}
+#endif
+
+static inline const char* get_dai_name(int type)
+{
+ switch(type) {
+ case SND_SOC_DAI_AC97:
+ return "AC97";
+ case SND_SOC_DAI_I2S:
+ return "I2S";
+ case SND_SOC_DAI_PCM:
+ return "PCM";
+ }
+ return NULL;
+}
+
+/*
+ * Called by ALSA when a PCM substream is opened, the runtime->hw record is
+ * then initialized and any private data can be allocated. This also calls
+ * startup for the cpu DAI, platform, machine and codec DAI.
+ */
+static int soc_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_dai_link *machine = rtd->dai;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+ struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+ int ret = 0;
+
+ mutex_lock(&pcm_mutex);
+
+ /* startup the audio subsystem */
+ if (cpu_dai->ops.startup) {
+ ret = cpu_dai->ops.startup(substream);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't open interface %s\n",
+ cpu_dai->name);
+ goto out;
+ }
+ }
+
+ if (platform->pcm_ops->open) {
+ ret = platform->pcm_ops->open(substream);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
+ goto platform_err;
+ }
+ }
+
+ if (codec_dai->ops.startup) {
+ ret = codec_dai->ops.startup(substream);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't open codec %s\n",
+ codec_dai->name);
+ goto codec_dai_err;
+ }
+ }
+
+ if (machine->ops && machine->ops->startup) {
+ ret = machine->ops->startup(substream);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: %s startup failed\n", machine->name);
+ goto machine_err;
+ }
+ }
+
+ /* Check that the codec and cpu DAI's are compatible */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw.rate_min =
+ max(codec_dai->playback.rate_min, cpu_dai->playback.rate_min);
+ runtime->hw.rate_max =
+ min(codec_dai->playback.rate_max, cpu_dai->playback.rate_max);
+ runtime->hw.channels_min =
+ max(codec_dai->playback.channels_min,
+ cpu_dai->playback.channels_min);
+ runtime->hw.channels_max =
+ min(codec_dai->playback.channels_max,
+ cpu_dai->playback.channels_max);
+ runtime->hw.formats =
+ codec_dai->playback.formats & cpu_dai->playback.formats;
+ runtime->hw.rates =
+ codec_dai->playback.rates & cpu_dai->playback.rates;
+ } else {
+ runtime->hw.rate_min =
+ max(codec_dai->capture.rate_min, cpu_dai->capture.rate_min);
+ runtime->hw.rate_max =
+ min(codec_dai->capture.rate_max, cpu_dai->capture.rate_max);
+ runtime->hw.channels_min =
+ max(codec_dai->capture.channels_min,
+ cpu_dai->capture.channels_min);
+ runtime->hw.channels_max =
+ min(codec_dai->capture.channels_max,
+ cpu_dai->capture.channels_max);
+ runtime->hw.formats =
+ codec_dai->capture.formats & cpu_dai->capture.formats;
+ runtime->hw.rates =
+ codec_dai->capture.rates & cpu_dai->capture.rates;
+ }
+
+ snd_pcm_limit_hw_rates(runtime);
+ if (!runtime->hw.rates) {
+ printk(KERN_ERR "asoc: %s <-> %s No matching rates\n",
+ codec_dai->name, cpu_dai->name);
+ goto machine_err;
+ }
+ if (!runtime->hw.formats) {
+ printk(KERN_ERR "asoc: %s <-> %s No matching formats\n",
+ codec_dai->name, cpu_dai->name);
+ goto machine_err;
+ }
+ if (!runtime->hw.channels_min || !runtime->hw.channels_max) {
+ printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
+ codec_dai->name, cpu_dai->name);
+ goto machine_err;
+ }
+
+ dbg("asoc: %s <-> %s info:\n",codec_dai->name, cpu_dai->name);
+ dbg("asoc: rate mask 0x%x\n", runtime->hw.rates);
+ dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
+ runtime->hw.channels_max);
+ dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
+ runtime->hw.rate_max);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_dai->playback.active = codec_dai->playback.active = 1;
+ else
+ cpu_dai->capture.active = codec_dai->capture.active = 1;
+ cpu_dai->active = codec_dai->active = 1;
+ cpu_dai->runtime = runtime;
+ socdev->codec->active++;
+ mutex_unlock(&pcm_mutex);
+ return 0;
+
+machine_err:
+ if (machine->ops && machine->ops->shutdown)
+ machine->ops->shutdown(substream);
+
+codec_dai_err:
+ if (platform->pcm_ops->close)
+ platform->pcm_ops->close(substream);
+
+platform_err:
+ if (cpu_dai->ops.shutdown)
+ cpu_dai->ops.shutdown(substream);
+out:
+ mutex_unlock(&pcm_mutex);
+ return ret;
+}
+
+/*
+ * Power down the audio subsytem pmdown_time msecs after close is called.
+ * This is to ensure there are no pops or clicks in between any music tracks
+ * due to DAPM power cycling.
+ */
+static void close_delayed_work(struct work_struct *work)
+{
+ struct snd_soc_device *socdev =
+ container_of(work, struct snd_soc_device, delayed_work.work);
+ struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec_dai *codec_dai;
+ int i;
+
+ mutex_lock(&pcm_mutex);
+ for(i = 0; i < codec->num_dai; i++) {
+ codec_dai = &codec->dai[i];
+
+ dbg("pop wq checking: %s status: %s waiting: %s\n",
+ codec_dai->playback.stream_name,
+ codec_dai->playback.active ? "active" : "inactive",
+ codec_dai->pop_wait ? "yes" : "no");
+
+ /* are we waiting on this codec DAI stream */
+ if (codec_dai->pop_wait == 1) {
+
+ codec_dai->pop_wait = 0;
+ snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name,
+ SND_SOC_DAPM_STREAM_STOP);
+
+ /* power down the codec power domain if no longer active */
+ if (codec->active == 0) {
+ dbg("pop wq D3 %s %s\n", codec->name,
+ codec_dai->playback.stream_name);
+ if (codec->dapm_event)
+ codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+ }
+ }
+ }
+ mutex_unlock(&pcm_mutex);
+}
+
+/*
+ * Called by ALSA when a PCM substream is closed. Private data can be
+ * freed here. The cpu DAI, codec DAI, machine and platform are also
+ * shutdown.
+ */
+static int soc_codec_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_dai_link *machine = rtd->dai;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+ struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_codec *codec = socdev->codec;
+
+ mutex_lock(&pcm_mutex);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_dai->playback.active = codec_dai->playback.active = 0;
+ else
+ cpu_dai->capture.active = codec_dai->capture.active = 0;
+
+ if (codec_dai->playback.active == 0 &&
+ codec_dai->capture.active == 0) {
+ cpu_dai->active = codec_dai->active = 0;
+ }
+ codec->active--;
+
+ if (cpu_dai->ops.shutdown)
+ cpu_dai->ops.shutdown(substream);
+
+ if (codec_dai->ops.shutdown)
+ codec_dai->ops.shutdown(substream);
+
+ if (machine->ops && machine->ops->shutdown)
+ machine->ops->shutdown(substream);
+
+ if (platform->pcm_ops->close)
+ platform->pcm_ops->close(substream);
+ cpu_dai->runtime = NULL;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* start delayed pop wq here for playback streams */
+ codec_dai->pop_wait = 1;
+ schedule_delayed_work(&socdev->delayed_work,
+ msecs_to_jiffies(pmdown_time));
+ } else {
+ /* capture streams can be powered down now */
+ snd_soc_dapm_stream_event(codec,
+ codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_STOP);
+
+ if (codec->active == 0 && codec_dai->pop_wait == 0){
+ if (codec->dapm_event)
+ codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+ }
+ }
+
+ mutex_unlock(&pcm_mutex);
+ return 0;
+}
+
+/*
+ * Called by ALSA when the PCM substream is prepared, can set format, sample
+ * rate, etc. This function is non atomic and can be called multiple times,
+ * it can refer to the runtime info.
+ */
+static int soc_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_dai_link *machine = rtd->dai;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+ struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_codec *codec = socdev->codec;
+ int ret = 0;
+
+ mutex_lock(&pcm_mutex);
+
+ if (machine->ops && machine->ops->prepare) {
+ ret = machine->ops->prepare(substream);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: machine prepare error\n");
+ goto out;
+ }
+ }
+
+ if (platform->pcm_ops->prepare) {
+ ret = platform->pcm_ops->prepare(substream);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: platform prepare error\n");
+ goto out;
+ }
+ }
+
+ if (codec_dai->ops.prepare) {
+ ret = codec_dai->ops.prepare(substream);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: codec DAI prepare error\n");
+ goto out;
+ }
+ }
+
+ if (cpu_dai->ops.prepare) {
+ ret = cpu_dai->ops.prepare(substream);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: cpu DAI prepare error\n");
+ goto out;
+ }
+ }
+
+ /* we only want to start a DAPM playback stream if we are not waiting
+ * on an existing one stopping */
+ if (codec_dai->pop_wait) {
+ /* we are waiting for the delayed work to start */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ snd_soc_dapm_stream_event(socdev->codec,
+ codec_dai->capture.stream_name,
+ SND_SOC_DAPM_STREAM_START);
+ else {
+ codec_dai->pop_wait = 0;
+ cancel_delayed_work(&socdev->delayed_work);
+ if (codec_dai->dai_ops.digital_mute)
+ codec_dai->dai_ops.digital_mute(codec_dai, 0);
+ }
+ } else {
+ /* no delayed work - do we need to power up codec */
+ if (codec->dapm_state != SNDRV_CTL_POWER_D0) {
+
+ if (codec->dapm_event)
+ codec->dapm_event(codec, SNDRV_CTL_POWER_D1);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dapm_stream_event(codec,
+ codec_dai->playback.stream_name,
+ SND_SOC_DAPM_STREAM_START);
+ else
+ snd_soc_dapm_stream_event(codec,
+ codec_dai->capture.stream_name,
+ SND_SOC_DAPM_STREAM_START);
+
+ if (codec->dapm_event)
+ codec->dapm_event(codec, SNDRV_CTL_POWER_D0);
+ if (codec_dai->dai_ops.digital_mute)
+ codec_dai->dai_ops.digital_mute(codec_dai, 0);
+
+ } else {
+ /* codec already powered - power on widgets */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dapm_stream_event(codec,
+ codec_dai->playback.stream_name,
+ SND_SOC_DAPM_STREAM_START);
+ else
+ snd_soc_dapm_stream_event(codec,
+ codec_dai->capture.stream_name,
+ SND_SOC_DAPM_STREAM_START);
+ if (codec_dai->dai_ops.digital_mute)
+ codec_dai->dai_ops.digital_mute(codec_dai, 0);
+ }
+ }
+
+out:
+ mutex_unlock(&pcm_mutex);
+ return ret;
+}
+
+/*
+ * Called by ALSA when the hardware params are set by application. This
+ * function can also be called multiple times and can allocate buffers
+ * (using snd_pcm_lib_* ). It's non-atomic.
+ */
+static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_dai_link *machine = rtd->dai;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+ struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+ int ret = 0;
+
+ mutex_lock(&pcm_mutex);
+
+ if (machine->ops && machine->ops->hw_params) {
+ ret = machine->ops->hw_params(substream, params);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: machine hw_params failed\n");
+ goto out;
+ }
+ }
+
+ if (codec_dai->ops.hw_params) {
+ ret = codec_dai->ops.hw_params(substream, params);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't set codec %s hw params\n",
+ codec_dai->name);
+ goto codec_err;
+ }
+ }
+
+ if (cpu_dai->ops.hw_params) {
+ ret = cpu_dai->ops.hw_params(substream, params);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't set interface %s hw params\n",
+ cpu_dai->name);
+ goto interface_err;
+ }
+ }
+
+ if (platform->pcm_ops->hw_params) {
+ ret = platform->pcm_ops->hw_params(substream, params);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't set platform %s hw params\n",
+ platform->name);
+ goto platform_err;
+ }
+ }
+
+out:
+ mutex_unlock(&pcm_mutex);
+ return ret;
+
+platform_err:
+ if (cpu_dai->ops.hw_free)
+ cpu_dai->ops.hw_free(substream);
+
+interface_err:
+ if (codec_dai->ops.hw_free)
+ codec_dai->ops.hw_free(substream);
+
+codec_err:
+ if(machine->ops && machine->ops->hw_free)
+ machine->ops->hw_free(substream);
+
+ mutex_unlock(&pcm_mutex);
+ return ret;
+}
+
+/*
+ * Free's resources allocated by hw_params, can be called multiple times
+ */
+static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_dai_link *machine = rtd->dai;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+ struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+ struct snd_soc_codec *codec = socdev->codec;
+
+ mutex_lock(&pcm_mutex);
+
+ /* apply codec digital mute */
+ if (!codec->active && codec_dai->dai_ops.digital_mute)
+ codec_dai->dai_ops.digital_mute(codec_dai, 1);
+
+ /* free any machine hw params */
+ if (machine->ops && machine->ops->hw_free)
+ machine->ops->hw_free(substream);
+
+ /* free any DMA resources */
+ if (platform->pcm_ops->hw_free)
+ platform->pcm_ops->hw_free(substream);
+
+ /* now free hw params for the DAI's */
+ if (codec_dai->ops.hw_free)
+ codec_dai->ops.hw_free(substream);
+
+ if (cpu_dai->ops.hw_free)
+ cpu_dai->ops.hw_free(substream);
+
+ mutex_unlock(&pcm_mutex);
+ return 0;
+}
+
+static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_dai_link *machine = rtd->dai;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
+ struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+ int ret;
+
+ if (codec_dai->ops.trigger) {
+ ret = codec_dai->ops.trigger(substream, cmd);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (platform->pcm_ops->trigger) {
+ ret = platform->pcm_ops->trigger(substream, cmd);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (cpu_dai->ops.trigger) {
+ ret = cpu_dai->ops.trigger(substream, cmd);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+/* ASoC PCM operations */
+static struct snd_pcm_ops soc_pcm_ops = {
+ .open = soc_pcm_open,
+ .close = soc_codec_close,
+ .hw_params = soc_pcm_hw_params,
+ .hw_free = soc_pcm_hw_free,
+ .prepare = soc_pcm_prepare,
+ .trigger = soc_pcm_trigger,
+};
+
+#ifdef CONFIG_PM
+/* powers down audio subsystem for suspend */
+static int soc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_machine *machine = socdev->machine;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+ struct snd_soc_codec *codec = socdev->codec;
+ int i;
+
+ /* mute any active DAC's */
+ for(i = 0; i < machine->num_links; i++) {
+ struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;
+ if (dai->dai_ops.digital_mute && dai->playback.active)
+ dai->dai_ops.digital_mute(dai, 1);
+ }
+
+ if (machine->suspend_pre)
+ machine->suspend_pre(pdev, state);
+
+ for(i = 0; i < machine->num_links; i++) {
+ struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+ if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97)
+ cpu_dai->suspend(pdev, cpu_dai);
+ if (platform->suspend)
+ platform->suspend(pdev, cpu_dai);
+ }
+
+ /* close any waiting streams and save state */
+ run_delayed_work(&socdev->delayed_work);
+ codec->suspend_dapm_state = codec->dapm_state;
+
+ for(i = 0; i < codec->num_dai; i++) {
+ char *stream = codec->dai[i].playback.stream_name;
+ if (stream != NULL)
+ snd_soc_dapm_stream_event(codec, stream,
+ SND_SOC_DAPM_STREAM_SUSPEND);
+ stream = codec->dai[i].capture.stream_name;
+ if (stream != NULL)
+ snd_soc_dapm_stream_event(codec, stream,
+ SND_SOC_DAPM_STREAM_SUSPEND);
+ }
+
+ if (codec_dev->suspend)
+ codec_dev->suspend(pdev, state);
+
+ for(i = 0; i < machine->num_links; i++) {
+ struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+ if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97)
+ cpu_dai->suspend(pdev, cpu_dai);
+ }
+
+ if (machine->suspend_post)
+ machine->suspend_post(pdev, state);
+
+ return 0;
+}
+
+/* powers up audio subsystem after a suspend */
+static int soc_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_machine *machine = socdev->machine;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+ struct snd_soc_codec *codec = socdev->codec;
+ int i;
+
+ if (machine->resume_pre)
+ machine->resume_pre(pdev);
+
+ for(i = 0; i < machine->num_links; i++) {
+ struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+ if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97)
+ cpu_dai->resume(pdev, cpu_dai);
+ }
+
+ if (codec_dev->resume)
+ codec_dev->resume(pdev);
+
+ for(i = 0; i < codec->num_dai; i++) {
+ char* stream = codec->dai[i].playback.stream_name;
+ if (stream != NULL)
+ snd_soc_dapm_stream_event(codec, stream,
+ SND_SOC_DAPM_STREAM_RESUME);
+ stream = codec->dai[i].capture.stream_name;
+ if (stream != NULL)
+ snd_soc_dapm_stream_event(codec, stream,
+ SND_SOC_DAPM_STREAM_RESUME);
+ }
+
+ /* unmute any active DAC's */
+ for(i = 0; i < machine->num_links; i++) {
+ struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;
+ if (dai->dai_ops.digital_mute && dai->playback.active)
+ dai->dai_ops.digital_mute(dai, 0);
+ }
+
+ for(i = 0; i < machine->num_links; i++) {
+ struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+ if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97)
+ cpu_dai->resume(pdev, cpu_dai);
+ if (platform->resume)
+ platform->resume(pdev, cpu_dai);
+ }
+
+ if (machine->resume_post)
+ machine->resume_post(pdev);
+
+ return 0;
+}
+
+#else
+#define soc_suspend NULL
+#define soc_resume NULL
+#endif
+
+/* probes a new socdev */
+static int soc_probe(struct platform_device *pdev)
+{
+ int ret = 0, i;
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_machine *machine = socdev->machine;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+
+ if (machine->probe) {
+ ret = machine->probe(pdev);
+ if(ret < 0)
+ return ret;
+ }
+
+ for (i = 0; i < machine->num_links; i++) {
+ struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+ if (cpu_dai->probe) {
+ ret = cpu_dai->probe(pdev);
+ if(ret < 0)
+ goto cpu_dai_err;
+ }
+ }
+
+ if (codec_dev->probe) {
+ ret = codec_dev->probe(pdev);
+ if(ret < 0)
+ goto cpu_dai_err;
+ }
+
+ if (platform->probe) {
+ ret = platform->probe(pdev);
+ if(ret < 0)
+ goto platform_err;
+ }
+
+ /* DAPM stream work */
+ INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work);
+ return 0;
+
+platform_err:
+ if (codec_dev->remove)
+ codec_dev->remove(pdev);
+
+cpu_dai_err:
+ for (i--; i >= 0; i--) {
+ struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+ if (cpu_dai->remove)
+ cpu_dai->remove(pdev);
+ }
+
+ if (machine->remove)
+ machine->remove(pdev);
+
+ return ret;
+}
+
+/* removes a socdev */
+static int soc_remove(struct platform_device *pdev)
+{
+ int i;
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_machine *machine = socdev->machine;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+
+ run_delayed_work(&socdev->delayed_work);
+
+ if (platform->remove)
+ platform->remove(pdev);
+
+ if (codec_dev->remove)
+ codec_dev->remove(pdev);
+
+ for (i = 0; i < machine->num_links; i++) {
+ struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+ if (cpu_dai->remove)
+ cpu_dai->remove(pdev);
+ }
+
+ if (machine->remove)
+ machine->remove(pdev);
+
+ return 0;
+}
+
+/* ASoC platform driver */
+static struct platform_driver soc_driver = {
+ .driver = {
+ .name = "soc-audio",
+ },
+ .probe = soc_probe,
+ .remove = soc_remove,
+ .suspend = soc_suspend,
+ .resume = soc_resume,
+};
+
+/* create a new pcm */
+static int soc_new_pcm(struct snd_soc_device *socdev,
+ struct snd_soc_dai_link *dai_link, int num)
+{
+ struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec_dai *codec_dai = dai_link->codec_dai;
+ struct snd_soc_cpu_dai *cpu_dai = dai_link->cpu_dai;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_pcm *pcm;
+ char new_name[64];
+ int ret = 0, playback = 0, capture = 0;
+
+ rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
+ if (rtd == NULL)
+ return -ENOMEM;
+
+ rtd->dai = dai_link;
+ rtd->socdev = socdev;
+ codec_dai->codec = socdev->codec;
+
+ /* check client and interface hw capabilities */
+ sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name,
+ get_dai_name(cpu_dai->type), num);
+
+ if (codec_dai->playback.channels_min)
+ playback = 1;
+ if (codec_dai->capture.channels_min)
+ capture = 1;
+
+ ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback,
+ capture, &pcm);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
+ kfree(rtd);
+ return ret;
+ }
+
+ pcm->private_data = rtd;
+ soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap;
+ soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer;
+ soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl;
+ soc_pcm_ops.copy = socdev->platform->pcm_ops->copy;
+ soc_pcm_ops.silence = socdev->platform->pcm_ops->silence;
+ soc_pcm_ops.ack = socdev->platform->pcm_ops->ack;
+ soc_pcm_ops.page = socdev->platform->pcm_ops->page;
+
+ if (playback)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
+
+ if (capture)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
+
+ ret = socdev->platform->pcm_new(codec->card, codec_dai, pcm);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: platform pcm constructor failed\n");
+ kfree(rtd);
+ return ret;
+ }
+
+ pcm->private_free = socdev->platform->pcm_free;
+ printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
+ cpu_dai->name);
+ return ret;
+}
+
+/* codec register dump */
+static ssize_t codec_reg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct snd_soc_device *devdata = dev_get_drvdata(dev);
+ struct snd_soc_codec *codec = devdata->codec;
+ int i, step = 1, count = 0;
+
+ if (!codec->reg_cache_size)
+ return 0;
+
+ if (codec->reg_cache_step)
+ step = codec->reg_cache_step;
+
+ count += sprintf(buf, "%s registers\n", codec->name);
+ for(i = 0; i < codec->reg_cache_size; i += step)
+ count += sprintf(buf + count, "%2x: %4x\n", i, codec->read(codec, i));
+
+ return count;
+}
+static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
+
+/**
+ * snd_soc_new_ac97_codec - initailise AC97 device
+ * @codec: audio codec
+ * @ops: AC97 bus operations
+ * @num: AC97 codec number
+ *
+ * Initialises AC97 codec resources for use by ad-hoc devices only.
+ */
+int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
+ struct snd_ac97_bus_ops *ops, int num)
+{
+ mutex_lock(&codec->mutex);
+
+ codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
+ if (codec->ac97 == NULL) {
+ mutex_unlock(&codec->mutex);
+ return -ENOMEM;
+ }
+
+ codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL);
+ if (codec->ac97->bus == NULL) {
+ kfree(codec->ac97);
+ codec->ac97 = NULL;
+ mutex_unlock(&codec->mutex);
+ return -ENOMEM;
+ }
+
+ codec->ac97->bus->ops = ops;
+ codec->ac97->num = num;
+ mutex_unlock(&codec->mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
+
+/**
+ * snd_soc_free_ac97_codec - free AC97 codec device
+ * @codec: audio codec
+ *
+ * Frees AC97 codec device resources.
+ */
+void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
+{
+ mutex_lock(&codec->mutex);
+ kfree(codec->ac97->bus);
+ kfree(codec->ac97);
+ codec->ac97 = NULL;
+ mutex_unlock(&codec->mutex);
+}
+EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
+
+/**
+ * snd_soc_update_bits - update codec register bits
+ * @codec: audio codec
+ * @reg: codec register
+ * @mask: register mask
+ * @value: new value
+ *
+ * Writes new register value.
+ *
+ * Returns 1 for change else 0.
+ */
+int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
+ unsigned short mask, unsigned short value)
+{
+ int change;
+ unsigned short old, new;
+
+ mutex_lock(&io_mutex);
+ old = snd_soc_read(codec, reg);
+ new = (old & ~mask) | value;
+ change = old != new;
+ if (change)
+ snd_soc_write(codec, reg, new);
+
+ mutex_unlock(&io_mutex);
+ return change;
+}
+EXPORT_SYMBOL_GPL(snd_soc_update_bits);
+
+/**
+ * snd_soc_test_bits - test register for change
+ * @codec: audio codec
+ * @reg: codec register
+ * @mask: register mask
+ * @value: new value
+ *
+ * Tests a register with a new value and checks if the new value is
+ * different from the old value.
+ *
+ * Returns 1 for change else 0.
+ */
+int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
+ unsigned short mask, unsigned short value)
+{
+ int change;
+ unsigned short old, new;
+
+ mutex_lock(&io_mutex);
+ old = snd_soc_read(codec, reg);
+ new = (old & ~mask) | value;
+ change = old != new;
+ mutex_unlock(&io_mutex);
+
+ return change;
+}
+EXPORT_SYMBOL_GPL(snd_soc_test_bits);
+
+/**
+ * snd_soc_new_pcms - create new sound card and pcms
+ * @socdev: the SoC audio device
+ *
+ * Create a new sound card based upon the codec and interface pcms.
+ *
+ * Returns 0 for success, else error.
+ */
+int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
+{
+ struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_machine *machine = socdev->machine;
+ int ret = 0, i;
+
+ mutex_lock(&codec->mutex);
+
+ /* register a sound card */
+ codec->card = snd_card_new(idx, xid, codec->owner, 0);
+ if (!codec->card) {
+ printk(KERN_ERR "asoc: can't create sound card for codec %s\n",
+ codec->name);
+ mutex_unlock(&codec->mutex);
+ return -ENODEV;
+ }
+
+ codec->card->dev = socdev->dev;
+ codec->card->private_data = codec;
+ strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
+
+ /* create the pcms */
+ for(i = 0; i < machine->num_links; i++) {
+ ret = soc_new_pcm(socdev, &machine->dai_link[i], i);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't create pcm %s\n",
+ machine->dai_link[i].stream_name);
+ mutex_unlock(&codec->mutex);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&codec->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
+
+/**
+ * snd_soc_register_card - register sound card
+ * @socdev: the SoC audio device
+ *
+ * Register a SoC sound card. Also registers an AC97 device if the
+ * codec is AC97 for ad hoc devices.
+ *
+ * Returns 0 for success, else error.
+ */
+int snd_soc_register_card(struct snd_soc_device *socdev)
+{
+ struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_machine *machine = socdev->machine;
+ int ret = 0, i, ac97 = 0, err = 0;
+
+ mutex_lock(&codec->mutex);
+ for(i = 0; i < machine->num_links; i++) {
+ if (socdev->machine->dai_link[i].init) {
+ err = socdev->machine->dai_link[i].init(codec);
+ if (err < 0) {
+ printk(KERN_ERR "asoc: failed to init %s\n",
+ socdev->machine->dai_link[i].stream_name);
+ continue;
+ }
+ }
+ if (socdev->machine->dai_link[i].cpu_dai->type == SND_SOC_DAI_AC97)
+ ac97 = 1;
+ }
+ snprintf(codec->card->shortname, sizeof(codec->card->shortname),
+ "%s", machine->name);
+ snprintf(codec->card->longname, sizeof(codec->card->longname),
+ "%s (%s)", machine->name, codec->name);
+
+ ret = snd_card_register(codec->card);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n",
+ codec->name);
+ goto out;
+ }
+
+#ifdef CONFIG_SND_SOC_AC97_BUS
+ if (ac97) {
+ ret = soc_ac97_dev_register(codec);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: AC97 device register failed\n");
+ snd_card_free(codec->card);
+ goto out;
+ }
+ }
+#endif
+
+ err = snd_soc_dapm_sys_add(socdev->dev);
+ if (err < 0)
+ printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
+
+ err = device_create_file(socdev->dev, &dev_attr_codec_reg);
+ if (err < 0)
+ printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n");
+out:
+ mutex_unlock(&codec->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_card);
+
+/**
+ * snd_soc_free_pcms - free sound card and pcms
+ * @socdev: the SoC audio device
+ *
+ * Frees sound card and pcms associated with the socdev.
+ * Also unregister the codec if it is an AC97 device.
+ */
+void snd_soc_free_pcms(struct snd_soc_device *socdev)
+{
+ struct snd_soc_codec *codec = socdev->codec;
+
+ mutex_lock(&codec->mutex);
+#ifdef CONFIG_SND_SOC_AC97_BUS
+ if (codec->ac97)
+ soc_ac97_dev_unregister(codec);
+#endif
+
+ if (codec->card)
+ snd_card_free(codec->card);
+ device_remove_file(socdev->dev, &dev_attr_codec_reg);
+ mutex_unlock(&codec->mutex);
+}
+EXPORT_SYMBOL_GPL(snd_soc_free_pcms);
+
+/**
+ * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
+ * @substream: the pcm substream
+ * @hw: the hardware parameters
+ *
+ * Sets the substream runtime hardware parameters.
+ */
+int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
+ const struct snd_pcm_hardware *hw)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ runtime->hw.info = hw->info;
+ runtime->hw.formats = hw->formats;
+ runtime->hw.period_bytes_min = hw->period_bytes_min;
+ runtime->hw.period_bytes_max = hw->period_bytes_max;
+ runtime->hw.periods_min = hw->periods_min;
+ runtime->hw.periods_max = hw->periods_max;
+ runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
+ runtime->hw.fifo_size = hw->fifo_size;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
+
+/**
+ * snd_soc_cnew - create new control
+ * @_template: control template
+ * @data: control private data
+ * @lnng_name: control long name
+ *
+ * Create a new mixer control from a template control.
+ *
+ * Returns 0 for success, else error.
+ */
+struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
+ void *data, char *long_name)
+{
+ struct snd_kcontrol_new template;
+
+ memcpy(&template, _template, sizeof(template));
+ if (long_name)
+ template.name = long_name;
+ template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+ template.index = 0;
+
+ return snd_ctl_new1(&template, data);
+}
+EXPORT_SYMBOL_GPL(snd_soc_cnew);
+
+/**
+ * snd_soc_info_enum_double - enumerated double mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a double enumerated
+ * mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
+ uinfo->value.enumerated.items = e->mask;
+
+ if (uinfo->value.enumerated.item > e->mask - 1)
+ uinfo->value.enumerated.item = e->mask - 1;
+ strcpy(uinfo->value.enumerated.name,
+ e->texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);
+
+/**
+ * snd_soc_get_enum_double - enumerated double mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a double enumerated mixer.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned short val, bitmask;
+
+ for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+ ;
+ val = snd_soc_read(codec, e->reg);
+ ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
+ if (e->shift_l != e->shift_r)
+ ucontrol->value.enumerated.item[1] =
+ (val >> e->shift_r) & (bitmask - 1);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_enum_double);
+
+/**
+ * snd_soc_put_enum_double - enumerated double mixer put callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a double enumerated mixer.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned short val;
+ unsigned short mask, bitmask;
+
+ for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+ ;
+ if (ucontrol->value.enumerated.item[0] > e->mask - 1)
+ return -EINVAL;
+ val = ucontrol->value.enumerated.item[0] << e->shift_l;
+ mask = (bitmask - 1) << e->shift_l;
+ if (e->shift_l != e->shift_r) {
+ if (ucontrol->value.enumerated.item[1] > e->mask - 1)
+ return -EINVAL;
+ val |= ucontrol->value.enumerated.item[1] << e->shift_r;
+ mask |= (bitmask - 1) << e->shift_r;
+ }
+
+ return snd_soc_update_bits(codec, e->reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
+
+/**
+ * snd_soc_info_enum_ext - external enumerated single mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about an external enumerated
+ * single mixer.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = e->mask;
+
+ if (uinfo->value.enumerated.item > e->mask - 1)
+ uinfo->value.enumerated.item = e->mask - 1;
+ strcpy(uinfo->value.enumerated.name,
+ e->texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext);
+
+/**
+ * snd_soc_info_volsw_ext - external single mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a single external mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int mask = kcontrol->private_value;
+
+ uinfo->type =
+ mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mask;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
+
+/**
+ * snd_soc_info_bool_ext - external single boolean mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a single boolean external mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_bool_ext);
+
+/**
+ * snd_soc_info_volsw - single mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0x0f;
+ int rshift = (kcontrol->private_value >> 12) & 0x0f;
+
+ uinfo->type =
+ mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = shift == rshift ? 1 : 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mask;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
+
+/**
+ * snd_soc_get_volsw - single mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int reg = kcontrol->private_value & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0x0f;
+ int rshift = (kcontrol->private_value >> 12) & 0x0f;
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & 0x01;
+
+ ucontrol->value.integer.value[0] =
+ (snd_soc_read(codec, reg) >> shift) & mask;
+ if (shift != rshift)
+ ucontrol->value.integer.value[1] =
+ (snd_soc_read(codec, reg) >> rshift) & mask;
+ if (invert) {
+ ucontrol->value.integer.value[0] =
+ mask - ucontrol->value.integer.value[0];
+ if (shift != rshift)
+ ucontrol->value.integer.value[1] =
+ mask - ucontrol->value.integer.value[1];
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
+
+/**
+ * snd_soc_put_volsw - single mixer put callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int reg = kcontrol->private_value & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0x0f;
+ int rshift = (kcontrol->private_value >> 12) & 0x0f;
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & 0x01;
+ int err;
+ unsigned short val, val2, val_mask;
+
+ val = (ucontrol->value.integer.value[0] & mask);
+ if (invert)
+ val = mask - val;
+ val_mask = mask << shift;
+ val = val << shift;
+ if (shift != rshift) {
+ val2 = (ucontrol->value.integer.value[1] & mask);
+ if (invert)
+ val2 = mask - val2;
+ val_mask |= mask << rshift;
+ val |= val2 << rshift;
+ }
+ err = snd_soc_update_bits(codec, reg, val_mask, val);
+ return err;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
+
+/**
+ * snd_soc_info_volsw_2r - double mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a double mixer control that
+ * spans 2 codec registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int mask = (kcontrol->private_value >> 12) & 0xff;
+
+ uinfo->type =
+ mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mask;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r);
+
+/**
+ * snd_soc_get_volsw_2r - double mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a double mixer control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int reg = kcontrol->private_value & 0xff;
+ int reg2 = (kcontrol->private_value >> 24) & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0x0f;
+ int mask = (kcontrol->private_value >> 12) & 0xff;
+ int invert = (kcontrol->private_value >> 20) & 0x01;
+
+ ucontrol->value.integer.value[0] =
+ (snd_soc_read(codec, reg) >> shift) & mask;
+ ucontrol->value.integer.value[1] =
+ (snd_soc_read(codec, reg2) >> shift) & mask;
+ if (invert) {
+ ucontrol->value.integer.value[0] =
+ mask - ucontrol->value.integer.value[0];
+ ucontrol->value.integer.value[1] =
+ mask - ucontrol->value.integer.value[1];
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r);
+
+/**
+ * snd_soc_put_volsw_2r - double mixer set callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a double mixer control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int reg = kcontrol->private_value & 0xff;
+ int reg2 = (kcontrol->private_value >> 24) & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0x0f;
+ int mask = (kcontrol->private_value >> 12) & 0xff;
+ int invert = (kcontrol->private_value >> 20) & 0x01;
+ int err;
+ unsigned short val, val2, val_mask;
+
+ val_mask = mask << shift;
+ val = (ucontrol->value.integer.value[0] & mask);
+ val2 = (ucontrol->value.integer.value[1] & mask);
+
+ if (invert) {
+ val = mask - val;
+ val2 = mask - val2;
+ }
+
+ val = val << shift;
+ val2 = val2 << shift;
+
+ if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0)
+ return err;
+
+ err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+ return err;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r);
+
+static int __devinit snd_soc_init(void)
+{
+ printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION);
+ return platform_driver_register(&soc_driver);
+}
+
+static void snd_soc_exit(void)
+{
+ platform_driver_unregister(&soc_driver);
+}
+
+module_init(snd_soc_init);
+module_exit(snd_soc_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC Core");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
new file mode 100644
index 00000000000..7caf8c7b0ac
--- /dev/null
+++ b/sound/soc/soc-dapm.c
@@ -0,0 +1,1323 @@
+/*
+ * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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.
+ *
+ * Revision history
+ * 12th Aug 2005 Initial version.
+ * 25th Oct 2005 Implemented path power domain.
+ * 18th Dec 2005 Implemented machine and stream level power domain.
+ *
+ * Features:
+ * o Changes power status of internal codec blocks depending on the
+ * dynamic configuration of codec internal audio paths and active
+ * DAC's/ADC's.
+ * o Platform power domain - can support external components i.e. amps and
+ * mic/meadphone insertion events.
+ * o Automatic Mic Bias support
+ * o Jack insertion power event initiation - e.g. hp insertion will enable
+ * sinks, dacs, etc
+ * o Delayed powerdown of audio susbsytem to reduce pops between a quick
+ * device reopen.
+ *
+ * Todo:
+ * o DAPM power change sequencing - allow for configurable per
+ * codec sequences.
+ * o Support for analogue bias optimisation.
+ * o Support for reduced codec oversampling rates.
+ * o Support for reduced codec bias currents.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+/* debug */
+#define DAPM_DEBUG 0
+#if DAPM_DEBUG
+#define dump_dapm(codec, action) dbg_dump_dapm(codec, action)
+#define dbg(format, arg...) printk(format, ## arg)
+#else
+#define dump_dapm(codec, action)
+#define dbg(format, arg...)
+#endif
+
+#define POP_DEBUG 0
+#if POP_DEBUG
+#define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */
+#define pop_wait(time) schedule_timeout_interruptible(msecs_to_jiffies(time))
+#define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME)
+#else
+#define pop_dbg(format, arg...)
+#define pop_wait(time)
+#endif
+
+/* dapm power sequences - make this per codec in the future */
+static int dapm_up_seq[] = {
+ snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
+ snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga,
+ snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post
+};
+static int dapm_down_seq[] = {
+ snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
+ snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic,
+ snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post
+};
+
+static int dapm_status = 1;
+module_param(dapm_status, int, 0);
+MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
+
+/* create a new dapm widget */
+static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
+ const struct snd_soc_dapm_widget *_widget)
+{
+ return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
+}
+
+/* set up initial codec paths */
+static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
+ struct snd_soc_dapm_path *p, int i)
+{
+ switch (w->id) {
+ case snd_soc_dapm_switch:
+ case snd_soc_dapm_mixer: {
+ int val;
+ int reg = w->kcontrols[i].private_value & 0xff;
+ int shift = (w->kcontrols[i].private_value >> 8) & 0x0f;
+ int mask = (w->kcontrols[i].private_value >> 16) & 0xff;
+ int invert = (w->kcontrols[i].private_value >> 24) & 0x01;
+
+ val = snd_soc_read(w->codec, reg);
+ val = (val >> shift) & mask;
+
+ if ((invert && !val) || (!invert && val))
+ p->connect = 1;
+ else
+ p->connect = 0;
+ }
+ break;
+ case snd_soc_dapm_mux: {
+ struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
+ int val, item, bitmask;
+
+ for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+ ;
+ val = snd_soc_read(w->codec, e->reg);
+ item = (val >> e->shift_l) & (bitmask - 1);
+
+ p->connect = 0;
+ for (i = 0; i < e->mask; i++) {
+ if (!(strcmp(p->name, e->texts[i])) && item == i)
+ p->connect = 1;
+ }
+ }
+ break;
+ /* does not effect routing - always connected */
+ case snd_soc_dapm_pga:
+ case snd_soc_dapm_output:
+ case snd_soc_dapm_adc:
+ case snd_soc_dapm_input:
+ case snd_soc_dapm_dac:
+ case snd_soc_dapm_micbias:
+ case snd_soc_dapm_vmid:
+ p->connect = 1;
+ break;
+ /* does effect routing - dynamically connected */
+ case snd_soc_dapm_hp:
+ case snd_soc_dapm_mic:
+ case snd_soc_dapm_spk:
+ case snd_soc_dapm_line:
+ case snd_soc_dapm_pre:
+ case snd_soc_dapm_post:
+ p->connect = 0;
+ break;
+ }
+}
+
+/* connect mux widget to it's interconnecting audio paths */
+static int dapm_connect_mux(struct snd_soc_codec *codec,
+ struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
+ struct snd_soc_dapm_path *path, const char *control_name,
+ const struct snd_kcontrol_new *kcontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int i;
+
+ for (i = 0; i < e->mask; i++) {
+ if (!(strcmp(control_name, e->texts[i]))) {
+ list_add(&path->list, &codec->dapm_paths);
+ list_add(&path->list_sink, &dest->sources);
+ list_add(&path->list_source, &src->sinks);
+ path->name = (char*)e->texts[i];
+ dapm_set_path_status(dest, path, 0);
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+/* connect mixer widget to it's interconnecting audio paths */
+static int dapm_connect_mixer(struct snd_soc_codec *codec,
+ struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
+ struct snd_soc_dapm_path *path, const char *control_name)
+{
+ int i;
+
+ /* search for mixer kcontrol */
+ for (i = 0; i < dest->num_kcontrols; i++) {
+ if (!strcmp(control_name, dest->kcontrols[i].name)) {
+ list_add(&path->list, &codec->dapm_paths);
+ list_add(&path->list_sink, &dest->sources);
+ list_add(&path->list_source, &src->sinks);
+ path->name = dest->kcontrols[i].name;
+ dapm_set_path_status(dest, path, i);
+ return 0;
+ }
+ }
+ return -ENODEV;
+}
+
+/* update dapm codec register bits */
+static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
+{
+ int change, power;
+ unsigned short old, new;
+ struct snd_soc_codec *codec = widget->codec;
+
+ /* check for valid widgets */
+ if (widget->reg < 0 || widget->id == snd_soc_dapm_input ||
+ widget->id == snd_soc_dapm_output ||
+ widget->id == snd_soc_dapm_hp ||
+ widget->id == snd_soc_dapm_mic ||
+ widget->id == snd_soc_dapm_line ||
+ widget->id == snd_soc_dapm_spk)
+ return 0;
+
+ power = widget->power;
+ if (widget->invert)
+ power = (power ? 0:1);
+
+ old = snd_soc_read(codec, widget->reg);
+ new = (old & ~(0x1 << widget->shift)) | (power << widget->shift);
+
+ change = old != new;
+ if (change) {
+ pop_dbg("pop test %s : %s in %d ms\n", widget->name,
+ widget->power ? "on" : "off", POP_TIME);
+ snd_soc_write(codec, widget->reg, new);
+ pop_wait(POP_TIME);
+ }
+ dbg("reg old %x new %x change %d\n", old, new, change);
+ return change;
+}
+
+/* ramps the volume up or down to minimise pops before or after a
+ * DAPM power event */
+static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power)
+{
+ const struct snd_kcontrol_new *k = widget->kcontrols;
+
+ if (widget->muted && !power)
+ return 0;
+ if (!widget->muted && power)
+ return 0;
+
+ if (widget->num_kcontrols && k) {
+ int reg = k->private_value & 0xff;
+ int shift = (k->private_value >> 8) & 0x0f;
+ int mask = (k->private_value >> 16) & 0xff;
+ int invert = (k->private_value >> 24) & 0x01;
+
+ if (power) {
+ int i;
+ /* power up has happended, increase volume to last level */
+ if (invert) {
+ for (i = mask; i > widget->saved_value; i--)
+ snd_soc_update_bits(widget->codec, reg, mask, i);
+ } else {
+ for (i = 0; i < widget->saved_value; i++)
+ snd_soc_update_bits(widget->codec, reg, mask, i);
+ }
+ widget->muted = 0;
+ } else {
+ /* power down is about to occur, decrease volume to mute */
+ int val = snd_soc_read(widget->codec, reg);
+ int i = widget->saved_value = (val >> shift) & mask;
+ if (invert) {
+ for (; i < mask; i++)
+ snd_soc_update_bits(widget->codec, reg, mask, i);
+ } else {
+ for (; i > 0; i--)
+ snd_soc_update_bits(widget->codec, reg, mask, i);
+ }
+ widget->muted = 1;
+ }
+ }
+ return 0;
+}
+
+/* create new dapm mixer control */
+static int dapm_new_mixer(struct snd_soc_codec *codec,
+ struct snd_soc_dapm_widget *w)
+{
+ int i, ret = 0;
+ char name[32];
+ struct snd_soc_dapm_path *path;
+
+ /* add kcontrol */
+ for (i = 0; i < w->num_kcontrols; i++) {
+
+ /* match name */
+ list_for_each_entry(path, &w->sources, list_sink) {
+
+ /* mixer/mux paths name must match control name */
+ if (path->name != (char*)w->kcontrols[i].name)
+ continue;
+
+ /* add dapm control with long name */
+ snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name);
+ path->long_name = kstrdup (name, GFP_KERNEL);
+ if (path->long_name == NULL)
+ return -ENOMEM;
+
+ path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
+ path->long_name);
+ ret = snd_ctl_add(codec->card, path->kcontrol);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n",
+ path->long_name);
+ kfree(path->long_name);
+ path->long_name = NULL;
+ return ret;
+ }
+ }
+ }
+ return ret;
+}
+
+/* create new dapm mux control */
+static int dapm_new_mux(struct snd_soc_codec *codec,
+ struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *path = NULL;
+ struct snd_kcontrol *kcontrol;
+ int ret = 0;
+
+ if (!w->num_kcontrols) {
+ printk(KERN_ERR "asoc: mux %s has no controls\n", w->name);
+ return -EINVAL;
+ }
+
+ kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
+ ret = snd_ctl_add(codec->card, kcontrol);
+ if (ret < 0)
+ goto err;
+
+ list_for_each_entry(path, &w->sources, list_sink)
+ path->kcontrol = kcontrol;
+
+ return ret;
+
+err:
+ printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
+ return ret;
+}
+
+/* create new dapm volume control */
+static int dapm_new_pga(struct snd_soc_codec *codec,
+ struct snd_soc_dapm_widget *w)
+{
+ struct snd_kcontrol *kcontrol;
+ int ret = 0;
+
+ if (!w->num_kcontrols)
+ return -EINVAL;
+
+ kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
+ ret = snd_ctl_add(codec->card, kcontrol);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
+ return ret;
+ }
+
+ return ret;
+}
+
+/* reset 'walked' bit for each dapm path */
+static inline void dapm_clear_walk(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_path *p;
+
+ list_for_each_entry(p, &codec->dapm_paths, list)
+ p->walked = 0;
+}
+
+/*
+ * Recursively check for a completed path to an active or physically connected
+ * output widget. Returns number of complete paths.
+ */
+static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
+{
+ struct snd_soc_dapm_path *path;
+ int con = 0;
+
+ if (widget->id == snd_soc_dapm_adc && widget->active)
+ return 1;
+
+ if (widget->connected) {
+ /* connected pin ? */
+ if (widget->id == snd_soc_dapm_output && !widget->ext)
+ return 1;
+
+ /* connected jack or spk ? */
+ if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk ||
+ widget->id == snd_soc_dapm_line)
+ return 1;
+ }
+
+ list_for_each_entry(path, &widget->sinks, list_source) {
+ if (path->walked)
+ continue;
+
+ if (path->sink && path->connect) {
+ path->walked = 1;
+ con += is_connected_output_ep(path->sink);
+ }
+ }
+
+ return con;
+}
+
+/*
+ * Recursively check for a completed path to an active or physically connected
+ * input widget. Returns number of complete paths.
+ */
+static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
+{
+ struct snd_soc_dapm_path *path;
+ int con = 0;
+
+ /* active stream ? */
+ if (widget->id == snd_soc_dapm_dac && widget->active)
+ return 1;
+
+ if (widget->connected) {
+ /* connected pin ? */
+ if (widget->id == snd_soc_dapm_input && !widget->ext)
+ return 1;
+
+ /* connected VMID/Bias for lower pops */
+ if (widget->id == snd_soc_dapm_vmid)
+ return 1;
+
+ /* connected jack ? */
+ if (widget->id == snd_soc_dapm_mic || widget->id == snd_soc_dapm_line)
+ return 1;
+ }
+
+ list_for_each_entry(path, &widget->sources, list_sink) {
+ if (path->walked)
+ continue;
+
+ if (path->source && path->connect) {
+ path->walked = 1;
+ con += is_connected_input_ep(path->source);
+ }
+ }
+
+ return con;
+}
+
+/*
+ * Scan each dapm widget for complete audio path.
+ * A complete path is a route that has valid endpoints i.e.:-
+ *
+ * o DAC to output pin.
+ * o Input Pin to ADC.
+ * o Input pin to Output pin (bypass, sidetone)
+ * o DAC to ADC (loopback).
+ */
+static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
+{
+ struct snd_soc_dapm_widget *w;
+ int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power;
+
+ /* do we have a sequenced stream event */
+ if (event == SND_SOC_DAPM_STREAM_START) {
+ c = ARRAY_SIZE(dapm_up_seq);
+ seq = dapm_up_seq;
+ } else if (event == SND_SOC_DAPM_STREAM_STOP) {
+ c = ARRAY_SIZE(dapm_down_seq);
+ seq = dapm_down_seq;
+ }
+
+ for(i = 0; i < c; i++) {
+ list_for_each_entry(w, &codec->dapm_widgets, list) {
+
+ /* is widget in stream order */
+ if (seq && seq[i] && w->id != seq[i])
+ continue;
+
+ /* vmid - no action */
+ if (w->id == snd_soc_dapm_vmid)
+ continue;
+
+ /* active ADC */
+ if (w->id == snd_soc_dapm_adc && w->active) {
+ in = is_connected_input_ep(w);
+ dapm_clear_walk(w->codec);
+ w->power = (in != 0) ? 1 : 0;
+ dapm_update_bits(w);
+ continue;
+ }
+
+ /* active DAC */
+ if (w->id == snd_soc_dapm_dac && w->active) {
+ out = is_connected_output_ep(w);
+ dapm_clear_walk(w->codec);
+ w->power = (out != 0) ? 1 : 0;
+ dapm_update_bits(w);
+ continue;
+ }
+
+ /* programmable gain/attenuation */
+ if (w->id == snd_soc_dapm_pga) {
+ int on;
+ in = is_connected_input_ep(w);
+ dapm_clear_walk(w->codec);
+ out = is_connected_output_ep(w);
+ dapm_clear_walk(w->codec);
+ w->power = on = (out != 0 && in != 0) ? 1 : 0;
+
+ if (!on)
+ dapm_set_pga(w, on); /* lower volume to reduce pops */
+ dapm_update_bits(w);
+ if (on)
+ dapm_set_pga(w, on); /* restore volume from zero */
+
+ continue;
+ }
+
+ /* pre and post event widgets */
+ if (w->id == snd_soc_dapm_pre) {
+ if (!w->event)
+ continue;
+
+ if (event == SND_SOC_DAPM_STREAM_START) {
+ ret = w->event(w, SND_SOC_DAPM_PRE_PMU);
+ if (ret < 0)
+ return ret;
+ } else if (event == SND_SOC_DAPM_STREAM_STOP) {
+ ret = w->event(w, SND_SOC_DAPM_PRE_PMD);
+ if (ret < 0)
+ return ret;
+ }
+ continue;
+ }
+ if (w->id == snd_soc_dapm_post) {
+ if (!w->event)
+ continue;
+
+ if (event == SND_SOC_DAPM_STREAM_START) {
+ ret = w->event(w, SND_SOC_DAPM_POST_PMU);
+ if (ret < 0)
+ return ret;
+ } else if (event == SND_SOC_DAPM_STREAM_STOP) {
+ ret = w->event(w, SND_SOC_DAPM_POST_PMD);
+ if (ret < 0)
+ return ret;
+ }
+ continue;
+ }
+
+ /* all other widgets */
+ in = is_connected_input_ep(w);
+ dapm_clear_walk(w->codec);
+ out = is_connected_output_ep(w);
+ dapm_clear_walk(w->codec);
+ power = (out != 0 && in != 0) ? 1 : 0;
+ power_change = (w->power == power) ? 0: 1;
+ w->power = power;
+
+ /* call any power change event handlers */
+ if (power_change) {
+ if (w->event) {
+ dbg("power %s event for %s flags %x\n",
+ w->power ? "on" : "off", w->name, w->event_flags);
+ if (power) {
+ /* power up event */
+ if (w->event_flags & SND_SOC_DAPM_PRE_PMU) {
+ ret = w->event(w, SND_SOC_DAPM_PRE_PMU);
+ if (ret < 0)
+ return ret;
+ }
+ dapm_update_bits(w);
+ if (w->event_flags & SND_SOC_DAPM_POST_PMU){
+ ret = w->event(w, SND_SOC_DAPM_POST_PMU);
+ if (ret < 0)
+ return ret;
+ }
+ } else {
+ /* power down event */
+ if (w->event_flags & SND_SOC_DAPM_PRE_PMD) {
+ ret = w->event(w, SND_SOC_DAPM_PRE_PMD);
+ if (ret < 0)
+ return ret;
+ }
+ dapm_update_bits(w);
+ if (w->event_flags & SND_SOC_DAPM_POST_PMD) {
+ ret = w->event(w, SND_SOC_DAPM_POST_PMD);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ } else
+ /* no event handler */
+ dapm_update_bits(w);
+ }
+ }
+ }
+
+ return ret;
+}
+
+#if DAPM_DEBUG
+static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
+{
+ struct snd_soc_dapm_widget *w;
+ struct snd_soc_dapm_path *p = NULL;
+ int in, out;
+
+ printk("DAPM %s %s\n", codec->name, action);
+
+ list_for_each_entry(w, &codec->dapm_widgets, list) {
+
+ /* only display widgets that effect routing */
+ switch (w->id) {
+ case snd_soc_dapm_pre:
+ case snd_soc_dapm_post:
+ case snd_soc_dapm_vmid:
+ continue;
+ case snd_soc_dapm_mux:
+ case snd_soc_dapm_output:
+ case snd_soc_dapm_input:
+ case snd_soc_dapm_switch:
+ case snd_soc_dapm_hp:
+ case snd_soc_dapm_mic:
+ case snd_soc_dapm_spk:
+ case snd_soc_dapm_line:
+ case snd_soc_dapm_micbias:
+ case snd_soc_dapm_dac:
+ case snd_soc_dapm_adc:
+ case snd_soc_dapm_pga:
+ case snd_soc_dapm_mixer:
+ if (w->name) {
+ in = is_connected_input_ep(w);
+ dapm_clear_walk(w->codec);
+ out = is_connected_output_ep(w);
+ dapm_clear_walk(w->codec);
+ printk("%s: %s in %d out %d\n", w->name,
+ w->power ? "On":"Off",in, out);
+
+ list_for_each_entry(p, &w->sources, list_sink) {
+ if (p->connect)
+ printk(" in %s %s\n", p->name ? p->name : "static",
+ p->source->name);
+ }
+ list_for_each_entry(p, &w->sinks, list_source) {
+ if (p->connect)
+ printk(" out %s %s\n", p->name ? p->name : "static",
+ p->sink->name);
+ }
+ }
+ break;
+ }
+ }
+}
+#endif
+
+/* test and update the power status of a mux widget */
+static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int mask,
+ int val, struct soc_enum* e)
+{
+ struct snd_soc_dapm_path *path;
+ int found = 0;
+
+ if (widget->id != snd_soc_dapm_mux)
+ return -ENODEV;
+
+ if (!snd_soc_test_bits(widget->codec, e->reg, mask, val))
+ return 0;
+
+ /* find dapm widget path assoc with kcontrol */
+ list_for_each_entry(path, &widget->codec->dapm_paths, list) {
+ if (path->kcontrol != kcontrol)
+ continue;
+
+ if (!path->name || ! e->texts[val])
+ continue;
+
+ found = 1;
+ /* we now need to match the string in the enum to the path */
+ if (!(strcmp(path->name, e->texts[val])))
+ path->connect = 1; /* new connection */
+ else
+ path->connect = 0; /* old connection must be powered down */
+ }
+
+ if (found)
+ dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
+
+ return 0;
+}
+
+/* test and update the power status of a mixer widget */
+static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int reg,
+ int val_mask, int val, int invert)
+{
+ struct snd_soc_dapm_path *path;
+ int found = 0;
+
+ if (widget->id != snd_soc_dapm_mixer)
+ return -ENODEV;
+
+ if (!snd_soc_test_bits(widget->codec, reg, val_mask, val))
+ return 0;
+
+ /* find dapm widget path assoc with kcontrol */
+ list_for_each_entry(path, &widget->codec->dapm_paths, list) {
+ if (path->kcontrol != kcontrol)
+ continue;
+
+ /* found, now check type */
+ found = 1;
+ if (val)
+ /* new connection */
+ path->connect = invert ? 0:1;
+ else
+ /* old connection must be powered down */
+ path->connect = invert ? 1:0;
+ break;
+ }
+
+ if (found)
+ dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
+
+ return 0;
+}
+
+/* show dapm widget status in sys fs */
+static ssize_t dapm_widget_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct snd_soc_device *devdata = dev_get_drvdata(dev);
+ struct snd_soc_codec *codec = devdata->codec;
+ struct snd_soc_dapm_widget *w;
+ int count = 0;
+ char *state = "not set";
+
+ list_for_each_entry(w, &codec->dapm_widgets, list) {
+
+ /* only display widgets that burnm power */
+ switch (w->id) {
+ case snd_soc_dapm_hp:
+ case snd_soc_dapm_mic:
+ case snd_soc_dapm_spk:
+ case snd_soc_dapm_line:
+ case snd_soc_dapm_micbias:
+ case snd_soc_dapm_dac:
+ case snd_soc_dapm_adc:
+ case snd_soc_dapm_pga:
+ case snd_soc_dapm_mixer:
+ if (w->name)
+ count += sprintf(buf + count, "%s: %s\n",
+ w->name, w->power ? "On":"Off");
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch(codec->dapm_state){
+ case SNDRV_CTL_POWER_D0:
+ state = "D0";
+ break;
+ case SNDRV_CTL_POWER_D1:
+ state = "D1";
+ break;
+ case SNDRV_CTL_POWER_D2:
+ state = "D2";
+ break;
+ case SNDRV_CTL_POWER_D3hot:
+ state = "D3hot";
+ break;
+ case SNDRV_CTL_POWER_D3cold:
+ state = "D3cold";
+ break;
+ }
+ count += sprintf(buf + count, "PM State: %s\n", state);
+
+ return count;
+}
+
+static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
+
+int snd_soc_dapm_sys_add(struct device *dev)
+{
+ int ret = 0;
+
+ if (dapm_status)
+ ret = device_create_file(dev, &dev_attr_dapm_widget);
+
+ return ret;
+}
+
+static void snd_soc_dapm_sys_remove(struct device *dev)
+{
+ if (dapm_status)
+ device_remove_file(dev, &dev_attr_dapm_widget);
+}
+
+/* free all dapm widgets and resources */
+static void dapm_free_widgets(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_widget *w, *next_w;
+ struct snd_soc_dapm_path *p, *next_p;
+
+ list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) {
+ list_del(&w->list);
+ kfree(w);
+ }
+
+ list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) {
+ list_del(&p->list);
+ kfree(p->long_name);
+ kfree(p);
+ }
+}
+
+/**
+ * snd_soc_dapm_sync_endpoints - scan and power dapm paths
+ * @codec: audio codec
+ *
+ * Walks all dapm audio paths and powers widgets according to their
+ * stream or path usage.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec)
+{
+ return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints);
+
+/**
+ * snd_soc_dapm_connect_input - connect dapm widgets
+ * @codec: audio codec
+ * @sink: name of target widget
+ * @control: mixer control name
+ * @source: name of source name
+ *
+ * Connects 2 dapm widgets together via a named audio path. The sink is
+ * the widget receiving the audio signal, whilst the source is the sender
+ * of the audio signal.
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
+ const char * control, const char *source)
+{
+ struct snd_soc_dapm_path *path;
+ struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
+ int ret = 0;
+
+ /* find src and dest widgets */
+ list_for_each_entry(w, &codec->dapm_widgets, list) {
+
+ if (!wsink && !(strcmp(w->name, sink))) {
+ wsink = w;
+ continue;
+ }
+ if (!wsource && !(strcmp(w->name, source))) {
+ wsource = w;
+ }
+ }
+
+ if (wsource == NULL || wsink == NULL)
+ return -ENODEV;
+
+ path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+
+ path->source = wsource;
+ path->sink = wsink;
+ INIT_LIST_HEAD(&path->list);
+ INIT_LIST_HEAD(&path->list_source);
+ INIT_LIST_HEAD(&path->list_sink);
+
+ /* check for external widgets */
+ if (wsink->id == snd_soc_dapm_input) {
+ if (wsource->id == snd_soc_dapm_micbias ||
+ wsource->id == snd_soc_dapm_mic ||
+ wsink->id == snd_soc_dapm_line)
+ wsink->ext = 1;
+ }
+ if (wsource->id == snd_soc_dapm_output) {
+ if (wsink->id == snd_soc_dapm_spk ||
+ wsink->id == snd_soc_dapm_hp ||
+ wsink->id == snd_soc_dapm_line)
+ wsource->ext = 1;
+ }
+
+ /* connect static paths */
+ if (control == NULL) {
+ list_add(&path->list, &codec->dapm_paths);
+ list_add(&path->list_sink, &wsink->sources);
+ list_add(&path->list_source, &wsource->sinks);
+ path->connect = 1;
+ return 0;
+ }
+
+ /* connect dynamic paths */
+ switch(wsink->id) {
+ case snd_soc_dapm_adc:
+ case snd_soc_dapm_dac:
+ case snd_soc_dapm_pga:
+ case snd_soc_dapm_input:
+ case snd_soc_dapm_output:
+ case snd_soc_dapm_micbias:
+ case snd_soc_dapm_vmid:
+ case snd_soc_dapm_pre:
+ case snd_soc_dapm_post:
+ list_add(&path->list, &codec->dapm_paths);
+ list_add(&path->list_sink, &wsink->sources);
+ list_add(&path->list_source, &wsource->sinks);
+ path->connect = 1;
+ return 0;
+ case snd_soc_dapm_mux:
+ ret = dapm_connect_mux(codec, wsource, wsink, path, control,
+ &wsink->kcontrols[0]);
+ if (ret != 0)
+ goto err;
+ break;
+ case snd_soc_dapm_switch:
+ case snd_soc_dapm_mixer:
+ ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
+ if (ret != 0)
+ goto err;
+ break;
+ case snd_soc_dapm_hp:
+ case snd_soc_dapm_mic:
+ case snd_soc_dapm_line:
+ case snd_soc_dapm_spk:
+ list_add(&path->list, &codec->dapm_paths);
+ list_add(&path->list_sink, &wsink->sources);
+ list_add(&path->list_source, &wsource->sinks);
+ path->connect = 0;
+ return 0;
+ }
+ return 0;
+
+err:
+ printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source,
+ control, sink);
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input);
+
+/**
+ * snd_soc_dapm_new_widgets - add new dapm widgets
+ * @codec: audio codec
+ *
+ * Checks the codec for any new dapm widgets and creates them if found.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_widget *w;
+
+ mutex_lock(&codec->mutex);
+ list_for_each_entry(w, &codec->dapm_widgets, list)
+ {
+ if (w->new)
+ continue;
+
+ switch(w->id) {
+ case snd_soc_dapm_switch:
+ case snd_soc_dapm_mixer:
+ dapm_new_mixer(codec, w);
+ break;
+ case snd_soc_dapm_mux:
+ dapm_new_mux(codec, w);
+ break;
+ case snd_soc_dapm_adc:
+ case snd_soc_dapm_dac:
+ case snd_soc_dapm_pga:
+ dapm_new_pga(codec, w);
+ break;
+ case snd_soc_dapm_input:
+ case snd_soc_dapm_output:
+ case snd_soc_dapm_micbias:
+ case snd_soc_dapm_spk:
+ case snd_soc_dapm_hp:
+ case snd_soc_dapm_mic:
+ case snd_soc_dapm_line:
+ case snd_soc_dapm_vmid:
+ case snd_soc_dapm_pre:
+ case snd_soc_dapm_post:
+ break;
+ }
+ w->new = 1;
+ }
+
+ dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
+ mutex_unlock(&codec->mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
+
+/**
+ * snd_soc_dapm_get_volsw - dapm mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a dapm mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ int reg = kcontrol->private_value & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0x0f;
+ int rshift = (kcontrol->private_value >> 12) & 0x0f;
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & 0x01;
+
+ /* return the saved value if we are powered down */
+ if (widget->id == snd_soc_dapm_pga && !widget->power) {
+ ucontrol->value.integer.value[0] = widget->saved_value;
+ return 0;
+ }
+
+ ucontrol->value.integer.value[0] =
+ (snd_soc_read(widget->codec, reg) >> shift) & mask;
+ if (shift != rshift)
+ ucontrol->value.integer.value[1] =
+ (snd_soc_read(widget->codec, reg) >> rshift) & mask;
+ if (invert) {
+ ucontrol->value.integer.value[0] =
+ mask - ucontrol->value.integer.value[0];
+ if (shift != rshift)
+ ucontrol->value.integer.value[1] =
+ mask - ucontrol->value.integer.value[1];
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
+
+/**
+ * snd_soc_dapm_put_volsw - dapm mixer set callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a dapm mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ int reg = kcontrol->private_value & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0x0f;
+ int rshift = (kcontrol->private_value >> 12) & 0x0f;
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & 0x01;
+ unsigned short val, val2, val_mask;
+ int ret;
+
+ val = (ucontrol->value.integer.value[0] & mask);
+
+ if (invert)
+ val = mask - val;
+ val_mask = mask << shift;
+ val = val << shift;
+ if (shift != rshift) {
+ val2 = (ucontrol->value.integer.value[1] & mask);
+ if (invert)
+ val2 = mask - val2;
+ val_mask |= mask << rshift;
+ val |= val2 << rshift;
+ }
+
+ mutex_lock(&widget->codec->mutex);
+ widget->value = val;
+
+ /* save volume value if the widget is powered down */
+ if (widget->id == snd_soc_dapm_pga && !widget->power) {
+ widget->saved_value = val;
+ mutex_unlock(&widget->codec->mutex);
+ return 1;
+ }
+
+ dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
+ if (widget->event) {
+ if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
+ ret = widget->event(widget, SND_SOC_DAPM_PRE_REG);
+ if (ret < 0)
+ goto out;
+ }
+ ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
+ if (widget->event_flags & SND_SOC_DAPM_POST_REG)
+ ret = widget->event(widget, SND_SOC_DAPM_POST_REG);
+ } else
+ ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
+
+out:
+ mutex_unlock(&widget->codec->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
+
+/**
+ * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a dapm enumerated double mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned short val, bitmask;
+
+ for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+ ;
+ val = snd_soc_read(widget->codec, e->reg);
+ ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
+ if (e->shift_l != e->shift_r)
+ ucontrol->value.enumerated.item[1] =
+ (val >> e->shift_r) & (bitmask - 1);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
+
+/**
+ * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a dapm enumerated double mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned short val, mux;
+ unsigned short mask, bitmask;
+ int ret = 0;
+
+ for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+ ;
+ if (ucontrol->value.enumerated.item[0] > e->mask - 1)
+ return -EINVAL;
+ mux = ucontrol->value.enumerated.item[0];
+ val = mux << e->shift_l;
+ mask = (bitmask - 1) << e->shift_l;
+ if (e->shift_l != e->shift_r) {
+ if (ucontrol->value.enumerated.item[1] > e->mask - 1)
+ return -EINVAL;
+ val |= ucontrol->value.enumerated.item[1] << e->shift_r;
+ mask |= (bitmask - 1) << e->shift_r;
+ }
+
+ mutex_lock(&widget->codec->mutex);
+ widget->value = val;
+ dapm_mux_update_power(widget, kcontrol, mask, mux, e);
+ if (widget->event) {
+ if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
+ ret = widget->event(widget, SND_SOC_DAPM_PRE_REG);
+ if (ret < 0)
+ goto out;
+ }
+ ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+ if (widget->event_flags & SND_SOC_DAPM_POST_REG)
+ ret = widget->event(widget, SND_SOC_DAPM_POST_REG);
+ } else
+ ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+
+out:
+ mutex_unlock(&widget->codec->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
+
+/**
+ * snd_soc_dapm_new_control - create new dapm control
+ * @codec: audio codec
+ * @widget: widget template
+ *
+ * Creates a new dapm control based upon the template.
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
+ const struct snd_soc_dapm_widget *widget)
+{
+ struct snd_soc_dapm_widget *w;
+
+ if ((w = dapm_cnew_widget(widget)) == NULL)
+ return -ENOMEM;
+
+ w->codec = codec;
+ INIT_LIST_HEAD(&w->sources);
+ INIT_LIST_HEAD(&w->sinks);
+ INIT_LIST_HEAD(&w->list);
+ list_add(&w->list, &codec->dapm_widgets);
+
+ /* machine layer set ups unconnected pins and insertions */
+ w->connected = 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
+
+/**
+ * snd_soc_dapm_stream_event - send a stream event to the dapm core
+ * @codec: audio codec
+ * @stream: stream name
+ * @event: stream event
+ *
+ * Sends a stream event to the dapm core. The core then makes any
+ * necessary widget power changes.
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
+ char *stream, int event)
+{
+ struct snd_soc_dapm_widget *w;
+
+ if (stream == NULL)
+ return 0;
+
+ mutex_lock(&codec->mutex);
+ list_for_each_entry(w, &codec->dapm_widgets, list)
+ {
+ if (!w->sname)
+ continue;
+ dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname,
+ stream, event);
+ if (strstr(w->sname, stream)) {
+ switch(event) {
+ case SND_SOC_DAPM_STREAM_START:
+ w->active = 1;
+ break;
+ case SND_SOC_DAPM_STREAM_STOP:
+ w->active = 0;
+ break;
+ case SND_SOC_DAPM_STREAM_SUSPEND:
+ if (w->active)
+ w->suspend = 1;
+ w->active = 0;
+ break;
+ case SND_SOC_DAPM_STREAM_RESUME:
+ if (w->suspend) {
+ w->active = 1;
+ w->suspend = 0;
+ }
+ break;
+ case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
+ break;
+ case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
+ break;
+ }
+ }
+ }
+ mutex_unlock(&codec->mutex);
+
+ dapm_power_widgets(codec, event);
+ dump_dapm(codec, __FUNCTION__);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
+
+/**
+ * snd_soc_dapm_set_endpoint - set audio endpoint status
+ * @codec: audio codec
+ * @endpoint: audio signal endpoint (or start point)
+ * @status: point status
+ *
+ * Set audio endpoint status - connected or disconnected.
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
+ char *endpoint, int status)
+{
+ struct snd_soc_dapm_widget *w;
+
+ list_for_each_entry(w, &codec->dapm_widgets, list) {
+ if (!strcmp(w->name, endpoint)) {
+ w->connected = status;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint);
+
+/**
+ * snd_soc_dapm_free - free dapm resources
+ * @socdev: SoC device
+ *
+ * Free all dapm widgets and resources.
+ */
+void snd_soc_dapm_free(struct snd_soc_device *socdev)
+{
+ struct snd_soc_codec *codec = socdev->codec;
+
+ snd_soc_dapm_sys_remove(socdev->dev);
+ dapm_free_widgets(codec);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
+MODULE_LICENSE("GPL");
diff --git a/sound/sound_firmware.c b/sound/sound_firmware.c
index 3a181d4c0dc..3304344713a 100644
--- a/sound/sound_firmware.c
+++ b/sound/sound_firmware.c
@@ -19,7 +19,7 @@ static int do_mod_firmware_load(const char *fn, char **fp)
printk(KERN_INFO "Unable to load '%s'.\n", fn);
return 0;
}
- l = filp->f_dentry->d_inode->i_size;
+ l = filp->f_path.dentry->d_inode->i_size;
if (l <= 0 || l > 131072)
{
printk(KERN_INFO "Invalid firmware '%s'\n", fn);
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index edeb3d3c4c7..f5956d557f7 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -1268,7 +1268,7 @@ static struct snd_pcm_hardware snd_cs4231_playback =
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = (32*1024),
- .period_bytes_min = 4096,
+ .period_bytes_min = 64,
.period_bytes_max = (32*1024),
.periods_min = 1,
.periods_max = 1024,
@@ -1288,7 +1288,7 @@ static struct snd_pcm_hardware snd_cs4231_capture =
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = (32*1024),
- .period_bytes_min = 4096,
+ .period_bytes_min = 64,
.period_bytes_max = (32*1024),
.periods_min = 1,
.periods_max = 1024,
@@ -1796,7 +1796,7 @@ static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id)
snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
spin_unlock_irqrestore(&chip->lock, flags);
- return 0;
+ return IRQ_HANDLED;
}
/*
@@ -1821,7 +1821,6 @@ static int sbus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_
if (!(csr & test))
goto out;
err = -EBUSY;
- csr = sbus_readl(base->regs + APCCSR);
test = APC_XINT_CNVA;
if ( base->dir == APC_PLAY )
test = APC_XINT_PNVA;
@@ -1862,17 +1861,16 @@ static void sbus_dma_enable(struct cs4231_dma_control *dma_cont, int on)
spin_lock_irqsave(&base->lock, flags);
if (!on) {
- if (base->dir == APC_PLAY) {
- sbus_writel(0, base->regs + base->dir + APCNVA);
- sbus_writel(1, base->regs + base->dir + APCC);
- }
- else
- {
- sbus_writel(0, base->regs + base->dir + APCNC);
- sbus_writel(0, base->regs + base->dir + APCVA);
- }
+ sbus_writel(0, base->regs + base->dir + APCNC);
+ sbus_writel(0, base->regs + base->dir + APCNVA);
+ sbus_writel(0, base->regs + base->dir + APCC);
+ sbus_writel(0, base->regs + base->dir + APCVA);
+
+ /* ACK any APC interrupts. */
+ csr = sbus_readl(base->regs + APCCSR);
+ sbus_writel(csr, base->regs + APCCSR);
}
- udelay(600);
+ udelay(1000);
csr = sbus_readl(base->regs + APCCSR);
shift = 0;
if ( base->dir == APC_PLAY )
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index 4ceb09d215d..25a2a733300 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -678,7 +678,7 @@ static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len)
* The JUMP cmd points to the new cmd string.
* It also releases the cmdlock spinlock.
*
- * Lock must not be held before calling this.
+ * Lock must be held before calling this.
*/
static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len)
{
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 67202b9eeb7..4dfb91d4398 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -186,6 +186,7 @@ struct snd_usb_substream {
u64 formats; /* format bitmasks (all or'ed) */
unsigned int num_formats; /* number of supported audio formats (list) */
struct list_head fmt_list; /* format list */
+ struct snd_pcm_hw_constraint_list rate_list; /* limited rates */
spinlock_t lock;
struct snd_urb_ops ops; /* callbacks (must be filled at init) */
@@ -253,7 +254,7 @@ static int prepare_capture_sync_urb(struct snd_usb_substream *subs,
struct urb *urb)
{
unsigned char *cp = urb->transfer_buffer;
- struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+ struct snd_urb_ctx *ctx = urb->context;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
urb->iso_frame_desc[0].length = 3;
@@ -275,7 +276,7 @@ static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs,
struct urb *urb)
{
unsigned char *cp = urb->transfer_buffer;
- struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+ struct snd_urb_ctx *ctx = urb->context;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
urb->iso_frame_desc[0].length = 4;
@@ -313,7 +314,7 @@ static int prepare_capture_urb(struct snd_usb_substream *subs,
struct urb *urb)
{
int i, offs;
- struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+ struct snd_urb_ctx *ctx = urb->context;
offs = 0;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
@@ -391,6 +392,16 @@ static int retire_capture_urb(struct snd_usb_substream *subs,
return 0;
}
+/*
+ * Process after capture complete when paused. Nothing to do.
+ */
+static int retire_paused_capture_urb(struct snd_usb_substream *subs,
+ struct snd_pcm_runtime *runtime,
+ struct urb *urb)
+{
+ return 0;
+}
+
/*
* prepare urb for full speed playback sync pipe
@@ -402,7 +413,7 @@ static int prepare_playback_sync_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
- struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+ struct snd_urb_ctx *ctx = urb->context;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
urb->iso_frame_desc[0].length = 3;
@@ -420,7 +431,7 @@ static int prepare_playback_sync_urb_hs(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
- struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+ struct snd_urb_ctx *ctx = urb->context;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
urb->iso_frame_desc[0].length = 4;
@@ -493,13 +504,13 @@ static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
}
/*
- * Prepare urb for streaming before playback starts.
+ * Prepare urb for streaming before playback starts or when paused.
*
- * We don't yet have data, so we send a frame of silence.
+ * We don't have any data, so we send a frame of silence.
*/
-static int prepare_startup_playback_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
+static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
+ struct snd_pcm_runtime *runtime,
+ struct urb *urb)
{
unsigned int i, offs, counts;
struct snd_urb_ctx *ctx = urb->context;
@@ -537,7 +548,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
unsigned int counts;
unsigned long flags;
int period_elapsed = 0;
- struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+ struct snd_urb_ctx *ctx = urb->context;
stride = runtime->frame_bits >> 3;
@@ -622,7 +633,7 @@ static int retire_playback_urb(struct snd_usb_substream *subs,
*/
static struct snd_urb_ops audio_urb_ops[2] = {
{
- .prepare = prepare_startup_playback_urb,
+ .prepare = prepare_nodata_playback_urb,
.retire = retire_playback_urb,
.prepare_sync = prepare_playback_sync_urb,
.retire_sync = retire_playback_sync_urb,
@@ -637,7 +648,7 @@ static struct snd_urb_ops audio_urb_ops[2] = {
static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
{
- .prepare = prepare_startup_playback_urb,
+ .prepare = prepare_nodata_playback_urb,
.retire = retire_playback_urb,
.prepare_sync = prepare_playback_sync_urb_hs,
.retire_sync = retire_playback_sync_urb_hs,
@@ -655,7 +666,7 @@ static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
*/
static void snd_complete_urb(struct urb *urb)
{
- struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+ struct snd_urb_ctx *ctx = urb->context;
struct snd_usb_substream *subs = ctx->subs;
struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
int err = 0;
@@ -678,7 +689,7 @@ static void snd_complete_urb(struct urb *urb)
*/
static void snd_complete_sync_urb(struct urb *urb)
{
- struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
+ struct snd_urb_ctx *ctx = urb->context;
struct snd_usb_substream *subs = ctx->subs;
struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
int err = 0;
@@ -925,10 +936,14 @@ static int snd_usb_pcm_playback_trigger(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
subs->ops.prepare = prepare_playback_urb;
return 0;
case SNDRV_PCM_TRIGGER_STOP:
return deactivate_urbs(subs, 0, 0);
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ subs->ops.prepare = prepare_nodata_playback_urb;
+ return 0;
default:
return -EINVAL;
}
@@ -944,9 +959,16 @@ static int snd_usb_pcm_capture_trigger(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ subs->ops.retire = retire_capture_urb;
return start_urbs(subs, substream->runtime);
case SNDRV_PCM_TRIGGER_STOP:
return deactivate_urbs(subs, 0, 0);
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ subs->ops.retire = retire_paused_capture_urb;
+ return 0;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ subs->ops.retire = retire_capture_urb;
+ return 0;
default:
return -EINVAL;
}
@@ -1408,7 +1430,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
static int snd_usb_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
- struct snd_usb_substream *subs = (struct snd_usb_substream *)substream->runtime->private_data;
+ struct snd_usb_substream *subs = substream->runtime->private_data;
struct audioformat *fmt;
unsigned int channels, rate, format;
int ret, changed;
@@ -1464,7 +1486,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
*/
static int snd_usb_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_usb_substream *subs = (struct snd_usb_substream *)substream->runtime->private_data;
+ struct snd_usb_substream *subs = substream->runtime->private_data;
subs->cur_audiofmt = NULL;
subs->cur_rate = 0;
@@ -1505,33 +1527,20 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
/* for playback, submit the URBs now; otherwise, the first hwptr_done
* updates for all URBs would happen at the same time when starting */
if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
- subs->ops.prepare = prepare_startup_playback_urb;
+ subs->ops.prepare = prepare_nodata_playback_urb;
return start_urbs(subs, runtime);
} else
return 0;
}
-static struct snd_pcm_hardware snd_usb_playback =
+static struct snd_pcm_hardware snd_usb_hardware =
{
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER,
- .buffer_bytes_max = 1024 * 1024,
- .period_bytes_min = 64,
- .period_bytes_max = 512 * 1024,
- .periods_min = 2,
- .periods_max = 1024,
-};
-
-static struct snd_pcm_hardware snd_usb_capture =
-{
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE,
.buffer_bytes_max = 1024 * 1024,
.period_bytes_min = 64,
.period_bytes_max = 512 * 1024,
@@ -1810,28 +1819,33 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
struct snd_usb_substream *subs)
{
- struct list_head *p;
- struct snd_pcm_hw_constraint_list constraints_rates;
+ struct audioformat *fp;
+ int count = 0, needs_knot = 0;
int err;
- list_for_each(p, &subs->fmt_list) {
- struct audioformat *fp;
- fp = list_entry(p, struct audioformat, list);
-
- if (!fp->needs_knot)
- continue;
-
- constraints_rates.count = fp->nr_rates;
- constraints_rates.list = fp->rate_table;
- constraints_rates.mask = 0;
-
- err = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_rates);
-
- if (err < 0)
- return err;
+ list_for_each_entry(fp, &subs->fmt_list, list) {
+ if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)
+ return 0;
+ count += fp->nr_rates;
+ if (fp->needs_knot)
+ needs_knot = 1;
}
+ if (!needs_knot)
+ return 0;
+
+ subs->rate_list.count = count;
+ subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL);
+ subs->rate_list.mask = 0;
+ count = 0;
+ list_for_each_entry(fp, &subs->fmt_list, list) {
+ int i;
+ for (i = 0; i < fp->nr_rates; i++)
+ subs->rate_list.list[count++] = fp->rate_table[i];
+ }
+ err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &subs->rate_list);
+ if (err < 0)
+ return err;
return 0;
}
@@ -1904,8 +1918,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
return 0;
}
-static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction,
- struct snd_pcm_hardware *hw)
+static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
{
struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1913,7 +1926,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction,
subs->interface = -1;
subs->format = 0;
- runtime->hw = *hw;
+ runtime->hw = snd_usb_hardware;
runtime->private_data = subs;
subs->pcm_substream = substream;
return setup_hw_info(runtime, subs);
@@ -1934,7 +1947,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
static int snd_usb_playback_open(struct snd_pcm_substream *substream)
{
- return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK, &snd_usb_playback);
+ return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK);
}
static int snd_usb_playback_close(struct snd_pcm_substream *substream)
@@ -1944,7 +1957,7 @@ static int snd_usb_playback_close(struct snd_pcm_substream *substream)
static int snd_usb_capture_open(struct snd_pcm_substream *substream)
{
- return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_capture);
+ return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE);
}
static int snd_usb_capture_close(struct snd_pcm_substream *substream)
@@ -2231,6 +2244,7 @@ static void free_substream(struct snd_usb_substream *subs)
kfree(fp->rate_table);
kfree(fp);
}
+ kfree(subs->rate_list.list);
}
@@ -2456,6 +2470,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
* build the rate table and bitmap flags
*/
int r, idx, c;
+ unsigned int nonzero_rates = 0;
/* this table corresponds to the SNDRV_PCM_RATE_XXX bit */
static unsigned int conv_rates[] = {
5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
@@ -2471,7 +2486,14 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
fp->nr_rates = nr_rates;
fp->rate_min = fp->rate_max = combine_triple(&fmt[8]);
for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) {
- unsigned int rate = fp->rate_table[r] = combine_triple(&fmt[idx]);
+ unsigned int rate = combine_triple(&fmt[idx]);
+ /* C-Media CM6501 mislabels its 96 kHz altsetting */
+ if (rate == 48000 && nr_rates == 1 &&
+ chip->usb_id == USB_ID(0x0d8c, 0x0201) &&
+ fp->altsetting == 5 && fp->maxpacksize == 392)
+ rate = 96000;
+ fp->rate_table[r] = rate;
+ nonzero_rates |= rate;
if (rate < fp->rate_min)
fp->rate_min = rate;
else if (rate > fp->rate_max)
@@ -2487,6 +2509,10 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
if (!found)
fp->needs_knot = 1;
}
+ if (!nonzero_rates) {
+ hwc_debug("All rates were zero. Skipping format!\n");
+ return -1;
+ }
if (fp->needs_knot)
fp->rates |= SNDRV_PCM_RATE_KNOT;
} else {
@@ -3051,6 +3077,58 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip,
return 0;
}
+/*
+ * Create a stream for an Edirol UA-101 interface.
+ * Copy, paste and modify from Edirol UA-1000
+ */
+static int create_ua101_quirk(struct snd_usb_audio *chip,
+ struct usb_interface *iface,
+ const struct snd_usb_audio_quirk *quirk)
+{
+ static const struct audioformat ua101_format = {
+ .format = SNDRV_PCM_FORMAT_S32_LE,
+ .fmt_type = USB_FORMAT_TYPE_I,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = 0,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ };
+ struct usb_host_interface *alts;
+ struct usb_interface_descriptor *altsd;
+ struct audioformat *fp;
+ int stream, err;
+
+ if (iface->num_altsetting != 2)
+ return -ENXIO;
+ alts = &iface->altsetting[1];
+ altsd = get_iface_desc(alts);
+ if (alts->extralen != 18 || alts->extra[1] != USB_DT_CS_INTERFACE ||
+ altsd->bNumEndpoints != 1)
+ return -ENXIO;
+
+ fp = kmemdup(&ua101_format, sizeof(*fp), GFP_KERNEL);
+ if (!fp)
+ return -ENOMEM;
+
+ fp->channels = alts->extra[11];
+ fp->iface = altsd->bInterfaceNumber;
+ fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
+ fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+ fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+ fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]);
+
+ stream = (fp->endpoint & USB_DIR_IN)
+ ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
+ err = add_audio_endpoint(chip, stream, fp);
+ if (err < 0) {
+ kfree(fp);
+ return err;
+ }
+ /* FIXME: playback must be synchronized to capture */
+ usb_set_interface(chip->dev, fp->iface, 0);
+ return 0;
+}
+
static int snd_usb_create_quirk(struct snd_usb_audio *chip,
struct usb_interface *iface,
const struct snd_usb_audio_quirk *quirk);
@@ -3232,6 +3310,7 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip,
[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
[QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk,
[QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
+ [QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk,
};
if (quirk->type < QUIRK_TYPE_COUNT) {
@@ -3280,6 +3359,7 @@ static void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
static int snd_usb_audio_free(struct snd_usb_audio *chip)
{
+ usb_chip[chip->index] = NULL;
kfree(chip);
return 0;
}
@@ -3541,7 +3621,6 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
list_for_each(p, &chip->mixer_list) {
snd_usb_mixer_disconnect(p);
}
- usb_chip[chip->index] = NULL;
mutex_unlock(&register_mutex);
snd_card_free_when_closed(card);
} else {
@@ -3577,8 +3656,7 @@ static int __init snd_usb_audio_init(void)
printk(KERN_WARNING "invalid nrpacks value.\n");
return -EINVAL;
}
- usb_register(&usb_audio_driver);
- return 0;
+ return usb_register(&usb_audio_driver);
}
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 0f4b2b8541d..2272f45a186 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -159,6 +159,7 @@ enum quirk_type {
QUIRK_AUDIO_FIXED_ENDPOINT,
QUIRK_AUDIO_EDIROL_UA700_UA25,
QUIRK_AUDIO_EDIROL_UA1000,
+ QUIRK_AUDIO_EDIROL_UA101,
QUIRK_TYPE_COUNT
};
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index e74eb1bc8d8..7b3bf3545a3 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -1526,7 +1526,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
if (! namelist[i]) {
snd_printk(KERN_ERR "cannot malloc\n");
- while (--i > 0)
+ while (i--)
kfree(namelist[i]);
kfree(namelist);
kfree(cval);
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index a7e9563a01d..25b4ab4f61e 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -1098,7 +1098,37 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
- /* TODO: add Edirol UA-101 support */
+/* Roland UA-101 in High-Speed Mode only */
+{
+ USB_DEVICE(0x0582, 0x007d),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .vendor_name = "Roland",
+ .product_name = "UA-101",
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_EDIROL_UA101
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_EDIROL_UA101
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const struct snd_usb_midi_endpoint_info) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
{
/* has ID 0x0081 when not in "Advanced Driver" mode */
USB_DEVICE(0x0582, 0x0080),
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 367f8a32a66..0a352e46862 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -322,7 +322,7 @@ static void i_usX2Y_urb_complete(struct urb *urb)
usX2Y_error_urb_status(usX2Y, subs, urb);
return;
}
- if (likely(urb->start_frame == usX2Y->wait_iso_frame))
+ if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
subs->completed_urb = urb;
else {
usX2Y_error_sequence(usX2Y, subs, urb);
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 8f3e35e24e7..a5e7bcd7ca2 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -243,7 +243,7 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
usX2Y_error_urb_status(usX2Y, subs, urb);
return;
}
- if (likely(urb->start_frame == usX2Y->wait_iso_frame))
+ if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
subs->completed_urb = urb;
else {
usX2Y_error_sequence(usX2Y, subs, urb);